diff --git a/.gitignore b/.gitignore index 2f3f09a8747d..c3f4ae123871 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ autom4te.cache/ build/* compile config.guess -config.h config.log config.status config.sub @@ -59,6 +58,7 @@ src/*.orig src/*.plist/* src/TAGS src/suricata +src/**/*.dirstamp stamp-h1 src/build-info.h test.sh diff --git a/doc/userguide/capture-hardware/ebpf-xdp.rst b/doc/userguide/capture-hardware/ebpf-xdp.rst index 116038716eff..c60049fe8c7e 100644 --- a/doc/userguide/capture-hardware/ebpf-xdp.rst +++ b/doc/userguide/capture-hardware/ebpf-xdp.rst @@ -419,7 +419,7 @@ Confirm you have the XDP filter engaged in the output (example):: (runmode-af-packet.c:424) (ParseAFPConfig) -- af-packet will use '/usr/libexec/suricata/ebpf/xdp_filter.bpf' as XDP filter file (runmode-af-packet.c:429) (ParseAFPConfig) -- Using bypass kernel functionality for AF_PACKET (iface eth3) (runmode-af-packet.c:609) (ParseAFPConfig) -- eth3: enabling zero copy mode by using data release call - (util-runmodes.c:296) (RunModeSetLiveCaptureWorkersForDevice) -- Going to use 8 thread(s) + (util/runmodes.c:296) (RunModeSetLiveCaptureWorkersForDevice) -- Going to use 8 thread(s) ... ... diff --git a/doc/userguide/devguide/codebase/code-style.rst b/doc/userguide/devguide/codebase/code-style.rst index 1d1d00917e02..df7b7a18c107 100644 --- a/doc/userguide/devguide/codebase/code-style.rst +++ b/doc/userguide/devguide/codebase/code-style.rst @@ -539,9 +539,9 @@ File names File names are all lowercase and have a .c. .h or .rs (Rust) extension. -Most files have a _subsystem_ prefix, e.g. ``detect-dsize.c, util-ip.c`` +Most files have a _subsystem_ prefix, e.g. ``detect-dsize.c, util/ip.c`` -Some cases have a multi-layer prefix, e.g. ``util-mpm-ac.c`` +Some cases have a multi-layer prefix, e.g. ``util/mpm/mpm-ac.c`` Enums ~~~~~ diff --git a/doc/userguide/devguide/codebase/unittests-c.rst b/doc/userguide/devguide/codebase/unittests-c.rst index 0ae7bdf92e0c..2e7eb7258186 100644 --- a/doc/userguide/devguide/codebase/unittests-c.rst +++ b/doc/userguide/devguide/codebase/unittests-c.rst @@ -117,7 +117,7 @@ From ``conf-yaml-loader.c``: PASS; } -In ``detect-ike-chosen-sa.c``, it is possible to see the freeing of resources (``DetectIkeChosenSaFree``) and the +In ``app-layer/ike/detect-chosen-sa.c``, it is possible to see the freeing of resources (``DetectIkeChosenSaFree``) and the function that should group all the ``UtRegisterTest`` calls: .. code-block:: c diff --git a/doc/userguide/devguide/extending/app-layer/app-layer-frames.rst b/doc/userguide/devguide/extending/app-layer/app-layer-frames.rst index a810f5588dcd..6cfe8b3ce9cc 100644 --- a/doc/userguide/devguide/extending/app-layer/app-layer-frames.rst +++ b/doc/userguide/devguide/extending/app-layer/app-layer-frames.rst @@ -159,32 +159,32 @@ Implementing Frame support in C involves a bit more manual work, as one cannot m Defining the frame types with the enum means: -.. literalinclude:: ../../../../../src/app-layer-htp.c - :caption: src/app-layer-htp.c +.. literalinclude:: ../../../../../src/app-layer/http/parser.c + :caption: src/app-layer/http/parser.c :start-after: /* app-layer-frame-documentation tag start: HttpFrameTypes :end-before: /* app-layer-frame-documentation tag end: HttpFrameTypes :lines: 1-16 The HTTP parser uses the Frame registration functions from the C API (``app-layer-frames.c``) directly for registering request Frames. Here we also don't know the length yet. The ``0`` indicates flow direction: ``toserver``, and ``1`` would be used for ``toclient``: -.. literalinclude:: ../../../../../src/app-layer-htp.c - :caption: src/app-layer-htp.c +.. literalinclude:: ../../../../../src/app-layer/http/parser.c + :caption: src/app-layer/http/parser.c :start-after: /* app-layer-frame-documentation tag start: frame registration http request :end-before: /* app-layer-frame-documentation tag end: frame registration http request :dedent: 4 Updating ``frame->len`` later: -.. literalinclude:: ../../../../../src/app-layer-htp.c - :caption: src/app-layer-htp.c +.. literalinclude:: ../../../../../src/app-layer/http/parser.c + :caption: src/app-layer/http/parser.c :start-after: /* app-layer-frame-documentation tag start: updating frame->len :end-before: /* app-layer-frame-documentation tag end: updating frame->len :dedent: 4 Register relevant callbacks (note that the actual functions will also have to be written, for C): -.. literalinclude:: ../../../../../src/app-layer-htp.c - :caption: src/app-layer-htp.c +.. literalinclude:: ../../../../../src/app-layer/http/parser.c + :caption: src/app-layer/http/parser.c :language: c :start-after: /* app-layer-frame-documentation tag start: registering relevant callbacks :end-before: /* app-layer-frame-documentation tag end: registering relevant callbacks diff --git a/doc/userguide/devguide/extending/app-layer/transactions.rst b/doc/userguide/devguide/extending/app-layer/transactions.rst index 357bdcd76d73..462558a67803 100644 --- a/doc/userguide/devguide/extending/app-layer/transactions.rst +++ b/doc/userguide/devguide/extending/app-layer/transactions.rst @@ -28,7 +28,7 @@ likely happen once per transaction, by the time of its completion. In other case In ``OutputTxLog``, the engine will compare current state with the value defined for the logging to happen, per flow direction (``logger->tc_log_progress``, ``logger->ts_log_progress``). If state is less than that value, the engine skips to -the next logger. Code snippet from: suricata/src/output-tx.c: +the next logger. Code snippet from: suricata/src/output/output-tx.c: .. code-block:: c @@ -144,7 +144,7 @@ Code snippet from: rust/src/ssh/ssh.rs: SshStateFinished = 3, } -From src/app-layer-ftp.h: +From src/app-layer/ftp/parser.h: .. code-block:: c @@ -154,7 +154,7 @@ From src/app-layer-ftp.h: FTP_STATE_FINISHED, }; -From src/app-layer-ssl.h: +From src/app-layer/ssl/parser.h: .. code-block:: c @@ -218,7 +218,7 @@ src/app-layer-dcerpc.c: AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_DCERPC, 1, 1); -src/app-layer-ftp.c: +src/app-layer/ftp/parser.c: .. code-block:: c diff --git a/doc/userguide/rules/file-keywords.rst b/doc/userguide/rules/file-keywords.rst index c708ee746c0d..39b5c6ec874b 100644 --- a/doc/userguide/rules/file-keywords.rst +++ b/doc/userguide/rules/file-keywords.rst @@ -177,10 +177,10 @@ info on the line it is ignored. Output from md5sum is fine:: - 2f8d0355f0032c3e6311c6408d7c2dc2 util-path.c - b9cf5cf347a70e02fde975fc4e117760 util-pidfile.c - 02aaa6c3f4dbae65f5889eeb8f2bbb8d util-pool.c - dd5fc1ee7f2f96b5f12d1a854007a818 util-print.c + 2f8d0355f0032c3e6311c6408d7c2dc2 util/path.c + b9cf5cf347a70e02fde975fc4e117760 util/pidfile.c + 02aaa6c3f4dbae65f5889eeb8f2bbb8d util/pool.c + dd5fc1ee7f2f96b5f12d1a854007a818 util/print.c Just MD5's are good as well:: diff --git a/examples/plugins/c-json-filetype/filetype.c b/examples/plugins/c-json-filetype/filetype.c index 9c81d7f03267..eff1298ea84a 100644 --- a/examples/plugins/c-json-filetype/filetype.c +++ b/examples/plugins/c-json-filetype/filetype.c @@ -17,8 +17,8 @@ #include "suricata-common.h" #include "suricata-plugin.h" -#include "util-mem.h" -#include "util-debug.h" +#include "util/mem.h" +#include "util/debug.h" #define FILETYPE_NAME "json-filetype-plugin" diff --git a/rust/derive/src/applayerevent.rs b/rust/derive/src/applayerevent.rs index 29475fa2d51b..3c6a236ec6af 100644 --- a/rust/derive/src/applayerevent.rs +++ b/rust/derive/src/applayerevent.rs @@ -51,7 +51,9 @@ pub fn derive_app_layer_event(input: TokenStream) -> TokenStream { // "crate", but if we're being used by a library or plugin user we need to reference the // Suricata name space as "suricata". Check the CARGO_PKG_NAME environment variable to // determine what identifier to setup. - let is_suricata = std::env::var("CARGO_PKG_NAME").map(|var| var == "suricata").unwrap_or(false); + let is_suricata = std::env::var("CARGO_PKG_NAME") + .map(|var| var == "suricata") + .unwrap_or(false); let crate_id = if is_suricata { syn::Ident::new("crate", proc_macro2::Span::call_site()) } else { diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml index 848158b48e0f..29217bae78b3 100644 --- a/rust/rustfmt.toml +++ b/rust/rustfmt.toml @@ -1,4 +1,5 @@ # Rust format configuration file. If empty, then this is a message that # we expect the default formatting rules to be used. -fn_args_layout = "compressed" +fn_params_layout = "compressed" +force_explicit_abi = false diff --git a/rust/src/applayer.rs b/rust/src/applayer.rs index 97db321e2249..8f3871b676c1 100644 --- a/rust/src/applayer.rs +++ b/rust/src/applayer.rs @@ -17,13 +17,13 @@ //! Parser registration functions and common interface module. -use std; -use crate::core::{self,DetectEngineState,Flow,AppLayerEventType,AppProto,Direction}; -use crate::filecontainer::FileContainer; -use std::os::raw::{c_void,c_char,c_int}; +use crate::core::StreamingBufferConfig; use crate::core::SC; +use crate::core::{self, AppLayerEventType, AppProto, DetectEngineState, Direction, Flow}; +use crate::filecontainer::FileContainer; +use std; use std::ffi::CStr; -use crate::core::StreamingBufferConfig; +use std::os::raw::{c_char, c_int, c_void}; // Make the AppLayerEvent derive macro available to users importing // AppLayerEvent from this module. @@ -39,7 +39,6 @@ pub struct StreamSlice { } impl StreamSlice { - /// Create a StreamSlice from a Rust slice. Useful in unit tests. #[cfg(test)] pub fn from_slice(slice: &[u8], flags: u8, offset: u64) -> Self { @@ -47,7 +46,7 @@ impl StreamSlice { input: slice.as_ptr(), input_len: slice.len() as u32, flags, - offset + offset, } } @@ -75,7 +74,7 @@ impl StreamSlice { } #[repr(C)] -#[derive(Default, Debug,PartialEq, Eq)] +#[derive(Default, Debug, PartialEq, Eq)] pub struct AppLayerTxConfig { /// config: log flags log_flags: u8, @@ -83,9 +82,7 @@ pub struct AppLayerTxConfig { impl AppLayerTxConfig { pub fn new() -> Self { - Self { - log_flags: 0, - } + Self { log_flags: 0 } } } @@ -192,54 +189,56 @@ impl AppLayerTxData { pub fn update_file_flags(&mut self, state_flags: u16) { if (self.file_flags & state_flags) != state_flags { - SCLogDebug!("updating tx file_flags {:04x} with state flags {:04x}", self.file_flags, state_flags); + SCLogDebug!( + "updating tx file_flags {:04x} with state flags {:04x}", + self.file_flags, + state_flags + ); self.file_flags |= state_flags; } } } #[macro_export] -macro_rules!export_tx_data_get { +macro_rules! export_tx_data_get { ($name:ident, $type:ty) => { #[no_mangle] - pub unsafe extern "C" fn $name(tx: *mut std::os::raw::c_void) - -> *mut $crate::applayer::AppLayerTxData - { + pub unsafe extern fn $name( + tx: *mut std::os::raw::c_void, + ) -> *mut $crate::applayer::AppLayerTxData { let tx = &mut *(tx as *mut $type); &mut tx.tx_data } - } + }; } #[repr(C)] -#[derive(Default,Debug,PartialEq, Eq,Copy,Clone)] +#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)] pub struct AppLayerStateData { pub file_flags: u16, } impl AppLayerStateData { pub fn new() -> Self { - Self { - file_flags: 0, - } + Self { file_flags: 0 } } } #[macro_export] -macro_rules!export_state_data_get { +macro_rules! export_state_data_get { ($name:ident, $type:ty) => { #[no_mangle] - pub unsafe extern "C" fn $name(state: *mut std::os::raw::c_void) - -> *mut $crate::applayer::AppLayerStateData - { + pub unsafe extern fn $name( + state: *mut std::os::raw::c_void, + ) -> *mut $crate::applayer::AppLayerStateData { let state = &mut *(state as *mut $type); &mut state.state_data } - } + }; } #[repr(C)] -#[derive(Default,Debug,PartialEq, Eq,Copy,Clone)] +#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)] pub struct AppLayerResult { pub status: i32, pub consumed: u32, @@ -301,60 +300,60 @@ impl From for AppLayerResult { #[repr(C)] pub struct RustParser { /// Parser name. - pub name: *const c_char, + pub name: *const c_char, /// Default port - pub default_port: *const c_char, + pub default_port: *const c_char, /// IP Protocol (core::IPPROTO_UDP, core::IPPROTO_TCP, etc.) - pub ipproto: u8, + pub ipproto: u8, /// Probing function, for packets going to server - pub probe_ts: Option, + pub probe_ts: Option, /// Probing function, for packets going to client - pub probe_tc: Option, + pub probe_tc: Option, /// Minimum frame depth for probing - pub min_depth: u16, + pub min_depth: u16, /// Maximum frame depth for probing - pub max_depth: u16, + pub max_depth: u16, /// Allocation function for a new state - pub state_new: StateAllocFn, + pub state_new: StateAllocFn, /// Function called to free a state - pub state_free: StateFreeFn, + pub state_free: StateFreeFn, /// Parsing function, for packets going to server - pub parse_ts: ParseFn, + pub parse_ts: ParseFn, /// Parsing function, for packets going to client - pub parse_tc: ParseFn, + pub parse_tc: ParseFn, /// Get the current transaction count - pub get_tx_count: StateGetTxCntFn, + pub get_tx_count: StateGetTxCntFn, /// Get a transaction - pub get_tx: StateGetTxFn, + pub get_tx: StateGetTxFn, /// Function called to free a transaction - pub tx_free: StateTxFreeFn, + pub tx_free: StateTxFreeFn, /// Progress values at which the tx is considered complete in a direction - pub tx_comp_st_ts: c_int, - pub tx_comp_st_tc: c_int, + pub tx_comp_st_ts: c_int, + pub tx_comp_st_tc: c_int, /// Function returning the current transaction progress - pub tx_get_progress: StateGetProgressFn, + pub tx_get_progress: StateGetProgressFn, /// Function to get an event id from a description - pub get_eventinfo: Option, + pub get_eventinfo: Option, /// Function to get an event description from an event id pub get_eventinfo_byid: Option, /// Function to allocate local storage - pub localstorage_new: Option, + pub localstorage_new: Option, /// Function to free local storage - pub localstorage_free: Option, + pub localstorage_free: Option, /// Function to get files - pub get_tx_files: Option, + pub get_tx_files: Option, /// Function to get the TX iterator - pub get_tx_iterator: Option, + pub get_tx_iterator: Option, pub get_state_data: GetStateDataFn, pub get_tx_data: GetTxDataFn, @@ -380,7 +379,9 @@ pub struct RustParser { /// UNSAFE ! #[macro_export] macro_rules! build_slice { - ($buf:ident, $len:expr) => ( std::slice::from_raw_parts($buf, $len) ); + ($buf:ident, $len:expr) => { + std::slice::from_raw_parts($buf, $len) + }; } /// Cast pointer to a variable, as a mutable reference to an object @@ -388,7 +389,9 @@ macro_rules! build_slice { /// UNSAFE ! #[macro_export] macro_rules! cast_pointer { - ($ptr:ident, $ty:ty) => ( &mut *($ptr as *mut $ty) ); + ($ptr:ident, $ty:ty) => { + &mut *($ptr as *mut $ty) + }; } /// helper for the GetTxFilesFn. Not meant to be embedded as the config @@ -401,44 +404,60 @@ pub struct AppLayerGetFileState { } impl AppLayerGetFileState { pub fn err() -> AppLayerGetFileState { - AppLayerGetFileState { fc: std::ptr::null_mut(), cfg: std::ptr::null() } - } -} - -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 TruncateFn = unsafe extern "C" fn (*mut c_void, u8); -pub type GetFrameIdByName = unsafe extern "C" fn(*const c_char) -> c_int; -pub type GetFrameNameById = unsafe extern "C" fn(u8) -> *const c_char; + AppLayerGetFileState { + fc: std::ptr::null_mut(), + cfg: std::ptr::null(), + } + } +} +pub type ParseFn = unsafe extern 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 fn( + flow: *const Flow, + flags: u8, + input: *const u8, + input_len: u32, + rdir: *mut u8, +) -> AppProto; +pub type StateAllocFn = extern fn(*mut c_void, AppProto) -> *mut c_void; +pub type StateFreeFn = unsafe extern fn(*mut c_void); +pub type StateTxFreeFn = unsafe extern fn(*mut c_void, u64); +pub type StateGetTxFn = unsafe extern fn(*mut c_void, u64) -> *mut c_void; +pub type StateGetTxCntFn = unsafe extern fn(*mut c_void) -> u64; +pub type StateGetProgressFn = unsafe extern fn(*mut c_void, u8) -> c_int; +pub type GetEventInfoFn = + unsafe extern fn(*const c_char, *mut c_int, *mut AppLayerEventType) -> c_int; +pub type GetEventInfoByIdFn = + unsafe extern fn(c_int, *mut *const c_char, *mut AppLayerEventType) -> i8; +pub type LocalStorageNewFn = extern fn() -> *mut c_void; +pub type LocalStorageFreeFn = extern fn(*mut c_void); +pub type GetTxFilesFn = unsafe extern fn(*mut c_void, *mut c_void, u8) -> AppLayerGetFileState; +pub type GetTxIteratorFn = unsafe extern 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 fn(*mut c_void) -> *mut AppLayerTxData; +pub type GetStateDataFn = unsafe extern fn(*mut c_void) -> *mut AppLayerStateData; +pub type ApplyTxConfigFn = unsafe extern fn(*mut c_void, *mut c_void, c_int, AppLayerTxConfig); +pub type TruncateFn = unsafe extern fn(*mut c_void, u8); +pub type GetFrameIdByName = unsafe extern fn(*const c_char) -> c_int; +pub type GetFrameNameById = unsafe extern fn(u8) -> *const c_char; // Defined in app-layer-register.h extern { - pub fn AppLayerRegisterProtocolDetection(parser: *const RustParser, enable_default: c_int) -> AppProto; + pub fn AppLayerRegisterProtocolDetection( + parser: *const RustParser, enable_default: c_int, + ) -> AppProto; pub fn AppLayerRegisterParserAlias(parser_name: *const c_char, alias_name: *const c_char); } @@ -449,34 +468,40 @@ pub unsafe fn AppLayerRegisterParser(parser: *const RustParser, alproto: AppProt // Defined in app-layer-detect-proto.h extern { - pub fn AppLayerProtoDetectPPRegister(ipproto: u8, portstr: *const c_char, alproto: AppProto, - min_depth: u16, max_depth: u16, dir: u8, - pparser1: ProbeFn, pparser2: ProbeFn); - pub fn AppLayerProtoDetectPPParseConfPorts(ipproto_name: *const c_char, ipproto: u8, - alproto_name: *const c_char, alproto: AppProto, - min_depth: u16, max_depth: u16, - pparser_ts: ProbeFn, pparser_tc: ProbeFn) -> i32; - pub fn AppLayerProtoDetectPMRegisterPatternCS(ipproto: u8, alproto: AppProto, - pattern: *const c_char, depth: u16, - offset: u16, direction: u8) -> c_int; - pub fn AppLayerProtoDetectPMRegisterPatternCSwPP(ipproto: u8, alproto: AppProto, - pattern: *const c_char, depth: u16, - offset: u16, direction: u8, ppfn: ProbeFn, - pp_min_depth: u16, pp_max_depth: u16) -> c_int; - pub fn AppLayerProtoDetectConfProtoDetectionEnabled(ipproto: *const c_char, proto: *const c_char) -> c_int; - pub fn AppLayerProtoDetectConfProtoDetectionEnabledDefault(ipproto: *const c_char, proto: *const c_char, default: bool) -> c_int; + pub fn AppLayerProtoDetectPPRegister( + ipproto: u8, portstr: *const c_char, alproto: AppProto, min_depth: u16, max_depth: u16, + dir: u8, pparser1: ProbeFn, pparser2: ProbeFn, + ); + pub fn AppLayerProtoDetectPPParseConfPorts( + ipproto_name: *const c_char, ipproto: u8, alproto_name: *const c_char, alproto: AppProto, + min_depth: u16, max_depth: u16, pparser_ts: ProbeFn, pparser_tc: ProbeFn, + ) -> i32; + pub fn AppLayerProtoDetectPMRegisterPatternCS( + ipproto: u8, alproto: AppProto, pattern: *const c_char, depth: u16, offset: u16, + direction: u8, + ) -> c_int; + pub fn AppLayerProtoDetectPMRegisterPatternCSwPP( + ipproto: u8, alproto: AppProto, pattern: *const c_char, depth: u16, offset: u16, + direction: u8, ppfn: ProbeFn, pp_min_depth: u16, pp_max_depth: u16, + ) -> c_int; + pub fn AppLayerProtoDetectConfProtoDetectionEnabled( + ipproto: *const c_char, proto: *const c_char, + ) -> c_int; + pub fn AppLayerProtoDetectConfProtoDetectionEnabledDefault( + ipproto: *const c_char, proto: *const c_char, default: bool, + ) -> c_int; pub fn AppLayerRequestProtocolTLSUpgrade(flow: *const Flow) -> bool; } // Defined in app-layer-parser.h -pub const APP_LAYER_PARSER_NO_INSPECTION : u16 = BIT_U16!(1); -pub const APP_LAYER_PARSER_NO_REASSEMBLY : u16 = BIT_U16!(2); -pub const APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD : u16 = BIT_U16!(3); -pub const APP_LAYER_PARSER_BYPASS_READY : u16 = BIT_U16!(4); -pub const APP_LAYER_PARSER_EOF_TS : u16 = BIT_U16!(5); -pub const APP_LAYER_PARSER_EOF_TC : u16 = BIT_U16!(6); -pub const APP_LAYER_PARSER_TRUNC_TS : u16 = BIT_U16!(7); -pub const APP_LAYER_PARSER_TRUNC_TC : u16 = BIT_U16!(8); +pub const APP_LAYER_PARSER_NO_INSPECTION: u16 = BIT_U16!(1); +pub const APP_LAYER_PARSER_NO_REASSEMBLY: u16 = BIT_U16!(2); +pub const APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD: u16 = BIT_U16!(3); +pub const APP_LAYER_PARSER_BYPASS_READY: u16 = BIT_U16!(4); +pub const APP_LAYER_PARSER_EOF_TS: u16 = BIT_U16!(5); +pub const APP_LAYER_PARSER_EOF_TC: u16 = BIT_U16!(6); +pub const APP_LAYER_PARSER_TRUNC_TS: u16 = BIT_U16!(7); +pub const APP_LAYER_PARSER_TRUNC_TC: u16 = BIT_U16!(8); pub const APP_LAYER_PARSER_OPT_ACCEPT_GAPS: u32 = BIT_U32!(0); @@ -497,27 +522,32 @@ pub struct AppLayerGetTxIterTuple { } impl AppLayerGetTxIterTuple { - pub fn with_values(tx_ptr: *mut std::os::raw::c_void, tx_id: u64, has_next: bool) -> 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, + tx_ptr, + tx_id, + has_next, } } pub fn not_found() -> AppLayerGetTxIterTuple { AppLayerGetTxIterTuple { - tx_ptr: std::ptr::null_mut(), tx_id: 0, has_next: false, + tx_ptr: std::ptr::null_mut(), + tx_id: 0, + has_next: false, } } } /// LoggerFlags tracks which loggers have already been executed. #[repr(C)] -#[derive(Default, Debug,PartialEq, Eq)] +#[derive(Default, Debug, PartialEq, Eq)] pub struct LoggerFlags { flags: u32, } impl LoggerFlags { - pub fn new() -> Self { Default::default() } @@ -529,33 +559,34 @@ impl LoggerFlags { pub fn set(&mut self, bits: u32) { self.flags = bits; } - } /// AppLayerEvent trait that will be implemented on enums that /// derive AppLayerEvent. pub trait AppLayerEvent { /// Return the enum variant of the given ID. - fn from_id(id: i32) -> Option where Self: std::marker::Sized; + fn from_id(id: i32) -> Option + where + Self: std::marker::Sized; /// Convert the enum variant to a C-style string (suffixed with \0). fn to_cstring(&self) -> &str; /// Return the enum variant for the given name. - fn from_string(s: &str) -> Option where Self: std::marker::Sized; + fn from_string(s: &str) -> Option + where + Self: std::marker::Sized; /// Return the ID value of the enum variant. fn as_i32(&self) -> i32; - unsafe extern "C" fn get_event_info( - event_name: *const std::os::raw::c_char, - event_id: *mut std::os::raw::c_int, + unsafe extern fn get_event_info( + event_name: *const std::os::raw::c_char, event_id: *mut std::os::raw::c_int, event_type: *mut core::AppLayerEventType, ) -> std::os::raw::c_int; - 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, + unsafe extern 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 core::AppLayerEventType, ) -> i8; } @@ -577,8 +608,7 @@ pub trait AppLayerEvent { /// ``` #[inline(always)] pub unsafe fn get_event_info( - event_name: *const std::os::raw::c_char, - event_id: *mut std::os::raw::c_int, + event_name: *const std::os::raw::c_char, event_id: *mut std::os::raw::c_int, event_type: *mut core::AppLayerEventType, ) -> std::os::raw::c_int { if event_name.is_null() { @@ -598,8 +628,7 @@ pub unsafe fn get_event_info( /// AppLayerEvent. #[inline(always)] pub unsafe fn get_event_info_by_id( - event_id: std::os::raw::c_int, - event_name: *mut *const std::os::raw::c_char, + event_id: std::os::raw::c_int, event_name: *mut *const std::os::raw::c_char, event_type: *mut core::AppLayerEventType, ) -> i8 { if let Some(e) = T::from_id(event_id) { @@ -645,7 +674,7 @@ pub trait State { } } -pub unsafe extern "C" fn state_get_tx_iterator, Tx: Transaction>( +pub unsafe extern fn state_get_tx_iterator, Tx: Transaction>( _ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64, _max_tx_id: u64, istate: &mut u64, ) -> AppLayerGetTxIterTuple { @@ -669,7 +698,9 @@ pub trait AppLayerFrameType { /// Create a frame type variant from a u8. /// /// None will be returned if there is no matching enum variant. - fn from_u8(value: u8) -> Option where Self: std::marker::Sized; + fn from_u8(value: u8) -> Option + where + Self: std::marker::Sized; /// Return the u8 value of the enum where the first entry has the value of 0. fn as_u8(&self) -> u8; @@ -677,14 +708,19 @@ pub trait AppLayerFrameType { /// Create a frame type variant from a &str. /// /// None will be returned if there is no matching enum variant. - fn from_str(s: &str) -> Option where Self: std::marker::Sized; + fn from_str(s: &str) -> Option + where + Self: std::marker::Sized; /// Return a pointer to a C string of the enum variant suitable as-is for /// FFI. fn to_cstring(&self) -> *const std::os::raw::c_char; /// Converts a C string formatted name to a frame type ID. - unsafe extern "C" fn ffi_id_from_name(name: *const std::os::raw::c_char) -> i32 where Self: Sized { + unsafe extern fn ffi_id_from_name(name: *const std::os::raw::c_char) -> i32 + where + Self: Sized, + { if name.is_null() { return -1; } @@ -697,7 +733,12 @@ pub trait AppLayerFrameType { } /// Converts a variant ID to an FFI safe name. - extern "C" fn ffi_name_from_id(id: u8) -> *const std::os::raw::c_char where Self: Sized { - Self::from_u8(id).map(|s| s.to_cstring()).unwrap_or_else(std::ptr::null) + extern fn ffi_name_from_id(id: u8) -> *const std::os::raw::c_char + where + Self: Sized, + { + Self::from_u8(id) + .map(|s| s.to_cstring()) + .unwrap_or_else(std::ptr::null) } } diff --git a/rust/src/applayertemplate/logger.rs b/rust/src/applayertemplate/logger.rs index 766a07acdb9d..d97c6c50a123 100644 --- a/rust/src/applayertemplate/logger.rs +++ b/rust/src/applayertemplate/logger.rs @@ -32,7 +32,7 @@ fn log_template(tx: &TemplateTransaction, js: &mut JsonBuilder) -> Result<(), Js } #[no_mangle] -pub unsafe extern "C" fn rs_template_logger_log( +pub unsafe extern fn rs_template_logger_log( tx: *mut std::os::raw::c_void, js: &mut JsonBuilder, ) -> bool { let tx = cast_pointer!(tx, TemplateTransaction); diff --git a/rust/src/applayertemplate/template.rs b/rust/src/applayertemplate/template.rs index acc6c26c37fa..21c4d17bb29b 100644 --- a/rust/src/applayertemplate/template.rs +++ b/rust/src/applayertemplate/template.rs @@ -114,7 +114,9 @@ impl TemplateState { } fn find_request(&mut self) -> Option<&mut TemplateTransaction> { - self.transactions.iter_mut().find(|tx| tx.response.is_none()) + self.transactions + .iter_mut() + .find(|tx| tx.response.is_none()) } fn parse_request(&mut self, input: &[u8]) -> AppLayerResult { @@ -188,7 +190,7 @@ impl TemplateState { Ok((rem, response)) => { start = rem; - if let Some(tx) = self.find_request() { + if let Some(tx) = self.find_request() { tx.response = Some(response); SCLogNotice!("Found response for request:"); SCLogNotice!("- Request: {:?}", tx.request); @@ -237,7 +239,7 @@ fn probe(input: &[u8]) -> nom::IResult<&[u8], ()> { // C exports. /// C entry point for a probing parser. -unsafe extern "C" fn rs_template_probing_parser( +unsafe extern fn rs_template_probing_parser( _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { // Need at least 2 bytes. @@ -250,24 +252,22 @@ unsafe extern "C" fn rs_template_probing_parser( return ALPROTO_UNKNOWN; } -extern "C" fn rs_template_state_new( - _orig_state: *mut c_void, _orig_proto: AppProto, -) -> *mut c_void { +extern fn rs_template_state_new(_orig_state: *mut c_void, _orig_proto: AppProto) -> *mut c_void { let state = TemplateState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut c_void; } -unsafe extern "C" fn rs_template_state_free(state: *mut c_void) { +unsafe extern fn rs_template_state_free(state: *mut c_void) { std::mem::drop(Box::from_raw(state as *mut TemplateState)); } -unsafe extern "C" fn rs_template_state_tx_free(state: *mut c_void, tx_id: u64) { +unsafe extern fn rs_template_state_tx_free(state: *mut c_void, tx_id: u64) { let state = cast_pointer!(state, TemplateState); state.free_tx(tx_id); } -unsafe extern "C" fn rs_template_parse_request( +unsafe extern fn rs_template_parse_request( _flow: *const Flow, state: *mut c_void, pstate: *mut c_void, stream_slice: StreamSlice, _data: *const c_void, ) -> AppLayerResult { @@ -291,7 +291,7 @@ unsafe extern "C" fn rs_template_parse_request( } } -unsafe extern "C" fn rs_template_parse_response( +unsafe extern fn rs_template_parse_response( _flow: *const Flow, state: *mut c_void, pstate: *mut c_void, stream_slice: StreamSlice, _data: *const c_void, ) -> AppLayerResult { @@ -309,7 +309,7 @@ unsafe extern "C" fn rs_template_parse_response( } } -unsafe extern "C" fn rs_template_state_get_tx(state: *mut c_void, tx_id: u64) -> *mut c_void { +unsafe extern fn rs_template_state_get_tx(state: *mut c_void, tx_id: u64) -> *mut c_void { let state = cast_pointer!(state, TemplateState); match state.get_tx(tx_id) { Some(tx) => { @@ -321,12 +321,12 @@ unsafe extern "C" fn rs_template_state_get_tx(state: *mut c_void, tx_id: u64) -> } } -unsafe extern "C" fn rs_template_state_get_tx_count(state: *mut c_void) -> u64 { +unsafe extern fn rs_template_state_get_tx_count(state: *mut c_void) -> u64 { let state = cast_pointer!(state, TemplateState); return state.tx_id; } -unsafe extern "C" fn rs_template_tx_get_alstate_progress(tx: *mut c_void, _direction: u8) -> c_int { +unsafe extern fn rs_template_tx_get_alstate_progress(tx: *mut c_void, _direction: u8) -> c_int { let tx = cast_pointer!(tx, TemplateTransaction); // Transaction is done if we have a response. @@ -341,7 +341,7 @@ unsafe extern "C" fn rs_template_tx_get_alstate_progress(tx: *mut c_void, _direc /// No required for parsing, but an example function for retrieving a /// pointer to the request buffer from C for detection. #[no_mangle] -pub unsafe extern "C" fn rs_template_get_request_buffer( +pub unsafe extern fn rs_template_get_request_buffer( tx: *mut c_void, buf: *mut *const u8, len: *mut u32, ) -> u8 { let tx = cast_pointer!(tx, TemplateTransaction); @@ -357,7 +357,7 @@ pub unsafe extern "C" fn rs_template_get_request_buffer( /// Get the response buffer for a transaction from C. #[no_mangle] -pub unsafe extern "C" fn rs_template_get_response_buffer( +pub unsafe extern fn rs_template_get_response_buffer( tx: *mut c_void, buf: *mut *const u8, len: *mut u32, ) -> u8 { let tx = cast_pointer!(tx, TemplateTransaction); @@ -378,7 +378,7 @@ export_state_data_get!(rs_template_get_state_data, TemplateState); const PARSER_NAME: &[u8] = b"template\0"; #[no_mangle] -pub unsafe extern "C" fn rs_template_register_parser() { +pub unsafe extern fn rs_template_register_parser() { /* TEMPLATE_START_REMOVE */ if crate::conf::conf_get_node("app-layer.protocols.template").is_none() { return; diff --git a/rust/src/asn1/mod.rs b/rust/src/asn1/mod.rs index cf382cf6077c..2de79ab0875c 100644 --- a/rust/src/asn1/mod.rs +++ b/rust/src/asn1/mod.rs @@ -107,9 +107,7 @@ impl<'a> Asn1<'a> { && obj.header.is_primitive()) { if let BerObjectContent::BitString(bits, _v) = &obj.content { - if len > 0 - && *bits as usize > len.saturating_mul(8) - { + if len > 0 && *bits as usize > len.saturating_mul(8) { return Some(Asn1Check::BitstringOverflow); } } @@ -217,7 +215,7 @@ fn asn1_decode<'a>( /// input must be a valid buffer of at least input_len bytes /// pointer must be freed using `rs_asn1_free` #[no_mangle] -pub unsafe extern "C" fn rs_asn1_decode( +pub unsafe extern fn rs_asn1_decode( input: *const u8, input_len: u32, buffer_offset: u32, ad_ptr: *const DetectAsn1Data, ) -> *mut Asn1<'static> { if input.is_null() || input_len == 0 || ad_ptr.is_null() { @@ -226,7 +224,7 @@ pub unsafe extern "C" fn rs_asn1_decode( let slice = build_slice!(input, input_len as usize); - let ad = &*ad_ptr ; + let ad = &*ad_ptr; let res = asn1_decode(slice, buffer_offset, ad); @@ -242,7 +240,7 @@ pub unsafe extern "C" fn rs_asn1_decode( /// /// ptr must be a valid object obtained using `rs_asn1_decode` #[no_mangle] -pub unsafe extern "C" fn rs_asn1_free(ptr: *mut Asn1) { +pub unsafe extern fn rs_asn1_free(ptr: *mut Asn1) { if ptr.is_null() { return; } @@ -261,7 +259,7 @@ pub unsafe extern "C" fn rs_asn1_free(ptr: *mut Asn1) { /// /// Returns 1 if any of the options match, 0 if not #[no_mangle] -pub unsafe extern "C" fn rs_asn1_checks(ptr: *const Asn1, ad_ptr: *const DetectAsn1Data) -> u8 { +pub unsafe extern fn rs_asn1_checks(ptr: *const Asn1, ad_ptr: *const DetectAsn1Data) -> u8 { if ptr.is_null() || ad_ptr.is_null() { return 0; } diff --git a/rust/src/asn1/parse_rules.rs b/rust/src/asn1/parse_rules.rs index 540734c72fa5..8b2d568ddb46 100644 --- a/rust/src/asn1/parse_rules.rs +++ b/rust/src/asn1/parse_rules.rs @@ -34,7 +34,7 @@ const ASN1_DEFAULT_MAX_FRAMES: u16 = 30; /// /// pointer must be free'd using `rs_detect_asn1_free` #[no_mangle] -pub unsafe extern "C" fn rs_detect_asn1_parse(input: *const c_char) -> *mut DetectAsn1Data { +pub unsafe extern fn rs_detect_asn1_parse(input: *const c_char) -> *mut DetectAsn1Data { if input.is_null() { return std::ptr::null_mut(); } @@ -75,7 +75,7 @@ pub unsafe extern "C" fn rs_detect_asn1_parse(input: *const c_char) -> *mut Dete /// /// ptr must be a valid object obtained using `rs_detect_asn1_parse` #[no_mangle] -pub unsafe extern "C" fn rs_detect_asn1_free(ptr: *mut DetectAsn1Data) { +pub unsafe extern fn rs_detect_asn1_free(ptr: *mut DetectAsn1Data) { if ptr.is_null() { return; } @@ -125,10 +125,7 @@ fn parse_i32_number(input: &str) -> IResult<&str, i32> { pub(super) fn asn1_parse_rule(input: &str) -> IResult<&str, DetectAsn1Data> { // If nothing to parse, return if input.is_empty() { - return Err(Err::Error(make_error( - input, - ErrorKind::Eof, - ))); + return Err(Err::Error(make_error(input, ErrorKind::Eof))); } // Rule parsing functions @@ -196,10 +193,7 @@ pub(super) fn asn1_parse_rule(input: &str) -> IResult<&str, DetectAsn1Data> { } else if let Some((_, v)) = relative_offset { data.relative_offset = Some(v); } else { - return Err(Err::Error(make_error( - rest, - ErrorKind::Verify, - ))); + return Err(Err::Error(make_error(rest, ErrorKind::Verify))); } rest = new_rest; diff --git a/rust/src/bittorrent_dht/bittorrent_dht.rs b/rust/src/bittorrent_dht/bittorrent_dht.rs index 8c6857dc5d92..d02b6cacf602 100644 --- a/rust/src/bittorrent_dht/bittorrent_dht.rs +++ b/rust/src/bittorrent_dht/bittorrent_dht.rs @@ -19,7 +19,7 @@ use crate::applayer::{self, *}; use crate::bittorrent_dht::parser::{ parse_bittorrent_dht_packet, BitTorrentDHTError, BitTorrentDHTRequest, BitTorrentDHTResponse, }; -use crate::core::{AppProto, Flow, ALPROTO_UNKNOWN, IPPROTO_UDP, Direction}; +use crate::core::{AppProto, Direction, Flow, ALPROTO_UNKNOWN, IPPROTO_UDP}; use std::ffi::CString; use std::os::raw::c_char; @@ -47,10 +47,10 @@ pub struct BitTorrentDHTTransaction { impl BitTorrentDHTTransaction { pub fn new(direction: Direction) -> Self { - Self { - tx_data: AppLayerTxData::for_direction(direction), - ..Default::default() - } + Self { + tx_data: AppLayerTxData::for_direction(direction), + ..Default::default() + } } /// Set an event on the transaction @@ -142,7 +142,7 @@ export_tx_data_get!(rs_bittorrent_dht_get_tx_data, BitTorrentDHTTransaction); export_state_data_get!(rs_bittorrent_dht_get_state_data, BitTorrentDHTState); #[no_mangle] -pub extern "C" fn rs_bittorrent_dht_state_new( +pub extern fn rs_bittorrent_dht_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = BitTorrentDHTState::new(); @@ -151,40 +151,48 @@ pub extern "C" fn rs_bittorrent_dht_state_new( } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_state_free(state: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_bittorrent_dht_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(Box::from_raw(state as *mut BitTorrentDHTState)); } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_state_tx_free( - state: *mut std::os::raw::c_void, tx_id: u64, -) { +pub unsafe extern fn rs_bittorrent_dht_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, BitTorrentDHTState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_parse_ts( +pub unsafe extern fn rs_bittorrent_dht_parse_ts( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { return rs_bittorrent_dht_parse( - _flow, state, _pstate, stream_slice, - _data, crate::core::Direction::ToServer); + _flow, + state, + _pstate, + stream_slice, + _data, + crate::core::Direction::ToServer, + ); } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_parse_tc( +pub unsafe extern fn rs_bittorrent_dht_parse_tc( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { return rs_bittorrent_dht_parse( - _flow, state, _pstate, stream_slice, - _data, crate::core::Direction::ToClient); + _flow, + state, + _pstate, + stream_slice, + _data, + crate::core::Direction::ToClient, + ); } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_parse( +pub unsafe extern fn rs_bittorrent_dht_parse( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, direction: crate::core::Direction, @@ -195,7 +203,7 @@ pub unsafe extern "C" fn rs_bittorrent_dht_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_state_get_tx( +pub unsafe extern fn rs_bittorrent_dht_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, BitTorrentDHTState); @@ -210,15 +218,13 @@ pub unsafe extern "C" fn rs_bittorrent_dht_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_state_get_tx_count( - state: *mut std::os::raw::c_void, -) -> u64 { +pub unsafe extern fn rs_bittorrent_dht_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, BitTorrentDHTState); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_tx_get_alstate_progress( +pub unsafe extern fn rs_bittorrent_dht_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, BitTorrentDHTTransaction); @@ -232,7 +238,7 @@ pub unsafe extern "C" fn rs_bittorrent_dht_tx_get_alstate_progress( } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_state_get_tx_iterator( +pub unsafe extern fn rs_bittorrent_dht_state_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, ) -> applayer::AppLayerGetTxIterTuple { @@ -253,7 +259,7 @@ pub unsafe extern "C" fn rs_bittorrent_dht_state_get_tx_iterator( const PARSER_NAME: &[u8] = b"bittorrent-dht\0"; #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_udp_register_parser() { +pub unsafe extern fn rs_bittorrent_dht_udp_register_parser() { let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, default_port: std::ptr::null(), diff --git a/rust/src/bittorrent_dht/logger.rs b/rust/src/bittorrent_dht/logger.rs index 74ea7c59ba57..42afac6effc8 100644 --- a/rust/src/bittorrent_dht/logger.rs +++ b/rust/src/bittorrent_dht/logger.rs @@ -131,7 +131,7 @@ fn log_bittorrent_dht( } #[no_mangle] -pub unsafe extern "C" fn rs_bittorrent_dht_logger_log( +pub unsafe extern fn rs_bittorrent_dht_logger_log( tx: *mut std::os::raw::c_void, js: &mut JsonBuilder, ) -> bool { let tx = cast_pointer!(tx, BitTorrentDHTTransaction); diff --git a/rust/src/common.rs b/rust/src/common.rs index c874cc58b87d..88b30ba9e495 100644 --- a/rust/src/common.rs +++ b/rust/src/common.rs @@ -114,7 +114,7 @@ pub fn rust_string_to_c(s: String) -> *mut c_char { /// /// s must be allocated by rust, using `CString::new` #[no_mangle] -pub unsafe extern "C" fn rs_cstring_free(s: *mut c_char) { +pub unsafe extern fn rs_cstring_free(s: *mut c_char) { if s.is_null() { return; } @@ -135,9 +135,7 @@ pub fn to_hex(input: &[u8]) -> String { } #[no_mangle] -pub unsafe extern "C" fn rs_to_hex( - output: *mut u8, out_len: usize, input: *const u8, in_len: usize, -) { +pub unsafe extern fn rs_to_hex(output: *mut u8, out_len: usize, input: *const u8, in_len: usize) { if out_len < 2 * in_len + 1 { return; } @@ -152,7 +150,7 @@ pub unsafe extern "C" fn rs_to_hex( } #[no_mangle] -pub unsafe extern "C" fn rs_to_hex_sep( +pub unsafe extern fn rs_to_hex_sep( output: *mut u8, out_len: usize, sep: u8, input: *const u8, in_len: usize, ) { if out_len < 3 * in_len { diff --git a/rust/src/conf.rs b/rust/src/conf.rs index 50acf6cae895..110e7e6a5ebc 100644 --- a/rust/src/conf.rs +++ b/rust/src/conf.rs @@ -17,26 +17,24 @@ //! Module for retrieving configuration details. -use std::os::raw::c_char; -use std::os::raw::c_void; -use std::os::raw::c_int; -use std::ffi::{CString, CStr}; -use std::ptr; -use std::str; use nom7::{ character::complete::{multispace0, not_line_ending}, - sequence::{preceded, tuple}, - number::complete::double, combinator::verify, + number::complete::double, + sequence::{preceded, tuple}, IResult, }; +use std::ffi::{CStr, CString}; +use std::os::raw::c_char; +use std::os::raw::c_int; +use std::os::raw::c_void; +use std::ptr; +use std::str; extern { fn ConfGet(key: *const c_char, res: *mut *const c_char) -> i8; - fn ConfGetChildValue(conf: *const c_void, key: *const c_char, - vptr: *mut *const c_char) -> i8; - fn ConfGetChildValueBool(conf: *const c_void, key: *const c_char, - vptr: *mut c_int) -> i8; + fn ConfGetChildValue(conf: *const c_void, key: *const c_char, vptr: *mut *const c_char) -> i8; + fn ConfGetChildValueBool(conf: *const c_void, key: *const c_char, vptr: *mut c_int) -> i8; fn ConfGetNode(key: *const c_char) -> *const c_void; } @@ -71,9 +69,7 @@ pub fn conf_get(key: &str) -> Option<&str> { return None; } - let value = str::from_utf8(unsafe{ - CStr::from_ptr(vptr).to_bytes() - }).unwrap(); + let value = str::from_utf8(unsafe { CStr::from_ptr(vptr).to_bytes() }).unwrap(); return Some(value); } @@ -85,8 +81,8 @@ pub fn conf_get_bool(key: &str) -> bool { match val { "1" | "yes" | "true" | "on" => { return true; - }, - _ => {}, + } + _ => {} } } @@ -100,9 +96,8 @@ pub struct ConfNode { } impl ConfNode { - pub fn wrap(conf: *const c_void) -> Self { - return Self { conf } + return Self { conf }; } pub fn get_child_value(&self, key: &str) -> Option<&str> { @@ -110,9 +105,7 @@ impl ConfNode { unsafe { let s = CString::new(key).unwrap(); - if ConfGetChildValue(self.conf, - s.as_ptr(), - &mut vptr) != 1 { + if ConfGetChildValue(self.conf, s.as_ptr(), &mut vptr) != 1 { return None; } } @@ -121,9 +114,7 @@ impl ConfNode { return None; } - let value = str::from_utf8(unsafe{ - CStr::from_ptr(vptr).to_bytes() - }).unwrap(); + let value = str::from_utf8(unsafe { CStr::from_ptr(vptr).to_bytes() }).unwrap(); return Some(value); } @@ -133,9 +124,7 @@ impl ConfNode { unsafe { let s = CString::new(key).unwrap(); - if ConfGetChildValueBool(self.conf, - s.as_ptr(), - &mut vptr) != 1 { + if ConfGetChildValueBool(self.conf, s.as_ptr(), &mut vptr) != 1 { return false; } } @@ -145,13 +134,12 @@ impl ConfNode { } return false; } - } -const BYTE: u64 = 1; -const KILOBYTE: u64 = 1024; -const MEGABYTE: u64 = 1_048_576; -const GIGABYTE: u64 = 1_073_741_824; +const BYTE: u64 = 1; +const KILOBYTE: u64 = 1024; +const MEGABYTE: u64 = 1_048_576; +const GIGABYTE: u64 = 1_073_741_824; /// Helper function to retrieve memory unit from a string slice /// @@ -163,11 +151,11 @@ const GIGABYTE: u64 = 1_073_741_824; fn get_memunit(unit: &str) -> u64 { let unit = &unit.to_lowercase()[..]; match unit { - "b" => { BYTE } - "kb" => { KILOBYTE } - "mb" => { MEGABYTE } - "gb" => { GIGABYTE } - _ => { 0 } + "b" => BYTE, + "kb" => KILOBYTE, + "mb" => MEGABYTE, + "gb" => GIGABYTE, + _ => 0, } } @@ -184,8 +172,10 @@ pub fn get_memval(arg: &str) -> Result { let arg = arg.trim(); let val: f64; let mut unit: &str; - let mut parser = tuple((preceded(multispace0, double), - preceded(multispace0, verify(not_line_ending, |c: &str| c.len() < 3)))); + let mut parser = tuple(( + preceded(multispace0, double), + preceded(multispace0, verify(not_line_ending, |c: &str| c.len() < 3)), + )); let r: IResult<&str, (f64, &str)> = parser(arg); if let Ok(r) = r { val = (r.1).0; @@ -211,7 +201,7 @@ mod tests { #[test] fn test_memval_nospace() { let s = "10"; - let res = 10 ; + let res = 10; assert_eq!(Ok(10), get_memval(s)); let s = "10kb"; @@ -233,7 +223,7 @@ mod tests { #[test] fn test_memval_space_start() { let s = " 10"; - let res = 10 ; + let res = 10; assert_eq!(Ok(res), get_memval(s)); let s = " 10Kb"; @@ -252,7 +242,7 @@ mod tests { #[test] fn test_memval_space_end() { let s = " 10 "; - let res = 10 ; + let res = 10; assert_eq!(Ok(res), get_memval(s)); let s = "10Kb "; @@ -271,7 +261,7 @@ mod tests { #[test] fn test_memval_space_in_bw() { let s = " 10 "; - let res = 10 ; + let res = 10; assert_eq!(Ok(res), get_memval(s)); let s = "10 Kb "; diff --git a/rust/src/core.rs b/rust/src/core.rs index abb27ea578fe..27cd6dc46aed 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -17,9 +17,9 @@ //! This module exposes items from the core "C" code to Rust. -use std; -use crate::filecontainer::*; use crate::debug_validate_fail; +use crate::filecontainer::*; +use std; /// Opaque C types. pub enum DetectEngineState {} @@ -33,16 +33,16 @@ pub enum AppLayerEventType { APP_LAYER_EVENT_TYPE_PACKET = 2, } -pub const STREAM_START: u8 = 0x01; -pub const STREAM_EOF: u8 = 0x02; +pub const STREAM_START: u8 = 0x01; +pub const STREAM_EOF: u8 = 0x02; pub const STREAM_TOSERVER: u8 = 0x04; pub const STREAM_TOCLIENT: u8 = 0x08; -pub const STREAM_GAP: u8 = 0x10; -pub const STREAM_DEPTH: u8 = 0x20; -pub const STREAM_MIDSTREAM:u8 = 0x40; -pub const DIR_BOTH: u8 = 0b0000_1100; -const DIR_TOSERVER: u8 = 0b0000_0100; -const DIR_TOCLIENT: u8 = 0b0000_1000; +pub const STREAM_GAP: u8 = 0x10; +pub const STREAM_DEPTH: u8 = 0x20; +pub const STREAM_MIDSTREAM: u8 = 0x40; +pub const DIR_BOTH: u8 = 0b0000_1100; +const DIR_TOSERVER: u8 = 0b0000_0100; +const DIR_TOCLIENT: u8 = 0b0000_1000; #[repr(C)] #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -54,17 +54,19 @@ pub enum Direction { impl Direction { /// Return true if the direction is to server. pub fn is_to_server(&self) -> bool { - matches!(self, Self::ToServer) + matches!(self, Self::ToServer) } /// Return true if the direction is to client. pub fn is_to_client(&self) -> bool { - matches!(self, Self::ToClient) + matches!(self, Self::ToClient) } } impl Default for Direction { - fn default() -> Self { Direction::ToServer } + fn default() -> Self { + Direction::ToServer + } } impl std::fmt::Display for Direction { @@ -101,27 +103,33 @@ impl From for u8 { // Application layer protocol identifiers (app-layer-protos.h) pub type AppProto = u16; -pub const ALPROTO_UNKNOWN : AppProto = 0; -pub static mut ALPROTO_FAILED : AppProto = 0; // updated during init +pub const ALPROTO_UNKNOWN: AppProto = 0; +pub static mut ALPROTO_FAILED: AppProto = 0; // updated during init -pub const IPPROTO_TCP : u8 = 6; -pub const IPPROTO_UDP : u8 = 17; +pub const IPPROTO_TCP: u8 = 6; +pub const IPPROTO_UDP: u8 = 17; /* macro_rules!BIT_U8 { ($x:expr) => (1 << $x); } */ -macro_rules!BIT_U16 { - ($x:expr) => (1 << $x); +macro_rules! BIT_U16 { + ($x:expr) => { + 1 << $x + }; } -macro_rules!BIT_U32 { - ($x:expr) => (1 << $x); +macro_rules! BIT_U32 { + ($x:expr) => { + 1 << $x + }; } -macro_rules!BIT_U64 { - ($x:expr) => (1 << $x); +macro_rules! BIT_U64 { + ($x:expr) => { + 1 << $x + }; } // Flow flags @@ -137,66 +145,72 @@ extern { // #[allow(non_snake_case)] -pub type SCLogMessageFunc = - extern "C" fn(level: std::os::raw::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) -> std::os::raw::c_int; +pub type SCLogMessageFunc = extern fn( + level: std::os::raw::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, +) -> std::os::raw::c_int; -pub type DetectEngineStateFreeFunc = - extern "C" fn(state: *mut DetectEngineState); +pub type DetectEngineStateFreeFunc = extern fn(state: *mut DetectEngineState); pub type AppLayerParserTriggerRawStreamReassemblyFunc = - extern "C" fn (flow: *const Flow, direction: i32); + extern fn(flow: *const Flow, direction: i32); pub type AppLayerDecoderEventsSetEventRawFunc = - extern "C" fn (events: *mut *mut AppLayerDecoderEvents, - event: u8); + extern fn(events: *mut *mut AppLayerDecoderEvents, event: u8); -pub type AppLayerDecoderEventsFreeEventsFunc = - extern "C" fn (events: *mut *mut AppLayerDecoderEvents); +pub type AppLayerDecoderEventsFreeEventsFunc = extern fn(events: *mut *mut AppLayerDecoderEvents); pub enum StreamingBufferConfig {} // Opaque flow type (defined in C) pub enum HttpRangeContainerBlock {} -pub type SCHttpRangeFreeBlock = extern "C" fn ( - c: *mut HttpRangeContainerBlock); -pub type SCHTPFileCloseHandleRange = extern "C" fn ( - sbcfg: &StreamingBufferConfig, - fc: *mut FileContainer, - flags: u16, - c: *mut HttpRangeContainerBlock, - data: *const u8, - data_len: u32) -> bool; -pub type SCFileOpenFileWithId = extern "C" fn ( - file_container: &FileContainer, - sbcfg: &StreamingBufferConfig, - track_id: u32, - name: *const u8, name_len: u16, - data: *const u8, data_len: u32, - flags: u16) -> i32; -pub type SCFileCloseFileById = extern "C" fn ( - file_container: &FileContainer, - sbcfg: &StreamingBufferConfig, - track_id: u32, - data: *const u8, data_len: u32, - flags: u16) -> i32; -pub type SCFileAppendDataById = extern "C" fn ( - file_container: &FileContainer, - sbcfg: &StreamingBufferConfig, - track_id: u32, - data: *const u8, data_len: u32) -> i32; -pub type SCFileAppendGAPById = extern "C" fn ( - file_container: &FileContainer, - sbcfg: &StreamingBufferConfig, - track_id: u32, - data: *const u8, data_len: u32) -> i32; -pub type SCFileContainerRecycle = extern "C" fn ( - file_container: &FileContainer, - sbcfg: &StreamingBufferConfig); +pub type SCHttpRangeFreeBlock = extern fn(c: *mut HttpRangeContainerBlock); +pub type SCHTPFileCloseHandleRange = extern fn( + sbcfg: &StreamingBufferConfig, + fc: *mut FileContainer, + flags: u16, + c: *mut HttpRangeContainerBlock, + data: *const u8, + data_len: u32, +) -> bool; +pub type SCFileOpenFileWithId = extern fn( + file_container: &FileContainer, + sbcfg: &StreamingBufferConfig, + track_id: u32, + name: *const u8, + name_len: u16, + data: *const u8, + data_len: u32, + flags: u16, +) -> i32; +pub type SCFileCloseFileById = extern fn( + file_container: &FileContainer, + sbcfg: &StreamingBufferConfig, + track_id: u32, + data: *const u8, + data_len: u32, + flags: u16, +) -> i32; +pub type SCFileAppendDataById = extern fn( + file_container: &FileContainer, + sbcfg: &StreamingBufferConfig, + track_id: u32, + data: *const u8, + data_len: u32, +) -> i32; +pub type SCFileAppendGAPById = extern fn( + file_container: &FileContainer, + sbcfg: &StreamingBufferConfig, + track_id: u32, + data: *const u8, + data_len: u32, +) -> i32; +pub type SCFileContainerRecycle = + extern fn(file_container: &FileContainer, sbcfg: &StreamingBufferConfig); // A Suricata context that is passed in from C. This is alternative to // using functions from Suricata directly, so they can be wrapped so @@ -223,7 +237,10 @@ pub struct SuricataContext { pub FileAppendGAP: SCFileAppendGAPById, pub FileContainerRecycle: SCFileContainerRecycle, - pub AppLayerRegisterParser: extern fn(parser: *const crate::applayer::RustParser, alproto: AppProto) -> std::os::raw::c_int, + pub AppLayerRegisterParser: extern fn( + parser: *const crate::applayer::RustParser, + alproto: AppProto, + ) -> std::os::raw::c_int, } #[allow(non_snake_case)] @@ -239,8 +256,7 @@ extern { pub static mut SC: Option<&'static SuricataContext> = None; -pub fn init_ffi(context: &'static SuricataContext) -{ +pub fn init_ffi(context: &'static SuricataContext) { unsafe { SC = Some(context); ALPROTO_FAILED = StringToAppProto("failed\0".as_ptr()); @@ -248,14 +264,12 @@ pub fn init_ffi(context: &'static SuricataContext) } #[no_mangle] -pub extern "C" fn rs_init(context: &'static SuricataContext) -{ +pub extern fn rs_init(context: &'static SuricataContext) { init_ffi(context); } /// DetectEngineStateFree wrapper. -pub fn sc_detect_engine_state_free(state: *mut DetectEngineState) -{ +pub fn sc_detect_engine_state_free(state: *mut DetectEngineState) { unsafe { if let Some(c) = SC { (c.DetectEngineStateFree)(state); @@ -274,8 +288,8 @@ pub fn sc_app_layer_parser_trigger_raw_stream_reassembly(flow: *const Flow, dire /// AppLayerDecoderEventsSetEventRaw wrapper. pub fn sc_app_layer_decoder_events_set_event_raw( - events: *mut *mut AppLayerDecoderEvents, event: u8) -{ + events: *mut *mut AppLayerDecoderEvents, event: u8, +) { unsafe { if let Some(c) = SC { (c.AppLayerDecoderEventsSetEventRaw)(events, event); @@ -284,9 +298,7 @@ pub fn sc_app_layer_decoder_events_set_event_raw( } /// AppLayerDecoderEventsFreeEvents wrapper. -pub fn sc_app_layer_decoder_events_free_events( - events: *mut *mut AppLayerDecoderEvents) -{ +pub fn sc_app_layer_decoder_events_free_events(events: *mut *mut AppLayerDecoderEvents) { unsafe { if let Some(c) = SC { (c.AppLayerDecoderEventsFreeEvents)(events); @@ -307,7 +319,6 @@ extern { /// Rust implementation of Flow. impl Flow { - /// Return the time of the last flow update as a `Duration` /// since the epoch. pub fn get_last_time(&mut self) -> std::time::Duration { @@ -336,10 +347,10 @@ mod test { #[test] fn test_direction() { - assert!(Direction::ToServer.is_to_server()); - assert!(!Direction::ToServer.is_to_client()); + assert!(Direction::ToServer.is_to_server()); + assert!(!Direction::ToServer.is_to_client()); - assert!(Direction::ToClient.is_to_client()); - assert!(!Direction::ToClient.is_to_server()); + assert!(Direction::ToClient.is_to_client()); + assert!(!Direction::ToClient.is_to_server()); } } diff --git a/rust/src/dcerpc/dcerpc.rs b/rust/src/dcerpc/dcerpc.rs index 759d5c26343a..61b612b08f75 100644 --- a/rust/src/dcerpc/dcerpc.rs +++ b/rust/src/dcerpc/dcerpc.rs @@ -16,6 +16,7 @@ */ use crate::applayer::{self, *}; +use crate::conf::conf_get; use crate::core::{self, *}; use crate::dcerpc::parser; use nom7::error::{Error, ErrorKind}; @@ -23,9 +24,8 @@ use nom7::number::Endianness; use nom7::{Err, IResult, Needed}; use std; use std::cmp; -use std::ffi::CString; use std::collections::VecDeque; -use crate::conf::conf_get; +use std::ffi::CString; // Constant DCERPC UDP Header length pub const DCERPC_HDR_LEN: u16 = 16; @@ -206,7 +206,7 @@ impl DCERPCTransaction { activityuuid: Vec::new(), tx_data: AppLayerTxData::new(), ..Default::default() - } + }; } pub fn get_req_ctxid(&self) -> u16 { @@ -322,7 +322,8 @@ pub struct DCERPCState { pub tc_gap: bool, pub ts_ssn_gap: bool, pub tc_ssn_gap: bool, - pub ts_ssn_trunc: bool, /// true if Truncated in this direction + pub ts_ssn_trunc: bool, + /// true if Truncated in this direction pub tc_ssn_trunc: bool, pub flow: Option<*const core::Flow>, state_data: AppLayerStateData, @@ -344,7 +345,7 @@ impl DCERPCState { data_needed_for_dir: Direction::ToServer, prev_dir: Direction::ToServer, ..Default::default() - } + }; } fn create_tx(&mut self, call_id: u32) -> DCERPCTransaction { @@ -372,13 +373,14 @@ impl DCERPCState { } pub fn free_tx(&mut self, tx_id: u64) { - SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id+1); + SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id + 1); 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.id == tx_id { //+ 1 { + if tx.id == tx_id { + //+ 1 { found = true; index = i; SCLogDebug!("tx {} progress {}/{}", tx.id, tx.req_done, tx.resp_done); @@ -386,8 +388,14 @@ impl DCERPCState { } } if found { - SCLogDebug!("freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", - tx_id, tx_id+1, index, self.transactions.len(), self.tx_id); + SCLogDebug!( + "freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", + tx_id, + tx_id + 1, + index, + self.transactions.len(), + self.tx_id + ); self.tx_index_completed = 0; self.transactions.remove(index); } @@ -512,7 +520,9 @@ impl DCERPCState { /// /// Return value: /// Option mutable reference to DCERPCTransaction - pub fn get_tx_by_call_id(&mut self, call_id: u32, dir: Direction) -> Option<&mut DCERPCTransaction> { + pub fn get_tx_by_call_id( + &mut self, call_id: u32, dir: Direction, + ) -> Option<&mut DCERPCTransaction> { let cmd = self.get_hdr_type().unwrap_or(0); for tx in &mut self.transactions { let found = tx.call_id == call_id; @@ -542,17 +552,22 @@ impl DCERPCState { Direction::ToServer => { self.ts_gap = true; self.ts_ssn_gap = true; - }, + } Direction::ToClient => { self.tc_gap = true; self.tc_ssn_gap = true; - }, + } } AppLayerResult::ok() } pub fn post_gap_housekeeping(&mut self, dir: Direction) { - SCLogDebug!("ts ssn gap: {:?}, tc ssn gap: {:?}, dir: {:?}", self.ts_ssn_gap, self.tc_ssn_gap, dir); + SCLogDebug!( + "ts ssn gap: {:?}, tc ssn gap: {:?}, dir: {:?}", + self.ts_ssn_gap, + self.tc_ssn_gap, + dir + ); if self.ts_ssn_gap && dir == Direction::ToServer { for tx in &mut self.transactions { if tx.id >= self.tx_id { @@ -588,7 +603,7 @@ impl DCERPCState { } } - pub fn search_dcerpc_record<'a>(&mut self, i: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> { + pub fn search_dcerpc_record<'a>(&mut self, i: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { let mut d = i; while d.len() >= 2 { if d[0] == 0x05 && d[1] == 0x00 { @@ -631,7 +646,10 @@ impl DCERPCState { SCLogDebug!("Insufficient data while parsing DCERPC header"); -1 } - Err(Err::Error(Error{code:ErrorKind::Eof, ..})) => { + Err(Err::Error(Error { + code: ErrorKind::Eof, + .. + })) => { SCLogDebug!("EoF reached while parsing DCERPC header"); -1 } @@ -697,7 +715,10 @@ impl DCERPCState { tx.req_cmd = self.get_hdr_type().unwrap_or(0); tx.req_done = true; if let Some(flow) = self.flow { - sc_app_layer_parser_trigger_raw_stream_reassembly(flow, Direction::ToServer as i32); + sc_app_layer_parser_trigger_raw_stream_reassembly( + flow, + Direction::ToServer as i32, + ); } tx.frag_cnt_ts = 1; self.transactions.push_back(tx); @@ -780,7 +801,10 @@ impl DCERPCState { tx.req_done = true; tx.frag_cnt_ts = 1; if let Some(flow) = self.flow { - sc_app_layer_parser_trigger_raw_stream_reassembly(flow, Direction::ToServer as i32); + sc_app_layer_parser_trigger_raw_stream_reassembly( + flow, + Direction::ToServer as i32, + ); } } DCERPC_TYPE_RESPONSE => { @@ -795,7 +819,10 @@ impl DCERPCState { tx.resp_done = true; tx.frag_cnt_tc = 1; if let Some(flow) = self.flow { - sc_app_layer_parser_trigger_raw_stream_reassembly(flow, Direction::ToClient as i32); + sc_app_layer_parser_trigger_raw_stream_reassembly( + flow, + Direction::ToClient as i32, + ); } } _ => { @@ -829,7 +856,9 @@ impl DCERPCState { /// Return value: /// * Success: Number of bytes successfully parsed. /// * Failure: -1 in case fragment length defined by header mismatches the data. - pub fn handle_common_stub(&mut self, input: &[u8], bytes_consumed: usize, dir: Direction) -> i32 { + pub fn handle_common_stub( + &mut self, input: &[u8], bytes_consumed: usize, dir: Direction, + ) -> i32 { let fraglen = self.get_hdr_fraglen().unwrap_or(0); if (fraglen as usize) < bytes_consumed + (DCERPC_HDR_LEN as usize) { return -1; @@ -912,7 +941,9 @@ impl DCERPCState { self.query_completed = false; // Skip the record since this means that its in the middle of a known length record - if (self.ts_gap && direction == Direction::ToServer) || (self.tc_gap && direction == Direction::ToClient) { + if (self.ts_gap && direction == Direction::ToServer) + || (self.tc_gap && direction == Direction::ToClient) + { SCLogDebug!("Trying to catch up after GAP (input {})", cur_i.len()); match self.search_dcerpc_record(cur_i) { Ok((_, pg)) => { @@ -922,12 +953,12 @@ impl DCERPCState { match direction { Direction::ToServer => { self.ts_gap = false; - }, + } Direction::ToClient => { self.tc_gap = false; } } - }, + } _ => { let mut consumed = cur_i.len(); // At least 2 bytes are required to know if a new record is beginning @@ -938,7 +969,7 @@ impl DCERPCState { } SCLogDebug!("DCERPC record NOT found"); return AppLayerResult::incomplete(consumed as u32, 2); - }, + } } } @@ -1016,7 +1047,9 @@ impl DCERPCState { if retval == -1 { return AppLayerResult::err(); } - let tx = if let Some(tx) = self.get_tx_by_call_id(current_call_id, Direction::ToClient) { + let tx = if let Some(tx) = + self.get_tx_by_call_id(current_call_id, Direction::ToClient) + { tx.resp_cmd = x; tx } else { @@ -1028,7 +1061,10 @@ impl DCERPCState { tx.resp_done = true; tx.frag_cnt_tc = 1; if let Some(flow) = self.flow { - sc_app_layer_parser_trigger_raw_stream_reassembly(flow, Direction::ToClient as i32); + sc_app_layer_parser_trigger_raw_stream_reassembly( + flow, + Direction::ToClient as i32, + ); } } DCERPC_TYPE_REQUEST => { @@ -1051,11 +1087,8 @@ impl DCERPCState { self.transactions.push_back(tx); } }; - retval = self.handle_common_stub( - &buffer[parsed as usize..], - 0, - Direction::ToClient, - ); + retval = + self.handle_common_stub(&buffer[parsed as usize..], 0, Direction::ToClient); if retval < 0 { return AppLayerResult::err(); } @@ -1084,10 +1117,9 @@ impl DCERPCState { } fn evaluate_stub_params( - input: &[u8], input_len: usize, hdrflags: u8, lenleft: u16, - stub_data_buffer: &mut Vec,stub_data_buffer_reset: &mut bool, + input: &[u8], input_len: usize, hdrflags: u8, lenleft: u16, stub_data_buffer: &mut Vec, + stub_data_buffer_reset: &mut bool, ) -> u16 { - let fragtype = hdrflags & (PFC_FIRST_FRAG | PFC_LAST_FRAG); // min of usize and u16 is a valid u16 let stub_len: u16 = cmp::min(lenleft as usize, input_len) as u16; @@ -1105,37 +1137,40 @@ fn evaluate_stub_params( } #[no_mangle] -pub extern "C" fn rs_parse_dcerpc_request_gap( - state: &mut DCERPCState, - _input_len: u32, +pub extern fn rs_parse_dcerpc_request_gap( + state: &mut DCERPCState, _input_len: u32, ) -> AppLayerResult { state.parse_data_gap(Direction::ToServer) } #[no_mangle] -pub extern "C" fn rs_parse_dcerpc_response_gap( - state: &mut DCERPCState, - _input_len: u32, +pub extern fn rs_parse_dcerpc_response_gap( + state: &mut DCERPCState, _input_len: u32, ) -> AppLayerResult { state.parse_data_gap(Direction::ToClient) } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_parse_request( +pub unsafe extern fn rs_dcerpc_parse_request( flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, DCERPCState); let flags = stream_slice.flags(); - SCLogDebug!("Handling request: input_len {} flags {:x} EOF {}", - stream_slice.len(), flags, flags & core::STREAM_EOF != 0); + SCLogDebug!( + "Handling request: input_len {} flags {:x} EOF {}", + stream_slice.len(), + flags, + flags & core::STREAM_EOF != 0 + ); if flags & core::STREAM_EOF != 0 && stream_slice.is_empty() { return AppLayerResult::ok(); } /* START with MIDSTREAM set: record might be starting the middle. */ - if flags & (core::STREAM_START|core::STREAM_MIDSTREAM) == (core::STREAM_START|core::STREAM_MIDSTREAM) { + if flags & (core::STREAM_START | core::STREAM_MIDSTREAM) + == (core::STREAM_START | core::STREAM_MIDSTREAM) + { state.ts_gap = true; } if !stream_slice.is_gap() { @@ -1146,10 +1181,9 @@ pub unsafe extern "C" fn rs_dcerpc_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_parse_response( +pub unsafe extern fn rs_dcerpc_parse_response( flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, DCERPCState); let flags = stream_slice.flags(); @@ -1158,7 +1192,9 @@ pub unsafe extern "C" fn rs_dcerpc_parse_response( return AppLayerResult::ok(); } /* START with MIDSTREAM set: record might be starting the middle. */ - if flags & (core::STREAM_START|core::STREAM_MIDSTREAM) == (core::STREAM_START|core::STREAM_MIDSTREAM) { + if flags & (core::STREAM_START | core::STREAM_MIDSTREAM) + == (core::STREAM_START | core::STREAM_MIDSTREAM) + { state.tc_gap = true; } if !stream_slice.is_gap() { @@ -1169,53 +1205,69 @@ pub unsafe extern "C" fn rs_dcerpc_parse_response( } #[no_mangle] -pub extern "C" fn rs_dcerpc_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: core::AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_dcerpc_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: core::AppProto, +) -> *mut std::os::raw::c_void { let state = DCERPCState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub extern "C" fn rs_dcerpc_state_free(state: *mut std::os::raw::c_void) { - std::mem::drop(unsafe { Box::from_raw(state as *mut DCERPCState)} ); +pub extern fn rs_dcerpc_state_free(state: *mut std::os::raw::c_void) { + std::mem::drop(unsafe { Box::from_raw(state as *mut DCERPCState) }); } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_state_transaction_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_dcerpc_state_transaction_free( + state: *mut std::os::raw::c_void, tx_id: u64, +) { let dce_state = cast_pointer!(state, DCERPCState); SCLogDebug!("freeing tx {}", tx_id); dce_state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_state_trunc(state: *mut std::os::raw::c_void, direction: u8) { +pub unsafe extern fn rs_dcerpc_state_trunc(state: *mut std::os::raw::c_void, direction: u8) { let dce_state = cast_pointer!(state, DCERPCState); match direction.into() { - Direction::ToServer => { + Direction::ToServer => { dce_state.ts_ssn_trunc = true; for tx in &mut dce_state.transactions { tx.req_done = true; if let Some(flow) = dce_state.flow { - sc_app_layer_parser_trigger_raw_stream_reassembly(flow, Direction::ToServer as i32); + sc_app_layer_parser_trigger_raw_stream_reassembly( + flow, + Direction::ToServer as i32, + ); } } - SCLogDebug!("dce_state.ts_ssn_trunc = true; txs {}", dce_state.transactions.len()); + SCLogDebug!( + "dce_state.ts_ssn_trunc = true; txs {}", + dce_state.transactions.len() + ); } Direction::ToClient => { dce_state.tc_ssn_trunc = true; for tx in &mut dce_state.transactions { tx.resp_done = true; if let Some(flow) = dce_state.flow { - sc_app_layer_parser_trigger_raw_stream_reassembly(flow, Direction::ToClient as i32); + sc_app_layer_parser_trigger_raw_stream_reassembly( + flow, + Direction::ToClient as i32, + ); } } - SCLogDebug!("dce_state.tc_ssn_trunc = true; txs {}", dce_state.transactions.len()); + SCLogDebug!( + "dce_state.tc_ssn_trunc = true; txs {}", + dce_state.transactions.len() + ); } } } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_get_tx( +pub unsafe extern fn rs_dcerpc_get_tx( vtx: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let dce_state = cast_pointer!(vtx, DCERPCState); @@ -1226,14 +1278,15 @@ pub unsafe extern "C" fn rs_dcerpc_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_get_tx_cnt(vtx: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_dcerpc_get_tx_cnt(vtx: *mut std::os::raw::c_void) -> u64 { let dce_state = cast_pointer!(vtx, DCERPCState); dce_state.tx_id } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_get_alstate_progress(tx: *mut std::os::raw::c_void, direction: u8 - )-> std::os::raw::c_int { +pub unsafe extern fn rs_dcerpc_get_alstate_progress( + tx: *mut std::os::raw::c_void, direction: u8, +) -> std::os::raw::c_int { let tx = cast_pointer!(tx, DCERPCTransaction); if direction == Direction::ToServer.into() && tx.req_done { SCLogDebug!("tx {} TOSERVER progress 1 => {:?}", tx.call_id, tx); @@ -1247,16 +1300,13 @@ pub unsafe extern "C" fn rs_dcerpc_get_alstate_progress(tx: *mut std::os::raw::c } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_get_tx_data( - tx: *mut std::os::raw::c_void) - -> *mut AppLayerTxData -{ +pub unsafe extern fn rs_dcerpc_get_tx_data(tx: *mut std::os::raw::c_void) -> *mut AppLayerTxData { let tx = cast_pointer!(tx, DCERPCTransaction); return &mut tx.tx_data; } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_get_stub_data( +pub unsafe extern fn rs_dcerpc_get_stub_data( tx: &mut DCERPCTransaction, buf: *mut *const u8, len: *mut u32, endianness: *mut u8, dir: u8, ) { match dir.into() { @@ -1279,26 +1329,26 @@ fn probe(input: &[u8]) -> (bool, bool) { match parser::parse_dcerpc_header(input) { Ok((_, hdr)) => { let is_request = hdr.hdrtype == 0x00 || hdr.hdrtype == 0x0e; - let is_dcerpc = hdr.rpc_vers == 0x05 && - hdr.rpc_vers_minor == 0x00 && - hdr.packed_drep[0] & 0xee == 0 && - hdr.packed_drep[1] <= 3; + let is_dcerpc = hdr.rpc_vers == 0x05 + && hdr.rpc_vers_minor == 0x00 + && hdr.packed_drep[0] & 0xee == 0 + && hdr.packed_drep[1] <= 3; return (is_dcerpc, is_request); - }, + } Err(_) => (false, false), } } -pub unsafe extern "C" fn rs_dcerpc_probe_tcp(_f: *const core::Flow, direction: u8, input: *const u8, - len: u32, rdir: *mut u8) -> AppProto -{ +pub unsafe extern fn rs_dcerpc_probe_tcp( + _f: *const core::Flow, direction: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> AppProto { SCLogDebug!("Probing packet for DCERPC"); if len == 0 { return core::ALPROTO_UNKNOWN; } let slice: &[u8] = std::slice::from_raw_parts(input as *mut u8, len as usize); //is_incomplete is checked by caller - let (is_dcerpc, is_request, ) = probe(slice); + let (is_dcerpc, is_request) = probe(slice); if is_dcerpc { let dir = if is_request { Direction::ToServer @@ -1315,15 +1365,33 @@ pub unsafe extern "C" fn rs_dcerpc_probe_tcp(_f: *const core::Flow, direction: u fn register_pattern_probe() -> i8 { unsafe { - if AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_DCERPC, - b"|05 00|\0".as_ptr() as *const std::os::raw::c_char, 2, 0, - Direction::ToServer.into(), rs_dcerpc_probe_tcp, 0, 0) < 0 { + if AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_DCERPC, + b"|05 00|\0".as_ptr() as *const std::os::raw::c_char, + 2, + 0, + Direction::ToServer.into(), + rs_dcerpc_probe_tcp, + 0, + 0, + ) < 0 + { SCLogDebug!("TOSERVER => AppLayerProtoDetectPMRegisterPatternCSwPP FAILED"); return -1; } - if AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_DCERPC, - b"|05 00|\0".as_ptr() as *const std::os::raw::c_char, 2, 0, - Direction::ToClient.into(), rs_dcerpc_probe_tcp, 0, 0) < 0 { + if AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_DCERPC, + b"|05 00|\0".as_ptr() as *const std::os::raw::c_char, + 2, + 0, + Direction::ToClient.into(), + rs_dcerpc_probe_tcp, + 0, + 0, + ) < 0 + { SCLogDebug!("TOCLIENT => AppLayerProtoDetectPMRegisterPatternCSwPP FAILED"); return -1; } @@ -1338,7 +1406,7 @@ export_state_data_get!(rs_dcerpc_get_state_data, DCERPCState); pub const PARSER_NAME: &[u8] = b"dcerpc\0"; #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_register_parser() { +pub unsafe extern fn rs_dcerpc_register_parser() { let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, default_port: std::ptr::null(), @@ -1358,7 +1426,7 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() { tx_comp_st_tc: 1, tx_get_progress: rs_dcerpc_get_alstate_progress, get_eventinfo: None, - get_eventinfo_byid : None, + get_eventinfo_byid: None, localstorage_new: None, localstorage_free: None, get_tx_files: None, @@ -1374,21 +1442,13 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() { let ip_proto_str = CString::new("tcp").unwrap(); - if AppLayerProtoDetectConfProtoDetectionEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let alproto = AppLayerRegisterProtocolDetection(&parser, 1); ALPROTO_DCERPC = alproto; if register_pattern_probe() < 0 { return; } - if AppLayerParserConfParserEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let _ = AppLayerRegisterParser(&parser, alproto); } if let Some(val) = conf_get("app-layer.protocols.dcerpc.max-tx") { diff --git a/rust/src/dcerpc/dcerpc_udp.rs b/rust/src/dcerpc/dcerpc_udp.rs index 83707bddcb21..9e0351a1cd58 100644 --- a/rust/src/dcerpc/dcerpc_udp.rs +++ b/rust/src/dcerpc/dcerpc_udp.rs @@ -18,14 +18,14 @@ use crate::applayer::{self, *}; use crate::core::{self, Direction, DIR_BOTH}; use crate::dcerpc::dcerpc::{ - DCERPCTransaction, DCERPC_MAX_TX, DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, PFCL1_FRAG, PFCL1_LASTFRAG, - rs_dcerpc_get_alstate_progress, ALPROTO_DCERPC, PARSER_NAME, + rs_dcerpc_get_alstate_progress, DCERPCTransaction, ALPROTO_DCERPC, DCERPC_MAX_TX, + DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, PARSER_NAME, PFCL1_FRAG, PFCL1_LASTFRAG, }; +use crate::dcerpc::parser; use nom7::Err; use std; -use std::ffi::CString; use std::collections::VecDeque; -use crate::dcerpc::parser; +use std::ffi::CString; // Constant DCERPC UDP Header length pub const DCERPC_UDP_HDR_LEN: i32 = 80; @@ -76,7 +76,7 @@ impl DCERPCUDPState { Default::default() } - fn create_tx(&mut self, hdr: &DCERPCHdrUdp) -> DCERPCTransaction { + fn create_tx(&mut self, hdr: &DCERPCHdrUdp) -> DCERPCTransaction { let mut tx = DCERPCTransaction::new(); tx.id = self.tx_id; tx.endianness = hdr.drep[0] & 0x10; @@ -99,13 +99,14 @@ impl DCERPCUDPState { } pub fn free_tx(&mut self, tx_id: u64) { - SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id+1); + SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id + 1); 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.id == tx_id { //+ 1 { + if tx.id == tx_id { + //+ 1 { found = true; index = i; SCLogDebug!("tx {} progress {}/{}", tx.id, tx.req_done, tx.resp_done); @@ -113,8 +114,14 @@ impl DCERPCUDPState { } } if found { - SCLogDebug!("freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", - tx_id, tx_id+1, index, self.transactions.len(), self.tx_id); + SCLogDebug!( + "freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", + tx_id, + tx_id + 1, + index, + self.transactions.len(), + self.tx_id + ); self.tx_index_completed = 0; self.transactions.remove(index); } @@ -142,8 +149,18 @@ impl DCERPCUDPState { fn find_incomplete_tx(&mut self, hdr: &DCERPCHdrUdp) -> Option<&mut DCERPCTransaction> { for tx in &mut self.transactions { - if tx.seqnum == hdr.seqnum && tx.activityuuid == hdr.activityuuid && ((hdr.pkt_type == DCERPC_TYPE_REQUEST && !tx.req_done) || (hdr.pkt_type == DCERPC_TYPE_RESPONSE && !tx.resp_done)) { - SCLogDebug!("found tx id {}, last tx_id {}, {} {}", tx.id, self.tx_id, tx.seqnum, tx.activityuuid[0]); + if tx.seqnum == hdr.seqnum + && tx.activityuuid == hdr.activityuuid + && ((hdr.pkt_type == DCERPC_TYPE_REQUEST && !tx.req_done) + || (hdr.pkt_type == DCERPC_TYPE_RESPONSE && !tx.resp_done)) + { + SCLogDebug!( + "found tx id {}, last tx_id {}, {} {}", + tx.id, + self.tx_id, + tx.seqnum, + tx.activityuuid[0] + ); return Some(tx); } } @@ -159,7 +176,13 @@ impl DCERPCUDPState { let mut otx = self.find_incomplete_tx(hdr); if otx.is_none() { let ntx = self.create_tx(hdr); - SCLogDebug!("new tx id {}, last tx_id {}, {} {}", ntx.id, self.tx_id, ntx.seqnum, ntx.activityuuid[0]); + SCLogDebug!( + "new tx id {}, last tx_id {}, {} {}", + ntx.id, + self.tx_id, + ntx.seqnum, + ntx.activityuuid[0] + ); self.transactions.push_back(ntx); otx = self.transactions.back_mut(); } @@ -206,7 +229,11 @@ impl DCERPCUDPState { return AppLayerResult::err(); } if leftover_bytes.len() < header.fraglen as usize { - SCLogDebug!("Insufficient data: leftover_bytes {}, fraglen {}", leftover_bytes.len(), header.fraglen); + SCLogDebug!( + "Insufficient data: leftover_bytes {}, fraglen {}", + leftover_bytes.len(), + header.fraglen + ); return AppLayerResult::err(); } if !self.handle_fragment_data(&header, &leftover_bytes[..header.fraglen as usize]) { @@ -229,10 +256,9 @@ impl DCERPCUDPState { } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_udp_parse( +pub unsafe extern fn rs_dcerpc_udp_parse( _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, DCERPCUDPState); if !stream_slice.is_gap() { @@ -242,19 +268,21 @@ pub unsafe extern "C" fn rs_dcerpc_udp_parse( } #[no_mangle] -pub extern "C" fn rs_dcerpc_udp_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_dcerpc_udp_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(unsafe { Box::from_raw(state as *mut DCERPCUDPState) }); } #[no_mangle] -pub extern "C" fn rs_dcerpc_udp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: core::AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_dcerpc_udp_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: core::AppProto, +) -> *mut std::os::raw::c_void { let state = DCERPCUDPState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_udp_state_transaction_free( +pub unsafe extern fn rs_dcerpc_udp_state_transaction_free( state: *mut std::os::raw::c_void, tx_id: u64, ) { let dce_state = cast_pointer!(state, DCERPCUDPState); @@ -263,31 +291,30 @@ pub unsafe extern "C" fn rs_dcerpc_udp_state_transaction_free( } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_udp_get_tx_data( - tx: *mut std::os::raw::c_void) - -> *mut AppLayerTxData -{ +pub unsafe extern fn rs_dcerpc_udp_get_tx_data( + tx: *mut std::os::raw::c_void, +) -> *mut AppLayerTxData { let tx = cast_pointer!(tx, DCERPCTransaction); return &mut tx.tx_data; } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_udp_get_tx( +pub unsafe extern fn rs_dcerpc_udp_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let dce_state = cast_pointer!(state, DCERPCUDPState); match dce_state.get_tx(tx_id) { Some(tx) => { return tx as *const _ as *mut _; - }, + } None => { return std::ptr::null_mut(); } - } + } } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_udp_get_tx_cnt(vtx: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_dcerpc_udp_get_tx_cnt(vtx: *mut std::os::raw::c_void) -> u64 { let dce_state = cast_pointer!(vtx, DCERPCUDPState); dce_state.tx_id } @@ -297,19 +324,19 @@ fn probe(input: &[u8]) -> (bool, bool) { match parser::parse_dcerpc_udp_header(input) { Ok((_, hdr)) => { let is_request = hdr.pkt_type == 0x00; - let is_dcerpc = hdr.rpc_vers == 0x04 && - (hdr.flags2 & 0xfc == 0) && - (hdr.drep[0] & 0xee == 0) && - (hdr.drep[1] <= 3); + let is_dcerpc = hdr.rpc_vers == 0x04 + && (hdr.flags2 & 0xfc == 0) + && (hdr.drep[0] & 0xee == 0) + && (hdr.drep[1] <= 3); return (is_dcerpc, is_request); - }, + } Err(_) => (false, false), } } -pub unsafe extern "C" fn rs_dcerpc_probe_udp(_f: *const core::Flow, direction: u8, input: *const u8, - len: u32, rdir: *mut u8) -> core::AppProto -{ +pub unsafe extern fn rs_dcerpc_probe_udp( + _f: *const core::Flow, direction: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> core::AppProto { SCLogDebug!("Probing the packet for DCERPC/UDP"); if len == 0 { return core::ALPROTO_UNKNOWN; @@ -333,9 +360,18 @@ pub unsafe extern "C" fn rs_dcerpc_probe_udp(_f: *const core::Flow, direction: u fn register_pattern_probe() -> i8 { unsafe { - if AppLayerProtoDetectPMRegisterPatternCSwPP(core::IPPROTO_UDP, ALPROTO_DCERPC, - b"|04 00|\0".as_ptr() as *const std::os::raw::c_char, 2, 0, - Direction::ToServer.into(), rs_dcerpc_probe_udp, 0, 0) < 0 { + if AppLayerProtoDetectPMRegisterPatternCSwPP( + core::IPPROTO_UDP, + ALPROTO_DCERPC, + b"|04 00|\0".as_ptr() as *const std::os::raw::c_char, + 2, + 0, + Direction::ToServer.into(), + rs_dcerpc_probe_udp, + 0, + 0, + ) < 0 + { SCLogDebug!("TOSERVER => AppLayerProtoDetectPMRegisterPatternCSwPP FAILED"); return -1; } @@ -346,7 +382,7 @@ fn register_pattern_probe() -> i8 { export_state_data_get!(rs_dcerpc_udp_get_state_data, DCERPCUDPState); #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_udp_register_parser() { +pub unsafe extern fn rs_dcerpc_udp_register_parser() { let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, default_port: std::ptr::null(), @@ -395,7 +431,6 @@ pub unsafe extern "C" fn rs_dcerpc_udp_register_parser() { } } - #[cfg(test)] mod tests { use crate::applayer::AppLayerResult; @@ -412,7 +447,7 @@ mod tests { match parser::parse_dcerpc_udp_header(request) { Ok((_rem, _header)) => { - { assert!(false); } + assert!(false); } _ => {} } @@ -433,7 +468,9 @@ mod tests { assert_eq!(4, header.rpc_vers); assert_eq!(80, request.len() - rem.len()); } - _ => { assert!(false); } + _ => { + assert!(false); + } } } @@ -453,7 +490,9 @@ mod tests { assert_eq!(80, request.len() - rem.len()); assert_eq!(0, rem.len()); } - _ => { assert!(false); } + _ => { + assert!(false); + } } } diff --git a/rust/src/dcerpc/detect.rs b/rust/src/dcerpc/detect.rs index 81f2854ace6d..4428fe2287d8 100644 --- a/rust/src/dcerpc/detect.rs +++ b/rust/src/dcerpc/detect.rs @@ -203,7 +203,7 @@ fn parse_opnum_data(arg: &str) -> Result { } #[no_mangle] -pub extern "C" fn rs_dcerpc_iface_match( +pub extern fn rs_dcerpc_iface_match( tx: &mut DCERPCTransaction, state: &mut DCERPCState, if_data: &mut DCEIfaceData, ) -> u8 { let first_req_seen = tx.get_first_req_seen(); @@ -227,7 +227,7 @@ pub extern "C" fn rs_dcerpc_iface_match( } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_iface_parse(carg: *const c_char) -> *mut c_void { +pub unsafe extern fn rs_dcerpc_iface_parse(carg: *const c_char) -> *mut c_void { if carg.is_null() { return std::ptr::null_mut(); } @@ -245,14 +245,14 @@ pub unsafe extern "C" fn rs_dcerpc_iface_parse(carg: *const c_char) -> *mut c_vo } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_iface_free(ptr: *mut c_void) { +pub unsafe extern fn rs_dcerpc_iface_free(ptr: *mut c_void) { if !ptr.is_null() { std::mem::drop(Box::from_raw(ptr as *mut DCEIfaceData)); } } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_opnum_match( +pub unsafe extern fn rs_dcerpc_opnum_match( tx: &mut DCERPCTransaction, opnum_data: &mut DCEOpnumData, ) -> u8 { let first_req_seen = tx.get_first_req_seen(); @@ -274,7 +274,7 @@ pub unsafe extern "C" fn rs_dcerpc_opnum_match( } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_opnum_parse(carg: *const c_char) -> *mut c_void { +pub unsafe extern fn rs_dcerpc_opnum_parse(carg: *const c_char) -> *mut c_void { if carg.is_null() { return std::ptr::null_mut(); } @@ -292,7 +292,7 @@ pub unsafe extern "C" fn rs_dcerpc_opnum_parse(carg: *const c_char) -> *mut c_vo } #[no_mangle] -pub unsafe extern "C" fn rs_dcerpc_opnum_free(ptr: *mut c_void) { +pub unsafe extern fn rs_dcerpc_opnum_free(ptr: *mut c_void) { if !ptr.is_null() { std::mem::drop(Box::from_raw(ptr as *mut DCEOpnumData)); } diff --git a/rust/src/dcerpc/log.rs b/rust/src/dcerpc/log.rs index 3e7322780342..9eebb32b1c3d 100644 --- a/rust/src/dcerpc/log.rs +++ b/rust/src/dcerpc/log.rs @@ -117,7 +117,9 @@ fn log_dcerpc_header_udp( jsb.set_string("response", "UNREPLIED")?; } let activityuuid = Uuid::from_slice(tx.activityuuid.as_slice()); - let activityuuid = activityuuid.map(|uuid| uuid.to_hyphenated().to_string()).unwrap(); + let activityuuid = activityuuid + .map(|uuid| uuid.to_hyphenated().to_string()) + .unwrap(); jsb.set_string("activityuuid", &activityuuid)?; jsb.set_uint("seqnum", tx.seqnum as u64)?; jsb.set_string("rpc_version", "4.0")?; @@ -125,14 +127,14 @@ fn log_dcerpc_header_udp( } #[no_mangle] -pub extern "C" fn rs_dcerpc_log_json_record_tcp( +pub extern fn rs_dcerpc_log_json_record_tcp( state: &DCERPCState, tx: &DCERPCTransaction, jsb: &mut JsonBuilder, ) -> bool { log_dcerpc_header_tcp(jsb, state, tx).is_ok() } #[no_mangle] -pub extern "C" fn rs_dcerpc_log_json_record_udp( +pub extern fn rs_dcerpc_log_json_record_udp( state: &DCERPCUDPState, tx: &DCERPCTransaction, jsb: &mut JsonBuilder, ) -> bool { log_dcerpc_header_udp(jsb, state, tx).is_ok() diff --git a/rust/src/dcerpc/mod.rs b/rust/src/dcerpc/mod.rs index 800d2ade7311..68dbaf6899ca 100644 --- a/rust/src/dcerpc/mod.rs +++ b/rust/src/dcerpc/mod.rs @@ -19,6 +19,6 @@ pub mod dcerpc; pub mod dcerpc_udp; -pub mod parser; pub mod detect; pub mod log; +pub mod parser; diff --git a/rust/src/dcerpc/parser.rs b/rust/src/dcerpc/parser.rs index 256259843f72..232b41b3662c 100644 --- a/rust/src/dcerpc/parser.rs +++ b/rust/src/dcerpc/parser.rs @@ -20,9 +20,9 @@ use crate::dcerpc::dcerpc::{ use crate::dcerpc::dcerpc_udp::DCERPCHdrUdp; use nom7::bytes::streaming::take; use nom7::combinator::cond; +use nom7::multi::count; use nom7::number::complete::{le_u16, le_u32, le_u8, u16, u32}; use nom7::number::Endianness; -use nom7::multi::count; use nom7::IResult; fn uuid_to_vec(uuid: Uuid) -> Vec { @@ -77,7 +77,11 @@ pub fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp> { let (i, flags1) = le_u8(i)?; let (i, flags2) = le_u8(i)?; let (i, drep) = take(3_usize)(i)?; - let endianness = if drep[0] == 0 { Endianness::Big } else { Endianness::Little }; + let endianness = if drep[0] == 0 { + Endianness::Big + } else { + Endianness::Little + }; let (i, serial_hi) = le_u8(i)?; let (i, objectuuid) = take(16_usize)(i)?; let (i, interfaceuuid) = take(16_usize)(i)?; @@ -104,21 +108,21 @@ pub fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp> { Err(_e) => { SCLogDebug!("{}", _e); vec![0] - }, + } }, interfaceuuid: match parse_uuid(interfaceuuid) { Ok((_, vect)) => assemble_uuid(vect), Err(_e) => { SCLogDebug!("{}", _e); vec![0] - }, + } }, - activityuuid: match parse_uuid(activityuuid){ + activityuuid: match parse_uuid(activityuuid) { Ok((_, vect)) => assemble_uuid(vect), Err(_e) => { SCLogDebug!("{}", _e); vec![0] - }, + } }, server_boot, if_vers, @@ -136,9 +140,9 @@ pub fn parse_dcerpc_udp_header(i: &[u8]) -> IResult<&[u8], DCERPCHdrUdp> { pub fn parse_dcerpc_bindack_result(i: &[u8]) -> IResult<&[u8], DCERPCBindAckResult> { let (i, ack_result) = le_u16(i)?; - let (i, ack_reason) = le_u16(i)?; - let (i, transfer_syntax) = take(16_usize)(i)?; - let (i, syntax_version) = le_u32(i)?; + let (i, ack_reason) = le_u16(i)?; + let (i, transfer_syntax) = take(16_usize)(i)?; + let (i, syntax_version) = le_u32(i)?; let result = DCERPCBindAckResult { ack_result, ack_reason, @@ -154,7 +158,9 @@ pub fn parse_dcerpc_bindack(i: &[u8]) -> IResult<&[u8], DCERPCBindAck> { let (i, _assoc_group) = take(4_usize)(i)?; let (i, sec_addr_len) = le_u16(i)?; let (i, _) = take(sec_addr_len)(i)?; - let (i, _) = cond((sec_addr_len.wrapping_add(2)) % 4 != 0, |b| take(4 - (sec_addr_len.wrapping_add(2)) % 4)(b))(i)?; + let (i, _) = cond((sec_addr_len.wrapping_add(2)) % 4 != 0, |b| { + take(4 - (sec_addr_len.wrapping_add(2)) % 4)(b) + })(i)?; let (i, numctxitems) = le_u8(i)?; let (i, _) = take(3_usize)(i)?; // Padding let (i, ctxitems) = count(parse_dcerpc_bindack_result, numctxitems as usize)(i)?; @@ -184,7 +190,9 @@ pub fn parse_bindctx_item(i: &[u8], endianness: Endianness) -> IResult<&[u8], Bi _ => uuid_to_vec(vect), }, // Shouldn't happen - Err(_e) => {vec![0]}, + Err(_e) => { + vec![0] + } }, version, versionminor, @@ -211,7 +219,11 @@ pub fn parse_dcerpc_header(i: &[u8]) -> IResult<&[u8], DCERPCHdr> { let (i, hdrtype) = le_u8(i)?; let (i, pfc_flags) = le_u8(i)?; let (i, packed_drep) = take(4_usize)(i)?; - let endianness = if packed_drep[0] & 0x10 == 0 { Endianness::Big } else { Endianness::Little }; + let endianness = if packed_drep[0] & 0x10 == 0 { + Endianness::Big + } else { + Endianness::Little + }; let (i, frag_length) = u16(endianness)(i)?; let (i, auth_length) = u16(endianness)(i)?; let (i, call_id) = u32(endianness)(i)?; diff --git a/rust/src/detect/byte_math.rs b/rust/src/detect/byte_math.rs index 80bd3d5ee178..9983ed2b23af 100644 --- a/rust/src/detect/byte_math.rs +++ b/rust/src/detect/byte_math.rs @@ -420,7 +420,7 @@ fn parse_bytemath(input: &str) -> IResult<&str, DetectByteMathData, RuleParseErr /// Intermediary function between the C code and the parsing functions. #[no_mangle] -pub unsafe extern "C" fn ScByteMathParse(c_arg: *const c_char) -> *mut DetectByteMathData { +pub unsafe extern fn ScByteMathParse(c_arg: *const c_char) -> *mut DetectByteMathData { if c_arg.is_null() { return std::ptr::null_mut(); } @@ -438,7 +438,7 @@ pub unsafe extern "C" fn ScByteMathParse(c_arg: *const c_char) -> *mut DetectByt } #[no_mangle] -pub unsafe extern "C" fn ScByteMathFree(ptr: *mut DetectByteMathData) { +pub unsafe extern fn ScByteMathFree(ptr: *mut DetectByteMathData) { if !ptr.is_null() { let _ = Box::from_raw(ptr); } @@ -491,8 +491,9 @@ mod tests { } fn valid_test( - args: &str, nbytes: u8, offset: i32, oper: ByteMathOperator, rvalue_str: &str, nbytes_str: &str, rvalue: u32, - result: &str, base: ByteMathBase, endian: ByteMathEndian, bitmask_val: u32, flags: u8, + args: &str, nbytes: u8, offset: i32, oper: ByteMathOperator, rvalue_str: &str, + nbytes_str: &str, rvalue: u32, result: &str, base: ByteMathBase, endian: ByteMathEndian, + bitmask_val: u32, flags: u8, ) { let bmd = DetectByteMathData { nbytes, @@ -673,24 +674,18 @@ mod tests { #[test] fn test_parser_string_invalid() { - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, string decimal" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, string hexadecimal" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, string octal" - ) - .is_err() - ); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, string decimal" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, string hexadecimal" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, string octal" + ) + .is_err()); } #[test] @@ -712,50 +707,38 @@ mod tests { #[test] fn test_parser_bitmask_invalid() { - assert!( - parse_bytemath("bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0x") - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask x12345678" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask X12345678" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0x123456789012" - ) - .is_err() - ); - assert!( - parse_bytemath("bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0q") - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask maple" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0xGHIJKLMN" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask #*#*@-" - ) - .is_err() - ); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0x" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask x12345678" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask X12345678" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0x123456789012" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0q" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask maple" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask 0xGHIJKLMN" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, bitmask #*#*@-" + ) + .is_err()); } #[test] @@ -871,38 +854,28 @@ mod tests { #[test] fn test_parser_endian_invalid() { - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian bigger" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian smaller" - ) - .is_err() - ); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian bigger" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian smaller" + ) + .is_err()); // endianess can only be specified once - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian big, dce" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian small, endian big" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian small, dce" - ) - .is_err() - ); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian big, dce" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian small, endian big" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 3933, oper +, rvalue myrvalue, result foo, endian small, dce" + ) + .is_err()); } #[test] @@ -979,24 +952,12 @@ mod tests { #[test] fn test_parser_oper_invalid() { - assert!( - parse_bytemath("bytes 4, offset 0, oper !, rvalue myvalue, result foo").is_err() - ); - assert!( - parse_bytemath("bytes 4, offset 0, oper ^, rvalue myvalue, result foo").is_err() - ); - assert!( - parse_bytemath("bytes 4, offset 0, oper <>, rvalue myvalue, result foo").is_err() - ); - assert!( - parse_bytemath("bytes 4, offset 0, oper ><, rvalue myvalue, result foo").is_err() - ); - assert!( - parse_bytemath("bytes 4, offset 0, oper <, rvalue myvalue, result foo").is_err() - ); - assert!( - parse_bytemath("bytes 4, offset 0, oper >, rvalue myvalue, result foo").is_err() - ); + assert!(parse_bytemath("bytes 4, offset 0, oper !, rvalue myvalue, result foo").is_err()); + assert!(parse_bytemath("bytes 4, offset 0, oper ^, rvalue myvalue, result foo").is_err()); + assert!(parse_bytemath("bytes 4, offset 0, oper <>, rvalue myvalue, result foo").is_err()); + assert!(parse_bytemath("bytes 4, offset 0, oper ><, rvalue myvalue, result foo").is_err()); + assert!(parse_bytemath("bytes 4, offset 0, oper <, rvalue myvalue, result foo").is_err()); + assert!(parse_bytemath("bytes 4, offset 0, oper >, rvalue myvalue, result foo").is_err()); } #[test] @@ -1115,9 +1076,7 @@ mod tests { parse_bytemath("bytes 4, offset 3933, endian big, rvalue myrvalue, result foo") .is_err() ); - assert!( - parse_bytemath("bytes 4, offset 3933, oper +, endian big, result foo").is_err() - ); + assert!(parse_bytemath("bytes 4, offset 3933, oper +, endian big, result foo").is_err()); assert!( parse_bytemath("bytes 4, offset 3933, oper +, rvalue myrvalue, endian big").is_err() ); @@ -1129,35 +1088,30 @@ mod tests { assert!(parse_bytemath("bytes nan").is_err()); assert!(parse_bytemath("bytes 4, offset nan").is_err()); assert!(parse_bytemath("bytes 4, offset 0, three 3, four 4, five 5, six 6, seven 7, eight 8, nine 9, ten 10, eleven 11").is_err()); - assert!( - parse_bytemath("bytes 4, offset 0, oper ><, rvalue myrvalue").is_err() - ); + assert!(parse_bytemath("bytes 4, offset 0, oper ><, rvalue myrvalue").is_err()); assert!( parse_bytemath("bytes 4, offset 0, oper +, rvalue myrvalue, endian endian").is_err() ); } #[test] fn test_parser_multiple() { - assert!( - parse_bytemath( - "bytes 4, bytes 4, offset 0, oper +, rvalue myrvalue, result myresult, endian big" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 0, offset 0, oper +, rvalue myrvalue, result myresult, endian big" - ) - .is_err() - ); - assert!( - parse_bytemath( - "bytes 4, offset 0, oper +, oper +, rvalue myrvalue, result myresult, endian big" - ) - .is_err() - ); + assert!(parse_bytemath( + "bytes 4, bytes 4, offset 0, oper +, rvalue myrvalue, result myresult, endian big" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 0, offset 0, oper +, rvalue myrvalue, result myresult, endian big" + ) + .is_err()); + assert!(parse_bytemath( + "bytes 4, offset 0, oper +, oper +, rvalue myrvalue, result myresult, endian big" + ) + .is_err()); assert!(parse_bytemath("bytes 4, offset 0, oper +, rvalue myrvalue, rvalue myrvalue, result myresult, endian big").is_err()); assert!(parse_bytemath("bytes 4, offset 0, oper +, rvalue myrvalue, result myresult, result myresult, endian big").is_err()); - assert!(parse_bytemath("bytes 4, offset 0, oper +, rvalue myrvalue, result myresult, endian big, endian big").is_err()); + assert!(parse_bytemath( + "bytes 4, offset 0, oper +, rvalue myrvalue, result myresult, endian big, endian big" + ) + .is_err()); } } diff --git a/rust/src/detect/iprep.rs b/rust/src/detect/iprep.rs index 16f5d9d5d15e..5b4bf6ae7e3a 100644 --- a/rust/src/detect/iprep.rs +++ b/rust/src/detect/iprep.rs @@ -71,7 +71,7 @@ pub fn is_alphanumeric_or_slash(chr: char) -> bool { return false; } -extern "C" { +extern { pub fn SRepCatGetByShortname(name: *const c_char) -> u8; } @@ -108,7 +108,7 @@ pub fn detect_parse_iprep(i: &str) -> IResult<&str, DetectIPRepData> { } #[no_mangle] -pub unsafe extern "C" fn rs_detect_iprep_parse( +pub unsafe extern fn rs_detect_iprep_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectIPRepData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -122,7 +122,7 @@ pub unsafe extern "C" fn rs_detect_iprep_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_iprep_free(ctx: &mut DetectIPRepData) { +pub unsafe extern fn rs_detect_iprep_free(ctx: &mut DetectIPRepData) { // Just unbox... std::mem::drop(Box::from_raw(ctx)); } diff --git a/rust/src/detect/stream_size.rs b/rust/src/detect/stream_size.rs index cb8c826697a7..7dff6cd2a860 100644 --- a/rust/src/detect/stream_size.rs +++ b/rust/src/detect/stream_size.rs @@ -78,7 +78,7 @@ pub fn detect_parse_stream_size(i: &str) -> IResult<&str, DetectStreamSizeData> } #[no_mangle] -pub unsafe extern "C" fn rs_detect_stream_size_parse( +pub unsafe extern fn rs_detect_stream_size_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectStreamSizeData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -92,7 +92,7 @@ pub unsafe extern "C" fn rs_detect_stream_size_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_stream_size_free(ctx: &mut DetectStreamSizeData) { +pub unsafe extern fn rs_detect_stream_size_free(ctx: &mut DetectStreamSizeData) { // Just unbox... std::mem::drop(Box::from_raw(ctx)); } diff --git a/rust/src/detect/uint.rs b/rust/src/detect/uint.rs index 3d6a5baab0ca..580c55f52c6e 100644 --- a/rust/src/detect/uint.rs +++ b/rust/src/detect/uint.rs @@ -270,7 +270,7 @@ pub fn detect_parse_uint_inclusive(i: &str) -> IResult<&str, D } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u64_parse( +pub unsafe extern fn rs_detect_u64_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectUintData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -284,7 +284,7 @@ pub unsafe extern "C" fn rs_detect_u64_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u64_match( +pub unsafe extern fn rs_detect_u64_match( arg: u64, ctx: &DetectUintData, ) -> std::os::raw::c_int { if detect_match_uint(ctx, arg) { @@ -294,13 +294,13 @@ pub unsafe extern "C" fn rs_detect_u64_match( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u64_free(ctx: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_detect_u64_free(ctx: *mut std::os::raw::c_void) { // Just unbox... std::mem::drop(Box::from_raw(ctx as *mut DetectUintData)); } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u32_parse( +pub unsafe extern fn rs_detect_u32_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectUintData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -314,7 +314,7 @@ pub unsafe extern "C" fn rs_detect_u32_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u32_parse_inclusive( +pub unsafe extern fn rs_detect_u32_parse_inclusive( ustr: *const std::os::raw::c_char, ) -> *mut DetectUintData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -328,7 +328,7 @@ pub unsafe extern "C" fn rs_detect_u32_parse_inclusive( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u32_match( +pub unsafe extern fn rs_detect_u32_match( arg: u32, ctx: &DetectUintData, ) -> std::os::raw::c_int { if detect_match_uint(ctx, arg) { @@ -338,13 +338,13 @@ pub unsafe extern "C" fn rs_detect_u32_match( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u32_free(ctx: &mut DetectUintData) { +pub unsafe extern fn rs_detect_u32_free(ctx: &mut DetectUintData) { // Just unbox... std::mem::drop(Box::from_raw(ctx)); } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u8_parse( +pub unsafe extern fn rs_detect_u8_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectUintData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -358,9 +358,7 @@ pub unsafe extern "C" fn rs_detect_u8_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u8_match( - arg: u8, ctx: &DetectUintData, -) -> std::os::raw::c_int { +pub unsafe extern fn rs_detect_u8_match(arg: u8, ctx: &DetectUintData) -> std::os::raw::c_int { if detect_match_uint(ctx, arg) { return 1; } @@ -368,13 +366,13 @@ pub unsafe extern "C" fn rs_detect_u8_match( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u8_free(ctx: &mut DetectUintData) { +pub unsafe extern fn rs_detect_u8_free(ctx: &mut DetectUintData) { // Just unbox... std::mem::drop(Box::from_raw(ctx)); } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u16_parse( +pub unsafe extern fn rs_detect_u16_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectUintData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -388,7 +386,7 @@ pub unsafe extern "C" fn rs_detect_u16_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u16_match( +pub unsafe extern fn rs_detect_u16_match( arg: u16, ctx: &DetectUintData, ) -> std::os::raw::c_int { if detect_match_uint(ctx, arg) { @@ -398,7 +396,7 @@ pub unsafe extern "C" fn rs_detect_u16_match( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_u16_free(ctx: &mut DetectUintData) { +pub unsafe extern fn rs_detect_u16_free(ctx: &mut DetectUintData) { // Just unbox... std::mem::drop(Box::from_raw(ctx)); } diff --git a/rust/src/detect/uri.rs b/rust/src/detect/uri.rs index ae982782cc4d..65ed53680ea5 100644 --- a/rust/src/detect/uri.rs +++ b/rust/src/detect/uri.rs @@ -58,7 +58,7 @@ pub fn detect_parse_urilen(i: &str) -> IResult<&str, DetectUrilenData> { } #[no_mangle] -pub unsafe extern "C" fn rs_detect_urilen_parse( +pub unsafe extern fn rs_detect_urilen_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectUrilenData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -72,7 +72,7 @@ pub unsafe extern "C" fn rs_detect_urilen_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_detect_urilen_free(ctx: &mut DetectUrilenData) { +pub unsafe extern fn rs_detect_urilen_free(ctx: &mut DetectUrilenData) { // Just unbox... std::mem::drop(Box::from_raw(ctx)); } diff --git a/rust/src/dhcp/detect.rs b/rust/src/dhcp/detect.rs index 0215810ae847..e31cad4b2f7e 100644 --- a/rust/src/dhcp/detect.rs +++ b/rust/src/dhcp/detect.rs @@ -21,9 +21,7 @@ use super::dhcp::{ use super::parser::DHCPOptionWrapper; #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_tx_get_leasetime( - tx: &mut DHCPTransaction, leasetime: *mut u64, -) -> u8 { +pub unsafe extern fn rs_dhcp_tx_get_leasetime(tx: &mut DHCPTransaction, leasetime: *mut u64) -> u8 { for option in &tx.message.options { if option.code == DHCP_OPT_ADDRESS_TIME { if let DHCPOptionWrapper::TimeValue(ref time_value) = option.option { @@ -36,9 +34,7 @@ pub unsafe extern "C" fn rs_dhcp_tx_get_leasetime( } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_tx_get_rebinding_time( - tx: &mut DHCPTransaction, res: *mut u64, -) -> u8 { +pub unsafe extern fn rs_dhcp_tx_get_rebinding_time(tx: &mut DHCPTransaction, res: *mut u64) -> u8 { for option in &tx.message.options { if option.code == DHCP_OPT_REBINDING_TIME { if let DHCPOptionWrapper::TimeValue(ref time_value) = option.option { @@ -51,9 +47,7 @@ pub unsafe extern "C" fn rs_dhcp_tx_get_rebinding_time( } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_tx_get_renewal_time( - tx: &mut DHCPTransaction, res: *mut u64, -) -> u8 { +pub unsafe extern fn rs_dhcp_tx_get_renewal_time(tx: &mut DHCPTransaction, res: *mut u64) -> u8 { for option in &tx.message.options { if option.code == DHCP_OPT_RENEWAL_TIME { if let DHCPOptionWrapper::TimeValue(ref time_value) = option.option { diff --git a/rust/src/dhcp/dhcp.rs b/rust/src/dhcp/dhcp.rs index b69b675b8ce9..0d576b8c4d45 100644 --- a/rust/src/dhcp/dhcp.rs +++ b/rust/src/dhcp/dhcp.rs @@ -17,7 +17,7 @@ use crate::applayer::{self, *}; use crate::core; -use crate::core::{ALPROTO_UNKNOWN, AppProto, Flow, IPPROTO_UDP}; +use crate::core::{AppProto, Flow, ALPROTO_UNKNOWN, IPPROTO_UDP}; use crate::dhcp::parser::*; use std; use std::ffi::CString; @@ -178,12 +178,9 @@ impl DHCPState { } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_probing_parser(_flow: *const Flow, - _direction: u8, - input: *const u8, - input_len: u32, - _rdir: *mut u8) -> AppProto -{ +pub unsafe extern fn rs_dhcp_probing_parser( + _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, +) -> AppProto { if input_len < DHCP_MIN_FRAME_LEN { return ALPROTO_UNKNOWN; } @@ -200,15 +197,17 @@ pub unsafe extern "C" fn rs_dhcp_probing_parser(_flow: *const Flow, } #[no_mangle] -pub extern "C" fn rs_dhcp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void, - _direction: u8) -> std::os::raw::c_int { +pub extern fn rs_dhcp_tx_get_alstate_progress( + _tx: *mut std::os::raw::c_void, _direction: u8, +) -> std::os::raw::c_int { // As this is a stateless parser, simply use 1. return 1; } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_state_get_tx(state: *mut std::os::raw::c_void, - tx_id: u64) -> *mut std::os::raw::c_void { +pub unsafe extern fn rs_dhcp_state_get_tx( + state: *mut std::os::raw::c_void, tx_id: u64, +) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, DHCPState); match state.get_tx(tx_id) { Some(tx) => { @@ -221,18 +220,16 @@ pub unsafe extern "C" fn rs_dhcp_state_get_tx(state: *mut std::os::raw::c_void, } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_dhcp_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, DHCPState); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_parse(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { +pub unsafe extern fn rs_dhcp_parse( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, DHCPState); if state.parse(stream_slice.as_slice()) { return AppLayerResult::ok(); @@ -241,23 +238,22 @@ pub unsafe extern "C" fn rs_dhcp_parse(_flow: *const core::Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_state_tx_free( - state: *mut std::os::raw::c_void, - tx_id: u64) -{ +pub unsafe extern fn rs_dhcp_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, DHCPState); state.free_tx(tx_id); } #[no_mangle] -pub extern "C" fn rs_dhcp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_dhcp_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = DHCPState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_state_free(state: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_dhcp_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(Box::from_raw(state as *mut DHCPState)); } @@ -267,38 +263,38 @@ export_state_data_get!(rs_dhcp_get_state_data, DHCPState); const PARSER_NAME: &[u8] = b"dhcp\0"; #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_register_parser() { +pub unsafe extern fn rs_dhcp_register_parser() { SCLogDebug!("Registering DHCP parser."); let ports = CString::new("[67,68]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, - default_port : ports.as_ptr(), - ipproto : IPPROTO_UDP, - probe_ts : Some(rs_dhcp_probing_parser), - probe_tc : Some(rs_dhcp_probing_parser), - min_depth : 0, - max_depth : 16, - state_new : rs_dhcp_state_new, - state_free : rs_dhcp_state_free, - tx_free : rs_dhcp_state_tx_free, - parse_ts : rs_dhcp_parse, - parse_tc : rs_dhcp_parse, - get_tx_count : rs_dhcp_state_get_tx_count, - get_tx : rs_dhcp_state_get_tx, - tx_comp_st_ts : 1, - tx_comp_st_tc : 1, - tx_get_progress : rs_dhcp_tx_get_alstate_progress, - get_eventinfo : Some(DHCPEvent::get_event_info), - get_eventinfo_byid : Some(DHCPEvent::get_event_info_by_id), - localstorage_new : None, - localstorage_free : None, - get_tx_files : None, - get_tx_iterator : Some(applayer::state_get_tx_iterator::), - get_tx_data : rs_dhcp_get_tx_data, - get_state_data : rs_dhcp_get_state_data, - apply_tx_config : None, - flags : 0, - truncate : None, + default_port: ports.as_ptr(), + ipproto: IPPROTO_UDP, + probe_ts: Some(rs_dhcp_probing_parser), + probe_tc: Some(rs_dhcp_probing_parser), + min_depth: 0, + max_depth: 16, + state_new: rs_dhcp_state_new, + state_free: rs_dhcp_state_free, + tx_free: rs_dhcp_state_tx_free, + parse_ts: rs_dhcp_parse, + parse_tc: rs_dhcp_parse, + get_tx_count: rs_dhcp_state_get_tx_count, + get_tx: rs_dhcp_state_get_tx, + tx_comp_st_ts: 1, + tx_comp_st_tc: 1, + tx_get_progress: rs_dhcp_tx_get_alstate_progress, + get_eventinfo: Some(DHCPEvent::get_event_info), + get_eventinfo_byid: Some(DHCPEvent::get_event_info_by_id), + localstorage_new: None, + localstorage_free: None, + get_tx_files: None, + get_tx_iterator: Some(applayer::state_get_tx_iterator::), + get_tx_data: rs_dhcp_get_tx_data, + get_state_data: rs_dhcp_get_state_data, + apply_tx_config: None, + flags: 0, + truncate: None, get_frame_id_by_name: None, get_frame_name_by_id: None, }; diff --git a/rust/src/dhcp/logger.rs b/rust/src/dhcp/logger.rs index b29e2158ef95..43e0df539931 100644 --- a/rust/src/dhcp/logger.rs +++ b/rust/src/dhcp/logger.rs @@ -18,10 +18,10 @@ use std; use std::os::raw::c_void; +use crate::conf::ConfNode; use crate::dhcp::dhcp::*; -use crate::dhcp::parser::{DHCPOptionWrapper,DHCPOptGeneric}; +use crate::dhcp::parser::{DHCPOptGeneric, DHCPOptionWrapper}; use crate::dns::log::dns_print_addr; -use crate::conf::ConfNode; use crate::jsonbuilder::{JsonBuilder, JsonError}; pub struct DHCPLogger { @@ -29,11 +29,10 @@ pub struct DHCPLogger { } impl DHCPLogger { - pub fn new(conf: ConfNode) -> Self { return Self { extended: conf.get_child_bool("extended"), - } + }; } fn get_type(&self, tx: &DHCPTransaction) -> Option { @@ -42,7 +41,8 @@ impl DHCPLogger { let code = option.code; #[allow(clippy::single_match)] match &option.option { - DHCPOptionWrapper::Generic(option) => { + DHCPOptionWrapper::Generic(option) => + { #[allow(clippy::single_match)] match code { DHCP_OPT_TYPE => { @@ -61,7 +61,7 @@ impl DHCPLogger { pub fn do_log(&self, tx: &DHCPTransaction) -> bool { if !self.extended { - if let Some(DHCP_TYPE_ACK) = self.get_type(tx){ + if let Some(DHCP_TYPE_ACK) = self.get_type(tx) { return true; } return false; @@ -86,101 +86,86 @@ impl DHCPLogger { js.set_string("type", "")?; } } - + js.set_uint("id", header.txid as u64)?; - js.set_string("client_mac", - &format_addr_hex(&header.clienthw.to_vec()))?; + js.set_string("client_mac", &format_addr_hex(&header.clienthw.to_vec()))?; js.set_string("assigned_ip", &dns_print_addr(&header.yourip))?; if self.extended { js.set_string("client_ip", &dns_print_addr(&header.clientip))?; if header.opcode == BOOTP_REPLY { - js.set_string("relay_ip", - &dns_print_addr(&header.giaddr))?; - js.set_string("next_server_ip", - &dns_print_addr(&header.serverip))?; + js.set_string("relay_ip", &dns_print_addr(&header.giaddr))?; + js.set_string("next_server_ip", &dns_print_addr(&header.serverip))?; } } - + for option in options { let code = option.code; match option.option { DHCPOptionWrapper::ClientId(ref clientid) => { - js.set_string("client_id", - &format_addr_hex(&clientid.data))?; + js.set_string("client_id", &format_addr_hex(&clientid.data))?; } - DHCPOptionWrapper::TimeValue(ref time_value) => { - match code { - DHCP_OPT_ADDRESS_TIME => { - if self.extended { - js.set_uint("lease_time", - time_value.seconds as u64)?; - } - } - DHCP_OPT_REBINDING_TIME => { - if self.extended { - js.set_uint("rebinding_time", - time_value.seconds as u64)?; - } - } - DHCP_OPT_RENEWAL_TIME => { - js.set_uint("renewal_time", - time_value.seconds as u64)?; + DHCPOptionWrapper::TimeValue(ref time_value) => match code { + DHCP_OPT_ADDRESS_TIME => { + if self.extended { + js.set_uint("lease_time", time_value.seconds as u64)?; } - _ => {} } - } - DHCPOptionWrapper::Generic(ref option) => { - match code { - DHCP_OPT_SUBNET_MASK => { - if self.extended { - js.set_string("subnet_mask", - &dns_print_addr(&option.data))?; - } + DHCP_OPT_REBINDING_TIME => { + if self.extended { + js.set_uint("rebinding_time", time_value.seconds as u64)?; } - DHCP_OPT_HOSTNAME => { - if !option.data.is_empty() { - js.set_string_from_bytes("hostname", - &option.data)?; - } + } + DHCP_OPT_RENEWAL_TIME => { + js.set_uint("renewal_time", time_value.seconds as u64)?; + } + _ => {} + }, + DHCPOptionWrapper::Generic(ref option) => match code { + DHCP_OPT_SUBNET_MASK => { + if self.extended { + js.set_string("subnet_mask", &dns_print_addr(&option.data))?; } - DHCP_OPT_TYPE => { - self.log_opt_type(js, option)?; + } + DHCP_OPT_HOSTNAME => { + if !option.data.is_empty() { + js.set_string_from_bytes("hostname", &option.data)?; } - DHCP_OPT_REQUESTED_IP => { - if self.extended { - js.set_string("requested_ip", - &dns_print_addr(&option.data))?; - } + } + DHCP_OPT_TYPE => { + self.log_opt_type(js, option)?; + } + DHCP_OPT_REQUESTED_IP => { + if self.extended { + js.set_string("requested_ip", &dns_print_addr(&option.data))?; } - DHCP_OPT_PARAMETER_LIST => { - if self.extended { - self.log_opt_parameters(js, option)?; - } + } + DHCP_OPT_PARAMETER_LIST => { + if self.extended { + self.log_opt_parameters(js, option)?; } - DHCP_OPT_DNS_SERVER => { - if self.extended { - self.log_opt_dns_server(js, option)?; - } + } + DHCP_OPT_DNS_SERVER => { + if self.extended { + self.log_opt_dns_server(js, option)?; } - DHCP_OPT_ROUTERS => { - if self.extended { - self.log_opt_routers(js, option)?; - } + } + DHCP_OPT_ROUTERS => { + if self.extended { + self.log_opt_routers(js, option)?; } - DHCP_OPT_VENDOR_CLASS_ID => { - if self.extended && !option.data.is_empty(){ - js.set_string_from_bytes("vendor_class_identifier", - &option.data)?; - } + } + DHCP_OPT_VENDOR_CLASS_ID => { + if self.extended && !option.data.is_empty() { + js.set_string_from_bytes("vendor_class_identifier", &option.data)?; } - _ => {} } - } + _ => {} + }, _ => {} } } - + js.close()?; return Ok(()); @@ -197,14 +182,16 @@ impl DHCPLogger { DHCP_TYPE_NAK => "nak", DHCP_TYPE_RELEASE => "release", DHCP_TYPE_INFORM => "inform", - _ => "unknown" + _ => "unknown", }; js.set_string("dhcp_type", dhcp_type)?; } Ok(()) } - fn log_opt_parameters(&self, js: &mut JsonBuilder, option: &DHCPOptGeneric) -> Result<(), JsonError> { + fn log_opt_parameters( + &self, js: &mut JsonBuilder, option: &DHCPOptGeneric, + ) -> Result<(), JsonError> { js.open_array("params")?; for i in &option.data { let param = match *i { @@ -216,7 +203,7 @@ impl DHCPLogger { DHCP_PARAM_NTP_SERVER => "ntp_server", DHCP_PARAM_TFTP_SERVER_NAME => "tftp_server_name", DHCP_PARAM_TFTP_SERVER_IP => "tftp_server_ip", - _ => "" + _ => "", }; if !param.is_empty() { js.append_string(param)?; @@ -225,8 +212,10 @@ impl DHCPLogger { js.close()?; Ok(()) } - - fn log_opt_dns_server(&self, js: &mut JsonBuilder, option: &DHCPOptGeneric) -> Result<(), JsonError> { + + fn log_opt_dns_server( + &self, js: &mut JsonBuilder, option: &DHCPOptGeneric, + ) -> Result<(), JsonError> { js.open_array("dns_servers")?; for i in 0..(option.data.len() / 4) { let val = dns_print_addr(&option.data[(i * 4)..(i * 4) + 4].to_vec()); @@ -235,8 +224,10 @@ impl DHCPLogger { js.close()?; Ok(()) } - - fn log_opt_routers(&self, js: &mut JsonBuilder, option: &DHCPOptGeneric) -> Result<(), JsonError> { + + fn log_opt_routers( + &self, js: &mut JsonBuilder, option: &DHCPOptGeneric, + ) -> Result<(), JsonError> { js.open_array("routers")?; for i in 0..(option.data.len() / 4) { let val = dns_print_addr(&option.data[(i * 4)..(i * 4) + 4].to_vec()); @@ -245,41 +236,38 @@ impl DHCPLogger { js.close()?; Ok(()) } - } fn format_addr_hex(input: &[u8]) -> String { - let parts: Vec = input.iter() - .map(|b| format!("{:02x}", b)) - .collect(); + let parts: Vec = input.iter().map(|b| format!("{:02x}", b)).collect(); return parts.join(":"); } #[no_mangle] -pub extern "C" fn rs_dhcp_logger_new(conf: *const c_void) -> *mut std::os::raw::c_void { +pub extern fn rs_dhcp_logger_new(conf: *const c_void) -> *mut std::os::raw::c_void { let conf = ConfNode::wrap(conf); let boxed = Box::new(DHCPLogger::new(conf)); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_logger_free(logger: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_dhcp_logger_free(logger: *mut std::os::raw::c_void) { std::mem::drop(Box::from_raw(logger as *mut DHCPLogger)); } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_logger_log(logger: *mut std::os::raw::c_void, - tx: *mut std::os::raw::c_void, - js: &mut JsonBuilder) -> bool { +pub unsafe extern fn rs_dhcp_logger_log( + logger: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, js: &mut JsonBuilder, +) -> bool { let logger = cast_pointer!(logger, DHCPLogger); let tx = cast_pointer!(tx, DHCPTransaction); logger.log(tx, js).is_ok() } #[no_mangle] -pub unsafe extern "C" fn rs_dhcp_logger_do_log(logger: *mut std::os::raw::c_void, - tx: *mut std::os::raw::c_void) - -> bool { +pub unsafe extern fn rs_dhcp_logger_do_log( + logger: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, +) -> bool { let logger = cast_pointer!(logger, DHCPLogger); let tx = cast_pointer!(tx, DHCPTransaction); logger.do_log(tx) diff --git a/rust/src/dhcp/mod.rs b/rust/src/dhcp/mod.rs index fd783d961ff2..50c993479196 100644 --- a/rust/src/dhcp/mod.rs +++ b/rust/src/dhcp/mod.rs @@ -17,7 +17,7 @@ //! DHCP parser, detection and logger module. +pub mod detect; pub mod dhcp; -pub mod parser; pub mod logger; -pub mod detect; +pub mod parser; diff --git a/rust/src/dns/detect.rs b/rust/src/dns/detect.rs index 268a409eac8d..5be1f2c6592d 100644 --- a/rust/src/dns/detect.rs +++ b/rust/src/dns/detect.rs @@ -57,7 +57,7 @@ fn parse_opcode(opcode: &str) -> Result { /// /// 1 will be returned on match, otherwise 0 will be returned. #[no_mangle] -pub extern "C" fn rs_dns_opcode_match( +pub extern fn rs_dns_opcode_match( tx: &mut DNSTransaction, detect: &mut DetectDnsOpcode, flags: u8, ) -> u8 { let header_flags = if flags & Direction::ToServer as u8 != 0 { @@ -90,7 +90,7 @@ fn match_opcode(detect: &DetectDnsOpcode, flags: u16) -> bool { } #[no_mangle] -pub unsafe extern "C" fn rs_detect_dns_opcode_parse(carg: *const c_char) -> *mut c_void { +pub unsafe extern fn rs_detect_dns_opcode_parse(carg: *const c_char) -> *mut c_void { if carg.is_null() { return std::ptr::null_mut(); } @@ -108,7 +108,7 @@ pub unsafe extern "C" fn rs_detect_dns_opcode_parse(carg: *const c_char) -> *mut } #[no_mangle] -pub unsafe extern "C" fn rs_dns_detect_opcode_free(ptr: *mut c_void) { +pub unsafe extern fn rs_dns_detect_opcode_free(ptr: *mut c_void) { if !ptr.is_null() { std::mem::drop(Box::from_raw(ptr as *mut DetectDnsOpcode)); } @@ -156,44 +156,36 @@ mod test { #[test] fn test_match_opcode() { - assert!( - match_opcode( - &DetectDnsOpcode { - negate: false, - opcode: 0, - }, - 0b0000_0000_0000_0000, - ) - ); + assert!(match_opcode( + &DetectDnsOpcode { + negate: false, + opcode: 0, + }, + 0b0000_0000_0000_0000, + )); - assert!( - !match_opcode( - &DetectDnsOpcode { - negate: true, - opcode: 0, - }, - 0b0000_0000_0000_0000, - ) - ); + assert!(!match_opcode( + &DetectDnsOpcode { + negate: true, + opcode: 0, + }, + 0b0000_0000_0000_0000, + )); - assert!( - match_opcode( - &DetectDnsOpcode { - negate: false, - opcode: 4, - }, - 0b0010_0000_0000_0000, - ) - ); + assert!(match_opcode( + &DetectDnsOpcode { + negate: false, + opcode: 4, + }, + 0b0010_0000_0000_0000, + )); - assert!( - !match_opcode( - &DetectDnsOpcode { - negate: true, - opcode: 4, - }, - 0b0010_0000_0000_0000, - ) - ); + assert!(!match_opcode( + &DetectDnsOpcode { + negate: true, + opcode: 4, + }, + 0b0010_0000_0000_0000, + )); } } diff --git a/rust/src/dns/dns.rs b/rust/src/dns/dns.rs index 382c76ae59b5..b87333885b92 100644 --- a/rust/src/dns/dns.rs +++ b/rust/src/dns/dns.rs @@ -250,10 +250,10 @@ impl Transaction for DNSTransaction { impl DNSTransaction { pub fn new(direction: Direction) -> Self { - Self { - tx_data: AppLayerTxData::for_direction(direction), + Self { + tx_data: AppLayerTxData::for_direction(direction), ..Default::default() - } + } } /// Get the DNS transactions ID (not the internal tracking ID). @@ -733,7 +733,7 @@ pub fn probe_tcp(input: &[u8]) -> (bool, bool, bool) { /// Returns *mut DNSState #[no_mangle] -pub extern "C" fn rs_dns_state_new( +pub extern fn rs_dns_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = DNSState::new(); @@ -743,7 +743,7 @@ pub extern "C" fn rs_dns_state_new( /// Returns *mut DNSState #[no_mangle] -pub extern "C" fn rs_dns_state_tcp_new() -> *mut std::os::raw::c_void { +pub extern fn rs_dns_state_tcp_new() -> *mut std::os::raw::c_void { let state = DNSState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; @@ -752,20 +752,20 @@ pub extern "C" fn rs_dns_state_tcp_new() -> *mut std::os::raw::c_void { /// Params: /// - state: *mut DNSState as void pointer #[no_mangle] -pub extern "C" fn rs_dns_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_dns_state_free(state: *mut std::os::raw::c_void) { // Just unbox... std::mem::drop(unsafe { Box::from_raw(state as *mut DNSState) }); } #[no_mangle] -pub unsafe extern "C" fn rs_dns_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_dns_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, DNSState); state.free_tx(tx_id); } /// C binding parse a DNS request. Returns 1 on success, -1 on failure. #[no_mangle] -pub unsafe extern "C" fn rs_dns_parse_request( +pub unsafe extern fn rs_dns_parse_request( flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -775,7 +775,7 @@ pub unsafe extern "C" fn rs_dns_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_dns_parse_response( +pub unsafe extern fn rs_dns_parse_response( flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -786,7 +786,7 @@ pub unsafe extern "C" fn rs_dns_parse_response( /// C binding parse a DNS request. Returns 1 on success, -1 on failure. #[no_mangle] -pub unsafe extern "C" fn rs_dns_parse_request_tcp( +pub unsafe extern fn rs_dns_parse_request_tcp( flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -800,7 +800,7 @@ pub unsafe extern "C" fn rs_dns_parse_request_tcp( } #[no_mangle] -pub unsafe extern "C" fn rs_dns_parse_response_tcp( +pub unsafe extern fn rs_dns_parse_response_tcp( flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -814,7 +814,7 @@ pub unsafe extern "C" fn rs_dns_parse_response_tcp( } #[no_mangle] -pub extern "C" fn rs_dns_tx_get_alstate_progress( +pub extern fn rs_dns_tx_get_alstate_progress( _tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { // This is a stateless parser, just the existence of a transaction @@ -824,14 +824,14 @@ pub extern "C" fn rs_dns_tx_get_alstate_progress( } #[no_mangle] -pub unsafe extern "C" fn rs_dns_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_dns_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, DNSState); SCLogDebug!("rs_dns_state_get_tx_count: returning {}", state.tx_id); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_dns_state_get_tx( +pub unsafe extern fn rs_dns_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, DNSState); @@ -846,16 +846,16 @@ pub unsafe extern "C" fn rs_dns_state_get_tx( } #[no_mangle] -pub extern "C" fn rs_dns_tx_is_request(tx: &mut DNSTransaction) -> bool { +pub extern fn rs_dns_tx_is_request(tx: &mut DNSTransaction) -> bool { tx.request.is_some() } #[no_mangle] -pub extern "C" fn rs_dns_tx_is_response(tx: &mut DNSTransaction) -> bool { +pub extern fn rs_dns_tx_is_response(tx: &mut DNSTransaction) -> bool { tx.response.is_some() } -pub unsafe extern "C" fn rs_dns_state_get_tx_data( +pub unsafe extern fn rs_dns_state_get_tx_data( tx: *mut std::os::raw::c_void, ) -> *mut AppLayerTxData { let tx = cast_pointer!(tx, DNSTransaction); @@ -865,7 +865,7 @@ pub unsafe extern "C" fn rs_dns_state_get_tx_data( export_state_data_get!(rs_dns_get_state_data, DNSState); #[no_mangle] -pub unsafe extern "C" fn rs_dns_tx_get_query_name( +pub unsafe extern fn rs_dns_tx_get_query_name( tx: &mut DNSTransaction, i: u32, buf: *mut *const u8, len: *mut u32, ) -> u8 { if let Some(request) = &tx.request { @@ -885,7 +885,7 @@ pub unsafe extern "C" fn rs_dns_tx_get_query_name( // /// extern uint16_t rs_dns_tx_get_tx_id(RSDNSTransaction *); #[no_mangle] -pub extern "C" fn rs_dns_tx_get_tx_id(tx: &mut DNSTransaction) -> u16 { +pub extern fn rs_dns_tx_get_tx_id(tx: &mut DNSTransaction) -> u16 { return tx.tx_id(); } @@ -893,12 +893,12 @@ pub extern "C" fn rs_dns_tx_get_tx_id(tx: &mut DNSTransaction) -> u16 { /// /// extern uint16_t rs_dns_tx_get_response_flags(RSDNSTransaction *); #[no_mangle] -pub extern "C" fn rs_dns_tx_get_response_flags(tx: &mut DNSTransaction) -> u16 { +pub extern fn rs_dns_tx_get_response_flags(tx: &mut DNSTransaction) -> u16 { return tx.rcode(); } #[no_mangle] -pub unsafe extern "C" fn rs_dns_tx_get_query_rrtype( +pub unsafe extern fn rs_dns_tx_get_query_rrtype( tx: &mut DNSTransaction, i: u16, rrtype: *mut u16, ) -> u8 { if let Some(request) = &tx.request { @@ -914,7 +914,7 @@ pub unsafe extern "C" fn rs_dns_tx_get_query_rrtype( } #[no_mangle] -pub unsafe extern "C" fn rs_dns_probe( +pub unsafe extern fn rs_dns_probe( _flow: *const core::Flow, _dir: u8, input: *const u8, len: u32, rdir: *mut u8, ) -> AppProto { if len == 0 || len < std::mem::size_of::() as u32 { @@ -935,7 +935,7 @@ pub unsafe extern "C" fn rs_dns_probe( } #[no_mangle] -pub unsafe extern "C" fn rs_dns_probe_tcp( +pub unsafe extern fn rs_dns_probe_tcp( _flow: *const core::Flow, direction: u8, input: *const u8, len: u32, rdir: *mut u8, ) -> AppProto { if len == 0 || len < std::mem::size_of::() as u32 + 2 { @@ -959,7 +959,7 @@ pub unsafe extern "C" fn rs_dns_probe_tcp( } #[no_mangle] -pub unsafe extern "C" fn rs_dns_apply_tx_config( +pub unsafe extern fn rs_dns_apply_tx_config( _state: *mut std::os::raw::c_void, _tx: *mut std::os::raw::c_void, _mode: std::os::raw::c_int, config: AppLayerTxConfig, ) { @@ -976,7 +976,7 @@ pub unsafe extern "C" fn rs_dns_apply_tx_config( } #[no_mangle] -pub unsafe extern "C" fn rs_dns_udp_register_parser() { +pub unsafe extern fn rs_dns_udp_register_parser() { let default_port = std::ffi::CString::new("[53]").unwrap(); let parser = RustParser { name: b"dns\0".as_ptr() as *const std::os::raw::c_char, @@ -1022,7 +1022,7 @@ pub unsafe extern "C" fn rs_dns_udp_register_parser() { } #[no_mangle] -pub unsafe extern "C" fn rs_dns_tcp_register_parser() { +pub unsafe extern fn rs_dns_tcp_register_parser() { let default_port = std::ffi::CString::new("53").unwrap(); let parser = RustParser { name: b"dns\0".as_ptr() as *const std::os::raw::c_char, diff --git a/rust/src/dns/log.rs b/rust/src/dns/log.rs index 5212b1a0da7c..b56c8645f15f 100644 --- a/rust/src/dns/log.rs +++ b/rust/src/dns/log.rs @@ -524,7 +524,8 @@ fn dns_log_json_answer( match &answer.data { DNSRData::A(addr) | DNSRData::AAAA(addr) => { if !answer_types.contains_key(&type_string) { - answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?); + answer_types + .insert(type_string.to_string(), JsonBuilder::try_new_array()?); } if let Some(a) = answer_types.get_mut(&type_string) { a.append_string(&dns_print_addr(addr))?; @@ -537,7 +538,8 @@ fn dns_log_json_answer( | DNSRData::NULL(bytes) | DNSRData::PTR(bytes) => { if !answer_types.contains_key(&type_string) { - answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?); + answer_types + .insert(type_string.to_string(), JsonBuilder::try_new_array()?); } if let Some(a) = answer_types.get_mut(&type_string) { a.append_string_from_bytes(bytes)?; @@ -545,7 +547,8 @@ fn dns_log_json_answer( } DNSRData::SOA(soa) => { if !answer_types.contains_key(&type_string) { - answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?); + answer_types + .insert(type_string.to_string(), JsonBuilder::try_new_array()?); } if let Some(a) = answer_types.get_mut(&type_string) { a.append_object(&dns_log_soa(soa)?)?; @@ -553,7 +556,8 @@ fn dns_log_json_answer( } DNSRData::SSHFP(sshfp) => { if !answer_types.contains_key(&type_string) { - answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?); + answer_types + .insert(type_string.to_string(), JsonBuilder::try_new_array()?); } if let Some(a) = answer_types.get_mut(&type_string) { a.append_object(&dns_log_sshfp(sshfp)?)?; @@ -561,7 +565,8 @@ fn dns_log_json_answer( } DNSRData::SRV(srv) => { if !answer_types.contains_key(&type_string) { - answer_types.insert(type_string.to_string(), JsonBuilder::try_new_array()?); + answer_types + .insert(type_string.to_string(), JsonBuilder::try_new_array()?); } if let Some(a) = answer_types.get_mut(&type_string) { a.append_object(&dns_log_srv(srv)?)?; @@ -631,7 +636,7 @@ fn dns_log_query( } #[no_mangle] -pub extern "C" fn rs_dns_log_json_query( +pub extern fn rs_dns_log_json_query( tx: &mut DNSTransaction, i: u16, flags: u64, jb: &mut JsonBuilder, ) -> bool { match dns_log_query(tx, i, flags, jb) { @@ -645,7 +650,7 @@ pub extern "C" fn rs_dns_log_json_query( } #[no_mangle] -pub extern "C" fn rs_dns_log_json_answer( +pub extern fn rs_dns_log_json_answer( tx: &mut DNSTransaction, flags: u64, js: &mut JsonBuilder, ) -> bool { if let Some(response) = &tx.response { @@ -659,7 +664,7 @@ pub extern "C" fn rs_dns_log_json_answer( } #[no_mangle] -pub extern "C" fn rs_dns_do_log_answer(tx: &mut DNSTransaction, flags: u64) -> bool { +pub extern fn rs_dns_do_log_answer(tx: &mut DNSTransaction, flags: u64) -> bool { if let Some(response) = &tx.response { for query in &response.queries { if dns_log_rrtype_enabled(query.rrtype, flags) { diff --git a/rust/src/dns/lua.rs b/rust/src/dns/lua.rs index b9935f87da84..fd7f128667c1 100644 --- a/rust/src/dns/lua.rs +++ b/rust/src/dns/lua.rs @@ -22,14 +22,14 @@ use crate::dns::log::*; use crate::lua::*; #[no_mangle] -pub extern "C" fn rs_dns_lua_get_tx_id(clua: &mut CLuaState, tx: &mut DNSTransaction) { +pub extern fn rs_dns_lua_get_tx_id(clua: &mut CLuaState, tx: &mut DNSTransaction) { let lua = LuaState { lua: clua }; lua.pushinteger(tx.tx_id() as i64); } #[no_mangle] -pub extern "C" fn rs_dns_lua_get_rrname(clua: &mut CLuaState, tx: &mut DNSTransaction) -> c_int { +pub extern fn rs_dns_lua_get_rrname(clua: &mut CLuaState, tx: &mut DNSTransaction) -> c_int { let lua = LuaState { lua: clua }; if let Some(request) = &tx.request { @@ -48,7 +48,7 @@ pub extern "C" fn rs_dns_lua_get_rrname(clua: &mut CLuaState, tx: &mut DNSTransa } #[no_mangle] -pub extern "C" fn rs_dns_lua_get_rcode(clua: &mut CLuaState, tx: &mut DNSTransaction) -> c_int { +pub extern fn rs_dns_lua_get_rcode(clua: &mut CLuaState, tx: &mut DNSTransaction) -> c_int { let lua = LuaState { lua: clua }; let rcode = tx.rcode(); @@ -61,9 +61,7 @@ pub extern "C" fn rs_dns_lua_get_rcode(clua: &mut CLuaState, tx: &mut DNSTransac } #[no_mangle] -pub extern "C" fn rs_dns_lua_get_query_table( - clua: &mut CLuaState, tx: &mut DNSTransaction, -) -> c_int { +pub extern fn rs_dns_lua_get_query_table(clua: &mut CLuaState, tx: &mut DNSTransaction) -> c_int { let lua = LuaState { lua: clua }; let mut i: i64 = 0; @@ -116,9 +114,7 @@ pub extern "C" fn rs_dns_lua_get_query_table( } #[no_mangle] -pub extern "C" fn rs_dns_lua_get_answer_table( - clua: &mut CLuaState, tx: &mut DNSTransaction, -) -> c_int { +pub extern fn rs_dns_lua_get_answer_table(clua: &mut CLuaState, tx: &mut DNSTransaction) -> c_int { let lua = LuaState { lua: clua }; let mut i: i64 = 0; @@ -195,7 +191,7 @@ pub extern "C" fn rs_dns_lua_get_answer_table( } #[no_mangle] -pub extern "C" fn rs_dns_lua_get_authority_table( +pub extern fn rs_dns_lua_get_authority_table( clua: &mut CLuaState, tx: &mut DNSTransaction, ) -> c_int { let lua = LuaState { lua: clua }; diff --git a/rust/src/ffi/base64.rs b/rust/src/ffi/base64.rs index ea72a344c393..2c4ee0faf505 100644 --- a/rust/src/ffi/base64.rs +++ b/rust/src/ffi/base64.rs @@ -15,8 +15,8 @@ * 02110-1301, USA. */ -use std::os::raw::c_uchar; use libc::c_ulong; +use std::os::raw::c_uchar; #[repr(C)] #[allow(non_camel_case_types)] @@ -35,7 +35,7 @@ pub enum Base64ReturnCode { /// from Base64EncodeBufferSize for the input_len, and this length must be provided /// in the output_len variable. #[no_mangle] -pub unsafe extern "C" fn Base64Encode( +pub unsafe extern fn Base64Encode( input: *const u8, input_len: c_ulong, output: *mut c_uchar, output_len: *mut c_ulong, ) -> Base64ReturnCode { if input.is_null() || output.is_null() || output_len.is_null() { @@ -57,6 +57,6 @@ pub unsafe extern "C" fn Base64Encode( /// required output bytes are 4 * ceil(input_len / 3) and an additional byte for /// storing the NULL pointer. #[no_mangle] -pub extern "C" fn Base64EncodeBufferSize(len: c_ulong) -> c_ulong { +pub extern fn Base64EncodeBufferSize(len: c_ulong) -> c_ulong { (4 * ((len) + 2) / 3) + 1 } diff --git a/rust/src/ffi/hashing.rs b/rust/src/ffi/hashing.rs index 59c7c9d3e970..dc259791dd83 100644 --- a/rust/src/ffi/hashing.rs +++ b/rust/src/ffi/hashing.rs @@ -34,18 +34,18 @@ pub const SC_SHA256_HEX_LEN: usize = 64; pub struct SCSha256(Sha256); #[no_mangle] -pub extern "C" fn SCSha256New() -> *mut SCSha256 { +pub extern fn SCSha256New() -> *mut SCSha256 { let hasher = Box::new(SCSha256(Sha256::new())); Box::into_raw(hasher) } #[no_mangle] -pub unsafe extern "C" fn SCSha256Update(hasher: &mut SCSha256, bytes: *const u8, len: u32) { +pub unsafe extern fn SCSha256Update(hasher: &mut SCSha256, bytes: *const u8, len: u32) { update(&mut hasher.0, bytes, len); } #[no_mangle] -pub unsafe extern "C" fn SCSha256Finalize(hasher: &mut SCSha256, out: *mut u8, len: u32) { +pub unsafe extern fn SCSha256Finalize(hasher: &mut SCSha256, out: *mut u8, len: u32) { let hasher: Box = Box::from_raw(hasher); finalize(hasher.0, out, len); } @@ -59,7 +59,7 @@ pub unsafe extern "C" fn SCSha256Finalize(hasher: &mut SCSha256, out: *mut u8, l /// But even given the notes, this appears to be faster than the equivalent that we /// did in C using NSS. #[no_mangle] -pub unsafe extern "C" fn SCSha256FinalizeToHex(hasher: &mut SCSha256, out: *mut c_char, len: u32) { +pub unsafe extern fn SCSha256FinalizeToHex(hasher: &mut SCSha256, out: *mut c_char, len: u32) { let hasher: Box = Box::from_raw(hasher); let result = hasher.0.finalize(); let hex = format!("{:x}", &result); @@ -68,13 +68,13 @@ pub unsafe extern "C" fn SCSha256FinalizeToHex(hasher: &mut SCSha256, out: *mut /// Free an unfinalized Sha256 context. #[no_mangle] -pub unsafe extern "C" fn SCSha256Free(hasher: &mut SCSha256) { +pub unsafe extern fn SCSha256Free(hasher: &mut SCSha256) { // Drop. let _: Box = Box::from_raw(hasher); } #[no_mangle] -pub unsafe extern "C" fn SCSha256HashBuffer( +pub unsafe extern fn SCSha256HashBuffer( buf: *const u8, buf_len: u32, out: *mut u8, len: u32, ) -> bool { if len as usize != SC_SHA256_LEN { @@ -92,31 +92,31 @@ pub unsafe extern "C" fn SCSha256HashBuffer( pub struct SCSha1(Sha1); #[no_mangle] -pub extern "C" fn SCSha1New() -> *mut SCSha1 { +pub extern fn SCSha1New() -> *mut SCSha1 { let hasher = Box::new(SCSha1(Sha1::new())); Box::into_raw(hasher) } #[no_mangle] -pub unsafe extern "C" fn SCSha1Update(hasher: &mut SCSha1, bytes: *const u8, len: u32) { +pub unsafe extern fn SCSha1Update(hasher: &mut SCSha1, bytes: *const u8, len: u32) { update(&mut hasher.0, bytes, len); } #[no_mangle] -pub unsafe extern "C" fn SCSha1Finalize(hasher: &mut SCSha1, out: *mut u8, len: u32) { +pub unsafe extern fn SCSha1Finalize(hasher: &mut SCSha1, out: *mut u8, len: u32) { let hasher: Box = Box::from_raw(hasher); finalize(hasher.0, out, len); } /// Free an unfinalized Sha1 context. #[no_mangle] -pub unsafe extern "C" fn SCSha1Free(hasher: &mut SCSha1) { +pub unsafe extern fn SCSha1Free(hasher: &mut SCSha1) { // Drop. let _: Box = Box::from_raw(hasher); } #[no_mangle] -pub unsafe extern "C" fn SCSha1HashBuffer( +pub unsafe extern fn SCSha1HashBuffer( buf: *const u8, buf_len: u32, out: *mut u8, len: u32, ) -> bool { if len as usize != SC_SHA1_LEN { @@ -134,13 +134,13 @@ pub unsafe extern "C" fn SCSha1HashBuffer( pub struct SCMd5(Md5); #[no_mangle] -pub extern "C" fn SCMd5New() -> *mut SCMd5 { +pub extern fn SCMd5New() -> *mut SCMd5 { let hasher = Box::new(SCMd5(Md5::new())); Box::into_raw(hasher) } #[no_mangle] -pub unsafe extern "C" fn SCMd5Update(hasher: &mut SCMd5, bytes: *const u8, len: u32) { +pub unsafe extern fn SCMd5Update(hasher: &mut SCMd5, bytes: *const u8, len: u32) { update(&mut hasher.0, bytes, len); } @@ -148,7 +148,7 @@ pub unsafe extern "C" fn SCMd5Update(hasher: &mut SCMd5, bytes: *const u8, len: /// /// This function consumes the SCMd5 hash context. #[no_mangle] -pub unsafe extern "C" fn SCMd5Finalize(hasher: &mut SCMd5, out: *mut u8, len: u32) { +pub unsafe extern fn SCMd5Finalize(hasher: &mut SCMd5, out: *mut u8, len: u32) { let hasher: Box = Box::from_raw(hasher); finalize(hasher.0, out, len); } @@ -157,7 +157,7 @@ pub unsafe extern "C" fn SCMd5Finalize(hasher: &mut SCMd5, out: *mut u8, len: u3 /// /// Consumes the hash context and cannot be re-used. #[no_mangle] -pub unsafe extern "C" fn SCMd5FinalizeToHex(hasher: &mut SCMd5, out: *mut c_char, len: u32) { +pub unsafe extern fn SCMd5FinalizeToHex(hasher: &mut SCMd5, out: *mut c_char, len: u32) { let hasher: Box = Box::from_raw(hasher); let result = hasher.0.finalize(); let hex = format!("{:x}", &result); @@ -166,13 +166,13 @@ pub unsafe extern "C" fn SCMd5FinalizeToHex(hasher: &mut SCMd5, out: *mut c_char /// Free an unfinalized Sha1 context. #[no_mangle] -pub unsafe extern "C" fn SCMd5Free(hasher: &mut SCMd5) { +pub unsafe extern fn SCMd5Free(hasher: &mut SCMd5) { // Drop. let _: Box = Box::from_raw(hasher); } #[no_mangle] -pub unsafe extern "C" fn SCMd5HashBuffer(buf: *const u8, buf_len: u32, out: *mut u8, len: u32) { +pub unsafe extern fn SCMd5HashBuffer(buf: *const u8, buf_len: u32, out: *mut u8, len: u32) { let data = std::slice::from_raw_parts(buf, buf_len as usize); let output = std::slice::from_raw_parts_mut(out, len as usize); let hash = Md5::new().chain(data).finalize(); @@ -181,7 +181,7 @@ pub unsafe extern "C" fn SCMd5HashBuffer(buf: *const u8, buf_len: u32, out: *mut /// C binding for a function to MD5 hash a single buffer to a hex string. #[no_mangle] -pub unsafe extern "C" fn SCMd5HashBufferToHex( +pub unsafe extern fn SCMd5HashBufferToHex( buf: *const u8, buf_len: u32, out: *mut c_char, len: u32, ) { let data = std::slice::from_raw_parts(buf, buf_len as usize); @@ -223,9 +223,18 @@ mod test { SCSha256Update(hasher, bytes.as_ptr(), bytes.len() as u32); SCSha256Update(hasher, bytes.as_ptr(), bytes.len() as u32); let hex = [0_u8; SC_SHA256_HEX_LEN + 1]; - SCSha256FinalizeToHex(hasher, hex.as_ptr() as *mut c_char, (SC_SHA256_HEX_LEN + 1) as u32); - let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char).to_str().unwrap(); - assert_eq!(string, "22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153"); + SCSha256FinalizeToHex( + hasher, + hex.as_ptr() as *mut c_char, + (SC_SHA256_HEX_LEN + 1) as u32, + ); + let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char) + .to_str() + .unwrap(); + assert_eq!( + string, + "22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153" + ); } } @@ -243,10 +252,15 @@ mod test { SCMd5Update(hasher, bytes.as_ptr(), bytes.len() as u32); SCMd5Update(hasher, bytes.as_ptr(), bytes.len() as u32); let hex = [0_u8; SC_MD5_HEX_LEN + 1]; - SCMd5FinalizeToHex(hasher, hex.as_ptr() as *mut c_char, (SC_MD5_HEX_LEN + 1) as u32); - let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char).to_str().unwrap(); + SCMd5FinalizeToHex( + hasher, + hex.as_ptr() as *mut c_char, + (SC_MD5_HEX_LEN + 1) as u32, + ); + let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char) + .to_str() + .unwrap(); assert_eq!(string, "5216ddcc58e8dade5256075e77f642da"); } } - } diff --git a/rust/src/ffi/mod.rs b/rust/src/ffi/mod.rs index e97e6c98c639..cdd57a19676e 100644 --- a/rust/src/ffi/mod.rs +++ b/rust/src/ffi/mod.rs @@ -17,6 +17,6 @@ //! Module that exposes C bindings to the Suricata Rust library. -pub mod hashing; pub mod base64; +pub mod hashing; pub mod strings; diff --git a/rust/src/filecontainer.rs b/rust/src/filecontainer.rs index 3a8bde5f7d5b..7525a39df6f4 100644 --- a/rust/src/filecontainer.rs +++ b/rust/src/filecontainer.rs @@ -17,8 +17,8 @@ //! This module handles file container operations (open, append, close). +use std::os::raw::c_void; use std::ptr; -use std::os::raw::{c_void}; use crate::core::*; @@ -30,76 +30,101 @@ extern { #[repr(C)] #[derive(Debug)] pub struct FileContainer { - head: * mut c_void, - tail: * mut c_void, + head: *mut c_void, + tail: *mut c_void, } impl Default for FileContainer { - fn default() -> Self { Self { - head: ptr::null_mut(), - tail: ptr::null_mut(), - }} + fn default() -> Self { + Self { + head: ptr::null_mut(), + tail: ptr::null_mut(), + } + } } impl FileContainer { pub fn free(&mut self, cfg: &'static SuricataFileContext) { SCLogDebug!("freeing self"); - if let Some(c) = unsafe {SC} { + if let Some(c) = unsafe { SC } { (c.FileContainerRecycle)(self, cfg.files_sbcfg); } } - pub fn file_open(&mut self, cfg: &'static SuricataFileContext, track_id: u32, name: &[u8], flags: u16) -> i32 { - match unsafe {SC} { + pub fn file_open( + &mut self, cfg: &'static SuricataFileContext, track_id: u32, name: &[u8], flags: u16, + ) -> i32 { + match unsafe { SC } { None => panic!("BUG no suricata_config"), Some(c) => { SCLogDebug!("FILE {:p} OPEN flags {:04X}", &self, flags); - let res = (c.FileOpenFile)(self, cfg.files_sbcfg, track_id, - name.as_ptr(), name.len() as u16, - ptr::null(), 0u32, flags); + let res = (c.FileOpenFile)( + self, + cfg.files_sbcfg, + track_id, + name.as_ptr(), + name.len() as u16, + ptr::null(), + 0u32, + flags, + ); res } } } - pub fn file_append(&mut self, cfg: &'static SuricataFileContext, track_id: &u32, data: &[u8], is_gap: bool) -> i32 { + pub fn file_append( + &mut self, cfg: &'static SuricataFileContext, track_id: &u32, data: &[u8], is_gap: bool, + ) -> i32 { SCLogDebug!("FILECONTAINER: append {}", data.len()); if data.is_empty() { - return 0 + return 0; } - match unsafe {SC} { + match unsafe { SC } { None => panic!("BUG no suricata_config"), Some(c) => { let res = match is_gap { false => { SCLogDebug!("appending file data"); - let r = (c.FileAppendData)(self, cfg.files_sbcfg, *track_id, - data.as_ptr(), data.len() as u32); + let r = (c.FileAppendData)( + self, + cfg.files_sbcfg, + *track_id, + data.as_ptr(), + data.len() as u32, + ); r - }, + } true => { SCLogDebug!("appending GAP"); - let r = (c.FileAppendGAP)(self, cfg.files_sbcfg, *track_id, - data.as_ptr(), data.len() as u32); + let r = (c.FileAppendGAP)( + self, + cfg.files_sbcfg, + *track_id, + data.as_ptr(), + data.len() as u32, + ); r - }, + } }; res } } } - pub fn file_close(&mut self, cfg: &'static SuricataFileContext, track_id: &u32, flags: u16) -> i32 { + pub fn file_close( + &mut self, cfg: &'static SuricataFileContext, track_id: &u32, flags: u16, + ) -> i32 { SCLogDebug!("FILECONTAINER: CLOSEing"); - match unsafe {SC} { + match unsafe { SC } { None => panic!("BUG no suricata_config"), Some(c) => { - let res = (c.FileCloseFile)(self, cfg.files_sbcfg, *track_id, ptr::null(), 0u32, flags); + let res = + (c.FileCloseFile)(self, cfg.files_sbcfg, *track_id, ptr::null(), 0u32, flags); res } } - } } diff --git a/rust/src/filetracker.rs b/rust/src/filetracker.rs index 3ae65eecb559..820683662f44 100644 --- a/rust/src/filetracker.rs +++ b/rust/src/filetracker.rs @@ -28,9 +28,9 @@ //! Author: Victor Julien use crate::core::*; -use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; use crate::filecontainer::*; +use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::collections::HashMap; #[derive(Debug)] struct FileChunk { @@ -47,11 +47,10 @@ impl FileChunk { } } -#[derive(Debug)] -#[derive(Default)] +#[derive(Debug, Default)] pub struct FileTransferTracker { pub tracked: u64, - cur_ooo: u64, // how many bytes do we have queued from ooo chunks + cur_ooo: u64, // how many bytes do we have queued from ooo chunks track_id: u32, chunk_left: u32, @@ -76,7 +75,7 @@ pub struct FileTransferTracker { impl FileTransferTracker { pub fn new() -> FileTransferTracker { FileTransferTracker { - chunks:HashMap::new(), + chunks: HashMap::new(), ..Default::default() } } @@ -89,28 +88,28 @@ impl FileTransferTracker { return self.file_open || self.file_is_truncated || self.file_closed; } - fn open(&mut self, config: &'static SuricataFileContext, name: &[u8]) -> i32 - { - let r = self.file.file_open(config, self.track_id, name, self.file_flags); + fn open(&mut self, config: &'static SuricataFileContext, name: &[u8]) -> i32 { + let r = self + .file + .file_open(config, self.track_id, name, self.file_flags); if r == 0 { self.file_open = true; } r } - pub fn close(&mut self, config: &'static SuricataFileContext) - { + pub fn close(&mut self, config: &'static SuricataFileContext) { if !self.file_is_truncated { SCLogDebug!("closing file with id {}", self.track_id); - self.file.file_close(config, &self.track_id, self.file_flags); + self.file + .file_close(config, &self.track_id, self.file_flags); } self.file_open = false; self.file_closed = true; self.tracked = 0; } - pub fn trunc (&mut self, config: &'static SuricataFileContext) - { + pub fn trunc(&mut self, config: &'static SuricataFileContext) { if self.file_is_truncated || !self.file_open { return; } @@ -123,22 +122,30 @@ impl FileTransferTracker { self.cur_ooo = 0; } - pub fn new_chunk(&mut self, config: &'static SuricataFileContext, - name: &[u8], data: &[u8], chunk_offset: u64, chunk_size: u32, - fill_bytes: u8, is_last: bool, xid: &u32) -> u32 - { + pub fn new_chunk( + &mut self, config: &'static SuricataFileContext, name: &[u8], data: &[u8], + chunk_offset: u64, chunk_size: u32, fill_bytes: u8, is_last: bool, xid: &u32, + ) -> u32 { if self.chunk_left != 0 || self.fill_bytes != 0 { SCLogDebug!("current chunk incomplete: truncating"); self.trunc(config); } - SCLogDebug!("NEW CHUNK: chunk_size {} fill_bytes {}", chunk_size, fill_bytes); + SCLogDebug!( + "NEW CHUNK: chunk_size {} fill_bytes {}", + chunk_size, + fill_bytes + ); // for now assume that is_last means its really the last chunk // so no out of order chunks coming after. This means that if // the last chunk is out or order, we've missed chunks before. if chunk_offset != self.tracked { - SCLogDebug!("NEW CHUNK IS OOO: expected {}, got {}", self.tracked, chunk_offset); + SCLogDebug!( + "NEW CHUNK IS OOO: expected {}, got {}", + self.tracked, + chunk_offset + ); if is_last { SCLogDebug!("last chunk is out of order, this means we missed data before"); self.trunc(config); @@ -172,8 +179,9 @@ impl FileTransferTracker { /// update the file tracker /// If gap_size > 0 'data' should not be used. /// return how much we consumed of data - pub fn update(&mut self, config: &'static SuricataFileContext, data: &[u8], gap_size: u32) -> u32 - { + pub fn update( + &mut self, config: &'static SuricataFileContext, data: &[u8], gap_size: u32, + ) -> u32 { if self.file_is_truncated { let consumed = std::cmp::min(data.len() as u32, self.chunk_left); self.chunk_left = self.chunk_left.saturating_sub(data.len() as u32); @@ -182,7 +190,12 @@ impl FileTransferTracker { let mut consumed = 0_usize; let is_gap = gap_size > 0; if is_gap || gap_size > 0 { - SCLogDebug!("is_gap {} size {} ooo? {}", is_gap, gap_size, self.chunk_is_ooo); + SCLogDebug!( + "is_gap {} size {} ooo? {}", + is_gap, + gap_size, + self.chunk_is_ooo + ); } if self.chunk_left == 0 && self.fill_bytes == 0 { @@ -192,7 +205,7 @@ impl FileTransferTracker { self.close(config); self.chunk_is_last = false; } - return 0 + return 0; } else if self.chunk_left == 0 { SCLogDebug!("FILL BYTES {} from prev run", self.fill_bytes); if data.len() >= self.fill_bytes as usize { @@ -205,7 +218,7 @@ impl FileTransferTracker { SCLogDebug!("CHUNK(pre) fill bytes now still {}", self.fill_bytes); } SCLogDebug!("FILL BYTES: returning {}", consumed); - return consumed as u32 + return consumed as u32; } SCLogDebug!("UPDATE: data {} chunk_left {}", data.len(), self.chunk_left); @@ -216,24 +229,26 @@ impl FileTransferTracker { if !self.chunk_is_ooo { let res = self.file.file_append(config, &self.track_id, d, is_gap); match res { - 0 => { }, - -2 => { + 0 => {} + -2 => { self.file_is_truncated = true; - }, + } _ => { SCLogDebug!("got error so truncating file"); self.file_is_truncated = true; - }, + } } self.tracked += self.chunk_left as u64; } else { - SCLogDebug!("UPDATE: appending data {} to ooo chunk at offset {}/{}", - d.len(), self.cur_ooo_chunk_offset, self.tracked); + SCLogDebug!( + "UPDATE: appending data {} to ooo chunk at offset {}/{}", + d.len(), + self.cur_ooo_chunk_offset, + self.tracked + ); let c = match self.chunks.entry(self.cur_ooo_chunk_offset) { - Vacant(entry) => { - entry.insert(FileChunk::new(self.chunk_left)) - }, + Vacant(entry) => entry.insert(FileChunk::new(self.chunk_left)), Occupied(entry) => entry.into_mut(), }; self.cur_ooo += d.len() as u64; @@ -267,31 +282,42 @@ impl FileTransferTracker { Some(c) => { self.in_flight -= c.chunk.len() as u64; - let res = self.file.file_append(config, &self.track_id, &c.chunk, c.contains_gap); + let res = self.file.file_append( + config, + &self.track_id, + &c.chunk, + c.contains_gap, + ); match res { - 0 => { }, - -2 => { + 0 => {} + -2 => { self.file_is_truncated = true; - }, + } _ => { SCLogDebug!("got error so truncating file"); self.file_is_truncated = true; - }, + } } self.tracked += c.chunk.len() as u64; self.cur_ooo -= c.chunk.len() as u64; SCLogDebug!("STORED OOO CHUNK at offset {}, tracked now {}, stored len {}", _offset, self.tracked, c.chunk.len()); - }, + } _ => { - SCLogDebug!("NO STORED CHUNK found at _offset {}", self.tracked); + SCLogDebug!( + "NO STORED CHUNK found at _offset {}", + self.tracked + ); break; - }, + } }; } } else { - SCLogDebug!("UPDATE: complete ooo chunk. Offset {}", self.cur_ooo_chunk_offset); + SCLogDebug!( + "UPDATE: complete ooo chunk. Offset {}", + self.cur_ooo_chunk_offset + ); self.chunk_is_ooo = false; self.cur_ooo_chunk_offset = 0; @@ -304,19 +330,18 @@ impl FileTransferTracker { } else { SCLogDebug!("NOT last chunk, keep going"); } - } else { if !self.chunk_is_ooo { let res = self.file.file_append(config, &self.track_id, data, is_gap); match res { - 0 => { }, - -2 => { + 0 => {} + -2 => { self.file_is_truncated = true; - }, + } _ => { SCLogDebug!("got error so truncating file"); self.file_is_truncated = true; - }, + } } self.tracked += data.len() as u64; } else { diff --git a/rust/src/frames.rs b/rust/src/frames.rs index 3a45d014b472..022fbc8fa8fc 100644 --- a/rust/src/frames.rs +++ b/rust/src/frames.rs @@ -18,10 +18,10 @@ //! Module for bindings to the Suricata C frame API. use crate::applayer::StreamSlice; +use crate::core::Direction; use crate::core::Flow; #[cfg(not(test))] use crate::core::STREAM_TOSERVER; -use crate::core::Direction; #[cfg(not(test))] #[repr(C)] @@ -62,7 +62,12 @@ impl Frame { frame_type: u8, ) -> Option { let offset = frame_start.as_ptr() as usize - stream_slice.as_slice().as_ptr() as usize; - SCLogDebug!("offset {} stream_slice.len() {} frame_start.len() {}", offset, stream_slice.len(), frame_start.len()); + SCLogDebug!( + "offset {} stream_slice.len() {} frame_start.len() {}", + offset, + stream_slice.len(), + frame_start.len() + ); let frame = unsafe { AppLayerFrameNewByRelativeOffset( flow, diff --git a/rust/src/ftp/event.rs b/rust/src/ftp/event.rs index 04cc9e3f1e3b..594aeee8a9e0 100644 --- a/rust/src/ftp/event.rs +++ b/rust/src/ftp/event.rs @@ -32,7 +32,7 @@ pub enum FtpEvent { /// # Safety /// Unsafe as called from C. #[no_mangle] -pub unsafe extern "C" fn ftp_get_event_info( +pub unsafe extern fn ftp_get_event_info( event_name: *const c_char, event_id: *mut c_int, event_type: *mut AppLayerEventType, ) -> c_int { crate::applayer::get_event_info::(event_name, event_id, event_type) @@ -43,7 +43,7 @@ pub unsafe extern "C" fn ftp_get_event_info( /// # Safety /// Unsafe as called from C. #[no_mangle] -pub unsafe extern "C" fn ftp_get_event_info_by_id( +pub unsafe extern fn ftp_get_event_info_by_id( event_id: c_int, event_name: *mut *const c_char, event_type: *mut AppLayerEventType, ) -> c_int { crate::applayer::get_event_info_by_id::(event_id, event_name, event_type) as c_int diff --git a/rust/src/ftp/mod.rs b/rust/src/ftp/mod.rs index 3839c9661e0d..35324bb49176 100644 --- a/rust/src/ftp/mod.rs +++ b/rust/src/ftp/mod.rs @@ -87,7 +87,7 @@ pub fn ftp_pasv_response(i: &[u8]) -> IResult<&[u8], u16> { } #[no_mangle] -pub unsafe extern "C" fn rs_ftp_active_port(input: *const u8, len: u32) -> u16 { +pub unsafe extern fn rs_ftp_active_port(input: *const u8, len: u32) -> u16 { let buf = build_slice!(input, len as usize); match ftp_active_port(buf) { Ok((_, dport)) => { @@ -104,7 +104,7 @@ pub unsafe extern "C" fn rs_ftp_active_port(input: *const u8, len: u32) -> u16 { } #[no_mangle] -pub unsafe extern "C" fn rs_ftp_pasv_response(input: *const u8, len: u32) -> u16 { +pub unsafe extern fn rs_ftp_pasv_response(input: *const u8, len: u32) -> u16 { let buf = std::slice::from_raw_parts(input, len as usize); match ftp_pasv_response(buf) { Ok((_, dport)) => { @@ -146,7 +146,7 @@ pub fn ftp_active_eprt(i: &[u8]) -> IResult<&[u8], u16> { } #[no_mangle] -pub unsafe extern "C" fn rs_ftp_active_eprt(input: *const u8, len: u32) -> u16 { +pub unsafe extern fn rs_ftp_active_eprt(input: *const u8, len: u32) -> u16 { let buf = build_slice!(input, len as usize); match ftp_active_eprt(buf) { Ok((_, dport)) => { @@ -162,7 +162,7 @@ pub unsafe extern "C" fn rs_ftp_active_eprt(input: *const u8, len: u32) -> u16 { return 0; } #[no_mangle] -pub unsafe extern "C" fn rs_ftp_epsv_response(input: *const u8, len: u32) -> u16 { +pub unsafe extern fn rs_ftp_epsv_response(input: *const u8, len: u32) -> u16 { let buf = std::slice::from_raw_parts(input, len as usize); match ftp_epsv_response(buf) { Ok((_, dport)) => { diff --git a/rust/src/http2/decompression.rs b/rust/src/http2/decompression.rs index 99f8af39032c..31e8547a8134 100644 --- a/rust/src/http2/decompression.rs +++ b/rust/src/http2/decompression.rs @@ -178,10 +178,12 @@ impl HTTP2DecoderHalf { if self.encoding == HTTP2ContentEncoding::Unknown { if input == b"gzip" { self.encoding = HTTP2ContentEncoding::Gzip; - self.decoder = HTTP2Decompresser::Gzip(Box::new(GzDecoder::new(HTTP2cursor::new()))); + self.decoder = + HTTP2Decompresser::Gzip(Box::new(GzDecoder::new(HTTP2cursor::new()))); } else if input == b"deflate" { self.encoding = HTTP2ContentEncoding::Deflate; - self.decoder = HTTP2Decompresser::Deflate(Box::new(DeflateDecoder::new(HTTP2cursor::new()))); + self.decoder = + HTTP2Decompresser::Deflate(Box::new(DeflateDecoder::new(HTTP2cursor::new()))); } else if input == b"br" { self.encoding = HTTP2ContentEncoding::Br; self.decoder = HTTP2Decompresser::Brotli(Box::new(brotli::Decompressor::new( diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index 1c595a0cb0f8..44edf83b017e 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -44,7 +44,7 @@ fn http2_tx_has_frametype( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_has_frametype( +pub unsafe extern fn rs_http2_tx_has_frametype( tx: *mut std::os::raw::c_void, direction: u8, value: u8, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, HTTP2Transaction); @@ -52,7 +52,7 @@ pub unsafe extern "C" fn rs_http2_tx_has_frametype( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_parse_frametype( +pub unsafe extern fn rs_http2_parse_frametype( str: *const std::os::raw::c_char, ) -> std::os::raw::c_int { let ft_name: &CStr = CStr::from_ptr(str); //unsafe @@ -104,7 +104,7 @@ fn http2_tx_has_errorcode( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_has_errorcode( +pub unsafe extern fn rs_http2_tx_has_errorcode( tx: *mut std::os::raw::c_void, direction: u8, code: u32, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, HTTP2Transaction); @@ -112,7 +112,7 @@ pub unsafe extern "C" fn rs_http2_tx_has_errorcode( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_parse_errorcode( +pub unsafe extern fn rs_http2_parse_errorcode( str: *const std::os::raw::c_char, ) -> std::os::raw::c_int { let ft_name: &CStr = CStr::from_ptr(str); //unsafe @@ -177,7 +177,7 @@ fn http2_tx_get_next_priority( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_next_priority( +pub unsafe extern fn rs_http2_tx_get_next_priority( tx: *mut std::os::raw::c_void, direction: u8, nb: u32, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, HTTP2Transaction); @@ -213,7 +213,7 @@ fn http2_tx_get_next_window( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_next_window( +pub unsafe extern fn rs_http2_tx_get_next_window( tx: *mut std::os::raw::c_void, direction: u8, nb: u32, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, HTTP2Transaction); @@ -221,7 +221,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_next_window( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_detect_settingsctx_parse( +pub unsafe extern fn rs_http2_detect_settingsctx_parse( str: *const std::os::raw::c_char, ) -> *mut std::os::raw::c_void { let ft_name: &CStr = CStr::from_ptr(str); //unsafe @@ -235,7 +235,7 @@ pub unsafe extern "C" fn rs_http2_detect_settingsctx_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_detect_settingsctx_free(ctx: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_http2_detect_settingsctx_free(ctx: *mut std::os::raw::c_void) { // Just unbox... std::mem::drop(Box::from_raw(ctx as *mut parser::DetectHTTP2settingsSigCtx)); } @@ -284,7 +284,7 @@ fn http2_detect_settingsctx_match( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_detect_settingsctx_match( +pub unsafe extern fn rs_http2_detect_settingsctx_match( ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8, ) -> std::os::raw::c_int { let ctx = cast_pointer!(ctx, parser::DetectHTTP2settingsSigCtx); @@ -345,7 +345,7 @@ fn http2_detect_sizeupdatectx_match( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_detect_sizeupdatectx_match( +pub unsafe extern fn rs_http2_detect_sizeupdatectx_match( ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8, ) -> std::os::raw::c_int { let ctx = cast_pointer!(ctx, DetectUintData); @@ -356,7 +356,7 @@ pub unsafe extern "C" fn rs_http2_detect_sizeupdatectx_match( //TODOask better syntax between rs_http2_tx_get_header_name in argument // and rs_http2_detect_sizeupdatectx_match explicitly casting #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_header_name( +pub unsafe extern fn rs_http2_tx_get_header_name( tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { let mut pos = 0_u32; @@ -523,7 +523,7 @@ fn http2_tx_get_req_line(tx: &mut HTTP2Transaction) { } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_request_line( +pub unsafe extern fn rs_http2_tx_get_request_line( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { http2_tx_get_req_line(tx); @@ -537,7 +537,7 @@ fn http2_tx_get_resp_line(tx: &mut HTTP2Transaction) { return; } let empty = Vec::new(); - let mut resp_line : Vec = Vec::new(); + let mut resp_line: Vec = Vec::new(); let status = if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToClient, ":status") { @@ -552,7 +552,7 @@ fn http2_tx_get_resp_line(tx: &mut HTTP2Transaction) { } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_response_line( +pub unsafe extern fn rs_http2_tx_get_response_line( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { http2_tx_get_resp_line(tx); @@ -562,7 +562,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_response_line( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_uri( +pub unsafe extern fn rs_http2_tx_get_uri( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToServer, ":path") { @@ -574,7 +574,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_uri( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_method( +pub unsafe extern fn rs_http2_tx_get_method( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToServer, ":method") { @@ -586,7 +586,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_method( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_host( +pub unsafe extern fn rs_http2_tx_get_host( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_value(tx, Direction::ToServer, ":authority") { @@ -616,7 +616,7 @@ fn http2_lower(value: &[u8]) -> Option> { fn http2_normalize_host(value: &[u8]) -> &[u8] { match value.iter().position(|&x| x == b'@') { Some(i) => { - let value = &value[i+1..]; + let value = &value[i + 1..]; match value.iter().position(|&x| x == b':') { Some(i) => { return &value[..i]; @@ -626,21 +626,19 @@ fn http2_normalize_host(value: &[u8]) -> &[u8] { } } } - None => { - match value.iter().position(|&x| x == b':') { - Some(i) => { - return &value[..i]; - } - None => { - return value; - } + None => match value.iter().position(|&x| x == b':') { + Some(i) => { + return &value[..i]; } - } + None => { + return value; + } + }, } } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_host_norm( +pub unsafe extern fn rs_http2_tx_get_host_norm( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_value(tx, Direction::ToServer, ":authority") { @@ -669,7 +667,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_host_norm( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_useragent( +pub unsafe extern fn rs_http2_tx_get_useragent( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_value(tx, Direction::ToServer, "user-agent") { @@ -681,7 +679,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_useragent( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_status( +pub unsafe extern fn rs_http2_tx_get_status( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToClient, ":status") { @@ -693,7 +691,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_status( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_cookie( +pub unsafe extern fn rs_http2_tx_get_cookie( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if direction == Direction::ToServer.into() { @@ -711,7 +709,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_cookie( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_header_value( +pub unsafe extern fn rs_http2_tx_get_header_value( tx: &mut HTTP2Transaction, direction: u8, strname: *const std::os::raw::c_char, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { @@ -737,7 +735,7 @@ fn http2_escape_header(blocks: &[parser::HTTP2FrameHeaderBlock], i: u32) -> Vec< } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_header_names( +pub unsafe extern fn rs_http2_tx_get_header_names( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { let mut vec = vec![b'\r', b'\n']; @@ -801,7 +799,7 @@ fn http2_header_trimspaces(value: &[u8]) -> &[u8] { } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_headers( +pub unsafe extern fn rs_http2_tx_get_headers( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { let mut vec = Vec::new(); @@ -835,7 +833,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_headers( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_headers_raw( +pub unsafe extern fn rs_http2_tx_get_headers_raw( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { let mut vec = Vec::new(); @@ -867,7 +865,7 @@ pub unsafe extern "C" fn rs_http2_tx_get_headers_raw( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_header( +pub unsafe extern fn rs_http2_tx_get_header( tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { let mut pos = 0_u32; @@ -942,7 +940,7 @@ fn http2_tx_set_header(state: &mut HTTP2State, name: &[u8], input: &[u8]) { } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_set_method( +pub unsafe extern fn rs_http2_tx_set_method( state: &mut HTTP2State, buffer: *const u8, buffer_len: u32, ) { let slice = build_slice!(buffer, buffer_len as usize); @@ -950,7 +948,7 @@ pub unsafe extern "C" fn rs_http2_tx_set_method( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_set_uri( +pub unsafe extern fn rs_http2_tx_set_uri( state: &mut HTTP2State, buffer: *const u8, buffer_len: u32, ) { let slice = build_slice!(buffer, buffer_len as usize); @@ -1000,7 +998,7 @@ fn http2_caseinsensitive_cmp(s1: &[u8], s2: &str) -> bool { } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_add_header( +pub unsafe extern fn rs_http2_tx_add_header( state: &mut HTTP2State, name: *const u8, name_len: u32, value: *const u8, value_len: u32, ) { let slice_name = build_slice!(name, name_len as usize); diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs index 14d7b47dfb03..4ab78ad1eb5a 100644 --- a/rust/src/http2/http2.rs +++ b/rust/src/http2/http2.rs @@ -41,7 +41,7 @@ const HTTP2_MIN_HANDLED_FRAME_SIZE: usize = 256; pub static mut SURICATA_HTTP2_FILE_CONFIG: Option<&'static SuricataFileContext> = None; #[no_mangle] -pub extern "C" fn rs_http2_init(context: &'static mut SuricataFileContext) { +pub extern fn rs_http2_init(context: &'static mut SuricataFileContext) { unsafe { SURICATA_HTTP2_FILE_CONFIG = Some(context); } @@ -184,13 +184,13 @@ impl HTTP2Transaction { if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } { //TODO get a file container instead of NULL (c.HTPFileCloseHandleRange)( - sfcm.files_sbcfg, - std::ptr::null_mut(), - 0, - self.file_range, - std::ptr::null_mut(), - 0, - ); + sfcm.files_sbcfg, + std::ptr::null_mut(), + 0, + self.file_range, + std::ptr::null_mut(), + 0, + ); (c.HttpRangeFreeBlock)(self.file_range); self.file_range = std::ptr::null_mut(); } @@ -237,7 +237,8 @@ impl HTTP2Transaction { } fn decompress<'a>( - &'a mut self, input: &'a [u8], dir: Direction, sfcm: &'static SuricataFileContext, over: bool, flow: *const Flow, + &'a mut self, input: &'a [u8], dir: Direction, sfcm: &'static SuricataFileContext, + over: bool, flow: *const Flow, ) -> io::Result<()> { let mut output = Vec::with_capacity(decompression::HTTP2_DECOMPRESSION_CHUNK_SIZE); let decompressed = self.decoder.decompress(input, &mut output, dir)?; @@ -256,7 +257,14 @@ impl HTTP2Transaction { ) { match range::http2_parse_check_content_range(&value) { Ok((_, v)) => { - range::http2_range_open(self, &v, flow, sfcm, Direction::ToClient, decompressed); + range::http2_range_open( + self, + &v, + flow, + sfcm, + Direction::ToClient, + decompressed, + ); if over && !self.file_range.is_null() { range::http2_range_close(self, Direction::ToClient, &[]) } @@ -589,7 +597,7 @@ impl HTTP2State { tx.state = HTTP2TransactionState::HTTP2StateGlobal; tx.tx_data.update_file_flags(self.state_data.file_flags); // TODO can this tx hold files? - tx.tx_data.file_tx = STREAM_TOSERVER|STREAM_TOCLIENT; // might hold files in both directions + tx.tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT; // might hold files in both directions tx.update_file_flags(tx.tx_data.file_flags); self.transactions.push_back(tx); return self.transactions.back_mut().unwrap(); @@ -650,7 +658,7 @@ impl HTTP2State { } tx.tx_data.update_file_flags(self.state_data.file_flags); tx.update_file_flags(tx.tx_data.file_flags); - tx.tx_data.file_tx = STREAM_TOSERVER|STREAM_TOCLIENT; // might hold files in both directions + tx.tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT; // might hold files in both directions self.transactions.push_back(tx); return self.transactions.back_mut().unwrap(); } @@ -661,9 +669,7 @@ impl HTTP2State { for block in blocks { if block.error >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError { self.set_event(HTTP2Event::InvalidHeader); - } else if block.error - == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate - { + } else if block.error == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate { update = true; if block.sizeupdate > sizeup { sizeup = block.sizeupdate; @@ -999,15 +1005,10 @@ impl HTTP2State { tx_same.ft_ts.tx_id = tx_same.tx_id - 1; }; let mut dinput = &rem[..hlsafe]; - if padded && !rem.is_empty() && usize::from(rem[0]) < hlsafe{ + if padded && !rem.is_empty() && usize::from(rem[0]) < hlsafe { dinput = &rem[1..hlsafe - usize::from(rem[0])]; } - if tx_same.decompress( - dinput, - dir, - sfcm, - over, - flow).is_err() { + if tx_same.decompress(dinput, dir, sfcm, over, flow).is_err() { self.set_event(HTTP2Event::FailedDecompression); } } @@ -1108,7 +1109,7 @@ export_state_data_get!(rs_http2_get_state_data, HTTP2State); /// C entry point for a probing parser. #[no_mangle] -pub unsafe extern "C" fn rs_http2_probing_parser_tc( +pub unsafe extern fn rs_http2_probing_parser_tc( _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { if !input.is_null() { @@ -1136,7 +1137,7 @@ pub unsafe extern "C" fn rs_http2_probing_parser_tc( } // Extern functions operating on HTTP2. -extern "C" { +extern { pub fn HTTP2MimicHttp1Request( orig_state: *mut std::os::raw::c_void, new_state: *mut std::os::raw::c_void, ); @@ -1146,7 +1147,7 @@ extern "C" { // is typically not unsafe. #[no_mangle] #[allow(clippy::not_unsafe_ptr_arg_deref)] -pub extern "C" fn rs_http2_state_new( +pub extern fn rs_http2_state_new( orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = HTTP2State::new(); @@ -1162,19 +1163,19 @@ pub extern "C" fn rs_http2_state_new( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_state_free(state: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_http2_state_free(state: *mut std::os::raw::c_void) { let mut state: Box = Box::from_raw(state as _); state.free(); } #[no_mangle] -pub unsafe extern "C" fn rs_http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, HTTP2State); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_http2_parse_ts( +pub unsafe extern fn rs_http2_parse_ts( flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -1184,7 +1185,7 @@ pub unsafe extern "C" fn rs_http2_parse_ts( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_parse_tc( +pub unsafe extern fn rs_http2_parse_tc( flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -1194,7 +1195,7 @@ pub unsafe extern "C" fn rs_http2_parse_tc( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_state_get_tx( +pub unsafe extern fn rs_http2_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, HTTP2State); @@ -1209,37 +1210,40 @@ pub unsafe extern "C" fn rs_http2_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, HTTP2State); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_state( - tx: *mut std::os::raw::c_void, -) -> HTTP2TransactionState { +pub unsafe extern fn rs_http2_tx_get_state(tx: *mut std::os::raw::c_void) -> HTTP2TransactionState { let tx = cast_pointer!(tx, HTTP2Transaction); return tx.state; } #[no_mangle] -pub unsafe extern "C" fn rs_http2_tx_get_alstate_progress( +pub unsafe extern fn rs_http2_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { return rs_http2_tx_get_state(tx) as i32; } #[no_mangle] -pub unsafe extern "C" fn rs_http2_getfiles( - _state: *mut std::os::raw::c_void, - tx: *mut std::os::raw::c_void, direction: u8, +pub unsafe extern fn rs_http2_getfiles( + _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8, ) -> AppLayerGetFileState { let tx = cast_pointer!(tx, HTTP2Transaction); if let Some(sfcm) = { SURICATA_HTTP2_FILE_CONFIG } { if direction & STREAM_TOSERVER != 0 { - return AppLayerGetFileState { fc: &mut tx.ft_ts.file, cfg: sfcm.files_sbcfg } + return AppLayerGetFileState { + fc: &mut tx.ft_ts.file, + cfg: sfcm.files_sbcfg, + }; } else { - return AppLayerGetFileState { fc: &mut tx.ft_tc.file, cfg: sfcm.files_sbcfg } + return AppLayerGetFileState { + fc: &mut tx.ft_tc.file, + cfg: sfcm.files_sbcfg, + }; } } AppLayerGetFileState::err() @@ -1249,7 +1253,7 @@ pub unsafe extern "C" fn rs_http2_getfiles( const PARSER_NAME: &[u8] = b"http2\0"; #[no_mangle] -pub unsafe extern "C" fn rs_http2_register_parser() { +pub unsafe extern fn rs_http2_register_parser() { let default_port = CString::new("[80]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, diff --git a/rust/src/http2/logger.rs b/rust/src/http2/logger.rs index 099112b1aeb4..9b0e1ee5e975 100644 --- a/rust/src/http2/logger.rs +++ b/rust/src/http2/logger.rs @@ -112,7 +112,10 @@ fn log_http2_frames(frames: &[HTTP2Frame], js: &mut JsonBuilder) -> Result Result bool { let tx = cast_pointer!(tx, HTTP2Transaction); diff --git a/rust/src/http2/parser.rs b/rust/src/http2/parser.rs index adabeb28c6e4..5a060bd1b2c3 100644 --- a/rust/src/http2/parser.rs +++ b/rust/src/http2/parser.rs @@ -460,8 +460,9 @@ fn http2_parse_headers_block_literal_incindex<'a>( while dyn_headers.current_size > dyn_headers.max_size && toremove < dyn_headers.table.len() { - dyn_headers.current_size -= - 32 + dyn_headers.table[toremove].name.len() + dyn_headers.table[toremove].value.len(); + dyn_headers.current_size -= 32 + + dyn_headers.table[toremove].name.len() + + dyn_headers.table[toremove].value.len(); toremove += 1; } dyn_headers.table.drain(0..toremove); diff --git a/rust/src/http2/range.rs b/rust/src/http2/range.rs index 9c96899443a1..df9dc816c2dc 100644 --- a/rust/src/http2/range.rs +++ b/rust/src/http2/range.rs @@ -84,7 +84,7 @@ pub fn http2_parse_check_content_range(input: &[u8]) -> IResult<&[u8], HTTPConte } #[no_mangle] -pub unsafe extern "C" fn rs_http_parse_content_range( +pub unsafe extern fn rs_http_parse_content_range( cr: &mut HTTPContentRange, buffer: *const u8, buffer_len: u32, ) -> std::os::raw::c_int { let slice = build_slice!(buffer, buffer_len as usize); @@ -131,7 +131,11 @@ pub fn http2_range_open( // whole file in one range return; } - let flags = if dir == Direction::ToServer { tx.ft_ts.file_flags } else { tx.ft_tc.file_flags }; + let flags = if dir == Direction::ToServer { + tx.ft_ts.file_flags + } else { + tx.ft_tc.file_flags + }; if let Ok((key, index)) = http2_range_key_get(tx) { let name = &key[index..]; tx.file_range = unsafe { @@ -151,15 +155,15 @@ pub fn http2_range_open( } } -pub fn http2_range_append(cfg: &'static SuricataFileContext, fr: *mut HttpRangeContainerBlock, data: &[u8]) { +pub fn http2_range_append( + cfg: &'static SuricataFileContext, fr: *mut HttpRangeContainerBlock, data: &[u8], +) { unsafe { HttpRangeAppendData(cfg.files_sbcfg, fr, data.as_ptr(), data.len() as u32); } } -pub fn http2_range_close( - tx: &mut HTTP2Transaction, dir: Direction, data: &[u8], -) { +pub fn http2_range_close(tx: &mut HTTP2Transaction, dir: Direction, data: &[u8]) { let added = if let Some(c) = unsafe { SC } { if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } { let (files, flags) = if dir == Direction::ToServer { @@ -168,13 +172,13 @@ pub fn http2_range_close( (&mut tx.ft_tc.file, tx.ft_tc.file_flags) }; let added = (c.HTPFileCloseHandleRange)( - sfcm.files_sbcfg, - files, - flags, - tx.file_range, - data.as_ptr(), - data.len() as u32, - ); + sfcm.files_sbcfg, + files, + flags, + tx.file_range, + data.as_ptr(), + data.len() as u32, + ); (c.HttpRangeFreeBlock)(tx.file_range); added } else { @@ -190,14 +194,15 @@ pub fn http2_range_close( } // Defined in app-layer-htp-range.h -extern "C" { +extern { pub fn HttpRangeContainerOpenFile( key: *const c_uchar, keylen: u32, f: *const Flow, cr: &HTTPContentRange, sbcfg: *const StreamingBufferConfig, name: *const c_uchar, name_len: u16, flags: u16, data: *const c_uchar, data_len: u32, ) -> *mut HttpRangeContainerBlock; pub fn HttpRangeAppendData( - cfg: *const StreamingBufferConfig, c: *mut HttpRangeContainerBlock, data: *const c_uchar, data_len: u32, + cfg: *const StreamingBufferConfig, c: *mut HttpRangeContainerBlock, data: *const c_uchar, + data_len: u32, ) -> std::os::raw::c_int; } diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 64d27a462afb..1701e7807be4 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -23,7 +23,7 @@ use std::ffi::CStr; use std::ptr; #[no_mangle] -pub extern "C" fn rs_ike_state_get_exch_type(tx: &mut IKETransaction, exch_type: *mut u8) -> u8 { +pub extern fn rs_ike_state_get_exch_type(tx: &mut IKETransaction, exch_type: *mut u8) -> u8 { debug_validate_bug_on!(exch_type.is_null()); if tx.ike_version == 1 { @@ -44,7 +44,7 @@ pub extern "C" fn rs_ike_state_get_exch_type(tx: &mut IKETransaction, exch_type: } #[no_mangle] -pub extern "C" fn rs_ike_state_get_spi_initiator( +pub extern fn rs_ike_state_get_spi_initiator( tx: &mut IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); @@ -57,7 +57,7 @@ pub extern "C" fn rs_ike_state_get_spi_initiator( } #[no_mangle] -pub extern "C" fn rs_ike_state_get_spi_responder( +pub extern fn rs_ike_state_get_spi_responder( tx: &mut IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); @@ -70,7 +70,7 @@ pub extern "C" fn rs_ike_state_get_spi_responder( } #[no_mangle] -pub extern "C" fn rs_ike_state_get_nonce( +pub extern fn rs_ike_state_get_nonce( tx: &mut IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); @@ -93,7 +93,7 @@ pub extern "C" fn rs_ike_state_get_nonce( } #[no_mangle] -pub extern "C" fn rs_ike_state_get_key_exchange( +pub extern fn rs_ike_state_get_key_exchange( tx: &mut IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); @@ -116,7 +116,7 @@ pub extern "C" fn rs_ike_state_get_key_exchange( } #[no_mangle] -pub extern "C" fn rs_ike_tx_get_vendor( +pub extern fn rs_ike_tx_get_vendor( tx: &IKETransaction, i: u32, buf: *mut *const u8, len: *mut u32, ) -> u8 { if tx.ike_version == 1 && i < tx.hdr.ikev1_header.vendor_ids.len() as u32 { @@ -136,7 +136,7 @@ pub extern "C" fn rs_ike_tx_get_vendor( } #[no_mangle] -pub extern "C" fn rs_ike_state_get_sa_attribute( +pub extern fn rs_ike_state_get_sa_attribute( tx: &mut IKETransaction, sa_type: *const std::os::raw::c_char, value: *mut u32, ) -> u8 { debug_validate_bug_on!(value.is_null()); @@ -207,7 +207,7 @@ pub extern "C" fn rs_ike_state_get_sa_attribute( } #[no_mangle] -pub unsafe extern "C" fn rs_ike_state_get_key_exchange_payload_length( +pub unsafe extern fn rs_ike_state_get_key_exchange_payload_length( tx: &mut IKETransaction, value: *mut u32, ) -> u8 { debug_validate_bug_on!(value.is_null()); @@ -222,7 +222,7 @@ pub unsafe extern "C" fn rs_ike_state_get_key_exchange_payload_length( } #[no_mangle] -pub unsafe extern "C" fn rs_ike_state_get_nonce_payload_length( +pub unsafe extern fn rs_ike_state_get_nonce_payload_length( tx: &mut IKETransaction, value: *mut u32, ) -> u8 { debug_validate_bug_on!(value.is_null()); diff --git a/rust/src/ike/ike.rs b/rust/src/ike/ike.rs index 2a5448ab27cf..a0d5a5ffecb4 100644 --- a/rust/src/ike/ike.rs +++ b/rust/src/ike/ike.rs @@ -124,11 +124,11 @@ impl Transaction for IKETransaction { impl IKETransaction { pub fn new(direction: Direction) -> Self { - Self { - direction, - tx_data: applayer::AppLayerTxData::for_direction(direction), - ..Default::default() - } + Self { + direction, + tx_data: applayer::AppLayerTxData::for_direction(direction), + ..Default::default() + } } /// Set an event. @@ -171,7 +171,9 @@ impl IKEState { } pub fn get_tx(&mut self, tx_id: u64) -> Option<&mut IKETransaction> { - self.transactions.iter_mut().find(|tx| tx.tx_id == tx_id + 1) + self.transactions + .iter_mut() + .find(|tx| tx.tx_id == tx_id + 1) } pub fn new_tx(&mut self, direction: Direction) -> IKETransaction { @@ -278,7 +280,7 @@ fn probe(input: &[u8], direction: Direction, rdir: *mut u8) -> bool { /// C entry point for a probing parser. #[no_mangle] -pub unsafe extern "C" fn rs_ike_probing_parser( +pub unsafe extern fn rs_ike_probing_parser( _flow: *const Flow, direction: u8, input: *const u8, input_len: u32, rdir: *mut u8, ) -> AppProto { if input_len < 28 { @@ -296,7 +298,7 @@ pub unsafe extern "C" fn rs_ike_probing_parser( } #[no_mangle] -pub extern "C" fn rs_ike_state_new( +pub extern fn rs_ike_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = IKEState::default(); @@ -305,19 +307,19 @@ pub extern "C" fn rs_ike_state_new( } #[no_mangle] -pub unsafe extern "C" fn rs_ike_state_free(state: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_ike_state_free(state: *mut std::os::raw::c_void) { // Just unbox... std::mem::drop(Box::from_raw(state as *mut IKEState)); } #[no_mangle] -pub unsafe extern "C" fn rs_ike_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_ike_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, IKEState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_ike_parse_request( +pub unsafe extern fn rs_ike_parse_request( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -326,7 +328,7 @@ pub unsafe extern "C" fn rs_ike_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_ike_parse_response( +pub unsafe extern fn rs_ike_parse_response( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -335,7 +337,7 @@ pub unsafe extern "C" fn rs_ike_parse_response( } #[no_mangle] -pub unsafe extern "C" fn rs_ike_state_get_tx( +pub unsafe extern fn rs_ike_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, IKEState); @@ -350,26 +352,26 @@ pub unsafe extern "C" fn rs_ike_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_ike_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_ike_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, IKEState); return state.tx_id; } #[no_mangle] -pub extern "C" fn rs_ike_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int { +pub extern fn rs_ike_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int { // This parser uses 1 to signal transaction completion status. return 1; } #[no_mangle] -pub extern "C" fn rs_ike_tx_get_alstate_progress( +pub extern fn rs_ike_tx_get_alstate_progress( _tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { return 1; } #[no_mangle] -pub unsafe extern "C" fn rs_ike_tx_get_logged( +pub unsafe extern fn rs_ike_tx_get_logged( _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, ) -> u32 { let tx = cast_pointer!(tx, IKETransaction); @@ -377,7 +379,7 @@ pub unsafe extern "C" fn rs_ike_tx_get_logged( } #[no_mangle] -pub unsafe extern "C" fn rs_ike_tx_set_logged( +pub unsafe extern fn rs_ike_tx_set_logged( _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, logged: u32, ) { let tx = cast_pointer!(tx, IKETransaction); @@ -394,7 +396,7 @@ export_tx_data_get!(rs_ike_get_tx_data, IKETransaction); export_state_data_get!(rs_ike_get_state_data, IKEState); #[no_mangle] -pub unsafe extern "C" fn rs_ike_register_parser() { +pub unsafe extern fn rs_ike_register_parser() { let default_port = CString::new("500").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, diff --git a/rust/src/ike/ikev1.rs b/rust/src/ike/ikev1.rs index 1e79c293cdea..7996b8dd053c 100644 --- a/rust/src/ike/ikev1.rs +++ b/rust/src/ike/ikev1.rs @@ -52,9 +52,7 @@ impl Ikev1ParticipantData { self.transform.clear(); } - pub fn update( - &mut self, key_exchange: &str, nonce: &str, transforms: &Vec>, - ) { + pub fn update(&mut self, key_exchange: &str, nonce: &str, transforms: &Vec>) { self.key_exchange = key_exchange.to_string(); self.nonce = nonce.to_string(); if self.nb_transforms == 0 && !transforms.is_empty() { @@ -103,7 +101,9 @@ pub fn handle_ikev1( &mut tx.hdr.ikev1_transforms, &mut tx.hdr.ikev1_header.vendor_ids, &mut payload_types, - ).is_err() { + ) + .is_err() + { SCLogDebug!("Error while parsing IKEV1 payloads"); return AppLayerResult::err(); } diff --git a/rust/src/ike/ikev2.rs b/rust/src/ike/ikev2.rs index a1be25ffb4a2..51895d25923d 100644 --- a/rust/src/ike/ikev2.rs +++ b/rust/src/ike/ikev2.rs @@ -276,9 +276,9 @@ fn add_proposals( IkeV2Transform::Auth(_) => true, _ => false, }) && !transforms.iter().any(|x| match *x { - IkeV2Transform::Encryption(ref enc) => enc.is_aead(), - _ => false, - }) { + IkeV2Transform::Encryption(ref enc) => enc.is_aead(), + _ => false, + }) { SCLogDebug!("No integrity transform found"); tx.set_event(IkeEvent::WeakCryptoNoAuth); } diff --git a/rust/src/ike/logger.rs b/rust/src/ike/logger.rs index cc5705f5808e..68057065c709 100644 --- a/rust/src/ike/logger.rs +++ b/rust/src/ike/logger.rs @@ -226,7 +226,7 @@ fn log_ikev2(tx: &IKETransaction, jb: &mut JsonBuilder) -> Result<(), JsonError> } #[no_mangle] -pub unsafe extern "C" fn rs_ike_logger_log( +pub unsafe extern fn rs_ike_logger_log( state: &mut IKEState, tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder, ) -> bool { let tx = cast_pointer!(tx, IKETransaction); diff --git a/rust/src/ike/parser.rs b/rust/src/ike/parser.rs index dcc574534290..08e97324d8ca 100644 --- a/rust/src/ike/parser.rs +++ b/rust/src/ike/parser.rs @@ -470,8 +470,7 @@ pub fn parse_sa_attribute(i: &[u8]) -> IResult<&[u8], Vec> { _ => None, }, hex_value: match format.0 { - 0 => variable_attribute_value - .map(to_hex), + 0 => variable_attribute_value.map(to_hex), _ => None, }, }; @@ -556,7 +555,9 @@ pub fn parse_payload( transforms, vendor_ids, payload_types, - ).is_err() { + ) + .is_err() + { SCLogDebug!("Error parsing SecurityAssociation"); return Err(()); } @@ -572,7 +573,9 @@ pub fn parse_payload( transforms, vendor_ids, payload_types, - ).is_err() { + ) + .is_err() + { SCLogDebug!("Error parsing Proposal"); return Err(()); } @@ -632,7 +635,9 @@ fn parse_proposal_payload( transforms, vendor_ids, payload_types, - ).is_err() { + ) + .is_err() + { SCLogDebug!("Error parsing transform payload"); return Err(()); } @@ -683,7 +688,9 @@ fn parse_security_association_payload( transforms, vendor_ids, payload_types, - ).is_err() { + ) + .is_err() + { SCLogDebug!("Error parsing proposal payload"); return Err(()); } diff --git a/rust/src/jsonbuilder.rs b/rust/src/jsonbuilder.rs index 82be09953c70..27fe6a8f9797 100644 --- a/rust/src/jsonbuilder.rs +++ b/rust/src/jsonbuilder.rs @@ -15,7 +15,7 @@ * 02110-1301, USA. */ - //! Module for building JSON documents. +//! Module for building JSON documents. #![allow(clippy::missing_safety_doc)] @@ -744,7 +744,7 @@ fn try_string_from_bytes(input: &[u8]) -> Result { } #[no_mangle] -pub extern "C" fn jb_new_object() -> *mut JsonBuilder { +pub extern fn jb_new_object() -> *mut JsonBuilder { match JsonBuilder::try_new_object() { Ok(js) => { let boxed = Box::new(js); @@ -755,7 +755,7 @@ pub extern "C" fn jb_new_object() -> *mut JsonBuilder { } #[no_mangle] -pub extern "C" fn jb_new_array() -> *mut JsonBuilder { +pub extern fn jb_new_array() -> *mut JsonBuilder { match JsonBuilder::try_new_array() { Ok(js) => { let boxed = Box::new(js); @@ -766,28 +766,28 @@ pub extern "C" fn jb_new_array() -> *mut JsonBuilder { } #[no_mangle] -pub extern "C" fn jb_clone(js: &mut JsonBuilder) -> *mut JsonBuilder { +pub extern fn jb_clone(js: &mut JsonBuilder) -> *mut JsonBuilder { let clone = Box::new(js.clone()); Box::into_raw(clone) } #[no_mangle] -pub unsafe extern "C" fn jb_free(js: &mut JsonBuilder) { +pub unsafe extern fn jb_free(js: &mut JsonBuilder) { let _ = Box::from_raw(js); } #[no_mangle] -pub extern "C" fn jb_capacity(jb: &mut JsonBuilder) -> usize { +pub extern fn jb_capacity(jb: &mut JsonBuilder) -> usize { jb.capacity() } #[no_mangle] -pub extern "C" fn jb_reset(jb: &mut JsonBuilder) { +pub extern fn jb_reset(jb: &mut JsonBuilder) { jb.reset(); } #[no_mangle] -pub unsafe extern "C" fn jb_open_object(js: &mut JsonBuilder, key: *const c_char) -> bool { +pub unsafe extern fn jb_open_object(js: &mut JsonBuilder, key: *const c_char) -> bool { if let Ok(s) = CStr::from_ptr(key).to_str() { js.open_object(s).is_ok() } else { @@ -796,12 +796,12 @@ pub unsafe extern "C" fn jb_open_object(js: &mut JsonBuilder, key: *const c_char } #[no_mangle] -pub unsafe extern "C" fn jb_start_object(js: &mut JsonBuilder) -> bool { +pub unsafe extern fn jb_start_object(js: &mut JsonBuilder) -> bool { js.start_object().is_ok() } #[no_mangle] -pub unsafe extern "C" fn jb_open_array(js: &mut JsonBuilder, key: *const c_char) -> bool { +pub unsafe extern fn jb_open_array(js: &mut JsonBuilder, key: *const c_char) -> bool { if let Ok(s) = CStr::from_ptr(key).to_str() { js.open_array(s).is_ok() } else { @@ -810,7 +810,7 @@ pub unsafe extern "C" fn jb_open_array(js: &mut JsonBuilder, key: *const c_char) } #[no_mangle] -pub unsafe extern "C" fn jb_set_string( +pub unsafe extern fn jb_set_string( js: &mut JsonBuilder, key: *const c_char, val: *const c_char, ) -> bool { if val.is_null() { @@ -825,7 +825,7 @@ pub unsafe extern "C" fn jb_set_string( } #[no_mangle] -pub unsafe extern "C" fn jb_set_string_from_bytes( +pub unsafe extern fn jb_set_string_from_bytes( js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32, ) -> bool { if bytes.is_null() || len == 0 { @@ -839,7 +839,7 @@ pub unsafe extern "C" fn jb_set_string_from_bytes( } #[no_mangle] -pub unsafe extern "C" fn jb_set_base64( +pub unsafe extern fn jb_set_base64( js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32, ) -> bool { if bytes.is_null() || len == 0 { @@ -853,7 +853,7 @@ pub unsafe extern "C" fn jb_set_base64( } #[no_mangle] -pub unsafe extern "C" fn jb_set_hex( +pub unsafe extern fn jb_set_hex( js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32, ) -> bool { if bytes.is_null() || len == 0 { @@ -867,7 +867,7 @@ pub unsafe extern "C" fn jb_set_hex( } #[no_mangle] -pub unsafe extern "C" fn jb_set_formatted(js: &mut JsonBuilder, formatted: *const c_char) -> bool { +pub unsafe extern fn jb_set_formatted(js: &mut JsonBuilder, formatted: *const c_char) -> bool { if let Ok(formatted) = CStr::from_ptr(formatted).to_str() { return js.set_formatted(formatted).is_ok(); } @@ -875,12 +875,12 @@ pub unsafe extern "C" fn jb_set_formatted(js: &mut JsonBuilder, formatted: *cons } #[no_mangle] -pub unsafe extern "C" fn jb_append_object(jb: &mut JsonBuilder, obj: &JsonBuilder) -> bool { +pub unsafe extern fn jb_append_object(jb: &mut JsonBuilder, obj: &JsonBuilder) -> bool { jb.append_object(obj).is_ok() } #[no_mangle] -pub unsafe extern "C" fn jb_set_object( +pub unsafe extern fn jb_set_object( js: &mut JsonBuilder, key: *const c_char, val: &mut JsonBuilder, ) -> bool { if let Ok(key) = CStr::from_ptr(key).to_str() { @@ -890,7 +890,7 @@ pub unsafe extern "C" fn jb_set_object( } #[no_mangle] -pub unsafe extern "C" fn jb_append_string(js: &mut JsonBuilder, val: *const c_char) -> bool { +pub unsafe extern fn jb_append_string(js: &mut JsonBuilder, val: *const c_char) -> bool { if val.is_null() { return false; } @@ -901,7 +901,7 @@ pub unsafe extern "C" fn jb_append_string(js: &mut JsonBuilder, val: *const c_ch } #[no_mangle] -pub unsafe extern "C" fn jb_append_string_from_bytes( +pub unsafe extern fn jb_append_string_from_bytes( js: &mut JsonBuilder, bytes: *const u8, len: u32, ) -> bool { if bytes.is_null() || len == 0 { @@ -912,9 +912,7 @@ pub unsafe extern "C" fn jb_append_string_from_bytes( } #[no_mangle] -pub unsafe extern "C" fn jb_append_base64( - js: &mut JsonBuilder, bytes: *const u8, len: u32, -) -> bool { +pub unsafe extern fn jb_append_base64(js: &mut JsonBuilder, bytes: *const u8, len: u32) -> bool { if bytes.is_null() || len == 0 { return false; } @@ -923,17 +921,17 @@ pub unsafe extern "C" fn jb_append_base64( } #[no_mangle] -pub unsafe extern "C" fn jb_append_uint(js: &mut JsonBuilder, val: u64) -> bool { +pub unsafe extern fn jb_append_uint(js: &mut JsonBuilder, val: u64) -> bool { return js.append_uint(val).is_ok(); } #[no_mangle] -pub unsafe extern "C" fn jb_append_float(js: &mut JsonBuilder, val: f64) -> bool { +pub unsafe extern fn jb_append_float(js: &mut JsonBuilder, val: f64) -> bool { return js.append_float(val).is_ok(); } #[no_mangle] -pub unsafe extern "C" fn jb_set_uint(js: &mut JsonBuilder, key: *const c_char, val: u64) -> bool { +pub unsafe extern fn jb_set_uint(js: &mut JsonBuilder, key: *const c_char, val: u64) -> bool { if let Ok(key) = CStr::from_ptr(key).to_str() { return js.set_uint(key, val).is_ok(); } @@ -941,7 +939,7 @@ pub unsafe extern "C" fn jb_set_uint(js: &mut JsonBuilder, key: *const c_char, v } #[no_mangle] -pub unsafe extern "C" fn jb_set_float(js: &mut JsonBuilder, key: *const c_char, val: f64) -> bool { +pub unsafe extern fn jb_set_float(js: &mut JsonBuilder, key: *const c_char, val: f64) -> bool { if let Ok(key) = CStr::from_ptr(key).to_str() { return js.set_float(key, val).is_ok(); } @@ -949,7 +947,7 @@ pub unsafe extern "C" fn jb_set_float(js: &mut JsonBuilder, key: *const c_char, } #[no_mangle] -pub unsafe extern "C" fn jb_set_bool(js: &mut JsonBuilder, key: *const c_char, val: bool) -> bool { +pub unsafe extern fn jb_set_bool(js: &mut JsonBuilder, key: *const c_char, val: bool) -> bool { if let Ok(key) = CStr::from_ptr(key).to_str() { return js.set_bool(key, val).is_ok(); } @@ -957,22 +955,22 @@ pub unsafe extern "C" fn jb_set_bool(js: &mut JsonBuilder, key: *const c_char, v } #[no_mangle] -pub unsafe extern "C" fn jb_close(js: &mut JsonBuilder) -> bool { +pub unsafe extern fn jb_close(js: &mut JsonBuilder) -> bool { js.close().is_ok() } #[no_mangle] -pub unsafe extern "C" fn jb_len(js: &JsonBuilder) -> usize { +pub unsafe extern fn jb_len(js: &JsonBuilder) -> usize { js.buf.len() } #[no_mangle] -pub unsafe extern "C" fn jb_ptr(js: &mut JsonBuilder) -> *const u8 { +pub unsafe extern fn jb_ptr(js: &mut JsonBuilder) -> *const u8 { js.buf.as_ptr() } #[no_mangle] -pub unsafe extern "C" fn jb_get_mark(js: &mut JsonBuilder, mark: &mut JsonBuilderMark) { +pub unsafe extern fn jb_get_mark(js: &mut JsonBuilder, mark: &mut JsonBuilderMark) { let m = js.get_mark(); mark.position = m.position; mark.state_index = m.state_index; @@ -980,7 +978,7 @@ pub unsafe extern "C" fn jb_get_mark(js: &mut JsonBuilder, mark: &mut JsonBuilde } #[no_mangle] -pub unsafe extern "C" fn jb_restore_mark(js: &mut JsonBuilder, mark: &mut JsonBuilderMark) -> bool { +pub unsafe extern fn jb_restore_mark(js: &mut JsonBuilder, mark: &mut JsonBuilderMark) -> bool { js.restore_mark(mark).is_ok() } diff --git a/rust/src/kerberos.rs b/rust/src/kerberos.rs index e7c51cc2f28f..0fef1ec256c6 100644 --- a/rust/src/kerberos.rs +++ b/rust/src/kerberos.rs @@ -17,14 +17,14 @@ //! Kerberos parser wrapper module. -use nom7::IResult; -use nom7::error::{ErrorKind, ParseError}; -use nom7::number::streaming::le_u16; use der_parser6; use der_parser6::der::parse_der_oid; use der_parser6::error::BerError; use kerberos_parser::krb5::{ApReq, PrincipalName, Realm}; use kerberos_parser::krb5_parser::parse_ap_req; +use nom7::error::{ErrorKind, ParseError}; +use nom7::number::streaming::le_u16; +use nom7::IResult; #[derive(Debug)] pub enum SecBlobError { @@ -55,12 +55,11 @@ pub struct Kerberos5Ticket { pub sname: PrincipalName, } -fn parse_kerberos5_request_do(blob: &[u8]) -> IResult<&[u8], ApReq, SecBlobError> -{ - let (_,b) = der_parser6::parse_der(blob).map_err(nom7::Err::convert)?; - let blob = b.as_slice().or( - Err(nom7::Err::Error(SecBlobError::KrbFmtError)) - )?; +fn parse_kerberos5_request_do(blob: &[u8]) -> IResult<&[u8], ApReq, SecBlobError> { + let (_, b) = der_parser6::parse_der(blob).map_err(nom7::Err::convert)?; + let blob = b + .as_slice() + .or(Err(nom7::Err::Error(SecBlobError::KrbFmtError)))?; let parser = |i| { let (i, _base_o) = parse_der_oid(i)?; let (i, _tok_id) = le_u16(i)?; diff --git a/rust/src/krb/detect.rs b/rust/src/krb/detect.rs index 25cce9bcf826..0e9f33f7ae76 100644 --- a/rust/src/krb/detect.rs +++ b/rust/src/krb/detect.rs @@ -31,14 +31,14 @@ use nom7::IResult; use std::ffi::CStr; #[no_mangle] -pub unsafe extern "C" fn rs_krb5_tx_get_msgtype(tx: &mut KRB5Transaction, ptr: *mut u32) { +pub unsafe extern fn rs_krb5_tx_get_msgtype(tx: &mut KRB5Transaction, ptr: *mut u32) { *ptr = tx.msg_type.0; } /// Get error code, if present in transaction /// Return 0 if error code was filled, else 1 #[no_mangle] -pub unsafe extern "C" fn rs_krb5_tx_get_errcode(tx: &mut KRB5Transaction, ptr: *mut i32) -> u32 { +pub unsafe extern fn rs_krb5_tx_get_errcode(tx: &mut KRB5Transaction, ptr: *mut i32) -> u32 { match tx.error_code { Some(ref e) => { *ptr = e.0; @@ -49,7 +49,7 @@ pub unsafe extern "C" fn rs_krb5_tx_get_errcode(tx: &mut KRB5Transaction, ptr: * } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_tx_get_cname( +pub unsafe extern fn rs_krb5_tx_get_cname( tx: &mut KRB5Transaction, i: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref s) = tx.cname { @@ -64,7 +64,7 @@ pub unsafe extern "C" fn rs_krb5_tx_get_cname( } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_tx_get_sname( +pub unsafe extern fn rs_krb5_tx_get_sname( tx: &mut KRB5Transaction, i: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref s) = tx.sname { @@ -103,7 +103,6 @@ impl DetectKrb5TicketEncryptionList { } } - // Suppress large enum variant lint as the LIST is very large compared // to the boolean variant. #[derive(Debug)] @@ -212,7 +211,7 @@ pub fn detect_parse_encryption(i: &str) -> IResult<&str, DetectKrb5TicketEncrypt } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_detect_encryption_parse( +pub unsafe extern fn rs_krb5_detect_encryption_parse( ustr: *const std::os::raw::c_char, ) -> *mut DetectKrb5TicketEncryptionData { let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe @@ -226,7 +225,7 @@ pub unsafe extern "C" fn rs_krb5_detect_encryption_parse( } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_detect_encryption_match( +pub unsafe extern fn rs_krb5_detect_encryption_match( tx: &mut KRB5Transaction, ctx: &DetectKrb5TicketEncryptionData, ) -> std::os::raw::c_int { if let Some(x) = tx.ticket_etype { @@ -260,7 +259,7 @@ pub unsafe extern "C" fn rs_krb5_detect_encryption_match( } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_detect_encryption_free(ctx: &mut DetectKrb5TicketEncryptionData) { +pub unsafe extern fn rs_krb5_detect_encryption_free(ctx: &mut DetectKrb5TicketEncryptionData) { // Just unbox... std::mem::drop(Box::from_raw(ctx)); } diff --git a/rust/src/krb/krb5.rs b/rust/src/krb/krb5.rs index 3282d50ba78b..fe7af7d0cf60 100644 --- a/rust/src/krb/krb5.rs +++ b/rust/src/krb/krb5.rs @@ -17,17 +17,17 @@ // written by Pierre Chifflier -use std; -use std::ffi::CString; -use nom7::{Err, IResult}; -use nom7::number::streaming::be_u32; -use der_parser::der::der_read_element_header; -use der_parser::ber::Class; -use kerberos_parser::krb5_parser; -use kerberos_parser::krb5::{EncryptionType,ErrorCode,MessageType,PrincipalName,Realm}; use crate::applayer::{self, *}; use crate::core; -use crate::core::{AppProto,Flow,ALPROTO_FAILED,ALPROTO_UNKNOWN,Direction}; +use crate::core::{AppProto, Direction, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN}; +use der_parser::ber::Class; +use der_parser::der::der_read_element_header; +use kerberos_parser::krb5::{EncryptionType, ErrorCode, MessageType, PrincipalName, Realm}; +use kerberos_parser::krb5_parser; +use nom7::number::streaming::be_u32; +use nom7::{Err, IResult}; +use std; +use std::ffi::CString; #[derive(AppLayerEvent)] pub enum KRB5Event { @@ -122,13 +122,15 @@ impl KRB5State { /// Returns 0 in case of success, or -1 on error fn parse(&mut self, i: &[u8], direction: Direction) -> i32 { match der_read_element_header(i) { - Ok((_rem,hdr)) => { + Ok((_rem, hdr)) => { // Kerberos messages start with an APPLICATION header - if hdr.class() != Class::Application { return 0; } + if hdr.class() != Class::Application { + return 0; + } match hdr.tag().0 { 10 => { let req = krb5_parser::parse_as_req(i); - if let Ok((_,kdc_req)) = req { + if let Ok((_, kdc_req)) = req { let mut tx = self.new_tx(direction); tx.msg_type = MessageType::KRB_AS_REQ; tx.cname = kdc_req.req_body.cname; @@ -138,10 +140,10 @@ impl KRB5State { self.transactions.push(tx); }; self.req_id = 10; - }, + } 11 => { let res = krb5_parser::parse_as_rep(i); - if let Ok((_,kdc_rep)) = res { + if let Ok((_, kdc_rep)) = res { let mut tx = self.new_tx(direction); tx.msg_type = MessageType::KRB_AS_REP; if self.req_id > 0 { @@ -160,10 +162,10 @@ impl KRB5State { } }; self.req_id = 0; - }, + } 12 => { let req = krb5_parser::parse_tgs_req(i); - if let Ok((_,kdc_req)) = req { + if let Ok((_, kdc_req)) = req { let mut tx = self.new_tx(direction); tx.msg_type = MessageType::KRB_TGS_REQ; tx.cname = kdc_req.req_body.cname; @@ -173,10 +175,10 @@ impl KRB5State { self.transactions.push(tx); }; self.req_id = 12; - }, + } 13 => { let res = krb5_parser::parse_tgs_rep(i); - if let Ok((_,kdc_rep)) = res { + if let Ok((_, kdc_rep)) = res { let mut tx = self.new_tx(direction); tx.msg_type = MessageType::KRB_TGS_REP; if self.req_id > 0 { @@ -195,16 +197,16 @@ impl KRB5State { } }; self.req_id = 0; - }, + } 14 => { self.req_id = 14; - }, + } 15 => { self.req_id = 0; - }, + } 30 => { let res = krb5_parser::parse_krb_error(i); - if let Ok((_,error)) = res { + if let Ok((_, error)) = res { let mut tx = self.new_tx(direction); if self.req_id > 0 { // set request type only if previous message @@ -219,21 +221,23 @@ impl KRB5State { self.transactions.push(tx); }; self.req_id = 0; - }, - _ => { SCLogDebug!("unknown/unsupported tag {}", hdr.tag()); }, + } + _ => { + SCLogDebug!("unknown/unsupported tag {}", hdr.tag()); + } } 0 - }, + } Err(Err::Incomplete(_)) => { SCLogDebug!("Insufficient data while parsing KRB5 data"); self.set_event(KRB5Event::MalformedData); -1 - }, + } Err(_) => { SCLogDebug!("Error while parsing KRB5 data"); self.set_event(KRB5Event::MalformedData); -1 - }, + } } } @@ -270,7 +274,7 @@ impl KRB5State { impl KRB5Transaction { pub fn new(direction: Direction, id: u64) -> KRB5Transaction { - let krbtx = KRB5Transaction{ + let krbtx = KRB5Transaction { msg_type: MessageType(0), cname: None, realm: None, @@ -287,25 +291,23 @@ impl KRB5Transaction { } /// Return true if Kerberos `EncryptionType` is weak -pub fn test_weak_encryption(alg:EncryptionType) -> bool { +pub fn test_weak_encryption(alg: EncryptionType) -> bool { match alg { - EncryptionType::AES128_CTS_HMAC_SHA1_96 | - EncryptionType::AES256_CTS_HMAC_SHA1_96 | - EncryptionType::AES128_CTS_HMAC_SHA256_128 | - EncryptionType::AES256_CTS_HMAC_SHA384_192 | - EncryptionType::CAMELLIA128_CTS_CMAC | - EncryptionType::CAMELLIA256_CTS_CMAC => false, + EncryptionType::AES128_CTS_HMAC_SHA1_96 + | EncryptionType::AES256_CTS_HMAC_SHA1_96 + | EncryptionType::AES128_CTS_HMAC_SHA256_128 + | EncryptionType::AES256_CTS_HMAC_SHA384_192 + | EncryptionType::CAMELLIA128_CTS_CMAC + | EncryptionType::CAMELLIA256_CTS_CMAC => false, _ => true, // all other ciphers are weak or deprecated } } - - - - /// Returns *mut KRB5State #[no_mangle] -pub extern "C" fn rs_krb5_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_krb5_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = KRB5State::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; @@ -314,121 +316,122 @@ pub extern "C" fn rs_krb5_state_new(_orig_state: *mut std::os::raw::c_void, _ori /// Params: /// - state: *mut KRB5State as void pointer #[no_mangle] -pub extern "C" fn rs_krb5_state_free(state: *mut std::os::raw::c_void) { - let mut state: Box = unsafe{Box::from_raw(state as _)}; +pub extern fn rs_krb5_state_free(state: *mut std::os::raw::c_void) { + let mut state: Box = unsafe { Box::from_raw(state as _) }; state.free(); } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_state_get_tx(state: *mut std::os::raw::c_void, - tx_id: u64) - -> *mut std::os::raw::c_void -{ - let state = cast_pointer!(state,KRB5State); +pub unsafe extern fn rs_krb5_state_get_tx( + state: *mut std::os::raw::c_void, tx_id: u64, +) -> *mut std::os::raw::c_void { + let state = cast_pointer!(state, KRB5State); match state.get_tx_by_id(tx_id) { Some(tx) => tx as *const _ as *mut _, - None => std::ptr::null_mut(), + None => std::ptr::null_mut(), } } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_state_get_tx_count(state: *mut std::os::raw::c_void) - -> u64 -{ - let state = cast_pointer!(state,KRB5State); +pub unsafe extern fn rs_krb5_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { + let state = cast_pointer!(state, KRB5State); state.tx_id } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_state_tx_free(state: *mut std::os::raw::c_void, - tx_id: u64) -{ - let state = cast_pointer!(state,KRB5State); +pub unsafe extern fn rs_krb5_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { + let state = cast_pointer!(state, KRB5State); state.free_tx(tx_id); } #[no_mangle] -pub extern "C" fn rs_krb5_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void, - _direction: u8) - -> std::os::raw::c_int -{ +pub extern fn rs_krb5_tx_get_alstate_progress( + _tx: *mut std::os::raw::c_void, _direction: u8, +) -> std::os::raw::c_int { 1 } -static mut ALPROTO_KRB5 : AppProto = ALPROTO_UNKNOWN; +static mut ALPROTO_KRB5: AppProto = ALPROTO_UNKNOWN; #[no_mangle] -pub unsafe extern "C" fn rs_krb5_probing_parser(_flow: *const Flow, - _direction: u8, - input:*const u8, input_len: u32, - _rdir: *mut u8) -> AppProto -{ - let slice = build_slice!(input,input_len as usize); +pub unsafe extern fn rs_krb5_probing_parser( + _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, +) -> AppProto { + let slice = build_slice!(input, input_len as usize); let alproto = ALPROTO_KRB5; - if slice.len() <= 10 { return ALPROTO_FAILED; } + if slice.len() <= 10 { + return ALPROTO_FAILED; + } match der_read_element_header(slice) { Ok((rem, ref hdr)) => { // Kerberos messages start with an APPLICATION header - if hdr.class() != Class::Application { return ALPROTO_FAILED; } + if hdr.class() != Class::Application { + return ALPROTO_FAILED; + } // Tag number should be <= 30 - if hdr.tag().0 > 30 { return ALPROTO_FAILED; } + if hdr.tag().0 > 30 { + return ALPROTO_FAILED; + } // Kerberos messages contain sequences - if rem.is_empty() || rem[0] != 0x30 { return ALPROTO_FAILED; } + if rem.is_empty() || rem[0] != 0x30 { + return ALPROTO_FAILED; + } // Check kerberos version - if let Ok((rem,_hdr)) = der_read_element_header(rem) { + if let Ok((rem, _hdr)) = der_read_element_header(rem) { if rem.len() > 5 { #[allow(clippy::single_match)] - match (rem[2],rem[3],rem[4]) { + match (rem[2], rem[3], rem[4]) { // Encoding of DER integer 5 (version) - (2,1,5) => { return alproto; }, - _ => (), + (2, 1, 5) => { + return alproto; + } + _ => (), } } } return ALPROTO_FAILED; - }, + } Err(Err::Incomplete(_)) => { return ALPROTO_UNKNOWN; - }, + } Err(_) => { return ALPROTO_FAILED; - }, + } } } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_probing_parser_tcp(_flow: *const Flow, - direction: u8, - input:*const u8, input_len: u32, - rdir: *mut u8) -> AppProto -{ - let slice = build_slice!(input,input_len as usize); - if slice.len() <= 14 { return ALPROTO_FAILED; } - match be_u32(slice) as IResult<&[u8],u32> { +pub unsafe extern fn rs_krb5_probing_parser_tcp( + _flow: *const Flow, direction: u8, input: *const u8, input_len: u32, rdir: *mut u8, +) -> AppProto { + let slice = build_slice!(input, input_len as usize); + if slice.len() <= 14 { + return ALPROTO_FAILED; + } + match be_u32(slice) as IResult<&[u8], u32> { Ok((rem, record_mark)) => { // protocol implementations forbid very large requests - if record_mark > 16384 { return ALPROTO_FAILED; } - return rs_krb5_probing_parser(_flow, direction, - rem.as_ptr(), rem.len() as u32, rdir); - }, + if record_mark > 16384 { + return ALPROTO_FAILED; + } + return rs_krb5_probing_parser(_flow, direction, rem.as_ptr(), rem.len() as u32, rdir); + } Err(Err::Incomplete(_)) => { return ALPROTO_UNKNOWN; - }, + } Err(_) => { return ALPROTO_FAILED; - }, + } } } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_parse_request(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { +pub unsafe extern fn rs_krb5_parse_request( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let buf = stream_slice.as_slice(); - let state = cast_pointer!(state,KRB5State); + let state = cast_pointer!(state, KRB5State); if state.parse(buf, Direction::ToServer) < 0 { return AppLayerResult::err(); } @@ -436,14 +439,12 @@ pub unsafe extern "C" fn rs_krb5_parse_request(_flow: *const core::Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_parse_response(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { +pub unsafe extern fn rs_krb5_parse_response( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let buf = stream_slice.as_slice(); - let state = cast_pointer!(state,KRB5State); + let state = cast_pointer!(state, KRB5State); if state.parse(buf, Direction::ToClient) < 0 { return AppLayerResult::err(); } @@ -451,23 +452,24 @@ pub unsafe extern "C" fn rs_krb5_parse_response(_flow: *const core::Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_parse_request_tcp(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { - let state = cast_pointer!(state,KRB5State); +pub unsafe extern fn rs_krb5_parse_request_tcp( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { + let state = cast_pointer!(state, KRB5State); let buf = stream_slice.as_slice(); - let mut v : Vec; + let mut v: Vec; let tcp_buffer = match state.record_ts { 0 => buf, _ => { // sanity check to avoid memory exhaustion if state.defrag_buf_ts.len() + buf.len() > 100000 { - SCLogDebug!("rs_krb5_parse_request_tcp: TCP buffer exploded {} {}", - state.defrag_buf_ts.len(), buf.len()); + SCLogDebug!( + "rs_krb5_parse_request_tcp: TCP buffer exploded {} {}", + state.defrag_buf_ts.len(), + buf.len() + ); return AppLayerResult::err(); } v = state.defrag_buf_ts.split_off(0); @@ -478,11 +480,11 @@ pub unsafe extern "C" fn rs_krb5_parse_request_tcp(_flow: *const core::Flow, let mut cur_i = tcp_buffer; while !cur_i.is_empty() { if state.record_ts == 0 { - match be_u32(cur_i) as IResult<&[u8],u32> { - Ok((rem,record)) => { + match be_u32(cur_i) as IResult<&[u8], u32> { + Ok((rem, record)) => { state.record_ts = record as usize; cur_i = rem; - }, + } Err(Err::Incomplete(_)) => { state.defrag_buf_ts.extend_from_slice(cur_i); return AppLayerResult::ok(); @@ -509,23 +511,24 @@ pub unsafe extern "C" fn rs_krb5_parse_request_tcp(_flow: *const core::Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_krb5_parse_response_tcp(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { - let state = cast_pointer!(state,KRB5State); +pub unsafe extern fn rs_krb5_parse_response_tcp( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { + let state = cast_pointer!(state, KRB5State); let buf = stream_slice.as_slice(); - let mut v : Vec; + let mut v: Vec; let tcp_buffer = match state.record_tc { 0 => buf, _ => { // sanity check to avoid memory exhaustion if state.defrag_buf_tc.len() + buf.len() > 100000 { - SCLogDebug!("rs_krb5_parse_response_tcp: TCP buffer exploded {} {}", - state.defrag_buf_tc.len(), buf.len()); + SCLogDebug!( + "rs_krb5_parse_response_tcp: TCP buffer exploded {} {}", + state.defrag_buf_tc.len(), + buf.len() + ); return AppLayerResult::err(); } v = state.defrag_buf_tc.split_off(0); @@ -536,11 +539,11 @@ pub unsafe extern "C" fn rs_krb5_parse_response_tcp(_flow: *const core::Flow, let mut cur_i = tcp_buffer; while !cur_i.is_empty() { if state.record_tc == 0 { - match be_u32(cur_i) as IResult<&[u8],_> { - Ok((rem,record)) => { + match be_u32(cur_i) as IResult<&[u8], _> { + Ok((rem, record)) => { state.record_tc = record as usize; cur_i = rem; - }, + } Err(Err::Incomplete(_)) => { state.defrag_buf_tc.extend_from_slice(cur_i); return AppLayerResult::ok(); @@ -569,40 +572,40 @@ pub unsafe extern "C" fn rs_krb5_parse_response_tcp(_flow: *const core::Flow, export_tx_data_get!(rs_krb5_get_tx_data, KRB5Transaction); export_state_data_get!(rs_krb5_get_state_data, KRB5State); -const PARSER_NAME : &[u8] = b"krb5\0"; +const PARSER_NAME: &[u8] = b"krb5\0"; #[no_mangle] -pub unsafe extern "C" fn rs_register_krb5_parser() { +pub unsafe extern fn rs_register_krb5_parser() { let default_port = CString::new("88").unwrap(); let mut parser = RustParser { - name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char, - default_port : default_port.as_ptr(), - ipproto : core::IPPROTO_UDP, - probe_ts : Some(rs_krb5_probing_parser), - probe_tc : Some(rs_krb5_probing_parser), - min_depth : 0, - max_depth : 16, - state_new : rs_krb5_state_new, - state_free : rs_krb5_state_free, - tx_free : rs_krb5_state_tx_free, - parse_ts : rs_krb5_parse_request, - parse_tc : rs_krb5_parse_response, - get_tx_count : rs_krb5_state_get_tx_count, - get_tx : rs_krb5_state_get_tx, - tx_comp_st_ts : 1, - tx_comp_st_tc : 1, - tx_get_progress : rs_krb5_tx_get_alstate_progress, - get_eventinfo : Some(KRB5Event::get_event_info), - get_eventinfo_byid : Some(KRB5Event::get_event_info_by_id), - localstorage_new : None, - localstorage_free : None, - get_tx_files : None, - get_tx_iterator : Some(applayer::state_get_tx_iterator::), - get_tx_data : rs_krb5_get_tx_data, - get_state_data : rs_krb5_get_state_data, - apply_tx_config : None, - flags : 0, - truncate : None, + name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, + default_port: default_port.as_ptr(), + ipproto: core::IPPROTO_UDP, + probe_ts: Some(rs_krb5_probing_parser), + probe_tc: Some(rs_krb5_probing_parser), + min_depth: 0, + max_depth: 16, + state_new: rs_krb5_state_new, + state_free: rs_krb5_state_free, + tx_free: rs_krb5_state_tx_free, + parse_ts: rs_krb5_parse_request, + parse_tc: rs_krb5_parse_response, + get_tx_count: rs_krb5_state_get_tx_count, + get_tx: rs_krb5_state_get_tx, + tx_comp_st_ts: 1, + tx_comp_st_tc: 1, + tx_get_progress: rs_krb5_tx_get_alstate_progress, + get_eventinfo: Some(KRB5Event::get_event_info), + get_eventinfo_byid: Some(KRB5Event::get_event_info_by_id), + localstorage_new: None, + localstorage_free: None, + get_tx_files: None, + get_tx_iterator: Some(applayer::state_get_tx_iterator::), + get_tx_data: rs_krb5_get_tx_data, + get_state_data: rs_krb5_get_state_data, + apply_tx_config: None, + flags: 0, + truncate: None, get_frame_id_by_name: None, get_frame_name_by_id: None, }; diff --git a/rust/src/krb/log.rs b/rust/src/krb/log.rs index 58c0d64b4893..e3377f35567f 100644 --- a/rust/src/krb/log.rs +++ b/rust/src/krb/log.rs @@ -18,10 +18,9 @@ // written by Pierre Chifflier use crate::jsonbuilder::{JsonBuilder, JsonError}; -use crate::krb::krb5::{KRB5Transaction,test_weak_encryption}; +use crate::krb::krb5::{test_weak_encryption, KRB5Transaction}; -fn krb5_log_response(jsb: &mut JsonBuilder, tx: &mut KRB5Transaction) -> Result<(), JsonError> -{ +fn krb5_log_response(jsb: &mut JsonBuilder, tx: &mut KRB5Transaction) -> Result<(), JsonError> { jsb.open_object("krb5")?; match tx.error_code { Some(c) => { @@ -35,30 +34,35 @@ fn krb5_log_response(jsb: &mut JsonBuilder, tx: &mut KRB5Transaction) -> Result< jsb.set_string("failed_request", "UNKNOWN")?; } jsb.set_string("error_code", &format!("{:?}", c))?; - }, - None => { jsb.set_string("msg_type", &format!("{:?}", tx.msg_type))?; }, + } + None => { + jsb.set_string("msg_type", &format!("{:?}", tx.msg_type))?; + } } let cname = match tx.cname { Some(ref x) => format!("{}", x), - None => "".to_owned(), + None => "".to_owned(), }; let realm = match tx.realm { Some(ref x) => x.0.to_string(), - None => "".to_owned(), + None => "".to_owned(), }; let sname = match tx.sname { Some(ref x) => format!("{}", x), - None => "".to_owned(), + None => "".to_owned(), }; let encryption = match tx.etype { Some(ref x) => format!("{:?}", x), - None => "".to_owned(), + None => "".to_owned(), }; jsb.set_string("cname", &cname)?; jsb.set_string("realm", &realm)?; jsb.set_string("sname", &sname)?; jsb.set_string("encryption", &encryption)?; - jsb.set_bool("weak_encryption", tx.etype.map_or(false,test_weak_encryption))?; + jsb.set_bool( + "weak_encryption", + tx.etype.map_or(false, test_weak_encryption), + )?; if let Some(x) = tx.ticket_etype { let refs = format!("{:?}", x); jsb.set_string("ticket_encryption", &refs)?; @@ -70,7 +74,6 @@ fn krb5_log_response(jsb: &mut JsonBuilder, tx: &mut KRB5Transaction) -> Result< } #[no_mangle] -pub extern "C" fn rs_krb5_log_json_response(tx: &mut KRB5Transaction, jsb: &mut JsonBuilder) -> bool -{ +pub extern fn rs_krb5_log_json_response(tx: &mut KRB5Transaction, jsb: &mut JsonBuilder) -> bool { krb5_log_response(jsb, tx).is_ok() } diff --git a/rust/src/krb/mod.rs b/rust/src/krb/mod.rs index ca6237d7bb6b..d13990241dd4 100644 --- a/rust/src/krb/mod.rs +++ b/rust/src/krb/mod.rs @@ -19,6 +19,6 @@ // written by Pierre Chifflier -pub mod krb5; pub mod detect; +pub mod krb5; pub mod log; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index da2859637783..e1ac51e165a2 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -21,27 +21,21 @@ //! the components written in Rust. #![cfg_attr(feature = "strict", deny(warnings))] - // Allow these patterns as its a style we like. #![allow(clippy::needless_return)] #![allow(clippy::let_and_return)] #![allow(clippy::uninlined_format_args)] - // We find this makes sense at time. #![allow(clippy::module_inception)] - // The match macro is not always more clear. But its use is // recommended where it makes sense. #![allow(clippy::match_like_matches_macro)] - // Something we should be conscious of, but due to interfacing with C // is unavoidable at this time. #![allow(clippy::too_many_arguments)] - // This would be nice, but having this lint enables causes // clippy --fix to make changes that don't meet our MSRV. #![allow(clippy::derivable_impls)] - // TODO: All unsafe functions should have a safety doc, even if its // just due to FFI. #![allow(clippy::missing_safety_doc)] @@ -75,44 +69,44 @@ pub mod conf; pub mod jsonbuilder; #[macro_use] pub mod applayer; -pub mod frames; +pub mod detect; pub mod filecontainer; pub mod filetracker; +pub mod frames; pub mod kerberos; -pub mod detect; #[cfg(feature = "lua")] pub mod lua; +pub mod dcerpc; pub mod dns; -pub mod nfs; pub mod ftp; -pub mod smb; pub mod krb; -pub mod dcerpc; pub mod modbus; +pub mod nfs; +pub mod smb; pub mod ike; pub mod snmp; -pub mod ntp; -pub mod tftp; +pub mod applayertemplate; +pub mod asn1; +pub mod bittorrent_dht; pub mod dhcp; -pub mod sip; -pub mod rfb; +pub mod ffi; +pub mod http2; +pub mod lzma; +pub mod mime; pub mod mqtt; +pub mod ntp; pub mod pgsql; -pub mod telnet; -pub mod applayertemplate; +pub mod plugin; +pub mod quic; pub mod rdp; -pub mod x509; -pub mod asn1; -pub mod mime; +pub mod rfb; +pub mod sip; pub mod ssh; -pub mod http2; -pub mod quic; -pub mod bittorrent_dht; -pub mod plugin; -pub mod lzma; +pub mod telnet; +pub mod tftp; pub mod util; -pub mod ffi; +pub mod x509; diff --git a/rust/src/log.rs b/rust/src/log.rs index 744169a97039..45344717730b 100644 --- a/rust/src/log.rs +++ b/rust/src/log.rs @@ -41,9 +41,7 @@ pub enum Level { pub static mut LEVEL: i32 = Level::NotSet as i32; pub fn get_log_level() -> i32 { - unsafe { - LEVEL - } + unsafe { LEVEL } } pub fn log_set_level(level: i32) { @@ -53,7 +51,7 @@ pub fn log_set_level(level: i32) { } #[no_mangle] -pub extern "C" fn rs_log_set_level(level: i32) { +pub extern fn rs_log_set_level(level: i32) { log_set_level(level); } @@ -67,17 +65,10 @@ fn basename(filename: &str) -> &str { return filename; } -pub fn sclog(level: Level, file: &str, line: u32, function: &str, - message: &str) -{ +pub fn sclog(level: Level, file: &str, line: u32, function: &str, message: &str) { let filename = basename(file); let noext = &filename[0..filename.len() - 3]; - sc_log_message(level, - filename, - line, - function, - noext, - message); + sc_log_message(level, filename, line, function, noext, message); } // This macro returns the function name. @@ -86,16 +77,16 @@ pub fn sclog(level: Level, file: &str, line: u32, function: &str, // is released under the MIT license as there is currently no macro in Rust // to provide the function name. #[macro_export(local_inner_macros)] -macro_rules!function { +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] - }} + // 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] + }}; } #[macro_export] @@ -158,20 +149,17 @@ macro_rules!SCLogDebug { // about unused variables, but is otherwise the equivalent to a no-op. #[cfg(not(feature = "debug"))] #[macro_export] -macro_rules!SCLogDebug { - ($($arg:tt)*) => () +macro_rules! SCLogDebug { + ($($arg:tt)*) => {}; } /// SCLogMessage wrapper. If the Suricata C context is not registered /// a more basic log format will be used (for example, when running /// Rust unit tests). -pub fn sc_log_message(level: Level, - filename: &str, - line: std::os::raw::c_uint, - function: &str, - module: &str, - message: &str) -> std::os::raw::c_int -{ +pub fn sc_log_message( + level: Level, filename: &str, line: std::os::raw::c_uint, function: &str, module: &str, + message: &str, +) -> std::os::raw::c_int { unsafe { if let Some(c) = SC { return (c.SCLogMessage)( @@ -180,7 +168,8 @@ pub fn sc_log_message(level: Level, line, to_safe_cstring(function).as_ptr(), to_safe_cstring(module).as_ptr(), - to_safe_cstring(message).as_ptr()); + to_safe_cstring(message).as_ptr(), + ); } } @@ -205,8 +194,6 @@ fn to_safe_cstring(val: &str) -> CString { } match CString::new(safe) { Ok(cstr) => cstr, - _ => { - CString::new("").unwrap() - } + _ => CString::new("").unwrap(), } } diff --git a/rust/src/lua.rs b/rust/src/lua.rs index 4fce2a824944..70fb64d9508f 100644 --- a/rust/src/lua.rs +++ b/rust/src/lua.rs @@ -42,7 +42,6 @@ pub struct LuaState { } impl LuaState { - pub fn newtable(&self) { unsafe { lua_createtable(self.lua, 0, 0); diff --git a/rust/src/lzma.rs b/rust/src/lzma.rs index e10d803a6e2c..26041a6154a2 100644 --- a/rust/src/lzma.rs +++ b/rust/src/lzma.rs @@ -57,7 +57,7 @@ impl From for LzmaStatus { /// Use the lzma algorithm to decompress a chunk of data. #[no_mangle] -pub unsafe extern "C" fn lzma_decompress( +pub unsafe extern fn lzma_decompress( input: *const u8, input_len: &mut usize, output: *mut u8, output_len: &mut usize, memlimit: usize, ) -> LzmaStatus { diff --git a/rust/src/mime/mod.rs b/rust/src/mime/mod.rs index 6f4a9bc21301..ec352db8c5c9 100644 --- a/rust/src/mime/mod.rs +++ b/rust/src/mime/mod.rs @@ -40,17 +40,11 @@ pub fn mime_parse_value_delimited(input: &[u8]) -> IResult<&[u8], &[u8]> { pub fn mime_parse_header_token(input: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> { // from RFC2047 : like ch.is_ascii_whitespace but without 0x0c FORM-FEED - let (input, _) = take_while(|ch: u8| ch == 0x20 - || ch == 0x09 - || ch == 0x0a - || ch == 0x0d)(input)?; + let (input, _) = + take_while(|ch: u8| ch == 0x20 || ch == 0x09 || ch == 0x0a || ch == 0x0d)(input)?; let (input, name) = take_until("=")(input)?; let (input, _) = tag("=")(input)?; - let (input, value) = alt(( - mime_parse_value_delimited, - complete(take_until(";")), - rest - ))(input)?; + let (input, value) = alt((mime_parse_value_delimited, complete(take_until(";")), rest))(input)?; let (input, _) = opt(complete(tag(";")))(input)?; return Ok((input, (name, value))); } @@ -133,7 +127,7 @@ fn mime_find_header_token<'a>( pub const RS_MIME_MAX_TOKEN_LEN: usize = 255; #[no_mangle] -pub unsafe extern "C" fn rs_mime_find_header_token( +pub unsafe extern fn rs_mime_find_header_token( hinput: *const u8, hlen: u32, tinput: *const u8, tlen: u32, outbuf: &mut [u8; 255], outlen: *mut u32, ) -> bool { diff --git a/rust/src/modbus/detect.rs b/rust/src/modbus/detect.rs index fdd5d51db9f5..d43b90c3ced8 100644 --- a/rust/src/modbus/detect.rs +++ b/rust/src/modbus/detect.rs @@ -135,7 +135,7 @@ fn parse_range(min_str: &str, max_str: &str) -> Result, ()> { /// Intermediary function between the C code and the parsing functions. #[no_mangle] -pub unsafe extern "C" fn rs_modbus_parse(c_arg: *const c_char) -> *mut c_void { +pub unsafe extern fn rs_modbus_parse(c_arg: *const c_char) -> *mut c_void { if c_arg.is_null() { return std::ptr::null_mut(); } @@ -152,7 +152,7 @@ pub unsafe extern "C" fn rs_modbus_parse(c_arg: *const c_char) -> *mut c_void { } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_free(ptr: *mut c_void) { +pub unsafe extern fn rs_modbus_free(ptr: *mut c_void) { if !ptr.is_null() { let _ = Box::from_raw(ptr as *mut DetectModbusRust); } @@ -161,7 +161,7 @@ pub unsafe extern "C" fn rs_modbus_free(ptr: *mut c_void) { /// Compares a transaction to a signature to determine whether the transaction /// matches the signature. If it does, 1 is returned; otherwise 0 is returned. #[no_mangle] -pub extern "C" fn rs_modbus_inspect(tx: &ModbusTransaction, modbus: &DetectModbusRust) -> u8 { +pub extern fn rs_modbus_inspect(tx: &ModbusTransaction, modbus: &DetectModbusRust) -> u8 { // All necessary information can be found in the request (value inspection currently // only supports write functions, which hold the value in the request). // Only inspect the response in the case where there is no request. diff --git a/rust/src/modbus/log.rs b/rust/src/modbus/log.rs index 6724291de786..1e6e48324a87 100644 --- a/rust/src/modbus/log.rs +++ b/rust/src/modbus/log.rs @@ -21,7 +21,7 @@ use crate::jsonbuilder::{JsonBuilder, JsonError}; use sawp_modbus::{Data, Message, Read, Write}; #[no_mangle] -pub extern "C" fn rs_modbus_to_json(tx: &mut ModbusTransaction, js: &mut JsonBuilder) -> bool { +pub extern fn rs_modbus_to_json(tx: &mut ModbusTransaction, js: &mut JsonBuilder) -> bool { log(tx, js).is_ok() } diff --git a/rust/src/modbus/modbus.rs b/rust/src/modbus/modbus.rs index 246e9cae6d6c..70f5ec64f597 100644 --- a/rust/src/modbus/modbus.rs +++ b/rust/src/modbus/modbus.rs @@ -271,7 +271,7 @@ impl ModbusState { /// Probe input to see if it looks like Modbus. #[no_mangle] -pub extern "C" fn rs_modbus_probe( +pub extern fn rs_modbus_probe( _flow: *const core::Flow, _direction: u8, input: *const u8, len: u32, _rdir: *mut u8, ) -> AppProto { let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, len as usize) }; @@ -283,28 +283,27 @@ pub extern "C" fn rs_modbus_probe( } #[no_mangle] -pub extern "C" fn rs_modbus_state_new( +pub extern fn rs_modbus_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { Box::into_raw(Box::new(ModbusState::new())) as *mut std::os::raw::c_void } #[no_mangle] -pub extern "C" fn rs_modbus_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_modbus_state_free(state: *mut std::os::raw::c_void) { let _state: Box = unsafe { Box::from_raw(state as *mut ModbusState) }; } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_modbus_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, ModbusState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_parse_request( +pub unsafe extern fn rs_modbus_parse_request( _flow: *const core::Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let buf = stream_slice.as_slice(); if buf.is_empty() { @@ -320,10 +319,9 @@ pub unsafe extern "C" fn rs_modbus_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_parse_response( +pub unsafe extern fn rs_modbus_parse_response( _flow: *const core::Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let buf = stream_slice.as_slice(); if buf.is_empty() { @@ -339,13 +337,13 @@ pub unsafe extern "C" fn rs_modbus_parse_response( } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_modbus_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, ModbusState); state.tx_id } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_state_get_tx( +pub unsafe extern fn rs_modbus_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, ModbusState); @@ -356,7 +354,7 @@ pub unsafe extern "C" fn rs_modbus_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_tx_get_alstate_progress( +pub unsafe extern fn rs_modbus_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, ModbusTransaction); @@ -364,7 +362,7 @@ pub unsafe extern "C" fn rs_modbus_tx_get_alstate_progress( } #[no_mangle] -pub unsafe extern "C" fn rs_modbus_state_get_tx_data( +pub unsafe extern fn rs_modbus_state_get_tx_data( tx: *mut std::os::raw::c_void, ) -> *mut AppLayerTxData { let tx = cast_pointer!(tx, ModbusTransaction); @@ -374,7 +372,7 @@ pub unsafe extern "C" fn rs_modbus_state_get_tx_data( export_state_data_get!(rs_modbus_get_state_data, ModbusState); #[no_mangle] -pub unsafe extern "C" fn rs_modbus_register_parser() { +pub unsafe extern fn rs_modbus_register_parser() { let default_port = std::ffi::CString::new("[502]").unwrap(); let parser = RustParser { name: b"modbus\0".as_ptr() as *const std::os::raw::c_char, @@ -410,7 +408,12 @@ pub unsafe extern "C" fn rs_modbus_register_parser() { }; let ip_proto_str = CString::new("tcp").unwrap(); - if AppLayerProtoDetectConfProtoDetectionEnabledDefault(ip_proto_str.as_ptr(), parser.name, false) != 0 { + if AppLayerProtoDetectConfProtoDetectionEnabledDefault( + ip_proto_str.as_ptr(), + parser.name, + false, + ) != 0 + { let alproto = AppLayerRegisterProtocolDetection(&parser, 1); ALPROTO_MODBUS = alproto; if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { @@ -428,14 +431,14 @@ pub mod test { pub struct ModbusMessage(*const c_void); #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_function(msg: *const ModbusMessage) -> u8 { + pub unsafe extern fn rs_modbus_message_get_function(msg: *const ModbusMessage) -> u8 { let msg = msg.as_ref().unwrap().0 as *const Message; let msg = msg.as_ref().unwrap(); msg.function.raw } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_subfunction(msg: *const ModbusMessage) -> u16 { + pub unsafe extern fn rs_modbus_message_get_subfunction(msg: *const ModbusMessage) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; let msg = msg.as_ref().unwrap(); if let Data::Diagnostic { func, data: _ } = &msg.data { @@ -446,7 +449,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_read_request_address( + pub unsafe extern fn rs_modbus_message_get_read_request_address( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -463,7 +466,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_read_request_quantity( + pub unsafe extern fn rs_modbus_message_get_read_request_quantity( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -480,7 +483,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_read_address( + pub unsafe extern fn rs_modbus_message_get_rw_multreq_read_address( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -501,7 +504,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_read_quantity( + pub unsafe extern fn rs_modbus_message_get_rw_multreq_read_quantity( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -522,7 +525,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_write_address( + pub unsafe extern fn rs_modbus_message_get_rw_multreq_write_address( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -544,7 +547,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_write_quantity( + pub unsafe extern fn rs_modbus_message_get_rw_multreq_write_quantity( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -566,7 +569,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_write_data( + pub unsafe extern fn rs_modbus_message_get_rw_multreq_write_data( msg: *const ModbusMessage, data_len: *mut usize, ) -> *const u8 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -589,7 +592,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_write_multreq_address( + pub unsafe extern fn rs_modbus_message_get_write_multreq_address( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -607,7 +610,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_write_multreq_quantity( + pub unsafe extern fn rs_modbus_message_get_write_multreq_quantity( msg: *const ModbusMessage, ) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -625,7 +628,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_write_multreq_data( + pub unsafe extern fn rs_modbus_message_get_write_multreq_data( msg: *const ModbusMessage, data_len: *mut usize, ) -> *const u8 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -644,7 +647,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_and_mask(msg: *const ModbusMessage) -> u16 { + pub unsafe extern fn rs_modbus_message_get_and_mask(msg: *const ModbusMessage) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; let msg = msg.as_ref().unwrap(); if let Data::Write(Write::Mask { @@ -660,7 +663,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_or_mask(msg: *const ModbusMessage) -> u16 { + pub unsafe extern fn rs_modbus_message_get_or_mask(msg: *const ModbusMessage) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; let msg = msg.as_ref().unwrap(); if let Data::Write(Write::Mask { @@ -676,7 +679,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_write_address(msg: *const ModbusMessage) -> u16 { + pub unsafe extern fn rs_modbus_message_get_write_address(msg: *const ModbusMessage) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; let msg = msg.as_ref().unwrap(); if let Data::Write(Write::Other { address, data: _ }) = &msg.data { @@ -687,7 +690,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_write_data(msg: *const ModbusMessage) -> u16 { + pub unsafe extern fn rs_modbus_message_get_write_data(msg: *const ModbusMessage) -> u16 { let msg = msg.as_ref().unwrap().0 as *const Message; let msg = msg.as_ref().unwrap(); if let Data::Write(Write::Other { address: _, data }) = &msg.data { @@ -698,7 +701,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_message_get_bytevec_data( + pub unsafe extern fn rs_modbus_message_get_bytevec_data( msg: *const ModbusMessage, data_len: *mut usize, ) -> *const u8 { let msg = msg.as_ref().unwrap().0 as *const Message; @@ -712,7 +715,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_state_get_tx_request( + pub unsafe extern fn rs_modbus_state_get_tx_request( state: *mut std::os::raw::c_void, tx_id: u64, ) -> ModbusMessage { let state = cast_pointer!(state, ModbusState); @@ -728,7 +731,7 @@ pub mod test { } #[no_mangle] - pub unsafe extern "C" fn rs_modbus_state_get_tx_response( + pub unsafe extern fn rs_modbus_state_get_tx_response( state: *mut std::os::raw::c_void, tx_id: u64, ) -> ModbusMessage { let state = cast_pointer!(state, ModbusState); diff --git a/rust/src/mqtt/detect.rs b/rust/src/mqtt/detect.rs index df0c78e8497f..e3f0a8e358f4 100644 --- a/rust/src/mqtt/detect.rs +++ b/rust/src/mqtt/detect.rs @@ -50,7 +50,7 @@ fn check_flag_state(flag_state: MQTTFlagState, flag_value: bool, ok: &mut bool) } #[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_type(tx: &MQTTTransaction, mtype: u8) -> u8 { +pub extern fn rs_mqtt_tx_has_type(tx: &MQTTTransaction, mtype: u8) -> u8 { for msg in tx.msg.iter() { if mtype == msg.header.message_type as u8 { return 1; @@ -60,7 +60,7 @@ pub extern "C" fn rs_mqtt_tx_has_type(tx: &MQTTTransaction, mtype: u8) -> u8 { } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_cstr_message_code( +pub unsafe extern fn rs_mqtt_cstr_message_code( str: *const std::os::raw::c_char, ) -> std::os::raw::c_int { let msgtype: &CStr = CStr::from_ptr(str); @@ -73,7 +73,7 @@ pub unsafe extern "C" fn rs_mqtt_cstr_message_code( } #[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_flags( +pub extern fn rs_mqtt_tx_has_flags( tx: &MQTTTransaction, qretain: MQTTFlagState, qdup: MQTTFlagState, ) -> u8 { for msg in tx.msg.iter() { @@ -89,7 +89,7 @@ pub extern "C" fn rs_mqtt_tx_has_flags( } #[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_qos(tx: &MQTTTransaction, qos: u8) -> u8 { +pub extern fn rs_mqtt_tx_has_qos(tx: &MQTTTransaction, qos: u8) -> u8 { for msg in tx.msg.iter() { if qos == msg.header.qos_level { return 1; @@ -99,12 +99,12 @@ pub extern "C" fn rs_mqtt_tx_has_qos(tx: &MQTTTransaction, qos: u8) -> u8 { } #[no_mangle] -pub extern "C" fn rs_mqtt_tx_get_protocol_version(state: &MQTTState) -> u8 { +pub extern fn rs_mqtt_tx_get_protocol_version(state: &MQTTState) -> u8 { return state.protocol_version; } #[no_mangle] -pub extern "C" fn rs_mqtt_tx_has_connect_flags( +pub extern fn rs_mqtt_tx_has_connect_flags( tx: &MQTTTransaction, username: MQTTFlagState, password: MQTTFlagState, will: MQTTFlagState, will_retain: MQTTFlagState, clean_session: MQTTFlagState, ) -> u8 { @@ -125,7 +125,7 @@ pub extern "C" fn rs_mqtt_tx_has_connect_flags( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_clientid( +pub unsafe extern fn rs_mqtt_tx_get_connect_clientid( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -145,7 +145,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_clientid( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_username( +pub unsafe extern fn rs_mqtt_tx_get_connect_username( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -167,7 +167,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_username( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_password( +pub unsafe extern fn rs_mqtt_tx_get_connect_password( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -188,7 +188,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_password( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willtopic( +pub unsafe extern fn rs_mqtt_tx_get_connect_willtopic( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -210,7 +210,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willtopic( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willmessage( +pub unsafe extern fn rs_mqtt_tx_get_connect_willmessage( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -232,7 +232,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_willmessage( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connect_protocol_string( +pub unsafe extern fn rs_mqtt_tx_get_connect_protocol_string( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -252,7 +252,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connect_protocol_string( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_connack_sessionpresent( +pub unsafe extern fn rs_mqtt_tx_get_connack_sessionpresent( tx: &MQTTTransaction, session_present: *mut bool, ) -> u8 { for msg in tx.msg.iter() { @@ -265,7 +265,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_connack_sessionpresent( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_publish_topic( +pub unsafe extern fn rs_mqtt_tx_get_publish_topic( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -286,7 +286,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_publish_topic( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_publish_message( +pub unsafe extern fn rs_mqtt_tx_get_publish_message( tx: &MQTTTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { for msg in tx.msg.iter() { @@ -307,7 +307,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_publish_message( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_subscribe_topic( +pub unsafe extern fn rs_mqtt_tx_get_subscribe_topic( tx: &MQTTTransaction, i: u32, buf: *mut *const u8, len: *mut u32, ) -> u8 { let mut offset = 0; @@ -333,7 +333,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_subscribe_topic( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_unsubscribe_topic( +pub unsafe extern fn rs_mqtt_tx_get_unsubscribe_topic( tx: &MQTTTransaction, i: u32, buf: *mut *const u8, len: *mut u32, ) -> u8 { let mut offset = 0; @@ -359,7 +359,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_unsubscribe_topic( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_reason_code(tx: &MQTTTransaction, result: *mut u8) -> u8 { +pub unsafe extern fn rs_mqtt_tx_get_reason_code(tx: &MQTTTransaction, result: *mut u8) -> u8 { for msg in tx.msg.iter() { match msg.op { MQTTOperation::PUBACK(ref v) @@ -392,7 +392,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_reason_code(tx: &MQTTTransaction, result } #[no_mangle] -pub extern "C" fn rs_mqtt_tx_unsuback_has_reason_code(tx: &MQTTTransaction, code: u8) -> u8 { +pub extern fn rs_mqtt_tx_unsuback_has_reason_code(tx: &MQTTTransaction, code: u8) -> u8 { for msg in tx.msg.iter() { if let MQTTOperation::UNSUBACK(ref unsuback) = msg.op { if let Some(ref reason_codes) = unsuback.reason_codes { @@ -410,28 +410,31 @@ pub extern "C" fn rs_mqtt_tx_unsuback_has_reason_code(tx: &MQTTTransaction, code #[cfg(test)] mod test { use super::*; + use crate::core::Direction; use crate::mqtt::mqtt::MQTTTransaction; use crate::mqtt::mqtt_message::*; use crate::mqtt::parser::FixedHeader; - use crate::core::Direction; use std; #[test] fn test_multi_unsubscribe() { - let mut t = MQTTTransaction::new(MQTTMessage { - header: FixedHeader { - message_type: MQTTTypeCode::UNSUBSCRIBE, - dup_flag: false, - qos_level: 0, - retain: false, - remaining_length: 0, + let mut t = MQTTTransaction::new( + MQTTMessage { + header: FixedHeader { + message_type: MQTTTypeCode::UNSUBSCRIBE, + dup_flag: false, + qos_level: 0, + retain: false, + remaining_length: 0, + }, + op: MQTTOperation::UNSUBSCRIBE(MQTTUnsubscribeData { + message_id: 1, + topics: vec!["foo".to_string(), "baar".to_string()], + properties: None, + }), }, - op: MQTTOperation::UNSUBSCRIBE(MQTTUnsubscribeData { - message_id: 1, - topics: vec!["foo".to_string(), "baar".to_string()], - properties: None, - }), - }, Direction::ToServer); + Direction::ToServer, + ); t.msg.push(MQTTMessage { header: FixedHeader { message_type: MQTTTypeCode::UNSUBSCRIBE, @@ -470,29 +473,32 @@ mod test { #[test] fn test_multi_subscribe() { - let mut t = MQTTTransaction::new(MQTTMessage { - header: FixedHeader { - message_type: MQTTTypeCode::SUBSCRIBE, - dup_flag: false, - qos_level: 0, - retain: false, - remaining_length: 0, + let mut t = MQTTTransaction::new( + MQTTMessage { + header: FixedHeader { + message_type: MQTTTypeCode::SUBSCRIBE, + dup_flag: false, + qos_level: 0, + retain: false, + remaining_length: 0, + }, + op: MQTTOperation::SUBSCRIBE(MQTTSubscribeData { + message_id: 1, + topics: vec![ + MQTTSubscribeTopicData { + topic_name: "foo".to_string(), + qos: 0, + }, + MQTTSubscribeTopicData { + topic_name: "baar".to_string(), + qos: 1, + }, + ], + properties: None, + }), }, - op: MQTTOperation::SUBSCRIBE(MQTTSubscribeData { - message_id: 1, - topics: vec![ - MQTTSubscribeTopicData { - topic_name: "foo".to_string(), - qos: 0, - }, - MQTTSubscribeTopicData { - topic_name: "baar".to_string(), - qos: 1, - }, - ], - properties: None, - }), - }, Direction::ToServer); + Direction::ToServer, + ); t.msg.push(MQTTMessage { header: FixedHeader { message_type: MQTTTypeCode::SUBSCRIBE, diff --git a/rust/src/mqtt/logger.rs b/rust/src/mqtt/logger.rs index af0db17bc2b8..653afc8f1081 100644 --- a/rust/src/mqtt/logger.rs +++ b/rust/src/mqtt/logger.rs @@ -297,7 +297,7 @@ fn log_mqtt(tx: &MQTTTransaction, flags: u32, js: &mut JsonBuilder) -> Result<() } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_logger_log( +pub unsafe extern fn rs_mqtt_logger_log( tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder, ) -> bool { let tx = cast_pointer!(tx, MQTTTransaction); diff --git a/rust/src/mqtt/mqtt.rs b/rust/src/mqtt/mqtt.rs index f1c37d83c881..3f531c5724af 100644 --- a/rust/src/mqtt/mqtt.rs +++ b/rust/src/mqtt/mqtt.rs @@ -183,11 +183,11 @@ impl MQTTState { } fn new_tx(&mut self, msg: MQTTMessage, toclient: bool) -> MQTTTransaction { - let direction = if toclient { - Direction::ToClient - } else { - Direction::ToServer - }; + let direction = if toclient { + Direction::ToClient + } else { + Direction::ToServer + }; let mut tx = MQTTTransaction::new(msg, direction); self.tx_id += 1; tx.tx_id = self.tx_id; @@ -608,7 +608,11 @@ impl MQTTState { } fn set_event_notx(&mut self, event: MQTTEvent, toclient: bool) { - let mut tx = MQTTTransaction::new_empty(if toclient { Direction::ToClient } else { Direction::ToServer }); + let mut tx = MQTTTransaction::new_empty(if toclient { + Direction::ToClient + } else { + Direction::ToServer + }); self.tx_id += 1; tx.tx_id = self.tx_id; if toclient { @@ -644,7 +648,7 @@ impl MQTTState { // C exports. #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_probing_parser( +pub unsafe extern fn rs_mqtt_probing_parser( _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { let buf = build_slice!(input, input_len as usize); @@ -666,7 +670,7 @@ pub unsafe extern "C" fn rs_mqtt_probing_parser( } #[no_mangle] -pub extern "C" fn rs_mqtt_state_new( +pub extern fn rs_mqtt_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = MQTTState::new(); @@ -675,18 +679,18 @@ pub extern "C" fn rs_mqtt_state_new( } #[no_mangle] -pub extern "C" fn rs_mqtt_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_mqtt_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(unsafe { Box::from_raw(state as *mut MQTTState) }); } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_mqtt_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, MQTTState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_parse_request( +pub unsafe extern fn rs_mqtt_parse_request( flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -695,7 +699,7 @@ pub unsafe extern "C" fn rs_mqtt_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_parse_response( +pub unsafe extern fn rs_mqtt_parse_response( flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -704,7 +708,7 @@ pub unsafe extern "C" fn rs_mqtt_parse_response( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_state_get_tx( +pub unsafe extern fn rs_mqtt_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, MQTTState); @@ -719,13 +723,13 @@ pub unsafe extern "C" fn rs_mqtt_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_mqtt_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, MQTTState); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_is_toclient( +pub unsafe extern fn rs_mqtt_tx_is_toclient( tx: *const std::os::raw::c_void, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, MQTTTransaction); @@ -736,7 +740,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_is_toclient( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_alstate_progress( +pub unsafe extern fn rs_mqtt_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, direction: u8, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, MQTTTransaction); @@ -756,7 +760,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_alstate_progress( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_get_logged( +pub unsafe extern fn rs_mqtt_tx_get_logged( _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, ) -> u32 { let tx = cast_pointer!(tx, MQTTTransaction); @@ -764,7 +768,7 @@ pub unsafe extern "C" fn rs_mqtt_tx_get_logged( } #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_tx_set_logged( +pub unsafe extern fn rs_mqtt_tx_set_logged( _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, logged: u32, ) { let tx = cast_pointer!(tx, MQTTTransaction); @@ -778,7 +782,7 @@ export_tx_data_get!(rs_mqtt_get_tx_data, MQTTTransaction); export_state_data_get!(rs_mqtt_get_state_data, MQTTState); #[no_mangle] -pub unsafe extern "C" fn rs_mqtt_register_parser(cfg_max_msg_len: u32) { +pub unsafe extern fn rs_mqtt_register_parser(cfg_max_msg_len: u32) { let default_port = CString::new("[1883]").unwrap(); let max_msg_len = &mut MAX_MSG_LEN; *max_msg_len = cfg_max_msg_len; diff --git a/rust/src/mqtt/parser.rs b/rust/src/mqtt/parser.rs index 8b1c8c542aba..7a36aca737bc 100644 --- a/rust/src/mqtt/parser.rs +++ b/rust/src/mqtt/parser.rs @@ -242,8 +242,7 @@ fn parse_connack(protocol_version: u8) -> impl Fn(&[u8]) -> IResult<&[u8], MQTTC #[inline] fn parse_publish( - protocol_version: u8, - has_id: bool, + protocol_version: u8, has_id: bool, ) -> impl Fn(&[u8]) -> IResult<&[u8], MQTTPublishData> { move |i: &[u8]| { let (i, topic) = parse_mqtt_string(i)?; @@ -414,8 +413,7 @@ fn parse_unsuback(protocol_version: u8) -> impl Fn(&[u8]) -> IResult<&[u8], MQTT #[inline] fn parse_disconnect( - remaining_len: usize, - protocol_version: u8, + remaining_len: usize, protocol_version: u8, ) -> impl Fn(&[u8]) -> IResult<&[u8], MQTTDisconnectData> { move |input: &[u8]| { if protocol_version < 5 { @@ -486,11 +484,7 @@ fn parse_auth(i: &[u8]) -> IResult<&[u8], MQTTAuthData> { #[inline] fn parse_remaining_message<'a>( - full: &'a [u8], - len: usize, - skiplen: usize, - header: FixedHeader, - message_type: MQTTTypeCode, + full: &'a [u8], len: usize, skiplen: usize, header: FixedHeader, message_type: MQTTTypeCode, protocol_version: u8, ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], MQTTMessage> { move |input: &'a [u8]| { @@ -632,9 +626,7 @@ fn parse_remaining_message<'a>( } pub fn parse_message( - input: &[u8], - protocol_version: u8, - max_msg_size: usize, + input: &[u8], protocol_version: u8, max_msg_size: usize, ) -> IResult<&[u8], MQTTMessage> { // Parse the fixed header first. This is identical across versions and can // be between 2 and 5 bytes long. diff --git a/rust/src/nfs/log.rs b/rust/src/nfs/log.rs index f6fdc8f5828a..492912769bf7 100644 --- a/rust/src/nfs/log.rs +++ b/rust/src/nfs/log.rs @@ -15,17 +15,14 @@ * 02110-1301, USA. */ -use std::string::String; use crate::jsonbuilder::{JsonBuilder, JsonError}; -use crate::nfs::types::*; use crate::nfs::nfs::*; +use crate::nfs::types::*; use crc::crc32; +use std::string::String; #[no_mangle] -pub extern "C" fn rs_nfs_tx_logging_is_filtered(state: &mut NFSState, - tx: &mut NFSTransaction) - -> u8 -{ +pub extern fn rs_nfs_tx_logging_is_filtered(state: &mut NFSState, tx: &mut NFSTransaction) -> u8 { // TODO probably best to make this configurable if state.nfs_version <= 3 && tx.procedure == NFSPROC3_GETATTR { @@ -35,15 +32,13 @@ pub extern "C" fn rs_nfs_tx_logging_is_filtered(state: &mut NFSState, return 0; } -fn nfs_rename_object(tx: &NFSTransaction, js: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn nfs_rename_object(tx: &NFSTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { let from_str = String::from_utf8_lossy(&tx.file_name); js.set_string("from", &from_str)?; let to_vec = match tx.type_data { - Some(NFSTransactionTypeData::RENAME(ref x)) => { x.to_vec() }, - _ => { Vec::new() } + Some(NFSTransactionTypeData::RENAME(ref x)) => x.to_vec(), + _ => Vec::new(), }; let to_str = String::from_utf8_lossy(&to_vec); @@ -51,9 +46,7 @@ fn nfs_rename_object(tx: &NFSTransaction, js: &mut JsonBuilder) Ok(()) } -fn nfs_creds_object(tx: &NFSTransaction, js: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn nfs_creds_object(tx: &NFSTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { let mach_name = String::from_utf8_lossy(&tx.request_machine_name); js.set_string("machine_name", &mach_name)?; js.set_uint("uid", tx.request_uid as u64)?; @@ -61,9 +54,7 @@ fn nfs_creds_object(tx: &NFSTransaction, js: &mut JsonBuilder) Ok(()) } -fn nfs_file_object(tx: &NFSTransaction, js: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn nfs_file_object(tx: &NFSTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { js.set_bool("first", tx.is_first)?; js.set_bool("last", tx.is_last)?; @@ -86,9 +77,9 @@ fn nfs_handle2crc(bytes: &[u8]) -> u32 { c } -fn nfs_common_header(state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn nfs_common_header( + state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder, +) -> Result<(), JsonError> { js.set_uint("version", state.nfs_version as u64)?; let proc_string = if state.nfs_version < 4 { nfs3_procedure_string(tx.procedure) @@ -110,24 +101,24 @@ fn nfs_common_header(state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder Ok(()) } -fn nfs_log_request(state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn nfs_log_request( + state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder, +) -> Result<(), JsonError> { nfs_common_header(state, tx, js)?; js.set_string("type", "request")?; Ok(()) } #[no_mangle] -pub extern "C" fn rs_nfs_log_json_request(state: &mut NFSState, tx: &mut NFSTransaction, - js: &mut JsonBuilder) -> bool -{ +pub extern fn rs_nfs_log_json_request( + state: &mut NFSState, tx: &mut NFSTransaction, js: &mut JsonBuilder, +) -> bool { nfs_log_request(state, tx, js).is_ok() } -fn nfs_log_response(state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn nfs_log_response( + state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder, +) -> Result<(), JsonError> { nfs_common_header(state, tx, js)?; js.set_string("type", "response")?; @@ -152,15 +143,13 @@ fn nfs_log_response(state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder) } #[no_mangle] -pub extern "C" fn rs_nfs_log_json_response(state: &mut NFSState, tx: &mut NFSTransaction, - js: &mut JsonBuilder) -> bool -{ +pub extern fn rs_nfs_log_json_response( + state: &mut NFSState, tx: &mut NFSTransaction, js: &mut JsonBuilder, +) -> bool { nfs_log_response(state, tx, js).is_ok() } -fn rpc_log_response(tx: &NFSTransaction, js: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn rpc_log_response(tx: &NFSTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { js.set_uint("xid", tx.xid as u64)?; js.set_string("status", &rpc_status_string(tx.rpc_response_status))?; js.set_string("auth_type", &rpc_auth_type_string(tx.auth_type))?; @@ -173,8 +162,6 @@ fn rpc_log_response(tx: &NFSTransaction, js: &mut JsonBuilder) } #[no_mangle] -pub extern "C" fn rs_rpc_log_json_response(tx: &mut NFSTransaction, - js: &mut JsonBuilder) -> bool -{ +pub extern fn rs_rpc_log_json_response(tx: &mut NFSTransaction, js: &mut JsonBuilder) -> bool { rpc_log_response(tx, js).is_ok() } diff --git a/rust/src/nfs/mod.rs b/rust/src/nfs/mod.rs index 2f6fe84df917..5dc3af3b63cc 100644 --- a/rust/src/nfs/mod.rs +++ b/rust/src/nfs/mod.rs @@ -17,17 +17,17 @@ //! NFS application layer, parser, logger module. -pub mod types; -pub mod rpc_records; -pub mod nfs_records; -pub mod nfs2_records; -pub mod nfs3_records; -pub mod nfs4_records; +pub mod log; pub mod nfs; pub mod nfs2; +pub mod nfs2_records; pub mod nfs3; +pub mod nfs3_records; pub mod nfs4; -pub mod log; +pub mod nfs4_records; +pub mod nfs_records; +pub mod rpc_records; +pub mod types; //#[cfg(feature = "lua")] //pub mod lua; diff --git a/rust/src/nfs/nfs.rs b/rust/src/nfs/nfs.rs index dfb5e0e72445..381573b2c476 100644 --- a/rust/src/nfs/nfs.rs +++ b/rust/src/nfs/nfs.rs @@ -26,17 +26,17 @@ use nom7::{Err, Needed}; use crate::applayer; use crate::applayer::*; -use crate::frames::*; -use crate::core::*; use crate::conf::*; -use crate::filetracker::*; +use crate::core::*; use crate::filecontainer::*; +use crate::filetracker::*; +use crate::frames::*; -use crate::nfs::types::*; -use crate::nfs::rpc_records::*; -use crate::nfs::nfs_records::*; use crate::nfs::nfs2_records::*; use crate::nfs::nfs3_records::*; +use crate::nfs::nfs_records::*; +use crate::nfs::rpc_records::*; +use crate::nfs::types::*; pub static mut SURICATA_NFS_FILE_CONFIG: Option<&'static SuricataFileContext> = None; @@ -150,22 +150,31 @@ impl NFSTransactionFile { return Self { file_tracker: FileTransferTracker::new(), ..Default::default() - } + }; } pub fn update_file_flags(&mut self, flow_file_flags: u16) { - let dir_flag = if self.direction == Direction::ToServer { STREAM_TOSERVER } else { STREAM_TOCLIENT }; + let dir_flag = if self.direction == Direction::ToServer { + STREAM_TOSERVER + } else { + STREAM_TOCLIENT + }; self.file_tracker.file_flags = unsafe { FileFlowFlagsToFlags(flow_file_flags, dir_flag) }; } } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_gettxfiles(_state: *mut std::ffi::c_void, tx: *mut std::ffi::c_void, direction: u8) -> AppLayerGetFileState { +pub unsafe extern fn rs_nfs_gettxfiles( + _state: *mut std::ffi::c_void, tx: *mut std::ffi::c_void, direction: u8, +) -> AppLayerGetFileState { let tx = cast_pointer!(tx, NFSTransaction); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let tx_dir : u8 = tdf.direction.into(); + let tx_dir: u8 = tdf.direction.into(); if direction & tx_dir != 0 { if let Some(sfcm) = { SURICATA_NFS_FILE_CONFIG } { - return AppLayerGetFileState { fc: &mut tdf.file_tracker.file, cfg: sfcm.files_sbcfg } + return AppLayerGetFileState { + fc: &mut tdf.file_tracker.file, + cfg: sfcm.files_sbcfg, + }; } } } @@ -174,8 +183,10 @@ pub unsafe extern "C" fn rs_nfs_gettxfiles(_state: *mut std::ffi::c_void, tx: *m #[derive(Debug)] pub struct NFSTransaction { - pub id: u64, /// internal id - pub xid: u32, /// nfs req/reply pair id + pub id: u64, + /// internal id + pub xid: u32, + /// nfs req/reply pair id pub procedure: u32, /// file name of the object we're dealing with. In case of RENAME /// this is the 'from' or original name. @@ -224,24 +235,24 @@ impl NFSTransaction { id: 0, xid: 0, procedure: 0, - file_name:Vec::new(), - request_machine_name:Vec::new(), - request_uid:0, - request_gid:0, - rpc_response_status:0, - nfs_response_status:0, + file_name: Vec::new(), + request_machine_name: Vec::new(), + request_uid: 0, + request_gid: 0, + rpc_response_status: 0, + nfs_response_status: 0, auth_type: 0, is_first: false, is_last: false, request_done: false, response_done: false, - nfs_version:0, + nfs_version: 0, is_file_tx: false, is_file_closed: false, - file_handle:Vec::new(), + file_handle: Vec::new(), type_data: None, tx_data: AppLayerTxData::new(), - } + }; } pub fn free(&mut self) { @@ -272,10 +283,10 @@ pub struct NFSRequestXidMap { pub progver: u32, pub procedure: u32, pub chunk_offset: u64, - pub file_name:Vec, + pub file_name: Vec, /// READ replies can use this to get to the handle the request used - pub file_handle:Vec, + pub file_handle: Vec, pub gssapi_proc: u32, pub gssapi_service: u32, @@ -287,8 +298,8 @@ impl NFSRequestXidMap { progver, procedure, chunk_offset, - file_name:Vec::new(), - file_handle:Vec::new(), + file_name: Vec::new(), + file_handle: Vec::new(), gssapi_proc: 0, gssapi_service: 0, } @@ -296,31 +307,37 @@ impl NFSRequestXidMap { } /// little wrapper around the FileTransferTracker::new_chunk method -pub fn filetracker_newchunk(ft: &mut FileTransferTracker, name: &[u8], data: &[u8], - chunk_offset: u64, chunk_size: u32, fill_bytes: u8, is_last: bool, xid: &u32) -{ +pub fn filetracker_newchunk( + ft: &mut FileTransferTracker, name: &[u8], data: &[u8], chunk_offset: u64, chunk_size: u32, + fill_bytes: u8, is_last: bool, xid: &u32, +) { if let Some(sfcm) = unsafe { SURICATA_NFS_FILE_CONFIG } { - ft.new_chunk(sfcm, name, data, chunk_offset, - chunk_size, fill_bytes, is_last, xid); + ft.new_chunk( + sfcm, + name, + data, + chunk_offset, + chunk_size, + fill_bytes, + is_last, + xid, + ); } } -fn filetracker_trunc(ft: &mut FileTransferTracker) -{ +fn filetracker_trunc(ft: &mut FileTransferTracker) { if let Some(sfcm) = unsafe { SURICATA_NFS_FILE_CONFIG } { ft.trunc(sfcm); } } -pub fn filetracker_close(ft: &mut FileTransferTracker) -{ +pub fn filetracker_close(ft: &mut FileTransferTracker) { if let Some(sfcm) = unsafe { SURICATA_NFS_FILE_CONFIG } { ft.close(sfcm); } } -fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) -> u32 -{ +fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) -> u32 { if let Some(sfcm) = unsafe { SURICATA_NFS_FILE_CONFIG } { ft.update(sfcm, data, gap_size) } else { @@ -328,7 +345,6 @@ fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) } } - #[derive(Debug)] pub struct NFSState { state_data: AppLayerStateData, @@ -395,23 +411,23 @@ impl NFSState { pub fn new() -> NFSState { NFSState { state_data: AppLayerStateData::new(), - requestmap:HashMap::new(), - namemap:HashMap::new(), + requestmap: HashMap::new(), + namemap: HashMap::new(), transactions: Vec::new(), - ts_chunk_xid:0, - tc_chunk_xid:0, - ts_chunk_left:0, - tc_chunk_left:0, - ts_chunk_fh:Vec::new(), - ts_ssn_gap:false, - tc_ssn_gap:false, - ts_gap:false, - tc_gap:false, - is_udp:false, - check_post_gap_file_txs:false, - post_gap_files_checked:false, - nfs_version:0, - tx_id:0, + ts_chunk_xid: 0, + tc_chunk_xid: 0, + ts_chunk_left: 0, + tc_chunk_left: 0, + ts_chunk_fh: Vec::new(), + ts_ssn_gap: false, + tc_ssn_gap: false, + ts_gap: false, + tc_gap: false, + is_udp: false, + check_post_gap_file_txs: false, + post_gap_files_checked: false, + nfs_version: 0, + tx_id: 0, ts: 0, } } @@ -434,7 +450,9 @@ impl NFSState { tx_old.request_done = true; tx_old.response_done = true; tx_old.is_file_closed = true; - tx_old.tx_data.set_event(NFSEvent::TooManyTransactions as u8); + tx_old + .tx_data + .set_event(NFSEvent::TooManyTransactions as u8); break; } } @@ -497,8 +515,9 @@ impl NFSState { } // TODO maybe not enough users to justify a func - pub fn mark_response_tx_done(&mut self, xid: u32, rpc_status: u32, nfs_status: u32, resp_handle: &Vec) - { + pub fn mark_response_tx_done( + &mut self, xid: u32, rpc_status: u32, nfs_status: u32, resp_handle: &Vec, + ) { if let Some(mytx) = self.get_tx_by_xid(xid) { mytx.response_done = true; mytx.rpc_response_status = rpc_status; @@ -506,108 +525,226 @@ impl NFSState { if mytx.file_handle.is_empty() && !resp_handle.is_empty() { mytx.file_handle = resp_handle.to_vec(); } - - SCLogDebug!("process_reply_record: tx ID {} XID {:04X} REQUEST {} RESPONSE {}", - mytx.id, mytx.xid, mytx.request_done, mytx.response_done); + + SCLogDebug!( + "process_reply_record: tx ID {} XID {:04X} REQUEST {} RESPONSE {}", + mytx.id, + mytx.xid, + mytx.request_done, + mytx.response_done + ); } else { //SCLogNotice!("process_reply_record: not TX found for XID {}", r.hdr.xid); } } - fn add_rpc_udp_ts_pdu(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64) -> Option { - let rpc_udp_ts_pdu = Frame::new(flow, stream_slice, input, rpc_len, NFSFrameType::RPCPdu as u8); + fn add_rpc_udp_ts_pdu( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64, + ) -> Option { + let rpc_udp_ts_pdu = Frame::new( + flow, + stream_slice, + input, + rpc_len, + NFSFrameType::RPCPdu as u8, + ); SCLogDebug!("rpc_udp_pdu ts frame {:?}", rpc_udp_ts_pdu); rpc_udp_ts_pdu } - fn add_rpc_udp_ts_creds(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], creds_len: i64) { - let _rpc_udp_ts_creds = Frame::new(flow, stream_slice, input, creds_len, NFSFrameType::RPCCreds as u8); + fn add_rpc_udp_ts_creds( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], creds_len: i64, + ) { + let _rpc_udp_ts_creds = Frame::new( + flow, + stream_slice, + input, + creds_len, + NFSFrameType::RPCCreds as u8, + ); SCLogDebug!("rpc_creds ts frame {:?}", _rpc_udp_ts_creds); } - fn add_rpc_tcp_ts_pdu(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64) -> Option { - let rpc_tcp_ts_pdu = Frame::new(flow, stream_slice, input, rpc_len, NFSFrameType::RPCPdu as u8); + fn add_rpc_tcp_ts_pdu( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64, + ) -> Option { + let rpc_tcp_ts_pdu = Frame::new( + flow, + stream_slice, + input, + rpc_len, + NFSFrameType::RPCPdu as u8, + ); SCLogDebug!("rpc_tcp_pdu ts frame {:?}", rpc_tcp_ts_pdu); rpc_tcp_ts_pdu } - fn add_rpc_tcp_ts_creds(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], creds_len: i64) { - let _rpc_tcp_ts_creds = Frame::new(flow, stream_slice, input, creds_len, NFSFrameType::RPCCreds as u8); + fn add_rpc_tcp_ts_creds( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], creds_len: i64, + ) { + let _rpc_tcp_ts_creds = Frame::new( + flow, + stream_slice, + input, + creds_len, + NFSFrameType::RPCCreds as u8, + ); SCLogDebug!("rpc_tcp_ts_creds {:?}", _rpc_tcp_ts_creds); } - fn add_nfs_ts_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs_len: i64) { - let _nfs_req_pdu = Frame::new(flow, stream_slice, input, nfs_len, NFSFrameType::NFSPdu as u8); + fn add_nfs_ts_frame( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs_len: i64, + ) { + let _nfs_req_pdu = Frame::new( + flow, + stream_slice, + input, + nfs_len, + NFSFrameType::NFSPdu as u8, + ); SCLogDebug!("nfs_ts_pdu Frame {:?}", _nfs_req_pdu); } - fn add_nfs4_ts_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs4_len: i64) { - let _nfs4_ts_pdu = Frame::new(flow, stream_slice, input, nfs4_len, NFSFrameType::NFS4Pdu as u8); + fn add_nfs4_ts_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs4_len: i64, + ) { + let _nfs4_ts_pdu = Frame::new( + flow, + stream_slice, + input, + nfs4_len, + NFSFrameType::NFS4Pdu as u8, + ); SCLogDebug!("nfs4_ts_pdu Frame: {:?}", _nfs4_ts_pdu); if nfs4_len > 8 { - let _nfs4_ts_hdr = Frame::new(flow, stream_slice, input, 8, NFSFrameType::NFS4Hdr as u8); + let _nfs4_ts_hdr = + Frame::new(flow, stream_slice, input, 8, NFSFrameType::NFS4Hdr as u8); SCLogDebug!("nfs4_ts_hdr Frame {:?}", _nfs4_ts_hdr); - let _nfs4_ts_ops = Frame::new(flow, stream_slice, &input[8..], nfs4_len - 8, NFSFrameType::NFS4Ops as u8); + let _nfs4_ts_ops = Frame::new( + flow, + stream_slice, + &input[8..], + nfs4_len - 8, + NFSFrameType::NFS4Ops as u8, + ); SCLogDebug!("nfs4_ts_ops Frame {:?}", _nfs4_ts_ops); } } - fn add_rpc_udp_tc_pdu(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64) -> Option { - let rpc_udp_tc_pdu = Frame::new(flow, stream_slice, input, rpc_len, NFSFrameType::RPCPdu as u8); + fn add_rpc_udp_tc_pdu( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64, + ) -> Option { + let rpc_udp_tc_pdu = Frame::new( + flow, + stream_slice, + input, + rpc_len, + NFSFrameType::RPCPdu as u8, + ); SCLogDebug!("rpc_tc_pdu frame {:?}", rpc_udp_tc_pdu); rpc_udp_tc_pdu } - fn add_rpc_udp_tc_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64) { + fn add_rpc_udp_tc_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_len: i64, + ) { if rpc_len > 8 { - let _rpc_udp_tc_hdr = Frame::new(flow, stream_slice, input, 8, NFSFrameType::RPCHdr as u8); - let _rpc_udp_tc_data = Frame::new(flow, stream_slice, &input[8..], rpc_len - 8, NFSFrameType::RPCData as u8); + let _rpc_udp_tc_hdr = + Frame::new(flow, stream_slice, input, 8, NFSFrameType::RPCHdr as u8); + let _rpc_udp_tc_data = Frame::new( + flow, + stream_slice, + &input[8..], + rpc_len - 8, + NFSFrameType::RPCData as u8, + ); SCLogDebug!("rpc_udp_tc_hdr frame {:?}", _rpc_udp_tc_hdr); SCLogDebug!("rpc_udp_tc_data frame {:?}", _rpc_udp_tc_data); } } - fn add_rpc_tcp_tc_pdu(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_tcp_len: i64) -> Option { - let rpc_tcp_tc_pdu = Frame::new(flow, stream_slice, input, rpc_tcp_len, NFSFrameType::RPCPdu as u8); + fn add_rpc_tcp_tc_pdu( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_tcp_len: i64, + ) -> Option { + let rpc_tcp_tc_pdu = Frame::new( + flow, + stream_slice, + input, + rpc_tcp_len, + NFSFrameType::RPCPdu as u8, + ); SCLogDebug!("rpc_tcp_pdu tc frame {:?}", rpc_tcp_tc_pdu); rpc_tcp_tc_pdu } - fn add_rpc_tcp_tc_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_tcp_len: i64) { + fn add_rpc_tcp_tc_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], rpc_tcp_len: i64, + ) { if rpc_tcp_len > 12 { - let _rpc_tcp_tc_hdr = Frame::new(flow, stream_slice, input, 12, NFSFrameType::RPCHdr as u8); - let _rpc_tcp_tc_data = Frame::new(flow, stream_slice, &input[12..], rpc_tcp_len - 12, NFSFrameType::RPCData as u8); + let _rpc_tcp_tc_hdr = + Frame::new(flow, stream_slice, input, 12, NFSFrameType::RPCHdr as u8); + let _rpc_tcp_tc_data = Frame::new( + flow, + stream_slice, + &input[12..], + rpc_tcp_len - 12, + NFSFrameType::RPCData as u8, + ); SCLogDebug!("rpc_tcp_tc_hdr frame {:?}", _rpc_tcp_tc_hdr); SCLogDebug!("rpc_tcp_tc_data frame {:?}", _rpc_tcp_tc_data); } } - fn add_nfs_tc_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs_len: i64) { + fn add_nfs_tc_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs_len: i64, + ) { if nfs_len > 0 { - let _nfs_tc_pdu = Frame::new(flow, stream_slice, input, nfs_len, NFSFrameType::NFSPdu as u8); + let _nfs_tc_pdu = Frame::new( + flow, + stream_slice, + input, + nfs_len, + NFSFrameType::NFSPdu as u8, + ); SCLogDebug!("nfs_tc_pdu frame {:?}", _nfs_tc_pdu); - let _nfs_res_status = Frame::new(flow, stream_slice, input, 4, NFSFrameType::NFSStatus as u8); + let _nfs_res_status = + Frame::new(flow, stream_slice, input, 4, NFSFrameType::NFSStatus as u8); SCLogDebug!("nfs_tc_status frame {:?}", _nfs_res_status); } } - fn add_nfs4_tc_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs4_len: i64) { + fn add_nfs4_tc_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nfs4_len: i64, + ) { if nfs4_len > 0 { - let _nfs4_tc_pdu = Frame::new(flow, stream_slice, input, nfs4_len, NFSFrameType::NFS4Pdu as u8); + let _nfs4_tc_pdu = Frame::new( + flow, + stream_slice, + input, + nfs4_len, + NFSFrameType::NFS4Pdu as u8, + ); SCLogDebug!("nfs4_tc_pdu frame {:?}", _nfs4_tc_pdu); - let _nfs4_tc_status = Frame::new(flow, stream_slice, input, 4, NFSFrameType::NFS4Status as u8); + let _nfs4_tc_status = + Frame::new(flow, stream_slice, input, 4, NFSFrameType::NFS4Status as u8); SCLogDebug!("nfs4_tc_status frame {:?}", _nfs4_tc_status); } if nfs4_len > 8 { - let _nfs4_tc_hdr = Frame::new(flow, stream_slice, input, 8, NFSFrameType::NFS4Hdr as u8); + let _nfs4_tc_hdr = + Frame::new(flow, stream_slice, input, 8, NFSFrameType::NFS4Hdr as u8); SCLogDebug!("nfs4_tc_hdr frame {:?}", _nfs4_tc_hdr); - let _nfs4_tc_ops = Frame::new(flow, stream_slice, &input[8..], nfs4_len - 8, NFSFrameType::NFS4Ops as u8); + let _nfs4_tc_ops = Frame::new( + flow, + stream_slice, + &input[8..], + nfs4_len - 8, + NFSFrameType::NFS4Ops as u8, + ); SCLogDebug!("nfs4_tc_ops frame {:?}", _nfs4_tc_ops); } } - fn post_gap_housekeeping_for_files(&mut self) - { + fn post_gap_housekeeping_for_files(&mut self) { let mut post_gap_txs = false; for tx in &mut self.transactions { if let Some(NFSTransactionTypeData::FILE(ref mut f)) = tx.type_data { @@ -630,8 +767,7 @@ impl NFSState { * can handle gaps. For the file transactions we set the current * (flow) time and prune them in 60 seconds if no update for them * was received. */ - fn post_gap_housekeeping(&mut self, dir: Direction) - { + fn post_gap_housekeeping(&mut self, dir: Direction) { if self.ts_ssn_gap && dir == Direction::ToServer { for tx in &mut self.transactions { if tx.id >= self.tx_id { @@ -677,10 +813,10 @@ impl NFSState { Ok((_, lookup)) => { SCLogDebug!("LOOKUP {:?}", lookup); xidmap.file_name = lookup.name_vec; - }, + } _ => { self.set_event(NFSEvent::MalformedData); - }, + } }; } @@ -689,39 +825,48 @@ impl NFSState { Some(n) => { SCLogDebug!("xidmap_handle2name: name {:?}", n); xidmap.file_name = n.to_vec(); - }, + } _ => { - SCLogDebug!("xidmap_handle2name: object {:?} not found", - xidmap.file_handle); - }, + SCLogDebug!( + "xidmap_handle2name: object {:?} not found", + xidmap.file_handle + ); + } } } /// complete request record - fn process_request_record(&mut self, flow: *const Flow, stream_slice: &StreamSlice, r: &RpcPacket) { - SCLogDebug!("REQUEST {} procedure {} ({}) blob size {}", - r.hdr.xid, r.procedure, self.requestmap.len(), r.prog_data.len()); + fn process_request_record( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, r: &RpcPacket, + ) { + SCLogDebug!( + "REQUEST {} procedure {} ({}) blob size {}", + r.hdr.xid, + r.procedure, + self.requestmap.len(), + r.prog_data.len() + ); match r.progver { 4 => { self.add_nfs4_ts_frames(flow, stream_slice, r.prog_data, r.prog_data_size as i64); self.process_request_record_v4(r) - }, + } 3 => { self.add_nfs_ts_frame(flow, stream_slice, r.prog_data, r.prog_data_size as i64); self.process_request_record_v3(r) - }, + } 2 => { self.add_nfs_ts_frame(flow, stream_slice, r.prog_data, r.prog_data_size as i64); self.process_request_record_v2(r) - }, - _ => { }, + } + _ => {} } } - pub fn new_file_tx(&mut self, file_handle: &[u8], file_name: &[u8], direction: Direction) - -> &mut NFSTransaction - { + pub fn new_file_tx( + &mut self, file_handle: &[u8], file_name: &[u8], direction: Direction, + ) -> &mut NFSTransaction { let mut tx = self.new_tx(); tx.file_name = file_name.to_vec(); tx.file_handle = file_handle.to_vec(); @@ -735,23 +880,31 @@ impl NFSState { d.update_file_flags(tx.tx_data.file_flags); } tx.tx_data.init_files_opened(); - tx.tx_data.file_tx = if direction == Direction::ToServer { STREAM_TOSERVER } else { STREAM_TOCLIENT }; // TODO direction to flag func? - SCLogDebug!("new_file_tx: TX FILE created: ID {} NAME {}", - tx.id, String::from_utf8_lossy(file_name)); + tx.tx_data.file_tx = if direction == Direction::ToServer { + STREAM_TOSERVER + } else { + STREAM_TOCLIENT + }; // TODO direction to flag func? + SCLogDebug!( + "new_file_tx: TX FILE created: ID {} NAME {}", + tx.id, + String::from_utf8_lossy(file_name) + ); self.transactions.push(tx); let tx_ref = self.transactions.last_mut(); return tx_ref.unwrap(); } - pub fn get_file_tx_by_handle(&mut self, file_handle: &[u8], direction: Direction) - -> Option<&mut NFSTransaction> - { + pub fn get_file_tx_by_handle( + &mut self, file_handle: &[u8], direction: Direction, + ) -> Option<&mut NFSTransaction> { let fh = file_handle.to_vec(); for tx in &mut self.transactions { if let Some(NFSTransactionTypeData::FILE(ref mut d)) = tx.type_data { - if tx.is_file_tx && !tx.is_file_closed && - direction == d.direction && - tx.file_handle == fh + if tx.is_file_tx + && !tx.is_file_closed + && direction == d.direction + && tx.file_handle == fh { tx.tx_data.update_file_flags(self.state_data.file_flags); d.update_file_flags(tx.tx_data.file_flags); @@ -790,9 +943,16 @@ impl NFSState { let found = match self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { Some(tx) => { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, w.file_data, w.offset, - w.file_len, fill_bytes as u8, is_last, &r.hdr.xid); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + w.file_data, + w.offset, + w.file_len, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); tdf.chunk_count += 1; if is_last { tdf.file_last_xid = r.hdr.xid; @@ -804,15 +964,22 @@ impl NFSState { } else { false } - }, - None => { false }, + } + None => false, }; if !found { let tx = self.new_file_tx(&file_handle, &file_name, Direction::ToServer); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, w.file_data, w.offset, - w.file_len, fill_bytes as u8, is_last, &r.hdr.xid); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + w.file_data, + w.offset, + w.file_len, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); tx.procedure = NFSPROC3_WRITE; tx.xid = r.hdr.xid; tx.is_first = true; @@ -830,13 +997,24 @@ impl NFSState { debug_validate_bug_on!(w.file_data.len() as u32 > w.count); self.ts_chunk_left = w.count - w.file_data.len() as u32; self.ts_chunk_fh = file_handle; - SCLogDebug!("REQUEST chunk_xid {:04X} chunk_left {}", self.ts_chunk_xid, self.ts_chunk_left); + SCLogDebug!( + "REQUEST chunk_xid {:04X} chunk_left {}", + self.ts_chunk_xid, + self.ts_chunk_left + ); } 0 } - fn process_partial_write_request_record<'b>(&mut self, r: &RpcPacket<'b>, w: &Nfs3RequestWrite<'b>) -> u32 { - SCLogDebug!("REQUEST {} procedure {} blob size {}", r.hdr.xid, r.procedure, r.prog_data.len()); + fn process_partial_write_request_record<'b>( + &mut self, r: &RpcPacket<'b>, w: &Nfs3RequestWrite<'b>, + ) -> u32 { + SCLogDebug!( + "REQUEST {} procedure {} blob size {}", + r.hdr.xid, + r.procedure, + r.prog_data.len() + ); let mut xidmap = NFSRequestXidMap::new(r.progver, r.procedure, 0); xidmap.file_handle = w.handle.value.to_vec(); @@ -845,21 +1023,31 @@ impl NFSState { return self.process_write_record(r, w); } - fn process_reply_record(&mut self, flow: *const Flow, stream_slice: &StreamSlice, r: &RpcReplyPacket) -> u32 { + fn process_reply_record( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, r: &RpcReplyPacket, + ) -> u32 { let mut xidmap; match self.requestmap.remove(&r.hdr.xid) { - Some(p) => { xidmap = p; }, + Some(p) => { + xidmap = p; + } _ => { - SCLogDebug!("REPLY: xid {:04X} NOT FOUND. GAPS? TS:{} TC:{}", - r.hdr.xid, self.ts_ssn_gap, self.tc_ssn_gap); + SCLogDebug!( + "REPLY: xid {:04X} NOT FOUND. GAPS? TS:{} TC:{}", + r.hdr.xid, + self.ts_ssn_gap, + self.tc_ssn_gap + ); // TODO we might be able to try to infer from the size + data // that this is a READ reply and pass the data to the file API anyway? return 0; - }, + } } - SCLogDebug!("process_reply_record: removed xid {:04X} from requestmap", - r.hdr.xid); + SCLogDebug!( + "process_reply_record: removed xid {:04X} from requestmap", + r.hdr.xid + ); if self.nfs_version == 0 { self.nfs_version = xidmap.progver as u16; @@ -871,24 +1059,24 @@ impl NFSState { self.add_nfs_tc_frames(flow, stream_slice, r.prog_data, r.prog_data_size as i64); self.process_reply_record_v2(r, &xidmap); return 0; - }, + } 3 => { SCLogDebug!("NFSv3 reply record"); self.add_nfs_tc_frames(flow, stream_slice, r.prog_data, r.prog_data_size as i64); self.process_reply_record_v3(r, &mut xidmap); return 0; - }, + } 4 => { SCLogDebug!("NFSv4 reply record"); self.add_nfs4_tc_frames(flow, stream_slice, r.prog_data, r.prog_data_size as i64); self.process_reply_record_v4(r, &mut xidmap); return 0; - }, + } _ => { SCLogDebug!("Invalid NFS version"); self.set_event(NFSEvent::NonExistingVersion); return 0; - }, + } } } @@ -901,14 +1089,19 @@ impl NFSState { self.tc_chunk_left }; if chunk_left == 0 { - return 0 + return 0; } let xid = if direction == Direction::ToServer { self.ts_chunk_xid } else { self.tc_chunk_xid }; - SCLogDebug!("filetracker_update: chunk left {}, input {} chunk_xid {:04X}", chunk_left, data.len(), xid); + SCLogDebug!( + "filetracker_update: chunk left {}, input {} chunk_xid {:04X}", + chunk_left, + data.len(), + xid + ); let file_handle; // we have the data that we expect @@ -926,11 +1119,11 @@ impl NFSState { match self.requestmap.remove(&xid) { None => { SCLogDebug!("no file handle found for XID {:04X}", xid); - return 0 - }, + return 0; + } Some(xidmap) => { file_handle = xidmap.file_handle.to_vec(); - }, + } } } } else { @@ -943,11 +1136,11 @@ impl NFSState { match self.requestmap.get(&xid) { None => { SCLogDebug!("no file handle found for XID {:04X}", xid); - return 0 - }, + return 0; + } Some(xidmap) => { file_handle = xidmap.file_handle.to_vec(); - }, + } } } } @@ -965,8 +1158,12 @@ impl NFSState { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { if ssn_gap { let queued_data = tdf.file_tracker.get_queued_size(); - if queued_data > 2000000 { // TODO should probably be configurable - SCLogDebug!("QUEUED size {} while we've seen GAPs. Truncating file.", queued_data); + if queued_data > 2000000 { + // TODO should probably be configurable + SCLogDebug!( + "QUEUED size {} while we've seen GAPs. Truncating file.", + queued_data + ); filetracker_trunc(&mut tdf.file_tracker); } } @@ -983,28 +1180,35 @@ impl NFSState { if direction == Direction::ToClient { tx.response_done = true; tx.is_file_closed = true; - SCLogDebug!("TX {} response is done now that the file track is ready", tx.id); + SCLogDebug!( + "TX {} response is done now that the file track is ready", + tx.id + ); } else { tx.request_done = true; tx.is_file_closed = true; - SCLogDebug!("TX {} request is done now that the file track is ready", tx.id); + SCLogDebug!( + "TX {} request is done now that the file track is ready", + tx.id + ); } } cs } else { 0 } - }, - None => { 0 }, + } + None => 0, }; return consumed; } /// xidmapr is an Option as it's already removed from the map if we /// have a complete record. Otherwise we do a lookup ourselves. - pub fn process_read_record<'b>(&mut self, r: &RpcReplyPacket<'b>, - reply: &NfsReplyRead<'b>, xidmapr: Option<&NFSRequestXidMap>) -> u32 - { + pub fn process_read_record<'b>( + &mut self, r: &RpcReplyPacket<'b>, reply: &NfsReplyRead<'b>, + xidmapr: Option<&NFSRequestXidMap>, + ) -> u32 { let file_name; let file_handle; let chunk_offset; @@ -1027,7 +1231,7 @@ impl NFSState { file_handle = xidmap.file_handle.to_vec(); chunk_offset = xidmap.chunk_offset; nfs_version = xidmap.progver; - }, + } None => { if let Some(xidmap) = self.requestmap.get(&r.hdr.xid) { file_name = xidmap.file_name.to_vec(); @@ -1037,26 +1241,37 @@ impl NFSState { } else { return 0; } - }, + } } SCLogDebug!("chunk_offset {}", chunk_offset); let mut is_last = reply.eof; - SCLogDebug!("XID {} is_last {} fill_bytes {} reply.count {} reply.data_len {} reply.data.len() {}", - r.hdr.xid, is_last, fill_bytes, reply.count, reply.data_len, reply.data.len()); + SCLogDebug!( + "XID {} is_last {} fill_bytes {} reply.count {} reply.data_len {} reply.data.len() {}", + r.hdr.xid, + is_last, + fill_bytes, + reply.count, + reply.data_len, + reply.data.len() + ); if nfs_version == 2 { let size = match parse_nfs2_attribs(reply.attr_blob) { Ok((_, ref attr)) => attr.asize, _ => 0, }; - SCLogDebug!("NFSv2 READ reply record: File size {}. Offset {} data len {}: total {}", - size, chunk_offset, reply.data_len, chunk_offset + reply.data_len as u64); + SCLogDebug!( + "NFSv2 READ reply record: File size {}. Offset {} data len {}: total {}", + size, + chunk_offset, + reply.data_len, + chunk_offset + reply.data_len as u64 + ); if size as u64 == chunk_offset + reply.data_len as u64 { is_last = true; } - } let is_partial = reply.data.len() < reply.count as usize; @@ -1066,9 +1281,16 @@ impl NFSState { Some(tx) => { SCLogDebug!("updated TX {:?}", tx); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, reply.data, chunk_offset, - reply.count, fill_bytes as u8, is_last, &r.hdr.xid); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + reply.data, + chunk_offset, + reply.count, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); tdf.chunk_count += 1; if is_last { tdf.file_last_xid = r.hdr.xid; @@ -1088,16 +1310,27 @@ impl NFSState { } else { false } - }, - None => { false }, + } + None => false, }; if !found { let tx = self.new_file_tx(&file_handle, &file_name, Direction::ToClient); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, reply.data, chunk_offset, - reply.count, fill_bytes as u8, is_last, &r.hdr.xid); - tx.procedure = if nfs_version < 4 { NFSPROC3_READ } else { NFSPROC4_READ }; + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + reply.data, + chunk_offset, + reply.count, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); + tx.procedure = if nfs_version < 4 { + NFSPROC3_READ + } else { + NFSPROC4_READ + }; tx.xid = r.hdr.xid; tx.is_first = true; if is_last { @@ -1123,15 +1356,27 @@ impl NFSState { self.tc_chunk_left = reply.count - reply.data.len() as u32; } - SCLogDebug!("REPLY {} to procedure {} blob size {} / {}: chunk_left {} chunk_xid {:04X}", - r.hdr.xid, NFSPROC3_READ, r.prog_data.len(), reply.count, self.tc_chunk_left, - self.tc_chunk_xid); + SCLogDebug!( + "REPLY {} to procedure {} blob size {} / {}: chunk_left {} chunk_xid {:04X}", + r.hdr.xid, + NFSPROC3_READ, + r.prog_data.len(), + reply.count, + self.tc_chunk_left, + self.tc_chunk_xid + ); 0 } - fn process_partial_read_reply_record<'b>(&mut self, r: &RpcReplyPacket<'b>, reply: &NfsReplyRead<'b>) -> u32 { - SCLogDebug!("REPLY {} to procedure READ blob size {} / {}", - r.hdr.xid, r.prog_data.len(), reply.count); + fn process_partial_read_reply_record<'b>( + &mut self, r: &RpcReplyPacket<'b>, reply: &NfsReplyRead<'b>, + ) -> u32 { + SCLogDebug!( + "REPLY {} to procedure READ blob size {} / {}", + r.hdr.xid, + r.prog_data.len(), + reply.count + ); return self.process_read_record(r, reply, None); } @@ -1174,8 +1419,10 @@ impl NFSState { } /// Handle partial records - fn parse_tcp_partial_data_ts<'b>(&mut self, base_input: &'b[u8], cur_i: &'b[u8], - phdr: &RpcRequestPacketPartial, rec_size: usize) -> AppLayerResult { + fn parse_tcp_partial_data_ts<'b>( + &mut self, base_input: &'b [u8], cur_i: &'b [u8], phdr: &RpcRequestPacketPartial, + rec_size: usize, + ) -> AppLayerResult { // special case: avoid buffering file write blobs // as these can be large. if rec_size >= 512 && cur_i.len() >= 44 { @@ -1184,7 +1431,10 @@ impl NFSState { // quick peek, are we in WRITE mode? if phdr.procedure == NFSPROC3_WRITE { - SCLogDebug!("CONFIRMED WRITE: large record {}, file chunk xfer", rec_size); + SCLogDebug!( + "CONFIRMED WRITE: large record {}, file chunk xfer", + rec_size + ); // lets try to parse the RPC record. Might fail with Incomplete. match parse_rpc(cur_i, false) { @@ -1230,7 +1480,9 @@ impl NFSState { } /// Parsing function, handling TCP chunks fragmentation - pub fn parse_tcp_data_ts(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult { + pub fn parse_tcp_data_ts( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let mut cur_i = stream_slice.as_slice(); // take care of in progress file chunk transfers // and skip buffer beyond it @@ -1255,27 +1507,34 @@ impl NFSState { SCLogDebug!("expected data found"); self.ts_gap = false; break; - }, + } 0 => { SCLogDebug!("incomplete, queue and retry with the next block (input {}). Looped {} times.", cur_i.len(), _cnt); - return AppLayerResult::incomplete(stream_slice.len() - cur_i.len() as u32, (cur_i.len() + 1) as u32); - }, + return AppLayerResult::incomplete( + stream_slice.len() - cur_i.len() as u32, + (cur_i.len() + 1) as u32, + ); + } -1 => { cur_i = &cur_i[1..]; if cur_i.is_empty() { - SCLogDebug!("all post-GAP data in this chunk was bad. Looped {} times.", _cnt); + SCLogDebug!( + "all post-GAP data in this chunk was bad. Looped {} times.", + _cnt + ); } - }, + } _ => { return AppLayerResult::err(); - }, + } } } SCLogDebug!("TS GAP handling done (input {})", cur_i.len()); } - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size self.add_rpc_tcp_ts_pdu(flow, stream_slice, cur_i, cur_i.len() as i64); match parse_rpc_request_partial(cur_i) { Ok((_, ref rpc_phdr)) => { @@ -1283,7 +1542,12 @@ impl NFSState { // Handle partial records if rec_size > cur_i.len() { - return self.parse_tcp_partial_data_ts(stream_slice.as_slice(), cur_i, rpc_phdr, rec_size); + return self.parse_tcp_partial_data_ts( + stream_slice.as_slice(), + cur_i, + rpc_phdr, + rec_size, + ); } // we have the full records size worth of data, @@ -1292,14 +1556,18 @@ impl NFSState { // go to the next record. match parse_rpc(cur_i, true) { Ok((_, ref rpc_record)) => { - self.add_rpc_tcp_ts_creds(flow, stream_slice, &cur_i[RPC_TCP_PRE_CREDS..], (rpc_record.creds_len + 8) as i64); + self.add_rpc_tcp_ts_creds( + flow, + stream_slice, + &cur_i[RPC_TCP_PRE_CREDS..], + (rpc_record.creds_len + 8) as i64, + ); self.process_request_record(flow, stream_slice, rpc_record); } Err(Err::Incomplete(_)) => { self.set_event(NFSEvent::MalformedData); } - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); } @@ -1313,20 +1581,22 @@ impl NFSState { // looks for. let n = usize::from(n); let need = if n > 28 { n } else { 28 }; - return AppLayerResult::incomplete(stream_slice.len() - cur_i.len() as u32, need as u32); + return AppLayerResult::incomplete( + stream_slice.len() - cur_i.len() as u32, + need as u32, + ); } return AppLayerResult::err(); } /* This error is fatal. If we failed to parse the RPC hdr we don't * have a length and we don't know where the next record starts. */ - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); } } - }; + } self.post_gap_housekeeping(Direction::ToServer); if self.check_post_gap_file_txs && !self.post_gap_files_checked { @@ -1338,17 +1608,22 @@ impl NFSState { } /// Handle partial records - fn parse_tcp_partial_data_tc<'b>(&mut self, base_input: &'b[u8], cur_i: &'b[u8], - phdr: &RpcPacketHeader, rec_size: usize) -> AppLayerResult { + fn parse_tcp_partial_data_tc<'b>( + &mut self, base_input: &'b [u8], cur_i: &'b [u8], phdr: &RpcPacketHeader, rec_size: usize, + ) -> AppLayerResult { // special case: avoid buffering file read blobs // as these can be large. - if rec_size >= 512 && cur_i.len() >= 128 {//36 { + if rec_size >= 512 && cur_i.len() >= 128 { + //36 { // large record, likely file xfer SCLogDebug!("large record {}, likely file xfer", rec_size); // quick peek, are in READ mode? if self.peek_reply_record(phdr) == NFSPROC3_READ { - SCLogDebug!("CONFIRMED large READ record {}, likely file chunk xfer", rec_size); + SCLogDebug!( + "CONFIRMED large READ record {}, likely file chunk xfer", + rec_size + ); // we should have enough data to parse the RPC record match parse_rpc_reply(cur_i, false) { @@ -1394,7 +1669,9 @@ impl NFSState { } /// Parsing function, handling TCP chunks fragmentation - pub fn parse_tcp_data_tc(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult { + pub fn parse_tcp_data_tc( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let mut cur_i = stream_slice.as_slice(); // take care of in progress file chunk transfers // and skip buffer beyond it @@ -1419,18 +1696,24 @@ impl NFSState { SCLogDebug!("expected data found"); self.tc_gap = false; break; - }, + } 0 => { SCLogDebug!("incomplete, queue and retry with the next block (input {}). Looped {} times.", cur_i.len(), _cnt); - return AppLayerResult::incomplete(stream_slice.len() - cur_i.len() as u32, (cur_i.len() + 1) as u32); - }, + return AppLayerResult::incomplete( + stream_slice.len() - cur_i.len() as u32, + (cur_i.len() + 1) as u32, + ); + } -1 => { cur_i = &cur_i[1..]; if cur_i.is_empty() { - SCLogDebug!("all post-GAP data in this chunk was bad. Looped {} times.", _cnt); + SCLogDebug!( + "all post-GAP data in this chunk was bad. Looped {} times.", + _cnt + ); } - }, + } _ => { return AppLayerResult::err(); } @@ -1446,13 +1729,23 @@ impl NFSState { let rec_size = (rpc_phdr.frag_len + 4) as usize; // see if we have all data available if rec_size > cur_i.len() { - return self.parse_tcp_partial_data_tc(stream_slice.as_slice(), cur_i, rpc_phdr, rec_size); + return self.parse_tcp_partial_data_tc( + stream_slice.as_slice(), + cur_i, + rpc_phdr, + rec_size, + ); } // we have the full data of the record, lets parse match parse_rpc_reply(cur_i, true) { Ok((_, ref rpc_record)) => { - self.add_rpc_tcp_tc_frames(flow, stream_slice, cur_i, cur_i.len() as i64); + self.add_rpc_tcp_tc_frames( + flow, + stream_slice, + cur_i, + cur_i.len() as i64, + ); self.process_reply_record(flow, stream_slice, rpc_record); } Err(Err::Incomplete(_)) => { @@ -1461,8 +1754,7 @@ impl NFSState { // bad. self.set_event(NFSEvent::MalformedData); } - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); } @@ -1476,20 +1768,22 @@ impl NFSState { // looks for. let n = usize::from(n); let need = if n > 12 { n } else { 12 }; - return AppLayerResult::incomplete(stream_slice.len() - cur_i.len() as u32, need as u32); + return AppLayerResult::incomplete( + stream_slice.len() - cur_i.len() as u32, + need as u32, + ); } return AppLayerResult::err(); } /* This error is fatal. If we failed to parse the RPC hdr we don't * have a length and we don't know where the next record starts. */ - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { self.set_event(NFSEvent::MalformedData); SCLogDebug!("Parsing failed: {:?}", _e); return AppLayerResult::err(); } } - }; + } self.post_gap_housekeeping(Direction::ToClient); if self.check_post_gap_file_txs && !self.post_gap_files_checked { self.post_gap_housekeeping_for_files(); @@ -1498,7 +1792,9 @@ impl NFSState { AppLayerResult::ok() } /// Parsing function - pub fn parse_udp_ts(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult { + pub fn parse_udp_ts( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let input = stream_slice.as_slice(); SCLogDebug!("parse_udp_ts ({})", input.len()); self.add_rpc_udp_ts_pdu(flow, stream_slice, input, input.len() as i64); @@ -1506,22 +1802,30 @@ impl NFSState { match parse_rpc_udp_request(input) { Ok((_, ref rpc_record)) => { self.is_udp = true; - self.add_rpc_udp_ts_creds(flow, stream_slice, &input[RPC_UDP_PRE_CREDS..], (rpc_record.creds_len + 8) as i64); + self.add_rpc_udp_ts_creds( + flow, + stream_slice, + &input[RPC_UDP_PRE_CREDS..], + (rpc_record.creds_len + 8) as i64, + ); match rpc_record.progver { 3 => { self.process_request_record(flow, stream_slice, rpc_record); - }, + } 2 => { - self.add_nfs_ts_frame(flow, stream_slice, rpc_record.prog_data, rpc_record.prog_data_size as i64); + self.add_nfs_ts_frame( + flow, + stream_slice, + rpc_record.prog_data, + rpc_record.prog_data_size as i64, + ); self.process_request_record_v2(rpc_record); - }, - _ => { }, + } + _ => {} } - }, - Err(Err::Incomplete(_)) => { - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Incomplete(_)) => {} + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("Parsing failed: {:?}", _e); } } @@ -1530,7 +1834,9 @@ impl NFSState { } /// Parsing function - pub fn parse_udp_tc(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult { + pub fn parse_udp_tc( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let input = stream_slice.as_slice(); SCLogDebug!("parse_udp_tc ({})", input.len()); self.add_rpc_udp_tc_pdu(flow, stream_slice, input, input.len() as i64); @@ -1540,11 +1846,9 @@ impl NFSState { self.is_udp = true; self.add_rpc_udp_tc_frames(flow, stream_slice, input, input.len() as i64); self.process_reply_record(flow, stream_slice, rpc_record); - }, - Err(Err::Incomplete(_)) => { - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Incomplete(_)) => {} + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("Parsing failed: {:?}", _e); } } @@ -1555,7 +1859,9 @@ impl NFSState { /// Returns *mut NFSState #[no_mangle] -pub extern "C" fn rs_nfs_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_nfs_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = NFSState::new(); let boxed = Box::new(state); SCLogDebug!("allocating state"); @@ -1565,7 +1871,7 @@ pub extern "C" fn rs_nfs_state_new(_orig_state: *mut std::os::raw::c_void, _orig /// Params: /// - state: *mut NFSState as void pointer #[no_mangle] -pub extern "C" fn rs_nfs_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_nfs_state_free(state: *mut std::os::raw::c_void) { // Just unbox... SCLogDebug!("freeing state"); std::mem::drop(unsafe { Box::from_raw(state as *mut NFSState) }); @@ -1573,13 +1879,10 @@ pub extern "C" fn rs_nfs_state_free(state: *mut std::os::raw::c_void) { /// C binding parse a NFS TCP request. Returns 1 on success, -1 on failure. #[no_mangle] -pub unsafe extern "C" fn rs_nfs_parse_request(flow: *const Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult -{ +pub unsafe extern fn rs_nfs_parse_request( + flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, NFSState); let flow = cast_pointer!(flow, Flow); @@ -1593,22 +1896,15 @@ pub unsafe extern "C" fn rs_nfs_parse_request(flow: *const Flow, } #[no_mangle] -pub extern "C" fn rs_nfs_parse_request_tcp_gap( - state: &mut NFSState, - input_len: u32) - -> AppLayerResult -{ +pub extern fn rs_nfs_parse_request_tcp_gap(state: &mut NFSState, input_len: u32) -> AppLayerResult { state.parse_tcp_data_ts_gap(input_len) } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_parse_response(flow: *const Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult -{ +pub unsafe extern fn rs_nfs_parse_response( + flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, NFSState); let flow = cast_pointer!(flow, Flow); @@ -1622,23 +1918,18 @@ pub unsafe extern "C" fn rs_nfs_parse_response(flow: *const Flow, } #[no_mangle] -pub extern "C" fn rs_nfs_parse_response_tcp_gap( - state: &mut NFSState, - input_len: u32) - -> AppLayerResult -{ +pub extern fn rs_nfs_parse_response_tcp_gap( + state: &mut NFSState, input_len: u32, +) -> AppLayerResult { state.parse_tcp_data_tc_gap(input_len) } /// C binding to parse an NFS/UDP request. Returns 1 on success, -1 on failure. #[no_mangle] -pub unsafe extern "C" fn rs_nfs_parse_request_udp(f: *const Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult -{ +pub unsafe extern fn rs_nfs_parse_request_udp( + f: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, NFSState); SCLogDebug!("parsing {} bytes of request data", stream_slice.len()); @@ -1646,32 +1937,26 @@ pub unsafe extern "C" fn rs_nfs_parse_request_udp(f: *const Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_parse_response_udp(f: *const Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult -{ +pub unsafe extern fn rs_nfs_parse_response_udp( + f: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, NFSState); SCLogDebug!("parsing {} bytes of response data", stream_slice.len()); state.parse_udp_tc(f, &stream_slice) } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_state_get_tx_count(state: *mut std::os::raw::c_void) - -> u64 -{ +pub unsafe extern fn rs_nfs_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, NFSState); SCLogDebug!("rs_nfs_state_get_tx_count: returning {}", state.tx_id); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_state_get_tx(state: *mut std::os::raw::c_void, - tx_id: u64) - -> *mut std::os::raw::c_void -{ +pub unsafe extern fn rs_nfs_state_get_tx( + state: *mut std::os::raw::c_void, tx_id: u64, +) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, NFSState); match state.get_tx_by_id(tx_id) { Some(tx) => { @@ -1684,18 +1969,15 @@ pub unsafe extern "C" fn rs_nfs_state_get_tx(state: *mut std::os::raw::c_void, } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_state_tx_free(state: *mut std::os::raw::c_void, - tx_id: u64) -{ +pub unsafe extern fn rs_nfs_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, NFSState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_tx_get_alstate_progress(tx: *mut std::os::raw::c_void, - direction: u8) - -> std::os::raw::c_int -{ +pub unsafe extern fn rs_nfs_tx_get_alstate_progress( + tx: *mut std::os::raw::c_void, direction: u8, +) -> std::os::raw::c_int { let tx = cast_pointer!(tx, NFSTransaction); if direction == Direction::ToServer.into() && tx.request_done { SCLogDebug!("TOSERVER progress 1"); @@ -1710,10 +1992,7 @@ pub unsafe extern "C" fn rs_nfs_tx_get_alstate_progress(tx: *mut std::os::raw::c } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_get_tx_data( - tx: *mut std::os::raw::c_void) - -> *mut AppLayerTxData -{ +pub unsafe extern fn rs_nfs_get_tx_data(tx: *mut std::os::raw::c_void) -> *mut AppLayerTxData { let tx = cast_pointer!(tx, NFSTransaction); return &mut tx.tx_data; } @@ -1724,11 +2003,9 @@ export_state_data_get!(rs_nfs_get_state_data, NFSState); /// otherwise get procs from the 'file_additional_procs'. /// Keep calling until 0 is returned. #[no_mangle] -pub unsafe extern "C" fn rs_nfs_tx_get_procedures(tx: &mut NFSTransaction, - i: u16, - procedure: *mut u32) - -> u8 -{ +pub unsafe extern fn rs_nfs_tx_get_procedures( + tx: &mut NFSTransaction, i: u16, procedure: *mut u32, +) -> u8 { if i == 0 { *procedure = tx.procedure; return 1; @@ -1752,15 +2029,12 @@ pub unsafe extern "C" fn rs_nfs_tx_get_procedures(tx: &mut NFSTransaction, } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_tx_get_version(tx: &mut NFSTransaction, - version: *mut u32) -{ +pub unsafe extern fn rs_nfs_tx_get_version(tx: &mut NFSTransaction, version: *mut u32) { *version = tx.nfs_version as u32; } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_init(context: &'static mut SuricataFileContext) -{ +pub unsafe extern fn rs_nfs_init(context: &'static mut SuricataFileContext) { SURICATA_NFS_FILE_CONFIG = Some(context); } @@ -1774,13 +2048,13 @@ fn nfs_probe_dir(i: &[u8], rdir: *mut u8) -> i8 { }; unsafe { *rdir = dir as u8 }; return 1; - }, + } Err(Err::Incomplete(_)) => { return 0; - }, + } Err(_) => { return -1; - }, + } } } @@ -1788,54 +2062,73 @@ pub fn nfs_probe(i: &[u8], direction: Direction) -> i32 { if direction == Direction::ToClient { match parse_rpc_reply(i, false) { Ok((_, ref rpc)) => { - if rpc.hdr.frag_len >= 24 && rpc.hdr.frag_len <= 35000 && rpc.hdr.msgtype == 1 && rpc.reply_state == 0 && rpc.accept_state == 0 { - SCLogDebug!("TC PROBE LEN {} XID {} TYPE {}", rpc.hdr.frag_len, rpc.hdr.xid, rpc.hdr.msgtype); + if rpc.hdr.frag_len >= 24 + && rpc.hdr.frag_len <= 35000 + && rpc.hdr.msgtype == 1 + && rpc.reply_state == 0 + && rpc.accept_state == 0 + { + SCLogDebug!( + "TC PROBE LEN {} XID {} TYPE {}", + rpc.hdr.frag_len, + rpc.hdr.xid, + rpc.hdr.msgtype + ); return 1; } else { return -1; } - }, - Err(Err::Incomplete(_)) => { - match parse_rpc_packet_header (i) { - Ok((_, ref rpc_hdr)) => { - if rpc_hdr.frag_len >= 24 && rpc_hdr.frag_len <= 35000 && rpc_hdr.xid != 0 && rpc_hdr.msgtype == 1 { - SCLogDebug!("TC PROBE LEN {} XID {} TYPE {}", rpc_hdr.frag_len, rpc_hdr.xid, rpc_hdr.msgtype); - return 1; - } else { - return -1; - } - }, - Err(Err::Incomplete(_)) => { - return 0; - }, - Err(_) => { + } + Err(Err::Incomplete(_)) => match parse_rpc_packet_header(i) { + Ok((_, ref rpc_hdr)) => { + if rpc_hdr.frag_len >= 24 + && rpc_hdr.frag_len <= 35000 + && rpc_hdr.xid != 0 + && rpc_hdr.msgtype == 1 + { + SCLogDebug!( + "TC PROBE LEN {} XID {} TYPE {}", + rpc_hdr.frag_len, + rpc_hdr.xid, + rpc_hdr.msgtype + ); + return 1; + } else { return -1; - }, + } + } + Err(Err::Incomplete(_)) => { + return 0; + } + Err(_) => { + return -1; } }, Err(_) => { return -1; - }, + } } } else { match parse_rpc(i, false) { Ok((_, ref rpc)) => { - if rpc.hdr.frag_len >= 40 && rpc.hdr.msgtype == 0 && - rpc.rpcver == 2 && (rpc.progver == 3 || rpc.progver == 4) && - rpc.program == 100003 && - rpc.procedure <= NFSPROC3_COMMIT + if rpc.hdr.frag_len >= 40 + && rpc.hdr.msgtype == 0 + && rpc.rpcver == 2 + && (rpc.progver == 3 || rpc.progver == 4) + && rpc.program == 100003 + && rpc.procedure <= NFSPROC3_COMMIT { return rpc_auth_type_known(rpc.creds_flavor) as i32; } else { return -1; } - }, + } Err(Err::Incomplete(_)) => { return 0; - }, + } Err(_) => { return -1; - }, + } } } } @@ -1844,46 +2137,61 @@ pub fn nfs_probe_udp(i: &[u8], direction: Direction) -> i32 { if direction == Direction::ToClient { match parse_rpc_udp_reply(i) { Ok((_, ref rpc)) => { - if i.len() >= 32 && rpc.hdr.msgtype == 1 && rpc.reply_state == 0 && rpc.accept_state == 0 { - SCLogDebug!("TC PROBE LEN {} XID {} TYPE {}", rpc.hdr.frag_len, rpc.hdr.xid, rpc.hdr.msgtype); + if i.len() >= 32 + && rpc.hdr.msgtype == 1 + && rpc.reply_state == 0 + && rpc.accept_state == 0 + { + SCLogDebug!( + "TC PROBE LEN {} XID {} TYPE {}", + rpc.hdr.frag_len, + rpc.hdr.xid, + rpc.hdr.msgtype + ); return 1; } else { return -1; } - }, + } Err(_) => { return -1; - }, + } } } else { match parse_rpc_udp_request(i) { Ok((_, ref rpc)) => { - if i.len() >= 48 && rpc.hdr.msgtype == 0 && rpc.progver == 3 && rpc.program == 100003 { + if i.len() >= 48 + && rpc.hdr.msgtype == 0 + && rpc.progver == 3 + && rpc.program == 100003 + { return 1; - } else if i.len() >= 48 && rpc.hdr.msgtype == 0 && rpc.progver == 2 && rpc.program == 100003 { + } else if i.len() >= 48 + && rpc.hdr.msgtype == 0 + && rpc.progver == 2 + && rpc.program == 100003 + { SCLogDebug!("NFSv2!"); return 1; } else { return -1; } - }, + } Err(_) => { return -1; - }, + } } } } /// MIDSTREAM #[no_mangle] -pub unsafe extern "C" fn rs_nfs_probe_ms( - _flow: *const Flow, - direction: u8, input: *const u8, - len: u32, rdir: *mut u8) -> AppProto -{ +pub unsafe extern fn rs_nfs_probe_ms( + _flow: *const Flow, direction: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> AppProto { let slice: &[u8] = build_slice!(input, len as usize); SCLogDebug!("rs_nfs_probe_ms: probing direction {:02x}", direction); - let mut adirection : u8 = 0; + let mut adirection: u8 = 0; match nfs_probe_dir(slice, &mut adirection) { 1 => { if adirection == Direction::ToServer.into() { @@ -1893,73 +2201,61 @@ pub unsafe extern "C" fn rs_nfs_probe_ms( } match nfs_probe(slice, adirection.into()) { 1 => { - SCLogDebug!("nfs_probe success: dir {:02x} adir {:02x}", direction, adirection); + SCLogDebug!( + "nfs_probe success: dir {:02x} adir {:02x}", + direction, + adirection + ); if (direction & DIR_BOTH) != adirection { *rdir = adirection; } ALPROTO_NFS - }, - 0 => { ALPROTO_UNKNOWN }, - _ => { ALPROTO_FAILED }, + } + 0 => ALPROTO_UNKNOWN, + _ => ALPROTO_FAILED, } - }, - 0 => { - ALPROTO_UNKNOWN - }, - _ => { - ALPROTO_FAILED } + 0 => ALPROTO_UNKNOWN, + _ => ALPROTO_FAILED, } } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_probe(_f: *const Flow, - direction: u8, - input: *const u8, - len: u32, - _rdir: *mut u8) - -> AppProto -{ +pub unsafe extern fn rs_nfs_probe( + _f: *const Flow, direction: u8, input: *const u8, len: u32, _rdir: *mut u8, +) -> AppProto { let slice: &[u8] = build_slice!(input, len as usize); SCLogDebug!("rs_nfs_probe: running probe"); match nfs_probe(slice, direction.into()) { - 1 => { ALPROTO_NFS }, - -1 => { ALPROTO_FAILED }, - _ => { ALPROTO_UNKNOWN }, + 1 => ALPROTO_NFS, + -1 => ALPROTO_FAILED, + _ => ALPROTO_UNKNOWN, } } /// TOSERVER probe function #[no_mangle] -pub unsafe extern "C" fn rs_nfs_probe_udp_ts(_f: *const Flow, - _direction: u8, - input: *const u8, - len: u32, - _rdir: *mut u8) - -> AppProto -{ +pub unsafe extern fn rs_nfs_probe_udp_ts( + _f: *const Flow, _direction: u8, input: *const u8, len: u32, _rdir: *mut u8, +) -> AppProto { let slice: &[u8] = build_slice!(input, len as usize); match nfs_probe_udp(slice, Direction::ToServer) { - 1 => { ALPROTO_NFS }, - -1 => { ALPROTO_FAILED }, - _ => { ALPROTO_UNKNOWN }, + 1 => ALPROTO_NFS, + -1 => ALPROTO_FAILED, + _ => ALPROTO_UNKNOWN, } } /// TOCLIENT probe function #[no_mangle] -pub unsafe extern "C" fn rs_nfs_probe_udp_tc(_f: *const Flow, - _direction: u8, - input: *const u8, - len: u32, - _rdir: *mut u8) - -> AppProto -{ +pub unsafe extern fn rs_nfs_probe_udp_tc( + _f: *const Flow, _direction: u8, input: *const u8, len: u32, _rdir: *mut u8, +) -> AppProto { let slice: &[u8] = build_slice!(input, len as usize); match nfs_probe_udp(slice, Direction::ToClient) { - 1 => { ALPROTO_NFS }, - -1 => { ALPROTO_FAILED }, - _ => { ALPROTO_UNKNOWN }, + 1 => ALPROTO_NFS, + -1 => ALPROTO_FAILED, + _ => ALPROTO_UNKNOWN, } } @@ -1967,7 +2263,7 @@ pub unsafe extern "C" fn rs_nfs_probe_udp_tc(_f: *const Flow, const PARSER_NAME: &[u8] = b"nfs\0"; #[no_mangle] -pub unsafe extern "C" fn rs_nfs_register_parser() { +pub unsafe extern fn rs_nfs_register_parser() { let default_port = CString::new("[2049]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, @@ -1988,7 +2284,7 @@ pub unsafe extern "C" fn rs_nfs_register_parser() { tx_comp_st_tc: 1, tx_get_progress: rs_nfs_tx_get_alstate_progress, get_eventinfo: Some(NFSEvent::get_event_info), - get_eventinfo_byid : Some(NFSEvent::get_event_info_by_id), + get_eventinfo_byid: Some(NFSEvent::get_event_info_by_id), localstorage_new: None, localstorage_free: None, get_tx_files: Some(rs_nfs_gettxfiles), @@ -2004,38 +2300,50 @@ pub unsafe extern "C" fn rs_nfs_register_parser() { let ip_proto_str = CString::new("tcp").unwrap(); - if AppLayerProtoDetectConfProtoDetectionEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let alproto = AppLayerRegisterProtocolDetection(&parser, 1); ALPROTO_NFS = alproto; let midstream = conf_get_bool("stream.midstream"); if midstream { - if AppLayerProtoDetectPPParseConfPorts(ip_proto_str.as_ptr(), IPPROTO_TCP, - parser.name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN, - rs_nfs_probe_ms, rs_nfs_probe_ms) == 0 { + if AppLayerProtoDetectPPParseConfPorts( + ip_proto_str.as_ptr(), + IPPROTO_TCP, + parser.name, + ALPROTO_NFS, + 0, + NFS_MIN_FRAME_LEN, + rs_nfs_probe_ms, + rs_nfs_probe_ms, + ) == 0 + { SCLogDebug!("No NFSTCP app-layer configuration, enabling NFSTCP detection TCP detection on port {:?}.", default_port); /* register 'midstream' probing parsers if midstream is enabled. */ - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - default_port.as_ptr(), ALPROTO_NFS, 0, - NFS_MIN_FRAME_LEN, Direction::ToServer.into(), - rs_nfs_probe_ms, rs_nfs_probe_ms); + AppLayerProtoDetectPPRegister( + IPPROTO_TCP, + default_port.as_ptr(), + ALPROTO_NFS, + 0, + NFS_MIN_FRAME_LEN, + Direction::ToServer.into(), + rs_nfs_probe_ms, + rs_nfs_probe_ms, + ); } } else { - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - default_port.as_ptr(), ALPROTO_NFS, 0, - NFS_MIN_FRAME_LEN, Direction::ToServer.into(), - rs_nfs_probe, rs_nfs_probe); - } - if AppLayerParserConfParserEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + AppLayerProtoDetectPPRegister( + IPPROTO_TCP, + default_port.as_ptr(), + ALPROTO_NFS, + 0, + NFS_MIN_FRAME_LEN, + Direction::ToServer.into(), + rs_nfs_probe, + rs_nfs_probe, + ); + } + if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let _ = AppLayerRegisterParser(&parser, alproto); } SCLogDebug!("Rust nfs parser registered."); @@ -2045,7 +2353,7 @@ pub unsafe extern "C" fn rs_nfs_register_parser() { } #[no_mangle] -pub unsafe extern "C" fn rs_nfs_udp_register_parser() { +pub unsafe extern fn rs_nfs_udp_register_parser() { let default_port = CString::new("[2049]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, @@ -2066,7 +2374,7 @@ pub unsafe extern "C" fn rs_nfs_udp_register_parser() { tx_comp_st_tc: 1, tx_get_progress: rs_nfs_tx_get_alstate_progress, get_eventinfo: Some(NFSEvent::get_event_info), - get_eventinfo_byid : Some(NFSEvent::get_event_info_by_id), + get_eventinfo_byid: Some(NFSEvent::get_event_info_by_id), localstorage_new: None, localstorage_free: None, get_tx_files: Some(rs_nfs_gettxfiles), @@ -2082,29 +2390,35 @@ pub unsafe extern "C" fn rs_nfs_udp_register_parser() { let ip_proto_str = CString::new("udp").unwrap(); - if AppLayerProtoDetectConfProtoDetectionEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let alproto = AppLayerRegisterProtocolDetection(&parser, 1); ALPROTO_NFS = alproto; - if AppLayerProtoDetectPPParseConfPorts(ip_proto_str.as_ptr(), IPPROTO_UDP, - parser.name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN, - rs_nfs_probe_udp_ts, rs_nfs_probe_udp_tc) == 0 { - SCLogDebug!("No NFSUDP app-layer configuration, enabling NFSUDP detection UDP detection on port {:?}.", - default_port); - AppLayerProtoDetectPPRegister(IPPROTO_UDP, - default_port.as_ptr(), ALPROTO_NFS, 0, - NFS_MIN_FRAME_LEN, Direction::ToServer.into(), - rs_nfs_probe_udp_ts, rs_nfs_probe_udp_tc); - } - if AppLayerParserConfParserEnabled( + if AppLayerProtoDetectPPParseConfPorts( ip_proto_str.as_ptr(), + IPPROTO_UDP, parser.name, - ) != 0 + ALPROTO_NFS, + 0, + NFS_MIN_FRAME_LEN, + rs_nfs_probe_udp_ts, + rs_nfs_probe_udp_tc, + ) == 0 { + SCLogDebug!("No NFSUDP app-layer configuration, enabling NFSUDP detection UDP detection on port {:?}.", + default_port); + AppLayerProtoDetectPPRegister( + IPPROTO_UDP, + default_port.as_ptr(), + ALPROTO_NFS, + 0, + NFS_MIN_FRAME_LEN, + Direction::ToServer.into(), + rs_nfs_probe_udp_ts, + rs_nfs_probe_udp_tc, + ); + } + if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let _ = AppLayerRegisterParser(&parser, alproto); } if let Some(val) = conf_get("app-layer.protocols.nfs.max-tx") { diff --git a/rust/src/nfs/nfs2.rs b/rust/src/nfs/nfs2.rs index f8000b4892a4..5229640c310e 100644 --- a/rust/src/nfs/nfs2.rs +++ b/rust/src/nfs/nfs2.rs @@ -18,18 +18,23 @@ // written by Victor Julien use crate::nfs::nfs::*; -use crate::nfs::types::*; -use crate::nfs::rpc_records::*; use crate::nfs::nfs2_records::*; +use crate::nfs::rpc_records::*; +use crate::nfs::types::*; -use nom7::IResult; use nom7::number::streaming::be_u32; +use nom7::IResult; impl NFSState { /// complete request record pub fn process_request_record_v2(&mut self, r: &RpcPacket) { - SCLogDebug!("NFSv2: REQUEST {} procedure {} ({}) blob size {}", - r.hdr.xid, r.procedure, self.requestmap.len(), r.prog_data.len()); + SCLogDebug!( + "NFSv2: REQUEST {} procedure {} ({}) blob size {}", + r.hdr.xid, + r.procedure, + self.requestmap.len(), + r.prog_data.len() + ); let mut xidmap = NFSRequestXidMap::new(r.progver, r.procedure, 0); let aux_file_name = Vec::new(); @@ -39,10 +44,10 @@ impl NFSState { Ok((_, ar)) => { xidmap.file_handle = ar.handle.value.to_vec(); self.xidmap_handle2name(&mut xidmap); - }, + } _ => { self.set_event(NFSEvent::MalformedData); - }, + } }; } else if r.procedure == NFSPROC3_READ { match parse_nfs2_request_read(r.prog_data) { @@ -50,16 +55,17 @@ impl NFSState { xidmap.chunk_offset = read_record.offset as u64; xidmap.file_handle = read_record.handle.value.to_vec(); self.xidmap_handle2name(&mut xidmap); - }, + } _ => { self.set_event(NFSEvent::MalformedData); - }, + } }; } if !(r.procedure == NFSPROC3_COMMIT || // commit handled separately r.procedure == NFSPROC3_WRITE || // write handled in file tx - r.procedure == NFSPROC3_READ) // read handled in file tx at reply + r.procedure == NFSPROC3_READ) + // read handled in file tx at reply { let mut tx = self.new_tx(); tx.xid = r.hdr.xid; @@ -80,11 +86,15 @@ impl NFSState { tx.request_machine_name = u.machine_name_buf.to_vec(); tx.request_uid = u.uid; tx.request_gid = u.gid; - }, - _ => { }, + } + _ => {} } - SCLogDebug!("NFSv2: TX created: ID {} XID {} PROCEDURE {}", - tx.id, tx.xid, tx.procedure); + SCLogDebug!( + "NFSv2: TX created: ID {} XID {} PROCEDURE {}", + tx.id, + tx.xid, + tx.procedure + ); self.transactions.push(tx); } @@ -102,20 +112,24 @@ impl NFSState { SCLogDebug!("NFSv2: READ reply record"); self.process_read_record(r, reply, Some(xidmap)); nfs_status = reply.status; - }, + } _ => { self.set_event(NFSEvent::MalformedData); - }, + } } } else { - let stat : u32 = match be_u32(r.prog_data) as IResult<&[u8],_> { + let stat: u32 = match be_u32(r.prog_data) as IResult<&[u8], _> { Ok((_, stat)) => stat, - _ => 0 + _ => 0, }; nfs_status = stat; } - SCLogDebug!("NFSv2: REPLY {} to procedure {} blob size {}", - r.hdr.xid, xidmap.procedure, r.prog_data.len()); + SCLogDebug!( + "NFSv2: REPLY {} to procedure {} blob size {}", + r.hdr.xid, + xidmap.procedure, + r.prog_data.len() + ); self.mark_response_tx_done(r.hdr.xid, r.reply_state, nfs_status, &resp_handle); } diff --git a/rust/src/nfs/nfs2_records.rs b/rust/src/nfs/nfs2_records.rs index d8fe84f49d8f..58c758a34d37 100644 --- a/rust/src/nfs/nfs2_records.rs +++ b/rust/src/nfs/nfs2_records.rs @@ -19,13 +19,13 @@ use crate::nfs::nfs_records::*; use nom7::bytes::streaming::take; -use nom7::combinator::{rest, cond}; +use nom7::combinator::{cond, rest}; use nom7::number::streaming::be_u32; use nom7::IResult; -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs2Handle<'a> { - pub value: &'a[u8], + pub value: &'a [u8], } pub fn parse_nfs2_handle(i: &[u8]) -> IResult<&[u8], Nfs2Handle> { @@ -33,7 +33,7 @@ pub fn parse_nfs2_handle(i: &[u8]) -> IResult<&[u8], Nfs2Handle> { Ok((i, Nfs2Handle { value })) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs2RequestLookup<'a> { pub handle: Nfs2Handle<'a>, pub name_vec: Vec, @@ -51,7 +51,7 @@ pub fn parse_nfs2_request_lookup(i: &[u8]) -> IResult<&[u8], Nfs2RequestLookup> Ok((i, req)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs2RequestRead<'a> { pub handle: Nfs2Handle<'a>, pub offset: u32, @@ -84,8 +84,8 @@ pub fn parse_nfs2_reply_read(i: &[u8]) -> IResult<&[u8], NfsReplyRead> { Ok((i, reply)) } -#[derive(Debug,PartialEq, Eq)] -pub struct Nfs2Attributes<> { +#[derive(Debug, PartialEq, Eq)] +pub struct Nfs2Attributes { pub atype: u32, pub asize: u32, } diff --git a/rust/src/nfs/nfs3.rs b/rust/src/nfs/nfs3.rs index 032751f536ca..2f5ef46e84c9 100644 --- a/rust/src/nfs/nfs3.rs +++ b/rust/src/nfs/nfs3.rs @@ -20,18 +20,23 @@ use crate::core::*; use crate::nfs::nfs::*; -use crate::nfs::types::*; -use crate::nfs::rpc_records::*; use crate::nfs::nfs3_records::*; +use crate::nfs::rpc_records::*; +use crate::nfs::types::*; -use nom7::IResult; use nom7::number::streaming::be_u32; +use nom7::IResult; impl NFSState { /// complete NFS3 request record pub fn process_request_record_v3(&mut self, r: &RpcPacket) { - SCLogDebug!("REQUEST {} procedure {} ({}) blob size {}", - r.hdr.xid, r.procedure, self.requestmap.len(), r.prog_data.len()); + SCLogDebug!( + "REQUEST {} procedure {} ({}) blob size {}", + r.hdr.xid, + r.procedure, + self.requestmap.len(), + r.prog_data.len() + ); let mut xidmap = NFSRequestXidMap::new(r.progver, r.procedure, 0); let mut aux_file_name = Vec::new(); @@ -42,7 +47,6 @@ impl NFSState { if r.procedure == NFSPROC3_LOOKUP { self.process_request_record_lookup(r, &mut xidmap); - } else if r.procedure == NFSPROC3_ACCESS { if let Ok((_, rd)) = parse_nfs3_request_access(r.prog_data) { xidmap.file_handle = rd.handle.value.to_vec(); @@ -136,7 +140,8 @@ impl NFSState { if !(r.procedure == NFSPROC3_COMMIT || // commit handled separately r.procedure == NFSPROC3_WRITE || // write handled in file tx - r.procedure == NFSPROC3_READ) // read handled in file tx at reply + r.procedure == NFSPROC3_READ) + // read handled in file tx at reply { let mut tx = self.new_tx(); tx.xid = r.hdr.xid; @@ -157,18 +162,23 @@ impl NFSState { tx.request_machine_name = u.machine_name_buf.to_vec(); tx.request_uid = u.uid; tx.request_gid = u.gid; - }, - _ => { }, + } + _ => {} } - SCLogDebug!("TX created: ID {} XID {} PROCEDURE {}", - tx.id, tx.xid, tx.procedure); + SCLogDebug!( + "TX created: ID {} XID {} PROCEDURE {}", + tx.id, + tx.xid, + tx.procedure + ); self.transactions.push(tx); - } else if r.procedure == NFSPROC3_READ { - - let found = self.get_file_tx_by_handle(&xidmap.file_handle, Direction::ToClient).is_some(); + let found = self + .get_file_tx_by_handle(&xidmap.file_handle, Direction::ToClient) + .is_some(); if !found { - let tx = self.new_file_tx(&xidmap.file_handle, &xidmap.file_name, Direction::ToClient); + let tx = + self.new_file_tx(&xidmap.file_handle, &xidmap.file_name, Direction::ToClient); tx.procedure = NFSPROC3_READ; tx.xid = r.hdr.xid; tx.is_first = true; @@ -198,7 +208,8 @@ impl NFSState { nfs_status = rd.status; SCLogDebug!("LOOKUP handle {:?}", rd.handle); - self.namemap.insert(rd.handle.value.to_vec(), xidmap.file_name.to_vec()); + self.namemap + .insert(rd.handle.value.to_vec(), xidmap.file_name.to_vec()); resp_handle = rd.handle.value.to_vec(); } else { self.set_event(NFSEvent::MalformedData); @@ -211,7 +222,8 @@ impl NFSState { if let Some(h) = rd.handle { SCLogDebug!("handle {:?}", h); - self.namemap.insert(h.value.to_vec(), xidmap.file_name.to_vec()); + self.namemap + .insert(h.value.to_vec(), xidmap.file_name.to_vec()); resp_handle = h.value.to_vec(); } } else { @@ -230,7 +242,7 @@ impl NFSState { // cut off final eof field let d = if rd.data.len() >= 4 { - &rd.data[..rd.data.len()-4_usize] + &rd.data[..rd.data.len() - 4_usize] } else { rd.data }; @@ -244,8 +256,7 @@ impl NFSState { SCLogDebug!("e {:?}", e); if let Some(ref h) = e.handle { SCLogDebug!("h {:?}", h); - self.namemap.insert(h.value.to_vec(), - e.name_vec.to_vec()); + self.namemap.insert(h.value.to_vec(), e.name_vec.to_vec()); } } } @@ -258,14 +269,18 @@ impl NFSState { } // for all other record types only parse the status else { - let stat : u32 = match be_u32(r.prog_data) as IResult<&[u8],_> { + let stat: u32 = match be_u32(r.prog_data) as IResult<&[u8], _> { Ok((_, stat)) => stat, - _ => 0 + _ => 0, }; nfs_status = stat; } - SCLogDebug!("REPLY {} to procedure {} blob size {}", - r.hdr.xid, xidmap.procedure, r.prog_data.len()); + SCLogDebug!( + "REPLY {} to procedure {} blob size {}", + r.hdr.xid, + xidmap.procedure, + r.prog_data.len() + ); if xidmap.procedure != NFSPROC3_READ { self.mark_response_tx_done(r.hdr.xid, r.reply_state, nfs_status, &resp_handle); diff --git a/rust/src/nfs/nfs3_records.rs b/rust/src/nfs/nfs3_records.rs index 952b367db827..300faf8937aa 100644 --- a/rust/src/nfs/nfs3_records.rs +++ b/rust/src/nfs/nfs3_records.rs @@ -17,13 +17,13 @@ //! Nom parsers for RPC & NFSv3 -use std::cmp; use crate::nfs::nfs_records::*; use nom7::bytes::streaming::take; use nom7::combinator::{complete, cond, rest, verify}; use nom7::multi::{length_data, many0}; use nom7::number::streaming::{be_u32, be_u64}; use nom7::IResult; +use std::cmp; #[derive(Debug, PartialEq, Eq)] pub struct Nfs3Handle<'a> { @@ -303,7 +303,6 @@ pub(crate) fn many0_nfs3_response_readdirplus_entries( many0(complete(parse_nfs3_response_readdirplus_entry_cond))(input) } - #[derive(Debug, PartialEq, Eq)] pub struct Nfs3RequestReaddirplus<'a> { pub handle: Nfs3Handle<'a>, @@ -364,7 +363,11 @@ pub fn parse_nfs3_request_write(i: &[u8], complete: bool) -> IResult<&[u8], Nfs3 let (i, count) = be_u32(i)?; let (i, stable) = verify(be_u32, |&v| v <= 2)(i)?; let (i, file_len) = verify(be_u32, |&v| v <= count)(i)?; - let fill_bytes = if file_len % 4 != 0 { 4 - file_len % 4 } else { 0 }; + let fill_bytes = if file_len % 4 != 0 { + 4 - file_len % 4 + } else { + 0 + }; // Handle the various file data parsing logics let (i, file_data) = if complete { parse_nfs3_data_complete(i, file_len as usize, fill_bytes as usize)? @@ -391,7 +394,11 @@ pub fn parse_nfs3_reply_read(i: &[u8], complete: bool) -> IResult<&[u8], NfsRepl let (i, count) = be_u32(i)?; let (i, eof) = verify(be_u32, |&v| v <= 1)(i)?; let (i, data_len) = verify(be_u32, |&v| v <= count)(i)?; - let fill_bytes = if data_len % 4 != 0 { 4 - data_len % 4 } else { 0 }; + let fill_bytes = if data_len % 4 != 0 { + 4 - data_len % 4 + } else { + 0 + }; // Handle the various file data parsing logics let (i, data) = if complete { parse_nfs3_data_complete(i, data_len as usize, fill_bytes as usize)? @@ -649,7 +656,6 @@ mod tests { #[test] fn test_nfs3_request_access() { - #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/ @@ -674,7 +680,6 @@ mod tests { #[test] fn test_nfs3_request_commit() { - // packet_bytes -- used [READ Call] message digest #[rustfmt::skip] let buf: &[u8] = &[ @@ -700,7 +705,6 @@ mod tests { #[test] fn test_nfs3_request_read() { - #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x20, /*handle_len: (32)*/ @@ -726,7 +730,6 @@ mod tests { #[test] fn test_nfs3_request_lookup() { - #[rustfmt::skip] let buf: &[u8] = &[ // [handle] @@ -755,7 +758,6 @@ mod tests { #[test] fn test_nfs3_response_readdirplus() { - #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, /*status*/ @@ -835,15 +837,24 @@ mod tests { match response { (r, entries) => { assert_eq!(r.len(), 4); - assert_eq!(entries[0], Nfs3ResponseReaddirplusEntry { entry: Some(entry0) }); - assert_eq!(entries[1], Nfs3ResponseReaddirplusEntry { entry: Some(entry1) }); + assert_eq!( + entries[0], + Nfs3ResponseReaddirplusEntry { + entry: Some(entry0) + } + ); + assert_eq!( + entries[1], + Nfs3ResponseReaddirplusEntry { + entry: Some(entry1) + } + ); } } } #[test] fn test_nfs3_response_readdirplus_entry() { - #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x01, /*value_follows*/ @@ -875,17 +886,20 @@ mod tests { let (_, response) = parse_nfs3_response_readdirplus_entry_cond(buf).unwrap(); match response { - Nfs3ResponseReaddirplusEntry { entry: Some(entry_c) } => { + Nfs3ResponseReaddirplusEntry { + entry: Some(entry_c), + } => { assert_eq!(entry_c.name_vec, ".".as_bytes()); assert_eq!(entry_c.handle, Some(entry_handle)); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } #[test] fn test_nfs3_request_readdirplus() { - #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x24, /*handle_len*/ @@ -920,7 +934,6 @@ mod tests { #[test] fn test_nfs3_request_write() { - #[rustfmt::skip] let buf: &[u8] = &[ // [handle] @@ -958,7 +971,6 @@ mod tests { #[test] fn test_nfs3_reply_read() { - #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, /*Status: NFS3_OK (0)*/ diff --git a/rust/src/nfs/nfs4.rs b/rust/src/nfs/nfs4.rs index 730e82ba1b60..c33a5a9c4e4c 100644 --- a/rust/src/nfs/nfs4.rs +++ b/rust/src/nfs/nfs4.rs @@ -68,9 +68,16 @@ impl NFSState { let found = match self.get_file_tx_by_handle(&file_handle, Direction::ToServer) { Some(tx) => { if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, w.data, w.offset, - w.write_len, fill_bytes as u8, is_last, &r.hdr.xid); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + w.data, + w.offset, + w.write_len, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); tdf.chunk_count += 1; if is_last { tdf.file_last_xid = r.hdr.xid; @@ -85,9 +92,16 @@ impl NFSState { if !found { let tx = self.new_file_tx(&file_handle, &file_name, Direction::ToServer); if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, w.data, w.offset, - w.write_len, fill_bytes as u8, is_last, &r.hdr.xid); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + w.data, + w.offset, + w.write_len, + fill_bytes as u8, + is_last, + &r.hdr.xid, + ); tx.procedure = NFSPROC4_WRITE; tx.xid = r.hdr.xid; tx.is_first = true; @@ -102,7 +116,7 @@ impl NFSState { } self.ts_chunk_xid = r.hdr.xid; debug_validate_bug_on!(w.data.len() as u32 > w.write_len); - self.ts_chunk_left = w.write_len - w.data.len() as u32; + self.ts_chunk_left = w.write_len - w.data.len() as u32; } fn close_v4<'b>(&mut self, r: &RpcPacket<'b>, fh: &'b [u8]) { @@ -125,8 +139,7 @@ impl NFSState { } fn new_tx_v4( - &mut self, r: &RpcPacket, xidmap: &NFSRequestXidMap, procedure: u32, - _aux_opcodes: &[u32], + &mut self, r: &RpcPacket, xidmap: &NFSRequestXidMap, procedure: u32, _aux_opcodes: &[u32], ) { let mut tx = self.new_tx(); tx.xid = r.hdr.xid; @@ -319,7 +332,7 @@ impl NFSState { match *c { Nfs4ResponseContent::ReadDir(_s, Some(ref rd)) => { SCLogDebug!("READDIRv4: status {} eof {}", _s, rd.eof); - + #[allow(clippy::manual_flatten)] for d in &rd.listing { if let Some(_d) = d { @@ -382,9 +395,7 @@ impl NFSState { } } - pub fn process_reply_record_v4( - &mut self, r: &RpcReplyPacket, xidmap: &mut NFSRequestXidMap, - ) { + pub fn process_reply_record_v4(&mut self, r: &RpcReplyPacket, xidmap: &mut NFSRequestXidMap) { if xidmap.procedure == NFSPROC4_COMPOUND { let mut data = r.prog_data; diff --git a/rust/src/nfs/nfs4_records.rs b/rust/src/nfs/nfs4_records.rs index 9d61da39d33e..c8f5aa94cc8b 100644 --- a/rust/src/nfs/nfs4_records.rs +++ b/rust/src/nfs/nfs4_records.rs @@ -17,7 +17,7 @@ //! Nom parsers for NFSv4 records use nom7::bytes::streaming::{tag, take}; -use nom7::combinator::{complete, cond, map, peek, verify, rest}; +use nom7::combinator::{complete, cond, map, peek, rest, verify}; use nom7::error::{make_error, ErrorKind}; use nom7::multi::{count, many_till}; use nom7::number::streaming::{be_u32, be_u64}; @@ -26,9 +26,9 @@ use nom7::{Err, IResult}; use crate::nfs::types::*; /*https://datatracker.ietf.org/doc/html/rfc7530 - section 16.16 File Delegation Types */ -const OPEN_DELEGATE_NONE: u32 = 0; -const OPEN_DELEGATE_READ: u32 = 1; -const OPEN_DELEGATE_WRITE: u32 = 2; +const OPEN_DELEGATE_NONE: u32 = 0; +const OPEN_DELEGATE_READ: u32 = 1; +const OPEN_DELEGATE_WRITE: u32 = 2; const RPCSEC_GSS: u32 = 6; @@ -36,7 +36,7 @@ const RPCSEC_GSS: u32 = 6; // Linux defines NFSD_MAX_OPS_PER_COMPOUND to 16 (tested in Linux 5.15.1). const NFSD_MAX_OPS_PER_COMPOUND: usize = 64; -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum Nfs4RequestContent<'a> { PutFH(Nfs4Handle<'a>), GetFH, @@ -56,7 +56,7 @@ pub enum Nfs4RequestContent<'a> { GetAttr(Nfs4Attr), SetAttr(Nfs4RequestSetAttr<'a>), Renew(u64), - Remove(&'a[u8]), + Remove(&'a [u8]), DelegReturn(Nfs4StateId<'a>), SetClientId(Nfs4RequestSetClientId<'a>), SetClientIdConfirm, @@ -68,11 +68,11 @@ pub enum Nfs4RequestContent<'a> { LayoutGet(Nfs4RequestLayoutGet<'a>), GetDevInfo(Nfs4RequestGetDevInfo<'a>), LayoutReturn(Nfs4RequestLayoutReturn<'a>), - DestroySession(&'a[u8]), - DestroyClientID(&'a[u8]), + DestroySession(&'a [u8]), + DestroyClientID(&'a [u8]), } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4Attr { attr_mask: u64, } @@ -106,10 +106,10 @@ fn nfs4_parse_attrbits(i: &[u8]) -> IResult<&[u8], Nfs4Attr> { Ok((i, attr)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4StateId<'a> { pub seqid: u32, - pub data: &'a[u8], + pub data: &'a [u8], } fn nfs4_parse_stateid(i: &[u8]) -> IResult<&[u8], Nfs4StateId> { @@ -119,10 +119,10 @@ fn nfs4_parse_stateid(i: &[u8]) -> IResult<&[u8], Nfs4StateId> { Ok((i, state)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4Handle<'a> { pub len: u32, - pub value: &'a[u8], + pub value: &'a [u8], } fn nfs4_parse_handle(i: &[u8]) -> IResult<&[u8], Nfs4Handle> { @@ -145,7 +145,7 @@ pub struct Nfs4RequestLayoutReturn<'a> { pub return_type: u32, pub length: u64, pub stateid: Nfs4StateId<'a>, - pub lrf_data: &'a[u8], + pub lrf_data: &'a [u8], } fn nfs4_req_layoutreturn(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -169,7 +169,7 @@ fn nfs4_req_layoutreturn(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { #[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestGetDevInfo<'a> { - pub device_id: &'a[u8], + pub device_id: &'a [u8], pub layout_type: u32, pub maxcount: u32, pub notify_mask: u32, @@ -192,9 +192,9 @@ fn nfs4_req_getdevinfo(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { #[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestCreateSession<'a> { - pub client_id: &'a[u8], + pub client_id: &'a [u8], pub seqid: u32, - pub machine_name: &'a[u8], + pub machine_name: &'a [u8], } fn nfs4_req_create_session(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -222,11 +222,11 @@ fn nfs4_req_putfh(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { map(nfs4_parse_handle, Nfs4RequestContent::PutFH)(i) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestSetClientId<'a> { - pub client_id: &'a[u8], - pub r_netid: &'a[u8], - pub r_addr: &'a[u8], + pub client_id: &'a [u8], + pub r_netid: &'a [u8], + pub r_addr: &'a [u8], } fn nfs4_req_setclientid(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -239,7 +239,7 @@ fn nfs4_req_setclientid(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { let req = Nfs4RequestContent::SetClientId(Nfs4RequestSetClientId { client_id, r_netid, - r_addr + r_addr, }); Ok((i, req)) } @@ -250,11 +250,11 @@ fn nfs4_req_setclientid_confirm(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> Ok((i, Nfs4RequestContent::SetClientIdConfirm)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestCreate<'a> { pub ftype4: u32, - pub filename: &'a[u8], - pub link_content: &'a[u8], + pub filename: &'a [u8], + pub link_content: &'a [u8], } fn nfs4_req_create(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -270,9 +270,9 @@ fn nfs4_req_create(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { Ok((i, req)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum Nfs4OpenRequestContent<'a> { - Exclusive4(&'a[u8]), + Exclusive4(&'a [u8]), Unchecked4(Nfs4Attr), Guarded4(Nfs4Attr), } @@ -295,15 +295,17 @@ fn nfs4_req_open_type(i: &[u8]) -> IResult<&[u8], Nfs4OpenRequestContent> { 0 => nfs4_req_open_unchecked4(i)?, 1 => nfs4_req_open_guarded4(i)?, 2 => nfs4_req_open_exclusive4(i)?, - _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } + _ => { + return Err(Err::Error(make_error(i, ErrorKind::Switch))); + } }; Ok((i, data)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestOpen<'a> { pub open_type: u32, - pub filename: &'a[u8], + pub filename: &'a [u8], pub open_data: Option>, } @@ -321,7 +323,7 @@ fn nfs4_req_open(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { let req = Nfs4RequestContent::Open(Nfs4RequestOpen { open_type, filename, - open_data + open_data, }); Ok((i, req)) } @@ -335,25 +337,22 @@ fn nfs4_req_readdir(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { Ok((i, Nfs4RequestContent::ReadDir)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestRename<'a> { - pub oldname: &'a[u8], - pub newname: &'a[u8], + pub oldname: &'a [u8], + pub newname: &'a [u8], } fn nfs4_req_rename(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { let (i, oldname) = nfs4_parse_nfsstring(i)?; let (i, newname) = nfs4_parse_nfsstring(i)?; - let req = Nfs4RequestContent::Rename(Nfs4RequestRename { - oldname, - newname - }); + let req = Nfs4RequestContent::Rename(Nfs4RequestRename { oldname, newname }); Ok((i, req)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestLookup<'a> { - pub filename: &'a[u8], + pub filename: &'a [u8], } fn nfs4_req_destroy_session(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -372,10 +371,10 @@ fn nfs4_req_remove(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { } fn nfs4_req_secinfo_no_name(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { - map(be_u32, Nfs4RequestContent::SecInfoNoName) (i) + map(be_u32, Nfs4RequestContent::SecInfoNoName)(i) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestSetAttr<'a> { pub stateid: Nfs4StateId<'a>, } @@ -391,13 +390,13 @@ fn nfs4_req_getattr(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { map(nfs4_parse_attrbits, Nfs4RequestContent::GetAttr)(i) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestWrite<'a> { pub stateid: Nfs4StateId<'a>, pub offset: u64, pub stable: u32, pub write_len: u32, - pub data: &'a[u8], + pub data: &'a [u8], } fn nfs4_req_write(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -417,7 +416,7 @@ fn nfs4_req_write(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { Ok((i, req)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestRead<'a> { pub stateid: Nfs4StateId<'a>, pub offset: u64, @@ -442,7 +441,7 @@ fn nfs4_req_close(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { Ok((i, Nfs4RequestContent::Close(stateid))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestOpenConfirm<'a> { pub stateid: Nfs4StateId<'a>, } @@ -450,9 +449,7 @@ pub struct Nfs4RequestOpenConfirm<'a> { fn nfs4_req_open_confirm(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { let (i, _seq_id) = be_u32(i)?; let (i, stateid) = nfs4_parse_stateid(i)?; - let req = Nfs4RequestContent::OpenConfirm(Nfs4RequestOpenConfirm { - stateid - }); + let req = Nfs4RequestContent::OpenConfirm(Nfs4RequestOpenConfirm { stateid }); Ok((i, req)) } @@ -487,7 +484,10 @@ fn nfs4_req_commit(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { } fn nfs4_req_reclaim_complete(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { - map(verify(be_u32, |&v| v <= 1), Nfs4RequestContent::ReclaimComplete) (i) + map( + verify(be_u32, |&v| v <= 1), + Nfs4RequestContent::ReclaimComplete, + )(i) } fn nfs4_req_destroy_clientid(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -521,11 +521,11 @@ fn nfs4_req_layoutget(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { Ok((i, req)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestExchangeId<'a> { - pub client_string: &'a[u8], - pub nii_domain: &'a[u8], - pub nii_name: &'a[u8], + pub client_string: &'a [u8], + pub nii_domain: &'a [u8], + pub nii_name: &'a [u8], } fn nfs4_req_exchangeid(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -541,14 +541,14 @@ fn nfs4_req_exchangeid(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { let req = Nfs4RequestContent::ExchangeId(Nfs4RequestExchangeId { client_string: eia_clientstring, nii_domain, - nii_name + nii_name, }); Ok((i, req)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestSequence<'a> { - pub ssn_id: &'a[u8], + pub ssn_id: &'a [u8], } fn nfs4_req_sequence(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { @@ -557,9 +557,7 @@ fn nfs4_req_sequence(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { let (i, _slot_id) = be_u32(i)?; let (i, _high_slot_id) = be_u32(i)?; let (i, _cache_this) = be_u32(i)?; - let req = Nfs4RequestContent::Sequence(Nfs4RequestSequence { - ssn_id - }); + let req = Nfs4RequestContent::Sequence(Nfs4RequestSequence { ssn_id }); Ok((i, req)) } @@ -598,12 +596,14 @@ fn parse_request_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent NFSPROC4_LAYOUTRETURN => nfs4_req_layoutreturn(i)?, NFSPROC4_DESTROY_SESSION => nfs4_req_destroy_session(i)?, NFSPROC4_DESTROY_CLIENTID => nfs4_req_destroy_clientid(i)?, - _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } + _ => { + return Err(Err::Error(make_error(i, ErrorKind::Switch))); + } }; Ok((i, cmd_data)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4RequestCompoundRecord<'a> { pub commands: Vec>, } @@ -620,7 +620,7 @@ pub fn parse_nfs4_request_compound(i: &[u8]) -> IResult<&[u8], Nfs4RequestCompou Ok((i, Nfs4RequestCompoundRecord { commands })) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum Nfs4ResponseContent<'a> { PutFH(u32), PutRootFH(u32), @@ -657,7 +657,7 @@ pub enum Nfs4ResponseContent<'a> { } // might need improvement with a stateid_present = yes case -fn nfs4_res_layoutreturn(i:&[u8]) -> IResult<&[u8], Nfs4ResponseContent> { +fn nfs4_res_layoutreturn(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { let (i, status) = be_u32(i)?; let (i, _stateid_present) = verify(be_u32, |&v| v <= 1)(i)?; Ok((i, Nfs4ResponseContent::LayoutReturn(status))) @@ -665,7 +665,7 @@ fn nfs4_res_layoutreturn(i:&[u8]) -> IResult<&[u8], Nfs4ResponseContent> { #[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseCreateSession<'a> { - pub ssn_id: &'a[u8], + pub ssn_id: &'a [u8], pub seq_id: u32, } @@ -675,25 +675,25 @@ fn nfs4_parse_res_create_session(i: &[u8]) -> IResult<&[u8], Nfs4ResponseCreateS let (i, _flags) = be_u32(i)?; let (i, _fore_chan_attrs) = take(28_usize)(i)?; let (i, _back_chan_attrs) = take(28_usize)(i)?; - Ok((i, Nfs4ResponseCreateSession { - ssn_id, - seq_id - })) + Ok((i, Nfs4ResponseCreateSession { ssn_id, seq_id })) } fn nfs4_res_create_session(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { let (i, status) = be_u32(i)?; let (i, create_ssn_data) = cond(status == 0, nfs4_parse_res_create_session)(i)?; - Ok((i, Nfs4ResponseContent::CreateSession( status, create_ssn_data ))) + Ok(( + i, + Nfs4ResponseContent::CreateSession(status, create_ssn_data), + )) } #[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseExchangeId<'a> { - pub client_id: &'a[u8], + pub client_id: &'a [u8], pub eir_minorid: u64, - pub eir_majorid: &'a[u8], - pub nii_domain: &'a[u8], - pub nii_name: &'a[u8], + pub eir_majorid: &'a [u8], + pub nii_domain: &'a [u8], + pub nii_name: &'a [u8], } fn nfs4_parse_res_exchangeid(i: &[u8]) -> IResult<&[u8], Nfs4ResponseExchangeId> { @@ -709,26 +709,29 @@ fn nfs4_parse_res_exchangeid(i: &[u8]) -> IResult<&[u8], Nfs4ResponseExchangeId> let (i, nii_name) = nfs4_parse_nfsstring(i)?; let (i, _nii_date_sec) = be_u64(i)?; let (i, _nii_date_nsec) = be_u32(i)?; - Ok((i, Nfs4ResponseExchangeId { - client_id, - eir_minorid, - eir_majorid, - nii_domain, - nii_name, - })) + Ok(( + i, + Nfs4ResponseExchangeId { + client_id, + eir_minorid, + eir_majorid, + nii_domain, + nii_name, + }, + )) } fn nfs4_res_reclaim_complete(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { - map(be_u32, Nfs4ResponseContent::ReclaimComplete) (i) + map(be_u32, Nfs4ResponseContent::ReclaimComplete)(i) } fn nfs4_res_exchangeid(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { let (i, status) = be_u32(i)?; let (i, xchngid_data) = cond(status == 0, nfs4_parse_res_exchangeid)(i)?; - Ok((i, Nfs4ResponseContent::ExchangeId( status, xchngid_data))) + Ok((i, Nfs4ResponseContent::ExchangeId(status, xchngid_data))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseWrite { pub count: u32, pub committed: u32, @@ -747,11 +750,11 @@ fn nfs4_res_write(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { Ok((i, Nfs4ResponseContent::Write(status, wd))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseRead<'a> { pub eof: bool, pub count: u32, - pub data: &'a[u8], + pub data: &'a [u8], } fn nfs4_res_read_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseRead> { @@ -759,7 +762,7 @@ fn nfs4_res_read_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseRead> { let (i, read_len) = be_u32(i)?; let (i, read_data) = take(read_len as usize)(i)?; let resp = Nfs4ResponseRead { - eof: eof==1, + eof: eof == 1, count: read_len, data: read_data, }; @@ -772,7 +775,7 @@ fn nfs4_res_read(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { Ok((i, Nfs4ResponseContent::Read(status, rd))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseOpen<'a> { pub stateid: Nfs4StateId<'a>, pub result_flags: u32, @@ -789,7 +792,7 @@ pub enum Nfs4ResponseFileDelegation<'a> { #[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseOpenDelegateWrite<'a> { pub stateid: Nfs4StateId<'a>, - pub who: &'a[u8], + pub who: &'a [u8], } fn nfs4_res_open_ok_delegate_write(i: &[u8]) -> IResult<&[u8], Nfs4ResponseFileDelegation> { @@ -801,13 +804,13 @@ fn nfs4_res_open_ok_delegate_write(i: &[u8]) -> IResult<&[u8], Nfs4ResponseFileD let (i, _ace_flags) = be_u32(i)?; let (i, _ace_mask) = be_u32(i)?; let (i, who) = nfs4_parse_nfsstring(i)?; - Ok((i, Nfs4ResponseFileDelegation::DelegateWrite(Nfs4ResponseOpenDelegateWrite { - stateid, - who, - }))) + Ok(( + i, + Nfs4ResponseFileDelegation::DelegateWrite(Nfs4ResponseOpenDelegateWrite { stateid, who }), + )) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseOpenDelegateRead<'a> { pub stateid: Nfs4StateId<'a>, } @@ -820,9 +823,10 @@ fn nfs4_res_open_ok_delegate_read(i: &[u8]) -> IResult<&[u8], Nfs4ResponseFileDe let (i, _ace_mask) = be_u32(i)?; let (i, who_len) = be_u32(i)?; let (i, _who) = take(who_len as usize)(i)?; - Ok((i, Nfs4ResponseFileDelegation::DelegateRead(Nfs4ResponseOpenDelegateRead { - stateid, - }))) + Ok(( + i, + Nfs4ResponseFileDelegation::DelegateRead(Nfs4ResponseOpenDelegateRead { stateid }), + )) } fn nfs4_parse_file_delegation(i: &[u8]) -> IResult<&[u8], Nfs4ResponseFileDelegation> { @@ -830,8 +834,13 @@ fn nfs4_parse_file_delegation(i: &[u8]) -> IResult<&[u8], Nfs4ResponseFileDelega let (i, file_delegation) = match delegation_type { OPEN_DELEGATE_READ => nfs4_res_open_ok_delegate_read(i)?, OPEN_DELEGATE_WRITE => nfs4_res_open_ok_delegate_write(i)?, - OPEN_DELEGATE_NONE => (i, Nfs4ResponseFileDelegation::DelegateNone(OPEN_DELEGATE_NONE)), - _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } + OPEN_DELEGATE_NONE => ( + i, + Nfs4ResponseFileDelegation::DelegateNone(OPEN_DELEGATE_NONE), + ), + _ => { + return Err(Err::Error(make_error(i, ErrorKind::Switch))); + } }; Ok((i, file_delegation)) } @@ -859,8 +868,8 @@ fn nfs4_res_open(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { #[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseGetDevInfo<'a> { pub layout_type: u32, - pub r_netid: &'a[u8], - pub r_addr: &'a[u8], + pub r_netid: &'a [u8], + pub r_addr: &'a [u8], pub notify_mask: u32, } @@ -872,18 +881,21 @@ fn nfs4_parse_res_getdevinfo(i: &[u8]) -> IResult<&[u8], Nfs4ResponseGetDevInfo> let (i, r_netid) = nfs4_parse_nfsstring(i)?; let (i, r_addr) = nfs4_parse_nfsstring(i)?; let (i, notify_mask) = be_u32(i)?; - Ok((i, Nfs4ResponseGetDevInfo { - layout_type, - r_netid, - r_addr, - notify_mask, - })) + Ok(( + i, + Nfs4ResponseGetDevInfo { + layout_type, + r_netid, + r_addr, + notify_mask, + }, + )) } fn nfs4_res_getdevinfo(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { let (i, status) = be_u32(i)?; let (i, getdevinfo) = cond(status == 0, nfs4_parse_res_getdevinfo)(i)?; - Ok((i, Nfs4ResponseContent::GetDevInfo( status, getdevinfo ))) + Ok((i, Nfs4ResponseContent::GetDevInfo(status, getdevinfo))) } /*https://datatracker.ietf.org/doc/html/rfc5661#section-13.1*/ @@ -893,12 +905,12 @@ pub struct Nfs4ResponseLayoutGet<'a> { pub stateid: Nfs4StateId<'a>, pub length: u64, pub layout_type: u32, - pub device_id: &'a[u8], + pub device_id: &'a [u8], pub file_handles: Vec>, } fn nfs4_parse_res_layoutget(i: &[u8]) -> IResult<&[u8], Nfs4ResponseLayoutGet> { - let (i, _return_on_close) = verify(be_u32, |&v| v <= 1)(i)?; + let (i, _return_on_close) = verify(be_u32, |&v| v <= 1)(i)?; let (i, stateid) = nfs4_parse_stateid(i)?; let (i, _layout_seg) = be_u32(i)?; let (i, _offset) = be_u64(i)?; @@ -917,19 +929,22 @@ fn nfs4_parse_res_layoutget(i: &[u8]) -> IResult<&[u8], Nfs4ResponseLayoutGet> { return Err(Err::Error(make_error(i, ErrorKind::Count))); } let (i, file_handles) = count(nfs4_parse_handle, fh_handles as usize)(i)?; - Ok((i, Nfs4ResponseLayoutGet { - stateid, - length, - layout_type, - device_id, - file_handles, - })) + Ok(( + i, + Nfs4ResponseLayoutGet { + stateid, + length, + layout_type, + device_id, + file_handles, + }, + )) } fn nfs4_res_layoutget(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { let (i, status) = be_u32(i)?; let (i, lyg_data) = cond(status == 0, nfs4_parse_res_layoutget)(i)?; - Ok((i, Nfs4ResponseContent::LayoutGet( status, lyg_data ))) + Ok((i, Nfs4ResponseContent::LayoutGet(status, lyg_data))) } // #[derive(Debug, PartialEq)] @@ -965,12 +980,12 @@ fn nfs4_res_secinfo_no_name(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { Ok((i, Nfs4ResponseContent::SecInfoNoName(status))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseReaddirEntry<'a> { - pub name: &'a[u8], + pub name: &'a [u8], } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseReaddir<'a> { pub eof: bool, pub listing: Vec>>, @@ -1114,7 +1129,7 @@ fn nfs4_res_commit(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { Ok((i, Nfs4ResponseContent::Commit(status))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseAccess { pub supported_types: u32, pub access_rights: u32, @@ -1125,7 +1140,7 @@ fn nfs4_res_access_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseAccess> { let (i, access_rights) = be_u32(i)?; let resp = Nfs4ResponseAccess { supported_types, - access_rights + access_rights, }; Ok((i, resp)) } @@ -1136,9 +1151,9 @@ fn nfs4_res_access(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { Ok((i, Nfs4ResponseContent::Access(status, ad))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseSequence<'a> { - pub ssn_id: &'a[u8], + pub ssn_id: &'a [u8], } fn nfs4_res_sequence_ok(i: &[u8]) -> IResult<&[u8], Nfs4ResponseSequence> { @@ -1156,11 +1171,11 @@ fn nfs4_res_sequence(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { } fn nfs4_res_destroy_session(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { - map(be_u32, Nfs4ResponseContent::DestroySession) (i) + map(be_u32, Nfs4ResponseContent::DestroySession)(i) } fn nfs4_res_destroy_clientid(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { - map(be_u32, Nfs4ResponseContent::DestroyClientID) (i) + map(be_u32, Nfs4ResponseContent::DestroyClientID)(i) } fn nfs4_res_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { @@ -1198,12 +1213,14 @@ fn nfs4_res_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { NFSPROC4_LAYOUTRETURN => nfs4_res_layoutreturn(i)?, NFSPROC4_DESTROY_SESSION => nfs4_res_destroy_session(i)?, NFSPROC4_DESTROY_CLIENTID => nfs4_res_destroy_clientid(i)?, - _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } + _ => { + return Err(Err::Error(make_error(i, ErrorKind::Switch))); + } }; Ok((i, cmd_data)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Nfs4ResponseCompoundRecord<'a> { pub status: u32, pub commands: Vec>, @@ -1227,7 +1244,7 @@ mod tests { #[test] fn test_nfs4_request_compound() { - // Operations: SEQUENCE, PUTFH, CLOSE + // Operations: SEQUENCE, PUTFH, CLOSE #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, /*Tag*/ @@ -1289,17 +1306,19 @@ mod tests { ]; let (_, req_client_id) = nfs4_parse_nfsstring(&buf[12..64]).unwrap(); - let (_, req_r_netid) = nfs4_parse_nfsstring(&buf[68 ..76]).unwrap(); + let (_, req_r_netid) = nfs4_parse_nfsstring(&buf[68..76]).unwrap(); let (_, req_r_adrr) = nfs4_parse_nfsstring(&buf[76..100]).unwrap(); let (_, resquest) = nfs4_req_setclientid(&buf[4..]).unwrap(); match resquest { - Nfs4RequestContent::SetClientId( req_setclientid ) => { + Nfs4RequestContent::SetClientId(req_setclientid) => { assert_eq!(req_setclientid.client_id, req_client_id); assert_eq!(req_setclientid.r_netid, req_r_netid); assert_eq!(req_setclientid.r_addr, req_r_adrr); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1336,10 +1355,15 @@ mod tests { match request { Nfs4RequestContent::Open(req_open) => { assert_eq!(req_open.open_type, 1); - assert_eq!(req_open.open_data, Some(Nfs4OpenRequestContent::Unchecked4(attr_buf))); + assert_eq!( + req_open.open_data, + Some(Nfs4OpenRequestContent::Unchecked4(attr_buf)) + ); assert_eq!(req_open.filename, filename_buf); } - _ => { panic!("Failure, {:?}", request); } + _ => { + panic!("Failure, {:?}", request); + } } } @@ -1368,7 +1392,9 @@ mod tests { assert_eq!(req_write.write_len, 5); assert_eq!(req_write.data, "test\n".as_bytes()); } - _ => { panic!("Failure, {:?}", request); } + _ => { + panic!("Failure, {:?}", request); + } } } @@ -1417,7 +1443,9 @@ mod tests { assert_eq!(req_exchangeid.nii_domain, nii_domain_buf); assert_eq!(req_exchangeid.nii_name, nii_name_buf); } - _ => { panic!("Failure, {:?}", request); } + _ => { + panic!("Failure, {:?}", request); + } } } @@ -1438,7 +1466,9 @@ mod tests { Nfs4RequestContent::Close(req_stateid) => { assert_eq!(req_stateid, stateid_buf); } - _ => { panic!("Failure, {:?}", request); } + _ => { + panic!("Failure, {:?}", request); + } } } @@ -1460,7 +1490,9 @@ mod tests { Nfs4RequestContent::Sequence(seq_buf) => { assert_eq!(seq_buf.ssn_id, &buf[4..20]); } - _ => { panic!("Failure, {:?}", req_sequence); } + _ => { + panic!("Failure, {:?}", req_sequence); + } } } @@ -1479,7 +1511,9 @@ mod tests { Nfs4RequestContent::Lookup(req_lookup) => { assert_eq!(req_lookup.filename, filename_buf); } - _ => { panic!("Failure, {:?}", request); } + _ => { + panic!("Failure, {:?}", request); + } } } @@ -1503,7 +1537,9 @@ mod tests { assert_eq!(putfh_handle.value, handle_buf.value); assert_eq!(putfh_handle.len, handle_buf.len); } - _ => { panic!("Failure, {:?}", result); } + _ => { + panic!("Failure, {:?}", result); + } } } @@ -1512,30 +1548,26 @@ mod tests { let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x2b, /*opcode*/ 0xe0, 0x14, 0x82, 0x00, 0x00, 0x00, 0x02, 0xd2, // create_session - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x14, - 0x00, 0x10, 0x03, 0x88, 0x00, 0x00, 0x0d, 0x64, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x0c, 0x09, 0x5e, 0x92, - 0x00, 0x00, 0x00, 0x09, 0x6e, 0x65, 0x74, 0x61, - 0x70, 0x70, 0x2d, 0x32, 0x36, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x04, 0x14, 0x00, 0x10, 0x03, 0x88, 0x00, 0x00, 0x0d, 0x64, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x09, 0x5e, 0x92, 0x00, 0x00, 0x00, 0x09, + 0x6e, 0x65, 0x74, 0x61, 0x70, 0x70, 0x2d, 0x32, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let (_, request) = nfs4_req_create_session(&buf[4..]).unwrap(); match request { - Nfs4RequestContent::CreateSession( create_ssn ) => { + Nfs4RequestContent::CreateSession(create_ssn) => { assert_eq!(create_ssn.client_id, &buf[4..12]); assert_eq!(create_ssn.seqid, 1); assert_eq!(create_ssn.machine_name, b"netapp-26"); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1544,12 +1576,10 @@ mod tests { let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x32, /*opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // layoutget - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x82, 0x14, 0xe0, 0x5b, 0x00, 0x89, 0xd9, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x14, 0xe0, 0x5b, 0x00, 0x89, 0xd9, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ]; let (_, stateid_buf) = nfs4_parse_stateid(&buf[40..56]).unwrap(); @@ -1557,12 +1587,14 @@ mod tests { let (_, request) = nfs4_req_layoutget(&buf[4..]).unwrap(); match request { - Nfs4RequestContent::LayoutGet( lyg_data ) => { + Nfs4RequestContent::LayoutGet(lyg_data) => { assert_eq!(lyg_data.layout_type, 1); assert_eq!(lyg_data.min_length, 4096); assert_eq!(lyg_data.stateid, stateid_buf); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1571,20 +1603,21 @@ mod tests { let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x2f, /*opcode*/ 0x01, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xfa, 0x80, // getdevinfo - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x3e, 0x20, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x3e, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, ]; let (_, request) = nfs4_req_getdevinfo(&buf[4..]).unwrap(); match request { - Nfs4RequestContent::GetDevInfo( getdevifo ) => { + Nfs4RequestContent::GetDevInfo(getdevifo) => { assert_eq!(getdevifo.device_id, &buf[4..20]); assert_eq!(getdevifo.layout_type, 1); assert_eq!(getdevifo.maxcount, 81440); assert_eq!(getdevifo.notify_mask, 6); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1593,12 +1626,10 @@ mod tests { let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x33, /*opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // layoutreturn - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x03, 0x82, 0x14, 0xe0, - 0x5b, 0x00, 0x89, 0xd9, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x03, 0x82, 0x14, 0xe0, 0x5b, 0x00, 0x89, 0xd9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, ]; let (_, stateid_buf) = nfs4_parse_stateid(&buf[36..52]).unwrap(); @@ -1606,12 +1637,14 @@ mod tests { let (_, request) = nfs4_req_layoutreturn(&buf[4..]).unwrap(); match request { - Nfs4RequestContent::LayoutReturn( layoutreturn ) => { + Nfs4RequestContent::LayoutReturn(layoutreturn) => { assert_eq!(layoutreturn.layout_type, 1); assert_eq!(layoutreturn.return_type, 1); assert_eq!(layoutreturn.stateid, stateid_buf); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1625,10 +1658,12 @@ mod tests { let (_, request) = nfs4_req_destroy_session(&buf[4..]).unwrap(); match request { - Nfs4RequestContent::DestroySession( ssn_id ) => { + Nfs4RequestContent::DestroySession(ssn_id) => { assert_eq!(ssn_id, &buf[4..]); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1650,7 +1685,7 @@ mod tests { } #[test] fn test_nfs4_response_compound() { - // Operations: SEQUENCE, PUTFH, CLOSE + // Operations: SEQUENCE, PUTFH, CLOSE #[rustfmt::skip] let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, /*status*/ @@ -1732,7 +1767,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(open_data, Some(res_open_data)); } - _ => { panic!("Failure, {:?}", response); } + _ => { + panic!("Failure, {:?}", response); + } } } @@ -1756,7 +1793,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(wd, Some(wd_buf)); } - _ => { panic!("Failure, {:?}", result); } + _ => { + panic!("Failure, {:?}", result); + } } } @@ -1779,7 +1818,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(ad, Some(ad_buf)); } - _ => { panic!("Failure, {:?}", result); } + _ => { + panic!("Failure, {:?}", result); + } } } @@ -1804,7 +1845,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(fh, Some(fh_buf)); } - _ => { panic!("Failure, {:?}", result); } + _ => { + panic!("Failure, {:?}", result); + } } } @@ -1837,7 +1880,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(attrs, Some(attrs_buf)); } - _ => { panic!("Failure, {:?}", result); } + _ => { + panic!("Failure, {:?}", result); + } } } @@ -1909,7 +1954,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(rd, Some(res_rd)); } - _ => { panic!("Failure!"); } + _ => { + panic!("Failure!"); + } } } @@ -1928,7 +1975,9 @@ mod tests { Nfs4ResponseContent::SetClientId(status) => { assert_eq!(status, 0); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1937,25 +1986,17 @@ mod tests { let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x2a, /*opcode*/ 0x00, 0x00, 0x00, 0x00, /*status*/ - // exchange_id - 0xe0, 0x14, 0x82, 0x00, 0x00, 0x00, 0x02, 0xd2, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x98, 0x3b, 0xa3, 0x1e, - 0xd7, 0xa9, 0x11, 0xe8, 0x00, 0x00, 0x00, 0x10, - 0x98, 0x3b, 0xa3, 0x1e, 0xd7, 0xa9, 0x11, 0xe8, - 0xbc, 0x0c, 0x00, 0x0c, 0x29, 0xe9, 0x13, 0x93, - 0x00, 0x00, 0x00, 0x10, 0x84, 0x8b, 0x93, 0x12, - 0xd7, 0xa9, 0x11, 0xe8, 0xbc, 0x0c, 0x00, 0x0c, - 0x29, 0xe9, 0x13, 0x93, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x65, 0x74, 0x61, - 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x24, 0x4e, 0x65, 0x74, 0x41, - 0x70, 0x70, 0x20, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x20, 0x56, 0x6f, 0x6f, 0x64, 0x6f, - 0x6f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x5f, - 0x5f, 0x39, 0x2e, 0x36, 0x2e, 0x30, 0x00, 0x00, - 0x26, 0x0d, 0xcf, 0x5b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, + // exchange_id + 0xe0, 0x14, 0x82, 0x00, 0x00, 0x00, 0x02, 0xd2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x3b, 0xa3, 0x1e, 0xd7, 0xa9, 0x11, 0xe8, + 0x00, 0x00, 0x00, 0x10, 0x98, 0x3b, 0xa3, 0x1e, 0xd7, 0xa9, 0x11, 0xe8, 0xbc, 0x0c, + 0x00, 0x0c, 0x29, 0xe9, 0x13, 0x93, 0x00, 0x00, 0x00, 0x10, 0x84, 0x8b, 0x93, 0x12, + 0xd7, 0xa9, 0x11, 0xe8, 0xbc, 0x0c, 0x00, 0x0c, 0x29, 0xe9, 0x13, 0x93, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x65, 0x74, 0x61, 0x70, 0x70, 0x2e, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x4e, 0x65, 0x74, 0x41, 0x70, 0x70, + 0x20, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x56, 0x6f, 0x6f, 0x64, 0x6f, + 0x6f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x5f, 0x39, 0x2e, 0x36, 0x2e, 0x30, + 0x00, 0x00, 0x26, 0x0d, 0xcf, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let (_, xchangeid) = nfs4_parse_res_exchangeid(&buf[8..]).unwrap(); @@ -1966,7 +2007,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(xchngid_data, Some(xchangeid)); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -1975,28 +2018,26 @@ mod tests { let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x2b, /*opcode*/ 0x00, 0x00, 0x00, 0x00, /*status*/ - // create_session - 0x00, 0x00, 0x02, 0xd2, 0xe0, 0x14, 0x82, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, - 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x02, 0x80, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + // create_session + 0x00, 0x00, 0x02, 0xd2, 0xe0, 0x14, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x18, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ]; let (_, create_ssn) = nfs4_parse_res_create_session(&buf[8..]).unwrap(); let (_, response) = nfs4_res_create_session(&buf[4..]).unwrap(); match response { - Nfs4ResponseContent::CreateSession( status, create_ssn_data) => { + Nfs4ResponseContent::CreateSession(status, create_ssn_data) => { assert_eq!(status, 0); assert_eq!(create_ssn_data, Some(create_ssn)); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -2005,25 +2046,17 @@ mod tests { let buf: &[u8] = &[ 0x00, 0x00, 0x00, 0x32, /*opcode*/ 0x00, 0x00, 0x00, 0x00, /*status*/ - // layoutget - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x03, 0x82, 0x14, 0xe0, 0x5b, 0x00, 0x89, 0xd9, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x58, 0x01, 0x01, 0x00, 0x00, - 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x84, 0x72, 0x00, 0x00, 0x23, 0xa6, 0xc0, 0x12, - 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, - 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, + // layoutget + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x82, 0x14, 0xe0, 0x5b, 0x00, + 0x89, 0xd9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x72, 0x00, 0x00, 0x23, 0xa6, 0xc0, 0x12, + 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0xf2, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, ]; let (_, stateid) = nfs4_parse_stateid(&buf[12..28]).unwrap(); @@ -2035,11 +2068,13 @@ mod tests { let (_, response) = nfs4_res_layoutget(&buf[4..]).unwrap(); match response { - Nfs4ResponseContent::LayoutGet( status, lyg ) => { + Nfs4ResponseContent::LayoutGet(status, lyg) => { assert_eq!(status, 0); assert_eq!(lyg, Some(lyg_data)); } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } @@ -2049,12 +2084,10 @@ mod tests { 0x00, 0x00, 0x00, 0x2f, /*opcode*/ 0x00, 0x00, 0x00, 0x00, /*status*/ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, // getdevinfo - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x03, 0x74, 0x63, 0x70, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x31, 0x39, 0x32, 0x2e, - 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x36, 0x31, - 0x2e, 0x38, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x74, 0x63, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x36, 0x31, 0x2e, 0x38, + 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, ]; let (_, getdevinfo) = nfs4_parse_res_getdevinfo(&buf[8..]).unwrap(); @@ -2068,7 +2101,9 @@ mod tests { assert_eq!(status, 0); assert_eq!(getdevinfo_data, Some(getdevinfo)) } - _ => { panic!("Failure"); } + _ => { + panic!("Failure"); + } } } } diff --git a/rust/src/nfs/nfs_records.rs b/rust/src/nfs/nfs_records.rs index 3b0804bfc0f0..183431ef4567 100644 --- a/rust/src/nfs/nfs_records.rs +++ b/rust/src/nfs/nfs_records.rs @@ -17,13 +17,13 @@ //! Nom parsers for NFS -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct NfsReplyRead<'a> { pub status: u32, pub attr_follows: u32, - pub attr_blob: &'a[u8], + pub attr_blob: &'a [u8], pub count: u32, pub eof: bool, pub data_len: u32, - pub data: &'a[u8], // likely partial + pub data: &'a [u8], // likely partial } diff --git a/rust/src/nfs/rpc_records.rs b/rust/src/nfs/rpc_records.rs index d373ae936ed6..43f35c707771 100644 --- a/rust/src/nfs/rpc_records.rs +++ b/rust/src/nfs/rpc_records.rs @@ -20,12 +20,12 @@ use crate::common::nom7::bits; use nom7::bits::streaming::take as take_bits; use nom7::bytes::streaming::take; -use nom7::combinator::{cond, verify, rest}; +use nom7::combinator::{cond, rest, verify}; +use nom7::error::{make_error, ErrorKind}; use nom7::multi::length_data; -use nom7::number::streaming::{be_u32}; +use nom7::number::streaming::be_u32; use nom7::sequence::tuple; -use nom7::error::{make_error, ErrorKind}; -use nom7::{IResult, Err}; +use nom7::{Err, IResult}; pub const RPC_MAX_MACHINE_SIZE: u32 = 256; // Linux kernel defines 64. pub const RPC_MAX_CREDS_SIZE: u32 = 4096; // Linux kernel defines 400. @@ -133,7 +133,7 @@ fn parse_bits(i: &[u8]) -> IResult<&[u8], (u8, u32)> { } pub fn parse_rpc_packet_header(i: &[u8]) -> IResult<&[u8], RpcPacketHeader> { - let (i, fraghdr) = verify(parse_bits, |v: &(u8,u32)| v.1 >= 24)(i)?; + let (i, fraghdr) = verify(parse_bits, |v: &(u8, u32)| v.1 >= 24)(i)?; let (i, xid) = be_u32(i)?; let (i, msgtype) = verify(be_u32, |&v| v <= 1)(i)?; let hdr = RpcPacketHeader { @@ -246,7 +246,7 @@ pub fn parse_rpc(start_i: &[u8], complete: bool) -> IResult<&[u8], RpcPacket> { return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } - let data_size : u32 = (rec_size - consumed) as u32; + let data_size: u32 = (rec_size - consumed) as u32; let (i, prog_data) = if !complete { rest(i)? } else { @@ -303,7 +303,7 @@ pub fn parse_rpc_reply(start_i: &[u8], complete: bool) -> IResult<&[u8], RpcRepl return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } - let data_size : u32 = (rec_size as usize - consumed) as u32; + let data_size: u32 = (rec_size as usize - consumed) as u32; let (i, prog_data) = if !complete { rest(i)? } else { @@ -359,7 +359,7 @@ pub fn parse_rpc_udp_request(i: &[u8]) -> IResult<&[u8], RpcPacket> { let (i, verifier_len) = verify(be_u32, |&size| size < RPC_MAX_VERIFIER_SIZE)(i)?; let (i, verifier) = take(verifier_len as usize)(i)?; - let data_size : u32 = i.len() as u32; + let data_size: u32 = i.len() as u32; let (i, prog_data) = rest(i)?; let packet = RpcPacket { hdr, @@ -393,7 +393,7 @@ pub fn parse_rpc_udp_reply(i: &[u8]) -> IResult<&[u8], RpcReplyPacket> { let (i, reply_state) = verify(be_u32, |&v| v <= 1)(i)?; let (i, accept_state) = be_u32(i)?; - let data_size : u32 = i.len() as u32; + let data_size: u32 = i.len() as u32; let (i, prog_data) = rest(i)?; let packet = RpcReplyPacket { hdr, @@ -421,13 +421,17 @@ mod tests { fn test_partial_input_too_short() { let buf: &[u8] = &[ 0x80, 0x00, 0x00, 0x9c, // flags - 0x8e, 0x28, 0x02, 0x7e // xid + 0x8e, 0x28, 0x02, 0x7e, // xid ]; let r = parse_rpc_request_partial(buf); match r { - Err(Incomplete(s)) => { assert_eq!(s, Needed::new(4)); }, - _ => { panic!("failed {:?}",r); } + Err(Incomplete(s)) => { + assert_eq!(s, Needed::new(4)); + } + _ => { + panic!("failed {:?}", r); + } } } #[test] @@ -443,23 +447,25 @@ mod tests { ]; let expected = RpcRequestPacketPartial { hdr: RpcPacketHeader { - frag_is_last: true, - frag_len: 156, - xid: 2384986750, - msgtype: 1 - }, + frag_is_last: true, + frag_len: 156, + xid: 2384986750, + msgtype: 1, + }, rpcver: 2, program: 3, progver: 4, - procedure: 5 + procedure: 5, }; let r = parse_rpc_request_partial(buf); match r { Ok((rem, hdr)) => { assert_eq!(rem.len(), 0); assert_eq!(hdr, expected); - }, - _ => { panic!("failed {:?}",r); } + } + _ => { + panic!("failed {:?}", r); + } } } } diff --git a/rust/src/nfs/types.rs b/rust/src/nfs/types.rs index 96195b9940ce..609d02be432d 100644 --- a/rust/src/nfs/types.rs +++ b/rust/src/nfs/types.rs @@ -16,165 +16,169 @@ */ /* RFC 1813, section '3. Server Procedures' */ -pub const NFSPROC3_NULL: u32 = 0; -pub const NFSPROC3_GETATTR: u32 = 1; -pub const NFSPROC3_SETATTR: u32 = 2; -pub const NFSPROC3_LOOKUP: u32 = 3; -pub const NFSPROC3_ACCESS: u32 = 4; -pub const NFSPROC3_READLINK: u32 = 5; -pub const NFSPROC3_READ: u32 = 6; -pub const NFSPROC3_WRITE: u32 = 7; -pub const NFSPROC3_CREATE: u32 = 8; -pub const NFSPROC3_MKDIR: u32 = 9; -pub const NFSPROC3_SYMLINK: u32 = 10; -pub const NFSPROC3_MKNOD: u32 = 11; -pub const NFSPROC3_REMOVE: u32 = 12; -pub const NFSPROC3_RMDIR: u32 = 13; -pub const NFSPROC3_RENAME: u32 = 14; -pub const NFSPROC3_LINK: u32 = 15; -pub const NFSPROC3_READDIR: u32 = 16; +pub const NFSPROC3_NULL: u32 = 0; +pub const NFSPROC3_GETATTR: u32 = 1; +pub const NFSPROC3_SETATTR: u32 = 2; +pub const NFSPROC3_LOOKUP: u32 = 3; +pub const NFSPROC3_ACCESS: u32 = 4; +pub const NFSPROC3_READLINK: u32 = 5; +pub const NFSPROC3_READ: u32 = 6; +pub const NFSPROC3_WRITE: u32 = 7; +pub const NFSPROC3_CREATE: u32 = 8; +pub const NFSPROC3_MKDIR: u32 = 9; +pub const NFSPROC3_SYMLINK: u32 = 10; +pub const NFSPROC3_MKNOD: u32 = 11; +pub const NFSPROC3_REMOVE: u32 = 12; +pub const NFSPROC3_RMDIR: u32 = 13; +pub const NFSPROC3_RENAME: u32 = 14; +pub const NFSPROC3_LINK: u32 = 15; +pub const NFSPROC3_READDIR: u32 = 16; pub const NFSPROC3_READDIRPLUS: u32 = 17; -pub const NFSPROC3_FSSTAT: u32 = 18; -pub const NFSPROC3_FSINFO: u32 = 19; -pub const NFSPROC3_PATHCONF: u32 = 20; -pub const NFSPROC3_COMMIT: u32 = 21; +pub const NFSPROC3_FSSTAT: u32 = 18; +pub const NFSPROC3_FSINFO: u32 = 19; +pub const NFSPROC3_PATHCONF: u32 = 20; +pub const NFSPROC3_COMMIT: u32 = 21; pub fn nfs3_procedure_string(procedure: u32) -> String { match procedure { - NFSPROC3_NULL => "NULL", - NFSPROC3_GETATTR => "GETATTR", - NFSPROC3_SETATTR => "SETATTR", - NFSPROC3_LOOKUP => "LOOKUP", - NFSPROC3_ACCESS => "ACCESS", - NFSPROC3_READLINK => "READLINK", - NFSPROC3_READ => "READ", - NFSPROC3_WRITE => "WRITE", - NFSPROC3_CREATE => "CREATE", - NFSPROC3_MKDIR => "MKDIR", - NFSPROC3_SYMLINK => "SYMLINK", - NFSPROC3_MKNOD => "MKNOD", - NFSPROC3_REMOVE => "REMOVE", - NFSPROC3_RMDIR => "RMDIR", - NFSPROC3_RENAME => "RENAME", - NFSPROC3_LINK => "LINK", - NFSPROC3_READDIR => "READDIR", - NFSPROC3_READDIRPLUS => "READDIRPLUS", - NFSPROC3_FSSTAT => "FSSTAT", - NFSPROC3_FSINFO => "FSINFO", - NFSPROC3_PATHCONF => "PATHCONF", - NFSPROC3_COMMIT => "COMMIT", + NFSPROC3_NULL => "NULL", + NFSPROC3_GETATTR => "GETATTR", + NFSPROC3_SETATTR => "SETATTR", + NFSPROC3_LOOKUP => "LOOKUP", + NFSPROC3_ACCESS => "ACCESS", + NFSPROC3_READLINK => "READLINK", + NFSPROC3_READ => "READ", + NFSPROC3_WRITE => "WRITE", + NFSPROC3_CREATE => "CREATE", + NFSPROC3_MKDIR => "MKDIR", + NFSPROC3_SYMLINK => "SYMLINK", + NFSPROC3_MKNOD => "MKNOD", + NFSPROC3_REMOVE => "REMOVE", + NFSPROC3_RMDIR => "RMDIR", + NFSPROC3_RENAME => "RENAME", + NFSPROC3_LINK => "LINK", + NFSPROC3_READDIR => "READDIR", + NFSPROC3_READDIRPLUS => "READDIRPLUS", + NFSPROC3_FSSTAT => "FSSTAT", + NFSPROC3_FSINFO => "FSINFO", + NFSPROC3_PATHCONF => "PATHCONF", + NFSPROC3_COMMIT => "COMMIT", _ => { return (procedure).to_string(); } - }.to_string() + } + .to_string() } /* RFC 1813, section '2.6 Defined Error Numbers' */ -pub const NFS3_OK: u32 = 0; -pub const NFS3ERR_PERM: u32 = 1; -pub const NFS3ERR_NOENT: u32 = 2; -pub const NFS3ERR_IO: u32 = 5; -pub const NFS3ERR_NXIO: u32 = 6; -pub const NFS3ERR_ACCES: u32 = 13; -pub const NFS3ERR_EXIST: u32 = 17; -pub const NFS3ERR_XDEV: u32 = 18; -pub const NFS3ERR_NODEV: u32 = 19; -pub const NFS3ERR_NOTDIR: u32 = 20; -pub const NFS3ERR_ISDIR: u32 = 21; -pub const NFS3ERR_INVAL: u32 = 22; -pub const NFS3ERR_FBIG: u32 = 27; -pub const NFS3ERR_NOSPC: u32 = 28; -pub const NFS3ERR_ROFS: u32 = 30; -pub const NFS3ERR_MLINK: u32 = 31; -pub const NFS3ERR_NAMETOOLONG: u32 = 63; -pub const NFS3ERR_NOTEMPTY: u32 = 66; -pub const NFS3ERR_DQUOT: u32 = 69; -pub const NFS3ERR_STALE: u32 = 70; -pub const NFS3ERR_REMOTE: u32 = 71; -pub const NFS3ERR_BADHANDLE: u32 = 10001; -pub const NFS3ERR_NOT_SYNC: u32 = 10002; -pub const NFS3ERR_BAD_COOKIE: u32 = 10003; -pub const NFS3ERR_NOTSUPP: u32 = 10004; -pub const NFS3ERR_TOOSMALL: u32 = 10005; -pub const NFS3ERR_SERVERFAULT: u32 = 10006; -pub const NFS3ERR_BADTYPE: u32 = 10007; -pub const NFS3ERR_JUKEBOX: u32 = 10008; +pub const NFS3_OK: u32 = 0; +pub const NFS3ERR_PERM: u32 = 1; +pub const NFS3ERR_NOENT: u32 = 2; +pub const NFS3ERR_IO: u32 = 5; +pub const NFS3ERR_NXIO: u32 = 6; +pub const NFS3ERR_ACCES: u32 = 13; +pub const NFS3ERR_EXIST: u32 = 17; +pub const NFS3ERR_XDEV: u32 = 18; +pub const NFS3ERR_NODEV: u32 = 19; +pub const NFS3ERR_NOTDIR: u32 = 20; +pub const NFS3ERR_ISDIR: u32 = 21; +pub const NFS3ERR_INVAL: u32 = 22; +pub const NFS3ERR_FBIG: u32 = 27; +pub const NFS3ERR_NOSPC: u32 = 28; +pub const NFS3ERR_ROFS: u32 = 30; +pub const NFS3ERR_MLINK: u32 = 31; +pub const NFS3ERR_NAMETOOLONG: u32 = 63; +pub const NFS3ERR_NOTEMPTY: u32 = 66; +pub const NFS3ERR_DQUOT: u32 = 69; +pub const NFS3ERR_STALE: u32 = 70; +pub const NFS3ERR_REMOTE: u32 = 71; +pub const NFS3ERR_BADHANDLE: u32 = 10001; +pub const NFS3ERR_NOT_SYNC: u32 = 10002; +pub const NFS3ERR_BAD_COOKIE: u32 = 10003; +pub const NFS3ERR_NOTSUPP: u32 = 10004; +pub const NFS3ERR_TOOSMALL: u32 = 10005; +pub const NFS3ERR_SERVERFAULT: u32 = 10006; +pub const NFS3ERR_BADTYPE: u32 = 10007; +pub const NFS3ERR_JUKEBOX: u32 = 10008; pub fn nfs3_status_string(status: u32) -> String { match status { - NFS3_OK => "OK", - NFS3ERR_PERM => "ERR_PERM", - NFS3ERR_NOENT => "ERR_NOENT", - NFS3ERR_IO => "ERR_IO", - NFS3ERR_NXIO => "ERR_NXIO", - NFS3ERR_ACCES => "ERR_ACCES", - NFS3ERR_EXIST => "ERR_EXIST", - NFS3ERR_XDEV => "ERR_XDEV", - NFS3ERR_NODEV => "ERR_NODEV", - NFS3ERR_NOTDIR => "ERR_NOTDIR", - NFS3ERR_ISDIR => "ERR_ISDIR", - NFS3ERR_INVAL => "ERR_INVAL", - NFS3ERR_FBIG => "ERR_FBIG", - NFS3ERR_NOSPC => "ERR_NOSPC", - NFS3ERR_ROFS => "ERR_ROFS", - NFS3ERR_MLINK => "ERR_MLINK", + NFS3_OK => "OK", + NFS3ERR_PERM => "ERR_PERM", + NFS3ERR_NOENT => "ERR_NOENT", + NFS3ERR_IO => "ERR_IO", + NFS3ERR_NXIO => "ERR_NXIO", + NFS3ERR_ACCES => "ERR_ACCES", + NFS3ERR_EXIST => "ERR_EXIST", + NFS3ERR_XDEV => "ERR_XDEV", + NFS3ERR_NODEV => "ERR_NODEV", + NFS3ERR_NOTDIR => "ERR_NOTDIR", + NFS3ERR_ISDIR => "ERR_ISDIR", + NFS3ERR_INVAL => "ERR_INVAL", + NFS3ERR_FBIG => "ERR_FBIG", + NFS3ERR_NOSPC => "ERR_NOSPC", + NFS3ERR_ROFS => "ERR_ROFS", + NFS3ERR_MLINK => "ERR_MLINK", NFS3ERR_NAMETOOLONG => "ERR_NAMETOOLONG", - NFS3ERR_NOTEMPTY => "ERR_NOTEMPTY", - NFS3ERR_DQUOT => "ERR_DQUOT", - NFS3ERR_STALE => "ERR_STALE", - NFS3ERR_REMOTE => "ERR_REMOTE", - NFS3ERR_BADHANDLE => "ERR_BADHANDLE", - NFS3ERR_NOT_SYNC => "ERR_NOT_SYNC", - NFS3ERR_BAD_COOKIE => "ERR_BAD_COOKIE", - NFS3ERR_NOTSUPP => "ERR_NOTSUPP", - NFS3ERR_TOOSMALL => "ERR_TOOSMALL", + NFS3ERR_NOTEMPTY => "ERR_NOTEMPTY", + NFS3ERR_DQUOT => "ERR_DQUOT", + NFS3ERR_STALE => "ERR_STALE", + NFS3ERR_REMOTE => "ERR_REMOTE", + NFS3ERR_BADHANDLE => "ERR_BADHANDLE", + NFS3ERR_NOT_SYNC => "ERR_NOT_SYNC", + NFS3ERR_BAD_COOKIE => "ERR_BAD_COOKIE", + NFS3ERR_NOTSUPP => "ERR_NOTSUPP", + NFS3ERR_TOOSMALL => "ERR_TOOSMALL", NFS3ERR_SERVERFAULT => "ERR_SERVERFAULT", - NFS3ERR_BADTYPE => "ERR_BADTYPE", - NFS3ERR_JUKEBOX => "ERR_JUKEBOX", + NFS3ERR_BADTYPE => "ERR_BADTYPE", + NFS3ERR_JUKEBOX => "ERR_JUKEBOX", _ => { return (status).to_string(); - }, - }.to_string() + } + } + .to_string() } -pub const RPCMSG_ACCEPTED: u32 = 0; -pub const RPCMSG_DENIED: u32 = 1; +pub const RPCMSG_ACCEPTED: u32 = 0; +pub const RPCMSG_DENIED: u32 = 1; pub fn rpc_status_string(status: u32) -> String { match status { RPCMSG_ACCEPTED => "ACCEPTED", - RPCMSG_DENIED => "DENIED", + RPCMSG_DENIED => "DENIED", _ => { return (status).to_string(); - }, - }.to_string() + } + } + .to_string() } /* http://www.iana.org/assignments/rpc-authentication-numbers/rpc-authentication-numbers.xhtml */ /* RFC 1057 Section 7.2 */ /* RFC 2203 Section 3 */ -pub const RPCAUTH_NULL: u32 = 0; -pub const RPCAUTH_UNIX: u32 = 1; -pub const RPCAUTH_SHORT: u32 = 2; -pub const RPCAUTH_DH: u32 = 3; -pub const RPCAUTH_KERB: u32 = 4; -pub const RPCAUTH_RSA: u32 = 5; -pub const RPCAUTH_GSS: u32 = 6; +pub const RPCAUTH_NULL: u32 = 0; +pub const RPCAUTH_UNIX: u32 = 1; +pub const RPCAUTH_SHORT: u32 = 2; +pub const RPCAUTH_DH: u32 = 3; +pub const RPCAUTH_KERB: u32 = 4; +pub const RPCAUTH_RSA: u32 = 5; +pub const RPCAUTH_GSS: u32 = 6; pub fn rpc_auth_type_string(auth_type: u32) -> String { match auth_type { - RPCAUTH_NULL => "NULL", - RPCAUTH_UNIX => "UNIX", - RPCAUTH_SHORT => "SHORT", - RPCAUTH_DH => "DH", - RPCAUTH_KERB => "KERB", - RPCAUTH_RSA => "RSA", - RPCAUTH_GSS => "GSS", + RPCAUTH_NULL => "NULL", + RPCAUTH_UNIX => "UNIX", + RPCAUTH_SHORT => "SHORT", + RPCAUTH_DH => "DH", + RPCAUTH_KERB => "KERB", + RPCAUTH_RSA => "RSA", + RPCAUTH_GSS => "GSS", _ => { return (auth_type).to_string(); - }, - }.to_string() + } + } + .to_string() } pub fn rpc_auth_type_known(auth_type: u32) -> i8 { @@ -185,109 +189,107 @@ pub fn rpc_auth_type_known(auth_type: u32) -> i8 { return -1; } - -pub const NFSPROC4_NULL: u32 = 0; -pub const NFSPROC4_COMPOUND: u32 = 1; +pub const NFSPROC4_NULL: u32 = 0; +pub const NFSPROC4_COMPOUND: u32 = 1; /* ops */ -pub const NFSPROC4_ACCESS: u32 = 3; -pub const NFSPROC4_CLOSE: u32 = 4; -pub const NFSPROC4_COMMIT: u32 = 5; -pub const NFSPROC4_CREATE: u32 = 6; -pub const NFSPROC4_DELEGPURGE: u32 = 7; -pub const NFSPROC4_DELEGRETURN: u32 = 8; -pub const NFSPROC4_GETATTR: u32 = 9; -pub const NFSPROC4_GETFH: u32 = 10; -pub const NFSPROC4_LINK: u32 = 11; -pub const NFSPROC4_LOCK: u32 = 12; -pub const NFSPROC4_LOCKT: u32 = 13; -pub const NFSPROC4_LOCKU: u32 = 14; -pub const NFSPROC4_LOOKUP: u32 = 15; -pub const NFSPROC4_LOOKUPP: u32 = 16; -pub const NFSPROC4_NVERIFY: u32 = 17; -pub const NFSPROC4_OPEN: u32 = 18; -pub const NFSPROC4_OPENATTR: u32 = 19; -pub const NFSPROC4_OPEN_CONFIRM: u32 = 20; -pub const NFSPROC4_OPEN_DOWNGRADE: u32 = 21; -pub const NFSPROC4_PUTFH: u32 = 22; -pub const NFSPROC4_PUTPUBFH: u32 = 23; -pub const NFSPROC4_PUTROOTFH: u32 = 24; -pub const NFSPROC4_READ: u32 = 25; -pub const NFSPROC4_READDIR: u32 = 26; -pub const NFSPROC4_READLINK: u32 = 27; -pub const NFSPROC4_REMOVE: u32 = 28; -pub const NFSPROC4_RENAME: u32 = 29; -pub const NFSPROC4_RENEW: u32 = 30; -pub const NFSPROC4_RESTOREFH: u32 = 31; -pub const NFSPROC4_SAVEFH: u32 = 32; -pub const NFSPROC4_SECINFO: u32 = 33; -pub const NFSPROC4_SETATTR: u32 = 34; -pub const NFSPROC4_SETCLIENTID: u32 = 35; +pub const NFSPROC4_ACCESS: u32 = 3; +pub const NFSPROC4_CLOSE: u32 = 4; +pub const NFSPROC4_COMMIT: u32 = 5; +pub const NFSPROC4_CREATE: u32 = 6; +pub const NFSPROC4_DELEGPURGE: u32 = 7; +pub const NFSPROC4_DELEGRETURN: u32 = 8; +pub const NFSPROC4_GETATTR: u32 = 9; +pub const NFSPROC4_GETFH: u32 = 10; +pub const NFSPROC4_LINK: u32 = 11; +pub const NFSPROC4_LOCK: u32 = 12; +pub const NFSPROC4_LOCKT: u32 = 13; +pub const NFSPROC4_LOCKU: u32 = 14; +pub const NFSPROC4_LOOKUP: u32 = 15; +pub const NFSPROC4_LOOKUPP: u32 = 16; +pub const NFSPROC4_NVERIFY: u32 = 17; +pub const NFSPROC4_OPEN: u32 = 18; +pub const NFSPROC4_OPENATTR: u32 = 19; +pub const NFSPROC4_OPEN_CONFIRM: u32 = 20; +pub const NFSPROC4_OPEN_DOWNGRADE: u32 = 21; +pub const NFSPROC4_PUTFH: u32 = 22; +pub const NFSPROC4_PUTPUBFH: u32 = 23; +pub const NFSPROC4_PUTROOTFH: u32 = 24; +pub const NFSPROC4_READ: u32 = 25; +pub const NFSPROC4_READDIR: u32 = 26; +pub const NFSPROC4_READLINK: u32 = 27; +pub const NFSPROC4_REMOVE: u32 = 28; +pub const NFSPROC4_RENAME: u32 = 29; +pub const NFSPROC4_RENEW: u32 = 30; +pub const NFSPROC4_RESTOREFH: u32 = 31; +pub const NFSPROC4_SAVEFH: u32 = 32; +pub const NFSPROC4_SECINFO: u32 = 33; +pub const NFSPROC4_SETATTR: u32 = 34; +pub const NFSPROC4_SETCLIENTID: u32 = 35; pub const NFSPROC4_SETCLIENTID_CONFIRM: u32 = 36; -pub const NFSPROC4_VERIFY: u32 = 37; -pub const NFSPROC4_WRITE: u32 = 38; -pub const NFSPROC4_RELEASE_LOCKOWNER: u32 = 39; -pub const NFSPROC4_EXCHANGE_ID: u32 = 42; -pub const NFSPROC4_CREATE_SESSION: u32 = 43; -pub const NFSPROC4_DESTROY_SESSION: u32 = 44; -pub const NFSPROC4_GETDEVINFO: u32 = 47; -pub const NFSPROC4_LAYOUTGET: u32 = 50; -pub const NFSPROC4_LAYOUTRETURN: u32 = 51; -pub const NFSPROC4_SECINFO_NO_NAME: u32 = 52; -pub const NFSPROC4_SEQUENCE: u32 = 53; -pub const NFSPROC4_DESTROY_CLIENTID: u32 = 57; -pub const NFSPROC4_RECLAIM_COMPLETE: u32 = 58; - -pub const NFSPROC4_ILLEGAL: u32 = 10044; +pub const NFSPROC4_VERIFY: u32 = 37; +pub const NFSPROC4_WRITE: u32 = 38; +pub const NFSPROC4_RELEASE_LOCKOWNER: u32 = 39; +pub const NFSPROC4_EXCHANGE_ID: u32 = 42; +pub const NFSPROC4_CREATE_SESSION: u32 = 43; +pub const NFSPROC4_DESTROY_SESSION: u32 = 44; +pub const NFSPROC4_GETDEVINFO: u32 = 47; +pub const NFSPROC4_LAYOUTGET: u32 = 50; +pub const NFSPROC4_LAYOUTRETURN: u32 = 51; +pub const NFSPROC4_SECINFO_NO_NAME: u32 = 52; +pub const NFSPROC4_SEQUENCE: u32 = 53; +pub const NFSPROC4_DESTROY_CLIENTID: u32 = 57; +pub const NFSPROC4_RECLAIM_COMPLETE: u32 = 58; +pub const NFSPROC4_ILLEGAL: u32 = 10044; pub fn nfs4_procedure_string(procedure: u32) -> String { match procedure { - NFSPROC4_COMPOUND => "COMPOUND", - NFSPROC4_NULL => "NULL", + NFSPROC4_COMPOUND => "COMPOUND", + NFSPROC4_NULL => "NULL", // ops - NFSPROC4_ACCESS => "ACCESS", - NFSPROC4_CLOSE => "CLOSE", - NFSPROC4_COMMIT => "COMMIT", - NFSPROC4_CREATE => "CREATE", - NFSPROC4_DELEGPURGE => "DELEGPURGE", - NFSPROC4_DELEGRETURN => "DELEGRETURN", - NFSPROC4_GETATTR => "GETATTR", - NFSPROC4_GETFH => "GETFH", - NFSPROC4_LINK => "LINK", - NFSPROC4_LOCK => "LOCK", - NFSPROC4_LOCKT => "LOCKT", - NFSPROC4_LOCKU => "LOCKU", - NFSPROC4_LOOKUP => "LOOKUP", - NFSPROC4_LOOKUPP => "LOOKUPP", - NFSPROC4_NVERIFY => "NVERIFY", - NFSPROC4_OPEN => "OPEN", - NFSPROC4_OPENATTR => "OPENATTR", - NFSPROC4_OPEN_CONFIRM => "OPEN_CONFIRM", - NFSPROC4_OPEN_DOWNGRADE => "OPEN_DOWNGRADE", - NFSPROC4_PUTFH => "PUTFH", - NFSPROC4_PUTPUBFH => "PUTPUBFH", - NFSPROC4_PUTROOTFH => "PUTROOTFH", - NFSPROC4_READ => "READ", - NFSPROC4_READDIR => "READDIR", - NFSPROC4_READLINK => "READLINK", - NFSPROC4_REMOVE => "REMOVE", - NFSPROC4_RENAME => "RENAME", - NFSPROC4_RENEW => "RENEW", - NFSPROC4_RESTOREFH => "RESTOREFH", - NFSPROC4_SAVEFH => "SAVEFH", - NFSPROC4_SECINFO => "SECINFO", - NFSPROC4_SETATTR => "SETATTR", - NFSPROC4_SETCLIENTID => "SETCLIENTID", - NFSPROC4_SETCLIENTID_CONFIRM => "SETCLIENTID_CONFIRM", - NFSPROC4_VERIFY => "VERIFY", - NFSPROC4_WRITE => "WRITE", - NFSPROC4_RELEASE_LOCKOWNER => "RELEASE_LOCKOWNER", - NFSPROC4_ILLEGAL => "ILLEGAL", + NFSPROC4_ACCESS => "ACCESS", + NFSPROC4_CLOSE => "CLOSE", + NFSPROC4_COMMIT => "COMMIT", + NFSPROC4_CREATE => "CREATE", + NFSPROC4_DELEGPURGE => "DELEGPURGE", + NFSPROC4_DELEGRETURN => "DELEGRETURN", + NFSPROC4_GETATTR => "GETATTR", + NFSPROC4_GETFH => "GETFH", + NFSPROC4_LINK => "LINK", + NFSPROC4_LOCK => "LOCK", + NFSPROC4_LOCKT => "LOCKT", + NFSPROC4_LOCKU => "LOCKU", + NFSPROC4_LOOKUP => "LOOKUP", + NFSPROC4_LOOKUPP => "LOOKUPP", + NFSPROC4_NVERIFY => "NVERIFY", + NFSPROC4_OPEN => "OPEN", + NFSPROC4_OPENATTR => "OPENATTR", + NFSPROC4_OPEN_CONFIRM => "OPEN_CONFIRM", + NFSPROC4_OPEN_DOWNGRADE => "OPEN_DOWNGRADE", + NFSPROC4_PUTFH => "PUTFH", + NFSPROC4_PUTPUBFH => "PUTPUBFH", + NFSPROC4_PUTROOTFH => "PUTROOTFH", + NFSPROC4_READ => "READ", + NFSPROC4_READDIR => "READDIR", + NFSPROC4_READLINK => "READLINK", + NFSPROC4_REMOVE => "REMOVE", + NFSPROC4_RENAME => "RENAME", + NFSPROC4_RENEW => "RENEW", + NFSPROC4_RESTOREFH => "RESTOREFH", + NFSPROC4_SAVEFH => "SAVEFH", + NFSPROC4_SECINFO => "SECINFO", + NFSPROC4_SETATTR => "SETATTR", + NFSPROC4_SETCLIENTID => "SETCLIENTID", + NFSPROC4_SETCLIENTID_CONFIRM => "SETCLIENTID_CONFIRM", + NFSPROC4_VERIFY => "VERIFY", + NFSPROC4_WRITE => "WRITE", + NFSPROC4_RELEASE_LOCKOWNER => "RELEASE_LOCKOWNER", + NFSPROC4_ILLEGAL => "ILLEGAL", _ => { return (procedure).to_string(); } - }.to_string() + } + .to_string() } -pub const NFS4_OK: u32 = 0; - +pub const NFS4_OK: u32 = 0; diff --git a/rust/src/ntp/ntp.rs b/rust/src/ntp/ntp.rs index c7b3b3d01826..71b94d72adfa 100644 --- a/rust/src/ntp/ntp.rs +++ b/rust/src/ntp/ntp.rs @@ -19,9 +19,9 @@ extern crate ntp_parser; use self::ntp_parser::*; -use crate::core; -use crate::core::{AppProto,Flow,ALPROTO_UNKNOWN,ALPROTO_FAILED,Direction}; use crate::applayer::{self, *}; +use crate::core; +use crate::core::{AppProto, Direction, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN}; use std; use std::ffi::CString; @@ -29,7 +29,7 @@ use nom7::Err; #[derive(AppLayerEvent)] pub enum NTPEvent { - UnsolicitedResponse , + UnsolicitedResponse, MalformedData, NotRequest, NotResponse, @@ -88,7 +88,7 @@ impl NTPState { /// Returns 0 if successful, or -1 on error fn parse(&mut self, i: &[u8], direction: Direction) -> i32 { match parse_ntp(i) { - Ok((_,ref msg)) => { + Ok((_, ref msg)) => { // SCLogDebug!("parse_ntp: {:?}",msg); let (mode, ref_id) = match msg { NtpPacket::V3(pkt) => (pkt.mode, pkt.ref_id), @@ -101,17 +101,17 @@ impl NTPState { self.transactions.push(tx); } 0 - }, + } Err(Err::Incomplete(_)) => { SCLogDebug!("Insufficient data while parsing NTP data"); self.set_event(NTPEvent::MalformedData); -1 - }, + } Err(_) => { SCLogDebug!("Error while parsing NTP data"); self.set_event(NTPEvent::MalformedData); -1 - }, + } } } @@ -159,7 +159,9 @@ impl NTPTransaction { /// Returns *mut NTPState #[no_mangle] -pub extern "C" fn rs_ntp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_ntp_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = NTPState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; @@ -168,19 +170,17 @@ pub extern "C" fn rs_ntp_state_new(_orig_state: *mut std::os::raw::c_void, _orig /// Params: /// - state: *mut NTPState as void pointer #[no_mangle] -pub extern "C" fn rs_ntp_state_free(state: *mut std::os::raw::c_void) { - let mut ntp_state = unsafe{ Box::from_raw(state as *mut NTPState) }; +pub extern fn rs_ntp_state_free(state: *mut std::os::raw::c_void) { + let mut ntp_state = unsafe { Box::from_raw(state as *mut NTPState) }; ntp_state.free(); } #[no_mangle] -pub unsafe extern "C" fn rs_ntp_parse_request(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { - let state = cast_pointer!(state,NTPState); +pub unsafe extern fn rs_ntp_parse_request( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { + let state = cast_pointer!(state, NTPState); if state.parse(stream_slice.as_slice(), Direction::ToServer) < 0 { return AppLayerResult::err(); } @@ -188,13 +188,11 @@ pub unsafe extern "C" fn rs_ntp_parse_request(_flow: *const core::Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_ntp_parse_response(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { - let state = cast_pointer!(state,NTPState); +pub unsafe extern fn rs_ntp_parse_response( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { + let state = cast_pointer!(state, NTPState); if state.parse(stream_slice.as_slice(), Direction::ToClient) < 0 { return AppLayerResult::err(); } @@ -202,102 +200,94 @@ pub unsafe extern "C" fn rs_ntp_parse_response(_flow: *const core::Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_ntp_state_get_tx(state: *mut std::os::raw::c_void, - tx_id: u64) - -> *mut std::os::raw::c_void -{ - let state = cast_pointer!(state,NTPState); +pub unsafe extern fn rs_ntp_state_get_tx( + state: *mut std::os::raw::c_void, tx_id: u64, +) -> *mut std::os::raw::c_void { + let state = cast_pointer!(state, NTPState); match state.get_tx_by_id(tx_id) { Some(tx) => tx as *const _ as *mut _, - None => std::ptr::null_mut(), + None => std::ptr::null_mut(), } } #[no_mangle] -pub unsafe extern "C" fn rs_ntp_state_get_tx_count(state: *mut std::os::raw::c_void) - -> u64 -{ - let state = cast_pointer!(state,NTPState); +pub unsafe extern fn rs_ntp_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { + let state = cast_pointer!(state, NTPState); state.tx_id } #[no_mangle] -pub unsafe extern "C" fn rs_ntp_state_tx_free(state: *mut std::os::raw::c_void, - tx_id: u64) -{ - let state = cast_pointer!(state,NTPState); +pub unsafe extern fn rs_ntp_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { + let state = cast_pointer!(state, NTPState); state.free_tx(tx_id); } #[no_mangle] -pub extern "C" fn rs_ntp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void, - _direction: u8) - -> std::os::raw::c_int -{ +pub extern fn rs_ntp_tx_get_alstate_progress( + _tx: *mut std::os::raw::c_void, _direction: u8, +) -> std::os::raw::c_int { 1 } -static mut ALPROTO_NTP : AppProto = ALPROTO_UNKNOWN; +static mut ALPROTO_NTP: AppProto = ALPROTO_UNKNOWN; #[no_mangle] -pub extern "C" fn ntp_probing_parser(_flow: *const Flow, - _direction: u8, - input:*const u8, input_len: u32, - _rdir: *mut u8) -> AppProto -{ +pub extern fn ntp_probing_parser( + _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, +) -> AppProto { let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, input_len as usize) }; - let alproto = unsafe{ ALPROTO_NTP }; + let alproto = unsafe { ALPROTO_NTP }; match parse_ntp(slice) { Ok((_, _)) => { // parse_ntp already checks for supported version (3 or 4) return alproto; - }, + } Err(Err::Incomplete(_)) => { return ALPROTO_UNKNOWN; - }, + } Err(_) => { - return unsafe{ALPROTO_FAILED}; - }, + return unsafe { ALPROTO_FAILED }; + } } } export_tx_data_get!(rs_ntp_get_tx_data, NTPTransaction); export_state_data_get!(rs_ntp_get_state_data, NTPState); -const PARSER_NAME : &[u8] = b"ntp\0"; +const PARSER_NAME: &[u8] = b"ntp\0"; #[no_mangle] -pub unsafe extern "C" fn rs_register_ntp_parser() { +pub unsafe extern fn rs_register_ntp_parser() { let default_port = CString::new("123").unwrap(); let parser = RustParser { - name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char, - default_port : default_port.as_ptr(), - ipproto : core::IPPROTO_UDP, - probe_ts : Some(ntp_probing_parser), - probe_tc : Some(ntp_probing_parser), - min_depth : 0, - max_depth : 16, - state_new : rs_ntp_state_new, - state_free : rs_ntp_state_free, - tx_free : rs_ntp_state_tx_free, - parse_ts : rs_ntp_parse_request, - parse_tc : rs_ntp_parse_response, - get_tx_count : rs_ntp_state_get_tx_count, - get_tx : rs_ntp_state_get_tx, - tx_comp_st_ts : 1, - tx_comp_st_tc : 1, - tx_get_progress : rs_ntp_tx_get_alstate_progress, - get_eventinfo : Some(NTPEvent::get_event_info), - get_eventinfo_byid : Some(NTPEvent::get_event_info_by_id), - localstorage_new : None, - localstorage_free : None, - get_tx_files : None, - get_tx_iterator : Some(applayer::state_get_tx_iterator::), - get_tx_data : rs_ntp_get_tx_data, - get_state_data : rs_ntp_get_state_data, - apply_tx_config : None, - flags : 0, - truncate : None, + name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, + default_port: default_port.as_ptr(), + ipproto: core::IPPROTO_UDP, + probe_ts: Some(ntp_probing_parser), + probe_tc: Some(ntp_probing_parser), + min_depth: 0, + max_depth: 16, + state_new: rs_ntp_state_new, + state_free: rs_ntp_state_free, + tx_free: rs_ntp_state_tx_free, + parse_ts: rs_ntp_parse_request, + parse_tc: rs_ntp_parse_response, + get_tx_count: rs_ntp_state_get_tx_count, + get_tx: rs_ntp_state_get_tx, + tx_comp_st_ts: 1, + tx_comp_st_tc: 1, + tx_get_progress: rs_ntp_tx_get_alstate_progress, + get_eventinfo: Some(NTPEvent::get_event_info), + get_eventinfo_byid: Some(NTPEvent::get_event_info_by_id), + localstorage_new: None, + localstorage_free: None, + get_tx_files: None, + get_tx_iterator: Some(applayer::state_get_tx_iterator::), + get_tx_data: rs_ntp_get_tx_data, + get_state_data: rs_ntp_get_state_data, + apply_tx_config: None, + flags: 0, + truncate: None, get_frame_id_by_name: None, get_frame_name_by_id: None, }; @@ -315,7 +305,6 @@ pub unsafe extern "C" fn rs_register_ntp_parser() { } } - #[cfg(test)] mod tests { use super::*; @@ -323,13 +312,11 @@ mod tests { #[test] fn test_ntp_parse_request_valid() { // A UDP NTP v4 request, in client mode - const REQ : &[u8] = &[ - 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x57, 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe + const REQ: &[u8] = &[ + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x57, + 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe, ]; let mut state = NTPState::new(); diff --git a/rust/src/pgsql/logger.rs b/rust/src/pgsql/logger.rs index 03b1ad0f4677..e10dea758fc0 100644 --- a/rust/src/pgsql/logger.rs +++ b/rust/src/pgsql/logger.rs @@ -278,7 +278,7 @@ fn log_pgsql_param(param: &PgsqlParameter) -> Result { } #[no_mangle] -pub unsafe extern "C" fn rs_pgsql_logger( +pub unsafe extern fn rs_pgsql_logger( tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder, ) -> bool { let tx_pgsql = cast_pointer!(tx, PgsqlTransaction); diff --git a/rust/src/pgsql/parser.rs b/rust/src/pgsql/parser.rs index ae07d5d5a078..e73ceb8e912d 100644 --- a/rust/src/pgsql/parser.rs +++ b/rust/src/pgsql/parser.rs @@ -275,7 +275,7 @@ impl PgsqlBEMessage { } PgsqlBEMessage::ConsolidatedDataRow(_) => "data_row", PgsqlBEMessage::NotificationResponse(_) => "notification_response", - PgsqlBEMessage::UnknownMessageType(_) => "unknown_message_type" + PgsqlBEMessage::UnknownMessageType(_) => "unknown_message_type", } } @@ -520,16 +520,25 @@ fn pgsql_parse_generic_parameter(i: &[u8]) -> IResult<&[u8], PgsqlParameter> { let (i, _) = tag("\x00")(i)?; let (i, param_value) = take_until("\x00")(i)?; let (i, _) = tag("\x00")(i)?; - Ok((i, PgsqlParameter { - name: PgsqlParameters::from(param_name), - value: param_value.to_vec(), - })) + Ok(( + i, + PgsqlParameter { + name: PgsqlParameters::from(param_name), + value: param_value.to_vec(), + }, + )) } pub fn pgsql_parse_startup_parameters(i: &[u8]) -> IResult<&[u8], PgsqlStartupParameters> { - let (i, mut optional) = opt(terminated(many1(pgsql_parse_generic_parameter), tag("\x00")))(i)?; + let (i, mut optional) = opt(terminated( + many1(pgsql_parse_generic_parameter), + tag("\x00"), + ))(i)?; if let Some(ref mut params) = optional { - let mut user = PgsqlParameter{name: PgsqlParameters::User, value: Vec::new() }; + let mut user = PgsqlParameter { + name: PgsqlParameters::User, + value: Vec::new(), + }; let mut index: usize = 0; for (j, p) in params.iter().enumerate() { if p.name == PgsqlParameters::User { @@ -541,17 +550,20 @@ pub fn pgsql_parse_startup_parameters(i: &[u8]) -> IResult<&[u8], PgsqlStartupPa if user.value.is_empty() { return Err(Err::Error(make_error(i, ErrorKind::Tag))); } - return Ok((i, PgsqlStartupParameters{ - user, - optional_params: if !params.is_empty() { - optional - } else { None }, - })); + return Ok(( + i, + PgsqlStartupParameters { + user, + optional_params: if !params.is_empty() { optional } else { None }, + }, + )); } return Err(Err::Error(make_error(i, ErrorKind::Tag))); } -fn parse_sasl_initial_response_payload(i: &[u8]) -> IResult<&[u8], (SASLAuthenticationMechanism, u32, Vec)> { +fn parse_sasl_initial_response_payload( + i: &[u8], +) -> IResult<&[u8], (SASLAuthenticationMechanism, u32, Vec)> { let (i, sasl_mechanism) = parse_sasl_mechanism(i)?; let (i, param_length) = be_u32(i)?; // From RFC 5802 - the client-first-message will always start w/ @@ -563,27 +575,31 @@ fn parse_sasl_initial_response_payload(i: &[u8]) -> IResult<&[u8], (SASLAuthenti pub fn parse_sasl_initial_response(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'p')(i)?; let (i, length) = verify(be_u32, |&x| x > PGSQL_LENGTH_FIELD)(i)?; - let (i, payload) = map_parser(take(length - PGSQL_LENGTH_FIELD), parse_sasl_initial_response_payload)(i)?; - Ok((i, PgsqlFEMessage::SASLInitialResponse( - SASLInitialResponsePacket { - identifier, - length, - auth_mechanism: payload.0, - param_length: payload.1, - sasl_param: payload.2, - }))) + let (i, payload) = map_parser( + take(length - PGSQL_LENGTH_FIELD), + parse_sasl_initial_response_payload, + )(i)?; + Ok(( + i, + PgsqlFEMessage::SASLInitialResponse(SASLInitialResponsePacket { + identifier, + length, + auth_mechanism: payload.0, + param_length: payload.1, + sasl_param: payload.2, + }), + )) } pub fn parse_sasl_response(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'p')(i)?; let (i, length) = verify(be_u32, |&x| x > PGSQL_LENGTH_FIELD)(i)?; let (i, payload) = take(length - PGSQL_LENGTH_FIELD)(i)?; - let resp = PgsqlFEMessage::SASLResponse( - RegularPacket { - identifier, - length, - payload: payload.to_vec(), - }); + let resp = PgsqlFEMessage::SASLResponse(RegularPacket { + identifier, + length, + payload: payload.to_vec(), + }); Ok((i, resp)) } @@ -591,33 +607,40 @@ pub fn pgsql_parse_startup_packet(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage> { let (i, len) = verify(be_u32, |&x| x >= 8)(i)?; let (i, proto_major) = peek(be_u16)(i)?; let (i, b) = take(len - PGSQL_LENGTH_FIELD)(i)?; - let (_, message) = - match proto_major { - 1..=3 => { - let (b, proto_major) = be_u16(b)?; - let (b, proto_minor) = be_u16(b)?; - let (b, params) = pgsql_parse_startup_parameters(b)?; - (b, PgsqlFEMessage::StartupMessage(StartupPacket{ + let (_, message) = match proto_major { + 1..=3 => { + let (b, proto_major) = be_u16(b)?; + let (b, proto_minor) = be_u16(b)?; + let (b, params) = pgsql_parse_startup_parameters(b)?; + ( + b, + PgsqlFEMessage::StartupMessage(StartupPacket { length: len, proto_major, proto_minor, - params})) - }, - PGSQL_DUMMY_PROTO_MAJOR => { - let (b, proto_major) = be_u16(b)?; - let (b, proto_minor) = all_consuming(be_u16)(b)?; - let _message = match proto_minor { - PGSQL_DUMMY_PROTO_MINOR_SSL => (len, proto_major, proto_minor), - _ => return Err(Err::Error(make_error(b, ErrorKind::Switch))), - }; - - (b, PgsqlFEMessage::SSLRequest(DummyStartupPacket{ + params, + }), + ) + } + PGSQL_DUMMY_PROTO_MAJOR => { + let (b, proto_major) = be_u16(b)?; + let (b, proto_minor) = all_consuming(be_u16)(b)?; + let _message = match proto_minor { + PGSQL_DUMMY_PROTO_MINOR_SSL => (len, proto_major, proto_minor), + _ => return Err(Err::Error(make_error(b, ErrorKind::Switch))), + }; + + ( + b, + PgsqlFEMessage::SSLRequest(DummyStartupPacket { length: len, proto_major, - proto_minor})) - } - _ => return Err(Err::Error(make_error(b, ErrorKind::Switch))), - }; + proto_minor, + }), + ) + } + _ => return Err(Err::Error(make_error(b, ErrorKind::Switch))), + }; Ok((i, message)) } @@ -637,33 +660,38 @@ pub fn pgsql_parse_startup_packet(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage> { pub fn parse_password_message(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'p')(i)?; let (i, length) = verify(be_u32, |&x| x >= PGSQL_LENGTH_FIELD)(i)?; - let (i, password) = map_parser( - take(length - PGSQL_LENGTH_FIELD), - take_until1("\x00") - )(i)?; - Ok((i, PgsqlFEMessage::PasswordMessage( - RegularPacket{ - identifier, - length, - payload: password.to_vec(), - }))) + let (i, password) = map_parser(take(length - PGSQL_LENGTH_FIELD), take_until1("\x00"))(i)?; + Ok(( + i, + PgsqlFEMessage::PasswordMessage(RegularPacket { + identifier, + length, + payload: password.to_vec(), + }), + )) } fn parse_simple_query(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'Q')(i)?; let (i, length) = verify(be_u32, |&x| x > PGSQL_LENGTH_FIELD)(i)?; let (i, query) = map_parser(take(length - PGSQL_LENGTH_FIELD), take_until1("\x00"))(i)?; - Ok((i, PgsqlFEMessage::SimpleQuery(RegularPacket { - identifier, - length, - payload: query.to_vec(), - }))) + Ok(( + i, + PgsqlFEMessage::SimpleQuery(RegularPacket { + identifier, + length, + payload: query.to_vec(), + }), + )) } fn parse_terminate_message(i: &[u8]) -> IResult<&[u8], PgsqlFEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'X')(i)?; let (i, length) = verify(be_u32, |&x| x == PGSQL_LENGTH_FIELD)(i)?; - Ok((i, PgsqlFEMessage::Terminate(TerminationMessage { identifier, length }))) + Ok(( + i, + PgsqlFEMessage::Terminate(TerminationMessage { identifier, length }), + )) } // Messages that begin with 'p' but are not password ones are not parsed here @@ -683,97 +711,114 @@ fn pgsql_parse_authentication_message<'a>(i: &'a [u8]) -> IResult<&'a [u8], Pgsq let (i, length) = verify(be_u32, |&x| x >= 8)(i)?; let (i, auth_type) = be_u32(i)?; let (i, payload) = peek(rest)(i)?; - let (i, message) = map_parser( - take(length - 8), - |b: &'a [u8]| { - match auth_type { - 0 => Ok((b, PgsqlBEMessage::AuthenticationOk( - AuthenticationMessage { - identifier, - length, - auth_type, - payload: payload.to_vec(), - }))), - 3 => Ok((b, PgsqlBEMessage::AuthenticationCleartextPassword( - AuthenticationMessage { - identifier, - length, - auth_type, - payload: payload.to_vec(), - }))), - 5 => { - let (b, salt) = all_consuming(take(4_usize))(b)?; - Ok((b, PgsqlBEMessage::AuthenticationMD5Password( - AuthenticationMessage { - identifier, - length, - auth_type, - payload: salt.to_vec(), - }))) - } - 9 => Ok((b, PgsqlBEMessage::AuthenticationSSPI( - AuthenticationMessage { - identifier, - length, - auth_type, - payload: payload.to_vec(), - }))), - // TODO - For SASL, should we parse specific details of the challenge itself? (as seen in: https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/postgres/message/authentication.rs ) - 10 => { - let (b, auth_mechanisms) = parse_sasl_mechanisms(b)?; - Ok((b, PgsqlBEMessage::AuthenticationSASL( - AuthenticationSASLMechanismMessage { - identifier, - length, - auth_type, - auth_mechanisms, - }))) - } - 11 => { - let (b, sasl_challenge) = rest(i)?; - Ok((b, PgsqlBEMessage::AuthenticationSASLContinue( - AuthenticationMessage { - identifier, - length, - auth_type, - payload: sasl_challenge.to_vec(), - }))) - }, - 12 => { - let (i, signature) = take(length - 8)(i)?; - Ok((i, PgsqlBEMessage::AuthenticationSASLFinal( - AuthenticationMessage { - identifier, - length, - auth_type, - payload: signature.to_vec(), - } - ))) - } - // TODO add other authentication messages - _ => return Err(Err::Error(make_error(i, ErrorKind::Switch))), - } + let (i, message) = map_parser(take(length - 8), |b: &'a [u8]| { + match auth_type { + 0 => Ok(( + b, + PgsqlBEMessage::AuthenticationOk(AuthenticationMessage { + identifier, + length, + auth_type, + payload: payload.to_vec(), + }), + )), + 3 => Ok(( + b, + PgsqlBEMessage::AuthenticationCleartextPassword(AuthenticationMessage { + identifier, + length, + auth_type, + payload: payload.to_vec(), + }), + )), + 5 => { + let (b, salt) = all_consuming(take(4_usize))(b)?; + Ok(( + b, + PgsqlBEMessage::AuthenticationMD5Password(AuthenticationMessage { + identifier, + length, + auth_type, + payload: salt.to_vec(), + }), + )) + } + 9 => Ok(( + b, + PgsqlBEMessage::AuthenticationSSPI(AuthenticationMessage { + identifier, + length, + auth_type, + payload: payload.to_vec(), + }), + )), + // TODO - For SASL, should we parse specific details of the challenge itself? (as seen in: https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/postgres/message/authentication.rs ) + 10 => { + let (b, auth_mechanisms) = parse_sasl_mechanisms(b)?; + Ok(( + b, + PgsqlBEMessage::AuthenticationSASL(AuthenticationSASLMechanismMessage { + identifier, + length, + auth_type, + auth_mechanisms, + }), + )) + } + 11 => { + let (b, sasl_challenge) = rest(i)?; + Ok(( + b, + PgsqlBEMessage::AuthenticationSASLContinue(AuthenticationMessage { + identifier, + length, + auth_type, + payload: sasl_challenge.to_vec(), + }), + )) + } + 12 => { + let (i, signature) = take(length - 8)(i)?; + Ok(( + i, + PgsqlBEMessage::AuthenticationSASLFinal(AuthenticationMessage { + identifier, + length, + auth_type, + payload: signature.to_vec(), + }), + )) + } + // TODO add other authentication messages + _ => return Err(Err::Error(make_error(i, ErrorKind::Switch))), } - )(i)?; + })(i)?; Ok((i, message)) } fn parse_parameter_status_message(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'S')(i)?; let (i, length) = verify(be_u32, |&x| x >= PGSQL_LENGTH_FIELD)(i)?; - let (i, param) = map_parser(take(length - PGSQL_LENGTH_FIELD), pgsql_parse_generic_parameter)(i)?; - Ok((i, PgsqlBEMessage::ParameterStatus(ParameterStatusMessage { - identifier, - length, - param, - }))) + let (i, param) = map_parser( + take(length - PGSQL_LENGTH_FIELD), + pgsql_parse_generic_parameter, + )(i)?; + Ok(( + i, + PgsqlBEMessage::ParameterStatus(ParameterStatusMessage { + identifier, + length, + param, + }), + )) } pub fn parse_ssl_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, tag) = alt((char('N'), char('S')))(i)?; - Ok((i, PgsqlBEMessage::SSLResponse( - SSLResponseMessage::from(tag)) - )) + Ok(( + i, + PgsqlBEMessage::SSLResponse(SSLResponseMessage::from(tag)), + )) } fn parse_backend_key_data_message(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { @@ -781,34 +826,43 @@ fn parse_backend_key_data_message(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, length) = verify(be_u32, |&x| x == 12)(i)?; let (i, pid) = be_u32(i)?; let (i, secret_key) = be_u32(i)?; - Ok((i, PgsqlBEMessage::BackendKeyData(BackendKeyDataMessage { - identifier, - length, - backend_pid: pid, - secret_key, - }))) + Ok(( + i, + PgsqlBEMessage::BackendKeyData(BackendKeyDataMessage { + identifier, + length, + backend_pid: pid, + secret_key, + }), + )) } fn parse_command_complete(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'C')(i)?; let (i, length) = verify(be_u32, |&x| x > PGSQL_LENGTH_FIELD)(i)?; let (i, payload) = map_parser(take(length - PGSQL_LENGTH_FIELD), take_until("\x00"))(i)?; - Ok((i, PgsqlBEMessage::CommandComplete(RegularPacket { - identifier, - length, - payload: payload.to_vec(), - }))) + Ok(( + i, + PgsqlBEMessage::CommandComplete(RegularPacket { + identifier, + length, + payload: payload.to_vec(), + }), + )) } fn parse_ready_for_query(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'Z')(i)?; let (i, length) = verify(be_u32, |&x| x == 5)(i)?; let (i, status) = verify(be_u8, |&x| x == b'I' || x == b'T' || x == b'E')(i)?; - Ok((i, PgsqlBEMessage::ReadyForQuery(ReadyForQueryMessage { - identifier, - length, - transaction_status: status, - }))) + Ok(( + i, + PgsqlBEMessage::ReadyForQuery(ReadyForQueryMessage { + identifier, + length, + transaction_status: status, + }), + )) } fn parse_row_field(i: &[u8]) -> IResult<&[u8], RowField> { @@ -820,15 +874,18 @@ fn parse_row_field(i: &[u8]) -> IResult<&[u8], RowField> { let (i, data_type_size) = be_i16(i)?; let (i, type_modifier) = be_i32(i)?; let (i, format_code) = be_u16(i)?; - Ok((i, RowField { - field_name: field_name.to_vec(), - table_oid, - column_index, - data_type_oid, - data_type_size, - type_modifier, - format_code, - })) + Ok(( + i, + RowField { + field_name: field_name.to_vec(), + table_oid, + column_index, + data_type_oid, + data_type_size, + type_modifier, + format_code, + }, + )) } pub fn parse_row_description(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { @@ -837,29 +894,34 @@ pub fn parse_row_description(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, field_count) = be_u16(i)?; let (i, fields) = map_parser( take(length - 6), - many_m_n(0, field_count.into(), parse_row_field) + many_m_n(0, field_count.into(), parse_row_field), )(i)?; - Ok((i, PgsqlBEMessage::RowDescription( - RowDescriptionMessage { - identifier, - length, - field_count, - fields, - }))) + Ok(( + i, + PgsqlBEMessage::RowDescription(RowDescriptionMessage { + identifier, + length, + field_count, + fields, + }), + )) } fn parse_data_row_value(i: &[u8]) -> IResult<&[u8], ColumnFieldValue> { let (i, value_length) = be_i32(i)?; let (i, value) = cond(value_length >= 0, take(value_length as usize))(i)?; - Ok((i, ColumnFieldValue { - value_length, - value: { - match value { - Some(data) => data.to_vec(), - None => [].to_vec(), - } + Ok(( + i, + ColumnFieldValue { + value_length, + value: { + match value { + Some(data) => data.to_vec(), + None => [].to_vec(), + } + }, }, - })) + )) } /// For each column, add up the data size. Return the total @@ -882,15 +944,19 @@ pub fn parse_consolidated_data_row(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, length) = verify(be_u32, |&x| x >= 6)(i)?; let (i, field_count) = be_u16(i)?; // 6 here is for skipping length + field_count - let (i, rows) = map_parser(take(length - 6), many_m_n(0, field_count.into(), parse_data_row_value))(i)?; - Ok((i, PgsqlBEMessage::ConsolidatedDataRow( - ConsolidatedDataRowPacket { - identifier, - length, - row_cnt: 1, - data_size: add_up_data_size(rows), - } - ))) + let (i, rows) = map_parser( + take(length - 6), + many_m_n(0, field_count.into(), parse_data_row_value), + )(i)?; + Ok(( + i, + PgsqlBEMessage::ConsolidatedDataRow(ConsolidatedDataRowPacket { + identifier, + length, + row_cnt: 1, + data_size: add_up_data_size(rows), + }), + )) } fn parse_sasl_mechanism(i: &[u8]) -> IResult<&[u8], SASLAuthenticationMechanism> { @@ -912,10 +978,13 @@ fn parse_sasl_mechanisms(i: &[u8]) -> IResult<&[u8], Vec IResult<&[u8], PgsqlErrorNoticeMessageField> { let (i, _field_type) = char('C')(i)?; let (i, field_value) = map_parser(take(6_usize), alphanumeric1)(i)?; - Ok((i, PgsqlErrorNoticeMessageField{ - field_type: PgsqlErrorNoticeFieldType::CodeSqlStateCode, - field_value: field_value.to_vec(), - })) + Ok(( + i, + PgsqlErrorNoticeMessageField { + field_type: PgsqlErrorNoticeFieldType::CodeSqlStateCode, + field_value: field_value.to_vec(), + }, + )) } // Parse an error response with non-localizeable severity message. @@ -924,10 +993,13 @@ pub fn parse_error_response_severity(i: &[u8]) -> IResult<&[u8], PgsqlErrorNotic let (i, field_type) = char('V')(i)?; let (i, field_value) = alt((tag("ERROR"), tag("FATAL"), tag("PANIC")))(i)?; let (i, _) = tag("\x00")(i)?; - Ok((i, PgsqlErrorNoticeMessageField{ - field_type: PgsqlErrorNoticeFieldType::from(field_type), - field_value: field_value.to_vec(), - })) + Ok(( + i, + PgsqlErrorNoticeMessageField { + field_type: PgsqlErrorNoticeFieldType::from(field_type), + field_value: field_value.to_vec(), + }, + )) } // The non-localizable version of Severity field has different values, @@ -935,16 +1007,20 @@ pub fn parse_error_response_severity(i: &[u8]) -> IResult<&[u8], PgsqlErrorNotic pub fn parse_notice_response_severity(i: &[u8]) -> IResult<&[u8], PgsqlErrorNoticeMessageField> { let (i, field_type) = char('V')(i)?; let (i, field_value) = alt(( - tag("WARNING"), - tag("NOTICE"), - tag("DEBUG"), - tag("INFO"), - tag("LOG")))(i)?; + tag("WARNING"), + tag("NOTICE"), + tag("DEBUG"), + tag("INFO"), + tag("LOG"), + ))(i)?; let (i, _) = tag("\x00")(i)?; - Ok((i, PgsqlErrorNoticeMessageField{ - field_type: PgsqlErrorNoticeFieldType::from(field_type), - field_value: field_value.to_vec(), - })) + Ok(( + i, + PgsqlErrorNoticeMessageField { + field_type: PgsqlErrorNoticeFieldType::from(field_type), + field_value: field_value.to_vec(), + }, + )) } pub fn parse_error_response_field( @@ -974,7 +1050,9 @@ pub fn parse_error_response_field( Ok((i, data)) } -pub fn parse_error_notice_fields(i: &[u8], is_err_msg: bool) -> IResult<&[u8], Vec> { +pub fn parse_error_notice_fields( + i: &[u8], is_err_msg: bool, +) -> IResult<&[u8], Vec> { let (i, data) = many_till(|b| parse_error_response_field(b, is_err_msg), tag("\x00"))(i)?; Ok((i, data.0)) } @@ -982,45 +1060,47 @@ pub fn parse_error_notice_fields(i: &[u8], is_err_msg: bool) -> IResult<&[u8], V fn pgsql_parse_error_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'E')(i)?; let (i, length) = verify(be_u32, |&x| x > 10)(i)?; - let (i, message_body) = map_parser( - take(length - PGSQL_LENGTH_FIELD), - |b| parse_error_notice_fields(b, true) - )(i)?; + let (i, message_body) = map_parser(take(length - PGSQL_LENGTH_FIELD), |b| { + parse_error_notice_fields(b, true) + })(i)?; - Ok((i, PgsqlBEMessage::ErrorResponse(ErrorNoticeMessage { - identifier, - length, - message_body, - }))) + Ok(( + i, + PgsqlBEMessage::ErrorResponse(ErrorNoticeMessage { + identifier, + length, + message_body, + }), + )) } fn pgsql_parse_notice_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'N')(i)?; let (i, length) = verify(be_u32, |&x| x > 10)(i)?; - let (i, message_body) = map_parser( - take(length - PGSQL_LENGTH_FIELD), - |b| parse_error_notice_fields(b, false) - )(i)?; - Ok((i, PgsqlBEMessage::NoticeResponse(ErrorNoticeMessage { - identifier, - length, - message_body, - }))) + let (i, message_body) = map_parser(take(length - PGSQL_LENGTH_FIELD), |b| { + parse_error_notice_fields(b, false) + })(i)?; + Ok(( + i, + PgsqlBEMessage::NoticeResponse(ErrorNoticeMessage { + identifier, + length, + message_body, + }), + )) } fn parse_notification_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, identifier) = verify(be_u8, |&x| x == b'A')(i)?; // length (u32) + pid (u32) + at least one byte, for we have two str fields let (i, length) = verify(be_u32, |&x| x > 9)(i)?; - let (i, data) = map_parser( - take(length - PGSQL_LENGTH_FIELD), - |b| { - let (b, pid) = be_u32(b)?; - let (b, channel_name) = take_until_and_consume(b"\x00")(b)?; - let (b, payload) = take_until_and_consume(b"\x00")(b)?; - Ok((b, (pid, channel_name, payload))) - })(i)?; - let msg = PgsqlBEMessage::NotificationResponse(NotificationResponse{ + let (i, data) = map_parser(take(length - PGSQL_LENGTH_FIELD), |b| { + let (b, pid) = be_u32(b)?; + let (b, channel_name) = take_until_and_consume(b"\x00")(b)?; + let (b, payload) = take_until_and_consume(b"\x00")(b)?; + Ok((b, (pid, channel_name, payload))) + })(i)?; + let msg = PgsqlBEMessage::NotificationResponse(NotificationResponse { identifier, length, pid: data.0, @@ -1032,30 +1112,28 @@ fn parse_notification_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { pub fn pgsql_parse_response(i: &[u8]) -> IResult<&[u8], PgsqlBEMessage> { let (i, pseudo_header) = peek(tuple((be_u8, be_u32)))(i)?; - let (i, message) = - match pseudo_header.0 { - b'E' => pgsql_parse_error_response(i)?, - b'K' => parse_backend_key_data_message(i)?, - b'N' => pgsql_parse_notice_response(i)?, - b'R' => pgsql_parse_authentication_message(i)?, - b'S' => parse_parameter_status_message(i)?, - b'C' => parse_command_complete(i)?, - b'Z' => parse_ready_for_query(i)?, - b'T' => parse_row_description(i)?, - b'A' => parse_notification_response(i)?, - b'D' => parse_consolidated_data_row(i)?, - // _ => return Err(Err::Error(make_error(i, ErrorKind::Switch))), - _ => { - let (i, payload) = rest(i)?; - let unknown = PgsqlBEMessage::UnknownMessageType (RegularPacket{ - identifier: pseudo_header.0, - length: pseudo_header.1, - payload: payload.to_vec(), - }); - (i, unknown) - } - - }; + let (i, message) = match pseudo_header.0 { + b'E' => pgsql_parse_error_response(i)?, + b'K' => parse_backend_key_data_message(i)?, + b'N' => pgsql_parse_notice_response(i)?, + b'R' => pgsql_parse_authentication_message(i)?, + b'S' => parse_parameter_status_message(i)?, + b'C' => parse_command_complete(i)?, + b'Z' => parse_ready_for_query(i)?, + b'T' => parse_row_description(i)?, + b'A' => parse_notification_response(i)?, + b'D' => parse_consolidated_data_row(i)?, + // _ => return Err(Err::Error(make_error(i, ErrorKind::Switch))), + _ => { + let (i, payload) = rest(i)?; + let unknown = PgsqlBEMessage::UnknownMessageType(RegularPacket { + identifier: pseudo_header.0, + length: pseudo_header.1, + payload: payload.to_vec(), + }); + (i, unknown) + } + }; Ok((i, message)) } @@ -1855,7 +1933,8 @@ mod tests { 0x2b, 0x4a, 0x36, 0x79, 0x78, 0x72, 0x66, 0x77, 0x2f, 0x7a, 0x7a, 0x70, 0x38, 0x59, 0x54, 0x39, 0x65, 0x78, 0x56, 0x37, 0x73, 0x38, 0x3d, ]; - let (remainder, result) = pgsql_parse_response(bad_buf).expect("parsing sasl final response failed"); + let (remainder, result) = + pgsql_parse_response(bad_buf).expect("parsing sasl final response failed"); let res = PgsqlBEMessage::UnknownMessageType(RegularPacket { identifier: b'`', length: 54, @@ -2067,55 +2146,34 @@ mod tests { // S #standard_conforming_strings on S ·TimeZone Europe/Paris // K ···O··Z ·I let buf = &[ - 0x52, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x53, 0x00, 0x00, 0x00, 0x16, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x19, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x00, 0x55, 0x54, 0x46, - 0x38, 0x00, 0x53, 0x00, 0x00, 0x00, 0x17, 0x44, - 0x61, 0x74, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, - 0x00, 0x49, 0x53, 0x4f, 0x2c, 0x20, 0x4d, 0x44, - 0x59, 0x00, 0x53, 0x00, 0x00, 0x00, 0x26, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, - 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 0x66, 0x66, - 0x00, 0x53, 0x00, 0x00, 0x00, 0x17, 0x69, 0x6e, - 0x5f, 0x68, 0x6f, 0x74, 0x5f, 0x73, 0x74, 0x61, - 0x6e, 0x64, 0x62, 0x79, 0x00, 0x6f, 0x66, 0x66, - 0x00, 0x53, 0x00, 0x00, 0x00, 0x19, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x64, 0x61, - 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x00, - 0x6f, 0x6e, 0x00, 0x53, 0x00, 0x00, 0x00, 0x1b, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, - 0x53, 0x74, 0x79, 0x6c, 0x65, 0x00, 0x70, 0x6f, - 0x73, 0x74, 0x67, 0x72, 0x65, 0x73, 0x00, 0x53, - 0x00, 0x00, 0x00, 0x15, 0x69, 0x73, 0x5f, 0x73, - 0x75, 0x70, 0x65, 0x72, 0x75, 0x73, 0x65, 0x72, - 0x00, 0x6f, 0x66, 0x66, 0x00, 0x53, 0x00, 0x00, - 0x00, 0x19, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, - 0x67, 0x00, 0x55, 0x54, 0x46, 0x38, 0x00, 0x53, - 0x00, 0x00, 0x00, 0x18, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x00, 0x31, 0x34, 0x2e, 0x35, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x22, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x00, 0x63, 0x74, 0x66, 0x70, 0x6f, - 0x73, 0x74, 0x00, 0x53, 0x00, 0x00, 0x00, 0x23, - 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, - 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x73, 0x00, 0x6f, 0x6e, 0x00, 0x53, - 0x00, 0x00, 0x00, 0x1a, 0x54, 0x69, 0x6d, 0x65, - 0x5a, 0x6f, 0x6e, 0x65, 0x00, 0x45, 0x75, 0x72, - 0x6f, 0x70, 0x65, 0x2f, 0x50, 0x61, 0x72, 0x69, - 0x73, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x0c, 0x00, - 0x00, 0x0b, 0x8d, 0xcf, 0x4f, 0xb6, 0xcf, 0x5a, - 0x00, 0x00, 0x00, 0x05, 0x49 + 0x52, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x16, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x19, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x55, 0x54, 0x46, + 0x38, 0x00, 0x53, 0x00, 0x00, 0x00, 0x17, 0x44, 0x61, 0x74, 0x65, 0x53, 0x74, 0x79, + 0x6c, 0x65, 0x00, 0x49, 0x53, 0x4f, 0x2c, 0x20, 0x4d, 0x44, 0x59, 0x00, 0x53, 0x00, + 0x00, 0x00, 0x26, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, + 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 0x66, 0x66, 0x00, 0x53, 0x00, 0x00, 0x00, 0x17, + 0x69, 0x6e, 0x5f, 0x68, 0x6f, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, + 0x00, 0x6f, 0x66, 0x66, 0x00, 0x53, 0x00, 0x00, 0x00, 0x19, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x00, + 0x6f, 0x6e, 0x00, 0x53, 0x00, 0x00, 0x00, 0x1b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x00, 0x70, 0x6f, 0x73, 0x74, 0x67, 0x72, + 0x65, 0x73, 0x00, 0x53, 0x00, 0x00, 0x00, 0x15, 0x69, 0x73, 0x5f, 0x73, 0x75, 0x70, + 0x65, 0x72, 0x75, 0x73, 0x65, 0x72, 0x00, 0x6f, 0x66, 0x66, 0x00, 0x53, 0x00, 0x00, + 0x00, 0x19, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, + 0x69, 0x6e, 0x67, 0x00, 0x55, 0x54, 0x46, 0x38, 0x00, 0x53, 0x00, 0x00, 0x00, 0x18, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x00, 0x31, 0x34, 0x2e, 0x35, 0x00, 0x53, 0x00, 0x00, 0x00, 0x22, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x63, 0x74, 0x66, 0x70, 0x6f, 0x73, 0x74, 0x00, 0x53, + 0x00, 0x00, 0x00, 0x23, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x73, 0x00, 0x6f, 0x6e, 0x00, 0x53, 0x00, 0x00, 0x00, 0x1a, 0x54, 0x69, + 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x00, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, + 0x50, 0x61, 0x72, 0x69, 0x73, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0b, + 0x8d, 0xcf, 0x4f, 0xb6, 0xcf, 0x5a, 0x00, 0x00, 0x00, 0x05, 0x49, ]; let result = pgsql_parse_response(buf); diff --git a/rust/src/pgsql/pgsql.rs b/rust/src/pgsql/pgsql.rs index f5fbebc8f950..1ee595371015 100644 --- a/rust/src/pgsql/pgsql.rs +++ b/rust/src/pgsql/pgsql.rs @@ -151,7 +151,7 @@ impl Default for PgsqlState { Self::new() } } - + impl PgsqlState { pub fn new() -> Self { Self { @@ -552,11 +552,10 @@ fn probe_tc(input: &[u8]) -> bool { /// C entry point for a probing parser. #[no_mangle] -pub unsafe extern "C" fn rs_pgsql_probing_parser_ts( +pub unsafe extern fn rs_pgsql_probing_parser_ts( _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { if input_len >= 1 && !input.is_null() { - let slice: &[u8] = build_slice!(input, input_len as usize); if probe_ts(slice) { return ALPROTO_PGSQL; @@ -567,11 +566,10 @@ pub unsafe extern "C" fn rs_pgsql_probing_parser_ts( /// C entry point for a probing parser. #[no_mangle] -pub unsafe extern "C" fn rs_pgsql_probing_parser_tc( +pub unsafe extern fn rs_pgsql_probing_parser_tc( _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { if input_len >= 1 && !input.is_null() { - let slice: &[u8] = build_slice!(input, input_len as usize); if parser::parse_ssl_response(slice).is_ok() { @@ -594,7 +592,7 @@ pub unsafe extern "C" fn rs_pgsql_probing_parser_tc( } #[no_mangle] -pub extern "C" fn rs_pgsql_state_new( +pub extern fn rs_pgsql_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = PgsqlState::new(); @@ -603,13 +601,13 @@ pub extern "C" fn rs_pgsql_state_new( } #[no_mangle] -pub extern "C" fn rs_pgsql_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_pgsql_state_free(state: *mut std::os::raw::c_void) { // Just unbox... std::mem::drop(unsafe { Box::from_raw(state as *mut PgsqlState) }); } #[no_mangle] -pub extern "C" fn rs_pgsql_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub extern fn rs_pgsql_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state_safe: &mut PgsqlState; unsafe { state_safe = cast_pointer!(state, PgsqlState); @@ -618,7 +616,7 @@ pub extern "C" fn rs_pgsql_state_tx_free(state: *mut std::os::raw::c_void, tx_id } #[no_mangle] -pub unsafe extern "C" fn rs_pgsql_parse_request( +pub unsafe extern fn rs_pgsql_parse_request( _flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -631,7 +629,6 @@ pub unsafe extern "C" fn rs_pgsql_parse_request( } } - let state_safe: &mut PgsqlState = cast_pointer!(state, PgsqlState); if stream_slice.is_gap() { @@ -643,7 +640,7 @@ pub unsafe extern "C" fn rs_pgsql_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_pgsql_parse_response( +pub unsafe extern fn rs_pgsql_parse_response( flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -660,7 +657,7 @@ pub unsafe extern "C" fn rs_pgsql_parse_response( } #[no_mangle] -pub unsafe extern "C" fn rs_pgsql_state_get_tx( +pub unsafe extern fn rs_pgsql_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state_safe: &mut PgsqlState = cast_pointer!(state, PgsqlState); @@ -675,7 +672,7 @@ pub unsafe extern "C" fn rs_pgsql_state_get_tx( } #[no_mangle] -pub extern "C" fn rs_pgsql_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub extern fn rs_pgsql_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state_safe: &mut PgsqlState; unsafe { state_safe = cast_pointer!(state, PgsqlState); @@ -684,7 +681,7 @@ pub extern "C" fn rs_pgsql_state_get_tx_count(state: *mut std::os::raw::c_void) } #[no_mangle] -pub extern "C" fn rs_pgsql_tx_get_state(tx: *mut std::os::raw::c_void) -> PgsqlTransactionState { +pub extern fn rs_pgsql_tx_get_state(tx: *mut std::os::raw::c_void) -> PgsqlTransactionState { let tx_safe: &mut PgsqlTransaction; unsafe { tx_safe = cast_pointer!(tx, PgsqlTransaction); @@ -693,7 +690,7 @@ pub extern "C" fn rs_pgsql_tx_get_state(tx: *mut std::os::raw::c_void) -> PgsqlT } #[no_mangle] -pub extern "C" fn rs_pgsql_tx_get_alstate_progress( +pub extern fn rs_pgsql_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { return rs_pgsql_tx_get_state(tx) as i32; @@ -706,7 +703,7 @@ export_state_data_get!(rs_pgsql_get_state_data, PgsqlState); const PARSER_NAME: &[u8] = b"pgsql\0"; #[no_mangle] -pub unsafe extern "C" fn rs_pgsql_register_parser() { +pub unsafe extern fn rs_pgsql_register_parser() { let default_port = CString::new("[5432]").unwrap(); let mut stream_depth = PGSQL_CONFIG_DEFAULT_STREAM_DEPTH; let parser = RustParser { diff --git a/rust/src/quic/detect.rs b/rust/src/quic/detect.rs index 7e9019bef004..bb14900f9bda 100644 --- a/rust/src/quic/detect.rs +++ b/rust/src/quic/detect.rs @@ -19,7 +19,7 @@ use crate::quic::quic::QuicTransaction; use std::ptr; #[no_mangle] -pub unsafe extern "C" fn rs_quic_tx_get_ua( +pub unsafe extern fn rs_quic_tx_get_ua( tx: &QuicTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ua) = &tx.ua { @@ -34,7 +34,7 @@ pub unsafe extern "C" fn rs_quic_tx_get_ua( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_tx_get_sni( +pub unsafe extern fn rs_quic_tx_get_sni( tx: &QuicTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(sni) = &tx.sni { @@ -49,7 +49,7 @@ pub unsafe extern "C" fn rs_quic_tx_get_sni( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_tx_get_ja3( +pub unsafe extern fn rs_quic_tx_get_ja3( tx: &QuicTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ja3) = &tx.ja3 { @@ -64,7 +64,7 @@ pub unsafe extern "C" fn rs_quic_tx_get_ja3( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_tx_get_version( +pub unsafe extern fn rs_quic_tx_get_version( tx: &QuicTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if tx.header.flags.is_long { @@ -80,7 +80,7 @@ pub unsafe extern "C" fn rs_quic_tx_get_version( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_tx_get_cyu_hash( +pub unsafe extern fn rs_quic_tx_get_cyu_hash( tx: &QuicTransaction, i: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if (i as usize) < tx.cyu.len() { @@ -101,7 +101,7 @@ pub unsafe extern "C" fn rs_quic_tx_get_cyu_hash( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_tx_get_cyu_string( +pub unsafe extern fn rs_quic_tx_get_cyu_string( tx: &QuicTransaction, i: u32, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if (i as usize) < tx.cyu.len() { diff --git a/rust/src/quic/frames.rs b/rust/src/quic/frames.rs index e1fb7d080727..97de729bfa2a 100644 --- a/rust/src/quic/frames.rs +++ b/rust/src/quic/frames.rs @@ -504,8 +504,7 @@ impl Frame { let mut d = vec![0; crypto_max_size as usize]; for f in &frames { if let Frame::CryptoFrag(c) = f { - d[c.offset as usize..(c.offset + c.length) as usize] - .clone_from_slice(&c.data); + d[c.offset as usize..(c.offset + c.length) as usize].clone_from_slice(&c.data); } } if let Ok((_, msg)) = parse_tls_message_handshake(&d) { diff --git a/rust/src/quic/logger.rs b/rust/src/quic/logger.rs index 8cb08830e4d0..4370539c765f 100644 --- a/rust/src/quic/logger.rs +++ b/rust/src/quic/logger.rs @@ -149,9 +149,7 @@ fn log_quic(tx: &QuicTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> } #[no_mangle] -pub unsafe extern "C" fn rs_quic_to_json( - tx: *mut std::os::raw::c_void, js: &mut JsonBuilder, -) -> bool { +pub unsafe extern fn rs_quic_to_json(tx: *mut std::os::raw::c_void, js: &mut JsonBuilder) -> bool { let tx = cast_pointer!(tx, QuicTransaction); log_quic(tx, js).is_ok() } diff --git a/rust/src/quic/quic.rs b/rust/src/quic/quic.rs index 8e3ea6f35a21..0303a62163a0 100644 --- a/rust/src/quic/quic.rs +++ b/rust/src/quic/quic.rs @@ -22,7 +22,7 @@ use super::{ parser::{quic_pkt_num, QuicData, QuicHeader, QuicType}, }; use crate::applayer::{self, *}; -use crate::core::{AppProto, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_UDP, Direction}; +use crate::core::{AppProto, Direction, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_UDP}; use std::collections::VecDeque; use std::ffi::CString; use tls_parser::TlsExtensionType; @@ -57,7 +57,11 @@ impl QuicTransaction { header: QuicHeader, data: QuicData, sni: Option>, ua: Option>, extv: Vec, ja3: Option, client: bool, ) -> Self { - let direction = if client { Direction::ToServer } else { Direction::ToClient }; + let direction = if client { + Direction::ToServer + } else { + Direction::ToClient + }; let cyu = Cyu::generate(&header, &data.frames); QuicTransaction { tx_id: 0, @@ -73,7 +77,11 @@ impl QuicTransaction { } fn new_empty(client: bool, header: QuicHeader) -> Self { - let direction = if client { Direction::ToServer } else { Direction::ToClient }; + let direction = if client { + Direction::ToServer + } else { + Direction::ToClient + }; QuicTransaction { tx_id: 0, header, @@ -329,7 +337,7 @@ impl QuicState { } #[no_mangle] -pub extern "C" fn rs_quic_state_new( +pub extern fn rs_quic_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = QuicState::new(); @@ -338,19 +346,19 @@ pub extern "C" fn rs_quic_state_new( } #[no_mangle] -pub extern "C" fn rs_quic_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_quic_state_free(state: *mut std::os::raw::c_void) { // Just unbox... std::mem::drop(unsafe { Box::from_raw(state as *mut QuicState) }); } #[no_mangle] -pub unsafe extern "C" fn rs_quic_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_quic_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, QuicState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_quic_probing_parser( +pub unsafe extern fn rs_quic_probing_parser( _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { let slice = build_slice!(input, input_len as usize); @@ -363,7 +371,7 @@ pub unsafe extern "C" fn rs_quic_probing_parser( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_parse_tc( +pub unsafe extern fn rs_quic_parse_tc( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -378,7 +386,7 @@ pub unsafe extern "C" fn rs_quic_parse_tc( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_parse_ts( +pub unsafe extern fn rs_quic_parse_ts( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -393,7 +401,7 @@ pub unsafe extern "C" fn rs_quic_parse_ts( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_state_get_tx( +pub unsafe extern fn rs_quic_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, QuicState); @@ -408,19 +416,19 @@ pub unsafe extern "C" fn rs_quic_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_quic_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, QuicState); return state.max_tx_id; } #[no_mangle] -pub extern "C" fn rs_quic_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int { +pub extern fn rs_quic_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int { // This parser uses 1 to signal transaction completion status. return 1; } #[no_mangle] -pub unsafe extern "C" fn rs_quic_tx_get_alstate_progress( +pub unsafe extern fn rs_quic_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { let _tx = cast_pointer!(tx, QuicTransaction); @@ -428,7 +436,7 @@ pub unsafe extern "C" fn rs_quic_tx_get_alstate_progress( } #[no_mangle] -pub unsafe extern "C" fn rs_quic_state_get_tx_iterator( +pub unsafe extern fn rs_quic_state_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, ) -> applayer::AppLayerGetTxIterTuple { @@ -452,7 +460,7 @@ export_state_data_get!(rs_quic_get_state_data, QuicState); const PARSER_NAME: &[u8] = b"quic\0"; #[no_mangle] -pub unsafe extern "C" fn rs_quic_register_parser() { +pub unsafe extern fn rs_quic_register_parser() { let default_port = CString::new("[443,80]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, diff --git a/rust/src/rdp/log.rs b/rust/src/rdp/log.rs index e0a71a839b8f..68dd78c6f9db 100644 --- a/rust/src/rdp/log.rs +++ b/rust/src/rdp/log.rs @@ -21,10 +21,10 @@ use super::rdp::{RdpTransaction, RdpTransactionItem}; use crate::jsonbuilder::{JsonBuilder, JsonError}; use crate::rdp::parser::*; use crate::rdp::windows; -use x509_parser::prelude::{X509Certificate, FromDer}; +use x509_parser::prelude::{FromDer, X509Certificate}; #[no_mangle] -pub extern "C" fn rs_rdp_to_json(tx: &mut RdpTransaction, js: &mut JsonBuilder) -> bool { +pub extern fn rs_rdp_to_json(tx: &mut RdpTransaction, js: &mut JsonBuilder) -> bool { log(tx, js).is_ok() } diff --git a/rust/src/rdp/parser.rs b/rust/src/rdp/parser.rs index a8004e290b96..fe4da5b5d9e7 100644 --- a/rust/src/rdp/parser.rs +++ b/rust/src/rdp/parser.rs @@ -480,12 +480,10 @@ fn take_4_4_bits(input: &[u8]) -> IResult<&[u8], (u8, u8), RdpError> { } fn parse_class_options(i: &[u8]) -> IResult<&[u8], (u8, u8)> { - bits( - tuple(( - verify(take_bits(4u8), |&x| x <= 4), - verify(take_bits(4u8), |&x| x <= 3) - )) - )(i) + bits(tuple(( + verify(take_bits(4u8), |&x| x <= 4), + verify(take_bits(4u8), |&x| x <= 3), + )))(i) } /// rdp-spec, section 2.2.1.1 @@ -576,14 +574,19 @@ fn parse_rdp_cookie(i: &[u8]) -> IResult<&[u8], RdpCookie, RdpError> { let (i, _name) = tag(b"mstshash=")(i)?; let (i, bytes) = take_until_and_consume(b"\r\n")(i)?; // let (i, s) = map_res(value!(bytes), std::str::from_utf8)(i)?; - let s = std::str::from_utf8(bytes).map_err(|_| Err::Error(make_error(bytes, ErrorKind::MapRes)))?; - let cookie = RdpCookie{ mstshash: String::from(s) }; + let s = + std::str::from_utf8(bytes).map_err(|_| Err::Error(make_error(bytes, ErrorKind::MapRes)))?; + let cookie = RdpCookie { + mstshash: String::from(s), + }; Ok((i, cookie)) } // rdp-spec, section 2.2.1.1.1 fn parse_negotiation_request(i: &[u8]) -> IResult<&[u8], NegotiationRequest, RdpError> { - let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationRequest as u8)(i)?; + let (i, _typ) = verify(le_u8, |&x| { + x == X224ConnectionRequestType::NegotiationRequest as u8 + })(i)?; let (i, flags) = map_opt(le_u8, NegotiationRequestFlags::from_bits)(i)?; // u8, u8, u16, and u32 give _length of 8 let (i, _length) = verify(le_u16, |&x| x == 8)(i)?; @@ -665,7 +668,9 @@ fn parse_x224_connection_confirm_class_0( // rdp-spec, section 2.2.1.1.1 fn parse_negotiation_response(i: &[u8]) -> IResult<&[u8], NegotiationResponse, RdpError> { - let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationResponse as u8)(i)?; + let (i, _typ) = verify(le_u8, |&x| { + x == X224ConnectionRequestType::NegotiationResponse as u8 + })(i)?; let (i, flags) = map_opt(le_u8, NegotiationResponseFlags::from_bits)(i)?; // u8, u8, u16, and u32 give _length of 8 let (i, _length) = verify(le_u16, |&x| x == 8)(i)?; @@ -675,7 +680,9 @@ fn parse_negotiation_response(i: &[u8]) -> IResult<&[u8], NegotiationResponse, R // rdp-spec, section 2.2.1.1.1 fn parse_negotiation_failure(i: &[u8]) -> IResult<&[u8], NegotiationFailure, RdpError> { - let (i, _typ) = verify(le_u8, |&x| x == X224ConnectionRequestType::NegotiationFailure as u8)(i)?; + let (i, _typ) = verify(le_u8, |&x| { + x == X224ConnectionRequestType::NegotiationFailure as u8 + })(i)?; let (i, _flags) = le_u8(i)?; // u8, u8, u16, and u32 give _length of 8 let (i, _length) = verify(le_u16, |&x| x == 8)(i)?; @@ -686,13 +693,11 @@ fn parse_negotiation_failure(i: &[u8]) -> IResult<&[u8], NegotiationFailure, Rdp /// x224-spec, section 13.7 fn parse_x223_data_class_0(input: &[u8]) -> IResult<&[u8], X223Data, RdpError> { fn parser(i: &[u8]) -> IResult<&[u8], (u8, u8, u8)> { - bits( - tuple(( - verify(take_bits(4u8), |&x| x == 0xf), - verify(take_bits(3u8), |&x| x == 0), - verify(take_bits(1u8), |&x| x == 0) - )) - )(i) + bits(tuple(( + verify(take_bits(4u8), |&x| x == 0xf), + verify(take_bits(3u8), |&x| x == 0), + verify(take_bits(1u8), |&x| x == 0), + )))(i) } let (i1, _length) = verify(be_u8, |&x| x == 2)(input)?; let (i2, _dt_x_roa) = parser(i1).map_err(Err::convert)?; @@ -728,10 +733,9 @@ fn parse_mcs_connect(input: &[u8]) -> IResult<&[u8], McsConnectRequest, RdpError let (i1, _ber_type) = verify( le_u8, // BER: 0b01=application, 0b1=non-primitive, 0b11111 - |&x| x == 0x7f + |&x| x == 0x7f, )(input)?; - let (i2, _t125_type) = verify(le_u8, |&x| x - == T125Type::T125TypeMcsConnectRequest as u8)(i1)?; + let (i2, _t125_type) = verify(le_u8, |&x| x == T125Type::T125TypeMcsConnectRequest as u8)(i1)?; // skip to, and consume, H.221 client-to-server key let (i3, _skipped) = take_until_and_consume(b"Duca")(i2)?; @@ -769,9 +773,7 @@ fn parse_mcs_connect(input: &[u8]) -> IResult<&[u8], McsConnectRequest, RdpError break; } }, - Err(Err::Incomplete(i)) => { - return Err(Err::Incomplete(i)) - } + Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)), Err(Err::Failure(_)) | Err(Err::Error(_)) => break, } } @@ -859,8 +861,7 @@ fn parse_cs_client_core_data(input: &[u8]) -> IResult<&[u8], CsClientCoreData> { let (j18, early_capability_flags) = match supported_color_depth { None => (j17, None), Some(_) => { - match opt(map_opt(le_u16, EarlyCapabilityFlags::from_bits))(j17) as IResult<&[u8], _> - { + match opt(map_opt(le_u16, EarlyCapabilityFlags::from_bits))(j17) as IResult<&[u8], _> { Ok((rem, obj)) => (rem, obj), _ => (j17, None), } @@ -897,12 +898,10 @@ fn parse_cs_client_core_data(input: &[u8]) -> IResult<&[u8], CsClientCoreData> { let (j22, server_selected_protocol) = match pad { None => (j21, None), - Some(_) => { - match opt(map_opt(le_u32, ProtocolFlags::from_bits))(j21) as IResult<&[u8], _> { - Ok((rem, obj)) => (rem, obj), - _ => (j21, None), - } - } + Some(_) => match opt(map_opt(le_u32, ProtocolFlags::from_bits))(j21) as IResult<&[u8], _> { + Ok((rem, obj)) => (rem, obj), + _ => (j21, None), + }, }; let (j23, desktop_physical_width) = match server_selected_protocol { @@ -1017,7 +1016,13 @@ fn parse_cs_unknown(i: &[u8]) -> IResult<&[u8], CsUnknown> { // less u16, u16 let (i, sz) = map_opt(le_u16, |x: u16| x.checked_sub(4))(i)?; let (i, data) = take(sz)(i)?; - Ok((i, CsUnknown { typ, data: data.to_vec() })) + Ok(( + i, + CsUnknown { + typ, + data: data.to_vec(), + }, + )) } // rdp-spec, section 2.2.1.4 @@ -1025,7 +1030,8 @@ fn parse_mcs_connect_response(i: &[u8]) -> IResult<&[u8], McsConnectResponse, Rd let (i, _ber_type) = verify( le_u8, // BER: 0b01=application, 0b1=non-primitive, 0b11111 - |&x| x == 0x7f)(i)?; + |&x| x == 0x7f, + )(i)?; let (i, _t125_type) = verify(le_u8, |&x| x == T125Type::T125TypeMcsConnectResponse as u8)(i)?; Ok((i, McsConnectResponse {})) } @@ -1090,7 +1096,9 @@ mod tests_negotiate_49350 { cookie: None, negotiation_request: Some(NegotiationRequest { flags: NegotiationRequestFlags::empty(), - protocols: ProtocolFlags { bits: Protocol::ProtocolRdp as u32 }, + protocols: ProtocolFlags { + bits: Protocol::ProtocolRdp as u32, + }, }), data: Vec::new(), }), @@ -1180,7 +1188,9 @@ mod tests_core_49350 { ), client_dig_product_id: Some(String::from("")), connection_hint: Some(ConnectionHint::ConnectionHintNotProvided), - server_selected_protocol: Some(ProtocolFlags { bits: Protocol::ProtocolRdp as u32 }), + server_selected_protocol: Some(ProtocolFlags { + bits: Protocol::ProtocolRdp as u32, + }), desktop_physical_width: None, desktop_physical_height: None, desktop_orientation: None, @@ -1351,7 +1361,7 @@ mod tests_negotiate_incomplete_49350 { assert_eq!( // fails: expr_opt!(i5, length.checked_sub(6))? // not counting a u8 length read, which was also successful - Err(Err::Incomplete(Needed::new( 1))), + Err(Err::Incomplete(Needed::new(1))), parse_x224_connection_request_class_0(x224_bytes) ) } diff --git a/rust/src/rdp/rdp.rs b/rust/src/rdp/rdp.rs index f08026a82db8..ffb79ac4d814 100644 --- a/rust/src/rdp/rdp.rs +++ b/rust/src/rdp/rdp.rs @@ -72,7 +72,7 @@ impl RdpTransaction { } #[no_mangle] -pub unsafe extern "C" fn rs_rdp_state_get_tx( +pub unsafe extern fn rs_rdp_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, RdpState); @@ -87,13 +87,13 @@ pub unsafe extern "C" fn rs_rdp_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_rdp_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_rdp_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, RdpState); return state.next_id; } #[no_mangle] -pub extern "C" fn rs_rdp_tx_get_progress( +pub extern fn rs_rdp_tx_get_progress( _tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { // tx complete when `rs_rdp_tx_get_progress(...) == rs_rdp_tx_get_progress_complete(...)` @@ -375,19 +375,21 @@ impl RdpState { } #[no_mangle] -pub extern "C" fn rs_rdp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_rdp_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = RdpState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub extern "C" fn rs_rdp_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_rdp_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(unsafe { Box::from_raw(state as *mut RdpState) }); } #[no_mangle] -pub unsafe extern "C" fn rs_rdp_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_rdp_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, RdpState); state.free_tx(tx_id); } @@ -403,7 +405,7 @@ fn probe_rdp(input: &[u8]) -> bool { /// probe for T.123 message, whether to client or to server #[no_mangle] -pub unsafe extern "C" fn rs_rdp_probe_ts_tc( +pub unsafe extern fn rs_rdp_probe_ts_tc( _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { if !input.is_null() { @@ -430,10 +432,9 @@ fn probe_tls_handshake(input: &[u8]) -> bool { // #[no_mangle] -pub unsafe extern "C" fn rs_rdp_parse_ts( +pub unsafe extern fn rs_rdp_parse_ts( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, RdpState); let buf = stream_slice.as_slice(); @@ -442,10 +443,9 @@ pub unsafe extern "C" fn rs_rdp_parse_ts( } #[no_mangle] -pub unsafe extern "C" fn rs_rdp_parse_tc( +pub unsafe extern fn rs_rdp_parse_tc( _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, RdpState); let buf = stream_slice.as_slice(); @@ -463,7 +463,7 @@ export_state_data_get!(rs_rdp_get_state_data, RdpState); const PARSER_NAME: &[u8] = b"rdp\0"; #[no_mangle] -pub unsafe extern "C" fn rs_rdp_register_parser() { +pub unsafe extern fn rs_rdp_register_parser() { let default_port = std::ffi::CString::new("[3389]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, diff --git a/rust/src/rfb/detect.rs b/rust/src/rfb/detect.rs index 1cf0887c4fda..23ba912f6bba 100644 --- a/rust/src/rfb/detect.rs +++ b/rust/src/rfb/detect.rs @@ -21,7 +21,7 @@ use crate::rfb::rfb::*; use std::ptr; #[no_mangle] -pub unsafe extern "C" fn rs_rfb_tx_get_name( +pub unsafe extern fn rs_rfb_tx_get_name( tx: &mut RFBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref r) = tx.tc_server_init { @@ -40,7 +40,7 @@ pub unsafe extern "C" fn rs_rfb_tx_get_name( } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_tx_get_sectype(tx: &mut RFBTransaction, sectype: *mut u32) -> u8 { +pub unsafe extern fn rs_rfb_tx_get_sectype(tx: &mut RFBTransaction, sectype: *mut u32) -> u8 { if let Some(ref r) = tx.chosen_security_type { *sectype = *r; return 1; @@ -52,9 +52,7 @@ pub unsafe extern "C" fn rs_rfb_tx_get_sectype(tx: &mut RFBTransaction, sectype: } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_tx_get_secresult( - tx: &mut RFBTransaction, secresult: *mut u32, -) -> u8 { +pub unsafe extern fn rs_rfb_tx_get_secresult(tx: &mut RFBTransaction, secresult: *mut u32) -> u8 { if let Some(ref r) = tx.tc_security_result { *secresult = r.status; return 1; diff --git a/rust/src/rfb/logger.rs b/rust/src/rfb/logger.rs index 62bb20966fe7..02fa61c52d31 100644 --- a/rust/src/rfb/logger.rs +++ b/rust/src/rfb/logger.rs @@ -127,7 +127,7 @@ fn log_rfb(tx: &RFBTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_logger_log( +pub unsafe extern fn rs_rfb_logger_log( tx: *mut std::os::raw::c_void, js: &mut JsonBuilder, ) -> bool { let tx = cast_pointer!(tx, RFBTransaction); diff --git a/rust/src/rfb/rfb.rs b/rust/src/rfb/rfb.rs index 8c3381345012..f81096e901b5 100644 --- a/rust/src/rfb/rfb.rs +++ b/rust/src/rfb/rfb.rs @@ -744,7 +744,7 @@ impl RFBState { // C exports. #[no_mangle] -pub extern "C" fn rs_rfb_state_new( +pub extern fn rs_rfb_state_new( _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, ) -> *mut std::os::raw::c_void { let state = RFBState::new(); @@ -753,19 +753,19 @@ pub extern "C" fn rs_rfb_state_new( } #[no_mangle] -pub extern "C" fn rs_rfb_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_rfb_state_free(state: *mut std::os::raw::c_void) { // Just unbox... std::mem::drop(unsafe { Box::from_raw(state as *mut RFBState) }); } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_rfb_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, RFBState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_parse_request( +pub unsafe extern fn rs_rfb_parse_request( flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -774,7 +774,7 @@ pub unsafe extern "C" fn rs_rfb_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_parse_response( +pub unsafe extern fn rs_rfb_parse_response( flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { @@ -783,7 +783,7 @@ pub unsafe extern "C" fn rs_rfb_parse_response( } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_state_get_tx( +pub unsafe extern fn rs_rfb_state_get_tx( state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, RFBState); @@ -798,13 +798,13 @@ pub unsafe extern "C" fn rs_rfb_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_rfb_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, RFBState); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_tx_get_alstate_progress( +pub unsafe extern fn rs_rfb_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, RFBTransaction); @@ -821,7 +821,7 @@ export_tx_data_get!(rs_rfb_get_tx_data, RFBTransaction); export_state_data_get!(rs_rfb_get_state_data, RFBState); #[no_mangle] -pub unsafe extern "C" fn rs_rfb_register_parser() { +pub unsafe extern fn rs_rfb_register_parser() { let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, default_port: std::ptr::null(), diff --git a/rust/src/sip/detect.rs b/rust/src/sip/detect.rs index 63f636529a34..94d623af72de 100644 --- a/rust/src/sip/detect.rs +++ b/rust/src/sip/detect.rs @@ -22,10 +22,8 @@ use crate::sip::sip::SIPTransaction; use std::ptr; #[no_mangle] -pub unsafe extern "C" fn rs_sip_tx_get_method( - tx: &mut SIPTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32, +pub unsafe extern fn rs_sip_tx_get_method( + tx: &mut SIPTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref r) = tx.request { let m = &r.method; @@ -43,10 +41,8 @@ pub unsafe extern "C" fn rs_sip_tx_get_method( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_tx_get_uri( - tx: &mut SIPTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32, +pub unsafe extern fn rs_sip_tx_get_uri( + tx: &mut SIPTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref r) = tx.request { let p = &r.path; @@ -64,11 +60,8 @@ pub unsafe extern "C" fn rs_sip_tx_get_uri( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_tx_get_protocol( - tx: &mut SIPTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32, - direction: u8, +pub unsafe extern fn rs_sip_tx_get_protocol( + tx: &mut SIPTransaction, buffer: *mut *const u8, buffer_len: *mut u32, direction: u8, ) -> u8 { match direction.into() { Direction::ToServer => { @@ -100,10 +93,8 @@ pub unsafe extern "C" fn rs_sip_tx_get_protocol( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_tx_get_stat_code( - tx: &mut SIPTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32, +pub unsafe extern fn rs_sip_tx_get_stat_code( + tx: &mut SIPTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref r) = tx.response { let c = &r.code; @@ -121,10 +112,8 @@ pub unsafe extern "C" fn rs_sip_tx_get_stat_code( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_tx_get_stat_msg( - tx: &mut SIPTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32, +pub unsafe extern fn rs_sip_tx_get_stat_msg( + tx: &mut SIPTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref r) = tx.response { let re = &r.reason; @@ -142,10 +131,8 @@ pub unsafe extern "C" fn rs_sip_tx_get_stat_msg( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_tx_get_request_line( - tx: &mut SIPTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32, +pub unsafe extern fn rs_sip_tx_get_request_line( + tx: &mut SIPTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref r) = tx.request_line { if !r.is_empty() { @@ -162,10 +149,8 @@ pub unsafe extern "C" fn rs_sip_tx_get_request_line( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_tx_get_response_line( - tx: &mut SIPTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32, +pub unsafe extern fn rs_sip_tx_get_response_line( + tx: &mut SIPTransaction, buffer: *mut *const u8, buffer_len: *mut u32, ) -> u8 { if let Some(ref r) = tx.response_line { if !r.is_empty() { diff --git a/rust/src/sip/log.rs b/rust/src/sip/log.rs index 792acfa49021..3f2afe334db2 100644 --- a/rust/src/sip/log.rs +++ b/rust/src/sip/log.rs @@ -49,6 +49,6 @@ fn log(tx: &SIPTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { } #[no_mangle] -pub extern "C" fn rs_sip_log_json(tx: &mut SIPTransaction, js: &mut JsonBuilder) -> bool { +pub extern fn rs_sip_log_json(tx: &mut SIPTransaction, js: &mut JsonBuilder) -> bool { log(tx, js).is_ok() -} \ No newline at end of file +} diff --git a/rust/src/sip/sip.rs b/rust/src/sip/sip.rs index 4e86f5ea476d..d4a49b964d7b 100755 --- a/rust/src/sip/sip.rs +++ b/rust/src/sip/sip.rs @@ -17,10 +17,10 @@ // written by Giuseppe Longo -use crate::frames::*; use crate::applayer::{self, *}; use crate::core; use crate::core::{AppProto, Flow, ALPROTO_UNKNOWN}; +use crate::frames::*; use crate::sip::parser::*; use nom7::Err; use std; @@ -96,10 +96,7 @@ impl SIPState { } fn free_tx(&mut self, tx_id: u64) { - let tx = self - .transactions - .iter() - .position(|tx| tx.id == tx_id + 1); + let tx = self.transactions.iter().position(|tx| tx.id == tx_id + 1); debug_assert!(tx.is_some()); if let Some(idx) = tx { let _ = self.transactions.remove(idx); @@ -149,7 +146,13 @@ impl SIPState { fn parse_response(&mut self, flow: *const core::Flow, stream_slice: StreamSlice) -> bool { let input = stream_slice.as_slice(); - let _pdu = Frame::new(flow, &stream_slice, input, input.len() as i64, SIPFrameType::Pdu as u8); + let _pdu = Frame::new( + flow, + &stream_slice, + input, + input.len() as i64, + SIPFrameType::Pdu as u8, + ); SCLogDebug!("tc: pdu {:?}", _pdu); match sip_parse_response(input) { @@ -224,35 +227,54 @@ fn sip_frames_ts(flow: *const core::Flow, stream_slice: &StreamSlice, r: &Reques fn sip_frames_tc(flow: *const core::Flow, stream_slice: &StreamSlice, r: &Response) { let oi = stream_slice.as_slice(); - let _f = Frame::new(flow, stream_slice, oi, r.response_line_len as i64, SIPFrameType::ResponseLine as u8); - let hi = &oi[r.response_line_len as usize ..]; + let _f = Frame::new( + flow, + stream_slice, + oi, + r.response_line_len as i64, + SIPFrameType::ResponseLine as u8, + ); + let hi = &oi[r.response_line_len as usize..]; SCLogDebug!("tc: response_line {:?}", _f); - let _f = Frame::new(flow, stream_slice, hi, r.headers_len as i64, SIPFrameType::ResponseHeaders as u8); + let _f = Frame::new( + flow, + stream_slice, + hi, + r.headers_len as i64, + SIPFrameType::ResponseHeaders as u8, + ); SCLogDebug!("tc: response_headers {:?}", _f); if r.body_len > 0 { - let bi = &oi[r.body_offset as usize ..]; - let _f = Frame::new(flow, stream_slice, bi, r.body_len as i64, SIPFrameType::ResponseBody as u8); + let bi = &oi[r.body_offset as usize..]; + let _f = Frame::new( + flow, + stream_slice, + bi, + r.body_len as i64, + SIPFrameType::ResponseBody as u8, + ); SCLogDebug!("tc: response_body {:?}", _f); } } #[no_mangle] -pub extern "C" fn rs_sip_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_sip_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = SIPState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub extern "C" fn rs_sip_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_sip_state_free(state: *mut std::os::raw::c_void) { let mut state = unsafe { Box::from_raw(state as *mut SIPState) }; state.free(); } #[no_mangle] -pub unsafe extern "C" fn rs_sip_state_get_tx( - state: *mut std::os::raw::c_void, - tx_id: u64, +pub unsafe extern fn rs_sip_state_get_tx( + state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, SIPState); match state.get_tx_by_id(tx_id) { @@ -262,21 +284,20 @@ pub unsafe extern "C" fn rs_sip_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { +pub unsafe extern fn rs_sip_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, SIPState); state.tx_id } #[no_mangle] -pub unsafe extern "C" fn rs_sip_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { +pub unsafe extern fn rs_sip_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, SIPState); state.free_tx(tx_id); } #[no_mangle] -pub extern "C" fn rs_sip_tx_get_alstate_progress( - _tx: *mut std::os::raw::c_void, - _direction: u8, +pub extern fn rs_sip_tx_get_alstate_progress( + _tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { 1 } @@ -284,12 +305,8 @@ pub extern "C" fn rs_sip_tx_get_alstate_progress( static mut ALPROTO_SIP: AppProto = ALPROTO_UNKNOWN; #[no_mangle] -pub unsafe extern "C" fn rs_sip_probing_parser_ts( - _flow: *const Flow, - _direction: u8, - input: *const u8, - input_len: u32, - _rdir: *mut u8, +pub unsafe extern fn rs_sip_probing_parser_ts( + _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { let buf = build_slice!(input, input_len as usize); if sip_parse_request(buf).is_ok() { @@ -299,12 +316,8 @@ pub unsafe extern "C" fn rs_sip_probing_parser_ts( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_probing_parser_tc( - _flow: *const Flow, - _direction: u8, - input: *const u8, - input_len: u32, - _rdir: *mut u8, +pub unsafe extern fn rs_sip_probing_parser_tc( + _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { let buf = build_slice!(input, input_len as usize); if sip_parse_response(buf).is_ok() { @@ -314,24 +327,18 @@ pub unsafe extern "C" fn rs_sip_probing_parser_tc( } #[no_mangle] -pub unsafe extern "C" fn rs_sip_parse_request( - flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, +pub unsafe extern fn rs_sip_parse_request( + flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, SIPState); state.parse_request(flow, stream_slice).into() } #[no_mangle] -pub unsafe extern "C" fn rs_sip_parse_response( - flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, +pub unsafe extern fn rs_sip_parse_response( + flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, SIPState); state.parse_response(flow, stream_slice).into() @@ -343,7 +350,7 @@ export_state_data_get!(rs_sip_get_state_data, SIPState); const PARSER_NAME: &[u8] = b"sip\0"; #[no_mangle] -pub unsafe extern "C" fn rs_sip_register_parser() { +pub unsafe extern fn rs_sip_register_parser() { let default_port = CString::new("[5060,5061]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, diff --git a/rust/src/smb/auth.rs b/rust/src/smb/auth.rs index c5d20bba6e29..6d66547caafc 100644 --- a/rust/src/smb/auth.rs +++ b/rust/src/smb/auth.rs @@ -20,16 +20,17 @@ use crate::kerberos::*; use crate::smb::ntlmssp_records::*; use crate::smb::smb::*; -use nom7::{Err, IResult}; use der_parser6::ber::BerObjectContent; use der_parser6::der::{parse_der_oid, parse_der_sequence}; +use nom7::{Err, IResult}; -fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> -{ +fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> { let (rem, base_o) = der_parser6::parse_der(blob).map_err(Err::convert)?; SCLogDebug!("parse_secblob_get_spnego: base_o {:?}", base_o); let d = match base_o.content.as_slice() { - Err(_) => { return Err(Err::Error(SecBlobError::NotSpNego)); }, + Err(_) => { + return Err(Err::Error(SecBlobError::NotSpNego)); + } Ok(d) => d, }; let (next, o) = parse_der_oid(d).map_err(Err::convert)?; @@ -39,17 +40,17 @@ fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> Ok(oid) => oid, Err(_) => { return Err(Err::Error(SecBlobError::NotSpNego)); - }, + } }; SCLogDebug!("oid {}", oid.to_string()); match oid.to_string().as_str() { "1.3.6.1.5.5.2" => { SCLogDebug!("SPNEGO {}", oid); - }, + } _ => { return Err(Err::Error(SecBlobError::NotSpNego)); - }, + } } SCLogDebug!("parse_secblob_get_spnego: next {:?}", next); @@ -57,17 +58,16 @@ fn parse_secblob_get_spnego(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> Ok((rem, next)) } -fn parse_secblob_spnego_start(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> -{ +fn parse_secblob_spnego_start(blob: &[u8]) -> IResult<&[u8], &[u8], SecBlobError> { let (rem, o) = der_parser6::parse_der(blob).map_err(Err::convert)?; let d = match o.content.as_slice() { Ok(d) => { - SCLogDebug!("d: next data len {}",d.len()); + SCLogDebug!("d: next data len {}", d.len()); d - }, + } _ => { return Err(Err::Error(SecBlobError::NotSpNego)); - }, + } }; Ok((rem, d)) } @@ -78,27 +78,32 @@ pub struct SpnegoRequest { pub ntlmssp: Option, } -fn parse_secblob_spnego(blob: &[u8]) -> Option -{ +fn parse_secblob_spnego(blob: &[u8]) -> Option { let mut have_ntlmssp = false; let mut have_kerberos = false; - let mut kticket : Option = None; - let mut ntlmssp : Option = None; + let mut kticket: Option = None; + let mut ntlmssp: Option = None; let o = match parse_der_sequence(blob) { Ok((_, o)) => o, - _ => { return None; }, + _ => { + return None; + } }; for s in o { SCLogDebug!("s {:?}", s); let n = match s.content.as_slice() { Ok(s) => s, - _ => { continue; }, + _ => { + continue; + } }; let o = match der_parser6::parse_der(n) { - Ok((_,x)) => x, - _ => { continue; }, + Ok((_, x)) => x, + _ => { + continue; + } }; SCLogDebug!("o {:?}", o); match o.content { @@ -109,20 +114,40 @@ fn parse_secblob_spnego(blob: &[u8]) -> Option BerObjectContent::OID(ref oid) => { SCLogDebug!("OID {:?}", oid); match oid.to_string().as_str() { - "1.2.840.48018.1.2.2" => { SCLogDebug!("Microsoft Kerberos 5"); }, - "1.2.840.113554.1.2.2" => { SCLogDebug!("Kerberos 5"); have_kerberos = true; }, - "1.2.840.113554.1.2.2.1" => { SCLogDebug!("krb5-name"); }, - "1.2.840.113554.1.2.2.2" => { SCLogDebug!("krb5-principal"); }, - "1.2.840.113554.1.2.2.3" => { SCLogDebug!("krb5-user-to-user-mech"); }, - "1.3.6.1.4.1.311.2.2.10" => { SCLogDebug!("NTLMSSP"); have_ntlmssp = true; }, - "1.3.6.1.4.1.311.2.2.30" => { SCLogDebug!("NegoEx"); }, - _ => { SCLogDebug!("unexpected OID {:?}", oid); }, + "1.2.840.48018.1.2.2" => { + SCLogDebug!("Microsoft Kerberos 5"); + } + "1.2.840.113554.1.2.2" => { + SCLogDebug!("Kerberos 5"); + have_kerberos = true; + } + "1.2.840.113554.1.2.2.1" => { + SCLogDebug!("krb5-name"); + } + "1.2.840.113554.1.2.2.2" => { + SCLogDebug!("krb5-principal"); + } + "1.2.840.113554.1.2.2.3" => { + SCLogDebug!("krb5-user-to-user-mech"); + } + "1.3.6.1.4.1.311.2.2.10" => { + SCLogDebug!("NTLMSSP"); + have_ntlmssp = true; + } + "1.3.6.1.4.1.311.2.2.30" => { + SCLogDebug!("NegoEx"); + } + _ => { + SCLogDebug!("unexpected OID {:?}", oid); + } } - }, - _ => { SCLogDebug!("expected OID, got {:?}", se); }, + } + _ => { + SCLogDebug!("expected OID, got {:?}", se); + } } } - }, + } BerObjectContent::OctetString(os) => { if have_kerberos { if let Ok((_, t)) = parse_kerberos5_request(os) { @@ -134,8 +159,8 @@ fn parse_secblob_spnego(blob: &[u8]) -> Option SCLogDebug!("parsing expected NTLMSSP"); ntlmssp = parse_ntlmssp_blob(os); } - }, - _ => {}, + } + _ => {} } } @@ -146,7 +171,7 @@ fn parse_secblob_spnego(blob: &[u8]) -> Option Some(s) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct NtlmsspData { pub host: Vec, pub user: Vec, @@ -156,27 +181,29 @@ pub struct NtlmsspData { } /// take in blob, search for the header and parse it -fn parse_ntlmssp_blob(blob: &[u8]) -> Option -{ - let mut ntlmssp_data : Option = None; +fn parse_ntlmssp_blob(blob: &[u8]) -> Option { + let mut ntlmssp_data: Option = None; SCLogDebug!("NTLMSSP {:?}", blob); if let Ok((_, nd)) = parse_ntlmssp(blob) { - SCLogDebug!("NTLMSSP TYPE {}/{} nd {:?}", - nd.msg_type, &ntlmssp_type_string(nd.msg_type), nd); + SCLogDebug!( + "NTLMSSP TYPE {}/{} nd {:?}", + nd.msg_type, + &ntlmssp_type_string(nd.msg_type), + nd + ); match nd.msg_type { - NTLMSSP_NEGOTIATE => { - }, + NTLMSSP_NEGOTIATE => {} NTLMSSP_AUTH => { if let Ok((_, ad)) = parse_ntlm_auth_record(nd.data) { SCLogDebug!("auth data {:?}", ad); let mut host = ad.host.to_vec(); - host.retain(|&i|i != 0x00); + host.retain(|&i| i != 0x00); let mut user = ad.user.to_vec(); - user.retain(|&i|i != 0x00); + user.retain(|&i| i != 0x00); let mut domain = ad.domain.to_vec(); - domain.retain(|&i|i != 0x00); - + domain.retain(|&i| i != 0x00); + let d = NtlmsspData { host, user, @@ -186,47 +213,38 @@ fn parse_ntlmssp_blob(blob: &[u8]) -> Option }; ntlmssp_data = Some(d); } - }, - _ => {}, + } + _ => {} } } return ntlmssp_data; } // if spnego parsing fails try to fall back to ntlmssp -pub fn parse_secblob(blob: &[u8]) -> Option -{ +pub fn parse_secblob(blob: &[u8]) -> Option { match parse_secblob_get_spnego(blob) { - Ok((_, spnego)) => { - match parse_secblob_spnego_start(spnego) { - Ok((_, spnego_start)) => { - parse_secblob_spnego(spnego_start) - }, - _ => { - match parse_ntlmssp_blob(blob) { - Some(n) => { - let s = SpnegoRequest { - krb: None, - ntlmssp: Some(n), - }; - Some(s) - }, - None => { None }, - } - }, - } - }, - _ => { - match parse_ntlmssp_blob(blob) { + Ok((_, spnego)) => match parse_secblob_spnego_start(spnego) { + Ok((_, spnego_start)) => parse_secblob_spnego(spnego_start), + _ => match parse_ntlmssp_blob(blob) { Some(n) => { let s = SpnegoRequest { krb: None, - ntlmssp: Some(n), + ntlmssp: Some(n), }; Some(s) - }, - None => { None }, + } + None => None, + }, + }, + _ => match parse_ntlmssp_blob(blob) { + Some(n) => { + let s = SpnegoRequest { + krb: None, + ntlmssp: Some(n), + }; + Some(s) } + None => None, }, } } diff --git a/rust/src/smb/dcerpc.rs b/rust/src/smb/dcerpc.rs index b4c5749eac46..ec911c6fcd54 100644 --- a/rust/src/smb/dcerpc.rs +++ b/rust/src/smb/dcerpc.rs @@ -17,13 +17,13 @@ // written by Victor Julien -use uuid; -use crate::smb::smb::*; -use crate::smb::smb2::*; +use crate::dcerpc::dcerpc::*; use crate::smb::dcerpc_records::*; use crate::smb::events::*; -use crate::dcerpc::dcerpc::*; +use crate::smb::smb::*; +use crate::smb::smb2::*; use crate::smb::smb_status::*; +use uuid; impl SMBCommonHdr { /// helper for DCERPC tx tracking. Check if we need @@ -37,21 +37,21 @@ impl SMBCommonHdr { 2 => { let (_, cmd2) = vercmd.get_smb2_cmd(); let x = match cmd2 { - SMB2_COMMAND_READ => { 0 }, - SMB2_COMMAND_WRITE => { 0 }, - SMB2_COMMAND_IOCTL => { self.msg_id }, - _ => { self.msg_id }, + SMB2_COMMAND_READ => 0, + SMB2_COMMAND_WRITE => 0, + SMB2_COMMAND_IOCTL => self.msg_id, + _ => self.msg_id, }; use_msg_id = x; - }, + } 1 => { SCLogDebug!("FIXME TODO"); //let (_, cmd1) = vercmd.get_smb1_cmd(); //if cmd1 != SMB1_COMMAND_IOCTL { use_msg_id = 0; //} - }, - _ => { }, + } + _ => {} } SMBCommonHdr { ssn_id: self.ssn_id, @@ -108,10 +108,10 @@ impl SMBTransactionDCERPC { req_set: true, call_id, ..Default::default() - } + }; } fn new_response(call_id: u32) -> Self { - return Self { + return Self { call_id, ..Default::default() }; @@ -123,14 +123,15 @@ impl SMBTransactionDCERPC { } impl SMBState { - fn new_dcerpc_tx(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32) - -> &mut SMBTransaction - { + fn new_dcerpc_tx( + &mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( - SMBTransactionDCERPC::new_request(cmd, call_id))); + SMBTransactionDCERPC::new_request(cmd, call_id), + )); SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); self.transactions.push_back(tx); @@ -138,14 +139,15 @@ impl SMBState { return tx_ref.unwrap(); } - fn new_dcerpc_tx_for_response(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, call_id: u32) - -> &mut SMBTransaction - { + fn new_dcerpc_tx_for_response( + &mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, call_id: u32, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( - SMBTransactionDCERPC::new_response(call_id))); + SMBTransactionDCERPC::new_response(call_id), + )); SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); self.transactions.push_back(tx); @@ -153,20 +155,18 @@ impl SMBState { return tx_ref.unwrap(); } - fn get_dcerpc_tx(&mut self, hdr: &SMBCommonHdr, vercmd: &SMBVerCmdStat, call_id: u32) - -> Option<&mut SMBTransaction> - { + fn get_dcerpc_tx( + &mut self, hdr: &SMBCommonHdr, vercmd: &SMBVerCmdStat, call_id: u32, + ) -> Option<&mut SMBTransaction> { let dce_hdr = hdr.to_dcerpc(vercmd); SCLogDebug!("looking for {:?}", dce_hdr); for tx in &mut self.transactions { - let found = dce_hdr.compare(&tx.hdr.to_dcerpc(vercmd)) && - match tx.type_data { - Some(SMBTransactionTypeData::DCERPC(ref x)) => { - x.call_id == call_id - }, - _ => { false }, - }; + let found = dce_hdr.compare(&tx.hdr.to_dcerpc(vercmd)) + && match tx.type_data { + Some(SMBTransactionTypeData::DCERPC(ref x)) => x.call_id == call_id, + _ => false, + }; if found { return Some(tx); } @@ -178,19 +178,22 @@ impl SMBState { /// Handle DCERPC request data from a WRITE, IOCTL or TRANS record. /// return bool indicating whether an tx has been created/updated. /// -pub fn smb_write_dcerpc_record(state: &mut SMBState, - vercmd: SMBVerCmdStat, - hdr: SMBCommonHdr, - data: &[u8]) -> bool -{ - let mut bind_ifaces : Option> = None; +pub fn smb_write_dcerpc_record( + state: &mut SMBState, vercmd: SMBVerCmdStat, hdr: SMBCommonHdr, data: &[u8], +) -> bool { + let mut bind_ifaces: Option> = None; let mut is_bind = false; SCLogDebug!("called for {} bytes of data", data.len()); match parse_dcerpc_record(data) { Ok((_, dcer)) => { - SCLogDebug!("DCERPC: version {}.{} write data {} => {:?}", - dcer.version_major, dcer.version_minor, dcer.data.len(), dcer); + SCLogDebug!( + "DCERPC: version {}.{} write data {} => {:?}", + dcer.version_major, + dcer.version_minor, + dcer.data.len(), + dcer + ); /* if this isn't the first frag, simply update the existing * tx with the additional stub data */ @@ -200,9 +203,15 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, Ok((_, recr)) => { let found = match state.get_dcerpc_tx(&hdr, &vercmd, dcer.call_id) { Some(tx) => { - SCLogDebug!("previous CMD {} found at tx {} => {:?}", - dcer.packet_type, tx.id, tx); - if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { + SCLogDebug!( + "previous CMD {} found at tx {} => {:?}", + dcer.packet_type, + tx.id, + tx + ); + if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = + tx.type_data + { SCLogDebug!("additional frag of size {}", recr.data.len()); tdn.stub_data_ts.extend_from_slice(recr.data); tdn.frag_cnt_ts += 1; @@ -212,51 +221,60 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, SCLogDebug!("last frag set, so request side of DCERPC closed"); tx.request_done = true; } else { - SCLogDebug!("NOT last frag, so request side of DCERPC remains open"); + SCLogDebug!( + "NOT last frag, so request side of DCERPC remains open" + ); } true - }, + } None => { SCLogDebug!("NO previous CMD {} found", dcer.packet_type); false - }, + } }; return found; - }, + } _ => { state.set_event(SMBEvent::MalformedData); return false; - }, + } } } let tx = state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id); match dcer.packet_type { DCERPC_TYPE_REQUEST => { - match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) { + match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) + { Ok((_, recr)) => { SCLogDebug!("DCERPC: REQUEST {:?}", recr); - if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data + { SCLogDebug!("first frag size {}", recr.data.len()); tdn.stub_data_ts.extend_from_slice(recr.data); tdn.opnum = recr.opnum; tdn.context_id = recr.context_id; tdn.frag_cnt_ts += 1; - SCLogDebug!("DCERPC: REQUEST opnum {} stub data len {}", - tdn.opnum, tdn.stub_data_ts.len()); + SCLogDebug!( + "DCERPC: REQUEST opnum {} stub data len {}", + tdn.opnum, + tdn.stub_data_ts.len() + ); } if dcer.last_frag { tx.request_done = true; } else { - SCLogDebug!("NOT last frag, so request side of DCERPC remains open"); + SCLogDebug!( + "NOT last frag, so request side of DCERPC remains open" + ); } - }, + } _ => { tx.set_event(SMBEvent::MalformedData); tx.request_done = true; - }, + } } - }, + } DCERPC_TYPE_BIND => { let brec = if dcer.little_endian { parse_dcerpc_bind_record(dcer.data) @@ -272,43 +290,63 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, let mut ifaces: Vec = Vec::new(); for i in bindr.ifaces { let x = if dcer.little_endian { - vec![i.iface[3], i.iface[2], i.iface[1], i.iface[0], - i.iface[5], i.iface[4], i.iface[7], i.iface[6], - i.iface[8], i.iface[9], i.iface[10], i.iface[11], - i.iface[12], i.iface[13], i.iface[14], i.iface[15]] + vec![ + i.iface[3], + i.iface[2], + i.iface[1], + i.iface[0], + i.iface[5], + i.iface[4], + i.iface[7], + i.iface[6], + i.iface[8], + i.iface[9], + i.iface[10], + i.iface[11], + i.iface[12], + i.iface[13], + i.iface[14], + i.iface[15], + ] } else { i.iface.to_vec() }; let uuid_str = uuid::Uuid::from_slice(&x.clone()); - let _uuid_str = uuid_str.map(|uuid_str| uuid_str.to_hyphenated().to_string()).unwrap(); - let d = DCERPCIface::new(x,i.ver,i.ver_min); - SCLogDebug!("UUID {} version {}/{} bytes {:?}", - _uuid_str, - i.ver, i.ver_min,i.iface); + let _uuid_str = uuid_str + .map(|uuid_str| uuid_str.to_hyphenated().to_string()) + .unwrap(); + let d = DCERPCIface::new(x, i.ver, i.ver_min); + SCLogDebug!( + "UUID {} version {}/{} bytes {:?}", + _uuid_str, + i.ver, + i.ver_min, + i.iface + ); ifaces.push(d); } bind_ifaces = Some(ifaces); } - }, + } _ => { tx.set_event(SMBEvent::MalformedData); - }, + } } tx.request_done = true; } 21..=255 => { tx.set_event(SMBEvent::MalformedData); tx.request_done = true; - }, + } _ => { // valid type w/o special processing tx.request_done = true; - }, + } } - }, + } _ => { state.set_event(SMBEvent::MalformedData); - }, + } } if is_bind { @@ -324,12 +362,9 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, /// Update TX for bind ack. Needs to update both tx and state. /// fn smb_dcerpc_response_bindack( - state: &mut SMBState, - vercmd: SMBVerCmdStat, - hdr: SMBCommonHdr, - dcer: &DceRpcRecord, - ntstatus: u32) -{ + state: &mut SMBState, vercmd: SMBVerCmdStat, hdr: SMBCommonHdr, dcer: &DceRpcRecord, + ntstatus: u32, +) { match parse_dcerpc_bindack_record(dcer.data) { Ok((_, bindackr)) => { SCLogDebug!("SMB READ BINDACK {:?}", bindackr); @@ -342,7 +377,7 @@ fn smb_dcerpc_response_bindack( tx.vercmd.set_ntstatus(ntstatus); tx.response_done = true; true - }, + } None => false, }; if found { @@ -357,17 +392,16 @@ fn smb_dcerpc_response_bindack( } } } - }, + } _ => { state.set_event(SMBEvent::MalformedData); - }, + } } } -fn smb_read_dcerpc_record_error(state: &mut SMBState, - hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, ntstatus: u32) - -> bool -{ +fn smb_read_dcerpc_record_error( + state: &mut SMBState, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, ntstatus: u32, +) -> bool { let ver = vercmd.get_version(); let cmd = if ver == 2 { let (_, c) = vercmd.get_smb2_cmd(); @@ -383,42 +417,37 @@ fn smb_read_dcerpc_record_error(state: &mut SMBState, tx.set_status(ntstatus, false); tx.response_done = true; true - }, + } None => { SCLogDebug!("NOT found"); false - }, + } }; return found; } -fn dcerpc_response_handle(tx: &mut SMBTransaction, - vercmd: SMBVerCmdStat, - dcer: &DceRpcRecord) -{ +fn dcerpc_response_handle(tx: &mut SMBTransaction, vercmd: SMBVerCmdStat, dcer: &DceRpcRecord) { let (_, ntstatus) = vercmd.get_ntstatus(); match dcer.packet_type { - DCERPC_TYPE_RESPONSE => { - match parse_dcerpc_response_record(dcer.data, dcer.frag_len) { - Ok((_, respr)) => { - SCLogDebug!("SMBv1 READ RESPONSE {:?}", respr); - if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { - SCLogDebug!("CMD 11 found at tx {}", tx.id); - tdn.set_result(DCERPC_TYPE_RESPONSE); - tdn.stub_data_tc.extend_from_slice(respr.data); - tdn.frag_cnt_tc += 1; - } - tx.vercmd.set_ntstatus(ntstatus); - tx.response_done = dcer.last_frag; - }, - _ => { - tx.set_event(SMBEvent::MalformedData); - }, + DCERPC_TYPE_RESPONSE => match parse_dcerpc_response_record(dcer.data, dcer.frag_len) { + Ok((_, respr)) => { + SCLogDebug!("SMBv1 READ RESPONSE {:?}", respr); + if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { + SCLogDebug!("CMD 11 found at tx {}", tx.id); + tdn.set_result(DCERPC_TYPE_RESPONSE); + tdn.stub_data_tc.extend_from_slice(respr.data); + tdn.frag_cnt_tc += 1; + } + tx.vercmd.set_ntstatus(ntstatus); + tx.response_done = dcer.last_frag; + } + _ => { + tx.set_event(SMBEvent::MalformedData); } }, DCERPC_TYPE_BINDACK => { // handled elsewhere - }, + } 21..=255 => { if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { tdn.set_result(dcer.packet_type); @@ -427,24 +456,22 @@ fn dcerpc_response_handle(tx: &mut SMBTransaction, tx.response_done = true; tx.set_event(SMBEvent::MalformedData); } - _ => { // valid type w/o special processing + _ => { + // valid type w/o special processing if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { tdn.set_result(dcer.packet_type); } tx.vercmd.set_ntstatus(ntstatus); tx.response_done = true; - }, + } } } /// Handle DCERPC reply record. Called for READ, TRANS, IOCTL /// -pub fn smb_read_dcerpc_record(state: &mut SMBState, - vercmd: SMBVerCmdStat, - hdr: SMBCommonHdr, - guid: &[u8], - indata: &[u8]) -> bool -{ +pub fn smb_read_dcerpc_record( + state: &mut SMBState, vercmd: SMBVerCmdStat, hdr: SMBCommonHdr, guid: &[u8], indata: &[u8], +) -> bool { let (_, ntstatus) = vercmd.get_ntstatus(); if ntstatus != SMB_NTSTATUS_SUCCESS && ntstatus != SMB_NTSTATUS_BUFFER_OVERFLOW { @@ -453,8 +480,10 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, SCLogDebug!("lets first see if we have prior data"); // msg_id 0 as this data crosses cmd/reply pairs - let ehdr = SMBHashKeyHdrGuid::new(SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG, - hdr.ssn_id, hdr.tree_id, 0_u64), guid.to_vec()); + let ehdr = SMBHashKeyHdrGuid::new( + SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG, hdr.ssn_id, hdr.tree_id, 0_u64), + guid.to_vec(), + ); let mut prevdata = match state.ssnguid2vec_map.remove(&ehdr) { Some(s) => s, None => Vec::new(), @@ -467,18 +496,25 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, if data.is_empty() { SCLogDebug!("weird: no DCERPC data"); // TODO - // TODO set event? + // TODO set event? return false; - } else { match parse_dcerpc_record(&data) { Ok((_, dcer)) => { - SCLogDebug!("DCERPC: version {}.{} read data {} => {:?}", - dcer.version_major, dcer.version_minor, dcer.data.len(), dcer); + SCLogDebug!( + "DCERPC: version {}.{} read data {} => {:?}", + dcer.version_major, + dcer.version_minor, + dcer.data.len(), + dcer + ); if ntstatus == SMB_NTSTATUS_BUFFER_OVERFLOW && data.len() < dcer.frag_len as usize { - SCLogDebug!("short record {} < {}: storing partial data in state", - data.len(), dcer.frag_len); + SCLogDebug!( + "short record {} < {}: storing partial data in state", + data.len(), + dcer.frag_len + ); state.ssnguid2vec_map.insert(ehdr, data.to_vec()); return true; // TODO review } @@ -492,21 +528,21 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, Some(tx) => { dcerpc_response_handle(tx, vercmd.clone(), &dcer); true - }, + } None => { SCLogDebug!("no tx"); false - }, + } }; if !found { // pick up DCERPC tx even if we missed the request let tx = state.new_dcerpc_tx_for_response(hdr, vercmd.clone(), dcer.call_id); dcerpc_response_handle(tx, vercmd, &dcer); } - }, + } _ => { malformed = true; - }, + } } } @@ -518,16 +554,17 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, } /// Try to find out if the input data looks like DCERPC -pub fn smb_dcerpc_probe(data: &[u8]) -> bool -{ +pub fn smb_dcerpc_probe(data: &[u8]) -> bool { if let Ok((_, recr)) = parse_dcerpc_record(data) { SCLogDebug!("SMB: could be DCERPC {:?}", recr); - if recr.version_major == 5 && recr.version_minor < 3 && - recr.frag_len > 0 && recr.packet_type <= 20 - { - SCLogDebug!("SMB: looks like we have dcerpc"); - return true; - } + if recr.version_major == 5 + && recr.version_minor < 3 + && recr.frag_len > 0 + && recr.packet_type <= 20 + { + SCLogDebug!("SMB: looks like we have dcerpc"); + return true; + } } return false; } diff --git a/rust/src/smb/dcerpc_records.rs b/rust/src/smb/dcerpc_records.rs index 0c8c17fe18c4..66eeee57cc3b 100644 --- a/rust/src/smb/dcerpc_records.rs +++ b/rust/src/smb/dcerpc_records.rs @@ -21,21 +21,21 @@ use nom7::bits::streaming::take as take_bits; use nom7::bytes::streaming::take; use nom7::combinator::{cond, rest}; use nom7::multi::count; +use nom7::number::streaming::{be_u16, le_u16, le_u32, le_u8, u16, u32}; use nom7::number::Endianness; -use nom7::number::streaming::{be_u16, le_u8, le_u16, le_u32, u16, u32}; use nom7::sequence::tuple; use nom7::{Err, IResult}; -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcResponseRecord<'a> { - pub data: &'a[u8], + pub data: &'a [u8], } /// parse a packet type 'response' DCERPC record. Implemented /// as function to be able to pass the fraglen in. -pub fn parse_dcerpc_response_record(i:&[u8], frag_len: u16 ) - -> IResult<&[u8], DceRpcResponseRecord, SmbError> -{ +pub fn parse_dcerpc_response_record( + i: &[u8], frag_len: u16, +) -> IResult<&[u8], DceRpcResponseRecord, SmbError> { if frag_len < 24 { return Err(Err::Error(SmbError::RecordTooSmall)); } @@ -45,33 +45,41 @@ pub fn parse_dcerpc_response_record(i:&[u8], frag_len: u16 ) Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcRequestRecord<'a> { pub opnum: u16, pub context_id: u16, - pub data: &'a[u8], + pub data: &'a [u8], } /// parse a packet type 'request' DCERPC record. Implemented /// as function to be able to pass the fraglen in. -pub fn parse_dcerpc_request_record(i:&[u8], frag_len: u16, little: bool) - -> IResult<&[u8], DceRpcRequestRecord, SmbError> -{ +pub fn parse_dcerpc_request_record( + i: &[u8], frag_len: u16, little: bool, +) -> IResult<&[u8], DceRpcRequestRecord, SmbError> { if frag_len < 24 { return Err(Err::Error(SmbError::RecordTooSmall)); } let (i, _) = take(4_usize)(i)?; - let endian = if little { Endianness::Little } else { Endianness::Big }; + let endian = if little { + Endianness::Little + } else { + Endianness::Big + }; let (i, context_id) = u16(endian)(i)?; let (i, opnum) = u16(endian)(i)?; let (i, data) = take(frag_len - 24)(i)?; - let record = DceRpcRequestRecord { opnum, context_id, data }; + let record = DceRpcRequestRecord { + opnum, + context_id, + data, + }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindIface<'a> { - pub iface: &'a[u8], + pub iface: &'a [u8], pub ver: u16, pub ver_min: u16, } @@ -85,7 +93,7 @@ pub fn parse_dcerpc_bind_iface(i: &[u8]) -> IResult<&[u8], DceRpcBindIface> { let (i, ver_min) = le_u16(i)?; let (i, _) = take(20_usize)(i)?; let res = DceRpcBindIface { - iface:interface, + iface: interface, ver, ver_min, }; @@ -101,14 +109,14 @@ pub fn parse_dcerpc_bind_iface_big(i: &[u8]) -> IResult<&[u8], DceRpcBindIface> let (i, ver) = be_u16(i)?; let (i, _) = take(20_usize)(i)?; let res = DceRpcBindIface { - iface:interface, + iface: interface, ver, ver_min, }; Ok((i, res)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindRecord<'a> { pub num_ctx_items: u8, pub ifaces: Vec>, @@ -142,11 +150,11 @@ pub fn parse_dcerpc_bind_record_big(i: &[u8]) -> IResult<&[u8], DceRpcBindRecord Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindAckResult<'a> { pub ack_result: u16, pub ack_reason: u16, - pub transfer_syntax: &'a[u8], + pub transfer_syntax: &'a [u8], pub syntax_version: u32, } @@ -164,7 +172,7 @@ pub fn parse_dcerpc_bindack_result(i: &[u8]) -> IResult<&[u8], DceRpcBindAckResu Ok((i, res)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcBindAckRecord<'a> { pub num_results: u8, pub results: Vec>, @@ -176,7 +184,10 @@ pub fn parse_dcerpc_bindack_record(i: &[u8]) -> IResult<&[u8], DceRpcBindAckReco let (i, _assoc_group) = take(4_usize)(i)?; let (i, sec_addr_len) = le_u16(i)?; let (i, _) = take(sec_addr_len)(i)?; - let (i, _) = cond((sec_addr_len+2) % 4 != 0, take(4 - (sec_addr_len+2) % 4))(i)?; + let (i, _) = cond( + (sec_addr_len + 2) % 4 != 0, + take(4 - (sec_addr_len + 2) % 4), + )(i)?; let (i, num_results) = le_u8(i)?; let (i, _) = take(3_usize)(i)?; // padding let (i, results) = count(parse_dcerpc_bindack_result, num_results as usize)(i)?; @@ -187,7 +198,7 @@ pub fn parse_dcerpc_bindack_record(i: &[u8]) -> IResult<&[u8], DceRpcBindAckReco Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DceRpcRecord<'a> { pub version_major: u8, pub version_minor: u8, @@ -202,22 +213,22 @@ pub struct DceRpcRecord<'a> { pub packet_type: u8, pub call_id: u32, - pub data: &'a[u8], + pub data: &'a [u8], } -fn parse_dcerpc_flags1(i:&[u8]) -> IResult<&[u8],(u8,u8,u8)> { +fn parse_dcerpc_flags1(i: &[u8]) -> IResult<&[u8], (u8, u8, u8)> { bits(tuple(( take_bits(6u8), - take_bits(1u8), // last (1) + take_bits(1u8), // last (1) take_bits(1u8), )))(i) } -fn parse_dcerpc_flags2(i:&[u8]) -> IResult<&[u8],(u32,u32,u32)> { +fn parse_dcerpc_flags2(i: &[u8]) -> IResult<&[u8], (u32, u32, u32)> { bits(tuple(( - take_bits(3u32), - take_bits(1u32), // endianness - take_bits(28u32), + take_bits(3u32), + take_bits(1u32), // endianness + take_bits(28u32), )))(i) } @@ -227,7 +238,11 @@ pub fn parse_dcerpc_record(i: &[u8]) -> IResult<&[u8], DceRpcRecord> { let (i, packet_type) = le_u8(i)?; let (i, packet_flags) = parse_dcerpc_flags1(i)?; let (i, data_rep) = parse_dcerpc_flags2(i)?; - let endian = if data_rep.1 == 0 { Endianness::Big } else { Endianness::Little }; + let endian = if data_rep.1 == 0 { + Endianness::Big + } else { + Endianness::Little + }; let (i, frag_len) = u16(endian)(i)?; let (i, _auth) = u16(endian)(i)?; let (i, call_id) = u32(endian)(i)?; diff --git a/rust/src/smb/debug.rs b/rust/src/smb/debug.rs index 86799dd7fa1d..56eb26fd400a 100644 --- a/rust/src/smb/debug.rs +++ b/rust/src/smb/debug.rs @@ -19,7 +19,7 @@ use crate::smb::smb::*; impl SMBState { #[cfg(not(feature = "debug"))] - pub fn _debug_tx_stats(&self) { } + pub fn _debug_tx_stats(&self) {} #[cfg(feature = "debug")] pub fn _debug_tx_stats(&self) { @@ -27,7 +27,12 @@ impl SMBState { let txf = self.transactions.front().unwrap(); let txl = self.transactions.back().unwrap(); - SCLogDebug!("TXs {} MIN {} MAX {}", self.transactions.len(), txf.id, txl.id); + SCLogDebug!( + "TXs {} MIN {} MAX {}", + self.transactions.len(), + txf.id, + txl.id + ); SCLogDebug!("- OLD tx.id {}: {:?}", txf.id, txf); SCLogDebug!("- NEW tx.id {}: {:?}", txl.id, txl); self._dump_txs(); @@ -35,7 +40,7 @@ impl SMBState { } #[cfg(not(feature = "debug"))] - pub fn _dump_txs(&self) { } + pub fn _dump_txs(&self) {} #[cfg(feature = "debug")] pub fn _dump_txs(&self) { let len = self.transactions.len(); @@ -52,20 +57,35 @@ impl SMBState { match tx.type_data { Some(SMBTransactionTypeData::FILE(ref d)) => { - SCLogDebug!("idx {} tx id {} progress {}/{} filename {} type_data {:?}", - i, tx.id, tx.request_done, tx.response_done, - String::from_utf8_lossy(&d.file_name), tx.type_data); - }, + SCLogDebug!( + "idx {} tx id {} progress {}/{} filename {} type_data {:?}", + i, + tx.id, + tx.request_done, + tx.response_done, + String::from_utf8_lossy(&d.file_name), + tx.type_data + ); + } _ => { - SCLogDebug!("idx {} tx id {} ver:{} cmd:{} progress {}/{} type_data {:?} tx {:?}", - i, tx.id, ver, _smbcmd, tx.request_done, tx.response_done, tx.type_data, tx); - }, + SCLogDebug!( + "idx {} tx id {} ver:{} cmd:{} progress {}/{} type_data {:?} tx {:?}", + i, + tx.id, + ver, + _smbcmd, + tx.request_done, + tx.response_done, + tx.type_data, + tx + ); + } } } } #[cfg(not(feature = "debug"))] - pub fn _debug_state_stats(&self) { } + pub fn _debug_state_stats(&self) {} #[cfg(feature = "debug")] pub fn _debug_state_stats(&self) { diff --git a/rust/src/smb/detect.rs b/rust/src/smb/detect.rs index c85a6f59ce33..41aa0fa7ddd6 100644 --- a/rust/src/smb/detect.rs +++ b/rust/src/smb/detect.rs @@ -15,19 +15,17 @@ * 02110-1301, USA. */ -use std::ptr; use crate::core::*; -use crate::smb::smb::*; -use crate::dcerpc::detect::{DCEIfaceData, DCEOpnumData, DETECT_DCE_OPNUM_RANGE_UNINITIALIZED}; use crate::dcerpc::dcerpc::DCERPC_TYPE_REQUEST; +use crate::dcerpc::detect::{DCEIfaceData, DCEOpnumData, DETECT_DCE_OPNUM_RANGE_UNINITIALIZED}; use crate::detect::uint::detect_match_uint; +use crate::smb::smb::*; +use std::ptr; #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_share(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern fn rs_smb_tx_get_share( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::TREECONNECT(ref x)) = tx.type_data { SCLogDebug!("is_pipe {}", x.is_pipe); if !x.is_pipe { @@ -43,11 +41,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_share(tx: &mut SMBTransaction, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_named_pipe(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern fn rs_smb_tx_get_named_pipe( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::TREECONNECT(ref x)) = tx.type_data { SCLogDebug!("is_pipe {}", x.is_pipe); if x.is_pipe { @@ -63,12 +59,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_named_pipe(tx: &mut SMBTransaction, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_stub_data(tx: &mut SMBTransaction, - direction: u8, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern fn rs_smb_tx_get_stub_data( + tx: &mut SMBTransaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::DCERPC(ref x)) = tx.type_data { let vref = if direction == Direction::ToServer as u8 { &x.stub_data_ts @@ -88,10 +81,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_stub_data(tx: &mut SMBTransaction, } #[no_mangle] -pub extern "C" fn rs_smb_tx_match_dce_opnum(tx: &mut SMBTransaction, - dce_data: &mut DCEOpnumData) - -> u8 -{ +pub extern fn rs_smb_tx_match_dce_opnum( + tx: &mut SMBTransaction, dce_data: &mut DCEOpnumData, +) -> u8 { SCLogDebug!("rs_smb_tx_get_dce_opnum: start"); if let Some(SMBTransactionTypeData::DCERPC(ref x)) = tx.type_data { if x.req_cmd == DCERPC_TYPE_REQUEST { @@ -115,17 +107,13 @@ pub extern "C" fn rs_smb_tx_match_dce_opnum(tx: &mut SMBTransaction, * dce_opnum and dce_stub_data) * - only match on approved ifaces (so ack_result == 0) */ #[no_mangle] -pub extern "C" fn rs_smb_tx_get_dce_iface(state: &mut SMBState, - tx: &mut SMBTransaction, - dce_data: &mut DCEIfaceData) - -> u8 -{ +pub extern fn rs_smb_tx_get_dce_iface( + state: &mut SMBState, tx: &mut SMBTransaction, dce_data: &mut DCEIfaceData, +) -> u8 { let if_uuid = dce_data.if_uuid.as_slice(); let is_dcerpc_request = match tx.type_data { - Some(SMBTransactionTypeData::DCERPC(ref x)) => { - x.req_cmd == DCERPC_TYPE_REQUEST - }, - _ => { false }, + Some(SMBTransactionTypeData::DCERPC(ref x)) => x.req_cmd == DCERPC_TYPE_REQUEST, + _ => false, }; if !is_dcerpc_request { return 0; @@ -134,13 +122,18 @@ pub extern "C" fn rs_smb_tx_get_dce_iface(state: &mut SMBState, Some(ref x) => x, _ => { return 0; - }, + } }; SCLogDebug!("looking for UUID {:?}", if_uuid); for i in ifaces { - SCLogDebug!("stored UUID {:?} acked {} ack_result {}", i, i.acked, i.ack_result); + SCLogDebug!( + "stored UUID {:?} acked {} ack_result {}", + i, + i.acked, + i.ack_result + ); if i.acked && i.ack_result == 0 && i.uuid == if_uuid { if let Some(x) = &dce_data.du16 { @@ -156,11 +149,9 @@ pub extern "C" fn rs_smb_tx_get_dce_iface(state: &mut SMBState, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_user(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern fn rs_smb_tx_get_ntlmssp_user( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::SESSIONSETUP(ref x)) = tx.type_data { if let Some(ref ntlmssp) = x.ntlmssp { *buffer = ntlmssp.user.as_ptr(); @@ -175,11 +166,9 @@ pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_user(tx: &mut SMBTransaction, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_ntlmssp_domain(tx: &mut SMBTransaction, - buffer: *mut *const u8, - buffer_len: *mut u32) - -> u8 -{ +pub unsafe extern fn rs_smb_tx_get_ntlmssp_domain( + tx: &mut SMBTransaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { if let Some(SMBTransactionTypeData::SESSIONSETUP(ref x)) = tx.type_data { if let Some(ref ntlmssp) = x.ntlmssp { *buffer = ntlmssp.domain.as_ptr(); diff --git a/rust/src/smb/files.rs b/rust/src/smb/files.rs index b290357428ee..c0b27688d295 100644 --- a/rust/src/smb/files.rs +++ b/rust/src/smb/files.rs @@ -15,10 +15,10 @@ * 02110-1301, USA. */ -use std; use crate::core::*; -use crate::filetracker::*; use crate::filecontainer::*; +use crate::filetracker::*; +use std; use crate::smb::smb::*; @@ -41,41 +41,42 @@ impl SMBTransactionFile { return Self { file_tracker: FileTransferTracker::new(), ..Default::default() - } + }; } pub fn update_file_flags(&mut self, flow_file_flags: u16) { - let dir_flag = if self.direction == Direction::ToServer { STREAM_TOSERVER } else { STREAM_TOCLIENT }; + let dir_flag = if self.direction == Direction::ToServer { + STREAM_TOSERVER + } else { + STREAM_TOCLIENT + }; self.file_tracker.file_flags = unsafe { FileFlowFlagsToFlags(flow_file_flags, dir_flag) }; } } /// little wrapper around the FileTransferTracker::new_chunk method -pub fn filetracker_newchunk(ft: &mut FileTransferTracker, name: &[u8], data: &[u8], - chunk_offset: u64, chunk_size: u32, is_last: bool, xid: &u32) -{ +pub fn filetracker_newchunk( + ft: &mut FileTransferTracker, name: &[u8], data: &[u8], chunk_offset: u64, chunk_size: u32, + is_last: bool, xid: &u32, +) { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { - ft.new_chunk(sfcm, name, data, chunk_offset, - chunk_size, 0, is_last, xid); + ft.new_chunk(sfcm, name, data, chunk_offset, chunk_size, 0, is_last, xid); } } -pub fn filetracker_trunc(ft: &mut FileTransferTracker) -{ +pub fn filetracker_trunc(ft: &mut FileTransferTracker) { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { ft.trunc(sfcm); } } -pub fn filetracker_close(ft: &mut FileTransferTracker) -{ +pub fn filetracker_close(ft: &mut FileTransferTracker) { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { ft.close(sfcm); } } -fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) -> u32 -{ +fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) -> u32 { if let Some(sfcm) = unsafe { SURICATA_SMB_FILE_CONFIG } { ft.update(sfcm, data, gap_size) } else { @@ -84,9 +85,9 @@ fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) } impl SMBState { - pub fn new_file_tx(&mut self, fuid: &[u8], file_name: &[u8], direction: Direction) - -> &mut SMBTransaction - { + pub fn new_file_tx( + &mut self, fuid: &[u8], file_name: &[u8], direction: Direction, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.type_data = Some(SMBTransactionTypeData::FILE(SMBTransactionFile::new())); if let Some(SMBTransactionTypeData::FILE(ref mut d)) = tx.type_data { @@ -98,9 +99,16 @@ impl SMBState { d.update_file_flags(tx.tx_data.file_flags); } tx.tx_data.init_files_opened(); - tx.tx_data.file_tx = if direction == Direction::ToServer { STREAM_TOSERVER } else { STREAM_TOCLIENT }; // TODO direction to flag func? - SCLogDebug!("SMB: new_file_tx: TX FILE created: ID {} NAME {}", - tx.id, String::from_utf8_lossy(file_name)); + tx.tx_data.file_tx = if direction == Direction::ToServer { + STREAM_TOSERVER + } else { + STREAM_TOCLIENT + }; // TODO direction to flag func? + SCLogDebug!( + "SMB: new_file_tx: TX FILE created: ID {} NAME {}", + tx.id, + String::from_utf8_lossy(file_name) + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); @@ -108,16 +116,16 @@ impl SMBState { /// get file tx for a open file. Returns None if a file for the fuid exists, /// but has already been closed. - pub fn get_file_tx_by_fuid_with_open_file(&mut self, fuid: &[u8], direction: Direction) - -> Option<&mut SMBTransaction> - { + pub fn get_file_tx_by_fuid_with_open_file( + &mut self, fuid: &[u8], direction: Direction, + ) -> Option<&mut SMBTransaction> { let f = fuid.to_vec(); for tx in &mut self.transactions { let found = match tx.type_data { Some(SMBTransactionTypeData::FILE(ref mut d)) => { direction == d.direction && f == d.fuid && !d.file_tracker.is_done() - }, - _ => { false }, + } + _ => false, }; if found { @@ -134,16 +142,16 @@ impl SMBState { } /// get file tx for a fuid. File may already have been closed. - pub fn get_file_tx_by_fuid(&mut self, fuid: &[u8], direction: Direction) - -> Option<&mut SMBTransaction> - { + pub fn get_file_tx_by_fuid( + &mut self, fuid: &[u8], direction: Direction, + ) -> Option<&mut SMBTransaction> { let f = fuid.to_vec(); for tx in &mut self.transactions { let found = match tx.type_data { Some(SMBTransactionTypeData::FILE(ref mut d)) => { direction == d.direction && f == d.fuid - }, - _ => { false }, + } + _ => false, }; if found { @@ -168,7 +176,7 @@ impl SMBState { self.file_tc_left }; if chunk_left == 0 { - return 0 + return 0; } SCLogDebug!("chunk_left {} data {}", chunk_left, data.len()); let file_handle = if direction == Direction::ToServer { @@ -202,8 +210,12 @@ impl SMBState { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { if ssn_gap { let queued_data = tdf.file_tracker.get_queued_size(); - if queued_data > 2000000 { // TODO should probably be configurable - SCLogDebug!("QUEUED size {} while we've seen GAPs. Truncating file.", queued_data); + if queued_data > 2000000 { + // TODO should probably be configurable + SCLogDebug!( + "QUEUED size {} while we've seen GAPs. Truncating file.", + queued_data + ); filetracker_trunc(&mut tdf.file_tracker); } } @@ -218,10 +230,11 @@ impl SMBState { } else { 0 } - }, + } None => { SCLogDebug!("not found for handle {:?}", file_handle); - 0 }, + 0 + } }; return consumed; @@ -230,13 +243,18 @@ impl SMBState { use crate::applayer::AppLayerGetFileState; #[no_mangle] -pub unsafe extern "C" fn rs_smb_gettxfiles(_state: *mut std::ffi::c_void, tx: *mut std::ffi::c_void, direction: u8) -> AppLayerGetFileState { +pub unsafe extern fn rs_smb_gettxfiles( + _state: *mut std::ffi::c_void, tx: *mut std::ffi::c_void, direction: u8, +) -> AppLayerGetFileState { let tx = cast_pointer!(tx, SMBTransaction); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let tx_dir : u8 = tdf.direction.into(); + let tx_dir: u8 = tdf.direction.into(); if direction & tx_dir != 0 { if let Some(sfcm) = { SURICATA_SMB_FILE_CONFIG } { - return AppLayerGetFileState { fc: &mut tdf.file_tracker.file, cfg: sfcm.files_sbcfg } + return AppLayerGetFileState { + fc: &mut tdf.file_tracker.file, + cfg: sfcm.files_sbcfg, + }; } } } diff --git a/rust/src/smb/funcs.rs b/rust/src/smb/funcs.rs index afab69d967b9..43410418beb8 100644 --- a/rust/src/smb/funcs.rs +++ b/rust/src/smb/funcs.rs @@ -23,7 +23,7 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x00060194 => "FSCTL_DFS_GET_REFERRALS", 0x000601B0 => "FSCTL_DFS_GET_REFERRALS_EX", 0x00090000 => "FSCTL_REQUEST_OPLOCK_LEVEL_1", - 0x00090004 => "FSCTL_REQUEST_OPLOCK_LEVEL_2", + 0x00090004 => "FSCTL_REQUEST_OPLOCK_LEVEL_2", 0x00090008 => "FSCTL_REQUEST_BATCH_OPLOCK", 0x0009000C => "FSCTL_OPLOCK_BREAK_ACKNOWLEDGE", 0x00090010 => "FSCTL_OPBATCH_ACK_CLOSE_PENDING", @@ -38,7 +38,7 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x0009003C => "FSCTL_GET_COMPRESSION", 0x0009004F => "FSCTL_MARK_AS_SYSTEM_HIVE", 0x00090050 => "FSCTL_OPLOCK_BREAK_ACK_NO_2", - 0x00090054 => "FSCTL_INVALIDATE_VOLUMES", + 0x00090054 => "FSCTL_INVALIDATE_VOLUMES", 0x00090058 => "FSCTL_QUERY_FAT_BPB", 0x0009005C => "FSCTL_REQUEST_FILTER_OPLOCK", 0x00090060 => "FSCTL_FILESYSTEM_GET_STATISTICS", @@ -48,7 +48,7 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x00090073 => "FSCTL_GET_RETRIEVAL_POINTERS", 0x00090074 => "FSCTL_MOVE_FILE", 0x00090078 => "FSCTL_IS_VOLUME_DIRTY", - 0x0009007C => "FSCTL_GET_HFS_INFORMATION", + 0x0009007C => "FSCTL_GET_HFS_INFORMATION", 0x00090083 => "FSCTL_ALLOW_EXTENDED_DASD_IO", 0x00090087 => "FSCTL_READ_PROPERTY_DATA", 0x0009008B => "FSCTL_WRITE_PROPERTY_DATA", @@ -109,6 +109,9 @@ pub fn fsctl_func_to_string(f: u32) -> String { 0x001440F2 => "FSCTL_SRV_COPYCHUNK", 0x001441bb => "FSCTL_SRV_READ_HASH", 0x001480F2 => "FSCTL_SRV_COPYCHUNK_WRITE", - _ => { return (f).to_string(); }, - }.to_string() + _ => { + return (f).to_string(); + } + } + .to_string() } diff --git a/rust/src/smb/log.rs b/rust/src/smb/log.rs index 84965749ba17..b2cc7f6c1970 100644 --- a/rust/src/smb/log.rs +++ b/rust/src/smb/log.rs @@ -15,19 +15,21 @@ * 02110-1301, USA. */ -use std::str; -use std::string::String; -use uuid; +use crate::dcerpc::dcerpc::*; use crate::jsonbuilder::{JsonBuilder, JsonError}; +use crate::smb::funcs::*; use crate::smb::smb::*; use crate::smb::smb1::*; use crate::smb::smb2::*; -use crate::dcerpc::dcerpc::*; -use crate::smb::funcs::*; use crate::smb::smb_status::*; +use std::str; +use std::string::String; +use uuid; #[cfg(not(feature = "debug"))] -fn debug_add_progress(_js: &mut JsonBuilder, _tx: &SMBTransaction) -> Result<(), JsonError> { Ok(()) } +fn debug_add_progress(_js: &mut JsonBuilder, _tx: &SMBTransaction) -> Result<(), JsonError> { + Ok(()) +} #[cfg(feature = "debug")] fn debug_add_progress(jsb: &mut JsonBuilder, tx: &SMBTransaction) -> Result<(), JsonError> { @@ -65,8 +67,9 @@ fn guid_to_string(guid: &Vec) -> String { } } -fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransaction) -> Result<(), JsonError> -{ +fn smb_common_header( + jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransaction, +) -> Result<(), JsonError> { jsb.set_uint("id", tx.id)?; if state.dialect != 0 { @@ -75,7 +78,7 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio } else { let dialect = match state.dialect_vec { Some(ref d) => str::from_utf8(d).unwrap_or("invalid"), - None => "unknown", + None => "unknown", }; jsb.set_string("dialect", dialect)?; } @@ -86,14 +89,14 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio if ok { jsb.set_string("command", &smb1_command_string(cmd))?; } - }, + } 2 => { let (ok, cmd) = tx.vercmd.get_smb2_cmd(); if ok { jsb.set_string("command", &smb2_command_string(cmd))?; } - }, - _ => { }, + } + _ => {} } match tx.vercmd.get_ntstatus() { @@ -104,39 +107,39 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio None => { let status_str = format!("{}", ntstatus); jsb.set_string("status", &status_str)? - }, + } }; let status_hex = format!("0x{:x}", ntstatus); jsb.set_string("status_code", &status_hex)?; - }, + } (false, _) => { #[allow(clippy::single_match)] match tx.vercmd.get_dos_error() { (true, errclass, errcode) => { match errclass { - 1 => { // DOSERR + 1 => { + // DOSERR let status = smb_dos_error_string(errcode); jsb.set_string("status", &status)?; - }, - 2 => { // SRVERR + } + 2 => { + // SRVERR let status = smb_srv_error_string(errcode); jsb.set_string("status", &status)?; } _ => { let s = format!("UNKNOWN_{:02x}_{:04x}", errclass, errcode); jsb.set_string("status", &s)?; - }, + } } let status_hex = format!("0x{:04x}", errcode); jsb.set_string("status_code", &status_hex)?; - }, - (_, _, _) => { - }, + } + (_, _, _) => {} } - }, + } } - jsb.set_uint("session_id", tx.hdr.ssn_id)?; jsb.set_uint("tree_id", tx.hdr.tree_id as u64)?; @@ -189,10 +192,10 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio jsb.set_string("native_lm", &lm)?; jsb.close()?; } - }, + } Some(SMBTransactionTypeData::CREATE(ref x)) => { let mut name_raw = x.filename.to_vec(); - name_raw.retain(|&i|i != 0x00); + name_raw.retain(|&i| i != 0x00); if !name_raw.is_empty() { let name = String::from_utf8_lossy(&name_raw); if x.directory { @@ -205,13 +208,27 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio jsb.set_string("filename", "")?; } match x.disposition { - 0 => { jsb.set_string("disposition", "FILE_SUPERSEDE")?; }, - 1 => { jsb.set_string("disposition", "FILE_OPEN")?; }, - 2 => { jsb.set_string("disposition", "FILE_CREATE")?; }, - 3 => { jsb.set_string("disposition", "FILE_OPEN_IF")?; }, - 4 => { jsb.set_string("disposition", "FILE_OVERWRITE")?; }, - 5 => { jsb.set_string("disposition", "FILE_OVERWRITE_IF")?; }, - _ => { jsb.set_string("disposition", "UNKNOWN")?; }, + 0 => { + jsb.set_string("disposition", "FILE_SUPERSEDE")?; + } + 1 => { + jsb.set_string("disposition", "FILE_OPEN")?; + } + 2 => { + jsb.set_string("disposition", "FILE_CREATE")?; + } + 3 => { + jsb.set_string("disposition", "FILE_OPEN_IF")?; + } + 4 => { + jsb.set_string("disposition", "FILE_OVERWRITE")?; + } + 5 => { + jsb.set_string("disposition", "FILE_OVERWRITE_IF")?; + } + _ => { + jsb.set_string("disposition", "UNKNOWN")?; + } } if x.delete_on_close { jsb.set_string("access", "delete on close")?; @@ -228,7 +245,7 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio let gs = fuid_to_string(&x.guid); jsb.set_string("fuid", &gs)?; - }, + } Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => { if x.smb_ver == 1 { jsb.open_array("client_dialects")?; @@ -258,7 +275,7 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio if state.max_write_size > 0 { jsb.set_uint("max_write_size", state.max_write_size.into())?; } - }, + } Some(SMBTransactionTypeData::TREECONNECT(ref x)) => { let share_name = String::from_utf8_lossy(&x.share_name); if x.is_pipe { @@ -284,13 +301,21 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio // share type only for SMB2 } else { match x.share_type { - 1 => { jsb.set_string("share_type", "FILE")?; }, - 2 => { jsb.set_string("share_type", "PIPE")?; }, - 3 => { jsb.set_string("share_type", "PRINT")?; }, - _ => { jsb.set_string("share_type", "UNKNOWN")?; }, + 1 => { + jsb.set_string("share_type", "FILE")?; + } + 2 => { + jsb.set_string("share_type", "PIPE")?; + } + 3 => { + jsb.set_string("share_type", "PRINT")?; + } + _ => { + jsb.set_string("share_type", "UNKNOWN")?; + } } } - }, + } Some(SMBTransactionTypeData::FILE(ref x)) => { let file_name = String::from_utf8_lossy(&x.file_name); jsb.set_string("filename", &file_name)?; @@ -298,7 +323,7 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio jsb.set_string("share", &share_name)?; let gs = fuid_to_string(&x.fuid); jsb.set_string("fuid", &gs)?; - }, + } Some(SMBTransactionTypeData::RENAME(ref x)) => { if tx.vercmd.get_version() == 2 { jsb.open_object("set_info")?; @@ -315,7 +340,7 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio jsb.close()?; let gs = fuid_to_string(&x.fuid); jsb.set_string("fuid", &gs)?; - }, + } Some(SMBTransactionTypeData::DCERPC(ref x)) => { jsb.open_object("dcerpc")?; if x.req_set { @@ -350,7 +375,9 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio for i in ifaces { jsb.start_object()?; let ifstr = uuid::Uuid::from_slice(&i.uuid); - let ifstr = ifstr.map(|ifstr| ifstr.to_hyphenated().to_string()).unwrap(); + let ifstr = ifstr + .map(|ifstr| ifstr.to_hyphenated().to_string()) + .unwrap(); jsb.set_string("uuid", &ifstr)?; let vstr = format!("{}.{}", i.ver, i.ver_min); jsb.set_string("version", &vstr)?; @@ -359,18 +386,20 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio jsb.close()?; } } - }, + } DCERPC_TYPE_BIND => { if let Some(ref ifaces) = state.dcerpc_ifaces { jsb.open_array("interfaces")?; for i in ifaces { jsb.start_object()?; let ifstr = uuid::Uuid::from_slice(&i.uuid); - let ifstr = ifstr.map(|ifstr| ifstr.to_hyphenated().to_string()).unwrap(); + let ifstr = ifstr + .map(|ifstr| ifstr.to_hyphenated().to_string()) + .unwrap(); jsb.set_string("uuid", &ifstr)?; let vstr = format!("{}.{}", i.ver, i.ver_min); jsb.set_string("version", &vstr)?; - + if i.acked { jsb.set_uint("ack_result", i.ack_result as u64)?; jsb.set_uint("ack_reason", i.ack_reason as u64)?; @@ -379,8 +408,8 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio } jsb.close()?; } - }, - _ => {}, + } + _ => {} } } if x.res_set { @@ -391,9 +420,9 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio jsb.set_uint("frag_cnt", x.frag_cnt_tc as u64)?; jsb.set_uint("stub_data_size", x.stub_data_tc.len() as u64)?; jsb.close()?; - }, + } // we don't handle BINDACK w/o BIND - _ => {}, + _ => {} } } jsb.set_uint("call_id", x.call_id as u64)?; @@ -401,10 +430,10 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio } Some(SMBTransactionTypeData::IOCTL(ref x)) => { jsb.set_string("function", &fsctl_func_to_string(x.func))?; - }, + } Some(SMBTransactionTypeData::SETFILEPATHINFO(ref x)) => { let mut name_raw = x.filename.to_vec(); - name_raw.retain(|&i|i != 0x00); + name_raw.retain(|&i| i != 0x00); if !name_raw.is_empty() { let name = String::from_utf8_lossy(&name_raw); jsb.set_string("filename", &name)?; @@ -421,38 +450,40 @@ fn smb_common_header(jsb: &mut JsonBuilder, state: &SMBState, tx: &SMBTransactio match x.subcmd { 8 => { jsb.set_string("subcmd", "SET_FILE_INFO")?; - }, + } 6 => { jsb.set_string("subcmd", "SET_PATH_INFO")?; - }, - _ => { }, + } + _ => {} } #[allow(clippy::single_match)] match x.loi { - 1013 => { // Set Disposition Information + 1013 => { + // Set Disposition Information jsb.set_string("level_of_interest", "Set Disposition Information")?; - }, - _ => { }, + } + _ => {} } let gs = fuid_to_string(&x.fid); jsb.set_string("fuid", &gs)?; - }, - _ => { }, + } + _ => {} } return Ok(()); } #[no_mangle] -pub extern "C" fn rs_smb_log_json_request(jsb: &mut JsonBuilder, state: &mut SMBState, tx: &mut SMBTransaction) -> bool -{ +pub extern fn rs_smb_log_json_request( + jsb: &mut JsonBuilder, state: &mut SMBState, tx: &mut SMBTransaction, +) -> bool { smb_common_header(jsb, state, tx).is_ok() } #[no_mangle] -pub extern "C" fn rs_smb_log_json_response(jsb: &mut JsonBuilder, state: &mut SMBState, tx: &mut SMBTransaction) -> bool -{ +pub extern fn rs_smb_log_json_response( + jsb: &mut JsonBuilder, state: &mut SMBState, tx: &mut SMBTransaction, +) -> bool { smb_common_header(jsb, state, tx).is_ok() } - diff --git a/rust/src/smb/mod.rs b/rust/src/smb/mod.rs index 5b74f1ca4e02..399878aab84f 100644 --- a/rust/src/smb/mod.rs +++ b/rust/src/smb/mod.rs @@ -17,31 +17,31 @@ //! SMB application layer, detection, logger and parser module. +pub mod dcerpc_records; pub mod error; -pub mod smb_records; -pub mod smb_status; -pub mod smb1_records; -pub mod smb2_records; pub mod nbss_records; -pub mod dcerpc_records; pub mod ntlmssp_records; +pub mod smb1_records; +pub mod smb2_records; +pub mod smb_records; +pub mod smb_status; +pub mod auth; +pub mod dcerpc; +pub mod debug; +pub mod detect; +pub mod events; +pub mod files; +pub mod funcs; +pub mod log; +pub mod session; pub mod smb; pub mod smb1; pub mod smb1_session; pub mod smb2; -pub mod smb2_session; pub mod smb2_ioctl; +pub mod smb2_session; pub mod smb3; -pub mod dcerpc; -pub mod session; -pub mod log; -pub mod detect; -pub mod debug; -pub mod events; -pub mod auth; -pub mod files; -pub mod funcs; //#[cfg(feature = "lua")] //pub mod lua; diff --git a/rust/src/smb/nbss_records.rs b/rust/src/smb/nbss_records.rs index 6225eb47067e..87fd247ebb9f 100644 --- a/rust/src/smb/nbss_records.rs +++ b/rust/src/smb/nbss_records.rs @@ -20,29 +20,29 @@ use nom7::combinator::rest; use nom7::number::streaming::be_u32; use nom7::IResult; -pub const NBSS_MSGTYPE_SESSION_MESSAGE: u8 = 0x00; -pub const NBSS_MSGTYPE_SESSION_REQUEST: u8 = 0x81; -pub const NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE: u8 = 0x82; -pub const NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE: u8 = 0x83; -pub const NBSS_MSGTYPE_RETARG_RESPONSE: u8 = 0x84; -pub const NBSS_MSGTYPE_KEEP_ALIVE: u8 = 0x85; - -#[derive(Debug,PartialEq, Eq)] +pub const NBSS_MSGTYPE_SESSION_MESSAGE: u8 = 0x00; +pub const NBSS_MSGTYPE_SESSION_REQUEST: u8 = 0x81; +pub const NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE: u8 = 0x82; +pub const NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE: u8 = 0x83; +pub const NBSS_MSGTYPE_RETARG_RESPONSE: u8 = 0x84; +pub const NBSS_MSGTYPE_KEEP_ALIVE: u8 = 0x85; + +#[derive(Debug, PartialEq, Eq)] pub struct NbssRecord<'a> { pub message_type: u8, pub length: u32, - pub data: &'a[u8], + pub data: &'a [u8], } impl<'a> NbssRecord<'a> { pub fn is_valid(&self) -> bool { let valid = match self.message_type { - NBSS_MSGTYPE_SESSION_MESSAGE | - NBSS_MSGTYPE_SESSION_REQUEST | - NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE | - NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE | - NBSS_MSGTYPE_RETARG_RESPONSE | - NBSS_MSGTYPE_KEEP_ALIVE => true, + NBSS_MSGTYPE_SESSION_MESSAGE + | NBSS_MSGTYPE_SESSION_REQUEST + | NBSS_MSGTYPE_POSITIVE_SSN_RESPONSE + | NBSS_MSGTYPE_NEGATIVE_SSN_RESPONSE + | NBSS_MSGTYPE_RETARG_RESPONSE + | NBSS_MSGTYPE_KEEP_ALIVE => true, _ => false, }; valid @@ -52,8 +52,11 @@ impl<'a> NbssRecord<'a> { } pub fn is_smb(&self) -> bool { let valid = self.is_valid(); - let smb = self.data.len() >= 4 && - self.data[1] == b'S' && self.data[2] == b'M' && self.data[3] == b'B' && (self.data[0] == b'\xFE' || self.data[0] == b'\xFF' || self.data[0] == b'\xFD'); + let smb = self.data.len() >= 4 + && self.data[1] == b'S' + && self.data[2] == b'M' + && self.data[3] == b'B' + && (self.data[0] == b'\xFE' || self.data[0] == b'\xFF' || self.data[0] == b'\xFD'); valid && smb } @@ -93,19 +96,15 @@ mod tests { #[test] fn test_parse_nbss_record() { - let buff:&[u8] = &[ - /* message type */ 0x00, - /* length */ 0x00, 0x00, 0x55, - /* data */ 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, - 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, - 0x00, 0x80, 0x2a, 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, - 0x01, 0x2c, 0x01, 0x00, 0x10, 0x00, 0xfe, 0x82, 0xf1, - 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, - 0x54, 0xae, 0xb8, 0x66]; + let buff: &[u8] = &[ + /* message type */ 0x00, /* length */ 0x00, 0x00, 0x55, /* data */ 0xff, + 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, 0x00, 0x80, 0x2a, + 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, 0x01, 0x2c, 0x01, 0x00, 0x10, 0x00, 0xfe, 0x82, + 0xf1, 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, 0x54, 0xae, 0xb8, 0x66, + ]; let result = parse_nbss_record(buff); match result { @@ -136,19 +135,16 @@ mod tests { } // Non-SMB packet scenario - let buff_not_smb:&[u8] = &[ - /* message type */ 0x00, - /* length */ 0x00, 0x00, 0x55, - /* data !SMB */ 0xff, 0x52, 0x4e, 0x41, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x98, 0x53, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, - 0x0a, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe3, - 0x00, 0x80, 0x2a, 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, - 0x01, 0x2c, 0x01, 0x00, 0x10, 0x00, 0xfe, 0x82, 0xf1, - 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, - 0x54, 0xae, 0xb8, 0x66]; + let buff_not_smb: &[u8] = &[ + /* message type */ 0x00, /* length */ 0x00, 0x00, 0x55, + /* data !SMB */ 0xff, 0x52, 0x4e, 0x41, 0x72, 0x00, 0x00, 0x00, 0x00, 0x98, 0x53, + 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x11, 0x05, 0x00, 0x03, 0x0a, 0x00, 0x01, + 0x00, 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, + 0xe3, 0x00, 0x80, 0x2a, 0x55, 0xc4, 0x38, 0x89, 0x03, 0xcd, 0x01, 0x2c, 0x01, 0x00, + 0x10, 0x00, 0xfe, 0x82, 0xf1, 0x64, 0x0b, 0x66, 0xba, 0x4a, 0xbb, 0x81, 0xe1, 0xea, + 0x54, 0xae, 0xb8, 0x66, + ]; let result_not_smb = parse_nbss_record(buff_not_smb); match result_not_smb { @@ -182,14 +178,13 @@ mod tests { #[test] fn test_parse_nbss_record_partial() { - let buff:&[u8] = &[ - /* message type */ 0x00, - /* length */ 0x00, 0x00, 0x29, - /* data < length*/ 0xff, 0x53, 0x4d, 0x42, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x08, 0xbd, 0x20, 0x02, 0x08, 0x06, 0x00, - 0x02, 0x40, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00]; + let buff: &[u8] = &[ + /* message type */ 0x00, /* length */ 0x00, 0x00, 0x29, + /* data < length*/ 0xff, 0x53, 0x4d, 0x42, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x08, 0xbd, 0x20, 0x02, 0x08, 0x06, 0x00, 0x02, 0x40, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, + ]; let result = parse_nbss_record_partial(buff); match result { @@ -218,6 +213,5 @@ mod tests { panic!("Unexpected behavior!"); } } - } } diff --git a/rust/src/smb/session.rs b/rust/src/smb/session.rs index be7866976dc9..069cdf6be334 100644 --- a/rust/src/smb/session.rs +++ b/rust/src/smb/session.rs @@ -16,9 +16,9 @@ */ use crate::kerberos::*; +use crate::smb::auth::*; use crate::smb::smb::*; use crate::smb::smb1_session::*; -use crate::smb::auth::*; #[derive(Default, Debug)] pub struct SMBTransactionSessionSetup { @@ -30,19 +30,18 @@ pub struct SMBTransactionSessionSetup { impl SMBTransactionSessionSetup { pub fn new() -> Self { - return Default::default() + return Default::default(); } } impl SMBState { - pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) - -> &mut SMBTransaction - { + pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::SESSIONSETUP( - SMBTransactionSessionSetup::new())); + SMBTransactionSessionSetup::new(), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -52,14 +51,13 @@ impl SMBState { return tx_ref.unwrap(); } - pub fn get_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) - -> Option<&mut SMBTransaction> - { + pub fn get_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { - let hit = tx.hdr.compare(&hdr) && match tx.type_data { - Some(SMBTransactionTypeData::SESSIONSETUP(_)) => { true }, - _ => { false }, - }; + let hit = tx.hdr.compare(&hdr) + && match tx.type_data { + Some(SMBTransactionTypeData::SESSIONSETUP(_)) => true, + _ => false, + }; if hit { return Some(tx); } diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index d6b0a565c060..6362eb79b695 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -26,34 +26,34 @@ // written by Victor Julien use std; -use std::str; use std::ffi::{self, CString}; +use std::str; use std::collections::HashMap; use std::collections::VecDeque; - -use nom7::{Err, Needed}; + use nom7::error::{make_error, ErrorKind}; +use nom7::{Err, Needed}; -use crate::core::*; use crate::applayer; use crate::applayer::*; -use crate::frames::*; +use crate::applayer::{AppLayerEvent, AppLayerResult, AppLayerTxData}; use crate::conf::*; -use crate::applayer::{AppLayerResult, AppLayerTxData, AppLayerEvent}; +use crate::core::*; +use crate::frames::*; use crate::smb::nbss_records::*; use crate::smb::smb1_records::*; use crate::smb::smb2_records::*; -use crate::smb::smb1::*; -use crate::smb::smb2::*; -use crate::smb::smb3::*; use crate::smb::dcerpc::*; -use crate::smb::session::*; use crate::smb::events::*; use crate::smb::files::*; +use crate::smb::session::*; +use crate::smb::smb1::*; +use crate::smb::smb2::*; use crate::smb::smb2_ioctl::*; +use crate::smb::smb3::*; #[derive(AppLayerFrameType)] pub enum SMBFrameType { @@ -88,62 +88,70 @@ static mut SMB_MAX_TX: usize = 1024; pub static mut SURICATA_SMB_FILE_CONFIG: Option<&'static SuricataFileContext> = None; #[no_mangle] -pub extern "C" fn rs_smb_init(context: &'static mut SuricataFileContext) -{ +pub extern fn rs_smb_init(context: &'static mut SuricataFileContext) { unsafe { SURICATA_SMB_FILE_CONFIG = Some(context); } } -pub const SMB_SRV_ERROR: u16 = 1; -pub const SMB_SRV_BADPW: u16 = 2; -pub const SMB_SRV_BADTYPE: u16 = 3; -pub const SMB_SRV_ACCESS: u16 = 4; -pub const SMB_SRV_BADUID: u16 = 91; +pub const SMB_SRV_ERROR: u16 = 1; +pub const SMB_SRV_BADPW: u16 = 2; +pub const SMB_SRV_BADTYPE: u16 = 3; +pub const SMB_SRV_ACCESS: u16 = 4; +pub const SMB_SRV_BADUID: u16 = 91; pub fn smb_srv_error_string(c: u16) -> String { match c { - SMB_SRV_ERROR => "SRV_ERROR", - SMB_SRV_BADPW => "SRV_BADPW", - SMB_SRV_BADTYPE => "SRV_BADTYPE", - SMB_SRV_ACCESS => "SRV_ACCESS", - SMB_SRV_BADUID => "SRV_BADUID", - _ => { return (c).to_string(); }, - }.to_string() + SMB_SRV_ERROR => "SRV_ERROR", + SMB_SRV_BADPW => "SRV_BADPW", + SMB_SRV_BADTYPE => "SRV_BADTYPE", + SMB_SRV_ACCESS => "SRV_ACCESS", + SMB_SRV_BADUID => "SRV_BADUID", + _ => { + return (c).to_string(); + } + } + .to_string() } -pub const SMB_DOS_SUCCESS: u16 = 0; -pub const SMB_DOS_BAD_FUNC: u16 = 1; -pub const SMB_DOS_BAD_FILE: u16 = 2; -pub const SMB_DOS_BAD_PATH: u16 = 3; -pub const SMB_DOS_TOO_MANY_OPEN_FILES: u16 = 4; -pub const SMB_DOS_ACCESS_DENIED: u16 = 5; +pub const SMB_DOS_SUCCESS: u16 = 0; +pub const SMB_DOS_BAD_FUNC: u16 = 1; +pub const SMB_DOS_BAD_FILE: u16 = 2; +pub const SMB_DOS_BAD_PATH: u16 = 3; +pub const SMB_DOS_TOO_MANY_OPEN_FILES: u16 = 4; +pub const SMB_DOS_ACCESS_DENIED: u16 = 5; pub fn smb_dos_error_string(c: u16) -> String { match c { - SMB_DOS_SUCCESS => "DOS_SUCCESS", - SMB_DOS_BAD_FUNC => "DOS_BAD_FUNC", - SMB_DOS_BAD_FILE => "DOS_BAD_FILE", - SMB_DOS_BAD_PATH => "DOS_BAD_PATH", + SMB_DOS_SUCCESS => "DOS_SUCCESS", + SMB_DOS_BAD_FUNC => "DOS_BAD_FUNC", + SMB_DOS_BAD_FILE => "DOS_BAD_FILE", + SMB_DOS_BAD_PATH => "DOS_BAD_PATH", SMB_DOS_TOO_MANY_OPEN_FILES => "DOS_TOO_MANY_OPEN_FILES", - SMB_DOS_ACCESS_DENIED => "DOS_ACCESS_DENIED", - _ => { return (c).to_string(); }, - }.to_string() + SMB_DOS_ACCESS_DENIED => "DOS_ACCESS_DENIED", + _ => { + return (c).to_string(); + } + } + .to_string() } -pub const NTLMSSP_NEGOTIATE: u32 = 1; +pub const NTLMSSP_NEGOTIATE: u32 = 1; #[cfg(feature = "debug")] -pub const NTLMSSP_CHALLENGE: u32 = 2; -pub const NTLMSSP_AUTH: u32 = 3; +pub const NTLMSSP_CHALLENGE: u32 = 2; +pub const NTLMSSP_AUTH: u32 = 3; #[cfg(feature = "debug")] pub fn ntlmssp_type_string(c: u32) -> String { match c { - NTLMSSP_NEGOTIATE => "NTLMSSP_NEGOTIATE", - NTLMSSP_CHALLENGE => "NTLMSSP_CHALLENGE", - NTLMSSP_AUTH => "NTLMSSP_AUTH", - _ => { return (c).to_string(); }, - }.to_string() + NTLMSSP_NEGOTIATE => "NTLMSSP_NEGOTIATE", + NTLMSSP_CHALLENGE => "NTLMSSP_CHALLENGE", + NTLMSSP_AUTH => "NTLMSSP_AUTH", + _ => { + return (c).to_string(); + } + } + .to_string() } #[derive(Default, Eq, PartialEq, Debug, Clone)] @@ -167,7 +175,7 @@ impl SMBVerCmdStat { smb_ver: 1, smb1_cmd: cmd, ..Default::default() - } + }; } pub fn new1_with_ntstatus(cmd: u8, status: u32) -> Self { return Self { @@ -176,14 +184,14 @@ impl SMBVerCmdStat { status_set: true, status, ..Default::default() - } + }; } pub fn new2(cmd: u16) -> Self { return Self { smb_ver: 2, smb2_cmd: cmd, ..Default::default() - } + }; } pub fn new2_with_ntstatus(cmd: u16, status: u32) -> Self { @@ -193,7 +201,7 @@ impl SMBVerCmdStat { status_set: true, status, ..Default::default() - } + }; } pub fn set_smb1_cmd(&mut self, cmd: u8) -> bool { @@ -237,11 +245,14 @@ impl SMBVerCmdStat { } pub fn get_dos_error(&self) -> (bool, u8, u16) { - (self.status_set && self.status_is_dos_error, self.status_error_class, self.status as u16) + ( + self.status_set && self.status_is_dos_error, + self.status_error_class, + self.status as u16, + ) } - fn set_status(&mut self, status: u32, is_dos_error: bool) - { + fn set_status(&mut self, status: u32, is_dos_error: bool) { if is_dos_error { self.status_is_dos_error = true; self.status_error_class = (status & 0x0000_00ff) as u8; @@ -252,13 +263,11 @@ impl SMBVerCmdStat { self.status_set = true; } - pub fn set_ntstatus(&mut self, status: u32) - { + pub fn set_ntstatus(&mut self, status: u32) { self.set_status(status, false) } - pub fn set_status_dos_error(&mut self, status: u32) - { + pub fn set_status_dos_error(&mut self, status: u32) { self.set_status(status, true) } } @@ -268,14 +277,12 @@ impl SMBVerCmdStat { /// Coordinated Universal Time (UTC)." #[derive(Eq, PartialEq, Debug, Clone)] pub struct SMBFiletime { - ts: u64, + ts: u64, } impl SMBFiletime { pub fn new(raw: u64) -> Self { - Self { - ts: raw, - } + Self { ts: raw } } /// inspired by Bro, convert FILETIME to secs since unix epoch @@ -313,11 +320,12 @@ pub struct SMBTransactionSetFilePathInfo { } impl SMBTransactionSetFilePathInfo { - pub fn new(filename: Vec, fid: Vec, subcmd: u16, loi: u16, delete_on_close: bool) - -> Self - { + pub fn new( + filename: Vec, fid: Vec, subcmd: u16, loi: u16, delete_on_close: bool, + ) -> Self { return Self { - filename, fid, + filename, + fid, subcmd, loi, delete_on_close, @@ -326,15 +334,14 @@ impl SMBTransactionSetFilePathInfo { } impl SMBState { - pub fn new_setfileinfo_tx(&mut self, filename: Vec, fid: Vec, - subcmd: u16, loi: u16, delete_on_close: bool) - -> &mut SMBTransaction - { + pub fn new_setfileinfo_tx( + &mut self, filename: Vec, fid: Vec, subcmd: u16, loi: u16, delete_on_close: bool, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( - SMBTransactionSetFilePathInfo::new( - filename, fid, subcmd, loi, delete_on_close))); + SMBTransactionSetFilePathInfo::new(filename, fid, subcmd, loi, delete_on_close), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -344,16 +351,15 @@ impl SMBState { return tx_ref.unwrap(); } - pub fn new_setpathinfo_tx(&mut self, filename: Vec, - subcmd: u16, loi: u16, delete_on_close: bool) - -> &mut SMBTransaction - { + pub fn new_setpathinfo_tx( + &mut self, filename: Vec, subcmd: u16, loi: u16, delete_on_close: bool, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); - let fid : Vec = Vec::new(); + let fid: Vec = Vec::new(); tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( - SMBTransactionSetFilePathInfo::new(filename, fid, - subcmd, loi, delete_on_close))); + SMBTransactionSetFilePathInfo::new(filename, fid, subcmd, loi, delete_on_close), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -374,19 +380,22 @@ pub struct SMBTransactionRename { impl SMBTransactionRename { pub fn new(fuid: Vec, oldname: Vec, newname: Vec) -> Self { return Self { - fuid, oldname, newname, + fuid, + oldname, + newname, }; } } impl SMBState { - pub fn new_rename_tx(&mut self, fuid: Vec, oldname: Vec, newname: Vec) - -> &mut SMBTransaction - { + pub fn new_rename_tx( + &mut self, fuid: Vec, oldname: Vec, newname: Vec, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); - tx.type_data = Some(SMBTransactionTypeData::RENAME( - SMBTransactionRename::new(fuid, oldname, newname))); + tx.type_data = Some(SMBTransactionTypeData::RENAME(SMBTransactionRename::new( + fuid, oldname, newname, + ))); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -421,7 +430,7 @@ impl SMBTransactionCreate { directory: dir, filename, ..Default::default() - } + }; } } @@ -469,7 +478,8 @@ impl SMBTransactionTreeConnect { #[derive(Debug)] pub struct SMBTransaction { - pub id: u64, /// internal id + pub id: u64, + /// internal id /// version, command and status pub vercmd: SMBVerCmdStat, @@ -502,18 +512,17 @@ impl Default for SMBTransaction { impl SMBTransaction { pub fn new() -> Self { return Self { - id: 0, - vercmd: SMBVerCmdStat::new(), - hdr: SMBCommonHdr::default(), - request_done: false, - response_done: false, - type_data: None, - tx_data: AppLayerTxData::new(), - } + id: 0, + vercmd: SMBVerCmdStat::new(), + hdr: SMBCommonHdr::default(), + request_done: false, + response_done: false, + type_data: None, + tx_data: AppLayerTxData::new(), + }; } - pub fn set_status(&mut self, status: u32, is_dos_error: bool) - { + pub fn set_status(&mut self, status: u32, is_dos_error: bool) { if is_dos_error { self.vercmd.set_status_dos_error(status); } else { @@ -547,25 +556,22 @@ pub struct SMBFileGUIDOffset { impl SMBFileGUIDOffset { pub fn new(guid: Vec, offset: u64) -> Self { - Self { - guid, - offset, - } + Self { guid, offset } } } /// type values to make sure we're not mixing things /// up in hashmap lookups -pub const SMBHDR_TYPE_GUID: u32 = 1; -pub const SMBHDR_TYPE_SHARE: u32 = 2; -pub const SMBHDR_TYPE_FILENAME: u32 = 3; -pub const SMBHDR_TYPE_OFFSET: u32 = 4; -pub const SMBHDR_TYPE_GENERICTX: u32 = 5; -pub const SMBHDR_TYPE_HEADER: u32 = 6; +pub const SMBHDR_TYPE_GUID: u32 = 1; +pub const SMBHDR_TYPE_SHARE: u32 = 2; +pub const SMBHDR_TYPE_FILENAME: u32 = 3; +pub const SMBHDR_TYPE_OFFSET: u32 = 4; +pub const SMBHDR_TYPE_GENERICTX: u32 = 5; +pub const SMBHDR_TYPE_HEADER: u32 = 6; //unused pub const SMBHDR_TYPE_MAX_SIZE: u32 = 7; // max resp size for SMB1_COMMAND_TRANS -pub const SMBHDR_TYPE_TRANS_FRAG: u32 = 8; -pub const SMBHDR_TYPE_TREE: u32 = 9; -pub const SMBHDR_TYPE_DCERPCTX: u32 = 10; +pub const SMBHDR_TYPE_TRANS_FRAG: u32 = 8; +pub const SMBHDR_TYPE_TREE: u32 = 9; +pub const SMBHDR_TYPE_DCERPCTX: u32 = 10; #[derive(Default, Hash, Eq, PartialEq, Debug)] pub struct SMBCommonHdr { @@ -586,21 +592,20 @@ impl SMBCommonHdr { } pub fn from2(r: &Smb2Record, rec_type: u32) -> SMBCommonHdr { let tree_id = match rec_type { - SMBHDR_TYPE_TREE => { 0 }, + SMBHDR_TYPE_TREE => 0, _ => r.tree_id, }; let msg_id = match rec_type { - SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 }, - _ => { r.message_id }, + SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => 0, + _ => r.message_id, }; SMBCommonHdr { rec_type, - ssn_id : r.session_id, + ssn_id: r.session_id, tree_id, msg_id, } - } pub fn from2_notree(r: &Smb2Record, rec_type: u32) -> SMBCommonHdr { // async responses do not have a tree id (even if the request has it) @@ -609,30 +614,30 @@ impl SMBCommonHdr { // across all messages that are sent on the same SMB2 Protocol transport connection. // cf https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/ea4560b7-90da-4803-82b5-344754b92a79 let msg_id = match rec_type { - SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 }, - _ => { r.message_id }, + SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => 0, + _ => r.message_id, }; SMBCommonHdr { rec_type, - ssn_id : r.session_id, - tree_id : 0, + ssn_id: r.session_id, + tree_id: 0, msg_id, } } pub fn from1(r: &SmbRecord, rec_type: u32) -> SMBCommonHdr { let tree_id = match rec_type { - SMBHDR_TYPE_TREE => { 0 }, + SMBHDR_TYPE_TREE => 0, _ => r.tree_id as u32, }; let msg_id = match rec_type { - SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => { 0 }, - _ => { r.multiplex_id as u64 }, + SMBHDR_TYPE_TRANS_FRAG | SMBHDR_TYPE_SHARE => 0, + _ => r.multiplex_id as u64, }; SMBCommonHdr { rec_type, - ssn_id : r.ssn_id as u64, + ssn_id: r.ssn_id as u64, tree_id, msg_id, } @@ -640,8 +645,7 @@ impl SMBCommonHdr { // don't include tree id pub fn compare(&self, hdr: &SMBCommonHdr) -> bool { - self.rec_type == hdr.rec_type && self.ssn_id == hdr.ssn_id && - self.msg_id == hdr.msg_id + self.rec_type == hdr.rec_type && self.ssn_id == hdr.ssn_id && self.msg_id == hdr.msg_id } } @@ -653,9 +657,7 @@ pub struct SMBHashKeyHdrGuid { impl SMBHashKeyHdrGuid { pub fn new(hdr: SMBCommonHdr, guid: Vec) -> Self { - Self { - hdr, guid, - } + Self { hdr, guid } } } @@ -667,23 +669,20 @@ pub struct SMBTree { impl SMBTree { pub fn new(name: Vec, is_pipe: bool) -> Self { - Self { - name, - is_pipe, - } + Self { name, is_pipe } } } -pub fn u32_as_bytes(i: u32) -> [u8;4] { +pub fn u32_as_bytes(i: u32) -> [u8; 4] { let o1: u8 = ((i >> 24) & 0xff) as u8; let o2: u8 = ((i >> 16) & 0xff) as u8; - let o3: u8 = ((i >> 8) & 0xff) as u8; - let o4: u8 = (i & 0xff) as u8; - return [o1, o2, o3, o4] + let o3: u8 = ((i >> 8) & 0xff) as u8; + let o4: u8 = (i & 0xff) as u8; + return [o1, o2, o3, o4]; } #[derive(Default, Debug)] -pub struct SMBState<> { +pub struct SMBState { pub state_data: AppLayerStateData, /// map ssn/tree/msgid to vec (guid/name/share) @@ -702,10 +701,10 @@ pub struct SMBState<> { skip_ts: u32, skip_tc: u32, - pub file_ts_left : u32, - pub file_tc_left : u32, - pub file_ts_guid : Vec, - pub file_tc_guid : Vec, + pub file_ts_left: u32, + pub file_tc_left: u32, + pub file_ts_guid: Vec, + pub file_tc_guid: Vec, pub ts_ssn_gap: bool, pub tc_ssn_gap: bool, @@ -759,18 +758,18 @@ impl SMBState { /// Allocation function for a new TLS parser instance pub fn new() -> Self { Self { - state_data:AppLayerStateData::new(), - ssn2vec_map:HashMap::new(), - guid2name_map:HashMap::new(), - ssn2vecoffset_map:HashMap::new(), - ssn2tree_map:HashMap::new(), - ssnguid2vec_map:HashMap::new(), - skip_ts:0, - skip_tc:0, - file_ts_left:0, - file_tc_left:0, - file_ts_guid:Vec::new(), - file_tc_guid:Vec::new(), + state_data: AppLayerStateData::new(), + ssn2vec_map: HashMap::new(), + guid2name_map: HashMap::new(), + ssn2vecoffset_map: HashMap::new(), + ssn2tree_map: HashMap::new(), + ssnguid2vec_map: HashMap::new(), + skip_ts: 0, + skip_tc: 0, + file_ts_left: 0, + file_tc_left: 0, + file_ts_guid: Vec::new(), + file_tc_guid: Vec::new(), ts_ssn_gap: false, tc_ssn_gap: false, ts_gap: false, @@ -781,8 +780,8 @@ impl SMBState { post_gap_files_checked: false, transactions: VecDeque::new(), tx_index_completed: 0, - tx_id:0, - dialect:0, + tx_id: 0, + dialect: 0, dialect_vec: None, dcerpc_ifaces: None, ts: 0, @@ -812,13 +811,12 @@ impl SMBState { } } self.tx_index_completed = index; - } return tx; } pub fn free_tx(&mut self, tx_id: u64) { - SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id+1); + SCLogDebug!("Freeing TX with ID {} TX.ID {}", tx_id, tx_id + 1); let len = self.transactions.len(); let mut found = false; let mut index = 0; @@ -827,26 +825,37 @@ impl SMBState { if tx.id == tx_id + 1 { found = true; index = i; - SCLogDebug!("tx {} progress {}/{}", tx.id, tx.request_done, tx.response_done); + SCLogDebug!( + "tx {} progress {}/{}", + tx.id, + tx.request_done, + tx.response_done + ); break; } } if found { - SCLogDebug!("freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", - tx_id, tx_id+1, index, self.transactions.len(), self.tx_id); + SCLogDebug!( + "freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", + tx_id, + tx_id + 1, + index, + self.transactions.len(), + self.tx_id + ); self.tx_index_completed = 0; self.transactions.remove(index); } } pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&SMBTransaction> { -/* - if self.transactions.len() > 100 { - SCLogNotice!("get_tx_by_id: tx_id={} in list={}", tx_id, self.transactions.len()); - self._dump_txs(); - panic!("txs exploded"); - } -*/ + /* + if self.transactions.len() > 100 { + SCLogNotice!("get_tx_by_id: tx_id={} in list={}", tx_id, self.transactions.len()); + self._dump_txs(); + panic!("txs exploded"); + } + */ for tx in &mut self.transactions { if tx.id == tx_id + 1 { let ver = tx.vercmd.get_version(); @@ -858,8 +867,15 @@ impl SMBState { let (_, cmd) = tx.vercmd.get_smb1_cmd(); _smbcmd = cmd as u16; } - SCLogDebug!("Found SMB TX: id {} ver:{} cmd:{} progress {}/{} type_data {:?}", - tx.id, ver, _smbcmd, tx.request_done, tx.response_done, tx.type_data); + SCLogDebug!( + "Found SMB TX: id {} ver:{} cmd:{} progress {}/{} type_data {:?}", + tx.id, + ver, + _smbcmd, + tx.request_done, + tx.response_done, + tx.type_data + ); /* hack: apply flow file flags to file tx here to make sure its propagated */ if let Some(SMBTransactionTypeData::FILE(ref mut d)) = tx.type_data { tx.tx_data.update_file_flags(self.state_data.file_flags); @@ -882,9 +898,9 @@ impl SMBState { /* generic TX has no type_data and is only used to * track a single cmd request/reply pair. */ - pub fn new_generic_tx(&mut self, smb_ver: u8, smb_cmd: u16, key: SMBCommonHdr) - -> &mut SMBTransaction - { + pub fn new_generic_tx( + &mut self, smb_ver: u8, smb_cmd: u16, key: SMBCommonHdr, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); if smb_ver == 1 && smb_cmd <= 255 { tx.vercmd.set_smb1_cmd(smb_cmd as u8); @@ -897,16 +913,18 @@ impl SMBState { tx.response_done = self.tc_trunc; // no response expected if tc is truncated tx.hdr = key; - SCLogDebug!("SMB: TX GENERIC created: ID {} tx list {} {:?}", - tx.id, self.transactions.len(), &tx); + SCLogDebug!( + "SMB: TX GENERIC created: ID {} tx list {} {:?}", + tx.id, + self.transactions.len(), + &tx + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); } - pub fn get_last_tx(&mut self, smb_ver: u8, smb_cmd: u16) - -> Option<&mut SMBTransaction> - { + pub fn get_last_tx(&mut self, smb_ver: u8, smb_cmd: u16) -> Option<&mut SMBTransaction> { let tx_ref = self.transactions.back_mut(); if let Some(tx) = tx_ref { let found = if tx.vercmd.get_version() == smb_ver { @@ -929,9 +947,9 @@ impl SMBState { return None; } - pub fn get_generic_tx(&mut self, smb_ver: u8, smb_cmd: u16, key: &SMBCommonHdr) - -> Option<&mut SMBTransaction> - { + pub fn get_generic_tx( + &mut self, smb_ver: u8, smb_cmd: u16, key: &SMBCommonHdr, + ) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { let found = if tx.vercmd.get_version() == smb_ver { if smb_ver == 1 { @@ -953,9 +971,7 @@ impl SMBState { return None; } - pub fn new_negotiate_tx(&mut self, smb_ver: u8) - -> &mut SMBTransaction - { + pub fn new_negotiate_tx(&mut self, smb_ver: u8) -> &mut SMBTransaction { let mut tx = self.new_tx(); if smb_ver == 1 { tx.vercmd.set_smb1_cmd(SMB1_COMMAND_NEGOTIATE_PROTOCOL); @@ -964,25 +980,26 @@ impl SMBState { } tx.type_data = Some(SMBTransactionTypeData::NEGOTIATE( - SMBTransactionNegotiate::new(smb_ver))); + SMBTransactionNegotiate::new(smb_ver), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated - SCLogDebug!("SMB: TX NEGOTIATE created: ID {} SMB ver {}", tx.id, smb_ver); + SCLogDebug!( + "SMB: TX NEGOTIATE created: ID {} SMB ver {}", + tx.id, + smb_ver + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); } - pub fn get_negotiate_tx(&mut self, smb_ver: u8) - -> Option<&mut SMBTransaction> - { + pub fn get_negotiate_tx(&mut self, smb_ver: u8) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { let found = match tx.type_data { - Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => { - x.smb_ver == smb_ver - }, - _ => { false }, + Some(SMBTransactionTypeData::NEGOTIATE(ref x)) => x.smb_ver == smb_ver, + _ => false, }; if found { return Some(tx); @@ -991,32 +1008,33 @@ impl SMBState { return None; } - pub fn new_treeconnect_tx(&mut self, hdr: SMBCommonHdr, name: Vec) - -> &mut SMBTransaction - { + pub fn new_treeconnect_tx(&mut self, hdr: SMBCommonHdr, name: Vec) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::TREECONNECT( - SMBTransactionTreeConnect::new(name.to_vec()))); + SMBTransactionTreeConnect::new(name.to_vec()), + )); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated - SCLogDebug!("SMB: TX TREECONNECT created: ID {} NAME {}", - tx.id, String::from_utf8_lossy(&name)); + SCLogDebug!( + "SMB: TX TREECONNECT created: ID {} NAME {}", + tx.id, + String::from_utf8_lossy(&name) + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); } - pub fn get_treeconnect_tx(&mut self, hdr: SMBCommonHdr) - -> Option<&mut SMBTransaction> - { + pub fn get_treeconnect_tx(&mut self, hdr: SMBCommonHdr) -> Option<&mut SMBTransaction> { for tx in &mut self.transactions { - let hit = tx.hdr.compare(&hdr) && match tx.type_data { - Some(SMBTransactionTypeData::TREECONNECT(_)) => { true }, - _ => { false }, - }; + let hit = tx.hdr.compare(&hdr) + && match tx.type_data { + Some(SMBTransactionTypeData::TREECONNECT(_)) => true, + _ => false, + }; if hit { return Some(tx); } @@ -1024,17 +1042,17 @@ impl SMBState { return None; } - pub fn new_create_tx(&mut self, file_name: &[u8], - disposition: u32, del: bool, dir: bool, - hdr: SMBCommonHdr) - -> &mut SMBTransaction - { + pub fn new_create_tx( + &mut self, file_name: &[u8], disposition: u32, del: bool, dir: bool, hdr: SMBCommonHdr, + ) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; - tx.type_data = Some(SMBTransactionTypeData::CREATE( - SMBTransactionCreate::new( - file_name.to_vec(), disposition, - del, dir))); + tx.type_data = Some(SMBTransactionTypeData::CREATE(SMBTransactionCreate::new( + file_name.to_vec(), + disposition, + del, + dir, + ))); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated @@ -1043,8 +1061,7 @@ impl SMBState { return tx_ref.unwrap(); } - pub fn get_service_for_guid(&self, guid: &[u8]) -> (&'static str, bool) - { + pub fn get_service_for_guid(&self, guid: &[u8]) -> (&'static str, bool) { let (name, is_dcerpc) = match self.guid2name_map.get(&guid.to_vec()) { Some(n) => { let mut s = n.as_slice(); @@ -1066,17 +1083,16 @@ impl SMBState { Ok(&_) => { SCLogDebug!("don't know {}", String::from_utf8_lossy(n)); ("UNKNOWN", false) - }, + } } - }, - _ => { ("UNKNOWN", false) }, + } + _ => ("UNKNOWN", false), }; SCLogDebug!("service {} is_dcerpc {}", name, is_dcerpc); (name, is_dcerpc) } - fn post_gap_housekeeping_for_files(&mut self) - { + fn post_gap_housekeeping_for_files(&mut self) { let mut post_gap_txs = false; for tx in &mut self.transactions { if let Some(SMBTransactionTypeData::FILE(ref mut f)) = tx.type_data { @@ -1099,8 +1115,7 @@ impl SMBState { * can handle gaps. For the file transactions we set the current * (flow) time and prune them in 60 seconds if no update for them * was received. */ - fn post_gap_housekeeping(&mut self, dir: Direction) - { + fn post_gap_housekeeping(&mut self, dir: Direction) { if self.ts_ssn_gap && dir == Direction::ToServer { for tx in &mut self.transactions { if tx.id >= self.tx_id { @@ -1138,12 +1153,12 @@ impl SMBState { tx.response_done = true; } } - } } - pub fn set_file_left(&mut self, direction: Direction, rec_size: u32, data_size: u32, fuid: Vec) - { + pub fn set_file_left( + &mut self, direction: Direction, rec_size: u32, data_size: u32, fuid: Vec, + ) { let left = rec_size.saturating_sub(data_size); if direction == Direction::ToServer { self.file_ts_left = left; @@ -1154,8 +1169,7 @@ impl SMBState { } } - pub fn set_skip(&mut self, direction: Direction, nbss_remaining: u32) - { + pub fn set_skip(&mut self, direction: Direction, nbss_remaining: u32) { if direction == Direction::ToServer { self.skip_ts = nbss_remaining; } else { @@ -1171,7 +1185,7 @@ impl SMBState { self.skip_tc }; if skip_left == 0 { - return 0 + return 0; } SCLogDebug!("skip_left {} input_size {}", skip_left, input_size); @@ -1195,61 +1209,149 @@ impl SMBState { return consumed; } - fn add_nbss_ts_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option, Option, Option) { - let nbss_pdu = Frame::new(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8); + fn add_nbss_ts_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> (Option, Option, Option) { + let nbss_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len + 4, + SMBFrameType::NBSSPdu as u8, + ); SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu); - let nbss_hdr_frame = Frame::new(flow, stream_slice, input, 4_i64, SMBFrameType::NBSSHdr as u8); + let nbss_hdr_frame = Frame::new( + flow, + stream_slice, + input, + 4_i64, + SMBFrameType::NBSSHdr as u8, + ); SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame); - let nbss_data_frame = Frame::new(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8); + let nbss_data_frame = Frame::new( + flow, + stream_slice, + &input[4..], + nbss_len, + SMBFrameType::NBSSData as u8, + ); SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame); (nbss_pdu, nbss_hdr_frame, nbss_data_frame) } - fn add_smb1_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8); + fn add_smb1_ts_pdu_frame( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB1Pdu as u8, + ); SCLogDebug!("SMB PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb1_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb1_hdr = Frame::new(flow, stream_slice, input, 32_i64, SMBFrameType::SMB1Hdr as u8); + fn add_smb1_ts_hdr_data_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb1_hdr = Frame::new( + flow, + stream_slice, + input, + 32_i64, + SMBFrameType::SMB1Hdr as u8, + ); SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr); if input.len() > 32 { - let _smb1_data = Frame::new(flow, stream_slice, &input[32..], nbss_len - 32, SMBFrameType::SMB1Data as u8); + let _smb1_data = Frame::new( + flow, + stream_slice, + &input[32..], + nbss_len - 32, + SMBFrameType::SMB1Data as u8, + ); SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data); } } - fn add_smb2_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8); + fn add_smb2_ts_pdu_frame( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB2Pdu as u8, + ); SCLogDebug!("SMBv2 PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb2_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) { - let _smb2_hdr = Frame::new(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8); + fn add_smb2_ts_hdr_data_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + hdr_len: i64, + ) { + let _smb2_hdr = Frame::new( + flow, + stream_slice, + input, + hdr_len, + SMBFrameType::SMB2Hdr as u8, + ); SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr); if input.len() > hdr_len as usize { - let _smb2_data = Frame::new(flow, stream_slice, &input[hdr_len as usize..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8); + let _smb2_data = Frame::new( + flow, + stream_slice, + &input[hdr_len as usize..], + nbss_len - hdr_len, + SMBFrameType::SMB2Data as u8, + ); SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data); } } - fn add_smb3_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8); + fn add_smb3_ts_pdu_frame( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB3Pdu as u8, + ); SCLogDebug!("SMBv3 PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb3_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb3_hdr = Frame::new(flow, stream_slice, input, 52_i64, SMBFrameType::SMB3Hdr as u8); + fn add_smb3_ts_hdr_data_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb3_hdr = Frame::new( + flow, + stream_slice, + input, + 52_i64, + SMBFrameType::SMB3Hdr as u8, + ); SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr); if input.len() > 52 { - let _smb3_data = Frame::new(flow, stream_slice, &input[52..], nbss_len - 52, SMBFrameType::SMB3Data as u8); + let _smb3_data = Frame::new( + flow, + stream_slice, + &input[52..], + nbss_len - 52, + SMBFrameType::SMB3Data as u8, + ); SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data); } } /// return bytes consumed - pub fn parse_tcp_data_ts_partial(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8]) -> usize - { + pub fn parse_tcp_data_ts_partial( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], + ) -> usize { SCLogDebug!("incomplete of size {}", input.len()); if input.len() < 512 { // check for malformed data. Wireshark reports as @@ -1258,7 +1360,10 @@ impl SMBState { if input.len() > 8 { if let Ok((_, ref hdr)) = parse_nbss_record_partial(input) { if !hdr.is_smb() { - SCLogDebug!("partial NBSS, not SMB and no known msg type {}", hdr.message_type); + SCLogDebug!( + "partial NBSS, not SMB and no known msg type {}", + hdr.message_type + ); self.trunc_ts(); return 0; } @@ -1272,14 +1377,19 @@ impl SMBState { if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE { if let Ok((_, ref smb)) = parse_smb_version(nbss_part_hdr.data) { SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); if let Ok((_, ref r)) = parse_smb_record(nbss_part_hdr.data) { if r.command == SMB1_COMMAND_WRITE_ANDX { // see if it's a write to a pipe. We only handle those // if complete. - let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE, - r.ssn_id as u64, r.tree_id as u32, 0); + let tree_key = SMBCommonHdr::new( + SMBHDR_TYPE_SHARE, + r.ssn_id as u64, + r.tree_id as u32, + 0, + ); let is_pipe = match self.ssn2tree_map.get(&tree_key) { Some(n) => n.is_pipe, None => false, @@ -1290,33 +1400,77 @@ impl SMBState { // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; - smb1_write_request_record(self, r, SMB1_HEADER_SIZE, SMB1_COMMAND_WRITE_ANDX, nbss_remaining); + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + smb1_write_request_record( + self, + r, + SMB1_HEADER_SIZE, + SMB1_COMMAND_WRITE_ANDX, + nbss_remaining, + ); + + self.add_nbss_ts_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb1_ts_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb1_ts_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); - self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - let consumed = input.len() - output.len(); return consumed; } } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 SCLogDebug!("SMBv2 record"); - if let Ok((_, ref smb_record)) = parse_smb2_request_record(nbss_part_hdr.data) { - SCLogDebug!("SMB2: partial record {}", - &smb2_command_string(smb_record.command)); + if let Ok((_, ref smb_record)) = + parse_smb2_request_record(nbss_part_hdr.data) + { + SCLogDebug!( + "SMB2: partial record {}", + &smb2_command_string(smb_record.command) + ); if smb_record.command == SMB2_COMMAND_WRITE { // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; smb2_write_request_record(self, smb_record, nbss_remaining); - self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64); - + self.add_nbss_ts_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb2_ts_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb2_ts_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + smb_record.header_len as i64, + ); + let consumed = input.len() - output.len(); SCLogDebug!("consumed {}", consumed); return consumed; @@ -1332,8 +1486,9 @@ impl SMBState { } /// Parsing function, handling TCP chunks fragmentation - pub fn parse_tcp_data_ts(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult - { + pub fn parse_tcp_data_ts( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let mut cur_i = stream_slice.as_slice(); let consumed = self.handle_skip(Direction::ToServer, cur_i.len() as u32); if consumed > 0 { @@ -1359,13 +1514,14 @@ impl SMBState { // gap if self.ts_gap { SCLogDebug!("TS trying to catch up after GAP (input {})", cur_i.len()); - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match search_smb_record(cur_i) { Ok((_, pg)) => { SCLogDebug!("smb record found"); let smb2_offset = cur_i.len() - pg.len(); if smb2_offset < 4 { - cur_i = &cur_i[smb2_offset+4..]; + cur_i = &cur_i[smb2_offset + 4..]; continue; // see if we have another record in our data } let nbss_offset = smb2_offset - 4; @@ -1373,7 +1529,7 @@ impl SMBState { self.ts_gap = false; break; - }, + } _ => { let mut consumed = stream_slice.len(); if consumed < 4 { @@ -1383,113 +1539,174 @@ impl SMBState { } SCLogDebug!("smb record NOT found"); return AppLayerResult::incomplete(consumed, 8); - }, + } } } } - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match parse_nbss_record(cur_i) { Ok((rem, ref nbss_hdr)) => { - SCLogDebug!("nbss frame offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len()); - let (_, _, nbss_data_frame) = self.add_nbss_ts_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64); + SCLogDebug!( + "nbss frame offset {} len {}", + stream_slice.offset_from(cur_i), + cur_i.len() - rem.len() + ); + let (_, _, nbss_data_frame) = + self.add_nbss_ts_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64); if nbss_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE { // we have the full records size worth of data, // let's parse it match parse_smb_version(nbss_hdr.data) { Ok((_, ref smb)) => { - SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); match parse_smb_record(nbss_hdr.data) { Ok((_, ref smb_record)) => { - let pdu_frame = self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); - self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); + let pdu_frame = self.add_smb1_ts_pdu_frame( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); + self.add_smb1_ts_hdr_data_frames( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); if smb_record.is_request() { smb1_request_record(self, smb_record); } else { // If we received a response when expecting a request, set an event // on the PDU frame instead of handling the response. - SCLogDebug!("SMB1 reply seen from client to server"); + SCLogDebug!( + "SMB1 reply seen from client to server" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::ResponseToServer as u8); + frame.add_event( + flow, + SMBEvent::ResponseToServer as u8, + ); } } - }, + } _ => { if let Some(frame) = nbss_data_frame { - frame.add_event(flow, SMBEvent::MalformedData as u8); + frame + .add_event(flow, SMBEvent::MalformedData as u8); } self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv2 record"); match parse_smb2_request_record(nbss_data) { Ok((nbss_data_rem, ref smb_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - let pdu_frame = self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64); - SCLogDebug!("nbss_data_rem {}", nbss_data_rem.len()); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + let pdu_frame = self.add_smb2_ts_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb2_ts_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + smb_record.header_len as i64, + ); + SCLogDebug!( + "nbss_data_rem {}", + nbss_data_rem.len() + ); if smb_record.is_request() { smb2_request_record(self, smb_record); } else { // If we received a response when expecting a request, set an event // on the PDU frame instead of handling the response. - SCLogDebug!("SMB2 reply seen from client to server"); + SCLogDebug!( + "SMB2 reply seen from client to server" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::ResponseToServer as u8); + frame.add_event( + flow, + SMBEvent::ResponseToServer as u8, + ); } } nbss_data = nbss_data_rem; - }, + } _ => { if let Some(frame) = nbss_data_frame { - frame.add_event(flow, SMBEvent::MalformedData as u8); + frame.add_event( + flow, + SMBEvent::MalformedData as u8, + ); } self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } - } else if smb.version == 0xfd_u8 { // SMB3 transform + } else if smb.version == 0xfd_u8 { + // SMB3 transform let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv3 transform record"); match parse_smb3_transform_record(nbss_data) { Ok((nbss_data_rem, ref _smb3_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - self.add_smb3_ts_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb3_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + self.add_smb3_ts_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb3_ts_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + ); nbss_data = nbss_data_rem; - }, + } _ => { if let Some(frame) = nbss_data_frame { - frame.add_event(flow, SMBEvent::MalformedData as u8); + frame.add_event( + flow, + SMBEvent::MalformedData as u8, + ); } self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } } - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } else { SCLogDebug!("NBSS message {:X}", nbss_hdr.message_type); } cur_i = rem; - }, + } Err(Err::Incomplete(needed)) => { if let Needed::Size(n) = needed { let n = usize::from(n) + cur_i.len(); @@ -1502,8 +1719,13 @@ impl SMBState { if consumed == 0 { // if we consumed none we will buffer the entire record let total_consumed = stream_slice.offset_from(cur_i); - SCLogDebug!("setting consumed {} need {} needed {:?} total input {}", - total_consumed, n, needed, stream_slice.len()); + SCLogDebug!( + "setting consumed {} need {} needed {:?} total input {}", + total_consumed, + n, + needed, + stream_slice.len() + ); let need = n; return AppLayerResult::incomplete(total_consumed, need as u32); } @@ -1515,13 +1737,13 @@ impl SMBState { self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } - }, + } Err(_) => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - }; + } self.post_gap_housekeeping(Direction::ToServer); if self.check_post_gap_file_txs && !self.post_gap_files_checked { @@ -1531,61 +1753,148 @@ impl SMBState { AppLayerResult::ok() } - fn add_nbss_tc_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option, Option, Option) { - let nbss_pdu = Frame::new(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8); + fn add_nbss_tc_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> (Option, Option, Option) { + let nbss_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len + 4, + SMBFrameType::NBSSPdu as u8, + ); SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu); - let nbss_hdr_frame = Frame::new(flow, stream_slice, input, 4_i64, SMBFrameType::NBSSHdr as u8); + let nbss_hdr_frame = Frame::new( + flow, + stream_slice, + input, + 4_i64, + SMBFrameType::NBSSHdr as u8, + ); SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame); - let nbss_data_frame = Frame::new(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8); + let nbss_data_frame = Frame::new( + flow, + stream_slice, + &input[4..], + nbss_len, + SMBFrameType::NBSSData as u8, + ); SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame); (nbss_pdu, nbss_hdr_frame, nbss_data_frame) } - fn add_smb1_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8); + fn add_smb1_tc_pdu_frame( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB1Pdu as u8, + ); SCLogDebug!("SMB PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb1_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb1_hdr = Frame::new(flow, stream_slice, input, SMB1_HEADER_SIZE as i64, SMBFrameType::SMB1Hdr as u8); + fn add_smb1_tc_hdr_data_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb1_hdr = Frame::new( + flow, + stream_slice, + input, + SMB1_HEADER_SIZE as i64, + SMBFrameType::SMB1Hdr as u8, + ); SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr); if input.len() > SMB1_HEADER_SIZE { - let _smb1_data = Frame::new(flow, stream_slice, &input[SMB1_HEADER_SIZE..], nbss_len - SMB1_HEADER_SIZE as i64, - SMBFrameType::SMB1Data as u8); + let _smb1_data = Frame::new( + flow, + stream_slice, + &input[SMB1_HEADER_SIZE..], + nbss_len - SMB1_HEADER_SIZE as i64, + SMBFrameType::SMB1Data as u8, + ); SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data); } } - fn add_smb2_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option { - let smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8); + fn add_smb2_tc_pdu_frame( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) -> Option { + let smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB2Pdu as u8, + ); SCLogDebug!("SMBv2 PDU frame {:?}", smb_pdu); smb_pdu } - fn add_smb2_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) { - let _smb2_hdr = Frame::new(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8); + fn add_smb2_tc_hdr_data_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + hdr_len: i64, + ) { + let _smb2_hdr = Frame::new( + flow, + stream_slice, + input, + hdr_len, + SMBFrameType::SMB2Hdr as u8, + ); SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr); if input.len() > hdr_len as usize { - let _smb2_data = Frame::new(flow, stream_slice, &input[hdr_len as usize ..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8); + let _smb2_data = Frame::new( + flow, + stream_slice, + &input[hdr_len as usize..], + nbss_len - hdr_len, + SMBFrameType::SMB2Data as u8, + ); SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data); } } - fn add_smb3_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb_pdu = Frame::new(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8); + fn add_smb3_tc_pdu_frame( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb_pdu = Frame::new( + flow, + stream_slice, + input, + nbss_len, + SMBFrameType::SMB3Pdu as u8, + ); SCLogDebug!("SMBv3 PDU frame {:?}", _smb_pdu); } - fn add_smb3_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) { - let _smb3_hdr = Frame::new(flow, stream_slice, input, 52_i64, SMBFrameType::SMB3Hdr as u8); + fn add_smb3_tc_hdr_data_frames( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, + ) { + let _smb3_hdr = Frame::new( + flow, + stream_slice, + input, + 52_i64, + SMBFrameType::SMB3Hdr as u8, + ); SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr); if input.len() > 52 { - let _smb3_data = Frame::new(flow, stream_slice, &input[52..], nbss_len - 52, SMBFrameType::SMB3Data as u8); + let _smb3_data = Frame::new( + flow, + stream_slice, + &input[52..], + nbss_len - 52, + SMBFrameType::SMB3Data as u8, + ); SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data); } } /// return bytes consumed - pub fn parse_tcp_data_tc_partial(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8]) -> usize - { + pub fn parse_tcp_data_tc_partial( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], + ) -> usize { SCLogDebug!("incomplete of size {}", input.len()); if input.len() < 512 { // check for malformed data. Wireshark reports as @@ -1594,7 +1903,10 @@ impl SMBState { if input.len() > 8 { if let Ok((_, ref hdr)) = parse_nbss_record_partial(input) { if !hdr.is_smb() { - SCLogDebug!("partial NBSS, not SMB and no known msg type {}", hdr.message_type); + SCLogDebug!( + "partial NBSS, not SMB and no known msg type {}", + hdr.message_type + ); self.trunc_tc(); return 0; } @@ -1608,17 +1920,21 @@ impl SMBState { if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE { if let Ok((_, ref smb)) = parse_smb_version(nbss_part_hdr.data) { SCLogDebug!("SMB {:?}", smb); - if smb.version == 255u8 { // SMB1 + if smb.version == 255u8 { + // SMB1 SCLogDebug!("SMBv1 record"); if let Ok((_, ref r)) = parse_smb_record(nbss_part_hdr.data) { - SCLogDebug!("SMB1: partial record {}", - r.command); + SCLogDebug!("SMB1: partial record {}", r.command); if r.command == SMB1_COMMAND_READ_ANDX { - let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE, - r.ssn_id as u64, r.tree_id as u32, 0); + let tree_key = SMBCommonHdr::new( + SMBHDR_TYPE_SHARE, + r.ssn_id as u64, + r.tree_id as u32, + 0, + ); let is_pipe = match self.ssn2tree_map.get(&tree_key) { Some(n) => n.is_pipe, - None => false, + None => false, }; if is_pipe { return 0; @@ -1626,35 +1942,78 @@ impl SMBState { // create NBSS frames here so we don't get double frames // when we don't consume the data now. - self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); + self.add_nbss_tc_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb1_tc_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb1_tc_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; - smb1_read_response_record(self, r, SMB1_HEADER_SIZE, nbss_remaining); + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + smb1_read_response_record( + self, + r, + SMB1_HEADER_SIZE, + nbss_remaining, + ); let consumed = input.len() - output.len(); return consumed; } } - } else if smb.version == 254u8 { // SMB2 + } else if smb.version == 254u8 { + // SMB2 SCLogDebug!("SMBv2 record"); - if let Ok((_, ref smb_record)) = parse_smb2_response_record(nbss_part_hdr.data) { - SCLogDebug!("SMB2: partial record {}", - &smb2_command_string(smb_record.command)); + if let Ok((_, ref smb_record)) = + parse_smb2_response_record(nbss_part_hdr.data) + { + SCLogDebug!( + "SMB2: partial record {}", + &smb2_command_string(smb_record.command) + ); if smb_record.command == SMB2_COMMAND_READ { // create NBSS frames here so we don't get double frames // when we don't consume the data now. - self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64); - self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64); - self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64); + self.add_nbss_tc_frames( + flow, + stream_slice, + input, + nbss_part_hdr.length as i64, + ); + self.add_smb2_tc_pdu_frame( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + ); + self.add_smb2_tc_hdr_data_frames( + flow, + stream_slice, + nbss_part_hdr.data, + nbss_part_hdr.length as i64, + smb_record.header_len as i64, + ); // how many more bytes are expected within this NBSS record // So that we can check that further parsed offsets and lengths // stay within the NBSS record. - let nbss_remaining = nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; + let nbss_remaining = + nbss_part_hdr.length - nbss_part_hdr.data.len() as u32; smb2_read_response_record(self, smb_record, nbss_remaining); let consumed = input.len() - output.len(); return consumed; @@ -1669,8 +2028,9 @@ impl SMBState { } /// Parsing function, handling TCP chunks fragmentation - pub fn parse_tcp_data_tc(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult - { + pub fn parse_tcp_data_tc( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, + ) -> AppLayerResult { let mut cur_i = stream_slice.as_slice(); let consumed = self.handle_skip(Direction::ToClient, cur_i.len() as u32); if consumed > 0 { @@ -1696,13 +2056,14 @@ impl SMBState { // gap if self.tc_gap { SCLogDebug!("TC trying to catch up after GAP (input {})", cur_i.len()); - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match search_smb_record(cur_i) { Ok((_, pg)) => { SCLogDebug!("smb record found"); let smb2_offset = cur_i.len() - pg.len(); if smb2_offset < 4 { - cur_i = &cur_i[smb2_offset+4..]; + cur_i = &cur_i[smb2_offset + 4..]; continue; // see if we have another record in our data } let nbss_offset = smb2_offset - 4; @@ -1710,7 +2071,7 @@ impl SMBState { self.tc_gap = false; break; - }, + } _ => { let mut consumed = stream_slice.len(); if consumed < 4 { @@ -1720,14 +2081,19 @@ impl SMBState { } SCLogDebug!("smb record NOT found"); return AppLayerResult::incomplete(consumed, 8); - }, + } } } } - while !cur_i.is_empty() { // min record size + while !cur_i.is_empty() { + // min record size match parse_nbss_record(cur_i) { Ok((rem, ref nbss_hdr)) => { - SCLogDebug!("nbss record offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len()); + SCLogDebug!( + "nbss record offset {} len {}", + stream_slice.offset_from(cur_i), + cur_i.len() - rem.len() + ); self.add_nbss_tc_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64); SCLogDebug!("nbss frames added"); @@ -1737,84 +2103,130 @@ impl SMBState { match parse_smb_version(nbss_hdr.data) { Ok((_, ref smb)) => { SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); match parse_smb_record(nbss_hdr.data) { Ok((_, ref smb_record)) => { - let pdu_frame = self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); - self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64); + let pdu_frame = self.add_smb1_tc_pdu_frame( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); + self.add_smb1_tc_hdr_data_frames( + flow, + stream_slice, + nbss_hdr.data, + nbss_hdr.length as i64, + ); if smb_record.is_response() { smb1_response_record(self, smb_record); } else { - SCLogDebug!("SMB1 request seen from server to client"); + SCLogDebug!( + "SMB1 request seen from server to client" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::RequestToClient as u8); + frame.add_event( + flow, + SMBEvent::RequestToClient as u8, + ); } } - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv2 record"); match parse_smb2_response_record(nbss_data) { Ok((nbss_data_rem, ref smb_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - let pdu_frame = self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + let pdu_frame = self.add_smb2_tc_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb2_tc_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + smb_record.header_len as i64, + ); if smb_record.is_response() { smb2_response_record(self, smb_record); } else { - SCLogDebug!("SMB2 request seen from server to client"); + SCLogDebug!( + "SMB2 request seen from server to client" + ); if let Some(frame) = pdu_frame { - frame.add_event(flow, SMBEvent::RequestToClient as u8); + frame.add_event( + flow, + SMBEvent::RequestToClient as u8, + ); } } nbss_data = nbss_data_rem; - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } - } else if smb.version == 0xfd_u8 { // SMB3 transform + } else if smb.version == 0xfd_u8 { + // SMB3 transform let mut nbss_data = nbss_hdr.data; while !nbss_data.is_empty() { SCLogDebug!("SMBv3 transform record"); match parse_smb3_transform_record(nbss_data) { Ok((nbss_data_rem, ref _smb3_record)) => { - let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64; - self.add_smb3_tc_pdu_frame(flow, stream_slice, nbss_data, record_len); - self.add_smb3_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len); + let record_len = + (nbss_data.len() - nbss_data_rem.len()) as i64; + self.add_smb3_tc_pdu_frame( + flow, + stream_slice, + nbss_data, + record_len, + ); + self.add_smb3_tc_hdr_data_frames( + flow, + stream_slice, + nbss_data, + record_len, + ); nbss_data = nbss_data_rem; - }, + } _ => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } } - }, + } Err(Err::Incomplete(_)) => { // not enough data to contain basic SMB hdr // TODO event: empty NBSS_MSGTYPE_SESSION_MESSAGE - }, + } Err(_) => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } } else { SCLogDebug!("NBSS message {:X}", nbss_hdr.message_type); } cur_i = rem; - }, + } Err(Err::Incomplete(needed)) => { SCLogDebug!("INCOMPLETE have {} needed {:?}", cur_i.len(), needed); if let Needed::Size(n) = needed { @@ -1828,8 +2240,13 @@ impl SMBState { if consumed == 0 { // if we consumed none we will buffer the entire record let total_consumed = stream_slice.offset_from(cur_i); - SCLogDebug!("setting consumed {} need {} needed {:?} total input {}", - total_consumed, n, needed, stream_slice.len()); + SCLogDebug!( + "setting consumed {} need {} needed {:?} total input {}", + total_consumed, + n, + needed, + stream_slice.len() + ); let need = n; return AppLayerResult::incomplete(total_consumed, need as u32); } @@ -1841,13 +2258,13 @@ impl SMBState { self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } - }, + } Err(_) => { self.set_event(SMBEvent::MalformedData); return AppLayerResult::err(); - }, + } } - }; + } self.post_gap_housekeeping(Direction::ToClient); if self.check_post_gap_file_txs && !self.post_gap_files_checked { self.post_gap_housekeeping_for_files(); @@ -1867,7 +2284,11 @@ impl SMBState { let consumed2 = self.filetracker_update(Direction::ToServer, &gap, new_gap_size); if consumed2 > new_gap_size { - SCLogDebug!("consumed more than GAP size: {} > {}", consumed2, new_gap_size); + SCLogDebug!( + "consumed more than GAP size: {} > {}", + consumed2, + new_gap_size + ); self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } @@ -1888,7 +2309,11 @@ impl SMBState { let consumed2 = self.filetracker_update(Direction::ToClient, &gap, new_gap_size); if consumed2 > new_gap_size { - SCLogDebug!("consumed more than GAP size: {} > {}", consumed2, new_gap_size); + SCLogDebug!( + "consumed more than GAP size: {} > {}", + consumed2, + new_gap_size + ); self.set_event(SMBEvent::InternalError); return AppLayerResult::err(); } @@ -1908,7 +2333,7 @@ impl SMBState { SCLogDebug!("TRUNCATING TX {} in TOSERVER direction", tx.id); tx.request_done = true; } - } + } } pub fn trunc_tc(&mut self) { SCLogDebug!("TRUNC TC"); @@ -1925,7 +2350,9 @@ impl SMBState { /// Returns *mut SMBState #[no_mangle] -pub extern "C" fn rs_smb_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_smb_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = SMBState::new(); let boxed = Box::new(state); SCLogDebug!("allocating state"); @@ -1935,7 +2362,7 @@ pub extern "C" fn rs_smb_state_new(_orig_state: *mut std::os::raw::c_void, _orig /// Params: /// - state: *mut SMBState as void pointer #[no_mangle] -pub extern "C" fn rs_smb_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_smb_state_free(state: *mut std::os::raw::c_void) { SCLogDebug!("freeing state"); let mut smb_state = unsafe { Box::from_raw(state as *mut SMBState) }; smb_state.free(); @@ -1943,14 +2370,10 @@ pub extern "C" fn rs_smb_state_free(state: *mut std::os::raw::c_void) { /// C binding parse a SMB request. Returns 1 on success, -1 on failure. #[no_mangle] -pub unsafe extern "C" fn rs_smb_parse_request_tcp(flow: *const Flow, - state: *mut ffi::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) - -> AppLayerResult -{ +pub unsafe extern fn rs_smb_parse_request_tcp( + flow: *const Flow, state: *mut ffi::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, SMBState); let flow = cast_pointer!(flow, Flow); @@ -1961,7 +2384,8 @@ pub unsafe extern "C" fn rs_smb_parse_request_tcp(flow: *const Flow, SCLogDebug!("parsing {} bytes of request data", stream_slice.len()); /* START with MISTREAM set: record might be starting the middle. */ - if stream_slice.flags() & (STREAM_START|STREAM_MIDSTREAM) == (STREAM_START|STREAM_MIDSTREAM) { + if stream_slice.flags() & (STREAM_START | STREAM_MIDSTREAM) == (STREAM_START | STREAM_MIDSTREAM) + { state.ts_gap = true; } @@ -1970,24 +2394,15 @@ pub unsafe extern "C" fn rs_smb_parse_request_tcp(flow: *const Flow, } #[no_mangle] -pub extern "C" fn rs_smb_parse_request_tcp_gap( - state: &mut SMBState, - input_len: u32) - -> AppLayerResult -{ +pub extern fn rs_smb_parse_request_tcp_gap(state: &mut SMBState, input_len: u32) -> AppLayerResult { state.parse_tcp_data_ts_gap(input_len) } - #[no_mangle] -pub unsafe extern "C" fn rs_smb_parse_response_tcp(flow: *const Flow, - state: *mut ffi::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const ffi::c_void, - ) - -> AppLayerResult -{ +pub unsafe extern fn rs_smb_parse_response_tcp( + flow: *const Flow, state: *mut ffi::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const ffi::c_void, +) -> AppLayerResult { let state = cast_pointer!(state, SMBState); let flow = cast_pointer!(flow, Flow); @@ -1996,7 +2411,8 @@ pub unsafe extern "C" fn rs_smb_parse_response_tcp(flow: *const Flow, } /* START with MISTREAM set: record might be starting the middle. */ - if stream_slice.flags() & (STREAM_START|STREAM_MIDSTREAM) == (STREAM_START|STREAM_MIDSTREAM) { + if stream_slice.flags() & (STREAM_START | STREAM_MIDSTREAM) == (STREAM_START | STREAM_MIDSTREAM) + { state.tc_gap = true; } @@ -2005,16 +2421,13 @@ pub unsafe extern "C" fn rs_smb_parse_response_tcp(flow: *const Flow, } #[no_mangle] -pub extern "C" fn rs_smb_parse_response_tcp_gap( - state: &mut SMBState, - input_len: u32) - -> AppLayerResult -{ +pub extern fn rs_smb_parse_response_tcp_gap( + state: &mut SMBState, input_len: u32, +) -> AppLayerResult { state.parse_tcp_data_tc_gap(input_len) } -fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, begins: bool) -> i8 -{ +fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, begins: bool) -> i8 { let r = if begins { // if pattern was found in the beginning, just check first byte if slice[0] == NBSS_MSGTYPE_SESSION_MESSAGE { @@ -2031,96 +2444,119 @@ fn smb_probe_tcp_midstream(direction: Direction, slice: &[u8], rdir: *mut u8, be match parse_smb_version(data) { Ok((_, ref smb)) => { SCLogDebug!("SMB {:?}", smb); - if smb.version == 0xff_u8 { // SMB1 + if smb.version == 0xff_u8 { + // SMB1 SCLogDebug!("SMBv1 record"); if let Ok((_, ref smb_record)) = parse_smb_record(data) { if smb_record.flags & 0x80 != 0 { SCLogDebug!("RESPONSE {:02x}", smb_record.flags); if direction == Direction::ToServer { - unsafe { *rdir = Direction::ToClient as u8; } + unsafe { + *rdir = Direction::ToClient as u8; + } } } else { SCLogDebug!("REQUEST {:02x}", smb_record.flags); if direction == Direction::ToClient { - unsafe { *rdir = Direction::ToServer as u8; } + unsafe { + *rdir = Direction::ToServer as u8; + } } } return 1; } - } else if smb.version == 0xfe_u8 { // SMB2 + } else if smb.version == 0xfe_u8 { + // SMB2 SCLogDebug!("SMB2 record"); if let Ok((_, ref smb_record)) = parse_smb2_record_direction(data) { if direction == Direction::ToServer { - SCLogDebug!("direction Direction::ToServer smb_record {:?}", smb_record); + SCLogDebug!( + "direction Direction::ToServer smb_record {:?}", + smb_record + ); if !smb_record.request { - unsafe { *rdir = Direction::ToClient as u8; } + unsafe { + *rdir = Direction::ToClient as u8; + } } } else { - SCLogDebug!("direction Direction::ToClient smb_record {:?}", smb_record); + SCLogDebug!( + "direction Direction::ToClient smb_record {:?}", + smb_record + ); if smb_record.request { - unsafe { *rdir = Direction::ToServer as u8; } + unsafe { + *rdir = Direction::ToServer as u8; + } } } } - } - else if smb.version == 0xfd_u8 { // SMB3 transform + } else if smb.version == 0xfd_u8 { + // SMB3 transform SCLogDebug!("SMB3 record"); } return 1; - }, - _ => { - SCLogDebug!("smb not found in {:?}", slice); - }, + } + _ => { + SCLogDebug!("smb not found in {:?}", slice); + } } - }, + } _ => { SCLogDebug!("no dice"); - }, + } } return 0; } -fn smb_probe_tcp(flags: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> AppProto -{ - if flags & STREAM_MIDSTREAM == STREAM_MIDSTREAM && smb_probe_tcp_midstream(flags.into(), slice, rdir, begins) == 1 { - unsafe { return ALPROTO_SMB; } +fn smb_probe_tcp(flags: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> AppProto { + if flags & STREAM_MIDSTREAM == STREAM_MIDSTREAM + && smb_probe_tcp_midstream(flags.into(), slice, rdir, begins) == 1 + { + unsafe { + return ALPROTO_SMB; + } } if let Ok((_, ref hdr)) = parse_nbss_record_partial(slice) { if hdr.is_smb() { SCLogDebug!("smb found"); - unsafe { return ALPROTO_SMB; } - } else if hdr.needs_more(){ + unsafe { + return ALPROTO_SMB; + } + } else if hdr.needs_more() { return 0; - } else if hdr.is_valid() && - hdr.message_type != NBSS_MSGTYPE_SESSION_MESSAGE { - //we accept a first small netbios message before real SMB - let hl = hdr.length as usize; - if hdr.data.len() >= hl + 8 { - // 8 is 4 bytes NBSS + 4 bytes SMB0xFX magic - if let Ok((_, ref hdr2)) = parse_nbss_record_partial(&hdr.data[hl..]) { - if hdr2.is_smb() { - SCLogDebug!("smb found"); - unsafe { return ALPROTO_SMB; } + } else if hdr.is_valid() && hdr.message_type != NBSS_MSGTYPE_SESSION_MESSAGE { + //we accept a first small netbios message before real SMB + let hl = hdr.length as usize; + if hdr.data.len() >= hl + 8 { + // 8 is 4 bytes NBSS + 4 bytes SMB0xFX magic + if let Ok((_, ref hdr2)) = parse_nbss_record_partial(&hdr.data[hl..]) { + if hdr2.is_smb() { + SCLogDebug!("smb found"); + unsafe { + return ALPROTO_SMB; } } - } else if hdr.length < 256 { - // we want more data, 256 is some random value - return 0; } - // default is failure + } else if hdr.length < 256 { + // we want more data, 256 is some random value + return 0; } + // default is failure + } } SCLogDebug!("no smb"); - unsafe { return ALPROTO_FAILED; } + unsafe { + return ALPROTO_FAILED; + } } // probing confirmation parser // return 1 if found, 0 is not found #[no_mangle] -pub unsafe extern "C" fn rs_smb_probe_begins_tcp(_f: *const Flow, - flags: u8, input: *const u8, len: u32, rdir: *mut u8) - -> AppProto -{ +pub unsafe extern fn rs_smb_probe_begins_tcp( + _f: *const Flow, flags: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> AppProto { if len < MIN_REC_SIZE as u32 { return ALPROTO_UNKNOWN; } @@ -2131,10 +2567,9 @@ pub unsafe extern "C" fn rs_smb_probe_begins_tcp(_f: *const Flow, // probing parser // return 1 if found, 0 is not found #[no_mangle] -pub unsafe extern "C" fn rs_smb_probe_tcp(_f: *const Flow, - flags: u8, input: *const u8, len: u32, rdir: *mut u8) - -> AppProto -{ +pub unsafe extern fn rs_smb_probe_tcp( + _f: *const Flow, flags: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> AppProto { if len < MIN_REC_SIZE as u32 { return ALPROTO_UNKNOWN; } @@ -2143,19 +2578,14 @@ pub unsafe extern "C" fn rs_smb_probe_tcp(_f: *const Flow, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_state_get_tx_count(state: *mut ffi::c_void) - -> u64 -{ +pub unsafe extern fn rs_smb_state_get_tx_count(state: *mut ffi::c_void) -> u64 { let state = cast_pointer!(state, SMBState); SCLogDebug!("rs_smb_state_get_tx_count: returning {}", state.tx_id); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_smb_state_get_tx(state: *mut ffi::c_void, - tx_id: u64) - -> *mut ffi::c_void -{ +pub unsafe extern fn rs_smb_state_get_tx(state: *mut ffi::c_void, tx_id: u64) -> *mut ffi::c_void { let state = cast_pointer!(state, SMBState); match state.get_tx_by_id(tx_id) { Some(tx) => { @@ -2168,19 +2598,14 @@ pub unsafe extern "C" fn rs_smb_state_get_tx(state: *mut ffi::c_void, } #[no_mangle] -pub unsafe extern "C" fn rs_smb_state_tx_free(state: *mut ffi::c_void, - tx_id: u64) -{ +pub unsafe extern fn rs_smb_state_tx_free(state: *mut ffi::c_void, tx_id: u64) { let state = cast_pointer!(state, SMBState); SCLogDebug!("freeing tx {}", tx_id); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_smb_tx_get_alstate_progress(tx: *mut ffi::c_void, - direction: u8) - -> i32 -{ +pub unsafe extern fn rs_smb_tx_get_alstate_progress(tx: *mut ffi::c_void, direction: u8) -> i32 { let tx = cast_pointer!(tx, SMBTransaction); if direction == Direction::ToServer as u8 && tx.request_done { @@ -2190,29 +2615,26 @@ pub unsafe extern "C" fn rs_smb_tx_get_alstate_progress(tx: *mut ffi::c_void, SCLogDebug!("tx {} TOCLIENT progress 1 => {:?}", tx.id, tx); return 1; } else { - SCLogDebug!("tx {} direction {} progress 0 => {:?}", tx.id, direction, tx); + SCLogDebug!( + "tx {} direction {} progress 0 => {:?}", + tx.id, + direction, + tx + ); return 0; } } - export_state_data_get!(rs_smb_get_state_data, SMBState); #[no_mangle] -pub unsafe extern "C" fn rs_smb_get_tx_data( - tx: *mut std::os::raw::c_void) - -> *mut AppLayerTxData -{ +pub unsafe extern fn rs_smb_get_tx_data(tx: *mut std::os::raw::c_void) -> *mut AppLayerTxData { let tx = cast_pointer!(tx, SMBTransaction); return &mut tx.tx_data; } - #[no_mangle] -pub unsafe extern "C" fn rs_smb_state_truncate( - state: *mut std::ffi::c_void, - direction: u8) -{ +pub unsafe extern fn rs_smb_state_truncate(state: *mut std::ffi::c_void, direction: u8) { let state = cast_pointer!(state, SMBState); match direction.into() { Direction::ToServer => { @@ -2225,24 +2647,24 @@ pub unsafe extern "C" fn rs_smb_state_truncate( } #[no_mangle] -pub unsafe extern "C" fn rs_smb_state_get_event_info_by_id( - event_id: std::os::raw::c_int, - event_name: *mut *const std::os::raw::c_char, +pub unsafe extern fn rs_smb_state_get_event_info_by_id( + event_id: std::os::raw::c_int, event_name: *mut *const std::os::raw::c_char, event_type: *mut AppLayerEventType, ) -> i8 { SMBEvent::get_event_info_by_id(event_id, event_name, event_type) } #[no_mangle] -pub unsafe extern "C" fn rs_smb_state_get_event_info( - event_name: *const std::os::raw::c_char, - event_id: *mut std::os::raw::c_int, +pub unsafe extern fn rs_smb_state_get_event_info( + event_name: *const std::os::raw::c_char, event_id: *mut std::os::raw::c_int, event_type: *mut AppLayerEventType, ) -> std::os::raw::c_int { SMBEvent::get_event_info(event_name, event_id, event_type) } -pub unsafe extern "C" fn smb3_probe_tcp(f: *const Flow, dir: u8, input: *const u8, len: u32, rdir: *mut u8) -> u16 { +pub unsafe extern fn smb3_probe_tcp( + f: *const Flow, dir: u8, input: *const u8, len: u32, rdir: *mut u8, +) -> u16 { let retval = rs_smb_probe_tcp(f, dir, input, len, rdir); let f = cast_pointer!(f, Flow); if retval != ALPROTO_SMB { @@ -2250,8 +2672,16 @@ pub unsafe extern "C" fn smb3_probe_tcp(f: *const Flow, dir: u8, input: *const u } let (sp, dp) = f.get_ports(); let flags = f.get_flags(); - let fsp = if (flags & FLOW_DIR_REVERSED) != 0 { dp } else { sp }; - let fdp = if (flags & FLOW_DIR_REVERSED) != 0 { sp } else { dp }; + let fsp = if (flags & FLOW_DIR_REVERSED) != 0 { + dp + } else { + sp + }; + let fdp = if (flags & FLOW_DIR_REVERSED) != 0 { + sp + } else { + dp + }; if fsp == 445 && fdp != 445 { match dir.into() { Direction::ToServer => { @@ -2269,26 +2699,74 @@ fn register_pattern_probe() -> i8 { let mut r = 0; unsafe { // SMB1 - r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToServer as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE); - r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToClient as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToServer as u8, + rs_smb_probe_begins_tcp, + MIN_REC_SIZE, + MIN_REC_SIZE, + ); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|ff|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToClient as u8, + rs_smb_probe_begins_tcp, + MIN_REC_SIZE, + MIN_REC_SIZE, + ); // SMB2/3 - r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToServer as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE); - r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToClient as u8, rs_smb_probe_begins_tcp, MIN_REC_SIZE, MIN_REC_SIZE); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToServer as u8, + rs_smb_probe_begins_tcp, + MIN_REC_SIZE, + MIN_REC_SIZE, + ); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fe|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToClient as u8, + rs_smb_probe_begins_tcp, + MIN_REC_SIZE, + MIN_REC_SIZE, + ); // SMB3 encrypted records - r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToServer as u8, smb3_probe_tcp, MIN_REC_SIZE, MIN_REC_SIZE); - r |= AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_SMB, - b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, 8, 4, - Direction::ToClient as u8, smb3_probe_tcp, MIN_REC_SIZE, MIN_REC_SIZE); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToServer as u8, + smb3_probe_tcp, + MIN_REC_SIZE, + MIN_REC_SIZE, + ); + r |= AppLayerProtoDetectPMRegisterPatternCSwPP( + IPPROTO_TCP, + ALPROTO_SMB, + b"|fd|SMB\0".as_ptr() as *const std::os::raw::c_char, + 8, + 4, + Direction::ToClient as u8, + smb3_probe_tcp, + MIN_REC_SIZE, + MIN_REC_SIZE, + ); } if r == 0 { @@ -2302,7 +2780,7 @@ fn register_pattern_probe() -> i8 { const PARSER_NAME: &[u8] = b"smb\0"; #[no_mangle] -pub unsafe extern "C" fn rs_smb_register_parser() { +pub unsafe extern fn rs_smb_register_parser() { let default_port = CString::new("445").unwrap(); let mut stream_depth = SMB_CONFIG_DEFAULT_STREAM_DEPTH; let parser = RustParser { @@ -2324,7 +2802,7 @@ pub unsafe extern "C" fn rs_smb_register_parser() { tx_comp_st_tc: 1, tx_get_progress: rs_smb_tx_get_alstate_progress, get_eventinfo: Some(rs_smb_state_get_event_info), - get_eventinfo_byid : Some(rs_smb_state_get_event_info_by_id), + get_eventinfo_byid: Some(rs_smb_state_get_event_info_by_id), localstorage_new: None, localstorage_free: None, get_tx_files: Some(rs_smb_gettxfiles), @@ -2340,82 +2818,117 @@ pub unsafe extern "C" fn rs_smb_register_parser() { let ip_proto_str = CString::new("tcp").unwrap(); - if AppLayerProtoDetectConfProtoDetectionEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let alproto = AppLayerRegisterProtocolDetection(&parser, 1); ALPROTO_SMB = alproto; if register_pattern_probe() < 0 { return; } - let have_cfg = AppLayerProtoDetectPPParseConfPorts(ip_proto_str.as_ptr(), - IPPROTO_TCP, parser.name, ALPROTO_SMB, 0, - MIN_REC_SIZE, rs_smb_probe_tcp, rs_smb_probe_tcp); - - if have_cfg == 0 { - AppLayerProtoDetectPPRegister(IPPROTO_TCP, default_port.as_ptr(), ALPROTO_SMB, - 0, MIN_REC_SIZE, Direction::ToServer as u8, rs_smb_probe_tcp, rs_smb_probe_tcp); - } - - if AppLayerParserConfParserEnabled( + let have_cfg = AppLayerProtoDetectPPParseConfPorts( ip_proto_str.as_ptr(), + IPPROTO_TCP, parser.name, - ) != 0 - { + ALPROTO_SMB, + 0, + MIN_REC_SIZE, + rs_smb_probe_tcp, + rs_smb_probe_tcp, + ); + + if have_cfg == 0 { + AppLayerProtoDetectPPRegister( + IPPROTO_TCP, + default_port.as_ptr(), + ALPROTO_SMB, + 0, + MIN_REC_SIZE, + Direction::ToServer as u8, + rs_smb_probe_tcp, + rs_smb_probe_tcp, + ); + } + + if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let _ = AppLayerRegisterParser(&parser, alproto); } SCLogDebug!("Rust SMB parser registered."); let retval = conf_get("app-layer.protocols.smb.stream-depth"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { stream_depth = retval as u32; } - Err(_) => { SCLogError!("Invalid depth value"); } + Ok(retval) => { + stream_depth = retval as u32; + } + Err(_) => { + SCLogError!("Invalid depth value"); + } } } AppLayerParserSetStreamDepth(IPPROTO_TCP, ALPROTO_SMB, stream_depth); let retval = conf_get("app-layer.protocols.smb.max-read-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_READ_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-read-size value"); } + Ok(retval) => { + SMB_CFG_MAX_READ_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-read-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-write-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_WRITE_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-write-size value"); } + Ok(retval) => { + SMB_CFG_MAX_WRITE_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-write-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-write-queue-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_WRITE_QUEUE_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-write-queue-size value"); } + Ok(retval) => { + SMB_CFG_MAX_WRITE_QUEUE_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-write-queue-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-write-queue-cnt"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_WRITE_QUEUE_CNT = retval as u32; } - Err(_) => { SCLogError!("Invalid max-write-queue-cnt value"); } + Ok(retval) => { + SMB_CFG_MAX_WRITE_QUEUE_CNT = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-write-queue-cnt value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-read-queue-size"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_READ_QUEUE_SIZE = retval as u32; } - Err(_) => { SCLogError!("Invalid max-read-queue-size value"); } + Ok(retval) => { + SMB_CFG_MAX_READ_QUEUE_SIZE = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-read-queue-size value"); + } } } let retval = conf_get("app-layer.protocols.smb.max-read-queue-cnt"); if let Some(val) = retval { match get_memval(val) { - Ok(retval) => { SMB_CFG_MAX_READ_QUEUE_CNT = retval as u32; } - Err(_) => { SCLogError!("Invalid max-read-queue-cnt value"); } + Ok(retval) => { + SMB_CFG_MAX_READ_QUEUE_CNT = retval as u32; + } + Err(_) => { + SCLogError!("Invalid max-read-queue-cnt value"); + } } } if let Some(val) = conf_get("app-layer.protocols.smb.max-tx") { @@ -2425,10 +2938,18 @@ pub unsafe extern "C" fn rs_smb_register_parser() { SCLogError!("Invalid value for smb.max-tx"); } } - SCLogConfig!("read: max record size: {}, max queued chunks {}, max queued size {}", - SMB_CFG_MAX_READ_SIZE, SMB_CFG_MAX_READ_QUEUE_CNT, SMB_CFG_MAX_READ_QUEUE_SIZE); - SCLogConfig!("write: max record size: {}, max queued chunks {}, max queued size {}", - SMB_CFG_MAX_WRITE_SIZE, SMB_CFG_MAX_WRITE_QUEUE_CNT, SMB_CFG_MAX_WRITE_QUEUE_SIZE); + SCLogConfig!( + "read: max record size: {}, max queued chunks {}, max queued size {}", + SMB_CFG_MAX_READ_SIZE, + SMB_CFG_MAX_READ_QUEUE_CNT, + SMB_CFG_MAX_READ_QUEUE_SIZE + ); + SCLogConfig!( + "write: max record size: {}, max queued chunks {}, max queued size {}", + SMB_CFG_MAX_WRITE_SIZE, + SMB_CFG_MAX_WRITE_QUEUE_CNT, + SMB_CFG_MAX_WRITE_QUEUE_SIZE + ); } else { SCLogDebug!("Protocol detector and parser disabled for SMB."); } diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs index 9d7d47e27c85..63ab45daac6f 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -21,10 +21,10 @@ use crate::core::*; -use crate::smb::smb::*; use crate::smb::dcerpc::*; use crate::smb::events::*; use crate::smb::files::*; +use crate::smb::smb::*; use crate::smb::smb1_records::*; use crate::smb::smb1_session::*; @@ -34,105 +34,108 @@ use crate::smb::smb_status::*; use nom7::Err; // https://msdn.microsoft.com/en-us/library/ee441741.aspx -pub const SMB1_COMMAND_CREATE_DIRECTORY: u8 = 0x00; -pub const SMB1_COMMAND_DELETE_DIRECTORY: u8 = 0x01; -pub const SMB1_COMMAND_OPEN: u8 = 0x02; -pub const SMB1_COMMAND_CREATE: u8 = 0x03; -pub const SMB1_COMMAND_CLOSE: u8 = 0x04; -pub const SMB1_COMMAND_FLUSH: u8 = 0x05; -pub const SMB1_COMMAND_DELETE: u8 = 0x06; -pub const SMB1_COMMAND_RENAME: u8 = 0x07; -pub const SMB1_COMMAND_QUERY_INFORMATION: u8 = 0x08; -pub const SMB1_COMMAND_SET_INFORMATION: u8 = 0x09; -pub const SMB1_COMMAND_READ: u8 = 0x0a; -pub const SMB1_COMMAND_WRITE: u8 = 0x0b; -pub const SMB1_COMMAND_LOCK_BYTE_RANGE: u8 = 0x0c; -pub const SMB1_COMMAND_UNLOCK_BYTE_RANGE: u8 = 0x0d; -pub const SMB1_COMMAND_CREATE_TEMPORARY: u8 = 0x0e; -pub const SMB1_COMMAND_CREATE_NEW: u8 = 0x0f; -pub const SMB1_COMMAND_CHECK_DIRECTORY: u8 = 0x10; -pub const SMB1_COMMAND_PROCESS_EXIT: u8 = 0x11; -pub const SMB1_COMMAND_SEEK: u8 = 0x12; -pub const SMB1_COMMAND_LOCK_AND_READ: u8 = 0x13; -pub const SMB1_COMMAND_WRITE_AND_UNLOCK: u8 = 0x14; -pub const SMB1_COMMAND_LOCKING_ANDX: u8 = 0x24; -pub const SMB1_COMMAND_TRANS: u8 = 0x25; -pub const SMB1_COMMAND_ECHO: u8 = 0x2b; -pub const SMB1_COMMAND_WRITE_AND_CLOSE: u8 = 0x2c; -pub const SMB1_COMMAND_OPEN_ANDX: u8 = 0x2d; -pub const SMB1_COMMAND_READ_ANDX: u8 = 0x2e; -pub const SMB1_COMMAND_WRITE_ANDX: u8 = 0x2f; -pub const SMB1_COMMAND_TRANS2: u8 = 0x32; -pub const SMB1_COMMAND_TRANS2_SECONDARY: u8 = 0x33; -pub const SMB1_COMMAND_FIND_CLOSE2: u8 = 0x34; -pub const SMB1_COMMAND_TREE_DISCONNECT: u8 = 0x71; -pub const SMB1_COMMAND_NEGOTIATE_PROTOCOL: u8 = 0x72; -pub const SMB1_COMMAND_SESSION_SETUP_ANDX: u8 = 0x73; -pub const SMB1_COMMAND_LOGOFF_ANDX: u8 = 0x74; -pub const SMB1_COMMAND_TREE_CONNECT_ANDX: u8 = 0x75; -pub const SMB1_COMMAND_QUERY_INFO_DISK: u8 = 0x80; -pub const SMB1_COMMAND_NT_TRANS: u8 = 0xa0; -pub const SMB1_COMMAND_NT_TRANS_SECONDARY: u8 = 0xa1; -pub const SMB1_COMMAND_NT_CREATE_ANDX: u8 = 0xa2; -pub const SMB1_COMMAND_NT_CANCEL: u8 = 0xa4; -pub const SMB1_COMMAND_NONE: u8 = 0xff; +pub const SMB1_COMMAND_CREATE_DIRECTORY: u8 = 0x00; +pub const SMB1_COMMAND_DELETE_DIRECTORY: u8 = 0x01; +pub const SMB1_COMMAND_OPEN: u8 = 0x02; +pub const SMB1_COMMAND_CREATE: u8 = 0x03; +pub const SMB1_COMMAND_CLOSE: u8 = 0x04; +pub const SMB1_COMMAND_FLUSH: u8 = 0x05; +pub const SMB1_COMMAND_DELETE: u8 = 0x06; +pub const SMB1_COMMAND_RENAME: u8 = 0x07; +pub const SMB1_COMMAND_QUERY_INFORMATION: u8 = 0x08; +pub const SMB1_COMMAND_SET_INFORMATION: u8 = 0x09; +pub const SMB1_COMMAND_READ: u8 = 0x0a; +pub const SMB1_COMMAND_WRITE: u8 = 0x0b; +pub const SMB1_COMMAND_LOCK_BYTE_RANGE: u8 = 0x0c; +pub const SMB1_COMMAND_UNLOCK_BYTE_RANGE: u8 = 0x0d; +pub const SMB1_COMMAND_CREATE_TEMPORARY: u8 = 0x0e; +pub const SMB1_COMMAND_CREATE_NEW: u8 = 0x0f; +pub const SMB1_COMMAND_CHECK_DIRECTORY: u8 = 0x10; +pub const SMB1_COMMAND_PROCESS_EXIT: u8 = 0x11; +pub const SMB1_COMMAND_SEEK: u8 = 0x12; +pub const SMB1_COMMAND_LOCK_AND_READ: u8 = 0x13; +pub const SMB1_COMMAND_WRITE_AND_UNLOCK: u8 = 0x14; +pub const SMB1_COMMAND_LOCKING_ANDX: u8 = 0x24; +pub const SMB1_COMMAND_TRANS: u8 = 0x25; +pub const SMB1_COMMAND_ECHO: u8 = 0x2b; +pub const SMB1_COMMAND_WRITE_AND_CLOSE: u8 = 0x2c; +pub const SMB1_COMMAND_OPEN_ANDX: u8 = 0x2d; +pub const SMB1_COMMAND_READ_ANDX: u8 = 0x2e; +pub const SMB1_COMMAND_WRITE_ANDX: u8 = 0x2f; +pub const SMB1_COMMAND_TRANS2: u8 = 0x32; +pub const SMB1_COMMAND_TRANS2_SECONDARY: u8 = 0x33; +pub const SMB1_COMMAND_FIND_CLOSE2: u8 = 0x34; +pub const SMB1_COMMAND_TREE_DISCONNECT: u8 = 0x71; +pub const SMB1_COMMAND_NEGOTIATE_PROTOCOL: u8 = 0x72; +pub const SMB1_COMMAND_SESSION_SETUP_ANDX: u8 = 0x73; +pub const SMB1_COMMAND_LOGOFF_ANDX: u8 = 0x74; +pub const SMB1_COMMAND_TREE_CONNECT_ANDX: u8 = 0x75; +pub const SMB1_COMMAND_QUERY_INFO_DISK: u8 = 0x80; +pub const SMB1_COMMAND_NT_TRANS: u8 = 0xa0; +pub const SMB1_COMMAND_NT_TRANS_SECONDARY: u8 = 0xa1; +pub const SMB1_COMMAND_NT_CREATE_ANDX: u8 = 0xa2; +pub const SMB1_COMMAND_NT_CANCEL: u8 = 0xa4; +pub const SMB1_COMMAND_NONE: u8 = 0xff; pub fn smb1_command_string(c: u8) -> String { match c { - SMB1_COMMAND_CREATE_DIRECTORY => "SMB1_COMMAND_CREATE_DIRECTORY", - SMB1_COMMAND_DELETE_DIRECTORY => "SMB1_COMMAND_DELETE_DIRECTORY", - SMB1_COMMAND_OPEN => "SMB1_COMMAND_OPEN", - SMB1_COMMAND_CREATE => "SMB1_COMMAND_CREATE", - SMB1_COMMAND_CLOSE => "SMB1_COMMAND_CLOSE", - SMB1_COMMAND_FLUSH => "SMB1_COMMAND_FLUSH", - SMB1_COMMAND_DELETE => "SMB1_COMMAND_DELETE", - SMB1_COMMAND_RENAME => "SMB1_COMMAND_RENAME", - SMB1_COMMAND_QUERY_INFORMATION => "SMB1_COMMAND_QUERY_INFORMATION", - SMB1_COMMAND_SET_INFORMATION => "SMB1_COMMAND_SET_INFORMATION", - SMB1_COMMAND_READ => "SMB1_COMMAND_READ", - SMB1_COMMAND_WRITE => "SMB1_COMMAND_WRITE", - SMB1_COMMAND_LOCK_BYTE_RANGE => "SMB1_COMMAND_LOCK_BYTE_RANGE", - SMB1_COMMAND_UNLOCK_BYTE_RANGE => "SMB1_COMMAND_UNLOCK_BYTE_RANGE", - SMB1_COMMAND_CREATE_TEMPORARY => "SMB1_COMMAND_CREATE_TEMPORARY", - SMB1_COMMAND_CREATE_NEW => "SMB1_COMMAND_CREATE_NEW", - SMB1_COMMAND_CHECK_DIRECTORY => "SMB1_COMMAND_CHECK_DIRECTORY", - SMB1_COMMAND_PROCESS_EXIT => "SMB1_COMMAND_PROCESS_EXIT", - SMB1_COMMAND_SEEK => "SMB1_COMMAND_SEEK", - SMB1_COMMAND_LOCK_AND_READ => "SMB1_COMMAND_LOCK_AND_READ", - SMB1_COMMAND_WRITE_AND_UNLOCK => "SMB1_COMMAND_WRITE_AND_UNLOCK", - SMB1_COMMAND_LOCKING_ANDX => "SMB1_COMMAND_LOCKING_ANDX", - SMB1_COMMAND_ECHO => "SMB1_COMMAND_ECHO", - SMB1_COMMAND_WRITE_AND_CLOSE => "SMB1_COMMAND_WRITE_AND_CLOSE", - SMB1_COMMAND_OPEN_ANDX => "SMB1_COMMAND_OPEN_ANDX", - SMB1_COMMAND_READ_ANDX => "SMB1_COMMAND_READ_ANDX", - SMB1_COMMAND_WRITE_ANDX => "SMB1_COMMAND_WRITE_ANDX", - SMB1_COMMAND_TRANS => "SMB1_COMMAND_TRANS", - SMB1_COMMAND_TRANS2 => "SMB1_COMMAND_TRANS2", - SMB1_COMMAND_TRANS2_SECONDARY => "SMB1_COMMAND_TRANS2_SECONDARY", - SMB1_COMMAND_FIND_CLOSE2 => "SMB1_COMMAND_FIND_CLOSE2", - SMB1_COMMAND_TREE_DISCONNECT => "SMB1_COMMAND_TREE_DISCONNECT", + SMB1_COMMAND_CREATE_DIRECTORY => "SMB1_COMMAND_CREATE_DIRECTORY", + SMB1_COMMAND_DELETE_DIRECTORY => "SMB1_COMMAND_DELETE_DIRECTORY", + SMB1_COMMAND_OPEN => "SMB1_COMMAND_OPEN", + SMB1_COMMAND_CREATE => "SMB1_COMMAND_CREATE", + SMB1_COMMAND_CLOSE => "SMB1_COMMAND_CLOSE", + SMB1_COMMAND_FLUSH => "SMB1_COMMAND_FLUSH", + SMB1_COMMAND_DELETE => "SMB1_COMMAND_DELETE", + SMB1_COMMAND_RENAME => "SMB1_COMMAND_RENAME", + SMB1_COMMAND_QUERY_INFORMATION => "SMB1_COMMAND_QUERY_INFORMATION", + SMB1_COMMAND_SET_INFORMATION => "SMB1_COMMAND_SET_INFORMATION", + SMB1_COMMAND_READ => "SMB1_COMMAND_READ", + SMB1_COMMAND_WRITE => "SMB1_COMMAND_WRITE", + SMB1_COMMAND_LOCK_BYTE_RANGE => "SMB1_COMMAND_LOCK_BYTE_RANGE", + SMB1_COMMAND_UNLOCK_BYTE_RANGE => "SMB1_COMMAND_UNLOCK_BYTE_RANGE", + SMB1_COMMAND_CREATE_TEMPORARY => "SMB1_COMMAND_CREATE_TEMPORARY", + SMB1_COMMAND_CREATE_NEW => "SMB1_COMMAND_CREATE_NEW", + SMB1_COMMAND_CHECK_DIRECTORY => "SMB1_COMMAND_CHECK_DIRECTORY", + SMB1_COMMAND_PROCESS_EXIT => "SMB1_COMMAND_PROCESS_EXIT", + SMB1_COMMAND_SEEK => "SMB1_COMMAND_SEEK", + SMB1_COMMAND_LOCK_AND_READ => "SMB1_COMMAND_LOCK_AND_READ", + SMB1_COMMAND_WRITE_AND_UNLOCK => "SMB1_COMMAND_WRITE_AND_UNLOCK", + SMB1_COMMAND_LOCKING_ANDX => "SMB1_COMMAND_LOCKING_ANDX", + SMB1_COMMAND_ECHO => "SMB1_COMMAND_ECHO", + SMB1_COMMAND_WRITE_AND_CLOSE => "SMB1_COMMAND_WRITE_AND_CLOSE", + SMB1_COMMAND_OPEN_ANDX => "SMB1_COMMAND_OPEN_ANDX", + SMB1_COMMAND_READ_ANDX => "SMB1_COMMAND_READ_ANDX", + SMB1_COMMAND_WRITE_ANDX => "SMB1_COMMAND_WRITE_ANDX", + SMB1_COMMAND_TRANS => "SMB1_COMMAND_TRANS", + SMB1_COMMAND_TRANS2 => "SMB1_COMMAND_TRANS2", + SMB1_COMMAND_TRANS2_SECONDARY => "SMB1_COMMAND_TRANS2_SECONDARY", + SMB1_COMMAND_FIND_CLOSE2 => "SMB1_COMMAND_FIND_CLOSE2", + SMB1_COMMAND_TREE_DISCONNECT => "SMB1_COMMAND_TREE_DISCONNECT", SMB1_COMMAND_NEGOTIATE_PROTOCOL => "SMB1_COMMAND_NEGOTIATE_PROTOCOL", SMB1_COMMAND_SESSION_SETUP_ANDX => "SMB1_COMMAND_SESSION_SETUP_ANDX", - SMB1_COMMAND_LOGOFF_ANDX => "SMB1_COMMAND_LOGOFF_ANDX", - SMB1_COMMAND_TREE_CONNECT_ANDX => "SMB1_COMMAND_TREE_CONNECT_ANDX", - SMB1_COMMAND_QUERY_INFO_DISK => "SMB1_COMMAND_QUERY_INFO_DISK", - SMB1_COMMAND_NT_TRANS => "SMB1_COMMAND_NT_TRANS", + SMB1_COMMAND_LOGOFF_ANDX => "SMB1_COMMAND_LOGOFF_ANDX", + SMB1_COMMAND_TREE_CONNECT_ANDX => "SMB1_COMMAND_TREE_CONNECT_ANDX", + SMB1_COMMAND_QUERY_INFO_DISK => "SMB1_COMMAND_QUERY_INFO_DISK", + SMB1_COMMAND_NT_TRANS => "SMB1_COMMAND_NT_TRANS", SMB1_COMMAND_NT_TRANS_SECONDARY => "SMB1_COMMAND_NT_TRANS_SECONDARY", - SMB1_COMMAND_NT_CREATE_ANDX => "SMB1_COMMAND_NT_CREATE_ANDX", - SMB1_COMMAND_NT_CANCEL => "SMB1_COMMAND_NT_CANCEL", - _ => { return (c).to_string(); }, - }.to_string() + SMB1_COMMAND_NT_CREATE_ANDX => "SMB1_COMMAND_NT_CREATE_ANDX", + SMB1_COMMAND_NT_CANCEL => "SMB1_COMMAND_NT_CANCEL", + _ => { + return (c).to_string(); + } + } + .to_string() } // later we'll use this to determine if we need to // track a ssn per type pub fn smb1_create_new_tx(cmd: u8) -> bool { match cmd { - SMB1_COMMAND_READ_ANDX | - SMB1_COMMAND_WRITE_ANDX | - SMB1_COMMAND_TRANS | - SMB1_COMMAND_TRANS2 => { false }, - _ => { true }, + SMB1_COMMAND_READ_ANDX + | SMB1_COMMAND_WRITE_ANDX + | SMB1_COMMAND_TRANS + | SMB1_COMMAND_TRANS2 => false, + _ => true, } } @@ -141,15 +144,12 @@ pub fn smb1_create_new_tx(cmd: u8) -> bool { // excludes the 'maybe' commands like TRANS2 pub fn smb1_check_tx(cmd: u8) -> bool { match cmd { - SMB1_COMMAND_READ_ANDX | - SMB1_COMMAND_WRITE_ANDX | - SMB1_COMMAND_TRANS => { false }, - _ => { true }, + SMB1_COMMAND_READ_ANDX | SMB1_COMMAND_WRITE_ANDX | SMB1_COMMAND_TRANS => false, + _ => true, } } -fn smb1_close_file(state: &mut SMBState, fid: &[u8], direction: Direction) -{ +fn smb1_close_file(state: &mut SMBState, fid: &[u8], direction: Direction) { if let Some(tx) = state.get_file_tx_by_fuid(fid, direction) { SCLogDebug!("found tx {}", tx.id); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { @@ -166,14 +166,14 @@ fn smb1_close_file(state: &mut SMBState, fid: &[u8], direction: Direction) fn smb1_command_is_andx(c: u8) -> bool { match c { - SMB1_COMMAND_LOCKING_ANDX | - SMB1_COMMAND_OPEN_ANDX | - SMB1_COMMAND_READ_ANDX | - SMB1_COMMAND_SESSION_SETUP_ANDX | - SMB1_COMMAND_LOGOFF_ANDX | - SMB1_COMMAND_TREE_CONNECT_ANDX | - SMB1_COMMAND_NT_CREATE_ANDX | - SMB1_COMMAND_WRITE_ANDX => { + SMB1_COMMAND_LOCKING_ANDX + | SMB1_COMMAND_OPEN_ANDX + | SMB1_COMMAND_READ_ANDX + | SMB1_COMMAND_SESSION_SETUP_ANDX + | SMB1_COMMAND_LOGOFF_ANDX + | SMB1_COMMAND_TREE_CONNECT_ANDX + | SMB1_COMMAND_NT_CREATE_ANDX + | SMB1_COMMAND_WRITE_ANDX => { return true; } _ => { @@ -182,32 +182,32 @@ fn smb1_command_is_andx(c: u8) -> bool { } } -fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize) { - let mut events : Vec = Vec::new(); +fn smb1_request_record_one( + state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize, +) { + let mut events: Vec = Vec::new(); let mut no_response_expected = false; let have_tx = match command { - SMB1_COMMAND_RENAME => { - match parse_smb_rename_request_record(r.data) { - Ok((_, rd)) => { - SCLogDebug!("RENAME {:?}", rd); + SMB1_COMMAND_RENAME => match parse_smb_rename_request_record(r.data) { + Ok((_, rd)) => { + SCLogDebug!("RENAME {:?}", rd); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let mut newname = rd.newname; - newname.retain(|&i|i != 0x00); - let mut oldname = rd.oldname; - oldname.retain(|&i|i != 0x00); + let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + let mut newname = rd.newname; + newname.retain(|&i| i != 0x00); + let mut oldname = rd.oldname; + oldname.retain(|&i| i != 0x00); - let tx = state.new_rename_tx(Vec::new(), oldname, newname); - tx.hdr = tx_hdr; - tx.request_done = true; - tx.vercmd.set_smb1_cmd(SMB1_COMMAND_RENAME); - true - }, - _ => { - events.push(SMBEvent::MalformedData); - false - }, + let tx = state.new_rename_tx(Vec::new(), oldname, newname); + tx.hdr = tx_hdr; + tx.request_done = true; + tx.vercmd.set_smb1_cmd(SMB1_COMMAND_RENAME); + true + } + _ => { + events.push(SMBEvent::MalformedData); + false } }, SMB1_COMMAND_TRANS2 => { @@ -221,75 +221,97 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and Ok((_, pd)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS DONE {:?}", pd); - if pd.loi == 1013 { // set disposition info - match parse_trans2_request_data_set_file_info_disposition(rd.data_blob) { + if pd.loi == 1013 { + // set disposition info + match parse_trans2_request_data_set_file_info_disposition( + rd.data_blob, + ) { Ok((_, disp)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", disp); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - - let tx = state.new_setpathinfo_tx(pd.oldname, - rd.subcmd, pd.loi, disp.delete); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", + disp + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + + let tx = state.new_setpathinfo_tx( + pd.oldname, + rd.subcmd, + pd.loi, + disp.delete, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else if pd.loi == 1010 { - match parse_trans2_request_data_set_path_info_rename(rd.data_blob) { + match parse_trans2_request_data_set_path_info_rename( + rd.data_blob, + ) { Ok((_, ren)) => { - SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME DONE {:?}", ren); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + SCLogDebug!( + "TRANS2 SET_PATH_INFO DATA RENAME DONE {:?}", + ren + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let mut newname = ren.newname.to_vec(); - newname.retain(|&i|i != 0x00); + newname.retain(|&i| i != 0x00); - let fid : Vec = Vec::new(); + let fid: Vec = Vec::new(); let tx = state.new_rename_tx(fid, pd.oldname, newname); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - }, + } Err(Err::Incomplete(_n)) => { - SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME INCOMPLETE {:?}", _n); + SCLogDebug!( + "TRANS2 SET_PATH_INFO DATA RENAME INCOMPLETE {:?}", + _n + ); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_PATH_INFO DATA RENAME ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_PATH_INFO DATA RENAME ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else { false } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_PATH_INFO PARAMS ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } } } else if rd.subcmd == 8 { SCLogDebug!("SET_FILE_INFO"); @@ -297,107 +319,135 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and Ok((_, pd)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS DONE {:?}", pd); - if pd.loi == 1013 { // set disposition info - match parse_trans2_request_data_set_file_info_disposition(rd.data_blob) { + if pd.loi == 1013 { + // set disposition info + match parse_trans2_request_data_set_file_info_disposition( + rd.data_blob, + ) { Ok((_, disp)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", disp); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", + disp + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let mut frankenfid = pd.fid.to_vec(); frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id)); - let filename = match state.guid2name_map.get(&frankenfid) { - Some(n) => n.to_vec(), - None => b"".to_vec(), - }; - let tx = state.new_setfileinfo_tx(filename, pd.fid.to_vec(), - rd.subcmd, pd.loi, disp.delete); + let filename = + match state.guid2name_map.get(&frankenfid) { + Some(n) => n.to_vec(), + None => b"".to_vec(), + }; + let tx = state.new_setfileinfo_tx( + filename, + pd.fid.to_vec(), + rd.subcmd, + pd.loi, + disp.delete, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA DISPOSITION ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else if pd.loi == 1010 { - match parse_trans2_request_data_set_file_info_rename(rd.data_blob) { + match parse_trans2_request_data_set_file_info_rename( + rd.data_blob, + ) { Ok((_, ren)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME DONE {:?}", ren); - let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA RENAME DONE {:?}", + ren + ); + let tx_hdr = + SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let mut newname = ren.newname.to_vec(); - newname.retain(|&i|i != 0x00); + newname.retain(|&i| i != 0x00); let mut frankenfid = pd.fid.to_vec(); frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id)); - let oldname = match state.guid2name_map.get(&frankenfid) { + let oldname = match state.guid2name_map.get(&frankenfid) + { Some(n) => n.to_vec(), None => b"".to_vec(), }; - let tx = state.new_rename_tx(pd.fid.to_vec(), oldname, newname); + let tx = state.new_rename_tx( + pd.fid.to_vec(), + oldname, + newname, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); true - }, + } Err(Err::Incomplete(_n)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME INCOMPLETE {:?}", _n); + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA RENAME INCOMPLETE {:?}", + _n + ); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { - SCLogDebug!("TRANS2 SET_FILE_INFO DATA RENAME ERROR {:?}", _e); + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { + SCLogDebug!( + "TRANS2 SET_FILE_INFO DATA RENAME ERROR {:?}", + _e + ); events.push(SMBEvent::MalformedData); false - }, + } } } else { false } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 SET_FILE_INFO PARAMS ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } } } else { false } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("TRANS2 INCOMPLETE {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("TRANS2 ERROR {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_READ_ANDX => { - match parse_smb_read_andx_request_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_read_andx_request_record(&r.data[*andx_offset - SMB1_HEADER_SIZE..]) { Ok((_, rr)) => { SCLogDebug!("rr {:?}", rr); @@ -407,70 +457,69 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and fid.extend_from_slice(&u32_as_bytes(r.ssn_id)); let fidoff = SMBFileGUIDOffset::new(fid, rr.offset); state.ssn2vecoffset_map.insert(fid_key, fidoff); - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } false - }, - SMB1_COMMAND_WRITE_ANDX | - SMB1_COMMAND_WRITE | - SMB1_COMMAND_WRITE_AND_CLOSE => { + } + SMB1_COMMAND_WRITE_ANDX | SMB1_COMMAND_WRITE | SMB1_COMMAND_WRITE_AND_CLOSE => { smb1_write_request_record(state, r, *andx_offset, command, 0); true // tx handling in func - }, + } SMB1_COMMAND_TRANS => { smb1_trans_request_record(state, r); true - }, - SMB1_COMMAND_NEGOTIATE_PROTOCOL => { - match parse_smb1_negotiate_protocol_record(r.data) { - Ok((_, pr)) => { - SCLogDebug!("SMB_COMMAND_NEGOTIATE_PROTOCOL {:?}", pr); - - let mut bad_dialects = false; - let mut dialects : Vec> = Vec::new(); - for d in &pr.dialects { - if d.is_empty() { - bad_dialects = true; - continue; - } else if d.len() == 1 { - bad_dialects = true; - } - let x = &d[1..d.len()]; - let dvec = x.to_vec(); - dialects.push(dvec); + } + SMB1_COMMAND_NEGOTIATE_PROTOCOL => match parse_smb1_negotiate_protocol_record(r.data) { + Ok((_, pr)) => { + SCLogDebug!("SMB_COMMAND_NEGOTIATE_PROTOCOL {:?}", pr); + + let mut bad_dialects = false; + let mut dialects: Vec> = Vec::new(); + for d in &pr.dialects { + if d.is_empty() { + bad_dialects = true; + continue; + } else if d.len() == 1 { + bad_dialects = true; } + let x = &d[1..d.len()]; + let dvec = x.to_vec(); + dialects.push(dvec); + } - let found = match state.get_negotiate_tx(1) { - Some(tx) => { - SCLogDebug!("WEIRD, should not have NEGOTIATE tx!"); - tx.set_event(SMBEvent::DuplicateNegotiate); - true - }, - None => { false }, - }; - if !found { - let tx = state.new_negotiate_tx(1); - if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { - tdn.dialects = dialects; - } - tx.request_done = true; - if bad_dialects { - tx.set_event(SMBEvent::NegotiateMalformedDialects); - } + let found = match state.get_negotiate_tx(1) { + Some(tx) => { + SCLogDebug!("WEIRD, should not have NEGOTIATE tx!"); + tx.set_event(SMBEvent::DuplicateNegotiate); + true } - true - }, - _ => { - events.push(SMBEvent::MalformedData); - false - }, + None => false, + }; + if !found { + let tx = state.new_negotiate_tx(1); + if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { + tdn.dialects = dialects; + } + tx.request_done = true; + if bad_dialects { + tx.set_event(SMBEvent::NegotiateMalformedDialects); + } + } + true + } + _ => { + events.push(SMBEvent::MalformedData); + false } }, SMB1_COMMAND_NT_CREATE_ANDX => { - match parse_smb_create_andx_request_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..], r) { + match parse_smb_create_andx_request_record( + &r.data[*andx_offset - SMB1_HEADER_SIZE..], + r, + ) { Ok((_, cr)) => { SCLogDebug!("Create AndX {:?}", cr); let del = cr.create_options & 0x0000_1000 != 0; @@ -482,26 +531,32 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and state.ssn2vec_map.insert(name_key, name_val); let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_create_tx(&cr.file_name.to_vec(), - cr.disposition, del, dir, tx_hdr); + let tx = state.new_create_tx( + &cr.file_name.to_vec(), + cr.disposition, + del, + dir, + tx_hdr, + ); tx.vercmd.set_smb1_cmd(command); SCLogDebug!("TS CREATE TX {} created", tx.id); true - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_SESSION_SETUP_ANDX => { SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id); smb1_session_setup_request(state, r, *andx_offset); true - }, + } SMB1_COMMAND_TREE_CONNECT_ANDX => { SCLogDebug!("SMB1_COMMAND_TREE_CONNECT_ANDX"); - match parse_smb_connect_tree_andx_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..], r) { + match parse_smb_connect_tree_andx_record(&r.data[*andx_offset - SMB1_HEADER_SIZE..], r) + { Ok((_, tr)) => { let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE); let mut name_val = tr.path; @@ -518,61 +573,70 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TREE_CONNECT_ANDX); true - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_TREE_DISCONNECT => { let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); state.ssn2tree_map.remove(&tree_key); false - }, + } SMB1_COMMAND_CLOSE => { match parse_smb1_close_request_record(r.data) { Ok((_, cd)) => { let mut fid = cd.fid.to_vec(); fid.extend_from_slice(&u32_as_bytes(r.ssn_id)); - state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), fid.to_vec()); + state + .ssn2vec_map + .insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), fid.to_vec()); SCLogDebug!("closing FID {:?}/{:?}", cd.fid, fid); smb1_close_file(state, &fid, Direction::ToServer); - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } false - }, - SMB1_COMMAND_NT_CANCEL | - SMB1_COMMAND_TRANS2_SECONDARY | - SMB1_COMMAND_LOCKING_ANDX => { + } + SMB1_COMMAND_NT_CANCEL | SMB1_COMMAND_TRANS2_SECONDARY | SMB1_COMMAND_LOCKING_ANDX => { no_response_expected = true; false - }, + } _ => { - if command == SMB1_COMMAND_LOGOFF_ANDX || - command == SMB1_COMMAND_TREE_DISCONNECT || - command == SMB1_COMMAND_NT_TRANS || - command == SMB1_COMMAND_NT_TRANS_SECONDARY || - command == SMB1_COMMAND_NT_CANCEL || - command == SMB1_COMMAND_RENAME || - command == SMB1_COMMAND_CHECK_DIRECTORY || - command == SMB1_COMMAND_ECHO || - command == SMB1_COMMAND_TRANS - { } else { - SCLogDebug!("unsupported command {}/{}", - command, &smb1_command_string(command)); + if command == SMB1_COMMAND_LOGOFF_ANDX + || command == SMB1_COMMAND_TREE_DISCONNECT + || command == SMB1_COMMAND_NT_TRANS + || command == SMB1_COMMAND_NT_TRANS_SECONDARY + || command == SMB1_COMMAND_NT_CANCEL + || command == SMB1_COMMAND_RENAME + || command == SMB1_COMMAND_CHECK_DIRECTORY + || command == SMB1_COMMAND_ECHO + || command == SMB1_COMMAND_TRANS + { + } else { + SCLogDebug!( + "unsupported command {}/{}", + command, + &smb1_command_string(command) + ); } false - }, + } }; if !have_tx && smb1_create_new_tx(command) { let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); let tx = state.new_generic_tx(1, command as u16, tx_key); - SCLogDebug!("tx {} created for {}/{}", tx.id, command, &smb1_command_string(command)); + SCLogDebug!( + "tx {} created for {}/{}", + tx.id, + command, + &smb1_command_string(command) + ); tx.set_events(events); if no_response_expected { tx.response_done = true; @@ -590,10 +654,13 @@ pub fn smb1_request_record(state: &mut SMBState, r: &SmbRecord) -> u32 { // continue for next andx command if any if smb1_command_is_andx(command) { - if let Ok((_, andx_hdr)) = smb1_parse_andx_header(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { - if (andx_hdr.andx_offset as usize) > andx_offset && - andx_hdr.andx_command != SMB1_COMMAND_NONE && - (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() { + if let Ok((_, andx_hdr)) = + smb1_parse_andx_header(&r.data[andx_offset - SMB1_HEADER_SIZE..]) + { + if (andx_hdr.andx_offset as usize) > andx_offset + && andx_hdr.andx_command != SMB1_COMMAND_NONE + && (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() + { andx_offset = andx_hdr.andx_offset as usize; command = andx_hdr.andx_command; continue; @@ -606,20 +673,27 @@ pub fn smb1_request_record(state: &mut SMBState, r: &SmbRecord) -> u32 { 0 } -fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize) { - SCLogDebug!("record: command {} status {} -> {:?}", r.command, r.nt_status, r); +fn smb1_response_record_one( + state: &mut SMBState, r: &SmbRecord, command: u8, andx_offset: &mut usize, +) { + SCLogDebug!( + "record: command {} status {} -> {:?}", + r.command, + r.nt_status, + r + ); let key_ssn_id = r.ssn_id; let key_tree_id = r.tree_id; let key_multiplex_id = r.multiplex_id; let mut tx_sync = false; - let mut events : Vec = Vec::new(); + let mut events: Vec = Vec::new(); let have_tx = match command { SMB1_COMMAND_READ_ANDX => { smb1_read_response_record(state, r, *andx_offset, 0); true // tx handling in func - }, + } SMB1_COMMAND_NEGOTIATE_PROTOCOL => { SCLogDebug!("SMB1_COMMAND_NEGOTIATE_PROTOCOL response"); match parse_smb1_negotiate_protocol_response_record(r.data) { @@ -640,28 +714,28 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an let d = x.dialects[dialect_idx].to_vec(); Some(d) } - }, - _ => { None }, + } + _ => None, }; if d.is_none() { tx.set_event(SMBEvent::NegotiateMalformedDialects); } (true, d) - }, - None => { (false, None) }, + } + None => (false, None), }; if let Some(d) = dialect { SCLogDebug!("dialect {:?}", d); state.dialect_vec = Some(d); } have_ntx - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_TREE_CONNECT_ANDX => { if r.nt_status != SMB_NTSTATUS_SUCCESS { let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE); @@ -676,14 +750,18 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an return; } - match parse_smb_connect_tree_andx_response_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_connect_tree_andx_response_record( + &r.data[*andx_offset - SMB1_HEADER_SIZE..], + ) { Ok((_, tr)) => { let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_TREE); let is_pipe = tr.service == "IPC".as_bytes(); let mut share_name = Vec::new(); let found = match state.get_treeconnect_tx(name_key) { Some(tx) => { - if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = + tx.type_data + { tdn.is_pipe = is_pipe; tdn.tree_id = r.tree_id as u32; share_name = tdn.share_name.to_vec(); @@ -694,8 +772,8 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an tx.response_done = true; SCLogDebug!("tx {} is done", tx.id); true - }, - None => { false }, + } + None => false, }; if found { let tree = SMBTree::new(share_name.to_vec(), is_pipe); @@ -703,51 +781,58 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an state.ssn2tree_map.insert(tree_key, tree); } found - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } - }, + } SMB1_COMMAND_TREE_DISCONNECT => { // normally removed when processing request, // but in case we missed that try again here let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); state.ssn2tree_map.remove(&tree_key); false - }, + } SMB1_COMMAND_NT_CREATE_ANDX => { SCLogDebug!("SMB1_COMMAND_NT_CREATE_ANDX response {:08x}", r.nt_status); if r.nt_status == SMB_NTSTATUS_SUCCESS { - match parse_smb_create_andx_response_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_create_andx_response_record( + &r.data[*andx_offset - SMB1_HEADER_SIZE..], + ) { Ok((_, cr)) => { SCLogDebug!("Create AndX {:?}", cr); let guid_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_FILENAME); match state.ssn2vec_map.remove(&guid_key) { Some(mut p) => { - p.retain(|&i|i != 0x00); + p.retain(|&i| i != 0x00); let mut fid = cr.fid.to_vec(); fid.extend_from_slice(&u32_as_bytes(r.ssn_id)); SCLogDebug!("SMB1_COMMAND_NT_CREATE_ANDX fid {:?}", fid); SCLogDebug!("fid {:?} name {:?}", fid, p); state.guid2name_map.insert(fid, p); - }, + } _ => { SCLogDebug!("SMBv1 response: GUID NOT FOUND"); - }, + } } let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); if let Some(tx) = state.get_generic_tx(1, command as u16, &tx_hdr) { - SCLogDebug!("tx {} with {}/{} marked as done", - tx.id, command, &smb1_command_string(command)); + SCLogDebug!( + "tx {} with {}/{} marked as done", + tx.id, + command, + &smb1_command_string(command) + ); tx.set_status(r.nt_status, false); tx.response_done = true; - if let Some(SMBTransactionTypeData::CREATE(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::CREATE(ref mut tdn)) = tx.type_data + { tdn.create_ts = cr.create_ts.as_unix(); tdn.last_access_ts = cr.last_access_ts.as_unix(); tdn.last_write_ts = cr.last_write_ts.as_unix(); @@ -757,39 +842,39 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an } } true - }, + } _ => { events.push(SMBEvent::MalformedData); false - }, + } } } else { false } - }, + } SMB1_COMMAND_CLOSE => { - let fid = state.ssn2vec_map.remove(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)); + let fid = state + .ssn2vec_map + .remove(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)); if let Some(fid) = fid { SCLogDebug!("closing FID {:?}", fid); smb1_close_file(state, &fid, Direction::ToClient); } false - }, + } SMB1_COMMAND_TRANS => { smb1_trans_response_record(state, r); true - }, + } SMB1_COMMAND_SESSION_SETUP_ANDX => { smb1_session_setup_response(state, r, *andx_offset); true - }, + } SMB1_COMMAND_LOGOFF_ANDX => { tx_sync = true; false - }, - _ => { - false - }, + } + _ => false, }; if !have_tx && tx_sync { @@ -801,8 +886,12 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an tx.set_events(events); } } else if !have_tx && smb1_check_tx(command) { - let tx_key = SMBCommonHdr::new(SMBHDR_TYPE_GENERICTX, - key_ssn_id as u64, key_tree_id as u32, key_multiplex_id as u64); + let tx_key = SMBCommonHdr::new( + SMBHDR_TYPE_GENERICTX, + key_ssn_id as u64, + key_tree_id as u32, + key_multiplex_id as u64, + ); let _have_tx2 = match state.get_generic_tx(1, command as u16, &tx_key) { Some(tx) => { tx.request_done = true; @@ -811,11 +900,11 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an tx.set_status(r.nt_status, r.is_dos_error); tx.set_events(events); true - }, + } None => { SCLogDebug!("no TX found for key {:?}", tx_key); false - }, + } }; } else { SCLogDebug!("have tx for cmd {}", command); @@ -830,10 +919,13 @@ pub fn smb1_response_record(state: &mut SMBState, r: &SmbRecord) -> u32 { // continue for next andx command if any if smb1_command_is_andx(command) { - if let Ok((_, andx_hdr)) = smb1_parse_andx_header(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { - if (andx_hdr.andx_offset as usize) > andx_offset && - andx_hdr.andx_command != SMB1_COMMAND_NONE && - (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() { + if let Ok((_, andx_hdr)) = + smb1_parse_andx_header(&r.data[andx_offset - SMB1_HEADER_SIZE..]) + { + if (andx_hdr.andx_offset as usize) > andx_offset + && andx_hdr.andx_command != SMB1_COMMAND_NONE + && (andx_hdr.andx_offset as usize) - SMB1_HEADER_SIZE < r.data.len() + { andx_offset = andx_hdr.andx_offset as usize; command = andx_hdr.andx_command; continue; @@ -846,9 +938,8 @@ pub fn smb1_response_record(state: &mut SMBState, r: &SmbRecord) -> u32 { 0 } -pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) { + let mut events: Vec = Vec::new(); match parse_smb_trans_request_record(r.data, r) { Ok((_, rd)) => { @@ -858,16 +949,20 @@ pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) let mut pipe_dcerpc = false; if rd.pipe.is_some() { let pipe = rd.pipe.unwrap(); - state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), - pipe.fid.to_vec()); + state + .ssn2vec_map + .insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), pipe.fid.to_vec()); let mut frankenfid = pipe.fid.to_vec(); frankenfid.extend_from_slice(&u32_as_bytes(r.ssn_id)); let (_filename, is_dcerpc) = state.get_service_for_guid(&frankenfid); - SCLogDebug!("smb1_trans_request_record: name {} is_dcerpc {}", - _filename, is_dcerpc); + SCLogDebug!( + "smb1_trans_request_record: name {} is_dcerpc {}", + _filename, + is_dcerpc + ); pipe_dcerpc = is_dcerpc; } @@ -877,25 +972,26 @@ pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord) let vercmd = SMBVerCmdStat::new1(r.command); smb_write_dcerpc_record(state, vercmd, hdr, rd.data.data); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } smb1_request_record_generic(state, r, events); } -pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) { + let mut events: Vec = Vec::new(); match parse_smb_trans_response_record(r.data) { Ok((_, rd)) => { SCLogDebug!("TRANS response {:?}", rd); // see if we have a stored fid - let fid = match state.ssn2vec_map.remove( - &SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)) { + let fid = match state + .ssn2vec_map + .remove(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)) + { Some(f) => f, None => Vec::new(), }; @@ -906,14 +1002,22 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) let (_filename, is_dcerpc) = state.get_service_for_guid(&frankenfid); - SCLogDebug!("smb1_trans_response_record: name {} is_dcerpc {}", - _filename, is_dcerpc); + SCLogDebug!( + "smb1_trans_response_record: name {} is_dcerpc {}", + _filename, + is_dcerpc + ); // if we get status 'BUFFER_OVERFLOW' this is only a part of // the data. Store it in the ssn/tree for later use. if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { - let key = SMBHashKeyHdrGuid::new(SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid); - SCLogDebug!("SMBv1/TRANS: queueing data for len {} key {:?}", rd.data.len(), key); + let key = + SMBHashKeyHdrGuid::new(SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid); + SCLogDebug!( + "SMBv1/TRANS: queueing data for len {} key {:?}", + rd.data.len(), + key + ); state.ssnguid2vec_map.insert(key, rd.data.to_vec()); } else if is_dcerpc { SCLogDebug!("SMBv1 TRANS TO PIPE"); @@ -921,10 +1025,10 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) let vercmd = SMBVerCmdStat::new1_with_ntstatus(r.command, r.nt_status); smb_read_dcerpc_record(state, vercmd, hdr, &fid, rd.data); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } // generic tx as well. Set events if needed. @@ -932,12 +1036,13 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) } /// Handle WRITE, WRITE_ANDX, WRITE_AND_CLOSE request records -pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offset: usize, command: u8, nbss_remaining: u32) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_write_request_record( + state: &mut SMBState, r: &SmbRecord, andx_offset: usize, command: u8, nbss_remaining: u32, +) { + let mut events: Vec = Vec::new(); let result = if command == SMB1_COMMAND_WRITE_ANDX { - parse_smb1_write_andx_request_record(&r.data[andx_offset-SMB1_HEADER_SIZE..], andx_offset) + parse_smb1_write_andx_request_record(&r.data[andx_offset - SMB1_HEADER_SIZE..], andx_offset) } else if command == SMB1_COMMAND_WRITE { parse_smb1_write_request_record(r.data) } else { @@ -955,30 +1060,36 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse } let mut file_fid = rd.fid.to_vec(); file_fid.extend_from_slice(&u32_as_bytes(r.ssn_id)); - SCLogDebug!("SMBv1 WRITE: FID {:?} offset {}", - file_fid, rd.offset); + SCLogDebug!("SMBv1 WRITE: FID {:?} offset {}", file_fid, rd.offset); let file_name = match state.guid2name_map.get(&file_fid) { Some(n) => n.to_vec(), None => b"".to_vec(), }; let mut set_event_fileoverlap = false; - let found = match state.get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToServer) { - Some(tx) => { - let file_id : u32 = tx.id as u32; - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - if rd.offset < tdf.file_tracker.tracked { - set_event_fileoverlap = true; + let found = + match state.get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToServer) { + Some(tx) => { + let file_id: u32 = tx.id as u32; + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + if rd.offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + rd.offset, + rd.len, + false, + &file_id, + ); + SCLogDebug!("FID {:?} found at tx {} => {:?}", file_fid, tx.id, tx); } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, rd.offset, - rd.len, false, &file_id); - SCLogDebug!("FID {:?} found at tx {} => {:?}", file_fid, tx.id, tx); + true } - true - }, - None => { false }, - }; + None => false, + }; if !found { let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); let (share_name, is_pipe) = match state.ssn2tree_map.get(&tree_key) { @@ -993,13 +1104,19 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse } else { let tx = state.new_file_tx(&file_fid, &file_name, Direction::ToServer); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if rd.offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, rd.offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + rd.offset, + rd.len, + false, + &file_id, + ); tdf.share_name = share_name; SCLogDebug!("tdf {:?}", tdf); } @@ -1011,26 +1128,32 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse state.set_event(SMBEvent::FileOverlap); } - state.set_file_left(Direction::ToServer, rd.len, rd.data.len() as u32, file_fid.to_vec()); + state.set_file_left( + Direction::ToServer, + rd.len, + rd.data.len() as u32, + file_fid.to_vec(), + ); if command == SMB1_COMMAND_WRITE_AND_CLOSE { SCLogDebug!("closing FID {:?}", file_fid); smb1_close_file(state, &file_fid, Direction::ToServer); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } smb1_request_record_generic(state, r, events); } -pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offset: usize, nbss_remaining: u32) -{ - let mut events : Vec = Vec::new(); +pub fn smb1_read_response_record( + state: &mut SMBState, r: &SmbRecord, andx_offset: usize, nbss_remaining: u32, +) { + let mut events: Vec = Vec::new(); if r.nt_status == SMB_NTSTATUS_SUCCESS { - match parse_smb_read_andx_response_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_read_andx_response_record(&r.data[andx_offset - SMB1_HEADER_SIZE..]) { Ok((_, rd)) => { SCLogDebug!("SMBv1: read response => {:?}", rd); if rd.len > nbss_remaining + rd.data.len() as u32 { @@ -1044,18 +1167,21 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse let (offset, file_fid) = match state.ssn2vecoffset_map.remove(&fid_key) { Some(o) => (o.offset, o.guid), None => { - SCLogDebug!("SMBv1 READ response: reply to unknown request: left {} {:?}", - rd.len - rd.data.len() as u32, rd); + SCLogDebug!( + "SMBv1 READ response: reply to unknown request: left {} {:?}", + rd.len - rd.data.len() as u32, + rd + ); state.set_skip(Direction::ToClient, nbss_remaining); return; - }, + } }; SCLogDebug!("SMBv1 READ: FID {:?} offset {}", file_fid, offset); let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); let (is_pipe, share_name) = match state.ssn2tree_map.get(&tree_key) { Some(n) => (n.is_pipe, n.name.to_vec()), - _ => { (false, Vec::new()) }, + _ => (false, Vec::new()), }; if !is_pipe { let file_name = match state.guid2name_map.get(&file_fid) { @@ -1063,33 +1189,47 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse None => Vec::new(), }; let mut set_event_fileoverlap = false; - let found = match state.get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToClient) { + let found = match state + .get_file_tx_by_fuid_with_open_file(&file_fid, Direction::ToClient) + { Some(tx) => { if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); if offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); } true - }, - None => { false }, + } + None => false, }; if !found { let tx = state.new_file_tx(&file_fid, &file_name, Direction::ToClient); if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); if offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); tdf.share_name = share_name; } tx.vercmd.set_smb1_cmd(SMB1_COMMAND_READ_ANDX); @@ -1104,15 +1244,24 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse // hack: we store fid with ssn id mixed in, but here we want the // real thing instead. - let pure_fid = if file_fid.len() > 2 { &file_fid[0..2] } else { &[] }; + let pure_fid = if file_fid.len() > 2 { + &file_fid[0..2] + } else { + &[] + }; smb_read_dcerpc_record(state, vercmd, hdr, pure_fid, rd.data); } - state.set_file_left(Direction::ToClient, rd.len, rd.data.len() as u32, file_fid.to_vec()); + state.set_file_left( + Direction::ToClient, + rd.len, + rd.data.len() as u32, + file_fid.to_vec(), + ); } _ => { events.push(SMBEvent::MalformedData); - }, + } } } diff --git a/rust/src/smb/smb1_records.rs b/rust/src/smb/smb1_records.rs index bf767da8b08b..7a36adde7ac0 100644 --- a/rust/src/smb/smb1_records.rs +++ b/rust/src/smb/smb1_records.rs @@ -22,9 +22,9 @@ use crate::smb::smb_records::*; use nom7::bytes::streaming::{tag, take}; use nom7::combinator::{complete, cond, peek, rest, verify}; use nom7::error::{make_error, ErrorKind}; -use nom7::Err; use nom7::multi::many1; -use nom7::number::streaming::{le_u8, le_u16, le_u32, le_u64}; +use nom7::number::streaming::{le_u16, le_u32, le_u64, le_u8}; +use nom7::Err; use nom7::IResult; pub const SMB1_HEADER_SIZE: usize = 32; @@ -32,14 +32,17 @@ pub const SMB1_HEADER_SIZE: usize = 32; // SMB_FLAGS_REPLY in Microsoft docs. const SMB1_FLAGS_RESPONSE: u8 = 0x80; -fn smb_get_unicode_string_with_offset(i: &[u8], offset: usize) -> IResult<&[u8], Vec, SmbError> -{ +fn smb_get_unicode_string_with_offset( + i: &[u8], offset: usize, +) -> IResult<&[u8], Vec, SmbError> { let (i, _) = cond(offset % 2 == 1, take(1_usize))(i)?; smb_get_unicode_string(i) } /// take a string, unicode or ascii based on record -pub fn smb1_get_string<'a>(i: &'a[u8], r: &SmbRecord, offset: usize) -> IResult<&'a[u8], Vec, SmbError> { +pub fn smb1_get_string<'a>( + i: &'a [u8], r: &SmbRecord, offset: usize, +) -> IResult<&'a [u8], Vec, SmbError> { if r.has_unicode_support() { smb_get_unicode_string_with_offset(i, offset) } else { @@ -47,8 +50,7 @@ pub fn smb1_get_string<'a>(i: &'a[u8], r: &SmbRecord, offset: usize) -> IResult< } } - -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbParamBlockAndXHeader { pub wct: u8, pub andx_command: u8, @@ -68,12 +70,12 @@ pub fn smb1_parse_andx_header(i: &[u8]) -> IResult<&[u8], SmbParamBlockAndXHeade Ok((i, hdr)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1WriteRequestRecord<'a> { pub offset: u64, pub len: u32, - pub fid: &'a[u8], - pub data: &'a[u8], + pub fid: &'a [u8], + pub data: &'a [u8], } pub fn parse_smb1_write_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequestRecord> { @@ -90,12 +92,14 @@ pub fn parse_smb1_write_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequ offset: offset as u64, len: data_len as u32, fid, - data:file_data, + data: file_data, }; Ok((i, record)) } -pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IResult<&[u8], Smb1WriteRequestRecord> { +pub fn parse_smb1_write_andx_request_record( + i: &[u8], andx_offset: usize, +) -> IResult<&[u8], Smb1WriteRequestRecord> { let origin_i = i; let ax = andx_offset as u16; let (i, wct) = le_u8(i)?; @@ -109,14 +113,14 @@ pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IR let (i, _remaining) = le_u16(i)?; let (i, data_len_high) = le_u16(i)?; let (i, data_len_low) = le_u16(i)?; - let data_len = ((data_len_high as u32) << 16)|(data_len_low as u32); + let data_len = ((data_len_high as u32) << 16) | (data_len_low as u32); let (i, data_offset) = le_u16(i)?; - if data_offset < 0x3c || data_offset < ax{ + if data_offset < 0x3c || data_offset < ax { return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } let (i, high_offset) = cond(wct == 14, le_u32)(i)?; let (_i, _bcc) = le_u16(i)?; - let (i, _padding_data) = take(data_offset-ax)(origin_i)?; + let (i, _padding_data) = take(data_offset - ax)(origin_i)?; let (i, file_data) = take(std::cmp::min(data_len, i.len() as u32))(i)?; let record = Smb1WriteRequestRecord { @@ -128,7 +132,9 @@ pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IR Ok((i, record)) } -pub fn parse_smb1_write_and_close_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequestRecord> { +pub fn parse_smb1_write_and_close_request_record( + i: &[u8], +) -> IResult<&[u8], Smb1WriteRequestRecord> { let (i, _wct) = le_u8(i)?; let (i, fid) = take(2_usize)(i)?; let (i, count) = le_u16(i)?; @@ -146,25 +152,27 @@ pub fn parse_smb1_write_and_close_request_record(i: &[u8]) -> IResult<&[u8], Smb Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1NegotiateProtocolResponseRecord<'a> { pub dialect_idx: u16, - pub server_guid: &'a[u8], + pub server_guid: &'a [u8], } -pub fn parse_smb1_negotiate_protocol_response_record_error(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { - let (i, _wct) = le_u8(i)?; - let (i, _bcc) = le_u16(i)?; - let record = Smb1NegotiateProtocolResponseRecord { - dialect_idx: 0, - server_guid: &[], - }; - Ok((i, record)) +pub fn parse_smb1_negotiate_protocol_response_record_error( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { + let (i, _wct) = le_u8(i)?; + let (i, _bcc) = le_u16(i)?; + let record = Smb1NegotiateProtocolResponseRecord { + dialect_idx: 0, + server_guid: &[], + }; + Ok((i, record)) } -pub fn parse_smb1_negotiate_protocol_response_record_ok(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { +pub fn parse_smb1_negotiate_protocol_response_record_ok( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { let (i, _wct) = le_u8(i)?; let (i, dialect_idx) = le_u16(i)?; let (i, _sec_mode) = le_u8(i)?; @@ -182,8 +190,9 @@ pub fn parse_smb1_negotiate_protocol_response_record_ok(i: &[u8]) Ok((i, record)) } -pub fn parse_smb1_negotiate_protocol_response_record(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { +pub fn parse_smb1_negotiate_protocol_response_record( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolResponseRecord> { let (i, wct) = peek(le_u8)(i)?; match wct { 0 => parse_smb1_negotiate_protocol_response_record_error(i), @@ -191,13 +200,14 @@ pub fn parse_smb1_negotiate_protocol_response_record(i: &[u8]) } } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1NegotiateProtocolRecord<'a> { pub dialects: Vec<&'a [u8]>, } -pub fn parse_smb1_negotiate_protocol_record(i: &[u8]) - -> IResult<&[u8], Smb1NegotiateProtocolRecord> { +pub fn parse_smb1_negotiate_protocol_record( + i: &[u8], +) -> IResult<&[u8], Smb1NegotiateProtocolRecord> { let (i, _wtc) = le_u8(i)?; let (i, _bcc) = le_u16(i)?; // dialects is a list of [1 byte buffer format][string][0 terminator] @@ -206,15 +216,15 @@ pub fn parse_smb1_negotiate_protocol_record(i: &[u8]) Ok((i, record)) } - -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb1ResponseRecordTreeConnectAndX<'a> { - pub service: &'a[u8], - pub nativefs: &'a[u8], + pub service: &'a [u8], + pub nativefs: &'a [u8], } -pub fn parse_smb_connect_tree_andx_response_record(i: &[u8]) - -> IResult<&[u8], Smb1ResponseRecordTreeConnectAndX> { +pub fn parse_smb_connect_tree_andx_response_record( + i: &[u8], +) -> IResult<&[u8], Smb1ResponseRecordTreeConnectAndX> { let (i, wct) = le_u8(i)?; let (i, _andx_command) = le_u8(i)?; let (i, _) = take(1_usize)(i)?; // reserved @@ -224,35 +234,30 @@ pub fn parse_smb_connect_tree_andx_response_record(i: &[u8]) let (i, _bcc) = le_u16(i)?; let (i, service) = take_until_and_consume(b"\x00")(i)?; let (i, nativefs) = take_until_and_consume(b"\x00")(i)?; - let record = Smb1ResponseRecordTreeConnectAndX { - service, - nativefs - }; + let record = Smb1ResponseRecordTreeConnectAndX { service, nativefs }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTreeConnectAndX<'a> { pub path: Vec, - pub service: &'a[u8], + pub service: &'a [u8], } -pub fn parse_smb_connect_tree_andx_record<'a>(i: &'a[u8], r: &SmbRecord) - -> IResult<&'a[u8], SmbRecordTreeConnectAndX<'a>, SmbError> { - let (i, _skip1) = take(7_usize)(i)?; - let (i, pwlen) = le_u16(i)?; - let (i, _bcc) = le_u16(i)?; - let (i, _pw) = take(pwlen)(i)?; - let (i, path) = smb1_get_string(i, r, 11 + pwlen as usize)?; - let (i, service) = take_until_and_consume(b"\x00")(i)?; - let record = SmbRecordTreeConnectAndX { - path, - service - }; - Ok((i, record)) +pub fn parse_smb_connect_tree_andx_record<'a>( + i: &'a [u8], r: &SmbRecord, +) -> IResult<&'a [u8], SmbRecordTreeConnectAndX<'a>, SmbError> { + let (i, _skip1) = take(7_usize)(i)?; + let (i, pwlen) = le_u16(i)?; + let (i, _bcc) = le_u16(i)?; + let (i, _pw) = take(pwlen)(i)?; + let (i, path) = smb1_get_string(i, r, 11 + pwlen as usize)?; + let (i, service) = take_until_and_consume(b"\x00")(i)?; + let record = SmbRecordTreeConnectAndX { path, service }; + Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTransRequest<'a> { pub params: SmbRecordTransRequestParams, pub pipe: Option>, @@ -260,26 +265,23 @@ pub struct SmbRecordTransRequest<'a> { pub data: SmbRecordTransRequestData<'a>, } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbPipeProtocolRecord<'a> { pub function: u16, - pub fid: &'a[u8], + pub fid: &'a [u8], } -pub fn parse_smb_trans_request_record_pipe(i: &[u8]) - -> IResult<&[u8], SmbPipeProtocolRecord, SmbError> { +pub fn parse_smb_trans_request_record_pipe( + i: &[u8], +) -> IResult<&[u8], SmbPipeProtocolRecord, SmbError> { let (i, fun) = le_u16(i)?; let (i, fid) = take(2_usize)(i)?; - let record = SmbPipeProtocolRecord { - function: fun, - fid - }; + let record = SmbPipeProtocolRecord { function: fun, fid }; Ok((i, record)) } - -#[derive(Debug,PartialEq, Eq)] -pub struct SmbRecordTransRequestParams<> { +#[derive(Debug, PartialEq, Eq)] +pub struct SmbRecordTransRequestParams { pub max_data_cnt: u16, param_cnt: u16, param_offset: u16, @@ -288,47 +290,49 @@ pub struct SmbRecordTransRequestParams<> { bcc: u16, } -pub fn parse_smb_trans_request_record_params(i: &[u8]) - -> IResult<&[u8], (SmbRecordTransRequestParams, Option), SmbError> -{ - let (i, wct) = le_u8(i)?; - let (i, _total_param_cnt) = le_u16(i)?; - let (i, _total_data_count) = le_u16(i)?; - let (i, _max_param_cnt) = le_u16(i)?; - let (i, max_data_cnt) = le_u16(i)?; - let (i, _max_setup_cnt) = le_u8(i)?; - let (i, _) = take(1_usize)(i)?; // reserved - let (i, _) = take(2_usize)(i)?; // flags - let (i, _timeout) = le_u32(i)?; - let (i, _) = take(2_usize)(i)?; // reserved - let (i, param_cnt) = le_u16(i)?; - let (i, param_offset) = le_u16(i)?; - let (i, data_cnt) = le_u16(i)?; - let (i, data_offset) = le_u16(i)?; - let (i, setup_cnt) = le_u8(i)?; - let (i, _) = take(1_usize)(i)?; // reserved - let (i, pipe) = cond(wct == 16 && setup_cnt == 2 && data_cnt > 0, parse_smb_trans_request_record_pipe)(i)?; - let (i, bcc) = le_u16(i)?; - let params = SmbRecordTransRequestParams { - max_data_cnt, - param_cnt, - param_offset, - data_cnt, - data_offset, - bcc - }; - Ok((i, (params, pipe))) +pub fn parse_smb_trans_request_record_params( + i: &[u8], +) -> IResult<&[u8], (SmbRecordTransRequestParams, Option), SmbError> { + let (i, wct) = le_u8(i)?; + let (i, _total_param_cnt) = le_u16(i)?; + let (i, _total_data_count) = le_u16(i)?; + let (i, _max_param_cnt) = le_u16(i)?; + let (i, max_data_cnt) = le_u16(i)?; + let (i, _max_setup_cnt) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, _) = take(2_usize)(i)?; // flags + let (i, _timeout) = le_u32(i)?; + let (i, _) = take(2_usize)(i)?; // reserved + let (i, param_cnt) = le_u16(i)?; + let (i, param_offset) = le_u16(i)?; + let (i, data_cnt) = le_u16(i)?; + let (i, data_offset) = le_u16(i)?; + let (i, setup_cnt) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, pipe) = cond( + wct == 16 && setup_cnt == 2 && data_cnt > 0, + parse_smb_trans_request_record_pipe, + )(i)?; + let (i, bcc) = le_u16(i)?; + let params = SmbRecordTransRequestParams { + max_data_cnt, + param_cnt, + param_offset, + data_cnt, + data_offset, + bcc, + }; + Ok((i, (params, pipe))) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTransRequestData<'a> { - pub data: &'a[u8], + pub data: &'a [u8], } -pub fn parse_smb_trans_request_record_data(i: &[u8], - pad1: usize, param_cnt: u16, pad2: usize, data_len: u16) - -> IResult<&[u8], SmbRecordTransRequestData, SmbError> -{ +pub fn parse_smb_trans_request_record_data( + i: &[u8], pad1: usize, param_cnt: u16, pad2: usize, data_len: u16, +) -> IResult<&[u8], SmbRecordTransRequestData, SmbError> { let (i, _) = take(pad1)(i)?; let (i, _) = take(param_cnt)(i)?; let (i, _) = take(pad2)(i)?; @@ -337,9 +341,9 @@ pub fn parse_smb_trans_request_record_data(i: &[u8], Ok((i, req)) } -pub fn parse_smb_trans_request_record<'a>(i: &'a[u8], r: &SmbRecord) - -> IResult<&'a[u8], SmbRecordTransRequest<'a>, SmbError> -{ +pub fn parse_smb_trans_request_record<'a>( + i: &'a [u8], r: &SmbRecord, +) -> IResult<&'a [u8], SmbRecordTransRequest<'a>, SmbError> { let (rem, (params, pipe)) = parse_smb_trans_request_record_params(i)?; let mut offset = 32 + (i.len() - rem.len()); // init with SMB header SCLogDebug!("params {:?}: offset {}", params, offset); @@ -350,8 +354,7 @@ pub fn parse_smb_trans_request_record<'a>(i: &'a[u8], r: &SmbRecord) // spec says pad to 4 bytes, but traffic shows this doesn't // always happen. - let pad1 = if offset == params.param_offset as usize || - offset == params.data_offset as usize { + let pad1 = if offset == params.param_offset as usize || offset == params.data_offset as usize { 0 } else { offset % 4 @@ -370,68 +373,76 @@ pub fn parse_smb_trans_request_record<'a>(i: &'a[u8], r: &SmbRecord) }; SCLogDebug!("pad2 {}", pad2); - let d = match parse_smb_trans_request_record_data(rem2, - pad1, params.param_cnt, pad2, params.data_cnt) { + let d = match parse_smb_trans_request_record_data( + rem2, + pad1, + params.param_cnt, + pad2, + params.data_cnt, + ) { Ok((_, rd)) => rd, - Err(e) => { return Err(e); } + Err(e) => { + return Err(e); + } }; SCLogDebug!("d {:?}", d); d } else { - SmbRecordTransRequestData { data: &[], } // no data + SmbRecordTransRequestData { data: &[] } // no data }; let res = SmbRecordTransRequest { - params, pipe, txname: n, data: recdata, + params, + pipe, + txname: n, + data: recdata, }; Ok((rem, res)) } - -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordTransResponse<'a> { pub data_cnt: u16, pub bcc: u16, - pub data: &'a[u8], + pub data: &'a [u8], } pub fn parse_smb_trans_response_error_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse> { - let (i, _wct) = le_u8(i)?; - let (i, bcc) = le_u16(i)?; - let resp = SmbRecordTransResponse { - data_cnt: 0, - bcc, - data: &[], - }; - Ok((i, resp)) + let (i, _wct) = le_u8(i)?; + let (i, bcc) = le_u16(i)?; + let resp = SmbRecordTransResponse { + data_cnt: 0, + bcc, + data: &[], + }; + Ok((i, resp)) } pub fn parse_smb_trans_response_regular_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse> { - let (i, wct) = le_u8(i)?; - let (i, _total_param_cnt) = le_u16(i)?; - let (i, _total_data_count) = le_u16(i)?; - let (i, _) = take(2_usize)(i)?; // reserved - let (i, _param_cnt) = le_u16(i)?; - let (i, _param_offset) = le_u16(i)?; - let (i, _param_displacement) = le_u16(i)?; - let (i, data_cnt) = le_u16(i)?; - let (i, data_offset) = le_u16(i)?; - let (i, _data_displacement) = le_u16(i)?; - let (i, _setup_cnt) = le_u8(i)?; - let (i, _) = take(1_usize)(i)?; // reserved - let (i, bcc) = le_u16(i)?; - let (i, _) = take(1_usize)(i)?; // padding - let (i, _padding_evasion) = cond( - data_offset > 36+2*(wct as u16), - |b| take(data_offset - (36+2*(wct as u16)))(b) - )(i)?; - let (i, data) = take(data_cnt)(i)?; - let resp = SmbRecordTransResponse { - data_cnt, - bcc, - data - }; - Ok((i, resp)) + let (i, wct) = le_u8(i)?; + let (i, _total_param_cnt) = le_u16(i)?; + let (i, _total_data_count) = le_u16(i)?; + let (i, _) = take(2_usize)(i)?; // reserved + let (i, _param_cnt) = le_u16(i)?; + let (i, _param_offset) = le_u16(i)?; + let (i, _param_displacement) = le_u16(i)?; + let (i, data_cnt) = le_u16(i)?; + let (i, data_offset) = le_u16(i)?; + let (i, _data_displacement) = le_u16(i)?; + let (i, _setup_cnt) = le_u8(i)?; + let (i, _) = take(1_usize)(i)?; // reserved + let (i, bcc) = le_u16(i)?; + let (i, _) = take(1_usize)(i)?; // padding + let (i, _padding_evasion) = cond(data_offset > 36 + 2 * (wct as u16), |b| { + take(data_offset - (36 + 2 * (wct as u16)))(b) + })(i)?; + let (i, data) = take(data_cnt)(i)?; + let resp = SmbRecordTransResponse { + data_cnt, + bcc, + data, + }; + Ok((i, resp)) } pub fn parse_smb_trans_response_record(i: &[u8]) -> IResult<&[u8], SmbRecordTransResponse> { @@ -442,9 +453,9 @@ pub fn parse_smb_trans_response_record(i: &[u8]) -> IResult<&[u8], SmbRecordTran } } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecordSetupAndX<'a> { - pub sec_blob: &'a[u8], + pub sec_blob: &'a [u8], } pub fn parse_smb_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbRecordSetupAndX> { @@ -457,39 +468,37 @@ pub fn parse_smb_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbRecordSetupAnd Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbResponseRecordSetupAndX<'a> { - pub sec_blob: &'a[u8], + pub sec_blob: &'a [u8], } fn response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { - let (i, _skip1) = take(7_usize)(i)?; - let (i, sec_blob_len) = le_u16(i)?; - let (i, _bcc) = le_u16(i)?; - let (i, sec_blob) = take(sec_blob_len)(i)?; - let record = SmbResponseRecordSetupAndX { sec_blob }; - Ok((i, record)) + let (i, _skip1) = take(7_usize)(i)?; + let (i, sec_blob_len) = le_u16(i)?; + let (i, _bcc) = le_u16(i)?; + let (i, sec_blob) = take(sec_blob_len)(i)?; + let record = SmbResponseRecordSetupAndX { sec_blob }; + Ok((i, record)) } fn response_setup_andx_wct3_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { - let (i, _skip1) = take(7_usize)(i)?; - let (i, _bcc) = le_u16(i)?; - let record = SmbResponseRecordSetupAndX { - sec_blob: &[], - }; - Ok((i, record)) + let (i, _skip1) = take(7_usize)(i)?; + let (i, _bcc) = le_u16(i)?; + let record = SmbResponseRecordSetupAndX { sec_blob: &[] }; + Ok((i, record)) } fn response_setup_andx_error_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { - let (i, _wct) = le_u8(i)?; - let (i, _bcc) = le_u16(i)?; - let record = SmbResponseRecordSetupAndX { - sec_blob: &[], - }; - Ok((i, record)) + let (i, _wct) = le_u8(i)?; + let (i, _bcc) = le_u16(i)?; + let record = SmbResponseRecordSetupAndX { sec_blob: &[] }; + Ok((i, record)) } -pub fn parse_smb_response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbResponseRecordSetupAndX> { +pub fn parse_smb_response_setup_andx_record( + i: &[u8], +) -> IResult<&[u8], SmbResponseRecordSetupAndX> { let (i, wct) = peek(le_u8)(i)?; match wct { 0 => response_setup_andx_error_record(i), @@ -498,9 +507,9 @@ pub fn parse_smb_response_setup_andx_record(i: &[u8]) -> IResult<&[u8], SmbRespo } } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestReadAndXRecord<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], pub size: u64, pub offset: u64, } @@ -516,19 +525,21 @@ pub fn parse_smb_read_andx_request_record(i: &[u8]) -> IResult<&[u8], SmbRequest let (i, _) = take(2_usize)(i)?; let (i, max_count_high) = le_u32(i)?; let (i, _) = take(2_usize)(i)?; - let (i, high_offset) = cond(wct == 12,le_u32)(i)?; // only from wct ==12? + let (i, high_offset) = cond(wct == 12, le_u32)(i)?; // only from wct ==12? let record = SmbRequestReadAndXRecord { fid, - size: (((max_count_high as u64) << 16)|max_count_low as u64), - offset: high_offset.map(|ho| (ho as u64) << 32 | offset as u64).unwrap_or(0), + size: (((max_count_high as u64) << 16) | max_count_low as u64), + offset: high_offset + .map(|ho| (ho as u64) << 32 | offset as u64) + .unwrap_or(0), }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbResponseReadAndXRecord<'a> { pub len: u32, - pub data: &'a[u8], + pub data: &'a [u8], } pub fn parse_smb_read_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResponseReadAndXRecord> { @@ -542,30 +553,28 @@ pub fn parse_smb_read_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbRespon let (i, data_len_high) = le_u32(i)?; let (i, _) = take(6_usize)(i)?; // reserved let (i, bcc) = le_u16(i)?; - let (i, _padding) = cond( - bcc > data_len_low, - |b| take(bcc - data_len_low)(b) - )(i)?; // TODO figure out how this works with data_len_high - let (i, _padding_evasion) = cond( - data_offset > 36+2*(wct as u16), - |b| take(data_offset - (36+2*(wct as u16)))(b) - )(i)?; + let (i, _padding) = cond(bcc > data_len_low, |b| take(bcc - data_len_low)(b))(i)?; // TODO figure out how this works with data_len_high + let (i, _padding_evasion) = cond(data_offset > 36 + 2 * (wct as u16), |b| { + take(data_offset - (36 + 2 * (wct as u16)))(b) + })(i)?; let (i, file_data) = rest(i)?; let record = SmbResponseReadAndXRecord { - len: ((data_len_high << 16)|data_len_low as u32), + len: ((data_len_high << 16) | data_len_low as u32), data: file_data, - }; + }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestRenameRecord { pub oldname: Vec, pub newname: Vec, } -pub fn parse_smb_rename_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestRenameRecord, SmbError> { +pub fn parse_smb_rename_request_record( + i: &[u8], +) -> IResult<&[u8], SmbRequestRenameRecord, SmbError> { let (i, _wct) = le_u8(i)?; let (i, _search_attr) = le_u16(i)?; let (i, _bcc) = le_u16(i)?; @@ -573,23 +582,20 @@ pub fn parse_smb_rename_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestRen let (i, oldname) = smb_get_unicode_string(i)?; let (i, _newtype) = le_u8(i)?; let (i, newname) = smb_get_unicode_string_with_offset(i, 1)?; // HACK if we assume oldname is a series of utf16 chars offset would be 1 - let record = SmbRequestRenameRecord { - oldname, - newname - }; + let record = SmbRequestRenameRecord { oldname, newname }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct SmbRequestCreateAndXRecord<> { +#[derive(Debug, PartialEq, Eq)] +pub struct SmbRequestCreateAndXRecord { pub disposition: u32, pub create_options: u32, pub file_name: Vec, } -pub fn parse_smb_create_andx_request_record<'a>(i: &'a[u8], r: &SmbRecord) - -> IResult<&'a[u8], SmbRequestCreateAndXRecord<>, SmbError> -{ +pub fn parse_smb_create_andx_request_record<'a>( + i: &'a [u8], r: &SmbRecord, +) -> IResult<&'a [u8], SmbRequestCreateAndXRecord, SmbError> { let (i, _skip1) = take(6_usize)(i)?; let (i, file_name_len) = le_u16(i)?; let (i, _skip3) = take(28_usize)(i)?; @@ -597,10 +603,9 @@ pub fn parse_smb_create_andx_request_record<'a>(i: &'a[u8], r: &SmbRecord) let (i, create_options) = le_u32(i)?; let (i, _skip2) = take(5_usize)(i)?; let (i, bcc) = le_u16(i)?; - let (i, file_name) = cond( - bcc >= file_name_len, - |b| smb1_get_string(b, r, (bcc - file_name_len) as usize) - )(i)?; + let (i, file_name) = cond(bcc >= file_name_len, |b| { + smb1_get_string(b, r, (bcc - file_name_len) as usize) + })(i)?; let (i, _skip3) = rest(i)?; let record = SmbRequestCreateAndXRecord { disposition, @@ -610,13 +615,14 @@ pub fn parse_smb_create_andx_request_record<'a>(i: &'a[u8], r: &SmbRecord) Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct Trans2RecordParamSetFileInfoDisposition<> { +#[derive(Debug, PartialEq, Eq)] +pub struct Trans2RecordParamSetFileInfoDisposition { pub delete: bool, } -pub fn parse_trans2_request_data_set_file_info_disposition(i: &[u8]) - -> IResult<&[u8], Trans2RecordParamSetFileInfoDisposition> { +pub fn parse_trans2_request_data_set_file_info_disposition( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetFileInfoDisposition> { let (i, delete) = le_u8(i)?; let record = Trans2RecordParamSetFileInfoDisposition { delete: delete & 1 == 1, @@ -624,45 +630,51 @@ pub fn parse_trans2_request_data_set_file_info_disposition(i: &[u8]) Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Trans2RecordParamSetFileInfo<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], pub loi: u16, } -pub fn parse_trans2_request_params_set_file_info(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetFileInfo> { +pub fn parse_trans2_request_params_set_file_info( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetFileInfo> { let (i, fid) = take(2_usize)(i)?; let (i, loi) = le_u16(i)?; let record = Trans2RecordParamSetFileInfo { fid, loi }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Trans2RecordParamSetFileInfoRename<'a> { pub replace: bool, - pub newname: &'a[u8], + pub newname: &'a [u8], } -pub fn parse_trans2_request_data_set_file_info_rename(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetFileInfoRename> { +pub fn parse_trans2_request_data_set_file_info_rename( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetFileInfoRename> { let (i, replace) = le_u8(i)?; let (i, _reserved) = take(3_usize)(i)?; let (i, _root_dir) = take(4_usize)(i)?; let (i, newname_len) = le_u32(i)?; let (i, newname) = take(newname_len)(i)?; let record = Trans2RecordParamSetFileInfoRename { - replace: replace==1, + replace: replace == 1, newname, }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct Trans2RecordParamSetPathInfo<> { +#[derive(Debug, PartialEq, Eq)] +pub struct Trans2RecordParamSetPathInfo { pub loi: u16, pub oldname: Vec, } -pub fn parse_trans2_request_params_set_path_info(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetPathInfo, SmbError> { +pub fn parse_trans2_request_params_set_path_info( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetPathInfo, SmbError> { let (i, loi) = le_u16(i)?; let (i, _reserved) = take(4_usize)(i)?; let (i, oldname) = smb_get_unicode_string(i)?; @@ -670,30 +682,32 @@ pub fn parse_trans2_request_params_set_path_info(i: &[u8]) -> IResult<&[u8], Tra Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Trans2RecordParamSetPathInfoRename<'a> { pub replace: bool, - pub newname: &'a[u8], + pub newname: &'a [u8], } -pub fn parse_trans2_request_data_set_path_info_rename(i: &[u8]) -> IResult<&[u8], Trans2RecordParamSetPathInfoRename> { +pub fn parse_trans2_request_data_set_path_info_rename( + i: &[u8], +) -> IResult<&[u8], Trans2RecordParamSetPathInfoRename> { let (i, replace) = le_u8(i)?; let (i, _reserved) = take(3_usize)(i)?; let (i, _root_dir) = take(4_usize)(i)?; let (i, newname_len) = le_u32(i)?; let (i, newname) = take(newname_len)(i)?; let record = Trans2RecordParamSetPathInfoRename { - replace: replace==1, - newname + replace: replace == 1, + newname, }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestTrans2Record<'a> { pub subcmd: u16, - pub setup_blob: &'a[u8], - pub data_blob: &'a[u8], + pub setup_blob: &'a [u8], + pub data_blob: &'a [u8], } pub fn parse_smb_trans2_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestTrans2Record> { @@ -718,23 +732,22 @@ pub fn parse_smb_trans2_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestTra //TODO test and use param_offset let (i, _padding) = take(3_usize)(i)?; let (i, setup_blob) = take(param_cnt)(i)?; - let (i, _padding2) = cond( - data_offset > param_offset + param_cnt, - |b| take(data_offset - param_offset - param_cnt)(b) - )(i)?; + let (i, _padding2) = cond(data_offset > param_offset + param_cnt, |b| { + take(data_offset - param_offset - param_cnt)(b) + })(i)?; let (i, data_blob) = take(data_cnt)(i)?; let record = SmbRequestTrans2Record { subcmd, setup_blob, - data_blob + data_blob, }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbResponseCreateAndXRecord<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], pub create_ts: SMBFiletime, pub last_access_ts: SMBFiletime, pub last_write_ts: SMBFiletime, @@ -742,7 +755,9 @@ pub struct SmbResponseCreateAndXRecord<'a> { pub file_size: u64, } -pub fn parse_smb_create_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResponseCreateAndXRecord> { +pub fn parse_smb_create_andx_response_record( + i: &[u8], +) -> IResult<&[u8], SmbResponseCreateAndXRecord> { let (i, wct) = le_u8(i)?; let (i, _andx_command) = le_u8(i)?; let (i, _) = take(1_usize)(i)?; // reserved @@ -773,22 +788,20 @@ pub fn parse_smb_create_andx_response_record(i: &[u8]) -> IResult<&[u8], SmbResp Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRequestCloseRecord<'a> { - pub fid: &'a[u8], + pub fid: &'a [u8], } pub fn parse_smb1_close_request_record(i: &[u8]) -> IResult<&[u8], SmbRequestCloseRecord> { let (i, _) = take(1_usize)(i)?; let (i, fid) = take(2_usize)(i)?; - let record = SmbRequestCloseRecord { - fid, - }; + let record = SmbRequestCloseRecord { fid }; Ok((i, record)) } -#[derive(Debug,PartialEq, Eq)] -pub struct SmbVersion<> { +#[derive(Debug, PartialEq, Eq)] +pub struct SmbVersion { pub version: u8, } @@ -799,7 +812,7 @@ pub fn parse_smb_version(i: &[u8]) -> IResult<&[u8], SmbVersion> { Ok((i, version)) } -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct SmbRecord<'a> { pub command: u8, pub is_dos_error: bool, @@ -814,7 +827,7 @@ pub struct SmbRecord<'a> { pub process_id: u32, pub ssn_id: u32, - pub data: &'a[u8], + pub data: &'a [u8], } impl<'a> SmbRecord<'a> { @@ -853,7 +866,7 @@ pub fn parse_smb_record(i: &[u8]) -> IResult<&[u8], SmbRecord> { nt_status, flags, flags2, - is_dos_error: (flags2 & 0x4000_u16 == 0),// && nt_status != 0), + is_dos_error: (flags2 & 0x4000_u16 == 0), // && nt_status != 0), tree_id, user_id, multiplex_id, @@ -870,7 +883,7 @@ pub fn parse_smb_record(i: &[u8]) -> IResult<&[u8], SmbRecord> { fn test_parse_smb1_write_andx_request_record_origin() { let data = hex::decode("0eff000000014000000000ff00000008001400000014003f000000000014004142434445464748494a4b4c4d4e4f5051520a0a").unwrap(); let result = parse_smb1_write_andx_request_record(&data, SMB1_HEADER_SIZE); - assert!(result.is_ok()); + assert!(result.is_ok()); let record = result.unwrap().1; assert_eq!(record.offset, 0); assert_eq!(record.len, 20); diff --git a/rust/src/smb/smb1_session.rs b/rust/src/smb/smb1_session.rs index c39c7ce98fc9..644b2ad09473 100644 --- a/rust/src/smb/smb1_session.rs +++ b/rust/src/smb/smb1_session.rs @@ -15,11 +15,11 @@ * 02110-1301, USA. */ -use crate::smb::smb_records::*; -use crate::smb::smb1_records::*; -use crate::smb::smb::*; -use crate::smb::events::*; use crate::smb::auth::*; +use crate::smb::events::*; +use crate::smb::smb::*; +use crate::smb::smb1_records::*; +use crate::smb::smb_records::*; #[derive(Debug)] pub struct SessionSetupRequest { @@ -34,27 +34,27 @@ pub struct SessionSetupResponse { pub native_lm: Vec, } -pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupRequest -{ +pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupRequest { if blob.len() > 1 && r.has_unicode_support() { let offset = r.data.len() - blob.len(); let blob = if offset % 2 == 1 { &blob[1..] } else { blob }; let (native_os, native_lm, primary_domain) = match smb_get_unicode_string(blob) { - Ok((rem, n1)) => { - match smb_get_unicode_string(rem) { - Ok((rem, n2)) => { - match smb_get_unicode_string(rem) { - Ok((_, n3)) => { (n1, n2, n3) }, - _ => { (n1, n2, Vec::new()) }, - } - }, - _ => { (n1, Vec::new(), Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_unicode_string(rem) { + Ok((rem, n2)) => match smb_get_unicode_string(rem) { + Ok((_, n3)) => (n1, n2, n3), + _ => (n1, n2, Vec::new()), + }, + _ => (n1, Vec::new(), Vec::new()), }, - _ => { (Vec::new(), Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new(), Vec::new()), }; - SCLogDebug!("name1 {:?} name2 {:?} name3 {:?}", native_os,native_lm,primary_domain); + SCLogDebug!( + "name1 {:?} name2 {:?} name3 {:?}", + native_os, + native_lm, + primary_domain + ); SessionSetupRequest { native_os, native_lm, @@ -62,18 +62,14 @@ pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> Sessi } } else { let (native_os, native_lm, primary_domain) = match smb_get_ascii_string(blob) { - Ok((rem, n1)) => { - match smb_get_ascii_string(rem) { - Ok((rem, n2)) => { - match smb_get_ascii_string(rem) { - Ok((_, n3)) => { (n1, n2, n3) }, - _ => { (n1, n2, Vec::new()) }, - } - }, - _ => { (n1, Vec::new(), Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_ascii_string(rem) { + Ok((rem, n2)) => match smb_get_ascii_string(rem) { + Ok((_, n3)) => (n1, n2, n3), + _ => (n1, n2, Vec::new()), + }, + _ => (n1, Vec::new(), Vec::new()), }, - _ => { (Vec::new(), Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new(), Vec::new()), }; SCLogDebug!("session_setup_request_host_info: not unicode"); @@ -85,22 +81,19 @@ pub fn smb1_session_setup_request_host_info(r: &SmbRecord, blob: &[u8]) -> Sessi } } -pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupResponse -{ +pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> SessionSetupResponse { if blob.len() > 1 && r.has_unicode_support() { let offset = r.data.len() - blob.len(); let blob = if offset % 2 == 1 { &blob[1..] } else { blob }; let (native_os, native_lm) = match smb_get_unicode_string(blob) { - Ok((rem, n1)) => { - match smb_get_unicode_string(rem) { - Ok((_, n2)) => (n1, n2), - _ => { (n1, Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_unicode_string(rem) { + Ok((_, n2)) => (n1, n2), + _ => (n1, Vec::new()), }, - _ => { (Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new()), }; - SCLogDebug!("name1 {:?} name2 {:?}", native_os,native_lm); + SCLogDebug!("name1 {:?} name2 {:?}", native_os, native_lm); SessionSetupResponse { native_os, native_lm, @@ -108,13 +101,11 @@ pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> Sess } else { SCLogDebug!("session_setup_response_host_info: not unicode"); let (native_os, native_lm) = match smb_get_ascii_string(blob) { - Ok((rem, n1)) => { - match smb_get_ascii_string(rem) { - Ok((_, n2)) => (n1, n2), - _ => { (n1, Vec::new()) }, - } + Ok((rem, n1)) => match smb_get_ascii_string(rem) { + Ok((_, n2)) => (n1, n2), + _ => (n1, Vec::new()), }, - _ => { (Vec::new(), Vec::new()) }, + _ => (Vec::new(), Vec::new()), }; SessionSetupResponse { native_os, @@ -123,14 +114,17 @@ pub fn smb1_session_setup_response_host_info(r: &SmbRecord, blob: &[u8]) -> Sess } } -pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) -{ +pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) { SCLogDebug!("SMB1_COMMAND_SESSION_SETUP_ANDX user_id {}", r.user_id); #[allow(clippy::single_match)] - match parse_smb_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { + match parse_smb_setup_andx_record(&r.data[andx_offset - SMB1_HEADER_SIZE..]) { Ok((rem, setup)) => { - let hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.ssn_id as u64, 0, r.multiplex_id as u64); + let hdr = SMBCommonHdr::new( + SMBHDR_TYPE_HEADER, + r.ssn_id as u64, + 0, + r.multiplex_id as u64, + ); let tx = state.new_sessionsetup_tx(hdr); tx.vercmd.set_smb1_cmd(r.command); @@ -146,24 +140,23 @@ pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offs } } } - }, + } _ => { // events.push(SMBEvent::MalformedData); - }, + } } } -fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_offset: usize) -{ - match parse_smb_response_setup_andx_record(&r.data[andx_offset-SMB1_HEADER_SIZE..]) { +fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_offset: usize) { + match parse_smb_response_setup_andx_record(&r.data[andx_offset - SMB1_HEADER_SIZE..]) { Ok((rem, _setup)) => { if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data { td.response_host = Some(smb1_session_setup_response_host_info(r, rem)); } - }, + } _ => { tx.set_event(SMBEvent::MalformedData); - }, + } } // update tx even if we can't parse the response tx.hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER); // to overwrite ssn_id 0 @@ -171,32 +164,37 @@ fn smb1_session_setup_update_tx(tx: &mut SMBTransaction, r: &SmbRecord, andx_off tx.response_done = true; } -pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) -{ +pub fn smb1_session_setup_response(state: &mut SMBState, r: &SmbRecord, andx_offset: usize) { // try exact match with session id already set (e.g. NTLMSSP AUTH phase) - let found = r.ssn_id != 0 && match state.get_sessionsetup_tx( - SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.ssn_id as u64, 0, r.multiplex_id as u64)) - { - Some(tx) => { - smb1_session_setup_update_tx(tx, r, andx_offset); - SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); - true - }, - None => { false }, - }; + let found = r.ssn_id != 0 + && match state.get_sessionsetup_tx(SMBCommonHdr::new( + SMBHDR_TYPE_HEADER, + r.ssn_id as u64, + 0, + r.multiplex_id as u64, + )) { + Some(tx) => { + smb1_session_setup_update_tx(tx, r, andx_offset); + SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); + true + } + None => false, + }; // otherwise try match with ssn id 0 (e.g. NTLMSSP_NEGOTIATE) if !found { - match state.get_sessionsetup_tx( - SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.multiplex_id as u64)) - { + match state.get_sessionsetup_tx(SMBCommonHdr::new( + SMBHDR_TYPE_HEADER, + 0, + 0, + r.multiplex_id as u64, + )) { Some(tx) => { smb1_session_setup_update_tx(tx, r, andx_offset); SCLogDebug!("smb1_session_setup_response: tx {:?}", tx); - }, + } None => { SCLogDebug!("smb1_session_setup_response: tx not found for {:?}", r); - }, + } } } } diff --git a/rust/src/smb/smb2.rs b/rust/src/smb/smb2.rs index a2fe021b0276..c88c4feaea3b 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -19,59 +19,61 @@ use nom7::Err; use crate::core::*; -use crate::smb::smb::*; -use crate::smb::smb2_records::*; -use crate::smb::smb2_session::*; -use crate::smb::smb2_ioctl::*; use crate::smb::dcerpc::*; use crate::smb::events::*; use crate::smb::files::*; +use crate::smb::smb::*; +use crate::smb::smb2_ioctl::*; +use crate::smb::smb2_records::*; +use crate::smb::smb2_session::*; use crate::smb::smb_status::*; -pub const SMB2_COMMAND_NEGOTIATE_PROTOCOL: u16 = 0; -pub const SMB2_COMMAND_SESSION_SETUP: u16 = 1; -pub const SMB2_COMMAND_SESSION_LOGOFF: u16 = 2; -pub const SMB2_COMMAND_TREE_CONNECT: u16 = 3; -pub const SMB2_COMMAND_TREE_DISCONNECT: u16 = 4; -pub const SMB2_COMMAND_CREATE: u16 = 5; -pub const SMB2_COMMAND_CLOSE: u16 = 6; -pub const SMB2_COMMAND_FLUSH: u16 = 7; -pub const SMB2_COMMAND_READ: u16 = 8; -pub const SMB2_COMMAND_WRITE: u16 = 9; -pub const SMB2_COMMAND_LOCK: u16 = 10; -pub const SMB2_COMMAND_IOCTL: u16 = 11; -pub const SMB2_COMMAND_CANCEL: u16 = 12; -pub const SMB2_COMMAND_KEEPALIVE: u16 = 13; -pub const SMB2_COMMAND_FIND: u16 = 14; -pub const SMB2_COMMAND_CHANGE_NOTIFY: u16 = 15; -pub const SMB2_COMMAND_GET_INFO: u16 = 16; -pub const SMB2_COMMAND_SET_INFO: u16 = 17; -pub const SMB2_COMMAND_OPLOCK_BREAK: u16 = 18; +pub const SMB2_COMMAND_NEGOTIATE_PROTOCOL: u16 = 0; +pub const SMB2_COMMAND_SESSION_SETUP: u16 = 1; +pub const SMB2_COMMAND_SESSION_LOGOFF: u16 = 2; +pub const SMB2_COMMAND_TREE_CONNECT: u16 = 3; +pub const SMB2_COMMAND_TREE_DISCONNECT: u16 = 4; +pub const SMB2_COMMAND_CREATE: u16 = 5; +pub const SMB2_COMMAND_CLOSE: u16 = 6; +pub const SMB2_COMMAND_FLUSH: u16 = 7; +pub const SMB2_COMMAND_READ: u16 = 8; +pub const SMB2_COMMAND_WRITE: u16 = 9; +pub const SMB2_COMMAND_LOCK: u16 = 10; +pub const SMB2_COMMAND_IOCTL: u16 = 11; +pub const SMB2_COMMAND_CANCEL: u16 = 12; +pub const SMB2_COMMAND_KEEPALIVE: u16 = 13; +pub const SMB2_COMMAND_FIND: u16 = 14; +pub const SMB2_COMMAND_CHANGE_NOTIFY: u16 = 15; +pub const SMB2_COMMAND_GET_INFO: u16 = 16; +pub const SMB2_COMMAND_SET_INFO: u16 = 17; +pub const SMB2_COMMAND_OPLOCK_BREAK: u16 = 18; pub fn smb2_command_string(c: u16) -> String { match c { - SMB2_COMMAND_NEGOTIATE_PROTOCOL => "SMB2_COMMAND_NEGOTIATE_PROTOCOL", - SMB2_COMMAND_SESSION_SETUP => "SMB2_COMMAND_SESSION_SETUP", - SMB2_COMMAND_SESSION_LOGOFF => "SMB2_COMMAND_SESSION_LOGOFF", - SMB2_COMMAND_TREE_CONNECT => "SMB2_COMMAND_TREE_CONNECT", - SMB2_COMMAND_TREE_DISCONNECT => "SMB2_COMMAND_TREE_DISCONNECT", - SMB2_COMMAND_CREATE => "SMB2_COMMAND_CREATE", - SMB2_COMMAND_CLOSE => "SMB2_COMMAND_CLOSE", - SMB2_COMMAND_READ => "SMB2_COMMAND_READ", - SMB2_COMMAND_FLUSH => "SMB2_COMMAND_FLUSH", - SMB2_COMMAND_WRITE => "SMB2_COMMAND_WRITE", - SMB2_COMMAND_LOCK => "SMB2_COMMAND_LOCK", - SMB2_COMMAND_IOCTL => "SMB2_COMMAND_IOCTL", - SMB2_COMMAND_CANCEL => "SMB2_COMMAND_CANCEL", - SMB2_COMMAND_KEEPALIVE => "SMB2_COMMAND_KEEPALIVE", - SMB2_COMMAND_FIND => "SMB2_COMMAND_FIND", - SMB2_COMMAND_CHANGE_NOTIFY => "SMB2_COMMAND_CHANGE_NOTIFY", - SMB2_COMMAND_GET_INFO => "SMB2_COMMAND_GET_INFO", - SMB2_COMMAND_SET_INFO => "SMB2_COMMAND_SET_INFO", - SMB2_COMMAND_OPLOCK_BREAK => "SMB2_COMMAND_OPLOCK_BREAK", - _ => { return (c).to_string(); }, - }.to_string() - + SMB2_COMMAND_NEGOTIATE_PROTOCOL => "SMB2_COMMAND_NEGOTIATE_PROTOCOL", + SMB2_COMMAND_SESSION_SETUP => "SMB2_COMMAND_SESSION_SETUP", + SMB2_COMMAND_SESSION_LOGOFF => "SMB2_COMMAND_SESSION_LOGOFF", + SMB2_COMMAND_TREE_CONNECT => "SMB2_COMMAND_TREE_CONNECT", + SMB2_COMMAND_TREE_DISCONNECT => "SMB2_COMMAND_TREE_DISCONNECT", + SMB2_COMMAND_CREATE => "SMB2_COMMAND_CREATE", + SMB2_COMMAND_CLOSE => "SMB2_COMMAND_CLOSE", + SMB2_COMMAND_READ => "SMB2_COMMAND_READ", + SMB2_COMMAND_FLUSH => "SMB2_COMMAND_FLUSH", + SMB2_COMMAND_WRITE => "SMB2_COMMAND_WRITE", + SMB2_COMMAND_LOCK => "SMB2_COMMAND_LOCK", + SMB2_COMMAND_IOCTL => "SMB2_COMMAND_IOCTL", + SMB2_COMMAND_CANCEL => "SMB2_COMMAND_CANCEL", + SMB2_COMMAND_KEEPALIVE => "SMB2_COMMAND_KEEPALIVE", + SMB2_COMMAND_FIND => "SMB2_COMMAND_FIND", + SMB2_COMMAND_CHANGE_NOTIFY => "SMB2_COMMAND_CHANGE_NOTIFY", + SMB2_COMMAND_GET_INFO => "SMB2_COMMAND_GET_INFO", + SMB2_COMMAND_SET_INFO => "SMB2_COMMAND_SET_INFO", + SMB2_COMMAND_OPLOCK_BREAK => "SMB2_COMMAND_OPLOCK_BREAK", + _ => { + return (c).to_string(); + } + } + .to_string() } pub fn smb2_dialect_string(d: u16) -> String { @@ -85,24 +87,25 @@ pub fn smb2_dialect_string(d: u16) -> String { 0x0302 => "3.02", 0x0310 => "3.10", 0x0311 => "3.11", - _ => { return (d).to_string(); }, - }.to_string() + _ => { + return (d).to_string(); + } + } + .to_string() } // later we'll use this to determine if we need to // track a ssn per type fn smb2_create_new_tx(cmd: u16) -> bool { match cmd { - SMB2_COMMAND_READ | - SMB2_COMMAND_WRITE | - SMB2_COMMAND_GET_INFO | - SMB2_COMMAND_SET_INFO => { false }, - _ => { true }, + SMB2_COMMAND_READ | SMB2_COMMAND_WRITE | SMB2_COMMAND_GET_INFO | SMB2_COMMAND_SET_INFO => { + false + } + _ => true, } } -fn smb2_read_response_record_generic(state: &mut SMBState, r: &Smb2Record) -{ +fn smb2_read_response_record_generic(state: &mut SMBState, r: &Smb2Record) { if smb2_create_new_tx(r.command) { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let tx = state.get_generic_tx(2, r.command, &tx_hdr); @@ -113,8 +116,7 @@ fn smb2_read_response_record_generic(state: &mut SMBState, r: &Smb2Record) } } -pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) -{ +pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) { let max_queue_size = unsafe { SMB_CFG_MAX_READ_QUEUE_SIZE }; let max_queue_cnt = unsafe { SMB_CFG_MAX_READ_QUEUE_CNT }; @@ -132,15 +134,14 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { SCLogDebug!("SMBv2/READ: incomplete record, expecting a follow up"); // fall through - } else if r.nt_status != SMB_NTSTATUS_SUCCESS { SCLogDebug!("SMBv2: read response error code received: skip record"); state.set_skip(Direction::ToClient, nbss_remaining); return; } - if (state.max_read_size != 0 && rd.len > state.max_read_size) || - (unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.len }) + if (state.max_read_size != 0 && rd.len > state.max_read_size) + || (unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.len }) { state.set_event(SMBEvent::ReadResponseTooLarge); state.set_skip(Direction::ToClient, nbss_remaining); @@ -155,52 +156,68 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema let (offset, file_guid) = match state.ssn2vecoffset_map.remove(&guid_key) { Some(o) => (o.offset, o.guid), None => { - SCLogDebug!("SMBv2 READ response: reply to unknown request {:?}",rd); + SCLogDebug!("SMBv2 READ response: reply to unknown request {:?}", rd); state.set_skip(Direction::ToClient, nbss_remaining); return; - }, + } }; SCLogDebug!("SMBv2 READ: GUID {:?} offset {}", file_guid, offset); let mut set_event_fileoverlap = false; // look up existing tracker and if we have it update it - let found = match state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToClient) { - Some(tx) => { - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; - if offset < tdf.file_tracker.tracked { - set_event_fileoverlap = true; - } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + rd.len as u64 > max_queue_size.into() { - state.set_event(SMBEvent::ReadQueueSizeExceeded); - state.set_skip(Direction::ToClient, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { - state.set_event(SMBEvent::ReadQueueCntExceeded); - state.set_skip(Direction::ToClient, nbss_remaining); - } else { - filetracker_newchunk(&mut tdf.file_tracker, - &tdf.file_name, rd.data, offset, - rd.len, false, &file_id); + let found = + match state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToClient) { + Some(tx) => { + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + let file_id: u32 = tx.id as u32; + if offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + rd.len as u64 + > max_queue_size.into() + { + state.set_event(SMBEvent::ReadQueueSizeExceeded); + state.set_skip(Direction::ToClient, nbss_remaining); + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { + state.set_event(SMBEvent::ReadQueueCntExceeded); + state.set_skip(Direction::ToClient, nbss_remaining); + } else { + filetracker_newchunk( + &mut tdf.file_tracker, + &tdf.file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); + } } + true } - true - }, - None => { false }, - }; + None => false, + }; SCLogDebug!("existing file tx? {}", found); if !found { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); let (share_name, mut is_pipe) = match state.ssn2tree_map.get(&tree_key) { Some(n) => (n.name.to_vec(), n.is_pipe), - _ => { (Vec::new(), false) }, + _ => (Vec::new(), false), }; let mut is_dcerpc = if is_pipe || share_name.is_empty() { state.get_service_for_guid(&file_guid).1 } else { false }; - SCLogDebug!("SMBv2/READ: share_name {:?} is_pipe {} is_dcerpc {}", - share_name, is_pipe, is_dcerpc); + SCLogDebug!( + "SMBv2/READ: share_name {:?} is_pipe {} is_dcerpc {}", + share_name, + is_pipe, + is_dcerpc + ); if share_name.is_empty() && !is_pipe { SCLogDebug!("SMBv2/READ: no tree connect seen, we don't know if we are a pipe"); @@ -211,7 +228,9 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema let tree = SMBTree::new(b"suricata::dcerpc".to_vec(), true); state.ssn2tree_map.insert(tree_key, tree); if !is_dcerpc { - state.guid2name_map.insert(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); + state + .guid2name_map + .insert(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); } is_pipe = true; is_dcerpc = true; @@ -230,30 +249,40 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema state.set_skip(Direction::ToClient, nbss_remaining); } else { let file_name = match state.guid2name_map.get(&file_guid) { - Some(n) => { n.to_vec() } - None => { b"".to_vec() } + Some(n) => n.to_vec(), + None => b"".to_vec(), }; let tx = state.new_file_tx(&file_guid, &file_name, Direction::ToClient); tx.vercmd.set_smb2_cmd(SMB2_COMMAND_READ); - tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.session_id, r.tree_id, 0); // TODO move into new_file_tx + tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, r.session_id, r.tree_id, 0); // TODO move into new_file_tx if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { tdf.share_name = share_name; - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + rd.len as u64 > max_queue_size.into() { + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + rd.len as u64 + > max_queue_size.into() + { state.set_event(SMBEvent::ReadQueueSizeExceeded); state.set_skip(Direction::ToClient, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { state.set_event(SMBEvent::ReadQueueCntExceeded); state.set_skip(Direction::ToClient, nbss_remaining); } else { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, rd.data, offset, - rd.len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + rd.data, + offset, + rd.len, + false, + &file_id, + ); } } } @@ -262,7 +291,12 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema if set_event_fileoverlap { state.set_event(SMBEvent::FileOverlap); } - state.set_file_left(Direction::ToClient, rd.len, rd.data.len() as u32, file_guid.to_vec()); + state.set_file_left( + Direction::ToClient, + rd.len, + rd.data.len() as u32, + file_guid.to_vec(), + ); } _ => { SCLogDebug!("SMBv2: failed to parse read response"); @@ -271,8 +305,7 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema } } -pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) -{ +pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_remaining: u32) { let max_queue_size = unsafe { SMB_CFG_MAX_WRITE_QUEUE_SIZE }; let max_queue_cnt = unsafe { SMB_CFG_MAX_WRITE_QUEUE_CNT }; @@ -291,8 +324,9 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema state.set_skip(Direction::ToServer, nbss_remaining); return; } - if (state.max_write_size != 0 && wr.wr_len > state.max_write_size) || - (unsafe { SMB_CFG_MAX_WRITE_SIZE != 0 && SMB_CFG_MAX_WRITE_SIZE < wr.wr_len }) { + if (state.max_write_size != 0 && wr.wr_len > state.max_write_size) + || (unsafe { SMB_CFG_MAX_WRITE_SIZE != 0 && SMB_CFG_MAX_WRITE_SIZE < wr.wr_len }) + { state.set_event(SMBEvent::WriteRequestTooLarge); state.set_skip(Direction::ToServer, nbss_remaining); return; @@ -309,46 +343,64 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema }; let mut set_event_fileoverlap = false; - let found = match state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToServer) { - Some(tx) => { - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; - if wr.wr_offset < tdf.file_tracker.tracked { - set_event_fileoverlap = true; - } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 > max_queue_size.into() { - state.set_event(SMBEvent::WriteQueueSizeExceeded); - state.set_skip(Direction::ToServer, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { - state.set_event(SMBEvent::WriteQueueCntExceeded); - state.set_skip(Direction::ToServer, nbss_remaining); - } else { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, wr.data, wr.wr_offset, - wr.wr_len, false, &file_id); + let found = + match state.get_file_tx_by_fuid_with_open_file(&file_guid, Direction::ToServer) { + Some(tx) => { + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + let file_id: u32 = tx.id as u32; + if wr.wr_offset < tdf.file_tracker.tracked { + set_event_fileoverlap = true; + } + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 + > max_queue_size.into() + { + state.set_event(SMBEvent::WriteQueueSizeExceeded); + state.set_skip(Direction::ToServer, nbss_remaining); + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { + state.set_event(SMBEvent::WriteQueueCntExceeded); + state.set_skip(Direction::ToServer, nbss_remaining); + } else { + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + wr.data, + wr.wr_offset, + wr.wr_len, + false, + &file_id, + ); + } } + true } - true - }, - None => { false }, - }; + None => false, + }; if !found { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); let (share_name, mut is_pipe) = match state.ssn2tree_map.get(&tree_key) { - Some(n) => { (n.name.to_vec(), n.is_pipe) }, - _ => { (Vec::new(), false) }, + Some(n) => (n.name.to_vec(), n.is_pipe), + _ => (Vec::new(), false), }; let mut is_dcerpc = if is_pipe || share_name.is_empty() { state.get_service_for_guid(wr.guid).1 } else { false }; - SCLogDebug!("SMBv2/WRITE: share_name {:?} is_pipe {} is_dcerpc {}", - share_name, is_pipe, is_dcerpc); + SCLogDebug!( + "SMBv2/WRITE: share_name {:?} is_pipe {} is_dcerpc {}", + share_name, + is_pipe, + is_dcerpc + ); // if we missed the TREE connect we can't be sure if 'is_dcerpc' is correct if share_name.is_empty() && !is_pipe { - SCLogDebug!("SMBv2/WRITE: no tree connect seen, we don't know if we are a pipe"); + SCLogDebug!( + "SMBv2/WRITE: no tree connect seen, we don't know if we are a pipe" + ); if smb_dcerpc_probe(wr.data) { SCLogDebug!("SMBv2/WRITE: looks like we have dcerpc"); @@ -356,8 +408,9 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema let tree = SMBTree::new(b"suricata::dcerpc".to_vec(), true); state.ssn2tree_map.insert(tree_key, tree); if !is_dcerpc { - state.guid2name_map.insert(file_guid.to_vec(), - b"suricata::dcerpc".to_vec()); + state + .guid2name_map + .insert(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); } is_pipe = true; is_dcerpc = true; @@ -376,24 +429,34 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema } else { let tx = state.new_file_tx(&file_guid, &file_name, Direction::ToServer); tx.vercmd.set_smb2_cmd(SMB2_COMMAND_WRITE); - tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, - r.session_id, r.tree_id, 0); // TODO move into new_file_tx + tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, r.session_id, r.tree_id, 0); // TODO move into new_file_tx if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { - let file_id : u32 = tx.id as u32; + let file_id: u32 = tx.id as u32; if wr.wr_offset < tdf.file_tracker.tracked { set_event_fileoverlap = true; } - if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 > max_queue_size.into() { + if max_queue_size != 0 + && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 + > max_queue_size.into() + { state.set_event(SMBEvent::WriteQueueSizeExceeded); state.set_skip(Direction::ToServer, nbss_remaining); - } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize { + } else if max_queue_cnt != 0 + && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize + { state.set_event(SMBEvent::WriteQueueCntExceeded); state.set_skip(Direction::ToServer, nbss_remaining); } else { - filetracker_newchunk(&mut tdf.file_tracker, - &file_name, wr.data, wr.wr_offset, - wr.wr_len, false, &file_id); + filetracker_newchunk( + &mut tdf.file_tracker, + &file_name, + wr.data, + wr.wr_offset, + wr.wr_len, + false, + &file_id, + ); } } } @@ -402,20 +465,28 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema if set_event_fileoverlap { state.set_event(SMBEvent::FileOverlap); } - state.set_file_left(Direction::ToServer, wr.wr_len, wr.data.len() as u32, file_guid.to_vec()); - }, + state.set_file_left( + Direction::ToServer, + wr.wr_len, + wr.data.len() as u32, + file_guid.to_vec(), + ); + } _ => { state.set_event(SMBEvent::MalformedData); - }, + } } } -pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) -{ - SCLogDebug!("SMBv2 request record, command {} tree {} session {}", - &smb2_command_string(r.command), r.tree_id, r.session_id); +pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) { + SCLogDebug!( + "SMBv2 request record, command {} tree {} session {}", + &smb2_command_string(r.command), + r.tree_id, + r.session_id + ); - let mut events : Vec = Vec::new(); + let mut events: Vec = Vec::new(); let have_tx = match r.command { SMB2_COMMAND_SET_INFO => { @@ -428,10 +499,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) Smb2SetInfoRequestData::RENAME(ref ren) => { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let mut newname = ren.name.to_vec(); - newname.retain(|&i|i != 0x00); + newname.retain(|&i| i != 0x00); let oldname = match state.guid2name_map.get(rd.guid) { - Some(n) => { n.to_vec() }, - None => { b"".to_vec() }, + Some(n) => n.to_vec(), + None => b"".to_vec(), }; let tx = state.new_rename_tx(rd.guid.to_vec(), oldname, newname); tx.hdr = tx_hdr; @@ -442,22 +513,29 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) Smb2SetInfoRequestData::DISPOSITION(ref dis) => { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let fname = match state.guid2name_map.get(rd.guid) { - Some(n) => { n.to_vec() }, + Some(n) => n.to_vec(), None => { // try to find latest created file in case of chained commands - let mut guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); + let mut guid_key = + SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); if guid_key.msg_id == 0 { b"".to_vec() } else { guid_key.msg_id -= 1; match state.ssn2vec_map.get(&guid_key) { - Some(n) => { n.to_vec() }, - None => { b"".to_vec()}, + Some(n) => n.to_vec(), + None => b"".to_vec(), } } - }, + } }; - let tx = state.new_setfileinfo_tx(fname, rd.guid.to_vec(), rd.class as u16, rd.infolvl as u16, dis.delete); + let tx = state.new_setfileinfo_tx( + fname, + rd.guid.to_vec(), + rd.class as u16, + rd.infolvl as u16, + dis.delete, + ); tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_SET_INFO); @@ -465,145 +543,146 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) } _ => false, } - }, + } Err(Err::Incomplete(_n)) => { SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _n); events.push(SMBEvent::MalformedData); false - }, - Err(Err::Error(_e)) | - Err(Err::Failure(_e)) => { + } + Err(Err::Error(_e)) | Err(Err::Failure(_e)) => { SCLogDebug!("SMB2_COMMAND_SET_INFO: {:?}", _e); events.push(SMBEvent::MalformedData); false - }, + } }; have_si_tx - }, + } SMB2_COMMAND_IOCTL => { smb2_ioctl_request_record(state, r); true - }, + } SMB2_COMMAND_TREE_DISCONNECT => { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); state.ssn2tree_map.remove(&tree_key); false } - SMB2_COMMAND_NEGOTIATE_PROTOCOL => { - match parse_smb2_request_negotiate_protocol(r.data) { - Ok((_, rd)) => { - let mut dialects : Vec> = Vec::new(); - for d in rd.dialects_vec { - SCLogDebug!("dialect {:x} => {}", d, &smb2_dialect_string(d)); - let dvec = smb2_dialect_string(d).as_bytes().to_vec(); - dialects.push(dvec); - } + SMB2_COMMAND_NEGOTIATE_PROTOCOL => match parse_smb2_request_negotiate_protocol(r.data) { + Ok((_, rd)) => { + let mut dialects: Vec> = Vec::new(); + for d in rd.dialects_vec { + SCLogDebug!("dialect {:x} => {}", d, &smb2_dialect_string(d)); + let dvec = smb2_dialect_string(d).as_bytes().to_vec(); + dialects.push(dvec); + } - let found = match state.get_negotiate_tx(2) { - Some(_) => { - SCLogDebug!("WEIRD, should not have NEGOTIATE tx!"); - true - }, - None => { false }, - }; - if !found { - let tx = state.new_negotiate_tx(2); - if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { - tdn.dialects2 = dialects; - tdn.client_guid = Some(rd.client_guid.to_vec()); - } - tx.request_done = true; + let found = match state.get_negotiate_tx(2) { + Some(_) => { + SCLogDebug!("WEIRD, should not have NEGOTIATE tx!"); + true } - true - }, - _ => { - events.push(SMBEvent::MalformedData); - false - }, + None => false, + }; + if !found { + let tx = state.new_negotiate_tx(2); + if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { + tdn.dialects2 = dialects; + tdn.client_guid = Some(rd.client_guid.to_vec()); + } + tx.request_done = true; + } + true + } + _ => { + events.push(SMBEvent::MalformedData); + false } }, SMB2_COMMAND_SESSION_SETUP => { smb2_session_setup_request(state, r); true - }, - SMB2_COMMAND_TREE_CONNECT => { - match parse_smb2_request_tree_connect(r.data) { - Ok((_, tr)) => { - let name_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_TREE); - let mut name_val = tr.share_name.to_vec(); - name_val.retain(|&i|i != 0x00); - if name_val.len() > 1 { - name_val = name_val[1..].to_vec(); - } - - let tx = state.new_treeconnect_tx(name_key, name_val); - tx.request_done = true; - tx.vercmd.set_smb2_cmd(SMB2_COMMAND_TREE_CONNECT); - true + } + SMB2_COMMAND_TREE_CONNECT => match parse_smb2_request_tree_connect(r.data) { + Ok((_, tr)) => { + let name_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_TREE); + let mut name_val = tr.share_name.to_vec(); + name_val.retain(|&i| i != 0x00); + if name_val.len() > 1 { + name_val = name_val[1..].to_vec(); } - _ => { - events.push(SMBEvent::MalformedData); - false - }, + + let tx = state.new_treeconnect_tx(name_key, name_val); + tx.request_done = true; + tx.vercmd.set_smb2_cmd(SMB2_COMMAND_TREE_CONNECT); + true + } + _ => { + events.push(SMBEvent::MalformedData); + false } }, SMB2_COMMAND_READ => { match parse_smb2_request_read(r.data) { Ok((_, rd)) => { - if (state.max_read_size != 0 && rd.rd_len > state.max_read_size) || - (unsafe { SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.rd_len }) { + if (state.max_read_size != 0 && rd.rd_len > state.max_read_size) + || (unsafe { + SMB_CFG_MAX_READ_SIZE != 0 && SMB_CFG_MAX_READ_SIZE < rd.rd_len + }) + { events.push(SMBEvent::ReadRequestTooLarge); } else { - SCLogDebug!("SMBv2 READ: GUID {:?} requesting {} bytes at offset {}", - rd.guid, rd.rd_len, rd.rd_offset); + SCLogDebug!( + "SMBv2 READ: GUID {:?} requesting {} bytes at offset {}", + rd.guid, + rd.rd_len, + rd.rd_offset + ); // store read guid,offset in map let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_OFFSET); let guidoff = SMBFileGUIDOffset::new(rd.guid.to_vec(), rd.rd_offset); state.ssn2vecoffset_map.insert(guid_key, guidoff); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } false - }, - SMB2_COMMAND_CREATE => { - match parse_smb2_request_create(r.data) { - Ok((_, cr)) => { - let del = cr.create_options & 0x0000_1000 != 0; - let dir = cr.create_options & 0x0000_0001 != 0; - - SCLogDebug!("create_options {:08x}", cr.create_options); - - let name_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); - state.ssn2vec_map.insert(name_key, cr.data.to_vec()); - - let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_create_tx(cr.data, - cr.disposition, del, dir, tx_hdr); - tx.vercmd.set_smb2_cmd(r.command); - SCLogDebug!("TS CREATE TX {} created", tx.id); - true - }, - _ => { - events.push(SMBEvent::MalformedData); - false - }, + } + SMB2_COMMAND_CREATE => match parse_smb2_request_create(r.data) { + Ok((_, cr)) => { + let del = cr.create_options & 0x0000_1000 != 0; + let dir = cr.create_options & 0x0000_0001 != 0; + + SCLogDebug!("create_options {:08x}", cr.create_options); + + let name_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); + state.ssn2vec_map.insert(name_key, cr.data.to_vec()); + + let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); + let tx = state.new_create_tx(cr.data, cr.disposition, del, dir, tx_hdr); + tx.vercmd.set_smb2_cmd(r.command); + SCLogDebug!("TS CREATE TX {} created", tx.id); + true + } + _ => { + events.push(SMBEvent::MalformedData); + false } }, SMB2_COMMAND_WRITE => { smb2_write_request_record(state, r, 0); true // write handling creates both file tx and generic tx - }, + } SMB2_COMMAND_CLOSE => { match parse_smb2_request_close(r.data) { Ok((_, cd)) => { let found_ts = match state.get_file_tx_by_fuid(cd.guid, Direction::ToServer) { Some(tx) => { if !tx.request_done { - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = + tx.type_data + { filetracker_close(&mut tdf.file_tracker); } } @@ -611,13 +690,15 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) tx.response_done = true; tx.set_status(SMB_NTSTATUS_SUCCESS, false); true - }, - None => { false }, + } + None => false, }; let found_tc = match state.get_file_tx_by_fuid(cd.guid, Direction::ToClient) { Some(tx) => { if !tx.request_done { - if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { + if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = + tx.type_data + { filetracker_close(&mut tdf.file_tracker); } } @@ -625,82 +706,91 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) tx.response_done = true; tx.set_status(SMB_NTSTATUS_SUCCESS, false); true - }, - None => { false }, + } + None => false, }; if !found_ts && !found_tc { SCLogDebug!("SMBv2: CLOSE(TS): no TX at GUID {:?}", cd.guid); } - }, + } _ => { events.push(SMBEvent::MalformedData); - }, + } } false - }, - _ => { - false - }, + } + _ => false, }; /* if we don't have a tx, create it here (maybe) */ if !have_tx && smb2_create_new_tx(r.command) { let tx_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); let tx = state.new_generic_tx(2, r.command, tx_key); - SCLogDebug!("TS TX {} command {} created with session_id {} tree_id {} message_id {}", - tx.id, r.command, r.session_id, r.tree_id, r.message_id); + SCLogDebug!( + "TS TX {} command {} created with session_id {} tree_id {} message_id {}", + tx.id, + r.command, + r.session_id, + r.tree_id, + r.message_id + ); tx.set_events(events); } } -pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) -{ - SCLogDebug!("SMBv2 response record, command {} status {} tree {} session {} message {}", - &smb2_command_string(r.command), r.nt_status, - r.tree_id, r.session_id, r.message_id); +pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) { + SCLogDebug!( + "SMBv2 response record, command {} status {} tree {} session {} message {}", + &smb2_command_string(r.command), + r.nt_status, + r.tree_id, + r.session_id, + r.message_id + ); - let mut events : Vec = Vec::new(); + let mut events: Vec = Vec::new(); let have_tx = match r.command { SMB2_COMMAND_IOCTL => { smb2_ioctl_response_record(state, r); true - }, + } SMB2_COMMAND_SESSION_SETUP => { smb2_session_setup_response(state, r); true - }, + } SMB2_COMMAND_WRITE => { if r.nt_status == SMB_NTSTATUS_SUCCESS { - match parse_smb2_response_write(r.data) - { + match parse_smb2_response_write(r.data) { Ok((_, _wr)) => { SCLogDebug!("SMBv2: Write response => {:?}", _wr); /* search key-guid map */ - let guid_key = SMBCommonHdr::new(SMBHDR_TYPE_GUID, - r.session_id, r.tree_id, r.message_id); + let guid_key = SMBCommonHdr::new( + SMBHDR_TYPE_GUID, + r.session_id, + r.tree_id, + r.message_id, + ); let _guid_vec = match state.ssn2vec_map.remove(&guid_key) { Some(p) => p, None => { SCLogDebug!("SMBv2 response: GUID NOT FOUND"); Vec::new() - }, + } }; SCLogDebug!("SMBv2 write response for GUID {:?}", _guid_vec); } _ => { events.push(SMBEvent::MalformedData); - }, + } } } false // the request may have created a generic tx, so handle that here - }, + } SMB2_COMMAND_READ => { - if r.nt_status == SMB_NTSTATUS_SUCCESS || - r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { + if r.nt_status == SMB_NTSTATUS_SUCCESS || r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { smb2_read_response_record(state, r, 0); false - } else if r.nt_status == SMB_NTSTATUS_END_OF_FILE { SCLogDebug!("SMBv2: read response => EOF"); @@ -710,7 +800,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) _ => { SCLogDebug!("SMBv2 READ response: reply to unknown request"); Vec::new() - }, + } }; let found = match state.get_file_tx_by_fuid(&file_guid, Direction::ToClient) { Some(tx) => { @@ -722,8 +812,8 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) tx.set_status(r.nt_status, false); tx.request_done = true; false - }, - None => { false }, + } + None => false, }; if !found { SCLogDebug!("SMBv2 READ: no TX at GUID {:?}", file_guid); @@ -733,7 +823,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) SCLogDebug!("SMBv2 READ: status {}", r.nt_status); false } - }, + } SMB2_COMMAND_CREATE => { if r.nt_status == SMB_NTSTATUS_SUCCESS { match parse_smb2_response_create(r.data) { @@ -742,7 +832,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME); if let Some(mut p) = state.ssn2vec_map.remove(&guid_key) { - p.retain(|&i|i != 0x00); + p.retain(|&i| i != 0x00); state.guid2name_map.insert(cr.guid.to_vec(), p); } else { SCLogDebug!("SMBv2 response: GUID NOT FOUND"); @@ -750,12 +840,17 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); if let Some(tx) = state.get_generic_tx(2, r.command, &tx_hdr) { - SCLogDebug!("tx {} with {}/{} marked as done", - tx.id, r.command, &smb2_command_string(r.command)); + SCLogDebug!( + "tx {} with {}/{} marked as done", + tx.id, + r.command, + &smb2_command_string(r.command) + ); tx.set_status(r.nt_status, false); tx.response_done = true; - if let Some(SMBTransactionTypeData::CREATE(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::CREATE(ref mut tdn)) = tx.type_data + { tdn.create_ts = cr.create_ts.as_unix(); tdn.last_access_ts = cr.last_access_ts.as_unix(); tdn.last_write_ts = cr.last_write_ts.as_unix(); @@ -767,13 +862,13 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) } _ => { events.push(SMBEvent::MalformedData); - }, + } } true } else { false } - }, + } SMB2_COMMAND_TREE_DISCONNECT => { // normally removed when processing request, // but in case we missed that try again here @@ -790,7 +885,9 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) let is_pipe = tr.share_type == 2; let found = match state.get_treeconnect_tx(name_key) { Some(tx) => { - if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = + tx.type_data + { tdn.share_type = tr.share_type; tdn.is_pipe = is_pipe; tdn.tree_id = r.tree_id; @@ -801,8 +898,8 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) tx.response_done = true; tx.set_status(r.nt_status, false); true - }, - None => { false }, + } + None => false, }; if found { let tree = SMBTree::new(share_name.to_vec(), is_pipe); @@ -814,7 +911,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) _ => { events.push(SMBEvent::MalformedData); false - }, + } } } else { let name_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_TREE); @@ -823,12 +920,12 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) tx.response_done = true; tx.set_status(r.nt_status, false); true - }, - None => { false }, + } + None => false, }; found } - }, + } SMB2_COMMAND_NEGOTIATE_PROTOCOL => { let res = if r.nt_status == SMB_NTSTATUS_SUCCESS { parse_smb2_response_negotiate_protocol(r.data) @@ -854,60 +951,73 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) let found2 = match state.get_negotiate_tx(2) { Some(tx) => { - if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { + if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = + tx.type_data + { tdn.server_guid = rd.server_guid.to_vec(); } tx.set_status(r.nt_status, false); tx.response_done = true; true - }, - None => { false }, + } + None => false, }; // SMB2 response to SMB1 request? - let found1 = !found2 && match state.get_negotiate_tx(1) { - Some(tx) => { - if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { - tdn.server_guid = rd.server_guid.to_vec(); + let found1 = !found2 + && match state.get_negotiate_tx(1) { + Some(tx) => { + if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = + tx.type_data + { + tdn.server_guid = rd.server_guid.to_vec(); + } + tx.set_status(r.nt_status, false); + tx.response_done = true; + true } - tx.set_status(r.nt_status, false); - tx.response_done = true; - true - }, - None => { false }, - }; + None => false, + }; found1 || found2 - }, + } _ => { events.push(SMBEvent::MalformedData); false } } - }, + } _ => { SCLogDebug!("default case: no TX"); false - }, + } }; if !have_tx { let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); - SCLogDebug!("looking for TX {} with session_id {} tree_id {} message_id {}", - &smb2_command_string(r.command), - r.session_id, r.tree_id, r.message_id); + SCLogDebug!( + "looking for TX {} with session_id {} tree_id {} message_id {}", + &smb2_command_string(r.command), + r.session_id, + r.tree_id, + r.message_id + ); let _found = match state.get_generic_tx(2, r.command, &tx_hdr) { Some(tx) => { - SCLogDebug!("tx {} with {}/{} marked as done", - tx.id, r.command, &smb2_command_string(r.command)); + SCLogDebug!( + "tx {} with {}/{} marked as done", + tx.id, + r.command, + &smb2_command_string(r.command) + ); if r.nt_status != SMB_NTSTATUS_PENDING { tx.response_done = true; } tx.set_status(r.nt_status, false); tx.set_events(events); true - }, + } _ => { SCLogDebug!("no tx found for {:?}", r); false - }, + } }; } } diff --git a/rust/src/smb/smb2_ioctl.rs b/rust/src/smb/smb2_ioctl.rs index 73687aa5568f..4677f680ea9a 100644 --- a/rust/src/smb/smb2_ioctl.rs +++ b/rust/src/smb/smb2_ioctl.rs @@ -15,13 +15,13 @@ * 02110-1301, USA. */ -use crate::smb::smb::*; -use crate::smb::smb2::*; -use crate::smb::smb2_records::*; use crate::smb::dcerpc::*; use crate::smb::events::*; #[cfg(feature = "debug")] use crate::smb::funcs::*; +use crate::smb::smb::*; +use crate::smb::smb2::*; +use crate::smb::smb2_records::*; use crate::smb::smb_status::*; #[derive(Debug)] @@ -31,25 +31,26 @@ pub struct SMBTransactionIoctl { impl SMBTransactionIoctl { pub fn new(func: u32) -> Self { - return Self { - func, - }; + return Self { func }; } } impl SMBState { - pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) - -> &mut SMBTransaction - { + pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) -> &mut SMBTransaction { let mut tx = self.new_tx(); tx.hdr = hdr; - tx.type_data = Some(SMBTransactionTypeData::IOCTL( - SMBTransactionIoctl::new(func))); + tx.type_data = Some(SMBTransactionTypeData::IOCTL(SMBTransactionIoctl::new( + func, + ))); tx.request_done = true; tx.response_done = self.tc_trunc; // no response expected if tc is truncated - SCLogDebug!("SMB: TX IOCTL created: ID {} FUNC {:08x}: {}", - tx.id, func, &fsctl_func_to_string(func)); + SCLogDebug!( + "SMB: TX IOCTL created: ID {} FUNC {:08x}: {}", + tx.id, + func, + &fsctl_func_to_string(func) + ); self.transactions.push_back(tx); let tx_ref = self.transactions.back_mut(); return tx_ref.unwrap(); @@ -57,8 +58,7 @@ impl SMBState { } // IOCTL responses ASYNC don't set the tree id -pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) { let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); match parse_smb2_request_ioctl(r.data) { Ok((_, rd)) => { @@ -73,21 +73,24 @@ pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) let vercmd = SMBVerCmdStat::new2(SMB2_COMMAND_IOCTL); smb_write_dcerpc_record(state, vercmd, hdr, rd.data); } else { - SCLogDebug!("IOCTL {:08x} {}", rd.function, &fsctl_func_to_string(rd.function)); + SCLogDebug!( + "IOCTL {:08x} {}", + rd.function, + &fsctl_func_to_string(rd.function) + ); let tx = state.new_ioctl_tx(hdr, rd.function); tx.vercmd.set_smb2_cmd(SMB2_COMMAND_IOCTL); } - }, + } _ => { let tx = state.new_generic_tx(2, r.command, hdr); tx.set_event(SMBEvent::MalformedData); - }, + } }; } // IOCTL responses ASYNC don't set the tree id -pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) { let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); match parse_smb2_response_ioctl(r.data) { Ok((_, rd)) => { @@ -102,9 +105,12 @@ pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) SCLogDebug!("IOCTL response data is_pipe. Calling smb_read_dcerpc_record"); let vercmd = SMBVerCmdStat::new2_with_ntstatus(SMB2_COMMAND_IOCTL, r.nt_status); SCLogDebug!("TODO passing empty GUID"); - smb_read_dcerpc_record(state, vercmd, hdr, &[],rd.data); + smb_read_dcerpc_record(state, vercmd, hdr, &[], rd.data); } else { - SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr); + SCLogDebug!( + "SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", + hdr + ); if let Some(tx) = state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) { tx.set_status(r.nt_status, false); if r.nt_status != SMB_NTSTATUS_PENDING { @@ -112,22 +118,25 @@ pub fn smb2_ioctl_response_record(state: &mut SMBState, r: &Smb2Record) } } } - }, + } _ => { - SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr); + SCLogDebug!( + "SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", + hdr + ); if let Some(tx) = state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) { SCLogDebug!("updated status of tx {}", tx.id); tx.set_status(r.nt_status, false); if r.nt_status != SMB_NTSTATUS_PENDING { tx.response_done = true; } - + // parsing failed for 'SUCCESS' record, set event if r.nt_status == SMB_NTSTATUS_SUCCESS { SCLogDebug!("parse fail {:?}", r); tx.set_event(SMBEvent::MalformedData); } } - }, + } }; } diff --git a/rust/src/smb/smb2_session.rs b/rust/src/smb/smb2_session.rs index 93cc99cdd4c6..ef6aba5bfb97 100644 --- a/rust/src/smb/smb2_session.rs +++ b/rust/src/smb/smb2_session.rs @@ -15,13 +15,12 @@ * 02110-1301, USA. */ -use crate::smb::smb2_records::*; -use crate::smb::smb::*; -use crate::smb::events::*; use crate::smb::auth::*; +use crate::smb::events::*; +use crate::smb::smb::*; +use crate::smb::smb2_records::*; -pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record) { SCLogDebug!("SMB2_COMMAND_SESSION_SETUP: r.data.len() {}", r.data.len()); #[allow(clippy::single_match)] match parse_smb2_request_session_setup(r.data) { @@ -41,45 +40,40 @@ pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record) } } } - }, - _ => { -// events.push(SMBEvent::MalformedData); - }, + } + _ => { + // events.push(SMBEvent::MalformedData); + } } } -fn smb2_session_setup_update_tx(tx: &mut SMBTransaction, r: &Smb2Record) -{ +fn smb2_session_setup_update_tx(tx: &mut SMBTransaction, r: &Smb2Record) { tx.hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); // to overwrite ssn_id 0 tx.set_status(r.nt_status, false); tx.response_done = true; } -pub fn smb2_session_setup_response(state: &mut SMBState, r: &Smb2Record) -{ +pub fn smb2_session_setup_response(state: &mut SMBState, r: &Smb2Record) { // try exact match with session id already set (e.g. NTLMSSP AUTH phase) - let found = r.session_id != 0 && match state.get_sessionsetup_tx( - SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER)) - { - Some(tx) => { - smb2_session_setup_update_tx(tx, r); - SCLogDebug!("smb2_session_setup_response: tx {:?}", tx); - true - }, - None => { false }, - }; + let found = r.session_id != 0 + && match state.get_sessionsetup_tx(SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER)) { + Some(tx) => { + smb2_session_setup_update_tx(tx, r); + SCLogDebug!("smb2_session_setup_response: tx {:?}", tx); + true + } + None => false, + }; // otherwise try match with ssn id 0 (e.g. NTLMSSP_NEGOTIATE) if !found { - match state.get_sessionsetup_tx( - SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.message_id)) - { + match state.get_sessionsetup_tx(SMBCommonHdr::new(SMBHDR_TYPE_HEADER, 0, 0, r.message_id)) { Some(tx) => { smb2_session_setup_update_tx(tx, r); SCLogDebug!("smb2_session_setup_response: tx {:?}", tx); - }, + } None => { SCLogDebug!("smb2_session_setup_response: tx not found for {:?}", r); - }, + } } } } diff --git a/rust/src/smb/smb3.rs b/rust/src/smb/smb3.rs index 07a705995502..c83d6cb2d9d4 100644 --- a/rust/src/smb/smb3.rs +++ b/rust/src/smb/smb3.rs @@ -19,11 +19,11 @@ use nom7::bytes::streaming::{tag, take}; use nom7::number::streaming::{le_u16, le_u32, le_u64}; use nom7::IResult; -#[derive(Debug,PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Smb3TransformRecord<'a> { pub session_id: u64, pub enc_algo: u16, - pub enc_data: &'a[u8], + pub enc_data: &'a [u8], } pub fn parse_smb3_transform_record(i: &[u8]) -> IResult<&[u8], Smb3TransformRecord> { @@ -46,8 +46,8 @@ pub fn parse_smb3_transform_record(i: &[u8]) -> IResult<&[u8], Smb3TransformReco #[cfg(test)] mod tests { use super::*; - #[test] - fn test_parse_smb3_transform_record() { + #[test] + fn test_parse_smb3_transform_record() { // https://raw.githubusercontent.com/bro/bro/master/testing/btest/Traces/smb/smb3.pcap let data = hex::decode("fd534d42188d39cea4b1e3f640aff5d0b1569852c0bd665516dbb4b499507f000000000069000000000001003d00009400480000d9f8a66572b40c621bea6f5922a412a8eb2e3cc2af9ce26a277e75898cb523b9eb49ef660a6a1a09368fadd6a58e893e08eb3b7c068bdb74b6cd38e9ed1a2559cefb2ebc2172fd86c08a1a636eb851f20bf53a242f4cfaf7ab44e77291073ad492d6297c3d3a67757c").unwrap(); let result = parse_smb3_transform_record(&data).unwrap(); diff --git a/rust/src/smb/smb_records.rs b/rust/src/smb/smb_records.rs index cc5b3cb7a210..f11b3ac8c78f 100644 --- a/rust/src/smb/smb_records.rs +++ b/rust/src/smb/smb_records.rs @@ -22,22 +22,21 @@ use nom7::{Err, IResult}; /// parse a UTF16 string that is null terminated. Normally by 2 null /// bytes, but at the end of the data it can also be a single null. /// Skip every second byte. -pub fn smb_get_unicode_string(blob: &[u8]) -> IResult<&[u8], Vec, SmbError> -{ +pub fn smb_get_unicode_string(blob: &[u8]) -> IResult<&[u8], Vec, SmbError> { SCLogDebug!("get_unicode_string: blob {} {:?}", blob.len(), blob); - let mut name : Vec = Vec::new(); + let mut name: Vec = Vec::new(); let mut c = blob; while !c.is_empty() { if c.len() == 1 && c[0] == 0 { let rem = &c[1..]; SCLogDebug!("get_unicode_string: name {:?}", name); - return Ok((rem, name)) + return Ok((rem, name)); } else if c.len() == 1 { break; } else if c[0] == 0 && c[1] == 0 { let rem = &c[2..]; SCLogDebug!("get_unicode_string: name {:?}", name); - return Ok((rem, name)) + return Ok((rem, name)); } name.push(c[0]); c = &c[2..]; @@ -50,4 +49,3 @@ pub fn smb_get_ascii_string(i: &[u8]) -> IResult<&[u8], Vec, SmbError> { let (i, s) = take_until_and_consume(b"\x00")(i)?; Ok((i, s.to_vec())) } - diff --git a/rust/src/smb/smb_status.rs b/rust/src/smb/smb_status.rs index 10b06a56cf60..61eaf742ac4f 100644 --- a/rust/src/smb/smb_status.rs +++ b/rust/src/smb/smb_status.rs @@ -15,3595 +15,4139 @@ * 02110-1301, USA. */ -pub const SMB_NTSTATUS_SUCCESS: u32 = 0x00000000; -pub const SMB_NTSTATUS_WAIT_1: u32 = 0x00000001; -pub const SMB_NTSTATUS_WAIT_2: u32 = 0x00000002; -pub const SMB_NTSTATUS_WAIT_3: u32 = 0x00000003; -pub const SMB_NTSTATUS_WAIT_63: u32 = 0x0000003f; -pub const SMB_NTSTATUS_ABANDONED: u32 = 0x00000080; -pub const SMB_NTSTATUS_ABANDONED_WAIT_63: u32 = 0x000000bf; -pub const SMB_NTSTATUS_USER_APC: u32 = 0x000000c0; -pub const SMB_NTSTATUS_ALERTED: u32 = 0x00000101; -pub const SMB_NTSTATUS_TIMEOUT: u32 = 0x00000102; -pub const SMB_NTSTATUS_PENDING: u32 = 0x00000103; -pub const SMB_NTSTATUS_REPARSE: u32 = 0x00000104; -pub const SMB_NTSTATUS_MORE_ENTRIES: u32 = 0x00000105; -pub const SMB_NTSTATUS_NOT_ALL_ASSIGNED: u32 = 0x00000106; -pub const SMB_NTSTATUS_SOME_NOT_MAPPED: u32 = 0x00000107; -pub const SMB_NTSTATUS_OPLOCK_BREAK_IN_PROGRESS: u32 = 0x00000108; -pub const SMB_NTSTATUS_VOLUME_MOUNTED: u32 = 0x00000109; -pub const SMB_NTSTATUS_RXACT_COMMITTED: u32 = 0x0000010a; -pub const SMB_NTSTATUS_NOTIFY_CLEANUP: u32 = 0x0000010b; -pub const SMB_NTSTATUS_NOTIFY_ENUM_DIR: u32 = 0x0000010c; -pub const SMB_NTSTATUS_NO_QUOTAS_FOR_ACCOUNT: u32 = 0x0000010d; -pub const SMB_NTSTATUS_PRIMARY_TRANSPORT_CONNECT_FAILED: u32 = 0x0000010e; -pub const SMB_NTSTATUS_PAGE_FAULT_TRANSITION: u32 = 0x00000110; -pub const SMB_NTSTATUS_PAGE_FAULT_DEMAND_ZERO: u32 = 0x00000111; -pub const SMB_NTSTATUS_PAGE_FAULT_COPY_ON_WRITE: u32 = 0x00000112; -pub const SMB_NTSTATUS_PAGE_FAULT_GUARD_PAGE: u32 = 0x00000113; -pub const SMB_NTSTATUS_PAGE_FAULT_PAGING_FILE: u32 = 0x00000114; -pub const SMB_NTSTATUS_CACHE_PAGE_LOCKED: u32 = 0x00000115; -pub const SMB_NTSTATUS_CRASH_DUMP: u32 = 0x00000116; -pub const SMB_NTSTATUS_BUFFER_ALL_ZEROS: u32 = 0x00000117; -pub const SMB_NTSTATUS_REPARSE_OBJECT: u32 = 0x00000118; -pub const SMB_NTSTATUS_RESOURCE_REQUIREMENTS_CHANGED: u32 = 0x00000119; -pub const SMB_NTSTATUS_TRANSLATION_COMPLETE: u32 = 0x00000120; -pub const SMB_NTSTATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY: u32 = 0x00000121; -pub const SMB_NTSTATUS_NOTHING_TO_TERMINATE: u32 = 0x00000122; -pub const SMB_NTSTATUS_PROCESS_NOT_IN_JOB: u32 = 0x00000123; -pub const SMB_NTSTATUS_PROCESS_IN_JOB: u32 = 0x00000124; -pub const SMB_NTSTATUS_VOLSNAP_HIBERNATE_READY: u32 = 0x00000125; -pub const SMB_NTSTATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY: u32 = 0x00000126; -pub const SMB_NTSTATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: u32 = 0x00000127; -pub const SMB_NTSTATUS_INTERRUPT_STILL_CONNECTED: u32 = 0x00000128; -pub const SMB_NTSTATUS_PROCESS_CLONED: u32 = 0x00000129; -pub const SMB_NTSTATUS_FILE_LOCKED_WITH_ONLY_READERS: u32 = 0x0000012a; -pub const SMB_NTSTATUS_FILE_LOCKED_WITH_WRITERS: u32 = 0x0000012b; -pub const SMB_NTSTATUS_RESOURCEMANAGER_READ_ONLY: u32 = 0x00000202; -pub const SMB_NTSTATUS_WAIT_FOR_OPLOCK: u32 = 0x00000367; -pub const SMB_NTDBG_EXCEPTION_HANDLED: u32 = 0x00010001; -pub const SMB_NTDBG_CONTINUE: u32 = 0x00010002; -pub const SMB_NTSTATUS_FLT_IO_COMPLETE: u32 = 0x001c0001; -pub const SMB_NTSTATUS_FILE_NOT_AVAILABLE: u32 = 0xc0000467; -pub const SMB_NTSTATUS_SHARE_UNAVAILABLE: u32 = 0xc0000480; -pub const SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_AFFINITY: u32 = 0xc0000721; -pub const SMB_NTSTATUS_OBJECT_NAME_EXISTS: u32 = 0x40000000; -pub const SMB_NTSTATUS_THREAD_WAS_SUSPENDED: u32 = 0x40000001; -pub const SMB_NTSTATUS_WORKING_SET_LIMIT_RANGE: u32 = 0x40000002; -pub const SMB_NTSTATUS_IMAGE_NOT_AT_BASE: u32 = 0x40000003; -pub const SMB_NTSTATUS_RXACT_STATE_CREATED: u32 = 0x40000004; -pub const SMB_NTSTATUS_SEGMENT_NOTIFICATION: u32 = 0x40000005; -pub const SMB_NTSTATUS_LOCAL_USER_SESSION_KEY: u32 = 0x40000006; -pub const SMB_NTSTATUS_BAD_CURRENT_DIRECTORY: u32 = 0x40000007; -pub const SMB_NTSTATUS_SERIAL_MORE_WRITES: u32 = 0x40000008; -pub const SMB_NTSTATUS_REGISTRY_RECOVERED: u32 = 0x40000009; -pub const SMB_NTSTATUS_FT_READ_RECOVERY_FROM_BACKUP: u32 = 0x4000000a; -pub const SMB_NTSTATUS_FT_WRITE_RECOVERY: u32 = 0x4000000b; -pub const SMB_NTSTATUS_SERIAL_COUNTER_TIMEOUT: u32 = 0x4000000c; -pub const SMB_NTSTATUS_NULL_LM_PASSWORD: u32 = 0x4000000d; -pub const SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH: u32 = 0x4000000e; -pub const SMB_NTSTATUS_RECEIVE_PARTIAL: u32 = 0x4000000f; -pub const SMB_NTSTATUS_RECEIVE_EXPEDITED: u32 = 0x40000010; -pub const SMB_NTSTATUS_RECEIVE_PARTIAL_EXPEDITED: u32 = 0x40000011; -pub const SMB_NTSTATUS_EVENT_DONE: u32 = 0x40000012; -pub const SMB_NTSTATUS_EVENT_PENDING: u32 = 0x40000013; -pub const SMB_NTSTATUS_CHECKING_FILE_SYSTEM: u32 = 0x40000014; -pub const SMB_NTSTATUS_FATAL_APP_EXIT: u32 = 0x40000015; -pub const SMB_NTSTATUS_PREDEFINED_HANDLE: u32 = 0x40000016; -pub const SMB_NTSTATUS_WAS_UNLOCKED: u32 = 0x40000017; -pub const SMB_NTSTATUS_SERVICE_NOTIFICATION: u32 = 0x40000018; -pub const SMB_NTSTATUS_WAS_LOCKED: u32 = 0x40000019; -pub const SMB_NTSTATUS_LOG_HARD_ERROR: u32 = 0x4000001a; -pub const SMB_NTSTATUS_ALREADY_WIN32: u32 = 0x4000001b; -pub const SMB_NTSTATUS_WX86_UNSIMULATE: u32 = 0x4000001c; -pub const SMB_NTSTATUS_WX86_CONTINUE: u32 = 0x4000001d; -pub const SMB_NTSTATUS_WX86_SINGLE_STEP: u32 = 0x4000001e; -pub const SMB_NTSTATUS_WX86_BREAKPOINT: u32 = 0x4000001f; -pub const SMB_NTSTATUS_WX86_EXCEPTION_CONTINUE: u32 = 0x40000020; -pub const SMB_NTSTATUS_WX86_EXCEPTION_LASTCHANCE: u32 = 0x40000021; -pub const SMB_NTSTATUS_WX86_EXCEPTION_CHAIN: u32 = 0x40000022; -pub const SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: u32 = 0x40000023; -pub const SMB_NTSTATUS_NO_YIELD_PERFORMED: u32 = 0x40000024; -pub const SMB_NTSTATUS_TIMER_RESUME_IGNORED: u32 = 0x40000025; -pub const SMB_NTSTATUS_ARBITRATION_UNHANDLED: u32 = 0x40000026; -pub const SMB_NTSTATUS_CARDBUS_NOT_SUPPORTED: u32 = 0x40000027; -pub const SMB_NTSTATUS_WX86_CREATEWX86TIB: u32 = 0x40000028; -pub const SMB_NTSTATUS_MP_PROCESSOR_MISMATCH: u32 = 0x40000029; -pub const SMB_NTSTATUS_HIBERNATED: u32 = 0x4000002a; -pub const SMB_NTSTATUS_RESUME_HIBERNATION: u32 = 0x4000002b; -pub const SMB_NTSTATUS_FIRMWARE_UPDATED: u32 = 0x4000002c; -pub const SMB_NTSTATUS_DRIVERS_LEAKING_LOCKED_PAGES: u32 = 0x4000002d; -pub const SMB_NTSTATUS_MESSAGE_RETRIEVED: u32 = 0x4000002e; -pub const SMB_NTSTATUS_SYSTEM_POWERSTATE_TRANSITION: u32 = 0x4000002f; -pub const SMB_NTSTATUS_ALPC_CHECK_COMPLETION_LIST: u32 = 0x40000030; -pub const SMB_NTSTATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION: u32 = 0x40000031; -pub const SMB_NTSTATUS_ACCESS_AUDIT_BY_POLICY: u32 = 0x40000032; -pub const SMB_NTSTATUS_ABANDON_HIBERFILE: u32 = 0x40000033; -pub const SMB_NTSTATUS_BIZRULES_NOT_ENABLED: u32 = 0x40000034; -pub const SMB_NTSTATUS_WAKE_SYSTEM: u32 = 0x40000294; -pub const SMB_NTSTATUS_DS_SHUTTING_DOWN: u32 = 0x40000370; -pub const SMB_NTDBG_REPLY_LATER: u32 = 0x40010001; -pub const SMB_NTDBG_UNABLE_TO_PROVIDE_HANDLE: u32 = 0x40010002; -pub const SMB_NTDBG_TERMINATE_THREAD: u32 = 0x40010003; -pub const SMB_NTDBG_TERMINATE_PROCESS: u32 = 0x40010004; -pub const SMB_NTDBG_CONTROL_C: u32 = 0x40010005; -pub const SMB_NTDBG_PRINTEXCEPTION_C: u32 = 0x40010006; -pub const SMB_NTDBG_RIPEXCEPTION: u32 = 0x40010007; -pub const SMB_NTDBG_CONTROL_BREAK: u32 = 0x40010008; -pub const SMB_NTDBG_COMMAND_EXCEPTION: u32 = 0x40010009; -pub const SMB_NTRPC_NT_UUID_LOCAL_ONLY: u32 = 0x40020056; -pub const SMB_NTRPC_NT_SEND_INCOMPLETE: u32 = 0x400200af; -pub const SMB_NTSTATUS_CTX_CDM_CONNECT: u32 = 0x400a0004; -pub const SMB_NTSTATUS_CTX_CDM_DISCONNECT: u32 = 0x400a0005; -pub const SMB_NTSTATUS_SXS_RELEASE_ACTIVATION_CONTEXT: u32 = 0x4015000d; -pub const SMB_NTSTATUS_RECOVERY_NOT_NEEDED: u32 = 0x40190034; -pub const SMB_NTSTATUS_RM_ALREADY_STARTED: u32 = 0x40190035; -pub const SMB_NTSTATUS_LOG_NO_RESTART: u32 = 0x401a000c; -pub const SMB_NTSTATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST: u32 = 0x401b00ec; -pub const SMB_NTSTATUS_GRAPHICS_PARTIAL_DATA_POPULATED: u32 = 0x401e000a; -pub const SMB_NTSTATUS_GRAPHICS_DRIVER_MISMATCH: u32 = 0x401e0117; -pub const SMB_NTSTATUS_GRAPHICS_MODE_NOT_PINNED: u32 = 0x401e0307; -pub const SMB_NTSTATUS_GRAPHICS_NO_PREFERRED_MODE: u32 = 0x401e031e; -pub const SMB_NTSTATUS_GRAPHICS_DATASET_IS_EMPTY: u32 = 0x401e034b; -pub const SMB_NTSTATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET: u32 = 0x401e034c; -pub const SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED: u32 = 0x401e0351; -pub const SMB_NTSTATUS_GRAPHICS_UNKNOWN_CHILD_STATUS: u32 = 0x401e042f; -pub const SMB_NTSTATUS_GRAPHICS_LEADLINK_START_DEFERRED: u32 = 0x401e0437; -pub const SMB_NTSTATUS_GRAPHICS_POLLING_TOO_FREQUENTLY: u32 = 0x401e0439; -pub const SMB_NTSTATUS_GRAPHICS_START_DEFERRED: u32 = 0x401e043a; -pub const SMB_NTSTATUS_NDIS_INDICATION_REQUIRED: u32 = 0x40230001; -pub const SMB_NTSTATUS_GUARD_PAGE_VIOLATION: u32 = 0x80000001; -pub const SMB_NTSTATUS_DATATYPE_MISALIGNMENT: u32 = 0x80000002; -pub const SMB_NTSTATUS_BREAKPOINT: u32 = 0x80000003; -pub const SMB_NTSTATUS_SINGLE_STEP: u32 = 0x80000004; -pub const SMB_NTSTATUS_BUFFER_OVERFLOW: u32 = 0x80000005; -pub const SMB_NTSTATUS_NO_MORE_FILES: u32 = 0x80000006; -pub const SMB_NTSTATUS_WAKE_SYSTEM_DEBUGGER: u32 = 0x80000007; -pub const SMB_NTSTATUS_HANDLES_CLOSED: u32 = 0x8000000a; -pub const SMB_NTSTATUS_NO_INHERITANCE: u32 = 0x8000000b; -pub const SMB_NTSTATUS_GUID_SUBSTITUTION_MADE: u32 = 0x8000000c; -pub const SMB_NTSTATUS_PARTIAL_COPY: u32 = 0x8000000d; -pub const SMB_NTSTATUS_DEVICE_PAPER_EMPTY: u32 = 0x8000000e; -pub const SMB_NTSTATUS_DEVICE_POWERED_OFF: u32 = 0x8000000f; -pub const SMB_NTSTATUS_DEVICE_OFF_LINE: u32 = 0x80000010; -pub const SMB_NTSTATUS_DEVICE_BUSY: u32 = 0x80000011; -pub const SMB_NTSTATUS_NO_MORE_EAS: u32 = 0x80000012; -pub const SMB_NTSTATUS_INVALID_EA_NAME: u32 = 0x80000013; -pub const SMB_NTSTATUS_EA_LIST_INCONSISTENT: u32 = 0x80000014; -pub const SMB_NTSTATUS_INVALID_EA_FLAG: u32 = 0x80000015; -pub const SMB_NTSTATUS_VERIFY_REQUIRED: u32 = 0x80000016; -pub const SMB_NTSTATUS_EXTRANEOUS_INFORMATION: u32 = 0x80000017; -pub const SMB_NTSTATUS_RXACT_COMMIT_NECESSARY: u32 = 0x80000018; -pub const SMB_NTSTATUS_NO_MORE_ENTRIES: u32 = 0x8000001a; -pub const SMB_NTSTATUS_FILEMARK_DETECTED: u32 = 0x8000001b; -pub const SMB_NTSTATUS_MEDIA_CHANGED: u32 = 0x8000001c; -pub const SMB_NTSTATUS_BUS_RESET: u32 = 0x8000001d; -pub const SMB_NTSTATUS_END_OF_MEDIA: u32 = 0x8000001e; -pub const SMB_NTSTATUS_BEGINNING_OF_MEDIA: u32 = 0x8000001f; -pub const SMB_NTSTATUS_MEDIA_CHECK: u32 = 0x80000020; -pub const SMB_NTSTATUS_SETMARK_DETECTED: u32 = 0x80000021; -pub const SMB_NTSTATUS_NO_DATA_DETECTED: u32 = 0x80000022; -pub const SMB_NTSTATUS_REDIRECTOR_HAS_OPEN_HANDLES: u32 = 0x80000023; -pub const SMB_NTSTATUS_SERVER_HAS_OPEN_HANDLES: u32 = 0x80000024; -pub const SMB_NTSTATUS_ALREADY_DISCONNECTED: u32 = 0x80000025; -pub const SMB_NTSTATUS_LONGJUMP: u32 = 0x80000026; -pub const SMB_NTSTATUS_CLEANER_CARTRIDGE_INSTALLED: u32 = 0x80000027; -pub const SMB_NTSTATUS_PLUGPLAY_QUERY_VETOED: u32 = 0x80000028; -pub const SMB_NTSTATUS_UNWIND_CONSOLIDATE: u32 = 0x80000029; -pub const SMB_NTSTATUS_REGISTRY_HIVE_RECOVERED: u32 = 0x8000002a; -pub const SMB_NTSTATUS_DLL_MIGHT_BE_INSECURE: u32 = 0x8000002b; -pub const SMB_NTSTATUS_DLL_MIGHT_BE_INCOMPATIBLE: u32 = 0x8000002c; -pub const SMB_NTSTATUS_STOPPED_ON_SYMLINK: u32 = 0x8000002d; -pub const SMB_NTSTATUS_DEVICE_REQUIRES_CLEANING: u32 = 0x80000288; -pub const SMB_NTSTATUS_DEVICE_DOOR_OPEN: u32 = 0x80000289; -pub const SMB_NTSTATUS_DATA_LOST_REPAIR: u32 = 0x80000803; -pub const SMB_NTDBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001; -pub const SMB_NTSTATUS_CLUSTER_NODE_ALREADY_UP: u32 = 0x80130001; -pub const SMB_NTSTATUS_CLUSTER_NODE_ALREADY_DOWN: u32 = 0x80130002; -pub const SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_ONLINE: u32 = 0x80130003; -pub const SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_OFFLINE: u32 = 0x80130004; -pub const SMB_NTSTATUS_CLUSTER_NODE_ALREADY_MEMBER: u32 = 0x80130005; -pub const SMB_NTSTATUS_COULD_NOT_RESIZE_LOG: u32 = 0x80190009; -pub const SMB_NTSTATUS_NO_TXF_METADATA: u32 = 0x80190029; -pub const SMB_NTSTATUS_CANT_RECOVER_WITH_HANDLE_OPEN: u32 = 0x80190031; -pub const SMB_NTSTATUS_TXF_METADATA_ALREADY_PRESENT: u32 = 0x80190041; -pub const SMB_NTSTATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET: u32 = 0x80190042; -pub const SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED: u32 = 0x801b00eb; -pub const SMB_NTSTATUS_FLT_BUFFER_TOO_SMALL: u32 = 0x801c0001; -pub const SMB_NTSTATUS_FVE_PARTIAL_METADATA: u32 = 0x80210001; -pub const SMB_NTSTATUS_FVE_TRANSIENT_STATE: u32 = 0x80210002; -pub const SMB_NTSTATUS_UNSUCCESSFUL: u32 = 0xc0000001; -pub const SMB_NTSTATUS_NOT_IMPLEMENTED: u32 = 0xc0000002; -pub const SMB_NTSTATUS_INVALID_INFO_CLASS: u32 = 0xc0000003; -pub const SMB_NTSTATUS_INFO_LENGTH_MISMATCH: u32 = 0xc0000004; -pub const SMB_NTSTATUS_ACCESS_VIOLATION: u32 = 0xc0000005; -pub const SMB_NTSTATUS_IN_PAGE_ERROR: u32 = 0xc0000006; -pub const SMB_NTSTATUS_PAGEFILE_QUOTA: u32 = 0xc0000007; -pub const SMB_NTSTATUS_INVALID_HANDLE: u32 = 0xc0000008; -pub const SMB_NTSTATUS_BAD_INITIAL_STACK: u32 = 0xc0000009; -pub const SMB_NTSTATUS_BAD_INITIAL_PC: u32 = 0xc000000a; -pub const SMB_NTSTATUS_INVALID_CID: u32 = 0xc000000b; -pub const SMB_NTSTATUS_TIMER_NOT_CANCELED: u32 = 0xc000000c; -pub const SMB_NTSTATUS_INVALID_PARAMETER: u32 = 0xc000000d; -pub const SMB_NTSTATUS_NO_SUCH_DEVICE: u32 = 0xc000000e; -pub const SMB_NTSTATUS_NO_SUCH_FILE: u32 = 0xc000000f; -pub const SMB_NTSTATUS_INVALID_DEVICE_REQUEST: u32 = 0xc0000010; -pub const SMB_NTSTATUS_END_OF_FILE: u32 = 0xc0000011; -pub const SMB_NTSTATUS_WRONG_VOLUME: u32 = 0xc0000012; -pub const SMB_NTSTATUS_NO_MEDIA_IN_DEVICE: u32 = 0xc0000013; -pub const SMB_NTSTATUS_UNRECOGNIZED_MEDIA: u32 = 0xc0000014; -pub const SMB_NTSTATUS_NONEXISTENT_SECTOR: u32 = 0xc0000015; -pub const SMB_NTSTATUS_MORE_PROCESSING_REQUIRED: u32 = 0xc0000016; -pub const SMB_NTSTATUS_NO_MEMORY: u32 = 0xc0000017; -pub const SMB_NTSTATUS_CONFLICTING_ADDRESSES: u32 = 0xc0000018; -pub const SMB_NTSTATUS_NOT_MAPPED_VIEW: u32 = 0xc0000019; -pub const SMB_NTSTATUS_UNABLE_TO_FREE_VM: u32 = 0xc000001a; -pub const SMB_NTSTATUS_UNABLE_TO_DELETE_SECTION: u32 = 0xc000001b; -pub const SMB_NTSTATUS_INVALID_SYSTEM_SERVICE: u32 = 0xc000001c; -pub const SMB_NTSTATUS_ILLEGAL_INSTRUCTION: u32 = 0xc000001d; -pub const SMB_NTSTATUS_INVALID_LOCK_SEQUENCE: u32 = 0xc000001e; -pub const SMB_NTSTATUS_INVALID_VIEW_SIZE: u32 = 0xc000001f; -pub const SMB_NTSTATUS_INVALID_FILE_FOR_SECTION: u32 = 0xc0000020; -pub const SMB_NTSTATUS_ALREADY_COMMITTED: u32 = 0xc0000021; -pub const SMB_NTSTATUS_ACCESS_DENIED: u32 = 0xc0000022; -pub const SMB_NTSTATUS_BUFFER_TOO_SMALL: u32 = 0xc0000023; -pub const SMB_NTSTATUS_OBJECT_TYPE_MISMATCH: u32 = 0xc0000024; -pub const SMB_NTSTATUS_NONCONTINUABLE_EXCEPTION: u32 = 0xc0000025; -pub const SMB_NTSTATUS_INVALID_DISPOSITION: u32 = 0xc0000026; -pub const SMB_NTSTATUS_UNWIND: u32 = 0xc0000027; -pub const SMB_NTSTATUS_BAD_STACK: u32 = 0xc0000028; -pub const SMB_NTSTATUS_INVALID_UNWIND_TARGET: u32 = 0xc0000029; -pub const SMB_NTSTATUS_NOT_LOCKED: u32 = 0xc000002a; -pub const SMB_NTSTATUS_PARITY_ERROR: u32 = 0xc000002b; -pub const SMB_NTSTATUS_UNABLE_TO_DECOMMIT_VM: u32 = 0xc000002c; -pub const SMB_NTSTATUS_NOT_COMMITTED: u32 = 0xc000002d; -pub const SMB_NTSTATUS_INVALID_PORT_ATTRIBUTES: u32 = 0xc000002e; -pub const SMB_NTSTATUS_PORT_MESSAGE_TOO_LONG: u32 = 0xc000002f; -pub const SMB_NTSTATUS_INVALID_PARAMETER_MIX: u32 = 0xc0000030; -pub const SMB_NTSTATUS_INVALID_QUOTA_LOWER: u32 = 0xc0000031; -pub const SMB_NTSTATUS_DISK_CORRUPT_ERROR: u32 = 0xc0000032; -pub const SMB_NTSTATUS_OBJECT_NAME_INVALID: u32 = 0xc0000033; -pub const SMB_NTSTATUS_OBJECT_NAME_NOT_FOUND: u32 = 0xc0000034; -pub const SMB_NTSTATUS_OBJECT_NAME_COLLISION: u32 = 0xc0000035; -pub const SMB_NTSTATUS_PORT_DISCONNECTED: u32 = 0xc0000037; -pub const SMB_NTSTATUS_DEVICE_ALREADY_ATTACHED: u32 = 0xc0000038; -pub const SMB_NTSTATUS_OBJECT_PATH_INVALID: u32 = 0xc0000039; -pub const SMB_NTSTATUS_OBJECT_PATH_NOT_FOUND: u32 = 0xc000003a; -pub const SMB_NTSTATUS_OBJECT_PATH_SYNTAX_BAD: u32 = 0xc000003b; -pub const SMB_NTSTATUS_DATA_OVERRUN: u32 = 0xc000003c; -pub const SMB_NTSTATUS_DATA_LATE_ERROR: u32 = 0xc000003d; -pub const SMB_NTSTATUS_DATA_ERROR: u32 = 0xc000003e; -pub const SMB_NTSTATUS_CRC_ERROR: u32 = 0xc000003f; -pub const SMB_NTSTATUS_SECTION_TOO_BIG: u32 = 0xc0000040; -pub const SMB_NTSTATUS_PORT_CONNECTION_REFUSED: u32 = 0xc0000041; -pub const SMB_NTSTATUS_INVALID_PORT_HANDLE: u32 = 0xc0000042; -pub const SMB_NTSTATUS_SHARING_VIOLATION: u32 = 0xc0000043; -pub const SMB_NTSTATUS_QUOTA_EXCEEDED: u32 = 0xc0000044; -pub const SMB_NTSTATUS_INVALID_PAGE_PROTECTION: u32 = 0xc0000045; -pub const SMB_NTSTATUS_MUTANT_NOT_OWNED: u32 = 0xc0000046; -pub const SMB_NTSTATUS_SEMAPHORE_LIMIT_EXCEEDED: u32 = 0xc0000047; -pub const SMB_NTSTATUS_PORT_ALREADY_SET: u32 = 0xc0000048; -pub const SMB_NTSTATUS_SECTION_NOT_IMAGE: u32 = 0xc0000049; -pub const SMB_NTSTATUS_SUSPEND_COUNT_EXCEEDED: u32 = 0xc000004a; -pub const SMB_NTSTATUS_THREAD_IS_TERMINATING: u32 = 0xc000004b; -pub const SMB_NTSTATUS_BAD_WORKING_SET_LIMIT: u32 = 0xc000004c; -pub const SMB_NTSTATUS_INCOMPATIBLE_FILE_MAP: u32 = 0xc000004d; -pub const SMB_NTSTATUS_SECTION_PROTECTION: u32 = 0xc000004e; -pub const SMB_NTSTATUS_EAS_NOT_SUPPORTED: u32 = 0xc000004f; -pub const SMB_NTSTATUS_EA_TOO_LARGE: u32 = 0xc0000050; -pub const SMB_NTSTATUS_NONEXISTENT_EA_ENTRY: u32 = 0xc0000051; -pub const SMB_NTSTATUS_NO_EAS_ON_FILE: u32 = 0xc0000052; -pub const SMB_NTSTATUS_EA_CORRUPT_ERROR: u32 = 0xc0000053; -pub const SMB_NTSTATUS_FILE_LOCK_CONFLICT: u32 = 0xc0000054; -pub const SMB_NTSTATUS_LOCK_NOT_GRANTED: u32 = 0xc0000055; -pub const SMB_NTSTATUS_DELETE_PENDING: u32 = 0xc0000056; -pub const SMB_NTSTATUS_CTL_FILE_NOT_SUPPORTED: u32 = 0xc0000057; -pub const SMB_NTSTATUS_UNKNOWN_REVISION: u32 = 0xc0000058; -pub const SMB_NTSTATUS_REVISION_MISMATCH: u32 = 0xc0000059; -pub const SMB_NTSTATUS_INVALID_OWNER: u32 = 0xc000005a; -pub const SMB_NTSTATUS_INVALID_PRIMARY_GROUP: u32 = 0xc000005b; -pub const SMB_NTSTATUS_NO_IMPERSONATION_TOKEN: u32 = 0xc000005c; -pub const SMB_NTSTATUS_CANT_DISABLE_MANDATORY: u32 = 0xc000005d; -pub const SMB_NTSTATUS_NO_LOGON_SERVERS: u32 = 0xc000005e; -pub const SMB_NTSTATUS_NO_SUCH_LOGON_SESSION: u32 = 0xc000005f; -pub const SMB_NTSTATUS_NO_SUCH_PRIVILEGE: u32 = 0xc0000060; -pub const SMB_NTSTATUS_PRIVILEGE_NOT_HELD: u32 = 0xc0000061; -pub const SMB_NTSTATUS_INVALID_ACCOUNT_NAME: u32 = 0xc0000062; -pub const SMB_NTSTATUS_USER_EXISTS: u32 = 0xc0000063; -pub const SMB_NTSTATUS_NO_SUCH_USER: u32 = 0xc0000064; -pub const SMB_NTSTATUS_GROUP_EXISTS: u32 = 0xc0000065; -pub const SMB_NTSTATUS_NO_SUCH_GROUP: u32 = 0xc0000066; -pub const SMB_NTSTATUS_MEMBER_IN_GROUP: u32 = 0xc0000067; -pub const SMB_NTSTATUS_MEMBER_NOT_IN_GROUP: u32 = 0xc0000068; -pub const SMB_NTSTATUS_LAST_ADMIN: u32 = 0xc0000069; -pub const SMB_NTSTATUS_WRONG_PASSWORD: u32 = 0xc000006a; -pub const SMB_NTSTATUS_ILL_FORMED_PASSWORD: u32 = 0xc000006b; -pub const SMB_NTSTATUS_PASSWORD_RESTRICTION: u32 = 0xc000006c; -pub const SMB_NTSTATUS_LOGON_FAILURE: u32 = 0xc000006d; -pub const SMB_NTSTATUS_ACCOUNT_RESTRICTION: u32 = 0xc000006e; -pub const SMB_NTSTATUS_INVALID_LOGON_HOURS: u32 = 0xc000006f; -pub const SMB_NTSTATUS_INVALID_WORKSTATION: u32 = 0xc0000070; -pub const SMB_NTSTATUS_PASSWORD_EXPIRED: u32 = 0xc0000071; -pub const SMB_NTSTATUS_ACCOUNT_DISABLED: u32 = 0xc0000072; -pub const SMB_NTSTATUS_NONE_MAPPED: u32 = 0xc0000073; -pub const SMB_NTSTATUS_TOO_MANY_LUIDS_REQUESTED: u32 = 0xc0000074; -pub const SMB_NTSTATUS_LUIDS_EXHAUSTED: u32 = 0xc0000075; -pub const SMB_NTSTATUS_INVALID_SUB_AUTHORITY: u32 = 0xc0000076; -pub const SMB_NTSTATUS_INVALID_ACL: u32 = 0xc0000077; -pub const SMB_NTSTATUS_INVALID_SID: u32 = 0xc0000078; -pub const SMB_NTSTATUS_INVALID_SECURITY_DESCR: u32 = 0xc0000079; -pub const SMB_NTSTATUS_PROCEDURE_NOT_FOUND: u32 = 0xc000007a; -pub const SMB_NTSTATUS_INVALID_IMAGE_FORMAT: u32 = 0xc000007b; -pub const SMB_NTSTATUS_NO_TOKEN: u32 = 0xc000007c; -pub const SMB_NTSTATUS_BAD_INHERITANCE_ACL: u32 = 0xc000007d; -pub const SMB_NTSTATUS_RANGE_NOT_LOCKED: u32 = 0xc000007e; -pub const SMB_NTSTATUS_DISK_FULL: u32 = 0xc000007f; -pub const SMB_NTSTATUS_SERVER_DISABLED: u32 = 0xc0000080; -pub const SMB_NTSTATUS_SERVER_NOT_DISABLED: u32 = 0xc0000081; -pub const SMB_NTSTATUS_TOO_MANY_GUIDS_REQUESTED: u32 = 0xc0000082; -pub const SMB_NTSTATUS_GUIDS_EXHAUSTED: u32 = 0xc0000083; -pub const SMB_NTSTATUS_INVALID_ID_AUTHORITY: u32 = 0xc0000084; -pub const SMB_NTSTATUS_AGENTS_EXHAUSTED: u32 = 0xc0000085; -pub const SMB_NTSTATUS_INVALID_VOLUME_LABEL: u32 = 0xc0000086; -pub const SMB_NTSTATUS_SECTION_NOT_EXTENDED: u32 = 0xc0000087; -pub const SMB_NTSTATUS_NOT_MAPPED_DATA: u32 = 0xc0000088; -pub const SMB_NTSTATUS_RESOURCE_DATA_NOT_FOUND: u32 = 0xc0000089; -pub const SMB_NTSTATUS_RESOURCE_TYPE_NOT_FOUND: u32 = 0xc000008a; -pub const SMB_NTSTATUS_RESOURCE_NAME_NOT_FOUND: u32 = 0xc000008b; -pub const SMB_NTSTATUS_ARRAY_BOUNDS_EXCEEDED: u32 = 0xc000008c; -pub const SMB_NTSTATUS_FLOAT_DENORMAL_OPERAND: u32 = 0xc000008d; -pub const SMB_NTSTATUS_FLOAT_DIVIDE_BY_ZERO: u32 = 0xc000008e; -pub const SMB_NTSTATUS_FLOAT_INEXACT_RESULT: u32 = 0xc000008f; -pub const SMB_NTSTATUS_FLOAT_INVALID_OPERATION: u32 = 0xc0000090; -pub const SMB_NTSTATUS_FLOAT_OVERFLOW: u32 = 0xc0000091; -pub const SMB_NTSTATUS_FLOAT_STACK_CHECK: u32 = 0xc0000092; -pub const SMB_NTSTATUS_FLOAT_UNDERFLOW: u32 = 0xc0000093; -pub const SMB_NTSTATUS_INTEGER_DIVIDE_BY_ZERO: u32 = 0xc0000094; -pub const SMB_NTSTATUS_INTEGER_OVERFLOW: u32 = 0xc0000095; -pub const SMB_NTSTATUS_PRIVILEGED_INSTRUCTION: u32 = 0xc0000096; -pub const SMB_NTSTATUS_TOO_MANY_PAGING_FILES: u32 = 0xc0000097; -pub const SMB_NTSTATUS_FILE_INVALID: u32 = 0xc0000098; -pub const SMB_NTSTATUS_ALLOTTED_SPACE_EXCEEDED: u32 = 0xc0000099; -pub const SMB_NTSTATUS_INSUFFICIENT_RESOURCES: u32 = 0xc000009a; -pub const SMB_NTSTATUS_DFS_EXIT_PATH_FOUND: u32 = 0xc000009b; -pub const SMB_NTSTATUS_DEVICE_DATA_ERROR: u32 = 0xc000009c; -pub const SMB_NTSTATUS_DEVICE_NOT_CONNECTED: u32 = 0xc000009d; -pub const SMB_NTSTATUS_FREE_VM_NOT_AT_BASE: u32 = 0xc000009f; -pub const SMB_NTSTATUS_MEMORY_NOT_ALLOCATED: u32 = 0xc00000a0; -pub const SMB_NTSTATUS_WORKING_SET_QUOTA: u32 = 0xc00000a1; -pub const SMB_NTSTATUS_MEDIA_WRITE_PROTECTED: u32 = 0xc00000a2; -pub const SMB_NTSTATUS_DEVICE_NOT_READY: u32 = 0xc00000a3; -pub const SMB_NTSTATUS_INVALID_GROUP_ATTRIBUTES: u32 = 0xc00000a4; -pub const SMB_NTSTATUS_BAD_IMPERSONATION_LEVEL: u32 = 0xc00000a5; -pub const SMB_NTSTATUS_CANT_OPEN_ANONYMOUS: u32 = 0xc00000a6; -pub const SMB_NTSTATUS_BAD_VALIDATION_CLASS: u32 = 0xc00000a7; -pub const SMB_NTSTATUS_BAD_TOKEN_TYPE: u32 = 0xc00000a8; -pub const SMB_NTSTATUS_BAD_MASTER_BOOT_RECORD: u32 = 0xc00000a9; -pub const SMB_NTSTATUS_INSTRUCTION_MISALIGNMENT: u32 = 0xc00000aa; -pub const SMB_NTSTATUS_INSTANCE_NOT_AVAILABLE: u32 = 0xc00000ab; -pub const SMB_NTSTATUS_PIPE_NOT_AVAILABLE: u32 = 0xc00000ac; -pub const SMB_NTSTATUS_INVALID_PIPE_STATE: u32 = 0xc00000ad; -pub const SMB_NTSTATUS_PIPE_BUSY: u32 = 0xc00000ae; -pub const SMB_NTSTATUS_ILLEGAL_FUNCTION: u32 = 0xc00000af; -pub const SMB_NTSTATUS_PIPE_DISCONNECTED: u32 = 0xc00000b0; -pub const SMB_NTSTATUS_PIPE_CLOSING: u32 = 0xc00000b1; -pub const SMB_NTSTATUS_PIPE_CONNECTED: u32 = 0xc00000b2; -pub const SMB_NTSTATUS_PIPE_LISTENING: u32 = 0xc00000b3; -pub const SMB_NTSTATUS_INVALID_READ_MODE: u32 = 0xc00000b4; -pub const SMB_NTSTATUS_IO_TIMEOUT: u32 = 0xc00000b5; -pub const SMB_NTSTATUS_FILE_FORCED_CLOSED: u32 = 0xc00000b6; -pub const SMB_NTSTATUS_PROFILING_NOT_STARTED: u32 = 0xc00000b7; -pub const SMB_NTSTATUS_PROFILING_NOT_STOPPED: u32 = 0xc00000b8; -pub const SMB_NTSTATUS_COULD_NOT_INTERPRET: u32 = 0xc00000b9; -pub const SMB_NTSTATUS_FILE_IS_A_DIRECTORY: u32 = 0xc00000ba; -pub const SMB_NTSTATUS_NOT_SUPPORTED: u32 = 0xc00000bb; -pub const SMB_NTSTATUS_REMOTE_NOT_LISTENING: u32 = 0xc00000bc; -pub const SMB_NTSTATUS_DUPLICATE_NAME: u32 = 0xc00000bd; -pub const SMB_NTSTATUS_BAD_NETWORK_PATH: u32 = 0xc00000be; -pub const SMB_NTSTATUS_NETWORK_BUSY: u32 = 0xc00000bf; -pub const SMB_NTSTATUS_DEVICE_DOES_NOT_EXIST: u32 = 0xc00000c0; -pub const SMB_NTSTATUS_TOO_MANY_COMMANDS: u32 = 0xc00000c1; -pub const SMB_NTSTATUS_ADAPTER_HARDWARE_ERROR: u32 = 0xc00000c2; -pub const SMB_NTSTATUS_INVALID_NETWORK_RESPONSE: u32 = 0xc00000c3; -pub const SMB_NTSTATUS_UNEXPECTED_NETWORK_ERROR: u32 = 0xc00000c4; -pub const SMB_NTSTATUS_BAD_REMOTE_ADAPTER: u32 = 0xc00000c5; -pub const SMB_NTSTATUS_PRINT_QUEUE_FULL: u32 = 0xc00000c6; -pub const SMB_NTSTATUS_NO_SPOOL_SPACE: u32 = 0xc00000c7; -pub const SMB_NTSTATUS_PRINT_CANCELLED: u32 = 0xc00000c8; -pub const SMB_NTSTATUS_NETWORK_NAME_DELETED: u32 = 0xc00000c9; -pub const SMB_NTSTATUS_NETWORK_ACCESS_DENIED: u32 = 0xc00000ca; -pub const SMB_NTSTATUS_BAD_DEVICE_TYPE: u32 = 0xc00000cb; -pub const SMB_NTSTATUS_BAD_NETWORK_NAME: u32 = 0xc00000cc; -pub const SMB_NTSTATUS_TOO_MANY_NAMES: u32 = 0xc00000cd; -pub const SMB_NTSTATUS_TOO_MANY_SESSIONS: u32 = 0xc00000ce; -pub const SMB_NTSTATUS_SHARING_PAUSED: u32 = 0xc00000cf; -pub const SMB_NTSTATUS_REQUEST_NOT_ACCEPTED: u32 = 0xc00000d0; -pub const SMB_NTSTATUS_REDIRECTOR_PAUSED: u32 = 0xc00000d1; -pub const SMB_NTSTATUS_NET_WRITE_FAULT: u32 = 0xc00000d2; -pub const SMB_NTSTATUS_PROFILING_AT_LIMIT: u32 = 0xc00000d3; -pub const SMB_NTSTATUS_NOT_SAME_DEVICE: u32 = 0xc00000d4; -pub const SMB_NTSTATUS_FILE_RENAMED: u32 = 0xc00000d5; -pub const SMB_NTSTATUS_VIRTUAL_CIRCUIT_CLOSED: u32 = 0xc00000d6; -pub const SMB_NTSTATUS_NO_SECURITY_ON_OBJECT: u32 = 0xc00000d7; -pub const SMB_NTSTATUS_CANT_WAIT: u32 = 0xc00000d8; -pub const SMB_NTSTATUS_PIPE_EMPTY: u32 = 0xc00000d9; -pub const SMB_NTSTATUS_CANT_ACCESS_DOMAIN_INFO: u32 = 0xc00000da; -pub const SMB_NTSTATUS_CANT_TERMINATE_SELF: u32 = 0xc00000db; -pub const SMB_NTSTATUS_INVALID_SERVER_STATE: u32 = 0xc00000dc; -pub const SMB_NTSTATUS_INVALID_DOMAIN_STATE: u32 = 0xc00000dd; -pub const SMB_NTSTATUS_INVALID_DOMAIN_ROLE: u32 = 0xc00000de; -pub const SMB_NTSTATUS_NO_SUCH_DOMAIN: u32 = 0xc00000df; -pub const SMB_NTSTATUS_DOMAIN_EXISTS: u32 = 0xc00000e0; -pub const SMB_NTSTATUS_DOMAIN_LIMIT_EXCEEDED: u32 = 0xc00000e1; -pub const SMB_NTSTATUS_OPLOCK_NOT_GRANTED: u32 = 0xc00000e2; -pub const SMB_NTSTATUS_INVALID_OPLOCK_PROTOCOL: u32 = 0xc00000e3; -pub const SMB_NTSTATUS_INTERNAL_DB_CORRUPTION: u32 = 0xc00000e4; -pub const SMB_NTSTATUS_INTERNAL_ERROR: u32 = 0xc00000e5; -pub const SMB_NTSTATUS_GENERIC_NOT_MAPPED: u32 = 0xc00000e6; -pub const SMB_NTSTATUS_BAD_DESCRIPTOR_FORMAT: u32 = 0xc00000e7; -pub const SMB_NTSTATUS_INVALID_USER_BUFFER: u32 = 0xc00000e8; -pub const SMB_NTSTATUS_UNEXPECTED_IO_ERROR: u32 = 0xc00000e9; -pub const SMB_NTSTATUS_UNEXPECTED_MM_CREATE_ERR: u32 = 0xc00000ea; -pub const SMB_NTSTATUS_UNEXPECTED_MM_MAP_ERROR: u32 = 0xc00000eb; -pub const SMB_NTSTATUS_UNEXPECTED_MM_EXTEND_ERR: u32 = 0xc00000ec; -pub const SMB_NTSTATUS_NOT_LOGON_PROCESS: u32 = 0xc00000ed; -pub const SMB_NTSTATUS_LOGON_SESSION_EXISTS: u32 = 0xc00000ee; -pub const SMB_NTSTATUS_INVALID_PARAMETER_1: u32 = 0xc00000ef; -pub const SMB_NTSTATUS_INVALID_PARAMETER_2: u32 = 0xc00000f0; -pub const SMB_NTSTATUS_INVALID_PARAMETER_3: u32 = 0xc00000f1; -pub const SMB_NTSTATUS_INVALID_PARAMETER_4: u32 = 0xc00000f2; -pub const SMB_NTSTATUS_INVALID_PARAMETER_5: u32 = 0xc00000f3; -pub const SMB_NTSTATUS_INVALID_PARAMETER_6: u32 = 0xc00000f4; -pub const SMB_NTSTATUS_INVALID_PARAMETER_7: u32 = 0xc00000f5; -pub const SMB_NTSTATUS_INVALID_PARAMETER_8: u32 = 0xc00000f6; -pub const SMB_NTSTATUS_INVALID_PARAMETER_9: u32 = 0xc00000f7; -pub const SMB_NTSTATUS_INVALID_PARAMETER_10: u32 = 0xc00000f8; -pub const SMB_NTSTATUS_INVALID_PARAMETER_11: u32 = 0xc00000f9; -pub const SMB_NTSTATUS_INVALID_PARAMETER_12: u32 = 0xc00000fa; -pub const SMB_NTSTATUS_REDIRECTOR_NOT_STARTED: u32 = 0xc00000fb; -pub const SMB_NTSTATUS_REDIRECTOR_STARTED: u32 = 0xc00000fc; -pub const SMB_NTSTATUS_STACK_OVERFLOW: u32 = 0xc00000fd; -pub const SMB_NTSTATUS_NO_SUCH_PACKAGE: u32 = 0xc00000fe; -pub const SMB_NTSTATUS_BAD_FUNCTION_TABLE: u32 = 0xc00000ff; -pub const SMB_NTSTATUS_VARIABLE_NOT_FOUND: u32 = 0xc0000100; -pub const SMB_NTSTATUS_DIRECTORY_NOT_EMPTY: u32 = 0xc0000101; -pub const SMB_NTSTATUS_FILE_CORRUPT_ERROR: u32 = 0xc0000102; -pub const SMB_NTSTATUS_NOT_A_DIRECTORY: u32 = 0xc0000103; -pub const SMB_NTSTATUS_BAD_LOGON_SESSION_STATE: u32 = 0xc0000104; -pub const SMB_NTSTATUS_LOGON_SESSION_COLLISION: u32 = 0xc0000105; -pub const SMB_NTSTATUS_NAME_TOO_LONG: u32 = 0xc0000106; -pub const SMB_NTSTATUS_FILES_OPEN: u32 = 0xc0000107; -pub const SMB_NTSTATUS_CONNECTION_IN_USE: u32 = 0xc0000108; -pub const SMB_NTSTATUS_MESSAGE_NOT_FOUND: u32 = 0xc0000109; -pub const SMB_NTSTATUS_PROCESS_IS_TERMINATING: u32 = 0xc000010a; -pub const SMB_NTSTATUS_INVALID_LOGON_TYPE: u32 = 0xc000010b; -pub const SMB_NTSTATUS_NO_GUID_TRANSLATION: u32 = 0xc000010c; -pub const SMB_NTSTATUS_CANNOT_IMPERSONATE: u32 = 0xc000010d; -pub const SMB_NTSTATUS_IMAGE_ALREADY_LOADED: u32 = 0xc000010e; -pub const SMB_NTSTATUS_NO_LDT: u32 = 0xc0000117; -pub const SMB_NTSTATUS_INVALID_LDT_SIZE: u32 = 0xc0000118; -pub const SMB_NTSTATUS_INVALID_LDT_OFFSET: u32 = 0xc0000119; -pub const SMB_NTSTATUS_INVALID_LDT_DESCRIPTOR: u32 = 0xc000011a; -pub const SMB_NTSTATUS_INVALID_IMAGE_NE_FORMAT: u32 = 0xc000011b; -pub const SMB_NTSTATUS_RXACT_INVALID_STATE: u32 = 0xc000011c; -pub const SMB_NTSTATUS_RXACT_COMMIT_FAILURE: u32 = 0xc000011d; -pub const SMB_NTSTATUS_MAPPED_FILE_SIZE_ZERO: u32 = 0xc000011e; -pub const SMB_NTSTATUS_TOO_MANY_OPENED_FILES: u32 = 0xc000011f; -pub const SMB_NTSTATUS_CANCELLED: u32 = 0xc0000120; -pub const SMB_NTSTATUS_CANNOT_DELETE: u32 = 0xc0000121; -pub const SMB_NTSTATUS_INVALID_COMPUTER_NAME: u32 = 0xc0000122; -pub const SMB_NTSTATUS_FILE_DELETED: u32 = 0xc0000123; -pub const SMB_NTSTATUS_SPECIAL_ACCOUNT: u32 = 0xc0000124; -pub const SMB_NTSTATUS_SPECIAL_GROUP: u32 = 0xc0000125; -pub const SMB_NTSTATUS_SPECIAL_USER: u32 = 0xc0000126; -pub const SMB_NTSTATUS_MEMBERS_PRIMARY_GROUP: u32 = 0xc0000127; -pub const SMB_NTSTATUS_FILE_CLOSED: u32 = 0xc0000128; -pub const SMB_NTSTATUS_TOO_MANY_THREADS: u32 = 0xc0000129; -pub const SMB_NTSTATUS_THREAD_NOT_IN_PROCESS: u32 = 0xc000012a; -pub const SMB_NTSTATUS_TOKEN_ALREADY_IN_USE: u32 = 0xc000012b; -pub const SMB_NTSTATUS_PAGEFILE_QUOTA_EXCEEDED: u32 = 0xc000012c; -pub const SMB_NTSTATUS_COMMITMENT_LIMIT: u32 = 0xc000012d; -pub const SMB_NTSTATUS_INVALID_IMAGE_LE_FORMAT: u32 = 0xc000012e; -pub const SMB_NTSTATUS_INVALID_IMAGE_NOT_MZ: u32 = 0xc000012f; -pub const SMB_NTSTATUS_INVALID_IMAGE_PROTECT: u32 = 0xc0000130; -pub const SMB_NTSTATUS_INVALID_IMAGE_WIN_16: u32 = 0xc0000131; -pub const SMB_NTSTATUS_LOGON_SERVER_CONFLICT: u32 = 0xc0000132; -pub const SMB_NTSTATUS_TIME_DIFFERENCE_AT_DC: u32 = 0xc0000133; -pub const SMB_NTSTATUS_SYNCHRONIZATION_REQUIRED: u32 = 0xc0000134; -pub const SMB_NTSTATUS_DLL_NOT_FOUND: u32 = 0xc0000135; -pub const SMB_NTSTATUS_OPEN_FAILED: u32 = 0xc0000136; -pub const SMB_NTSTATUS_IO_PRIVILEGE_FAILED: u32 = 0xc0000137; -pub const SMB_NTSTATUS_ORDINAL_NOT_FOUND: u32 = 0xc0000138; -pub const SMB_NTSTATUS_ENTRYPOINT_NOT_FOUND: u32 = 0xc0000139; -pub const SMB_NTSTATUS_CONTROL_C_EXIT: u32 = 0xc000013a; -pub const SMB_NTSTATUS_LOCAL_DISCONNECT: u32 = 0xc000013b; -pub const SMB_NTSTATUS_REMOTE_DISCONNECT: u32 = 0xc000013c; -pub const SMB_NTSTATUS_REMOTE_RESOURCES: u32 = 0xc000013d; -pub const SMB_NTSTATUS_LINK_FAILED: u32 = 0xc000013e; -pub const SMB_NTSTATUS_LINK_TIMEOUT: u32 = 0xc000013f; -pub const SMB_NTSTATUS_INVALID_CONNECTION: u32 = 0xc0000140; -pub const SMB_NTSTATUS_INVALID_ADDRESS: u32 = 0xc0000141; -pub const SMB_NTSTATUS_DLL_INIT_FAILED: u32 = 0xc0000142; -pub const SMB_NTSTATUS_MISSING_SYSTEMFILE: u32 = 0xc0000143; -pub const SMB_NTSTATUS_UNHANDLED_EXCEPTION: u32 = 0xc0000144; -pub const SMB_NTSTATUS_APP_INIT_FAILURE: u32 = 0xc0000145; -pub const SMB_NTSTATUS_PAGEFILE_CREATE_FAILED: u32 = 0xc0000146; -pub const SMB_NTSTATUS_NO_PAGEFILE: u32 = 0xc0000147; -pub const SMB_NTSTATUS_INVALID_LEVEL: u32 = 0xc0000148; -pub const SMB_NTSTATUS_WRONG_PASSWORD_CORE: u32 = 0xc0000149; -pub const SMB_NTSTATUS_ILLEGAL_FLOAT_CONTEXT: u32 = 0xc000014a; -pub const SMB_NTSTATUS_PIPE_BROKEN: u32 = 0xc000014b; -pub const SMB_NTSTATUS_REGISTRY_CORRUPT: u32 = 0xc000014c; -pub const SMB_NTSTATUS_REGISTRY_IO_FAILED: u32 = 0xc000014d; -pub const SMB_NTSTATUS_NO_EVENT_PAIR: u32 = 0xc000014e; -pub const SMB_NTSTATUS_UNRECOGNIZED_VOLUME: u32 = 0xc000014f; -pub const SMB_NTSTATUS_SERIAL_NO_DEVICE_INITED: u32 = 0xc0000150; -pub const SMB_NTSTATUS_NO_SUCH_ALIAS: u32 = 0xc0000151; -pub const SMB_NTSTATUS_MEMBER_NOT_IN_ALIAS: u32 = 0xc0000152; -pub const SMB_NTSTATUS_MEMBER_IN_ALIAS: u32 = 0xc0000153; -pub const SMB_NTSTATUS_ALIAS_EXISTS: u32 = 0xc0000154; -pub const SMB_NTSTATUS_LOGON_NOT_GRANTED: u32 = 0xc0000155; -pub const SMB_NTSTATUS_TOO_MANY_SECRETS: u32 = 0xc0000156; -pub const SMB_NTSTATUS_SECRET_TOO_LONG: u32 = 0xc0000157; -pub const SMB_NTSTATUS_INTERNAL_DB_ERROR: u32 = 0xc0000158; -pub const SMB_NTSTATUS_FULLSCREEN_MODE: u32 = 0xc0000159; -pub const SMB_NTSTATUS_TOO_MANY_CONTEXT_IDS: u32 = 0xc000015a; -pub const SMB_NTSTATUS_LOGON_TYPE_NOT_GRANTED: u32 = 0xc000015b; -pub const SMB_NTSTATUS_NOT_REGISTRY_FILE: u32 = 0xc000015c; -pub const SMB_NTSTATUS_NT_CROSS_ENCRYPTION_REQUIRED: u32 = 0xc000015d; -pub const SMB_NTSTATUS_DOMAIN_CTRLR_CONFIG_ERROR: u32 = 0xc000015e; -pub const SMB_NTSTATUS_FT_MISSING_MEMBER: u32 = 0xc000015f; -pub const SMB_NTSTATUS_ILL_FORMED_SERVICE_ENTRY: u32 = 0xc0000160; -pub const SMB_NTSTATUS_ILLEGAL_CHARACTER: u32 = 0xc0000161; -pub const SMB_NTSTATUS_UNMAPPABLE_CHARACTER: u32 = 0xc0000162; -pub const SMB_NTSTATUS_UNDEFINED_CHARACTER: u32 = 0xc0000163; -pub const SMB_NTSTATUS_FLOPPY_VOLUME: u32 = 0xc0000164; -pub const SMB_NTSTATUS_FLOPPY_ID_MARK_NOT_FOUND: u32 = 0xc0000165; -pub const SMB_NTSTATUS_FLOPPY_WRONG_CYLINDER: u32 = 0xc0000166; -pub const SMB_NTSTATUS_FLOPPY_UNKNOWN_ERROR: u32 = 0xc0000167; -pub const SMB_NTSTATUS_FLOPPY_BAD_REGISTERS: u32 = 0xc0000168; -pub const SMB_NTSTATUS_DISK_RECALIBRATE_FAILED: u32 = 0xc0000169; -pub const SMB_NTSTATUS_DISK_OPERATION_FAILED: u32 = 0xc000016a; -pub const SMB_NTSTATUS_DISK_RESET_FAILED: u32 = 0xc000016b; -pub const SMB_NTSTATUS_SHARED_IRQ_BUSY: u32 = 0xc000016c; -pub const SMB_NTSTATUS_FT_ORPHANING: u32 = 0xc000016d; -pub const SMB_NTSTATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT: u32 = 0xc000016e; -pub const SMB_NTSTATUS_PARTITION_FAILURE: u32 = 0xc0000172; -pub const SMB_NTSTATUS_INVALID_BLOCK_LENGTH: u32 = 0xc0000173; -pub const SMB_NTSTATUS_DEVICE_NOT_PARTITIONED: u32 = 0xc0000174; -pub const SMB_NTSTATUS_UNABLE_TO_LOCK_MEDIA: u32 = 0xc0000175; -pub const SMB_NTSTATUS_UNABLE_TO_UNLOAD_MEDIA: u32 = 0xc0000176; -pub const SMB_NTSTATUS_EOM_OVERFLOW: u32 = 0xc0000177; -pub const SMB_NTSTATUS_NO_MEDIA: u32 = 0xc0000178; -pub const SMB_NTSTATUS_NO_SUCH_MEMBER: u32 = 0xc000017a; -pub const SMB_NTSTATUS_INVALID_MEMBER: u32 = 0xc000017b; -pub const SMB_NTSTATUS_KEY_DELETED: u32 = 0xc000017c; -pub const SMB_NTSTATUS_NO_LOG_SPACE: u32 = 0xc000017d; -pub const SMB_NTSTATUS_TOO_MANY_SIDS: u32 = 0xc000017e; -pub const SMB_NTSTATUS_LM_CROSS_ENCRYPTION_REQUIRED: u32 = 0xc000017f; -pub const SMB_NTSTATUS_KEY_HAS_CHILDREN: u32 = 0xc0000180; -pub const SMB_NTSTATUS_CHILD_MUST_BE_VOLATILE: u32 = 0xc0000181; -pub const SMB_NTSTATUS_DEVICE_CONFIGURATION_ERROR: u32 = 0xc0000182; -pub const SMB_NTSTATUS_DRIVER_INTERNAL_ERROR: u32 = 0xc0000183; -pub const SMB_NTSTATUS_INVALID_DEVICE_STATE: u32 = 0xc0000184; -pub const SMB_NTSTATUS_IO_DEVICE_ERROR: u32 = 0xc0000185; -pub const SMB_NTSTATUS_DEVICE_PROTOCOL_ERROR: u32 = 0xc0000186; -pub const SMB_NTSTATUS_BACKUP_CONTROLLER: u32 = 0xc0000187; -pub const SMB_NTSTATUS_LOG_FILE_FULL: u32 = 0xc0000188; -pub const SMB_NTSTATUS_TOO_LATE: u32 = 0xc0000189; -pub const SMB_NTSTATUS_NO_TRUST_LSA_SECRET: u32 = 0xc000018a; -pub const SMB_NTSTATUS_NO_TRUST_SAM_ACCOUNT: u32 = 0xc000018b; -pub const SMB_NTSTATUS_TRUSTED_DOMAIN_FAILURE: u32 = 0xc000018c; -pub const SMB_NTSTATUS_TRUSTED_RELATIONSHIP_FAILURE: u32 = 0xc000018d; -pub const SMB_NTSTATUS_EVENTLOG_FILE_CORRUPT: u32 = 0xc000018e; -pub const SMB_NTSTATUS_EVENTLOG_CANT_START: u32 = 0xc000018f; -pub const SMB_NTSTATUS_TRUST_FAILURE: u32 = 0xc0000190; -pub const SMB_NTSTATUS_MUTANT_LIMIT_EXCEEDED: u32 = 0xc0000191; -pub const SMB_NTSTATUS_NETLOGON_NOT_STARTED: u32 = 0xc0000192; -pub const SMB_NTSTATUS_ACCOUNT_EXPIRED: u32 = 0xc0000193; -pub const SMB_NTSTATUS_POSSIBLE_DEADLOCK: u32 = 0xc0000194; -pub const SMB_NTSTATUS_NETWORK_CREDENTIAL_CONFLICT: u32 = 0xc0000195; -pub const SMB_NTSTATUS_REMOTE_SESSION_LIMIT: u32 = 0xc0000196; -pub const SMB_NTSTATUS_EVENTLOG_FILE_CHANGED: u32 = 0xc0000197; -pub const SMB_NTSTATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: u32 = 0xc0000198; -pub const SMB_NTSTATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT: u32 = 0xc0000199; -pub const SMB_NTSTATUS_NOLOGON_SERVER_TRUST_ACCOUNT: u32 = 0xc000019a; -pub const SMB_NTSTATUS_DOMAIN_TRUST_INCONSISTENT: u32 = 0xc000019b; -pub const SMB_NTSTATUS_FS_DRIVER_REQUIRED: u32 = 0xc000019c; -pub const SMB_NTSTATUS_IMAGE_ALREADY_LOADED_AS_DLL: u32 = 0xc000019d; -pub const SMB_NTSTATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING: u32 = 0xc000019e; -pub const SMB_NTSTATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME: u32 = 0xc000019f; -pub const SMB_NTSTATUS_SECURITY_STREAM_IS_INCONSISTENT: u32 = 0xc00001a0; -pub const SMB_NTSTATUS_INVALID_LOCK_RANGE: u32 = 0xc00001a1; -pub const SMB_NTSTATUS_INVALID_ACE_CONDITION: u32 = 0xc00001a2; -pub const SMB_NTSTATUS_IMAGE_SUBSYSTEM_NOT_PRESENT: u32 = 0xc00001a3; -pub const SMB_NTSTATUS_NOTIFICATION_GUID_ALREADY_DEFINED: u32 = 0xc00001a4; -pub const SMB_NTSTATUS_NETWORK_OPEN_RESTRICTION: u32 = 0xc0000201; -pub const SMB_NTSTATUS_NO_USER_SESSION_KEY: u32 = 0xc0000202; -pub const SMB_NTSTATUS_USER_SESSION_DELETED: u32 = 0xc0000203; -pub const SMB_NTSTATUS_RESOURCE_LANG_NOT_FOUND: u32 = 0xc0000204; -pub const SMB_NTSTATUS_INSUFF_SERVER_RESOURCES: u32 = 0xc0000205; -pub const SMB_NTSTATUS_INVALID_BUFFER_SIZE: u32 = 0xc0000206; -pub const SMB_NTSTATUS_INVALID_ADDRESS_COMPONENT: u32 = 0xc0000207; -pub const SMB_NTSTATUS_INVALID_ADDRESS_WILDCARD: u32 = 0xc0000208; -pub const SMB_NTSTATUS_TOO_MANY_ADDRESSES: u32 = 0xc0000209; -pub const SMB_NTSTATUS_ADDRESS_ALREADY_EXISTS: u32 = 0xc000020a; -pub const SMB_NTSTATUS_ADDRESS_CLOSED: u32 = 0xc000020b; -pub const SMB_NTSTATUS_CONNECTION_DISCONNECTED: u32 = 0xc000020c; -pub const SMB_NTSTATUS_CONNECTION_RESET: u32 = 0xc000020d; -pub const SMB_NTSTATUS_TOO_MANY_NODES: u32 = 0xc000020e; -pub const SMB_NTSTATUS_TRANSACTION_ABORTED: u32 = 0xc000020f; -pub const SMB_NTSTATUS_TRANSACTION_TIMED_OUT: u32 = 0xc0000210; -pub const SMB_NTSTATUS_TRANSACTION_NO_RELEASE: u32 = 0xc0000211; -pub const SMB_NTSTATUS_TRANSACTION_NO_MATCH: u32 = 0xc0000212; -pub const SMB_NTSTATUS_TRANSACTION_RESPONDED: u32 = 0xc0000213; -pub const SMB_NTSTATUS_TRANSACTION_INVALID_ID: u32 = 0xc0000214; -pub const SMB_NTSTATUS_TRANSACTION_INVALID_TYPE: u32 = 0xc0000215; -pub const SMB_NTSTATUS_NOT_SERVER_SESSION: u32 = 0xc0000216; -pub const SMB_NTSTATUS_NOT_CLIENT_SESSION: u32 = 0xc0000217; -pub const SMB_NTSTATUS_CANNOT_LOAD_REGISTRY_FILE: u32 = 0xc0000218; -pub const SMB_NTSTATUS_DEBUG_ATTACH_FAILED: u32 = 0xc0000219; -pub const SMB_NTSTATUS_SYSTEM_PROCESS_TERMINATED: u32 = 0xc000021a; -pub const SMB_NTSTATUS_DATA_NOT_ACCEPTED: u32 = 0xc000021b; -pub const SMB_NTSTATUS_NO_BROWSER_SERVERS_FOUND: u32 = 0xc000021c; -pub const SMB_NTSTATUS_VDM_HARD_ERROR: u32 = 0xc000021d; -pub const SMB_NTSTATUS_DRIVER_CANCEL_TIMEOUT: u32 = 0xc000021e; -pub const SMB_NTSTATUS_REPLY_MESSAGE_MISMATCH: u32 = 0xc000021f; -pub const SMB_NTSTATUS_MAPPED_ALIGNMENT: u32 = 0xc0000220; -pub const SMB_NTSTATUS_IMAGE_CHECKSUM_MISMATCH: u32 = 0xc0000221; -pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA: u32 = 0xc0000222; -pub const SMB_NTSTATUS_CLIENT_SERVER_PARAMETERS_INVALID: u32 = 0xc0000223; -pub const SMB_NTSTATUS_PASSWORD_MUST_CHANGE: u32 = 0xc0000224; -pub const SMB_NTSTATUS_NOT_FOUND: u32 = 0xc0000225; -pub const SMB_NTSTATUS_NOT_TINY_STREAM: u32 = 0xc0000226; -pub const SMB_NTSTATUS_RECOVERY_FAILURE: u32 = 0xc0000227; -pub const SMB_NTSTATUS_STACK_OVERFLOW_READ: u32 = 0xc0000228; -pub const SMB_NTSTATUS_FAIL_CHECK: u32 = 0xc0000229; -pub const SMB_NTSTATUS_DUPLICATE_OBJECTID: u32 = 0xc000022a; -pub const SMB_NTSTATUS_OBJECTID_EXISTS: u32 = 0xc000022b; -pub const SMB_NTSTATUS_CONVERT_TO_LARGE: u32 = 0xc000022c; -pub const SMB_NTSTATUS_RETRY: u32 = 0xc000022d; -pub const SMB_NTSTATUS_FOUND_OUT_OF_SCOPE: u32 = 0xc000022e; -pub const SMB_NTSTATUS_ALLOCATE_BUCKET: u32 = 0xc000022f; -pub const SMB_NTSTATUS_PROPSET_NOT_FOUND: u32 = 0xc0000230; -pub const SMB_NTSTATUS_MARSHALL_OVERFLOW: u32 = 0xc0000231; -pub const SMB_NTSTATUS_INVALID_VARIANT: u32 = 0xc0000232; -pub const SMB_NTSTATUS_DOMAIN_CONTROLLER_NOT_FOUND: u32 = 0xc0000233; -pub const SMB_NTSTATUS_ACCOUNT_LOCKED_OUT: u32 = 0xc0000234; -pub const SMB_NTSTATUS_HANDLE_NOT_CLOSABLE: u32 = 0xc0000235; -pub const SMB_NTSTATUS_CONNECTION_REFUSED: u32 = 0xc0000236; -pub const SMB_NTSTATUS_GRACEFUL_DISCONNECT: u32 = 0xc0000237; -pub const SMB_NTSTATUS_ADDRESS_ALREADY_ASSOCIATED: u32 = 0xc0000238; -pub const SMB_NTSTATUS_ADDRESS_NOT_ASSOCIATED: u32 = 0xc0000239; -pub const SMB_NTSTATUS_CONNECTION_INVALID: u32 = 0xc000023a; -pub const SMB_NTSTATUS_CONNECTION_ACTIVE: u32 = 0xc000023b; -pub const SMB_NTSTATUS_NETWORK_UNREACHABLE: u32 = 0xc000023c; -pub const SMB_NTSTATUS_HOST_UNREACHABLE: u32 = 0xc000023d; -pub const SMB_NTSTATUS_PROTOCOL_UNREACHABLE: u32 = 0xc000023e; -pub const SMB_NTSTATUS_PORT_UNREACHABLE: u32 = 0xc000023f; -pub const SMB_NTSTATUS_REQUEST_ABORTED: u32 = 0xc0000240; -pub const SMB_NTSTATUS_CONNECTION_ABORTED: u32 = 0xc0000241; -pub const SMB_NTSTATUS_BAD_COMPRESSION_BUFFER: u32 = 0xc0000242; -pub const SMB_NTSTATUS_USER_MAPPED_FILE: u32 = 0xc0000243; -pub const SMB_NTSTATUS_AUDIT_FAILED: u32 = 0xc0000244; -pub const SMB_NTSTATUS_TIMER_RESOLUTION_NOT_SET: u32 = 0xc0000245; -pub const SMB_NTSTATUS_CONNECTION_COUNT_LIMIT: u32 = 0xc0000246; -pub const SMB_NTSTATUS_LOGIN_TIME_RESTRICTION: u32 = 0xc0000247; -pub const SMB_NTSTATUS_LOGIN_WKSTA_RESTRICTION: u32 = 0xc0000248; -pub const SMB_NTSTATUS_IMAGE_MP_UP_MISMATCH: u32 = 0xc0000249; -pub const SMB_NTSTATUS_INSUFFICIENT_LOGON_INFO: u32 = 0xc0000250; -pub const SMB_NTSTATUS_BAD_DLL_ENTRYPOINT: u32 = 0xc0000251; -pub const SMB_NTSTATUS_BAD_SERVICE_ENTRYPOINT: u32 = 0xc0000252; -pub const SMB_NTSTATUS_LPC_REPLY_LOST: u32 = 0xc0000253; -pub const SMB_NTSTATUS_IP_ADDRESS_CONFLICT1: u32 = 0xc0000254; -pub const SMB_NTSTATUS_IP_ADDRESS_CONFLICT2: u32 = 0xc0000255; -pub const SMB_NTSTATUS_REGISTRY_QUOTA_LIMIT: u32 = 0xc0000256; -pub const SMB_NTSTATUS_PATH_NOT_COVERED: u32 = 0xc0000257; -pub const SMB_NTSTATUS_NO_CALLBACK_ACTIVE: u32 = 0xc0000258; -pub const SMB_NTSTATUS_LICENSE_QUOTA_EXCEEDED: u32 = 0xc0000259; -pub const SMB_NTSTATUS_PWD_TOO_SHORT: u32 = 0xc000025a; -pub const SMB_NTSTATUS_PWD_TOO_RECENT: u32 = 0xc000025b; -pub const SMB_NTSTATUS_PWD_HISTORY_CONFLICT: u32 = 0xc000025c; -pub const SMB_NTSTATUS_PLUGPLAY_NO_DEVICE: u32 = 0xc000025e; -pub const SMB_NTSTATUS_UNSUPPORTED_COMPRESSION: u32 = 0xc000025f; -pub const SMB_NTSTATUS_INVALID_HW_PROFILE: u32 = 0xc0000260; -pub const SMB_NTSTATUS_INVALID_PLUGPLAY_DEVICE_PATH: u32 = 0xc0000261; -pub const SMB_NTSTATUS_DRIVER_ORDINAL_NOT_FOUND: u32 = 0xc0000262; -pub const SMB_NTSTATUS_DRIVER_ENTRYPOINT_NOT_FOUND: u32 = 0xc0000263; -pub const SMB_NTSTATUS_RESOURCE_NOT_OWNED: u32 = 0xc0000264; -pub const SMB_NTSTATUS_TOO_MANY_LINKS: u32 = 0xc0000265; -pub const SMB_NTSTATUS_QUOTA_LIST_INCONSISTENT: u32 = 0xc0000266; -pub const SMB_NTSTATUS_FILE_IS_OFFLINE: u32 = 0xc0000267; -pub const SMB_NTSTATUS_EVALUATION_EXPIRATION: u32 = 0xc0000268; -pub const SMB_NTSTATUS_ILLEGAL_DLL_RELOCATION: u32 = 0xc0000269; -pub const SMB_NTSTATUS_LICENSE_VIOLATION: u32 = 0xc000026a; -pub const SMB_NTSTATUS_DLL_INIT_FAILED_LOGOFF: u32 = 0xc000026b; -pub const SMB_NTSTATUS_DRIVER_UNABLE_TO_LOAD: u32 = 0xc000026c; -pub const SMB_NTSTATUS_DFS_UNAVAILABLE: u32 = 0xc000026d; -pub const SMB_NTSTATUS_VOLUME_DISMOUNTED: u32 = 0xc000026e; -pub const SMB_NTSTATUS_WX86_INTERNAL_ERROR: u32 = 0xc000026f; -pub const SMB_NTSTATUS_WX86_FLOAT_STACK_CHECK: u32 = 0xc0000270; -pub const SMB_NTSTATUS_VALIDATE_CONTINUE: u32 = 0xc0000271; -pub const SMB_NTSTATUS_NO_MATCH: u32 = 0xc0000272; -pub const SMB_NTSTATUS_NO_MORE_MATCHES: u32 = 0xc0000273; -pub const SMB_NTSTATUS_NOT_A_REPARSE_POINT: u32 = 0xc0000275; -pub const SMB_NTSTATUS_IO_REPARSE_TAG_INVALID: u32 = 0xc0000276; -pub const SMB_NTSTATUS_IO_REPARSE_TAG_MISMATCH: u32 = 0xc0000277; -pub const SMB_NTSTATUS_IO_REPARSE_DATA_INVALID: u32 = 0xc0000278; -pub const SMB_NTSTATUS_IO_REPARSE_TAG_NOT_HANDLED: u32 = 0xc0000279; -pub const SMB_NTSTATUS_REPARSE_POINT_NOT_RESOLVED: u32 = 0xc0000280; -pub const SMB_NTSTATUS_DIRECTORY_IS_A_REPARSE_POINT: u32 = 0xc0000281; -pub const SMB_NTSTATUS_RANGE_LIST_CONFLICT: u32 = 0xc0000282; -pub const SMB_NTSTATUS_SOURCE_ELEMENT_EMPTY: u32 = 0xc0000283; -pub const SMB_NTSTATUS_DESTINATION_ELEMENT_FULL: u32 = 0xc0000284; -pub const SMB_NTSTATUS_ILLEGAL_ELEMENT_ADDRESS: u32 = 0xc0000285; -pub const SMB_NTSTATUS_MAGAZINE_NOT_PRESENT: u32 = 0xc0000286; -pub const SMB_NTSTATUS_REINITIALIZATION_NEEDED: u32 = 0xc0000287; -pub const SMB_NTSTATUS_ENCRYPTION_FAILED: u32 = 0xc000028a; -pub const SMB_NTSTATUS_DECRYPTION_FAILED: u32 = 0xc000028b; -pub const SMB_NTSTATUS_RANGE_NOT_FOUND: u32 = 0xc000028c; -pub const SMB_NTSTATUS_NO_RECOVERY_POLICY: u32 = 0xc000028d; -pub const SMB_NTSTATUS_NO_EFS: u32 = 0xc000028e; -pub const SMB_NTSTATUS_WRONG_EFS: u32 = 0xc000028f; -pub const SMB_NTSTATUS_NO_USER_KEYS: u32 = 0xc0000290; -pub const SMB_NTSTATUS_FILE_NOT_ENCRYPTED: u32 = 0xc0000291; -pub const SMB_NTSTATUS_NOT_EXPORT_FORMAT: u32 = 0xc0000292; -pub const SMB_NTSTATUS_FILE_ENCRYPTED: u32 = 0xc0000293; -pub const SMB_NTSTATUS_WMI_GUID_NOT_FOUND: u32 = 0xc0000295; -pub const SMB_NTSTATUS_WMI_INSTANCE_NOT_FOUND: u32 = 0xc0000296; -pub const SMB_NTSTATUS_WMI_ITEMID_NOT_FOUND: u32 = 0xc0000297; -pub const SMB_NTSTATUS_WMI_TRY_AGAIN: u32 = 0xc0000298; -pub const SMB_NTSTATUS_SHARED_POLICY: u32 = 0xc0000299; -pub const SMB_NTSTATUS_POLICY_OBJECT_NOT_FOUND: u32 = 0xc000029a; -pub const SMB_NTSTATUS_POLICY_ONLY_IN_DS: u32 = 0xc000029b; -pub const SMB_NTSTATUS_VOLUME_NOT_UPGRADED: u32 = 0xc000029c; -pub const SMB_NTSTATUS_REMOTE_STORAGE_NOT_ACTIVE: u32 = 0xc000029d; -pub const SMB_NTSTATUS_REMOTE_STORAGE_MEDIA_ERROR: u32 = 0xc000029e; -pub const SMB_NTSTATUS_NO_TRACKING_SERVICE: u32 = 0xc000029f; -pub const SMB_NTSTATUS_SERVER_SID_MISMATCH: u32 = 0xc00002a0; -pub const SMB_NTSTATUS_DS_NO_ATTRIBUTE_OR_VALUE: u32 = 0xc00002a1; -pub const SMB_NTSTATUS_DS_INVALID_ATTRIBUTE_SYNTAX: u32 = 0xc00002a2; -pub const SMB_NTSTATUS_DS_ATTRIBUTE_TYPE_UNDEFINED: u32 = 0xc00002a3; -pub const SMB_NTSTATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS: u32 = 0xc00002a4; -pub const SMB_NTSTATUS_DS_BUSY: u32 = 0xc00002a5; -pub const SMB_NTSTATUS_DS_UNAVAILABLE: u32 = 0xc00002a6; -pub const SMB_NTSTATUS_DS_NO_RIDS_ALLOCATED: u32 = 0xc00002a7; -pub const SMB_NTSTATUS_DS_NO_MORE_RIDS: u32 = 0xc00002a8; -pub const SMB_NTSTATUS_DS_INCORRECT_ROLE_OWNER: u32 = 0xc00002a9; -pub const SMB_NTSTATUS_DS_RIDMGR_INIT_ERROR: u32 = 0xc00002aa; -pub const SMB_NTSTATUS_DS_OBJ_CLASS_VIOLATION: u32 = 0xc00002ab; -pub const SMB_NTSTATUS_DS_CANT_ON_NON_LEAF: u32 = 0xc00002ac; -pub const SMB_NTSTATUS_DS_CANT_ON_RDN: u32 = 0xc00002ad; -pub const SMB_NTSTATUS_DS_CANT_MOD_OBJ_CLASS: u32 = 0xc00002ae; -pub const SMB_NTSTATUS_DS_CROSS_DOM_MOVE_FAILED: u32 = 0xc00002af; -pub const SMB_NTSTATUS_DS_GC_NOT_AVAILABLE: u32 = 0xc00002b0; -pub const SMB_NTSTATUS_DIRECTORY_SERVICE_REQUIRED: u32 = 0xc00002b1; -pub const SMB_NTSTATUS_REPARSE_ATTRIBUTE_CONFLICT: u32 = 0xc00002b2; -pub const SMB_NTSTATUS_CANT_ENABLE_DENY_ONLY: u32 = 0xc00002b3; -pub const SMB_NTSTATUS_FLOAT_MULTIPLE_FAULTS: u32 = 0xc00002b4; -pub const SMB_NTSTATUS_FLOAT_MULTIPLE_TRAPS: u32 = 0xc00002b5; -pub const SMB_NTSTATUS_DEVICE_REMOVED: u32 = 0xc00002b6; -pub const SMB_NTSTATUS_JOURNAL_DELETE_IN_PROGRESS: u32 = 0xc00002b7; -pub const SMB_NTSTATUS_JOURNAL_NOT_ACTIVE: u32 = 0xc00002b8; -pub const SMB_NTSTATUS_NOINTERFACE: u32 = 0xc00002b9; -pub const SMB_NTSTATUS_DS_ADMIN_LIMIT_EXCEEDED: u32 = 0xc00002c1; -pub const SMB_NTSTATUS_DRIVER_FAILED_SLEEP: u32 = 0xc00002c2; -pub const SMB_NTSTATUS_MUTUAL_AUTHENTICATION_FAILED: u32 = 0xc00002c3; -pub const SMB_NTSTATUS_CORRUPT_SYSTEM_FILE: u32 = 0xc00002c4; -pub const SMB_NTSTATUS_DATATYPE_MISALIGNMENT_ERROR: u32 = 0xc00002c5; -pub const SMB_NTSTATUS_WMI_READ_ONLY: u32 = 0xc00002c6; -pub const SMB_NTSTATUS_WMI_SET_FAILURE: u32 = 0xc00002c7; -pub const SMB_NTSTATUS_COMMITMENT_MINIMUM: u32 = 0xc00002c8; -pub const SMB_NTSTATUS_REG_NAT_CONSUMPTION: u32 = 0xc00002c9; -pub const SMB_NTSTATUS_TRANSPORT_FULL: u32 = 0xc00002ca; -pub const SMB_NTSTATUS_DS_SAM_INIT_FAILURE: u32 = 0xc00002cb; -pub const SMB_NTSTATUS_ONLY_IF_CONNECTED: u32 = 0xc00002cc; -pub const SMB_NTSTATUS_DS_SENSITIVE_GROUP_VIOLATION: u32 = 0xc00002cd; -pub const SMB_NTSTATUS_PNP_RESTART_ENUMERATION: u32 = 0xc00002ce; -pub const SMB_NTSTATUS_JOURNAL_ENTRY_DELETED: u32 = 0xc00002cf; -pub const SMB_NTSTATUS_DS_CANT_MOD_PRIMARYGROUPID: u32 = 0xc00002d0; -pub const SMB_NTSTATUS_SYSTEM_IMAGE_BAD_SIGNATURE: u32 = 0xc00002d1; -pub const SMB_NTSTATUS_PNP_REBOOT_REQUIRED: u32 = 0xc00002d2; -pub const SMB_NTSTATUS_POWER_STATE_INVALID: u32 = 0xc00002d3; -pub const SMB_NTSTATUS_DS_INVALID_GROUP_TYPE: u32 = 0xc00002d4; -pub const SMB_NTSTATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN: u32 = 0xc00002d5; -pub const SMB_NTSTATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN: u32 = 0xc00002d6; -pub const SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER: u32 = 0xc00002d7; -pub const SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER: u32 = 0xc00002d8; -pub const SMB_NTSTATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER: u32 = 0xc00002d9; -pub const SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER: u32 = 0xc00002da; -pub const SMB_NTSTATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER: u32 = 0xc00002db; -pub const SMB_NTSTATUS_DS_HAVE_PRIMARY_MEMBERS: u32 = 0xc00002dc; -pub const SMB_NTSTATUS_WMI_NOT_SUPPORTED: u32 = 0xc00002dd; -pub const SMB_NTSTATUS_INSUFFICIENT_POWER: u32 = 0xc00002de; -pub const SMB_NTSTATUS_SAM_NEED_BOOTKEY_PASSWORD: u32 = 0xc00002df; -pub const SMB_NTSTATUS_SAM_NEED_BOOTKEY_FLOPPY: u32 = 0xc00002e0; -pub const SMB_NTSTATUS_DS_CANT_START: u32 = 0xc00002e1; -pub const SMB_NTSTATUS_DS_INIT_FAILURE: u32 = 0xc00002e2; -pub const SMB_NTSTATUS_SAM_INIT_FAILURE: u32 = 0xc00002e3; -pub const SMB_NTSTATUS_DS_GC_REQUIRED: u32 = 0xc00002e4; -pub const SMB_NTSTATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY: u32 = 0xc00002e5; -pub const SMB_NTSTATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS: u32 = 0xc00002e6; -pub const SMB_NTSTATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED: u32 = 0xc00002e7; -pub const SMB_NTSTATUS_CURRENT_DOMAIN_NOT_ALLOWED: u32 = 0xc00002e9; -pub const SMB_NTSTATUS_CANNOT_MAKE: u32 = 0xc00002ea; -pub const SMB_NTSTATUS_SYSTEM_SHUTDOWN: u32 = 0xc00002eb; -pub const SMB_NTSTATUS_DS_INIT_FAILURE_CONSOLE: u32 = 0xc00002ec; -pub const SMB_NTSTATUS_DS_SAM_INIT_FAILURE_CONSOLE: u32 = 0xc00002ed; -pub const SMB_NTSTATUS_UNFINISHED_CONTEXT_DELETED: u32 = 0xc00002ee; -pub const SMB_NTSTATUS_NO_TGT_REPLY: u32 = 0xc00002ef; -pub const SMB_NTSTATUS_OBJECTID_NOT_FOUND: u32 = 0xc00002f0; -pub const SMB_NTSTATUS_NO_IP_ADDRESSES: u32 = 0xc00002f1; -pub const SMB_NTSTATUS_WRONG_CREDENTIAL_HANDLE: u32 = 0xc00002f2; -pub const SMB_NTSTATUS_CRYPTO_SYSTEM_INVALID: u32 = 0xc00002f3; -pub const SMB_NTSTATUS_MAX_REFERRALS_EXCEEDED: u32 = 0xc00002f4; -pub const SMB_NTSTATUS_MUST_BE_KDC: u32 = 0xc00002f5; -pub const SMB_NTSTATUS_STRONG_CRYPTO_NOT_SUPPORTED: u32 = 0xc00002f6; -pub const SMB_NTSTATUS_TOO_MANY_PRINCIPALS: u32 = 0xc00002f7; -pub const SMB_NTSTATUS_NO_PA_DATA: u32 = 0xc00002f8; -pub const SMB_NTSTATUS_PKINIT_NAME_MISMATCH: u32 = 0xc00002f9; -pub const SMB_NTSTATUS_SMARTCARD_LOGON_REQUIRED: u32 = 0xc00002fa; -pub const SMB_NTSTATUS_KDC_INVALID_REQUEST: u32 = 0xc00002fb; -pub const SMB_NTSTATUS_KDC_UNABLE_TO_REFER: u32 = 0xc00002fc; -pub const SMB_NTSTATUS_KDC_UNKNOWN_ETYPE: u32 = 0xc00002fd; -pub const SMB_NTSTATUS_SHUTDOWN_IN_PROGRESS: u32 = 0xc00002fe; -pub const SMB_NTSTATUS_SERVER_SHUTDOWN_IN_PROGRESS: u32 = 0xc00002ff; -pub const SMB_NTSTATUS_NOT_SUPPORTED_ON_SBS: u32 = 0xc0000300; -pub const SMB_NTSTATUS_WMI_GUID_DISCONNECTED: u32 = 0xc0000301; -pub const SMB_NTSTATUS_WMI_ALREADY_DISABLED: u32 = 0xc0000302; -pub const SMB_NTSTATUS_WMI_ALREADY_ENABLED: u32 = 0xc0000303; -pub const SMB_NTSTATUS_MFT_TOO_FRAGMENTED: u32 = 0xc0000304; -pub const SMB_NTSTATUS_COPY_PROTECTION_FAILURE: u32 = 0xc0000305; -pub const SMB_NTSTATUS_CSS_AUTHENTICATION_FAILURE: u32 = 0xc0000306; -pub const SMB_NTSTATUS_CSS_KEY_NOT_PRESENT: u32 = 0xc0000307; -pub const SMB_NTSTATUS_CSS_KEY_NOT_ESTABLISHED: u32 = 0xc0000308; -pub const SMB_NTSTATUS_CSS_SCRAMBLED_SECTOR: u32 = 0xc0000309; -pub const SMB_NTSTATUS_CSS_REGION_MISMATCH: u32 = 0xc000030a; -pub const SMB_NTSTATUS_CSS_RESETS_EXHAUSTED: u32 = 0xc000030b; -pub const SMB_NTSTATUS_PKINIT_FAILURE: u32 = 0xc0000320; -pub const SMB_NTSTATUS_SMARTCARD_SUBSYSTEM_FAILURE: u32 = 0xc0000321; -pub const SMB_NTSTATUS_NO_KERB_KEY: u32 = 0xc0000322; -pub const SMB_NTSTATUS_HOST_DOWN: u32 = 0xc0000350; -pub const SMB_NTSTATUS_UNSUPPORTED_PREAUTH: u32 = 0xc0000351; -pub const SMB_NTSTATUS_EFS_ALG_BLOB_TOO_BIG: u32 = 0xc0000352; -pub const SMB_NTSTATUS_PORT_NOT_SET: u32 = 0xc0000353; -pub const SMB_NTSTATUS_DEBUGGER_INACTIVE: u32 = 0xc0000354; -pub const SMB_NTSTATUS_DS_VERSION_CHECK_FAILURE: u32 = 0xc0000355; -pub const SMB_NTSTATUS_AUDITING_DISABLED: u32 = 0xc0000356; -pub const SMB_NTSTATUS_PRENT4_MACHINE_ACCOUNT: u32 = 0xc0000357; -pub const SMB_NTSTATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER: u32 = 0xc0000358; -pub const SMB_NTSTATUS_INVALID_IMAGE_WIN_32: u32 = 0xc0000359; -pub const SMB_NTSTATUS_INVALID_IMAGE_WIN_64: u32 = 0xc000035a; -pub const SMB_NTSTATUS_BAD_BINDINGS: u32 = 0xc000035b; -pub const SMB_NTSTATUS_NETWORK_SESSION_EXPIRED: u32 = 0xc000035c; -pub const SMB_NTSTATUS_APPHELP_BLOCK: u32 = 0xc000035d; -pub const SMB_NTSTATUS_ALL_SIDS_FILTERED: u32 = 0xc000035e; -pub const SMB_NTSTATUS_NOT_SAFE_MODE_DRIVER: u32 = 0xc000035f; -pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT: u32 = 0xc0000361; -pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PATH: u32 = 0xc0000362; -pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER: u32 = 0xc0000363; -pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_OTHER: u32 = 0xc0000364; -pub const SMB_NTSTATUS_FAILED_DRIVER_ENTRY: u32 = 0xc0000365; -pub const SMB_NTSTATUS_DEVICE_ENUMERATION_ERROR: u32 = 0xc0000366; -pub const SMB_NTSTATUS_MOUNT_POINT_NOT_RESOLVED: u32 = 0xc0000368; -pub const SMB_NTSTATUS_INVALID_DEVICE_OBJECT_PARAMETER: u32 = 0xc0000369; -pub const SMB_NTSTATUS_MCA_OCCURED: u32 = 0xc000036a; -pub const SMB_NTSTATUS_DRIVER_BLOCKED_CRITICAL: u32 = 0xc000036b; -pub const SMB_NTSTATUS_DRIVER_BLOCKED: u32 = 0xc000036c; -pub const SMB_NTSTATUS_DRIVER_DATABASE_ERROR: u32 = 0xc000036d; -pub const SMB_NTSTATUS_SYSTEM_HIVE_TOO_LARGE: u32 = 0xc000036e; -pub const SMB_NTSTATUS_INVALID_IMPORT_OF_NON_DLL: u32 = 0xc000036f; -pub const SMB_NTSTATUS_NO_SECRETS: u32 = 0xc0000371; -pub const SMB_NTSTATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY: u32 = 0xc0000372; -pub const SMB_NTSTATUS_FAILED_STACK_SWITCH: u32 = 0xc0000373; -pub const SMB_NTSTATUS_HEAP_CORRUPTION: u32 = 0xc0000374; -pub const SMB_NTSTATUS_SMARTCARD_WRONG_PIN: u32 = 0xc0000380; -pub const SMB_NTSTATUS_SMARTCARD_CARD_BLOCKED: u32 = 0xc0000381; -pub const SMB_NTSTATUS_SMARTCARD_CARD_NOT_AUTHENTICATED: u32 = 0xc0000382; -pub const SMB_NTSTATUS_SMARTCARD_NO_CARD: u32 = 0xc0000383; -pub const SMB_NTSTATUS_SMARTCARD_NO_KEY_CONTAINER: u32 = 0xc0000384; -pub const SMB_NTSTATUS_SMARTCARD_NO_CERTIFICATE: u32 = 0xc0000385; -pub const SMB_NTSTATUS_SMARTCARD_NO_KEYSET: u32 = 0xc0000386; -pub const SMB_NTSTATUS_SMARTCARD_IO_ERROR: u32 = 0xc0000387; -pub const SMB_NTSTATUS_DOWNGRADE_DETECTED: u32 = 0xc0000388; -pub const SMB_NTSTATUS_SMARTCARD_CERT_REVOKED: u32 = 0xc0000389; -pub const SMB_NTSTATUS_ISSUING_CA_UNTRUSTED: u32 = 0xc000038a; -pub const SMB_NTSTATUS_REVOCATION_OFFLINE_C: u32 = 0xc000038b; -pub const SMB_NTSTATUS_PKINIT_CLIENT_FAILURE: u32 = 0xc000038c; -pub const SMB_NTSTATUS_SMARTCARD_CERT_EXPIRED: u32 = 0xc000038d; -pub const SMB_NTSTATUS_DRIVER_FAILED_PRIOR_UNLOAD: u32 = 0xc000038e; -pub const SMB_NTSTATUS_SMARTCARD_SILENT_CONTEXT: u32 = 0xc000038f; -pub const SMB_NTSTATUS_PER_USER_TRUST_QUOTA_EXCEEDED: u32 = 0xc0000401; -pub const SMB_NTSTATUS_ALL_USER_TRUST_QUOTA_EXCEEDED: u32 = 0xc0000402; -pub const SMB_NTSTATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED: u32 = 0xc0000403; -pub const SMB_NTSTATUS_DS_NAME_NOT_UNIQUE: u32 = 0xc0000404; -pub const SMB_NTSTATUS_DS_DUPLICATE_ID_FOUND: u32 = 0xc0000405; -pub const SMB_NTSTATUS_DS_GROUP_CONVERSION_ERROR: u32 = 0xc0000406; -pub const SMB_NTSTATUS_VOLSNAP_PREPARE_HIBERNATE: u32 = 0xc0000407; -pub const SMB_NTSTATUS_USER2USER_REQUIRED: u32 = 0xc0000408; -pub const SMB_NTSTATUS_STACK_BUFFER_OVERRUN: u32 = 0xc0000409; -pub const SMB_NTSTATUS_NO_S4U_PROT_SUPPORT: u32 = 0xc000040a; -pub const SMB_NTSTATUS_CROSSREALM_DELEGATION_FAILURE: u32 = 0xc000040b; -pub const SMB_NTSTATUS_REVOCATION_OFFLINE_KDC: u32 = 0xc000040c; -pub const SMB_NTSTATUS_ISSUING_CA_UNTRUSTED_KDC: u32 = 0xc000040d; -pub const SMB_NTSTATUS_KDC_CERT_EXPIRED: u32 = 0xc000040e; -pub const SMB_NTSTATUS_KDC_CERT_REVOKED: u32 = 0xc000040f; -pub const SMB_NTSTATUS_PARAMETER_QUOTA_EXCEEDED: u32 = 0xc0000410; -pub const SMB_NTSTATUS_HIBERNATION_FAILURE: u32 = 0xc0000411; -pub const SMB_NTSTATUS_DELAY_LOAD_FAILED: u32 = 0xc0000412; -pub const SMB_NTSTATUS_AUTHENTICATION_FIREWALL_FAILED: u32 = 0xc0000413; -pub const SMB_NTSTATUS_VDM_DISALLOWED: u32 = 0xc0000414; -pub const SMB_NTSTATUS_HUNG_DISPLAY_DRIVER_THREAD: u32 = 0xc0000415; -pub const SMB_NTSTATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE: u32 = 0xc0000416; -pub const SMB_NTSTATUS_INVALID_CRUNTIME_PARAMETER: u32 = 0xc0000417; -pub const SMB_NTSTATUS_NTLM_BLOCKED: u32 = 0xc0000418; -pub const SMB_NTSTATUS_DS_SRC_SID_EXISTS_IN_FOREST: u32 = 0xc0000419; -pub const SMB_NTSTATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST: u32 = 0xc000041a; -pub const SMB_NTSTATUS_DS_FLAT_NAME_EXISTS_IN_FOREST: u32 = 0xc000041b; -pub const SMB_NTSTATUS_INVALID_USER_PRINCIPAL_NAME: u32 = 0xc000041c; -pub const SMB_NTSTATUS_ASSERTION_FAILURE: u32 = 0xc0000420; -pub const SMB_NTSTATUS_VERIFIER_STOP: u32 = 0xc0000421; -pub const SMB_NTSTATUS_CALLBACK_POP_STACK: u32 = 0xc0000423; -pub const SMB_NTSTATUS_INCOMPATIBLE_DRIVER_BLOCKED: u32 = 0xc0000424; -pub const SMB_NTSTATUS_HIVE_UNLOADED: u32 = 0xc0000425; -pub const SMB_NTSTATUS_COMPRESSION_DISABLED: u32 = 0xc0000426; -pub const SMB_NTSTATUS_FILE_SYSTEM_LIMITATION: u32 = 0xc0000427; -pub const SMB_NTSTATUS_INVALID_IMAGE_HASH: u32 = 0xc0000428; -pub const SMB_NTSTATUS_NOT_CAPABLE: u32 = 0xc0000429; -pub const SMB_NTSTATUS_REQUEST_OUT_OF_SEQUENCE: u32 = 0xc000042a; -pub const SMB_NTSTATUS_IMPLEMENTATION_LIMIT: u32 = 0xc000042b; -pub const SMB_NTSTATUS_ELEVATION_REQUIRED: u32 = 0xc000042c; -pub const SMB_NTSTATUS_NO_SECURITY_CONTEXT: u32 = 0xc000042d; -pub const SMB_NTSTATUS_PKU2U_CERT_FAILURE: u32 = 0xc000042e; -pub const SMB_NTSTATUS_BEYOND_VDL: u32 = 0xc0000432; -pub const SMB_NTSTATUS_ENCOUNTERED_WRITE_IN_PROGRESS: u32 = 0xc0000433; -pub const SMB_NTSTATUS_PTE_CHANGED: u32 = 0xc0000434; -pub const SMB_NTSTATUS_PURGE_FAILED: u32 = 0xc0000435; -pub const SMB_NTSTATUS_CRED_REQUIRES_CONFIRMATION: u32 = 0xc0000440; -pub const SMB_NTSTATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE: u32 = 0xc0000441; -pub const SMB_NTSTATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER: u32 = 0xc0000442; -pub const SMB_NTSTATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE: u32 = 0xc0000443; -pub const SMB_NTSTATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE: u32 = 0xc0000444; -pub const SMB_NTSTATUS_CS_ENCRYPTION_FILE_NOT_CSE: u32 = 0xc0000445; -pub const SMB_NTSTATUS_INVALID_LABEL: u32 = 0xc0000446; -pub const SMB_NTSTATUS_DRIVER_PROCESS_TERMINATED: u32 = 0xc0000450; -pub const SMB_NTSTATUS_AMBIGUOUS_SYSTEM_DEVICE: u32 = 0xc0000451; -pub const SMB_NTSTATUS_SYSTEM_DEVICE_NOT_FOUND: u32 = 0xc0000452; -pub const SMB_NTSTATUS_RESTART_BOOT_APPLICATION: u32 = 0xc0000453; -pub const SMB_NTSTATUS_INSUFFICIENT_NVRAM_RESOURCES: u32 = 0xc0000454; -pub const SMB_NTSTATUS_NO_RANGES_PROCESSED: u32 = 0xc0000460; -pub const SMB_NTSTATUS_DEVICE_FEATURE_NOT_SUPPORTED: u32 = 0xc0000463; -pub const SMB_NTSTATUS_DEVICE_UNREACHABLE: u32 = 0xc0000464; -pub const SMB_NTSTATUS_INVALID_TOKEN: u32 = 0xc0000465; -pub const SMB_NTSTATUS_SERVER_UNAVAILABLE: u32 = 0xc0000466; -pub const SMB_NTSTATUS_INVALID_TASK_NAME: u32 = 0xc0000500; -pub const SMB_NTSTATUS_INVALID_TASK_INDEX: u32 = 0xc0000501; -pub const SMB_NTSTATUS_THREAD_ALREADY_IN_TASK: u32 = 0xc0000502; -pub const SMB_NTSTATUS_CALLBACK_BYPASS: u32 = 0xc0000503; -pub const SMB_NTSTATUS_FAIL_FAST_EXCEPTION: u32 = 0xc0000602; -pub const SMB_NTSTATUS_IMAGE_CERT_REVOKED: u32 = 0xc0000603; -pub const SMB_NTSTATUS_PORT_CLOSED: u32 = 0xc0000700; -pub const SMB_NTSTATUS_MESSAGE_LOST: u32 = 0xc0000701; -pub const SMB_NTSTATUS_INVALID_MESSAGE: u32 = 0xc0000702; -pub const SMB_NTSTATUS_REQUEST_CANCELED: u32 = 0xc0000703; -pub const SMB_NTSTATUS_RECURSIVE_DISPATCH: u32 = 0xc0000704; -pub const SMB_NTSTATUS_LPC_RECEIVE_BUFFER_EXPECTED: u32 = 0xc0000705; -pub const SMB_NTSTATUS_LPC_INVALID_CONNECTION_USAGE: u32 = 0xc0000706; -pub const SMB_NTSTATUS_LPC_REQUESTS_NOT_ALLOWED: u32 = 0xc0000707; -pub const SMB_NTSTATUS_RESOURCE_IN_USE: u32 = 0xc0000708; -pub const SMB_NTSTATUS_HARDWARE_MEMORY_ERROR: u32 = 0xc0000709; -pub const SMB_NTSTATUS_THREADPOOL_HANDLE_EXCEPTION: u32 = 0xc000070a; -pub const SMB_NTSTATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED: u32 = 0xc000070b; -pub const SMB_NTSTATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED: u32 = 0xc000070c; -pub const SMB_NTSTATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED: u32 = 0xc000070d; -pub const SMB_NTSTATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED: u32 = 0xc000070e; -pub const SMB_NTSTATUS_THREADPOOL_RELEASED_DURING_OPERATION: u32 = 0xc000070f; -pub const SMB_NTSTATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING: u32 = 0xc0000710; -pub const SMB_NTSTATUS_APC_RETURNED_WHILE_IMPERSONATING: u32 = 0xc0000711; -pub const SMB_NTSTATUS_PROCESS_IS_PROTECTED: u32 = 0xc0000712; -pub const SMB_NTSTATUS_MCA_EXCEPTION: u32 = 0xc0000713; -pub const SMB_NTSTATUS_CERTIFICATE_MAPPING_NOT_UNIQUE: u32 = 0xc0000714; -pub const SMB_NTSTATUS_SYMLINK_CLASS_DISABLED: u32 = 0xc0000715; -pub const SMB_NTSTATUS_INVALID_IDN_NORMALIZATION: u32 = 0xc0000716; -pub const SMB_NTSTATUS_NO_UNICODE_TRANSLATION: u32 = 0xc0000717; -pub const SMB_NTSTATUS_ALREADY_REGISTERED: u32 = 0xc0000718; -pub const SMB_NTSTATUS_CONTEXT_MISMATCH: u32 = 0xc0000719; -pub const SMB_NTSTATUS_PORT_ALREADY_HAS_COMPLETION_LIST: u32 = 0xc000071a; -pub const SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_PRIORITY: u32 = 0xc000071b; -pub const SMB_NTSTATUS_INVALID_THREAD: u32 = 0xc000071c; -pub const SMB_NTSTATUS_CALLBACK_RETURNED_TRANSACTION: u32 = 0xc000071d; -pub const SMB_NTSTATUS_CALLBACK_RETURNED_LDR_LOCK: u32 = 0xc000071e; -pub const SMB_NTSTATUS_CALLBACK_RETURNED_LANG: u32 = 0xc000071f; -pub const SMB_NTSTATUS_CALLBACK_RETURNED_PRI_BACK: u32 = 0xc0000720; -pub const SMB_NTSTATUS_DISK_REPAIR_DISABLED: u32 = 0xc0000800; -pub const SMB_NTSTATUS_DS_DOMAIN_RENAME_IN_PROGRESS: u32 = 0xc0000801; -pub const SMB_NTSTATUS_DISK_QUOTA_EXCEEDED: u32 = 0xc0000802; -pub const SMB_NTSTATUS_CONTENT_BLOCKED: u32 = 0xc0000804; -pub const SMB_NTSTATUS_BAD_CLUSTERS: u32 = 0xc0000805; -pub const SMB_NTSTATUS_VOLUME_DIRTY: u32 = 0xc0000806; -pub const SMB_NTSTATUS_FILE_CHECKED_OUT: u32 = 0xc0000901; -pub const SMB_NTSTATUS_CHECKOUT_REQUIRED: u32 = 0xc0000902; -pub const SMB_NTSTATUS_BAD_FILE_TYPE: u32 = 0xc0000903; -pub const SMB_NTSTATUS_FILE_TOO_LARGE: u32 = 0xc0000904; -pub const SMB_NTSTATUS_FORMS_AUTH_REQUIRED: u32 = 0xc0000905; -pub const SMB_NTSTATUS_VIRUS_INFECTED: u32 = 0xc0000906; -pub const SMB_NTSTATUS_VIRUS_DELETED: u32 = 0xc0000907; -pub const SMB_NTSTATUS_BAD_MCFG_TABLE: u32 = 0xc0000908; -pub const SMB_NTSTATUS_CANNOT_BREAK_OPLOCK: u32 = 0xc0000909; -pub const SMB_NTSTATUS_WOW_ASSERTION: u32 = 0xc0009898; -pub const SMB_NTSTATUS_INVALID_SIGNATURE: u32 = 0xc000a000; -pub const SMB_NTSTATUS_HMAC_NOT_SUPPORTED: u32 = 0xc000a001; -pub const SMB_NTSTATUS_IPSEC_QUEUE_OVERFLOW: u32 = 0xc000a010; -pub const SMB_NTSTATUS_ND_QUEUE_OVERFLOW: u32 = 0xc000a011; -pub const SMB_NTSTATUS_HOPLIMIT_EXCEEDED: u32 = 0xc000a012; -pub const SMB_NTSTATUS_PROTOCOL_NOT_SUPPORTED: u32 = 0xc000a013; -pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED: u32 = 0xc000a080; -pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR: u32 = 0xc000a081; -pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR: u32 = 0xc000a082; -pub const SMB_NTSTATUS_XML_PARSE_ERROR: u32 = 0xc000a083; -pub const SMB_NTSTATUS_XMLDSIG_ERROR: u32 = 0xc000a084; -pub const SMB_NTSTATUS_WRONG_COMPARTMENT: u32 = 0xc000a085; -pub const SMB_NTSTATUS_AUTHIP_FAILURE: u32 = 0xc000a086; -pub const SMB_NTSTATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS: u32 = 0xc000a087; -pub const SMB_NTSTATUS_DS_OID_NOT_FOUND: u32 = 0xc000a088; -pub const SMB_NTSTATUS_HASH_NOT_SUPPORTED: u32 = 0xc000a100; -pub const SMB_NTSTATUS_HASH_NOT_PRESENT: u32 = 0xc000a101; -pub const SMB_NTSTATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED: u32 = 0xc000a2a1; -pub const SMB_NTSTATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED: u32 = 0xc000a2a2; -pub const SMB_NTSTATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED: u32 = 0xc000a2a3; -pub const SMB_NTSTATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED: u32 = 0xc000a2a4; -pub const SMB_NTDBG_NO_STATE_CHANGE: u32 = 0xc0010001; -pub const SMB_NTDBG_APP_NOT_IDLE: u32 = 0xc0010002; -pub const SMB_NTRPC_NT_INVALID_STRING_BINDING: u32 = 0xc0020001; -pub const SMB_NTRPC_NT_WRONG_KIND_OF_BINDING: u32 = 0xc0020002; -pub const SMB_NTRPC_NT_INVALID_BINDING: u32 = 0xc0020003; -pub const SMB_NTRPC_NT_PROTSEQ_NOT_SUPPORTED: u32 = 0xc0020004; -pub const SMB_NTRPC_NT_INVALID_RPC_PROTSEQ: u32 = 0xc0020005; -pub const SMB_NTRPC_NT_INVALID_STRING_UUID: u32 = 0xc0020006; -pub const SMB_NTRPC_NT_INVALID_ENDPOINT_FORMAT: u32 = 0xc0020007; -pub const SMB_NTRPC_NT_INVALID_NET_ADDR: u32 = 0xc0020008; -pub const SMB_NTRPC_NT_NO_ENDPOINT_FOUND: u32 = 0xc0020009; -pub const SMB_NTRPC_NT_INVALID_TIMEOUT: u32 = 0xc002000a; -pub const SMB_NTRPC_NT_OBJECT_NOT_FOUND: u32 = 0xc002000b; -pub const SMB_NTRPC_NT_ALREADY_REGISTERED: u32 = 0xc002000c; -pub const SMB_NTRPC_NT_TYPE_ALREADY_REGISTERED: u32 = 0xc002000d; -pub const SMB_NTRPC_NT_ALREADY_LISTENING: u32 = 0xc002000e; -pub const SMB_NTRPC_NT_NO_PROTSEQS_REGISTERED: u32 = 0xc002000f; -pub const SMB_NTRPC_NT_NOT_LISTENING: u32 = 0xc0020010; -pub const SMB_NTRPC_NT_UNKNOWN_MGR_TYPE: u32 = 0xc0020011; -pub const SMB_NTRPC_NT_UNKNOWN_IF: u32 = 0xc0020012; -pub const SMB_NTRPC_NT_NO_BINDINGS: u32 = 0xc0020013; -pub const SMB_NTRPC_NT_NO_PROTSEQS: u32 = 0xc0020014; -pub const SMB_NTRPC_NT_CANT_CREATE_ENDPOINT: u32 = 0xc0020015; -pub const SMB_NTRPC_NT_OUT_OF_RESOURCES: u32 = 0xc0020016; -pub const SMB_NTRPC_NT_SERVER_UNAVAILABLE: u32 = 0xc0020017; -pub const SMB_NTRPC_NT_SERVER_TOO_BUSY: u32 = 0xc0020018; -pub const SMB_NTRPC_NT_INVALID_NETWORK_OPTIONS: u32 = 0xc0020019; -pub const SMB_NTRPC_NT_NO_CALL_ACTIVE: u32 = 0xc002001a; -pub const SMB_NTRPC_NT_CALL_FAILED: u32 = 0xc002001b; -pub const SMB_NTRPC_NT_CALL_FAILED_DNE: u32 = 0xc002001c; -pub const SMB_NTRPC_NT_PROTOCOL_ERROR: u32 = 0xc002001d; -pub const SMB_NTRPC_NT_UNSUPPORTED_TRANS_SYN: u32 = 0xc002001f; -pub const SMB_NTRPC_NT_UNSUPPORTED_TYPE: u32 = 0xc0020021; -pub const SMB_NTRPC_NT_INVALID_TAG: u32 = 0xc0020022; -pub const SMB_NTRPC_NT_INVALID_BOUND: u32 = 0xc0020023; -pub const SMB_NTRPC_NT_NO_ENTRY_NAME: u32 = 0xc0020024; -pub const SMB_NTRPC_NT_INVALID_NAME_SYNTAX: u32 = 0xc0020025; -pub const SMB_NTRPC_NT_UNSUPPORTED_NAME_SYNTAX: u32 = 0xc0020026; -pub const SMB_NTRPC_NT_UUID_NO_ADDRESS: u32 = 0xc0020028; -pub const SMB_NTRPC_NT_DUPLICATE_ENDPOINT: u32 = 0xc0020029; -pub const SMB_NTRPC_NT_UNKNOWN_AUTHN_TYPE: u32 = 0xc002002a; -pub const SMB_NTRPC_NT_MAX_CALLS_TOO_SMALL: u32 = 0xc002002b; -pub const SMB_NTRPC_NT_STRING_TOO_LONG: u32 = 0xc002002c; -pub const SMB_NTRPC_NT_PROTSEQ_NOT_FOUND: u32 = 0xc002002d; -pub const SMB_NTRPC_NT_PROCNUM_OUT_OF_RANGE: u32 = 0xc002002e; -pub const SMB_NTRPC_NT_BINDING_HAS_NO_AUTH: u32 = 0xc002002f; -pub const SMB_NTRPC_NT_UNKNOWN_AUTHN_SERVICE: u32 = 0xc0020030; -pub const SMB_NTRPC_NT_UNKNOWN_AUTHN_LEVEL: u32 = 0xc0020031; -pub const SMB_NTRPC_NT_INVALID_AUTH_IDENTITY: u32 = 0xc0020032; -pub const SMB_NTRPC_NT_UNKNOWN_AUTHZ_SERVICE: u32 = 0xc0020033; -pub const SMB_NTEPT_NT_INVALID_ENTRY: u32 = 0xc0020034; -pub const SMB_NTEPT_NT_CANT_PERFORM_OP: u32 = 0xc0020035; -pub const SMB_NTEPT_NT_NOT_REGISTERED: u32 = 0xc0020036; -pub const SMB_NTRPC_NT_NOTHING_TO_EXPORT: u32 = 0xc0020037; -pub const SMB_NTRPC_NT_INCOMPLETE_NAME: u32 = 0xc0020038; -pub const SMB_NTRPC_NT_INVALID_VERS_OPTION: u32 = 0xc0020039; -pub const SMB_NTRPC_NT_NO_MORE_MEMBERS: u32 = 0xc002003a; -pub const SMB_NTRPC_NT_NOT_ALL_OBJS_UNEXPORTED: u32 = 0xc002003b; -pub const SMB_NTRPC_NT_INTERFACE_NOT_FOUND: u32 = 0xc002003c; -pub const SMB_NTRPC_NT_ENTRY_ALREADY_EXISTS: u32 = 0xc002003d; -pub const SMB_NTRPC_NT_ENTRY_NOT_FOUND: u32 = 0xc002003e; -pub const SMB_NTRPC_NT_NAME_SERVICE_UNAVAILABLE: u32 = 0xc002003f; -pub const SMB_NTRPC_NT_INVALID_NAF_ID: u32 = 0xc0020040; -pub const SMB_NTRPC_NT_CANNOT_SUPPORT: u32 = 0xc0020041; -pub const SMB_NTRPC_NT_NO_CONTEXT_AVAILABLE: u32 = 0xc0020042; -pub const SMB_NTRPC_NT_INTERNAL_ERROR: u32 = 0xc0020043; -pub const SMB_NTRPC_NT_ZERO_DIVIDE: u32 = 0xc0020044; -pub const SMB_NTRPC_NT_ADDRESS_ERROR: u32 = 0xc0020045; -pub const SMB_NTRPC_NT_FP_DIV_ZERO: u32 = 0xc0020046; -pub const SMB_NTRPC_NT_FP_UNDERFLOW: u32 = 0xc0020047; -pub const SMB_NTRPC_NT_FP_OVERFLOW: u32 = 0xc0020048; -pub const SMB_NTRPC_NT_CALL_IN_PROGRESS: u32 = 0xc0020049; -pub const SMB_NTRPC_NT_NO_MORE_BINDINGS: u32 = 0xc002004a; -pub const SMB_NTRPC_NT_GROUP_MEMBER_NOT_FOUND: u32 = 0xc002004b; -pub const SMB_NTEPT_NT_CANT_CREATE: u32 = 0xc002004c; -pub const SMB_NTRPC_NT_INVALID_OBJECT: u32 = 0xc002004d; -pub const SMB_NTRPC_NT_NO_INTERFACES: u32 = 0xc002004f; -pub const SMB_NTRPC_NT_CALL_CANCELLED: u32 = 0xc0020050; -pub const SMB_NTRPC_NT_BINDING_INCOMPLETE: u32 = 0xc0020051; -pub const SMB_NTRPC_NT_COMM_FAILURE: u32 = 0xc0020052; -pub const SMB_NTRPC_NT_UNSUPPORTED_AUTHN_LEVEL: u32 = 0xc0020053; -pub const SMB_NTRPC_NT_NO_PRINC_NAME: u32 = 0xc0020054; -pub const SMB_NTRPC_NT_NOT_RPC_ERROR: u32 = 0xc0020055; -pub const SMB_NTRPC_NT_SEC_PKG_ERROR: u32 = 0xc0020057; -pub const SMB_NTRPC_NT_NOT_CANCELLED: u32 = 0xc0020058; -pub const SMB_NTRPC_NT_INVALID_ASYNC_HANDLE: u32 = 0xc0020062; -pub const SMB_NTRPC_NT_INVALID_ASYNC_CALL: u32 = 0xc0020063; -pub const SMB_NTRPC_NT_PROXY_ACCESS_DENIED: u32 = 0xc0020064; -pub const SMB_NTRPC_NT_NO_MORE_ENTRIES: u32 = 0xc0030001; -pub const SMB_NTRPC_NT_SS_CHAR_TRANS_OPEN_FAIL: u32 = 0xc0030002; -pub const SMB_NTRPC_NT_SS_CHAR_TRANS_SHORT_FILE: u32 = 0xc0030003; -pub const SMB_NTRPC_NT_SS_IN_NULL_CONTEXT: u32 = 0xc0030004; -pub const SMB_NTRPC_NT_SS_CONTEXT_MISMATCH: u32 = 0xc0030005; -pub const SMB_NTRPC_NT_SS_CONTEXT_DAMAGED: u32 = 0xc0030006; -pub const SMB_NTRPC_NT_SS_HANDLES_MISMATCH: u32 = 0xc0030007; -pub const SMB_NTRPC_NT_SS_CANNOT_GET_CALL_HANDLE: u32 = 0xc0030008; -pub const SMB_NTRPC_NT_NULL_REF_POINTER: u32 = 0xc0030009; -pub const SMB_NTRPC_NT_ENUM_VALUE_OUT_OF_RANGE: u32 = 0xc003000a; -pub const SMB_NTRPC_NT_BYTE_COUNT_TOO_SMALL: u32 = 0xc003000b; -pub const SMB_NTRPC_NT_BAD_STUB_DATA: u32 = 0xc003000c; -pub const SMB_NTRPC_NT_INVALID_ES_ACTION: u32 = 0xc0030059; -pub const SMB_NTRPC_NT_WRONG_ES_VERSION: u32 = 0xc003005a; -pub const SMB_NTRPC_NT_WRONG_STUB_VERSION: u32 = 0xc003005b; -pub const SMB_NTRPC_NT_INVALID_PIPE_OBJECT: u32 = 0xc003005c; -pub const SMB_NTRPC_NT_INVALID_PIPE_OPERATION: u32 = 0xc003005d; -pub const SMB_NTRPC_NT_WRONG_PIPE_VERSION: u32 = 0xc003005e; -pub const SMB_NTRPC_NT_PIPE_CLOSED: u32 = 0xc003005f; -pub const SMB_NTRPC_NT_PIPE_DISCIPLINE_ERROR: u32 = 0xc0030060; -pub const SMB_NTRPC_NT_PIPE_EMPTY: u32 = 0xc0030061; -pub const SMB_NTSTATUS_PNP_BAD_MPS_TABLE: u32 = 0xc0040035; -pub const SMB_NTSTATUS_PNP_TRANSLATION_FAILED: u32 = 0xc0040036; -pub const SMB_NTSTATUS_PNP_IRQ_TRANSLATION_FAILED: u32 = 0xc0040037; -pub const SMB_NTSTATUS_PNP_INVALID_ID: u32 = 0xc0040038; -pub const SMB_NTSTATUS_IO_REISSUE_AS_CACHED: u32 = 0xc0040039; -pub const SMB_NTSTATUS_CTX_WINSTATION_NAME_INVALID: u32 = 0xc00a0001; -pub const SMB_NTSTATUS_CTX_INVALID_PD: u32 = 0xc00a0002; -pub const SMB_NTSTATUS_CTX_PD_NOT_FOUND: u32 = 0xc00a0003; -pub const SMB_NTSTATUS_CTX_CLOSE_PENDING: u32 = 0xc00a0006; -pub const SMB_NTSTATUS_CTX_NO_OUTBUF: u32 = 0xc00a0007; -pub const SMB_NTSTATUS_CTX_MODEM_INF_NOT_FOUND: u32 = 0xc00a0008; -pub const SMB_NTSTATUS_CTX_INVALID_MODEMNAME: u32 = 0xc00a0009; -pub const SMB_NTSTATUS_CTX_RESPONSE_ERROR: u32 = 0xc00a000a; -pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_TIMEOUT: u32 = 0xc00a000b; -pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_CARRIER: u32 = 0xc00a000c; -pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_DIALTONE: u32 = 0xc00a000d; -pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_BUSY: u32 = 0xc00a000e; -pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_VOICE: u32 = 0xc00a000f; -pub const SMB_NTSTATUS_CTX_TD_ERROR: u32 = 0xc00a0010; -pub const SMB_NTSTATUS_CTX_LICENSE_CLIENT_INVALID: u32 = 0xc00a0012; -pub const SMB_NTSTATUS_CTX_LICENSE_NOT_AVAILABLE: u32 = 0xc00a0013; -pub const SMB_NTSTATUS_CTX_LICENSE_EXPIRED: u32 = 0xc00a0014; -pub const SMB_NTSTATUS_CTX_WINSTATION_NOT_FOUND: u32 = 0xc00a0015; -pub const SMB_NTSTATUS_CTX_WINSTATION_NAME_COLLISION: u32 = 0xc00a0016; -pub const SMB_NTSTATUS_CTX_WINSTATION_BUSY: u32 = 0xc00a0017; -pub const SMB_NTSTATUS_CTX_BAD_VIDEO_MODE: u32 = 0xc00a0018; -pub const SMB_NTSTATUS_CTX_GRAPHICS_INVALID: u32 = 0xc00a0022; -pub const SMB_NTSTATUS_CTX_NOT_CONSOLE: u32 = 0xc00a0024; -pub const SMB_NTSTATUS_CTX_CLIENT_QUERY_TIMEOUT: u32 = 0xc00a0026; -pub const SMB_NTSTATUS_CTX_CONSOLE_DISCONNECT: u32 = 0xc00a0027; -pub const SMB_NTSTATUS_CTX_CONSOLE_CONNECT: u32 = 0xc00a0028; -pub const SMB_NTSTATUS_CTX_SHADOW_DENIED: u32 = 0xc00a002a; -pub const SMB_NTSTATUS_CTX_WINSTATION_ACCESS_DENIED: u32 = 0xc00a002b; -pub const SMB_NTSTATUS_CTX_INVALID_WD: u32 = 0xc00a002e; -pub const SMB_NTSTATUS_CTX_WD_NOT_FOUND: u32 = 0xc00a002f; -pub const SMB_NTSTATUS_CTX_SHADOW_INVALID: u32 = 0xc00a0030; -pub const SMB_NTSTATUS_CTX_SHADOW_DISABLED: u32 = 0xc00a0031; -pub const SMB_NTSTATUS_RDP_PROTOCOL_ERROR: u32 = 0xc00a0032; -pub const SMB_NTSTATUS_CTX_CLIENT_LICENSE_NOT_SET: u32 = 0xc00a0033; -pub const SMB_NTSTATUS_CTX_CLIENT_LICENSE_IN_USE: u32 = 0xc00a0034; -pub const SMB_NTSTATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE: u32 = 0xc00a0035; -pub const SMB_NTSTATUS_CTX_SHADOW_NOT_RUNNING: u32 = 0xc00a0036; -pub const SMB_NTSTATUS_CTX_LOGON_DISABLED: u32 = 0xc00a0037; -pub const SMB_NTSTATUS_CTX_SECURITY_LAYER_ERROR: u32 = 0xc00a0038; -pub const SMB_NTSTATUS_TS_INCOMPATIBLE_SESSIONS: u32 = 0xc00a0039; -pub const SMB_NTSTATUS_MUI_FILE_NOT_FOUND: u32 = 0xc00b0001; -pub const SMB_NTSTATUS_MUI_INVALID_FILE: u32 = 0xc00b0002; -pub const SMB_NTSTATUS_MUI_INVALID_RC_CONFIG: u32 = 0xc00b0003; -pub const SMB_NTSTATUS_MUI_INVALID_LOCALE_NAME: u32 = 0xc00b0004; -pub const SMB_NTSTATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME: u32 = 0xc00b0005; -pub const SMB_NTSTATUS_MUI_FILE_NOT_LOADED: u32 = 0xc00b0006; -pub const SMB_NTSTATUS_RESOURCE_ENUM_USER_STOP: u32 = 0xc00b0007; -pub const SMB_NTSTATUS_CLUSTER_INVALID_NODE: u32 = 0xc0130001; -pub const SMB_NTSTATUS_CLUSTER_NODE_EXISTS: u32 = 0xc0130002; -pub const SMB_NTSTATUS_CLUSTER_JOIN_IN_PROGRESS: u32 = 0xc0130003; -pub const SMB_NTSTATUS_CLUSTER_NODE_NOT_FOUND: u32 = 0xc0130004; -pub const SMB_NTSTATUS_CLUSTER_LOCAL_NODE_NOT_FOUND: u32 = 0xc0130005; -pub const SMB_NTSTATUS_CLUSTER_NETWORK_EXISTS: u32 = 0xc0130006; -pub const SMB_NTSTATUS_CLUSTER_NETWORK_NOT_FOUND: u32 = 0xc0130007; -pub const SMB_NTSTATUS_CLUSTER_NETINTERFACE_EXISTS: u32 = 0xc0130008; -pub const SMB_NTSTATUS_CLUSTER_NETINTERFACE_NOT_FOUND: u32 = 0xc0130009; -pub const SMB_NTSTATUS_CLUSTER_INVALID_REQUEST: u32 = 0xc013000a; -pub const SMB_NTSTATUS_CLUSTER_INVALID_NETWORK_PROVIDER: u32 = 0xc013000b; -pub const SMB_NTSTATUS_CLUSTER_NODE_DOWN: u32 = 0xc013000c; -pub const SMB_NTSTATUS_CLUSTER_NODE_UNREACHABLE: u32 = 0xc013000d; -pub const SMB_NTSTATUS_CLUSTER_NODE_NOT_MEMBER: u32 = 0xc013000e; -pub const SMB_NTSTATUS_CLUSTER_JOIN_NOT_IN_PROGRESS: u32 = 0xc013000f; -pub const SMB_NTSTATUS_CLUSTER_INVALID_NETWORK: u32 = 0xc0130010; -pub const SMB_NTSTATUS_CLUSTER_NO_NET_ADAPTERS: u32 = 0xc0130011; -pub const SMB_NTSTATUS_CLUSTER_NODE_UP: u32 = 0xc0130012; -pub const SMB_NTSTATUS_CLUSTER_NODE_PAUSED: u32 = 0xc0130013; -pub const SMB_NTSTATUS_CLUSTER_NODE_NOT_PAUSED: u32 = 0xc0130014; -pub const SMB_NTSTATUS_CLUSTER_NO_SECURITY_CONTEXT: u32 = 0xc0130015; -pub const SMB_NTSTATUS_CLUSTER_NETWORK_NOT_INTERNAL: u32 = 0xc0130016; -pub const SMB_NTSTATUS_CLUSTER_POISONED: u32 = 0xc0130017; -pub const SMB_NTSTATUS_ACPI_INVALID_OPCODE: u32 = 0xc0140001; -pub const SMB_NTSTATUS_ACPI_STACK_OVERFLOW: u32 = 0xc0140002; -pub const SMB_NTSTATUS_ACPI_ASSERT_FAILED: u32 = 0xc0140003; -pub const SMB_NTSTATUS_ACPI_INVALID_INDEX: u32 = 0xc0140004; -pub const SMB_NTSTATUS_ACPI_INVALID_ARGUMENT: u32 = 0xc0140005; -pub const SMB_NTSTATUS_ACPI_FATAL: u32 = 0xc0140006; -pub const SMB_NTSTATUS_ACPI_INVALID_SUPERNAME: u32 = 0xc0140007; -pub const SMB_NTSTATUS_ACPI_INVALID_ARGTYPE: u32 = 0xc0140008; -pub const SMB_NTSTATUS_ACPI_INVALID_OBJTYPE: u32 = 0xc0140009; -pub const SMB_NTSTATUS_ACPI_INVALID_TARGETTYPE: u32 = 0xc014000a; -pub const SMB_NTSTATUS_ACPI_INCORRECT_ARGUMENT_COUNT: u32 = 0xc014000b; -pub const SMB_NTSTATUS_ACPI_ADDRESS_NOT_MAPPED: u32 = 0xc014000c; -pub const SMB_NTSTATUS_ACPI_INVALID_EVENTTYPE: u32 = 0xc014000d; -pub const SMB_NTSTATUS_ACPI_HANDLER_COLLISION: u32 = 0xc014000e; -pub const SMB_NTSTATUS_ACPI_INVALID_DATA: u32 = 0xc014000f; -pub const SMB_NTSTATUS_ACPI_INVALID_REGION: u32 = 0xc0140010; -pub const SMB_NTSTATUS_ACPI_INVALID_ACCESS_SIZE: u32 = 0xc0140011; -pub const SMB_NTSTATUS_ACPI_ACQUIRE_GLOBAL_LOCK: u32 = 0xc0140012; -pub const SMB_NTSTATUS_ACPI_ALREADY_INITIALIZED: u32 = 0xc0140013; -pub const SMB_NTSTATUS_ACPI_NOT_INITIALIZED: u32 = 0xc0140014; -pub const SMB_NTSTATUS_ACPI_INVALID_MUTEX_LEVEL: u32 = 0xc0140015; -pub const SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNED: u32 = 0xc0140016; -pub const SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNER: u32 = 0xc0140017; -pub const SMB_NTSTATUS_ACPI_RS_ACCESS: u32 = 0xc0140018; -pub const SMB_NTSTATUS_ACPI_INVALID_TABLE: u32 = 0xc0140019; -pub const SMB_NTSTATUS_ACPI_REG_HANDLER_FAILED: u32 = 0xc0140020; -pub const SMB_NTSTATUS_ACPI_POWER_REQUEST_FAILED: u32 = 0xc0140021; -pub const SMB_NTSTATUS_SXS_SECTION_NOT_FOUND: u32 = 0xc0150001; -pub const SMB_NTSTATUS_SXS_CANT_GEN_ACTCTX: u32 = 0xc0150002; -pub const SMB_NTSTATUS_SXS_INVALID_ACTCTXDATA_FORMAT: u32 = 0xc0150003; -pub const SMB_NTSTATUS_SXS_ASSEMBLY_NOT_FOUND: u32 = 0xc0150004; -pub const SMB_NTSTATUS_SXS_MANIFEST_FORMAT_ERROR: u32 = 0xc0150005; -pub const SMB_NTSTATUS_SXS_MANIFEST_PARSE_ERROR: u32 = 0xc0150006; -pub const SMB_NTSTATUS_SXS_ACTIVATION_CONTEXT_DISABLED: u32 = 0xc0150007; -pub const SMB_NTSTATUS_SXS_KEY_NOT_FOUND: u32 = 0xc0150008; -pub const SMB_NTSTATUS_SXS_VERSION_CONFLICT: u32 = 0xc0150009; -pub const SMB_NTSTATUS_SXS_WRONG_SECTION_TYPE: u32 = 0xc015000a; -pub const SMB_NTSTATUS_SXS_THREAD_QUERIES_DISABLED: u32 = 0xc015000b; -pub const SMB_NTSTATUS_SXS_ASSEMBLY_MISSING: u32 = 0xc015000c; -pub const SMB_NTSTATUS_SXS_PROCESS_DEFAULT_ALREADY_SET: u32 = 0xc015000e; -pub const SMB_NTSTATUS_SXS_EARLY_DEACTIVATION: u32 = 0xc015000f; -pub const SMB_NTSTATUS_SXS_INVALID_DEACTIVATION: u32 = 0xc0150010; -pub const SMB_NTSTATUS_SXS_MULTIPLE_DEACTIVATION: u32 = 0xc0150011; -pub const SMB_NTSTATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY: u32 = 0xc0150012; -pub const SMB_NTSTATUS_SXS_PROCESS_TERMINATION_REQUESTED: u32 = 0xc0150013; -pub const SMB_NTSTATUS_SXS_CORRUPT_ACTIVATION_STACK: u32 = 0xc0150014; -pub const SMB_NTSTATUS_SXS_CORRUPTION: u32 = 0xc0150015; -pub const SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE: u32 = 0xc0150016; -pub const SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME: u32 = 0xc0150017; -pub const SMB_NTSTATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE: u32 = 0xc0150018; -pub const SMB_NTSTATUS_SXS_IDENTITY_PARSE_ERROR: u32 = 0xc0150019; -pub const SMB_NTSTATUS_SXS_COMPONENT_STORE_CORRUPT: u32 = 0xc015001a; -pub const SMB_NTSTATUS_SXS_FILE_HASH_MISMATCH: u32 = 0xc015001b; -pub const SMB_NTSTATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT: u32 = 0xc015001c; -pub const SMB_NTSTATUS_SXS_IDENTITIES_DIFFERENT: u32 = 0xc015001d; -pub const SMB_NTSTATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT: u32 = 0xc015001e; -pub const SMB_NTSTATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY: u32 = 0xc015001f; -pub const SMB_NTSTATUS_ADVANCED_INSTALLER_FAILED: u32 = 0xc0150020; -pub const SMB_NTSTATUS_XML_ENCODING_MISMATCH: u32 = 0xc0150021; -pub const SMB_NTSTATUS_SXS_MANIFEST_TOO_BIG: u32 = 0xc0150022; -pub const SMB_NTSTATUS_SXS_SETTING_NOT_REGISTERED: u32 = 0xc0150023; -pub const SMB_NTSTATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE: u32 = 0xc0150024; -pub const SMB_NTSTATUS_SMI_PRIMITIVE_INSTALLER_FAILED: u32 = 0xc0150025; -pub const SMB_NTSTATUS_GENERIC_COMMAND_FAILED: u32 = 0xc0150026; -pub const SMB_NTSTATUS_SXS_FILE_HASH_MISSING: u32 = 0xc0150027; -pub const SMB_NTSTATUS_TRANSACTIONAL_CONFLICT: u32 = 0xc0190001; -pub const SMB_NTSTATUS_INVALID_TRANSACTION: u32 = 0xc0190002; -pub const SMB_NTSTATUS_TRANSACTION_NOT_ACTIVE: u32 = 0xc0190003; -pub const SMB_NTSTATUS_TM_INITIALIZATION_FAILED: u32 = 0xc0190004; -pub const SMB_NTSTATUS_RM_NOT_ACTIVE: u32 = 0xc0190005; -pub const SMB_NTSTATUS_RM_METADATA_CORRUPT: u32 = 0xc0190006; -pub const SMB_NTSTATUS_TRANSACTION_NOT_JOINED: u32 = 0xc0190007; -pub const SMB_NTSTATUS_DIRECTORY_NOT_RM: u32 = 0xc0190008; -pub const SMB_NTSTATUS_TRANSACTIONS_UNSUPPORTED_REMOTE: u32 = 0xc019000a; -pub const SMB_NTSTATUS_LOG_RESIZE_INVALID_SIZE: u32 = 0xc019000b; -pub const SMB_NTSTATUS_REMOTE_FILE_VERSION_MISMATCH: u32 = 0xc019000c; -pub const SMB_NTSTATUS_CRM_PROTOCOL_ALREADY_EXISTS: u32 = 0xc019000f; -pub const SMB_NTSTATUS_TRANSACTION_PROPAGATION_FAILED: u32 = 0xc0190010; -pub const SMB_NTSTATUS_CRM_PROTOCOL_NOT_FOUND: u32 = 0xc0190011; -pub const SMB_NTSTATUS_TRANSACTION_SUPERIOR_EXISTS: u32 = 0xc0190012; -pub const SMB_NTSTATUS_TRANSACTION_REQUEST_NOT_VALID: u32 = 0xc0190013; -pub const SMB_NTSTATUS_TRANSACTION_NOT_REQUESTED: u32 = 0xc0190014; -pub const SMB_NTSTATUS_TRANSACTION_ALREADY_ABORTED: u32 = 0xc0190015; -pub const SMB_NTSTATUS_TRANSACTION_ALREADY_COMMITTED: u32 = 0xc0190016; -pub const SMB_NTSTATUS_TRANSACTION_INVALID_MARSHALL_BUFFER: u32 = 0xc0190017; -pub const SMB_NTSTATUS_CURRENT_TRANSACTION_NOT_VALID: u32 = 0xc0190018; -pub const SMB_NTSTATUS_LOG_GROWTH_FAILED: u32 = 0xc0190019; -pub const SMB_NTSTATUS_OBJECT_NO_LONGER_EXISTS: u32 = 0xc0190021; -pub const SMB_NTSTATUS_STREAM_MINIVERSION_NOT_FOUND: u32 = 0xc0190022; -pub const SMB_NTSTATUS_STREAM_MINIVERSION_NOT_VALID: u32 = 0xc0190023; -pub const SMB_NTSTATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION: u32 = 0xc0190024; -pub const SMB_NTSTATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT: u32 = 0xc0190025; -pub const SMB_NTSTATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS: u32 = 0xc0190026; -pub const SMB_NTSTATUS_HANDLE_NO_LONGER_VALID: u32 = 0xc0190028; -pub const SMB_NTSTATUS_LOG_CORRUPTION_DETECTED: u32 = 0xc0190030; -pub const SMB_NTSTATUS_RM_DISCONNECTED: u32 = 0xc0190032; -pub const SMB_NTSTATUS_ENLISTMENT_NOT_SUPERIOR: u32 = 0xc0190033; -pub const SMB_NTSTATUS_FILE_IDENTITY_NOT_PERSISTENT: u32 = 0xc0190036; -pub const SMB_NTSTATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY: u32 = 0xc0190037; -pub const SMB_NTSTATUS_CANT_CROSS_RM_BOUNDARY: u32 = 0xc0190038; -pub const SMB_NTSTATUS_TXF_DIR_NOT_EMPTY: u32 = 0xc0190039; -pub const SMB_NTSTATUS_INDOUBT_TRANSACTIONS_EXIST: u32 = 0xc019003a; -pub const SMB_NTSTATUS_TM_VOLATILE: u32 = 0xc019003b; -pub const SMB_NTSTATUS_ROLLBACK_TIMER_EXPIRED: u32 = 0xc019003c; -pub const SMB_NTSTATUS_TXF_ATTRIBUTE_CORRUPT: u32 = 0xc019003d; -pub const SMB_NTSTATUS_EFS_NOT_ALLOWED_IN_TRANSACTION: u32 = 0xc019003e; -pub const SMB_NTSTATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED: u32 = 0xc019003f; -pub const SMB_NTSTATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE: u32 = 0xc0190040; -pub const SMB_NTSTATUS_TRANSACTION_REQUIRED_PROMOTION: u32 = 0xc0190043; -pub const SMB_NTSTATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION: u32 = 0xc0190044; -pub const SMB_NTSTATUS_TRANSACTIONS_NOT_FROZEN: u32 = 0xc0190045; -pub const SMB_NTSTATUS_TRANSACTION_FREEZE_IN_PROGRESS: u32 = 0xc0190046; -pub const SMB_NTSTATUS_NOT_SNAPSHOT_VOLUME: u32 = 0xc0190047; -pub const SMB_NTSTATUS_NO_SAVEPOINT_WITH_OPEN_FILES: u32 = 0xc0190048; -pub const SMB_NTSTATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION: u32 = 0xc0190049; -pub const SMB_NTSTATUS_TM_IDENTITY_MISMATCH: u32 = 0xc019004a; -pub const SMB_NTSTATUS_FLOATED_SECTION: u32 = 0xc019004b; -pub const SMB_NTSTATUS_CANNOT_ACCEPT_TRANSACTED_WORK: u32 = 0xc019004c; -pub const SMB_NTSTATUS_CANNOT_ABORT_TRANSACTIONS: u32 = 0xc019004d; -pub const SMB_NTSTATUS_TRANSACTION_NOT_FOUND: u32 = 0xc019004e; -pub const SMB_NTSTATUS_RESOURCEMANAGER_NOT_FOUND: u32 = 0xc019004f; -pub const SMB_NTSTATUS_ENLISTMENT_NOT_FOUND: u32 = 0xc0190050; -pub const SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_FOUND: u32 = 0xc0190051; -pub const SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_ONLINE: u32 = 0xc0190052; -pub const SMB_NTSTATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION: u32 = 0xc0190053; -pub const SMB_NTSTATUS_TRANSACTION_NOT_ROOT: u32 = 0xc0190054; -pub const SMB_NTSTATUS_TRANSACTION_OBJECT_EXPIRED: u32 = 0xc0190055; -pub const SMB_NTSTATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION: u32 = 0xc0190056; -pub const SMB_NTSTATUS_TRANSACTION_RESPONSE_NOT_ENLISTED: u32 = 0xc0190057; -pub const SMB_NTSTATUS_TRANSACTION_RECORD_TOO_LONG: u32 = 0xc0190058; -pub const SMB_NTSTATUS_NO_LINK_TRACKING_IN_TRANSACTION: u32 = 0xc0190059; -pub const SMB_NTSTATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION: u32 = 0xc019005a; -pub const SMB_NTSTATUS_TRANSACTION_INTEGRITY_VIOLATED: u32 = 0xc019005b; -pub const SMB_NTSTATUS_EXPIRED_HANDLE: u32 = 0xc0190060; -pub const SMB_NTSTATUS_TRANSACTION_NOT_ENLISTED: u32 = 0xc0190061; -pub const SMB_NTSTATUS_LOG_SECTOR_INVALID: u32 = 0xc01a0001; -pub const SMB_NTSTATUS_LOG_SECTOR_PARITY_INVALID: u32 = 0xc01a0002; -pub const SMB_NTSTATUS_LOG_SECTOR_REMAPPED: u32 = 0xc01a0003; -pub const SMB_NTSTATUS_LOG_BLOCK_INCOMPLETE: u32 = 0xc01a0004; -pub const SMB_NTSTATUS_LOG_INVALID_RANGE: u32 = 0xc01a0005; -pub const SMB_NTSTATUS_LOG_BLOCKS_EXHAUSTED: u32 = 0xc01a0006; -pub const SMB_NTSTATUS_LOG_READ_CONTEXT_INVALID: u32 = 0xc01a0007; -pub const SMB_NTSTATUS_LOG_RESTART_INVALID: u32 = 0xc01a0008; -pub const SMB_NTSTATUS_LOG_BLOCK_VERSION: u32 = 0xc01a0009; -pub const SMB_NTSTATUS_LOG_BLOCK_INVALID: u32 = 0xc01a000a; -pub const SMB_NTSTATUS_LOG_READ_MODE_INVALID: u32 = 0xc01a000b; -pub const SMB_NTSTATUS_LOG_METADATA_CORRUPT: u32 = 0xc01a000d; -pub const SMB_NTSTATUS_LOG_METADATA_INVALID: u32 = 0xc01a000e; -pub const SMB_NTSTATUS_LOG_METADATA_INCONSISTENT: u32 = 0xc01a000f; -pub const SMB_NTSTATUS_LOG_RESERVATION_INVALID: u32 = 0xc01a0010; -pub const SMB_NTSTATUS_LOG_CANT_DELETE: u32 = 0xc01a0011; -pub const SMB_NTSTATUS_LOG_CONTAINER_LIMIT_EXCEEDED: u32 = 0xc01a0012; -pub const SMB_NTSTATUS_LOG_START_OF_LOG: u32 = 0xc01a0013; -pub const SMB_NTSTATUS_LOG_POLICY_ALREADY_INSTALLED: u32 = 0xc01a0014; -pub const SMB_NTSTATUS_LOG_POLICY_NOT_INSTALLED: u32 = 0xc01a0015; -pub const SMB_NTSTATUS_LOG_POLICY_INVALID: u32 = 0xc01a0016; -pub const SMB_NTSTATUS_LOG_POLICY_CONFLICT: u32 = 0xc01a0017; -pub const SMB_NTSTATUS_LOG_PINNED_ARCHIVE_TAIL: u32 = 0xc01a0018; -pub const SMB_NTSTATUS_LOG_RECORD_NONEXISTENT: u32 = 0xc01a0019; -pub const SMB_NTSTATUS_LOG_RECORDS_RESERVED_INVALID: u32 = 0xc01a001a; -pub const SMB_NTSTATUS_LOG_SPACE_RESERVED_INVALID: u32 = 0xc01a001b; -pub const SMB_NTSTATUS_LOG_TAIL_INVALID: u32 = 0xc01a001c; -pub const SMB_NTSTATUS_LOG_FULL: u32 = 0xc01a001d; -pub const SMB_NTSTATUS_LOG_MULTIPLEXED: u32 = 0xc01a001e; -pub const SMB_NTSTATUS_LOG_DEDICATED: u32 = 0xc01a001f; -pub const SMB_NTSTATUS_LOG_ARCHIVE_NOT_IN_PROGRESS: u32 = 0xc01a0020; -pub const SMB_NTSTATUS_LOG_ARCHIVE_IN_PROGRESS: u32 = 0xc01a0021; -pub const SMB_NTSTATUS_LOG_EPHEMERAL: u32 = 0xc01a0022; -pub const SMB_NTSTATUS_LOG_NOT_ENOUGH_CONTAINERS: u32 = 0xc01a0023; -pub const SMB_NTSTATUS_LOG_CLIENT_ALREADY_REGISTERED: u32 = 0xc01a0024; -pub const SMB_NTSTATUS_LOG_CLIENT_NOT_REGISTERED: u32 = 0xc01a0025; -pub const SMB_NTSTATUS_LOG_FULL_HANDLER_IN_PROGRESS: u32 = 0xc01a0026; -pub const SMB_NTSTATUS_LOG_CONTAINER_READ_FAILED: u32 = 0xc01a0027; -pub const SMB_NTSTATUS_LOG_CONTAINER_WRITE_FAILED: u32 = 0xc01a0028; -pub const SMB_NTSTATUS_LOG_CONTAINER_OPEN_FAILED: u32 = 0xc01a0029; -pub const SMB_NTSTATUS_LOG_CONTAINER_STATE_INVALID: u32 = 0xc01a002a; -pub const SMB_NTSTATUS_LOG_STATE_INVALID: u32 = 0xc01a002b; -pub const SMB_NTSTATUS_LOG_PINNED: u32 = 0xc01a002c; -pub const SMB_NTSTATUS_LOG_METADATA_FLUSH_FAILED: u32 = 0xc01a002d; -pub const SMB_NTSTATUS_LOG_INCONSISTENT_SECURITY: u32 = 0xc01a002e; -pub const SMB_NTSTATUS_LOG_APPENDED_FLUSH_FAILED: u32 = 0xc01a002f; -pub const SMB_NTSTATUS_LOG_PINNED_RESERVATION: u32 = 0xc01a0030; -pub const SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD: u32 = 0xc01b00ea; -pub const SMB_NTSTATUS_FLT_NO_HANDLER_DEFINED: u32 = 0xc01c0001; -pub const SMB_NTSTATUS_FLT_CONTEXT_ALREADY_DEFINED: u32 = 0xc01c0002; -pub const SMB_NTSTATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST: u32 = 0xc01c0003; -pub const SMB_NTSTATUS_FLT_DISALLOW_FAST_IO: u32 = 0xc01c0004; -pub const SMB_NTSTATUS_FLT_INVALID_NAME_REQUEST: u32 = 0xc01c0005; -pub const SMB_NTSTATUS_FLT_NOT_SAFE_TO_POST_OPERATION: u32 = 0xc01c0006; -pub const SMB_NTSTATUS_FLT_NOT_INITIALIZED: u32 = 0xc01c0007; -pub const SMB_NTSTATUS_FLT_FILTER_NOT_READY: u32 = 0xc01c0008; -pub const SMB_NTSTATUS_FLT_POST_OPERATION_CLEANUP: u32 = 0xc01c0009; -pub const SMB_NTSTATUS_FLT_INTERNAL_ERROR: u32 = 0xc01c000a; -pub const SMB_NTSTATUS_FLT_DELETING_OBJECT: u32 = 0xc01c000b; -pub const SMB_NTSTATUS_FLT_MUST_BE_NONPAGED_POOL: u32 = 0xc01c000c; -pub const SMB_NTSTATUS_FLT_DUPLICATE_ENTRY: u32 = 0xc01c000d; -pub const SMB_NTSTATUS_FLT_CBDQ_DISABLED: u32 = 0xc01c000e; -pub const SMB_NTSTATUS_FLT_DO_NOT_ATTACH: u32 = 0xc01c000f; -pub const SMB_NTSTATUS_FLT_DO_NOT_DETACH: u32 = 0xc01c0010; -pub const SMB_NTSTATUS_FLT_INSTANCE_ALTITUDE_COLLISION: u32 = 0xc01c0011; -pub const SMB_NTSTATUS_FLT_INSTANCE_NAME_COLLISION: u32 = 0xc01c0012; -pub const SMB_NTSTATUS_FLT_FILTER_NOT_FOUND: u32 = 0xc01c0013; -pub const SMB_NTSTATUS_FLT_VOLUME_NOT_FOUND: u32 = 0xc01c0014; -pub const SMB_NTSTATUS_FLT_INSTANCE_NOT_FOUND: u32 = 0xc01c0015; -pub const SMB_NTSTATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND: u32 = 0xc01c0016; -pub const SMB_NTSTATUS_FLT_INVALID_CONTEXT_REGISTRATION: u32 = 0xc01c0017; -pub const SMB_NTSTATUS_FLT_NAME_CACHE_MISS: u32 = 0xc01c0018; -pub const SMB_NTSTATUS_FLT_NO_DEVICE_OBJECT: u32 = 0xc01c0019; -pub const SMB_NTSTATUS_FLT_VOLUME_ALREADY_MOUNTED: u32 = 0xc01c001a; -pub const SMB_NTSTATUS_FLT_ALREADY_ENLISTED: u32 = 0xc01c001b; -pub const SMB_NTSTATUS_FLT_CONTEXT_ALREADY_LINKED: u32 = 0xc01c001c; -pub const SMB_NTSTATUS_FLT_NO_WAITER_FOR_REPLY: u32 = 0xc01c0020; -pub const SMB_NTSTATUS_MONITOR_NO_DESCRIPTOR: u32 = 0xc01d0001; -pub const SMB_NTSTATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT: u32 = 0xc01d0002; -pub const SMB_NTSTATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM: u32 = 0xc01d0003; -pub const SMB_NTSTATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK: u32 = 0xc01d0004; -pub const SMB_NTSTATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED: u32 = 0xc01d0005; -pub const SMB_NTSTATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK: u32 = 0xc01d0006; -pub const SMB_NTSTATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK: u32 = 0xc01d0007; -pub const SMB_NTSTATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA: u32 = 0xc01d0008; -pub const SMB_NTSTATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK: u32 = 0xc01d0009; -pub const SMB_NTSTATUS_MONITOR_INVALID_MANUFACTURE_DATE: u32 = 0xc01d000a; -pub const SMB_NTSTATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER: u32 = 0xc01e0000; -pub const SMB_NTSTATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER: u32 = 0xc01e0001; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER: u32 = 0xc01e0002; -pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_WAS_RESET: u32 = 0xc01e0003; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_DRIVER_MODEL: u32 = 0xc01e0004; -pub const SMB_NTSTATUS_GRAPHICS_PRESENT_MODE_CHANGED: u32 = 0xc01e0005; -pub const SMB_NTSTATUS_GRAPHICS_PRESENT_OCCLUDED: u32 = 0xc01e0006; -pub const SMB_NTSTATUS_GRAPHICS_PRESENT_DENIED: u32 = 0xc01e0007; -pub const SMB_NTSTATUS_GRAPHICS_CANNOTCOLORCONVERT: u32 = 0xc01e0008; -pub const SMB_NTSTATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED: u32 = 0xc01e000b; -pub const SMB_NTSTATUS_GRAPHICS_PRESENT_UNOCCLUDED: u32 = 0xc01e000c; -pub const SMB_NTSTATUS_GRAPHICS_NO_VIDEO_MEMORY: u32 = 0xc01e0100; -pub const SMB_NTSTATUS_GRAPHICS_CANT_LOCK_MEMORY: u32 = 0xc01e0101; -pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_BUSY: u32 = 0xc01e0102; -pub const SMB_NTSTATUS_GRAPHICS_TOO_MANY_REFERENCES: u32 = 0xc01e0103; -pub const SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_LATER: u32 = 0xc01e0104; -pub const SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_NOW: u32 = 0xc01e0105; -pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_INVALID: u32 = 0xc01e0106; -pub const SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE: u32 = 0xc01e0107; -pub const SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED: u32 = 0xc01e0108; -pub const SMB_NTSTATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION: u32 = 0xc01e0109; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_USAGE: u32 = 0xc01e0110; -pub const SMB_NTSTATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION: u32 = 0xc01e0111; -pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_CLOSED: u32 = 0xc01e0112; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE: u32 = 0xc01e0113; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE: u32 = 0xc01e0114; -pub const SMB_NTSTATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE: u32 = 0xc01e0115; -pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_CONTENT_LOST: u32 = 0xc01e0116; -pub const SMB_NTSTATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE: u32 = 0xc01e0200; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY: u32 = 0xc01e0300; -pub const SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED: u32 = 0xc01e0301; -pub const SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED: u32 = 0xc01e0302; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN: u32 = 0xc01e0303; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE: u32 = 0xc01e0304; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET: u32 = 0xc01e0305; -pub const SMB_NTSTATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED: u32 = 0xc01e0306; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET: u32 = 0xc01e0308; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET: u32 = 0xc01e0309; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_FREQUENCY: u32 = 0xc01e030a; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_ACTIVE_REGION: u32 = 0xc01e030b; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_TOTAL_REGION: u32 = 0xc01e030c; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE: u32 = 0xc01e0310; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE: u32 = 0xc01e0311; -pub const SMB_NTSTATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET: u32 = 0xc01e0312; -pub const SMB_NTSTATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY: u32 = 0xc01e0313; -pub const SMB_NTSTATUS_GRAPHICS_MODE_ALREADY_IN_MODESET: u32 = 0xc01e0314; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET: u32 = 0xc01e0315; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET: u32 = 0xc01e0316; -pub const SMB_NTSTATUS_GRAPHICS_SOURCE_ALREADY_IN_SET: u32 = 0xc01e0317; -pub const SMB_NTSTATUS_GRAPHICS_TARGET_ALREADY_IN_SET: u32 = 0xc01e0318; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH: u32 = 0xc01e0319; -pub const SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY: u32 = 0xc01e031a; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET: u32 = 0xc01e031b; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE: u32 = 0xc01e031c; -pub const SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET: u32 = 0xc01e031d; -pub const SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET: u32 = 0xc01e031f; -pub const SMB_NTSTATUS_GRAPHICS_STALE_MODESET: u32 = 0xc01e0320; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET: u32 = 0xc01e0321; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE: u32 = 0xc01e0322; -pub const SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN: u32 = 0xc01e0323; -pub const SMB_NTSTATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE: u32 = 0xc01e0324; -pub const SMB_NTSTATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION: u32 = 0xc01e0325; -pub const SMB_NTSTATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES: u32 = 0xc01e0326; -pub const SMB_NTSTATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY: u32 = 0xc01e0327; -pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE: u32 = 0xc01e0328; -pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET: u32 = 0xc01e0329; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET: u32 = 0xc01e032a; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR: u32 = 0xc01e032b; -pub const SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET: u32 = 0xc01e032c; -pub const SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET: u32 = 0xc01e032d; -pub const SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE: u32 = 0xc01e032e; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE: u32 = 0xc01e032f; -pub const SMB_NTSTATUS_GRAPHICS_RESOURCES_NOT_RELATED: u32 = 0xc01e0330; -pub const SMB_NTSTATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE: u32 = 0xc01e0331; -pub const SMB_NTSTATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE: u32 = 0xc01e0332; -pub const SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET: u32 = 0xc01e0333; -pub const SMB_NTSTATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER: u32 = 0xc01e0334; -pub const SMB_NTSTATUS_GRAPHICS_NO_VIDPNMGR: u32 = 0xc01e0335; -pub const SMB_NTSTATUS_GRAPHICS_NO_ACTIVE_VIDPN: u32 = 0xc01e0336; -pub const SMB_NTSTATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY: u32 = 0xc01e0337; -pub const SMB_NTSTATUS_GRAPHICS_MONITOR_NOT_CONNECTED: u32 = 0xc01e0338; -pub const SMB_NTSTATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY: u32 = 0xc01e0339; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE: u32 = 0xc01e033a; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE: u32 = 0xc01e033b; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_STRIDE: u32 = 0xc01e033c; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_PIXELFORMAT: u32 = 0xc01e033d; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_COLORBASIS: u32 = 0xc01e033e; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE: u32 = 0xc01e033f; -pub const SMB_NTSTATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY: u32 = 0xc01e0340; -pub const SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT: u32 = 0xc01e0341; -pub const SMB_NTSTATUS_GRAPHICS_VIDPN_SOURCE_IN_USE: u32 = 0xc01e0342; -pub const SMB_NTSTATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN: u32 = 0xc01e0343; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL: u32 = 0xc01e0344; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION: u32 = 0xc01e0345; -pub const SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED: u32 = 0xc01e0346; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_GAMMA_RAMP: u32 = 0xc01e0347; -pub const SMB_NTSTATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED: u32 = 0xc01e0348; -pub const SMB_NTSTATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED: u32 = 0xc01e0349; -pub const SMB_NTSTATUS_GRAPHICS_MODE_NOT_IN_MODESET: u32 = 0xc01e034a; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON: u32 = 0xc01e034d; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE: u32 = 0xc01e034e; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE: u32 = 0xc01e034f; -pub const SMB_NTSTATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS: u32 = 0xc01e0350; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_SCANLINE_ORDERING: u32 = 0xc01e0352; -pub const SMB_NTSTATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED: u32 = 0xc01e0353; -pub const SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS: u32 = 0xc01e0354; -pub const SMB_NTSTATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT: u32 = 0xc01e0355; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM: u32 = 0xc01e0356; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN: u32 = 0xc01e0357; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT: u32 = 0xc01e0358; -pub const SMB_NTSTATUS_GRAPHICS_MAX_NUM_PATHS_REACHED: u32 = 0xc01e0359; -pub const SMB_NTSTATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION: u32 = 0xc01e035a; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_CLIENT_TYPE: u32 = 0xc01e035b; -pub const SMB_NTSTATUS_GRAPHICS_CLIENTVIDPN_NOT_SET: u32 = 0xc01e035c; -pub const SMB_NTSTATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED: u32 = 0xc01e0400; -pub const SMB_NTSTATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED: u32 = 0xc01e0401; -pub const SMB_NTSTATUS_GRAPHICS_NOT_A_LINKED_ADAPTER: u32 = 0xc01e0430; -pub const SMB_NTSTATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED: u32 = 0xc01e0431; -pub const SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED: u32 = 0xc01e0432; -pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY: u32 = 0xc01e0433; -pub const SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_STARTED: u32 = 0xc01e0434; -pub const SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON: u32 = 0xc01e0435; -pub const SMB_NTSTATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE: u32 = 0xc01e0436; -pub const SMB_NTSTATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER: u32 = 0xc01e0438; -pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED: u32 = 0xc01e043b; -pub const SMB_NTSTATUS_GRAPHICS_OPM_NOT_SUPPORTED: u32 = 0xc01e0500; -pub const SMB_NTSTATUS_GRAPHICS_COPP_NOT_SUPPORTED: u32 = 0xc01e0501; -pub const SMB_NTSTATUS_GRAPHICS_UAB_NOT_SUPPORTED: u32 = 0xc01e0502; -pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS: u32 = 0xc01e0503; -pub const SMB_NTSTATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL: u32 = 0xc01e0504; -pub const SMB_NTSTATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST: u32 = 0xc01e0505; -pub const SMB_NTSTATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME: u32 = 0xc01e0506; -pub const SMB_NTSTATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP: u32 = 0xc01e0507; -pub const SMB_NTSTATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED: u32 = 0xc01e0508; -pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_POINTER: u32 = 0xc01e050a; -pub const SMB_NTSTATUS_GRAPHICS_OPM_INTERNAL_ERROR: u32 = 0xc01e050b; -pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_HANDLE: u32 = 0xc01e050c; -pub const SMB_NTSTATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE: u32 = 0xc01e050d; -pub const SMB_NTSTATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH: u32 = 0xc01e050e; -pub const SMB_NTSTATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED: u32 = 0xc01e050f; -pub const SMB_NTSTATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED: u32 = 0xc01e0510; -pub const SMB_NTSTATUS_GRAPHICS_PVP_HFS_FAILED: u32 = 0xc01e0511; -pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_SRM: u32 = 0xc01e0512; -pub const SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP: u32 = 0xc01e0513; -pub const SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP: u32 = 0xc01e0514; -pub const SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA: u32 = 0xc01e0515; -pub const SMB_NTSTATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET: u32 = 0xc01e0516; -pub const SMB_NTSTATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH: u32 = 0xc01e0517; -pub const SMB_NTSTATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE: u32 = 0xc01e0518; -pub const SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS: u32 = 0xc01e051a; -pub const SMB_NTSTATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS: u32 = 0xc01e051b; -pub const SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS: u32 = 0xc01e051c; -pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST: u32 = 0xc01e051d; -pub const SMB_NTSTATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR: u32 = 0xc01e051e; -pub const SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS: u32 = 0xc01e051f; -pub const SMB_NTSTATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED: u32 = 0xc01e0520; -pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST: u32 = 0xc01e0521; -pub const SMB_NTSTATUS_GRAPHICS_I2C_NOT_SUPPORTED: u32 = 0xc01e0580; -pub const SMB_NTSTATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST: u32 = 0xc01e0581; -pub const SMB_NTSTATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA: u32 = 0xc01e0582; -pub const SMB_NTSTATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA: u32 = 0xc01e0583; -pub const SMB_NTSTATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED: u32 = 0xc01e0584; -pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_DATA: u32 = 0xc01e0585; -pub const SMB_NTSTATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE: u32 = 0xc01e0586; -pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING: u32 = 0xc01e0587; -pub const SMB_NTSTATUS_GRAPHICS_MCA_INTERNAL_ERROR: u32 = 0xc01e0588; -pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND: u32 = 0xc01e0589; -pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH: u32 = 0xc01e058a; -pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM: u32 = 0xc01e058b; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE: u32 = 0xc01e058c; -pub const SMB_NTSTATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS: u32 = 0xc01e058d; -pub const SMB_NTSTATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED: u32 = 0xc01e05e0; -pub const SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME: u32 = 0xc01e05e1; -pub const SMB_NTSTATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP: u32 = 0xc01e05e2; -pub const SMB_NTSTATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED: u32 = 0xc01e05e3; -pub const SMB_NTSTATUS_GRAPHICS_INVALID_POINTER: u32 = 0xc01e05e4; -pub const SMB_NTSTATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE: u32 = 0xc01e05e5; -pub const SMB_NTSTATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL: u32 = 0xc01e05e6; -pub const SMB_NTSTATUS_GRAPHICS_INTERNAL_ERROR: u32 = 0xc01e05e7; -pub const SMB_NTSTATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS: u32 = 0xc01e05e8; -pub const SMB_NTSTATUS_FVE_LOCKED_VOLUME: u32 = 0xc0210000; -pub const SMB_NTSTATUS_FVE_NOT_ENCRYPTED: u32 = 0xc0210001; -pub const SMB_NTSTATUS_FVE_BAD_INFORMATION: u32 = 0xc0210002; -pub const SMB_NTSTATUS_FVE_TOO_SMALL: u32 = 0xc0210003; -pub const SMB_NTSTATUS_FVE_FAILED_WRONG_FS: u32 = 0xc0210004; -pub const SMB_NTSTATUS_FVE_FAILED_BAD_FS: u32 = 0xc0210005; -pub const SMB_NTSTATUS_FVE_FS_NOT_EXTENDED: u32 = 0xc0210006; -pub const SMB_NTSTATUS_FVE_FS_MOUNTED: u32 = 0xc0210007; -pub const SMB_NTSTATUS_FVE_NO_LICENSE: u32 = 0xc0210008; -pub const SMB_NTSTATUS_FVE_ACTION_NOT_ALLOWED: u32 = 0xc0210009; -pub const SMB_NTSTATUS_FVE_BAD_DATA: u32 = 0xc021000a; -pub const SMB_NTSTATUS_FVE_VOLUME_NOT_BOUND: u32 = 0xc021000b; -pub const SMB_NTSTATUS_FVE_NOT_DATA_VOLUME: u32 = 0xc021000c; -pub const SMB_NTSTATUS_FVE_CONV_READ_ERROR: u32 = 0xc021000d; -pub const SMB_NTSTATUS_FVE_CONV_WRITE_ERROR: u32 = 0xc021000e; -pub const SMB_NTSTATUS_FVE_OVERLAPPED_UPDATE: u32 = 0xc021000f; -pub const SMB_NTSTATUS_FVE_FAILED_SECTOR_SIZE: u32 = 0xc0210010; -pub const SMB_NTSTATUS_FVE_FAILED_AUTHENTICATION: u32 = 0xc0210011; -pub const SMB_NTSTATUS_FVE_NOT_OS_VOLUME: u32 = 0xc0210012; -pub const SMB_NTSTATUS_FVE_KEYFILE_NOT_FOUND: u32 = 0xc0210013; -pub const SMB_NTSTATUS_FVE_KEYFILE_INVALID: u32 = 0xc0210014; -pub const SMB_NTSTATUS_FVE_KEYFILE_NO_VMK: u32 = 0xc0210015; -pub const SMB_NTSTATUS_FVE_TPM_DISABLED: u32 = 0xc0210016; -pub const SMB_NTSTATUS_FVE_TPM_SRK_AUTH_NOT_ZERO: u32 = 0xc0210017; -pub const SMB_NTSTATUS_FVE_TPM_INVALID_PCR: u32 = 0xc0210018; -pub const SMB_NTSTATUS_FVE_TPM_NO_VMK: u32 = 0xc0210019; -pub const SMB_NTSTATUS_FVE_PIN_INVALID: u32 = 0xc021001a; -pub const SMB_NTSTATUS_FVE_AUTH_INVALID_APPLICATION: u32 = 0xc021001b; -pub const SMB_NTSTATUS_FVE_AUTH_INVALID_CONFIG: u32 = 0xc021001c; -pub const SMB_NTSTATUS_FVE_DEBUGGER_ENABLED: u32 = 0xc021001d; -pub const SMB_NTSTATUS_FVE_DRY_RUN_FAILED: u32 = 0xc021001e; -pub const SMB_NTSTATUS_FVE_BAD_METADATA_POINTER: u32 = 0xc021001f; -pub const SMB_NTSTATUS_FVE_OLD_METADATA_COPY: u32 = 0xc0210020; -pub const SMB_NTSTATUS_FVE_REBOOT_REQUIRED: u32 = 0xc0210021; -pub const SMB_NTSTATUS_FVE_RAW_ACCESS: u32 = 0xc0210022; -pub const SMB_NTSTATUS_FVE_RAW_BLOCKED: u32 = 0xc0210023; -pub const SMB_NTSTATUS_FVE_NO_FEATURE_LICENSE: u32 = 0xc0210026; -pub const SMB_NTSTATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED: u32 = 0xc0210027; -pub const SMB_NTSTATUS_FVE_CONV_RECOVERY_FAILED: u32 = 0xc0210028; -pub const SMB_NTSTATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG: u32 = 0xc0210029; -pub const SMB_NTSTATUS_FVE_VOLUME_TOO_SMALL: u32 = 0xc0210030; -pub const SMB_NTSTATUS_FWP_CALLOUT_NOT_FOUND: u32 = 0xc0220001; -pub const SMB_NTSTATUS_FWP_CONDITION_NOT_FOUND: u32 = 0xc0220002; -pub const SMB_NTSTATUS_FWP_FILTER_NOT_FOUND: u32 = 0xc0220003; -pub const SMB_NTSTATUS_FWP_LAYER_NOT_FOUND: u32 = 0xc0220004; -pub const SMB_NTSTATUS_FWP_PROVIDER_NOT_FOUND: u32 = 0xc0220005; -pub const SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND: u32 = 0xc0220006; -pub const SMB_NTSTATUS_FWP_SUBLAYER_NOT_FOUND: u32 = 0xc0220007; -pub const SMB_NTSTATUS_FWP_NOT_FOUND: u32 = 0xc0220008; -pub const SMB_NTSTATUS_FWP_ALREADY_EXISTS: u32 = 0xc0220009; -pub const SMB_NTSTATUS_FWP_IN_USE: u32 = 0xc022000a; -pub const SMB_NTSTATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS: u32 = 0xc022000b; -pub const SMB_NTSTATUS_FWP_WRONG_SESSION: u32 = 0xc022000c; -pub const SMB_NTSTATUS_FWP_NO_TXN_IN_PROGRESS: u32 = 0xc022000d; -pub const SMB_NTSTATUS_FWP_TXN_IN_PROGRESS: u32 = 0xc022000e; -pub const SMB_NTSTATUS_FWP_TXN_ABORTED: u32 = 0xc022000f; -pub const SMB_NTSTATUS_FWP_SESSION_ABORTED: u32 = 0xc0220010; -pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_TXN: u32 = 0xc0220011; -pub const SMB_NTSTATUS_FWP_TIMEOUT: u32 = 0xc0220012; -pub const SMB_NTSTATUS_FWP_NET_EVENTS_DISABLED: u32 = 0xc0220013; -pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_LAYER: u32 = 0xc0220014; -pub const SMB_NTSTATUS_FWP_KM_CLIENTS_ONLY: u32 = 0xc0220015; -pub const SMB_NTSTATUS_FWP_LIFETIME_MISMATCH: u32 = 0xc0220016; -pub const SMB_NTSTATUS_FWP_BUILTIN_OBJECT: u32 = 0xc0220017; -pub const SMB_NTSTATUS_FWP_TOO_MANY_BOOTTIME_FILTERS: u32 = 0xc0220018; -pub const SMB_NTSTATUS_FWP_NOTIFICATION_DROPPED: u32 = 0xc0220019; -pub const SMB_NTSTATUS_FWP_TRAFFIC_MISMATCH: u32 = 0xc022001a; -pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_SA_STATE: u32 = 0xc022001b; -pub const SMB_NTSTATUS_FWP_NULL_POINTER: u32 = 0xc022001c; -pub const SMB_NTSTATUS_FWP_INVALID_ENUMERATOR: u32 = 0xc022001d; -pub const SMB_NTSTATUS_FWP_INVALID_FLAGS: u32 = 0xc022001e; -pub const SMB_NTSTATUS_FWP_INVALID_NET_MASK: u32 = 0xc022001f; -pub const SMB_NTSTATUS_FWP_INVALID_RANGE: u32 = 0xc0220020; -pub const SMB_NTSTATUS_FWP_INVALID_INTERVAL: u32 = 0xc0220021; -pub const SMB_NTSTATUS_FWP_ZERO_LENGTH_ARRAY: u32 = 0xc0220022; -pub const SMB_NTSTATUS_FWP_NULL_DISPLAY_NAME: u32 = 0xc0220023; -pub const SMB_NTSTATUS_FWP_INVALID_ACTION_TYPE: u32 = 0xc0220024; -pub const SMB_NTSTATUS_FWP_INVALID_WEIGHT: u32 = 0xc0220025; -pub const SMB_NTSTATUS_FWP_MATCH_TYPE_MISMATCH: u32 = 0xc0220026; -pub const SMB_NTSTATUS_FWP_TYPE_MISMATCH: u32 = 0xc0220027; -pub const SMB_NTSTATUS_FWP_OUT_OF_BOUNDS: u32 = 0xc0220028; -pub const SMB_NTSTATUS_FWP_RESERVED: u32 = 0xc0220029; -pub const SMB_NTSTATUS_FWP_DUPLICATE_CONDITION: u32 = 0xc022002a; -pub const SMB_NTSTATUS_FWP_DUPLICATE_KEYMOD: u32 = 0xc022002b; -pub const SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER: u32 = 0xc022002c; -pub const SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER: u32 = 0xc022002d; -pub const SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER: u32 = 0xc022002e; -pub const SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT: u32 = 0xc022002f; -pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_METHOD: u32 = 0xc0220030; -pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_DH_GROUP: u32 = 0xc0220031; -pub const SMB_NTSTATUS_FWP_EM_NOT_SUPPORTED: u32 = 0xc0220032; -pub const SMB_NTSTATUS_FWP_NEVER_MATCH: u32 = 0xc0220033; -pub const SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_MISMATCH: u32 = 0xc0220034; -pub const SMB_NTSTATUS_FWP_INVALID_PARAMETER: u32 = 0xc0220035; -pub const SMB_NTSTATUS_FWP_TOO_MANY_SUBLAYERS: u32 = 0xc0220036; -pub const SMB_NTSTATUS_FWP_CALLOUT_NOTIFICATION_FAILED: u32 = 0xc0220037; -pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_CONFIG: u32 = 0xc0220038; -pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG: u32 = 0xc0220039; -pub const SMB_NTSTATUS_FWP_DUPLICATE_AUTH_METHOD: u32 = 0xc022003c; -pub const SMB_NTSTATUS_FWP_TCPIP_NOT_READY: u32 = 0xc0220100; -pub const SMB_NTSTATUS_FWP_INJECT_HANDLE_CLOSING: u32 = 0xc0220101; -pub const SMB_NTSTATUS_FWP_INJECT_HANDLE_STALE: u32 = 0xc0220102; -pub const SMB_NTSTATUS_FWP_CANNOT_PEND: u32 = 0xc0220103; -pub const SMB_NTSTATUS_NDIS_CLOSING: u32 = 0xc0230002; -pub const SMB_NTSTATUS_NDIS_BAD_VERSION: u32 = 0xc0230004; -pub const SMB_NTSTATUS_NDIS_BAD_CHARACTERISTICS: u32 = 0xc0230005; -pub const SMB_NTSTATUS_NDIS_ADAPTER_NOT_FOUND: u32 = 0xc0230006; -pub const SMB_NTSTATUS_NDIS_OPEN_FAILED: u32 = 0xc0230007; -pub const SMB_NTSTATUS_NDIS_DEVICE_FAILED: u32 = 0xc0230008; -pub const SMB_NTSTATUS_NDIS_MULTICAST_FULL: u32 = 0xc0230009; -pub const SMB_NTSTATUS_NDIS_MULTICAST_EXISTS: u32 = 0xc023000a; -pub const SMB_NTSTATUS_NDIS_MULTICAST_NOT_FOUND: u32 = 0xc023000b; -pub const SMB_NTSTATUS_NDIS_REQUEST_ABORTED: u32 = 0xc023000c; -pub const SMB_NTSTATUS_NDIS_RESET_IN_PROGRESS: u32 = 0xc023000d; -pub const SMB_NTSTATUS_NDIS_INVALID_PACKET: u32 = 0xc023000f; -pub const SMB_NTSTATUS_NDIS_INVALID_DEVICE_REQUEST: u32 = 0xc0230010; -pub const SMB_NTSTATUS_NDIS_ADAPTER_NOT_READY: u32 = 0xc0230011; -pub const SMB_NTSTATUS_NDIS_INVALID_LENGTH: u32 = 0xc0230014; -pub const SMB_NTSTATUS_NDIS_INVALID_DATA: u32 = 0xc0230015; -pub const SMB_NTSTATUS_NDIS_BUFFER_TOO_SHORT: u32 = 0xc0230016; -pub const SMB_NTSTATUS_NDIS_INVALID_OID: u32 = 0xc0230017; -pub const SMB_NTSTATUS_NDIS_ADAPTER_REMOVED: u32 = 0xc0230018; -pub const SMB_NTSTATUS_NDIS_UNSUPPORTED_MEDIA: u32 = 0xc0230019; -pub const SMB_NTSTATUS_NDIS_GROUP_ADDRESS_IN_USE: u32 = 0xc023001a; -pub const SMB_NTSTATUS_NDIS_FILE_NOT_FOUND: u32 = 0xc023001b; -pub const SMB_NTSTATUS_NDIS_ERROR_READING_FILE: u32 = 0xc023001c; -pub const SMB_NTSTATUS_NDIS_ALREADY_MAPPED: u32 = 0xc023001d; -pub const SMB_NTSTATUS_NDIS_RESOURCE_CONFLICT: u32 = 0xc023001e; -pub const SMB_NTSTATUS_NDIS_MEDIA_DISCONNECTED: u32 = 0xc023001f; -pub const SMB_NTSTATUS_NDIS_INVALID_ADDRESS: u32 = 0xc0230022; -pub const SMB_NTSTATUS_NDIS_PAUSED: u32 = 0xc023002a; -pub const SMB_NTSTATUS_NDIS_INTERFACE_NOT_FOUND: u32 = 0xc023002b; -pub const SMB_NTSTATUS_NDIS_UNSUPPORTED_REVISION: u32 = 0xc023002c; -pub const SMB_NTSTATUS_NDIS_INVALID_PORT: u32 = 0xc023002d; -pub const SMB_NTSTATUS_NDIS_INVALID_PORT_STATE: u32 = 0xc023002e; -pub const SMB_NTSTATUS_NDIS_LOW_POWER_STATE: u32 = 0xc023002f; -pub const SMB_NTSTATUS_NDIS_NOT_SUPPORTED: u32 = 0xc02300bb; -pub const SMB_NTSTATUS_NDIS_OFFLOAD_POLICY: u32 = 0xc023100f; -pub const SMB_NTSTATUS_NDIS_OFFLOAD_CONNECTION_REJECTED: u32 = 0xc0231012; -pub const SMB_NTSTATUS_NDIS_OFFLOAD_PATH_REJECTED: u32 = 0xc0231013; -pub const SMB_NTSTATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED: u32 = 0xc0232000; -pub const SMB_NTSTATUS_NDIS_DOT11_MEDIA_IN_USE: u32 = 0xc0232001; -pub const SMB_NTSTATUS_NDIS_DOT11_POWER_STATE_INVALID: u32 = 0xc0232002; -pub const SMB_NTSTATUS_NDIS_PM_WOL_PATTERN_LIST_FULL: u32 = 0xc0232003; -pub const SMB_NTSTATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL: u32 = 0xc0232004; -pub const SMB_NTSTATUS_IPSEC_BAD_SPI: u32 = 0xc0360001; -pub const SMB_NTSTATUS_IPSEC_SA_LIFETIME_EXPIRED: u32 = 0xc0360002; -pub const SMB_NTSTATUS_IPSEC_WRONG_SA: u32 = 0xc0360003; -pub const SMB_NTSTATUS_IPSEC_REPLAY_CHECK_FAILED: u32 = 0xc0360004; -pub const SMB_NTSTATUS_IPSEC_INVALID_PACKET: u32 = 0xc0360005; -pub const SMB_NTSTATUS_IPSEC_INTEGRITY_CHECK_FAILED: u32 = 0xc0360006; -pub const SMB_NTSTATUS_IPSEC_CLEAR_TEXT_DROP: u32 = 0xc0360007; -pub const SMB_NTSTATUS_IPSEC_AUTH_FIREWALL_DROP: u32 = 0xc0360008; -pub const SMB_NTSTATUS_IPSEC_THROTTLE_DROP: u32 = 0xc0360009; -pub const SMB_NTSTATUS_IPSEC_DOSP_BLOCK: u32 = 0xc0368000; -pub const SMB_NTSTATUS_IPSEC_DOSP_RECEIVED_MULTICAST: u32 = 0xc0368001; -pub const SMB_NTSTATUS_IPSEC_DOSP_INVALID_PACKET: u32 = 0xc0368002; -pub const SMB_NTSTATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED: u32 = 0xc0368003; -pub const SMB_NTSTATUS_IPSEC_DOSP_MAX_ENTRIES: u32 = 0xc0368004; -pub const SMB_NTSTATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED: u32 = 0xc0368005; -pub const SMB_NTSTATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES: u32 = 0xc0368006; -pub const SMB_NTSTATUS_VOLMGR_MIRROR_NOT_SUPPORTED: u32 = 0xc038005b; -pub const SMB_NTSTATUS_VOLMGR_RAID5_NOT_SUPPORTED: u32 = 0xc038005c; -pub const SMB_NTSTATUS_VIRTDISK_PROVIDER_NOT_FOUND: u32 = 0xc03a0014; -pub const SMB_NTSTATUS_VIRTDISK_NOT_VIRTUAL_DISK: u32 = 0xc03a0015; -pub const SMB_NTSTATUS_VHD_PARENT_VHD_ACCESS_DENIED: u32 = 0xc03a0016; -pub const SMB_NTSTATUS_VHD_CHILD_PARENT_SIZE_MISMATCH: u32 = 0xc03a0017; -pub const SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED: u32 = 0xc03a0018; -pub const SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT: u32 = 0xc03a0019; +pub const SMB_NTSTATUS_SUCCESS: u32 = 0x00000000; +pub const SMB_NTSTATUS_WAIT_1: u32 = 0x00000001; +pub const SMB_NTSTATUS_WAIT_2: u32 = 0x00000002; +pub const SMB_NTSTATUS_WAIT_3: u32 = 0x00000003; +pub const SMB_NTSTATUS_WAIT_63: u32 = 0x0000003f; +pub const SMB_NTSTATUS_ABANDONED: u32 = 0x00000080; +pub const SMB_NTSTATUS_ABANDONED_WAIT_63: u32 = 0x000000bf; +pub const SMB_NTSTATUS_USER_APC: u32 = 0x000000c0; +pub const SMB_NTSTATUS_ALERTED: u32 = 0x00000101; +pub const SMB_NTSTATUS_TIMEOUT: u32 = 0x00000102; +pub const SMB_NTSTATUS_PENDING: u32 = 0x00000103; +pub const SMB_NTSTATUS_REPARSE: u32 = 0x00000104; +pub const SMB_NTSTATUS_MORE_ENTRIES: u32 = 0x00000105; +pub const SMB_NTSTATUS_NOT_ALL_ASSIGNED: u32 = 0x00000106; +pub const SMB_NTSTATUS_SOME_NOT_MAPPED: u32 = 0x00000107; +pub const SMB_NTSTATUS_OPLOCK_BREAK_IN_PROGRESS: u32 = 0x00000108; +pub const SMB_NTSTATUS_VOLUME_MOUNTED: u32 = 0x00000109; +pub const SMB_NTSTATUS_RXACT_COMMITTED: u32 = 0x0000010a; +pub const SMB_NTSTATUS_NOTIFY_CLEANUP: u32 = 0x0000010b; +pub const SMB_NTSTATUS_NOTIFY_ENUM_DIR: u32 = 0x0000010c; +pub const SMB_NTSTATUS_NO_QUOTAS_FOR_ACCOUNT: u32 = 0x0000010d; +pub const SMB_NTSTATUS_PRIMARY_TRANSPORT_CONNECT_FAILED: u32 = 0x0000010e; +pub const SMB_NTSTATUS_PAGE_FAULT_TRANSITION: u32 = 0x00000110; +pub const SMB_NTSTATUS_PAGE_FAULT_DEMAND_ZERO: u32 = 0x00000111; +pub const SMB_NTSTATUS_PAGE_FAULT_COPY_ON_WRITE: u32 = 0x00000112; +pub const SMB_NTSTATUS_PAGE_FAULT_GUARD_PAGE: u32 = 0x00000113; +pub const SMB_NTSTATUS_PAGE_FAULT_PAGING_FILE: u32 = 0x00000114; +pub const SMB_NTSTATUS_CACHE_PAGE_LOCKED: u32 = 0x00000115; +pub const SMB_NTSTATUS_CRASH_DUMP: u32 = 0x00000116; +pub const SMB_NTSTATUS_BUFFER_ALL_ZEROS: u32 = 0x00000117; +pub const SMB_NTSTATUS_REPARSE_OBJECT: u32 = 0x00000118; +pub const SMB_NTSTATUS_RESOURCE_REQUIREMENTS_CHANGED: u32 = 0x00000119; +pub const SMB_NTSTATUS_TRANSLATION_COMPLETE: u32 = 0x00000120; +pub const SMB_NTSTATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY: u32 = 0x00000121; +pub const SMB_NTSTATUS_NOTHING_TO_TERMINATE: u32 = 0x00000122; +pub const SMB_NTSTATUS_PROCESS_NOT_IN_JOB: u32 = 0x00000123; +pub const SMB_NTSTATUS_PROCESS_IN_JOB: u32 = 0x00000124; +pub const SMB_NTSTATUS_VOLSNAP_HIBERNATE_READY: u32 = 0x00000125; +pub const SMB_NTSTATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY: u32 = 0x00000126; +pub const SMB_NTSTATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: u32 = 0x00000127; +pub const SMB_NTSTATUS_INTERRUPT_STILL_CONNECTED: u32 = 0x00000128; +pub const SMB_NTSTATUS_PROCESS_CLONED: u32 = 0x00000129; +pub const SMB_NTSTATUS_FILE_LOCKED_WITH_ONLY_READERS: u32 = 0x0000012a; +pub const SMB_NTSTATUS_FILE_LOCKED_WITH_WRITERS: u32 = 0x0000012b; +pub const SMB_NTSTATUS_RESOURCEMANAGER_READ_ONLY: u32 = 0x00000202; +pub const SMB_NTSTATUS_WAIT_FOR_OPLOCK: u32 = 0x00000367; +pub const SMB_NTDBG_EXCEPTION_HANDLED: u32 = 0x00010001; +pub const SMB_NTDBG_CONTINUE: u32 = 0x00010002; +pub const SMB_NTSTATUS_FLT_IO_COMPLETE: u32 = 0x001c0001; +pub const SMB_NTSTATUS_FILE_NOT_AVAILABLE: u32 = 0xc0000467; +pub const SMB_NTSTATUS_SHARE_UNAVAILABLE: u32 = 0xc0000480; +pub const SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_AFFINITY: u32 = 0xc0000721; +pub const SMB_NTSTATUS_OBJECT_NAME_EXISTS: u32 = 0x40000000; +pub const SMB_NTSTATUS_THREAD_WAS_SUSPENDED: u32 = 0x40000001; +pub const SMB_NTSTATUS_WORKING_SET_LIMIT_RANGE: u32 = 0x40000002; +pub const SMB_NTSTATUS_IMAGE_NOT_AT_BASE: u32 = 0x40000003; +pub const SMB_NTSTATUS_RXACT_STATE_CREATED: u32 = 0x40000004; +pub const SMB_NTSTATUS_SEGMENT_NOTIFICATION: u32 = 0x40000005; +pub const SMB_NTSTATUS_LOCAL_USER_SESSION_KEY: u32 = 0x40000006; +pub const SMB_NTSTATUS_BAD_CURRENT_DIRECTORY: u32 = 0x40000007; +pub const SMB_NTSTATUS_SERIAL_MORE_WRITES: u32 = 0x40000008; +pub const SMB_NTSTATUS_REGISTRY_RECOVERED: u32 = 0x40000009; +pub const SMB_NTSTATUS_FT_READ_RECOVERY_FROM_BACKUP: u32 = 0x4000000a; +pub const SMB_NTSTATUS_FT_WRITE_RECOVERY: u32 = 0x4000000b; +pub const SMB_NTSTATUS_SERIAL_COUNTER_TIMEOUT: u32 = 0x4000000c; +pub const SMB_NTSTATUS_NULL_LM_PASSWORD: u32 = 0x4000000d; +pub const SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH: u32 = 0x4000000e; +pub const SMB_NTSTATUS_RECEIVE_PARTIAL: u32 = 0x4000000f; +pub const SMB_NTSTATUS_RECEIVE_EXPEDITED: u32 = 0x40000010; +pub const SMB_NTSTATUS_RECEIVE_PARTIAL_EXPEDITED: u32 = 0x40000011; +pub const SMB_NTSTATUS_EVENT_DONE: u32 = 0x40000012; +pub const SMB_NTSTATUS_EVENT_PENDING: u32 = 0x40000013; +pub const SMB_NTSTATUS_CHECKING_FILE_SYSTEM: u32 = 0x40000014; +pub const SMB_NTSTATUS_FATAL_APP_EXIT: u32 = 0x40000015; +pub const SMB_NTSTATUS_PREDEFINED_HANDLE: u32 = 0x40000016; +pub const SMB_NTSTATUS_WAS_UNLOCKED: u32 = 0x40000017; +pub const SMB_NTSTATUS_SERVICE_NOTIFICATION: u32 = 0x40000018; +pub const SMB_NTSTATUS_WAS_LOCKED: u32 = 0x40000019; +pub const SMB_NTSTATUS_LOG_HARD_ERROR: u32 = 0x4000001a; +pub const SMB_NTSTATUS_ALREADY_WIN32: u32 = 0x4000001b; +pub const SMB_NTSTATUS_WX86_UNSIMULATE: u32 = 0x4000001c; +pub const SMB_NTSTATUS_WX86_CONTINUE: u32 = 0x4000001d; +pub const SMB_NTSTATUS_WX86_SINGLE_STEP: u32 = 0x4000001e; +pub const SMB_NTSTATUS_WX86_BREAKPOINT: u32 = 0x4000001f; +pub const SMB_NTSTATUS_WX86_EXCEPTION_CONTINUE: u32 = 0x40000020; +pub const SMB_NTSTATUS_WX86_EXCEPTION_LASTCHANCE: u32 = 0x40000021; +pub const SMB_NTSTATUS_WX86_EXCEPTION_CHAIN: u32 = 0x40000022; +pub const SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: u32 = 0x40000023; +pub const SMB_NTSTATUS_NO_YIELD_PERFORMED: u32 = 0x40000024; +pub const SMB_NTSTATUS_TIMER_RESUME_IGNORED: u32 = 0x40000025; +pub const SMB_NTSTATUS_ARBITRATION_UNHANDLED: u32 = 0x40000026; +pub const SMB_NTSTATUS_CARDBUS_NOT_SUPPORTED: u32 = 0x40000027; +pub const SMB_NTSTATUS_WX86_CREATEWX86TIB: u32 = 0x40000028; +pub const SMB_NTSTATUS_MP_PROCESSOR_MISMATCH: u32 = 0x40000029; +pub const SMB_NTSTATUS_HIBERNATED: u32 = 0x4000002a; +pub const SMB_NTSTATUS_RESUME_HIBERNATION: u32 = 0x4000002b; +pub const SMB_NTSTATUS_FIRMWARE_UPDATED: u32 = 0x4000002c; +pub const SMB_NTSTATUS_DRIVERS_LEAKING_LOCKED_PAGES: u32 = 0x4000002d; +pub const SMB_NTSTATUS_MESSAGE_RETRIEVED: u32 = 0x4000002e; +pub const SMB_NTSTATUS_SYSTEM_POWERSTATE_TRANSITION: u32 = 0x4000002f; +pub const SMB_NTSTATUS_ALPC_CHECK_COMPLETION_LIST: u32 = 0x40000030; +pub const SMB_NTSTATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION: u32 = 0x40000031; +pub const SMB_NTSTATUS_ACCESS_AUDIT_BY_POLICY: u32 = 0x40000032; +pub const SMB_NTSTATUS_ABANDON_HIBERFILE: u32 = 0x40000033; +pub const SMB_NTSTATUS_BIZRULES_NOT_ENABLED: u32 = 0x40000034; +pub const SMB_NTSTATUS_WAKE_SYSTEM: u32 = 0x40000294; +pub const SMB_NTSTATUS_DS_SHUTTING_DOWN: u32 = 0x40000370; +pub const SMB_NTDBG_REPLY_LATER: u32 = 0x40010001; +pub const SMB_NTDBG_UNABLE_TO_PROVIDE_HANDLE: u32 = 0x40010002; +pub const SMB_NTDBG_TERMINATE_THREAD: u32 = 0x40010003; +pub const SMB_NTDBG_TERMINATE_PROCESS: u32 = 0x40010004; +pub const SMB_NTDBG_CONTROL_C: u32 = 0x40010005; +pub const SMB_NTDBG_PRINTEXCEPTION_C: u32 = 0x40010006; +pub const SMB_NTDBG_RIPEXCEPTION: u32 = 0x40010007; +pub const SMB_NTDBG_CONTROL_BREAK: u32 = 0x40010008; +pub const SMB_NTDBG_COMMAND_EXCEPTION: u32 = 0x40010009; +pub const SMB_NTRPC_NT_UUID_LOCAL_ONLY: u32 = 0x40020056; +pub const SMB_NTRPC_NT_SEND_INCOMPLETE: u32 = 0x400200af; +pub const SMB_NTSTATUS_CTX_CDM_CONNECT: u32 = 0x400a0004; +pub const SMB_NTSTATUS_CTX_CDM_DISCONNECT: u32 = 0x400a0005; +pub const SMB_NTSTATUS_SXS_RELEASE_ACTIVATION_CONTEXT: u32 = 0x4015000d; +pub const SMB_NTSTATUS_RECOVERY_NOT_NEEDED: u32 = 0x40190034; +pub const SMB_NTSTATUS_RM_ALREADY_STARTED: u32 = 0x40190035; +pub const SMB_NTSTATUS_LOG_NO_RESTART: u32 = 0x401a000c; +pub const SMB_NTSTATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST: u32 = 0x401b00ec; +pub const SMB_NTSTATUS_GRAPHICS_PARTIAL_DATA_POPULATED: u32 = 0x401e000a; +pub const SMB_NTSTATUS_GRAPHICS_DRIVER_MISMATCH: u32 = 0x401e0117; +pub const SMB_NTSTATUS_GRAPHICS_MODE_NOT_PINNED: u32 = 0x401e0307; +pub const SMB_NTSTATUS_GRAPHICS_NO_PREFERRED_MODE: u32 = 0x401e031e; +pub const SMB_NTSTATUS_GRAPHICS_DATASET_IS_EMPTY: u32 = 0x401e034b; +pub const SMB_NTSTATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET: u32 = 0x401e034c; +pub const SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED: u32 = 0x401e0351; +pub const SMB_NTSTATUS_GRAPHICS_UNKNOWN_CHILD_STATUS: u32 = 0x401e042f; +pub const SMB_NTSTATUS_GRAPHICS_LEADLINK_START_DEFERRED: u32 = 0x401e0437; +pub const SMB_NTSTATUS_GRAPHICS_POLLING_TOO_FREQUENTLY: u32 = 0x401e0439; +pub const SMB_NTSTATUS_GRAPHICS_START_DEFERRED: u32 = 0x401e043a; +pub const SMB_NTSTATUS_NDIS_INDICATION_REQUIRED: u32 = 0x40230001; +pub const SMB_NTSTATUS_GUARD_PAGE_VIOLATION: u32 = 0x80000001; +pub const SMB_NTSTATUS_DATATYPE_MISALIGNMENT: u32 = 0x80000002; +pub const SMB_NTSTATUS_BREAKPOINT: u32 = 0x80000003; +pub const SMB_NTSTATUS_SINGLE_STEP: u32 = 0x80000004; +pub const SMB_NTSTATUS_BUFFER_OVERFLOW: u32 = 0x80000005; +pub const SMB_NTSTATUS_NO_MORE_FILES: u32 = 0x80000006; +pub const SMB_NTSTATUS_WAKE_SYSTEM_DEBUGGER: u32 = 0x80000007; +pub const SMB_NTSTATUS_HANDLES_CLOSED: u32 = 0x8000000a; +pub const SMB_NTSTATUS_NO_INHERITANCE: u32 = 0x8000000b; +pub const SMB_NTSTATUS_GUID_SUBSTITUTION_MADE: u32 = 0x8000000c; +pub const SMB_NTSTATUS_PARTIAL_COPY: u32 = 0x8000000d; +pub const SMB_NTSTATUS_DEVICE_PAPER_EMPTY: u32 = 0x8000000e; +pub const SMB_NTSTATUS_DEVICE_POWERED_OFF: u32 = 0x8000000f; +pub const SMB_NTSTATUS_DEVICE_OFF_LINE: u32 = 0x80000010; +pub const SMB_NTSTATUS_DEVICE_BUSY: u32 = 0x80000011; +pub const SMB_NTSTATUS_NO_MORE_EAS: u32 = 0x80000012; +pub const SMB_NTSTATUS_INVALID_EA_NAME: u32 = 0x80000013; +pub const SMB_NTSTATUS_EA_LIST_INCONSISTENT: u32 = 0x80000014; +pub const SMB_NTSTATUS_INVALID_EA_FLAG: u32 = 0x80000015; +pub const SMB_NTSTATUS_VERIFY_REQUIRED: u32 = 0x80000016; +pub const SMB_NTSTATUS_EXTRANEOUS_INFORMATION: u32 = 0x80000017; +pub const SMB_NTSTATUS_RXACT_COMMIT_NECESSARY: u32 = 0x80000018; +pub const SMB_NTSTATUS_NO_MORE_ENTRIES: u32 = 0x8000001a; +pub const SMB_NTSTATUS_FILEMARK_DETECTED: u32 = 0x8000001b; +pub const SMB_NTSTATUS_MEDIA_CHANGED: u32 = 0x8000001c; +pub const SMB_NTSTATUS_BUS_RESET: u32 = 0x8000001d; +pub const SMB_NTSTATUS_END_OF_MEDIA: u32 = 0x8000001e; +pub const SMB_NTSTATUS_BEGINNING_OF_MEDIA: u32 = 0x8000001f; +pub const SMB_NTSTATUS_MEDIA_CHECK: u32 = 0x80000020; +pub const SMB_NTSTATUS_SETMARK_DETECTED: u32 = 0x80000021; +pub const SMB_NTSTATUS_NO_DATA_DETECTED: u32 = 0x80000022; +pub const SMB_NTSTATUS_REDIRECTOR_HAS_OPEN_HANDLES: u32 = 0x80000023; +pub const SMB_NTSTATUS_SERVER_HAS_OPEN_HANDLES: u32 = 0x80000024; +pub const SMB_NTSTATUS_ALREADY_DISCONNECTED: u32 = 0x80000025; +pub const SMB_NTSTATUS_LONGJUMP: u32 = 0x80000026; +pub const SMB_NTSTATUS_CLEANER_CARTRIDGE_INSTALLED: u32 = 0x80000027; +pub const SMB_NTSTATUS_PLUGPLAY_QUERY_VETOED: u32 = 0x80000028; +pub const SMB_NTSTATUS_UNWIND_CONSOLIDATE: u32 = 0x80000029; +pub const SMB_NTSTATUS_REGISTRY_HIVE_RECOVERED: u32 = 0x8000002a; +pub const SMB_NTSTATUS_DLL_MIGHT_BE_INSECURE: u32 = 0x8000002b; +pub const SMB_NTSTATUS_DLL_MIGHT_BE_INCOMPATIBLE: u32 = 0x8000002c; +pub const SMB_NTSTATUS_STOPPED_ON_SYMLINK: u32 = 0x8000002d; +pub const SMB_NTSTATUS_DEVICE_REQUIRES_CLEANING: u32 = 0x80000288; +pub const SMB_NTSTATUS_DEVICE_DOOR_OPEN: u32 = 0x80000289; +pub const SMB_NTSTATUS_DATA_LOST_REPAIR: u32 = 0x80000803; +pub const SMB_NTDBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001; +pub const SMB_NTSTATUS_CLUSTER_NODE_ALREADY_UP: u32 = 0x80130001; +pub const SMB_NTSTATUS_CLUSTER_NODE_ALREADY_DOWN: u32 = 0x80130002; +pub const SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_ONLINE: u32 = 0x80130003; +pub const SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_OFFLINE: u32 = 0x80130004; +pub const SMB_NTSTATUS_CLUSTER_NODE_ALREADY_MEMBER: u32 = 0x80130005; +pub const SMB_NTSTATUS_COULD_NOT_RESIZE_LOG: u32 = 0x80190009; +pub const SMB_NTSTATUS_NO_TXF_METADATA: u32 = 0x80190029; +pub const SMB_NTSTATUS_CANT_RECOVER_WITH_HANDLE_OPEN: u32 = 0x80190031; +pub const SMB_NTSTATUS_TXF_METADATA_ALREADY_PRESENT: u32 = 0x80190041; +pub const SMB_NTSTATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET: u32 = 0x80190042; +pub const SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED: u32 = 0x801b00eb; +pub const SMB_NTSTATUS_FLT_BUFFER_TOO_SMALL: u32 = 0x801c0001; +pub const SMB_NTSTATUS_FVE_PARTIAL_METADATA: u32 = 0x80210001; +pub const SMB_NTSTATUS_FVE_TRANSIENT_STATE: u32 = 0x80210002; +pub const SMB_NTSTATUS_UNSUCCESSFUL: u32 = 0xc0000001; +pub const SMB_NTSTATUS_NOT_IMPLEMENTED: u32 = 0xc0000002; +pub const SMB_NTSTATUS_INVALID_INFO_CLASS: u32 = 0xc0000003; +pub const SMB_NTSTATUS_INFO_LENGTH_MISMATCH: u32 = 0xc0000004; +pub const SMB_NTSTATUS_ACCESS_VIOLATION: u32 = 0xc0000005; +pub const SMB_NTSTATUS_IN_PAGE_ERROR: u32 = 0xc0000006; +pub const SMB_NTSTATUS_PAGEFILE_QUOTA: u32 = 0xc0000007; +pub const SMB_NTSTATUS_INVALID_HANDLE: u32 = 0xc0000008; +pub const SMB_NTSTATUS_BAD_INITIAL_STACK: u32 = 0xc0000009; +pub const SMB_NTSTATUS_BAD_INITIAL_PC: u32 = 0xc000000a; +pub const SMB_NTSTATUS_INVALID_CID: u32 = 0xc000000b; +pub const SMB_NTSTATUS_TIMER_NOT_CANCELED: u32 = 0xc000000c; +pub const SMB_NTSTATUS_INVALID_PARAMETER: u32 = 0xc000000d; +pub const SMB_NTSTATUS_NO_SUCH_DEVICE: u32 = 0xc000000e; +pub const SMB_NTSTATUS_NO_SUCH_FILE: u32 = 0xc000000f; +pub const SMB_NTSTATUS_INVALID_DEVICE_REQUEST: u32 = 0xc0000010; +pub const SMB_NTSTATUS_END_OF_FILE: u32 = 0xc0000011; +pub const SMB_NTSTATUS_WRONG_VOLUME: u32 = 0xc0000012; +pub const SMB_NTSTATUS_NO_MEDIA_IN_DEVICE: u32 = 0xc0000013; +pub const SMB_NTSTATUS_UNRECOGNIZED_MEDIA: u32 = 0xc0000014; +pub const SMB_NTSTATUS_NONEXISTENT_SECTOR: u32 = 0xc0000015; +pub const SMB_NTSTATUS_MORE_PROCESSING_REQUIRED: u32 = 0xc0000016; +pub const SMB_NTSTATUS_NO_MEMORY: u32 = 0xc0000017; +pub const SMB_NTSTATUS_CONFLICTING_ADDRESSES: u32 = 0xc0000018; +pub const SMB_NTSTATUS_NOT_MAPPED_VIEW: u32 = 0xc0000019; +pub const SMB_NTSTATUS_UNABLE_TO_FREE_VM: u32 = 0xc000001a; +pub const SMB_NTSTATUS_UNABLE_TO_DELETE_SECTION: u32 = 0xc000001b; +pub const SMB_NTSTATUS_INVALID_SYSTEM_SERVICE: u32 = 0xc000001c; +pub const SMB_NTSTATUS_ILLEGAL_INSTRUCTION: u32 = 0xc000001d; +pub const SMB_NTSTATUS_INVALID_LOCK_SEQUENCE: u32 = 0xc000001e; +pub const SMB_NTSTATUS_INVALID_VIEW_SIZE: u32 = 0xc000001f; +pub const SMB_NTSTATUS_INVALID_FILE_FOR_SECTION: u32 = 0xc0000020; +pub const SMB_NTSTATUS_ALREADY_COMMITTED: u32 = 0xc0000021; +pub const SMB_NTSTATUS_ACCESS_DENIED: u32 = 0xc0000022; +pub const SMB_NTSTATUS_BUFFER_TOO_SMALL: u32 = 0xc0000023; +pub const SMB_NTSTATUS_OBJECT_TYPE_MISMATCH: u32 = 0xc0000024; +pub const SMB_NTSTATUS_NONCONTINUABLE_EXCEPTION: u32 = 0xc0000025; +pub const SMB_NTSTATUS_INVALID_DISPOSITION: u32 = 0xc0000026; +pub const SMB_NTSTATUS_UNWIND: u32 = 0xc0000027; +pub const SMB_NTSTATUS_BAD_STACK: u32 = 0xc0000028; +pub const SMB_NTSTATUS_INVALID_UNWIND_TARGET: u32 = 0xc0000029; +pub const SMB_NTSTATUS_NOT_LOCKED: u32 = 0xc000002a; +pub const SMB_NTSTATUS_PARITY_ERROR: u32 = 0xc000002b; +pub const SMB_NTSTATUS_UNABLE_TO_DECOMMIT_VM: u32 = 0xc000002c; +pub const SMB_NTSTATUS_NOT_COMMITTED: u32 = 0xc000002d; +pub const SMB_NTSTATUS_INVALID_PORT_ATTRIBUTES: u32 = 0xc000002e; +pub const SMB_NTSTATUS_PORT_MESSAGE_TOO_LONG: u32 = 0xc000002f; +pub const SMB_NTSTATUS_INVALID_PARAMETER_MIX: u32 = 0xc0000030; +pub const SMB_NTSTATUS_INVALID_QUOTA_LOWER: u32 = 0xc0000031; +pub const SMB_NTSTATUS_DISK_CORRUPT_ERROR: u32 = 0xc0000032; +pub const SMB_NTSTATUS_OBJECT_NAME_INVALID: u32 = 0xc0000033; +pub const SMB_NTSTATUS_OBJECT_NAME_NOT_FOUND: u32 = 0xc0000034; +pub const SMB_NTSTATUS_OBJECT_NAME_COLLISION: u32 = 0xc0000035; +pub const SMB_NTSTATUS_PORT_DISCONNECTED: u32 = 0xc0000037; +pub const SMB_NTSTATUS_DEVICE_ALREADY_ATTACHED: u32 = 0xc0000038; +pub const SMB_NTSTATUS_OBJECT_PATH_INVALID: u32 = 0xc0000039; +pub const SMB_NTSTATUS_OBJECT_PATH_NOT_FOUND: u32 = 0xc000003a; +pub const SMB_NTSTATUS_OBJECT_PATH_SYNTAX_BAD: u32 = 0xc000003b; +pub const SMB_NTSTATUS_DATA_OVERRUN: u32 = 0xc000003c; +pub const SMB_NTSTATUS_DATA_LATE_ERROR: u32 = 0xc000003d; +pub const SMB_NTSTATUS_DATA_ERROR: u32 = 0xc000003e; +pub const SMB_NTSTATUS_CRC_ERROR: u32 = 0xc000003f; +pub const SMB_NTSTATUS_SECTION_TOO_BIG: u32 = 0xc0000040; +pub const SMB_NTSTATUS_PORT_CONNECTION_REFUSED: u32 = 0xc0000041; +pub const SMB_NTSTATUS_INVALID_PORT_HANDLE: u32 = 0xc0000042; +pub const SMB_NTSTATUS_SHARING_VIOLATION: u32 = 0xc0000043; +pub const SMB_NTSTATUS_QUOTA_EXCEEDED: u32 = 0xc0000044; +pub const SMB_NTSTATUS_INVALID_PAGE_PROTECTION: u32 = 0xc0000045; +pub const SMB_NTSTATUS_MUTANT_NOT_OWNED: u32 = 0xc0000046; +pub const SMB_NTSTATUS_SEMAPHORE_LIMIT_EXCEEDED: u32 = 0xc0000047; +pub const SMB_NTSTATUS_PORT_ALREADY_SET: u32 = 0xc0000048; +pub const SMB_NTSTATUS_SECTION_NOT_IMAGE: u32 = 0xc0000049; +pub const SMB_NTSTATUS_SUSPEND_COUNT_EXCEEDED: u32 = 0xc000004a; +pub const SMB_NTSTATUS_THREAD_IS_TERMINATING: u32 = 0xc000004b; +pub const SMB_NTSTATUS_BAD_WORKING_SET_LIMIT: u32 = 0xc000004c; +pub const SMB_NTSTATUS_INCOMPATIBLE_FILE_MAP: u32 = 0xc000004d; +pub const SMB_NTSTATUS_SECTION_PROTECTION: u32 = 0xc000004e; +pub const SMB_NTSTATUS_EAS_NOT_SUPPORTED: u32 = 0xc000004f; +pub const SMB_NTSTATUS_EA_TOO_LARGE: u32 = 0xc0000050; +pub const SMB_NTSTATUS_NONEXISTENT_EA_ENTRY: u32 = 0xc0000051; +pub const SMB_NTSTATUS_NO_EAS_ON_FILE: u32 = 0xc0000052; +pub const SMB_NTSTATUS_EA_CORRUPT_ERROR: u32 = 0xc0000053; +pub const SMB_NTSTATUS_FILE_LOCK_CONFLICT: u32 = 0xc0000054; +pub const SMB_NTSTATUS_LOCK_NOT_GRANTED: u32 = 0xc0000055; +pub const SMB_NTSTATUS_DELETE_PENDING: u32 = 0xc0000056; +pub const SMB_NTSTATUS_CTL_FILE_NOT_SUPPORTED: u32 = 0xc0000057; +pub const SMB_NTSTATUS_UNKNOWN_REVISION: u32 = 0xc0000058; +pub const SMB_NTSTATUS_REVISION_MISMATCH: u32 = 0xc0000059; +pub const SMB_NTSTATUS_INVALID_OWNER: u32 = 0xc000005a; +pub const SMB_NTSTATUS_INVALID_PRIMARY_GROUP: u32 = 0xc000005b; +pub const SMB_NTSTATUS_NO_IMPERSONATION_TOKEN: u32 = 0xc000005c; +pub const SMB_NTSTATUS_CANT_DISABLE_MANDATORY: u32 = 0xc000005d; +pub const SMB_NTSTATUS_NO_LOGON_SERVERS: u32 = 0xc000005e; +pub const SMB_NTSTATUS_NO_SUCH_LOGON_SESSION: u32 = 0xc000005f; +pub const SMB_NTSTATUS_NO_SUCH_PRIVILEGE: u32 = 0xc0000060; +pub const SMB_NTSTATUS_PRIVILEGE_NOT_HELD: u32 = 0xc0000061; +pub const SMB_NTSTATUS_INVALID_ACCOUNT_NAME: u32 = 0xc0000062; +pub const SMB_NTSTATUS_USER_EXISTS: u32 = 0xc0000063; +pub const SMB_NTSTATUS_NO_SUCH_USER: u32 = 0xc0000064; +pub const SMB_NTSTATUS_GROUP_EXISTS: u32 = 0xc0000065; +pub const SMB_NTSTATUS_NO_SUCH_GROUP: u32 = 0xc0000066; +pub const SMB_NTSTATUS_MEMBER_IN_GROUP: u32 = 0xc0000067; +pub const SMB_NTSTATUS_MEMBER_NOT_IN_GROUP: u32 = 0xc0000068; +pub const SMB_NTSTATUS_LAST_ADMIN: u32 = 0xc0000069; +pub const SMB_NTSTATUS_WRONG_PASSWORD: u32 = 0xc000006a; +pub const SMB_NTSTATUS_ILL_FORMED_PASSWORD: u32 = 0xc000006b; +pub const SMB_NTSTATUS_PASSWORD_RESTRICTION: u32 = 0xc000006c; +pub const SMB_NTSTATUS_LOGON_FAILURE: u32 = 0xc000006d; +pub const SMB_NTSTATUS_ACCOUNT_RESTRICTION: u32 = 0xc000006e; +pub const SMB_NTSTATUS_INVALID_LOGON_HOURS: u32 = 0xc000006f; +pub const SMB_NTSTATUS_INVALID_WORKSTATION: u32 = 0xc0000070; +pub const SMB_NTSTATUS_PASSWORD_EXPIRED: u32 = 0xc0000071; +pub const SMB_NTSTATUS_ACCOUNT_DISABLED: u32 = 0xc0000072; +pub const SMB_NTSTATUS_NONE_MAPPED: u32 = 0xc0000073; +pub const SMB_NTSTATUS_TOO_MANY_LUIDS_REQUESTED: u32 = 0xc0000074; +pub const SMB_NTSTATUS_LUIDS_EXHAUSTED: u32 = 0xc0000075; +pub const SMB_NTSTATUS_INVALID_SUB_AUTHORITY: u32 = 0xc0000076; +pub const SMB_NTSTATUS_INVALID_ACL: u32 = 0xc0000077; +pub const SMB_NTSTATUS_INVALID_SID: u32 = 0xc0000078; +pub const SMB_NTSTATUS_INVALID_SECURITY_DESCR: u32 = 0xc0000079; +pub const SMB_NTSTATUS_PROCEDURE_NOT_FOUND: u32 = 0xc000007a; +pub const SMB_NTSTATUS_INVALID_IMAGE_FORMAT: u32 = 0xc000007b; +pub const SMB_NTSTATUS_NO_TOKEN: u32 = 0xc000007c; +pub const SMB_NTSTATUS_BAD_INHERITANCE_ACL: u32 = 0xc000007d; +pub const SMB_NTSTATUS_RANGE_NOT_LOCKED: u32 = 0xc000007e; +pub const SMB_NTSTATUS_DISK_FULL: u32 = 0xc000007f; +pub const SMB_NTSTATUS_SERVER_DISABLED: u32 = 0xc0000080; +pub const SMB_NTSTATUS_SERVER_NOT_DISABLED: u32 = 0xc0000081; +pub const SMB_NTSTATUS_TOO_MANY_GUIDS_REQUESTED: u32 = 0xc0000082; +pub const SMB_NTSTATUS_GUIDS_EXHAUSTED: u32 = 0xc0000083; +pub const SMB_NTSTATUS_INVALID_ID_AUTHORITY: u32 = 0xc0000084; +pub const SMB_NTSTATUS_AGENTS_EXHAUSTED: u32 = 0xc0000085; +pub const SMB_NTSTATUS_INVALID_VOLUME_LABEL: u32 = 0xc0000086; +pub const SMB_NTSTATUS_SECTION_NOT_EXTENDED: u32 = 0xc0000087; +pub const SMB_NTSTATUS_NOT_MAPPED_DATA: u32 = 0xc0000088; +pub const SMB_NTSTATUS_RESOURCE_DATA_NOT_FOUND: u32 = 0xc0000089; +pub const SMB_NTSTATUS_RESOURCE_TYPE_NOT_FOUND: u32 = 0xc000008a; +pub const SMB_NTSTATUS_RESOURCE_NAME_NOT_FOUND: u32 = 0xc000008b; +pub const SMB_NTSTATUS_ARRAY_BOUNDS_EXCEEDED: u32 = 0xc000008c; +pub const SMB_NTSTATUS_FLOAT_DENORMAL_OPERAND: u32 = 0xc000008d; +pub const SMB_NTSTATUS_FLOAT_DIVIDE_BY_ZERO: u32 = 0xc000008e; +pub const SMB_NTSTATUS_FLOAT_INEXACT_RESULT: u32 = 0xc000008f; +pub const SMB_NTSTATUS_FLOAT_INVALID_OPERATION: u32 = 0xc0000090; +pub const SMB_NTSTATUS_FLOAT_OVERFLOW: u32 = 0xc0000091; +pub const SMB_NTSTATUS_FLOAT_STACK_CHECK: u32 = 0xc0000092; +pub const SMB_NTSTATUS_FLOAT_UNDERFLOW: u32 = 0xc0000093; +pub const SMB_NTSTATUS_INTEGER_DIVIDE_BY_ZERO: u32 = 0xc0000094; +pub const SMB_NTSTATUS_INTEGER_OVERFLOW: u32 = 0xc0000095; +pub const SMB_NTSTATUS_PRIVILEGED_INSTRUCTION: u32 = 0xc0000096; +pub const SMB_NTSTATUS_TOO_MANY_PAGING_FILES: u32 = 0xc0000097; +pub const SMB_NTSTATUS_FILE_INVALID: u32 = 0xc0000098; +pub const SMB_NTSTATUS_ALLOTTED_SPACE_EXCEEDED: u32 = 0xc0000099; +pub const SMB_NTSTATUS_INSUFFICIENT_RESOURCES: u32 = 0xc000009a; +pub const SMB_NTSTATUS_DFS_EXIT_PATH_FOUND: u32 = 0xc000009b; +pub const SMB_NTSTATUS_DEVICE_DATA_ERROR: u32 = 0xc000009c; +pub const SMB_NTSTATUS_DEVICE_NOT_CONNECTED: u32 = 0xc000009d; +pub const SMB_NTSTATUS_FREE_VM_NOT_AT_BASE: u32 = 0xc000009f; +pub const SMB_NTSTATUS_MEMORY_NOT_ALLOCATED: u32 = 0xc00000a0; +pub const SMB_NTSTATUS_WORKING_SET_QUOTA: u32 = 0xc00000a1; +pub const SMB_NTSTATUS_MEDIA_WRITE_PROTECTED: u32 = 0xc00000a2; +pub const SMB_NTSTATUS_DEVICE_NOT_READY: u32 = 0xc00000a3; +pub const SMB_NTSTATUS_INVALID_GROUP_ATTRIBUTES: u32 = 0xc00000a4; +pub const SMB_NTSTATUS_BAD_IMPERSONATION_LEVEL: u32 = 0xc00000a5; +pub const SMB_NTSTATUS_CANT_OPEN_ANONYMOUS: u32 = 0xc00000a6; +pub const SMB_NTSTATUS_BAD_VALIDATION_CLASS: u32 = 0xc00000a7; +pub const SMB_NTSTATUS_BAD_TOKEN_TYPE: u32 = 0xc00000a8; +pub const SMB_NTSTATUS_BAD_MASTER_BOOT_RECORD: u32 = 0xc00000a9; +pub const SMB_NTSTATUS_INSTRUCTION_MISALIGNMENT: u32 = 0xc00000aa; +pub const SMB_NTSTATUS_INSTANCE_NOT_AVAILABLE: u32 = 0xc00000ab; +pub const SMB_NTSTATUS_PIPE_NOT_AVAILABLE: u32 = 0xc00000ac; +pub const SMB_NTSTATUS_INVALID_PIPE_STATE: u32 = 0xc00000ad; +pub const SMB_NTSTATUS_PIPE_BUSY: u32 = 0xc00000ae; +pub const SMB_NTSTATUS_ILLEGAL_FUNCTION: u32 = 0xc00000af; +pub const SMB_NTSTATUS_PIPE_DISCONNECTED: u32 = 0xc00000b0; +pub const SMB_NTSTATUS_PIPE_CLOSING: u32 = 0xc00000b1; +pub const SMB_NTSTATUS_PIPE_CONNECTED: u32 = 0xc00000b2; +pub const SMB_NTSTATUS_PIPE_LISTENING: u32 = 0xc00000b3; +pub const SMB_NTSTATUS_INVALID_READ_MODE: u32 = 0xc00000b4; +pub const SMB_NTSTATUS_IO_TIMEOUT: u32 = 0xc00000b5; +pub const SMB_NTSTATUS_FILE_FORCED_CLOSED: u32 = 0xc00000b6; +pub const SMB_NTSTATUS_PROFILING_NOT_STARTED: u32 = 0xc00000b7; +pub const SMB_NTSTATUS_PROFILING_NOT_STOPPED: u32 = 0xc00000b8; +pub const SMB_NTSTATUS_COULD_NOT_INTERPRET: u32 = 0xc00000b9; +pub const SMB_NTSTATUS_FILE_IS_A_DIRECTORY: u32 = 0xc00000ba; +pub const SMB_NTSTATUS_NOT_SUPPORTED: u32 = 0xc00000bb; +pub const SMB_NTSTATUS_REMOTE_NOT_LISTENING: u32 = 0xc00000bc; +pub const SMB_NTSTATUS_DUPLICATE_NAME: u32 = 0xc00000bd; +pub const SMB_NTSTATUS_BAD_NETWORK_PATH: u32 = 0xc00000be; +pub const SMB_NTSTATUS_NETWORK_BUSY: u32 = 0xc00000bf; +pub const SMB_NTSTATUS_DEVICE_DOES_NOT_EXIST: u32 = 0xc00000c0; +pub const SMB_NTSTATUS_TOO_MANY_COMMANDS: u32 = 0xc00000c1; +pub const SMB_NTSTATUS_ADAPTER_HARDWARE_ERROR: u32 = 0xc00000c2; +pub const SMB_NTSTATUS_INVALID_NETWORK_RESPONSE: u32 = 0xc00000c3; +pub const SMB_NTSTATUS_UNEXPECTED_NETWORK_ERROR: u32 = 0xc00000c4; +pub const SMB_NTSTATUS_BAD_REMOTE_ADAPTER: u32 = 0xc00000c5; +pub const SMB_NTSTATUS_PRINT_QUEUE_FULL: u32 = 0xc00000c6; +pub const SMB_NTSTATUS_NO_SPOOL_SPACE: u32 = 0xc00000c7; +pub const SMB_NTSTATUS_PRINT_CANCELLED: u32 = 0xc00000c8; +pub const SMB_NTSTATUS_NETWORK_NAME_DELETED: u32 = 0xc00000c9; +pub const SMB_NTSTATUS_NETWORK_ACCESS_DENIED: u32 = 0xc00000ca; +pub const SMB_NTSTATUS_BAD_DEVICE_TYPE: u32 = 0xc00000cb; +pub const SMB_NTSTATUS_BAD_NETWORK_NAME: u32 = 0xc00000cc; +pub const SMB_NTSTATUS_TOO_MANY_NAMES: u32 = 0xc00000cd; +pub const SMB_NTSTATUS_TOO_MANY_SESSIONS: u32 = 0xc00000ce; +pub const SMB_NTSTATUS_SHARING_PAUSED: u32 = 0xc00000cf; +pub const SMB_NTSTATUS_REQUEST_NOT_ACCEPTED: u32 = 0xc00000d0; +pub const SMB_NTSTATUS_REDIRECTOR_PAUSED: u32 = 0xc00000d1; +pub const SMB_NTSTATUS_NET_WRITE_FAULT: u32 = 0xc00000d2; +pub const SMB_NTSTATUS_PROFILING_AT_LIMIT: u32 = 0xc00000d3; +pub const SMB_NTSTATUS_NOT_SAME_DEVICE: u32 = 0xc00000d4; +pub const SMB_NTSTATUS_FILE_RENAMED: u32 = 0xc00000d5; +pub const SMB_NTSTATUS_VIRTUAL_CIRCUIT_CLOSED: u32 = 0xc00000d6; +pub const SMB_NTSTATUS_NO_SECURITY_ON_OBJECT: u32 = 0xc00000d7; +pub const SMB_NTSTATUS_CANT_WAIT: u32 = 0xc00000d8; +pub const SMB_NTSTATUS_PIPE_EMPTY: u32 = 0xc00000d9; +pub const SMB_NTSTATUS_CANT_ACCESS_DOMAIN_INFO: u32 = 0xc00000da; +pub const SMB_NTSTATUS_CANT_TERMINATE_SELF: u32 = 0xc00000db; +pub const SMB_NTSTATUS_INVALID_SERVER_STATE: u32 = 0xc00000dc; +pub const SMB_NTSTATUS_INVALID_DOMAIN_STATE: u32 = 0xc00000dd; +pub const SMB_NTSTATUS_INVALID_DOMAIN_ROLE: u32 = 0xc00000de; +pub const SMB_NTSTATUS_NO_SUCH_DOMAIN: u32 = 0xc00000df; +pub const SMB_NTSTATUS_DOMAIN_EXISTS: u32 = 0xc00000e0; +pub const SMB_NTSTATUS_DOMAIN_LIMIT_EXCEEDED: u32 = 0xc00000e1; +pub const SMB_NTSTATUS_OPLOCK_NOT_GRANTED: u32 = 0xc00000e2; +pub const SMB_NTSTATUS_INVALID_OPLOCK_PROTOCOL: u32 = 0xc00000e3; +pub const SMB_NTSTATUS_INTERNAL_DB_CORRUPTION: u32 = 0xc00000e4; +pub const SMB_NTSTATUS_INTERNAL_ERROR: u32 = 0xc00000e5; +pub const SMB_NTSTATUS_GENERIC_NOT_MAPPED: u32 = 0xc00000e6; +pub const SMB_NTSTATUS_BAD_DESCRIPTOR_FORMAT: u32 = 0xc00000e7; +pub const SMB_NTSTATUS_INVALID_USER_BUFFER: u32 = 0xc00000e8; +pub const SMB_NTSTATUS_UNEXPECTED_IO_ERROR: u32 = 0xc00000e9; +pub const SMB_NTSTATUS_UNEXPECTED_MM_CREATE_ERR: u32 = 0xc00000ea; +pub const SMB_NTSTATUS_UNEXPECTED_MM_MAP_ERROR: u32 = 0xc00000eb; +pub const SMB_NTSTATUS_UNEXPECTED_MM_EXTEND_ERR: u32 = 0xc00000ec; +pub const SMB_NTSTATUS_NOT_LOGON_PROCESS: u32 = 0xc00000ed; +pub const SMB_NTSTATUS_LOGON_SESSION_EXISTS: u32 = 0xc00000ee; +pub const SMB_NTSTATUS_INVALID_PARAMETER_1: u32 = 0xc00000ef; +pub const SMB_NTSTATUS_INVALID_PARAMETER_2: u32 = 0xc00000f0; +pub const SMB_NTSTATUS_INVALID_PARAMETER_3: u32 = 0xc00000f1; +pub const SMB_NTSTATUS_INVALID_PARAMETER_4: u32 = 0xc00000f2; +pub const SMB_NTSTATUS_INVALID_PARAMETER_5: u32 = 0xc00000f3; +pub const SMB_NTSTATUS_INVALID_PARAMETER_6: u32 = 0xc00000f4; +pub const SMB_NTSTATUS_INVALID_PARAMETER_7: u32 = 0xc00000f5; +pub const SMB_NTSTATUS_INVALID_PARAMETER_8: u32 = 0xc00000f6; +pub const SMB_NTSTATUS_INVALID_PARAMETER_9: u32 = 0xc00000f7; +pub const SMB_NTSTATUS_INVALID_PARAMETER_10: u32 = 0xc00000f8; +pub const SMB_NTSTATUS_INVALID_PARAMETER_11: u32 = 0xc00000f9; +pub const SMB_NTSTATUS_INVALID_PARAMETER_12: u32 = 0xc00000fa; +pub const SMB_NTSTATUS_REDIRECTOR_NOT_STARTED: u32 = 0xc00000fb; +pub const SMB_NTSTATUS_REDIRECTOR_STARTED: u32 = 0xc00000fc; +pub const SMB_NTSTATUS_STACK_OVERFLOW: u32 = 0xc00000fd; +pub const SMB_NTSTATUS_NO_SUCH_PACKAGE: u32 = 0xc00000fe; +pub const SMB_NTSTATUS_BAD_FUNCTION_TABLE: u32 = 0xc00000ff; +pub const SMB_NTSTATUS_VARIABLE_NOT_FOUND: u32 = 0xc0000100; +pub const SMB_NTSTATUS_DIRECTORY_NOT_EMPTY: u32 = 0xc0000101; +pub const SMB_NTSTATUS_FILE_CORRUPT_ERROR: u32 = 0xc0000102; +pub const SMB_NTSTATUS_NOT_A_DIRECTORY: u32 = 0xc0000103; +pub const SMB_NTSTATUS_BAD_LOGON_SESSION_STATE: u32 = 0xc0000104; +pub const SMB_NTSTATUS_LOGON_SESSION_COLLISION: u32 = 0xc0000105; +pub const SMB_NTSTATUS_NAME_TOO_LONG: u32 = 0xc0000106; +pub const SMB_NTSTATUS_FILES_OPEN: u32 = 0xc0000107; +pub const SMB_NTSTATUS_CONNECTION_IN_USE: u32 = 0xc0000108; +pub const SMB_NTSTATUS_MESSAGE_NOT_FOUND: u32 = 0xc0000109; +pub const SMB_NTSTATUS_PROCESS_IS_TERMINATING: u32 = 0xc000010a; +pub const SMB_NTSTATUS_INVALID_LOGON_TYPE: u32 = 0xc000010b; +pub const SMB_NTSTATUS_NO_GUID_TRANSLATION: u32 = 0xc000010c; +pub const SMB_NTSTATUS_CANNOT_IMPERSONATE: u32 = 0xc000010d; +pub const SMB_NTSTATUS_IMAGE_ALREADY_LOADED: u32 = 0xc000010e; +pub const SMB_NTSTATUS_NO_LDT: u32 = 0xc0000117; +pub const SMB_NTSTATUS_INVALID_LDT_SIZE: u32 = 0xc0000118; +pub const SMB_NTSTATUS_INVALID_LDT_OFFSET: u32 = 0xc0000119; +pub const SMB_NTSTATUS_INVALID_LDT_DESCRIPTOR: u32 = 0xc000011a; +pub const SMB_NTSTATUS_INVALID_IMAGE_NE_FORMAT: u32 = 0xc000011b; +pub const SMB_NTSTATUS_RXACT_INVALID_STATE: u32 = 0xc000011c; +pub const SMB_NTSTATUS_RXACT_COMMIT_FAILURE: u32 = 0xc000011d; +pub const SMB_NTSTATUS_MAPPED_FILE_SIZE_ZERO: u32 = 0xc000011e; +pub const SMB_NTSTATUS_TOO_MANY_OPENED_FILES: u32 = 0xc000011f; +pub const SMB_NTSTATUS_CANCELLED: u32 = 0xc0000120; +pub const SMB_NTSTATUS_CANNOT_DELETE: u32 = 0xc0000121; +pub const SMB_NTSTATUS_INVALID_COMPUTER_NAME: u32 = 0xc0000122; +pub const SMB_NTSTATUS_FILE_DELETED: u32 = 0xc0000123; +pub const SMB_NTSTATUS_SPECIAL_ACCOUNT: u32 = 0xc0000124; +pub const SMB_NTSTATUS_SPECIAL_GROUP: u32 = 0xc0000125; +pub const SMB_NTSTATUS_SPECIAL_USER: u32 = 0xc0000126; +pub const SMB_NTSTATUS_MEMBERS_PRIMARY_GROUP: u32 = 0xc0000127; +pub const SMB_NTSTATUS_FILE_CLOSED: u32 = 0xc0000128; +pub const SMB_NTSTATUS_TOO_MANY_THREADS: u32 = 0xc0000129; +pub const SMB_NTSTATUS_THREAD_NOT_IN_PROCESS: u32 = 0xc000012a; +pub const SMB_NTSTATUS_TOKEN_ALREADY_IN_USE: u32 = 0xc000012b; +pub const SMB_NTSTATUS_PAGEFILE_QUOTA_EXCEEDED: u32 = 0xc000012c; +pub const SMB_NTSTATUS_COMMITMENT_LIMIT: u32 = 0xc000012d; +pub const SMB_NTSTATUS_INVALID_IMAGE_LE_FORMAT: u32 = 0xc000012e; +pub const SMB_NTSTATUS_INVALID_IMAGE_NOT_MZ: u32 = 0xc000012f; +pub const SMB_NTSTATUS_INVALID_IMAGE_PROTECT: u32 = 0xc0000130; +pub const SMB_NTSTATUS_INVALID_IMAGE_WIN_16: u32 = 0xc0000131; +pub const SMB_NTSTATUS_LOGON_SERVER_CONFLICT: u32 = 0xc0000132; +pub const SMB_NTSTATUS_TIME_DIFFERENCE_AT_DC: u32 = 0xc0000133; +pub const SMB_NTSTATUS_SYNCHRONIZATION_REQUIRED: u32 = 0xc0000134; +pub const SMB_NTSTATUS_DLL_NOT_FOUND: u32 = 0xc0000135; +pub const SMB_NTSTATUS_OPEN_FAILED: u32 = 0xc0000136; +pub const SMB_NTSTATUS_IO_PRIVILEGE_FAILED: u32 = 0xc0000137; +pub const SMB_NTSTATUS_ORDINAL_NOT_FOUND: u32 = 0xc0000138; +pub const SMB_NTSTATUS_ENTRYPOINT_NOT_FOUND: u32 = 0xc0000139; +pub const SMB_NTSTATUS_CONTROL_C_EXIT: u32 = 0xc000013a; +pub const SMB_NTSTATUS_LOCAL_DISCONNECT: u32 = 0xc000013b; +pub const SMB_NTSTATUS_REMOTE_DISCONNECT: u32 = 0xc000013c; +pub const SMB_NTSTATUS_REMOTE_RESOURCES: u32 = 0xc000013d; +pub const SMB_NTSTATUS_LINK_FAILED: u32 = 0xc000013e; +pub const SMB_NTSTATUS_LINK_TIMEOUT: u32 = 0xc000013f; +pub const SMB_NTSTATUS_INVALID_CONNECTION: u32 = 0xc0000140; +pub const SMB_NTSTATUS_INVALID_ADDRESS: u32 = 0xc0000141; +pub const SMB_NTSTATUS_DLL_INIT_FAILED: u32 = 0xc0000142; +pub const SMB_NTSTATUS_MISSING_SYSTEMFILE: u32 = 0xc0000143; +pub const SMB_NTSTATUS_UNHANDLED_EXCEPTION: u32 = 0xc0000144; +pub const SMB_NTSTATUS_APP_INIT_FAILURE: u32 = 0xc0000145; +pub const SMB_NTSTATUS_PAGEFILE_CREATE_FAILED: u32 = 0xc0000146; +pub const SMB_NTSTATUS_NO_PAGEFILE: u32 = 0xc0000147; +pub const SMB_NTSTATUS_INVALID_LEVEL: u32 = 0xc0000148; +pub const SMB_NTSTATUS_WRONG_PASSWORD_CORE: u32 = 0xc0000149; +pub const SMB_NTSTATUS_ILLEGAL_FLOAT_CONTEXT: u32 = 0xc000014a; +pub const SMB_NTSTATUS_PIPE_BROKEN: u32 = 0xc000014b; +pub const SMB_NTSTATUS_REGISTRY_CORRUPT: u32 = 0xc000014c; +pub const SMB_NTSTATUS_REGISTRY_IO_FAILED: u32 = 0xc000014d; +pub const SMB_NTSTATUS_NO_EVENT_PAIR: u32 = 0xc000014e; +pub const SMB_NTSTATUS_UNRECOGNIZED_VOLUME: u32 = 0xc000014f; +pub const SMB_NTSTATUS_SERIAL_NO_DEVICE_INITED: u32 = 0xc0000150; +pub const SMB_NTSTATUS_NO_SUCH_ALIAS: u32 = 0xc0000151; +pub const SMB_NTSTATUS_MEMBER_NOT_IN_ALIAS: u32 = 0xc0000152; +pub const SMB_NTSTATUS_MEMBER_IN_ALIAS: u32 = 0xc0000153; +pub const SMB_NTSTATUS_ALIAS_EXISTS: u32 = 0xc0000154; +pub const SMB_NTSTATUS_LOGON_NOT_GRANTED: u32 = 0xc0000155; +pub const SMB_NTSTATUS_TOO_MANY_SECRETS: u32 = 0xc0000156; +pub const SMB_NTSTATUS_SECRET_TOO_LONG: u32 = 0xc0000157; +pub const SMB_NTSTATUS_INTERNAL_DB_ERROR: u32 = 0xc0000158; +pub const SMB_NTSTATUS_FULLSCREEN_MODE: u32 = 0xc0000159; +pub const SMB_NTSTATUS_TOO_MANY_CONTEXT_IDS: u32 = 0xc000015a; +pub const SMB_NTSTATUS_LOGON_TYPE_NOT_GRANTED: u32 = 0xc000015b; +pub const SMB_NTSTATUS_NOT_REGISTRY_FILE: u32 = 0xc000015c; +pub const SMB_NTSTATUS_NT_CROSS_ENCRYPTION_REQUIRED: u32 = 0xc000015d; +pub const SMB_NTSTATUS_DOMAIN_CTRLR_CONFIG_ERROR: u32 = 0xc000015e; +pub const SMB_NTSTATUS_FT_MISSING_MEMBER: u32 = 0xc000015f; +pub const SMB_NTSTATUS_ILL_FORMED_SERVICE_ENTRY: u32 = 0xc0000160; +pub const SMB_NTSTATUS_ILLEGAL_CHARACTER: u32 = 0xc0000161; +pub const SMB_NTSTATUS_UNMAPPABLE_CHARACTER: u32 = 0xc0000162; +pub const SMB_NTSTATUS_UNDEFINED_CHARACTER: u32 = 0xc0000163; +pub const SMB_NTSTATUS_FLOPPY_VOLUME: u32 = 0xc0000164; +pub const SMB_NTSTATUS_FLOPPY_ID_MARK_NOT_FOUND: u32 = 0xc0000165; +pub const SMB_NTSTATUS_FLOPPY_WRONG_CYLINDER: u32 = 0xc0000166; +pub const SMB_NTSTATUS_FLOPPY_UNKNOWN_ERROR: u32 = 0xc0000167; +pub const SMB_NTSTATUS_FLOPPY_BAD_REGISTERS: u32 = 0xc0000168; +pub const SMB_NTSTATUS_DISK_RECALIBRATE_FAILED: u32 = 0xc0000169; +pub const SMB_NTSTATUS_DISK_OPERATION_FAILED: u32 = 0xc000016a; +pub const SMB_NTSTATUS_DISK_RESET_FAILED: u32 = 0xc000016b; +pub const SMB_NTSTATUS_SHARED_IRQ_BUSY: u32 = 0xc000016c; +pub const SMB_NTSTATUS_FT_ORPHANING: u32 = 0xc000016d; +pub const SMB_NTSTATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT: u32 = 0xc000016e; +pub const SMB_NTSTATUS_PARTITION_FAILURE: u32 = 0xc0000172; +pub const SMB_NTSTATUS_INVALID_BLOCK_LENGTH: u32 = 0xc0000173; +pub const SMB_NTSTATUS_DEVICE_NOT_PARTITIONED: u32 = 0xc0000174; +pub const SMB_NTSTATUS_UNABLE_TO_LOCK_MEDIA: u32 = 0xc0000175; +pub const SMB_NTSTATUS_UNABLE_TO_UNLOAD_MEDIA: u32 = 0xc0000176; +pub const SMB_NTSTATUS_EOM_OVERFLOW: u32 = 0xc0000177; +pub const SMB_NTSTATUS_NO_MEDIA: u32 = 0xc0000178; +pub const SMB_NTSTATUS_NO_SUCH_MEMBER: u32 = 0xc000017a; +pub const SMB_NTSTATUS_INVALID_MEMBER: u32 = 0xc000017b; +pub const SMB_NTSTATUS_KEY_DELETED: u32 = 0xc000017c; +pub const SMB_NTSTATUS_NO_LOG_SPACE: u32 = 0xc000017d; +pub const SMB_NTSTATUS_TOO_MANY_SIDS: u32 = 0xc000017e; +pub const SMB_NTSTATUS_LM_CROSS_ENCRYPTION_REQUIRED: u32 = 0xc000017f; +pub const SMB_NTSTATUS_KEY_HAS_CHILDREN: u32 = 0xc0000180; +pub const SMB_NTSTATUS_CHILD_MUST_BE_VOLATILE: u32 = 0xc0000181; +pub const SMB_NTSTATUS_DEVICE_CONFIGURATION_ERROR: u32 = 0xc0000182; +pub const SMB_NTSTATUS_DRIVER_INTERNAL_ERROR: u32 = 0xc0000183; +pub const SMB_NTSTATUS_INVALID_DEVICE_STATE: u32 = 0xc0000184; +pub const SMB_NTSTATUS_IO_DEVICE_ERROR: u32 = 0xc0000185; +pub const SMB_NTSTATUS_DEVICE_PROTOCOL_ERROR: u32 = 0xc0000186; +pub const SMB_NTSTATUS_BACKUP_CONTROLLER: u32 = 0xc0000187; +pub const SMB_NTSTATUS_LOG_FILE_FULL: u32 = 0xc0000188; +pub const SMB_NTSTATUS_TOO_LATE: u32 = 0xc0000189; +pub const SMB_NTSTATUS_NO_TRUST_LSA_SECRET: u32 = 0xc000018a; +pub const SMB_NTSTATUS_NO_TRUST_SAM_ACCOUNT: u32 = 0xc000018b; +pub const SMB_NTSTATUS_TRUSTED_DOMAIN_FAILURE: u32 = 0xc000018c; +pub const SMB_NTSTATUS_TRUSTED_RELATIONSHIP_FAILURE: u32 = 0xc000018d; +pub const SMB_NTSTATUS_EVENTLOG_FILE_CORRUPT: u32 = 0xc000018e; +pub const SMB_NTSTATUS_EVENTLOG_CANT_START: u32 = 0xc000018f; +pub const SMB_NTSTATUS_TRUST_FAILURE: u32 = 0xc0000190; +pub const SMB_NTSTATUS_MUTANT_LIMIT_EXCEEDED: u32 = 0xc0000191; +pub const SMB_NTSTATUS_NETLOGON_NOT_STARTED: u32 = 0xc0000192; +pub const SMB_NTSTATUS_ACCOUNT_EXPIRED: u32 = 0xc0000193; +pub const SMB_NTSTATUS_POSSIBLE_DEADLOCK: u32 = 0xc0000194; +pub const SMB_NTSTATUS_NETWORK_CREDENTIAL_CONFLICT: u32 = 0xc0000195; +pub const SMB_NTSTATUS_REMOTE_SESSION_LIMIT: u32 = 0xc0000196; +pub const SMB_NTSTATUS_EVENTLOG_FILE_CHANGED: u32 = 0xc0000197; +pub const SMB_NTSTATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: u32 = 0xc0000198; +pub const SMB_NTSTATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT: u32 = 0xc0000199; +pub const SMB_NTSTATUS_NOLOGON_SERVER_TRUST_ACCOUNT: u32 = 0xc000019a; +pub const SMB_NTSTATUS_DOMAIN_TRUST_INCONSISTENT: u32 = 0xc000019b; +pub const SMB_NTSTATUS_FS_DRIVER_REQUIRED: u32 = 0xc000019c; +pub const SMB_NTSTATUS_IMAGE_ALREADY_LOADED_AS_DLL: u32 = 0xc000019d; +pub const SMB_NTSTATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING: u32 = 0xc000019e; +pub const SMB_NTSTATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME: u32 = 0xc000019f; +pub const SMB_NTSTATUS_SECURITY_STREAM_IS_INCONSISTENT: u32 = 0xc00001a0; +pub const SMB_NTSTATUS_INVALID_LOCK_RANGE: u32 = 0xc00001a1; +pub const SMB_NTSTATUS_INVALID_ACE_CONDITION: u32 = 0xc00001a2; +pub const SMB_NTSTATUS_IMAGE_SUBSYSTEM_NOT_PRESENT: u32 = 0xc00001a3; +pub const SMB_NTSTATUS_NOTIFICATION_GUID_ALREADY_DEFINED: u32 = 0xc00001a4; +pub const SMB_NTSTATUS_NETWORK_OPEN_RESTRICTION: u32 = 0xc0000201; +pub const SMB_NTSTATUS_NO_USER_SESSION_KEY: u32 = 0xc0000202; +pub const SMB_NTSTATUS_USER_SESSION_DELETED: u32 = 0xc0000203; +pub const SMB_NTSTATUS_RESOURCE_LANG_NOT_FOUND: u32 = 0xc0000204; +pub const SMB_NTSTATUS_INSUFF_SERVER_RESOURCES: u32 = 0xc0000205; +pub const SMB_NTSTATUS_INVALID_BUFFER_SIZE: u32 = 0xc0000206; +pub const SMB_NTSTATUS_INVALID_ADDRESS_COMPONENT: u32 = 0xc0000207; +pub const SMB_NTSTATUS_INVALID_ADDRESS_WILDCARD: u32 = 0xc0000208; +pub const SMB_NTSTATUS_TOO_MANY_ADDRESSES: u32 = 0xc0000209; +pub const SMB_NTSTATUS_ADDRESS_ALREADY_EXISTS: u32 = 0xc000020a; +pub const SMB_NTSTATUS_ADDRESS_CLOSED: u32 = 0xc000020b; +pub const SMB_NTSTATUS_CONNECTION_DISCONNECTED: u32 = 0xc000020c; +pub const SMB_NTSTATUS_CONNECTION_RESET: u32 = 0xc000020d; +pub const SMB_NTSTATUS_TOO_MANY_NODES: u32 = 0xc000020e; +pub const SMB_NTSTATUS_TRANSACTION_ABORTED: u32 = 0xc000020f; +pub const SMB_NTSTATUS_TRANSACTION_TIMED_OUT: u32 = 0xc0000210; +pub const SMB_NTSTATUS_TRANSACTION_NO_RELEASE: u32 = 0xc0000211; +pub const SMB_NTSTATUS_TRANSACTION_NO_MATCH: u32 = 0xc0000212; +pub const SMB_NTSTATUS_TRANSACTION_RESPONDED: u32 = 0xc0000213; +pub const SMB_NTSTATUS_TRANSACTION_INVALID_ID: u32 = 0xc0000214; +pub const SMB_NTSTATUS_TRANSACTION_INVALID_TYPE: u32 = 0xc0000215; +pub const SMB_NTSTATUS_NOT_SERVER_SESSION: u32 = 0xc0000216; +pub const SMB_NTSTATUS_NOT_CLIENT_SESSION: u32 = 0xc0000217; +pub const SMB_NTSTATUS_CANNOT_LOAD_REGISTRY_FILE: u32 = 0xc0000218; +pub const SMB_NTSTATUS_DEBUG_ATTACH_FAILED: u32 = 0xc0000219; +pub const SMB_NTSTATUS_SYSTEM_PROCESS_TERMINATED: u32 = 0xc000021a; +pub const SMB_NTSTATUS_DATA_NOT_ACCEPTED: u32 = 0xc000021b; +pub const SMB_NTSTATUS_NO_BROWSER_SERVERS_FOUND: u32 = 0xc000021c; +pub const SMB_NTSTATUS_VDM_HARD_ERROR: u32 = 0xc000021d; +pub const SMB_NTSTATUS_DRIVER_CANCEL_TIMEOUT: u32 = 0xc000021e; +pub const SMB_NTSTATUS_REPLY_MESSAGE_MISMATCH: u32 = 0xc000021f; +pub const SMB_NTSTATUS_MAPPED_ALIGNMENT: u32 = 0xc0000220; +pub const SMB_NTSTATUS_IMAGE_CHECKSUM_MISMATCH: u32 = 0xc0000221; +pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA: u32 = 0xc0000222; +pub const SMB_NTSTATUS_CLIENT_SERVER_PARAMETERS_INVALID: u32 = 0xc0000223; +pub const SMB_NTSTATUS_PASSWORD_MUST_CHANGE: u32 = 0xc0000224; +pub const SMB_NTSTATUS_NOT_FOUND: u32 = 0xc0000225; +pub const SMB_NTSTATUS_NOT_TINY_STREAM: u32 = 0xc0000226; +pub const SMB_NTSTATUS_RECOVERY_FAILURE: u32 = 0xc0000227; +pub const SMB_NTSTATUS_STACK_OVERFLOW_READ: u32 = 0xc0000228; +pub const SMB_NTSTATUS_FAIL_CHECK: u32 = 0xc0000229; +pub const SMB_NTSTATUS_DUPLICATE_OBJECTID: u32 = 0xc000022a; +pub const SMB_NTSTATUS_OBJECTID_EXISTS: u32 = 0xc000022b; +pub const SMB_NTSTATUS_CONVERT_TO_LARGE: u32 = 0xc000022c; +pub const SMB_NTSTATUS_RETRY: u32 = 0xc000022d; +pub const SMB_NTSTATUS_FOUND_OUT_OF_SCOPE: u32 = 0xc000022e; +pub const SMB_NTSTATUS_ALLOCATE_BUCKET: u32 = 0xc000022f; +pub const SMB_NTSTATUS_PROPSET_NOT_FOUND: u32 = 0xc0000230; +pub const SMB_NTSTATUS_MARSHALL_OVERFLOW: u32 = 0xc0000231; +pub const SMB_NTSTATUS_INVALID_VARIANT: u32 = 0xc0000232; +pub const SMB_NTSTATUS_DOMAIN_CONTROLLER_NOT_FOUND: u32 = 0xc0000233; +pub const SMB_NTSTATUS_ACCOUNT_LOCKED_OUT: u32 = 0xc0000234; +pub const SMB_NTSTATUS_HANDLE_NOT_CLOSABLE: u32 = 0xc0000235; +pub const SMB_NTSTATUS_CONNECTION_REFUSED: u32 = 0xc0000236; +pub const SMB_NTSTATUS_GRACEFUL_DISCONNECT: u32 = 0xc0000237; +pub const SMB_NTSTATUS_ADDRESS_ALREADY_ASSOCIATED: u32 = 0xc0000238; +pub const SMB_NTSTATUS_ADDRESS_NOT_ASSOCIATED: u32 = 0xc0000239; +pub const SMB_NTSTATUS_CONNECTION_INVALID: u32 = 0xc000023a; +pub const SMB_NTSTATUS_CONNECTION_ACTIVE: u32 = 0xc000023b; +pub const SMB_NTSTATUS_NETWORK_UNREACHABLE: u32 = 0xc000023c; +pub const SMB_NTSTATUS_HOST_UNREACHABLE: u32 = 0xc000023d; +pub const SMB_NTSTATUS_PROTOCOL_UNREACHABLE: u32 = 0xc000023e; +pub const SMB_NTSTATUS_PORT_UNREACHABLE: u32 = 0xc000023f; +pub const SMB_NTSTATUS_REQUEST_ABORTED: u32 = 0xc0000240; +pub const SMB_NTSTATUS_CONNECTION_ABORTED: u32 = 0xc0000241; +pub const SMB_NTSTATUS_BAD_COMPRESSION_BUFFER: u32 = 0xc0000242; +pub const SMB_NTSTATUS_USER_MAPPED_FILE: u32 = 0xc0000243; +pub const SMB_NTSTATUS_AUDIT_FAILED: u32 = 0xc0000244; +pub const SMB_NTSTATUS_TIMER_RESOLUTION_NOT_SET: u32 = 0xc0000245; +pub const SMB_NTSTATUS_CONNECTION_COUNT_LIMIT: u32 = 0xc0000246; +pub const SMB_NTSTATUS_LOGIN_TIME_RESTRICTION: u32 = 0xc0000247; +pub const SMB_NTSTATUS_LOGIN_WKSTA_RESTRICTION: u32 = 0xc0000248; +pub const SMB_NTSTATUS_IMAGE_MP_UP_MISMATCH: u32 = 0xc0000249; +pub const SMB_NTSTATUS_INSUFFICIENT_LOGON_INFO: u32 = 0xc0000250; +pub const SMB_NTSTATUS_BAD_DLL_ENTRYPOINT: u32 = 0xc0000251; +pub const SMB_NTSTATUS_BAD_SERVICE_ENTRYPOINT: u32 = 0xc0000252; +pub const SMB_NTSTATUS_LPC_REPLY_LOST: u32 = 0xc0000253; +pub const SMB_NTSTATUS_IP_ADDRESS_CONFLICT1: u32 = 0xc0000254; +pub const SMB_NTSTATUS_IP_ADDRESS_CONFLICT2: u32 = 0xc0000255; +pub const SMB_NTSTATUS_REGISTRY_QUOTA_LIMIT: u32 = 0xc0000256; +pub const SMB_NTSTATUS_PATH_NOT_COVERED: u32 = 0xc0000257; +pub const SMB_NTSTATUS_NO_CALLBACK_ACTIVE: u32 = 0xc0000258; +pub const SMB_NTSTATUS_LICENSE_QUOTA_EXCEEDED: u32 = 0xc0000259; +pub const SMB_NTSTATUS_PWD_TOO_SHORT: u32 = 0xc000025a; +pub const SMB_NTSTATUS_PWD_TOO_RECENT: u32 = 0xc000025b; +pub const SMB_NTSTATUS_PWD_HISTORY_CONFLICT: u32 = 0xc000025c; +pub const SMB_NTSTATUS_PLUGPLAY_NO_DEVICE: u32 = 0xc000025e; +pub const SMB_NTSTATUS_UNSUPPORTED_COMPRESSION: u32 = 0xc000025f; +pub const SMB_NTSTATUS_INVALID_HW_PROFILE: u32 = 0xc0000260; +pub const SMB_NTSTATUS_INVALID_PLUGPLAY_DEVICE_PATH: u32 = 0xc0000261; +pub const SMB_NTSTATUS_DRIVER_ORDINAL_NOT_FOUND: u32 = 0xc0000262; +pub const SMB_NTSTATUS_DRIVER_ENTRYPOINT_NOT_FOUND: u32 = 0xc0000263; +pub const SMB_NTSTATUS_RESOURCE_NOT_OWNED: u32 = 0xc0000264; +pub const SMB_NTSTATUS_TOO_MANY_LINKS: u32 = 0xc0000265; +pub const SMB_NTSTATUS_QUOTA_LIST_INCONSISTENT: u32 = 0xc0000266; +pub const SMB_NTSTATUS_FILE_IS_OFFLINE: u32 = 0xc0000267; +pub const SMB_NTSTATUS_EVALUATION_EXPIRATION: u32 = 0xc0000268; +pub const SMB_NTSTATUS_ILLEGAL_DLL_RELOCATION: u32 = 0xc0000269; +pub const SMB_NTSTATUS_LICENSE_VIOLATION: u32 = 0xc000026a; +pub const SMB_NTSTATUS_DLL_INIT_FAILED_LOGOFF: u32 = 0xc000026b; +pub const SMB_NTSTATUS_DRIVER_UNABLE_TO_LOAD: u32 = 0xc000026c; +pub const SMB_NTSTATUS_DFS_UNAVAILABLE: u32 = 0xc000026d; +pub const SMB_NTSTATUS_VOLUME_DISMOUNTED: u32 = 0xc000026e; +pub const SMB_NTSTATUS_WX86_INTERNAL_ERROR: u32 = 0xc000026f; +pub const SMB_NTSTATUS_WX86_FLOAT_STACK_CHECK: u32 = 0xc0000270; +pub const SMB_NTSTATUS_VALIDATE_CONTINUE: u32 = 0xc0000271; +pub const SMB_NTSTATUS_NO_MATCH: u32 = 0xc0000272; +pub const SMB_NTSTATUS_NO_MORE_MATCHES: u32 = 0xc0000273; +pub const SMB_NTSTATUS_NOT_A_REPARSE_POINT: u32 = 0xc0000275; +pub const SMB_NTSTATUS_IO_REPARSE_TAG_INVALID: u32 = 0xc0000276; +pub const SMB_NTSTATUS_IO_REPARSE_TAG_MISMATCH: u32 = 0xc0000277; +pub const SMB_NTSTATUS_IO_REPARSE_DATA_INVALID: u32 = 0xc0000278; +pub const SMB_NTSTATUS_IO_REPARSE_TAG_NOT_HANDLED: u32 = 0xc0000279; +pub const SMB_NTSTATUS_REPARSE_POINT_NOT_RESOLVED: u32 = 0xc0000280; +pub const SMB_NTSTATUS_DIRECTORY_IS_A_REPARSE_POINT: u32 = 0xc0000281; +pub const SMB_NTSTATUS_RANGE_LIST_CONFLICT: u32 = 0xc0000282; +pub const SMB_NTSTATUS_SOURCE_ELEMENT_EMPTY: u32 = 0xc0000283; +pub const SMB_NTSTATUS_DESTINATION_ELEMENT_FULL: u32 = 0xc0000284; +pub const SMB_NTSTATUS_ILLEGAL_ELEMENT_ADDRESS: u32 = 0xc0000285; +pub const SMB_NTSTATUS_MAGAZINE_NOT_PRESENT: u32 = 0xc0000286; +pub const SMB_NTSTATUS_REINITIALIZATION_NEEDED: u32 = 0xc0000287; +pub const SMB_NTSTATUS_ENCRYPTION_FAILED: u32 = 0xc000028a; +pub const SMB_NTSTATUS_DECRYPTION_FAILED: u32 = 0xc000028b; +pub const SMB_NTSTATUS_RANGE_NOT_FOUND: u32 = 0xc000028c; +pub const SMB_NTSTATUS_NO_RECOVERY_POLICY: u32 = 0xc000028d; +pub const SMB_NTSTATUS_NO_EFS: u32 = 0xc000028e; +pub const SMB_NTSTATUS_WRONG_EFS: u32 = 0xc000028f; +pub const SMB_NTSTATUS_NO_USER_KEYS: u32 = 0xc0000290; +pub const SMB_NTSTATUS_FILE_NOT_ENCRYPTED: u32 = 0xc0000291; +pub const SMB_NTSTATUS_NOT_EXPORT_FORMAT: u32 = 0xc0000292; +pub const SMB_NTSTATUS_FILE_ENCRYPTED: u32 = 0xc0000293; +pub const SMB_NTSTATUS_WMI_GUID_NOT_FOUND: u32 = 0xc0000295; +pub const SMB_NTSTATUS_WMI_INSTANCE_NOT_FOUND: u32 = 0xc0000296; +pub const SMB_NTSTATUS_WMI_ITEMID_NOT_FOUND: u32 = 0xc0000297; +pub const SMB_NTSTATUS_WMI_TRY_AGAIN: u32 = 0xc0000298; +pub const SMB_NTSTATUS_SHARED_POLICY: u32 = 0xc0000299; +pub const SMB_NTSTATUS_POLICY_OBJECT_NOT_FOUND: u32 = 0xc000029a; +pub const SMB_NTSTATUS_POLICY_ONLY_IN_DS: u32 = 0xc000029b; +pub const SMB_NTSTATUS_VOLUME_NOT_UPGRADED: u32 = 0xc000029c; +pub const SMB_NTSTATUS_REMOTE_STORAGE_NOT_ACTIVE: u32 = 0xc000029d; +pub const SMB_NTSTATUS_REMOTE_STORAGE_MEDIA_ERROR: u32 = 0xc000029e; +pub const SMB_NTSTATUS_NO_TRACKING_SERVICE: u32 = 0xc000029f; +pub const SMB_NTSTATUS_SERVER_SID_MISMATCH: u32 = 0xc00002a0; +pub const SMB_NTSTATUS_DS_NO_ATTRIBUTE_OR_VALUE: u32 = 0xc00002a1; +pub const SMB_NTSTATUS_DS_INVALID_ATTRIBUTE_SYNTAX: u32 = 0xc00002a2; +pub const SMB_NTSTATUS_DS_ATTRIBUTE_TYPE_UNDEFINED: u32 = 0xc00002a3; +pub const SMB_NTSTATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS: u32 = 0xc00002a4; +pub const SMB_NTSTATUS_DS_BUSY: u32 = 0xc00002a5; +pub const SMB_NTSTATUS_DS_UNAVAILABLE: u32 = 0xc00002a6; +pub const SMB_NTSTATUS_DS_NO_RIDS_ALLOCATED: u32 = 0xc00002a7; +pub const SMB_NTSTATUS_DS_NO_MORE_RIDS: u32 = 0xc00002a8; +pub const SMB_NTSTATUS_DS_INCORRECT_ROLE_OWNER: u32 = 0xc00002a9; +pub const SMB_NTSTATUS_DS_RIDMGR_INIT_ERROR: u32 = 0xc00002aa; +pub const SMB_NTSTATUS_DS_OBJ_CLASS_VIOLATION: u32 = 0xc00002ab; +pub const SMB_NTSTATUS_DS_CANT_ON_NON_LEAF: u32 = 0xc00002ac; +pub const SMB_NTSTATUS_DS_CANT_ON_RDN: u32 = 0xc00002ad; +pub const SMB_NTSTATUS_DS_CANT_MOD_OBJ_CLASS: u32 = 0xc00002ae; +pub const SMB_NTSTATUS_DS_CROSS_DOM_MOVE_FAILED: u32 = 0xc00002af; +pub const SMB_NTSTATUS_DS_GC_NOT_AVAILABLE: u32 = 0xc00002b0; +pub const SMB_NTSTATUS_DIRECTORY_SERVICE_REQUIRED: u32 = 0xc00002b1; +pub const SMB_NTSTATUS_REPARSE_ATTRIBUTE_CONFLICT: u32 = 0xc00002b2; +pub const SMB_NTSTATUS_CANT_ENABLE_DENY_ONLY: u32 = 0xc00002b3; +pub const SMB_NTSTATUS_FLOAT_MULTIPLE_FAULTS: u32 = 0xc00002b4; +pub const SMB_NTSTATUS_FLOAT_MULTIPLE_TRAPS: u32 = 0xc00002b5; +pub const SMB_NTSTATUS_DEVICE_REMOVED: u32 = 0xc00002b6; +pub const SMB_NTSTATUS_JOURNAL_DELETE_IN_PROGRESS: u32 = 0xc00002b7; +pub const SMB_NTSTATUS_JOURNAL_NOT_ACTIVE: u32 = 0xc00002b8; +pub const SMB_NTSTATUS_NOINTERFACE: u32 = 0xc00002b9; +pub const SMB_NTSTATUS_DS_ADMIN_LIMIT_EXCEEDED: u32 = 0xc00002c1; +pub const SMB_NTSTATUS_DRIVER_FAILED_SLEEP: u32 = 0xc00002c2; +pub const SMB_NTSTATUS_MUTUAL_AUTHENTICATION_FAILED: u32 = 0xc00002c3; +pub const SMB_NTSTATUS_CORRUPT_SYSTEM_FILE: u32 = 0xc00002c4; +pub const SMB_NTSTATUS_DATATYPE_MISALIGNMENT_ERROR: u32 = 0xc00002c5; +pub const SMB_NTSTATUS_WMI_READ_ONLY: u32 = 0xc00002c6; +pub const SMB_NTSTATUS_WMI_SET_FAILURE: u32 = 0xc00002c7; +pub const SMB_NTSTATUS_COMMITMENT_MINIMUM: u32 = 0xc00002c8; +pub const SMB_NTSTATUS_REG_NAT_CONSUMPTION: u32 = 0xc00002c9; +pub const SMB_NTSTATUS_TRANSPORT_FULL: u32 = 0xc00002ca; +pub const SMB_NTSTATUS_DS_SAM_INIT_FAILURE: u32 = 0xc00002cb; +pub const SMB_NTSTATUS_ONLY_IF_CONNECTED: u32 = 0xc00002cc; +pub const SMB_NTSTATUS_DS_SENSITIVE_GROUP_VIOLATION: u32 = 0xc00002cd; +pub const SMB_NTSTATUS_PNP_RESTART_ENUMERATION: u32 = 0xc00002ce; +pub const SMB_NTSTATUS_JOURNAL_ENTRY_DELETED: u32 = 0xc00002cf; +pub const SMB_NTSTATUS_DS_CANT_MOD_PRIMARYGROUPID: u32 = 0xc00002d0; +pub const SMB_NTSTATUS_SYSTEM_IMAGE_BAD_SIGNATURE: u32 = 0xc00002d1; +pub const SMB_NTSTATUS_PNP_REBOOT_REQUIRED: u32 = 0xc00002d2; +pub const SMB_NTSTATUS_POWER_STATE_INVALID: u32 = 0xc00002d3; +pub const SMB_NTSTATUS_DS_INVALID_GROUP_TYPE: u32 = 0xc00002d4; +pub const SMB_NTSTATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN: u32 = 0xc00002d5; +pub const SMB_NTSTATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN: u32 = 0xc00002d6; +pub const SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER: u32 = 0xc00002d7; +pub const SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER: u32 = 0xc00002d8; +pub const SMB_NTSTATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER: u32 = 0xc00002d9; +pub const SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER: u32 = 0xc00002da; +pub const SMB_NTSTATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER: u32 = 0xc00002db; +pub const SMB_NTSTATUS_DS_HAVE_PRIMARY_MEMBERS: u32 = 0xc00002dc; +pub const SMB_NTSTATUS_WMI_NOT_SUPPORTED: u32 = 0xc00002dd; +pub const SMB_NTSTATUS_INSUFFICIENT_POWER: u32 = 0xc00002de; +pub const SMB_NTSTATUS_SAM_NEED_BOOTKEY_PASSWORD: u32 = 0xc00002df; +pub const SMB_NTSTATUS_SAM_NEED_BOOTKEY_FLOPPY: u32 = 0xc00002e0; +pub const SMB_NTSTATUS_DS_CANT_START: u32 = 0xc00002e1; +pub const SMB_NTSTATUS_DS_INIT_FAILURE: u32 = 0xc00002e2; +pub const SMB_NTSTATUS_SAM_INIT_FAILURE: u32 = 0xc00002e3; +pub const SMB_NTSTATUS_DS_GC_REQUIRED: u32 = 0xc00002e4; +pub const SMB_NTSTATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY: u32 = 0xc00002e5; +pub const SMB_NTSTATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS: u32 = 0xc00002e6; +pub const SMB_NTSTATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED: u32 = 0xc00002e7; +pub const SMB_NTSTATUS_CURRENT_DOMAIN_NOT_ALLOWED: u32 = 0xc00002e9; +pub const SMB_NTSTATUS_CANNOT_MAKE: u32 = 0xc00002ea; +pub const SMB_NTSTATUS_SYSTEM_SHUTDOWN: u32 = 0xc00002eb; +pub const SMB_NTSTATUS_DS_INIT_FAILURE_CONSOLE: u32 = 0xc00002ec; +pub const SMB_NTSTATUS_DS_SAM_INIT_FAILURE_CONSOLE: u32 = 0xc00002ed; +pub const SMB_NTSTATUS_UNFINISHED_CONTEXT_DELETED: u32 = 0xc00002ee; +pub const SMB_NTSTATUS_NO_TGT_REPLY: u32 = 0xc00002ef; +pub const SMB_NTSTATUS_OBJECTID_NOT_FOUND: u32 = 0xc00002f0; +pub const SMB_NTSTATUS_NO_IP_ADDRESSES: u32 = 0xc00002f1; +pub const SMB_NTSTATUS_WRONG_CREDENTIAL_HANDLE: u32 = 0xc00002f2; +pub const SMB_NTSTATUS_CRYPTO_SYSTEM_INVALID: u32 = 0xc00002f3; +pub const SMB_NTSTATUS_MAX_REFERRALS_EXCEEDED: u32 = 0xc00002f4; +pub const SMB_NTSTATUS_MUST_BE_KDC: u32 = 0xc00002f5; +pub const SMB_NTSTATUS_STRONG_CRYPTO_NOT_SUPPORTED: u32 = 0xc00002f6; +pub const SMB_NTSTATUS_TOO_MANY_PRINCIPALS: u32 = 0xc00002f7; +pub const SMB_NTSTATUS_NO_PA_DATA: u32 = 0xc00002f8; +pub const SMB_NTSTATUS_PKINIT_NAME_MISMATCH: u32 = 0xc00002f9; +pub const SMB_NTSTATUS_SMARTCARD_LOGON_REQUIRED: u32 = 0xc00002fa; +pub const SMB_NTSTATUS_KDC_INVALID_REQUEST: u32 = 0xc00002fb; +pub const SMB_NTSTATUS_KDC_UNABLE_TO_REFER: u32 = 0xc00002fc; +pub const SMB_NTSTATUS_KDC_UNKNOWN_ETYPE: u32 = 0xc00002fd; +pub const SMB_NTSTATUS_SHUTDOWN_IN_PROGRESS: u32 = 0xc00002fe; +pub const SMB_NTSTATUS_SERVER_SHUTDOWN_IN_PROGRESS: u32 = 0xc00002ff; +pub const SMB_NTSTATUS_NOT_SUPPORTED_ON_SBS: u32 = 0xc0000300; +pub const SMB_NTSTATUS_WMI_GUID_DISCONNECTED: u32 = 0xc0000301; +pub const SMB_NTSTATUS_WMI_ALREADY_DISABLED: u32 = 0xc0000302; +pub const SMB_NTSTATUS_WMI_ALREADY_ENABLED: u32 = 0xc0000303; +pub const SMB_NTSTATUS_MFT_TOO_FRAGMENTED: u32 = 0xc0000304; +pub const SMB_NTSTATUS_COPY_PROTECTION_FAILURE: u32 = 0xc0000305; +pub const SMB_NTSTATUS_CSS_AUTHENTICATION_FAILURE: u32 = 0xc0000306; +pub const SMB_NTSTATUS_CSS_KEY_NOT_PRESENT: u32 = 0xc0000307; +pub const SMB_NTSTATUS_CSS_KEY_NOT_ESTABLISHED: u32 = 0xc0000308; +pub const SMB_NTSTATUS_CSS_SCRAMBLED_SECTOR: u32 = 0xc0000309; +pub const SMB_NTSTATUS_CSS_REGION_MISMATCH: u32 = 0xc000030a; +pub const SMB_NTSTATUS_CSS_RESETS_EXHAUSTED: u32 = 0xc000030b; +pub const SMB_NTSTATUS_PKINIT_FAILURE: u32 = 0xc0000320; +pub const SMB_NTSTATUS_SMARTCARD_SUBSYSTEM_FAILURE: u32 = 0xc0000321; +pub const SMB_NTSTATUS_NO_KERB_KEY: u32 = 0xc0000322; +pub const SMB_NTSTATUS_HOST_DOWN: u32 = 0xc0000350; +pub const SMB_NTSTATUS_UNSUPPORTED_PREAUTH: u32 = 0xc0000351; +pub const SMB_NTSTATUS_EFS_ALG_BLOB_TOO_BIG: u32 = 0xc0000352; +pub const SMB_NTSTATUS_PORT_NOT_SET: u32 = 0xc0000353; +pub const SMB_NTSTATUS_DEBUGGER_INACTIVE: u32 = 0xc0000354; +pub const SMB_NTSTATUS_DS_VERSION_CHECK_FAILURE: u32 = 0xc0000355; +pub const SMB_NTSTATUS_AUDITING_DISABLED: u32 = 0xc0000356; +pub const SMB_NTSTATUS_PRENT4_MACHINE_ACCOUNT: u32 = 0xc0000357; +pub const SMB_NTSTATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER: u32 = 0xc0000358; +pub const SMB_NTSTATUS_INVALID_IMAGE_WIN_32: u32 = 0xc0000359; +pub const SMB_NTSTATUS_INVALID_IMAGE_WIN_64: u32 = 0xc000035a; +pub const SMB_NTSTATUS_BAD_BINDINGS: u32 = 0xc000035b; +pub const SMB_NTSTATUS_NETWORK_SESSION_EXPIRED: u32 = 0xc000035c; +pub const SMB_NTSTATUS_APPHELP_BLOCK: u32 = 0xc000035d; +pub const SMB_NTSTATUS_ALL_SIDS_FILTERED: u32 = 0xc000035e; +pub const SMB_NTSTATUS_NOT_SAFE_MODE_DRIVER: u32 = 0xc000035f; +pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT: u32 = 0xc0000361; +pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PATH: u32 = 0xc0000362; +pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER: u32 = 0xc0000363; +pub const SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_OTHER: u32 = 0xc0000364; +pub const SMB_NTSTATUS_FAILED_DRIVER_ENTRY: u32 = 0xc0000365; +pub const SMB_NTSTATUS_DEVICE_ENUMERATION_ERROR: u32 = 0xc0000366; +pub const SMB_NTSTATUS_MOUNT_POINT_NOT_RESOLVED: u32 = 0xc0000368; +pub const SMB_NTSTATUS_INVALID_DEVICE_OBJECT_PARAMETER: u32 = 0xc0000369; +pub const SMB_NTSTATUS_MCA_OCCURED: u32 = 0xc000036a; +pub const SMB_NTSTATUS_DRIVER_BLOCKED_CRITICAL: u32 = 0xc000036b; +pub const SMB_NTSTATUS_DRIVER_BLOCKED: u32 = 0xc000036c; +pub const SMB_NTSTATUS_DRIVER_DATABASE_ERROR: u32 = 0xc000036d; +pub const SMB_NTSTATUS_SYSTEM_HIVE_TOO_LARGE: u32 = 0xc000036e; +pub const SMB_NTSTATUS_INVALID_IMPORT_OF_NON_DLL: u32 = 0xc000036f; +pub const SMB_NTSTATUS_NO_SECRETS: u32 = 0xc0000371; +pub const SMB_NTSTATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY: u32 = 0xc0000372; +pub const SMB_NTSTATUS_FAILED_STACK_SWITCH: u32 = 0xc0000373; +pub const SMB_NTSTATUS_HEAP_CORRUPTION: u32 = 0xc0000374; +pub const SMB_NTSTATUS_SMARTCARD_WRONG_PIN: u32 = 0xc0000380; +pub const SMB_NTSTATUS_SMARTCARD_CARD_BLOCKED: u32 = 0xc0000381; +pub const SMB_NTSTATUS_SMARTCARD_CARD_NOT_AUTHENTICATED: u32 = 0xc0000382; +pub const SMB_NTSTATUS_SMARTCARD_NO_CARD: u32 = 0xc0000383; +pub const SMB_NTSTATUS_SMARTCARD_NO_KEY_CONTAINER: u32 = 0xc0000384; +pub const SMB_NTSTATUS_SMARTCARD_NO_CERTIFICATE: u32 = 0xc0000385; +pub const SMB_NTSTATUS_SMARTCARD_NO_KEYSET: u32 = 0xc0000386; +pub const SMB_NTSTATUS_SMARTCARD_IO_ERROR: u32 = 0xc0000387; +pub const SMB_NTSTATUS_DOWNGRADE_DETECTED: u32 = 0xc0000388; +pub const SMB_NTSTATUS_SMARTCARD_CERT_REVOKED: u32 = 0xc0000389; +pub const SMB_NTSTATUS_ISSUING_CA_UNTRUSTED: u32 = 0xc000038a; +pub const SMB_NTSTATUS_REVOCATION_OFFLINE_C: u32 = 0xc000038b; +pub const SMB_NTSTATUS_PKINIT_CLIENT_FAILURE: u32 = 0xc000038c; +pub const SMB_NTSTATUS_SMARTCARD_CERT_EXPIRED: u32 = 0xc000038d; +pub const SMB_NTSTATUS_DRIVER_FAILED_PRIOR_UNLOAD: u32 = 0xc000038e; +pub const SMB_NTSTATUS_SMARTCARD_SILENT_CONTEXT: u32 = 0xc000038f; +pub const SMB_NTSTATUS_PER_USER_TRUST_QUOTA_EXCEEDED: u32 = 0xc0000401; +pub const SMB_NTSTATUS_ALL_USER_TRUST_QUOTA_EXCEEDED: u32 = 0xc0000402; +pub const SMB_NTSTATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED: u32 = 0xc0000403; +pub const SMB_NTSTATUS_DS_NAME_NOT_UNIQUE: u32 = 0xc0000404; +pub const SMB_NTSTATUS_DS_DUPLICATE_ID_FOUND: u32 = 0xc0000405; +pub const SMB_NTSTATUS_DS_GROUP_CONVERSION_ERROR: u32 = 0xc0000406; +pub const SMB_NTSTATUS_VOLSNAP_PREPARE_HIBERNATE: u32 = 0xc0000407; +pub const SMB_NTSTATUS_USER2USER_REQUIRED: u32 = 0xc0000408; +pub const SMB_NTSTATUS_STACK_BUFFER_OVERRUN: u32 = 0xc0000409; +pub const SMB_NTSTATUS_NO_S4U_PROT_SUPPORT: u32 = 0xc000040a; +pub const SMB_NTSTATUS_CROSSREALM_DELEGATION_FAILURE: u32 = 0xc000040b; +pub const SMB_NTSTATUS_REVOCATION_OFFLINE_KDC: u32 = 0xc000040c; +pub const SMB_NTSTATUS_ISSUING_CA_UNTRUSTED_KDC: u32 = 0xc000040d; +pub const SMB_NTSTATUS_KDC_CERT_EXPIRED: u32 = 0xc000040e; +pub const SMB_NTSTATUS_KDC_CERT_REVOKED: u32 = 0xc000040f; +pub const SMB_NTSTATUS_PARAMETER_QUOTA_EXCEEDED: u32 = 0xc0000410; +pub const SMB_NTSTATUS_HIBERNATION_FAILURE: u32 = 0xc0000411; +pub const SMB_NTSTATUS_DELAY_LOAD_FAILED: u32 = 0xc0000412; +pub const SMB_NTSTATUS_AUTHENTICATION_FIREWALL_FAILED: u32 = 0xc0000413; +pub const SMB_NTSTATUS_VDM_DISALLOWED: u32 = 0xc0000414; +pub const SMB_NTSTATUS_HUNG_DISPLAY_DRIVER_THREAD: u32 = 0xc0000415; +pub const SMB_NTSTATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE: u32 = 0xc0000416; +pub const SMB_NTSTATUS_INVALID_CRUNTIME_PARAMETER: u32 = 0xc0000417; +pub const SMB_NTSTATUS_NTLM_BLOCKED: u32 = 0xc0000418; +pub const SMB_NTSTATUS_DS_SRC_SID_EXISTS_IN_FOREST: u32 = 0xc0000419; +pub const SMB_NTSTATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST: u32 = 0xc000041a; +pub const SMB_NTSTATUS_DS_FLAT_NAME_EXISTS_IN_FOREST: u32 = 0xc000041b; +pub const SMB_NTSTATUS_INVALID_USER_PRINCIPAL_NAME: u32 = 0xc000041c; +pub const SMB_NTSTATUS_ASSERTION_FAILURE: u32 = 0xc0000420; +pub const SMB_NTSTATUS_VERIFIER_STOP: u32 = 0xc0000421; +pub const SMB_NTSTATUS_CALLBACK_POP_STACK: u32 = 0xc0000423; +pub const SMB_NTSTATUS_INCOMPATIBLE_DRIVER_BLOCKED: u32 = 0xc0000424; +pub const SMB_NTSTATUS_HIVE_UNLOADED: u32 = 0xc0000425; +pub const SMB_NTSTATUS_COMPRESSION_DISABLED: u32 = 0xc0000426; +pub const SMB_NTSTATUS_FILE_SYSTEM_LIMITATION: u32 = 0xc0000427; +pub const SMB_NTSTATUS_INVALID_IMAGE_HASH: u32 = 0xc0000428; +pub const SMB_NTSTATUS_NOT_CAPABLE: u32 = 0xc0000429; +pub const SMB_NTSTATUS_REQUEST_OUT_OF_SEQUENCE: u32 = 0xc000042a; +pub const SMB_NTSTATUS_IMPLEMENTATION_LIMIT: u32 = 0xc000042b; +pub const SMB_NTSTATUS_ELEVATION_REQUIRED: u32 = 0xc000042c; +pub const SMB_NTSTATUS_NO_SECURITY_CONTEXT: u32 = 0xc000042d; +pub const SMB_NTSTATUS_PKU2U_CERT_FAILURE: u32 = 0xc000042e; +pub const SMB_NTSTATUS_BEYOND_VDL: u32 = 0xc0000432; +pub const SMB_NTSTATUS_ENCOUNTERED_WRITE_IN_PROGRESS: u32 = 0xc0000433; +pub const SMB_NTSTATUS_PTE_CHANGED: u32 = 0xc0000434; +pub const SMB_NTSTATUS_PURGE_FAILED: u32 = 0xc0000435; +pub const SMB_NTSTATUS_CRED_REQUIRES_CONFIRMATION: u32 = 0xc0000440; +pub const SMB_NTSTATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE: u32 = 0xc0000441; +pub const SMB_NTSTATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER: u32 = 0xc0000442; +pub const SMB_NTSTATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE: u32 = 0xc0000443; +pub const SMB_NTSTATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE: u32 = 0xc0000444; +pub const SMB_NTSTATUS_CS_ENCRYPTION_FILE_NOT_CSE: u32 = 0xc0000445; +pub const SMB_NTSTATUS_INVALID_LABEL: u32 = 0xc0000446; +pub const SMB_NTSTATUS_DRIVER_PROCESS_TERMINATED: u32 = 0xc0000450; +pub const SMB_NTSTATUS_AMBIGUOUS_SYSTEM_DEVICE: u32 = 0xc0000451; +pub const SMB_NTSTATUS_SYSTEM_DEVICE_NOT_FOUND: u32 = 0xc0000452; +pub const SMB_NTSTATUS_RESTART_BOOT_APPLICATION: u32 = 0xc0000453; +pub const SMB_NTSTATUS_INSUFFICIENT_NVRAM_RESOURCES: u32 = 0xc0000454; +pub const SMB_NTSTATUS_NO_RANGES_PROCESSED: u32 = 0xc0000460; +pub const SMB_NTSTATUS_DEVICE_FEATURE_NOT_SUPPORTED: u32 = 0xc0000463; +pub const SMB_NTSTATUS_DEVICE_UNREACHABLE: u32 = 0xc0000464; +pub const SMB_NTSTATUS_INVALID_TOKEN: u32 = 0xc0000465; +pub const SMB_NTSTATUS_SERVER_UNAVAILABLE: u32 = 0xc0000466; +pub const SMB_NTSTATUS_INVALID_TASK_NAME: u32 = 0xc0000500; +pub const SMB_NTSTATUS_INVALID_TASK_INDEX: u32 = 0xc0000501; +pub const SMB_NTSTATUS_THREAD_ALREADY_IN_TASK: u32 = 0xc0000502; +pub const SMB_NTSTATUS_CALLBACK_BYPASS: u32 = 0xc0000503; +pub const SMB_NTSTATUS_FAIL_FAST_EXCEPTION: u32 = 0xc0000602; +pub const SMB_NTSTATUS_IMAGE_CERT_REVOKED: u32 = 0xc0000603; +pub const SMB_NTSTATUS_PORT_CLOSED: u32 = 0xc0000700; +pub const SMB_NTSTATUS_MESSAGE_LOST: u32 = 0xc0000701; +pub const SMB_NTSTATUS_INVALID_MESSAGE: u32 = 0xc0000702; +pub const SMB_NTSTATUS_REQUEST_CANCELED: u32 = 0xc0000703; +pub const SMB_NTSTATUS_RECURSIVE_DISPATCH: u32 = 0xc0000704; +pub const SMB_NTSTATUS_LPC_RECEIVE_BUFFER_EXPECTED: u32 = 0xc0000705; +pub const SMB_NTSTATUS_LPC_INVALID_CONNECTION_USAGE: u32 = 0xc0000706; +pub const SMB_NTSTATUS_LPC_REQUESTS_NOT_ALLOWED: u32 = 0xc0000707; +pub const SMB_NTSTATUS_RESOURCE_IN_USE: u32 = 0xc0000708; +pub const SMB_NTSTATUS_HARDWARE_MEMORY_ERROR: u32 = 0xc0000709; +pub const SMB_NTSTATUS_THREADPOOL_HANDLE_EXCEPTION: u32 = 0xc000070a; +pub const SMB_NTSTATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED: u32 = 0xc000070b; +pub const SMB_NTSTATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED: u32 = 0xc000070c; +pub const SMB_NTSTATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED: u32 = 0xc000070d; +pub const SMB_NTSTATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED: u32 = 0xc000070e; +pub const SMB_NTSTATUS_THREADPOOL_RELEASED_DURING_OPERATION: u32 = 0xc000070f; +pub const SMB_NTSTATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING: u32 = 0xc0000710; +pub const SMB_NTSTATUS_APC_RETURNED_WHILE_IMPERSONATING: u32 = 0xc0000711; +pub const SMB_NTSTATUS_PROCESS_IS_PROTECTED: u32 = 0xc0000712; +pub const SMB_NTSTATUS_MCA_EXCEPTION: u32 = 0xc0000713; +pub const SMB_NTSTATUS_CERTIFICATE_MAPPING_NOT_UNIQUE: u32 = 0xc0000714; +pub const SMB_NTSTATUS_SYMLINK_CLASS_DISABLED: u32 = 0xc0000715; +pub const SMB_NTSTATUS_INVALID_IDN_NORMALIZATION: u32 = 0xc0000716; +pub const SMB_NTSTATUS_NO_UNICODE_TRANSLATION: u32 = 0xc0000717; +pub const SMB_NTSTATUS_ALREADY_REGISTERED: u32 = 0xc0000718; +pub const SMB_NTSTATUS_CONTEXT_MISMATCH: u32 = 0xc0000719; +pub const SMB_NTSTATUS_PORT_ALREADY_HAS_COMPLETION_LIST: u32 = 0xc000071a; +pub const SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_PRIORITY: u32 = 0xc000071b; +pub const SMB_NTSTATUS_INVALID_THREAD: u32 = 0xc000071c; +pub const SMB_NTSTATUS_CALLBACK_RETURNED_TRANSACTION: u32 = 0xc000071d; +pub const SMB_NTSTATUS_CALLBACK_RETURNED_LDR_LOCK: u32 = 0xc000071e; +pub const SMB_NTSTATUS_CALLBACK_RETURNED_LANG: u32 = 0xc000071f; +pub const SMB_NTSTATUS_CALLBACK_RETURNED_PRI_BACK: u32 = 0xc0000720; +pub const SMB_NTSTATUS_DISK_REPAIR_DISABLED: u32 = 0xc0000800; +pub const SMB_NTSTATUS_DS_DOMAIN_RENAME_IN_PROGRESS: u32 = 0xc0000801; +pub const SMB_NTSTATUS_DISK_QUOTA_EXCEEDED: u32 = 0xc0000802; +pub const SMB_NTSTATUS_CONTENT_BLOCKED: u32 = 0xc0000804; +pub const SMB_NTSTATUS_BAD_CLUSTERS: u32 = 0xc0000805; +pub const SMB_NTSTATUS_VOLUME_DIRTY: u32 = 0xc0000806; +pub const SMB_NTSTATUS_FILE_CHECKED_OUT: u32 = 0xc0000901; +pub const SMB_NTSTATUS_CHECKOUT_REQUIRED: u32 = 0xc0000902; +pub const SMB_NTSTATUS_BAD_FILE_TYPE: u32 = 0xc0000903; +pub const SMB_NTSTATUS_FILE_TOO_LARGE: u32 = 0xc0000904; +pub const SMB_NTSTATUS_FORMS_AUTH_REQUIRED: u32 = 0xc0000905; +pub const SMB_NTSTATUS_VIRUS_INFECTED: u32 = 0xc0000906; +pub const SMB_NTSTATUS_VIRUS_DELETED: u32 = 0xc0000907; +pub const SMB_NTSTATUS_BAD_MCFG_TABLE: u32 = 0xc0000908; +pub const SMB_NTSTATUS_CANNOT_BREAK_OPLOCK: u32 = 0xc0000909; +pub const SMB_NTSTATUS_WOW_ASSERTION: u32 = 0xc0009898; +pub const SMB_NTSTATUS_INVALID_SIGNATURE: u32 = 0xc000a000; +pub const SMB_NTSTATUS_HMAC_NOT_SUPPORTED: u32 = 0xc000a001; +pub const SMB_NTSTATUS_IPSEC_QUEUE_OVERFLOW: u32 = 0xc000a010; +pub const SMB_NTSTATUS_ND_QUEUE_OVERFLOW: u32 = 0xc000a011; +pub const SMB_NTSTATUS_HOPLIMIT_EXCEEDED: u32 = 0xc000a012; +pub const SMB_NTSTATUS_PROTOCOL_NOT_SUPPORTED: u32 = 0xc000a013; +pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED: u32 = 0xc000a080; +pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR: u32 = 0xc000a081; +pub const SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR: u32 = 0xc000a082; +pub const SMB_NTSTATUS_XML_PARSE_ERROR: u32 = 0xc000a083; +pub const SMB_NTSTATUS_XMLDSIG_ERROR: u32 = 0xc000a084; +pub const SMB_NTSTATUS_WRONG_COMPARTMENT: u32 = 0xc000a085; +pub const SMB_NTSTATUS_AUTHIP_FAILURE: u32 = 0xc000a086; +pub const SMB_NTSTATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS: u32 = 0xc000a087; +pub const SMB_NTSTATUS_DS_OID_NOT_FOUND: u32 = 0xc000a088; +pub const SMB_NTSTATUS_HASH_NOT_SUPPORTED: u32 = 0xc000a100; +pub const SMB_NTSTATUS_HASH_NOT_PRESENT: u32 = 0xc000a101; +pub const SMB_NTSTATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED: u32 = 0xc000a2a1; +pub const SMB_NTSTATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED: u32 = 0xc000a2a2; +pub const SMB_NTSTATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED: u32 = 0xc000a2a3; +pub const SMB_NTSTATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED: u32 = 0xc000a2a4; +pub const SMB_NTDBG_NO_STATE_CHANGE: u32 = 0xc0010001; +pub const SMB_NTDBG_APP_NOT_IDLE: u32 = 0xc0010002; +pub const SMB_NTRPC_NT_INVALID_STRING_BINDING: u32 = 0xc0020001; +pub const SMB_NTRPC_NT_WRONG_KIND_OF_BINDING: u32 = 0xc0020002; +pub const SMB_NTRPC_NT_INVALID_BINDING: u32 = 0xc0020003; +pub const SMB_NTRPC_NT_PROTSEQ_NOT_SUPPORTED: u32 = 0xc0020004; +pub const SMB_NTRPC_NT_INVALID_RPC_PROTSEQ: u32 = 0xc0020005; +pub const SMB_NTRPC_NT_INVALID_STRING_UUID: u32 = 0xc0020006; +pub const SMB_NTRPC_NT_INVALID_ENDPOINT_FORMAT: u32 = 0xc0020007; +pub const SMB_NTRPC_NT_INVALID_NET_ADDR: u32 = 0xc0020008; +pub const SMB_NTRPC_NT_NO_ENDPOINT_FOUND: u32 = 0xc0020009; +pub const SMB_NTRPC_NT_INVALID_TIMEOUT: u32 = 0xc002000a; +pub const SMB_NTRPC_NT_OBJECT_NOT_FOUND: u32 = 0xc002000b; +pub const SMB_NTRPC_NT_ALREADY_REGISTERED: u32 = 0xc002000c; +pub const SMB_NTRPC_NT_TYPE_ALREADY_REGISTERED: u32 = 0xc002000d; +pub const SMB_NTRPC_NT_ALREADY_LISTENING: u32 = 0xc002000e; +pub const SMB_NTRPC_NT_NO_PROTSEQS_REGISTERED: u32 = 0xc002000f; +pub const SMB_NTRPC_NT_NOT_LISTENING: u32 = 0xc0020010; +pub const SMB_NTRPC_NT_UNKNOWN_MGR_TYPE: u32 = 0xc0020011; +pub const SMB_NTRPC_NT_UNKNOWN_IF: u32 = 0xc0020012; +pub const SMB_NTRPC_NT_NO_BINDINGS: u32 = 0xc0020013; +pub const SMB_NTRPC_NT_NO_PROTSEQS: u32 = 0xc0020014; +pub const SMB_NTRPC_NT_CANT_CREATE_ENDPOINT: u32 = 0xc0020015; +pub const SMB_NTRPC_NT_OUT_OF_RESOURCES: u32 = 0xc0020016; +pub const SMB_NTRPC_NT_SERVER_UNAVAILABLE: u32 = 0xc0020017; +pub const SMB_NTRPC_NT_SERVER_TOO_BUSY: u32 = 0xc0020018; +pub const SMB_NTRPC_NT_INVALID_NETWORK_OPTIONS: u32 = 0xc0020019; +pub const SMB_NTRPC_NT_NO_CALL_ACTIVE: u32 = 0xc002001a; +pub const SMB_NTRPC_NT_CALL_FAILED: u32 = 0xc002001b; +pub const SMB_NTRPC_NT_CALL_FAILED_DNE: u32 = 0xc002001c; +pub const SMB_NTRPC_NT_PROTOCOL_ERROR: u32 = 0xc002001d; +pub const SMB_NTRPC_NT_UNSUPPORTED_TRANS_SYN: u32 = 0xc002001f; +pub const SMB_NTRPC_NT_UNSUPPORTED_TYPE: u32 = 0xc0020021; +pub const SMB_NTRPC_NT_INVALID_TAG: u32 = 0xc0020022; +pub const SMB_NTRPC_NT_INVALID_BOUND: u32 = 0xc0020023; +pub const SMB_NTRPC_NT_NO_ENTRY_NAME: u32 = 0xc0020024; +pub const SMB_NTRPC_NT_INVALID_NAME_SYNTAX: u32 = 0xc0020025; +pub const SMB_NTRPC_NT_UNSUPPORTED_NAME_SYNTAX: u32 = 0xc0020026; +pub const SMB_NTRPC_NT_UUID_NO_ADDRESS: u32 = 0xc0020028; +pub const SMB_NTRPC_NT_DUPLICATE_ENDPOINT: u32 = 0xc0020029; +pub const SMB_NTRPC_NT_UNKNOWN_AUTHN_TYPE: u32 = 0xc002002a; +pub const SMB_NTRPC_NT_MAX_CALLS_TOO_SMALL: u32 = 0xc002002b; +pub const SMB_NTRPC_NT_STRING_TOO_LONG: u32 = 0xc002002c; +pub const SMB_NTRPC_NT_PROTSEQ_NOT_FOUND: u32 = 0xc002002d; +pub const SMB_NTRPC_NT_PROCNUM_OUT_OF_RANGE: u32 = 0xc002002e; +pub const SMB_NTRPC_NT_BINDING_HAS_NO_AUTH: u32 = 0xc002002f; +pub const SMB_NTRPC_NT_UNKNOWN_AUTHN_SERVICE: u32 = 0xc0020030; +pub const SMB_NTRPC_NT_UNKNOWN_AUTHN_LEVEL: u32 = 0xc0020031; +pub const SMB_NTRPC_NT_INVALID_AUTH_IDENTITY: u32 = 0xc0020032; +pub const SMB_NTRPC_NT_UNKNOWN_AUTHZ_SERVICE: u32 = 0xc0020033; +pub const SMB_NTEPT_NT_INVALID_ENTRY: u32 = 0xc0020034; +pub const SMB_NTEPT_NT_CANT_PERFORM_OP: u32 = 0xc0020035; +pub const SMB_NTEPT_NT_NOT_REGISTERED: u32 = 0xc0020036; +pub const SMB_NTRPC_NT_NOTHING_TO_EXPORT: u32 = 0xc0020037; +pub const SMB_NTRPC_NT_INCOMPLETE_NAME: u32 = 0xc0020038; +pub const SMB_NTRPC_NT_INVALID_VERS_OPTION: u32 = 0xc0020039; +pub const SMB_NTRPC_NT_NO_MORE_MEMBERS: u32 = 0xc002003a; +pub const SMB_NTRPC_NT_NOT_ALL_OBJS_UNEXPORTED: u32 = 0xc002003b; +pub const SMB_NTRPC_NT_INTERFACE_NOT_FOUND: u32 = 0xc002003c; +pub const SMB_NTRPC_NT_ENTRY_ALREADY_EXISTS: u32 = 0xc002003d; +pub const SMB_NTRPC_NT_ENTRY_NOT_FOUND: u32 = 0xc002003e; +pub const SMB_NTRPC_NT_NAME_SERVICE_UNAVAILABLE: u32 = 0xc002003f; +pub const SMB_NTRPC_NT_INVALID_NAF_ID: u32 = 0xc0020040; +pub const SMB_NTRPC_NT_CANNOT_SUPPORT: u32 = 0xc0020041; +pub const SMB_NTRPC_NT_NO_CONTEXT_AVAILABLE: u32 = 0xc0020042; +pub const SMB_NTRPC_NT_INTERNAL_ERROR: u32 = 0xc0020043; +pub const SMB_NTRPC_NT_ZERO_DIVIDE: u32 = 0xc0020044; +pub const SMB_NTRPC_NT_ADDRESS_ERROR: u32 = 0xc0020045; +pub const SMB_NTRPC_NT_FP_DIV_ZERO: u32 = 0xc0020046; +pub const SMB_NTRPC_NT_FP_UNDERFLOW: u32 = 0xc0020047; +pub const SMB_NTRPC_NT_FP_OVERFLOW: u32 = 0xc0020048; +pub const SMB_NTRPC_NT_CALL_IN_PROGRESS: u32 = 0xc0020049; +pub const SMB_NTRPC_NT_NO_MORE_BINDINGS: u32 = 0xc002004a; +pub const SMB_NTRPC_NT_GROUP_MEMBER_NOT_FOUND: u32 = 0xc002004b; +pub const SMB_NTEPT_NT_CANT_CREATE: u32 = 0xc002004c; +pub const SMB_NTRPC_NT_INVALID_OBJECT: u32 = 0xc002004d; +pub const SMB_NTRPC_NT_NO_INTERFACES: u32 = 0xc002004f; +pub const SMB_NTRPC_NT_CALL_CANCELLED: u32 = 0xc0020050; +pub const SMB_NTRPC_NT_BINDING_INCOMPLETE: u32 = 0xc0020051; +pub const SMB_NTRPC_NT_COMM_FAILURE: u32 = 0xc0020052; +pub const SMB_NTRPC_NT_UNSUPPORTED_AUTHN_LEVEL: u32 = 0xc0020053; +pub const SMB_NTRPC_NT_NO_PRINC_NAME: u32 = 0xc0020054; +pub const SMB_NTRPC_NT_NOT_RPC_ERROR: u32 = 0xc0020055; +pub const SMB_NTRPC_NT_SEC_PKG_ERROR: u32 = 0xc0020057; +pub const SMB_NTRPC_NT_NOT_CANCELLED: u32 = 0xc0020058; +pub const SMB_NTRPC_NT_INVALID_ASYNC_HANDLE: u32 = 0xc0020062; +pub const SMB_NTRPC_NT_INVALID_ASYNC_CALL: u32 = 0xc0020063; +pub const SMB_NTRPC_NT_PROXY_ACCESS_DENIED: u32 = 0xc0020064; +pub const SMB_NTRPC_NT_NO_MORE_ENTRIES: u32 = 0xc0030001; +pub const SMB_NTRPC_NT_SS_CHAR_TRANS_OPEN_FAIL: u32 = 0xc0030002; +pub const SMB_NTRPC_NT_SS_CHAR_TRANS_SHORT_FILE: u32 = 0xc0030003; +pub const SMB_NTRPC_NT_SS_IN_NULL_CONTEXT: u32 = 0xc0030004; +pub const SMB_NTRPC_NT_SS_CONTEXT_MISMATCH: u32 = 0xc0030005; +pub const SMB_NTRPC_NT_SS_CONTEXT_DAMAGED: u32 = 0xc0030006; +pub const SMB_NTRPC_NT_SS_HANDLES_MISMATCH: u32 = 0xc0030007; +pub const SMB_NTRPC_NT_SS_CANNOT_GET_CALL_HANDLE: u32 = 0xc0030008; +pub const SMB_NTRPC_NT_NULL_REF_POINTER: u32 = 0xc0030009; +pub const SMB_NTRPC_NT_ENUM_VALUE_OUT_OF_RANGE: u32 = 0xc003000a; +pub const SMB_NTRPC_NT_BYTE_COUNT_TOO_SMALL: u32 = 0xc003000b; +pub const SMB_NTRPC_NT_BAD_STUB_DATA: u32 = 0xc003000c; +pub const SMB_NTRPC_NT_INVALID_ES_ACTION: u32 = 0xc0030059; +pub const SMB_NTRPC_NT_WRONG_ES_VERSION: u32 = 0xc003005a; +pub const SMB_NTRPC_NT_WRONG_STUB_VERSION: u32 = 0xc003005b; +pub const SMB_NTRPC_NT_INVALID_PIPE_OBJECT: u32 = 0xc003005c; +pub const SMB_NTRPC_NT_INVALID_PIPE_OPERATION: u32 = 0xc003005d; +pub const SMB_NTRPC_NT_WRONG_PIPE_VERSION: u32 = 0xc003005e; +pub const SMB_NTRPC_NT_PIPE_CLOSED: u32 = 0xc003005f; +pub const SMB_NTRPC_NT_PIPE_DISCIPLINE_ERROR: u32 = 0xc0030060; +pub const SMB_NTRPC_NT_PIPE_EMPTY: u32 = 0xc0030061; +pub const SMB_NTSTATUS_PNP_BAD_MPS_TABLE: u32 = 0xc0040035; +pub const SMB_NTSTATUS_PNP_TRANSLATION_FAILED: u32 = 0xc0040036; +pub const SMB_NTSTATUS_PNP_IRQ_TRANSLATION_FAILED: u32 = 0xc0040037; +pub const SMB_NTSTATUS_PNP_INVALID_ID: u32 = 0xc0040038; +pub const SMB_NTSTATUS_IO_REISSUE_AS_CACHED: u32 = 0xc0040039; +pub const SMB_NTSTATUS_CTX_WINSTATION_NAME_INVALID: u32 = 0xc00a0001; +pub const SMB_NTSTATUS_CTX_INVALID_PD: u32 = 0xc00a0002; +pub const SMB_NTSTATUS_CTX_PD_NOT_FOUND: u32 = 0xc00a0003; +pub const SMB_NTSTATUS_CTX_CLOSE_PENDING: u32 = 0xc00a0006; +pub const SMB_NTSTATUS_CTX_NO_OUTBUF: u32 = 0xc00a0007; +pub const SMB_NTSTATUS_CTX_MODEM_INF_NOT_FOUND: u32 = 0xc00a0008; +pub const SMB_NTSTATUS_CTX_INVALID_MODEMNAME: u32 = 0xc00a0009; +pub const SMB_NTSTATUS_CTX_RESPONSE_ERROR: u32 = 0xc00a000a; +pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_TIMEOUT: u32 = 0xc00a000b; +pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_CARRIER: u32 = 0xc00a000c; +pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_DIALTONE: u32 = 0xc00a000d; +pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_BUSY: u32 = 0xc00a000e; +pub const SMB_NTSTATUS_CTX_MODEM_RESPONSE_VOICE: u32 = 0xc00a000f; +pub const SMB_NTSTATUS_CTX_TD_ERROR: u32 = 0xc00a0010; +pub const SMB_NTSTATUS_CTX_LICENSE_CLIENT_INVALID: u32 = 0xc00a0012; +pub const SMB_NTSTATUS_CTX_LICENSE_NOT_AVAILABLE: u32 = 0xc00a0013; +pub const SMB_NTSTATUS_CTX_LICENSE_EXPIRED: u32 = 0xc00a0014; +pub const SMB_NTSTATUS_CTX_WINSTATION_NOT_FOUND: u32 = 0xc00a0015; +pub const SMB_NTSTATUS_CTX_WINSTATION_NAME_COLLISION: u32 = 0xc00a0016; +pub const SMB_NTSTATUS_CTX_WINSTATION_BUSY: u32 = 0xc00a0017; +pub const SMB_NTSTATUS_CTX_BAD_VIDEO_MODE: u32 = 0xc00a0018; +pub const SMB_NTSTATUS_CTX_GRAPHICS_INVALID: u32 = 0xc00a0022; +pub const SMB_NTSTATUS_CTX_NOT_CONSOLE: u32 = 0xc00a0024; +pub const SMB_NTSTATUS_CTX_CLIENT_QUERY_TIMEOUT: u32 = 0xc00a0026; +pub const SMB_NTSTATUS_CTX_CONSOLE_DISCONNECT: u32 = 0xc00a0027; +pub const SMB_NTSTATUS_CTX_CONSOLE_CONNECT: u32 = 0xc00a0028; +pub const SMB_NTSTATUS_CTX_SHADOW_DENIED: u32 = 0xc00a002a; +pub const SMB_NTSTATUS_CTX_WINSTATION_ACCESS_DENIED: u32 = 0xc00a002b; +pub const SMB_NTSTATUS_CTX_INVALID_WD: u32 = 0xc00a002e; +pub const SMB_NTSTATUS_CTX_WD_NOT_FOUND: u32 = 0xc00a002f; +pub const SMB_NTSTATUS_CTX_SHADOW_INVALID: u32 = 0xc00a0030; +pub const SMB_NTSTATUS_CTX_SHADOW_DISABLED: u32 = 0xc00a0031; +pub const SMB_NTSTATUS_RDP_PROTOCOL_ERROR: u32 = 0xc00a0032; +pub const SMB_NTSTATUS_CTX_CLIENT_LICENSE_NOT_SET: u32 = 0xc00a0033; +pub const SMB_NTSTATUS_CTX_CLIENT_LICENSE_IN_USE: u32 = 0xc00a0034; +pub const SMB_NTSTATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE: u32 = 0xc00a0035; +pub const SMB_NTSTATUS_CTX_SHADOW_NOT_RUNNING: u32 = 0xc00a0036; +pub const SMB_NTSTATUS_CTX_LOGON_DISABLED: u32 = 0xc00a0037; +pub const SMB_NTSTATUS_CTX_SECURITY_LAYER_ERROR: u32 = 0xc00a0038; +pub const SMB_NTSTATUS_TS_INCOMPATIBLE_SESSIONS: u32 = 0xc00a0039; +pub const SMB_NTSTATUS_MUI_FILE_NOT_FOUND: u32 = 0xc00b0001; +pub const SMB_NTSTATUS_MUI_INVALID_FILE: u32 = 0xc00b0002; +pub const SMB_NTSTATUS_MUI_INVALID_RC_CONFIG: u32 = 0xc00b0003; +pub const SMB_NTSTATUS_MUI_INVALID_LOCALE_NAME: u32 = 0xc00b0004; +pub const SMB_NTSTATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME: u32 = 0xc00b0005; +pub const SMB_NTSTATUS_MUI_FILE_NOT_LOADED: u32 = 0xc00b0006; +pub const SMB_NTSTATUS_RESOURCE_ENUM_USER_STOP: u32 = 0xc00b0007; +pub const SMB_NTSTATUS_CLUSTER_INVALID_NODE: u32 = 0xc0130001; +pub const SMB_NTSTATUS_CLUSTER_NODE_EXISTS: u32 = 0xc0130002; +pub const SMB_NTSTATUS_CLUSTER_JOIN_IN_PROGRESS: u32 = 0xc0130003; +pub const SMB_NTSTATUS_CLUSTER_NODE_NOT_FOUND: u32 = 0xc0130004; +pub const SMB_NTSTATUS_CLUSTER_LOCAL_NODE_NOT_FOUND: u32 = 0xc0130005; +pub const SMB_NTSTATUS_CLUSTER_NETWORK_EXISTS: u32 = 0xc0130006; +pub const SMB_NTSTATUS_CLUSTER_NETWORK_NOT_FOUND: u32 = 0xc0130007; +pub const SMB_NTSTATUS_CLUSTER_NETINTERFACE_EXISTS: u32 = 0xc0130008; +pub const SMB_NTSTATUS_CLUSTER_NETINTERFACE_NOT_FOUND: u32 = 0xc0130009; +pub const SMB_NTSTATUS_CLUSTER_INVALID_REQUEST: u32 = 0xc013000a; +pub const SMB_NTSTATUS_CLUSTER_INVALID_NETWORK_PROVIDER: u32 = 0xc013000b; +pub const SMB_NTSTATUS_CLUSTER_NODE_DOWN: u32 = 0xc013000c; +pub const SMB_NTSTATUS_CLUSTER_NODE_UNREACHABLE: u32 = 0xc013000d; +pub const SMB_NTSTATUS_CLUSTER_NODE_NOT_MEMBER: u32 = 0xc013000e; +pub const SMB_NTSTATUS_CLUSTER_JOIN_NOT_IN_PROGRESS: u32 = 0xc013000f; +pub const SMB_NTSTATUS_CLUSTER_INVALID_NETWORK: u32 = 0xc0130010; +pub const SMB_NTSTATUS_CLUSTER_NO_NET_ADAPTERS: u32 = 0xc0130011; +pub const SMB_NTSTATUS_CLUSTER_NODE_UP: u32 = 0xc0130012; +pub const SMB_NTSTATUS_CLUSTER_NODE_PAUSED: u32 = 0xc0130013; +pub const SMB_NTSTATUS_CLUSTER_NODE_NOT_PAUSED: u32 = 0xc0130014; +pub const SMB_NTSTATUS_CLUSTER_NO_SECURITY_CONTEXT: u32 = 0xc0130015; +pub const SMB_NTSTATUS_CLUSTER_NETWORK_NOT_INTERNAL: u32 = 0xc0130016; +pub const SMB_NTSTATUS_CLUSTER_POISONED: u32 = 0xc0130017; +pub const SMB_NTSTATUS_ACPI_INVALID_OPCODE: u32 = 0xc0140001; +pub const SMB_NTSTATUS_ACPI_STACK_OVERFLOW: u32 = 0xc0140002; +pub const SMB_NTSTATUS_ACPI_ASSERT_FAILED: u32 = 0xc0140003; +pub const SMB_NTSTATUS_ACPI_INVALID_INDEX: u32 = 0xc0140004; +pub const SMB_NTSTATUS_ACPI_INVALID_ARGUMENT: u32 = 0xc0140005; +pub const SMB_NTSTATUS_ACPI_FATAL: u32 = 0xc0140006; +pub const SMB_NTSTATUS_ACPI_INVALID_SUPERNAME: u32 = 0xc0140007; +pub const SMB_NTSTATUS_ACPI_INVALID_ARGTYPE: u32 = 0xc0140008; +pub const SMB_NTSTATUS_ACPI_INVALID_OBJTYPE: u32 = 0xc0140009; +pub const SMB_NTSTATUS_ACPI_INVALID_TARGETTYPE: u32 = 0xc014000a; +pub const SMB_NTSTATUS_ACPI_INCORRECT_ARGUMENT_COUNT: u32 = 0xc014000b; +pub const SMB_NTSTATUS_ACPI_ADDRESS_NOT_MAPPED: u32 = 0xc014000c; +pub const SMB_NTSTATUS_ACPI_INVALID_EVENTTYPE: u32 = 0xc014000d; +pub const SMB_NTSTATUS_ACPI_HANDLER_COLLISION: u32 = 0xc014000e; +pub const SMB_NTSTATUS_ACPI_INVALID_DATA: u32 = 0xc014000f; +pub const SMB_NTSTATUS_ACPI_INVALID_REGION: u32 = 0xc0140010; +pub const SMB_NTSTATUS_ACPI_INVALID_ACCESS_SIZE: u32 = 0xc0140011; +pub const SMB_NTSTATUS_ACPI_ACQUIRE_GLOBAL_LOCK: u32 = 0xc0140012; +pub const SMB_NTSTATUS_ACPI_ALREADY_INITIALIZED: u32 = 0xc0140013; +pub const SMB_NTSTATUS_ACPI_NOT_INITIALIZED: u32 = 0xc0140014; +pub const SMB_NTSTATUS_ACPI_INVALID_MUTEX_LEVEL: u32 = 0xc0140015; +pub const SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNED: u32 = 0xc0140016; +pub const SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNER: u32 = 0xc0140017; +pub const SMB_NTSTATUS_ACPI_RS_ACCESS: u32 = 0xc0140018; +pub const SMB_NTSTATUS_ACPI_INVALID_TABLE: u32 = 0xc0140019; +pub const SMB_NTSTATUS_ACPI_REG_HANDLER_FAILED: u32 = 0xc0140020; +pub const SMB_NTSTATUS_ACPI_POWER_REQUEST_FAILED: u32 = 0xc0140021; +pub const SMB_NTSTATUS_SXS_SECTION_NOT_FOUND: u32 = 0xc0150001; +pub const SMB_NTSTATUS_SXS_CANT_GEN_ACTCTX: u32 = 0xc0150002; +pub const SMB_NTSTATUS_SXS_INVALID_ACTCTXDATA_FORMAT: u32 = 0xc0150003; +pub const SMB_NTSTATUS_SXS_ASSEMBLY_NOT_FOUND: u32 = 0xc0150004; +pub const SMB_NTSTATUS_SXS_MANIFEST_FORMAT_ERROR: u32 = 0xc0150005; +pub const SMB_NTSTATUS_SXS_MANIFEST_PARSE_ERROR: u32 = 0xc0150006; +pub const SMB_NTSTATUS_SXS_ACTIVATION_CONTEXT_DISABLED: u32 = 0xc0150007; +pub const SMB_NTSTATUS_SXS_KEY_NOT_FOUND: u32 = 0xc0150008; +pub const SMB_NTSTATUS_SXS_VERSION_CONFLICT: u32 = 0xc0150009; +pub const SMB_NTSTATUS_SXS_WRONG_SECTION_TYPE: u32 = 0xc015000a; +pub const SMB_NTSTATUS_SXS_THREAD_QUERIES_DISABLED: u32 = 0xc015000b; +pub const SMB_NTSTATUS_SXS_ASSEMBLY_MISSING: u32 = 0xc015000c; +pub const SMB_NTSTATUS_SXS_PROCESS_DEFAULT_ALREADY_SET: u32 = 0xc015000e; +pub const SMB_NTSTATUS_SXS_EARLY_DEACTIVATION: u32 = 0xc015000f; +pub const SMB_NTSTATUS_SXS_INVALID_DEACTIVATION: u32 = 0xc0150010; +pub const SMB_NTSTATUS_SXS_MULTIPLE_DEACTIVATION: u32 = 0xc0150011; +pub const SMB_NTSTATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY: u32 = 0xc0150012; +pub const SMB_NTSTATUS_SXS_PROCESS_TERMINATION_REQUESTED: u32 = 0xc0150013; +pub const SMB_NTSTATUS_SXS_CORRUPT_ACTIVATION_STACK: u32 = 0xc0150014; +pub const SMB_NTSTATUS_SXS_CORRUPTION: u32 = 0xc0150015; +pub const SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE: u32 = 0xc0150016; +pub const SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME: u32 = 0xc0150017; +pub const SMB_NTSTATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE: u32 = 0xc0150018; +pub const SMB_NTSTATUS_SXS_IDENTITY_PARSE_ERROR: u32 = 0xc0150019; +pub const SMB_NTSTATUS_SXS_COMPONENT_STORE_CORRUPT: u32 = 0xc015001a; +pub const SMB_NTSTATUS_SXS_FILE_HASH_MISMATCH: u32 = 0xc015001b; +pub const SMB_NTSTATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT: u32 = 0xc015001c; +pub const SMB_NTSTATUS_SXS_IDENTITIES_DIFFERENT: u32 = 0xc015001d; +pub const SMB_NTSTATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT: u32 = 0xc015001e; +pub const SMB_NTSTATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY: u32 = 0xc015001f; +pub const SMB_NTSTATUS_ADVANCED_INSTALLER_FAILED: u32 = 0xc0150020; +pub const SMB_NTSTATUS_XML_ENCODING_MISMATCH: u32 = 0xc0150021; +pub const SMB_NTSTATUS_SXS_MANIFEST_TOO_BIG: u32 = 0xc0150022; +pub const SMB_NTSTATUS_SXS_SETTING_NOT_REGISTERED: u32 = 0xc0150023; +pub const SMB_NTSTATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE: u32 = 0xc0150024; +pub const SMB_NTSTATUS_SMI_PRIMITIVE_INSTALLER_FAILED: u32 = 0xc0150025; +pub const SMB_NTSTATUS_GENERIC_COMMAND_FAILED: u32 = 0xc0150026; +pub const SMB_NTSTATUS_SXS_FILE_HASH_MISSING: u32 = 0xc0150027; +pub const SMB_NTSTATUS_TRANSACTIONAL_CONFLICT: u32 = 0xc0190001; +pub const SMB_NTSTATUS_INVALID_TRANSACTION: u32 = 0xc0190002; +pub const SMB_NTSTATUS_TRANSACTION_NOT_ACTIVE: u32 = 0xc0190003; +pub const SMB_NTSTATUS_TM_INITIALIZATION_FAILED: u32 = 0xc0190004; +pub const SMB_NTSTATUS_RM_NOT_ACTIVE: u32 = 0xc0190005; +pub const SMB_NTSTATUS_RM_METADATA_CORRUPT: u32 = 0xc0190006; +pub const SMB_NTSTATUS_TRANSACTION_NOT_JOINED: u32 = 0xc0190007; +pub const SMB_NTSTATUS_DIRECTORY_NOT_RM: u32 = 0xc0190008; +pub const SMB_NTSTATUS_TRANSACTIONS_UNSUPPORTED_REMOTE: u32 = 0xc019000a; +pub const SMB_NTSTATUS_LOG_RESIZE_INVALID_SIZE: u32 = 0xc019000b; +pub const SMB_NTSTATUS_REMOTE_FILE_VERSION_MISMATCH: u32 = 0xc019000c; +pub const SMB_NTSTATUS_CRM_PROTOCOL_ALREADY_EXISTS: u32 = 0xc019000f; +pub const SMB_NTSTATUS_TRANSACTION_PROPAGATION_FAILED: u32 = 0xc0190010; +pub const SMB_NTSTATUS_CRM_PROTOCOL_NOT_FOUND: u32 = 0xc0190011; +pub const SMB_NTSTATUS_TRANSACTION_SUPERIOR_EXISTS: u32 = 0xc0190012; +pub const SMB_NTSTATUS_TRANSACTION_REQUEST_NOT_VALID: u32 = 0xc0190013; +pub const SMB_NTSTATUS_TRANSACTION_NOT_REQUESTED: u32 = 0xc0190014; +pub const SMB_NTSTATUS_TRANSACTION_ALREADY_ABORTED: u32 = 0xc0190015; +pub const SMB_NTSTATUS_TRANSACTION_ALREADY_COMMITTED: u32 = 0xc0190016; +pub const SMB_NTSTATUS_TRANSACTION_INVALID_MARSHALL_BUFFER: u32 = 0xc0190017; +pub const SMB_NTSTATUS_CURRENT_TRANSACTION_NOT_VALID: u32 = 0xc0190018; +pub const SMB_NTSTATUS_LOG_GROWTH_FAILED: u32 = 0xc0190019; +pub const SMB_NTSTATUS_OBJECT_NO_LONGER_EXISTS: u32 = 0xc0190021; +pub const SMB_NTSTATUS_STREAM_MINIVERSION_NOT_FOUND: u32 = 0xc0190022; +pub const SMB_NTSTATUS_STREAM_MINIVERSION_NOT_VALID: u32 = 0xc0190023; +pub const SMB_NTSTATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION: u32 = 0xc0190024; +pub const SMB_NTSTATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT: u32 = 0xc0190025; +pub const SMB_NTSTATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS: u32 = 0xc0190026; +pub const SMB_NTSTATUS_HANDLE_NO_LONGER_VALID: u32 = 0xc0190028; +pub const SMB_NTSTATUS_LOG_CORRUPTION_DETECTED: u32 = 0xc0190030; +pub const SMB_NTSTATUS_RM_DISCONNECTED: u32 = 0xc0190032; +pub const SMB_NTSTATUS_ENLISTMENT_NOT_SUPERIOR: u32 = 0xc0190033; +pub const SMB_NTSTATUS_FILE_IDENTITY_NOT_PERSISTENT: u32 = 0xc0190036; +pub const SMB_NTSTATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY: u32 = 0xc0190037; +pub const SMB_NTSTATUS_CANT_CROSS_RM_BOUNDARY: u32 = 0xc0190038; +pub const SMB_NTSTATUS_TXF_DIR_NOT_EMPTY: u32 = 0xc0190039; +pub const SMB_NTSTATUS_INDOUBT_TRANSACTIONS_EXIST: u32 = 0xc019003a; +pub const SMB_NTSTATUS_TM_VOLATILE: u32 = 0xc019003b; +pub const SMB_NTSTATUS_ROLLBACK_TIMER_EXPIRED: u32 = 0xc019003c; +pub const SMB_NTSTATUS_TXF_ATTRIBUTE_CORRUPT: u32 = 0xc019003d; +pub const SMB_NTSTATUS_EFS_NOT_ALLOWED_IN_TRANSACTION: u32 = 0xc019003e; +pub const SMB_NTSTATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED: u32 = 0xc019003f; +pub const SMB_NTSTATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE: u32 = 0xc0190040; +pub const SMB_NTSTATUS_TRANSACTION_REQUIRED_PROMOTION: u32 = 0xc0190043; +pub const SMB_NTSTATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION: u32 = 0xc0190044; +pub const SMB_NTSTATUS_TRANSACTIONS_NOT_FROZEN: u32 = 0xc0190045; +pub const SMB_NTSTATUS_TRANSACTION_FREEZE_IN_PROGRESS: u32 = 0xc0190046; +pub const SMB_NTSTATUS_NOT_SNAPSHOT_VOLUME: u32 = 0xc0190047; +pub const SMB_NTSTATUS_NO_SAVEPOINT_WITH_OPEN_FILES: u32 = 0xc0190048; +pub const SMB_NTSTATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION: u32 = 0xc0190049; +pub const SMB_NTSTATUS_TM_IDENTITY_MISMATCH: u32 = 0xc019004a; +pub const SMB_NTSTATUS_FLOATED_SECTION: u32 = 0xc019004b; +pub const SMB_NTSTATUS_CANNOT_ACCEPT_TRANSACTED_WORK: u32 = 0xc019004c; +pub const SMB_NTSTATUS_CANNOT_ABORT_TRANSACTIONS: u32 = 0xc019004d; +pub const SMB_NTSTATUS_TRANSACTION_NOT_FOUND: u32 = 0xc019004e; +pub const SMB_NTSTATUS_RESOURCEMANAGER_NOT_FOUND: u32 = 0xc019004f; +pub const SMB_NTSTATUS_ENLISTMENT_NOT_FOUND: u32 = 0xc0190050; +pub const SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_FOUND: u32 = 0xc0190051; +pub const SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_ONLINE: u32 = 0xc0190052; +pub const SMB_NTSTATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION: u32 = 0xc0190053; +pub const SMB_NTSTATUS_TRANSACTION_NOT_ROOT: u32 = 0xc0190054; +pub const SMB_NTSTATUS_TRANSACTION_OBJECT_EXPIRED: u32 = 0xc0190055; +pub const SMB_NTSTATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION: u32 = 0xc0190056; +pub const SMB_NTSTATUS_TRANSACTION_RESPONSE_NOT_ENLISTED: u32 = 0xc0190057; +pub const SMB_NTSTATUS_TRANSACTION_RECORD_TOO_LONG: u32 = 0xc0190058; +pub const SMB_NTSTATUS_NO_LINK_TRACKING_IN_TRANSACTION: u32 = 0xc0190059; +pub const SMB_NTSTATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION: u32 = 0xc019005a; +pub const SMB_NTSTATUS_TRANSACTION_INTEGRITY_VIOLATED: u32 = 0xc019005b; +pub const SMB_NTSTATUS_EXPIRED_HANDLE: u32 = 0xc0190060; +pub const SMB_NTSTATUS_TRANSACTION_NOT_ENLISTED: u32 = 0xc0190061; +pub const SMB_NTSTATUS_LOG_SECTOR_INVALID: u32 = 0xc01a0001; +pub const SMB_NTSTATUS_LOG_SECTOR_PARITY_INVALID: u32 = 0xc01a0002; +pub const SMB_NTSTATUS_LOG_SECTOR_REMAPPED: u32 = 0xc01a0003; +pub const SMB_NTSTATUS_LOG_BLOCK_INCOMPLETE: u32 = 0xc01a0004; +pub const SMB_NTSTATUS_LOG_INVALID_RANGE: u32 = 0xc01a0005; +pub const SMB_NTSTATUS_LOG_BLOCKS_EXHAUSTED: u32 = 0xc01a0006; +pub const SMB_NTSTATUS_LOG_READ_CONTEXT_INVALID: u32 = 0xc01a0007; +pub const SMB_NTSTATUS_LOG_RESTART_INVALID: u32 = 0xc01a0008; +pub const SMB_NTSTATUS_LOG_BLOCK_VERSION: u32 = 0xc01a0009; +pub const SMB_NTSTATUS_LOG_BLOCK_INVALID: u32 = 0xc01a000a; +pub const SMB_NTSTATUS_LOG_READ_MODE_INVALID: u32 = 0xc01a000b; +pub const SMB_NTSTATUS_LOG_METADATA_CORRUPT: u32 = 0xc01a000d; +pub const SMB_NTSTATUS_LOG_METADATA_INVALID: u32 = 0xc01a000e; +pub const SMB_NTSTATUS_LOG_METADATA_INCONSISTENT: u32 = 0xc01a000f; +pub const SMB_NTSTATUS_LOG_RESERVATION_INVALID: u32 = 0xc01a0010; +pub const SMB_NTSTATUS_LOG_CANT_DELETE: u32 = 0xc01a0011; +pub const SMB_NTSTATUS_LOG_CONTAINER_LIMIT_EXCEEDED: u32 = 0xc01a0012; +pub const SMB_NTSTATUS_LOG_START_OF_LOG: u32 = 0xc01a0013; +pub const SMB_NTSTATUS_LOG_POLICY_ALREADY_INSTALLED: u32 = 0xc01a0014; +pub const SMB_NTSTATUS_LOG_POLICY_NOT_INSTALLED: u32 = 0xc01a0015; +pub const SMB_NTSTATUS_LOG_POLICY_INVALID: u32 = 0xc01a0016; +pub const SMB_NTSTATUS_LOG_POLICY_CONFLICT: u32 = 0xc01a0017; +pub const SMB_NTSTATUS_LOG_PINNED_ARCHIVE_TAIL: u32 = 0xc01a0018; +pub const SMB_NTSTATUS_LOG_RECORD_NONEXISTENT: u32 = 0xc01a0019; +pub const SMB_NTSTATUS_LOG_RECORDS_RESERVED_INVALID: u32 = 0xc01a001a; +pub const SMB_NTSTATUS_LOG_SPACE_RESERVED_INVALID: u32 = 0xc01a001b; +pub const SMB_NTSTATUS_LOG_TAIL_INVALID: u32 = 0xc01a001c; +pub const SMB_NTSTATUS_LOG_FULL: u32 = 0xc01a001d; +pub const SMB_NTSTATUS_LOG_MULTIPLEXED: u32 = 0xc01a001e; +pub const SMB_NTSTATUS_LOG_DEDICATED: u32 = 0xc01a001f; +pub const SMB_NTSTATUS_LOG_ARCHIVE_NOT_IN_PROGRESS: u32 = 0xc01a0020; +pub const SMB_NTSTATUS_LOG_ARCHIVE_IN_PROGRESS: u32 = 0xc01a0021; +pub const SMB_NTSTATUS_LOG_EPHEMERAL: u32 = 0xc01a0022; +pub const SMB_NTSTATUS_LOG_NOT_ENOUGH_CONTAINERS: u32 = 0xc01a0023; +pub const SMB_NTSTATUS_LOG_CLIENT_ALREADY_REGISTERED: u32 = 0xc01a0024; +pub const SMB_NTSTATUS_LOG_CLIENT_NOT_REGISTERED: u32 = 0xc01a0025; +pub const SMB_NTSTATUS_LOG_FULL_HANDLER_IN_PROGRESS: u32 = 0xc01a0026; +pub const SMB_NTSTATUS_LOG_CONTAINER_READ_FAILED: u32 = 0xc01a0027; +pub const SMB_NTSTATUS_LOG_CONTAINER_WRITE_FAILED: u32 = 0xc01a0028; +pub const SMB_NTSTATUS_LOG_CONTAINER_OPEN_FAILED: u32 = 0xc01a0029; +pub const SMB_NTSTATUS_LOG_CONTAINER_STATE_INVALID: u32 = 0xc01a002a; +pub const SMB_NTSTATUS_LOG_STATE_INVALID: u32 = 0xc01a002b; +pub const SMB_NTSTATUS_LOG_PINNED: u32 = 0xc01a002c; +pub const SMB_NTSTATUS_LOG_METADATA_FLUSH_FAILED: u32 = 0xc01a002d; +pub const SMB_NTSTATUS_LOG_INCONSISTENT_SECURITY: u32 = 0xc01a002e; +pub const SMB_NTSTATUS_LOG_APPENDED_FLUSH_FAILED: u32 = 0xc01a002f; +pub const SMB_NTSTATUS_LOG_PINNED_RESERVATION: u32 = 0xc01a0030; +pub const SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD: u32 = 0xc01b00ea; +pub const SMB_NTSTATUS_FLT_NO_HANDLER_DEFINED: u32 = 0xc01c0001; +pub const SMB_NTSTATUS_FLT_CONTEXT_ALREADY_DEFINED: u32 = 0xc01c0002; +pub const SMB_NTSTATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST: u32 = 0xc01c0003; +pub const SMB_NTSTATUS_FLT_DISALLOW_FAST_IO: u32 = 0xc01c0004; +pub const SMB_NTSTATUS_FLT_INVALID_NAME_REQUEST: u32 = 0xc01c0005; +pub const SMB_NTSTATUS_FLT_NOT_SAFE_TO_POST_OPERATION: u32 = 0xc01c0006; +pub const SMB_NTSTATUS_FLT_NOT_INITIALIZED: u32 = 0xc01c0007; +pub const SMB_NTSTATUS_FLT_FILTER_NOT_READY: u32 = 0xc01c0008; +pub const SMB_NTSTATUS_FLT_POST_OPERATION_CLEANUP: u32 = 0xc01c0009; +pub const SMB_NTSTATUS_FLT_INTERNAL_ERROR: u32 = 0xc01c000a; +pub const SMB_NTSTATUS_FLT_DELETING_OBJECT: u32 = 0xc01c000b; +pub const SMB_NTSTATUS_FLT_MUST_BE_NONPAGED_POOL: u32 = 0xc01c000c; +pub const SMB_NTSTATUS_FLT_DUPLICATE_ENTRY: u32 = 0xc01c000d; +pub const SMB_NTSTATUS_FLT_CBDQ_DISABLED: u32 = 0xc01c000e; +pub const SMB_NTSTATUS_FLT_DO_NOT_ATTACH: u32 = 0xc01c000f; +pub const SMB_NTSTATUS_FLT_DO_NOT_DETACH: u32 = 0xc01c0010; +pub const SMB_NTSTATUS_FLT_INSTANCE_ALTITUDE_COLLISION: u32 = 0xc01c0011; +pub const SMB_NTSTATUS_FLT_INSTANCE_NAME_COLLISION: u32 = 0xc01c0012; +pub const SMB_NTSTATUS_FLT_FILTER_NOT_FOUND: u32 = 0xc01c0013; +pub const SMB_NTSTATUS_FLT_VOLUME_NOT_FOUND: u32 = 0xc01c0014; +pub const SMB_NTSTATUS_FLT_INSTANCE_NOT_FOUND: u32 = 0xc01c0015; +pub const SMB_NTSTATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND: u32 = 0xc01c0016; +pub const SMB_NTSTATUS_FLT_INVALID_CONTEXT_REGISTRATION: u32 = 0xc01c0017; +pub const SMB_NTSTATUS_FLT_NAME_CACHE_MISS: u32 = 0xc01c0018; +pub const SMB_NTSTATUS_FLT_NO_DEVICE_OBJECT: u32 = 0xc01c0019; +pub const SMB_NTSTATUS_FLT_VOLUME_ALREADY_MOUNTED: u32 = 0xc01c001a; +pub const SMB_NTSTATUS_FLT_ALREADY_ENLISTED: u32 = 0xc01c001b; +pub const SMB_NTSTATUS_FLT_CONTEXT_ALREADY_LINKED: u32 = 0xc01c001c; +pub const SMB_NTSTATUS_FLT_NO_WAITER_FOR_REPLY: u32 = 0xc01c0020; +pub const SMB_NTSTATUS_MONITOR_NO_DESCRIPTOR: u32 = 0xc01d0001; +pub const SMB_NTSTATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT: u32 = 0xc01d0002; +pub const SMB_NTSTATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM: u32 = 0xc01d0003; +pub const SMB_NTSTATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK: u32 = 0xc01d0004; +pub const SMB_NTSTATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED: u32 = 0xc01d0005; +pub const SMB_NTSTATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK: u32 = 0xc01d0006; +pub const SMB_NTSTATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK: u32 = 0xc01d0007; +pub const SMB_NTSTATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA: u32 = 0xc01d0008; +pub const SMB_NTSTATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK: u32 = 0xc01d0009; +pub const SMB_NTSTATUS_MONITOR_INVALID_MANUFACTURE_DATE: u32 = 0xc01d000a; +pub const SMB_NTSTATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER: u32 = 0xc01e0000; +pub const SMB_NTSTATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER: u32 = 0xc01e0001; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER: u32 = 0xc01e0002; +pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_WAS_RESET: u32 = 0xc01e0003; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_DRIVER_MODEL: u32 = 0xc01e0004; +pub const SMB_NTSTATUS_GRAPHICS_PRESENT_MODE_CHANGED: u32 = 0xc01e0005; +pub const SMB_NTSTATUS_GRAPHICS_PRESENT_OCCLUDED: u32 = 0xc01e0006; +pub const SMB_NTSTATUS_GRAPHICS_PRESENT_DENIED: u32 = 0xc01e0007; +pub const SMB_NTSTATUS_GRAPHICS_CANNOTCOLORCONVERT: u32 = 0xc01e0008; +pub const SMB_NTSTATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED: u32 = 0xc01e000b; +pub const SMB_NTSTATUS_GRAPHICS_PRESENT_UNOCCLUDED: u32 = 0xc01e000c; +pub const SMB_NTSTATUS_GRAPHICS_NO_VIDEO_MEMORY: u32 = 0xc01e0100; +pub const SMB_NTSTATUS_GRAPHICS_CANT_LOCK_MEMORY: u32 = 0xc01e0101; +pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_BUSY: u32 = 0xc01e0102; +pub const SMB_NTSTATUS_GRAPHICS_TOO_MANY_REFERENCES: u32 = 0xc01e0103; +pub const SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_LATER: u32 = 0xc01e0104; +pub const SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_NOW: u32 = 0xc01e0105; +pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_INVALID: u32 = 0xc01e0106; +pub const SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE: u32 = 0xc01e0107; +pub const SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED: u32 = 0xc01e0108; +pub const SMB_NTSTATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION: u32 = 0xc01e0109; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_USAGE: u32 = 0xc01e0110; +pub const SMB_NTSTATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION: u32 = 0xc01e0111; +pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_CLOSED: u32 = 0xc01e0112; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE: u32 = 0xc01e0113; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE: u32 = 0xc01e0114; +pub const SMB_NTSTATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE: u32 = 0xc01e0115; +pub const SMB_NTSTATUS_GRAPHICS_ALLOCATION_CONTENT_LOST: u32 = 0xc01e0116; +pub const SMB_NTSTATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE: u32 = 0xc01e0200; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY: u32 = 0xc01e0300; +pub const SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED: u32 = 0xc01e0301; +pub const SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED: u32 = 0xc01e0302; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN: u32 = 0xc01e0303; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE: u32 = 0xc01e0304; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET: u32 = 0xc01e0305; +pub const SMB_NTSTATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED: u32 = 0xc01e0306; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET: u32 = 0xc01e0308; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET: u32 = 0xc01e0309; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_FREQUENCY: u32 = 0xc01e030a; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_ACTIVE_REGION: u32 = 0xc01e030b; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_TOTAL_REGION: u32 = 0xc01e030c; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE: u32 = 0xc01e0310; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE: u32 = 0xc01e0311; +pub const SMB_NTSTATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET: u32 = 0xc01e0312; +pub const SMB_NTSTATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY: u32 = 0xc01e0313; +pub const SMB_NTSTATUS_GRAPHICS_MODE_ALREADY_IN_MODESET: u32 = 0xc01e0314; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET: u32 = 0xc01e0315; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET: u32 = 0xc01e0316; +pub const SMB_NTSTATUS_GRAPHICS_SOURCE_ALREADY_IN_SET: u32 = 0xc01e0317; +pub const SMB_NTSTATUS_GRAPHICS_TARGET_ALREADY_IN_SET: u32 = 0xc01e0318; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH: u32 = 0xc01e0319; +pub const SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY: u32 = 0xc01e031a; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET: u32 = 0xc01e031b; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE: u32 = 0xc01e031c; +pub const SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET: u32 = 0xc01e031d; +pub const SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET: u32 = 0xc01e031f; +pub const SMB_NTSTATUS_GRAPHICS_STALE_MODESET: u32 = 0xc01e0320; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET: u32 = 0xc01e0321; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE: u32 = 0xc01e0322; +pub const SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN: u32 = 0xc01e0323; +pub const SMB_NTSTATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE: u32 = 0xc01e0324; +pub const SMB_NTSTATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION: u32 = 0xc01e0325; +pub const SMB_NTSTATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES: u32 = 0xc01e0326; +pub const SMB_NTSTATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY: u32 = 0xc01e0327; +pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE: u32 = 0xc01e0328; +pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET: u32 = 0xc01e0329; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET: u32 = 0xc01e032a; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR: u32 = 0xc01e032b; +pub const SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET: u32 = 0xc01e032c; +pub const SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET: u32 = 0xc01e032d; +pub const SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE: u32 = 0xc01e032e; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE: u32 = 0xc01e032f; +pub const SMB_NTSTATUS_GRAPHICS_RESOURCES_NOT_RELATED: u32 = 0xc01e0330; +pub const SMB_NTSTATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE: u32 = 0xc01e0331; +pub const SMB_NTSTATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE: u32 = 0xc01e0332; +pub const SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET: u32 = 0xc01e0333; +pub const SMB_NTSTATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER: u32 = 0xc01e0334; +pub const SMB_NTSTATUS_GRAPHICS_NO_VIDPNMGR: u32 = 0xc01e0335; +pub const SMB_NTSTATUS_GRAPHICS_NO_ACTIVE_VIDPN: u32 = 0xc01e0336; +pub const SMB_NTSTATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY: u32 = 0xc01e0337; +pub const SMB_NTSTATUS_GRAPHICS_MONITOR_NOT_CONNECTED: u32 = 0xc01e0338; +pub const SMB_NTSTATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY: u32 = 0xc01e0339; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE: u32 = 0xc01e033a; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE: u32 = 0xc01e033b; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_STRIDE: u32 = 0xc01e033c; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_PIXELFORMAT: u32 = 0xc01e033d; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_COLORBASIS: u32 = 0xc01e033e; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE: u32 = 0xc01e033f; +pub const SMB_NTSTATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY: u32 = 0xc01e0340; +pub const SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT: u32 = 0xc01e0341; +pub const SMB_NTSTATUS_GRAPHICS_VIDPN_SOURCE_IN_USE: u32 = 0xc01e0342; +pub const SMB_NTSTATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN: u32 = 0xc01e0343; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL: u32 = 0xc01e0344; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION: u32 = 0xc01e0345; +pub const SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED: u32 = + 0xc01e0346; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_GAMMA_RAMP: u32 = 0xc01e0347; +pub const SMB_NTSTATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED: u32 = 0xc01e0348; +pub const SMB_NTSTATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED: u32 = 0xc01e0349; +pub const SMB_NTSTATUS_GRAPHICS_MODE_NOT_IN_MODESET: u32 = 0xc01e034a; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON: u32 = 0xc01e034d; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE: u32 = 0xc01e034e; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE: u32 = 0xc01e034f; +pub const SMB_NTSTATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS: u32 = 0xc01e0350; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_SCANLINE_ORDERING: u32 = 0xc01e0352; +pub const SMB_NTSTATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED: u32 = 0xc01e0353; +pub const SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS: u32 = 0xc01e0354; +pub const SMB_NTSTATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT: u32 = 0xc01e0355; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM: u32 = 0xc01e0356; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN: u32 = 0xc01e0357; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT: u32 = 0xc01e0358; +pub const SMB_NTSTATUS_GRAPHICS_MAX_NUM_PATHS_REACHED: u32 = 0xc01e0359; +pub const SMB_NTSTATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION: u32 = 0xc01e035a; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_CLIENT_TYPE: u32 = 0xc01e035b; +pub const SMB_NTSTATUS_GRAPHICS_CLIENTVIDPN_NOT_SET: u32 = 0xc01e035c; +pub const SMB_NTSTATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED: u32 = 0xc01e0400; +pub const SMB_NTSTATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED: u32 = 0xc01e0401; +pub const SMB_NTSTATUS_GRAPHICS_NOT_A_LINKED_ADAPTER: u32 = 0xc01e0430; +pub const SMB_NTSTATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED: u32 = 0xc01e0431; +pub const SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED: u32 = 0xc01e0432; +pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY: u32 = 0xc01e0433; +pub const SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_STARTED: u32 = 0xc01e0434; +pub const SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON: u32 = 0xc01e0435; +pub const SMB_NTSTATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE: u32 = 0xc01e0436; +pub const SMB_NTSTATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER: u32 = 0xc01e0438; +pub const SMB_NTSTATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED: u32 = 0xc01e043b; +pub const SMB_NTSTATUS_GRAPHICS_OPM_NOT_SUPPORTED: u32 = 0xc01e0500; +pub const SMB_NTSTATUS_GRAPHICS_COPP_NOT_SUPPORTED: u32 = 0xc01e0501; +pub const SMB_NTSTATUS_GRAPHICS_UAB_NOT_SUPPORTED: u32 = 0xc01e0502; +pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS: u32 = 0xc01e0503; +pub const SMB_NTSTATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL: u32 = 0xc01e0504; +pub const SMB_NTSTATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST: u32 = 0xc01e0505; +pub const SMB_NTSTATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME: u32 = 0xc01e0506; +pub const SMB_NTSTATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP: u32 = 0xc01e0507; +pub const SMB_NTSTATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED: u32 = 0xc01e0508; +pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_POINTER: u32 = 0xc01e050a; +pub const SMB_NTSTATUS_GRAPHICS_OPM_INTERNAL_ERROR: u32 = 0xc01e050b; +pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_HANDLE: u32 = 0xc01e050c; +pub const SMB_NTSTATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE: u32 = 0xc01e050d; +pub const SMB_NTSTATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH: u32 = 0xc01e050e; +pub const SMB_NTSTATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED: u32 = 0xc01e050f; +pub const SMB_NTSTATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED: u32 = 0xc01e0510; +pub const SMB_NTSTATUS_GRAPHICS_PVP_HFS_FAILED: u32 = 0xc01e0511; +pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_SRM: u32 = 0xc01e0512; +pub const SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP: u32 = 0xc01e0513; +pub const SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP: u32 = 0xc01e0514; +pub const SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA: u32 = 0xc01e0515; +pub const SMB_NTSTATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET: u32 = 0xc01e0516; +pub const SMB_NTSTATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH: u32 = 0xc01e0517; +pub const SMB_NTSTATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE: u32 = 0xc01e0518; +pub const SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS: u32 = 0xc01e051a; +pub const SMB_NTSTATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS: u32 = 0xc01e051b; +pub const SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS: u32 = 0xc01e051c; +pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST: u32 = 0xc01e051d; +pub const SMB_NTSTATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR: u32 = 0xc01e051e; +pub const SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS: u32 = 0xc01e051f; +pub const SMB_NTSTATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED: u32 = 0xc01e0520; +pub const SMB_NTSTATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST: u32 = 0xc01e0521; +pub const SMB_NTSTATUS_GRAPHICS_I2C_NOT_SUPPORTED: u32 = 0xc01e0580; +pub const SMB_NTSTATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST: u32 = 0xc01e0581; +pub const SMB_NTSTATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA: u32 = 0xc01e0582; +pub const SMB_NTSTATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA: u32 = 0xc01e0583; +pub const SMB_NTSTATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED: u32 = 0xc01e0584; +pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_DATA: u32 = 0xc01e0585; +pub const SMB_NTSTATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE: u32 = 0xc01e0586; +pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING: u32 = 0xc01e0587; +pub const SMB_NTSTATUS_GRAPHICS_MCA_INTERNAL_ERROR: u32 = 0xc01e0588; +pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND: u32 = 0xc01e0589; +pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH: u32 = 0xc01e058a; +pub const SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM: u32 = 0xc01e058b; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE: u32 = 0xc01e058c; +pub const SMB_NTSTATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS: u32 = 0xc01e058d; +pub const SMB_NTSTATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED: u32 = 0xc01e05e0; +pub const SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME: u32 = 0xc01e05e1; +pub const SMB_NTSTATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP: u32 = 0xc01e05e2; +pub const SMB_NTSTATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED: u32 = 0xc01e05e3; +pub const SMB_NTSTATUS_GRAPHICS_INVALID_POINTER: u32 = 0xc01e05e4; +pub const SMB_NTSTATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE: u32 = 0xc01e05e5; +pub const SMB_NTSTATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL: u32 = 0xc01e05e6; +pub const SMB_NTSTATUS_GRAPHICS_INTERNAL_ERROR: u32 = 0xc01e05e7; +pub const SMB_NTSTATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS: u32 = 0xc01e05e8; +pub const SMB_NTSTATUS_FVE_LOCKED_VOLUME: u32 = 0xc0210000; +pub const SMB_NTSTATUS_FVE_NOT_ENCRYPTED: u32 = 0xc0210001; +pub const SMB_NTSTATUS_FVE_BAD_INFORMATION: u32 = 0xc0210002; +pub const SMB_NTSTATUS_FVE_TOO_SMALL: u32 = 0xc0210003; +pub const SMB_NTSTATUS_FVE_FAILED_WRONG_FS: u32 = 0xc0210004; +pub const SMB_NTSTATUS_FVE_FAILED_BAD_FS: u32 = 0xc0210005; +pub const SMB_NTSTATUS_FVE_FS_NOT_EXTENDED: u32 = 0xc0210006; +pub const SMB_NTSTATUS_FVE_FS_MOUNTED: u32 = 0xc0210007; +pub const SMB_NTSTATUS_FVE_NO_LICENSE: u32 = 0xc0210008; +pub const SMB_NTSTATUS_FVE_ACTION_NOT_ALLOWED: u32 = 0xc0210009; +pub const SMB_NTSTATUS_FVE_BAD_DATA: u32 = 0xc021000a; +pub const SMB_NTSTATUS_FVE_VOLUME_NOT_BOUND: u32 = 0xc021000b; +pub const SMB_NTSTATUS_FVE_NOT_DATA_VOLUME: u32 = 0xc021000c; +pub const SMB_NTSTATUS_FVE_CONV_READ_ERROR: u32 = 0xc021000d; +pub const SMB_NTSTATUS_FVE_CONV_WRITE_ERROR: u32 = 0xc021000e; +pub const SMB_NTSTATUS_FVE_OVERLAPPED_UPDATE: u32 = 0xc021000f; +pub const SMB_NTSTATUS_FVE_FAILED_SECTOR_SIZE: u32 = 0xc0210010; +pub const SMB_NTSTATUS_FVE_FAILED_AUTHENTICATION: u32 = 0xc0210011; +pub const SMB_NTSTATUS_FVE_NOT_OS_VOLUME: u32 = 0xc0210012; +pub const SMB_NTSTATUS_FVE_KEYFILE_NOT_FOUND: u32 = 0xc0210013; +pub const SMB_NTSTATUS_FVE_KEYFILE_INVALID: u32 = 0xc0210014; +pub const SMB_NTSTATUS_FVE_KEYFILE_NO_VMK: u32 = 0xc0210015; +pub const SMB_NTSTATUS_FVE_TPM_DISABLED: u32 = 0xc0210016; +pub const SMB_NTSTATUS_FVE_TPM_SRK_AUTH_NOT_ZERO: u32 = 0xc0210017; +pub const SMB_NTSTATUS_FVE_TPM_INVALID_PCR: u32 = 0xc0210018; +pub const SMB_NTSTATUS_FVE_TPM_NO_VMK: u32 = 0xc0210019; +pub const SMB_NTSTATUS_FVE_PIN_INVALID: u32 = 0xc021001a; +pub const SMB_NTSTATUS_FVE_AUTH_INVALID_APPLICATION: u32 = 0xc021001b; +pub const SMB_NTSTATUS_FVE_AUTH_INVALID_CONFIG: u32 = 0xc021001c; +pub const SMB_NTSTATUS_FVE_DEBUGGER_ENABLED: u32 = 0xc021001d; +pub const SMB_NTSTATUS_FVE_DRY_RUN_FAILED: u32 = 0xc021001e; +pub const SMB_NTSTATUS_FVE_BAD_METADATA_POINTER: u32 = 0xc021001f; +pub const SMB_NTSTATUS_FVE_OLD_METADATA_COPY: u32 = 0xc0210020; +pub const SMB_NTSTATUS_FVE_REBOOT_REQUIRED: u32 = 0xc0210021; +pub const SMB_NTSTATUS_FVE_RAW_ACCESS: u32 = 0xc0210022; +pub const SMB_NTSTATUS_FVE_RAW_BLOCKED: u32 = 0xc0210023; +pub const SMB_NTSTATUS_FVE_NO_FEATURE_LICENSE: u32 = 0xc0210026; +pub const SMB_NTSTATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED: u32 = 0xc0210027; +pub const SMB_NTSTATUS_FVE_CONV_RECOVERY_FAILED: u32 = 0xc0210028; +pub const SMB_NTSTATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG: u32 = 0xc0210029; +pub const SMB_NTSTATUS_FVE_VOLUME_TOO_SMALL: u32 = 0xc0210030; +pub const SMB_NTSTATUS_FWP_CALLOUT_NOT_FOUND: u32 = 0xc0220001; +pub const SMB_NTSTATUS_FWP_CONDITION_NOT_FOUND: u32 = 0xc0220002; +pub const SMB_NTSTATUS_FWP_FILTER_NOT_FOUND: u32 = 0xc0220003; +pub const SMB_NTSTATUS_FWP_LAYER_NOT_FOUND: u32 = 0xc0220004; +pub const SMB_NTSTATUS_FWP_PROVIDER_NOT_FOUND: u32 = 0xc0220005; +pub const SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND: u32 = 0xc0220006; +pub const SMB_NTSTATUS_FWP_SUBLAYER_NOT_FOUND: u32 = 0xc0220007; +pub const SMB_NTSTATUS_FWP_NOT_FOUND: u32 = 0xc0220008; +pub const SMB_NTSTATUS_FWP_ALREADY_EXISTS: u32 = 0xc0220009; +pub const SMB_NTSTATUS_FWP_IN_USE: u32 = 0xc022000a; +pub const SMB_NTSTATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS: u32 = 0xc022000b; +pub const SMB_NTSTATUS_FWP_WRONG_SESSION: u32 = 0xc022000c; +pub const SMB_NTSTATUS_FWP_NO_TXN_IN_PROGRESS: u32 = 0xc022000d; +pub const SMB_NTSTATUS_FWP_TXN_IN_PROGRESS: u32 = 0xc022000e; +pub const SMB_NTSTATUS_FWP_TXN_ABORTED: u32 = 0xc022000f; +pub const SMB_NTSTATUS_FWP_SESSION_ABORTED: u32 = 0xc0220010; +pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_TXN: u32 = 0xc0220011; +pub const SMB_NTSTATUS_FWP_TIMEOUT: u32 = 0xc0220012; +pub const SMB_NTSTATUS_FWP_NET_EVENTS_DISABLED: u32 = 0xc0220013; +pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_LAYER: u32 = 0xc0220014; +pub const SMB_NTSTATUS_FWP_KM_CLIENTS_ONLY: u32 = 0xc0220015; +pub const SMB_NTSTATUS_FWP_LIFETIME_MISMATCH: u32 = 0xc0220016; +pub const SMB_NTSTATUS_FWP_BUILTIN_OBJECT: u32 = 0xc0220017; +pub const SMB_NTSTATUS_FWP_TOO_MANY_BOOTTIME_FILTERS: u32 = 0xc0220018; +pub const SMB_NTSTATUS_FWP_NOTIFICATION_DROPPED: u32 = 0xc0220019; +pub const SMB_NTSTATUS_FWP_TRAFFIC_MISMATCH: u32 = 0xc022001a; +pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_SA_STATE: u32 = 0xc022001b; +pub const SMB_NTSTATUS_FWP_NULL_POINTER: u32 = 0xc022001c; +pub const SMB_NTSTATUS_FWP_INVALID_ENUMERATOR: u32 = 0xc022001d; +pub const SMB_NTSTATUS_FWP_INVALID_FLAGS: u32 = 0xc022001e; +pub const SMB_NTSTATUS_FWP_INVALID_NET_MASK: u32 = 0xc022001f; +pub const SMB_NTSTATUS_FWP_INVALID_RANGE: u32 = 0xc0220020; +pub const SMB_NTSTATUS_FWP_INVALID_INTERVAL: u32 = 0xc0220021; +pub const SMB_NTSTATUS_FWP_ZERO_LENGTH_ARRAY: u32 = 0xc0220022; +pub const SMB_NTSTATUS_FWP_NULL_DISPLAY_NAME: u32 = 0xc0220023; +pub const SMB_NTSTATUS_FWP_INVALID_ACTION_TYPE: u32 = 0xc0220024; +pub const SMB_NTSTATUS_FWP_INVALID_WEIGHT: u32 = 0xc0220025; +pub const SMB_NTSTATUS_FWP_MATCH_TYPE_MISMATCH: u32 = 0xc0220026; +pub const SMB_NTSTATUS_FWP_TYPE_MISMATCH: u32 = 0xc0220027; +pub const SMB_NTSTATUS_FWP_OUT_OF_BOUNDS: u32 = 0xc0220028; +pub const SMB_NTSTATUS_FWP_RESERVED: u32 = 0xc0220029; +pub const SMB_NTSTATUS_FWP_DUPLICATE_CONDITION: u32 = 0xc022002a; +pub const SMB_NTSTATUS_FWP_DUPLICATE_KEYMOD: u32 = 0xc022002b; +pub const SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER: u32 = 0xc022002c; +pub const SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER: u32 = 0xc022002d; +pub const SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER: u32 = 0xc022002e; +pub const SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT: u32 = 0xc022002f; +pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_METHOD: u32 = 0xc0220030; +pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_DH_GROUP: u32 = 0xc0220031; +pub const SMB_NTSTATUS_FWP_EM_NOT_SUPPORTED: u32 = 0xc0220032; +pub const SMB_NTSTATUS_FWP_NEVER_MATCH: u32 = 0xc0220033; +pub const SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_MISMATCH: u32 = 0xc0220034; +pub const SMB_NTSTATUS_FWP_INVALID_PARAMETER: u32 = 0xc0220035; +pub const SMB_NTSTATUS_FWP_TOO_MANY_SUBLAYERS: u32 = 0xc0220036; +pub const SMB_NTSTATUS_FWP_CALLOUT_NOTIFICATION_FAILED: u32 = 0xc0220037; +pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_CONFIG: u32 = 0xc0220038; +pub const SMB_NTSTATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG: u32 = 0xc0220039; +pub const SMB_NTSTATUS_FWP_DUPLICATE_AUTH_METHOD: u32 = 0xc022003c; +pub const SMB_NTSTATUS_FWP_TCPIP_NOT_READY: u32 = 0xc0220100; +pub const SMB_NTSTATUS_FWP_INJECT_HANDLE_CLOSING: u32 = 0xc0220101; +pub const SMB_NTSTATUS_FWP_INJECT_HANDLE_STALE: u32 = 0xc0220102; +pub const SMB_NTSTATUS_FWP_CANNOT_PEND: u32 = 0xc0220103; +pub const SMB_NTSTATUS_NDIS_CLOSING: u32 = 0xc0230002; +pub const SMB_NTSTATUS_NDIS_BAD_VERSION: u32 = 0xc0230004; +pub const SMB_NTSTATUS_NDIS_BAD_CHARACTERISTICS: u32 = 0xc0230005; +pub const SMB_NTSTATUS_NDIS_ADAPTER_NOT_FOUND: u32 = 0xc0230006; +pub const SMB_NTSTATUS_NDIS_OPEN_FAILED: u32 = 0xc0230007; +pub const SMB_NTSTATUS_NDIS_DEVICE_FAILED: u32 = 0xc0230008; +pub const SMB_NTSTATUS_NDIS_MULTICAST_FULL: u32 = 0xc0230009; +pub const SMB_NTSTATUS_NDIS_MULTICAST_EXISTS: u32 = 0xc023000a; +pub const SMB_NTSTATUS_NDIS_MULTICAST_NOT_FOUND: u32 = 0xc023000b; +pub const SMB_NTSTATUS_NDIS_REQUEST_ABORTED: u32 = 0xc023000c; +pub const SMB_NTSTATUS_NDIS_RESET_IN_PROGRESS: u32 = 0xc023000d; +pub const SMB_NTSTATUS_NDIS_INVALID_PACKET: u32 = 0xc023000f; +pub const SMB_NTSTATUS_NDIS_INVALID_DEVICE_REQUEST: u32 = 0xc0230010; +pub const SMB_NTSTATUS_NDIS_ADAPTER_NOT_READY: u32 = 0xc0230011; +pub const SMB_NTSTATUS_NDIS_INVALID_LENGTH: u32 = 0xc0230014; +pub const SMB_NTSTATUS_NDIS_INVALID_DATA: u32 = 0xc0230015; +pub const SMB_NTSTATUS_NDIS_BUFFER_TOO_SHORT: u32 = 0xc0230016; +pub const SMB_NTSTATUS_NDIS_INVALID_OID: u32 = 0xc0230017; +pub const SMB_NTSTATUS_NDIS_ADAPTER_REMOVED: u32 = 0xc0230018; +pub const SMB_NTSTATUS_NDIS_UNSUPPORTED_MEDIA: u32 = 0xc0230019; +pub const SMB_NTSTATUS_NDIS_GROUP_ADDRESS_IN_USE: u32 = 0xc023001a; +pub const SMB_NTSTATUS_NDIS_FILE_NOT_FOUND: u32 = 0xc023001b; +pub const SMB_NTSTATUS_NDIS_ERROR_READING_FILE: u32 = 0xc023001c; +pub const SMB_NTSTATUS_NDIS_ALREADY_MAPPED: u32 = 0xc023001d; +pub const SMB_NTSTATUS_NDIS_RESOURCE_CONFLICT: u32 = 0xc023001e; +pub const SMB_NTSTATUS_NDIS_MEDIA_DISCONNECTED: u32 = 0xc023001f; +pub const SMB_NTSTATUS_NDIS_INVALID_ADDRESS: u32 = 0xc0230022; +pub const SMB_NTSTATUS_NDIS_PAUSED: u32 = 0xc023002a; +pub const SMB_NTSTATUS_NDIS_INTERFACE_NOT_FOUND: u32 = 0xc023002b; +pub const SMB_NTSTATUS_NDIS_UNSUPPORTED_REVISION: u32 = 0xc023002c; +pub const SMB_NTSTATUS_NDIS_INVALID_PORT: u32 = 0xc023002d; +pub const SMB_NTSTATUS_NDIS_INVALID_PORT_STATE: u32 = 0xc023002e; +pub const SMB_NTSTATUS_NDIS_LOW_POWER_STATE: u32 = 0xc023002f; +pub const SMB_NTSTATUS_NDIS_NOT_SUPPORTED: u32 = 0xc02300bb; +pub const SMB_NTSTATUS_NDIS_OFFLOAD_POLICY: u32 = 0xc023100f; +pub const SMB_NTSTATUS_NDIS_OFFLOAD_CONNECTION_REJECTED: u32 = 0xc0231012; +pub const SMB_NTSTATUS_NDIS_OFFLOAD_PATH_REJECTED: u32 = 0xc0231013; +pub const SMB_NTSTATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED: u32 = 0xc0232000; +pub const SMB_NTSTATUS_NDIS_DOT11_MEDIA_IN_USE: u32 = 0xc0232001; +pub const SMB_NTSTATUS_NDIS_DOT11_POWER_STATE_INVALID: u32 = 0xc0232002; +pub const SMB_NTSTATUS_NDIS_PM_WOL_PATTERN_LIST_FULL: u32 = 0xc0232003; +pub const SMB_NTSTATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL: u32 = 0xc0232004; +pub const SMB_NTSTATUS_IPSEC_BAD_SPI: u32 = 0xc0360001; +pub const SMB_NTSTATUS_IPSEC_SA_LIFETIME_EXPIRED: u32 = 0xc0360002; +pub const SMB_NTSTATUS_IPSEC_WRONG_SA: u32 = 0xc0360003; +pub const SMB_NTSTATUS_IPSEC_REPLAY_CHECK_FAILED: u32 = 0xc0360004; +pub const SMB_NTSTATUS_IPSEC_INVALID_PACKET: u32 = 0xc0360005; +pub const SMB_NTSTATUS_IPSEC_INTEGRITY_CHECK_FAILED: u32 = 0xc0360006; +pub const SMB_NTSTATUS_IPSEC_CLEAR_TEXT_DROP: u32 = 0xc0360007; +pub const SMB_NTSTATUS_IPSEC_AUTH_FIREWALL_DROP: u32 = 0xc0360008; +pub const SMB_NTSTATUS_IPSEC_THROTTLE_DROP: u32 = 0xc0360009; +pub const SMB_NTSTATUS_IPSEC_DOSP_BLOCK: u32 = 0xc0368000; +pub const SMB_NTSTATUS_IPSEC_DOSP_RECEIVED_MULTICAST: u32 = 0xc0368001; +pub const SMB_NTSTATUS_IPSEC_DOSP_INVALID_PACKET: u32 = 0xc0368002; +pub const SMB_NTSTATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED: u32 = 0xc0368003; +pub const SMB_NTSTATUS_IPSEC_DOSP_MAX_ENTRIES: u32 = 0xc0368004; +pub const SMB_NTSTATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED: u32 = 0xc0368005; +pub const SMB_NTSTATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES: u32 = 0xc0368006; +pub const SMB_NTSTATUS_VOLMGR_MIRROR_NOT_SUPPORTED: u32 = 0xc038005b; +pub const SMB_NTSTATUS_VOLMGR_RAID5_NOT_SUPPORTED: u32 = 0xc038005c; +pub const SMB_NTSTATUS_VIRTDISK_PROVIDER_NOT_FOUND: u32 = 0xc03a0014; +pub const SMB_NTSTATUS_VIRTDISK_NOT_VIRTUAL_DISK: u32 = 0xc03a0015; +pub const SMB_NTSTATUS_VHD_PARENT_VHD_ACCESS_DENIED: u32 = 0xc03a0016; +pub const SMB_NTSTATUS_VHD_CHILD_PARENT_SIZE_MISMATCH: u32 = 0xc03a0017; +pub const SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED: u32 = 0xc03a0018; +pub const SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT: u32 = 0xc03a0019; pub fn smb_ntstatus_string(c: u32) -> Option<&'static str> { match c { - SMB_NTSTATUS_SUCCESS => Some("STATUS_SUCCESS"), - SMB_NTSTATUS_WAIT_1 => Some("STATUS_WAIT_1"), - SMB_NTSTATUS_WAIT_2 => Some("STATUS_WAIT_2"), - SMB_NTSTATUS_WAIT_3 => Some("STATUS_WAIT_3"), - SMB_NTSTATUS_WAIT_63 => Some("STATUS_WAIT_63"), - SMB_NTSTATUS_ABANDONED => Some("STATUS_ABANDONED"), - SMB_NTSTATUS_ABANDONED_WAIT_63 => Some("STATUS_ABANDONED_WAIT_63"), - SMB_NTSTATUS_USER_APC => Some("STATUS_USER_APC"), - SMB_NTSTATUS_ALERTED => Some("STATUS_ALERTED"), - SMB_NTSTATUS_TIMEOUT => Some("STATUS_TIMEOUT"), - SMB_NTSTATUS_PENDING => Some("STATUS_PENDING"), - SMB_NTSTATUS_REPARSE => Some("STATUS_REPARSE"), - SMB_NTSTATUS_MORE_ENTRIES => Some("STATUS_MORE_ENTRIES"), - SMB_NTSTATUS_NOT_ALL_ASSIGNED => Some("STATUS_NOT_ALL_ASSIGNED"), - SMB_NTSTATUS_SOME_NOT_MAPPED => Some("STATUS_SOME_NOT_MAPPED"), - SMB_NTSTATUS_OPLOCK_BREAK_IN_PROGRESS => Some("STATUS_OPLOCK_BREAK_IN_PROGRESS"), - SMB_NTSTATUS_VOLUME_MOUNTED => Some("STATUS_VOLUME_MOUNTED"), - SMB_NTSTATUS_RXACT_COMMITTED => Some("STATUS_RXACT_COMMITTED"), - SMB_NTSTATUS_NOTIFY_CLEANUP => Some("STATUS_NOTIFY_CLEANUP"), - SMB_NTSTATUS_NOTIFY_ENUM_DIR => Some("STATUS_NOTIFY_ENUM_DIR"), - SMB_NTSTATUS_NO_QUOTAS_FOR_ACCOUNT => Some("STATUS_NO_QUOTAS_FOR_ACCOUNT"), - SMB_NTSTATUS_PRIMARY_TRANSPORT_CONNECT_FAILED => Some("STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED"), - SMB_NTSTATUS_PAGE_FAULT_TRANSITION => Some("STATUS_PAGE_FAULT_TRANSITION"), - SMB_NTSTATUS_PAGE_FAULT_DEMAND_ZERO => Some("STATUS_PAGE_FAULT_DEMAND_ZERO"), - SMB_NTSTATUS_PAGE_FAULT_COPY_ON_WRITE => Some("STATUS_PAGE_FAULT_COPY_ON_WRITE"), - SMB_NTSTATUS_PAGE_FAULT_GUARD_PAGE => Some("STATUS_PAGE_FAULT_GUARD_PAGE"), - SMB_NTSTATUS_PAGE_FAULT_PAGING_FILE => Some("STATUS_PAGE_FAULT_PAGING_FILE"), - SMB_NTSTATUS_CACHE_PAGE_LOCKED => Some("STATUS_CACHE_PAGE_LOCKED"), - SMB_NTSTATUS_CRASH_DUMP => Some("STATUS_CRASH_DUMP"), - SMB_NTSTATUS_BUFFER_ALL_ZEROS => Some("STATUS_BUFFER_ALL_ZEROS"), - SMB_NTSTATUS_REPARSE_OBJECT => Some("STATUS_REPARSE_OBJECT"), - SMB_NTSTATUS_RESOURCE_REQUIREMENTS_CHANGED => Some("STATUS_RESOURCE_REQUIREMENTS_CHANGED"), - SMB_NTSTATUS_TRANSLATION_COMPLETE => Some("STATUS_TRANSLATION_COMPLETE"), - SMB_NTSTATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY => Some("STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY"), - SMB_NTSTATUS_NOTHING_TO_TERMINATE => Some("STATUS_NOTHING_TO_TERMINATE"), - SMB_NTSTATUS_PROCESS_NOT_IN_JOB => Some("STATUS_PROCESS_NOT_IN_JOB"), - SMB_NTSTATUS_PROCESS_IN_JOB => Some("STATUS_PROCESS_IN_JOB"), - SMB_NTSTATUS_VOLSNAP_HIBERNATE_READY => Some("STATUS_VOLSNAP_HIBERNATE_READY"), - SMB_NTSTATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY => Some("STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY"), - SMB_NTSTATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED => Some("STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED"), - SMB_NTSTATUS_INTERRUPT_STILL_CONNECTED => Some("STATUS_INTERRUPT_STILL_CONNECTED"), - SMB_NTSTATUS_PROCESS_CLONED => Some("STATUS_PROCESS_CLONED"), - SMB_NTSTATUS_FILE_LOCKED_WITH_ONLY_READERS => Some("STATUS_FILE_LOCKED_WITH_ONLY_READERS"), - SMB_NTSTATUS_FILE_LOCKED_WITH_WRITERS => Some("STATUS_FILE_LOCKED_WITH_WRITERS"), - SMB_NTSTATUS_RESOURCEMANAGER_READ_ONLY => Some("STATUS_RESOURCEMANAGER_READ_ONLY"), - SMB_NTSTATUS_WAIT_FOR_OPLOCK => Some("STATUS_WAIT_FOR_OPLOCK"), - SMB_NTDBG_EXCEPTION_HANDLED => Some("DBG_EXCEPTION_HANDLED"), - SMB_NTDBG_CONTINUE => Some("DBG_CONTINUE"), - SMB_NTSTATUS_FLT_IO_COMPLETE => Some("STATUS_FLT_IO_COMPLETE"), - SMB_NTSTATUS_FILE_NOT_AVAILABLE => Some("STATUS_FILE_NOT_AVAILABLE"), - SMB_NTSTATUS_SHARE_UNAVAILABLE => Some("STATUS_SHARE_UNAVAILABLE"), - SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_AFFINITY => Some("STATUS_CALLBACK_RETURNED_THREAD_AFFINITY"), - SMB_NTSTATUS_OBJECT_NAME_EXISTS => Some("STATUS_OBJECT_NAME_EXISTS"), - SMB_NTSTATUS_THREAD_WAS_SUSPENDED => Some("STATUS_THREAD_WAS_SUSPENDED"), - SMB_NTSTATUS_WORKING_SET_LIMIT_RANGE => Some("STATUS_WORKING_SET_LIMIT_RANGE"), - SMB_NTSTATUS_IMAGE_NOT_AT_BASE => Some("STATUS_IMAGE_NOT_AT_BASE"), - SMB_NTSTATUS_RXACT_STATE_CREATED => Some("STATUS_RXACT_STATE_CREATED"), - SMB_NTSTATUS_SEGMENT_NOTIFICATION => Some("STATUS_SEGMENT_NOTIFICATION"), - SMB_NTSTATUS_LOCAL_USER_SESSION_KEY => Some("STATUS_LOCAL_USER_SESSION_KEY"), - SMB_NTSTATUS_BAD_CURRENT_DIRECTORY => Some("STATUS_BAD_CURRENT_DIRECTORY"), - SMB_NTSTATUS_SERIAL_MORE_WRITES => Some("STATUS_SERIAL_MORE_WRITES"), - SMB_NTSTATUS_REGISTRY_RECOVERED => Some("STATUS_REGISTRY_RECOVERED"), - SMB_NTSTATUS_FT_READ_RECOVERY_FROM_BACKUP => Some("STATUS_FT_READ_RECOVERY_FROM_BACKUP"), - SMB_NTSTATUS_FT_WRITE_RECOVERY => Some("STATUS_FT_WRITE_RECOVERY"), - SMB_NTSTATUS_SERIAL_COUNTER_TIMEOUT => Some("STATUS_SERIAL_COUNTER_TIMEOUT"), - SMB_NTSTATUS_NULL_LM_PASSWORD => Some("STATUS_NULL_LM_PASSWORD"), - SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH => Some("STATUS_IMAGE_MACHINE_TYPE_MISMATCH"), - SMB_NTSTATUS_RECEIVE_PARTIAL => Some("STATUS_RECEIVE_PARTIAL"), - SMB_NTSTATUS_RECEIVE_EXPEDITED => Some("STATUS_RECEIVE_EXPEDITED"), - SMB_NTSTATUS_RECEIVE_PARTIAL_EXPEDITED => Some("STATUS_RECEIVE_PARTIAL_EXPEDITED"), - SMB_NTSTATUS_EVENT_DONE => Some("STATUS_EVENT_DONE"), - SMB_NTSTATUS_EVENT_PENDING => Some("STATUS_EVENT_PENDING"), - SMB_NTSTATUS_CHECKING_FILE_SYSTEM => Some("STATUS_CHECKING_FILE_SYSTEM"), - SMB_NTSTATUS_FATAL_APP_EXIT => Some("STATUS_FATAL_APP_EXIT"), - SMB_NTSTATUS_PREDEFINED_HANDLE => Some("STATUS_PREDEFINED_HANDLE"), - SMB_NTSTATUS_WAS_UNLOCKED => Some("STATUS_WAS_UNLOCKED"), - SMB_NTSTATUS_SERVICE_NOTIFICATION => Some("STATUS_SERVICE_NOTIFICATION"), - SMB_NTSTATUS_WAS_LOCKED => Some("STATUS_WAS_LOCKED"), - SMB_NTSTATUS_LOG_HARD_ERROR => Some("STATUS_LOG_HARD_ERROR"), - SMB_NTSTATUS_ALREADY_WIN32 => Some("STATUS_ALREADY_WIN32"), - SMB_NTSTATUS_WX86_UNSIMULATE => Some("STATUS_WX86_UNSIMULATE"), - SMB_NTSTATUS_WX86_CONTINUE => Some("STATUS_WX86_CONTINUE"), - SMB_NTSTATUS_WX86_SINGLE_STEP => Some("STATUS_WX86_SINGLE_STEP"), - SMB_NTSTATUS_WX86_BREAKPOINT => Some("STATUS_WX86_BREAKPOINT"), - SMB_NTSTATUS_WX86_EXCEPTION_CONTINUE => Some("STATUS_WX86_EXCEPTION_CONTINUE"), - SMB_NTSTATUS_WX86_EXCEPTION_LASTCHANCE => Some("STATUS_WX86_EXCEPTION_LASTCHANCE"), - SMB_NTSTATUS_WX86_EXCEPTION_CHAIN => Some("STATUS_WX86_EXCEPTION_CHAIN"), - SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE => Some("STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE"), - SMB_NTSTATUS_NO_YIELD_PERFORMED => Some("STATUS_NO_YIELD_PERFORMED"), - SMB_NTSTATUS_TIMER_RESUME_IGNORED => Some("STATUS_TIMER_RESUME_IGNORED"), - SMB_NTSTATUS_ARBITRATION_UNHANDLED => Some("STATUS_ARBITRATION_UNHANDLED"), - SMB_NTSTATUS_CARDBUS_NOT_SUPPORTED => Some("STATUS_CARDBUS_NOT_SUPPORTED"), - SMB_NTSTATUS_WX86_CREATEWX86TIB => Some("STATUS_WX86_CREATEWX86TIB"), - SMB_NTSTATUS_MP_PROCESSOR_MISMATCH => Some("STATUS_MP_PROCESSOR_MISMATCH"), - SMB_NTSTATUS_HIBERNATED => Some("STATUS_HIBERNATED"), - SMB_NTSTATUS_RESUME_HIBERNATION => Some("STATUS_RESUME_HIBERNATION"), - SMB_NTSTATUS_FIRMWARE_UPDATED => Some("STATUS_FIRMWARE_UPDATED"), - SMB_NTSTATUS_DRIVERS_LEAKING_LOCKED_PAGES => Some("STATUS_DRIVERS_LEAKING_LOCKED_PAGES"), - SMB_NTSTATUS_MESSAGE_RETRIEVED => Some("STATUS_MESSAGE_RETRIEVED"), - SMB_NTSTATUS_SYSTEM_POWERSTATE_TRANSITION => Some("STATUS_SYSTEM_POWERSTATE_TRANSITION"), - SMB_NTSTATUS_ALPC_CHECK_COMPLETION_LIST => Some("STATUS_ALPC_CHECK_COMPLETION_LIST"), - SMB_NTSTATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION => Some("STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION"), - SMB_NTSTATUS_ACCESS_AUDIT_BY_POLICY => Some("STATUS_ACCESS_AUDIT_BY_POLICY"), - SMB_NTSTATUS_ABANDON_HIBERFILE => Some("STATUS_ABANDON_HIBERFILE"), - SMB_NTSTATUS_BIZRULES_NOT_ENABLED => Some("STATUS_BIZRULES_NOT_ENABLED"), - SMB_NTSTATUS_WAKE_SYSTEM => Some("STATUS_WAKE_SYSTEM"), - SMB_NTSTATUS_DS_SHUTTING_DOWN => Some("STATUS_DS_SHUTTING_DOWN"), - SMB_NTDBG_REPLY_LATER => Some("DBG_REPLY_LATER"), - SMB_NTDBG_UNABLE_TO_PROVIDE_HANDLE => Some("DBG_UNABLE_TO_PROVIDE_HANDLE"), - SMB_NTDBG_TERMINATE_THREAD => Some("DBG_TERMINATE_THREAD"), - SMB_NTDBG_TERMINATE_PROCESS => Some("DBG_TERMINATE_PROCESS"), - SMB_NTDBG_CONTROL_C => Some("DBG_CONTROL_C"), - SMB_NTDBG_PRINTEXCEPTION_C => Some("DBG_PRINTEXCEPTION_C"), - SMB_NTDBG_RIPEXCEPTION => Some("DBG_RIPEXCEPTION"), - SMB_NTDBG_CONTROL_BREAK => Some("DBG_CONTROL_BREAK"), - SMB_NTDBG_COMMAND_EXCEPTION => Some("DBG_COMMAND_EXCEPTION"), - SMB_NTRPC_NT_UUID_LOCAL_ONLY => Some("RPC_NT_UUID_LOCAL_ONLY"), - SMB_NTRPC_NT_SEND_INCOMPLETE => Some("RPC_NT_SEND_INCOMPLETE"), - SMB_NTSTATUS_CTX_CDM_CONNECT => Some("STATUS_CTX_CDM_CONNECT"), - SMB_NTSTATUS_CTX_CDM_DISCONNECT => Some("STATUS_CTX_CDM_DISCONNECT"), - SMB_NTSTATUS_SXS_RELEASE_ACTIVATION_CONTEXT => Some("STATUS_SXS_RELEASE_ACTIVATION_CONTEXT"), - SMB_NTSTATUS_RECOVERY_NOT_NEEDED => Some("STATUS_RECOVERY_NOT_NEEDED"), - SMB_NTSTATUS_RM_ALREADY_STARTED => Some("STATUS_RM_ALREADY_STARTED"), - SMB_NTSTATUS_LOG_NO_RESTART => Some("STATUS_LOG_NO_RESTART"), - SMB_NTSTATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST => Some("STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST"), - SMB_NTSTATUS_GRAPHICS_PARTIAL_DATA_POPULATED => Some("STATUS_GRAPHICS_PARTIAL_DATA_POPULATED"), - SMB_NTSTATUS_GRAPHICS_DRIVER_MISMATCH => Some("STATUS_GRAPHICS_DRIVER_MISMATCH"), - SMB_NTSTATUS_GRAPHICS_MODE_NOT_PINNED => Some("STATUS_GRAPHICS_MODE_NOT_PINNED"), - SMB_NTSTATUS_GRAPHICS_NO_PREFERRED_MODE => Some("STATUS_GRAPHICS_NO_PREFERRED_MODE"), - SMB_NTSTATUS_GRAPHICS_DATASET_IS_EMPTY => Some("STATUS_GRAPHICS_DATASET_IS_EMPTY"), - SMB_NTSTATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET => Some("STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET"), - SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED => Some("STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED"), - SMB_NTSTATUS_GRAPHICS_UNKNOWN_CHILD_STATUS => Some("STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS"), - SMB_NTSTATUS_GRAPHICS_LEADLINK_START_DEFERRED => Some("STATUS_GRAPHICS_LEADLINK_START_DEFERRED"), - SMB_NTSTATUS_GRAPHICS_POLLING_TOO_FREQUENTLY => Some("STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY"), - SMB_NTSTATUS_GRAPHICS_START_DEFERRED => Some("STATUS_GRAPHICS_START_DEFERRED"), - SMB_NTSTATUS_NDIS_INDICATION_REQUIRED => Some("STATUS_NDIS_INDICATION_REQUIRED"), - SMB_NTSTATUS_GUARD_PAGE_VIOLATION => Some("STATUS_GUARD_PAGE_VIOLATION"), - SMB_NTSTATUS_DATATYPE_MISALIGNMENT => Some("STATUS_DATATYPE_MISALIGNMENT"), - SMB_NTSTATUS_BREAKPOINT => Some("STATUS_BREAKPOINT"), - SMB_NTSTATUS_SINGLE_STEP => Some("STATUS_SINGLE_STEP"), - SMB_NTSTATUS_BUFFER_OVERFLOW => Some("STATUS_BUFFER_OVERFLOW"), - SMB_NTSTATUS_NO_MORE_FILES => Some("STATUS_NO_MORE_FILES"), - SMB_NTSTATUS_WAKE_SYSTEM_DEBUGGER => Some("STATUS_WAKE_SYSTEM_DEBUGGER"), - SMB_NTSTATUS_HANDLES_CLOSED => Some("STATUS_HANDLES_CLOSED"), - SMB_NTSTATUS_NO_INHERITANCE => Some("STATUS_NO_INHERITANCE"), - SMB_NTSTATUS_GUID_SUBSTITUTION_MADE => Some("STATUS_GUID_SUBSTITUTION_MADE"), - SMB_NTSTATUS_PARTIAL_COPY => Some("STATUS_PARTIAL_COPY"), - SMB_NTSTATUS_DEVICE_PAPER_EMPTY => Some("STATUS_DEVICE_PAPER_EMPTY"), - SMB_NTSTATUS_DEVICE_POWERED_OFF => Some("STATUS_DEVICE_POWERED_OFF"), - SMB_NTSTATUS_DEVICE_OFF_LINE => Some("STATUS_DEVICE_OFF_LINE"), - SMB_NTSTATUS_DEVICE_BUSY => Some("STATUS_DEVICE_BUSY"), - SMB_NTSTATUS_NO_MORE_EAS => Some("STATUS_NO_MORE_EAS"), - SMB_NTSTATUS_INVALID_EA_NAME => Some("STATUS_INVALID_EA_NAME"), - SMB_NTSTATUS_EA_LIST_INCONSISTENT => Some("STATUS_EA_LIST_INCONSISTENT"), - SMB_NTSTATUS_INVALID_EA_FLAG => Some("STATUS_INVALID_EA_FLAG"), - SMB_NTSTATUS_VERIFY_REQUIRED => Some("STATUS_VERIFY_REQUIRED"), - SMB_NTSTATUS_EXTRANEOUS_INFORMATION => Some("STATUS_EXTRANEOUS_INFORMATION"), - SMB_NTSTATUS_RXACT_COMMIT_NECESSARY => Some("STATUS_RXACT_COMMIT_NECESSARY"), - SMB_NTSTATUS_NO_MORE_ENTRIES => Some("STATUS_NO_MORE_ENTRIES"), - SMB_NTSTATUS_FILEMARK_DETECTED => Some("STATUS_FILEMARK_DETECTED"), - SMB_NTSTATUS_MEDIA_CHANGED => Some("STATUS_MEDIA_CHANGED"), - SMB_NTSTATUS_BUS_RESET => Some("STATUS_BUS_RESET"), - SMB_NTSTATUS_END_OF_MEDIA => Some("STATUS_END_OF_MEDIA"), - SMB_NTSTATUS_BEGINNING_OF_MEDIA => Some("STATUS_BEGINNING_OF_MEDIA"), - SMB_NTSTATUS_MEDIA_CHECK => Some("STATUS_MEDIA_CHECK"), - SMB_NTSTATUS_SETMARK_DETECTED => Some("STATUS_SETMARK_DETECTED"), - SMB_NTSTATUS_NO_DATA_DETECTED => Some("STATUS_NO_DATA_DETECTED"), - SMB_NTSTATUS_REDIRECTOR_HAS_OPEN_HANDLES => Some("STATUS_REDIRECTOR_HAS_OPEN_HANDLES"), - SMB_NTSTATUS_SERVER_HAS_OPEN_HANDLES => Some("STATUS_SERVER_HAS_OPEN_HANDLES"), - SMB_NTSTATUS_ALREADY_DISCONNECTED => Some("STATUS_ALREADY_DISCONNECTED"), - SMB_NTSTATUS_LONGJUMP => Some("STATUS_LONGJUMP"), - SMB_NTSTATUS_CLEANER_CARTRIDGE_INSTALLED => Some("STATUS_CLEANER_CARTRIDGE_INSTALLED"), - SMB_NTSTATUS_PLUGPLAY_QUERY_VETOED => Some("STATUS_PLUGPLAY_QUERY_VETOED"), - SMB_NTSTATUS_UNWIND_CONSOLIDATE => Some("STATUS_UNWIND_CONSOLIDATE"), - SMB_NTSTATUS_REGISTRY_HIVE_RECOVERED => Some("STATUS_REGISTRY_HIVE_RECOVERED"), - SMB_NTSTATUS_DLL_MIGHT_BE_INSECURE => Some("STATUS_DLL_MIGHT_BE_INSECURE"), - SMB_NTSTATUS_DLL_MIGHT_BE_INCOMPATIBLE => Some("STATUS_DLL_MIGHT_BE_INCOMPATIBLE"), - SMB_NTSTATUS_STOPPED_ON_SYMLINK => Some("STATUS_STOPPED_ON_SYMLINK"), - SMB_NTSTATUS_DEVICE_REQUIRES_CLEANING => Some("STATUS_DEVICE_REQUIRES_CLEANING"), - SMB_NTSTATUS_DEVICE_DOOR_OPEN => Some("STATUS_DEVICE_DOOR_OPEN"), - SMB_NTSTATUS_DATA_LOST_REPAIR => Some("STATUS_DATA_LOST_REPAIR"), - SMB_NTDBG_EXCEPTION_NOT_HANDLED => Some("DBG_EXCEPTION_NOT_HANDLED"), - SMB_NTSTATUS_CLUSTER_NODE_ALREADY_UP => Some("STATUS_CLUSTER_NODE_ALREADY_UP"), - SMB_NTSTATUS_CLUSTER_NODE_ALREADY_DOWN => Some("STATUS_CLUSTER_NODE_ALREADY_DOWN"), - SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_ONLINE => Some("STATUS_CLUSTER_NETWORK_ALREADY_ONLINE"), - SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_OFFLINE => Some("STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE"), - SMB_NTSTATUS_CLUSTER_NODE_ALREADY_MEMBER => Some("STATUS_CLUSTER_NODE_ALREADY_MEMBER"), - SMB_NTSTATUS_COULD_NOT_RESIZE_LOG => Some("STATUS_COULD_NOT_RESIZE_LOG"), - SMB_NTSTATUS_NO_TXF_METADATA => Some("STATUS_NO_TXF_METADATA"), - SMB_NTSTATUS_CANT_RECOVER_WITH_HANDLE_OPEN => Some("STATUS_CANT_RECOVER_WITH_HANDLE_OPEN"), - SMB_NTSTATUS_TXF_METADATA_ALREADY_PRESENT => Some("STATUS_TXF_METADATA_ALREADY_PRESENT"), - SMB_NTSTATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET => Some("STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET"), - SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED => Some("STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED"), - SMB_NTSTATUS_FLT_BUFFER_TOO_SMALL => Some("STATUS_FLT_BUFFER_TOO_SMALL"), - SMB_NTSTATUS_FVE_PARTIAL_METADATA => Some("STATUS_FVE_PARTIAL_METADATA"), - SMB_NTSTATUS_FVE_TRANSIENT_STATE => Some("STATUS_FVE_TRANSIENT_STATE"), - SMB_NTSTATUS_UNSUCCESSFUL => Some("STATUS_UNSUCCESSFUL"), - SMB_NTSTATUS_NOT_IMPLEMENTED => Some("STATUS_NOT_IMPLEMENTED"), - SMB_NTSTATUS_INVALID_INFO_CLASS => Some("STATUS_INVALID_INFO_CLASS"), - SMB_NTSTATUS_INFO_LENGTH_MISMATCH => Some("STATUS_INFO_LENGTH_MISMATCH"), - SMB_NTSTATUS_ACCESS_VIOLATION => Some("STATUS_ACCESS_VIOLATION"), - SMB_NTSTATUS_IN_PAGE_ERROR => Some("STATUS_IN_PAGE_ERROR"), - SMB_NTSTATUS_PAGEFILE_QUOTA => Some("STATUS_PAGEFILE_QUOTA"), - SMB_NTSTATUS_INVALID_HANDLE => Some("STATUS_INVALID_HANDLE"), - SMB_NTSTATUS_BAD_INITIAL_STACK => Some("STATUS_BAD_INITIAL_STACK"), - SMB_NTSTATUS_BAD_INITIAL_PC => Some("STATUS_BAD_INITIAL_PC"), - SMB_NTSTATUS_INVALID_CID => Some("STATUS_INVALID_CID"), - SMB_NTSTATUS_TIMER_NOT_CANCELED => Some("STATUS_TIMER_NOT_CANCELED"), - SMB_NTSTATUS_INVALID_PARAMETER => Some("STATUS_INVALID_PARAMETER"), - SMB_NTSTATUS_NO_SUCH_DEVICE => Some("STATUS_NO_SUCH_DEVICE"), - SMB_NTSTATUS_NO_SUCH_FILE => Some("STATUS_NO_SUCH_FILE"), - SMB_NTSTATUS_INVALID_DEVICE_REQUEST => Some("STATUS_INVALID_DEVICE_REQUEST"), - SMB_NTSTATUS_END_OF_FILE => Some("STATUS_END_OF_FILE"), - SMB_NTSTATUS_WRONG_VOLUME => Some("STATUS_WRONG_VOLUME"), - SMB_NTSTATUS_NO_MEDIA_IN_DEVICE => Some("STATUS_NO_MEDIA_IN_DEVICE"), - SMB_NTSTATUS_UNRECOGNIZED_MEDIA => Some("STATUS_UNRECOGNIZED_MEDIA"), - SMB_NTSTATUS_NONEXISTENT_SECTOR => Some("STATUS_NONEXISTENT_SECTOR"), - SMB_NTSTATUS_MORE_PROCESSING_REQUIRED => Some("STATUS_MORE_PROCESSING_REQUIRED"), - SMB_NTSTATUS_NO_MEMORY => Some("STATUS_NO_MEMORY"), - SMB_NTSTATUS_CONFLICTING_ADDRESSES => Some("STATUS_CONFLICTING_ADDRESSES"), - SMB_NTSTATUS_NOT_MAPPED_VIEW => Some("STATUS_NOT_MAPPED_VIEW"), - SMB_NTSTATUS_UNABLE_TO_FREE_VM => Some("STATUS_UNABLE_TO_FREE_VM"), - SMB_NTSTATUS_UNABLE_TO_DELETE_SECTION => Some("STATUS_UNABLE_TO_DELETE_SECTION"), - SMB_NTSTATUS_INVALID_SYSTEM_SERVICE => Some("STATUS_INVALID_SYSTEM_SERVICE"), - SMB_NTSTATUS_ILLEGAL_INSTRUCTION => Some("STATUS_ILLEGAL_INSTRUCTION"), - SMB_NTSTATUS_INVALID_LOCK_SEQUENCE => Some("STATUS_INVALID_LOCK_SEQUENCE"), - SMB_NTSTATUS_INVALID_VIEW_SIZE => Some("STATUS_INVALID_VIEW_SIZE"), - SMB_NTSTATUS_INVALID_FILE_FOR_SECTION => Some("STATUS_INVALID_FILE_FOR_SECTION"), - SMB_NTSTATUS_ALREADY_COMMITTED => Some("STATUS_ALREADY_COMMITTED"), - SMB_NTSTATUS_ACCESS_DENIED => Some("STATUS_ACCESS_DENIED"), - SMB_NTSTATUS_BUFFER_TOO_SMALL => Some("STATUS_BUFFER_TOO_SMALL"), - SMB_NTSTATUS_OBJECT_TYPE_MISMATCH => Some("STATUS_OBJECT_TYPE_MISMATCH"), - SMB_NTSTATUS_NONCONTINUABLE_EXCEPTION => Some("STATUS_NONCONTINUABLE_EXCEPTION"), - SMB_NTSTATUS_INVALID_DISPOSITION => Some("STATUS_INVALID_DISPOSITION"), - SMB_NTSTATUS_UNWIND => Some("STATUS_UNWIND"), - SMB_NTSTATUS_BAD_STACK => Some("STATUS_BAD_STACK"), - SMB_NTSTATUS_INVALID_UNWIND_TARGET => Some("STATUS_INVALID_UNWIND_TARGET"), - SMB_NTSTATUS_NOT_LOCKED => Some("STATUS_NOT_LOCKED"), - SMB_NTSTATUS_PARITY_ERROR => Some("STATUS_PARITY_ERROR"), - SMB_NTSTATUS_UNABLE_TO_DECOMMIT_VM => Some("STATUS_UNABLE_TO_DECOMMIT_VM"), - SMB_NTSTATUS_NOT_COMMITTED => Some("STATUS_NOT_COMMITTED"), - SMB_NTSTATUS_INVALID_PORT_ATTRIBUTES => Some("STATUS_INVALID_PORT_ATTRIBUTES"), - SMB_NTSTATUS_PORT_MESSAGE_TOO_LONG => Some("STATUS_PORT_MESSAGE_TOO_LONG"), - SMB_NTSTATUS_INVALID_PARAMETER_MIX => Some("STATUS_INVALID_PARAMETER_MIX"), - SMB_NTSTATUS_INVALID_QUOTA_LOWER => Some("STATUS_INVALID_QUOTA_LOWER"), - SMB_NTSTATUS_DISK_CORRUPT_ERROR => Some("STATUS_DISK_CORRUPT_ERROR"), - SMB_NTSTATUS_OBJECT_NAME_INVALID => Some("STATUS_OBJECT_NAME_INVALID"), - SMB_NTSTATUS_OBJECT_NAME_NOT_FOUND => Some("STATUS_OBJECT_NAME_NOT_FOUND"), - SMB_NTSTATUS_OBJECT_NAME_COLLISION => Some("STATUS_OBJECT_NAME_COLLISION"), - SMB_NTSTATUS_PORT_DISCONNECTED => Some("STATUS_PORT_DISCONNECTED"), - SMB_NTSTATUS_DEVICE_ALREADY_ATTACHED => Some("STATUS_DEVICE_ALREADY_ATTACHED"), - SMB_NTSTATUS_OBJECT_PATH_INVALID => Some("STATUS_OBJECT_PATH_INVALID"), - SMB_NTSTATUS_OBJECT_PATH_NOT_FOUND => Some("STATUS_OBJECT_PATH_NOT_FOUND"), - SMB_NTSTATUS_OBJECT_PATH_SYNTAX_BAD => Some("STATUS_OBJECT_PATH_SYNTAX_BAD"), - SMB_NTSTATUS_DATA_OVERRUN => Some("STATUS_DATA_OVERRUN"), - SMB_NTSTATUS_DATA_LATE_ERROR => Some("STATUS_DATA_LATE_ERROR"), - SMB_NTSTATUS_DATA_ERROR => Some("STATUS_DATA_ERROR"), - SMB_NTSTATUS_CRC_ERROR => Some("STATUS_CRC_ERROR"), - SMB_NTSTATUS_SECTION_TOO_BIG => Some("STATUS_SECTION_TOO_BIG"), - SMB_NTSTATUS_PORT_CONNECTION_REFUSED => Some("STATUS_PORT_CONNECTION_REFUSED"), - SMB_NTSTATUS_INVALID_PORT_HANDLE => Some("STATUS_INVALID_PORT_HANDLE"), - SMB_NTSTATUS_SHARING_VIOLATION => Some("STATUS_SHARING_VIOLATION"), - SMB_NTSTATUS_QUOTA_EXCEEDED => Some("STATUS_QUOTA_EXCEEDED"), - SMB_NTSTATUS_INVALID_PAGE_PROTECTION => Some("STATUS_INVALID_PAGE_PROTECTION"), - SMB_NTSTATUS_MUTANT_NOT_OWNED => Some("STATUS_MUTANT_NOT_OWNED"), - SMB_NTSTATUS_SEMAPHORE_LIMIT_EXCEEDED => Some("STATUS_SEMAPHORE_LIMIT_EXCEEDED"), - SMB_NTSTATUS_PORT_ALREADY_SET => Some("STATUS_PORT_ALREADY_SET"), - SMB_NTSTATUS_SECTION_NOT_IMAGE => Some("STATUS_SECTION_NOT_IMAGE"), - SMB_NTSTATUS_SUSPEND_COUNT_EXCEEDED => Some("STATUS_SUSPEND_COUNT_EXCEEDED"), - SMB_NTSTATUS_THREAD_IS_TERMINATING => Some("STATUS_THREAD_IS_TERMINATING"), - SMB_NTSTATUS_BAD_WORKING_SET_LIMIT => Some("STATUS_BAD_WORKING_SET_LIMIT"), - SMB_NTSTATUS_INCOMPATIBLE_FILE_MAP => Some("STATUS_INCOMPATIBLE_FILE_MAP"), - SMB_NTSTATUS_SECTION_PROTECTION => Some("STATUS_SECTION_PROTECTION"), - SMB_NTSTATUS_EAS_NOT_SUPPORTED => Some("STATUS_EAS_NOT_SUPPORTED"), - SMB_NTSTATUS_EA_TOO_LARGE => Some("STATUS_EA_TOO_LARGE"), - SMB_NTSTATUS_NONEXISTENT_EA_ENTRY => Some("STATUS_NONEXISTENT_EA_ENTRY"), - SMB_NTSTATUS_NO_EAS_ON_FILE => Some("STATUS_NO_EAS_ON_FILE"), - SMB_NTSTATUS_EA_CORRUPT_ERROR => Some("STATUS_EA_CORRUPT_ERROR"), - SMB_NTSTATUS_FILE_LOCK_CONFLICT => Some("STATUS_FILE_LOCK_CONFLICT"), - SMB_NTSTATUS_LOCK_NOT_GRANTED => Some("STATUS_LOCK_NOT_GRANTED"), - SMB_NTSTATUS_DELETE_PENDING => Some("STATUS_DELETE_PENDING"), - SMB_NTSTATUS_CTL_FILE_NOT_SUPPORTED => Some("STATUS_CTL_FILE_NOT_SUPPORTED"), - SMB_NTSTATUS_UNKNOWN_REVISION => Some("STATUS_UNKNOWN_REVISION"), - SMB_NTSTATUS_REVISION_MISMATCH => Some("STATUS_REVISION_MISMATCH"), - SMB_NTSTATUS_INVALID_OWNER => Some("STATUS_INVALID_OWNER"), - SMB_NTSTATUS_INVALID_PRIMARY_GROUP => Some("STATUS_INVALID_PRIMARY_GROUP"), - SMB_NTSTATUS_NO_IMPERSONATION_TOKEN => Some("STATUS_NO_IMPERSONATION_TOKEN"), - SMB_NTSTATUS_CANT_DISABLE_MANDATORY => Some("STATUS_CANT_DISABLE_MANDATORY"), - SMB_NTSTATUS_NO_LOGON_SERVERS => Some("STATUS_NO_LOGON_SERVERS"), - SMB_NTSTATUS_NO_SUCH_LOGON_SESSION => Some("STATUS_NO_SUCH_LOGON_SESSION"), - SMB_NTSTATUS_NO_SUCH_PRIVILEGE => Some("STATUS_NO_SUCH_PRIVILEGE"), - SMB_NTSTATUS_PRIVILEGE_NOT_HELD => Some("STATUS_PRIVILEGE_NOT_HELD"), - SMB_NTSTATUS_INVALID_ACCOUNT_NAME => Some("STATUS_INVALID_ACCOUNT_NAME"), - SMB_NTSTATUS_USER_EXISTS => Some("STATUS_USER_EXISTS"), - SMB_NTSTATUS_NO_SUCH_USER => Some("STATUS_NO_SUCH_USER"), - SMB_NTSTATUS_GROUP_EXISTS => Some("STATUS_GROUP_EXISTS"), - SMB_NTSTATUS_NO_SUCH_GROUP => Some("STATUS_NO_SUCH_GROUP"), - SMB_NTSTATUS_MEMBER_IN_GROUP => Some("STATUS_MEMBER_IN_GROUP"), - SMB_NTSTATUS_MEMBER_NOT_IN_GROUP => Some("STATUS_MEMBER_NOT_IN_GROUP"), - SMB_NTSTATUS_LAST_ADMIN => Some("STATUS_LAST_ADMIN"), - SMB_NTSTATUS_WRONG_PASSWORD => Some("STATUS_WRONG_PASSWORD"), - SMB_NTSTATUS_ILL_FORMED_PASSWORD => Some("STATUS_ILL_FORMED_PASSWORD"), - SMB_NTSTATUS_PASSWORD_RESTRICTION => Some("STATUS_PASSWORD_RESTRICTION"), - SMB_NTSTATUS_LOGON_FAILURE => Some("STATUS_LOGON_FAILURE"), - SMB_NTSTATUS_ACCOUNT_RESTRICTION => Some("STATUS_ACCOUNT_RESTRICTION"), - SMB_NTSTATUS_INVALID_LOGON_HOURS => Some("STATUS_INVALID_LOGON_HOURS"), - SMB_NTSTATUS_INVALID_WORKSTATION => Some("STATUS_INVALID_WORKSTATION"), - SMB_NTSTATUS_PASSWORD_EXPIRED => Some("STATUS_PASSWORD_EXPIRED"), - SMB_NTSTATUS_ACCOUNT_DISABLED => Some("STATUS_ACCOUNT_DISABLED"), - SMB_NTSTATUS_NONE_MAPPED => Some("STATUS_NONE_MAPPED"), - SMB_NTSTATUS_TOO_MANY_LUIDS_REQUESTED => Some("STATUS_TOO_MANY_LUIDS_REQUESTED"), - SMB_NTSTATUS_LUIDS_EXHAUSTED => Some("STATUS_LUIDS_EXHAUSTED"), - SMB_NTSTATUS_INVALID_SUB_AUTHORITY => Some("STATUS_INVALID_SUB_AUTHORITY"), - SMB_NTSTATUS_INVALID_ACL => Some("STATUS_INVALID_ACL"), - SMB_NTSTATUS_INVALID_SID => Some("STATUS_INVALID_SID"), - SMB_NTSTATUS_INVALID_SECURITY_DESCR => Some("STATUS_INVALID_SECURITY_DESCR"), - SMB_NTSTATUS_PROCEDURE_NOT_FOUND => Some("STATUS_PROCEDURE_NOT_FOUND"), - SMB_NTSTATUS_INVALID_IMAGE_FORMAT => Some("STATUS_INVALID_IMAGE_FORMAT"), - SMB_NTSTATUS_NO_TOKEN => Some("STATUS_NO_TOKEN"), - SMB_NTSTATUS_BAD_INHERITANCE_ACL => Some("STATUS_BAD_INHERITANCE_ACL"), - SMB_NTSTATUS_RANGE_NOT_LOCKED => Some("STATUS_RANGE_NOT_LOCKED"), - SMB_NTSTATUS_DISK_FULL => Some("STATUS_DISK_FULL"), - SMB_NTSTATUS_SERVER_DISABLED => Some("STATUS_SERVER_DISABLED"), - SMB_NTSTATUS_SERVER_NOT_DISABLED => Some("STATUS_SERVER_NOT_DISABLED"), - SMB_NTSTATUS_TOO_MANY_GUIDS_REQUESTED => Some("STATUS_TOO_MANY_GUIDS_REQUESTED"), - SMB_NTSTATUS_GUIDS_EXHAUSTED => Some("STATUS_GUIDS_EXHAUSTED"), - SMB_NTSTATUS_INVALID_ID_AUTHORITY => Some("STATUS_INVALID_ID_AUTHORITY"), - SMB_NTSTATUS_AGENTS_EXHAUSTED => Some("STATUS_AGENTS_EXHAUSTED"), - SMB_NTSTATUS_INVALID_VOLUME_LABEL => Some("STATUS_INVALID_VOLUME_LABEL"), - SMB_NTSTATUS_SECTION_NOT_EXTENDED => Some("STATUS_SECTION_NOT_EXTENDED"), - SMB_NTSTATUS_NOT_MAPPED_DATA => Some("STATUS_NOT_MAPPED_DATA"), - SMB_NTSTATUS_RESOURCE_DATA_NOT_FOUND => Some("STATUS_RESOURCE_DATA_NOT_FOUND"), - SMB_NTSTATUS_RESOURCE_TYPE_NOT_FOUND => Some("STATUS_RESOURCE_TYPE_NOT_FOUND"), - SMB_NTSTATUS_RESOURCE_NAME_NOT_FOUND => Some("STATUS_RESOURCE_NAME_NOT_FOUND"), - SMB_NTSTATUS_ARRAY_BOUNDS_EXCEEDED => Some("STATUS_ARRAY_BOUNDS_EXCEEDED"), - SMB_NTSTATUS_FLOAT_DENORMAL_OPERAND => Some("STATUS_FLOAT_DENORMAL_OPERAND"), - SMB_NTSTATUS_FLOAT_DIVIDE_BY_ZERO => Some("STATUS_FLOAT_DIVIDE_BY_ZERO"), - SMB_NTSTATUS_FLOAT_INEXACT_RESULT => Some("STATUS_FLOAT_INEXACT_RESULT"), - SMB_NTSTATUS_FLOAT_INVALID_OPERATION => Some("STATUS_FLOAT_INVALID_OPERATION"), - SMB_NTSTATUS_FLOAT_OVERFLOW => Some("STATUS_FLOAT_OVERFLOW"), - SMB_NTSTATUS_FLOAT_STACK_CHECK => Some("STATUS_FLOAT_STACK_CHECK"), - SMB_NTSTATUS_FLOAT_UNDERFLOW => Some("STATUS_FLOAT_UNDERFLOW"), - SMB_NTSTATUS_INTEGER_DIVIDE_BY_ZERO => Some("STATUS_INTEGER_DIVIDE_BY_ZERO"), - SMB_NTSTATUS_INTEGER_OVERFLOW => Some("STATUS_INTEGER_OVERFLOW"), - SMB_NTSTATUS_PRIVILEGED_INSTRUCTION => Some("STATUS_PRIVILEGED_INSTRUCTION"), - SMB_NTSTATUS_TOO_MANY_PAGING_FILES => Some("STATUS_TOO_MANY_PAGING_FILES"), - SMB_NTSTATUS_FILE_INVALID => Some("STATUS_FILE_INVALID"), - SMB_NTSTATUS_ALLOTTED_SPACE_EXCEEDED => Some("STATUS_ALLOTTED_SPACE_EXCEEDED"), - SMB_NTSTATUS_INSUFFICIENT_RESOURCES => Some("STATUS_INSUFFICIENT_RESOURCES"), - SMB_NTSTATUS_DFS_EXIT_PATH_FOUND => Some("STATUS_DFS_EXIT_PATH_FOUND"), - SMB_NTSTATUS_DEVICE_DATA_ERROR => Some("STATUS_DEVICE_DATA_ERROR"), - SMB_NTSTATUS_DEVICE_NOT_CONNECTED => Some("STATUS_DEVICE_NOT_CONNECTED"), - SMB_NTSTATUS_FREE_VM_NOT_AT_BASE => Some("STATUS_FREE_VM_NOT_AT_BASE"), - SMB_NTSTATUS_MEMORY_NOT_ALLOCATED => Some("STATUS_MEMORY_NOT_ALLOCATED"), - SMB_NTSTATUS_WORKING_SET_QUOTA => Some("STATUS_WORKING_SET_QUOTA"), - SMB_NTSTATUS_MEDIA_WRITE_PROTECTED => Some("STATUS_MEDIA_WRITE_PROTECTED"), - SMB_NTSTATUS_DEVICE_NOT_READY => Some("STATUS_DEVICE_NOT_READY"), - SMB_NTSTATUS_INVALID_GROUP_ATTRIBUTES => Some("STATUS_INVALID_GROUP_ATTRIBUTES"), - SMB_NTSTATUS_BAD_IMPERSONATION_LEVEL => Some("STATUS_BAD_IMPERSONATION_LEVEL"), - SMB_NTSTATUS_CANT_OPEN_ANONYMOUS => Some("STATUS_CANT_OPEN_ANONYMOUS"), - SMB_NTSTATUS_BAD_VALIDATION_CLASS => Some("STATUS_BAD_VALIDATION_CLASS"), - SMB_NTSTATUS_BAD_TOKEN_TYPE => Some("STATUS_BAD_TOKEN_TYPE"), - SMB_NTSTATUS_BAD_MASTER_BOOT_RECORD => Some("STATUS_BAD_MASTER_BOOT_RECORD"), - SMB_NTSTATUS_INSTRUCTION_MISALIGNMENT => Some("STATUS_INSTRUCTION_MISALIGNMENT"), - SMB_NTSTATUS_INSTANCE_NOT_AVAILABLE => Some("STATUS_INSTANCE_NOT_AVAILABLE"), - SMB_NTSTATUS_PIPE_NOT_AVAILABLE => Some("STATUS_PIPE_NOT_AVAILABLE"), - SMB_NTSTATUS_INVALID_PIPE_STATE => Some("STATUS_INVALID_PIPE_STATE"), - SMB_NTSTATUS_PIPE_BUSY => Some("STATUS_PIPE_BUSY"), - SMB_NTSTATUS_ILLEGAL_FUNCTION => Some("STATUS_ILLEGAL_FUNCTION"), - SMB_NTSTATUS_PIPE_DISCONNECTED => Some("STATUS_PIPE_DISCONNECTED"), - SMB_NTSTATUS_PIPE_CLOSING => Some("STATUS_PIPE_CLOSING"), - SMB_NTSTATUS_PIPE_CONNECTED => Some("STATUS_PIPE_CONNECTED"), - SMB_NTSTATUS_PIPE_LISTENING => Some("STATUS_PIPE_LISTENING"), - SMB_NTSTATUS_INVALID_READ_MODE => Some("STATUS_INVALID_READ_MODE"), - SMB_NTSTATUS_IO_TIMEOUT => Some("STATUS_IO_TIMEOUT"), - SMB_NTSTATUS_FILE_FORCED_CLOSED => Some("STATUS_FILE_FORCED_CLOSED"), - SMB_NTSTATUS_PROFILING_NOT_STARTED => Some("STATUS_PROFILING_NOT_STARTED"), - SMB_NTSTATUS_PROFILING_NOT_STOPPED => Some("STATUS_PROFILING_NOT_STOPPED"), - SMB_NTSTATUS_COULD_NOT_INTERPRET => Some("STATUS_COULD_NOT_INTERPRET"), - SMB_NTSTATUS_FILE_IS_A_DIRECTORY => Some("STATUS_FILE_IS_A_DIRECTORY"), - SMB_NTSTATUS_NOT_SUPPORTED => Some("STATUS_NOT_SUPPORTED"), - SMB_NTSTATUS_REMOTE_NOT_LISTENING => Some("STATUS_REMOTE_NOT_LISTENING"), - SMB_NTSTATUS_DUPLICATE_NAME => Some("STATUS_DUPLICATE_NAME"), - SMB_NTSTATUS_BAD_NETWORK_PATH => Some("STATUS_BAD_NETWORK_PATH"), - SMB_NTSTATUS_NETWORK_BUSY => Some("STATUS_NETWORK_BUSY"), - SMB_NTSTATUS_DEVICE_DOES_NOT_EXIST => Some("STATUS_DEVICE_DOES_NOT_EXIST"), - SMB_NTSTATUS_TOO_MANY_COMMANDS => Some("STATUS_TOO_MANY_COMMANDS"), - SMB_NTSTATUS_ADAPTER_HARDWARE_ERROR => Some("STATUS_ADAPTER_HARDWARE_ERROR"), - SMB_NTSTATUS_INVALID_NETWORK_RESPONSE => Some("STATUS_INVALID_NETWORK_RESPONSE"), - SMB_NTSTATUS_UNEXPECTED_NETWORK_ERROR => Some("STATUS_UNEXPECTED_NETWORK_ERROR"), - SMB_NTSTATUS_BAD_REMOTE_ADAPTER => Some("STATUS_BAD_REMOTE_ADAPTER"), - SMB_NTSTATUS_PRINT_QUEUE_FULL => Some("STATUS_PRINT_QUEUE_FULL"), - SMB_NTSTATUS_NO_SPOOL_SPACE => Some("STATUS_NO_SPOOL_SPACE"), - SMB_NTSTATUS_PRINT_CANCELLED => Some("STATUS_PRINT_CANCELLED"), - SMB_NTSTATUS_NETWORK_NAME_DELETED => Some("STATUS_NETWORK_NAME_DELETED"), - SMB_NTSTATUS_NETWORK_ACCESS_DENIED => Some("STATUS_NETWORK_ACCESS_DENIED"), - SMB_NTSTATUS_BAD_DEVICE_TYPE => Some("STATUS_BAD_DEVICE_TYPE"), - SMB_NTSTATUS_BAD_NETWORK_NAME => Some("STATUS_BAD_NETWORK_NAME"), - SMB_NTSTATUS_TOO_MANY_NAMES => Some("STATUS_TOO_MANY_NAMES"), - SMB_NTSTATUS_TOO_MANY_SESSIONS => Some("STATUS_TOO_MANY_SESSIONS"), - SMB_NTSTATUS_SHARING_PAUSED => Some("STATUS_SHARING_PAUSED"), - SMB_NTSTATUS_REQUEST_NOT_ACCEPTED => Some("STATUS_REQUEST_NOT_ACCEPTED"), - SMB_NTSTATUS_REDIRECTOR_PAUSED => Some("STATUS_REDIRECTOR_PAUSED"), - SMB_NTSTATUS_NET_WRITE_FAULT => Some("STATUS_NET_WRITE_FAULT"), - SMB_NTSTATUS_PROFILING_AT_LIMIT => Some("STATUS_PROFILING_AT_LIMIT"), - SMB_NTSTATUS_NOT_SAME_DEVICE => Some("STATUS_NOT_SAME_DEVICE"), - SMB_NTSTATUS_FILE_RENAMED => Some("STATUS_FILE_RENAMED"), - SMB_NTSTATUS_VIRTUAL_CIRCUIT_CLOSED => Some("STATUS_VIRTUAL_CIRCUIT_CLOSED"), - SMB_NTSTATUS_NO_SECURITY_ON_OBJECT => Some("STATUS_NO_SECURITY_ON_OBJECT"), - SMB_NTSTATUS_CANT_WAIT => Some("STATUS_CANT_WAIT"), - SMB_NTSTATUS_PIPE_EMPTY => Some("STATUS_PIPE_EMPTY"), - SMB_NTSTATUS_CANT_ACCESS_DOMAIN_INFO => Some("STATUS_CANT_ACCESS_DOMAIN_INFO"), - SMB_NTSTATUS_CANT_TERMINATE_SELF => Some("STATUS_CANT_TERMINATE_SELF"), - SMB_NTSTATUS_INVALID_SERVER_STATE => Some("STATUS_INVALID_SERVER_STATE"), - SMB_NTSTATUS_INVALID_DOMAIN_STATE => Some("STATUS_INVALID_DOMAIN_STATE"), - SMB_NTSTATUS_INVALID_DOMAIN_ROLE => Some("STATUS_INVALID_DOMAIN_ROLE"), - SMB_NTSTATUS_NO_SUCH_DOMAIN => Some("STATUS_NO_SUCH_DOMAIN"), - SMB_NTSTATUS_DOMAIN_EXISTS => Some("STATUS_DOMAIN_EXISTS"), - SMB_NTSTATUS_DOMAIN_LIMIT_EXCEEDED => Some("STATUS_DOMAIN_LIMIT_EXCEEDED"), - SMB_NTSTATUS_OPLOCK_NOT_GRANTED => Some("STATUS_OPLOCK_NOT_GRANTED"), - SMB_NTSTATUS_INVALID_OPLOCK_PROTOCOL => Some("STATUS_INVALID_OPLOCK_PROTOCOL"), - SMB_NTSTATUS_INTERNAL_DB_CORRUPTION => Some("STATUS_INTERNAL_DB_CORRUPTION"), - SMB_NTSTATUS_INTERNAL_ERROR => Some("STATUS_INTERNAL_ERROR"), - SMB_NTSTATUS_GENERIC_NOT_MAPPED => Some("STATUS_GENERIC_NOT_MAPPED"), - SMB_NTSTATUS_BAD_DESCRIPTOR_FORMAT => Some("STATUS_BAD_DESCRIPTOR_FORMAT"), - SMB_NTSTATUS_INVALID_USER_BUFFER => Some("STATUS_INVALID_USER_BUFFER"), - SMB_NTSTATUS_UNEXPECTED_IO_ERROR => Some("STATUS_UNEXPECTED_IO_ERROR"), - SMB_NTSTATUS_UNEXPECTED_MM_CREATE_ERR => Some("STATUS_UNEXPECTED_MM_CREATE_ERR"), - SMB_NTSTATUS_UNEXPECTED_MM_MAP_ERROR => Some("STATUS_UNEXPECTED_MM_MAP_ERROR"), - SMB_NTSTATUS_UNEXPECTED_MM_EXTEND_ERR => Some("STATUS_UNEXPECTED_MM_EXTEND_ERR"), - SMB_NTSTATUS_NOT_LOGON_PROCESS => Some("STATUS_NOT_LOGON_PROCESS"), - SMB_NTSTATUS_LOGON_SESSION_EXISTS => Some("STATUS_LOGON_SESSION_EXISTS"), - SMB_NTSTATUS_INVALID_PARAMETER_1 => Some("STATUS_INVALID_PARAMETER_1"), - SMB_NTSTATUS_INVALID_PARAMETER_2 => Some("STATUS_INVALID_PARAMETER_2"), - SMB_NTSTATUS_INVALID_PARAMETER_3 => Some("STATUS_INVALID_PARAMETER_3"), - SMB_NTSTATUS_INVALID_PARAMETER_4 => Some("STATUS_INVALID_PARAMETER_4"), - SMB_NTSTATUS_INVALID_PARAMETER_5 => Some("STATUS_INVALID_PARAMETER_5"), - SMB_NTSTATUS_INVALID_PARAMETER_6 => Some("STATUS_INVALID_PARAMETER_6"), - SMB_NTSTATUS_INVALID_PARAMETER_7 => Some("STATUS_INVALID_PARAMETER_7"), - SMB_NTSTATUS_INVALID_PARAMETER_8 => Some("STATUS_INVALID_PARAMETER_8"), - SMB_NTSTATUS_INVALID_PARAMETER_9 => Some("STATUS_INVALID_PARAMETER_9"), - SMB_NTSTATUS_INVALID_PARAMETER_10 => Some("STATUS_INVALID_PARAMETER_10"), - SMB_NTSTATUS_INVALID_PARAMETER_11 => Some("STATUS_INVALID_PARAMETER_11"), - SMB_NTSTATUS_INVALID_PARAMETER_12 => Some("STATUS_INVALID_PARAMETER_12"), - SMB_NTSTATUS_REDIRECTOR_NOT_STARTED => Some("STATUS_REDIRECTOR_NOT_STARTED"), - SMB_NTSTATUS_REDIRECTOR_STARTED => Some("STATUS_REDIRECTOR_STARTED"), - SMB_NTSTATUS_STACK_OVERFLOW => Some("STATUS_STACK_OVERFLOW"), - SMB_NTSTATUS_NO_SUCH_PACKAGE => Some("STATUS_NO_SUCH_PACKAGE"), - SMB_NTSTATUS_BAD_FUNCTION_TABLE => Some("STATUS_BAD_FUNCTION_TABLE"), - SMB_NTSTATUS_VARIABLE_NOT_FOUND => Some("STATUS_VARIABLE_NOT_FOUND"), - SMB_NTSTATUS_DIRECTORY_NOT_EMPTY => Some("STATUS_DIRECTORY_NOT_EMPTY"), - SMB_NTSTATUS_FILE_CORRUPT_ERROR => Some("STATUS_FILE_CORRUPT_ERROR"), - SMB_NTSTATUS_NOT_A_DIRECTORY => Some("STATUS_NOT_A_DIRECTORY"), - SMB_NTSTATUS_BAD_LOGON_SESSION_STATE => Some("STATUS_BAD_LOGON_SESSION_STATE"), - SMB_NTSTATUS_LOGON_SESSION_COLLISION => Some("STATUS_LOGON_SESSION_COLLISION"), - SMB_NTSTATUS_NAME_TOO_LONG => Some("STATUS_NAME_TOO_LONG"), - SMB_NTSTATUS_FILES_OPEN => Some("STATUS_FILES_OPEN"), - SMB_NTSTATUS_CONNECTION_IN_USE => Some("STATUS_CONNECTION_IN_USE"), - SMB_NTSTATUS_MESSAGE_NOT_FOUND => Some("STATUS_MESSAGE_NOT_FOUND"), - SMB_NTSTATUS_PROCESS_IS_TERMINATING => Some("STATUS_PROCESS_IS_TERMINATING"), - SMB_NTSTATUS_INVALID_LOGON_TYPE => Some("STATUS_INVALID_LOGON_TYPE"), - SMB_NTSTATUS_NO_GUID_TRANSLATION => Some("STATUS_NO_GUID_TRANSLATION"), - SMB_NTSTATUS_CANNOT_IMPERSONATE => Some("STATUS_CANNOT_IMPERSONATE"), - SMB_NTSTATUS_IMAGE_ALREADY_LOADED => Some("STATUS_IMAGE_ALREADY_LOADED"), - SMB_NTSTATUS_NO_LDT => Some("STATUS_NO_LDT"), - SMB_NTSTATUS_INVALID_LDT_SIZE => Some("STATUS_INVALID_LDT_SIZE"), - SMB_NTSTATUS_INVALID_LDT_OFFSET => Some("STATUS_INVALID_LDT_OFFSET"), - SMB_NTSTATUS_INVALID_LDT_DESCRIPTOR => Some("STATUS_INVALID_LDT_DESCRIPTOR"), - SMB_NTSTATUS_INVALID_IMAGE_NE_FORMAT => Some("STATUS_INVALID_IMAGE_NE_FORMAT"), - SMB_NTSTATUS_RXACT_INVALID_STATE => Some("STATUS_RXACT_INVALID_STATE"), - SMB_NTSTATUS_RXACT_COMMIT_FAILURE => Some("STATUS_RXACT_COMMIT_FAILURE"), - SMB_NTSTATUS_MAPPED_FILE_SIZE_ZERO => Some("STATUS_MAPPED_FILE_SIZE_ZERO"), - SMB_NTSTATUS_TOO_MANY_OPENED_FILES => Some("STATUS_TOO_MANY_OPENED_FILES"), - SMB_NTSTATUS_CANCELLED => Some("STATUS_CANCELLED"), - SMB_NTSTATUS_CANNOT_DELETE => Some("STATUS_CANNOT_DELETE"), - SMB_NTSTATUS_INVALID_COMPUTER_NAME => Some("STATUS_INVALID_COMPUTER_NAME"), - SMB_NTSTATUS_FILE_DELETED => Some("STATUS_FILE_DELETED"), - SMB_NTSTATUS_SPECIAL_ACCOUNT => Some("STATUS_SPECIAL_ACCOUNT"), - SMB_NTSTATUS_SPECIAL_GROUP => Some("STATUS_SPECIAL_GROUP"), - SMB_NTSTATUS_SPECIAL_USER => Some("STATUS_SPECIAL_USER"), - SMB_NTSTATUS_MEMBERS_PRIMARY_GROUP => Some("STATUS_MEMBERS_PRIMARY_GROUP"), - SMB_NTSTATUS_FILE_CLOSED => Some("STATUS_FILE_CLOSED"), - SMB_NTSTATUS_TOO_MANY_THREADS => Some("STATUS_TOO_MANY_THREADS"), - SMB_NTSTATUS_THREAD_NOT_IN_PROCESS => Some("STATUS_THREAD_NOT_IN_PROCESS"), - SMB_NTSTATUS_TOKEN_ALREADY_IN_USE => Some("STATUS_TOKEN_ALREADY_IN_USE"), - SMB_NTSTATUS_PAGEFILE_QUOTA_EXCEEDED => Some("STATUS_PAGEFILE_QUOTA_EXCEEDED"), - SMB_NTSTATUS_COMMITMENT_LIMIT => Some("STATUS_COMMITMENT_LIMIT"), - SMB_NTSTATUS_INVALID_IMAGE_LE_FORMAT => Some("STATUS_INVALID_IMAGE_LE_FORMAT"), - SMB_NTSTATUS_INVALID_IMAGE_NOT_MZ => Some("STATUS_INVALID_IMAGE_NOT_MZ"), - SMB_NTSTATUS_INVALID_IMAGE_PROTECT => Some("STATUS_INVALID_IMAGE_PROTECT"), - SMB_NTSTATUS_INVALID_IMAGE_WIN_16 => Some("STATUS_INVALID_IMAGE_WIN_16"), - SMB_NTSTATUS_LOGON_SERVER_CONFLICT => Some("STATUS_LOGON_SERVER_CONFLICT"), - SMB_NTSTATUS_TIME_DIFFERENCE_AT_DC => Some("STATUS_TIME_DIFFERENCE_AT_DC"), - SMB_NTSTATUS_SYNCHRONIZATION_REQUIRED => Some("STATUS_SYNCHRONIZATION_REQUIRED"), - SMB_NTSTATUS_DLL_NOT_FOUND => Some("STATUS_DLL_NOT_FOUND"), - SMB_NTSTATUS_OPEN_FAILED => Some("STATUS_OPEN_FAILED"), - SMB_NTSTATUS_IO_PRIVILEGE_FAILED => Some("STATUS_IO_PRIVILEGE_FAILED"), - SMB_NTSTATUS_ORDINAL_NOT_FOUND => Some("STATUS_ORDINAL_NOT_FOUND"), - SMB_NTSTATUS_ENTRYPOINT_NOT_FOUND => Some("STATUS_ENTRYPOINT_NOT_FOUND"), - SMB_NTSTATUS_CONTROL_C_EXIT => Some("STATUS_CONTROL_C_EXIT"), - SMB_NTSTATUS_LOCAL_DISCONNECT => Some("STATUS_LOCAL_DISCONNECT"), - SMB_NTSTATUS_REMOTE_DISCONNECT => Some("STATUS_REMOTE_DISCONNECT"), - SMB_NTSTATUS_REMOTE_RESOURCES => Some("STATUS_REMOTE_RESOURCES"), - SMB_NTSTATUS_LINK_FAILED => Some("STATUS_LINK_FAILED"), - SMB_NTSTATUS_LINK_TIMEOUT => Some("STATUS_LINK_TIMEOUT"), - SMB_NTSTATUS_INVALID_CONNECTION => Some("STATUS_INVALID_CONNECTION"), - SMB_NTSTATUS_INVALID_ADDRESS => Some("STATUS_INVALID_ADDRESS"), - SMB_NTSTATUS_DLL_INIT_FAILED => Some("STATUS_DLL_INIT_FAILED"), - SMB_NTSTATUS_MISSING_SYSTEMFILE => Some("STATUS_MISSING_SYSTEMFILE"), - SMB_NTSTATUS_UNHANDLED_EXCEPTION => Some("STATUS_UNHANDLED_EXCEPTION"), - SMB_NTSTATUS_APP_INIT_FAILURE => Some("STATUS_APP_INIT_FAILURE"), - SMB_NTSTATUS_PAGEFILE_CREATE_FAILED => Some("STATUS_PAGEFILE_CREATE_FAILED"), - SMB_NTSTATUS_NO_PAGEFILE => Some("STATUS_NO_PAGEFILE"), - SMB_NTSTATUS_INVALID_LEVEL => Some("STATUS_INVALID_LEVEL"), - SMB_NTSTATUS_WRONG_PASSWORD_CORE => Some("STATUS_WRONG_PASSWORD_CORE"), - SMB_NTSTATUS_ILLEGAL_FLOAT_CONTEXT => Some("STATUS_ILLEGAL_FLOAT_CONTEXT"), - SMB_NTSTATUS_PIPE_BROKEN => Some("STATUS_PIPE_BROKEN"), - SMB_NTSTATUS_REGISTRY_CORRUPT => Some("STATUS_REGISTRY_CORRUPT"), - SMB_NTSTATUS_REGISTRY_IO_FAILED => Some("STATUS_REGISTRY_IO_FAILED"), - SMB_NTSTATUS_NO_EVENT_PAIR => Some("STATUS_NO_EVENT_PAIR"), - SMB_NTSTATUS_UNRECOGNIZED_VOLUME => Some("STATUS_UNRECOGNIZED_VOLUME"), - SMB_NTSTATUS_SERIAL_NO_DEVICE_INITED => Some("STATUS_SERIAL_NO_DEVICE_INITED"), - SMB_NTSTATUS_NO_SUCH_ALIAS => Some("STATUS_NO_SUCH_ALIAS"), - SMB_NTSTATUS_MEMBER_NOT_IN_ALIAS => Some("STATUS_MEMBER_NOT_IN_ALIAS"), - SMB_NTSTATUS_MEMBER_IN_ALIAS => Some("STATUS_MEMBER_IN_ALIAS"), - SMB_NTSTATUS_ALIAS_EXISTS => Some("STATUS_ALIAS_EXISTS"), - SMB_NTSTATUS_LOGON_NOT_GRANTED => Some("STATUS_LOGON_NOT_GRANTED"), - SMB_NTSTATUS_TOO_MANY_SECRETS => Some("STATUS_TOO_MANY_SECRETS"), - SMB_NTSTATUS_SECRET_TOO_LONG => Some("STATUS_SECRET_TOO_LONG"), - SMB_NTSTATUS_INTERNAL_DB_ERROR => Some("STATUS_INTERNAL_DB_ERROR"), - SMB_NTSTATUS_FULLSCREEN_MODE => Some("STATUS_FULLSCREEN_MODE"), - SMB_NTSTATUS_TOO_MANY_CONTEXT_IDS => Some("STATUS_TOO_MANY_CONTEXT_IDS"), - SMB_NTSTATUS_LOGON_TYPE_NOT_GRANTED => Some("STATUS_LOGON_TYPE_NOT_GRANTED"), - SMB_NTSTATUS_NOT_REGISTRY_FILE => Some("STATUS_NOT_REGISTRY_FILE"), - SMB_NTSTATUS_NT_CROSS_ENCRYPTION_REQUIRED => Some("STATUS_NT_CROSS_ENCRYPTION_REQUIRED"), - SMB_NTSTATUS_DOMAIN_CTRLR_CONFIG_ERROR => Some("STATUS_DOMAIN_CTRLR_CONFIG_ERROR"), - SMB_NTSTATUS_FT_MISSING_MEMBER => Some("STATUS_FT_MISSING_MEMBER"), - SMB_NTSTATUS_ILL_FORMED_SERVICE_ENTRY => Some("STATUS_ILL_FORMED_SERVICE_ENTRY"), - SMB_NTSTATUS_ILLEGAL_CHARACTER => Some("STATUS_ILLEGAL_CHARACTER"), - SMB_NTSTATUS_UNMAPPABLE_CHARACTER => Some("STATUS_UNMAPPABLE_CHARACTER"), - SMB_NTSTATUS_UNDEFINED_CHARACTER => Some("STATUS_UNDEFINED_CHARACTER"), - SMB_NTSTATUS_FLOPPY_VOLUME => Some("STATUS_FLOPPY_VOLUME"), - SMB_NTSTATUS_FLOPPY_ID_MARK_NOT_FOUND => Some("STATUS_FLOPPY_ID_MARK_NOT_FOUND"), - SMB_NTSTATUS_FLOPPY_WRONG_CYLINDER => Some("STATUS_FLOPPY_WRONG_CYLINDER"), - SMB_NTSTATUS_FLOPPY_UNKNOWN_ERROR => Some("STATUS_FLOPPY_UNKNOWN_ERROR"), - SMB_NTSTATUS_FLOPPY_BAD_REGISTERS => Some("STATUS_FLOPPY_BAD_REGISTERS"), - SMB_NTSTATUS_DISK_RECALIBRATE_FAILED => Some("STATUS_DISK_RECALIBRATE_FAILED"), - SMB_NTSTATUS_DISK_OPERATION_FAILED => Some("STATUS_DISK_OPERATION_FAILED"), - SMB_NTSTATUS_DISK_RESET_FAILED => Some("STATUS_DISK_RESET_FAILED"), - SMB_NTSTATUS_SHARED_IRQ_BUSY => Some("STATUS_SHARED_IRQ_BUSY"), - SMB_NTSTATUS_FT_ORPHANING => Some("STATUS_FT_ORPHANING"), - SMB_NTSTATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT => Some("STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT"), - SMB_NTSTATUS_PARTITION_FAILURE => Some("STATUS_PARTITION_FAILURE"), - SMB_NTSTATUS_INVALID_BLOCK_LENGTH => Some("STATUS_INVALID_BLOCK_LENGTH"), - SMB_NTSTATUS_DEVICE_NOT_PARTITIONED => Some("STATUS_DEVICE_NOT_PARTITIONED"), - SMB_NTSTATUS_UNABLE_TO_LOCK_MEDIA => Some("STATUS_UNABLE_TO_LOCK_MEDIA"), - SMB_NTSTATUS_UNABLE_TO_UNLOAD_MEDIA => Some("STATUS_UNABLE_TO_UNLOAD_MEDIA"), - SMB_NTSTATUS_EOM_OVERFLOW => Some("STATUS_EOM_OVERFLOW"), - SMB_NTSTATUS_NO_MEDIA => Some("STATUS_NO_MEDIA"), - SMB_NTSTATUS_NO_SUCH_MEMBER => Some("STATUS_NO_SUCH_MEMBER"), - SMB_NTSTATUS_INVALID_MEMBER => Some("STATUS_INVALID_MEMBER"), - SMB_NTSTATUS_KEY_DELETED => Some("STATUS_KEY_DELETED"), - SMB_NTSTATUS_NO_LOG_SPACE => Some("STATUS_NO_LOG_SPACE"), - SMB_NTSTATUS_TOO_MANY_SIDS => Some("STATUS_TOO_MANY_SIDS"), - SMB_NTSTATUS_LM_CROSS_ENCRYPTION_REQUIRED => Some("STATUS_LM_CROSS_ENCRYPTION_REQUIRED"), - SMB_NTSTATUS_KEY_HAS_CHILDREN => Some("STATUS_KEY_HAS_CHILDREN"), - SMB_NTSTATUS_CHILD_MUST_BE_VOLATILE => Some("STATUS_CHILD_MUST_BE_VOLATILE"), - SMB_NTSTATUS_DEVICE_CONFIGURATION_ERROR => Some("STATUS_DEVICE_CONFIGURATION_ERROR"), - SMB_NTSTATUS_DRIVER_INTERNAL_ERROR => Some("STATUS_DRIVER_INTERNAL_ERROR"), - SMB_NTSTATUS_INVALID_DEVICE_STATE => Some("STATUS_INVALID_DEVICE_STATE"), - SMB_NTSTATUS_IO_DEVICE_ERROR => Some("STATUS_IO_DEVICE_ERROR"), - SMB_NTSTATUS_DEVICE_PROTOCOL_ERROR => Some("STATUS_DEVICE_PROTOCOL_ERROR"), - SMB_NTSTATUS_BACKUP_CONTROLLER => Some("STATUS_BACKUP_CONTROLLER"), - SMB_NTSTATUS_LOG_FILE_FULL => Some("STATUS_LOG_FILE_FULL"), - SMB_NTSTATUS_TOO_LATE => Some("STATUS_TOO_LATE"), - SMB_NTSTATUS_NO_TRUST_LSA_SECRET => Some("STATUS_NO_TRUST_LSA_SECRET"), - SMB_NTSTATUS_NO_TRUST_SAM_ACCOUNT => Some("STATUS_NO_TRUST_SAM_ACCOUNT"), - SMB_NTSTATUS_TRUSTED_DOMAIN_FAILURE => Some("STATUS_TRUSTED_DOMAIN_FAILURE"), - SMB_NTSTATUS_TRUSTED_RELATIONSHIP_FAILURE => Some("STATUS_TRUSTED_RELATIONSHIP_FAILURE"), - SMB_NTSTATUS_EVENTLOG_FILE_CORRUPT => Some("STATUS_EVENTLOG_FILE_CORRUPT"), - SMB_NTSTATUS_EVENTLOG_CANT_START => Some("STATUS_EVENTLOG_CANT_START"), - SMB_NTSTATUS_TRUST_FAILURE => Some("STATUS_TRUST_FAILURE"), - SMB_NTSTATUS_MUTANT_LIMIT_EXCEEDED => Some("STATUS_MUTANT_LIMIT_EXCEEDED"), - SMB_NTSTATUS_NETLOGON_NOT_STARTED => Some("STATUS_NETLOGON_NOT_STARTED"), - SMB_NTSTATUS_ACCOUNT_EXPIRED => Some("STATUS_ACCOUNT_EXPIRED"), - SMB_NTSTATUS_POSSIBLE_DEADLOCK => Some("STATUS_POSSIBLE_DEADLOCK"), - SMB_NTSTATUS_NETWORK_CREDENTIAL_CONFLICT => Some("STATUS_NETWORK_CREDENTIAL_CONFLICT"), - SMB_NTSTATUS_REMOTE_SESSION_LIMIT => Some("STATUS_REMOTE_SESSION_LIMIT"), - SMB_NTSTATUS_EVENTLOG_FILE_CHANGED => Some("STATUS_EVENTLOG_FILE_CHANGED"), - SMB_NTSTATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT => Some("STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"), - SMB_NTSTATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT => Some("STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT"), - SMB_NTSTATUS_NOLOGON_SERVER_TRUST_ACCOUNT => Some("STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"), - SMB_NTSTATUS_DOMAIN_TRUST_INCONSISTENT => Some("STATUS_DOMAIN_TRUST_INCONSISTENT"), - SMB_NTSTATUS_FS_DRIVER_REQUIRED => Some("STATUS_FS_DRIVER_REQUIRED"), - SMB_NTSTATUS_IMAGE_ALREADY_LOADED_AS_DLL => Some("STATUS_IMAGE_ALREADY_LOADED_AS_DLL"), - SMB_NTSTATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING => Some("STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING"), - SMB_NTSTATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME => Some("STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME"), - SMB_NTSTATUS_SECURITY_STREAM_IS_INCONSISTENT => Some("STATUS_SECURITY_STREAM_IS_INCONSISTENT"), - SMB_NTSTATUS_INVALID_LOCK_RANGE => Some("STATUS_INVALID_LOCK_RANGE"), - SMB_NTSTATUS_INVALID_ACE_CONDITION => Some("STATUS_INVALID_ACE_CONDITION"), - SMB_NTSTATUS_IMAGE_SUBSYSTEM_NOT_PRESENT => Some("STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT"), - SMB_NTSTATUS_NOTIFICATION_GUID_ALREADY_DEFINED => Some("STATUS_NOTIFICATION_GUID_ALREADY_DEFINED"), - SMB_NTSTATUS_NETWORK_OPEN_RESTRICTION => Some("STATUS_NETWORK_OPEN_RESTRICTION"), - SMB_NTSTATUS_NO_USER_SESSION_KEY => Some("STATUS_NO_USER_SESSION_KEY"), - SMB_NTSTATUS_USER_SESSION_DELETED => Some("STATUS_USER_SESSION_DELETED"), - SMB_NTSTATUS_RESOURCE_LANG_NOT_FOUND => Some("STATUS_RESOURCE_LANG_NOT_FOUND"), - SMB_NTSTATUS_INSUFF_SERVER_RESOURCES => Some("STATUS_INSUFF_SERVER_RESOURCES"), - SMB_NTSTATUS_INVALID_BUFFER_SIZE => Some("STATUS_INVALID_BUFFER_SIZE"), - SMB_NTSTATUS_INVALID_ADDRESS_COMPONENT => Some("STATUS_INVALID_ADDRESS_COMPONENT"), - SMB_NTSTATUS_INVALID_ADDRESS_WILDCARD => Some("STATUS_INVALID_ADDRESS_WILDCARD"), - SMB_NTSTATUS_TOO_MANY_ADDRESSES => Some("STATUS_TOO_MANY_ADDRESSES"), - SMB_NTSTATUS_ADDRESS_ALREADY_EXISTS => Some("STATUS_ADDRESS_ALREADY_EXISTS"), - SMB_NTSTATUS_ADDRESS_CLOSED => Some("STATUS_ADDRESS_CLOSED"), - SMB_NTSTATUS_CONNECTION_DISCONNECTED => Some("STATUS_CONNECTION_DISCONNECTED"), - SMB_NTSTATUS_CONNECTION_RESET => Some("STATUS_CONNECTION_RESET"), - SMB_NTSTATUS_TOO_MANY_NODES => Some("STATUS_TOO_MANY_NODES"), - SMB_NTSTATUS_TRANSACTION_ABORTED => Some("STATUS_TRANSACTION_ABORTED"), - SMB_NTSTATUS_TRANSACTION_TIMED_OUT => Some("STATUS_TRANSACTION_TIMED_OUT"), - SMB_NTSTATUS_TRANSACTION_NO_RELEASE => Some("STATUS_TRANSACTION_NO_RELEASE"), - SMB_NTSTATUS_TRANSACTION_NO_MATCH => Some("STATUS_TRANSACTION_NO_MATCH"), - SMB_NTSTATUS_TRANSACTION_RESPONDED => Some("STATUS_TRANSACTION_RESPONDED"), - SMB_NTSTATUS_TRANSACTION_INVALID_ID => Some("STATUS_TRANSACTION_INVALID_ID"), - SMB_NTSTATUS_TRANSACTION_INVALID_TYPE => Some("STATUS_TRANSACTION_INVALID_TYPE"), - SMB_NTSTATUS_NOT_SERVER_SESSION => Some("STATUS_NOT_SERVER_SESSION"), - SMB_NTSTATUS_NOT_CLIENT_SESSION => Some("STATUS_NOT_CLIENT_SESSION"), - SMB_NTSTATUS_CANNOT_LOAD_REGISTRY_FILE => Some("STATUS_CANNOT_LOAD_REGISTRY_FILE"), - SMB_NTSTATUS_DEBUG_ATTACH_FAILED => Some("STATUS_DEBUG_ATTACH_FAILED"), - SMB_NTSTATUS_SYSTEM_PROCESS_TERMINATED => Some("STATUS_SYSTEM_PROCESS_TERMINATED"), - SMB_NTSTATUS_DATA_NOT_ACCEPTED => Some("STATUS_DATA_NOT_ACCEPTED"), - SMB_NTSTATUS_NO_BROWSER_SERVERS_FOUND => Some("STATUS_NO_BROWSER_SERVERS_FOUND"), - SMB_NTSTATUS_VDM_HARD_ERROR => Some("STATUS_VDM_HARD_ERROR"), - SMB_NTSTATUS_DRIVER_CANCEL_TIMEOUT => Some("STATUS_DRIVER_CANCEL_TIMEOUT"), - SMB_NTSTATUS_REPLY_MESSAGE_MISMATCH => Some("STATUS_REPLY_MESSAGE_MISMATCH"), - SMB_NTSTATUS_MAPPED_ALIGNMENT => Some("STATUS_MAPPED_ALIGNMENT"), - SMB_NTSTATUS_IMAGE_CHECKSUM_MISMATCH => Some("STATUS_IMAGE_CHECKSUM_MISMATCH"), - SMB_NTSTATUS_LOST_WRITEBEHIND_DATA => Some("STATUS_LOST_WRITEBEHIND_DATA"), - SMB_NTSTATUS_CLIENT_SERVER_PARAMETERS_INVALID => Some("STATUS_CLIENT_SERVER_PARAMETERS_INVALID"), - SMB_NTSTATUS_PASSWORD_MUST_CHANGE => Some("STATUS_PASSWORD_MUST_CHANGE"), - SMB_NTSTATUS_NOT_FOUND => Some("STATUS_NOT_FOUND"), - SMB_NTSTATUS_NOT_TINY_STREAM => Some("STATUS_NOT_TINY_STREAM"), - SMB_NTSTATUS_RECOVERY_FAILURE => Some("STATUS_RECOVERY_FAILURE"), - SMB_NTSTATUS_STACK_OVERFLOW_READ => Some("STATUS_STACK_OVERFLOW_READ"), - SMB_NTSTATUS_FAIL_CHECK => Some("STATUS_FAIL_CHECK"), - SMB_NTSTATUS_DUPLICATE_OBJECTID => Some("STATUS_DUPLICATE_OBJECTID"), - SMB_NTSTATUS_OBJECTID_EXISTS => Some("STATUS_OBJECTID_EXISTS"), - SMB_NTSTATUS_CONVERT_TO_LARGE => Some("STATUS_CONVERT_TO_LARGE"), - SMB_NTSTATUS_RETRY => Some("STATUS_RETRY"), - SMB_NTSTATUS_FOUND_OUT_OF_SCOPE => Some("STATUS_FOUND_OUT_OF_SCOPE"), - SMB_NTSTATUS_ALLOCATE_BUCKET => Some("STATUS_ALLOCATE_BUCKET"), - SMB_NTSTATUS_PROPSET_NOT_FOUND => Some("STATUS_PROPSET_NOT_FOUND"), - SMB_NTSTATUS_MARSHALL_OVERFLOW => Some("STATUS_MARSHALL_OVERFLOW"), - SMB_NTSTATUS_INVALID_VARIANT => Some("STATUS_INVALID_VARIANT"), - SMB_NTSTATUS_DOMAIN_CONTROLLER_NOT_FOUND => Some("STATUS_DOMAIN_CONTROLLER_NOT_FOUND"), - SMB_NTSTATUS_ACCOUNT_LOCKED_OUT => Some("STATUS_ACCOUNT_LOCKED_OUT"), - SMB_NTSTATUS_HANDLE_NOT_CLOSABLE => Some("STATUS_HANDLE_NOT_CLOSABLE"), - SMB_NTSTATUS_CONNECTION_REFUSED => Some("STATUS_CONNECTION_REFUSED"), - SMB_NTSTATUS_GRACEFUL_DISCONNECT => Some("STATUS_GRACEFUL_DISCONNECT"), - SMB_NTSTATUS_ADDRESS_ALREADY_ASSOCIATED => Some("STATUS_ADDRESS_ALREADY_ASSOCIATED"), - SMB_NTSTATUS_ADDRESS_NOT_ASSOCIATED => Some("STATUS_ADDRESS_NOT_ASSOCIATED"), - SMB_NTSTATUS_CONNECTION_INVALID => Some("STATUS_CONNECTION_INVALID"), - SMB_NTSTATUS_CONNECTION_ACTIVE => Some("STATUS_CONNECTION_ACTIVE"), - SMB_NTSTATUS_NETWORK_UNREACHABLE => Some("STATUS_NETWORK_UNREACHABLE"), - SMB_NTSTATUS_HOST_UNREACHABLE => Some("STATUS_HOST_UNREACHABLE"), - SMB_NTSTATUS_PROTOCOL_UNREACHABLE => Some("STATUS_PROTOCOL_UNREACHABLE"), - SMB_NTSTATUS_PORT_UNREACHABLE => Some("STATUS_PORT_UNREACHABLE"), - SMB_NTSTATUS_REQUEST_ABORTED => Some("STATUS_REQUEST_ABORTED"), - SMB_NTSTATUS_CONNECTION_ABORTED => Some("STATUS_CONNECTION_ABORTED"), - SMB_NTSTATUS_BAD_COMPRESSION_BUFFER => Some("STATUS_BAD_COMPRESSION_BUFFER"), - SMB_NTSTATUS_USER_MAPPED_FILE => Some("STATUS_USER_MAPPED_FILE"), - SMB_NTSTATUS_AUDIT_FAILED => Some("STATUS_AUDIT_FAILED"), - SMB_NTSTATUS_TIMER_RESOLUTION_NOT_SET => Some("STATUS_TIMER_RESOLUTION_NOT_SET"), - SMB_NTSTATUS_CONNECTION_COUNT_LIMIT => Some("STATUS_CONNECTION_COUNT_LIMIT"), - SMB_NTSTATUS_LOGIN_TIME_RESTRICTION => Some("STATUS_LOGIN_TIME_RESTRICTION"), - SMB_NTSTATUS_LOGIN_WKSTA_RESTRICTION => Some("STATUS_LOGIN_WKSTA_RESTRICTION"), - SMB_NTSTATUS_IMAGE_MP_UP_MISMATCH => Some("STATUS_IMAGE_MP_UP_MISMATCH"), - SMB_NTSTATUS_INSUFFICIENT_LOGON_INFO => Some("STATUS_INSUFFICIENT_LOGON_INFO"), - SMB_NTSTATUS_BAD_DLL_ENTRYPOINT => Some("STATUS_BAD_DLL_ENTRYPOINT"), - SMB_NTSTATUS_BAD_SERVICE_ENTRYPOINT => Some("STATUS_BAD_SERVICE_ENTRYPOINT"), - SMB_NTSTATUS_LPC_REPLY_LOST => Some("STATUS_LPC_REPLY_LOST"), - SMB_NTSTATUS_IP_ADDRESS_CONFLICT1 => Some("STATUS_IP_ADDRESS_CONFLICT1"), - SMB_NTSTATUS_IP_ADDRESS_CONFLICT2 => Some("STATUS_IP_ADDRESS_CONFLICT2"), - SMB_NTSTATUS_REGISTRY_QUOTA_LIMIT => Some("STATUS_REGISTRY_QUOTA_LIMIT"), - SMB_NTSTATUS_PATH_NOT_COVERED => Some("STATUS_PATH_NOT_COVERED"), - SMB_NTSTATUS_NO_CALLBACK_ACTIVE => Some("STATUS_NO_CALLBACK_ACTIVE"), - SMB_NTSTATUS_LICENSE_QUOTA_EXCEEDED => Some("STATUS_LICENSE_QUOTA_EXCEEDED"), - SMB_NTSTATUS_PWD_TOO_SHORT => Some("STATUS_PWD_TOO_SHORT"), - SMB_NTSTATUS_PWD_TOO_RECENT => Some("STATUS_PWD_TOO_RECENT"), - SMB_NTSTATUS_PWD_HISTORY_CONFLICT => Some("STATUS_PWD_HISTORY_CONFLICT"), - SMB_NTSTATUS_PLUGPLAY_NO_DEVICE => Some("STATUS_PLUGPLAY_NO_DEVICE"), - SMB_NTSTATUS_UNSUPPORTED_COMPRESSION => Some("STATUS_UNSUPPORTED_COMPRESSION"), - SMB_NTSTATUS_INVALID_HW_PROFILE => Some("STATUS_INVALID_HW_PROFILE"), - SMB_NTSTATUS_INVALID_PLUGPLAY_DEVICE_PATH => Some("STATUS_INVALID_PLUGPLAY_DEVICE_PATH"), - SMB_NTSTATUS_DRIVER_ORDINAL_NOT_FOUND => Some("STATUS_DRIVER_ORDINAL_NOT_FOUND"), - SMB_NTSTATUS_DRIVER_ENTRYPOINT_NOT_FOUND => Some("STATUS_DRIVER_ENTRYPOINT_NOT_FOUND"), - SMB_NTSTATUS_RESOURCE_NOT_OWNED => Some("STATUS_RESOURCE_NOT_OWNED"), - SMB_NTSTATUS_TOO_MANY_LINKS => Some("STATUS_TOO_MANY_LINKS"), - SMB_NTSTATUS_QUOTA_LIST_INCONSISTENT => Some("STATUS_QUOTA_LIST_INCONSISTENT"), - SMB_NTSTATUS_FILE_IS_OFFLINE => Some("STATUS_FILE_IS_OFFLINE"), - SMB_NTSTATUS_EVALUATION_EXPIRATION => Some("STATUS_EVALUATION_EXPIRATION"), - SMB_NTSTATUS_ILLEGAL_DLL_RELOCATION => Some("STATUS_ILLEGAL_DLL_RELOCATION"), - SMB_NTSTATUS_LICENSE_VIOLATION => Some("STATUS_LICENSE_VIOLATION"), - SMB_NTSTATUS_DLL_INIT_FAILED_LOGOFF => Some("STATUS_DLL_INIT_FAILED_LOGOFF"), - SMB_NTSTATUS_DRIVER_UNABLE_TO_LOAD => Some("STATUS_DRIVER_UNABLE_TO_LOAD"), - SMB_NTSTATUS_DFS_UNAVAILABLE => Some("STATUS_DFS_UNAVAILABLE"), - SMB_NTSTATUS_VOLUME_DISMOUNTED => Some("STATUS_VOLUME_DISMOUNTED"), - SMB_NTSTATUS_WX86_INTERNAL_ERROR => Some("STATUS_WX86_INTERNAL_ERROR"), - SMB_NTSTATUS_WX86_FLOAT_STACK_CHECK => Some("STATUS_WX86_FLOAT_STACK_CHECK"), - SMB_NTSTATUS_VALIDATE_CONTINUE => Some("STATUS_VALIDATE_CONTINUE"), - SMB_NTSTATUS_NO_MATCH => Some("STATUS_NO_MATCH"), - SMB_NTSTATUS_NO_MORE_MATCHES => Some("STATUS_NO_MORE_MATCHES"), - SMB_NTSTATUS_NOT_A_REPARSE_POINT => Some("STATUS_NOT_A_REPARSE_POINT"), - SMB_NTSTATUS_IO_REPARSE_TAG_INVALID => Some("STATUS_IO_REPARSE_TAG_INVALID"), - SMB_NTSTATUS_IO_REPARSE_TAG_MISMATCH => Some("STATUS_IO_REPARSE_TAG_MISMATCH"), - SMB_NTSTATUS_IO_REPARSE_DATA_INVALID => Some("STATUS_IO_REPARSE_DATA_INVALID"), - SMB_NTSTATUS_IO_REPARSE_TAG_NOT_HANDLED => Some("STATUS_IO_REPARSE_TAG_NOT_HANDLED"), - SMB_NTSTATUS_REPARSE_POINT_NOT_RESOLVED => Some("STATUS_REPARSE_POINT_NOT_RESOLVED"), - SMB_NTSTATUS_DIRECTORY_IS_A_REPARSE_POINT => Some("STATUS_DIRECTORY_IS_A_REPARSE_POINT"), - SMB_NTSTATUS_RANGE_LIST_CONFLICT => Some("STATUS_RANGE_LIST_CONFLICT"), - SMB_NTSTATUS_SOURCE_ELEMENT_EMPTY => Some("STATUS_SOURCE_ELEMENT_EMPTY"), - SMB_NTSTATUS_DESTINATION_ELEMENT_FULL => Some("STATUS_DESTINATION_ELEMENT_FULL"), - SMB_NTSTATUS_ILLEGAL_ELEMENT_ADDRESS => Some("STATUS_ILLEGAL_ELEMENT_ADDRESS"), - SMB_NTSTATUS_MAGAZINE_NOT_PRESENT => Some("STATUS_MAGAZINE_NOT_PRESENT"), - SMB_NTSTATUS_REINITIALIZATION_NEEDED => Some("STATUS_REINITIALIZATION_NEEDED"), - SMB_NTSTATUS_ENCRYPTION_FAILED => Some("STATUS_ENCRYPTION_FAILED"), - SMB_NTSTATUS_DECRYPTION_FAILED => Some("STATUS_DECRYPTION_FAILED"), - SMB_NTSTATUS_RANGE_NOT_FOUND => Some("STATUS_RANGE_NOT_FOUND"), - SMB_NTSTATUS_NO_RECOVERY_POLICY => Some("STATUS_NO_RECOVERY_POLICY"), - SMB_NTSTATUS_NO_EFS => Some("STATUS_NO_EFS"), - SMB_NTSTATUS_WRONG_EFS => Some("STATUS_WRONG_EFS"), - SMB_NTSTATUS_NO_USER_KEYS => Some("STATUS_NO_USER_KEYS"), - SMB_NTSTATUS_FILE_NOT_ENCRYPTED => Some("STATUS_FILE_NOT_ENCRYPTED"), - SMB_NTSTATUS_NOT_EXPORT_FORMAT => Some("STATUS_NOT_EXPORT_FORMAT"), - SMB_NTSTATUS_FILE_ENCRYPTED => Some("STATUS_FILE_ENCRYPTED"), - SMB_NTSTATUS_WMI_GUID_NOT_FOUND => Some("STATUS_WMI_GUID_NOT_FOUND"), - SMB_NTSTATUS_WMI_INSTANCE_NOT_FOUND => Some("STATUS_WMI_INSTANCE_NOT_FOUND"), - SMB_NTSTATUS_WMI_ITEMID_NOT_FOUND => Some("STATUS_WMI_ITEMID_NOT_FOUND"), - SMB_NTSTATUS_WMI_TRY_AGAIN => Some("STATUS_WMI_TRY_AGAIN"), - SMB_NTSTATUS_SHARED_POLICY => Some("STATUS_SHARED_POLICY"), - SMB_NTSTATUS_POLICY_OBJECT_NOT_FOUND => Some("STATUS_POLICY_OBJECT_NOT_FOUND"), - SMB_NTSTATUS_POLICY_ONLY_IN_DS => Some("STATUS_POLICY_ONLY_IN_DS"), - SMB_NTSTATUS_VOLUME_NOT_UPGRADED => Some("STATUS_VOLUME_NOT_UPGRADED"), - SMB_NTSTATUS_REMOTE_STORAGE_NOT_ACTIVE => Some("STATUS_REMOTE_STORAGE_NOT_ACTIVE"), - SMB_NTSTATUS_REMOTE_STORAGE_MEDIA_ERROR => Some("STATUS_REMOTE_STORAGE_MEDIA_ERROR"), - SMB_NTSTATUS_NO_TRACKING_SERVICE => Some("STATUS_NO_TRACKING_SERVICE"), - SMB_NTSTATUS_SERVER_SID_MISMATCH => Some("STATUS_SERVER_SID_MISMATCH"), - SMB_NTSTATUS_DS_NO_ATTRIBUTE_OR_VALUE => Some("STATUS_DS_NO_ATTRIBUTE_OR_VALUE"), - SMB_NTSTATUS_DS_INVALID_ATTRIBUTE_SYNTAX => Some("STATUS_DS_INVALID_ATTRIBUTE_SYNTAX"), - SMB_NTSTATUS_DS_ATTRIBUTE_TYPE_UNDEFINED => Some("STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED"), - SMB_NTSTATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS => Some("STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS"), - SMB_NTSTATUS_DS_BUSY => Some("STATUS_DS_BUSY"), - SMB_NTSTATUS_DS_UNAVAILABLE => Some("STATUS_DS_UNAVAILABLE"), - SMB_NTSTATUS_DS_NO_RIDS_ALLOCATED => Some("STATUS_DS_NO_RIDS_ALLOCATED"), - SMB_NTSTATUS_DS_NO_MORE_RIDS => Some("STATUS_DS_NO_MORE_RIDS"), - SMB_NTSTATUS_DS_INCORRECT_ROLE_OWNER => Some("STATUS_DS_INCORRECT_ROLE_OWNER"), - SMB_NTSTATUS_DS_RIDMGR_INIT_ERROR => Some("STATUS_DS_RIDMGR_INIT_ERROR"), - SMB_NTSTATUS_DS_OBJ_CLASS_VIOLATION => Some("STATUS_DS_OBJ_CLASS_VIOLATION"), - SMB_NTSTATUS_DS_CANT_ON_NON_LEAF => Some("STATUS_DS_CANT_ON_NON_LEAF"), - SMB_NTSTATUS_DS_CANT_ON_RDN => Some("STATUS_DS_CANT_ON_RDN"), - SMB_NTSTATUS_DS_CANT_MOD_OBJ_CLASS => Some("STATUS_DS_CANT_MOD_OBJ_CLASS"), - SMB_NTSTATUS_DS_CROSS_DOM_MOVE_FAILED => Some("STATUS_DS_CROSS_DOM_MOVE_FAILED"), - SMB_NTSTATUS_DS_GC_NOT_AVAILABLE => Some("STATUS_DS_GC_NOT_AVAILABLE"), - SMB_NTSTATUS_DIRECTORY_SERVICE_REQUIRED => Some("STATUS_DIRECTORY_SERVICE_REQUIRED"), - SMB_NTSTATUS_REPARSE_ATTRIBUTE_CONFLICT => Some("STATUS_REPARSE_ATTRIBUTE_CONFLICT"), - SMB_NTSTATUS_CANT_ENABLE_DENY_ONLY => Some("STATUS_CANT_ENABLE_DENY_ONLY"), - SMB_NTSTATUS_FLOAT_MULTIPLE_FAULTS => Some("STATUS_FLOAT_MULTIPLE_FAULTS"), - SMB_NTSTATUS_FLOAT_MULTIPLE_TRAPS => Some("STATUS_FLOAT_MULTIPLE_TRAPS"), - SMB_NTSTATUS_DEVICE_REMOVED => Some("STATUS_DEVICE_REMOVED"), - SMB_NTSTATUS_JOURNAL_DELETE_IN_PROGRESS => Some("STATUS_JOURNAL_DELETE_IN_PROGRESS"), - SMB_NTSTATUS_JOURNAL_NOT_ACTIVE => Some("STATUS_JOURNAL_NOT_ACTIVE"), - SMB_NTSTATUS_NOINTERFACE => Some("STATUS_NOINTERFACE"), - SMB_NTSTATUS_DS_ADMIN_LIMIT_EXCEEDED => Some("STATUS_DS_ADMIN_LIMIT_EXCEEDED"), - SMB_NTSTATUS_DRIVER_FAILED_SLEEP => Some("STATUS_DRIVER_FAILED_SLEEP"), - SMB_NTSTATUS_MUTUAL_AUTHENTICATION_FAILED => Some("STATUS_MUTUAL_AUTHENTICATION_FAILED"), - SMB_NTSTATUS_CORRUPT_SYSTEM_FILE => Some("STATUS_CORRUPT_SYSTEM_FILE"), - SMB_NTSTATUS_DATATYPE_MISALIGNMENT_ERROR => Some("STATUS_DATATYPE_MISALIGNMENT_ERROR"), - SMB_NTSTATUS_WMI_READ_ONLY => Some("STATUS_WMI_READ_ONLY"), - SMB_NTSTATUS_WMI_SET_FAILURE => Some("STATUS_WMI_SET_FAILURE"), - SMB_NTSTATUS_COMMITMENT_MINIMUM => Some("STATUS_COMMITMENT_MINIMUM"), - SMB_NTSTATUS_REG_NAT_CONSUMPTION => Some("STATUS_REG_NAT_CONSUMPTION"), - SMB_NTSTATUS_TRANSPORT_FULL => Some("STATUS_TRANSPORT_FULL"), - SMB_NTSTATUS_DS_SAM_INIT_FAILURE => Some("STATUS_DS_SAM_INIT_FAILURE"), - SMB_NTSTATUS_ONLY_IF_CONNECTED => Some("STATUS_ONLY_IF_CONNECTED"), - SMB_NTSTATUS_DS_SENSITIVE_GROUP_VIOLATION => Some("STATUS_DS_SENSITIVE_GROUP_VIOLATION"), - SMB_NTSTATUS_PNP_RESTART_ENUMERATION => Some("STATUS_PNP_RESTART_ENUMERATION"), - SMB_NTSTATUS_JOURNAL_ENTRY_DELETED => Some("STATUS_JOURNAL_ENTRY_DELETED"), - SMB_NTSTATUS_DS_CANT_MOD_PRIMARYGROUPID => Some("STATUS_DS_CANT_MOD_PRIMARYGROUPID"), - SMB_NTSTATUS_SYSTEM_IMAGE_BAD_SIGNATURE => Some("STATUS_SYSTEM_IMAGE_BAD_SIGNATURE"), - SMB_NTSTATUS_PNP_REBOOT_REQUIRED => Some("STATUS_PNP_REBOOT_REQUIRED"), - SMB_NTSTATUS_POWER_STATE_INVALID => Some("STATUS_POWER_STATE_INVALID"), - SMB_NTSTATUS_DS_INVALID_GROUP_TYPE => Some("STATUS_DS_INVALID_GROUP_TYPE"), - SMB_NTSTATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN => Some("STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN"), - SMB_NTSTATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN => Some("STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN"), - SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER => Some("STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER"), - SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER => Some("STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER"), - SMB_NTSTATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER => Some("STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER"), - SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER => Some("STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER"), - SMB_NTSTATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER => Some("STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER"), - SMB_NTSTATUS_DS_HAVE_PRIMARY_MEMBERS => Some("STATUS_DS_HAVE_PRIMARY_MEMBERS"), - SMB_NTSTATUS_WMI_NOT_SUPPORTED => Some("STATUS_WMI_NOT_SUPPORTED"), - SMB_NTSTATUS_INSUFFICIENT_POWER => Some("STATUS_INSUFFICIENT_POWER"), - SMB_NTSTATUS_SAM_NEED_BOOTKEY_PASSWORD => Some("STATUS_SAM_NEED_BOOTKEY_PASSWORD"), - SMB_NTSTATUS_SAM_NEED_BOOTKEY_FLOPPY => Some("STATUS_SAM_NEED_BOOTKEY_FLOPPY"), - SMB_NTSTATUS_DS_CANT_START => Some("STATUS_DS_CANT_START"), - SMB_NTSTATUS_DS_INIT_FAILURE => Some("STATUS_DS_INIT_FAILURE"), - SMB_NTSTATUS_SAM_INIT_FAILURE => Some("STATUS_SAM_INIT_FAILURE"), - SMB_NTSTATUS_DS_GC_REQUIRED => Some("STATUS_DS_GC_REQUIRED"), - SMB_NTSTATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY => Some("STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY"), - SMB_NTSTATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS => Some("STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS"), - SMB_NTSTATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED => Some("STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED"), - SMB_NTSTATUS_CURRENT_DOMAIN_NOT_ALLOWED => Some("STATUS_CURRENT_DOMAIN_NOT_ALLOWED"), - SMB_NTSTATUS_CANNOT_MAKE => Some("STATUS_CANNOT_MAKE"), - SMB_NTSTATUS_SYSTEM_SHUTDOWN => Some("STATUS_SYSTEM_SHUTDOWN"), - SMB_NTSTATUS_DS_INIT_FAILURE_CONSOLE => Some("STATUS_DS_INIT_FAILURE_CONSOLE"), - SMB_NTSTATUS_DS_SAM_INIT_FAILURE_CONSOLE => Some("STATUS_DS_SAM_INIT_FAILURE_CONSOLE"), - SMB_NTSTATUS_UNFINISHED_CONTEXT_DELETED => Some("STATUS_UNFINISHED_CONTEXT_DELETED"), - SMB_NTSTATUS_NO_TGT_REPLY => Some("STATUS_NO_TGT_REPLY"), - SMB_NTSTATUS_OBJECTID_NOT_FOUND => Some("STATUS_OBJECTID_NOT_FOUND"), - SMB_NTSTATUS_NO_IP_ADDRESSES => Some("STATUS_NO_IP_ADDRESSES"), - SMB_NTSTATUS_WRONG_CREDENTIAL_HANDLE => Some("STATUS_WRONG_CREDENTIAL_HANDLE"), - SMB_NTSTATUS_CRYPTO_SYSTEM_INVALID => Some("STATUS_CRYPTO_SYSTEM_INVALID"), - SMB_NTSTATUS_MAX_REFERRALS_EXCEEDED => Some("STATUS_MAX_REFERRALS_EXCEEDED"), - SMB_NTSTATUS_MUST_BE_KDC => Some("STATUS_MUST_BE_KDC"), - SMB_NTSTATUS_STRONG_CRYPTO_NOT_SUPPORTED => Some("STATUS_STRONG_CRYPTO_NOT_SUPPORTED"), - SMB_NTSTATUS_TOO_MANY_PRINCIPALS => Some("STATUS_TOO_MANY_PRINCIPALS"), - SMB_NTSTATUS_NO_PA_DATA => Some("STATUS_NO_PA_DATA"), - SMB_NTSTATUS_PKINIT_NAME_MISMATCH => Some("STATUS_PKINIT_NAME_MISMATCH"), - SMB_NTSTATUS_SMARTCARD_LOGON_REQUIRED => Some("STATUS_SMARTCARD_LOGON_REQUIRED"), - SMB_NTSTATUS_KDC_INVALID_REQUEST => Some("STATUS_KDC_INVALID_REQUEST"), - SMB_NTSTATUS_KDC_UNABLE_TO_REFER => Some("STATUS_KDC_UNABLE_TO_REFER"), - SMB_NTSTATUS_KDC_UNKNOWN_ETYPE => Some("STATUS_KDC_UNKNOWN_ETYPE"), - SMB_NTSTATUS_SHUTDOWN_IN_PROGRESS => Some("STATUS_SHUTDOWN_IN_PROGRESS"), - SMB_NTSTATUS_SERVER_SHUTDOWN_IN_PROGRESS => Some("STATUS_SERVER_SHUTDOWN_IN_PROGRESS"), - SMB_NTSTATUS_NOT_SUPPORTED_ON_SBS => Some("STATUS_NOT_SUPPORTED_ON_SBS"), - SMB_NTSTATUS_WMI_GUID_DISCONNECTED => Some("STATUS_WMI_GUID_DISCONNECTED"), - SMB_NTSTATUS_WMI_ALREADY_DISABLED => Some("STATUS_WMI_ALREADY_DISABLED"), - SMB_NTSTATUS_WMI_ALREADY_ENABLED => Some("STATUS_WMI_ALREADY_ENABLED"), - SMB_NTSTATUS_MFT_TOO_FRAGMENTED => Some("STATUS_MFT_TOO_FRAGMENTED"), - SMB_NTSTATUS_COPY_PROTECTION_FAILURE => Some("STATUS_COPY_PROTECTION_FAILURE"), - SMB_NTSTATUS_CSS_AUTHENTICATION_FAILURE => Some("STATUS_CSS_AUTHENTICATION_FAILURE"), - SMB_NTSTATUS_CSS_KEY_NOT_PRESENT => Some("STATUS_CSS_KEY_NOT_PRESENT"), - SMB_NTSTATUS_CSS_KEY_NOT_ESTABLISHED => Some("STATUS_CSS_KEY_NOT_ESTABLISHED"), - SMB_NTSTATUS_CSS_SCRAMBLED_SECTOR => Some("STATUS_CSS_SCRAMBLED_SECTOR"), - SMB_NTSTATUS_CSS_REGION_MISMATCH => Some("STATUS_CSS_REGION_MISMATCH"), - SMB_NTSTATUS_CSS_RESETS_EXHAUSTED => Some("STATUS_CSS_RESETS_EXHAUSTED"), - SMB_NTSTATUS_PKINIT_FAILURE => Some("STATUS_PKINIT_FAILURE"), - SMB_NTSTATUS_SMARTCARD_SUBSYSTEM_FAILURE => Some("STATUS_SMARTCARD_SUBSYSTEM_FAILURE"), - SMB_NTSTATUS_NO_KERB_KEY => Some("STATUS_NO_KERB_KEY"), - SMB_NTSTATUS_HOST_DOWN => Some("STATUS_HOST_DOWN"), - SMB_NTSTATUS_UNSUPPORTED_PREAUTH => Some("STATUS_UNSUPPORTED_PREAUTH"), - SMB_NTSTATUS_EFS_ALG_BLOB_TOO_BIG => Some("STATUS_EFS_ALG_BLOB_TOO_BIG"), - SMB_NTSTATUS_PORT_NOT_SET => Some("STATUS_PORT_NOT_SET"), - SMB_NTSTATUS_DEBUGGER_INACTIVE => Some("STATUS_DEBUGGER_INACTIVE"), - SMB_NTSTATUS_DS_VERSION_CHECK_FAILURE => Some("STATUS_DS_VERSION_CHECK_FAILURE"), - SMB_NTSTATUS_AUDITING_DISABLED => Some("STATUS_AUDITING_DISABLED"), - SMB_NTSTATUS_PRENT4_MACHINE_ACCOUNT => Some("STATUS_PRENT4_MACHINE_ACCOUNT"), - SMB_NTSTATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER => Some("STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER"), - SMB_NTSTATUS_INVALID_IMAGE_WIN_32 => Some("STATUS_INVALID_IMAGE_WIN_32"), - SMB_NTSTATUS_INVALID_IMAGE_WIN_64 => Some("STATUS_INVALID_IMAGE_WIN_64"), - SMB_NTSTATUS_BAD_BINDINGS => Some("STATUS_BAD_BINDINGS"), - SMB_NTSTATUS_NETWORK_SESSION_EXPIRED => Some("STATUS_NETWORK_SESSION_EXPIRED"), - SMB_NTSTATUS_APPHELP_BLOCK => Some("STATUS_APPHELP_BLOCK"), - SMB_NTSTATUS_ALL_SIDS_FILTERED => Some("STATUS_ALL_SIDS_FILTERED"), - SMB_NTSTATUS_NOT_SAFE_MODE_DRIVER => Some("STATUS_NOT_SAFE_MODE_DRIVER"), - SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT => Some("STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT"), - SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PATH => Some("STATUS_ACCESS_DISABLED_BY_POLICY_PATH"), - SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER => Some("STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER"), - SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_OTHER => Some("STATUS_ACCESS_DISABLED_BY_POLICY_OTHER"), - SMB_NTSTATUS_FAILED_DRIVER_ENTRY => Some("STATUS_FAILED_DRIVER_ENTRY"), - SMB_NTSTATUS_DEVICE_ENUMERATION_ERROR => Some("STATUS_DEVICE_ENUMERATION_ERROR"), - SMB_NTSTATUS_MOUNT_POINT_NOT_RESOLVED => Some("STATUS_MOUNT_POINT_NOT_RESOLVED"), - SMB_NTSTATUS_INVALID_DEVICE_OBJECT_PARAMETER => Some("STATUS_INVALID_DEVICE_OBJECT_PARAMETER"), - SMB_NTSTATUS_MCA_OCCURED => Some("STATUS_MCA_OCCURED"), - SMB_NTSTATUS_DRIVER_BLOCKED_CRITICAL => Some("STATUS_DRIVER_BLOCKED_CRITICAL"), - SMB_NTSTATUS_DRIVER_BLOCKED => Some("STATUS_DRIVER_BLOCKED"), - SMB_NTSTATUS_DRIVER_DATABASE_ERROR => Some("STATUS_DRIVER_DATABASE_ERROR"), - SMB_NTSTATUS_SYSTEM_HIVE_TOO_LARGE => Some("STATUS_SYSTEM_HIVE_TOO_LARGE"), - SMB_NTSTATUS_INVALID_IMPORT_OF_NON_DLL => Some("STATUS_INVALID_IMPORT_OF_NON_DLL"), - SMB_NTSTATUS_NO_SECRETS => Some("STATUS_NO_SECRETS"), - SMB_NTSTATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY => Some("STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY"), - SMB_NTSTATUS_FAILED_STACK_SWITCH => Some("STATUS_FAILED_STACK_SWITCH"), - SMB_NTSTATUS_HEAP_CORRUPTION => Some("STATUS_HEAP_CORRUPTION"), - SMB_NTSTATUS_SMARTCARD_WRONG_PIN => Some("STATUS_SMARTCARD_WRONG_PIN"), - SMB_NTSTATUS_SMARTCARD_CARD_BLOCKED => Some("STATUS_SMARTCARD_CARD_BLOCKED"), - SMB_NTSTATUS_SMARTCARD_CARD_NOT_AUTHENTICATED => Some("STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED"), - SMB_NTSTATUS_SMARTCARD_NO_CARD => Some("STATUS_SMARTCARD_NO_CARD"), - SMB_NTSTATUS_SMARTCARD_NO_KEY_CONTAINER => Some("STATUS_SMARTCARD_NO_KEY_CONTAINER"), - SMB_NTSTATUS_SMARTCARD_NO_CERTIFICATE => Some("STATUS_SMARTCARD_NO_CERTIFICATE"), - SMB_NTSTATUS_SMARTCARD_NO_KEYSET => Some("STATUS_SMARTCARD_NO_KEYSET"), - SMB_NTSTATUS_SMARTCARD_IO_ERROR => Some("STATUS_SMARTCARD_IO_ERROR"), - SMB_NTSTATUS_DOWNGRADE_DETECTED => Some("STATUS_DOWNGRADE_DETECTED"), - SMB_NTSTATUS_SMARTCARD_CERT_REVOKED => Some("STATUS_SMARTCARD_CERT_REVOKED"), - SMB_NTSTATUS_ISSUING_CA_UNTRUSTED => Some("STATUS_ISSUING_CA_UNTRUSTED"), - SMB_NTSTATUS_REVOCATION_OFFLINE_C => Some("STATUS_REVOCATION_OFFLINE_C"), - SMB_NTSTATUS_PKINIT_CLIENT_FAILURE => Some("STATUS_PKINIT_CLIENT_FAILURE"), - SMB_NTSTATUS_SMARTCARD_CERT_EXPIRED => Some("STATUS_SMARTCARD_CERT_EXPIRED"), - SMB_NTSTATUS_DRIVER_FAILED_PRIOR_UNLOAD => Some("STATUS_DRIVER_FAILED_PRIOR_UNLOAD"), - SMB_NTSTATUS_SMARTCARD_SILENT_CONTEXT => Some("STATUS_SMARTCARD_SILENT_CONTEXT"), - SMB_NTSTATUS_PER_USER_TRUST_QUOTA_EXCEEDED => Some("STATUS_PER_USER_TRUST_QUOTA_EXCEEDED"), - SMB_NTSTATUS_ALL_USER_TRUST_QUOTA_EXCEEDED => Some("STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED"), - SMB_NTSTATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED => Some("STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED"), - SMB_NTSTATUS_DS_NAME_NOT_UNIQUE => Some("STATUS_DS_NAME_NOT_UNIQUE"), - SMB_NTSTATUS_DS_DUPLICATE_ID_FOUND => Some("STATUS_DS_DUPLICATE_ID_FOUND"), - SMB_NTSTATUS_DS_GROUP_CONVERSION_ERROR => Some("STATUS_DS_GROUP_CONVERSION_ERROR"), - SMB_NTSTATUS_VOLSNAP_PREPARE_HIBERNATE => Some("STATUS_VOLSNAP_PREPARE_HIBERNATE"), - SMB_NTSTATUS_USER2USER_REQUIRED => Some("STATUS_USER2USER_REQUIRED"), - SMB_NTSTATUS_STACK_BUFFER_OVERRUN => Some("STATUS_STACK_BUFFER_OVERRUN"), - SMB_NTSTATUS_NO_S4U_PROT_SUPPORT => Some("STATUS_NO_S4U_PROT_SUPPORT"), - SMB_NTSTATUS_CROSSREALM_DELEGATION_FAILURE => Some("STATUS_CROSSREALM_DELEGATION_FAILURE"), - SMB_NTSTATUS_REVOCATION_OFFLINE_KDC => Some("STATUS_REVOCATION_OFFLINE_KDC"), - SMB_NTSTATUS_ISSUING_CA_UNTRUSTED_KDC => Some("STATUS_ISSUING_CA_UNTRUSTED_KDC"), - SMB_NTSTATUS_KDC_CERT_EXPIRED => Some("STATUS_KDC_CERT_EXPIRED"), - SMB_NTSTATUS_KDC_CERT_REVOKED => Some("STATUS_KDC_CERT_REVOKED"), - SMB_NTSTATUS_PARAMETER_QUOTA_EXCEEDED => Some("STATUS_PARAMETER_QUOTA_EXCEEDED"), - SMB_NTSTATUS_HIBERNATION_FAILURE => Some("STATUS_HIBERNATION_FAILURE"), - SMB_NTSTATUS_DELAY_LOAD_FAILED => Some("STATUS_DELAY_LOAD_FAILED"), - SMB_NTSTATUS_AUTHENTICATION_FIREWALL_FAILED => Some("STATUS_AUTHENTICATION_FIREWALL_FAILED"), - SMB_NTSTATUS_VDM_DISALLOWED => Some("STATUS_VDM_DISALLOWED"), - SMB_NTSTATUS_HUNG_DISPLAY_DRIVER_THREAD => Some("STATUS_HUNG_DISPLAY_DRIVER_THREAD"), - SMB_NTSTATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE => Some("STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE"), - SMB_NTSTATUS_INVALID_CRUNTIME_PARAMETER => Some("STATUS_INVALID_CRUNTIME_PARAMETER"), - SMB_NTSTATUS_NTLM_BLOCKED => Some("STATUS_NTLM_BLOCKED"), - SMB_NTSTATUS_DS_SRC_SID_EXISTS_IN_FOREST => Some("STATUS_DS_SRC_SID_EXISTS_IN_FOREST"), - SMB_NTSTATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST => Some("STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST"), - SMB_NTSTATUS_DS_FLAT_NAME_EXISTS_IN_FOREST => Some("STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST"), - SMB_NTSTATUS_INVALID_USER_PRINCIPAL_NAME => Some("STATUS_INVALID_USER_PRINCIPAL_NAME"), - SMB_NTSTATUS_ASSERTION_FAILURE => Some("STATUS_ASSERTION_FAILURE"), - SMB_NTSTATUS_VERIFIER_STOP => Some("STATUS_VERIFIER_STOP"), - SMB_NTSTATUS_CALLBACK_POP_STACK => Some("STATUS_CALLBACK_POP_STACK"), - SMB_NTSTATUS_INCOMPATIBLE_DRIVER_BLOCKED => Some("STATUS_INCOMPATIBLE_DRIVER_BLOCKED"), - SMB_NTSTATUS_HIVE_UNLOADED => Some("STATUS_HIVE_UNLOADED"), - SMB_NTSTATUS_COMPRESSION_DISABLED => Some("STATUS_COMPRESSION_DISABLED"), - SMB_NTSTATUS_FILE_SYSTEM_LIMITATION => Some("STATUS_FILE_SYSTEM_LIMITATION"), - SMB_NTSTATUS_INVALID_IMAGE_HASH => Some("STATUS_INVALID_IMAGE_HASH"), - SMB_NTSTATUS_NOT_CAPABLE => Some("STATUS_NOT_CAPABLE"), - SMB_NTSTATUS_REQUEST_OUT_OF_SEQUENCE => Some("STATUS_REQUEST_OUT_OF_SEQUENCE"), - SMB_NTSTATUS_IMPLEMENTATION_LIMIT => Some("STATUS_IMPLEMENTATION_LIMIT"), - SMB_NTSTATUS_ELEVATION_REQUIRED => Some("STATUS_ELEVATION_REQUIRED"), - SMB_NTSTATUS_NO_SECURITY_CONTEXT => Some("STATUS_NO_SECURITY_CONTEXT"), - SMB_NTSTATUS_PKU2U_CERT_FAILURE => Some("STATUS_PKU2U_CERT_FAILURE"), - SMB_NTSTATUS_BEYOND_VDL => Some("STATUS_BEYOND_VDL"), - SMB_NTSTATUS_ENCOUNTERED_WRITE_IN_PROGRESS => Some("STATUS_ENCOUNTERED_WRITE_IN_PROGRESS"), - SMB_NTSTATUS_PTE_CHANGED => Some("STATUS_PTE_CHANGED"), - SMB_NTSTATUS_PURGE_FAILED => Some("STATUS_PURGE_FAILED"), - SMB_NTSTATUS_CRED_REQUIRES_CONFIRMATION => Some("STATUS_CRED_REQUIRES_CONFIRMATION"), - SMB_NTSTATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE => Some("STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE"), - SMB_NTSTATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER => Some("STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER"), - SMB_NTSTATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE => Some("STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE"), - SMB_NTSTATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE => Some("STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE"), - SMB_NTSTATUS_CS_ENCRYPTION_FILE_NOT_CSE => Some("STATUS_CS_ENCRYPTION_FILE_NOT_CSE"), - SMB_NTSTATUS_INVALID_LABEL => Some("STATUS_INVALID_LABEL"), - SMB_NTSTATUS_DRIVER_PROCESS_TERMINATED => Some("STATUS_DRIVER_PROCESS_TERMINATED"), - SMB_NTSTATUS_AMBIGUOUS_SYSTEM_DEVICE => Some("STATUS_AMBIGUOUS_SYSTEM_DEVICE"), - SMB_NTSTATUS_SYSTEM_DEVICE_NOT_FOUND => Some("STATUS_SYSTEM_DEVICE_NOT_FOUND"), - SMB_NTSTATUS_RESTART_BOOT_APPLICATION => Some("STATUS_RESTART_BOOT_APPLICATION"), - SMB_NTSTATUS_INSUFFICIENT_NVRAM_RESOURCES => Some("STATUS_INSUFFICIENT_NVRAM_RESOURCES"), - SMB_NTSTATUS_NO_RANGES_PROCESSED => Some("STATUS_NO_RANGES_PROCESSED"), - SMB_NTSTATUS_DEVICE_FEATURE_NOT_SUPPORTED => Some("STATUS_DEVICE_FEATURE_NOT_SUPPORTED"), - SMB_NTSTATUS_DEVICE_UNREACHABLE => Some("STATUS_DEVICE_UNREACHABLE"), - SMB_NTSTATUS_INVALID_TOKEN => Some("STATUS_INVALID_TOKEN"), - SMB_NTSTATUS_SERVER_UNAVAILABLE => Some("STATUS_SERVER_UNAVAILABLE"), - SMB_NTSTATUS_INVALID_TASK_NAME => Some("STATUS_INVALID_TASK_NAME"), - SMB_NTSTATUS_INVALID_TASK_INDEX => Some("STATUS_INVALID_TASK_INDEX"), - SMB_NTSTATUS_THREAD_ALREADY_IN_TASK => Some("STATUS_THREAD_ALREADY_IN_TASK"), - SMB_NTSTATUS_CALLBACK_BYPASS => Some("STATUS_CALLBACK_BYPASS"), - SMB_NTSTATUS_FAIL_FAST_EXCEPTION => Some("STATUS_FAIL_FAST_EXCEPTION"), - SMB_NTSTATUS_IMAGE_CERT_REVOKED => Some("STATUS_IMAGE_CERT_REVOKED"), - SMB_NTSTATUS_PORT_CLOSED => Some("STATUS_PORT_CLOSED"), - SMB_NTSTATUS_MESSAGE_LOST => Some("STATUS_MESSAGE_LOST"), - SMB_NTSTATUS_INVALID_MESSAGE => Some("STATUS_INVALID_MESSAGE"), - SMB_NTSTATUS_REQUEST_CANCELED => Some("STATUS_REQUEST_CANCELED"), - SMB_NTSTATUS_RECURSIVE_DISPATCH => Some("STATUS_RECURSIVE_DISPATCH"), - SMB_NTSTATUS_LPC_RECEIVE_BUFFER_EXPECTED => Some("STATUS_LPC_RECEIVE_BUFFER_EXPECTED"), - SMB_NTSTATUS_LPC_INVALID_CONNECTION_USAGE => Some("STATUS_LPC_INVALID_CONNECTION_USAGE"), - SMB_NTSTATUS_LPC_REQUESTS_NOT_ALLOWED => Some("STATUS_LPC_REQUESTS_NOT_ALLOWED"), - SMB_NTSTATUS_RESOURCE_IN_USE => Some("STATUS_RESOURCE_IN_USE"), - SMB_NTSTATUS_HARDWARE_MEMORY_ERROR => Some("STATUS_HARDWARE_MEMORY_ERROR"), - SMB_NTSTATUS_THREADPOOL_HANDLE_EXCEPTION => Some("STATUS_THREADPOOL_HANDLE_EXCEPTION"), - SMB_NTSTATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED => Some("STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED"), - SMB_NTSTATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED => Some("STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED"), - SMB_NTSTATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED => Some("STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED"), - SMB_NTSTATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED => Some("STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED"), - SMB_NTSTATUS_THREADPOOL_RELEASED_DURING_OPERATION => Some("STATUS_THREADPOOL_RELEASED_DURING_OPERATION"), - SMB_NTSTATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING => Some("STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING"), - SMB_NTSTATUS_APC_RETURNED_WHILE_IMPERSONATING => Some("STATUS_APC_RETURNED_WHILE_IMPERSONATING"), - SMB_NTSTATUS_PROCESS_IS_PROTECTED => Some("STATUS_PROCESS_IS_PROTECTED"), - SMB_NTSTATUS_MCA_EXCEPTION => Some("STATUS_MCA_EXCEPTION"), - SMB_NTSTATUS_CERTIFICATE_MAPPING_NOT_UNIQUE => Some("STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE"), - SMB_NTSTATUS_SYMLINK_CLASS_DISABLED => Some("STATUS_SYMLINK_CLASS_DISABLED"), - SMB_NTSTATUS_INVALID_IDN_NORMALIZATION => Some("STATUS_INVALID_IDN_NORMALIZATION"), - SMB_NTSTATUS_NO_UNICODE_TRANSLATION => Some("STATUS_NO_UNICODE_TRANSLATION"), - SMB_NTSTATUS_ALREADY_REGISTERED => Some("STATUS_ALREADY_REGISTERED"), - SMB_NTSTATUS_CONTEXT_MISMATCH => Some("STATUS_CONTEXT_MISMATCH"), - SMB_NTSTATUS_PORT_ALREADY_HAS_COMPLETION_LIST => Some("STATUS_PORT_ALREADY_HAS_COMPLETION_LIST"), - SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_PRIORITY => Some("STATUS_CALLBACK_RETURNED_THREAD_PRIORITY"), - SMB_NTSTATUS_INVALID_THREAD => Some("STATUS_INVALID_THREAD"), - SMB_NTSTATUS_CALLBACK_RETURNED_TRANSACTION => Some("STATUS_CALLBACK_RETURNED_TRANSACTION"), - SMB_NTSTATUS_CALLBACK_RETURNED_LDR_LOCK => Some("STATUS_CALLBACK_RETURNED_LDR_LOCK"), - SMB_NTSTATUS_CALLBACK_RETURNED_LANG => Some("STATUS_CALLBACK_RETURNED_LANG"), - SMB_NTSTATUS_CALLBACK_RETURNED_PRI_BACK => Some("STATUS_CALLBACK_RETURNED_PRI_BACK"), - SMB_NTSTATUS_DISK_REPAIR_DISABLED => Some("STATUS_DISK_REPAIR_DISABLED"), - SMB_NTSTATUS_DS_DOMAIN_RENAME_IN_PROGRESS => Some("STATUS_DS_DOMAIN_RENAME_IN_PROGRESS"), - SMB_NTSTATUS_DISK_QUOTA_EXCEEDED => Some("STATUS_DISK_QUOTA_EXCEEDED"), - SMB_NTSTATUS_CONTENT_BLOCKED => Some("STATUS_CONTENT_BLOCKED"), - SMB_NTSTATUS_BAD_CLUSTERS => Some("STATUS_BAD_CLUSTERS"), - SMB_NTSTATUS_VOLUME_DIRTY => Some("STATUS_VOLUME_DIRTY"), - SMB_NTSTATUS_FILE_CHECKED_OUT => Some("STATUS_FILE_CHECKED_OUT"), - SMB_NTSTATUS_CHECKOUT_REQUIRED => Some("STATUS_CHECKOUT_REQUIRED"), - SMB_NTSTATUS_BAD_FILE_TYPE => Some("STATUS_BAD_FILE_TYPE"), - SMB_NTSTATUS_FILE_TOO_LARGE => Some("STATUS_FILE_TOO_LARGE"), - SMB_NTSTATUS_FORMS_AUTH_REQUIRED => Some("STATUS_FORMS_AUTH_REQUIRED"), - SMB_NTSTATUS_VIRUS_INFECTED => Some("STATUS_VIRUS_INFECTED"), - SMB_NTSTATUS_VIRUS_DELETED => Some("STATUS_VIRUS_DELETED"), - SMB_NTSTATUS_BAD_MCFG_TABLE => Some("STATUS_BAD_MCFG_TABLE"), - SMB_NTSTATUS_CANNOT_BREAK_OPLOCK => Some("STATUS_CANNOT_BREAK_OPLOCK"), - SMB_NTSTATUS_WOW_ASSERTION => Some("STATUS_WOW_ASSERTION"), - SMB_NTSTATUS_INVALID_SIGNATURE => Some("STATUS_INVALID_SIGNATURE"), - SMB_NTSTATUS_HMAC_NOT_SUPPORTED => Some("STATUS_HMAC_NOT_SUPPORTED"), - SMB_NTSTATUS_IPSEC_QUEUE_OVERFLOW => Some("STATUS_IPSEC_QUEUE_OVERFLOW"), - SMB_NTSTATUS_ND_QUEUE_OVERFLOW => Some("STATUS_ND_QUEUE_OVERFLOW"), - SMB_NTSTATUS_HOPLIMIT_EXCEEDED => Some("STATUS_HOPLIMIT_EXCEEDED"), - SMB_NTSTATUS_PROTOCOL_NOT_SUPPORTED => Some("STATUS_PROTOCOL_NOT_SUPPORTED"), - SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED => Some("STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED"), - SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR => Some("STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR"), - SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR => Some("STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR"), - SMB_NTSTATUS_XML_PARSE_ERROR => Some("STATUS_XML_PARSE_ERROR"), - SMB_NTSTATUS_XMLDSIG_ERROR => Some("STATUS_XMLDSIG_ERROR"), - SMB_NTSTATUS_WRONG_COMPARTMENT => Some("STATUS_WRONG_COMPARTMENT"), - SMB_NTSTATUS_AUTHIP_FAILURE => Some("STATUS_AUTHIP_FAILURE"), - SMB_NTSTATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS => Some("STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS"), - SMB_NTSTATUS_DS_OID_NOT_FOUND => Some("STATUS_DS_OID_NOT_FOUND"), - SMB_NTSTATUS_HASH_NOT_SUPPORTED => Some("STATUS_HASH_NOT_SUPPORTED"), - SMB_NTSTATUS_HASH_NOT_PRESENT => Some("STATUS_HASH_NOT_PRESENT"), - SMB_NTSTATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED => Some("STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED"), - SMB_NTSTATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED => Some("STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED"), - SMB_NTSTATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED => Some("STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED"), - SMB_NTSTATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED => Some("STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED"), - SMB_NTDBG_NO_STATE_CHANGE => Some("DBG_NO_STATE_CHANGE"), - SMB_NTDBG_APP_NOT_IDLE => Some("DBG_APP_NOT_IDLE"), - SMB_NTRPC_NT_INVALID_STRING_BINDING => Some("RPC_NT_INVALID_STRING_BINDING"), - SMB_NTRPC_NT_WRONG_KIND_OF_BINDING => Some("RPC_NT_WRONG_KIND_OF_BINDING"), - SMB_NTRPC_NT_INVALID_BINDING => Some("RPC_NT_INVALID_BINDING"), - SMB_NTRPC_NT_PROTSEQ_NOT_SUPPORTED => Some("RPC_NT_PROTSEQ_NOT_SUPPORTED"), - SMB_NTRPC_NT_INVALID_RPC_PROTSEQ => Some("RPC_NT_INVALID_RPC_PROTSEQ"), - SMB_NTRPC_NT_INVALID_STRING_UUID => Some("RPC_NT_INVALID_STRING_UUID"), - SMB_NTRPC_NT_INVALID_ENDPOINT_FORMAT => Some("RPC_NT_INVALID_ENDPOINT_FORMAT"), - SMB_NTRPC_NT_INVALID_NET_ADDR => Some("RPC_NT_INVALID_NET_ADDR"), - SMB_NTRPC_NT_NO_ENDPOINT_FOUND => Some("RPC_NT_NO_ENDPOINT_FOUND"), - SMB_NTRPC_NT_INVALID_TIMEOUT => Some("RPC_NT_INVALID_TIMEOUT"), - SMB_NTRPC_NT_OBJECT_NOT_FOUND => Some("RPC_NT_OBJECT_NOT_FOUND"), - SMB_NTRPC_NT_ALREADY_REGISTERED => Some("RPC_NT_ALREADY_REGISTERED"), - SMB_NTRPC_NT_TYPE_ALREADY_REGISTERED => Some("RPC_NT_TYPE_ALREADY_REGISTERED"), - SMB_NTRPC_NT_ALREADY_LISTENING => Some("RPC_NT_ALREADY_LISTENING"), - SMB_NTRPC_NT_NO_PROTSEQS_REGISTERED => Some("RPC_NT_NO_PROTSEQS_REGISTERED"), - SMB_NTRPC_NT_NOT_LISTENING => Some("RPC_NT_NOT_LISTENING"), - SMB_NTRPC_NT_UNKNOWN_MGR_TYPE => Some("RPC_NT_UNKNOWN_MGR_TYPE"), - SMB_NTRPC_NT_UNKNOWN_IF => Some("RPC_NT_UNKNOWN_IF"), - SMB_NTRPC_NT_NO_BINDINGS => Some("RPC_NT_NO_BINDINGS"), - SMB_NTRPC_NT_NO_PROTSEQS => Some("RPC_NT_NO_PROTSEQS"), - SMB_NTRPC_NT_CANT_CREATE_ENDPOINT => Some("RPC_NT_CANT_CREATE_ENDPOINT"), - SMB_NTRPC_NT_OUT_OF_RESOURCES => Some("RPC_NT_OUT_OF_RESOURCES"), - SMB_NTRPC_NT_SERVER_UNAVAILABLE => Some("RPC_NT_SERVER_UNAVAILABLE"), - SMB_NTRPC_NT_SERVER_TOO_BUSY => Some("RPC_NT_SERVER_TOO_BUSY"), - SMB_NTRPC_NT_INVALID_NETWORK_OPTIONS => Some("RPC_NT_INVALID_NETWORK_OPTIONS"), - SMB_NTRPC_NT_NO_CALL_ACTIVE => Some("RPC_NT_NO_CALL_ACTIVE"), - SMB_NTRPC_NT_CALL_FAILED => Some("RPC_NT_CALL_FAILED"), - SMB_NTRPC_NT_CALL_FAILED_DNE => Some("RPC_NT_CALL_FAILED_DNE"), - SMB_NTRPC_NT_PROTOCOL_ERROR => Some("RPC_NT_PROTOCOL_ERROR"), - SMB_NTRPC_NT_UNSUPPORTED_TRANS_SYN => Some("RPC_NT_UNSUPPORTED_TRANS_SYN"), - SMB_NTRPC_NT_UNSUPPORTED_TYPE => Some("RPC_NT_UNSUPPORTED_TYPE"), - SMB_NTRPC_NT_INVALID_TAG => Some("RPC_NT_INVALID_TAG"), - SMB_NTRPC_NT_INVALID_BOUND => Some("RPC_NT_INVALID_BOUND"), - SMB_NTRPC_NT_NO_ENTRY_NAME => Some("RPC_NT_NO_ENTRY_NAME"), - SMB_NTRPC_NT_INVALID_NAME_SYNTAX => Some("RPC_NT_INVALID_NAME_SYNTAX"), - SMB_NTRPC_NT_UNSUPPORTED_NAME_SYNTAX => Some("RPC_NT_UNSUPPORTED_NAME_SYNTAX"), - SMB_NTRPC_NT_UUID_NO_ADDRESS => Some("RPC_NT_UUID_NO_ADDRESS"), - SMB_NTRPC_NT_DUPLICATE_ENDPOINT => Some("RPC_NT_DUPLICATE_ENDPOINT"), - SMB_NTRPC_NT_UNKNOWN_AUTHN_TYPE => Some("RPC_NT_UNKNOWN_AUTHN_TYPE"), - SMB_NTRPC_NT_MAX_CALLS_TOO_SMALL => Some("RPC_NT_MAX_CALLS_TOO_SMALL"), - SMB_NTRPC_NT_STRING_TOO_LONG => Some("RPC_NT_STRING_TOO_LONG"), - SMB_NTRPC_NT_PROTSEQ_NOT_FOUND => Some("RPC_NT_PROTSEQ_NOT_FOUND"), - SMB_NTRPC_NT_PROCNUM_OUT_OF_RANGE => Some("RPC_NT_PROCNUM_OUT_OF_RANGE"), - SMB_NTRPC_NT_BINDING_HAS_NO_AUTH => Some("RPC_NT_BINDING_HAS_NO_AUTH"), - SMB_NTRPC_NT_UNKNOWN_AUTHN_SERVICE => Some("RPC_NT_UNKNOWN_AUTHN_SERVICE"), - SMB_NTRPC_NT_UNKNOWN_AUTHN_LEVEL => Some("RPC_NT_UNKNOWN_AUTHN_LEVEL"), - SMB_NTRPC_NT_INVALID_AUTH_IDENTITY => Some("RPC_NT_INVALID_AUTH_IDENTITY"), - SMB_NTRPC_NT_UNKNOWN_AUTHZ_SERVICE => Some("RPC_NT_UNKNOWN_AUTHZ_SERVICE"), - SMB_NTEPT_NT_INVALID_ENTRY => Some("EPT_NT_INVALID_ENTRY"), - SMB_NTEPT_NT_CANT_PERFORM_OP => Some("EPT_NT_CANT_PERFORM_OP"), - SMB_NTEPT_NT_NOT_REGISTERED => Some("EPT_NT_NOT_REGISTERED"), - SMB_NTRPC_NT_NOTHING_TO_EXPORT => Some("RPC_NT_NOTHING_TO_EXPORT"), - SMB_NTRPC_NT_INCOMPLETE_NAME => Some("RPC_NT_INCOMPLETE_NAME"), - SMB_NTRPC_NT_INVALID_VERS_OPTION => Some("RPC_NT_INVALID_VERS_OPTION"), - SMB_NTRPC_NT_NO_MORE_MEMBERS => Some("RPC_NT_NO_MORE_MEMBERS"), - SMB_NTRPC_NT_NOT_ALL_OBJS_UNEXPORTED => Some("RPC_NT_NOT_ALL_OBJS_UNEXPORTED"), - SMB_NTRPC_NT_INTERFACE_NOT_FOUND => Some("RPC_NT_INTERFACE_NOT_FOUND"), - SMB_NTRPC_NT_ENTRY_ALREADY_EXISTS => Some("RPC_NT_ENTRY_ALREADY_EXISTS"), - SMB_NTRPC_NT_ENTRY_NOT_FOUND => Some("RPC_NT_ENTRY_NOT_FOUND"), - SMB_NTRPC_NT_NAME_SERVICE_UNAVAILABLE => Some("RPC_NT_NAME_SERVICE_UNAVAILABLE"), - SMB_NTRPC_NT_INVALID_NAF_ID => Some("RPC_NT_INVALID_NAF_ID"), - SMB_NTRPC_NT_CANNOT_SUPPORT => Some("RPC_NT_CANNOT_SUPPORT"), - SMB_NTRPC_NT_NO_CONTEXT_AVAILABLE => Some("RPC_NT_NO_CONTEXT_AVAILABLE"), - SMB_NTRPC_NT_INTERNAL_ERROR => Some("RPC_NT_INTERNAL_ERROR"), - SMB_NTRPC_NT_ZERO_DIVIDE => Some("RPC_NT_ZERO_DIVIDE"), - SMB_NTRPC_NT_ADDRESS_ERROR => Some("RPC_NT_ADDRESS_ERROR"), - SMB_NTRPC_NT_FP_DIV_ZERO => Some("RPC_NT_FP_DIV_ZERO"), - SMB_NTRPC_NT_FP_UNDERFLOW => Some("RPC_NT_FP_UNDERFLOW"), - SMB_NTRPC_NT_FP_OVERFLOW => Some("RPC_NT_FP_OVERFLOW"), - SMB_NTRPC_NT_CALL_IN_PROGRESS => Some("RPC_NT_CALL_IN_PROGRESS"), - SMB_NTRPC_NT_NO_MORE_BINDINGS => Some("RPC_NT_NO_MORE_BINDINGS"), - SMB_NTRPC_NT_GROUP_MEMBER_NOT_FOUND => Some("RPC_NT_GROUP_MEMBER_NOT_FOUND"), - SMB_NTEPT_NT_CANT_CREATE => Some("EPT_NT_CANT_CREATE"), - SMB_NTRPC_NT_INVALID_OBJECT => Some("RPC_NT_INVALID_OBJECT"), - SMB_NTRPC_NT_NO_INTERFACES => Some("RPC_NT_NO_INTERFACES"), - SMB_NTRPC_NT_CALL_CANCELLED => Some("RPC_NT_CALL_CANCELLED"), - SMB_NTRPC_NT_BINDING_INCOMPLETE => Some("RPC_NT_BINDING_INCOMPLETE"), - SMB_NTRPC_NT_COMM_FAILURE => Some("RPC_NT_COMM_FAILURE"), - SMB_NTRPC_NT_UNSUPPORTED_AUTHN_LEVEL => Some("RPC_NT_UNSUPPORTED_AUTHN_LEVEL"), - SMB_NTRPC_NT_NO_PRINC_NAME => Some("RPC_NT_NO_PRINC_NAME"), - SMB_NTRPC_NT_NOT_RPC_ERROR => Some("RPC_NT_NOT_RPC_ERROR"), - SMB_NTRPC_NT_SEC_PKG_ERROR => Some("RPC_NT_SEC_PKG_ERROR"), - SMB_NTRPC_NT_NOT_CANCELLED => Some("RPC_NT_NOT_CANCELLED"), - SMB_NTRPC_NT_INVALID_ASYNC_HANDLE => Some("RPC_NT_INVALID_ASYNC_HANDLE"), - SMB_NTRPC_NT_INVALID_ASYNC_CALL => Some("RPC_NT_INVALID_ASYNC_CALL"), - SMB_NTRPC_NT_PROXY_ACCESS_DENIED => Some("RPC_NT_PROXY_ACCESS_DENIED"), - SMB_NTRPC_NT_NO_MORE_ENTRIES => Some("RPC_NT_NO_MORE_ENTRIES"), - SMB_NTRPC_NT_SS_CHAR_TRANS_OPEN_FAIL => Some("RPC_NT_SS_CHAR_TRANS_OPEN_FAIL"), - SMB_NTRPC_NT_SS_CHAR_TRANS_SHORT_FILE => Some("RPC_NT_SS_CHAR_TRANS_SHORT_FILE"), - SMB_NTRPC_NT_SS_IN_NULL_CONTEXT => Some("RPC_NT_SS_IN_NULL_CONTEXT"), - SMB_NTRPC_NT_SS_CONTEXT_MISMATCH => Some("RPC_NT_SS_CONTEXT_MISMATCH"), - SMB_NTRPC_NT_SS_CONTEXT_DAMAGED => Some("RPC_NT_SS_CONTEXT_DAMAGED"), - SMB_NTRPC_NT_SS_HANDLES_MISMATCH => Some("RPC_NT_SS_HANDLES_MISMATCH"), - SMB_NTRPC_NT_SS_CANNOT_GET_CALL_HANDLE => Some("RPC_NT_SS_CANNOT_GET_CALL_HANDLE"), - SMB_NTRPC_NT_NULL_REF_POINTER => Some("RPC_NT_NULL_REF_POINTER"), - SMB_NTRPC_NT_ENUM_VALUE_OUT_OF_RANGE => Some("RPC_NT_ENUM_VALUE_OUT_OF_RANGE"), - SMB_NTRPC_NT_BYTE_COUNT_TOO_SMALL => Some("RPC_NT_BYTE_COUNT_TOO_SMALL"), - SMB_NTRPC_NT_BAD_STUB_DATA => Some("RPC_NT_BAD_STUB_DATA"), - SMB_NTRPC_NT_INVALID_ES_ACTION => Some("RPC_NT_INVALID_ES_ACTION"), - SMB_NTRPC_NT_WRONG_ES_VERSION => Some("RPC_NT_WRONG_ES_VERSION"), - SMB_NTRPC_NT_WRONG_STUB_VERSION => Some("RPC_NT_WRONG_STUB_VERSION"), - SMB_NTRPC_NT_INVALID_PIPE_OBJECT => Some("RPC_NT_INVALID_PIPE_OBJECT"), - SMB_NTRPC_NT_INVALID_PIPE_OPERATION => Some("RPC_NT_INVALID_PIPE_OPERATION"), - SMB_NTRPC_NT_WRONG_PIPE_VERSION => Some("RPC_NT_WRONG_PIPE_VERSION"), - SMB_NTRPC_NT_PIPE_CLOSED => Some("RPC_NT_PIPE_CLOSED"), - SMB_NTRPC_NT_PIPE_DISCIPLINE_ERROR => Some("RPC_NT_PIPE_DISCIPLINE_ERROR"), - SMB_NTRPC_NT_PIPE_EMPTY => Some("RPC_NT_PIPE_EMPTY"), - SMB_NTSTATUS_PNP_BAD_MPS_TABLE => Some("STATUS_PNP_BAD_MPS_TABLE"), - SMB_NTSTATUS_PNP_TRANSLATION_FAILED => Some("STATUS_PNP_TRANSLATION_FAILED"), - SMB_NTSTATUS_PNP_IRQ_TRANSLATION_FAILED => Some("STATUS_PNP_IRQ_TRANSLATION_FAILED"), - SMB_NTSTATUS_PNP_INVALID_ID => Some("STATUS_PNP_INVALID_ID"), - SMB_NTSTATUS_IO_REISSUE_AS_CACHED => Some("STATUS_IO_REISSUE_AS_CACHED"), - SMB_NTSTATUS_CTX_WINSTATION_NAME_INVALID => Some("STATUS_CTX_WINSTATION_NAME_INVALID"), - SMB_NTSTATUS_CTX_INVALID_PD => Some("STATUS_CTX_INVALID_PD"), - SMB_NTSTATUS_CTX_PD_NOT_FOUND => Some("STATUS_CTX_PD_NOT_FOUND"), - SMB_NTSTATUS_CTX_CLOSE_PENDING => Some("STATUS_CTX_CLOSE_PENDING"), - SMB_NTSTATUS_CTX_NO_OUTBUF => Some("STATUS_CTX_NO_OUTBUF"), - SMB_NTSTATUS_CTX_MODEM_INF_NOT_FOUND => Some("STATUS_CTX_MODEM_INF_NOT_FOUND"), - SMB_NTSTATUS_CTX_INVALID_MODEMNAME => Some("STATUS_CTX_INVALID_MODEMNAME"), - SMB_NTSTATUS_CTX_RESPONSE_ERROR => Some("STATUS_CTX_RESPONSE_ERROR"), - SMB_NTSTATUS_CTX_MODEM_RESPONSE_TIMEOUT => Some("STATUS_CTX_MODEM_RESPONSE_TIMEOUT"), - SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_CARRIER => Some("STATUS_CTX_MODEM_RESPONSE_NO_CARRIER"), - SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_DIALTONE => Some("STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE"), - SMB_NTSTATUS_CTX_MODEM_RESPONSE_BUSY => Some("STATUS_CTX_MODEM_RESPONSE_BUSY"), - SMB_NTSTATUS_CTX_MODEM_RESPONSE_VOICE => Some("STATUS_CTX_MODEM_RESPONSE_VOICE"), - SMB_NTSTATUS_CTX_TD_ERROR => Some("STATUS_CTX_TD_ERROR"), - SMB_NTSTATUS_CTX_LICENSE_CLIENT_INVALID => Some("STATUS_CTX_LICENSE_CLIENT_INVALID"), - SMB_NTSTATUS_CTX_LICENSE_NOT_AVAILABLE => Some("STATUS_CTX_LICENSE_NOT_AVAILABLE"), - SMB_NTSTATUS_CTX_LICENSE_EXPIRED => Some("STATUS_CTX_LICENSE_EXPIRED"), - SMB_NTSTATUS_CTX_WINSTATION_NOT_FOUND => Some("STATUS_CTX_WINSTATION_NOT_FOUND"), - SMB_NTSTATUS_CTX_WINSTATION_NAME_COLLISION => Some("STATUS_CTX_WINSTATION_NAME_COLLISION"), - SMB_NTSTATUS_CTX_WINSTATION_BUSY => Some("STATUS_CTX_WINSTATION_BUSY"), - SMB_NTSTATUS_CTX_BAD_VIDEO_MODE => Some("STATUS_CTX_BAD_VIDEO_MODE"), - SMB_NTSTATUS_CTX_GRAPHICS_INVALID => Some("STATUS_CTX_GRAPHICS_INVALID"), - SMB_NTSTATUS_CTX_NOT_CONSOLE => Some("STATUS_CTX_NOT_CONSOLE"), - SMB_NTSTATUS_CTX_CLIENT_QUERY_TIMEOUT => Some("STATUS_CTX_CLIENT_QUERY_TIMEOUT"), - SMB_NTSTATUS_CTX_CONSOLE_DISCONNECT => Some("STATUS_CTX_CONSOLE_DISCONNECT"), - SMB_NTSTATUS_CTX_CONSOLE_CONNECT => Some("STATUS_CTX_CONSOLE_CONNECT"), - SMB_NTSTATUS_CTX_SHADOW_DENIED => Some("STATUS_CTX_SHADOW_DENIED"), - SMB_NTSTATUS_CTX_WINSTATION_ACCESS_DENIED => Some("STATUS_CTX_WINSTATION_ACCESS_DENIED"), - SMB_NTSTATUS_CTX_INVALID_WD => Some("STATUS_CTX_INVALID_WD"), - SMB_NTSTATUS_CTX_WD_NOT_FOUND => Some("STATUS_CTX_WD_NOT_FOUND"), - SMB_NTSTATUS_CTX_SHADOW_INVALID => Some("STATUS_CTX_SHADOW_INVALID"), - SMB_NTSTATUS_CTX_SHADOW_DISABLED => Some("STATUS_CTX_SHADOW_DISABLED"), - SMB_NTSTATUS_RDP_PROTOCOL_ERROR => Some("STATUS_RDP_PROTOCOL_ERROR"), - SMB_NTSTATUS_CTX_CLIENT_LICENSE_NOT_SET => Some("STATUS_CTX_CLIENT_LICENSE_NOT_SET"), - SMB_NTSTATUS_CTX_CLIENT_LICENSE_IN_USE => Some("STATUS_CTX_CLIENT_LICENSE_IN_USE"), - SMB_NTSTATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE => Some("STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE"), - SMB_NTSTATUS_CTX_SHADOW_NOT_RUNNING => Some("STATUS_CTX_SHADOW_NOT_RUNNING"), - SMB_NTSTATUS_CTX_LOGON_DISABLED => Some("STATUS_CTX_LOGON_DISABLED"), - SMB_NTSTATUS_CTX_SECURITY_LAYER_ERROR => Some("STATUS_CTX_SECURITY_LAYER_ERROR"), - SMB_NTSTATUS_TS_INCOMPATIBLE_SESSIONS => Some("STATUS_TS_INCOMPATIBLE_SESSIONS"), - SMB_NTSTATUS_MUI_FILE_NOT_FOUND => Some("STATUS_MUI_FILE_NOT_FOUND"), - SMB_NTSTATUS_MUI_INVALID_FILE => Some("STATUS_MUI_INVALID_FILE"), - SMB_NTSTATUS_MUI_INVALID_RC_CONFIG => Some("STATUS_MUI_INVALID_RC_CONFIG"), - SMB_NTSTATUS_MUI_INVALID_LOCALE_NAME => Some("STATUS_MUI_INVALID_LOCALE_NAME"), - SMB_NTSTATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME => Some("STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME"), - SMB_NTSTATUS_MUI_FILE_NOT_LOADED => Some("STATUS_MUI_FILE_NOT_LOADED"), - SMB_NTSTATUS_RESOURCE_ENUM_USER_STOP => Some("STATUS_RESOURCE_ENUM_USER_STOP"), - SMB_NTSTATUS_CLUSTER_INVALID_NODE => Some("STATUS_CLUSTER_INVALID_NODE"), - SMB_NTSTATUS_CLUSTER_NODE_EXISTS => Some("STATUS_CLUSTER_NODE_EXISTS"), - SMB_NTSTATUS_CLUSTER_JOIN_IN_PROGRESS => Some("STATUS_CLUSTER_JOIN_IN_PROGRESS"), - SMB_NTSTATUS_CLUSTER_NODE_NOT_FOUND => Some("STATUS_CLUSTER_NODE_NOT_FOUND"), - SMB_NTSTATUS_CLUSTER_LOCAL_NODE_NOT_FOUND => Some("STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND"), - SMB_NTSTATUS_CLUSTER_NETWORK_EXISTS => Some("STATUS_CLUSTER_NETWORK_EXISTS"), - SMB_NTSTATUS_CLUSTER_NETWORK_NOT_FOUND => Some("STATUS_CLUSTER_NETWORK_NOT_FOUND"), - SMB_NTSTATUS_CLUSTER_NETINTERFACE_EXISTS => Some("STATUS_CLUSTER_NETINTERFACE_EXISTS"), - SMB_NTSTATUS_CLUSTER_NETINTERFACE_NOT_FOUND => Some("STATUS_CLUSTER_NETINTERFACE_NOT_FOUND"), - SMB_NTSTATUS_CLUSTER_INVALID_REQUEST => Some("STATUS_CLUSTER_INVALID_REQUEST"), - SMB_NTSTATUS_CLUSTER_INVALID_NETWORK_PROVIDER => Some("STATUS_CLUSTER_INVALID_NETWORK_PROVIDER"), - SMB_NTSTATUS_CLUSTER_NODE_DOWN => Some("STATUS_CLUSTER_NODE_DOWN"), - SMB_NTSTATUS_CLUSTER_NODE_UNREACHABLE => Some("STATUS_CLUSTER_NODE_UNREACHABLE"), - SMB_NTSTATUS_CLUSTER_NODE_NOT_MEMBER => Some("STATUS_CLUSTER_NODE_NOT_MEMBER"), - SMB_NTSTATUS_CLUSTER_JOIN_NOT_IN_PROGRESS => Some("STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS"), - SMB_NTSTATUS_CLUSTER_INVALID_NETWORK => Some("STATUS_CLUSTER_INVALID_NETWORK"), - SMB_NTSTATUS_CLUSTER_NO_NET_ADAPTERS => Some("STATUS_CLUSTER_NO_NET_ADAPTERS"), - SMB_NTSTATUS_CLUSTER_NODE_UP => Some("STATUS_CLUSTER_NODE_UP"), - SMB_NTSTATUS_CLUSTER_NODE_PAUSED => Some("STATUS_CLUSTER_NODE_PAUSED"), - SMB_NTSTATUS_CLUSTER_NODE_NOT_PAUSED => Some("STATUS_CLUSTER_NODE_NOT_PAUSED"), - SMB_NTSTATUS_CLUSTER_NO_SECURITY_CONTEXT => Some("STATUS_CLUSTER_NO_SECURITY_CONTEXT"), - SMB_NTSTATUS_CLUSTER_NETWORK_NOT_INTERNAL => Some("STATUS_CLUSTER_NETWORK_NOT_INTERNAL"), - SMB_NTSTATUS_CLUSTER_POISONED => Some("STATUS_CLUSTER_POISONED"), - SMB_NTSTATUS_ACPI_INVALID_OPCODE => Some("STATUS_ACPI_INVALID_OPCODE"), - SMB_NTSTATUS_ACPI_STACK_OVERFLOW => Some("STATUS_ACPI_STACK_OVERFLOW"), - SMB_NTSTATUS_ACPI_ASSERT_FAILED => Some("STATUS_ACPI_ASSERT_FAILED"), - SMB_NTSTATUS_ACPI_INVALID_INDEX => Some("STATUS_ACPI_INVALID_INDEX"), - SMB_NTSTATUS_ACPI_INVALID_ARGUMENT => Some("STATUS_ACPI_INVALID_ARGUMENT"), - SMB_NTSTATUS_ACPI_FATAL => Some("STATUS_ACPI_FATAL"), - SMB_NTSTATUS_ACPI_INVALID_SUPERNAME => Some("STATUS_ACPI_INVALID_SUPERNAME"), - SMB_NTSTATUS_ACPI_INVALID_ARGTYPE => Some("STATUS_ACPI_INVALID_ARGTYPE"), - SMB_NTSTATUS_ACPI_INVALID_OBJTYPE => Some("STATUS_ACPI_INVALID_OBJTYPE"), - SMB_NTSTATUS_ACPI_INVALID_TARGETTYPE => Some("STATUS_ACPI_INVALID_TARGETTYPE"), - SMB_NTSTATUS_ACPI_INCORRECT_ARGUMENT_COUNT => Some("STATUS_ACPI_INCORRECT_ARGUMENT_COUNT"), - SMB_NTSTATUS_ACPI_ADDRESS_NOT_MAPPED => Some("STATUS_ACPI_ADDRESS_NOT_MAPPED"), - SMB_NTSTATUS_ACPI_INVALID_EVENTTYPE => Some("STATUS_ACPI_INVALID_EVENTTYPE"), - SMB_NTSTATUS_ACPI_HANDLER_COLLISION => Some("STATUS_ACPI_HANDLER_COLLISION"), - SMB_NTSTATUS_ACPI_INVALID_DATA => Some("STATUS_ACPI_INVALID_DATA"), - SMB_NTSTATUS_ACPI_INVALID_REGION => Some("STATUS_ACPI_INVALID_REGION"), - SMB_NTSTATUS_ACPI_INVALID_ACCESS_SIZE => Some("STATUS_ACPI_INVALID_ACCESS_SIZE"), - SMB_NTSTATUS_ACPI_ACQUIRE_GLOBAL_LOCK => Some("STATUS_ACPI_ACQUIRE_GLOBAL_LOCK"), - SMB_NTSTATUS_ACPI_ALREADY_INITIALIZED => Some("STATUS_ACPI_ALREADY_INITIALIZED"), - SMB_NTSTATUS_ACPI_NOT_INITIALIZED => Some("STATUS_ACPI_NOT_INITIALIZED"), - SMB_NTSTATUS_ACPI_INVALID_MUTEX_LEVEL => Some("STATUS_ACPI_INVALID_MUTEX_LEVEL"), - SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNED => Some("STATUS_ACPI_MUTEX_NOT_OWNED"), - SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNER => Some("STATUS_ACPI_MUTEX_NOT_OWNER"), - SMB_NTSTATUS_ACPI_RS_ACCESS => Some("STATUS_ACPI_RS_ACCESS"), - SMB_NTSTATUS_ACPI_INVALID_TABLE => Some("STATUS_ACPI_INVALID_TABLE"), - SMB_NTSTATUS_ACPI_REG_HANDLER_FAILED => Some("STATUS_ACPI_REG_HANDLER_FAILED"), - SMB_NTSTATUS_ACPI_POWER_REQUEST_FAILED => Some("STATUS_ACPI_POWER_REQUEST_FAILED"), - SMB_NTSTATUS_SXS_SECTION_NOT_FOUND => Some("STATUS_SXS_SECTION_NOT_FOUND"), - SMB_NTSTATUS_SXS_CANT_GEN_ACTCTX => Some("STATUS_SXS_CANT_GEN_ACTCTX"), - SMB_NTSTATUS_SXS_INVALID_ACTCTXDATA_FORMAT => Some("STATUS_SXS_INVALID_ACTCTXDATA_FORMAT"), - SMB_NTSTATUS_SXS_ASSEMBLY_NOT_FOUND => Some("STATUS_SXS_ASSEMBLY_NOT_FOUND"), - SMB_NTSTATUS_SXS_MANIFEST_FORMAT_ERROR => Some("STATUS_SXS_MANIFEST_FORMAT_ERROR"), - SMB_NTSTATUS_SXS_MANIFEST_PARSE_ERROR => Some("STATUS_SXS_MANIFEST_PARSE_ERROR"), - SMB_NTSTATUS_SXS_ACTIVATION_CONTEXT_DISABLED => Some("STATUS_SXS_ACTIVATION_CONTEXT_DISABLED"), - SMB_NTSTATUS_SXS_KEY_NOT_FOUND => Some("STATUS_SXS_KEY_NOT_FOUND"), - SMB_NTSTATUS_SXS_VERSION_CONFLICT => Some("STATUS_SXS_VERSION_CONFLICT"), - SMB_NTSTATUS_SXS_WRONG_SECTION_TYPE => Some("STATUS_SXS_WRONG_SECTION_TYPE"), - SMB_NTSTATUS_SXS_THREAD_QUERIES_DISABLED => Some("STATUS_SXS_THREAD_QUERIES_DISABLED"), - SMB_NTSTATUS_SXS_ASSEMBLY_MISSING => Some("STATUS_SXS_ASSEMBLY_MISSING"), - SMB_NTSTATUS_SXS_PROCESS_DEFAULT_ALREADY_SET => Some("STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET"), - SMB_NTSTATUS_SXS_EARLY_DEACTIVATION => Some("STATUS_SXS_EARLY_DEACTIVATION"), - SMB_NTSTATUS_SXS_INVALID_DEACTIVATION => Some("STATUS_SXS_INVALID_DEACTIVATION"), - SMB_NTSTATUS_SXS_MULTIPLE_DEACTIVATION => Some("STATUS_SXS_MULTIPLE_DEACTIVATION"), - SMB_NTSTATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY => Some("STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY"), - SMB_NTSTATUS_SXS_PROCESS_TERMINATION_REQUESTED => Some("STATUS_SXS_PROCESS_TERMINATION_REQUESTED"), - SMB_NTSTATUS_SXS_CORRUPT_ACTIVATION_STACK => Some("STATUS_SXS_CORRUPT_ACTIVATION_STACK"), - SMB_NTSTATUS_SXS_CORRUPTION => Some("STATUS_SXS_CORRUPTION"), - SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE => Some("STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE"), - SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME => Some("STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME"), - SMB_NTSTATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE => Some("STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE"), - SMB_NTSTATUS_SXS_IDENTITY_PARSE_ERROR => Some("STATUS_SXS_IDENTITY_PARSE_ERROR"), - SMB_NTSTATUS_SXS_COMPONENT_STORE_CORRUPT => Some("STATUS_SXS_COMPONENT_STORE_CORRUPT"), - SMB_NTSTATUS_SXS_FILE_HASH_MISMATCH => Some("STATUS_SXS_FILE_HASH_MISMATCH"), - SMB_NTSTATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT => Some("STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT"), - SMB_NTSTATUS_SXS_IDENTITIES_DIFFERENT => Some("STATUS_SXS_IDENTITIES_DIFFERENT"), - SMB_NTSTATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT => Some("STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT"), - SMB_NTSTATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY => Some("STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY"), - SMB_NTSTATUS_ADVANCED_INSTALLER_FAILED => Some("STATUS_ADVANCED_INSTALLER_FAILED"), - SMB_NTSTATUS_XML_ENCODING_MISMATCH => Some("STATUS_XML_ENCODING_MISMATCH"), - SMB_NTSTATUS_SXS_MANIFEST_TOO_BIG => Some("STATUS_SXS_MANIFEST_TOO_BIG"), - SMB_NTSTATUS_SXS_SETTING_NOT_REGISTERED => Some("STATUS_SXS_SETTING_NOT_REGISTERED"), - SMB_NTSTATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE => Some("STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE"), - SMB_NTSTATUS_SMI_PRIMITIVE_INSTALLER_FAILED => Some("STATUS_SMI_PRIMITIVE_INSTALLER_FAILED"), - SMB_NTSTATUS_GENERIC_COMMAND_FAILED => Some("STATUS_GENERIC_COMMAND_FAILED"), - SMB_NTSTATUS_SXS_FILE_HASH_MISSING => Some("STATUS_SXS_FILE_HASH_MISSING"), - SMB_NTSTATUS_TRANSACTIONAL_CONFLICT => Some("STATUS_TRANSACTIONAL_CONFLICT"), - SMB_NTSTATUS_INVALID_TRANSACTION => Some("STATUS_INVALID_TRANSACTION"), - SMB_NTSTATUS_TRANSACTION_NOT_ACTIVE => Some("STATUS_TRANSACTION_NOT_ACTIVE"), - SMB_NTSTATUS_TM_INITIALIZATION_FAILED => Some("STATUS_TM_INITIALIZATION_FAILED"), - SMB_NTSTATUS_RM_NOT_ACTIVE => Some("STATUS_RM_NOT_ACTIVE"), - SMB_NTSTATUS_RM_METADATA_CORRUPT => Some("STATUS_RM_METADATA_CORRUPT"), - SMB_NTSTATUS_TRANSACTION_NOT_JOINED => Some("STATUS_TRANSACTION_NOT_JOINED"), - SMB_NTSTATUS_DIRECTORY_NOT_RM => Some("STATUS_DIRECTORY_NOT_RM"), - SMB_NTSTATUS_TRANSACTIONS_UNSUPPORTED_REMOTE => Some("STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE"), - SMB_NTSTATUS_LOG_RESIZE_INVALID_SIZE => Some("STATUS_LOG_RESIZE_INVALID_SIZE"), - SMB_NTSTATUS_REMOTE_FILE_VERSION_MISMATCH => Some("STATUS_REMOTE_FILE_VERSION_MISMATCH"), - SMB_NTSTATUS_CRM_PROTOCOL_ALREADY_EXISTS => Some("STATUS_CRM_PROTOCOL_ALREADY_EXISTS"), - SMB_NTSTATUS_TRANSACTION_PROPAGATION_FAILED => Some("STATUS_TRANSACTION_PROPAGATION_FAILED"), - SMB_NTSTATUS_CRM_PROTOCOL_NOT_FOUND => Some("STATUS_CRM_PROTOCOL_NOT_FOUND"), - SMB_NTSTATUS_TRANSACTION_SUPERIOR_EXISTS => Some("STATUS_TRANSACTION_SUPERIOR_EXISTS"), - SMB_NTSTATUS_TRANSACTION_REQUEST_NOT_VALID => Some("STATUS_TRANSACTION_REQUEST_NOT_VALID"), - SMB_NTSTATUS_TRANSACTION_NOT_REQUESTED => Some("STATUS_TRANSACTION_NOT_REQUESTED"), - SMB_NTSTATUS_TRANSACTION_ALREADY_ABORTED => Some("STATUS_TRANSACTION_ALREADY_ABORTED"), - SMB_NTSTATUS_TRANSACTION_ALREADY_COMMITTED => Some("STATUS_TRANSACTION_ALREADY_COMMITTED"), - SMB_NTSTATUS_TRANSACTION_INVALID_MARSHALL_BUFFER => Some("STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER"), - SMB_NTSTATUS_CURRENT_TRANSACTION_NOT_VALID => Some("STATUS_CURRENT_TRANSACTION_NOT_VALID"), - SMB_NTSTATUS_LOG_GROWTH_FAILED => Some("STATUS_LOG_GROWTH_FAILED"), - SMB_NTSTATUS_OBJECT_NO_LONGER_EXISTS => Some("STATUS_OBJECT_NO_LONGER_EXISTS"), - SMB_NTSTATUS_STREAM_MINIVERSION_NOT_FOUND => Some("STATUS_STREAM_MINIVERSION_NOT_FOUND"), - SMB_NTSTATUS_STREAM_MINIVERSION_NOT_VALID => Some("STATUS_STREAM_MINIVERSION_NOT_VALID"), - SMB_NTSTATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION => Some("STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION"), - SMB_NTSTATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT => Some("STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT"), - SMB_NTSTATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS => Some("STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS"), - SMB_NTSTATUS_HANDLE_NO_LONGER_VALID => Some("STATUS_HANDLE_NO_LONGER_VALID"), - SMB_NTSTATUS_LOG_CORRUPTION_DETECTED => Some("STATUS_LOG_CORRUPTION_DETECTED"), - SMB_NTSTATUS_RM_DISCONNECTED => Some("STATUS_RM_DISCONNECTED"), - SMB_NTSTATUS_ENLISTMENT_NOT_SUPERIOR => Some("STATUS_ENLISTMENT_NOT_SUPERIOR"), - SMB_NTSTATUS_FILE_IDENTITY_NOT_PERSISTENT => Some("STATUS_FILE_IDENTITY_NOT_PERSISTENT"), - SMB_NTSTATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY => Some("STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY"), - SMB_NTSTATUS_CANT_CROSS_RM_BOUNDARY => Some("STATUS_CANT_CROSS_RM_BOUNDARY"), - SMB_NTSTATUS_TXF_DIR_NOT_EMPTY => Some("STATUS_TXF_DIR_NOT_EMPTY"), - SMB_NTSTATUS_INDOUBT_TRANSACTIONS_EXIST => Some("STATUS_INDOUBT_TRANSACTIONS_EXIST"), - SMB_NTSTATUS_TM_VOLATILE => Some("STATUS_TM_VOLATILE"), - SMB_NTSTATUS_ROLLBACK_TIMER_EXPIRED => Some("STATUS_ROLLBACK_TIMER_EXPIRED"), - SMB_NTSTATUS_TXF_ATTRIBUTE_CORRUPT => Some("STATUS_TXF_ATTRIBUTE_CORRUPT"), - SMB_NTSTATUS_EFS_NOT_ALLOWED_IN_TRANSACTION => Some("STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION"), - SMB_NTSTATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED => Some("STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED"), - SMB_NTSTATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE => Some("STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE"), - SMB_NTSTATUS_TRANSACTION_REQUIRED_PROMOTION => Some("STATUS_TRANSACTION_REQUIRED_PROMOTION"), - SMB_NTSTATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION => Some("STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION"), - SMB_NTSTATUS_TRANSACTIONS_NOT_FROZEN => Some("STATUS_TRANSACTIONS_NOT_FROZEN"), - SMB_NTSTATUS_TRANSACTION_FREEZE_IN_PROGRESS => Some("STATUS_TRANSACTION_FREEZE_IN_PROGRESS"), - SMB_NTSTATUS_NOT_SNAPSHOT_VOLUME => Some("STATUS_NOT_SNAPSHOT_VOLUME"), - SMB_NTSTATUS_NO_SAVEPOINT_WITH_OPEN_FILES => Some("STATUS_NO_SAVEPOINT_WITH_OPEN_FILES"), - SMB_NTSTATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION => Some("STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION"), - SMB_NTSTATUS_TM_IDENTITY_MISMATCH => Some("STATUS_TM_IDENTITY_MISMATCH"), - SMB_NTSTATUS_FLOATED_SECTION => Some("STATUS_FLOATED_SECTION"), - SMB_NTSTATUS_CANNOT_ACCEPT_TRANSACTED_WORK => Some("STATUS_CANNOT_ACCEPT_TRANSACTED_WORK"), - SMB_NTSTATUS_CANNOT_ABORT_TRANSACTIONS => Some("STATUS_CANNOT_ABORT_TRANSACTIONS"), - SMB_NTSTATUS_TRANSACTION_NOT_FOUND => Some("STATUS_TRANSACTION_NOT_FOUND"), - SMB_NTSTATUS_RESOURCEMANAGER_NOT_FOUND => Some("STATUS_RESOURCEMANAGER_NOT_FOUND"), - SMB_NTSTATUS_ENLISTMENT_NOT_FOUND => Some("STATUS_ENLISTMENT_NOT_FOUND"), - SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_FOUND => Some("STATUS_TRANSACTIONMANAGER_NOT_FOUND"), - SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_ONLINE => Some("STATUS_TRANSACTIONMANAGER_NOT_ONLINE"), - SMB_NTSTATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION => Some("STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION"), - SMB_NTSTATUS_TRANSACTION_NOT_ROOT => Some("STATUS_TRANSACTION_NOT_ROOT"), - SMB_NTSTATUS_TRANSACTION_OBJECT_EXPIRED => Some("STATUS_TRANSACTION_OBJECT_EXPIRED"), - SMB_NTSTATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION => Some("STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION"), - SMB_NTSTATUS_TRANSACTION_RESPONSE_NOT_ENLISTED => Some("STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED"), - SMB_NTSTATUS_TRANSACTION_RECORD_TOO_LONG => Some("STATUS_TRANSACTION_RECORD_TOO_LONG"), - SMB_NTSTATUS_NO_LINK_TRACKING_IN_TRANSACTION => Some("STATUS_NO_LINK_TRACKING_IN_TRANSACTION"), - SMB_NTSTATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION => Some("STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION"), - SMB_NTSTATUS_TRANSACTION_INTEGRITY_VIOLATED => Some("STATUS_TRANSACTION_INTEGRITY_VIOLATED"), - SMB_NTSTATUS_EXPIRED_HANDLE => Some("STATUS_EXPIRED_HANDLE"), - SMB_NTSTATUS_TRANSACTION_NOT_ENLISTED => Some("STATUS_TRANSACTION_NOT_ENLISTED"), - SMB_NTSTATUS_LOG_SECTOR_INVALID => Some("STATUS_LOG_SECTOR_INVALID"), - SMB_NTSTATUS_LOG_SECTOR_PARITY_INVALID => Some("STATUS_LOG_SECTOR_PARITY_INVALID"), - SMB_NTSTATUS_LOG_SECTOR_REMAPPED => Some("STATUS_LOG_SECTOR_REMAPPED"), - SMB_NTSTATUS_LOG_BLOCK_INCOMPLETE => Some("STATUS_LOG_BLOCK_INCOMPLETE"), - SMB_NTSTATUS_LOG_INVALID_RANGE => Some("STATUS_LOG_INVALID_RANGE"), - SMB_NTSTATUS_LOG_BLOCKS_EXHAUSTED => Some("STATUS_LOG_BLOCKS_EXHAUSTED"), - SMB_NTSTATUS_LOG_READ_CONTEXT_INVALID => Some("STATUS_LOG_READ_CONTEXT_INVALID"), - SMB_NTSTATUS_LOG_RESTART_INVALID => Some("STATUS_LOG_RESTART_INVALID"), - SMB_NTSTATUS_LOG_BLOCK_VERSION => Some("STATUS_LOG_BLOCK_VERSION"), - SMB_NTSTATUS_LOG_BLOCK_INVALID => Some("STATUS_LOG_BLOCK_INVALID"), - SMB_NTSTATUS_LOG_READ_MODE_INVALID => Some("STATUS_LOG_READ_MODE_INVALID"), - SMB_NTSTATUS_LOG_METADATA_CORRUPT => Some("STATUS_LOG_METADATA_CORRUPT"), - SMB_NTSTATUS_LOG_METADATA_INVALID => Some("STATUS_LOG_METADATA_INVALID"), - SMB_NTSTATUS_LOG_METADATA_INCONSISTENT => Some("STATUS_LOG_METADATA_INCONSISTENT"), - SMB_NTSTATUS_LOG_RESERVATION_INVALID => Some("STATUS_LOG_RESERVATION_INVALID"), - SMB_NTSTATUS_LOG_CANT_DELETE => Some("STATUS_LOG_CANT_DELETE"), - SMB_NTSTATUS_LOG_CONTAINER_LIMIT_EXCEEDED => Some("STATUS_LOG_CONTAINER_LIMIT_EXCEEDED"), - SMB_NTSTATUS_LOG_START_OF_LOG => Some("STATUS_LOG_START_OF_LOG"), - SMB_NTSTATUS_LOG_POLICY_ALREADY_INSTALLED => Some("STATUS_LOG_POLICY_ALREADY_INSTALLED"), - SMB_NTSTATUS_LOG_POLICY_NOT_INSTALLED => Some("STATUS_LOG_POLICY_NOT_INSTALLED"), - SMB_NTSTATUS_LOG_POLICY_INVALID => Some("STATUS_LOG_POLICY_INVALID"), - SMB_NTSTATUS_LOG_POLICY_CONFLICT => Some("STATUS_LOG_POLICY_CONFLICT"), - SMB_NTSTATUS_LOG_PINNED_ARCHIVE_TAIL => Some("STATUS_LOG_PINNED_ARCHIVE_TAIL"), - SMB_NTSTATUS_LOG_RECORD_NONEXISTENT => Some("STATUS_LOG_RECORD_NONEXISTENT"), - SMB_NTSTATUS_LOG_RECORDS_RESERVED_INVALID => Some("STATUS_LOG_RECORDS_RESERVED_INVALID"), - SMB_NTSTATUS_LOG_SPACE_RESERVED_INVALID => Some("STATUS_LOG_SPACE_RESERVED_INVALID"), - SMB_NTSTATUS_LOG_TAIL_INVALID => Some("STATUS_LOG_TAIL_INVALID"), - SMB_NTSTATUS_LOG_FULL => Some("STATUS_LOG_FULL"), - SMB_NTSTATUS_LOG_MULTIPLEXED => Some("STATUS_LOG_MULTIPLEXED"), - SMB_NTSTATUS_LOG_DEDICATED => Some("STATUS_LOG_DEDICATED"), - SMB_NTSTATUS_LOG_ARCHIVE_NOT_IN_PROGRESS => Some("STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS"), - SMB_NTSTATUS_LOG_ARCHIVE_IN_PROGRESS => Some("STATUS_LOG_ARCHIVE_IN_PROGRESS"), - SMB_NTSTATUS_LOG_EPHEMERAL => Some("STATUS_LOG_EPHEMERAL"), - SMB_NTSTATUS_LOG_NOT_ENOUGH_CONTAINERS => Some("STATUS_LOG_NOT_ENOUGH_CONTAINERS"), - SMB_NTSTATUS_LOG_CLIENT_ALREADY_REGISTERED => Some("STATUS_LOG_CLIENT_ALREADY_REGISTERED"), - SMB_NTSTATUS_LOG_CLIENT_NOT_REGISTERED => Some("STATUS_LOG_CLIENT_NOT_REGISTERED"), - SMB_NTSTATUS_LOG_FULL_HANDLER_IN_PROGRESS => Some("STATUS_LOG_FULL_HANDLER_IN_PROGRESS"), - SMB_NTSTATUS_LOG_CONTAINER_READ_FAILED => Some("STATUS_LOG_CONTAINER_READ_FAILED"), - SMB_NTSTATUS_LOG_CONTAINER_WRITE_FAILED => Some("STATUS_LOG_CONTAINER_WRITE_FAILED"), - SMB_NTSTATUS_LOG_CONTAINER_OPEN_FAILED => Some("STATUS_LOG_CONTAINER_OPEN_FAILED"), - SMB_NTSTATUS_LOG_CONTAINER_STATE_INVALID => Some("STATUS_LOG_CONTAINER_STATE_INVALID"), - SMB_NTSTATUS_LOG_STATE_INVALID => Some("STATUS_LOG_STATE_INVALID"), - SMB_NTSTATUS_LOG_PINNED => Some("STATUS_LOG_PINNED"), - SMB_NTSTATUS_LOG_METADATA_FLUSH_FAILED => Some("STATUS_LOG_METADATA_FLUSH_FAILED"), - SMB_NTSTATUS_LOG_INCONSISTENT_SECURITY => Some("STATUS_LOG_INCONSISTENT_SECURITY"), - SMB_NTSTATUS_LOG_APPENDED_FLUSH_FAILED => Some("STATUS_LOG_APPENDED_FLUSH_FAILED"), - SMB_NTSTATUS_LOG_PINNED_RESERVATION => Some("STATUS_LOG_PINNED_RESERVATION"), - SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD => Some("STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD"), - SMB_NTSTATUS_FLT_NO_HANDLER_DEFINED => Some("STATUS_FLT_NO_HANDLER_DEFINED"), - SMB_NTSTATUS_FLT_CONTEXT_ALREADY_DEFINED => Some("STATUS_FLT_CONTEXT_ALREADY_DEFINED"), - SMB_NTSTATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST => Some("STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST"), - SMB_NTSTATUS_FLT_DISALLOW_FAST_IO => Some("STATUS_FLT_DISALLOW_FAST_IO"), - SMB_NTSTATUS_FLT_INVALID_NAME_REQUEST => Some("STATUS_FLT_INVALID_NAME_REQUEST"), - SMB_NTSTATUS_FLT_NOT_SAFE_TO_POST_OPERATION => Some("STATUS_FLT_NOT_SAFE_TO_POST_OPERATION"), - SMB_NTSTATUS_FLT_NOT_INITIALIZED => Some("STATUS_FLT_NOT_INITIALIZED"), - SMB_NTSTATUS_FLT_FILTER_NOT_READY => Some("STATUS_FLT_FILTER_NOT_READY"), - SMB_NTSTATUS_FLT_POST_OPERATION_CLEANUP => Some("STATUS_FLT_POST_OPERATION_CLEANUP"), - SMB_NTSTATUS_FLT_INTERNAL_ERROR => Some("STATUS_FLT_INTERNAL_ERROR"), - SMB_NTSTATUS_FLT_DELETING_OBJECT => Some("STATUS_FLT_DELETING_OBJECT"), - SMB_NTSTATUS_FLT_MUST_BE_NONPAGED_POOL => Some("STATUS_FLT_MUST_BE_NONPAGED_POOL"), - SMB_NTSTATUS_FLT_DUPLICATE_ENTRY => Some("STATUS_FLT_DUPLICATE_ENTRY"), - SMB_NTSTATUS_FLT_CBDQ_DISABLED => Some("STATUS_FLT_CBDQ_DISABLED"), - SMB_NTSTATUS_FLT_DO_NOT_ATTACH => Some("STATUS_FLT_DO_NOT_ATTACH"), - SMB_NTSTATUS_FLT_DO_NOT_DETACH => Some("STATUS_FLT_DO_NOT_DETACH"), - SMB_NTSTATUS_FLT_INSTANCE_ALTITUDE_COLLISION => Some("STATUS_FLT_INSTANCE_ALTITUDE_COLLISION"), - SMB_NTSTATUS_FLT_INSTANCE_NAME_COLLISION => Some("STATUS_FLT_INSTANCE_NAME_COLLISION"), - SMB_NTSTATUS_FLT_FILTER_NOT_FOUND => Some("STATUS_FLT_FILTER_NOT_FOUND"), - SMB_NTSTATUS_FLT_VOLUME_NOT_FOUND => Some("STATUS_FLT_VOLUME_NOT_FOUND"), - SMB_NTSTATUS_FLT_INSTANCE_NOT_FOUND => Some("STATUS_FLT_INSTANCE_NOT_FOUND"), - SMB_NTSTATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND => Some("STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND"), - SMB_NTSTATUS_FLT_INVALID_CONTEXT_REGISTRATION => Some("STATUS_FLT_INVALID_CONTEXT_REGISTRATION"), - SMB_NTSTATUS_FLT_NAME_CACHE_MISS => Some("STATUS_FLT_NAME_CACHE_MISS"), - SMB_NTSTATUS_FLT_NO_DEVICE_OBJECT => Some("STATUS_FLT_NO_DEVICE_OBJECT"), - SMB_NTSTATUS_FLT_VOLUME_ALREADY_MOUNTED => Some("STATUS_FLT_VOLUME_ALREADY_MOUNTED"), - SMB_NTSTATUS_FLT_ALREADY_ENLISTED => Some("STATUS_FLT_ALREADY_ENLISTED"), - SMB_NTSTATUS_FLT_CONTEXT_ALREADY_LINKED => Some("STATUS_FLT_CONTEXT_ALREADY_LINKED"), - SMB_NTSTATUS_FLT_NO_WAITER_FOR_REPLY => Some("STATUS_FLT_NO_WAITER_FOR_REPLY"), - SMB_NTSTATUS_MONITOR_NO_DESCRIPTOR => Some("STATUS_MONITOR_NO_DESCRIPTOR"), - SMB_NTSTATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT => Some("STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT"), - SMB_NTSTATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM => Some("STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM"), - SMB_NTSTATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK => Some("STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK"), - SMB_NTSTATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED => Some("STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED"), - SMB_NTSTATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK => Some("STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK"), - SMB_NTSTATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK => Some("STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK"), - SMB_NTSTATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA => Some("STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA"), - SMB_NTSTATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK => Some("STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK"), - SMB_NTSTATUS_MONITOR_INVALID_MANUFACTURE_DATE => Some("STATUS_MONITOR_INVALID_MANUFACTURE_DATE"), - SMB_NTSTATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER => Some("STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER"), - SMB_NTSTATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER => Some("STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER"), - SMB_NTSTATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER => Some("STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER"), - SMB_NTSTATUS_GRAPHICS_ADAPTER_WAS_RESET => Some("STATUS_GRAPHICS_ADAPTER_WAS_RESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_DRIVER_MODEL => Some("STATUS_GRAPHICS_INVALID_DRIVER_MODEL"), - SMB_NTSTATUS_GRAPHICS_PRESENT_MODE_CHANGED => Some("STATUS_GRAPHICS_PRESENT_MODE_CHANGED"), - SMB_NTSTATUS_GRAPHICS_PRESENT_OCCLUDED => Some("STATUS_GRAPHICS_PRESENT_OCCLUDED"), - SMB_NTSTATUS_GRAPHICS_PRESENT_DENIED => Some("STATUS_GRAPHICS_PRESENT_DENIED"), - SMB_NTSTATUS_GRAPHICS_CANNOTCOLORCONVERT => Some("STATUS_GRAPHICS_CANNOTCOLORCONVERT"), - SMB_NTSTATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED => Some("STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED"), - SMB_NTSTATUS_GRAPHICS_PRESENT_UNOCCLUDED => Some("STATUS_GRAPHICS_PRESENT_UNOCCLUDED"), - SMB_NTSTATUS_GRAPHICS_NO_VIDEO_MEMORY => Some("STATUS_GRAPHICS_NO_VIDEO_MEMORY"), - SMB_NTSTATUS_GRAPHICS_CANT_LOCK_MEMORY => Some("STATUS_GRAPHICS_CANT_LOCK_MEMORY"), - SMB_NTSTATUS_GRAPHICS_ALLOCATION_BUSY => Some("STATUS_GRAPHICS_ALLOCATION_BUSY"), - SMB_NTSTATUS_GRAPHICS_TOO_MANY_REFERENCES => Some("STATUS_GRAPHICS_TOO_MANY_REFERENCES"), - SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_LATER => Some("STATUS_GRAPHICS_TRY_AGAIN_LATER"), - SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_NOW => Some("STATUS_GRAPHICS_TRY_AGAIN_NOW"), - SMB_NTSTATUS_GRAPHICS_ALLOCATION_INVALID => Some("STATUS_GRAPHICS_ALLOCATION_INVALID"), - SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE => Some("STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE"), - SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED => Some("STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED"), - SMB_NTSTATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION => Some("STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION"), - SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_USAGE => Some("STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE"), - SMB_NTSTATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION => Some("STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION"), - SMB_NTSTATUS_GRAPHICS_ALLOCATION_CLOSED => Some("STATUS_GRAPHICS_ALLOCATION_CLOSED"), - SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE => Some("STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE"), - SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE => Some("STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE"), - SMB_NTSTATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE => Some("STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE"), - SMB_NTSTATUS_GRAPHICS_ALLOCATION_CONTENT_LOST => Some("STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST"), - SMB_NTSTATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE => Some("STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY => Some("STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY"), - SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED => Some("STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED => Some("STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN => Some("STATUS_GRAPHICS_INVALID_VIDPN"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE => Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET => Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET"), - SMB_NTSTATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED => Some("STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET => Some("STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET => Some("STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_FREQUENCY => Some("STATUS_GRAPHICS_INVALID_FREQUENCY"), - SMB_NTSTATUS_GRAPHICS_INVALID_ACTIVE_REGION => Some("STATUS_GRAPHICS_INVALID_ACTIVE_REGION"), - SMB_NTSTATUS_GRAPHICS_INVALID_TOTAL_REGION => Some("STATUS_GRAPHICS_INVALID_TOTAL_REGION"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE => Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE => Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE"), - SMB_NTSTATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET => Some("STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET"), - SMB_NTSTATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY => Some("STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY"), - SMB_NTSTATUS_GRAPHICS_MODE_ALREADY_IN_MODESET => Some("STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET => Some("STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET => Some("STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET"), - SMB_NTSTATUS_GRAPHICS_SOURCE_ALREADY_IN_SET => Some("STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET"), - SMB_NTSTATUS_GRAPHICS_TARGET_ALREADY_IN_SET => Some("STATUS_GRAPHICS_TARGET_ALREADY_IN_SET"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH => Some("STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH"), - SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY => Some("STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET => Some("STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE => Some("STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE"), - SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET => Some("STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET"), - SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET => Some("STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET"), - SMB_NTSTATUS_GRAPHICS_STALE_MODESET => Some("STATUS_GRAPHICS_STALE_MODESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET => Some("STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE => Some("STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE"), - SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN => Some("STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN"), - SMB_NTSTATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE => Some("STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE"), - SMB_NTSTATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION => Some("STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION"), - SMB_NTSTATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES => Some("STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES"), - SMB_NTSTATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY => Some("STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY"), - SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE => Some("STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE"), - SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET => Some("STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET => Some("STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR => Some("STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR"), - SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET => Some("STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET"), - SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET => Some("STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET"), - SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE => Some("STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE => Some("STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE"), - SMB_NTSTATUS_GRAPHICS_RESOURCES_NOT_RELATED => Some("STATUS_GRAPHICS_RESOURCES_NOT_RELATED"), - SMB_NTSTATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE => Some("STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE"), - SMB_NTSTATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE => Some("STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE"), - SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET => Some("STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET"), - SMB_NTSTATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER => Some("STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER"), - SMB_NTSTATUS_GRAPHICS_NO_VIDPNMGR => Some("STATUS_GRAPHICS_NO_VIDPNMGR"), - SMB_NTSTATUS_GRAPHICS_NO_ACTIVE_VIDPN => Some("STATUS_GRAPHICS_NO_ACTIVE_VIDPN"), - SMB_NTSTATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY => Some("STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY"), - SMB_NTSTATUS_GRAPHICS_MONITOR_NOT_CONNECTED => Some("STATUS_GRAPHICS_MONITOR_NOT_CONNECTED"), - SMB_NTSTATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY => Some("STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY"), - SMB_NTSTATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE => Some("STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE"), - SMB_NTSTATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE => Some("STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE"), - SMB_NTSTATUS_GRAPHICS_INVALID_STRIDE => Some("STATUS_GRAPHICS_INVALID_STRIDE"), - SMB_NTSTATUS_GRAPHICS_INVALID_PIXELFORMAT => Some("STATUS_GRAPHICS_INVALID_PIXELFORMAT"), - SMB_NTSTATUS_GRAPHICS_INVALID_COLORBASIS => Some("STATUS_GRAPHICS_INVALID_COLORBASIS"), - SMB_NTSTATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE => Some("STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE"), - SMB_NTSTATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY => Some("STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY"), - SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT => Some("STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT"), - SMB_NTSTATUS_GRAPHICS_VIDPN_SOURCE_IN_USE => Some("STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"), - SMB_NTSTATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN => Some("STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN"), - SMB_NTSTATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL => Some("STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL"), - SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION => Some("STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION"), - SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED => Some("STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_INVALID_GAMMA_RAMP => Some("STATUS_GRAPHICS_INVALID_GAMMA_RAMP"), - SMB_NTSTATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED => Some("STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED => Some("STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_MODE_NOT_IN_MODESET => Some("STATUS_GRAPHICS_MODE_NOT_IN_MODESET"), - SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON => Some("STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON"), - SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE => Some("STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE"), - SMB_NTSTATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE => Some("STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE"), - SMB_NTSTATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS => Some("STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS"), - SMB_NTSTATUS_GRAPHICS_INVALID_SCANLINE_ORDERING => Some("STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING"), - SMB_NTSTATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED => Some("STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED"), - SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS => Some("STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS"), - SMB_NTSTATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT => Some("STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT"), - SMB_NTSTATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM => Some("STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN => Some("STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN"), - SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT => Some("STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT"), - SMB_NTSTATUS_GRAPHICS_MAX_NUM_PATHS_REACHED => Some("STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED"), - SMB_NTSTATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION => Some("STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION"), - SMB_NTSTATUS_GRAPHICS_INVALID_CLIENT_TYPE => Some("STATUS_GRAPHICS_INVALID_CLIENT_TYPE"), - SMB_NTSTATUS_GRAPHICS_CLIENTVIDPN_NOT_SET => Some("STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET"), - SMB_NTSTATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED => Some("STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED"), - SMB_NTSTATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED => Some("STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_NOT_A_LINKED_ADAPTER => Some("STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER"), - SMB_NTSTATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED => Some("STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED"), - SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED => Some("STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED"), - SMB_NTSTATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY => Some("STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY"), - SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_STARTED => Some("STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED"), - SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON => Some("STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON"), - SMB_NTSTATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE => Some("STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE"), - SMB_NTSTATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER => Some("STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER"), - SMB_NTSTATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED => Some("STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED"), - SMB_NTSTATUS_GRAPHICS_OPM_NOT_SUPPORTED => Some("STATUS_GRAPHICS_OPM_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_COPP_NOT_SUPPORTED => Some("STATUS_GRAPHICS_COPP_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_UAB_NOT_SUPPORTED => Some("STATUS_GRAPHICS_UAB_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS => Some("STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS"), - SMB_NTSTATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL => Some("STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL"), - SMB_NTSTATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST => Some("STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST"), - SMB_NTSTATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME => Some("STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"), - SMB_NTSTATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP => Some("STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"), - SMB_NTSTATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED => Some("STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_OPM_INVALID_POINTER => Some("STATUS_GRAPHICS_OPM_INVALID_POINTER"), - SMB_NTSTATUS_GRAPHICS_OPM_INTERNAL_ERROR => Some("STATUS_GRAPHICS_OPM_INTERNAL_ERROR"), - SMB_NTSTATUS_GRAPHICS_OPM_INVALID_HANDLE => Some("STATUS_GRAPHICS_OPM_INVALID_HANDLE"), - SMB_NTSTATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE => Some("STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"), - SMB_NTSTATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH => Some("STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH"), - SMB_NTSTATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED => Some("STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED"), - SMB_NTSTATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED => Some("STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED"), - SMB_NTSTATUS_GRAPHICS_PVP_HFS_FAILED => Some("STATUS_GRAPHICS_PVP_HFS_FAILED"), - SMB_NTSTATUS_GRAPHICS_OPM_INVALID_SRM => Some("STATUS_GRAPHICS_OPM_INVALID_SRM"), - SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP => Some("STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP"), - SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP => Some("STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP"), - SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA => Some("STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA"), - SMB_NTSTATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET => Some("STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET"), - SMB_NTSTATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH => Some("STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH"), - SMB_NTSTATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE => Some("STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE"), - SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS => Some("STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS"), - SMB_NTSTATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS => Some("STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS"), - SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS => Some("STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS"), - SMB_NTSTATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST => Some("STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST"), - SMB_NTSTATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR => Some("STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR"), - SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS => Some("STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS"), - SMB_NTSTATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED => Some("STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST => Some("STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST"), - SMB_NTSTATUS_GRAPHICS_I2C_NOT_SUPPORTED => Some("STATUS_GRAPHICS_I2C_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST => Some("STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST"), - SMB_NTSTATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA => Some("STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA"), - SMB_NTSTATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA => Some("STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA"), - SMB_NTSTATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED => Some("STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_DATA => Some("STATUS_GRAPHICS_DDCCI_INVALID_DATA"), - SMB_NTSTATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE => Some("STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE"), - SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING => Some("STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING"), - SMB_NTSTATUS_GRAPHICS_MCA_INTERNAL_ERROR => Some("STATUS_GRAPHICS_MCA_INTERNAL_ERROR"), - SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND => Some("STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND"), - SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH => Some("STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH"), - SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM => Some("STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM"), - SMB_NTSTATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE => Some("STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE"), - SMB_NTSTATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS => Some("STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS"), - SMB_NTSTATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED => Some("STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME => Some("STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"), - SMB_NTSTATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP => Some("STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"), - SMB_NTSTATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED => Some("STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED"), - SMB_NTSTATUS_GRAPHICS_INVALID_POINTER => Some("STATUS_GRAPHICS_INVALID_POINTER"), - SMB_NTSTATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE => Some("STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"), - SMB_NTSTATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL => Some("STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL"), - SMB_NTSTATUS_GRAPHICS_INTERNAL_ERROR => Some("STATUS_GRAPHICS_INTERNAL_ERROR"), - SMB_NTSTATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS => Some("STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS"), - SMB_NTSTATUS_FVE_LOCKED_VOLUME => Some("STATUS_FVE_LOCKED_VOLUME"), - SMB_NTSTATUS_FVE_NOT_ENCRYPTED => Some("STATUS_FVE_NOT_ENCRYPTED"), - SMB_NTSTATUS_FVE_BAD_INFORMATION => Some("STATUS_FVE_BAD_INFORMATION"), - SMB_NTSTATUS_FVE_TOO_SMALL => Some("STATUS_FVE_TOO_SMALL"), - SMB_NTSTATUS_FVE_FAILED_WRONG_FS => Some("STATUS_FVE_FAILED_WRONG_FS"), - SMB_NTSTATUS_FVE_FAILED_BAD_FS => Some("STATUS_FVE_FAILED_BAD_FS"), - SMB_NTSTATUS_FVE_FS_NOT_EXTENDED => Some("STATUS_FVE_FS_NOT_EXTENDED"), - SMB_NTSTATUS_FVE_FS_MOUNTED => Some("STATUS_FVE_FS_MOUNTED"), - SMB_NTSTATUS_FVE_NO_LICENSE => Some("STATUS_FVE_NO_LICENSE"), - SMB_NTSTATUS_FVE_ACTION_NOT_ALLOWED => Some("STATUS_FVE_ACTION_NOT_ALLOWED"), - SMB_NTSTATUS_FVE_BAD_DATA => Some("STATUS_FVE_BAD_DATA"), - SMB_NTSTATUS_FVE_VOLUME_NOT_BOUND => Some("STATUS_FVE_VOLUME_NOT_BOUND"), - SMB_NTSTATUS_FVE_NOT_DATA_VOLUME => Some("STATUS_FVE_NOT_DATA_VOLUME"), - SMB_NTSTATUS_FVE_CONV_READ_ERROR => Some("STATUS_FVE_CONV_READ_ERROR"), - SMB_NTSTATUS_FVE_CONV_WRITE_ERROR => Some("STATUS_FVE_CONV_WRITE_ERROR"), - SMB_NTSTATUS_FVE_OVERLAPPED_UPDATE => Some("STATUS_FVE_OVERLAPPED_UPDATE"), - SMB_NTSTATUS_FVE_FAILED_SECTOR_SIZE => Some("STATUS_FVE_FAILED_SECTOR_SIZE"), - SMB_NTSTATUS_FVE_FAILED_AUTHENTICATION => Some("STATUS_FVE_FAILED_AUTHENTICATION"), - SMB_NTSTATUS_FVE_NOT_OS_VOLUME => Some("STATUS_FVE_NOT_OS_VOLUME"), - SMB_NTSTATUS_FVE_KEYFILE_NOT_FOUND => Some("STATUS_FVE_KEYFILE_NOT_FOUND"), - SMB_NTSTATUS_FVE_KEYFILE_INVALID => Some("STATUS_FVE_KEYFILE_INVALID"), - SMB_NTSTATUS_FVE_KEYFILE_NO_VMK => Some("STATUS_FVE_KEYFILE_NO_VMK"), - SMB_NTSTATUS_FVE_TPM_DISABLED => Some("STATUS_FVE_TPM_DISABLED"), - SMB_NTSTATUS_FVE_TPM_SRK_AUTH_NOT_ZERO => Some("STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO"), - SMB_NTSTATUS_FVE_TPM_INVALID_PCR => Some("STATUS_FVE_TPM_INVALID_PCR"), - SMB_NTSTATUS_FVE_TPM_NO_VMK => Some("STATUS_FVE_TPM_NO_VMK"), - SMB_NTSTATUS_FVE_PIN_INVALID => Some("STATUS_FVE_PIN_INVALID"), - SMB_NTSTATUS_FVE_AUTH_INVALID_APPLICATION => Some("STATUS_FVE_AUTH_INVALID_APPLICATION"), - SMB_NTSTATUS_FVE_AUTH_INVALID_CONFIG => Some("STATUS_FVE_AUTH_INVALID_CONFIG"), - SMB_NTSTATUS_FVE_DEBUGGER_ENABLED => Some("STATUS_FVE_DEBUGGER_ENABLED"), - SMB_NTSTATUS_FVE_DRY_RUN_FAILED => Some("STATUS_FVE_DRY_RUN_FAILED"), - SMB_NTSTATUS_FVE_BAD_METADATA_POINTER => Some("STATUS_FVE_BAD_METADATA_POINTER"), - SMB_NTSTATUS_FVE_OLD_METADATA_COPY => Some("STATUS_FVE_OLD_METADATA_COPY"), - SMB_NTSTATUS_FVE_REBOOT_REQUIRED => Some("STATUS_FVE_REBOOT_REQUIRED"), - SMB_NTSTATUS_FVE_RAW_ACCESS => Some("STATUS_FVE_RAW_ACCESS"), - SMB_NTSTATUS_FVE_RAW_BLOCKED => Some("STATUS_FVE_RAW_BLOCKED"), - SMB_NTSTATUS_FVE_NO_FEATURE_LICENSE => Some("STATUS_FVE_NO_FEATURE_LICENSE"), - SMB_NTSTATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED => Some("STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED"), - SMB_NTSTATUS_FVE_CONV_RECOVERY_FAILED => Some("STATUS_FVE_CONV_RECOVERY_FAILED"), - SMB_NTSTATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG => Some("STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG"), - SMB_NTSTATUS_FVE_VOLUME_TOO_SMALL => Some("STATUS_FVE_VOLUME_TOO_SMALL"), - SMB_NTSTATUS_FWP_CALLOUT_NOT_FOUND => Some("STATUS_FWP_CALLOUT_NOT_FOUND"), - SMB_NTSTATUS_FWP_CONDITION_NOT_FOUND => Some("STATUS_FWP_CONDITION_NOT_FOUND"), - SMB_NTSTATUS_FWP_FILTER_NOT_FOUND => Some("STATUS_FWP_FILTER_NOT_FOUND"), - SMB_NTSTATUS_FWP_LAYER_NOT_FOUND => Some("STATUS_FWP_LAYER_NOT_FOUND"), - SMB_NTSTATUS_FWP_PROVIDER_NOT_FOUND => Some("STATUS_FWP_PROVIDER_NOT_FOUND"), - SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND => Some("STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND"), - SMB_NTSTATUS_FWP_SUBLAYER_NOT_FOUND => Some("STATUS_FWP_SUBLAYER_NOT_FOUND"), - SMB_NTSTATUS_FWP_NOT_FOUND => Some("STATUS_FWP_NOT_FOUND"), - SMB_NTSTATUS_FWP_ALREADY_EXISTS => Some("STATUS_FWP_ALREADY_EXISTS"), - SMB_NTSTATUS_FWP_IN_USE => Some("STATUS_FWP_IN_USE"), - SMB_NTSTATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS => Some("STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS"), - SMB_NTSTATUS_FWP_WRONG_SESSION => Some("STATUS_FWP_WRONG_SESSION"), - SMB_NTSTATUS_FWP_NO_TXN_IN_PROGRESS => Some("STATUS_FWP_NO_TXN_IN_PROGRESS"), - SMB_NTSTATUS_FWP_TXN_IN_PROGRESS => Some("STATUS_FWP_TXN_IN_PROGRESS"), - SMB_NTSTATUS_FWP_TXN_ABORTED => Some("STATUS_FWP_TXN_ABORTED"), - SMB_NTSTATUS_FWP_SESSION_ABORTED => Some("STATUS_FWP_SESSION_ABORTED"), - SMB_NTSTATUS_FWP_INCOMPATIBLE_TXN => Some("STATUS_FWP_INCOMPATIBLE_TXN"), - SMB_NTSTATUS_FWP_TIMEOUT => Some("STATUS_FWP_TIMEOUT"), - SMB_NTSTATUS_FWP_NET_EVENTS_DISABLED => Some("STATUS_FWP_NET_EVENTS_DISABLED"), - SMB_NTSTATUS_FWP_INCOMPATIBLE_LAYER => Some("STATUS_FWP_INCOMPATIBLE_LAYER"), - SMB_NTSTATUS_FWP_KM_CLIENTS_ONLY => Some("STATUS_FWP_KM_CLIENTS_ONLY"), - SMB_NTSTATUS_FWP_LIFETIME_MISMATCH => Some("STATUS_FWP_LIFETIME_MISMATCH"), - SMB_NTSTATUS_FWP_BUILTIN_OBJECT => Some("STATUS_FWP_BUILTIN_OBJECT"), - SMB_NTSTATUS_FWP_TOO_MANY_BOOTTIME_FILTERS => Some("STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS"), - SMB_NTSTATUS_FWP_NOTIFICATION_DROPPED => Some("STATUS_FWP_NOTIFICATION_DROPPED"), - SMB_NTSTATUS_FWP_TRAFFIC_MISMATCH => Some("STATUS_FWP_TRAFFIC_MISMATCH"), - SMB_NTSTATUS_FWP_INCOMPATIBLE_SA_STATE => Some("STATUS_FWP_INCOMPATIBLE_SA_STATE"), - SMB_NTSTATUS_FWP_NULL_POINTER => Some("STATUS_FWP_NULL_POINTER"), - SMB_NTSTATUS_FWP_INVALID_ENUMERATOR => Some("STATUS_FWP_INVALID_ENUMERATOR"), - SMB_NTSTATUS_FWP_INVALID_FLAGS => Some("STATUS_FWP_INVALID_FLAGS"), - SMB_NTSTATUS_FWP_INVALID_NET_MASK => Some("STATUS_FWP_INVALID_NET_MASK"), - SMB_NTSTATUS_FWP_INVALID_RANGE => Some("STATUS_FWP_INVALID_RANGE"), - SMB_NTSTATUS_FWP_INVALID_INTERVAL => Some("STATUS_FWP_INVALID_INTERVAL"), - SMB_NTSTATUS_FWP_ZERO_LENGTH_ARRAY => Some("STATUS_FWP_ZERO_LENGTH_ARRAY"), - SMB_NTSTATUS_FWP_NULL_DISPLAY_NAME => Some("STATUS_FWP_NULL_DISPLAY_NAME"), - SMB_NTSTATUS_FWP_INVALID_ACTION_TYPE => Some("STATUS_FWP_INVALID_ACTION_TYPE"), - SMB_NTSTATUS_FWP_INVALID_WEIGHT => Some("STATUS_FWP_INVALID_WEIGHT"), - SMB_NTSTATUS_FWP_MATCH_TYPE_MISMATCH => Some("STATUS_FWP_MATCH_TYPE_MISMATCH"), - SMB_NTSTATUS_FWP_TYPE_MISMATCH => Some("STATUS_FWP_TYPE_MISMATCH"), - SMB_NTSTATUS_FWP_OUT_OF_BOUNDS => Some("STATUS_FWP_OUT_OF_BOUNDS"), - SMB_NTSTATUS_FWP_RESERVED => Some("STATUS_FWP_RESERVED"), - SMB_NTSTATUS_FWP_DUPLICATE_CONDITION => Some("STATUS_FWP_DUPLICATE_CONDITION"), - SMB_NTSTATUS_FWP_DUPLICATE_KEYMOD => Some("STATUS_FWP_DUPLICATE_KEYMOD"), - SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER => Some("STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER"), - SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER => Some("STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER"), - SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER => Some("STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER"), - SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT => Some("STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT"), - SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_METHOD => Some("STATUS_FWP_INCOMPATIBLE_AUTH_METHOD"), - SMB_NTSTATUS_FWP_INCOMPATIBLE_DH_GROUP => Some("STATUS_FWP_INCOMPATIBLE_DH_GROUP"), - SMB_NTSTATUS_FWP_EM_NOT_SUPPORTED => Some("STATUS_FWP_EM_NOT_SUPPORTED"), - SMB_NTSTATUS_FWP_NEVER_MATCH => Some("STATUS_FWP_NEVER_MATCH"), - SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_MISMATCH => Some("STATUS_FWP_PROVIDER_CONTEXT_MISMATCH"), - SMB_NTSTATUS_FWP_INVALID_PARAMETER => Some("STATUS_FWP_INVALID_PARAMETER"), - SMB_NTSTATUS_FWP_TOO_MANY_SUBLAYERS => Some("STATUS_FWP_TOO_MANY_SUBLAYERS"), - SMB_NTSTATUS_FWP_CALLOUT_NOTIFICATION_FAILED => Some("STATUS_FWP_CALLOUT_NOTIFICATION_FAILED"), - SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_CONFIG => Some("STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG"), - SMB_NTSTATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG => Some("STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG"), - SMB_NTSTATUS_FWP_DUPLICATE_AUTH_METHOD => Some("STATUS_FWP_DUPLICATE_AUTH_METHOD"), - SMB_NTSTATUS_FWP_TCPIP_NOT_READY => Some("STATUS_FWP_TCPIP_NOT_READY"), - SMB_NTSTATUS_FWP_INJECT_HANDLE_CLOSING => Some("STATUS_FWP_INJECT_HANDLE_CLOSING"), - SMB_NTSTATUS_FWP_INJECT_HANDLE_STALE => Some("STATUS_FWP_INJECT_HANDLE_STALE"), - SMB_NTSTATUS_FWP_CANNOT_PEND => Some("STATUS_FWP_CANNOT_PEND"), - SMB_NTSTATUS_NDIS_CLOSING => Some("STATUS_NDIS_CLOSING"), - SMB_NTSTATUS_NDIS_BAD_VERSION => Some("STATUS_NDIS_BAD_VERSION"), - SMB_NTSTATUS_NDIS_BAD_CHARACTERISTICS => Some("STATUS_NDIS_BAD_CHARACTERISTICS"), - SMB_NTSTATUS_NDIS_ADAPTER_NOT_FOUND => Some("STATUS_NDIS_ADAPTER_NOT_FOUND"), - SMB_NTSTATUS_NDIS_OPEN_FAILED => Some("STATUS_NDIS_OPEN_FAILED"), - SMB_NTSTATUS_NDIS_DEVICE_FAILED => Some("STATUS_NDIS_DEVICE_FAILED"), - SMB_NTSTATUS_NDIS_MULTICAST_FULL => Some("STATUS_NDIS_MULTICAST_FULL"), - SMB_NTSTATUS_NDIS_MULTICAST_EXISTS => Some("STATUS_NDIS_MULTICAST_EXISTS"), - SMB_NTSTATUS_NDIS_MULTICAST_NOT_FOUND => Some("STATUS_NDIS_MULTICAST_NOT_FOUND"), - SMB_NTSTATUS_NDIS_REQUEST_ABORTED => Some("STATUS_NDIS_REQUEST_ABORTED"), - SMB_NTSTATUS_NDIS_RESET_IN_PROGRESS => Some("STATUS_NDIS_RESET_IN_PROGRESS"), - SMB_NTSTATUS_NDIS_INVALID_PACKET => Some("STATUS_NDIS_INVALID_PACKET"), - SMB_NTSTATUS_NDIS_INVALID_DEVICE_REQUEST => Some("STATUS_NDIS_INVALID_DEVICE_REQUEST"), - SMB_NTSTATUS_NDIS_ADAPTER_NOT_READY => Some("STATUS_NDIS_ADAPTER_NOT_READY"), - SMB_NTSTATUS_NDIS_INVALID_LENGTH => Some("STATUS_NDIS_INVALID_LENGTH"), - SMB_NTSTATUS_NDIS_INVALID_DATA => Some("STATUS_NDIS_INVALID_DATA"), - SMB_NTSTATUS_NDIS_BUFFER_TOO_SHORT => Some("STATUS_NDIS_BUFFER_TOO_SHORT"), - SMB_NTSTATUS_NDIS_INVALID_OID => Some("STATUS_NDIS_INVALID_OID"), - SMB_NTSTATUS_NDIS_ADAPTER_REMOVED => Some("STATUS_NDIS_ADAPTER_REMOVED"), - SMB_NTSTATUS_NDIS_UNSUPPORTED_MEDIA => Some("STATUS_NDIS_UNSUPPORTED_MEDIA"), - SMB_NTSTATUS_NDIS_GROUP_ADDRESS_IN_USE => Some("STATUS_NDIS_GROUP_ADDRESS_IN_USE"), - SMB_NTSTATUS_NDIS_FILE_NOT_FOUND => Some("STATUS_NDIS_FILE_NOT_FOUND"), - SMB_NTSTATUS_NDIS_ERROR_READING_FILE => Some("STATUS_NDIS_ERROR_READING_FILE"), - SMB_NTSTATUS_NDIS_ALREADY_MAPPED => Some("STATUS_NDIS_ALREADY_MAPPED"), - SMB_NTSTATUS_NDIS_RESOURCE_CONFLICT => Some("STATUS_NDIS_RESOURCE_CONFLICT"), - SMB_NTSTATUS_NDIS_MEDIA_DISCONNECTED => Some("STATUS_NDIS_MEDIA_DISCONNECTED"), - SMB_NTSTATUS_NDIS_INVALID_ADDRESS => Some("STATUS_NDIS_INVALID_ADDRESS"), - SMB_NTSTATUS_NDIS_PAUSED => Some("STATUS_NDIS_PAUSED"), - SMB_NTSTATUS_NDIS_INTERFACE_NOT_FOUND => Some("STATUS_NDIS_INTERFACE_NOT_FOUND"), - SMB_NTSTATUS_NDIS_UNSUPPORTED_REVISION => Some("STATUS_NDIS_UNSUPPORTED_REVISION"), - SMB_NTSTATUS_NDIS_INVALID_PORT => Some("STATUS_NDIS_INVALID_PORT"), - SMB_NTSTATUS_NDIS_INVALID_PORT_STATE => Some("STATUS_NDIS_INVALID_PORT_STATE"), - SMB_NTSTATUS_NDIS_LOW_POWER_STATE => Some("STATUS_NDIS_LOW_POWER_STATE"), - SMB_NTSTATUS_NDIS_NOT_SUPPORTED => Some("STATUS_NDIS_NOT_SUPPORTED"), - SMB_NTSTATUS_NDIS_OFFLOAD_POLICY => Some("STATUS_NDIS_OFFLOAD_POLICY"), - SMB_NTSTATUS_NDIS_OFFLOAD_CONNECTION_REJECTED => Some("STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED"), - SMB_NTSTATUS_NDIS_OFFLOAD_PATH_REJECTED => Some("STATUS_NDIS_OFFLOAD_PATH_REJECTED"), - SMB_NTSTATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED => Some("STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED"), - SMB_NTSTATUS_NDIS_DOT11_MEDIA_IN_USE => Some("STATUS_NDIS_DOT11_MEDIA_IN_USE"), - SMB_NTSTATUS_NDIS_DOT11_POWER_STATE_INVALID => Some("STATUS_NDIS_DOT11_POWER_STATE_INVALID"), - SMB_NTSTATUS_NDIS_PM_WOL_PATTERN_LIST_FULL => Some("STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL"), - SMB_NTSTATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL => Some("STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL"), - SMB_NTSTATUS_IPSEC_BAD_SPI => Some("STATUS_IPSEC_BAD_SPI"), - SMB_NTSTATUS_IPSEC_SA_LIFETIME_EXPIRED => Some("STATUS_IPSEC_SA_LIFETIME_EXPIRED"), - SMB_NTSTATUS_IPSEC_WRONG_SA => Some("STATUS_IPSEC_WRONG_SA"), - SMB_NTSTATUS_IPSEC_REPLAY_CHECK_FAILED => Some("STATUS_IPSEC_REPLAY_CHECK_FAILED"), - SMB_NTSTATUS_IPSEC_INVALID_PACKET => Some("STATUS_IPSEC_INVALID_PACKET"), - SMB_NTSTATUS_IPSEC_INTEGRITY_CHECK_FAILED => Some("STATUS_IPSEC_INTEGRITY_CHECK_FAILED"), - SMB_NTSTATUS_IPSEC_CLEAR_TEXT_DROP => Some("STATUS_IPSEC_CLEAR_TEXT_DROP"), - SMB_NTSTATUS_IPSEC_AUTH_FIREWALL_DROP => Some("STATUS_IPSEC_AUTH_FIREWALL_DROP"), - SMB_NTSTATUS_IPSEC_THROTTLE_DROP => Some("STATUS_IPSEC_THROTTLE_DROP"), - SMB_NTSTATUS_IPSEC_DOSP_BLOCK => Some("STATUS_IPSEC_DOSP_BLOCK"), - SMB_NTSTATUS_IPSEC_DOSP_RECEIVED_MULTICAST => Some("STATUS_IPSEC_DOSP_RECEIVED_MULTICAST"), - SMB_NTSTATUS_IPSEC_DOSP_INVALID_PACKET => Some("STATUS_IPSEC_DOSP_INVALID_PACKET"), - SMB_NTSTATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED => Some("STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED"), - SMB_NTSTATUS_IPSEC_DOSP_MAX_ENTRIES => Some("STATUS_IPSEC_DOSP_MAX_ENTRIES"), - SMB_NTSTATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED => Some("STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED"), - SMB_NTSTATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES => Some("STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES"), - SMB_NTSTATUS_VOLMGR_MIRROR_NOT_SUPPORTED => Some("STATUS_VOLMGR_MIRROR_NOT_SUPPORTED"), - SMB_NTSTATUS_VOLMGR_RAID5_NOT_SUPPORTED => Some("STATUS_VOLMGR_RAID5_NOT_SUPPORTED"), - SMB_NTSTATUS_VIRTDISK_PROVIDER_NOT_FOUND => Some("STATUS_VIRTDISK_PROVIDER_NOT_FOUND"), - SMB_NTSTATUS_VIRTDISK_NOT_VIRTUAL_DISK => Some("STATUS_VIRTDISK_NOT_VIRTUAL_DISK"), - SMB_NTSTATUS_VHD_PARENT_VHD_ACCESS_DENIED => Some("STATUS_VHD_PARENT_VHD_ACCESS_DENIED"), - SMB_NTSTATUS_VHD_CHILD_PARENT_SIZE_MISMATCH => Some("STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH"), - SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED => Some("STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED"), - SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT => Some("STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT"), - + SMB_NTSTATUS_SUCCESS => Some("STATUS_SUCCESS"), + SMB_NTSTATUS_WAIT_1 => Some("STATUS_WAIT_1"), + SMB_NTSTATUS_WAIT_2 => Some("STATUS_WAIT_2"), + SMB_NTSTATUS_WAIT_3 => Some("STATUS_WAIT_3"), + SMB_NTSTATUS_WAIT_63 => Some("STATUS_WAIT_63"), + SMB_NTSTATUS_ABANDONED => Some("STATUS_ABANDONED"), + SMB_NTSTATUS_ABANDONED_WAIT_63 => Some("STATUS_ABANDONED_WAIT_63"), + SMB_NTSTATUS_USER_APC => Some("STATUS_USER_APC"), + SMB_NTSTATUS_ALERTED => Some("STATUS_ALERTED"), + SMB_NTSTATUS_TIMEOUT => Some("STATUS_TIMEOUT"), + SMB_NTSTATUS_PENDING => Some("STATUS_PENDING"), + SMB_NTSTATUS_REPARSE => Some("STATUS_REPARSE"), + SMB_NTSTATUS_MORE_ENTRIES => Some("STATUS_MORE_ENTRIES"), + SMB_NTSTATUS_NOT_ALL_ASSIGNED => Some("STATUS_NOT_ALL_ASSIGNED"), + SMB_NTSTATUS_SOME_NOT_MAPPED => Some("STATUS_SOME_NOT_MAPPED"), + SMB_NTSTATUS_OPLOCK_BREAK_IN_PROGRESS => Some("STATUS_OPLOCK_BREAK_IN_PROGRESS"), + SMB_NTSTATUS_VOLUME_MOUNTED => Some("STATUS_VOLUME_MOUNTED"), + SMB_NTSTATUS_RXACT_COMMITTED => Some("STATUS_RXACT_COMMITTED"), + SMB_NTSTATUS_NOTIFY_CLEANUP => Some("STATUS_NOTIFY_CLEANUP"), + SMB_NTSTATUS_NOTIFY_ENUM_DIR => Some("STATUS_NOTIFY_ENUM_DIR"), + SMB_NTSTATUS_NO_QUOTAS_FOR_ACCOUNT => Some("STATUS_NO_QUOTAS_FOR_ACCOUNT"), + SMB_NTSTATUS_PRIMARY_TRANSPORT_CONNECT_FAILED => { + Some("STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED") + } + SMB_NTSTATUS_PAGE_FAULT_TRANSITION => Some("STATUS_PAGE_FAULT_TRANSITION"), + SMB_NTSTATUS_PAGE_FAULT_DEMAND_ZERO => Some("STATUS_PAGE_FAULT_DEMAND_ZERO"), + SMB_NTSTATUS_PAGE_FAULT_COPY_ON_WRITE => Some("STATUS_PAGE_FAULT_COPY_ON_WRITE"), + SMB_NTSTATUS_PAGE_FAULT_GUARD_PAGE => Some("STATUS_PAGE_FAULT_GUARD_PAGE"), + SMB_NTSTATUS_PAGE_FAULT_PAGING_FILE => Some("STATUS_PAGE_FAULT_PAGING_FILE"), + SMB_NTSTATUS_CACHE_PAGE_LOCKED => Some("STATUS_CACHE_PAGE_LOCKED"), + SMB_NTSTATUS_CRASH_DUMP => Some("STATUS_CRASH_DUMP"), + SMB_NTSTATUS_BUFFER_ALL_ZEROS => Some("STATUS_BUFFER_ALL_ZEROS"), + SMB_NTSTATUS_REPARSE_OBJECT => Some("STATUS_REPARSE_OBJECT"), + SMB_NTSTATUS_RESOURCE_REQUIREMENTS_CHANGED => Some("STATUS_RESOURCE_REQUIREMENTS_CHANGED"), + SMB_NTSTATUS_TRANSLATION_COMPLETE => Some("STATUS_TRANSLATION_COMPLETE"), + SMB_NTSTATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY => { + Some("STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY") + } + SMB_NTSTATUS_NOTHING_TO_TERMINATE => Some("STATUS_NOTHING_TO_TERMINATE"), + SMB_NTSTATUS_PROCESS_NOT_IN_JOB => Some("STATUS_PROCESS_NOT_IN_JOB"), + SMB_NTSTATUS_PROCESS_IN_JOB => Some("STATUS_PROCESS_IN_JOB"), + SMB_NTSTATUS_VOLSNAP_HIBERNATE_READY => Some("STATUS_VOLSNAP_HIBERNATE_READY"), + SMB_NTSTATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY => { + Some("STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY") + } + SMB_NTSTATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED => { + Some("STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED") + } + SMB_NTSTATUS_INTERRUPT_STILL_CONNECTED => Some("STATUS_INTERRUPT_STILL_CONNECTED"), + SMB_NTSTATUS_PROCESS_CLONED => Some("STATUS_PROCESS_CLONED"), + SMB_NTSTATUS_FILE_LOCKED_WITH_ONLY_READERS => Some("STATUS_FILE_LOCKED_WITH_ONLY_READERS"), + SMB_NTSTATUS_FILE_LOCKED_WITH_WRITERS => Some("STATUS_FILE_LOCKED_WITH_WRITERS"), + SMB_NTSTATUS_RESOURCEMANAGER_READ_ONLY => Some("STATUS_RESOURCEMANAGER_READ_ONLY"), + SMB_NTSTATUS_WAIT_FOR_OPLOCK => Some("STATUS_WAIT_FOR_OPLOCK"), + SMB_NTDBG_EXCEPTION_HANDLED => Some("DBG_EXCEPTION_HANDLED"), + SMB_NTDBG_CONTINUE => Some("DBG_CONTINUE"), + SMB_NTSTATUS_FLT_IO_COMPLETE => Some("STATUS_FLT_IO_COMPLETE"), + SMB_NTSTATUS_FILE_NOT_AVAILABLE => Some("STATUS_FILE_NOT_AVAILABLE"), + SMB_NTSTATUS_SHARE_UNAVAILABLE => Some("STATUS_SHARE_UNAVAILABLE"), + SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_AFFINITY => { + Some("STATUS_CALLBACK_RETURNED_THREAD_AFFINITY") + } + SMB_NTSTATUS_OBJECT_NAME_EXISTS => Some("STATUS_OBJECT_NAME_EXISTS"), + SMB_NTSTATUS_THREAD_WAS_SUSPENDED => Some("STATUS_THREAD_WAS_SUSPENDED"), + SMB_NTSTATUS_WORKING_SET_LIMIT_RANGE => Some("STATUS_WORKING_SET_LIMIT_RANGE"), + SMB_NTSTATUS_IMAGE_NOT_AT_BASE => Some("STATUS_IMAGE_NOT_AT_BASE"), + SMB_NTSTATUS_RXACT_STATE_CREATED => Some("STATUS_RXACT_STATE_CREATED"), + SMB_NTSTATUS_SEGMENT_NOTIFICATION => Some("STATUS_SEGMENT_NOTIFICATION"), + SMB_NTSTATUS_LOCAL_USER_SESSION_KEY => Some("STATUS_LOCAL_USER_SESSION_KEY"), + SMB_NTSTATUS_BAD_CURRENT_DIRECTORY => Some("STATUS_BAD_CURRENT_DIRECTORY"), + SMB_NTSTATUS_SERIAL_MORE_WRITES => Some("STATUS_SERIAL_MORE_WRITES"), + SMB_NTSTATUS_REGISTRY_RECOVERED => Some("STATUS_REGISTRY_RECOVERED"), + SMB_NTSTATUS_FT_READ_RECOVERY_FROM_BACKUP => Some("STATUS_FT_READ_RECOVERY_FROM_BACKUP"), + SMB_NTSTATUS_FT_WRITE_RECOVERY => Some("STATUS_FT_WRITE_RECOVERY"), + SMB_NTSTATUS_SERIAL_COUNTER_TIMEOUT => Some("STATUS_SERIAL_COUNTER_TIMEOUT"), + SMB_NTSTATUS_NULL_LM_PASSWORD => Some("STATUS_NULL_LM_PASSWORD"), + SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH => Some("STATUS_IMAGE_MACHINE_TYPE_MISMATCH"), + SMB_NTSTATUS_RECEIVE_PARTIAL => Some("STATUS_RECEIVE_PARTIAL"), + SMB_NTSTATUS_RECEIVE_EXPEDITED => Some("STATUS_RECEIVE_EXPEDITED"), + SMB_NTSTATUS_RECEIVE_PARTIAL_EXPEDITED => Some("STATUS_RECEIVE_PARTIAL_EXPEDITED"), + SMB_NTSTATUS_EVENT_DONE => Some("STATUS_EVENT_DONE"), + SMB_NTSTATUS_EVENT_PENDING => Some("STATUS_EVENT_PENDING"), + SMB_NTSTATUS_CHECKING_FILE_SYSTEM => Some("STATUS_CHECKING_FILE_SYSTEM"), + SMB_NTSTATUS_FATAL_APP_EXIT => Some("STATUS_FATAL_APP_EXIT"), + SMB_NTSTATUS_PREDEFINED_HANDLE => Some("STATUS_PREDEFINED_HANDLE"), + SMB_NTSTATUS_WAS_UNLOCKED => Some("STATUS_WAS_UNLOCKED"), + SMB_NTSTATUS_SERVICE_NOTIFICATION => Some("STATUS_SERVICE_NOTIFICATION"), + SMB_NTSTATUS_WAS_LOCKED => Some("STATUS_WAS_LOCKED"), + SMB_NTSTATUS_LOG_HARD_ERROR => Some("STATUS_LOG_HARD_ERROR"), + SMB_NTSTATUS_ALREADY_WIN32 => Some("STATUS_ALREADY_WIN32"), + SMB_NTSTATUS_WX86_UNSIMULATE => Some("STATUS_WX86_UNSIMULATE"), + SMB_NTSTATUS_WX86_CONTINUE => Some("STATUS_WX86_CONTINUE"), + SMB_NTSTATUS_WX86_SINGLE_STEP => Some("STATUS_WX86_SINGLE_STEP"), + SMB_NTSTATUS_WX86_BREAKPOINT => Some("STATUS_WX86_BREAKPOINT"), + SMB_NTSTATUS_WX86_EXCEPTION_CONTINUE => Some("STATUS_WX86_EXCEPTION_CONTINUE"), + SMB_NTSTATUS_WX86_EXCEPTION_LASTCHANCE => Some("STATUS_WX86_EXCEPTION_LASTCHANCE"), + SMB_NTSTATUS_WX86_EXCEPTION_CHAIN => Some("STATUS_WX86_EXCEPTION_CHAIN"), + SMB_NTSTATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE => { + Some("STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE") + } + SMB_NTSTATUS_NO_YIELD_PERFORMED => Some("STATUS_NO_YIELD_PERFORMED"), + SMB_NTSTATUS_TIMER_RESUME_IGNORED => Some("STATUS_TIMER_RESUME_IGNORED"), + SMB_NTSTATUS_ARBITRATION_UNHANDLED => Some("STATUS_ARBITRATION_UNHANDLED"), + SMB_NTSTATUS_CARDBUS_NOT_SUPPORTED => Some("STATUS_CARDBUS_NOT_SUPPORTED"), + SMB_NTSTATUS_WX86_CREATEWX86TIB => Some("STATUS_WX86_CREATEWX86TIB"), + SMB_NTSTATUS_MP_PROCESSOR_MISMATCH => Some("STATUS_MP_PROCESSOR_MISMATCH"), + SMB_NTSTATUS_HIBERNATED => Some("STATUS_HIBERNATED"), + SMB_NTSTATUS_RESUME_HIBERNATION => Some("STATUS_RESUME_HIBERNATION"), + SMB_NTSTATUS_FIRMWARE_UPDATED => Some("STATUS_FIRMWARE_UPDATED"), + SMB_NTSTATUS_DRIVERS_LEAKING_LOCKED_PAGES => Some("STATUS_DRIVERS_LEAKING_LOCKED_PAGES"), + SMB_NTSTATUS_MESSAGE_RETRIEVED => Some("STATUS_MESSAGE_RETRIEVED"), + SMB_NTSTATUS_SYSTEM_POWERSTATE_TRANSITION => Some("STATUS_SYSTEM_POWERSTATE_TRANSITION"), + SMB_NTSTATUS_ALPC_CHECK_COMPLETION_LIST => Some("STATUS_ALPC_CHECK_COMPLETION_LIST"), + SMB_NTSTATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION => { + Some("STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION") + } + SMB_NTSTATUS_ACCESS_AUDIT_BY_POLICY => Some("STATUS_ACCESS_AUDIT_BY_POLICY"), + SMB_NTSTATUS_ABANDON_HIBERFILE => Some("STATUS_ABANDON_HIBERFILE"), + SMB_NTSTATUS_BIZRULES_NOT_ENABLED => Some("STATUS_BIZRULES_NOT_ENABLED"), + SMB_NTSTATUS_WAKE_SYSTEM => Some("STATUS_WAKE_SYSTEM"), + SMB_NTSTATUS_DS_SHUTTING_DOWN => Some("STATUS_DS_SHUTTING_DOWN"), + SMB_NTDBG_REPLY_LATER => Some("DBG_REPLY_LATER"), + SMB_NTDBG_UNABLE_TO_PROVIDE_HANDLE => Some("DBG_UNABLE_TO_PROVIDE_HANDLE"), + SMB_NTDBG_TERMINATE_THREAD => Some("DBG_TERMINATE_THREAD"), + SMB_NTDBG_TERMINATE_PROCESS => Some("DBG_TERMINATE_PROCESS"), + SMB_NTDBG_CONTROL_C => Some("DBG_CONTROL_C"), + SMB_NTDBG_PRINTEXCEPTION_C => Some("DBG_PRINTEXCEPTION_C"), + SMB_NTDBG_RIPEXCEPTION => Some("DBG_RIPEXCEPTION"), + SMB_NTDBG_CONTROL_BREAK => Some("DBG_CONTROL_BREAK"), + SMB_NTDBG_COMMAND_EXCEPTION => Some("DBG_COMMAND_EXCEPTION"), + SMB_NTRPC_NT_UUID_LOCAL_ONLY => Some("RPC_NT_UUID_LOCAL_ONLY"), + SMB_NTRPC_NT_SEND_INCOMPLETE => Some("RPC_NT_SEND_INCOMPLETE"), + SMB_NTSTATUS_CTX_CDM_CONNECT => Some("STATUS_CTX_CDM_CONNECT"), + SMB_NTSTATUS_CTX_CDM_DISCONNECT => Some("STATUS_CTX_CDM_DISCONNECT"), + SMB_NTSTATUS_SXS_RELEASE_ACTIVATION_CONTEXT => { + Some("STATUS_SXS_RELEASE_ACTIVATION_CONTEXT") + } + SMB_NTSTATUS_RECOVERY_NOT_NEEDED => Some("STATUS_RECOVERY_NOT_NEEDED"), + SMB_NTSTATUS_RM_ALREADY_STARTED => Some("STATUS_RM_ALREADY_STARTED"), + SMB_NTSTATUS_LOG_NO_RESTART => Some("STATUS_LOG_NO_RESTART"), + SMB_NTSTATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST => { + Some("STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST") + } + SMB_NTSTATUS_GRAPHICS_PARTIAL_DATA_POPULATED => { + Some("STATUS_GRAPHICS_PARTIAL_DATA_POPULATED") + } + SMB_NTSTATUS_GRAPHICS_DRIVER_MISMATCH => Some("STATUS_GRAPHICS_DRIVER_MISMATCH"), + SMB_NTSTATUS_GRAPHICS_MODE_NOT_PINNED => Some("STATUS_GRAPHICS_MODE_NOT_PINNED"), + SMB_NTSTATUS_GRAPHICS_NO_PREFERRED_MODE => Some("STATUS_GRAPHICS_NO_PREFERRED_MODE"), + SMB_NTSTATUS_GRAPHICS_DATASET_IS_EMPTY => Some("STATUS_GRAPHICS_DATASET_IS_EMPTY"), + SMB_NTSTATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET => { + Some("STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET") + } + SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED => { + Some("STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED") + } + SMB_NTSTATUS_GRAPHICS_UNKNOWN_CHILD_STATUS => Some("STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS"), + SMB_NTSTATUS_GRAPHICS_LEADLINK_START_DEFERRED => { + Some("STATUS_GRAPHICS_LEADLINK_START_DEFERRED") + } + SMB_NTSTATUS_GRAPHICS_POLLING_TOO_FREQUENTLY => { + Some("STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY") + } + SMB_NTSTATUS_GRAPHICS_START_DEFERRED => Some("STATUS_GRAPHICS_START_DEFERRED"), + SMB_NTSTATUS_NDIS_INDICATION_REQUIRED => Some("STATUS_NDIS_INDICATION_REQUIRED"), + SMB_NTSTATUS_GUARD_PAGE_VIOLATION => Some("STATUS_GUARD_PAGE_VIOLATION"), + SMB_NTSTATUS_DATATYPE_MISALIGNMENT => Some("STATUS_DATATYPE_MISALIGNMENT"), + SMB_NTSTATUS_BREAKPOINT => Some("STATUS_BREAKPOINT"), + SMB_NTSTATUS_SINGLE_STEP => Some("STATUS_SINGLE_STEP"), + SMB_NTSTATUS_BUFFER_OVERFLOW => Some("STATUS_BUFFER_OVERFLOW"), + SMB_NTSTATUS_NO_MORE_FILES => Some("STATUS_NO_MORE_FILES"), + SMB_NTSTATUS_WAKE_SYSTEM_DEBUGGER => Some("STATUS_WAKE_SYSTEM_DEBUGGER"), + SMB_NTSTATUS_HANDLES_CLOSED => Some("STATUS_HANDLES_CLOSED"), + SMB_NTSTATUS_NO_INHERITANCE => Some("STATUS_NO_INHERITANCE"), + SMB_NTSTATUS_GUID_SUBSTITUTION_MADE => Some("STATUS_GUID_SUBSTITUTION_MADE"), + SMB_NTSTATUS_PARTIAL_COPY => Some("STATUS_PARTIAL_COPY"), + SMB_NTSTATUS_DEVICE_PAPER_EMPTY => Some("STATUS_DEVICE_PAPER_EMPTY"), + SMB_NTSTATUS_DEVICE_POWERED_OFF => Some("STATUS_DEVICE_POWERED_OFF"), + SMB_NTSTATUS_DEVICE_OFF_LINE => Some("STATUS_DEVICE_OFF_LINE"), + SMB_NTSTATUS_DEVICE_BUSY => Some("STATUS_DEVICE_BUSY"), + SMB_NTSTATUS_NO_MORE_EAS => Some("STATUS_NO_MORE_EAS"), + SMB_NTSTATUS_INVALID_EA_NAME => Some("STATUS_INVALID_EA_NAME"), + SMB_NTSTATUS_EA_LIST_INCONSISTENT => Some("STATUS_EA_LIST_INCONSISTENT"), + SMB_NTSTATUS_INVALID_EA_FLAG => Some("STATUS_INVALID_EA_FLAG"), + SMB_NTSTATUS_VERIFY_REQUIRED => Some("STATUS_VERIFY_REQUIRED"), + SMB_NTSTATUS_EXTRANEOUS_INFORMATION => Some("STATUS_EXTRANEOUS_INFORMATION"), + SMB_NTSTATUS_RXACT_COMMIT_NECESSARY => Some("STATUS_RXACT_COMMIT_NECESSARY"), + SMB_NTSTATUS_NO_MORE_ENTRIES => Some("STATUS_NO_MORE_ENTRIES"), + SMB_NTSTATUS_FILEMARK_DETECTED => Some("STATUS_FILEMARK_DETECTED"), + SMB_NTSTATUS_MEDIA_CHANGED => Some("STATUS_MEDIA_CHANGED"), + SMB_NTSTATUS_BUS_RESET => Some("STATUS_BUS_RESET"), + SMB_NTSTATUS_END_OF_MEDIA => Some("STATUS_END_OF_MEDIA"), + SMB_NTSTATUS_BEGINNING_OF_MEDIA => Some("STATUS_BEGINNING_OF_MEDIA"), + SMB_NTSTATUS_MEDIA_CHECK => Some("STATUS_MEDIA_CHECK"), + SMB_NTSTATUS_SETMARK_DETECTED => Some("STATUS_SETMARK_DETECTED"), + SMB_NTSTATUS_NO_DATA_DETECTED => Some("STATUS_NO_DATA_DETECTED"), + SMB_NTSTATUS_REDIRECTOR_HAS_OPEN_HANDLES => Some("STATUS_REDIRECTOR_HAS_OPEN_HANDLES"), + SMB_NTSTATUS_SERVER_HAS_OPEN_HANDLES => Some("STATUS_SERVER_HAS_OPEN_HANDLES"), + SMB_NTSTATUS_ALREADY_DISCONNECTED => Some("STATUS_ALREADY_DISCONNECTED"), + SMB_NTSTATUS_LONGJUMP => Some("STATUS_LONGJUMP"), + SMB_NTSTATUS_CLEANER_CARTRIDGE_INSTALLED => Some("STATUS_CLEANER_CARTRIDGE_INSTALLED"), + SMB_NTSTATUS_PLUGPLAY_QUERY_VETOED => Some("STATUS_PLUGPLAY_QUERY_VETOED"), + SMB_NTSTATUS_UNWIND_CONSOLIDATE => Some("STATUS_UNWIND_CONSOLIDATE"), + SMB_NTSTATUS_REGISTRY_HIVE_RECOVERED => Some("STATUS_REGISTRY_HIVE_RECOVERED"), + SMB_NTSTATUS_DLL_MIGHT_BE_INSECURE => Some("STATUS_DLL_MIGHT_BE_INSECURE"), + SMB_NTSTATUS_DLL_MIGHT_BE_INCOMPATIBLE => Some("STATUS_DLL_MIGHT_BE_INCOMPATIBLE"), + SMB_NTSTATUS_STOPPED_ON_SYMLINK => Some("STATUS_STOPPED_ON_SYMLINK"), + SMB_NTSTATUS_DEVICE_REQUIRES_CLEANING => Some("STATUS_DEVICE_REQUIRES_CLEANING"), + SMB_NTSTATUS_DEVICE_DOOR_OPEN => Some("STATUS_DEVICE_DOOR_OPEN"), + SMB_NTSTATUS_DATA_LOST_REPAIR => Some("STATUS_DATA_LOST_REPAIR"), + SMB_NTDBG_EXCEPTION_NOT_HANDLED => Some("DBG_EXCEPTION_NOT_HANDLED"), + SMB_NTSTATUS_CLUSTER_NODE_ALREADY_UP => Some("STATUS_CLUSTER_NODE_ALREADY_UP"), + SMB_NTSTATUS_CLUSTER_NODE_ALREADY_DOWN => Some("STATUS_CLUSTER_NODE_ALREADY_DOWN"), + SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_ONLINE => { + Some("STATUS_CLUSTER_NETWORK_ALREADY_ONLINE") + } + SMB_NTSTATUS_CLUSTER_NETWORK_ALREADY_OFFLINE => { + Some("STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE") + } + SMB_NTSTATUS_CLUSTER_NODE_ALREADY_MEMBER => Some("STATUS_CLUSTER_NODE_ALREADY_MEMBER"), + SMB_NTSTATUS_COULD_NOT_RESIZE_LOG => Some("STATUS_COULD_NOT_RESIZE_LOG"), + SMB_NTSTATUS_NO_TXF_METADATA => Some("STATUS_NO_TXF_METADATA"), + SMB_NTSTATUS_CANT_RECOVER_WITH_HANDLE_OPEN => Some("STATUS_CANT_RECOVER_WITH_HANDLE_OPEN"), + SMB_NTSTATUS_TXF_METADATA_ALREADY_PRESENT => Some("STATUS_TXF_METADATA_ALREADY_PRESENT"), + SMB_NTSTATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET => { + Some("STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET") + } + SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED => { + Some("STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED") + } + SMB_NTSTATUS_FLT_BUFFER_TOO_SMALL => Some("STATUS_FLT_BUFFER_TOO_SMALL"), + SMB_NTSTATUS_FVE_PARTIAL_METADATA => Some("STATUS_FVE_PARTIAL_METADATA"), + SMB_NTSTATUS_FVE_TRANSIENT_STATE => Some("STATUS_FVE_TRANSIENT_STATE"), + SMB_NTSTATUS_UNSUCCESSFUL => Some("STATUS_UNSUCCESSFUL"), + SMB_NTSTATUS_NOT_IMPLEMENTED => Some("STATUS_NOT_IMPLEMENTED"), + SMB_NTSTATUS_INVALID_INFO_CLASS => Some("STATUS_INVALID_INFO_CLASS"), + SMB_NTSTATUS_INFO_LENGTH_MISMATCH => Some("STATUS_INFO_LENGTH_MISMATCH"), + SMB_NTSTATUS_ACCESS_VIOLATION => Some("STATUS_ACCESS_VIOLATION"), + SMB_NTSTATUS_IN_PAGE_ERROR => Some("STATUS_IN_PAGE_ERROR"), + SMB_NTSTATUS_PAGEFILE_QUOTA => Some("STATUS_PAGEFILE_QUOTA"), + SMB_NTSTATUS_INVALID_HANDLE => Some("STATUS_INVALID_HANDLE"), + SMB_NTSTATUS_BAD_INITIAL_STACK => Some("STATUS_BAD_INITIAL_STACK"), + SMB_NTSTATUS_BAD_INITIAL_PC => Some("STATUS_BAD_INITIAL_PC"), + SMB_NTSTATUS_INVALID_CID => Some("STATUS_INVALID_CID"), + SMB_NTSTATUS_TIMER_NOT_CANCELED => Some("STATUS_TIMER_NOT_CANCELED"), + SMB_NTSTATUS_INVALID_PARAMETER => Some("STATUS_INVALID_PARAMETER"), + SMB_NTSTATUS_NO_SUCH_DEVICE => Some("STATUS_NO_SUCH_DEVICE"), + SMB_NTSTATUS_NO_SUCH_FILE => Some("STATUS_NO_SUCH_FILE"), + SMB_NTSTATUS_INVALID_DEVICE_REQUEST => Some("STATUS_INVALID_DEVICE_REQUEST"), + SMB_NTSTATUS_END_OF_FILE => Some("STATUS_END_OF_FILE"), + SMB_NTSTATUS_WRONG_VOLUME => Some("STATUS_WRONG_VOLUME"), + SMB_NTSTATUS_NO_MEDIA_IN_DEVICE => Some("STATUS_NO_MEDIA_IN_DEVICE"), + SMB_NTSTATUS_UNRECOGNIZED_MEDIA => Some("STATUS_UNRECOGNIZED_MEDIA"), + SMB_NTSTATUS_NONEXISTENT_SECTOR => Some("STATUS_NONEXISTENT_SECTOR"), + SMB_NTSTATUS_MORE_PROCESSING_REQUIRED => Some("STATUS_MORE_PROCESSING_REQUIRED"), + SMB_NTSTATUS_NO_MEMORY => Some("STATUS_NO_MEMORY"), + SMB_NTSTATUS_CONFLICTING_ADDRESSES => Some("STATUS_CONFLICTING_ADDRESSES"), + SMB_NTSTATUS_NOT_MAPPED_VIEW => Some("STATUS_NOT_MAPPED_VIEW"), + SMB_NTSTATUS_UNABLE_TO_FREE_VM => Some("STATUS_UNABLE_TO_FREE_VM"), + SMB_NTSTATUS_UNABLE_TO_DELETE_SECTION => Some("STATUS_UNABLE_TO_DELETE_SECTION"), + SMB_NTSTATUS_INVALID_SYSTEM_SERVICE => Some("STATUS_INVALID_SYSTEM_SERVICE"), + SMB_NTSTATUS_ILLEGAL_INSTRUCTION => Some("STATUS_ILLEGAL_INSTRUCTION"), + SMB_NTSTATUS_INVALID_LOCK_SEQUENCE => Some("STATUS_INVALID_LOCK_SEQUENCE"), + SMB_NTSTATUS_INVALID_VIEW_SIZE => Some("STATUS_INVALID_VIEW_SIZE"), + SMB_NTSTATUS_INVALID_FILE_FOR_SECTION => Some("STATUS_INVALID_FILE_FOR_SECTION"), + SMB_NTSTATUS_ALREADY_COMMITTED => Some("STATUS_ALREADY_COMMITTED"), + SMB_NTSTATUS_ACCESS_DENIED => Some("STATUS_ACCESS_DENIED"), + SMB_NTSTATUS_BUFFER_TOO_SMALL => Some("STATUS_BUFFER_TOO_SMALL"), + SMB_NTSTATUS_OBJECT_TYPE_MISMATCH => Some("STATUS_OBJECT_TYPE_MISMATCH"), + SMB_NTSTATUS_NONCONTINUABLE_EXCEPTION => Some("STATUS_NONCONTINUABLE_EXCEPTION"), + SMB_NTSTATUS_INVALID_DISPOSITION => Some("STATUS_INVALID_DISPOSITION"), + SMB_NTSTATUS_UNWIND => Some("STATUS_UNWIND"), + SMB_NTSTATUS_BAD_STACK => Some("STATUS_BAD_STACK"), + SMB_NTSTATUS_INVALID_UNWIND_TARGET => Some("STATUS_INVALID_UNWIND_TARGET"), + SMB_NTSTATUS_NOT_LOCKED => Some("STATUS_NOT_LOCKED"), + SMB_NTSTATUS_PARITY_ERROR => Some("STATUS_PARITY_ERROR"), + SMB_NTSTATUS_UNABLE_TO_DECOMMIT_VM => Some("STATUS_UNABLE_TO_DECOMMIT_VM"), + SMB_NTSTATUS_NOT_COMMITTED => Some("STATUS_NOT_COMMITTED"), + SMB_NTSTATUS_INVALID_PORT_ATTRIBUTES => Some("STATUS_INVALID_PORT_ATTRIBUTES"), + SMB_NTSTATUS_PORT_MESSAGE_TOO_LONG => Some("STATUS_PORT_MESSAGE_TOO_LONG"), + SMB_NTSTATUS_INVALID_PARAMETER_MIX => Some("STATUS_INVALID_PARAMETER_MIX"), + SMB_NTSTATUS_INVALID_QUOTA_LOWER => Some("STATUS_INVALID_QUOTA_LOWER"), + SMB_NTSTATUS_DISK_CORRUPT_ERROR => Some("STATUS_DISK_CORRUPT_ERROR"), + SMB_NTSTATUS_OBJECT_NAME_INVALID => Some("STATUS_OBJECT_NAME_INVALID"), + SMB_NTSTATUS_OBJECT_NAME_NOT_FOUND => Some("STATUS_OBJECT_NAME_NOT_FOUND"), + SMB_NTSTATUS_OBJECT_NAME_COLLISION => Some("STATUS_OBJECT_NAME_COLLISION"), + SMB_NTSTATUS_PORT_DISCONNECTED => Some("STATUS_PORT_DISCONNECTED"), + SMB_NTSTATUS_DEVICE_ALREADY_ATTACHED => Some("STATUS_DEVICE_ALREADY_ATTACHED"), + SMB_NTSTATUS_OBJECT_PATH_INVALID => Some("STATUS_OBJECT_PATH_INVALID"), + SMB_NTSTATUS_OBJECT_PATH_NOT_FOUND => Some("STATUS_OBJECT_PATH_NOT_FOUND"), + SMB_NTSTATUS_OBJECT_PATH_SYNTAX_BAD => Some("STATUS_OBJECT_PATH_SYNTAX_BAD"), + SMB_NTSTATUS_DATA_OVERRUN => Some("STATUS_DATA_OVERRUN"), + SMB_NTSTATUS_DATA_LATE_ERROR => Some("STATUS_DATA_LATE_ERROR"), + SMB_NTSTATUS_DATA_ERROR => Some("STATUS_DATA_ERROR"), + SMB_NTSTATUS_CRC_ERROR => Some("STATUS_CRC_ERROR"), + SMB_NTSTATUS_SECTION_TOO_BIG => Some("STATUS_SECTION_TOO_BIG"), + SMB_NTSTATUS_PORT_CONNECTION_REFUSED => Some("STATUS_PORT_CONNECTION_REFUSED"), + SMB_NTSTATUS_INVALID_PORT_HANDLE => Some("STATUS_INVALID_PORT_HANDLE"), + SMB_NTSTATUS_SHARING_VIOLATION => Some("STATUS_SHARING_VIOLATION"), + SMB_NTSTATUS_QUOTA_EXCEEDED => Some("STATUS_QUOTA_EXCEEDED"), + SMB_NTSTATUS_INVALID_PAGE_PROTECTION => Some("STATUS_INVALID_PAGE_PROTECTION"), + SMB_NTSTATUS_MUTANT_NOT_OWNED => Some("STATUS_MUTANT_NOT_OWNED"), + SMB_NTSTATUS_SEMAPHORE_LIMIT_EXCEEDED => Some("STATUS_SEMAPHORE_LIMIT_EXCEEDED"), + SMB_NTSTATUS_PORT_ALREADY_SET => Some("STATUS_PORT_ALREADY_SET"), + SMB_NTSTATUS_SECTION_NOT_IMAGE => Some("STATUS_SECTION_NOT_IMAGE"), + SMB_NTSTATUS_SUSPEND_COUNT_EXCEEDED => Some("STATUS_SUSPEND_COUNT_EXCEEDED"), + SMB_NTSTATUS_THREAD_IS_TERMINATING => Some("STATUS_THREAD_IS_TERMINATING"), + SMB_NTSTATUS_BAD_WORKING_SET_LIMIT => Some("STATUS_BAD_WORKING_SET_LIMIT"), + SMB_NTSTATUS_INCOMPATIBLE_FILE_MAP => Some("STATUS_INCOMPATIBLE_FILE_MAP"), + SMB_NTSTATUS_SECTION_PROTECTION => Some("STATUS_SECTION_PROTECTION"), + SMB_NTSTATUS_EAS_NOT_SUPPORTED => Some("STATUS_EAS_NOT_SUPPORTED"), + SMB_NTSTATUS_EA_TOO_LARGE => Some("STATUS_EA_TOO_LARGE"), + SMB_NTSTATUS_NONEXISTENT_EA_ENTRY => Some("STATUS_NONEXISTENT_EA_ENTRY"), + SMB_NTSTATUS_NO_EAS_ON_FILE => Some("STATUS_NO_EAS_ON_FILE"), + SMB_NTSTATUS_EA_CORRUPT_ERROR => Some("STATUS_EA_CORRUPT_ERROR"), + SMB_NTSTATUS_FILE_LOCK_CONFLICT => Some("STATUS_FILE_LOCK_CONFLICT"), + SMB_NTSTATUS_LOCK_NOT_GRANTED => Some("STATUS_LOCK_NOT_GRANTED"), + SMB_NTSTATUS_DELETE_PENDING => Some("STATUS_DELETE_PENDING"), + SMB_NTSTATUS_CTL_FILE_NOT_SUPPORTED => Some("STATUS_CTL_FILE_NOT_SUPPORTED"), + SMB_NTSTATUS_UNKNOWN_REVISION => Some("STATUS_UNKNOWN_REVISION"), + SMB_NTSTATUS_REVISION_MISMATCH => Some("STATUS_REVISION_MISMATCH"), + SMB_NTSTATUS_INVALID_OWNER => Some("STATUS_INVALID_OWNER"), + SMB_NTSTATUS_INVALID_PRIMARY_GROUP => Some("STATUS_INVALID_PRIMARY_GROUP"), + SMB_NTSTATUS_NO_IMPERSONATION_TOKEN => Some("STATUS_NO_IMPERSONATION_TOKEN"), + SMB_NTSTATUS_CANT_DISABLE_MANDATORY => Some("STATUS_CANT_DISABLE_MANDATORY"), + SMB_NTSTATUS_NO_LOGON_SERVERS => Some("STATUS_NO_LOGON_SERVERS"), + SMB_NTSTATUS_NO_SUCH_LOGON_SESSION => Some("STATUS_NO_SUCH_LOGON_SESSION"), + SMB_NTSTATUS_NO_SUCH_PRIVILEGE => Some("STATUS_NO_SUCH_PRIVILEGE"), + SMB_NTSTATUS_PRIVILEGE_NOT_HELD => Some("STATUS_PRIVILEGE_NOT_HELD"), + SMB_NTSTATUS_INVALID_ACCOUNT_NAME => Some("STATUS_INVALID_ACCOUNT_NAME"), + SMB_NTSTATUS_USER_EXISTS => Some("STATUS_USER_EXISTS"), + SMB_NTSTATUS_NO_SUCH_USER => Some("STATUS_NO_SUCH_USER"), + SMB_NTSTATUS_GROUP_EXISTS => Some("STATUS_GROUP_EXISTS"), + SMB_NTSTATUS_NO_SUCH_GROUP => Some("STATUS_NO_SUCH_GROUP"), + SMB_NTSTATUS_MEMBER_IN_GROUP => Some("STATUS_MEMBER_IN_GROUP"), + SMB_NTSTATUS_MEMBER_NOT_IN_GROUP => Some("STATUS_MEMBER_NOT_IN_GROUP"), + SMB_NTSTATUS_LAST_ADMIN => Some("STATUS_LAST_ADMIN"), + SMB_NTSTATUS_WRONG_PASSWORD => Some("STATUS_WRONG_PASSWORD"), + SMB_NTSTATUS_ILL_FORMED_PASSWORD => Some("STATUS_ILL_FORMED_PASSWORD"), + SMB_NTSTATUS_PASSWORD_RESTRICTION => Some("STATUS_PASSWORD_RESTRICTION"), + SMB_NTSTATUS_LOGON_FAILURE => Some("STATUS_LOGON_FAILURE"), + SMB_NTSTATUS_ACCOUNT_RESTRICTION => Some("STATUS_ACCOUNT_RESTRICTION"), + SMB_NTSTATUS_INVALID_LOGON_HOURS => Some("STATUS_INVALID_LOGON_HOURS"), + SMB_NTSTATUS_INVALID_WORKSTATION => Some("STATUS_INVALID_WORKSTATION"), + SMB_NTSTATUS_PASSWORD_EXPIRED => Some("STATUS_PASSWORD_EXPIRED"), + SMB_NTSTATUS_ACCOUNT_DISABLED => Some("STATUS_ACCOUNT_DISABLED"), + SMB_NTSTATUS_NONE_MAPPED => Some("STATUS_NONE_MAPPED"), + SMB_NTSTATUS_TOO_MANY_LUIDS_REQUESTED => Some("STATUS_TOO_MANY_LUIDS_REQUESTED"), + SMB_NTSTATUS_LUIDS_EXHAUSTED => Some("STATUS_LUIDS_EXHAUSTED"), + SMB_NTSTATUS_INVALID_SUB_AUTHORITY => Some("STATUS_INVALID_SUB_AUTHORITY"), + SMB_NTSTATUS_INVALID_ACL => Some("STATUS_INVALID_ACL"), + SMB_NTSTATUS_INVALID_SID => Some("STATUS_INVALID_SID"), + SMB_NTSTATUS_INVALID_SECURITY_DESCR => Some("STATUS_INVALID_SECURITY_DESCR"), + SMB_NTSTATUS_PROCEDURE_NOT_FOUND => Some("STATUS_PROCEDURE_NOT_FOUND"), + SMB_NTSTATUS_INVALID_IMAGE_FORMAT => Some("STATUS_INVALID_IMAGE_FORMAT"), + SMB_NTSTATUS_NO_TOKEN => Some("STATUS_NO_TOKEN"), + SMB_NTSTATUS_BAD_INHERITANCE_ACL => Some("STATUS_BAD_INHERITANCE_ACL"), + SMB_NTSTATUS_RANGE_NOT_LOCKED => Some("STATUS_RANGE_NOT_LOCKED"), + SMB_NTSTATUS_DISK_FULL => Some("STATUS_DISK_FULL"), + SMB_NTSTATUS_SERVER_DISABLED => Some("STATUS_SERVER_DISABLED"), + SMB_NTSTATUS_SERVER_NOT_DISABLED => Some("STATUS_SERVER_NOT_DISABLED"), + SMB_NTSTATUS_TOO_MANY_GUIDS_REQUESTED => Some("STATUS_TOO_MANY_GUIDS_REQUESTED"), + SMB_NTSTATUS_GUIDS_EXHAUSTED => Some("STATUS_GUIDS_EXHAUSTED"), + SMB_NTSTATUS_INVALID_ID_AUTHORITY => Some("STATUS_INVALID_ID_AUTHORITY"), + SMB_NTSTATUS_AGENTS_EXHAUSTED => Some("STATUS_AGENTS_EXHAUSTED"), + SMB_NTSTATUS_INVALID_VOLUME_LABEL => Some("STATUS_INVALID_VOLUME_LABEL"), + SMB_NTSTATUS_SECTION_NOT_EXTENDED => Some("STATUS_SECTION_NOT_EXTENDED"), + SMB_NTSTATUS_NOT_MAPPED_DATA => Some("STATUS_NOT_MAPPED_DATA"), + SMB_NTSTATUS_RESOURCE_DATA_NOT_FOUND => Some("STATUS_RESOURCE_DATA_NOT_FOUND"), + SMB_NTSTATUS_RESOURCE_TYPE_NOT_FOUND => Some("STATUS_RESOURCE_TYPE_NOT_FOUND"), + SMB_NTSTATUS_RESOURCE_NAME_NOT_FOUND => Some("STATUS_RESOURCE_NAME_NOT_FOUND"), + SMB_NTSTATUS_ARRAY_BOUNDS_EXCEEDED => Some("STATUS_ARRAY_BOUNDS_EXCEEDED"), + SMB_NTSTATUS_FLOAT_DENORMAL_OPERAND => Some("STATUS_FLOAT_DENORMAL_OPERAND"), + SMB_NTSTATUS_FLOAT_DIVIDE_BY_ZERO => Some("STATUS_FLOAT_DIVIDE_BY_ZERO"), + SMB_NTSTATUS_FLOAT_INEXACT_RESULT => Some("STATUS_FLOAT_INEXACT_RESULT"), + SMB_NTSTATUS_FLOAT_INVALID_OPERATION => Some("STATUS_FLOAT_INVALID_OPERATION"), + SMB_NTSTATUS_FLOAT_OVERFLOW => Some("STATUS_FLOAT_OVERFLOW"), + SMB_NTSTATUS_FLOAT_STACK_CHECK => Some("STATUS_FLOAT_STACK_CHECK"), + SMB_NTSTATUS_FLOAT_UNDERFLOW => Some("STATUS_FLOAT_UNDERFLOW"), + SMB_NTSTATUS_INTEGER_DIVIDE_BY_ZERO => Some("STATUS_INTEGER_DIVIDE_BY_ZERO"), + SMB_NTSTATUS_INTEGER_OVERFLOW => Some("STATUS_INTEGER_OVERFLOW"), + SMB_NTSTATUS_PRIVILEGED_INSTRUCTION => Some("STATUS_PRIVILEGED_INSTRUCTION"), + SMB_NTSTATUS_TOO_MANY_PAGING_FILES => Some("STATUS_TOO_MANY_PAGING_FILES"), + SMB_NTSTATUS_FILE_INVALID => Some("STATUS_FILE_INVALID"), + SMB_NTSTATUS_ALLOTTED_SPACE_EXCEEDED => Some("STATUS_ALLOTTED_SPACE_EXCEEDED"), + SMB_NTSTATUS_INSUFFICIENT_RESOURCES => Some("STATUS_INSUFFICIENT_RESOURCES"), + SMB_NTSTATUS_DFS_EXIT_PATH_FOUND => Some("STATUS_DFS_EXIT_PATH_FOUND"), + SMB_NTSTATUS_DEVICE_DATA_ERROR => Some("STATUS_DEVICE_DATA_ERROR"), + SMB_NTSTATUS_DEVICE_NOT_CONNECTED => Some("STATUS_DEVICE_NOT_CONNECTED"), + SMB_NTSTATUS_FREE_VM_NOT_AT_BASE => Some("STATUS_FREE_VM_NOT_AT_BASE"), + SMB_NTSTATUS_MEMORY_NOT_ALLOCATED => Some("STATUS_MEMORY_NOT_ALLOCATED"), + SMB_NTSTATUS_WORKING_SET_QUOTA => Some("STATUS_WORKING_SET_QUOTA"), + SMB_NTSTATUS_MEDIA_WRITE_PROTECTED => Some("STATUS_MEDIA_WRITE_PROTECTED"), + SMB_NTSTATUS_DEVICE_NOT_READY => Some("STATUS_DEVICE_NOT_READY"), + SMB_NTSTATUS_INVALID_GROUP_ATTRIBUTES => Some("STATUS_INVALID_GROUP_ATTRIBUTES"), + SMB_NTSTATUS_BAD_IMPERSONATION_LEVEL => Some("STATUS_BAD_IMPERSONATION_LEVEL"), + SMB_NTSTATUS_CANT_OPEN_ANONYMOUS => Some("STATUS_CANT_OPEN_ANONYMOUS"), + SMB_NTSTATUS_BAD_VALIDATION_CLASS => Some("STATUS_BAD_VALIDATION_CLASS"), + SMB_NTSTATUS_BAD_TOKEN_TYPE => Some("STATUS_BAD_TOKEN_TYPE"), + SMB_NTSTATUS_BAD_MASTER_BOOT_RECORD => Some("STATUS_BAD_MASTER_BOOT_RECORD"), + SMB_NTSTATUS_INSTRUCTION_MISALIGNMENT => Some("STATUS_INSTRUCTION_MISALIGNMENT"), + SMB_NTSTATUS_INSTANCE_NOT_AVAILABLE => Some("STATUS_INSTANCE_NOT_AVAILABLE"), + SMB_NTSTATUS_PIPE_NOT_AVAILABLE => Some("STATUS_PIPE_NOT_AVAILABLE"), + SMB_NTSTATUS_INVALID_PIPE_STATE => Some("STATUS_INVALID_PIPE_STATE"), + SMB_NTSTATUS_PIPE_BUSY => Some("STATUS_PIPE_BUSY"), + SMB_NTSTATUS_ILLEGAL_FUNCTION => Some("STATUS_ILLEGAL_FUNCTION"), + SMB_NTSTATUS_PIPE_DISCONNECTED => Some("STATUS_PIPE_DISCONNECTED"), + SMB_NTSTATUS_PIPE_CLOSING => Some("STATUS_PIPE_CLOSING"), + SMB_NTSTATUS_PIPE_CONNECTED => Some("STATUS_PIPE_CONNECTED"), + SMB_NTSTATUS_PIPE_LISTENING => Some("STATUS_PIPE_LISTENING"), + SMB_NTSTATUS_INVALID_READ_MODE => Some("STATUS_INVALID_READ_MODE"), + SMB_NTSTATUS_IO_TIMEOUT => Some("STATUS_IO_TIMEOUT"), + SMB_NTSTATUS_FILE_FORCED_CLOSED => Some("STATUS_FILE_FORCED_CLOSED"), + SMB_NTSTATUS_PROFILING_NOT_STARTED => Some("STATUS_PROFILING_NOT_STARTED"), + SMB_NTSTATUS_PROFILING_NOT_STOPPED => Some("STATUS_PROFILING_NOT_STOPPED"), + SMB_NTSTATUS_COULD_NOT_INTERPRET => Some("STATUS_COULD_NOT_INTERPRET"), + SMB_NTSTATUS_FILE_IS_A_DIRECTORY => Some("STATUS_FILE_IS_A_DIRECTORY"), + SMB_NTSTATUS_NOT_SUPPORTED => Some("STATUS_NOT_SUPPORTED"), + SMB_NTSTATUS_REMOTE_NOT_LISTENING => Some("STATUS_REMOTE_NOT_LISTENING"), + SMB_NTSTATUS_DUPLICATE_NAME => Some("STATUS_DUPLICATE_NAME"), + SMB_NTSTATUS_BAD_NETWORK_PATH => Some("STATUS_BAD_NETWORK_PATH"), + SMB_NTSTATUS_NETWORK_BUSY => Some("STATUS_NETWORK_BUSY"), + SMB_NTSTATUS_DEVICE_DOES_NOT_EXIST => Some("STATUS_DEVICE_DOES_NOT_EXIST"), + SMB_NTSTATUS_TOO_MANY_COMMANDS => Some("STATUS_TOO_MANY_COMMANDS"), + SMB_NTSTATUS_ADAPTER_HARDWARE_ERROR => Some("STATUS_ADAPTER_HARDWARE_ERROR"), + SMB_NTSTATUS_INVALID_NETWORK_RESPONSE => Some("STATUS_INVALID_NETWORK_RESPONSE"), + SMB_NTSTATUS_UNEXPECTED_NETWORK_ERROR => Some("STATUS_UNEXPECTED_NETWORK_ERROR"), + SMB_NTSTATUS_BAD_REMOTE_ADAPTER => Some("STATUS_BAD_REMOTE_ADAPTER"), + SMB_NTSTATUS_PRINT_QUEUE_FULL => Some("STATUS_PRINT_QUEUE_FULL"), + SMB_NTSTATUS_NO_SPOOL_SPACE => Some("STATUS_NO_SPOOL_SPACE"), + SMB_NTSTATUS_PRINT_CANCELLED => Some("STATUS_PRINT_CANCELLED"), + SMB_NTSTATUS_NETWORK_NAME_DELETED => Some("STATUS_NETWORK_NAME_DELETED"), + SMB_NTSTATUS_NETWORK_ACCESS_DENIED => Some("STATUS_NETWORK_ACCESS_DENIED"), + SMB_NTSTATUS_BAD_DEVICE_TYPE => Some("STATUS_BAD_DEVICE_TYPE"), + SMB_NTSTATUS_BAD_NETWORK_NAME => Some("STATUS_BAD_NETWORK_NAME"), + SMB_NTSTATUS_TOO_MANY_NAMES => Some("STATUS_TOO_MANY_NAMES"), + SMB_NTSTATUS_TOO_MANY_SESSIONS => Some("STATUS_TOO_MANY_SESSIONS"), + SMB_NTSTATUS_SHARING_PAUSED => Some("STATUS_SHARING_PAUSED"), + SMB_NTSTATUS_REQUEST_NOT_ACCEPTED => Some("STATUS_REQUEST_NOT_ACCEPTED"), + SMB_NTSTATUS_REDIRECTOR_PAUSED => Some("STATUS_REDIRECTOR_PAUSED"), + SMB_NTSTATUS_NET_WRITE_FAULT => Some("STATUS_NET_WRITE_FAULT"), + SMB_NTSTATUS_PROFILING_AT_LIMIT => Some("STATUS_PROFILING_AT_LIMIT"), + SMB_NTSTATUS_NOT_SAME_DEVICE => Some("STATUS_NOT_SAME_DEVICE"), + SMB_NTSTATUS_FILE_RENAMED => Some("STATUS_FILE_RENAMED"), + SMB_NTSTATUS_VIRTUAL_CIRCUIT_CLOSED => Some("STATUS_VIRTUAL_CIRCUIT_CLOSED"), + SMB_NTSTATUS_NO_SECURITY_ON_OBJECT => Some("STATUS_NO_SECURITY_ON_OBJECT"), + SMB_NTSTATUS_CANT_WAIT => Some("STATUS_CANT_WAIT"), + SMB_NTSTATUS_PIPE_EMPTY => Some("STATUS_PIPE_EMPTY"), + SMB_NTSTATUS_CANT_ACCESS_DOMAIN_INFO => Some("STATUS_CANT_ACCESS_DOMAIN_INFO"), + SMB_NTSTATUS_CANT_TERMINATE_SELF => Some("STATUS_CANT_TERMINATE_SELF"), + SMB_NTSTATUS_INVALID_SERVER_STATE => Some("STATUS_INVALID_SERVER_STATE"), + SMB_NTSTATUS_INVALID_DOMAIN_STATE => Some("STATUS_INVALID_DOMAIN_STATE"), + SMB_NTSTATUS_INVALID_DOMAIN_ROLE => Some("STATUS_INVALID_DOMAIN_ROLE"), + SMB_NTSTATUS_NO_SUCH_DOMAIN => Some("STATUS_NO_SUCH_DOMAIN"), + SMB_NTSTATUS_DOMAIN_EXISTS => Some("STATUS_DOMAIN_EXISTS"), + SMB_NTSTATUS_DOMAIN_LIMIT_EXCEEDED => Some("STATUS_DOMAIN_LIMIT_EXCEEDED"), + SMB_NTSTATUS_OPLOCK_NOT_GRANTED => Some("STATUS_OPLOCK_NOT_GRANTED"), + SMB_NTSTATUS_INVALID_OPLOCK_PROTOCOL => Some("STATUS_INVALID_OPLOCK_PROTOCOL"), + SMB_NTSTATUS_INTERNAL_DB_CORRUPTION => Some("STATUS_INTERNAL_DB_CORRUPTION"), + SMB_NTSTATUS_INTERNAL_ERROR => Some("STATUS_INTERNAL_ERROR"), + SMB_NTSTATUS_GENERIC_NOT_MAPPED => Some("STATUS_GENERIC_NOT_MAPPED"), + SMB_NTSTATUS_BAD_DESCRIPTOR_FORMAT => Some("STATUS_BAD_DESCRIPTOR_FORMAT"), + SMB_NTSTATUS_INVALID_USER_BUFFER => Some("STATUS_INVALID_USER_BUFFER"), + SMB_NTSTATUS_UNEXPECTED_IO_ERROR => Some("STATUS_UNEXPECTED_IO_ERROR"), + SMB_NTSTATUS_UNEXPECTED_MM_CREATE_ERR => Some("STATUS_UNEXPECTED_MM_CREATE_ERR"), + SMB_NTSTATUS_UNEXPECTED_MM_MAP_ERROR => Some("STATUS_UNEXPECTED_MM_MAP_ERROR"), + SMB_NTSTATUS_UNEXPECTED_MM_EXTEND_ERR => Some("STATUS_UNEXPECTED_MM_EXTEND_ERR"), + SMB_NTSTATUS_NOT_LOGON_PROCESS => Some("STATUS_NOT_LOGON_PROCESS"), + SMB_NTSTATUS_LOGON_SESSION_EXISTS => Some("STATUS_LOGON_SESSION_EXISTS"), + SMB_NTSTATUS_INVALID_PARAMETER_1 => Some("STATUS_INVALID_PARAMETER_1"), + SMB_NTSTATUS_INVALID_PARAMETER_2 => Some("STATUS_INVALID_PARAMETER_2"), + SMB_NTSTATUS_INVALID_PARAMETER_3 => Some("STATUS_INVALID_PARAMETER_3"), + SMB_NTSTATUS_INVALID_PARAMETER_4 => Some("STATUS_INVALID_PARAMETER_4"), + SMB_NTSTATUS_INVALID_PARAMETER_5 => Some("STATUS_INVALID_PARAMETER_5"), + SMB_NTSTATUS_INVALID_PARAMETER_6 => Some("STATUS_INVALID_PARAMETER_6"), + SMB_NTSTATUS_INVALID_PARAMETER_7 => Some("STATUS_INVALID_PARAMETER_7"), + SMB_NTSTATUS_INVALID_PARAMETER_8 => Some("STATUS_INVALID_PARAMETER_8"), + SMB_NTSTATUS_INVALID_PARAMETER_9 => Some("STATUS_INVALID_PARAMETER_9"), + SMB_NTSTATUS_INVALID_PARAMETER_10 => Some("STATUS_INVALID_PARAMETER_10"), + SMB_NTSTATUS_INVALID_PARAMETER_11 => Some("STATUS_INVALID_PARAMETER_11"), + SMB_NTSTATUS_INVALID_PARAMETER_12 => Some("STATUS_INVALID_PARAMETER_12"), + SMB_NTSTATUS_REDIRECTOR_NOT_STARTED => Some("STATUS_REDIRECTOR_NOT_STARTED"), + SMB_NTSTATUS_REDIRECTOR_STARTED => Some("STATUS_REDIRECTOR_STARTED"), + SMB_NTSTATUS_STACK_OVERFLOW => Some("STATUS_STACK_OVERFLOW"), + SMB_NTSTATUS_NO_SUCH_PACKAGE => Some("STATUS_NO_SUCH_PACKAGE"), + SMB_NTSTATUS_BAD_FUNCTION_TABLE => Some("STATUS_BAD_FUNCTION_TABLE"), + SMB_NTSTATUS_VARIABLE_NOT_FOUND => Some("STATUS_VARIABLE_NOT_FOUND"), + SMB_NTSTATUS_DIRECTORY_NOT_EMPTY => Some("STATUS_DIRECTORY_NOT_EMPTY"), + SMB_NTSTATUS_FILE_CORRUPT_ERROR => Some("STATUS_FILE_CORRUPT_ERROR"), + SMB_NTSTATUS_NOT_A_DIRECTORY => Some("STATUS_NOT_A_DIRECTORY"), + SMB_NTSTATUS_BAD_LOGON_SESSION_STATE => Some("STATUS_BAD_LOGON_SESSION_STATE"), + SMB_NTSTATUS_LOGON_SESSION_COLLISION => Some("STATUS_LOGON_SESSION_COLLISION"), + SMB_NTSTATUS_NAME_TOO_LONG => Some("STATUS_NAME_TOO_LONG"), + SMB_NTSTATUS_FILES_OPEN => Some("STATUS_FILES_OPEN"), + SMB_NTSTATUS_CONNECTION_IN_USE => Some("STATUS_CONNECTION_IN_USE"), + SMB_NTSTATUS_MESSAGE_NOT_FOUND => Some("STATUS_MESSAGE_NOT_FOUND"), + SMB_NTSTATUS_PROCESS_IS_TERMINATING => Some("STATUS_PROCESS_IS_TERMINATING"), + SMB_NTSTATUS_INVALID_LOGON_TYPE => Some("STATUS_INVALID_LOGON_TYPE"), + SMB_NTSTATUS_NO_GUID_TRANSLATION => Some("STATUS_NO_GUID_TRANSLATION"), + SMB_NTSTATUS_CANNOT_IMPERSONATE => Some("STATUS_CANNOT_IMPERSONATE"), + SMB_NTSTATUS_IMAGE_ALREADY_LOADED => Some("STATUS_IMAGE_ALREADY_LOADED"), + SMB_NTSTATUS_NO_LDT => Some("STATUS_NO_LDT"), + SMB_NTSTATUS_INVALID_LDT_SIZE => Some("STATUS_INVALID_LDT_SIZE"), + SMB_NTSTATUS_INVALID_LDT_OFFSET => Some("STATUS_INVALID_LDT_OFFSET"), + SMB_NTSTATUS_INVALID_LDT_DESCRIPTOR => Some("STATUS_INVALID_LDT_DESCRIPTOR"), + SMB_NTSTATUS_INVALID_IMAGE_NE_FORMAT => Some("STATUS_INVALID_IMAGE_NE_FORMAT"), + SMB_NTSTATUS_RXACT_INVALID_STATE => Some("STATUS_RXACT_INVALID_STATE"), + SMB_NTSTATUS_RXACT_COMMIT_FAILURE => Some("STATUS_RXACT_COMMIT_FAILURE"), + SMB_NTSTATUS_MAPPED_FILE_SIZE_ZERO => Some("STATUS_MAPPED_FILE_SIZE_ZERO"), + SMB_NTSTATUS_TOO_MANY_OPENED_FILES => Some("STATUS_TOO_MANY_OPENED_FILES"), + SMB_NTSTATUS_CANCELLED => Some("STATUS_CANCELLED"), + SMB_NTSTATUS_CANNOT_DELETE => Some("STATUS_CANNOT_DELETE"), + SMB_NTSTATUS_INVALID_COMPUTER_NAME => Some("STATUS_INVALID_COMPUTER_NAME"), + SMB_NTSTATUS_FILE_DELETED => Some("STATUS_FILE_DELETED"), + SMB_NTSTATUS_SPECIAL_ACCOUNT => Some("STATUS_SPECIAL_ACCOUNT"), + SMB_NTSTATUS_SPECIAL_GROUP => Some("STATUS_SPECIAL_GROUP"), + SMB_NTSTATUS_SPECIAL_USER => Some("STATUS_SPECIAL_USER"), + SMB_NTSTATUS_MEMBERS_PRIMARY_GROUP => Some("STATUS_MEMBERS_PRIMARY_GROUP"), + SMB_NTSTATUS_FILE_CLOSED => Some("STATUS_FILE_CLOSED"), + SMB_NTSTATUS_TOO_MANY_THREADS => Some("STATUS_TOO_MANY_THREADS"), + SMB_NTSTATUS_THREAD_NOT_IN_PROCESS => Some("STATUS_THREAD_NOT_IN_PROCESS"), + SMB_NTSTATUS_TOKEN_ALREADY_IN_USE => Some("STATUS_TOKEN_ALREADY_IN_USE"), + SMB_NTSTATUS_PAGEFILE_QUOTA_EXCEEDED => Some("STATUS_PAGEFILE_QUOTA_EXCEEDED"), + SMB_NTSTATUS_COMMITMENT_LIMIT => Some("STATUS_COMMITMENT_LIMIT"), + SMB_NTSTATUS_INVALID_IMAGE_LE_FORMAT => Some("STATUS_INVALID_IMAGE_LE_FORMAT"), + SMB_NTSTATUS_INVALID_IMAGE_NOT_MZ => Some("STATUS_INVALID_IMAGE_NOT_MZ"), + SMB_NTSTATUS_INVALID_IMAGE_PROTECT => Some("STATUS_INVALID_IMAGE_PROTECT"), + SMB_NTSTATUS_INVALID_IMAGE_WIN_16 => Some("STATUS_INVALID_IMAGE_WIN_16"), + SMB_NTSTATUS_LOGON_SERVER_CONFLICT => Some("STATUS_LOGON_SERVER_CONFLICT"), + SMB_NTSTATUS_TIME_DIFFERENCE_AT_DC => Some("STATUS_TIME_DIFFERENCE_AT_DC"), + SMB_NTSTATUS_SYNCHRONIZATION_REQUIRED => Some("STATUS_SYNCHRONIZATION_REQUIRED"), + SMB_NTSTATUS_DLL_NOT_FOUND => Some("STATUS_DLL_NOT_FOUND"), + SMB_NTSTATUS_OPEN_FAILED => Some("STATUS_OPEN_FAILED"), + SMB_NTSTATUS_IO_PRIVILEGE_FAILED => Some("STATUS_IO_PRIVILEGE_FAILED"), + SMB_NTSTATUS_ORDINAL_NOT_FOUND => Some("STATUS_ORDINAL_NOT_FOUND"), + SMB_NTSTATUS_ENTRYPOINT_NOT_FOUND => Some("STATUS_ENTRYPOINT_NOT_FOUND"), + SMB_NTSTATUS_CONTROL_C_EXIT => Some("STATUS_CONTROL_C_EXIT"), + SMB_NTSTATUS_LOCAL_DISCONNECT => Some("STATUS_LOCAL_DISCONNECT"), + SMB_NTSTATUS_REMOTE_DISCONNECT => Some("STATUS_REMOTE_DISCONNECT"), + SMB_NTSTATUS_REMOTE_RESOURCES => Some("STATUS_REMOTE_RESOURCES"), + SMB_NTSTATUS_LINK_FAILED => Some("STATUS_LINK_FAILED"), + SMB_NTSTATUS_LINK_TIMEOUT => Some("STATUS_LINK_TIMEOUT"), + SMB_NTSTATUS_INVALID_CONNECTION => Some("STATUS_INVALID_CONNECTION"), + SMB_NTSTATUS_INVALID_ADDRESS => Some("STATUS_INVALID_ADDRESS"), + SMB_NTSTATUS_DLL_INIT_FAILED => Some("STATUS_DLL_INIT_FAILED"), + SMB_NTSTATUS_MISSING_SYSTEMFILE => Some("STATUS_MISSING_SYSTEMFILE"), + SMB_NTSTATUS_UNHANDLED_EXCEPTION => Some("STATUS_UNHANDLED_EXCEPTION"), + SMB_NTSTATUS_APP_INIT_FAILURE => Some("STATUS_APP_INIT_FAILURE"), + SMB_NTSTATUS_PAGEFILE_CREATE_FAILED => Some("STATUS_PAGEFILE_CREATE_FAILED"), + SMB_NTSTATUS_NO_PAGEFILE => Some("STATUS_NO_PAGEFILE"), + SMB_NTSTATUS_INVALID_LEVEL => Some("STATUS_INVALID_LEVEL"), + SMB_NTSTATUS_WRONG_PASSWORD_CORE => Some("STATUS_WRONG_PASSWORD_CORE"), + SMB_NTSTATUS_ILLEGAL_FLOAT_CONTEXT => Some("STATUS_ILLEGAL_FLOAT_CONTEXT"), + SMB_NTSTATUS_PIPE_BROKEN => Some("STATUS_PIPE_BROKEN"), + SMB_NTSTATUS_REGISTRY_CORRUPT => Some("STATUS_REGISTRY_CORRUPT"), + SMB_NTSTATUS_REGISTRY_IO_FAILED => Some("STATUS_REGISTRY_IO_FAILED"), + SMB_NTSTATUS_NO_EVENT_PAIR => Some("STATUS_NO_EVENT_PAIR"), + SMB_NTSTATUS_UNRECOGNIZED_VOLUME => Some("STATUS_UNRECOGNIZED_VOLUME"), + SMB_NTSTATUS_SERIAL_NO_DEVICE_INITED => Some("STATUS_SERIAL_NO_DEVICE_INITED"), + SMB_NTSTATUS_NO_SUCH_ALIAS => Some("STATUS_NO_SUCH_ALIAS"), + SMB_NTSTATUS_MEMBER_NOT_IN_ALIAS => Some("STATUS_MEMBER_NOT_IN_ALIAS"), + SMB_NTSTATUS_MEMBER_IN_ALIAS => Some("STATUS_MEMBER_IN_ALIAS"), + SMB_NTSTATUS_ALIAS_EXISTS => Some("STATUS_ALIAS_EXISTS"), + SMB_NTSTATUS_LOGON_NOT_GRANTED => Some("STATUS_LOGON_NOT_GRANTED"), + SMB_NTSTATUS_TOO_MANY_SECRETS => Some("STATUS_TOO_MANY_SECRETS"), + SMB_NTSTATUS_SECRET_TOO_LONG => Some("STATUS_SECRET_TOO_LONG"), + SMB_NTSTATUS_INTERNAL_DB_ERROR => Some("STATUS_INTERNAL_DB_ERROR"), + SMB_NTSTATUS_FULLSCREEN_MODE => Some("STATUS_FULLSCREEN_MODE"), + SMB_NTSTATUS_TOO_MANY_CONTEXT_IDS => Some("STATUS_TOO_MANY_CONTEXT_IDS"), + SMB_NTSTATUS_LOGON_TYPE_NOT_GRANTED => Some("STATUS_LOGON_TYPE_NOT_GRANTED"), + SMB_NTSTATUS_NOT_REGISTRY_FILE => Some("STATUS_NOT_REGISTRY_FILE"), + SMB_NTSTATUS_NT_CROSS_ENCRYPTION_REQUIRED => Some("STATUS_NT_CROSS_ENCRYPTION_REQUIRED"), + SMB_NTSTATUS_DOMAIN_CTRLR_CONFIG_ERROR => Some("STATUS_DOMAIN_CTRLR_CONFIG_ERROR"), + SMB_NTSTATUS_FT_MISSING_MEMBER => Some("STATUS_FT_MISSING_MEMBER"), + SMB_NTSTATUS_ILL_FORMED_SERVICE_ENTRY => Some("STATUS_ILL_FORMED_SERVICE_ENTRY"), + SMB_NTSTATUS_ILLEGAL_CHARACTER => Some("STATUS_ILLEGAL_CHARACTER"), + SMB_NTSTATUS_UNMAPPABLE_CHARACTER => Some("STATUS_UNMAPPABLE_CHARACTER"), + SMB_NTSTATUS_UNDEFINED_CHARACTER => Some("STATUS_UNDEFINED_CHARACTER"), + SMB_NTSTATUS_FLOPPY_VOLUME => Some("STATUS_FLOPPY_VOLUME"), + SMB_NTSTATUS_FLOPPY_ID_MARK_NOT_FOUND => Some("STATUS_FLOPPY_ID_MARK_NOT_FOUND"), + SMB_NTSTATUS_FLOPPY_WRONG_CYLINDER => Some("STATUS_FLOPPY_WRONG_CYLINDER"), + SMB_NTSTATUS_FLOPPY_UNKNOWN_ERROR => Some("STATUS_FLOPPY_UNKNOWN_ERROR"), + SMB_NTSTATUS_FLOPPY_BAD_REGISTERS => Some("STATUS_FLOPPY_BAD_REGISTERS"), + SMB_NTSTATUS_DISK_RECALIBRATE_FAILED => Some("STATUS_DISK_RECALIBRATE_FAILED"), + SMB_NTSTATUS_DISK_OPERATION_FAILED => Some("STATUS_DISK_OPERATION_FAILED"), + SMB_NTSTATUS_DISK_RESET_FAILED => Some("STATUS_DISK_RESET_FAILED"), + SMB_NTSTATUS_SHARED_IRQ_BUSY => Some("STATUS_SHARED_IRQ_BUSY"), + SMB_NTSTATUS_FT_ORPHANING => Some("STATUS_FT_ORPHANING"), + SMB_NTSTATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT => { + Some("STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT") + } + SMB_NTSTATUS_PARTITION_FAILURE => Some("STATUS_PARTITION_FAILURE"), + SMB_NTSTATUS_INVALID_BLOCK_LENGTH => Some("STATUS_INVALID_BLOCK_LENGTH"), + SMB_NTSTATUS_DEVICE_NOT_PARTITIONED => Some("STATUS_DEVICE_NOT_PARTITIONED"), + SMB_NTSTATUS_UNABLE_TO_LOCK_MEDIA => Some("STATUS_UNABLE_TO_LOCK_MEDIA"), + SMB_NTSTATUS_UNABLE_TO_UNLOAD_MEDIA => Some("STATUS_UNABLE_TO_UNLOAD_MEDIA"), + SMB_NTSTATUS_EOM_OVERFLOW => Some("STATUS_EOM_OVERFLOW"), + SMB_NTSTATUS_NO_MEDIA => Some("STATUS_NO_MEDIA"), + SMB_NTSTATUS_NO_SUCH_MEMBER => Some("STATUS_NO_SUCH_MEMBER"), + SMB_NTSTATUS_INVALID_MEMBER => Some("STATUS_INVALID_MEMBER"), + SMB_NTSTATUS_KEY_DELETED => Some("STATUS_KEY_DELETED"), + SMB_NTSTATUS_NO_LOG_SPACE => Some("STATUS_NO_LOG_SPACE"), + SMB_NTSTATUS_TOO_MANY_SIDS => Some("STATUS_TOO_MANY_SIDS"), + SMB_NTSTATUS_LM_CROSS_ENCRYPTION_REQUIRED => Some("STATUS_LM_CROSS_ENCRYPTION_REQUIRED"), + SMB_NTSTATUS_KEY_HAS_CHILDREN => Some("STATUS_KEY_HAS_CHILDREN"), + SMB_NTSTATUS_CHILD_MUST_BE_VOLATILE => Some("STATUS_CHILD_MUST_BE_VOLATILE"), + SMB_NTSTATUS_DEVICE_CONFIGURATION_ERROR => Some("STATUS_DEVICE_CONFIGURATION_ERROR"), + SMB_NTSTATUS_DRIVER_INTERNAL_ERROR => Some("STATUS_DRIVER_INTERNAL_ERROR"), + SMB_NTSTATUS_INVALID_DEVICE_STATE => Some("STATUS_INVALID_DEVICE_STATE"), + SMB_NTSTATUS_IO_DEVICE_ERROR => Some("STATUS_IO_DEVICE_ERROR"), + SMB_NTSTATUS_DEVICE_PROTOCOL_ERROR => Some("STATUS_DEVICE_PROTOCOL_ERROR"), + SMB_NTSTATUS_BACKUP_CONTROLLER => Some("STATUS_BACKUP_CONTROLLER"), + SMB_NTSTATUS_LOG_FILE_FULL => Some("STATUS_LOG_FILE_FULL"), + SMB_NTSTATUS_TOO_LATE => Some("STATUS_TOO_LATE"), + SMB_NTSTATUS_NO_TRUST_LSA_SECRET => Some("STATUS_NO_TRUST_LSA_SECRET"), + SMB_NTSTATUS_NO_TRUST_SAM_ACCOUNT => Some("STATUS_NO_TRUST_SAM_ACCOUNT"), + SMB_NTSTATUS_TRUSTED_DOMAIN_FAILURE => Some("STATUS_TRUSTED_DOMAIN_FAILURE"), + SMB_NTSTATUS_TRUSTED_RELATIONSHIP_FAILURE => Some("STATUS_TRUSTED_RELATIONSHIP_FAILURE"), + SMB_NTSTATUS_EVENTLOG_FILE_CORRUPT => Some("STATUS_EVENTLOG_FILE_CORRUPT"), + SMB_NTSTATUS_EVENTLOG_CANT_START => Some("STATUS_EVENTLOG_CANT_START"), + SMB_NTSTATUS_TRUST_FAILURE => Some("STATUS_TRUST_FAILURE"), + SMB_NTSTATUS_MUTANT_LIMIT_EXCEEDED => Some("STATUS_MUTANT_LIMIT_EXCEEDED"), + SMB_NTSTATUS_NETLOGON_NOT_STARTED => Some("STATUS_NETLOGON_NOT_STARTED"), + SMB_NTSTATUS_ACCOUNT_EXPIRED => Some("STATUS_ACCOUNT_EXPIRED"), + SMB_NTSTATUS_POSSIBLE_DEADLOCK => Some("STATUS_POSSIBLE_DEADLOCK"), + SMB_NTSTATUS_NETWORK_CREDENTIAL_CONFLICT => Some("STATUS_NETWORK_CREDENTIAL_CONFLICT"), + SMB_NTSTATUS_REMOTE_SESSION_LIMIT => Some("STATUS_REMOTE_SESSION_LIMIT"), + SMB_NTSTATUS_EVENTLOG_FILE_CHANGED => Some("STATUS_EVENTLOG_FILE_CHANGED"), + SMB_NTSTATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT => { + Some("STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT") + } + SMB_NTSTATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT => { + Some("STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT") + } + SMB_NTSTATUS_NOLOGON_SERVER_TRUST_ACCOUNT => Some("STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"), + SMB_NTSTATUS_DOMAIN_TRUST_INCONSISTENT => Some("STATUS_DOMAIN_TRUST_INCONSISTENT"), + SMB_NTSTATUS_FS_DRIVER_REQUIRED => Some("STATUS_FS_DRIVER_REQUIRED"), + SMB_NTSTATUS_IMAGE_ALREADY_LOADED_AS_DLL => Some("STATUS_IMAGE_ALREADY_LOADED_AS_DLL"), + SMB_NTSTATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING => { + Some("STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING") + } + SMB_NTSTATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME => { + Some("STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME") + } + SMB_NTSTATUS_SECURITY_STREAM_IS_INCONSISTENT => { + Some("STATUS_SECURITY_STREAM_IS_INCONSISTENT") + } + SMB_NTSTATUS_INVALID_LOCK_RANGE => Some("STATUS_INVALID_LOCK_RANGE"), + SMB_NTSTATUS_INVALID_ACE_CONDITION => Some("STATUS_INVALID_ACE_CONDITION"), + SMB_NTSTATUS_IMAGE_SUBSYSTEM_NOT_PRESENT => Some("STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT"), + SMB_NTSTATUS_NOTIFICATION_GUID_ALREADY_DEFINED => { + Some("STATUS_NOTIFICATION_GUID_ALREADY_DEFINED") + } + SMB_NTSTATUS_NETWORK_OPEN_RESTRICTION => Some("STATUS_NETWORK_OPEN_RESTRICTION"), + SMB_NTSTATUS_NO_USER_SESSION_KEY => Some("STATUS_NO_USER_SESSION_KEY"), + SMB_NTSTATUS_USER_SESSION_DELETED => Some("STATUS_USER_SESSION_DELETED"), + SMB_NTSTATUS_RESOURCE_LANG_NOT_FOUND => Some("STATUS_RESOURCE_LANG_NOT_FOUND"), + SMB_NTSTATUS_INSUFF_SERVER_RESOURCES => Some("STATUS_INSUFF_SERVER_RESOURCES"), + SMB_NTSTATUS_INVALID_BUFFER_SIZE => Some("STATUS_INVALID_BUFFER_SIZE"), + SMB_NTSTATUS_INVALID_ADDRESS_COMPONENT => Some("STATUS_INVALID_ADDRESS_COMPONENT"), + SMB_NTSTATUS_INVALID_ADDRESS_WILDCARD => Some("STATUS_INVALID_ADDRESS_WILDCARD"), + SMB_NTSTATUS_TOO_MANY_ADDRESSES => Some("STATUS_TOO_MANY_ADDRESSES"), + SMB_NTSTATUS_ADDRESS_ALREADY_EXISTS => Some("STATUS_ADDRESS_ALREADY_EXISTS"), + SMB_NTSTATUS_ADDRESS_CLOSED => Some("STATUS_ADDRESS_CLOSED"), + SMB_NTSTATUS_CONNECTION_DISCONNECTED => Some("STATUS_CONNECTION_DISCONNECTED"), + SMB_NTSTATUS_CONNECTION_RESET => Some("STATUS_CONNECTION_RESET"), + SMB_NTSTATUS_TOO_MANY_NODES => Some("STATUS_TOO_MANY_NODES"), + SMB_NTSTATUS_TRANSACTION_ABORTED => Some("STATUS_TRANSACTION_ABORTED"), + SMB_NTSTATUS_TRANSACTION_TIMED_OUT => Some("STATUS_TRANSACTION_TIMED_OUT"), + SMB_NTSTATUS_TRANSACTION_NO_RELEASE => Some("STATUS_TRANSACTION_NO_RELEASE"), + SMB_NTSTATUS_TRANSACTION_NO_MATCH => Some("STATUS_TRANSACTION_NO_MATCH"), + SMB_NTSTATUS_TRANSACTION_RESPONDED => Some("STATUS_TRANSACTION_RESPONDED"), + SMB_NTSTATUS_TRANSACTION_INVALID_ID => Some("STATUS_TRANSACTION_INVALID_ID"), + SMB_NTSTATUS_TRANSACTION_INVALID_TYPE => Some("STATUS_TRANSACTION_INVALID_TYPE"), + SMB_NTSTATUS_NOT_SERVER_SESSION => Some("STATUS_NOT_SERVER_SESSION"), + SMB_NTSTATUS_NOT_CLIENT_SESSION => Some("STATUS_NOT_CLIENT_SESSION"), + SMB_NTSTATUS_CANNOT_LOAD_REGISTRY_FILE => Some("STATUS_CANNOT_LOAD_REGISTRY_FILE"), + SMB_NTSTATUS_DEBUG_ATTACH_FAILED => Some("STATUS_DEBUG_ATTACH_FAILED"), + SMB_NTSTATUS_SYSTEM_PROCESS_TERMINATED => Some("STATUS_SYSTEM_PROCESS_TERMINATED"), + SMB_NTSTATUS_DATA_NOT_ACCEPTED => Some("STATUS_DATA_NOT_ACCEPTED"), + SMB_NTSTATUS_NO_BROWSER_SERVERS_FOUND => Some("STATUS_NO_BROWSER_SERVERS_FOUND"), + SMB_NTSTATUS_VDM_HARD_ERROR => Some("STATUS_VDM_HARD_ERROR"), + SMB_NTSTATUS_DRIVER_CANCEL_TIMEOUT => Some("STATUS_DRIVER_CANCEL_TIMEOUT"), + SMB_NTSTATUS_REPLY_MESSAGE_MISMATCH => Some("STATUS_REPLY_MESSAGE_MISMATCH"), + SMB_NTSTATUS_MAPPED_ALIGNMENT => Some("STATUS_MAPPED_ALIGNMENT"), + SMB_NTSTATUS_IMAGE_CHECKSUM_MISMATCH => Some("STATUS_IMAGE_CHECKSUM_MISMATCH"), + SMB_NTSTATUS_LOST_WRITEBEHIND_DATA => Some("STATUS_LOST_WRITEBEHIND_DATA"), + SMB_NTSTATUS_CLIENT_SERVER_PARAMETERS_INVALID => { + Some("STATUS_CLIENT_SERVER_PARAMETERS_INVALID") + } + SMB_NTSTATUS_PASSWORD_MUST_CHANGE => Some("STATUS_PASSWORD_MUST_CHANGE"), + SMB_NTSTATUS_NOT_FOUND => Some("STATUS_NOT_FOUND"), + SMB_NTSTATUS_NOT_TINY_STREAM => Some("STATUS_NOT_TINY_STREAM"), + SMB_NTSTATUS_RECOVERY_FAILURE => Some("STATUS_RECOVERY_FAILURE"), + SMB_NTSTATUS_STACK_OVERFLOW_READ => Some("STATUS_STACK_OVERFLOW_READ"), + SMB_NTSTATUS_FAIL_CHECK => Some("STATUS_FAIL_CHECK"), + SMB_NTSTATUS_DUPLICATE_OBJECTID => Some("STATUS_DUPLICATE_OBJECTID"), + SMB_NTSTATUS_OBJECTID_EXISTS => Some("STATUS_OBJECTID_EXISTS"), + SMB_NTSTATUS_CONVERT_TO_LARGE => Some("STATUS_CONVERT_TO_LARGE"), + SMB_NTSTATUS_RETRY => Some("STATUS_RETRY"), + SMB_NTSTATUS_FOUND_OUT_OF_SCOPE => Some("STATUS_FOUND_OUT_OF_SCOPE"), + SMB_NTSTATUS_ALLOCATE_BUCKET => Some("STATUS_ALLOCATE_BUCKET"), + SMB_NTSTATUS_PROPSET_NOT_FOUND => Some("STATUS_PROPSET_NOT_FOUND"), + SMB_NTSTATUS_MARSHALL_OVERFLOW => Some("STATUS_MARSHALL_OVERFLOW"), + SMB_NTSTATUS_INVALID_VARIANT => Some("STATUS_INVALID_VARIANT"), + SMB_NTSTATUS_DOMAIN_CONTROLLER_NOT_FOUND => Some("STATUS_DOMAIN_CONTROLLER_NOT_FOUND"), + SMB_NTSTATUS_ACCOUNT_LOCKED_OUT => Some("STATUS_ACCOUNT_LOCKED_OUT"), + SMB_NTSTATUS_HANDLE_NOT_CLOSABLE => Some("STATUS_HANDLE_NOT_CLOSABLE"), + SMB_NTSTATUS_CONNECTION_REFUSED => Some("STATUS_CONNECTION_REFUSED"), + SMB_NTSTATUS_GRACEFUL_DISCONNECT => Some("STATUS_GRACEFUL_DISCONNECT"), + SMB_NTSTATUS_ADDRESS_ALREADY_ASSOCIATED => Some("STATUS_ADDRESS_ALREADY_ASSOCIATED"), + SMB_NTSTATUS_ADDRESS_NOT_ASSOCIATED => Some("STATUS_ADDRESS_NOT_ASSOCIATED"), + SMB_NTSTATUS_CONNECTION_INVALID => Some("STATUS_CONNECTION_INVALID"), + SMB_NTSTATUS_CONNECTION_ACTIVE => Some("STATUS_CONNECTION_ACTIVE"), + SMB_NTSTATUS_NETWORK_UNREACHABLE => Some("STATUS_NETWORK_UNREACHABLE"), + SMB_NTSTATUS_HOST_UNREACHABLE => Some("STATUS_HOST_UNREACHABLE"), + SMB_NTSTATUS_PROTOCOL_UNREACHABLE => Some("STATUS_PROTOCOL_UNREACHABLE"), + SMB_NTSTATUS_PORT_UNREACHABLE => Some("STATUS_PORT_UNREACHABLE"), + SMB_NTSTATUS_REQUEST_ABORTED => Some("STATUS_REQUEST_ABORTED"), + SMB_NTSTATUS_CONNECTION_ABORTED => Some("STATUS_CONNECTION_ABORTED"), + SMB_NTSTATUS_BAD_COMPRESSION_BUFFER => Some("STATUS_BAD_COMPRESSION_BUFFER"), + SMB_NTSTATUS_USER_MAPPED_FILE => Some("STATUS_USER_MAPPED_FILE"), + SMB_NTSTATUS_AUDIT_FAILED => Some("STATUS_AUDIT_FAILED"), + SMB_NTSTATUS_TIMER_RESOLUTION_NOT_SET => Some("STATUS_TIMER_RESOLUTION_NOT_SET"), + SMB_NTSTATUS_CONNECTION_COUNT_LIMIT => Some("STATUS_CONNECTION_COUNT_LIMIT"), + SMB_NTSTATUS_LOGIN_TIME_RESTRICTION => Some("STATUS_LOGIN_TIME_RESTRICTION"), + SMB_NTSTATUS_LOGIN_WKSTA_RESTRICTION => Some("STATUS_LOGIN_WKSTA_RESTRICTION"), + SMB_NTSTATUS_IMAGE_MP_UP_MISMATCH => Some("STATUS_IMAGE_MP_UP_MISMATCH"), + SMB_NTSTATUS_INSUFFICIENT_LOGON_INFO => Some("STATUS_INSUFFICIENT_LOGON_INFO"), + SMB_NTSTATUS_BAD_DLL_ENTRYPOINT => Some("STATUS_BAD_DLL_ENTRYPOINT"), + SMB_NTSTATUS_BAD_SERVICE_ENTRYPOINT => Some("STATUS_BAD_SERVICE_ENTRYPOINT"), + SMB_NTSTATUS_LPC_REPLY_LOST => Some("STATUS_LPC_REPLY_LOST"), + SMB_NTSTATUS_IP_ADDRESS_CONFLICT1 => Some("STATUS_IP_ADDRESS_CONFLICT1"), + SMB_NTSTATUS_IP_ADDRESS_CONFLICT2 => Some("STATUS_IP_ADDRESS_CONFLICT2"), + SMB_NTSTATUS_REGISTRY_QUOTA_LIMIT => Some("STATUS_REGISTRY_QUOTA_LIMIT"), + SMB_NTSTATUS_PATH_NOT_COVERED => Some("STATUS_PATH_NOT_COVERED"), + SMB_NTSTATUS_NO_CALLBACK_ACTIVE => Some("STATUS_NO_CALLBACK_ACTIVE"), + SMB_NTSTATUS_LICENSE_QUOTA_EXCEEDED => Some("STATUS_LICENSE_QUOTA_EXCEEDED"), + SMB_NTSTATUS_PWD_TOO_SHORT => Some("STATUS_PWD_TOO_SHORT"), + SMB_NTSTATUS_PWD_TOO_RECENT => Some("STATUS_PWD_TOO_RECENT"), + SMB_NTSTATUS_PWD_HISTORY_CONFLICT => Some("STATUS_PWD_HISTORY_CONFLICT"), + SMB_NTSTATUS_PLUGPLAY_NO_DEVICE => Some("STATUS_PLUGPLAY_NO_DEVICE"), + SMB_NTSTATUS_UNSUPPORTED_COMPRESSION => Some("STATUS_UNSUPPORTED_COMPRESSION"), + SMB_NTSTATUS_INVALID_HW_PROFILE => Some("STATUS_INVALID_HW_PROFILE"), + SMB_NTSTATUS_INVALID_PLUGPLAY_DEVICE_PATH => Some("STATUS_INVALID_PLUGPLAY_DEVICE_PATH"), + SMB_NTSTATUS_DRIVER_ORDINAL_NOT_FOUND => Some("STATUS_DRIVER_ORDINAL_NOT_FOUND"), + SMB_NTSTATUS_DRIVER_ENTRYPOINT_NOT_FOUND => Some("STATUS_DRIVER_ENTRYPOINT_NOT_FOUND"), + SMB_NTSTATUS_RESOURCE_NOT_OWNED => Some("STATUS_RESOURCE_NOT_OWNED"), + SMB_NTSTATUS_TOO_MANY_LINKS => Some("STATUS_TOO_MANY_LINKS"), + SMB_NTSTATUS_QUOTA_LIST_INCONSISTENT => Some("STATUS_QUOTA_LIST_INCONSISTENT"), + SMB_NTSTATUS_FILE_IS_OFFLINE => Some("STATUS_FILE_IS_OFFLINE"), + SMB_NTSTATUS_EVALUATION_EXPIRATION => Some("STATUS_EVALUATION_EXPIRATION"), + SMB_NTSTATUS_ILLEGAL_DLL_RELOCATION => Some("STATUS_ILLEGAL_DLL_RELOCATION"), + SMB_NTSTATUS_LICENSE_VIOLATION => Some("STATUS_LICENSE_VIOLATION"), + SMB_NTSTATUS_DLL_INIT_FAILED_LOGOFF => Some("STATUS_DLL_INIT_FAILED_LOGOFF"), + SMB_NTSTATUS_DRIVER_UNABLE_TO_LOAD => Some("STATUS_DRIVER_UNABLE_TO_LOAD"), + SMB_NTSTATUS_DFS_UNAVAILABLE => Some("STATUS_DFS_UNAVAILABLE"), + SMB_NTSTATUS_VOLUME_DISMOUNTED => Some("STATUS_VOLUME_DISMOUNTED"), + SMB_NTSTATUS_WX86_INTERNAL_ERROR => Some("STATUS_WX86_INTERNAL_ERROR"), + SMB_NTSTATUS_WX86_FLOAT_STACK_CHECK => Some("STATUS_WX86_FLOAT_STACK_CHECK"), + SMB_NTSTATUS_VALIDATE_CONTINUE => Some("STATUS_VALIDATE_CONTINUE"), + SMB_NTSTATUS_NO_MATCH => Some("STATUS_NO_MATCH"), + SMB_NTSTATUS_NO_MORE_MATCHES => Some("STATUS_NO_MORE_MATCHES"), + SMB_NTSTATUS_NOT_A_REPARSE_POINT => Some("STATUS_NOT_A_REPARSE_POINT"), + SMB_NTSTATUS_IO_REPARSE_TAG_INVALID => Some("STATUS_IO_REPARSE_TAG_INVALID"), + SMB_NTSTATUS_IO_REPARSE_TAG_MISMATCH => Some("STATUS_IO_REPARSE_TAG_MISMATCH"), + SMB_NTSTATUS_IO_REPARSE_DATA_INVALID => Some("STATUS_IO_REPARSE_DATA_INVALID"), + SMB_NTSTATUS_IO_REPARSE_TAG_NOT_HANDLED => Some("STATUS_IO_REPARSE_TAG_NOT_HANDLED"), + SMB_NTSTATUS_REPARSE_POINT_NOT_RESOLVED => Some("STATUS_REPARSE_POINT_NOT_RESOLVED"), + SMB_NTSTATUS_DIRECTORY_IS_A_REPARSE_POINT => Some("STATUS_DIRECTORY_IS_A_REPARSE_POINT"), + SMB_NTSTATUS_RANGE_LIST_CONFLICT => Some("STATUS_RANGE_LIST_CONFLICT"), + SMB_NTSTATUS_SOURCE_ELEMENT_EMPTY => Some("STATUS_SOURCE_ELEMENT_EMPTY"), + SMB_NTSTATUS_DESTINATION_ELEMENT_FULL => Some("STATUS_DESTINATION_ELEMENT_FULL"), + SMB_NTSTATUS_ILLEGAL_ELEMENT_ADDRESS => Some("STATUS_ILLEGAL_ELEMENT_ADDRESS"), + SMB_NTSTATUS_MAGAZINE_NOT_PRESENT => Some("STATUS_MAGAZINE_NOT_PRESENT"), + SMB_NTSTATUS_REINITIALIZATION_NEEDED => Some("STATUS_REINITIALIZATION_NEEDED"), + SMB_NTSTATUS_ENCRYPTION_FAILED => Some("STATUS_ENCRYPTION_FAILED"), + SMB_NTSTATUS_DECRYPTION_FAILED => Some("STATUS_DECRYPTION_FAILED"), + SMB_NTSTATUS_RANGE_NOT_FOUND => Some("STATUS_RANGE_NOT_FOUND"), + SMB_NTSTATUS_NO_RECOVERY_POLICY => Some("STATUS_NO_RECOVERY_POLICY"), + SMB_NTSTATUS_NO_EFS => Some("STATUS_NO_EFS"), + SMB_NTSTATUS_WRONG_EFS => Some("STATUS_WRONG_EFS"), + SMB_NTSTATUS_NO_USER_KEYS => Some("STATUS_NO_USER_KEYS"), + SMB_NTSTATUS_FILE_NOT_ENCRYPTED => Some("STATUS_FILE_NOT_ENCRYPTED"), + SMB_NTSTATUS_NOT_EXPORT_FORMAT => Some("STATUS_NOT_EXPORT_FORMAT"), + SMB_NTSTATUS_FILE_ENCRYPTED => Some("STATUS_FILE_ENCRYPTED"), + SMB_NTSTATUS_WMI_GUID_NOT_FOUND => Some("STATUS_WMI_GUID_NOT_FOUND"), + SMB_NTSTATUS_WMI_INSTANCE_NOT_FOUND => Some("STATUS_WMI_INSTANCE_NOT_FOUND"), + SMB_NTSTATUS_WMI_ITEMID_NOT_FOUND => Some("STATUS_WMI_ITEMID_NOT_FOUND"), + SMB_NTSTATUS_WMI_TRY_AGAIN => Some("STATUS_WMI_TRY_AGAIN"), + SMB_NTSTATUS_SHARED_POLICY => Some("STATUS_SHARED_POLICY"), + SMB_NTSTATUS_POLICY_OBJECT_NOT_FOUND => Some("STATUS_POLICY_OBJECT_NOT_FOUND"), + SMB_NTSTATUS_POLICY_ONLY_IN_DS => Some("STATUS_POLICY_ONLY_IN_DS"), + SMB_NTSTATUS_VOLUME_NOT_UPGRADED => Some("STATUS_VOLUME_NOT_UPGRADED"), + SMB_NTSTATUS_REMOTE_STORAGE_NOT_ACTIVE => Some("STATUS_REMOTE_STORAGE_NOT_ACTIVE"), + SMB_NTSTATUS_REMOTE_STORAGE_MEDIA_ERROR => Some("STATUS_REMOTE_STORAGE_MEDIA_ERROR"), + SMB_NTSTATUS_NO_TRACKING_SERVICE => Some("STATUS_NO_TRACKING_SERVICE"), + SMB_NTSTATUS_SERVER_SID_MISMATCH => Some("STATUS_SERVER_SID_MISMATCH"), + SMB_NTSTATUS_DS_NO_ATTRIBUTE_OR_VALUE => Some("STATUS_DS_NO_ATTRIBUTE_OR_VALUE"), + SMB_NTSTATUS_DS_INVALID_ATTRIBUTE_SYNTAX => Some("STATUS_DS_INVALID_ATTRIBUTE_SYNTAX"), + SMB_NTSTATUS_DS_ATTRIBUTE_TYPE_UNDEFINED => Some("STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED"), + SMB_NTSTATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS => Some("STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS"), + SMB_NTSTATUS_DS_BUSY => Some("STATUS_DS_BUSY"), + SMB_NTSTATUS_DS_UNAVAILABLE => Some("STATUS_DS_UNAVAILABLE"), + SMB_NTSTATUS_DS_NO_RIDS_ALLOCATED => Some("STATUS_DS_NO_RIDS_ALLOCATED"), + SMB_NTSTATUS_DS_NO_MORE_RIDS => Some("STATUS_DS_NO_MORE_RIDS"), + SMB_NTSTATUS_DS_INCORRECT_ROLE_OWNER => Some("STATUS_DS_INCORRECT_ROLE_OWNER"), + SMB_NTSTATUS_DS_RIDMGR_INIT_ERROR => Some("STATUS_DS_RIDMGR_INIT_ERROR"), + SMB_NTSTATUS_DS_OBJ_CLASS_VIOLATION => Some("STATUS_DS_OBJ_CLASS_VIOLATION"), + SMB_NTSTATUS_DS_CANT_ON_NON_LEAF => Some("STATUS_DS_CANT_ON_NON_LEAF"), + SMB_NTSTATUS_DS_CANT_ON_RDN => Some("STATUS_DS_CANT_ON_RDN"), + SMB_NTSTATUS_DS_CANT_MOD_OBJ_CLASS => Some("STATUS_DS_CANT_MOD_OBJ_CLASS"), + SMB_NTSTATUS_DS_CROSS_DOM_MOVE_FAILED => Some("STATUS_DS_CROSS_DOM_MOVE_FAILED"), + SMB_NTSTATUS_DS_GC_NOT_AVAILABLE => Some("STATUS_DS_GC_NOT_AVAILABLE"), + SMB_NTSTATUS_DIRECTORY_SERVICE_REQUIRED => Some("STATUS_DIRECTORY_SERVICE_REQUIRED"), + SMB_NTSTATUS_REPARSE_ATTRIBUTE_CONFLICT => Some("STATUS_REPARSE_ATTRIBUTE_CONFLICT"), + SMB_NTSTATUS_CANT_ENABLE_DENY_ONLY => Some("STATUS_CANT_ENABLE_DENY_ONLY"), + SMB_NTSTATUS_FLOAT_MULTIPLE_FAULTS => Some("STATUS_FLOAT_MULTIPLE_FAULTS"), + SMB_NTSTATUS_FLOAT_MULTIPLE_TRAPS => Some("STATUS_FLOAT_MULTIPLE_TRAPS"), + SMB_NTSTATUS_DEVICE_REMOVED => Some("STATUS_DEVICE_REMOVED"), + SMB_NTSTATUS_JOURNAL_DELETE_IN_PROGRESS => Some("STATUS_JOURNAL_DELETE_IN_PROGRESS"), + SMB_NTSTATUS_JOURNAL_NOT_ACTIVE => Some("STATUS_JOURNAL_NOT_ACTIVE"), + SMB_NTSTATUS_NOINTERFACE => Some("STATUS_NOINTERFACE"), + SMB_NTSTATUS_DS_ADMIN_LIMIT_EXCEEDED => Some("STATUS_DS_ADMIN_LIMIT_EXCEEDED"), + SMB_NTSTATUS_DRIVER_FAILED_SLEEP => Some("STATUS_DRIVER_FAILED_SLEEP"), + SMB_NTSTATUS_MUTUAL_AUTHENTICATION_FAILED => Some("STATUS_MUTUAL_AUTHENTICATION_FAILED"), + SMB_NTSTATUS_CORRUPT_SYSTEM_FILE => Some("STATUS_CORRUPT_SYSTEM_FILE"), + SMB_NTSTATUS_DATATYPE_MISALIGNMENT_ERROR => Some("STATUS_DATATYPE_MISALIGNMENT_ERROR"), + SMB_NTSTATUS_WMI_READ_ONLY => Some("STATUS_WMI_READ_ONLY"), + SMB_NTSTATUS_WMI_SET_FAILURE => Some("STATUS_WMI_SET_FAILURE"), + SMB_NTSTATUS_COMMITMENT_MINIMUM => Some("STATUS_COMMITMENT_MINIMUM"), + SMB_NTSTATUS_REG_NAT_CONSUMPTION => Some("STATUS_REG_NAT_CONSUMPTION"), + SMB_NTSTATUS_TRANSPORT_FULL => Some("STATUS_TRANSPORT_FULL"), + SMB_NTSTATUS_DS_SAM_INIT_FAILURE => Some("STATUS_DS_SAM_INIT_FAILURE"), + SMB_NTSTATUS_ONLY_IF_CONNECTED => Some("STATUS_ONLY_IF_CONNECTED"), + SMB_NTSTATUS_DS_SENSITIVE_GROUP_VIOLATION => Some("STATUS_DS_SENSITIVE_GROUP_VIOLATION"), + SMB_NTSTATUS_PNP_RESTART_ENUMERATION => Some("STATUS_PNP_RESTART_ENUMERATION"), + SMB_NTSTATUS_JOURNAL_ENTRY_DELETED => Some("STATUS_JOURNAL_ENTRY_DELETED"), + SMB_NTSTATUS_DS_CANT_MOD_PRIMARYGROUPID => Some("STATUS_DS_CANT_MOD_PRIMARYGROUPID"), + SMB_NTSTATUS_SYSTEM_IMAGE_BAD_SIGNATURE => Some("STATUS_SYSTEM_IMAGE_BAD_SIGNATURE"), + SMB_NTSTATUS_PNP_REBOOT_REQUIRED => Some("STATUS_PNP_REBOOT_REQUIRED"), + SMB_NTSTATUS_POWER_STATE_INVALID => Some("STATUS_POWER_STATE_INVALID"), + SMB_NTSTATUS_DS_INVALID_GROUP_TYPE => Some("STATUS_DS_INVALID_GROUP_TYPE"), + SMB_NTSTATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN => { + Some("STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN") + } + SMB_NTSTATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN => { + Some("STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN") + } + SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER => { + Some("STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER") + } + SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER => { + Some("STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER") + } + SMB_NTSTATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER => { + Some("STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER") + } + SMB_NTSTATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER => { + Some("STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER") + } + SMB_NTSTATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER => { + Some("STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER") + } + SMB_NTSTATUS_DS_HAVE_PRIMARY_MEMBERS => Some("STATUS_DS_HAVE_PRIMARY_MEMBERS"), + SMB_NTSTATUS_WMI_NOT_SUPPORTED => Some("STATUS_WMI_NOT_SUPPORTED"), + SMB_NTSTATUS_INSUFFICIENT_POWER => Some("STATUS_INSUFFICIENT_POWER"), + SMB_NTSTATUS_SAM_NEED_BOOTKEY_PASSWORD => Some("STATUS_SAM_NEED_BOOTKEY_PASSWORD"), + SMB_NTSTATUS_SAM_NEED_BOOTKEY_FLOPPY => Some("STATUS_SAM_NEED_BOOTKEY_FLOPPY"), + SMB_NTSTATUS_DS_CANT_START => Some("STATUS_DS_CANT_START"), + SMB_NTSTATUS_DS_INIT_FAILURE => Some("STATUS_DS_INIT_FAILURE"), + SMB_NTSTATUS_SAM_INIT_FAILURE => Some("STATUS_SAM_INIT_FAILURE"), + SMB_NTSTATUS_DS_GC_REQUIRED => Some("STATUS_DS_GC_REQUIRED"), + SMB_NTSTATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY => Some("STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY"), + SMB_NTSTATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS => Some("STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS"), + SMB_NTSTATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED => { + Some("STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED") + } + SMB_NTSTATUS_CURRENT_DOMAIN_NOT_ALLOWED => Some("STATUS_CURRENT_DOMAIN_NOT_ALLOWED"), + SMB_NTSTATUS_CANNOT_MAKE => Some("STATUS_CANNOT_MAKE"), + SMB_NTSTATUS_SYSTEM_SHUTDOWN => Some("STATUS_SYSTEM_SHUTDOWN"), + SMB_NTSTATUS_DS_INIT_FAILURE_CONSOLE => Some("STATUS_DS_INIT_FAILURE_CONSOLE"), + SMB_NTSTATUS_DS_SAM_INIT_FAILURE_CONSOLE => Some("STATUS_DS_SAM_INIT_FAILURE_CONSOLE"), + SMB_NTSTATUS_UNFINISHED_CONTEXT_DELETED => Some("STATUS_UNFINISHED_CONTEXT_DELETED"), + SMB_NTSTATUS_NO_TGT_REPLY => Some("STATUS_NO_TGT_REPLY"), + SMB_NTSTATUS_OBJECTID_NOT_FOUND => Some("STATUS_OBJECTID_NOT_FOUND"), + SMB_NTSTATUS_NO_IP_ADDRESSES => Some("STATUS_NO_IP_ADDRESSES"), + SMB_NTSTATUS_WRONG_CREDENTIAL_HANDLE => Some("STATUS_WRONG_CREDENTIAL_HANDLE"), + SMB_NTSTATUS_CRYPTO_SYSTEM_INVALID => Some("STATUS_CRYPTO_SYSTEM_INVALID"), + SMB_NTSTATUS_MAX_REFERRALS_EXCEEDED => Some("STATUS_MAX_REFERRALS_EXCEEDED"), + SMB_NTSTATUS_MUST_BE_KDC => Some("STATUS_MUST_BE_KDC"), + SMB_NTSTATUS_STRONG_CRYPTO_NOT_SUPPORTED => Some("STATUS_STRONG_CRYPTO_NOT_SUPPORTED"), + SMB_NTSTATUS_TOO_MANY_PRINCIPALS => Some("STATUS_TOO_MANY_PRINCIPALS"), + SMB_NTSTATUS_NO_PA_DATA => Some("STATUS_NO_PA_DATA"), + SMB_NTSTATUS_PKINIT_NAME_MISMATCH => Some("STATUS_PKINIT_NAME_MISMATCH"), + SMB_NTSTATUS_SMARTCARD_LOGON_REQUIRED => Some("STATUS_SMARTCARD_LOGON_REQUIRED"), + SMB_NTSTATUS_KDC_INVALID_REQUEST => Some("STATUS_KDC_INVALID_REQUEST"), + SMB_NTSTATUS_KDC_UNABLE_TO_REFER => Some("STATUS_KDC_UNABLE_TO_REFER"), + SMB_NTSTATUS_KDC_UNKNOWN_ETYPE => Some("STATUS_KDC_UNKNOWN_ETYPE"), + SMB_NTSTATUS_SHUTDOWN_IN_PROGRESS => Some("STATUS_SHUTDOWN_IN_PROGRESS"), + SMB_NTSTATUS_SERVER_SHUTDOWN_IN_PROGRESS => Some("STATUS_SERVER_SHUTDOWN_IN_PROGRESS"), + SMB_NTSTATUS_NOT_SUPPORTED_ON_SBS => Some("STATUS_NOT_SUPPORTED_ON_SBS"), + SMB_NTSTATUS_WMI_GUID_DISCONNECTED => Some("STATUS_WMI_GUID_DISCONNECTED"), + SMB_NTSTATUS_WMI_ALREADY_DISABLED => Some("STATUS_WMI_ALREADY_DISABLED"), + SMB_NTSTATUS_WMI_ALREADY_ENABLED => Some("STATUS_WMI_ALREADY_ENABLED"), + SMB_NTSTATUS_MFT_TOO_FRAGMENTED => Some("STATUS_MFT_TOO_FRAGMENTED"), + SMB_NTSTATUS_COPY_PROTECTION_FAILURE => Some("STATUS_COPY_PROTECTION_FAILURE"), + SMB_NTSTATUS_CSS_AUTHENTICATION_FAILURE => Some("STATUS_CSS_AUTHENTICATION_FAILURE"), + SMB_NTSTATUS_CSS_KEY_NOT_PRESENT => Some("STATUS_CSS_KEY_NOT_PRESENT"), + SMB_NTSTATUS_CSS_KEY_NOT_ESTABLISHED => Some("STATUS_CSS_KEY_NOT_ESTABLISHED"), + SMB_NTSTATUS_CSS_SCRAMBLED_SECTOR => Some("STATUS_CSS_SCRAMBLED_SECTOR"), + SMB_NTSTATUS_CSS_REGION_MISMATCH => Some("STATUS_CSS_REGION_MISMATCH"), + SMB_NTSTATUS_CSS_RESETS_EXHAUSTED => Some("STATUS_CSS_RESETS_EXHAUSTED"), + SMB_NTSTATUS_PKINIT_FAILURE => Some("STATUS_PKINIT_FAILURE"), + SMB_NTSTATUS_SMARTCARD_SUBSYSTEM_FAILURE => Some("STATUS_SMARTCARD_SUBSYSTEM_FAILURE"), + SMB_NTSTATUS_NO_KERB_KEY => Some("STATUS_NO_KERB_KEY"), + SMB_NTSTATUS_HOST_DOWN => Some("STATUS_HOST_DOWN"), + SMB_NTSTATUS_UNSUPPORTED_PREAUTH => Some("STATUS_UNSUPPORTED_PREAUTH"), + SMB_NTSTATUS_EFS_ALG_BLOB_TOO_BIG => Some("STATUS_EFS_ALG_BLOB_TOO_BIG"), + SMB_NTSTATUS_PORT_NOT_SET => Some("STATUS_PORT_NOT_SET"), + SMB_NTSTATUS_DEBUGGER_INACTIVE => Some("STATUS_DEBUGGER_INACTIVE"), + SMB_NTSTATUS_DS_VERSION_CHECK_FAILURE => Some("STATUS_DS_VERSION_CHECK_FAILURE"), + SMB_NTSTATUS_AUDITING_DISABLED => Some("STATUS_AUDITING_DISABLED"), + SMB_NTSTATUS_PRENT4_MACHINE_ACCOUNT => Some("STATUS_PRENT4_MACHINE_ACCOUNT"), + SMB_NTSTATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER => { + Some("STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER") + } + SMB_NTSTATUS_INVALID_IMAGE_WIN_32 => Some("STATUS_INVALID_IMAGE_WIN_32"), + SMB_NTSTATUS_INVALID_IMAGE_WIN_64 => Some("STATUS_INVALID_IMAGE_WIN_64"), + SMB_NTSTATUS_BAD_BINDINGS => Some("STATUS_BAD_BINDINGS"), + SMB_NTSTATUS_NETWORK_SESSION_EXPIRED => Some("STATUS_NETWORK_SESSION_EXPIRED"), + SMB_NTSTATUS_APPHELP_BLOCK => Some("STATUS_APPHELP_BLOCK"), + SMB_NTSTATUS_ALL_SIDS_FILTERED => Some("STATUS_ALL_SIDS_FILTERED"), + SMB_NTSTATUS_NOT_SAFE_MODE_DRIVER => Some("STATUS_NOT_SAFE_MODE_DRIVER"), + SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT => { + Some("STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT") + } + SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PATH => { + Some("STATUS_ACCESS_DISABLED_BY_POLICY_PATH") + } + SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER => { + Some("STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER") + } + SMB_NTSTATUS_ACCESS_DISABLED_BY_POLICY_OTHER => { + Some("STATUS_ACCESS_DISABLED_BY_POLICY_OTHER") + } + SMB_NTSTATUS_FAILED_DRIVER_ENTRY => Some("STATUS_FAILED_DRIVER_ENTRY"), + SMB_NTSTATUS_DEVICE_ENUMERATION_ERROR => Some("STATUS_DEVICE_ENUMERATION_ERROR"), + SMB_NTSTATUS_MOUNT_POINT_NOT_RESOLVED => Some("STATUS_MOUNT_POINT_NOT_RESOLVED"), + SMB_NTSTATUS_INVALID_DEVICE_OBJECT_PARAMETER => { + Some("STATUS_INVALID_DEVICE_OBJECT_PARAMETER") + } + SMB_NTSTATUS_MCA_OCCURED => Some("STATUS_MCA_OCCURED"), + SMB_NTSTATUS_DRIVER_BLOCKED_CRITICAL => Some("STATUS_DRIVER_BLOCKED_CRITICAL"), + SMB_NTSTATUS_DRIVER_BLOCKED => Some("STATUS_DRIVER_BLOCKED"), + SMB_NTSTATUS_DRIVER_DATABASE_ERROR => Some("STATUS_DRIVER_DATABASE_ERROR"), + SMB_NTSTATUS_SYSTEM_HIVE_TOO_LARGE => Some("STATUS_SYSTEM_HIVE_TOO_LARGE"), + SMB_NTSTATUS_INVALID_IMPORT_OF_NON_DLL => Some("STATUS_INVALID_IMPORT_OF_NON_DLL"), + SMB_NTSTATUS_NO_SECRETS => Some("STATUS_NO_SECRETS"), + SMB_NTSTATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY => { + Some("STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY") + } + SMB_NTSTATUS_FAILED_STACK_SWITCH => Some("STATUS_FAILED_STACK_SWITCH"), + SMB_NTSTATUS_HEAP_CORRUPTION => Some("STATUS_HEAP_CORRUPTION"), + SMB_NTSTATUS_SMARTCARD_WRONG_PIN => Some("STATUS_SMARTCARD_WRONG_PIN"), + SMB_NTSTATUS_SMARTCARD_CARD_BLOCKED => Some("STATUS_SMARTCARD_CARD_BLOCKED"), + SMB_NTSTATUS_SMARTCARD_CARD_NOT_AUTHENTICATED => { + Some("STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED") + } + SMB_NTSTATUS_SMARTCARD_NO_CARD => Some("STATUS_SMARTCARD_NO_CARD"), + SMB_NTSTATUS_SMARTCARD_NO_KEY_CONTAINER => Some("STATUS_SMARTCARD_NO_KEY_CONTAINER"), + SMB_NTSTATUS_SMARTCARD_NO_CERTIFICATE => Some("STATUS_SMARTCARD_NO_CERTIFICATE"), + SMB_NTSTATUS_SMARTCARD_NO_KEYSET => Some("STATUS_SMARTCARD_NO_KEYSET"), + SMB_NTSTATUS_SMARTCARD_IO_ERROR => Some("STATUS_SMARTCARD_IO_ERROR"), + SMB_NTSTATUS_DOWNGRADE_DETECTED => Some("STATUS_DOWNGRADE_DETECTED"), + SMB_NTSTATUS_SMARTCARD_CERT_REVOKED => Some("STATUS_SMARTCARD_CERT_REVOKED"), + SMB_NTSTATUS_ISSUING_CA_UNTRUSTED => Some("STATUS_ISSUING_CA_UNTRUSTED"), + SMB_NTSTATUS_REVOCATION_OFFLINE_C => Some("STATUS_REVOCATION_OFFLINE_C"), + SMB_NTSTATUS_PKINIT_CLIENT_FAILURE => Some("STATUS_PKINIT_CLIENT_FAILURE"), + SMB_NTSTATUS_SMARTCARD_CERT_EXPIRED => Some("STATUS_SMARTCARD_CERT_EXPIRED"), + SMB_NTSTATUS_DRIVER_FAILED_PRIOR_UNLOAD => Some("STATUS_DRIVER_FAILED_PRIOR_UNLOAD"), + SMB_NTSTATUS_SMARTCARD_SILENT_CONTEXT => Some("STATUS_SMARTCARD_SILENT_CONTEXT"), + SMB_NTSTATUS_PER_USER_TRUST_QUOTA_EXCEEDED => Some("STATUS_PER_USER_TRUST_QUOTA_EXCEEDED"), + SMB_NTSTATUS_ALL_USER_TRUST_QUOTA_EXCEEDED => Some("STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED"), + SMB_NTSTATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED => { + Some("STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED") + } + SMB_NTSTATUS_DS_NAME_NOT_UNIQUE => Some("STATUS_DS_NAME_NOT_UNIQUE"), + SMB_NTSTATUS_DS_DUPLICATE_ID_FOUND => Some("STATUS_DS_DUPLICATE_ID_FOUND"), + SMB_NTSTATUS_DS_GROUP_CONVERSION_ERROR => Some("STATUS_DS_GROUP_CONVERSION_ERROR"), + SMB_NTSTATUS_VOLSNAP_PREPARE_HIBERNATE => Some("STATUS_VOLSNAP_PREPARE_HIBERNATE"), + SMB_NTSTATUS_USER2USER_REQUIRED => Some("STATUS_USER2USER_REQUIRED"), + SMB_NTSTATUS_STACK_BUFFER_OVERRUN => Some("STATUS_STACK_BUFFER_OVERRUN"), + SMB_NTSTATUS_NO_S4U_PROT_SUPPORT => Some("STATUS_NO_S4U_PROT_SUPPORT"), + SMB_NTSTATUS_CROSSREALM_DELEGATION_FAILURE => Some("STATUS_CROSSREALM_DELEGATION_FAILURE"), + SMB_NTSTATUS_REVOCATION_OFFLINE_KDC => Some("STATUS_REVOCATION_OFFLINE_KDC"), + SMB_NTSTATUS_ISSUING_CA_UNTRUSTED_KDC => Some("STATUS_ISSUING_CA_UNTRUSTED_KDC"), + SMB_NTSTATUS_KDC_CERT_EXPIRED => Some("STATUS_KDC_CERT_EXPIRED"), + SMB_NTSTATUS_KDC_CERT_REVOKED => Some("STATUS_KDC_CERT_REVOKED"), + SMB_NTSTATUS_PARAMETER_QUOTA_EXCEEDED => Some("STATUS_PARAMETER_QUOTA_EXCEEDED"), + SMB_NTSTATUS_HIBERNATION_FAILURE => Some("STATUS_HIBERNATION_FAILURE"), + SMB_NTSTATUS_DELAY_LOAD_FAILED => Some("STATUS_DELAY_LOAD_FAILED"), + SMB_NTSTATUS_AUTHENTICATION_FIREWALL_FAILED => { + Some("STATUS_AUTHENTICATION_FIREWALL_FAILED") + } + SMB_NTSTATUS_VDM_DISALLOWED => Some("STATUS_VDM_DISALLOWED"), + SMB_NTSTATUS_HUNG_DISPLAY_DRIVER_THREAD => Some("STATUS_HUNG_DISPLAY_DRIVER_THREAD"), + SMB_NTSTATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE => { + Some("STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE") + } + SMB_NTSTATUS_INVALID_CRUNTIME_PARAMETER => Some("STATUS_INVALID_CRUNTIME_PARAMETER"), + SMB_NTSTATUS_NTLM_BLOCKED => Some("STATUS_NTLM_BLOCKED"), + SMB_NTSTATUS_DS_SRC_SID_EXISTS_IN_FOREST => Some("STATUS_DS_SRC_SID_EXISTS_IN_FOREST"), + SMB_NTSTATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST => { + Some("STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST") + } + SMB_NTSTATUS_DS_FLAT_NAME_EXISTS_IN_FOREST => Some("STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST"), + SMB_NTSTATUS_INVALID_USER_PRINCIPAL_NAME => Some("STATUS_INVALID_USER_PRINCIPAL_NAME"), + SMB_NTSTATUS_ASSERTION_FAILURE => Some("STATUS_ASSERTION_FAILURE"), + SMB_NTSTATUS_VERIFIER_STOP => Some("STATUS_VERIFIER_STOP"), + SMB_NTSTATUS_CALLBACK_POP_STACK => Some("STATUS_CALLBACK_POP_STACK"), + SMB_NTSTATUS_INCOMPATIBLE_DRIVER_BLOCKED => Some("STATUS_INCOMPATIBLE_DRIVER_BLOCKED"), + SMB_NTSTATUS_HIVE_UNLOADED => Some("STATUS_HIVE_UNLOADED"), + SMB_NTSTATUS_COMPRESSION_DISABLED => Some("STATUS_COMPRESSION_DISABLED"), + SMB_NTSTATUS_FILE_SYSTEM_LIMITATION => Some("STATUS_FILE_SYSTEM_LIMITATION"), + SMB_NTSTATUS_INVALID_IMAGE_HASH => Some("STATUS_INVALID_IMAGE_HASH"), + SMB_NTSTATUS_NOT_CAPABLE => Some("STATUS_NOT_CAPABLE"), + SMB_NTSTATUS_REQUEST_OUT_OF_SEQUENCE => Some("STATUS_REQUEST_OUT_OF_SEQUENCE"), + SMB_NTSTATUS_IMPLEMENTATION_LIMIT => Some("STATUS_IMPLEMENTATION_LIMIT"), + SMB_NTSTATUS_ELEVATION_REQUIRED => Some("STATUS_ELEVATION_REQUIRED"), + SMB_NTSTATUS_NO_SECURITY_CONTEXT => Some("STATUS_NO_SECURITY_CONTEXT"), + SMB_NTSTATUS_PKU2U_CERT_FAILURE => Some("STATUS_PKU2U_CERT_FAILURE"), + SMB_NTSTATUS_BEYOND_VDL => Some("STATUS_BEYOND_VDL"), + SMB_NTSTATUS_ENCOUNTERED_WRITE_IN_PROGRESS => Some("STATUS_ENCOUNTERED_WRITE_IN_PROGRESS"), + SMB_NTSTATUS_PTE_CHANGED => Some("STATUS_PTE_CHANGED"), + SMB_NTSTATUS_PURGE_FAILED => Some("STATUS_PURGE_FAILED"), + SMB_NTSTATUS_CRED_REQUIRES_CONFIRMATION => Some("STATUS_CRED_REQUIRES_CONFIRMATION"), + SMB_NTSTATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE => { + Some("STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE") + } + SMB_NTSTATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER => { + Some("STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER") + } + SMB_NTSTATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE => { + Some("STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE") + } + SMB_NTSTATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE => { + Some("STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE") + } + SMB_NTSTATUS_CS_ENCRYPTION_FILE_NOT_CSE => Some("STATUS_CS_ENCRYPTION_FILE_NOT_CSE"), + SMB_NTSTATUS_INVALID_LABEL => Some("STATUS_INVALID_LABEL"), + SMB_NTSTATUS_DRIVER_PROCESS_TERMINATED => Some("STATUS_DRIVER_PROCESS_TERMINATED"), + SMB_NTSTATUS_AMBIGUOUS_SYSTEM_DEVICE => Some("STATUS_AMBIGUOUS_SYSTEM_DEVICE"), + SMB_NTSTATUS_SYSTEM_DEVICE_NOT_FOUND => Some("STATUS_SYSTEM_DEVICE_NOT_FOUND"), + SMB_NTSTATUS_RESTART_BOOT_APPLICATION => Some("STATUS_RESTART_BOOT_APPLICATION"), + SMB_NTSTATUS_INSUFFICIENT_NVRAM_RESOURCES => Some("STATUS_INSUFFICIENT_NVRAM_RESOURCES"), + SMB_NTSTATUS_NO_RANGES_PROCESSED => Some("STATUS_NO_RANGES_PROCESSED"), + SMB_NTSTATUS_DEVICE_FEATURE_NOT_SUPPORTED => Some("STATUS_DEVICE_FEATURE_NOT_SUPPORTED"), + SMB_NTSTATUS_DEVICE_UNREACHABLE => Some("STATUS_DEVICE_UNREACHABLE"), + SMB_NTSTATUS_INVALID_TOKEN => Some("STATUS_INVALID_TOKEN"), + SMB_NTSTATUS_SERVER_UNAVAILABLE => Some("STATUS_SERVER_UNAVAILABLE"), + SMB_NTSTATUS_INVALID_TASK_NAME => Some("STATUS_INVALID_TASK_NAME"), + SMB_NTSTATUS_INVALID_TASK_INDEX => Some("STATUS_INVALID_TASK_INDEX"), + SMB_NTSTATUS_THREAD_ALREADY_IN_TASK => Some("STATUS_THREAD_ALREADY_IN_TASK"), + SMB_NTSTATUS_CALLBACK_BYPASS => Some("STATUS_CALLBACK_BYPASS"), + SMB_NTSTATUS_FAIL_FAST_EXCEPTION => Some("STATUS_FAIL_FAST_EXCEPTION"), + SMB_NTSTATUS_IMAGE_CERT_REVOKED => Some("STATUS_IMAGE_CERT_REVOKED"), + SMB_NTSTATUS_PORT_CLOSED => Some("STATUS_PORT_CLOSED"), + SMB_NTSTATUS_MESSAGE_LOST => Some("STATUS_MESSAGE_LOST"), + SMB_NTSTATUS_INVALID_MESSAGE => Some("STATUS_INVALID_MESSAGE"), + SMB_NTSTATUS_REQUEST_CANCELED => Some("STATUS_REQUEST_CANCELED"), + SMB_NTSTATUS_RECURSIVE_DISPATCH => Some("STATUS_RECURSIVE_DISPATCH"), + SMB_NTSTATUS_LPC_RECEIVE_BUFFER_EXPECTED => Some("STATUS_LPC_RECEIVE_BUFFER_EXPECTED"), + SMB_NTSTATUS_LPC_INVALID_CONNECTION_USAGE => Some("STATUS_LPC_INVALID_CONNECTION_USAGE"), + SMB_NTSTATUS_LPC_REQUESTS_NOT_ALLOWED => Some("STATUS_LPC_REQUESTS_NOT_ALLOWED"), + SMB_NTSTATUS_RESOURCE_IN_USE => Some("STATUS_RESOURCE_IN_USE"), + SMB_NTSTATUS_HARDWARE_MEMORY_ERROR => Some("STATUS_HARDWARE_MEMORY_ERROR"), + SMB_NTSTATUS_THREADPOOL_HANDLE_EXCEPTION => Some("STATUS_THREADPOOL_HANDLE_EXCEPTION"), + SMB_NTSTATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED => { + Some("STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED") + } + SMB_NTSTATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED => { + Some("STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED") + } + SMB_NTSTATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED => { + Some("STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED") + } + SMB_NTSTATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED => { + Some("STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED") + } + SMB_NTSTATUS_THREADPOOL_RELEASED_DURING_OPERATION => { + Some("STATUS_THREADPOOL_RELEASED_DURING_OPERATION") + } + SMB_NTSTATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING => { + Some("STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING") + } + SMB_NTSTATUS_APC_RETURNED_WHILE_IMPERSONATING => { + Some("STATUS_APC_RETURNED_WHILE_IMPERSONATING") + } + SMB_NTSTATUS_PROCESS_IS_PROTECTED => Some("STATUS_PROCESS_IS_PROTECTED"), + SMB_NTSTATUS_MCA_EXCEPTION => Some("STATUS_MCA_EXCEPTION"), + SMB_NTSTATUS_CERTIFICATE_MAPPING_NOT_UNIQUE => { + Some("STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE") + } + SMB_NTSTATUS_SYMLINK_CLASS_DISABLED => Some("STATUS_SYMLINK_CLASS_DISABLED"), + SMB_NTSTATUS_INVALID_IDN_NORMALIZATION => Some("STATUS_INVALID_IDN_NORMALIZATION"), + SMB_NTSTATUS_NO_UNICODE_TRANSLATION => Some("STATUS_NO_UNICODE_TRANSLATION"), + SMB_NTSTATUS_ALREADY_REGISTERED => Some("STATUS_ALREADY_REGISTERED"), + SMB_NTSTATUS_CONTEXT_MISMATCH => Some("STATUS_CONTEXT_MISMATCH"), + SMB_NTSTATUS_PORT_ALREADY_HAS_COMPLETION_LIST => { + Some("STATUS_PORT_ALREADY_HAS_COMPLETION_LIST") + } + SMB_NTSTATUS_CALLBACK_RETURNED_THREAD_PRIORITY => { + Some("STATUS_CALLBACK_RETURNED_THREAD_PRIORITY") + } + SMB_NTSTATUS_INVALID_THREAD => Some("STATUS_INVALID_THREAD"), + SMB_NTSTATUS_CALLBACK_RETURNED_TRANSACTION => Some("STATUS_CALLBACK_RETURNED_TRANSACTION"), + SMB_NTSTATUS_CALLBACK_RETURNED_LDR_LOCK => Some("STATUS_CALLBACK_RETURNED_LDR_LOCK"), + SMB_NTSTATUS_CALLBACK_RETURNED_LANG => Some("STATUS_CALLBACK_RETURNED_LANG"), + SMB_NTSTATUS_CALLBACK_RETURNED_PRI_BACK => Some("STATUS_CALLBACK_RETURNED_PRI_BACK"), + SMB_NTSTATUS_DISK_REPAIR_DISABLED => Some("STATUS_DISK_REPAIR_DISABLED"), + SMB_NTSTATUS_DS_DOMAIN_RENAME_IN_PROGRESS => Some("STATUS_DS_DOMAIN_RENAME_IN_PROGRESS"), + SMB_NTSTATUS_DISK_QUOTA_EXCEEDED => Some("STATUS_DISK_QUOTA_EXCEEDED"), + SMB_NTSTATUS_CONTENT_BLOCKED => Some("STATUS_CONTENT_BLOCKED"), + SMB_NTSTATUS_BAD_CLUSTERS => Some("STATUS_BAD_CLUSTERS"), + SMB_NTSTATUS_VOLUME_DIRTY => Some("STATUS_VOLUME_DIRTY"), + SMB_NTSTATUS_FILE_CHECKED_OUT => Some("STATUS_FILE_CHECKED_OUT"), + SMB_NTSTATUS_CHECKOUT_REQUIRED => Some("STATUS_CHECKOUT_REQUIRED"), + SMB_NTSTATUS_BAD_FILE_TYPE => Some("STATUS_BAD_FILE_TYPE"), + SMB_NTSTATUS_FILE_TOO_LARGE => Some("STATUS_FILE_TOO_LARGE"), + SMB_NTSTATUS_FORMS_AUTH_REQUIRED => Some("STATUS_FORMS_AUTH_REQUIRED"), + SMB_NTSTATUS_VIRUS_INFECTED => Some("STATUS_VIRUS_INFECTED"), + SMB_NTSTATUS_VIRUS_DELETED => Some("STATUS_VIRUS_DELETED"), + SMB_NTSTATUS_BAD_MCFG_TABLE => Some("STATUS_BAD_MCFG_TABLE"), + SMB_NTSTATUS_CANNOT_BREAK_OPLOCK => Some("STATUS_CANNOT_BREAK_OPLOCK"), + SMB_NTSTATUS_WOW_ASSERTION => Some("STATUS_WOW_ASSERTION"), + SMB_NTSTATUS_INVALID_SIGNATURE => Some("STATUS_INVALID_SIGNATURE"), + SMB_NTSTATUS_HMAC_NOT_SUPPORTED => Some("STATUS_HMAC_NOT_SUPPORTED"), + SMB_NTSTATUS_IPSEC_QUEUE_OVERFLOW => Some("STATUS_IPSEC_QUEUE_OVERFLOW"), + SMB_NTSTATUS_ND_QUEUE_OVERFLOW => Some("STATUS_ND_QUEUE_OVERFLOW"), + SMB_NTSTATUS_HOPLIMIT_EXCEEDED => Some("STATUS_HOPLIMIT_EXCEEDED"), + SMB_NTSTATUS_PROTOCOL_NOT_SUPPORTED => Some("STATUS_PROTOCOL_NOT_SUPPORTED"), + SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED => { + Some("STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED") + } + SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR => { + Some("STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR") + } + SMB_NTSTATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR => { + Some("STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR") + } + SMB_NTSTATUS_XML_PARSE_ERROR => Some("STATUS_XML_PARSE_ERROR"), + SMB_NTSTATUS_XMLDSIG_ERROR => Some("STATUS_XMLDSIG_ERROR"), + SMB_NTSTATUS_WRONG_COMPARTMENT => Some("STATUS_WRONG_COMPARTMENT"), + SMB_NTSTATUS_AUTHIP_FAILURE => Some("STATUS_AUTHIP_FAILURE"), + SMB_NTSTATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS => { + Some("STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS") + } + SMB_NTSTATUS_DS_OID_NOT_FOUND => Some("STATUS_DS_OID_NOT_FOUND"), + SMB_NTSTATUS_HASH_NOT_SUPPORTED => Some("STATUS_HASH_NOT_SUPPORTED"), + SMB_NTSTATUS_HASH_NOT_PRESENT => Some("STATUS_HASH_NOT_PRESENT"), + SMB_NTSTATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED => { + Some("STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED") + } + SMB_NTSTATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED => { + Some("STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED") + } + SMB_NTSTATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED => { + Some("STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED") + } + SMB_NTSTATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED => { + Some("STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED") + } + SMB_NTDBG_NO_STATE_CHANGE => Some("DBG_NO_STATE_CHANGE"), + SMB_NTDBG_APP_NOT_IDLE => Some("DBG_APP_NOT_IDLE"), + SMB_NTRPC_NT_INVALID_STRING_BINDING => Some("RPC_NT_INVALID_STRING_BINDING"), + SMB_NTRPC_NT_WRONG_KIND_OF_BINDING => Some("RPC_NT_WRONG_KIND_OF_BINDING"), + SMB_NTRPC_NT_INVALID_BINDING => Some("RPC_NT_INVALID_BINDING"), + SMB_NTRPC_NT_PROTSEQ_NOT_SUPPORTED => Some("RPC_NT_PROTSEQ_NOT_SUPPORTED"), + SMB_NTRPC_NT_INVALID_RPC_PROTSEQ => Some("RPC_NT_INVALID_RPC_PROTSEQ"), + SMB_NTRPC_NT_INVALID_STRING_UUID => Some("RPC_NT_INVALID_STRING_UUID"), + SMB_NTRPC_NT_INVALID_ENDPOINT_FORMAT => Some("RPC_NT_INVALID_ENDPOINT_FORMAT"), + SMB_NTRPC_NT_INVALID_NET_ADDR => Some("RPC_NT_INVALID_NET_ADDR"), + SMB_NTRPC_NT_NO_ENDPOINT_FOUND => Some("RPC_NT_NO_ENDPOINT_FOUND"), + SMB_NTRPC_NT_INVALID_TIMEOUT => Some("RPC_NT_INVALID_TIMEOUT"), + SMB_NTRPC_NT_OBJECT_NOT_FOUND => Some("RPC_NT_OBJECT_NOT_FOUND"), + SMB_NTRPC_NT_ALREADY_REGISTERED => Some("RPC_NT_ALREADY_REGISTERED"), + SMB_NTRPC_NT_TYPE_ALREADY_REGISTERED => Some("RPC_NT_TYPE_ALREADY_REGISTERED"), + SMB_NTRPC_NT_ALREADY_LISTENING => Some("RPC_NT_ALREADY_LISTENING"), + SMB_NTRPC_NT_NO_PROTSEQS_REGISTERED => Some("RPC_NT_NO_PROTSEQS_REGISTERED"), + SMB_NTRPC_NT_NOT_LISTENING => Some("RPC_NT_NOT_LISTENING"), + SMB_NTRPC_NT_UNKNOWN_MGR_TYPE => Some("RPC_NT_UNKNOWN_MGR_TYPE"), + SMB_NTRPC_NT_UNKNOWN_IF => Some("RPC_NT_UNKNOWN_IF"), + SMB_NTRPC_NT_NO_BINDINGS => Some("RPC_NT_NO_BINDINGS"), + SMB_NTRPC_NT_NO_PROTSEQS => Some("RPC_NT_NO_PROTSEQS"), + SMB_NTRPC_NT_CANT_CREATE_ENDPOINT => Some("RPC_NT_CANT_CREATE_ENDPOINT"), + SMB_NTRPC_NT_OUT_OF_RESOURCES => Some("RPC_NT_OUT_OF_RESOURCES"), + SMB_NTRPC_NT_SERVER_UNAVAILABLE => Some("RPC_NT_SERVER_UNAVAILABLE"), + SMB_NTRPC_NT_SERVER_TOO_BUSY => Some("RPC_NT_SERVER_TOO_BUSY"), + SMB_NTRPC_NT_INVALID_NETWORK_OPTIONS => Some("RPC_NT_INVALID_NETWORK_OPTIONS"), + SMB_NTRPC_NT_NO_CALL_ACTIVE => Some("RPC_NT_NO_CALL_ACTIVE"), + SMB_NTRPC_NT_CALL_FAILED => Some("RPC_NT_CALL_FAILED"), + SMB_NTRPC_NT_CALL_FAILED_DNE => Some("RPC_NT_CALL_FAILED_DNE"), + SMB_NTRPC_NT_PROTOCOL_ERROR => Some("RPC_NT_PROTOCOL_ERROR"), + SMB_NTRPC_NT_UNSUPPORTED_TRANS_SYN => Some("RPC_NT_UNSUPPORTED_TRANS_SYN"), + SMB_NTRPC_NT_UNSUPPORTED_TYPE => Some("RPC_NT_UNSUPPORTED_TYPE"), + SMB_NTRPC_NT_INVALID_TAG => Some("RPC_NT_INVALID_TAG"), + SMB_NTRPC_NT_INVALID_BOUND => Some("RPC_NT_INVALID_BOUND"), + SMB_NTRPC_NT_NO_ENTRY_NAME => Some("RPC_NT_NO_ENTRY_NAME"), + SMB_NTRPC_NT_INVALID_NAME_SYNTAX => Some("RPC_NT_INVALID_NAME_SYNTAX"), + SMB_NTRPC_NT_UNSUPPORTED_NAME_SYNTAX => Some("RPC_NT_UNSUPPORTED_NAME_SYNTAX"), + SMB_NTRPC_NT_UUID_NO_ADDRESS => Some("RPC_NT_UUID_NO_ADDRESS"), + SMB_NTRPC_NT_DUPLICATE_ENDPOINT => Some("RPC_NT_DUPLICATE_ENDPOINT"), + SMB_NTRPC_NT_UNKNOWN_AUTHN_TYPE => Some("RPC_NT_UNKNOWN_AUTHN_TYPE"), + SMB_NTRPC_NT_MAX_CALLS_TOO_SMALL => Some("RPC_NT_MAX_CALLS_TOO_SMALL"), + SMB_NTRPC_NT_STRING_TOO_LONG => Some("RPC_NT_STRING_TOO_LONG"), + SMB_NTRPC_NT_PROTSEQ_NOT_FOUND => Some("RPC_NT_PROTSEQ_NOT_FOUND"), + SMB_NTRPC_NT_PROCNUM_OUT_OF_RANGE => Some("RPC_NT_PROCNUM_OUT_OF_RANGE"), + SMB_NTRPC_NT_BINDING_HAS_NO_AUTH => Some("RPC_NT_BINDING_HAS_NO_AUTH"), + SMB_NTRPC_NT_UNKNOWN_AUTHN_SERVICE => Some("RPC_NT_UNKNOWN_AUTHN_SERVICE"), + SMB_NTRPC_NT_UNKNOWN_AUTHN_LEVEL => Some("RPC_NT_UNKNOWN_AUTHN_LEVEL"), + SMB_NTRPC_NT_INVALID_AUTH_IDENTITY => Some("RPC_NT_INVALID_AUTH_IDENTITY"), + SMB_NTRPC_NT_UNKNOWN_AUTHZ_SERVICE => Some("RPC_NT_UNKNOWN_AUTHZ_SERVICE"), + SMB_NTEPT_NT_INVALID_ENTRY => Some("EPT_NT_INVALID_ENTRY"), + SMB_NTEPT_NT_CANT_PERFORM_OP => Some("EPT_NT_CANT_PERFORM_OP"), + SMB_NTEPT_NT_NOT_REGISTERED => Some("EPT_NT_NOT_REGISTERED"), + SMB_NTRPC_NT_NOTHING_TO_EXPORT => Some("RPC_NT_NOTHING_TO_EXPORT"), + SMB_NTRPC_NT_INCOMPLETE_NAME => Some("RPC_NT_INCOMPLETE_NAME"), + SMB_NTRPC_NT_INVALID_VERS_OPTION => Some("RPC_NT_INVALID_VERS_OPTION"), + SMB_NTRPC_NT_NO_MORE_MEMBERS => Some("RPC_NT_NO_MORE_MEMBERS"), + SMB_NTRPC_NT_NOT_ALL_OBJS_UNEXPORTED => Some("RPC_NT_NOT_ALL_OBJS_UNEXPORTED"), + SMB_NTRPC_NT_INTERFACE_NOT_FOUND => Some("RPC_NT_INTERFACE_NOT_FOUND"), + SMB_NTRPC_NT_ENTRY_ALREADY_EXISTS => Some("RPC_NT_ENTRY_ALREADY_EXISTS"), + SMB_NTRPC_NT_ENTRY_NOT_FOUND => Some("RPC_NT_ENTRY_NOT_FOUND"), + SMB_NTRPC_NT_NAME_SERVICE_UNAVAILABLE => Some("RPC_NT_NAME_SERVICE_UNAVAILABLE"), + SMB_NTRPC_NT_INVALID_NAF_ID => Some("RPC_NT_INVALID_NAF_ID"), + SMB_NTRPC_NT_CANNOT_SUPPORT => Some("RPC_NT_CANNOT_SUPPORT"), + SMB_NTRPC_NT_NO_CONTEXT_AVAILABLE => Some("RPC_NT_NO_CONTEXT_AVAILABLE"), + SMB_NTRPC_NT_INTERNAL_ERROR => Some("RPC_NT_INTERNAL_ERROR"), + SMB_NTRPC_NT_ZERO_DIVIDE => Some("RPC_NT_ZERO_DIVIDE"), + SMB_NTRPC_NT_ADDRESS_ERROR => Some("RPC_NT_ADDRESS_ERROR"), + SMB_NTRPC_NT_FP_DIV_ZERO => Some("RPC_NT_FP_DIV_ZERO"), + SMB_NTRPC_NT_FP_UNDERFLOW => Some("RPC_NT_FP_UNDERFLOW"), + SMB_NTRPC_NT_FP_OVERFLOW => Some("RPC_NT_FP_OVERFLOW"), + SMB_NTRPC_NT_CALL_IN_PROGRESS => Some("RPC_NT_CALL_IN_PROGRESS"), + SMB_NTRPC_NT_NO_MORE_BINDINGS => Some("RPC_NT_NO_MORE_BINDINGS"), + SMB_NTRPC_NT_GROUP_MEMBER_NOT_FOUND => Some("RPC_NT_GROUP_MEMBER_NOT_FOUND"), + SMB_NTEPT_NT_CANT_CREATE => Some("EPT_NT_CANT_CREATE"), + SMB_NTRPC_NT_INVALID_OBJECT => Some("RPC_NT_INVALID_OBJECT"), + SMB_NTRPC_NT_NO_INTERFACES => Some("RPC_NT_NO_INTERFACES"), + SMB_NTRPC_NT_CALL_CANCELLED => Some("RPC_NT_CALL_CANCELLED"), + SMB_NTRPC_NT_BINDING_INCOMPLETE => Some("RPC_NT_BINDING_INCOMPLETE"), + SMB_NTRPC_NT_COMM_FAILURE => Some("RPC_NT_COMM_FAILURE"), + SMB_NTRPC_NT_UNSUPPORTED_AUTHN_LEVEL => Some("RPC_NT_UNSUPPORTED_AUTHN_LEVEL"), + SMB_NTRPC_NT_NO_PRINC_NAME => Some("RPC_NT_NO_PRINC_NAME"), + SMB_NTRPC_NT_NOT_RPC_ERROR => Some("RPC_NT_NOT_RPC_ERROR"), + SMB_NTRPC_NT_SEC_PKG_ERROR => Some("RPC_NT_SEC_PKG_ERROR"), + SMB_NTRPC_NT_NOT_CANCELLED => Some("RPC_NT_NOT_CANCELLED"), + SMB_NTRPC_NT_INVALID_ASYNC_HANDLE => Some("RPC_NT_INVALID_ASYNC_HANDLE"), + SMB_NTRPC_NT_INVALID_ASYNC_CALL => Some("RPC_NT_INVALID_ASYNC_CALL"), + SMB_NTRPC_NT_PROXY_ACCESS_DENIED => Some("RPC_NT_PROXY_ACCESS_DENIED"), + SMB_NTRPC_NT_NO_MORE_ENTRIES => Some("RPC_NT_NO_MORE_ENTRIES"), + SMB_NTRPC_NT_SS_CHAR_TRANS_OPEN_FAIL => Some("RPC_NT_SS_CHAR_TRANS_OPEN_FAIL"), + SMB_NTRPC_NT_SS_CHAR_TRANS_SHORT_FILE => Some("RPC_NT_SS_CHAR_TRANS_SHORT_FILE"), + SMB_NTRPC_NT_SS_IN_NULL_CONTEXT => Some("RPC_NT_SS_IN_NULL_CONTEXT"), + SMB_NTRPC_NT_SS_CONTEXT_MISMATCH => Some("RPC_NT_SS_CONTEXT_MISMATCH"), + SMB_NTRPC_NT_SS_CONTEXT_DAMAGED => Some("RPC_NT_SS_CONTEXT_DAMAGED"), + SMB_NTRPC_NT_SS_HANDLES_MISMATCH => Some("RPC_NT_SS_HANDLES_MISMATCH"), + SMB_NTRPC_NT_SS_CANNOT_GET_CALL_HANDLE => Some("RPC_NT_SS_CANNOT_GET_CALL_HANDLE"), + SMB_NTRPC_NT_NULL_REF_POINTER => Some("RPC_NT_NULL_REF_POINTER"), + SMB_NTRPC_NT_ENUM_VALUE_OUT_OF_RANGE => Some("RPC_NT_ENUM_VALUE_OUT_OF_RANGE"), + SMB_NTRPC_NT_BYTE_COUNT_TOO_SMALL => Some("RPC_NT_BYTE_COUNT_TOO_SMALL"), + SMB_NTRPC_NT_BAD_STUB_DATA => Some("RPC_NT_BAD_STUB_DATA"), + SMB_NTRPC_NT_INVALID_ES_ACTION => Some("RPC_NT_INVALID_ES_ACTION"), + SMB_NTRPC_NT_WRONG_ES_VERSION => Some("RPC_NT_WRONG_ES_VERSION"), + SMB_NTRPC_NT_WRONG_STUB_VERSION => Some("RPC_NT_WRONG_STUB_VERSION"), + SMB_NTRPC_NT_INVALID_PIPE_OBJECT => Some("RPC_NT_INVALID_PIPE_OBJECT"), + SMB_NTRPC_NT_INVALID_PIPE_OPERATION => Some("RPC_NT_INVALID_PIPE_OPERATION"), + SMB_NTRPC_NT_WRONG_PIPE_VERSION => Some("RPC_NT_WRONG_PIPE_VERSION"), + SMB_NTRPC_NT_PIPE_CLOSED => Some("RPC_NT_PIPE_CLOSED"), + SMB_NTRPC_NT_PIPE_DISCIPLINE_ERROR => Some("RPC_NT_PIPE_DISCIPLINE_ERROR"), + SMB_NTRPC_NT_PIPE_EMPTY => Some("RPC_NT_PIPE_EMPTY"), + SMB_NTSTATUS_PNP_BAD_MPS_TABLE => Some("STATUS_PNP_BAD_MPS_TABLE"), + SMB_NTSTATUS_PNP_TRANSLATION_FAILED => Some("STATUS_PNP_TRANSLATION_FAILED"), + SMB_NTSTATUS_PNP_IRQ_TRANSLATION_FAILED => Some("STATUS_PNP_IRQ_TRANSLATION_FAILED"), + SMB_NTSTATUS_PNP_INVALID_ID => Some("STATUS_PNP_INVALID_ID"), + SMB_NTSTATUS_IO_REISSUE_AS_CACHED => Some("STATUS_IO_REISSUE_AS_CACHED"), + SMB_NTSTATUS_CTX_WINSTATION_NAME_INVALID => Some("STATUS_CTX_WINSTATION_NAME_INVALID"), + SMB_NTSTATUS_CTX_INVALID_PD => Some("STATUS_CTX_INVALID_PD"), + SMB_NTSTATUS_CTX_PD_NOT_FOUND => Some("STATUS_CTX_PD_NOT_FOUND"), + SMB_NTSTATUS_CTX_CLOSE_PENDING => Some("STATUS_CTX_CLOSE_PENDING"), + SMB_NTSTATUS_CTX_NO_OUTBUF => Some("STATUS_CTX_NO_OUTBUF"), + SMB_NTSTATUS_CTX_MODEM_INF_NOT_FOUND => Some("STATUS_CTX_MODEM_INF_NOT_FOUND"), + SMB_NTSTATUS_CTX_INVALID_MODEMNAME => Some("STATUS_CTX_INVALID_MODEMNAME"), + SMB_NTSTATUS_CTX_RESPONSE_ERROR => Some("STATUS_CTX_RESPONSE_ERROR"), + SMB_NTSTATUS_CTX_MODEM_RESPONSE_TIMEOUT => Some("STATUS_CTX_MODEM_RESPONSE_TIMEOUT"), + SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_CARRIER => Some("STATUS_CTX_MODEM_RESPONSE_NO_CARRIER"), + SMB_NTSTATUS_CTX_MODEM_RESPONSE_NO_DIALTONE => { + Some("STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE") + } + SMB_NTSTATUS_CTX_MODEM_RESPONSE_BUSY => Some("STATUS_CTX_MODEM_RESPONSE_BUSY"), + SMB_NTSTATUS_CTX_MODEM_RESPONSE_VOICE => Some("STATUS_CTX_MODEM_RESPONSE_VOICE"), + SMB_NTSTATUS_CTX_TD_ERROR => Some("STATUS_CTX_TD_ERROR"), + SMB_NTSTATUS_CTX_LICENSE_CLIENT_INVALID => Some("STATUS_CTX_LICENSE_CLIENT_INVALID"), + SMB_NTSTATUS_CTX_LICENSE_NOT_AVAILABLE => Some("STATUS_CTX_LICENSE_NOT_AVAILABLE"), + SMB_NTSTATUS_CTX_LICENSE_EXPIRED => Some("STATUS_CTX_LICENSE_EXPIRED"), + SMB_NTSTATUS_CTX_WINSTATION_NOT_FOUND => Some("STATUS_CTX_WINSTATION_NOT_FOUND"), + SMB_NTSTATUS_CTX_WINSTATION_NAME_COLLISION => Some("STATUS_CTX_WINSTATION_NAME_COLLISION"), + SMB_NTSTATUS_CTX_WINSTATION_BUSY => Some("STATUS_CTX_WINSTATION_BUSY"), + SMB_NTSTATUS_CTX_BAD_VIDEO_MODE => Some("STATUS_CTX_BAD_VIDEO_MODE"), + SMB_NTSTATUS_CTX_GRAPHICS_INVALID => Some("STATUS_CTX_GRAPHICS_INVALID"), + SMB_NTSTATUS_CTX_NOT_CONSOLE => Some("STATUS_CTX_NOT_CONSOLE"), + SMB_NTSTATUS_CTX_CLIENT_QUERY_TIMEOUT => Some("STATUS_CTX_CLIENT_QUERY_TIMEOUT"), + SMB_NTSTATUS_CTX_CONSOLE_DISCONNECT => Some("STATUS_CTX_CONSOLE_DISCONNECT"), + SMB_NTSTATUS_CTX_CONSOLE_CONNECT => Some("STATUS_CTX_CONSOLE_CONNECT"), + SMB_NTSTATUS_CTX_SHADOW_DENIED => Some("STATUS_CTX_SHADOW_DENIED"), + SMB_NTSTATUS_CTX_WINSTATION_ACCESS_DENIED => Some("STATUS_CTX_WINSTATION_ACCESS_DENIED"), + SMB_NTSTATUS_CTX_INVALID_WD => Some("STATUS_CTX_INVALID_WD"), + SMB_NTSTATUS_CTX_WD_NOT_FOUND => Some("STATUS_CTX_WD_NOT_FOUND"), + SMB_NTSTATUS_CTX_SHADOW_INVALID => Some("STATUS_CTX_SHADOW_INVALID"), + SMB_NTSTATUS_CTX_SHADOW_DISABLED => Some("STATUS_CTX_SHADOW_DISABLED"), + SMB_NTSTATUS_RDP_PROTOCOL_ERROR => Some("STATUS_RDP_PROTOCOL_ERROR"), + SMB_NTSTATUS_CTX_CLIENT_LICENSE_NOT_SET => Some("STATUS_CTX_CLIENT_LICENSE_NOT_SET"), + SMB_NTSTATUS_CTX_CLIENT_LICENSE_IN_USE => Some("STATUS_CTX_CLIENT_LICENSE_IN_USE"), + SMB_NTSTATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE => { + Some("STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE") + } + SMB_NTSTATUS_CTX_SHADOW_NOT_RUNNING => Some("STATUS_CTX_SHADOW_NOT_RUNNING"), + SMB_NTSTATUS_CTX_LOGON_DISABLED => Some("STATUS_CTX_LOGON_DISABLED"), + SMB_NTSTATUS_CTX_SECURITY_LAYER_ERROR => Some("STATUS_CTX_SECURITY_LAYER_ERROR"), + SMB_NTSTATUS_TS_INCOMPATIBLE_SESSIONS => Some("STATUS_TS_INCOMPATIBLE_SESSIONS"), + SMB_NTSTATUS_MUI_FILE_NOT_FOUND => Some("STATUS_MUI_FILE_NOT_FOUND"), + SMB_NTSTATUS_MUI_INVALID_FILE => Some("STATUS_MUI_INVALID_FILE"), + SMB_NTSTATUS_MUI_INVALID_RC_CONFIG => Some("STATUS_MUI_INVALID_RC_CONFIG"), + SMB_NTSTATUS_MUI_INVALID_LOCALE_NAME => Some("STATUS_MUI_INVALID_LOCALE_NAME"), + SMB_NTSTATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME => { + Some("STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME") + } + SMB_NTSTATUS_MUI_FILE_NOT_LOADED => Some("STATUS_MUI_FILE_NOT_LOADED"), + SMB_NTSTATUS_RESOURCE_ENUM_USER_STOP => Some("STATUS_RESOURCE_ENUM_USER_STOP"), + SMB_NTSTATUS_CLUSTER_INVALID_NODE => Some("STATUS_CLUSTER_INVALID_NODE"), + SMB_NTSTATUS_CLUSTER_NODE_EXISTS => Some("STATUS_CLUSTER_NODE_EXISTS"), + SMB_NTSTATUS_CLUSTER_JOIN_IN_PROGRESS => Some("STATUS_CLUSTER_JOIN_IN_PROGRESS"), + SMB_NTSTATUS_CLUSTER_NODE_NOT_FOUND => Some("STATUS_CLUSTER_NODE_NOT_FOUND"), + SMB_NTSTATUS_CLUSTER_LOCAL_NODE_NOT_FOUND => Some("STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND"), + SMB_NTSTATUS_CLUSTER_NETWORK_EXISTS => Some("STATUS_CLUSTER_NETWORK_EXISTS"), + SMB_NTSTATUS_CLUSTER_NETWORK_NOT_FOUND => Some("STATUS_CLUSTER_NETWORK_NOT_FOUND"), + SMB_NTSTATUS_CLUSTER_NETINTERFACE_EXISTS => Some("STATUS_CLUSTER_NETINTERFACE_EXISTS"), + SMB_NTSTATUS_CLUSTER_NETINTERFACE_NOT_FOUND => { + Some("STATUS_CLUSTER_NETINTERFACE_NOT_FOUND") + } + SMB_NTSTATUS_CLUSTER_INVALID_REQUEST => Some("STATUS_CLUSTER_INVALID_REQUEST"), + SMB_NTSTATUS_CLUSTER_INVALID_NETWORK_PROVIDER => { + Some("STATUS_CLUSTER_INVALID_NETWORK_PROVIDER") + } + SMB_NTSTATUS_CLUSTER_NODE_DOWN => Some("STATUS_CLUSTER_NODE_DOWN"), + SMB_NTSTATUS_CLUSTER_NODE_UNREACHABLE => Some("STATUS_CLUSTER_NODE_UNREACHABLE"), + SMB_NTSTATUS_CLUSTER_NODE_NOT_MEMBER => Some("STATUS_CLUSTER_NODE_NOT_MEMBER"), + SMB_NTSTATUS_CLUSTER_JOIN_NOT_IN_PROGRESS => Some("STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS"), + SMB_NTSTATUS_CLUSTER_INVALID_NETWORK => Some("STATUS_CLUSTER_INVALID_NETWORK"), + SMB_NTSTATUS_CLUSTER_NO_NET_ADAPTERS => Some("STATUS_CLUSTER_NO_NET_ADAPTERS"), + SMB_NTSTATUS_CLUSTER_NODE_UP => Some("STATUS_CLUSTER_NODE_UP"), + SMB_NTSTATUS_CLUSTER_NODE_PAUSED => Some("STATUS_CLUSTER_NODE_PAUSED"), + SMB_NTSTATUS_CLUSTER_NODE_NOT_PAUSED => Some("STATUS_CLUSTER_NODE_NOT_PAUSED"), + SMB_NTSTATUS_CLUSTER_NO_SECURITY_CONTEXT => Some("STATUS_CLUSTER_NO_SECURITY_CONTEXT"), + SMB_NTSTATUS_CLUSTER_NETWORK_NOT_INTERNAL => Some("STATUS_CLUSTER_NETWORK_NOT_INTERNAL"), + SMB_NTSTATUS_CLUSTER_POISONED => Some("STATUS_CLUSTER_POISONED"), + SMB_NTSTATUS_ACPI_INVALID_OPCODE => Some("STATUS_ACPI_INVALID_OPCODE"), + SMB_NTSTATUS_ACPI_STACK_OVERFLOW => Some("STATUS_ACPI_STACK_OVERFLOW"), + SMB_NTSTATUS_ACPI_ASSERT_FAILED => Some("STATUS_ACPI_ASSERT_FAILED"), + SMB_NTSTATUS_ACPI_INVALID_INDEX => Some("STATUS_ACPI_INVALID_INDEX"), + SMB_NTSTATUS_ACPI_INVALID_ARGUMENT => Some("STATUS_ACPI_INVALID_ARGUMENT"), + SMB_NTSTATUS_ACPI_FATAL => Some("STATUS_ACPI_FATAL"), + SMB_NTSTATUS_ACPI_INVALID_SUPERNAME => Some("STATUS_ACPI_INVALID_SUPERNAME"), + SMB_NTSTATUS_ACPI_INVALID_ARGTYPE => Some("STATUS_ACPI_INVALID_ARGTYPE"), + SMB_NTSTATUS_ACPI_INVALID_OBJTYPE => Some("STATUS_ACPI_INVALID_OBJTYPE"), + SMB_NTSTATUS_ACPI_INVALID_TARGETTYPE => Some("STATUS_ACPI_INVALID_TARGETTYPE"), + SMB_NTSTATUS_ACPI_INCORRECT_ARGUMENT_COUNT => Some("STATUS_ACPI_INCORRECT_ARGUMENT_COUNT"), + SMB_NTSTATUS_ACPI_ADDRESS_NOT_MAPPED => Some("STATUS_ACPI_ADDRESS_NOT_MAPPED"), + SMB_NTSTATUS_ACPI_INVALID_EVENTTYPE => Some("STATUS_ACPI_INVALID_EVENTTYPE"), + SMB_NTSTATUS_ACPI_HANDLER_COLLISION => Some("STATUS_ACPI_HANDLER_COLLISION"), + SMB_NTSTATUS_ACPI_INVALID_DATA => Some("STATUS_ACPI_INVALID_DATA"), + SMB_NTSTATUS_ACPI_INVALID_REGION => Some("STATUS_ACPI_INVALID_REGION"), + SMB_NTSTATUS_ACPI_INVALID_ACCESS_SIZE => Some("STATUS_ACPI_INVALID_ACCESS_SIZE"), + SMB_NTSTATUS_ACPI_ACQUIRE_GLOBAL_LOCK => Some("STATUS_ACPI_ACQUIRE_GLOBAL_LOCK"), + SMB_NTSTATUS_ACPI_ALREADY_INITIALIZED => Some("STATUS_ACPI_ALREADY_INITIALIZED"), + SMB_NTSTATUS_ACPI_NOT_INITIALIZED => Some("STATUS_ACPI_NOT_INITIALIZED"), + SMB_NTSTATUS_ACPI_INVALID_MUTEX_LEVEL => Some("STATUS_ACPI_INVALID_MUTEX_LEVEL"), + SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNED => Some("STATUS_ACPI_MUTEX_NOT_OWNED"), + SMB_NTSTATUS_ACPI_MUTEX_NOT_OWNER => Some("STATUS_ACPI_MUTEX_NOT_OWNER"), + SMB_NTSTATUS_ACPI_RS_ACCESS => Some("STATUS_ACPI_RS_ACCESS"), + SMB_NTSTATUS_ACPI_INVALID_TABLE => Some("STATUS_ACPI_INVALID_TABLE"), + SMB_NTSTATUS_ACPI_REG_HANDLER_FAILED => Some("STATUS_ACPI_REG_HANDLER_FAILED"), + SMB_NTSTATUS_ACPI_POWER_REQUEST_FAILED => Some("STATUS_ACPI_POWER_REQUEST_FAILED"), + SMB_NTSTATUS_SXS_SECTION_NOT_FOUND => Some("STATUS_SXS_SECTION_NOT_FOUND"), + SMB_NTSTATUS_SXS_CANT_GEN_ACTCTX => Some("STATUS_SXS_CANT_GEN_ACTCTX"), + SMB_NTSTATUS_SXS_INVALID_ACTCTXDATA_FORMAT => Some("STATUS_SXS_INVALID_ACTCTXDATA_FORMAT"), + SMB_NTSTATUS_SXS_ASSEMBLY_NOT_FOUND => Some("STATUS_SXS_ASSEMBLY_NOT_FOUND"), + SMB_NTSTATUS_SXS_MANIFEST_FORMAT_ERROR => Some("STATUS_SXS_MANIFEST_FORMAT_ERROR"), + SMB_NTSTATUS_SXS_MANIFEST_PARSE_ERROR => Some("STATUS_SXS_MANIFEST_PARSE_ERROR"), + SMB_NTSTATUS_SXS_ACTIVATION_CONTEXT_DISABLED => { + Some("STATUS_SXS_ACTIVATION_CONTEXT_DISABLED") + } + SMB_NTSTATUS_SXS_KEY_NOT_FOUND => Some("STATUS_SXS_KEY_NOT_FOUND"), + SMB_NTSTATUS_SXS_VERSION_CONFLICT => Some("STATUS_SXS_VERSION_CONFLICT"), + SMB_NTSTATUS_SXS_WRONG_SECTION_TYPE => Some("STATUS_SXS_WRONG_SECTION_TYPE"), + SMB_NTSTATUS_SXS_THREAD_QUERIES_DISABLED => Some("STATUS_SXS_THREAD_QUERIES_DISABLED"), + SMB_NTSTATUS_SXS_ASSEMBLY_MISSING => Some("STATUS_SXS_ASSEMBLY_MISSING"), + SMB_NTSTATUS_SXS_PROCESS_DEFAULT_ALREADY_SET => { + Some("STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET") + } + SMB_NTSTATUS_SXS_EARLY_DEACTIVATION => Some("STATUS_SXS_EARLY_DEACTIVATION"), + SMB_NTSTATUS_SXS_INVALID_DEACTIVATION => Some("STATUS_SXS_INVALID_DEACTIVATION"), + SMB_NTSTATUS_SXS_MULTIPLE_DEACTIVATION => Some("STATUS_SXS_MULTIPLE_DEACTIVATION"), + SMB_NTSTATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY => { + Some("STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY") + } + SMB_NTSTATUS_SXS_PROCESS_TERMINATION_REQUESTED => { + Some("STATUS_SXS_PROCESS_TERMINATION_REQUESTED") + } + SMB_NTSTATUS_SXS_CORRUPT_ACTIVATION_STACK => Some("STATUS_SXS_CORRUPT_ACTIVATION_STACK"), + SMB_NTSTATUS_SXS_CORRUPTION => Some("STATUS_SXS_CORRUPTION"), + SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE => { + Some("STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE") + } + SMB_NTSTATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME => { + Some("STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME") + } + SMB_NTSTATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE => { + Some("STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE") + } + SMB_NTSTATUS_SXS_IDENTITY_PARSE_ERROR => Some("STATUS_SXS_IDENTITY_PARSE_ERROR"), + SMB_NTSTATUS_SXS_COMPONENT_STORE_CORRUPT => Some("STATUS_SXS_COMPONENT_STORE_CORRUPT"), + SMB_NTSTATUS_SXS_FILE_HASH_MISMATCH => Some("STATUS_SXS_FILE_HASH_MISMATCH"), + SMB_NTSTATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT => { + Some("STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT") + } + SMB_NTSTATUS_SXS_IDENTITIES_DIFFERENT => Some("STATUS_SXS_IDENTITIES_DIFFERENT"), + SMB_NTSTATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT => { + Some("STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT") + } + SMB_NTSTATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY => Some("STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY"), + SMB_NTSTATUS_ADVANCED_INSTALLER_FAILED => Some("STATUS_ADVANCED_INSTALLER_FAILED"), + SMB_NTSTATUS_XML_ENCODING_MISMATCH => Some("STATUS_XML_ENCODING_MISMATCH"), + SMB_NTSTATUS_SXS_MANIFEST_TOO_BIG => Some("STATUS_SXS_MANIFEST_TOO_BIG"), + SMB_NTSTATUS_SXS_SETTING_NOT_REGISTERED => Some("STATUS_SXS_SETTING_NOT_REGISTERED"), + SMB_NTSTATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE => { + Some("STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE") + } + SMB_NTSTATUS_SMI_PRIMITIVE_INSTALLER_FAILED => { + Some("STATUS_SMI_PRIMITIVE_INSTALLER_FAILED") + } + SMB_NTSTATUS_GENERIC_COMMAND_FAILED => Some("STATUS_GENERIC_COMMAND_FAILED"), + SMB_NTSTATUS_SXS_FILE_HASH_MISSING => Some("STATUS_SXS_FILE_HASH_MISSING"), + SMB_NTSTATUS_TRANSACTIONAL_CONFLICT => Some("STATUS_TRANSACTIONAL_CONFLICT"), + SMB_NTSTATUS_INVALID_TRANSACTION => Some("STATUS_INVALID_TRANSACTION"), + SMB_NTSTATUS_TRANSACTION_NOT_ACTIVE => Some("STATUS_TRANSACTION_NOT_ACTIVE"), + SMB_NTSTATUS_TM_INITIALIZATION_FAILED => Some("STATUS_TM_INITIALIZATION_FAILED"), + SMB_NTSTATUS_RM_NOT_ACTIVE => Some("STATUS_RM_NOT_ACTIVE"), + SMB_NTSTATUS_RM_METADATA_CORRUPT => Some("STATUS_RM_METADATA_CORRUPT"), + SMB_NTSTATUS_TRANSACTION_NOT_JOINED => Some("STATUS_TRANSACTION_NOT_JOINED"), + SMB_NTSTATUS_DIRECTORY_NOT_RM => Some("STATUS_DIRECTORY_NOT_RM"), + SMB_NTSTATUS_TRANSACTIONS_UNSUPPORTED_REMOTE => { + Some("STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE") + } + SMB_NTSTATUS_LOG_RESIZE_INVALID_SIZE => Some("STATUS_LOG_RESIZE_INVALID_SIZE"), + SMB_NTSTATUS_REMOTE_FILE_VERSION_MISMATCH => Some("STATUS_REMOTE_FILE_VERSION_MISMATCH"), + SMB_NTSTATUS_CRM_PROTOCOL_ALREADY_EXISTS => Some("STATUS_CRM_PROTOCOL_ALREADY_EXISTS"), + SMB_NTSTATUS_TRANSACTION_PROPAGATION_FAILED => { + Some("STATUS_TRANSACTION_PROPAGATION_FAILED") + } + SMB_NTSTATUS_CRM_PROTOCOL_NOT_FOUND => Some("STATUS_CRM_PROTOCOL_NOT_FOUND"), + SMB_NTSTATUS_TRANSACTION_SUPERIOR_EXISTS => Some("STATUS_TRANSACTION_SUPERIOR_EXISTS"), + SMB_NTSTATUS_TRANSACTION_REQUEST_NOT_VALID => Some("STATUS_TRANSACTION_REQUEST_NOT_VALID"), + SMB_NTSTATUS_TRANSACTION_NOT_REQUESTED => Some("STATUS_TRANSACTION_NOT_REQUESTED"), + SMB_NTSTATUS_TRANSACTION_ALREADY_ABORTED => Some("STATUS_TRANSACTION_ALREADY_ABORTED"), + SMB_NTSTATUS_TRANSACTION_ALREADY_COMMITTED => Some("STATUS_TRANSACTION_ALREADY_COMMITTED"), + SMB_NTSTATUS_TRANSACTION_INVALID_MARSHALL_BUFFER => { + Some("STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER") + } + SMB_NTSTATUS_CURRENT_TRANSACTION_NOT_VALID => Some("STATUS_CURRENT_TRANSACTION_NOT_VALID"), + SMB_NTSTATUS_LOG_GROWTH_FAILED => Some("STATUS_LOG_GROWTH_FAILED"), + SMB_NTSTATUS_OBJECT_NO_LONGER_EXISTS => Some("STATUS_OBJECT_NO_LONGER_EXISTS"), + SMB_NTSTATUS_STREAM_MINIVERSION_NOT_FOUND => Some("STATUS_STREAM_MINIVERSION_NOT_FOUND"), + SMB_NTSTATUS_STREAM_MINIVERSION_NOT_VALID => Some("STATUS_STREAM_MINIVERSION_NOT_VALID"), + SMB_NTSTATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION => { + Some("STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION") + } + SMB_NTSTATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT => { + Some("STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT") + } + SMB_NTSTATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS => { + Some("STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS") + } + SMB_NTSTATUS_HANDLE_NO_LONGER_VALID => Some("STATUS_HANDLE_NO_LONGER_VALID"), + SMB_NTSTATUS_LOG_CORRUPTION_DETECTED => Some("STATUS_LOG_CORRUPTION_DETECTED"), + SMB_NTSTATUS_RM_DISCONNECTED => Some("STATUS_RM_DISCONNECTED"), + SMB_NTSTATUS_ENLISTMENT_NOT_SUPERIOR => Some("STATUS_ENLISTMENT_NOT_SUPERIOR"), + SMB_NTSTATUS_FILE_IDENTITY_NOT_PERSISTENT => Some("STATUS_FILE_IDENTITY_NOT_PERSISTENT"), + SMB_NTSTATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY => { + Some("STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY") + } + SMB_NTSTATUS_CANT_CROSS_RM_BOUNDARY => Some("STATUS_CANT_CROSS_RM_BOUNDARY"), + SMB_NTSTATUS_TXF_DIR_NOT_EMPTY => Some("STATUS_TXF_DIR_NOT_EMPTY"), + SMB_NTSTATUS_INDOUBT_TRANSACTIONS_EXIST => Some("STATUS_INDOUBT_TRANSACTIONS_EXIST"), + SMB_NTSTATUS_TM_VOLATILE => Some("STATUS_TM_VOLATILE"), + SMB_NTSTATUS_ROLLBACK_TIMER_EXPIRED => Some("STATUS_ROLLBACK_TIMER_EXPIRED"), + SMB_NTSTATUS_TXF_ATTRIBUTE_CORRUPT => Some("STATUS_TXF_ATTRIBUTE_CORRUPT"), + SMB_NTSTATUS_EFS_NOT_ALLOWED_IN_TRANSACTION => { + Some("STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION") + } + SMB_NTSTATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED => { + Some("STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED") + } + SMB_NTSTATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE => { + Some("STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE") + } + SMB_NTSTATUS_TRANSACTION_REQUIRED_PROMOTION => { + Some("STATUS_TRANSACTION_REQUIRED_PROMOTION") + } + SMB_NTSTATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION => { + Some("STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION") + } + SMB_NTSTATUS_TRANSACTIONS_NOT_FROZEN => Some("STATUS_TRANSACTIONS_NOT_FROZEN"), + SMB_NTSTATUS_TRANSACTION_FREEZE_IN_PROGRESS => { + Some("STATUS_TRANSACTION_FREEZE_IN_PROGRESS") + } + SMB_NTSTATUS_NOT_SNAPSHOT_VOLUME => Some("STATUS_NOT_SNAPSHOT_VOLUME"), + SMB_NTSTATUS_NO_SAVEPOINT_WITH_OPEN_FILES => Some("STATUS_NO_SAVEPOINT_WITH_OPEN_FILES"), + SMB_NTSTATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION => { + Some("STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION") + } + SMB_NTSTATUS_TM_IDENTITY_MISMATCH => Some("STATUS_TM_IDENTITY_MISMATCH"), + SMB_NTSTATUS_FLOATED_SECTION => Some("STATUS_FLOATED_SECTION"), + SMB_NTSTATUS_CANNOT_ACCEPT_TRANSACTED_WORK => Some("STATUS_CANNOT_ACCEPT_TRANSACTED_WORK"), + SMB_NTSTATUS_CANNOT_ABORT_TRANSACTIONS => Some("STATUS_CANNOT_ABORT_TRANSACTIONS"), + SMB_NTSTATUS_TRANSACTION_NOT_FOUND => Some("STATUS_TRANSACTION_NOT_FOUND"), + SMB_NTSTATUS_RESOURCEMANAGER_NOT_FOUND => Some("STATUS_RESOURCEMANAGER_NOT_FOUND"), + SMB_NTSTATUS_ENLISTMENT_NOT_FOUND => Some("STATUS_ENLISTMENT_NOT_FOUND"), + SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_FOUND => Some("STATUS_TRANSACTIONMANAGER_NOT_FOUND"), + SMB_NTSTATUS_TRANSACTIONMANAGER_NOT_ONLINE => Some("STATUS_TRANSACTIONMANAGER_NOT_ONLINE"), + SMB_NTSTATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION => { + Some("STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION") + } + SMB_NTSTATUS_TRANSACTION_NOT_ROOT => Some("STATUS_TRANSACTION_NOT_ROOT"), + SMB_NTSTATUS_TRANSACTION_OBJECT_EXPIRED => Some("STATUS_TRANSACTION_OBJECT_EXPIRED"), + SMB_NTSTATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION => { + Some("STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION") + } + SMB_NTSTATUS_TRANSACTION_RESPONSE_NOT_ENLISTED => { + Some("STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED") + } + SMB_NTSTATUS_TRANSACTION_RECORD_TOO_LONG => Some("STATUS_TRANSACTION_RECORD_TOO_LONG"), + SMB_NTSTATUS_NO_LINK_TRACKING_IN_TRANSACTION => { + Some("STATUS_NO_LINK_TRACKING_IN_TRANSACTION") + } + SMB_NTSTATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION => { + Some("STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION") + } + SMB_NTSTATUS_TRANSACTION_INTEGRITY_VIOLATED => { + Some("STATUS_TRANSACTION_INTEGRITY_VIOLATED") + } + SMB_NTSTATUS_EXPIRED_HANDLE => Some("STATUS_EXPIRED_HANDLE"), + SMB_NTSTATUS_TRANSACTION_NOT_ENLISTED => Some("STATUS_TRANSACTION_NOT_ENLISTED"), + SMB_NTSTATUS_LOG_SECTOR_INVALID => Some("STATUS_LOG_SECTOR_INVALID"), + SMB_NTSTATUS_LOG_SECTOR_PARITY_INVALID => Some("STATUS_LOG_SECTOR_PARITY_INVALID"), + SMB_NTSTATUS_LOG_SECTOR_REMAPPED => Some("STATUS_LOG_SECTOR_REMAPPED"), + SMB_NTSTATUS_LOG_BLOCK_INCOMPLETE => Some("STATUS_LOG_BLOCK_INCOMPLETE"), + SMB_NTSTATUS_LOG_INVALID_RANGE => Some("STATUS_LOG_INVALID_RANGE"), + SMB_NTSTATUS_LOG_BLOCKS_EXHAUSTED => Some("STATUS_LOG_BLOCKS_EXHAUSTED"), + SMB_NTSTATUS_LOG_READ_CONTEXT_INVALID => Some("STATUS_LOG_READ_CONTEXT_INVALID"), + SMB_NTSTATUS_LOG_RESTART_INVALID => Some("STATUS_LOG_RESTART_INVALID"), + SMB_NTSTATUS_LOG_BLOCK_VERSION => Some("STATUS_LOG_BLOCK_VERSION"), + SMB_NTSTATUS_LOG_BLOCK_INVALID => Some("STATUS_LOG_BLOCK_INVALID"), + SMB_NTSTATUS_LOG_READ_MODE_INVALID => Some("STATUS_LOG_READ_MODE_INVALID"), + SMB_NTSTATUS_LOG_METADATA_CORRUPT => Some("STATUS_LOG_METADATA_CORRUPT"), + SMB_NTSTATUS_LOG_METADATA_INVALID => Some("STATUS_LOG_METADATA_INVALID"), + SMB_NTSTATUS_LOG_METADATA_INCONSISTENT => Some("STATUS_LOG_METADATA_INCONSISTENT"), + SMB_NTSTATUS_LOG_RESERVATION_INVALID => Some("STATUS_LOG_RESERVATION_INVALID"), + SMB_NTSTATUS_LOG_CANT_DELETE => Some("STATUS_LOG_CANT_DELETE"), + SMB_NTSTATUS_LOG_CONTAINER_LIMIT_EXCEEDED => Some("STATUS_LOG_CONTAINER_LIMIT_EXCEEDED"), + SMB_NTSTATUS_LOG_START_OF_LOG => Some("STATUS_LOG_START_OF_LOG"), + SMB_NTSTATUS_LOG_POLICY_ALREADY_INSTALLED => Some("STATUS_LOG_POLICY_ALREADY_INSTALLED"), + SMB_NTSTATUS_LOG_POLICY_NOT_INSTALLED => Some("STATUS_LOG_POLICY_NOT_INSTALLED"), + SMB_NTSTATUS_LOG_POLICY_INVALID => Some("STATUS_LOG_POLICY_INVALID"), + SMB_NTSTATUS_LOG_POLICY_CONFLICT => Some("STATUS_LOG_POLICY_CONFLICT"), + SMB_NTSTATUS_LOG_PINNED_ARCHIVE_TAIL => Some("STATUS_LOG_PINNED_ARCHIVE_TAIL"), + SMB_NTSTATUS_LOG_RECORD_NONEXISTENT => Some("STATUS_LOG_RECORD_NONEXISTENT"), + SMB_NTSTATUS_LOG_RECORDS_RESERVED_INVALID => Some("STATUS_LOG_RECORDS_RESERVED_INVALID"), + SMB_NTSTATUS_LOG_SPACE_RESERVED_INVALID => Some("STATUS_LOG_SPACE_RESERVED_INVALID"), + SMB_NTSTATUS_LOG_TAIL_INVALID => Some("STATUS_LOG_TAIL_INVALID"), + SMB_NTSTATUS_LOG_FULL => Some("STATUS_LOG_FULL"), + SMB_NTSTATUS_LOG_MULTIPLEXED => Some("STATUS_LOG_MULTIPLEXED"), + SMB_NTSTATUS_LOG_DEDICATED => Some("STATUS_LOG_DEDICATED"), + SMB_NTSTATUS_LOG_ARCHIVE_NOT_IN_PROGRESS => Some("STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS"), + SMB_NTSTATUS_LOG_ARCHIVE_IN_PROGRESS => Some("STATUS_LOG_ARCHIVE_IN_PROGRESS"), + SMB_NTSTATUS_LOG_EPHEMERAL => Some("STATUS_LOG_EPHEMERAL"), + SMB_NTSTATUS_LOG_NOT_ENOUGH_CONTAINERS => Some("STATUS_LOG_NOT_ENOUGH_CONTAINERS"), + SMB_NTSTATUS_LOG_CLIENT_ALREADY_REGISTERED => Some("STATUS_LOG_CLIENT_ALREADY_REGISTERED"), + SMB_NTSTATUS_LOG_CLIENT_NOT_REGISTERED => Some("STATUS_LOG_CLIENT_NOT_REGISTERED"), + SMB_NTSTATUS_LOG_FULL_HANDLER_IN_PROGRESS => Some("STATUS_LOG_FULL_HANDLER_IN_PROGRESS"), + SMB_NTSTATUS_LOG_CONTAINER_READ_FAILED => Some("STATUS_LOG_CONTAINER_READ_FAILED"), + SMB_NTSTATUS_LOG_CONTAINER_WRITE_FAILED => Some("STATUS_LOG_CONTAINER_WRITE_FAILED"), + SMB_NTSTATUS_LOG_CONTAINER_OPEN_FAILED => Some("STATUS_LOG_CONTAINER_OPEN_FAILED"), + SMB_NTSTATUS_LOG_CONTAINER_STATE_INVALID => Some("STATUS_LOG_CONTAINER_STATE_INVALID"), + SMB_NTSTATUS_LOG_STATE_INVALID => Some("STATUS_LOG_STATE_INVALID"), + SMB_NTSTATUS_LOG_PINNED => Some("STATUS_LOG_PINNED"), + SMB_NTSTATUS_LOG_METADATA_FLUSH_FAILED => Some("STATUS_LOG_METADATA_FLUSH_FAILED"), + SMB_NTSTATUS_LOG_INCONSISTENT_SECURITY => Some("STATUS_LOG_INCONSISTENT_SECURITY"), + SMB_NTSTATUS_LOG_APPENDED_FLUSH_FAILED => Some("STATUS_LOG_APPENDED_FLUSH_FAILED"), + SMB_NTSTATUS_LOG_PINNED_RESERVATION => Some("STATUS_LOG_PINNED_RESERVATION"), + SMB_NTSTATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD => { + Some("STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD") + } + SMB_NTSTATUS_FLT_NO_HANDLER_DEFINED => Some("STATUS_FLT_NO_HANDLER_DEFINED"), + SMB_NTSTATUS_FLT_CONTEXT_ALREADY_DEFINED => Some("STATUS_FLT_CONTEXT_ALREADY_DEFINED"), + SMB_NTSTATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST => { + Some("STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST") + } + SMB_NTSTATUS_FLT_DISALLOW_FAST_IO => Some("STATUS_FLT_DISALLOW_FAST_IO"), + SMB_NTSTATUS_FLT_INVALID_NAME_REQUEST => Some("STATUS_FLT_INVALID_NAME_REQUEST"), + SMB_NTSTATUS_FLT_NOT_SAFE_TO_POST_OPERATION => { + Some("STATUS_FLT_NOT_SAFE_TO_POST_OPERATION") + } + SMB_NTSTATUS_FLT_NOT_INITIALIZED => Some("STATUS_FLT_NOT_INITIALIZED"), + SMB_NTSTATUS_FLT_FILTER_NOT_READY => Some("STATUS_FLT_FILTER_NOT_READY"), + SMB_NTSTATUS_FLT_POST_OPERATION_CLEANUP => Some("STATUS_FLT_POST_OPERATION_CLEANUP"), + SMB_NTSTATUS_FLT_INTERNAL_ERROR => Some("STATUS_FLT_INTERNAL_ERROR"), + SMB_NTSTATUS_FLT_DELETING_OBJECT => Some("STATUS_FLT_DELETING_OBJECT"), + SMB_NTSTATUS_FLT_MUST_BE_NONPAGED_POOL => Some("STATUS_FLT_MUST_BE_NONPAGED_POOL"), + SMB_NTSTATUS_FLT_DUPLICATE_ENTRY => Some("STATUS_FLT_DUPLICATE_ENTRY"), + SMB_NTSTATUS_FLT_CBDQ_DISABLED => Some("STATUS_FLT_CBDQ_DISABLED"), + SMB_NTSTATUS_FLT_DO_NOT_ATTACH => Some("STATUS_FLT_DO_NOT_ATTACH"), + SMB_NTSTATUS_FLT_DO_NOT_DETACH => Some("STATUS_FLT_DO_NOT_DETACH"), + SMB_NTSTATUS_FLT_INSTANCE_ALTITUDE_COLLISION => { + Some("STATUS_FLT_INSTANCE_ALTITUDE_COLLISION") + } + SMB_NTSTATUS_FLT_INSTANCE_NAME_COLLISION => Some("STATUS_FLT_INSTANCE_NAME_COLLISION"), + SMB_NTSTATUS_FLT_FILTER_NOT_FOUND => Some("STATUS_FLT_FILTER_NOT_FOUND"), + SMB_NTSTATUS_FLT_VOLUME_NOT_FOUND => Some("STATUS_FLT_VOLUME_NOT_FOUND"), + SMB_NTSTATUS_FLT_INSTANCE_NOT_FOUND => Some("STATUS_FLT_INSTANCE_NOT_FOUND"), + SMB_NTSTATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND => { + Some("STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND") + } + SMB_NTSTATUS_FLT_INVALID_CONTEXT_REGISTRATION => { + Some("STATUS_FLT_INVALID_CONTEXT_REGISTRATION") + } + SMB_NTSTATUS_FLT_NAME_CACHE_MISS => Some("STATUS_FLT_NAME_CACHE_MISS"), + SMB_NTSTATUS_FLT_NO_DEVICE_OBJECT => Some("STATUS_FLT_NO_DEVICE_OBJECT"), + SMB_NTSTATUS_FLT_VOLUME_ALREADY_MOUNTED => Some("STATUS_FLT_VOLUME_ALREADY_MOUNTED"), + SMB_NTSTATUS_FLT_ALREADY_ENLISTED => Some("STATUS_FLT_ALREADY_ENLISTED"), + SMB_NTSTATUS_FLT_CONTEXT_ALREADY_LINKED => Some("STATUS_FLT_CONTEXT_ALREADY_LINKED"), + SMB_NTSTATUS_FLT_NO_WAITER_FOR_REPLY => Some("STATUS_FLT_NO_WAITER_FOR_REPLY"), + SMB_NTSTATUS_MONITOR_NO_DESCRIPTOR => Some("STATUS_MONITOR_NO_DESCRIPTOR"), + SMB_NTSTATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT => { + Some("STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT") + } + SMB_NTSTATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM => { + Some("STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM") + } + SMB_NTSTATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK => { + Some("STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK") + } + SMB_NTSTATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED => { + Some("STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED") + } + SMB_NTSTATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK => { + Some("STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK") + } + SMB_NTSTATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK => { + Some("STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK") + } + SMB_NTSTATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA => { + Some("STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA") + } + SMB_NTSTATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK => { + Some("STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK") + } + SMB_NTSTATUS_MONITOR_INVALID_MANUFACTURE_DATE => { + Some("STATUS_MONITOR_INVALID_MANUFACTURE_DATE") + } + SMB_NTSTATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER => { + Some("STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER") + } + SMB_NTSTATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER => { + Some("STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER") + } + SMB_NTSTATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER => { + Some("STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER") + } + SMB_NTSTATUS_GRAPHICS_ADAPTER_WAS_RESET => Some("STATUS_GRAPHICS_ADAPTER_WAS_RESET"), + SMB_NTSTATUS_GRAPHICS_INVALID_DRIVER_MODEL => Some("STATUS_GRAPHICS_INVALID_DRIVER_MODEL"), + SMB_NTSTATUS_GRAPHICS_PRESENT_MODE_CHANGED => Some("STATUS_GRAPHICS_PRESENT_MODE_CHANGED"), + SMB_NTSTATUS_GRAPHICS_PRESENT_OCCLUDED => Some("STATUS_GRAPHICS_PRESENT_OCCLUDED"), + SMB_NTSTATUS_GRAPHICS_PRESENT_DENIED => Some("STATUS_GRAPHICS_PRESENT_DENIED"), + SMB_NTSTATUS_GRAPHICS_CANNOTCOLORCONVERT => Some("STATUS_GRAPHICS_CANNOTCOLORCONVERT"), + SMB_NTSTATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED => { + Some("STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED") + } + SMB_NTSTATUS_GRAPHICS_PRESENT_UNOCCLUDED => Some("STATUS_GRAPHICS_PRESENT_UNOCCLUDED"), + SMB_NTSTATUS_GRAPHICS_NO_VIDEO_MEMORY => Some("STATUS_GRAPHICS_NO_VIDEO_MEMORY"), + SMB_NTSTATUS_GRAPHICS_CANT_LOCK_MEMORY => Some("STATUS_GRAPHICS_CANT_LOCK_MEMORY"), + SMB_NTSTATUS_GRAPHICS_ALLOCATION_BUSY => Some("STATUS_GRAPHICS_ALLOCATION_BUSY"), + SMB_NTSTATUS_GRAPHICS_TOO_MANY_REFERENCES => Some("STATUS_GRAPHICS_TOO_MANY_REFERENCES"), + SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_LATER => Some("STATUS_GRAPHICS_TRY_AGAIN_LATER"), + SMB_NTSTATUS_GRAPHICS_TRY_AGAIN_NOW => Some("STATUS_GRAPHICS_TRY_AGAIN_NOW"), + SMB_NTSTATUS_GRAPHICS_ALLOCATION_INVALID => Some("STATUS_GRAPHICS_ALLOCATION_INVALID"), + SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE => { + Some("STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE") + } + SMB_NTSTATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED => { + Some("STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION => { + Some("STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION") + } + SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_USAGE => { + Some("STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE") + } + SMB_NTSTATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION => { + Some("STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION") + } + SMB_NTSTATUS_GRAPHICS_ALLOCATION_CLOSED => Some("STATUS_GRAPHICS_ALLOCATION_CLOSED"), + SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE => { + Some("STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE => { + Some("STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE") + } + SMB_NTSTATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE => { + Some("STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE") + } + SMB_NTSTATUS_GRAPHICS_ALLOCATION_CONTENT_LOST => { + Some("STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST") + } + SMB_NTSTATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE => { + Some("STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY => { + Some("STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY") + } + SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN => Some("STATUS_GRAPHICS_INVALID_VIDPN"), + SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE => { + Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET => { + Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET") + } + SMB_NTSTATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET => { + Some("STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET => { + Some("STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_FREQUENCY => Some("STATUS_GRAPHICS_INVALID_FREQUENCY"), + SMB_NTSTATUS_GRAPHICS_INVALID_ACTIVE_REGION => { + Some("STATUS_GRAPHICS_INVALID_ACTIVE_REGION") + } + SMB_NTSTATUS_GRAPHICS_INVALID_TOTAL_REGION => Some("STATUS_GRAPHICS_INVALID_TOTAL_REGION"), + SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE => { + Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE => { + Some("STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE") + } + SMB_NTSTATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET => { + Some("STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET") + } + SMB_NTSTATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY => { + Some("STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY") + } + SMB_NTSTATUS_GRAPHICS_MODE_ALREADY_IN_MODESET => { + Some("STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET => { + Some("STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET => { + Some("STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET") + } + SMB_NTSTATUS_GRAPHICS_SOURCE_ALREADY_IN_SET => { + Some("STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET") + } + SMB_NTSTATUS_GRAPHICS_TARGET_ALREADY_IN_SET => { + Some("STATUS_GRAPHICS_TARGET_ALREADY_IN_SET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH => { + Some("STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH") + } + SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY => { + Some("STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET => { + Some("STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE => { + Some("STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE") + } + SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET => { + Some("STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET") + } + SMB_NTSTATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET => { + Some("STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET") + } + SMB_NTSTATUS_GRAPHICS_STALE_MODESET => Some("STATUS_GRAPHICS_STALE_MODESET"), + SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET => { + Some("STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE => { + Some("STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE") + } + SMB_NTSTATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN => { + Some("STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN") + } + SMB_NTSTATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE => { + Some("STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE") + } + SMB_NTSTATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION => { + Some("STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION") + } + SMB_NTSTATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES => { + Some("STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES") + } + SMB_NTSTATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY => Some("STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY"), + SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE => { + Some("STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE") + } + SMB_NTSTATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET => { + Some("STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET => { + Some("STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR => { + Some("STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR") + } + SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET => { + Some("STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET") + } + SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET => { + Some("STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET") + } + SMB_NTSTATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE => { + Some("STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE => { + Some("STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE") + } + SMB_NTSTATUS_GRAPHICS_RESOURCES_NOT_RELATED => { + Some("STATUS_GRAPHICS_RESOURCES_NOT_RELATED") + } + SMB_NTSTATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE => { + Some("STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE") + } + SMB_NTSTATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE => { + Some("STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE") + } + SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET => { + Some("STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET") + } + SMB_NTSTATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER => { + Some("STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER") + } + SMB_NTSTATUS_GRAPHICS_NO_VIDPNMGR => Some("STATUS_GRAPHICS_NO_VIDPNMGR"), + SMB_NTSTATUS_GRAPHICS_NO_ACTIVE_VIDPN => Some("STATUS_GRAPHICS_NO_ACTIVE_VIDPN"), + SMB_NTSTATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY => Some("STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY"), + SMB_NTSTATUS_GRAPHICS_MONITOR_NOT_CONNECTED => { + Some("STATUS_GRAPHICS_MONITOR_NOT_CONNECTED") + } + SMB_NTSTATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY => { + Some("STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY") + } + SMB_NTSTATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE => { + Some("STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE => { + Some("STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_STRIDE => Some("STATUS_GRAPHICS_INVALID_STRIDE"), + SMB_NTSTATUS_GRAPHICS_INVALID_PIXELFORMAT => Some("STATUS_GRAPHICS_INVALID_PIXELFORMAT"), + SMB_NTSTATUS_GRAPHICS_INVALID_COLORBASIS => Some("STATUS_GRAPHICS_INVALID_COLORBASIS"), + SMB_NTSTATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE => { + Some("STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE") + } + SMB_NTSTATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY => { + Some("STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY") + } + SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT => { + Some("STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT") + } + SMB_NTSTATUS_GRAPHICS_VIDPN_SOURCE_IN_USE => Some("STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"), + SMB_NTSTATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN => { + Some("STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN") + } + SMB_NTSTATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL => { + Some("STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL") + } + SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION => { + Some("STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION") + } + SMB_NTSTATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_INVALID_GAMMA_RAMP => Some("STATUS_GRAPHICS_INVALID_GAMMA_RAMP"), + SMB_NTSTATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_MODE_NOT_IN_MODESET => Some("STATUS_GRAPHICS_MODE_NOT_IN_MODESET"), + SMB_NTSTATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON => { + Some("STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON") + } + SMB_NTSTATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE => { + Some("STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE") + } + SMB_NTSTATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE => { + Some("STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE") + } + SMB_NTSTATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS => { + Some("STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS") + } + SMB_NTSTATUS_GRAPHICS_INVALID_SCANLINE_ORDERING => { + Some("STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING") + } + SMB_NTSTATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED => { + Some("STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED") + } + SMB_NTSTATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS => { + Some("STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS") + } + SMB_NTSTATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT => { + Some("STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM => { + Some("STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN => { + Some("STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN") + } + SMB_NTSTATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT => { + Some("STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT") + } + SMB_NTSTATUS_GRAPHICS_MAX_NUM_PATHS_REACHED => { + Some("STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED") + } + SMB_NTSTATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION => { + Some("STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION") + } + SMB_NTSTATUS_GRAPHICS_INVALID_CLIENT_TYPE => Some("STATUS_GRAPHICS_INVALID_CLIENT_TYPE"), + SMB_NTSTATUS_GRAPHICS_CLIENTVIDPN_NOT_SET => Some("STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET"), + SMB_NTSTATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED => { + Some("STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED") + } + SMB_NTSTATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_NOT_A_LINKED_ADAPTER => Some("STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER"), + SMB_NTSTATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED => { + Some("STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED") + } + SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED => { + Some("STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED") + } + SMB_NTSTATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY => { + Some("STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY") + } + SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_STARTED => { + Some("STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED") + } + SMB_NTSTATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON => { + Some("STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON") + } + SMB_NTSTATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE => { + Some("STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE") + } + SMB_NTSTATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER => { + Some("STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER") + } + SMB_NTSTATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED => { + Some("STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED") + } + SMB_NTSTATUS_GRAPHICS_OPM_NOT_SUPPORTED => Some("STATUS_GRAPHICS_OPM_NOT_SUPPORTED"), + SMB_NTSTATUS_GRAPHICS_COPP_NOT_SUPPORTED => Some("STATUS_GRAPHICS_COPP_NOT_SUPPORTED"), + SMB_NTSTATUS_GRAPHICS_UAB_NOT_SUPPORTED => Some("STATUS_GRAPHICS_UAB_NOT_SUPPORTED"), + SMB_NTSTATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS => { + Some("STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS") + } + SMB_NTSTATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL => { + Some("STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL") + } + SMB_NTSTATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST => { + Some("STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST") + } + SMB_NTSTATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME => { + Some("STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME") + } + SMB_NTSTATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP => { + Some("STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP") + } + SMB_NTSTATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_OPM_INVALID_POINTER => Some("STATUS_GRAPHICS_OPM_INVALID_POINTER"), + SMB_NTSTATUS_GRAPHICS_OPM_INTERNAL_ERROR => Some("STATUS_GRAPHICS_OPM_INTERNAL_ERROR"), + SMB_NTSTATUS_GRAPHICS_OPM_INVALID_HANDLE => Some("STATUS_GRAPHICS_OPM_INVALID_HANDLE"), + SMB_NTSTATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE => { + Some("STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE") + } + SMB_NTSTATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH => { + Some("STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH") + } + SMB_NTSTATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED => { + Some("STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED") + } + SMB_NTSTATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED => { + Some("STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED") + } + SMB_NTSTATUS_GRAPHICS_PVP_HFS_FAILED => Some("STATUS_GRAPHICS_PVP_HFS_FAILED"), + SMB_NTSTATUS_GRAPHICS_OPM_INVALID_SRM => Some("STATUS_GRAPHICS_OPM_INVALID_SRM"), + SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP => { + Some("STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP") + } + SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP => { + Some("STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP") + } + SMB_NTSTATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA => { + Some("STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA") + } + SMB_NTSTATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET => { + Some("STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET") + } + SMB_NTSTATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH => { + Some("STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH") + } + SMB_NTSTATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE => { + Some("STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE") + } + SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS => { + Some("STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS") + } + SMB_NTSTATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS => { + Some("STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS") + } + SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS => { + Some("STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS") + } + SMB_NTSTATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST => { + Some("STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST") + } + SMB_NTSTATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR => { + Some("STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR") + } + SMB_NTSTATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS => { + Some("STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS") + } + SMB_NTSTATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST => { + Some("STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST") + } + SMB_NTSTATUS_GRAPHICS_I2C_NOT_SUPPORTED => Some("STATUS_GRAPHICS_I2C_NOT_SUPPORTED"), + SMB_NTSTATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST => { + Some("STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST") + } + SMB_NTSTATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA => { + Some("STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA") + } + SMB_NTSTATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA => { + Some("STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA") + } + SMB_NTSTATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_DATA => Some("STATUS_GRAPHICS_DDCCI_INVALID_DATA"), + SMB_NTSTATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE => { + Some("STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE") + } + SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING => { + Some("STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING") + } + SMB_NTSTATUS_GRAPHICS_MCA_INTERNAL_ERROR => Some("STATUS_GRAPHICS_MCA_INTERNAL_ERROR"), + SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND => { + Some("STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND") + } + SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH => { + Some("STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH") + } + SMB_NTSTATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM => { + Some("STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM") + } + SMB_NTSTATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE => { + Some("STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE") + } + SMB_NTSTATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS => { + Some("STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS") + } + SMB_NTSTATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED => { + Some("STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME => { + Some("STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME") + } + SMB_NTSTATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP => { + Some("STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP") + } + SMB_NTSTATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED => { + Some("STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED") + } + SMB_NTSTATUS_GRAPHICS_INVALID_POINTER => Some("STATUS_GRAPHICS_INVALID_POINTER"), + SMB_NTSTATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE => { + Some("STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE") + } + SMB_NTSTATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL => { + Some("STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL") + } + SMB_NTSTATUS_GRAPHICS_INTERNAL_ERROR => Some("STATUS_GRAPHICS_INTERNAL_ERROR"), + SMB_NTSTATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS => { + Some("STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS") + } + SMB_NTSTATUS_FVE_LOCKED_VOLUME => Some("STATUS_FVE_LOCKED_VOLUME"), + SMB_NTSTATUS_FVE_NOT_ENCRYPTED => Some("STATUS_FVE_NOT_ENCRYPTED"), + SMB_NTSTATUS_FVE_BAD_INFORMATION => Some("STATUS_FVE_BAD_INFORMATION"), + SMB_NTSTATUS_FVE_TOO_SMALL => Some("STATUS_FVE_TOO_SMALL"), + SMB_NTSTATUS_FVE_FAILED_WRONG_FS => Some("STATUS_FVE_FAILED_WRONG_FS"), + SMB_NTSTATUS_FVE_FAILED_BAD_FS => Some("STATUS_FVE_FAILED_BAD_FS"), + SMB_NTSTATUS_FVE_FS_NOT_EXTENDED => Some("STATUS_FVE_FS_NOT_EXTENDED"), + SMB_NTSTATUS_FVE_FS_MOUNTED => Some("STATUS_FVE_FS_MOUNTED"), + SMB_NTSTATUS_FVE_NO_LICENSE => Some("STATUS_FVE_NO_LICENSE"), + SMB_NTSTATUS_FVE_ACTION_NOT_ALLOWED => Some("STATUS_FVE_ACTION_NOT_ALLOWED"), + SMB_NTSTATUS_FVE_BAD_DATA => Some("STATUS_FVE_BAD_DATA"), + SMB_NTSTATUS_FVE_VOLUME_NOT_BOUND => Some("STATUS_FVE_VOLUME_NOT_BOUND"), + SMB_NTSTATUS_FVE_NOT_DATA_VOLUME => Some("STATUS_FVE_NOT_DATA_VOLUME"), + SMB_NTSTATUS_FVE_CONV_READ_ERROR => Some("STATUS_FVE_CONV_READ_ERROR"), + SMB_NTSTATUS_FVE_CONV_WRITE_ERROR => Some("STATUS_FVE_CONV_WRITE_ERROR"), + SMB_NTSTATUS_FVE_OVERLAPPED_UPDATE => Some("STATUS_FVE_OVERLAPPED_UPDATE"), + SMB_NTSTATUS_FVE_FAILED_SECTOR_SIZE => Some("STATUS_FVE_FAILED_SECTOR_SIZE"), + SMB_NTSTATUS_FVE_FAILED_AUTHENTICATION => Some("STATUS_FVE_FAILED_AUTHENTICATION"), + SMB_NTSTATUS_FVE_NOT_OS_VOLUME => Some("STATUS_FVE_NOT_OS_VOLUME"), + SMB_NTSTATUS_FVE_KEYFILE_NOT_FOUND => Some("STATUS_FVE_KEYFILE_NOT_FOUND"), + SMB_NTSTATUS_FVE_KEYFILE_INVALID => Some("STATUS_FVE_KEYFILE_INVALID"), + SMB_NTSTATUS_FVE_KEYFILE_NO_VMK => Some("STATUS_FVE_KEYFILE_NO_VMK"), + SMB_NTSTATUS_FVE_TPM_DISABLED => Some("STATUS_FVE_TPM_DISABLED"), + SMB_NTSTATUS_FVE_TPM_SRK_AUTH_NOT_ZERO => Some("STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO"), + SMB_NTSTATUS_FVE_TPM_INVALID_PCR => Some("STATUS_FVE_TPM_INVALID_PCR"), + SMB_NTSTATUS_FVE_TPM_NO_VMK => Some("STATUS_FVE_TPM_NO_VMK"), + SMB_NTSTATUS_FVE_PIN_INVALID => Some("STATUS_FVE_PIN_INVALID"), + SMB_NTSTATUS_FVE_AUTH_INVALID_APPLICATION => Some("STATUS_FVE_AUTH_INVALID_APPLICATION"), + SMB_NTSTATUS_FVE_AUTH_INVALID_CONFIG => Some("STATUS_FVE_AUTH_INVALID_CONFIG"), + SMB_NTSTATUS_FVE_DEBUGGER_ENABLED => Some("STATUS_FVE_DEBUGGER_ENABLED"), + SMB_NTSTATUS_FVE_DRY_RUN_FAILED => Some("STATUS_FVE_DRY_RUN_FAILED"), + SMB_NTSTATUS_FVE_BAD_METADATA_POINTER => Some("STATUS_FVE_BAD_METADATA_POINTER"), + SMB_NTSTATUS_FVE_OLD_METADATA_COPY => Some("STATUS_FVE_OLD_METADATA_COPY"), + SMB_NTSTATUS_FVE_REBOOT_REQUIRED => Some("STATUS_FVE_REBOOT_REQUIRED"), + SMB_NTSTATUS_FVE_RAW_ACCESS => Some("STATUS_FVE_RAW_ACCESS"), + SMB_NTSTATUS_FVE_RAW_BLOCKED => Some("STATUS_FVE_RAW_BLOCKED"), + SMB_NTSTATUS_FVE_NO_FEATURE_LICENSE => Some("STATUS_FVE_NO_FEATURE_LICENSE"), + SMB_NTSTATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED => { + Some("STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED") + } + SMB_NTSTATUS_FVE_CONV_RECOVERY_FAILED => Some("STATUS_FVE_CONV_RECOVERY_FAILED"), + SMB_NTSTATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG => Some("STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG"), + SMB_NTSTATUS_FVE_VOLUME_TOO_SMALL => Some("STATUS_FVE_VOLUME_TOO_SMALL"), + SMB_NTSTATUS_FWP_CALLOUT_NOT_FOUND => Some("STATUS_FWP_CALLOUT_NOT_FOUND"), + SMB_NTSTATUS_FWP_CONDITION_NOT_FOUND => Some("STATUS_FWP_CONDITION_NOT_FOUND"), + SMB_NTSTATUS_FWP_FILTER_NOT_FOUND => Some("STATUS_FWP_FILTER_NOT_FOUND"), + SMB_NTSTATUS_FWP_LAYER_NOT_FOUND => Some("STATUS_FWP_LAYER_NOT_FOUND"), + SMB_NTSTATUS_FWP_PROVIDER_NOT_FOUND => Some("STATUS_FWP_PROVIDER_NOT_FOUND"), + SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND => { + Some("STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND") + } + SMB_NTSTATUS_FWP_SUBLAYER_NOT_FOUND => Some("STATUS_FWP_SUBLAYER_NOT_FOUND"), + SMB_NTSTATUS_FWP_NOT_FOUND => Some("STATUS_FWP_NOT_FOUND"), + SMB_NTSTATUS_FWP_ALREADY_EXISTS => Some("STATUS_FWP_ALREADY_EXISTS"), + SMB_NTSTATUS_FWP_IN_USE => Some("STATUS_FWP_IN_USE"), + SMB_NTSTATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS => { + Some("STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS") + } + SMB_NTSTATUS_FWP_WRONG_SESSION => Some("STATUS_FWP_WRONG_SESSION"), + SMB_NTSTATUS_FWP_NO_TXN_IN_PROGRESS => Some("STATUS_FWP_NO_TXN_IN_PROGRESS"), + SMB_NTSTATUS_FWP_TXN_IN_PROGRESS => Some("STATUS_FWP_TXN_IN_PROGRESS"), + SMB_NTSTATUS_FWP_TXN_ABORTED => Some("STATUS_FWP_TXN_ABORTED"), + SMB_NTSTATUS_FWP_SESSION_ABORTED => Some("STATUS_FWP_SESSION_ABORTED"), + SMB_NTSTATUS_FWP_INCOMPATIBLE_TXN => Some("STATUS_FWP_INCOMPATIBLE_TXN"), + SMB_NTSTATUS_FWP_TIMEOUT => Some("STATUS_FWP_TIMEOUT"), + SMB_NTSTATUS_FWP_NET_EVENTS_DISABLED => Some("STATUS_FWP_NET_EVENTS_DISABLED"), + SMB_NTSTATUS_FWP_INCOMPATIBLE_LAYER => Some("STATUS_FWP_INCOMPATIBLE_LAYER"), + SMB_NTSTATUS_FWP_KM_CLIENTS_ONLY => Some("STATUS_FWP_KM_CLIENTS_ONLY"), + SMB_NTSTATUS_FWP_LIFETIME_MISMATCH => Some("STATUS_FWP_LIFETIME_MISMATCH"), + SMB_NTSTATUS_FWP_BUILTIN_OBJECT => Some("STATUS_FWP_BUILTIN_OBJECT"), + SMB_NTSTATUS_FWP_TOO_MANY_BOOTTIME_FILTERS => Some("STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS"), + SMB_NTSTATUS_FWP_NOTIFICATION_DROPPED => Some("STATUS_FWP_NOTIFICATION_DROPPED"), + SMB_NTSTATUS_FWP_TRAFFIC_MISMATCH => Some("STATUS_FWP_TRAFFIC_MISMATCH"), + SMB_NTSTATUS_FWP_INCOMPATIBLE_SA_STATE => Some("STATUS_FWP_INCOMPATIBLE_SA_STATE"), + SMB_NTSTATUS_FWP_NULL_POINTER => Some("STATUS_FWP_NULL_POINTER"), + SMB_NTSTATUS_FWP_INVALID_ENUMERATOR => Some("STATUS_FWP_INVALID_ENUMERATOR"), + SMB_NTSTATUS_FWP_INVALID_FLAGS => Some("STATUS_FWP_INVALID_FLAGS"), + SMB_NTSTATUS_FWP_INVALID_NET_MASK => Some("STATUS_FWP_INVALID_NET_MASK"), + SMB_NTSTATUS_FWP_INVALID_RANGE => Some("STATUS_FWP_INVALID_RANGE"), + SMB_NTSTATUS_FWP_INVALID_INTERVAL => Some("STATUS_FWP_INVALID_INTERVAL"), + SMB_NTSTATUS_FWP_ZERO_LENGTH_ARRAY => Some("STATUS_FWP_ZERO_LENGTH_ARRAY"), + SMB_NTSTATUS_FWP_NULL_DISPLAY_NAME => Some("STATUS_FWP_NULL_DISPLAY_NAME"), + SMB_NTSTATUS_FWP_INVALID_ACTION_TYPE => Some("STATUS_FWP_INVALID_ACTION_TYPE"), + SMB_NTSTATUS_FWP_INVALID_WEIGHT => Some("STATUS_FWP_INVALID_WEIGHT"), + SMB_NTSTATUS_FWP_MATCH_TYPE_MISMATCH => Some("STATUS_FWP_MATCH_TYPE_MISMATCH"), + SMB_NTSTATUS_FWP_TYPE_MISMATCH => Some("STATUS_FWP_TYPE_MISMATCH"), + SMB_NTSTATUS_FWP_OUT_OF_BOUNDS => Some("STATUS_FWP_OUT_OF_BOUNDS"), + SMB_NTSTATUS_FWP_RESERVED => Some("STATUS_FWP_RESERVED"), + SMB_NTSTATUS_FWP_DUPLICATE_CONDITION => Some("STATUS_FWP_DUPLICATE_CONDITION"), + SMB_NTSTATUS_FWP_DUPLICATE_KEYMOD => Some("STATUS_FWP_DUPLICATE_KEYMOD"), + SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER => { + Some("STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER") + } + SMB_NTSTATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER => { + Some("STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER") + } + SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER => { + Some("STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER") + } + SMB_NTSTATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT => { + Some("STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT") + } + SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_METHOD => Some("STATUS_FWP_INCOMPATIBLE_AUTH_METHOD"), + SMB_NTSTATUS_FWP_INCOMPATIBLE_DH_GROUP => Some("STATUS_FWP_INCOMPATIBLE_DH_GROUP"), + SMB_NTSTATUS_FWP_EM_NOT_SUPPORTED => Some("STATUS_FWP_EM_NOT_SUPPORTED"), + SMB_NTSTATUS_FWP_NEVER_MATCH => Some("STATUS_FWP_NEVER_MATCH"), + SMB_NTSTATUS_FWP_PROVIDER_CONTEXT_MISMATCH => Some("STATUS_FWP_PROVIDER_CONTEXT_MISMATCH"), + SMB_NTSTATUS_FWP_INVALID_PARAMETER => Some("STATUS_FWP_INVALID_PARAMETER"), + SMB_NTSTATUS_FWP_TOO_MANY_SUBLAYERS => Some("STATUS_FWP_TOO_MANY_SUBLAYERS"), + SMB_NTSTATUS_FWP_CALLOUT_NOTIFICATION_FAILED => { + Some("STATUS_FWP_CALLOUT_NOTIFICATION_FAILED") + } + SMB_NTSTATUS_FWP_INCOMPATIBLE_AUTH_CONFIG => Some("STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG"), + SMB_NTSTATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG => { + Some("STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG") + } + SMB_NTSTATUS_FWP_DUPLICATE_AUTH_METHOD => Some("STATUS_FWP_DUPLICATE_AUTH_METHOD"), + SMB_NTSTATUS_FWP_TCPIP_NOT_READY => Some("STATUS_FWP_TCPIP_NOT_READY"), + SMB_NTSTATUS_FWP_INJECT_HANDLE_CLOSING => Some("STATUS_FWP_INJECT_HANDLE_CLOSING"), + SMB_NTSTATUS_FWP_INJECT_HANDLE_STALE => Some("STATUS_FWP_INJECT_HANDLE_STALE"), + SMB_NTSTATUS_FWP_CANNOT_PEND => Some("STATUS_FWP_CANNOT_PEND"), + SMB_NTSTATUS_NDIS_CLOSING => Some("STATUS_NDIS_CLOSING"), + SMB_NTSTATUS_NDIS_BAD_VERSION => Some("STATUS_NDIS_BAD_VERSION"), + SMB_NTSTATUS_NDIS_BAD_CHARACTERISTICS => Some("STATUS_NDIS_BAD_CHARACTERISTICS"), + SMB_NTSTATUS_NDIS_ADAPTER_NOT_FOUND => Some("STATUS_NDIS_ADAPTER_NOT_FOUND"), + SMB_NTSTATUS_NDIS_OPEN_FAILED => Some("STATUS_NDIS_OPEN_FAILED"), + SMB_NTSTATUS_NDIS_DEVICE_FAILED => Some("STATUS_NDIS_DEVICE_FAILED"), + SMB_NTSTATUS_NDIS_MULTICAST_FULL => Some("STATUS_NDIS_MULTICAST_FULL"), + SMB_NTSTATUS_NDIS_MULTICAST_EXISTS => Some("STATUS_NDIS_MULTICAST_EXISTS"), + SMB_NTSTATUS_NDIS_MULTICAST_NOT_FOUND => Some("STATUS_NDIS_MULTICAST_NOT_FOUND"), + SMB_NTSTATUS_NDIS_REQUEST_ABORTED => Some("STATUS_NDIS_REQUEST_ABORTED"), + SMB_NTSTATUS_NDIS_RESET_IN_PROGRESS => Some("STATUS_NDIS_RESET_IN_PROGRESS"), + SMB_NTSTATUS_NDIS_INVALID_PACKET => Some("STATUS_NDIS_INVALID_PACKET"), + SMB_NTSTATUS_NDIS_INVALID_DEVICE_REQUEST => Some("STATUS_NDIS_INVALID_DEVICE_REQUEST"), + SMB_NTSTATUS_NDIS_ADAPTER_NOT_READY => Some("STATUS_NDIS_ADAPTER_NOT_READY"), + SMB_NTSTATUS_NDIS_INVALID_LENGTH => Some("STATUS_NDIS_INVALID_LENGTH"), + SMB_NTSTATUS_NDIS_INVALID_DATA => Some("STATUS_NDIS_INVALID_DATA"), + SMB_NTSTATUS_NDIS_BUFFER_TOO_SHORT => Some("STATUS_NDIS_BUFFER_TOO_SHORT"), + SMB_NTSTATUS_NDIS_INVALID_OID => Some("STATUS_NDIS_INVALID_OID"), + SMB_NTSTATUS_NDIS_ADAPTER_REMOVED => Some("STATUS_NDIS_ADAPTER_REMOVED"), + SMB_NTSTATUS_NDIS_UNSUPPORTED_MEDIA => Some("STATUS_NDIS_UNSUPPORTED_MEDIA"), + SMB_NTSTATUS_NDIS_GROUP_ADDRESS_IN_USE => Some("STATUS_NDIS_GROUP_ADDRESS_IN_USE"), + SMB_NTSTATUS_NDIS_FILE_NOT_FOUND => Some("STATUS_NDIS_FILE_NOT_FOUND"), + SMB_NTSTATUS_NDIS_ERROR_READING_FILE => Some("STATUS_NDIS_ERROR_READING_FILE"), + SMB_NTSTATUS_NDIS_ALREADY_MAPPED => Some("STATUS_NDIS_ALREADY_MAPPED"), + SMB_NTSTATUS_NDIS_RESOURCE_CONFLICT => Some("STATUS_NDIS_RESOURCE_CONFLICT"), + SMB_NTSTATUS_NDIS_MEDIA_DISCONNECTED => Some("STATUS_NDIS_MEDIA_DISCONNECTED"), + SMB_NTSTATUS_NDIS_INVALID_ADDRESS => Some("STATUS_NDIS_INVALID_ADDRESS"), + SMB_NTSTATUS_NDIS_PAUSED => Some("STATUS_NDIS_PAUSED"), + SMB_NTSTATUS_NDIS_INTERFACE_NOT_FOUND => Some("STATUS_NDIS_INTERFACE_NOT_FOUND"), + SMB_NTSTATUS_NDIS_UNSUPPORTED_REVISION => Some("STATUS_NDIS_UNSUPPORTED_REVISION"), + SMB_NTSTATUS_NDIS_INVALID_PORT => Some("STATUS_NDIS_INVALID_PORT"), + SMB_NTSTATUS_NDIS_INVALID_PORT_STATE => Some("STATUS_NDIS_INVALID_PORT_STATE"), + SMB_NTSTATUS_NDIS_LOW_POWER_STATE => Some("STATUS_NDIS_LOW_POWER_STATE"), + SMB_NTSTATUS_NDIS_NOT_SUPPORTED => Some("STATUS_NDIS_NOT_SUPPORTED"), + SMB_NTSTATUS_NDIS_OFFLOAD_POLICY => Some("STATUS_NDIS_OFFLOAD_POLICY"), + SMB_NTSTATUS_NDIS_OFFLOAD_CONNECTION_REJECTED => { + Some("STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED") + } + SMB_NTSTATUS_NDIS_OFFLOAD_PATH_REJECTED => Some("STATUS_NDIS_OFFLOAD_PATH_REJECTED"), + SMB_NTSTATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED => { + Some("STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED") + } + SMB_NTSTATUS_NDIS_DOT11_MEDIA_IN_USE => Some("STATUS_NDIS_DOT11_MEDIA_IN_USE"), + SMB_NTSTATUS_NDIS_DOT11_POWER_STATE_INVALID => { + Some("STATUS_NDIS_DOT11_POWER_STATE_INVALID") + } + SMB_NTSTATUS_NDIS_PM_WOL_PATTERN_LIST_FULL => Some("STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL"), + SMB_NTSTATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL => { + Some("STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL") + } + SMB_NTSTATUS_IPSEC_BAD_SPI => Some("STATUS_IPSEC_BAD_SPI"), + SMB_NTSTATUS_IPSEC_SA_LIFETIME_EXPIRED => Some("STATUS_IPSEC_SA_LIFETIME_EXPIRED"), + SMB_NTSTATUS_IPSEC_WRONG_SA => Some("STATUS_IPSEC_WRONG_SA"), + SMB_NTSTATUS_IPSEC_REPLAY_CHECK_FAILED => Some("STATUS_IPSEC_REPLAY_CHECK_FAILED"), + SMB_NTSTATUS_IPSEC_INVALID_PACKET => Some("STATUS_IPSEC_INVALID_PACKET"), + SMB_NTSTATUS_IPSEC_INTEGRITY_CHECK_FAILED => Some("STATUS_IPSEC_INTEGRITY_CHECK_FAILED"), + SMB_NTSTATUS_IPSEC_CLEAR_TEXT_DROP => Some("STATUS_IPSEC_CLEAR_TEXT_DROP"), + SMB_NTSTATUS_IPSEC_AUTH_FIREWALL_DROP => Some("STATUS_IPSEC_AUTH_FIREWALL_DROP"), + SMB_NTSTATUS_IPSEC_THROTTLE_DROP => Some("STATUS_IPSEC_THROTTLE_DROP"), + SMB_NTSTATUS_IPSEC_DOSP_BLOCK => Some("STATUS_IPSEC_DOSP_BLOCK"), + SMB_NTSTATUS_IPSEC_DOSP_RECEIVED_MULTICAST => Some("STATUS_IPSEC_DOSP_RECEIVED_MULTICAST"), + SMB_NTSTATUS_IPSEC_DOSP_INVALID_PACKET => Some("STATUS_IPSEC_DOSP_INVALID_PACKET"), + SMB_NTSTATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED => { + Some("STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED") + } + SMB_NTSTATUS_IPSEC_DOSP_MAX_ENTRIES => Some("STATUS_IPSEC_DOSP_MAX_ENTRIES"), + SMB_NTSTATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED => Some("STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED"), + SMB_NTSTATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES => { + Some("STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES") + } + SMB_NTSTATUS_VOLMGR_MIRROR_NOT_SUPPORTED => Some("STATUS_VOLMGR_MIRROR_NOT_SUPPORTED"), + SMB_NTSTATUS_VOLMGR_RAID5_NOT_SUPPORTED => Some("STATUS_VOLMGR_RAID5_NOT_SUPPORTED"), + SMB_NTSTATUS_VIRTDISK_PROVIDER_NOT_FOUND => Some("STATUS_VIRTDISK_PROVIDER_NOT_FOUND"), + SMB_NTSTATUS_VIRTDISK_NOT_VIRTUAL_DISK => Some("STATUS_VIRTDISK_NOT_VIRTUAL_DISK"), + SMB_NTSTATUS_VHD_PARENT_VHD_ACCESS_DENIED => Some("STATUS_VHD_PARENT_VHD_ACCESS_DENIED"), + SMB_NTSTATUS_VHD_CHILD_PARENT_SIZE_MISMATCH => { + Some("STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH") + } + SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED => { + Some("STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED") + } + SMB_NTSTATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT => { + Some("STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT") + } + _ => None, } } - diff --git a/rust/src/snmp/detect.rs b/rust/src/snmp/detect.rs index bb4ffd12c3ba..7661d3ce7473 100644 --- a/rust/src/snmp/detect.rs +++ b/rust/src/snmp/detect.rs @@ -20,23 +20,23 @@ use crate::snmp::snmp::SNMPTransaction; #[no_mangle] -pub unsafe extern "C" fn rs_snmp_tx_get_version(tx: &mut SNMPTransaction, version: *mut u32) { +pub unsafe extern fn rs_snmp_tx_get_version(tx: &mut SNMPTransaction, version: *mut u32) { debug_assert!(tx.version != 0, "SNMP version is 0"); *version = tx.version; } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_tx_get_community( +pub unsafe extern fn rs_snmp_tx_get_community( tx: &mut SNMPTransaction, buf: *mut *const u8, len: *mut u32, ) { - if let Some(ref c) = tx.community { + if let Some(ref c) = tx.community { *buf = c.as_ptr(); *len = c.len() as u32; } } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_tx_get_pdu_type(tx: &mut SNMPTransaction, pdu_type: *mut u32) { +pub unsafe extern fn rs_snmp_tx_get_pdu_type(tx: &mut SNMPTransaction, pdu_type: *mut u32) { match tx.info { Some(ref info) => { *pdu_type = info.pdu_type.0; @@ -48,10 +48,10 @@ pub unsafe extern "C" fn rs_snmp_tx_get_pdu_type(tx: &mut SNMPTransaction, pdu_t } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_tx_get_usm( +pub unsafe extern fn rs_snmp_tx_get_usm( tx: &mut SNMPTransaction, buf: *mut *const u8, len: *mut u32, ) { - if let Some(ref c) = tx.usm { + if let Some(ref c) = tx.usm { *buf = c.as_ptr(); *len = c.len() as u32; } diff --git a/rust/src/snmp/log.rs b/rust/src/snmp/log.rs index 5707f30ccb4e..20f45c04828a 100644 --- a/rust/src/snmp/log.rs +++ b/rust/src/snmp/log.rs @@ -19,10 +19,10 @@ use crate::jsonbuilder::{JsonBuilder, JsonError}; use crate::snmp::snmp::SNMPTransaction; -use crate::snmp::snmp_parser::{NetworkAddress,PduType}; +use crate::snmp::snmp_parser::{NetworkAddress, PduType}; use std::borrow::Cow; -fn str_of_pdu_type(t:&PduType) -> Cow { +fn str_of_pdu_type(t: &PduType) -> Cow { match t { &PduType::GetRequest => Cow::Borrowed("get_request"), &PduType::GetNextRequest => Cow::Borrowed("get_next_request"), @@ -37,8 +37,7 @@ fn str_of_pdu_type(t:&PduType) -> Cow { } } -fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result<(), JsonError> -{ +fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result<(), JsonError> { jsb.open_object("snmp")?; jsb.set_uint("version", tx.version as u64)?; if tx.encrypted { @@ -53,7 +52,9 @@ fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result< jsb.set_string("trap_type", &format!("{:?}", trap_type))?; jsb.set_string("trap_oid", &oid.to_string())?; match address { - NetworkAddress::IPv4(ip) => {jsb.set_string("trap_address", &ip.to_string())?;}, + NetworkAddress::IPv4(ip) => { + jsb.set_string("trap_address", &ip.to_string())?; + } } } if !info.vars.is_empty() { @@ -77,7 +78,6 @@ fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result< } #[no_mangle] -pub extern "C" fn rs_snmp_log_json_response(tx: &mut SNMPTransaction, jsb: &mut JsonBuilder) -> bool -{ +pub extern fn rs_snmp_log_json_response(tx: &mut SNMPTransaction, jsb: &mut JsonBuilder) -> bool { snmp_log_response(jsb, tx).is_ok() } diff --git a/rust/src/snmp/mod.rs b/rust/src/snmp/mod.rs index 7c6ceb35884b..b8c769f45855 100644 --- a/rust/src/snmp/mod.rs +++ b/rust/src/snmp/mod.rs @@ -21,6 +21,6 @@ extern crate snmp_parser; -pub mod snmp; -pub mod log; pub mod detect; +pub mod log; +pub mod snmp; diff --git a/rust/src/snmp/snmp.rs b/rust/src/snmp/snmp.rs index a4481f4bc191..daaa99a67a01 100644 --- a/rust/src/snmp/snmp.rs +++ b/rust/src/snmp/snmp.rs @@ -17,17 +17,17 @@ // written by Pierre Chifflier -use crate::snmp::snmp_parser::*; -use crate::core::{self, *}; use crate::applayer::{self, *}; +use crate::core::{self, *}; +use crate::snmp::snmp_parser::*; use std; use std::ffi::CString; use asn1_rs::Oid; use der_parser::ber::BerObjectContent; use der_parser::der::parse_der_sequence; +use nom7::error::{make_error, ErrorKind}; use nom7::{Err, IResult}; -use nom7::error::{ErrorKind, make_error}; #[derive(AppLayerEvent)] pub enum SNMPEvent { @@ -55,7 +55,7 @@ pub struct SNMPPduInfo<'a> { pub err: ErrorStatus, - pub trap_type: Option<(TrapType,Oid<'a>,NetworkAddress)>, + pub trap_type: Option<(TrapType, Oid<'a>, NetworkAddress)>, pub vars: Vec>, } @@ -96,11 +96,11 @@ impl<'a> SNMPState<'a> { impl<'a> Default for SNMPPduInfo<'a> { fn default() -> SNMPPduInfo<'a> { - SNMPPduInfo{ + SNMPPduInfo { pdu_type: PduType(0), err: ErrorStatus::NoError, trap_type: None, - vars: Vec::new() + vars: Vec::new(), } } } @@ -124,11 +124,10 @@ impl<'a> SNMPState<'a> { match *pdu { SnmpPdu::Generic(ref pdu) => { pdu_info.err = pdu.err; - }, - SnmpPdu::Bulk(_) => { - }, - SnmpPdu::TrapV1(ref t) => { - pdu_info.trap_type = Some((t.generic_trap,t.enterprise.clone(),t.agent_addr)); + } + SnmpPdu::Bulk(_) => {} + SnmpPdu::TrapV1(ref t) => { + pdu_info.trap_type = Some((t.generic_trap, t.enterprise.clone(), t.agent_addr)); } } @@ -142,7 +141,11 @@ impl<'a> SNMPState<'a> { let mut tx = self.new_tx(_direction); // in the message, version is encoded as 0 (version 1) or 1 (version 2) if self.version != msg.version + 1 { - SCLogDebug!("SNMP version mismatch: expected {}, received {}", self.version, msg.version+1); + SCLogDebug!( + "SNMP version mismatch: expected {}, received {}", + self.version, + msg.version + 1 + ); self.set_event_tx(&mut tx, SNMPEvent::VersionMismatch); } self.add_pdu_info(&msg.pdu, &mut tx); @@ -154,22 +157,26 @@ impl<'a> SNMPState<'a> { fn handle_snmp_v3(&mut self, msg: SnmpV3Message<'a>, _direction: Direction) -> i32 { let mut tx = self.new_tx(_direction); if self.version != msg.version { - SCLogDebug!("SNMP version mismatch: expected {}, received {}", self.version, msg.version); + SCLogDebug!( + "SNMP version mismatch: expected {}, received {}", + self.version, + msg.version + ); self.set_event_tx(&mut tx, SNMPEvent::VersionMismatch); } match msg.data { ScopedPduData::Plaintext(pdu) => { self.add_pdu_info(&pdu.data, &mut tx); - }, - _ => { + } + _ => { tx.encrypted = true; } } match msg.security_params { SecurityParameters::USM(usm) => { tx.usm = Some(usm.msg_user_name); - }, - _ => { + } + _ => { self.set_event_tx(&mut tx, SNMPEvent::UnknownSecurityModel); } } @@ -187,14 +194,15 @@ impl<'a> SNMPState<'a> { } } match parse_snmp_generic_message(i) { - Ok((_rem,SnmpGenericMessage::V1(msg))) | - Ok((_rem,SnmpGenericMessage::V2(msg))) => self.handle_snmp_v12(msg, direction), - Ok((_rem,SnmpGenericMessage::V3(msg))) => self.handle_snmp_v3(msg, direction), + Ok((_rem, SnmpGenericMessage::V1(msg))) | Ok((_rem, SnmpGenericMessage::V2(msg))) => { + self.handle_snmp_v12(msg, direction) + } + Ok((_rem, SnmpGenericMessage::V3(msg))) => self.handle_snmp_v3(msg, direction), Err(_e) => { SCLogDebug!("parse_snmp failed: {:?}", _e); self.set_event(SNMPEvent::MalformedData); -1 - }, + } } } @@ -210,7 +218,10 @@ impl<'a> SNMPState<'a> { } fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&SNMPTransaction> { - self.transactions.iter().rev().find(|&tx| tx.id == tx_id + 1) + self.transactions + .iter() + .rev() + .find(|&tx| tx.id == tx_id + 1) } fn free_tx(&mut self, tx_id: u64) { @@ -250,7 +261,9 @@ impl<'a> SNMPTransaction<'a> { /// Returns *mut SNMPState #[no_mangle] -pub extern "C" fn rs_snmp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_snmp_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = SNMPState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; @@ -259,151 +272,150 @@ pub extern "C" fn rs_snmp_state_new(_orig_state: *mut std::os::raw::c_void, _ori /// Params: /// - state: *mut SNMPState as void pointer #[no_mangle] -pub extern "C" fn rs_snmp_state_free(state: *mut std::os::raw::c_void) { - let mut snmp_state = unsafe{ Box::from_raw(state as *mut SNMPState) }; +pub extern fn rs_snmp_state_free(state: *mut std::os::raw::c_void) { + let mut snmp_state = unsafe { Box::from_raw(state as *mut SNMPState) }; snmp_state.free(); } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_parse_request(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { - let state = cast_pointer!(state,SNMPState); - state.parse(stream_slice.as_slice(), Direction::ToServer).into() +pub unsafe extern fn rs_snmp_parse_request( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { + let state = cast_pointer!(state, SNMPState); + state + .parse(stream_slice.as_slice(), Direction::ToServer) + .into() } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_parse_response(_flow: *const core::Flow, - state: *mut std::os::raw::c_void, - _pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void, - ) -> AppLayerResult { - let state = cast_pointer!(state,SNMPState); - state.parse(stream_slice.as_slice(), Direction::ToClient).into() +pub unsafe extern fn rs_snmp_parse_response( + _flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, +) -> AppLayerResult { + let state = cast_pointer!(state, SNMPState); + state + .parse(stream_slice.as_slice(), Direction::ToClient) + .into() } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_state_get_tx(state: *mut std::os::raw::c_void, - tx_id: u64) - -> *mut std::os::raw::c_void -{ - let state = cast_pointer!(state,SNMPState); +pub unsafe extern fn rs_snmp_state_get_tx( + state: *mut std::os::raw::c_void, tx_id: u64, +) -> *mut std::os::raw::c_void { + let state = cast_pointer!(state, SNMPState); match state.get_tx_by_id(tx_id) { Some(tx) => tx as *const _ as *mut _, - None => std::ptr::null_mut(), + None => std::ptr::null_mut(), } } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_state_get_tx_count(state: *mut std::os::raw::c_void) - -> u64 -{ - let state = cast_pointer!(state,SNMPState); +pub unsafe extern fn rs_snmp_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { + let state = cast_pointer!(state, SNMPState); state.tx_id } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_state_tx_free(state: *mut std::os::raw::c_void, - tx_id: u64) -{ - let state = cast_pointer!(state,SNMPState); +pub unsafe extern fn rs_snmp_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { + let state = cast_pointer!(state, SNMPState); state.free_tx(tx_id); } #[no_mangle] -pub extern "C" fn rs_snmp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void, - _direction: u8) - -> std::os::raw::c_int -{ +pub extern fn rs_snmp_tx_get_alstate_progress( + _tx: *mut std::os::raw::c_void, _direction: u8, +) -> std::os::raw::c_int { 1 } -static mut ALPROTO_SNMP : AppProto = ALPROTO_UNKNOWN; +static mut ALPROTO_SNMP: AppProto = ALPROTO_UNKNOWN; // Read PDU sequence and extract version, if similar to SNMP definition -fn parse_pdu_envelope_version(i:&[u8]) -> IResult<&[u8],u32> { +fn parse_pdu_envelope_version(i: &[u8]) -> IResult<&[u8], u32> { match parse_der_sequence(i) { - Ok((_,x)) => { + Ok((_, x)) => { #[allow(clippy::single_match)] match x.content { BerObjectContent::Sequence(ref v) => { if v.len() == 3 { - match v[0].as_u32() { - Ok(0) => { return Ok((i,1)); }, // possibly SNMPv1 - Ok(1) => { return Ok((i,2)); }, // possibly SNMPv2c - _ => () + match v[0].as_u32() { + Ok(0) => { + return Ok((i, 1)); + } // possibly SNMPv1 + Ok(1) => { + return Ok((i, 2)); + } // possibly SNMPv2c + _ => (), } } else if v.len() == 4 && v[0].as_u32() == Ok(3) { - return Ok((i,3)); // possibly SNMPv3 + return Ok((i, 3)); // possibly SNMPv3 } - }, - _ => () + } + _ => (), }; Err(Err::Error(make_error(i, ErrorKind::Verify))) - }, + } Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), - Err(Err::Failure(_)) | - Err(Err::Error(_)) => Err(Err::Error(make_error(i,ErrorKind::Verify))) + Err(Err::Failure(_)) | Err(Err::Error(_)) => { + Err(Err::Error(make_error(i, ErrorKind::Verify))) + } } } #[no_mangle] -pub unsafe extern "C" fn rs_snmp_probing_parser(_flow: *const Flow, - _direction: u8, - input:*const u8, - input_len: u32, - _rdir: *mut u8) -> AppProto { - let slice = build_slice!(input,input_len as usize); +pub unsafe extern fn rs_snmp_probing_parser( + _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, +) -> AppProto { + let slice = build_slice!(input, input_len as usize); let alproto = ALPROTO_SNMP; - if slice.len() < 4 { return ALPROTO_FAILED; } + if slice.len() < 4 { + return ALPROTO_FAILED; + } match parse_pdu_envelope_version(slice) { - Ok((_,_)) => alproto, + Ok((_, _)) => alproto, Err(Err::Incomplete(_)) => ALPROTO_UNKNOWN, - _ => ALPROTO_FAILED, + _ => ALPROTO_FAILED, } } export_tx_data_get!(rs_snmp_get_tx_data, SNMPTransaction); export_state_data_get!(rs_snmp_get_state_data, SNMPState); -const PARSER_NAME : &[u8] = b"snmp\0"; +const PARSER_NAME: &[u8] = b"snmp\0"; #[no_mangle] -pub unsafe extern "C" fn rs_register_snmp_parser() { +pub unsafe extern fn rs_register_snmp_parser() { let default_port = CString::new("161").unwrap(); let mut parser = RustParser { - name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char, - default_port : default_port.as_ptr(), - ipproto : core::IPPROTO_UDP, - probe_ts : Some(rs_snmp_probing_parser), - probe_tc : Some(rs_snmp_probing_parser), - min_depth : 0, - max_depth : 16, - state_new : rs_snmp_state_new, - state_free : rs_snmp_state_free, - tx_free : rs_snmp_state_tx_free, - parse_ts : rs_snmp_parse_request, - parse_tc : rs_snmp_parse_response, - get_tx_count : rs_snmp_state_get_tx_count, - get_tx : rs_snmp_state_get_tx, - tx_comp_st_ts : 1, - tx_comp_st_tc : 1, - tx_get_progress : rs_snmp_tx_get_alstate_progress, - get_eventinfo : Some(SNMPEvent::get_event_info), - get_eventinfo_byid : Some(SNMPEvent::get_event_info_by_id), - localstorage_new : None, - localstorage_free : None, - get_tx_files : None, - get_tx_iterator : Some(applayer::state_get_tx_iterator::), - get_tx_data : rs_snmp_get_tx_data, - get_state_data : rs_snmp_get_state_data, - apply_tx_config : None, - flags : 0, - truncate : None, + name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, + default_port: default_port.as_ptr(), + ipproto: core::IPPROTO_UDP, + probe_ts: Some(rs_snmp_probing_parser), + probe_tc: Some(rs_snmp_probing_parser), + min_depth: 0, + max_depth: 16, + state_new: rs_snmp_state_new, + state_free: rs_snmp_state_free, + tx_free: rs_snmp_state_tx_free, + parse_ts: rs_snmp_parse_request, + parse_tc: rs_snmp_parse_response, + get_tx_count: rs_snmp_state_get_tx_count, + get_tx: rs_snmp_state_get_tx, + tx_comp_st_ts: 1, + tx_comp_st_tc: 1, + tx_get_progress: rs_snmp_tx_get_alstate_progress, + get_eventinfo: Some(SNMPEvent::get_event_info), + get_eventinfo_byid: Some(SNMPEvent::get_event_info_by_id), + localstorage_new: None, + localstorage_free: None, + get_tx_files: None, + get_tx_iterator: Some(applayer::state_get_tx_iterator::), + get_tx_data: rs_snmp_get_tx_data, + get_state_data: rs_snmp_get_state_data, + apply_tx_config: None, + flags: 0, + truncate: None, get_frame_id_by_name: None, get_frame_name_by_id: None, }; diff --git a/rust/src/ssh/detect.rs b/rust/src/ssh/detect.rs index 6aa18cdac781..4061757d2ec1 100644 --- a/rust/src/ssh/detect.rs +++ b/rust/src/ssh/detect.rs @@ -20,7 +20,7 @@ use crate::core::Direction; use std::ptr; #[no_mangle] -pub unsafe extern "C" fn rs_ssh_tx_get_protocol( +pub unsafe extern fn rs_ssh_tx_get_protocol( tx: *mut std::os::raw::c_void, buffer: *mut *const u8, buffer_len: *mut u32, direction: u8, ) -> u8 { let tx = cast_pointer!(tx, SSHTransaction); @@ -49,7 +49,7 @@ pub unsafe extern "C" fn rs_ssh_tx_get_protocol( } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_tx_get_software( +pub unsafe extern fn rs_ssh_tx_get_software( tx: *mut std::os::raw::c_void, buffer: *mut *const u8, buffer_len: *mut u32, direction: u8, ) -> u8 { let tx = cast_pointer!(tx, SSHTransaction); @@ -78,11 +78,8 @@ pub unsafe extern "C" fn rs_ssh_tx_get_software( } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_tx_get_hassh( - tx: *mut std::os::raw::c_void, - buffer: *mut *const u8, - buffer_len: *mut u32, - direction: u8, +pub unsafe extern fn rs_ssh_tx_get_hassh( + tx: *mut std::os::raw::c_void, buffer: *mut *const u8, buffer_len: *mut u32, direction: u8, ) -> u8 { let tx = cast_pointer!(tx, SSHTransaction); match direction.into() { @@ -110,11 +107,8 @@ pub unsafe extern "C" fn rs_ssh_tx_get_hassh( } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_tx_get_hassh_string( - tx: *mut std::os::raw::c_void, - buffer: *mut *const u8, - buffer_len: *mut u32, - direction: u8, +pub unsafe extern fn rs_ssh_tx_get_hassh_string( + tx: *mut std::os::raw::c_void, buffer: *mut *const u8, buffer_len: *mut u32, direction: u8, ) -> u8 { let tx = cast_pointer!(tx, SSHTransaction); match direction.into() { diff --git a/rust/src/ssh/logger.rs b/rust/src/ssh/logger.rs index 008c6cb4517a..d45e9af4fb52 100644 --- a/rust/src/ssh/logger.rs +++ b/rust/src/ssh/logger.rs @@ -64,7 +64,7 @@ fn log_ssh(tx: &SSHTransaction, js: &mut JsonBuilder) -> Result } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_log_json(tx: *mut std::os::raw::c_void, js: &mut JsonBuilder) -> bool { +pub unsafe extern fn rs_ssh_log_json(tx: *mut std::os::raw::c_void, js: &mut JsonBuilder) -> bool { let tx = cast_pointer!(tx, SSHTransaction); if let Ok(x) = log_ssh(tx, js) { return x; diff --git a/rust/src/ssh/parser.rs b/rust/src/ssh/parser.rs index bfad8c005a9d..7a5d0ee6c26c 100644 --- a/rust/src/ssh/parser.rs +++ b/rust/src/ssh/parser.rs @@ -30,18 +30,18 @@ use std::fmt; #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum MessageCode { - Disconnect, - Ignore, - Unimplemented, - Debug, - ServiceRequest, - ServiceAccept, - Kexinit, - NewKeys, - KexdhInit, - KexdhReply, - - Undefined(u8), + Disconnect, + Ignore, + Unimplemented, + Debug, + ServiceRequest, + ServiceAccept, + Kexinit, + NewKeys, + KexdhInit, + KexdhReply, + + Undefined(u8), } impl MessageCode { @@ -79,9 +79,8 @@ pub fn ssh_parse_line(i: &[u8]) -> IResult<&[u8], &[u8]> { } terminated( take_while(is_not_lineend), - alt(( tag("\n"), tag("\r\n"), parser - )) - )(i) + alt((tag("\n"), tag("\r\n"), parser)), + )(i) } #[derive(PartialEq, Eq)] @@ -340,100 +339,111 @@ mod tests { } #[test] fn test_parse_key_exchange() { - let client_key_exchange = [0x18 ,0x70 ,0xCB ,0xA4 ,0xA3 ,0xD4 ,0xDC ,0x88 ,0x6F - ,0xFD ,0x76 ,0x06 ,0xCF ,0x36 ,0x1B ,0xC6 ,0x00 ,0x00 ,0x01 ,0x0D ,0x63 ,0x75 ,0x72 ,0x76 - ,0x65 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 ,0x36 ,0x2C ,0x63 - ,0x75 ,0x72 ,0x76 ,0x65 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 - ,0x36 ,0x40 ,0x6C ,0x69 ,0x62 ,0x73 ,0x73 ,0x68 ,0x2E ,0x6F ,0x72 ,0x67 ,0x2C ,0x65 ,0x63 - ,0x64 ,0x68 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x32 ,0x35 - ,0x36 ,0x2C ,0x65 ,0x63 ,0x64 ,0x68 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 - ,0x74 ,0x70 ,0x33 ,0x38 ,0x34 ,0x2C ,0x65 ,0x63 ,0x64 ,0x68 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 - ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x35 ,0x32 ,0x31 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 - ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 - ,0x2D ,0x65 ,0x78 ,0x63 ,0x68 ,0x61 ,0x6E ,0x67 ,0x65 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 - ,0x36 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x36 ,0x2D ,0x73 ,0x68 ,0x61 ,0x35 ,0x31 - ,0x32 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x38 ,0x2D ,0x73 ,0x68 ,0x61 ,0x35 ,0x31 - ,0x32 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x34 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 - ,0x36 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x34 ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x2C - ,0x65 ,0x78 ,0x74 ,0x2D ,0x69 ,0x6E ,0x66 ,0x6F ,0x2D ,0x63 ,0x00 ,0x00 ,0x01 ,0x66 ,0x65 - ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 - ,0x32 ,0x35 ,0x36 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 - ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x33 ,0x38 ,0x34 ,0x2D - ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 - ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 - ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x35 ,0x32 ,0x31 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 - ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F - ,0x6D ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 - ,0x73 ,0x74 ,0x70 ,0x32 ,0x35 ,0x36 ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 - ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x33 ,0x38 ,0x34 ,0x2C ,0x65 ,0x63 ,0x64 - ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x35 ,0x32 - ,0x31 ,0x2C ,0x73 ,0x73 ,0x68 ,0x2D ,0x65 ,0x64 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2D ,0x63 - ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 - ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 - ,0x31 ,0x32 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 - ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 - ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 ,0x36 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 - ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x73 ,0x73 - ,0x68 ,0x2D ,0x72 ,0x73 ,0x61 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x73 ,0x73 ,0x68 - ,0x2D ,0x65 ,0x64 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 - ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 - ,0x2D ,0x32 ,0x35 ,0x36 ,0x2C ,0x73 ,0x73 ,0x68 ,0x2D ,0x72 ,0x73 ,0x61 ,0x00 ,0x00 ,0x00 - ,0x6C ,0x63 ,0x68 ,0x61 ,0x63 ,0x68 ,0x61 ,0x32 ,0x30 ,0x2D ,0x70 ,0x6F ,0x6C ,0x79 ,0x31 - ,0x33 ,0x30 ,0x35 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D - ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x32 ,0x38 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 - ,0x31 ,0x39 ,0x32 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x32 ,0x35 ,0x36 ,0x2D - ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x32 ,0x38 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x61 ,0x65 ,0x73 - ,0x32 ,0x35 ,0x36 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 - ,0x2E ,0x63 ,0x6F ,0x6D ,0x00 ,0x00 ,0x00 ,0x6C ,0x63 ,0x68 ,0x61 ,0x63 ,0x68 ,0x61 ,0x32 - ,0x30 ,0x2D ,0x70 ,0x6F ,0x6C ,0x79 ,0x31 ,0x33 ,0x30 ,0x35 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E - ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x32 ,0x38 ,0x2D - ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x39 ,0x32 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C - ,0x61 ,0x65 ,0x73 ,0x32 ,0x35 ,0x36 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 - ,0x32 ,0x38 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x61 ,0x65 ,0x73 ,0x32 ,0x35 ,0x36 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x00 ,0x00 ,0x00 ,0xD5 - ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 - ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x31 - ,0x32 ,0x38 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 - ,0x35 ,0x36 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 - ,0x31 ,0x32 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x2D ,0x65 - ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C - ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 - ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x31 ,0x32 ,0x38 ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 ,0x36 ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D - ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 - ,0x68 ,0x61 ,0x31 ,0x00 ,0x00 ,0x00 ,0xD5 ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x2D - ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D - ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x31 ,0x32 ,0x38 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 ,0x36 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 - ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 - ,0x63 ,0x2D ,0x31 ,0x32 ,0x38 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 - ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 - ,0x36 ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 - ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x00 ,0x00 ,0x00 ,0x1A ,0x6E - ,0x6F ,0x6E ,0x65 ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 - ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x00 ,0x00 ,0x00 ,0x1A ,0x6E - ,0x6F ,0x6E ,0x65 ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 - ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 - ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00]; - let cookie = [0x18, 0x70, 0xcb, 0xa4, 0xa3, 0xd4, 0xdc, 0x88, 0x6f, 0xfd, 0x76, 0x06, 0xcf, 0x36, 0x1b, 0xc6]; + let client_key_exchange = [ + 0x18, 0x70, 0xCB, 0xA4, 0xA3, 0xD4, 0xDC, 0x88, 0x6F, 0xFD, 0x76, 0x06, 0xCF, 0x36, + 0x1B, 0xC6, 0x00, 0x00, 0x01, 0x0D, 0x63, 0x75, 0x72, 0x76, 0x65, 0x32, 0x35, 0x35, + 0x31, 0x39, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2C, 0x63, 0x75, 0x72, 0x76, + 0x65, 0x32, 0x35, 0x35, 0x31, 0x39, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x40, + 0x6C, 0x69, 0x62, 0x73, 0x73, 0x68, 0x2E, 0x6F, 0x72, 0x67, 0x2C, 0x65, 0x63, 0x64, + 0x68, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, + 0x36, 0x2C, 0x65, 0x63, 0x64, 0x68, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, + 0x73, 0x74, 0x70, 0x33, 0x38, 0x34, 0x2C, 0x65, 0x63, 0x64, 0x68, 0x2D, 0x73, 0x68, + 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, 0x31, 0x2C, 0x64, 0x69, + 0x66, 0x66, 0x69, 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, + 0x72, 0x6F, 0x75, 0x70, 0x2D, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x2D, + 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2C, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2D, + 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, 0x72, 0x6F, 0x75, 0x70, 0x31, + 0x36, 0x2D, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2C, 0x64, 0x69, 0x66, 0x66, 0x69, + 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, 0x72, 0x6F, 0x75, + 0x70, 0x31, 0x38, 0x2D, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2C, 0x64, 0x69, 0x66, + 0x66, 0x69, 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, 0x72, + 0x6F, 0x75, 0x70, 0x31, 0x34, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2C, 0x64, + 0x69, 0x66, 0x66, 0x69, 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, + 0x67, 0x72, 0x6F, 0x75, 0x70, 0x31, 0x34, 0x2D, 0x73, 0x68, 0x61, 0x31, 0x2C, 0x65, + 0x78, 0x74, 0x2D, 0x69, 0x6E, 0x66, 0x6F, 0x2D, 0x63, 0x00, 0x00, 0x01, 0x66, 0x65, + 0x63, 0x64, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, + 0x70, 0x32, 0x35, 0x36, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, + 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x65, 0x63, + 0x64, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, + 0x33, 0x38, 0x34, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, + 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x65, 0x63, 0x64, + 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x35, + 0x32, 0x31, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, + 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x65, 0x63, 0x64, 0x73, + 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, + 0x36, 0x2C, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, + 0x69, 0x73, 0x74, 0x70, 0x33, 0x38, 0x34, 0x2C, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2D, + 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, 0x31, 0x2C, + 0x73, 0x73, 0x68, 0x2D, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x2D, 0x63, 0x65, + 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x72, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, + 0x35, 0x31, 0x32, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, + 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x72, 0x73, 0x61, + 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2D, 0x63, 0x65, 0x72, 0x74, + 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, + 0x6F, 0x6D, 0x2C, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61, 0x2D, 0x63, 0x65, 0x72, + 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, + 0x63, 0x6F, 0x6D, 0x2C, 0x73, 0x73, 0x68, 0x2D, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, + 0x39, 0x2C, 0x72, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x35, 0x31, 0x32, + 0x2C, 0x72, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2C, + 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61, 0x00, 0x00, 0x00, 0x6C, 0x63, 0x68, 0x61, + 0x63, 0x68, 0x61, 0x32, 0x30, 0x2D, 0x70, 0x6F, 0x6C, 0x79, 0x31, 0x33, 0x30, 0x35, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, + 0x39, 0x32, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, + 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x67, 0x63, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, 0x67, 0x63, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, + 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x00, 0x6C, 0x63, 0x68, 0x61, + 0x63, 0x68, 0x61, 0x32, 0x30, 0x2D, 0x70, 0x6F, 0x6C, 0x79, 0x31, 0x33, 0x30, 0x35, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, + 0x39, 0x32, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, + 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x67, 0x63, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, 0x67, 0x63, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, + 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x00, 0xD5, 0x75, 0x6D, 0x61, + 0x63, 0x2D, 0x36, 0x34, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, + 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x31, 0x32, + 0x38, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, + 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, + 0x32, 0x35, 0x36, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, + 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, + 0x32, 0x2D, 0x35, 0x31, 0x32, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, + 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, + 0x68, 0x61, 0x31, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, + 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x36, 0x34, 0x40, + 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, + 0x61, 0x63, 0x2D, 0x31, 0x32, 0x38, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, + 0x2D, 0x32, 0x35, 0x36, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, + 0x2D, 0x35, 0x31, 0x32, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x31, + 0x00, 0x00, 0x00, 0xD5, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x36, 0x34, 0x2D, 0x65, 0x74, + 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, + 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x31, 0x32, 0x38, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, + 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, + 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2D, 0x65, 0x74, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, + 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x35, 0x31, 0x32, 0x2D, 0x65, + 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, + 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x31, 0x2D, 0x65, 0x74, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, + 0x6D, 0x61, 0x63, 0x2D, 0x36, 0x34, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x31, 0x32, 0x38, 0x40, + 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, + 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2C, 0x68, 0x6D, + 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x35, 0x31, 0x32, 0x2C, 0x68, 0x6D, + 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x1A, 0x6E, 0x6F, 0x6E, + 0x65, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x00, 0x00, 0x00, 0x1A, 0x6E, + 0x6F, 0x6E, 0x65, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, + 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + let cookie = [ + 0x18, 0x70, 0xcb, 0xa4, 0xa3, 0xd4, 0xdc, 0x88, 0x6f, 0xfd, 0x76, 0x06, 0xcf, 0x36, + 0x1b, 0xc6, + ]; let key_exchange = SshPacketKeyExchange { cookie: &cookie, kex_algs: b"curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,ext-info-c", @@ -457,106 +467,114 @@ mod tests { #[test] fn test_parse_hassh() { - let client_key_exchange = [0x18 ,0x70 ,0xCB ,0xA4 ,0xA3 ,0xD4 ,0xDC ,0x88 ,0x6F - ,0xFD ,0x76 ,0x06 ,0xCF ,0x36 ,0x1B ,0xC6 ,0x00 ,0x00 ,0x01 ,0x0D ,0x63 ,0x75 ,0x72 ,0x76 - ,0x65 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 ,0x36 ,0x2C ,0x63 - ,0x75 ,0x72 ,0x76 ,0x65 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 - ,0x36 ,0x40 ,0x6C ,0x69 ,0x62 ,0x73 ,0x73 ,0x68 ,0x2E ,0x6F ,0x72 ,0x67 ,0x2C ,0x65 ,0x63 - ,0x64 ,0x68 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x32 ,0x35 - ,0x36 ,0x2C ,0x65 ,0x63 ,0x64 ,0x68 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 - ,0x74 ,0x70 ,0x33 ,0x38 ,0x34 ,0x2C ,0x65 ,0x63 ,0x64 ,0x68 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 - ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x35 ,0x32 ,0x31 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 - ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 - ,0x2D ,0x65 ,0x78 ,0x63 ,0x68 ,0x61 ,0x6E ,0x67 ,0x65 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 - ,0x36 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x36 ,0x2D ,0x73 ,0x68 ,0x61 ,0x35 ,0x31 - ,0x32 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x38 ,0x2D ,0x73 ,0x68 ,0x61 ,0x35 ,0x31 - ,0x32 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x34 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x35 - ,0x36 ,0x2C ,0x64 ,0x69 ,0x66 ,0x66 ,0x69 ,0x65 ,0x2D ,0x68 ,0x65 ,0x6C ,0x6C ,0x6D ,0x61 - ,0x6E ,0x2D ,0x67 ,0x72 ,0x6F ,0x75 ,0x70 ,0x31 ,0x34 ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x2C - ,0x65 ,0x78 ,0x74 ,0x2D ,0x69 ,0x6E ,0x66 ,0x6F ,0x2D ,0x63 ,0x00 ,0x00 ,0x01 ,0x66 ,0x65 - ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 - ,0x32 ,0x35 ,0x36 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 - ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x33 ,0x38 ,0x34 ,0x2D - ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 - ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 - ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x35 ,0x32 ,0x31 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 - ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F - ,0x6D ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 - ,0x73 ,0x74 ,0x70 ,0x32 ,0x35 ,0x36 ,0x2C ,0x65 ,0x63 ,0x64 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 - ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x33 ,0x38 ,0x34 ,0x2C ,0x65 ,0x63 ,0x64 - ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x6E ,0x69 ,0x73 ,0x74 ,0x70 ,0x35 ,0x32 - ,0x31 ,0x2C ,0x73 ,0x73 ,0x68 ,0x2D ,0x65 ,0x64 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2D ,0x63 - ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 - ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 - ,0x31 ,0x32 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 ,0x6F ,0x70 ,0x65 - ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 - ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 ,0x36 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 - ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x73 ,0x73 - ,0x68 ,0x2D ,0x72 ,0x73 ,0x61 ,0x2D ,0x63 ,0x65 ,0x72 ,0x74 ,0x2D ,0x76 ,0x30 ,0x31 ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x73 ,0x73 ,0x68 - ,0x2D ,0x65 ,0x64 ,0x32 ,0x35 ,0x35 ,0x31 ,0x39 ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 - ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 ,0x2C ,0x72 ,0x73 ,0x61 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 - ,0x2D ,0x32 ,0x35 ,0x36 ,0x2C ,0x73 ,0x73 ,0x68 ,0x2D ,0x72 ,0x73 ,0x61 ,0x00 ,0x00 ,0x00 - ,0x6C ,0x63 ,0x68 ,0x61 ,0x63 ,0x68 ,0x61 ,0x32 ,0x30 ,0x2D ,0x70 ,0x6F ,0x6C ,0x79 ,0x31 - ,0x33 ,0x30 ,0x35 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D - ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x32 ,0x38 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 - ,0x31 ,0x39 ,0x32 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x32 ,0x35 ,0x36 ,0x2D - ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x32 ,0x38 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x61 ,0x65 ,0x73 - ,0x32 ,0x35 ,0x36 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 - ,0x2E ,0x63 ,0x6F ,0x6D ,0x00 ,0x00 ,0x00 ,0x6C ,0x63 ,0x68 ,0x61 ,0x63 ,0x68 ,0x61 ,0x32 - ,0x30 ,0x2D ,0x70 ,0x6F ,0x6C ,0x79 ,0x31 ,0x33 ,0x30 ,0x35 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E - ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x32 ,0x38 ,0x2D - ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 ,0x39 ,0x32 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C - ,0x61 ,0x65 ,0x73 ,0x32 ,0x35 ,0x36 ,0x2D ,0x63 ,0x74 ,0x72 ,0x2C ,0x61 ,0x65 ,0x73 ,0x31 - ,0x32 ,0x38 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x61 ,0x65 ,0x73 ,0x32 ,0x35 ,0x36 ,0x2D ,0x67 ,0x63 ,0x6D ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x00 ,0x00 ,0x00 ,0xD5 - ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 - ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x31 - ,0x32 ,0x38 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 - ,0x35 ,0x36 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 - ,0x31 ,0x32 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E - ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x2D ,0x65 - ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C - ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 - ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x31 ,0x32 ,0x38 ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 ,0x36 ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D - ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 - ,0x68 ,0x61 ,0x31 ,0x00 ,0x00 ,0x00 ,0xD5 ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x2D - ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D - ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x31 ,0x32 ,0x38 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 ,0x36 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F - ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 - ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x2D ,0x65 ,0x74 ,0x6D ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 - ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 ,0x63 ,0x2D ,0x36 ,0x34 ,0x40 - ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x75 ,0x6D ,0x61 - ,0x63 ,0x2D ,0x31 ,0x32 ,0x38 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 ,0x68 ,0x2E ,0x63 - ,0x6F ,0x6D ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x32 ,0x35 - ,0x36 ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x32 ,0x2D ,0x35 ,0x31 ,0x32 - ,0x2C ,0x68 ,0x6D ,0x61 ,0x63 ,0x2D ,0x73 ,0x68 ,0x61 ,0x31 ,0x00 ,0x00 ,0x00 ,0x1A ,0x6E - ,0x6F ,0x6E ,0x65 ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 - ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x00 ,0x00 ,0x00 ,0x1A ,0x6E - ,0x6F ,0x6E ,0x65 ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x40 ,0x6F ,0x70 ,0x65 ,0x6E ,0x73 ,0x73 - ,0x68 ,0x2E ,0x63 ,0x6F ,0x6D ,0x2C ,0x7A ,0x6C ,0x69 ,0x62 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 - ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00]; - let mut hassh_string: Vec = vec!(); - let mut hassh: Vec = vec!(); - match ssh_parse_key_exchange(&client_key_exchange){ - Ok((_, key_exchange)) => { - key_exchange.generate_hassh(&mut hassh_string, &mut hassh, &true); + let client_key_exchange = [ + 0x18, 0x70, 0xCB, 0xA4, 0xA3, 0xD4, 0xDC, 0x88, 0x6F, 0xFD, 0x76, 0x06, 0xCF, 0x36, + 0x1B, 0xC6, 0x00, 0x00, 0x01, 0x0D, 0x63, 0x75, 0x72, 0x76, 0x65, 0x32, 0x35, 0x35, + 0x31, 0x39, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2C, 0x63, 0x75, 0x72, 0x76, + 0x65, 0x32, 0x35, 0x35, 0x31, 0x39, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x40, + 0x6C, 0x69, 0x62, 0x73, 0x73, 0x68, 0x2E, 0x6F, 0x72, 0x67, 0x2C, 0x65, 0x63, 0x64, + 0x68, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, + 0x36, 0x2C, 0x65, 0x63, 0x64, 0x68, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, + 0x73, 0x74, 0x70, 0x33, 0x38, 0x34, 0x2C, 0x65, 0x63, 0x64, 0x68, 0x2D, 0x73, 0x68, + 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, 0x31, 0x2C, 0x64, 0x69, + 0x66, 0x66, 0x69, 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, + 0x72, 0x6F, 0x75, 0x70, 0x2D, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x2D, + 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2C, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2D, + 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, 0x72, 0x6F, 0x75, 0x70, 0x31, + 0x36, 0x2D, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2C, 0x64, 0x69, 0x66, 0x66, 0x69, + 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, 0x72, 0x6F, 0x75, + 0x70, 0x31, 0x38, 0x2D, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2C, 0x64, 0x69, 0x66, + 0x66, 0x69, 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, 0x67, 0x72, + 0x6F, 0x75, 0x70, 0x31, 0x34, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2C, 0x64, + 0x69, 0x66, 0x66, 0x69, 0x65, 0x2D, 0x68, 0x65, 0x6C, 0x6C, 0x6D, 0x61, 0x6E, 0x2D, + 0x67, 0x72, 0x6F, 0x75, 0x70, 0x31, 0x34, 0x2D, 0x73, 0x68, 0x61, 0x31, 0x2C, 0x65, + 0x78, 0x74, 0x2D, 0x69, 0x6E, 0x66, 0x6F, 0x2D, 0x63, 0x00, 0x00, 0x01, 0x66, 0x65, + 0x63, 0x64, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, + 0x70, 0x32, 0x35, 0x36, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, + 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x65, 0x63, + 0x64, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, + 0x33, 0x38, 0x34, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, + 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x65, 0x63, 0x64, + 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x35, + 0x32, 0x31, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, + 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x65, 0x63, 0x64, 0x73, + 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, + 0x36, 0x2C, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, + 0x69, 0x73, 0x74, 0x70, 0x33, 0x38, 0x34, 0x2C, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2D, + 0x73, 0x68, 0x61, 0x32, 0x2D, 0x6E, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, 0x31, 0x2C, + 0x73, 0x73, 0x68, 0x2D, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x2D, 0x63, 0x65, + 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x72, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, + 0x35, 0x31, 0x32, 0x2D, 0x63, 0x65, 0x72, 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, + 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x72, 0x73, 0x61, + 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2D, 0x63, 0x65, 0x72, 0x74, + 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, + 0x6F, 0x6D, 0x2C, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61, 0x2D, 0x63, 0x65, 0x72, + 0x74, 0x2D, 0x76, 0x30, 0x31, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, + 0x63, 0x6F, 0x6D, 0x2C, 0x73, 0x73, 0x68, 0x2D, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, + 0x39, 0x2C, 0x72, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x35, 0x31, 0x32, + 0x2C, 0x72, 0x73, 0x61, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2C, + 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61, 0x00, 0x00, 0x00, 0x6C, 0x63, 0x68, 0x61, + 0x63, 0x68, 0x61, 0x32, 0x30, 0x2D, 0x70, 0x6F, 0x6C, 0x79, 0x31, 0x33, 0x30, 0x35, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, + 0x39, 0x32, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, + 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x67, 0x63, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, 0x67, 0x63, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, + 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x00, 0x6C, 0x63, 0x68, 0x61, + 0x63, 0x68, 0x61, 0x32, 0x30, 0x2D, 0x70, 0x6F, 0x6C, 0x79, 0x31, 0x33, 0x30, 0x35, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, + 0x39, 0x32, 0x2D, 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, + 0x63, 0x74, 0x72, 0x2C, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2D, 0x67, 0x63, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x61, + 0x65, 0x73, 0x32, 0x35, 0x36, 0x2D, 0x67, 0x63, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, + 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x00, 0xD5, 0x75, 0x6D, 0x61, + 0x63, 0x2D, 0x36, 0x34, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, + 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x31, 0x32, + 0x38, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, + 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, + 0x32, 0x35, 0x36, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, + 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, + 0x32, 0x2D, 0x35, 0x31, 0x32, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, + 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, + 0x68, 0x61, 0x31, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, + 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x36, 0x34, 0x40, + 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, + 0x61, 0x63, 0x2D, 0x31, 0x32, 0x38, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, + 0x2D, 0x32, 0x35, 0x36, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, + 0x2D, 0x35, 0x31, 0x32, 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x31, + 0x00, 0x00, 0x00, 0xD5, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x36, 0x34, 0x2D, 0x65, 0x74, + 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, + 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x31, 0x32, 0x38, 0x2D, 0x65, 0x74, 0x6D, 0x40, 0x6F, + 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, 0x61, + 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2D, 0x65, 0x74, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, + 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x35, 0x31, 0x32, 0x2D, 0x65, + 0x74, 0x6D, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, + 0x2C, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x31, 0x2D, 0x65, 0x74, 0x6D, + 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, + 0x6D, 0x61, 0x63, 0x2D, 0x36, 0x34, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x75, 0x6D, 0x61, 0x63, 0x2D, 0x31, 0x32, 0x38, 0x40, + 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x68, 0x6D, + 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x32, 0x35, 0x36, 0x2C, 0x68, 0x6D, + 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x32, 0x2D, 0x35, 0x31, 0x32, 0x2C, 0x68, 0x6D, + 0x61, 0x63, 0x2D, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x1A, 0x6E, 0x6F, 0x6E, + 0x65, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, 0x73, 0x68, + 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x00, 0x00, 0x00, 0x1A, 0x6E, + 0x6F, 0x6E, 0x65, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x40, 0x6F, 0x70, 0x65, 0x6E, 0x73, + 0x73, 0x68, 0x2E, 0x63, 0x6F, 0x6D, 0x2C, 0x7A, 0x6C, 0x69, 0x62, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + let mut hassh_string: Vec = vec![]; + let mut hassh: Vec = vec![]; + match ssh_parse_key_exchange(&client_key_exchange) { + Ok((_, key_exchange)) => { + key_exchange.generate_hassh(&mut hassh_string, &mut hassh, &true); } - Err(_) => { } + Err(_) => {} } assert_eq!(hassh_string, "curve25519-sha256,curve25519-sha256@libssh.org,\ @@ -567,167 +585,194 @@ mod tests { umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,\ hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,\ hmac-sha2-256,hmac-sha2-512,hmac-sha1;none,zlib@openssh.com,zlib".as_bytes().to_vec()); - - assert_eq!(hassh, "ec7378c1a92f5a8dde7e8b7a1ddf33d1".as_bytes().to_vec()); + + assert_eq!( + hassh, + "ec7378c1a92f5a8dde7e8b7a1ddf33d1".as_bytes().to_vec() + ); } #[test] fn test_parse_hassh_server() { - let server_key_exchange = [0x7d, 0x76, 0x4f, 0x78, 0x81, 0x9e, 0x10, 0xfa, 0x23, 0x72, - 0xb5, 0x15, 0x56, 0xba, 0xf9, 0x46, 0x00, 0x00, 0x01, 0x02, 0x63, 0x75, 0x72, 0x76, 0x65, 0x32, - 0x35, 0x35, 0x31, 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x63, 0x75, 0x72, 0x76, - 0x65, 0x32, 0x35, 0x35, 0x31, 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x40, 0x6c, 0x69, - 0x62, 0x73, 0x73, 0x68, 0x2e, 0x6f, 0x72, 0x67, 0x2c, 0x65, 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, - 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x2c, 0x65, 0x63, 0x64, 0x68, - 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x33, 0x38, 0x34, 0x2c, 0x65, - 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, - 0x31, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, - 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2d, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, - 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, - 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x36, 0x2d, 0x73, 0x68, - 0x61, 0x35, 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, - 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x38, 0x2d, 0x73, 0x68, 0x61, 0x35, - 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, - 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, - 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x41, - 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x2c, 0x72, 0x73, 0x61, 0x2d, 0x73, 0x68, 0x61, 0x32, - 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x72, 0x73, 0x61, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, - 0x36, 0x2c, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, - 0x74, 0x70, 0x32, 0x35, 0x36, 0x2c, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, - 0x39, 0x00, 0x00, 0x00, 0x6c, 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, - 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, - 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, - 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, - 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, - 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, - 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, - 0x6d, 0x00, 0x00, 0x00, 0x6c, 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, - 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, - 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, - 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, - 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, - 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, - 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, - 0x6d, 0x00, 0x00, 0x00, 0xd5, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x2d, 0x65, 0x74, 0x6d, - 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, - 0x63, 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, - 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, - 0x32, 0x35, 0x36, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, - 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, - 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, - 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x2d, 0x65, 0x74, 0x6d, 0x40, - 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, - 0x2d, 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, - 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, - 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, - 0x35, 0x36, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, - 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0xd5, 0x75, 0x6d, - 0x61, 0x63, 0x2d, 0x36, 0x34, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, - 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, - 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, - 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2d, 0x65, 0x74, 0x6d, - 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, - 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, - 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, - 0x73, 0x68, 0x61, 0x31, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, - 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, - 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, - 0x38, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, - 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2c, 0x68, 0x6d, 0x61, 0x63, - 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, - 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x15, 0x6e, 0x6f, 0x6e, 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, - 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x15, - 0x6e, 0x6f, 0x6e, 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, - 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - let mut hassh_server_string: Vec = vec!(); - let mut hassh_server: Vec = vec!(); - match ssh_parse_key_exchange(&server_key_exchange){ - Ok((_, key_exchange)) => { + let server_key_exchange = [ + 0x7d, 0x76, 0x4f, 0x78, 0x81, 0x9e, 0x10, 0xfa, 0x23, 0x72, 0xb5, 0x15, 0x56, 0xba, + 0xf9, 0x46, 0x00, 0x00, 0x01, 0x02, 0x63, 0x75, 0x72, 0x76, 0x65, 0x32, 0x35, 0x35, + 0x31, 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x63, 0x75, 0x72, 0x76, + 0x65, 0x32, 0x35, 0x35, 0x31, 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x40, + 0x6c, 0x69, 0x62, 0x73, 0x73, 0x68, 0x2e, 0x6f, 0x72, 0x67, 0x2c, 0x65, 0x63, 0x64, + 0x68, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, + 0x36, 0x2c, 0x65, 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, + 0x73, 0x74, 0x70, 0x33, 0x38, 0x34, 0x2c, 0x65, 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, + 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, 0x31, 0x2c, 0x64, 0x69, + 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x2d, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, + 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, + 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, + 0x36, 0x2d, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, + 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x31, 0x38, 0x2d, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, + 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x64, + 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, + 0x00, 0x41, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x2c, 0x72, 0x73, 0x61, 0x2d, + 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x72, 0x73, 0x61, 0x2d, 0x73, + 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2c, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, + 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x2c, + 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x00, 0x00, 0x00, + 0x6c, 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, 0x6c, 0x79, + 0x31, 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, + 0x61, 0x65, 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, + 0x32, 0x35, 0x36, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, + 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, + 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, + 0x6c, 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, 0x6c, 0x79, + 0x31, 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, + 0x61, 0x65, 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, + 0x32, 0x35, 0x36, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, + 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, + 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, + 0xd5, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, + 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, + 0x63, 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, + 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, + 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, + 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, + 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, + 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, + 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, + 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, + 0x2d, 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x40, 0x6f, 0x70, 0x65, + 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, + 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, + 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, + 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0xd5, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, + 0x34, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, + 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, + 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, + 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, + 0x31, 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, + 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, + 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, + 0x31, 0x32, 0x38, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, + 0x36, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, + 0x32, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, + 0x15, 0x6e, 0x6f, 0x6e, 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, 0x40, 0x6f, 0x70, 0x65, + 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x15, 0x6e, 0x6f, + 0x6e, 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, + 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + let mut hassh_server_string: Vec = vec![]; + let mut hassh_server: Vec = vec![]; + match ssh_parse_key_exchange(&server_key_exchange) { + Ok((_, key_exchange)) => { key_exchange.generate_hassh(&mut hassh_server_string, &mut hassh_server, &true); } - Err(_) => { } + Err(_) => {} } - assert_eq!(hassh_server, "b12d2871a1189eff20364cf5333619ee".as_bytes().to_vec()); + assert_eq!( + hassh_server, + "b12d2871a1189eff20364cf5333619ee".as_bytes().to_vec() + ); } - + #[test] fn test_parse_hassh_server_malicious() { - let server_key_exchange = [0x7d, 0x76, 0x4f, 0x78, 0x81, 0x9e, 0x10, 0xfa, 0x23, 0x72, - 0xb5, 0x15, 0x56, 0xba, 0xf9, 0x46, 0x00, 0x00, 0x01, 0x02, 0x75, 0x72, 0x76, 0x65, 0x32, - 0x35, 0x35, 0x31, 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x63, 0x75, 0x72, 0x76, - 0x65, 0x32, 0x35, 0x35, 0x31, 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x40, 0x6c, 0x69, - 0x62, 0x73, 0x73, 0x68, 0x2e, 0x6f, 0x72, 0x67, 0x2c, 0x65, 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, - 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x2c, 0x65, 0x63, 0x64, 0x68, - 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x33, 0x38, 0x34, 0x2c, 0x65, - 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, - 0x31, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, - 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2d, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, - 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, - 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x36, 0x2d, 0x73, 0x68, - 0x61, 0x35, 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, - 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x38, 0x2d, 0x73, 0x68, 0x61, 0x35, - 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, - 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, - 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x41, - 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x2c, 0x72, 0x73, 0x61, 0x2d, 0x73, 0x68, 0x61, 0x32, - 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x72, 0x73, 0x61, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, - 0x36, 0x2c, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, - 0x74, 0x70, 0x32, 0x35, 0x36, 0x2c, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, - 0x39, 0x00, 0x00, 0x00, 0x6c, 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, - 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, - 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, - 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, - 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, - 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, - 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, - 0x6d, 0x00, 0x00, 0x00, 0x6c, 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, - 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, - 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, - 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, - 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, - 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, - 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, - 0x6d, 0x00, 0x00, 0x00, 0xd5, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x2d, 0x65, 0x74, 0x6d, - 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, - 0x63, 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, - 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, - 0x32, 0x35, 0x36, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, - 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, - 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, - 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x2d, 0x65, 0x74, 0x6d, 0x40, - 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, - 0x2d, 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, - 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, - 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, - 0x35, 0x36, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, - 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0xd5, 0x75, 0x6d, - 0x61, 0x63, 0x2d, 0x36, 0x34, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, - 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, - 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, - 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2d, 0x65, 0x74, 0x6d, - 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, - 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, - 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, - 0x73, 0x68, 0x61, 0x31, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, - 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, - 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, - 0x38, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, - 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2c, 0x68, 0x6d, 0x61, 0x63, - 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, - 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x15, 0x6e, 0x6f, 0x6e, 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, - 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x15, - 0x6e, 0x6f, 0x6e, 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, - 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + let server_key_exchange = [ + 0x7d, 0x76, 0x4f, 0x78, 0x81, 0x9e, 0x10, 0xfa, 0x23, 0x72, 0xb5, 0x15, 0x56, 0xba, + 0xf9, 0x46, 0x00, 0x00, 0x01, 0x02, 0x75, 0x72, 0x76, 0x65, 0x32, 0x35, 0x35, 0x31, + 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x63, 0x75, 0x72, 0x76, 0x65, + 0x32, 0x35, 0x35, 0x31, 0x39, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x40, 0x6c, + 0x69, 0x62, 0x73, 0x73, 0x68, 0x2e, 0x6f, 0x72, 0x67, 0x2c, 0x65, 0x63, 0x64, 0x68, + 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, + 0x2c, 0x65, 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, + 0x74, 0x70, 0x33, 0x38, 0x34, 0x2c, 0x65, 0x63, 0x64, 0x68, 0x2d, 0x73, 0x68, 0x61, + 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x35, 0x32, 0x31, 0x2c, 0x64, 0x69, 0x66, + 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x2d, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, + 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, + 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x36, + 0x2d, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, + 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x31, 0x38, 0x2d, 0x73, 0x68, 0x61, 0x35, 0x31, 0x32, 0x2c, 0x64, 0x69, 0x66, 0x66, + 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2c, 0x64, 0x69, + 0x66, 0x66, 0x69, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x2d, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x31, 0x34, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, + 0x41, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x2c, 0x72, 0x73, 0x61, 0x2d, 0x73, + 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x72, 0x73, 0x61, 0x2d, 0x73, 0x68, + 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2c, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, + 0x68, 0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x2c, 0x73, + 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x6c, + 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, 0x6c, 0x79, 0x31, + 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, + 0x65, 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x32, + 0x35, 0x36, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, + 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, + 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x6c, + 0x63, 0x68, 0x61, 0x63, 0x68, 0x61, 0x32, 0x30, 0x2d, 0x70, 0x6f, 0x6c, 0x79, 0x31, + 0x33, 0x30, 0x35, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, + 0x65, 0x73, 0x31, 0x39, 0x32, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x32, + 0x35, 0x36, 0x2d, 0x63, 0x74, 0x72, 0x2c, 0x61, 0x65, 0x73, 0x31, 0x32, 0x38, 0x2d, + 0x67, 0x63, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x61, 0x65, 0x73, 0x32, 0x35, 0x36, 0x2d, 0x67, 0x63, 0x6d, 0x40, 0x6f, + 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0xd5, + 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, + 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, + 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, + 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, + 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, + 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, + 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, + 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, + 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, + 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, + 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x40, 0x6f, 0x70, 0x65, 0x6e, + 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, + 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, + 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, + 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0xd5, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, + 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, 0x32, 0x38, 0x2d, 0x65, 0x74, + 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, + 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, 0x2d, + 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, + 0x32, 0x2d, 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, + 0x63, 0x6f, 0x6d, 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x2d, + 0x65, 0x74, 0x6d, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x36, 0x34, 0x40, 0x6f, 0x70, 0x65, 0x6e, + 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x75, 0x6d, 0x61, 0x63, 0x2d, 0x31, + 0x32, 0x38, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x32, 0x35, 0x36, + 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x2d, 0x35, 0x31, 0x32, + 0x2c, 0x68, 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x68, 0x61, 0x31, 0x00, 0x00, 0x00, 0x15, + 0x6e, 0x6f, 0x6e, 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, 0x40, 0x6f, 0x70, 0x65, 0x6e, + 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x15, 0x6e, 0x6f, 0x6e, + 0x65, 0x2c, 0x7a, 0x6c, 0x69, 0x62, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, + 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; if let Err(e) = ssh_parse_key_exchange(&server_key_exchange) { assert_eq!(e, Err::Incomplete(Needed::new(15964))); - } - else { + } else { panic!("ssh_parse_key_exchange() parsed malicious key_exchange"); } -} + } } diff --git a/rust/src/ssh/ssh.rs b/rust/src/ssh/ssh.rs index 6280e0b6ace9..306a91f9cc92 100644 --- a/rust/src/ssh/ssh.rs +++ b/rust/src/ssh/ssh.rs @@ -154,8 +154,14 @@ impl SSHState { parser::MessageCode::Kexinit if hassh_is_enabled() => { //let endkex = SSH_RECORD_HEADER_LEN + head.pkt_len - 2; let endkex = input.len() - rem.len(); - if let Ok((_, key_exchange)) = parser::ssh_parse_key_exchange(&input[SSH_RECORD_HEADER_LEN..endkex]) { - key_exchange.generate_hassh(&mut hdr.hassh_string, &mut hdr.hassh, &resp); + if let Ok((_, key_exchange)) = parser::ssh_parse_key_exchange( + &input[SSH_RECORD_HEADER_LEN..endkex], + ) { + key_exchange.generate_hassh( + &mut hdr.hassh_string, + &mut hdr.hassh, + &resp, + ); } } parser::MessageCode::NewKeys => { @@ -165,15 +171,15 @@ impl SSHState { AppLayerParserStateSetFlag( pstate, APP_LAYER_PARSER_NO_INSPECTION - | APP_LAYER_PARSER_NO_REASSEMBLY - | APP_LAYER_PARSER_BYPASS_READY, + | APP_LAYER_PARSER_NO_REASSEMBLY + | APP_LAYER_PARSER_BYPASS_READY, ); } } } _ => {} } - + input = rem; //header and complete data (not returned) } @@ -184,7 +190,7 @@ impl SSHState { let remlen = rem.len() as u32; hdr.record_left = head.pkt_len - 2 - remlen; //header with rem as incomplete data - match head.msg_code { + match head.msg_code { parser::MessageCode::NewKeys => { hdr.flags = SSHConnectionState::SshStateFinished; } @@ -196,10 +202,9 @@ impl SSHState { hdr.record_left_msg = parser::MessageCode::Kexinit; return AppLayerResult::incomplete( (il - rem.len()) as u32, - head.pkt_len - 2 + head.pkt_len - 2, ); - } - else { + } else { SCLogDebug!("SSH buffer is bigger than maximum reassembled packet size"); self.set_event(SSHEvent::LongKexRecord); } @@ -332,27 +337,28 @@ export_tx_data_get!(rs_ssh_get_tx_data, SSHTransaction); export_state_data_get!(rs_ssh_get_state_data, SSHState); #[no_mangle] -pub extern "C" fn rs_ssh_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_ssh_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = SSHState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_state_free(state: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_ssh_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(Box::from_raw(state as *mut SSHState)); } #[no_mangle] -pub extern "C" fn rs_ssh_state_tx_free(_state: *mut std::os::raw::c_void, _tx_id: u64) { +pub extern fn rs_ssh_state_tx_free(_state: *mut std::os::raw::c_void, _tx_id: u64) { //do nothing } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_parse_request( +pub unsafe extern fn rs_ssh_parse_request( _flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = &mut cast_pointer!(state, SSHState); let buf = stream_slice.as_slice(); @@ -365,10 +371,9 @@ pub unsafe extern "C" fn rs_ssh_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_parse_response( +pub unsafe extern fn rs_ssh_parse_response( _flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = &mut cast_pointer!(state, SSHState); let buf = stream_slice.as_slice(); @@ -381,7 +386,7 @@ pub unsafe extern "C" fn rs_ssh_parse_response( } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_state_get_tx( +pub unsafe extern fn rs_ssh_state_get_tx( state: *mut std::os::raw::c_void, _tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, SSHState); @@ -389,12 +394,12 @@ pub unsafe extern "C" fn rs_ssh_state_get_tx( } #[no_mangle] -pub extern "C" fn rs_ssh_state_get_tx_count(_state: *mut std::os::raw::c_void) -> u64 { +pub extern fn rs_ssh_state_get_tx_count(_state: *mut std::os::raw::c_void) -> u64 { return 1; } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_tx_get_flags( +pub unsafe extern fn rs_ssh_tx_get_flags( tx: *mut std::os::raw::c_void, direction: u8, ) -> SSHConnectionState { let tx = cast_pointer!(tx, SSHTransaction); @@ -406,7 +411,7 @@ pub unsafe extern "C" fn rs_ssh_tx_get_flags( } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_tx_get_alstate_progress( +pub unsafe extern fn rs_ssh_tx_get_alstate_progress( tx: *mut std::os::raw::c_void, direction: u8, ) -> std::os::raw::c_int { let tx = cast_pointer!(tx, SSHTransaction); @@ -432,7 +437,7 @@ pub unsafe extern "C" fn rs_ssh_tx_get_alstate_progress( const PARSER_NAME: &[u8] = b"ssh\0"; #[no_mangle] -pub unsafe extern "C" fn rs_ssh_register_parser() { +pub unsafe extern fn rs_ssh_register_parser() { let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, default_port: std::ptr::null(), @@ -482,27 +487,28 @@ pub unsafe extern "C" fn rs_ssh_register_parser() { } #[no_mangle] -pub extern "C" fn rs_ssh_enable_hassh() { +pub extern fn rs_ssh_enable_hassh() { HASSH_ENABLED.store(true, Ordering::Relaxed) } #[no_mangle] -pub extern "C" fn rs_ssh_hassh_is_enabled() -> bool { +pub extern fn rs_ssh_hassh_is_enabled() -> bool { hassh_is_enabled() } #[no_mangle] -pub unsafe extern "C" fn rs_ssh_tx_get_log_condition( tx: *mut std::os::raw::c_void) -> bool { +pub unsafe extern fn rs_ssh_tx_get_log_condition(tx: *mut std::os::raw::c_void) -> bool { let tx = cast_pointer!(tx, SSHTransaction); - + if rs_ssh_hassh_is_enabled() { - if tx.cli_hdr.flags == SSHConnectionState::SshStateFinished && - tx.srv_hdr.flags == SSHConnectionState::SshStateFinished { - return true; + if tx.cli_hdr.flags == SSHConnectionState::SshStateFinished + && tx.srv_hdr.flags == SSHConnectionState::SshStateFinished + { + return true; } - } - else if tx.cli_hdr.flags == SSHConnectionState::SshStateBannerDone && - tx.srv_hdr.flags == SSHConnectionState::SshStateBannerDone { + } else if tx.cli_hdr.flags == SSHConnectionState::SshStateBannerDone + && tx.srv_hdr.flags == SSHConnectionState::SshStateBannerDone + { return true; } return false; diff --git a/rust/src/telnet/mod.rs b/rust/src/telnet/mod.rs index 38685c795443..6af7a8d6c387 100644 --- a/rust/src/telnet/mod.rs +++ b/rust/src/telnet/mod.rs @@ -17,5 +17,5 @@ //! Telnet application layer and parser module. -pub mod telnet; mod parser; +pub mod telnet; diff --git a/rust/src/telnet/parser.rs b/rust/src/telnet/parser.rs index e2dbfa4a6eea..cdacdd49aa65 100644 --- a/rust/src/telnet/parser.rs +++ b/rust/src/telnet/parser.rs @@ -16,12 +16,12 @@ */ use crate::common::nom7::take_until_and_consume; -use nom7::combinator::peek; use nom7::bytes::complete::take; -use nom7::{IResult}; -use nom7::number::streaming::le_u8; use nom7::bytes::streaming::tag; -use nom7::bytes::streaming::{take_until}; +use nom7::bytes::streaming::take_until; +use nom7::combinator::peek; +use nom7::number::streaming::le_u8; +use nom7::IResult; pub fn peek_message_is_ctl(i: &[u8]) -> IResult<&[u8], bool> { let (i, v) = peek(le_u8)(i)?; @@ -33,11 +33,11 @@ pub enum TelnetMessageType<'a> { Data(&'a [u8]), } -pub fn parse_ctl_suboption<'a>(i: &'a[u8], full: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> { +pub fn parse_ctl_suboption<'a>(i: &'a [u8], full: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { let (i, _sc) = le_u8(i)?; let tag: &[u8] = b"\xff\xf0"; let (i, x) = take_until(tag)(i)?; - let o = &full[..(x.len()+3)]; + let o = &full[..(x.len() + 3)]; Ok((i, o)) } diff --git a/rust/src/telnet/telnet.rs b/rust/src/telnet/telnet.rs index f1e7eec50281..99e355fcaac6 100644 --- a/rust/src/telnet/telnet.rs +++ b/rust/src/telnet/telnet.rs @@ -15,13 +15,13 @@ * 02110-1301, USA. */ -use std; -use crate::core::{ALPROTO_UNKNOWN, AppProto, Flow, IPPROTO_TCP}; +use super::parser; use crate::applayer::{self, *}; +use crate::core::{AppProto, Flow, ALPROTO_UNKNOWN, IPPROTO_TCP}; use crate::frames::*; -use std::ffi::CString; use nom7::IResult; -use super::parser; +use std; +use std::ffi::CString; static mut ALPROTO_TELNET: AppProto = ALPROTO_UNKNOWN; @@ -184,7 +184,7 @@ impl TelnetState { -1_i64, TelnetFrameType::Data as u8, ) - // app-layer-frame-documentation tag end: parse_request + // app-layer-frame-documentation tag end: parse_request }; self.request_specific_frame = f; } @@ -246,7 +246,9 @@ impl TelnetState { return AppLayerResult::ok(); } - fn parse_response(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8]) -> AppLayerResult { + fn parse_response( + &mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], + ) -> AppLayerResult { // We're not interested in empty responses. if input.is_empty() { return AppLayerResult::ok(); @@ -266,14 +268,32 @@ impl TelnetState { let mut start = input; while !start.is_empty() { if self.response_frame.is_none() { - self.response_frame = Frame::new(flow, stream_slice, start, -1_i64, TelnetFrameType::Pdu as u8); + self.response_frame = Frame::new( + flow, + stream_slice, + start, + -1_i64, + TelnetFrameType::Pdu as u8, + ); } if self.response_specific_frame.is_none() { if let Ok((_, is_ctl)) = parser::peek_message_is_ctl(start) { self.response_specific_frame = if is_ctl { - Frame::new(flow, stream_slice, start, -1_i64, TelnetFrameType::Ctl as u8) + Frame::new( + flow, + stream_slice, + start, + -1_i64, + TelnetFrameType::Ctl as u8, + ) } else { - Frame::new(flow, stream_slice, start, -1_i64, TelnetFrameType::Data as u8) + Frame::new( + flow, + stream_slice, + start, + -1_i64, + TelnetFrameType::Data as u8, + ) }; } } @@ -300,37 +320,34 @@ impl TelnetState { if let parser::TelnetMessageType::Data(d) = response { match self.state { - TelnetProtocolState::Idle | - TelnetProtocolState::AuthFail => { + TelnetProtocolState::Idle | TelnetProtocolState::AuthFail => { self.state = TelnetProtocolState::LoginSent; - }, + } TelnetProtocolState::LoginRecv => { self.state = TelnetProtocolState::PasswdSent; - }, + } TelnetProtocolState::PasswdRecv => { if let Ok(message) = std::str::from_utf8(d) { match message { "Login incorrect" => { SCLogDebug!("LOGIN FAILED"); self.state = TelnetProtocolState::AuthFail; - }, - "" => { - - }, + } + "" => {} &_ => { SCLogDebug!("LOGIN OK"); self.state = TelnetProtocolState::AuthOk; - }, + } } } - }, + } TelnetProtocolState::AuthOk => { let _message = std::str::from_utf8(d); if let Ok(_message) = _message { SCLogDebug!("<= {}", _message); } - }, - _ => {}, + } + _ => {} } } else if let parser::TelnetMessageType::Control(_c) = response { SCLogDebug!("response {:?}", _c); @@ -374,12 +391,8 @@ fn probe(input: &[u8]) -> IResult<&[u8], ()> { /// C entry point for a probing parser. #[no_mangle] -pub unsafe extern "C" fn rs_telnet_probing_parser( - _flow: *const Flow, - _direction: u8, - input: *const u8, - input_len: u32, - _rdir: *mut u8 +pub unsafe extern fn rs_telnet_probing_parser( + _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8, ) -> AppProto { // Need at least 2 bytes. if input_len > 1 && !input.is_null() { @@ -393,33 +406,29 @@ pub unsafe extern "C" fn rs_telnet_probing_parser( } #[no_mangle] -pub extern "C" fn rs_telnet_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { +pub extern fn rs_telnet_state_new( + _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, +) -> *mut std::os::raw::c_void { let state = TelnetState::new(); let boxed = Box::new(state); return Box::into_raw(boxed) as *mut std::os::raw::c_void; } #[no_mangle] -pub unsafe extern "C" fn rs_telnet_state_free(state: *mut std::os::raw::c_void) { +pub unsafe extern fn rs_telnet_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(Box::from_raw(state as *mut TelnetState)); } #[no_mangle] -pub unsafe extern "C" fn rs_telnet_state_tx_free( - state: *mut std::os::raw::c_void, - tx_id: u64, -) { +pub unsafe extern fn rs_telnet_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { let state = cast_pointer!(state, TelnetState); state.free_tx(tx_id); } #[no_mangle] -pub unsafe extern "C" fn rs_telnet_parse_request( - flow: *const Flow, - state: *mut std::os::raw::c_void, - pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void +pub unsafe extern fn rs_telnet_parse_request( + flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let eof = AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) > 0; @@ -442,12 +451,9 @@ pub unsafe extern "C" fn rs_telnet_parse_request( } #[no_mangle] -pub unsafe extern "C" fn rs_telnet_parse_response( - flow: *const Flow, - state: *mut std::os::raw::c_void, - pstate: *mut std::os::raw::c_void, - stream_slice: StreamSlice, - _data: *const std::os::raw::c_void +pub unsafe extern fn rs_telnet_parse_response( + flow: *const Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void, + stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let _eof = AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) > 0; let state = cast_pointer!(state, TelnetState); @@ -464,9 +470,8 @@ pub unsafe extern "C" fn rs_telnet_parse_response( } #[no_mangle] -pub unsafe extern "C" fn rs_telnet_state_get_tx( - state: *mut std::os::raw::c_void, - tx_id: u64, +pub unsafe extern fn rs_telnet_state_get_tx( + state: *mut std::os::raw::c_void, tx_id: u64, ) -> *mut std::os::raw::c_void { let state = cast_pointer!(state, TelnetState); match state.get_tx(tx_id) { @@ -480,17 +485,14 @@ pub unsafe extern "C" fn rs_telnet_state_get_tx( } #[no_mangle] -pub unsafe extern "C" fn rs_telnet_state_get_tx_count( - state: *mut std::os::raw::c_void, -) -> u64 { +pub unsafe extern fn rs_telnet_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { let state = cast_pointer!(state, TelnetState); return state.tx_id; } #[no_mangle] -pub unsafe extern "C" fn rs_telnet_tx_get_alstate_progress( - tx: *mut std::os::raw::c_void, - _direction: u8, +pub unsafe extern fn rs_telnet_tx_get_alstate_progress( + tx: *mut std::os::raw::c_void, _direction: u8, ) -> std::os::raw::c_int { let _tx = cast_pointer!(tx, TelnetTransaction); // TODO @@ -504,7 +506,7 @@ export_state_data_get!(rs_telnet_get_state_data, TelnetState); const PARSER_NAME: &[u8] = b"telnet\0"; #[no_mangle] -pub unsafe extern "C" fn rs_telnet_register_parser() { +pub unsafe extern fn rs_telnet_register_parser() { let default_port = CString::new("[23]").unwrap(); let parser = RustParser { name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char, @@ -525,7 +527,7 @@ pub unsafe extern "C" fn rs_telnet_register_parser() { tx_comp_st_tc: 1, tx_get_progress: rs_telnet_tx_get_alstate_progress, get_eventinfo: Some(TelnetEvent::get_event_info), - get_eventinfo_byid : Some(TelnetEvent::get_event_info_by_id), + get_eventinfo_byid: Some(TelnetEvent::get_event_info_by_id), localstorage_new: None, localstorage_free: None, get_tx_files: None, @@ -537,23 +539,14 @@ pub unsafe extern "C" fn rs_telnet_register_parser() { truncate: None, get_frame_id_by_name: Some(TelnetFrameType::ffi_id_from_name), get_frame_name_by_id: Some(TelnetFrameType::ffi_name_from_id), - }; let ip_proto_str = CString::new("tcp").unwrap(); - if AppLayerProtoDetectConfProtoDetectionEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let alproto = AppLayerRegisterProtocolDetection(&parser, 1); ALPROTO_TELNET = alproto; - if AppLayerParserConfParserEnabled( - ip_proto_str.as_ptr(), - parser.name, - ) != 0 - { + if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let _ = AppLayerRegisterParser(&parser, alproto); } SCLogDebug!("Rust telnet parser registered."); diff --git a/rust/src/tftp/log.rs b/rust/src/tftp/log.rs index f6e63531a07e..30a840c4e1d9 100644 --- a/rust/src/tftp/log.rs +++ b/rust/src/tftp/log.rs @@ -20,15 +20,12 @@ use crate::jsonbuilder::{JsonBuilder, JsonError}; use crate::tftp::tftp::TFTPTransaction; -fn tftp_log_request(tx: &mut TFTPTransaction, - jb: &mut JsonBuilder) - -> Result<(), JsonError> -{ +fn tftp_log_request(tx: &mut TFTPTransaction, jb: &mut JsonBuilder) -> Result<(), JsonError> { jb.open_object("tftp")?; match tx.opcode { 1 => jb.set_string("packet", "read")?, 2 => jb.set_string("packet", "write")?, - _ => jb.set_string("packet", "error")? + _ => jb.set_string("packet", "error")?, }; jb.set_string("file", tx.filename.as_str())?; jb.set_string("mode", tx.mode.as_str())?; @@ -37,9 +34,6 @@ fn tftp_log_request(tx: &mut TFTPTransaction, } #[no_mangle] -pub extern "C" fn rs_tftp_log_json_request(tx: &mut TFTPTransaction, - jb: &mut JsonBuilder) - -> bool -{ +pub extern fn rs_tftp_log_json_request(tx: &mut TFTPTransaction, jb: &mut JsonBuilder) -> bool { tftp_log_request(tx, jb).is_ok() } diff --git a/rust/src/tftp/mod.rs b/rust/src/tftp/mod.rs index 6ae29ac90143..cd7c5ec45aab 100644 --- a/rust/src/tftp/mod.rs +++ b/rust/src/tftp/mod.rs @@ -19,5 +19,5 @@ // written by Clément Galland -pub mod tftp; pub mod log; +pub mod tftp; diff --git a/rust/src/tftp/tftp.rs b/rust/src/tftp/tftp.rs index 1b093fed256d..3a8b09c202a7 100644 --- a/rust/src/tftp/tftp.rs +++ b/rust/src/tftp/tftp.rs @@ -17,33 +17,33 @@ // written by Clément Galland -use std::str; -use std; -use nom7::IResult; -use nom7::combinator::map_res; use nom7::bytes::streaming::{tag, take_while}; +use nom7::combinator::map_res; use nom7::number::streaming::be_u8; +use nom7::IResult; +use std; +use std::str; -use crate::applayer::{AppLayerTxData,AppLayerStateData}; +use crate::applayer::{AppLayerStateData, AppLayerTxData}; -const READREQUEST: u8 = 1; +const READREQUEST: u8 = 1; const WRITEREQUEST: u8 = 2; -const DATA: u8 = 3; -const ACK: u8 = 4; -const ERROR: u8 = 5; +const DATA: u8 = 3; +const ACK: u8 = 4; +const ERROR: u8 = 5; #[derive(Debug, PartialEq, Eq)] pub struct TFTPTransaction { - pub opcode : u8, - pub filename : String, - pub mode : String, + pub opcode: u8, + pub filename: String, + pub mode: String, id: u64, tx_data: AppLayerTxData, } pub struct TFTPState { state_data: AppLayerStateData, - pub transactions : Vec, + pub transactions: Vec, /// tx counter for assigning incrementing id's to tx's tx_id: u64, } @@ -63,66 +63,65 @@ impl TFTPState { } impl TFTPTransaction { - pub fn new(opcode : u8, filename : String, mode : String) -> TFTPTransaction { + pub fn new(opcode: u8, filename: String, mode: String) -> TFTPTransaction { TFTPTransaction { opcode, filename, - mode : mode.to_lowercase(), - id : 0, + mode: mode.to_lowercase(), + id: 0, tx_data: AppLayerTxData::new(), } } pub fn is_mode_ok(&self) -> bool { match self.mode.as_str() { "netascii" | "mail" | "octet" => true, - _ => false + _ => false, } } pub fn is_opcode_ok(&self) -> bool { match self.opcode { READREQUEST | WRITEREQUEST | ACK | DATA | ERROR => true, - _ => false + _ => false, } } } #[no_mangle] -pub extern "C" fn rs_tftp_state_alloc() -> *mut std::os::raw::c_void { - let state = TFTPState { state_data: AppLayerStateData::new(), transactions : Vec::new(), tx_id: 0, }; +pub extern fn rs_tftp_state_alloc() -> *mut std::os::raw::c_void { + let state = TFTPState { + state_data: AppLayerStateData::new(), + transactions: Vec::new(), + tx_id: 0, + }; let boxed = Box::new(state); return Box::into_raw(boxed) as *mut _; } #[no_mangle] -pub extern "C" fn rs_tftp_state_free(state: *mut std::os::raw::c_void) { +pub extern fn rs_tftp_state_free(state: *mut std::os::raw::c_void) { std::mem::drop(unsafe { Box::from_raw(state as *mut TFTPState) }); } #[no_mangle] -pub extern "C" fn rs_tftp_state_tx_free(state: &mut TFTPState, - tx_id: u64) { +pub extern fn rs_tftp_state_tx_free(state: &mut TFTPState, tx_id: u64) { state.free_tx(tx_id); } #[no_mangle] -pub extern "C" fn rs_tftp_get_tx(state: &mut TFTPState, - tx_id: u64) -> *mut std::os::raw::c_void { +pub extern fn rs_tftp_get_tx(state: &mut TFTPState, tx_id: u64) -> *mut std::os::raw::c_void { match state.get_tx_by_id(tx_id) { Some(tx) => tx as *const _ as *mut _, - None => std::ptr::null_mut(), + None => std::ptr::null_mut(), } } #[no_mangle] -pub extern "C" fn rs_tftp_get_tx_cnt(state: &mut TFTPState) -> u64 { +pub extern fn rs_tftp_get_tx_cnt(state: &mut TFTPState) -> u64 { return state.tx_id; } fn getstr(i: &[u8]) -> IResult<&[u8], &str> { - map_res( - take_while(|c| c != 0), - str::from_utf8 - )(i) + map_res(take_while(|c| c != 0), str::from_utf8)(i) } fn tftp_request(slice: &[u8]) -> IResult<&[u8], TFTPTransaction> { @@ -131,10 +130,10 @@ fn tftp_request(slice: &[u8]) -> IResult<&[u8], TFTPTransaction> { let (i, filename) = getstr(i)?; let (i, _) = tag([0])(i)?; let (i, mode) = getstr(i)?; - Ok((i, - TFTPTransaction::new(opcode, String::from(filename), String::from(mode)) - ) - ) + Ok(( + i, + TFTPTransaction::new(opcode, String::from(filename), String::from(mode)), + )) } fn parse_tftp_request(input: &[u8]) -> Option { @@ -155,9 +154,7 @@ fn parse_tftp_request(input: &[u8]) -> Option { } #[no_mangle] -pub unsafe extern "C" fn rs_tftp_request(state: &mut TFTPState, - input: *const u8, - len: u32) -> i64 { +pub unsafe extern fn rs_tftp_request(state: &mut TFTPState, input: *const u8, len: u32) -> i64 { let buf = std::slice::from_raw_parts(input, len as usize); match parse_tftp_request(buf) { Some(mut tx) => { @@ -165,27 +162,21 @@ pub unsafe extern "C" fn rs_tftp_request(state: &mut TFTPState, tx.id = state.tx_id; state.transactions.push(tx); 0 - }, - None => { - -1 } + None => -1, } } #[no_mangle] -pub unsafe extern "C" fn rs_tftp_get_tx_data( - tx: *mut std::os::raw::c_void) - -> *mut AppLayerTxData -{ +pub unsafe extern fn rs_tftp_get_tx_data(tx: *mut std::os::raw::c_void) -> *mut AppLayerTxData { let tx = cast_pointer!(tx, TFTPTransaction); return &mut tx.tx_data; } #[no_mangle] -pub unsafe extern "C" fn rs_tftp_get_state_data( - state: *mut std::os::raw::c_void) - -> *mut AppLayerStateData -{ +pub unsafe extern fn rs_tftp_get_state_data( + state: *mut std::os::raw::c_void, +) -> *mut AppLayerStateData { let state = cast_pointer!(state, TFTPState); return &mut state.state_data; } @@ -194,25 +185,28 @@ pub unsafe extern "C" fn rs_tftp_get_state_data( mod test { use super::*; static READ_REQUEST: [u8; 20] = [ - 0x00, 0x01, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00, + 0x00, 0x01, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x6f, + 0x63, 0x74, 0x65, 0x74, 0x00, ]; /* filename not terminated */ static READ_REQUEST_INVALID_1: [u8; 20] = [ - 0x00, 0x01, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x6e, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00, + 0x00, 0x01, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x6e, 0x6f, + 0x63, 0x74, 0x65, 0x74, 0x00, ]; /* garbage */ - static READ_REQUEST_INVALID_2: [u8; 3] = [ - 0xff, 0xff, 0xff, - ]; + static READ_REQUEST_INVALID_2: [u8; 3] = [0xff, 0xff, 0xff]; static WRITE_REQUEST: [u8; 20] = [ - 0x00, 0x02, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00, + 0x00, 0x02, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x6f, + 0x63, 0x74, 0x65, 0x74, 0x00, ]; /* filename not terminated */ static INVALID_OPCODE: [u8; 20] = [ - 0x00, 0x06, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x6e, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00, + 0x00, 0x06, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x6e, 0x6f, + 0x63, 0x74, 0x65, 0x74, 0x00, ]; static INVALID_MODE: [u8; 20] = [ - 0x00, 0x01, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, + 0x00, 0x01, 0x72, 0x66, 0x63, 0x31, 0x33, 0x35, 0x30, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x00, ]; #[test] @@ -274,7 +268,6 @@ mod test { #[test] pub fn test_parse_tftp_invalid_mode() { - assert_eq!(None, parse_tftp_request(&INVALID_MODE[..])); } } diff --git a/rust/src/util.rs b/rust/src/util.rs index d7109464f773..cde0a3ee8a49 100644 --- a/rust/src/util.rs +++ b/rust/src/util.rs @@ -21,6 +21,6 @@ use std::ffi::CStr; use std::os::raw::c_char; #[no_mangle] -pub unsafe extern "C" fn rs_check_utf8(val: *const c_char) -> bool { +pub unsafe extern fn rs_check_utf8(val: *const c_char) -> bool { CStr::from_ptr(val).to_str().is_ok() } diff --git a/rust/src/x509/log.rs b/rust/src/x509/log.rs index adb64646a752..3595f94db05f 100644 --- a/rust/src/x509/log.rs +++ b/rust/src/x509/log.rs @@ -28,7 +28,7 @@ use std::os::raw::c_char; /// /// FFI function that dereferences pointers from C. #[no_mangle] -pub unsafe extern "C" fn sc_x509_log_timestamp( +pub unsafe extern fn sc_x509_log_timestamp( jb: &mut JsonBuilder, key: *const c_char, timestamp: i64, ) -> bool { if let Ok(key) = CStr::from_ptr(key).to_str() { diff --git a/rust/src/x509/mod.rs b/rust/src/x509/mod.rs index c87928cf17a8..67b4e563e708 100644 --- a/rust/src/x509/mod.rs +++ b/rust/src/x509/mod.rs @@ -24,8 +24,8 @@ use nom7::Err; use std; use std::os::raw::c_char; use x509_parser::prelude::*; -mod time; mod log; +mod time; #[repr(u32)] pub enum X509DecodeError { @@ -52,10 +52,8 @@ pub struct X509(X509Certificate<'static>); /// /// input must be a valid buffer of at least input_len bytes #[no_mangle] -pub unsafe extern "C" fn rs_x509_decode( - input: *const u8, - input_len: u32, - err_code: *mut u32, +pub unsafe extern fn rs_x509_decode( + input: *const u8, input_len: u32, err_code: *mut u32, ) -> *mut X509 { let slice = std::slice::from_raw_parts(input, input_len as usize); let res = X509Certificate::from_der(slice); @@ -70,7 +68,7 @@ pub unsafe extern "C" fn rs_x509_decode( } #[no_mangle] -pub unsafe extern "C" fn rs_x509_get_subject(ptr: *const X509) -> *mut c_char { +pub unsafe extern fn rs_x509_get_subject(ptr: *const X509) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -80,7 +78,7 @@ pub unsafe extern "C" fn rs_x509_get_subject(ptr: *const X509) -> *mut c_char { } #[no_mangle] -pub unsafe extern "C" fn rs_x509_get_issuer(ptr: *const X509) -> *mut c_char { +pub unsafe extern fn rs_x509_get_issuer(ptr: *const X509) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -90,7 +88,7 @@ pub unsafe extern "C" fn rs_x509_get_issuer(ptr: *const X509) -> *mut c_char { } #[no_mangle] -pub unsafe extern "C" fn rs_x509_get_serial(ptr: *const X509) -> *mut c_char { +pub unsafe extern fn rs_x509_get_serial(ptr: *const X509) -> *mut c_char { if ptr.is_null() { return std::ptr::null_mut(); } @@ -107,10 +105,8 @@ pub unsafe extern "C" fn rs_x509_get_serial(ptr: *const X509) -> *mut c_char { /// /// ptr must be a valid object obtained using `rs_x509_decode` #[no_mangle] -pub unsafe extern "C" fn rs_x509_get_validity( - ptr: *const X509, - not_before: *mut i64, - not_after: *mut i64, +pub unsafe extern fn rs_x509_get_validity( + ptr: *const X509, not_before: *mut i64, not_after: *mut i64, ) -> i32 { if ptr.is_null() { return -1; @@ -129,7 +125,7 @@ pub unsafe extern "C" fn rs_x509_get_validity( /// /// ptr must be a valid object obtained using `rs_x509_decode` #[no_mangle] -pub unsafe extern "C" fn rs_x509_free(ptr: *mut X509) { +pub unsafe extern fn rs_x509_free(ptr: *mut X509) { if ptr.is_null() { return; } diff --git a/rust/src/x509/time.rs b/rust/src/x509/time.rs index 507b39c5f872..9b77f7339ac2 100644 --- a/rust/src/x509/time.rs +++ b/rust/src/x509/time.rs @@ -37,7 +37,7 @@ pub fn format_timestamp(timestamp: i64) -> Result { /// /// Access buffers from C that are expected to be valid. #[no_mangle] -pub unsafe extern "C" fn sc_x509_format_timestamp( +pub unsafe extern fn sc_x509_format_timestamp( timestamp: i64, buf: *mut c_char, size: usize, ) -> bool { let timestamp = match format_timestamp(timestamp) { diff --git a/src/Makefile.am b/src/Makefile.am index 4695c2d35f51..e948d1a69875 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,55 +15,210 @@ noinst_HEADERS = \ alert-fastlog.h \ alert-syslog.h \ app-layer-detect-proto.h \ - app-layer-dnp3.h \ - app-layer-dnp3-objects.h \ - app-layer-enip-common.h \ - app-layer-enip.h \ app-layer-events.h \ app-layer-expectation.h \ app-layer-frames.h \ - app-layer-ftp.h \ - app-layer.h \ - app-layer-htp-body.h \ - app-layer-htp-file.h \ - app-layer-htp.h \ - app-layer-htp-libhtp.h \ - app-layer-htp-mem.h \ - app-layer-htp-range.h \ - app-layer-htp-xff.h \ - app-layer-http2.h \ - app-layer-ike.h \ - app-layer-krb5.h \ - app-layer-modbus.h \ - app-layer-quic.h \ - app-layer-mqtt.h \ - app-layer-nfs-tcp.h \ - app-layer-nfs-udp.h \ - app-layer-ntp.h \ app-layer-parser.h \ app-layer-protos.h \ - app-layer-rdp.h \ app-layer-register.h \ - app-layer-rfb.h \ - app-layer-sip.h \ - app-layer-smb.h \ - app-layer-smtp.h \ - app-layer-snmp.h \ - app-layer-ssh.h \ - app-layer-ssl.h \ - app-layer-tftp.h \ + app-layer.h \ + app-layer/bittorrent-dht/logger.h \ + app-layer/dcerpc/logger.h \ + app-layer/dhcp/detect-leasetime.h \ + app-layer/dhcp/detect-rebinding-time.h \ + app-layer/dhcp/detect-renewal-time.h \ + app-layer/dhcp/logger.h \ + app-layer/dnp3/detect.h \ + app-layer/dnp3/logger-objects.h \ + app-layer/dnp3/logger.h \ + app-layer/dnp3/lua-objects.h \ + app-layer/dnp3/lua.h \ + app-layer/dnp3/parser-objects.h \ + app-layer/dnp3/parser.h \ + app-layer/dns/detect-opcode.h \ + app-layer/dns/detect-query.h \ + app-layer/dns/logger.h \ + app-layer/dns/lua.h \ + app-layer/enip/parser-common.h \ + app-layer/enip/parser.h \ + app-layer/ftp/detect-bounce.h \ + app-layer/ftp/detect-data.h \ + app-layer/ftp/logger.h \ + app-layer/ftp/parser.h \ + app-layer/http/detect-accept-enc.h \ + app-layer/http/detect-accept-lang.h \ + app-layer/http/detect-accept.h \ + app-layer/http/detect-client-body.h \ + app-layer/http/detect-connection.h \ + app-layer/http/detect-content-len.h \ + app-layer/http/detect-content-type.h \ + app-layer/http/detect-cookie.h \ + app-layer/http/detect-header-common.h \ + app-layer/http/detect-header-names.h \ + app-layer/http/detect-header.h \ + app-layer/http/detect-headers-stub.h \ + app-layer/http/detect-headers.h \ + app-layer/http/detect-host.h \ + app-layer/http/detect-location.h \ + app-layer/http/detect-method.h \ + app-layer/http/detect-protocol.h \ + app-layer/http/detect-raw-header.h \ + app-layer/http/detect-referer.h \ + app-layer/http/detect-request-line.h \ + app-layer/http/detect-response-line.h \ + app-layer/http/detect-server-body.h \ + app-layer/http/detect-server.h \ + app-layer/http/detect-start.h \ + app-layer/http/detect-stat-code.h \ + app-layer/http/detect-stat-msg.h \ + app-layer/http/detect-ua.h \ + app-layer/http/detect-uri.h \ + app-layer/http/log-httplog.h \ + app-layer/http/logger.h \ + app-layer/http/lua.h \ + app-layer/http/parser-body.h \ + app-layer/http/parser-file.h \ + app-layer/http/parser-libhtp.h \ + app-layer/http/parser-mem.h \ + app-layer/http/parser-range.h \ + app-layer/http/parser-xff.h \ + app-layer/http/parser.h \ + app-layer/http2/detect.h \ + app-layer/http2/logger.h \ + app-layer/http2/parser.h \ + app-layer/ike/detect-chosen-sa.h \ + app-layer/ike/detect-exch-type.h \ + app-layer/ike/detect-key-exchange-payload-length.h \ + app-layer/ike/detect-key-exchange-payload.h \ + app-layer/ike/detect-nonce-payload-length.h \ + app-layer/ike/detect-nonce-payload.h \ + app-layer/ike/detect-spi.h \ + app-layer/ike/detect-vendor.h \ + app-layer/ike/logger.h \ + app-layer/ike/parser.h \ + app-layer/krb5/detect-cname.h \ + app-layer/krb5/detect-errcode.h \ + app-layer/krb5/detect-msgtype.h \ + app-layer/krb5/detect-sname.h \ + app-layer/krb5/detect-ticket-encryption.h \ + app-layer/krb5/logger.h \ + app-layer/krb5/parser.h \ + app-layer/modbus/detect.h \ + app-layer/modbus/logger.h \ + app-layer/modbus/parser.h \ + app-layer/mqtt/detect-connack-sessionpresent.h \ + app-layer/mqtt/detect-connect-clientid.h \ + app-layer/mqtt/detect-connect-flags.h \ + app-layer/mqtt/detect-connect-password.h \ + app-layer/mqtt/detect-connect-protocol-string.h \ + app-layer/mqtt/detect-connect-username.h \ + app-layer/mqtt/detect-connect-willmessage.h \ + app-layer/mqtt/detect-connect-willtopic.h \ + app-layer/mqtt/detect-flags.h \ + app-layer/mqtt/detect-protocol-version.h \ + app-layer/mqtt/detect-publish-message.h \ + app-layer/mqtt/detect-publish-topic.h \ + app-layer/mqtt/detect-qos.h \ + app-layer/mqtt/detect-reason-code.h \ + app-layer/mqtt/detect-subscribe-topic.h \ + app-layer/mqtt/detect-type.h \ + app-layer/mqtt/detect-unsubscribe-topic.h \ + app-layer/mqtt/logger.h \ + app-layer/mqtt/parser.h \ + app-layer/nfs/detect-procedure.h \ + app-layer/nfs/detect-version.h \ + app-layer/nfs/logger.h \ + app-layer/nfs/parser-tcp.h \ + app-layer/nfs/parser-udp.h \ + app-layer/ntp/parser.h \ + app-layer/pgsql/logger.h \ + app-layer/quic/detect-cyu-hash.h \ + app-layer/quic/detect-cyu-string.h \ + app-layer/quic/detect-sni.h \ + app-layer/quic/detect-ua.h \ + app-layer/quic/detect-version.h \ + app-layer/quic/logger.h \ + app-layer/quic/parser.h \ + app-layer/rdp/logger.h \ + app-layer/rdp/parser.h \ + app-layer/rfb/detect-name.h \ + app-layer/rfb/detect-secresult.h \ + app-layer/rfb/detect-sectype.h \ + app-layer/rfb/logger.h \ + app-layer/rfb/parser.h \ + app-layer/sip/detect-method.h \ + app-layer/sip/detect-protocol.h \ + app-layer/sip/detect-request-line.h \ + app-layer/sip/detect-response-line.h \ + app-layer/sip/detect-stat-code.h \ + app-layer/sip/detect-stat-msg.h \ + app-layer/sip/detect-uri.h \ + app-layer/sip/logger.h \ + app-layer/sip/parser.h \ + app-layer/smb/detect-ntlmssp.h \ + app-layer/smb/detect-share.h \ + app-layer/smb/logger.h \ + app-layer/smb/parser.h \ + app-layer/smtp/logger.h \ + app-layer/smtp/lua.h \ + app-layer/smtp/parser.h \ + app-layer/snmp/detect-community.h \ + app-layer/snmp/detect-pdu_type.h \ + app-layer/snmp/detect-usm.h \ + app-layer/snmp/detect-version.h \ + app-layer/snmp/logger.h \ + app-layer/snmp/parser.h \ + app-layer/ssh/detect-hassh-server-string.h \ + app-layer/ssh/detect-hassh-server.h \ + app-layer/ssh/detect-hassh-string.h \ + app-layer/ssh/detect-hassh.h \ + app-layer/ssh/detect-proto-version.h \ + app-layer/ssh/detect-proto.h \ + app-layer/ssh/detect-software-version.h \ + app-layer/ssh/detect-software.h \ + app-layer/ssh/logger.h \ + app-layer/ssh/lua-hassh.h \ + app-layer/ssh/lua.h \ + app-layer/ssh/parser.h \ + app-layer/ssl/detect-state.h \ + app-layer/ssl/detect-version.h \ + app-layer/ssl/parser.h \ + app-layer/template/detect-2.h \ + app-layer/template/detect-rust-buffer.h \ + app-layer/template/detect.h \ + app-layer/template/logger.h \ + app-layer/tftp/logger.h \ + app-layer/tftp/parser.h \ + app-layer/tls/detect-cert-fingerprint.h \ + app-layer/tls/detect-cert-issuer.h \ + app-layer/tls/detect-cert-serial.h \ + app-layer/tls/detect-cert-subject.h \ + app-layer/tls/detect-cert-validity.h \ + app-layer/tls/detect-certs.h \ + app-layer/tls/detect-ja3-hash.h \ + app-layer/tls/detect-ja3-string.h \ + app-layer/tls/detect-ja3s-hash.h \ + app-layer/tls/detect-ja3s-string.h \ + app-layer/tls/detect-random.h \ + app-layer/tls/detect-sni.h \ + app-layer/tls/detect-version.h \ + app-layer/tls/detect.h \ + app-layer/tls/log-tlslog.h \ + app-layer/tls/log-tlsstore.h \ + app-layer/tls/logger.h \ + app-layer/tls/lua.h \ autoconf.h \ build-info.h \ - conf.h \ conf-yaml-loader.h \ + conf.h \ counters.h \ - datasets.h \ datasets-ipv4.h \ datasets-ipv6.h \ datasets-md5.h \ datasets-reputation.h \ datasets-sha256.h \ datasets-string.h \ + datasets.h \ decode-chdlc.h \ decode-erspan.h \ decode-esp.h \ @@ -71,7 +226,6 @@ noinst_HEADERS = \ decode-events.h \ decode-geneve.h \ decode-gre.h \ - decode.h \ decode-icmpv4.h \ decode-icmpv6.h \ decode-ipv4.h \ @@ -90,11 +244,12 @@ noinst_HEADERS = \ decode-vlan.h \ decode-vntag.h \ decode-vxlan.h \ + decode.h \ defrag-config.h \ - defrag.h \ defrag-hash.h \ defrag-queue.h \ defrag-timeout.h \ + defrag.h \ detect-app-layer-event.h \ detect-app-layer-protocol.h \ detect-asn1.h \ @@ -120,13 +275,10 @@ noinst_HEADERS = \ detect-depth.h \ detect-detection-filter.h \ detect-distance.h \ - detect-dnp3.h \ - detect-dns-opcode.h \ - detect-dns-query.h \ detect-dsize.h \ - detect-engine-address.h \ detect-engine-address-ipv4.h \ detect-engine-address-ipv6.h \ + detect-engine-address.h \ detect-engine-alert.h \ detect-engine-analyzer.h \ detect-engine-build.h \ @@ -136,7 +288,6 @@ noinst_HEADERS = \ detect-engine-event.h \ detect-engine-file.h \ detect-engine-frame.h \ - detect-engine.h \ detect-engine-iponly.h \ detect-engine-loader.h \ detect-engine-mpm.h \ @@ -153,6 +304,7 @@ noinst_HEADERS = \ detect-engine-tag.h \ detect-engine-threshold.h \ detect-engine-uint.h \ + detect-engine.h \ detect-fast-pattern.h \ detect-file-data.h \ detect-file-hash-common.h \ @@ -163,65 +315,25 @@ noinst_HEADERS = \ detect-filesha256.h \ detect-filesize.h \ detect-filestore.h \ - detect-flowbits.h \ - detect-flow.h \ detect-flow-age.h \ detect-flow-pkts.h \ + detect-flow.h \ + detect-flowbits.h \ detect-flowint.h \ detect-flowvar.h \ detect-fragbits.h \ detect-fragoffset.h \ detect-frame.h \ - detect-ftpbounce.h \ - detect-ftpdata.h \ detect-geoip.h \ detect-gid.h \ - detect.h \ detect-hostbits.h \ - detect-http2.h \ - detect-http-accept-enc.h \ - detect-http-accept.h \ - detect-http-accept-lang.h \ - detect-http-client-body.h \ - detect-http-connection.h \ - detect-http-content-len.h \ - detect-http-content-type.h \ - detect-http-cookie.h \ - detect-http-header-common.h \ - detect-http-header.h \ - detect-http-header-names.h \ - detect-http-headers.h \ - detect-http-headers-stub.h \ - detect-http-host.h \ - detect-http-location.h \ - detect-http-method.h \ - detect-http-protocol.h \ - detect-http-raw-header.h \ - detect-http-referer.h \ - detect-http-request-line.h \ - detect-http-response-line.h \ - detect-http-server-body.h \ - detect-http-server.h \ - detect-http-start.h \ - detect-http-stat-code.h \ - detect-http-stat-msg.h \ - detect-http-ua.h \ - detect-http-uri.h \ detect-icmp-id.h \ detect-icmp-seq.h \ detect-icmpv4hdr.h \ - detect-icmpv6hdr.h \ detect-icmpv6-mtu.h \ + detect-icmpv6hdr.h \ detect-icode.h \ detect-id.h \ - detect-ike-exch-type.h \ - detect-ike-spi.h \ - detect-ike-vendor.h \ - detect-ike-chosen-sa.h \ - detect-ike-key-exchange-payload-length.h \ - detect-ike-nonce-payload-length.h \ - detect-ike-nonce-payload.h \ - detect-ike-key-exchange-payload.h \ detect-ipaddr.h \ detect-ipopts.h \ detect-ipproto.h \ @@ -230,42 +342,12 @@ noinst_HEADERS = \ detect-ipv6hdr.h \ detect-isdataat.h \ detect-itype.h \ - detect-krb5-cname.h \ - detect-krb5-errcode.h \ - detect-krb5-msgtype.h \ - detect-krb5-sname.h \ - detect-krb5-ticket-encryption.h \ detect-l3proto.h \ detect-lua-extensions.h \ detect-lua.h \ detect-mark.h \ detect-metadata.h \ - detect-modbus.h \ - detect-quic-sni.h \ - detect-quic-ua.h \ - detect-quic-version.h \ - detect-quic-cyu-hash.h \ - detect-quic-cyu-string.h \ - detect-mqtt-connack-sessionpresent.h \ - detect-mqtt-connect-clientid.h \ - detect-mqtt-connect-flags.h \ - detect-mqtt-connect-password.h \ - detect-mqtt-connect-protocol-string.h \ - detect-mqtt-connect-username.h \ - detect-mqtt-connect-willmessage.h \ - detect-mqtt-connect-willtopic.h \ - detect-mqtt-flags.h \ - detect-mqtt-protocol-version.h \ - detect-mqtt-publish-message.h \ - detect-mqtt-publish-topic.h \ - detect-mqtt-qos.h \ - detect-mqtt-reason-code.h \ - detect-mqtt-subscribe-topic.h \ - detect-mqtt-type.h \ - detect-mqtt-unsubscribe-topic.h \ detect-msg.h \ - detect-nfs-procedure.h \ - detect-nfs-version.h \ detect-noalert.h \ detect-nocase.h \ detect-offset.h \ @@ -279,65 +361,19 @@ noinst_HEADERS = \ detect-reference.h \ detect-replace.h \ detect-rev.h \ - detect-rfb-name.h \ - detect-rfb-secresult.h \ - detect-rfb-sectype.h \ detect-rpc.h \ detect-sameip.h \ detect-sid.h \ - detect-sip-method.h \ - detect-sip-protocol.h \ - detect-sip-request-line.h \ - detect-sip-response-line.h \ - detect-sip-stat-code.h \ - detect-sip-stat-msg.h \ - detect-sip-uri.h \ - detect-smb-ntlmssp.h \ - detect-smb-share.h \ - detect-snmp-community.h \ - detect-snmp-pdu_type.h \ - detect-snmp-usm.h \ - detect-snmp-version.h \ - detect-dhcp-leasetime.h \ - detect-dhcp-rebinding-time.h \ - detect-dhcp-renewal-time.h \ - detect-ssh-hassh.h \ - detect-ssh-hassh-server.h \ - detect-ssh-hassh-server-string.h \ - detect-ssh-hassh-string.h \ - detect-ssh-proto.h \ - detect-ssh-proto-version.h \ - detect-ssh-software.h \ - detect-ssh-software-version.h \ - detect-ssl-state.h \ - detect-ssl-version.h \ detect-stream_size.h \ detect-tag.h \ detect-target.h \ detect-tcp-ack.h \ detect-tcp-flags.h \ - detect-tcphdr.h \ - detect-tcpmss.h \ detect-tcp-seq.h \ detect-tcp-window.h \ - detect-template2.h \ - detect-template.h \ - detect-template-rust-buffer.h \ + detect-tcphdr.h \ + detect-tcpmss.h \ detect-threshold.h \ - detect-tls-cert-fingerprint.h \ - detect-tls-cert-issuer.h \ - detect-tls-cert-serial.h \ - detect-tls-certs.h \ - detect-tls-cert-subject.h \ - detect-tls-cert-validity.h \ - detect-tls.h \ - detect-tls-ja3-hash.h \ - detect-tls-ja3s-hash.h \ - detect-tls-ja3s-string.h \ - detect-tls-ja3-string.h \ - detect-tls-sni.h \ - detect-tls-version.h \ - detect-tls-random.h \ detect-tos.h \ detect-transform-casechange.h \ detect-transform-compress-whitespace.h \ @@ -356,11 +392,11 @@ noinst_HEADERS = \ detect-urilen.h \ detect-within.h \ detect-xbits.h \ + detect.h \ device-storage.h \ feature.h \ flow-bit.h \ flow-bypass.h \ - flow.h \ flow-hash.h \ flow-manager.h \ flow-private.h \ @@ -371,80 +407,52 @@ noinst_HEADERS = \ flow-util.h \ flow-var.h \ flow-worker.h \ + flow.h \ host-bit.h \ - host.h \ host-queue.h \ host-storage.h \ host-timeout.h \ + host.h \ ippair-bit.h \ - ippair.h \ ippair-queue.h \ ippair-storage.h \ ippair-timeout.h \ + ippair.h \ log-cf-common.h \ - log-httplog.h \ log-pcap.h \ log-stats.h \ log-tcp-data.h \ - log-tlslog.h \ - log-tlsstore.h \ - output-eve-stream.h \ - output-eve-null.h \ - output-filedata.h \ - output-file.h \ - output-filestore.h \ - output-flow.h \ - output.h \ - output-json-alert.h \ - output-json-anomaly.h \ - output-json-bittorrent-dht.h \ - output-json-dcerpc.h \ - output-json-dhcp.h \ - output-json-dnp3.h \ - output-json-dnp3-objects.h \ - output-json-dns.h \ - output-json-drop.h \ - output-json-email-common.h \ - output-json-file.h \ - output-json-flow.h \ - output-json-frame.h \ - output-json-ftp.h \ - output-json.h \ - output-json-http2.h \ - output-json-http.h \ - output-json-ike.h \ - output-json-krb5.h \ - output-json-metadata.h \ - output-json-modbus.h \ - output-json-quic.h \ - output-json-mqtt.h \ - output-json-netflow.h \ - output-json-nfs.h \ - output-json-pgsql.h \ - output-json-rdp.h \ - output-json-rfb.h \ - output-json-sip.h \ - output-json-smb.h \ - output-json-smtp.h \ - output-json-snmp.h \ - output-json-ssh.h \ - output-json-stats.h \ - output-json-template.h \ - output-json-tftp.h \ - output-json-tls.h \ - output-eve-syslog.h \ - output-lua.h \ - output-packet.h \ - output-stats.h \ - output-streaming.h \ - output-tx.h \ - packet.h \ + output/eve/output-eve-null.h \ + output/eve/output-eve-stream.h \ + output/eve/output-eve-syslog.h \ + output/eve/output-json-alert.h \ + output/eve/output-json-anomaly.h \ + output/eve/output-json-drop.h \ + output/eve/output-json-email-common.h \ + output/eve/output-json-file.h \ + output/eve/output-json-flow.h \ + output/eve/output-json-frame.h \ + output/eve/output-json-metadata.h \ + output/eve/output-json-netflow.h \ + output/eve/output-json-stats.h \ + output/eve/output-json.h \ + output/output-file.h \ + output/output-filedata.h \ + output/output-filestore.h \ + output/output-flow.h \ + output/output-lua.h \ + output/output-packet.h \ + output/output-stats.h \ + output/output-streaming.h \ + output/output-tx.h \ + output/output.h \ packet-queue.h \ + packet.h \ pkt-var.h \ queue.h \ reputation.h \ - respond-reject.h \ respond-reject-libnet11.h \ + respond-reject.h \ runmode-af-packet.h \ runmode-af-xdp.h \ runmode-dpdk.h \ @@ -458,10 +466,10 @@ noinst_HEADERS = \ runmode-pcap-file.h \ runmode-pcap.h \ runmode-pfring.h \ - runmodes.h \ runmode-unittests.h \ runmode-unix-socket.h \ runmode-windivert.h \ + runmodes.h \ rust-context.h \ rust.h \ source-af-packet.h \ @@ -473,17 +481,15 @@ noinst_HEADERS = \ source-napatech.h \ source-netmap.h \ source-nflog.h \ - source-nfq.h \ source-nfq-prototypes.h \ + source-nfq.h \ source-pcap-file-directory-helper.h \ - source-pcap-file.h \ source-pcap-file-helper.h \ + source-pcap-file.h \ source-pcap.h \ source-pfring.h \ - source-windivert.h \ source-windivert-prototypes.h \ - stream.h \ - stream-tcp.h \ + source-windivert.h \ stream-tcp-cache.h \ stream-tcp-inline.h \ stream-tcp-list.h \ @@ -491,193 +497,340 @@ noinst_HEADERS = \ stream-tcp-reassemble.h \ stream-tcp-sack.h \ stream-tcp-util.h \ + stream-tcp.h \ + stream.h \ suricata-common.h \ - suricata.h \ suricata-plugin.h \ + suricata.h \ threads-debug.h \ - threads.h \ threads-profile.h \ + threads.h \ threadvars.h \ tm-modules.h \ - tmqh-flow.h \ - tmqh-packetpool.h \ - tmqh-simple.h \ tm-queuehandlers.h \ tm-queues.h \ tm-threads-common.h \ tm-threads.h \ + tmqh-flow.h \ + tmqh-packetpool.h \ + tmqh-simple.h \ tree.h \ unix-manager.h \ - util-action.h \ - util-affinity.h \ - util-atomic.h \ - util-base64.h \ - util-bloomfilter-counting.h \ - util-bloomfilter.h \ - util-bpf.h \ - util-buffer.h \ - util-byte.h \ - util-checksum.h \ - util-cidr.h \ - util-classification-config.h \ - util-clock.h \ - util-conf.h \ - util-config.h \ - util-coredump-config.h \ - util-cpu.h \ - util-daemon.h \ - util-datalink.h \ - util-debug-filters.h \ - util-debug.h \ - util-decode-mime.h \ - util-detect.h \ - util-device.h \ - util-dpdk.h \ - util-dpdk-i40e.h \ - util-dpdk-ice.h \ - util-dpdk-ixgbe.h \ - util-dpdk-bonding.h \ - util-ebpf.h \ - util-enum.h \ - util-error.h \ - util-exception-policy.h \ - util-file-decompression.h \ - util-file.h \ - util-file-swf-decompression.h \ - util-fix_checksum.h \ - util-fmemopen.h \ - util-hash.h \ - util-hashlist.h \ - util-hash-lookup3.h \ - util-hash-string.h \ - util-host-info.h \ - util-host-os-info.h \ - util-hyperscan.h \ - util-ioctl.h \ - util-ip.h \ - util-ja3.h \ - util-landlock.h \ - util-logopenfile.h \ - util-log-redis.h \ - util-lua-common.h \ - util-lua-dnp3.h \ - util-lua-dnp3-objects.h \ - util-lua-dns.h \ - util-lua.h \ - util-lua-hassh.h \ - util-lua-http.h \ - util-lua-ja3.h \ - util-luajit.h \ - util-lua-smtp.h \ - util-lua-ssh.h \ - util-lua-tls.h \ - util-macset.h \ - util-magic.h \ - util-memcmp.h \ - util-memcpy.h \ - util-mem.h \ - util-memrchr.h \ - util-misc.h \ - util-mpm-ac.h \ - util-mpm-ac-ks.h \ - util-mpm.h \ - util-mpm-hs.h \ - util-napatech.h \ - util-optimize.h \ - util-pages.h \ - util-path.h \ - util-pidfile.h \ - util-plugin.h \ - util-pool.h \ - util-pool-thread.h \ - util-prefilter.h \ - util-print.h \ - util-privs.h \ - util-profiling.h \ - util-profiling-locks.h \ - util-proto-name.h \ - util-radix-tree.h \ - util-random.h \ - util-reference-config.h \ - util-rohash.h \ - util-rule-vars.h \ - util-runmodes.h \ - util-running-modes.h \ - util-signal.h \ - util-spm-bm.h \ - util-spm-bs2bm.h \ - util-spm-bs.h \ - util-spm.h \ - util-spm-hs.h \ - util-storage.h \ - util-streaming-buffer.h \ - util-syslog.h \ - util-sysfs.h \ - util-thash.h \ - util-threshold-config.h \ - util-time.h \ - util-unittest.h \ - util-unittest-helper.h \ - util-validate.h \ - util-var.h \ - util-var-name.h \ - win32-misc.h \ - win32-service.h \ - win32-syscall.h \ - win32-syslog.h + util/action.h \ + util/affinity.h \ + util/atomic.h \ + util/base64.h \ + util/bloomfilter-counting.h \ + util/bloomfilter.h \ + util/bpf.h \ + util/buffer.h \ + util/byte.h \ + util/checksum.h \ + util/cidr.h \ + util/classification-config.h \ + util/clock.h \ + util/conf.h \ + util/config.h \ + util/coredump-config.h \ + util/cpu.h \ + util/daemon.h \ + util/datalink.h \ + util/debug-filters.h \ + util/debug.h \ + util/decode-mime.h \ + util/detect.h \ + util/device.h \ + util/dpdk-bonding.h \ + util/dpdk-i40e.h \ + util/dpdk-ice.h \ + util/dpdk-ixgbe.h \ + util/dpdk.h \ + util/ebpf.h \ + util/enum.h \ + util/error.h \ + util/exception-policy.h \ + util/file-decompression.h \ + util/file-swf-decompression.h \ + util/file.h \ + util/fix_checksum.h \ + util/fmemopen.h \ + util/hash-lookup3.h \ + util/hash-string.h \ + util/hash.h \ + util/hashlist.h \ + util/host-info.h \ + util/host-os-info.h \ + util/hyperscan.h \ + util/ioctl.h \ + util/ip.h \ + util/ja3.h \ + util/landlock.h \ + util/log-redis.h \ + util/logopenfile.h \ + util/lua/lua-common.h \ + util/lua/lua-ja3.h \ + util/lua/lua.h \ + util/lua/luajit.h \ + util/macset.h \ + util/magic.h \ + util/mem.h \ + util/memcmp.h \ + util/memcpy.h \ + util/memrchr.h \ + util/misc.h \ + util/mpm/mpm-ac-ks.h \ + util/mpm/mpm-ac.h \ + util/mpm/mpm-hs.h \ + util/mpm/mpm.h \ + util/napatech.h \ + util/optimize.h \ + util/pages.h \ + util/path.h \ + util/pidfile.h \ + util/plugin.h \ + util/pool-thread.h \ + util/pool.h \ + util/prefilter.h \ + util/print.h \ + util/privs.h \ + util/profiling-locks.h \ + util/profiling.h \ + util/proto-name.h \ + util/radix-tree.h \ + util/random.h \ + util/reference-config.h \ + util/rohash.h \ + util/rule-vars.h \ + util/runmodes.h \ + util/running-modes.h \ + util/signal.h \ + util/spm-bm.h \ + util/spm-bs.h \ + util/spm-bs2bm.h \ + util/spm-hs.h \ + util/spm.h \ + util/storage.h \ + util/streaming-buffer.h \ + util/sysfs.h \ + util/syslog.h \ + util/thash.h \ + util/threshold-config.h \ + util/time.h \ + util/unittest-helper.h \ + util/unittest.h \ + util/validate.h \ + util/var-name.h \ + util/var.h \ + windows/win32-misc.h \ + windows/win32-service.h \ + windows/win32-syscall.h \ + windows/win32-syslog.h libsuricata_c_a_SOURCES = \ alert-debuglog.c \ alert-fastlog.c \ alert-syslog.c \ - app-layer.c \ app-layer-detect-proto.c \ - app-layer-dnp3.c \ - app-layer-dnp3-objects.c \ - app-layer-enip.c \ - app-layer-enip-common.c \ app-layer-events.c \ app-layer-expectation.c \ - app-layer-ftp.c \ app-layer-frames.c \ - app-layer-htp-body.c \ - app-layer-htp.c \ - app-layer-htp-file.c \ - app-layer-htp-libhtp.c \ - app-layer-htp-mem.c \ - app-layer-htp-range.c \ - app-layer-htp-xff.c \ - app-layer-http2.c \ - app-layer-ike.c \ - app-layer-krb5.c \ - app-layer-modbus.c \ - app-layer-quic.c \ - app-layer-mqtt.c \ - app-layer-nfs-tcp.c \ - app-layer-nfs-udp.c \ - app-layer-ntp.c \ app-layer-parser.c \ app-layer-protos.c \ - app-layer-rdp.c \ app-layer-register.c \ - app-layer-rfb.c \ - app-layer-sip.c \ - app-layer-smb.c \ - app-layer-smtp.c \ - app-layer-snmp.c \ - app-layer-ssh.c \ - app-layer-ssl.c \ - app-layer-tftp.c \ - conf.c \ + app-layer.c \ + app-layer/bittorrent-dht/logger.c \ + app-layer/dcerpc/logger.c \ + app-layer/dhcp/detect-leasetime.c \ + app-layer/dhcp/detect-rebinding-time.c \ + app-layer/dhcp/detect-renewal-time.c \ + app-layer/dhcp/logger.c \ + app-layer/dnp3/detect.c \ + app-layer/dnp3/logger-objects.c \ + app-layer/dnp3/logger.c \ + app-layer/dnp3/lua-objects.c \ + app-layer/dnp3/lua.c \ + app-layer/dnp3/parser-objects.c \ + app-layer/dnp3/parser.c \ + app-layer/dns/detect-opcode.c \ + app-layer/dns/detect-query.c \ + app-layer/dns/logger.c \ + app-layer/dns/lua.c \ + app-layer/enip/parser-common.c \ + app-layer/enip/parser.c \ + app-layer/ftp/detect-bounce.c \ + app-layer/ftp/detect-data.c \ + app-layer/ftp/logger.c \ + app-layer/ftp/parser.c \ + app-layer/http/detect-accept-enc.c \ + app-layer/http/detect-accept-lang.c \ + app-layer/http/detect-accept.c \ + app-layer/http/detect-client-body.c \ + app-layer/http/detect-connection.c \ + app-layer/http/detect-content-len.c \ + app-layer/http/detect-content-type.c \ + app-layer/http/detect-cookie.c \ + app-layer/http/detect-header-common.c \ + app-layer/http/detect-header-names.c \ + app-layer/http/detect-header.c \ + app-layer/http/detect-headers.c \ + app-layer/http/detect-host.c \ + app-layer/http/detect-location.c \ + app-layer/http/detect-method.c \ + app-layer/http/detect-protocol.c \ + app-layer/http/detect-raw-header.c \ + app-layer/http/detect-referer.c \ + app-layer/http/detect-request-line.c \ + app-layer/http/detect-response-line.c \ + app-layer/http/detect-server-body.c \ + app-layer/http/detect-server.c \ + app-layer/http/detect-start.c \ + app-layer/http/detect-stat-code.c \ + app-layer/http/detect-stat-msg.c \ + app-layer/http/detect-ua.c \ + app-layer/http/detect-uri.c \ + app-layer/http/log-httplog.c \ + app-layer/http/logger.c \ + app-layer/http/lua.c \ + app-layer/http/parser-body.c \ + app-layer/http/parser-file.c \ + app-layer/http/parser-libhtp.c \ + app-layer/http/parser-mem.c \ + app-layer/http/parser-range.c \ + app-layer/http/parser-xff.c \ + app-layer/http/parser.c \ + app-layer/http2/detect.c \ + app-layer/http2/logger.c \ + app-layer/http2/parser.c \ + app-layer/ike/detect-chosen-sa.c \ + app-layer/ike/detect-exch-type.c \ + app-layer/ike/detect-key-exchange-payload-length.c \ + app-layer/ike/detect-key-exchange-payload.c \ + app-layer/ike/detect-nonce-payload-length.c \ + app-layer/ike/detect-nonce-payload.c \ + app-layer/ike/detect-spi.c \ + app-layer/ike/detect-vendor.c \ + app-layer/ike/logger.c \ + app-layer/ike/parser.c \ + app-layer/krb5/detect-cname.c \ + app-layer/krb5/detect-errcode.c \ + app-layer/krb5/detect-msgtype.c \ + app-layer/krb5/detect-sname.c \ + app-layer/krb5/detect-ticket-encryption.c \ + app-layer/krb5/logger.c \ + app-layer/krb5/parser.c \ + app-layer/modbus/detect.c \ + app-layer/modbus/logger.c \ + app-layer/modbus/parser.c \ + app-layer/mqtt/detect-connack-sessionpresent.c \ + app-layer/mqtt/detect-connect-clientid.c \ + app-layer/mqtt/detect-connect-flags.c \ + app-layer/mqtt/detect-connect-password.c \ + app-layer/mqtt/detect-connect-protocol-string.c \ + app-layer/mqtt/detect-connect-username.c \ + app-layer/mqtt/detect-connect-willmessage.c \ + app-layer/mqtt/detect-connect-willtopic.c \ + app-layer/mqtt/detect-flags.c \ + app-layer/mqtt/detect-protocol-version.c \ + app-layer/mqtt/detect-publish-message.c \ + app-layer/mqtt/detect-publish-topic.c \ + app-layer/mqtt/detect-qos.c \ + app-layer/mqtt/detect-reason-code.c \ + app-layer/mqtt/detect-subscribe-topic.c \ + app-layer/mqtt/detect-type.c \ + app-layer/mqtt/detect-unsubscribe-topic.c \ + app-layer/mqtt/logger.c \ + app-layer/mqtt/parser.c \ + app-layer/nfs/detect-procedure.c \ + app-layer/nfs/detect-version.c \ + app-layer/nfs/logger.c \ + app-layer/nfs/parser-tcp.c \ + app-layer/nfs/parser-udp.c \ + app-layer/ntp/parser.c \ + app-layer/pgsql/logger.c \ + app-layer/quic/detect-cyu-hash.c \ + app-layer/quic/detect-cyu-string.c \ + app-layer/quic/detect-sni.c \ + app-layer/quic/detect-ua.c \ + app-layer/quic/detect-version.c \ + app-layer/quic/logger.c \ + app-layer/quic/parser.c \ + app-layer/rdp/logger.c \ + app-layer/rdp/parser.c \ + app-layer/rfb/detect-name.c \ + app-layer/rfb/detect-secresult.c \ + app-layer/rfb/detect-sectype.c \ + app-layer/rfb/logger.c \ + app-layer/rfb/parser.c \ + app-layer/sip/detect-method.c \ + app-layer/sip/detect-protocol.c \ + app-layer/sip/detect-request-line.c \ + app-layer/sip/detect-response-line.c \ + app-layer/sip/detect-stat-code.c \ + app-layer/sip/detect-stat-msg.c \ + app-layer/sip/detect-uri.c \ + app-layer/sip/logger.c \ + app-layer/sip/parser.c \ + app-layer/smb/detect-ntlmssp.c \ + app-layer/smb/detect-share.c \ + app-layer/smb/logger.c \ + app-layer/smb/parser.c \ + app-layer/smtp/logger.c \ + app-layer/smtp/lua.c \ + app-layer/smtp/parser.c \ + app-layer/snmp/detect-community.c \ + app-layer/snmp/detect-pdu_type.c \ + app-layer/snmp/detect-usm.c \ + app-layer/snmp/detect-version.c \ + app-layer/snmp/logger.c \ + app-layer/snmp/parser.c \ + app-layer/ssh/detect-hassh-server-string.c \ + app-layer/ssh/detect-hassh-server.c \ + app-layer/ssh/detect-hassh-string.c \ + app-layer/ssh/detect-hassh.c \ + app-layer/ssh/detect-proto-version.c \ + app-layer/ssh/detect-proto.c \ + app-layer/ssh/detect-software-version.c \ + app-layer/ssh/detect-software.c \ + app-layer/ssh/logger.c \ + app-layer/ssh/lua-hassh.c \ + app-layer/ssh/lua.c \ + app-layer/ssh/parser.c \ + app-layer/ssl/detect-state.c \ + app-layer/ssl/detect-version.c \ + app-layer/ssl/parser.c \ + app-layer/template/detect-2.c \ + app-layer/template/detect-rust-buffer.c \ + app-layer/template/detect.c \ + app-layer/template/logger.c \ + app-layer/tftp/logger.c \ + app-layer/tftp/parser.c \ + app-layer/tls/detect-cert-fingerprint.c \ + app-layer/tls/detect-cert-issuer.c \ + app-layer/tls/detect-cert-serial.c \ + app-layer/tls/detect-cert-subject.c \ + app-layer/tls/detect-cert-validity.c \ + app-layer/tls/detect-certs.c \ + app-layer/tls/detect-ja3-hash.c \ + app-layer/tls/detect-ja3-string.c \ + app-layer/tls/detect-ja3s-hash.c \ + app-layer/tls/detect-ja3s-string.c \ + app-layer/tls/detect-random.c \ + app-layer/tls/detect-sni.c \ + app-layer/tls/detect-version.c \ + app-layer/tls/detect.c \ + app-layer/tls/log-tlslog.c \ + app-layer/tls/log-tlsstore.c \ + app-layer/tls/logger.c \ + app-layer/tls/lua.c \ conf-yaml-loader.c \ + conf.c \ counters.c \ - datasets.c \ datasets-ipv4.c \ datasets-ipv6.c \ datasets-md5.c \ datasets-sha256.c \ datasets-string.c \ - decode.c \ + datasets.c \ decode-chdlc.c \ decode-erspan.c \ decode-esp.c \ @@ -704,11 +857,12 @@ libsuricata_c_a_SOURCES = \ decode-vlan.c \ decode-vntag.c \ decode-vxlan.c \ - defrag.c \ + decode.c \ defrag-config.c \ defrag-hash.c \ defrag-queue.c \ defrag-timeout.c \ + defrag.c \ detect-app-layer-event.c \ detect-app-layer-protocol.c \ detect-asn1.c \ @@ -716,12 +870,11 @@ libsuricata_c_a_SOURCES = \ detect-base64-decode.c \ detect-bsize.c \ detect-bypass.c \ - detect-byte.c \ detect-byte-extract.c \ + detect-byte.c \ detect-bytejump.c \ detect-bytemath.c \ detect-bytetest.c \ - detect.c \ detect-cipservice.c \ detect-classtype.c \ detect-config.c \ @@ -735,17 +888,13 @@ libsuricata_c_a_SOURCES = \ detect-depth.c \ detect-detection-filter.c \ detect-distance.c \ - detect-dnp3.c \ - detect-dns-opcode.c \ - detect-dns-query.c \ detect-dsize.c \ - detect-engine-address.c \ detect-engine-address-ipv4.c \ detect-engine-address-ipv6.c \ + detect-engine-address.c \ detect-engine-alert.c \ detect-engine-analyzer.c \ detect-engine-build.c \ - detect-engine.c \ detect-engine-content-inspection.c \ detect-engine-dcepayload.c \ detect-engine-enip.c \ @@ -757,8 +906,8 @@ libsuricata_c_a_SOURCES = \ detect-engine-mpm.c \ detect-engine-payload.c \ detect-engine-port.c \ - detect-engine-prefilter.c \ detect-engine-prefilter-common.c \ + detect-engine-prefilter.c \ detect-engine-profile.c \ detect-engine-proto.c \ detect-engine-register.c \ @@ -768,6 +917,7 @@ libsuricata_c_a_SOURCES = \ detect-engine-tag.c \ detect-engine-threshold.c \ detect-engine-uint.c \ + detect-engine.c \ detect-fast-pattern.c \ detect-file-data.c \ detect-file-hash-common.c \ @@ -778,63 +928,25 @@ libsuricata_c_a_SOURCES = \ detect-filesha256.c \ detect-filesize.c \ detect-filestore.c \ - detect-flowbits.c \ - detect-flow.c \ detect-flow-age.c \ detect-flow-pkts.c \ + detect-flow.c \ + detect-flowbits.c \ detect-flowint.c \ detect-flowvar.c \ detect-fragbits.c \ detect-fragoffset.c \ detect-frame.c \ - detect-ftpbounce.c \ - detect-ftpdata.c \ detect-geoip.c \ detect-gid.c \ detect-hostbits.c \ - detect-http2.c \ - detect-http-accept.c \ - detect-http-accept-enc.c \ - detect-http-accept-lang.c \ - detect-http-client-body.c \ - detect-http-connection.c \ - detect-http-content-len.c \ - detect-http-content-type.c \ - detect-http-cookie.c \ - detect-http-header.c \ - detect-http-header-common.c \ - detect-http-header-names.c \ - detect-http-headers.c \ - detect-http-host.c \ - detect-http-location.c \ - detect-http-method.c \ - detect-http-protocol.c \ - detect-http-raw-header.c \ - detect-http-referer.c \ - detect-http-request-line.c \ - detect-http-response-line.c \ - detect-http-server-body.c \ - detect-http-server.c \ - detect-http-start.c \ - detect-http-stat-code.c \ - detect-http-stat-msg.c \ - detect-http-ua.c \ - detect-http-uri.c \ detect-icmp-id.c \ detect-icmp-seq.c \ detect-icmpv4hdr.c \ - detect-icmpv6hdr.c \ detect-icmpv6-mtu.c \ + detect-icmpv6hdr.c \ detect-icode.c \ detect-id.c \ - detect-ike-exch-type.c \ - detect-ike-spi.c \ - detect-ike-vendor.c \ - detect-ike-chosen-sa.c \ - detect-ike-key-exchange-payload-length.c \ - detect-ike-nonce-payload-length.c \ - detect-ike-nonce-payload.c \ - detect-ike-key-exchange-payload.c \ detect-ipaddr.c \ detect-ipopts.c \ detect-ipproto.c \ @@ -843,42 +955,12 @@ libsuricata_c_a_SOURCES = \ detect-ipv6hdr.c \ detect-isdataat.c \ detect-itype.c \ - detect-krb5-cname.c \ - detect-krb5-errcode.c \ - detect-krb5-msgtype.c \ - detect-krb5-sname.c \ - detect-krb5-ticket-encryption.c \ detect-l3proto.c \ - detect-lua.c \ detect-lua-extensions.c \ + detect-lua.c \ detect-mark.c \ detect-metadata.c \ - detect-modbus.c \ - detect-quic-sni.c \ - detect-quic-ua.c \ - detect-quic-version.c \ - detect-quic-cyu-hash.c \ - detect-quic-cyu-string.c \ - detect-mqtt-connack-sessionpresent.c \ - detect-mqtt-connect-clientid.c \ - detect-mqtt-connect-flags.c \ - detect-mqtt-connect-password.c \ - detect-mqtt-connect-protocol-string.c \ - detect-mqtt-connect-username.c \ - detect-mqtt-connect-willmessage.c \ - detect-mqtt-connect-willtopic.c \ - detect-mqtt-flags.c \ - detect-mqtt-protocol-version.c \ - detect-mqtt-publish-message.c \ - detect-mqtt-publish-topic.c \ - detect-mqtt-qos.c \ - detect-mqtt-reason-code.c \ - detect-mqtt-subscribe-topic.c \ - detect-mqtt-type.c \ - detect-mqtt-unsubscribe-topic.c \ detect-msg.c \ - detect-nfs-procedure.c \ - detect-nfs-version.c \ detect-noalert.c \ detect-nocase.c \ detect-offset.c \ @@ -892,65 +974,19 @@ libsuricata_c_a_SOURCES = \ detect-reference.c \ detect-replace.c \ detect-rev.c \ - detect-rfb-name.c \ - detect-rfb-secresult.c \ - detect-rfb-sectype.c \ detect-rpc.c \ detect-sameip.c \ detect-sid.c \ - detect-sip-method.c \ - detect-sip-protocol.c \ - detect-sip-request-line.c \ - detect-sip-response-line.c \ - detect-sip-stat-code.c \ - detect-sip-stat-msg.c \ - detect-sip-uri.c \ - detect-smb-ntlmssp.c \ - detect-smb-share.c \ - detect-snmp-community.c \ - detect-snmp-pdu_type.c \ - detect-snmp-usm.c \ - detect-snmp-version.c \ - detect-dhcp-leasetime.c \ - detect-dhcp-rebinding-time.c \ - detect-dhcp-renewal-time.c \ - detect-ssh-hassh.c \ - detect-ssh-hassh-server.c \ - detect-ssh-hassh-server-string.c \ - detect-ssh-hassh-string.c \ - detect-ssh-proto.c \ - detect-ssh-proto-version.c \ - detect-ssh-software.c \ - detect-ssh-software-version.c \ - detect-ssl-state.c \ - detect-ssl-version.c \ detect-stream_size.c \ detect-tag.c \ detect-target.c \ detect-tcp-ack.c \ detect-tcp-flags.c \ - detect-tcphdr.c \ - detect-tcpmss.c \ detect-tcp-seq.c \ detect-tcp-window.c \ - detect-template2.c \ - detect-template.c \ - detect-template-rust-buffer.c \ + detect-tcphdr.c \ + detect-tcpmss.c \ detect-threshold.c \ - detect-tls.c \ - detect-tls-cert-fingerprint.c \ - detect-tls-cert-issuer.c \ - detect-tls-certs.c \ - detect-tls-cert-serial.c \ - detect-tls-cert-subject.c \ - detect-tls-cert-validity.c \ - detect-tls-ja3-hash.c \ - detect-tls-ja3s-hash.c \ - detect-tls-ja3s-string.c \ - detect-tls-ja3-string.c \ - detect-tls-sni.c \ - detect-tls-version.c \ - detect-tls-random.c \ detect-tos.c \ detect-transform-casechange.c \ detect-transform-compress-whitespace.c \ @@ -969,11 +1005,11 @@ libsuricata_c_a_SOURCES = \ detect-urilen.c \ detect-within.c \ detect-xbits.c \ + detect.c \ device-storage.c \ feature.c \ flow-bit.c \ flow-bypass.c \ - flow.c \ flow-hash.c \ flow-manager.c \ flow-queue.c \ @@ -983,80 +1019,52 @@ libsuricata_c_a_SOURCES = \ flow-util.c \ flow-var.c \ flow-worker.c \ + flow.c \ host-bit.c \ - host.c \ host-queue.c \ host-storage.c \ host-timeout.c \ + host.c \ ippair-bit.c \ - ippair.c \ ippair-queue.c \ ippair-storage.c \ ippair-timeout.c \ + ippair.c \ log-cf-common.c \ - log-httplog.c \ log-pcap.c \ log-stats.c \ log-tcp-data.c \ - log-tlslog.c \ - log-tlsstore.c \ - output.c \ - output-eve-stream.c \ - output-file.c \ - output-filedata.c \ - output-filestore.c \ - output-flow.c \ - output-json-alert.c \ - output-json-anomaly.c \ - output-json-bittorrent-dht.c \ - output-json.c \ - output-json-common.c \ - output-json-dcerpc.c \ - output-json-dhcp.c \ - output-json-dnp3.c \ - output-json-dnp3-objects.c \ - output-json-dns.c \ - output-json-drop.c \ - output-json-email-common.c \ - output-json-file.c \ - output-json-flow.c \ - output-json-frame.c \ - output-json-ftp.c \ - output-json-http2.c \ - output-json-http.c \ - output-json-ike.c \ - output-json-krb5.c \ - output-json-metadata.c \ - output-json-modbus.c \ - output-json-quic.c \ - output-json-mqtt.c \ - output-json-netflow.c \ - output-json-nfs.c \ - output-json-pgsql.c \ - output-json-rdp.c \ - output-json-rfb.c \ - output-json-sip.c \ - output-json-smb.c \ - output-json-smtp.c \ - output-json-snmp.c \ - output-json-ssh.c \ - output-json-stats.c \ - output-json-template.c \ - output-json-tftp.c \ - output-json-tls.c \ - output-eve-syslog.c \ - output-eve-null.c \ - output-lua.c \ - output-packet.c \ - output-stats.c \ - output-streaming.c \ - output-tx.c \ - packet.c \ + output/eve/output-eve-null.c \ + output/eve/output-eve-stream.c \ + output/eve/output-eve-syslog.c \ + output/eve/output-json-alert.c \ + output/eve/output-json-anomaly.c \ + output/eve/output-json-common.c \ + output/eve/output-json-drop.c \ + output/eve/output-json-email-common.c \ + output/eve/output-json-file.c \ + output/eve/output-json-flow.c \ + output/eve/output-json-frame.c \ + output/eve/output-json-metadata.c \ + output/eve/output-json-netflow.c \ + output/eve/output-json-stats.c \ + output/eve/output-json.c \ + output/output-file.c \ + output/output-filedata.c \ + output/output-filestore.c \ + output/output-flow.c \ + output/output-lua.c \ + output/output-packet.c \ + output/output-stats.c \ + output/output-streaming.c \ + output/output-tx.c \ + output/output.c \ packet-queue.c \ + packet.c \ pkt-var.c \ reputation.c \ - respond-reject.c \ respond-reject-libnet11.c \ + respond-reject.c \ runmode-af-packet.c \ runmode-af-xdp.c \ runmode-dpdk.c \ @@ -1067,13 +1075,13 @@ libsuricata_c_a_SOURCES = \ runmode-netmap.c \ runmode-nflog.c \ runmode-nfq.c \ - runmode-pcap.c \ runmode-pcap-file.c \ + runmode-pcap.c \ runmode-pfring.c \ - runmodes.c \ runmode-unittests.c \ runmode-unix-socket.c \ runmode-windivert.c \ + runmodes.c \ rust-context.c \ source-af-packet.c \ source-af-xdp.c \ @@ -1085,175 +1093,147 @@ libsuricata_c_a_SOURCES = \ source-netmap.c \ source-nflog.c \ source-nfq.c \ - source-pcap.c \ - source-pcap-file.c \ source-pcap-file-directory-helper.c \ source-pcap-file-helper.c \ + source-pcap-file.c \ + source-pcap.c \ source-pfring.c \ source-windivert.c \ - stream.c \ - stream-tcp.c \ stream-tcp-cache.c \ stream-tcp-inline.c \ stream-tcp-list.c \ stream-tcp-reassemble.c \ stream-tcp-sack.c \ stream-tcp-util.c \ + stream-tcp.c \ + stream.c \ suricata.c \ threads.c \ tm-modules.c \ - tmqh-flow.c \ - tmqh-packetpool.c \ - tmqh-simple.c \ tm-queuehandlers.c \ tm-queues.c \ tm-threads.c \ + tmqh-flow.c \ + tmqh-packetpool.c \ + tmqh-simple.c \ unix-manager.c \ - util-action.c \ - util-affinity.c \ - util-atomic.c \ - util-base64.c \ - util-bloomfilter.c \ - util-bloomfilter-counting.c \ - util-bpf.c \ - util-buffer.c \ - util-byte.c \ - util-checksum.c \ - util-cidr.c \ - util-classification-config.c \ - util-conf.c \ - util-coredump-config.c \ - util-cpu.c \ - util-daemon.c \ - util-datalink.c \ - util-debug.c \ - util-debug-filters.c \ - util-decode-mime.c \ - util-detect.c \ - util-device.c \ - util-dpdk.c \ - util-dpdk-i40e.c \ - util-dpdk-ice.c \ - util-dpdk-ixgbe.c \ - util-dpdk-bonding.c \ - util-ebpf.c \ - util-enum.c \ - util-error.c \ - util-exception-policy.c \ - util-file.c \ - util-file-decompression.c \ - util-file-swf-decompression.c \ - util-fix_checksum.c \ - util-fmemopen.c \ - util-hash.c \ - util-hashlist.c \ - util-hash-lookup3.c \ - util-hash-string.c \ - util-host-info.c \ - util-host-os-info.c \ - util-hyperscan.c \ - util-ioctl.c \ - util-ip.c \ - util-ja3.c \ - util-landlock.c \ - util-logopenfile.c \ - util-log-redis.c \ - util-lua.c \ - util-lua-common.c \ - util-lua-dnp3.c \ - util-lua-dnp3-objects.c \ - util-lua-dns.c \ - util-lua-hassh.c \ - util-lua-http.c \ - util-lua-ja3.c \ - util-luajit.c \ - util-lua-smtp.c \ - util-lua-ssh.c \ - util-lua-tls.c \ - util-macset.c \ - util-magic.c \ - util-mem.c \ - util-memcmp.c \ - util-memrchr.c \ - util-misc.c \ - util-mpm-ac.c \ - util-mpm-ac-ks.c \ - util-mpm-ac-ks-small.c \ - util-mpm.c \ - util-mpm-hs.c \ - util-napatech.c \ - util-pages.c \ - util-path.c \ - util-pidfile.c \ - util-plugin.c \ - util-pool.c \ - util-pool-thread.c \ - util-prefilter.c \ - util-print.c \ - util-privs.c \ - util-profiling.c \ - util-profiling-keywords.c \ - util-profiling-locks.c \ - util-profiling-prefilter.c \ - util-profiling-rulegroups.c \ - util-profiling-rules.c \ - util-proto-name.c \ - util-radix-tree.c \ - util-random.c \ - util-reference-config.c \ - util-rohash.c \ - util-rule-vars.c \ - util-runmodes.c \ - util-running-modes.c \ - util-signal.c \ - util-spm-bm.c \ - util-spm-bs2bm.c \ - util-spm-bs.c \ - util-spm.c \ - util-spm-hs.c \ - util-storage.c \ - util-streaming-buffer.c \ - util-strlcatu.c \ - util-strlcpyu.c \ - util-strptime.c \ - util-syslog.c \ - util-sysfs.c \ - util-thash.c \ - util-threshold-config.c \ - util-time.c \ - util-unittest.c \ - util-unittest-helper.c \ - util-var.c \ - util-var-name.c \ - win32-misc.c \ - win32-service.c \ - win32-syscall.c + util/action.c \ + util/affinity.c \ + util/atomic.c \ + util/base64.c \ + util/bloomfilter-counting.c \ + util/bloomfilter.c \ + util/bpf.c \ + util/buffer.c \ + util/byte.c \ + util/checksum.c \ + util/cidr.c \ + util/classification-config.c \ + util/conf.c \ + util/coredump-config.c \ + util/cpu.c \ + util/daemon.c \ + util/datalink.c \ + util/debug-filters.c \ + util/debug.c \ + util/decode-mime.c \ + util/detect.c \ + util/device.c \ + util/dpdk-bonding.c \ + util/dpdk-i40e.c \ + util/dpdk-ice.c \ + util/dpdk-ixgbe.c \ + util/dpdk.c \ + util/ebpf.c \ + util/enum.c \ + util/error.c \ + util/exception-policy.c \ + util/file-decompression.c \ + util/file-swf-decompression.c \ + util/file.c \ + util/fix_checksum.c \ + util/fmemopen.c \ + util/hash-lookup3.c \ + util/hash-string.c \ + util/hash.c \ + util/hashlist.c \ + util/host-info.c \ + util/host-os-info.c \ + util/hyperscan.c \ + util/ioctl.c \ + util/ip.c \ + util/ja3.c \ + util/landlock.c \ + util/log-redis.c \ + util/logopenfile.c \ + util/lua/lua-common.c \ + util/lua/lua-ja3.c \ + util/lua/lua.c \ + util/lua/luajit.c \ + util/macset.c \ + util/magic.c \ + util/mem.c \ + util/memcmp.c \ + util/memrchr.c \ + util/misc.c \ + util/mpm/mpm-ac-ks-small.c \ + util/mpm/mpm-ac-ks.c \ + util/mpm/mpm-ac.c \ + util/mpm/mpm-hs.c \ + util/mpm/mpm.c \ + util/napatech.c \ + util/pages.c \ + util/path.c \ + util/pidfile.c \ + util/plugin.c \ + util/pool-thread.c \ + util/pool.c \ + util/prefilter.c \ + util/print.c \ + util/privs.c \ + util/profiling-keywords.c \ + util/profiling-locks.c \ + util/profiling-prefilter.c \ + util/profiling-rulegroups.c \ + util/profiling-rules.c \ + util/profiling.c \ + util/proto-name.c \ + util/radix-tree.c \ + util/random.c \ + util/reference-config.c \ + util/rohash.c \ + util/rule-vars.c \ + util/runmodes.c \ + util/running-modes.c \ + util/signal.c \ + util/spm-bm.c \ + util/spm-bs.c \ + util/spm-bs2bm.c \ + util/spm-hs.c \ + util/spm.c \ + util/storage.c \ + util/streaming-buffer.c \ + util/strlcatu.c \ + util/strlcpyu.c \ + util/strptime.c \ + util/sysfs.c \ + util/syslog.c \ + util/thash.c \ + util/threshold-config.c \ + util/time.c \ + util/unittest-helper.c \ + util/unittest.c \ + util/var-name.c \ + util/var.c \ + windows/win32-misc.c \ + windows/win32-service.c \ + windows/win32-syscall.c EXTRA_DIST = \ - tests/stream-tcp-inline.c \ - tests/stream-tcp-list.c \ - tests/detect-ipv4hdr.c \ - tests/detect-ipv6hdr.c \ - tests/detect-tcphdr.c \ - tests/detect-udphdr.c \ - tests/reputation.c \ - tests/detect-bsize.c \ - tests/detect-http2.c \ - tests/detect-icmpv6-mtu.c \ - tests/detect-icmpv6hdr.c \ - tests/detect-snmp-pdu_type.c \ - tests/detect-snmp-version.c \ - tests/detect-template.c \ - tests/detect-transform-pcrexform.c \ - tests/detect-transform-xor.c \ - tests/detect-ttl.c \ - tests/source-pcap.c \ tests/app-layer-htp-file.c \ + tests/detect-bsize.c \ tests/detect-engine-alert.c \ tests/detect-engine-content-inspection.c \ - tests/detect-icmpv4hdr.c \ - tests/detect-parse.c \ - tests/stream-tcp-reassemble.c \ tests/detect-file-data.c \ tests/detect-http-client-body.c \ tests/detect-http-cookie.c \ @@ -1266,10 +1246,22 @@ EXTRA_DIST = \ tests/detect-http-stat-msg.c \ tests/detect-http-uri.c \ tests/detect-http-user-agent.c \ + tests/detect-http2.c \ + tests/detect-icmpv4hdr.c \ + tests/detect-icmpv6-mtu.c \ + tests/detect-icmpv6hdr.c \ + tests/detect-ipaddr.c \ + tests/detect-ipv4hdr.c \ + tests/detect-ipv6hdr.c \ + tests/detect-parse.c \ tests/detect-snmp-community.c \ + tests/detect-snmp-pdu_type.c \ + tests/detect-snmp-version.c \ tests/detect-ssl-state.c \ tests/detect-ssl-version.c \ + tests/detect-tcphdr.c \ tests/detect-template-buffer.c \ + tests/detect-template.c \ tests/detect-tls-cert-fingerprint.c \ tests/detect-tls-cert-issuer.c \ tests/detect-tls-cert-serial.c \ @@ -1277,8 +1269,16 @@ EXTRA_DIST = \ tests/detect-tls-cert-validity.c \ tests/detect-tls-certs.c \ tests/detect-tls-version.c \ - tests/detect-ipaddr.c \ + tests/detect-transform-pcrexform.c \ + tests/detect-transform-xor.c \ + tests/detect-ttl.c \ + tests/detect-udphdr.c \ tests/detect.c \ + tests/reputation.c \ + tests/source-pcap.c \ + tests/stream-tcp-inline.c \ + tests/stream-tcp-list.c \ + tests/stream-tcp-reassemble.c \ tests/stream-tcp.c install-headers: diff --git a/src/action-globals.h b/src/action-globals.h index b63086f668d3..7f0fdc9a719a 100644 --- a/src/action-globals.h +++ b/src/action-globals.h @@ -26,15 +26,15 @@ /* Changing them as flags, so later we can have alerts * and drop simultaneously */ -#define ACTION_ALERT 0x01 -#define ACTION_DROP 0x02 -#define ACTION_REJECT 0x04 -#define ACTION_REJECT_DST 0x08 -#define ACTION_REJECT_BOTH 0x10 -#define ACTION_PASS 0x20 -#define ACTION_CONFIG 0x40 +#define ACTION_ALERT 0x01 +#define ACTION_DROP 0x02 +#define ACTION_REJECT 0x04 +#define ACTION_REJECT_DST 0x08 +#define ACTION_REJECT_BOTH 0x10 +#define ACTION_PASS 0x20 +#define ACTION_CONFIG 0x40 -#define ACTION_REJECT_ANY (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH) +#define ACTION_REJECT_ANY (ACTION_REJECT | ACTION_REJECT_DST | ACTION_REJECT_BOTH) #define ACTION_DROP_REJECT (ACTION_REJECT_ANY | ACTION_DROP) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index aaba84cc6ea6..0ba9bad38ba7 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -34,25 +34,25 @@ #include "threadvars.h" #include "tm-threads.h" -#include "util-print.h" +#include "util/print.h" #include "pkt-var.h" -#include "util-unittest.h" +#include "util/unittest.h" -#include "util-debug.h" -#include "util-validate.h" -#include "util-buffer.h" +#include "util/debug.h" +#include "util/validate.h" +#include "util/buffer.h" -#include "output.h" +#include "output/output.h" #include "alert-debuglog.h" -#include "util-privs.h" +#include "util/privs.h" #include "flow-var.h" #include "flow-bit.h" -#include "util-var-name.h" -#include "util-optimize.h" -#include "util-logopenfile.h" -#include "util-time.h" +#include "util/var-name.h" +#include "util/optimize.h" +#include "util/logopenfile.h" +#include "util/time.h" #include "stream-tcp-reassemble.h" @@ -82,32 +82,28 @@ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, const Packet *p) FlowBit *fb = (FlowBit *)gv; const char *fbname = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); if (fbname) { - MemBufferWriteString(aft->buffer, "FLOWBIT: %s\n", - fbname); + MemBufferWriteString(aft->buffer, "FLOWBIT: %s\n", fbname); } } else if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { - FlowVar *fv = (FlowVar *) gv; + FlowVar *fv = (FlowVar *)gv; if (fv->datatype == FLOWVAR_TYPE_STR) { - const char *fvname = VarNameStoreLookupById(fv->idx, - VAR_TYPE_FLOW_VAR); - MemBufferWriteString(aft->buffer, "FLOWVAR: \"%s\" => \"", - fvname); + const char *fvname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_VAR); + MemBufferWriteString(aft->buffer, "FLOWVAR: \"%s\" => \"", fvname); for (i = 0; i < fv->data.fv_str.value_len; i++) { if (isprint(fv->data.fv_str.value[i])) { - MemBufferWriteString(aft->buffer, "%c", - fv->data.fv_str.value[i]); + MemBufferWriteString(aft->buffer, "%c", fv->data.fv_str.value[i]); } else { - MemBufferWriteString(aft->buffer, "\\%02X", - fv->data.fv_str.value[i]); + MemBufferWriteString(aft->buffer, "\\%02X", fv->data.fv_str.value[i]); } } MemBufferWriteString(aft->buffer, "\"\n"); } else if (fv->datatype == FLOWVAR_TYPE_INT) { - const char *fvname = VarNameStoreLookupById(fv->idx, - VAR_TYPE_FLOW_INT); - MemBufferWriteString(aft->buffer, "FLOWINT: \"%s\" =>" - " %"PRIu32"\n", fvname, fv->data.fv_int.value); + const char *fvname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_INT); + MemBufferWriteString(aft->buffer, + "FLOWINT: \"%s\" =>" + " %" PRIu32 "\n", + fvname, fv->data.fv_int.value); } } gv = gv->next; @@ -129,7 +125,7 @@ static void AlertDebugLogPktVars(AlertDebugLogThread *aft, const Packet *p) const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); MemBufferWriteString(aft->buffer, "PKTVAR: %s\n", varname); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - pv->value, pv->value_len); + pv->value, pv->value_len); pv = pv->next; } } @@ -141,11 +137,10 @@ static int AlertDebugPrintStreamSegmentCallback( { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; - MemBufferWriteString(aft->buffer, "STREAM DATA LEN: %"PRIu32"\n", buflen); + MemBufferWriteString(aft->buffer, "STREAM DATA LEN: %" PRIu32 "\n", buflen); MemBufferWriteString(aft->buffer, "STREAM DATA:\n"); - PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - buf, buflen); + PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, buf, buflen); return 1; } @@ -164,10 +159,12 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da CreateTimeString(p->ts, timebuf, sizeof(timebuf)); - MemBufferWriteString(aft->buffer, "+================\n" - "TIME: %s\n", timebuf); + MemBufferWriteString(aft->buffer, + "+================\n" + "TIME: %s\n", + timebuf); if (p->pcap_cnt > 0) { - MemBufferWriteString(aft->buffer, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt); + MemBufferWriteString(aft->buffer, "PCAP PKT NUM: %" PRIu64 "\n", p->pcap_cnt); } pkt_src_str = PktSrcToString(p->pkt_src); MemBufferWriteString(aft->buffer, "PKT SRC: %s\n", pkt_src_str); @@ -182,66 +179,70 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); } - MemBufferWriteString(aft->buffer, "SRC IP: %s\n" - "DST IP: %s\n" - "PROTO: %" PRIu32 "\n", - srcip, dstip, p->proto); + MemBufferWriteString(aft->buffer, + "SRC IP: %s\n" + "DST IP: %s\n" + "PROTO: %" PRIu32 "\n", + srcip, dstip, p->proto); if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { - MemBufferWriteString(aft->buffer, "SRC PORT: %" PRIu32 "\n" - "DST PORT: %" PRIu32 "\n", - p->sp, p->dp); + MemBufferWriteString(aft->buffer, + "SRC PORT: %" PRIu32 "\n" + "DST PORT: %" PRIu32 "\n", + p->sp, p->dp); if (PKT_IS_TCP(p)) { - MemBufferWriteString(aft->buffer, "TCP SEQ: %"PRIu32"\n" - "TCP ACK: %"PRIu32"\n", - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + MemBufferWriteString(aft->buffer, + "TCP SEQ: %" PRIu32 "\n" + "TCP ACK: %" PRIu32 "\n", + TCP_GET_SEQ(p), TCP_GET_ACK(p)); } } /* flow stuff */ - MemBufferWriteString(aft->buffer, "FLOW: to_server: %s, " - "to_client: %s\n", - p->flowflags & FLOW_PKT_TOSERVER ? "TRUE" : "FALSE", - p->flowflags & FLOW_PKT_TOCLIENT ? "TRUE" : "FALSE"); + MemBufferWriteString(aft->buffer, + "FLOW: to_server: %s, " + "to_client: %s\n", + p->flowflags & FLOW_PKT_TOSERVER ? "TRUE" : "FALSE", + p->flowflags & FLOW_PKT_TOCLIENT ? "TRUE" : "FALSE"); if (p->flow != NULL) { int applayer = 0; applayer = StreamTcpAppLayerIsDisabled(p->flow); CreateTimeString(p->flow->startts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, "FLOW Start TS: %s\n", timebuf); - MemBufferWriteString(aft->buffer, "FLOW PKTS TODST: %"PRIu32"\n" - "FLOW PKTS TOSRC: %"PRIu32"\n" - "FLOW Total Bytes: %"PRIu64"\n", - p->flow->todstpktcnt, p->flow->tosrcpktcnt, - p->flow->todstbytecnt + p->flow->tosrcbytecnt); MemBufferWriteString(aft->buffer, - "FLOW IPONLY SET: TOSERVER: %s, TOCLIENT: %s\n" - "FLOW ACTION: DROP: %s\n" - "FLOW NOINSPECTION: PACKET: %s, PAYLOAD: %s, APP_LAYER: %s\n" - "FLOW APP_LAYER: DETECTED: %s, PROTO %"PRIu16"\n", - p->flow->flags & FLOW_TOSERVER_IPONLY_SET ? "TRUE" : "FALSE", - p->flow->flags & FLOW_TOCLIENT_IPONLY_SET ? "TRUE" : "FALSE", - p->flow->flags & FLOW_ACTION_DROP ? "TRUE" : "FALSE", - p->flow->flags & FLOW_NOPACKET_INSPECTION ? "TRUE" : "FALSE", - p->flow->flags & FLOW_NOPAYLOAD_INSPECTION ? "TRUE" : "FALSE", - applayer ? "TRUE" : "FALSE", - (p->flow->alproto != ALPROTO_UNKNOWN) ? "TRUE" : "FALSE", p->flow->alproto); + "FLOW PKTS TODST: %" PRIu32 "\n" + "FLOW PKTS TOSRC: %" PRIu32 "\n" + "FLOW Total Bytes: %" PRIu64 "\n", + p->flow->todstpktcnt, p->flow->tosrcpktcnt, + p->flow->todstbytecnt + p->flow->tosrcbytecnt); + MemBufferWriteString(aft->buffer, + "FLOW IPONLY SET: TOSERVER: %s, TOCLIENT: %s\n" + "FLOW ACTION: DROP: %s\n" + "FLOW NOINSPECTION: PACKET: %s, PAYLOAD: %s, APP_LAYER: %s\n" + "FLOW APP_LAYER: DETECTED: %s, PROTO %" PRIu16 "\n", + p->flow->flags & FLOW_TOSERVER_IPONLY_SET ? "TRUE" : "FALSE", + p->flow->flags & FLOW_TOCLIENT_IPONLY_SET ? "TRUE" : "FALSE", + p->flow->flags & FLOW_ACTION_DROP ? "TRUE" : "FALSE", + p->flow->flags & FLOW_NOPACKET_INSPECTION ? "TRUE" : "FALSE", + p->flow->flags & FLOW_NOPAYLOAD_INSPECTION ? "TRUE" : "FALSE", + applayer ? "TRUE" : "FALSE", + (p->flow->alproto != ALPROTO_UNKNOWN) ? "TRUE" : "FALSE", p->flow->alproto); AlertDebugLogFlowVars(aft, p); } AlertDebugLogPktVars(aft, p); -/* any stuff */ -/* Sig details? */ + /* any stuff */ + /* Sig details? */ MemBufferWriteString(aft->buffer, - "PACKET LEN: %" PRIu32 "\n" - "PACKET:\n", - GET_PKT_LEN(p)); + "PACKET LEN: %" PRIu32 "\n" + "PACKET:\n", + GET_PKT_LEN(p)); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - GET_PKT_DATA(p), GET_PKT_LEN(p)); + GET_PKT_DATA(p), GET_PKT_LEN(p)); - MemBufferWriteString(aft->buffer, "ALERT CNT: %" PRIu32 "\n", - p->alerts.cnt); + MemBufferWriteString(aft->buffer, "ALERT CNT: %" PRIu32 "\n", p->alerts.cnt); for (i = 0; i < p->alerts.cnt; i++) { const PacketAlert *pa = &p->alerts.alerts[i]; @@ -250,44 +251,37 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da } MemBufferWriteString(aft->buffer, - "ALERT MSG [%02d]: %s\n" - "ALERT GID [%02d]: %" PRIu32 "\n" - "ALERT SID [%02d]: %" PRIu32 "\n" - "ALERT REV [%02d]: %" PRIu32 "\n" - "ALERT CLASS [%02d]: %s\n" - "ALERT PRIO [%02d]: %" PRIu32 "\n" - "ALERT FOUND IN [%02d]: %s\n", - i, pa->s->msg, - i, pa->s->gid, - i, pa->s->id, - i, pa->s->rev, - i, pa->s->class_msg ? pa->s->class_msg : "", - i, pa->s->prio, - i, - pa->flags & PACKET_ALERT_FLAG_STREAM_MATCH ? "STREAM" : - (pa->flags & PACKET_ALERT_FLAG_STATE_MATCH ? "STATE" : "PACKET")); + "ALERT MSG [%02d]: %s\n" + "ALERT GID [%02d]: %" PRIu32 "\n" + "ALERT SID [%02d]: %" PRIu32 "\n" + "ALERT REV [%02d]: %" PRIu32 "\n" + "ALERT CLASS [%02d]: %s\n" + "ALERT PRIO [%02d]: %" PRIu32 "\n" + "ALERT FOUND IN [%02d]: %s\n", + i, pa->s->msg, i, pa->s->gid, i, pa->s->id, i, pa->s->rev, i, + pa->s->class_msg ? pa->s->class_msg : "", i, pa->s->prio, i, + pa->flags & PACKET_ALERT_FLAG_STREAM_MATCH + ? "STREAM" + : (pa->flags & PACKET_ALERT_FLAG_STATE_MATCH ? "STATE" : "PACKET")); if (pa->flags & PACKET_ALERT_FLAG_TX) { - MemBufferWriteString(aft->buffer, - "ALERT IN TX [%02d]: %"PRIu64"\n", i, pa->tx_id); + MemBufferWriteString(aft->buffer, "ALERT IN TX [%02d]: %" PRIu64 "\n", i, pa->tx_id); } else { - MemBufferWriteString(aft->buffer, - "ALERT IN TX [%02d]: N/A\n", i); + MemBufferWriteString(aft->buffer, "ALERT IN TX [%02d]: N/A\n", i); } if (p->payload_len > 0) { MemBufferWriteString(aft->buffer, - "PAYLOAD LEN: %" PRIu32 "\n" - "PAYLOAD:\n", - p->payload_len); + "PAYLOAD LEN: %" PRIu32 "\n" + "PAYLOAD:\n", + p->payload_len); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - p->payload, p->payload_len); + p->payload, p->payload_len); } if ((pa->flags & PACKET_ALERT_FLAG_STATE_MATCH) || - (pa->flags & PACKET_ALERT_FLAG_STREAM_MATCH)) { + (pa->flags & PACKET_ALERT_FLAG_STREAM_MATCH)) { /* This is an app layer or stream alert */ int ret; uint8_t flag; - if (!(PKT_IS_TCP(p)) || p->flow == NULL || - p->flow->protoctx == NULL) { + if (!(PKT_IS_TCP(p)) || p->flow == NULL || p->flow->protoctx == NULL) { return TM_ECODE_OK; } /* IDS mode reverse the data */ @@ -297,17 +291,16 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da } else { flag = STREAM_DUMP_TOSERVER; } - ret = StreamSegmentForEach((const Packet *)p, flag, - AlertDebugPrintStreamSegmentCallback, - (void *)aft); + ret = StreamSegmentForEach( + (const Packet *)p, flag, AlertDebugPrintStreamSegmentCallback, (void *)aft); if (ret < 0) { return TM_ECODE_FAILED; } } } - aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), - MEMBUFFER_OFFSET(aft->buffer), aft->file_ctx); + aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), + aft->file_ctx); return TM_ECODE_OK; } @@ -327,16 +320,15 @@ static TmEcode AlertDebugLogDecoderEvent(ThreadVars *tv, const Packet *p, void * CreateTimeString(p->ts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, - "+================\n" - "TIME: %s\n", timebuf); + "+================\n" + "TIME: %s\n", + timebuf); if (p->pcap_cnt > 0) { - MemBufferWriteString(aft->buffer, - "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt); + MemBufferWriteString(aft->buffer, "PCAP PKT NUM: %" PRIu64 "\n", p->pcap_cnt); } pkt_src_str = PktSrcToString(p->pkt_src); MemBufferWriteString(aft->buffer, "PKT SRC: %s\n", pkt_src_str); - MemBufferWriteString(aft->buffer, - "ALERT CNT: %" PRIu32 "\n", p->alerts.cnt); + MemBufferWriteString(aft->buffer, "ALERT CNT: %" PRIu32 "\n", p->alerts.cnt); for (i = 0; i < p->alerts.cnt; i++) { const PacketAlert *pa = &p->alerts.alerts[i]; @@ -345,29 +337,25 @@ static TmEcode AlertDebugLogDecoderEvent(ThreadVars *tv, const Packet *p, void * } MemBufferWriteString(aft->buffer, - "ALERT MSG [%02d]: %s\n" - "ALERT GID [%02d]: %" PRIu32 "\n" - "ALERT SID [%02d]: %" PRIu32 "\n" - "ALERT REV [%02d]: %" PRIu32 "\n" - "ALERT CLASS [%02d]: %s\n" - "ALERT PRIO [%02d]: %" PRIu32 "\n", - i, pa->s->msg, - i, pa->s->gid, - i, pa->s->id, - i, pa->s->rev, - i, pa->s->class_msg, - i, pa->s->prio); + "ALERT MSG [%02d]: %s\n" + "ALERT GID [%02d]: %" PRIu32 "\n" + "ALERT SID [%02d]: %" PRIu32 "\n" + "ALERT REV [%02d]: %" PRIu32 "\n" + "ALERT CLASS [%02d]: %s\n" + "ALERT PRIO [%02d]: %" PRIu32 "\n", + i, pa->s->msg, i, pa->s->gid, i, pa->s->id, i, pa->s->rev, i, pa->s->class_msg, i, + pa->s->prio); } MemBufferWriteString(aft->buffer, - "PACKET LEN: %" PRIu32 "\n" - "PACKET:\n", - GET_PKT_LEN(p)); + "PACKET LEN: %" PRIu32 "\n" + "PACKET:\n", + GET_PKT_LEN(p)); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - GET_PKT_DATA(p), GET_PKT_LEN(p)); + GET_PKT_DATA(p), GET_PKT_LEN(p)); - aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), - MEMBUFFER_OFFSET(aft->buffer), aft->file_ctx); + aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), + aft->file_ctx); return TM_ECODE_OK; } @@ -378,8 +366,7 @@ static TmEcode AlertDebugLogThreadInit(ThreadVars *t, const void *initdata, void if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if(initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context for AlertDebugLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; @@ -483,7 +470,7 @@ static int AlertDebugLogLogger(ThreadVars *tv, void *thread_data, const Packet * void AlertDebugLogRegister(void) { - OutputRegisterPacketModule(LOGGER_ALERT_DEBUG, MODULE_NAME, "alert-debug", - AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, - AlertDebugLogThreadInit, AlertDebugLogThreadDeinit, NULL); + OutputRegisterPacketModule(LOGGER_ALERT_DEBUG, MODULE_NAME, "alert-debug", AlertDebugLogInitCtx, + AlertDebugLogLogger, AlertDebugLogCondition, AlertDebugLogThreadInit, + AlertDebugLogThreadDeinit, NULL); } diff --git a/src/alert-debuglog.h b/src/alert-debuglog.h index f7c411c3ab3e..aab462667508 100644 --- a/src/alert-debuglog.h +++ b/src/alert-debuglog.h @@ -27,4 +27,3 @@ void AlertDebugLogRegister(void); #endif /* __ALERT_DEBUGLOG_H__ */ - diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 7b4a22a85954..70db95001fb1 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -32,27 +32,27 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-build.h" #include "detect-engine-mpm.h" #include "detect-reference.h" -#include "util-classification-config.h" +#include "util/classification-config.h" -#include "output.h" +#include "output/output.h" #include "alert-fastlog.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-optimize.h" -#include "util-logopenfile.h" -#include "util-time.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/optimize.h" +#include "util/logopenfile.h" +#include "util/time.h" #include "action-globals.h" @@ -76,15 +76,15 @@ int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p); void AlertFastLogRegister(void) { - OutputRegisterPacketModule(LOGGER_ALERT_FAST, MODULE_NAME, "fast", - AlertFastLogInitCtx, AlertFastLogger, AlertFastLogCondition, - AlertFastLogThreadInit, AlertFastLogThreadDeinit, NULL); + OutputRegisterPacketModule(LOGGER_ALERT_FAST, MODULE_NAME, "fast", AlertFastLogInitCtx, + AlertFastLogger, AlertFastLogCondition, AlertFastLogThreadInit, + AlertFastLogThreadDeinit, NULL); AlertFastLogRegisterTests(); } typedef struct AlertFastLogThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ - LogFileCtx* file_ctx; + LogFileCtx *file_ctx; } AlertFastLogThread; static bool AlertFastLogCondition(ThreadVars *tv, void *thread_data, const Packet *p) @@ -92,8 +92,7 @@ static bool AlertFastLogCondition(ThreadVars *tv, void *thread_data, const Packe return (p->alerts.cnt > 0); } -static inline void AlertFastLogOutputAlert(AlertFastLogThread *aft, char *buffer, - int alert_size) +static inline void AlertFastLogOutputAlert(AlertFastLogThread *aft, char *buffer, int alert_size) { /* Output the alert string and count alerts. Only need to lock here. */ aft->file_ctx->Write(buffer, alert_size, aft->file_ctx); @@ -158,22 +157,24 @@ int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p) int size = 0; if (likely(decoder_event == 0)) { PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, - "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" - PRIu32 "] %s [**] [Classification: %s] [Priority: %"PRIu32"]" - " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "\n", timebuf, action, - pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, - protoptr, srcip, src_port_or_icmp, dstip, dst_port_or_icmp); + "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 + "] %s [**] [Classification: %s] [Priority: %" PRIu32 "]" + " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "\n", + timebuf, action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, + pa->s->class_msg, pa->s->prio, protoptr, srcip, src_port_or_icmp, dstip, + dst_port_or_icmp); } else { - PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, - "%s %s[**] [%" PRIu32 ":%" PRIu32 - ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: " - "%" PRIu32 "] [**] [Raw pkt: ", timebuf, action, pa->s->gid, - pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio); - PrintBufferRawLineHex(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, - GET_PKT_DATA(p), GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); + PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, + "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 + "] %s [**] [Classification: %s] [Priority: " + "%" PRIu32 "] [**] [Raw pkt: ", + timebuf, action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, + pa->s->class_msg, pa->s->prio); + PrintBufferRawLineHex(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, GET_PKT_DATA(p), + GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); if (p->pcap_cnt != 0) { - PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, - "] [pcap file packet: %"PRIu64"]\n", p->pcap_cnt); + PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, + "] [pcap file packet: %" PRIu64 "]\n", p->pcap_cnt); } else { PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, "]\n"); } @@ -191,8 +192,7 @@ TmEcode AlertFastLogThreadInit(ThreadVars *t, const void *initdata, void **data) AlertFastLogThread *aft = SCCalloc(1, sizeof(AlertFastLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if(initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; @@ -264,8 +264,8 @@ static void AlertFastLogDeInitCtx(OutputCtx *output_ctx) static int AlertFastLogTest01(void) { - uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; @@ -284,8 +284,8 @@ static int AlertFastLogTest01(void) SCClassConfLoadClassificationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"FastLog test\"; content:\"GET\"; " - "Classtype:unknown; sid:1;)"); + "(msg:\"FastLog test\"; content:\"GET\"; " + "Classtype:unknown; sid:1;)"); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -305,8 +305,8 @@ static int AlertFastLogTest01(void) static int AlertFastLogTest02(void) { - uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -325,8 +325,8 @@ static int AlertFastLogTest02(void) SCClassConfLoadClassificationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"FastLog test\"; content:\"GET\"; " - "Classtype:unknown; sid:1;)"); + "(msg:\"FastLog test\"; content:\"GET\"; " + "Classtype:unknown; sid:1;)"); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -358,5 +358,4 @@ void AlertFastLogRegisterTests(void) UtRegisterTest("AlertFastLogTest02", AlertFastLogTest02); #endif /* UNITTESTS */ - } diff --git a/src/alert-fastlog.h b/src/alert-fastlog.h index cdac2a49d404..e86faa289971 100644 --- a/src/alert-fastlog.h +++ b/src/alert-fastlog.h @@ -28,4 +28,3 @@ void AlertFastLogRegister(void); OutputInitResult AlertFastLogInitCtx(ConfNode *); #endif /* __ALERT_FASTLOG_H__ */ - diff --git a/src/alert-syslog.c b/src/alert-syslog.c index fd1742adb01f..caba81d71678 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -38,27 +38,27 @@ #include "detect-engine-mpm.h" #include "detect-reference.h" -#include "output.h" +#include "output/output.h" #include "alert-syslog.h" -#include "util-classification-config.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-syslog.h" -#include "util-optimize.h" -#include "util-logopenfile.h" +#include "util/classification-config.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/syslog.h" +#include "util/optimize.h" +#include "util/logopenfile.h" #include "action-globals.h" #ifndef OS_WIN32 -#define MODULE_NAME "AlertSyslog" +#define MODULE_NAME "AlertSyslog" static int alert_syslog_level = DEFAULT_ALERT_SYSLOG_LEVEL; typedef struct AlertSyslogThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ - LogFileCtx* file_ctx; + LogFileCtx *file_ctx; } AlertSyslogThread; /** @@ -119,7 +119,7 @@ static OutputInitResult AlertSyslogInitCtx(ConfNode *conf) /* if null we just pass that to openlog, which will then * figure it out by itself. */ - openlog(ident, LOG_PID|LOG_NDELAY, facility); + openlog(ident, LOG_PID | LOG_NDELAY, facility); OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { @@ -148,9 +148,9 @@ static OutputInitResult AlertSyslogInitCtx(ConfNode *conf) */ static TmEcode AlertSyslogThreadInit(ThreadVars *t, const void *initdata, void **data) { - if(initdata == NULL) { + if (initdata == NULL) { SCLogDebug("Error getting context for AlertSyslog. \"initdata\" " - "argument NULL"); + "argument NULL"); return TM_ECODE_FAILED; } @@ -232,11 +232,12 @@ static TmEcode AlertSyslogIPv4(ThreadVars *tv, const Packet *p, void *data) action = "[wDrop] "; } - syslog(alert_syslog_level, "%s[%" PRIu32 ":%" PRIu32 ":%" - PRIu32 "] %s [Classification: %s] [Priority: %"PRIu32"]" - " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "", action, pa->s->gid, - pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio, - protoptr, srcip, p->sp, dstip, p->dp); + syslog(alert_syslog_level, + "%s[%" PRIu32 ":%" PRIu32 ":%" PRIu32 + "] %s [Classification: %s] [Priority: %" PRIu32 "]" + " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "", + action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, + pa->s->prio, protoptr, srcip, p->sp, dstip, p->dp); } SCMutexUnlock(&ast->file_ctx->fp_mutex); @@ -289,13 +290,12 @@ static TmEcode AlertSyslogIPv6(ThreadVars *tv, const Packet *p, void *data) action = "[wDrop] "; } - syslog(alert_syslog_level, "%s[%" PRIu32 ":%" PRIu32 ":%" + syslog(alert_syslog_level, + "%s[%" PRIu32 ":%" PRIu32 ":%" "" PRIu32 "] %s [Classification: %s] [Priority: %" "" PRIu32 "] {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "", action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, - pa->s->prio, protoptr, srcip, p->sp, - dstip, p->dp); - + pa->s->prio, protoptr, srcip, p->sp, dstip, p->dp); } SCMutexUnlock(&ast->file_ctx->fp_mutex); @@ -339,17 +339,19 @@ static TmEcode AlertSyslogDecoderEvent(ThreadVars *tv, const Packet *p, void *da action = "[wDrop] "; } - snprintf(temp_buf_hdr, sizeof(temp_buf_hdr), "%s[%" PRIu32 ":%" PRIu32 - ":%" PRIu32 "] %s [Classification: %s] [Priority: %" PRIu32 - "] [**] [Raw pkt: ", action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, - pa->s->class_msg, pa->s->prio); + snprintf(temp_buf_hdr, sizeof(temp_buf_hdr), + "%s[%" PRIu32 ":%" PRIu32 ":%" PRIu32 + "] %s [Classification: %s] [Priority: %" PRIu32 "] [**] [Raw pkt: ", + action, pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, + pa->s->prio); strlcpy(alert, temp_buf_hdr, sizeof(alert)); - PrintRawLineHexBuf(temp_buf_pkt, sizeof(temp_buf_pkt), GET_PKT_DATA(p), GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); + PrintRawLineHexBuf(temp_buf_pkt, sizeof(temp_buf_pkt), GET_PKT_DATA(p), + GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); strlcat(alert, temp_buf_pkt, sizeof(alert)); if (p->pcap_cnt != 0) { - snprintf(temp_buf_tail, sizeof(temp_buf_tail), "] [pcap file packet: %"PRIu64"]", + snprintf(temp_buf_tail, sizeof(temp_buf_tail), "] [pcap file packet: %" PRIu64 "]", p->pcap_cnt); } else { temp_buf_tail[0] = ']'; @@ -385,11 +387,11 @@ static int AlertSyslogLogger(ThreadVars *tv, void *thread_data, const Packet *p) #endif /* !OS_WIN32 */ /** \brief Function to register the AlertSyslog module */ -void AlertSyslogRegister (void) +void AlertSyslogRegister(void) { #ifndef OS_WIN32 - OutputRegisterPacketModule(LOGGER_ALERT_SYSLOG, MODULE_NAME, "syslog", - AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition, - AlertSyslogThreadInit, AlertSyslogThreadDeinit, NULL); + OutputRegisterPacketModule(LOGGER_ALERT_SYSLOG, MODULE_NAME, "syslog", AlertSyslogInitCtx, + AlertSyslogLogger, AlertSyslogCondition, AlertSyslogThreadInit, AlertSyslogThreadDeinit, + NULL); #endif /* !OS_WIN32 */ } diff --git a/src/alert-syslog.h b/src/alert-syslog.h index 0655a3ae47cb..1c866b613b5c 100644 --- a/src/alert-syslog.h +++ b/src/alert-syslog.h @@ -30,4 +30,3 @@ void AlertSyslogRegister(void); #endif /* __ALERT_SYSLOG_H__ */ - diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 690950d34e72..6a1d332fd64c 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -37,11 +37,11 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" -#include "util-print.h" -#include "util-pool.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-validate.h" +#include "util/print.h" +#include "util/pool.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/validate.h" #include "flow.h" #include "flow-util.h" @@ -59,9 +59,9 @@ #include "app-layer-expectation.h" #include "conf.h" -#include "util-memcmp.h" -#include "util-spm.h" -#include "util-debug.h" +#include "util/memcmp.h" +#include "util/spm.h" +#include "util/debug.h" #include "runmodes.h" @@ -110,7 +110,7 @@ typedef struct AppLayerProtoDetectProbingParser_ { typedef struct AppLayerProtoDetectPMSignature_ { AppProto alproto; - uint8_t direction; /**< direction for midstream */ + uint8_t direction; /**< direction for midstream */ SigIntId id; /* \todo Change this into a non-pointer */ DetectContentData *cd; @@ -181,8 +181,7 @@ struct AppLayerProtoDetectThreadCtx_ { static AppLayerProtoDetectCtx alpd_ctx; static AppLayerProtoDetectAliases *alpda_ctx = NULL; -static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto, - uint8_t *ipprotos); +static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto, uint8_t *ipprotos); /***** Static Internal Calls: Protocol Retrieval *****/ @@ -197,23 +196,21 @@ static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMS SCEnter(); if (s->cd->offset > searchlen) { - SCLogDebug("s->co->offset (%"PRIu16") > searchlen (%"PRIu16")", - s->cd->offset, searchlen); + SCLogDebug( + "s->co->offset (%" PRIu16 ") > searchlen (%" PRIu16 ")", s->cd->offset, searchlen); SCReturnUInt(ALPROTO_UNKNOWN); } if (s->cd->depth > searchlen) { - SCLogDebug("s->co->depth (%"PRIu16") > searchlen (%"PRIu16")", - s->cd->depth, searchlen); + SCLogDebug("s->co->depth (%" PRIu16 ") > searchlen (%" PRIu16 ")", s->cd->depth, searchlen); SCReturnUInt(ALPROTO_UNKNOWN); } const uint8_t *sbuf = buf + s->cd->offset; uint16_t ssearchlen = s->cd->depth - s->cd->offset; - SCLogDebug("s->co->offset (%"PRIu16") s->cd->depth (%"PRIu16")", - s->cd->offset, s->cd->depth); + SCLogDebug( + "s->co->offset (%" PRIu16 ") s->cd->depth (%" PRIu16 ")", s->cd->offset, s->cd->depth); - uint8_t *found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx, - sbuf, ssearchlen); + uint8_t *found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx, sbuf, ssearchlen); if (found == NULL) { SCReturnUInt(ALPROTO_UNKNOWN); } @@ -229,19 +226,18 @@ static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMS SCLogDebug("direction is wrong, rflow = true"); *rflow = true; } - /* validate using Probing Parser */ + /* validate using Probing Parser */ } else { if (s->pp_min_depth > buflen) { - SCLogDebug("PP can't be run yet as pp_min_depth %u > buflen %u", - s->pp_min_depth, buflen); + SCLogDebug( + "PP can't be run yet as pp_min_depth %u > buflen %u", s->pp_min_depth, buflen); SCReturnInt(ALPROTO_UNKNOWN); } uint8_t rdir = 0; AppProto r = s->PPFunc(f, flags, buf, buflen, &rdir); if (r == s->alproto) { - SCLogDebug("found %s/%u, rdir %02x reverse_flow? %s", - AppProtoToString(r), r, rdir, + SCLogDebug("found %s/%u, rdir %02x reverse_flow? %s", AppProtoToString(r), r, rdir, (rdir && direction != rdir) ? "true" : "false"); *rflow = (rdir && direction != rdir); SCReturnUInt(s->alproto); @@ -275,8 +271,7 @@ static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx, /* do the mpm search */ uint32_t search_cnt = mpm_table[pm_ctx->mpm_ctx.mpm_type].Search( - &pm_ctx->mpm_ctx, mpm_tctx, &tctx->pmq, - buf, searchlen); + &pm_ctx->mpm_ctx, mpm_tctx, &tctx->pmq, buf, searchlen); if (search_cnt == 0) { if (buflen >= pm_ctx->mpm_ctx.maxdepth) return -1; @@ -297,9 +292,7 @@ static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx, s, tctx, f, flags, buf, buflen, searchlen, rflow); /* store each unique proto once */ - if (AppProtoIsValid(proto) && - !(pm_results_bf[proto / 8] & (1 << (proto % 8))) ) - { + if (AppProtoIsValid(proto) && !(pm_results_bf[proto / 8] & (1 << (proto % 8)))) { pm_results[pm_matches++] = proto; pm_results_bf[proto / 8] |= 1 << (proto % 8); } @@ -348,7 +341,7 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx FLOW_SET_PM_DONE(f, flags); SCReturnUInt((uint16_t)m); - /* handle non-found in non-midstream case */ + /* handle non-found in non-midstream case */ } else if (!stream_config.midstream) { /* we can give up if mpm gave no results and its search depth * was reached. */ @@ -360,7 +353,7 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx } SCReturnUInt((uint16_t)m); - /* handle non-found in midstream case */ + /* handle non-found in midstream case */ } else if (m <= 0) { if (flags & STREAM_TOSERVER) { pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1]; @@ -382,12 +375,12 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx FLOW_SET_PM_DONE(f, flags); SCReturnUInt((uint16_t)om); - /* both sides failed */ + /* both sides failed */ } else if (om < 0 && m && m < 0) { FLOW_SET_PM_DONE(f, flags); SCReturnUInt(0); - /* one side still uncertain */ + /* one side still uncertain */ } else if (om == 0 || m == 0) { SCReturnUInt(0); } @@ -425,9 +418,8 @@ static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectGetProbingPar SCReturnPtr(pp_elem, "AppLayerProtoDetectProbingParserElement *"); } -static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectGetProbingParsers(AppLayerProtoDetectProbingParser *pp, - uint8_t ipproto, - uint16_t port) +static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectGetProbingParsers( + AppLayerProtoDetectProbingParser *pp, uint8_t ipproto, uint16_t port) { AppLayerProtoDetectProbingParserPort *pp_port = NULL; @@ -449,11 +441,10 @@ static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectGetProbingParser pp_port = pp_port->next; } - end: +end: SCReturnPtr(pp_port, "AppLayerProtoDetectProbingParserPort *"); } - /** * \brief Call the probing expectation to see if there is some for this flow. * @@ -474,8 +465,7 @@ static inline AppProto PPGetProto(const AppLayerProtoDetectProbingParserElement uint8_t flags, const uint8_t *buf, uint32_t buflen, uint32_t *alproto_masks, uint8_t *rdir) { while (pe != NULL) { - if ((buflen < pe->min_depth) || - (alproto_masks[0] & pe->alproto_mask)) { + if ((buflen < pe->min_depth) || (alproto_masks[0] & pe->alproto_mask)) { pe = pe->next; continue; } @@ -489,8 +479,7 @@ static inline AppProto PPGetProto(const AppLayerProtoDetectProbingParserElement if (AppProtoIsValid(alproto)) { SCReturnUInt(alproto); } - if (alproto == ALPROTO_FAILED || - (pe->max_depth != 0 && buflen > pe->max_depth)) { + if (alproto == ALPROTO_FAILED || (pe->max_depth != 0 && buflen > pe->max_depth)) { alproto_masks[0] |= pe->alproto_mask; } pe = pe->next; @@ -527,30 +516,29 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 if (idir != dir) { SWAP_VARS(uint16_t, dp, sp); /* look up parsers in rev dir */ } - SCLogDebug("%u->%u %s", sp, dp, - (dir == STREAM_TOSERVER) ? "toserver" : "toclient"); + SCLogDebug("%u->%u %s", sp, dp, (dir == STREAM_TOSERVER) ? "toserver" : "toclient"); if (dir == STREAM_TOSERVER) { /* first try the destination port */ pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp); alproto_masks = &f->probing_parser_toserver_alproto_masks; if (pp_port_dp != NULL) { - SCLogDebug("toserver - Probing parser found for destination port %"PRIu16, dp); + SCLogDebug("toserver - Probing parser found for destination port %" PRIu16, dp); /* found based on destination port, so use dp registration */ pe1 = pp_port_dp->dp; } else { - SCLogDebug("toserver - No probing parser registered for dest port %"PRIu16, dp); + SCLogDebug("toserver - No probing parser registered for dest port %" PRIu16, dp); } pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp); if (pp_port_sp != NULL) { - SCLogDebug("toserver - Probing parser found for source port %"PRIu16, sp); + SCLogDebug("toserver - Probing parser found for source port %" PRIu16, sp); /* found based on source port, so use sp registration */ pe2 = pp_port_sp->sp; } else { - SCLogDebug("toserver - No probing parser registered for source port %"PRIu16, sp); + SCLogDebug("toserver - No probing parser registered for source port %" PRIu16, sp); } } else { /* first try the destination port */ @@ -561,21 +549,21 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 alproto_masks = &f->probing_parser_toclient_alproto_masks; } if (pp_port_dp != NULL) { - SCLogDebug("toclient - Probing parser found for destination port %"PRIu16, dp); + SCLogDebug("toclient - Probing parser found for destination port %" PRIu16, dp); /* found based on destination port, so use dp registration */ pe1 = pp_port_dp->dp; } else { - SCLogDebug("toclient - No probing parser registered for dest port %"PRIu16, dp); + SCLogDebug("toclient - No probing parser registered for dest port %" PRIu16, dp); } pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp); if (pp_port_sp != NULL) { - SCLogDebug("toclient - Probing parser found for source port %"PRIu16, sp); + SCLogDebug("toclient - Probing parser found for source port %" PRIu16, sp); pe2 = pp_port_sp->sp; } else { - SCLogDebug("toclient - No probing parser registered for source port %"PRIu16, sp); + SCLogDebug("toclient - No probing parser registered for source port %" PRIu16, sp); } } @@ -587,7 +575,7 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 if (pe1 == NULL && pe2 == NULL && pe0 == NULL) { SCLogDebug("%s - No probing parsers found for either port", - (dir == STREAM_TOSERVER) ? "toserver":"toclient"); + (dir == STREAM_TOSERVER) ? "toserver" : "toclient"); goto noparsers; } else { probe_is_found = true; @@ -608,7 +596,7 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 /* 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; + 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) @@ -617,12 +605,10 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 if (alproto_masks[0] == mask) { 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], mask); } 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], mask); } } @@ -640,21 +626,20 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 FLOW_SET_PP_DONE(f, idir); } - end: +end: if (AppProtoIsValid(alproto) && rdir != 0 && rdir != idir) { SCLogDebug("PP found %u, is reverse flow", alproto); *reverse_flow = true; } - SCLogDebug("%s, mask is now %08x", - (idir == STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]); + SCLogDebug("%s, mask is now %08x", (idir == STREAM_TOSERVER) ? "toserver" : "toclient", + alproto_masks[0]); SCReturnUInt(alproto); } /***** Static Internal Calls: PP registration *****/ -static void AppLayerProtoDetectPPGetIpprotos(AppProto alproto, - uint8_t *ipprotos) +static void AppLayerProtoDetectPPGetIpprotos(AppProto alproto, uint8_t *ipprotos) { SCEnter(); @@ -702,7 +687,6 @@ static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParser SCReturnPtr(p, "AppLayerProtoDetectProbingParserElement"); } - static void AppLayerProtoDetectProbingParserElementFree(AppLayerProtoDetectProbingParserElement *p) { SCEnter(); @@ -776,11 +760,8 @@ static void AppLayerProtoDetectProbingParserFree(AppLayerProtoDetectProbingParse SCReturn; } -static AppLayerProtoDetectProbingParserElement * -AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, - uint16_t port, - uint16_t min_depth, - uint16_t max_depth) +static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParserElementCreate( + AppProto alproto, uint16_t port, uint16_t min_depth, uint16_t max_depth) { AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc(); @@ -804,17 +785,18 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, } SCReturnPtr(pe, "AppLayerProtoDetectProbingParserElement"); - error: +error: AppLayerProtoDetectProbingParserElementFree(pe); SCReturnPtr(NULL, "AppLayerProtoDetectProbingParserElement"); } -static AppLayerProtoDetectProbingParserElement * -AppLayerProtoDetectProbingParserElementDuplicate(AppLayerProtoDetectProbingParserElement *pe) +static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParserElementDuplicate( + AppLayerProtoDetectProbingParserElement *pe) { SCEnter(); - AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementAlloc(); + AppLayerProtoDetectProbingParserElement *new_pe = + AppLayerProtoDetectProbingParserElementAlloc(); new_pe->alproto = pe->alproto; new_pe->port = pe->port; @@ -838,32 +820,31 @@ static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingPar printf("\nProtocol Detection Configuration\n"); - for ( ; pp != NULL; pp = pp->next) { + for (; pp != NULL; pp = pp->next) { /* print ip protocol */ if (pp->ipproto == IPPROTO_TCP) printf("IPProto: TCP\n"); else if (pp->ipproto == IPPROTO_UDP) printf("IPProto: UDP\n"); else - printf("IPProto: %"PRIu8"\n", pp->ipproto); + printf("IPProto: %" PRIu8 "\n", pp->ipproto); pp_port = pp->port; - for ( ; pp_port != NULL; pp_port = pp_port->next) { + for (; pp_port != NULL; pp_port = pp_port->next) { if (pp_port->dp != NULL) { - printf(" Port: %"PRIu16 "\n", pp_port->port); + 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 ", " + "mask - %" PRIu32 ")\n", + pp_port->dp_max_depth, pp_port->alproto_mask); pp_pe = pp_port->dp; - for ( ; pp_pe != NULL; pp_pe = pp_pe->next) { + for (; pp_pe != NULL; pp_pe = pp_pe->next) { printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto)); - printf(" port: %"PRIu16 "\n", pp_pe->port); - 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); + printf(" port: %" PRIu16 "\n", pp_pe->port); + 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); printf("\n"); } @@ -873,18 +854,17 @@ 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 ", " + "mask - %" PRIu32 ")\n", + pp_port->sp_max_depth, pp_port->alproto_mask); pp_pe = pp_port->sp; - for ( ; pp_pe != NULL; pp_pe = pp_pe->next) { + for (; pp_pe != NULL; pp_pe = pp_pe->next) { printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto)); - printf(" port: %"PRIu16 "\n", pp_pe->port); - 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); + printf(" port: %" PRIu16 "\n", pp_pe->port); + 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); printf("\n"); } @@ -895,8 +875,9 @@ static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingPar } #endif -static void AppLayerProtoDetectProbingParserElementAppend(AppLayerProtoDetectProbingParserElement **head_pe, - AppLayerProtoDetectProbingParserElement *new_pe) +static void AppLayerProtoDetectProbingParserElementAppend( + AppLayerProtoDetectProbingParserElement **head_pe, + AppLayerProtoDetectProbingParserElement *new_pe) { SCEnter(); @@ -926,16 +907,15 @@ static void AppLayerProtoDetectProbingParserElementAppend(AppLayerProtoDetectPro temp_pe = temp_pe->next; new_pe->next = temp_pe->next; temp_pe->next = new_pe; - } } - end: +end: SCReturn; } -static void AppLayerProtoDetectProbingParserAppend(AppLayerProtoDetectProbingParser **head_pp, - AppLayerProtoDetectProbingParser *new_pp) +static void AppLayerProtoDetectProbingParserAppend( + AppLayerProtoDetectProbingParser **head_pp, AppLayerProtoDetectProbingParser *new_pp) { SCEnter(); @@ -949,12 +929,13 @@ static void AppLayerProtoDetectProbingParserAppend(AppLayerProtoDetectProbingPar temp_pp = temp_pp->next; temp_pp->next = new_pp; - end: +end: SCReturn; } -static void AppLayerProtoDetectProbingParserPortAppend(AppLayerProtoDetectProbingParserPort **head_port, - AppLayerProtoDetectProbingParserPort *new_port) +static void AppLayerProtoDetectProbingParserPortAppend( + AppLayerProtoDetectProbingParserPort **head_port, + AppLayerProtoDetectProbingParserPort *new_port) { SCEnter(); @@ -975,18 +956,13 @@ static void AppLayerProtoDetectProbingParserPortAppend(AppLayerProtoDetectProbin temp_port->next = new_port; } - end: +end: SCReturn; } static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbingParser **pp, - uint8_t ipproto, - uint16_t port, - AppProto alproto, - uint16_t min_depth, uint16_t max_depth, - uint8_t direction, - ProbingParserFPtr ProbingParser1, - ProbingParserFPtr ProbingParser2) + uint8_t ipproto, uint16_t port, AppProto alproto, uint16_t min_depth, uint16_t max_depth, + uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2) { SCEnter(); @@ -1012,7 +988,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_port = curr_port->next; } if (curr_port == NULL) { - AppLayerProtoDetectProbingParserPort *new_port = AppLayerProtoDetectProbingParserPortAlloc(); + AppLayerProtoDetectProbingParserPort *new_port = + AppLayerProtoDetectProbingParserPortAlloc(); new_port->port = port; AppLayerProtoDetectProbingParserPortAppend(&curr_pp->port, new_port); curr_port = new_port; @@ -1032,40 +1009,38 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing AppLayerProtoDetectProbingParserElement *zero_pe; zero_pe = zero_port->dp; - for ( ; zero_pe != NULL; zero_pe = zero_pe->next) { + for (; zero_pe != NULL; zero_pe = zero_pe->next) { if (curr_port->dp == NULL) curr_port->dp_max_depth = zero_pe->max_depth; if (zero_pe->max_depth == 0) curr_port->dp_max_depth = zero_pe->max_depth; - if (curr_port->dp_max_depth != 0 && - curr_port->dp_max_depth < zero_pe->max_depth) { + if (curr_port->dp_max_depth != 0 && curr_port->dp_max_depth < zero_pe->max_depth) { curr_port->dp_max_depth = zero_pe->max_depth; } AppLayerProtoDetectProbingParserElement *dup_pe = - AppLayerProtoDetectProbingParserElementDuplicate(zero_pe); + AppLayerProtoDetectProbingParserElementDuplicate(zero_pe); AppLayerProtoDetectProbingParserElementAppend(&curr_port->dp, dup_pe); curr_port->alproto_mask |= dup_pe->alproto_mask; } zero_pe = zero_port->sp; - for ( ; zero_pe != NULL; zero_pe = zero_pe->next) { + for (; zero_pe != NULL; zero_pe = zero_pe->next) { if (curr_port->sp == NULL) curr_port->sp_max_depth = zero_pe->max_depth; if (zero_pe->max_depth == 0) curr_port->sp_max_depth = zero_pe->max_depth; - if (curr_port->sp_max_depth != 0 && - curr_port->sp_max_depth < zero_pe->max_depth) { + if (curr_port->sp_max_depth != 0 && curr_port->sp_max_depth < zero_pe->max_depth) { curr_port->sp_max_depth = zero_pe->max_depth; } AppLayerProtoDetectProbingParserElement *dup_pe = - AppLayerProtoDetectProbingParserElementDuplicate(zero_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) */ + } /* if (curr_port == NULL) */ /* insert the pe_pp */ AppLayerProtoDetectProbingParserElement *curr_pe; @@ -1086,10 +1061,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_pe = curr_pe->next; } /* Get a new parser element */ - AppLayerProtoDetectProbingParserElement *new_pe = - AppLayerProtoDetectProbingParserElementCreate(alproto, - curr_port->port, - min_depth, max_depth); + AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementCreate( + alproto, curr_port->port, min_depth, max_depth); if (new_pe == NULL) goto error; curr_pe = new_pe; @@ -1101,8 +1074,7 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_port->dp_max_depth = new_pe->max_depth; if (new_pe->max_depth == 0) curr_port->dp_max_depth = new_pe->max_depth; - if (curr_port->dp_max_depth != 0 && - curr_port->dp_max_depth < new_pe->max_depth) { + if (curr_port->dp_max_depth != 0 && 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; @@ -1114,8 +1086,7 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_port->sp_max_depth = new_pe->max_depth; if (new_pe->max_depth == 0) curr_port->sp_max_depth = new_pe->max_depth; - if (curr_port->sp_max_depth != 0 && - curr_port->sp_max_depth < new_pe->max_depth) { + if (curr_port->sp_max_depth != 0 && 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; @@ -1131,38 +1102,35 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing temp_port->dp_max_depth = curr_pe->max_depth; if (curr_pe->max_depth == 0) temp_port->dp_max_depth = curr_pe->max_depth; - if (temp_port->dp_max_depth != 0 && - temp_port->dp_max_depth < curr_pe->max_depth) { + if (temp_port->dp_max_depth != 0 && 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)); + AppLayerProtoDetectProbingParserElementAppend( + &temp_port->dp, AppLayerProtoDetectProbingParserElementDuplicate(curr_pe)); temp_port->alproto_mask |= curr_pe->alproto_mask; } else { if (temp_port->sp == NULL) temp_port->sp_max_depth = curr_pe->max_depth; if (curr_pe->max_depth == 0) temp_port->sp_max_depth = curr_pe->max_depth; - if (temp_port->sp_max_depth != 0 && - temp_port->sp_max_depth < curr_pe->max_depth) { + if (temp_port->sp_max_depth != 0 && 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)); + AppLayerProtoDetectProbingParserElementAppend( + &temp_port->sp, AppLayerProtoDetectProbingParserElementDuplicate(curr_pe)); temp_port->alproto_mask |= curr_pe->alproto_mask; } temp_port = temp_port->next; } /* while */ - } /* if */ + } /* if */ - error: +error: SCReturn; } /***** Static Internal Calls: PM registration *****/ -static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto, - uint8_t *ipprotos) +static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto, uint8_t *ipprotos) { SCEnter(); @@ -1226,8 +1194,7 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) for (; tcdup != struct_offset; tcdup++) { if (tcdup->content_len != content_len || - SCMemcmp(tcdup->content, content, tcdup->content_len) != 0) - { + SCMemcmp(tcdup->content, content, tcdup->content_len) != 0) { continue; } break; @@ -1251,9 +1218,9 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) ctx->max_pat_id = max_id; goto end; - error: +error: ret = -1; - end: +end: if (ahb != NULL) SCFree(ahb); SCReturnInt(ret); @@ -1273,21 +1240,18 @@ static int AppLayerProtoDetectPMMapSignatures(AppLayerProtoDetectPMCtx *ctx) goto error; /* add an array indexed by rule id to look up the sig */ - for (s = ctx->head; s != NULL; ) { + for (s = ctx->head; s != NULL;) { next_s = s->next; s->id = id++; - SCLogDebug("s->id %u offset %u depth %u", - s->id, s->cd->offset, s->cd->depth); + SCLogDebug("s->id %u offset %u depth %u", s->id, s->cd->offset, s->cd->depth); if (s->cd->flags & DETECT_CONTENT_NOCASE) { - mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx, - s->cd->content, s->cd->content_len, + mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx, s->cd->content, s->cd->content_len, s->cd->offset, s->cd->depth, s->cd->id, s->id, 0); if (mpm_ret < 0) goto error; } else { - mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx, - s->cd->content, s->cd->content_len, + mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx, s->cd->content, s->cd->content_len, s->cd->offset, s->cd->depth, s->cd->id, s->id, 0); if (mpm_ret < 0) goto error; @@ -1300,9 +1264,9 @@ static int AppLayerProtoDetectPMMapSignatures(AppLayerProtoDetectPMCtx *ctx) ctx->head = NULL; goto end; - error: +error: ret = -1; - end: +end: SCReturnInt(ret); } @@ -1317,9 +1281,9 @@ static int AppLayerProtoDetectPMPrepareMpm(AppLayerProtoDetectPMCtx *ctx) goto error; goto end; - error: +error: ret = -1; - end: +end: SCReturnInt(ret); } @@ -1335,9 +1299,8 @@ static void AppLayerProtoDetectPMFreeSignature(AppLayerProtoDetectPMSignature *s } static int AppLayerProtoDetectPMAddSignature(AppLayerProtoDetectPMCtx *ctx, DetectContentData *cd, - AppProto alproto, uint8_t direction, - ProbingParserFPtr PPFunc, - uint16_t pp_min_depth, uint16_t pp_max_depth) + AppProto alproto, uint8_t direction, ProbingParserFPtr PPFunc, uint16_t pp_min_depth, + uint16_t pp_max_depth) { SCEnter(); @@ -1360,12 +1323,8 @@ static int AppLayerProtoDetectPMAddSignature(AppLayerProtoDetectPMCtx *ctx, Dete } static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alproto, - const char *pattern, - uint16_t depth, uint16_t offset, - uint8_t direction, - uint8_t is_cs, - ProbingParserFPtr PPFunc, - uint16_t pp_min_depth, uint16_t pp_max_depth) + const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction, uint8_t is_cs, + ProbingParserFPtr PPFunc, uint16_t pp_min_depth, uint16_t pp_max_depth) { SCEnter(); @@ -1373,8 +1332,8 @@ static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alprot AppLayerProtoDetectPMCtx *ctx_pm = NULL; int ret = 0; - DetectContentData *cd = DetectContentParseEncloseQuotes( - alpd_ctx.spm_global_thread_ctx, pattern); + DetectContentData *cd = + DetectContentParseEncloseQuotes(alpd_ctx.spm_global_thread_ctx, pattern); if (cd == NULL) goto error; cd->depth = depth; @@ -1382,8 +1341,7 @@ static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alprot if (!is_cs) { /* Rebuild as nocase */ SpmDestroyCtx(cd->spm_ctx); - cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, - alpd_ctx.spm_global_thread_ctx); + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, alpd_ctx.spm_global_thread_ctx); if (cd->spm_ctx == NULL) { goto error; } @@ -1403,14 +1361,14 @@ static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alprot ctx_pm->min_len = depth; /* Finally turn it into a signature and add to the ctx. */ - AppLayerProtoDetectPMAddSignature(ctx_pm, cd, alproto, direction, - PPFunc, pp_min_depth, pp_max_depth); + AppLayerProtoDetectPMAddSignature( + ctx_pm, cd, alproto, direction, PPFunc, pp_min_depth, pp_max_depth); goto end; - error: +error: DetectContentFree(NULL, cd); ret = -1; - end: +end: SCReturnInt(ret); } @@ -1470,7 +1428,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f alproto = AppLayerProtoDetectPEGetProto(f, ipproto, flags); } - end: +end: if (!AppProtoIsValid(alproto)) alproto = pm_alproto; @@ -1492,7 +1450,7 @@ static void AppLayerProtoDetectFreeProbingParsers(AppLayerProtoDetectProbingPars pp = tmp_pp; } - end: +end: SCReturn; } @@ -1551,9 +1509,9 @@ int AppLayerProtoDetectPrepareState(void) #endif goto end; - error: +error: ret = -1; - end: +end: SCReturnInt(ret); } @@ -1563,32 +1521,22 @@ int AppLayerProtoDetectPrepareState(void) * * \param direction STREAM_TOSERVER or STREAM_TOCLIENT for dp or sp */ -void AppLayerProtoDetectPPRegister(uint8_t ipproto, - const char *portstr, - AppProto alproto, - uint16_t min_depth, uint16_t max_depth, - uint8_t direction, - ProbingParserFPtr ProbingParser1, - ProbingParserFPtr ProbingParser2) +void AppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, + uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2) { SCEnter(); DetectPort *head = NULL; - DetectPortParse(NULL,&head, portstr); + DetectPortParse(NULL, &head, portstr); DetectPort *temp_dp = head; while (temp_dp != NULL) { uint16_t port = temp_dp->port; if (port == 0 && temp_dp->port2 != 0) port++; for (;;) { - AppLayerProtoDetectInsertNewProbingParser(&alpd_ctx.ctx_pp, - ipproto, - port, - alproto, - min_depth, max_depth, - direction, - ProbingParser1, - ProbingParser2); + AppLayerProtoDetectInsertNewProbingParser(&alpd_ctx.ctx_pp, ipproto, port, alproto, + min_depth, max_depth, direction, ProbingParser1, ProbingParser2); if (port == temp_dp->port2) { break; } else { @@ -1597,18 +1545,14 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, } temp_dp = temp_dp->next; } - DetectPortCleanupList(NULL,head); + DetectPortCleanupList(NULL, head); SCReturn; } -int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, - uint8_t ipproto, - const char *alproto_name, - AppProto alproto, - uint16_t min_depth, uint16_t max_depth, - ProbingParserFPtr ProbingParserTs, - ProbingParserFPtr ProbingParserTc) +int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, + const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, + ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc) { SCEnter(); @@ -1618,8 +1562,8 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, ConfNode *port_node = NULL; int config = 0; - r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", - alproto_name, ".detection-ports"); + r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", alproto_name, + ".detection-ports"); if (r < 0) { FatalError("snprintf failure."); } else if (r > (int)sizeof(param)) { @@ -1628,8 +1572,8 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, node = ConfGetNode(param); if (node == NULL) { SCLogDebug("Entry for %s not found.", param); - r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", - alproto_name, ".", ipproto_name, ".detection-ports"); + r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", alproto_name, ".", + ipproto_name, ".detection-ports"); if (r < 0) { FatalError("snprintf failure."); } else if (r > (int)sizeof(param)) { @@ -1646,12 +1590,9 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, port_node = ConfNodeLookupChild(node, "toserver"); if (port_node != NULL && port_node->val != NULL) { - AppLayerProtoDetectPPRegister(ipproto, - port_node->val, - alproto, - min_depth, max_depth, - STREAM_TOSERVER, /* to indicate dp */ - ProbingParserTs, ProbingParserTc); + AppLayerProtoDetectPPRegister(ipproto, port_node->val, alproto, min_depth, max_depth, + STREAM_TOSERVER, /* to indicate dp */ + ProbingParserTs, ProbingParserTc); } /* detect by source port of flow */ @@ -1660,59 +1601,43 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, port_node = ConfNodeLookupChild(node, "toclient"); if (port_node != NULL && port_node->val != NULL) { - AppLayerProtoDetectPPRegister(ipproto, - port_node->val, - alproto, - min_depth, max_depth, - STREAM_TOCLIENT, /* to indicate sp */ - ProbingParserTc, ProbingParserTs); - + AppLayerProtoDetectPPRegister(ipproto, port_node->val, alproto, min_depth, max_depth, + STREAM_TOCLIENT, /* to indicate sp */ + ProbingParserTc, ProbingParserTs); } config = 1; - end: +end: SCReturnInt(config); } /***** PM registration *****/ -int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, - const char *pattern, - uint16_t depth, uint16_t offset, - uint8_t direction) +int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, const char *pattern, + uint16_t depth, uint16_t offset, uint8_t direction) { SCEnter(); - int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, - pattern, depth, offset, - direction, 1 /* case-sensitive */, - NULL, 0, 0); + int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, pattern, depth, offset, + direction, 1 /* case-sensitive */, NULL, 0, 0); SCReturnInt(r); } int AppLayerProtoDetectPMRegisterPatternCSwPP(uint8_t ipproto, AppProto alproto, - const char *pattern, uint16_t depth, uint16_t offset, - uint8_t direction, - ProbingParserFPtr PPFunc, - uint16_t pp_min_depth, uint16_t pp_max_depth) + const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction, + ProbingParserFPtr PPFunc, uint16_t pp_min_depth, uint16_t pp_max_depth) { SCEnter(); - int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, - pattern, depth, offset, - direction, 1 /* case-sensitive */, - PPFunc, pp_min_depth, pp_max_depth); + int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, pattern, depth, offset, + direction, 1 /* case-sensitive */, PPFunc, pp_min_depth, pp_max_depth); SCReturnInt(r); } -int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, - const char *pattern, - uint16_t depth, uint16_t offset, - uint8_t direction) +int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, + uint16_t depth, uint16_t offset, uint8_t direction) { SCEnter(); - int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, - pattern, depth, offset, - direction, 0 /* !case-sensitive */, - NULL, 0, 0); + int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, pattern, depth, offset, + direction, 0 /* !case-sensitive */, NULL, 0, 0); SCReturnInt(r); } @@ -1880,7 +1805,7 @@ void AppLayerProtoDetectReset(Flow *f) // Does not free the structures for the parser // keeps f->alstate for new state creation f->alparser = NULL; - f->alproto = ALPROTO_UNKNOWN; + f->alproto = ALPROTO_UNKNOWN; f->alproto_ts = ALPROTO_UNKNOWN; f->alproto_tc = ALPROTO_UNKNOWN; } @@ -1905,8 +1830,7 @@ int AppLayerProtoDetectConfProtoDetectionEnabledDefault( default_enabled = true; #endif - r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", - alproto, ".enabled"); + r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", alproto, ".enabled"); if (r < 0) { FatalError("snprintf failure."); } else if (r > (int)sizeof(param)) { @@ -1916,8 +1840,8 @@ int AppLayerProtoDetectConfProtoDetectionEnabledDefault( node = ConfGetNode(param); if (node == NULL) { SCLogDebug("Entry for %s not found.", param); - r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", - alproto, ".", ipproto, ".enabled"); + r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", alproto, ".", + ipproto, ".enabled"); if (r < 0) { FatalError("snprintf failure."); } else if (r > (int)sizeof(param)) { @@ -1949,9 +1873,9 @@ int AppLayerProtoDetectConfProtoDetectionEnabledDefault( SCLogError("Invalid value found for %s.", param); exit(EXIT_FAILURE); - disabled: +disabled: enabled = 0; - enabled: +enabled: SCReturnInt(enabled); } @@ -1976,8 +1900,7 @@ AppLayerProtoDetectThreadCtx *AppLayerProtoDetectGetCtxThread(void) max_pat_id = alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id; } else if (alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id && - max_pat_id < alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id) - { + max_pat_id < alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id) { max_pat_id = alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id; } } @@ -2005,11 +1928,11 @@ AppLayerProtoDetectThreadCtx *AppLayerProtoDetectGetCtxThread(void) } goto end; - error: +error: if (alpd_tctx != NULL) AppLayerProtoDetectDestroyCtxThread(alpd_tctx); alpd_tctx = NULL; - end: +end: SCReturnPtr(alpd_tctx, "AppLayerProtoDetectThreadCtx"); } @@ -2116,8 +2039,7 @@ void AppLayerProtoDetectSupportedAppProtocols(AppProto *alprotos) uint8_t expectation_proto[ALPROTO_MAX]; -static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto, - uint8_t *ipprotos) +static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto, uint8_t *ipprotos) { if (expectation_proto[alproto] == IPPROTO_TCP) { ipprotos[IPPROTO_TCP / 8] |= 1 << (IPPROTO_TCP % 8); @@ -2141,7 +2063,7 @@ void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto) #ifdef UNITTESTS -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "detect-engine-alert.h" static AppLayerProtoDetectCtx alpd_ctx_ut; @@ -2218,15 +2140,14 @@ static int AppLayerProtoDetectTest03(void) memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - const char *buf = "HTTP"; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT); buf = "220 "; AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2238,10 +2159,8 @@ static int AppLayerProtoDetectTest03(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP1); bool rflow = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), - STREAM_TOCLIENT, - pm_results, &rflow); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rflow); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_HTTP1); @@ -2267,8 +2186,8 @@ static int AppLayerProtoDetectTest04(void) AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 13, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2279,9 +2198,8 @@ static int AppLayerProtoDetectTest04(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOCLIENT, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_HTTP1); @@ -2296,7 +2214,8 @@ static int AppLayerProtoDetectTest05(void) AppLayerProtoDetectUnittestCtxBackup(); AppLayerProtoDetectSetup(); - uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\nBlahblah"; + uint8_t l7data[] = + "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\nBlahblah"; AppProto pm_results[ALPROTO_MAX]; memset(pm_results, 0, sizeof(pm_results)); Flow f; @@ -2309,8 +2228,8 @@ static int AppLayerProtoDetectTest05(void) AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2322,10 +2241,8 @@ static int AppLayerProtoDetectTest05(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP1); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), - STREAM_TOCLIENT, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_HTTP1); @@ -2353,8 +2270,8 @@ static int AppLayerProtoDetectTest06(void) AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2366,9 +2283,8 @@ static int AppLayerProtoDetectTest06(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP1); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOCLIENT, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_FTP); @@ -2394,8 +2310,8 @@ static int AppLayerProtoDetectTest07(void) AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0); @@ -2405,9 +2321,8 @@ static int AppLayerProtoDetectTest07(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOCLIENT, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 0); AppLayerProtoDetectDestroyCtxThread(alpd_tctx); @@ -2421,6 +2336,7 @@ static int AppLayerProtoDetectTest08(void) AppLayerProtoDetectUnittestCtxBackup(); AppLayerProtoDetectSetup(); + // clang-format off uint8_t l7data[] = { 0x00, 0x00, 0x00, 0x85, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xc8, @@ -2441,6 +2357,7 @@ static int AppLayerProtoDetectTest08(void) 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00 }; + // clang-format on AppProto pm_results[ALPROTO_MAX]; memset(pm_results, 0, sizeof(pm_results)); Flow f; @@ -2451,8 +2368,8 @@ static int AppLayerProtoDetectTest08(void) AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2463,9 +2380,8 @@ static int AppLayerProtoDetectTest08(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOCLIENT, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_SMB); @@ -2480,6 +2396,7 @@ static int AppLayerProtoDetectTest09(void) AppLayerProtoDetectUnittestCtxBackup(); AppLayerProtoDetectSetup(); + // clang-format off uint8_t l7data[] = { 0x00, 0x00, 0x00, 0x66, 0xfe, 0x53, 0x4d, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2496,6 +2413,7 @@ static int AppLayerProtoDetectTest09(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02 }; + // clang-format on AppProto pm_results[ALPROTO_MAX]; memset(pm_results, 0, sizeof(pm_results)); Flow f; @@ -2506,8 +2424,8 @@ static int AppLayerProtoDetectTest09(void) AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2518,9 +2436,8 @@ static int AppLayerProtoDetectTest09(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOCLIENT, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_SMB); @@ -2535,6 +2452,7 @@ static int AppLayerProtoDetectTest10(void) AppLayerProtoDetectUnittestCtxBackup(); AppLayerProtoDetectSetup(); + // clang-format off uint8_t l7data[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2546,6 +2464,7 @@ static int AppLayerProtoDetectTest10(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; + // clang-format on AppProto pm_results[ALPROTO_MAX]; memset(pm_results, 0, sizeof(pm_results)); Flow f; @@ -2556,8 +2475,8 @@ static int AppLayerProtoDetectTest10(void) AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_DCERPC, buf, 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2568,9 +2487,8 @@ static int AppLayerProtoDetectTest10(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_DCERPC); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOCLIENT, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_DCERPC); @@ -2615,8 +2533,8 @@ static int AppLayerProtoDetectTest11(void) IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2635,16 +2553,14 @@ static int AppLayerProtoDetectTest11(void) FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOSERVER, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOSERVER, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_HTTP1); memset(pm_results, 0, sizeof(pm_results)); - cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, - pm_results, &rdir); + cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_HTTP1); @@ -2667,8 +2583,7 @@ static int AppLayerProtoDetectTest12(void) AppLayerProtoDetectPMRegisterPatternCS( IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER); if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].head == NULL || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) - { + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { printf("failure 1\n"); goto end; } @@ -2679,8 +2594,7 @@ static int AppLayerProtoDetectTest12(void) goto end; } if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].head != NULL || - alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL) - { + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL) { printf("failure 3\n"); goto end; } @@ -2699,7 +2613,7 @@ static int AppLayerProtoDetectTest12(void) r = 1; - end: +end: AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); return r; @@ -2740,8 +2654,8 @@ static int AppLayerProtoDetectTest13(void) IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7); @@ -2758,15 +2672,13 @@ static int AppLayerProtoDetectTest13(void) memset(pm_results, 0, sizeof(pm_results)); bool rdir = false; - uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOSERVER, - pm_results, &rdir); + uint32_t cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOSERVER, pm_results, &rdir); FAIL_IF(cnt != 0); memset(pm_results, 0, sizeof(pm_results)); - cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, - pm_results, &rdir); + cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 0); AppLayerProtoDetectDestroyCtxThread(alpd_tctx); @@ -2811,8 +2723,8 @@ static int AppLayerProtoDetectTest14(void) IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT); AppLayerProtoDetectPrepareState(); - /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since - * it sets internal structures which depends on the above function. */ + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), + * since it sets internal structures which depends on the above function. */ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread(); FAIL_IF_NULL(alpd_tctx); @@ -2830,16 +2742,14 @@ static int AppLayerProtoDetectTest14(void) memset(pm_results, 0, sizeof(pm_results)); bool rdir = false; - cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data, sizeof(l7data), STREAM_TOSERVER, - pm_results, &rdir); + cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data, sizeof(l7data), STREAM_TOSERVER, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_HTTP1); memset(pm_results, 0, sizeof(pm_results)); - cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, - &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, - pm_results, &rdir); + cnt = AppLayerProtoDetectPMGetProto( + alpd_tctx, &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT, pm_results, &rdir); FAIL_IF(cnt != 1); FAIL_IF(pm_results[0] != ALPROTO_HTTP1); @@ -2870,7 +2780,6 @@ typedef struct AppLayerProtoDetectPPTestDataPort_ { int tc_no_of_element; } AppLayerProtoDetectPPTestDataPort; - typedef struct AppLayerProtoDetectPPTestDataIPProto_ { uint8_t ipproto; @@ -2879,11 +2788,10 @@ typedef struct AppLayerProtoDetectPPTestDataIPProto_ { } AppLayerProtoDetectPPTestDataIPProto; static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, - AppLayerProtoDetectPPTestDataIPProto *ip_proto, - int no_of_ip_proto) + AppLayerProtoDetectPPTestDataIPProto *ip_proto, int no_of_ip_proto) { int result = 0; - int i = -1, j = -1 , k = -1; + int i = -1, j = -1, k = -1; #ifdef DEBUG int dir = 0; #endif @@ -2908,8 +2816,8 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, #ifdef DEBUG dir = 0; #endif - for (j = 0 ; j < ip_proto[i].port[k].ts_no_of_element; - j++, pp_element = pp_element->next) { + for (j = 0; j < ip_proto[i].port[k].ts_no_of_element; + j++, pp_element = pp_element->next) { if (pp_element->alproto != ip_proto[i].port[k].toserver_element[j].alproto) { goto end; @@ -2917,7 +2825,8 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, if (pp_element->port != ip_proto[i].port[k].toserver_element[j].port) { goto end; } - if (pp_element->alproto_mask != ip_proto[i].port[k].toserver_element[j].alproto_mask) { + 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) { @@ -2934,14 +2843,16 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, #ifdef DEBUG dir = 1; #endif - for (j = 0 ; j < ip_proto[i].port[k].tc_no_of_element; j++, pp_element = pp_element->next) { + for (j = 0; j < ip_proto[i].port[k].tc_no_of_element; + j++, pp_element = pp_element->next) { if (pp_element->alproto != ip_proto[i].port[k].toclient_element[j].alproto) { goto end; } if (pp_element->port != ip_proto[i].port[k].toclient_element[j].port) { goto end; } - if (pp_element->alproto_mask != ip_proto[i].port[k].toclient_element[j].alproto_mask) { + 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) { @@ -2961,16 +2872,15 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, goto end; result = 1; - end: +end: #ifdef DEBUG printf("i = %d, k = %d, j = %d(%s)\n", i, k, j, (dir == 0) ? "ts" : "tc"); #endif return result; } -static uint16_t ProbingParserDummyForTesting(Flow *f, uint8_t direction, - const uint8_t *input, - uint32_t input_len, uint8_t *rdir) +static uint16_t ProbingParserDummyForTesting( + Flow *f, uint8_t direction, const uint8_t *input, uint32_t input_len, uint8_t *rdir) { return 0; } @@ -2984,135 +2894,55 @@ static int AppLayerProtoDetectTest15(void) AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP1, 5, 8, STREAM_TOSERVER, ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "80", - ALPROTO_SMB, - 5, 6, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "80", - ALPROTO_FTP, - 7, 10, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); - - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "81", - ALPROTO_DCERPC, - 9, 10, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "81", - ALPROTO_FTP, - 7, 15, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "0", - ALPROTO_SMTP, - 12, 0, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "0", - ALPROTO_TLS, - 12, 18, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); - - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "85", - ALPROTO_DCERPC, - 9, 10, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "85", - ALPROTO_FTP, - 7, 15, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 0, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); result = 1; - AppLayerProtoDetectPPRegister(IPPROTO_UDP, - "85", - ALPROTO_IMAP, - 12, 23, - STREAM_TOSERVER, - ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "85", ALPROTO_IMAP, 12, 23, STREAM_TOSERVER, + ProbingParserDummyForTesting, NULL); /* toclient */ - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "0", - ALPROTO_JABBER, - 12, 23, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "0", - ALPROTO_IRC, - 12, 14, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "85", - ALPROTO_DCERPC, - 9, 10, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "81", - ALPROTO_FTP, - 7, 15, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "0", - ALPROTO_TLS, - 12, 18, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_JABBER, 12, 23, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_IRC, 12, 14, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP1, 5, 8, STREAM_TOCLIENT, ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "81", - ALPROTO_DCERPC, - 9, 10, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "90", - ALPROTO_FTP, - 7, 15, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "80", - ALPROTO_SMB, - 5, 6, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_UDP, - "85", - ALPROTO_IMAP, - 12, 23, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "0", - ALPROTO_SMTP, - 12, 17, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "80", - ALPROTO_FTP, - 7, 10, - STREAM_TOCLIENT, - ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "90", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "85", ALPROTO_IMAP, 12, 23, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 17, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOCLIENT, + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPTestDataElement element_ts_80[] = { { "http", ALPROTO_HTTP1, 80, 1 << ALPROTO_HTTP1, 5, 8 }, @@ -3134,71 +2964,66 @@ static int AppLayerProtoDetectTest15(void) 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 } - }; + { "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 } }; 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 } - }; + { "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 } }; 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 } - }; + { "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 } }; 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[] = { + { "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 }, - { "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_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 } }; AppLayerProtoDetectPPTestDataElement element_ts_85_udp[] = { { "imap", ALPROTO_IMAP, 85, 1 << ALPROTO_IMAP, 12, 23 }, - }; + }; AppLayerProtoDetectPPTestDataElement element_tc_85_udp[] = { { "imap", ALPROTO_IMAP, 85, 1 << ALPROTO_IMAP, 12, 23 }, - }; + }; AppLayerProtoDetectPPTestDataPort ports_tcp[] = { { @@ -3254,41 +3079,43 @@ static int AppLayerProtoDetectTest15(void) }; 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, + (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), + }, + }; AppLayerProtoDetectPPTestDataIPProto ip_proto[] = { - { IPPROTO_TCP, - ports_tcp, - sizeof(ports_tcp) / sizeof(AppLayerProtoDetectPPTestDataPort), + { + IPPROTO_TCP, + ports_tcp, + sizeof(ports_tcp) / sizeof(AppLayerProtoDetectPPTestDataPort), }, - { IPPROTO_UDP, - ports_udp, - sizeof(ports_udp) / sizeof(AppLayerProtoDetectPPTestDataPort), + { + IPPROTO_UDP, + ports_udp, + sizeof(ports_udp) / sizeof(AppLayerProtoDetectPPTestDataPort), }, }; - if (AppLayerProtoDetectPPTestData(alpd_ctx.ctx_pp, ip_proto, - sizeof(ip_proto) / sizeof(AppLayerProtoDetectPPTestDataIPProto)) == 0) { + sizeof(ip_proto) / sizeof(AppLayerProtoDetectPPTestDataIPProto)) == 0) { goto end; } result = 1; - end: +end: AppLayerProtoDetectDeSetup(); AppLayerProtoDetectUnittestCtxRestore(); return result; } - /** \test test if the engine detect the proto and match with it */ static int AppLayerProtoDetectTest16(void) { @@ -3296,8 +3123,8 @@ static int AppLayerProtoDetectTest16(void) Flow *f = NULL; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; @@ -3327,7 +3154,7 @@ static int AppLayerProtoDetectTest16(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f->alproto = ALPROTO_HTTP1; @@ -3340,8 +3167,8 @@ static int AppLayerProtoDetectTest16(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " - "(msg:\"Test content option\"; " - "sid:1;)"); + "(msg:\"Test content option\"; " + "sid:1;)"); if (s == NULL) { goto end; } @@ -3370,7 +3197,7 @@ static int AppLayerProtoDetectTest16(void) goto end; } result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) @@ -3395,8 +3222,8 @@ static int AppLayerProtoDetectTest17(void) Flow *f = NULL; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; @@ -3419,7 +3246,7 @@ static int AppLayerProtoDetectTest17(void) p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f->alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3431,8 +3258,8 @@ static int AppLayerProtoDetectTest17(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " - "(msg:\"http over non standar port\"; " - "sid:1;)"); + "(msg:\"http over non standar port\"; " + "sid:1;)"); if (s == NULL) { goto end; } @@ -3463,7 +3290,7 @@ static int AppLayerProtoDetectTest17(void) result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) @@ -3488,8 +3315,8 @@ static int AppLayerProtoDetectTest18(void) Flow *f = NULL; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; TcpSession ssn; Packet *p = NULL; @@ -3512,7 +3339,7 @@ static int AppLayerProtoDetectTest18(void) p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f->alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3524,8 +3351,8 @@ static int AppLayerProtoDetectTest18(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ftp any any -> any any " - "(msg:\"Test content option\"; " - "sid:1;)"); + "(msg:\"Test content option\"; " + "sid:1;)"); if (s == NULL) { goto end; } @@ -3555,7 +3382,7 @@ static int AppLayerProtoDetectTest18(void) } result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) @@ -3601,7 +3428,7 @@ static int AppLayerProtoDetectTest19(void) p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f->alproto = ALPROTO_FTP; StreamTcpInitConfig(true); @@ -3613,8 +3440,8 @@ static int AppLayerProtoDetectTest19(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " - "(msg:\"http over non standar port\"; " - "sid:1;)"); + "(msg:\"http over non standar port\"; " + "sid:1;)"); if (s == NULL) { goto end; } @@ -3622,8 +3449,8 @@ static int AppLayerProtoDetectTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_FTP, - STREAM_TOSERVER, http_buf1, http_buf1_len); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_FTP, STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; @@ -3639,7 +3466,7 @@ static int AppLayerProtoDetectTest19(void) result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) diff --git a/src/app-layer-detect-proto.h b/src/app-layer-detect-proto.h index 4ee4bac10ad8..59a87e0306b0 100644 --- a/src/app-layer-detect-proto.h +++ b/src/app-layer-detect-proto.h @@ -62,45 +62,32 @@ int AppLayerProtoDetectPrepareState(void); /***** PP registration *****/ -void AppLayerProtoDetectPPRegister(uint8_t ipproto, - const char *portstr, - AppProto alproto, - uint16_t min_depth, uint16_t max_depth, - uint8_t direction, - ProbingParserFPtr ProbingParser1, - ProbingParserFPtr ProbingParser2); +void AppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, + uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2); /** * \retval bool 0 if no config was found, 1 if config was found */ -int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, - uint8_t ipproto, - const char *alproto_name, - AppProto alproto, - uint16_t min_depth, uint16_t max_depth, - ProbingParserFPtr ProbingParserTs, - ProbingParserFPtr ProbingParserTc); +int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, + const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, + ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc); /***** PM registration *****/ /** * \brief Registers a case-sensitive pattern for protocol detection. */ -int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, - const char *pattern, uint16_t depth, uint16_t offset, - uint8_t direction); +int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, const char *pattern, + uint16_t depth, uint16_t offset, uint8_t direction); int AppLayerProtoDetectPMRegisterPatternCSwPP(uint8_t ipproto, AppProto alproto, - const char *pattern, uint16_t depth, uint16_t offset, - uint8_t direction, - ProbingParserFPtr PPFunc, - uint16_t pp_min_depth, uint16_t pp_max_depth); + const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction, + ProbingParserFPtr PPFunc, uint16_t pp_min_depth, uint16_t pp_max_depth); /** * \brief Registers a case-insensitive pattern for protocol detection. */ -int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, - const char *pattern, - uint16_t depth, uint16_t offset, - uint8_t direction); +int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, + uint16_t depth, uint16_t offset, uint8_t direction); /***** Setup/General Registration *****/ @@ -162,8 +149,7 @@ void AppLayerProtoDetectRegisterAlias(const char *proto_name, const char *proto_ * \retval 1 If enabled. * \retval 0 If disabled. */ -int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, - const char *alproto); +int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto); /** * \brief Given a protocol name, checks if proto detection is enabled in diff --git a/src/app-layer-dnp3-objects.c b/src/app-layer-dnp3-objects.c deleted file mode 100644 index 0bf9cd37bda2..000000000000 --- a/src/app-layer-dnp3-objects.c +++ /dev/null @@ -1,9728 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Jason Ish - * - * This file contains the DNP3 object decoders. - */ - -#include "suricata-common.h" - -#include "app-layer-dnp3.h" -#include "app-layer-dnp3-objects.h" - -void DNP3FreeObjectPoint(int group, int variation, void *point); - -#if 0 -static void DNP3HexDump(uint8_t *data, int len) -{ - for (int i = 0; i < len; i++) { - printf("%02x ", data[i]); - } -} -#endif - -/** - * \brief Allocate a list for DNP3 points. - */ -DNP3PointList *DNP3PointListAlloc(void) -{ - DNP3PointList *items = SCCalloc(1, sizeof(*items)); - if (unlikely(items == NULL)) { - return NULL; - } - TAILQ_INIT(items); - return items; -} - -/** - * \brief Free a DNP3PointList. - */ -void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *list) -{ - DNP3Point *point; - while ((point = TAILQ_FIRST(list)) != NULL) { - TAILQ_REMOVE(list, point, next); - if (point->data != NULL) { - DNP3FreeObjectPoint(group, variation, point->data); - } - SCFree(point); - } - SCFree(list); -} - -/** - * \brief Read an uint8_t from a buffer. - * - * Reads a uint8_t from a buffer advancing the pointer and - * decrementing the length. - * - * \param buf A pointer to the buffer to read from. - * \param len A pointer to the buffer length. - * \param out A pointer to where the value will be stored. - * - * \retval Returns 1 if there was enough space in the buffer to read from, - * otherwise 0 is returned. - */ -static int DNP3ReadUint8(const uint8_t **buf, uint32_t *len, uint8_t *out) -{ - if (*len < (int)sizeof(*out)) { - return 0; - } - *out = *(uint8_t *)(*buf); - *buf += sizeof(*out); - *len -= sizeof(*out); - return 1; -} - -/** - * \brief Read an uint16_t from a buffer. - * - * Reads an uint16_t from a buffer advancing the pointer and - * decrementing the length. - * - * \param buf A pointer to the buffer to read from. - * \param len A pointer to the buffer length. - * \param out A pointer to where the value will be stored. - * - * \retval Returns 1 if there was enough space in the buffer to read from, - * otherwise 0 is returned. - */ -static int DNP3ReadUint16(const uint8_t **buf, uint32_t *len, uint16_t *out) -{ - if (*len < (int)sizeof(*out)) { - return 0; - } - *out = DNP3_SWAP16(*(uint16_t *)(*buf)); - *buf += sizeof(*out); - *len -= sizeof(*out); - return 1; -} - -/** - * \brief Read an unsigned 24 bit integer from a buffer. - * - * Reads an an unsigned 24 bit integer from a buffer advancing the - * pointer and decrementing the length. - * - * \param buf A pointer to the buffer to read from. - * \param len A pointer to the buffer length. - * \param out A pointer to where the value will be stored. - * - * \retval Returns 1 if there was enough space in the buffer to read from, - * otherwise 0 is returned. - */ -static int DNP3ReadUint24(const uint8_t **buf, uint32_t *len, uint32_t *out) -{ - if (*len < (int)(sizeof(uint8_t) * 3)) { - return 0; - } - -#if __BYTE_ORDER__ == __BIG_ENDIAN - *out = ((uint32_t)(*buf)[0] << 16) | ((uint32_t)(*buf)[1] << 8) | - (uint32_t)(*buf)[2]; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | - ((uint64_t)(*buf)[2] << 16); -#endif - - *buf += 3; - *len -= 3; - - return 1; -} - -/** - * \brief Read an uint32_t from a buffer. - * - * Reads an uint32_t from a buffer advancing the pointer and - * decrementing the length. - * - * \param buf A pointer to the buffer to read from. - * \param len A pointer to the buffer length. - * \param out A pointer to where the value will be stored. - * - * \retval Returns 1 if there was enough space in the buffer to read from, - * otherwise 0 is returned. - */ -static int DNP3ReadUint32(const uint8_t **buf, uint32_t *len, uint32_t *out) -{ - if (*len < (int)sizeof(*out)) { - return 0; - } - *out = DNP3_SWAP32(*(uint32_t *)(*buf)); - *buf += sizeof(*out); - *len -= sizeof(*out); - return 1; -} - -/** - * \brief Read an unsigned 48 bit integer from a buffer. - * - * Reads an an unsigned 48 bit integer from a buffer advancing the - * pointer and decrementing the length. - * - * \param buf A pointer to the buffer to read from. - * \param len A pointer to the buffer length. - * \param out A pointer to where the value will be stored. - * - * \retval Returns 1 if there was enough space in the buffer to read from, - * otherwise 0 is returned. - */ -static int DNP3ReadUint48(const uint8_t **buf, uint32_t *len, uint64_t *out) -{ - if (*len < (int)(sizeof(uint8_t) * 6)) { - return 0; - } - -#if __BYTE_ORDER__ == __BIG_ENDIAN - *out = ((uint64_t)(*buf)[0] << 40) | ((uint64_t)(*buf)[1] << 32) | - ((uint64_t)(*buf)[2] << 24) | ((uint64_t)(*buf)[3] << 16) | - ((uint64_t)(*buf)[4] << 8) | (uint64_t)(*buf)[5]; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | - ((uint64_t)(*buf)[2] << 16) | ((uint64_t)(*buf)[3] << 24) | - ((uint64_t)(*buf)[4] << 32) | ((uint64_t)(*buf)[5] << 40); -#endif - - *buf += 6; - *len -= 6; - - return 1; -} - -/** - * \brief Read a 32 bit float from a buffer. - * - * Reads an 32 bit float from a buffer advancing the pointer and - * decrementing the length. - * - * \param buf A pointer to the buffer to read from. - * \param len A pointer to the buffer length. - * \param out A pointer to where the value will be stored. - * - * \retval Returns 1 if there was enough space in the buffer to read from, - * otherwise 0 is returned. - */ -static int DNP3ReadFloat32(const uint8_t **buf, uint32_t *len, float *out) -{ - if (*len < 4) { - return 0; - } - -#if __BYTE_ORDER == __LITTLE_ENDIAN - *((uint8_t *)out + 0) = (*buf)[0]; - *((uint8_t *)out + 1) = (*buf)[1]; - *((uint8_t *)out + 2) = (*buf)[2]; - *((uint8_t *)out + 3) = (*buf)[3]; -#else - *((uint8_t *)out + 3) = (*buf)[0]; - *((uint8_t *)out + 2) = (*buf)[1]; - *((uint8_t *)out + 1) = (*buf)[2]; - *((uint8_t *)out + 0) = (*buf)[3]; -#endif - *len -= 4; - *buf += 4; - - return 1; -} - -/** - * \brief Read a 64 bit float from a buffer. - * - * Reads an 64 bit float from a buffer advancing the pointer and - * decrementing the length. - * - * \param buf A pointer to the buffer to read from. - * \param len A pointer to the buffer length. - * \param out A pointer to where the value will be stored. - * - * \retval Returns 1 if there was enough space in the buffer to read from, - * otherwise 0 is returned. - */ -static int DNP3ReadFloat64(const uint8_t **buf, uint32_t *len, double *out) -{ - if (*len < 8) { - return 0; - } - -#if __BYTE_ORDER == __LITTLE_ENDIAN - *((uint8_t *)out + 0) = (*buf)[0]; - *((uint8_t *)out + 1) = (*buf)[1]; - *((uint8_t *)out + 2) = (*buf)[2]; - *((uint8_t *)out + 3) = (*buf)[3]; - *((uint8_t *)out + 4) = (*buf)[4]; - *((uint8_t *)out + 5) = (*buf)[5]; - *((uint8_t *)out + 6) = (*buf)[6]; - *((uint8_t *)out + 7) = (*buf)[7]; -#else - *((uint8_t *)out + 7) = (*buf)[0]; - *((uint8_t *)out + 6) = (*buf)[1]; - *((uint8_t *)out + 5) = (*buf)[2]; - *((uint8_t *)out + 4) = (*buf)[3]; - *((uint8_t *)out + 3) = (*buf)[4]; - *((uint8_t *)out + 2) = (*buf)[5]; - *((uint8_t *)out + 1) = (*buf)[6]; - *((uint8_t *)out + 0) = (*buf)[7]; -#endif - *len -= 8; - *buf += 8; - - return 1; -} - -/** - * \brief Get the prefix value and advance the buffer. - */ -static int DNP3ReadPrefix( - const uint8_t **buf, uint32_t *len, uint8_t prefix_code, uint32_t *out) -{ - uint8_t prefix_len = 0; - - switch (prefix_code) { - case 0x01: - case 0x04: - prefix_len = 1; - break; - case 0x02: - case 0x05: - prefix_len = 2; - break; - case 0x03: - case 0x06: - prefix_len = 4; - default: - break; - } - - if (*len < (uint32_t)prefix_len) { - return 0; - } - - switch (prefix_len) { - case sizeof(uint32_t): - if (!DNP3ReadUint32(buf, len, out)) { - return 0; - } - break; - case sizeof(uint16_t): { - /* Temp value for strict-aliasing. */ - uint16_t val = 0; - if (!DNP3ReadUint16(buf, len, &val)) { - return 0; - } - *out = val; - break; - } - case sizeof(uint8_t): { - /* Temp value for strict-aliasing. */ - uint8_t val = 0; - if (!DNP3ReadUint8(buf, len, &val)) { - return 0; - } - *out = val; - break; - } - default: - *out = 0; - break; - } - - return 1; -} - -/** - * \brief Add an object to a DNP3PointList. - * - * \retval 1 if successful, 0 on failure. - */ -static int DNP3AddPoint(DNP3PointList *list, void *object, uint32_t point_index, - uint8_t prefix_code, uint32_t prefix) -{ - DNP3Point *point = SCCalloc(1, sizeof(*point)); - if (unlikely(point == NULL)) { - return 0; - } - TAILQ_INSERT_TAIL(list, point, next); - point->data = object; - point->prefix = prefix; - point->index = point_index; - switch (prefix_code) { - case 0x00: - break; - case 0x01: - case 0x02: - case 0x03: - point->index = prefix; - break; - case 0x04: - case 0x05: - case 0x06: - point->size = prefix; - break; - default: - break; - } - - return 1; -} - -/* START GENERATED CODE */ - -/* Code generated by: - * ./scripts/dnp3-gen/dnp3-gen.py - */ - -static int DNP3DecodeObjectG1V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG1V1 *object = NULL; - uint32_t bytes = (count / 8) + 1; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - for (uint32_t i = 0; i < bytes; i++) { - - uint8_t octet; - - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - - for (int j = 0; j < 8 && count; j = j + 1) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - object->state = (octet >> j) & 0x1; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - count--; - point_index++; - } - - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - return 0; -} - -static int DNP3DecodeObjectG1V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG1V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->chatter_filter = (octet >> 5) & 0x1; - object->reserved = (octet >> 6) & 0x1; - object->state = (octet >> 7) & 0x1; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG2V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG2V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint8(buf, len, &object->state)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG2V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG2V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->chatter_filter = (octet >> 5) & 0x1; - object->reserved = (octet >> 6) & 0x1; - object->state = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG2V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG2V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->chatter_filter = (octet >> 5) & 0x1; - object->reserved = (octet >> 6) & 0x1; - object->state = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG3V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG3V1 *object = NULL; - uint32_t bytes = (count / 8) + 1; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - for (uint32_t i = 0; i < bytes; i++) { - - uint8_t octet; - - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - - for (int j = 0; j < 8 && count; j = j + 2) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - object->state = (octet >> j) & 0x3; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - count--; - point_index++; - } - - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - return 0; -} - -static int DNP3DecodeObjectG3V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG3V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->chatter_filter = (octet >> 5) & 0x1; - object->state = (octet >> 6) & 0x3; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG4V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG4V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->chatter_filter = (octet >> 5) & 0x1; - object->state = (octet >> 6) & 0x3; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG4V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG4V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->chatter_filter = (octet >> 5) & 0x1; - object->state = (octet >> 6) & 0x3; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG4V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG4V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->chatter_filter = (octet >> 5) & 0x1; - object->state = (octet >> 6) & 0x3; - } - if (!DNP3ReadUint16(buf, len, &object->relative_time_ms)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG10V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG10V1 *object = NULL; - uint32_t bytes = (count / 8) + 1; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - for (uint32_t i = 0; i < bytes; i++) { - - uint8_t octet; - - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - - for (int j = 0; j < 8 && count; j = j + 1) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - object->state = (octet >> j) & 0x1; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - count--; - point_index++; - } - - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - return 0; -} - -static int DNP3DecodeObjectG10V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG10V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->reserved0 = (octet >> 5) & 0x1; - object->reserved1 = (octet >> 6) & 0x1; - object->state = (octet >> 7) & 0x1; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG11V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG11V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->reserved0 = (octet >> 5) & 0x1; - object->reserved1 = (octet >> 6) & 0x1; - object->state = (octet >> 7) & 0x1; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG11V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG11V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->reserved0 = (octet >> 5) & 0x1; - object->reserved1 = (octet >> 6) & 0x1; - object->state = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG12V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG12V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->op_type = (octet >> 0) & 0xf; - object->qu = (octet >> 4) & 0x1; - object->cr = (octet >> 5) & 0x1; - object->tcc = (octet >> 6) & 0x3; - } - if (!DNP3ReadUint8(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->ontime)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->offtime)) { - goto error; - } - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved = (octet >> 7) & 0x1; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG12V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG12V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->op_type = (octet >> 0) & 0xf; - object->qu = (octet >> 4) & 0x1; - object->cr = (octet >> 5) & 0x1; - object->tcc = (octet >> 6) & 0x3; - } - if (!DNP3ReadUint8(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->ontime)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->offtime)) { - goto error; - } - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved = (octet >> 7) & 0x1; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG12V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG12V3 *object = NULL; - uint32_t bytes = (count / 8) + 1; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - for (uint32_t i = 0; i < bytes; i++) { - - uint8_t octet; - - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - - for (int j = 0; j < 8 && count; j = j + 1) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - object->point = (octet >> j) & 0x1; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - count--; - point_index++; - } - - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - return 0; -} - -static int DNP3DecodeObjectG13V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG13V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->commanded_state = (octet >> 7) & 0x1; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG13V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG13V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->commanded_state = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG20V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG20V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V9(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V9 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V10(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V10 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V11(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V11 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG21V12(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG21V12 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG22V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG22V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG23V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG23V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->rollover = (octet >> 5) & 0x1; - object->reserved0 = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->count)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG30V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG30V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG30V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG30V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG30V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG30V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG30V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG30V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG30V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG30V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG30V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG30V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG31V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG31V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG32V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG32V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG33V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG33V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG34V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG34V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->deadband_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG34V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG34V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->deadband_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG34V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG34V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadFloat32(buf, len, &object->deadband_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG40V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG40V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG40V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG40V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG40V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG40V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG40V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG40V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG41V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG41V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->control_status)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG41V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG41V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->control_status)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG41V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG41V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->control_status)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG41V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG41V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->control_status)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG42V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG42V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->over_range = (octet >> 5) & 0x1; - object->reference_err = (octet >> 6) & 0x1; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG43V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG43V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->status_code = (octet >> 0) & 0x7f; - object->reserved0 = (octet >> 7) & 0x1; - } - if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG50V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG50V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG50V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG50V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->interval)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG50V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG50V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG50V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG50V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->interval_count)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->interval_units)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG51V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG51V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG51V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG51V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG52V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG52V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->delay_secs)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG52V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG52V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->delay_ms)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->filename_size)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->filetype_code)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->attribute_code)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->start_record)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->end_record)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->file_size)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->permission)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->file_id)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->owner_id)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->group_id)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->file_function_code)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->status_code)) { - goto error; - } - if (object->filename_size > 0) { - if (*len < object->filename_size) { - /* Not enough data. */ - goto error; - } - memcpy(object->filename, *buf, object->filename_size); - *buf += object->filename_size; - *len -= object->filename_size; - } - object->filename[object->filename_size] = '\0'; - if (!DNP3ReadUint16(buf, len, &object->data_size)) { - goto error; - } - if (object->data_size > 0) { - if (*len < object->data_size) { - /* Not enough data. */ - goto error; - } - memcpy(object->data, *buf, object->data_size); - *buf += object->data_size; - *len -= object->data_size; - } - object->data[object->data_size] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->username_offset)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->username_size)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->password_offset)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->password_size)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { - goto error; - } - if (object->username_size > 0) { - if (*len < object->username_size) { - /* Not enough data. */ - goto error; - } - memcpy(object->username, *buf, object->username_size); - *buf += object->username_size; - *len -= object->username_size; - } - object->username[object->username_size] = '\0'; - if (object->password_size > 0) { - if (*len < object->password_size) { - /* Not enough data. */ - goto error; - } - memcpy(object->password, *buf, object->password_size); - *buf += object->password_size; - *len -= object->password_size; - } - object->password[object->password_size] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->filename_size)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->created)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->permissions)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->file_size)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->operational_mode)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->request_id)) { - goto error; - } - if (object->filename_size > 0) { - if (*len < object->filename_size) { - /* Not enough data. */ - goto error; - } - memcpy(object->filename, *buf, object->filename_size); - *buf += object->filename_size; - *len -= object->filename_size; - } - object->filename[object->filename_size] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (!DNP3PrefixIsSize(prefix_code)) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint32(buf, len, &object->file_handle)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->file_size)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->request_id)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->status_code)) { - goto error; - } - if (prefix - (offset - *len) >= 255 || prefix < (offset - *len)) { - goto error; - } - object->optional_text_len = (uint8_t)(prefix - (offset - *len)); - if (object->optional_text_len > 0) { - if (*len < object->optional_text_len) { - /* Not enough data. */ - goto error; - } - memcpy(object->optional_text, *buf, object->optional_text_len); - *buf += object->optional_text_len; - *len -= object->optional_text_len; - } - object->optional_text[object->optional_text_len] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (!DNP3PrefixIsSize(prefix_code)) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint32(buf, len, &object->file_handle)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->block_number)) { - goto error; - } - if (prefix - (offset - *len) >= 255 || prefix < (offset - *len)) { - goto error; - } - object->file_data_len = (uint8_t)(prefix - (offset - *len)); - if (object->file_data_len > 0) { - if (*len < object->file_data_len) { - /* Not enough data. */ - goto error; - } - memcpy(object->file_data, *buf, object->file_data_len); - *buf += object->file_data_len; - *len -= object->file_data_len; - } - object->file_data[object->file_data_len] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (!DNP3PrefixIsSize(prefix_code)) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint32(buf, len, &object->file_handle)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->block_number)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->status_code)) { - goto error; - } - if (prefix - (offset - *len) >= 255 || prefix < (offset - *len)) { - goto error; - } - object->optional_text_len = (uint8_t)(prefix - (offset - *len)); - if (object->optional_text_len > 0) { - if (*len < object->optional_text_len) { - /* Not enough data. */ - goto error; - } - memcpy(object->optional_text, *buf, object->optional_text_len); - *buf += object->optional_text_len; - *len -= object->optional_text_len; - } - object->optional_text[object->optional_text_len] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->filename_size)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->file_type)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->file_size)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->permissions)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->request_id)) { - goto error; - } - if (object->filename_size > 0) { - if (*len < object->filename_size) { - /* Not enough data. */ - goto error; - } - memcpy(object->filename, *buf, object->filename_size); - *buf += object->filename_size; - *len -= object->filename_size; - } - object->filename[object->filename_size] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG70V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG70V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (prefix - (offset - *len) >= 65535 || prefix < (offset - *len)) { - goto error; - } - object->file_specification_len = (uint16_t)(prefix - (offset - *len)); - if (object->file_specification_len > 0) { - if (*len < object->file_specification_len) { - /* Not enough data. */ - goto error; - } - memcpy(object->file_specification, *buf, object->file_specification_len); - *buf += object->file_specification_len; - *len -= object->file_specification_len; - } - object->file_specification[object->file_specification_len] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG80V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG80V1 *object = NULL; - uint32_t bytes = (count / 8) + 1; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - for (uint32_t i = 0; i < bytes; i++) { - - uint8_t octet; - - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - - for (int j = 0; j < 8 && count; j = j + 1) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - object->state = (octet >> j) & 0x1; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - count--; - point_index++; - } - - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - return 0; -} - -static int DNP3DecodeObjectG81V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG81V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->fill_percentage = (octet >> 0) & 0x7f; - object->overflow_state = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint8(buf, len, &object->group)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->variation)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG83V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG83V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (*len < 4) { - goto error; - } - memcpy(object->vendor_code, *buf, 4); - object->vendor_code[4] = '\0'; - *buf += 4; - *len -= 4; - if (!DNP3ReadUint16(buf, len, &object->object_id)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->length)) { - goto error; - } - if (object->length > 0) { - if (*len < object->length) { - /* Not enough data. */ - goto error; - } - object->data_objects = SCCalloc(1, object->length); - if (unlikely(object->data_objects == NULL)) { - goto error; - } - memcpy(object->data_objects, *buf, object->length); - *buf += object->length; - *len -= object->length; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->data_objects != NULL) { - SCFree(object->data_objects); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG86V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG86V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->rd = (octet >> 0) & 0x1; - object->wr = (octet >> 1) & 0x1; - object->st = (octet >> 2) & 0x1; - object->ev = (octet >> 3) & 0x1; - object->df = (octet >> 4) & 0x1; - object->padding0 = (octet >> 5) & 0x1; - object->padding1 = (octet >> 6) & 0x1; - object->padding2 = (octet >> 7) & 0x1; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG102V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG102V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint8(buf, len, &object->value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint32(buf, len, &object->csq)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->usr)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->mal)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->reason)) { - goto error; - } - if (prefix < (offset - *len)) { - goto error; - } - object->challenge_data_len = (uint16_t)(prefix - (offset - *len)); - if (object->challenge_data_len > 0) { - if (*len < object->challenge_data_len) { - /* Not enough data. */ - goto error; - } - object->challenge_data = SCCalloc(1, object->challenge_data_len); - if (unlikely(object->challenge_data == NULL)) { - goto error; - } - memcpy(object->challenge_data, *buf, object->challenge_data_len); - *buf += object->challenge_data_len; - *len -= object->challenge_data_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->challenge_data != NULL) { - SCFree(object->challenge_data); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint32(buf, len, &object->csq)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->usr)) { - goto error; - } - if (prefix < (offset - *len)) { - goto error; - } - object->mac_value_len = (uint16_t)(prefix - (offset - *len)); - if (object->mac_value_len > 0) { - if (*len < object->mac_value_len) { - /* Not enough data. */ - goto error; - } - object->mac_value = SCCalloc(1, object->mac_value_len); - if (unlikely(object->mac_value == NULL)) { - goto error; - } - memcpy(object->mac_value, *buf, object->mac_value_len); - *buf += object->mac_value_len; - *len -= object->mac_value_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->mac_value != NULL) { - SCFree(object->mac_value); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V3(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V3 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->csq)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->user_number)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V4(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V4 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint16(buf, len, &object->user_number)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V5(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V5 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint32(buf, len, &object->ksq)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->user_number)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->key_wrap_alg)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->key_status)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->mal)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { - goto error; - } - if (object->challenge_data_len > 0) { - if (*len < object->challenge_data_len) { - /* Not enough data. */ - goto error; - } - object->challenge_data = SCCalloc(1, object->challenge_data_len); - if (unlikely(object->challenge_data == NULL)) { - goto error; - } - memcpy(object->challenge_data, *buf, object->challenge_data_len); - *buf += object->challenge_data_len; - *len -= object->challenge_data_len; - } - if (prefix < (offset - *len)) { - goto error; - } - object->mac_value_len = (uint16_t)(prefix - (offset - *len)); - if (object->mac_value_len > 0) { - if (*len < object->mac_value_len) { - /* Not enough data. */ - goto error; - } - object->mac_value = SCCalloc(1, object->mac_value_len); - if (unlikely(object->mac_value == NULL)) { - goto error; - } - memcpy(object->mac_value, *buf, object->mac_value_len); - *buf += object->mac_value_len; - *len -= object->mac_value_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->challenge_data != NULL) { - SCFree(object->challenge_data); - } - if (object->mac_value != NULL) { - SCFree(object->mac_value); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V6(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V6 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint24(buf, len, &object->ksq)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->usr)) { - goto error; - } - if (prefix < (offset - *len)) { - goto error; - } - object->wrapped_key_data_len = (uint16_t)(prefix - (offset - *len)); - if (object->wrapped_key_data_len > 0) { - if (*len < object->wrapped_key_data_len) { - /* Not enough data. */ - goto error; - } - object->wrapped_key_data = SCCalloc(1, object->wrapped_key_data_len); - if (unlikely(object->wrapped_key_data == NULL)) { - goto error; - } - memcpy(object->wrapped_key_data, *buf, object->wrapped_key_data_len); - *buf += object->wrapped_key_data_len; - *len -= object->wrapped_key_data_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->wrapped_key_data != NULL) { - SCFree(object->wrapped_key_data); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V7(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V7 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint32(buf, len, &object->sequence_number)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->usr)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->association_id)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->error_code)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->time_of_error)) { - goto error; - } - if (prefix - (offset - *len) >= 65535 || prefix < (offset - *len)) { - goto error; - } - object->error_text_len = (uint16_t)(prefix - (offset - *len)); - if (object->error_text_len > 0) { - if (*len < object->error_text_len) { - /* Not enough data. */ - goto error; - } - memcpy(object->error_text, *buf, object->error_text_len); - *buf += object->error_text_len; - *len -= object->error_text_len; - } - object->error_text[object->error_text_len] = '\0'; - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V8(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V8 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->certificate_type)) { - goto error; - } - if (prefix < (offset - *len)) { - goto error; - } - object->certificate_len = (uint16_t)(prefix - (offset - *len)); - if (object->certificate_len > 0) { - if (*len < object->certificate_len) { - /* Not enough data. */ - goto error; - } - object->certificate = SCCalloc(1, object->certificate_len); - if (unlikely(object->certificate == NULL)) { - goto error; - } - memcpy(object->certificate, *buf, object->certificate_len); - *buf += object->certificate_len; - *len -= object->certificate_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->certificate != NULL) { - SCFree(object->certificate); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V9(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V9 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (prefix < (offset - *len)) { - goto error; - } - object->mac_value_len = (uint16_t)(prefix - (offset - *len)); - if (object->mac_value_len > 0) { - if (*len < object->mac_value_len) { - /* Not enough data. */ - goto error; - } - object->mac_value = SCCalloc(1, object->mac_value_len); - if (unlikely(object->mac_value == NULL)) { - goto error; - } - memcpy(object->mac_value, *buf, object->mac_value_len); - *buf += object->mac_value_len; - *len -= object->mac_value_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->mac_value != NULL) { - SCFree(object->mac_value); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V10(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V10 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { - goto error; - } - if (!DNP3ReadUint8(buf, len, &object->operation)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->scs)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->user_role)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->user_role_expiry_interval)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->username_len)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->user_public_key_len)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->certification_data_len)) { - goto error; - } - if (object->username_len > 0) { - if (*len < object->username_len) { - /* Not enough data. */ - goto error; - } - memcpy(object->username, *buf, object->username_len); - *buf += object->username_len; - *len -= object->username_len; - } - object->username[object->username_len] = '\0'; - if (object->user_public_key_len > 0) { - if (*len < object->user_public_key_len) { - /* Not enough data. */ - goto error; - } - object->user_public_key = SCCalloc(1, object->user_public_key_len); - if (unlikely(object->user_public_key == NULL)) { - goto error; - } - memcpy(object->user_public_key, *buf, object->user_public_key_len); - *buf += object->user_public_key_len; - *len -= object->user_public_key_len; - } - if (object->certification_data_len > 0) { - if (*len < object->certification_data_len) { - /* Not enough data. */ - goto error; - } - object->certification_data = SCCalloc(1, object->certification_data_len); - if (unlikely(object->certification_data == NULL)) { - goto error; - } - memcpy(object->certification_data, *buf, object->certification_data_len); - *buf += object->certification_data_len; - *len -= object->certification_data_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->user_public_key != NULL) { - SCFree(object->user_public_key); - } - if (object->certification_data != NULL) { - SCFree(object->certification_data); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V11(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V11 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->username_len)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->master_challenge_data_len)) { - goto error; - } - if (object->username_len > 0) { - if (*len < object->username_len) { - /* Not enough data. */ - goto error; - } - memcpy(object->username, *buf, object->username_len); - *buf += object->username_len; - *len -= object->username_len; - } - object->username[object->username_len] = '\0'; - if (object->master_challenge_data_len > 0) { - if (*len < object->master_challenge_data_len) { - /* Not enough data. */ - goto error; - } - object->master_challenge_data = SCCalloc(1, object->master_challenge_data_len); - if (unlikely(object->master_challenge_data == NULL)) { - goto error; - } - memcpy(object->master_challenge_data, *buf, object->master_challenge_data_len); - *buf += object->master_challenge_data_len; - *len -= object->master_challenge_data_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->master_challenge_data != NULL) { - SCFree(object->master_challenge_data); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V12(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V12 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->ksq)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->user_number)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { - goto error; - } - if (object->challenge_data_len > 0) { - if (*len < object->challenge_data_len) { - /* Not enough data. */ - goto error; - } - object->challenge_data = SCCalloc(1, object->challenge_data_len); - if (unlikely(object->challenge_data == NULL)) { - goto error; - } - memcpy(object->challenge_data, *buf, object->challenge_data_len); - *buf += object->challenge_data_len; - *len -= object->challenge_data_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->challenge_data != NULL) { - SCFree(object->challenge_data); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V13(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V13 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - if (!DNP3ReadUint32(buf, len, &object->ksq)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->user_number)) { - goto error; - } - if (!DNP3ReadUint16(buf, len, &object->encrypted_update_key_len)) { - goto error; - } - if (object->encrypted_update_key_len > 0) { - if (*len < object->encrypted_update_key_len) { - /* Not enough data. */ - goto error; - } - object->encrypted_update_key_data = SCCalloc(1, object->encrypted_update_key_len); - if (unlikely(object->encrypted_update_key_data == NULL)) { - goto error; - } - memcpy(object->encrypted_update_key_data, *buf, object->encrypted_update_key_len); - *buf += object->encrypted_update_key_len; - *len -= object->encrypted_update_key_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->encrypted_update_key_data != NULL) { - SCFree(object->encrypted_update_key_data); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V14(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V14 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (prefix < (offset - *len)) { - goto error; - } - object->digital_signature_len = (uint16_t)(prefix - (offset - *len)); - if (object->digital_signature_len > 0) { - if (*len < object->digital_signature_len) { - /* Not enough data. */ - goto error; - } - object->digital_signature = SCCalloc(1, object->digital_signature_len); - if (unlikely(object->digital_signature == NULL)) { - goto error; - } - memcpy(object->digital_signature, *buf, object->digital_signature_len); - *buf += object->digital_signature_len; - *len -= object->digital_signature_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->digital_signature != NULL) { - SCFree(object->digital_signature); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG120V15(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG120V15 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - uint32_t offset; - - if (prefix_code != 5) { - goto error; - } - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - offset = *len; - - if (prefix < (offset - *len)) { - goto error; - } - object->mac_len = (uint16_t)(prefix - (offset - *len)); - if (object->mac_len > 0) { - if (*len < object->mac_len) { - /* Not enough data. */ - goto error; - } - object->mac = SCCalloc(1, object->mac_len); - if (unlikely(object->mac == NULL)) { - goto error; - } - memcpy(object->mac, *buf, object->mac_len); - *buf += object->mac_len; - *len -= object->mac_len; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - if (object->mac != NULL) { - SCFree(object->mac); - } - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG121V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG121V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->reserved0 = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->association_id)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->count_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG122V1(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG122V1 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->reserved0 = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->association_id)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->count_value)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - -static int DNP3DecodeObjectG122V2(const uint8_t **buf, uint32_t *len, - uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *points) -{ - DNP3ObjectG122V2 *object = NULL; - uint32_t prefix = 0; - uint32_t point_index = start; - - if (*len < count/8) { - goto error; - } - while (count--) { - - object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - goto error; - } - - if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { - goto error; - } - - { - uint8_t octet; - if (!DNP3ReadUint8(buf, len, &octet)) { - goto error; - } - object->online = (octet >> 0) & 0x1; - object->restart = (octet >> 1) & 0x1; - object->comm_lost = (octet >> 2) & 0x1; - object->remote_forced = (octet >> 3) & 0x1; - object->local_forced = (octet >> 4) & 0x1; - object->reserved0 = (octet >> 5) & 0x1; - object->discontinuity = (octet >> 6) & 0x1; - object->reserved1 = (octet >> 7) & 0x1; - } - if (!DNP3ReadUint16(buf, len, &object->association_id)) { - goto error; - } - if (!DNP3ReadUint32(buf, len, &object->count_value)) { - goto error; - } - if (!DNP3ReadUint48(buf, len, &object->timestamp)) { - goto error; - } - - if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { - goto error; - } - - object = NULL; - point_index++; - } - - return 1; -error: - if (object != NULL) { - SCFree(object); - } - - return 0; -} - - -void DNP3FreeObjectPoint(int group, int variation, void *point) -{ - switch(DNP3_OBJECT_CODE(group, variation)) { - case DNP3_OBJECT_CODE(83, 1): { - DNP3ObjectG83V1 *object = (DNP3ObjectG83V1 *) point; - if (object->data_objects != NULL) { - SCFree(object->data_objects); - } - break; - } - case DNP3_OBJECT_CODE(120, 1): { - DNP3ObjectG120V1 *object = (DNP3ObjectG120V1 *) point; - if (object->challenge_data != NULL) { - SCFree(object->challenge_data); - } - break; - } - case DNP3_OBJECT_CODE(120, 2): { - DNP3ObjectG120V2 *object = (DNP3ObjectG120V2 *) point; - if (object->mac_value != NULL) { - SCFree(object->mac_value); - } - break; - } - case DNP3_OBJECT_CODE(120, 5): { - DNP3ObjectG120V5 *object = (DNP3ObjectG120V5 *) point; - if (object->challenge_data != NULL) { - SCFree(object->challenge_data); - } - if (object->mac_value != NULL) { - SCFree(object->mac_value); - } - break; - } - case DNP3_OBJECT_CODE(120, 6): { - DNP3ObjectG120V6 *object = (DNP3ObjectG120V6 *) point; - if (object->wrapped_key_data != NULL) { - SCFree(object->wrapped_key_data); - } - break; - } - case DNP3_OBJECT_CODE(120, 8): { - DNP3ObjectG120V8 *object = (DNP3ObjectG120V8 *) point; - if (object->certificate != NULL) { - SCFree(object->certificate); - } - break; - } - case DNP3_OBJECT_CODE(120, 9): { - DNP3ObjectG120V9 *object = (DNP3ObjectG120V9 *) point; - if (object->mac_value != NULL) { - SCFree(object->mac_value); - } - break; - } - case DNP3_OBJECT_CODE(120, 10): { - DNP3ObjectG120V10 *object = (DNP3ObjectG120V10 *) point; - if (object->user_public_key != NULL) { - SCFree(object->user_public_key); - } - if (object->certification_data != NULL) { - SCFree(object->certification_data); - } - break; - } - case DNP3_OBJECT_CODE(120, 11): { - DNP3ObjectG120V11 *object = (DNP3ObjectG120V11 *) point; - if (object->master_challenge_data != NULL) { - SCFree(object->master_challenge_data); - } - break; - } - case DNP3_OBJECT_CODE(120, 12): { - DNP3ObjectG120V12 *object = (DNP3ObjectG120V12 *) point; - if (object->challenge_data != NULL) { - SCFree(object->challenge_data); - } - break; - } - case DNP3_OBJECT_CODE(120, 13): { - DNP3ObjectG120V13 *object = (DNP3ObjectG120V13 *) point; - if (object->encrypted_update_key_data != NULL) { - SCFree(object->encrypted_update_key_data); - } - break; - } - case DNP3_OBJECT_CODE(120, 14): { - DNP3ObjectG120V14 *object = (DNP3ObjectG120V14 *) point; - if (object->digital_signature != NULL) { - SCFree(object->digital_signature); - } - break; - } - case DNP3_OBJECT_CODE(120, 15): { - DNP3ObjectG120V15 *object = (DNP3ObjectG120V15 *) point; - if (object->mac != NULL) { - SCFree(object->mac); - } - break; - } - default: - break; - } - SCFree(point); -} - -/** - * \brief Decode a DNP3 object. - * - * \retval 0 on success. On failure a positive integer corresponding - * to a DNP3 application layer event will be returned. - */ -int DNP3DecodeObject(int group, int variation, const uint8_t **buf, - uint32_t *len, uint8_t prefix_code, uint32_t start, - uint32_t count, DNP3PointList *points) -{ - int rc = 0; - - switch (DNP3_OBJECT_CODE(group, variation)) { - case DNP3_OBJECT_CODE(1, 1): - rc = DNP3DecodeObjectG1V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(1, 2): - rc = DNP3DecodeObjectG1V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(2, 1): - rc = DNP3DecodeObjectG2V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(2, 2): - rc = DNP3DecodeObjectG2V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(2, 3): - rc = DNP3DecodeObjectG2V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(3, 1): - rc = DNP3DecodeObjectG3V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(3, 2): - rc = DNP3DecodeObjectG3V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(4, 1): - rc = DNP3DecodeObjectG4V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(4, 2): - rc = DNP3DecodeObjectG4V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(4, 3): - rc = DNP3DecodeObjectG4V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(10, 1): - rc = DNP3DecodeObjectG10V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(10, 2): - rc = DNP3DecodeObjectG10V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(11, 1): - rc = DNP3DecodeObjectG11V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(11, 2): - rc = DNP3DecodeObjectG11V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(12, 1): - rc = DNP3DecodeObjectG12V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(12, 2): - rc = DNP3DecodeObjectG12V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(12, 3): - rc = DNP3DecodeObjectG12V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(13, 1): - rc = DNP3DecodeObjectG13V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(13, 2): - rc = DNP3DecodeObjectG13V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 1): - rc = DNP3DecodeObjectG20V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 2): - rc = DNP3DecodeObjectG20V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 3): - rc = DNP3DecodeObjectG20V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 4): - rc = DNP3DecodeObjectG20V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 5): - rc = DNP3DecodeObjectG20V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 6): - rc = DNP3DecodeObjectG20V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 7): - rc = DNP3DecodeObjectG20V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(20, 8): - rc = DNP3DecodeObjectG20V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 1): - rc = DNP3DecodeObjectG21V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 2): - rc = DNP3DecodeObjectG21V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 3): - rc = DNP3DecodeObjectG21V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 4): - rc = DNP3DecodeObjectG21V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 5): - rc = DNP3DecodeObjectG21V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 6): - rc = DNP3DecodeObjectG21V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 7): - rc = DNP3DecodeObjectG21V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 8): - rc = DNP3DecodeObjectG21V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 9): - rc = DNP3DecodeObjectG21V9(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 10): - rc = DNP3DecodeObjectG21V10(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 11): - rc = DNP3DecodeObjectG21V11(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(21, 12): - rc = DNP3DecodeObjectG21V12(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 1): - rc = DNP3DecodeObjectG22V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 2): - rc = DNP3DecodeObjectG22V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 3): - rc = DNP3DecodeObjectG22V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 4): - rc = DNP3DecodeObjectG22V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 5): - rc = DNP3DecodeObjectG22V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 6): - rc = DNP3DecodeObjectG22V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 7): - rc = DNP3DecodeObjectG22V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(22, 8): - rc = DNP3DecodeObjectG22V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 1): - rc = DNP3DecodeObjectG23V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 2): - rc = DNP3DecodeObjectG23V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 3): - rc = DNP3DecodeObjectG23V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 4): - rc = DNP3DecodeObjectG23V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 5): - rc = DNP3DecodeObjectG23V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 6): - rc = DNP3DecodeObjectG23V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 7): - rc = DNP3DecodeObjectG23V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(23, 8): - rc = DNP3DecodeObjectG23V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(30, 1): - rc = DNP3DecodeObjectG30V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(30, 2): - rc = DNP3DecodeObjectG30V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(30, 3): - rc = DNP3DecodeObjectG30V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(30, 4): - rc = DNP3DecodeObjectG30V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(30, 5): - rc = DNP3DecodeObjectG30V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(30, 6): - rc = DNP3DecodeObjectG30V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 1): - rc = DNP3DecodeObjectG31V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 2): - rc = DNP3DecodeObjectG31V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 3): - rc = DNP3DecodeObjectG31V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 4): - rc = DNP3DecodeObjectG31V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 5): - rc = DNP3DecodeObjectG31V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 6): - rc = DNP3DecodeObjectG31V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 7): - rc = DNP3DecodeObjectG31V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(31, 8): - rc = DNP3DecodeObjectG31V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 1): - rc = DNP3DecodeObjectG32V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 2): - rc = DNP3DecodeObjectG32V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 3): - rc = DNP3DecodeObjectG32V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 4): - rc = DNP3DecodeObjectG32V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 5): - rc = DNP3DecodeObjectG32V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 6): - rc = DNP3DecodeObjectG32V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 7): - rc = DNP3DecodeObjectG32V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(32, 8): - rc = DNP3DecodeObjectG32V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 1): - rc = DNP3DecodeObjectG33V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 2): - rc = DNP3DecodeObjectG33V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 3): - rc = DNP3DecodeObjectG33V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 4): - rc = DNP3DecodeObjectG33V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 5): - rc = DNP3DecodeObjectG33V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 6): - rc = DNP3DecodeObjectG33V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 7): - rc = DNP3DecodeObjectG33V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(33, 8): - rc = DNP3DecodeObjectG33V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(34, 1): - rc = DNP3DecodeObjectG34V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(34, 2): - rc = DNP3DecodeObjectG34V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(34, 3): - rc = DNP3DecodeObjectG34V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(40, 1): - rc = DNP3DecodeObjectG40V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(40, 2): - rc = DNP3DecodeObjectG40V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(40, 3): - rc = DNP3DecodeObjectG40V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(40, 4): - rc = DNP3DecodeObjectG40V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(41, 1): - rc = DNP3DecodeObjectG41V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(41, 2): - rc = DNP3DecodeObjectG41V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(41, 3): - rc = DNP3DecodeObjectG41V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(41, 4): - rc = DNP3DecodeObjectG41V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 1): - rc = DNP3DecodeObjectG42V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 2): - rc = DNP3DecodeObjectG42V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 3): - rc = DNP3DecodeObjectG42V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 4): - rc = DNP3DecodeObjectG42V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 5): - rc = DNP3DecodeObjectG42V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 6): - rc = DNP3DecodeObjectG42V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 7): - rc = DNP3DecodeObjectG42V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(42, 8): - rc = DNP3DecodeObjectG42V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 1): - rc = DNP3DecodeObjectG43V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 2): - rc = DNP3DecodeObjectG43V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 3): - rc = DNP3DecodeObjectG43V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 4): - rc = DNP3DecodeObjectG43V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 5): - rc = DNP3DecodeObjectG43V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 6): - rc = DNP3DecodeObjectG43V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 7): - rc = DNP3DecodeObjectG43V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(43, 8): - rc = DNP3DecodeObjectG43V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(50, 1): - rc = DNP3DecodeObjectG50V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(50, 2): - rc = DNP3DecodeObjectG50V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(50, 3): - rc = DNP3DecodeObjectG50V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(50, 4): - rc = DNP3DecodeObjectG50V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(51, 1): - rc = DNP3DecodeObjectG51V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(51, 2): - rc = DNP3DecodeObjectG51V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(52, 1): - rc = DNP3DecodeObjectG52V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(52, 2): - rc = DNP3DecodeObjectG52V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 1): - rc = DNP3DecodeObjectG70V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 2): - rc = DNP3DecodeObjectG70V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 3): - rc = DNP3DecodeObjectG70V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 4): - rc = DNP3DecodeObjectG70V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 5): - rc = DNP3DecodeObjectG70V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 6): - rc = DNP3DecodeObjectG70V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 7): - rc = DNP3DecodeObjectG70V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(70, 8): - rc = DNP3DecodeObjectG70V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(80, 1): - rc = DNP3DecodeObjectG80V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(81, 1): - rc = DNP3DecodeObjectG81V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(83, 1): - rc = DNP3DecodeObjectG83V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(86, 2): - rc = DNP3DecodeObjectG86V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(102, 1): - rc = DNP3DecodeObjectG102V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 1): - rc = DNP3DecodeObjectG120V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 2): - rc = DNP3DecodeObjectG120V2(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 3): - rc = DNP3DecodeObjectG120V3(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 4): - rc = DNP3DecodeObjectG120V4(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 5): - rc = DNP3DecodeObjectG120V5(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 6): - rc = DNP3DecodeObjectG120V6(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 7): - rc = DNP3DecodeObjectG120V7(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 8): - rc = DNP3DecodeObjectG120V8(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 9): - rc = DNP3DecodeObjectG120V9(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 10): - rc = DNP3DecodeObjectG120V10(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 11): - rc = DNP3DecodeObjectG120V11(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 12): - rc = DNP3DecodeObjectG120V12(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 13): - rc = DNP3DecodeObjectG120V13(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 14): - rc = DNP3DecodeObjectG120V14(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(120, 15): - rc = DNP3DecodeObjectG120V15(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(121, 1): - rc = DNP3DecodeObjectG121V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(122, 1): - rc = DNP3DecodeObjectG122V1(buf, len, prefix_code, start, count, - points); - break; - case DNP3_OBJECT_CODE(122, 2): - rc = DNP3DecodeObjectG122V2(buf, len, prefix_code, start, count, - points); - break; - default: - return DNP3_DECODER_EVENT_UNKNOWN_OBJECT; - } - - return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED; -} - -/* END GENERATED CODE */ diff --git a/src/app-layer-dnp3-objects.h b/src/app-layer-dnp3-objects.h deleted file mode 100644 index e292f012758b..000000000000 --- a/src/app-layer-dnp3-objects.h +++ /dev/null @@ -1,1464 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Jason Ish - * - * This file contains the types (definitions) of the DNP3 objects. - */ - -#ifndef __APP_LAYER_DNP3_OBJECTS_H__ -#define __APP_LAYER_DNP3_OBJECTS_H__ - -#define DNP3_OBJECT_CODE(group, variation) (group << 8 | variation) - -/* START GENERATED CODE */ - -/* Code generated by: - * ./scripts/dnp3-gen/dnp3-gen.py - */ - -typedef struct DNP3ObjectG1V1_ { - uint8_t state; -} DNP3ObjectG1V1; - -typedef struct DNP3ObjectG1V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t chatter_filter:1; - uint8_t reserved:1; - uint8_t state:1; -} DNP3ObjectG1V2; - -typedef struct DNP3ObjectG2V1_ { - uint8_t state; -} DNP3ObjectG2V1; - -typedef struct DNP3ObjectG2V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t chatter_filter:1; - uint8_t reserved:1; - uint8_t state:1; - uint64_t timestamp; -} DNP3ObjectG2V2; - -typedef struct DNP3ObjectG2V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t chatter_filter:1; - uint8_t reserved:1; - uint8_t state:1; - uint16_t timestamp; -} DNP3ObjectG2V3; - -typedef struct DNP3ObjectG3V1_ { - uint8_t state; -} DNP3ObjectG3V1; - -typedef struct DNP3ObjectG3V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t chatter_filter:1; - uint8_t state:2; -} DNP3ObjectG3V2; - -typedef struct DNP3ObjectG4V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t chatter_filter:1; - uint8_t state:2; -} DNP3ObjectG4V1; - -typedef struct DNP3ObjectG4V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t chatter_filter:1; - uint8_t state:2; - uint64_t timestamp; -} DNP3ObjectG4V2; - -typedef struct DNP3ObjectG4V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t chatter_filter:1; - uint8_t state:2; - uint16_t relative_time_ms; -} DNP3ObjectG4V3; - -typedef struct DNP3ObjectG10V1_ { - uint8_t state; -} DNP3ObjectG10V1; - -typedef struct DNP3ObjectG10V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint8_t state:1; -} DNP3ObjectG10V2; - -typedef struct DNP3ObjectG11V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint8_t state:1; -} DNP3ObjectG11V1; - -typedef struct DNP3ObjectG11V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint8_t state:1; - uint64_t timestamp; -} DNP3ObjectG11V2; - -typedef struct DNP3ObjectG12V1_ { - uint8_t op_type:4; - uint8_t qu:1; - uint8_t cr:1; - uint8_t tcc:2; - uint8_t count; - uint32_t ontime; - uint32_t offtime; - uint8_t status_code:7; - uint8_t reserved:1; -} DNP3ObjectG12V1; - -typedef struct DNP3ObjectG12V2_ { - uint8_t op_type:4; - uint8_t qu:1; - uint8_t cr:1; - uint8_t tcc:2; - uint8_t count; - uint32_t ontime; - uint32_t offtime; - uint8_t status_code:7; - uint8_t reserved:1; -} DNP3ObjectG12V2; - -typedef struct DNP3ObjectG12V3_ { - uint8_t point; -} DNP3ObjectG12V3; - -typedef struct DNP3ObjectG13V1_ { - uint8_t status_code:7; - uint8_t commanded_state:1; -} DNP3ObjectG13V1; - -typedef struct DNP3ObjectG13V2_ { - uint8_t status_code:7; - uint8_t commanded_state:1; - uint64_t timestamp; -} DNP3ObjectG13V2; - -typedef struct DNP3ObjectG20V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint32_t count; -} DNP3ObjectG20V1; - -typedef struct DNP3ObjectG20V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint16_t count; -} DNP3ObjectG20V2; - -typedef struct DNP3ObjectG20V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; -} DNP3ObjectG20V3; - -typedef struct DNP3ObjectG20V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; -} DNP3ObjectG20V4; - -typedef struct DNP3ObjectG20V5_ { - uint32_t count; -} DNP3ObjectG20V5; - -typedef struct DNP3ObjectG20V6_ { - uint16_t count; -} DNP3ObjectG20V6; - -typedef struct DNP3ObjectG20V7_ { - uint32_t count; -} DNP3ObjectG20V7; - -typedef struct DNP3ObjectG20V8_ { - uint16_t count; -} DNP3ObjectG20V8; - -typedef struct DNP3ObjectG21V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint32_t count; -} DNP3ObjectG21V1; - -typedef struct DNP3ObjectG21V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint16_t count; -} DNP3ObjectG21V2; - -typedef struct DNP3ObjectG21V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; -} DNP3ObjectG21V3; - -typedef struct DNP3ObjectG21V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; -} DNP3ObjectG21V4; - -typedef struct DNP3ObjectG21V5_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved1:1; - uint32_t count; - uint64_t timestamp; -} DNP3ObjectG21V5; - -typedef struct DNP3ObjectG21V6_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved1:1; - uint16_t count; - uint64_t timestamp; -} DNP3ObjectG21V6; - -typedef struct DNP3ObjectG21V7_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; - uint64_t timestamp; -} DNP3ObjectG21V7; - -typedef struct DNP3ObjectG21V8_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; - uint64_t timestamp; -} DNP3ObjectG21V8; - -typedef struct DNP3ObjectG21V9_ { - uint32_t count; -} DNP3ObjectG21V9; - -typedef struct DNP3ObjectG21V10_ { - uint16_t count; -} DNP3ObjectG21V10; - -typedef struct DNP3ObjectG21V11_ { - uint32_t count; -} DNP3ObjectG21V11; - -typedef struct DNP3ObjectG21V12_ { - uint16_t count; -} DNP3ObjectG21V12; - -typedef struct DNP3ObjectG22V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint32_t count; -} DNP3ObjectG22V1; - -typedef struct DNP3ObjectG22V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint16_t count; -} DNP3ObjectG22V2; - -typedef struct DNP3ObjectG22V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; -} DNP3ObjectG22V3; - -typedef struct DNP3ObjectG22V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; -} DNP3ObjectG22V4; - -typedef struct DNP3ObjectG22V5_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; - uint64_t timestamp; -} DNP3ObjectG22V5; - -typedef struct DNP3ObjectG22V6_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint16_t count; - uint64_t timestamp; -} DNP3ObjectG22V6; - -typedef struct DNP3ObjectG22V7_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; - uint64_t timestamp; -} DNP3ObjectG22V7; - -typedef struct DNP3ObjectG22V8_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; - uint64_t timestamp; -} DNP3ObjectG22V8; - -typedef struct DNP3ObjectG23V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint32_t count; -} DNP3ObjectG23V1; - -typedef struct DNP3ObjectG23V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; -} DNP3ObjectG23V2; - -typedef struct DNP3ObjectG23V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; -} DNP3ObjectG23V3; - -typedef struct DNP3ObjectG23V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; -} DNP3ObjectG23V4; - -typedef struct DNP3ObjectG23V5_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint32_t count; - uint64_t timestamp; -} DNP3ObjectG23V5; - -typedef struct DNP3ObjectG23V6_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t discontinuity:1; - uint8_t reserved0:1; - uint16_t count; - uint64_t timestamp; -} DNP3ObjectG23V6; - -typedef struct DNP3ObjectG23V7_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint32_t count; - uint64_t timestamp; -} DNP3ObjectG23V7; - -typedef struct DNP3ObjectG23V8_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t rollover:1; - uint8_t reserved0:1; - uint8_t reserved1:1; - uint16_t count; - uint64_t timestamp; -} DNP3ObjectG23V8; - -typedef struct DNP3ObjectG30V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; -} DNP3ObjectG30V1; - -typedef struct DNP3ObjectG30V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; -} DNP3ObjectG30V2; - -typedef struct DNP3ObjectG30V3_ { - int32_t value; -} DNP3ObjectG30V3; - -typedef struct DNP3ObjectG30V4_ { - int16_t value; -} DNP3ObjectG30V4; - -typedef struct DNP3ObjectG30V5_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; -} DNP3ObjectG30V5; - -typedef struct DNP3ObjectG30V6_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; -} DNP3ObjectG30V6; - -typedef struct DNP3ObjectG31V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; -} DNP3ObjectG31V1; - -typedef struct DNP3ObjectG31V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; -} DNP3ObjectG31V2; - -typedef struct DNP3ObjectG31V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; - uint64_t timestamp; -} DNP3ObjectG31V3; - -typedef struct DNP3ObjectG31V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; - uint64_t timestamp; -} DNP3ObjectG31V4; - -typedef struct DNP3ObjectG31V5_ { - int32_t value; -} DNP3ObjectG31V5; - -typedef struct DNP3ObjectG31V6_ { - int16_t value; -} DNP3ObjectG31V6; - -typedef struct DNP3ObjectG31V7_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; -} DNP3ObjectG31V7; - -typedef struct DNP3ObjectG31V8_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; -} DNP3ObjectG31V8; - -typedef struct DNP3ObjectG32V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; -} DNP3ObjectG32V1; - -typedef struct DNP3ObjectG32V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; -} DNP3ObjectG32V2; - -typedef struct DNP3ObjectG32V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; - uint64_t timestamp; -} DNP3ObjectG32V3; - -typedef struct DNP3ObjectG32V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; - uint64_t timestamp; -} DNP3ObjectG32V4; - -typedef struct DNP3ObjectG32V5_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; -} DNP3ObjectG32V5; - -typedef struct DNP3ObjectG32V6_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; -} DNP3ObjectG32V6; - -typedef struct DNP3ObjectG32V7_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; - uint64_t timestamp; -} DNP3ObjectG32V7; - -typedef struct DNP3ObjectG32V8_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; - uint64_t timestamp; -} DNP3ObjectG32V8; - -typedef struct DNP3ObjectG33V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; -} DNP3ObjectG33V1; - -typedef struct DNP3ObjectG33V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; -} DNP3ObjectG33V2; - -typedef struct DNP3ObjectG33V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; - uint64_t timestamp; -} DNP3ObjectG33V3; - -typedef struct DNP3ObjectG33V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; - uint64_t timestamp; -} DNP3ObjectG33V4; - -typedef struct DNP3ObjectG33V5_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; -} DNP3ObjectG33V5; - -typedef struct DNP3ObjectG33V6_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; -} DNP3ObjectG33V6; - -typedef struct DNP3ObjectG33V7_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; - uint64_t timestamp; -} DNP3ObjectG33V7; - -typedef struct DNP3ObjectG33V8_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; - uint64_t timestamp; -} DNP3ObjectG33V8; - -typedef struct DNP3ObjectG34V1_ { - uint16_t deadband_value; -} DNP3ObjectG34V1; - -typedef struct DNP3ObjectG34V2_ { - uint32_t deadband_value; -} DNP3ObjectG34V2; - -typedef struct DNP3ObjectG34V3_ { - float deadband_value; -} DNP3ObjectG34V3; - -typedef struct DNP3ObjectG40V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; -} DNP3ObjectG40V1; - -typedef struct DNP3ObjectG40V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; -} DNP3ObjectG40V2; - -typedef struct DNP3ObjectG40V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; -} DNP3ObjectG40V3; - -typedef struct DNP3ObjectG40V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; -} DNP3ObjectG40V4; - -typedef struct DNP3ObjectG41V1_ { - int32_t value; - uint8_t control_status; -} DNP3ObjectG41V1; - -typedef struct DNP3ObjectG41V2_ { - int16_t value; - uint8_t control_status; -} DNP3ObjectG41V2; - -typedef struct DNP3ObjectG41V3_ { - float value; - uint8_t control_status; -} DNP3ObjectG41V3; - -typedef struct DNP3ObjectG41V4_ { - double value; - uint8_t control_status; -} DNP3ObjectG41V4; - -typedef struct DNP3ObjectG42V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; -} DNP3ObjectG42V1; - -typedef struct DNP3ObjectG42V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; -} DNP3ObjectG42V2; - -typedef struct DNP3ObjectG42V3_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int32_t value; - uint64_t timestamp; -} DNP3ObjectG42V3; - -typedef struct DNP3ObjectG42V4_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - int16_t value; - uint64_t timestamp; -} DNP3ObjectG42V4; - -typedef struct DNP3ObjectG42V5_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; -} DNP3ObjectG42V5; - -typedef struct DNP3ObjectG42V6_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; -} DNP3ObjectG42V6; - -typedef struct DNP3ObjectG42V7_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - float value; - uint64_t timestamp; -} DNP3ObjectG42V7; - -typedef struct DNP3ObjectG42V8_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t over_range:1; - uint8_t reference_err:1; - uint8_t reserved0:1; - double value; - uint64_t timestamp; -} DNP3ObjectG42V8; - -typedef struct DNP3ObjectG43V1_ { - uint8_t status_code:7; - uint8_t reserved0:1; - int32_t commanded_value; -} DNP3ObjectG43V1; - -typedef struct DNP3ObjectG43V2_ { - uint8_t status_code:7; - uint8_t reserved0:1; - int16_t commanded_value; -} DNP3ObjectG43V2; - -typedef struct DNP3ObjectG43V3_ { - uint8_t status_code:7; - uint8_t reserved0:1; - int32_t commanded_value; - uint64_t timestamp; -} DNP3ObjectG43V3; - -typedef struct DNP3ObjectG43V4_ { - uint8_t status_code:7; - uint8_t reserved0:1; - int16_t commanded_value; - uint64_t timestamp; -} DNP3ObjectG43V4; - -typedef struct DNP3ObjectG43V5_ { - uint8_t status_code:7; - uint8_t reserved0:1; - float commanded_value; -} DNP3ObjectG43V5; - -typedef struct DNP3ObjectG43V6_ { - uint8_t status_code:7; - uint8_t reserved0:1; - double commanded_value; -} DNP3ObjectG43V6; - -typedef struct DNP3ObjectG43V7_ { - uint8_t status_code:7; - uint8_t reserved0:1; - float commanded_value; - uint64_t timestamp; -} DNP3ObjectG43V7; - -typedef struct DNP3ObjectG43V8_ { - uint8_t status_code:7; - uint8_t reserved0:1; - double commanded_value; - uint64_t timestamp; -} DNP3ObjectG43V8; - -typedef struct DNP3ObjectG50V1_ { - uint64_t timestamp; -} DNP3ObjectG50V1; - -typedef struct DNP3ObjectG50V2_ { - uint64_t timestamp; - uint32_t interval; -} DNP3ObjectG50V2; - -typedef struct DNP3ObjectG50V3_ { - uint64_t timestamp; -} DNP3ObjectG50V3; - -typedef struct DNP3ObjectG50V4_ { - uint64_t timestamp; - uint32_t interval_count; - uint8_t interval_units; -} DNP3ObjectG50V4; - -typedef struct DNP3ObjectG51V1_ { - uint64_t timestamp; -} DNP3ObjectG51V1; - -typedef struct DNP3ObjectG51V2_ { - uint64_t timestamp; -} DNP3ObjectG51V2; - -typedef struct DNP3ObjectG52V1_ { - uint16_t delay_secs; -} DNP3ObjectG52V1; - -typedef struct DNP3ObjectG52V2_ { - uint16_t delay_ms; -} DNP3ObjectG52V2; - -typedef struct DNP3ObjectG70V1_ { - uint16_t filename_size; - uint8_t filetype_code; - uint8_t attribute_code; - uint16_t start_record; - uint16_t end_record; - uint32_t file_size; - uint64_t created_timestamp; - uint16_t permission; - uint32_t file_id; - uint32_t owner_id; - uint32_t group_id; - uint8_t file_function_code; - uint8_t status_code; - char filename[65535]; - uint16_t data_size; - char data[65535]; -} DNP3ObjectG70V1; - -typedef struct DNP3ObjectG70V2_ { - uint16_t username_offset; - uint16_t username_size; - uint16_t password_offset; - uint16_t password_size; - uint32_t authentication_key; - char username[65535]; - char password[65535]; -} DNP3ObjectG70V2; - -typedef struct DNP3ObjectG70V3_ { - uint16_t filename_offset; - uint16_t filename_size; - uint64_t created; - uint16_t permissions; - uint32_t authentication_key; - uint32_t file_size; - uint16_t operational_mode; - uint16_t maximum_block_size; - uint16_t request_id; - char filename[65535]; -} DNP3ObjectG70V3; - -typedef struct DNP3ObjectG70V4_ { - uint32_t file_handle; - uint32_t file_size; - uint16_t maximum_block_size; - uint16_t request_id; - uint8_t status_code; - char optional_text[255]; - uint8_t optional_text_len; -} DNP3ObjectG70V4; - -typedef struct DNP3ObjectG70V5_ { - uint32_t file_handle; - uint32_t block_number; - char file_data[255]; - uint8_t file_data_len; -} DNP3ObjectG70V5; - -typedef struct DNP3ObjectG70V6_ { - uint32_t file_handle; - uint32_t block_number; - uint8_t status_code; - char optional_text[255]; - uint8_t optional_text_len; -} DNP3ObjectG70V6; - -typedef struct DNP3ObjectG70V7_ { - uint16_t filename_offset; - uint16_t filename_size; - uint16_t file_type; - uint32_t file_size; - uint64_t created_timestamp; - uint16_t permissions; - uint16_t request_id; - char filename[65535]; -} DNP3ObjectG70V7; - -typedef struct DNP3ObjectG70V8_ { - char file_specification[65535]; - uint16_t file_specification_len; -} DNP3ObjectG70V8; - -typedef struct DNP3ObjectG80V1_ { - uint8_t state; -} DNP3ObjectG80V1; - -typedef struct DNP3ObjectG81V1_ { - uint8_t fill_percentage:7; - uint8_t overflow_state:1; - uint8_t group; - uint8_t variation; -} DNP3ObjectG81V1; - -typedef struct DNP3ObjectG83V1_ { - char vendor_code[5]; - uint16_t object_id; - uint16_t length; - uint8_t *data_objects; -} DNP3ObjectG83V1; - -typedef struct DNP3ObjectG86V2_ { - uint8_t rd:1; - uint8_t wr:1; - uint8_t st:1; - uint8_t ev:1; - uint8_t df:1; - uint8_t padding0:1; - uint8_t padding1:1; - uint8_t padding2:1; -} DNP3ObjectG86V2; - -typedef struct DNP3ObjectG102V1_ { - uint8_t value; -} DNP3ObjectG102V1; - -typedef struct DNP3ObjectG120V1_ { - uint32_t csq; - uint16_t usr; - uint8_t mal; - uint8_t reason; - uint8_t *challenge_data; - uint16_t challenge_data_len; -} DNP3ObjectG120V1; - -typedef struct DNP3ObjectG120V2_ { - uint32_t csq; - uint16_t usr; - uint8_t *mac_value; - uint16_t mac_value_len; -} DNP3ObjectG120V2; - -typedef struct DNP3ObjectG120V3_ { - uint32_t csq; - uint16_t user_number; -} DNP3ObjectG120V3; - -typedef struct DNP3ObjectG120V4_ { - uint16_t user_number; -} DNP3ObjectG120V4; - -typedef struct DNP3ObjectG120V5_ { - uint32_t ksq; - uint16_t user_number; - uint8_t key_wrap_alg; - uint8_t key_status; - uint8_t mal; - uint16_t challenge_data_len; - uint8_t *challenge_data; - uint8_t *mac_value; - uint16_t mac_value_len; -} DNP3ObjectG120V5; - -typedef struct DNP3ObjectG120V6_ { - uint32_t ksq; - uint16_t usr; - uint8_t *wrapped_key_data; - uint16_t wrapped_key_data_len; -} DNP3ObjectG120V6; - -typedef struct DNP3ObjectG120V7_ { - uint32_t sequence_number; - uint16_t usr; - uint16_t association_id; - uint8_t error_code; - uint64_t time_of_error; - char error_text[65535]; - uint16_t error_text_len; -} DNP3ObjectG120V7; - -typedef struct DNP3ObjectG120V8_ { - uint8_t key_change_method; - uint8_t certificate_type; - uint8_t *certificate; - uint16_t certificate_len; -} DNP3ObjectG120V8; - -typedef struct DNP3ObjectG120V9_ { - uint8_t *mac_value; - uint16_t mac_value_len; -} DNP3ObjectG120V9; - -typedef struct DNP3ObjectG120V10_ { - uint8_t key_change_method; - uint8_t operation; - uint32_t scs; - uint16_t user_role; - uint16_t user_role_expiry_interval; - uint16_t username_len; - uint16_t user_public_key_len; - uint16_t certification_data_len; - char username[65535]; - uint8_t *user_public_key; - uint8_t *certification_data; -} DNP3ObjectG120V10; - -typedef struct DNP3ObjectG120V11_ { - uint8_t key_change_method; - uint16_t username_len; - uint16_t master_challenge_data_len; - char username[65535]; - uint8_t *master_challenge_data; -} DNP3ObjectG120V11; - -typedef struct DNP3ObjectG120V12_ { - uint32_t ksq; - uint16_t user_number; - uint16_t challenge_data_len; - uint8_t *challenge_data; -} DNP3ObjectG120V12; - -typedef struct DNP3ObjectG120V13_ { - uint32_t ksq; - uint16_t user_number; - uint16_t encrypted_update_key_len; - uint8_t *encrypted_update_key_data; -} DNP3ObjectG120V13; - -typedef struct DNP3ObjectG120V14_ { - uint8_t *digital_signature; - uint16_t digital_signature_len; -} DNP3ObjectG120V14; - -typedef struct DNP3ObjectG120V15_ { - uint8_t *mac; - uint32_t mac_len; -} DNP3ObjectG120V15; - -typedef struct DNP3ObjectG121V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t reserved0:1; - uint8_t discontinuity:1; - uint8_t reserved1:1; - uint16_t association_id; - uint32_t count_value; -} DNP3ObjectG121V1; - -typedef struct DNP3ObjectG122V1_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t reserved0:1; - uint8_t discontinuity:1; - uint8_t reserved1:1; - uint16_t association_id; - uint32_t count_value; -} DNP3ObjectG122V1; - -typedef struct DNP3ObjectG122V2_ { - uint8_t online:1; - uint8_t restart:1; - uint8_t comm_lost:1; - uint8_t remote_forced:1; - uint8_t local_forced:1; - uint8_t reserved0:1; - uint8_t discontinuity:1; - uint8_t reserved1:1; - uint16_t association_id; - uint32_t count_value; - uint64_t timestamp; -} DNP3ObjectG122V2; - -/* END GENERATED CODE */ - -int DNP3DecodeObject(int group, int variation, const uint8_t **buf, - uint32_t *len, uint8_t prefix_code, uint32_t start, uint32_t count, - DNP3PointList *); -DNP3PointList *DNP3PointListAlloc(void); -void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *); - -#endif /* __APP_LAYER_DNP3_OBJECTS_H__ */ diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c deleted file mode 100644 index 9501b9f5ea57..000000000000 --- a/src/app-layer-dnp3.c +++ /dev/null @@ -1,2655 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * DNP3 protocol implementation - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "stream.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-hashlist.h" - -#include "util-print.h" -#include "util-spm-bs.h" -#include "util-enum.h" - -#include "app-layer.h" -#include "app-layer-protos.h" -#include "app-layer-parser.h" -#include "app-layer-detect-proto.h" - -#include "app-layer-dnp3.h" -#include "app-layer-dnp3-objects.h" - -/* Default number of unreplied requests to be considered a flood. */ -#define DNP3_DEFAULT_REQ_FLOOD_COUNT 500 - -#define DNP3_DEFAULT_PORT "20000" - -/* Expected values for the start bytes. */ -#define DNP3_START_BYTE0 0x05 -#define DNP3_START_BYTE1 0x64 - -/* Minimum length for a DNP3 frame. */ -#define DNP3_MIN_LEN 5 - -/* Length of each CRC. */ -#define DNP3_CRC_LEN 2 - -/* DNP3 block size. After the link header a CRC is inserted after - * after 16 bytes of data. */ -#define DNP3_BLOCK_SIZE 16 - -/* Maximum transport layer sequence number. */ -#define DNP3_MAX_TRAN_SEQNO 64 - -/* Maximum application layer sequence number. */ -#define DNP3_MAX_APP_SEQNO 16 - -/* The number of bytes in the header that are counted as part of the - * header length field. */ -#define DNP3_LINK_HDR_LEN 5 - -/* Link function codes. */ -enum { - DNP3_LINK_FC_CONFIRMED_USER_DATA = 3, - DNP3_LINK_FC_UNCONFIRMED_USER_DATA -}; - -/* Reserved addresses. */ -#define DNP3_RESERVED_ADDR_MIN 0xfff0 -#define DNP3_RESERVED_ADDR_MAX 0xfffb - -/* Source addresses must be < 0xfff0. */ -#define DNP3_SRC_ADDR_MAX 0xfff0 - -#define DNP3_OBJ_TIME_SIZE 6 /* AKA UINT48. */ -#define DNP3_OBJ_G12_V1_SIZE 11 -#define DNP3_OBJ_G12_V2_SIZE 11 -#define DNP3_OBJ_G12_V3_SIZE 1 - -/* Extract the prefix code from the object qualifier. */ -#define DNP3_OBJ_PREFIX(x) ((x >> 4) & 0x7) - -/* Extract the range code from the object qualifier. */ -#define DNP3_OBJ_RANGE(x) (x & 0xf) - -/* Decoder event map. */ -SCEnumCharMap dnp3_decoder_event_table[] = { - {"FLOODED", DNP3_DECODER_EVENT_FLOODED}, - {"LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL}, - {"BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC}, - {"BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC}, - {"MALFORMED", DNP3_DECODER_EVENT_MALFORMED}, - {"UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT}, - {NULL, -1}, -}; - -/* Calculate the next transport sequence number. */ -#define NEXT_TH_SEQNO(current) ((current + 1) % DNP3_MAX_TRAN_SEQNO) - -/* Calculate the next application sequence number. */ -#define NEXT_APP_SEQNO(current) ((current + 1) % DNP3_MAX_APP_SEQNO) - -/* CRC table generated by pycrc - http://github.com/tpircher/pycrc. - * - Polynomial: 0x3d65. */ -static const uint16_t crc_table[256] = { - 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a, - 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13, - 0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1, - 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78, - 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35, - 0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc, - 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e, - 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7, - 0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4, - 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d, - 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af, - 0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26, - 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b, - 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2, - 0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00, - 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489, - 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526, - 0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf, - 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d, - 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4, - 0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89, - 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300, - 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2, - 0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b, - 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678, - 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1, - 0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413, - 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a, - 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7, - 0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e, - 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc, - 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235 -}; - -/** - * \brief Compute the CRC for a buffer. - * - * \param buf Buffer to create CRC from. - * \param len Length of buffer (number of bytes to use for CRC). - - */ -static uint16_t DNP3ComputeCRC(const uint8_t *buf, uint32_t len) -{ - const uint8_t *byte = buf; - uint16_t crc = 0; - int idx; - - while (len--) { - idx = (crc ^ *byte) & 0xff; - crc = (crc_table[idx] ^ (crc >> 8)) & 0xffff; - byte++; - } - - return ~crc & 0xffff; -} - -/** - * \brief Check the CRC of a block. - * - * \param block The block of data with CRC to be checked. - * \param len The size of the data block. - * - * \retval 1 if CRC is OK, otherwise 0. - */ -static int DNP3CheckCRC(const uint8_t *block, uint32_t len) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 1; -#endif - uint32_t crc_offset; - uint16_t crc; - - /* Need at least one byte plus the CRC. */ - if (len < DNP3_CRC_LEN + 1) { - return 0; - } - - crc_offset = len - DNP3_CRC_LEN; - crc = DNP3ComputeCRC(block, len - DNP3_CRC_LEN); - if (((crc & 0xff) == block[crc_offset]) && - ((crc >> 8) == block[crc_offset + 1])) { - return 1; - } - - return 0; -} - -/** - * \brief Check the CRC of the link header. - * - * \param header Point to the link header. - * - * \retval 1 if header CRC is OK, otherwise 0. - */ -static int DNP3CheckLinkHeaderCRC(const DNP3LinkHeader *header) -{ - return DNP3CheckCRC((uint8_t *)header, sizeof(DNP3LinkHeader)); -} - -/** - * \brief Check user data CRCs. - * - * \param data Pointer to user data. - * \param len Length of user data. - * - * \retval 1 if CRCs are OK, otherwise 0. - */ -static int DNP3CheckUserDataCRCs(const uint8_t *data, uint32_t len) -{ - uint32_t offset = 0; - uint32_t block_size; - - while (offset < len) { - if (len - offset >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { - block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; - } - else { - block_size = len - offset; - } - - if (!DNP3CheckCRC(data + offset, block_size)) { - /* Once failed, may as well return immediately. */ - return 0; - } - - offset += block_size; - } - - return 1; -} - -/** - * \brief Check the DNP3 frame start bytes. - * - * \retval 1 if valid, 0 if not. - */ -static int DNP3CheckStartBytes(const DNP3LinkHeader *header) -{ - return header->start_byte0 == DNP3_START_BYTE0 && - header->start_byte1 == DNP3_START_BYTE1; -} - -/* Some DNP3 servers start with a banner. */ -#define DNP3_BANNER "DNP3" - -/** - * \brief Check if a frame contains a banner. - * - * Some servers (outstations) appear to send back a banner that fails - * the normal frame checks. So first check for a banner. - * - * \retval 1 if a banner is found, 0 if not. - */ -static int DNP3ContainsBanner(const uint8_t *input, uint32_t len) -{ - return BasicSearch(input, len, (uint8_t *)DNP3_BANNER, strlen(DNP3_BANNER)) != NULL; -} - -/** - * \brief DNP3 probing parser. - */ -static uint16_t DNP3ProbingParser(Flow *f, uint8_t direction, - const uint8_t *input, uint32_t len, - uint8_t *rdir) -{ - const DNP3LinkHeader *const hdr = (const DNP3LinkHeader *)input; - const bool toserver = (direction & STREAM_TOSERVER) != 0; - - /* May be a banner. */ - if (DNP3ContainsBanner(input, len)) { - SCLogDebug("Packet contains a DNP3 banner."); - bool is_banner = true; - // magic 0x100 = 256 seems good enough - for (uint32_t i = 0; i < len && i < 0x100; i++) { - if (!isprint(input[i])) { - is_banner = false; - break; - } - } - if (is_banner) { - if (toserver) { - *rdir = STREAM_TOCLIENT; - } - return ALPROTO_DNP3; - } - } - - /* Check that we have the minimum amount of bytes. */ - if (len < sizeof(DNP3LinkHeader)) { - SCLogDebug("Length too small to be a DNP3 header."); - return ALPROTO_UNKNOWN; - } - - /* Verify start value (from AN2013-004b). */ - if (!DNP3CheckStartBytes(hdr)) { - SCLogDebug("Invalid start bytes."); - return ALPROTO_FAILED; - } - - /* Verify minimum length. */ - if (hdr->len < DNP3_MIN_LEN) { - SCLogDebug("Packet too small to be a valid DNP3 fragment."); - return ALPROTO_FAILED; - } - - // Test compatibility between direction and dnp3.ctl.direction - if ((DNP3_LINK_DIR(hdr->control) != 0) != toserver) { - *rdir = toserver ? STREAM_TOCLIENT : STREAM_TOSERVER; - } - SCLogDebug("Detected DNP3."); - return ALPROTO_DNP3; -} - -/** - * \brief Calculate the length of the transport layer with CRCs removed. - * - * \param input_len The length of the transport layer buffer. - * - * \retval The length of the buffer after CRCs are removed. - */ -static int DNP3CalculateTransportLengthWithoutCRCs(uint32_t input_len) -{ - /* Too small. */ - if (input_len < DNP3_CRC_LEN) { - return -1; - } - - /* Get the number of complete blocks. */ - int blocks = input_len / (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); - - /* And the number of bytes in the last block. */ - int rem = input_len - (blocks * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); - - if (rem) { - if (rem < DNP3_CRC_LEN) { - return -1; - } - return (blocks * DNP3_BLOCK_SIZE) + (rem - DNP3_CRC_LEN); - } - else { - return (blocks * DNP3_BLOCK_SIZE); - } -} - -/** - * \brief Reassemble the application layer by stripping the CRCs. - * - * Remove the CRCs from the user data blocks. The output is the user - * data with the CRCs removed as well as the transport header removed, - * but the input data still needs to include the transport header as - * its part of the first user data block. - * - * If the output length passed in is non-null, the new input data will - * be appended, and the output length pointer incremented as needed. - * - * \param input Input buffer starting at the transport header (which - * will be removed from the output). - * \param input_len Length of the input buffer. - * \param output Pointer to output buffer (may be realloc'd). - * \param output_len Pointer to output length. - * - * \retval 1 if reassembly was successful, otherwise 0. - */ -static int DNP3ReassembleApplicationLayer(const uint8_t *input, - uint32_t input_len, uint8_t **output, uint32_t *output_len) -{ - int len = DNP3CalculateTransportLengthWithoutCRCs(input_len); - - if (len <= 0) { - return 0; - } - - /* Remove one byte for the transport header and make sure we have - * at least one byte of user data. */ - if (--len < 1) { - return 0; - } - - if (*output == NULL) { - *output = SCCalloc(1, len); - if (unlikely(*output == NULL)) { - return 0; - } - } - else { - uint8_t *ptr = SCRealloc(*output, (size_t)(*output_len + len)); - if (unlikely(ptr == NULL)) { - return 0; - } - *output = ptr; - } - - int offset = 0, block_size; - while ((uint32_t)offset < input_len) { - if (input_len - offset > DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { - block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; - } - else { - block_size = input_len - offset; - } - - /* If handling the first block (offset is 0), trim off the - * first byte which is the transport header, and not part of - * the application data. */ - if (offset == 0) { - offset++; - block_size--; - } - - /* Need at least 3 bytes to continue. One for application - * data, and 2 for the CRC. If not, return failure for - * malformed frame. */ - if (block_size < DNP3_CRC_LEN + 1) { - SCLogDebug("Not enough data to continue."); - return 0; - } - - /* Make sure there is enough space to write into. */ - if (block_size - DNP3_CRC_LEN > len) { - SCLogDebug("Not enough data to continue."); - return 0; - } - - memcpy(*output + *output_len, input + offset, - block_size - DNP3_CRC_LEN); - *output_len += block_size - DNP3_CRC_LEN; - offset += block_size; - len -= block_size - DNP3_CRC_LEN; - } - - return 1; -} - -/** - * \brief Allocate a DNP3 state object. - * - * The DNP3 state object represents a single DNP3 TCP session. - */ -static void *DNP3StateAlloc(void *orig_state, AppProto proto_orig) -{ - SCEnter(); - DNP3State *dnp3; - - dnp3 = (DNP3State *)SCCalloc(1, sizeof(DNP3State)); - if (unlikely(dnp3 == NULL)) { - return NULL; - } - TAILQ_INIT(&dnp3->tx_list); - - SCReturnPtr(dnp3, "void"); -} - -/** - * \brief Set a DNP3 application layer event. - * - * Sets an event on the current transaction object. - */ -static void DNP3SetEvent(DNP3State *dnp3, uint8_t event) -{ - if (dnp3 && dnp3->curr) { - AppLayerDecoderEventsSetEventRaw(&dnp3->curr->tx_data.events, event); - dnp3->events++; - } - else { - SCLogWarning("Failed to set event, state or tx pointer was NULL."); - } -} - -/** - * \brief Set a DNP3 application layer event on a transaction. - */ -static void DNP3SetEventTx(DNP3Transaction *tx, uint8_t event) -{ - AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, event); - tx->dnp3->events++; -} - -/** - * \brief Allocation a DNP3 transaction. - */ -static DNP3Transaction *DNP3TxAlloc(DNP3State *dnp3, bool request) -{ - DNP3Transaction *tx = SCCalloc(1, sizeof(DNP3Transaction)); - if (unlikely(tx == NULL)) { - return NULL; - } - dnp3->transaction_max++; - dnp3->unreplied++; - dnp3->curr = tx; - tx->dnp3 = dnp3; - tx->tx_num = dnp3->transaction_max; - tx->is_request = request; - if (tx->is_request) { - tx->tx_data.detect_flags_tc |= APP_LAYER_TX_SKIP_INSPECT_FLAG; - } else { - tx->tx_data.detect_flags_ts |= APP_LAYER_TX_SKIP_INSPECT_FLAG; - } - TAILQ_INIT(&tx->objects); - TAILQ_INSERT_TAIL(&dnp3->tx_list, tx, next); - - /* Check for flood state. */ - if (dnp3->unreplied > DNP3_DEFAULT_REQ_FLOOD_COUNT) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_FLOODED); - dnp3->flooded = 1; - } - - return tx; -} - -/** - * \brief Calculate the length of a link frame with CRCs. - * - * This is required as the length parameter in the DNP3 header does not - * include the added CRCs. - * - * \param length The length from the DNP3 link header. - * - * \retval The length of the frame with CRCs included or 0 if the length isn't - * long enough to be a valid DNP3 frame. - */ -static uint32_t DNP3CalculateLinkLength(uint8_t length) -{ - uint32_t frame_len = 0; - int rem; - - /* Fail early if the length is less than the minimum size. */ - if (length < DNP3_LINK_HDR_LEN) { - return 0; - } - - /* Subtract the 5 bytes of the header that are included in the - * length. */ - length -= DNP3_LINK_HDR_LEN; - - rem = length % DNP3_BLOCK_SIZE; - frame_len = (length / DNP3_BLOCK_SIZE) * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); - if (rem) { - frame_len += rem + DNP3_CRC_LEN; - } - - return frame_len + sizeof(DNP3LinkHeader); -} - -/** - * \brief Check if the link function code specifies user data. - * - * \param header Point to link header. - * - * \retval 1 if frame contains user data, otherwise 0. - */ -static int DNP3IsUserData(const DNP3LinkHeader *header) -{ - switch (DNP3_LINK_FC(header->control)) { - case DNP3_LINK_FC_CONFIRMED_USER_DATA: - case DNP3_LINK_FC_UNCONFIRMED_USER_DATA: - return 1; - default: - return 0; - } -} - -/** - * \brief Check if the frame has user data. - * - * Check if the DNP3 frame actually has user data by checking if data - * exists after the headers. - * - * \retval 1 if user data exists, otherwise 0. - */ -static int DNP3HasUserData(const DNP3LinkHeader *header, uint8_t direction) -{ - if (direction == STREAM_TOSERVER) { - return header->len >= DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + - sizeof(DNP3ApplicationHeader); - } - else { - return header->len >= DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + - sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); - } -} - -/** - * \brief Reset a DNP3Buffer. - */ -static void DNP3BufferReset(DNP3Buffer *buffer) -{ - buffer->offset = 0; - buffer->len = 0; -} - -/** - * \brief Add data to a DNP3 buffer, enlarging the buffer if required. - * - * \param buffer Buffer to add data data. - * \param data Data to be added to buffer. - * \param len Size of data to be added to buffer. - * - * \param 1 if data was added successful, otherwise 0. - */ -static int DNP3BufferAdd(DNP3Buffer *buffer, const uint8_t *data, uint32_t len) -{ - if (buffer->size == 0) { - buffer->buffer = SCCalloc(1, len); - if (unlikely(buffer->buffer == NULL)) { - return 0; - } - buffer->size = len; - } - else if (buffer->len + len > buffer->size) { - uint8_t *tmp = SCRealloc(buffer->buffer, buffer->len + len); - if (unlikely(tmp == NULL)) { - return 0; - } - buffer->buffer = tmp; - buffer->size = buffer->len + len; - } - memcpy(buffer->buffer + buffer->len, data, len); - buffer->len += len; - - return 1; -} - -/** - * \brief Trim a DNP3 buffer. - * - * Trimming a buffer moves the data in the buffer up to the front of - * the buffer freeing up room at the end for more incoming data. - * - * \param buffer The buffer to trim. - */ -static void DNP3BufferTrim(DNP3Buffer *buffer) -{ - if (buffer->offset == buffer->len) { - DNP3BufferReset(buffer); - } - else if (buffer->offset > 0) { - memmove(buffer->buffer, buffer->buffer + buffer->offset, - buffer->len - buffer->offset); - buffer->len = buffer->len - buffer->offset; - buffer->offset = 0; - } -} - -/** - * \brief Free a DNP3 object. - */ -static void DNP3ObjectFree(DNP3Object *object) -{ - if (object->points != NULL) { - DNP3FreeObjectPointList(object->group, object->variation, - object->points); - } - SCFree(object); -} - -/** - * \brief Allocate a DNP3 object. - */ -static DNP3Object *DNP3ObjectAlloc(void) -{ - DNP3Object *object = SCCalloc(1, sizeof(*object)); - if (unlikely(object == NULL)) { - return NULL; - } - object->points = DNP3PointListAlloc(); - if (object->points == NULL) { - DNP3ObjectFree(object); - return NULL; - } - return object; -} - -/** - * \brief Decode DNP3 application objects. - * - * This function decoded known DNP3 application objects. As the - * protocol isn't self describing, we can only decode the buffer while - * the application objects are known. As soon as an unknown - * group/variation is hit, we must stop processing. - * - * \param buf the input buffer - * \param len length of the input buffer - * \param objects pointer to list where decoded objects will be stored. - * - * \retval 1 if all objects decoded, 0 if all objects could not be decoded ( - * unknown group/variations) - */ -static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf, - uint32_t len, DNP3ObjectList *objects) -{ - int retval = 0; - - if (buf == NULL || len == 0) { - return 1; - } - - while (len) { - uint32_t offset = 0; - - if (len < sizeof(DNP3ObjHeader)) { - goto done; - } - DNP3ObjHeader *header = (DNP3ObjHeader *)buf; - offset += sizeof(DNP3ObjHeader); - - DNP3Object *object = DNP3ObjectAlloc(); - if (unlikely(object == NULL)) { - goto done; - } - TAILQ_INSERT_TAIL(objects, object, next); - - object->group = header->group; - object->variation = header->variation; - object->qualifier = header->qualifier; - object->prefix_code = DNP3_OBJ_PREFIX(header->qualifier); - object->range_code = DNP3_OBJ_RANGE(header->qualifier); - - /* IEEE 1815-2012, Table 4-5. */ - switch (object->range_code) { - case 0x00: - case 0x03: { - /* 1 octet start and stop indexes OR 1 octet start and - * stop virtual addresses. */ - if (offset + (sizeof(uint8_t) * 2) > len) { - /* Not enough data. */ - SCLogDebug("Not enough data."); - goto not_enough_data; - } - object->start = buf[offset++]; - object->stop = buf[offset++]; - object->count = object->stop - object->start + 1; - break; - } - case 0x01: - case 0x04: { - /* 2 octet start and stop indexes OR 2 octect start - * and stop virtual addresses. */ - if (offset + (sizeof(uint16_t) * 2) > len) { - /* Not enough data. */ - SCLogDebug("Not enough data."); - goto not_enough_data; - } - object->start = DNP3_SWAP16(*(uint16_t *)(buf + offset)); - offset += sizeof(uint16_t); - object->stop = DNP3_SWAP16(*(uint16_t *)(buf + offset)); - offset += sizeof(uint16_t); - object->count = object->stop - object->start + 1; - break; - } - case 0x02: - case 0x05: { - /* 4 octet start and stop indexes OR 4 octect start - * and stop virtual addresses. */ - if (offset + (sizeof(uint32_t) * 2) > len) { - /* Not enough data. */ - SCLogDebug("Not enough data."); - goto not_enough_data; - } - object->start = DNP3_SWAP32(*(uint32_t *)(buf + offset)); - offset += sizeof(uint32_t); - object->stop = DNP3_SWAP32(*(uint32_t *)(buf + offset)); - offset += sizeof(uint32_t); - object->count = object->stop - object->start + 1; - break; - } - case 0x06: - /* No range field. */ - object->count = 0; - break; - case 0x07: - /* 1 octet count of objects. */ - if (offset + sizeof(uint8_t) > len) { - SCLogDebug("Not enough data."); - goto not_enough_data; - } - object->count = buf[offset]; - offset += sizeof(uint8_t); - break; - case 0x08: { - /* 2 octet count of objects. */ - if (offset + sizeof(uint16_t) > len) { - SCLogDebug("Not enough data."); - goto not_enough_data; - } - object->count = DNP3_SWAP16(*(uint16_t *)(buf + offset)); - offset += sizeof(uint16_t); - break; - } - case 0x09: { - /* 4 octet count of objects. */ - if (offset + sizeof(uint32_t) > len) { - SCLogDebug("Not enough data."); - goto not_enough_data; - } - object->count = DNP3_SWAP32(*(uint32_t *)(buf + offset)); - offset += sizeof(uint32_t); - break; - } - case 0x0b: { - if (offset + sizeof(uint8_t) > len) { - /* Not enough data. */ - SCLogDebug("Not enough data."); - goto not_enough_data; - } - object->count = *(uint8_t *)(buf + offset); - offset += sizeof(uint8_t); - break; - } - default: - SCLogDebug("Range code 0x%02x is reserved.", - object->range_code); - goto done; - } - - buf += offset; - len -= offset; - - if (object->variation == 0 || object->count == 0) { - goto next; - } - - int event = DNP3DecodeObject(header->group, header->variation, &buf, - &len, object->prefix_code, object->start, object->count, - object->points); - if (event) { - DNP3SetEventTx(tx, DNP3_DECODER_EVENT_UNKNOWN_OBJECT); - goto done; - } - - next: - continue; - } - - /* All objects were decoded. */ - retval = 1; - -not_enough_data: -done: - return retval; -} - -/** - * \brief Handle DNP3 request user data. - * - * \param dnp3 the current DNP3State - * \param input pointer to the DNP3 frame (starting with link header) - * \param input_len length of the input frame - */ -static void DNP3HandleUserDataRequest(DNP3State *dnp3, const uint8_t *input, - uint32_t input_len) -{ - DNP3LinkHeader *lh; - DNP3TransportHeader th; - DNP3ApplicationHeader *ah; - DNP3Transaction *tx = NULL, *ttx; - - lh = (DNP3LinkHeader *)input; - - if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), - input_len - sizeof(DNP3LinkHeader))) { - return; - } - - th = input[sizeof(DNP3LinkHeader)]; - - if (!DNP3_TH_FIR(th)) { - TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { - if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && ttx->is_request && !ttx->done && - NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->th)) == DNP3_TH_SEQ(th)) { - tx = ttx; - break; - } - } - - if (tx == NULL) { - return; - } - - /* Update the saved transport header so subsequent segments - * will be matched to this sequence number. */ - tx->th = th; - } - else { - ah = (DNP3ApplicationHeader *)(input + sizeof(DNP3LinkHeader) + - sizeof(DNP3TransportHeader)); - - /* Ignore confirms - for now. */ - if (ah->function_code == DNP3_APP_FC_CONFIRM) { - return; - } - - /* Create a transaction. */ - tx = DNP3TxAlloc(dnp3, true); - if (unlikely(tx == NULL)) { - return; - } - tx->lh = *lh; - tx->th = th; - tx->ah = *ah; - } - - if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), - input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) { - - /* Malformed, set event and mark as done. */ - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); - tx->done = 1; - return; - } - - /* If this is not the final segment, just return. */ - if (!DNP3_TH_FIN(th)) { - return; - } - - tx->done = 1; - - if (DNP3DecodeApplicationObjects(tx, tx->buffer + sizeof(DNP3ApplicationHeader), - tx->buffer_len - sizeof(DNP3ApplicationHeader), &tx->objects)) { - tx->complete = 1; - } -} - -static void DNP3HandleUserDataResponse(DNP3State *dnp3, const uint8_t *input, - uint32_t input_len) -{ - DNP3LinkHeader *lh; - DNP3TransportHeader th; - DNP3ApplicationHeader *ah; - DNP3InternalInd *iin; - DNP3Transaction *tx = NULL, *ttx; - uint32_t offset = 0; - - lh = (DNP3LinkHeader *)input; - offset += sizeof(DNP3LinkHeader); - - if (!DNP3CheckUserDataCRCs(input + offset, input_len - offset)) { - return; - } - - th = input[offset++]; - - if (!DNP3_TH_FIR(th)) { - TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { - if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && !ttx->is_request && - !ttx->done && NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->th)) == DNP3_TH_SEQ(th)) { - tx = ttx; - break; - } - } - - if (tx == NULL) { - return; - } - - /* Replace the transport header in the transaction with this - * one in case there are more frames. */ - tx->th = th; - } - else { - ah = (DNP3ApplicationHeader *)(input + offset); - offset += sizeof(DNP3ApplicationHeader); - iin = (DNP3InternalInd *)(input + offset); - - tx = DNP3TxAlloc(dnp3, false); - if (unlikely(tx == NULL)) { - return; - } - tx->lh = *lh; - tx->th = th; - tx->ah = *ah; - tx->iin = *iin; - } - - BUG_ON(tx->is_request); - - if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), - input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); - return; - } - - if (!DNP3_TH_FIN(th)) { - return; - } - - tx->done = 1; - - offset = sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); - if (DNP3DecodeApplicationObjects( - tx, tx->buffer + offset, tx->buffer_len - offset, &tx->objects)) { - tx->complete = 1; - } -} - -/** - * \brief Decode the DNP3 request link layer. - * - * \retval number of bytes processed or -1 if the data stream does not look - * like DNP3. - */ -static int DNP3HandleRequestLinkLayer(DNP3State *dnp3, const uint8_t *input, - uint32_t input_len) -{ - SCEnter(); - uint32_t processed = 0; - - while (input_len) { - - /* Need at least enough bytes for a DNP3 header. */ - if (input_len < sizeof(DNP3LinkHeader)) { - break; - } - - DNP3LinkHeader *header = (DNP3LinkHeader *)input; - - if (!DNP3CheckStartBytes(header)) { - goto error; - } - - if (!DNP3CheckLinkHeaderCRC(header)) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); - goto error; - } - - uint32_t frame_len = DNP3CalculateLinkLength(header->len); - if (frame_len == 0) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); - goto error; - } - if (input_len < frame_len) { - /* Insufficient data, just break - will wait for more data. */ - break; - } - - /* Ignore non-user data for now. */ - if (!DNP3IsUserData(header)) { - goto next; - } - - /* Make sure the header length is large enough for transport and - * application headers. */ - if (!DNP3HasUserData(header, STREAM_TOSERVER)) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); - goto next; - } - - if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), - frame_len - sizeof(DNP3LinkHeader))) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); - goto next; - } - - DNP3HandleUserDataRequest(dnp3, input, frame_len); - - next: - /* Advance the input buffer. */ - input += frame_len; - input_len -= frame_len; - processed += frame_len; - } - - SCReturnInt(processed); -error: - /* Error out. Should only happen if this doesn't look like a DNP3 - * frame. */ - SCReturnInt(-1); -} - -/** - * \brief Handle incoming request data. - * - * The actual request PDU parsing is done in - * DNP3HandleRequestLinkLayer. This function takes care of buffering TCP - * date if a segment does not contain a complete frame (or contains - * multiple frames, but not the complete final frame). - */ -static AppLayerResult DNP3ParseRequest(Flow *f, void *state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - SCEnter(); - DNP3State *dnp3 = (DNP3State *)state; - DNP3Buffer *buffer = &dnp3->request_buffer; - int processed = 0; - - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - if (input_len == 0) { - SCReturnStruct(APP_LAYER_OK); - } - - if (buffer->len) { - if (!DNP3BufferAdd(buffer, input, input_len)) { - goto error; - } - processed = DNP3HandleRequestLinkLayer(dnp3, - buffer->buffer + buffer->offset, - buffer->len - buffer->offset); - if (processed < 0) { - goto error; - } - buffer->offset += processed; - DNP3BufferTrim(buffer); - } - else { - processed = DNP3HandleRequestLinkLayer(dnp3, input, input_len); - if (processed < 0) { - SCLogDebug("Failed to process request link layer."); - goto error; - } - - input += processed; - input_len -= processed; - - /* Not all data was processed, buffer it. */ - if (input_len) { - if (!DNP3BufferAdd(buffer, input, input_len)) { - goto error; - } - } - } - - SCReturnStruct(APP_LAYER_OK); - -error: - /* Reset the buffer. */ - DNP3BufferReset(buffer); - SCReturnStruct(APP_LAYER_ERROR); -} - -/** - * \brief Decode the DNP3 response link layer. - * - * \retval number of bytes processed or -1 if the data stream does not - * like look DNP3. - */ -static int DNP3HandleResponseLinkLayer(DNP3State *dnp3, const uint8_t *input, - uint32_t input_len) -{ - SCEnter(); - uint32_t processed = 0; - - while (input_len) { - - /* Need at least enough bytes for a DNP3 header. */ - if (input_len < sizeof(DNP3LinkHeader)) { - break; - } - - DNP3LinkHeader *header = (DNP3LinkHeader *)input; - - if (!DNP3CheckStartBytes(header)) { - goto error; - } - - if (!DNP3CheckLinkHeaderCRC(header)) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); - goto error; - } - - /* Calculate the number of bytes needed to for this frame. */ - uint32_t frame_len = DNP3CalculateLinkLength(header->len); - if (frame_len == 0) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); - goto error; - } - if (input_len < frame_len) { - /* Insufficient data, just break - will wait for more data. */ - break; - } - - /* Only handle user data frames for now. */ - if (!DNP3IsUserData(header)) { - goto next; - } - - /* Make sure the header length is large enough for transport and - * application headers. */ - if (!DNP3HasUserData(header, STREAM_TOCLIENT)) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); - goto error; - } - - if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), - frame_len - sizeof(DNP3LinkHeader))) { - DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); - goto next; - } - - DNP3HandleUserDataResponse(dnp3, input, frame_len); - - next: - /* Advance the input buffer. */ - input += frame_len; - input_len -= frame_len; - processed += frame_len; - } - - SCReturnInt(processed); -error: - /* Error out. Should only happen if the data stream no longer - * looks like DNP3. */ - SCReturnInt(-1); -} - -/** - * \brief Parse incoming data. - * - * This is the entry function for DNP3 application layer data. Its - * main responsibility is buffering incoming data that cannot be - * processed. - * - * See DNP3ParseResponsePDUs for DNP3 frame handling. - */ -static AppLayerResult DNP3ParseResponse(Flow *f, void *state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - SCEnter(); - - DNP3State *dnp3 = (DNP3State *)state; - DNP3Buffer *buffer = &dnp3->response_buffer; - int processed; - - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - if (buffer->len) { - if (!DNP3BufferAdd(buffer, input, input_len)) { - goto error; - } - processed = DNP3HandleResponseLinkLayer(dnp3, - buffer->buffer + buffer->offset, - buffer->len - buffer->offset); - if (processed < 0) { - goto error; - } - buffer->offset += processed; - DNP3BufferTrim(buffer); - } - else { - - /* Check if this is a banner, ignore if it is. */ - if (DNP3ContainsBanner(input, input_len)) { - goto done; - } - - processed = DNP3HandleResponseLinkLayer(dnp3, input, input_len); - if (processed < 0) { - goto error; - } - input += processed; - input_len -= processed; - - /* Not all data was processed, buffer it. */ - if (input_len) { - if (!DNP3BufferAdd(buffer, input, input_len)) { - goto error; - } - } - } - -done: - SCReturnStruct(APP_LAYER_OK); - -error: - /* An error occurred while processing DNP3 frames. Dump the - * buffer as we can't be assured that they are valid anymore. */ - DNP3BufferReset(buffer); - SCReturnStruct(APP_LAYER_ERROR); -} - -static void *DNP3GetTx(void *alstate, uint64_t tx_id) -{ - SCEnter(); - DNP3State *dnp3 = (DNP3State *)alstate; - DNP3Transaction *tx = NULL; - uint64_t tx_num = tx_id + 1; - - if (dnp3->curr && dnp3->curr->tx_num == (tx_num)) { - SCReturnPtr(dnp3->curr, "void"); - } - - TAILQ_FOREACH(tx, &dnp3->tx_list, next) { - if (tx_num != tx->tx_num) { - continue; - } - SCReturnPtr(tx, "void"); - } - - SCReturnPtr(NULL, "void"); -} - -static uint64_t DNP3GetTxCnt(void *state) -{ - SCEnter(); - uint64_t count = ((uint64_t)((DNP3State *)state)->transaction_max); - SCReturnUInt(count); -} - -/** - * \brief Free all the objects in a DNP3ObjectList. - */ -static void DNP3TxFreeObjectList(DNP3ObjectList *objects) -{ - DNP3Object *object; - - while ((object = TAILQ_FIRST(objects)) != NULL) { - TAILQ_REMOVE(objects, object, next); - DNP3ObjectFree(object); - } -} - -/** - * \brief Free a DNP3 transaction. - */ -static void DNP3TxFree(DNP3Transaction *tx) -{ - SCEnter(); - - if (tx->buffer != NULL) { - SCFree(tx->buffer); - } - - AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); - - if (tx->tx_data.de_state != NULL) { - DetectEngineStateFree(tx->tx_data.de_state); - } - - DNP3TxFreeObjectList(&tx->objects); - - SCFree(tx); - SCReturn; -} - -/** - * \brief Free a transaction by ID on a specific DNP3 state. - * - * This function is called by the app-layer to free a transaction on a - * specific DNP3 state object. - */ -static void DNP3StateTxFree(void *state, uint64_t tx_id) -{ - SCEnter(); - DNP3State *dnp3 = state; - DNP3Transaction *tx = NULL, *ttx; - uint64_t tx_num = tx_id + 1; - - TAILQ_FOREACH_SAFE(tx, &dnp3->tx_list, next, ttx) { - - if (tx->tx_num != tx_num) { - continue; - } - - if (tx == dnp3->curr) { - dnp3->curr = NULL; - } - - if (tx->tx_data.events != NULL) { - if (tx->tx_data.events->cnt <= dnp3->events) { - dnp3->events -= tx->tx_data.events->cnt; - } else { - dnp3->events = 0; - } - } - dnp3->unreplied--; - - /* Check flood state. */ - if (dnp3->flooded && dnp3->unreplied < DNP3_DEFAULT_REQ_FLOOD_COUNT) { - dnp3->flooded = 0; - } - - TAILQ_REMOVE(&dnp3->tx_list, tx, next); - DNP3TxFree(tx); - break; - } - - SCReturn; -} - -/** - * \brief Free a DNP3 state. - */ -static void DNP3StateFree(void *state) -{ - SCEnter(); - DNP3State *dnp3 = state; - DNP3Transaction *tx; - if (state != NULL) { - while ((tx = TAILQ_FIRST(&dnp3->tx_list)) != NULL) { - TAILQ_REMOVE(&dnp3->tx_list, tx, next); - DNP3TxFree(tx); - } - if (dnp3->request_buffer.buffer != NULL) { - SCFree(dnp3->request_buffer.buffer); - } - if (dnp3->response_buffer.buffer != NULL) { - SCFree(dnp3->response_buffer.buffer); - } - SCFree(dnp3); - } - SCReturn; -} - -/** - * \brief Called by the app-layer to get the state progress. - */ -static int DNP3GetAlstateProgress(void *tx, uint8_t direction) -{ - DNP3Transaction *dnp3tx = (DNP3Transaction *)tx; - DNP3State *dnp3 = dnp3tx->dnp3; - int retval = 0; - - /* If flooded, "ack" old transactions. */ - if (dnp3->flooded && (dnp3->transaction_max - - dnp3tx->tx_num >= DNP3_DEFAULT_REQ_FLOOD_COUNT)) { - SCLogDebug("flooded: returning tx as done."); - SCReturnInt(1); - } - - if (dnp3tx->complete) - retval = 1; - - SCReturnInt(retval); -} - -/** - * \brief App-layer support. - */ -static int DNP3StateGetEventInfo(const char *event_name, int *event_id, - AppLayerEventType *event_type) -{ - *event_id = SCMapEnumNameToValue(event_name, dnp3_decoder_event_table); - if (*event_id == -1) { - SCLogError("Event \"%s\" not present in " - "the DNP3 enum event map table.", - event_name); - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -/** - * \brief App-layer support. - */ -static int DNP3StateGetEventInfoById(int event_id, const char **event_name, - AppLayerEventType *event_type) -{ - *event_name = SCMapEnumValueToName(event_id, dnp3_decoder_event_table); - if (*event_name == NULL) { - SCLogError("Event \"%d\" not present in " - "the DNP3 enum event map table.", - event_id); - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static AppLayerTxData *DNP3GetTxData(void *vtx) -{ - DNP3Transaction *tx = (DNP3Transaction *)vtx; - return &tx->tx_data; -} - -static AppLayerStateData *DNP3GetStateData(void *vstate) -{ - DNP3State *state = (DNP3State *)vstate; - return &state->state_data; -} - -/** - * \brief Check if the prefix code is a size prefix. - * - * \retval 1 if the prefix_code specifies a size prefix, 0 if not. - */ -int DNP3PrefixIsSize(uint8_t prefix_code) -{ - switch (prefix_code) { - case 0x04: - case 0x05: - case 0x06: - return 1; - break; - default: - return 0; - } -} - -static AppLayerGetTxIterTuple DNP3GetTxIterator(const uint8_t ipproto, const AppProto alproto, - void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) -{ - DNP3State *dnp_state = (DNP3State *)alstate; - AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; - if (dnp_state) { - DNP3Transaction *tx_ptr; - if (state->un.ptr == NULL) { - tx_ptr = TAILQ_FIRST(&dnp_state->tx_list); - } else { - tx_ptr = (DNP3Transaction *)state->un.ptr; - } - if (tx_ptr) { - while (tx_ptr->tx_num < min_tx_id + 1) { - tx_ptr = TAILQ_NEXT(tx_ptr, next); - if (!tx_ptr) { - return no_tuple; - } - } - if (tx_ptr->tx_num >= max_tx_id + 1) { - return no_tuple; - } - state->un.ptr = TAILQ_NEXT(tx_ptr, next); - AppLayerGetTxIterTuple tuple = { - .tx_ptr = tx_ptr, - .tx_id = tx_ptr->tx_num - 1, - .has_next = (state->un.ptr != NULL), - }; - return tuple; - } - } - return no_tuple; -} - -/** - * \brief Register the DNP3 application protocol parser. - */ -void RegisterDNP3Parsers(void) -{ - SCEnter(); - - const char *proto_name = "dnp3"; - - if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_DNP3, proto_name); - - if (RunmodeIsUnittests()) { - AppLayerProtoDetectPPRegister(IPPROTO_TCP, DNP3_DEFAULT_PORT, - ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), STREAM_TOSERVER, - DNP3ProbingParser, DNP3ProbingParser); - } - else { - if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, - proto_name, ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), - DNP3ProbingParser, DNP3ProbingParser)) { - return; - } - } - - } else { - SCLogConfig("Protocol detection and parser disabled for DNP3."); - SCReturn; - } - - if (AppLayerParserConfParserEnabled("tcp", proto_name)) - { - SCLogConfig("Registering DNP3/tcp parsers."); - - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOSERVER, - DNP3ParseRequest); - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOCLIENT, - DNP3ParseResponse); - - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_DNP3, - DNP3StateAlloc, DNP3StateFree); - - AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTx); - AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTxIterator); - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTxCnt); - AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_DNP3, - DNP3StateTxFree); - - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNP3, - DNP3GetAlstateProgress); - AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_DNP3, 1, 1); - - AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNP3, - DNP3StateGetEventInfo); - AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_DNP3, - DNP3StateGetEventInfoById); - - AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_DNP3, - DNP3GetTxData); - AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetStateData); - } - else { - SCLogConfig("Parser disabled for protocol %s. " - "Protocol detection still on.", proto_name); - } - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_DNP3, - DNP3ParserRegisterTests); -#endif - - SCReturn; -} - -#ifdef UNITTESTS - -#include "flow-util.h" -#include "stream-tcp.h" - -/** - * \brief Utility function to fix CRCs when mangling a frame. - */ -static void DNP3FixCrc(uint8_t *data, uint32_t len) -{ - uint32_t block_size; - - while (len) { - if (len >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { - block_size = DNP3_BLOCK_SIZE; - } else { - block_size = len - DNP3_CRC_LEN; - } - uint16_t crc = DNP3ComputeCRC(data, block_size); - data[block_size + 1] = (crc >> 8) & 0xff; - data[block_size] = crc & 0xff; - data += block_size + DNP3_CRC_LEN; - len -= block_size + DNP3_CRC_LEN; - } -} - -/** - * \test Test CRC checking on partial and full blocks. - */ -static int DNP3ParserTestCheckCRC(void) -{ - uint8_t request[] = { - /* DNP3 start. */ - 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, - 0xa5, 0xe9, - - /* Transport header. */ - 0xff, - - /* Application layer - segment 1. */ - 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, - 0xef, - - /* Application layer - segment 2. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff - }; - - /* Check link header CRC. */ - FAIL_IF(!DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); - - /* Check first application layer segment. */ - FAIL_IF(!DNP3CheckCRC(request + sizeof(DNP3LinkHeader), - DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Change a byte in link header, should fail now. */ - request[2]++; - FAIL_IF(DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); - - /* Change a byte in the first application segment, should fail - * now. */ - request[sizeof(DNP3LinkHeader) + 3]++; - FAIL_IF(DNP3CheckCRC(request + sizeof(DNP3LinkHeader), - DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); -#endif - - PASS; -} - -/** - * \test Test validation of all CRCs in user data. - */ -static int DNP3CheckUserDataCRCsTest(void) -{ - /* Multi-block data with valid CRCs. */ - uint8_t data_valid[] = { - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0x00, 0x00, 0x00, 0x00, - 0x00, - 0xff, 0xff, /* CRC. */ - }; - FAIL_IF(!DNP3CheckUserDataCRCs(data_valid, sizeof(data_valid))); - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Multi-block data with one non-crc byte altered. */ - uint8_t data_invalid[] = { - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0x00, 0x00, 0x00, 0x00, - 0x01, /* Invalid byte. */ - 0xff, 0xff, /* CRC. */ - }; - FAIL_IF(DNP3CheckUserDataCRCs(data_invalid, sizeof(data_invalid))); - - /* 1 byte - need at least 3. */ - uint8_t one_byte_nocrc[] = { 0x01 }; - FAIL_IF(DNP3CheckUserDataCRCs(one_byte_nocrc, sizeof(one_byte_nocrc))); - - /* 2 bytes - need at least 3. */ - uint8_t two_byte_nocrc[] = { 0x01, 0x02 }; - FAIL_IF(DNP3CheckUserDataCRCs(two_byte_nocrc, sizeof(two_byte_nocrc))); -#endif - - /* 3 bytes, valid CRC. */ - uint8_t three_bytes_good_crc[] = { 0x00, 0x00, 0x00 }; - *(uint16_t *)(three_bytes_good_crc + 1) = DNP3ComputeCRC( - three_bytes_good_crc, 1); - FAIL_IF(!DNP3CheckUserDataCRCs(three_bytes_good_crc, - sizeof(three_bytes_good_crc))); - - PASS; -} - -/** - * \test Test the link layer length calculation. - * - * Test the calculation that converts the link provided in the DNP3 - * header to the actual length of the frame. That is the length with - * CRCs as the length in the header does not include CRCs. - */ -static int DNP3CalculateLinkLengthTest(void) -{ - /* These are invalid. */ - FAIL_IF(DNP3CalculateLinkLength(0) != 0); - FAIL_IF(DNP3CalculateLinkLength(1) != 0); - FAIL_IF(DNP3CalculateLinkLength(2) != 0); - FAIL_IF(DNP3CalculateLinkLength(3) != 0); - FAIL_IF(DNP3CalculateLinkLength(4) != 0); - - /* This is the minimum size. */ - FAIL_IF(DNP3CalculateLinkLength(5) != 10); - - /* 1 full user data blocks of data. */ - FAIL_IF(DNP3CalculateLinkLength(21) != 28); - - /* 2 full user data blocks of data. */ - FAIL_IF(DNP3CalculateLinkLength(37) != 46); - - /* 2 full user data blocks, plus one more byte. */ - /* 2 full user data blocks of data. */ - FAIL_IF(DNP3CalculateLinkLength(38) != 49); - - /* The maximum size. */ - FAIL_IF(DNP3CalculateLinkLength(255) != 292); - - PASS; -} - -/** - * \test The conversion of length with CRCs to the length without - * CRCs. - */ -static int DNP3CalculateTransportLengthWithoutCRCsTest(void) -{ - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(0) != -1); - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(1) != -1); - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(2) != 0); - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(3) != 1); - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(16) != 14); - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(17) != 15); - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(18) != 16); - - /* 19 bytes is not enough for a second block. */ - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(19) != -1); - - /* 20 bytes really isn't enough either, but is large enough to - * satisfy the CRC on the second block. */ - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(20) != 16); - - FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(21) != 17); - - PASS; -} - -/** - * \test Test the validation of the link header CRC. - */ -static int DNP3ParserCheckLinkHeaderCRC(void) -{ - /* DNP3 frame with valid headers and CRCs. */ - uint8_t request[] = { - /* DNP3 start. */ - 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, - 0xa5, 0xe9, - - /* Transport header. */ - 0xff, - - /* Application layer. */ - 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, - 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff - }; - - DNP3LinkHeader *header = (DNP3LinkHeader *)request; - FAIL_IF(!DNP3CheckLinkHeaderCRC(header)); - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Alter a byte in the header. */ - request[4] = 0; - FAIL_IF(DNP3CheckLinkHeaderCRC(header)); -#endif - - PASS; -} - -/** - * \test Test removal of CRCs from user data. - */ -static int DNP3ReassembleApplicationLayerTest01(void) -{ - uint32_t reassembled_len = 0; - uint8_t *output = NULL; - - uint8_t payload[] = { - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0x00, 0x00, 0x00, 0x00, - 0x00, - 0xff, 0xff, /* CRC. */ - }; - - uint8_t expected[] = { - 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - /* CRC removed. */ - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - /* CRC removed. */ - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - /* CRC removed. */ - 0x00, 0x00, 0x00, 0x00, - 0x00 - /* CRC removed. */ - }; - - /* Valid frame. */ - FAIL_IF(!DNP3ReassembleApplicationLayer(payload, - sizeof(payload), &output, &reassembled_len)); - FAIL_IF(output == NULL); - FAIL_IF(reassembled_len != sizeof(expected)); - FAIL_IF(memcmp(expected, output, reassembled_len)); - SCFree(output); - - /* 1 byte, invalid. */ - reassembled_len = 0; - output = NULL; - FAIL_IF(DNP3ReassembleApplicationLayer(payload, 1, &output, - &reassembled_len)); - FAIL_IF(output != NULL); - FAIL_IF(reassembled_len != 0); - - /* 2 bytes, invalid. */ - reassembled_len = 0; - output = NULL; - FAIL_IF(DNP3ReassembleApplicationLayer(payload, 2, &output, - &reassembled_len)); - FAIL_IF(output != NULL); - FAIL_IF(reassembled_len != 0); - - /* 3 bytes, minimum - but that would only be the transport header - * which isn't included in the output. */ - reassembled_len = 0; - output = NULL; - FAIL_IF(DNP3ReassembleApplicationLayer(payload, 3, &output, - &reassembled_len)); - FAIL_IF(output != NULL); - FAIL_IF(reassembled_len != 0); - - /* 4 bytes is the minimum to get any reassembled data. */ - reassembled_len = 0; - output = NULL; - FAIL_IF(!DNP3ReassembleApplicationLayer(payload, 4, &output, - &reassembled_len)); - FAIL_IF(output == NULL); - FAIL_IF(reassembled_len != 1); - - /* Last block too short (by 1 byte) for data + CRC. */ - uint8_t short_payload1[] = { - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0x00, 0x00 - }; - reassembled_len = 0; - FAIL_IF(DNP3ReassembleApplicationLayer(short_payload1, - sizeof(short_payload1), &output, &reassembled_len)); - - /* Last block too short (by 2 bytes) for data + CRC. */ - uint8_t short_payload2[] = { - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0xff, 0xc9, 0x05, 0x0c, - 0x01, 0x28, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, - 0x72, 0xef, /* CRC. */ - - 0x00, - }; - reassembled_len = 0; - FAIL_IF(DNP3ReassembleApplicationLayer(short_payload2, - sizeof(short_payload2), &output, &reassembled_len)); - - PASS; -} - -/** - * \test Test the probing parser. - */ -static int DNP3ProbingParserTest(void) -{ - uint8_t pkt[] = { - 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00, - 0xbd, 0x71 - }; - uint8_t rdir = 0; - - /* Valid frame. */ - FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_DNP3); - - /* Send too little bytes. */ - FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(DNP3LinkHeader) - 1, &rdir) != ALPROTO_UNKNOWN); - - /* Bad start bytes. */ - pkt[0] = 0x06; - FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_FAILED); - - /* Restore start byte. */ - pkt[0] = 0x05; - - /* Set the length to a value less than the minimum length of 5. */ - pkt[2] = 0x03; - FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_FAILED); - - /* Send a banner. */ - char mybanner[] = "Welcome to DNP3 SCADA."; - FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, (uint8_t *)mybanner, sizeof(mybanner) - 1, - &rdir) != ALPROTO_DNP3); - FAIL_IF(rdir != STREAM_TOCLIENT); - - PASS; -} - -/** - * \test Test a basic request/response. - */ -static int DNP3ParserTestRequestResponse(void) -{ - DNP3State *state = NULL; - - uint8_t request[] = { - /* DNP3 start. */ - 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, - 0xa5, 0xe9, - - /* Transport header. */ - 0xff, - - /* Application layer. */ - 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, - 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff - }; - - uint8_t response[] = { - /* DNP3 start. */ - 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, - 0xe2, 0x59, - - /* Transport header. */ - 0xc3, - - /* Application layer. */ - 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, - 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, - 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff - }; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow flow; - TcpSession ssn; - - memset(&flow, 0, sizeof(flow)); - memset(&ssn, 0, sizeof(ssn)); - - flow.protoctx = (void *)&ssn; - flow.proto = IPPROTO_TCP; - flow.alproto = ALPROTO_DNP3; - - StreamTcpInitConfig(true); - - SCMutexLock(&flow.m); - FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOSERVER, request, sizeof(request))); - SCMutexUnlock(&flow.m); - - state = flow.alstate; - FAIL_IF(state == NULL); - - DNP3Transaction *tx = DNP3GetTx(state, 0); - FAIL_IF(tx == NULL); - FAIL_IF(tx->tx_num != 1); - FAIL_IF(tx != state->curr); - FAIL_IF(tx->buffer == NULL); - FAIL_IF(tx->buffer_len != 20); - FAIL_IF(tx->ah.function_code != DNP3_APP_FC_DIR_OPERATE); - - SCMutexLock(&flow.m); - FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOCLIENT, response, sizeof(response))); - SCMutexUnlock(&flow.m); - DNP3Transaction *tx0 = DNP3GetTx(state, 1); - FAIL_IF(tx0 == NULL); - FAIL_IF(tx0 == tx); - FAIL_IF(!tx0->done); - FAIL_IF(tx0->buffer == NULL); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&flow); - PASS; -} - -/** - * \test Test an unsolicited response from an outstation. - * - * This is kind of like a request initiated from the "server". - */ -static int DNP3ParserTestUnsolicitedResponseConfirm(void) -{ - DNP3State *state = NULL; - - /* Unsolicited response with confirm bit set. */ - uint8_t response[] = { - 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, - 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, - 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, - 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9 - }; - - /* Confirm. */ - uint8_t confirm[] = { - 0x05, 0x64, 0x08, 0xc4, 0x02, 0x00, - 0x01, 0x00, 0xd3, 0xb7, 0xc0, 0xda, 0x00, 0x6a, - 0x3d - }; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow flow; - TcpSession ssn; - - memset(&flow, 0, sizeof(flow)); - memset(&ssn, 0, sizeof(ssn)); - - flow.protoctx = (void *)&ssn; - flow.proto = IPPROTO_TCP; - flow.alproto = ALPROTO_DNP3; - - StreamTcpInitConfig(true); - - SCMutexLock(&flow.m); - FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOCLIENT, response, sizeof(response))); - SCMutexUnlock(&flow.m); - - state = flow.alstate; - FAIL_IF(state == NULL); - - DNP3Transaction *tx = DNP3GetTx(state, 0); - FAIL_IF(tx == NULL); - FAIL_IF(tx->tx_num != 1); - FAIL_IF(tx != state->curr); - FAIL_IF(!tx->done); - FAIL_IF(tx->ah.function_code != DNP3_APP_FC_UNSOLICITED_RESP); - - SCMutexLock(&flow.m); - FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOSERVER, confirm, sizeof(confirm))); - SCMutexUnlock(&flow.m); - - /* Confirms are ignored currently. With the move to - unidirectional transactions it might be easy to support these - now. */ - DNP3Transaction *resptx = DNP3GetTx(state, 1); - FAIL_IF(resptx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&flow); - PASS; -} - -/** - * \test Test flood state. - * - * Note that flood state needs to revisited with the modification to a - * unidirectional protocol. - */ -static int DNP3ParserTestFlooded(void) -{ - DNP3State *state = NULL; - - uint8_t request[] = { - /* DNP3 start. */ - 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, - 0xa5, 0xe9, - - /* Transport header. */ - 0xff, - - /* Application layer. */ - 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, - 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff - }; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow flow; - TcpSession ssn; - - memset(&flow, 0, sizeof(flow)); - memset(&ssn, 0, sizeof(ssn)); - - flow.protoctx = (void *)&ssn; - flow.proto = IPPROTO_TCP; - flow.alproto = ALPROTO_DNP3; - - StreamTcpInitConfig(true); - - SCMutexLock(&flow.m); - FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOSERVER, request, sizeof(request))); - SCMutexUnlock(&flow.m); - - state = flow.alstate; - FAIL_IF(state == NULL); - - DNP3Transaction *tx = DNP3GetTx(state, 0); - FAIL_IF(tx == NULL); - FAIL_IF(tx->tx_num != 1); - FAIL_IF(tx != state->curr); - FAIL_IF(tx->buffer == NULL); - FAIL_IF(tx->buffer_len != 20); - FAIL_IF(tx->ah.function_code != DNP3_APP_FC_DIR_OPERATE); - FAIL_IF_NOT(tx->done); - FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER)); - - for (int i = 0; i < DNP3_DEFAULT_REQ_FLOOD_COUNT - 1; i++) { - SCMutexLock(&flow.m); - FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOSERVER, request, sizeof(request))); - SCMutexUnlock(&flow.m); - } - FAIL_IF(state->flooded); - FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER)); - - /* One more request should trip us into flooded state. */ - SCMutexLock(&flow.m); - FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOSERVER, request, sizeof(request))); - SCMutexUnlock(&flow.m); - FAIL_IF(!state->flooded); - - /* Progress for the oldest tx should return 1. */ - FAIL_IF(!DNP3GetAlstateProgress(tx, 0)); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&flow); - PASS; -} - -/** - * \test Test parsing of partial frames. - * - * As DNP3 operates over TCP, it is possible that a partial DNP3 frame - * is received. Test that the partial frame will be buffered until the - * remainder is seen. - */ -static int DNP3ParserTestPartialFrame(void) -{ - DNP3State *state = NULL; - DNP3Transaction *tx; - int r; - - uint8_t request_partial1[] = { - /* DNP3 start. */ - 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, - 0xa5, 0xe9, - - /* Transport header. */ - 0xff, - - /* Application layer. */ - 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, - }; - - uint8_t request_partial2[] = { - /* Remainder of application layer. */ - 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, - 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff - }; - - uint8_t response_partial1[] = { - /* DNP3 start. */ - 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, - 0xe2, 0x59, - - /* Transport header. */ - 0xc3, - - /* Application layer. */ - 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, - }; - - uint8_t response_partial2[] = { - 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, - 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff - }; - - /* Boiler plate for app layer setup. */ - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow flow; - TcpSession ssn; - memset(&flow, 0, sizeof(flow)); - memset(&ssn, 0, sizeof(ssn)); - flow.protoctx = (void *)&ssn; - flow.proto = IPPROTO_TCP; - flow.alproto = ALPROTO_DNP3; - StreamTcpInitConfig(true); - - /* Pass in the first partial frame. */ - - SCMutexLock(&flow.m); - r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOSERVER, request_partial1, sizeof(request_partial1)); - SCMutexUnlock(&flow.m); - FAIL_IF(r != 0); - - /* Frame should just be buffered, but not yet processed. */ - state = flow.alstate; - FAIL_IF(state == NULL); - FAIL_IF(state->request_buffer.len != sizeof(request_partial1)); - FAIL_IF(state->request_buffer.offset != 0); - FAIL_IF(memcmp(state->request_buffer.buffer, request_partial1, - sizeof(request_partial1))); - - /* There should not be a transaction yet. */ - FAIL_IF(state->transaction_max != 0); - FAIL_IF(DNP3GetTx(state, 0) != NULL); - - /* Send the second partial. */ - SCMutexLock(&flow.m); - r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOSERVER, request_partial2, sizeof(request_partial2)); - SCMutexUnlock(&flow.m); - FAIL_IF(r != 0); - - /* The second partial completed the frame, the buffer should now - * be clear. */ - FAIL_IF(state->request_buffer.len != 0); - FAIL_IF(state->request_buffer.offset != 0); - - /* Should now have a complete transaction. */ - tx = DNP3GetTx(state, 0); - FAIL_IF(tx == NULL); - FAIL_IF(tx->tx_num != 1); - FAIL_IF(tx != state->curr); - FAIL_IF(tx->buffer == NULL); - FAIL_IF(tx->buffer_len != 20); - FAIL_IF(tx->ah.function_code != DNP3_APP_FC_DIR_OPERATE); - - /* Send partial response. */ - SCMutexLock(&flow.m); - r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOCLIENT, response_partial1, sizeof(response_partial1)); - SCMutexUnlock(&flow.m); - FAIL_IF(r != 0); - FAIL_IF(state->response_buffer.len != sizeof(response_partial1)); - FAIL_IF(state->response_buffer.offset != 0); - tx = DNP3GetTx(state, 1); - FAIL_IF_NOT_NULL(tx); - - /* Send rest of response. */ - SCMutexLock(&flow.m); - r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOCLIENT, response_partial2, sizeof(response_partial2)); - SCMutexUnlock(&flow.m); - FAIL_IF(r != 0); - - /* Buffer should now be empty. */ - FAIL_IF(state->response_buffer.len != 0); - FAIL_IF(state->response_buffer.offset != 0); - - /* There should now be a response transaction. */ - tx = DNP3GetTx(state, 1); - FAIL_IF_NULL(tx); - FAIL_IF(tx->buffer == NULL); - FAIL_IF(tx->buffer_len == 0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&flow); - PASS; -} - -/** - * \test Test multiple DNP3 frames in one TCP read. - */ -static int DNP3ParserTestMultiFrame(void) -{ - DNP3State *state = NULL; - - /* Unsolicited response 1. */ - uint8_t unsol_response1[] = { - 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, - 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, - 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, - 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9, - }; - - /* Unsolicited response 2. */ - uint8_t unsol_response2[] = { - 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, - 0x89, 0xe5, 0xc5, 0xfb, 0x82, 0x00, 0x00, 0x02, - 0x02, 0x17, 0x01, 0x0c, 0x01, 0xd8, 0x75, 0xd8, - 0x32, 0x4c, 0xc9, 0x3c, 0x01, 0xa1, 0xc9, - }; - - uint8_t combined[sizeof(unsol_response1) + sizeof(unsol_response2)]; - memcpy(combined, unsol_response1, sizeof(unsol_response1)); - memcpy(combined + sizeof(unsol_response1), unsol_response2, - sizeof(unsol_response2)); - - /* Setup. */ - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow flow; - TcpSession ssn; - int r; - memset(&flow, 0, sizeof(flow)); - memset(&ssn, 0, sizeof(ssn)); - flow.protoctx = (void *)&ssn; - flow.proto = IPPROTO_TCP; - flow.alproto = ALPROTO_DNP3; - StreamTcpInitConfig(true); - - SCMutexLock(&flow.m); - r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOCLIENT, combined, sizeof(combined)); - SCMutexUnlock(&flow.m); - FAIL_IF(r != 0); - - state = flow.alstate; - FAIL_IF(state == NULL); - FAIL_IF(state->transaction_max != 2); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&flow); - PASS; -} - -/** - * \test Test the parsing of a request PDU. - * - * The PDU under test contains a single read request object: - * - Group: 1 - * - Variation: 0 - * - Count: 0 - */ -static int DNP3ParserTestParsePDU01(void) -{ - /* Frame to be tested. This frame is a DNP3 request with one read - * request data object, group 1, variation 0. */ - const uint8_t pkt[] = { - 0x05, 0x64, - 0x0b, 0xc4, 0x17, 0x00, 0xef, 0xff, 0xc4, 0x8f, - 0xe1, 0xc8, 0x01, 0x01, 0x00, 0x06, 0x77, 0x6e - }; - - DNP3State *dnp3state = DNP3StateAlloc(NULL, ALPROTO_UNKNOWN); - int pdus = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); - FAIL_IF(pdus < 1); - DNP3Transaction *dnp3tx = DNP3GetTx(dnp3state, 0); - FAIL_IF_NULL(dnp3tx); - FAIL_IF(!dnp3tx->is_request); - FAIL_IF(TAILQ_EMPTY(&dnp3tx->objects)); - DNP3Object *object = TAILQ_FIRST(&dnp3tx->objects); - FAIL_IF(object->group != 1 || object->variation != 0); - FAIL_IF(object->count != 0); - - DNP3StateFree(dnp3state); - PASS; -} - -/** - * \test Test the decode of a DNP3 fragment with a single 70:3 object. - */ -static int DNP3ParserDecodeG70V3Test(void) -{ - const uint8_t pkt[] = { - 0x05, 0x64, - 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, 0xc7, 0xee, - 0xc7, 0xc9, 0x1b, 0x46, 0x03, 0x5b, 0x01, 0x55, - 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, - 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, - 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, - 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, - 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, - 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, - 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, - 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, - 0xc4, 0x8b - }; - - DNP3State *dnp3state = DNP3StateAlloc(NULL, ALPROTO_UNKNOWN); - FAIL_IF_NULL(dnp3state); - int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); - FAIL_IF(bytes != sizeof(pkt)); - DNP3Transaction *tx = DNP3GetTx(dnp3state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NOT(tx->is_request); - DNP3Object *obj = TAILQ_FIRST(&tx->objects); - FAIL_IF_NULL(obj); - FAIL_IF_NOT(obj->group == 70); - FAIL_IF_NOT(obj->variation == 3); - FAIL_IF_NOT(obj->prefix_code == 0x5); - FAIL_IF_NOT(obj->range_code == 0xb); - FAIL_IF_NOT(obj->count == 1); - DNP3Point *point = TAILQ_FIRST(obj->points); - FAIL_IF_NULL(point); - FAIL_IF_NOT(point->prefix == 85); - FAIL_IF_NOT(point->size == 85); - FAIL_IF_NULL(point->data); - DNP3ObjectG70V3 *data = point->data; - FAIL_IF_NOT(strcmp( - data->filename, - "C:/temp/DNPDeviceConfiguration written to Remote Device.xml") == 0); - DNP3StateFree(dnp3state); - PASS; -} - -/** - * \brief Test that an alert is raised on an unknown object. - */ -static int DNP3ParserUnknownEventAlertTest(void) -{ - /* Valid DNP3 frame with 70:3 object. */ - uint8_t pkt[] = { - 0x05, 0x64, 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, - 0xc7, 0xee, - - 0xc7, 0xc9, 0x1b, - - /* Object and variation. Originally 70:3, now 70:99, an - * unknown object. */ - 0x46, 0x63, - - 0x5b, 0x01, 0x55, - 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, - 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, - 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, - 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, - 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, - 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, - 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, - 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, - 0xc4, 0x8b - }; - - DNP3FixCrc(pkt + 10, sizeof(pkt) - 10); - - DNP3State *dnp3state = DNP3StateAlloc(NULL, ALPROTO_UNKNOWN); - FAIL_IF_NULL(dnp3state); - int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); - FAIL_IF(bytes != sizeof(pkt)); - - DNP3StateFree(dnp3state); - PASS; -} - -/** -* \brief Test that an alert is raised on incorrect data. -*/ -static int DNP3ParserIncorrectUserData(void) -{ - uint8_t packet_bytes[] = { - 0x05, 0x64, 0x08, 0xc4, 0x03, 0x00, 0x04, 0x00, - 0xbf, 0xe9, 0xc1, 0xc1, 0x82, 0xc5, 0xee - }; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow flow; - TcpSession ssn; - memset(&flow, 0, sizeof(flow)); - memset(&ssn, 0, sizeof(ssn)); - flow.protoctx = (void *)&ssn; - flow.proto = IPPROTO_TCP; - flow.alproto = ALPROTO_DNP3; - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, - STREAM_TOCLIENT, packet_bytes, sizeof(packet_bytes)); - - FAIL_IF(r == 0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&flow); - PASS; -} - -#endif - -void DNP3ParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("DNP3ParserTestCheckCRC", DNP3ParserTestCheckCRC); - UtRegisterTest("DNP3ParserCheckLinkHeaderCRC", - DNP3ParserCheckLinkHeaderCRC); - UtRegisterTest("DNP3CheckUserDataCRCsTest", DNP3CheckUserDataCRCsTest); - UtRegisterTest("DNP3CalculateLinkLengthTest", DNP3CalculateLinkLengthTest); - UtRegisterTest("DNP3CalculateTransportLengthWithoutCRCsTest", - DNP3CalculateTransportLengthWithoutCRCsTest); - UtRegisterTest("DNP3ReassembleApplicationLayerTest01", - DNP3ReassembleApplicationLayerTest01); - UtRegisterTest("DNP3ProbingParserTest", DNP3ProbingParserTest); - UtRegisterTest("DNP3ParserTestRequestResponse", - DNP3ParserTestRequestResponse); - UtRegisterTest("DNP3ParserTestUnsolicitedResponseConfirm", - DNP3ParserTestUnsolicitedResponseConfirm); - UtRegisterTest("DNP3ParserTestPartialFrame", DNP3ParserTestPartialFrame); - UtRegisterTest("DNP3ParserTestMultiFrame", DNP3ParserTestMultiFrame); - UtRegisterTest("DNP3ParserTestFlooded", DNP3ParserTestFlooded); - UtRegisterTest("DNP3ParserTestParsePDU01", DNP3ParserTestParsePDU01); - UtRegisterTest("DNP3ParserDecodeG70V3Test", DNP3ParserDecodeG70V3Test); - UtRegisterTest("DNP3ParserUnknownEventAlertTest", - DNP3ParserUnknownEventAlertTest); - UtRegisterTest("DNP3ParserIncorrectUserData", DNP3ParserIncorrectUserData); -#endif -} diff --git a/src/app-layer-dnp3.h b/src/app-layer-dnp3.h deleted file mode 100644 index aae07f9c8095..000000000000 --- a/src/app-layer-dnp3.h +++ /dev/null @@ -1,260 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * DNP3 application layer protocol header file - */ - -#ifndef __APP_LAYER_DNP3_H__ -#define __APP_LAYER_DNP3_H__ - -#include "rust.h" -#if __BYTE_ORDER == __BIG_ENDIAN -#include "util-byte.h" -#endif - -/* DNP3 application request function codes. */ -#define DNP3_APP_FC_CONFIRM 0x00 -#define DNP3_APP_FC_READ 0x01 -#define DNP3_APP_FC_WRITE 0x02 -#define DNP3_APP_FC_SELECT 0x03 -#define DNP3_APP_FC_OPERATE 0x04 -#define DNP3_APP_FC_DIR_OPERATE 0x05 -#define DNP3_APP_FC_DIR_OPERATE_NR 0x06 -#define DNP3_APP_FC_FREEZE 0x07 -#define DNP3_APP_FC_FREEZE_NR 0x08 -#define DNP3_APP_FC_FREEZE_CLEAR 0x09 -#define DNP3_APP_FC_FREEZE_CLEAR_NR 0x0a -#define DNP3_APP_FC_FREEZE_AT_TIME 0x0b -#define DNP3_APP_FC_FREEZE_AT_TIME_NR 0x0c -#define DNP3_APP_FC_COLD_RESTART 0x0d -#define DNP3_APP_FC_WARM_RESTART 0x0e -#define DNP3_APP_FC_INITIALIZE_DATA 0x0f -#define DNP3_APP_FC_INITIALIZE_APPLICATION 0x10 -#define DNP3_APP_FC_START_APPLICATION 0x11 -#define DNP3_APP_FC_STOP_APPLICATION 0x12 -#define DNP3_APP_FC_SAVE_CONFIGURATION 0x13 -#define DNP3_APP_FC_ENABLE_UNSOLICITED 0x14 -#define DNP3_APP_FC_DISABLE_UNSOLICITED 0x15 -#define DNP3_APP_FC_ASSIGN_CLASS 0x16 -#define DNP3_APP_FC_DELAY_MEASUREMENT 0x17 -#define DNP3_APP_FC_RECORD_CURRENT_TIME 0x18 -#define DNP3_APP_FC_OPEN_TIME 0x19 -#define DNP3_APP_FC_CLOSE_FILE 0x1a -#define DNP3_APP_FC_DELETE_FILE 0x1b -#define DNP3_APP_FC_GET_FILE_INFO 0x1c -#define DNP3_APP_FC_AUTHENTICATE_FILE 0x1d -#define DNP3_APP_FC_ABORT_FILE 0x1e -#define DNP3_APP_FC_ACTIVATE_CONFIG 0x1f -#define DNP3_APP_FC_AUTH_REQ 0x20 -#define DNP3_APP_FC_AUTH_REQ_NR 0x21 - -/* DNP3 application response function codes. */ -#define DNP3_APP_FC_RESPONSE 0x81 -#define DNP3_APP_FC_UNSOLICITED_RESP 0x82 -#define DNP3_APP_FC_AUTH_RESP 0x83 - -/* Extract fields from the link control octet. */ -#define DNP3_LINK_DIR(control) (control & 0x80) -#define DNP3_LINK_PRI(control) (control & 0x40) -#define DNP3_LINK_FCB(control) (control & 0x20) -#define DNP3_LINK_FCV(control) (control & 0x10) -#define DNP3_LINK_FC(control) (control & 0x0f) - -/* Extract fields from transport layer header octet. */ -#define DNP3_TH_FIN(x) (x & 0x80) -#define DNP3_TH_FIR(x) (x & 0x40) -#define DNP3_TH_SEQ(x) (x & 0x3f) - -/* Extract fields from the application control octet. */ -#define DNP3_APP_FIR(x) (x & 0x80) -#define DNP3_APP_FIN(x) (x & 0x40) -#define DNP3_APP_CON(x) (x & 0x20) -#define DNP3_APP_UNS(x) (x & 0x10) -#define DNP3_APP_SEQ(x) (x & 0x0f) - -/* DNP3 values are stored in little endian on the wire, so swapping will be - * needed on big endian architectures. */ -#if __BYTE_ORDER == __BIG_ENDIAN -#define DNP3_SWAP16(x) SCByteSwap16(x) -#define DNP3_SWAP32(x) SCByteSwap32(x) -#define DNP3_SWAP64(x) SCByteSwap64(x) -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#define DNP3_SWAP16(x) x -#define DNP3_SWAP32(x) x -#define DNP3_SWAP64(x) x -#endif - -/* DNP3 decoder events. */ -enum { - DNP3_DECODER_EVENT_FLOODED = 1, - DNP3_DECODER_EVENT_LEN_TOO_SMALL, - DNP3_DECODER_EVENT_BAD_LINK_CRC, - DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC, - DNP3_DECODER_EVENT_MALFORMED, - DNP3_DECODER_EVENT_UNKNOWN_OBJECT, -}; - -/** - * \brief DNP3 link header. - */ -typedef struct DNP3LinkHeader_ { - uint8_t start_byte0; /**< First check byte. */ - uint8_t start_byte1; /**< Second check byte. */ - uint8_t len; /**< Length of PDU without CRCs. */ - uint8_t control; /**< Control flags. */ - uint16_t dst; /**< DNP3 destination address. */ - uint16_t src; /**< DNP3 source address. */ - uint16_t crc; /**< Link header CRC. */ -} __attribute__((__packed__)) DNP3LinkHeader; - -/** - * \brief DNP3 transport header. - */ -typedef uint8_t DNP3TransportHeader; - -/** - * \brief DNP3 application header. - */ -typedef struct DNP3ApplicationHeader_ { - uint8_t control; /**< Control flags. */ - uint8_t function_code; /**< Application function code. */ -} __attribute__((__packed__)) DNP3ApplicationHeader; - -/** - * \brief DNP3 internal indicators. - * - * Part of the application header for responses only. - */ -typedef struct DNP3InternalInd_ { - uint8_t iin1; - uint8_t iin2; -} __attribute__((__packed__)) DNP3InternalInd; - -/** - * \brief A struct used for buffering incoming data prior to reassembly. - */ -typedef struct DNP3Buffer_ { - uint8_t *buffer; - size_t size; - int len; - int offset; -} DNP3Buffer; - -/** - * \brief DNP3 application object header. - */ -typedef struct DNP3ObjHeader_ { - uint8_t group; - uint8_t variation; - uint8_t qualifier; -} __attribute__((packed)) DNP3ObjHeader; - -/** - * \brief DNP3 object point. - * - * Each DNP3 object can have 0 or more points representing the values - * of the object. - */ -typedef struct DNP3Point_ { - uint32_t prefix; /**< Prefix value for point. */ - uint32_t index; /**< Index of point. If the object is prefixed - * with an index then this will be that - * value. Otherwise this is the place the point - * was in the list of points (starting at 0). */ - uint32_t size; /**< Size of point if the object prefix was a - * size. */ - void *data; /**< Data for this point. */ - TAILQ_ENTRY(DNP3Point_) next; -} DNP3Point; - -typedef TAILQ_HEAD(DNP3PointList_, DNP3Point_) DNP3PointList; - -/** - * \brief Struct to hold the list of decoded objects. - */ -typedef struct DNP3Object_ { - uint8_t group; - uint8_t variation; - uint8_t qualifier; - uint8_t prefix_code; - uint8_t range_code; - uint32_t start; - uint32_t stop; - uint32_t count; - DNP3PointList *points; /**< List of points for this object. */ - - TAILQ_ENTRY(DNP3Object_) next; -} DNP3Object; - -typedef TAILQ_HEAD(DNP3ObjectList_, DNP3Object_) DNP3ObjectList; - -/** - * \brief DNP3 transaction. - */ -typedef struct DNP3Transaction_ { - AppLayerTxData tx_data; - - uint64_t tx_num; /**< Internal transaction ID. */ - bool is_request; /**< Is this tx a request? */ - - struct DNP3State_ *dnp3; - - uint8_t *buffer; /**< Reassembled request buffer. */ - uint32_t buffer_len; - DNP3ObjectList objects; - DNP3LinkHeader lh; - DNP3TransportHeader th; - DNP3ApplicationHeader ah; - DNP3InternalInd iin; - uint8_t done; - uint8_t complete; /**< Was the decode complete. It will not be - complete if we hit objects we do not know. */ - - TAILQ_ENTRY(DNP3Transaction_) next; -} DNP3Transaction; - -TAILQ_HEAD(TxListHead, DNP3Transaction_); - -/** - * \brief Per flow DNP3 state. - */ -typedef struct DNP3State_ { - AppLayerStateData state_data; - TAILQ_HEAD(, DNP3Transaction_) tx_list; - DNP3Transaction *curr; /**< Current transaction. */ - uint64_t transaction_max; - uint16_t events; - uint32_t unreplied; /**< Number of unreplied requests. */ - uint8_t flooded; /**< Flag indicating flood. */ - - DNP3Buffer request_buffer; /**< Request buffer for buffering - * incomplete request PDUs received - * over TCP. */ - DNP3Buffer response_buffer; /**< Response buffer for buffering - * incomplete response PDUs received - * over TCP. */ - -} DNP3State; - -void RegisterDNP3Parsers(void); -void DNP3ParserRegisterTests(void); -int DNP3PrefixIsSize(uint8_t); - -#endif /* __APP_LAYER_DNP3_H__ */ diff --git a/src/app-layer-enip-common.c b/src/app-layer-enip-common.c deleted file mode 100644 index 0608080e21f1..000000000000 --- a/src/app-layer-enip-common.c +++ /dev/null @@ -1,958 +0,0 @@ -/* Copyright (C) 2015-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Kevin Wong - * - * App-layer parser for ENIP protocol common code - * - */ - -#include "suricata-common.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "util-byte.h" -#include "pkt-var.h" -#include "util-profiling.h" - -#include "app-layer-enip-common.h" - -/** - * \brief Extract 8 bits and move up the offset - * @param res - * @param input - * @param offset - */ -static int ENIPExtractUint8(uint8_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) -{ - - if (input_len < sizeof(uint8_t) || *offset > (input_len - sizeof(uint8_t))) - { - SCLogDebug("ENIPExtractUint8: Parsing beyond payload length"); - return 0; - } - - *res = *(input + *offset); - *offset += sizeof(uint8_t); - return 1; -} - -/** - * \brief Extract 16 bits and move up the offset - * @param res - * @param input - * @param offset - */ -static int ENIPExtractUint16(uint16_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) -{ - - if (input_len < sizeof(uint16_t) || *offset > (input_len - sizeof(uint16_t))) { - SCLogDebug("ENIPExtractUint16: Parsing beyond payload length"); - return 0; - } - - if (ByteExtractUint16(res, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), - (const uint8_t *)(input + *offset)) == -1) { - return 0; - } - - *offset += sizeof(uint16_t); - return 1; -} - -/** - * \brief Extract 32 bits and move up the offset - * @param res - * @param input - * @param offset - */ -static int ENIPExtractUint32(uint32_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) -{ - - if (input_len < sizeof(uint32_t) || *offset > (input_len - sizeof(uint32_t))) - { - SCLogDebug("ENIPExtractUint32: Parsing beyond payload length"); - return 0; - } - - if (ByteExtractUint32(res, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), - (const uint8_t *)(input + *offset)) == -1) { - return 0; - } - - *offset += sizeof(uint32_t); - return 1; -} - -/** - * \brief Extract 64 bits and move up the offset - * @param res - * @param input - * @param offset - */ -static int ENIPExtractUint64(uint64_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) -{ - - if (input_len < sizeof(uint64_t) || *offset > (input_len - sizeof(uint64_t))) - { - SCLogDebug("ENIPExtractUint64: Parsing beyond payload length"); - return 0; - } - - if (ByteExtractUint64(res, BYTE_LITTLE_ENDIAN, sizeof(uint64_t), - (const uint8_t *)(input + *offset)) == -1) { - return 0; - } - - *offset += sizeof(uint64_t); - return 1; -} - - -/** - * \brief Create service entry, add to transaction - * @param tx Transaction - * @return service entry - */ -static CIPServiceEntry *CIPServiceAlloc(ENIPTransaction *tx) -{ - - CIPServiceEntry *svc = (CIPServiceEntry *) SCCalloc(1, - sizeof(CIPServiceEntry)); - if (unlikely(svc == NULL)) - return NULL; - - TAILQ_INIT(&svc->segment_list); - TAILQ_INIT(&svc->attrib_list); - - TAILQ_INSERT_TAIL(&tx->service_list, svc, next); - tx->service_count++; - return svc; - -} - -#if 0 -/** - * \brief Delete service entry - */ - -static void CIPServiceFree(void *s) -{ - SCEnter(); - if (s) - { - CIPServiceEntry *svc = (CIPServiceEntry *) s; - - SegmentEntry *seg = NULL; - while ((seg = TAILQ_FIRST(&svc->segment_list))) - { - TAILQ_REMOVE(&svc->segment_list, seg, next); - SCFree(seg); - } - - AttributeEntry *attr = NULL; - while ((attr = TAILQ_FIRST(&svc->attrib_list))) - { - TAILQ_REMOVE(&svc->attrib_list, attr, next); - SCFree(attr); - } - - SCFree(s); - } - SCReturn; -} -#endif - -/** - * \brief Decode ENIP Encapsulation Header - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @return 1 Packet ok - * @return 0 Packet has errors - */ -int DecodeENIPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data) -{ - int ret = 1; - - uint16_t offset = 0; //byte offset - - //Decode Encapsulation Header - uint16_t cmd; - uint16_t len; - uint32_t session; - uint32_t status; - uint64_t context; - uint32_t option; - if (ENIPExtractUint16(&cmd, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint16(&len, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint32(&session, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint32(&status, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint64(&context, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint32(&option, input, &offset, input_len) != 1) - { - return 0; - } - - enip_data->header.command = cmd; - enip_data->header.length = len; - enip_data->header.session = session; - enip_data->header.status = status; - enip_data->header.context = context; - enip_data->header.option = option; - - switch (enip_data->header.command) - { - case NOP: - SCLogDebug("DecodeENIP - NOP"); - break; - case LIST_SERVICES: - SCLogDebug("DecodeENIP - LIST_SERVICES"); - break; - case LIST_IDENTITY: - SCLogDebug("DecodeENIP - LIST_IDENTITY"); - break; - case LIST_INTERFACES: - SCLogDebug("DecodeENIP - LIST_INTERFACES"); - break; - case REGISTER_SESSION: - SCLogDebug("DecodeENIP - REGISTER_SESSION"); - break; - case UNREGISTER_SESSION: - SCLogDebug("DecodeENIP - UNREGISTER_SESSION"); - break; - case SEND_RR_DATA: - SCLogDebug( - "DecodeENIP - SEND_RR_DATA - parse Common Packet Format"); - ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, - offset); - break; - case SEND_UNIT_DATA: - SCLogDebug( - "DecodeENIP - SEND UNIT DATA - parse Common Packet Format"); - ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, - offset); - break; - case INDICATE_STATUS: - SCLogDebug("DecodeENIP - INDICATE_STATUS"); - break; - case CANCEL: - SCLogDebug("DecodeENIP - CANCEL"); - break; - default: - SCLogDebug("DecodeENIP - UNSUPPORTED COMMAND 0x%x", - enip_data->header.command); - } - - return ret; -} - - -/** - * \brief Decode Common Packet Format - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @param offset current point in the packet - * @return 1 Packet ok - * @return 0 Packet has errors - */ -int DecodeCommonPacketFormatPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset) -{ - - if (enip_data->header.length < sizeof(ENIPEncapDataHdr)) - { - SCLogDebug("DecodeCommonPacketFormat: Malformed ENIP packet"); - return 0; - } - - uint32_t handle; - uint16_t timeout; - uint16_t count; - if (ENIPExtractUint32(&handle, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint16(&timeout, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint16(&count, input, &offset, input_len) != 1) - { - return 0; - } - enip_data->encap_data_header.interface_handle = handle; - enip_data->encap_data_header.timeout = timeout; - enip_data->encap_data_header.item_count = count; - - uint16_t address_type; - uint16_t address_length; //length of connection id in bytes - uint32_t address_connectionid = 0; - uint32_t address_sequence = 0; - - if (ENIPExtractUint16(&address_type, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint16(&address_length, input, &offset, input_len) != 1) - { - return 0; - } - - //depending on addr type, get connection id, sequence if needed. Can also use addr length too? - if (address_type == CONNECTION_BASED) - { //get 4 byte connection id - if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) - { - return 0; - } - } else if (address_type == SEQUENCE_ADDR_ITEM) - { // get 4 byte connection id and 4 byte sequence - if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint32(&address_sequence, input, &offset, input_len) != 1) - { - return 0; - } - } - - enip_data->encap_addr_item.type = address_type; - enip_data->encap_addr_item.length = address_length; - enip_data->encap_addr_item.conn_id = address_connectionid; - enip_data->encap_addr_item.sequence_num = address_sequence; - - uint16_t data_type; - uint16_t data_length; //length of data in bytes - uint16_t data_sequence_count; - - if (ENIPExtractUint16(&data_type, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint16(&data_length, input, &offset, input_len) != 1) - { - return 0; - } - - enip_data->encap_data_item.type = data_type; - enip_data->encap_data_item.length = data_length; - - if (enip_data->encap_data_item.type == CONNECTED_DATA_ITEM) - { //connected data items have seq number - if (ENIPExtractUint16(&data_sequence_count, input, &offset, input_len) != 1) - { - return 0; - } - enip_data->encap_data_item.sequence_count = data_sequence_count; - } - - switch (enip_data->encap_data_item.type) { - case CONNECTED_DATA_ITEM: - SCLogDebug( - "DecodeCommonPacketFormat - CONNECTED DATA ITEM - parse CIP"); - DecodeCIPPDU(input, input_len, enip_data, offset); - break; - case UNCONNECTED_DATA_ITEM: - SCLogDebug("DecodeCommonPacketFormat - UNCONNECTED DATA ITEM"); - DecodeCIPPDU(input, input_len, enip_data, offset); - break; - default: - SCLogDebug("DecodeCommonPacketFormat - UNKNOWN TYPE 0x%x", - enip_data->encap_data_item.type); - return 0; - } - - return 1; -} - -/** - * \brief Decode CIP packet - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @param offset current point in the packet - * @return 1 Packet ok - * @return 0 Packet has errors - */ - -int DecodeCIPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset) -{ - int ret = 1; - - if (enip_data->encap_data_item.length == 0) - { - SCLogDebug("DecodeCIP: No CIP Data"); - return 0; - } - - if (offset > (input_len - sizeof(uint8_t))) - { - SCLogDebug("DecodeCIP: Parsing beyond payload length"); - return 0; - } - - uint8_t service = 0; - service = *(input + offset); - - //SCLogDebug("CIP Service 0x%x", service); - - //use service code first bit to determine request/response, no need to save or push offset - if (service >> 7) - { - ret = DecodeCIPResponsePDU(input, input_len, enip_data, offset); - } else - { - ret = DecodeCIPRequestPDU(input, input_len, enip_data, offset); - } - - return ret; -} - - - -/** - * \brief Decode CIP Request - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @param offset current point in the packet - * @return 1 Packet ok - * @return 0 Packet has errors - */ -int DecodeCIPRequestPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset) -{ - int ret = 1; - - if (enip_data->encap_data_item.length < sizeof(CIPReqHdr)) - { - SCLogDebug("DecodeCIPRequest - Malformed CIP Data"); - return 0; - } - - uint8_t service = 0; //<-----CIP SERVICE - uint8_t path_size = 0; - - if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint8(&path_size, input, &offset, input_len) != 1) - { - return 0; - } - - if (service > MAX_CIP_SERVICE) - { // service codes of value 0x80 or greater are not permitted because in the CIP protocol the highest order bit is used to flag request(0)/response(1) - SCLogDebug("DecodeCIPRequest - INVALID CIP SERVICE 0x%x", service); - return 0; - } - - //reached maximum number of services - if (enip_data->service_count > 32) - { - SCLogDebug("DecodeCIPRequest: Maximum services reached"); - return 0; - } - - //save CIP data - CIPServiceEntry *node = CIPServiceAlloc(enip_data); - if (node == NULL) - { - SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); - return 0; - } - node->direction = 0; - node->service = service; - node->request.path_size = path_size; - node->request.path_offset = offset; - // SCLogDebug("DecodeCIPRequestPDU: service 0x%x size %d", node->service, - // node->request.path_size); - - DecodeCIPRequestPathPDU(input, input_len, node, offset); - - offset += path_size * sizeof(uint16_t); //move offset past pathsize - - //list of CIP services is large and can be vendor specific, store CIP service anyways and let the rule decide the action - switch (service) - { - case CIP_RESERVED: - SCLogDebug("DecodeCIPRequest - CIP_RESERVED"); - break; - case CIP_GET_ATTR_ALL: - SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_ALL"); - break; - case CIP_GET_ATTR_LIST: - SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_LIST"); - break; - case CIP_SET_ATTR_LIST: - SCLogDebug("DecodeCIPRequest - CIP_SET_ATTR_LIST"); - break; - case CIP_RESET: - SCLogDebug("DecodeCIPRequest - CIP_RESET"); - break; - case CIP_START: - SCLogDebug("DecodeCIPRequest - CIP_START"); - break; - case CIP_STOP: - SCLogDebug("DecodeCIPRequest - CIP_STOP"); - break; - case CIP_CREATE: - SCLogDebug("DecodeCIPRequest - CIP_CREATE"); - break; - case CIP_DELETE: - SCLogDebug("DecodeCIPRequest - CIP_DELETE"); - break; - case CIP_MSP: - SCLogDebug("DecodeCIPRequest - CIP_MSP"); - DecodeCIPRequestMSPPDU(input, input_len, enip_data, offset); - break; - case CIP_APPLY_ATTR: - SCLogDebug("DecodeCIPRequest - CIP_APPLY_ATTR"); - break; - case CIP_KICK_TIMER: - SCLogDebug("DecodeCIPRequest - CIP_KICK_TIMER"); - break; - case CIP_OPEN_CONNECTION: - SCLogDebug("DecodeCIPRequest - CIP_OPEN_CONNECTION"); - break; - case CIP_CHANGE_START: - SCLogDebug("DecodeCIPRequest - CIP_CHANGE_START"); - break; - case CIP_GET_STATUS: - SCLogDebug("DecodeCIPRequest - CIP_GET_STATUS"); - break; - default: - SCLogDebug("DecodeCIPRequest - CIP SERVICE 0x%x", service); - } - - return ret; -} - -/** - * \brief Decode CIP Request Path - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @param offset current point in the packet - * @param cipserviced the cip service rule - * @return 1 Packet matches - * @return 0 Packet not match - */ -int DecodeCIPRequestPathPDU(const uint8_t *input, uint32_t input_len, - CIPServiceEntry *node, uint16_t offset) -{ - //SCLogDebug("DecodeCIPRequestPath: service 0x%x size %d length %d", - // node->service, node->request.path_size, input_len); - - if (node->request.path_size < 1) - { - //SCLogDebug("DecodeCIPRequestPath: empty path or CIP Response"); - return 0; - } - - int bytes_remain = node->request.path_size; - - uint8_t reserved; //unused byte reserved by ODVA - - //8 bit fields - uint8_t req_path_instance8; - uint8_t req_path_attr8; - - //16 bit fields - uint16_t req_path_class16; - uint16_t req_path_instance16; - - uint16_t class = 0; - - SegmentEntry *seg = NULL; - - while (bytes_remain > 0) - { - uint8_t segment = 0; - if (ENIPExtractUint8(&segment, input, &offset, input_len) != 1) - { - return 0; - } - switch (segment) - { //assume order is class then instance. Can have multiple - case PATH_CLASS_8BIT: { - uint8_t req_path_class8 = 0; - if (ENIPExtractUint8(&req_path_class8, input, &offset, input_len) != 1) { - return 0; - } - class = (uint16_t) req_path_class8; - SCLogDebug("DecodeCIPRequestPathPDU: 8bit class 0x%x", class); - - seg = SCMalloc(sizeof(SegmentEntry)); - if (unlikely(seg == NULL)) - return 0; - seg->segment = segment; - seg->value = class; - TAILQ_INSERT_TAIL(&node->segment_list, seg, next); - - bytes_remain--; - break; - } - case PATH_INSTANCE_8BIT: - if (ENIPExtractUint8(&req_path_instance8, input, &offset, input_len) != 1) - { - return 0; - } - //skip instance, don't need to store - bytes_remain--; - break; - case PATH_ATTR_8BIT: //single attribute - if (ENIPExtractUint8(&req_path_attr8, input, &offset, input_len) != 1) - { - return 0; - } - //uint16_t attrib = (uint16_t) req_path_attr8; - //SCLogDebug("DecodeCIPRequestPath: 8bit attr 0x%x", attrib); - - seg = SCMalloc(sizeof(SegmentEntry)); - if (unlikely(seg == NULL)) - return 0; - seg->segment = segment; - seg->value = class; - TAILQ_INSERT_TAIL(&node->segment_list, seg, next); - - bytes_remain--; - break; - case PATH_CLASS_16BIT: - if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) //skip reserved - { - return 0; - } - if (ENIPExtractUint16(&req_path_class16, input, &offset, input_len) != 1) - { - return 0; - } - class = req_path_class16; - SCLogDebug("DecodeCIPRequestPath: 16bit class 0x%x", class); - - seg = SCMalloc(sizeof(SegmentEntry)); - if (unlikely(seg == NULL)) - return 0; - seg->segment = segment; - seg->value = class; - TAILQ_INSERT_TAIL(&node->segment_list, seg, next); - if (bytes_remain >= 2) - { - bytes_remain = bytes_remain - 2; - } else - { - bytes_remain = 0; - } - break; - case PATH_INSTANCE_16BIT: - if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) // skip reserved - { - return 0; - } - if (ENIPExtractUint16(&req_path_instance16, input, &offset, input_len) != 1) - { - return 0; - } - //skip instance, don't need to store - if (bytes_remain >= 2) - { - bytes_remain = bytes_remain - 2; - } else - { - bytes_remain = 0; - } - break; - default: - SCLogDebug( - "DecodeCIPRequestPath: UNKNOWN SEGMENT 0x%x service 0x%x", - segment, node->service); - return 0; - } - } - - if ((node->service == CIP_SET_ATTR_LIST) || (node->service - == CIP_GET_ATTR_LIST)) - { - uint16_t attr_list_count; - uint16_t attribute; - //parse get/set attribute list - - if (ENIPExtractUint16(&attr_list_count, input, &offset, input_len) != 1) - { - return 0; - } - SCLogDebug("DecodeCIPRequestPathPDU: attribute list count %d", - attr_list_count); - for (int i = 0; i < attr_list_count; i++) - { - if (ENIPExtractUint16(&attribute, input, &offset, input_len) != 1) - { - return 0; - } - SCLogDebug("DecodeCIPRequestPathPDU: attribute %d", attribute); - //save attrs - AttributeEntry *attr = SCMalloc(sizeof(AttributeEntry)); - if (unlikely(attr == NULL)) - return 0; - attr->attribute = attribute; - TAILQ_INSERT_TAIL(&node->attrib_list, attr, next); - - } - } - - return 1; -} - -/** - * \brief Decode CIP Response - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @param offset current point in the packet - * @return 1 Packet ok - * @return 0 Packet has errors - */ -int DecodeCIPResponsePDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset) -{ - int ret = 1; - - if (enip_data->encap_data_item.length < sizeof(CIPRespHdr)) - { - SCLogDebug("DecodeCIPResponse - Malformed CIP Data"); - return 0; - } - - uint8_t service = 0; //<----CIP SERVICE - uint8_t reserved; //unused byte reserved by ODVA - uint16_t status; - - if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) - { - return 0; - } - if (ENIPExtractUint16(&status, input, &offset, input_len) != 1) - { - return 0; - } - - //SCLogDebug("DecodeCIPResponse: service 0x%x",service); - service &= 0x7f; //strip off top bit to get service code. Responses have first bit as 1 - - SCLogDebug("CIP service 0x%x status 0x%x", service, status); - - //reached maximum number of services - if (enip_data->service_count > 32) - { - SCLogDebug("DecodeCIPRequest: Maximum services reached"); - return 0; - } - - //save CIP data - CIPServiceEntry *node = CIPServiceAlloc(enip_data); - if (node == NULL) - { - SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); - return 0; - } - node->direction = 1; - node->service = service; - node->response.status = status; - - SCLogDebug("DecodeCIPResponsePDU: service 0x%x size %d", node->service, - node->request.path_size); - - //list of CIP services is large and can be vendor specific, store CIP service anyways and let the rule decide the action - switch (service) - { - case CIP_RESERVED: - SCLogDebug("DecodeCIPResponse - CIP_RESERVED"); - break; - case CIP_GET_ATTR_ALL: - SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_ALL"); - break; - case CIP_GET_ATTR_LIST: - SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_LIST"); - break; - case CIP_SET_ATTR_LIST: - SCLogDebug("DecodeCIPResponse - CIP_SET_ATTR_LIST"); - break; - case CIP_RESET: - SCLogDebug("DecodeCIPResponse - CIP_RESET"); - break; - case CIP_START: - SCLogDebug("DecodeCIPResponse - CIP_START"); - break; - case CIP_STOP: - SCLogDebug("DecodeCIPResponse - CIP_STOP"); - break; - case CIP_CREATE: - SCLogDebug("DecodeCIPResponse - CIP_CREATE"); - break; - case CIP_DELETE: - SCLogDebug("DecodeCIPResponse - CIP_DELETE"); - break; - case CIP_MSP: - SCLogDebug("DecodeCIPResponse - CIP_MSP"); - DecodeCIPResponseMSPPDU(input, input_len, enip_data, offset); - break; - case CIP_APPLY_ATTR: - SCLogDebug("DecodeCIPResponse - CIP_APPLY_ATTR"); - break; - case CIP_KICK_TIMER: - SCLogDebug("DecodeCIPResponse - CIP_KICK_TIMER"); - break; - case CIP_OPEN_CONNECTION: - SCLogDebug("DecodeCIPResponse - CIP_OPEN_CONNECTION"); - break; - case CIP_CHANGE_START: - SCLogDebug("DecodeCIPResponse - CIP_CHANGE_START"); - break; - case CIP_GET_STATUS: - SCLogDebug("DecodeCIPResponse - CIP_GET_STATUS"); - break; - default: - SCLogDebug("DecodeCIPResponse - CIP SERVICE 0x%x", service); - } - - return ret; -} - - -/** - * \brief Decode CIP Request Multi Service Packet - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @param offset current point in the packet - * @return 1 Packet ok - * @return 0 Packet has errors - */ -int DecodeCIPRequestMSPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset) -{ - int ret = 1; - if (offset >= (input_len - sizeof(uint16_t))) - { - SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); - return 0; - } - //use temp_offset just to grab the service offset, don't want to use and push offset - uint16_t temp_offset = offset; - uint16_t num_services; - if (ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), - (const uint8_t *)(input + temp_offset)) == -1) { - return 0; - } - - temp_offset += sizeof(uint16_t); - //SCLogDebug("DecodeCIPRequestMSP number of services %d",num_services); - - for (int svc = 1; svc < num_services + 1; svc++) - { - if (temp_offset >= (input_len - sizeof(uint16_t))) - { - SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); - return 0; - } - - uint16_t svc_offset; //read set of service offsets - if (ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), - (const uint8_t *)(input + temp_offset)) == -1) { - return 0; - } - temp_offset += sizeof(uint16_t); - //SCLogDebug("parseCIPRequestMSP service %d offset %d",svc, svc_offset); - - DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset - } - - return ret; -} - - - -/** - * \brief Decode CIP Response MultiService Packet. - * @param input, input_len data stream - * @param enip_data stores data from Packet - * @param offset current point in the packet - * @return 1 Packet ok - * @return 0 Packet has errors - */ -int DecodeCIPResponseMSPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset) -{ - int ret = 1; - - if (offset >= (input_len - sizeof(uint16_t))) - { - SCLogDebug("DecodeCIPResponseMSPPDU: Parsing beyond payload length"); - return 0; - } - //use temp_offset just to grab the service offset, don't want to use and push offset - uint16_t temp_offset = offset; - uint16_t num_services; - if (ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), - (const uint8_t *)(input + temp_offset)) == -1) { - return 0; - } - temp_offset += sizeof(uint16_t); - //SCLogDebug("DecodeCIPResponseMSP number of services %d", num_services); - - for (int svc = 0; svc < num_services; svc++) { - if (temp_offset >= (input_len - sizeof(uint16_t))) - { - SCLogDebug("DecodeCIPResponseMSP: Parsing beyond payload length"); - return 0; - } - - uint16_t svc_offset; //read set of service offsets - if (ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), - (const uint8_t *)(input + temp_offset)) == -1) { - return 0; - } - temp_offset += sizeof(uint16_t); - //SCLogDebug("parseCIPResponseMSP service %d offset %d", svc, svc_offset); - - DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset - } - - return ret; -} diff --git a/src/app-layer-enip-common.h b/src/app-layer-enip-common.h deleted file mode 100644 index 1578343a69eb..000000000000 --- a/src/app-layer-enip-common.h +++ /dev/null @@ -1,245 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Kevin Wong - */ - -#ifndef __APP_LAYER_ENIP_COMMON_H__ -#define __APP_LAYER_ENIP_COMMON_H__ - -#include "rust.h" - -// EtherNet/IP commands -#define NOP 0x0000 -#define LIST_SERVICES 0x0004 -#define LIST_IDENTITY 0x0063 -#define LIST_INTERFACES 0x0064 -#define REGISTER_SESSION 0x0065 -#define UNREGISTER_SESSION 0x0066 -#define SEND_RR_DATA 0x006F -#define SEND_UNIT_DATA 0x0070 -#define INDICATE_STATUS 0x0072 -#define CANCEL 0x0073 - -//Common Packet Format Types -#define NULL_ADDR 0x0000 -#define CONNECTION_BASED 0x00a1 -#define CONNECTED_DATA_ITEM 0x00b1 -#define UNCONNECTED_DATA_ITEM 0x00b2 -#define SEQUENCE_ADDR_ITEM 0xB002 - -//status codes -#define SUCCESS 0x0000 -#define INVALID_CMD 0x0001 -#define NO_RESOURCES 0x0002 -#define INCORRECT_DATA 0x0003 -#define INVALID_SESSION 0x0064 -#define INVALID_LENGTH 0x0065 -#define UNSUPPORTED_PROT_REV 0x0069 -//Found in wireshark -#define ENCAP_HEADER_ERROR 0x006A - -#define MAX_CIP_SERVICE 127 -#define MAX_CIP_CLASS 65535 -#define MAX_CIP_ATTRIBUTE 65535 - -// CIP service codes -#define CIP_RESERVED 0x00 -#define CIP_GET_ATTR_ALL 0x01 -#define CIP_GET_ATTR_LIST 0x03 -#define CIP_SET_ATTR_LIST 0x04 -#define CIP_RESET 0x05 -#define CIP_START 0x06 -#define CIP_STOP 0x07 -#define CIP_CREATE 0x08 -#define CIP_DELETE 0x09 -#define CIP_MSP 0x0a -#define CIP_APPLY_ATTR 0x0d -#define CIP_GET_ATTR_SINGLE 0x0e -#define CIP_SET_ATTR_SINGLE 0x10 -#define CIP_KICK_TIMER 0x4b -#define CIP_OPEN_CONNECTION 0x4c -#define CIP_CHANGE_START 0x4f -#define CIP_GET_STATUS 0x50 - -//PATH sizing codes -#define PATH_CLASS_8BIT 0x20 -#define PATH_CLASS_16BIT 0x21 -#define PATH_INSTANCE_8BIT 0x24 -#define PATH_INSTANCE_16BIT 0x25 -#define PATH_ATTR_8BIT 0x30 -#define PATH_ATTR_16BIT 0x31 //possible value - -/** - * ENIP encapsulation header - */ -typedef struct ENIPEncapHdr_ -{ - uint64_t context; - uint32_t session; - uint32_t status; - uint32_t option; - uint16_t command; - uint16_t length; -} ENIPEncapHdr; - -/** - * ENIP encapsulation data header - */ -typedef struct ENIPEncapDataHdr_ -{ - uint32_t interface_handle; - uint16_t timeout; - uint16_t item_count; -} ENIPEncapDataHdr; - -/** - * ENIP encapsulation address item - */ -typedef struct ENIPEncapAddressItem_ { - uint16_t type; - uint16_t length; - uint32_t conn_id; - uint32_t sequence_num; -} ENIPEncapAddressItem; - -/** - * ENIP encapsulation data item - */ -typedef struct ENIPEncapDataItem_ -{ - uint16_t type; - uint16_t length; - uint16_t sequence_count; -} ENIPEncapDataItem; - -/** - * CIP Request Header - */ -typedef struct CIPReqHdr_ -{ - uint8_t service; - uint8_t path_size; -} CIPReqHdr; - -/** - * CIP Response Header - */ -typedef struct CIPRespHdr_ -{ - uint8_t service; - uint8_t pad; - uint8_t status; - uint8_t status_size; -} CIPRespHdr; - -typedef struct SegmentEntry_ -{ - uint16_t segment; /**< segment type */ - uint16_t value; /**< segment value (class or attribute) */ - - TAILQ_ENTRY(SegmentEntry_) next; -} SegmentEntry; - -typedef struct AttributeEntry_ -{ - uint16_t attribute; /**< segment class */ - - TAILQ_ENTRY(AttributeEntry_) next; -} AttributeEntry; - -typedef struct CIPServiceEntry_ -{ - uint8_t service; /**< cip service */ - uint8_t direction; - union - { - struct - { - uint8_t path_size; /**< cip path size */ - uint16_t path_offset; /**< offset to cip path */ - } request; - struct - { - uint16_t status; - } response; - }; - - TAILQ_HEAD(, SegmentEntry_) segment_list; /**< list for CIP segment */ - TAILQ_HEAD(, AttributeEntry_) attrib_list; /**< list for CIP segment */ - - TAILQ_ENTRY(CIPServiceEntry_) next; -} CIPServiceEntry; - -typedef struct ENIPTransaction_ -{ - struct ENIPState_ *enip; - uint64_t tx_num; /**< internal: id */ - uint16_t tx_id; /**< transaction id */ - uint16_t service_count; - - ENIPEncapHdr header; /**< encapsulation header */ - ENIPEncapDataHdr encap_data_header; /**< encapsulation data header */ - ENIPEncapAddressItem encap_addr_item; /**< encapsulated address item */ - ENIPEncapDataItem encap_data_item; /**< encapsulated data item */ - - TAILQ_HEAD(, CIPServiceEntry_) service_list; /**< list for CIP */ - - TAILQ_ENTRY(ENIPTransaction_) next; - AppLayerTxData tx_data; -} ENIPTransaction; - -/** \brief Per flow ENIP state container */ -typedef struct ENIPState_ -{ - AppLayerStateData state_data; - TAILQ_HEAD(, ENIPTransaction_) tx_list; /**< transaction list */ - ENIPTransaction *curr; /**< ptr to current tx */ - ENIPTransaction *iter; - uint64_t transaction_max; - uint64_t tx_with_detect_state_cnt; - - uint16_t events; - uint16_t givenup; - - /* used by TCP only */ - uint16_t offset; - uint16_t record_len; - uint8_t *buffer; -} ENIPState; - -int DecodeENIPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data); -int DecodeCommonPacketFormatPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset); -int DecodeCIPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset); -int DecodeCIPRequestPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset); -int DecodeCIPResponsePDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset); -int DecodeCIPRequestPathPDU(const uint8_t *input, uint32_t input_len, - CIPServiceEntry *node, uint16_t offset); -int DecodeCIPRequestMSPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset); -int DecodeCIPResponseMSPPDU(const uint8_t *input, uint32_t input_len, - ENIPTransaction *enip_data, uint16_t offset); - -#endif /* __APP_LAYER_ENIP_COMMON_H__ */ diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c deleted file mode 100644 index f059774b6da5..000000000000 --- a/src/app-layer-enip.c +++ /dev/null @@ -1,709 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Kevin Wong - * - * App-layer parser for ENIP protocol - * - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "util-debug.h" -#include "util-byte.h" -#include "util-enum.h" -#include "util-mem.h" -#include "util-misc.h" - -#include "stream.h" - -#include "app-layer.h" -#include "app-layer-protos.h" -#include "app-layer-parser.h" -#include "app-layer-enip.h" -#include "app-layer-enip-common.h" - -#include "app-layer-detect-proto.h" - -#include "conf.h" -#include "decode.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "pkt-var.h" -#include "util-profiling.h" - - -SCEnumCharMap enip_decoder_event_table[ ] = { - { NULL, -1 }, -}; - -/** \brief get value for 'complete' status in ENIP - * - * For ENIP we use a simple bool. - */ -static int ENIPGetAlstateProgress(void *tx, uint8_t direction) -{ - return 1; -} - -static AppLayerTxData *ENIPGetTxData(void *vtx) -{ - ENIPTransaction *tx = (ENIPTransaction *)vtx; - return &tx->tx_data; -} - -static AppLayerStateData *ENIPGetStateData(void *vstate) -{ - ENIPState *state = (ENIPState *)vstate; - return &state->state_data; -} - -static void *ENIPGetTx(void *alstate, uint64_t tx_id) -{ - ENIPState *enip = (ENIPState *) alstate; - ENIPTransaction *tx = NULL; - - if (enip->curr && enip->curr->tx_num == tx_id + 1) - return enip->curr; - - TAILQ_FOREACH(tx, &enip->tx_list, next) { - if (tx->tx_num != (tx_id+1)) - continue; - - SCLogDebug("returning tx %p", tx); - return tx; - } - - return NULL; -} - -static uint64_t ENIPGetTxCnt(void *alstate) -{ - return ((ENIPState *)alstate)->transaction_max; -} - -static int ENIPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type) -{ - *event_id = SCMapEnumNameToValue(event_name, enip_decoder_event_table); - - if (*event_id == -1) { - SCLogError("event \"%s\" not present in " - "enip's enum map table.", - event_name); - /* yes this is fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static int ENIPStateGetEventInfoById(int event_id, const char **event_name, - AppLayerEventType *event_type) -{ - *event_name = SCMapEnumValueToName(event_id, enip_decoder_event_table); - if (*event_name == NULL) { - SCLogError("event \"%d\" not present in " - "enip's enum map table.", - event_id); - /* yes this is fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -/** \brief Allocate enip state - * - * return state - */ -static void *ENIPStateAlloc(void *orig_state, AppProto proto_orig) -{ - SCLogDebug("ENIPStateAlloc"); - void *s = SCCalloc(1, sizeof(ENIPState)); - if (unlikely(s == NULL)) - return NULL; - - ENIPState *enip_state = (ENIPState *) s; - - TAILQ_INIT(&enip_state->tx_list); - return s; -} - -/** \internal - * \brief Free a ENIP TX - * \param tx ENIP TX to free */ -static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state) -{ - SCEnter(); - SCLogDebug("ENIPTransactionFree"); - CIPServiceEntry *svc = NULL; - while ((svc = TAILQ_FIRST(&tx->service_list))) - { - TAILQ_REMOVE(&tx->service_list, svc, next); - - SegmentEntry *seg = NULL; - while ((seg = TAILQ_FIRST(&svc->segment_list))) - { - TAILQ_REMOVE(&svc->segment_list, seg, next); - SCFree(seg); - } - - AttributeEntry *attr = NULL; - while ((attr = TAILQ_FIRST(&svc->attrib_list))) - { - TAILQ_REMOVE(&svc->attrib_list, attr, next); - SCFree(attr); - } - - SCFree(svc); - } - - AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); - - if (tx->tx_data.de_state != NULL) { - DetectEngineStateFree(tx->tx_data.de_state); - - state->tx_with_detect_state_cnt--; - } - - if (state->iter == tx) - state->iter = NULL; - - SCFree(tx); - SCReturn; -} - -/** \brief Free enip state - * - */ -static void ENIPStateFree(void *s) -{ - SCEnter(); - SCLogDebug("ENIPStateFree"); - if (s) - { - ENIPState *enip_state = (ENIPState *) s; - - ENIPTransaction *tx = NULL; - while ((tx = TAILQ_FIRST(&enip_state->tx_list))) - { - TAILQ_REMOVE(&enip_state->tx_list, tx, next); - ENIPTransactionFree(tx, enip_state); - } - - if (enip_state->buffer != NULL) - { - SCFree(enip_state->buffer); - } - - SCFree(s); - } - SCReturn; -} - -/** \internal - * \brief Allocate a ENIP TX - * \retval tx or NULL */ -static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state) -{ - SCLogDebug("ENIPStateTransactionAlloc"); - ENIPTransaction *tx = (ENIPTransaction *) SCCalloc(1, - sizeof(ENIPTransaction)); - if (unlikely(tx == NULL)) - return NULL; - - state->curr = tx; - state->transaction_max++; - - TAILQ_INIT(&tx->service_list); - - tx->enip = state; - tx->tx_num = state->transaction_max; - tx->service_count = 0; - - TAILQ_INSERT_TAIL(&state->tx_list, tx, next); - - return tx; -} - -/** - * \brief enip transaction cleanup callback - */ -static void ENIPStateTransactionFree(void *state, uint64_t tx_id) -{ - SCEnter(); - SCLogDebug("ENIPStateTransactionFree"); - ENIPState *enip_state = state; - ENIPTransaction *tx = NULL; - TAILQ_FOREACH(tx, &enip_state->tx_list, next) - { - - if ((tx_id+1) < tx->tx_num) - break; - else if ((tx_id+1) > tx->tx_num) - continue; - - if (tx == enip_state->curr) - enip_state->curr = NULL; - - if (tx->tx_data.events != NULL) { - if (tx->tx_data.events->cnt <= enip_state->events) - enip_state->events -= tx->tx_data.events->cnt; - else - enip_state->events = 0; - } - - TAILQ_REMOVE(&enip_state->tx_list, tx, next); - ENIPTransactionFree(tx, state); - break; - } - SCReturn; -} - -/** \internal - * - * \brief This function is called to retrieve a ENIP - * - * \param state ENIP state structure for the parser - * \param input Input line of the command - * \param input_len Length of the request - * - * \retval 1 when the command is parsed, 0 otherwise - */ -static AppLayerResult ENIPParse(Flow *f, void *state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data, uint8_t direction) -{ - SCEnter(); - ENIPState *enip = (ENIPState *) state; - ENIPTransaction *tx; - - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - if (input == NULL && AppLayerParserStateIssetFlag(pstate, - APP_LAYER_PARSER_EOF_TS|APP_LAYER_PARSER_EOF_TC)) - { - SCReturnStruct(APP_LAYER_OK); - } else if (input == NULL && input_len != 0) { - // GAP - SCReturnStruct(APP_LAYER_OK); - } else if (input == NULL || input_len == 0) - { - SCReturnStruct(APP_LAYER_ERROR); - } - - while (input_len > 0) - { - tx = ENIPTransactionAlloc(enip); - if (tx == NULL) - SCReturnStruct(APP_LAYER_OK); - - if (direction == STREAM_TOCLIENT) - tx->tx_data.detect_flags_ts |= APP_LAYER_TX_SKIP_INSPECT_FLAG; - else - tx->tx_data.detect_flags_tc |= APP_LAYER_TX_SKIP_INSPECT_FLAG; - - SCLogDebug("ENIPParse input len %d", input_len); - DecodeENIPPDU(input, input_len, tx); - uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr); - SCLogDebug("ENIPParse packet len %d", pkt_len); - if (pkt_len > input_len) - { - SCLogDebug("Invalid packet length"); - break; - } - - input += pkt_len; - input_len -= pkt_len; - //SCLogDebug("remaining %d", input_len); - - if (input_len < sizeof(ENIPEncapHdr)) - { - //SCLogDebug("Not enough data"); //not enough data for ENIP - break; - } - } - - SCReturnStruct(APP_LAYER_OK); -} - -static AppLayerResult ENIPParseRequest(Flow *f, void *state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOSERVER); -} - -static AppLayerResult ENIPParseResponse(Flow *f, void *state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOCLIENT); -} - -#define ENIP_LEN_REGISTER_SESSION 4 // protocol u16, options u16 - -static uint16_t ENIPProbingParser(Flow *f, uint8_t direction, - const uint8_t *input, uint32_t input_len, uint8_t *rdir) -{ - // SCLogDebug("ENIPProbingParser %d", input_len); - if (input_len < sizeof(ENIPEncapHdr)) - { - SCLogDebug("length too small to be a ENIP header"); - return ALPROTO_UNKNOWN; - } - uint16_t cmd; - uint16_t enip_len; - uint32_t status; - uint32_t option; - uint16_t nbitems; - - int ret = ByteExtractUint32( - &status, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 8)); - if (ret < 0) { - return ALPROTO_FAILED; - } - switch (status) { - case SUCCESS: - case INVALID_CMD: - case NO_RESOURCES: - case INCORRECT_DATA: - case INVALID_SESSION: - case INVALID_LENGTH: - case UNSUPPORTED_PROT_REV: - case ENCAP_HEADER_ERROR: - break; - default: - return ALPROTO_FAILED; - } - ret = ByteExtractUint16(&cmd, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input)); - if(ret < 0) { - return ALPROTO_FAILED; - } - ret = ByteExtractUint32( - &option, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 20)); - if (ret < 0) { - return ALPROTO_FAILED; - } - ret = ByteExtractUint16( - &enip_len, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input + 2)); - if (ret < 0) { - return ALPROTO_FAILED; - } - - //ok for all the known commands - switch(cmd) { - case NOP: - if (option != 0) { - return ALPROTO_FAILED; - } - break; - case REGISTER_SESSION: - if (enip_len != ENIP_LEN_REGISTER_SESSION) { - return ALPROTO_FAILED; - } - break; - case UNREGISTER_SESSION: - if (enip_len != ENIP_LEN_REGISTER_SESSION && enip_len != 0) { - // 0 for request and 4 for response - return ALPROTO_FAILED; - } - break; - case LIST_SERVICES: - case LIST_IDENTITY: - case SEND_RR_DATA: - case SEND_UNIT_DATA: - case INDICATE_STATUS: - case CANCEL: - break; - case LIST_INTERFACES: - if (input_len < sizeof(ENIPEncapHdr) + 2) { - SCLogDebug("length too small to be a ENIP LIST_INTERFACES"); - return ALPROTO_UNKNOWN; - } - ret = ByteExtractUint16( - &nbitems, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input)); - if(ret < 0) { - return ALPROTO_FAILED; - } - if (enip_len < sizeof(ENIPEncapHdr) + 2 * (size_t)nbitems) { - return ALPROTO_FAILED; - } - break; - default: - return ALPROTO_FAILED; - } - return ALPROTO_ENIP; -} - -static AppLayerGetTxIterTuple ENIPGetTxIterator(const uint8_t ipproto, const AppProto alproto, - void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) -{ - ENIPState *enip_state = (ENIPState *)alstate; - AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; - if (enip_state) { - ENIPTransaction *tx_ptr; - if (state->un.ptr == NULL) { - tx_ptr = TAILQ_FIRST(&enip_state->tx_list); - } else { - tx_ptr = (ENIPTransaction *)state->un.ptr; - } - if (tx_ptr) { - while (tx_ptr->tx_num < min_tx_id + 1) { - tx_ptr = TAILQ_NEXT(tx_ptr, next); - if (!tx_ptr) { - return no_tuple; - } - } - if (tx_ptr->tx_num >= max_tx_id + 1) { - return no_tuple; - } - state->un.ptr = TAILQ_NEXT(tx_ptr, next); - AppLayerGetTxIterTuple tuple = { - .tx_ptr = tx_ptr, - .tx_id = tx_ptr->tx_num - 1, - .has_next = (state->un.ptr != NULL), - }; - return tuple; - } - } - return no_tuple; -} - -/** - * \brief Function to register the ENIP protocol parsers and other functions - */ -void RegisterENIPUDPParsers(void) -{ - SCEnter(); - const char *proto_name = "enip"; - - if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("udp", proto_name, false)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); - - if (RunmodeIsUnittests()) - { - AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); - - AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); - - } else - { - if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, - proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), - ENIPProbingParser, ENIPProbingParser)) - { - SCLogDebug( - "no ENIP UDP config found enabling ENIP detection on port 44818."); - - AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", - ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, - ENIPProbingParser, NULL); - - AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", - ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, - ENIPProbingParser, NULL); - } - } - - } else { - SCLogConfig("Protocol detection and parser disabled for %s protocol.", - proto_name); - return; - } - - if (AppLayerParserConfParserEnabled("udp", proto_name)) - { - AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest); - AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse); - - AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_ENIP, - ENIPStateAlloc, ENIPStateFree); - - AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx); - AppLayerParserRegisterGetTxIterator(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxIterator); - AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxData); - AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetStateData); - AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt); - AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree); - - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress); - AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1); - - AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo); - AppLayerParserRegisterGetEventInfoById(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfoById); - - AppLayerParserRegisterParserAcceptableDataDirection( - IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); - } else - { - SCLogInfo( - "Parsed disabled for %s protocol. Protocol detection" "still on.", - proto_name); - } - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_ENIP, ENIPParserRegisterTests); -#endif - - SCReturn; -} - -/** - * \brief Function to register the ENIP protocol parsers and other functions - */ -void RegisterENIPTCPParsers(void) -{ - SCEnter(); - const char *proto_name = "enip"; - - if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); - - if (RunmodeIsUnittests()) - { - AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); - - AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, - 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); - - } else - { - if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, - proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), - ENIPProbingParser, ENIPProbingParser)) - { - return; - } - } - - } else { - SCLogDebug("Protocol detection and parser disabled for %s protocol.", - proto_name); - return; - } - - if (AppLayerParserConfParserEnabled("tcp", proto_name)) - { - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest); - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse); - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_ENIP, - ENIPStateAlloc, ENIPStateFree); - - AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx); - AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxIterator); - AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxData); - AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetStateData); - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt); - AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree); - - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress); - AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1); - - AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo); - - AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, - ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); - - /* This parser accepts gaps. */ - AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_ENIP, - APP_LAYER_PARSER_OPT_ACCEPT_GAPS); - - AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_ENIP, 0); - } else - { - SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.", - proto_name); - } - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_ENIP, ENIPParserRegisterTests); -#endif - - SCReturn; -} - -/* UNITTESTS */ -#ifdef UNITTESTS -#include "flow-util.h" -#include "stream-tcp.h" - -static uint8_t listIdentity[] = {/* List ID */ 0x63, 0x00, - /* Length */ 0x00, 0x00, - /* Session */ 0x00, 0x00, 0x00, 0x00, - /* Status */ 0x00, 0x00, 0x00, 0x00, - /* Delay*/ 0x00, - /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00, 0x00}; - -/** - * \brief Test if ENIP Packet matches signature - */ -static int ALDecodeENIPTest(void) -{ - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_ENIP; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER, - listIdentity, sizeof(listIdentity)); - FAIL_IF(r != 0); - - ENIPState *enip_state = f.alstate; - FAIL_IF_NULL(enip_state); - - ENIPTransaction *tx = ENIPGetTx(enip_state, 0); - FAIL_IF_NULL(tx); - - FAIL_IF(tx->header.command != 99); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - - PASS; -} - -#endif /* UNITTESTS */ - -void ENIPParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest); -#endif /* UNITTESTS */ -} diff --git a/src/app-layer-enip.h b/src/app-layer-enip.h deleted file mode 100644 index 25cb1d5745da..000000000000 --- a/src/app-layer-enip.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Kevin Wong - */ - -#ifndef __APP_LAYER_ENIP_H__ -#define __APP_LAYER_ENIP_H__ - - -void RegisterENIPUDPParsers(void); -void RegisterENIPTCPParsers(void); -void ENIPParserRegisterTests(void); - -#endif /* __APP_LAYER_ENIP_H__ */ diff --git a/src/app-layer-events.c b/src/app-layer-events.c index be5ee99ac290..89c02b5082eb 100644 --- a/src/app-layer-events.c +++ b/src/app-layer-events.c @@ -27,29 +27,21 @@ #include "flow.h" #include "app-layer-events.h" #include "app-layer-parser.h" -#include "util-enum.h" +#include "util/enum.h" /* events raised during protocol detection are stored in the * packets storage, not in the flow. */ -SCEnumCharMap app_layer_event_pkt_table[ ] = { - { "APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS", - APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS }, - { "APPLAYER_WRONG_DIRECTION_FIRST_DATA", - APPLAYER_WRONG_DIRECTION_FIRST_DATA }, - { "APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION", - APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION }, - { "APPLAYER_PROTO_DETECTION_SKIPPED", - APPLAYER_PROTO_DETECTION_SKIPPED }, - { "APPLAYER_NO_TLS_AFTER_STARTTLS", - APPLAYER_NO_TLS_AFTER_STARTTLS }, - { "APPLAYER_UNEXPECTED_PROTOCOL", - APPLAYER_UNEXPECTED_PROTOCOL }, - { NULL, - -1 }, +SCEnumCharMap app_layer_event_pkt_table[] = { + { "APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS", APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS }, + { "APPLAYER_WRONG_DIRECTION_FIRST_DATA", APPLAYER_WRONG_DIRECTION_FIRST_DATA }, + { "APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION", APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION }, + { "APPLAYER_PROTO_DETECTION_SKIPPED", APPLAYER_PROTO_DETECTION_SKIPPED }, + { "APPLAYER_NO_TLS_AFTER_STARTTLS", APPLAYER_NO_TLS_AFTER_STARTTLS }, + { "APPLAYER_UNEXPECTED_PROTOCOL", APPLAYER_UNEXPECTED_PROTOCOL }, + { NULL, -1 }, }; -int AppLayerGetEventInfoById(int event_id, const char **event_name, - AppLayerEventType *event_type) +int AppLayerGetEventInfoById(int event_id, const char **event_name, AppLayerEventType *event_type) { *event_name = SCMapEnumValueToName(event_id, app_layer_event_pkt_table); if (*event_name == NULL) { @@ -96,7 +88,6 @@ void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t e return; *sevents = new_devents; - } if ((*sevents)->cnt == UCHAR_MAX) { /* we're full */ @@ -107,8 +98,7 @@ void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t e if (UCHAR_MAX - (*sevents)->cnt < steps) steps = UCHAR_MAX - (*sevents)->cnt < steps; - void *ptr = SCRealloc((*sevents)->events, - ((*sevents)->cnt + steps) * sizeof(uint8_t)); + void *ptr = SCRealloc((*sevents)->events, ((*sevents)->cnt + steps) * sizeof(uint8_t)); if (ptr == NULL) { /* couldn't grow buffer, but no reason to free old * so we keep the events that may already be here */ @@ -129,7 +119,6 @@ void AppLayerDecoderEventsResetEvents(AppLayerDecoderEvents *events) } } - void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events) { if (events && *events != NULL) { diff --git a/src/app-layer-events.h b/src/app-layer-events.h index 8b0dc8276d61..de6d9357edde 100644 --- a/src/app-layer-events.h +++ b/src/app-layer-events.h @@ -55,8 +55,7 @@ enum { int AppLayerGetPktEventInfo(const char *event_name, int *event_id); -int AppLayerGetEventInfoById(int event_id, const char **event_name, - AppLayerEventType *event_type); +int AppLayerGetEventInfoById(int event_id, const char **event_name, AppLayerEventType *event_type); void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event); static inline int AppLayerDecoderEventsIsEventSet( @@ -79,4 +78,3 @@ void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events); int DetectEngineGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type); #endif /* __APP_LAYER_EVENTS_H__ */ - diff --git a/src/app-layer-expectation.c b/src/app-layer-expectation.c index 7a456f87a336..ccb551102fd5 100644 --- a/src/app-layer-expectation.c +++ b/src/app-layer-expectation.c @@ -60,14 +60,14 @@ #include "app-layer-expectation.h" -#include "util-print.h" +#include "util/print.h" static IPPairStorageId g_ippair_expectation_id = { .id = -1 }; static FlowStorageId g_flow_expectation_id = { .id = -1 }; SC_ATOMIC_DECLARE(uint32_t, expectation_count); -#define EXPECTATION_TIMEOUT 30 +#define EXPECTATION_TIMEOUT 30 #define EXPECTATION_MAX_LEVEL 10 typedef struct Expectation_ { @@ -96,7 +96,7 @@ typedef struct ExpectationList_ { static void ExpectationDataFree(void *e) { SCLogDebug("Free expectation data"); - ExpectationData *ed = (ExpectationData *) e; + ExpectationData *ed = (ExpectationData *)e; if (ed->DFree) { ed->DFree(e); } else { @@ -128,7 +128,7 @@ static void ExpectationListFree(void *el) if (exp_list->length > 0) { Expectation *exp = NULL, *pexp = NULL; - CIRCLEQ_FOREACH_SAFE(exp, &exp_list->list, entries, pexp) { + CIRCLEQ_FOREACH_SAFE (exp, &exp_list->list, entries, pexp) { CIRCLEQ_REMOVE(&exp_list->list, exp, entries); exp_list->length--; AppLayerFreeExpectation(exp); @@ -181,10 +181,8 @@ static ExpectationList *AppLayerExpectationLookup(Flow *f, IPPair **ipp) return IPPairGetStorageById(*ipp, g_ippair_expectation_id); } - -static ExpectationList *AppLayerExpectationRemove(IPPair *ipp, - ExpectationList *exp_list, - Expectation *exp) +static ExpectationList *AppLayerExpectationRemove( + IPPair *ipp, ExpectationList *exp_list, Expectation *exp) { CIRCLEQ_REMOVE(&exp_list->list, exp, entries); AppLayerFreeExpectation(exp); @@ -216,8 +214,8 @@ static ExpectationList *AppLayerExpectationRemove(IPPair *ipp, * \return -1 if error * \return 0 if success */ -int AppLayerExpectationCreate(Flow *f, int direction, Port src, Port dst, - AppProto alproto, void *data) +int AppLayerExpectationCreate( + Flow *f, int direction, Port src, Port dst, AppProto alproto, void *data) { ExpectationList *exp_list = NULL; IPPair *ipp; @@ -317,7 +315,7 @@ AppProto AppLayerExpectationHandle(Flow *f, uint8_t flags) if (exp_list == NULL) goto out; - CIRCLEQ_FOREACH_SAFE(exp, &exp_list->list, entries, lexp) { + CIRCLEQ_FOREACH_SAFE (exp, &exp_list->list, entries, lexp) { if ((exp->direction & flags) && ((exp->sp == 0) || (exp->sp == f->sp)) && ((exp->dp == 0) || (exp->dp == f->dp))) { alproto = exp->alproto; @@ -374,7 +372,7 @@ void AppLayerExpectationClean(Flow *f) if (exp_list == NULL) goto out; - CIRCLEQ_FOREACH_SAFE(exp, &exp_list->list, entries, pexp) { + CIRCLEQ_FOREACH_SAFE (exp, &exp_list->list, entries, pexp) { /* Cleaning remove old entries */ if (exp->orig_f == (void *)f) { exp_list = AppLayerExpectationRemove(ipp, exp_list, exp); diff --git a/src/app-layer-expectation.h b/src/app-layer-expectation.h index 0219e33bcf24..fa5339a8d21f 100644 --- a/src/app-layer-expectation.h +++ b/src/app-layer-expectation.h @@ -27,8 +27,8 @@ #include "flow-storage.h" void AppLayerExpectationSetup(void); -int AppLayerExpectationCreate(Flow *f, int direction, Port src, Port dst, - AppProto alproto, void *data); +int AppLayerExpectationCreate( + Flow *f, int direction, Port src, Port dst, AppProto alproto, void *data); AppProto AppLayerExpectationHandle(Flow *f, uint8_t flags); FlowStorageId AppLayerExpectationGetFlowId(void); diff --git a/src/app-layer-frames.c b/src/app-layer-frames.c index 832752cf16e9..2d35c5dfc62c 100644 --- a/src/app-layer-frames.c +++ b/src/app-layer-frames.c @@ -23,7 +23,7 @@ */ #include "suricata-common.h" -#include "util-print.h" +#include "util/print.h" #include "flow.h" #include "stream-tcp.h" diff --git a/src/app-layer-frames.h b/src/app-layer-frames.h index 65ba5b6a6919..86f8142015a8 100644 --- a/src/app-layer-frames.h +++ b/src/app-layer-frames.h @@ -47,11 +47,11 @@ typedef struct Frame { uint8_t flags; /**< frame flags: FRAME_FLAG_* */ uint8_t event_cnt; // TODO one event per frame enough? - uint8_t events[4]; /**< per frame store for events */ - uint64_t offset; /**< offset from the start of the stream */ + uint8_t events[4]; /**< per frame store for events */ + uint64_t offset; /**< offset from the start of the stream */ int64_t len; int64_t id; - uint64_t tx_id; /**< tx_id to match this frame. UINT64T_MAX if not used. */ + uint64_t tx_id; /**< tx_id to match this frame. UINT64T_MAX if not used. */ uint64_t inspect_progress; /**< inspection tracker relative to the start of the frame */ } Frame; @@ -59,7 +59,7 @@ typedef struct Frame { typedef struct Frames { uint16_t cnt; - uint16_t dyn_size; /**< size in elements of `dframes` */ + uint16_t dyn_size; /**< size in elements of `dframes` */ uint32_t left_edge_rel; uint64_t base_id; Frame sframes[FRAMES_STATIC_CNT]; /**< static frames */ diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c deleted file mode 100644 index 8925d6dd6a13..000000000000 --- a/src/app-layer-ftp.c +++ /dev/null @@ -1,1575 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * \author Eric Leblond - * \author Jeff Lucovsky - * - * App Layer Parser for FTP - */ - -#include "suricata-common.h" -#include "app-layer-ftp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-expectation.h" -#include "app-layer-detect-proto.h" - -#include "rust.h" - -#include "util-misc.h" -#include "util-mpm.h" -#include "util-validate.h" - -typedef struct FTPThreadCtx_ { - MpmThreadCtx *ftp_mpm_thread_ctx; - PrefilterRuleStore *pmq; -} FTPThreadCtx; - -#define FTP_MPM mpm_default_matcher - -static MpmCtx *ftp_mpm_ctx = NULL; - -// clang-format off -const FtpCommand FtpCommands[FTP_COMMAND_MAX + 1] = { - /* Parsed and handled */ - { "PORT", FTP_COMMAND_PORT, 4 }, - { "EPRT", FTP_COMMAND_EPRT, 4 }, - { "AUTH TLS", FTP_COMMAND_AUTH_TLS, 8 }, - { "PASV", FTP_COMMAND_PASV, 4 }, - { "RETR", FTP_COMMAND_RETR, 4 }, - { "EPSV", FTP_COMMAND_EPSV, 4 }, - { "STOR", FTP_COMMAND_STOR, 4 }, - - /* Parsed, but not handled */ - { "ABOR", FTP_COMMAND_ABOR, 4 }, - { "ACCT", FTP_COMMAND_ACCT, 4 }, - { "ALLO", FTP_COMMAND_ALLO, 4 }, - { "APPE", FTP_COMMAND_APPE, 4 }, - { "CDUP", FTP_COMMAND_CDUP, 4 }, - { "CHMOD", FTP_COMMAND_CHMOD, 5 }, - { "CWD", FTP_COMMAND_CWD, 3 }, - { "DELE", FTP_COMMAND_DELE, 4 }, - { "HELP", FTP_COMMAND_HELP, 4 }, - { "IDLE", FTP_COMMAND_IDLE, 4 }, - { "LIST", FTP_COMMAND_LIST, 4 }, - { "MAIL", FTP_COMMAND_MAIL, 4 }, - { "MDTM", FTP_COMMAND_MDTM, 4 }, - { "MKD", FTP_COMMAND_MKD, 3 }, - { "MLFL", FTP_COMMAND_MLFL, 4 }, - { "MODE", FTP_COMMAND_MODE, 4 }, - { "MRCP", FTP_COMMAND_MRCP, 4 }, - { "MRSQ", FTP_COMMAND_MRSQ, 4 }, - { "MSAM", FTP_COMMAND_MSAM, 4 }, - { "MSND", FTP_COMMAND_MSND, 4 }, - { "MSOM", FTP_COMMAND_MSOM, 4 }, - { "NLST", FTP_COMMAND_NLST, 4 }, - { "NOOP", FTP_COMMAND_NOOP, 4 }, - { "PASS", FTP_COMMAND_PASS, 4 }, - { "PWD", FTP_COMMAND_PWD, 3 }, - { "QUIT", FTP_COMMAND_QUIT, 4 }, - { "REIN", FTP_COMMAND_REIN, 4 }, - { "REST", FTP_COMMAND_REST, 4 }, - { "RMD", FTP_COMMAND_RMD, 3 }, - { "RNFR", FTP_COMMAND_RNFR, 4 }, - { "RNTO", FTP_COMMAND_RNTO, 4 }, - { "SITE", FTP_COMMAND_SITE, 4 }, - { "SIZE", FTP_COMMAND_SIZE, 4 }, - { "SMNT", FTP_COMMAND_SMNT, 4 }, - { "STAT", FTP_COMMAND_STAT, 4 }, - { "STOU", FTP_COMMAND_STOU, 4 }, - { "STRU", FTP_COMMAND_STRU, 4 }, - { "SYST", FTP_COMMAND_SYST, 4 }, - { "TYPE", FTP_COMMAND_TYPE, 4 }, - { "UMASK", FTP_COMMAND_UMASK, 5 }, - { "USER", FTP_COMMAND_USER, 4 }, - { NULL, FTP_COMMAND_UNKNOWN, 0 } -}; -// clang-format on - -uint64_t ftp_config_memcap = 0; -uint32_t ftp_config_maxtx = 1024; -uint32_t ftp_max_line_len = 4096; - -SC_ATOMIC_DECLARE(uint64_t, ftp_memuse); -SC_ATOMIC_DECLARE(uint64_t, ftp_memcap); - -static FTPTransaction *FTPGetOldestTx(const FtpState *, FTPTransaction *); - -static void FTPParseMemcap(void) -{ - const char *conf_val; - - /** set config values for memcap, prealloc and hash_size */ - if ((ConfGet("app-layer.protocols.ftp.memcap", &conf_val)) == 1) - { - if (ParseSizeStringU64(conf_val, &ftp_config_memcap) < 0) { - SCLogError("Error parsing ftp.memcap " - "from conf file - %s. Killing engine", - conf_val); - exit(EXIT_FAILURE); - } - SCLogInfo("FTP memcap: %"PRIu64, ftp_config_memcap); - } else { - /* default to unlimited */ - ftp_config_memcap = 0; - } - - SC_ATOMIC_INIT(ftp_memuse); - SC_ATOMIC_INIT(ftp_memcap); - - if ((ConfGet("app-layer.protocols.ftp.max-tx", &conf_val)) == 1) { - if (ParseSizeStringU32(conf_val, &ftp_config_maxtx) < 0) { - SCLogError("Error parsing ftp.max-tx " - "from conf file - %s.", - conf_val); - } - SCLogInfo("FTP max tx: %" PRIu32, ftp_config_maxtx); - } - - if ((ConfGet("app-layer.protocols.ftp.max-line-length", &conf_val)) == 1) { - if (ParseSizeStringU32(conf_val, &ftp_max_line_len) < 0) { - SCLogError("Error parsing ftp.max-line-length from conf file - %s.", conf_val); - } - SCLogConfig("FTP max line length: %" PRIu32, ftp_max_line_len); - } -} - -static void FTPIncrMemuse(uint64_t size) -{ - (void) SC_ATOMIC_ADD(ftp_memuse, size); - return; -} - -static void FTPDecrMemuse(uint64_t size) -{ - (void) SC_ATOMIC_SUB(ftp_memuse, size); - return; -} - -uint64_t FTPMemuseGlobalCounter(void) -{ - uint64_t tmpval = SC_ATOMIC_GET(ftp_memuse); - return tmpval; -} - -uint64_t FTPMemcapGlobalCounter(void) -{ - uint64_t tmpval = SC_ATOMIC_GET(ftp_memcap); - return tmpval; -} - -/** - * \brief Check if alloc'ing "size" would mean we're over memcap - * - * \retval 1 if in bounds - * \retval 0 if not in bounds - */ -static int FTPCheckMemcap(uint64_t size) -{ - if (ftp_config_memcap == 0 || size + SC_ATOMIC_GET(ftp_memuse) <= ftp_config_memcap) - return 1; - (void) SC_ATOMIC_ADD(ftp_memcap, 1); - return 0; -} - -static void *FTPCalloc(size_t n, size_t size) -{ - if (FTPCheckMemcap((uint32_t)(n * size)) == 0) - return NULL; - - void *ptr = SCCalloc(n, size); - - if (unlikely(ptr == NULL)) - return NULL; - - FTPIncrMemuse((uint64_t)(n * size)); - return ptr; -} - -static void *FTPRealloc(void *ptr, size_t orig_size, size_t size) -{ - void *rptr = NULL; - - if (FTPCheckMemcap((uint32_t)(size - orig_size)) == 0) - return NULL; - - rptr = SCRealloc(ptr, size); - if (rptr == NULL) - return NULL; - - if (size > orig_size) { - FTPIncrMemuse(size - orig_size); - } else { - FTPDecrMemuse(orig_size - size); - } - - return rptr; -} - -static void FTPFree(void *ptr, size_t size) -{ - SCFree(ptr); - - FTPDecrMemuse((uint64_t)size); -} - -static FTPString *FTPStringAlloc(void) -{ - return FTPCalloc(1, sizeof(FTPString)); -} - -static void FTPStringFree(FTPString *str) -{ - if (str->str) { - FTPFree(str->str, str->len); - } - - FTPFree(str, sizeof(FTPString)); -} - -static void *FTPLocalStorageAlloc(void) -{ - /* needed by the mpm */ - FTPThreadCtx *td = SCCalloc(1, sizeof(*td)); - if (td == NULL) { - exit(EXIT_FAILURE); - } - - td->pmq = SCCalloc(1, sizeof(*td->pmq)); - if (td->pmq == NULL) { - exit(EXIT_FAILURE); - } - PmqSetup(td->pmq); - - td->ftp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx)); - if (unlikely(td->ftp_mpm_thread_ctx == NULL)) { - exit(EXIT_FAILURE); - } - MpmInitThreadCtx(td->ftp_mpm_thread_ctx, FTP_MPM); - return td; -} - -static void FTPLocalStorageFree(void *ptr) -{ - FTPThreadCtx *td = ptr; - if (td != NULL) { - if (td->pmq != NULL) { - PmqFree(td->pmq); - SCFree(td->pmq); - } - - if (td->ftp_mpm_thread_ctx != NULL) { - MpmDestroyThreadCtx(td->ftp_mpm_thread_ctx, FTP_MPM); - SCFree(td->ftp_mpm_thread_ctx); - } - - SCFree(td); - } - - return; -} -static FTPTransaction *FTPTransactionCreate(FtpState *state) -{ - SCEnter(); - FTPTransaction *firsttx = TAILQ_FIRST(&state->tx_list); - if (firsttx && state->tx_cnt - firsttx->tx_id > ftp_config_maxtx) { - // FTP does not set events yet... - return NULL; - } - FTPTransaction *tx = FTPCalloc(1, sizeof(*tx)); - if (tx == NULL) { - return NULL; - } - - TAILQ_INSERT_TAIL(&state->tx_list, tx, next); - tx->tx_id = state->tx_cnt++; - - TAILQ_INIT(&tx->response_list); - - SCLogDebug("new transaction %p (state tx cnt %"PRIu64")", tx, state->tx_cnt); - return tx; -} - -static void FTPTransactionFree(FTPTransaction *tx) -{ - SCEnter(); - - if (tx->tx_data.de_state != NULL) { - DetectEngineStateFree(tx->tx_data.de_state); - } - - if (tx->request) { - FTPFree(tx->request, tx->request_length); - } - - FTPString *str = NULL; - while ((str = TAILQ_FIRST(&tx->response_list))) { - TAILQ_REMOVE(&tx->response_list, str, next); - FTPStringFree(str); - } - - if (tx->tx_data.events) { - AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); - } - - FTPFree(tx, sizeof(*tx)); -} - -typedef struct FtpInput_ { - const uint8_t *buf; - int32_t consumed; - int32_t len; - int32_t orig_len; -} FtpInput; - -static AppLayerResult FTPGetLineForDirection( - FtpState *state, FtpLineState *line, FtpInput *input, bool *current_line_truncated) -{ - SCEnter(); - - /* we have run out of input */ - if (input->len <= 0) - return APP_LAYER_ERROR; - - uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len); - - if (lf_idx == NULL) { - if (!(*current_line_truncated) && (uint32_t)input->len >= ftp_max_line_len) { - *current_line_truncated = true; - line->buf = input->buf; - line->len = ftp_max_line_len; - line->delim_len = 0; - input->len = 0; - SCReturnStruct(APP_LAYER_OK); - } - SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1)); - } else if (*current_line_truncated) { - // Whatever came in with first LF should also get discarded - *current_line_truncated = false; - line->len = 0; - line->delim_len = 0; - input->len = 0; - SCReturnStruct(APP_LAYER_ERROR); - } else { - // There could be one chunk of command data that has LF but post the line limit - // e.g. input_len = 5077 - // lf_idx = 5010 - // max_line_len = 4096 - uint32_t o_consumed = input->consumed; - input->consumed = lf_idx - input->buf + 1; - line->len = input->consumed - o_consumed; - input->len -= line->len; - line->lf_found = true; - DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len); - line->buf = input->buf + o_consumed; - if (line->len >= ftp_max_line_len) { - *current_line_truncated = true; - line->len = ftp_max_line_len; - SCReturnStruct(APP_LAYER_OK); - } - if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) { - line->delim_len = 2; - line->len -= 2; - } else { - line->delim_len = 1; - line->len -= 1; - } - SCReturnStruct(APP_LAYER_OK); - } -} - -/** - * \brief This function is called to determine and set which command is being - * transferred to the ftp server - * \param thread context - * \param input input line of the command - * \param len of the command - * \param cmd_descriptor when the command has been parsed - * - * \retval 1 when the command is parsed, 0 otherwise - */ -static int FTPParseRequestCommand( - FTPThreadCtx *td, FtpLineState *line, const FtpCommand **cmd_descriptor) -{ - SCEnter(); - - /* I don't like this pmq reset here. We'll devise a method later, that - * should make the use of the mpm very efficient */ - PmqReset(td->pmq); - int mpm_cnt = mpm_table[FTP_MPM].Search( - ftp_mpm_ctx, td->ftp_mpm_thread_ctx, td->pmq, line->buf, line->len); - if (mpm_cnt) { - *cmd_descriptor = &FtpCommands[td->pmq->rule_id_array[0]]; - SCReturnInt(1); - } - - *cmd_descriptor = NULL; - SCReturnInt(0); -} - -struct FtpTransferCmd { - /** Need to look like a ExpectationData so DFree must - * be first field . */ - void (*DFree)(void *); - uint64_t flow_id; - uint8_t *file_name; - uint16_t file_len; - uint8_t direction; /**< direction in which the data will flow */ - FtpRequestCommand cmd; -}; - -static void FtpTransferCmdFree(void *data) -{ - struct FtpTransferCmd *cmd = (struct FtpTransferCmd *) data; - if (cmd == NULL) - return; - if (cmd->file_name) { - FTPFree(cmd->file_name, cmd->file_len + 1); - } - FTPFree(cmd, sizeof(struct FtpTransferCmd)); -} - -static uint32_t CopyCommandLine(uint8_t **dest, FtpLineState *line) -{ - if (likely(line->len)) { - uint8_t *where = FTPCalloc(line->len + 1, sizeof(char)); - if (unlikely(where == NULL)) { - return 0; - } - memcpy(where, line->buf, line->len); - - /* Remove trailing newlines/carriage returns */ - while (line->len && isspace((unsigned char)where[line->len - 1])) { - line->len--; - } - - where[line->len] = '\0'; - *dest = where; - } - /* either 0 or actual */ - return line->len ? line->len + 1 : 0; -} - -#include "util-print.h" - -/** - * \brief This function is called to retrieve a ftp request - * \param ftp_state the ftp state structure for the parser - * - * \retval APP_LAYER_OK when input was process successfully - * \retval APP_LAYER_ERROR when a unrecoverable error was encountered - */ -static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - FTPThreadCtx *thread_data = local_data; - - SCEnter(); - /* PrintRawDataFp(stdout, input,input_len); */ - - FtpState *state = (FtpState *)ftp_state; - void *ptmp; - - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) { - SCReturnStruct(APP_LAYER_OK); - } else if (input == NULL || input_len == 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - - FtpInput ftpi = { .buf = input, .len = input_len, .orig_len = input_len, .consumed = 0 }; - FtpLineState line = { .buf = NULL, .len = 0, .delim_len = 0, .lf_found = false }; - - uint8_t direction = STREAM_TOSERVER; - AppLayerResult res; - while (1) { - res = FTPGetLineForDirection(state, &line, &ftpi, &state->current_line_truncated_ts); - if (res.status == 1) { - return res; - } else if (res.status == -1) { - break; - } - const FtpCommand *cmd_descriptor; - - if (!FTPParseRequestCommand(thread_data, &line, &cmd_descriptor)) { - state->command = FTP_COMMAND_UNKNOWN; - continue; - } - - state->command = cmd_descriptor->command; - FTPTransaction *tx = FTPTransactionCreate(state); - if (unlikely(tx == NULL)) - SCReturnStruct(APP_LAYER_ERROR); - state->curr_tx = tx; - - tx->command_descriptor = cmd_descriptor; - tx->request_length = CopyCommandLine(&tx->request, &line); - tx->request_truncated = state->current_line_truncated_ts; - - if (line.lf_found) { - state->current_line_truncated_ts = false; - } - if (tx->request_truncated) { - AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, FtpEventRequestCommandTooLong); - } - - /* change direction (default to server) so expectation will handle - * the correct message when expectation will match. - * For ftp active mode, data connection direction is opposite to - * control direction. - */ - if ((state->active && state->command == FTP_COMMAND_STOR) || - (!state->active && state->command == FTP_COMMAND_RETR)) { - direction = STREAM_TOCLIENT; - } - - switch (state->command) { - case FTP_COMMAND_EPRT: - // fallthrough - case FTP_COMMAND_PORT: - if (line.len + 1 > state->port_line_size) { - /* Allocate an extra byte for a NULL terminator */ - ptmp = FTPRealloc(state->port_line, state->port_line_size, line.len); - if (ptmp == NULL) { - if (state->port_line) { - FTPFree(state->port_line, state->port_line_size); - state->port_line = NULL; - state->port_line_size = 0; - state->port_line_len = 0; - } - SCReturnStruct(APP_LAYER_OK); - } - state->port_line = ptmp; - state->port_line_size = line.len; - } - memcpy(state->port_line, line.buf, line.len); - state->port_line_len = line.len; - break; - case FTP_COMMAND_RETR: - // fallthrough - case FTP_COMMAND_STOR: { - /* Ensure that there is a negotiated dyn port and a file - * name -- need more than 5 chars: cmd [4], space, - */ - if (state->dyn_port == 0 || line.len < 6) { - SCReturnStruct(APP_LAYER_ERROR); - } - struct FtpTransferCmd *data = FTPCalloc(1, sizeof(struct FtpTransferCmd)); - if (data == NULL) - SCReturnStruct(APP_LAYER_ERROR); - data->DFree = FtpTransferCmdFree; - /* - * Min size has been checked in FTPParseRequestCommand - * SC_FILENAME_MAX includes the null - */ - uint32_t file_name_len = MIN(SC_FILENAME_MAX - 1, line.len - 5); -#if SC_FILENAME_MAX > UINT16_MAX -#error SC_FILENAME_MAX is greater than UINT16_MAX -#endif - data->file_name = FTPCalloc(file_name_len + 1, sizeof(char)); - if (data->file_name == NULL) { - FtpTransferCmdFree(data); - SCReturnStruct(APP_LAYER_ERROR); - } - data->file_name[file_name_len] = 0; - data->file_len = (uint16_t)file_name_len; - memcpy(data->file_name, line.buf + 5, file_name_len); - data->cmd = state->command; - data->flow_id = FlowGetId(f); - data->direction = direction; - int ret = AppLayerExpectationCreate(f, direction, - 0, state->dyn_port, ALPROTO_FTPDATA, data); - if (ret == -1) { - FtpTransferCmdFree(data); - SCLogDebug("No expectation created."); - SCReturnStruct(APP_LAYER_ERROR); - } else { - SCLogDebug("Expectation created [direction: %s, dynamic port %"PRIu16"].", - state->active ? "to server" : "to client", - state->dyn_port); - } - - /* reset the dyn port to avoid duplicate */ - state->dyn_port = 0; - /* reset active/passive indicator */ - state->active = false; - } break; - default: - break; - } - if (line.len >= ftp_max_line_len) { - ftpi.consumed = ftpi.len + 1; - break; - } - } - - SCReturnStruct(APP_LAYER_OK); -} - -static int FTPParsePassiveResponse(Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len) -{ - uint16_t dyn_port = rs_ftp_pasv_response(input, input_len); - if (dyn_port == 0) { - return -1; - } - SCLogDebug("FTP passive mode (v4): dynamic port %"PRIu16"", dyn_port); - state->active = false; - state->dyn_port = dyn_port; - state->curr_tx->dyn_port = dyn_port; - state->curr_tx->active = false; - - return 0; -} - -static int FTPParsePassiveResponseV6(Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len) -{ - uint16_t dyn_port = rs_ftp_epsv_response(input, input_len); - if (dyn_port == 0) { - return -1; - } - SCLogDebug("FTP passive mode (v6): dynamic port %"PRIu16"", dyn_port); - state->active = false; - state->dyn_port = dyn_port; - state->curr_tx->dyn_port = dyn_port; - state->curr_tx->active = false; - return 0; -} - -/** - * \brief Handle preliminary replies -- keep tx open - * \retval bool True for a positive preliminary reply; false otherwise - * - * 1yz Positive Preliminary reply - * - * The requested action is being initiated; expect another - * reply before proceeding with a new command - */ -static inline bool FTPIsPPR(const uint8_t *input, uint32_t input_len) -{ - return input_len >= 4 && isdigit(input[0]) && input[0] == '1' && - isdigit(input[1]) && isdigit(input[2]) && isspace(input[3]); -} - -/** - * \brief This function is called to retrieve a ftp response - * \param ftp_state the ftp state structure for the parser - * \param input input line of the command - * \param input_len length of the request - * \param output the resulting output - * - * \retval 1 when the command is parsed, 0 otherwise - */ -static AppLayerResult FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - FtpState *state = (FtpState *)ftp_state; - - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - if (unlikely(input_len == 0)) { - SCReturnStruct(APP_LAYER_OK); - } - FtpInput ftpi = { .buf = input, .len = input_len, .orig_len = input_len, .consumed = 0 }; - FtpLineState line = { .buf = NULL, .len = 0, .delim_len = 0, .lf_found = false }; - - FTPTransaction *lasttx = TAILQ_FIRST(&state->tx_list); - AppLayerResult res; - while (1) { - res = FTPGetLineForDirection(state, &line, &ftpi, &state->current_line_truncated_tc); - if (res.status == 1) { - return res; - } else if (res.status == -1) { - break; - } - FTPTransaction *tx = FTPGetOldestTx(state, lasttx); - if (tx == NULL) { - tx = FTPTransactionCreate(state); - } - if (unlikely(tx == NULL)) { - SCReturnStruct(APP_LAYER_ERROR); - } - lasttx = tx; - if (state->command == FTP_COMMAND_UNKNOWN || tx->command_descriptor == NULL) { - /* unknown */ - tx->command_descriptor = &FtpCommands[FTP_COMMAND_MAX - 1]; - } - - state->curr_tx = tx; - uint16_t dyn_port; - switch (state->command) { - case FTP_COMMAND_AUTH_TLS: - if (line.len >= 4 && SCMemcmp("234 ", line.buf, 4) == 0) { - AppLayerRequestProtocolTLSUpgrade(f); - } - break; - - case FTP_COMMAND_EPRT: - dyn_port = rs_ftp_active_eprt(state->port_line, state->port_line_len); - if (dyn_port == 0) { - goto tx_complete; - } - state->dyn_port = dyn_port; - state->active = true; - tx->dyn_port = dyn_port; - tx->active = true; - SCLogDebug("FTP active mode (v6): dynamic port %" PRIu16 "", dyn_port); - break; - - case FTP_COMMAND_PORT: - dyn_port = rs_ftp_active_port(state->port_line, state->port_line_len); - if (dyn_port == 0) { - goto tx_complete; - } - state->dyn_port = dyn_port; - state->active = true; - tx->dyn_port = state->dyn_port; - tx->active = true; - SCLogDebug("FTP active mode (v4): dynamic port %" PRIu16 "", dyn_port); - break; - - case FTP_COMMAND_PASV: - if (line.len >= 4 && SCMemcmp("227 ", line.buf, 4) == 0) { - FTPParsePassiveResponse(f, ftp_state, line.buf, line.len); - } - break; - - case FTP_COMMAND_EPSV: - if (line.len >= 4 && SCMemcmp("229 ", line.buf, 4) == 0) { - FTPParsePassiveResponseV6(f, ftp_state, line.buf, line.len); - } - break; - default: - break; - } - - if (likely(line.len)) { - FTPString *response = FTPStringAlloc(); - if (likely(response)) { - response->len = CopyCommandLine(&response->str, &line); - response->truncated = state->current_line_truncated_tc; - if (response->truncated) { - AppLayerDecoderEventsSetEventRaw( - &tx->tx_data.events, FtpEventResponseCommandTooLong); - } - if (line.lf_found) { - state->current_line_truncated_tc = false; - } - TAILQ_INSERT_TAIL(&tx->response_list, response, next); - } - } - - /* Handle preliminary replies -- keep tx open */ - if (FTPIsPPR(line.buf, line.len)) { - continue; - } - tx_complete: - tx->done = true; - - if (line.len >= ftp_max_line_len) { - ftpi.consumed = ftpi.len + 1; - break; - } - } - - SCReturnStruct(APP_LAYER_OK); -} - - -#ifdef DEBUG -static SCMutex ftp_state_mem_lock = SCMUTEX_INITIALIZER; -static uint64_t ftp_state_memuse = 0; -static uint64_t ftp_state_memcnt = 0; -#endif - -static void *FTPStateAlloc(void *orig_state, AppProto proto_orig) -{ - void *s = FTPCalloc(1, sizeof(FtpState)); - if (unlikely(s == NULL)) - return NULL; - - FtpState *ftp_state = (FtpState *) s; - TAILQ_INIT(&ftp_state->tx_list); - -#ifdef DEBUG - SCMutexLock(&ftp_state_mem_lock); - ftp_state_memcnt++; - ftp_state_memuse+=sizeof(FtpState); - SCMutexUnlock(&ftp_state_mem_lock); -#endif - return s; -} - -static void FTPStateFree(void *s) -{ - FtpState *fstate = (FtpState *) s; - if (fstate->port_line != NULL) - FTPFree(fstate->port_line, fstate->port_line_size); - - FTPTransaction *tx = NULL; - while ((tx = TAILQ_FIRST(&fstate->tx_list))) { - TAILQ_REMOVE(&fstate->tx_list, tx, next); - SCLogDebug("[%s] state %p id %" PRIu64 ", Freeing %d bytes at %p", - tx->command_descriptor->command_name, s, tx->tx_id, tx->request_length, - tx->request); - FTPTransactionFree(tx); - } - - FTPFree(s, sizeof(FtpState)); -#ifdef DEBUG - SCMutexLock(&ftp_state_mem_lock); - ftp_state_memcnt--; - ftp_state_memuse-=sizeof(FtpState); - SCMutexUnlock(&ftp_state_mem_lock); -#endif -} - -/** - * \brief This function returns the oldest open transaction; if none - * are open, then the oldest transaction is returned - * \param ftp_state the ftp state structure for the parser - * \param starttx the ftp transaction where to start looking - * - * \retval transaction pointer when a transaction was found; NULL otherwise. - */ -static FTPTransaction *FTPGetOldestTx(const FtpState *ftp_state, FTPTransaction *starttx) -{ - if (unlikely(!ftp_state)) { - SCLogDebug("NULL state object; no transactions available"); - return NULL; - } - FTPTransaction *tx = starttx; - FTPTransaction *lasttx = NULL; - while(tx != NULL) { - /* Return oldest open tx */ - if (!tx->done) { - SCLogDebug("Returning tx %p id %"PRIu64, tx, tx->tx_id); - return tx; - } - /* save for the end */ - lasttx = tx; - tx = TAILQ_NEXT(tx, next); - } - /* All tx are closed; return last element */ - if (lasttx) - SCLogDebug("Returning OLDEST tx %p id %"PRIu64, lasttx, lasttx->tx_id); - return lasttx; -} - -static void *FTPGetTx(void *state, uint64_t tx_id) -{ - FtpState *ftp_state = (FtpState *)state; - if (ftp_state) { - FTPTransaction *tx = NULL; - - if (ftp_state->curr_tx == NULL) - return NULL; - if (ftp_state->curr_tx->tx_id == tx_id) - return ftp_state->curr_tx; - - TAILQ_FOREACH(tx, &ftp_state->tx_list, next) { - if (tx->tx_id == tx_id) - return tx; - } - } - return NULL; -} - -static AppLayerTxData *FTPGetTxData(void *vtx) -{ - FTPTransaction *tx = (FTPTransaction *)vtx; - return &tx->tx_data; -} - -static AppLayerStateData *FTPGetStateData(void *vstate) -{ - FtpState *s = (FtpState *)vstate; - return &s->state_data; -} - -static void FTPStateTransactionFree(void *state, uint64_t tx_id) -{ - FtpState *ftp_state = state; - FTPTransaction *tx = NULL; - TAILQ_FOREACH(tx, &ftp_state->tx_list, next) { - if (tx_id < tx->tx_id) - break; - else if (tx_id > tx->tx_id) - continue; - - if (tx == ftp_state->curr_tx) - ftp_state->curr_tx = NULL; - TAILQ_REMOVE(&ftp_state->tx_list, tx, next); - FTPTransactionFree(tx); - break; - } -} - -static uint64_t FTPGetTxCnt(void *state) -{ - uint64_t cnt = 0; - FtpState *ftp_state = state; - if (ftp_state) { - cnt = ftp_state->tx_cnt; - } - SCLogDebug("returning state %p %"PRIu64, state, cnt); - return cnt; -} - -static int FTPGetAlstateProgress(void *vtx, uint8_t direction) -{ - SCLogDebug("tx %p", vtx); - FTPTransaction *tx = vtx; - - if (!tx->done) { - if (direction == STREAM_TOSERVER && tx->command_descriptor->command == FTP_COMMAND_PORT) { - return FTP_STATE_PORT_DONE; - } - return FTP_STATE_IN_PROGRESS; - } - - return FTP_STATE_FINISHED; -} - - -static int FTPRegisterPatternsForProtocolDetection(void) -{ - if (AppLayerProtoDetectPMRegisterPatternCI( - IPPROTO_TCP, ALPROTO_FTP, "220 (", 5, 0, STREAM_TOCLIENT) < 0) { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI( - IPPROTO_TCP, ALPROTO_FTP, "FEAT", 4, 0, STREAM_TOSERVER) < 0) { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI( - IPPROTO_TCP, ALPROTO_FTP, "USER ", 5, 0, STREAM_TOSERVER) < 0) { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI( - IPPROTO_TCP, ALPROTO_FTP, "PASS ", 5, 0, STREAM_TOSERVER) < 0) { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI( - IPPROTO_TCP, ALPROTO_FTP, "PORT ", 5, 0, STREAM_TOSERVER) < 0) { - return -1; - } - - return 0; -} - - -static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; - -/** - * \brief This function is called to retrieve a ftp request - * \param ftp_state the ftp state structure for the parser - * \param output the resulting output - * - * \retval 1 when the command is parsed, 0 otherwise - */ -static AppLayerResult FTPDataParse(Flow *f, FtpDataState *ftpdata_state, - AppLayerParserState *pstate, StreamSlice stream_slice, void *local_data, uint8_t direction) -{ - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - const bool eof = (direction & STREAM_TOSERVER) - ? AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) != 0 - : AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) != 0; - - ftpdata_state->tx_data.file_flags |= ftpdata_state->state_data.file_flags; - if (ftpdata_state->tx_data.file_tx == 0) - ftpdata_state->tx_data.file_tx = direction & (STREAM_TOSERVER | STREAM_TOCLIENT); - - /* we depend on detection engine for file pruning */ - const uint16_t flags = FileFlowFlagsToFlags(ftpdata_state->tx_data.file_flags, direction); - int ret = 0; - - SCLogDebug("FTP-DATA input_len %u flags %04x dir %d/%s EOF %s", input_len, flags, direction, - (direction & STREAM_TOSERVER) ? "toserver" : "toclient", eof ? "true" : "false"); - - SCLogDebug("FTP-DATA flags %04x dir %d", flags, direction); - if (input_len && ftpdata_state->files == NULL) { - struct FtpTransferCmd *data = - (struct FtpTransferCmd *)FlowGetStorageById(f, AppLayerExpectationGetFlowId()); - if (data == NULL) { - SCReturnStruct(APP_LAYER_ERROR); - } - - /* we shouldn't get data in the wrong dir. Don't set things up for this dir */ - if ((direction & data->direction) == 0) { - // TODO set event for data in wrong direction - SCLogDebug("input %u not for our direction (%s): %s/%s", input_len, - (direction & STREAM_TOSERVER) ? "toserver" : "toclient", - data->cmd == FTP_COMMAND_STOR ? "STOR" : "RETR", - (data->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); - SCReturnStruct(APP_LAYER_OK); - } - - ftpdata_state->files = FileContainerAlloc(); - if (ftpdata_state->files == NULL) { - FlowFreeStorageById(f, AppLayerExpectationGetFlowId()); - SCReturnStruct(APP_LAYER_ERROR); - } - - ftpdata_state->file_name = data->file_name; - ftpdata_state->file_len = data->file_len; - data->file_name = NULL; - data->file_len = 0; - f->parent_id = data->flow_id; - ftpdata_state->command = data->cmd; - switch (data->cmd) { - case FTP_COMMAND_STOR: - ftpdata_state->direction = data->direction; - SCLogDebug("STOR data to %s", - (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); - break; - case FTP_COMMAND_RETR: - ftpdata_state->direction = data->direction; - SCLogDebug("RETR data to %s", - (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); - break; - default: - break; - } - - /* open with fixed track_id 0 as we can have just one - * file per ftp-data flow. */ - if (FileOpenFileWithId(ftpdata_state->files, &sbcfg, - 0ULL, (uint8_t *) ftpdata_state->file_name, - ftpdata_state->file_len, - input, input_len, flags) != 0) { - SCLogDebug("Can't open file"); - ret = -1; - } - FlowFreeStorageById(f, AppLayerExpectationGetFlowId()); - ftpdata_state->tx_data.files_opened = 1; - } else { - if (ftpdata_state->state == FTPDATA_STATE_FINISHED) { - SCLogDebug("state is already finished"); - DEBUG_VALIDATE_BUG_ON(input_len); // data after state finished is a bug. - SCReturnStruct(APP_LAYER_OK); - } - if ((direction & ftpdata_state->direction) == 0) { - if (input_len) { - // TODO set event for data in wrong direction - } - SCLogDebug("input %u not for us (%s): %s/%s", input_len, - (direction & STREAM_TOSERVER) ? "toserver" : "toclient", - ftpdata_state->command == FTP_COMMAND_STOR ? "STOR" : "RETR", - (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); - SCReturnStruct(APP_LAYER_OK); - } - if (input_len != 0) { - ret = FileAppendData(ftpdata_state->files, &sbcfg, input, input_len); - if (ret == -2) { - ret = 0; - SCLogDebug("FileAppendData() - file no longer being extracted"); - goto out; - } else if (ret < 0) { - SCLogDebug("FileAppendData() failed: %d", ret); - ret = -2; - goto out; - } - } - } - - BUG_ON((direction & ftpdata_state->direction) == 0); // should be unreachable - if (eof) { - ret = FileCloseFile(ftpdata_state->files, &sbcfg, NULL, 0, flags); - ftpdata_state->state = FTPDATA_STATE_FINISHED; - SCLogDebug("closed because of eof: state now FTPDATA_STATE_FINISHED"); - } -out: - if (ret < 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - SCReturnStruct(APP_LAYER_OK); -} - -static AppLayerResult FTPDataParseRequest(Flow *f, void *ftp_state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - return FTPDataParse(f, ftp_state, pstate, stream_slice, local_data, STREAM_TOSERVER); -} - -static AppLayerResult FTPDataParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - return FTPDataParse(f, ftp_state, pstate, stream_slice, local_data, STREAM_TOCLIENT); -} - -#ifdef DEBUG -static SCMutex ftpdata_state_mem_lock = SCMUTEX_INITIALIZER; -static uint64_t ftpdata_state_memuse = 0; -static uint64_t ftpdata_state_memcnt = 0; -#endif - -static void *FTPDataStateAlloc(void *orig_state, AppProto proto_orig) -{ - void *s = FTPCalloc(1, sizeof(FtpDataState)); - if (unlikely(s == NULL)) - return NULL; - - FtpDataState *state = (FtpDataState *) s; - state->state = FTPDATA_STATE_IN_PROGRESS; - -#ifdef DEBUG - SCMutexLock(&ftpdata_state_mem_lock); - ftpdata_state_memcnt++; - ftpdata_state_memuse+=sizeof(FtpDataState); - SCMutexUnlock(&ftpdata_state_mem_lock); -#endif - return s; -} - -static void FTPDataStateFree(void *s) -{ - FtpDataState *fstate = (FtpDataState *) s; - - if (fstate->tx_data.de_state != NULL) { - DetectEngineStateFree(fstate->tx_data.de_state); - } - if (fstate->file_name != NULL) { - FTPFree(fstate->file_name, fstate->file_len + 1); - } - - FileContainerFree(fstate->files, &sbcfg); - - FTPFree(s, sizeof(FtpDataState)); -#ifdef DEBUG - SCMutexLock(&ftpdata_state_mem_lock); - ftpdata_state_memcnt--; - ftpdata_state_memuse-=sizeof(FtpDataState); - SCMutexUnlock(&ftpdata_state_mem_lock); -#endif -} - -static AppLayerTxData *FTPDataGetTxData(void *vtx) -{ - FtpDataState *ftp_state = (FtpDataState *)vtx; - return &ftp_state->tx_data; -} - -static AppLayerStateData *FTPDataGetStateData(void *vstate) -{ - FtpDataState *ftp_state = (FtpDataState *)vstate; - return &ftp_state->state_data; -} - -static void FTPDataStateTransactionFree(void *state, uint64_t tx_id) -{ - /* do nothing */ -} - -static void *FTPDataGetTx(void *state, uint64_t tx_id) -{ - FtpDataState *ftp_state = (FtpDataState *)state; - return ftp_state; -} - -static uint64_t FTPDataGetTxCnt(void *state) -{ - /* ftp-data is single tx */ - return 1; -} - -static int FTPDataGetAlstateProgress(void *tx, uint8_t direction) -{ - FtpDataState *ftpdata_state = (FtpDataState *)tx; - if (direction == ftpdata_state->direction) - return ftpdata_state->state; - else - return FTPDATA_STATE_FINISHED; -} - -static AppLayerGetFileState FTPDataStateGetTxFiles(void *_state, void *tx, uint8_t direction) -{ - FtpDataState *ftpdata_state = (FtpDataState *)tx; - AppLayerGetFileState files = { .fc = NULL, .cfg = &sbcfg }; - - if (direction == ftpdata_state->direction) - files.fc = ftpdata_state->files; - - return files; -} - -static void FTPSetMpmState(void) -{ - ftp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx)); - if (unlikely(ftp_mpm_ctx == NULL)) { - exit(EXIT_FAILURE); - } - MpmInitCtx(ftp_mpm_ctx, FTP_MPM); - - uint32_t i = 0; - for (i = 0; i < sizeof(FtpCommands)/sizeof(FtpCommand) - 1; i++) { - const FtpCommand *cmd = &FtpCommands[i]; - if (cmd->command_length == 0) - continue; - - MpmAddPatternCI(ftp_mpm_ctx, - (uint8_t *)cmd->command_name, - cmd->command_length, - 0 /* defunct */, 0 /* defunct */, - i /* id */, i /* rule id */ , 0 /* no flags */); - } - - mpm_table[FTP_MPM].Prepare(ftp_mpm_ctx); - -} - -static void FTPFreeMpmState(void) -{ - if (ftp_mpm_ctx != NULL) { - mpm_table[FTP_MPM].DestroyCtx(ftp_mpm_ctx); - SCFree(ftp_mpm_ctx); - ftp_mpm_ctx = NULL; - } -} - -/** \brief FTP tx iterator, specialized for its linked list - * - * \retval txptr or NULL if no more txs in list - */ -static AppLayerGetTxIterTuple FTPGetTxIterator(const uint8_t ipproto, const AppProto alproto, - void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) -{ - FtpState *ftp_state = (FtpState *)alstate; - AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; - if (ftp_state) { - FTPTransaction *tx_ptr; - if (state->un.ptr == NULL) { - tx_ptr = TAILQ_FIRST(&ftp_state->tx_list); - } else { - tx_ptr = (FTPTransaction *)state->un.ptr; - } - if (tx_ptr) { - while (tx_ptr->tx_id < min_tx_id) { - tx_ptr = TAILQ_NEXT(tx_ptr, next); - if (!tx_ptr) { - return no_tuple; - } - } - if (tx_ptr->tx_id >= max_tx_id) { - return no_tuple; - } - state->un.ptr = TAILQ_NEXT(tx_ptr, next); - AppLayerGetTxIterTuple tuple = { - .tx_ptr = tx_ptr, - .tx_id = tx_ptr->tx_id, - .has_next = (state->un.ptr != NULL), - }; - return tuple; - } - } - return no_tuple; -} - -void RegisterFTPParsers(void) -{ - const char *proto_name = "ftp"; - const char *proto_data_name = "ftp-data"; - - /** FTP */ - if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_FTP, proto_name); - if (FTPRegisterPatternsForProtocolDetection() < 0 ) - return; - AppLayerProtoDetectRegisterProtocol(ALPROTO_FTPDATA, proto_data_name); - } - - if (AppLayerParserConfParserEnabled("tcp", proto_name)) { - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER, - FTPParseRequest); - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOCLIENT, - FTPParseResponse); - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree); - AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER | STREAM_TOCLIENT); - - AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree); - - AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx); - AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxData); - AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxIterator); - AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetStateData); - - AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_FTP, FTPLocalStorageAlloc, - FTPLocalStorageFree); - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt); - - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress); - - AppLayerParserRegisterStateProgressCompletionStatus( - ALPROTO_FTP, FTP_STATE_FINISHED, FTP_STATE_FINISHED); - - AppLayerRegisterExpectationProto(IPPROTO_TCP, ALPROTO_FTPDATA); - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER, - FTPDataParseRequest); - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOCLIENT, - FTPDataParseResponse); - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree); - AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER | STREAM_TOCLIENT); - AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree); - - AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetTxFiles); - - AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx); - AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxData); - AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetStateData); - - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt); - - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress); - - AppLayerParserRegisterStateProgressCompletionStatus( - ALPROTO_FTPDATA, FTPDATA_STATE_FINISHED, FTPDATA_STATE_FINISHED); - - AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info); - AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info_by_id); - - sbcfg.buf_size = 4096; - sbcfg.Calloc = FTPCalloc; - sbcfg.Realloc = FTPRealloc; - sbcfg.Free = FTPFree; - - FTPParseMemcap(); - } else { - SCLogInfo("Parsed disabled for %s protocol. Protocol detection" - "still on.", proto_name); - } - - FTPSetMpmState(); - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_FTP, FTPParserRegisterTests); -#endif -} - -void FTPAtExitPrintStats(void) -{ -#ifdef DEBUG - SCMutexLock(&ftp_state_mem_lock); - SCLogDebug("ftp_state_memcnt %"PRIu64", ftp_state_memuse %"PRIu64"", - ftp_state_memcnt, ftp_state_memuse); - SCMutexUnlock(&ftp_state_mem_lock); -#endif -} - - -/* - * \brief Returns the ending offset of the next line from a multi-line buffer. - * - * "Buffer" refers to a FTP response in a single buffer containing multiple lines. - * Here, "next line" is defined as terminating on - * - Newline character - * - Null character - * - * \param buffer Contains zero or more characters. - * \param len Size, in bytes, of buffer. - * - * \retval Offset from the start of buffer indicating the where the - * next "line ends". The characters between the input buffer and this - * value comprise the line. - * - * NULL is found first or a newline isn't found, then UINT16_MAX is returned. - */ -uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len) -{ - if (!buffer || *buffer == '\0') { - return UINT16_MAX; - } - - char *c = strchr(buffer, '\n'); - return c == NULL ? len : (uint16_t)(c - buffer + 1); -} - -bool EveFTPDataAddMetadata(void *vtx, JsonBuilder *jb) -{ - const FtpDataState *ftp_state = (FtpDataState *)vtx; - jb_open_object(jb, "ftp_data"); - - if (ftp_state->file_name) { - jb_set_string_from_bytes(jb, "filename", ftp_state->file_name, ftp_state->file_len); - } - switch (ftp_state->command) { - case FTP_COMMAND_STOR: - JB_SET_STRING(jb, "command", "STOR"); - break; - case FTP_COMMAND_RETR: - JB_SET_STRING(jb, "command", "RETR"); - break; - default: - break; - } - jb_close(jb); - return true; -} - -/** - * \brief Free memory allocated for global FTP parser state. - */ -void FTPParserCleanup(void) -{ - FTPFreeMpmState(); -} - -/* UNITTESTS */ -#ifdef UNITTESTS -#include "stream-tcp.h" - -/** \test Send a get request in one chunk. */ -static int FTPParserTest01(void) -{ - Flow f; - uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n"; - uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_FTP; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, - STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen); - FAIL_IF(r != 0); - - FtpState *ftp_state = f.alstate; - FAIL_IF_NULL(ftp_state); - FAIL_IF(ftp_state->command != FTP_COMMAND_PORT); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - PASS; -} - -/** \test Supply RETR without a filename */ -static int FTPParserTest11(void) -{ - Flow f; - uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n"; - uint8_t ftpbuf2[] = "RETR\r\n"; - uint8_t ftpbuf3[] = "227 OK\r\n"; - TcpSession ssn; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_FTP; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, - STREAM_TOSERVER | STREAM_START, ftpbuf1, - sizeof(ftpbuf1) - 1); - FAIL_IF(r != 0); - - /* Response */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, - STREAM_TOCLIENT, - ftpbuf3, - sizeof(ftpbuf3) - 1); - FAIL_IF(r != 0); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, - STREAM_TOSERVER, ftpbuf2, - sizeof(ftpbuf2) - 1); - FAIL_IF(r == 0); - - FtpState *ftp_state = f.alstate; - FAIL_IF_NULL(ftp_state); - - FAIL_IF(ftp_state->command != FTP_COMMAND_RETR); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - PASS; -} - -/** \test Supply STOR without a filename */ -static int FTPParserTest12(void) -{ - Flow f; - uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n"; - uint8_t ftpbuf2[] = "STOR\r\n"; - uint8_t ftpbuf3[] = "227 OK\r\n"; - TcpSession ssn; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_FTP; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, - STREAM_TOSERVER | STREAM_START, ftpbuf1, - sizeof(ftpbuf1) - 1); - FAIL_IF(r != 0); - - /* Response */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, - STREAM_TOCLIENT, - ftpbuf3, - sizeof(ftpbuf3) - 1); - FAIL_IF(r != 0); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, - STREAM_TOSERVER, ftpbuf2, - sizeof(ftpbuf2) - 1); - FAIL_IF(r == 0); - - FtpState *ftp_state = f.alstate; - FAIL_IF_NULL(ftp_state); - - FAIL_IF(ftp_state->command != FTP_COMMAND_STOR); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - PASS; -} -#endif /* UNITTESTS */ - -void FTPParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("FTPParserTest01", FTPParserTest01); - UtRegisterTest("FTPParserTest11", FTPParserTest11); - UtRegisterTest("FTPParserTest12", FTPParserTest12); -#endif /* UNITTESTS */ -} - diff --git a/src/app-layer-ftp.h b/src/app-layer-ftp.h deleted file mode 100644 index fb71d6b52de7..000000000000 --- a/src/app-layer-ftp.h +++ /dev/null @@ -1,196 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * \author Jeff Lucovsky - */ - -#ifndef __APP_LAYER_FTP_H__ -#define __APP_LAYER_FTP_H__ - -#include "rust.h" - -enum { - FTP_STATE_IN_PROGRESS, - FTP_STATE_PORT_DONE, - FTP_STATE_FINISHED, -}; - -typedef enum { - FTP_COMMAND_UNKNOWN = 0, - FTP_COMMAND_ABOR, - FTP_COMMAND_ACCT, - FTP_COMMAND_ALLO, - FTP_COMMAND_APPE, - FTP_COMMAND_AUTH_TLS, - FTP_COMMAND_CDUP, - FTP_COMMAND_CHMOD, - FTP_COMMAND_CWD, - FTP_COMMAND_DELE, - FTP_COMMAND_EPSV, - FTP_COMMAND_HELP, - FTP_COMMAND_IDLE, - FTP_COMMAND_LIST, - FTP_COMMAND_MAIL, - FTP_COMMAND_MDTM, - FTP_COMMAND_MKD, - FTP_COMMAND_MLFL, - FTP_COMMAND_MODE, - FTP_COMMAND_MRCP, - FTP_COMMAND_MRSQ, - FTP_COMMAND_MSAM, - FTP_COMMAND_MSND, - FTP_COMMAND_MSOM, - FTP_COMMAND_NLST, - FTP_COMMAND_NOOP, - FTP_COMMAND_PASS, - FTP_COMMAND_PASV, - FTP_COMMAND_PORT, - FTP_COMMAND_PWD, - FTP_COMMAND_QUIT, - FTP_COMMAND_REIN, - FTP_COMMAND_REST, - FTP_COMMAND_RETR, - FTP_COMMAND_RMD, - FTP_COMMAND_RNFR, - FTP_COMMAND_RNTO, - FTP_COMMAND_SITE, - FTP_COMMAND_SIZE, - FTP_COMMAND_SMNT, - FTP_COMMAND_STAT, - FTP_COMMAND_STOR, - FTP_COMMAND_STOU, - FTP_COMMAND_STRU, - FTP_COMMAND_SYST, - FTP_COMMAND_TYPE, - FTP_COMMAND_UMASK, - FTP_COMMAND_USER, - FTP_COMMAND_EPRT, - - /* must be last */ - FTP_COMMAND_MAX - /** \todo more if missing.. */ -} FtpRequestCommand; - -typedef struct FtpCommand_ { - const char *command_name; - FtpRequestCommand command; - const uint8_t command_length; -} FtpCommand; -extern const FtpCommand FtpCommands[FTP_COMMAND_MAX + 1]; - -typedef uint32_t FtpRequestCommandArgOfs; - -/** used to hold the line state when we have fragmentation. */ -typedef struct FtpLineState_ { - /** used to indicate if the current_line buffer is a malloced buffer. We - * use a malloced buffer, if a line is fragmented */ - const uint8_t *buf; - uint32_t len; - uint8_t delim_len; - bool lf_found; -} FtpLineState; - -typedef struct FTPString_ { - uint8_t *str; - uint32_t len; - bool truncated; - TAILQ_ENTRY(FTPString_) next; -} FTPString; - -typedef struct FTPTransaction_ { - /** id of this tx, starting at 0 */ - uint64_t tx_id; - - AppLayerTxData tx_data; - - /* for the request */ - uint32_t request_length; - uint8_t *request; - bool request_truncated; - - /* for the command description */ - const FtpCommand *command_descriptor; - - uint16_t dyn_port; /* dynamic port, if applicable */ - bool done; /* transaction complete? */ - bool active; /* active or passive mode */ - - uint8_t direction; - - /* Handle multiple responses */ - TAILQ_HEAD(, FTPString_) response_list; - - TAILQ_ENTRY(FTPTransaction_) next; -} FTPTransaction; - -/** FTP State for app layer parser */ -typedef struct FtpState_ { - bool active; - - FTPTransaction *curr_tx; - TAILQ_HEAD(, FTPTransaction_) tx_list; /**< transaction list */ - uint64_t tx_cnt; - - bool current_line_truncated_ts; - bool current_line_truncated_tc; - - FtpRequestCommand command; - FtpRequestCommandArgOfs arg_offset; - uint32_t port_line_len; - uint32_t port_line_size; - uint8_t *port_line; - - uint16_t dyn_port; - - AppLayerStateData state_data; -} FtpState; - -enum { - FTPDATA_STATE_IN_PROGRESS, - FTPDATA_STATE_FINISHED, -}; - -/** FTP Data State for app layer parser */ -typedef struct FtpDataState_ { - uint8_t *input; - uint8_t *file_name; - FileContainer *files; - int32_t input_len; - int16_t file_len; - FtpRequestCommand command; - uint8_t state; - uint8_t direction; - AppLayerTxData tx_data; - AppLayerStateData state_data; -} FtpDataState; - -void RegisterFTPParsers(void); -void FTPParserRegisterTests(void); -void FTPAtExitPrintStats(void); -void FTPParserCleanup(void); -uint64_t FTPMemuseGlobalCounter(void); -uint64_t FTPMemcapGlobalCounter(void); - -uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len); -bool EveFTPDataAddMetadata(void *vtx, JsonBuilder *jb); - -#endif /* __APP_LAYER_FTP_H__ */ - diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c deleted file mode 100644 index 11b5941d7e21..000000000000 --- a/src/app-layer-htp-body.c +++ /dev/null @@ -1,215 +0,0 @@ -/* Copyright (C) 2007-2011 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Gurvinder Singh - * \author Pablo Rincon - * \author Brian Rectanus - * - * This file provides a HTTP protocol support for the engine using HTP library. - */ - -#include "suricata-common.h" -#include "app-layer-htp.h" -#include "app-layer-htp-mem.h" -#include "app-layer-htp-body.h" -#include "util-streaming-buffer.h" -#include "util-print.h" - -extern StreamingBufferConfig htp_sbcfg; - -/** - * \brief Append a chunk of body to the HtpBody struct - * - * \param body pointer to the HtpBody holding the list - * \param data pointer to the data of the chunk - * \param len length of the chunk pointed by data - * - * \retval 0 ok - * \retval -1 error - */ -int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, - const uint8_t *data, uint32_t len) -{ - SCEnter(); - - HtpBodyChunk *bd = NULL; - - if (len == 0 || data == NULL) { - SCReturnInt(0); - } - - if (body->sb == NULL) { - body->sb = StreamingBufferInit(&htp_sbcfg); - if (body->sb == NULL) - SCReturnInt(-1); - } - - /* New chunk */ - bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); - if (bd == NULL) { - SCReturnInt(-1); - } - - if (StreamingBufferAppend(body->sb, &htp_sbcfg, &bd->sbseg, data, len) != 0) { - HTPFree(bd, sizeof(HtpBodyChunk)); - SCReturnInt(-1); - } - - if (body->first == NULL) { - body->first = body->last = bd; - } else { - body->last->next = bd; - body->last = bd; - } - body->content_len_so_far += len; - - SCLogDebug("body %p", body); - - SCReturnInt(0); -} - -/** - * \brief Print the information and chunks of a Body - * \param body pointer to the HtpBody holding the list - * \retval none - */ -void HtpBodyPrint(HtpBody *body) -{ - if (SCLogDebugEnabled()||1) { - SCEnter(); - - if (body->first == NULL) - return; - - HtpBodyChunk *cur = NULL; - SCLogDebug("--- Start body chunks at %p ---", body); - printf("--- Start body chunks at %p ---\n", body); - for (cur = body->first; cur != NULL; cur = cur->next) { - const uint8_t *data = NULL; - uint32_t data_len = 0; - StreamingBufferSegmentGetData(body->sb, &cur->sbseg, &data, &data_len); - SCLogDebug("Body %p; data %p, len %"PRIu32, body, data, data_len); - printf("Body %p; data %p, len %"PRIu32"\n", body, data, data_len); - PrintRawDataFp(stdout, data, data_len); - } - SCLogDebug("--- End body chunks at %p ---", body); - } -} - -/** - * \brief Free the information held in the request body - * \param body pointer to the HtpBody holding the list - * \retval none - */ -void HtpBodyFree(const HTPCfgDir *hcfg, HtpBody *body) -{ - SCEnter(); - - SCLogDebug("removing chunks of body %p", body); - - HtpBodyChunk *cur = NULL; - HtpBodyChunk *prev = NULL; - - prev = body->first; - while (prev != NULL) { - cur = prev->next; - HTPFree(prev, sizeof(HtpBodyChunk)); - prev = cur; - } - body->first = body->last = NULL; - - StreamingBufferFree(body->sb, &htp_sbcfg); -} - -/** - * \brief Free request body chunks that are already fully parsed. - * - * \param state htp_state, with reference to our config - * \param body the body to prune - * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response) - * - * \retval none - */ -void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) -{ - SCEnter(); - - if (body == NULL || body->first == NULL) { - SCReturn; - } - - if (body->body_parsed == 0) { - SCReturn; - } - - const HTPCfgDir *cfg = - (direction == STREAM_TOCLIENT) ? &state->cfg->response : &state->cfg->request; - uint32_t min_size = cfg->inspect_min_size; - uint32_t window = cfg->inspect_window; - uint64_t max_window = ((min_size > window) ? min_size : window); - uint64_t in_flight = body->content_len_so_far - body->body_inspected; - - /* Special case. If body_inspected is not being updated, we make sure that - * we prune the body. We allow for some extra size/room as we may be called - * multiple times on uninspected body chunk additions if a large block of - * data was ack'd at once. Want to avoid pruning before inspection. */ - if (in_flight > (max_window * 3)) { - body->body_inspected = body->content_len_so_far - max_window; - } else if (body->body_inspected < max_window) { - SCReturn; - } - - uint64_t left_edge = body->body_inspected; - if (left_edge <= min_size || left_edge <= window) - left_edge = 0; - if (left_edge) - left_edge -= window; - - if (left_edge) { - SCLogDebug("sliding body to offset %"PRIu64, left_edge); - StreamingBufferSlideToOffset(body->sb, &htp_sbcfg, left_edge); - } - - SCLogDebug("pruning chunks of body %p", body); - - HtpBodyChunk *cur = body->first; - while (cur != NULL) { - HtpBodyChunk *next = cur->next; - SCLogDebug("cur %p", cur); - - if (!StreamingBufferSegmentIsBeforeWindow(body->sb, &cur->sbseg)) { - SCLogDebug("not removed"); - break; - } - - body->first = next; - if (body->last == cur) { - body->last = next; - } - - HTPFree(cur, sizeof(HtpBodyChunk)); - - cur = next; - SCLogDebug("removed"); - } - - SCReturn; -} diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c deleted file mode 100644 index f96b37016061..000000000000 --- a/src/app-layer-htp-file.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * This file provides HTTP protocol file handling support for the engine - * using the HTP library. - */ - -#include "suricata-common.h" -#include "app-layer-htp-file.h" -#include "app-layer-htp-range.h" -#include "app-layer-events.h" -#include "util-validate.h" - -extern StreamingBufferConfig htp_sbcfg; - -/** - * \brief Open the file with "filename" and pass the first chunk - * of data if any. - * - * \param s http state - * \param filename name of the file - * \param filename_len length of the name - * \param data data chunk (if any) - * \param data_len length of the data portion - * \param direction flow direction - * - * \retval 0 ok - * \retval -1 error - * \retval -2 not handling files on this flow - */ -int HTPFileOpen(HtpState *s, HtpTxUserData *tx, const uint8_t *filename, uint16_t filename_len, - const uint8_t *data, uint32_t data_len, uint64_t txid, uint8_t direction) -{ - int retval = 0; - uint16_t flags = 0; - FileContainer *files = NULL; - - SCLogDebug("data %p data_len %"PRIu32, data, data_len); - - if (direction & STREAM_TOCLIENT) { - files = &tx->files_tc; - flags = FileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOCLIENT); - - // we shall not open a new file if there is a current one - DEBUG_VALIDATE_BUG_ON(tx->file_range != NULL); - } else { - files = &tx->files_ts; - flags = FileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOSERVER); - } - - if (FileOpenFileWithId(files, &htp_sbcfg, s->file_track_id++, filename, filename_len, data, - data_len, flags) != 0) { - retval = -1; - } else { - const HTPCfgDir *cfg; - if (direction & STREAM_TOCLIENT) { - cfg = &s->cfg->response; - } else { - cfg = &s->cfg->request; - } - FileSetInspectSizes(files->tail, cfg->inspect_window, cfg->inspect_min_size); - } - - tx->tx_data.files_opened++; - - SCReturnInt(retval); -} - -/** - * Performs parsing of the content-range value - * - * @param[in] rawvalue - * @param[out] range - * - * @return HTP_OK on success, HTP_ERROR on failure. - */ -int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range) -{ - uint32_t len = bstr_len(rawvalue); - return rs_http_parse_content_range(range, bstr_ptr(rawvalue), len); -} - -/** - * Performs parsing + checking of the content-range value - * - * @param[in] rawvalue - * @param[out] range - * - * @return HTP_OK on success, HTP_ERROR, -2, -3 on failure. - */ -static int HTPParseAndCheckContentRange( - bstr *rawvalue, HTTPContentRange *range, HtpState *s, HtpTxUserData *htud) -{ - int r = HTPParseContentRange(rawvalue, range); - if (r != 0) { - AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, HTTP_DECODER_EVENT_RANGE_INVALID); - s->events++; - SCLogDebug("parsing range failed, going back to normal file"); - return r; - } - /* crparsed.end <= 0 means a range with only size - * this is the answer to an unsatisfied range with the whole file - * crparsed.size <= 0 means an unknown size, so we do not know - * when to close it... - */ - if (range->end <= 0 || range->size <= 0) { - SCLogDebug("range without all information"); - return -2; - } else if (range->end == range->size - 1 && range->start == 0) { - SCLogDebug("range without all information"); - return -3; - } else if (range->start > range->end || range->end > range->size - 1) { - AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, HTTP_DECODER_EVENT_RANGE_INVALID); - s->events++; - SCLogDebug("invalid range"); - return -4; - } - return r; -} - -/** - * \brief Sets range for a file - * - * \param s http state - * \param rawvalue raw header value - * - * \retval 0 ok - * \retval -1 error - */ -int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename, - uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint64_t txid, - bstr *rawvalue, HtpTxUserData *htud) -{ - SCEnter(); - uint16_t flags; - - DEBUG_VALIDATE_BUG_ON(s == NULL); - - // This function is only called STREAM_TOCLIENT from HtpResponseBodyHandle - HTTPContentRange crparsed; - if (HTPParseAndCheckContentRange(rawvalue, &crparsed, s, htud) != 0) { - // range is invalid, fall back to classic open - return HTPFileOpen(s, txud, filename, filename_len, data, data_len, txid, STREAM_TOCLIENT); - } - flags = FileFlowToFlags(s->f, STREAM_TOCLIENT); - FileContainer *files = &txud->files_tc; - - // we open a file for this specific range - if (FileOpenFileWithId(files, &htp_sbcfg, s->file_track_id++, filename, filename_len, data, - data_len, flags) != 0) { - SCReturnInt(-1); - } else { - const HTPCfgDir *cfg = &s->cfg->response; - FileSetInspectSizes(files->tail, cfg->inspect_window, cfg->inspect_min_size); - } - txud->tx_data.files_opened++; - - if (FileSetRange(files, crparsed.start, crparsed.end) < 0) { - SCLogDebug("set range failed"); - } - - // Then, we will try to handle reassembly of different ranges of the same file - htp_tx_t *tx = htp_list_get(s->conn->transactions, txid); - if (!tx) { - SCReturnInt(-1); - } - uint8_t *keyurl; - uint32_t keylen; - if (tx->request_hostname != NULL) { - keylen = bstr_len(tx->request_hostname) + filename_len; - keyurl = SCMalloc(keylen); - if (keyurl == NULL) { - SCReturnInt(-1); - } - memcpy(keyurl, bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname)); - memcpy(keyurl + bstr_len(tx->request_hostname), filename, filename_len); - } else { - // do not reassemble file without host info - SCReturnInt(0); - } - DEBUG_VALIDATE_BUG_ON(htud->file_range); - htud->file_range = HttpRangeContainerOpenFile(keyurl, keylen, s->f, &crparsed, &htp_sbcfg, - filename, filename_len, flags, data, data_len); - SCFree(keyurl); - if (htud->file_range == NULL) { - SCReturnInt(-1); - } - SCReturnInt(0); -} - -/** - * \brief Store a chunk of data in the flow - * - * \param s HtpState - * \param tx HtpTxUserData - * \param data data chunk (if any) - * \param data_len length of the data portion - * \param direction flow direction - * - * \retval 0 ok - * \retval -1 error - * \retval -2 file doesn't need storing - */ -int HTPFileStoreChunk( - HtpState *s, HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t direction) -{ - SCEnter(); - - int retval = 0; - int result = 0; - FileContainer *files = NULL; - - if (direction & STREAM_TOCLIENT) { - files = &tx->files_tc; - } else { - files = &tx->files_ts; - } - SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len); - - if (files == NULL) { - SCLogDebug("no files in state"); - retval = -1; - goto end; - } - - if (tx->file_range != NULL) { - if (HttpRangeAppendData(&htp_sbcfg, tx->file_range, data, data_len) < 0) { - SCLogDebug("Failed to append data"); - } - } - - result = FileAppendData(files, &htp_sbcfg, data, data_len); - if (result == -1) { - SCLogDebug("appending data failed"); - retval = -1; - } else if (result == -2) { - retval = -2; - } - SCLogDebug("result %u", result); - -end: - SCReturnInt(retval); -} - -/** \brief close range, add reassembled file if possible - * \retval true if reassembled file was added - * \retval false if no reassembled file was added - */ -bool HTPFileCloseHandleRange(const StreamingBufferConfig *sbcfg, FileContainer *files, - const uint16_t flags, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t data_len) -{ - bool added = false; - if (HttpRangeAppendData(sbcfg, c, data, data_len) < 0) { - SCLogDebug("Failed to append data"); - } - if (c->container) { - // we only call HttpRangeClose if we may some new data - // ie we do not call it if we skipped all this range request - THashDataLock(c->container->hdata); - if (c->container->error) { - SCLogDebug("range in ERROR state"); - } - File *ranged = HttpRangeClose(sbcfg, c, flags); - if (ranged && files) { - /* HtpState owns the constructed file now */ - FileContainerAdd(files, ranged); - added = true; - } - DEBUG_VALIDATE_BUG_ON(ranged && !files); - THashDataUnlock(c->container->hdata); - } - return added; -} - -/** - * \brief Close the file in the flow - * - * \param tx HtpTxUserData - * \param data data chunk if any - * \param data_len length of the data portion - * \param flags flags to indicate events - * \param direction flow direction - * - * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating - * that the file isn't complete but we're stopping storing it. - * - * \retval 0 ok - * \retval -1 error - * \retval -2 not storing files on this flow/tx - */ -int HTPFileClose(HtpState *s, HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, - uint8_t flags, uint8_t direction) -{ - SCEnter(); - - SCLogDebug("flags %04x FILE_TRUNCATED %s", flags, (flags & FILE_TRUNCATED) ? "true" : "false"); - - int retval = 0; - int result = 0; - FileContainer *files = NULL; - - if (direction & STREAM_TOCLIENT) { - files = &tx->files_tc; - } else { - files = &tx->files_ts; - } - - SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len); - - if (files == NULL) { - retval = -1; - goto end; - } - - result = FileCloseFile(files, &htp_sbcfg, data, data_len, flags); - if (result == -1) { - retval = -1; - } else if (result == -2) { - retval = -2; - } - SCLogDebug("result %u", result); - - if (tx->file_range != NULL) { - bool added = - HTPFileCloseHandleRange(&htp_sbcfg, files, flags, tx->file_range, data, data_len); - if (added) { - tx->tx_data.files_opened++; - } - HttpRangeFreeBlock(tx->file_range); - tx->file_range = NULL; - } - -end: - SCReturnInt(retval); -} - -#ifdef UNITTESTS -#include "stream-tcp.h" -#include "app-layer-parser.h" -#include "util-unittest-helper.h" - -static int HTPFileParserTest01(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 215\r\n" - "\r\n" - "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n"; - - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "filecontent\r\n" - "-----------------------------277531038314945--"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - HtpState *http_state = NULL; - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -static int HTPFileParserTest02(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 337\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"email\"\r\n" - "\r\n" - "someaddress@somedomain.lan\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - - uint8_t httpbuf4[] = "filecontent\r\n" - "-----------------------------277531038314945--"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -static int HTPFileParserTest03(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 337\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"email\"\r\n" - "\r\n" - "someaddress@somedomain.lan\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - - uint8_t httpbuf4[] = "file"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - - uint8_t httpbuf5[] = "content\r\n"; - uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ - - uint8_t httpbuf6[] = "-----------------------------277531038314945--"; - uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->files_ts.head); - FAIL_IF_NULL(tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); - FAIL_IF(FileDataSize(tx_ud->files_ts.head) != 11); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -static int HTPFileParserTest04(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 373\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"email\"\r\n" - "\r\n" - "someaddress@somedomain.lan\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - - uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - - uint8_t httpbuf5[] = "content\r\n"; - uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ - - uint8_t httpbuf6[] = "-----------------------------277531038314945--"; - uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->files_ts.head); - FAIL_IF_NULL(tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -static int HTPFileParserTest05(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 544\r\n" - "\r\n" - "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n" - "filecontent\r\n" - "-----------------------------277531038314945\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n" - "FILECONTENT\r\n" - "-----------------------------277531038314945--"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->files_ts.head); - FAIL_IF_NULL(tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); - - FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail); - - FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) != - 1); - - FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != - 1); - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test first multipart part contains file but doesn't end in first chunk */ -static int HTPFileParserTest06(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 544\r\n" - "\r\n" - "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n" - "filecontent\r\n" - "-----------------------------27753103831494"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n" - "Content-Type: image/jpeg\r\n" - "\r\n" - "FILECONTENT\r\n" - "-----------------------------277531038314945--"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->files_ts.head); - FAIL_IF_NULL(tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); - - FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail); - - FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) != - 1); - - FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != - 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test POST, but not multipart */ -static int HTPFileParserTest07(void) -{ - uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Length: 11\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "FILECONTENT"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->files_ts.head); - FAIL_IF_NULL(tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); - - FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != - 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -static int HTPFileParserTest08(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 215\r\n" - "\r\n" - "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Content-Type: image/jpeg\r\n"; - - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "filecontent\r\n\r\n" - "-----------------------------277531038314945--"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - HtpState *http_state = NULL; - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); - FAIL_IF_NULL(tx); - - AppLayerDecoderEvents *decoder_events = - AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx); - FAIL_IF_NULL(decoder_events); - - FAIL_IF(decoder_events->cnt != 2); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test invalid header: Somereallylongheaderstr: has no value */ -static int HTPFileParserTest09(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 337\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"email\"\r\n" - "\r\n" - "someaddress@somedomain.lan\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Somereallylongheaderstr:\r\n" - "\r\n"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - - uint8_t httpbuf4[] = "filecontent\r\n" - "-----------------------------277531038314945--"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); - FAIL_IF_NULL(tx); - - AppLayerDecoderEvents *decoder_events = - AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx); - FAIL_IF_NULL(decoder_events); - - FAIL_IF(decoder_events->cnt != 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test empty entries */ -static int HTPFileParserTest10(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" - "Content-Length: 337\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" - "\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" - "Somereallylongheaderstr: with a good value\r\n" - "\r\n"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - - uint8_t httpbuf4[] = "filecontent\r\n" - "-----------------------------277531038314945--"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); - FAIL_IF_NULL(tx); - AppLayerDecoderEvents *decoder_events = - AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx); - FAIL_IF_NOT_NULL(decoder_events); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test filedata cut in two pieces */ -static int HTPFileParserTest11(void) -{ - uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" - "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Length: 1102\r\n" - "\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - uint8_t httpbuf3[] = "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n" - "\r\n" - "http://somserver.com/progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n" - "\r\n" - "10\r\n" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"js_enabled\"\r\n" - "\r\n" - "1" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"signature\"\r\n" - "\r\n" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"upload_files\"\r\n" - "\r\n" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"terms\"\r\n" - "\r\n" - "1" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"file[]\"\r\n" - "\r\n" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"description[]\"\r\n" - "\r\n" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" - "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n" - "Content-Type: application/msword\r\n" - "\r\n" - "FILE"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - - uint8_t httpbuf4[] = "CONTENT\r\n" - "------WebKitFormBoundaryBRDbP74mBhBxsIdo--"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3); - FAIL_IF_NOT(r == 0); - - SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); - FAIL_IF_NOT(r == 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - - void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); - FAIL_IF_NULL(txtmp); - - AppLayerDecoderEvents *decoder_events = - AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); - FAIL_IF_NOT_NULL(decoder_events); - - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NULL(tx->request_method); - - FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->files_ts.head); - FAIL_IF_NULL(tx_ud->files_ts.tail); - FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); - - FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != - 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -void AppLayerHtpFileRegisterTests (void); -#include "tests/app-layer-htp-file.c" -#endif /* UNITTESTS */ - -void HTPFileParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01); - UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02); - UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03); - UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04); - UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05); - UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06); - UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07); - UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08); - UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09); - UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10); - UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11); - AppLayerHtpFileRegisterTests(); -#endif /* UNITTESTS */ -} diff --git a/src/app-layer-htp-file.h b/src/app-layer-htp-file.h deleted file mode 100644 index 4b682bc03781..000000000000 --- a/src/app-layer-htp-file.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2007-2011 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#ifndef __APP_LAYER_HTP_FILE_H__ -#define __APP_LAYER_HTP_FILE_H__ - -#include "app-layer-htp.h" - -int HTPFileOpen(HtpState *, HtpTxUserData *, const uint8_t *, uint16_t, const uint8_t *, uint32_t, - uint64_t, uint8_t); -int HTPFileOpenWithRange(HtpState *, HtpTxUserData *, const uint8_t *, uint16_t, const uint8_t *, - uint32_t, uint64_t, bstr *rawvalue, HtpTxUserData *htud); -bool HTPFileCloseHandleRange(const StreamingBufferConfig *sbcfg, FileContainer *, const uint16_t, - HttpRangeContainerBlock *, const uint8_t *, uint32_t); -int HTPFileStoreChunk(HtpState *, HtpTxUserData *, const uint8_t *, uint32_t, uint8_t); - -int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range); -int HTPFileClose(HtpState *, HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, - uint8_t flags, uint8_t direction); - -void HTPFileParserRegisterTests(void); - -#endif /* __APP_LAYER_HTP_FILE_H__ */ diff --git a/src/app-layer-htp-libhtp.c b/src/app-layer-htp-libhtp.c deleted file mode 100644 index dcc4a92b8bb0..000000000000 --- a/src/app-layer-htp-libhtp.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * We are using this file to hold APIs copied from libhtp 0.5.x. - */ - -/*************************************************************************** - * Copyright (c) 2009-2010 Open Information Security Foundation - * Copyright (c) 2010-2013 Qualys, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Qualys, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ***************************************************************************/ - -/** - * \file - * - * \author Anoop Saldanha - * - * APIs from libhtp 0.5.x. - */ - -#include "suricata-common.h" -#include -#include "app-layer-htp-libhtp.h" - -/** - * \brief Generates the normalized uri. - * - * Libhtp doesn't recreate the whole normalized uri and save it. - * That duty has now been passed to us. A lot of this code has been - * copied from libhtp. - * - * Keep an eye out on the tx->parsed_uri struct and how the parameters - * in it are generated, just in case some modifications are made to - * them in the future. - * - * \param uri_include_all boolean to indicate if scheme, username/password, - hostname and port should be part of the buffer - */ -bstr *SCHTPGenerateNormalizedUri(htp_tx_t *tx, htp_uri_t *uri, bool uri_include_all) -{ - if (uri == NULL) - return NULL; - - // On the first pass determine the length of the final string - size_t len = 0; - - if (uri_include_all) { - if (uri->scheme != NULL) { - len += bstr_len(uri->scheme); - len += 3; // "://" - } - - if ((uri->username != NULL) || (uri->password != NULL)) { - if (uri->username != NULL) { - len += bstr_len(uri->username); - } - - len += 1; // ":" - - if (uri->password != NULL) { - len += bstr_len(uri->password); - } - - len += 1; // "@" - } - - if (uri->hostname != NULL) { - len += bstr_len(uri->hostname); - } - - if (uri->port != NULL) { - len += 1; // ":" - len += bstr_len(uri->port); - } - } - - if (uri->path != NULL) { - len += bstr_len(uri->path); - } - - if (uri->query != NULL) { - len += 1; // "?" - len += bstr_len(uri->query); - } - - if (uri->fragment != NULL) { - len += 1; // "#" - len += bstr_len(uri->fragment); - } - - // On the second pass construct the string - /* FIXME in memcap */ - bstr *r = bstr_alloc(len); - if (r == NULL) { - return NULL; - } - - if (uri_include_all) { - if (uri->scheme != NULL) { - bstr_add_noex(r, uri->scheme); - bstr_add_c_noex(r, "://"); - } - - if ((uri->username != NULL) || (uri->password != NULL)) { - if (uri->username != NULL) { - bstr_add_noex(r, uri->username); - } - - bstr_add_c_noex(r, ":"); - - if (uri->password != NULL) { - bstr_add_noex(r, uri->password); - } - - bstr_add_c_noex(r, "@"); - } - - if (uri->hostname != NULL) { - bstr_add_noex(r, uri->hostname); - } - - if (uri->port != NULL) { - bstr_add_c_noex(r, ":"); - bstr_add_noex(r, uri->port); - } - } - - if (uri->path != NULL) { - bstr_add_noex(r, uri->path); - } - - if (uri->query != NULL) { - bstr *query = bstr_dup(uri->query); - if (query) { - uint64_t flags = 0; - htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags); - bstr_add_c_noex(r, "?"); - bstr_add_noex(r, query); - bstr_free(query); - } - } - - if (uri->fragment != NULL) { - bstr_add_c_noex(r, "#"); - bstr_add_noex(r, uri->fragment); - } - - return r; -} diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c deleted file mode 100644 index bd9b79f67623..000000000000 --- a/src/app-layer-htp-mem.c +++ /dev/null @@ -1,198 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - -/** - * \file - * - * \author Eric Leblond - * - * This file provides a memory handling for the HTTP protocol support. - */ - -#include "suricata-common.h" -#include "app-layer-htp-mem.h" - -#include "conf.h" -#include "util-misc.h" -#include "util-debug.h" - -SC_ATOMIC_DECLARE(uint64_t, htp_config_memcap); -SC_ATOMIC_DECLARE(uint64_t, htp_memuse); -SC_ATOMIC_DECLARE(uint64_t, htp_memcap); - -void HTPParseMemcap(void) -{ - const char *conf_val; - - SC_ATOMIC_INIT(htp_config_memcap); - - /** set config values for memcap, prealloc and hash_size */ - uint64_t memcap; - if ((ConfGet("app-layer.protocols.http.memcap", &conf_val)) == 1) - { - if (ParseSizeStringU64(conf_val, &memcap) < 0) { - SCLogError("Error parsing http.memcap " - "from conf file - %s. Killing engine", - conf_val); - exit(EXIT_FAILURE); - } else { - SC_ATOMIC_SET(htp_config_memcap, memcap); - } - SCLogInfo("HTTP memcap: %"PRIu64, SC_ATOMIC_GET(htp_config_memcap)); - } else { - /* default to unlimited */ - SC_ATOMIC_SET(htp_config_memcap, 0); - } - - SC_ATOMIC_INIT(htp_memuse); - SC_ATOMIC_INIT(htp_memcap); -} - -static void HTPIncrMemuse(uint64_t size) -{ - (void) SC_ATOMIC_ADD(htp_memuse, size); - return; -} - -static void HTPDecrMemuse(uint64_t size) -{ - (void) SC_ATOMIC_SUB(htp_memuse, size); - return; -} - -uint64_t HTPMemuseGlobalCounter(void) -{ - uint64_t tmpval = SC_ATOMIC_GET(htp_memuse); - return tmpval; -} - -uint64_t HTPMemcapGlobalCounter(void) -{ - uint64_t tmpval = SC_ATOMIC_GET(htp_memcap); - return tmpval; -} - -/** - * \brief Check if alloc'ing "size" would mean we're over memcap - * - * \retval 1 if in bounds - * \retval 0 if not in bounds - */ -static int HTPCheckMemcap(uint64_t size) -{ - uint64_t memcapcopy = SC_ATOMIC_GET(htp_config_memcap); - if (memcapcopy == 0 || size + SC_ATOMIC_GET(htp_memuse) <= memcapcopy) - return 1; - (void) SC_ATOMIC_ADD(htp_memcap, 1); - return 0; -} - -/** - * \brief Update memcap value - * - * \param size new memcap value - */ -int HTPSetMemcap(uint64_t size) -{ - if (size == 0 || (uint64_t)SC_ATOMIC_GET(htp_memuse) < size) { - SC_ATOMIC_SET(htp_config_memcap, size); - return 1; - } - return 0; -} - -/** - * \brief Update memcap value - * - * \retval memcap value - */ -uint64_t HTPGetMemcap(void) -{ - uint64_t memcapcopy = SC_ATOMIC_GET(htp_config_memcap); - return memcapcopy; -} - -void *HTPMalloc(size_t size) -{ - void *ptr = NULL; - - if (HTPCheckMemcap((uint32_t)size) == 0) - return NULL; - - ptr = SCMalloc(size); - - if (unlikely(ptr == NULL)) - return NULL; - - HTPIncrMemuse((uint64_t)size); - - return ptr; -} - -void *HTPCalloc(size_t n, size_t size) -{ - void *ptr = NULL; - - if (HTPCheckMemcap((uint32_t)(n * size)) == 0) - return NULL; - - ptr = SCCalloc(n, size); - - if (unlikely(ptr == NULL)) - return NULL; - - HTPIncrMemuse((uint64_t)(n * size)); - - return ptr; -} - -void *HTPRealloc(void *ptr, size_t orig_size, size_t size) -{ - if (size > orig_size) { - if (HTPCheckMemcap((uint32_t)(size - orig_size)) == 0) - return NULL; - } - - void *rptr = SCRealloc(ptr, size); - if (rptr == NULL) - return NULL; - - if (size > orig_size) { - HTPIncrMemuse((uint64_t)(size - orig_size)); - } else { - HTPDecrMemuse((uint64_t)(orig_size - size)); - } - - return rptr; -} - -void HTPFree(void *ptr, size_t size) -{ - SCFree(ptr); - - HTPDecrMemuse((uint64_t)size); -} - -/** - * @} - */ diff --git a/src/app-layer-htp-range.c b/src/app-layer-htp-range.c deleted file mode 100644 index 3cdde35ba288..000000000000 --- a/src/app-layer-htp-range.c +++ /dev/null @@ -1,634 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Philippe Antoine - */ - -#include "suricata-common.h" -#include "app-layer-htp-range.h" -#include "util-misc.h" //ParseSizeStringU64 -#include "util-thash.h" //HashTable -#include "util-memcmp.h" //SCBufferCmp -#include "util-hash-string.h" //StringHashDjb2 -#include "util-validate.h" //DEBUG_VALIDATE_BUG_ON -#include "util-byte.h" //StringParseUint32 - -typedef struct ContainerTHashTable { - THashTableContext *ht; - uint32_t timeout; -} ContainerTHashTable; - -// globals -ContainerTHashTable ContainerUrlRangeList; - -static void HttpRangeBlockDerefContainer(HttpRangeContainerBlock *b); - -#define CONTAINER_URLRANGE_HASH_SIZE 256 - -int HttpRangeContainerBufferCompare(HttpRangeContainerBuffer *a, HttpRangeContainerBuffer *b) -{ - // lexical order : start, buflen, offset - if (a->start > b->start) - return 1; - if (a->start < b->start) - return -1; - if (a->buflen > b->buflen) - return 1; - if (a->buflen < b->buflen) - return -1; - if (a->offset > b->offset) - return 1; - if (a->offset < b->offset) - return -1; - return 0; -} - -RB_GENERATE(HTTP_RANGES, HttpRangeContainerBuffer, rb, HttpRangeContainerBufferCompare); - -static int ContainerUrlRangeSet(void *dst, void *src) -{ - HttpRangeContainerFile *src_s = src; - HttpRangeContainerFile *dst_s = dst; - dst_s->len = src_s->len; - dst_s->key = SCMalloc(dst_s->len); - if (dst_s->key == NULL) - return -1; - memcpy(dst_s->key, src_s->key, dst_s->len); - dst_s->files = FileContainerAlloc(); - if (dst_s->files == NULL) { - SCFree(dst_s->key); - return -1; - } - RB_INIT(&dst_s->fragment_tree); - dst_s->flags = 0; - dst_s->lastsize = 0; - dst_s->totalsize = 0; - dst_s->hdata = NULL; - dst_s->error = false; - return 0; -} - -static bool ContainerUrlRangeCompare(void *a, void *b) -{ - const HttpRangeContainerFile *as = a; - const HttpRangeContainerFile *bs = b; - - /* ranges in the error state should not be found so they can - * be evicted */ - if (as->error || bs->error) { - return false; - } - - if (SCBufferCmp(as->key, as->len, bs->key, bs->len) == 0) { - return true; - } - return false; -} - -static uint32_t ContainerUrlRangeHash(void *s) -{ - HttpRangeContainerFile *cur = s; - uint32_t h = StringHashDjb2(cur->key, cur->len); - return h; -} - -// base data stays in hash -static void ContainerUrlRangeFree(void *s) -{ - HttpRangeContainerBuffer *range = NULL, *tmp = NULL; - - HttpRangeContainerFile *cu = s; - SCFree(cu->key); - cu->key = NULL; - FileContainerFree(cu->files, cu->sbcfg); - cu->files = NULL; - RB_FOREACH_SAFE (range, HTTP_RANGES, &cu->fragment_tree, tmp) { - RB_REMOVE(HTTP_RANGES, &cu->fragment_tree, range); - SCFree(range->buffer); - (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, range->buflen); - SCFree(range); - } -} - -static inline bool ContainerValueRangeTimeout(HttpRangeContainerFile *cu, const SCTime_t ts) -{ - // we only timeout if we have no flow referencing us - if ((uint32_t)SCTIME_SECS(ts) > cu->expire || cu->error) { - if (SC_ATOMIC_GET(cu->hdata->use_cnt) == 0) { - DEBUG_VALIDATE_BUG_ON(cu->files == NULL); - return true; - } - } - return false; -} - -static void ContainerUrlRangeUpdate(HttpRangeContainerFile *cu, uint32_t expire) -{ - cu->expire = expire; -} - -#define HTTP_RANGE_DEFAULT_TIMEOUT 60 -#define HTTP_RANGE_DEFAULT_MEMCAP 100 * 1024 * 1024 - -void HttpRangeContainersInit(void) -{ - SCLogDebug("containers start"); - const char *str = NULL; - uint64_t memcap = HTTP_RANGE_DEFAULT_MEMCAP; - uint32_t timeout = HTTP_RANGE_DEFAULT_TIMEOUT; - if (ConfGet("app-layer.protocols.http.byterange.memcap", &str) == 1) { - if (ParseSizeStringU64(str, &memcap) < 0) { - SCLogWarning("memcap value cannot be deduced: %s," - " resetting to default", - str); - memcap = 0; - } - } - if (ConfGet("app-layer.protocols.http.byterange.timeout", &str) == 1) { - size_t slen = strlen(str); - if (slen > UINT16_MAX || StringParseUint32(&timeout, 10, (uint16_t)slen, str) <= 0) { - SCLogWarning("timeout value cannot be deduced: %s," - " resetting to default", - str); - timeout = 0; - } - } - - ContainerUrlRangeList.ht = - THashInit("app-layer.protocols.http.byterange", sizeof(HttpRangeContainerFile), - ContainerUrlRangeSet, ContainerUrlRangeFree, ContainerUrlRangeHash, - ContainerUrlRangeCompare, false, memcap, CONTAINER_URLRANGE_HASH_SIZE); - ContainerUrlRangeList.timeout = timeout; - - SCLogDebug("containers started"); -} - -void HttpRangeContainersDestroy(void) -{ - THashShutdown(ContainerUrlRangeList.ht); -} - -uint32_t HttpRangeContainersTimeoutHash(const SCTime_t ts) -{ - SCLogDebug("timeout: starting"); - uint32_t cnt = 0; - - for (uint32_t i = 0; i < ContainerUrlRangeList.ht->config.hash_size; i++) { - THashHashRow *hb = &ContainerUrlRangeList.ht->array[i]; - - if (HRLOCK_TRYLOCK(hb) != 0) - continue; - /* hash bucket is now locked */ - THashData *h = hb->head; - while (h) { - DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(h->use_cnt) > (uint32_t)INT_MAX); - THashData *n = h->next; - THashDataLock(h); - if (ContainerValueRangeTimeout(h->data, ts)) { - /* remove from the hash */ - if (h->prev != NULL) - h->prev->next = h->next; - if (h->next != NULL) - h->next->prev = h->prev; - if (hb->head == h) - hb->head = h->next; - if (hb->tail == h) - hb->tail = h->prev; - h->next = NULL; - h->prev = NULL; - // we should log the timed out file somehow... - // but it does not belong to any flow... - SCLogDebug("timeout: removing range %p", h); - ContainerUrlRangeFree(h->data); // TODO do we need a "RECYCLE" func? - DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(h->use_cnt) > (uint32_t)INT_MAX); - THashDataUnlock(h); - THashDataMoveToSpare(ContainerUrlRangeList.ht, h); - } else { - THashDataUnlock(h); - } - h = n; - } - HRLOCK_UNLOCK(hb); - } - - SCLogDebug("timeout: ending"); - return cnt; -} - -/** - * \returns locked data - */ -static void *HttpRangeContainerUrlGet(const uint8_t *key, uint32_t keylen, const Flow *f) -{ - const SCTime_t ts = f->lastts; - HttpRangeContainerFile lookup; - memset(&lookup, 0, sizeof(lookup)); - // cast so as not to have const in the structure - lookup.key = (uint8_t *)key; - lookup.len = keylen; - struct THashDataGetResult res = THashGetFromHash(ContainerUrlRangeList.ht, &lookup); - if (res.data) { - // nothing more to do if (res.is_new) - ContainerUrlRangeUpdate(res.data->data, SCTIME_SECS(ts) + ContainerUrlRangeList.timeout); - HttpRangeContainerFile *c = res.data->data; - c->hdata = res.data; - SCLogDebug("c %p", c); - return res.data->data; - } - return NULL; -} - -static HttpRangeContainerBlock *HttpRangeOpenFileAux(HttpRangeContainerFile *c, uint64_t start, - uint64_t end, uint64_t total, const StreamingBufferConfig *sbcfg, const uint8_t *name, - uint16_t name_len, uint16_t flags) -{ - if (c->files != NULL && c->files->tail == NULL) { - /* this is the first request, we open a single file in the file container - * this could be part of ContainerUrlRangeSet if we could have - * all the arguments there - */ - if (FileOpenFileWithId(c->files, sbcfg, 0, name, name_len, NULL, 0, flags) != 0) { - SCLogDebug("open file for range failed"); - return NULL; - } - } - HttpRangeContainerBlock *curf = SCCalloc(1, sizeof(HttpRangeContainerBlock)); - if (curf == NULL) { - c->error = true; - return NULL; - } - curf->files = NULL; - if (total > c->totalsize) { - // we grow to the maximum size indicated by different range requests - // we could add some warning/app-layer event in this case where - // different range requests indicate different total sizes - c->totalsize = total; - } - const uint64_t buflen = end - start + 1; - - /* The big part of this function is now to decide which kind of HttpRangeContainerBlock - * we will return : - * - skipping already processed data - * - storing out of order data for later use - * - directly appending to the file if we are at the right offset - */ - if (start == c->lastsize && c->files != NULL) { - // easy case : append to current file - curf->container = c; - // If we see 2 duplicate range requests with the same range, - // the first one takes the ownership of the files container - // protected by the lock from caller HTPFileOpenWithRange - curf->files = c->files; - c->files = NULL; - return curf; - } else if (start < c->lastsize && c->lastsize - start >= buflen) { - // only overlap - // redundant to be explicit that this block is independent - curf->toskip = buflen; - return curf; - } else if (start < c->lastsize && c->lastsize - start < buflen && c->files != NULL) { - // some overlap, then some data to append to the file - curf->toskip = c->lastsize - start; - curf->files = c->files; - c->files = NULL; - curf->container = c; - return curf; - } - // Because we are not in the previous cases, we will store the data for later use - - // block/range to be inserted in ordered linked list - if (!(THASH_CHECK_MEMCAP(ContainerUrlRangeList.ht, buflen))) { - // skips this range - curf->toskip = buflen; - return curf; - } - curf->container = c; - - HttpRangeContainerBuffer *range = SCCalloc(1, sizeof(HttpRangeContainerBuffer)); - if (range == NULL) { - c->error = true; - SCFree(curf); - return NULL; - } - - (void)SC_ATOMIC_ADD(ContainerUrlRangeList.ht->memuse, buflen); - range->buffer = SCMalloc(buflen); - if (range->buffer == NULL) { - c->error = true; - SCFree(curf); - SCFree(range); - (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, buflen); - return NULL; - } - range->buflen = buflen; - range->start = start; - range->offset = 0; - range->gap = 0; - curf->current = range; - return curf; -} - -static HttpRangeContainerBlock *HttpRangeOpenFile(HttpRangeContainerFile *c, uint64_t start, - uint64_t end, uint64_t total, const StreamingBufferConfig *sbcfg, const uint8_t *name, - uint16_t name_len, uint16_t flags, const uint8_t *data, uint32_t len) -{ - HttpRangeContainerBlock *r = - HttpRangeOpenFileAux(c, start, end, total, sbcfg, name, name_len, flags); - if (HttpRangeAppendData(sbcfg, r, data, len) < 0) { - SCLogDebug("Failed to append data while opening"); - } - return r; -} - -HttpRangeContainerBlock *HttpRangeContainerOpenFile(const uint8_t *key, uint32_t keylen, - const Flow *f, const HTTPContentRange *crparsed, const StreamingBufferConfig *sbcfg, - const uint8_t *name, uint16_t name_len, uint16_t flags, const uint8_t *data, - uint32_t data_len) -{ - HttpRangeContainerFile *file_range_container = HttpRangeContainerUrlGet(key, keylen, f); - if (file_range_container == NULL) { - // probably reached memcap - return NULL; - } - file_range_container->sbcfg = sbcfg; - - HttpRangeContainerBlock *r = HttpRangeOpenFile(file_range_container, crparsed->start, - crparsed->end, crparsed->size, sbcfg, name, name_len, flags, data, data_len); - SCLogDebug("s->file_range == %p", r); - if (r == NULL) { - THashDecrUsecnt(file_range_container->hdata); - DEBUG_VALIDATE_BUG_ON( - SC_ATOMIC_GET(file_range_container->hdata->use_cnt) > (uint32_t)INT_MAX); - THashDataUnlock(file_range_container->hdata); - - // probably reached memcap - return NULL; - /* in some cases we don't take a reference, so decr use cnt */ - } else if (r->container == NULL) { - THashDecrUsecnt(file_range_container->hdata); - } else { - SCLogDebug("container %p use_cnt %u", r, SC_ATOMIC_GET(r->container->hdata->use_cnt)); - DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(r->container->hdata->use_cnt) > (uint32_t)INT_MAX); - } - - /* we're done, so unlock. But since we have a reference in s->file_range keep use_cnt. */ - THashDataUnlock(file_range_container->hdata); - return r; -} - -int HttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, - const uint8_t *data, uint32_t len) -{ - if (len == 0) { - return 0; - } - // first check if we need to skip all bytes - if (c->toskip >= len) { - c->toskip -= len; - return 0; - } - // then if we need to skip only some bytes - if (c->toskip > 0) { - int r = 0; - if (c->files) { - if (data == NULL) { - // gap overlapping already known data - r = FileAppendData(c->files, sbcfg, NULL, len - c->toskip); - } else { - r = FileAppendData(c->files, sbcfg, data + c->toskip, len - c->toskip); - } - } - c->toskip = 0; - return r; - } - // If we are owning the file to append to it, let's do it - if (c->files) { - SCLogDebug("update files (FileAppendData)"); - return FileAppendData(c->files, sbcfg, data, len); - } - // Maybe we were in the skipping case, - // but we get more data than expected and had set c->toskip = 0 - // so we need to check for last case with something to do - if (c->current) { - // So we have a current allocated buffer to copy to - // in the case of an unordered range being handled - SCLogDebug("update current: adding %u bytes to block %p", len, c); - // GAP "data" - if (data == NULL) { - // just save the length of the gap - c->current->gap += len; - // data, but we're not yet complete - } else if (c->current->offset + len < c->current->buflen) { - memcpy(c->current->buffer + c->current->offset, data, len); - c->current->offset += len; - // data, we're complete - } else if (c->current->offset + len == c->current->buflen) { - memcpy(c->current->buffer + c->current->offset, data, len); - c->current->offset += len; - // data, more than expected - } else { - memcpy(c->current->buffer + c->current->offset, data, - c->current->buflen - c->current->offset); - c->current->offset = c->current->buflen; - } - } - return 0; -} - -static void HttpRangeFileClose( - const StreamingBufferConfig *sbcfg, HttpRangeContainerFile *c, uint16_t flags) -{ - SCLogDebug("closing range %p flags %04x", c, flags); - DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(c->hdata->use_cnt) == 0); - // move ownership of file c->files->head to caller - FileCloseFile(c->files, sbcfg, NULL, 0, c->flags | flags); - c->files->head = NULL; - c->files->tail = NULL; -} - -/** - * \note if `f` is non-NULL, the ownership of the file is transferred to the caller. - */ -File *HttpRangeClose(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags) -{ - SCLogDebug("c %p c->container %p c->current %p", c, c->container, c->current); - - DEBUG_VALIDATE_BUG_ON(c->container == NULL); - - /* we're processing an OOO chunk, won't be able to get us a full file just yet */ - if (c->current) { - SCLogDebug("processing ooo chunk as c->current is set %p", c->current); - // some out-or-order range is finished - if (c->container->lastsize >= c->current->start + c->current->offset) { - // if the range has become obsolete because we received the data already - // we just free it - (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, c->current->buflen); - SCFree(c->current->buffer); - SCFree(c->current); - c->current = NULL; - SCLogDebug("c->current was obsolete"); - return NULL; - } else { - /* otherwise insert in red and black tree. If res != NULL, the insert - failed because its a dup. */ - HttpRangeContainerBuffer *res = - HTTP_RANGES_RB_INSERT(&c->container->fragment_tree, c->current); - if (res) { - SCLogDebug("duplicate range fragment"); - (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, c->current->buflen); - SCFree(c->current->buffer); - SCFree(c->current); - c->current = NULL; - return NULL; - } - SCLogDebug("inserted range fragment"); - c->current = NULL; - if (c->container->files == NULL) { - // we have to wait for the flow owning the file - return NULL; - } - if (c->container->files->tail == NULL) { - // file has already been closed meanwhile - return NULL; - } - // keep on going, maybe this out of order chunk - // became the missing part between open and close - } - SCLogDebug("c->current was set, file incomplete so return NULL"); - } else if (c->toskip > 0) { - // was only an overlapping range, truncated before new bytes - SCLogDebug("c->toskip %" PRIu64, c->toskip); - if (c->files) { - // if we expected new bytes after overlap - c->container->files = c->files; - c->files = NULL; - } - return NULL; - } else { - // we just finished an in-order block - DEBUG_VALIDATE_BUG_ON(c->files == NULL); - // move back the ownership of the file container to HttpRangeContainerFile - c->container->files = c->files; - c->files = NULL; - DEBUG_VALIDATE_BUG_ON(c->container->files->tail == NULL); - } - - File *f = c->container->files->tail; - - /* See if we can use our stored fragments to (partly) reconstruct the file */ - HttpRangeContainerBuffer *range, *safe = NULL; - RB_FOREACH_SAFE (range, HTTP_RANGES, &c->container->fragment_tree, safe) { - if (f->size < range->start) { - // this next range is not reached yet - break; - } - if (f->size == range->start) { - // a new range just begins where we ended, append it - if (range->gap > 0) { - // if the range had a gap, begin by it - if (FileAppendData(c->container->files, sbcfg, NULL, range->gap) != 0) { - c->container->lastsize = f->size; - HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); - c->container->error = true; - return f; - } - } - if (FileAppendData(c->container->files, sbcfg, range->buffer, range->offset) != 0) { - c->container->lastsize = f->size; - HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); - c->container->error = true; - return f; - } - } else { - // the range starts before where we ended - uint64_t overlap = f->size - range->start; - if (overlap < range->offset) { - if (range->gap > 0) { - // if the range had a gap, begin by it - if (FileAppendData(c->container->files, sbcfg, NULL, range->gap) != 0) { - c->container->lastsize = f->size; - HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); - c->container->error = true; - return f; - } - } - // And the range ends beyond where we ended - // in this case of overlap, only add the extra data - if (FileAppendData(c->container->files, sbcfg, range->buffer + overlap, - range->offset - overlap) != 0) { - c->container->lastsize = f->size; - HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); - c->container->error = true; - return f; - } - } - } - /* Remove this range from the tree */ - HTTP_RANGES_RB_REMOVE(&c->container->fragment_tree, range); - (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, range->buflen); - SCFree(range->buffer); - SCFree(range); - } - // wait until we merged all the buffers to update known size - c->container->lastsize = f->size; - - if (f->size >= c->container->totalsize) { - // we finished the whole file - HttpRangeFileClose(sbcfg, c->container, flags); - } else { - // we are expecting more ranges - f = NULL; - SCLogDebug("expecting more use_cnt %u", SC_ATOMIC_GET(c->container->hdata->use_cnt)); - } - SCLogDebug("returning f %p (c:%p container:%p)", f, c, c->container); - return f; -} - -static void HttpRangeBlockDerefContainer(HttpRangeContainerBlock *b) -{ - if (b && b->container) { - DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(b->container->hdata->use_cnt) == 0); - THashDecrUsecnt(b->container->hdata); - b->container = NULL; - } -} - -void HttpRangeFreeBlock(HttpRangeContainerBlock *b) -{ - if (b) { - BUG_ON(b->container == NULL && b->files != NULL); - const StreamingBufferConfig *sbcfg = b->container ? b->container->sbcfg : NULL; - - HttpRangeBlockDerefContainer(b); - - if (b->current) { - (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, b->current->buflen); - SCFree(b->current->buffer); - SCFree(b->current); - } - // we did not move ownership of the file container back to HttpRangeContainerFile - DEBUG_VALIDATE_BUG_ON(b->files != NULL); - if (b->files != NULL) { - FileContainerFree(b->files, sbcfg); - b->files = NULL; - } - SCFree(b); - } -} diff --git a/src/app-layer-htp-range.h b/src/app-layer-htp-range.h deleted file mode 100644 index 8a668aee6d2c..000000000000 --- a/src/app-layer-htp-range.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __APP_LAYER_HTP_RANGE_H__ -#define __APP_LAYER_HTP_RANGE_H__ - -#include "suricata-common.h" - -#include "util-thash.h" -#include "rust.h" - -void HttpRangeContainersInit(void); -void HttpRangeContainersDestroy(void); -uint32_t HttpRangeContainersTimeoutHash(const SCTime_t ts); - -// linked list of ranges : buffer with offset -typedef struct HttpRangeContainerBuffer { - /** red and black tree */ - RB_ENTRY(HttpRangeContainerBuffer) rb; - /** allocated buffer */ - uint8_t *buffer; - /** length of buffer */ - uint64_t buflen; - /** the start of the range (offset relative to the absolute beginning of the file) */ - uint64_t start; - /** offset of bytes written in buffer (relative to the start of the range) */ - uint64_t offset; - /** number of gaped bytes */ - uint64_t gap; -} HttpRangeContainerBuffer; - -int HttpRangeContainerBufferCompare(HttpRangeContainerBuffer *a, HttpRangeContainerBuffer *b); - -RB_HEAD(HTTP_RANGES, HttpRangeContainerBuffer); -RB_PROTOTYPE(HTTP_RANGES, HttpRangeContainerBuffer, rb, HttpRangeContainerBufferCompare); - -/** Item in hash table for a file in multiple ranges - * Thread-safety is ensured with the thread-safe hash table cf THashData - * The number of use is increased for each flow opening a new HttpRangeContainerBlock - * until it closes this HttpRangeContainerBlock - * The design goal is to have concurrency only on opening and closing a range request - * and have a lock-free data structure belonging to one Flow - * (see HttpRangeContainerBlock below) - * for every append in between (we suppose we have many appends per range request) - */ -typedef struct HttpRangeContainerFile { - /** key for hashtable */ - uint8_t *key; - /** key length */ - uint32_t len; - /** expire time in epoch */ - uint32_t expire; - /** pointer to hashtable data, for locking and use count */ - THashData *hdata; - /** total expected size of the file in ranges */ - uint64_t totalsize; - /** size of the file after last sync */ - uint64_t lastsize; - /** streaming buffer config for files below */ - const StreamingBufferConfig *sbcfg; - /** file container, with only one file */ - FileContainer *files; - /** red and black tree list of ranges which came out of order */ - struct HTTP_RANGES fragment_tree; - /** file flags */ - uint16_t flags; - /** error condition for this range. Its up to timeout handling to cleanup */ - bool error; -} HttpRangeContainerFile; - -/** A structure representing a single range request : - * either skipping, buffering, or appending - * As this belongs to a flow, appending data to it is ensured to be thread-safe - * Only one block per file has the pointer to the container - */ -typedef struct HttpRangeContainerBlock { - /** state where we skip content */ - uint64_t toskip; - /** current out of order range to write into */ - HttpRangeContainerBuffer *current; - /** pointer to the main file container, where to directly append data */ - HttpRangeContainerFile *container; - /** file container we are owning for now */ - FileContainer *files; -} HttpRangeContainerBlock; - -int HttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, - const uint8_t *data, uint32_t len); -File *HttpRangeClose( - const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags); - -// HttpRangeContainerBlock but trouble with headers inclusion order -HttpRangeContainerBlock *HttpRangeContainerOpenFile(const unsigned char *key, uint32_t keylen, - const Flow *f, const HTTPContentRange *cr, const StreamingBufferConfig *sbcfg, - const unsigned char *name, uint16_t name_len, uint16_t flags, const unsigned char *data, - uint32_t data_len); - -void HttpRangeFreeBlock(HttpRangeContainerBlock *b); - -#endif /* __APP_LAYER_HTP_RANGE_H__ */ diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c deleted file mode 100644 index c145e5818e23..000000000000 --- a/src/app-layer-htp-xff.c +++ /dev/null @@ -1,349 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Ignacio Sanchez - * \author Duarte Silva - */ - -#include "suricata-common.h" -#include "conf.h" - -#include "app-layer-parser.h" -#include "app-layer-htp.h" -#include "app-layer-htp-xff.h" - -#ifndef HAVE_MEMRCHR -#include "util-memrchr.h" -#endif - -#include "util-misc.h" -#include "util-unittest.h" - -/** XFF header value minimal length */ -#define XFF_CHAIN_MINLEN 7 -/** XFF header value maximum length */ -#define XFF_CHAIN_MAXLEN 256 -/** Default XFF header name */ -#define XFF_DEFAULT "X-Forwarded-For" - -/** \internal - * \brief parse XFF string - * \param input input string, might be modified - * \param output output buffer - * \param output_size size of output buffer - * \retval bool 1 ok, 0 fail - */ -static int ParseXFFString(char *input, char *output, int output_size) -{ - size_t len = strlen(input); - if (len == 0) - return 0; - - if (input[0] == '[') { - char *end = strchr(input, ']'); - if (end == NULL) // malformed, not closed - return 0; - - if (end != input+(len - 1)) { - SCLogDebug("data after closing bracket"); - // if we ever want to parse the port, we can do it here - } - - /* done, lets wrap up */ - input++; // skip past [ - *end = '\0'; // overwrite ], ignore anything after - - } else { - /* lets see if the xff string ends in a port */ - int c = 0; - int d = 0; - char *p = input; - while (*p != '\0') { - if (*p == ':') - c++; - if (*p == '.') - d++; - p++; - } - /* 3 dots: ipv4, one ':' port */ - if (d == 3 && c == 1) { - SCLogDebug("XFF w port %s", input); - char *x = strchr(input, ':'); - if (x) { - *x = '\0'; - SCLogDebug("XFF w/o port %s", input); - // if we ever want to parse the port, we can do it here - } - } - } - - SCLogDebug("XFF %s", input); - - /** Sanity check on extracted IP for IPv4 and IPv6 */ - uint32_t ip[4]; - if (inet_pton(AF_INET, input, ip) == 1 || - inet_pton(AF_INET6, input, ip) == 1) - { - strlcpy(output, input, output_size); - return 1; // OK - } - return 0; -} - -/** - * \brief Function to return XFF IP if any in the selected transaction. The - * caller needs to lock the flow. - * \retval 1 if the IP has been found and returned in dstbuf - * \retval 0 if the IP has not being found or error - */ -int HttpXFFGetIPFromTx(const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg, - char *dstbuf, int dstbuflen) -{ - uint8_t xff_chain[XFF_CHAIN_MAXLEN]; - HtpState *htp_state = NULL; - htp_tx_t *tx = NULL; - uint64_t total_txs = 0; - uint8_t *p_xff = NULL; - - htp_state = (HtpState *)FlowGetAppState(f); - - if (htp_state == NULL) { - SCLogDebug("no http state, XFF IP cannot be retrieved"); - return 0; - } - - total_txs = AppLayerParserGetTxCnt(f, htp_state); - if (tx_id >= total_txs) - return 0; - - tx = AppLayerParserGetTx(f->proto, ALPROTO_HTTP1, htp_state, tx_id); - if (tx == NULL) { - SCLogDebug("tx is NULL, XFF cannot be retrieved"); - return 0; - } - - htp_header_t *h_xff = NULL; - if (tx->request_headers != NULL) { - h_xff = htp_table_get_c(tx->request_headers, xff_cfg->header); - } - - if (h_xff != NULL && bstr_len(h_xff->value) >= XFF_CHAIN_MINLEN && - bstr_len(h_xff->value) < XFF_CHAIN_MAXLEN) { - - memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); - xff_chain[bstr_len(h_xff->value)]=0; - - if (xff_cfg->flags & XFF_REVERSE) { - /** Get the last IP address from the chain */ - p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); - if (p_xff == NULL) { - p_xff = xff_chain; - } else { - p_xff++; - } - } - else { - /** Get the first IP address from the chain */ - p_xff = memchr(xff_chain, ',', bstr_len(h_xff->value)); - if (p_xff != NULL) { - *p_xff = 0; - } - p_xff = xff_chain; - } - return ParseXFFString((char *)p_xff, dstbuf, dstbuflen); - } - return 0; -} - -/** - * \brief Function to return XFF IP if any. The caller needs to lock the flow. - * \retval 1 if the IP has been found and returned in dstbuf - * \retval 0 if the IP has not being found or error - */ -int HttpXFFGetIP(const Flow *f, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen) -{ - HtpState *htp_state = NULL; - uint64_t tx_id = 0; - uint64_t total_txs = 0; - - htp_state = (HtpState *)FlowGetAppState(f); - if (htp_state == NULL) { - SCLogDebug("no http state, XFF IP cannot be retrieved"); - goto end; - } - - total_txs = AppLayerParserGetTxCnt(f, htp_state); - for (; tx_id < total_txs; tx_id++) { - if (HttpXFFGetIPFromTx(f, tx_id, xff_cfg, dstbuf, dstbuflen) == 1) - return 1; - } - -end: - return 0; // Not found -} - -/** - * \brief Function to return XFF configuration from a configuration node. - */ -void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) -{ - BUG_ON(result == NULL); - - ConfNode *xff_node = NULL; - - if (conf != NULL) - xff_node = ConfNodeLookupChild(conf, "xff"); - - if (xff_node != NULL && ConfNodeChildValueIsTrue(xff_node, "enabled")) { - const char *xff_mode = ConfNodeLookupChildValue(xff_node, "mode"); - - if (xff_mode != NULL && strcasecmp(xff_mode, "overwrite") == 0) { - result->flags |= XFF_OVERWRITE; - } else { - if (xff_mode == NULL) { - SCLogWarning("The XFF mode hasn't been defined, falling back to extra-data mode"); - } - else if (strcasecmp(xff_mode, "extra-data") != 0) { - SCLogWarning( - "The XFF mode %s is invalid, falling back to extra-data mode", xff_mode); - } - result->flags |= XFF_EXTRADATA; - } - - const char *xff_deployment = ConfNodeLookupChildValue(xff_node, "deployment"); - - if (xff_deployment != NULL && strcasecmp(xff_deployment, "forward") == 0) { - result->flags |= XFF_FORWARD; - } else { - if (xff_deployment == NULL) { - SCLogWarning("The XFF deployment hasn't been defined, falling back to reverse " - "proxy deployment"); - } - else if (strcasecmp(xff_deployment, "reverse") != 0) { - SCLogWarning("The XFF mode %s is invalid, falling back to reverse proxy deployment", - xff_deployment); - } - result->flags |= XFF_REVERSE; - } - - const char *xff_header = ConfNodeLookupChildValue(xff_node, "header"); - - if (xff_header != NULL) { - result->header = (char *) xff_header; - } else { - SCLogWarning("The XFF header hasn't been defined, using the default %s", XFF_DEFAULT); - result->header = XFF_DEFAULT; - } - } - else { - result->flags = XFF_DISABLED; - } -} - - -#ifdef UNITTESTS -static int XFFTest01(void) { - char input[] = "1.2.3.4:5678"; - char output[16]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 1 && strcmp(output, "1.2.3.4") == 0); - PASS; -} - -static int XFFTest02(void) { - char input[] = "[12::34]:1234"; // thanks chort! - char output[16]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 1 && strcmp(output, "12::34") == 0); - PASS; -} - -static int XFFTest03(void) { - char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]:80"; // thanks chort! - char output[46]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0); - PASS; -} - -static int XFFTest04(void) { - char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]"; // thanks chort! - char output[46]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0); - PASS; -} - -static int XFFTest05(void) { - char input[] = "[::ffff:1.2.3.4]:1234"; // thanks double-p - char output[46]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 1 && strcmp(output, "::ffff:1.2.3.4") == 0); - PASS; -} - -static int XFFTest06(void) { - char input[] = "12::34"; - char output[46]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 1 && strcmp(output, "12::34") == 0); - PASS; -} - -static int XFFTest07(void) { - char input[] = "1.2.3.4"; - char output[46]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 1 && strcmp(output, "1.2.3.4") == 0); - PASS; -} - -static int XFFTest08(void) { - char input[] = "[1.2.3.4:1234"; - char output[46]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 0); - PASS; -} - -static int XFFTest09(void) { - char input[] = "999.999.999.999:1234"; - char output[46]; - int r = ParseXFFString(input, output, sizeof(output)); - FAIL_IF_NOT(r == 0); - PASS; -} - -#endif - -void HTPXFFParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("XFFTest01", XFFTest01); - UtRegisterTest("XFFTest02", XFFTest02); - UtRegisterTest("XFFTest03", XFFTest03); - UtRegisterTest("XFFTest04", XFFTest04); - UtRegisterTest("XFFTest05", XFFTest05); - UtRegisterTest("XFFTest06", XFFTest06); - UtRegisterTest("XFFTest07", XFFTest07); - UtRegisterTest("XFFTest08", XFFTest08); - UtRegisterTest("XFFTest09", XFFTest09); -#endif -} diff --git a/src/app-layer-htp-xff.h b/src/app-layer-htp-xff.h deleted file mode 100644 index 03671d3fbb71..000000000000 --- a/src/app-layer-htp-xff.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Ignacio Sanchez - * \author Duarte Silva - */ - -#ifndef __APP_LAYER_HTP_XFF_H__ -#define __APP_LAYER_HTP_XFF_H__ - -/** XFF is disabled */ -#define XFF_DISABLED 1 -/** XFF extra data mode */ -#define XFF_EXTRADATA 2 -/** XFF overwrite mode */ -#define XFF_OVERWRITE 4 -/** XFF is to be used in a reverse proxy deployment */ -#define XFF_REVERSE 8 -/** XFF is to be used in a forward proxy deployment */ -#define XFF_FORWARD 16 -/** Single XFF IP maximum length (default value based on IPv6 address length) */ -#define XFF_MAXLEN 46 - -typedef struct HttpXFFCfg_ { - uint8_t flags; /**< XFF operation mode and deployment */ - const char *header; /**< XFF header name */ -} HttpXFFCfg; - -void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result); - -int HttpXFFGetIPFromTx(const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); - -int HttpXFFGetIP(const Flow *f, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); - -void HTPXFFParserRegisterTests(void); - -#endif /* __APP_LAYER_HTP_XFF_H__ */ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c deleted file mode 100644 index 5d48611812c1..000000000000 --- a/src/app-layer-htp.c +++ /dev/null @@ -1,7104 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - -/** - * \file - * - * \author Victor Julien - * \author Gurvinder Singh - * \author Pablo Rincon - * \author Brian Rectanus - * \author Anoop Saldanha - * - * This file provides a HTTP protocol support for the engine using HTP library. - */ - -#include "suricata.h" -#include "suricata-common.h" -#include "conf.h" -#include "decode.h" -#include "threads.h" -#include "counters.h" - -#include "util-print.h" -#include "util-pool.h" -#include "util-radix-tree.h" -#include "util-file.h" -#include "util-byte.h" - -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" -#include "stream-tcp.h" -#include "stream.h" - -#include "app-layer-protos.h" -#include "app-layer-parser.h" - -#include "app-layer.h" -#include "app-layer-detect-proto.h" -#include "app-layer-frames.h" -#include "app-layer-htp.h" -#include "app-layer-htp-body.h" -#include "app-layer-htp-file.h" -#include "app-layer-htp-libhtp.h" -#include "app-layer-htp-xff.h" -#include "app-layer-htp-range.h" -#include "app-layer-htp-mem.h" - -#include "util-spm.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-misc.h" -#include "util-enum.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "flow-util.h" - -#include "detect-engine.h" -#include "detect-engine-build.h" -#include "detect-engine-state.h" -#include "detect-parse.h" - -#include "decode-events.h" - -#include "util-memcmp.h" -#include "util-random.h" -#include "util-validate.h" - -//#define PRINT - -/** Fast lookup tree (radix) for the various HTP configurations */ -static SCRadixTree *cfgtree; -/** List of HTP configurations. */ -static HTPCfgRec cfglist; - -StreamingBufferConfig htp_sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; - -/** Limit to the number of libhtp messages that can be handled */ -#define HTP_MAX_MESSAGES 512 - -SC_ATOMIC_DECLARE(uint32_t, htp_config_flags); - -#ifdef DEBUG -static SCMutex htp_state_mem_lock = SCMUTEX_INITIALIZER; -static uint64_t htp_state_memuse = 0; -static uint64_t htp_state_memcnt = 0; -#endif - -SCEnumCharMap http_decoder_event_table[] = { - { "UNKNOWN_ERROR", HTTP_DECODER_EVENT_UNKNOWN_ERROR }, - { "GZIP_DECOMPRESSION_FAILED", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED }, - { "REQUEST_FIELD_MISSING_COLON", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON }, - { "RESPONSE_FIELD_MISSING_COLON", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON }, - { "INVALID_REQUEST_CHUNK_LEN", HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN }, - { "INVALID_RESPONSE_CHUNK_LEN", HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN }, - { "INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST", - HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST }, - { "INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE", - HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE }, - { "INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST", - HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST }, - { "INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE", - HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE }, - { "DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST", - HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST }, - { "DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE", - HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE }, - { "100_CONTINUE_ALREADY_SEEN", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN }, - { "UNABLE_TO_MATCH_RESPONSE_TO_REQUEST", - HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST }, - { "INVALID_SERVER_PORT_IN_REQUEST", HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST }, - { "INVALID_AUTHORITY_PORT", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT }, - { "REQUEST_HEADER_INVALID", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID }, - { "RESPONSE_HEADER_INVALID", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID }, - { "MISSING_HOST_HEADER", HTTP_DECODER_EVENT_MISSING_HOST_HEADER }, - { "HOST_HEADER_AMBIGUOUS", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS }, - { "INVALID_REQUEST_FIELD_FOLDING", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING }, - { "INVALID_RESPONSE_FIELD_FOLDING", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING }, - { "REQUEST_FIELD_TOO_LONG", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG }, - { "RESPONSE_FIELD_TOO_LONG", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG }, - { "FILE_NAME_TOO_LONG", HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG }, - { "REQUEST_LINE_INVALID", HTTP_DECODER_EVENT_REQUEST_LINE_INVALID }, - { "REQUEST_BODY_UNEXPECTED", HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED }, - { "REQUEST_SERVER_PORT_TCP_PORT_MISMATCH", - HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH }, - { "REQUEST_URI_HOST_INVALID", HTTP_DECODER_EVENT_URI_HOST_INVALID }, - { "REQUEST_HEADER_HOST_INVALID", HTTP_DECODER_EVENT_HEADER_HOST_INVALID }, - { "REQUEST_AUTH_UNRECOGNIZED", HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED }, - { "REQUEST_HEADER_REPETITION", HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION }, - { "RESPONSE_HEADER_REPETITION", HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION }, - { "DOUBLE_ENCODED_URI", HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI }, - { "URI_DELIM_NON_COMPLIANT", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT }, - { "METHOD_DELIM_NON_COMPLIANT", HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT }, - { "REQUEST_LINE_LEADING_WHITESPACE", HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE }, - { "TOO_MANY_ENCODING_LAYERS", HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS }, - { "ABNORMAL_CE_HEADER", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, - { "RESPONSE_MULTIPART_BYTERANGES", HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES }, - { "RESPONSE_ABNORMAL_TRANSFER_ENCODING", - HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING }, - { "RESPONSE_CHUNKED_OLD_PROTO", HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO }, - { "RESPONSE_INVALID_PROTOCOL", HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL }, - { "RESPONSE_INVALID_STATUS", HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS }, - { "REQUEST_LINE_INCOMPLETE", HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE }, - - { "LZMA_MEMLIMIT_REACHED", HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED }, - { "COMPRESSION_BOMB", HTTP_DECODER_EVENT_COMPRESSION_BOMB }, - - { "RANGE_INVALID", HTTP_DECODER_EVENT_RANGE_INVALID }, - { "REQUEST_CHUNK_EXTENSION", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION }, - - /* suricata warnings/errors */ - { "MULTIPART_GENERIC_ERROR", HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR }, - { "MULTIPART_NO_FILEDATA", HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA }, - { "MULTIPART_INVALID_HEADER", HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER }, - - { "TOO_MANY_WARNINGS", HTTP_DECODER_EVENT_TOO_MANY_WARNINGS }, - { "FAILED_PROTOCOL_CHANGE", HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE }, - - { NULL, -1 }, -}; - -/* app-layer-frame-documentation tag start: HttpFrameTypes */ -enum HttpFrameTypes { - HTTP_FRAME_REQUEST, - HTTP_FRAME_RESPONSE, -}; - -SCEnumCharMap http_frame_table[] = { - { - "request", - HTTP_FRAME_REQUEST, - }, - { - "response", - HTTP_FRAME_RESPONSE, - }, - { NULL, -1 }, -}; -/* app-layer-frame-documentation tag end: HttpFrameTypes */ - -static int HTTPGetFrameIdByName(const char *frame_name) -{ - int id = SCMapEnumNameToValue(frame_name, http_frame_table); - if (id < 0) { - return -1; - } - return id; -} - -static const char *HTTPGetFrameNameById(const uint8_t frame_id) -{ - const char *name = SCMapEnumValueToName(frame_id, http_frame_table); - return name; -} - -static void *HTPStateGetTx(void *alstate, uint64_t tx_id); -static int HTPStateGetAlstateProgress(void *tx, uint8_t direction); -static uint64_t HTPStateGetTxCnt(void *alstate); -#ifdef UNITTESTS -static void HTPParserRegisterTests(void); -#endif - -static inline uint64_t HtpGetActiveRequestTxID(HtpState *s) -{ - uint64_t id = HTPStateGetTxCnt(s); - BUG_ON(id == 0); - return id - 1; -} - -static inline uint64_t HtpGetActiveResponseTxID(HtpState *s) -{ - return s->transaction_cnt; -} - -#ifdef DEBUG -/** - * \internal - * - * \brief Lookup the HTP personality string from the numeric personality. - * - * \todo This needs to be a libhtp function. - */ -static const char *HTPLookupPersonalityString(int p) -{ -#define CASE_HTP_PERSONALITY_STRING(p) \ - case HTP_SERVER_ ## p: return #p - - switch (p) { - CASE_HTP_PERSONALITY_STRING(MINIMAL); - CASE_HTP_PERSONALITY_STRING(GENERIC); - CASE_HTP_PERSONALITY_STRING(IDS); - CASE_HTP_PERSONALITY_STRING(IIS_4_0); - CASE_HTP_PERSONALITY_STRING(IIS_5_0); - CASE_HTP_PERSONALITY_STRING(IIS_5_1); - CASE_HTP_PERSONALITY_STRING(IIS_6_0); - CASE_HTP_PERSONALITY_STRING(IIS_7_0); - CASE_HTP_PERSONALITY_STRING(IIS_7_5); - CASE_HTP_PERSONALITY_STRING(APACHE_2); - } - - return NULL; -} -#endif /* DEBUG */ - -/** - * \internal - * - * \brief Lookup the numeric HTP personality from a string. - * - * \todo This needs to be a libhtp function. - */ -static int HTPLookupPersonality(const char *str) -{ -#define IF_HTP_PERSONALITY_NUM(p) \ - if (strcasecmp(#p, str) == 0) return HTP_SERVER_ ## p - - IF_HTP_PERSONALITY_NUM(MINIMAL); - IF_HTP_PERSONALITY_NUM(GENERIC); - IF_HTP_PERSONALITY_NUM(IDS); - IF_HTP_PERSONALITY_NUM(IIS_4_0); - IF_HTP_PERSONALITY_NUM(IIS_5_0); - IF_HTP_PERSONALITY_NUM(IIS_5_1); - IF_HTP_PERSONALITY_NUM(IIS_6_0); - IF_HTP_PERSONALITY_NUM(IIS_7_0); - IF_HTP_PERSONALITY_NUM(IIS_7_5); - IF_HTP_PERSONALITY_NUM(APACHE_2); - if (strcasecmp("TOMCAT_6_0", str) == 0) { - SCLogError("Personality %s no " - "longer supported by libhtp.", - str); - return -1; - } else if ((strcasecmp("APACHE", str) == 0) || - (strcasecmp("APACHE_2_2", str) == 0)) - { - SCLogWarning("Personality %s no " - "longer supported by libhtp, failing back to " - "Apache2 personality.", - str); - return HTP_SERVER_APACHE_2; - } - - return -1; -} - -static void HTPSetEvent(HtpState *s, HtpTxUserData *htud, - const uint8_t dir, const uint8_t e) -{ - SCLogDebug("setting event %u", e); - - if (htud) { - AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, e); - s->events++; - return; - } - - const uint64_t tx_id = (dir == STREAM_TOSERVER) ? - HtpGetActiveRequestTxID(s) : HtpGetActiveResponseTxID(s); - - htp_tx_t *tx = HTPStateGetTx(s, tx_id); - if (tx == NULL && tx_id > 0) - tx = HTPStateGetTx(s, tx_id - 1); - if (tx != NULL) { - htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, e); - s->events++; - return; - } - } - SCLogDebug("couldn't set event %u", e); -} - -/** \brief Function to allocates the HTTP state memory and also creates the HTTP - * connection parser to be used by the HTP library - */ -static void *HTPStateAlloc(void *orig_state, AppProto proto_orig) -{ - SCEnter(); - - HtpState *s = HTPMalloc(sizeof(HtpState)); - if (unlikely(s == NULL)) { - SCReturnPtr(NULL, "void"); - } - - memset(s, 0x00, sizeof(HtpState)); - -#ifdef DEBUG - SCMutexLock(&htp_state_mem_lock); - htp_state_memcnt++; - htp_state_memuse += sizeof(HtpState); - SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); - SCMutexUnlock(&htp_state_mem_lock); -#endif - - SCReturnPtr((void *)s, "void"); -} - -static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud) -{ - if (likely(htud)) { - HtpBodyFree(&state->cfg->request, &htud->request_body); - HtpBodyFree(&state->cfg->response, &htud->response_body); - bstr_free(htud->request_uri_normalized); - if (htud->request_headers_raw) - HTPFree(htud->request_headers_raw, htud->request_headers_raw_len); - if (htud->response_headers_raw) - HTPFree(htud->response_headers_raw, htud->response_headers_raw_len); - AppLayerDecoderEventsFreeEvents(&htud->tx_data.events); - if (htud->boundary) - HTPFree(htud->boundary, htud->boundary_len); - if (htud->tx_data.de_state != NULL) { - DetectEngineStateFree(htud->tx_data.de_state); - } - if (htud->file_range) { - HTPFileCloseHandleRange(&htp_sbcfg, &htud->files_tc, 0, htud->file_range, NULL, 0); - HttpRangeFreeBlock(htud->file_range); - } - FileContainerRecycle(&htud->files_ts, &htp_sbcfg); - FileContainerRecycle(&htud->files_tc, &htp_sbcfg); - HTPFree(htud, sizeof(HtpTxUserData)); - } -} - -/** \brief Function to frees the HTTP state memory and also frees the HTTP - * connection parser memory which was used by the HTP library - */ -void HTPStateFree(void *state) -{ - SCEnter(); - - HtpState *s = (HtpState *)state; - if (s == NULL) { - SCReturn; - } - - /* free the connection parser memory used by HTP library */ - if (s->connp != NULL) { - SCLogDebug("freeing HTP state"); - - uint64_t tx_id; - uint64_t total_txs = HTPStateGetTxCnt(state); - /* free the list of body chunks */ - if (s->conn != NULL) { - for (tx_id = 0; tx_id < total_txs; tx_id++) { - htp_tx_t *tx = HTPStateGetTx(s, tx_id); - if (tx != NULL) { - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - HtpTxUserDataFree(s, htud); - htp_tx_set_user_data(tx, NULL); - } - } - } - htp_connp_destroy_all(s->connp); - } - - HTPFree(s, sizeof(HtpState)); - -#ifdef DEBUG - SCMutexLock(&htp_state_mem_lock); - htp_state_memcnt--; - htp_state_memuse -= sizeof(HtpState); - SCLogDebug("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); - SCMutexUnlock(&htp_state_mem_lock); -#endif - - SCReturn; -} - -/** - * \brief HTP transaction cleanup callback - * - * \warning We cannot actually free the transactions here. It seems that - * HTP only accepts freeing of transactions in the response callback. - */ -static void HTPStateTransactionFree(void *state, uint64_t id) -{ - SCEnter(); - - HtpState *s = (HtpState *)state; - - SCLogDebug("state %p, id %"PRIu64, s, id); - - htp_tx_t *tx = HTPStateGetTx(s, id); - if (tx != NULL) { - /* This will remove obsolete body chunks */ - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - HtpTxUserDataFree(s, htud); - htp_tx_set_user_data(tx, NULL); - - /* hack: even if libhtp considers the tx incomplete, we want to - * free it here. htp_tx_destroy however, will refuse to do this. - * As htp_tx_destroy_incomplete isn't available in the public API, - * we hack around it here. */ - if (unlikely(!( - tx->request_progress == HTP_REQUEST_COMPLETE && - tx->response_progress == HTP_RESPONSE_COMPLETE))) - { - tx->request_progress = HTP_REQUEST_COMPLETE; - tx->response_progress = HTP_RESPONSE_COMPLETE; - } - htp_tx_destroy(tx); - } -} - -/** - * \brief Sets a flag that informs the HTP app layer that some module in the - * engine needs the http request body data. - * \initonly - */ -void AppLayerHtpEnableRequestBodyCallback(void) -{ - SCEnter(); - - SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_BODY); - SCReturn; -} - -/** - * \brief Sets a flag that informs the HTP app layer that some module in the - * engine needs the http request body data. - * \initonly - */ -void AppLayerHtpEnableResponseBodyCallback(void) -{ - SCEnter(); - - SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_RESPONSE_BODY); - SCReturn; -} - -/** - * \brief Sets a flag that informs the HTP app layer that some module in the - * engine needs the http request multi part header. - * - * \initonly - */ -static void AppLayerHtpNeedMultipartHeader(void) -{ - SCEnter(); - AppLayerHtpEnableRequestBodyCallback(); - - SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_MULTIPART); - SCReturn; -} - -/** - * \brief Sets a flag that informs the HTP app layer that some module in the - * engine needs the http request file. - * - * \initonly - */ -void AppLayerHtpNeedFileInspection(void) -{ - SCEnter(); - AppLayerHtpNeedMultipartHeader(); - AppLayerHtpEnableRequestBodyCallback(); - AppLayerHtpEnableResponseBodyCallback(); - - SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_FILE); - SCReturn; -} - -static void AppLayerHtpSetStreamDepthFlag(void *tx, const uint8_t flags) -{ - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data((htp_tx_t *)tx); - if (tx_ud) { - SCLogDebug("setting HTP_STREAM_DEPTH_SET, flags %02x", flags); - if (flags & STREAM_TOCLIENT) { - tx_ud->tcflags |= HTP_STREAM_DEPTH_SET; - } else { - tx_ud->tsflags |= HTP_STREAM_DEPTH_SET; - } - } -} - -static bool AppLayerHtpCheckDepth(const HTPCfgDir *cfg, HtpBody *body, uint8_t flags) -{ - SCLogDebug("cfg->body_limit %u stream_depth %u body->content_len_so_far %" PRIu64, - cfg->body_limit, FileReassemblyDepth(), body->content_len_so_far); - if (flags & HTP_STREAM_DEPTH_SET) { - uint32_t stream_depth = FileReassemblyDepth(); - if (body->content_len_so_far < (uint64_t)stream_depth || stream_depth == 0) { - SCLogDebug("true"); - return true; - } - } else { - if (cfg->body_limit == 0 || body->content_len_so_far < cfg->body_limit) { - return true; - } - } - SCLogDebug("false"); - return false; -} - -static uint32_t AppLayerHtpComputeChunkLength(uint64_t content_len_so_far, uint32_t body_limit, - uint32_t stream_depth, uint8_t flags, uint32_t data_len) -{ - uint32_t chunk_len = 0; - if (!(flags & HTP_STREAM_DEPTH_SET) && body_limit > 0 && - (content_len_so_far < (uint64_t)body_limit) && - (content_len_so_far + (uint64_t)data_len) > body_limit) - { - chunk_len = body_limit - content_len_so_far; - } else if ((flags & HTP_STREAM_DEPTH_SET) && stream_depth > 0 && - (content_len_so_far < (uint64_t)stream_depth) && - (content_len_so_far + (uint64_t)data_len) > stream_depth) - { - chunk_len = stream_depth - content_len_so_far; - } - SCLogDebug("len %u", chunk_len); - return (chunk_len == 0 ? data_len : chunk_len); -} - -/* below error messages updated up to libhtp 0.5.7 (git 379632278b38b9a792183694a4febb9e0dbd1e7a) */ -struct { - const char *msg; - uint8_t de; -} htp_errors[] = { - { "GZip decompressor: inflateInit2 failed", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED}, - { "Request field invalid: colon missing", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON}, - { "Response field invalid: missing colon", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON}, - { "Request chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN}, - { "Response chunk encoding: Invalid chunk length", HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN}, -/* { "Invalid T-E value in request", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST}, <- tx flag HTP_REQUEST_INVALID_T_E - { "Invalid T-E value in response", HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE}, <- nothing to replace it */ -/* { "Invalid C-L field in request", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST}, <- tx flag HTP_REQUEST_INVALID_C_L */ - { "Invalid C-L field in response", HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE}, - { "Already seen 100-Continue", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN}, - { "Unable to match response to request", HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST}, - { "Invalid server port information in request", HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST}, -/* { "Invalid authority port", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT}, htp no longer returns this error */ - { "Request buffer over", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG}, - { "Response buffer over", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG}, - { "C-T multipart/byteranges in responses not supported", HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES}, - { "Compression bomb:", HTTP_DECODER_EVENT_COMPRESSION_BOMB}, -}; - -struct { - const char *msg; - uint8_t de; -} htp_warnings[] = { - { "GZip decompressor:", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED }, - { "Request field invalid", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID }, - { "Response field invalid", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID }, - { "Request header name is not a token", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID }, - { "Response header name is not a token", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID }, - /* { "Host information in request headers required by HTTP/1.1", - HTTP_DECODER_EVENT_MISSING_HOST_HEADER}, <- tx flag HTP_HOST_MISSING { "Host information - ambiguous", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS}, <- tx flag HTP_HOST_AMBIGUOUS */ - { "Invalid request field folding", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING }, - { "Invalid response field folding", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING }, - /* line is now: htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request server port=%d number - * differs from the actual TCP port=%d", port, connp->conn->server_port); luckily, "Request - * server port=" is unique */ - /* { "Request server port number differs from the actual TCP port", - HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, */ - { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH }, - { "Request line: URI contains non-compliant delimiter", - HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT }, - { "Request line: non-compliant delimiter between Method and URI", - HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT }, - { "Request line: leading whitespace", HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE }, - { "Too many response content encoding layers", HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS }, - { "C-E gzip has abnormal value", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, - { "C-E deflate has abnormal value", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, - { "C-E unknown setting", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, - { "Excessive request header repetitions", HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION }, - { "Excessive response header repetitions", HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION }, - { "Transfer-encoding has abnormal chunked value", - HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING }, - { "Chunked transfer-encoding on HTTP/0.9 or HTTP/1.0", - HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO }, - { "Invalid response line: invalid protocol", HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL }, - { "Invalid response line: invalid response status", - HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS }, - { "Request line incomplete", HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE }, - { "Unexpected request body", HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED }, - { "LZMA decompressor: memory limit reached", HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED }, - { "Ambiguous request C-L value", HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST }, - { "Ambiguous response C-L value", - HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE }, - { "Request chunk extension", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION }, -}; - -#define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0])) -#define HTP_WARNING_MAX (sizeof(htp_warnings) / sizeof(htp_warnings[0])) - -/** - * \internal - * - * \brief Get the warning id for the warning msg. - * - * \param msg warning message - * - * \retval id the id or 0 in case of not found - */ -static uint8_t HTPHandleWarningGetId(const char *msg) -{ - SCLogDebug("received warning \"%s\"", msg); - size_t idx; - for (idx = 0; idx < HTP_WARNING_MAX; idx++) { - if (strncmp(htp_warnings[idx].msg, msg, - strlen(htp_warnings[idx].msg)) == 0) - { - return htp_warnings[idx].de; - } - } - - return 0; -} - -/** - * \internal - * - * \brief Get the error id for the error msg. - * - * \param msg error message - * - * \retval id the id or 0 in case of not found - */ -static uint8_t HTPHandleErrorGetId(const char *msg) -{ - SCLogDebug("received error \"%s\"", msg); - - size_t idx; - for (idx = 0; idx < HTP_ERROR_MAX; idx++) { - if (strncmp(htp_errors[idx].msg, msg, - strlen(htp_errors[idx].msg)) == 0) - { - return htp_errors[idx].de; - } - } - - return 0; -} - -/** - * \internal - * - * \brief Check state for errors, warnings and add any as events - * - * \param s state - * \param dir direction: STREAM_TOSERVER or STREAM_TOCLIENT - */ -static void HTPHandleError(HtpState *s, const uint8_t dir) -{ - if (s == NULL || s->conn == NULL || - s->conn->messages == NULL) { - return; - } - - size_t size = htp_list_size(s->conn->messages); - size_t msg; - if(size >= HTP_MAX_MESSAGES) { - if (s->htp_messages_offset < HTP_MAX_MESSAGES) { - //only once per HtpState - HTPSetEvent(s, NULL, dir, HTTP_DECODER_EVENT_TOO_MANY_WARNINGS); - s->htp_messages_offset = HTP_MAX_MESSAGES; - //too noisy in fuzzing - //DEBUG_VALIDATE_BUG_ON("Too many libhtp messages"); - } - // ignore further messages - return; - } - - for (msg = s->htp_messages_offset; msg < size; msg++) { - htp_log_t *log = htp_list_get(s->conn->messages, msg); - if (log == NULL) - continue; - - HtpTxUserData *htud = NULL; - htp_tx_t *tx = log->tx; // will be NULL in <=0.5.9 - if (tx != NULL) - htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - - SCLogDebug("message %s", log->msg); - - uint8_t id = HTPHandleErrorGetId(log->msg); - if (id == 0) { - id = HTPHandleWarningGetId(log->msg); - if (id == 0) - id = HTTP_DECODER_EVENT_UNKNOWN_ERROR; - } - - if (id > 0) { - HTPSetEvent(s, htud, dir, id); - } - } - s->htp_messages_offset = (uint16_t)msg; - SCLogDebug("s->htp_messages_offset %u", s->htp_messages_offset); -} - -static inline void HTPErrorCheckTxRequestFlags(HtpState *s, htp_tx_t *tx) -{ -#ifdef DEBUG - BUG_ON(s == NULL || tx == NULL); -#endif - if (tx->flags & ( HTP_REQUEST_INVALID_T_E|HTP_REQUEST_INVALID_C_L| - HTP_HOST_MISSING|HTP_HOST_AMBIGUOUS|HTP_HOSTU_INVALID| - HTP_HOSTH_INVALID)) - { - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud == NULL) - return; - - if (tx->flags & HTP_REQUEST_INVALID_T_E) - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST); - if (tx->flags & HTP_REQUEST_INVALID_C_L) - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST); - if (tx->flags & HTP_HOST_MISSING) - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MISSING_HOST_HEADER); - if (tx->flags & HTP_HOST_AMBIGUOUS) - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS); - if (tx->flags & HTP_HOSTU_INVALID) - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_URI_HOST_INVALID); - if (tx->flags & HTP_HOSTH_INVALID) - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_HEADER_HOST_INVALID); - } - if (tx->request_auth_type == HTP_AUTH_UNRECOGNIZED) { - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud == NULL) - return; - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED); - } - if (tx->is_protocol_0_9 && tx->request_method_number == HTP_M_UNKNOWN && - (tx->request_protocol_number == HTP_PROTOCOL_INVALID || - tx->request_protocol_number == HTP_PROTOCOL_UNKNOWN)) { - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud == NULL) - return; - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_REQUEST_LINE_INVALID); - } -} - -static int Setup(Flow *f, HtpState *hstate) -{ - /* store flow ref in state so callbacks can access it */ - hstate->f = f; - - HTPCfgRec *htp_cfg_rec = &cfglist; - htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */ - void *user_data = NULL; - - if (FLOW_IS_IPV4(f)) { - SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f)); - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(f), cfgtree, &user_data); - } - else if (FLOW_IS_IPV6(f)) { - SCLogDebug("Looking up HTP config for ipv6"); - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)GET_IPV6_DST_ADDR(f), cfgtree, &user_data); - } - else { - SCLogError("unknown address family, bug!"); - goto error; - } - - if (user_data != NULL) { - htp_cfg_rec = user_data; - htp = htp_cfg_rec->cfg; - SCLogDebug("LIBHTP using config: %p", htp); - } else { - SCLogDebug("Using default HTP config: %p", htp); - } - - if (NULL == htp) { -#ifdef DEBUG_VALIDATION - BUG_ON(htp == NULL); -#endif - /* should never happen if HTPConfigure is properly invoked */ - goto error; - } - - hstate->connp = htp_connp_create(htp); - if (hstate->connp == NULL) { - goto error; - } - - hstate->conn = htp_connp_get_connection(hstate->connp); - - htp_connp_set_user_data(hstate->connp, (void *)hstate); - hstate->cfg = htp_cfg_rec; - - SCLogDebug("New hstate->connp %p", hstate->connp); - - struct timeval tv = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) }; - htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &tv); - - StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, - htp_cfg_rec->request.inspect_min_size); - StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOCLIENT, - htp_cfg_rec->response.inspect_min_size); - return 0; -error: - return -1; -} - -/** - * \brief Function to handle the reassembled data from client and feed it to - * the HTP library to process it. - * - * \param flow Pointer to the flow the data belong to - * \param htp_state Pointer the state in which the parsed value to be stored - * \param pstate Application layer parser state for this session - * - * \retval On success returns 1 or on failure returns -1. - */ -static AppLayerResult HTPHandleRequestData(Flow *f, void *htp_state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - SCEnter(); - int ret = 0; - HtpState *hstate = (HtpState *)htp_state; - - /* On the first invocation, create the connection parser structure to - * be used by HTP library. This is looked up via IP in the radix - * tree. Failing that, the default HTP config is used. - */ - if (NULL == hstate->conn) { - if (Setup(f, hstate) != 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - } - DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL); - hstate->slice = &stream_slice; - - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - htp_time_t ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) }; - /* pass the new data to the htp parser */ - if (input_len > 0) { - const int r = htp_connp_req_data(hstate->connp, &ts, input, input_len); - switch (r) { - case HTP_STREAM_ERROR: - ret = -1; - break; - default: - break; - } - HTPHandleError(hstate, STREAM_TOSERVER); - } - - /* if the TCP connection is closed, then close the HTTP connection */ - if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) && - !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS)) - { - htp_connp_req_close(hstate->connp, &ts); - hstate->flags |= HTP_FLAG_STATE_CLOSED_TS; - SCLogDebug("stream eof encountered, closing htp handle for ts"); - } - - SCLogDebug("hstate->connp %p", hstate->connp); - hstate->slice = NULL; - - if (ret < 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - SCReturnStruct(APP_LAYER_OK); -} - -/** - * \brief Function to handle the reassembled data from server and feed it to - * the HTP library to process it. - * - * \param flow Pointer to the flow the data belong to - * \param htp_state Pointer the state in which the parsed value to be stored - * \param pstate Application layer parser state for this session - * \param input Pointer the received HTTP server data - * \param input_len Length in bytes of the received data - * \param output Pointer to the output (not used in this function) - * - * \retval On success returns 1 or on failure returns -1 - */ -static AppLayerResult HTPHandleResponseData(Flow *f, void *htp_state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - SCEnter(); - int ret = 0; - HtpState *hstate = (HtpState *)htp_state; - - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - /* On the first invocation, create the connection parser structure to - * be used by HTP library. This is looked up via IP in the radix - * tree. Failing that, the default HTP config is used. - */ - if (NULL == hstate->conn) { - if (Setup(f, hstate) != 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - } - DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL); - hstate->slice = &stream_slice; - - htp_time_t ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) }; - htp_tx_t *tx = NULL; - size_t consumed = 0; - if (input_len > 0) { - const int r = htp_connp_res_data(hstate->connp, &ts, input, input_len); - switch (r) { - case HTP_STREAM_ERROR: - ret = -1; - break; - case HTP_STREAM_TUNNEL: - tx = htp_connp_get_out_tx(hstate->connp); - if (tx != NULL && tx->response_status_number == 101) { - htp_header_t *h = - (htp_header_t *)htp_table_get_c(tx->response_headers, "Upgrade"); - if (h == NULL || bstr_cmp_c(h->value, "h2c") != 0) { - break; - } - if (AppLayerProtoDetectGetProtoName(ALPROTO_HTTP2) == NULL) { - // if HTTP2 is disabled, keep the HTP_STREAM_TUNNEL mode - break; - } - uint16_t dp = 0; - if (tx->request_port_number != -1) { - dp = (uint16_t)tx->request_port_number; - } - consumed = htp_connp_res_data_consumed(hstate->connp); - hstate->slice = NULL; - if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_HTTP2)) { - HTPSetEvent(hstate, NULL, STREAM_TOCLIENT, - HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE); - } - // During HTTP2 upgrade, we may consume the HTTP1 part of the data - // and we need to parser the remaining part with HTTP2 - if (consumed > 0 && consumed < input_len) { - SCReturnStruct(APP_LAYER_INCOMPLETE(consumed, input_len - consumed)); - } - SCReturnStruct(APP_LAYER_OK); - } - break; - default: - break; - } - HTPHandleError(hstate, STREAM_TOCLIENT); - } - - /* if we the TCP connection is closed, then close the HTTP connection */ - if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) && - !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC)) - { - htp_connp_close(hstate->connp, &ts); - hstate->flags |= HTP_FLAG_STATE_CLOSED_TC; - } - - SCLogDebug("hstate->connp %p", hstate->connp); - hstate->slice = NULL; - - if (ret < 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - SCReturnStruct(APP_LAYER_OK); -} - -/** - * \param name /Lowercase/ version of the variable name - */ -static int HTTPParseContentDispositionHeader(uint8_t *name, size_t name_len, - uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen) -{ -#ifdef PRINT - printf("DATA START: \n"); - PrintRawDataFp(stdout, data, len); - printf("DATA END: \n"); -#endif - size_t x; - int quote = 0; - - for (x = 0; x < len; x++) { - if (!(isspace(data[x]))) - break; - } - - if (x >= len) - return 0; - - uint8_t *line = data+x; - size_t line_len = len-x; - size_t offset = 0; -#ifdef PRINT - printf("LINE START: \n"); - PrintRawDataFp(stdout, line, line_len); - printf("LINE END: \n"); -#endif - for (x = 0 ; x < line_len; x++) { - if (x > 0) { - if (line[x - 1] != '\\' && line[x] == '\"') { - quote++; - } - - if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) { - uint8_t *token = line + offset; - size_t token_len = x - offset; - - if ((x + 1) == line_len) { - token_len++; - } - - offset = x + 1; - - while (offset < line_len && isspace(line[offset])) { - x++; - offset++; - } -#ifdef PRINT - printf("TOKEN START: \n"); - PrintRawDataFp(stdout, token, token_len); - printf("TOKEN END: \n"); -#endif - if (token_len > name_len) { - if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) { - uint8_t *value = token + name_len; - size_t value_len = token_len - name_len; - - if (value[0] == '\"') { - value++; - value_len--; - } - if (value[value_len-1] == '\"') { - value_len--; - } -#ifdef PRINT - printf("VALUE START: \n"); - PrintRawDataFp(stdout, value, value_len); - printf("VALUE END: \n"); -#endif - *retptr = value; - *retlen = value_len; - return 1; - } - } - } - } - } - - return 0; -} - -/** - * \param name /Lowercase/ version of the variable name - */ -static int HTTPParseContentTypeHeader(uint8_t *name, size_t name_len, - uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen) -{ - SCEnter(); -#ifdef PRINT - printf("DATA START: \n"); - PrintRawDataFp(stdout, data, len); - printf("DATA END: \n"); -#endif - size_t x; - int quote = 0; - - for (x = 0; x < len; x++) { - if (!(isspace(data[x]))) - break; - } - - if (x >= len) { - SCReturnInt(0); - } - - uint8_t *line = data+x; - size_t line_len = len-x; - size_t offset = 0; -#ifdef PRINT - printf("LINE START: \n"); - PrintRawDataFp(stdout, line, line_len); - printf("LINE END: \n"); -#endif - for (x = 0 ; x < line_len; x++) { - if (x > 0) { - if (line[x - 1] != '\\' && line[x] == '\"') { - quote++; - } - - if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && (quote == 0 || quote % 2 == 0)) { - uint8_t *token = line + offset; - size_t token_len = x - offset; - - if ((x + 1) == line_len) { - token_len++; - } - - offset = x + 1; - - while (offset < line_len && isspace(line[offset])) { - x++; - offset++; - } -#ifdef PRINT - printf("TOKEN START: \n"); - PrintRawDataFp(stdout, token, token_len); - printf("TOKEN END: \n"); -#endif - if (token_len > name_len) { - if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) { - uint8_t *value = token + name_len; - size_t value_len = token_len - name_len; - - if (value[0] == '\"') { - value++; - value_len--; - } - if (value[value_len-1] == '\"') { - value_len--; - } -#ifdef PRINT - printf("VALUE START: \n"); - PrintRawDataFp(stdout, value, value_len); - printf("VALUE END: \n"); -#endif - *retptr = value; - *retlen = value_len; - SCReturnInt(1); - } - } - } - } - } - - SCReturnInt(0); -} - -/** - * \brief setup multipart parsing: extract boundary and store it - * - * \param d HTTP transaction - * \param htud transaction userdata - * - * \retval 1 ok, multipart set up - * \retval 0 ok, not multipart though - * \retval -1 error: problem with the boundary - * - * If the request contains a multipart message, this function will - * set the HTP_BOUNDARY_SET in the transaction. - */ -static int HtpRequestBodySetupMultipart(htp_tx_t *tx, HtpTxUserData *htud) -{ - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "Content-Type"); - if (h != NULL && bstr_len(h->value) > 0) { - uint8_t *boundary = NULL; - size_t boundary_len = 0; - - int r = HTTPParseContentTypeHeader((uint8_t *)"boundary=", 9, - (uint8_t *) bstr_ptr(h->value), bstr_len(h->value), - &boundary, &boundary_len); - if (r == 1) { -#ifdef PRINT - printf("BOUNDARY START: \n"); - PrintRawDataFp(stdout, boundary, boundary_len); - printf("BOUNDARY END: \n"); -#endif - if (boundary_len < HTP_BOUNDARY_MAX) { - htud->boundary = HTPMalloc(boundary_len); - if (htud->boundary == NULL) { - return -1; - } - htud->boundary_len = (uint8_t)boundary_len; - memcpy(htud->boundary, boundary, boundary_len); - - htud->tsflags |= HTP_BOUNDARY_SET; - } else { - SCLogDebug("invalid boundary"); - return -1; - } - SCReturnInt(1); - } - //SCReturnInt(1); - } - SCReturnInt(0); -} - -#define C_D_HDR "content-disposition:" -#define C_D_HDR_LEN 20 -#define C_T_HDR "content-type:" -#define C_T_HDR_LEN 13 - -static void HtpRequestBodyMultipartParseHeader(HtpState *hstate, - HtpTxUserData *htud, - uint8_t *header, uint32_t header_len, - uint8_t **filename, uint16_t *filename_len, - uint8_t **filetype, uint16_t *filetype_len) -{ - uint8_t *fn = NULL; - size_t fn_len = 0; - uint8_t *ft = NULL; - size_t ft_len = 0; - -#ifdef PRINT - printf("HEADER START: \n"); - PrintRawDataFp(stdout, header, header_len); - printf("HEADER END: \n"); -#endif - - while (header_len > 0) { - uint8_t *next_line = Bs2bmSearch(header, header_len, (uint8_t *)"\r\n", 2); - uint8_t *line = header; - uint32_t line_len; - - if (next_line == NULL) { - line_len = header_len; - } else { - line_len = next_line - header; - } - uint8_t *sc = (uint8_t *)memchr(line, ':', line_len); - if (sc == NULL) { - HTPSetEvent(hstate, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER); - /* if the : we found is the final char, it means we have - * no value */ - } else if (line_len > 0 && sc == &line[line_len - 1]) { - HTPSetEvent(hstate, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER); - } else { -#ifdef PRINT - printf("LINE START: \n"); - PrintRawDataFp(stdout, line, line_len); - printf("LINE END: \n"); -#endif - if (line_len >= C_D_HDR_LEN && - SCMemcmpLowercase(C_D_HDR, line, C_D_HDR_LEN) == 0) { - uint8_t *value = line + C_D_HDR_LEN; - uint32_t value_len = line_len - C_D_HDR_LEN; - - /* parse content-disposition */ - (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9, - value, value_len, &fn, &fn_len); - } else if (line_len >= C_T_HDR_LEN && - SCMemcmpLowercase(C_T_HDR, line, C_T_HDR_LEN) == 0) { - SCLogDebug("content-type line"); - uint8_t *value = line + C_T_HDR_LEN; - uint32_t value_len = line_len - C_T_HDR_LEN; - - (void)HTTPParseContentTypeHeader(NULL, 0, - value, value_len, &ft, &ft_len); - } - } - - if (next_line == NULL) { - SCLogDebug("no next_line"); - break; - } - header_len -= ((next_line + 2) - header); - header = next_line + 2; - } /* while (header_len > 0) */ - - if (fn_len > USHRT_MAX) - fn_len = USHRT_MAX; - if (ft_len > USHRT_MAX) - ft_len = USHRT_MAX; - - *filename = fn; - *filename_len = (uint16_t)fn_len; - *filetype = ft; - *filetype_len = (uint16_t)ft_len; -} - -/** - * \brief Create a single buffer from the HtpBodyChunks in our list - * - * \param htud transaction user data - * \param chunks_buffers pointer to pass back the buffer to the caller - * \param chunks_buffer_len pointer to pass back the buffer length to the caller - */ -static void HtpRequestBodyReassemble(HtpTxUserData *htud, - const uint8_t **chunks_buffer, uint32_t *chunks_buffer_len) -{ - StreamingBufferGetDataAtOffset(htud->request_body.sb, - chunks_buffer, chunks_buffer_len, - htud->request_body.body_parsed); -} - -static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir) -{ - SCEnter(); - if (tx && tx->tx_data.de_state) { - if (dir == STREAM_TOSERVER) { - SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set"); - tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW; - } else if (STREAM_TOCLIENT) { - SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set"); - tx->tx_data.de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW; - } - } -} - -/** - * \brief Setup boundary buffers - */ -static void HtpRequestBodySetupBoundary(HtpTxUserData *htud, - uint8_t *boundary, uint32_t boundary_len) -{ - memset(boundary, '-', boundary_len); - memcpy(boundary + 2, htud->boundary, htud->boundary_len); -} - -static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, void *tx, - const uint8_t *chunks_buffer, uint32_t chunks_buffer_len) -{ - int result = 0; - uint8_t boundary[htud->boundary_len + 4]; /**< size limited to HTP_BOUNDARY_MAX + 4 */ - uint16_t expected_boundary_len = htud->boundary_len + 2; - uint16_t expected_boundary_end_len = htud->boundary_len + 4; - int tx_progress = 0; - -#ifdef PRINT - printf("CHUNK START: \n"); - PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); - printf("CHUNK END: \n"); -#endif - - HtpRequestBodySetupBoundary(htud, boundary, htud->boundary_len + 4); - - /* search for the header start, header end and form end */ - const uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len, - boundary, expected_boundary_len); - /* end of the multipart form */ - const uint8_t *form_end = NULL; - /* end marker belonging to header_start */ - const uint8_t *header_end = NULL; - if (header_start != NULL) { - header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), - (uint8_t *)"\r\n\r\n", 4); - form_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), - boundary, expected_boundary_end_len); - } - - SCLogDebug("header_start %p, header_end %p, form_end %p", header_start, - header_end, form_end); - - /* we currently only handle multipart for ts. When we support it for tc, - * we will need to supply right direction */ - tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, STREAM_TOSERVER); - /* if we're in the file storage process, deal with that now */ - if (htud->tsflags & HTP_FILENAME_SET) { - if (header_start != NULL || (tx_progress > HTP_REQUEST_BODY)) { - SCLogDebug("reached the end of the file"); - - const uint8_t *filedata = chunks_buffer; - uint32_t filedata_len = 0; - uint8_t flags = 0; - - if (header_start != NULL) { - if (header_start == filedata + 2) { - /* last chunk had all data, but not the boundary */ - SCLogDebug("last chunk had all data, but not the boundary"); - filedata_len = 0; - } else if (header_start > filedata + 2) { - SCLogDebug("some data from last file before the boundary"); - /* some data from last file before the boundary */ - filedata_len = header_start - filedata - 2; - } - } - /* body parsing done, we did not get our form end. Use all data - * we still have and signal to files API we have an issue. */ - if (tx_progress > HTP_REQUEST_BODY) { - filedata_len = chunks_buffer_len; - flags = FILE_TRUNCATED; - } - - if (filedata_len > chunks_buffer_len) { - HTPSetEvent(hstate, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); - goto end; - } -#ifdef PRINT - printf("FILEDATA (final chunk) START: \n"); - PrintRawDataFp(stdout, filedata, filedata_len); - printf("FILEDATA (final chunk) END: \n"); -#endif - if (!(htud->tsflags & HTP_DONTSTORE)) { - if (HTPFileClose(hstate, htud, filedata, filedata_len, flags, STREAM_TOSERVER) == - -1) { - goto end; - } - } - - htud->tsflags &=~ HTP_FILENAME_SET; - - /* fall through */ - } else { - SCLogDebug("not yet at the end of the file"); - - if (chunks_buffer_len > expected_boundary_end_len) { - const uint8_t *filedata = chunks_buffer; - uint32_t filedata_len = chunks_buffer_len - expected_boundary_len; - for (; filedata_len < chunks_buffer_len; filedata_len++) { - // take as much as we can until the beginning of a new line - if (chunks_buffer[filedata_len] == '\r') { - if (filedata_len + 1 == chunks_buffer_len || - chunks_buffer[filedata_len + 1] == '\n') { - break; - } - } - } - -#ifdef PRINT - printf("FILEDATA (part) START: \n"); - PrintRawDataFp(stdout, filedata, filedata_len); - printf("FILEDATA (part) END: \n"); -#endif - - if (!(htud->tsflags & HTP_DONTSTORE)) { - result = HTPFileStoreChunk( - hstate, htud, filedata, filedata_len, STREAM_TOSERVER); - if (result == -1) { - goto end; - } else if (result == -2) { - /* we know for sure we're not storing the file */ - htud->tsflags |= HTP_DONTSTORE; - } - } - - htud->request_body.body_parsed += filedata_len; - } else { - SCLogDebug("chunk too small to already process in part"); - } - - goto end; - } - } - - while (header_start != NULL && header_end != NULL && - header_end != form_end && - header_start < (chunks_buffer + chunks_buffer_len) && - header_end < (chunks_buffer + chunks_buffer_len) && - header_start < header_end) - { - uint8_t *filename = NULL; - uint16_t filename_len = 0; - uint8_t *filetype = NULL; - uint16_t filetype_len = 0; - - uint32_t header_len = header_end - header_start; - SCLogDebug("header_len %u", header_len); - uint8_t *header = (uint8_t *)header_start; - - /* skip empty records */ - if (expected_boundary_len == header_len) { - goto next; - } else if ((uint32_t)(expected_boundary_len + 2) <= header_len) { - header_len -= (expected_boundary_len + 2); - header = (uint8_t *)header_start + (expected_boundary_len + 2); // + for 0d 0a - } - - HtpRequestBodyMultipartParseHeader(hstate, htud, header, header_len, - &filename, &filename_len, &filetype, &filetype_len); - - if (filename != NULL) { - const uint8_t *filedata = NULL; - uint32_t filedata_len = 0; - - SCLogDebug("we have a filename"); - - htud->tsflags |= HTP_FILENAME_SET; - htud->tsflags &= ~HTP_DONTSTORE; - - SCLogDebug("header_end %p", header_end); - SCLogDebug("form_end %p", form_end); - - /* everything until the final boundary is the file */ - if (form_end != NULL) { - SCLogDebug("have form_end"); - - filedata = header_end + 4; - if (form_end == filedata) { - HTPSetEvent(hstate, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA); - goto end; - } else if (form_end < filedata) { - HTPSetEvent(hstate, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); - goto end; - } - - filedata_len = form_end - (header_end + 4 + 2); - SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len); - - /* or is it? */ - uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, - boundary, expected_boundary_len); - if (header_next != NULL) { - filedata_len -= (form_end - header_next); - } - - if (filedata_len > chunks_buffer_len) { - HTPSetEvent(hstate, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); - goto end; - } - SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len); -#ifdef PRINT - printf("FILEDATA START: \n"); - PrintRawDataFp(stdout, filedata, filedata_len); - printf("FILEDATA END: \n"); -#endif - - result = HTPFileOpen(hstate, htud, filename, filename_len, filedata, filedata_len, - HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); - if (result == -1) { - goto end; - } else if (result == -2) { - htud->tsflags |= HTP_DONTSTORE; - } else { - if (HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOSERVER) == -1) { - goto end; - } - } - FlagDetectStateNewFile(htud, STREAM_TOSERVER); - - htud->request_body.body_parsed += (header_end - chunks_buffer); - htud->tsflags &= ~HTP_FILENAME_SET; - } else { - SCLogDebug("chunk doesn't contain form end"); - - filedata = header_end + 4; - filedata_len = chunks_buffer_len - (filedata - chunks_buffer); - SCLogDebug("filedata_len %u (chunks_buffer_len %u)", filedata_len, chunks_buffer_len); - - if (filedata_len > chunks_buffer_len) { - HTPSetEvent(hstate, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); - goto end; - } - -#ifdef PRINT - printf("FILEDATA START: \n"); - PrintRawDataFp(stdout, filedata, filedata_len); - printf("FILEDATA END: \n"); -#endif - /* form doesn't end in this chunk, but the part might. Lets - * see if have another coming up */ - uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, - boundary, expected_boundary_len); - SCLogDebug("header_next %p", header_next); - if (header_next == NULL) { - SCLogDebug("more file data to come"); - - uint32_t offset = (header_end + 4) - chunks_buffer; - SCLogDebug("offset %u", offset); - htud->request_body.body_parsed += offset; - - if (filedata_len >= (uint32_t)(expected_boundary_len + 2)) { - filedata_len -= (expected_boundary_len + 2 - 1); - // take as much as we can until start of boundary - for (size_t nb = 0; nb < (size_t)expected_boundary_len + 1; nb++) { - if (filedata[filedata_len] == '\r') { - if (nb == expected_boundary_len || - filedata[filedata_len + 1] == '\n') { - break; - } - } - filedata_len++; - } - SCLogDebug("opening file with partial data"); - } else { - filedata = NULL; - filedata_len = 0; - } - result = HTPFileOpen(hstate, htud, filename, filename_len, filedata, - filedata_len, HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); - if (result == -1) { - goto end; - } else if (result == -2) { - htud->tsflags |= HTP_DONTSTORE; - } - FlagDetectStateNewFile(htud, STREAM_TOSERVER); - htud->request_body.body_parsed += filedata_len; - SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed); - - } else if (header_next - filedata > 2) { - filedata_len = header_next - filedata - 2; - SCLogDebug("filedata_len %u", filedata_len); - - result = HTPFileOpen(hstate, htud, filename, filename_len, filedata, - filedata_len, HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); - if (result == -1) { - goto end; - } else if (result == -2) { - htud->tsflags |= HTP_DONTSTORE; - } else { - if (HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOSERVER) == -1) { - goto end; - } - } - FlagDetectStateNewFile(htud, STREAM_TOSERVER); - - htud->tsflags &= ~HTP_FILENAME_SET; - htud->request_body.body_parsed += (header_end - chunks_buffer); - } - } - } -next: - SCLogDebug("header_start %p, header_end %p, form_end %p", - header_start, header_end, form_end); - - /* Search next boundary entry after the start of body */ - uint32_t cursizeread = header_end - chunks_buffer; - header_start = Bs2bmSearch(header_end + 4, - chunks_buffer_len - (cursizeread + 4), - boundary, expected_boundary_len); - if (header_start != NULL) { - header_end = Bs2bmSearch(header_end + 4, - chunks_buffer_len - (cursizeread + 4), - (uint8_t *) "\r\n\r\n", 4); - } - } - - /* if we're parsing the multipart and we're not currently processing a - * file, we move the body pointer forward. */ - if (form_end == NULL && !(htud->tsflags & HTP_FILENAME_SET) && header_start == NULL) { - if (chunks_buffer_len > expected_boundary_end_len) { - uint32_t move = chunks_buffer_len - expected_boundary_end_len + 1; - - htud->request_body.body_parsed += move; - SCLogDebug("form not ready, file not set, parsing non-file " - "record: moved %u", move); - } - } - -end: - SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed); - return 0; -} - -/** \internal - * \brief Handle POST or PUT, no multipart body data - */ -static int HtpRequestBodyHandlePOSTorPUT(HtpState *hstate, HtpTxUserData *htud, - htp_tx_t *tx, uint8_t *data, uint32_t data_len) -{ - int result = 0; - - /* see if we need to open the file */ - if (!(htud->tsflags & HTP_FILENAME_SET)) - { - uint8_t *filename = NULL; - size_t filename_len = 0; - - /* get the name */ - if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { - filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); - filename_len = bstr_len(tx->parsed_uri->path); - } - - if (filename != NULL) { - if (filename_len > SC_FILENAME_MAX) { - // explicitly truncate the file name if too long - filename_len = SC_FILENAME_MAX; - HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG); - } - result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len, - HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); - if (result == -1) { - goto end; - } else if (result == -2) { - htud->tsflags |= HTP_DONTSTORE; - } else { - FlagDetectStateNewFile(htud, STREAM_TOSERVER); - htud->tsflags |= HTP_FILENAME_SET; - htud->tsflags &= ~HTP_DONTSTORE; - } - } - } - else - { - /* otherwise, just store the data */ - - if (!(htud->tsflags & HTP_DONTSTORE)) { - result = HTPFileStoreChunk(hstate, htud, data, data_len, STREAM_TOSERVER); - if (result == -1) { - goto end; - } else if (result == -2) { - /* we know for sure we're not storing the file */ - htud->tsflags |= HTP_DONTSTORE; - } - } - } - - return 0; -end: - return -1; -} - -static int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, - htp_tx_t *tx, uint8_t *data, uint32_t data_len) -{ - SCEnter(); - - int result = 0; - - /* see if we need to open the file - * we check for tx->response_line in case of junk - * interpreted as body before response line - */ - if (!(htud->tcflags & HTP_FILENAME_SET)) { - SCLogDebug("setting up file name"); - - uint8_t *filename = NULL; - size_t filename_len = 0; - - /* try Content-Disposition header first */ - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, - "Content-Disposition"); - if (h != NULL && bstr_len(h->value) > 0) { - /* parse content-disposition */ - (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9, - (uint8_t *) bstr_ptr(h->value), bstr_len(h->value), &filename, &filename_len); - } - - /* fall back to name from the uri */ - if (filename == NULL) { - /* get the name */ - if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { - filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); - filename_len = bstr_len(tx->parsed_uri->path); - } - } - - if (filename != NULL) { - // set range if present - htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range"); - if (filename_len > SC_FILENAME_MAX) { - // explicitly truncate the file name if too long - filename_len = SC_FILENAME_MAX; - HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG); - } - if (h_content_range != NULL) { - result = HTPFileOpenWithRange(hstate, htud, filename, (uint16_t)filename_len, data, - data_len, HtpGetActiveResponseTxID(hstate), h_content_range->value, htud); - } else { - result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len, - HtpGetActiveResponseTxID(hstate), STREAM_TOCLIENT); - } - SCLogDebug("result %d", result); - if (result == -1) { - goto end; - } else if (result == -2) { - htud->tcflags |= HTP_DONTSTORE; - } else { - FlagDetectStateNewFile(htud, STREAM_TOCLIENT); - htud->tcflags |= HTP_FILENAME_SET; - htud->tcflags &= ~HTP_DONTSTORE; - } - } - } else { - /* otherwise, just store the data */ - - if (!(htud->tcflags & HTP_DONTSTORE)) { - result = HTPFileStoreChunk(hstate, htud, data, data_len, STREAM_TOCLIENT); - SCLogDebug("result %d", result); - if (result == -1) { - goto end; - } else if (result == -2) { - /* we know for sure we're not storing the file */ - htud->tcflags |= HTP_DONTSTORE; - } - } - } - - htud->response_body.body_parsed += data_len; - return 0; -end: - return -1; -} - -/** - * \brief Function callback to append chunks for Requests - * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib) - * \retval int HTP_OK if all goes well - */ -static int HTPCallbackRequestBodyData(htp_tx_data_t *d) -{ - SCEnter(); - - if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY)) - SCReturnInt(HTP_OK); - - if (d->len == 0) - SCReturnInt(HTP_OK); - -#ifdef PRINT - printf("HTPBODY START: \n"); - PrintRawDataFp(stdout, (uint8_t *)d->data, d->len); - printf("HTPBODY END: \n"); -#endif - - HtpState *hstate = htp_connp_get_user_data(d->tx->connp); - if (hstate == NULL) { - SCReturnInt(HTP_ERROR); - } - - SCLogDebug("New request body data available at %p -> %p -> %p, bodylen " - "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len); - - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx); - if (tx_ud == NULL) { - SCReturnInt(HTP_OK); - } - tx_ud->tx_data.file_flags |= hstate->state_data.file_flags; - - if (!tx_ud->response_body_init) { - tx_ud->response_body_init = 1; - - if (d->tx->request_method_number == HTP_M_POST) { - SCLogDebug("POST"); - int r = HtpRequestBodySetupMultipart(d->tx, tx_ud); - if (r == 1) { - tx_ud->request_body_type = HTP_BODY_REQUEST_MULTIPART; - } else if (r == 0) { - tx_ud->request_body_type = HTP_BODY_REQUEST_POST; - SCLogDebug("not multipart"); - } - } else if (d->tx->request_method_number == HTP_M_PUT) { - tx_ud->request_body_type = HTP_BODY_REQUEST_PUT; - } - } - - /* see if we can get rid of htp body chunks */ - HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER); - - SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far); - SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit); - - /* within limits, add the body chunk to the state. */ - if (AppLayerHtpCheckDepth(&hstate->cfg->request, &tx_ud->request_body, tx_ud->tsflags)) { - uint32_t stream_depth = FileReassemblyDepth(); - uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far, - hstate->cfg->request.body_limit, - stream_depth, - tx_ud->tsflags, - (uint32_t)d->len); - BUG_ON(len > (uint32_t)d->len); - - HtpBodyAppendChunk(&hstate->cfg->request, &tx_ud->request_body, d->data, len); - - const uint8_t *chunks_buffer = NULL; - uint32_t chunks_buffer_len = 0; - - if (tx_ud->request_body_type == HTP_BODY_REQUEST_MULTIPART) { - /* multi-part body handling starts here */ - if (!(tx_ud->tsflags & HTP_BOUNDARY_SET)) { - goto end; - } - - HtpRequestBodyReassemble(tx_ud, &chunks_buffer, &chunks_buffer_len); - if (chunks_buffer == NULL) { - goto end; - } -#ifdef PRINT - printf("REASSCHUNK START: \n"); - PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); - printf("REASSCHUNK END: \n"); -#endif - - HtpRequestBodyHandleMultipart(hstate, tx_ud, d->tx, chunks_buffer, chunks_buffer_len); - - } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST || - tx_ud->request_body_type == HTP_BODY_REQUEST_PUT) { - HtpRequestBodyHandlePOSTorPUT(hstate, tx_ud, d->tx, (uint8_t *)d->data, len); - } - - } else { - if (tx_ud->tsflags & HTP_FILENAME_SET) { - SCLogDebug("closing file that was being stored"); - (void)HTPFileClose(hstate, tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOSERVER); - tx_ud->tsflags &= ~HTP_FILENAME_SET; - } - } - -end: - if (hstate->conn != NULL) { - SCLogDebug("checking body size %"PRIu64" against inspect limit %u (cur %"PRIu64", last %"PRIu64")", - tx_ud->request_body.content_len_so_far, - hstate->cfg->request.inspect_min_size, - (uint64_t)hstate->conn->in_data_counter, hstate->last_request_data_stamp); - - /* if we reach the inspect_min_size we'll trigger inspection, - * so make sure that raw stream is also inspected. Set the - * data to be used to the amount of raw bytes we've seen to - * get here. */ - if (tx_ud->request_body.body_inspected == 0 && - tx_ud->request_body.content_len_so_far >= hstate->cfg->request.inspect_min_size) { - if ((uint64_t)hstate->conn->in_data_counter > hstate->last_request_data_stamp && - (uint64_t)hstate->conn->in_data_counter - hstate->last_request_data_stamp < (uint64_t)UINT_MAX) - { - const uint32_t data_size = (uint32_t)( - (uint64_t)hstate->conn->in_data_counter - hstate->last_request_data_stamp); - const uint32_t depth = MIN(data_size, hstate->cfg->request.inspect_min_size); - - /* body still in progress, but due to min inspect size we need to inspect now */ - StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, depth); - AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER); - } - /* after the start of the body, disable the depth logic */ - } else if (tx_ud->request_body.body_inspected > 0) { - StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, 0); - } - } - SCReturnInt(HTP_OK); -} - -/** - * \brief Function callback to append chunks for Responses - * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib) - * \retval int HTP_OK if all goes well - */ -static int HTPCallbackResponseBodyData(htp_tx_data_t *d) -{ - SCEnter(); - - if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY)) - SCReturnInt(HTP_OK); - - if (d->len == 0) - SCReturnInt(HTP_OK); - - HtpState *hstate = htp_connp_get_user_data(d->tx->connp); - if (hstate == NULL) { - SCReturnInt(HTP_ERROR); - } - - SCLogDebug("New response body data available at %p -> %p -> %p, bodylen " - "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len); - - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx); - if (tx_ud == NULL) { - SCReturnInt(HTP_OK); - } - tx_ud->tx_data.file_flags |= hstate->state_data.file_flags; - if (!tx_ud->request_body_init) { - tx_ud->request_body_init = 1; - } - - /* see if we can get rid of htp body chunks */ - HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT); - - SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far); - SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit); - - /* within limits, add the body chunk to the state. */ - if (AppLayerHtpCheckDepth(&hstate->cfg->response, &tx_ud->response_body, tx_ud->tcflags)) { - uint32_t stream_depth = FileReassemblyDepth(); - uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->response_body.content_len_so_far, - hstate->cfg->response.body_limit, - stream_depth, - tx_ud->tcflags, - (uint32_t)d->len); - BUG_ON(len > (uint32_t)d->len); - - HtpBodyAppendChunk(&hstate->cfg->response, &tx_ud->response_body, d->data, len); - - HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, len); - } else { - if (tx_ud->tcflags & HTP_FILENAME_SET) { - SCLogDebug("closing file that was being stored"); - (void)HTPFileClose(hstate, tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT); - tx_ud->tcflags &= ~HTP_FILENAME_SET; - } - } - - if (hstate->conn != NULL) { - SCLogDebug("checking body size %"PRIu64" against inspect limit %u (cur %"PRIu64", last %"PRIu64")", - tx_ud->response_body.content_len_so_far, - hstate->cfg->response.inspect_min_size, - (uint64_t)hstate->conn->in_data_counter, hstate->last_response_data_stamp); - /* if we reach the inspect_min_size we'll trigger inspection, - * so make sure that raw stream is also inspected. Set the - * data to be used to the amount of raw bytes we've seen to - * get here. */ - if (tx_ud->response_body.body_inspected == 0 && - tx_ud->response_body.content_len_so_far >= hstate->cfg->response.inspect_min_size) { - if ((uint64_t)hstate->conn->out_data_counter > hstate->last_response_data_stamp && - (uint64_t)hstate->conn->out_data_counter - hstate->last_response_data_stamp < (uint64_t)UINT_MAX) - { - const uint32_t data_size = (uint32_t)((uint64_t)hstate->conn->out_data_counter - - hstate->last_response_data_stamp); - const uint32_t depth = MIN(data_size, hstate->cfg->response.inspect_min_size); - - /* body still in progress, but due to min inspect size we need to inspect now */ - StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, depth); - AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT); - } - /* after the start of the body, disable the depth logic */ - } else if (tx_ud->response_body.body_inspected > 0) { - StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, 0); - } - } - SCReturnInt(HTP_OK); -} - -/** - * \brief Print the stats of the HTTP requests - */ -void HTPAtExitPrintStats(void) -{ -#ifdef DEBUG - SCEnter(); - SCMutexLock(&htp_state_mem_lock); - SCLogDebug("http_state_memcnt %"PRIu64", http_state_memuse %"PRIu64"", - htp_state_memcnt, htp_state_memuse); - SCMutexUnlock(&htp_state_mem_lock); - SCReturn; -#endif -} - -/** \brief Clears the HTTP server configuration memory used by HTP library */ -void HTPFreeConfig(void) -{ - SCEnter(); - - if (!AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "http") || - !AppLayerParserConfParserEnabled("tcp", "http")) - { - SCReturn; - } - - HTPCfgRec *nextrec = cfglist.next; - SCRadixReleaseRadixTree(cfgtree); - cfgtree = NULL; - htp_config_destroy(cfglist.cfg); - while (nextrec != NULL) { - HTPCfgRec *htprec = nextrec; - nextrec = nextrec->next; - - htp_config_destroy(htprec->cfg); - SCFree(htprec); - } - SCReturn; -} - -static int HTPCallbackRequestHasTrailer(htp_tx_t *tx) -{ - HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (htud != NULL) { - htud->request_has_trailers = 1; - } - return HTP_OK; -} - -static int HTPCallbackResponseHasTrailer(htp_tx_t *tx) -{ - HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (htud != NULL) { - htud->response_has_trailers = 1; - } - return HTP_OK; -} - -/**\internal - * \brief called at start of request - * Set min inspect size. - */ -static int HTPCallbackRequestStart(htp_tx_t *tx) -{ - HtpState *hstate = htp_connp_get_user_data(tx->connp); - if (hstate == NULL) { - SCReturnInt(HTP_ERROR); - } - - uint64_t consumed = hstate->slice->offset + htp_connp_req_data_consumed(hstate->connp); - SCLogDebug("HTTP request start: data offset %" PRIu64 ", in_data_counter %" PRIu64, consumed, - (uint64_t)hstate->conn->in_data_counter); - - /* app-layer-frame-documentation tag start: frame registration http request */ - Frame *frame = AppLayerFrameNewByAbsoluteOffset( - hstate->f, hstate->slice, consumed, -1, 0, HTTP_FRAME_REQUEST); - if (frame) { - SCLogDebug("frame %p/%" PRIi64, frame, frame->id); - hstate->request_frame_id = frame->id; - AppLayerFrameSetTxId(frame, HtpGetActiveRequestTxID(hstate)); - } - /* app-layer-frame-documentation tag end: frame registration http request */ - - if (hstate->cfg) - StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, - hstate->cfg->request.inspect_min_size); - - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud == NULL) { - tx_ud = HTPCalloc(1, sizeof(HtpTxUserData)); - if (unlikely(tx_ud == NULL)) { - SCReturnInt(HTP_OK); - } - tx_ud->tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT; // each http tx may xfer files - htp_tx_set_user_data(tx, tx_ud); - } - SCReturnInt(HTP_OK); -} - -/**\internal - * \brief called at start of response - * Set min inspect size. - */ -static int HTPCallbackResponseStart(htp_tx_t *tx) -{ - HtpState *hstate = htp_connp_get_user_data(tx->connp); - if (hstate == NULL) { - SCReturnInt(HTP_ERROR); - } - - uint64_t consumed = hstate->slice->offset + htp_connp_res_data_consumed(hstate->connp); - SCLogDebug("HTTP response start: data offset %" PRIu64 ", out_data_counter %" PRIu64, consumed, - (uint64_t)hstate->conn->out_data_counter); - - Frame *frame = AppLayerFrameNewByAbsoluteOffset( - hstate->f, hstate->slice, consumed, -1, 1, HTTP_FRAME_RESPONSE); - if (frame) { - SCLogDebug("frame %p/%" PRIi64, frame, frame->id); - hstate->response_frame_id = frame->id; - AppLayerFrameSetTxId(frame, HtpGetActiveResponseTxID(hstate)); - } - - if (hstate->cfg) - StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, - hstate->cfg->response.inspect_min_size); - - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud == NULL) { - tx_ud = HTPCalloc(1, sizeof(HtpTxUserData)); - if (unlikely(tx_ud == NULL)) { - SCReturnInt(HTP_OK); - } - tx_ud->tx_data.file_tx = - STREAM_TOCLIENT; // each http tx may xfer files. Toserver already missed. - htp_tx_set_user_data(tx, tx_ud); - } - SCReturnInt(HTP_OK); -} - -/** - * \brief callback for request to store the recent incoming request - into the recent_in_tx for the given htp state - * \param connp pointer to the current connection parser which has the htp - * state in it as user data - */ -static int HTPCallbackRequestComplete(htp_tx_t *tx) -{ - SCEnter(); - - if (tx == NULL) { - SCReturnInt(HTP_ERROR); - } - - HtpState *hstate = htp_connp_get_user_data(tx->connp); - if (hstate == NULL) { - SCReturnInt(HTP_ERROR); - } - - const uint64_t abs_right_edge = - hstate->slice->offset + htp_connp_req_data_consumed(hstate->connp); - - /* app-layer-frame-documentation tag start: updating frame->len */ - if (hstate->request_frame_id > 0) { - Frame *frame = AppLayerFrameGetById(hstate->f, 0, hstate->request_frame_id); - if (frame) { - const uint64_t request_size = abs_right_edge - hstate->last_request_data_stamp; - - SCLogDebug("HTTP request complete: data offset %" PRIu64 ", request_size %" PRIu64, - hstate->last_request_data_stamp, request_size); - SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id, - request_size); - frame->len = (int64_t)request_size; - /* app-layer-frame-documentation tag end: updating frame->len */ - } - hstate->request_frame_id = 0; - } - - SCLogDebug("transaction_cnt %"PRIu64", list_size %"PRIu64, - hstate->transaction_cnt, HTPStateGetTxCnt(hstate)); - - SCLogDebug("HTTP request completed"); - - HTPErrorCheckTxRequestFlags(hstate, tx); - - HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (htud != NULL) { - if (htud->tsflags & HTP_FILENAME_SET) { - SCLogDebug("closing file that was being stored"); - (void)HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOSERVER); - htud->tsflags &= ~HTP_FILENAME_SET; - if (abs_right_edge < (uint64_t)UINT32_MAX) { - StreamTcpReassemblySetMinInspectDepth( - hstate->f->protoctx, STREAM_TOSERVER, (uint32_t)abs_right_edge); - } - } - } - - hstate->last_request_data_stamp = abs_right_edge; - /* request done, do raw reassembly now to inspect state and stream - * at the same time. */ - AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER); - SCReturnInt(HTP_OK); -} - -/** - * \brief callback for response to remove the recent received requests - from the recent_in_tx for the given htp state - * \param connp pointer to the current connection parser which has the htp - * state in it as user data - */ -static int HTPCallbackResponseComplete(htp_tx_t *tx) -{ - SCEnter(); - - HtpState *hstate = htp_connp_get_user_data(tx->connp); - if (hstate == NULL) { - SCReturnInt(HTP_ERROR); - } - - /* we have one whole transaction now */ - hstate->transaction_cnt++; - - const uint64_t abs_right_edge = - hstate->slice->offset + htp_connp_res_data_consumed(hstate->connp); - - if (hstate->response_frame_id > 0) { - Frame *frame = AppLayerFrameGetById(hstate->f, 1, hstate->response_frame_id); - if (frame) { - const uint64_t response_size = abs_right_edge - hstate->last_response_data_stamp; - - SCLogDebug("HTTP response complete: data offset %" PRIu64 ", response_size %" PRIu64, - hstate->last_response_data_stamp, response_size); - SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id, - response_size); - frame->len = (int64_t)response_size; - } - hstate->response_frame_id = 0; - } - - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - if (htud->tcflags & HTP_FILENAME_SET) { - SCLogDebug("closing file that was being stored"); - (void)HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOCLIENT); - htud->tcflags &= ~HTP_FILENAME_SET; - } - } - - /* response done, do raw reassembly now to inspect state and stream - * at the same time. */ - AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT); - - /* handle HTTP CONNECT */ - if (tx->request_method_number == HTP_M_CONNECT) { - /* any 2XX status response implies that the connection will become - a tunnel immediately after this packet (RFC 7230, 3.3.3). */ - if ((tx->response_status_number >= 200) && - (tx->response_status_number < 300) && - (hstate->transaction_cnt == 1)) { - uint16_t dp = 0; - if (tx->request_port_number != -1) { - dp = (uint16_t)tx->request_port_number; - } - // both ALPROTO_HTTP1 and ALPROTO_TLS are normal options - if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_UNKNOWN)) { - HTPSetEvent( - hstate, htud, STREAM_TOCLIENT, HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE); - } - tx->request_progress = HTP_REQUEST_COMPLETE; - tx->response_progress = HTP_RESPONSE_COMPLETE; - } - } - - hstate->last_response_data_stamp = abs_right_edge; - SCReturnInt(HTP_OK); -} - -static int HTPCallbackRequestLine(htp_tx_t *tx) -{ - HtpTxUserData *tx_ud; - bstr *request_uri_normalized; - HtpState *hstate = htp_connp_get_user_data(tx->connp); - const HTPCfgRec *cfg = hstate->cfg; - - request_uri_normalized = SCHTPGenerateNormalizedUri(tx, tx->parsed_uri, cfg->uri_include_all); - if (request_uri_normalized == NULL) - return HTP_OK; - - tx_ud = htp_tx_get_user_data(tx); - if (unlikely(tx_ud == NULL)) { - bstr_free(request_uri_normalized); - return HTP_OK; - } - if (unlikely(tx_ud->request_uri_normalized != NULL)) - bstr_free(tx_ud->request_uri_normalized); - tx_ud->request_uri_normalized = request_uri_normalized; - - if (tx->flags) { - HTPErrorCheckTxRequestFlags(hstate, tx); - } - return HTP_OK; -} - -static int HTPCallbackDoubleDecodeUriPart(htp_tx_t *tx, bstr *part) -{ - if (part == NULL) - return HTP_OK; - - uint64_t flags = 0; - size_t prevlen = bstr_len(part); - htp_status_t res = htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, part, &flags); - // shorter string means that uri was encoded - if (res == HTP_OK && prevlen > bstr_len(part)) { - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud == NULL) - return HTP_OK; - HtpState *s = htp_connp_get_user_data(tx->connp); - if (s == NULL) - return HTP_OK; - HTPSetEvent(s, htud, STREAM_TOSERVER, - HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI); - } - - return HTP_OK; -} - -static int HTPCallbackDoubleDecodeQuery(htp_tx_t *tx) -{ - if (tx->parsed_uri == NULL) - return HTP_OK; - - return HTPCallbackDoubleDecodeUriPart(tx, tx->parsed_uri->query); -} - -static int HTPCallbackDoubleDecodePath(htp_tx_t *tx) -{ - if (tx->parsed_uri == NULL) - return HTP_OK; - - return HTPCallbackDoubleDecodeUriPart(tx, tx->parsed_uri->path); -} - -static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) -{ - void *ptmp; - if (tx_data->len == 0 || tx_data->tx == NULL) - return HTP_OK; - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); - if (tx_ud == NULL) { - return HTP_OK; - } - ptmp = HTPRealloc(tx_ud->request_headers_raw, - tx_ud->request_headers_raw_len, - tx_ud->request_headers_raw_len + tx_data->len); - if (ptmp == NULL) { - return HTP_OK; - } - tx_ud->request_headers_raw = ptmp; - - memcpy(tx_ud->request_headers_raw + tx_ud->request_headers_raw_len, - tx_data->data, tx_data->len); - tx_ud->request_headers_raw_len += tx_data->len; - - if (tx_data->tx && tx_data->tx->flags) { - HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); - HTPErrorCheckTxRequestFlags(hstate, tx_data->tx); - } - return HTP_OK; -} - -static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) -{ - void *ptmp; - if (tx_data->len == 0 || tx_data->tx == NULL) - return HTP_OK; - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); - if (tx_ud == NULL) { - return HTP_OK; - } - ptmp = HTPRealloc(tx_ud->response_headers_raw, - tx_ud->response_headers_raw_len, - tx_ud->response_headers_raw_len + tx_data->len); - if (ptmp == NULL) { - return HTP_OK; - } - tx_ud->response_headers_raw = ptmp; - - memcpy(tx_ud->response_headers_raw + tx_ud->response_headers_raw_len, - tx_data->data, tx_data->len); - tx_ud->response_headers_raw_len += tx_data->len; - - return HTP_OK; -} - -/* - * We have a similar set function called HTPConfigSetDefaultsPhase1. - */ -static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) -{ - cfg_prec->uri_include_all = false; - cfg_prec->request.body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT; - cfg_prec->response.body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT; - cfg_prec->request.inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE; - cfg_prec->request.inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; - cfg_prec->response.inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; - cfg_prec->response.inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; - - if (!g_disable_randomness) { - cfg_prec->randomize = HTP_CONFIG_DEFAULT_RANDOMIZE; - } else { - cfg_prec->randomize = 0; - } - cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE; - - htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); - htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); - htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); - htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); - - htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer); - htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer); - - htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData); - htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData); - - htp_config_register_request_start(cfg_prec->cfg, HTPCallbackRequestStart); - htp_config_register_request_complete(cfg_prec->cfg, HTPCallbackRequestComplete); - - htp_config_register_response_start(cfg_prec->cfg, HTPCallbackResponseStart); - htp_config_register_response_complete(cfg_prec->cfg, HTPCallbackResponseComplete); - - htp_config_set_parse_request_cookies(cfg_prec->cfg, 0); - - /* don't convert + to space by default */ - htp_config_set_plusspace_decode(cfg_prec->cfg, HTP_DECODER_URLENCODED, 0); - // enables request decompression - htp_config_set_request_decompression(cfg_prec->cfg, 1); -#ifdef HAVE_HTP_CONFIG_SET_LZMA_LAYERS - // disable by default - htp_config_set_lzma_layers(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_LAYERS); -#endif -#ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT - htp_config_set_lzma_memlimit(cfg_prec->cfg, - HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT); -#endif -#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT - htp_config_set_compression_bomb_limit(cfg_prec->cfg, - HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT); -#endif -#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT - htp_config_set_compression_time_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT); -#endif - /* libhtp <= 0.5.9 doesn't use soft limit, but it's impossible to set - * only the hard limit. So we set both here to the (current) htp defaults. - * The reason we do this is that if the user sets the hard limit in the - * config, we have to set the soft limit as well. If libhtp starts using - * the soft limit in the future, we at least make sure we control what - * it's value is. */ - htp_config_set_field_limits(cfg_prec->cfg, - (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT, - (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_HARD); - return; -} - -/* hack: htp random range code expects random values in range of 0-RAND_MAX, - * but we can get both <0 and >RAND_MAX values from RandomGet - */ -static int RandomGetWrap(void) -{ - unsigned long r; - - do { - r = RandomGet(); - } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX)); - - return r % RAND_MAX; -} - -/* - * We have this splitup so that in case double decoding has been enabled - * for query and path, they would be called first on the callback queue, - * before the callback set by Phase2() is called. We need this, since - * the callback in Phase2() generates the normalized uri which utilizes - * the query and path. */ -static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec) -{ - /* randomize inspection size if needed */ - if (cfg_prec->randomize) { - int rdrange = cfg_prec->randomize_range; - - long int r = RandomGetWrap(); - cfg_prec->request.inspect_min_size += (int)(cfg_prec->request.inspect_min_size * - ((double)r / RAND_MAX - 0.5) * rdrange / 100); - - r = RandomGetWrap(); - cfg_prec->request.inspect_window += (int)(cfg_prec->request.inspect_window * - ((double)r / RAND_MAX - 0.5) * rdrange / 100); - SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to" - " %u and 'request-body-inspect-window' set to %u after" - " randomization.", - name, cfg_prec->request.inspect_min_size, cfg_prec->request.inspect_window); - - r = RandomGetWrap(); - cfg_prec->response.inspect_min_size += (int)(cfg_prec->response.inspect_min_size * - ((double)r / RAND_MAX - 0.5) * rdrange / 100); - - r = RandomGetWrap(); - cfg_prec->response.inspect_window += (int)(cfg_prec->response.inspect_window * - ((double)r / RAND_MAX - 0.5) * rdrange / 100); - - SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to" - " %u and 'response-body-inspect-window' set to %u after" - " randomization.", - name, cfg_prec->response.inspect_min_size, cfg_prec->response.inspect_window); - } - - htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine); - return; -} - -static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, - SCRadixTree *tree) -{ - if (cfg_prec == NULL || s == NULL || tree == NULL) - return; - - ConfNode *p = NULL; - - /* Default Parameters */ - TAILQ_FOREACH(p, &s->head, next) { - - if (strcasecmp("address", p->name) == 0) { - ConfNode *pval; - /* Addresses */ - TAILQ_FOREACH(pval, &p->head, next) { - SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, - pval->val); - - /* IPV6 or IPV4? */ - if (strchr(pval->val, ':') != NULL) { - SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p", - s->name, pval->val, cfg_prec->cfg); - if (!SCRadixAddKeyIPV6String(pval->val, tree, cfg_prec)) { - SCLogWarning("LIBHTP failed to " - "add ipv6 server %s, ignoring", - pval->val); - } - } else { - SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p", - s->name, pval->val, cfg_prec->cfg); - if (!SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec)) { - SCLogWarning("LIBHTP failed " - "to add ipv4 server %s, ignoring", - pval->val); - } - } /* else - if (strchr(pval->val, ':') != NULL) */ - } /* TAILQ_FOREACH(pval, &p->head, next) */ - - } else if (strcasecmp("personality", p->name) == 0) { - /* Personalities */ - int personality = HTPLookupPersonality(p->val); - SCLogDebug("LIBHTP default: %s = %s", p->name, p->val); - SCLogDebug("LIBHTP default: %s = %s", p->name, p->val); - - if (personality >= 0) { - SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val, - personality); - if (htp_config_set_server_personality(cfg_prec->cfg, personality) == HTP_ERROR){ - SCLogWarning("LIBHTP Failed adding " - "personality \"%s\", ignoring", - p->val); - } else { - SCLogDebug("LIBHTP personality set to %s", - HTPLookupPersonalityString(personality)); - } - - /* The IDS personality by default converts the path (and due to - * our query string callback also the query string) to lowercase. - * Signatures do not expect this, so override it. */ - htp_config_set_convert_lowercase(cfg_prec->cfg, HTP_DECODER_URL_PATH, 0); - } else { - SCLogWarning("LIBHTP Unknown personality " - "\"%s\", ignoring", - p->val); - continue; - } - - } else if (strcasecmp("request-body-limit", p->name) == 0 || - strcasecmp("request_body_limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) { - SCLogError("Error parsing request-body-limit " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - - } else if (strcasecmp("response-body-limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) { - SCLogError("Error parsing response-body-limit " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - - } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) { - SCLogError("Error parsing request-body-minimal-inspect-size " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - - } else if (strcasecmp("request-body-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) { - SCLogError("Error parsing request-body-inspect-window " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - - } else if (strcasecmp("double-decode-query", p->name) == 0) { - if (ConfValIsTrue(p->val)) { - htp_config_register_request_line(cfg_prec->cfg, - HTPCallbackDoubleDecodeQuery); - } - - } else if (strcasecmp("double-decode-path", p->name) == 0) { - if (ConfValIsTrue(p->val)) { - htp_config_register_request_line(cfg_prec->cfg, - HTPCallbackDoubleDecodePath); - } - - } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) { - SCLogError("Error parsing response-body-minimal-inspect-size " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - - } else if (strcasecmp("response-body-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) { - SCLogError("Error parsing response-body-inspect-window " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - - } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) { - uint32_t value = 2; - if (ParseSizeStringU32(p->val, &value) < 0) { - SCLogError("Error parsing response-body-inspect-window " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } -#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT - htp_config_set_response_decompression_layer_limit(cfg_prec->cfg, value); -#else - SCLogWarning("can't set response-body-decompress-layer-limit " - "to %u, libhtp version too old", - value); -#endif - } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) { - htp_config_set_backslash_convert_slashes(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) { - if (strlen(p->val) == 1) { - htp_config_set_bestfit_replacement_byte(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - p->val[0]); - } else { - SCLogError("Invalid entry " - "for libhtp param path-bestfit-replacement-char"); - } - } else if (strcasecmp("path-convert-lowercase", p->name) == 0) { - htp_config_set_convert_lowercase(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) { - htp_config_set_nul_encoded_terminates(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) { - htp_config_set_nul_raw_terminates(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("path-separators-compress", p->name) == 0) { - htp_config_set_path_separators_compress(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("path-separators-decode", p->name) == 0) { - htp_config_set_path_separators_decode(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) { - htp_config_set_u_encoding_decode(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) { - enum htp_url_encoding_handling_t handling; - if (strcasecmp(p->val, "preserve_percent") == 0) { - handling = HTP_URL_DECODE_PRESERVE_PERCENT; - } else if (strcasecmp(p->val, "remove_percent") == 0) { - handling = HTP_URL_DECODE_REMOVE_PERCENT; - } else if (strcasecmp(p->val, "decode_invalid") == 0) { - handling = HTP_URL_DECODE_PROCESS_INVALID; - } else { - SCLogError("Invalid entry " - "for libhtp param path-url-encoding-invalid-handling"); - return; - } - htp_config_set_url_encoding_invalid_handling(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - handling); - } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) { - htp_config_set_utf8_convert_bestfit(cfg_prec->cfg, - HTP_DECODER_URL_PATH, - ConfValIsTrue(p->val)); - } else if (strcasecmp("uri-include-all", p->name) == 0) { - cfg_prec->uri_include_all = (1 == ConfValIsTrue(p->val)); - SCLogDebug("uri-include-all %s", - cfg_prec->uri_include_all ? "enabled" : "disabled"); - } else if (strcasecmp("query-plusspace-decode", p->name) == 0) { - htp_config_set_plusspace_decode(cfg_prec->cfg, - HTP_DECODER_URLENCODED, - ConfValIsTrue(p->val)); - } else if (strcasecmp("meta-field-limit", p->name) == 0) { - uint32_t limit = 0; - if (ParseSizeStringU32(p->val, &limit) < 0) { - SCLogError("Error meta-field-limit " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - if (limit == 0) { - FatalError("Error meta-field-limit " - "from conf file cannot be 0. Killing engine"); - } - /* set default soft-limit with our new hard limit */ - htp_config_set_field_limits(cfg_prec->cfg, - (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT, - (size_t)limit); -#ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT - } else if (strcasecmp("lzma-memlimit", p->name) == 0) { - uint32_t limit = 0; - if (ParseSizeStringU32(p->val, &limit) < 0) { - FatalError("failed to parse 'lzma-memlimit' " - "from conf file - %s.", - p->val); - } - if (limit == 0) { - FatalError("'lzma-memlimit' " - "from conf file cannot be 0."); - } - /* set default soft-limit with our new hard limit */ - SCLogConfig("Setting HTTP LZMA memory limit to %"PRIu32" bytes", limit); - htp_config_set_lzma_memlimit(cfg_prec->cfg, (size_t)limit); -#endif -#ifdef HAVE_HTP_CONFIG_SET_LZMA_LAYERS - } else if (strcasecmp("lzma-enabled", p->name) == 0) { - if (ConfValIsTrue(p->val)) { - htp_config_set_lzma_layers(cfg_prec->cfg, 1); - } else if (!ConfValIsFalse(p->val)) { - int8_t limit; - if (StringParseInt8(&limit, 10, 0, (const char *)p->val) < 0) { - FatalError("failed to parse 'lzma-enabled' " - "from conf file - %s.", - p->val); - } - SCLogConfig("Setting HTTP LZMA decompression layers to %" PRIu32 "", (int)limit); - htp_config_set_lzma_layers(cfg_prec->cfg, limit); - } -#endif -#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT - } else if (strcasecmp("compression-bomb-limit", p->name) == 0) { - uint32_t limit = 0; - if (ParseSizeStringU32(p->val, &limit) < 0) { - FatalError("failed to parse 'compression-bomb-limit' " - "from conf file - %s.", - p->val); - } - if (limit == 0) { - FatalError("'compression-bomb-limit' " - "from conf file cannot be 0."); - } - /* set default soft-limit with our new hard limit */ - SCLogConfig("Setting HTTP compression bomb limit to %"PRIu32" bytes", limit); - htp_config_set_compression_bomb_limit(cfg_prec->cfg, (size_t)limit); -#endif -#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT - } else if (strcasecmp("decompression-time-limit", p->name) == 0) { - uint32_t limit = 0; - // between 1 usec and 1 second - if (StringParseU32RangeCheck(&limit, 10, 0, p->val, 1, 1000000) < 0) { - FatalError("failed to parse 'decompression-time-limit' " - "from conf file - %s.", - p->val); - } - SCLogConfig("Setting HTTP decompression time limit to %" PRIu32 " usec", limit); - htp_config_set_compression_time_limit(cfg_prec->cfg, (size_t)limit); -#endif - } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) { - if (!g_disable_randomness) { - cfg_prec->randomize = ConfValIsTrue(p->val); - } - } else if (strcasecmp("randomize-inspection-range", p->name) == 0) { - uint32_t range; - if (StringParseU32RangeCheck(&range, 10, 0, - (const char *)p->val, 0, 100) < 0) { - SCLogError("Invalid value for randomize" - "-inspection-range setting from conf file - \"%s\"." - " It should be a valid integer less than or equal to 100." - " Killing engine", - p->val); - exit(EXIT_FAILURE); - } - cfg_prec->randomize_range = range; - } else if (strcasecmp("http-body-inline", p->name) == 0) { - if (ConfValIsTrue(p->val)) { - cfg_prec->http_body_inline = 1; - } else if (ConfValIsFalse(p->val)) { - cfg_prec->http_body_inline = 0; - } else { - if (strcmp("auto", p->val) != 0) { - WarnInvalidConfEntry("http_body_inline", "%s", "auto"); - } - if (EngineModeIsIPS()) { - cfg_prec->http_body_inline = 1; - } else { - cfg_prec->http_body_inline = 0; - } - } - } else if (strcasecmp("swf-decompression", p->name) == 0) { - ConfNode *pval; - - TAILQ_FOREACH(pval, &p->head, next) { - if (strcasecmp("enabled", pval->name) == 0) { - if (ConfValIsTrue(pval->val)) { - cfg_prec->swf_decompression_enabled = 1; - SCLogWarning("Flash decompression is deprecated and will be removed in " - "Suricata 8; see ticket #6179"); - } else if (ConfValIsFalse(pval->val)) { - cfg_prec->swf_decompression_enabled = 0; - } else { - WarnInvalidConfEntry("swf-decompression.enabled", "%s", "no"); - } - } else if (strcasecmp("type", pval->name) == 0) { - if (strcasecmp("no", pval->val) == 0) { - cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_NONE; - } else if (strcasecmp("deflate", pval->val) == 0) { - cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_ZLIB; - } else if (strcasecmp("lzma", pval->val) == 0) { - cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_LZMA; - } else if (strcasecmp("both", pval->val) == 0) { - cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_BOTH; - } else { - SCLogError("Invalid entry for " - "swf-decompression.type: %s - " - "Killing engine", - pval->val); - exit(EXIT_FAILURE); - } - } else if (strcasecmp("compress-depth", pval->name) == 0) { - if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) { - SCLogError("Error parsing swf-decompression.compression-depth " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - } else if (strcasecmp("decompress-depth", pval->name) == 0) { - if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) { - SCLogError("Error parsing swf-decompression.decompression-depth " - "from conf file - %s. Killing engine", - p->val); - exit(EXIT_FAILURE); - } - } else { - SCLogWarning("Ignoring unknown param %s", pval->name); - } - } - } else { - SCLogWarning("LIBHTP Ignoring unknown " - "default config: %s", - p->name); - } - } /* TAILQ_FOREACH(p, &default_config->head, next) */ - - return; -} - -void HTPConfigure(void) -{ - SCEnter(); - - cfglist.next = NULL; - - htp_sbcfg.Calloc = HTPCalloc; - htp_sbcfg.Realloc = HTPRealloc; - htp_sbcfg.Free = HTPFree; - - cfgtree = SCRadixCreateRadixTree(NULL, NULL); - if (NULL == cfgtree) - exit(EXIT_FAILURE); - - /* Default Config */ - cfglist.cfg = htp_config_create(); - if (NULL == cfglist.cfg) { - FatalError("Failed to create HTP default config"); - } - SCLogDebug("LIBHTP default config: %p", cfglist.cfg); - HTPConfigSetDefaultsPhase1(&cfglist); - if (ConfGetNode("app-layer.protocols.http.libhtp") == NULL) { - HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"), - cfgtree); - } else { - HTPConfigParseParameters(&cfglist, ConfGetNode("app-layer.protocols.http.libhtp.default-config"), cfgtree); - } - HTPConfigSetDefaultsPhase2("default", &cfglist); - - HTPParseMemcap(); - - /* Read server config and create a parser for each IP in radix tree */ - ConfNode *server_config = ConfGetNode("app-layer.protocols.http.libhtp.server-config"); - if (server_config == NULL) { - server_config = ConfGetNode("libhtp.server-config"); - if (server_config == NULL) { - SCLogDebug("LIBHTP Configuring %p", server_config); - SCReturn; - } - } - SCLogDebug("LIBHTP Configuring %p", server_config); - - ConfNode *si; - /* Server Nodes */ - TAILQ_FOREACH(si, &server_config->head, next) { - /* Need the named node, not the index */ - ConfNode *s = TAILQ_FIRST(&si->head); - if (NULL == s) { - SCLogDebug("LIBHTP s NULL"); - continue; - } - - SCLogDebug("LIBHTP server %s", s->name); - - HTPCfgRec *nextrec = cfglist.next; - HTPCfgRec *htprec = SCCalloc(1, sizeof(HTPCfgRec)); - if (NULL == htprec) - exit(EXIT_FAILURE); - - cfglist.next = htprec; - - cfglist.next->next = nextrec; - cfglist.next->cfg = htp_config_create(); - if (NULL == cfglist.next->cfg) { - FatalError("Failed to create HTP server config"); - } - - HTPConfigSetDefaultsPhase1(htprec); - HTPConfigParseParameters(htprec, s, cfgtree); - HTPConfigSetDefaultsPhase2(s->name, htprec); - } - - SCReturn; -} - -void AppLayerHtpPrintStats(void) -{ -#ifdef DEBUG - SCMutexLock(&htp_state_mem_lock); - SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); - SCMutexUnlock(&htp_state_mem_lock); -#endif -} - -/** \internal - * \brief get files callback - * \param state state ptr - * \param direction flow direction - * \retval files files ptr - */ -static AppLayerGetFileState HTPGetTxFiles(void *state, void *txv, uint8_t direction) -{ - AppLayerGetFileState files = { .fc = NULL, .cfg = &htp_sbcfg }; - htp_tx_t *tx = (htp_tx_t *)txv; - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud) { - if (direction & STREAM_TOCLIENT) { - files.fc = &tx_ud->files_tc; - } else { - files.fc = &tx_ud->files_ts; - } - } - return files; -} - -static int HTPStateGetAlstateProgress(void *tx, uint8_t direction) -{ - if (direction & STREAM_TOSERVER) - return ((htp_tx_t *)tx)->request_progress; - else - return ((htp_tx_t *)tx)->response_progress; -} - -static uint64_t HTPStateGetTxCnt(void *alstate) -{ - HtpState *http_state = (HtpState *)alstate; - - if (http_state != NULL && http_state->conn != NULL) { - const int64_t size = (int64_t)htp_list_size(http_state->conn->transactions); - if (size < 0) - return 0ULL; - SCLogDebug("size %"PRIu64, size); - return (uint64_t)size; - } else { - return 0ULL; - } -} - -static void *HTPStateGetTx(void *alstate, uint64_t tx_id) -{ - HtpState *http_state = (HtpState *)alstate; - - if (http_state != NULL && http_state->conn != NULL) - return htp_list_get(http_state->conn->transactions, tx_id); - else - return NULL; -} - -void *HtpGetTxForH2(void *alstate) -{ - // gets last transaction - HtpState *http_state = (HtpState *)alstate; - if (http_state != NULL && http_state->conn != NULL) { - size_t txid = htp_list_array_size(http_state->conn->transactions); - if (txid > 0) { - return htp_list_get(http_state->conn->transactions, txid - 1); - } - } - return NULL; -} - -static int HTPStateGetEventInfo(const char *event_name, - int *event_id, AppLayerEventType *event_type) -{ - *event_id = SCMapEnumNameToValue(event_name, http_decoder_event_table); - if (*event_id == -1) { - SCLogError("event \"%s\" not present in " - "http's enum map table.", - event_name); - /* this should be treated as fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static int HTPStateGetEventInfoById(int event_id, const char **event_name, - AppLayerEventType *event_type) -{ - *event_name = SCMapEnumValueToName(event_id, http_decoder_event_table); - if (*event_name == NULL) { - SCLogError("event \"%d\" not present in " - "http's enum map table.", - event_id); - /* this should be treated as fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static AppLayerTxData *HTPGetTxData(void *vtx) -{ - htp_tx_t *tx = (htp_tx_t *)vtx; - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud) { - return &tx_ud->tx_data; - } - return NULL; -} - -static AppLayerStateData *HTPGetStateData(void *vstate) -{ - HtpState *s = vstate; - return &s->state_data; -} - -static int HTPRegisterPatternsForProtocolDetection(void) -{ - const char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS", - "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", - "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN", - "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE", - "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL}; - const char *spacings[] = { "|20|", "|09|", NULL }; - const char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL }; - - int methods_pos; - int spacings_pos; - int versions_pos; - int register_result; - char method_buffer[32] = ""; - - /* Loop through all the methods ands spacings and register the patterns */ - for (methods_pos = 0; methods[methods_pos]; methods_pos++) { - for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) { - - /* Combine the method name and the spacing */ - snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]); - - /* Register the new method+spacing pattern - * 3 is subtracted from the length since the spacing is hex typed as |xx| - * but the pattern matching should only be one char - */ - register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1, - method_buffer, (uint16_t)strlen(method_buffer) - 3, 0, STREAM_TOSERVER); - if (register_result < 0) { - return -1; - } - } - } - - /* Loop through all the http version patterns that are TO_CLIENT */ - for (versions_pos = 0; versions[versions_pos]; versions_pos++) { - register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1, - versions[versions_pos], (uint16_t)strlen(versions[versions_pos]), 0, - STREAM_TOCLIENT); - if (register_result < 0) { - return -1; - } - } - - return 0; -} - -/** - * \brief Register the HTTP protocol and state handling functions to APP layer - * of the engine. - */ -void RegisterHTPParsers(void) -{ - SCEnter(); - - const char *proto_name = "http"; - - /** HTTP */ - if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP1, proto_name); - if (HTPRegisterPatternsForProtocolDetection() < 0) - return; - } else { - SCLogInfo("Protocol detection and parser disabled for %s protocol", - proto_name); - return; - } - - if (AppLayerParserConfParserEnabled("tcp", proto_name)) { - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateAlloc, HTPStateFree); - AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateTransactionFree); - AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxFiles); - AppLayerParserRegisterGetStateProgressFunc( - IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetAlstateProgress); - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTxCnt); - AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTx); - - AppLayerParserRegisterStateProgressCompletionStatus( - ALPROTO_HTTP1, HTP_REQUEST_COMPLETE, HTP_RESPONSE_COMPLETE); - AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfo); - AppLayerParserRegisterGetEventInfoById( - IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfoById); - - AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxData); - AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetStateData); - - AppLayerParserRegisterSetStreamDepthFlag( - IPPROTO_TCP, ALPROTO_HTTP1, AppLayerHtpSetStreamDepthFlag); - - AppLayerParserRegisterParser( - IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER, HTPHandleRequestData); - AppLayerParserRegisterParser( - IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOCLIENT, HTPHandleResponseData); - SC_ATOMIC_INIT(htp_config_flags); - /* This parser accepts gaps. */ - AppLayerParserRegisterOptionFlags( - IPPROTO_TCP, ALPROTO_HTTP1, APP_LAYER_PARSER_OPT_ACCEPT_GAPS); - AppLayerParserRegisterParserAcceptableDataDirection( - IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_TOCLIENT); - /* app-layer-frame-documentation tag start: registering relevant callbacks */ - AppLayerParserRegisterGetFrameFuncs( - IPPROTO_TCP, ALPROTO_HTTP1, HTTPGetFrameIdByName, HTTPGetFrameNameById); - /* app-layer-frame-documentation tag end: registering relevant callbacks */ - HTPConfigure(); - } else { - SCLogInfo("Parsed disabled for %s protocol. Protocol detection" - "still on.", proto_name); - } -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP1, HTPParserRegisterTests); -#endif - - SCReturn; -} - -#ifdef UNITTESTS -#include "detect-engine-alert.h" - -static HTPCfgRec cfglist_backup; - -void HtpConfigCreateBackup(void) -{ - cfglist_backup = cfglist; - - return; -} - -void HtpConfigRestoreBackup(void) -{ - cfglist = cfglist_backup; - - return; -} - -/** \test Test case where chunks are sent in smaller chunks and check the - * response of the parser from HTP library. */ -static int HTPParserTest01(void) -{ - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" - " Data is c0oL!"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - TcpSession ssn; - memset(&ssn, 0, sizeof(ssn)); - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - FAIL_IF(r != 0); - } - - HtpState *htp_state = f->alstate; - FAIL_IF_NULL(htp_state); - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - FAIL_IF_NULL(tx); - - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")); - FAIL_IF(tx->request_method_number != HTP_M_POST); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test folding in 1 read case */ -static int HTPParserTest01b(void) -{ - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost" - " Data is c0oL!"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - TcpSession ssn; - memset(&ssn, 0, sizeof(ssn)); - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint8_t flags =STREAM_TOSERVER|STREAM_START|STREAM_EOF; - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1); - FAIL_IF(r != 0); - - HtpState *htp_state = f->alstate; - FAIL_IF_NULL(htp_state); - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - FAIL_IF_NULL(tx); - - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")); - FAIL_IF(tx->request_method_number != HTP_M_POST); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test folding in 1byte per read case */ -static int HTPParserTest01c(void) -{ - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost" - " Data is c0oL!"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - TcpSession ssn; - memset(&ssn, 0, sizeof(ssn)); - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - FAIL_IF(r != 0); - } - - HtpState *htp_state = f->alstate; - FAIL_IF_NULL(htp_state); - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - FAIL_IF_NULL(tx); - - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")); - FAIL_IF(tx->request_method_number != HTP_M_POST); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test case where chunks are sent in smaller chunks and check the - * response of the parser from HTP library. */ -static int HTPParserTest01a(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" - " Data is c0oL!"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - if (strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0") - || tx->request_method_number != HTP_M_POST || - tx->request_protocol_number != HTP_PROTOCOL_1_0) - { - printf("expected header value: Victor/1.0 and got %s: and expected" - " method: POST and got %s, expected protocol number HTTP/1.0" - " and got: %s \n", bstr_util_strdup_to_c(h->value), - bstr_util_strdup_to_c(tx->request_method), - bstr_util_strdup_to_c(tx->request_protocol)); - goto end; - } - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test See how it deals with an incomplete request. */ -static int HTPParserTest02(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "POST"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, - STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - http_state = f->alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NOT_NULL(h); - - FAIL_IF_NULL(tx->request_method); - char *method = bstr_util_strdup_to_c(tx->request_method); - FAIL_IF_NULL(method); - - FAIL_IF(strcmp(method, "POST") != 0); - SCFree(method); - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test case where method is invalid and data is sent in smaller chunks - * and check the response of the parser from HTP library. */ -static int HTPParserTest03(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - if (tx->request_method_number != HTP_M_UNKNOWN || - h != NULL || tx->request_protocol_number != HTP_PROTOCOL_1_0) - { - printf("expected method M_UNKNOWN and got %s: , expected protocol " - "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method), - bstr_util_strdup_to_c(tx->request_protocol)); - goto end; - } - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test case where invalid data is sent and check the response of the - * parser from HTP library. */ -static int HTPParserTest04(void) -{ - int result = 0; - Flow *f = NULL; - HtpState *htp_state = NULL; - uint8_t httpbuf1[] = "World!\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, - STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1); - if (r != 0) { - goto end; - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - if (tx->request_method_number != HTP_M_UNKNOWN || - h != NULL || tx->request_protocol_number != HTP_PROTOCOL_0_9) - { - printf("expected method M_UNKNOWN and got %s: , expected protocol " - "NULL and got %s \n", bstr_util_strdup_to_c(tx->request_method), - bstr_util_strdup_to_c(tx->request_protocol)); - goto end; - } - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test both sides of a http stream mixed up to see if the HTP parser - * properly parsed them and also keeps them separated. */ -static int HTPParserTest05(void) -{ - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\nContent-Length: 17\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "Post D"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - uint8_t httpbuf3[] = "ata is c0oL!"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - - uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - uint8_t httpbuf5[] = "post R"; - uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ - uint8_t httpbuf6[] = "esults are tha bomb!"; - uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ - - TcpSession ssn; - memset(&ssn, 0, sizeof(ssn)); - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4); - FAIL_IF(r != 0); - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf5, httplen5); - FAIL_IF(r != 0); - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6); - FAIL_IF(r != 0); - - HtpState *http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF_NOT(tx->request_method_number == HTP_M_POST); - FAIL_IF_NOT(tx->request_protocol_number == HTP_PROTOCOL_1_0); - - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF_NOT(tx->response_status_number == 200); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test proper chunked encoded response body - */ -static int HTPParserTest06(void) -{ - uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" - "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " - "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 " - "GMT\r\n" - "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 " - "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 " - "FrontPage/5.0.2.2510\r\n" - "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: " - "chunked\r\n" - "Content-Type: text/html\r\n\r\n" - "580\r\n" - "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu" - "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN" - "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N" - "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk" - "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l" - "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN" - "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt" - "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz" - "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw" - "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps" - "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw" - "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9" - "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N" - "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu" - "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3" - "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo" - "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv" - "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh" - "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5" - "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx" - "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y" - "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv" - "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv" - "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n" - "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt" - "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N" - "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w" - "aHA=\r\n0\r\n\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - TcpSession ssn; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF(r != 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); - FAIL_IF(r != 0); - - HtpState *http_state = f->alstate; - FAIL_IF_NULL(http_state); - - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - - FAIL_IF(tx->request_method_number != HTP_M_GET); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - FAIL_IF(tx->response_status_number != 200); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test - */ -static int HTPParserTest07(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref[] = "/awstats.pl?/migratemigrate = |"; - size_t reflen = sizeof(ref) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref, reflen); - printf("\": "); - goto end; - } - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -#include "conf-yaml-loader.h" - -/** \test Abort - */ -static int HTPParserTest08(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - HtpState *htp_state = NULL; - int r = 0; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint8_t flags = 0; - flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk returned %" PRId32 ", expected" - " 0: ", r); - result = 0; - goto end; - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - //printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized)); - PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized)); - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - UTHFreeFlow(f); - return result; -} - -/** \test Abort - */ -static int HTPParserTest09(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: Apache_2_2\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - HtpState *htp_state = NULL; - int r = 0; - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint8_t flags = 0; - flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk returned %" PRId32 ", expected" - " 0: ", r); - goto end; - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - //printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized)); - PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized)); - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - UTHFreeFlow(f); - return result; -} - -/** \test Host:www.google.com <- missing space between name:value (rfc violation) - */ -static int HTPParserTest10(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - if (h == NULL) { - goto end; - } - - char *name = bstr_util_strdup_to_c(h->name); - if (name == NULL) { - goto end; - } - - if (strcmp(name, "Host") != 0) { - printf("header name not \"Host\", instead \"%s\": ", name); - free(name); - goto end; - } - free(name); - - char *value = bstr_util_strdup_to_c(h->value); - if (value == NULL) { - goto end; - } - - if (strcmp(value, "www.google.com") != 0) { - printf("header value not \"www.google.com\", instead \"%s\": ", value); - free(value); - goto end; - } - free(value); - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test double encoding in path - */ -static int HTPParserTest11(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (tx != NULL && tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (4 != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be 2, is %"PRIuMAX, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' || - bstr_ptr(tx_ud->request_uri_normalized)[1] != '%' || - bstr_ptr(tx_ud->request_uri_normalized)[2] != '0' || - bstr_ptr(tx_ud->request_uri_normalized)[3] != '0') - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\": "); - goto end; - } - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test double encoding in query - */ -static int HTPParserTest12(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (7 != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be 5, is %"PRIuMAX, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' || - bstr_ptr(tx_ud->request_uri_normalized)[1] != '?' || - bstr_ptr(tx_ud->request_uri_normalized)[2] != 'a' || - bstr_ptr(tx_ud->request_uri_normalized)[3] != '=' || - bstr_ptr(tx_ud->request_uri_normalized)[4] != '%' || - bstr_ptr(tx_ud->request_uri_normalized)[5] != '0' || - bstr_ptr(tx_ud->request_uri_normalized)[6] != '0') - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\": "); - goto end; - } - } - - result = 1; - end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation) - */ -static int HTPParserTest13(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) - flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) - flags = STREAM_TOSERVER|STREAM_EOF; - else - flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - if (h == NULL) { - goto end; - } - - char *name = bstr_util_strdup_to_c(h->name); - if (name == NULL) { - goto end; - } - - if (strcmp(name, "Host") != 0) { - printf("header name not \"Host\", instead \"%s\": ", name); - free(name); - goto end; - } - free(name); - - char *value = bstr_util_strdup_to_c(h->value); - if (value == NULL) { - goto end; - } - - if (strcmp(value, "www.google.com\rName: Value") != 0) { - printf("header value not \"www.google.com\", instead \""); - PrintRawUriFp(stdout, (uint8_t *)value, strlen(value)); - printf("\": "); - free(value); - goto end; - } - free(value); - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test basic config */ -static int HTPParserConfigTest01(void) -{ - int ret = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ -\n\ - server-config:\n\ -\n\ - - apache-tomcat:\n\ - address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ - personality: Tomcat_6_0\n\ -\n\ - - iis7:\n\ - address: \n\ - - 192.168.0.0/24\n\ - - 192.168.10.0/24\n\ - personality: IIS_7_0\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - - ConfYamlLoadString(input, strlen(input)); - - ConfNode *outputs; - outputs = ConfGetNode("libhtp.default-config.personality"); - if (outputs == NULL) { - goto end; - } - - outputs = ConfGetNode("libhtp.server-config"); - if (outputs == NULL) { - goto end; - } - - ConfNode *node = TAILQ_FIRST(&outputs->head); - if (node == NULL) { - goto end; - } - if (strcmp(node->name, "0") != 0) { - goto end; - } - node = TAILQ_FIRST(&node->head); - if (node == NULL) { - goto end; - } - if (strcmp(node->name, "apache-tomcat") != 0) { - goto end; - } - - int i = 0; - ConfNode *n; - - ConfNode *node2 = ConfNodeLookupChild(node, "personality"); - if (node2 == NULL) { - goto end; - } - if (strcmp(node2->val, "Tomcat_6_0") != 0) { - goto end; - } - - node = ConfNodeLookupChild(node, "address"); - if (node == NULL) { - goto end; - } - TAILQ_FOREACH(n, &node->head, next) { - if (n == NULL) { - goto end; - } - - switch(i) { - case 0: - if (strcmp(n->name, "0") != 0) { - goto end; - } - if (strcmp(n->val, "192.168.1.0/24") != 0) { - goto end; - } - break; - case 1: - if (strcmp(n->name, "1") != 0) { - goto end; - } - if (strcmp(n->val, "127.0.0.0/8") != 0) { - goto end; - } - break; - case 2: - if (strcmp(n->name, "2") != 0) { - goto end; - } - if (strcmp(n->val, "::1") != 0) { - goto end; - } - break; - default: - goto end; - } - i++; - } - - outputs = ConfGetNode("libhtp.server-config"); - if (outputs == NULL) { - goto end; - } - - node = TAILQ_FIRST(&outputs->head); - node = TAILQ_NEXT(node, next); - if (node == NULL) { - goto end; - } - if (strcmp(node->name, "1") != 0) { - goto end; - } - node = TAILQ_FIRST(&node->head); - if (node == NULL) { - goto end; - } - if (strcmp(node->name, "iis7") != 0) { - goto end; - } - - node2 = ConfNodeLookupChild(node, "personality"); - if (node2 == NULL) { - goto end; - } - if (strcmp(node2->val, "IIS_7_0") != 0) { - goto end; - } - - node = ConfNodeLookupChild(node, "address"); - if (node == NULL) { - goto end; - } - - i = 0; - TAILQ_FOREACH(n, &node->head, next) { - if (n == NULL) { - goto end; - } - - switch(i) { - case 0: - if (strcmp(n->name, "0") != 0) { - goto end; - } - if (strcmp(n->val, "192.168.0.0/24") != 0) { - goto end; - } - break; - case 1: - if (strcmp(n->name, "1") != 0) { - goto end; - } - if (strcmp(n->val, "192.168.10.0/24") != 0) { - goto end; - } - break; - default: - goto end; - } - i++; - } - - ret = 1; - -end: - ConfDeInit(); - ConfRestoreContextBackup(); - - return ret; -} - -/** \test Test config builds radix correctly */ -static int HTPParserConfigTest02(void) -{ - int ret = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ -\n\ - server-config:\n\ -\n\ - - apache-tomcat:\n\ - address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ - personality: Tomcat_6_0\n\ -\n\ - - iis7:\n\ - address: \n\ - - 192.168.0.0/24\n\ - - 192.168.10.0/24\n\ - personality: IIS_7_0\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - - HTPConfigure(); - - if (cfglist.cfg == NULL) { - printf("No default config created.\n"); - goto end; - } - - if (cfgtree == NULL) { - printf("No config tree created.\n"); - goto end; - } - - htp_cfg_t *htp = cfglist.cfg; - uint8_t buf[128]; - const char *addr; - void *user_data = NULL; - - addr = "192.168.10.42"; - if (inet_pton(AF_INET, addr, buf) == 1) { - (void)SCRadixFindKeyIPV4BestMatch(buf, cfgtree, &user_data); - if (user_data != NULL) { - HTPCfgRec *htp_cfg_rec = user_data; - htp = htp_cfg_rec->cfg; - SCLogDebug("LIBHTP using config: %p", htp); - } - if (htp == NULL) { - printf("Could not get config for: %s\n", addr); - goto end; - } - } - else { - printf("Failed to parse address: %s\n", addr); - goto end; - } - - user_data = NULL; - addr = "::1"; - if (inet_pton(AF_INET6, addr, buf) == 1) { - (void)SCRadixFindKeyIPV6BestMatch(buf, cfgtree, &user_data); - if (user_data != NULL) { - HTPCfgRec *htp_cfg_rec = user_data; - htp = htp_cfg_rec->cfg; - SCLogDebug("LIBHTP using config: %p", htp); - } - if (htp == NULL) { - printf("Could not get config for: %s\n", addr); - goto end; - } - } - else { - printf("Failed to parse address: %s\n", addr); - goto end; - } - - ret = 1; - -end: - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - return ret; -} - -/** \test Test traffic is handled by the correct htp config */ -static int HTPParserConfigTest03(void) -{ - int result = 1; - Flow *f = NULL; - uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" - " Data is c0oL!"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ -\n\ - server-config:\n\ -\n\ - - apache-tomcat:\n\ - address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ - personality: Tomcat_6_0\n\ -\n\ - - iis7:\n\ - address: \n\ - - 192.168.0.0/24\n\ - - 192.168.10.0/24\n\ - personality: IIS_7_0\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - - HTPConfigure(); - - const char *addr = "192.168.10.42"; - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - htp_cfg_t *htp = cfglist.cfg; - - void *user_data = NULL; - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)f->dst.addr_data32, cfgtree, &user_data); - if (user_data != NULL) { - HTPCfgRec *htp_cfg_rec = user_data; - htp = htp_cfg_rec->cfg; - SCLogDebug("LIBHTP using config: %p", htp); - } - if (htp == NULL) { - printf("Could not get config for: %s\n", addr); - goto end; - } - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - result = 0; - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - if (HTPStateGetTxCnt(htp_state) != 2) { - printf("HTPStateGetTxCnt(htp_state) failure\n"); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - if (tx->cfg != htp) { - printf("wrong HTP config (%p instead of %p - default=%p): ", - tx->cfg, htp, cfglist.cfg); - goto end; - } - tx = HTPStateGetTx(htp_state, 1); - if (tx == NULL) - goto end; - if (tx->cfg != htp) { - printf("wrong HTP config (%p instead of %p - default=%p): ", - tx->cfg, htp, cfglist.cfg); - goto end; - } - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/* disabled when we upgraded to libhtp 0.5.x */ -#if 0 -static int HTPParserConfigTest04(void) -{ - int result = 0; - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - path-control-char-handling: status_400\n\ - path-convert-utf8: yes\n\ - path-invalid-encoding-handling: remove_percent\n\ -\n\ - server-config:\n\ -\n\ - - apache-tomcat:\n\ - personality: Tomcat_6_0\n\ - path-invalid-utf8-handling: none\n\ - path-nul-encoded-handling: status_404\n\ - path-nul-raw-handling: status_400\n\ -\n\ - - iis7:\n\ - personality: IIS_7_0\n\ - path-replacement-char: o\n\ - path-unicode-mapping: status_400\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - - HTPConfigure(); - - HTPCfgRec *cfg_rec = &cfglist; - if (cfg_rec->cfg->path_control_char_handling != STATUS_400 || - cfg_rec->cfg->path_convert_utf8 != 1 || - cfg_rec->cfg->path_invalid_encoding_handling != URL_DECODER_REMOVE_PERCENT) { - printf("failed 1\n"); - goto end; - } - - cfg_rec = cfg_rec->next; - if (cfg_rec->cfg->bestfit_replacement_char != 'o' || - cfg_rec->cfg->path_unicode_mapping != STATUS_400) { - printf("failed 2\n"); - goto end; - } - - cfg_rec = cfg_rec->next; - if (cfg_rec->cfg->path_invalid_utf8_handling != NONE || - cfg_rec->cfg->path_nul_encoded_handling != STATUS_404 || - cfg_rec->cfg->path_nul_raw_handling != STATUS_400) { - printf("failed 3\n"); - goto end; - } - - result = 1; - -end: - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - return result; -} -#endif - -/** \test Test %2f decoding in profile Apache_2_2 - * - * %2f in path is left untouched - * %2f in query string is normalized to %2F - * %252f in query string is decoded/normalized to %2F - */ -static int HTPParserDecodingTest01(void) -{ - uint8_t httpbuf1[] = - "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" - "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" - "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: Apache_2\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - for (uint32_t u = 0; u < httplen1; u++) { - uint8_t flags = 0; - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - FAIL_IF(r != 0); - } - - HtpState *htp_state = f->alstate; - FAIL_IF_NULL(htp_state); - - uint8_t ref1[] = "/abc%2fdef"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - FAIL_IF_NULL(tx); - - HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->request_uri_normalized); - FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); - FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0); - - uint8_t ref2[] = "/abc/def?ghi/jkl"; - reflen = sizeof(ref2) - 1; - - tx = HTPStateGetTx(htp_state, 1); - FAIL_IF_NULL(tx); - tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->request_uri_normalized); - FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); - - FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, - bstr_len(tx_ud->request_uri_normalized)) != 0); - - uint8_t ref3[] = "/abc/def?ghi%2fjkl"; - reflen = sizeof(ref3) - 1; - tx = HTPStateGetTx(htp_state, 2); - FAIL_IF_NULL(tx); - tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->request_uri_normalized); - FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); - - FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3, - bstr_len(tx_ud->request_uri_normalized)) != 0); - - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -static int HTPParserDecodingTest01a(void) -{ - uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" - "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" - "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: Apache_2\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, - (STREAM_TOSERVER | STREAM_START | STREAM_EOF), httpbuf1, httplen1); - FAIL_IF(r != 0); - - HtpState *htp_state = f->alstate; - FAIL_IF_NULL(htp_state); - - uint8_t ref1[] = "/abc%2fdef"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - FAIL_IF_NULL(tx); - - HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->request_uri_normalized); - FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); - FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0); - - uint8_t ref2[] = "/abc/def?ghi/jkl"; - reflen = sizeof(ref2) - 1; - - tx = HTPStateGetTx(htp_state, 1); - FAIL_IF_NULL(tx); - tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->request_uri_normalized); - FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); - - FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, - bstr_len(tx_ud->request_uri_normalized)) != 0); - - uint8_t ref3[] = "/abc/def?ghi%2fjkl"; - reflen = sizeof(ref3) - 1; - tx = HTPStateGetTx(htp_state, 2); - FAIL_IF_NULL(tx); - tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - FAIL_IF_NULL(tx_ud); - FAIL_IF_NULL(tx_ud->request_uri_normalized); - FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); - - FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3, - bstr_len(tx_ud->request_uri_normalized)) != 0); - - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test %2f decoding in profile IDS - * - * %2f in path decoded to / - * %2f in query string is decoded to / - * %252f in query string is decoded to %2F - */ -static int HTPParserDecodingTest02(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" - "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" - "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: no\n\ - double-decode-query: no\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "/abc/def"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - uint8_t ref2[] = "/abc/def?ghi/jkl"; - reflen = sizeof(ref2) - 1; - - tx = HTPStateGetTx(htp_state, 1); - if (tx == NULL) - goto end; - tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref2, reflen); - printf("\": "); - goto end; - } - } - - uint8_t ref3[] = "/abc/def?ghi%2fjkl"; - reflen = sizeof(ref3) - 1; - tx = HTPStateGetTx(htp_state, 2); - if (tx == NULL) - goto end; - tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX" (3): ", - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref3, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test %2f decoding in profile IDS with double-decode-* options - * - * %252f in path decoded to / - * %252f in query string is decoded to / - */ -static int HTPParserDecodingTest03(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" - "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: yes\n\ - double-decode-query: yes\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "/abc/def"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - uint8_t ref2[] = "/abc/def?ghi/jkl"; - reflen = sizeof(ref2) - 1; - - tx = HTPStateGetTx(htp_state, 1); - if (tx == NULL) - goto end; - tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref2, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test http:// in query profile IDS - */ -static int HTPParserDecodingTest04(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: yes\n\ - double-decode-query: yes\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "/abc/def?a=http://www.abc.com/"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test \ char in query profile IDS. Bug 739 - */ -static int HTPParserDecodingTest05(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET /index?id=\\\" HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: yes\n\ - double-decode-query: yes\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "/index?id=\\\""; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test + char in query. Bug 1035 - */ -static int HTPParserDecodingTest06(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: yes\n\ - double-decode-query: yes\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test + char in query. Bug 1035 - */ -static int HTPParserDecodingTest07(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: yes\n\ - double-decode-query: yes\n\ - query-plusspace-decode: yes\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test 'proxy' URI normalization. Ticket 1008 - */ -static int HTPParserDecodingTest08(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "/blah/"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test 'proxy' URI normalization. Ticket 1008 - */ -static int HTPParserDecodingTest09(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = - "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - uri-include-all: true\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - const char *addr = "4.3.2.1"; - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < httplen1; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - uint8_t ref1[] = "http://suricata-ids.org/blah/"; - size_t reflen = sizeof(ref1) - 1; - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL) - goto end; - HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - if (reflen != bstr_len(tx_ud->request_uri_normalized)) { - printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, - (uintmax_t)reflen, - (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); - goto end; - } - - if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, - bstr_len(tx_ud->request_uri_normalized)) != 0) - { - printf("normalized uri \""); - PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized)); - printf("\" != \""); - PrintRawUriFp(stdout, ref1, reflen); - printf("\": "); - goto end; - } - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test BG box crash -- chunks are messed up. Observed for real. */ -static int HTPBodyReassemblyTest01(void) -{ - int result = 0; - HtpTxUserData htud; - memset(&htud, 0x00, sizeof(htud)); - HtpState hstate; - memset(&hstate, 0x00, sizeof(hstate)); - Flow flow; - memset(&flow, 0x00, sizeof(flow)); - AppLayerParserState *parser = AppLayerParserStateAlloc(); - htp_tx_t tx; - memset(&tx, 0, sizeof(tx)); - - hstate.f = &flow; - flow.alparser = parser; - - uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; - uint8_t chunk2[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; - - int r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk1, sizeof(chunk1)-1); - BUG_ON(r != 0); - r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk2, sizeof(chunk2)-1); - BUG_ON(r != 0); - - const uint8_t *chunks_buffer = NULL; - uint32_t chunks_buffer_len = 0; - - HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len); - if (chunks_buffer == NULL) { - goto end; - } -#ifdef PRINT - printf("REASSCHUNK START: \n"); - PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); - printf("REASSCHUNK END: \n"); -#endif - - HtpRequestBodyHandleMultipart(&hstate, &htud, &tx, chunks_buffer, chunks_buffer_len); - - if (htud.request_body.content_len_so_far != 669) { - printf("htud.request_body.content_len_so_far %"PRIu64": ", htud.request_body.content_len_so_far); - goto end; - } - - FAIL_IF_NOT_NULL(htud.files_ts.head); - - result = 1; -end: - return result; -} - -/** \test BG crash */ -static int HTPSegvTest01(void) -{ - int result = 0; - Flow *f = NULL; - uint8_t httpbuf1[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: no\n\ - double-decode-query: no\n\ - request-body-limit: 0\n\ - response-body-limit: 0\n\ -"; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - SCLogDebug("\n>>>> processing chunk 1 again <<<<\n"); - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - http_state = f->alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } - - AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(f->alparser); - if (decoder_events != NULL) { - printf("app events: "); - goto end; - } - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test really long request, this should result in HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */ -static int HTPParserTest14(void) -{ - size_t len = 18887; - TcpSession ssn; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: no\n\ - double-decode-query: no\n\ - request-body-limit: 0\n\ - response-body-limit: 0\n\ -"; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&ssn, 0, sizeof(ssn)); - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - char *httpbuf = SCMalloc(len); - FAIL_IF_NULL(httpbuf); - memset(httpbuf, 0x00, len); - - /* create the request with a longer than 18k cookie */ - strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n" - "Host: myhost.lan\r\n" - "Connection: keep-alive\r\n" - "Accept: */*\r\n" - "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" - "Referer: http://blah.lan/\r\n" - "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" - "Cookie: ", len); - size_t o = strlen(httpbuf); - for ( ; o < len - 4; o++) { - httpbuf[o] = 'A'; - } - httpbuf[len - 4] = '\r'; - httpbuf[len - 3] = '\n'; - httpbuf[len - 2] = '\r'; - httpbuf[len - 1] = '\n'; - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->alproto = ALPROTO_HTTP1; - f->proto = IPPROTO_TCP; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < len; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - (void)AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1); - } - HtpState *htp_state = f->alstate; - FAIL_IF_NULL(htp_state); - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - FAIL_IF_NULL(tx); - FAIL_IF(tx->request_method_number != HTP_M_GET); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); - AppLayerDecoderEvents *decoder_events = - AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); - FAIL_IF_NULL(decoder_events); - - FAIL_IF(decoder_events->events[0] != HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - SCFree(httpbuf); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - PASS; -} - -/** \test Test really long request (same as HTPParserTest14), now with config - * update to allow it */ -static int HTPParserTest15(void) -{ - int result = 0; - Flow *f = NULL; - char *httpbuf = NULL; - size_t len = 18887; - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - double-decode-path: no\n\ - double-decode-query: no\n\ - request-body-limit: 0\n\ - response-body-limit: 0\n\ - meta-field-limit: 20000\n\ -"; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - httpbuf = SCMalloc(len); - if (unlikely(httpbuf == NULL)) - goto end; - memset(httpbuf, 0x00, len); - - /* create the request with a longer than 18k cookie */ - strlcpy(httpbuf, "GET /blah/ HTTP/1.1\r\n" - "Host: myhost.lan\r\n" - "Connection: keep-alive\r\n" - "Accept: */*\r\n" - "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" - "Referer: http://blah.lan/\r\n" - "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" - "Cookie: ", len); - size_t o = strlen(httpbuf); - for ( ; o < len - 4; o++) { - httpbuf[o] = 'A'; - } - httpbuf[len - 4] = '\r'; - httpbuf[len - 3] = '\n'; - httpbuf[len - 2] = '\r'; - httpbuf[len - 1] = '\n'; - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint32_t u; - for (u = 0; u < len; u++) { - uint8_t flags = 0; - - if (u == 0) flags = STREAM_TOSERVER|STREAM_START; - else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF; - else flags = STREAM_TOSERVER; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1); - if (r != 0) { - printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" - " 0: ", u, r); - goto end; - } - } - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1) - { - printf("expected method M_GET and got %s: , expected protocol " - "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), - bstr_util_strdup_to_c(tx->request_protocol)); - goto end; - } - - void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); - AppLayerDecoderEvents *decoder_events = - AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); - if (decoder_events != NULL) { - printf("app events: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - if (httpbuf != NULL) - SCFree(httpbuf); - HTPFreeConfig(); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - return result; -} - -/** \test Test unusual delims in request line HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */ -static int HTPParserTest16(void) -{ - int result = 0; - Flow *f = NULL; - TcpSession ssn; - HtpState *htp_state = NULL; - int r = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&ssn, 0, sizeof(ssn)); - - uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n" - "Host: myhost.lan\r\n" - "Connection: keep-alive\r\n" - "Accept: */*\r\n" - "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" - "Referer: http://blah.lan/\r\n" - "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" - "Cookie: blah\r\n\r\n"; - size_t len = sizeof(httpbuf) - 1; - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)httpbuf, len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - htp_state = f->alstate; - if (htp_state == NULL) { - printf("no http state: "); - goto end; - } - - htp_tx_t *tx = HTPStateGetTx(htp_state, 0); - if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1) - { - printf("expected method M_GET and got %s: , expected protocol " - "HTTP/1.1 and got %s \n", tx ? bstr_util_strdup_to_c(tx->request_method) : "tx null", - tx ? bstr_util_strdup_to_c(tx->request_protocol) : "tx null"); - goto end; - } - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -//these events are disabled during fuzzing as they are too noisy and consume much resource - void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); - AppLayerDecoderEvents *decoder_events = - AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); - if (decoder_events == NULL) { - printf("no app events: "); - goto end; - } - - if (decoder_events->events[0] != HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT) { - printf("HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT not set: "); - goto end; - } - - if (decoder_events->events[1] != HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT) { - printf("HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT not set: "); - goto end; - } -#endif - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - return result; -} - -/** \test Test response not HTTP - */ -static int HTPParserTest20(void) -{ - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" - "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " - "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "NOTHTTP\r\nSOMEOTHERDATA"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3); - FAIL_IF(r != 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(tx->request_method_number != HTP_M_GET); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - FAIL_IF(tx->response_status_number != 0); - FAIL_IF(tx->response_protocol_number != -1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test response not HTTP - */ -static int HTPParserTest21(void) -{ - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" - "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " - "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "999 NOTHTTP REALLY\r\nSOMEOTHERDATA\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3); - FAIL_IF(r != 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(tx->request_method_number != HTP_M_GET); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - FAIL_IF(tx->response_status_number != 0); - FAIL_IF(tx->response_protocol_number != -1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test response not HTTP - */ -static int HTPParserTest22(void) -{ - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" - "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " - "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "\r\n0000=0000000/ASDF3_31.zip, 456723\r\n" - "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); - FAIL_IF(r != 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(tx->request_method_number != HTP_M_GET); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - FAIL_IF(tx->response_status_number != -0); - FAIL_IF(tx->response_protocol_number != -1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test response not HTTP - */ -static int HTPParserTest23(void) -{ - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" - "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " - "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP0000=0000000/ASDF3_31.zip, 456723\r\n" - "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); - FAIL_IF(r != 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(tx->request_method_number != HTP_M_GET); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - FAIL_IF(tx->response_status_number != -1); - FAIL_IF(tx->response_protocol_number != -2); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test Test response not HTTP - */ -static int HTPParserTest24(void) -{ - Flow *f = NULL; - uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" - "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " - "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP/1.0 0000=0000000/ASDF3_31.zip, 456723\r\n" - "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&ssn, 0, sizeof(ssn)); - - f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); - FAIL_IF(r != 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); - FAIL_IF(r != 0); - - http_state = f->alstate; - FAIL_IF_NULL(http_state); - htp_tx_t *tx = HTPStateGetTx(http_state, 0); - FAIL_IF_NULL(tx); - htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - FAIL_IF_NULL(h); - - FAIL_IF(tx->request_method_number != HTP_M_GET); - FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); - - FAIL_IF(tx->response_status_number != -1); - FAIL_IF(tx->response_protocol_number != HTP_PROTOCOL_1_0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - PASS; -} - -/** \test multi transactions and cleanup */ -static int HTPParserTest25(void) -{ - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - StreamTcpInitConfig(true); - TcpSession ssn; - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_HTTP1; - - const char *str = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Suricata/1.0\r\n\r\n"; - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, - (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - - str = "HTTP 1.1 200 OK\r\nServer: Suricata/1.0\r\nContent-Length: 8\r\n\r\nSuricata"; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, - (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - - uint64_t ret[4]; - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 8); // log_id - FAIL_IF_NOT(ret[3] == 8); // min_id - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, - (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done - FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 8); // log_id - FAIL_IF_NOT(ret[3] == 8); // min_id - - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, - (uint8_t *)str, strlen(str)); - FAIL_IF_NOT(r == 0); - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 9); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 9); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 9); // log_id - FAIL_IF_NOT(ret[3] == 9); // min_id - - HtpState *http_state = f->alstate; - FAIL_IF_NULL(http_state); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - - PASS; -} - -static int HTPParserTest26(void) -{ - char input[] = "\ -%YAML 1.1\n\ ----\n\ -libhtp:\n\ -\n\ - default-config:\n\ - personality: IDS\n\ - request-body-limit: 1\n\ - response-body-limit: 1\n\ -"; - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t httpbuf1[] = "GET /alice.txt HTTP/1.1\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 228\r\n\r\n" - "Alice was beginning to get very tired of sitting by her sister on the bank." - "Alice was beginning to get very tired of sitting by her sister on the bank."; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - uint8_t httpbuf3[] = "Alice was beginning to get very tired of sitting by her sister on the bank.\r\n\r\n"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - TcpSession ssn; - HtpState *http_state = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP1; - - StreamTcpInitConfig(true); - - de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(filestore; sid:1; rev:1;)"); - FAIL_IF_NULL(de_ctx->sig_list); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse( - &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1); - FAIL_IF(r != 0); - - http_state = f.alstate; - FAIL_IF_NULL(http_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - FAIL_IF((PacketAlertCheck(p1, 1))); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - FAIL_IF((PacketAlertCheck(p1, 1))); - - r = AppLayerParserParse( - &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf2, httplen2); - FAIL_IF(r != 0); - - http_state = f.alstate; - FAIL_IF_NULL(http_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - FAIL_IF(!(PacketAlertCheck(p2, 1))); - - r = AppLayerParserParse( - &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf3, httplen3); - FAIL_IF(r != 0); - - http_state = f.alstate; - FAIL_IF_NULL(http_state); - - void *tx_ptr = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); - FAIL_IF_NULL(tx_ptr); - - AppLayerGetFileState files = HTPGetTxFiles(http_state, tx_ptr, STREAM_TOCLIENT); - FileContainer *ffc = files.fc; - FAIL_IF_NULL(ffc); - - File *ptr = ffc->head; - FAIL_IF(ptr->state != FILE_STATE_CLOSED); - - AppLayerParserThreadCtxFree(alp_tctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - StreamTcpFreeConfig(true); - - HTPFreeConfig(); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - ConfDeInit(); - ConfRestoreContextBackup(); - HtpConfigRestoreBackup(); - PASS; -} - -static int HTPParserTest27(void) -{ - HTPCfgDir cfg; - memset(&cfg, 0, sizeof(cfg)); - cfg.body_limit = 1500; - FileReassemblyDepthEnable(2000); - - uint32_t len = 1000; - - HtpTxUserData *tx_ud = SCMalloc(sizeof(HtpTxUserData)); - FAIL_IF_NULL(tx_ud); - - tx_ud->tsflags |= HTP_STREAM_DEPTH_SET; - tx_ud->request_body.content_len_so_far = 2500; - - FAIL_IF(AppLayerHtpCheckDepth(&cfg, &tx_ud->request_body, tx_ud->tsflags)); - - len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far, - 0, - FileReassemblyDepth(), - tx_ud->tsflags, - len); - FAIL_IF(len != 1000); - - SCFree(tx_ud); - - PASS; -} - -/** - * \brief Register the Unit tests for the HTTP protocol - */ -static void HTPParserRegisterTests(void) -{ - UtRegisterTest("HTPParserTest01", HTPParserTest01); - UtRegisterTest("HTPParserTest01a", HTPParserTest01a); - UtRegisterTest("HTPParserTest01b", HTPParserTest01b); - UtRegisterTest("HTPParserTest01c", HTPParserTest01c); - UtRegisterTest("HTPParserTest02", HTPParserTest02); - UtRegisterTest("HTPParserTest03", HTPParserTest03); - UtRegisterTest("HTPParserTest04", HTPParserTest04); - UtRegisterTest("HTPParserTest05", HTPParserTest05); - UtRegisterTest("HTPParserTest06", HTPParserTest06); - UtRegisterTest("HTPParserTest07", HTPParserTest07); - UtRegisterTest("HTPParserTest08", HTPParserTest08); - UtRegisterTest("HTPParserTest09", HTPParserTest09); - UtRegisterTest("HTPParserTest10", HTPParserTest10); - UtRegisterTest("HTPParserTest11", HTPParserTest11); - UtRegisterTest("HTPParserTest12", HTPParserTest12); - UtRegisterTest("HTPParserTest13", HTPParserTest13); - UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01); - UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02); - UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03); -#if 0 /* disabled when we upgraded to libhtp 0.5.x */ - UtRegisterTest("HTPParserConfigTest04", HTPParserConfigTest04, 1); -#endif - - UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01); - UtRegisterTest("HTPParserDecodingTest01a", HTPParserDecodingTest01a); - UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02); - UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03); - UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04); - UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05); - UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06); - UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07); - UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08); - UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09); - - UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01); - - UtRegisterTest("HTPSegvTest01", HTPSegvTest01); - - UtRegisterTest("HTPParserTest14", HTPParserTest14); - UtRegisterTest("HTPParserTest15", HTPParserTest15); - UtRegisterTest("HTPParserTest16", HTPParserTest16); - UtRegisterTest("HTPParserTest20", HTPParserTest20); - UtRegisterTest("HTPParserTest21", HTPParserTest21); - UtRegisterTest("HTPParserTest22", HTPParserTest22); - UtRegisterTest("HTPParserTest23", HTPParserTest23); - UtRegisterTest("HTPParserTest24", HTPParserTest24); - UtRegisterTest("HTPParserTest25", HTPParserTest25); - UtRegisterTest("HTPParserTest26", HTPParserTest26); - UtRegisterTest("HTPParserTest27", HTPParserTest27); - - HTPFileParserRegisterTests(); - HTPXFFParserRegisterTests(); -} -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h deleted file mode 100644 index dee5c17e833e..000000000000 --- a/src/app-layer-htp.h +++ /dev/null @@ -1,297 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \defgroup httplayer HTTP layer support - * - * @{ - */ - -/** - * \file - * - * \author Gurvinder Singh - * \author Pablo Rincon - * - * This file provides a HTTP protocol support for the engine using HTP library. - */ - -#ifndef __APP_LAYER_HTP_H__ -#define __APP_LAYER_HTP_H__ - -#include "rust.h" -#include "app-layer-frames.h" - -#include - -/* default request body limit */ -#define HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT 4096U -#define HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT 4096U -#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE 32768U -#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW 4096U -#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE 32768U -#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW 4096U -#define HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT 9000U -#define HTP_CONFIG_DEFAULT_FIELD_LIMIT_HARD 18000U - -#define HTP_CONFIG_DEFAULT_LZMA_LAYERS 0U -/* default libhtp lzma limit, taken from libhtp. */ -#define HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT 1048576U -#define HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT 1048576U -// 100000 usec is 0.1 sec -#define HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT 100000 - -#define HTP_CONFIG_DEFAULT_RANDOMIZE 1 -#define HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE 10 - -/** a boundary should be smaller in size */ -#define HTP_BOUNDARY_MAX 200U - -// 0x0001 not used -#define HTP_FLAG_STATE_CLOSED_TS 0x0002 /**< Flag to indicate that HTTP - connection is closed */ -#define HTP_FLAG_STATE_CLOSED_TC \ - 0x0004 /**< Flag to indicate that HTTP \ - connection is closed */ - -enum { - HTP_BODY_REQUEST_NONE = 0, - HTP_BODY_REQUEST_MULTIPART, /* POST, MP */ - HTP_BODY_REQUEST_POST, /* POST, no MP */ - HTP_BODY_REQUEST_PUT, -}; - -enum { - /* libhtp errors/warnings */ - HTTP_DECODER_EVENT_UNKNOWN_ERROR, - HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED, - HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON, - HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON, - HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN, - HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN, - HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST, - HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE, - HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST, - HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE, - HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST, - HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE, - HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN, - HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST, - HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST, - HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT, - HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID, - HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID, - HTTP_DECODER_EVENT_MISSING_HOST_HEADER, - HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS, - HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING, - HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING, - HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG, - HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG, - HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG, - HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH, - HTTP_DECODER_EVENT_URI_HOST_INVALID, - HTTP_DECODER_EVENT_HEADER_HOST_INVALID, - HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT, - HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT, - HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE, - HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS, - HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER, - HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED, - HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION, - HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION, - HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES, - HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING, - HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO, - HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL, - HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS, - HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE, - HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI, - HTTP_DECODER_EVENT_REQUEST_LINE_INVALID, - HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED, - - HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED, - HTTP_DECODER_EVENT_COMPRESSION_BOMB, - - HTTP_DECODER_EVENT_RANGE_INVALID, - HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION, - - /* suricata errors/warnings */ - HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR, - HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA, - HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER, - - HTTP_DECODER_EVENT_TOO_MANY_WARNINGS, - - HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE, -}; - -typedef enum HtpSwfCompressType_ { - HTTP_SWF_COMPRESSION_NONE = 0, - HTTP_SWF_COMPRESSION_ZLIB, - HTTP_SWF_COMPRESSION_LZMA, - HTTP_SWF_COMPRESSION_BOTH, -} HtpSwfCompressType; - -typedef struct HTPCfgDir_ { - uint32_t body_limit; - uint32_t inspect_min_size; - uint32_t inspect_window; -} HTPCfgDir; - -/** Need a linked list in order to keep track of these */ -typedef struct HTPCfgRec_ { - htp_cfg_t *cfg; - struct HTPCfgRec_ *next; - - /** max size of the client body we inspect */ - int randomize; - int randomize_range; - int http_body_inline; - - int swf_decompression_enabled; - HtpSwfCompressType swf_compression_type; - uint32_t swf_decompress_depth; - uint32_t swf_compress_depth; - - HTPCfgDir request; - HTPCfgDir response; - - bool uri_include_all; /**< use all info in uri (bool) */ -} HTPCfgRec; - -/** Struct used to hold chunks of a body on a request */ -struct HtpBodyChunk_ { - struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */ - int logged; - StreamingBufferSegment sbseg; -} __attribute__((__packed__)); -typedef struct HtpBodyChunk_ HtpBodyChunk; - -/** Struct used to hold all the chunks of a body on a request */ -typedef struct HtpBody_ { - HtpBodyChunk *first; /**< Pointer to the first chunk */ - HtpBodyChunk *last; /**< Pointer to the last chunk */ - - StreamingBuffer *sb; - - /* Holds the length of the htp request body seen so far */ - uint64_t content_len_so_far; - /* parser tracker */ - uint64_t body_parsed; - /* inspection tracker */ - uint64_t body_inspected; -} HtpBody; - -#define HTP_BOUNDARY_SET BIT_U8(1) /**< We have a boundary string */ -#define HTP_FILENAME_SET BIT_U8(3) /**< filename is registered in the flow */ -#define HTP_DONTSTORE BIT_U8(4) /**< not storing this file */ -#define HTP_STREAM_DEPTH_SET BIT_U8(5) /**< stream-depth is set */ - -/** Now the Body Chunks will be stored per transaction, at - * the tx user data */ -typedef struct HtpTxUserData_ { - /* Body of the request (if any) */ - uint8_t request_body_init; - uint8_t response_body_init; - - uint8_t request_has_trailers; - uint8_t response_has_trailers; - - uint8_t boundary_len; - - uint8_t tsflags; - uint8_t tcflags; - - uint8_t request_body_type; - - HtpBody request_body; - HtpBody response_body; - - bstr *request_uri_normalized; - - uint8_t *request_headers_raw; - uint8_t *response_headers_raw; - uint32_t request_headers_raw_len; - uint32_t response_headers_raw_len; - - /** Holds the boundary identification string if any (used on - * multipart/form-data only) - */ - uint8_t *boundary; - - HttpRangeContainerBlock *file_range; /**< used to assign track ids to range file */ - - AppLayerTxData tx_data; - FileContainer files_ts; - FileContainer files_tc; -} HtpTxUserData; - -typedef struct HtpState_ { - /* Connection parser structure for each connection */ - htp_connp_t *connp; - /* Connection structure for each connection */ - htp_conn_t *conn; - Flow *f; /**< Needed to retrieve the original flow when using HTPLib callbacks */ - uint64_t transaction_cnt; - const struct HTPCfgRec_ *cfg; - uint16_t flags; - uint16_t events; - uint16_t htp_messages_offset; /**< offset into conn->messages list */ - uint32_t file_track_id; /**< used to assign file track ids to files */ - uint64_t last_request_data_stamp; - uint64_t last_response_data_stamp; - StreamSlice *slice; - FrameId request_frame_id; - FrameId response_frame_id; - AppLayerStateData state_data; -} HtpState; - -/** part of the engine needs the request body (e.g. http_client_body keyword) */ -#define HTP_REQUIRE_REQUEST_BODY (1 << 0) -/** part of the engine needs the request body multipart header (e.g. filename - * and / or fileext keywords) */ -#define HTP_REQUIRE_REQUEST_MULTIPART (1 << 1) -/** part of the engine needs the request file (e.g. log-file module) */ -#define HTP_REQUIRE_REQUEST_FILE (1 << 2) -/** part of the engine needs the request body (e.g. file_data keyword) */ -#define HTP_REQUIRE_RESPONSE_BODY (1 << 3) - -SC_ATOMIC_EXTERN(uint32_t, htp_config_flags); - -void RegisterHTPParsers(void); -void HTPAtExitPrintStats(void); -void HTPFreeConfig(void); - -/* To free the state from unittests using app-layer-htp */ -void HTPStateFree(void *); -void AppLayerHtpEnableRequestBodyCallback(void); -void AppLayerHtpEnableResponseBodyCallback(void); -void AppLayerHtpNeedFileInspection(void); -void AppLayerHtpPrintStats(void); - -void HTPConfigure(void); - -void HtpConfigCreateBackup(void); -void HtpConfigRestoreBackup(void); - -void *HtpGetTxForH2(void *); - -#endif /* __APP_LAYER_HTP_H__ */ - -/** - * @} - */ diff --git a/src/app-layer-http2.c b/src/app-layer-http2.c deleted file mode 100644 index dd0b3ec53f93..000000000000 --- a/src/app-layer-http2.c +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Philippe Antoine - * - * Parser for HTTP2, RFC 7540 - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "app-layer-http2.h" -#include "rust.h" - -static int HTTP2RegisterPatternsForProtocolDetection(void) -{ - /* Using the 24 bytes pattern makes AppLayerTest09 fail/leak - * The complete pattern is "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" - */ - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP2, - "PRI * HTTP/2.0\r\n", - 16, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - return 0; -} - -static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; -static SuricataFileContext sfc = { &sbcfg }; - -void RegisterHTTP2Parsers(void) -{ - const char *proto_name = "http2"; - - if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, true)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP2, proto_name); - if (HTTP2RegisterPatternsForProtocolDetection() < 0) - return; - - rs_http2_init(&sfc); - rs_http2_register_parser(); - } - -#ifdef UNITTESTS - //TODOask HTTP2ParserRegisterTests(); -#endif -} - -void HTTP2MimicHttp1Request(void *alstate_orig, void *h2s) -{ - htp_tx_t *h1tx = HtpGetTxForH2(alstate_orig); - if (h2s == NULL || h1tx == NULL) { - return; - } - if (h1tx->request_method == NULL) { - // may happen if we only got the reply, not the HTTP1 request - return; - } - // else - rs_http2_tx_set_method(h2s, bstr_ptr(h1tx->request_method), bstr_len(h1tx->request_method)); - if (h1tx->request_uri != NULL) { - // A request line without spaces gets interpreted as a request_method - // and has request_uri=NULL - rs_http2_tx_set_uri(h2s, bstr_ptr(h1tx->request_uri), bstr_len(h1tx->request_uri)); - } - size_t nbheaders = htp_table_size(h1tx->request_headers); - for (size_t i = 0; i < nbheaders; i++) { - htp_header_t *h = htp_table_get_index(h1tx->request_headers, i, NULL); - rs_http2_tx_add_header( - h2s, bstr_ptr(h->name), bstr_len(h->name), bstr_ptr(h->value), bstr_len(h->value)); - } -} diff --git a/src/app-layer-ike.c b/src/app-layer-ike.c deleted file mode 100644 index 9a66904ab0a3..000000000000 --- a/src/app-layer-ike.c +++ /dev/null @@ -1,189 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * \author Frank Honza - * - * IKE application layer detector and parser. - * - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-ike.h" -#include "rust.h" - -void RegisterIKEParsers(void) -{ - rs_ike_register_parser(); -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_IKE, IKEParserRegisterTests); -#endif -} - -#ifdef UNITTESTS -#include "stream-tcp.h" -#include "util-unittest-helper.h" -#include "flow-util.h" - -static int IkeParserTest(void) -{ - uint64_t ret[4]; - - Flow f; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - f.alproto = ALPROTO_IKE; - - StreamTcpInitConfig(true); - - static const unsigned char initiator_sa[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0d, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, - 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x07, 0x80, 0x0e, 0x00, 0x80, 0x80, 0x02, 0x00, 0x02, - 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01, 0x80, 0x0b, 0x00, 0x01, 0x00, 0x0c, 0x00, - 0x04, 0x00, 0x01, 0x51, 0x80, 0x0d, 0x00, 0x00, 0x14, 0x4a, 0x13, 0x1c, 0x81, 0x07, 0x03, - 0x58, 0x45, 0x5c, 0x57, 0x28, 0xf2, 0x0e, 0x95, 0x45, 0x2f, 0x0d, 0x00, 0x00, 0x14, 0x43, - 0x9b, 0x59, 0xf8, 0xba, 0x67, 0x6c, 0x4c, 0x77, 0x37, 0xae, 0x22, 0xea, 0xb8, 0xf5, 0x82, - 0x0d, 0x00, 0x00, 0x14, 0x7d, 0x94, 0x19, 0xa6, 0x53, 0x10, 0xca, 0x6f, 0x2c, 0x17, 0x9d, - 0x92, 0x15, 0x52, 0x9d, 0x56, 0x00, 0x00, 0x00, 0x14, 0x90, 0xcb, 0x80, 0x91, 0x3e, 0xbb, - 0x69, 0x6e, 0x08, 0x63, 0x81, 0xb5, 0xec, 0x42, 0x7b, 0x1f }; - - // the initiator sending the security association with proposals - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOSERVER | STREAM_START, - (uint8_t *)initiator_sa, sizeof(initiator_sa)); - FAIL_IF_NOT(r == 0); - - static const unsigned char responder_sa[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, - 0xa0, 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x01, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x6c, 0x0d, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, - 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x07, 0x80, 0x0e, 0x00, 0x80, 0x80, 0x02, 0x00, 0x02, - 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01, 0x80, 0x0b, 0x00, 0x01, 0x00, 0x0c, 0x00, - 0x04, 0x00, 0x01, 0x51, 0x80, 0x00, 0x00, 0x00, 0x14, 0x4a, 0x13, 0x1c, 0x81, 0x07, 0x03, - 0x58, 0x45, 0x5c, 0x57, 0x28, 0xf2, 0x0e, 0x95, 0x45, 0x2f }; - - // responder answering with chosen proposal - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOCLIENT, - (uint8_t *)responder_sa, sizeof(responder_sa)); - FAIL_IF_NOT(r == 0); - - static const unsigned char initiator_key[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, - 0xa0, 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x04, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x1c, 0x0a, 0x00, 0x00, 0x84, 0x35, 0x04, 0xd3, 0xd2, 0xed, 0x14, - 0xe0, 0xca, 0x03, 0xb8, 0x51, 0xa5, 0x1a, 0x9d, 0xa2, 0xe5, 0xa4, 0xc1, 0x4c, 0x1d, 0x7e, - 0xc3, 0xe1, 0xfb, 0xe9, 0x50, 0x02, 0x54, 0x24, 0x51, 0x4b, 0x3c, 0x69, 0xed, 0x7f, 0xbb, - 0x44, 0xe0, 0x92, 0x25, 0xda, 0x52, 0xd2, 0xa9, 0x26, 0x04, 0xa9, 0x9b, 0xf6, 0x1b, 0x7b, - 0xee, 0xd7, 0xfb, 0xfa, 0x63, 0x5e, 0x82, 0xf0, 0x65, 0xf4, 0xfe, 0x78, 0x07, 0x51, 0x35, - 0x4d, 0xbe, 0x47, 0x4c, 0x3d, 0xe7, 0x20, 0x7d, 0xcf, 0x69, 0xfd, 0xbb, 0xed, 0x32, 0xc1, - 0x69, 0x1c, 0xc1, 0x49, 0xb3, 0x18, 0xee, 0xe0, 0x03, 0x70, 0xe6, 0x5f, 0xc3, 0x06, 0x9b, - 0xba, 0xcf, 0xb0, 0x13, 0x46, 0x71, 0x73, 0x96, 0x6e, 0x9d, 0x5f, 0x4b, 0xc4, 0xf3, 0x85, - 0x7e, 0x35, 0x9b, 0xba, 0x3a, 0xdb, 0xb6, 0xef, 0xee, 0xa5, 0x16, 0xf3, 0x89, 0x7d, 0x85, - 0x34, 0xf3, 0x0d, 0x00, 0x00, 0x18, 0x89, 0xd7, 0xc8, 0xfb, 0xf9, 0x4b, 0x51, 0x5b, 0x52, - 0x1d, 0x5d, 0x95, 0x89, 0xc2, 0x60, 0x20, 0x21, 0xe1, 0xa7, 0x09, 0x0d, 0x00, 0x00, 0x14, - 0xaf, 0xca, 0xd7, 0x13, 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, - 0x00, 0x0d, 0x00, 0x00, 0x14, 0x11, 0xbd, 0xfe, 0x02, 0xd0, 0x56, 0x58, 0x7f, 0x2c, 0x18, - 0x12, 0x59, 0x72, 0xc3, 0x24, 0x01, 0x14, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89, 0xdf, - 0xd6, 0xb7, 0x12, 0x14, 0x00, 0x00, 0x18, 0x15, 0x74, 0xd6, 0x4c, 0x01, 0x65, 0xba, 0xd1, - 0x6a, 0x02, 0x3f, 0x03, 0x8d, 0x45, 0xa0, 0x74, 0x98, 0xd8, 0xd0, 0x51, 0x00, 0x00, 0x00, - 0x18, 0xfe, 0xbf, 0x46, 0x2f, 0x1c, 0xd7, 0x58, 0x05, 0xa7, 0xba, 0xa2, 0x87, 0x47, 0xe7, - 0x69, 0xd6, 0x74, 0xf8, 0x56, 0x00 }; - - // the initiator sending key exchange - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOSERVER, - (uint8_t *)initiator_key, sizeof(initiator_key)); - FAIL_IF_NOT(r == 0); - - static const unsigned char responder_key[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, - 0xa0, 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x04, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x30, 0x0a, 0x00, 0x00, 0x84, 0x6d, 0x02, 0x6d, 0x56, 0x16, 0xc4, - 0x5b, 0xe0, 0x5e, 0x5b, 0x89, 0x84, 0x11, 0xe9, 0xf9, 0x5d, 0x19, 0x5c, 0xea, 0x00, 0x9a, - 0xd2, 0x2c, 0x62, 0xbe, 0xf0, 0x6c, 0x57, 0x1b, 0x7c, 0xfb, 0xc4, 0x79, 0x2f, 0x45, 0x56, - 0x4e, 0xc7, 0x10, 0xac, 0x58, 0x4a, 0xa1, 0x8d, 0x20, 0xcb, 0xc8, 0xf5, 0xf8, 0x91, 0x06, - 0x66, 0xb8, 0x9e, 0x4e, 0xe2, 0xf9, 0x5a, 0xbc, 0x02, 0x30, 0xe2, 0xcb, 0xa1, 0xb8, 0x8a, - 0xc4, 0xbb, 0xa7, 0xfc, 0xc8, 0x18, 0xa9, 0x86, 0xc0, 0x1a, 0x4c, 0xa8, 0x65, 0xa5, 0xeb, - 0x82, 0x88, 0x4d, 0xbe, 0xc8, 0x5b, 0xfd, 0x7d, 0x1a, 0x30, 0x3b, 0x09, 0x89, 0x4d, 0xcf, - 0x2e, 0x37, 0x85, 0xfd, 0x79, 0xdb, 0xa2, 0x25, 0x37, 0x7c, 0xf8, 0xcc, 0xa0, 0x09, 0xce, - 0xff, 0xbb, 0x6a, 0xa3, 0x8b, 0x64, 0x8c, 0x4b, 0x05, 0x40, 0x4f, 0x1c, 0xfa, 0xac, 0x36, - 0x1a, 0xff, 0x0d, 0x00, 0x00, 0x18, 0x15, 0xb6, 0x88, 0x42, 0x1e, 0xd5, 0xc3, 0xdd, 0x92, - 0xd3, 0xb8, 0x6e, 0x47, 0xa7, 0x6f, 0x0d, 0x39, 0xcc, 0x09, 0xe0, 0x0d, 0x00, 0x00, 0x14, - 0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2, 0x74, 0xcc, 0x01, - 0x00, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13, 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, - 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x14, 0x55, 0xcc, 0x29, 0xed, 0x90, - 0x2a, 0xb8, 0xec, 0x53, 0xb1, 0xdf, 0x86, 0x7c, 0x61, 0x09, 0x29, 0x14, 0x00, 0x00, 0x0c, - 0x09, 0x00, 0x26, 0x89, 0xdf, 0xd6, 0xb7, 0x12, 0x14, 0x00, 0x00, 0x18, 0xfe, 0xbf, 0x46, - 0x2f, 0x1c, 0xd7, 0x58, 0x05, 0xa7, 0xba, 0xa2, 0x87, 0x47, 0xe7, 0x69, 0xd6, 0x74, 0xf8, - 0x56, 0x00, 0x00, 0x00, 0x00, 0x18, 0x15, 0x74, 0xd6, 0x4c, 0x01, 0x65, 0xba, 0xd1, 0x6a, - 0x02, 0x3f, 0x03, 0x8d, 0x45, 0xa0, 0x74, 0x98, 0xd8, 0xd0, 0x51 }; - - // responder sending key exchange - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOCLIENT, - (uint8_t *)responder_key, sizeof(responder_key)); - FAIL_IF_NOT(r == 0); - - static const unsigned char encrypted[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, 0xa0, - 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x05, 0x10, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x6c, 0xa4, 0x85, 0xa5, 0xd5, 0x86, 0x8a, 0x3c, 0x92, 0x5d, 0xed, 0xf2, - 0xd1, 0x0d, 0x5e, 0x47, 0x11, 0x2b, 0xc2, 0x94, 0x60, 0x18, 0xc7, 0x61, 0x28, 0xed, 0x7b, - 0xb2, 0x9d, 0xb0, 0x61, 0xfd, 0xab, 0xf7, 0x9a, 0x18, 0xe7, 0x56, 0x89, 0x53, 0x6d, 0x27, - 0xcb, 0xe0, 0x92, 0x1d, 0x67, 0xf7, 0x02, 0xf3, 0x47, 0xae, 0x6e, 0x79, 0xde, 0xe1, 0x09, - 0x4d, 0xc8, 0x6a, 0x5a, 0x26, 0x44, 0x8a, 0xde, 0x72, 0x83, 0x06, 0x94, 0xe1, 0x5d, 0xca, - 0x2d, 0x96, 0x03, 0xeb, 0xc5, 0xf7, 0x90, 0x47, 0x3d }; - // the initiator sending encrypted data - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOSERVER, (uint8_t *)encrypted, - sizeof(encrypted)); - FAIL_IF_NOT(r == 0); - - AppLayerParserTransactionsCleanup(&f, STREAM_TOCLIENT); - UTHAppLayerParserStateGetIds(f.alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 5); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 5); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 5); // log_id - FAIL_IF_NOT(ret[3] == 5); // min_id - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} -#endif - -void IKEParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("IkeParserTest", IkeParserTest); -#endif -} diff --git a/src/app-layer-krb5.c b/src/app-layer-krb5.c deleted file mode 100644 index 7b2b63f11999..000000000000 --- a/src/app-layer-krb5.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * - * Parser for Kerberos v5 application layer running on UDP port 88. - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-krb5.h" -#include "rust.h" - -void RegisterKRB5Parsers(void) -{ - rs_register_krb5_parser(); - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_KRB5, - KRB5ParserRegisterTests); -#endif -} - -#ifdef UNITTESTS -#endif - -void KRB5ParserRegisterTests(void) -{ -#ifdef UNITTESTS -#endif -} diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c deleted file mode 100644 index c1edbf2d3698..000000000000 --- a/src/app-layer-modbus.c +++ /dev/null @@ -1,1562 +0,0 @@ -/* - * Copyright (C) 2014 ANSSI - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * \author David DIALLO - * - * App-layer parser for Modbus protocol - * - */ - -#include "suricata-common.h" - -#include "util-debug.h" - -#include "app-layer-parser.h" -#include "app-layer-modbus.h" - -void ModbusParserRegisterTests(void); - -/** - * \brief Function to register the Modbus protocol parser - */ -void RegisterModbusParsers(void) -{ - rs_modbus_register_parser(); -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_MODBUS, ModbusParserRegisterTests); -#endif - - SCReturn; -} - -/* UNITTESTS */ -#ifdef UNITTESTS -#include "detect.h" -#include "detect-engine.h" -#include "detect-parse.h" -#include "detect-engine-build.h" -#include "detect-engine-alert.h" - -#include "flow-util.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "stream-tcp.h" -#include "stream-tcp-private.h" - -#include "rust.h" - -/* Modbus default stream reassembly depth */ -#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH 0 - -/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ -static uint8_t invalidFunctionCode[] = { - /* Transaction ID */ 0x00, 0x00, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x02, - /* Unit ID */ 0x00, - /* Function code */ 0x00 -}; - -/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ -/* Example of a request to read discrete outputs 20-38 */ -static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x01, - /* Starting Address */ 0x78, 0x90, - /* Quantity of coils */ 0x00, 0x13 }; - -static uint8_t readCoilsRsp[] = {/* Transaction ID */ 0x00, 0x00, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x01, - /* Byte count */ 0x03, - /* Coil Status */ 0xCD, 0x6B, 0x05 }; - -static uint8_t readCoilsErrorRsp[] = { - /* Transaction ID */ 0x00, 0x00, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x03, - /* Unit ID */ 0x00, - /* Function code */ 0x81, - /* Invalid Exception code: should trigger the InvalidExceptionCode ModbusEvent */ - 0xFF -}; - -/* Modbus Application Protocol Specification V1.1b3 6.6: Write Single register */ -/* Example of a request to write register 2 to 00 03 hex */ -static uint8_t writeSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x06, - /* Register Address */ 0x00, 0x01, - /* Register Value */ 0x00, 0x03}; - -static uint8_t invalidWriteSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x04, - /* Unit ID */ 0x00, - /* Function code */ 0x06, - /* Register Address */ 0x00, 0x01}; - -static uint8_t writeSingleRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x06, - /* Register Address */ 0x00, 0x01, - /* Register Value */ 0x00, 0x03}; - -/* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */ -/* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */ -static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x0B, - /* Unit ID */ 0x00, - /* Function code */ 0x10, - /* Starting Address */ 0x00, 0x01, - /* Quantity of Registers */ 0x00, 0x02, - /* Byte count */ 0x04, - /* Registers Value */ 0x00, 0x0A, - 0x01, 0x02}; - -static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x10, - /* Starting Address */ 0x00, 0x01, - /* Quantity of Registers */ 0x00, 0x02}; - -/* Modbus Application Protocol Specification V1.1b3 6.16: Mask Write Register */ -/* Example of a request to mask write to register 5 */ -static uint8_t maskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x08, - /* Unit ID */ 0x00, - /* Function code */ 0x16, - /* Reference Address */ 0x00, 0x04, - /* And_Mask */ 0x00, 0xF2, - /* Or_Mask */ 0x00, 0x25}; - -static uint8_t invalidMaskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x16, - /* Reference Address */ 0x00, 0x04, - /* And_Mask */ 0x00, 0xF2}; - -static uint8_t maskWriteRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x08, - /* Unit ID */ 0x00, - /* Function code */ 0x16, - /* Reference Address */ 0x00, 0x04, - /* And_Mask */ 0x00, 0xF2, - /* Or_Mask */ 0x00, 0x25}; - -/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */ -/* Example of a request to read six registers starting at register 4, */ -/* and to write three registers starting at register 15 */ -static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x11, - /* Unit ID */ 0x00, - /* Function code */ 0x17, - /* Read Starting Address */ 0x00, 0x03, - /* Quantity to Read */ 0x00, 0x06, - /* Write Starting Address */ 0x00, 0x0E, - /* Quantity to Write */ 0x00, 0x03, - /* Write Byte count */ 0x06, - /* Write Registers Value */ 0x12, 0x34, - 0x56, 0x78, - 0x9A, 0xBC}; - -/* Mismatch value in Byte count 0x0B instead of 0x0C */ -static uint8_t readWriteMultipleRegistersRsp[] = {/* Transaction ID */ 0x12, 0x34, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x0E, - /* Unit ID */ 0x00, - /* Function code */ 0x17, - /* Byte count */ 0x0B, - /* Read Registers Value */ 0x00, 0xFE, - 0x0A, 0xCD, - 0x00, 0x01, - 0x00, 0x03, - 0x00, 0x0D, - 0x00}; - -/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */ -/* Example of a request to to remote device to its Listen Only Mode for Modbus Communications. */ -static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x08, - /* Sub-function code */ 0x00, 0x04, - /* Data */ 0x00, 0x00}; - -static uint8_t invalidProtocolIdReq[] = {/* Transaction ID */ 0x00, 0x00, - /* Protocol ID */ 0x00, 0x01, - /* Length */ 0x00, 0x06, - /* Unit ID */ 0x00, - /* Function code */ 0x01, - /* Starting Address */ 0x78, 0x90, - /* Quantity of coils */ 0x00, 0x13 }; - -static uint8_t invalidLengthWriteMultipleRegistersReq[] = { - /* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x09, - /* Unit ID */ 0x00, - /* Function code */ 0x10, - /* Starting Address */ 0x00, 0x01, - /* Quantity of Registers */ 0x00, 0x02, - /* Byte count */ 0x04, - /* Registers Value */ 0x00, 0x0A, - 0x01, 0x02}; - -static uint8_t exceededLengthWriteMultipleRegistersReq[] = { - /* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0xff, 0xfa, - /* Unit ID */ 0x00, - /* Function code */ 0x10, - /* Starting Address */ 0x00, 0x01, - /* Quantity of Registers */ 0x7f, 0xf9, - /* Byte count */ 0xff}; - -static uint8_t invalidLengthPDUWriteMultipleRegistersReq[] = { - /* Transaction ID */ 0x00, 0x0A, - /* Protocol ID */ 0x00, 0x00, - /* Length */ 0x00, 0x02, - /* Unit ID */ 0x00, - /* Function code */ 0x10}; - -/** \test Send Modbus Read Coils request/response. */ -static int ModbusParserTest01(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, readCoilsReq, - sizeof(readCoilsReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1); - FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890); - FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, readCoilsRsp, - sizeof(readCoilsRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Send Modbus Write Multiple registers request/response. */ -static int ModbusParserTest02(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, writeMultipleRegistersReq, - sizeof(writeMultipleRegistersReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 16); - FAIL_IF_NOT(rs_modbus_message_get_write_multreq_address(&request) == 0x01); - FAIL_IF_NOT(rs_modbus_message_get_write_multreq_quantity(&request) == 2); - - size_t data_len; - const uint8_t *data = rs_modbus_message_get_write_multreq_data(&request, &data_len); - FAIL_IF_NOT(data_len == 4); - FAIL_IF_NOT(data[0] == 0x00); - FAIL_IF_NOT(data[1] == 0x0A); - FAIL_IF_NOT(data[2] == 0x01); - FAIL_IF_NOT(data[3] == 0x02); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, writeMultipleRegistersRsp, - sizeof(writeMultipleRegistersRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */ -static int ModbusParserTest03(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus Data mismatch\"; " - "app-layer-event: " - "modbus.value_mismatch; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, - readWriteMultipleRegistersReq, - sizeof(readWriteMultipleRegistersReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 23); - FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_read_address(&request) == 0x03); - FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_read_quantity(&request) == 6); - FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_write_address(&request) == 0x0E); - FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_write_quantity(&request) == 3); - - size_t data_len; - uint8_t const *data = rs_modbus_message_get_rw_multreq_write_data(&request, &data_len); - FAIL_IF_NOT(data_len == 6); - FAIL_IF_NOT(data[0] == 0x12); - FAIL_IF_NOT(data[1] == 0x34); - FAIL_IF_NOT(data[2] == 0x56); - FAIL_IF_NOT(data[3] == 0x78); - FAIL_IF_NOT(data[4] == 0x9A); - FAIL_IF_NOT(data[5] == 0xBC); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, readWriteMultipleRegistersRsp, - sizeof(readWriteMultipleRegistersRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Send Modbus Force Listen Only Mode request. */ -static int ModbusParserTest04(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, forceListenOnlyMode, - sizeof(forceListenOnlyMode)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 8); - FAIL_IF_NOT(rs_modbus_message_get_subfunction(&request) == 4); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Send Modbus invalid Protocol version in request. */ -static int ModbusParserTest05(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus invalid Protocol version\"; " - "app-layer-event: " - "modbus.invalid_protocol_id; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, invalidProtocolIdReq, - sizeof(invalidProtocolIdReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Send Modbus unsolicited response. */ -static int ModbusParserTest06(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus unsolicited response\"; " - "app-layer-event: " - "modbus.unsolicited_response; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, readCoilsRsp, - sizeof(readCoilsRsp)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Send Modbus invalid Length request. */ -static int ModbusParserTest07(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus invalid Length\"; " - "app-layer-event: " - "modbus.invalid_length; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, - invalidLengthWriteMultipleRegistersReq, - sizeof(invalidLengthWriteMultipleRegistersReq)); - FAIL_IF_NOT(r == 1); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Send Modbus Read Coils request and error response with Exception code invalid. */ -static int ModbusParserTest08(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus Exception code invalid\"; " - "app-layer-event: " - "modbus.invalid_exception_code; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, readCoilsReq, - sizeof(readCoilsReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1); - FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890); - FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, readCoilsErrorRsp, - sizeof(readCoilsErrorRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */ -static int ModbusParserTest09(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; - uint8_t *input = readCoilsReq; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, input, input_len - part2_len); - FAIL_IF_NOT(r == 1); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, input, input_len); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1); - FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890); - FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19); - - input_len = sizeof(readCoilsRsp); - part2_len = 10; - input = readCoilsRsp; - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, input, input_len - part2_len); - FAIL_IF_NOT(r == 1); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, input, input_len); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */ -static int ModbusParserTest10(void) { - uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq); - uint8_t *input, *ptr; - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - FAIL_IF_NULL(alp_tctx); - - input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t)); - FAIL_IF_NULL(input); - - memcpy(input, readCoilsReq, sizeof(readCoilsReq)); - memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq)); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, input, input_len); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 2); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 1); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 16); - FAIL_IF_NOT(rs_modbus_message_get_write_multreq_address(&request) == 0x01); - FAIL_IF_NOT(rs_modbus_message_get_write_multreq_quantity(&request) == 2); - - size_t data_len; - uint8_t const *data = rs_modbus_message_get_write_multreq_data(&request, &data_len); - FAIL_IF_NOT(data_len == 4); - FAIL_IF_NOT(data[0] == 0x00); - FAIL_IF_NOT(data[1] == 0x0A); - FAIL_IF_NOT(data[2] == 0x01); - FAIL_IF_NOT(data[3] == 0x02); - - input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp); - - ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t)); - FAIL_IF_NULL(ptr); - input = ptr; - - memcpy(input, readCoilsRsp, sizeof(readCoilsRsp)); - memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len); - FAIL_IF_NOT(r == 0); - - SCFree(input); - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Send Modbus exceed Length request. */ -static int ModbusParserTest11(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - size_t input_len = 65536; - uint8_t *input = SCCalloc(1, input_len); - - FAIL_IF(input == NULL); - - memcpy(input, exceededLengthWriteMultipleRegistersReq, - sizeof(exceededLengthWriteMultipleRegistersReq)); - - FAIL_IF(alp_tctx == NULL); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus invalid Length\"; " - "app-layer-event: " - "modbus.invalid_length; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse( - NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Send Modbus invalid PDU Length. */ -static int ModbusParserTest12(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus invalid Length\"; " - "app-layer-event: " - "modbus.invalid_length; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, - invalidLengthPDUWriteMultipleRegistersReq, - sizeof(invalidLengthPDUWriteMultipleRegistersReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Send Modbus Mask Write register request/response. */ -static int ModbusParserTest13(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, maskWriteRegisterReq, - sizeof(maskWriteRegisterReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 22); - FAIL_IF_NOT(rs_modbus_message_get_and_mask(&request) == 0x00F2); - FAIL_IF_NOT(rs_modbus_message_get_or_mask(&request) == 0x0025); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, maskWriteRegisterRsp, - sizeof(maskWriteRegisterRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Send Modbus Write single register request/response. */ -static int ModbusParserTest14(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, writeSingleRegisterReq, - sizeof(writeSingleRegisterReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 6); - FAIL_IF_NOT(rs_modbus_message_get_write_address(&request) == 0x0001); - FAIL_IF_NOT(rs_modbus_message_get_write_data(&request) == 0x0003); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, writeSingleRegisterRsp, - sizeof(writeSingleRegisterRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Send invalid Modbus Mask Write register request. */ -static int ModbusParserTest15(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus invalid Length\"; " - "app-layer-event: " - "modbus.invalid_length; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, invalidMaskWriteRegisterReq, - sizeof(invalidMaskWriteRegisterReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 22); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, maskWriteRegisterRsp, - sizeof(maskWriteRegisterRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - ModbusMessage response = rs_modbus_state_get_tx_response(modbus_state, 0); - FAIL_IF_NULL(response._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&response) == 22); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} - -/** \test Send invalid Modbus Mask Write register request. */ -static int ModbusParserTest16(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus invalid Length\"; " - "app-layer-event: " - "modbus.invalid_length; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, - invalidWriteSingleRegisterReq, - sizeof(invalidWriteSingleRegisterReq)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); - FAIL_IF_NULL(request._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 6); - size_t data_len; - const uint8_t *data = rs_modbus_message_get_bytevec_data(&request, &data_len); - FAIL_IF_NOT(data_len == 2); - FAIL_IF_NOT(data[0] == 0x00); - FAIL_IF_NOT(data[1] == 0x01); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOCLIENT, writeSingleRegisterRsp, - sizeof(writeSingleRegisterRsp)); - FAIL_IF_NOT(r == 0); - - FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); - ModbusMessage response = rs_modbus_state_get_tx_response(modbus_state, 0); - FAIL_IF_NULL(response._0); - - FAIL_IF_NOT(rs_modbus_message_get_function(&response) == 6); - FAIL_IF_NOT(rs_modbus_message_get_write_address(&response) == 0x0001); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS;} - -/** \test Checks if stream_depth is correct */ -static int ModbusParserTest17(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - readCoilsReq, sizeof(readCoilsReq)); - FAIL_IF(r != 0); - - FAIL_IF(f.alstate == NULL); - - FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - readCoilsRsp, sizeof(readCoilsRsp)); - FAIL_IF(r != 0); - - FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/*/ \test Checks if stream depth is correct over 2 TCP packets */ -static int ModbusParserTest18(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - Flow f; - TcpSession ssn; - - uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; - uint8_t *input = readCoilsReq; - - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - input, input_len - part2_len); - FAIL_IF(r != 1); - - FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, - input, input_len); - FAIL_IF(r != 0); - - FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); - - FAIL_IF(f.alstate == NULL); - - input_len = sizeof(readCoilsRsp); - part2_len = 10; - input = readCoilsRsp; - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - input, input_len - part2_len); - FAIL_IF(r != 1); - - FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, - input, input_len); - FAIL_IF(r != 0); - - FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -/** \test Send Modbus invalid function. */ -static int ModbusParserTest19(void) { - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - Packet *p = NULL; - Signature *s = NULL; - TcpSession ssn; - ThreadVars tv; - - FAIL_IF_NULL(alp_tctx); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_MODBUS; - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_MODBUS; - f.flags |= FLOW_IPV4; - - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " - "(msg:\"Modbus invalid Function code\"; " - "app-layer-event: " - "modbus.invalid_function_code; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, - STREAM_TOSERVER, - invalidFunctionCode, - sizeof(invalidFunctionCode)); - FAIL_IF_NOT(r == 0); - - ModbusState *modbus_state = f.alstate; - FAIL_IF_NULL(modbus_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - FAIL_IF_NOT(PacketAlertCheck(p, 1)); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - PASS; -} -#endif /* UNITTESTS */ - -void ModbusParserRegisterTests(void) { -#ifdef UNITTESTS - UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request", - ModbusParserTest01); - UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request", - ModbusParserTest02); - UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request", - ModbusParserTest03); - UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request", - ModbusParserTest04); - UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version", - ModbusParserTest05); - UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response", - ModbusParserTest06); - UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request", - ModbusParserTest07); - UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", - ModbusParserTest08); - UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", - ModbusParserTest09); - UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", - ModbusParserTest10); - UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", - ModbusParserTest11); - UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length", - ModbusParserTest12); - UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request", - ModbusParserTest13); - UtRegisterTest("ModbusParserTest14 - Modbus Write single register request", - ModbusParserTest14); - UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request", - ModbusParserTest15); - UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request", - ModbusParserTest16); - UtRegisterTest("ModbusParserTest17 - Modbus stream depth", - ModbusParserTest17); - UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets", - ModbusParserTest18); - UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code", - ModbusParserTest19); -#endif /* UNITTESTS */ -} diff --git a/src/app-layer-mqtt.c b/src/app-layer-mqtt.c deleted file mode 100644 index 96b4cc27afcc..000000000000 --- a/src/app-layer-mqtt.c +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-misc.h" -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-mqtt.h" -#include "rust.h" - -void RegisterMQTTParsers(void) -{ - SCLogDebug("Registering Rust mqtt parser."); - uint32_t max_msg_len = 1048576; /* default: 1MB */ - - if (AppLayerParserConfParserEnabled("tcp", "mqtt")) { - ConfNode *p = ConfGetNode("app-layer.protocols.mqtt.max-msg-length"); - if (p != NULL) { - uint32_t value; - if (ParseSizeStringU32(p->val, &value) < 0) { - SCLogError("invalid value for max-msg-length: %s", p->val); - } else { - max_msg_len = value; - } - } - rs_mqtt_register_parser(max_msg_len); - } -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_MQTT, - MQTTParserRegisterTests); -#endif -} - -void MQTTParserRegisterTests(void) -{ -#ifdef UNITTESTS -#endif -} diff --git a/src/app-layer-nfs-tcp.c b/src/app-layer-nfs-tcp.c deleted file mode 100644 index e02dd13788f6..000000000000 --- a/src/app-layer-nfs-tcp.c +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (C) 2015-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * NFS application layer detector and parser. - * - * This implements a application layer for the NFS protocol - * running on port 2049. - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-nfs-tcp.h" - -#include "rust.h" - - -static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; -static SuricataFileContext sfc = { &sbcfg }; - -void RegisterNFSTCPParsers(void) -{ - const char *proto_name = "nfs"; - - /* Check if NFSTCP TCP detection is enabled. If it does not exist in - * the configuration file then it will be enabled by default. */ - if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { - - rs_nfs_init(&sfc); - rs_nfs_register_parser(); - } -} diff --git a/src/app-layer-nfs-udp.c b/src/app-layer-nfs-udp.c deleted file mode 100644 index af90c11a758f..000000000000 --- a/src/app-layer-nfs-udp.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2015-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * NFS application layer detector and parser - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-nfs-udp.h" -#include "util-enum.h" - -#include "rust.h" - -/* Enum of app-layer events for an echo protocol. Normally you might - * have events for errors in parsing data, like unexpected data being - * received. For echo we'll make something up, and log an app-layer - * level alert if an empty message is received. - * - * Example rule: - * - * alert nfs any any -> any any (msg:"SURICATA NFS empty message"; \ - * app-layer-event:nfs.empty_message; sid:X; rev:Y;) - */ -enum { - NFS_DECODER_EVENT_EMPTY_MESSAGE, -}; - -SCEnumCharMap nfs_udp_decoder_event_table[] = { - {"EMPTY_MESSAGE", NFS_DECODER_EVENT_EMPTY_MESSAGE}, - { NULL, 0 } -}; - - -static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; -static SuricataFileContext sfc = { &sbcfg }; - -void RegisterNFSUDPParsers(void) -{ - rs_nfs_init(&sfc); - rs_nfs_udp_register_parser(); - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_NFS, - NFSUDPParserRegisterTests); -#endif -} - -#ifdef UNITTESTS -#endif - -void NFSUDPParserRegisterTests(void) -{ -#ifdef UNITTESTS -#endif -} diff --git a/src/app-layer-ntp.c b/src/app-layer-ntp.c deleted file mode 100644 index fa7f95d71124..000000000000 --- a/src/app-layer-ntp.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * - * Parser for NTP application layer running on UDP port 123. - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-ntp.h" -#include "rust.h" - -void RegisterNTPParsers(void) -{ - rs_register_ntp_parser(); - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_NTP, - NTPParserRegisterTests); -#endif -} - -#ifdef UNITTESTS -#endif - -void NTPParserRegisterTests(void) -{ -#ifdef UNITTESTS -#endif -} diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 1f6066471757..2eda09f43aa5 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -34,45 +34,43 @@ #include "stream-tcp.h" -#include "util-validate.h" +#include "util/validate.h" #include "app-layer.h" #include "app-layer-detect-proto.h" -#include "app-layer-ftp.h" -#include "app-layer-smtp.h" - -#include "app-layer-smb.h" -#include "app-layer-htp.h" -#include "app-layer-ssl.h" -#include "app-layer-ssh.h" -#include "app-layer-modbus.h" -#include "app-layer-enip.h" -#include "app-layer-dnp3.h" -#include "app-layer-nfs-tcp.h" -#include "app-layer-nfs-udp.h" -#include "app-layer-ntp.h" -#include "app-layer-tftp.h" -#include "app-layer-ike.h" -#include "app-layer-krb5.h" -#include "app-layer-sip.h" -#include "app-layer-rfb.h" -#include "app-layer-mqtt.h" -#include "app-layer-snmp.h" -#include "app-layer-quic.h" -#include "app-layer-rdp.h" -#include "app-layer-http2.h" +#include "app-layer/ftp/parser.h" +#include "app-layer/smtp/parser.h" + +#include "app-layer/smb/parser.h" +#include "app-layer/http/parser.h" +#include "app-layer/ssl/parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/modbus/parser.h" +#include "app-layer/enip/parser.h" +#include "app-layer/dnp3/parser.h" +#include "app-layer/nfs/parser-tcp.h" +#include "app-layer/nfs/parser-udp.h" +#include "app-layer/ntp/parser.h" +#include "app-layer/tftp/parser.h" +#include "app-layer/ike/parser.h" +#include "app-layer/krb5/parser.h" +#include "app-layer/sip/parser.h" +#include "app-layer/rfb/parser.h" +#include "app-layer/mqtt/parser.h" +#include "app-layer/snmp/parser.h" +#include "app-layer/quic/parser.h" +#include "app-layer/rdp/parser.h" +#include "app-layer/http2/parser.h" struct AppLayerParserThreadCtx_ { void *alproto_local_storage[FLOW_PROTO_MAX][ALPROTO_MAX]; }; - /** * \brief App layer protocol parser context. */ -typedef struct AppLayerParserProtoCtx_ -{ +typedef struct AppLayerParserProtoCtx_ { /* 0 - to_server, 1 - to_client. */ AppLayerParserFPtr Parser[2]; @@ -83,7 +81,7 @@ typedef struct AppLayerParserProtoCtx_ * STREAM_TOSERVER, STREAM_TOCLIENT */ uint8_t first_data_dir; - uint32_t logger_bits; /**< registered loggers for this proto */ + uint32_t logger_bits; /**< registered loggers for this proto */ void *(*StateAlloc)(void *, AppProto); void (*StateFree)(void *); @@ -103,10 +101,9 @@ typedef struct AppLayerParserProtoCtx_ AppLayerGetTxIteratorFunc StateGetTxIterator; int complete_ts; int complete_tc; - int (*StateGetEventInfoById)(int event_id, const char **event_name, - AppLayerEventType *event_type); - int (*StateGetEventInfo)(const char *event_name, - int *event_id, AppLayerEventType *event_type); + int (*StateGetEventInfoById)( + int event_id, const char **event_name, AppLayerEventType *event_type); + int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type); AppLayerStateData *(*GetStateData)(void *state); AppLayerTxData *(*GetTxData)(void *tx); @@ -213,7 +210,8 @@ static inline void AppLayerParserStreamTruncated(AppLayerParserState *pstate, co const AppProto alproto, void *alstate, const uint8_t direction); #ifdef UNITTESTS -void UTHAppLayerParserStateGetIds(void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min) +void UTHAppLayerParserStateGetIds( + void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min) { struct AppLayerParserState_ *s = ptr; *i1 = s->inspect_id[0]; @@ -242,7 +240,7 @@ AppLayerParserState *AppLayerParserStateAlloc(void) if (pstate == NULL) goto end; - end: +end: SCReturnPtr(pstate, "AppLayerParserState"); } @@ -272,8 +270,7 @@ void AppLayerParserPostStreamSetup(void) for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { if (!(alp_ctx.ctxs[flow_proto][alproto].internal_flags & APP_LAYER_PARSER_INT_STREAM_DEPTH_SET)) { - alp_ctx.ctxs[flow_proto][alproto].stream_depth = - stream_config.reassembly_depth; + alp_ctx.ctxs[flow_proto][alproto].stream_depth = stream_config.reassembly_depth; } } } @@ -302,11 +299,11 @@ AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void) uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto); tctx->alproto_local_storage[flow_proto][alproto] = - AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto); + AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto); } } - end: +end: SCReturnPtr(tctx, "void *"); } @@ -318,8 +315,8 @@ void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx) for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto); - AppLayerParserDestroyProtocolParserLocalStorage(ipproto, alproto, - tctx->alproto_local_storage[flow_proto][alproto]); + AppLayerParserDestroyProtocolParserLocalStorage( + ipproto, alproto, tctx->alproto_local_storage[flow_proto][alproto]); } } @@ -330,8 +327,7 @@ void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx) /** \brief check if a parser is enabled in the config * Returns enabled always if: were running unittests */ -int AppLayerParserConfParserEnabled(const char *ipproto, - const char *alproto_name) +int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name) { SCEnter(); @@ -343,8 +339,7 @@ int AppLayerParserConfParserEnabled(const char *ipproto, if (RunmodeIsUnittests()) goto enabled; - r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", - alproto_name, ".enabled"); + r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", alproto_name, ".enabled"); if (r < 0) { FatalError("snprintf failure."); } else if (r > (int)sizeof(param)) { @@ -354,8 +349,8 @@ int AppLayerParserConfParserEnabled(const char *ipproto, node = ConfGetNode(param); if (node == NULL) { SCLogDebug("Entry for %s not found.", param); - r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", - alproto_name, ".", ipproto, ".enabled"); + r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", alproto_name, ".", + ipproto, ".enabled"); if (r < 0) { FatalError("snprintf failure."); } else if (r > (int)sizeof(param)) { @@ -380,39 +375,37 @@ int AppLayerParserConfParserEnabled(const char *ipproto, exit(EXIT_FAILURE); } - disabled: +disabled: enabled = 0; - enabled: +enabled: SCReturnInt(enabled); } /***** Parser related registration *****/ -int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, - uint8_t direction, - AppLayerParserFPtr Parser) +int AppLayerParserRegisterParser( + uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - Parser[(direction & STREAM_TOSERVER) ? 0 : 1] = Parser; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto] + .Parser[(direction & STREAM_TOSERVER) ? 0 : 1] = Parser; SCReturnInt(0); } -void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, - uint8_t direction) +void AppLayerParserRegisterParserAcceptableDataDirection( + uint8_t ipproto, AppProto alproto, uint8_t direction) { SCEnter(); alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].first_data_dir |= - (direction & (STREAM_TOSERVER | STREAM_TOCLIENT)); + (direction & (STREAM_TOSERVER | STREAM_TOCLIENT)); SCReturn; } -void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, - uint32_t flags) +void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, uint32_t flags) { SCEnter(); @@ -432,24 +425,19 @@ 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[FlowGetProtoMapping(ipproto)][alproto].StateAlloc = StateAlloc; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateFree = StateFree; SCReturn; } void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, - void *(*LocalStorageAlloc)(void), - void (*LocalStorageFree)(void *)) + void *(*LocalStorageAlloc)(void), void (*LocalStorageFree)(void *)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageAlloc = - LocalStorageAlloc; - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageFree = - LocalStorageFree; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageAlloc = LocalStorageAlloc; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageFree = LocalStorageFree; SCReturn; } @@ -482,8 +470,8 @@ void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto) SCReturn; } -void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, - void (*Truncate)(void *, uint8_t)) +void AppLayerParserRegisterTruncateFunc( + uint8_t ipproto, AppProto alproto, void (*Truncate)(void *, uint8_t)) { SCEnter(); @@ -493,51 +481,47 @@ void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, } void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, - int (*StateGetProgress)(void *alstate, uint8_t direction)) + int (*StateGetProgress)(void *alstate, uint8_t direction)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetProgress = StateGetProgress; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetProgress = StateGetProgress; SCReturn; } -void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, - void (*StateTransactionFree)(void *, uint64_t)) +void AppLayerParserRegisterTxFreeFunc( + uint8_t ipproto, AppProto alproto, void (*StateTransactionFree)(void *, uint64_t)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateTransactionFree = StateTransactionFree; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateTransactionFree = StateTransactionFree; SCReturn; } -void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, - uint64_t (*StateGetTxCnt)(void *alstate)) +void AppLayerParserRegisterGetTxCnt( + uint8_t ipproto, AppProto alproto, uint64_t (*StateGetTxCnt)(void *alstate)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetTxCnt = StateGetTxCnt; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxCnt = StateGetTxCnt; SCReturn; } -void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, - void *(StateGetTx)(void *alstate, uint64_t tx_id)) +void AppLayerParserRegisterGetTx( + uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetTx = StateGetTx; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTx = StateGetTx; SCReturn; } -void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, - AppLayerGetTxIteratorFunc Func) +void AppLayerParserRegisterGetTxIterator( + uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func) { SCEnter(); alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator = Func; @@ -560,13 +544,13 @@ void AppLayerParserRegisterStateProgressCompletionStatus( } void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, - int (*StateGetEventInfoById)(int event_id, const char **event_name, - AppLayerEventType *event_type)) + int (*StateGetEventInfoById)( + int event_id, const char **event_name, AppLayerEventType *event_type)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetEventInfoById = StateGetEventInfoById; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetEventInfoById = + StateGetEventInfoById; SCReturn; } @@ -582,19 +566,18 @@ void AppLayerParserRegisterGetFrameFuncs(uint8_t ipproto, AppProto alproto, } void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, - int (*StateGetEventInfo)(const char *event_name, int *event_id, - AppLayerEventType *event_type)) + int (*StateGetEventInfo)( + const char *event_name, int *event_id, AppLayerEventType *event_type)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetEventInfo = StateGetEventInfo; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetEventInfo = StateGetEventInfo; SCReturn; } -void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, - AppLayerTxData *(*GetTxData)(void *tx)) +void AppLayerParserRegisterTxDataFunc( + uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx)) { SCEnter(); @@ -623,8 +606,8 @@ void AppLayerParserRegisterApplyTxConfigFunc(uint8_t ipproto, AppProto alproto, SCReturn; } -void AppLayerParserRegisterSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, - void (*SetStreamDepthFlag)(void *tx, uint8_t flags)) +void AppLayerParserRegisterSetStreamDepthFlag( + uint8_t ipproto, AppProto alproto, void (*SetStreamDepthFlag)(void *tx, uint8_t flags)) { SCEnter(); @@ -638,28 +621,22 @@ void AppLayerParserRegisterSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto) { SCEnter(); - void * r = NULL; + void *r = NULL; - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageAlloc != NULL) - { - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageAlloc(); + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageAlloc != NULL) { + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageAlloc(); } SCReturnPtr(r, "void *"); } -void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto, - void *local_data) +void AppLayerParserDestroyProtocolParserLocalStorage( + uint8_t ipproto, AppProto alproto, void *local_data) { SCEnter(); - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageFree != NULL) - { - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageFree(local_data); + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageFree != NULL) { + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageFree(local_data); } SCReturn; @@ -673,14 +650,13 @@ void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto a * * \retval txptr or NULL if no more txs in list */ -static AppLayerGetTxIterTuple AppLayerDefaultGetTxIterator( - const uint8_t ipproto, const AppProto alproto, - void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, +static AppLayerGetTxIterTuple AppLayerDefaultGetTxIterator(const uint8_t ipproto, + const AppProto alproto, void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) { uint64_t ustate = *(uint64_t *)state; uint64_t tx_id = MAX(min_tx_id, ustate); - for ( ; tx_id < max_tx_id; tx_id++) { + for (; tx_id < max_tx_id; tx_id++) { void *tx_ptr = AppLayerParserGetTx(ipproto, alproto, alstate, tx_id); if (tx_ptr != NULL) { ustate = tx_id + 1; @@ -690,7 +666,7 @@ static AppLayerGetTxIterTuple AppLayerDefaultGetTxIterator( .tx_id = tx_id, .has_next = (tx_id + 1 < max_tx_id), }; - SCLogDebug("tuple: %p/%"PRIu64"/%s", tuple.tx_ptr, tuple.tx_id, + SCLogDebug("tuple: %p/%" PRIu64 "/%s", tuple.tx_ptr, tuple.tx_id, tuple.has_next ? "true" : "false"); return tuple; } @@ -700,11 +676,10 @@ static AppLayerGetTxIterTuple AppLayerDefaultGetTxIterator( return no_tuple; } -AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, - const AppProto alproto) +AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, const AppProto alproto) { AppLayerGetTxIteratorFunc Func = - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator; return Func ? Func : AppLayerDefaultGetTxIterator; } @@ -737,12 +712,12 @@ uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint inline uint64_t AppLayerParserGetTxDetectFlags(AppLayerTxData *txd, const uint8_t dir) { - uint64_t detect_flags = - (dir & STREAM_TOSERVER) ? txd->detect_flags_ts : txd->detect_flags_tc; + uint64_t detect_flags = (dir & STREAM_TOSERVER) ? txd->detect_flags_ts : txd->detect_flags_tc; return detect_flags; } -static inline void SetTxDetectFlags(AppLayerTxData *txd, const uint8_t dir, const uint64_t detect_flags) +static inline void SetTxDetectFlags( + AppLayerTxData *txd, const uint8_t dir, const uint64_t detect_flags) { if (dir & STREAM_TOSERVER) { txd->detect_flags_ts = detect_flags; @@ -757,15 +732,15 @@ static inline uint32_t GetTxLogged(AppLayerTxData *txd) } void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *pstate, - void *alstate, const uint8_t flags, - bool tag_txs_as_inspected) + void *alstate, const uint8_t flags, bool tag_txs_as_inspected) { SCEnter(); const int direction = (flags & STREAM_TOSERVER) ? 0 : 1; const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate); uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, flags); - const int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags); + const int state_done_progress = + AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags); const uint8_t ipproto = f->proto; const AppProto alproto = f->alproto; @@ -773,8 +748,8 @@ void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *p AppLayerGetTxIterState state; memset(&state, 0, sizeof(state)); - SCLogDebug("called: %s, tag_txs_as_inspected %s",direction==0?"toserver":"toclient", - tag_txs_as_inspected?"true":"false"); + SCLogDebug("called: %s, tag_txs_as_inspected %s", direction == 0 ? "toserver" : "toclient", + tag_txs_as_inspected ? "true" : "false"); /* mark all txs as inspected if the applayer progress is * at the 'end state'. */ @@ -796,7 +771,7 @@ void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *p if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) { detect_flags |= APP_LAYER_TX_INSPECTED_FLAG; SetTxDetectFlags(txd, flags, detect_flags); - SCLogDebug("%p/%"PRIu64" in-order tx is done for direction %s. Flag %016"PRIx64, + SCLogDebug("%p/%" PRIu64 " in-order tx is done for direction %s. Flag %016" PRIx64, tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags); } } @@ -805,14 +780,15 @@ void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *p break; } pstate->inspect_id[direction] = idx; - SCLogDebug("inspect_id now %"PRIu64, pstate->inspect_id[direction]); + SCLogDebug("inspect_id now %" PRIu64, pstate->inspect_id[direction]); /* if necessary we flag all txs that are complete as 'inspected' * also move inspect_id forward. */ if (tag_txs_as_inspected) { /* continue at idx */ while (1) { - AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, idx, total_txs, &state); + AppLayerGetTxIterTuple ires = + IterFunc(ipproto, alproto, alstate, idx, total_txs, &state); if (ires.tx_ptr == NULL) break; @@ -836,16 +812,18 @@ void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *p if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) { detect_flags |= APP_LAYER_TX_INSPECTED_FLAG; SetTxDetectFlags(txd, flags, detect_flags); - SCLogDebug("%p/%"PRIu64" out of order tx is done for direction %s. Flag %016"PRIx64, - tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags); - - SCLogDebug("%p/%"PRIu64" out of order tx. Update inspect_id? %"PRIu64, - tx, idx, pstate->inspect_id[direction]); - if (pstate->inspect_id[direction]+1 == idx) + SCLogDebug("%p/%" PRIu64 + " out of order tx is done for direction %s. Flag %016" PRIx64, + tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", + detect_flags); + + SCLogDebug("%p/%" PRIu64 " out of order tx. Update inspect_id? %" PRIu64, tx, + idx, pstate->inspect_id[direction]); + if (pstate->inspect_id[direction] + 1 == idx) pstate->inspect_id[direction] = idx; } } else { - if (pstate->inspect_id[direction]+1 == idx) + if (pstate->inspect_id[direction] + 1 == idx) pstate->inspect_id[direction] = idx; } if (!ires.has_next) @@ -861,8 +839,7 @@ AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstat { SCEnter(); - SCReturnPtr(pstate->decoder_events, - "AppLayerDecoderEvents *"); + SCReturnPtr(pstate->decoder_events, "AppLayerDecoderEvents *"); } void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoderEvents *devents) @@ -870,8 +847,7 @@ void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoder pstate->decoder_events = devents; } -AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, - void *tx) +AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx) { SCEnter(); @@ -929,8 +905,8 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) const bool has_tx_detect_flags = !g_detect_disabled; const uint8_t ipproto = f->proto; const AppProto alproto = f->alproto; - void * const alstate = f->alstate; - AppLayerParserState * const alparser = f->alparser; + void *const alstate = f->alstate; + AppLayerParserState *const alparser = f->alparser; if (alstate == NULL || alparser == NULL) SCReturn; @@ -938,8 +914,10 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) const uint64_t min = alparser->min_id; const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate); const LoggerId logger_expectation = AppLayerParserProtocolGetLoggerBits(ipproto, alproto); - const int tx_end_state_ts = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); - const int tx_end_state_tc = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); + const int tx_end_state_ts = + AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); + const int tx_end_state_tc = + AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); const uint8_t ts_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOSERVER); const uint8_t tc_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOCLIENT); @@ -950,7 +928,7 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) memset(&state, 0, sizeof(state)); uint64_t i = min; uint64_t new_min = min; - SCLogDebug("start min %"PRIu64, min); + SCLogDebug("start min %" PRIu64, min); bool skipped = false; // const bool support_files = AppLayerParserSupportsFiles(f->proto, f->alproto); @@ -963,7 +941,7 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) void *tx = ires.tx_ptr; i = ires.tx_id; // actual tx id for the tx the IterFunc returned - SCLogDebug("%p/%"PRIu64" checking", tx, i); + SCLogDebug("%p/%" PRIu64 " checking", tx, i); AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx); if (txd != NULL && AppLayerParserHasFilesInDir(txd, pkt_dir)) { if (pkt_dir_trunc == -1) @@ -978,14 +956,14 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) const int tx_progress_tc = AppLayerParserGetStateProgress(ipproto, alproto, tx, tc_disrupt_flags); if (tx_progress_tc < tx_end_state_tc) { - SCLogDebug("%p/%"PRIu64" skipping: tc parser not done", tx, i); + SCLogDebug("%p/%" PRIu64 " skipping: tc parser not done", tx, i); skipped = true; goto next; } const int tx_progress_ts = AppLayerParserGetStateProgress(ipproto, alproto, tx, ts_disrupt_flags); if (tx_progress_ts < tx_end_state_ts) { - SCLogDebug("%p/%"PRIu64" skipping: ts parser not done", tx, i); + SCLogDebug("%p/%" PRIu64 " skipping: ts parser not done", tx, i); skipped = true; goto next; } @@ -1020,7 +998,8 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) if (txd && logger_expectation != 0) { LoggerId tx_logged = GetTxLogged(txd); if (tx_logged != logger_expectation) { - SCLogDebug("%p/%"PRIu64" skipping: logging not done: want:%"PRIx32", have:%"PRIx32, + SCLogDebug("%p/%" PRIu64 " skipping: logging not done: want:%" PRIx32 + ", have:%" PRIx32, tx, i, logger_expectation, tx_logged); skipped = true; goto next; @@ -1047,24 +1026,26 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) /* if we are here, the tx can be freed. */ p->StateTransactionFree(alstate, i); - SCLogDebug("%p/%"PRIu64" freed", tx, i); + SCLogDebug("%p/%" PRIu64 " freed", tx, i); /* if we didn't skip any tx so far, up the minimum */ - SCLogDebug("skipped? %s i %"PRIu64", new_min %"PRIu64, skipped ? "true" : "false", i, new_min); + SCLogDebug("skipped? %s i %" PRIu64 ", new_min %" PRIu64, skipped ? "true" : "false", i, + new_min); if (!skipped) new_min = i + 1; - SCLogDebug("final i %"PRIu64", new_min %"PRIu64, i, new_min); + SCLogDebug("final i %" PRIu64 ", new_min %" PRIu64, i, new_min); -next: + next: if (!ires.has_next) { /* this was the last tx. See if we skipped any. If not * we removed all and can update the minimum to the max * id. */ - SCLogDebug("no next: cur tx i %"PRIu64", total %"PRIu64, i, total_txs); + SCLogDebug("no next: cur tx i %" PRIu64 ", total %" PRIu64, i, total_txs); if (!skipped) { new_min = total_txs; - SCLogDebug("no next: cur tx i %"PRIu64", total %"PRIu64": " - "new_min updated to %"PRIu64, i, total_txs, new_min); + SCLogDebug("no next: cur tx i %" PRIu64 ", total %" PRIu64 ": " + "new_min updated to %" PRIu64, + i, total_txs, new_min); } break; } @@ -1072,14 +1053,14 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) } /* see if we need to bring all trackers up to date. */ - SCLogDebug("update f->alparser->min_id? %"PRIu64" vs %"PRIu64, new_min, alparser->min_id); + SCLogDebug("update f->alparser->min_id? %" PRIu64 " vs %" PRIu64, new_min, alparser->min_id); if (new_min > alparser->min_id) { const uint64_t next_id = new_min; alparser->min_id = next_id; alparser->inspect_id[0] = MAX(alparser->inspect_id[0], next_id); alparser->inspect_id[1] = MAX(alparser->inspect_id[1], next_id); alparser->log_id = MAX(alparser->log_id, next_id); - SCLogDebug("updated f->alparser->min_id %"PRIu64, alparser->min_id); + SCLogDebug("updated f->alparser->min_id %" PRIu64, alparser->min_id); } SCReturn; } @@ -1101,8 +1082,7 @@ static inline int StateGetProgressCompletionStatus(const AppProto alproto, const * * If the stream is disrupted, we return the 'completion' value. */ -int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, - void *alstate, uint8_t flags) +int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t flags) { SCEnter(); int r; @@ -1130,8 +1110,7 @@ void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint SCReturnPtr(r, "void *"); } -int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, - uint8_t direction) +int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction) { SCEnter(); int r = StateGetProgressCompletionStatus(alproto, direction); @@ -1139,23 +1118,27 @@ int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, } int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *event_name, - int *event_id, AppLayerEventType *event_type) + int *event_id, AppLayerEventType *event_type) { 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[ipproto_map][alproto].StateGetEventInfo == NULL) + ? -1 + : alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfo( + event_name, event_id, event_type); SCReturnInt(r); } int AppLayerParserGetEventInfoById(uint8_t ipproto, AppProto alproto, int event_id, - const char **event_name, AppLayerEventType *event_type) + const char **event_name, AppLayerEventType *event_type) { 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[ipproto_map][alproto].StateGetEventInfoById == NULL) + ? -1 + : alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfoById( + event_id, event_name, event_type); SCReturnInt(r); } @@ -1166,8 +1149,8 @@ uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto) SCReturnCT(r, "uint8_t"); } -uint64_t AppLayerParserGetTransactionActive(const Flow *f, - AppLayerParserState *pstate, uint8_t direction) +uint64_t AppLayerParserGetTransactionActive( + const Flow *f, AppLayerParserState *pstate, uint8_t direction) { SCEnter(); @@ -1211,8 +1194,8 @@ AppLayerStateData *AppLayerParserGetStateData(uint8_t ipproto, AppProto alproto, SCReturnPtr(NULL, "AppLayerStateData"); } -void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto, - void *state, void *tx, enum ConfigAction mode, AppLayerTxConfig config) +void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto, void *state, void *tx, + enum ConfigAction mode, AppLayerTxConfig config) { SCEnter(); const int ipproto_map = FlowGetProtoMapping(ipproto); @@ -1226,10 +1209,10 @@ void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto, static inline void SetEOFFlags(AppLayerParserState *pstate, const uint8_t flags) { - if ((flags & (STREAM_EOF|STREAM_TOSERVER)) == (STREAM_EOF|STREAM_TOSERVER)) { + if ((flags & (STREAM_EOF | STREAM_TOSERVER)) == (STREAM_EOF | STREAM_TOSERVER)) { SCLogDebug("setting APP_LAYER_PARSER_EOF_TS"); AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF_TS); - } else if ((flags & (STREAM_EOF|STREAM_TOCLIENT)) == (STREAM_EOF|STREAM_TOCLIENT)) { + } else if ((flags & (STREAM_EOF | STREAM_TOCLIENT)) == (STREAM_EOF | STREAM_TOCLIENT)) { SCLogDebug("setting APP_LAYER_PARSER_EOF_TC"); AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF_TC); } @@ -1301,8 +1284,8 @@ static void Setup(Flow *f, const uint8_t direction, const uint8_t *input, uint32 /** \retval int -1 in case of unrecoverable error. App-layer tracking stops for this flow. * \retval int 0 ok: we did not update app_progress * \retval int 1 ok: we updated app_progress */ -int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, - uint8_t flags, const uint8_t *input, uint32_t input_len) +int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, + AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len) { SCEnter(); #ifdef DEBUG_VALIDATION @@ -1353,8 +1336,8 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow AppLayerIncAllocErrorCounter(tv, f); goto error; } - SCLogDebug("alloced new app layer state %p (name %s)", - alstate, AppLayerGetProtoName(f->alproto)); + SCLogDebug("alloced new app layer state %p (name %s)", alstate, + AppLayerGetProtoName(f->alproto)); /* set flow flags to state */ if (f->file_flags != 0) { @@ -1368,8 +1351,8 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow } } } else { - SCLogDebug("using existing app layer state %p (name %s))", - alstate, AppLayerGetProtoName(f->alproto)); + SCLogDebug("using existing app layer state %p (name %s))", alstate, + AppLayerGetProtoName(f->alproto)); } p_tx_cnt = AppLayerParserGetTxCnt(f, f->alstate); @@ -1467,7 +1450,8 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow } /* In cases like HeartBleed for TLS we need to inspect AppLayer but not Payload */ - if (!(f->flags & FLOW_NOPAYLOAD_INSPECTION) && pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) { + if (!(f->flags & FLOW_NOPAYLOAD_INSPECTION) && + pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) { FlowSetNoPayloadInspectionFlag(f); /* Set the no reassembly flag for both the stream in this TcpSession */ if (f->proto == IPPROTO_TCP) { @@ -1490,7 +1474,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow if (flags & STREAM_DEPTH) AppLayerParserStreamTruncated(pstate, f->proto, alproto, f->alstate, flags); - end: +end: /* update app progress */ if (consumed != input_len && f->proto == IPPROTO_TCP && f->protoctx != NULL) { TcpSession *ssn = f->protoctx; @@ -1499,7 +1483,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow } SCReturnInt(0); - error: +error: /* Set the no app layer inspection flag for both * the stream in this Flow */ if (f->proto == IPPROTO_TCP) { @@ -1517,9 +1501,9 @@ void AppLayerParserSetEOF(AppLayerParserState *pstate) goto end; SCLogDebug("setting APP_LAYER_PARSER_EOF_TC and APP_LAYER_PARSER_EOF_TS"); - AppLayerParserStateSetFlag(pstate, (APP_LAYER_PARSER_EOF_TS|APP_LAYER_PARSER_EOF_TC)); + AppLayerParserStateSetFlag(pstate, (APP_LAYER_PARSER_EOF_TS | APP_LAYER_PARSER_EOF_TC)); - end: +end: SCReturn; } @@ -1586,7 +1570,7 @@ void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t st 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; + APP_LAYER_PARSER_INT_STREAM_DEPTH_SET; SCReturn; } @@ -1596,7 +1580,8 @@ uint32_t AppLayerParserGetStreamDepth(const Flow *f) SCReturnInt(alp_ctx.ctxs[f->protomap][f->alproto].stream_depth); } -void AppLayerParserSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void *state, uint64_t tx_id, uint8_t flags) +void AppLayerParserSetStreamDepthFlag( + uint8_t ipproto, AppProto alproto, void *state, uint64_t tx_id, uint8_t flags) { SCEnter(); void *tx = NULL; @@ -1658,25 +1643,27 @@ static void ValidateParserProtoDump(AppProto alproto, uint8_t ipproto) const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[map][alproto]; 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); - printf("- first_data_dir %"PRIx8"\n", ctx->first_data_dir); + printf("- option flags %" PRIx32 "\n", ctx->option_flags); + printf("- first_data_dir %" PRIx8 "\n", ctx->first_data_dir); printf("Mandatory:\n"); printf("- Parser[0] %p Parser[1] %p\n", ctx->Parser[0], ctx->Parser[1]); printf("- StateAlloc %p StateFree %p\n", ctx->StateAlloc, ctx->StateFree); - printf("- StateGetTx %p StateGetTxCnt %p StateTransactionFree %p\n", - ctx->StateGetTx, ctx->StateGetTxCnt, ctx->StateTransactionFree); + printf("- StateGetTx %p StateGetTxCnt %p StateTransactionFree %p\n", ctx->StateGetTx, + ctx->StateGetTxCnt, ctx->StateTransactionFree); printf("- GetTxData %p\n", ctx->GetTxData); printf("- GetStateData %p\n", ctx->GetStateData); printf("- StateGetProgress %p\n", ctx->StateGetProgress); printf("Optional:\n"); - printf("- LocalStorageAlloc %p LocalStorageFree %p\n", ctx->LocalStorageAlloc, ctx->LocalStorageFree); + printf("- LocalStorageAlloc %p LocalStorageFree %p\n", ctx->LocalStorageAlloc, + ctx->LocalStorageFree); printf("- StateGetEventInfo %p StateGetEventInfoById %p\n", ctx->StateGetEventInfo, ctx->StateGetEventInfoById); } -#define BOTH_SET(a, b) ((a) != NULL && (b) != NULL) +#define BOTH_SET(a, b) ((a) != NULL && (b) != NULL) #define BOTH_SET_OR_BOTH_UNSET(a, b) (((a) == NULL && (b) == NULL) || ((a) != NULL && (b) != NULL)) -#define THREE_SET_OR_THREE_UNSET(a, b, c) (((a) == NULL && (b) == NULL && (c) == NULL) || ((a) != NULL && (b) != NULL && (c) != NULL)) +#define THREE_SET_OR_THREE_UNSET(a, b, c) \ + (((a) == NULL && (b) == NULL && (c) == NULL) || ((a) != NULL && (b) != NULL && (c) != NULL)) #define THREE_SET(a, b, c) ((a) != NULL && (b) != NULL && (c) != NULL) static void ValidateParserProto(AppProto alproto, uint8_t ipproto) @@ -1728,7 +1715,7 @@ static void ValidateParser(AppProto alproto) static void ValidateParsers(void) { AppProto p = 0; - for ( ; p < ALPROTO_MAX; p++) { + for (; p < ALPROTO_MAX; p++) { ValidateParser(p); } } @@ -1775,22 +1762,19 @@ void AppLayerParserRegisterProtocolParsers(void) /** IMAP */ AppLayerProtoDetectRegisterProtocol(ALPROTO_IMAP, "imap"); if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "imap")) { - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_IMAP, - "1|20|capability", 12, 0, STREAM_TOSERVER) < 0) - { + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_IMAP, "1|20|capability", 12, 0, STREAM_TOSERVER) < 0) { SCLogInfo("imap proto registration failure"); exit(EXIT_FAILURE); } } else { - SCLogInfo("Protocol detection and parser disabled for %s protocol.", - "imap"); + SCLogInfo("Protocol detection and parser disabled for %s protocol.", "imap"); } ValidateParsers(); return; } - /* coccinelle: AppLayerParserStateSetFlag():2,2:APP_LAYER_PARSER_ */ void AppLayerParserStateSetFlag(AppLayerParserState *pstate, uint16_t flag) { @@ -1834,12 +1818,11 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) AppLayerParserState *p = pstate; SCLogDebug("AppLayerParser parser state information for parser state p(%p). " - "p->inspect_id[0](%"PRIu64"), " - "p->inspect_id[1](%"PRIu64"), " - "p->log_id(%"PRIu64"), " + "p->inspect_id[0](%" PRIu64 "), " + "p->inspect_id[1](%" PRIu64 "), " + "p->log_id(%" PRIu64 "), " "p->decoder_events(%p).", - pstate, p->inspect_id[0], p->inspect_id[1], p->log_id, - p->decoder_events); + pstate, p->inspect_id[0], p->inspect_id[1], p->log_id, p->decoder_events); SCReturn; } @@ -1848,7 +1831,7 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) /***** Unittests *****/ #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" static AppLayerParserCtx alp_ctx_backup_unittest; @@ -1876,7 +1859,7 @@ static void *TestProtocolStateAlloc(void *orig_state, AppProto proto_orig) if (unlikely(s == NULL)) goto end; memset(s, 0, sizeof(TestState)); - end: +end: SCReturnPtr(s, "TestState"); } @@ -1904,12 +1887,11 @@ static void *TestGetTx(void *state, uint64_t tx_id) return test_state; } -void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, - void (*RegisterUnittests)(void)) +void AppLayerParserRegisterProtocolUnittests( + uint8_t ipproto, AppProto alproto, void (*RegisterUnittests)(void)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - RegisterUnittests = RegisterUnittests; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].RegisterUnittests = RegisterUnittests; SCReturn; } @@ -1947,8 +1929,8 @@ static int AppLayerParserTest01(void) /* Register the Test protocol state and parser functions */ AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEST, STREAM_TOSERVER, TestProtocolParser); - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEST, - TestProtocolStateAlloc, TestProtocolStateFree); + AppLayerParserRegisterStateFuncs( + IPPROTO_TCP, ALPROTO_TEST, TestProtocolStateAlloc, TestProtocolStateFree); AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEST, TestStateTransactionFree); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEST, TestGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEST, TestGetTxCnt); @@ -1961,9 +1943,8 @@ static int AppLayerParserTest01(void) StreamTcpInitConfig(true); - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, - STREAM_TOSERVER | STREAM_EOF, testbuf, - testlen); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER | STREAM_EOF, testbuf, testlen); FAIL_IF(r != -1); FAIL_IF(!(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); @@ -1988,10 +1969,9 @@ static int AppLayerParserTest02(void) AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); /* Register the Test protocol state and parser functions */ - AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TEST, STREAM_TOSERVER, - TestProtocolParser); - AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_TEST, - TestProtocolStateAlloc, TestProtocolStateFree); + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TEST, STREAM_TOSERVER, TestProtocolParser); + AppLayerParserRegisterStateFuncs( + IPPROTO_UDP, ALPROTO_TEST, TestProtocolStateAlloc, TestProtocolStateFree); AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_TEST, TestStateTransactionFree); AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_TEST, TestGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_TEST, TestGetTxCnt); @@ -2004,9 +1984,8 @@ static int AppLayerParserTest02(void) StreamTcpInitConfig(true); - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, - STREAM_TOSERVER | STREAM_EOF, testbuf, - testlen); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER | STREAM_EOF, testbuf, testlen); FAIL_IF(r != -1); AppLayerParserRestoreParserTable(); @@ -2015,7 +1994,6 @@ static int AppLayerParserTest02(void) PASS; } - void AppLayerParserRegisterUnittests(void) { SCEnter(); diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index e9f8cf55e925..66bae5bfa308 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -26,9 +26,9 @@ #define __APP_LAYER_PARSER_H__ #include "app-layer-events.h" -#include "util-file.h" +#include "util/file.h" #include "rust.h" -#include "util-config.h" +#include "util/config.h" /* Flags for AppLayerParserState. */ // flag available BIT_U16(0) @@ -46,7 +46,7 @@ /* Flags for AppLayerParserProtoCtx. */ #define APP_LAYER_PARSER_OPT_ACCEPT_GAPS BIT_U32(0) -#define APP_LAYER_PARSER_INT_STREAM_DEPTH_SET BIT_U32(0) +#define APP_LAYER_PARSER_INT_STREAM_DEPTH_SET BIT_U32(0) /* applies to DetectFlags uint64_t field */ @@ -78,18 +78,26 @@ /** should inspection be skipped in that direction */ #define APP_LAYER_TX_SKIP_INSPECT_FLAG BIT_U64(62) /** is tx fully inspected? */ -#define APP_LAYER_TX_INSPECTED_FLAG BIT_U64(63) +#define APP_LAYER_TX_INSPECTED_FLAG BIT_U64(63) /** other 63 bits are for tracking which prefilter engine is already * completely inspected */ #define APP_LAYER_TX_PREFILTER_MASK ~(APP_LAYER_TX_INSPECTED_FLAG | APP_LAYER_TX_RESERVED_FLAGS) /** parser has successfully processed in the input, and has consumed * all of it. */ -#define APP_LAYER_OK (AppLayerResult) { 0, 0, 0 } +#define APP_LAYER_OK \ + (AppLayerResult) \ + { \ + 0, 0, 0 \ + } /** parser has hit an unrecoverable error. Returning this to the API * leads to no further calls to the parser. */ -#define APP_LAYER_ERROR (AppLayerResult) { -1, 0, 0 } +#define APP_LAYER_ERROR \ + (AppLayerResult) \ + { \ + -1, 0, 0 \ + } /** parser needs more data. Through 'c' it will indicate how many * of the input bytes it has consumed. Through 'n' it will indicate @@ -97,7 +105,11 @@ * \note consumed (c) should never be more than the input len * needed (n) + consumed (c) should be more than the input len */ -#define APP_LAYER_INCOMPLETE(c,n) (AppLayerResult) { 1, (c), (n) } +#define APP_LAYER_INCOMPLETE(c, n) \ + (AppLayerResult) \ + { \ + 1, (c), (n) \ + } int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto); @@ -134,8 +146,7 @@ void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx); * \retval 1 If enabled. * \retval 0 If disabled. */ -int AppLayerParserConfParserEnabled(const char *ipproto, - const char *alproto_name); +int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name); /** \brief Prototype for parsing functions */ typedef AppLayerResult (*AppLayerParserFPtr)(Flow *f, void *protocol_state, @@ -149,9 +160,8 @@ typedef struct AppLayerGetTxIterState { } AppLayerGetTxIterState; /** \brief tx iterator prototype */ -typedef AppLayerGetTxIterTuple (*AppLayerGetTxIteratorFunc) - (const uint8_t ipproto, const AppProto alproto, - void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, +typedef AppLayerGetTxIterTuple (*AppLayerGetTxIteratorFunc)(const uint8_t ipproto, + const AppProto alproto, void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state); /***** Parser related registration *****/ @@ -165,14 +175,11 @@ typedef const char *(*AppLayerParserGetFrameNameByIdFn)(const uint8_t id); * \retval 0 On success. * \retval -1 On failure. */ -int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, - uint8_t direction, - AppLayerParserFPtr Parser); -void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, - AppProto alproto, - uint8_t direction); -void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, - uint32_t flags); +int AppLayerParserRegisterParser( + uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser); +void AppLayerParserRegisterParserAcceptableDataDirection( + uint8_t ipproto, AppProto alproto, uint8_t direction); +void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, uint32_t flags); void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void (*StateFree)(void *)); void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto proto, @@ -183,34 +190,34 @@ void AppLayerParserRegisterGetTxFilesFunc(uint8_t ipproto, AppProto alproto, AppLayerGetFileState (*GetTxFiles)(void *, void *, uint8_t)); void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto); void AppLayerParserRegisterLoggerBits(uint8_t ipproto, AppProto alproto, LoggerId bits); -void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, - void (*Truncate)(void *, uint8_t)); +void AppLayerParserRegisterTruncateFunc( + uint8_t ipproto, AppProto alproto, void (*Truncate)(void *, uint8_t)); void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, - int (*StateGetStateProgress)(void *alstate, uint8_t direction)); -void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, - void (*StateTransactionFree)(void *, uint64_t)); -void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, - uint64_t (*StateGetTxCnt)(void *alstate)); -void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, - void *(StateGetTx)(void *alstate, uint64_t tx_id)); -void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, - AppLayerGetTxIteratorFunc Func); + int (*StateGetStateProgress)(void *alstate, uint8_t direction)); +void AppLayerParserRegisterTxFreeFunc( + uint8_t ipproto, AppProto alproto, void (*StateTransactionFree)(void *, uint64_t)); +void AppLayerParserRegisterGetTxCnt( + uint8_t ipproto, AppProto alproto, uint64_t (*StateGetTxCnt)(void *alstate)); +void AppLayerParserRegisterGetTx( + uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id)); +void AppLayerParserRegisterGetTxIterator( + uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func); void AppLayerParserRegisterStateProgressCompletionStatus( AppProto alproto, const int ts, const int tc); void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, - int (*StateGetEventInfo)(const char *event_name, int *event_id, - AppLayerEventType *event_type)); + int (*StateGetEventInfo)( + const char *event_name, int *event_id, AppLayerEventType *event_type)); void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, - int (*StateGetEventInfoById)(int event_id, const char **event_name, - AppLayerEventType *event_type)); + int (*StateGetEventInfoById)( + int event_id, const char **event_name, AppLayerEventType *event_type)); void AppLayerParserRegisterGetFrameFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetFrameIdByNameFn GetFrameIdByName, AppLayerParserGetFrameNameByIdFn GetFrameNameById); -void AppLayerParserRegisterSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, - void (*SetStreamDepthFlag)(void *tx, uint8_t flags)); +void AppLayerParserRegisterSetStreamDepthFlag( + uint8_t ipproto, AppProto alproto, void (*SetStreamDepthFlag)(void *tx, uint8_t flags)); -void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, - AppLayerTxData *(*GetTxData)(void *tx)); +void AppLayerParserRegisterTxDataFunc( + uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx)); void AppLayerParserRegisterApplyTxConfigFunc(uint8_t ipproto, AppProto alproto, bool (*ApplyTxConfig)(void *state, void *tx, int mode, AppLayerTxConfig)); void AppLayerParserRegisterStateDataFunc( @@ -219,37 +226,36 @@ void AppLayerParserRegisterStateDataFunc( /***** Get and transaction functions *****/ uint32_t AppLayerParserGetOptionFlags(uint8_t protomap, AppProto alproto); -AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, - const AppProto alproto); +AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, const AppProto alproto); void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto); -void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto, - void *local_data); - +void AppLayerParserDestroyProtocolParserLocalStorage( + uint8_t ipproto, AppProto alproto, void *local_data); uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate); void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id); uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction); void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *pstate, - void *alstate, const uint8_t flags, bool tag_txs_as_inspected); + void *alstate, const uint8_t flags, bool tag_txs_as_inspected); AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate); void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoderEvents *devents); AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *tx); AppLayerGetFileState AppLayerParserGetTxFiles( const Flow *f, void *state, void *tx, const uint8_t direction); -int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, - void *alstate, uint8_t direction); +int AppLayerParserGetStateProgress( + uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction); uint64_t AppLayerParserGetTxCnt(const Flow *, void *alstate); void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id); int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction); int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *event_name, - int *event_id, AppLayerEventType *event_type); + int *event_id, AppLayerEventType *event_type); int AppLayerParserGetEventInfoById(uint8_t ipproto, AppProto alproto, int event_id, - const char **event_name, AppLayerEventType *event_type); + const char **event_name, AppLayerEventType *event_type); -uint64_t AppLayerParserGetTransactionActive(const Flow *f, AppLayerParserState *pstate, uint8_t direction); +uint64_t AppLayerParserGetTransactionActive( + const Flow *f, AppLayerParserState *pstate, uint8_t direction); uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto); @@ -258,8 +264,8 @@ bool AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto); AppLayerTxData *AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx); uint64_t AppLayerParserGetTxDetectFlags(AppLayerTxData *txd, const uint8_t dir); AppLayerStateData *AppLayerParserGetStateData(uint8_t ipproto, AppProto alproto, void *state); -void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto, - void *state, void *tx, enum ConfigAction mode, AppLayerTxConfig); +void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto, void *state, void *tx, + enum ConfigAction mode, AppLayerTxConfig); static inline bool AppLayerParserIsFileTx(const AppLayerTxData *txd) { @@ -286,7 +292,7 @@ static inline bool AppLayerParserHasFilesInDir(const AppLayerTxData *txd, const /***** General *****/ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *tctx, Flow *f, AppProto alproto, - uint8_t flags, const uint8_t *input, uint32_t input_len); + uint8_t flags, const uint8_t *input, uint32_t input_len); void AppLayerParserSetEOF(AppLayerParserState *pstate); bool AppLayerParserHasDecoderEvents(AppLayerParserState *pstate); int AppLayerParserProtocolHasLogger(uint8_t ipproto, AppProto alproto); @@ -294,7 +300,8 @@ LoggerId AppLayerParserProtocolGetLoggerBits(uint8_t ipproto, AppProto alproto); void AppLayerParserTriggerRawStreamReassembly(Flow *f, int direction); void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t stream_depth); uint32_t AppLayerParserGetStreamDepth(const Flow *f); -void AppLayerParserSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void *state, uint64_t tx_id, uint8_t flags); +void AppLayerParserSetStreamDepthFlag( + uint8_t ipproto, AppProto alproto, void *state, uint64_t tx_id, uint8_t flags); int AppLayerParserIsEnabled(AppProto alproto); int AppLayerParserGetFrameIdByName(uint8_t ipproto, AppProto alproto, const char *name); const char *AppLayerParserGetFrameNameById(uint8_t ipproto, AppProto alproto, const uint8_t id); @@ -319,16 +326,16 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir); void AppLayerParserStatePrintDetails(AppLayerParserState *pstate); #endif - /***** Unittests *****/ #ifdef UNITTESTS -void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, - void (*RegisterUnittests)(void)); +void AppLayerParserRegisterProtocolUnittests( + uint8_t ipproto, AppProto alproto, void (*RegisterUnittests)(void)); void AppLayerParserRegisterUnittests(void); void AppLayerParserBackupParserTable(void); void AppLayerParserRestoreParserTable(void); -void UTHAppLayerParserStateGetIds(void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min); +void UTHAppLayerParserStateGetIds( + void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min); #endif void AppLayerFramesFreeContainer(Flow *f); diff --git a/src/app-layer-quic.c b/src/app-layer-quic.c deleted file mode 100644 index 837aa9c49632..000000000000 --- a/src/app-layer-quic.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * Quic Application Layer - * - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-quic.h" -#include "rust.h" - -void RegisterQuicParsers(void) -{ - rs_quic_register_parser(); -} diff --git a/src/app-layer-rdp.c b/src/app-layer-rdp.c deleted file mode 100644 index 2611de4237b0..000000000000 --- a/src/app-layer-rdp.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Zach Kelly - * - * Application layer parser for RDP - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" -#include "util-unittest.h" -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" -#include "app-layer-rdp.h" -#include "rust.h" - -void RegisterRdpParsers(void) { - SCLogDebug("Registering rdp parser"); - rs_rdp_register_parser(); -} diff --git a/src/app-layer-register.c b/src/app-layer-register.c index c4441d9f7c5b..4f055b5c2efd 100644 --- a/src/app-layer-register.c +++ b/src/app-layer-register.c @@ -33,7 +33,7 @@ #include "app-layer-register.h" -static const char * IpProtoToString(int ip_proto); +static const char *IpProtoToString(int ip_proto); AppProto AppLayerRegisterProtocolDetection(const struct AppLayerParser *p, int enable_default) { @@ -65,30 +65,24 @@ AppProto AppLayerRegisterProtocolDetection(const struct AppLayerParser *p, int e if (RunmodeIsUnittests()) { SCLogDebug("Unittest mode, registering default configuration."); - AppLayerProtoDetectPPRegister(p->ip_proto, p->default_port, - alproto, p->min_depth, p->max_depth, STREAM_TOSERVER, - p->ProbeTS, p->ProbeTC); + AppLayerProtoDetectPPRegister(p->ip_proto, p->default_port, alproto, p->min_depth, + p->max_depth, STREAM_TOSERVER, p->ProbeTS, p->ProbeTC); - } - else { + } else { - if (!AppLayerProtoDetectPPParseConfPorts(ip_proto_str, p->ip_proto, - p->name, alproto, p->min_depth, p->max_depth, - p->ProbeTS, p->ProbeTC)) { + if (!AppLayerProtoDetectPPParseConfPorts(ip_proto_str, p->ip_proto, p->name, alproto, + p->min_depth, p->max_depth, p->ProbeTS, p->ProbeTC)) { if (enable_default != 0) { SCLogDebug("No %s app-layer configuration, enabling %s" - " detection %s detection on port %s.", + " detection %s detection on port %s.", p->name, p->name, ip_proto_str, p->default_port); - AppLayerProtoDetectPPRegister(p->ip_proto, - p->default_port, alproto, - p->min_depth, p->max_depth, STREAM_TOSERVER, - p->ProbeTS, p->ProbeTC); + AppLayerProtoDetectPPRegister(p->ip_proto, p->default_port, alproto, p->min_depth, + p->max_depth, STREAM_TOSERVER, p->ProbeTS, p->ProbeTC); } else { - SCLogDebug("No %s app-layer configuration for detection port (%s).", - p->name, ip_proto_str); + SCLogDebug("No %s app-layer configuration for detection port (%s).", p->name, + ip_proto_str); } } - } return alproto; @@ -114,58 +108,47 @@ int AppLayerRegisterParser(const struct AppLayerParser *p, AppProto alproto) /* Register functions for state allocation and freeing. A * state is allocated for every new flow. */ - AppLayerParserRegisterStateFuncs(p->ip_proto, alproto, - p->StateAlloc, p->StateFree); + AppLayerParserRegisterStateFuncs(p->ip_proto, alproto, p->StateAlloc, p->StateFree); /* Register request parser for parsing frame from server to server. */ - AppLayerParserRegisterParser(p->ip_proto, alproto, - STREAM_TOSERVER, p->ParseTS); + AppLayerParserRegisterParser(p->ip_proto, alproto, STREAM_TOSERVER, p->ParseTS); /* Register response parser for parsing frames from server to client. */ - AppLayerParserRegisterParser(p->ip_proto, alproto, - STREAM_TOCLIENT, p->ParseTC); + AppLayerParserRegisterParser(p->ip_proto, alproto, STREAM_TOCLIENT, p->ParseTC); /* Register a function to be called by the application layer * when a transaction is to be freed. */ - AppLayerParserRegisterTxFreeFunc(p->ip_proto, alproto, - p->StateTransactionFree); + AppLayerParserRegisterTxFreeFunc(p->ip_proto, alproto, p->StateTransactionFree); /* Register a function to return the current transaction count. */ - AppLayerParserRegisterGetTxCnt(p->ip_proto, alproto, - p->StateGetTxCnt); + AppLayerParserRegisterGetTxCnt(p->ip_proto, alproto, p->StateGetTxCnt); /* Transaction handling. */ AppLayerParserRegisterStateProgressCompletionStatus(alproto, p->complete_ts, p->complete_tc); - AppLayerParserRegisterGetStateProgressFunc(p->ip_proto, alproto, - p->StateGetProgress); - AppLayerParserRegisterGetTx(p->ip_proto, alproto, - p->StateGetTx); + AppLayerParserRegisterGetStateProgressFunc(p->ip_proto, alproto, p->StateGetProgress); + AppLayerParserRegisterGetTx(p->ip_proto, alproto, p->StateGetTx); if (p->StateGetEventInfo) { - AppLayerParserRegisterGetEventInfo(p->ip_proto, alproto, - p->StateGetEventInfo); + AppLayerParserRegisterGetEventInfo(p->ip_proto, alproto, p->StateGetEventInfo); } if (p->StateGetEventInfoById) { - AppLayerParserRegisterGetEventInfoById(p->ip_proto, alproto, - p->StateGetEventInfoById); + AppLayerParserRegisterGetEventInfoById(p->ip_proto, alproto, p->StateGetEventInfoById); } if (p->LocalStorageAlloc && p->LocalStorageFree) { - AppLayerParserRegisterLocalStorageFunc(p->ip_proto, alproto, - p->LocalStorageAlloc, p->LocalStorageFree); + AppLayerParserRegisterLocalStorageFunc( + p->ip_proto, alproto, p->LocalStorageAlloc, p->LocalStorageFree); } if (p->GetTxFiles) { AppLayerParserRegisterGetTxFilesFunc(p->ip_proto, alproto, p->GetTxFiles); } if (p->GetTxIterator) { - AppLayerParserRegisterGetTxIterator(p->ip_proto, alproto, - p->GetTxIterator); + AppLayerParserRegisterGetTxIterator(p->ip_proto, alproto, p->GetTxIterator); } if (p->GetTxData) { - AppLayerParserRegisterTxDataFunc(p->ip_proto, alproto, - p->GetTxData); + AppLayerParserRegisterTxDataFunc(p->ip_proto, alproto, p->GetTxData); } if (p->GetStateData) { @@ -173,14 +156,11 @@ int AppLayerRegisterParser(const struct AppLayerParser *p, AppProto alproto) } if (p->ApplyTxConfig) { - AppLayerParserRegisterApplyTxConfigFunc(p->ip_proto, alproto, - p->ApplyTxConfig); + AppLayerParserRegisterApplyTxConfigFunc(p->ip_proto, alproto, p->ApplyTxConfig); } if (p->flags) { - AppLayerParserRegisterOptionFlags(p->ip_proto, alproto, - p->flags); - + AppLayerParserRegisterOptionFlags(p->ip_proto, alproto, p->flags); } if (p->Truncate) { @@ -202,7 +182,7 @@ int AppLayerRegisterParserAlias(const char *proto_name, const char *proto_alias) return 0; } -static const char * IpProtoToString(int ip_proto) +static const char *IpProtoToString(int ip_proto) { switch (ip_proto) { case IPPROTO_TCP: @@ -212,5 +192,4 @@ static const char * IpProtoToString(int ip_proto) default: return NULL; }; - } diff --git a/src/app-layer-register.h b/src/app-layer-register.h index 4fcbe6cf8b6c..3473119d4791 100644 --- a/src/app-layer-register.h +++ b/src/app-layer-register.h @@ -51,19 +51,17 @@ typedef struct AppLayerParser { const int complete_tc; int (*StateGetProgress)(void *alstate, uint8_t direction); - int (*StateGetEventInfo)(const char *event_name, - int *event_id, AppLayerEventType *event_type); - int (*StateGetEventInfoById)(int event_id, const char **event_name, - AppLayerEventType *event_type); + int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type); + int (*StateGetEventInfoById)( + int event_id, const char **event_name, AppLayerEventType *event_type); void *(*LocalStorageAlloc)(void); void (*LocalStorageFree)(void *); AppLayerGetFileState (*GetTxFiles)(void *, void *, uint8_t); - AppLayerGetTxIterTuple (*GetTxIterator)(const uint8_t ipproto, - const AppProto alproto, void *alstate, uint64_t min_tx_id, - uint64_t max_tx_id, AppLayerGetTxIterState *istate); + AppLayerGetTxIterTuple (*GetTxIterator)(const uint8_t ipproto, const AppProto alproto, + void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *istate); AppLayerStateData *(*GetStateData)(void *state); AppLayerTxData *(*GetTxData)(void *tx); @@ -82,7 +80,8 @@ typedef struct AppLayerParser { * \brief App layer protocol detection function. * * \param parser The parser declaration structure. - * \param enable_default A boolean to indicate if default port configuration should be used if none given + * \param enable_default A boolean to indicate if default port configuration should be used if none + * given * * \retval The AppProto constant if successful. On error, this function never returns. */ diff --git a/src/app-layer-rfb.c b/src/app-layer-rfb.c deleted file mode 100644 index 829e918adc8c..000000000000 --- a/src/app-layer-rfb.c +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - * - * RFB (VNC) application layer detector and parser. - * - */ - -#include "suricata-common.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" -#include "app-layer-rfb.h" - -#include "rust.h" - -static int RFBRegisterPatternsForProtocolDetection(void) -{ - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_RFB, - "RFB ", 4, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_RFB, - "RFB ", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - return 0; -} - -void RFBParserRegisterTests(void); - -void RegisterRFBParsers(void) -{ - rs_rfb_register_parser(); - if (RFBRegisterPatternsForProtocolDetection() < 0 ) - return; -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_RFB, - RFBParserRegisterTests); -#endif -} - - -#ifdef UNITTESTS - -#include "stream-tcp.h" -#include "util-unittest-helper.h" - -static int RFBParserTest(void) -{ - uint64_t ret[4]; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - StreamTcpInitConfig(true); - TcpSession ssn; - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 59001, 5900); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_RFB; - - static const unsigned char rfb_version_str[12] = { - 0x52, 0x46, 0x42, 0x20, 0x30, 0x30, 0x33, 0x2e, 0x30, 0x30, 0x37, 0x0a - }; - - // the RFB server sending the first handshake message - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOCLIENT | STREAM_START, - (uint8_t *)rfb_version_str, sizeof(rfb_version_str)); - FAIL_IF_NOT(r == 0); - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOSERVER, (uint8_t *)rfb_version_str, sizeof(rfb_version_str)); - FAIL_IF_NOT(r == 0); - - static const unsigned char security_types[3] = { - 0x02, 0x01, 0x02 - }; - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOCLIENT, (uint8_t *)security_types, sizeof(security_types)); - FAIL_IF_NOT(r == 0); - - static const unsigned char type_selection[1] = { - 0x01 - }; - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOSERVER, (uint8_t *)type_selection, sizeof(type_selection)); - FAIL_IF_NOT(r == 0); - - static const unsigned char client_init[1] = { - 0x01 - }; - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOSERVER, (uint8_t *)client_init, sizeof(client_init)); - FAIL_IF_NOT(r == 0); - - static const unsigned char server_init[] = { - 0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, - 0x61, 0x6e, 0x65, 0x61, 0x67, 0x6c, 0x65, 0x73, - 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, - 0x73, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, - 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e - }; - - r = AppLayerParserParse( - NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOCLIENT, (uint8_t *)server_init, sizeof(server_init)); - FAIL_IF_NOT(r == 0); - - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 1); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 1); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 1); // log_id - FAIL_IF_NOT(ret[3] == 1); // min_id - - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - - PASS; -} - -void RFBParserRegisterTests(void) -{ - UtRegisterTest("RFBParserTest", RFBParserTest); -} - -#endif diff --git a/src/app-layer-sip.c b/src/app-layer-sip.c deleted file mode 100644 index 780d21cbcf45..000000000000 --- a/src/app-layer-sip.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2019-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Giuseppe Longo - * - * Parser for SIP application layer running on UDP port 5060. - */ - -#include "suricata-common.h" -#include "app-layer-sip.h" -#include "rust.h" - -void RegisterSIPParsers(void) -{ - rs_sip_register_parser(); -} diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c deleted file mode 100644 index 0c6102e83e5f..000000000000 --- a/src/app-layer-smb.c +++ /dev/null @@ -1,222 +0,0 @@ -/* Copyright (C) 2017-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * SMB protocol handling - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "app-layer-protos.h" -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "util-unittest.h" - -#include "rust.h" -#include "app-layer-smb.h" -#include "util-misc.h" - - -static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; -static SuricataFileContext sfc = { &sbcfg }; - -#ifdef UNITTESTS -static void SMBParserRegisterTests(void); -#endif - -void RegisterSMBParsers(void) -{ - rs_smb_init(&sfc); - rs_smb_register_parser(); - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMB, SMBParserRegisterTests); -#endif - - return; -} - -#ifdef UNITTESTS -#include "stream-tcp.h" -#include "util-unittest-helper.h" - -/** \test multi transactions and cleanup */ -static int SMBParserTxCleanupTest(void) -{ - uint64_t ret[4]; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - StreamTcpInitConfig(true); - TcpSession ssn; - memset(&ssn, 0, sizeof(ssn)); - - Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 445); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SMB; - - char req_str[] ="\x00\x00\x00\x79\xfe\x53\x4d\x42\x40\x00\x01\x00\x00\x00\x00\x00" \ - "\x05\x00\xe0\x1e\x10\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00" \ - "\x00\x00\x00\x00\x00\x00\x00\x00\x10\x72\xd2\x9f\x36\xc2\x08\x14" \ - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ - "\x00\x00\x00\x00\x39\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00" \ - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00" \ - "\x00\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ - "\x78\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - req_str[28] = 0x01; - int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER | STREAM_START, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - req_str[28]++; - - AppLayerParserTransactionsCleanup(f, STREAM_TOSERVER); - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 0); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 0); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 0); // log_id - FAIL_IF_NOT(ret[3] == 0); // min_id - - char resp_str[] = "\x00\x00\x00\x98\xfe\x53\x4d\x42\x40\x00\x01\x00\x00\x00\x00\x00" \ - "\x05\x00\x21\x00\x11\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00" \ - "\x00\x00\x00\x00\x00\x00\x00\x00\x10\x72\xd2\x9f\x36\xc2\x08\x14" \ - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ - "\x00\x00\x00\x00\x59\x00\x00\x00\x01\x00\x00\x00\x48\x38\x40\xb3" \ - "\x0f\xa8\xd3\x01\x84\x9a\x2b\x46\xf7\xa8\xd3\x01\x48\x38\x40\xb3" \ - "\x0f\xa8\xd3\x01\x48\x38\x40\xb3\x0f\xa8\xd3\x01\x00\x00\x00\x00" \ - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00" \ - "\x00\x00\x00\x00\x9e\x8f\xb8\x91\x00\x00\x00\x00\x01\x5b\x11\xbb" \ - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - - resp_str[28] = 0x01; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT | STREAM_START, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - resp_str[28] = 0x04; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - resp_str[28] = 0x05; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - resp_str[28] = 0x06; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - resp_str[28] = 0x08; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - resp_str[28] = 0x02; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - resp_str[28] = 0x07; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 2); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 2); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 2); // log_id - FAIL_IF_NOT(ret[3] == 2); // min_id - - resp_str[28] = 0x03; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 8); // log_id - FAIL_IF_NOT(ret[3] == 8); // min_id - - req_str[28] = 0x09; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOSERVER | STREAM_EOF, (uint8_t *)req_str, sizeof(req_str)); - FAIL_IF_NOT(r == 0); - AppLayerParserTransactionsCleanup(f, STREAM_TOSERVER); - - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done - FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 8); // log_id - FAIL_IF_NOT(ret[3] == 8); // min_id - - resp_str[28] = 0x09; - r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, - STREAM_TOCLIENT | STREAM_EOF, (uint8_t *)resp_str, sizeof(resp_str)); - FAIL_IF_NOT(r == 0); - AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); - - UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); - FAIL_IF_NOT(ret[0] == 9); // inspect_id[0] - FAIL_IF_NOT(ret[1] == 9); // inspect_id[1] - FAIL_IF_NOT(ret[2] == 9); // log_id - FAIL_IF_NOT(ret[3] == 9); // min_id - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - UTHFreeFlow(f); - - PASS; -} - -static void SMBParserRegisterTests(void) -{ - UtRegisterTest("SMBParserTxCleanupTest", SMBParserTxCleanupTest); -} - -#endif /* UNITTESTS */ diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c deleted file mode 100644 index a4d94a94ded2..000000000000 --- a/src/app-layer-smtp.c +++ /dev/null @@ -1,4265 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#include "suricata.h" -#include "suricata-common.h" -#include "decode.h" -#include "threads.h" - -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" -#include "stream-tcp.h" -#include "stream.h" - -#include "app-layer.h" -#include "app-layer-detect-proto.h" -#include "app-layer-protos.h" -#include "app-layer-parser.h" -#include "app-layer-smtp.h" - -#include "util-enum.h" -#include "util-mpm.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-memcmp.h" -#include "flow-util.h" - -#include "detect-engine.h" -#include "detect-engine-state.h" -#include "detect-engine-build.h" -#include "detect-parse.h" - -#include "decode-events.h" -#include "conf.h" - -#include "util-mem.h" -#include "util-misc.h" -#include "util-validate.h" - -/* content-limit default value */ -#define FILEDATA_CONTENT_LIMIT 100000 -/* content-inspect-min-size default value */ -#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768 -/* content-inspect-window default value */ -#define FILEDATA_CONTENT_INSPECT_WINDOW 4096 - -/* raw extraction default value */ -#define SMTP_RAW_EXTRACTION_DEFAULT_VALUE false -#define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510 - -#define SMTP_COMMAND_BUFFER_STEPS 5 - -/* we are in process of parsing a fresh command. Just a placeholder. If we - * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */ -#define SMTP_PARSER_STATE_COMMAND_MODE 0x00 -/* we are in mode of parsing a command's data. Used when we are parsing tls - * or accepting the rfc 2822 mail after DATA command */ -#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01 -/* Used when we are still in the process of parsing a server command. Used - * with multi-line replies and the stream is fragmented before all the lines - * for a response is seen */ -#define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02 -/* Used to indicate that the parser has seen the first reply */ -#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04 -/* Used to indicate that the parser is parsing a multiline reply */ -#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08 -/* Used to indicate that the server supports pipelining */ -#define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10 - -/* Various SMTP commands - * We currently have var-ified just STARTTLS and DATA, since we need to them - * for state transitions. The rest are just indicate as OTHER_CMD. Other - * commands would be introduced as and when needed */ -#define SMTP_COMMAND_STARTTLS 1 -#define SMTP_COMMAND_DATA 2 -#define SMTP_COMMAND_BDAT 3 -/* not an actual command per se, but the mode where we accept the mail after - * DATA has it's own reply code for completion, from the server. We give this - * stage a pseudo command of it's own, so that we can add this to the command - * buffer to match with the reply */ -#define SMTP_COMMAND_DATA_MODE 4 -/* All other commands are represented by this var */ -#define SMTP_COMMAND_OTHER_CMD 5 -#define SMTP_COMMAND_RSET 6 - -/* Different EHLO extensions. Not used now. */ -#define SMTP_EHLO_EXTENSION_PIPELINING -#define SMTP_EHLO_EXTENSION_SIZE -#define SMTP_EHLO_EXTENSION_DSN -#define SMTP_EHLO_EXTENSION_STARTTLS -#define SMTP_EHLO_EXTENSION_8BITMIME - -typedef struct SMTPInput_ { - /* current input that is being parsed */ - const uint8_t *buf; - int32_t len; - - /* original length of an input */ - int32_t orig_len; - - /* Consumed bytes till current line */ - int32_t consumed; -} SMTPInput; - -typedef struct SMTPLine_ { - /** current line extracted by the parser from the call to SMTPGetline() */ - const uint8_t *buf; - /** length of the line in current_line. Doesn't include the delimiter */ - int32_t len; - uint8_t delim_len; - bool lf_found; -} SMTPLine; - -SCEnumCharMap smtp_decoder_event_table[] = { - { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY }, - { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST", SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST }, - { "MAX_COMMAND_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED }, - { "MAX_REPLY_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED }, - { "INVALID_PIPELINED_SEQUENCE", SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE }, - { "BDAT_CHUNK_LEN_EXCEEDED", SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED }, - { "NO_SERVER_WELCOME_MESSAGE", SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE }, - { "TLS_REJECTED", SMTP_DECODER_EVENT_TLS_REJECTED }, - { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED }, - { "FAILED_PROTOCOL_CHANGE", SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE }, - - /* MIME Events */ - { "MIME_PARSE_FAILED", SMTP_DECODER_EVENT_MIME_PARSE_FAILED }, - { "MIME_MALFORMED_MSG", SMTP_DECODER_EVENT_MIME_MALFORMED_MSG }, - { "MIME_INVALID_BASE64", SMTP_DECODER_EVENT_MIME_INVALID_BASE64 }, - { "MIME_INVALID_QP", SMTP_DECODER_EVENT_MIME_INVALID_QP }, - { "MIME_LONG_LINE", SMTP_DECODER_EVENT_MIME_LONG_LINE }, - { "MIME_LONG_ENC_LINE", SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE }, - { "MIME_LONG_HEADER_NAME", SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME }, - { "MIME_LONG_HEADER_VALUE", SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE }, - { "MIME_LONG_BOUNDARY", SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG }, - { "MIME_LONG_FILENAME", SMTP_DECODER_EVENT_MIME_LONG_FILENAME }, - - /* Invalid behavior or content */ - { "DUPLICATE_FIELDS", SMTP_DECODER_EVENT_DUPLICATE_FIELDS }, - { "UNPARSABLE_CONTENT", SMTP_DECODER_EVENT_UNPARSABLE_CONTENT }, - { "TRUNCATED_LINE", SMTP_DECODER_EVENT_TRUNCATED_LINE }, - { NULL, -1 }, -}; - -typedef struct SMTPThreadCtx_ { - MpmThreadCtx *smtp_mpm_thread_ctx; - PrefilterRuleStore *pmq; -} SMTPThreadCtx; - -#define SMTP_MPM mpm_default_matcher - -static MpmCtx *smtp_mpm_ctx = NULL; - -/* smtp reply codes. If an entry is made here, please make a simultaneous - * entry in smtp_reply_map */ -enum SMTPCode { - SMTP_REPLY_211, - SMTP_REPLY_214, - SMTP_REPLY_220, - SMTP_REPLY_221, - SMTP_REPLY_235, - SMTP_REPLY_250, - SMTP_REPLY_251, - SMTP_REPLY_252, - - SMTP_REPLY_334, - SMTP_REPLY_354, - - SMTP_REPLY_421, - SMTP_REPLY_450, - SMTP_REPLY_451, - SMTP_REPLY_452, - SMTP_REPLY_455, - - SMTP_REPLY_500, - SMTP_REPLY_501, - SMTP_REPLY_502, - SMTP_REPLY_503, - SMTP_REPLY_504, - SMTP_REPLY_550, - SMTP_REPLY_551, - SMTP_REPLY_552, - SMTP_REPLY_553, - SMTP_REPLY_554, - SMTP_REPLY_555, -}; - -SCEnumCharMap smtp_reply_map[ ] = { - { "211", SMTP_REPLY_211 }, - { "214", SMTP_REPLY_214 }, - { "220", SMTP_REPLY_220 }, - { "221", SMTP_REPLY_221 }, - { "235", SMTP_REPLY_235 }, - { "250", SMTP_REPLY_250 }, - { "251", SMTP_REPLY_251 }, - { "252", SMTP_REPLY_252 }, - - { "334", SMTP_REPLY_334 }, - { "354", SMTP_REPLY_354 }, - - { "421", SMTP_REPLY_421 }, - { "450", SMTP_REPLY_450 }, - { "451", SMTP_REPLY_451 }, - { "452", SMTP_REPLY_452 }, - { "455", SMTP_REPLY_455 }, - - { "500", SMTP_REPLY_500 }, - { "501", SMTP_REPLY_501 }, - { "502", SMTP_REPLY_502 }, - { "503", SMTP_REPLY_503 }, - { "504", SMTP_REPLY_504 }, - { "550", SMTP_REPLY_550 }, - { "551", SMTP_REPLY_551 }, - { "552", SMTP_REPLY_552 }, - { "553", SMTP_REPLY_553 }, - { "554", SMTP_REPLY_554 }, - { "555", SMTP_REPLY_555 }, - { NULL, -1 }, -}; - -/* Create SMTP config structure */ -SMTPConfig smtp_config = { - .decode_mime = true, - { - .decode_base64 = true, - .decode_quoted_printable = true, - .extract_urls = true, - .extract_urls_schemes = NULL, - .log_url_scheme = false, - .body_md5 = false, - .header_value_depth = 0, - }, - .content_limit = FILEDATA_CONTENT_LIMIT, - .content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE, - .content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW, - .raw_extraction = SMTP_RAW_EXTRACTION_DEFAULT_VALUE, - STREAMING_BUFFER_CONFIG_INITIALIZER, -}; - -static SMTPString *SMTPStringAlloc(void); - -/** - * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML - * config file - * - * \return none - */ -static void SMTPConfigure(void) { - - SCEnter(); - intmax_t imval; - uint32_t content_limit = 0; - uint32_t content_inspect_min_size = 0; - uint32_t content_inspect_window = 0; - - ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime"); - if (config != NULL) { - ConfNode *extract_urls_schemes = NULL; - - int val; - int ret = ConfGetChildValueBool(config, "decode-mime", &val); - if (ret) { - smtp_config.decode_mime = val; - } - - ret = ConfGetChildValueBool(config, "decode-base64", &val); - if (ret) { - smtp_config.mime_config.decode_base64 = val; - } - - ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val); - if (ret) { - smtp_config.mime_config.decode_quoted_printable = val; - } - - ret = ConfGetChildValueInt(config, "header-value-depth", &imval); - if (ret) { - smtp_config.mime_config.header_value_depth = (uint32_t) imval; - } - - ret = ConfGetChildValueBool(config, "extract-urls", &val); - if (ret) { - smtp_config.mime_config.extract_urls = val; - } - - /* Parse extract-urls-schemes from mime config, add '://' suffix to found schemes, - * and provide a default value of 'http' for the schemes to be extracted - * if no schemes are found in the config */ - extract_urls_schemes = ConfNodeLookupChild(config, "extract-urls-schemes"); - if (extract_urls_schemes) { - ConfNode *scheme = NULL; - - TAILQ_FOREACH (scheme, &extract_urls_schemes->head, next) { - /* new_val_len: scheme value from config e.g. 'http' + '://' + null terminator */ - size_t new_val_len = strlen(scheme->val) + 3 + 1; - if (new_val_len > UINT16_MAX) { - FatalError("Too long value for extract-urls-schemes"); - } - char *new_val = SCMalloc(new_val_len); - if (unlikely(new_val == NULL)) { - FatalError("SCMalloc failure."); - } - - int r = snprintf(new_val, new_val_len, "%s://", scheme->val); - if (r < 0 || r >= (int)new_val_len) { - FatalError("snprintf failure."); - } - - /* replace existing scheme value stored on the linked list with new value including - * '://' suffix */ - SCFree(scheme->val); - scheme->val = new_val; - } - - smtp_config.mime_config.extract_urls_schemes = extract_urls_schemes; - } else { - /* Add default extract url scheme 'http' since - * extract-urls-schemes wasn't found in the config */ - ConfNode *seq_node = ConfNodeNew(); - if (unlikely(seq_node == NULL)) { - FatalError("ConfNodeNew failure."); - } - ConfNode *scheme = ConfNodeNew(); - if (unlikely(scheme == NULL)) { - FatalError("ConfNodeNew failure."); - } - - seq_node->name = SCStrdup("extract-urls-schemes"); - if (unlikely(seq_node->name == NULL)) { - FatalError("SCStrdup failure."); - } - scheme->val = SCStrdup("http://"); - if (unlikely(scheme->val == NULL)) { - FatalError("SCStrdup failure."); - } - - seq_node->is_seq = 1; - TAILQ_INSERT_TAIL(&seq_node->head, scheme, next); - TAILQ_INSERT_TAIL(&config->head, seq_node, next); - - smtp_config.mime_config.extract_urls_schemes = seq_node; - } - - ret = ConfGetChildValueBool(config, "log-url-scheme", &val); - if (ret) { - smtp_config.mime_config.log_url_scheme = val; - } - - ret = ConfGetChildValueBool(config, "body-md5", &val); - if (ret) { - smtp_config.mime_config.body_md5 = val; - } - } - - /* Pass mime config data to MimeDec API */ - MimeDecSetConfig(&smtp_config.mime_config); - - ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker"); - ConfNode *p = NULL; - - if (t != NULL) { - TAILQ_FOREACH(p, &t->head, next) { - if (strcasecmp("content-limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &content_limit) < 0) { - SCLogWarning("parsing content-limit %s failed", p->val); - content_limit = FILEDATA_CONTENT_LIMIT; - } - smtp_config.content_limit = content_limit; - } - - if (strcasecmp("content-inspect-min-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) { - SCLogWarning("parsing content-inspect-min-size %s failed", p->val); - content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; - } - smtp_config.content_inspect_min_size = content_inspect_min_size; - } - - if (strcasecmp("content-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) { - SCLogWarning("parsing content-inspect-window %s failed", p->val); - content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; - } - smtp_config.content_inspect_window = content_inspect_window; - } - } - } - - smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256; - - if (ConfGetBool("app-layer.protocols.smtp.raw-extraction", - (int *)&smtp_config.raw_extraction) != 1) { - smtp_config.raw_extraction = SMTP_RAW_EXTRACTION_DEFAULT_VALUE; - } - if (smtp_config.raw_extraction && smtp_config.decode_mime) { - SCLogError("\"decode-mime\" and \"raw-extraction\" " - "options can't be enabled at the same time, " - "disabling raw extraction"); - smtp_config.raw_extraction = 0; - } - - SCReturn; -} - -static void SMTPSetEvent(SMTPState *s, uint8_t e) -{ - SCLogDebug("setting event %u", e); - - if (s->curr_tx != NULL) { - AppLayerDecoderEventsSetEventRaw(&s->curr_tx->tx_data.events, e); - // s->events++; - return; - } - SCLogDebug("couldn't set event %u", e); -} - -static SMTPTransaction *SMTPTransactionCreate(void) -{ - SMTPTransaction *tx = SCCalloc(1, sizeof(*tx)); - if (tx == NULL) { - return NULL; - } - - TAILQ_INIT(&tx->rcpt_to_list); - tx->mime_state = NULL; - tx->tx_data.file_tx = STREAM_TOSERVER; // can xfer files - return tx; -} - -static void FlagDetectStateNewFile(SMTPTransaction *tx) -{ - if (tx && tx->tx_data.de_state) { - SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set"); - tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW; - } else if (tx == NULL) { - SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX"); - } else if (tx->tx_data.de_state == NULL) { - SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX DESTATE"); - } -} - -static void SMTPNewFile(SMTPTransaction *tx, File *file) -{ - DEBUG_VALIDATE_BUG_ON(tx == NULL); - DEBUG_VALIDATE_BUG_ON(file == NULL); -#ifdef UNITTESTS - if (RunmodeIsUnittests()) { - if (tx == NULL || file == NULL) { - return; - } - } -#endif - FlagDetectStateNewFile(tx); - tx->tx_data.files_opened++; - - /* set inspect sizes used in file pruning logic. - * TODO consider moving this to the file.data code that - * would actually have use for this. */ - FileSetInspectSizes(file, smtp_config.content_inspect_window, - smtp_config.content_inspect_min_size); -} - -int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state) -{ - SCEnter(); - int ret = MIME_DEC_OK; - Flow *flow = (Flow *) state->data; - SMTPState *smtp_state = (SMTPState *) flow->alstate; - SMTPTransaction *tx = smtp_state->curr_tx; - MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - FileContainer *files = NULL; - - DEBUG_VALIDATE_BUG_ON(tx == NULL); - - uint16_t flags = FileFlowToFlags(flow, STREAM_TOSERVER); - - /* Find file */ - if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { - files = &tx->files_ts; - - /* Open file if necessary */ - if (state->body_begin) { - - if (SCLogDebugEnabled()) { - SCLogDebug("Opening file...%u bytes", len); - printf("File - "); - for (uint32_t i = 0; i < entity->filename_len; i++) { - printf("%c", entity->filename[i]); - } - printf("\n"); - } - - /* Set storage flag if applicable since only the first file in the - * flow seems to be processed by the 'filestore' detector */ - if (files->head != NULL && (files->head->flags & FILE_STORE)) { - flags |= FILE_STORE; - } - - uint32_t depth = smtp_config.content_inspect_min_size + - (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp); - SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %"PRIu32, depth); - StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth); - - uint16_t flen = (uint16_t)entity->filename_len; - if (entity->filename_len > SC_FILENAME_MAX) { - flen = SC_FILENAME_MAX; - SMTPSetEvent(smtp_state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME); - } - if (FileOpenFileWithId(files, &smtp_config.sbcfg, smtp_state->file_track_id++, - (uint8_t *)entity->filename, flen, (uint8_t *)chunk, len, flags) != 0) { - ret = MIME_DEC_ERR_DATA; - SCLogDebug("FileOpenFile() failed"); - } else { - SMTPNewFile(tx, files->tail); - } - - /* If close in the same chunk, then pass in empty bytes */ - if (state->body_end) { - - SCLogDebug("Closing file...%u bytes", len); - - if (files->tail->state == FILE_STATE_OPENED) { - ret = FileCloseFile(files, &smtp_config.sbcfg, (uint8_t *)NULL, 0, flags); - if (ret != 0) { - SCLogDebug("FileCloseFile() failed: %d", ret); - ret = MIME_DEC_ERR_DATA; - } - } else { - SCLogDebug("File already closed"); - } - depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp; - - AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER); - SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", - depth); - StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, - depth); - } - } else if (state->body_end) { - /* Close file */ - SCLogDebug("Closing file...%u bytes", len); - - if (files->tail && files->tail->state == FILE_STATE_OPENED) { - ret = FileCloseFile(files, &smtp_config.sbcfg, (uint8_t *)chunk, len, flags); - if (ret != 0) { - SCLogDebug("FileCloseFile() failed: %d", ret); - ret = MIME_DEC_ERR_DATA; - } - } else { - SCLogDebug("File already closed"); - } - uint32_t depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp; - AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER); - SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", - depth); - StreamTcpReassemblySetMinInspectDepth(flow->protoctx, - STREAM_TOSERVER, depth); - } else { - /* Append data chunk to file */ - SCLogDebug("Appending file...%u bytes", len); - /* 0 is ok, -2 is not stored, -1 is error */ - ret = FileAppendData(files, &smtp_config.sbcfg, (uint8_t *)chunk, len); - if (ret == -2) { - ret = 0; - SCLogDebug("FileAppendData() - file no longer being extracted"); - } else if (ret < 0) { - SCLogDebug("FileAppendData() failed: %d", ret); - ret = MIME_DEC_ERR_DATA; - } - - if (files->tail && files->tail->content_inspected == 0 && - files->tail->size >= smtp_config.content_inspect_min_size) { - uint32_t depth = smtp_config.content_inspect_min_size + - (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp); - AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER); - SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", - depth); - StreamTcpReassemblySetMinInspectDepth(flow->protoctx, - STREAM_TOSERVER, depth); - - /* after the start of the body inspection, disable the depth logic */ - } else if (files->tail && files->tail->content_inspected > 0) { - StreamTcpReassemblySetMinInspectDepth(flow->protoctx, - STREAM_TOSERVER, 0); - - /* expand the limit as long as we get file data, as the file data is bigger on the - * wire due to base64 */ - } else { - uint32_t depth = smtp_config.content_inspect_min_size + - (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp); - SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %"PRIu32, - depth); - StreamTcpReassemblySetMinInspectDepth(flow->protoctx, - STREAM_TOSERVER, depth); - } - } - - if (ret == 0) { - SCLogDebug("Successfully processed file data!"); - } - } else { - SCLogDebug("Body not a Ctnt_attachment"); - } - SCReturnInt(ret); -} - -/** - * \internal - * \brief Get the next line from input. It doesn't do any length validation. - * - * \param state The smtp state. - * - * \retval 0 On success. - * \retval -1 Either when we don't have any new lines to supply anymore or - * on failure. - */ -static AppLayerResult SMTPGetLine( - SMTPState *state, SMTPInput *input, SMTPLine *line, uint16_t direction) -{ - SCEnter(); - - /* we have run out of input */ - if (input->len <= 0) - return APP_LAYER_ERROR; - - uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len); - bool discard_till_lf = (direction == 0) ? state->discard_till_lf_ts : state->discard_till_lf_tc; - - if (lf_idx == NULL) { - if (!discard_till_lf && input->len >= SMTP_LINE_BUFFER_LIMIT) { - line->buf = input->buf; - line->len = SMTP_LINE_BUFFER_LIMIT; - line->delim_len = 0; - SCReturnStruct(APP_LAYER_OK); - } - SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1)); - } else { - /* There could be one chunk of command data that has LF but post the line limit - * e.g. input_len = 5077 - * lf_idx = 5010 - * max_line_len = 4096 */ - uint32_t o_consumed = input->consumed; - input->consumed = lf_idx - input->buf + 1; - line->len = input->consumed - o_consumed; - line->lf_found = true; - DEBUG_VALIDATE_BUG_ON(line->len < 0); - if (line->len < 0) - SCReturnStruct(APP_LAYER_ERROR); - input->len -= line->len; - DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len); - line->buf = input->buf + o_consumed; - if (line->len >= SMTP_LINE_BUFFER_LIMIT) { - line->len = SMTP_LINE_BUFFER_LIMIT; - line->delim_len = 0; - SCReturnStruct(APP_LAYER_OK); - } - if (discard_till_lf) { - // Whatever came in with first LF should also get discarded - if (direction == 0) { - state->discard_till_lf_ts = false; - } else { - state->discard_till_lf_tc = false; - } - line->len = 0; - line->delim_len = 0; - SCReturnStruct(APP_LAYER_OK); - } - if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) { - line->delim_len = 2; - line->len -= 2; - } else { - line->delim_len = 1; - line->len -= 1; - } - SCReturnStruct(APP_LAYER_OK); - } -} - -static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f) -{ - SCEnter(); - void *ptmp; - - if (state->cmds_cnt >= state->cmds_buffer_len) { - int increment = SMTP_COMMAND_BUFFER_STEPS; - if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) { - increment = USHRT_MAX - state->cmds_buffer_len; - } - - ptmp = SCRealloc(state->cmds, - sizeof(uint8_t) * (state->cmds_buffer_len + increment)); - if (ptmp == NULL) { - SCFree(state->cmds); - state->cmds = NULL; - SCLogDebug("SCRealloc failure"); - return -1; - } - state->cmds = ptmp; - - state->cmds_buffer_len += increment; - } - if (state->cmds_cnt >= 1 && - ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) || - (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) { - /* decoder event */ - SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE); - /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP, - * STARTTLS as the last command in pipelined mode */ - } - - /** \todo decoder event */ - if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) { - SCLogDebug("command buffer overflow"); - return -1; - } - - state->cmds[state->cmds_cnt] = command; - state->cmds_cnt++; - - return 0; -} - -static int SMTPProcessCommandBDAT( - SMTPState *state, Flow *f, AppLayerParserState *pstate, const SMTPLine *line) -{ - SCEnter(); - - state->bdat_chunk_idx += (line->len + line->delim_len); - if (state->bdat_chunk_idx > state->bdat_chunk_len) { - state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; - /* decoder event */ - SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED); - SCReturnInt(-1); - } else if (state->bdat_chunk_idx == state->bdat_chunk_len) { - state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; - } - - SCReturnInt(0); -} - -static void SetMimeEvents(SMTPState *state) -{ - if (state->curr_tx->mime_state->msg == NULL) { - return; - } - - /* Generate decoder events */ - MimeDecEntity *msg = state->curr_tx->mime_state->msg; - if (msg->anomaly_flags & ANOM_INVALID_BASE64) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64); - } - if (msg->anomaly_flags & ANOM_INVALID_QP) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP); - } - if (msg->anomaly_flags & ANOM_LONG_LINE) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE); - } - if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE); - } - if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME); - } - if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE); - } - if (msg->anomaly_flags & ANOM_MALFORMED_MSG) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG); - } - if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG); - } - if (msg->anomaly_flags & ANOM_LONG_FILENAME) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME); - } -} - -static inline void SMTPTransactionComplete(SMTPState *state) -{ - DEBUG_VALIDATE_BUG_ON(state->curr_tx == NULL); - if (state->curr_tx) - state->curr_tx->done = 1; -} - -/** - * \retval 0 ok - * \retval -1 error - */ -static int SMTPProcessCommandDATA(SMTPState *state, SMTPTransaction *tx, Flow *f, - AppLayerParserState *pstate, const SMTPLine *line) -{ - SCEnter(); - DEBUG_VALIDATE_BUG_ON(tx == NULL); - - if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - /* looks like are still waiting for a confirmation from the server */ - return 0; - } - - if (line->len == 1 && line->buf[0] == '.') { - state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; - /* kinda like a hack. The mail sent in DATA mode, would be - * acknowledged with a reply. We insert a dummy command to - * the command buffer to be used by the reply handler to match - * the reply received */ - SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f); - if (smtp_config.raw_extraction) { - /* we use this as the signal that message data is complete. */ - FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, 0); - } else if (smtp_config.decode_mime && tx->mime_state != NULL) { - /* Complete parsing task */ - int ret = MimeDecParseComplete(tx->mime_state); - if (ret != MIME_DEC_OK) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); - SCLogDebug("MimeDecParseComplete() function failed"); - } - - /* Generate decoder events */ - SetMimeEvents(state); - } - SMTPTransactionComplete(state); - SCLogDebug("marked tx as done"); - } else if (smtp_config.raw_extraction) { - // message not over, store the line. This is a substitution of - // ProcessDataChunk - FileAppendData(&tx->files_ts, &smtp_config.sbcfg, line->buf, line->len + line->delim_len); - } - - /* If DATA, then parse out a MIME message */ - if (state->current_command == SMTP_COMMAND_DATA && - (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - if (smtp_config.decode_mime && tx->mime_state != NULL) { - int ret = MimeDecParseLine(line->buf, line->len, line->delim_len, tx->mime_state); - if (ret != MIME_DEC_OK) { - if (ret != MIME_DEC_ERR_STATE) { - /* Generate decoder events */ - SetMimeEvents(state); - - SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret); - SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); - } - /* keep the parser in its error state so we can log that, - * the parser will reject new data */ - } - } - } - - return 0; -} - -static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f, - AppLayerParserState *pstate) -{ - return 0; -} - -static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd) -{ - return (state->cmds_idx < state->cmds_buffer_len && - state->cmds[state->cmds_idx] == cmd); -} - -static int SMTPProcessReply(SMTPState *state, Flow *f, AppLayerParserState *pstate, - SMTPThreadCtx *td, SMTPInput *input, const SMTPLine *line) -{ - SCEnter(); - - /* Line with just LF */ - if (line->len == 0 && input->consumed == 1 && line->delim_len == 1) { - return 0; // to continue processing further - } - - /* the reply code has to contain at least 3 bytes, to hold the 3 digit - * reply code */ - if (line->len < 3) { - /* decoder event */ - SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); - return -1; - } - - if (line->len >= 4) { - if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) { - if (line->buf[3] != '-') { - state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; - } - } else { - if (line->buf[3] == '-') { - state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; - } - } - } else { - if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) { - state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; - } - } - - /* I don't like this pmq reset here. We'll devise a method later, that - * should make the use of the mpm very efficient */ - PmqReset(td->pmq); - int mpm_cnt = mpm_table[SMTP_MPM].Search( - smtp_mpm_ctx, td->smtp_mpm_thread_ctx, td->pmq, line->buf, 3); - if (mpm_cnt == 0) { - /* set decoder event - reply code invalid */ - SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); - SCLogDebug("invalid reply code %02x %02x %02x", line->buf[0], line->buf[1], line->buf[2]); - SCReturnInt(-1); - } - enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value; - SCLogDebug("REPLY: reply_code %u / %s", reply_code, - smtp_reply_map[reply_code].enum_name); - - if (state->cmds_idx == state->cmds_cnt) { - if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - /* the first server reply can be a multiline message. Let's - * flag the fact that we have seen the first reply only at the end - * of a multiline reply - */ - if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) - state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; - if (reply_code == SMTP_REPLY_220) - SCReturnInt(0); - else { - SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); - SCReturnInt(0); - } - } else { - /* decoder event - unable to match reply with request */ - SCLogDebug("unable to match reply with request"); - SCReturnInt(0); - } - } - - if (state->cmds_cnt == 0) { - /* reply but not a command we have stored, fall through */ - } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) { - if (reply_code == SMTP_REPLY_220) { - /* we are entering STARTTLS data mode */ - state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; - if (!AppLayerRequestProtocolTLSUpgrade(f)) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE); - } - if (state->curr_tx) { - SMTPTransactionComplete(state); - } - } else { - /* decoder event */ - SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED); - } - } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) { - if (reply_code == SMTP_REPLY_354) { - /* Next comes the mail for the DATA command in toserver direction */ - state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; - } else { - /* decoder event */ - SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED); - } - } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) { - if (reply_code == SMTP_REPLY_250 && state->curr_tx && - !(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) { - SMTPTransactionComplete(state); - } - } else { - /* we don't care for any other command for now */ - } - - /* if it is a multi-line reply, we need to move the index only once for all - * the line of the reply. We unset the multiline flag on the last - * line of the multiline reply, following which we increment the index */ - if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) { - state->cmds_idx++; - } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - /* we check if the server is indicating pipelining support */ - if (reply_code == SMTP_REPLY_250 && line->len == 14 && - SCMemcmpLowercase("pipelining", line->buf + 4, 10) == 0) { - state->parser_state |= SMTP_PARSER_STATE_PIPELINING_SERVER; - } - } - - /* if we have matched all the buffered commands, reset the cnt and index */ - if (state->cmds_idx == state->cmds_cnt) { - state->cmds_cnt = 0; - state->cmds_idx = 0; - } - - return 0; -} - -static int SMTPParseCommandBDAT(SMTPState *state, const SMTPLine *line) -{ - SCEnter(); - - int i = 4; - while (i < line->len) { - if (line->buf[i] != ' ') { - break; - } - i++; - } - if (i == 4) { - /* decoder event */ - return -1; - } - if (i == line->len) { - /* decoder event */ - return -1; - } - char *endptr = NULL; - // copy in temporary null-terminated buffer to call strtoul - char strbuf[24]; - int len = 23; - if (line->len - i < len) { - len = line->len - i; - } - memcpy(strbuf, line->buf + i, len); - strbuf[len] = '\0'; - state->bdat_chunk_len = strtoul((const char *)strbuf, (char **)&endptr, 10); - if ((uint8_t *)endptr == line->buf + i) { - /* decoder event */ - return -1; - } - - return 0; -} - -static int SMTPParseCommandWithParam(SMTPState *state, const SMTPLine *line, uint8_t prefix_len, - uint8_t **target, uint16_t *target_len) -{ - int i = prefix_len + 1; - - while (i < line->len) { - if (line->buf[i] != ' ') { - break; - } - i++; - } - - /* rfc1870: with the size extension the mail from can be followed by an option. - We use the space separator to detect it. */ - int spc_i = i; - while (spc_i < line->len) { - if (line->buf[spc_i] == ' ') { - break; - } - spc_i++; - } - - *target = SCMalloc(spc_i - i + 1); - if (*target == NULL) - return -1; - memcpy(*target, line->buf + i, spc_i - i); - (*target)[spc_i - i] = '\0'; - if (spc_i - i > UINT16_MAX) { - *target_len = UINT16_MAX; - SMTPSetEvent(state, SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED); - } else { - *target_len = (uint16_t)(spc_i - i); - } - - return 0; -} - -static int SMTPParseCommandHELO(SMTPState *state, const SMTPLine *line) -{ - if (state->helo) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); - return 0; - } - return SMTPParseCommandWithParam(state, line, 4, &state->helo, &state->helo_len); -} - -static int SMTPParseCommandMAILFROM(SMTPState *state, const SMTPLine *line) -{ - if (state->curr_tx->mail_from) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); - return 0; - } - return SMTPParseCommandWithParam( - state, line, 9, &state->curr_tx->mail_from, &state->curr_tx->mail_from_len); -} - -static int SMTPParseCommandRCPTTO(SMTPState *state, const SMTPLine *line) -{ - uint8_t *rcptto; - uint16_t rcptto_len; - - if (SMTPParseCommandWithParam(state, line, 7, &rcptto, &rcptto_len) == 0) { - SMTPString *rcptto_str = SMTPStringAlloc(); - if (rcptto_str) { - rcptto_str->str = rcptto; - rcptto_str->len = rcptto_len; - TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next); - } else { - SCFree(rcptto); - return -1; - } - } else { - return -1; - } - return 0; -} - -/* consider 'rset' and 'quit' to be part of the existing state */ -static int NoNewTx(SMTPState *state, const SMTPLine *line) -{ - if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) { - return 1; - } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) { - return 1; - } - } - return 0; -} - -/* XXX have a better name */ -#define rawmsgname "rawmsg" - -/* - * @brief Process an SMTP Request - * - * Parse and decide the current command and set appropriate variables on the state - * accordingly. Create transactions if needed or update the current transaction - * with the appropriate data/params. Pass the control to the respective command - * parser in the end. - * - * @param state Pointer to current SMTPState - * @param f Pointer to the current Flow - * @param pstate Pointer to the current AppLayerParserState - * @param input Pointer to the current input data to SMTP parser - * @param line Pointer to the current line being parsed by the SMTP parser - * @return 0 for success - * -1 for errors and inconsistent states - * -2 if MIME state could not be allocated - * */ -static int SMTPProcessRequest(SMTPState *state, Flow *f, AppLayerParserState *pstate, - SMTPInput *input, const SMTPLine *line) -{ - SCEnter(); - SMTPTransaction *tx = state->curr_tx; - - /* If current input is to be discarded because it completes a long line, - * line's length and delimiter len are reset to 0. Skip processing this line. - * This line is only to get us out of the state where we should discard any - * data till LF. */ - if (line->len == 0 && line->delim_len == 0) { - return 0; - } - if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state, line))) { - tx = SMTPTransactionCreate(); - if (tx == NULL) - return -1; - state->curr_tx = tx; - TAILQ_INSERT_TAIL(&state->tx_list, tx, next); - tx->tx_id = state->tx_cnt++; - - /* keep track of the start of the tx */ - state->toserver_last_data_stamp = state->toserver_data_count; - StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, - smtp_config.content_inspect_min_size); - } - - state->toserver_data_count += (line->len + line->delim_len); - - if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE); - } - - /* there are 2 commands that can push it into this COMMAND_DATA mode - - * STARTTLS and DATA */ - if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - int r = 0; - - if (line->len >= 8 && SCMemcmpLowercase("starttls", line->buf, 8) == 0) { - state->current_command = SMTP_COMMAND_STARTTLS; - } else if (line->len >= 4 && SCMemcmpLowercase("data", line->buf, 4) == 0) { - state->current_command = SMTP_COMMAND_DATA; - if (smtp_config.raw_extraction) { - if (state->tx_cnt > 1 && !state->curr_tx->done) { - // we did not close the previous tx, set error - SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT); - FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, FILE_TRUNCATED); - tx = SMTPTransactionCreate(); - if (tx == NULL) - return -1; - state->curr_tx = tx; - TAILQ_INSERT_TAIL(&state->tx_list, tx, next); - tx->tx_id = state->tx_cnt++; - } - if (FileOpenFileWithId(&tx->files_ts, &smtp_config.sbcfg, state->file_track_id++, - (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0, - FILE_NOMD5 | FILE_NOMAGIC) == 0) { - SMTPNewFile(tx, tx->files_ts.tail); - } - } else if (smtp_config.decode_mime) { - if (tx->mime_state) { - /* We have 2 chained mails and did not detect the end - * of first one. So we start a new transaction. */ - tx->mime_state->state_flag = PARSE_ERROR; - SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT); - tx = SMTPTransactionCreate(); - if (tx == NULL) - return -1; - state->curr_tx = tx; - TAILQ_INSERT_TAIL(&state->tx_list, tx, next); - tx->tx_id = state->tx_cnt++; - } - tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk); - if (tx->mime_state == NULL) { - return MIME_DEC_ERR_MEM; - } - - /* Add new MIME message to end of list */ - if (tx->msg_head == NULL) { - tx->msg_head = tx->mime_state->msg; - tx->msg_tail = tx->mime_state->msg; - } - else { - tx->msg_tail->next = tx->mime_state->msg; - tx->msg_tail = tx->mime_state->msg; - } - } - /* Enter immediately data mode without waiting for server reply */ - if (state->parser_state & SMTP_PARSER_STATE_PIPELINING_SERVER) { - state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; - } - } else if (line->len >= 4 && SCMemcmpLowercase("bdat", line->buf, 4) == 0) { - r = SMTPParseCommandBDAT(state, line); - if (r == -1) { - SCReturnInt(-1); - } - state->current_command = SMTP_COMMAND_BDAT; - state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; - } else if (line->len >= 4 && ((SCMemcmpLowercase("helo", line->buf, 4) == 0) || - SCMemcmpLowercase("ehlo", line->buf, 4) == 0)) { - r = SMTPParseCommandHELO(state, line); - if (r == -1) { - SCReturnInt(-1); - } - state->current_command = SMTP_COMMAND_OTHER_CMD; - } else if (line->len >= 9 && SCMemcmpLowercase("mail from", line->buf, 9) == 0) { - r = SMTPParseCommandMAILFROM(state, line); - if (r == -1) { - SCReturnInt(-1); - } - state->current_command = SMTP_COMMAND_OTHER_CMD; - } else if (line->len >= 7 && SCMemcmpLowercase("rcpt to", line->buf, 7) == 0) { - r = SMTPParseCommandRCPTTO(state, line); - if (r == -1) { - SCReturnInt(-1); - } - state->current_command = SMTP_COMMAND_OTHER_CMD; - } else if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) { - // Resets chunk index in case of connection reuse - state->bdat_chunk_idx = 0; - state->current_command = SMTP_COMMAND_RSET; - } else { - state->current_command = SMTP_COMMAND_OTHER_CMD; - } - - /* Every command is inserted into a command buffer, to be matched - * against reply(ies) sent by the server */ - if (SMTPInsertCommandIntoCommandBuffer(state->current_command, - state, f) == -1) { - SCReturnInt(-1); - } - - SCReturnInt(r); - } - - switch (state->current_command) { - case SMTP_COMMAND_STARTTLS: - return SMTPProcessCommandSTARTTLS(state, f, pstate); - - case SMTP_COMMAND_DATA: - return SMTPProcessCommandDATA(state, tx, f, pstate, line); - - case SMTP_COMMAND_BDAT: - return SMTPProcessCommandBDAT(state, f, pstate, line); - - default: - /* we have nothing to do with any other command at this instant. - * Just let it go through */ - SCReturnInt(0); - } -} - -static inline void ResetLine(SMTPLine *line) -{ - if (line != NULL) { - line->len = 0; - line->delim_len = 0; - line->buf = NULL; - } -} - -/* - * @brief Pre Process the data that comes in DATA mode. - * - * If currently, the command that is being processed is DATA, whatever data - * comes as a part of it must be handled by this function. This is because - * there should be no char limit imposition on the line arriving in the DATA - * mode. Such limits are in place for any lines passed to the GetLine function - * and the lines are capped there at SMTP_LINE_BUFFER_LIMIT. - * One such limit in DATA mode may lead to file data or parts of e-mail being - * truncated if the line were too long. - * - * @param state Pointer to the current SMTPState - * @param f Pointer to the current Flow - * @param pstate Pointer to the current AppLayerParserState - * @param input Pointer to the current input data to SMTP parser - * @param line Pointer to the current line being parsed by the SMTP parser - * @return 0 for success - * 1 for handing control over to GetLine - * -1 for errors and inconsistent states - * */ -static int SMTPPreProcessCommands( - SMTPState *state, Flow *f, AppLayerParserState *pstate, SMTPInput *input, SMTPLine *line) -{ - DEBUG_VALIDATE_BUG_ON((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0); - DEBUG_VALIDATE_BUG_ON(line->len != 0); - DEBUG_VALIDATE_BUG_ON(line->delim_len != 0); - - /* fall back to strict line parsing for mime header parsing */ - if (state->curr_tx && state->curr_tx->mime_state && - state->curr_tx->mime_state->state_flag < HEADER_DONE) - return 1; - - bool line_complete = false; - const int32_t input_len = input->len; - const int32_t offset = input->consumed; - for (int32_t i = 0; i < input_len; i++) { - if (input->buf[offset + i] == 0x0d) { - if (i < input_len - 1 && input->buf[offset + i + 1] == 0x0a) { - i++; - line->delim_len++; - } - /* Line is just ending in CR */ - line->delim_len++; - line_complete = true; - } else if (input->buf[offset + i] == 0x0a) { - /* Line is just ending in LF */ - line->delim_len++; - line_complete = true; - } - /* Either line is complete or fragmented */ - if (line_complete || (i == input_len - 1)) { - DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len); - DEBUG_VALIDATE_BUG_ON(input->len == 0 && input_len != 0); - /* state->input_len reflects data from start of the line in progress. */ - if ((input->len == 1 && input->buf[input->consumed] == '-') || - (input->len > 1 && input->buf[input->consumed] == '-' && - input->buf[input->consumed + 1] == '-')) { - SCLogDebug("Possible boundary, yield to GetLine"); - return 1; - } - /* total_consumed should be input consumed so far + i + 1 */ - int32_t total_consumed = offset + i + 1; - int32_t current_line_consumed = total_consumed - input->consumed; - DEBUG_VALIDATE_BUG_ON(current_line_consumed < line->delim_len); - line->buf = input->buf + input->consumed; - line->len = current_line_consumed - line->delim_len; - DEBUG_VALIDATE_BUG_ON(line->len < 0); - if (line->len < 0) { - return -1; - } - input->consumed = total_consumed; - input->len -= current_line_consumed; - DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len); - if (SMTPProcessRequest(state, f, pstate, input, line) == -1) { - return -1; - } - line_complete = false; - line->buf = NULL; - line->len = 0; - line->delim_len = 0; - - /* bail if `SMTPProcessRequest` ended the data mode */ - if ((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0) - break; - } - } - return 0; -} - -static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state, - AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data) -{ - SCEnter(); - - const uint8_t *input_buf = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - if (input_buf == NULL && - ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) || - (direction == 1 && - AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) { - SCReturnStruct(APP_LAYER_OK); - } else if (input_buf == NULL || input_len == 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - - SMTPInput input = { .buf = input_buf, .len = input_len, .orig_len = input_len, .consumed = 0 }; - SMTPLine line = { NULL, 0, 0, false }; - - /* toserver */ - if (direction == 0) { - if (((state->current_command == SMTP_COMMAND_DATA) || - (state->current_command == SMTP_COMMAND_BDAT)) && - (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - int ret = SMTPPreProcessCommands(state, f, pstate, &input, &line); - DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1); - if (ret == 0 && input.consumed == input.orig_len) { - SCReturnStruct(APP_LAYER_OK); - } else if (ret < 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - } - AppLayerResult res = SMTPGetLine(state, &input, &line, direction); - while (res.status == 0) { - int retval = SMTPProcessRequest(state, f, pstate, &input, &line); - if (retval != 0) - SCReturnStruct(APP_LAYER_ERROR); - if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) { - if (!line.lf_found) { - state->discard_till_lf_ts = true; - } - input.consumed = input.len + 1; // For the newly found LF - SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE); - break; - } - /* If request was successfully parsed, reset line as it has already been used - * wherever it had to be */ - ResetLine(&line); - - /* If DATA mode was entered in the middle of input parsing, exempt it from GetLine as we - * don't want input limits to be exercised on DATA data. Here, SMTPPreProcessCommands - * should either consume all the data or return in case it encounters another boundary. - * In case of another boundary, the control should be passed to SMTPGetLine */ - if ((input.len > 0) && (state->current_command == SMTP_COMMAND_DATA) && - (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - int ret = SMTPPreProcessCommands(state, f, pstate, &input, &line); - DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1); - if (ret == 0 && input.consumed == input.orig_len) { - SCReturnStruct(APP_LAYER_OK); - } else if (ret < 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - } - res = SMTPGetLine(state, &input, &line, direction); - } - if (res.status == 1) - return res; - /* toclient */ - } else { - AppLayerResult res = SMTPGetLine(state, &input, &line, direction); - while (res.status == 0) { - if (SMTPProcessReply(state, f, pstate, thread_data, &input, &line) != 0) - SCReturnStruct(APP_LAYER_ERROR); - if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) { - if (!line.lf_found) { - state->discard_till_lf_tc = true; - } - input.consumed = input.len + 1; // For the newly found LF - SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE); - break; - } - res = SMTPGetLine(state, &input, &line, direction); - } - if (res.status == 1) - return res; - } - - SCReturnStruct(APP_LAYER_OK); -} - -static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - SCEnter(); - - /* first arg 0 is toserver */ - return SMTPParse(0, f, alstate, pstate, stream_slice, local_data); -} - -static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - SCEnter(); - - /* first arg 1 is toclient */ - return SMTPParse(1, f, alstate, pstate, stream_slice, local_data); -} - -/** - * \internal - * \brief Function to allocate SMTP state memory. - */ -void *SMTPStateAlloc(void *orig_state, AppProto proto_orig) -{ - SMTPState *smtp_state = SCCalloc(1, sizeof(SMTPState)); - if (unlikely(smtp_state == NULL)) - return NULL; - - smtp_state->cmds = SCMalloc(sizeof(uint8_t) * - SMTP_COMMAND_BUFFER_STEPS); - if (smtp_state->cmds == NULL) { - SCFree(smtp_state); - return NULL; - } - smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS; - - TAILQ_INIT(&smtp_state->tx_list); - - return smtp_state; -} - -static SMTPString *SMTPStringAlloc(void) -{ - SMTPString *smtp_string = SCCalloc(1, sizeof(SMTPString)); - if (unlikely(smtp_string == NULL)) - return NULL; - - return smtp_string; -} - - -static void SMTPStringFree(SMTPString *str) -{ - if (str->str) { - SCFree(str->str); - } - SCFree(str); -} - -static void *SMTPLocalStorageAlloc(void) -{ - /* needed by the mpm */ - SMTPThreadCtx *td = SCCalloc(1, sizeof(*td)); - if (td == NULL) { - exit(EXIT_FAILURE); - } - - td->pmq = SCCalloc(1, sizeof(*td->pmq)); - if (td->pmq == NULL) { - exit(EXIT_FAILURE); - } - PmqSetup(td->pmq); - - td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx)); - if (unlikely(td->smtp_mpm_thread_ctx == NULL)) { - exit(EXIT_FAILURE); - } - MpmInitThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM); - return td; -} - -static void SMTPLocalStorageFree(void *ptr) -{ - SMTPThreadCtx *td = ptr; - if (td != NULL) { - if (td->pmq != NULL) { - PmqFree(td->pmq); - SCFree(td->pmq); - } - - if (td->smtp_mpm_thread_ctx != NULL) { - MpmDestroyThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM); - SCFree(td->smtp_mpm_thread_ctx); - } - - SCFree(td); - } - - return; -} - -static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) -{ - if (tx->mime_state != NULL) { - MimeDecDeInitParser(tx->mime_state); - } - /* Free list of MIME message recursively */ - MimeDecFreeEntity(tx->msg_head); - - if (tx->tx_data.events != NULL) - AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); - - if (tx->tx_data.de_state != NULL) - DetectEngineStateFree(tx->tx_data.de_state); - - if (tx->mail_from) - SCFree(tx->mail_from); - - SMTPString *str = NULL; - while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) { - TAILQ_REMOVE(&tx->rcpt_to_list, str, next); - SMTPStringFree(str); - } - FileContainerRecycle(&tx->files_ts, &smtp_config.sbcfg); - - SCFree(tx); -} - -/** - * \internal - * \brief Function to free SMTP state memory. - */ -static void SMTPStateFree(void *p) -{ - SMTPState *smtp_state = (SMTPState *)p; - - if (smtp_state->cmds != NULL) { - SCFree(smtp_state->cmds); - } - - if (smtp_state->helo) { - SCFree(smtp_state->helo); - } - - SMTPTransaction *tx = NULL; - while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) { - TAILQ_REMOVE(&smtp_state->tx_list, tx, next); - SMTPTransactionFree(tx, smtp_state); - } - - SCFree(smtp_state); - - return; -} - -static void SMTPSetMpmState(void) -{ - smtp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx)); - if (unlikely(smtp_mpm_ctx == NULL)) { - exit(EXIT_FAILURE); - } - MpmInitCtx(smtp_mpm_ctx, SMTP_MPM); - - uint32_t i = 0; - for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) { - SCEnumCharMap *map = &smtp_reply_map[i]; - /* The third argument is 3, because reply code is always 3 bytes. */ - MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3, - 0 /* defunct */, 0 /* defunct */, - i /* pattern id */, i /* rule id */ , 0 /* no flags */); - } - - mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); - -} - -static void SMTPFreeMpmState(void) -{ - if (smtp_mpm_ctx != NULL) { - mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx); - SCFree(smtp_mpm_ctx); - smtp_mpm_ctx = NULL; - } -} - -static int SMTPStateGetEventInfo(const char *event_name, - int *event_id, AppLayerEventType *event_type) -{ - *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table); - if (*event_id == -1) { - SCLogError("event \"%s\" not present in " - "smtp's enum map table.", - event_name); - /* yes this is fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static int SMTPStateGetEventInfoById(int event_id, const char **event_name, - AppLayerEventType *event_type) -{ - *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table); - if (*event_name == NULL) { - SCLogError("event \"%d\" not present in " - "smtp's enum map table.", - event_id); - /* yes this is fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static int SMTPRegisterPatternsForProtocolDetection(void) -{ - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, - "EHLO", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, - "HELO", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, - "QUIT", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - return 0; -} - -static void SMTPStateTransactionFree (void *state, uint64_t tx_id) -{ - SMTPState *smtp_state = state; - SMTPTransaction *tx = NULL; - TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { - if (tx_id < tx->tx_id) - break; - else if (tx_id > tx->tx_id) - continue; - - if (tx == smtp_state->curr_tx) - smtp_state->curr_tx = NULL; - TAILQ_REMOVE(&smtp_state->tx_list, tx, next); - SMTPTransactionFree(tx, state); - break; - } - - -} - -/** \retval cnt highest tx id */ -static uint64_t SMTPStateGetTxCnt(void *state) -{ - uint64_t cnt = 0; - SMTPState *smtp_state = state; - if (smtp_state) { - cnt = smtp_state->tx_cnt; - } - SCLogDebug("returning %"PRIu64, cnt); - return cnt; -} - -static void *SMTPStateGetTx(void *state, uint64_t id) -{ - SMTPState *smtp_state = state; - if (smtp_state) { - SMTPTransaction *tx = NULL; - - if (smtp_state->curr_tx == NULL) - return NULL; - if (smtp_state->curr_tx->tx_id == id) - return smtp_state->curr_tx; - - TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { - if (tx->tx_id == id) - return tx; - } - } - return NULL; - -} - -static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction) -{ - SMTPTransaction *tx = vtx; - return tx->done; -} - -static AppLayerGetFileState SMTPGetTxFiles(void *state, void *txv, uint8_t direction) -{ - AppLayerGetFileState files = { .fc = NULL, .cfg = &smtp_config.sbcfg }; - SMTPTransaction *tx = (SMTPTransaction *)txv; - - if (direction & STREAM_TOSERVER) { - files.fc = &tx->files_ts; - } - return files; -} - -static AppLayerTxData *SMTPGetTxData(void *vtx) -{ - SMTPTransaction *tx = (SMTPTransaction *)vtx; - return &tx->tx_data; -} - -static AppLayerStateData *SMTPGetStateData(void *vstate) -{ - SMTPState *state = (SMTPState *)vstate; - return &state->state_data; -} - -/** \brief SMTP tx iterator, specialized for its linked list - * - * \retval txptr or NULL if no more txs in list - */ -static AppLayerGetTxIterTuple SMTPGetTxIterator(const uint8_t ipproto, const AppProto alproto, - void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) -{ - SMTPState *smtp_state = (SMTPState *)alstate; - AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; - if (smtp_state) { - SMTPTransaction *tx_ptr; - if (state->un.ptr == NULL) { - tx_ptr = TAILQ_FIRST(&smtp_state->tx_list); - } else { - tx_ptr = (SMTPTransaction *)state->un.ptr; - } - if (tx_ptr) { - while (tx_ptr->tx_id < min_tx_id) { - tx_ptr = TAILQ_NEXT(tx_ptr, next); - if (!tx_ptr) { - return no_tuple; - } - } - if (tx_ptr->tx_id >= max_tx_id) { - return no_tuple; - } - state->un.ptr = TAILQ_NEXT(tx_ptr, next); - AppLayerGetTxIterTuple tuple = { - .tx_ptr = tx_ptr, - .tx_id = tx_ptr->tx_id, - .has_next = (state->un.ptr != NULL), - }; - return tuple; - } - } - return no_tuple; -} - -/** - * \brief Register the SMTP Protocol parser. - */ -void RegisterSMTPParsers(void) -{ - const char *proto_name = "smtp"; - - if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_SMTP, proto_name); - if (SMTPRegisterPatternsForProtocolDetection() < 0 ) - return; - } else { - SCLogInfo("Protocol detection and parser disabled for %s protocol.", - proto_name); - return; - } - - if (AppLayerParserConfParserEnabled("tcp", proto_name)) { - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree); - - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER, - SMTPParseClientRecord); - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT, - SMTPParseServerRecord); - - AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo); - AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById); - - AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, - SMTPLocalStorageFree); - - AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree); - AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxFiles); - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress); - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt); - AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx); - AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxIterator); - AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData); - AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetStateData); - AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_SMTP, 1, 1); - } else { - SCLogInfo("Parsed disabled for %s protocol. Protocol detection" - "still on.", proto_name); - } - - SMTPSetMpmState(); - - SMTPConfigure(); - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests); -#endif - return; -} - -/** - * \brief Free memory allocated for global SMTP parser state. - */ -void SMTPParserCleanup(void) -{ - SMTPFreeMpmState(); -} - -/***************************************Unittests******************************/ - -#ifdef UNITTESTS -#include "detect-engine-alert.h" - -static void SMTPTestInitConfig(void) -{ - MimeDecSetConfig(&smtp_config.mime_config); - - smtp_config.content_limit = FILEDATA_CONTENT_LIMIT; - smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; - smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; - - smtp_config.sbcfg.buf_size = FILEDATA_CONTENT_INSPECT_WINDOW; -} - -/* - * \test Test STARTTLS. - */ -static int SMTPParserTest01(void) -{ - int result = 0; - Flow f; - int r = 0; - - /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ - uint8_t welcome_reply[] = { - 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, - 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, - 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, - 0x0d, 0x0a - }; - uint32_t welcome_reply_len = sizeof(welcome_reply); - - /* EHLO [192.168.0.158] */ - uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39, - 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, - 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a - }; - uint32_t request1_len = sizeof(request1); - /* 250-mx.google.com at your service, [117.198.115.50] - * 250-SIZE 35882577 - * 250-8BITMIME - * 250-STARTTLS - * 250 ENHANCEDSTATUSCODES - */ - uint8_t reply1[] = { - 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, - 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e, - 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e, - 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, - 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35, - 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a, - 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54, - 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, - 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, - 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f, - 0x44, 0x45, 0x53, 0x0d, 0x0a - }; - uint32_t reply1_len = sizeof(reply1); - - /* STARTTLS */ - uint8_t request2[] = { - 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, - 0x0d, 0x0a - }; - uint32_t request2_len = sizeof(request2); - /* 220 2.0.0 Ready to start TLS */ - uint8_t reply2[] = { - 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, - 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20, - 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a - }; - uint32_t reply2_len = sizeof(reply2); - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, welcome_reply, welcome_reply_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - SMTPState *smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply1, reply1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply2, reply2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - if (!FlowChangeProto(&f)) { - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** - * \test Test multiple DATA commands(full mail transactions). - */ -static int SMTPParserTest02(void) -{ - int result = 0; - Flow f; - int r = 0; - - /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ - uint8_t welcome_reply[] = { - 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, - 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, - 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, - 0x0d, 0x0a - }; - uint32_t welcome_reply_len = sizeof(welcome_reply); - - /* EHLO boo.com */ - uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a - }; - uint32_t request1_len = sizeof(request1); - /* 250-mx.google.com at your service, [117.198.115.50] - * 250-SIZE 35882577 - * 250-8BITMIME - * 250-STARTTLS - * 250 ENHANCEDSTATUSCODES - */ - uint8_t reply1[] = { - 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, - 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, - 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, - 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, - 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, - 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, - 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, - 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a - }; - uint32_t reply1_len = sizeof(reply1); - - /* MAIL FROM:asdff@asdf.com */ - uint8_t request2[] = { - 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, - 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, - 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a - }; - uint32_t request2_len = sizeof(request2); - /* 250 2.1.0 Ok */ - uint8_t reply2[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - uint32_t reply2_len = sizeof(reply2); - - /* RCPT TO:bimbs@gmail.com */ - uint8_t request3[] = { - 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, - 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, - 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, - 0x0a - }; - uint32_t request3_len = sizeof(request3); - /* 250 2.1.5 Ok */ - uint8_t reply3[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - uint32_t reply3_len = sizeof(reply3); - - /* DATA */ - uint8_t request4[] = { - 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a - }; - uint32_t request4_len = sizeof(request4); - /* 354 End data with .|| */ - uint8_t reply4[] = { - 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, - 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, - 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, - 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, - 0x4c, 0x46, 0x3e, 0x0d, 0x0a - }; - uint32_t reply4_len = sizeof(reply4); - - /* FROM:asdff@asdf.com */ - uint8_t request5_1[] = { - 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, - 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, - 0x63, 0x6f, 0x6d, 0x0d, 0x0a - }; - uint32_t request5_1_len = sizeof(request5_1); - /* TO:bimbs@gmail.com */ - uint8_t request5_2[] = { - 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, - 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, - 0x6f, 0x6d, 0x0d, 0x0a - }; - uint32_t request5_2_len = sizeof(request5_2); - /* */ - uint8_t request5_3[] = { - 0x0d, 0x0a - }; - uint32_t request5_3_len = sizeof(request5_3); - /* this is test mail1 */ - uint8_t request5_4[] = { - 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, - 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69, - 0x6c, 0x31, 0x0d, 0x0a - }; - uint32_t request5_4_len = sizeof(request5_4); - /* . */ - uint8_t request5_5[] = { - 0x2e, 0x0d, 0x0a - }; - uint32_t request5_5_len = sizeof(request5_5); - /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ - uint8_t reply5[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, - 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, - 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, - 0x46, 0x32, 0x0d, 0x0a - }; - uint32_t reply5_len = sizeof(reply5); - - /* MAIL FROM:asdfg@asdf.com */ - uint8_t request6[] = { - 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, - 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40, - 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a - }; - uint32_t request6_len = sizeof(request6); - /* 250 2.1.0 Ok */ - uint8_t reply6[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - uint32_t reply6_len = sizeof(reply6); - - /* RCPT TO:bimbs@gmail.com */ - uint8_t request7[] = { - 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, - 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, - 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, - 0x0a - }; - uint32_t request7_len = sizeof(request7); - /* 250 2.1.5 Ok */ - uint8_t reply7[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - uint32_t reply7_len = sizeof(reply7); - - /* DATA */ - uint8_t request8[] = { - 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a - }; - uint32_t request8_len = sizeof(request8); - /* 354 End data with .|| */ - uint8_t reply8[] = { - 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, - 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, - 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, - 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, - 0x4c, 0x46, 0x3e, 0x0d, 0x0a - }; - uint32_t reply8_len = sizeof(reply8); - - /* FROM:asdfg@gmail.com */ - uint8_t request9_1[] = { - 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, - 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, - 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a - }; - uint32_t request9_1_len = sizeof(request9_1); - /* TO:bimbs@gmail.com */ - uint8_t request9_2[] = { - 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, - 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, - 0x6f, 0x6d, 0x0d, 0x0a - }; - uint32_t request9_2_len = sizeof(request9_2); - /* */ - uint8_t request9_3[] = { - 0x0d, 0x0a - }; - uint32_t request9_3_len = sizeof(request9_3); - /* this is test mail2 */ - uint8_t request9_4[] = { - 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, - 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69, - 0x6c, 0x32, 0x0d, 0x0a - }; - uint32_t request9_4_len = sizeof(request9_4); - /* . */ - uint8_t request9_5[] = { - 0x2e, 0x0d, 0x0a - }; - uint32_t request9_5_len = sizeof(request9_5); - /* 250 2.0.0 Ok: queued as 28CFF20BF2 */ - uint8_t reply9[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, - 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, - 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42, - 0x46, 0x32, 0x0d, 0x0a - }; - uint32_t reply9_len = sizeof(reply9); - - /* QUIT */ - uint8_t request10[] = { - 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a - }; - uint32_t request10_len = sizeof(request10); - /* 221 2.0.0 Bye */ - uint8_t reply10[] = { - 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, - 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a - }; - uint32_t reply10_len = sizeof(reply10); - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, welcome_reply, welcome_reply_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - SMTPState *smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply1, reply1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply2, reply2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply3, reply3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request4, request4_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_DATA || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply4, reply4_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request5_1, request5_1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request5_2, request5_2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request5_3, request5_3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request5_4, request5_4_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request5_5, request5_5_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply5, reply5_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request6, request6_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply6, reply6_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request7, request7_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply7, reply7_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request8, request8_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_DATA || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply8, reply8_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request9_1, request9_1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request9_2, request9_2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request9_3, request9_3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request9_4, request9_4_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request9_5, request9_5_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply9, reply9_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request10, request10_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply10, reply10_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** - * \test Testing parsing pipelined commands. - */ -static int SMTPParserTest03(void) -{ - int result = 0; - Flow f; - int r = 0; - - /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ - uint8_t welcome_reply[] = { - 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, - 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, - 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a - }; - uint32_t welcome_reply_len = sizeof(welcome_reply); - - /* EHLO boo.com */ - uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x0a - }; - uint32_t request1_len = sizeof(request1); - /* 250-poona_slack_vm1.localdomain - * 250-PIPELINING - * 250-SIZE 10240000 - * 250-VRFY - * 250-ETRN - * 250-ENHANCEDSTATUSCODES - * 250-8BITMIME - * 250 DSN - */ - uint8_t reply1[] = { - 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, - 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, - 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, - 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, - 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, - 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, - 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, - 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, - 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a - }; - uint32_t reply1_len = sizeof(reply1); - - /* MAIL FROM:pbsf@asdfs.com - * RCPT TO:pbsf@asdfs.com - * DATA - * Immediate data - */ - uint8_t request2[] = { - 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, - 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, - 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, - 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, - 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a, - 0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, - 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a, - }; - uint32_t request2_len = sizeof(request2); - /* 250 2.1.0 Ok - * 250 2.1.5 Ok - * 354 End data with .|| - */ - uint8_t reply2[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20, - 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20, - 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, - 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43, - 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c, - 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d, - 0x0a - }; - uint32_t reply2_len = sizeof(reply2); - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, welcome_reply, welcome_reply_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - SMTPState *smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply1, reply1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD || - smtp_state->cmds[2] != SMTP_COMMAND_DATA || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE | - SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply2, reply2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE | - SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/* - * \test Test smtp with just delimiter instead of . - */ -static int SMTPParserTest04(void) -{ - int result = 0; - Flow f; - int r = 0; - - /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ - uint8_t welcome_reply[] = { - 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, - 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, - 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a - }; - uint32_t welcome_reply_len = sizeof(welcome_reply); - - /* EHLO boo.com */ - uint8_t request1[] = { - 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, - 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, - 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a - }; - uint32_t request1_len = sizeof(request1); - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, welcome_reply, welcome_reply_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - SMTPState *smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/* - * \test Test STARTTLS fail. - */ -static int SMTPParserTest05(void) -{ - int result = 0; - Flow f; - int r = 0; - - /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ - uint8_t welcome_reply[] = { - 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, - 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, - 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a - }; - uint32_t welcome_reply_len = sizeof(welcome_reply); - - /* EHLO boo.com */ - uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a - }; - uint32_t request1_len = sizeof(request1); - /* 250-poona_slack_vm1.localdomain - * 250-PIPELINING - * 250-SIZE 10240000 - * 250-VRFY - * 250-ETRN - * 250-ENHANCEDSTATUSCODES - * 250-8BITMIME - * 250 DSN - */ - uint8_t reply1[] = { - 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, - 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, - 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, - 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, - 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, - 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, - 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, - 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, - 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a - }; - uint32_t reply1_len = sizeof(reply1); - - /* STARTTLS */ - uint8_t request2[] = { - 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, - 0x0d, 0x0a - }; - uint32_t request2_len = sizeof(request2); - /* 502 5.5.2 Error: command not recognized */ - uint8_t reply2[] = { - 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e, - 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, - 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63, - 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d, - 0x0a - }; - uint32_t reply2_len = sizeof(reply2); - - /* QUIT */ - uint8_t request3[] = { - 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a - - }; - uint32_t request3_len = sizeof(request3); - /* 221 2.0.0 Bye */ - uint8_t reply3[] = { - 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, - 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a - }; - uint32_t reply3_len = sizeof(reply3); - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, welcome_reply, welcome_reply_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - SMTPState *smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply1, reply1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply2, reply2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) || - (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || - (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply3, reply3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** - * \test Test multiple DATA commands(full mail transactions). - */ -static int SMTPParserTest06(void) -{ - int result = 0; - Flow f; - int r = 0; - - uint8_t welcome_reply[] = { - 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30, - 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30, - 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f, - 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, - 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69, - 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f, - 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, - 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b, - 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20, - 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f, - 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63, - 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69, - 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f, - 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, - 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f, - 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68, - 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72, - 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73, - 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e, - 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f, - 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c, - 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20, - 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70, - 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, - 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, - 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, - 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69, - 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62, - 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35, - 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d, - 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a - }; - uint32_t welcome_reply_len = sizeof(welcome_reply); - - uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43, - 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63, - 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69, - 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d, - 0x0a - }; - uint32_t request1_len = sizeof(request1); - - uint8_t reply1[] = { - 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30, - 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30, - 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f, - 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, - 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31, - 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c, - 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31, - 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39, - 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, - 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39, - 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69, - 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, - 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49, - 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, - 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47, - 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55, - 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e, - 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55, - 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e, - 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b, - 0x0d, 0x0a - }; - uint32_t reply1_len = sizeof(reply1); - - /* MAIL FROM:asdff@asdf.com */ - uint8_t request2[] = { - 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, - 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, - 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a - }; - uint32_t request2_len = sizeof(request2); - /* 250 2.1.0 Ok */ - uint8_t reply2[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - uint32_t reply2_len = sizeof(reply2); - - /* RCPT TO:bimbs@gmail.com */ - uint8_t request3[] = { - 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, - 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, - 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, - 0x0a - }; - uint32_t request3_len = sizeof(request3); - /* 250 2.1.5 Ok */ - uint8_t reply3[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - uint32_t reply3_len = sizeof(reply3); - - /* BDAT 51 */ - uint8_t request4[] = { - 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d, - 0x0a, - }; - uint32_t request4_len = sizeof(request4); - - uint8_t request5[] = { - 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, - 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, - 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, - 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a, - }; - uint32_t request5_len = sizeof(request5); - - uint8_t request6[] = { - 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, - 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, - 0x66, 0x0d, 0x0a, - }; - uint32_t request6_len = sizeof(request6); - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, welcome_reply, welcome_reply_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - SMTPState *smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply1, reply1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply2, reply2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply3, reply3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request4, request4_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_BDAT || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE) || - smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 0) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request5, request5_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE) || - smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 32) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request6, request6_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN || - smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 51) { - printf("smtp parser in inconsistent state\n"); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -static int SMTPParserTest12(void) -{ - int result = 0; - Signature *s = NULL; - ThreadVars th_v; - Packet *p = NULL; - Flow f; - TcpSession ssn; - DetectEngineThreadCtx *det_ctx = NULL; - DetectEngineCtx *de_ctx = NULL; - SMTPState *smtp_state = NULL; - int r = 0; - - /* EHLO boo.com */ - uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, - }; - int32_t request1_len = sizeof(request1); - - /* 388 - */ - uint8_t reply1[] = { - 0x31, 0x38, 0x38, 0x0d, 0x0a, - }; - uint32_t reply1_len = sizeof(reply1); - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any " - "(msg:\"SMTP event handling\"; " - "app-layer-event: smtp.invalid_reply; " - "sid:1;)"); - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER | STREAM_START, request1, - request1_len); - if (r != 0) { - printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - goto end; - } - - smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched. It shouldn't match: "); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT | STREAM_TOCLIENT, reply1, - reply1_len); - if (r == 0) { - printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match. Should have matched: "); - goto end; - } - - result = 1; - -end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -static int SMTPParserTest13(void) -{ - int result = 0; - Signature *s = NULL; - ThreadVars th_v; - Packet *p = NULL; - Flow f; - TcpSession ssn; - DetectEngineThreadCtx *det_ctx = NULL; - DetectEngineCtx *de_ctx = NULL; - SMTPState *smtp_state = NULL; - int r = 0; - - /* EHLO boo.com */ - uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, - }; - int32_t request1_len = sizeof(request1); - - /* 250 - */ - uint8_t reply1[] = { - 0x32, 0x35, 0x30, 0x0d, 0x0a, - }; - uint32_t reply1_len = sizeof(reply1); - - /* MAIL FROM:pbsf@asdfs.com - * RCPT TO:pbsf@asdfs.com - * DATA - * STARTTLS - */ - uint8_t request2[] = { - 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, - 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, - 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, - 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, - 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a, - 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, - 0x0d, 0x0a - }; - uint32_t request2_len = sizeof(request2); - - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"SMTP event handling\"; " - "app-layer-event: " - "smtp.invalid_pipelined_sequence; " - "sid:1;)"); - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER | STREAM_START, request1, - request1_len); - if (r != 0) { - printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - goto end; - } - - smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched. It shouldn't match: "); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply1, reply1_len); - if (r != 0) { - printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched. It shouldn't match: "); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match. Should have matched: "); - goto end; - } - - result = 1; - -end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - * \test Test DATA command w/MIME message. - */ -static int SMTPParserTest14(void) -{ - int result = 0; - Flow f; - int r = 0; - - /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ - static uint8_t welcome_reply[] = { - 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, - 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, - 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, - 0x0d, 0x0a - }; - static uint32_t welcome_reply_len = sizeof(welcome_reply); - - /* EHLO boo.com */ - static uint8_t request1[] = { - 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, - 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a - }; - static uint32_t request1_len = sizeof(request1); - /* 250-mx.google.com at your service, [117.198.115.50] - * 250-SIZE 35882577 - * 250-8BITMIME - * 250-STARTTLS - * 250 ENHANCEDSTATUSCODES - */ - static uint8_t reply1[] = { - 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, - 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, - 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, - 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, - 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, - 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, - 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, - 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, - 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, - 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a - }; - static uint32_t reply1_len = sizeof(reply1); - - /* MAIL FROM:asdff@asdf.com */ - static uint8_t request2[] = { - 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, - 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, - 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a - }; - static uint32_t request2_len = sizeof(request2); - /* 250 2.1.0 Ok */ - static uint8_t reply2[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - static uint32_t reply2_len = sizeof(reply2); - - /* RCPT TO:bimbs@gmail.com */ - static uint8_t request3[] = { - 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, - 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, - 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, - 0x0a - }; - static uint32_t request3_len = sizeof(request3); - /* 250 2.1.5 Ok */ - static uint8_t reply3[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, - 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a - }; - static uint32_t reply3_len = sizeof(reply3); - - /* DATA */ - static uint8_t request4[] = { - 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a - }; - static uint32_t request4_len = sizeof(request4); - /* 354 End data with .|| */ - static uint8_t reply4[] = { - 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, - 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, - 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, - 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, - 0x4c, 0x46, 0x3e, 0x0d, 0x0a - }; - static uint32_t reply4_len = sizeof(reply4); - - /* MIME_MSG */ - static uint64_t filesize = 133; - static uint8_t request4_msg[] = { - 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, - 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, - 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, - 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, - 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, - 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, - 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, - 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, - 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, - 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, - 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, - 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, - 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, - 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78, - 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, - 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41, - 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61, - 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, - 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43, - 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41, - 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65, - 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, - 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, - 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C, - 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, - 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, - 0x41, 0x3D, 0x3D, 0x0D,0x0A }; - static uint32_t request4_msg_len = sizeof(request4_msg); - - /* DATA COMPLETED */ - static uint8_t request4_end[] = { - 0x0d, 0x0a, 0x2e, 0x0d, 0x0a - }; - static uint32_t request4_end_len = sizeof(request4_end); - /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ - static uint8_t reply4_end[] = { - 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, - 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, - 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, - 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, - 0x46, 0x32, 0x0d, 0x0a - }; - static uint32_t reply4_end_len = sizeof(reply4_end); - - /* QUIT */ - static uint8_t request5[] = { - 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a - }; - static uint32_t request5_len = sizeof(request5); - /* 221 2.0.0 Bye */ - static uint8_t reply5[] = { - 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, - 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a - }; - static uint32_t reply5_len = sizeof(reply5); - - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.alproto = ALPROTO_SMTP; - - StreamTcpInitConfig(true); - SMTPTestInitConfig(); - - /* Welcome reply */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, welcome_reply, welcome_reply_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - SMTPState *smtp_state = f.alstate; - if (smtp_state == NULL) { - printf("no smtp state: "); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* EHLO Reply */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply1, reply1_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - - if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) { - printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len); - goto end; - } - - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* MAIL FROM Request */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* MAIL FROM Reply */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply2, reply2_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - - if ((smtp_state->curr_tx->mail_from_len != 14) || - strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) { - printf("incorrect parsing of MAIL FROM field '%s' (%d)\n", - smtp_state->curr_tx->mail_from, - smtp_state->curr_tx->mail_from_len); - goto end; - } - - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* RCPT TO Request */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* RCPT TO Reply */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply3, reply3_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* Enable mime decoding */ - smtp_config.decode_mime = true; - smtp_config.mime_config.decode_base64 = true; - smtp_config.mime_config.decode_quoted_printable = true; - MimeDecSetConfig(&smtp_config.mime_config); - - /* DATA request */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request4, request4_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_DATA || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* Data reply */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply4, reply4_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* DATA message */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request4_msg, request4_msg_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->curr_tx->mime_state == NULL || - smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ - smtp_state->parser_state != - (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* DATA . request */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request4_end, request4_end_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || - smtp_state->curr_tx->mime_state == NULL || - smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - SMTPState *state = (SMTPState *) f.alstate; - FAIL_IF_NULL(state); - FAIL_IF_NULL(state->curr_tx); - - FileContainer *files = &state->curr_tx->files_ts; - if (files != NULL && files->head != NULL) { - File *file = files->head; - - if(strncmp((const char *)file->name, "test.exe", 8) != 0){ - printf("smtp-mime file name is incorrect"); - goto end; - } - if (FileTrackedSize(file) != filesize){ - printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file)); - goto end; - } - static uint8_t org_binary[] = { - 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, - 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00, - 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, - 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36, - 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36, - 0x5C, 0x7A, 0x00, 0x00, 0x38,}; - - if (StreamingBufferCompareRawData(file->sb, - org_binary, sizeof(org_binary)) != 1) - { - printf("smtp-mime file data incorrect\n"); - goto end; - } - } - - /* DATA . reply */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply4_end, reply4_end_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* QUIT Request */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOSERVER, request5, request5_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || - smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - /* QUIT Reply */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, - STREAM_TOCLIENT, reply5, reply5_len); - if (r != 0) { - printf("smtp check returned %" PRId32 ", expected 0: ", r); - goto end; - } - if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - printf("smtp parser in inconsistent state l.%d\n", __LINE__); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} -#endif /* UNITTESTS */ - -void SMTPParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SMTPParserTest01", SMTPParserTest01); - UtRegisterTest("SMTPParserTest02", SMTPParserTest02); - UtRegisterTest("SMTPParserTest03", SMTPParserTest03); - UtRegisterTest("SMTPParserTest04", SMTPParserTest04); - UtRegisterTest("SMTPParserTest05", SMTPParserTest05); - UtRegisterTest("SMTPParserTest06", SMTPParserTest06); - UtRegisterTest("SMTPParserTest12", SMTPParserTest12); - UtRegisterTest("SMTPParserTest13", SMTPParserTest13); - UtRegisterTest("SMTPParserTest14", SMTPParserTest14); -#endif /* UNITTESTS */ - - return; -} diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h deleted file mode 100644 index 9fc1d506bbbb..000000000000 --- a/src/app-layer-smtp.h +++ /dev/null @@ -1,161 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __APP_LAYER_SMTP_H__ -#define __APP_LAYER_SMTP_H__ - -#include "util-decode-mime.h" -#include "util-streaming-buffer.h" -#include "rust.h" - -/* Limit till the data would be buffered in current line */ -#define SMTP_LINE_BUFFER_LIMIT 4096 - -enum { - SMTP_DECODER_EVENT_INVALID_REPLY, - SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST, - SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED, - SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED, - SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE, - SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED, - SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE, - SMTP_DECODER_EVENT_TLS_REJECTED, - SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED, - SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE, - - /* MIME Events */ - SMTP_DECODER_EVENT_MIME_PARSE_FAILED, - SMTP_DECODER_EVENT_MIME_MALFORMED_MSG, - SMTP_DECODER_EVENT_MIME_INVALID_BASE64, - SMTP_DECODER_EVENT_MIME_INVALID_QP, - SMTP_DECODER_EVENT_MIME_LONG_LINE, - SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE, - SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME, - SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE, - SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG, - SMTP_DECODER_EVENT_MIME_LONG_FILENAME, - - /* Invalid behavior or content */ - SMTP_DECODER_EVENT_DUPLICATE_FIELDS, - SMTP_DECODER_EVENT_UNPARSABLE_CONTENT, - /* For line >= 4KB */ - SMTP_DECODER_EVENT_TRUNCATED_LINE, -}; - -typedef struct SMTPString_ { - uint8_t *str; - uint16_t len; - - TAILQ_ENTRY(SMTPString_) next; -} SMTPString; - -typedef struct SMTPTransaction_ { - /** id of this tx, starting at 0 */ - uint64_t tx_id; - - AppLayerTxData tx_data; - - int done; - /** the first message contained in the session */ - MimeDecEntity *msg_head; - /** the last message contained in the session */ - MimeDecEntity *msg_tail; - /** the mime decoding parser state */ - MimeDecParseState *mime_state; - - /* MAIL FROM parameters */ - uint8_t *mail_from; - uint16_t mail_from_len; - - TAILQ_HEAD(, SMTPString_) rcpt_to_list; /**< rcpt to string list */ - - FileContainer files_ts; - - TAILQ_ENTRY(SMTPTransaction_) next; -} SMTPTransaction; - -typedef struct SMTPConfig { - - bool decode_mime; - MimeDecConfig mime_config; - uint32_t content_limit; - uint32_t content_inspect_min_size; - uint32_t content_inspect_window; - - bool raw_extraction; - - StreamingBufferConfig sbcfg; -} SMTPConfig; - -typedef struct SMTPState_ { - AppLayerStateData state_data; - SMTPTransaction *curr_tx; - TAILQ_HEAD(, SMTPTransaction_) tx_list; /**< transaction list */ - uint64_t tx_cnt; - uint64_t toserver_data_count; - uint64_t toserver_last_data_stamp; - - /* If rest of the bytes should be discarded in case of long line w/o LF */ - bool discard_till_lf_ts; - bool discard_till_lf_tc; - - /** var to indicate parser state */ - uint8_t parser_state; - /** current command in progress */ - uint8_t current_command; - /** bdat chunk len */ - uint32_t bdat_chunk_len; - /** bdat chunk idx */ - uint32_t bdat_chunk_idx; - - /* the request commands are store here and the reply handler uses these - * stored command in the buffer to match the reply(ies) with the command */ - /** the command buffer */ - uint8_t *cmds; - /** the buffer length */ - uint16_t cmds_buffer_len; - /** no of commands stored in the above buffer */ - uint16_t cmds_cnt; - /** index of the command in the buffer, currently in inspection by reply - * handler */ - uint16_t cmds_idx; - - /* HELO of HELO message content */ - uint16_t helo_len; - uint8_t *helo; - - /* SMTP Mime decoding and file extraction */ - /** the list of files sent to the server */ - uint32_t file_track_id; -} SMTPState; - -/* Create SMTP config structure */ -extern SMTPConfig smtp_config; - -int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state); -void *SMTPStateAlloc(void *orig_state, AppProto proto_orig); -void RegisterSMTPParsers(void); -void SMTPParserCleanup(void); -void SMTPParserRegisterTests(void); - -#endif /* __APP_LAYER_SMTP_H__ */ diff --git a/src/app-layer-snmp.c b/src/app-layer-snmp.c deleted file mode 100644 index 589aa451ed48..000000000000 --- a/src/app-layer-snmp.c +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (C) 2015-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * - * Parser for SNMP v2c/v3 application layer running on UDP port 161. - * - */ - -#include "suricata-common.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-snmp.h" -#include "rust.h" - -void RegisterSNMPParsers(void) -{ - rs_register_snmp_parser(); -} - diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c deleted file mode 100644 index 71bc786ad6b4..000000000000 --- a/src/app-layer-ssh.c +++ /dev/null @@ -1,1592 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - * \author Victor Julien - * - * App-layer parser for SSH protocol - * - */ - -#include "suricata-common.h" -#include "decode.h" -#include "threads.h" - -#include "util-print.h" -#include "util-pool.h" - -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" -#include "stream-tcp.h" -#include "stream.h" - -#include "app-layer-detect-proto.h" -#include "app-layer-protos.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "rust.h" - -#include "conf.h" - -#include "util-spm.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "flow-private.h" - -#include "util-byte.h" -#include "util-memcmp.h" - -/* HASSH fingerprints are disabled by default */ -#define SSH_CONFIG_DEFAULT_HASSH false - -static int SSHRegisterPatternsForProtocolDetection(void) -{ - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH, - "SSH-", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH, - "SSH-", 4, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - return 0; -} - -bool SSHTxLogCondition(ThreadVars *tv, const Packet *p, void *state, void *tx, uint64_t tx_id) -{ - return rs_ssh_tx_get_log_condition(tx); -} - -/** \brief Function to register the SSH protocol parsers and other functions - */ -void RegisterSSHParsers(void) -{ - const char *proto_name = "ssh"; - - if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_SSH, proto_name); - if (SSHRegisterPatternsForProtocolDetection() < 0) - return; - - /* Check if we should generate Hassh fingerprints */ - int enable_hassh = SSH_CONFIG_DEFAULT_HASSH; - const char *strval = NULL; - if (ConfGet("app-layer.protocols.ssh.hassh", &strval) != 1) { - enable_hassh = SSH_CONFIG_DEFAULT_HASSH; - } else if (strcmp(strval, "auto") == 0) { - enable_hassh = SSH_CONFIG_DEFAULT_HASSH; - } else if (ConfValIsFalse(strval)) { - enable_hassh = SSH_CONFIG_DEFAULT_HASSH; - } else if (ConfValIsTrue(strval)) { - enable_hassh = true; - } - - if (RunmodeIsUnittests() || enable_hassh) { - rs_ssh_enable_hassh(); - } - } - - SCLogDebug("Registering Rust SSH parser."); - rs_ssh_register_parser(); - - -#ifdef UNITTESTS - AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SSH, SSHParserRegisterTests); -#endif -} - -/* UNITTESTS */ -#ifdef UNITTESTS -#include "flow-util.h" -#include "stream-tcp-util.h" -#include "util-unittest-helper.h" - -static int SSHParserTestUtilCheck(const char *protoexp, const char *softexp, void *tx, uint8_t flags) { - const uint8_t *protocol = NULL; - uint32_t p_len = 0; - const uint8_t *software = NULL; - uint32_t s_len = 0; - - if (rs_ssh_tx_get_protocol(tx, &protocol, &p_len, flags) != 1) { - printf("Version string not parsed correctly return: "); - return 1; - } - if (protocol == NULL) { - printf("Version string not parsed correctly NULL: "); - return 1; - } - - if (p_len != strlen(protoexp)) { - printf("Version string not parsed correctly length: "); - return 1; - } - if (memcmp(protocol, protoexp, strlen(protoexp)) != 0) { - printf("Version string not parsed correctly: "); - return 1; - } - - if (softexp != NULL) { - if (rs_ssh_tx_get_software(tx, &software, &s_len, flags) != 1) - return 1; - if (software == NULL) - return 1; - if (s_len != strlen(softexp)) { - printf("Software string not parsed correctly length: "); - return 1; - } - if (memcmp(software, softexp, strlen(softexp)) != 0) { - printf("Software string not parsed correctly: "); - return 1; - } - } - return 0; -} - -/** \test Send a version string in one chunk (client version str). */ -static int SSHParserTest01(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone ) { - printf("Client version string not parsed: "); - goto end; - } - - if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) - goto end; - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a version string in one chunk but multiple lines and comments. - * (client version str) - */ -static int SSHParserTest02(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - - if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone ) { - printf("Client version string not parsed: "); - goto end; - } - if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) - goto end; - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a invalid version string in one chunk but multiple lines and comments. - * (client version str) - */ -static int SSHParserTest03(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0 some comments...\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); - if (r == 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - - if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) == SshStateBannerDone ) { - printf("Client version string parsed? It's not a valid string: "); - goto end; - } - const uint8_t *dummy = NULL; - uint32_t dummy_len = 0; - if (rs_ssh_tx_get_protocol(tx, &dummy, &dummy_len, STREAM_TOSERVER) != 0) - goto end; - if (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOSERVER) != 0) - goto end; - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a version string in one chunk (server version str). */ -static int SSHParserTest04(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - - if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone ) { - printf("Client version string not parsed: "); - goto end; - } - if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)) - goto end; - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a version string in one chunk (server version str) - */ -static int SSHParserTest05(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - - if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone ) { - printf("Client version string not parsed: "); - goto end; - } - if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)) - goto end; - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a invalid version string in one chunk (server version str) - */ -static int SSHParserTest06(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0 some comments...\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r); - goto end; - } - /* Ok, it returned an error. Let's make sure we didn't parse the string at all */ - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - - if ( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) == SshStateBannerDone ) { - printf("Client version string parsed? It's not a valid string: "); - goto end; - } - const uint8_t *dummy = NULL; - uint32_t dummy_len = 0; - if (rs_ssh_tx_get_protocol(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0) - goto end; - if (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0) - goto end; - - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -#define MAX_SSH_TEST_SIZE 512 - -static int SSHParserTest07(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - char sshbufs[2][MAX_SSH_TEST_SIZE] = {"SSH-2.", "0-MySSHClient-0.5.1\r\n"}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<2; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1); - seq += strlen(sshbufs[i]); - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a version banner in three chunks. */ -static int SSHParserTest08(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - char sshbufs[3][MAX_SSH_TEST_SIZE] = {"SSH-", "2.", "0-MySSHClient-0.5.1\r\n"}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<3; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1); - seq += strlen(sshbufs[i]); - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -static int SSHParserTest09(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - char sshbufs[2][MAX_SSH_TEST_SIZE] = {"SSH-2.", "0-MySSHClient-0.5.1\r\n"}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<2; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1); - seq += strlen(sshbufs[i]); - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a version banner in three chunks. */ -static int SSHParserTest10(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - char sshbufs[3][MAX_SSH_TEST_SIZE] = {"SSH-", "2.", "0-MySSHClient-0.5.1\r\n"}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<3; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, (uint8_t *) sshbufs[i], strlen(sshbufs[i])) == -1); - seq += strlen(sshbufs[i]); - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a banner and record in three chunks. */ -static int SSHParserTest11(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; - uint32_t sshlen1 = sizeof(sshbuf1) - 1; - uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00}; - uint32_t sshlen2 = sizeof(sshbuf2); - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER, sshbuf1, sshlen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, - sshbuf2, sshlen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - if ( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished ) { - printf("Didn't detect the msg code of new keys (ciphered data starts): "); - goto end; - } - if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) - goto end; - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a banner and 2 records record in four chunks. */ -static int SSHParserTest12(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; - uint32_t sshlen1 = sizeof(sshbuf1) - 1; - uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00}; - uint32_t sshlen2 = sizeof(sshbuf2); - uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00}; - uint32_t sshlen3 = sizeof(sshbuf3); - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER, sshbuf1, sshlen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, - sshbuf2, sshlen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - goto end; - } - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, - sshbuf3, sshlen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - if ( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished ) { - printf("Didn't detect the msg code of new keys (ciphered data starts): "); - goto end; - } - if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) - goto end; - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a banner and 2 records record in four chunks. */ -static int SSHParserTest13(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; - uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 17}; - uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 21}; - - uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3}; - uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3)}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<3; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a banner and 2 records record in four chunks. */ -static int SSHParserTest14(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; - uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00}; - uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00}; - /* first byte of this record in sshbuf4 */ - uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 21}; - - uint8_t* sshbufs[5] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5}; - uint32_t sshlens[5] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), sizeof(sshbuf5)}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<5; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a banner and 2 records record in four chunks. */ -static int SSHParserTest15(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; - uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00}; - uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00}; - uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 20, 0x00, 0x00, 0x00, 0x02, 0x01, 21}; - - uint8_t* sshbufs[5] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5}; - uint32_t sshlens[5] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), sizeof(sshbuf5)}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<5; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send toserver a banner and record in three chunks. */ -static int SSHParserTest16(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-"; - uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; - uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00}; - - uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3}; - uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3)}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<3; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send toserver a banner and 2 records record in four chunks. */ -static int SSHParserTest17(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-"; - uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; - uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00}; - uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00}; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3), sizeof(sshbuf4)}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test 2 directional test */ -static int SSHParserTest18(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t server1[] = "SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu3\r\n"; - uint8_t sshbuf1[] = "SSH-"; - uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; - uint8_t server2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; - uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; - - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - uint8_t* sshbufs[5] = {server1, sshbuf1, sshbuf2, server2, sshbuf3}; - uint32_t sshlens[5] = {sizeof(server1) - 1, sizeof(sshbuf1) - 1, sizeof(sshbuf2) -1, sizeof(server2) - 1, sizeof(sshbuf3)}; - bool sshdirs[5] = {true, false, false, true, false}; - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seqcli = 2; - uint32_t seqsrv = 2; - for (int i=0; i<5; i++) { - if (sshdirs[i]) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seqsrv, sshbufs[i], sshlens[i]) == -1); - seqsrv += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } else { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seqcli, sshbufs[i], sshlens[i]) == -1); - seqcli += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0); - } - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished ); - - FAIL_IF(!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_NO_INSPECTION))); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Really long banner handling: bannel exactly 255 */ -static int SSHParserTest19(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-"; - uint8_t sshbuf2[] = "2.0-"; - uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//60 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//112 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//164 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//216 - "abcdefghijklmnopqrstuvwxyz"//242 - "abcdefghijkl\r";//255 - uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00}; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4)}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished ); - - sshbuf3[sizeof(sshbuf3) - 2] = 0; - FAIL_IF(SSHParserTestUtilCheck("2.0", (char *)sshbuf3, tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Really long banner handling: banner exactly 255, - * followed by malformed record */ -static int SSHParserTest20(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-"; - uint8_t sshbuf2[] = "2.0-"; - uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//60 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//112 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//164 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//216 - "abcdefghijklmnopqrstuvwxyz"//242 - "abcdefghijklm\r";//256 - uint8_t sshbuf4[] = {'a','b','c','d','e','f', '\r', - 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00}; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Fragmented banner handling: chunk has final part of bannel plus - * a record. */ -static int SSHParserTest21(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-"; - uint8_t sshbuf2[] = "2.0-"; - uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//60 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//112 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//164 - "abcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyz"//216 - "abcdefghijklmnopqrstuvwxy";//241 - uint8_t sshbuf4[] = {'l','i','b','s','s','h', '\r', - 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00}; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4)}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Fragmented banner handling: chunk has final part of bannel plus - * a record. */ -static int SSHParserTest22(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-"; - uint8_t sshbuf2[] = "2.0-"; - uint8_t sshbuf3[] = { - 'l', 'i', 'b', 's', 's', 'h', '\r', //7 - - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //50 - - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //100 - - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //150 - - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //200 - - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //250 - - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00, 0x00, //300 - }; - - - uint8_t* sshbufs[3] = {sshbuf1, sshbuf2, sshbuf3}; - uint32_t sshlens[3] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = PacketGetFromAlloc(); - FAIL_IF(unlikely(p == NULL)); - p->proto = IPPROTO_TCP; - p->flow = f; - - uint32_t seq = 2; - for (int i=0; i<3; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished ); - - FAIL_IF(SSHParserTestUtilCheck("2.0", "libssh", tx, STREAM_TOCLIENT)); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a version string in one chunk (client version str). */ -static int SSHParserTest23(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0\r-MySSHClient-0.5.1\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); - if (r == 0) { - printf("toclient chunk 1 returned 0 expected non null: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a version string in one chunk (client version str). */ -static int SSHParserTest24(void) -{ - int result = 0; - Flow f; - uint8_t sshbuf[] = "SSH-2.0-\rMySSHClient-0.5.1\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } - - void *ssh_state = f.alstate; - if (ssh_state == NULL) { - printf("no ssh state: "); - goto end; - } - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - if ( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateBannerDone ) { - printf("Didn't detect the msg code of new keys (ciphered data starts): "); - goto end; - } - if (SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOSERVER)) - goto end; - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - return result; -} - -/** \test Send a malformed banner */ -static int SSHParserTest25(void) -{ - Flow f; - uint8_t sshbuf[] = "\n"; - uint32_t sshlen = sizeof(sshbuf) - 1; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - FAIL_IF_NULL(alp_tctx); - - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.alproto = ALPROTO_SSH; - - StreamTcpInitConfig(true); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, - STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); - FAIL_IF(r != -1); - - void *ssh_state = f.alstate; - FAIL_IF_NULL(ssh_state); - void * tx = rs_ssh_state_get_tx(ssh_state, 0); - FAIL_IF( rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) == SshStateBannerDone ); - const uint8_t *dummy = NULL; - uint32_t dummy_len = 0; - FAIL_IF (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0); - - AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - PASS; -} - -#endif /* UNITTESTS */ - -void SSHParserRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01); - UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02); - UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03); - UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04); - UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05); - UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06); - UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07); - UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08); - UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09); - UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10); - UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11); - UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12); - UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13); - UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14); - UtRegisterTest("SSHParserTest15", SSHParserTest15); - UtRegisterTest("SSHParserTest16", SSHParserTest16); - UtRegisterTest("SSHParserTest17", SSHParserTest17); - UtRegisterTest("SSHParserTest18", SSHParserTest18); - UtRegisterTest("SSHParserTest19", SSHParserTest19); - UtRegisterTest("SSHParserTest20", SSHParserTest20); - UtRegisterTest("SSHParserTest21", SSHParserTest21); - UtRegisterTest("SSHParserTest22", SSHParserTest22); - UtRegisterTest("SSHParserTest23", SSHParserTest23); - UtRegisterTest("SSHParserTest24", SSHParserTest24); - UtRegisterTest("SSHParserTest25", SSHParserTest25); -#endif /* UNITTESTS */ -} - diff --git a/src/app-layer-ssh.h b/src/app-layer-ssh.h deleted file mode 100644 index 996cc260c735..000000000000 --- a/src/app-layer-ssh.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - * \author Victor Julien - */ - -#ifndef __APP_LAYER_SSH_H__ -#define __APP_LAYER_SSH_H__ - -void RegisterSSHParsers(void); -void SSHParserRegisterTests(void); - -bool SSHTxLogCondition(ThreadVars *, const Packet *, void *state, void *tx, uint64_t tx_id); - -#endif /* __APP_LAYER_SSH_H__ */ - diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c deleted file mode 100644 index cb094f3801ab..000000000000 --- a/src/app-layer-ssl.c +++ /dev/null @@ -1,3107 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * \author Pierre Chifflier - * \author Mats Klepsland - * - */ - -#include "suricata-common.h" -#include "decode.h" -#include "threads.h" - -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" -#include "stream-tcp.h" -#include "stream.h" - -#include "app-layer.h" -#include "app-layer-detect-proto.h" -#include "app-layer-protos.h" -#include "app-layer-parser.h" -#include "app-layer-frames.h" -#include "app-layer-ssl.h" - -#include "decode-events.h" -#include "conf.h" - -#include "util-spm.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-pool.h" -#include "util-byte.h" -#include "util-ja3.h" -#include "util-enum.h" -#include "flow-util.h" -#include "flow-private.h" -#include "util-validate.h" - -SCEnumCharMap tls_frame_table[] = { - { - "pdu", - TLS_FRAME_PDU, - }, - { - "hdr", - TLS_FRAME_HDR, - }, - { - "data", - TLS_FRAME_DATA, - }, - { - "alert", - TLS_FRAME_ALERT_DATA, - }, - { - "heartbeat", - TLS_FRAME_HB_DATA, - }, - { - "ssl2.hdr", - TLS_FRAME_SSLV2_HDR, - }, - { - "ssl2.pdu", - TLS_FRAME_SSLV2_PDU, - }, - { NULL, -1 }, -}; - -SCEnumCharMap tls_decoder_event_table[] = { - /* TLS protocol messages */ - { "INVALID_SSLV2_HEADER", TLS_DECODER_EVENT_INVALID_SSLV2_HEADER }, - { "INVALID_TLS_HEADER", TLS_DECODER_EVENT_INVALID_TLS_HEADER }, - { "INVALID_RECORD_VERSION", TLS_DECODER_EVENT_INVALID_RECORD_VERSION }, - { "INVALID_RECORD_TYPE", TLS_DECODER_EVENT_INVALID_RECORD_TYPE }, - { "INVALID_RECORD_LENGTH", TLS_DECODER_EVENT_INVALID_RECORD_LENGTH }, - { "INVALID_HANDSHAKE_MESSAGE", TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE }, - { "HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_HEARTBEAT }, - { "INVALID_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_INVALID_HEARTBEAT }, - { "OVERFLOW_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT }, - { "DATALEAK_HEARTBEAT_MISMATCH", TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH }, - { "HANDSHAKE_INVALID_LENGTH", TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH }, - { "MULTIPLE_SNI_EXTENSIONS", TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS }, - { "INVALID_SNI_TYPE", TLS_DECODER_EVENT_INVALID_SNI_TYPE }, - { "INVALID_SNI_LENGTH", TLS_DECODER_EVENT_INVALID_SNI_LENGTH }, - { "TOO_MANY_RECORDS_IN_PACKET", TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET }, - /* certificate decoding messages */ - { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, - { "CERTIFICATE_INVALID_LENGTH", TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH }, - { "CERTIFICATE_INVALID_VERSION", TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION }, - { "CERTIFICATE_INVALID_SERIAL", TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL }, - { "CERTIFICATE_INVALID_ALGORITHMIDENTIFIER", - TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER }, - { "CERTIFICATE_INVALID_X509NAME", TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME }, - { "CERTIFICATE_INVALID_DATE", TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE }, - { "CERTIFICATE_INVALID_EXTENSIONS", TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS }, - { "CERTIFICATE_INVALID_DER", TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER }, - { "CERTIFICATE_INVALID_SUBJECT", TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT }, - { "CERTIFICATE_INVALID_ISSUER", TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER }, - { "CERTIFICATE_INVALID_VALIDITY", TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY }, - { "ERROR_MESSAGE_ENCOUNTERED", TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED }, - /* used as a generic error event */ - { "INVALID_SSL_RECORD", TLS_DECODER_EVENT_INVALID_SSL_RECORD }, - { NULL, -1 }, -}; - -enum { - /* X.509 error codes, returned by decoder - * THESE CONSTANTS MUST MATCH rust/src/x509/mod.rs ! */ - ERR_INVALID_CERTIFICATE=1, - ERR_INVALID_LENGTH, - ERR_INVALID_VERSION, - ERR_INVALID_SERIAL, - ERR_INVALID_ALGORITHMIDENTIFIER, - ERR_INVALID_X509NAME, - ERR_INVALID_DATE, - ERR_INVALID_EXTENSIONS, - ERR_INVALID_DER, - - /* error getting data */ - ERR_EXTRACT_SUBJECT, - ERR_EXTRACT_ISSUER, - ERR_EXTRACT_VALIDITY, -}; - -/* JA3 fingerprints are disabled by default */ -#define SSL_CONFIG_DEFAULT_JA3 0 - -enum SslConfigEncryptHandling { - SSL_CNF_ENC_HANDLE_DEFAULT = 0, /**< disable raw content, continue tracking */ - SSL_CNF_ENC_HANDLE_BYPASS = 1, /**< skip processing of flow, bypass if possible */ - SSL_CNF_ENC_HANDLE_FULL = 2, /**< handle fully like any other proto */ -}; - -typedef struct SslConfig_ { - enum SslConfigEncryptHandling encrypt_mode; - /** dynamic setting for ja3: can be enabled on demand if not explicitly - * disabled. */ - SC_ATOMIC_DECLARE(int, enable_ja3); - bool disable_ja3; /**< ja3 explicitly disabled. Don't enable on demand. */ -} SslConfig; - -SslConfig ssl_config; - -/* SSLv3 record types */ -#define SSLV3_CHANGE_CIPHER_SPEC 20 -#define SSLV3_ALERT_PROTOCOL 21 -#define SSLV3_HANDSHAKE_PROTOCOL 22 -#define SSLV3_APPLICATION_PROTOCOL 23 -#define SSLV3_HEARTBEAT_PROTOCOL 24 - -/* SSLv3 handshake protocol types */ -#define SSLV3_HS_HELLO_REQUEST 0 -#define SSLV3_HS_CLIENT_HELLO 1 -#define SSLV3_HS_SERVER_HELLO 2 -#define SSLV3_HS_NEW_SESSION_TICKET 4 -#define SSLV3_HS_CERTIFICATE 11 -#define SSLV3_HS_SERVER_KEY_EXCHANGE 12 -#define SSLV3_HS_CERTIFICATE_REQUEST 13 -#define SSLV3_HS_SERVER_HELLO_DONE 14 -#define SSLV3_HS_CERTIFICATE_VERIFY 15 -#define SSLV3_HS_CLIENT_KEY_EXCHANGE 16 -#define SSLV3_HS_FINISHED 20 -#define SSLV3_HS_CERTIFICATE_URL 21 -#define SSLV3_HS_CERTIFICATE_STATUS 22 - -/* SSLv2 protocol message types */ -#define SSLV2_MT_ERROR 0 -#define SSLV2_MT_CLIENT_HELLO 1 -#define SSLV2_MT_CLIENT_MASTER_KEY 2 -#define SSLV2_MT_CLIENT_FINISHED 3 -#define SSLV2_MT_SERVER_HELLO 4 -#define SSLV2_MT_SERVER_VERIFY 5 -#define SSLV2_MT_SERVER_FINISHED 6 -#define SSLV2_MT_REQUEST_CERTIFICATE 7 -#define SSLV2_MT_CLIENT_CERTIFICATE 8 - -#define SSLV3_RECORD_HDR_LEN 5 -#define SSLV3_MESSAGE_HDR_LEN 4 -/** max length according to RFC 5246 6.2.2 is 2^14 + 1024 */ -#define SSLV3_RECORD_MAX_LEN ((1 << 14) + 1024) - -#define SSLV3_CLIENT_HELLO_VERSION_LEN 2 -#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32 - -/* TLS heartbeat protocol types */ -#define TLS_HB_REQUEST 1 -#define TLS_HB_RESPONSE 2 - -#define SSL_RECORD_MINIMUM_LENGTH 6 - -#define SHA1_STRING_LENGTH 60 - -#define HAS_SPACE(n) ((uint64_t)(input - initial_input) + (uint64_t)(n) <= (uint64_t)(input_len)) - -struct SSLDecoderResult { - int retval; // nr bytes consumed from input, or < 0 on error - uint32_t needed; // more bytes needed -}; -#define SSL_DECODER_ERROR(e) \ - (struct SSLDecoderResult) \ - { \ - (e), 0 \ - } -#define SSL_DECODER_OK(c) \ - (struct SSLDecoderResult) \ - { \ - (c), 0 \ - } -#define SSL_DECODER_INCOMPLETE(c, n) \ - (struct SSLDecoderResult) \ - { \ - (c), (n) \ - } - -static inline int SafeMemcpy(void *dst, size_t dst_offset, size_t dst_size, - const void *src, size_t src_offset, size_t src_size, size_t src_tocopy) WARN_UNUSED; - -static inline int SafeMemcpy(void *dst, size_t dst_offset, size_t dst_size, - const void *src, size_t src_offset, size_t src_size, size_t src_tocopy) -{ - DEBUG_VALIDATE_BUG_ON(dst_offset >= dst_size); - DEBUG_VALIDATE_BUG_ON(src_offset >= src_size); - DEBUG_VALIDATE_BUG_ON(src_tocopy > (src_size - src_offset)); - DEBUG_VALIDATE_BUG_ON(src_tocopy > (dst_size - dst_offset)); - - if (dst_offset < dst_size && src_offset < src_size && - src_tocopy <= (src_size - src_offset) && - src_tocopy <= (dst_size - dst_offset)) { - memcpy(dst + dst_offset, src + src_offset, src_tocopy); - return 0; - } - return -1; -} - -#ifdef DEBUG_VALIDATION -#define ValidateRecordState(connp) \ - do { \ - DEBUG_VALIDATE_BUG_ON(((connp)->record_length + SSLV3_RECORD_HDR_LEN) < \ - (connp)->bytes_processed); \ - } while(0); -#else -#define ValidateRecordState(...) -#endif - -#define SSLParserHSReset(connp) \ - do { \ - (connp)->handshake_type = 0; \ - (connp)->message_length = 0; \ - } while (0) - -#define SSLParserReset(state) \ - do { \ - SCLogDebug("resetting state"); \ - (state)->curr_connp->bytes_processed = 0; \ - SSLParserHSReset((state)->curr_connp); \ - } while(0) - -#define SSLSetEvent(ssl_state, event) \ - do { \ - SCLogDebug("setting event %u", (event)); \ - if ((ssl_state) == NULL) { \ - SCLogDebug("could not set decoder event %u", event); \ - } else { \ - AppLayerDecoderEventsSetEventRaw(&(ssl_state)->tx_data.events, (event)); \ - (ssl_state)->events++; \ - } \ - } while (0) - -static void *SSLGetTx(void *state, uint64_t tx_id) -{ - SSLState *ssl_state = (SSLState *)state; - return ssl_state; -} - -static uint64_t SSLGetTxCnt(void *state) -{ - /* single tx */ - return 1; -} - -static int SSLGetAlstateProgress(void *tx, uint8_t direction) -{ - SSLState *ssl_state = (SSLState *)tx; - - /* we don't care about direction, only that app-layer parser is done - and have sent an EOF */ - if (ssl_state->flags & SSL_AL_FLAG_STATE_FINISHED) { - return TLS_STATE_FINISHED; - } - - /* we want the logger to log when the handshake is done, even if the - state is not finished */ - if (ssl_state->flags & SSL_AL_FLAG_HANDSHAKE_DONE) { - return TLS_HANDSHAKE_DONE; - } - - if (direction == STREAM_TOSERVER && - (ssl_state->server_connp.cert0_subject != NULL || - ssl_state->server_connp.cert0_issuerdn != NULL)) - { - return TLS_STATE_CERT_READY; - } - - return TLS_STATE_IN_PROGRESS; -} - -static AppLayerTxData *SSLGetTxData(void *vtx) -{ - SSLState *ssl_state = (SSLState *)vtx; - return &ssl_state->tx_data; -} - -static AppLayerStateData *SSLGetStateData(void *vstate) -{ - SSLState *ssl_state = (SSLState *)vstate; - return &ssl_state->state_data; -} - -void SSLVersionToString(uint16_t version, char *buffer) -{ - buffer[0] = '\0'; - - switch (version) { - case TLS_VERSION_UNKNOWN: - strlcat(buffer, "UNDETERMINED", 13); - break; - case SSL_VERSION_2: - strlcat(buffer, "SSLv2", 6); - break; - case SSL_VERSION_3: - strlcat(buffer, "SSLv3", 6); - break; - case TLS_VERSION_10: - strlcat(buffer, "TLSv1", 6); - break; - case TLS_VERSION_11: - strlcat(buffer, "TLS 1.1", 8); - break; - case TLS_VERSION_12: - strlcat(buffer, "TLS 1.2", 8); - break; - case TLS_VERSION_13: - strlcat(buffer, "TLS 1.3", 8); - break; - case TLS_VERSION_13_DRAFT28: - strlcat(buffer, "TLS 1.3 draft-28", 17); - break; - case TLS_VERSION_13_DRAFT27: - strlcat(buffer, "TLS 1.3 draft-27", 17); - break; - case TLS_VERSION_13_DRAFT26: - strlcat(buffer, "TLS 1.3 draft-26", 17); - break; - case TLS_VERSION_13_DRAFT25: - strlcat(buffer, "TLS 1.3 draft-25", 17); - break; - case TLS_VERSION_13_DRAFT24: - strlcat(buffer, "TLS 1.3 draft-24", 17); - break; - case TLS_VERSION_13_DRAFT23: - strlcat(buffer, "TLS 1.3 draft-23", 17); - break; - case TLS_VERSION_13_DRAFT22: - strlcat(buffer, "TLS 1.3 draft-22", 17); - break; - case TLS_VERSION_13_DRAFT21: - strlcat(buffer, "TLS 1.3 draft-21", 17); - break; - case TLS_VERSION_13_DRAFT20: - strlcat(buffer, "TLS 1.3 draft-20", 17); - break; - case TLS_VERSION_13_DRAFT19: - strlcat(buffer, "TLS 1.3 draft-19", 17); - break; - case TLS_VERSION_13_DRAFT18: - strlcat(buffer, "TLS 1.3 draft-18", 17); - break; - case TLS_VERSION_13_DRAFT17: - strlcat(buffer, "TLS 1.3 draft-17", 17); - break; - case TLS_VERSION_13_DRAFT16: - strlcat(buffer, "TLS 1.3 draft-16", 17); - break; - case TLS_VERSION_13_PRE_DRAFT16: - strlcat(buffer, "TLS 1.3 draft-<16", 18); - break; - case TLS_VERSION_13_DRAFT20_FB: - strlcat(buffer, "TLS 1.3 draft-20-fb", 20); - break; - case TLS_VERSION_13_DRAFT21_FB: - strlcat(buffer, "TLS 1.3 draft-21-fb", 20); - break; - case TLS_VERSION_13_DRAFT22_FB: - strlcat(buffer, "TLS 1.3 draft-22-fb", 20); - break; - case TLS_VERSION_13_DRAFT23_FB: - strlcat(buffer, "TLS 1.3 draft-23-fb", 20); - break; - case TLS_VERSION_13_DRAFT26_FB: - strlcat(buffer, "TLS 1.3 draft-26-fb", 20); - break; - default: - snprintf(buffer, 7, "0x%04x", version); - break; - } -} - -static void TlsDecodeHSCertificateErrSetEvent(SSLState *ssl_state, uint32_t err) -{ - switch(err) { - case ERR_EXTRACT_VALIDITY: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY); - break; - case ERR_EXTRACT_ISSUER: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER); - break; - case ERR_EXTRACT_SUBJECT: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT); - break; - case ERR_INVALID_DER: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER); - break; - case ERR_INVALID_EXTENSIONS: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS); - break; - case ERR_INVALID_DATE: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE); - break; - case ERR_INVALID_X509NAME: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME); - break; - case ERR_INVALID_ALGORITHMIDENTIFIER: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER); - break; - case ERR_INVALID_SERIAL: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL); - break; - case ERR_INVALID_VERSION: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION); - break; - case ERR_INVALID_LENGTH: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH); - break; - case ERR_INVALID_CERTIFICATE: - default: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); - break; - } -} - -static inline int TlsDecodeHSCertificateFingerprint( - SSLStateConnp *connp, const uint8_t *input, uint32_t cert_len) -{ - if (unlikely(connp->cert0_fingerprint != NULL)) - return 0; - - connp->cert0_fingerprint = SCCalloc(1, SHA1_STRING_LENGTH); - if (connp->cert0_fingerprint == NULL) - return -1; - - uint8_t hash[SC_SHA1_LEN]; - if (SCSha1HashBuffer(input, cert_len, hash, sizeof(hash)) == 1) { - rs_to_hex_sep( - (uint8_t *)connp->cert0_fingerprint, SHA1_STRING_LENGTH, ':', hash, SC_SHA1_LEN); - } - return 0; -} - -static inline int TlsDecodeHSCertificateAddCertToChain( - SSLStateConnp *connp, const uint8_t *input, uint32_t cert_len) -{ - SSLCertsChain *cert = SCCalloc(1, sizeof(SSLCertsChain)); - if (cert == NULL) - return -1; - - cert->cert_data = (uint8_t *)input; - cert->cert_len = cert_len; - TAILQ_INSERT_TAIL(&connp->certs, cert, next); - - return 0; -} - -static int TlsDecodeHSCertificate(SSLState *ssl_state, SSLStateConnp *connp, - const uint8_t *const initial_input, const uint32_t input_len, const int certn) -{ - const uint8_t *input = (uint8_t *)initial_input; - uint32_t err_code = 0; - X509 *x509 = NULL; - int rc = 0; - - if (!(HAS_SPACE(3))) - goto invalid_cert; - - uint32_t cert_len = *input << 16 | *(input + 1) << 8 | *(input + 2); - input += 3; - - if (!(HAS_SPACE(cert_len))) - goto invalid_cert; - - /* only store fields from the first certificate in the chain */ - if (certn == 0 && connp->cert0_subject == NULL && connp->cert0_issuerdn == NULL && - connp->cert0_serial == NULL) { - x509 = rs_x509_decode(input, cert_len, &err_code); - if (x509 == NULL) { - TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code); - goto next; - } - - char *str = rs_x509_get_subject(x509); - if (str == NULL) { - err_code = ERR_EXTRACT_SUBJECT; - goto error; - } - connp->cert0_subject = str; - - str = rs_x509_get_issuer(x509); - if (str == NULL) { - err_code = ERR_EXTRACT_ISSUER; - goto error; - } - connp->cert0_issuerdn = str; - - str = rs_x509_get_serial(x509); - if (str == NULL) { - err_code = ERR_INVALID_SERIAL; - goto error; - } - connp->cert0_serial = str; - - rc = rs_x509_get_validity(x509, &connp->cert0_not_before, &connp->cert0_not_after); - if (rc != 0) { - err_code = ERR_EXTRACT_VALIDITY; - goto error; - } - - rs_x509_free(x509); - x509 = NULL; - - rc = TlsDecodeHSCertificateFingerprint(connp, input, cert_len); - if (rc != 0) { - SCLogDebug("TlsDecodeHSCertificateFingerprint failed with %d", rc); - goto error; - } - } - - rc = TlsDecodeHSCertificateAddCertToChain(connp, input, cert_len); - if (rc != 0) { - SCLogDebug("TlsDecodeHSCertificateAddCertToChain failed with %d", rc); - goto error; - } - -next: - input += cert_len; - return (input - initial_input); - -error: - if (err_code != 0) - TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code); - if (x509 != NULL) - rs_x509_free(x509); - return -1; - -invalid_cert: - SCLogDebug("TLS invalid certificate"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); - return -1; -} - -/** \internal - * \brief parse cert data in a certificate handshake message - * will be called with all data. - * \retval consumed bytes consumed or -1 on error - */ -static int TlsDecodeHSCertificates(SSLState *ssl_state, SSLStateConnp *connp, - const uint8_t *const initial_input, const uint32_t input_len) -{ - const uint8_t *input = (uint8_t *)initial_input; - - if (!(HAS_SPACE(3))) - return -1; - - const uint32_t cert_chain_len = *input << 16 | *(input + 1) << 8 | *(input + 2); - input += 3; - - if (!(HAS_SPACE(cert_chain_len))) - return -1; - - if (connp->certs_buffer != NULL) { - // TODO should we set an event here? - return -1; - } - - connp->certs_buffer = SCCalloc(1, cert_chain_len); - if (connp->certs_buffer == NULL) { - return -1; - } - connp->certs_buffer_size = cert_chain_len; - memcpy(connp->certs_buffer, input, cert_chain_len); - - int cert_cnt = 0; - uint32_t processed_len = 0; - /* coverity[tainted_data] */ - while (processed_len < cert_chain_len) { - int rc = TlsDecodeHSCertificate(ssl_state, connp, connp->certs_buffer + processed_len, - connp->certs_buffer_size - processed_len, cert_cnt); - if (rc <= 0) { // 0 should be impossible, but lets be defensive - return -1; - } - DEBUG_VALIDATE_BUG_ON(processed_len + (uint32_t)rc > cert_chain_len); - if (processed_len + (uint32_t)rc > cert_chain_len) { - return -1; - } - - processed_len += (uint32_t)rc; - } - - return processed_len + 3; -} - -/** - * \inline - * \brief Check if value is GREASE. - * - * http://tools.ietf.org/html/draft-davidben-tls-grease-00 - * - * \param value Value to check. - * - * \retval 1 if is GREASE. - * \retval 0 if not is GREASE. - */ -static inline int TLSDecodeValueIsGREASE(const uint16_t value) -{ - switch (value) - { - case 0x0a0a: - case 0x1a1a: - case 0x2a2a: - case 0x3a3a: - case 0x4a4a: - case 0x5a5a: - case 0x6a6a: - case 0x7a7a: - case 0x8a8a: - case 0x9a9a: - case 0xaaaa: - case 0xbaba: - case 0xcaca: - case 0xdada: - case 0xeaea: - case 0xfafa: - return 1; - default: - return 0; - } -} - -static inline int TLSDecodeHSHelloVersion(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - uint8_t *input = (uint8_t *)initial_input; - - if (!(HAS_SPACE(SSLV3_CLIENT_HELLO_VERSION_LEN))) { - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - return -1; - } - - uint16_t version = (uint16_t)(*input << 8) | *(input + 1); - ssl_state->curr_connp->version = version; - - /* TLSv1.3 draft1 to draft21 use the version field as earlier TLS - versions, instead of using the supported versions extension. */ - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - ((ssl_state->curr_connp->version == TLS_VERSION_13) || - (((ssl_state->curr_connp->version >> 8) & 0xff) == 0x7f))) { - ssl_state->flags |= SSL_AL_FLAG_LOG_WITHOUT_CERT; - } - - /* Catch some early TLSv1.3 draft implementations that does not conform - to the draft version. */ - if ((ssl_state->curr_connp->version >= 0x7f01) && - (ssl_state->curr_connp->version < 0x7f10)) { - ssl_state->curr_connp->version = TLS_VERSION_13_PRE_DRAFT16; - } - - /* TLSv1.3 drafts from draft1 to draft15 use 0x0304 (TLSv1.3) as the - version number, which makes it hard to accurately pinpoint the - exact draft version. */ - else if (ssl_state->curr_connp->version == TLS_VERSION_13) { - ssl_state->curr_connp->version = TLS_VERSION_13_PRE_DRAFT16; - } - - if (SC_ATOMIC_GET(ssl_config.enable_ja3) && ssl_state->curr_connp->ja3_str == NULL) { - ssl_state->curr_connp->ja3_str = Ja3BufferInit(); - if (ssl_state->curr_connp->ja3_str == NULL) - return -1; - - int rc = Ja3BufferAddValue(&ssl_state->curr_connp->ja3_str, version); - if (rc != 0) - return -1; - } - - input += SSLV3_CLIENT_HELLO_VERSION_LEN; - - return (input - initial_input); -} - -static inline int TLSDecodeHSHelloRandom(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - uint8_t *input = (uint8_t *)initial_input; - - if (!(HAS_SPACE(SSLV3_CLIENT_HELLO_RANDOM_LEN))) { - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - return -1; - } - - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { - memcpy(ssl_state->server_connp.random, input, TLS_RANDOM_LEN); - ssl_state->flags |= TLS_TS_RANDOM_SET; - } else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { - memcpy(ssl_state->client_connp.random, input, TLS_RANDOM_LEN); - ssl_state->flags |= TLS_TC_RANDOM_SET; - } - - /* Skip random */ - input += SSLV3_CLIENT_HELLO_RANDOM_LEN; - - return (input - initial_input); -} - -static inline int TLSDecodeHSHelloSessionID(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - uint8_t *input = (uint8_t *)initial_input; - - if (!(HAS_SPACE(1))) - goto invalid_length; - - uint8_t session_id_length = *input; - input += 1; - - if (!(HAS_SPACE(session_id_length))) - goto invalid_length; - - if (session_id_length != 0 && ssl_state->curr_connp->session_id == NULL) { - ssl_state->curr_connp->session_id = SCMalloc(session_id_length); - - if (unlikely(ssl_state->curr_connp->session_id == NULL)) { - return -1; - } - - if (SafeMemcpy(ssl_state->curr_connp->session_id, 0, session_id_length, - input, 0, input_len, session_id_length) != 0) { - return -1; - } - ssl_state->curr_connp->session_id_length = session_id_length; - - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - ssl_state->client_connp.session_id != NULL && - ssl_state->server_connp.session_id != NULL) { - if ((ssl_state->client_connp.session_id_length == - ssl_state->server_connp.session_id_length) && - (memcmp(ssl_state->server_connp.session_id, - ssl_state->client_connp.session_id, session_id_length) == 0)) { - ssl_state->flags |= SSL_AL_FLAG_SESSION_RESUMED; - } - } - } - - input += session_id_length; - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - return -1; -} - -static inline int TLSDecodeHSHelloCipherSuites(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - const uint8_t *input = initial_input; - - if (!(HAS_SPACE(2))) - goto invalid_length; - - uint16_t cipher_suites_length; - - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { - cipher_suites_length = 2; - } else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { - cipher_suites_length = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - } else { - return -1; - } - - if (!(HAS_SPACE(cipher_suites_length))) - goto invalid_length; - - /* Cipher suites length should always be divisible by 2 */ - if ((cipher_suites_length % 2) != 0) { - goto invalid_length; - } - - if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { - JA3Buffer *ja3_cipher_suites = Ja3BufferInit(); - if (ja3_cipher_suites == NULL) - return -1; - - uint16_t processed_len = 0; - /* coverity[tainted_data] */ - while (processed_len < cipher_suites_length) - { - if (!(HAS_SPACE(2))) { - Ja3BufferFree(&ja3_cipher_suites); - goto invalid_length; - } - - uint16_t cipher_suite = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - - if (TLSDecodeValueIsGREASE(cipher_suite) != 1) { - int rc = Ja3BufferAddValue(&ja3_cipher_suites, cipher_suite); - if (rc != 0) { - return -1; - } - } - - processed_len += 2; - } - - int rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, - &ja3_cipher_suites); - if (rc == -1) { - return -1; - } - - } else { - /* Skip cipher suites */ - input += cipher_suites_length; - } - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - return -1; -} - -static inline int TLSDecodeHSHelloCompressionMethods(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - const uint8_t *input = initial_input; - - if (!(HAS_SPACE(1))) - goto invalid_length; - - /* Skip compression methods */ - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { - input += 1; - } else { - uint8_t compression_methods_length = *input; - input += 1; - - if (!(HAS_SPACE(compression_methods_length))) - goto invalid_length; - - input += compression_methods_length; - } - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid_length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - return -1; -} - -static inline int TLSDecodeHSHelloExtensionSni(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - uint8_t *input = (uint8_t *)initial_input; - - /* Empty extension */ - if (input_len == 0) - return 0; - - if (!(HAS_SPACE(2))) - goto invalid_length; - - /* Skip sni_list_length */ - input += 2; - - if (!(HAS_SPACE(1))) - goto invalid_length; - - uint8_t sni_type = *input; - input += 1; - - /* Currently the only type allowed is host_name - (RFC6066 section 3). */ - if (sni_type != SSL_SNI_TYPE_HOST_NAME) { - SCLogDebug("Unknown SNI type"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_INVALID_SNI_TYPE); - return -1; - } - - if (!(HAS_SPACE(2))) - goto invalid_length; - - uint16_t sni_len = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - - /* host_name contains the fully qualified domain name, - and should therefore be limited by the maximum domain - name length. */ - if (!(HAS_SPACE(sni_len)) || sni_len > 255 || sni_len == 0) { - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_INVALID_SNI_LENGTH); - return -1; - } - - /* There must not be more than one extension of the same - type (RFC5246 section 7.4.1.4). */ - if (ssl_state->curr_connp->sni) { - SCLogDebug("Multiple SNI extensions"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS); - input += sni_len; - return (input - initial_input); - } - - const size_t sni_strlen = sni_len + 1; - ssl_state->curr_connp->sni = SCMalloc(sni_strlen); - if (unlikely(ssl_state->curr_connp->sni == NULL)) - return -1; - - const size_t consumed = input - initial_input; - if (SafeMemcpy(ssl_state->curr_connp->sni, 0, sni_strlen, - initial_input, consumed, input_len, sni_len) != 0) { - SCFree(ssl_state->curr_connp->sni); - ssl_state->curr_connp->sni = NULL; - return -1; - } - ssl_state->curr_connp->sni[sni_strlen-1] = 0; - - input += sni_len; - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - - - return -1; -} - -static inline int TLSDecodeHSHelloExtensionSupportedVersions(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - const uint8_t *input = initial_input; - - /* Empty extension */ - if (input_len == 0) - return 0; - - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { - if (!(HAS_SPACE(1))) - goto invalid_length; - - uint8_t supported_ver_len = *input; - input += 1; - - if (supported_ver_len < 2) - goto invalid_length; - - if (!(HAS_SPACE(supported_ver_len))) - goto invalid_length; - - /* Use the first (and prefered) valid version as client version, - * skip over GREASE and other possible noise. */ - uint16_t i = 0; - while (i + 1 < (uint16_t)supported_ver_len) { - uint16_t ver = (uint16_t)(input[i] << 8) | input[i + 1]; - if (TLSVersionValid(ver)) { - ssl_state->curr_connp->version = ver; - break; - } - i += 2; - } - - /* Set a flag to indicate that we have seen this extension */ - ssl_state->flags |= SSL_AL_FLAG_CH_VERSION_EXTENSION; - - input += supported_ver_len; - } - else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { - if (!(HAS_SPACE(2))) - goto invalid_length; - - uint16_t ver = (uint16_t)(*input << 8) | *(input + 1); - - if ((ssl_state->flags & SSL_AL_FLAG_CH_VERSION_EXTENSION) && - (ver > TLS_VERSION_12)) { - ssl_state->flags |= SSL_AL_FLAG_LOG_WITHOUT_CERT; - } - - ssl_state->curr_connp->version = ver; - input += 2; - } - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - - return -1; -} - -static inline int TLSDecodeHSHelloExtensionEllipticCurves(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len, - JA3Buffer *ja3_elliptic_curves) -{ - const uint8_t *input = initial_input; - - /* Empty extension */ - if (input_len == 0) - return 0; - - if (!(HAS_SPACE(2))) - goto invalid_length; - - uint16_t elliptic_curves_len = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - - if (!(HAS_SPACE(elliptic_curves_len))) - goto invalid_length; - - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - SC_ATOMIC_GET(ssl_config.enable_ja3)) { - uint16_t ec_processed_len = 0; - /* coverity[tainted_data] */ - while (ec_processed_len < elliptic_curves_len) - { - if (!(HAS_SPACE(2))) - goto invalid_length; - - uint16_t elliptic_curve = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - - if (TLSDecodeValueIsGREASE(elliptic_curve) != 1) { - int rc = Ja3BufferAddValue(&ja3_elliptic_curves, - elliptic_curve); - if (rc != 0) - return -1; - } - - ec_processed_len += 2; - } - - } else { - /* Skip elliptic curves */ - input += elliptic_curves_len; - } - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - - return -1; -} - -static inline int TLSDecodeHSHelloExtensionEllipticCurvePF(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len, - JA3Buffer *ja3_elliptic_curves_pf) -{ - const uint8_t *input = initial_input; - - /* Empty extension */ - if (input_len == 0) - return 0; - - if (!(HAS_SPACE(1))) - goto invalid_length; - - uint8_t ec_pf_len = *input; - input += 1; - - if (!(HAS_SPACE(ec_pf_len))) - goto invalid_length; - - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - SC_ATOMIC_GET(ssl_config.enable_ja3)) { - uint8_t ec_pf_processed_len = 0; - /* coverity[tainted_data] */ - while (ec_pf_processed_len < ec_pf_len) - { - uint8_t elliptic_curve_pf = *input; - input += 1; - - if (TLSDecodeValueIsGREASE(elliptic_curve_pf) != 1) { - int rc = Ja3BufferAddValue(&ja3_elliptic_curves_pf, - elliptic_curve_pf); - if (rc != 0) - return -1; - } - - ec_pf_processed_len += 1; - } - - } else { - /* Skip elliptic curve point formats */ - input += ec_pf_len; - } - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - - return -1; -} - -static inline int TLSDecodeHSHelloExtensions(SSLState *ssl_state, - const uint8_t * const initial_input, - const uint32_t input_len) -{ - const uint8_t *input = initial_input; - - int ret; - int rc; - const bool ja3 = (SC_ATOMIC_GET(ssl_config.enable_ja3) == 1); - - JA3Buffer *ja3_extensions = NULL; - JA3Buffer *ja3_elliptic_curves = NULL; - JA3Buffer *ja3_elliptic_curves_pf = NULL; - - if (ja3) { - ja3_extensions = Ja3BufferInit(); - if (ja3_extensions == NULL) - goto error; - - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { - ja3_elliptic_curves = Ja3BufferInit(); - if (ja3_elliptic_curves == NULL) - goto error; - - ja3_elliptic_curves_pf = Ja3BufferInit(); - if (ja3_elliptic_curves_pf == NULL) - goto error; - } - } - - /* Extensions are optional (RFC5246 section 7.4.1.2) */ - if (!(HAS_SPACE(2))) - goto end; - - uint16_t extensions_len = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - - if (!(HAS_SPACE(extensions_len))) - goto invalid_length; - - uint16_t processed_len = 0; - /* coverity[tainted_data] */ - while (processed_len < extensions_len) - { - if (!(HAS_SPACE(2))) - goto invalid_length; - - uint16_t ext_type = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - - if (!(HAS_SPACE(2))) - goto invalid_length; - - uint16_t ext_len = (uint16_t)(*input << 8) | *(input + 1); - input += 2; - - if (!(HAS_SPACE(ext_len))) - goto invalid_length; - - switch (ext_type) { - case SSL_EXTENSION_SNI: - { - /* coverity[tainted_data] */ - ret = TLSDecodeHSHelloExtensionSni(ssl_state, input, - ext_len); - if (ret < 0) - goto end; - - input += ret; - - break; - } - - case SSL_EXTENSION_ELLIPTIC_CURVES: - { - /* coverity[tainted_data] */ - ret = TLSDecodeHSHelloExtensionEllipticCurves(ssl_state, input, - ext_len, - ja3_elliptic_curves); - if (ret < 0) - goto end; - - input += ret; - - break; - } - - case SSL_EXTENSION_EC_POINT_FORMATS: - { - /* coverity[tainted_data] */ - ret = TLSDecodeHSHelloExtensionEllipticCurvePF(ssl_state, input, - ext_len, - ja3_elliptic_curves_pf); - if (ret < 0) - goto end; - - input += ret; - - break; - } - - case SSL_EXTENSION_EARLY_DATA: - { - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { - /* Used by 0-RTT to indicate that encrypted data will - be sent right after the ClientHello record. */ - ssl_state->flags |= SSL_AL_FLAG_EARLY_DATA; - } - - input += ext_len; - - break; - } - - case SSL_EXTENSION_SUPPORTED_VERSIONS: - { - ret = TLSDecodeHSHelloExtensionSupportedVersions(ssl_state, input, - ext_len); - if (ret < 0) - goto end; - - input += ret; - - break; - } - - case SSL_EXTENSION_SESSION_TICKET: - { - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { - /* This has to be verified later on by checking if a - certificate record has been sent by the server. */ - ssl_state->flags |= SSL_AL_FLAG_SESSION_RESUMED; - } - - input += ext_len; - - break; - } - - default: - { - input += ext_len; - break; - } - } - - if (ja3) { - if (TLSDecodeValueIsGREASE(ext_type) != 1) { - rc = Ja3BufferAddValue(&ja3_extensions, ext_type); - if (rc != 0) - goto error; - } - } - - processed_len += ext_len + 4; - } - -end: - if (ja3) { - rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, - &ja3_extensions); - if (rc == -1) - goto error; - - if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { - rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, - &ja3_elliptic_curves); - if (rc == -1) - goto error; - - rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, - &ja3_elliptic_curves_pf); - if (rc == -1) - goto error; - } - } - - return (input - initial_input); - -invalid_length: - SCLogDebug("TLS handshake invalid length"); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); - -error: - if (ja3_extensions != NULL) - Ja3BufferFree(&ja3_extensions); - if (ja3_elliptic_curves != NULL) - Ja3BufferFree(&ja3_elliptic_curves); - if (ja3_elliptic_curves_pf != NULL) - Ja3BufferFree(&ja3_elliptic_curves_pf); - - return -1; -} - -static int TLSDecodeHandshakeHello(SSLState *ssl_state, - const uint8_t * const input, - const uint32_t input_len) -{ - int ret; - uint32_t parsed = 0; - - ret = TLSDecodeHSHelloVersion(ssl_state, input, input_len); - if (ret < 0) - goto end; - - parsed += ret; - - ret = TLSDecodeHSHelloRandom(ssl_state, input + parsed, input_len - parsed); - if (ret < 0) - goto end; - - parsed += ret; - - /* The session id field in the server hello record was removed in - TLSv1.3 draft1, but was readded in draft22. */ - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) || - ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0))) { - ret = TLSDecodeHSHelloSessionID(ssl_state, input + parsed, - input_len - parsed); - if (ret < 0) - goto end; - - parsed += ret; - } - - ret = TLSDecodeHSHelloCipherSuites(ssl_state, input + parsed, - input_len - parsed); - if (ret < 0) - goto end; - - parsed += ret; - - /* The compression methods field in the server hello record was - removed in TLSv1.3 draft1, but was readded in draft22. */ - if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) || - ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0))) { - ret = TLSDecodeHSHelloCompressionMethods(ssl_state, input + parsed, - input_len - parsed); - if (ret < 0) - goto end; - - parsed += ret; - } - - ret = TLSDecodeHSHelloExtensions(ssl_state, input + parsed, - input_len - parsed); - if (ret < 0) - goto end; - - if (SC_ATOMIC_GET(ssl_config.enable_ja3) && ssl_state->curr_connp->ja3_hash == NULL) { - ssl_state->curr_connp->ja3_hash = Ja3GenerateHash(ssl_state->curr_connp->ja3_str); - } - -end: - return 0; -} - -#ifdef DEBUG_VALIDATION -static inline bool -RecordAlreadyProcessed(const SSLStateConnp *curr_connp) -{ - return ((curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < - curr_connp->bytes_processed); -} -#endif - -static inline int SSLv3ParseHandshakeTypeCertificate(SSLState *ssl_state, SSLStateConnp *connp, - const uint8_t *const initial_input, const uint32_t input_len) -{ - int rc = TlsDecodeHSCertificates(ssl_state, connp, initial_input, input_len); - SCLogDebug("rc %d", rc); - if (rc > 0) { - DEBUG_VALIDATE_BUG_ON(rc > (int)input_len); - SSLParserHSReset(connp); - } else if (rc < 0) { - SCLogDebug("error parsing cert, reset state"); - SSLParserHSReset(connp); - /* fall through to still consume the cert bytes */ - } - return input_len; -} - -static int SupportedHandshakeType(const uint8_t type) -{ - switch (type) { - case SSLV3_HS_CLIENT_HELLO: - case SSLV3_HS_SERVER_HELLO: - case SSLV3_HS_SERVER_KEY_EXCHANGE: - case SSLV3_HS_CLIENT_KEY_EXCHANGE: - case SSLV3_HS_CERTIFICATE: - case SSLV3_HS_HELLO_REQUEST: - case SSLV3_HS_CERTIFICATE_REQUEST: - case SSLV3_HS_CERTIFICATE_VERIFY: - case SSLV3_HS_FINISHED: - case SSLV3_HS_CERTIFICATE_URL: - case SSLV3_HS_CERTIFICATE_STATUS: - case SSLV3_HS_NEW_SESSION_TICKET: - case SSLV3_HS_SERVER_HELLO_DONE: - return true; - break; - - default: - return false; - break; - } -} - -/** - * \retval parsed number of consumed bytes - * \retval < 0 error - */ -static int SSLv3ParseHandshakeType(SSLState *ssl_state, const uint8_t *input, - uint32_t input_len, uint8_t direction) -{ - const uint8_t *initial_input = input; - int rc; - - if (input_len == 0) { - return 0; - } - DEBUG_VALIDATE_BUG_ON(RecordAlreadyProcessed(ssl_state->curr_connp)); - - switch (ssl_state->curr_connp->handshake_type) { - case SSLV3_HS_CLIENT_HELLO: - ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; - - rc = TLSDecodeHandshakeHello(ssl_state, input, input_len); - if (rc < 0) - return rc; - break; - - case SSLV3_HS_SERVER_HELLO: - ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; - - DEBUG_VALIDATE_BUG_ON(ssl_state->curr_connp->message_length != input_len); - rc = TLSDecodeHandshakeHello(ssl_state, input, input_len); - if (rc < 0) - return rc; - break; - - case SSLV3_HS_SERVER_KEY_EXCHANGE: - ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_KEYX; - break; - - case SSLV3_HS_CLIENT_KEY_EXCHANGE: - ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; - break; - - case SSLV3_HS_CERTIFICATE: - - rc = SSLv3ParseHandshakeTypeCertificate(ssl_state, - direction ? &ssl_state->server_connp : &ssl_state->client_connp, initial_input, - input_len); - if (rc < 0) - return rc; - break; - - case SSLV3_HS_HELLO_REQUEST: - break; - case SSLV3_HS_CERTIFICATE_REQUEST: - if (direction) { - ssl_state->current_flags = SSL_AL_FLAG_NEED_CLIENT_CERT; - } - break; - case SSLV3_HS_CERTIFICATE_VERIFY: - case SSLV3_HS_FINISHED: - case SSLV3_HS_CERTIFICATE_URL: - case SSLV3_HS_CERTIFICATE_STATUS: - break; - case SSLV3_HS_NEW_SESSION_TICKET: - SCLogDebug("new session ticket"); - break; - case SSLV3_HS_SERVER_HELLO_DONE: - break; - default: - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); - return -1; - } - - ssl_state->flags |= ssl_state->current_flags; - - SCLogDebug("message: length %u", ssl_state->curr_connp->message_length); - SCLogDebug("input_len %u ssl_state->curr_connp->bytes_processed %u", input_len, ssl_state->curr_connp->bytes_processed); - - return input_len; -} - -static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, const uint8_t *input, - uint32_t input_len, uint8_t direction) -{ - const uint8_t *initial_input = input; - - if (input_len == 0 || ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { - SCReturnInt(0); - } - - while (input_len) { - SCLogDebug("input_len %u", input_len); - - if (ssl_state->curr_connp->hs_buffer != NULL) { - SCLogDebug("partial handshake record in place"); - const uint32_t need = ssl_state->curr_connp->hs_buffer_message_size - - ssl_state->curr_connp->hs_buffer_offset; - const uint32_t add = MIN(need, input_len); - - /* grow buffer to next multiple of 4k that fits all data we have */ - if (ssl_state->curr_connp->hs_buffer_offset + add > - ssl_state->curr_connp->hs_buffer_size) { - const uint32_t avail = ssl_state->curr_connp->hs_buffer_offset + add; - const uint32_t new_size = avail + (4096 - (avail % 4096)); - SCLogDebug("new_size %u, avail %u", new_size, avail); - void *ptr = SCRealloc(ssl_state->curr_connp->hs_buffer, new_size); - if (ptr == NULL) - return -1; - ssl_state->curr_connp->hs_buffer = ptr; - ssl_state->curr_connp->hs_buffer_size = new_size; - } - - SCLogDebug("ssl_state->curr_connp->hs_buffer_offset %u " - "ssl_state->curr_connp->hs_buffer_size %u", - ssl_state->curr_connp->hs_buffer_offset, ssl_state->curr_connp->hs_buffer_size); - SCLogDebug("to add %u total %u", add, ssl_state->curr_connp->hs_buffer_offset + add); - - if (SafeMemcpy(ssl_state->curr_connp->hs_buffer, - ssl_state->curr_connp->hs_buffer_offset, - ssl_state->curr_connp->hs_buffer_size, input, 0, add, add) != 0) { - SCLogDebug("copy failed"); - return -1; - } - ssl_state->curr_connp->hs_buffer_offset += add; - - if (ssl_state->curr_connp->hs_buffer_message_size <= - ssl_state->curr_connp->hs_buffer_offset) { - DEBUG_VALIDATE_BUG_ON(ssl_state->curr_connp->hs_buffer_message_size != - ssl_state->curr_connp->hs_buffer_offset); - - ssl_state->curr_connp->handshake_type = - ssl_state->curr_connp->hs_buffer_message_type; - ssl_state->curr_connp->message_length = - ssl_state->curr_connp->hs_buffer_message_size; - - SCLogDebug("got all data now: handshake_type %u message_length %u", - ssl_state->curr_connp->handshake_type, - ssl_state->curr_connp->message_length); - - int retval = SSLv3ParseHandshakeType(ssl_state, ssl_state->curr_connp->hs_buffer, - ssl_state->curr_connp->hs_buffer_offset, direction); - if (retval < 0) { - SSLParserHSReset(ssl_state->curr_connp); - return (retval); - } - SCLogDebug("retval %d", retval); - - /* data processed, reset buffer */ - SCFree(ssl_state->curr_connp->hs_buffer); - ssl_state->curr_connp->hs_buffer = NULL; - ssl_state->curr_connp->hs_buffer_size = 0; - ssl_state->curr_connp->hs_buffer_message_size = 0; - ssl_state->curr_connp->hs_buffer_message_type = 0; - ssl_state->curr_connp->hs_buffer_offset = 0; - } else { - SCLogDebug("partial data"); - } - - input += add; - input_len -= add; - SCLogDebug("input_len %u", input_len); - SSLParserHSReset(ssl_state->curr_connp); - continue; - } - - SCLogDebug("bytes_processed %u", ssl_state->curr_connp->bytes_processed); - SCLogDebug("input %p input_len %u", input, input_len); - - if (input_len < 4) { - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); - SCReturnInt(-1); - } - - ssl_state->curr_connp->handshake_type = input[0]; - ssl_state->curr_connp->message_length = input[1] << 16 | input[2] << 8 | input[3]; - SCLogDebug("handshake_type %u message len %u input %p input_len %u", - ssl_state->curr_connp->handshake_type, ssl_state->curr_connp->message_length, input, - input_len); - input += 4; - input_len -= 4; - - const uint32_t record_len = ssl_state->curr_connp->message_length; - /* see if we support this type. We check here to not use the fragment - * handling on things we don't support. */ - const bool supported_type = SupportedHandshakeType(ssl_state->curr_connp->handshake_type); - SCLogDebug("supported_type %s handshake_type %u/%02x", supported_type ? "true" : "false", - ssl_state->curr_connp->handshake_type, ssl_state->curr_connp->handshake_type); - if (!supported_type) { - uint32_t avail_record_len = MIN(input_len, record_len); - input += avail_record_len; - input_len -= avail_record_len; - - SSLParserHSReset(ssl_state->curr_connp); - - if ((direction && (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) || - (!direction && (ssl_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC))) { - // after Change Cipher Spec we get Encrypted Handshake Messages - } else { - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); - } - continue; - } - - /* if the message length exceeds our input_len, we have a tls fragment. */ - if (record_len > input_len) { - const uint32_t avail = input_len; - const uint32_t size = avail + (4096 - (avail % 4096)); - SCLogDebug("initial buffer size %u, based on input %u", size, avail); - ssl_state->curr_connp->hs_buffer = SCCalloc(1, size); - if (ssl_state->curr_connp->hs_buffer == NULL) { - return -1; - } - ssl_state->curr_connp->hs_buffer_size = size; - ssl_state->curr_connp->hs_buffer_message_size = record_len; - ssl_state->curr_connp->hs_buffer_message_type = ssl_state->curr_connp->handshake_type; - - if (input_len > 0) { - if (SafeMemcpy(ssl_state->curr_connp->hs_buffer, 0, - ssl_state->curr_connp->hs_buffer_size, input, 0, input_len, - input_len) != 0) { - return -1; - } - ssl_state->curr_connp->hs_buffer_offset = input_len; - } - SCLogDebug("opened record buffer %p size %u offset %u type %u msg_size %u", - ssl_state->curr_connp->hs_buffer, ssl_state->curr_connp->hs_buffer_size, - ssl_state->curr_connp->hs_buffer_offset, - ssl_state->curr_connp->hs_buffer_message_type, - ssl_state->curr_connp->hs_buffer_message_size); - input += input_len; - SSLParserHSReset(ssl_state->curr_connp); - return (input - initial_input); - - } else { - /* full record, parse it now */ - int retval = SSLv3ParseHandshakeType( - ssl_state, input, ssl_state->curr_connp->message_length, direction); - if (retval < 0 || retval > (int)input_len) { - DEBUG_VALIDATE_BUG_ON(retval > (int)input_len); - return (retval); - } - SCLogDebug("retval %d input_len %u", retval, input_len); - input += retval; - input_len -= retval; - - SSLParserHSReset(ssl_state->curr_connp); - } - SCLogDebug("input_len left %u", input_len); - } - return (input - initial_input); -} - -/** - * \internal - * \brief TLS Heartbeat parser (see RFC 6520) - * - * \param sslstate Pointer to the SSL state. - * \param input Pointer to the received input data. - * \param input_len Length in bytes of the received data. - * \param direction 1 toclient, 0 toserver - * - * \retval The number of bytes parsed on success, 0 if nothing parsed, -1 on failure. - */ -static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, const uint8_t *input, - uint32_t input_len, uint8_t direction) -{ - uint8_t hb_type; - uint16_t payload_len; - uint32_t padding_len; - - /* expect at least 3 bytes: heartbeat type (1) + length (2) */ - if (input_len < 3) { - return 0; - } - - hb_type = *input++; - - if (!(ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { - if (!(hb_type == TLS_HB_REQUEST || hb_type == TLS_HB_RESPONSE)) { - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); - return -1; - } - } - - if ((ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) == 0) { - ssl_state->flags |= SSL_AL_FLAG_HB_INFLIGHT; - - if (direction) { - SCLogDebug("HeartBeat Record type sent in the toclient direction!"); - ssl_state->flags |= SSL_AL_FLAG_HB_SERVER_INIT; - } else { - SCLogDebug("HeartBeat Record type sent in the toserver direction!"); - ssl_state->flags |= SSL_AL_FLAG_HB_CLIENT_INIT; - } - - /* if we reach this point, then we can assume that the HB request - is encrypted. If so, let's set the HB record length */ - if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { - ssl_state->hb_record_len = ssl_state->curr_connp->record_length; - SCLogDebug("Encrypted HeartBeat Request In-flight. Storing len %u", - ssl_state->hb_record_len); - return (ssl_state->curr_connp->record_length - 3); - } - - payload_len = (uint16_t)(*input << 8) | *(input + 1); - - /* check that the requested payload length is really present in - the record (CVE-2014-0160) */ - if ((uint32_t)(payload_len+3) > ssl_state->curr_connp->record_length) { - SCLogDebug("We have a short record in HeartBeat Request"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); - return -1; - } - - /* check the padding length. It must be at least 16 bytes - (RFC 6520, section 4) */ - padding_len = ssl_state->curr_connp->record_length - payload_len - 3; - if (padding_len < 16) { - SCLogDebug("We have a short record in HeartBeat Request"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); - return -1; - } - - /* we don't have the payload */ - if (input_len < payload_len + padding_len) { - return 0; - } - - /* OpenSSL still seems to discard multiple in-flight - heartbeats although some tools send multiple at once */ - } else if (direction == 1 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && - (ssl_state->flags & SSL_AL_FLAG_HB_SERVER_INIT)) { - SCLogDebug("Multiple in-flight server initiated HeartBeats"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); - return -1; - - } else if (direction == 0 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && - (ssl_state->flags & SSL_AL_FLAG_HB_CLIENT_INIT)) { - SCLogDebug("Multiple in-flight client initiated HeartBeats"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); - return -1; - - } else { - /* we have a HB record in the opposite direction of the request, - let's reset our flags */ - ssl_state->flags &= ~SSL_AL_FLAG_HB_INFLIGHT; - ssl_state->flags &= ~SSL_AL_FLAG_HB_SERVER_INIT; - ssl_state->flags &= ~SSL_AL_FLAG_HB_CLIENT_INIT; - - /* if we reach this point, then we can assume that the HB request - is encrypted. If so, let's set the HB record length */ - if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { - /* check to see if the encrypted response is longer than the - encrypted request */ - if (ssl_state->hb_record_len > 0 && ssl_state->hb_record_len < - ssl_state->curr_connp->record_length) { - SCLogDebug("My heart is bleeding.. OpenSSL HeartBleed response (%u)", - ssl_state->hb_record_len); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH); - ssl_state->hb_record_len = 0; - return -1; - } - } - - /* reset the HB record length in case we have a legit HB followed - by a bad one */ - ssl_state->hb_record_len = 0; - } - - /* skip the HeartBeat, 3 bytes were already parsed, - e.g |18 03 02| for TLS 1.2 */ - return (ssl_state->curr_connp->record_length - 3); -} - -static int SSLv3ParseRecord(uint8_t direction, SSLState *ssl_state, - const uint8_t *input, uint32_t input_len) -{ - const uint8_t *initial_input = input; - - if (input_len == 0) { - return 0; - } - - uint8_t skip_version = 0; - - /* Only set SSL/TLS version here if it has not already been set in - client/server hello. */ - if (direction == 0) { - if ((ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - (ssl_state->client_connp.version != TLS_VERSION_UNKNOWN)) { - skip_version = 1; - } - } else { - if ((ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - (ssl_state->server_connp.version != TLS_VERSION_UNKNOWN)) { - skip_version = 1; - } - } - - switch (ssl_state->curr_connp->bytes_processed) { - case 0: - if (input_len >= 5) { - ssl_state->curr_connp->content_type = input[0]; - if (!skip_version) { - ssl_state->curr_connp->version = (uint16_t)(input[1] << 8) | input[2]; - } - ssl_state->curr_connp->record_length = input[3] << 8; - ssl_state->curr_connp->record_length |= input[4]; - ssl_state->curr_connp->bytes_processed += SSLV3_RECORD_HDR_LEN; - return SSLV3_RECORD_HDR_LEN; - } else { - ssl_state->curr_connp->content_type = *(input++); - if (--input_len == 0) - break; - } - - /* fall through */ - case 1: - if (!skip_version) { - ssl_state->curr_connp->version = (uint16_t)(*(input++) << 8); - } else { - input++; - } - if (--input_len == 0) - break; - - /* fall through */ - case 2: - if (!skip_version) { - ssl_state->curr_connp->version |= *(input++); - } else { - input++; - } - if (--input_len == 0) - break; - - /* fall through */ - case 3: - ssl_state->curr_connp->record_length = *(input++) << 8; - if (--input_len == 0) - break; - - /* fall through */ - case 4: - ssl_state->curr_connp->record_length |= *(input++); - if (--input_len == 0) - break; - - /* fall through */ - } - - ssl_state->curr_connp->bytes_processed += (input - initial_input); - - return (input - initial_input); -} - -static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, - const uint8_t *input, uint32_t input_len) -{ - const uint8_t *initial_input = input; - - if (input_len == 0) { - return 0; - } - - if (ssl_state->curr_connp->record_lengths_length == 2) { - switch (ssl_state->curr_connp->bytes_processed) { - case 0: - if (input_len >= ssl_state->curr_connp->record_lengths_length + 1) { - ssl_state->curr_connp->record_length = (0x7f & input[0]) << 8 | input[1]; - ssl_state->curr_connp->content_type = input[2]; - ssl_state->curr_connp->version = SSL_VERSION_2; - ssl_state->curr_connp->bytes_processed += 3; - return 3; - } else { - ssl_state->curr_connp->record_length = (0x7f & *(input++)) << 8; - if (--input_len == 0) - break; - } - - /* fall through */ - case 1: - ssl_state->curr_connp->record_length |= *(input++); - if (--input_len == 0) - break; - - /* fall through */ - case 2: - ssl_state->curr_connp->content_type = *(input++); - ssl_state->curr_connp->version = SSL_VERSION_2; - if (--input_len == 0) - break; - - /* fall through */ - } - - } else { - switch (ssl_state->curr_connp->bytes_processed) { - case 0: - if (input_len >= ssl_state->curr_connp->record_lengths_length + 1) { - ssl_state->curr_connp->record_length = (0x3f & input[0]) << 8 | input[1]; - ssl_state->curr_connp->content_type = input[3]; - ssl_state->curr_connp->version = SSL_VERSION_2; - ssl_state->curr_connp->bytes_processed += 4; - return 4; - } else { - ssl_state->curr_connp->record_length = (0x3f & *(input++)) << 8; - if (--input_len == 0) - break; - } - - /* fall through */ - case 1: - ssl_state->curr_connp->record_length |= *(input++); - if (--input_len == 0) - break; - - /* fall through */ - case 2: - /* padding */ - input++; - if (--input_len == 0) - break; - - /* fall through */ - case 3: - ssl_state->curr_connp->content_type = *(input++); - ssl_state->curr_connp->version = SSL_VERSION_2; - if (--input_len == 0) - break; - - /* fall through */ - } - } - - ssl_state->curr_connp->bytes_processed += (input - initial_input); - - return (input - initial_input); -} - -static struct SSLDecoderResult SSLv2Decode(uint8_t direction, SSLState *ssl_state, - AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len, - const StreamSlice stream_slice) -{ - const uint8_t *initial_input = input; - - if (ssl_state->curr_connp->bytes_processed == 0) { - if (input[0] & 0x80) { - ssl_state->curr_connp->record_lengths_length = 2; - } else { - ssl_state->curr_connp->record_lengths_length = 3; - } - - SCLogDebug("record start: ssl2.hdr frame"); - AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, - ssl_state->curr_connp->record_lengths_length + 1, direction, TLS_FRAME_SSLV2_HDR); - } - - SCLogDebug("direction %u ssl_state->curr_connp->record_lengths_length + 1 %u, " - "ssl_state->curr_connp->bytes_processed %u", - direction, ssl_state->curr_connp->record_lengths_length + 1, - ssl_state->curr_connp->bytes_processed); - /* the +1 is because we read one extra byte inside SSLv2ParseRecord - to read the msg_type */ - if (ssl_state->curr_connp->bytes_processed < - (ssl_state->curr_connp->record_lengths_length + 1)) { - const int retval = SSLv2ParseRecord(direction, ssl_state, input, input_len); - SCLogDebug("retval %d ssl_state->curr_connp->record_length %u", retval, - ssl_state->curr_connp->record_length); - if (retval < 0 || retval > (int)input_len) { - DEBUG_VALIDATE_BUG_ON(retval > (int)input_len); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); - return SSL_DECODER_ERROR(-1); - } - - AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, - ssl_state->curr_connp->record_lengths_length + ssl_state->curr_connp->record_length, - direction, TLS_FRAME_SSLV2_PDU); - SCLogDebug("record start: ssl2.pdu frame"); - - input += retval; - input_len -= retval; - } - - /* if we don't have the full record, we return incomplete */ - if (ssl_state->curr_connp->record_lengths_length + ssl_state->curr_connp->record_length > - input_len + ssl_state->curr_connp->bytes_processed) { - uint32_t needed = ssl_state->curr_connp->record_length; - SCLogDebug("record len %u input_len %u parsed %u: need %u bytes more data", - ssl_state->curr_connp->record_length, input_len, (uint32_t)(input - initial_input), - needed); - return SSL_DECODER_INCOMPLETE((input - initial_input), needed); - } - - if (input_len == 0) { - return SSL_DECODER_OK((input - initial_input)); - } - - /* record_length should never be zero */ - if (ssl_state->curr_connp->record_length == 0) { - SCLogDebug("SSLv2 record length is zero"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); - return SSL_DECODER_ERROR(-1); - } - - /* record_lengths_length should never be zero */ - if (ssl_state->curr_connp->record_lengths_length == 0) { - SCLogDebug("SSLv2 record lengths length is zero"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); - return SSL_DECODER_ERROR(-1); - } - - switch (ssl_state->curr_connp->content_type) { - case SSLV2_MT_ERROR: - SCLogDebug("SSLV2_MT_ERROR msg_type received. Error encountered " - "in establishing the sslv2 session, may be version"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); - - break; - - case SSLV2_MT_CLIENT_HELLO: - if (input_len < 6) { - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); - return SSL_DECODER_ERROR(-1); - } - - ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; - ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_HS; - - const uint16_t version = (uint16_t)(input[0] << 8) | input[1]; - SCLogDebug("SSLv2: version %04x", version); - ssl_state->curr_connp->version = version; - uint16_t session_id_length = (input[5]) | (uint16_t)(input[4] << 8); - input += 6; - input_len -= 6; - ssl_state->curr_connp->bytes_processed += 6; - if (session_id_length == 0) { - ssl_state->current_flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; - } - break; - - case SSLV2_MT_CLIENT_MASTER_KEY: - if (!(ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS)) { - SCLogDebug("Client hello is not seen before master key " - "message!"); - } - ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; - - break; - - case SSLV2_MT_CLIENT_CERTIFICATE: - if (direction == 1) { - SCLogDebug("Incorrect SSL Record type sent in the toclient " - "direction!"); - } else { - ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; - } - - /* fall through */ - case SSLV2_MT_SERVER_VERIFY: - case SSLV2_MT_SERVER_FINISHED: - if (direction == 0 && - !(ssl_state->curr_connp->content_type & - SSLV2_MT_CLIENT_CERTIFICATE)) { - SCLogDebug("Incorrect SSL Record type sent in the toserver " - "direction!"); - } - - /* fall through */ - case SSLV2_MT_CLIENT_FINISHED: - case SSLV2_MT_REQUEST_CERTIFICATE: - /* both client hello and server hello must be seen */ - if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) && - (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_HS)) { - - if (direction == 0) { - if (ssl_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) { - ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; - SCLogDebug("SSLv2 client side has started the encryption"); - } else if (ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY) { - ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; - SCLogDebug("SSLv2 client side has started the encryption"); - } - } else { - ssl_state->current_flags = SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED; - SCLogDebug("SSLv2 Server side has started the encryption"); - } - - if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED) && - (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED)) - { - if (ssl_config.encrypt_mode != SSL_CNF_ENC_HANDLE_FULL) { - AppLayerParserStateSetFlag(pstate, - APP_LAYER_PARSER_NO_INSPECTION); - } - - if (ssl_config.encrypt_mode == SSL_CNF_ENC_HANDLE_BYPASS) { - AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); - AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_BYPASS_READY); - } - SCLogDebug("SSLv2 No reassembly & inspection has been set"); - } - } - - break; - - case SSLV2_MT_SERVER_HELLO: - ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; - ssl_state->current_flags |= SSL_AL_FLAG_SSL_SERVER_HS; - - break; - } - - ssl_state->flags |= ssl_state->current_flags; - - if (input_len + ssl_state->curr_connp->bytes_processed >= - (ssl_state->curr_connp->record_length + - ssl_state->curr_connp->record_lengths_length)) { - - /* looks like we have another record after this */ - uint32_t diff = ssl_state->curr_connp->record_length + - ssl_state->curr_connp->record_lengths_length + - - ssl_state->curr_connp->bytes_processed; - input += diff; - SSLParserReset(ssl_state); - - /* we still don't have the entire record for the one we are - currently parsing */ - } else { - input += input_len; - ssl_state->curr_connp->bytes_processed += input_len; - } - return SSL_DECODER_OK((input - initial_input)); -} - -static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_state, - AppLayerParserState *pstate, const uint8_t *input, const uint32_t input_len, - const StreamSlice stream_slice) -{ - uint32_t parsed = 0; - uint32_t record_len; /* slice of input_len for the current record */ - const bool first_call = (ssl_state->curr_connp->bytes_processed == 0); - - if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { - const uint16_t prev_version = ssl_state->curr_connp->version; - - int retval = SSLv3ParseRecord(direction, ssl_state, input, input_len); - if (retval < 0 || retval > (int)input_len) { - DEBUG_VALIDATE_BUG_ON(retval > (int)input_len); - SCLogDebug("SSLv3ParseRecord returned %d", retval); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_TLS_HEADER); - return SSL_DECODER_ERROR(-1); - } - parsed = retval; - - SCLogDebug("%s input %p record_length %u", (direction == 0) ? "toserver" : "toclient", - input, ssl_state->curr_connp->record_length); - - /* first the hdr frame at our first chance */ - if (first_call) { - AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, SSLV3_RECORD_HDR_LEN, - direction, TLS_FRAME_HDR); - } - - /* parser is streaming for the initial header, then switches to incomplete - * API: so if we don't have the hdr yet, return consumed bytes and wait - * until we are called again with new data. */ - if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { - SCLogDebug( - "incomplete header, return %u bytes consumed and wait for more data", parsed); - return SSL_DECODER_OK(parsed); - } - - /* pdu frame needs record length, so only create it when hdr fully parsed. */ - AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, - ssl_state->curr_connp->record_length + retval, direction, TLS_FRAME_PDU); - record_len = MIN(input_len - parsed, ssl_state->curr_connp->record_length); - SCLogDebug( - "record_len %u (input_len %u, parsed %u, ssl_state->curr_connp->record_length %u)", - record_len, input_len, parsed, ssl_state->curr_connp->record_length); - - bool unknown_record = false; - switch (ssl_state->curr_connp->content_type) { - case SSLV3_CHANGE_CIPHER_SPEC: - case SSLV3_ALERT_PROTOCOL: - case SSLV3_HANDSHAKE_PROTOCOL: - case SSLV3_APPLICATION_PROTOCOL: - case SSLV3_HEARTBEAT_PROTOCOL: - break; - default: - unknown_record = true; - break; - } - - /* unknown record type. For TLS 1.0, 1.1 and 1.2 this is ok. For the rest it is fatal. Based - * on Wireshark logic. */ - if (prev_version == TLS_VERSION_10 || prev_version == TLS_VERSION_11) { - if (unknown_record) { - SCLogDebug("unknown record, ignore it"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); - - ssl_state->curr_connp->bytes_processed = 0; // TODO review this reset logic - ssl_state->curr_connp->content_type = 0; - ssl_state->curr_connp->record_length = 0; - // restore last good version - ssl_state->curr_connp->version = prev_version; - return SSL_DECODER_OK(input_len); // consume everything - } - } else { - if (unknown_record) { - SCLogDebug("unknown record, fatal"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); - return SSL_DECODER_ERROR(-1); - } - } - - /* record_length should never be zero */ - if (ssl_state->curr_connp->record_length == 0) { - SCLogDebug("SSLv3 Record length is 0"); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_LENGTH); - return SSL_DECODER_ERROR(-1); - } - - if (!TLSVersionValid(ssl_state->curr_connp->version)) { - SCLogDebug("ssl_state->curr_connp->version %04x", ssl_state->curr_connp->version); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_VERSION); - return SSL_DECODER_ERROR(-1); - } - - if (ssl_state->curr_connp->bytes_processed == SSLV3_RECORD_HDR_LEN && - ssl_state->curr_connp->record_length > SSLV3_RECORD_MAX_LEN) { - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_LENGTH); - return SSL_DECODER_ERROR(-1); - } - DEBUG_VALIDATE_BUG_ON(ssl_state->curr_connp->bytes_processed > SSLV3_RECORD_HDR_LEN); - } else { - ValidateRecordState(ssl_state->curr_connp); - - record_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)- ssl_state->curr_connp->bytes_processed; - record_len = MIN(input_len, record_len); - } - SCLogDebug("record length %u processed %u got %u", - ssl_state->curr_connp->record_length, ssl_state->curr_connp->bytes_processed, record_len); - - /* if we don't have the full record, we return incomplete */ - if (ssl_state->curr_connp->record_length > input_len - parsed) { - /* no need to use incomplete api buffering for application - * records that we'll not use anyway. */ - if (ssl_state->curr_connp->content_type == SSLV3_APPLICATION_PROTOCOL) { - SCLogDebug("application record"); - } else { - uint32_t needed = ssl_state->curr_connp->record_length; - SCLogDebug("record len %u input_len %u parsed %u: need %u bytes more data", - ssl_state->curr_connp->record_length, input_len, parsed, needed); - DEBUG_VALIDATE_BUG_ON(needed > SSLV3_RECORD_MAX_LEN); - return SSL_DECODER_INCOMPLETE(parsed, needed); - } - } - - if (record_len == 0) { - return SSL_DECODER_OK(parsed); - } - - AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input + parsed, - ssl_state->curr_connp->record_length, direction, TLS_FRAME_DATA); - - switch (ssl_state->curr_connp->content_type) { - /* we don't need any data from these types */ - case SSLV3_CHANGE_CIPHER_SPEC: - ssl_state->flags |= SSL_AL_FLAG_CHANGE_CIPHER_SPEC; - - if (direction) { - ssl_state->flags |= SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC; - } else { - ssl_state->flags |= SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC; - } - break; - - case SSLV3_ALERT_PROTOCOL: - AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input + parsed, - ssl_state->curr_connp->record_length, direction, TLS_FRAME_ALERT_DATA); - break; - - case SSLV3_APPLICATION_PROTOCOL: - /* In TLSv1.3 early data (0-RTT) could be sent before the - handshake is complete (rfc8446, section 2.3). We should - therefore not mark the handshake as done before we have - seen the ServerHello record. */ - if ((ssl_state->flags & SSL_AL_FLAG_EARLY_DATA) && - ((ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0)) - break; - - /* if we see (encrypted) application data, then this means the - handshake must be done */ - ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; - - if (ssl_config.encrypt_mode != SSL_CNF_ENC_HANDLE_FULL) { - SCLogDebug("setting APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD"); - AppLayerParserStateSetFlag(pstate, - APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD); - } - - /* Encrypted data, reassembly not asked, bypass asked, let's sacrifice - * heartbeat lke inspection to be able to be able to bypass the flow */ - if (ssl_config.encrypt_mode == SSL_CNF_ENC_HANDLE_BYPASS) { - SCLogDebug("setting APP_LAYER_PARSER_NO_REASSEMBLY"); - AppLayerParserStateSetFlag(pstate, - APP_LAYER_PARSER_NO_REASSEMBLY); - AppLayerParserStateSetFlag(pstate, - APP_LAYER_PARSER_NO_INSPECTION); - AppLayerParserStateSetFlag(pstate, - APP_LAYER_PARSER_BYPASS_READY); - } - break; - - case SSLV3_HANDSHAKE_PROTOCOL: { - if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { - /* In TLSv1.3, ChangeCipherSpec is only used for middlebox - compatibility (rfc8446, appendix D.4). */ - // Client hello flags is needed to have a valid version - if ((ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - (ssl_state->client_connp.version > TLS_VERSION_12) && - ((ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0)) { - /* do nothing */ - } else { - // if we started parsing this, we must stop - break; - } - } - - if (ssl_state->curr_connp->record_length < 4) { - SSLParserReset(ssl_state); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); - SCLogDebug("record len < 4 => %u", ssl_state->curr_connp->record_length); - return SSL_DECODER_ERROR(-1); - } - - int retval = SSLv3ParseHandshakeProtocol(ssl_state, input + parsed, - record_len, direction); - SCLogDebug("retval %d", retval); - if (retval < 0 || retval > (int)record_len) { - DEBUG_VALIDATE_BUG_ON(retval > (int)record_len); - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); - SCLogDebug("SSLv3ParseHandshakeProtocol returned %d", retval); - return SSL_DECODER_ERROR(-1); - } - ValidateRecordState(ssl_state->curr_connp); - break; - } - case SSLV3_HEARTBEAT_PROTOCOL: { - AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input + parsed, - ssl_state->curr_connp->record_length, direction, TLS_FRAME_HB_DATA); - int retval = SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, - record_len, direction); - if (retval < 0) { - SCLogDebug("SSLv3ParseHeartbeatProtocol returned %d", retval); - return SSL_DECODER_ERROR(-1); - } - break; - } - default: - // should be unreachable now that we check after header parsing - DEBUG_VALIDATE_BUG_ON(1); - SCLogDebug("unsupported record type"); - return SSL_DECODER_ERROR(-1); - } - - parsed += record_len; - ssl_state->curr_connp->bytes_processed += record_len; - - if (ssl_state->curr_connp->bytes_processed >= - ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { - SCLogDebug("record complete, trigger RAW"); - AppLayerParserTriggerRawStreamReassembly( - ssl_state->f, direction == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT); - SSLParserReset(ssl_state); - ValidateRecordState(ssl_state->curr_connp); - return SSL_DECODER_OK(parsed); - - } else { - /* we still don't have the entire record for the one we are - currently parsing */ - ValidateRecordState(ssl_state->curr_connp); - return SSL_DECODER_OK(parsed); - } -} - -/** - * \internal - * \brief SSLv2, SSLv23, SSLv3, TLSv1.1, TLSv1.2, TLSv1.3 parser. - * - * On parsing error, this should be the only function that should reset - * the parser state, to avoid multiple functions in the chain resetting - * the parser state. - * - * \param direction 0 for toserver, 1 for toclient. - * \param alstate Pointer to the state. - * \param pstate Application layer parser state for this session. - * \param output Pointer to the list of parsed output elements. - * - * \todo On reaching an inconsistent state, check if the input has - * another new record, instead of just returning after the reset - * - * \retval >=0 On success. - */ -static AppLayerResult SSLDecode(Flow *f, uint8_t direction, void *alstate, - AppLayerParserState *pstate, StreamSlice stream_slice) -{ - SSLState *ssl_state = (SSLState *)alstate; - uint32_t counter = 0; - ssl_state->f = f; - const uint8_t *input = StreamSliceGetData(&stream_slice); - const uint8_t *init_input = input; - int32_t input_len = (int32_t)StreamSliceGetDataLen(&stream_slice); - - if (input == NULL && - ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) || - (direction == 1 && - AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) { - /* flag session as finished if APP_LAYER_PARSER_EOF is set */ - ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; - SCReturnStruct(APP_LAYER_OK); - } else if (input == NULL || input_len == 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - - if (direction == 0) - ssl_state->curr_connp = &ssl_state->client_connp; - else - ssl_state->curr_connp = &ssl_state->server_connp; - - /* If entering on a new record, reset the current flags. */ - if (ssl_state->curr_connp->bytes_processed == 0) { - ssl_state->current_flags = 0; - } - - /* if we have more than one record */ - uint32_t max_records = MAX((input_len / SSL_RECORD_MINIMUM_LENGTH),1); - while (input_len > 0) { - if (counter > max_records) { - SCLogDebug("Looks like we have looped quite a bit. Reset state " - "and get out of here"); - SSLParserReset(ssl_state); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET); - return APP_LAYER_ERROR; - } - - /* ssl_state->bytes_processed is zero for a fresh record or - positive to indicate a record currently being parsed */ - - if (ssl_state->curr_connp->bytes_processed == 0) { - if ((input[0] & 0x80) || (input[0] & 0x40)) { - /* only SSLv2, has one of the top 2 bits set */ - ssl_state->curr_connp->version = SSL_VERSION_2; - SCLogDebug("SSLv2 detected"); - } else if (ssl_state->curr_connp->version == SSL_VERSION_2) { - ssl_state->curr_connp->version = TLS_VERSION_UNKNOWN; - SCLogDebug("SSL/TLS version reset"); - } - } - SCLogDebug("record %u: bytes_processed %u, version %02X, input_len %u", counter, - ssl_state->curr_connp->bytes_processed, ssl_state->curr_connp->version, input_len); - - if (ssl_state->curr_connp->version == SSL_VERSION_2) { - if (ssl_state->curr_connp->bytes_processed == 0) { - SCLogDebug("New SSLv2 record parsing"); - } else { - SCLogDebug("Continuing parsing SSLv2 record"); - } - struct SSLDecoderResult r = - SSLv2Decode(direction, ssl_state, pstate, input, input_len, stream_slice); - if (r.retval < 0 || r.retval > input_len) { - DEBUG_VALIDATE_BUG_ON(r.retval > input_len); - SCLogDebug("Error parsing SSLv2. Resetting parser " - "state. Let's get outta here"); - SSLParserReset(ssl_state); - SSLSetEvent(ssl_state, - TLS_DECODER_EVENT_INVALID_SSL_RECORD); - return APP_LAYER_ERROR; - } else if (r.needed) { - input += r.retval; - SCLogDebug("returning consumed %" PRIuMAX " needed %u", - (uintmax_t)(input - init_input), r.needed); - SCReturnStruct(APP_LAYER_INCOMPLETE(input - init_input, r.needed)); - } - input_len -= r.retval; - input += r.retval; - SCLogDebug("SSLv2 decoder consumed %d bytes: %u left", r.retval, input_len); - } else { - if (ssl_state->curr_connp->bytes_processed == 0) { - SCLogDebug("New TLS record: record_length %u", - ssl_state->curr_connp->record_length); - } else { - SCLogDebug("Continuing parsing TLS record: record_length %u, bytes_processed %u", - ssl_state->curr_connp->record_length, ssl_state->curr_connp->bytes_processed); - } - struct SSLDecoderResult r = - SSLv3Decode(direction, ssl_state, pstate, input, input_len, stream_slice); - if (r.retval < 0 || r.retval > input_len) { - DEBUG_VALIDATE_BUG_ON(r.retval > input_len); - SCLogDebug("Error parsing TLS. Resetting parser " - "state. Let's get outta here"); - SSLParserReset(ssl_state); - return APP_LAYER_ERROR; - } else if (r.needed) { - input += r.retval; - SCLogDebug("returning consumed %" PRIuMAX " needed %u", - (uintmax_t)(input - init_input), r.needed); - SCReturnStruct(APP_LAYER_INCOMPLETE(input - init_input, r.needed)); - } - input_len -= r.retval; - input += r.retval; - SCLogDebug("TLS decoder consumed %d bytes: %u left", r.retval, input_len); - - if (ssl_state->curr_connp->bytes_processed == SSLV3_RECORD_HDR_LEN - && ssl_state->curr_connp->record_length == 0) { - SCLogDebug("TLS empty record"); - /* empty record */ - SSLParserReset(ssl_state); - } - } - counter++; - } /* while (input_len) */ - - /* mark handshake as done if we have subject and issuer */ - if ((ssl_state->flags & SSL_AL_FLAG_NEED_CLIENT_CERT) && - ssl_state->client_connp.cert0_subject && ssl_state->client_connp.cert0_issuerdn) { - SCLogDebug("SSL_AL_FLAG_HANDSHAKE_DONE"); - ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; - } else if ((ssl_state->flags & SSL_AL_FLAG_NEED_CLIENT_CERT) == 0 && - ssl_state->server_connp.cert0_subject && ssl_state->server_connp.cert0_issuerdn) { - SCLogDebug("SSL_AL_FLAG_HANDSHAKE_DONE"); - ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; - } - - /* flag session as finished if APP_LAYER_PARSER_EOF is set */ - if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) && - AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)) { - SCLogDebug("SSL_AL_FLAG_STATE_FINISHED"); - ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; - } - - return APP_LAYER_OK; -} - -static AppLayerResult SSLParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - return SSLDecode(f, 0 /* toserver */, alstate, pstate, stream_slice); -} - -static AppLayerResult SSLParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - return SSLDecode(f, 1 /* toclient */, alstate, pstate, stream_slice); -} - -/** - * \internal - * \brief Function to allocate the SSL state memory. - */ -static void *SSLStateAlloc(void *orig_state, AppProto proto_orig) -{ - SSLState *ssl_state = SCCalloc(1, sizeof(SSLState)); - if (unlikely(ssl_state == NULL)) - return NULL; - ssl_state->client_connp.cert_log_flag = 0; - ssl_state->server_connp.cert_log_flag = 0; - memset(ssl_state->client_connp.random, 0, TLS_RANDOM_LEN); - memset(ssl_state->server_connp.random, 0, TLS_RANDOM_LEN); - TAILQ_INIT(&ssl_state->server_connp.certs); - TAILQ_INIT(&ssl_state->client_connp.certs); - - return (void *)ssl_state; -} - -/** - * \internal - * \brief Function to free the SSL state memory. - */ -static void SSLStateFree(void *p) -{ - SSLState *ssl_state = (SSLState *)p; - SSLCertsChain *item; - - if (ssl_state->client_connp.cert0_subject) - rs_cstring_free(ssl_state->client_connp.cert0_subject); - if (ssl_state->client_connp.cert0_issuerdn) - rs_cstring_free(ssl_state->client_connp.cert0_issuerdn); - if (ssl_state->client_connp.cert0_serial) - rs_cstring_free(ssl_state->client_connp.cert0_serial); - if (ssl_state->client_connp.cert0_fingerprint) - SCFree(ssl_state->client_connp.cert0_fingerprint); - if (ssl_state->client_connp.sni) - SCFree(ssl_state->client_connp.sni); - if (ssl_state->client_connp.session_id) - SCFree(ssl_state->client_connp.session_id); - if (ssl_state->client_connp.hs_buffer) - SCFree(ssl_state->client_connp.hs_buffer); - - if (ssl_state->server_connp.cert0_subject) - rs_cstring_free(ssl_state->server_connp.cert0_subject); - if (ssl_state->server_connp.cert0_issuerdn) - rs_cstring_free(ssl_state->server_connp.cert0_issuerdn); - if (ssl_state->server_connp.cert0_serial) - rs_cstring_free(ssl_state->server_connp.cert0_serial); - if (ssl_state->server_connp.cert0_fingerprint) - SCFree(ssl_state->server_connp.cert0_fingerprint); - if (ssl_state->server_connp.sni) - SCFree(ssl_state->server_connp.sni); - if (ssl_state->server_connp.session_id) - SCFree(ssl_state->server_connp.session_id); - - if (ssl_state->client_connp.ja3_str) - Ja3BufferFree(&ssl_state->client_connp.ja3_str); - if (ssl_state->client_connp.ja3_hash) - SCFree(ssl_state->client_connp.ja3_hash); - if (ssl_state->server_connp.ja3_str) - Ja3BufferFree(&ssl_state->server_connp.ja3_str); - if (ssl_state->server_connp.ja3_hash) - SCFree(ssl_state->server_connp.ja3_hash); - if (ssl_state->server_connp.hs_buffer) - SCFree(ssl_state->server_connp.hs_buffer); - - AppLayerDecoderEventsFreeEvents(&ssl_state->tx_data.events); - - if (ssl_state->tx_data.de_state != NULL) { - DetectEngineStateFree(ssl_state->tx_data.de_state); - } - - /* Free certificate chain */ - if (ssl_state->server_connp.certs_buffer) - SCFree(ssl_state->server_connp.certs_buffer); - while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) { - TAILQ_REMOVE(&ssl_state->server_connp.certs, item, next); - SCFree(item); - } - TAILQ_INIT(&ssl_state->server_connp.certs); - /* Free certificate chain */ - if (ssl_state->client_connp.certs_buffer) - SCFree(ssl_state->client_connp.certs_buffer); - while ((item = TAILQ_FIRST(&ssl_state->client_connp.certs))) { - TAILQ_REMOVE(&ssl_state->client_connp.certs, item, next); - SCFree(item); - } - TAILQ_INIT(&ssl_state->client_connp.certs); - - SCFree(ssl_state); - - return; -} - -static void SSLStateTransactionFree(void *state, uint64_t tx_id) -{ - /* do nothing */ -} - -static AppProto SSLProbingParser(Flow *f, uint8_t direction, - const uint8_t *input, uint32_t ilen, uint8_t *rdir) -{ - /* probably a rst/fin sending an eof */ - if (ilen < 3) - return ALPROTO_UNKNOWN; - - /* for now just the 3 byte header ones */ - /* \todo Detect the 2 byte ones */ - if ((input[0] & 0x80) && (input[2] == 0x01)) { - return ALPROTO_TLS; - } - - return ALPROTO_FAILED; -} - -static int SSLStateGetFrameIdByName(const char *frame_name) -{ - int id = SCMapEnumNameToValue(frame_name, tls_frame_table); - if (id < 0) { - return -1; - } - return id; -} - -static const char *SSLStateGetFrameNameById(const uint8_t frame_id) -{ - const char *name = SCMapEnumValueToName(frame_id, tls_frame_table); - return name; -} - -static int SSLStateGetEventInfo(const char *event_name, - int *event_id, AppLayerEventType *event_type) -{ - *event_id = SCMapEnumNameToValue(event_name, tls_decoder_event_table); - if (*event_id == -1) { - SCLogError("event \"%s\" not present in " - "ssl's enum map table.", - event_name); - /* yes this is fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static int SSLStateGetEventInfoById(int event_id, const char **event_name, - AppLayerEventType *event_type) -{ - *event_name = SCMapEnumValueToName(event_id, tls_decoder_event_table); - if (*event_name == NULL) { - SCLogError("event \"%d\" not present in " - "ssl's enum map table.", - event_id); - /* yes this is fatal */ - return -1; - } - - *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; - - return 0; -} - -static int SSLRegisterPatternsForProtocolDetection(void) -{ - if (AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_TLS, "|01 00 02|", 5, 2, - STREAM_TOSERVER, SSLProbingParser, 0, 3) < 0) { - return -1; - } - - /** SSLv3 */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|01 03 00|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 00|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /** TLSv1 */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|01 03 01|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 01|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /** TLSv1.1 */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|01 03 02|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 02|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /** TLSv1.2 */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|01 03 03|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 03|", 3, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - - /***** toclient direction *****/ - - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|15 03 00|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 00|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|17 03 00|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - - /** TLSv1 */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|15 03 01|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 01|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|17 03 01|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - - /** TLSv1.1 */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|15 03 02|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 02|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|17 03 02|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - - /** TLSv1.2 */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|15 03 03|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|16 03 03|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|17 03 03|", 3, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - - /* Subsection - SSLv2 style record by client, but informing the server - * the max version it supports. - * Updated by Anoop Saldanha. Disabled it for now. We'll get back to - * it after some tests */ -#if 0 - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|01 03 00|", 5, 2, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, - "|00 02|", 7, 5, STREAM_TOCLIENT) < 0) - { - return -1; - } -#endif - - return 0; -} - -/** - * \brief Function to register the SSL protocol parser and other functions - */ -void RegisterSSLParsers(void) -{ - const char *proto_name = "tls"; - - SC_ATOMIC_INIT(ssl_config.enable_ja3); - - /** SSLv2 and SSLv23*/ - if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { - AppLayerProtoDetectRegisterProtocol(ALPROTO_TLS, proto_name); - - if (SSLRegisterPatternsForProtocolDetection() < 0) - return; - - if (RunmodeIsUnittests()) { - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "443", - ALPROTO_TLS, - 0, 3, - STREAM_TOSERVER, - SSLProbingParser, NULL); - } else { - if (AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, - proto_name, ALPROTO_TLS, - 0, 3, - SSLProbingParser, NULL) == 0) { - SCLogConfig("no TLS config found, " - "enabling TLS detection on port 443."); - AppLayerProtoDetectPPRegister(IPPROTO_TCP, - "443", - ALPROTO_TLS, - 0, 3, - STREAM_TOSERVER, - SSLProbingParser, NULL); - } - } - } else { - SCLogConfig("Protocol detection and parser disabled for %s protocol", - proto_name); - return; - } - - if (AppLayerParserConfParserEnabled("tcp", proto_name)) { - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER, - SSLParseClientRecord); - - AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOCLIENT, - SSLParseServerRecord); - - AppLayerParserRegisterGetFrameFuncs( - IPPROTO_TCP, ALPROTO_TLS, SSLStateGetFrameIdByName, SSLStateGetFrameNameById); - AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfo); - AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfoById); - - AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateAlloc, SSLStateFree); - - AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER); - - AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TLS, SSLStateTransactionFree); - - AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TLS, SSLGetTx); - AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxData); - AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetStateData); - - AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxCnt); - - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetAlstateProgress); - - AppLayerParserRegisterStateProgressCompletionStatus( - ALPROTO_TLS, TLS_STATE_FINISHED, TLS_STATE_FINISHED); - - ConfNode *enc_handle = ConfGetNode("app-layer.protocols.tls.encryption-handling"); - if (enc_handle != NULL && enc_handle->val != NULL) { - SCLogDebug("have app-layer.protocols.tls.encryption-handling = %s", enc_handle->val); - if (strcmp(enc_handle->val, "full") == 0) { - ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_FULL; - } else if (strcmp(enc_handle->val, "bypass") == 0) { - ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS; - } else if (strcmp(enc_handle->val, "default") == 0) { - ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_DEFAULT; - } else { - ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_DEFAULT; - } - } else { - /* Get the value of no reassembly option from the config file */ - if (ConfGetNode("app-layer.protocols.tls.no-reassemble") == NULL) { - int value = 0; - if (ConfGetBool("tls.no-reassemble", &value) == 1 && value == 1) - ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS; - } else { - int value = 0; - if (ConfGetBool("app-layer.protocols.tls.no-reassemble", &value) == 1 && value == 1) - ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS; - } - } - SCLogDebug("ssl_config.encrypt_mode %u", ssl_config.encrypt_mode); - - /* Check if we should generate JA3 fingerprints */ - int enable_ja3 = SSL_CONFIG_DEFAULT_JA3; - const char *strval = NULL; - if (ConfGet("app-layer.protocols.tls.ja3-fingerprints", &strval) != 1) { - enable_ja3 = SSL_CONFIG_DEFAULT_JA3; - } else if (strcmp(strval, "auto") == 0) { - enable_ja3 = SSL_CONFIG_DEFAULT_JA3; - } else if (ConfValIsFalse(strval)) { - enable_ja3 = 0; - ssl_config.disable_ja3 = true; - } else if (ConfValIsTrue(strval)) { - enable_ja3 = true; - } - SC_ATOMIC_SET(ssl_config.enable_ja3, enable_ja3); - - if (g_disable_hashing) { - if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { - SCLogWarning("MD5 calculation has been disabled, disabling JA3"); - SC_ATOMIC_SET(ssl_config.enable_ja3, 0); - } - } else { - if (RunmodeIsUnittests()) { - SC_ATOMIC_SET(ssl_config.enable_ja3, 1); - } - } - } else { - SCLogConfig("Parsed disabled for %s protocol. Protocol detection" - "still on.", proto_name); - } - - return; -} - -/** - * \brief if not explicitly disabled in config, enable ja3 support - * - * Implemented using atomic to allow rule reloads to do this at - * runtime. - */ -void SSLEnableJA3(void) -{ - if (g_disable_hashing || ssl_config.disable_ja3) { - return; - } - if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { - return; - } - SC_ATOMIC_SET(ssl_config.enable_ja3, 1); -} - -bool SSLJA3IsEnabled(void) -{ - if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { - return true; - } - return false; -} diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h deleted file mode 100644 index f2e42622308e..000000000000 --- a/src/app-layer-ssl.h +++ /dev/null @@ -1,311 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * \author Pierre Chifflier - * - */ - -#ifndef __APP_LAYER_SSL_H__ -#define __APP_LAYER_SSL_H__ - -#include "util-ja3.h" -#include "rust.h" - -enum TlsFrameTypes { - TLS_FRAME_PDU = 0, /**< whole PDU, so header + data */ - TLS_FRAME_HDR, /**< only header portion */ - TLS_FRAME_DATA, /**< only data portion */ - TLS_FRAME_ALERT_DATA, - TLS_FRAME_HB_DATA, - TLS_FRAME_SSLV2_HDR, - TLS_FRAME_SSLV2_PDU, -}; - -enum { - /* TLS protocol messages */ - TLS_DECODER_EVENT_INVALID_SSLV2_HEADER, - TLS_DECODER_EVENT_INVALID_TLS_HEADER, - TLS_DECODER_EVENT_INVALID_RECORD_VERSION, - TLS_DECODER_EVENT_INVALID_RECORD_TYPE, - TLS_DECODER_EVENT_INVALID_RECORD_LENGTH, - TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE, - TLS_DECODER_EVENT_HEARTBEAT, - TLS_DECODER_EVENT_INVALID_HEARTBEAT, - TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT, - TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH, - TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH, - TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS, - TLS_DECODER_EVENT_INVALID_SNI_TYPE, - TLS_DECODER_EVENT_INVALID_SNI_LENGTH, - TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET, - /* Certificates decoding messages */ - TLS_DECODER_EVENT_INVALID_CERTIFICATE, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY, - TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED, - TLS_DECODER_EVENT_INVALID_SSL_RECORD, -}; - -enum { - TLS_STATE_IN_PROGRESS = 0, - TLS_STATE_CERT_READY = 1, - TLS_HANDSHAKE_DONE = 2, - TLS_STATE_FINISHED = 3 -}; - -/* Flag to indicate that server will now on send encrypted msgs */ -#define SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC BIT_U32(0) -/* Flag to indicate that client will now on send encrypted msgs */ -#define SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC BIT_U32(1) -#define SSL_AL_FLAG_CHANGE_CIPHER_SPEC BIT_U32(2) - -/* SSL related flags */ -#define SSL_AL_FLAG_SSL_CLIENT_HS BIT_U32(3) -#define SSL_AL_FLAG_SSL_SERVER_HS BIT_U32(4) -#define SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY BIT_U32(5) -#define SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED BIT_U32(6) -#define SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED BIT_U32(7) -#define SSL_AL_FLAG_SSL_NO_SESSION_ID BIT_U32(8) - -/* flags specific to detect-ssl-state keyword */ -#define SSL_AL_FLAG_STATE_CLIENT_HELLO BIT_U32(9) -#define SSL_AL_FLAG_STATE_SERVER_HELLO BIT_U32(10) -#define SSL_AL_FLAG_STATE_CLIENT_KEYX BIT_U32(11) -#define SSL_AL_FLAG_STATE_SERVER_KEYX BIT_U32(12) -#define SSL_AL_FLAG_STATE_UNKNOWN BIT_U32(13) - -/* flag to indicate that session is finished */ -#define SSL_AL_FLAG_STATE_FINISHED BIT_U32(14) - -/* flags specific to HeartBeat state */ -#define SSL_AL_FLAG_HB_INFLIGHT BIT_U32(15) -#define SSL_AL_FLAG_HB_CLIENT_INIT BIT_U32(16) -#define SSL_AL_FLAG_HB_SERVER_INIT BIT_U32(17) - -/* flag to indicate that handshake is done */ -#define SSL_AL_FLAG_HANDSHAKE_DONE BIT_U32(18) - -/* Session resumed without a full handshake */ -#define SSL_AL_FLAG_SESSION_RESUMED BIT_U32(20) - -/* Encountered a supported_versions extension in client hello */ -#define SSL_AL_FLAG_CH_VERSION_EXTENSION BIT_U32(21) - -/* Log the session even without ever seeing a certificate. This is used - to log TLSv1.3 sessions. */ -#define SSL_AL_FLAG_LOG_WITHOUT_CERT BIT_U32(22) - -/* Encountered a early data extension in client hello. This extension is - used by 0-RTT. */ -#define SSL_AL_FLAG_EARLY_DATA BIT_U32(23) - -/* flag to indicate that server random was filled */ -#define TLS_TS_RANDOM_SET BIT_U32(24) - -/* flag to indicate that client random was filled */ -#define TLS_TC_RANDOM_SET BIT_U32(25) - -#define SSL_AL_FLAG_NEED_CLIENT_CERT BIT_U32(26) - -/* config flags */ -#define SSL_TLS_LOG_PEM (1 << 0) - -/* extensions */ -#define SSL_EXTENSION_SNI 0x0000 -#define SSL_EXTENSION_ELLIPTIC_CURVES 0x000a -#define SSL_EXTENSION_EC_POINT_FORMATS 0x000b -#define SSL_EXTENSION_SESSION_TICKET 0x0023 -#define SSL_EXTENSION_EARLY_DATA 0x002a -#define SSL_EXTENSION_SUPPORTED_VERSIONS 0x002b - -/* SNI types */ -#define SSL_SNI_TYPE_HOST_NAME 0 - -/* Max string length of the TLS version string */ -#define SSL_VERSION_MAX_STRLEN 20 - -/* TLS random bytes for the sticky buffer */ -#define TLS_RANDOM_LEN 32 - -/* SSL versions. We'll use a unified format for all, with the top byte - * holding the major version and the lower byte the minor version */ -enum { - TLS_VERSION_UNKNOWN = 0x0000, - SSL_VERSION_2 = 0x0200, - SSL_VERSION_3 = 0x0300, - TLS_VERSION_10 = 0x0301, - TLS_VERSION_11 = 0x0302, - TLS_VERSION_12 = 0x0303, - TLS_VERSION_13 = 0x0304, - TLS_VERSION_13_DRAFT28 = 0x7f1c, - TLS_VERSION_13_DRAFT27 = 0x7f1b, - TLS_VERSION_13_DRAFT26 = 0x7f1a, - TLS_VERSION_13_DRAFT25 = 0x7f19, - TLS_VERSION_13_DRAFT24 = 0x7f18, - TLS_VERSION_13_DRAFT23 = 0x7f17, - TLS_VERSION_13_DRAFT22 = 0x7f16, - TLS_VERSION_13_DRAFT21 = 0x7f15, - TLS_VERSION_13_DRAFT20 = 0x7f14, - TLS_VERSION_13_DRAFT19 = 0x7f13, - TLS_VERSION_13_DRAFT18 = 0x7f12, - TLS_VERSION_13_DRAFT17 = 0x7f11, - TLS_VERSION_13_DRAFT16 = 0x7f10, - TLS_VERSION_13_PRE_DRAFT16 = 0x7f01, - TLS_VERSION_13_DRAFT20_FB = 0xfb14, - TLS_VERSION_13_DRAFT21_FB = 0xfb15, - TLS_VERSION_13_DRAFT22_FB = 0xfb16, - TLS_VERSION_13_DRAFT23_FB = 0xfb17, - TLS_VERSION_13_DRAFT26_FB = 0xfb1a, -}; - -static inline bool TLSVersionValid(const uint16_t version) -{ - switch (version) { - case TLS_VERSION_13: - case TLS_VERSION_12: - case TLS_VERSION_11: - case TLS_VERSION_10: - case SSL_VERSION_3: - - case TLS_VERSION_13_DRAFT28: - case TLS_VERSION_13_DRAFT27: - case TLS_VERSION_13_DRAFT26: - case TLS_VERSION_13_DRAFT25: - case TLS_VERSION_13_DRAFT24: - case TLS_VERSION_13_DRAFT23: - case TLS_VERSION_13_DRAFT22: - case TLS_VERSION_13_DRAFT21: - case TLS_VERSION_13_DRAFT20: - case TLS_VERSION_13_DRAFT19: - case TLS_VERSION_13_DRAFT18: - case TLS_VERSION_13_DRAFT17: - case TLS_VERSION_13_DRAFT16: - case TLS_VERSION_13_PRE_DRAFT16: - case TLS_VERSION_13_DRAFT20_FB: - case TLS_VERSION_13_DRAFT21_FB: - case TLS_VERSION_13_DRAFT22_FB: - case TLS_VERSION_13_DRAFT23_FB: - case TLS_VERSION_13_DRAFT26_FB: - return true; - } - return false; -} - -typedef struct SSLCertsChain_ { - uint8_t *cert_data; - uint32_t cert_len; - TAILQ_ENTRY(SSLCertsChain_) next; -} SSLCertsChain; - - -typedef struct SSLStateConnp_ { - /* record length */ - uint32_t record_length; - /* record length's length for SSLv2 */ - uint32_t record_lengths_length; - - /* offset of the beginning of the current message (including header) */ - uint32_t message_length; - - uint16_t version; - uint8_t content_type; - - uint8_t handshake_type; - - /* the no of bytes processed in the currently parsed record */ - uint32_t bytes_processed; - - uint16_t session_id_length; - - uint8_t random[TLS_RANDOM_LEN]; - char *cert0_subject; - char *cert0_issuerdn; - char *cert0_serial; - int64_t cert0_not_before; - int64_t cert0_not_after; - char *cert0_fingerprint; - - /* ssl server name indication extension */ - char *sni; - - char *session_id; - - TAILQ_HEAD(, SSLCertsChain_) certs; - - uint8_t *certs_buffer; - uint32_t certs_buffer_size; - - uint32_t cert_log_flag; - - JA3Buffer *ja3_str; - char *ja3_hash; - - /* handshake tls fragmentation buffer. Handshake messages can be fragmented over multiple - * TLS records. */ - uint8_t *hs_buffer; - uint8_t hs_buffer_message_type; - uint32_t hs_buffer_message_size; - uint32_t hs_buffer_size; /**< allocation size */ - uint32_t hs_buffer_offset; /**< write offset */ -} SSLStateConnp; - -/** - * \brief SSLv[2.0|3.[0|1|2|3]] state structure. - * - * Structure to store the SSL state values. - */ -typedef struct SSLState_ { - Flow *f; - - AppLayerStateData state_data; - AppLayerTxData tx_data; - - /* holds some state flags we need */ - uint32_t flags; - - /* there might be a better place to store this*/ - uint32_t hb_record_len; - - uint16_t events; - - uint32_t current_flags; - - SSLStateConnp *curr_connp; - - SSLStateConnp client_connp; - SSLStateConnp server_connp; -} SSLState; - -void RegisterSSLParsers(void); -void SSLVersionToString(uint16_t, char *); -void SSLEnableJA3(void); -bool SSLJA3IsEnabled(void); - -#endif /* __APP_LAYER_SSL_H__ */ diff --git a/src/app-layer-tftp.c b/src/app-layer-tftp.c deleted file mode 100644 index 73dc52a59eac..000000000000 --- a/src/app-layer-tftp.c +++ /dev/null @@ -1,242 +0,0 @@ -/* Copyright (C) 2017-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -/** - * \file - * - * \author Clément Galland - * - * Parser for NTP application layer running on UDP port 69. - */ - - -#include "suricata-common.h" -#include "suricata.h" -#include "stream.h" -#include "conf.h" - -#include "util-unittest.h" - -#include "app-layer.h" -#include "app-layer-detect-proto.h" -#include "app-layer-parser.h" - -#include "app-layer-tftp.h" -#include "rust.h" - -/* The default port to probe if not provided in the configuration file. */ -#define TFTP_DEFAULT_PORT "69" - -/* The minimum size for an message. For some protocols this might - * be the size of a header. */ -#define TFTP_MIN_FRAME_LEN 4 - -static void *TFTPStateAlloc(void *orig_state, AppProto proto_orig) -{ - return rs_tftp_state_alloc(); -} - -static void TFTPStateFree(void *state) -{ - rs_tftp_state_free(state); -} - -/** - * \brief Callback from the application layer to have a transaction freed. - * - * \param state a void pointer to the TFTPState object. - * \param tx_id the transaction ID to free. - */ -static void TFTPStateTxFree(void *state, uint64_t tx_id) -{ - rs_tftp_state_tx_free(state, tx_id); -} - -static int TFTPStateGetEventInfo(const char *event_name, int *event_id, - AppLayerEventType *event_type) -{ - return -1; -} - -/** - * \brief Probe the input to see if it looks like tftp. - * - * \retval ALPROTO_TFTP if it looks like tftp, otherwise - * ALPROTO_UNKNOWN. - */ -static AppProto TFTPProbingParser(Flow *f, uint8_t direction, - const uint8_t *input, uint32_t input_len, uint8_t *rdir) -{ - /* Very simple test - if there is input, this is tftp. - * Also check if it's starting by a zero */ - if (input_len >= TFTP_MIN_FRAME_LEN && *input == 0) { - SCLogDebug("Detected as ALPROTO_TFTP."); - return ALPROTO_TFTP; - } - - SCLogDebug("Protocol not detected as ALPROTO_TFTP."); - return ALPROTO_UNKNOWN; -} - -static AppLayerResult TFTPParseRequest(Flow *f, void *state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - const uint8_t *input = StreamSliceGetData(&stream_slice); - uint32_t input_len = StreamSliceGetDataLen(&stream_slice); - - SCLogDebug("Parsing tftp request: len=%" PRIu32, input_len); - - /* Likely connection closed, we can just return here. */ - if ((input == NULL || input_len == 0) && - AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) { - SCReturnStruct(APP_LAYER_OK); - } - - /* Probably don't want to create a transaction in this case - * either. */ - if (input == NULL || input_len == 0) { - SCReturnStruct(APP_LAYER_OK); - } - - int res = rs_tftp_request(state, input, input_len); - if (res < 0) { - SCReturnStruct(APP_LAYER_ERROR); - } - SCReturnStruct(APP_LAYER_OK); -} - -/** - * \brief Response parsing is not implemented - */ -static AppLayerResult TFTPParseResponse(Flow *f, void *state, AppLayerParserState *pstate, - StreamSlice stream_slice, void *local_data) -{ - SCReturnStruct(APP_LAYER_OK); -} - -static uint64_t TFTPGetTxCnt(void *state) -{ - return rs_tftp_get_tx_cnt(state); -} - -static void *TFTPGetTx(void *state, uint64_t tx_id) -{ - return rs_tftp_get_tx(state, tx_id); -} - -/** - * \brief Return the state of a transaction in a given direction. - * - * In the case of the tftp protocol, the existence of a transaction - * means that the request is done. However, some protocols that may - * need multiple chunks of data to complete the request may need more - * than just the existence of a transaction for the request to be - * considered complete. - * - * For the response to be considered done, the response for a request - * needs to be seen. The response_done flag is set on response for - * checking here. - */ -static int TFTPGetStateProgress(void *tx, uint8_t direction) -{ - return 1; -} - -void RegisterTFTPParsers(void) -{ - const char *proto_name = "tftp"; - - /* Check if TFTP UDP detection is enabled. If it does not exist in - * the configuration file then it will be enabled by default. */ - if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) { - - SCLogDebug("TFTP UDP protocol detection enabled."); - - AppLayerProtoDetectRegisterProtocol(ALPROTO_TFTP, proto_name); - - if (RunmodeIsUnittests()) { - SCLogDebug("Unittest mode, registering default configuration."); - AppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT, - ALPROTO_TFTP, 0, TFTP_MIN_FRAME_LEN, - STREAM_TOSERVER, TFTPProbingParser, - TFTPProbingParser); - } else { - if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, - proto_name, ALPROTO_TFTP, - 0, TFTP_MIN_FRAME_LEN, - TFTPProbingParser, TFTPProbingParser)) { - SCLogDebug("No tftp app-layer configuration, enabling tftp" - " detection UDP detection on port %s.", - TFTP_DEFAULT_PORT); - AppLayerProtoDetectPPRegister(IPPROTO_UDP, - TFTP_DEFAULT_PORT, ALPROTO_TFTP, - 0, TFTP_MIN_FRAME_LEN, - STREAM_TOSERVER,TFTPProbingParser, - TFTPProbingParser); - } - } - } else { - SCLogDebug("Protocol detector and parser disabled for TFTP."); - return; - } - - if (AppLayerParserConfParserEnabled("udp", proto_name)) { - - SCLogDebug("Registering TFTP protocol parser."); - - /* Register functions for state allocation and freeing. A - * state is allocated for every new TFTP flow. */ - AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_TFTP, - TFTPStateAlloc, TFTPStateFree); - - /* Register request parser for parsing frame from server to client. */ - AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP, - STREAM_TOSERVER, TFTPParseRequest); - - /* Register response parser for parsing frames from server to client. */ - AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP, - STREAM_TOCLIENT, TFTPParseResponse); - - /* Register a function to be called by the application layer - * when a transaction is to be freed. */ - AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_TFTP, - TFTPStateTxFree); - - /* Register a function to return the current transaction count. */ - AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_TFTP, - TFTPGetTxCnt); - - /* Transaction handling. */ - AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_TFTP, 1, 1); - AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, - ALPROTO_TFTP, - TFTPGetStateProgress); - AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_TFTP, - TFTPGetTx); - - AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_TFTP, - TFTPStateGetEventInfo); - - AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_TFTP, - rs_tftp_get_tx_data); - AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_TFTP, rs_tftp_get_state_data); - } - else { - SCLogDebug("TFTP protocol parsing disabled."); - } -} diff --git a/src/app-layer-tftp.h b/src/app-layer-tftp.h deleted file mode 100644 index 65dd8f4c9bbd..000000000000 --- a/src/app-layer-tftp.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Clément Galland - */ - -#ifndef __APP_LAYER_TFTP_H__ -#define __APP_LAYER_TFTP_H__ - -void RegisterTFTPParsers(void); - -/** Opaque Rust types. */ -typedef struct TFTPState_ TFTPState; -typedef struct TFTPTransaction_ TFTPTransaction; - -#endif /* __APP_LAYER_TFTP_H__ */ diff --git a/src/app-layer.c b/src/app-layer.c index 3625e87e9ed6..b394b823ad21 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -30,7 +30,7 @@ #include "app-layer-parser.h" #include "app-layer-protos.h" #include "app-layer-expectation.h" -#include "app-layer-ftp.h" +#include "app-layer/ftp/parser.h" #include "app-layer-detect-proto.h" #include "app-layer-frames.h" #include "stream-tcp-reassemble.h" @@ -41,13 +41,13 @@ #include "flow-util.h" #include "flow-private.h" #include "ippair.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/profiling.h" +#include "util/validate.h" #include "decode-events.h" -#include "app-layer-htp-mem.h" -#include "util-exception-policy.h" +#include "app-layer/http/parser-mem.h" +#include "util/exception-policy.h" /** * \brief This is for the app layer in general and it contains per thread @@ -101,7 +101,8 @@ void AppLayerDeSetupCounters(void); /***** L7 layer dispatchers *****/ -static inline int ProtoDetectDone(const Flow *f, const TcpSession *ssn, uint8_t direction) { +static inline int ProtoDetectDone(const Flow *f, const TcpSession *ssn, uint8_t direction) +{ const TcpStream *stream = (direction & STREAM_TOSERVER) ? &ssn->client : &ssn->server; return ((stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) || (FLOW_IS_PM_DONE(f, direction) && FLOW_IS_PP_DONE(f, direction))); @@ -194,8 +195,8 @@ static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t flags) static void DisableAppLayer(ThreadVars *tv, Flow *f, Packet *p) { - SCLogDebug("disable app layer for flow %p alproto %u ts %u tc %u", - f, f->alproto, f->alproto_ts, f->alproto_tc); + SCLogDebug("disable app layer for flow %p alproto %u ts %u tc %u", f, f->alproto, f->alproto_ts, + f->alproto_tc); FlowCleanupAppLayer(f); StreamTcpDisableAppLayer(f); TcpSession *ssn = f->protoctx; @@ -215,8 +216,8 @@ static void DisableAppLayer(ThreadVars *tv, Flow *f, Packet *p) } FlagPacketFlow(p, f, STREAM_TOSERVER); } - SCLogDebug("disabled app layer for flow %p alproto %u ts %u tc %u", - f, f->alproto, f->alproto_ts, f->alproto_tc); + SCLogDebug("disabled app layer for flow %p alproto %u ts %u tc %u", f, f->alproto, + f->alproto_ts, f->alproto_tc); } /* See if we're going to have to give up: @@ -238,8 +239,7 @@ static void DisableAppLayer(ThreadVars *tv, Flow *f, Packet *p) * * Giving up means we disable applayer an set an applayer event */ -static void TCPProtoDetectCheckBailConditions(ThreadVars *tv, - Flow *f, TcpSession *ssn, Packet *p) +static void TCPProtoDetectCheckBailConditions(ThreadVars *tv, Flow *f, TcpSession *ssn, Packet *p) { if (ssn->state < TCP_ESTABLISHED) { SCLogDebug("skip as long as TCP is not ESTABLISHED (TCP fast open)"); @@ -257,9 +257,7 @@ static void TCPProtoDetectCheckBailConditions(ThreadVars *tv, const uint32_t size_ts_limit = MAX(100000, MIN(ssn->server.window, stream_config.reassembly_depth)); - if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && - ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) - { + if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) { goto failure; /* we bail out whatever the pp and pm states if @@ -270,34 +268,30 @@ static void TCPProtoDetectCheckBailConditions(ThreadVars *tv, } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && size_ts > size_ts_limit && size_tc == 0) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); goto failure; } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && size_tc > size_tc_limit && size_ts == 0) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); goto failure; - /* little data in ts direction, pp done, pm not done (max - * depth not reached), ts direction done, lots of data in - * tc direction. */ + /* little data in ts direction, pp done, pm not done (max + * depth not reached), ts direction done, lots of data in + * tc direction. */ } else if (size_tc > size_tc_limit && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); goto failure; - /* little data in tc direction, pp done, pm not done (max - * depth not reached), tc direction done, lots of data in - * ts direction. */ + /* little data in tc direction, pp done, pm not done (max + * depth not reached), tc direction done, lots of data in + * ts direction. */ } else if (size_ts > size_ts_limit && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); goto failure; } return; @@ -324,11 +318,8 @@ static int TCPProtoDetectTriggerOpposingSide(ThreadVars *tv, TcpReassemblyThread return -1; } - enum StreamUpdateDir dir = StreamTcpInlineMode() ? - UPDATE_DIR_OPPOSING : - UPDATE_DIR_PACKET; - int ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, - opposing_stream, p, dir); + enum StreamUpdateDir dir = StreamTcpInlineMode() ? UPDATE_DIR_OPPOSING : UPDATE_DIR_PACKET; + int ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, opposing_stream, p, dir); return ret; } @@ -368,16 +359,15 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, bool reverse_flow = false; DEBUG_VALIDATE_BUG_ON(data == NULL && data_len > 0); PACKET_PROFILING_APP_PD_START(app_tctx); - *alproto = AppLayerProtoDetectGetProto(app_tctx->alpd_tctx, - f, data, data_len, - IPPROTO_TCP, flags, &reverse_flow); + *alproto = AppLayerProtoDetectGetProto( + app_tctx->alpd_tctx, f, data, data_len, IPPROTO_TCP, flags, &reverse_flow); PACKET_PROFILING_APP_PD_END(app_tctx); SCLogDebug("alproto %u rev %s", *alproto, reverse_flow ? "true" : "false"); if (*alproto != ALPROTO_UNKNOWN) { if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != *alproto) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); + AppLayerDecoderEventsSetEventRaw( + &p->app_layer_events, APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); if (ssn->data_first_seen_dir == APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { /* if we already invoked the parser, we go with that proto */ @@ -395,8 +385,7 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, } StreamTcpSetStreamFlagAppProtoDetectionCompleted(*stream); - TcpSessionSetReassemblyDepth(ssn, - AppLayerParserGetStreamDepth(f)); + TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f)); FlagPacketFlow(p, f, flags); /* if protocol detection indicated that we need to reverse @@ -435,14 +424,11 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * called by the very same StreamReassembly() function that we * will now call shortly for the opposing direction. */ if ((ssn->data_first_seen_dir & (STREAM_TOSERVER | STREAM_TOCLIENT)) && - !(flags & ssn->data_first_seen_dir)) - { - SCLogDebug("protocol %s needs first data in other direction", - AppProtoToString(*alproto)); - - if (TCPProtoDetectTriggerOpposingSide(tv, ra_ctx, - p, ssn, *stream) != 0) - { + !(flags & ssn->data_first_seen_dir)) { + SCLogDebug( + "protocol %s needs first data in other direction", AppProtoToString(*alproto)); + + if (TCPProtoDetectTriggerOpposingSide(tv, ra_ctx, p, ssn, *stream) != 0) { goto detect_error; } if (FlowChangeProto(f)) { @@ -451,8 +437,8 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * As the second data was recognized as P1, the protocol did not change ! */ FlowUnsetChangeProtoFlag(f); - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_UNEXPECTED_PROTOCOL); + AppLayerDecoderEventsSetEventRaw( + &p->app_layer_events, APPLAYER_UNEXPECTED_PROTOCOL); } } @@ -477,8 +463,8 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, first_data_dir = AppLayerParserGetFirstDataDir(f->proto, f->alproto); if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_WRONG_DIRECTION_FIRST_DATA); + AppLayerDecoderEventsSetEventRaw( + &p->app_layer_events, APPLAYER_WRONG_DIRECTION_FIRST_DATA); goto detect_error; } /* This can happen if the current direction is not the @@ -503,8 +489,7 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* finally, invoke the parser */ PACKET_PROFILING_APP_START(app_tctx, f->alproto); - int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, - flags, data, data_len); + int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, flags, data, data_len); PACKET_PROFILING_APP_END(app_tctx, f->alproto); p->app_update_direction = (uint8_t)dir; if (r != 1) { @@ -529,8 +514,7 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * detection and parsing is possible. So we give up. */ if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) && - !(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) - { + !(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) { if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { SCLogDebug("midstream end pd %p", ssn); /* midstream and toserver detection failed: give up */ @@ -559,8 +543,7 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * acceptable direction we error out. */ if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && - (first_data_dir) && !(first_data_dir & flags)) - { + (first_data_dir) && !(first_data_dir & flags)) { goto detect_error; } @@ -576,22 +559,21 @@ static int TCPProtoDetect(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (*alproto_otherdir != ALPROTO_FAILED) { PACKET_PROFILING_APP_START(app_tctx, f->alproto); - int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, - f->alproto, flags, - data, data_len); + int r = AppLayerParserParse( + tv, app_tctx->alp_tctx, f, f->alproto, flags, data, data_len); PACKET_PROFILING_APP_END(app_tctx, f->alproto); p->app_update_direction = (uint8_t)dir; if (r != 1) { StreamTcpUpdateAppLayerProgress(ssn, direction, data_len); } - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); - TcpSessionSetReassemblyDepth(ssn, - AppLayerParserGetStreamDepth(f)); + AppLayerDecoderEventsSetEventRaw( + &p->app_layer_events, APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); + TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f)); *alproto = *alproto_otherdir; - SCLogDebug("packet %"PRIu64": pd done(us %u them %u), parser called (r==%d), APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION set", + SCLogDebug("packet %" PRIu64 ": pd done(us %u them %u), parser called (r==%d), " + "APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION set", p->pcap_cnt, *alproto, *alproto_otherdir, r); if (r < 0) { goto parser_error; @@ -685,8 +667,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet goto failure; } PACKET_PROFILING_APP_START(app_tctx, f->alproto); - r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, - flags, data, data_len); + r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, flags, data, data_len); PACKET_PROFILING_APP_END(app_tctx, f->alproto); p->app_update_direction = (uint8_t)dir; /* ignore parser result for gap */ @@ -740,28 +721,27 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet SCLogDebug("proto detect failure"); goto failure; } - SCLogDebug("protocol change, old %s, new %s", - AppProtoToString(f->alproto_orig), AppProtoToString(f->alproto)); + SCLogDebug("protocol change, old %s, new %s", AppProtoToString(f->alproto_orig), + AppProtoToString(f->alproto)); if (f->alproto_expect != ALPROTO_UNKNOWN && f->alproto != ALPROTO_UNKNOWN && f->alproto != f->alproto_expect) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_UNEXPECTED_PROTOCOL); + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_UNEXPECTED_PROTOCOL); if (f->alproto_expect == ALPROTO_TLS && f->alproto != ALPROTO_TLS) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_NO_TLS_AFTER_STARTTLS); - + AppLayerDecoderEventsSetEventRaw( + &p->app_layer_events, APPLAYER_NO_TLS_AFTER_STARTTLS); } } } else { SCLogDebug("stream data (len %" PRIu32 " alproto " - "%"PRIu16" (flow %p)", data_len, f->alproto, f); + "%" PRIu16 " (flow %p)", + data_len, f->alproto, f); #ifdef PRINT if (data_len > 0) { printf("=> Stream Data (app layer) -- start %s%s\n", - flags & STREAM_TOCLIENT ? "toclient" : "", - flags & STREAM_TOSERVER ? "toserver" : ""); + flags & STREAM_TOCLIENT ? "toclient" : "", + flags & STREAM_TOSERVER ? "toserver" : ""); PrintRawDataFp(stdout, data, data_len); printf("=> Stream Data -- end\n"); } @@ -770,8 +750,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet * a start msg should have gotten us one */ if (f->alproto != ALPROTO_UNKNOWN) { PACKET_PROFILING_APP_START(app_tctx, f->alproto); - r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, - flags, data, data_len); + r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, flags, data, data_len); PACKET_PROFILING_APP_END(app_tctx, f->alproto); p->app_update_direction = (uint8_t)dir; if (r != 1) { @@ -786,9 +765,9 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet } goto end; - failure: +failure: r = -1; - end: +end: SCReturnInt(r); } @@ -830,8 +809,7 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * /* if the protocol is still unknown, run detection */ if (*alproto == ALPROTO_UNKNOWN) { - SCLogDebug("Detecting AL proto on udp mesg (len %" PRIu32 ")", - p->payload_len); + SCLogDebug("Detecting AL proto on udp mesg (len %" PRIu32 ")", p->payload_len); bool reverse_flow = false; PACKET_PROFILING_APP_PD_START(tctx); @@ -895,8 +873,8 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * } PACKET_PROFILING_APP_START(tctx, f->alproto); - r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, - flags, p->payload, p->payload_len); + r = AppLayerParserParse( + tv, tctx->alp_tctx, f, f->alproto, flags, p->payload, p->payload_len); PACKET_PROFILING_APP_END(tctx, f->alproto); p->app_update_direction = (uint8_t)UPDATE_DIR_PACKET; } @@ -907,12 +885,13 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * FlagPacketFlow(p, f, STREAM_TOCLIENT); } else { SCLogDebug("data (len %" PRIu32 " ), alproto " - "%"PRIu16" (flow %p)", p->payload_len, f->alproto, f); + "%" PRIu16 " (flow %p)", + p->payload_len, f->alproto, f); /* run the parser */ PACKET_PROFILING_APP_START(tctx, f->alproto); - r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, - flags, p->payload, p->payload_len); + r = AppLayerParserParse( + tv, tctx->alp_tctx, f, f->alproto, flags, p->payload, p->payload_len); PACKET_PROFILING_APP_END(tctx, f->alproto); PACKET_PROFILING_APP_STORE(tctx, p); p->app_update_direction = (uint8_t)UPDATE_DIR_PACKET; @@ -937,7 +916,7 @@ AppProto AppLayerGetProtoByName(char *alproto_name) const char *AppLayerGetProtoName(AppProto alproto) { SCEnter(); - const char * r = AppLayerProtoDetectGetProtoName(alproto); + const char *r = AppLayerProtoDetectGetProtoName(alproto); SCReturnCT(r, "char *"); } @@ -1002,10 +981,10 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv) goto error; goto done; - error: +error: AppLayerDestroyCtxThread(app_tctx); app_tctx = NULL; - done: +done: SCReturnPtr(app_tctx, "void *"); } @@ -1072,11 +1051,11 @@ void AppLayerSetupCounters(void) if (AppLayerParserProtoIsRegistered(ipproto, alproto) && AppLayerParserProtoIsRegistered(other_ipproto, alproto)) { snprintf(applayer_counter_names[ipproto_map][alproto].name, - sizeof(applayer_counter_names[ipproto_map][alproto].name), - "%s%s%s", str, alproto_str, ipproto_suffix); + 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); + sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), "%s%s%s", + tx_str, alproto_str, ipproto_suffix); if (ipproto == IPPROTO_TCP) { snprintf(applayer_counter_names[ipproto_map][alproto].gap_error, @@ -1094,11 +1073,11 @@ void AppLayerSetupCounters(void) "%s%s%s.internal", estr, 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); + 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); + sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), "%s%s", + tx_str, alproto_str); if (ipproto == IPPROTO_TCP) { snprintf(applayer_counter_names[ipproto_map][alproto].gap_error, @@ -1117,8 +1096,8 @@ void AppLayerSetupCounters(void) } } 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); + sizeof(applayer_counter_names[ipproto_map][alproto].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), @@ -1142,10 +1121,10 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { if (alprotos[alproto] == 1) { applayer_counters[ipproto_map][alproto].counter_id = - StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); - applayer_counters[ipproto_map][alproto].counter_tx_id = - StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].tx_name, tv); + applayer_counters[ipproto_map][alproto].counter_tx_id = StatsRegisterCounter( + applayer_counter_names[ipproto_map][alproto].tx_name, tv); if (ipproto == IPPROTO_TCP) { applayer_counters[ipproto_map][alproto].gap_error_id = StatsRegisterCounter( @@ -1159,7 +1138,7 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) applayer_counter_names[ipproto_map][alproto].internal_error, tv); } else if (alproto == ALPROTO_FAILED) { applayer_counters[ipproto_map][alproto].counter_id = - StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); if (ipproto == IPPROTO_TCP) { applayer_counters[ipproto_map][alproto].gap_error_id = StatsRegisterCounter( @@ -1182,7 +1161,7 @@ void AppLayerDeSetupCounters(void) #include "pkt-var.h" #include "stream-tcp-util.h" #include "stream.h" -#include "util-unittest.h" +#include "util/unittest.h" #define TEST_START \ Packet *p = PacketGetFromAlloc(); \ @@ -1282,6 +1261,7 @@ static int AppLayerTest01(void) TEST_START; /* full request */ + // clang-format off uint8_t request[] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -1294,6 +1274,7 @@ static int AppLayerTest01(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -1314,6 +1295,7 @@ static int AppLayerTest01(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ + // clang-format off uint8_t response[] = { 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -1356,6 +1338,7 @@ static int AppLayerTest01(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -1407,7 +1390,10 @@ static int AppLayerTest02(void) TEST_START; /* partial request */ - uint8_t request1[] = { 0x47, 0x45, }; + uint8_t request1[] = { + 0x47, + 0x45, + }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -1448,6 +1434,7 @@ static int AppLayerTest02(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* complete partial request */ + // clang-format off uint8_t request2[] = { 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -1460,6 +1447,7 @@ static int AppLayerTest02(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(3); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -1480,6 +1468,7 @@ static int AppLayerTest02(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ + // clang-format off uint8_t response[] = { 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -1522,6 +1511,7 @@ static int AppLayerTest02(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -1573,6 +1563,7 @@ static int AppLayerTest03(void) TEST_START; /* request */ + // clang-format off uint8_t request[] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -1585,6 +1576,7 @@ static int AppLayerTest03(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -1605,6 +1597,7 @@ static int AppLayerTest03(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* rubbish response */ + // clang-format off uint8_t response[] = { 0x58, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -1647,6 +1640,7 @@ static int AppLayerTest03(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -1698,6 +1692,7 @@ static int AppLayerTest04(void) TEST_START; /* request */ + // clang-format off uint8_t request[] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -1710,6 +1705,7 @@ static int AppLayerTest04(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on PrintRawDataFp(stdout, request, sizeof(request)); p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); @@ -1728,10 +1724,15 @@ static int AppLayerTest04(void) FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); // TOSERVER data now seen + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); // TOSERVER data now seen /* partial response */ - uint8_t response1[] = { 0x58, 0x54, 0x54, 0x50, }; + uint8_t response1[] = { + 0x58, + 0x54, + 0x54, + 0x50, + }; PrintRawDataFp(stdout, response1, sizeof(response1)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); @@ -1750,7 +1751,8 @@ static int AppLayerTest04(void) FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer + FAIL_IF(ssn->data_first_seen_dir != + APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* partial response ack */ p->tcph->th_ack = htonl(5); @@ -1769,10 +1771,12 @@ static int AppLayerTest04(void) FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing - FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != + APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* remaining response */ + // clang-format off uint8_t response2[] = { 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -1815,6 +1819,7 @@ static int AppLayerTest04(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on PrintRawDataFp(stdout, response2, sizeof(response2)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(5); @@ -1832,8 +1837,9 @@ static int AppLayerTest04(void) FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing - FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != + APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* response ack */ p->tcph->th_ack = htonl(328); @@ -1843,17 +1849,19 @@ static int AppLayerTest04(void) p->payload_len = 0; p->payload = NULL; FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); - FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); // toclient complete (failed) + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted( + &ssn->server)); // toclient complete (failed) FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete FAIL_IF(f.alproto != ALPROTO_HTTP1); // http based on ts FAIL_IF(f.alproto_ts != ALPROTO_HTTP1); // ts complete - FAIL_IF(f.alproto_tc != ALPROTO_FAILED); // tc failed + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); // tc failed FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); - FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing - FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != + APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer TEST_END; PASS; @@ -1867,6 +1875,7 @@ static int AppLayerTest05(void) TEST_START; /* full request */ + // clang-format off uint8_t request[] = { 0x48, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -1879,6 +1888,7 @@ static int AppLayerTest05(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on PrintRawDataFp(stdout, request, sizeof(request)); p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); @@ -1900,6 +1910,7 @@ static int AppLayerTest05(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ + // clang-format off uint8_t response[] = { 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -1942,6 +1953,7 @@ static int AppLayerTest05(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on PrintRawDataFp(stdout, response, sizeof(response)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); @@ -1994,6 +2006,7 @@ static int AppLayerTest06(void) TEST_START; /* full response - request ack */ + // clang-format off uint8_t response[] = { 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -2036,6 +2049,7 @@ static int AppLayerTest06(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2056,6 +2070,7 @@ static int AppLayerTest06(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOCLIENT); /* full request - response ack*/ + // clang-format off uint8_t request[] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -2068,6 +2083,7 @@ static int AppLayerTest06(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on p->tcph->th_ack = htonl(328); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2118,6 +2134,7 @@ static int AppLayerTest07(void) TEST_START; /* full request */ + // clang-format off uint8_t request[] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -2130,6 +2147,7 @@ static int AppLayerTest07(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2150,6 +2168,7 @@ static int AppLayerTest07(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ + // clang-format off uint8_t response[] = { 0x05, 0x00, 0x4d, 0x42, 0x00, 0x01, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, 0x30, 0x36, @@ -2172,6 +2191,7 @@ static int AppLayerTest07(void) 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2223,12 +2243,14 @@ static int AppLayerTest08(void) TEST_START; /* full request */ + // clang-format off uint8_t request[] = { 0x05, 0x00, 0x54, 0x20, 0x00, 0x01, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e, 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2249,6 +2271,7 @@ static int AppLayerTest08(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ + // clang-format off uint8_t response[] = { 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -2291,6 +2314,7 @@ static int AppLayerTest08(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2344,8 +2368,10 @@ static int AppLayerTest09(void) TEST_START; /* full request */ + // clang-format off uint8_t request1[] = { 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64 }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2386,8 +2412,10 @@ static int AppLayerTest09(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full request */ + // clang-format off uint8_t request2[] = { 0x44, 0x44, 0x45, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(9); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2408,6 +2436,7 @@ static int AppLayerTest09(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ + // clang-format off uint8_t response[] = { 0x55, 0x74, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -2450,6 +2479,7 @@ static int AppLayerTest09(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2502,9 +2532,11 @@ static int AppLayerTest10(void) TEST_START; /* full request */ + // clang-format off uint8_t request1[] = { 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2545,6 +2577,7 @@ static int AppLayerTest10(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ + // clang-format off uint8_t response[] = { 0x55, 0x74, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -2587,6 +2620,7 @@ static int AppLayerTest10(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2640,9 +2674,11 @@ static int AppLayerTest11(void) TEST_START; /* full request */ + // clang-format off uint8_t request1[] = { 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2683,8 +2719,10 @@ static int AppLayerTest11(void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ + // clang-format off uint8_t response1[] = { 0x55, 0x74, 0x54, 0x50, }; + // clang-format on p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2724,6 +2762,7 @@ static int AppLayerTest11(void) FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); + // clang-format off uint8_t response2[] = { 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -2766,6 +2805,7 @@ static int AppLayerTest11(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; diff --git a/src/app-layer.h b/src/app-layer.h index cbe2fbc9af84..9179c13d58e2 100644 --- a/src/app-layer.h +++ b/src/app-layer.h @@ -34,11 +34,9 @@ #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" - #include "rust.h" -#define APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER \ - (~STREAM_TOSERVER & ~STREAM_TOCLIENT) +#define APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER (~STREAM_TOSERVER & ~STREAM_TOCLIENT) /***** L7 layer dispatchers *****/ @@ -52,8 +50,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet /** * \brief Handles an udp chunk. */ -int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *app_tctx, - Packet *p, Flow *f); +int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *app_tctx, Packet *p, Flow *f); /***** Utility *****/ diff --git a/src/app-layer/bittorrent-dht/logger.c b/src/app-layer/bittorrent-dht/logger.c new file mode 100644 index 000000000000..096dc71f9485 --- /dev/null +++ b/src/app-layer/bittorrent-dht/logger.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * Implement JSON/eve logging app-layer BitTorrent DHT. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/bittorrent-dht/logger.h" +#include "rust.h" + +typedef struct LogBitTorrentDHTFileCtx_ { + uint32_t flags; + OutputJsonCtx *eve_ctx; +} LogBitTorrentDHTFileCtx; + +typedef struct LogBitTorrentDHTLogThread_ { + LogBitTorrentDHTFileCtx *bittorrent_dht_log_ctx; + OutputJsonThreadCtx *ctx; +} LogBitTorrentDHTLogThread; + +static int JsonBitTorrentDHTLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *tx, uint64_t tx_id) +{ + LogBitTorrentDHTLogThread *thread = thread_data; + + JsonBuilder *js = CreateEveHeader( + p, LOG_DIR_PACKET, "bittorrent_dht", NULL, thread->bittorrent_dht_log_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_FAILED; + } + + if (!rs_bittorrent_dht_logger_log(tx, js)) { + goto error; + } + + OutputJsonBuilderBuffer(js, thread->ctx); + jb_free(js); + + return TM_ECODE_OK; + +error: + jb_free(js); + return TM_ECODE_FAILED; +} + +static void OutputBitTorrentDHTLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogBitTorrentDHTFileCtx *bittorrent_dht_log_ctx = (LogBitTorrentDHTFileCtx *)output_ctx->data; + SCFree(bittorrent_dht_log_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputBitTorrentDHTLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ajt = parent_ctx->data; + + LogBitTorrentDHTFileCtx *bittorrent_dht_log_ctx = SCCalloc(1, sizeof(*bittorrent_dht_log_ctx)); + if (unlikely(bittorrent_dht_log_ctx == NULL)) { + return result; + } + bittorrent_dht_log_ctx->eve_ctx = ajt; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(bittorrent_dht_log_ctx); + return result; + } + output_ctx->data = bittorrent_dht_log_ctx; + output_ctx->DeInit = OutputBitTorrentDHTLogDeInitCtxSub; + + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_BITTORRENT_DHT); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonBitTorrentDHTLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogBitTorrentDHTLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogBitTorrentDHT. \"initdata\" is NULL."); + goto error_exit; + } + + thread->bittorrent_dht_log_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->bittorrent_dht_log_ctx->eve_ctx); + if (!thread->ctx) { + goto error_exit; + } + *data = (void *)thread; + + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonBitTorrentDHTLogThreadDeinit(ThreadVars *t, void *data) +{ + LogBitTorrentDHTLogThread *thread = (LogBitTorrentDHTLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonBitTorrentDHTLogRegister(void) +{ + if (ConfGetNode("app-layer.protocols.bittorrent-dht") == NULL) { + return; + } + + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonBitTorrentDHTLog", + "eve-log.bittorrent-dht", OutputBitTorrentDHTLogInitSub, ALPROTO_BITTORRENT_DHT, + JsonBitTorrentDHTLogger, JsonBitTorrentDHTLogThreadInit, + JsonBitTorrentDHTLogThreadDeinit, NULL); +} diff --git a/src/output-json-bittorrent-dht.h b/src/app-layer/bittorrent-dht/logger.h similarity index 100% rename from src/output-json-bittorrent-dht.h rename to src/app-layer/bittorrent-dht/logger.h diff --git a/src/app-layer/dcerpc/logger.c b/src/app-layer/dcerpc/logger.c new file mode 100644 index 000000000000..e93df7fe9e14 --- /dev/null +++ b/src/app-layer/dcerpc/logger.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2017-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "util/buffer.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "app-layer-parser.h" +#include "app-layer/dcerpc/logger.h" +#include "rust.h" + +static int JsonDCERPCLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *tx, uint64_t tx_id) +{ + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "dcerpc", NULL, thread->ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_FAILED; + } + + jb_open_object(jb, "dcerpc"); + if (p->proto == IPPROTO_TCP) { + if (!rs_dcerpc_log_json_record_tcp(state, tx, jb)) { + goto error; + } + } else { + if (!rs_dcerpc_log_json_record_udp(state, tx, jb)) { + goto error; + } + } + jb_close(jb); + + MemBufferReset(thread->buffer); + OutputJsonBuilderBuffer(jb, thread); + + jb_free(jb); + return TM_ECODE_OK; + +error: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static OutputInitResult DCERPCLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DCERPC); + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DCERPC); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonDCERPCLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonDCERPCLog", "eve-log.dcerpc", + DCERPCLogInitSub, ALPROTO_DCERPC, JsonDCERPCLogger, JsonLogThreadInit, + JsonLogThreadDeinit, NULL); + + SCLogDebug("DCERPC JSON logger registered."); +} diff --git a/src/output-json-dcerpc.h b/src/app-layer/dcerpc/logger.h similarity index 100% rename from src/output-json-dcerpc.h rename to src/app-layer/dcerpc/logger.h diff --git a/src/app-layer/dhcp/detect-leasetime.c b/src/app-layer/dhcp/detect-leasetime.c new file mode 100644 index 000000000000..3584d0c34ba2 --- /dev/null +++ b/src/app-layer/dhcp/detect-leasetime.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "rust.h" +#include "app-layer/dhcp/detect-leasetime.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-uint.h" +#include "detect-parse.h" + +static int g_buffer_id = 0; + +/** + * \internal + * \brief Function to match leasetime of a TX + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectU64Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectDHCPLeaseTimeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + uint64_t leasetime; + if (rs_dhcp_tx_get_leasetime(txv, &leasetime)) { + const DetectU64Data *dd = (const DetectU64Data *)ctx; + if (DetectU64Match(leasetime, dd)) { + SCReturnInt(1); + } + } + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to free memory associated with DetectU64Data. + * + * \param de_ptr Pointer to DetectU64Data. + */ +static void DetectDHCPLeaseTimeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u64_free(ptr); +} + +/** + * \brief Function to add the parsed dhcp leasetime field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectDHCPLeaseTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_DHCP) != 0) + return -1; + + DetectU64Data *dd = DetectU64Parse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed for %s", rawstr, + sigmatch_table[DETECT_AL_DHCP_LEASETIME].name); + return -1; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList( + de_ctx, s, DETECT_AL_DHCP_LEASETIME, (SigMatchCtx *)dd, g_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectDHCPLeaseTimeFree(de_ctx, dd); + return -1; +} + +/** + * \brief Registration function for dhcp.procedure keyword. + */ +void DetectDHCPLeaseTimeRegister(void) +{ + sigmatch_table[DETECT_AL_DHCP_LEASETIME].name = "dhcp.leasetime"; + sigmatch_table[DETECT_AL_DHCP_LEASETIME].desc = "match DHCP leasetime"; + sigmatch_table[DETECT_AL_DHCP_LEASETIME].url = "/rules/dhcp-keywords.html#dhcp-leasetime"; + sigmatch_table[DETECT_AL_DHCP_LEASETIME].AppLayerTxMatch = DetectDHCPLeaseTimeMatch; + sigmatch_table[DETECT_AL_DHCP_LEASETIME].Setup = DetectDHCPLeaseTimeSetup; + sigmatch_table[DETECT_AL_DHCP_LEASETIME].Free = DetectDHCPLeaseTimeFree; + + DetectAppLayerInspectEngineRegister2("dhcp.leasetime", ALPROTO_DHCP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("dhcp.leasetime", ALPROTO_DHCP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + + g_buffer_id = DetectBufferTypeGetByName("dhcp.leasetime"); +} diff --git a/src/detect-dhcp-leasetime.h b/src/app-layer/dhcp/detect-leasetime.h similarity index 100% rename from src/detect-dhcp-leasetime.h rename to src/app-layer/dhcp/detect-leasetime.h diff --git a/src/app-layer/dhcp/detect-rebinding-time.c b/src/app-layer/dhcp/detect-rebinding-time.c new file mode 100644 index 000000000000..0d7f7fe43eab --- /dev/null +++ b/src/app-layer/dhcp/detect-rebinding-time.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "rust.h" +#include "app-layer/dhcp/detect-rebinding-time.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-uint.h" +#include "detect-parse.h" + +static int g_buffer_id = 0; + +/** + * \internal + * \brief Function to match rebinding time of a TX + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectU64Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectDHCPRebindingTimeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + uint64_t res; + if (rs_dhcp_tx_get_rebinding_time(txv, &res)) { + const DetectU64Data *dd = (const DetectU64Data *)ctx; + if (DetectU64Match(res, dd)) { + SCReturnInt(1); + } + } + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to free memory associated with DetectU64Data. + * + * \param de_ptr Pointer to DetectU64Data. + */ +static void DetectDHCPRebindingTimeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u64_free(ptr); +} + +/** + * \brief Function to add the parsed dhcp rebinding time field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectDHCPRebindingTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_DHCP) != 0) + return -1; + + DetectU64Data *dd = DetectU64Parse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed for %s", rawstr, + sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].name); + return -1; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList( + de_ctx, s, DETECT_AL_DHCP_REBINDING_TIME, (SigMatchCtx *)dd, g_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectDHCPRebindingTimeFree(de_ctx, dd); + return -1; +} + +/** + * \brief Registration function for dhcp.procedure keyword. + */ +void DetectDHCPRebindingTimeRegister(void) +{ + sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].name = "dhcp.rebinding_time"; + sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].desc = "match DHCP rebinding time"; + sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].url = + "/rules/dhcp-keywords.html#dhcp-rebinding-time"; + sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].AppLayerTxMatch = DetectDHCPRebindingTimeMatch; + sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].Setup = DetectDHCPRebindingTimeSetup; + sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].Free = DetectDHCPRebindingTimeFree; + + DetectAppLayerInspectEngineRegister2("dhcp.rebinding-time", ALPROTO_DHCP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("dhcp.rebinding-time", ALPROTO_DHCP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + + g_buffer_id = DetectBufferTypeGetByName("dhcp.rebinding-time"); +} diff --git a/src/detect-dhcp-rebinding-time.h b/src/app-layer/dhcp/detect-rebinding-time.h similarity index 100% rename from src/detect-dhcp-rebinding-time.h rename to src/app-layer/dhcp/detect-rebinding-time.h diff --git a/src/app-layer/dhcp/detect-renewal-time.c b/src/app-layer/dhcp/detect-renewal-time.c new file mode 100644 index 000000000000..0e703199f298 --- /dev/null +++ b/src/app-layer/dhcp/detect-renewal-time.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "rust.h" +#include "app-layer/dhcp/detect-renewal-time.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-uint.h" +#include "detect-parse.h" + +static int g_buffer_id = 0; + +/** + * \internal + * \brief Function to match renewal time of a TX + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectU64Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectDHCPRenewalTimeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + uint64_t res; + if (rs_dhcp_tx_get_renewal_time(txv, &res)) { + const DetectU64Data *dd = (const DetectU64Data *)ctx; + if (DetectU64Match(res, dd)) { + SCReturnInt(1); + } + } + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to free memory associated with DetectU64Data. + * + * \param de_ptr Pointer to DetectU64Data. + */ +static void DetectDHCPRenewalTimeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u64_free(ptr); +} + +/** + * \brief Function to add the parsed dhcp renewal time field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectDHCPRenewalTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_DHCP) != 0) + return -1; + + DetectU64Data *dd = DetectU64Parse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed for %s", rawstr, + sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].name); + return -1; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList( + de_ctx, s, DETECT_AL_DHCP_RENEWAL_TIME, (SigMatchCtx *)dd, g_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectDHCPRenewalTimeFree(de_ctx, dd); + return -1; +} + +/** + * \brief Registration function for dhcp.procedure keyword. + */ +void DetectDHCPRenewalTimeRegister(void) +{ + sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].name = "dhcp.renewal_time"; + sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].desc = "match DHCP renewal time"; + sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].url = "/rules/dhcp-keywords.html#dhcp-renewal-time"; + sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].AppLayerTxMatch = DetectDHCPRenewalTimeMatch; + sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].Setup = DetectDHCPRenewalTimeSetup; + sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].Free = DetectDHCPRenewalTimeFree; + + DetectAppLayerInspectEngineRegister2("dhcp.renewal-time", ALPROTO_DHCP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("dhcp.renewal-time", ALPROTO_DHCP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + + g_buffer_id = DetectBufferTypeGetByName("dhcp.renewal-time"); +} diff --git a/src/detect-dhcp-renewal-time.h b/src/app-layer/dhcp/detect-renewal-time.h similarity index 100% rename from src/detect-dhcp-renewal-time.h rename to src/app-layer/dhcp/detect-renewal-time.h diff --git a/src/app-layer/dhcp/logger.c b/src/app-layer/dhcp/logger.c new file mode 100644 index 000000000000..1026897114bc --- /dev/null +++ b/src/app-layer/dhcp/logger.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2015-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jason Ish + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/dhcp/logger.h" +#include "rust.h" + +typedef struct LogDHCPFileCtx_ { + void *rs_logger; + OutputJsonCtx *eve_ctx; +} LogDHCPFileCtx; + +typedef struct LogDHCPLogThread_ { + LogDHCPFileCtx *dhcplog_ctx; + OutputJsonThreadCtx *thread; +} LogDHCPLogThread; + +static int JsonDHCPLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + LogDHCPLogThread *thread = thread_data; + LogDHCPFileCtx *ctx = thread->dhcplog_ctx; + + if (!rs_dhcp_logger_do_log(ctx->rs_logger, tx)) { + return TM_ECODE_OK; + } + + JsonBuilder *js = CreateEveHeader((Packet *)p, 0, "dhcp", NULL, ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_FAILED; + } + + rs_dhcp_logger_log(ctx->rs_logger, tx, js); + + OutputJsonBuilderBuffer(js, thread->thread); + jb_free(js); + + return TM_ECODE_OK; +} + +static void OutputDHCPLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogDHCPFileCtx *dhcplog_ctx = (LogDHCPFileCtx *)output_ctx->data; + rs_dhcp_logger_free(dhcplog_ctx->rs_logger); + SCFree(dhcplog_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputDHCPLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + + LogDHCPFileCtx *dhcplog_ctx = SCCalloc(1, sizeof(*dhcplog_ctx)); + if (unlikely(dhcplog_ctx == NULL)) { + return result; + } + dhcplog_ctx->eve_ctx = parent_ctx->data; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(dhcplog_ctx); + return result; + } + output_ctx->data = dhcplog_ctx; + output_ctx->DeInit = OutputDHCPLogDeInitCtxSub; + + dhcplog_ctx->rs_logger = rs_dhcp_logger_new(conf); + + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DHCP); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonDHCPLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogDHCPLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + LogDHCPFileCtx *ctx = ((OutputCtx *)initdata)->data; + thread->dhcplog_ctx = ctx; + thread->thread = CreateEveThreadCtx(t, ctx->eve_ctx); + if (thread->thread == NULL) { + SCFree(thread); + return TM_ECODE_FAILED; + } + + *data = (void *)thread; + return TM_ECODE_OK; +} + +static TmEcode JsonDHCPLogThreadDeinit(ThreadVars *t, void *data) +{ + LogDHCPLogThread *thread = (LogDHCPLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->thread); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonDHCPLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonDHCPLog", "eve-log.dhcp", + OutputDHCPLogInitSub, ALPROTO_DHCP, JsonDHCPLogger, JsonDHCPLogThreadInit, + JsonDHCPLogThreadDeinit, NULL); +} diff --git a/src/output-json-dhcp.h b/src/app-layer/dhcp/logger.h similarity index 100% rename from src/output-json-dhcp.h rename to src/app-layer/dhcp/logger.h diff --git a/src/app-layer/dnp3/detect.c b/src/app-layer/dnp3/detect.c new file mode 100644 index 000000000000..6b1ba479609d --- /dev/null +++ b/src/app-layer/dnp3/detect.c @@ -0,0 +1,689 @@ +/* Copyright (C) 2015-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" + +#include "stream.h" + +#include "detect.h" +#include "detect-parse.h" +#include "app-layer/dnp3/detect.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer/dnp3/parser.h" +#include "util/byte.h" + +static int g_dnp3_match_buffer_id = 0; +static int g_dnp3_data_buffer_id = 0; + +/** + * The detection struct. + */ +typedef struct DetectDNP3_ { + union { + struct { + /* Function code for function code detection. */ + uint8_t function_code; + }; + struct { + /* Internal indicator flags for IIN detection. */ + uint16_t ind_flags; + }; + struct { + /* Object info for object detection. */ + uint8_t obj_group; + uint8_t obj_variation; + }; + }; +} DetectDNP3; + +/** + * Indicator names to value mappings (Snort compatible). + */ +DNP3Mapping DNP3IndicatorsMap[] = { + { "device_restart", 0x8000 }, + { "device_trouble", 0x4000 }, + { "local_control", 0x2000 }, + { "need_time", 0x1000 }, + { "class_3_events", 0x0800 }, + { "class_2_events", 0x0400 }, + { "class_1_events", 0x0200 }, + { "all_stations", 0x0100 }, + + { "reserved_1", 0x0080 }, + { "reserved_2", 0x0040 }, + { "config_corrupt", 0x0020 }, + { "already_executing", 0x0010 }, + { "event_buffer_overflow", 0x0008 }, + { "parameter_error", 0x0004 }, + { "object_unknown", 0x0002 }, + { "no_func_code_support", 0x0001 }, + + { NULL, 0 }, +}; + +/** + * Application function code name to code mappings (Snort compatible). + */ +DNP3Mapping DNP3FunctionNameMap[] = { { "confirm", 0 }, { "read", 1 }, { "write", 2 }, + { "select", 3 }, { "operate", 4 }, { "direct_operate", 5 }, { "direct_operate_nr", 6 }, + { "immed_freeze", 7 }, { "immed_freeze_nr", 8 }, { "freeze_clear", 9 }, + { "freeze_clear_nr", 10 }, { "freeze_at_time", 11 }, { "freeze_at_time_nr", 12 }, + { "cold_restart", 13 }, { "warm_restart", 14 }, { "initialize_data", 15 }, + { "initialize_appl", 16 }, { "start_appl", 17 }, { "stop_appl", 18 }, { "save_config", 19 }, + { "enable_unsolicited", 20 }, { "disable_unsolicited", 21 }, { "assign_class", 22 }, + { "delay_measure", 23 }, { "record_current_time", 24 }, { "open_file", 25 }, + { "close_file", 26 }, { "delete_file", 27 }, { "get_file_info", 28 }, + { "authenticate_file", 29 }, { "abort_file", 30 }, { "activate_config", 31 }, + { "authenticate_req", 32 }, { "authenticate_err", 33 }, { "response", 129 }, + { "unsolicited_response", 130 }, { "authenticate_resp", 131 } }; + +#ifdef UNITTESTS +static void DetectDNP3FuncRegisterTests(void); +static void DetectDNP3IndRegisterTests(void); +static void DetectDNP3ObjRegisterTests(void); +#endif + +/** + * \brief Utility function to trim leading and trailing whitespace + * from a string. + */ +static char *TrimString(char *str) +{ + char *end = str + strlen(str) - 1; + while (isspace(*str)) { + str++; + } + while (end > str && isspace(*end)) { + end--; + } + *(end + 1) = '\0'; + return str; +} + +static InspectionBuffer *GetDNP3Data(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + SCLogDebug("list_id %d", list_id); + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + DNP3Transaction *tx = (DNP3Transaction *)txv; + SCLogDebug("tx %p", tx); + + if ((flow_flags & STREAM_TOSERVER && !tx->is_request) || + (flow_flags & STREAM_TOCLIENT && tx->is_request)) { + return NULL; + } + + if (tx->buffer == NULL || tx->buffer_len == 0) { + return NULL; + } + + SCLogDebug("tx %p data %p data_len %u", tx, tx->buffer, tx->buffer_len); + InspectionBufferSetup(det_ctx, list_id, buffer, tx->buffer, tx->buffer_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +/** + * \brief Parse the provided function name or code to its integer + * value. + * + * If the value passed is a number, it will be checked that it falls + * within the range of valid function codes. If function name is + * passed it will be resolved to its function code. + * + * \retval The function code as an integer if successful, -1 on + * failure. + */ +static int DetectDNP3FuncParseFunctionCode(const char *str, uint8_t *fc) +{ + if (StringParseUint8(fc, 10, (uint16_t)strlen(str), str) >= 0) { + return 1; + } + + /* Lookup by name. */ + for (size_t i = 0; i < sizeof(DNP3FunctionNameMap) / sizeof(DNP3Mapping); i++) { + if (strcasecmp(str, DNP3FunctionNameMap[i].name) == 0) { + *fc = (uint8_t)(DNP3FunctionNameMap[i].value); + return 1; + } + } + + return 0; +} + +static int DetectDNP3FuncSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + SCEnter(); + DetectDNP3 *dnp3 = NULL; + uint8_t function_code; + + if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) + return -1; + + if (!DetectDNP3FuncParseFunctionCode(str, &function_code)) { + SCLogError("Invalid argument \"%s\" supplied to dnp3_func keyword.", str); + return -1; + } + + dnp3 = SCCalloc(1, sizeof(DetectDNP3)); + if (unlikely(dnp3 == NULL)) { + goto error; + } + dnp3->function_code = function_code; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNP3FUNC, (SigMatchCtx *)dnp3, + g_dnp3_match_buffer_id) == NULL) { + goto error; + } + + SCReturnInt(0); +error: + if (dnp3 != NULL) { + SCFree(dnp3); + } + SCReturnInt(-1); +} + +static int DetectDNP3IndParseByName(const char *str, uint16_t *flags) +{ + char tmp[strlen(str) + 1]; + char *p, *last = NULL; + + strlcpy(tmp, str, sizeof(tmp)); + + for ((p = strtok_r(tmp, ",", &last)); p; (p = strtok_r(NULL, ",", &last))) { + p = TrimString(p); + int found = 0; + int i = 0; + while (DNP3IndicatorsMap[i].name != NULL) { + if (strcasecmp(p, DNP3IndicatorsMap[i].name) == 0) { + *flags |= DNP3IndicatorsMap[i].value; + found = 1; + break; + } + i++; + } + + if (!found) { + SCLogError("Bad argument \"%s\" supplied to dnp3.ind keyword.", p); + return 0; + } + } + + return 1; +} + +static int DetectDNP3IndParse(const char *str, uint16_t *flags) +{ + *flags = 0; + + if (StringParseUint16(flags, 0, (uint16_t)strlen(str), str) > 0) { + return 1; + } + + /* Parse by name - will log a more specific error message on error. */ + if (DetectDNP3IndParseByName(str, flags)) { + return 1; + } + + return 0; +} + +static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + SCEnter(); + DetectDNP3 *detect = NULL; + uint16_t flags; + + if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) + return -1; + + if (!DetectDNP3IndParse(str, &flags)) { + SCLogError("Invalid argument \"%s\" supplied to dnp3.ind keyword.", str); + return -1; + } + + detect = SCCalloc(1, sizeof(DetectDNP3)); + if (unlikely(detect == NULL)) { + goto error; + } + detect->ind_flags = flags; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNP3IND, (SigMatchCtx *)detect, + g_dnp3_match_buffer_id) == NULL) { + goto error; + } + + SCReturnInt(0); +error: + if (detect != NULL) { + SCFree(detect); + } + SCReturnInt(-1); +} + +/** + * \brief Parse the value of string of the dnp3_obj keyword. + * + * \param str the input string + * \param gout pointer to variable to store the parsed group integer + * \param vout pointer to variable to store the parsed variation integer + * + * \retval 1 if parsing successful otherwise 0. + */ +static int DetectDNP3ObjParse(const char *str, uint8_t *group, uint8_t *var) +{ + size_t size = strlen(str) + 1; + char groupstr[size], *varstr, *sep; + strlcpy(groupstr, str, size); + + sep = strchr(groupstr, ','); + if (sep == NULL) { + return 0; + } + *sep = '\0'; + varstr = sep + 1; + + if (StringParseUint8(group, 0, (uint16_t)strlen(groupstr), groupstr) < 0) { + return 0; + } + + if (StringParseUint8(var, 0, (uint16_t)strlen(varstr), varstr) < 0) { + return 0; + } + + return 1; +} + +static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + SCEnter(); + uint8_t group; + uint8_t variation; + DetectDNP3 *detect = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) + return -1; + + if (!DetectDNP3ObjParse(str, &group, &variation)) { + goto fail; + } + + detect = SCCalloc(1, sizeof(*detect)); + if (unlikely(detect == NULL)) { + goto fail; + } + detect->obj_group = group; + detect->obj_variation = variation; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNP3OBJ, (SigMatchCtx *)detect, + g_dnp3_match_buffer_id) == NULL) { + goto fail; + } + + SCReturnInt(1); +fail: + if (detect != NULL) { + SCFree(detect); + } + SCReturnInt(0); +} + +static void DetectDNP3Free(DetectEngineCtx *de_ctx, void *ptr) +{ + SCEnter(); + if (ptr != NULL) { + SCFree(ptr); + } + SCReturn; +} + +static int DetectDNP3FuncMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + int match = 0; + + if (flags & STREAM_TOSERVER && tx->is_request) { + match = detect->function_code == tx->ah.function_code; + } else if (flags & STREAM_TOCLIENT && !tx->is_request) { + match = detect->function_code == tx->ah.function_code; + } + + return match; +} + +static int DetectDNP3ObjMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + DNP3ObjectList *objects = NULL; + + if (flags & STREAM_TOSERVER && tx->is_request) { + objects = &tx->objects; + } else if (flags & STREAM_TOCLIENT && !tx->is_request) { + objects = &tx->objects; + } + + if (objects != NULL) { + DNP3Object *object; + TAILQ_FOREACH (object, objects, next) { + if (object->group == detect->obj_group && object->variation == detect->obj_variation) { + return 1; + } + } + } + + return 0; +} + +static int DetectDNP3IndMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + + if (flags & STREAM_TOCLIENT) { + if ((tx->iin.iin1 & (detect->ind_flags >> 8)) || + (tx->iin.iin2 & (detect->ind_flags & 0xf))) { + return 1; + } + } + + return 0; +} + +static void DetectDNP3FuncRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3_func"; + sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3.func"; + sigmatch_table[DETECT_AL_DNP3FUNC].desc = + "match on the application function code found in DNP3 request and responses"; + sigmatch_table[DETECT_AL_DNP3FUNC].url = "/rules/dnp3-keywords.html#dnp3-func"; + sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL; + sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerTxMatch = DetectDNP3FuncMatch; + sigmatch_table[DETECT_AL_DNP3FUNC].Setup = DetectDNP3FuncSetup; + sigmatch_table[DETECT_AL_DNP3FUNC].Free = DetectDNP3Free; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_DNP3FUNC].RegisterTests = DetectDNP3FuncRegisterTests; +#endif + SCReturn; +} + +static void DetectDNP3IndRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3_ind"; + sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3.ind"; + sigmatch_table[DETECT_AL_DNP3IND].desc = + "match on the DNP3 internal indicator flags in the response application header"; + sigmatch_table[DETECT_AL_DNP3IND].url = "/rules/dnp3-keywords.html#dnp3-ind"; + sigmatch_table[DETECT_AL_DNP3IND].Match = NULL; + sigmatch_table[DETECT_AL_DNP3IND].AppLayerTxMatch = DetectDNP3IndMatch; + sigmatch_table[DETECT_AL_DNP3IND].Setup = DetectDNP3IndSetup; + sigmatch_table[DETECT_AL_DNP3IND].Free = DetectDNP3Free; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_DNP3IND].RegisterTests = DetectDNP3IndRegisterTests; +#endif + SCReturn; +} + +static void DetectDNP3ObjRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3_obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3.obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].desc = "match on the DNP3 application data objects"; + sigmatch_table[DETECT_AL_DNP3OBJ].url = "/rules/dnp3-keywords.html#dnp3-obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL; + sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerTxMatch = DetectDNP3ObjMatch; + sigmatch_table[DETECT_AL_DNP3OBJ].Setup = DetectDNP3ObjSetup; + sigmatch_table[DETECT_AL_DNP3OBJ].Free = DetectDNP3Free; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_DNP3OBJ].RegisterTests = DetectDNP3ObjRegisterTests; +#endif + SCReturn; +} + +static int DetectDNP3DataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + SCEnter(); + if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) + return -1; + + if (DetectBufferSetActiveList(de_ctx, s, g_dnp3_data_buffer_id) != 0) + return -1; + + SCReturnInt(0); +} + +static void DetectDNP3DataRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3DATA].name = "dnp3.data"; + sigmatch_table[DETECT_AL_DNP3DATA].alias = "dnp3_data"; + sigmatch_table[DETECT_AL_DNP3DATA].desc = + "make the following content options to match on the re-assembled application buffer"; + sigmatch_table[DETECT_AL_DNP3DATA].url = "/rules/dnp3-keywords.html#dnp3-data"; + sigmatch_table[DETECT_AL_DNP3DATA].Setup = DetectDNP3DataSetup; + sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("dnp3_data", ALPROTO_DNP3, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetDNP3Data); + DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetDNP3Data, ALPROTO_DNP3, 0); + + DetectAppLayerInspectEngineRegister2("dnp3_data", ALPROTO_DNP3, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetDNP3Data); + DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetDNP3Data, ALPROTO_DNP3, 0); + + g_dnp3_data_buffer_id = DetectBufferTypeGetByName("dnp3_data"); + SCReturn; +} + +void DetectDNP3Register(void) +{ + DetectDNP3DataRegister(); + + DetectDNP3FuncRegister(); + DetectDNP3IndRegister(); + DetectDNP3ObjRegister(); + + /* Register the list of func, ind and obj. */ + DetectAppLayerInspectEngineRegister2( + "dnp3", ALPROTO_DNP3, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + DetectAppLayerInspectEngineRegister2( + "dnp3", ALPROTO_DNP3, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); + + g_dnp3_match_buffer_id = DetectBufferTypeRegister("dnp3"); +} + +#ifdef UNITTESTS + +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "app-layer-parser.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int DetectDNP3FuncParseFunctionCodeTest(void) +{ + uint8_t fc; + + /* Valid. */ + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("0", &fc)); + FAIL_IF(fc != 0); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("1", &fc)); + FAIL_IF(fc != 1); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("254", &fc)); + FAIL_IF(fc != 254); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("255", &fc)); + FAIL_IF(fc != 255); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("confirm", &fc)); + FAIL_IF(fc != 0); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("CONFIRM", &fc)); + FAIL_IF(fc != 0); + + /* Invalid. */ + FAIL_IF(DetectDNP3FuncParseFunctionCode("", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("-1", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("-2", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("256", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("unknown_function_code", &fc)); + + PASS; +} + +static int DetectDNP3FuncTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *s = DetectEngineAppendSig(de_ctx, "alert dnp3 any any -> any any " + "(msg:\"SURICATA DNP3 Write request\"; " + "dnp3_func:2; sid:5000009; rev:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dnp3_match_buffer_id); + FAIL_IF_NULL(sm); + FAIL_IF_NULL(sm->ctx); + + DetectDNP3 *dnp3func = (DetectDNP3 *)sm->ctx; + FAIL_IF(dnp3func->function_code != 2); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +static int DetectDNP3IndTestParseAsInteger(void) +{ + uint16_t flags = 0; + + FAIL_IF(!DetectDNP3IndParse("0", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("1", &flags)); + FAIL_IF(flags != 0x0001); + + FAIL_IF(!DetectDNP3IndParse("0x0", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("0x0000", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("0x0001", &flags)); + FAIL_IF(flags != 0x0001); + + FAIL_IF(!DetectDNP3IndParse("0x8421", &flags)); + FAIL_IF(flags != 0x8421); + + FAIL_IF(DetectDNP3IndParse("a", &flags)); + + PASS; +} + +static int DetectDNP3IndTestParseByName(void) +{ + uint16_t flags = 0; + + FAIL_IF(!DetectDNP3IndParse("all_stations", &flags)); + FAIL_IF(!(flags & 0x0100)); + FAIL_IF(!DetectDNP3IndParse("class_1_events , class_2_events", &flags)); + FAIL_IF(!(flags & 0x0200)); + FAIL_IF(!(flags & 0x0400)); + FAIL_IF((flags & 0xf9ff)); + + FAIL_IF(DetectDNP3IndParse("something", &flags)); + + PASS; +} + +static int DetectDNP3ObjSetupTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + Signature *s = DetectEngineAppendSig(de_ctx, "alert dnp3 any any -> any any " + "(msg:\"SURICATA DNP3 Object Test\"; " + "dnp3_obj:99,99; sid:1; rev:1;)"); + FAIL_IF(de_ctx->sig_list == NULL); + + SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dnp3_match_buffer_id); + FAIL_IF_NULL(sm); + FAIL_IF_NULL(sm->ctx); + + DetectDNP3 *detect = (DetectDNP3 *)sm->ctx; + FAIL_IF(detect->obj_group != 99); + FAIL_IF(detect->obj_variation != 99); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +static int DetectDNP3ObjParseTest(void) +{ + uint8_t group, var; + + FAIL_IF(!DetectDNP3ObjParse("0,0", &group, &var)); + FAIL_IF(group != 0 || var != 0); + + FAIL_IF(!DetectDNP3ObjParse("255,255", &group, &var)); + FAIL_IF(group != 255 || var != 255); + + FAIL_IF(DetectDNP3ObjParse("-1,-1", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("256,256", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("a,1", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("1,a", &group, &var)); + + PASS; +} + +static void DetectDNP3FuncRegisterTests(void) +{ + UtRegisterTest("DetectDNP3FuncParseFunctionCodeTest", DetectDNP3FuncParseFunctionCodeTest); + UtRegisterTest("DetectDNP3FuncTest01", DetectDNP3FuncTest01); +} + +static void DetectDNP3IndRegisterTests(void) +{ + UtRegisterTest("DetectDNP3IndTestParseAsInteger", DetectDNP3IndTestParseAsInteger); + UtRegisterTest("DetectDNP3IndTestParseByName", DetectDNP3IndTestParseByName); +} + +static void DetectDNP3ObjRegisterTests(void) +{ + UtRegisterTest("DetectDNP3ObjParseTest", DetectDNP3ObjParseTest); + UtRegisterTest("DetectDNP3ObjSetupTest", DetectDNP3ObjSetupTest); +} +#endif diff --git a/src/app-layer/dnp3/detect.h b/src/app-layer/dnp3/detect.h new file mode 100644 index 000000000000..518a483d7373 --- /dev/null +++ b/src/app-layer/dnp3/detect.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DETECT_DNP3_H__ +#define __DETECT_DNP3_H__ + +/** + * Struct for mapping symbolic names to values. + */ +typedef struct DNP3Mapping_ { + const char *name; + uint16_t value; +} DNP3Mapping; + +/* Map of internal indicators to value for external use. */ +extern DNP3Mapping DNP3IndicatorsMap[]; + +void DetectDNP3Register(void); + +#endif /* __DETECT_DNP3_H__ */ diff --git a/src/app-layer/dnp3/logger-objects.c b/src/app-layer/dnp3/logger-objects.c new file mode 100644 index 000000000000..f837e481ae24 --- /dev/null +++ b/src/app-layer/dnp3/logger-objects.c @@ -0,0 +1,1667 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +#include "suricata-common.h" + +#include "app-layer/dnp3/parser.h" +#include "app-layer/dnp3/parser-objects.h" +#include "app-layer/dnp3/logger-objects.h" +#include "output/eve/output-json.h" + +// clang-format off +void OutputJsonDNP3SetItem(JsonBuilder *js, DNP3Object *object, + DNP3Point *point) +{ + + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { + case DNP3_OBJECT_CODE(1, 1): { + DNP3ObjectG1V1 *data = point->data; + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(1, 2): { + DNP3ObjectG1V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "chatter_filter", data->chatter_filter); + jb_set_uint(js, "reserved", data->reserved); + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(2, 1): { + DNP3ObjectG2V1 *data = point->data; + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(2, 2): { + DNP3ObjectG2V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "chatter_filter", data->chatter_filter); + jb_set_uint(js, "reserved", data->reserved); + jb_set_uint(js, "state", data->state); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(2, 3): { + DNP3ObjectG2V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "chatter_filter", data->chatter_filter); + jb_set_uint(js, "reserved", data->reserved); + jb_set_uint(js, "state", data->state); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(3, 1): { + DNP3ObjectG3V1 *data = point->data; + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(3, 2): { + DNP3ObjectG3V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "chatter_filter", data->chatter_filter); + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(4, 1): { + DNP3ObjectG4V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "chatter_filter", data->chatter_filter); + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(4, 2): { + DNP3ObjectG4V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "chatter_filter", data->chatter_filter); + jb_set_uint(js, "state", data->state); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(4, 3): { + DNP3ObjectG4V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "chatter_filter", data->chatter_filter); + jb_set_uint(js, "state", data->state); + jb_set_uint(js, "relative_time_ms", data->relative_time_ms); + break; + } + case DNP3_OBJECT_CODE(10, 1): { + DNP3ObjectG10V1 *data = point->data; + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(10, 2): { + DNP3ObjectG10V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(11, 1): { + DNP3ObjectG11V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(11, 2): { + DNP3ObjectG11V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "state", data->state); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(12, 1): { + DNP3ObjectG12V1 *data = point->data; + jb_set_uint(js, "op_type", data->op_type); + jb_set_uint(js, "qu", data->qu); + jb_set_uint(js, "cr", data->cr); + jb_set_uint(js, "tcc", data->tcc); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "ontime", data->ontime); + jb_set_uint(js, "offtime", data->offtime); + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved", data->reserved); + break; + } + case DNP3_OBJECT_CODE(12, 2): { + DNP3ObjectG12V2 *data = point->data; + jb_set_uint(js, "op_type", data->op_type); + jb_set_uint(js, "qu", data->qu); + jb_set_uint(js, "cr", data->cr); + jb_set_uint(js, "tcc", data->tcc); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "ontime", data->ontime); + jb_set_uint(js, "offtime", data->offtime); + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved", data->reserved); + break; + } + case DNP3_OBJECT_CODE(12, 3): { + DNP3ObjectG12V3 *data = point->data; + jb_set_uint(js, "point", data->point); + break; + } + case DNP3_OBJECT_CODE(13, 1): { + DNP3ObjectG13V1 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "commanded_state", data->commanded_state); + break; + } + case DNP3_OBJECT_CODE(13, 2): { + DNP3ObjectG13V2 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "commanded_state", data->commanded_state); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(20, 1): { + DNP3ObjectG20V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(20, 2): { + DNP3ObjectG20V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(20, 3): { + DNP3ObjectG20V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(20, 4): { + DNP3ObjectG20V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(20, 5): { + DNP3ObjectG20V5 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(20, 6): { + DNP3ObjectG20V6 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(20, 7): { + DNP3ObjectG20V7 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(20, 8): { + DNP3ObjectG20V8 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 1): { + DNP3ObjectG21V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 2): { + DNP3ObjectG21V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 3): { + DNP3ObjectG21V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 4): { + DNP3ObjectG21V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 5): { + DNP3ObjectG21V5 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(21, 6): { + DNP3ObjectG21V6 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(21, 7): { + DNP3ObjectG21V7 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(21, 8): { + DNP3ObjectG21V8 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(21, 9): { + DNP3ObjectG21V9 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 10): { + DNP3ObjectG21V10 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 11): { + DNP3ObjectG21V11 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(21, 12): { + DNP3ObjectG21V12 *data = point->data; + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(22, 1): { + DNP3ObjectG22V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(22, 2): { + DNP3ObjectG22V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(22, 3): { + DNP3ObjectG22V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(22, 4): { + DNP3ObjectG22V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(22, 5): { + DNP3ObjectG22V5 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(22, 6): { + DNP3ObjectG22V6 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(22, 7): { + DNP3ObjectG22V7 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(22, 8): { + DNP3ObjectG22V8 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(23, 1): { + DNP3ObjectG23V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(23, 2): { + DNP3ObjectG23V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(23, 3): { + DNP3ObjectG23V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(23, 4): { + DNP3ObjectG23V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + break; + } + case DNP3_OBJECT_CODE(23, 5): { + DNP3ObjectG23V5 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(23, 6): { + DNP3ObjectG23V6 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(23, 7): { + DNP3ObjectG23V7 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(23, 8): { + DNP3ObjectG23V8 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "rollover", data->rollover); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "count", data->count); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(30, 1): { + DNP3ObjectG30V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(30, 2): { + DNP3ObjectG30V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(30, 3): { + DNP3ObjectG30V3 *data = point->data; + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(30, 4): { + DNP3ObjectG30V4 *data = point->data; + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(30, 5): { + DNP3ObjectG30V5 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(30, 6): { + DNP3ObjectG30V6 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(31, 1): { + DNP3ObjectG31V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(31, 2): { + DNP3ObjectG31V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(31, 3): { + DNP3ObjectG31V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(31, 4): { + DNP3ObjectG31V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(31, 5): { + DNP3ObjectG31V5 *data = point->data; + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(31, 6): { + DNP3ObjectG31V6 *data = point->data; + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(31, 7): { + DNP3ObjectG31V7 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(31, 8): { + DNP3ObjectG31V8 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(32, 1): { + DNP3ObjectG32V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(32, 2): { + DNP3ObjectG32V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(32, 3): { + DNP3ObjectG32V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(32, 4): { + DNP3ObjectG32V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(32, 5): { + DNP3ObjectG32V5 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(32, 6): { + DNP3ObjectG32V6 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(32, 7): { + DNP3ObjectG32V7 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(32, 8): { + DNP3ObjectG32V8 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(33, 1): { + DNP3ObjectG33V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(33, 2): { + DNP3ObjectG33V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(33, 3): { + DNP3ObjectG33V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(33, 4): { + DNP3ObjectG33V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(33, 5): { + DNP3ObjectG33V5 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(33, 6): { + DNP3ObjectG33V6 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(33, 7): { + DNP3ObjectG33V7 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(33, 8): { + DNP3ObjectG33V8 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(34, 1): { + DNP3ObjectG34V1 *data = point->data; + jb_set_uint(js, "deadband_value", data->deadband_value); + break; + } + case DNP3_OBJECT_CODE(34, 2): { + DNP3ObjectG34V2 *data = point->data; + jb_set_uint(js, "deadband_value", data->deadband_value); + break; + } + case DNP3_OBJECT_CODE(34, 3): { + DNP3ObjectG34V3 *data = point->data; + jb_set_float(js, "deadband_value", data->deadband_value); + break; + } + case DNP3_OBJECT_CODE(40, 1): { + DNP3ObjectG40V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(40, 2): { + DNP3ObjectG40V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(40, 3): { + DNP3ObjectG40V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(40, 4): { + DNP3ObjectG40V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(41, 1): { + DNP3ObjectG41V1 *data = point->data; + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "control_status", data->control_status); + break; + } + case DNP3_OBJECT_CODE(41, 2): { + DNP3ObjectG41V2 *data = point->data; + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "control_status", data->control_status); + break; + } + case DNP3_OBJECT_CODE(41, 3): { + DNP3ObjectG41V3 *data = point->data; + jb_set_float(js, "value", data->value); + jb_set_uint(js, "control_status", data->control_status); + break; + } + case DNP3_OBJECT_CODE(41, 4): { + DNP3ObjectG41V4 *data = point->data; + jb_set_float(js, "value", data->value); + jb_set_uint(js, "control_status", data->control_status); + break; + } + case DNP3_OBJECT_CODE(42, 1): { + DNP3ObjectG42V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(42, 2): { + DNP3ObjectG42V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(42, 3): { + DNP3ObjectG42V3 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(42, 4): { + DNP3ObjectG42V4 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(42, 5): { + DNP3ObjectG42V5 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(42, 6): { + DNP3ObjectG42V6 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(42, 7): { + DNP3ObjectG42V7 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(42, 8): { + DNP3ObjectG42V8 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "over_range", data->over_range); + jb_set_uint(js, "reference_err", data->reference_err); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "value", data->value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(43, 1): { + DNP3ObjectG43V1 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "commanded_value", data->commanded_value); + break; + } + case DNP3_OBJECT_CODE(43, 2): { + DNP3ObjectG43V2 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "commanded_value", data->commanded_value); + break; + } + case DNP3_OBJECT_CODE(43, 3): { + DNP3ObjectG43V3 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "commanded_value", data->commanded_value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(43, 4): { + DNP3ObjectG43V4 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "commanded_value", data->commanded_value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(43, 5): { + DNP3ObjectG43V5 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "commanded_value", data->commanded_value); + break; + } + case DNP3_OBJECT_CODE(43, 6): { + DNP3ObjectG43V6 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "commanded_value", data->commanded_value); + break; + } + case DNP3_OBJECT_CODE(43, 7): { + DNP3ObjectG43V7 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "commanded_value", data->commanded_value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(43, 8): { + DNP3ObjectG43V8 *data = point->data; + jb_set_uint(js, "status_code", data->status_code); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_float(js, "commanded_value", data->commanded_value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(50, 1): { + DNP3ObjectG50V1 *data = point->data; + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(50, 2): { + DNP3ObjectG50V2 *data = point->data; + jb_set_uint(js, "timestamp", data->timestamp); + jb_set_uint(js, "interval", data->interval); + break; + } + case DNP3_OBJECT_CODE(50, 3): { + DNP3ObjectG50V3 *data = point->data; + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(50, 4): { + DNP3ObjectG50V4 *data = point->data; + jb_set_uint(js, "timestamp", data->timestamp); + jb_set_uint(js, "interval_count", data->interval_count); + jb_set_uint(js, "interval_units", data->interval_units); + break; + } + case DNP3_OBJECT_CODE(51, 1): { + DNP3ObjectG51V1 *data = point->data; + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(51, 2): { + DNP3ObjectG51V2 *data = point->data; + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + case DNP3_OBJECT_CODE(52, 1): { + DNP3ObjectG52V1 *data = point->data; + jb_set_uint(js, "delay_secs", data->delay_secs); + break; + } + case DNP3_OBJECT_CODE(52, 2): { + DNP3ObjectG52V2 *data = point->data; + jb_set_uint(js, "delay_ms", data->delay_ms); + break; + } + case DNP3_OBJECT_CODE(70, 1): { + DNP3ObjectG70V1 *data = point->data; + jb_set_uint(js, "filename_size", data->filename_size); + jb_set_uint(js, "filetype_code", data->filetype_code); + jb_set_uint(js, "attribute_code", data->attribute_code); + jb_set_uint(js, "start_record", data->start_record); + jb_set_uint(js, "end_record", data->end_record); + jb_set_uint(js, "file_size", data->file_size); + jb_set_uint(js, "created_timestamp", data->created_timestamp); + jb_set_uint(js, "permission", data->permission); + jb_set_uint(js, "file_id", data->file_id); + jb_set_uint(js, "owner_id", data->owner_id); + jb_set_uint(js, "group_id", data->group_id); + jb_set_uint(js, "file_function_code", data->file_function_code); + jb_set_uint(js, "status_code", data->status_code); + if (data->filename_size > 0) { + jb_set_string_from_bytes( + js, "filename", (const uint8_t *)data->filename, data->filename_size); + } else { + jb_set_string(js, "filename", ""); + } + jb_set_uint(js, "data_size", data->data_size); + if (data->data_size > 0) { + jb_set_string_from_bytes( + js, "data", (const uint8_t *)data->data, data->data_size); + } else { + jb_set_string(js, "data", ""); + } + break; + } + case DNP3_OBJECT_CODE(70, 2): { + DNP3ObjectG70V2 *data = point->data; + jb_set_uint(js, "username_offset", data->username_offset); + jb_set_uint(js, "username_size", data->username_size); + jb_set_uint(js, "password_offset", data->password_offset); + jb_set_uint(js, "password_size", data->password_size); + jb_set_uint(js, "authentication_key", data->authentication_key); + if (data->username_size > 0) { + jb_set_string_from_bytes( + js, "username", (const uint8_t *)data->username, data->username_size); + } else { + jb_set_string(js, "username", ""); + } + if (data->password_size > 0) { + jb_set_string_from_bytes( + js, "password", (const uint8_t *)data->password, data->password_size); + } else { + jb_set_string(js, "password", ""); + } + break; + } + case DNP3_OBJECT_CODE(70, 3): { + DNP3ObjectG70V3 *data = point->data; + jb_set_uint(js, "filename_offset", data->filename_offset); + jb_set_uint(js, "filename_size", data->filename_size); + jb_set_uint(js, "created", data->created); + jb_set_uint(js, "permissions", data->permissions); + jb_set_uint(js, "authentication_key", data->authentication_key); + jb_set_uint(js, "file_size", data->file_size); + jb_set_uint(js, "operational_mode", data->operational_mode); + jb_set_uint(js, "maximum_block_size", data->maximum_block_size); + jb_set_uint(js, "request_id", data->request_id); + if (data->filename_size > 0) { + jb_set_string_from_bytes( + js, "filename", (const uint8_t *)data->filename, data->filename_size); + } else { + jb_set_string(js, "filename", ""); + } + break; + } + case DNP3_OBJECT_CODE(70, 4): { + DNP3ObjectG70V4 *data = point->data; + jb_set_uint(js, "file_handle", data->file_handle); + jb_set_uint(js, "file_size", data->file_size); + jb_set_uint(js, "maximum_block_size", data->maximum_block_size); + jb_set_uint(js, "request_id", data->request_id); + jb_set_uint(js, "status_code", data->status_code); + if (data->optional_text_len > 0) { + jb_set_string_from_bytes( + js, "optional_text", (const uint8_t *)data->optional_text, data->optional_text_len); + } else { + jb_set_string(js, "optional_text", ""); + } + break; + } + case DNP3_OBJECT_CODE(70, 5): { + DNP3ObjectG70V5 *data = point->data; + jb_set_uint(js, "file_handle", data->file_handle); + jb_set_uint(js, "block_number", data->block_number); + if (data->file_data_len > 0) { + jb_set_string_from_bytes( + js, "file_data", (const uint8_t *)data->file_data, data->file_data_len); + } else { + jb_set_string(js, "file_data", ""); + } + break; + } + case DNP3_OBJECT_CODE(70, 6): { + DNP3ObjectG70V6 *data = point->data; + jb_set_uint(js, "file_handle", data->file_handle); + jb_set_uint(js, "block_number", data->block_number); + jb_set_uint(js, "status_code", data->status_code); + if (data->optional_text_len > 0) { + jb_set_string_from_bytes( + js, "optional_text", (const uint8_t *)data->optional_text, data->optional_text_len); + } else { + jb_set_string(js, "optional_text", ""); + } + break; + } + case DNP3_OBJECT_CODE(70, 7): { + DNP3ObjectG70V7 *data = point->data; + jb_set_uint(js, "filename_offset", data->filename_offset); + jb_set_uint(js, "filename_size", data->filename_size); + jb_set_uint(js, "file_type", data->file_type); + jb_set_uint(js, "file_size", data->file_size); + jb_set_uint(js, "created_timestamp", data->created_timestamp); + jb_set_uint(js, "permissions", data->permissions); + jb_set_uint(js, "request_id", data->request_id); + if (data->filename_size > 0) { + jb_set_string_from_bytes( + js, "filename", (const uint8_t *)data->filename, data->filename_size); + } else { + jb_set_string(js, "filename", ""); + } + break; + } + case DNP3_OBJECT_CODE(70, 8): { + DNP3ObjectG70V8 *data = point->data; + if (data->file_specification_len > 0) { + jb_set_string_from_bytes( + js, "file_specification", (const uint8_t *)data->file_specification, data->file_specification_len); + } else { + jb_set_string(js, "file_specification", ""); + } + break; + } + case DNP3_OBJECT_CODE(80, 1): { + DNP3ObjectG80V1 *data = point->data; + jb_set_uint(js, "state", data->state); + break; + } + case DNP3_OBJECT_CODE(81, 1): { + DNP3ObjectG81V1 *data = point->data; + jb_set_uint(js, "fill_percentage", data->fill_percentage); + jb_set_uint(js, "overflow_state", data->overflow_state); + jb_set_uint(js, "group", data->group); + jb_set_uint(js, "variation", data->variation); + break; + } + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *data = point->data; + jb_set_string(js, "data->vendor_code", data->vendor_code); + jb_set_uint(js, "object_id", data->object_id); + jb_set_uint(js, "length", data->length); + jb_set_base64(js, "data->data_objects", data->data_objects, data->length); + break; + } + case DNP3_OBJECT_CODE(86, 2): { + DNP3ObjectG86V2 *data = point->data; + jb_set_uint(js, "rd", data->rd); + jb_set_uint(js, "wr", data->wr); + jb_set_uint(js, "st", data->st); + jb_set_uint(js, "ev", data->ev); + jb_set_uint(js, "df", data->df); + jb_set_uint(js, "padding0", data->padding0); + jb_set_uint(js, "padding1", data->padding1); + jb_set_uint(js, "padding2", data->padding2); + break; + } + case DNP3_OBJECT_CODE(102, 1): { + DNP3ObjectG102V1 *data = point->data; + jb_set_uint(js, "value", data->value); + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *data = point->data; + jb_set_uint(js, "csq", data->csq); + jb_set_uint(js, "usr", data->usr); + jb_set_uint(js, "mal", data->mal); + jb_set_uint(js, "reason", data->reason); + jb_set_base64(js, "data->challenge_data", data->challenge_data, data->challenge_data_len); + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *data = point->data; + jb_set_uint(js, "csq", data->csq); + jb_set_uint(js, "usr", data->usr); + jb_set_base64(js, "data->mac_value", data->mac_value, data->mac_value_len); + break; + } + case DNP3_OBJECT_CODE(120, 3): { + DNP3ObjectG120V3 *data = point->data; + jb_set_uint(js, "csq", data->csq); + jb_set_uint(js, "user_number", data->user_number); + break; + } + case DNP3_OBJECT_CODE(120, 4): { + DNP3ObjectG120V4 *data = point->data; + jb_set_uint(js, "user_number", data->user_number); + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *data = point->data; + jb_set_uint(js, "ksq", data->ksq); + jb_set_uint(js, "user_number", data->user_number); + jb_set_uint(js, "key_wrap_alg", data->key_wrap_alg); + jb_set_uint(js, "key_status", data->key_status); + jb_set_uint(js, "mal", data->mal); + jb_set_uint(js, "challenge_data_len", data->challenge_data_len); + jb_set_base64(js, "data->challenge_data", data->challenge_data, data->challenge_data_len); + jb_set_base64(js, "data->mac_value", data->mac_value, data->mac_value_len); + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *data = point->data; + jb_set_uint(js, "ksq", data->ksq); + jb_set_uint(js, "usr", data->usr); + jb_set_base64(js, "data->wrapped_key_data", data->wrapped_key_data, data->wrapped_key_data_len); + break; + } + case DNP3_OBJECT_CODE(120, 7): { + DNP3ObjectG120V7 *data = point->data; + jb_set_uint(js, "sequence_number", data->sequence_number); + jb_set_uint(js, "usr", data->usr); + jb_set_uint(js, "association_id", data->association_id); + jb_set_uint(js, "error_code", data->error_code); + jb_set_uint(js, "time_of_error", data->time_of_error); + if (data->error_text_len > 0) { + jb_set_string_from_bytes( + js, "error_text", (const uint8_t *)data->error_text, data->error_text_len); + } else { + jb_set_string(js, "error_text", ""); + } + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *data = point->data; + jb_set_uint(js, "key_change_method", data->key_change_method); + jb_set_uint(js, "certificate_type", data->certificate_type); + jb_set_base64(js, "data->certificate", data->certificate, data->certificate_len); + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *data = point->data; + jb_set_base64(js, "data->mac_value", data->mac_value, data->mac_value_len); + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *data = point->data; + jb_set_uint(js, "key_change_method", data->key_change_method); + jb_set_uint(js, "operation", data->operation); + jb_set_uint(js, "scs", data->scs); + jb_set_uint(js, "user_role", data->user_role); + jb_set_uint(js, "user_role_expiry_interval", data->user_role_expiry_interval); + jb_set_uint(js, "username_len", data->username_len); + jb_set_uint(js, "user_public_key_len", data->user_public_key_len); + jb_set_uint(js, "certification_data_len", data->certification_data_len); + if (data->username_len > 0) { + jb_set_string_from_bytes( + js, "username", (const uint8_t *)data->username, data->username_len); + } else { + jb_set_string(js, "username", ""); + } + jb_set_base64(js, "data->user_public_key", data->user_public_key, data->user_public_key_len); + jb_set_base64(js, "data->certification_data", data->certification_data, data->certification_data_len); + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *data = point->data; + jb_set_uint(js, "key_change_method", data->key_change_method); + jb_set_uint(js, "username_len", data->username_len); + jb_set_uint(js, "master_challenge_data_len", data->master_challenge_data_len); + if (data->username_len > 0) { + jb_set_string_from_bytes( + js, "username", (const uint8_t *)data->username, data->username_len); + } else { + jb_set_string(js, "username", ""); + } + jb_set_base64(js, "data->master_challenge_data", data->master_challenge_data, data->master_challenge_data_len); + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *data = point->data; + jb_set_uint(js, "ksq", data->ksq); + jb_set_uint(js, "user_number", data->user_number); + jb_set_uint(js, "challenge_data_len", data->challenge_data_len); + jb_set_base64(js, "data->challenge_data", data->challenge_data, data->challenge_data_len); + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *data = point->data; + jb_set_uint(js, "ksq", data->ksq); + jb_set_uint(js, "user_number", data->user_number); + jb_set_uint(js, "encrypted_update_key_len", data->encrypted_update_key_len); + jb_set_base64(js, "data->encrypted_update_key_data", data->encrypted_update_key_data, data->encrypted_update_key_len); + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *data = point->data; + jb_set_base64(js, "data->digital_signature", data->digital_signature, data->digital_signature_len); + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *data = point->data; + jb_set_base64(js, "data->mac", data->mac, data->mac_len); + break; + } + case DNP3_OBJECT_CODE(121, 1): { + DNP3ObjectG121V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "association_id", data->association_id); + jb_set_uint(js, "count_value", data->count_value); + break; + } + case DNP3_OBJECT_CODE(122, 1): { + DNP3ObjectG122V1 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "association_id", data->association_id); + jb_set_uint(js, "count_value", data->count_value); + break; + } + case DNP3_OBJECT_CODE(122, 2): { + DNP3ObjectG122V2 *data = point->data; + jb_set_uint(js, "online", data->online); + jb_set_uint(js, "restart", data->restart); + jb_set_uint(js, "comm_lost", data->comm_lost); + jb_set_uint(js, "remote_forced", data->remote_forced); + jb_set_uint(js, "local_forced", data->local_forced); + jb_set_uint(js, "reserved0", data->reserved0); + jb_set_uint(js, "discontinuity", data->discontinuity); + jb_set_uint(js, "reserved1", data->reserved1); + jb_set_uint(js, "association_id", data->association_id); + jb_set_uint(js, "count_value", data->count_value); + jb_set_uint(js, "timestamp", data->timestamp); + break; + } + default: + SCLogDebug("Unknown object: %d:%d", object->group, + object->variation); + break; + } + +} +// clang-format on diff --git a/src/app-layer/dnp3/logger-objects.h b/src/app-layer/dnp3/logger-objects.h new file mode 100644 index 000000000000..a8ac428f35b4 --- /dev/null +++ b/src/app-layer/dnp3/logger-objects.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __OUTPUT_JSON_DNP3_OBJECTS_H__ +#define __OUTPUT_JSON_DNP3_OBJECTS_H__ + +#include "rust-bindings.h" + +void OutputJsonDNP3SetItem(JsonBuilder *js, DNP3Object *object, DNP3Point *item); + +#endif /* __OUTPUT_JSON_DNP3_OBJECTS_H__ */ diff --git a/src/app-layer/dnp3/logger.c b/src/app-layer/dnp3/logger.c new file mode 100644 index 000000000000..626aa7d2f181 --- /dev/null +++ b/src/app-layer/dnp3/logger.c @@ -0,0 +1,370 @@ +/* Copyright (C) 2015-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/dnp3/parser.h" +#include "app-layer/dnp3/parser-objects.h" + +#include "app-layer/dnp3/detect.h" + +#include "output/output.h" +#include "output/eve/output-json.h" +#include "app-layer/dnp3/logger.h" +#include "app-layer/dnp3/logger-objects.h" + +typedef struct LogDNP3FileCtx_ { + uint32_t flags; + uint8_t include_object_data; + OutputJsonCtx *eve_ctx; +} LogDNP3FileCtx; + +typedef struct LogDNP3LogThread_ { + LogDNP3FileCtx *dnp3log_ctx; + OutputJsonThreadCtx *ctx; +} LogDNP3LogThread; + +static void JsonDNP3LogLinkControl(JsonBuilder *js, uint8_t lc) +{ + jb_set_bool(js, "dir", DNP3_LINK_DIR(lc)); + jb_set_bool(js, "pri", DNP3_LINK_PRI(lc)); + jb_set_bool(js, "fcb", DNP3_LINK_FCB(lc)); + jb_set_bool(js, "fcv", DNP3_LINK_FCV(lc)); + jb_set_uint(js, "function_code", DNP3_LINK_FC(lc)); +} + +static void JsonDNP3LogIin(JsonBuilder *js, uint16_t iin) +{ + if (iin) { + jb_open_array(js, "indicators"); + + int mapping = 0; + do { + if (iin & DNP3IndicatorsMap[mapping].value) { + jb_append_string(js, DNP3IndicatorsMap[mapping].name); + } + mapping++; + } while (DNP3IndicatorsMap[mapping].name != NULL); + jb_close(js); + } +} + +static void JsonDNP3LogApplicationControl(JsonBuilder *js, uint8_t ac) +{ + jb_set_bool(js, "fir", DNP3_APP_FIR(ac)); + jb_set_bool(js, "fin", DNP3_APP_FIN(ac)); + jb_set_bool(js, "con", DNP3_APP_CON(ac)); + jb_set_bool(js, "uns", DNP3_APP_UNS(ac)); + jb_set_uint(js, "sequence", DNP3_APP_SEQ(ac)); +} + +/** + * \brief Log the items (points) for an object. + * + * TODO: Autogenerate this function based on object definitions. + */ +static void JsonDNP3LogObjectItems(JsonBuilder *js, DNP3Object *object) +{ + DNP3Point *item; + + TAILQ_FOREACH (item, object->points, next) { + jb_start_object(js); + + jb_set_uint(js, "prefix", item->prefix); + jb_set_uint(js, "index", item->index); + if (DNP3PrefixIsSize(object->prefix_code)) { + jb_set_uint(js, "size", item->size); + } + + OutputJsonDNP3SetItem(js, object, item); + jb_close(js); + } +} + +/** + * \brief Log the application layer objects. + * + * \param objects A list of DNP3 objects. + * \param jb A JsonBuilder instance with an open array. + */ +static void JsonDNP3LogObjects(JsonBuilder *js, DNP3ObjectList *objects) +{ + DNP3Object *object; + + TAILQ_FOREACH (object, objects, next) { + jb_start_object(js); + jb_set_uint(js, "group", object->group); + jb_set_uint(js, "variation", object->variation); + jb_set_uint(js, "qualifier", object->qualifier); + jb_set_uint(js, "prefix_code", object->prefix_code); + jb_set_uint(js, "range_code", object->range_code); + jb_set_uint(js, "start", object->start); + jb_set_uint(js, "stop", object->stop); + jb_set_uint(js, "count", object->count); + + if (object->points != NULL && !TAILQ_EMPTY(object->points)) { + jb_open_array(js, "points"); + JsonDNP3LogObjectItems(js, object); + jb_close(js); + } + + jb_close(js); + } +} + +void JsonDNP3LogRequest(JsonBuilder *js, DNP3Transaction *dnp3tx) +{ + JB_SET_STRING(js, "type", "request"); + + jb_open_object(js, "control"); + JsonDNP3LogLinkControl(js, dnp3tx->lh.control); + jb_close(js); + + jb_set_uint(js, "src", DNP3_SWAP16(dnp3tx->lh.src)); + jb_set_uint(js, "dst", DNP3_SWAP16(dnp3tx->lh.dst)); + + jb_open_object(js, "application"); + + jb_open_object(js, "control"); + JsonDNP3LogApplicationControl(js, dnp3tx->ah.control); + jb_close(js); + + jb_set_uint(js, "function_code", dnp3tx->ah.function_code); + + if (!TAILQ_EMPTY(&dnp3tx->objects)) { + jb_open_array(js, "objects"); + JsonDNP3LogObjects(js, &dnp3tx->objects); + jb_close(js); + } + + jb_set_bool(js, "complete", dnp3tx->complete); + + /* Close application. */ + jb_close(js); +} + +void JsonDNP3LogResponse(JsonBuilder *js, DNP3Transaction *dnp3tx) +{ + if (dnp3tx->ah.function_code == DNP3_APP_FC_UNSOLICITED_RESP) { + JB_SET_STRING(js, "type", "unsolicited_response"); + } else { + JB_SET_STRING(js, "type", "response"); + } + + jb_open_object(js, "control"); + JsonDNP3LogLinkControl(js, dnp3tx->lh.control); + jb_close(js); + + jb_set_uint(js, "src", DNP3_SWAP16(dnp3tx->lh.src)); + jb_set_uint(js, "dst", DNP3_SWAP16(dnp3tx->lh.dst)); + + jb_open_object(js, "application"); + + jb_open_object(js, "control"); + JsonDNP3LogApplicationControl(js, dnp3tx->ah.control); + jb_close(js); + + jb_set_uint(js, "function_code", dnp3tx->ah.function_code); + + if (!TAILQ_EMPTY(&dnp3tx->objects)) { + jb_open_array(js, "objects"); + JsonDNP3LogObjects(js, &dnp3tx->objects); + jb_close(js); + } + + jb_set_bool(js, "complete", dnp3tx->complete); + + /* Close application. */ + jb_close(js); + + jb_open_object(js, "iin"); + JsonDNP3LogIin(js, (uint16_t)(dnp3tx->iin.iin1 << 8 | dnp3tx->iin.iin2)); + jb_close(js); +} + +bool AlertJsonDnp3(void *vtx, JsonBuilder *js) +{ + DNP3Transaction *tx = (DNP3Transaction *)vtx; + bool logged = false; + jb_open_object(js, "dnp3"); + if (tx->is_request && tx->done) { + jb_open_object(js, "request"); + JsonDNP3LogRequest(js, tx); + jb_close(js); + logged = true; + } + if (!tx->is_request && tx->done) { + jb_open_object(js, "response"); + JsonDNP3LogResponse(js, tx); + jb_close(js); + logged = true; + } + jb_close(js); + return logged; +} + +static int JsonDNP3LoggerToServer(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *vtx, uint64_t tx_id) +{ + SCEnter(); + LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; + DNP3Transaction *tx = vtx; + + JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "dnp3", NULL, thread->dnp3log_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + + jb_open_object(js, "dnp3"); + JsonDNP3LogRequest(js, tx); + jb_close(js); + OutputJsonBuilderBuffer(js, thread->ctx); + jb_free(js); + + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDNP3LoggerToClient(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *vtx, uint64_t tx_id) +{ + SCEnter(); + LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; + DNP3Transaction *tx = vtx; + + JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "dnp3", NULL, thread->dnp3log_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + + jb_open_object(js, "dnp3"); + JsonDNP3LogResponse(js, tx); + jb_close(js); + OutputJsonBuilderBuffer(js, thread->ctx); + jb_free(js); + + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDNP3Logger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *vtx, uint64_t tx_id) +{ + SCEnter(); + DNP3Transaction *tx = vtx; + if (tx->is_request && tx->done) { + JsonDNP3LoggerToServer(tv, thread_data, p, f, state, vtx, tx_id); + } else if (!tx->is_request && tx->done) { + JsonDNP3LoggerToClient(tv, thread_data, p, f, state, vtx, tx_id); + } + SCReturnInt(TM_ECODE_OK); +} + +static void OutputDNP3LogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + LogDNP3FileCtx *dnp3log_ctx = (LogDNP3FileCtx *)output_ctx->data; + SCFree(dnp3log_ctx); + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "dnp3.json" + +static OutputInitResult OutputDNP3LogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *json_ctx = parent_ctx->data; + + LogDNP3FileCtx *dnp3log_ctx = SCCalloc(1, sizeof(*dnp3log_ctx)); + if (unlikely(dnp3log_ctx == NULL)) { + return result; + } + dnp3log_ctx->eve_ctx = json_ctx; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(dnp3log_ctx); + return result; + } + output_ctx->data = dnp3log_ctx; + output_ctx->DeInit = OutputDNP3LogDeInitCtxSub; + + SCLogInfo("DNP3 log sub-module initialized."); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNP3); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonDNP3LogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogDNP3LogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for DNP3. \"initdata\" is NULL."); + goto error_exit; + } + + thread->dnp3log_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->dnp3log_ctx->eve_ctx); + if (thread->ctx == NULL) { + goto error_exit; + } + + *data = (void *)thread; + + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonDNP3LogThreadDeinit(ThreadVars *t, void *data) +{ + LogDNP3LogThread *thread = (LogDNP3LogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonDNP3LogRegister(void) +{ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonDNP3Log", "eve-log.dnp3", + OutputDNP3LogInitSub, ALPROTO_DNP3, JsonDNP3Logger, JsonDNP3LogThreadInit, + JsonDNP3LogThreadDeinit, NULL); +} diff --git a/src/app-layer/dnp3/logger.h b/src/app-layer/dnp3/logger.h new file mode 100644 index 000000000000..b2e3c117711c --- /dev/null +++ b/src/app-layer/dnp3/logger.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __OUTPUT_JSON_DNP3_H__ +#define __OUTPUT_JSON_DNP3_H__ + +#include "app-layer/dnp3/parser.h" + +void JsonDNP3LogRequest(JsonBuilder *js, DNP3Transaction *); +void JsonDNP3LogResponse(JsonBuilder *js, DNP3Transaction *); + +void JsonDNP3LogRegister(void); +bool AlertJsonDnp3(void *vtx, JsonBuilder *js); + +#endif /* __OUTPUT_JSON_DNP3_H__ */ diff --git a/src/app-layer/dnp3/lua-objects.c b/src/app-layer/dnp3/lua-objects.c new file mode 100644 index 000000000000..9a49ae524839 --- /dev/null +++ b/src/app-layer/dnp3/lua-objects.c @@ -0,0 +1,3522 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +#include "suricata-common.h" + +#include "app-layer/dnp3/parser.h" +#include "app-layer/dnp3/parser-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "app-layer/dnp3/lua-objects.h" + +/** + * \brief Push an object point item onto the stack. + */ +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, DNP3Point *point) +{ + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { + case DNP3_OBJECT_CODE(1, 1): { + DNP3ObjectG1V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(1, 2): { + DNP3ObjectG1V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 1): { + DNP3ObjectG2V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 2): { + DNP3ObjectG2V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 3): { + DNP3ObjectG2V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(3, 1): { + DNP3ObjectG3V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(3, 2): { + DNP3ObjectG3V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 1): { + DNP3ObjectG4V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 2): { + DNP3ObjectG4V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 3): { + DNP3ObjectG4V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "relative_time_ms"); + lua_pushinteger(luastate, data->relative_time_ms); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(10, 1): { + DNP3ObjectG10V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(10, 2): { + DNP3ObjectG10V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(11, 1): { + DNP3ObjectG11V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(11, 2): { + DNP3ObjectG11V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 1): { + DNP3ObjectG12V1 *data = point->data; + lua_pushliteral(luastate, "op_type"); + lua_pushinteger(luastate, data->op_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "qu"); + lua_pushinteger(luastate, data->qu); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "cr"); + lua_pushinteger(luastate, data->cr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "tcc"); + lua_pushinteger(luastate, data->tcc); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ontime"); + lua_pushinteger(luastate, data->ontime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "offtime"); + lua_pushinteger(luastate, data->offtime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 2): { + DNP3ObjectG12V2 *data = point->data; + lua_pushliteral(luastate, "op_type"); + lua_pushinteger(luastate, data->op_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "qu"); + lua_pushinteger(luastate, data->qu); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "cr"); + lua_pushinteger(luastate, data->cr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "tcc"); + lua_pushinteger(luastate, data->tcc); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ontime"); + lua_pushinteger(luastate, data->ontime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "offtime"); + lua_pushinteger(luastate, data->offtime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 3): { + DNP3ObjectG12V3 *data = point->data; + lua_pushliteral(luastate, "point"); + lua_pushinteger(luastate, data->point); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(13, 1): { + DNP3ObjectG13V1 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_state"); + lua_pushinteger(luastate, data->commanded_state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(13, 2): { + DNP3ObjectG13V2 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_state"); + lua_pushinteger(luastate, data->commanded_state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 1): { + DNP3ObjectG20V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 2): { + DNP3ObjectG20V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 3): { + DNP3ObjectG20V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 4): { + DNP3ObjectG20V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 5): { + DNP3ObjectG20V5 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 6): { + DNP3ObjectG20V6 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 7): { + DNP3ObjectG20V7 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 8): { + DNP3ObjectG20V8 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 1): { + DNP3ObjectG21V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 2): { + DNP3ObjectG21V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 3): { + DNP3ObjectG21V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 4): { + DNP3ObjectG21V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 5): { + DNP3ObjectG21V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 6): { + DNP3ObjectG21V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 7): { + DNP3ObjectG21V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 8): { + DNP3ObjectG21V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 9): { + DNP3ObjectG21V9 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 10): { + DNP3ObjectG21V10 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 11): { + DNP3ObjectG21V11 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 12): { + DNP3ObjectG21V12 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 1): { + DNP3ObjectG22V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 2): { + DNP3ObjectG22V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 3): { + DNP3ObjectG22V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 4): { + DNP3ObjectG22V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 5): { + DNP3ObjectG22V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 6): { + DNP3ObjectG22V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 7): { + DNP3ObjectG22V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 8): { + DNP3ObjectG22V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 1): { + DNP3ObjectG23V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 2): { + DNP3ObjectG23V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 3): { + DNP3ObjectG23V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 4): { + DNP3ObjectG23V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 5): { + DNP3ObjectG23V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 6): { + DNP3ObjectG23V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 7): { + DNP3ObjectG23V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 8): { + DNP3ObjectG23V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 1): { + DNP3ObjectG30V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 2): { + DNP3ObjectG30V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 3): { + DNP3ObjectG30V3 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 4): { + DNP3ObjectG30V4 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 5): { + DNP3ObjectG30V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 6): { + DNP3ObjectG30V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 1): { + DNP3ObjectG31V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 2): { + DNP3ObjectG31V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 3): { + DNP3ObjectG31V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 4): { + DNP3ObjectG31V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 5): { + DNP3ObjectG31V5 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 6): { + DNP3ObjectG31V6 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 7): { + DNP3ObjectG31V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 8): { + DNP3ObjectG31V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 1): { + DNP3ObjectG32V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 2): { + DNP3ObjectG32V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 3): { + DNP3ObjectG32V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 4): { + DNP3ObjectG32V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 5): { + DNP3ObjectG32V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 6): { + DNP3ObjectG32V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 7): { + DNP3ObjectG32V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 8): { + DNP3ObjectG32V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 1): { + DNP3ObjectG33V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 2): { + DNP3ObjectG33V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 3): { + DNP3ObjectG33V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 4): { + DNP3ObjectG33V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 5): { + DNP3ObjectG33V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 6): { + DNP3ObjectG33V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 7): { + DNP3ObjectG33V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 8): { + DNP3ObjectG33V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 1): { + DNP3ObjectG34V1 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushinteger(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 2): { + DNP3ObjectG34V2 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushinteger(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 3): { + DNP3ObjectG34V3 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushnumber(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 1): { + DNP3ObjectG40V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 2): { + DNP3ObjectG40V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 3): { + DNP3ObjectG40V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 4): { + DNP3ObjectG40V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 1): { + DNP3ObjectG41V1 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 2): { + DNP3ObjectG41V2 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 3): { + DNP3ObjectG41V3 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 4): { + DNP3ObjectG41V4 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 1): { + DNP3ObjectG42V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 2): { + DNP3ObjectG42V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 3): { + DNP3ObjectG42V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 4): { + DNP3ObjectG42V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 5): { + DNP3ObjectG42V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 6): { + DNP3ObjectG42V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 7): { + DNP3ObjectG42V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 8): { + DNP3ObjectG42V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 1): { + DNP3ObjectG43V1 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 2): { + DNP3ObjectG43V2 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 3): { + DNP3ObjectG43V3 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 4): { + DNP3ObjectG43V4 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 5): { + DNP3ObjectG43V5 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 6): { + DNP3ObjectG43V6 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 7): { + DNP3ObjectG43V7 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 8): { + DNP3ObjectG43V8 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 1): { + DNP3ObjectG50V1 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 2): { + DNP3ObjectG50V2 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval"); + lua_pushinteger(luastate, data->interval); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 3): { + DNP3ObjectG50V3 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 4): { + DNP3ObjectG50V4 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval_count"); + lua_pushinteger(luastate, data->interval_count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval_units"); + lua_pushinteger(luastate, data->interval_units); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(51, 1): { + DNP3ObjectG51V1 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(51, 2): { + DNP3ObjectG51V2 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(52, 1): { + DNP3ObjectG52V1 *data = point->data; + lua_pushliteral(luastate, "delay_secs"); + lua_pushinteger(luastate, data->delay_secs); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(52, 2): { + DNP3ObjectG52V2 *data = point->data; + lua_pushliteral(luastate, "delay_ms"); + lua_pushinteger(luastate, data->delay_ms); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 1): { + DNP3ObjectG70V1 *data = point->data; + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filetype_code"); + lua_pushinteger(luastate, data->filetype_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "attribute_code"); + lua_pushinteger(luastate, data->attribute_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "start_record"); + lua_pushinteger(luastate, data->start_record); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "end_record"); + lua_pushinteger(luastate, data->end_record); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created_timestamp"); + lua_pushinteger(luastate, data->created_timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permission"); + lua_pushinteger(luastate, data->permission); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_id"); + lua_pushinteger(luastate, data->file_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "owner_id"); + lua_pushinteger(luastate, data->owner_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "group_id"); + lua_pushinteger(luastate, data->group_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_function_code"); + lua_pushinteger(luastate, data->file_function_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, strlen(data->filename)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data_size"); + lua_pushinteger(luastate, data->data_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data"); + LuaPushStringBuffer(luastate, (uint8_t *)data->data, strlen(data->data)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 2): { + DNP3ObjectG70V2 *data = point->data; + lua_pushliteral(luastate, "username_offset"); + lua_pushinteger(luastate, data->username_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_size"); + lua_pushinteger(luastate, data->username_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password_offset"); + lua_pushinteger(luastate, data->password_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password_size"); + lua_pushinteger(luastate, data->password_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "authentication_key"); + lua_pushinteger(luastate, data->authentication_key); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password"); + LuaPushStringBuffer(luastate, (uint8_t *)data->password, strlen(data->password)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 3): { + DNP3ObjectG70V3 *data = point->data; + lua_pushliteral(luastate, "filename_offset"); + lua_pushinteger(luastate, data->filename_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created"); + lua_pushinteger(luastate, data->created); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permissions"); + lua_pushinteger(luastate, data->permissions); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "authentication_key"); + lua_pushinteger(luastate, data->authentication_key); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "operational_mode"); + lua_pushinteger(luastate, data->operational_mode); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "maximum_block_size"); + lua_pushinteger(luastate, data->maximum_block_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, strlen(data->filename)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 4): { + DNP3ObjectG70V4 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "maximum_block_size"); + lua_pushinteger(luastate, data->maximum_block_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "optional_text"); + LuaPushStringBuffer( + luastate, (uint8_t *)data->optional_text, strlen(data->optional_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 5): { + DNP3ObjectG70V5 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "block_number"); + lua_pushinteger(luastate, data->block_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_data"); + LuaPushStringBuffer(luastate, (uint8_t *)data->file_data, strlen(data->file_data)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 6): { + DNP3ObjectG70V6 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "block_number"); + lua_pushinteger(luastate, data->block_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "optional_text"); + LuaPushStringBuffer( + luastate, (uint8_t *)data->optional_text, strlen(data->optional_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 7): { + DNP3ObjectG70V7 *data = point->data; + lua_pushliteral(luastate, "filename_offset"); + lua_pushinteger(luastate, data->filename_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_type"); + lua_pushinteger(luastate, data->file_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created_timestamp"); + lua_pushinteger(luastate, data->created_timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permissions"); + lua_pushinteger(luastate, data->permissions); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, strlen(data->filename)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 8): { + DNP3ObjectG70V8 *data = point->data; + lua_pushliteral(luastate, "file_specification"); + LuaPushStringBuffer(luastate, (uint8_t *)data->file_specification, + strlen(data->file_specification)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(80, 1): { + DNP3ObjectG80V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(81, 1): { + DNP3ObjectG81V1 *data = point->data; + lua_pushliteral(luastate, "fill_percentage"); + lua_pushinteger(luastate, data->fill_percentage); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "overflow_state"); + lua_pushinteger(luastate, data->overflow_state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "group"); + lua_pushinteger(luastate, data->group); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "variation"); + lua_pushinteger(luastate, data->variation); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *data = point->data; + lua_pushliteral(luastate, "vendor_code"); + LuaPushStringBuffer(luastate, (uint8_t *)data->vendor_code, strlen(data->vendor_code)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "object_id"); + lua_pushinteger(luastate, data->object_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "length"); + lua_pushinteger(luastate, data->length); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data_objects"); + lua_pushlstring(luastate, (const char *)data->data_objects, data->length); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(86, 2): { + DNP3ObjectG86V2 *data = point->data; + lua_pushliteral(luastate, "rd"); + lua_pushinteger(luastate, data->rd); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "wr"); + lua_pushinteger(luastate, data->wr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "st"); + lua_pushinteger(luastate, data->st); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ev"); + lua_pushinteger(luastate, data->ev); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "df"); + lua_pushinteger(luastate, data->df); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding0"); + lua_pushinteger(luastate, data->padding0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding1"); + lua_pushinteger(luastate, data->padding1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding2"); + lua_pushinteger(luastate, data->padding2); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(102, 1): { + DNP3ObjectG102V1 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mal"); + lua_pushinteger(luastate, data->mal); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reason"); + lua_pushinteger(luastate, data->reason); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, data->challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 3): { + DNP3ObjectG120V3 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 4): { + DNP3ObjectG120V4 *data = point->data; + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "key_wrap_alg"); + lua_pushinteger(luastate, data->key_wrap_alg); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "key_status"); + lua_pushinteger(luastate, data->key_status); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mal"); + lua_pushinteger(luastate, data->mal); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data_len"); + lua_pushinteger(luastate, data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "wrapped_key_data"); + lua_pushlstring( + luastate, (const char *)data->wrapped_key_data, data->wrapped_key_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 7): { + DNP3ObjectG120V7 *data = point->data; + lua_pushliteral(luastate, "sequence_number"); + lua_pushinteger(luastate, data->sequence_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "error_code"); + lua_pushinteger(luastate, data->error_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "time_of_error"); + lua_pushinteger(luastate, data->time_of_error); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "error_text"); + LuaPushStringBuffer(luastate, (uint8_t *)data->error_text, strlen(data->error_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certificate_type"); + lua_pushinteger(luastate, data->certificate_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certificate"); + lua_pushlstring(luastate, (const char *)data->certificate, data->certificate_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *data = point->data; + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "operation"); + lua_pushinteger(luastate, data->operation); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "scs"); + lua_pushinteger(luastate, data->scs); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_role"); + lua_pushinteger(luastate, data->user_role); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_role_expiry_interval"); + lua_pushinteger(luastate, data->user_role_expiry_interval); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_len"); + lua_pushinteger(luastate, data->username_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_public_key_len"); + lua_pushinteger(luastate, data->user_public_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certification_data_len"); + lua_pushinteger(luastate, data->certification_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_public_key"); + lua_pushlstring( + luastate, (const char *)data->user_public_key, data->user_public_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certification_data"); + lua_pushlstring( + luastate, (const char *)data->certification_data, data->certification_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_len"); + lua_pushinteger(luastate, data->username_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "master_challenge_data_len"); + lua_pushinteger(luastate, data->master_challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "master_challenge_data"); + lua_pushlstring(luastate, (const char *)data->master_challenge_data, + data->master_challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data_len"); + lua_pushinteger(luastate, data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, data->challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "encrypted_update_key_len"); + lua_pushinteger(luastate, data->encrypted_update_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "encrypted_update_key_data"); + lua_pushlstring(luastate, (const char *)data->encrypted_update_key_data, + data->encrypted_update_key_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *data = point->data; + lua_pushliteral(luastate, "digital_signature"); + lua_pushlstring( + luastate, (const char *)data->digital_signature, data->digital_signature_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *data = point->data; + lua_pushliteral(luastate, "mac"); + lua_pushlstring(luastate, (const char *)data->mac, data->mac_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(121, 1): { + DNP3ObjectG121V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(122, 1): { + DNP3ObjectG122V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(122, 2): { + DNP3ObjectG122V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + default: + break; + } +} + +#endif /* HAVE_LUA */ diff --git a/src/app-layer/dnp3/lua-objects.h b/src/app-layer/dnp3/lua-objects.h new file mode 100644 index 000000000000..8de14a1b9a86 --- /dev/null +++ b/src/app-layer/dnp3/lua-objects.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_LUA_DNP3_OBJECTS_H__ +#define __UTIL_LUA_DNP3_OBJECTS_H__ + +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, DNP3Point *item); + +#endif /* ! __UTIL_LUA_DNP3_OBJECTS_H__ */ diff --git a/src/app-layer/dnp3/lua.c b/src/app-layer/dnp3/lua.c new file mode 100644 index 000000000000..664cda27138a --- /dev/null +++ b/src/app-layer/dnp3/lua.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" + +#include "app-layer/dnp3/parser.h" +#include "app-layer/dnp3/parser-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/dnp3/lua.h" +#include "app-layer/dnp3/lua-objects.h" + +/** + * \brief Helper macro to push key and integer value onto a table. + */ +#define LUA_PUSHT_INT(l, k, v) \ + do { \ + lua_pushliteral(luastate, k); \ + lua_pushinteger(luastate, v); \ + lua_settable(luastate, -3); \ + } while (0); + +static void DNP3PushPoints(lua_State *luastate, DNP3Object *object) +{ + DNP3Point *point; + int i = 1; + + TAILQ_FOREACH (point, object->points, next) { + lua_pushinteger(luastate, i++); + lua_newtable(luastate); + + lua_pushliteral(luastate, "index"); + lua_pushinteger(luastate, point->index); + lua_settable(luastate, -3); + + DNP3PushPoint(luastate, object, point); + + lua_settable(luastate, -3); + } +} + +static void DNP3PushObjects(lua_State *luastate, DNP3ObjectList *objects) +{ + DNP3Object *object = NULL; + int i = 1; + + TAILQ_FOREACH (object, objects, next) { + lua_pushinteger(luastate, i++); + lua_newtable(luastate); + + lua_pushliteral(luastate, "group"); + lua_pushinteger(luastate, object->group); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "variation"); + lua_pushinteger(luastate, object->variation); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "points"); + lua_newtable(luastate); + DNP3PushPoints(luastate, object); + lua_settable(luastate, -3); + + lua_settable(luastate, -3); + } +} + +static void DNP3PushLinkHeader(lua_State *luastate, DNP3LinkHeader *header) +{ + LUA_PUSHT_INT(luastate, "len", header->len); + LUA_PUSHT_INT(luastate, "control", header->control); + LUA_PUSHT_INT(luastate, "dst", header->dst); + LUA_PUSHT_INT(luastate, "src", header->src); + LUA_PUSHT_INT(luastate, "crc", header->crc); +} + +static void DNP3PushApplicationHeader(lua_State *luastate, DNP3ApplicationHeader *header) +{ + LUA_PUSHT_INT(luastate, "control", header->control); + LUA_PUSHT_INT(luastate, "function_code", header->function_code); +} + +static void DNP3PushRequest(lua_State *luastate, DNP3Transaction *tx) +{ + /* Link header. */ + lua_pushliteral(luastate, "link_header"); + lua_newtable(luastate); + DNP3PushLinkHeader(luastate, &tx->lh); + lua_settable(luastate, -3); + + /* Transport header. */ + LUA_PUSHT_INT(luastate, "transport_header", tx->th); + + /* Application header. */ + lua_pushliteral(luastate, "application_header"); + lua_newtable(luastate); + DNP3PushApplicationHeader(luastate, &tx->ah); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "objects"); + lua_newtable(luastate); + DNP3PushObjects(luastate, &tx->objects); + lua_settable(luastate, -3); +} + +static void DNP3PushResponse(lua_State *luastate, DNP3Transaction *tx) +{ + /* Link header. */ + lua_pushliteral(luastate, "link_header"); + lua_newtable(luastate); + DNP3PushLinkHeader(luastate, &tx->lh); + lua_settable(luastate, -3); + + /* Transport header. */ + LUA_PUSHT_INT(luastate, "transport_header", tx->th); + + /* Application header. */ + lua_pushliteral(luastate, "application_header"); + lua_newtable(luastate); + DNP3PushApplicationHeader(luastate, &tx->ah); + lua_settable(luastate, -3); + + /* Internal indicators. */ + LUA_PUSHT_INT(luastate, "indicators", tx->iin.iin1 << 8 | tx->iin.iin2); + + lua_pushliteral(luastate, "objects"); + lua_newtable(luastate); + DNP3PushObjects(luastate, &tx->objects); + lua_settable(luastate, -3); +} + +static int DNP3GetTx(lua_State *luastate) +{ + if (!LuaStateNeedProto(luastate, ALPROTO_DNP3)) { + return LuaCallbackError(luastate, "error: protocol not dnp3"); + } + + DNP3Transaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "error: no tx"); + } + + lua_newtable(luastate); + + lua_pushliteral(luastate, "tx_num"); + lua_pushinteger(luastate, tx->tx_num); + lua_settable(luastate, -3); + + LUA_PUSHT_INT(luastate, "has_request", tx->is_request ? 1 : 0); + if (tx->is_request) { + lua_pushliteral(luastate, "request"); + lua_newtable(luastate); + LUA_PUSHT_INT(luastate, "done", tx->done); + LUA_PUSHT_INT(luastate, "complete", tx->complete); + DNP3PushRequest(luastate, tx); + lua_settable(luastate, -3); + } + + LUA_PUSHT_INT(luastate, "has_response", tx->is_request ? 0 : 1); + if (!tx->is_request) { + lua_pushliteral(luastate, "response"); + lua_newtable(luastate); + LUA_PUSHT_INT(luastate, "done", tx->done); + LUA_PUSHT_INT(luastate, "complete", tx->complete); + DNP3PushResponse(luastate, tx); + lua_settable(luastate, -3); + } + + return 1; +} + +int LuaRegisterDNP3Functions(lua_State *luastate) +{ + lua_pushcfunction(luastate, DNP3GetTx); + lua_setglobal(luastate, "DNP3GetTx"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dnp3.h b/src/app-layer/dnp3/lua.h similarity index 100% rename from src/util-lua-dnp3.h rename to src/app-layer/dnp3/lua.h diff --git a/src/app-layer/dnp3/parser-objects.c b/src/app-layer/dnp3/parser-objects.c new file mode 100644 index 000000000000..bb64e1d34122 --- /dev/null +++ b/src/app-layer/dnp3/parser-objects.c @@ -0,0 +1,9414 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jason Ish + * + * This file contains the DNP3 object decoders. + */ + +#include "suricata-common.h" + +#include "app-layer/dnp3/parser.h" +#include "app-layer/dnp3/parser-objects.h" + +void DNP3FreeObjectPoint(int group, int variation, void *point); + +#if 0 +static void DNP3HexDump(uint8_t *data, int len) +{ + for (int i = 0; i < len; i++) { + printf("%02x ", data[i]); + } +} +#endif + +/** + * \brief Allocate a list for DNP3 points. + */ +DNP3PointList *DNP3PointListAlloc(void) +{ + DNP3PointList *items = SCCalloc(1, sizeof(*items)); + if (unlikely(items == NULL)) { + return NULL; + } + TAILQ_INIT(items); + return items; +} + +/** + * \brief Free a DNP3PointList. + */ +void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *list) +{ + DNP3Point *point; + while ((point = TAILQ_FIRST(list)) != NULL) { + TAILQ_REMOVE(list, point, next); + if (point->data != NULL) { + DNP3FreeObjectPoint(group, variation, point->data); + } + SCFree(point); + } + SCFree(list); +} + +/** + * \brief Read an uint8_t from a buffer. + * + * Reads a uint8_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint8(const uint8_t **buf, uint32_t *len, uint8_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = *(uint8_t *)(*buf); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an uint16_t from a buffer. + * + * Reads an uint16_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint16(const uint8_t **buf, uint32_t *len, uint16_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = DNP3_SWAP16(*(uint16_t *)(*buf)); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an unsigned 24 bit integer from a buffer. + * + * Reads an an unsigned 24 bit integer from a buffer advancing the + * pointer and decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint24(const uint8_t **buf, uint32_t *len, uint32_t *out) +{ + if (*len < (int)(sizeof(uint8_t) * 3)) { + return 0; + } + +#if __BYTE_ORDER__ == __BIG_ENDIAN + *out = ((uint32_t)(*buf)[0] << 16) | ((uint32_t)(*buf)[1] << 8) | (uint32_t)(*buf)[2]; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | ((uint64_t)(*buf)[2] << 16); +#endif + + *buf += 3; + *len -= 3; + + return 1; +} + +/** + * \brief Read an uint32_t from a buffer. + * + * Reads an uint32_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint32(const uint8_t **buf, uint32_t *len, uint32_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = DNP3_SWAP32(*(uint32_t *)(*buf)); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an unsigned 48 bit integer from a buffer. + * + * Reads an an unsigned 48 bit integer from a buffer advancing the + * pointer and decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint48(const uint8_t **buf, uint32_t *len, uint64_t *out) +{ + if (*len < (int)(sizeof(uint8_t) * 6)) { + return 0; + } + +#if __BYTE_ORDER__ == __BIG_ENDIAN + *out = ((uint64_t)(*buf)[0] << 40) | ((uint64_t)(*buf)[1] << 32) | ((uint64_t)(*buf)[2] << 24) | + ((uint64_t)(*buf)[3] << 16) | ((uint64_t)(*buf)[4] << 8) | (uint64_t)(*buf)[5]; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | ((uint64_t)(*buf)[2] << 16) | + ((uint64_t)(*buf)[3] << 24) | ((uint64_t)(*buf)[4] << 32) | ((uint64_t)(*buf)[5] << 40); +#endif + + *buf += 6; + *len -= 6; + + return 1; +} + +/** + * \brief Read a 32 bit float from a buffer. + * + * Reads an 32 bit float from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadFloat32(const uint8_t **buf, uint32_t *len, float *out) +{ + if (*len < 4) { + return 0; + } + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *((uint8_t *)out + 0) = (*buf)[0]; + *((uint8_t *)out + 1) = (*buf)[1]; + *((uint8_t *)out + 2) = (*buf)[2]; + *((uint8_t *)out + 3) = (*buf)[3]; +#else + *((uint8_t *)out + 3) = (*buf)[0]; + *((uint8_t *)out + 2) = (*buf)[1]; + *((uint8_t *)out + 1) = (*buf)[2]; + *((uint8_t *)out + 0) = (*buf)[3]; +#endif + *len -= 4; + *buf += 4; + + return 1; +} + +/** + * \brief Read a 64 bit float from a buffer. + * + * Reads an 64 bit float from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadFloat64(const uint8_t **buf, uint32_t *len, double *out) +{ + if (*len < 8) { + return 0; + } + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *((uint8_t *)out + 0) = (*buf)[0]; + *((uint8_t *)out + 1) = (*buf)[1]; + *((uint8_t *)out + 2) = (*buf)[2]; + *((uint8_t *)out + 3) = (*buf)[3]; + *((uint8_t *)out + 4) = (*buf)[4]; + *((uint8_t *)out + 5) = (*buf)[5]; + *((uint8_t *)out + 6) = (*buf)[6]; + *((uint8_t *)out + 7) = (*buf)[7]; +#else + *((uint8_t *)out + 7) = (*buf)[0]; + *((uint8_t *)out + 6) = (*buf)[1]; + *((uint8_t *)out + 5) = (*buf)[2]; + *((uint8_t *)out + 4) = (*buf)[3]; + *((uint8_t *)out + 3) = (*buf)[4]; + *((uint8_t *)out + 2) = (*buf)[5]; + *((uint8_t *)out + 1) = (*buf)[6]; + *((uint8_t *)out + 0) = (*buf)[7]; +#endif + *len -= 8; + *buf += 8; + + return 1; +} + +/** + * \brief Get the prefix value and advance the buffer. + */ +static int DNP3ReadPrefix(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, uint32_t *out) +{ + uint8_t prefix_len = 0; + + switch (prefix_code) { + case 0x01: + case 0x04: + prefix_len = 1; + break; + case 0x02: + case 0x05: + prefix_len = 2; + break; + case 0x03: + case 0x06: + prefix_len = 4; + default: + break; + } + + if (*len < (uint32_t)prefix_len) { + return 0; + } + + switch (prefix_len) { + case sizeof(uint32_t): + if (!DNP3ReadUint32(buf, len, out)) { + return 0; + } + break; + case sizeof(uint16_t): { + /* Temp value for strict-aliasing. */ + uint16_t val = 0; + if (!DNP3ReadUint16(buf, len, &val)) { + return 0; + } + *out = val; + break; + } + case sizeof(uint8_t): { + /* Temp value for strict-aliasing. */ + uint8_t val = 0; + if (!DNP3ReadUint8(buf, len, &val)) { + return 0; + } + *out = val; + break; + } + default: + *out = 0; + break; + } + + return 1; +} + +/** + * \brief Add an object to a DNP3PointList. + * + * \retval 1 if successful, 0 on failure. + */ +static int DNP3AddPoint(DNP3PointList *list, void *object, uint32_t point_index, + uint8_t prefix_code, uint32_t prefix) +{ + DNP3Point *point = SCCalloc(1, sizeof(*point)); + if (unlikely(point == NULL)) { + return 0; + } + TAILQ_INSERT_TAIL(list, point, next); + point->data = object; + point->prefix = prefix; + point->index = point_index; + switch (prefix_code) { + case 0x00: + break; + case 0x01: + case 0x02: + case 0x03: + point->index = prefix; + break; + case 0x04: + case 0x05: + case 0x06: + point->size = prefix; + break; + default: + break; + } + + return 1; +} + +/* START GENERATED CODE */ + +/* Code generated by: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +static int DNP3DecodeObjectG1V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG1V1 *object = NULL; + uint32_t bytes = (count / 8) + 1; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (uint32_t i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG1V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG1V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG2V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->state)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG2V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG2V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG3V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG3V1 *object = NULL; + uint32_t bytes = (count / 8) + 1; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (uint32_t i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 2) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x3; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG3V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG3V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG4V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG4V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG4V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint16(buf, len, &object->relative_time_ms)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG10V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG10V1 *object = NULL; + uint32_t bytes = (count / 8) + 1; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (uint32_t i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG10V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG10V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG11V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG11V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG11V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG11V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG12V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->op_type = (octet >> 0) & 0xf; + object->qu = (octet >> 4) & 0x1; + object->cr = (octet >> 5) & 0x1; + object->tcc = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint8(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->ontime)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->offtime)) { + goto error; + } + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG12V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->op_type = (octet >> 0) & 0xf; + object->qu = (octet >> 4) & 0x1; + object->cr = (octet >> 5) & 0x1; + object->tcc = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint8(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->ontime)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->offtime)) { + goto error; + } + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG12V3 *object = NULL; + uint32_t bytes = (count / 8) + 1; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (uint32_t i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->point = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG13V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG13V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->commanded_state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG13V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG13V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->commanded_state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG20V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V9(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V9 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V10(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V10 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V11(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V11 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V12(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG21V12 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG22V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG23V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG30V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG30V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG30V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG30V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG30V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG30V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG31V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG32V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG33V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG34V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG34V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG34V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat32(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG40V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG40V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG40V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG40V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG41V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG41V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG41V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG41V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG42V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG43V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG50V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG50V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->interval)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG50V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG50V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->interval_count)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->interval_units)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG51V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG51V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG51V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG51V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG52V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG52V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->delay_secs)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG52V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG52V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->delay_ms)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->filetype_code)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->attribute_code)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->start_record)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->end_record)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permission)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->owner_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->group_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->file_function_code)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + if (object->filename_size > 0) { + if (*len < object->filename_size) { + /* Not enough data. */ + goto error; + } + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + if (!DNP3ReadUint16(buf, len, &object->data_size)) { + goto error; + } + if (object->data_size > 0) { + if (*len < object->data_size) { + /* Not enough data. */ + goto error; + } + memcpy(object->data, *buf, object->data_size); + *buf += object->data_size; + *len -= object->data_size; + } + object->data[object->data_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->username_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->password_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->password_size)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { + goto error; + } + if (object->username_size > 0) { + if (*len < object->username_size) { + /* Not enough data. */ + goto error; + } + memcpy(object->username, *buf, object->username_size); + *buf += object->username_size; + *len -= object->username_size; + } + object->username[object->username_size] = '\0'; + if (object->password_size > 0) { + if (*len < object->password_size) { + /* Not enough data. */ + goto error; + } + memcpy(object->password, *buf, object->password_size); + *buf += object->password_size; + *len -= object->password_size; + } + object->password[object->password_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permissions)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->operational_mode)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (object->filename_size > 0) { + if (*len < object->filename_size) { + /* Not enough data. */ + goto error; + } + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + if (prefix - (offset - *len) >= 255 || prefix < (offset - *len)) { + goto error; + } + object->optional_text_len = (uint8_t)(prefix - (offset - *len)); + if (object->optional_text_len > 0) { + if (*len < object->optional_text_len) { + /* Not enough data. */ + goto error; + } + memcpy(object->optional_text, *buf, object->optional_text_len); + *buf += object->optional_text_len; + *len -= object->optional_text_len; + } + object->optional_text[object->optional_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->block_number)) { + goto error; + } + if (prefix - (offset - *len) >= 255 || prefix < (offset - *len)) { + goto error; + } + object->file_data_len = (uint8_t)(prefix - (offset - *len)); + if (object->file_data_len > 0) { + if (*len < object->file_data_len) { + /* Not enough data. */ + goto error; + } + memcpy(object->file_data, *buf, object->file_data_len); + *buf += object->file_data_len; + *len -= object->file_data_len; + } + object->file_data[object->file_data_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->block_number)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + if (prefix - (offset - *len) >= 255 || prefix < (offset - *len)) { + goto error; + } + object->optional_text_len = (uint8_t)(prefix - (offset - *len)); + if (object->optional_text_len > 0) { + if (*len < object->optional_text_len) { + /* Not enough data. */ + goto error; + } + memcpy(object->optional_text, *buf, object->optional_text_len); + *buf += object->optional_text_len; + *len -= object->optional_text_len; + } + object->optional_text[object->optional_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->file_type)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permissions)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (object->filename_size > 0) { + if (*len < object->filename_size) { + /* Not enough data. */ + goto error; + } + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG70V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (prefix - (offset - *len) >= 65535 || prefix < (offset - *len)) { + goto error; + } + object->file_specification_len = (uint16_t)(prefix - (offset - *len)); + if (object->file_specification_len > 0) { + if (*len < object->file_specification_len) { + /* Not enough data. */ + goto error; + } + memcpy(object->file_specification, *buf, object->file_specification_len); + *buf += object->file_specification_len; + *len -= object->file_specification_len; + } + object->file_specification[object->file_specification_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG80V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG80V1 *object = NULL; + uint32_t bytes = (count / 8) + 1; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (uint32_t i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG81V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG81V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->fill_percentage = (octet >> 0) & 0x7f; + object->overflow_state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint8(buf, len, &object->group)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->variation)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG83V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG83V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (*len < 4) { + goto error; + } + memcpy(object->vendor_code, *buf, 4); + object->vendor_code[4] = '\0'; + *buf += 4; + *len -= 4; + if (!DNP3ReadUint16(buf, len, &object->object_id)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->length)) { + goto error; + } + if (object->length > 0) { + if (*len < object->length) { + /* Not enough data. */ + goto error; + } + object->data_objects = SCCalloc(1, object->length); + if (unlikely(object->data_objects == NULL)) { + goto error; + } + memcpy(object->data_objects, *buf, object->length); + *buf += object->length; + *len -= object->length; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->data_objects != NULL) { + SCFree(object->data_objects); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG86V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG86V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->rd = (octet >> 0) & 0x1; + object->wr = (octet >> 1) & 0x1; + object->st = (octet >> 2) & 0x1; + object->ev = (octet >> 3) & 0x1; + object->df = (octet >> 4) & 0x1; + object->padding0 = (octet >> 5) & 0x1; + object->padding1 = (octet >> 6) & 0x1; + object->padding2 = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG102V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG102V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->mal)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->reason)) { + goto error; + } + if (prefix < (offset - *len)) { + goto error; + } + object->challenge_data_len = (uint16_t)(prefix - (offset - *len)); + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (prefix < (offset - *len)) { + goto error; + } + object->mac_value_len = (uint16_t)(prefix - (offset - *len)); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V3(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V4(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V5(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->key_wrap_alg)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->key_status)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->mal)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { + goto error; + } + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + if (prefix < (offset - *len)) { + goto error; + } + object->mac_value_len = (uint16_t)(prefix - (offset - *len)); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V6(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint24(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (prefix < (offset - *len)) { + goto error; + } + object->wrapped_key_data_len = (uint16_t)(prefix - (offset - *len)); + if (object->wrapped_key_data_len > 0) { + if (*len < object->wrapped_key_data_len) { + /* Not enough data. */ + goto error; + } + object->wrapped_key_data = SCCalloc(1, object->wrapped_key_data_len); + if (unlikely(object->wrapped_key_data == NULL)) { + goto error; + } + memcpy(object->wrapped_key_data, *buf, object->wrapped_key_data_len); + *buf += object->wrapped_key_data_len; + *len -= object->wrapped_key_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->wrapped_key_data != NULL) { + SCFree(object->wrapped_key_data); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V7(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->sequence_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->error_code)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->time_of_error)) { + goto error; + } + if (prefix - (offset - *len) >= 65535 || prefix < (offset - *len)) { + goto error; + } + object->error_text_len = (uint16_t)(prefix - (offset - *len)); + if (object->error_text_len > 0) { + if (*len < object->error_text_len) { + /* Not enough data. */ + goto error; + } + memcpy(object->error_text, *buf, object->error_text_len); + *buf += object->error_text_len; + *len -= object->error_text_len; + } + object->error_text[object->error_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V8(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->certificate_type)) { + goto error; + } + if (prefix < (offset - *len)) { + goto error; + } + object->certificate_len = (uint16_t)(prefix - (offset - *len)); + if (object->certificate_len > 0) { + if (*len < object->certificate_len) { + /* Not enough data. */ + goto error; + } + object->certificate = SCCalloc(1, object->certificate_len); + if (unlikely(object->certificate == NULL)) { + goto error; + } + memcpy(object->certificate, *buf, object->certificate_len); + *buf += object->certificate_len; + *len -= object->certificate_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->certificate != NULL) { + SCFree(object->certificate); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V9(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V9 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (prefix < (offset - *len)) { + goto error; + } + object->mac_value_len = (uint16_t)(prefix - (offset - *len)); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V10(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V10 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->operation)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->scs)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_role)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_role_expiry_interval)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_public_key_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->certification_data_len)) { + goto error; + } + if (object->username_len > 0) { + if (*len < object->username_len) { + /* Not enough data. */ + goto error; + } + memcpy(object->username, *buf, object->username_len); + *buf += object->username_len; + *len -= object->username_len; + } + object->username[object->username_len] = '\0'; + if (object->user_public_key_len > 0) { + if (*len < object->user_public_key_len) { + /* Not enough data. */ + goto error; + } + object->user_public_key = SCCalloc(1, object->user_public_key_len); + if (unlikely(object->user_public_key == NULL)) { + goto error; + } + memcpy(object->user_public_key, *buf, object->user_public_key_len); + *buf += object->user_public_key_len; + *len -= object->user_public_key_len; + } + if (object->certification_data_len > 0) { + if (*len < object->certification_data_len) { + /* Not enough data. */ + goto error; + } + object->certification_data = SCCalloc(1, object->certification_data_len); + if (unlikely(object->certification_data == NULL)) { + goto error; + } + memcpy(object->certification_data, *buf, object->certification_data_len); + *buf += object->certification_data_len; + *len -= object->certification_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->user_public_key != NULL) { + SCFree(object->user_public_key); + } + if (object->certification_data != NULL) { + SCFree(object->certification_data); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V11(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V11 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->master_challenge_data_len)) { + goto error; + } + if (object->username_len > 0) { + if (*len < object->username_len) { + /* Not enough data. */ + goto error; + } + memcpy(object->username, *buf, object->username_len); + *buf += object->username_len; + *len -= object->username_len; + } + object->username[object->username_len] = '\0'; + if (object->master_challenge_data_len > 0) { + if (*len < object->master_challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->master_challenge_data = SCCalloc(1, object->master_challenge_data_len); + if (unlikely(object->master_challenge_data == NULL)) { + goto error; + } + memcpy(object->master_challenge_data, *buf, object->master_challenge_data_len); + *buf += object->master_challenge_data_len; + *len -= object->master_challenge_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->master_challenge_data != NULL) { + SCFree(object->master_challenge_data); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V12(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V12 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { + goto error; + } + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V13(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V13 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->encrypted_update_key_len)) { + goto error; + } + if (object->encrypted_update_key_len > 0) { + if (*len < object->encrypted_update_key_len) { + /* Not enough data. */ + goto error; + } + object->encrypted_update_key_data = SCCalloc(1, object->encrypted_update_key_len); + if (unlikely(object->encrypted_update_key_data == NULL)) { + goto error; + } + memcpy(object->encrypted_update_key_data, *buf, object->encrypted_update_key_len); + *buf += object->encrypted_update_key_len; + *len -= object->encrypted_update_key_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->encrypted_update_key_data != NULL) { + SCFree(object->encrypted_update_key_data); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V14(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V14 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (prefix < (offset - *len)) { + goto error; + } + object->digital_signature_len = (uint16_t)(prefix - (offset - *len)); + if (object->digital_signature_len > 0) { + if (*len < object->digital_signature_len) { + /* Not enough data. */ + goto error; + } + object->digital_signature = SCCalloc(1, object->digital_signature_len); + if (unlikely(object->digital_signature == NULL)) { + goto error; + } + memcpy(object->digital_signature, *buf, object->digital_signature_len); + *buf += object->digital_signature_len; + *len -= object->digital_signature_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->digital_signature != NULL) { + SCFree(object->digital_signature); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V15(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG120V15 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (prefix < (offset - *len)) { + goto error; + } + object->mac_len = (uint16_t)(prefix - (offset - *len)); + if (object->mac_len > 0) { + if (*len < object->mac_len) { + /* Not enough data. */ + goto error; + } + object->mac = SCCalloc(1, object->mac_len); + if (unlikely(object->mac == NULL)) { + goto error; + } + memcpy(object->mac, *buf, object->mac_len); + *buf += object->mac_len; + *len -= object->mac_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + if (object->mac != NULL) { + SCFree(object->mac); + } + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG121V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG121V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG122V1(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG122V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG122V2(const uint8_t **buf, uint32_t *len, uint8_t prefix_code, + uint32_t start, uint32_t count, DNP3PointList *points) +{ + DNP3ObjectG122V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (*len < count / 8) { + goto error; + } + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +void DNP3FreeObjectPoint(int group, int variation, void *point) +{ + switch (DNP3_OBJECT_CODE(group, variation)) { + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *object = (DNP3ObjectG83V1 *)point; + if (object->data_objects != NULL) { + SCFree(object->data_objects); + } + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *object = (DNP3ObjectG120V1 *)point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *object = (DNP3ObjectG120V2 *)point; + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *object = (DNP3ObjectG120V5 *)point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *object = (DNP3ObjectG120V6 *)point; + if (object->wrapped_key_data != NULL) { + SCFree(object->wrapped_key_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *object = (DNP3ObjectG120V8 *)point; + if (object->certificate != NULL) { + SCFree(object->certificate); + } + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *object = (DNP3ObjectG120V9 *)point; + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *object = (DNP3ObjectG120V10 *)point; + if (object->user_public_key != NULL) { + SCFree(object->user_public_key); + } + if (object->certification_data != NULL) { + SCFree(object->certification_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *object = (DNP3ObjectG120V11 *)point; + if (object->master_challenge_data != NULL) { + SCFree(object->master_challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *object = (DNP3ObjectG120V12 *)point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *object = (DNP3ObjectG120V13 *)point; + if (object->encrypted_update_key_data != NULL) { + SCFree(object->encrypted_update_key_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *object = (DNP3ObjectG120V14 *)point; + if (object->digital_signature != NULL) { + SCFree(object->digital_signature); + } + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *object = (DNP3ObjectG120V15 *)point; + if (object->mac != NULL) { + SCFree(object->mac); + } + break; + } + default: + break; + } + SCFree(point); +} + +/** + * \brief Decode a DNP3 object. + * + * \retval 0 on success. On failure a positive integer corresponding + * to a DNP3 application layer event will be returned. + */ +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, DNP3PointList *points) +{ + int rc = 0; + + switch (DNP3_OBJECT_CODE(group, variation)) { + case DNP3_OBJECT_CODE(1, 1): + rc = DNP3DecodeObjectG1V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(1, 2): + rc = DNP3DecodeObjectG1V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(2, 1): + rc = DNP3DecodeObjectG2V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(2, 2): + rc = DNP3DecodeObjectG2V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(2, 3): + rc = DNP3DecodeObjectG2V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(3, 1): + rc = DNP3DecodeObjectG3V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(3, 2): + rc = DNP3DecodeObjectG3V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(4, 1): + rc = DNP3DecodeObjectG4V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(4, 2): + rc = DNP3DecodeObjectG4V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(4, 3): + rc = DNP3DecodeObjectG4V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(10, 1): + rc = DNP3DecodeObjectG10V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(10, 2): + rc = DNP3DecodeObjectG10V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(11, 1): + rc = DNP3DecodeObjectG11V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(11, 2): + rc = DNP3DecodeObjectG11V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(12, 1): + rc = DNP3DecodeObjectG12V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(12, 2): + rc = DNP3DecodeObjectG12V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(12, 3): + rc = DNP3DecodeObjectG12V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(13, 1): + rc = DNP3DecodeObjectG13V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(13, 2): + rc = DNP3DecodeObjectG13V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 1): + rc = DNP3DecodeObjectG20V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 2): + rc = DNP3DecodeObjectG20V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 3): + rc = DNP3DecodeObjectG20V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 4): + rc = DNP3DecodeObjectG20V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 5): + rc = DNP3DecodeObjectG20V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 6): + rc = DNP3DecodeObjectG20V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 7): + rc = DNP3DecodeObjectG20V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(20, 8): + rc = DNP3DecodeObjectG20V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 1): + rc = DNP3DecodeObjectG21V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 2): + rc = DNP3DecodeObjectG21V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 3): + rc = DNP3DecodeObjectG21V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 4): + rc = DNP3DecodeObjectG21V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 5): + rc = DNP3DecodeObjectG21V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 6): + rc = DNP3DecodeObjectG21V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 7): + rc = DNP3DecodeObjectG21V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 8): + rc = DNP3DecodeObjectG21V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 9): + rc = DNP3DecodeObjectG21V9(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 10): + rc = DNP3DecodeObjectG21V10(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 11): + rc = DNP3DecodeObjectG21V11(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(21, 12): + rc = DNP3DecodeObjectG21V12(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 1): + rc = DNP3DecodeObjectG22V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 2): + rc = DNP3DecodeObjectG22V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 3): + rc = DNP3DecodeObjectG22V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 4): + rc = DNP3DecodeObjectG22V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 5): + rc = DNP3DecodeObjectG22V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 6): + rc = DNP3DecodeObjectG22V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 7): + rc = DNP3DecodeObjectG22V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(22, 8): + rc = DNP3DecodeObjectG22V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 1): + rc = DNP3DecodeObjectG23V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 2): + rc = DNP3DecodeObjectG23V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 3): + rc = DNP3DecodeObjectG23V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 4): + rc = DNP3DecodeObjectG23V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 5): + rc = DNP3DecodeObjectG23V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 6): + rc = DNP3DecodeObjectG23V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 7): + rc = DNP3DecodeObjectG23V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(23, 8): + rc = DNP3DecodeObjectG23V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(30, 1): + rc = DNP3DecodeObjectG30V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(30, 2): + rc = DNP3DecodeObjectG30V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(30, 3): + rc = DNP3DecodeObjectG30V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(30, 4): + rc = DNP3DecodeObjectG30V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(30, 5): + rc = DNP3DecodeObjectG30V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(30, 6): + rc = DNP3DecodeObjectG30V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 1): + rc = DNP3DecodeObjectG31V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 2): + rc = DNP3DecodeObjectG31V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 3): + rc = DNP3DecodeObjectG31V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 4): + rc = DNP3DecodeObjectG31V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 5): + rc = DNP3DecodeObjectG31V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 6): + rc = DNP3DecodeObjectG31V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 7): + rc = DNP3DecodeObjectG31V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(31, 8): + rc = DNP3DecodeObjectG31V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 1): + rc = DNP3DecodeObjectG32V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 2): + rc = DNP3DecodeObjectG32V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 3): + rc = DNP3DecodeObjectG32V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 4): + rc = DNP3DecodeObjectG32V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 5): + rc = DNP3DecodeObjectG32V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 6): + rc = DNP3DecodeObjectG32V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 7): + rc = DNP3DecodeObjectG32V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(32, 8): + rc = DNP3DecodeObjectG32V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 1): + rc = DNP3DecodeObjectG33V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 2): + rc = DNP3DecodeObjectG33V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 3): + rc = DNP3DecodeObjectG33V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 4): + rc = DNP3DecodeObjectG33V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 5): + rc = DNP3DecodeObjectG33V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 6): + rc = DNP3DecodeObjectG33V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 7): + rc = DNP3DecodeObjectG33V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(33, 8): + rc = DNP3DecodeObjectG33V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(34, 1): + rc = DNP3DecodeObjectG34V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(34, 2): + rc = DNP3DecodeObjectG34V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(34, 3): + rc = DNP3DecodeObjectG34V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(40, 1): + rc = DNP3DecodeObjectG40V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(40, 2): + rc = DNP3DecodeObjectG40V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(40, 3): + rc = DNP3DecodeObjectG40V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(40, 4): + rc = DNP3DecodeObjectG40V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(41, 1): + rc = DNP3DecodeObjectG41V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(41, 2): + rc = DNP3DecodeObjectG41V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(41, 3): + rc = DNP3DecodeObjectG41V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(41, 4): + rc = DNP3DecodeObjectG41V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 1): + rc = DNP3DecodeObjectG42V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 2): + rc = DNP3DecodeObjectG42V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 3): + rc = DNP3DecodeObjectG42V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 4): + rc = DNP3DecodeObjectG42V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 5): + rc = DNP3DecodeObjectG42V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 6): + rc = DNP3DecodeObjectG42V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 7): + rc = DNP3DecodeObjectG42V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(42, 8): + rc = DNP3DecodeObjectG42V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 1): + rc = DNP3DecodeObjectG43V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 2): + rc = DNP3DecodeObjectG43V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 3): + rc = DNP3DecodeObjectG43V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 4): + rc = DNP3DecodeObjectG43V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 5): + rc = DNP3DecodeObjectG43V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 6): + rc = DNP3DecodeObjectG43V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 7): + rc = DNP3DecodeObjectG43V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(43, 8): + rc = DNP3DecodeObjectG43V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(50, 1): + rc = DNP3DecodeObjectG50V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(50, 2): + rc = DNP3DecodeObjectG50V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(50, 3): + rc = DNP3DecodeObjectG50V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(50, 4): + rc = DNP3DecodeObjectG50V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(51, 1): + rc = DNP3DecodeObjectG51V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(51, 2): + rc = DNP3DecodeObjectG51V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(52, 1): + rc = DNP3DecodeObjectG52V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(52, 2): + rc = DNP3DecodeObjectG52V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 1): + rc = DNP3DecodeObjectG70V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 2): + rc = DNP3DecodeObjectG70V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 3): + rc = DNP3DecodeObjectG70V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 4): + rc = DNP3DecodeObjectG70V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 5): + rc = DNP3DecodeObjectG70V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 6): + rc = DNP3DecodeObjectG70V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 7): + rc = DNP3DecodeObjectG70V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(70, 8): + rc = DNP3DecodeObjectG70V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(80, 1): + rc = DNP3DecodeObjectG80V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(81, 1): + rc = DNP3DecodeObjectG81V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(83, 1): + rc = DNP3DecodeObjectG83V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(86, 2): + rc = DNP3DecodeObjectG86V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(102, 1): + rc = DNP3DecodeObjectG102V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 1): + rc = DNP3DecodeObjectG120V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 2): + rc = DNP3DecodeObjectG120V2(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 3): + rc = DNP3DecodeObjectG120V3(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 4): + rc = DNP3DecodeObjectG120V4(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 5): + rc = DNP3DecodeObjectG120V5(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 6): + rc = DNP3DecodeObjectG120V6(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 7): + rc = DNP3DecodeObjectG120V7(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 8): + rc = DNP3DecodeObjectG120V8(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 9): + rc = DNP3DecodeObjectG120V9(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 10): + rc = DNP3DecodeObjectG120V10(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 11): + rc = DNP3DecodeObjectG120V11(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 12): + rc = DNP3DecodeObjectG120V12(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 13): + rc = DNP3DecodeObjectG120V13(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 14): + rc = DNP3DecodeObjectG120V14(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(120, 15): + rc = DNP3DecodeObjectG120V15(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(121, 1): + rc = DNP3DecodeObjectG121V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(122, 1): + rc = DNP3DecodeObjectG122V1(buf, len, prefix_code, start, count, points); + break; + case DNP3_OBJECT_CODE(122, 2): + rc = DNP3DecodeObjectG122V2(buf, len, prefix_code, start, count, points); + break; + default: + return DNP3_DECODER_EVENT_UNKNOWN_OBJECT; + } + + return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED; +} + +/* END GENERATED CODE */ diff --git a/src/app-layer/dnp3/parser-objects.h b/src/app-layer/dnp3/parser-objects.h new file mode 100644 index 000000000000..72b61cd8472c --- /dev/null +++ b/src/app-layer/dnp3/parser-objects.h @@ -0,0 +1,1463 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jason Ish + * + * This file contains the types (definitions) of the DNP3 objects. + */ + +#ifndef __APP_LAYER_DNP3_OBJECTS_H__ +#define __APP_LAYER_DNP3_OBJECTS_H__ + +#define DNP3_OBJECT_CODE(group, variation) (group << 8 | variation) + +/* START GENERATED CODE */ + +/* Code generated by: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +typedef struct DNP3ObjectG1V1_ { + uint8_t state; +} DNP3ObjectG1V1; + +typedef struct DNP3ObjectG1V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t chatter_filter : 1; + uint8_t reserved : 1; + uint8_t state : 1; +} DNP3ObjectG1V2; + +typedef struct DNP3ObjectG2V1_ { + uint8_t state; +} DNP3ObjectG2V1; + +typedef struct DNP3ObjectG2V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t chatter_filter : 1; + uint8_t reserved : 1; + uint8_t state : 1; + uint64_t timestamp; +} DNP3ObjectG2V2; + +typedef struct DNP3ObjectG2V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t chatter_filter : 1; + uint8_t reserved : 1; + uint8_t state : 1; + uint16_t timestamp; +} DNP3ObjectG2V3; + +typedef struct DNP3ObjectG3V1_ { + uint8_t state; +} DNP3ObjectG3V1; + +typedef struct DNP3ObjectG3V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t chatter_filter : 1; + uint8_t state : 2; +} DNP3ObjectG3V2; + +typedef struct DNP3ObjectG4V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t chatter_filter : 1; + uint8_t state : 2; +} DNP3ObjectG4V1; + +typedef struct DNP3ObjectG4V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t chatter_filter : 1; + uint8_t state : 2; + uint64_t timestamp; +} DNP3ObjectG4V2; + +typedef struct DNP3ObjectG4V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t chatter_filter : 1; + uint8_t state : 2; + uint16_t relative_time_ms; +} DNP3ObjectG4V3; + +typedef struct DNP3ObjectG10V1_ { + uint8_t state; +} DNP3ObjectG10V1; + +typedef struct DNP3ObjectG10V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint8_t state : 1; +} DNP3ObjectG10V2; + +typedef struct DNP3ObjectG11V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint8_t state : 1; +} DNP3ObjectG11V1; + +typedef struct DNP3ObjectG11V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint8_t state : 1; + uint64_t timestamp; +} DNP3ObjectG11V2; + +typedef struct DNP3ObjectG12V1_ { + uint8_t op_type : 4; + uint8_t qu : 1; + uint8_t cr : 1; + uint8_t tcc : 2; + uint8_t count; + uint32_t ontime; + uint32_t offtime; + uint8_t status_code : 7; + uint8_t reserved : 1; +} DNP3ObjectG12V1; + +typedef struct DNP3ObjectG12V2_ { + uint8_t op_type : 4; + uint8_t qu : 1; + uint8_t cr : 1; + uint8_t tcc : 2; + uint8_t count; + uint32_t ontime; + uint32_t offtime; + uint8_t status_code : 7; + uint8_t reserved : 1; +} DNP3ObjectG12V2; + +typedef struct DNP3ObjectG12V3_ { + uint8_t point; +} DNP3ObjectG12V3; + +typedef struct DNP3ObjectG13V1_ { + uint8_t status_code : 7; + uint8_t commanded_state : 1; +} DNP3ObjectG13V1; + +typedef struct DNP3ObjectG13V2_ { + uint8_t status_code : 7; + uint8_t commanded_state : 1; + uint64_t timestamp; +} DNP3ObjectG13V2; + +typedef struct DNP3ObjectG20V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint32_t count; +} DNP3ObjectG20V1; + +typedef struct DNP3ObjectG20V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint16_t count; +} DNP3ObjectG20V2; + +typedef struct DNP3ObjectG20V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; +} DNP3ObjectG20V3; + +typedef struct DNP3ObjectG20V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; +} DNP3ObjectG20V4; + +typedef struct DNP3ObjectG20V5_ { + uint32_t count; +} DNP3ObjectG20V5; + +typedef struct DNP3ObjectG20V6_ { + uint16_t count; +} DNP3ObjectG20V6; + +typedef struct DNP3ObjectG20V7_ { + uint32_t count; +} DNP3ObjectG20V7; + +typedef struct DNP3ObjectG20V8_ { + uint16_t count; +} DNP3ObjectG20V8; + +typedef struct DNP3ObjectG21V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint32_t count; +} DNP3ObjectG21V1; + +typedef struct DNP3ObjectG21V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint16_t count; +} DNP3ObjectG21V2; + +typedef struct DNP3ObjectG21V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; +} DNP3ObjectG21V3; + +typedef struct DNP3ObjectG21V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; +} DNP3ObjectG21V4; + +typedef struct DNP3ObjectG21V5_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved1 : 1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG21V5; + +typedef struct DNP3ObjectG21V6_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved1 : 1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG21V6; + +typedef struct DNP3ObjectG21V7_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG21V7; + +typedef struct DNP3ObjectG21V8_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG21V8; + +typedef struct DNP3ObjectG21V9_ { + uint32_t count; +} DNP3ObjectG21V9; + +typedef struct DNP3ObjectG21V10_ { + uint16_t count; +} DNP3ObjectG21V10; + +typedef struct DNP3ObjectG21V11_ { + uint32_t count; +} DNP3ObjectG21V11; + +typedef struct DNP3ObjectG21V12_ { + uint16_t count; +} DNP3ObjectG21V12; + +typedef struct DNP3ObjectG22V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint32_t count; +} DNP3ObjectG22V1; + +typedef struct DNP3ObjectG22V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint16_t count; +} DNP3ObjectG22V2; + +typedef struct DNP3ObjectG22V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; +} DNP3ObjectG22V3; + +typedef struct DNP3ObjectG22V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; +} DNP3ObjectG22V4; + +typedef struct DNP3ObjectG22V5_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG22V5; + +typedef struct DNP3ObjectG22V6_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG22V6; + +typedef struct DNP3ObjectG22V7_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG22V7; + +typedef struct DNP3ObjectG22V8_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG22V8; + +typedef struct DNP3ObjectG23V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint32_t count; +} DNP3ObjectG23V1; + +typedef struct DNP3ObjectG23V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; +} DNP3ObjectG23V2; + +typedef struct DNP3ObjectG23V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; +} DNP3ObjectG23V3; + +typedef struct DNP3ObjectG23V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; +} DNP3ObjectG23V4; + +typedef struct DNP3ObjectG23V5_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG23V5; + +typedef struct DNP3ObjectG23V6_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t discontinuity : 1; + uint8_t reserved0 : 1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG23V6; + +typedef struct DNP3ObjectG23V7_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG23V7; + +typedef struct DNP3ObjectG23V8_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t rollover : 1; + uint8_t reserved0 : 1; + uint8_t reserved1 : 1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG23V8; + +typedef struct DNP3ObjectG30V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; +} DNP3ObjectG30V1; + +typedef struct DNP3ObjectG30V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; +} DNP3ObjectG30V2; + +typedef struct DNP3ObjectG30V3_ { + int32_t value; +} DNP3ObjectG30V3; + +typedef struct DNP3ObjectG30V4_ { + int16_t value; +} DNP3ObjectG30V4; + +typedef struct DNP3ObjectG30V5_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; +} DNP3ObjectG30V5; + +typedef struct DNP3ObjectG30V6_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; +} DNP3ObjectG30V6; + +typedef struct DNP3ObjectG31V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; +} DNP3ObjectG31V1; + +typedef struct DNP3ObjectG31V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; +} DNP3ObjectG31V2; + +typedef struct DNP3ObjectG31V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG31V3; + +typedef struct DNP3ObjectG31V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG31V4; + +typedef struct DNP3ObjectG31V5_ { + int32_t value; +} DNP3ObjectG31V5; + +typedef struct DNP3ObjectG31V6_ { + int16_t value; +} DNP3ObjectG31V6; + +typedef struct DNP3ObjectG31V7_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; +} DNP3ObjectG31V7; + +typedef struct DNP3ObjectG31V8_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; +} DNP3ObjectG31V8; + +typedef struct DNP3ObjectG32V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; +} DNP3ObjectG32V1; + +typedef struct DNP3ObjectG32V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; +} DNP3ObjectG32V2; + +typedef struct DNP3ObjectG32V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG32V3; + +typedef struct DNP3ObjectG32V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG32V4; + +typedef struct DNP3ObjectG32V5_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; +} DNP3ObjectG32V5; + +typedef struct DNP3ObjectG32V6_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; +} DNP3ObjectG32V6; + +typedef struct DNP3ObjectG32V7_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; + uint64_t timestamp; +} DNP3ObjectG32V7; + +typedef struct DNP3ObjectG32V8_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; + uint64_t timestamp; +} DNP3ObjectG32V8; + +typedef struct DNP3ObjectG33V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; +} DNP3ObjectG33V1; + +typedef struct DNP3ObjectG33V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; +} DNP3ObjectG33V2; + +typedef struct DNP3ObjectG33V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG33V3; + +typedef struct DNP3ObjectG33V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG33V4; + +typedef struct DNP3ObjectG33V5_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; +} DNP3ObjectG33V5; + +typedef struct DNP3ObjectG33V6_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; +} DNP3ObjectG33V6; + +typedef struct DNP3ObjectG33V7_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; + uint64_t timestamp; +} DNP3ObjectG33V7; + +typedef struct DNP3ObjectG33V8_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; + uint64_t timestamp; +} DNP3ObjectG33V8; + +typedef struct DNP3ObjectG34V1_ { + uint16_t deadband_value; +} DNP3ObjectG34V1; + +typedef struct DNP3ObjectG34V2_ { + uint32_t deadband_value; +} DNP3ObjectG34V2; + +typedef struct DNP3ObjectG34V3_ { + float deadband_value; +} DNP3ObjectG34V3; + +typedef struct DNP3ObjectG40V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; +} DNP3ObjectG40V1; + +typedef struct DNP3ObjectG40V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; +} DNP3ObjectG40V2; + +typedef struct DNP3ObjectG40V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; +} DNP3ObjectG40V3; + +typedef struct DNP3ObjectG40V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; +} DNP3ObjectG40V4; + +typedef struct DNP3ObjectG41V1_ { + int32_t value; + uint8_t control_status; +} DNP3ObjectG41V1; + +typedef struct DNP3ObjectG41V2_ { + int16_t value; + uint8_t control_status; +} DNP3ObjectG41V2; + +typedef struct DNP3ObjectG41V3_ { + float value; + uint8_t control_status; +} DNP3ObjectG41V3; + +typedef struct DNP3ObjectG41V4_ { + double value; + uint8_t control_status; +} DNP3ObjectG41V4; + +typedef struct DNP3ObjectG42V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; +} DNP3ObjectG42V1; + +typedef struct DNP3ObjectG42V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; +} DNP3ObjectG42V2; + +typedef struct DNP3ObjectG42V3_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG42V3; + +typedef struct DNP3ObjectG42V4_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG42V4; + +typedef struct DNP3ObjectG42V5_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; +} DNP3ObjectG42V5; + +typedef struct DNP3ObjectG42V6_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; +} DNP3ObjectG42V6; + +typedef struct DNP3ObjectG42V7_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + float value; + uint64_t timestamp; +} DNP3ObjectG42V7; + +typedef struct DNP3ObjectG42V8_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t over_range : 1; + uint8_t reference_err : 1; + uint8_t reserved0 : 1; + double value; + uint64_t timestamp; +} DNP3ObjectG42V8; + +typedef struct DNP3ObjectG43V1_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + int32_t commanded_value; +} DNP3ObjectG43V1; + +typedef struct DNP3ObjectG43V2_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + int16_t commanded_value; +} DNP3ObjectG43V2; + +typedef struct DNP3ObjectG43V3_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + int32_t commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V3; + +typedef struct DNP3ObjectG43V4_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + int16_t commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V4; + +typedef struct DNP3ObjectG43V5_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + float commanded_value; +} DNP3ObjectG43V5; + +typedef struct DNP3ObjectG43V6_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + double commanded_value; +} DNP3ObjectG43V6; + +typedef struct DNP3ObjectG43V7_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + float commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V7; + +typedef struct DNP3ObjectG43V8_ { + uint8_t status_code : 7; + uint8_t reserved0 : 1; + double commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V8; + +typedef struct DNP3ObjectG50V1_ { + uint64_t timestamp; +} DNP3ObjectG50V1; + +typedef struct DNP3ObjectG50V2_ { + uint64_t timestamp; + uint32_t interval; +} DNP3ObjectG50V2; + +typedef struct DNP3ObjectG50V3_ { + uint64_t timestamp; +} DNP3ObjectG50V3; + +typedef struct DNP3ObjectG50V4_ { + uint64_t timestamp; + uint32_t interval_count; + uint8_t interval_units; +} DNP3ObjectG50V4; + +typedef struct DNP3ObjectG51V1_ { + uint64_t timestamp; +} DNP3ObjectG51V1; + +typedef struct DNP3ObjectG51V2_ { + uint64_t timestamp; +} DNP3ObjectG51V2; + +typedef struct DNP3ObjectG52V1_ { + uint16_t delay_secs; +} DNP3ObjectG52V1; + +typedef struct DNP3ObjectG52V2_ { + uint16_t delay_ms; +} DNP3ObjectG52V2; + +typedef struct DNP3ObjectG70V1_ { + uint16_t filename_size; + uint8_t filetype_code; + uint8_t attribute_code; + uint16_t start_record; + uint16_t end_record; + uint32_t file_size; + uint64_t created_timestamp; + uint16_t permission; + uint32_t file_id; + uint32_t owner_id; + uint32_t group_id; + uint8_t file_function_code; + uint8_t status_code; + char filename[65535]; + uint16_t data_size; + char data[65535]; +} DNP3ObjectG70V1; + +typedef struct DNP3ObjectG70V2_ { + uint16_t username_offset; + uint16_t username_size; + uint16_t password_offset; + uint16_t password_size; + uint32_t authentication_key; + char username[65535]; + char password[65535]; +} DNP3ObjectG70V2; + +typedef struct DNP3ObjectG70V3_ { + uint16_t filename_offset; + uint16_t filename_size; + uint64_t created; + uint16_t permissions; + uint32_t authentication_key; + uint32_t file_size; + uint16_t operational_mode; + uint16_t maximum_block_size; + uint16_t request_id; + char filename[65535]; +} DNP3ObjectG70V3; + +typedef struct DNP3ObjectG70V4_ { + uint32_t file_handle; + uint32_t file_size; + uint16_t maximum_block_size; + uint16_t request_id; + uint8_t status_code; + char optional_text[255]; + uint8_t optional_text_len; +} DNP3ObjectG70V4; + +typedef struct DNP3ObjectG70V5_ { + uint32_t file_handle; + uint32_t block_number; + char file_data[255]; + uint8_t file_data_len; +} DNP3ObjectG70V5; + +typedef struct DNP3ObjectG70V6_ { + uint32_t file_handle; + uint32_t block_number; + uint8_t status_code; + char optional_text[255]; + uint8_t optional_text_len; +} DNP3ObjectG70V6; + +typedef struct DNP3ObjectG70V7_ { + uint16_t filename_offset; + uint16_t filename_size; + uint16_t file_type; + uint32_t file_size; + uint64_t created_timestamp; + uint16_t permissions; + uint16_t request_id; + char filename[65535]; +} DNP3ObjectG70V7; + +typedef struct DNP3ObjectG70V8_ { + char file_specification[65535]; + uint16_t file_specification_len; +} DNP3ObjectG70V8; + +typedef struct DNP3ObjectG80V1_ { + uint8_t state; +} DNP3ObjectG80V1; + +typedef struct DNP3ObjectG81V1_ { + uint8_t fill_percentage : 7; + uint8_t overflow_state : 1; + uint8_t group; + uint8_t variation; +} DNP3ObjectG81V1; + +typedef struct DNP3ObjectG83V1_ { + char vendor_code[5]; + uint16_t object_id; + uint16_t length; + uint8_t *data_objects; +} DNP3ObjectG83V1; + +typedef struct DNP3ObjectG86V2_ { + uint8_t rd : 1; + uint8_t wr : 1; + uint8_t st : 1; + uint8_t ev : 1; + uint8_t df : 1; + uint8_t padding0 : 1; + uint8_t padding1 : 1; + uint8_t padding2 : 1; +} DNP3ObjectG86V2; + +typedef struct DNP3ObjectG102V1_ { + uint8_t value; +} DNP3ObjectG102V1; + +typedef struct DNP3ObjectG120V1_ { + uint32_t csq; + uint16_t usr; + uint8_t mal; + uint8_t reason; + uint8_t *challenge_data; + uint16_t challenge_data_len; +} DNP3ObjectG120V1; + +typedef struct DNP3ObjectG120V2_ { + uint32_t csq; + uint16_t usr; + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V2; + +typedef struct DNP3ObjectG120V3_ { + uint32_t csq; + uint16_t user_number; +} DNP3ObjectG120V3; + +typedef struct DNP3ObjectG120V4_ { + uint16_t user_number; +} DNP3ObjectG120V4; + +typedef struct DNP3ObjectG120V5_ { + uint32_t ksq; + uint16_t user_number; + uint8_t key_wrap_alg; + uint8_t key_status; + uint8_t mal; + uint16_t challenge_data_len; + uint8_t *challenge_data; + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V5; + +typedef struct DNP3ObjectG120V6_ { + uint32_t ksq; + uint16_t usr; + uint8_t *wrapped_key_data; + uint16_t wrapped_key_data_len; +} DNP3ObjectG120V6; + +typedef struct DNP3ObjectG120V7_ { + uint32_t sequence_number; + uint16_t usr; + uint16_t association_id; + uint8_t error_code; + uint64_t time_of_error; + char error_text[65535]; + uint16_t error_text_len; +} DNP3ObjectG120V7; + +typedef struct DNP3ObjectG120V8_ { + uint8_t key_change_method; + uint8_t certificate_type; + uint8_t *certificate; + uint16_t certificate_len; +} DNP3ObjectG120V8; + +typedef struct DNP3ObjectG120V9_ { + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V9; + +typedef struct DNP3ObjectG120V10_ { + uint8_t key_change_method; + uint8_t operation; + uint32_t scs; + uint16_t user_role; + uint16_t user_role_expiry_interval; + uint16_t username_len; + uint16_t user_public_key_len; + uint16_t certification_data_len; + char username[65535]; + uint8_t *user_public_key; + uint8_t *certification_data; +} DNP3ObjectG120V10; + +typedef struct DNP3ObjectG120V11_ { + uint8_t key_change_method; + uint16_t username_len; + uint16_t master_challenge_data_len; + char username[65535]; + uint8_t *master_challenge_data; +} DNP3ObjectG120V11; + +typedef struct DNP3ObjectG120V12_ { + uint32_t ksq; + uint16_t user_number; + uint16_t challenge_data_len; + uint8_t *challenge_data; +} DNP3ObjectG120V12; + +typedef struct DNP3ObjectG120V13_ { + uint32_t ksq; + uint16_t user_number; + uint16_t encrypted_update_key_len; + uint8_t *encrypted_update_key_data; +} DNP3ObjectG120V13; + +typedef struct DNP3ObjectG120V14_ { + uint8_t *digital_signature; + uint16_t digital_signature_len; +} DNP3ObjectG120V14; + +typedef struct DNP3ObjectG120V15_ { + uint8_t *mac; + uint32_t mac_len; +} DNP3ObjectG120V15; + +typedef struct DNP3ObjectG121V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t reserved0 : 1; + uint8_t discontinuity : 1; + uint8_t reserved1 : 1; + uint16_t association_id; + uint32_t count_value; +} DNP3ObjectG121V1; + +typedef struct DNP3ObjectG122V1_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t reserved0 : 1; + uint8_t discontinuity : 1; + uint8_t reserved1 : 1; + uint16_t association_id; + uint32_t count_value; +} DNP3ObjectG122V1; + +typedef struct DNP3ObjectG122V2_ { + uint8_t online : 1; + uint8_t restart : 1; + uint8_t comm_lost : 1; + uint8_t remote_forced : 1; + uint8_t local_forced : 1; + uint8_t reserved0 : 1; + uint8_t discontinuity : 1; + uint8_t reserved1 : 1; + uint16_t association_id; + uint32_t count_value; + uint64_t timestamp; +} DNP3ObjectG122V2; + +/* END GENERATED CODE */ + +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, DNP3PointList *); +DNP3PointList *DNP3PointListAlloc(void); +void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *); + +#endif /* __APP_LAYER_DNP3_OBJECTS_H__ */ diff --git a/src/app-layer/dnp3/parser.c b/src/app-layer/dnp3/parser.c new file mode 100644 index 000000000000..3a5b4a5a2aa2 --- /dev/null +++ b/src/app-layer/dnp3/parser.c @@ -0,0 +1,2635 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * DNP3 protocol implementation + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "stream.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/hashlist.h" + +#include "util/print.h" +#include "util/spm-bs.h" +#include "util/enum.h" + +#include "app-layer.h" +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-detect-proto.h" + +#include "app-layer/dnp3/parser.h" +#include "app-layer/dnp3/parser-objects.h" + +/* Default number of unreplied requests to be considered a flood. */ +#define DNP3_DEFAULT_REQ_FLOOD_COUNT 500 + +#define DNP3_DEFAULT_PORT "20000" + +/* Expected values for the start bytes. */ +#define DNP3_START_BYTE0 0x05 +#define DNP3_START_BYTE1 0x64 + +/* Minimum length for a DNP3 frame. */ +#define DNP3_MIN_LEN 5 + +/* Length of each CRC. */ +#define DNP3_CRC_LEN 2 + +/* DNP3 block size. After the link header a CRC is inserted after + * after 16 bytes of data. */ +#define DNP3_BLOCK_SIZE 16 + +/* Maximum transport layer sequence number. */ +#define DNP3_MAX_TRAN_SEQNO 64 + +/* Maximum application layer sequence number. */ +#define DNP3_MAX_APP_SEQNO 16 + +/* The number of bytes in the header that are counted as part of the + * header length field. */ +#define DNP3_LINK_HDR_LEN 5 + +/* Link function codes. */ +enum { DNP3_LINK_FC_CONFIRMED_USER_DATA = 3, DNP3_LINK_FC_UNCONFIRMED_USER_DATA }; + +/* Reserved addresses. */ +#define DNP3_RESERVED_ADDR_MIN 0xfff0 +#define DNP3_RESERVED_ADDR_MAX 0xfffb + +/* Source addresses must be < 0xfff0. */ +#define DNP3_SRC_ADDR_MAX 0xfff0 + +#define DNP3_OBJ_TIME_SIZE 6 /* AKA UINT48. */ +#define DNP3_OBJ_G12_V1_SIZE 11 +#define DNP3_OBJ_G12_V2_SIZE 11 +#define DNP3_OBJ_G12_V3_SIZE 1 + +/* Extract the prefix code from the object qualifier. */ +#define DNP3_OBJ_PREFIX(x) ((x >> 4) & 0x7) + +/* Extract the range code from the object qualifier. */ +#define DNP3_OBJ_RANGE(x) (x & 0xf) + +/* Decoder event map. */ +SCEnumCharMap dnp3_decoder_event_table[] = { + { "FLOODED", DNP3_DECODER_EVENT_FLOODED }, + { "LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL }, + { "BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC }, + { "BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC }, + { "MALFORMED", DNP3_DECODER_EVENT_MALFORMED }, + { "UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT }, + { NULL, -1 }, +}; + +/* Calculate the next transport sequence number. */ +#define NEXT_TH_SEQNO(current) ((current + 1) % DNP3_MAX_TRAN_SEQNO) + +/* Calculate the next application sequence number. */ +#define NEXT_APP_SEQNO(current) ((current + 1) % DNP3_MAX_APP_SEQNO) + +/* CRC table generated by pycrc - http://github.com/tpircher/pycrc. + * - Polynomial: 0x3d65. */ +static const uint16_t crc_table[256] = { 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, + 0x839a, 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13, 0xb26b, 0x8435, 0xded7, + 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1, 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, + 0xce78, 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35, 0xd626, 0xe078, 0xba9a, + 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc, 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, + 0x185e, 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7, 0x535e, 0x6500, 0x3fe2, + 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4, 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, + 0x2f4d, 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af, 0x1ebc, 0x28e2, 0x7200, + 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26, 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, + 0xf96b, 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2, 0xc89a, 0xfec4, 0xa426, + 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00, 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, + 0xb489, 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526, 0x5935, 0x6f6b, 0x3589, + 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf, 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, + 0x974d, 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4, 0x8f13, 0xb94d, 0xe3af, + 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89, 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, + 0xf300, 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2, 0xc2f1, 0xf4af, 0xae4d, + 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b, 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, + 0x7678, 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1, 0x4789, 0x71d7, 0x2b35, + 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413, 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, + 0x3b9a, 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7, 0x23c4, 0x159a, 0x4f78, + 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e, 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, + 0xedbc, 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235 }; + +/** + * \brief Compute the CRC for a buffer. + * + * \param buf Buffer to create CRC from. + * \param len Length of buffer (number of bytes to use for CRC). + + */ +static uint16_t DNP3ComputeCRC(const uint8_t *buf, uint32_t len) +{ + const uint8_t *byte = buf; + uint16_t crc = 0; + int idx; + + while (len--) { + idx = (crc ^ *byte) & 0xff; + crc = (crc_table[idx] ^ (crc >> 8)) & 0xffff; + byte++; + } + + return ~crc & 0xffff; +} + +/** + * \brief Check the CRC of a block. + * + * \param block The block of data with CRC to be checked. + * \param len The size of the data block. + * + * \retval 1 if CRC is OK, otherwise 0. + */ +static int DNP3CheckCRC(const uint8_t *block, uint32_t len) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + return 1; +#endif + uint32_t crc_offset; + uint16_t crc; + + /* Need at least one byte plus the CRC. */ + if (len < DNP3_CRC_LEN + 1) { + return 0; + } + + crc_offset = len - DNP3_CRC_LEN; + crc = DNP3ComputeCRC(block, len - DNP3_CRC_LEN); + if (((crc & 0xff) == block[crc_offset]) && ((crc >> 8) == block[crc_offset + 1])) { + return 1; + } + + return 0; +} + +/** + * \brief Check the CRC of the link header. + * + * \param header Point to the link header. + * + * \retval 1 if header CRC is OK, otherwise 0. + */ +static int DNP3CheckLinkHeaderCRC(const DNP3LinkHeader *header) +{ + return DNP3CheckCRC((uint8_t *)header, sizeof(DNP3LinkHeader)); +} + +/** + * \brief Check user data CRCs. + * + * \param data Pointer to user data. + * \param len Length of user data. + * + * \retval 1 if CRCs are OK, otherwise 0. + */ +static int DNP3CheckUserDataCRCs(const uint8_t *data, uint32_t len) +{ + uint32_t offset = 0; + uint32_t block_size; + + while (offset < len) { + if (len - offset >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; + } else { + block_size = len - offset; + } + + if (!DNP3CheckCRC(data + offset, block_size)) { + /* Once failed, may as well return immediately. */ + return 0; + } + + offset += block_size; + } + + return 1; +} + +/** + * \brief Check the DNP3 frame start bytes. + * + * \retval 1 if valid, 0 if not. + */ +static int DNP3CheckStartBytes(const DNP3LinkHeader *header) +{ + return header->start_byte0 == DNP3_START_BYTE0 && header->start_byte1 == DNP3_START_BYTE1; +} + +/* Some DNP3 servers start with a banner. */ +#define DNP3_BANNER "DNP3" + +/** + * \brief Check if a frame contains a banner. + * + * Some servers (outstations) appear to send back a banner that fails + * the normal frame checks. So first check for a banner. + * + * \retval 1 if a banner is found, 0 if not. + */ +static int DNP3ContainsBanner(const uint8_t *input, uint32_t len) +{ + return BasicSearch(input, len, (uint8_t *)DNP3_BANNER, strlen(DNP3_BANNER)) != NULL; +} + +/** + * \brief DNP3 probing parser. + */ +static uint16_t DNP3ProbingParser( + Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir) +{ + const DNP3LinkHeader *const hdr = (const DNP3LinkHeader *)input; + const bool toserver = (direction & STREAM_TOSERVER) != 0; + + /* May be a banner. */ + if (DNP3ContainsBanner(input, len)) { + SCLogDebug("Packet contains a DNP3 banner."); + bool is_banner = true; + // magic 0x100 = 256 seems good enough + for (uint32_t i = 0; i < len && i < 0x100; i++) { + if (!isprint(input[i])) { + is_banner = false; + break; + } + } + if (is_banner) { + if (toserver) { + *rdir = STREAM_TOCLIENT; + } + return ALPROTO_DNP3; + } + } + + /* Check that we have the minimum amount of bytes. */ + if (len < sizeof(DNP3LinkHeader)) { + SCLogDebug("Length too small to be a DNP3 header."); + return ALPROTO_UNKNOWN; + } + + /* Verify start value (from AN2013-004b). */ + if (!DNP3CheckStartBytes(hdr)) { + SCLogDebug("Invalid start bytes."); + return ALPROTO_FAILED; + } + + /* Verify minimum length. */ + if (hdr->len < DNP3_MIN_LEN) { + SCLogDebug("Packet too small to be a valid DNP3 fragment."); + return ALPROTO_FAILED; + } + + // Test compatibility between direction and dnp3.ctl.direction + if ((DNP3_LINK_DIR(hdr->control) != 0) != toserver) { + *rdir = toserver ? STREAM_TOCLIENT : STREAM_TOSERVER; + } + SCLogDebug("Detected DNP3."); + return ALPROTO_DNP3; +} + +/** + * \brief Calculate the length of the transport layer with CRCs removed. + * + * \param input_len The length of the transport layer buffer. + * + * \retval The length of the buffer after CRCs are removed. + */ +static int DNP3CalculateTransportLengthWithoutCRCs(uint32_t input_len) +{ + /* Too small. */ + if (input_len < DNP3_CRC_LEN) { + return -1; + } + + /* Get the number of complete blocks. */ + int blocks = input_len / (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); + + /* And the number of bytes in the last block. */ + int rem = input_len - (blocks * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + + if (rem) { + if (rem < DNP3_CRC_LEN) { + return -1; + } + return (blocks * DNP3_BLOCK_SIZE) + (rem - DNP3_CRC_LEN); + } else { + return (blocks * DNP3_BLOCK_SIZE); + } +} + +/** + * \brief Reassemble the application layer by stripping the CRCs. + * + * Remove the CRCs from the user data blocks. The output is the user + * data with the CRCs removed as well as the transport header removed, + * but the input data still needs to include the transport header as + * its part of the first user data block. + * + * If the output length passed in is non-null, the new input data will + * be appended, and the output length pointer incremented as needed. + * + * \param input Input buffer starting at the transport header (which + * will be removed from the output). + * \param input_len Length of the input buffer. + * \param output Pointer to output buffer (may be realloc'd). + * \param output_len Pointer to output length. + * + * \retval 1 if reassembly was successful, otherwise 0. + */ +static int DNP3ReassembleApplicationLayer( + const uint8_t *input, uint32_t input_len, uint8_t **output, uint32_t *output_len) +{ + int len = DNP3CalculateTransportLengthWithoutCRCs(input_len); + + if (len <= 0) { + return 0; + } + + /* Remove one byte for the transport header and make sure we have + * at least one byte of user data. */ + if (--len < 1) { + return 0; + } + + if (*output == NULL) { + *output = SCCalloc(1, len); + if (unlikely(*output == NULL)) { + return 0; + } + } else { + uint8_t *ptr = SCRealloc(*output, (size_t)(*output_len + len)); + if (unlikely(ptr == NULL)) { + return 0; + } + *output = ptr; + } + + int offset = 0, block_size; + while ((uint32_t)offset < input_len) { + if (input_len - offset > DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; + } else { + block_size = input_len - offset; + } + + /* If handling the first block (offset is 0), trim off the + * first byte which is the transport header, and not part of + * the application data. */ + if (offset == 0) { + offset++; + block_size--; + } + + /* Need at least 3 bytes to continue. One for application + * data, and 2 for the CRC. If not, return failure for + * malformed frame. */ + if (block_size < DNP3_CRC_LEN + 1) { + SCLogDebug("Not enough data to continue."); + return 0; + } + + /* Make sure there is enough space to write into. */ + if (block_size - DNP3_CRC_LEN > len) { + SCLogDebug("Not enough data to continue."); + return 0; + } + + memcpy(*output + *output_len, input + offset, block_size - DNP3_CRC_LEN); + *output_len += block_size - DNP3_CRC_LEN; + offset += block_size; + len -= block_size - DNP3_CRC_LEN; + } + + return 1; +} + +/** + * \brief Allocate a DNP3 state object. + * + * The DNP3 state object represents a single DNP3 TCP session. + */ +static void *DNP3StateAlloc(void *orig_state, AppProto proto_orig) +{ + SCEnter(); + DNP3State *dnp3; + + dnp3 = (DNP3State *)SCCalloc(1, sizeof(DNP3State)); + if (unlikely(dnp3 == NULL)) { + return NULL; + } + TAILQ_INIT(&dnp3->tx_list); + + SCReturnPtr(dnp3, "void"); +} + +/** + * \brief Set a DNP3 application layer event. + * + * Sets an event on the current transaction object. + */ +static void DNP3SetEvent(DNP3State *dnp3, uint8_t event) +{ + if (dnp3 && dnp3->curr) { + AppLayerDecoderEventsSetEventRaw(&dnp3->curr->tx_data.events, event); + dnp3->events++; + } else { + SCLogWarning("Failed to set event, state or tx pointer was NULL."); + } +} + +/** + * \brief Set a DNP3 application layer event on a transaction. + */ +static void DNP3SetEventTx(DNP3Transaction *tx, uint8_t event) +{ + AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, event); + tx->dnp3->events++; +} + +/** + * \brief Allocation a DNP3 transaction. + */ +static DNP3Transaction *DNP3TxAlloc(DNP3State *dnp3, bool request) +{ + DNP3Transaction *tx = SCCalloc(1, sizeof(DNP3Transaction)); + if (unlikely(tx == NULL)) { + return NULL; + } + dnp3->transaction_max++; + dnp3->unreplied++; + dnp3->curr = tx; + tx->dnp3 = dnp3; + tx->tx_num = dnp3->transaction_max; + tx->is_request = request; + if (tx->is_request) { + tx->tx_data.detect_flags_tc |= APP_LAYER_TX_SKIP_INSPECT_FLAG; + } else { + tx->tx_data.detect_flags_ts |= APP_LAYER_TX_SKIP_INSPECT_FLAG; + } + TAILQ_INIT(&tx->objects); + TAILQ_INSERT_TAIL(&dnp3->tx_list, tx, next); + + /* Check for flood state. */ + if (dnp3->unreplied > DNP3_DEFAULT_REQ_FLOOD_COUNT) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_FLOODED); + dnp3->flooded = 1; + } + + return tx; +} + +/** + * \brief Calculate the length of a link frame with CRCs. + * + * This is required as the length parameter in the DNP3 header does not + * include the added CRCs. + * + * \param length The length from the DNP3 link header. + * + * \retval The length of the frame with CRCs included or 0 if the length isn't + * long enough to be a valid DNP3 frame. + */ +static uint32_t DNP3CalculateLinkLength(uint8_t length) +{ + uint32_t frame_len = 0; + int rem; + + /* Fail early if the length is less than the minimum size. */ + if (length < DNP3_LINK_HDR_LEN) { + return 0; + } + + /* Subtract the 5 bytes of the header that are included in the + * length. */ + length -= DNP3_LINK_HDR_LEN; + + rem = length % DNP3_BLOCK_SIZE; + frame_len = (length / DNP3_BLOCK_SIZE) * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); + if (rem) { + frame_len += rem + DNP3_CRC_LEN; + } + + return frame_len + sizeof(DNP3LinkHeader); +} + +/** + * \brief Check if the link function code specifies user data. + * + * \param header Point to link header. + * + * \retval 1 if frame contains user data, otherwise 0. + */ +static int DNP3IsUserData(const DNP3LinkHeader *header) +{ + switch (DNP3_LINK_FC(header->control)) { + case DNP3_LINK_FC_CONFIRMED_USER_DATA: + case DNP3_LINK_FC_UNCONFIRMED_USER_DATA: + return 1; + default: + return 0; + } +} + +/** + * \brief Check if the frame has user data. + * + * Check if the DNP3 frame actually has user data by checking if data + * exists after the headers. + * + * \retval 1 if user data exists, otherwise 0. + */ +static int DNP3HasUserData(const DNP3LinkHeader *header, uint8_t direction) +{ + if (direction == STREAM_TOSERVER) { + return header->len >= + DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + sizeof(DNP3ApplicationHeader); + } else { + return header->len >= DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + + sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); + } +} + +/** + * \brief Reset a DNP3Buffer. + */ +static void DNP3BufferReset(DNP3Buffer *buffer) +{ + buffer->offset = 0; + buffer->len = 0; +} + +/** + * \brief Add data to a DNP3 buffer, enlarging the buffer if required. + * + * \param buffer Buffer to add data data. + * \param data Data to be added to buffer. + * \param len Size of data to be added to buffer. + * + * \param 1 if data was added successful, otherwise 0. + */ +static int DNP3BufferAdd(DNP3Buffer *buffer, const uint8_t *data, uint32_t len) +{ + if (buffer->size == 0) { + buffer->buffer = SCCalloc(1, len); + if (unlikely(buffer->buffer == NULL)) { + return 0; + } + buffer->size = len; + } else if (buffer->len + len > buffer->size) { + uint8_t *tmp = SCRealloc(buffer->buffer, buffer->len + len); + if (unlikely(tmp == NULL)) { + return 0; + } + buffer->buffer = tmp; + buffer->size = buffer->len + len; + } + memcpy(buffer->buffer + buffer->len, data, len); + buffer->len += len; + + return 1; +} + +/** + * \brief Trim a DNP3 buffer. + * + * Trimming a buffer moves the data in the buffer up to the front of + * the buffer freeing up room at the end for more incoming data. + * + * \param buffer The buffer to trim. + */ +static void DNP3BufferTrim(DNP3Buffer *buffer) +{ + if (buffer->offset == buffer->len) { + DNP3BufferReset(buffer); + } else if (buffer->offset > 0) { + memmove(buffer->buffer, buffer->buffer + buffer->offset, buffer->len - buffer->offset); + buffer->len = buffer->len - buffer->offset; + buffer->offset = 0; + } +} + +/** + * \brief Free a DNP3 object. + */ +static void DNP3ObjectFree(DNP3Object *object) +{ + if (object->points != NULL) { + DNP3FreeObjectPointList(object->group, object->variation, object->points); + } + SCFree(object); +} + +/** + * \brief Allocate a DNP3 object. + */ +static DNP3Object *DNP3ObjectAlloc(void) +{ + DNP3Object *object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + return NULL; + } + object->points = DNP3PointListAlloc(); + if (object->points == NULL) { + DNP3ObjectFree(object); + return NULL; + } + return object; +} + +/** + * \brief Decode DNP3 application objects. + * + * This function decoded known DNP3 application objects. As the + * protocol isn't self describing, we can only decode the buffer while + * the application objects are known. As soon as an unknown + * group/variation is hit, we must stop processing. + * + * \param buf the input buffer + * \param len length of the input buffer + * \param objects pointer to list where decoded objects will be stored. + * + * \retval 1 if all objects decoded, 0 if all objects could not be decoded ( + * unknown group/variations) + */ +static int DNP3DecodeApplicationObjects( + DNP3Transaction *tx, const uint8_t *buf, uint32_t len, DNP3ObjectList *objects) +{ + int retval = 0; + + if (buf == NULL || len == 0) { + return 1; + } + + while (len) { + uint32_t offset = 0; + + if (len < sizeof(DNP3ObjHeader)) { + goto done; + } + DNP3ObjHeader *header = (DNP3ObjHeader *)buf; + offset += sizeof(DNP3ObjHeader); + + DNP3Object *object = DNP3ObjectAlloc(); + if (unlikely(object == NULL)) { + goto done; + } + TAILQ_INSERT_TAIL(objects, object, next); + + object->group = header->group; + object->variation = header->variation; + object->qualifier = header->qualifier; + object->prefix_code = DNP3_OBJ_PREFIX(header->qualifier); + object->range_code = DNP3_OBJ_RANGE(header->qualifier); + + /* IEEE 1815-2012, Table 4-5. */ + switch (object->range_code) { + case 0x00: + case 0x03: { + /* 1 octet start and stop indexes OR 1 octet start and + * stop virtual addresses. */ + if (offset + (sizeof(uint8_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = buf[offset++]; + object->stop = buf[offset++]; + object->count = object->stop - object->start + 1; + break; + } + case 0x01: + case 0x04: { + /* 2 octet start and stop indexes OR 2 octect start + * and stop virtual addresses. */ + if (offset + (sizeof(uint16_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + object->stop = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + object->count = object->stop - object->start + 1; + break; + } + case 0x02: + case 0x05: { + /* 4 octet start and stop indexes OR 4 octect start + * and stop virtual addresses. */ + if (offset + (sizeof(uint32_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + object->stop = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + object->count = object->stop - object->start + 1; + break; + } + case 0x06: + /* No range field. */ + object->count = 0; + break; + case 0x07: + /* 1 octet count of objects. */ + if (offset + sizeof(uint8_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = buf[offset]; + offset += sizeof(uint8_t); + break; + case 0x08: { + /* 2 octet count of objects. */ + if (offset + sizeof(uint16_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + break; + } + case 0x09: { + /* 4 octet count of objects. */ + if (offset + sizeof(uint32_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + break; + } + case 0x0b: { + if (offset + sizeof(uint8_t) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = *(uint8_t *)(buf + offset); + offset += sizeof(uint8_t); + break; + } + default: + SCLogDebug("Range code 0x%02x is reserved.", object->range_code); + goto done; + } + + buf += offset; + len -= offset; + + if (object->variation == 0 || object->count == 0) { + goto next; + } + + int event = DNP3DecodeObject(header->group, header->variation, &buf, &len, + object->prefix_code, object->start, object->count, object->points); + if (event) { + DNP3SetEventTx(tx, DNP3_DECODER_EVENT_UNKNOWN_OBJECT); + goto done; + } + + next: + continue; + } + + /* All objects were decoded. */ + retval = 1; + +not_enough_data: +done: + return retval; +} + +/** + * \brief Handle DNP3 request user data. + * + * \param dnp3 the current DNP3State + * \param input pointer to the DNP3 frame (starting with link header) + * \param input_len length of the input frame + */ +static void DNP3HandleUserDataRequest(DNP3State *dnp3, const uint8_t *input, uint32_t input_len) +{ + DNP3LinkHeader *lh; + DNP3TransportHeader th; + DNP3ApplicationHeader *ah; + DNP3Transaction *tx = NULL, *ttx; + + lh = (DNP3LinkHeader *)input; + + if (!DNP3CheckUserDataCRCs( + input + sizeof(DNP3LinkHeader), input_len - sizeof(DNP3LinkHeader))) { + return; + } + + th = input[sizeof(DNP3LinkHeader)]; + + if (!DNP3_TH_FIR(th)) { + TAILQ_FOREACH (ttx, &dnp3->tx_list, next) { + if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && ttx->is_request && !ttx->done && + NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->th)) == DNP3_TH_SEQ(th)) { + tx = ttx; + break; + } + } + + if (tx == NULL) { + return; + } + + /* Update the saved transport header so subsequent segments + * will be matched to this sequence number. */ + tx->th = th; + } else { + ah = (DNP3ApplicationHeader *)(input + sizeof(DNP3LinkHeader) + + sizeof(DNP3TransportHeader)); + + /* Ignore confirms - for now. */ + if (ah->function_code == DNP3_APP_FC_CONFIRM) { + return; + } + + /* Create a transaction. */ + tx = DNP3TxAlloc(dnp3, true); + if (unlikely(tx == NULL)) { + return; + } + tx->lh = *lh; + tx->th = th; + tx->ah = *ah; + } + + if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) { + + /* Malformed, set event and mark as done. */ + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); + tx->done = 1; + return; + } + + /* If this is not the final segment, just return. */ + if (!DNP3_TH_FIN(th)) { + return; + } + + tx->done = 1; + + if (DNP3DecodeApplicationObjects(tx, tx->buffer + sizeof(DNP3ApplicationHeader), + tx->buffer_len - sizeof(DNP3ApplicationHeader), &tx->objects)) { + tx->complete = 1; + } +} + +static void DNP3HandleUserDataResponse(DNP3State *dnp3, const uint8_t *input, uint32_t input_len) +{ + DNP3LinkHeader *lh; + DNP3TransportHeader th; + DNP3ApplicationHeader *ah; + DNP3InternalInd *iin; + DNP3Transaction *tx = NULL, *ttx; + uint32_t offset = 0; + + lh = (DNP3LinkHeader *)input; + offset += sizeof(DNP3LinkHeader); + + if (!DNP3CheckUserDataCRCs(input + offset, input_len - offset)) { + return; + } + + th = input[offset++]; + + if (!DNP3_TH_FIR(th)) { + TAILQ_FOREACH (ttx, &dnp3->tx_list, next) { + if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && !ttx->is_request && + !ttx->done && NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->th)) == DNP3_TH_SEQ(th)) { + tx = ttx; + break; + } + } + + if (tx == NULL) { + return; + } + + /* Replace the transport header in the transaction with this + * one in case there are more frames. */ + tx->th = th; + } else { + ah = (DNP3ApplicationHeader *)(input + offset); + offset += sizeof(DNP3ApplicationHeader); + iin = (DNP3InternalInd *)(input + offset); + + tx = DNP3TxAlloc(dnp3, false); + if (unlikely(tx == NULL)) { + return; + } + tx->lh = *lh; + tx->th = th; + tx->ah = *ah; + tx->iin = *iin; + } + + BUG_ON(tx->is_request); + + if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); + return; + } + + if (!DNP3_TH_FIN(th)) { + return; + } + + tx->done = 1; + + offset = sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); + if (DNP3DecodeApplicationObjects( + tx, tx->buffer + offset, tx->buffer_len - offset, &tx->objects)) { + tx->complete = 1; + } +} + +/** + * \brief Decode the DNP3 request link layer. + * + * \retval number of bytes processed or -1 if the data stream does not look + * like DNP3. + */ +static int DNP3HandleRequestLinkLayer(DNP3State *dnp3, const uint8_t *input, uint32_t input_len) +{ + SCEnter(); + uint32_t processed = 0; + + while (input_len) { + + /* Need at least enough bytes for a DNP3 header. */ + if (input_len < sizeof(DNP3LinkHeader)) { + break; + } + + DNP3LinkHeader *header = (DNP3LinkHeader *)input; + + if (!DNP3CheckStartBytes(header)) { + goto error; + } + + if (!DNP3CheckLinkHeaderCRC(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); + goto error; + } + + uint32_t frame_len = DNP3CalculateLinkLength(header->len); + if (frame_len == 0) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + if (input_len < frame_len) { + /* Insufficient data, just break - will wait for more data. */ + break; + } + + /* Ignore non-user data for now. */ + if (!DNP3IsUserData(header)) { + goto next; + } + + /* Make sure the header length is large enough for transport and + * application headers. */ + if (!DNP3HasUserData(header, STREAM_TOSERVER)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto next; + } + + if (!DNP3CheckUserDataCRCs( + input + sizeof(DNP3LinkHeader), frame_len - sizeof(DNP3LinkHeader))) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); + goto next; + } + + DNP3HandleUserDataRequest(dnp3, input, frame_len); + + next: + /* Advance the input buffer. */ + input += frame_len; + input_len -= frame_len; + processed += frame_len; + } + + SCReturnInt(processed); +error: + /* Error out. Should only happen if this doesn't look like a DNP3 + * frame. */ + SCReturnInt(-1); +} + +/** + * \brief Handle incoming request data. + * + * The actual request PDU parsing is done in + * DNP3HandleRequestLinkLayer. This function takes care of buffering TCP + * date if a segment does not contain a complete frame (or contains + * multiple frames, but not the complete final frame). + */ +static AppLayerResult DNP3ParseRequest(Flow *f, void *state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)state; + DNP3Buffer *buffer = &dnp3->request_buffer; + int processed = 0; + + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + if (input_len == 0) { + SCReturnStruct(APP_LAYER_OK); + } + + if (buffer->len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + goto error; + } + processed = DNP3HandleRequestLinkLayer( + dnp3, buffer->buffer + buffer->offset, buffer->len - buffer->offset); + if (processed < 0) { + goto error; + } + buffer->offset += processed; + DNP3BufferTrim(buffer); + } else { + processed = DNP3HandleRequestLinkLayer(dnp3, input, input_len); + if (processed < 0) { + SCLogDebug("Failed to process request link layer."); + goto error; + } + + input += processed; + input_len -= processed; + + /* Not all data was processed, buffer it. */ + if (input_len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + goto error; + } + } + } + + SCReturnStruct(APP_LAYER_OK); + +error: + /* Reset the buffer. */ + DNP3BufferReset(buffer); + SCReturnStruct(APP_LAYER_ERROR); +} + +/** + * \brief Decode the DNP3 response link layer. + * + * \retval number of bytes processed or -1 if the data stream does not + * like look DNP3. + */ +static int DNP3HandleResponseLinkLayer(DNP3State *dnp3, const uint8_t *input, uint32_t input_len) +{ + SCEnter(); + uint32_t processed = 0; + + while (input_len) { + + /* Need at least enough bytes for a DNP3 header. */ + if (input_len < sizeof(DNP3LinkHeader)) { + break; + } + + DNP3LinkHeader *header = (DNP3LinkHeader *)input; + + if (!DNP3CheckStartBytes(header)) { + goto error; + } + + if (!DNP3CheckLinkHeaderCRC(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); + goto error; + } + + /* Calculate the number of bytes needed to for this frame. */ + uint32_t frame_len = DNP3CalculateLinkLength(header->len); + if (frame_len == 0) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + if (input_len < frame_len) { + /* Insufficient data, just break - will wait for more data. */ + break; + } + + /* Only handle user data frames for now. */ + if (!DNP3IsUserData(header)) { + goto next; + } + + /* Make sure the header length is large enough for transport and + * application headers. */ + if (!DNP3HasUserData(header, STREAM_TOCLIENT)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + + if (!DNP3CheckUserDataCRCs( + input + sizeof(DNP3LinkHeader), frame_len - sizeof(DNP3LinkHeader))) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); + goto next; + } + + DNP3HandleUserDataResponse(dnp3, input, frame_len); + + next: + /* Advance the input buffer. */ + input += frame_len; + input_len -= frame_len; + processed += frame_len; + } + + SCReturnInt(processed); +error: + /* Error out. Should only happen if the data stream no longer + * looks like DNP3. */ + SCReturnInt(-1); +} + +/** + * \brief Parse incoming data. + * + * This is the entry function for DNP3 application layer data. Its + * main responsibility is buffering incoming data that cannot be + * processed. + * + * See DNP3ParseResponsePDUs for DNP3 frame handling. + */ +static AppLayerResult DNP3ParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + SCEnter(); + + DNP3State *dnp3 = (DNP3State *)state; + DNP3Buffer *buffer = &dnp3->response_buffer; + int processed; + + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + if (buffer->len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + goto error; + } + processed = DNP3HandleResponseLinkLayer( + dnp3, buffer->buffer + buffer->offset, buffer->len - buffer->offset); + if (processed < 0) { + goto error; + } + buffer->offset += processed; + DNP3BufferTrim(buffer); + } else { + + /* Check if this is a banner, ignore if it is. */ + if (DNP3ContainsBanner(input, input_len)) { + goto done; + } + + processed = DNP3HandleResponseLinkLayer(dnp3, input, input_len); + if (processed < 0) { + goto error; + } + input += processed; + input_len -= processed; + + /* Not all data was processed, buffer it. */ + if (input_len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + goto error; + } + } + } + +done: + SCReturnStruct(APP_LAYER_OK); + +error: + /* An error occurred while processing DNP3 frames. Dump the + * buffer as we can't be assured that they are valid anymore. */ + DNP3BufferReset(buffer); + SCReturnStruct(APP_LAYER_ERROR); +} + +static void *DNP3GetTx(void *alstate, uint64_t tx_id) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)alstate; + DNP3Transaction *tx = NULL; + uint64_t tx_num = tx_id + 1; + + if (dnp3->curr && dnp3->curr->tx_num == (tx_num)) { + SCReturnPtr(dnp3->curr, "void"); + } + + TAILQ_FOREACH (tx, &dnp3->tx_list, next) { + if (tx_num != tx->tx_num) { + continue; + } + SCReturnPtr(tx, "void"); + } + + SCReturnPtr(NULL, "void"); +} + +static uint64_t DNP3GetTxCnt(void *state) +{ + SCEnter(); + uint64_t count = ((uint64_t)((DNP3State *)state)->transaction_max); + SCReturnUInt(count); +} + +/** + * \brief Free all the objects in a DNP3ObjectList. + */ +static void DNP3TxFreeObjectList(DNP3ObjectList *objects) +{ + DNP3Object *object; + + while ((object = TAILQ_FIRST(objects)) != NULL) { + TAILQ_REMOVE(objects, object, next); + DNP3ObjectFree(object); + } +} + +/** + * \brief Free a DNP3 transaction. + */ +static void DNP3TxFree(DNP3Transaction *tx) +{ + SCEnter(); + + if (tx->buffer != NULL) { + SCFree(tx->buffer); + } + + AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); + + if (tx->tx_data.de_state != NULL) { + DetectEngineStateFree(tx->tx_data.de_state); + } + + DNP3TxFreeObjectList(&tx->objects); + + SCFree(tx); + SCReturn; +} + +/** + * \brief Free a transaction by ID on a specific DNP3 state. + * + * This function is called by the app-layer to free a transaction on a + * specific DNP3 state object. + */ +static void DNP3StateTxFree(void *state, uint64_t tx_id) +{ + SCEnter(); + DNP3State *dnp3 = state; + DNP3Transaction *tx = NULL, *ttx; + uint64_t tx_num = tx_id + 1; + + TAILQ_FOREACH_SAFE (tx, &dnp3->tx_list, next, ttx) { + + if (tx->tx_num != tx_num) { + continue; + } + + if (tx == dnp3->curr) { + dnp3->curr = NULL; + } + + if (tx->tx_data.events != NULL) { + if (tx->tx_data.events->cnt <= dnp3->events) { + dnp3->events -= tx->tx_data.events->cnt; + } else { + dnp3->events = 0; + } + } + dnp3->unreplied--; + + /* Check flood state. */ + if (dnp3->flooded && dnp3->unreplied < DNP3_DEFAULT_REQ_FLOOD_COUNT) { + dnp3->flooded = 0; + } + + TAILQ_REMOVE(&dnp3->tx_list, tx, next); + DNP3TxFree(tx); + break; + } + + SCReturn; +} + +/** + * \brief Free a DNP3 state. + */ +static void DNP3StateFree(void *state) +{ + SCEnter(); + DNP3State *dnp3 = state; + DNP3Transaction *tx; + if (state != NULL) { + while ((tx = TAILQ_FIRST(&dnp3->tx_list)) != NULL) { + TAILQ_REMOVE(&dnp3->tx_list, tx, next); + DNP3TxFree(tx); + } + if (dnp3->request_buffer.buffer != NULL) { + SCFree(dnp3->request_buffer.buffer); + } + if (dnp3->response_buffer.buffer != NULL) { + SCFree(dnp3->response_buffer.buffer); + } + SCFree(dnp3); + } + SCReturn; +} + +/** + * \brief Called by the app-layer to get the state progress. + */ +static int DNP3GetAlstateProgress(void *tx, uint8_t direction) +{ + DNP3Transaction *dnp3tx = (DNP3Transaction *)tx; + DNP3State *dnp3 = dnp3tx->dnp3; + int retval = 0; + + /* If flooded, "ack" old transactions. */ + if (dnp3->flooded && (dnp3->transaction_max - dnp3tx->tx_num >= DNP3_DEFAULT_REQ_FLOOD_COUNT)) { + SCLogDebug("flooded: returning tx as done."); + SCReturnInt(1); + } + + if (dnp3tx->complete) + retval = 1; + + SCReturnInt(retval); +} + +/** + * \brief App-layer support. + */ +static int DNP3StateGetEventInfo( + const char *event_name, int *event_id, AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, dnp3_decoder_event_table); + if (*event_id == -1) { + SCLogError("Event \"%s\" not present in " + "the DNP3 enum event map table.", + event_name); + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +/** + * \brief App-layer support. + */ +static int DNP3StateGetEventInfoById( + int event_id, const char **event_name, AppLayerEventType *event_type) +{ + *event_name = SCMapEnumValueToName(event_id, dnp3_decoder_event_table); + if (*event_name == NULL) { + SCLogError("Event \"%d\" not present in " + "the DNP3 enum event map table.", + event_id); + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static AppLayerTxData *DNP3GetTxData(void *vtx) +{ + DNP3Transaction *tx = (DNP3Transaction *)vtx; + return &tx->tx_data; +} + +static AppLayerStateData *DNP3GetStateData(void *vstate) +{ + DNP3State *state = (DNP3State *)vstate; + return &state->state_data; +} + +/** + * \brief Check if the prefix code is a size prefix. + * + * \retval 1 if the prefix_code specifies a size prefix, 0 if not. + */ +int DNP3PrefixIsSize(uint8_t prefix_code) +{ + switch (prefix_code) { + case 0x04: + case 0x05: + case 0x06: + return 1; + break; + default: + return 0; + } +} + +static AppLayerGetTxIterTuple DNP3GetTxIterator(const uint8_t ipproto, const AppProto alproto, + void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) +{ + DNP3State *dnp_state = (DNP3State *)alstate; + AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; + if (dnp_state) { + DNP3Transaction *tx_ptr; + if (state->un.ptr == NULL) { + tx_ptr = TAILQ_FIRST(&dnp_state->tx_list); + } else { + tx_ptr = (DNP3Transaction *)state->un.ptr; + } + if (tx_ptr) { + while (tx_ptr->tx_num < min_tx_id + 1) { + tx_ptr = TAILQ_NEXT(tx_ptr, next); + if (!tx_ptr) { + return no_tuple; + } + } + if (tx_ptr->tx_num >= max_tx_id + 1) { + return no_tuple; + } + state->un.ptr = TAILQ_NEXT(tx_ptr, next); + AppLayerGetTxIterTuple tuple = { + .tx_ptr = tx_ptr, + .tx_id = tx_ptr->tx_num - 1, + .has_next = (state->un.ptr != NULL), + }; + return tuple; + } + } + return no_tuple; +} + +/** + * \brief Register the DNP3 application protocol parser. + */ +void RegisterDNP3Parsers(void) +{ + SCEnter(); + + const char *proto_name = "dnp3"; + + if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_DNP3, proto_name); + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, DNP3_DEFAULT_PORT, ALPROTO_DNP3, 0, + sizeof(DNP3LinkHeader), STREAM_TOSERVER, DNP3ProbingParser, DNP3ProbingParser); + } else { + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_DNP3, + 0, sizeof(DNP3LinkHeader), DNP3ProbingParser, DNP3ProbingParser)) { + return; + } + } + + } else { + SCLogConfig("Protocol detection and parser disabled for DNP3."); + SCReturn; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + SCLogConfig("Registering DNP3/tcp parsers."); + + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOSERVER, DNP3ParseRequest); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOCLIENT, DNP3ParseResponse); + + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_DNP3, DNP3StateAlloc, DNP3StateFree); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTx); + AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTxIterator); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_DNP3, DNP3StateTxFree); + + AppLayerParserRegisterGetStateProgressFunc( + IPPROTO_TCP, ALPROTO_DNP3, DNP3GetAlstateProgress); + AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_DNP3, 1, 1); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNP3, DNP3StateGetEventInfo); + AppLayerParserRegisterGetEventInfoById( + IPPROTO_TCP, ALPROTO_DNP3, DNP3StateGetEventInfoById); + + AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTxData); + AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetStateData); + } else { + SCLogConfig("Parser disabled for protocol %s. " + "Protocol detection still on.", + proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_DNP3, DNP3ParserRegisterTests); +#endif + + SCReturn; +} + +#ifdef UNITTESTS + +#include "flow-util.h" +#include "stream-tcp.h" + +/** + * \brief Utility function to fix CRCs when mangling a frame. + */ +static void DNP3FixCrc(uint8_t *data, uint32_t len) +{ + uint32_t block_size; + + while (len) { + if (len >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE; + } else { + block_size = len - DNP3_CRC_LEN; + } + uint16_t crc = DNP3ComputeCRC(data, block_size); + data[block_size + 1] = (crc >> 8) & 0xff; + data[block_size] = crc & 0xff; + data += block_size + DNP3_CRC_LEN; + len -= block_size + DNP3_CRC_LEN; + } +} + +/** + * \test Test CRC checking on partial and full blocks. + */ +static int DNP3ParserTestCheckCRC(void) +{ + // clang-format off + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer - segment 1. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, + + /* Application layer - segment 2. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + // clang-format on + + /* Check link header CRC. */ + FAIL_IF(!DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); + + /* Check first application layer segment. */ + FAIL_IF(!DNP3CheckCRC(request + sizeof(DNP3LinkHeader), DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Change a byte in link header, should fail now. */ + request[2]++; + FAIL_IF(DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); + + /* Change a byte in the first application segment, should fail + * now. */ + request[sizeof(DNP3LinkHeader) + 3]++; + FAIL_IF(DNP3CheckCRC(request + sizeof(DNP3LinkHeader), DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); +#endif + + PASS; +} + +/** + * \test Test validation of all CRCs in user data. + */ +static int DNP3CheckUserDataCRCsTest(void) +{ + /* Multi-block data with valid CRCs. */ + // clang-format off + uint8_t data_valid[] = { + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0xff, 0xff, /* CRC. */ + }; + // clang-format on + FAIL_IF(!DNP3CheckUserDataCRCs(data_valid, sizeof(data_valid))); + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Multi-block data with one non-crc byte altered. */ + // clang-format off + uint8_t data_invalid[] = { + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x01, /* Invalid byte. */ + 0xff, 0xff, /* CRC. */ + }; + // clang-format on + FAIL_IF(DNP3CheckUserDataCRCs(data_invalid, sizeof(data_invalid))); + + /* 1 byte - need at least 3. */ + uint8_t one_byte_nocrc[] = { 0x01 }; + FAIL_IF(DNP3CheckUserDataCRCs(one_byte_nocrc, sizeof(one_byte_nocrc))); + + /* 2 bytes - need at least 3. */ + uint8_t two_byte_nocrc[] = { 0x01, 0x02 }; + FAIL_IF(DNP3CheckUserDataCRCs(two_byte_nocrc, sizeof(two_byte_nocrc))); +#endif + + /* 3 bytes, valid CRC. */ + uint8_t three_bytes_good_crc[] = { 0x00, 0x00, 0x00 }; + *(uint16_t *)(three_bytes_good_crc + 1) = DNP3ComputeCRC(three_bytes_good_crc, 1); + FAIL_IF(!DNP3CheckUserDataCRCs(three_bytes_good_crc, sizeof(three_bytes_good_crc))); + + PASS; +} + +/** + * \test Test the link layer length calculation. + * + * Test the calculation that converts the link provided in the DNP3 + * header to the actual length of the frame. That is the length with + * CRCs as the length in the header does not include CRCs. + */ +static int DNP3CalculateLinkLengthTest(void) +{ + /* These are invalid. */ + FAIL_IF(DNP3CalculateLinkLength(0) != 0); + FAIL_IF(DNP3CalculateLinkLength(1) != 0); + FAIL_IF(DNP3CalculateLinkLength(2) != 0); + FAIL_IF(DNP3CalculateLinkLength(3) != 0); + FAIL_IF(DNP3CalculateLinkLength(4) != 0); + + /* This is the minimum size. */ + FAIL_IF(DNP3CalculateLinkLength(5) != 10); + + /* 1 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(21) != 28); + + /* 2 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(37) != 46); + + /* 2 full user data blocks, plus one more byte. */ + /* 2 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(38) != 49); + + /* The maximum size. */ + FAIL_IF(DNP3CalculateLinkLength(255) != 292); + + PASS; +} + +/** + * \test The conversion of length with CRCs to the length without + * CRCs. + */ +static int DNP3CalculateTransportLengthWithoutCRCsTest(void) +{ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(0) != -1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(1) != -1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(2) != 0); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(3) != 1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(16) != 14); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(17) != 15); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(18) != 16); + + /* 19 bytes is not enough for a second block. */ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(19) != -1); + + /* 20 bytes really isn't enough either, but is large enough to + * satisfy the CRC on the second block. */ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(20) != 16); + + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(21) != 17); + + PASS; +} + +/** + * \test Test the validation of the link header CRC. + */ +static int DNP3ParserCheckLinkHeaderCRC(void) +{ + /* DNP3 frame with valid headers and CRCs. */ + // clang-format off + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + // clang-format on + + DNP3LinkHeader *header = (DNP3LinkHeader *)request; + FAIL_IF(!DNP3CheckLinkHeaderCRC(header)); + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Alter a byte in the header. */ + request[4] = 0; + FAIL_IF(DNP3CheckLinkHeaderCRC(header)); +#endif + + PASS; +} + +/** + * \test Test removal of CRCs from user data. + */ +static int DNP3ReassembleApplicationLayerTest01(void) +{ + uint32_t reassembled_len = 0; + uint8_t *output = NULL; + + // clang-format off + uint8_t payload[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0xff, 0xff, /* CRC. */ + }; + // clang-format on + + // clang-format off + uint8_t expected[] = { + 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0x00, 0x00, 0x00, 0x00, + 0x00 + /* CRC removed. */ + }; + // clang-format on + + /* Valid frame. */ + FAIL_IF(!DNP3ReassembleApplicationLayer(payload, sizeof(payload), &output, &reassembled_len)); + FAIL_IF(output == NULL); + FAIL_IF(reassembled_len != sizeof(expected)); + FAIL_IF(memcmp(expected, output, reassembled_len)); + SCFree(output); + + /* 1 byte, invalid. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 1, &output, &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 2 bytes, invalid. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 2, &output, &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 3 bytes, minimum - but that would only be the transport header + * which isn't included in the output. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 3, &output, &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 4 bytes is the minimum to get any reassembled data. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(!DNP3ReassembleApplicationLayer(payload, 4, &output, &reassembled_len)); + FAIL_IF(output == NULL); + FAIL_IF(reassembled_len != 1); + + /* Last block too short (by 1 byte) for data + CRC. */ + // clang-format off + uint8_t short_payload1[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00 + }; + // clang-format on + reassembled_len = 0; + FAIL_IF(DNP3ReassembleApplicationLayer( + short_payload1, sizeof(short_payload1), &output, &reassembled_len)); + + /* Last block too short (by 2 bytes) for data + CRC. */ + // clang-format off + uint8_t short_payload2[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, + }; + // clang-format on + reassembled_len = 0; + FAIL_IF(DNP3ReassembleApplicationLayer( + short_payload2, sizeof(short_payload2), &output, &reassembled_len)); + + PASS; +} + +/** + * \test Test the probing parser. + */ +static int DNP3ProbingParserTest(void) +{ + // clang-format off + uint8_t pkt[] = { + 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00, + 0xbd, 0x71 + }; + // clang-format on + uint8_t rdir = 0; + + /* Valid frame. */ + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_DNP3); + + /* Send too little bytes. */ + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(DNP3LinkHeader) - 1, &rdir) != + ALPROTO_UNKNOWN); + + /* Bad start bytes. */ + pkt[0] = 0x06; + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_FAILED); + + /* Restore start byte. */ + pkt[0] = 0x05; + + /* Set the length to a value less than the minimum length of 5. */ + pkt[2] = 0x03; + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt, sizeof(pkt), &rdir) != ALPROTO_FAILED); + + /* Send a banner. */ + char mybanner[] = "Welcome to DNP3 SCADA."; + FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, (uint8_t *)mybanner, sizeof(mybanner) - 1, + &rdir) != ALPROTO_DNP3); + FAIL_IF(rdir != STREAM_TOCLIENT); + + PASS; +} + +/** + * \test Test a basic request/response. + */ +static int DNP3ParserTestRequestResponse(void) +{ + DNP3State *state = NULL; + + // clang-format off + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + // clang-format on + + // clang-format off + uint8_t response[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff + }; + // clang-format on + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + flow.alproto = ALPROTO_DNP3; + + StreamTcpInitConfig(true); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->buffer == NULL); + FAIL_IF(tx->buffer_len != 20); + FAIL_IF(tx->ah.function_code != DNP3_APP_FC_DIR_OPERATE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOCLIENT, response, sizeof(response))); + SCMutexUnlock(&flow.m); + DNP3Transaction *tx0 = DNP3GetTx(state, 1); + FAIL_IF(tx0 == NULL); + FAIL_IF(tx0 == tx); + FAIL_IF(!tx0->done); + FAIL_IF(tx0->buffer == NULL); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&flow); + PASS; +} + +/** + * \test Test an unsolicited response from an outstation. + * + * This is kind of like a request initiated from the "server". + */ +static int DNP3ParserTestUnsolicitedResponseConfirm(void) +{ + DNP3State *state = NULL; + + /* Unsolicited response with confirm bit set. */ + // clang-format off + uint8_t response[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, + 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9 + }; + // clang-format on + + /* Confirm. */ + // clang-format off + uint8_t confirm[] = { + 0x05, 0x64, 0x08, 0xc4, 0x02, 0x00, + 0x01, 0x00, 0xd3, 0xb7, 0xc0, 0xda, 0x00, 0x6a, + 0x3d + }; + // clang-format on + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + flow.alproto = ALPROTO_DNP3; + + StreamTcpInitConfig(true); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOCLIENT, response, sizeof(response))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(!tx->done); + FAIL_IF(tx->ah.function_code != DNP3_APP_FC_UNSOLICITED_RESP); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOSERVER, confirm, sizeof(confirm))); + SCMutexUnlock(&flow.m); + + /* Confirms are ignored currently. With the move to + unidirectional transactions it might be easy to support these + now. */ + DNP3Transaction *resptx = DNP3GetTx(state, 1); + FAIL_IF(resptx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&flow); + PASS; +} + +/** + * \test Test flood state. + * + * Note that flood state needs to revisited with the modification to a + * unidirectional protocol. + */ +static int DNP3ParserTestFlooded(void) +{ + DNP3State *state = NULL; + + // clang-format off + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + // clang-format on + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + flow.alproto = ALPROTO_DNP3; + + StreamTcpInitConfig(true); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->buffer == NULL); + FAIL_IF(tx->buffer_len != 20); + FAIL_IF(tx->ah.function_code != DNP3_APP_FC_DIR_OPERATE); + FAIL_IF_NOT(tx->done); + FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER)); + + for (int i = 0; i < DNP3_DEFAULT_REQ_FLOOD_COUNT - 1; i++) { + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + } + FAIL_IF(state->flooded); + FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER)); + + /* One more request should trip us into flooded state. */ + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + FAIL_IF(!state->flooded); + + /* Progress for the oldest tx should return 1. */ + FAIL_IF(!DNP3GetAlstateProgress(tx, 0)); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&flow); + PASS; +} + +/** + * \test Test parsing of partial frames. + * + * As DNP3 operates over TCP, it is possible that a partial DNP3 frame + * is received. Test that the partial frame will be buffered until the + * remainder is seen. + */ +static int DNP3ParserTestPartialFrame(void) +{ + DNP3State *state = NULL; + DNP3Transaction *tx; + int r; + + // clang-format off + uint8_t request_partial1[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + }; + // clang-format on + + // clang-format off + uint8_t request_partial2[] = { + /* Remainder of application layer. */ + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + // clang-format on + + // clang-format off + uint8_t response_partial1[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + }; + // clang-format on + + // clang-format off + uint8_t response_partial2[] = { + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff + }; + // clang-format on + + /* Boiler plate for app layer setup. */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + flow.alproto = ALPROTO_DNP3; + StreamTcpInitConfig(true); + + /* Pass in the first partial frame. */ + + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOSERVER, request_partial1, + sizeof(request_partial1)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* Frame should just be buffered, but not yet processed. */ + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(state->request_buffer.len != sizeof(request_partial1)); + FAIL_IF(state->request_buffer.offset != 0); + FAIL_IF(memcmp(state->request_buffer.buffer, request_partial1, sizeof(request_partial1))); + + /* There should not be a transaction yet. */ + FAIL_IF(state->transaction_max != 0); + FAIL_IF(DNP3GetTx(state, 0) != NULL); + + /* Send the second partial. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOSERVER, request_partial2, + sizeof(request_partial2)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* The second partial completed the frame, the buffer should now + * be clear. */ + FAIL_IF(state->request_buffer.len != 0); + FAIL_IF(state->request_buffer.offset != 0); + + /* Should now have a complete transaction. */ + tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->buffer == NULL); + FAIL_IF(tx->buffer_len != 20); + FAIL_IF(tx->ah.function_code != DNP3_APP_FC_DIR_OPERATE); + + /* Send partial response. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOCLIENT, response_partial1, + sizeof(response_partial1)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + FAIL_IF(state->response_buffer.len != sizeof(response_partial1)); + FAIL_IF(state->response_buffer.offset != 0); + tx = DNP3GetTx(state, 1); + FAIL_IF_NOT_NULL(tx); + + /* Send rest of response. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOCLIENT, response_partial2, + sizeof(response_partial2)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* Buffer should now be empty. */ + FAIL_IF(state->response_buffer.len != 0); + FAIL_IF(state->response_buffer.offset != 0); + + /* There should now be a response transaction. */ + tx = DNP3GetTx(state, 1); + FAIL_IF_NULL(tx); + FAIL_IF(tx->buffer == NULL); + FAIL_IF(tx->buffer_len == 0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&flow); + PASS; +} + +/** + * \test Test multiple DNP3 frames in one TCP read. + */ +static int DNP3ParserTestMultiFrame(void) +{ + DNP3State *state = NULL; + + /* Unsolicited response 1. */ + // clang-format off + uint8_t unsol_response1[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, + 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9, + }; + // clang-format on + + /* Unsolicited response 2. */ + // clang-format off + uint8_t unsol_response2[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc5, 0xfb, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x0c, 0x01, 0xd8, 0x75, 0xd8, + 0x32, 0x4c, 0xc9, 0x3c, 0x01, 0xa1, 0xc9, + }; + // clang-format on + + uint8_t combined[sizeof(unsol_response1) + sizeof(unsol_response2)]; + memcpy(combined, unsol_response1, sizeof(unsol_response1)); + memcpy(combined + sizeof(unsol_response1), unsol_response2, sizeof(unsol_response2)); + + /* Setup. */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + int r; + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + flow.alproto = ALPROTO_DNP3; + StreamTcpInitConfig(true); + + SCMutexLock(&flow.m); + r = AppLayerParserParse( + NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOCLIENT, combined, sizeof(combined)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(state->transaction_max != 2); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&flow); + PASS; +} + +/** + * \test Test the parsing of a request PDU. + * + * The PDU under test contains a single read request object: + * - Group: 1 + * - Variation: 0 + * - Count: 0 + */ +static int DNP3ParserTestParsePDU01(void) +{ + /* Frame to be tested. This frame is a DNP3 request with one read + * request data object, group 1, variation 0. */ + // clang-format off + const uint8_t pkt[] = { + 0x05, 0x64, + 0x0b, 0xc4, 0x17, 0x00, 0xef, 0xff, 0xc4, 0x8f, + 0xe1, 0xc8, 0x01, 0x01, 0x00, 0x06, 0x77, 0x6e + }; + // clang-format on + + DNP3State *dnp3state = DNP3StateAlloc(NULL, ALPROTO_UNKNOWN); + int pdus = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(pdus < 1); + DNP3Transaction *dnp3tx = DNP3GetTx(dnp3state, 0); + FAIL_IF_NULL(dnp3tx); + FAIL_IF(!dnp3tx->is_request); + FAIL_IF(TAILQ_EMPTY(&dnp3tx->objects)); + DNP3Object *object = TAILQ_FIRST(&dnp3tx->objects); + FAIL_IF(object->group != 1 || object->variation != 0); + FAIL_IF(object->count != 0); + + DNP3StateFree(dnp3state); + PASS; +} + +/** + * \test Test the decode of a DNP3 fragment with a single 70:3 object. + */ +static int DNP3ParserDecodeG70V3Test(void) +{ + // clang-format off + const uint8_t pkt[] = { + 0x05, 0x64, + 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, 0xc7, 0xee, + 0xc7, 0xc9, 0x1b, 0x46, 0x03, 0x5b, 0x01, 0x55, + 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, + 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, + 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, + 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, + 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, + 0xc4, 0x8b + }; + // clang-format on + + DNP3State *dnp3state = DNP3StateAlloc(NULL, ALPROTO_UNKNOWN); + FAIL_IF_NULL(dnp3state); + int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(bytes != sizeof(pkt)); + DNP3Transaction *tx = DNP3GetTx(dnp3state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NOT(tx->is_request); + DNP3Object *obj = TAILQ_FIRST(&tx->objects); + FAIL_IF_NULL(obj); + FAIL_IF_NOT(obj->group == 70); + FAIL_IF_NOT(obj->variation == 3); + FAIL_IF_NOT(obj->prefix_code == 0x5); + FAIL_IF_NOT(obj->range_code == 0xb); + FAIL_IF_NOT(obj->count == 1); + DNP3Point *point = TAILQ_FIRST(obj->points); + FAIL_IF_NULL(point); + FAIL_IF_NOT(point->prefix == 85); + FAIL_IF_NOT(point->size == 85); + FAIL_IF_NULL(point->data); + DNP3ObjectG70V3 *data = point->data; + FAIL_IF_NOT(strcmp(data->filename, + "C:/temp/DNPDeviceConfiguration written to Remote Device.xml") == 0); + DNP3StateFree(dnp3state); + PASS; +} + +/** + * \brief Test that an alert is raised on an unknown object. + */ +static int DNP3ParserUnknownEventAlertTest(void) +{ + /* Valid DNP3 frame with 70:3 object. */ + // clang-format off + uint8_t pkt[] = { + 0x05, 0x64, 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, + 0xc7, 0xee, + + 0xc7, 0xc9, 0x1b, + + /* Object and variation. Originally 70:3, now 70:99, an + * unknown object. */ + 0x46, 0x63, + + 0x5b, 0x01, 0x55, + 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, + 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, + 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, + 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, + 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, + 0xc4, 0x8b + }; + // clang-format on + + DNP3FixCrc(pkt + 10, sizeof(pkt) - 10); + + DNP3State *dnp3state = DNP3StateAlloc(NULL, ALPROTO_UNKNOWN); + FAIL_IF_NULL(dnp3state); + int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(bytes != sizeof(pkt)); + + DNP3StateFree(dnp3state); + PASS; +} + +/** + * \brief Test that an alert is raised on incorrect data. + */ +static int DNP3ParserIncorrectUserData(void) +{ + // clang-format off + uint8_t packet_bytes[] = { + 0x05, 0x64, 0x08, 0xc4, 0x03, 0x00, 0x04, 0x00, + 0xbf, 0xe9, 0xc1, 0xc1, 0x82, 0xc5, 0xee + }; + // clang-format on + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + flow.alproto = ALPROTO_DNP3; + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, STREAM_TOCLIENT, packet_bytes, + sizeof(packet_bytes)); + + FAIL_IF(r == 0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&flow); + PASS; +} + +#endif + +void DNP3ParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DNP3ParserTestCheckCRC", DNP3ParserTestCheckCRC); + UtRegisterTest("DNP3ParserCheckLinkHeaderCRC", DNP3ParserCheckLinkHeaderCRC); + UtRegisterTest("DNP3CheckUserDataCRCsTest", DNP3CheckUserDataCRCsTest); + UtRegisterTest("DNP3CalculateLinkLengthTest", DNP3CalculateLinkLengthTest); + UtRegisterTest("DNP3CalculateTransportLengthWithoutCRCsTest", + DNP3CalculateTransportLengthWithoutCRCsTest); + UtRegisterTest("DNP3ReassembleApplicationLayerTest01", DNP3ReassembleApplicationLayerTest01); + UtRegisterTest("DNP3ProbingParserTest", DNP3ProbingParserTest); + UtRegisterTest("DNP3ParserTestRequestResponse", DNP3ParserTestRequestResponse); + UtRegisterTest( + "DNP3ParserTestUnsolicitedResponseConfirm", DNP3ParserTestUnsolicitedResponseConfirm); + UtRegisterTest("DNP3ParserTestPartialFrame", DNP3ParserTestPartialFrame); + UtRegisterTest("DNP3ParserTestMultiFrame", DNP3ParserTestMultiFrame); + UtRegisterTest("DNP3ParserTestFlooded", DNP3ParserTestFlooded); + UtRegisterTest("DNP3ParserTestParsePDU01", DNP3ParserTestParsePDU01); + UtRegisterTest("DNP3ParserDecodeG70V3Test", DNP3ParserDecodeG70V3Test); + UtRegisterTest("DNP3ParserUnknownEventAlertTest", DNP3ParserUnknownEventAlertTest); + UtRegisterTest("DNP3ParserIncorrectUserData", DNP3ParserIncorrectUserData); +#endif +} diff --git a/src/app-layer/dnp3/parser.h b/src/app-layer/dnp3/parser.h new file mode 100644 index 000000000000..345257e0aaf5 --- /dev/null +++ b/src/app-layer/dnp3/parser.h @@ -0,0 +1,260 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * DNP3 application layer protocol header file + */ + +#ifndef __APP_LAYER_DNP3_H__ +#define __APP_LAYER_DNP3_H__ + +#include "rust.h" +#if __BYTE_ORDER == __BIG_ENDIAN +#include "util/byte.h" +#endif + +/* DNP3 application request function codes. */ +#define DNP3_APP_FC_CONFIRM 0x00 +#define DNP3_APP_FC_READ 0x01 +#define DNP3_APP_FC_WRITE 0x02 +#define DNP3_APP_FC_SELECT 0x03 +#define DNP3_APP_FC_OPERATE 0x04 +#define DNP3_APP_FC_DIR_OPERATE 0x05 +#define DNP3_APP_FC_DIR_OPERATE_NR 0x06 +#define DNP3_APP_FC_FREEZE 0x07 +#define DNP3_APP_FC_FREEZE_NR 0x08 +#define DNP3_APP_FC_FREEZE_CLEAR 0x09 +#define DNP3_APP_FC_FREEZE_CLEAR_NR 0x0a +#define DNP3_APP_FC_FREEZE_AT_TIME 0x0b +#define DNP3_APP_FC_FREEZE_AT_TIME_NR 0x0c +#define DNP3_APP_FC_COLD_RESTART 0x0d +#define DNP3_APP_FC_WARM_RESTART 0x0e +#define DNP3_APP_FC_INITIALIZE_DATA 0x0f +#define DNP3_APP_FC_INITIALIZE_APPLICATION 0x10 +#define DNP3_APP_FC_START_APPLICATION 0x11 +#define DNP3_APP_FC_STOP_APPLICATION 0x12 +#define DNP3_APP_FC_SAVE_CONFIGURATION 0x13 +#define DNP3_APP_FC_ENABLE_UNSOLICITED 0x14 +#define DNP3_APP_FC_DISABLE_UNSOLICITED 0x15 +#define DNP3_APP_FC_ASSIGN_CLASS 0x16 +#define DNP3_APP_FC_DELAY_MEASUREMENT 0x17 +#define DNP3_APP_FC_RECORD_CURRENT_TIME 0x18 +#define DNP3_APP_FC_OPEN_TIME 0x19 +#define DNP3_APP_FC_CLOSE_FILE 0x1a +#define DNP3_APP_FC_DELETE_FILE 0x1b +#define DNP3_APP_FC_GET_FILE_INFO 0x1c +#define DNP3_APP_FC_AUTHENTICATE_FILE 0x1d +#define DNP3_APP_FC_ABORT_FILE 0x1e +#define DNP3_APP_FC_ACTIVATE_CONFIG 0x1f +#define DNP3_APP_FC_AUTH_REQ 0x20 +#define DNP3_APP_FC_AUTH_REQ_NR 0x21 + +/* DNP3 application response function codes. */ +#define DNP3_APP_FC_RESPONSE 0x81 +#define DNP3_APP_FC_UNSOLICITED_RESP 0x82 +#define DNP3_APP_FC_AUTH_RESP 0x83 + +/* Extract fields from the link control octet. */ +#define DNP3_LINK_DIR(control) (control & 0x80) +#define DNP3_LINK_PRI(control) (control & 0x40) +#define DNP3_LINK_FCB(control) (control & 0x20) +#define DNP3_LINK_FCV(control) (control & 0x10) +#define DNP3_LINK_FC(control) (control & 0x0f) + +/* Extract fields from transport layer header octet. */ +#define DNP3_TH_FIN(x) (x & 0x80) +#define DNP3_TH_FIR(x) (x & 0x40) +#define DNP3_TH_SEQ(x) (x & 0x3f) + +/* Extract fields from the application control octet. */ +#define DNP3_APP_FIR(x) (x & 0x80) +#define DNP3_APP_FIN(x) (x & 0x40) +#define DNP3_APP_CON(x) (x & 0x20) +#define DNP3_APP_UNS(x) (x & 0x10) +#define DNP3_APP_SEQ(x) (x & 0x0f) + +/* DNP3 values are stored in little endian on the wire, so swapping will be + * needed on big endian architectures. */ +#if __BYTE_ORDER == __BIG_ENDIAN +#define DNP3_SWAP16(x) SCByteSwap16(x) +#define DNP3_SWAP32(x) SCByteSwap32(x) +#define DNP3_SWAP64(x) SCByteSwap64(x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define DNP3_SWAP16(x) x +#define DNP3_SWAP32(x) x +#define DNP3_SWAP64(x) x +#endif + +/* DNP3 decoder events. */ +enum { + DNP3_DECODER_EVENT_FLOODED = 1, + DNP3_DECODER_EVENT_LEN_TOO_SMALL, + DNP3_DECODER_EVENT_BAD_LINK_CRC, + DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC, + DNP3_DECODER_EVENT_MALFORMED, + DNP3_DECODER_EVENT_UNKNOWN_OBJECT, +}; + +/** + * \brief DNP3 link header. + */ +typedef struct DNP3LinkHeader_ { + uint8_t start_byte0; /**< First check byte. */ + uint8_t start_byte1; /**< Second check byte. */ + uint8_t len; /**< Length of PDU without CRCs. */ + uint8_t control; /**< Control flags. */ + uint16_t dst; /**< DNP3 destination address. */ + uint16_t src; /**< DNP3 source address. */ + uint16_t crc; /**< Link header CRC. */ +} __attribute__((__packed__)) DNP3LinkHeader; + +/** + * \brief DNP3 transport header. + */ +typedef uint8_t DNP3TransportHeader; + +/** + * \brief DNP3 application header. + */ +typedef struct DNP3ApplicationHeader_ { + uint8_t control; /**< Control flags. */ + uint8_t function_code; /**< Application function code. */ +} __attribute__((__packed__)) DNP3ApplicationHeader; + +/** + * \brief DNP3 internal indicators. + * + * Part of the application header for responses only. + */ +typedef struct DNP3InternalInd_ { + uint8_t iin1; + uint8_t iin2; +} __attribute__((__packed__)) DNP3InternalInd; + +/** + * \brief A struct used for buffering incoming data prior to reassembly. + */ +typedef struct DNP3Buffer_ { + uint8_t *buffer; + size_t size; + int len; + int offset; +} DNP3Buffer; + +/** + * \brief DNP3 application object header. + */ +typedef struct DNP3ObjHeader_ { + uint8_t group; + uint8_t variation; + uint8_t qualifier; +} __attribute__((packed)) DNP3ObjHeader; + +/** + * \brief DNP3 object point. + * + * Each DNP3 object can have 0 or more points representing the values + * of the object. + */ +typedef struct DNP3Point_ { + uint32_t prefix; /**< Prefix value for point. */ + uint32_t index; /**< Index of point. If the object is prefixed + * with an index then this will be that + * value. Otherwise this is the place the point + * was in the list of points (starting at 0). */ + uint32_t size; /**< Size of point if the object prefix was a + * size. */ + void *data; /**< Data for this point. */ + TAILQ_ENTRY(DNP3Point_) next; +} DNP3Point; + +typedef TAILQ_HEAD(DNP3PointList_, DNP3Point_) DNP3PointList; + +/** + * \brief Struct to hold the list of decoded objects. + */ +typedef struct DNP3Object_ { + uint8_t group; + uint8_t variation; + uint8_t qualifier; + uint8_t prefix_code; + uint8_t range_code; + uint32_t start; + uint32_t stop; + uint32_t count; + DNP3PointList *points; /**< List of points for this object. */ + + TAILQ_ENTRY(DNP3Object_) next; +} DNP3Object; + +typedef TAILQ_HEAD(DNP3ObjectList_, DNP3Object_) DNP3ObjectList; + +/** + * \brief DNP3 transaction. + */ +typedef struct DNP3Transaction_ { + AppLayerTxData tx_data; + + uint64_t tx_num; /**< Internal transaction ID. */ + bool is_request; /**< Is this tx a request? */ + + struct DNP3State_ *dnp3; + + uint8_t *buffer; /**< Reassembled request buffer. */ + uint32_t buffer_len; + DNP3ObjectList objects; + DNP3LinkHeader lh; + DNP3TransportHeader th; + DNP3ApplicationHeader ah; + DNP3InternalInd iin; + uint8_t done; + uint8_t complete; /**< Was the decode complete. It will not be + complete if we hit objects we do not know. */ + + TAILQ_ENTRY(DNP3Transaction_) next; +} DNP3Transaction; + +TAILQ_HEAD(TxListHead, DNP3Transaction_); + +/** + * \brief Per flow DNP3 state. + */ +typedef struct DNP3State_ { + AppLayerStateData state_data; + TAILQ_HEAD(, DNP3Transaction_) tx_list; + DNP3Transaction *curr; /**< Current transaction. */ + uint64_t transaction_max; + uint16_t events; + uint32_t unreplied; /**< Number of unreplied requests. */ + uint8_t flooded; /**< Flag indicating flood. */ + + DNP3Buffer request_buffer; /**< Request buffer for buffering + * incomplete request PDUs received + * over TCP. */ + DNP3Buffer response_buffer; /**< Response buffer for buffering + * incomplete response PDUs received + * over TCP. */ + +} DNP3State; + +void RegisterDNP3Parsers(void); +void DNP3ParserRegisterTests(void); +int DNP3PrefixIsSize(uint8_t); + +#endif /* __APP_LAYER_DNP3_H__ */ diff --git a/src/app-layer/dns/detect-opcode.c b/src/app-layer/dns/detect-opcode.c new file mode 100644 index 000000000000..64bbb5c2f5d0 --- /dev/null +++ b/src/app-layer/dns/detect-opcode.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "app-layer/dns/detect-opcode.h" +#include "rust.h" + +static int dns_opcode_list_id = 0; + +static void DetectDnsOpcodeFree(DetectEngineCtx *, void *ptr); + +static int DetectDnsOpcodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + SCEnter(); + + if (DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0) { + return -1; + } + + void *detect = rs_detect_dns_opcode_parse(str); + if (detect == NULL) { + SCLogError("failed to parse dns.opcode: %s", str); + return -1; + } + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNS_OPCODE, (SigMatchCtx *)detect, + dns_opcode_list_id) == NULL) { + goto error; + } + + SCReturnInt(0); + +error: + DetectDnsOpcodeFree(de_ctx, detect); + SCReturnInt(-1); +} + +static void DetectDnsOpcodeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCEnter(); + if (ptr != NULL) { + rs_dns_detect_opcode_free(ptr); + } + SCReturn; +} + +static int DetectDnsOpcodeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + return rs_dns_opcode_match(txv, (void *)ctx, flags); +} + +void DetectDnsOpcodeRegister(void) +{ + sigmatch_table[DETECT_AL_DNS_OPCODE].name = "dns.opcode"; + sigmatch_table[DETECT_AL_DNS_OPCODE].desc = "Match the DNS header opcode flag."; + sigmatch_table[DETECT_AL_DNS_OPCODE].Setup = DetectDnsOpcodeSetup; + sigmatch_table[DETECT_AL_DNS_OPCODE].Free = DetectDnsOpcodeFree; + sigmatch_table[DETECT_AL_DNS_OPCODE].Match = NULL; + sigmatch_table[DETECT_AL_DNS_OPCODE].AppLayerTxMatch = DetectDnsOpcodeMatch; + + DetectAppLayerInspectEngineRegister2( + "dns.opcode", ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2( + "dns.opcode", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); + + dns_opcode_list_id = DetectBufferTypeGetByName("dns.opcode"); +} diff --git a/src/detect-dns-opcode.h b/src/app-layer/dns/detect-opcode.h similarity index 100% rename from src/detect-dns-opcode.h rename to src/app-layer/dns/detect-opcode.h diff --git a/src/app-layer/dns/detect-query.c b/src/app-layer/dns/detect-query.c new file mode 100644 index 000000000000..556de9f639d5 --- /dev/null +++ b/src/app-layer/dns/detect-query.c @@ -0,0 +1,864 @@ +/* Copyright (C) 2013-2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup dnslayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-build.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/spm.h" +#include "util/print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/dns/detect-query.h" + +#include "util/profiling.h" +#include "util/unittest-helper.h" +#include "rust.h" + +static int DetectDnsQuerySetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectDnsQueryRegisterTests(void); +#endif +static int g_dns_query_buffer_id = 0; + +struct DnsQueryGetDataArgs { + uint32_t local_id; /**< used as index into thread inspect array */ + void *txv; +}; + +static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, struct DnsQueryGetDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + const uint8_t *data; + uint32_t data_len; + if (rs_dns_tx_get_query_name(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectDnsQuery(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct DnsQueryGetDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + DnsQueryGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmDnsQuery { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmDnsQuery; + +/** \brief DnsQuery DnsQuery Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxDnsQuery(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmDnsQuery *ctx = (const PrefilterMpmDnsQuery *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + while (1) { + // loop until we get a NULL + + struct DnsQueryGetDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = DnsQueryGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static void PrefilterMpmDnsQueryFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmDnsQueryRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, + const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmDnsQuery *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxDnsQuery, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmDnsQueryFree, mpm_reg->pname); +} + +/** + * \brief Registration function for keyword: dns_query + */ +void DetectDnsQueryRegister(void) +{ + sigmatch_table[DETECT_AL_DNS_QUERY].name = "dns.query"; + sigmatch_table[DETECT_AL_DNS_QUERY].alias = "dns_query"; + sigmatch_table[DETECT_AL_DNS_QUERY].desc = "sticky buffer to match DNS query-buffer"; + sigmatch_table[DETECT_AL_DNS_QUERY].url = "/rules/dns-keywords.html#dns-query"; + sigmatch_table[DETECT_AL_DNS_QUERY].Setup = DetectDnsQuerySetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_DNS_QUERY].RegisterTests = DetectDnsQueryRegisterTests; +#endif + sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerMpmRegister2( + "dns_query", SIG_FLAG_TOSERVER, 2, PrefilterMpmDnsQueryRegister, NULL, ALPROTO_DNS, 1); + + DetectAppLayerInspectEngineRegister2( + "dns_query", ALPROTO_DNS, SIG_FLAG_TOSERVER, 1, DetectEngineInspectDnsQuery, NULL); + + DetectBufferTypeSetDescriptionByName("dns_query", "dns request query"); + DetectBufferTypeSupportsMultiInstance("dns_query"); + + g_dns_query_buffer_id = DetectBufferTypeGetByName("dns_query"); + +#ifdef HAVE_LUA + /* register these generic engines from here for now */ + DetectAppLayerInspectEngineRegister2( + "dns_request", ALPROTO_DNS, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + DetectAppLayerInspectEngineRegister2("dns_response", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectGenericList, NULL); + + DetectBufferTypeSetDescriptionByName("dns_request", "dns requests"); + DetectBufferTypeSetDescriptionByName("dns_response", "dns responses"); +#endif +} + +/** + * \brief setup the dns_query sticky buffer keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_dns_query_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_DNS) < 0) + return -1; + return 0; +} + +#ifdef UNITTESTS +#include "detect-isdataat.h" +#include "detect-engine-alert.h" + +/** \test simple google.com query matching */ +static int DetectDnsQueryTest01(void) +{ + /* google.com */ + // clang-format off + uint8_t buf[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, + 0x00, 0x10, 0x00, 0x01, }; + // clang-format on + Flow f; + void *dns_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_UDP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW; + p->flowflags |= FLOW_PKT_TOSERVER; + f.alproto = ALPROTO_DNS; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google\"; nocase; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + dns_state = f.alstate; + FAIL_IF_NULL(dns_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert, but it should have: "); + FAIL; + } + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +/** \test multi tx google.(com|net) query matching */ +static int DetectDnsQueryTest02(void) +{ + /* google.com */ + // clang-format off + uint8_t buf1[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, + 0x00, 0x01, 0x00, 0x01, }; + // clang-format on + + // clang-format off + uint8_t buf2[] = { 0x10, 0x32, /* tx id */ + 0x81, 0x80, /* flags: resp, recursion desired, recursion available */ + 0x00, 0x01, /* 1 query */ + 0x00, 0x01, /* 1 answer */ + 0x00, 0x00, 0x00, 0x00, /* no auth rr, additional rr */ + /* query record */ + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, /* name */ + 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* name cont */ + 0x00, 0x01, 0x00, 0x01, /* type a, class in */ + /* answer */ + 0xc0, 0x0c, /* ref to name in query above */ + 0x00, 0x01, 0x00, 0x01, /* type a, class in */ + 0x00, 0x01, 0x40, 0xef, /* ttl */ + 0x00, 0x04, /* data len */ + 0x01, 0x02, 0x03, 0x04 }; + // clang-format on /* addr */ + + /* google.net */ + // clang-format off + uint8_t buf3[] = { 0x11, 0x33, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x03, 0x6E, 0x65, 0x74, 0x00, + 0x00, 0x10, 0x00, 0x01, }; + // clang-format on + Flow f; + void *dns_state = NULL; + Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + + p1 = UTHBuildPacketReal( + buf1, sizeof(buf1), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + p2 = UTHBuildPacketReal( + buf1, sizeof(buf1), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + p3 = UTHBuildPacketReal( + buf1, sizeof(buf1), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_UDP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_DNS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW; + p3->flowflags |= FLOW_PKT_TOSERVER; + p3->pcap_cnt = 3; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google.com\"; nocase; sid:1;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google.net\"; nocase; sid:2;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + dns_state = f.alstate; + FAIL_IF_NULL(dns_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + if (!(PacketAlertCheck(p1, 1))) { + printf("(p1) sig 1 didn't alert, but it should have: "); + FAIL; + } + if (PacketAlertCheck(p1, 2)) { + printf("(p1) sig 2 did alert, but it should not have: "); + FAIL; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); + if (r != 0) { + printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("(p2) sig 1 alerted, but it should not have: "); + FAIL; + } + if (PacketAlertCheck(p2, 2)) { + printf("(p2) sig 2 alerted, but it should not have: "); + FAIL; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + if (PacketAlertCheck(p3, 1)) { + printf("(p3) sig 1 alerted, but it should not have: "); + FAIL; + } + if (!(PacketAlertCheck(p3, 2))) { + printf("(p3) sig 2 didn't alert, but it should have: "); + FAIL; + } + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + PASS; +} + +/** \test simple google.com query matching (TCP) */ +static int DetectDnsQueryTest03(void) +{ + /* google.com */ + // clang-format off + uint8_t buf[] = { 0x00, 28, + 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, + 0x00, 0x10, 0x00, 0x01, }; + // clang-format on + Flow f; + void *dns_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 53); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_DNS; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google\"; nocase; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + dns_state = f.alstate; + FAIL_IF_NULL(dns_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert, but it should have: "); + FAIL; + } + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +/** \test simple google.com query matching, pcre */ +static int DetectDnsQueryTest04(void) +{ + /* google.com */ + // clang-format off + uint8_t buf[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, + 0x00, 0x10, 0x00, 0x01, }; + // clang-format on + Flow f; + void *dns_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_UDP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW; + p->flowflags |= FLOW_PKT_TOSERVER; + f.alproto = ALPROTO_DNS; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google\"; nocase; " + "pcre:\"/google\\.com$/i\"; sid:1;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google\"; nocase; " + "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + dns_state = f.alstate; + FAIL_IF_NULL(dns_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert, but it should have: "); + FAIL; + } + if (!(PacketAlertCheck(p, 2))) { + printf("sig 2 didn't alert, but it should have: "); + FAIL; + } + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +/** \test multi tx google.(com|net) query matching + + * app layer event */ +static int DetectDnsQueryTest05(void) +{ + /* google.com */ + // clang-format off + uint8_t buf1[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, + 0x00, 0x01, 0x00, 0x01, }; + // clang-format on + + // clang-format off + uint8_t buf2[] = { 0x10, 0x32, /* tx id */ + 0x81, 0x80|0x40, /* flags: resp, recursion desired, recursion available */ + 0x00, 0x01, /* 1 query */ + 0x00, 0x01, /* 1 answer */ + 0x00, 0x00, 0x00, 0x00, /* no auth rr, additional rr */ + /* query record */ + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, /* name */ + 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* name cont */ + 0x00, 0x01, 0x00, 0x01, /* type a, class in */ + /* answer */ + 0xc0, 0x0c, /* ref to name in query above */ + 0x00, 0x01, 0x00, 0x01, /* type a, class in */ + 0x00, 0x01, 0x40, 0xef, /* ttl */ + 0x00, 0x04, /* data len */ + 0x01, 0x02, 0x03, 0x04 }; + // clang-format on /* addr */ + + /* google.net */ + // clang-format off + uint8_t buf3[] = { 0x11, 0x33, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, + 0x65, 0x03, 0x6E, 0x65, 0x74, 0x00, + 0x00, 0x10, 0x00, 0x01, }; + // clang-format on + Flow f; + void *dns_state = NULL; + Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + + p1 = UTHBuildPacketReal( + buf1, sizeof(buf1), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + p2 = UTHBuildPacketReal( + buf2, sizeof(buf2), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + p3 = UTHBuildPacketReal( + buf3, sizeof(buf3), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_UDP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_DNS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW; + p3->flowflags |= FLOW_PKT_TOSERVER; + p3->pcap_cnt = 3; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google.com\"; nocase; sid:1;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test dns_query option\"; " + "dns_query; content:\"google.net\"; nocase; sid:2;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " + "(msg:\"Test Z flag event\"; " + "app-layer-event:dns.z_flag_set; sid:3;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + dns_state = f.alstate; + FAIL_IF_NULL(dns_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + if (!(PacketAlertCheck(p1, 1))) { + printf("(p1) sig 1 didn't alert, but it should have: "); + FAIL; + } + if (PacketAlertCheck(p1, 2)) { + printf("(p1) sig 2 did alert, but it should not have: "); + FAIL; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); + if (r != 0) { + printf("toserver client 1 returned %" PRId32 ", expected 0\n", r); + FAIL; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("(p2) sig 1 alerted, but it should not have: "); + FAIL; + } + if (PacketAlertCheck(p2, 2)) { + printf("(p2) sig 2 alerted, but it should not have: "); + FAIL; + } + if (!(PacketAlertCheck(p2, 3))) { + printf("(p2) sig 3 didn't alert, but it should have: "); + FAIL; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + if (PacketAlertCheck(p3, 1)) { + printf("(p3) sig 1 alerted, but it should not have: "); + FAIL; + } + if (!(PacketAlertCheck(p3, 2))) { + printf("(p3) sig 2 didn't alert, but it should have: "); + FAIL; + } + /** \todo should not alert, bug #839 + if (PacketAlertCheck(p3, 3)) { + printf("(p3) sig 3 did alert, but it should not have: "); + goto end; + } + */ + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + PASS; +} + +static void DetectDnsQueryRegisterTests(void) +{ + UtRegisterTest("DetectDnsQueryTest01", DetectDnsQueryTest01); + UtRegisterTest("DetectDnsQueryTest02", DetectDnsQueryTest02); + UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03); + UtRegisterTest("DetectDnsQueryTest04 -- pcre", DetectDnsQueryTest04); + UtRegisterTest("DetectDnsQueryTest05 -- app layer event", DetectDnsQueryTest05); +} +#endif diff --git a/src/app-layer/dns/detect-query.h b/src/app-layer/dns/detect-query.h new file mode 100644 index 000000000000..a041ff1f27e9 --- /dev/null +++ b/src/app-layer/dns/detect-query.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_DNS_QUERY_H__ +#define __DETECT_DNS_QUERY_H__ + +void DetectDnsQueryRegister(void); + +#endif /* __DETECT_DNS_QUERY_H__ */ diff --git a/src/app-layer/dns/logger.c b/src/app-layer/dns/logger.c new file mode 100644 index 000000000000..d7a1b6498421 --- /dev/null +++ b/src/app-layer/dns/logger.c @@ -0,0 +1,604 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + * + * Implements JSON DNS logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" +#include "util/mem.h" +#include "app-layer-parser.h" +#include "output/output.h" +#include "app-layer.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" + +#include "output/eve/output-json.h" +#include "app-layer/dns/logger.h" +#include "rust.h" + +/* we can do query logging as well, but it's disabled for now as the + * TX id handling doesn't expect it */ +#define QUERY 0 + +#define LOG_QUERIES BIT_U64(0) +#define LOG_ANSWERS BIT_U64(1) + +#define LOG_A BIT_U64(2) +#define LOG_NS BIT_U64(3) +#define LOG_MD BIT_U64(4) +#define LOG_MF BIT_U64(5) +#define LOG_CNAME BIT_U64(6) +#define LOG_SOA BIT_U64(7) +#define LOG_MB BIT_U64(8) +#define LOG_MG BIT_U64(9) +#define LOG_MR BIT_U64(10) +#define LOG_NULL BIT_U64(11) +#define LOG_WKS BIT_U64(12) +#define LOG_PTR BIT_U64(13) +#define LOG_HINFO BIT_U64(14) +#define LOG_MINFO BIT_U64(15) +#define LOG_MX BIT_U64(16) +#define LOG_TXT BIT_U64(17) +#define LOG_RP BIT_U64(18) +#define LOG_AFSDB BIT_U64(19) +#define LOG_X25 BIT_U64(20) +#define LOG_ISDN BIT_U64(21) +#define LOG_RT BIT_U64(22) +#define LOG_NSAP BIT_U64(23) +#define LOG_NSAPPTR BIT_U64(24) +#define LOG_SIG BIT_U64(25) +#define LOG_KEY BIT_U64(26) +#define LOG_PX BIT_U64(27) +#define LOG_GPOS BIT_U64(28) +#define LOG_AAAA BIT_U64(29) +#define LOG_LOC BIT_U64(30) +#define LOG_NXT BIT_U64(31) +#define LOG_SRV BIT_U64(32) +#define LOG_ATMA BIT_U64(33) +#define LOG_NAPTR BIT_U64(34) +#define LOG_KX BIT_U64(35) +#define LOG_CERT BIT_U64(36) +#define LOG_A6 BIT_U64(37) +#define LOG_DNAME BIT_U64(38) +#define LOG_OPT BIT_U64(39) +#define LOG_APL BIT_U64(40) +#define LOG_DS BIT_U64(41) +#define LOG_SSHFP BIT_U64(42) +#define LOG_IPSECKEY BIT_U64(43) +#define LOG_RRSIG BIT_U64(44) +#define LOG_NSEC BIT_U64(45) +#define LOG_DNSKEY BIT_U64(46) +#define LOG_DHCID BIT_U64(47) +#define LOG_NSEC3 BIT_U64(48) +#define LOG_NSEC3PARAM BIT_U64(49) +#define LOG_TLSA BIT_U64(50) +#define LOG_HIP BIT_U64(51) +#define LOG_CDS BIT_U64(52) +#define LOG_CDNSKEY BIT_U64(53) +#define LOG_SPF BIT_U64(54) +#define LOG_TKEY BIT_U64(55) +#define LOG_TSIG BIT_U64(56) +#define LOG_MAILA BIT_U64(57) +#define LOG_ANY BIT_U64(58) +#define LOG_URI BIT_U64(59) + +#define LOG_FORMAT_GROUPED BIT_U64(60) +#define LOG_FORMAT_DETAILED BIT_U64(61) +#define LOG_HTTPS BIT_U64(62) + +#define LOG_FORMAT_ALL (LOG_FORMAT_GROUPED | LOG_FORMAT_DETAILED) +#define LOG_ALL_RRTYPES \ + (~(uint64_t)(LOG_QUERIES | LOG_ANSWERS | LOG_FORMAT_DETAILED | LOG_FORMAT_GROUPED)) + +typedef enum { + DNS_RRTYPE_A = 0, + DNS_RRTYPE_NS, + DNS_RRTYPE_MD, + DNS_RRTYPE_MF, + DNS_RRTYPE_CNAME, + DNS_RRTYPE_SOA, + DNS_RRTYPE_MB, + DNS_RRTYPE_MG, + DNS_RRTYPE_MR, + DNS_RRTYPE_NULL, + DNS_RRTYPE_WKS, + DNS_RRTYPE_PTR, + DNS_RRTYPE_HINFO, + DNS_RRTYPE_MINFO, + DNS_RRTYPE_MX, + DNS_RRTYPE_TXT, + DNS_RRTYPE_RP, + DNS_RRTYPE_AFSDB, + DNS_RRTYPE_X25, + DNS_RRTYPE_ISDN, + DNS_RRTYPE_RT, + DNS_RRTYPE_NSAP, + DNS_RRTYPE_NSAPPTR, + DNS_RRTYPE_SIG, + DNS_RRTYPE_KEY, + DNS_RRTYPE_PX, + DNS_RRTYPE_GPOS, + DNS_RRTYPE_AAAA, + DNS_RRTYPE_LOC, + DNS_RRTYPE_NXT, + DNS_RRTYPE_SRV, + DNS_RRTYPE_ATMA, + DNS_RRTYPE_NAPTR, + DNS_RRTYPE_KX, + DNS_RRTYPE_CERT, + DNS_RRTYPE_A6, + DNS_RRTYPE_DNAME, + DNS_RRTYPE_OPT, + DNS_RRTYPE_APL, + DNS_RRTYPE_DS, + DNS_RRTYPE_SSHFP, + DNS_RRTYPE_IPSECKEY, + DNS_RRTYPE_RRSIG, + DNS_RRTYPE_NSEC, + DNS_RRTYPE_DNSKEY, + DNS_RRTYPE_DHCID, + DNS_RRTYPE_NSEC3, + DNS_RRTYPE_NSEC3PARAM, + DNS_RRTYPE_TLSA, + DNS_RRTYPE_HIP, + DNS_RRTYPE_CDS, + DNS_RRTYPE_CDNSKEY, + DNS_RRTYPE_HTTPS, + DNS_RRTYPE_SPF, + DNS_RRTYPE_TKEY, + DNS_RRTYPE_TSIG, + DNS_RRTYPE_MAILA, + DNS_RRTYPE_ANY, + DNS_RRTYPE_URI, + DNS_RRTYPE_MAX, +} DnsRRTypes; + +static struct { + const char *config_rrtype; + uint64_t flags; +} dns_rrtype_fields[] = { + // clang-format off + { "a", LOG_A }, + { "ns", LOG_NS }, + { "md", LOG_MD }, + { "mf", LOG_MF }, + { "cname", LOG_CNAME }, + { "soa", LOG_SOA }, + { "mb", LOG_MB }, + { "mg", LOG_MG }, + { "mr", LOG_MR }, + { "null", LOG_NULL }, + { "wks", LOG_WKS }, + { "ptr", LOG_PTR }, + { "hinfo", LOG_HINFO }, + { "minfo", LOG_MINFO }, + { "mx", LOG_MX }, + { "txt", LOG_TXT }, + { "rp", LOG_RP }, + { "afsdb", LOG_AFSDB }, + { "x25", LOG_X25 }, + { "isdn", LOG_ISDN }, + { "rt", LOG_RT }, + { "nsap", LOG_NSAP }, + { "nsapptr", LOG_NSAPPTR }, + { "sig", LOG_SIG }, + { "key", LOG_KEY }, + { "px", LOG_PX }, + { "gpos", LOG_GPOS }, + { "aaaa", LOG_AAAA }, + { "loc", LOG_LOC }, + { "nxt", LOG_NXT }, + { "srv", LOG_SRV }, + { "atma", LOG_ATMA }, + { "naptr", LOG_NAPTR }, + { "kx", LOG_KX }, + { "cert", LOG_CERT }, + { "a6", LOG_A6 }, + { "dname", LOG_DNAME }, + { "opt", LOG_OPT }, + { "apl", LOG_APL }, + { "ds", LOG_DS }, + { "sshfp", LOG_SSHFP }, + { "ipseckey", LOG_IPSECKEY }, + { "rrsig", LOG_RRSIG }, + { "nsec", LOG_NSEC }, + { "dnskey", LOG_DNSKEY }, + { "dhcid", LOG_DHCID }, + { "nsec3", LOG_NSEC3 }, + { "nsec3param", LOG_NSEC3PARAM }, + { "tlsa", LOG_TLSA }, + { "hip", LOG_HIP }, + { "cds", LOG_CDS }, + { "cdnskey", LOG_CDNSKEY }, + { "https", LOG_HTTPS }, + { "spf", LOG_SPF }, + { "tkey", LOG_TKEY }, + { "tsig", LOG_TSIG }, + { "maila", LOG_MAILA }, + { "any", LOG_ANY }, + { "uri", LOG_URI } + // clang-format on +}; + +typedef struct LogDnsFileCtx_ { + uint64_t flags; /** Store mode */ + OutputJsonCtx *eve_ctx; +} LogDnsFileCtx; + +typedef struct LogDnsLogThread_ { + LogDnsFileCtx *dnslog_ctx; + OutputJsonThreadCtx *ctx; +} LogDnsLogThread; + +static JsonBuilder *JsonDNSLogQuery(void *txptr) +{ + JsonBuilder *queryjb = jb_new_array(); + if (queryjb == NULL) { + return NULL; + } + bool has_query = false; + + for (uint16_t i = 0; i < UINT16_MAX; i++) { + JsonBuilder *js = jb_new_object(); + if (!rs_dns_log_json_query((void *)txptr, i, LOG_ALL_RRTYPES, js)) { + jb_free(js); + break; + } + jb_close(js); + has_query = true; + jb_append_object(queryjb, js); + jb_free(js); + } + + if (!has_query) { + jb_free(queryjb); + return NULL; + } + + jb_close(queryjb); + return queryjb; +} + +static JsonBuilder *JsonDNSLogAnswer(void *txptr) +{ + if (!rs_dns_do_log_answer(txptr, LOG_ALL_RRTYPES)) { + return NULL; + } else { + JsonBuilder *js = jb_new_object(); + rs_dns_log_json_answer(txptr, LOG_ALL_RRTYPES, js); + jb_close(js); + return js; + } +} + +bool AlertJsonDns(void *txptr, JsonBuilder *js) +{ + jb_open_object(js, "dns"); + JsonBuilder *qjs = JsonDNSLogQuery(txptr); + if (qjs != NULL) { + jb_set_object(js, "query", qjs); + jb_free(qjs); + } + JsonBuilder *ajs = JsonDNSLogAnswer(txptr); + if (ajs != NULL) { + jb_set_object(js, "answer", ajs); + jb_free(ajs); + } + jb_close(js); + return true; +} + +static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *alstate, void *txptr, uint64_t tx_id) +{ + SCEnter(); + + LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; + + if (unlikely(dnslog_ctx->flags & LOG_QUERIES) == 0) { + return TM_ECODE_OK; + } + + for (uint16_t i = 0; i < 0xffff; i++) { + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "dns", NULL, dnslog_ctx->eve_ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_OK; + } + + jb_open_object(jb, "dns"); + if (!rs_dns_log_json_query(txptr, i, td->dnslog_ctx->flags, jb)) { + jb_free(jb); + break; + } + jb_close(jb); + + OutputJsonBuilderBuffer(jb, td->ctx); + jb_free(jb); + } + + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *alstate, void *txptr, uint64_t tx_id) +{ + SCEnter(); + + LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; + + if (unlikely(dnslog_ctx->flags & LOG_ANSWERS) == 0) { + return TM_ECODE_OK; + } + + if (rs_dns_do_log_answer(txptr, td->dnslog_ctx->flags)) { + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "dns", NULL, dnslog_ctx->eve_ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_OK; + } + + jb_open_object(jb, "dns"); + rs_dns_log_json_answer(txptr, td->dnslog_ctx->flags, jb); + jb_close(jb); + OutputJsonBuilderBuffer(jb, td->ctx); + jb_free(jb); + } + + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDnsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, + void *txptr, uint64_t tx_id) +{ + if (rs_dns_tx_is_request(txptr)) { + return JsonDnsLoggerToServer(tv, thread_data, p, f, alstate, txptr, tx_id); + } else if (rs_dns_tx_is_response(txptr)) { + return JsonDnsLoggerToClient(tv, thread_data, p, f, alstate, txptr, tx_id); + } + return TM_ECODE_OK; +} + +static TmEcode LogDnsLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogDnsLogThread *aft = SCCalloc(1, sizeof(LogDnsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogDNS. \"initdata\" argument NULL"); + goto error_exit; + } + + /* Use the Output Context (file pointer and mutex) */ + aft->dnslog_ctx = ((OutputCtx *)initdata)->data; + aft->ctx = CreateEveThreadCtx(t, aft->dnslog_ctx->eve_ctx); + if (!aft->ctx) { + goto error_exit; + } + + *data = (void *)aft; + return TM_ECODE_OK; + +error_exit: + SCFree(aft); + return TM_ECODE_FAILED; +} + +static TmEcode LogDnsLogThreadDeinit(ThreadVars *t, void *data) +{ + LogDnsLogThread *aft = (LogDnsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(aft->ctx); + + /* clear memory */ + memset(aft, 0, sizeof(LogDnsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void LogDnsLogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + LogDnsFileCtx *dnslog_ctx = (LogDnsFileCtx *)output_ctx->data; + SCFree(dnslog_ctx); + SCFree(output_ctx); +} + +static void JsonDnsLogParseConfig(LogDnsFileCtx *dnslog_ctx, ConfNode *conf, const char *query_key, + const char *answer_key, const char *answer_types_key) +{ + const char *query = ConfNodeLookupChildValue(conf, query_key); + if (query != NULL) { + if (ConfValIsTrue(query)) { + dnslog_ctx->flags |= LOG_QUERIES; + } else { + dnslog_ctx->flags &= ~LOG_QUERIES; + } + } else { + dnslog_ctx->flags |= LOG_QUERIES; + } + + const char *response = ConfNodeLookupChildValue(conf, answer_key); + if (response != NULL) { + if (ConfValIsTrue(response)) { + dnslog_ctx->flags |= LOG_ANSWERS; + } else { + dnslog_ctx->flags &= ~LOG_ANSWERS; + } + } else { + dnslog_ctx->flags |= LOG_ANSWERS; + } + + ConfNode *custom; + if ((custom = ConfNodeLookupChild(conf, answer_types_key)) != NULL) { + dnslog_ctx->flags &= ~LOG_ALL_RRTYPES; + ConfNode *field; + TAILQ_FOREACH (field, &custom->head, next) { + DnsRRTypes f; + for (f = DNS_RRTYPE_A; f < DNS_RRTYPE_MAX; f++) { + if (strcasecmp(dns_rrtype_fields[f].config_rrtype, field->val) == 0) { + dnslog_ctx->flags |= dns_rrtype_fields[f].flags; + break; + } + } + } + } else { + dnslog_ctx->flags |= LOG_ALL_RRTYPES; + } +} + +static void JsonDnsCheckVersion(ConfNode *conf) +{ + if (conf == NULL) { + return; + } + + static bool v1_deprecation_warned = false; + const ConfNode *has_version = ConfNodeLookupChild(conf, "version"); + if (has_version != NULL) { + bool invalid = false; + intmax_t config_version; + if (ConfGetChildValueInt(conf, "version", &config_version)) { + switch (config_version) { + case 2: + break; + case 1: + if (!v1_deprecation_warned) { + SCLogWarning("DNS EVE v1 logging has been removed, will use v2"); + v1_deprecation_warned = true; + } + break; + default: + invalid = true; + break; + } + } else { + invalid = true; + } + if (invalid) { + SCLogWarning("Invalid EVE DNS version \"%s\", will use v2", has_version->val); + } + } +} + +static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf) +{ + dnslog_ctx->flags = ~0ULL; + + if (conf) { + JsonDnsLogParseConfig(dnslog_ctx, conf, "requests", "responses", "types"); + if (dnslog_ctx->flags & LOG_ANSWERS) { + ConfNode *format; + if ((format = ConfNodeLookupChild(conf, "formats")) != NULL) { + uint64_t flags = 0; + ConfNode *field; + TAILQ_FOREACH (field, &format->head, next) { + if (strcasecmp(field->val, "detailed") == 0) { + flags |= LOG_FORMAT_DETAILED; + } else if (strcasecmp(field->val, "grouped") == 0) { + flags |= LOG_FORMAT_GROUPED; + } else { + SCLogWarning("Invalid JSON DNS log format: %s", field->val); + } + } + if (flags) { + dnslog_ctx->flags &= ~LOG_FORMAT_ALL; + dnslog_ctx->flags |= flags; + } else { + SCLogWarning("Empty EVE DNS format array, using defaults"); + } + } else { + dnslog_ctx->flags |= LOG_FORMAT_ALL; + } + } + } +} + +static OutputInitResult JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + const char *enabled = ConfNodeLookupChildValue(conf, "enabled"); + if (enabled != NULL && !ConfValIsTrue(enabled)) { + result.ok = true; + return result; + } + + /* As only a single version of logging is supported, this exists to warn about + * unsupported versions. */ + JsonDnsCheckVersion(conf); + + OutputJsonCtx *ojc = parent_ctx->data; + + LogDnsFileCtx *dnslog_ctx = SCCalloc(1, sizeof(LogDnsFileCtx)); + if (unlikely(dnslog_ctx == NULL)) { + return result; + } + + dnslog_ctx->eve_ctx = ojc; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(dnslog_ctx); + return result; + } + + output_ctx->data = dnslog_ctx; + output_ctx->DeInit = LogDnsLogDeInitCtxSub; + + JsonDnsLogInitFilters(dnslog_ctx, conf); + + SCLogDebug("DNS log sub-module initialized"); + + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +#define MODULE_NAME "JsonDnsLog" +void JsonDnsLogRegister(void) +{ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", MODULE_NAME, "eve-log.dns", + JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLogger, LogDnsLogThreadInit, + LogDnsLogThreadDeinit, NULL); +} diff --git a/src/output-json-dns.h b/src/app-layer/dns/logger.h similarity index 100% rename from src/output-json-dns.h rename to src/app-layer/dns/logger.h diff --git a/src/app-layer/dns/lua.c b/src/app-layer/dns/lua.c new file mode 100644 index 000000000000..24021606409c --- /dev/null +++ b/src/app-layer/dns/lua.c @@ -0,0 +1,161 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "rust.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/dns/lua.h" + +static int DnsGetDnsRrname(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + RSDNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "internal error: no tx"); + } + return rs_dns_lua_get_rrname(luastate, tx); +} + +static int DnsGetTxid(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + RSDNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "internal error: no tx"); + } + rs_dns_lua_get_tx_id(luastate, tx); + return 1; +} + +static int DnsGetRcode(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + RSDNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "internal error: no tx"); + } + return rs_dns_lua_get_rcode(luastate, tx); +} + +static int DnsGetRecursionDesired(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + RSDNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "internal error: no tx"); + } + uint16_t flags = rs_dns_tx_get_response_flags(tx); + int recursion_desired = flags & 0x0080 ? 1 : 0; + lua_pushboolean(luastate, recursion_desired); + return 1; +} + +static int DnsGetQueryTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + RSDNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "internal error: no tx"); + } + return rs_dns_lua_get_query_table(luastate, tx); +} + +static int DnsGetAnswerTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + RSDNSTransaction *tx = LuaStateGetTX(luastate); + return rs_dns_lua_get_answer_table(luastate, tx); +} + +static int DnsGetAuthorityTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + RSDNSTransaction *tx = LuaStateGetTX(luastate); + return rs_dns_lua_get_authority_table(luastate, tx); +} + +/** \brief register http lua extensions in a luastate */ +int LuaRegisterDnsFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, DnsGetDnsRrname); + lua_setglobal(luastate, "DnsGetDnsRrname"); + + lua_pushcfunction(luastate, DnsGetQueryTable); + lua_setglobal(luastate, "DnsGetQueries"); + + lua_pushcfunction(luastate, DnsGetAnswerTable); + lua_setglobal(luastate, "DnsGetAnswers"); + + lua_pushcfunction(luastate, DnsGetAuthorityTable); + lua_setglobal(luastate, "DnsGetAuthorities"); + + lua_pushcfunction(luastate, DnsGetTxid); + lua_setglobal(luastate, "DnsGetTxid"); + + lua_pushcfunction(luastate, DnsGetRcode); + lua_setglobal(luastate, "DnsGetRcode"); + + lua_pushcfunction(luastate, DnsGetRecursionDesired); + lua_setglobal(luastate, "DnsGetRecursionDesired"); + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dns.h b/src/app-layer/dns/lua.h similarity index 100% rename from src/util-lua-dns.h rename to src/app-layer/dns/lua.h diff --git a/src/app-layer/enip/parser-common.c b/src/app-layer/enip/parser-common.c new file mode 100644 index 000000000000..fe9d835ff472 --- /dev/null +++ b/src/app-layer/enip/parser-common.c @@ -0,0 +1,883 @@ +/* Copyright (C) 2015-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + * + * App-layer parser for ENIP protocol common code + * + */ + +#include "suricata-common.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "util/byte.h" +#include "pkt-var.h" +#include "util/profiling.h" + +#include "app-layer/enip/parser-common.h" + +/** + * \brief Extract 8 bits and move up the offset + * @param res + * @param input + * @param offset + */ +static int ENIPExtractUint8( + uint8_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (input_len < sizeof(uint8_t) || *offset > (input_len - sizeof(uint8_t))) { + SCLogDebug("ENIPExtractUint8: Parsing beyond payload length"); + return 0; + } + + *res = *(input + *offset); + *offset += sizeof(uint8_t); + return 1; +} + +/** + * \brief Extract 16 bits and move up the offset + * @param res + * @param input + * @param offset + */ +static int ENIPExtractUint16( + uint16_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (input_len < sizeof(uint16_t) || *offset > (input_len - sizeof(uint16_t))) { + SCLogDebug("ENIPExtractUint16: Parsing beyond payload length"); + return 0; + } + + if (ByteExtractUint16(res, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *)(input + *offset)) == -1) { + return 0; + } + + *offset += sizeof(uint16_t); + return 1; +} + +/** + * \brief Extract 32 bits and move up the offset + * @param res + * @param input + * @param offset + */ +static int ENIPExtractUint32( + uint32_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (input_len < sizeof(uint32_t) || *offset > (input_len - sizeof(uint32_t))) { + SCLogDebug("ENIPExtractUint32: Parsing beyond payload length"); + return 0; + } + + if (ByteExtractUint32(res, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), + (const uint8_t *)(input + *offset)) == -1) { + return 0; + } + + *offset += sizeof(uint32_t); + return 1; +} + +/** + * \brief Extract 64 bits and move up the offset + * @param res + * @param input + * @param offset + */ +static int ENIPExtractUint64( + uint64_t *res, const uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (input_len < sizeof(uint64_t) || *offset > (input_len - sizeof(uint64_t))) { + SCLogDebug("ENIPExtractUint64: Parsing beyond payload length"); + return 0; + } + + if (ByteExtractUint64(res, BYTE_LITTLE_ENDIAN, sizeof(uint64_t), + (const uint8_t *)(input + *offset)) == -1) { + return 0; + } + + *offset += sizeof(uint64_t); + return 1; +} + +/** + * \brief Create service entry, add to transaction + * @param tx Transaction + * @return service entry + */ +static CIPServiceEntry *CIPServiceAlloc(ENIPTransaction *tx) +{ + + CIPServiceEntry *svc = (CIPServiceEntry *)SCCalloc(1, sizeof(CIPServiceEntry)); + if (unlikely(svc == NULL)) + return NULL; + + TAILQ_INIT(&svc->segment_list); + TAILQ_INIT(&svc->attrib_list); + + TAILQ_INSERT_TAIL(&tx->service_list, svc, next); + tx->service_count++; + return svc; +} + +#if 0 +/** + * \brief Delete service entry + */ + +static void CIPServiceFree(void *s) +{ + SCEnter(); + if (s) + { + CIPServiceEntry *svc = (CIPServiceEntry *) s; + + SegmentEntry *seg = NULL; + while ((seg = TAILQ_FIRST(&svc->segment_list))) + { + TAILQ_REMOVE(&svc->segment_list, seg, next); + SCFree(seg); + } + + AttributeEntry *attr = NULL; + while ((attr = TAILQ_FIRST(&svc->attrib_list))) + { + TAILQ_REMOVE(&svc->attrib_list, attr, next); + SCFree(attr); + } + + SCFree(s); + } + SCReturn; +} +#endif + +/** + * \brief Decode ENIP Encapsulation Header + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeENIPPDU(const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data) +{ + int ret = 1; + + uint16_t offset = 0; // byte offset + + // Decode Encapsulation Header + uint16_t cmd; + uint16_t len; + uint32_t session; + uint32_t status; + uint64_t context; + uint32_t option; + if (ENIPExtractUint16(&cmd, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint16(&len, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint32(&session, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint32(&status, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint64(&context, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint32(&option, input, &offset, input_len) != 1) { + return 0; + } + + enip_data->header.command = cmd; + enip_data->header.length = len; + enip_data->header.session = session; + enip_data->header.status = status; + enip_data->header.context = context; + enip_data->header.option = option; + + switch (enip_data->header.command) { + case NOP: + SCLogDebug("DecodeENIP - NOP"); + break; + case LIST_SERVICES: + SCLogDebug("DecodeENIP - LIST_SERVICES"); + break; + case LIST_IDENTITY: + SCLogDebug("DecodeENIP - LIST_IDENTITY"); + break; + case LIST_INTERFACES: + SCLogDebug("DecodeENIP - LIST_INTERFACES"); + break; + case REGISTER_SESSION: + SCLogDebug("DecodeENIP - REGISTER_SESSION"); + break; + case UNREGISTER_SESSION: + SCLogDebug("DecodeENIP - UNREGISTER_SESSION"); + break; + case SEND_RR_DATA: + SCLogDebug("DecodeENIP - SEND_RR_DATA - parse Common Packet Format"); + ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, offset); + break; + case SEND_UNIT_DATA: + SCLogDebug("DecodeENIP - SEND UNIT DATA - parse Common Packet Format"); + ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, offset); + break; + case INDICATE_STATUS: + SCLogDebug("DecodeENIP - INDICATE_STATUS"); + break; + case CANCEL: + SCLogDebug("DecodeENIP - CANCEL"); + break; + default: + SCLogDebug("DecodeENIP - UNSUPPORTED COMMAND 0x%x", enip_data->header.command); + } + + return ret; +} + +/** + * \brief Decode Common Packet Format + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCommonPacketFormatPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset) +{ + + if (enip_data->header.length < sizeof(ENIPEncapDataHdr)) { + SCLogDebug("DecodeCommonPacketFormat: Malformed ENIP packet"); + return 0; + } + + uint32_t handle; + uint16_t timeout; + uint16_t count; + if (ENIPExtractUint32(&handle, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint16(&timeout, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint16(&count, input, &offset, input_len) != 1) { + return 0; + } + enip_data->encap_data_header.interface_handle = handle; + enip_data->encap_data_header.timeout = timeout; + enip_data->encap_data_header.item_count = count; + + uint16_t address_type; + uint16_t address_length; // length of connection id in bytes + uint32_t address_connectionid = 0; + uint32_t address_sequence = 0; + + if (ENIPExtractUint16(&address_type, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint16(&address_length, input, &offset, input_len) != 1) { + return 0; + } + + // depending on addr type, get connection id, sequence if needed. Can also use addr length too? + if (address_type == CONNECTION_BASED) { // get 4 byte connection id + if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) { + return 0; + } + } else if (address_type == SEQUENCE_ADDR_ITEM) { // get 4 byte connection id and 4 byte sequence + if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint32(&address_sequence, input, &offset, input_len) != 1) { + return 0; + } + } + + enip_data->encap_addr_item.type = address_type; + enip_data->encap_addr_item.length = address_length; + enip_data->encap_addr_item.conn_id = address_connectionid; + enip_data->encap_addr_item.sequence_num = address_sequence; + + uint16_t data_type; + uint16_t data_length; // length of data in bytes + uint16_t data_sequence_count; + + if (ENIPExtractUint16(&data_type, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint16(&data_length, input, &offset, input_len) != 1) { + return 0; + } + + enip_data->encap_data_item.type = data_type; + enip_data->encap_data_item.length = data_length; + + if (enip_data->encap_data_item.type == + CONNECTED_DATA_ITEM) { // connected data items have seq number + if (ENIPExtractUint16(&data_sequence_count, input, &offset, input_len) != 1) { + return 0; + } + enip_data->encap_data_item.sequence_count = data_sequence_count; + } + + switch (enip_data->encap_data_item.type) { + case CONNECTED_DATA_ITEM: + SCLogDebug("DecodeCommonPacketFormat - CONNECTED DATA ITEM - parse CIP"); + DecodeCIPPDU(input, input_len, enip_data, offset); + break; + case UNCONNECTED_DATA_ITEM: + SCLogDebug("DecodeCommonPacketFormat - UNCONNECTED DATA ITEM"); + DecodeCIPPDU(input, input_len, enip_data, offset); + break; + default: + SCLogDebug("DecodeCommonPacketFormat - UNKNOWN TYPE 0x%x", + enip_data->encap_data_item.type); + return 0; + } + + return 1; +} + +/** + * \brief Decode CIP packet + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ + +int DecodeCIPPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length == 0) { + SCLogDebug("DecodeCIP: No CIP Data"); + return 0; + } + + if (offset > (input_len - sizeof(uint8_t))) { + SCLogDebug("DecodeCIP: Parsing beyond payload length"); + return 0; + } + + uint8_t service = 0; + service = *(input + offset); + + // SCLogDebug("CIP Service 0x%x", service); + + // use service code first bit to determine request/response, no need to save or push offset + if (service >> 7) { + ret = DecodeCIPResponsePDU(input, input_len, enip_data, offset); + } else { + ret = DecodeCIPRequestPDU(input, input_len, enip_data, offset); + } + + return ret; +} + +/** + * \brief Decode CIP Request + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPRequestPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length < sizeof(CIPReqHdr)) { + SCLogDebug("DecodeCIPRequest - Malformed CIP Data"); + return 0; + } + + uint8_t service = 0; //<-----CIP SERVICE + uint8_t path_size = 0; + + if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint8(&path_size, input, &offset, input_len) != 1) { + return 0; + } + + if (service > MAX_CIP_SERVICE) { // service codes of value 0x80 or greater are not permitted + // because in the CIP protocol the highest order bit is used to + // flag request(0)/response(1) + SCLogDebug("DecodeCIPRequest - INVALID CIP SERVICE 0x%x", service); + return 0; + } + + // reached maximum number of services + if (enip_data->service_count > 32) { + SCLogDebug("DecodeCIPRequest: Maximum services reached"); + return 0; + } + + // save CIP data + CIPServiceEntry *node = CIPServiceAlloc(enip_data); + if (node == NULL) { + SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); + return 0; + } + node->direction = 0; + node->service = service; + node->request.path_size = path_size; + node->request.path_offset = offset; + // SCLogDebug("DecodeCIPRequestPDU: service 0x%x size %d", node->service, + // node->request.path_size); + + DecodeCIPRequestPathPDU(input, input_len, node, offset); + + offset += path_size * sizeof(uint16_t); // move offset past pathsize + + // list of CIP services is large and can be vendor specific, store CIP service anyways and let + // the rule decide the action + switch (service) { + case CIP_RESERVED: + SCLogDebug("DecodeCIPRequest - CIP_RESERVED"); + break; + case CIP_GET_ATTR_ALL: + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_ALL"); + break; + case CIP_GET_ATTR_LIST: + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_LIST"); + break; + case CIP_SET_ATTR_LIST: + SCLogDebug("DecodeCIPRequest - CIP_SET_ATTR_LIST"); + break; + case CIP_RESET: + SCLogDebug("DecodeCIPRequest - CIP_RESET"); + break; + case CIP_START: + SCLogDebug("DecodeCIPRequest - CIP_START"); + break; + case CIP_STOP: + SCLogDebug("DecodeCIPRequest - CIP_STOP"); + break; + case CIP_CREATE: + SCLogDebug("DecodeCIPRequest - CIP_CREATE"); + break; + case CIP_DELETE: + SCLogDebug("DecodeCIPRequest - CIP_DELETE"); + break; + case CIP_MSP: + SCLogDebug("DecodeCIPRequest - CIP_MSP"); + DecodeCIPRequestMSPPDU(input, input_len, enip_data, offset); + break; + case CIP_APPLY_ATTR: + SCLogDebug("DecodeCIPRequest - CIP_APPLY_ATTR"); + break; + case CIP_KICK_TIMER: + SCLogDebug("DecodeCIPRequest - CIP_KICK_TIMER"); + break; + case CIP_OPEN_CONNECTION: + SCLogDebug("DecodeCIPRequest - CIP_OPEN_CONNECTION"); + break; + case CIP_CHANGE_START: + SCLogDebug("DecodeCIPRequest - CIP_CHANGE_START"); + break; + case CIP_GET_STATUS: + SCLogDebug("DecodeCIPRequest - CIP_GET_STATUS"); + break; + default: + SCLogDebug("DecodeCIPRequest - CIP SERVICE 0x%x", service); + } + + return ret; +} + +/** + * \brief Decode CIP Request Path + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @param cipserviced the cip service rule + * @return 1 Packet matches + * @return 0 Packet not match + */ +int DecodeCIPRequestPathPDU( + const uint8_t *input, uint32_t input_len, CIPServiceEntry *node, uint16_t offset) +{ + // SCLogDebug("DecodeCIPRequestPath: service 0x%x size %d length %d", + // node->service, node->request.path_size, input_len); + + if (node->request.path_size < 1) { + // SCLogDebug("DecodeCIPRequestPath: empty path or CIP Response"); + return 0; + } + + int bytes_remain = node->request.path_size; + + uint8_t reserved; // unused byte reserved by ODVA + + // 8 bit fields + uint8_t req_path_instance8; + uint8_t req_path_attr8; + + // 16 bit fields + uint16_t req_path_class16; + uint16_t req_path_instance16; + + uint16_t class = 0; + + SegmentEntry *seg = NULL; + + while (bytes_remain > 0) { + uint8_t segment = 0; + if (ENIPExtractUint8(&segment, input, &offset, input_len) != 1) { + return 0; + } + switch (segment) { // assume order is class then instance. Can have multiple + case PATH_CLASS_8BIT: { + uint8_t req_path_class8 = 0; + if (ENIPExtractUint8(&req_path_class8, input, &offset, input_len) != 1) { + return 0; + } + class = (uint16_t)req_path_class8; + SCLogDebug("DecodeCIPRequestPathPDU: 8bit class 0x%x", class); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + + bytes_remain--; + break; + } + case PATH_INSTANCE_8BIT: + if (ENIPExtractUint8(&req_path_instance8, input, &offset, input_len) != 1) { + return 0; + } + // skip instance, don't need to store + bytes_remain--; + break; + case PATH_ATTR_8BIT: // single attribute + if (ENIPExtractUint8(&req_path_attr8, input, &offset, input_len) != 1) { + return 0; + } + // uint16_t attrib = (uint16_t) req_path_attr8; + // SCLogDebug("DecodeCIPRequestPath: 8bit attr 0x%x", attrib); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + + bytes_remain--; + break; + case PATH_CLASS_16BIT: + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) // skip reserved + { + return 0; + } + if (ENIPExtractUint16(&req_path_class16, input, &offset, input_len) != 1) { + return 0; + } + class = req_path_class16; + SCLogDebug("DecodeCIPRequestPath: 16bit class 0x%x", class); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + if (bytes_remain >= 2) { + bytes_remain = bytes_remain - 2; + } else { + bytes_remain = 0; + } + break; + case PATH_INSTANCE_16BIT: + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) // skip reserved + { + return 0; + } + if (ENIPExtractUint16(&req_path_instance16, input, &offset, input_len) != 1) { + return 0; + } + // skip instance, don't need to store + if (bytes_remain >= 2) { + bytes_remain = bytes_remain - 2; + } else { + bytes_remain = 0; + } + break; + default: + SCLogDebug("DecodeCIPRequestPath: UNKNOWN SEGMENT 0x%x service 0x%x", segment, + node->service); + return 0; + } + } + + if ((node->service == CIP_SET_ATTR_LIST) || (node->service == CIP_GET_ATTR_LIST)) { + uint16_t attr_list_count; + uint16_t attribute; + // parse get/set attribute list + + if (ENIPExtractUint16(&attr_list_count, input, &offset, input_len) != 1) { + return 0; + } + SCLogDebug("DecodeCIPRequestPathPDU: attribute list count %d", attr_list_count); + for (int i = 0; i < attr_list_count; i++) { + if (ENIPExtractUint16(&attribute, input, &offset, input_len) != 1) { + return 0; + } + SCLogDebug("DecodeCIPRequestPathPDU: attribute %d", attribute); + // save attrs + AttributeEntry *attr = SCMalloc(sizeof(AttributeEntry)); + if (unlikely(attr == NULL)) + return 0; + attr->attribute = attribute; + TAILQ_INSERT_TAIL(&node->attrib_list, attr, next); + } + } + + return 1; +} + +/** + * \brief Decode CIP Response + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPResponsePDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length < sizeof(CIPRespHdr)) { + SCLogDebug("DecodeCIPResponse - Malformed CIP Data"); + return 0; + } + + uint8_t service = 0; //<----CIP SERVICE + uint8_t reserved; // unused byte reserved by ODVA + uint16_t status; + + if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) { + return 0; + } + if (ENIPExtractUint16(&status, input, &offset, input_len) != 1) { + return 0; + } + + // SCLogDebug("DecodeCIPResponse: service 0x%x",service); + service &= 0x7f; // strip off top bit to get service code. Responses have first bit as 1 + + SCLogDebug("CIP service 0x%x status 0x%x", service, status); + + // reached maximum number of services + if (enip_data->service_count > 32) { + SCLogDebug("DecodeCIPRequest: Maximum services reached"); + return 0; + } + + // save CIP data + CIPServiceEntry *node = CIPServiceAlloc(enip_data); + if (node == NULL) { + SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); + return 0; + } + node->direction = 1; + node->service = service; + node->response.status = status; + + SCLogDebug( + "DecodeCIPResponsePDU: service 0x%x size %d", node->service, node->request.path_size); + + // list of CIP services is large and can be vendor specific, store CIP service anyways and let + // the rule decide the action + switch (service) { + case CIP_RESERVED: + SCLogDebug("DecodeCIPResponse - CIP_RESERVED"); + break; + case CIP_GET_ATTR_ALL: + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_ALL"); + break; + case CIP_GET_ATTR_LIST: + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_LIST"); + break; + case CIP_SET_ATTR_LIST: + SCLogDebug("DecodeCIPResponse - CIP_SET_ATTR_LIST"); + break; + case CIP_RESET: + SCLogDebug("DecodeCIPResponse - CIP_RESET"); + break; + case CIP_START: + SCLogDebug("DecodeCIPResponse - CIP_START"); + break; + case CIP_STOP: + SCLogDebug("DecodeCIPResponse - CIP_STOP"); + break; + case CIP_CREATE: + SCLogDebug("DecodeCIPResponse - CIP_CREATE"); + break; + case CIP_DELETE: + SCLogDebug("DecodeCIPResponse - CIP_DELETE"); + break; + case CIP_MSP: + SCLogDebug("DecodeCIPResponse - CIP_MSP"); + DecodeCIPResponseMSPPDU(input, input_len, enip_data, offset); + break; + case CIP_APPLY_ATTR: + SCLogDebug("DecodeCIPResponse - CIP_APPLY_ATTR"); + break; + case CIP_KICK_TIMER: + SCLogDebug("DecodeCIPResponse - CIP_KICK_TIMER"); + break; + case CIP_OPEN_CONNECTION: + SCLogDebug("DecodeCIPResponse - CIP_OPEN_CONNECTION"); + break; + case CIP_CHANGE_START: + SCLogDebug("DecodeCIPResponse - CIP_CHANGE_START"); + break; + case CIP_GET_STATUS: + SCLogDebug("DecodeCIPResponse - CIP_GET_STATUS"); + break; + default: + SCLogDebug("DecodeCIPResponse - CIP SERVICE 0x%x", service); + } + + return ret; +} + +/** + * \brief Decode CIP Request Multi Service Packet + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPRequestMSPPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + if (offset >= (input_len - sizeof(uint16_t))) { + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); + return 0; + } + // use temp_offset just to grab the service offset, don't want to use and push offset + uint16_t temp_offset = offset; + uint16_t num_services; + if (ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *)(input + temp_offset)) == -1) { + return 0; + } + + temp_offset += sizeof(uint16_t); + // SCLogDebug("DecodeCIPRequestMSP number of services %d",num_services); + + for (int svc = 1; svc < num_services + 1; svc++) { + if (temp_offset >= (input_len - sizeof(uint16_t))) { + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); + return 0; + } + + uint16_t svc_offset; // read set of service offsets + if (ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *)(input + temp_offset)) == -1) { + return 0; + } + temp_offset += sizeof(uint16_t); + // SCLogDebug("parseCIPRequestMSP service %d offset %d",svc, svc_offset); + + DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); // parse CIP at found offset + } + + return ret; +} + +/** + * \brief Decode CIP Response MultiService Packet. + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPResponseMSPPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (offset >= (input_len - sizeof(uint16_t))) { + SCLogDebug("DecodeCIPResponseMSPPDU: Parsing beyond payload length"); + return 0; + } + // use temp_offset just to grab the service offset, don't want to use and push offset + uint16_t temp_offset = offset; + uint16_t num_services; + if (ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *)(input + temp_offset)) == -1) { + return 0; + } + temp_offset += sizeof(uint16_t); + // SCLogDebug("DecodeCIPResponseMSP number of services %d", num_services); + + for (int svc = 0; svc < num_services; svc++) { + if (temp_offset >= (input_len - sizeof(uint16_t))) { + SCLogDebug("DecodeCIPResponseMSP: Parsing beyond payload length"); + return 0; + } + + uint16_t svc_offset; // read set of service offsets + if (ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *)(input + temp_offset)) == -1) { + return 0; + } + temp_offset += sizeof(uint16_t); + // SCLogDebug("parseCIPResponseMSP service %d offset %d", svc, svc_offset); + + DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); // parse CIP at found offset + } + + return ret; +} diff --git a/src/app-layer/enip/parser-common.h b/src/app-layer/enip/parser-common.h new file mode 100644 index 000000000000..318971e06dae --- /dev/null +++ b/src/app-layer/enip/parser-common.h @@ -0,0 +1,231 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + */ + +#ifndef __APP_LAYER_ENIP_COMMON_H__ +#define __APP_LAYER_ENIP_COMMON_H__ + +#include "rust.h" + +// EtherNet/IP commands +#define NOP 0x0000 +#define LIST_SERVICES 0x0004 +#define LIST_IDENTITY 0x0063 +#define LIST_INTERFACES 0x0064 +#define REGISTER_SESSION 0x0065 +#define UNREGISTER_SESSION 0x0066 +#define SEND_RR_DATA 0x006F +#define SEND_UNIT_DATA 0x0070 +#define INDICATE_STATUS 0x0072 +#define CANCEL 0x0073 + +// Common Packet Format Types +#define NULL_ADDR 0x0000 +#define CONNECTION_BASED 0x00a1 +#define CONNECTED_DATA_ITEM 0x00b1 +#define UNCONNECTED_DATA_ITEM 0x00b2 +#define SEQUENCE_ADDR_ITEM 0xB002 + +// status codes +#define SUCCESS 0x0000 +#define INVALID_CMD 0x0001 +#define NO_RESOURCES 0x0002 +#define INCORRECT_DATA 0x0003 +#define INVALID_SESSION 0x0064 +#define INVALID_LENGTH 0x0065 +#define UNSUPPORTED_PROT_REV 0x0069 +// Found in wireshark +#define ENCAP_HEADER_ERROR 0x006A + +#define MAX_CIP_SERVICE 127 +#define MAX_CIP_CLASS 65535 +#define MAX_CIP_ATTRIBUTE 65535 + +// CIP service codes +#define CIP_RESERVED 0x00 +#define CIP_GET_ATTR_ALL 0x01 +#define CIP_GET_ATTR_LIST 0x03 +#define CIP_SET_ATTR_LIST 0x04 +#define CIP_RESET 0x05 +#define CIP_START 0x06 +#define CIP_STOP 0x07 +#define CIP_CREATE 0x08 +#define CIP_DELETE 0x09 +#define CIP_MSP 0x0a +#define CIP_APPLY_ATTR 0x0d +#define CIP_GET_ATTR_SINGLE 0x0e +#define CIP_SET_ATTR_SINGLE 0x10 +#define CIP_KICK_TIMER 0x4b +#define CIP_OPEN_CONNECTION 0x4c +#define CIP_CHANGE_START 0x4f +#define CIP_GET_STATUS 0x50 + +// PATH sizing codes +#define PATH_CLASS_8BIT 0x20 +#define PATH_CLASS_16BIT 0x21 +#define PATH_INSTANCE_8BIT 0x24 +#define PATH_INSTANCE_16BIT 0x25 +#define PATH_ATTR_8BIT 0x30 +#define PATH_ATTR_16BIT 0x31 // possible value + +/** + * ENIP encapsulation header + */ +typedef struct ENIPEncapHdr_ { + uint64_t context; + uint32_t session; + uint32_t status; + uint32_t option; + uint16_t command; + uint16_t length; +} ENIPEncapHdr; + +/** + * ENIP encapsulation data header + */ +typedef struct ENIPEncapDataHdr_ { + uint32_t interface_handle; + uint16_t timeout; + uint16_t item_count; +} ENIPEncapDataHdr; + +/** + * ENIP encapsulation address item + */ +typedef struct ENIPEncapAddressItem_ { + uint16_t type; + uint16_t length; + uint32_t conn_id; + uint32_t sequence_num; +} ENIPEncapAddressItem; + +/** + * ENIP encapsulation data item + */ +typedef struct ENIPEncapDataItem_ { + uint16_t type; + uint16_t length; + uint16_t sequence_count; +} ENIPEncapDataItem; + +/** + * CIP Request Header + */ +typedef struct CIPReqHdr_ { + uint8_t service; + uint8_t path_size; +} CIPReqHdr; + +/** + * CIP Response Header + */ +typedef struct CIPRespHdr_ { + uint8_t service; + uint8_t pad; + uint8_t status; + uint8_t status_size; +} CIPRespHdr; + +typedef struct SegmentEntry_ { + uint16_t segment; /**< segment type */ + uint16_t value; /**< segment value (class or attribute) */ + + TAILQ_ENTRY(SegmentEntry_) next; +} SegmentEntry; + +typedef struct AttributeEntry_ { + uint16_t attribute; /**< segment class */ + + TAILQ_ENTRY(AttributeEntry_) next; +} AttributeEntry; + +typedef struct CIPServiceEntry_ { + uint8_t service; /**< cip service */ + uint8_t direction; + union { + struct { + uint8_t path_size; /**< cip path size */ + uint16_t path_offset; /**< offset to cip path */ + } request; + struct { + uint16_t status; + } response; + }; + + TAILQ_HEAD(, SegmentEntry_) segment_list; /**< list for CIP segment */ + TAILQ_HEAD(, AttributeEntry_) attrib_list; /**< list for CIP segment */ + + TAILQ_ENTRY(CIPServiceEntry_) next; +} CIPServiceEntry; + +typedef struct ENIPTransaction_ { + struct ENIPState_ *enip; + uint64_t tx_num; /**< internal: id */ + uint16_t tx_id; /**< transaction id */ + uint16_t service_count; + + ENIPEncapHdr header; /**< encapsulation header */ + ENIPEncapDataHdr encap_data_header; /**< encapsulation data header */ + ENIPEncapAddressItem encap_addr_item; /**< encapsulated address item */ + ENIPEncapDataItem encap_data_item; /**< encapsulated data item */ + + TAILQ_HEAD(, CIPServiceEntry_) service_list; /**< list for CIP */ + + TAILQ_ENTRY(ENIPTransaction_) next; + AppLayerTxData tx_data; +} ENIPTransaction; + +/** \brief Per flow ENIP state container */ +typedef struct ENIPState_ { + AppLayerStateData state_data; + TAILQ_HEAD(, ENIPTransaction_) tx_list; /**< transaction list */ + ENIPTransaction *curr; /**< ptr to current tx */ + ENIPTransaction *iter; + uint64_t transaction_max; + uint64_t tx_with_detect_state_cnt; + + uint16_t events; + uint16_t givenup; + + /* used by TCP only */ + uint16_t offset; + uint16_t record_len; + uint8_t *buffer; +} ENIPState; + +int DecodeENIPPDU(const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data); +int DecodeCommonPacketFormatPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPRequestPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPResponsePDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPRequestPathPDU( + const uint8_t *input, uint32_t input_len, CIPServiceEntry *node, uint16_t offset); +int DecodeCIPRequestMSPPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPResponseMSPPDU( + const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data, uint16_t offset); + +#endif /* __APP_LAYER_ENIP_COMMON_H__ */ diff --git a/src/app-layer/enip/parser.c b/src/app-layer/enip/parser.c new file mode 100644 index 000000000000..0572e2c7c015 --- /dev/null +++ b/src/app-layer/enip/parser.c @@ -0,0 +1,680 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + * + * App-layer parser for ENIP protocol + * + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "util/debug.h" +#include "util/byte.h" +#include "util/enum.h" +#include "util/mem.h" +#include "util/misc.h" + +#include "stream.h" + +#include "app-layer.h" +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer/enip/parser.h" +#include "app-layer/enip/parser-common.h" + +#include "app-layer-detect-proto.h" + +#include "conf.h" +#include "decode.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "pkt-var.h" +#include "util/profiling.h" + +SCEnumCharMap enip_decoder_event_table[] = { + { NULL, -1 }, +}; + +/** \brief get value for 'complete' status in ENIP + * + * For ENIP we use a simple bool. + */ +static int ENIPGetAlstateProgress(void *tx, uint8_t direction) +{ + return 1; +} + +static AppLayerTxData *ENIPGetTxData(void *vtx) +{ + ENIPTransaction *tx = (ENIPTransaction *)vtx; + return &tx->tx_data; +} + +static AppLayerStateData *ENIPGetStateData(void *vstate) +{ + ENIPState *state = (ENIPState *)vstate; + return &state->state_data; +} + +static void *ENIPGetTx(void *alstate, uint64_t tx_id) +{ + ENIPState *enip = (ENIPState *)alstate; + ENIPTransaction *tx = NULL; + + if (enip->curr && enip->curr->tx_num == tx_id + 1) + return enip->curr; + + TAILQ_FOREACH (tx, &enip->tx_list, next) { + if (tx->tx_num != (tx_id + 1)) + continue; + + SCLogDebug("returning tx %p", tx); + return tx; + } + + return NULL; +} + +static uint64_t ENIPGetTxCnt(void *alstate) +{ + return ((ENIPState *)alstate)->transaction_max; +} + +static int ENIPStateGetEventInfo( + const char *event_name, int *event_id, AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, enip_decoder_event_table); + + if (*event_id == -1) { + SCLogError("event \"%s\" not present in " + "enip's enum map table.", + event_name); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static int ENIPStateGetEventInfoById( + int event_id, const char **event_name, AppLayerEventType *event_type) +{ + *event_name = SCMapEnumValueToName(event_id, enip_decoder_event_table); + if (*event_name == NULL) { + SCLogError("event \"%d\" not present in " + "enip's enum map table.", + event_id); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +/** \brief Allocate enip state + * + * return state + */ +static void *ENIPStateAlloc(void *orig_state, AppProto proto_orig) +{ + SCLogDebug("ENIPStateAlloc"); + void *s = SCCalloc(1, sizeof(ENIPState)); + if (unlikely(s == NULL)) + return NULL; + + ENIPState *enip_state = (ENIPState *)s; + + TAILQ_INIT(&enip_state->tx_list); + return s; +} + +/** \internal + * \brief Free a ENIP TX + * \param tx ENIP TX to free */ +static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state) +{ + SCEnter(); + SCLogDebug("ENIPTransactionFree"); + CIPServiceEntry *svc = NULL; + while ((svc = TAILQ_FIRST(&tx->service_list))) { + TAILQ_REMOVE(&tx->service_list, svc, next); + + SegmentEntry *seg = NULL; + while ((seg = TAILQ_FIRST(&svc->segment_list))) { + TAILQ_REMOVE(&svc->segment_list, seg, next); + SCFree(seg); + } + + AttributeEntry *attr = NULL; + while ((attr = TAILQ_FIRST(&svc->attrib_list))) { + TAILQ_REMOVE(&svc->attrib_list, attr, next); + SCFree(attr); + } + + SCFree(svc); + } + + AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); + + if (tx->tx_data.de_state != NULL) { + DetectEngineStateFree(tx->tx_data.de_state); + + state->tx_with_detect_state_cnt--; + } + + if (state->iter == tx) + state->iter = NULL; + + SCFree(tx); + SCReturn; +} + +/** \brief Free enip state + * + */ +static void ENIPStateFree(void *s) +{ + SCEnter(); + SCLogDebug("ENIPStateFree"); + if (s) { + ENIPState *enip_state = (ENIPState *)s; + + ENIPTransaction *tx = NULL; + while ((tx = TAILQ_FIRST(&enip_state->tx_list))) { + TAILQ_REMOVE(&enip_state->tx_list, tx, next); + ENIPTransactionFree(tx, enip_state); + } + + if (enip_state->buffer != NULL) { + SCFree(enip_state->buffer); + } + + SCFree(s); + } + SCReturn; +} + +/** \internal + * \brief Allocate a ENIP TX + * \retval tx or NULL */ +static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state) +{ + SCLogDebug("ENIPStateTransactionAlloc"); + ENIPTransaction *tx = (ENIPTransaction *)SCCalloc(1, sizeof(ENIPTransaction)); + if (unlikely(tx == NULL)) + return NULL; + + state->curr = tx; + state->transaction_max++; + + TAILQ_INIT(&tx->service_list); + + tx->enip = state; + tx->tx_num = state->transaction_max; + tx->service_count = 0; + + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + + return tx; +} + +/** + * \brief enip transaction cleanup callback + */ +static void ENIPStateTransactionFree(void *state, uint64_t tx_id) +{ + SCEnter(); + SCLogDebug("ENIPStateTransactionFree"); + ENIPState *enip_state = state; + ENIPTransaction *tx = NULL; + TAILQ_FOREACH (tx, &enip_state->tx_list, next) { + + if ((tx_id + 1) < tx->tx_num) + break; + else if ((tx_id + 1) > tx->tx_num) + continue; + + if (tx == enip_state->curr) + enip_state->curr = NULL; + + if (tx->tx_data.events != NULL) { + if (tx->tx_data.events->cnt <= enip_state->events) + enip_state->events -= tx->tx_data.events->cnt; + else + enip_state->events = 0; + } + + TAILQ_REMOVE(&enip_state->tx_list, tx, next); + ENIPTransactionFree(tx, state); + break; + } + SCReturn; +} + +/** \internal + * + * \brief This function is called to retrieve a ENIP + * + * \param state ENIP state structure for the parser + * \param input Input line of the command + * \param input_len Length of the request + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static AppLayerResult ENIPParse(Flow *f, void *state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data, uint8_t direction) +{ + SCEnter(); + ENIPState *enip = (ENIPState *)state; + ENIPTransaction *tx; + + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + if (input == NULL && AppLayerParserStateIssetFlag( + pstate, APP_LAYER_PARSER_EOF_TS | APP_LAYER_PARSER_EOF_TC)) { + SCReturnStruct(APP_LAYER_OK); + } else if (input == NULL && input_len != 0) { + // GAP + SCReturnStruct(APP_LAYER_OK); + } else if (input == NULL || input_len == 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + + while (input_len > 0) { + tx = ENIPTransactionAlloc(enip); + if (tx == NULL) + SCReturnStruct(APP_LAYER_OK); + + if (direction == STREAM_TOCLIENT) + tx->tx_data.detect_flags_ts |= APP_LAYER_TX_SKIP_INSPECT_FLAG; + else + tx->tx_data.detect_flags_tc |= APP_LAYER_TX_SKIP_INSPECT_FLAG; + + SCLogDebug("ENIPParse input len %d", input_len); + DecodeENIPPDU(input, input_len, tx); + uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr); + SCLogDebug("ENIPParse packet len %d", pkt_len); + if (pkt_len > input_len) { + SCLogDebug("Invalid packet length"); + break; + } + + input += pkt_len; + input_len -= pkt_len; + // SCLogDebug("remaining %d", input_len); + + if (input_len < sizeof(ENIPEncapHdr)) { + // SCLogDebug("Not enough data"); //not enough data for ENIP + break; + } + } + + SCReturnStruct(APP_LAYER_OK); +} + +static AppLayerResult ENIPParseRequest(Flow *f, void *state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOSERVER); +} + +static AppLayerResult ENIPParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOCLIENT); +} + +#define ENIP_LEN_REGISTER_SESSION 4 // protocol u16, options u16 + +static uint16_t ENIPProbingParser( + Flow *f, uint8_t direction, const uint8_t *input, uint32_t input_len, uint8_t *rdir) +{ + // SCLogDebug("ENIPProbingParser %d", input_len); + if (input_len < sizeof(ENIPEncapHdr)) { + SCLogDebug("length too small to be a ENIP header"); + return ALPROTO_UNKNOWN; + } + uint16_t cmd; + uint16_t enip_len; + uint32_t status; + uint32_t option; + uint16_t nbitems; + + int ret = ByteExtractUint32( + &status, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 8)); + if (ret < 0) { + return ALPROTO_FAILED; + } + switch (status) { + case SUCCESS: + case INVALID_CMD: + case NO_RESOURCES: + case INCORRECT_DATA: + case INVALID_SESSION: + case INVALID_LENGTH: + case UNSUPPORTED_PROT_REV: + case ENCAP_HEADER_ERROR: + break; + default: + return ALPROTO_FAILED; + } + ret = ByteExtractUint16(&cmd, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input)); + if (ret < 0) { + return ALPROTO_FAILED; + } + ret = ByteExtractUint32( + &option, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 20)); + if (ret < 0) { + return ALPROTO_FAILED; + } + ret = ByteExtractUint16( + &enip_len, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input + 2)); + if (ret < 0) { + return ALPROTO_FAILED; + } + + // ok for all the known commands + switch (cmd) { + case NOP: + if (option != 0) { + return ALPROTO_FAILED; + } + break; + case REGISTER_SESSION: + if (enip_len != ENIP_LEN_REGISTER_SESSION) { + return ALPROTO_FAILED; + } + break; + case UNREGISTER_SESSION: + if (enip_len != ENIP_LEN_REGISTER_SESSION && enip_len != 0) { + // 0 for request and 4 for response + return ALPROTO_FAILED; + } + break; + case LIST_SERVICES: + case LIST_IDENTITY: + case SEND_RR_DATA: + case SEND_UNIT_DATA: + case INDICATE_STATUS: + case CANCEL: + break; + case LIST_INTERFACES: + if (input_len < sizeof(ENIPEncapHdr) + 2) { + SCLogDebug("length too small to be a ENIP LIST_INTERFACES"); + return ALPROTO_UNKNOWN; + } + ret = ByteExtractUint16( + &nbitems, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input)); + if (ret < 0) { + return ALPROTO_FAILED; + } + if (enip_len < sizeof(ENIPEncapHdr) + 2 * (size_t)nbitems) { + return ALPROTO_FAILED; + } + break; + default: + return ALPROTO_FAILED; + } + return ALPROTO_ENIP; +} + +static AppLayerGetTxIterTuple ENIPGetTxIterator(const uint8_t ipproto, const AppProto alproto, + void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) +{ + ENIPState *enip_state = (ENIPState *)alstate; + AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; + if (enip_state) { + ENIPTransaction *tx_ptr; + if (state->un.ptr == NULL) { + tx_ptr = TAILQ_FIRST(&enip_state->tx_list); + } else { + tx_ptr = (ENIPTransaction *)state->un.ptr; + } + if (tx_ptr) { + while (tx_ptr->tx_num < min_tx_id + 1) { + tx_ptr = TAILQ_NEXT(tx_ptr, next); + if (!tx_ptr) { + return no_tuple; + } + } + if (tx_ptr->tx_num >= max_tx_id + 1) { + return no_tuple; + } + state->un.ptr = TAILQ_NEXT(tx_ptr, next); + AppLayerGetTxIterTuple tuple = { + .tx_ptr = tx_ptr, + .tx_id = tx_ptr->tx_num - 1, + .has_next = (state->un.ptr != NULL), + }; + return tuple; + } + } + return no_tuple; +} + +/** + * \brief Function to register the ENIP protocol parsers and other functions + */ +void RegisterENIPUDPParsers(void) +{ + SCEnter(); + const char *proto_name = "enip"; + + if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("udp", proto_name, false)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, 0, + sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, 0, + sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); + + } else { + if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, proto_name, ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), ENIPProbingParser, ENIPProbingParser)) { + SCLogDebug("no ENIP UDP config found enabling ENIP detection on port 44818."); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, 0, + sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, 0, + sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); + } + } + + } else { + SCLogConfig("Protocol detection and parser disabled for %s protocol.", proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("udp", proto_name)) { + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest); + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse); + + AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateAlloc, ENIPStateFree); + + AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx); + AppLayerParserRegisterGetTxIterator(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxIterator); + AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxData); + AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetStateData); + AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree); + + AppLayerParserRegisterGetStateProgressFunc( + IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress); + AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1); + + AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo); + AppLayerParserRegisterGetEventInfoById( + IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfoById); + + AppLayerParserRegisterParserAcceptableDataDirection( + IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); + } else { + SCLogInfo("Parsed disabled for %s protocol. Protocol detection" + "still on.", + proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_ENIP, ENIPParserRegisterTests); +#endif + + SCReturn; +} + +/** + * \brief Function to register the ENIP protocol parsers and other functions + */ +void RegisterENIPTCPParsers(void) +{ + SCEnter(); + const char *proto_name = "enip"; + + if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, 0, + sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, 0, + sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); + + } else { + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), ENIPProbingParser, ENIPProbingParser)) { + return; + } + } + + } else { + SCLogDebug("Protocol detection and parser disabled for %s protocol.", proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse); + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateAlloc, ENIPStateFree); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx); + AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxIterator); + AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxData); + AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetStateData); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree); + + AppLayerParserRegisterGetStateProgressFunc( + IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress); + AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo); + + AppLayerParserRegisterParserAcceptableDataDirection( + IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); + + /* This parser accepts gaps. */ + AppLayerParserRegisterOptionFlags( + IPPROTO_TCP, ALPROTO_ENIP, APP_LAYER_PARSER_OPT_ACCEPT_GAPS); + + AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_ENIP, 0); + } else { + SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.", proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_ENIP, ENIPParserRegisterTests); +#endif + + SCReturn; +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "flow-util.h" +#include "stream-tcp.h" + +// clang-format off +static uint8_t listIdentity[] = {/* List ID */ 0x63, 0x00, + /* Length */ 0x00, 0x00, + /* Session */ 0x00, 0x00, 0x00, 0x00, + /* Status */ 0x00, 0x00, 0x00, 0x00, + /* Delay*/ 0x00, + /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00, 0x00}; +// clang-format on + +/** + * \brief Test if ENIP Packet matches signature + */ +static int ALDecodeENIPTest(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_ENIP; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER, listIdentity, sizeof(listIdentity)); + FAIL_IF(r != 0); + + ENIPState *enip_state = f.alstate; + FAIL_IF_NULL(enip_state); + + ENIPTransaction *tx = ENIPGetTx(enip_state, 0); + FAIL_IF_NULL(tx); + + FAIL_IF(tx->header.command != 99); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + + PASS; +} + +#endif /* UNITTESTS */ + +void ENIPParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer/enip/parser.h b/src/app-layer/enip/parser.h new file mode 100644 index 000000000000..5feac137b324 --- /dev/null +++ b/src/app-layer/enip/parser.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + */ + +#ifndef __APP_LAYER_ENIP_H__ +#define __APP_LAYER_ENIP_H__ + +void RegisterENIPUDPParsers(void); +void RegisterENIPTCPParsers(void); +void ENIPParserRegisterTests(void); + +#endif /* __APP_LAYER_ENIP_H__ */ diff --git a/src/app-layer/ftp/detect-bounce.c b/src/app-layer/ftp/detect-bounce.c new file mode 100644 index 000000000000..801e510e9bfd --- /dev/null +++ b/src/app-layer/ftp/detect-bounce.c @@ -0,0 +1,224 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + * + * ftpbounce keyword, part of the detection engine. + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-content.h" +#include "detect-engine-build.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ftp/parser.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" +#include "threads.h" +#include "app-layer/ftp/detect-bounce.h" +#include "stream-tcp.h" +#include "util/byte.h" + +static int DetectFtpbounceALMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +static int DetectFtpbounceSetup(DetectEngineCtx *, Signature *, const char *); +static int g_ftp_request_list_id = 0; + +/** + * \brief Registration function for ftpbounce: keyword + * \todo add support for no_stream and stream_only + */ +void DetectFtpbounceRegister(void) +{ + sigmatch_table[DETECT_FTPBOUNCE].name = "ftpbounce"; + sigmatch_table[DETECT_FTPBOUNCE].desc = "detect FTP bounce attacks"; + sigmatch_table[DETECT_FTPBOUNCE].Setup = DetectFtpbounceSetup; + sigmatch_table[DETECT_FTPBOUNCE].AppLayerTxMatch = DetectFtpbounceALMatch; + sigmatch_table[DETECT_FTPBOUNCE].url = "/rules/ftp-keywords.html#ftpbounce"; + sigmatch_table[DETECT_FTPBOUNCE].flags = SIGMATCH_NOOPT; + + g_ftp_request_list_id = DetectBufferTypeRegister("ftp_request"); + + DetectAppLayerInspectEngineRegister2( + "ftp_request", ALPROTO_FTP, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); +} + +/** + * \brief This function is used to match ftpbounce attacks + * + * \param payload Payload of the PORT command + * \param payload_len Length of the payload + * \param ip_orig IP source to check the ftpbounce condition + * \param offset offset to the arguments of the PORT command + * + * \retval 1 if ftpbounce detected, 0 if not + */ +static int DetectFtpbounceMatchArgs( + uint8_t *payload, uint32_t payload_len, uint32_t ip_orig, uint32_t offset) +{ + SCEnter(); + SCLogDebug("Checking ftpbounce condition"); + char *c = NULL; + uint32_t i = 0; + int octet = 0; + int octet_ascii_len = 0; + int noctet = 0; + uint32_t ip = 0; + /* PrintRawDataFp(stdout, payload, payload_len); */ + + if (payload_len < 7) { + /* we need at least a different ip address + * in the format 1,2,3,4,x,y where x,y is the port + * in two byte representation so let's look at + * least for the IP octets in comma separated */ + return 0; + } + + if (offset + 7 >= payload_len) + return 0; + + c = (char *)payload; + if (c == NULL) { + SCLogDebug("No payload to check"); + return 0; + } + + i = offset; + /* Search for the first IP octect(Skips "PORT ") */ + while (i < payload_len && !isdigit((unsigned char)c[i])) + i++; + + for (; i < payload_len && octet_ascii_len < 4; i++) { + if (isdigit((unsigned char)c[i])) { + octet = (c[i] - '0') + octet * 10; + octet_ascii_len++; + } else { + if (octet > 256) { + SCLogDebug("Octet not in ip format"); + return 0; + } + + if (isspace((unsigned char)c[i])) + while (i < payload_len && isspace((unsigned char)c[i])) + i++; + + if (i < payload_len && c[i] == ',') { /* we have an octet */ + noctet++; + octet_ascii_len = 0; + ip = (ip << 8) + octet; + octet = 0; + } else { + SCLogDebug("Unrecognized character '%c'", c[i]); + return 0; + } + if (noctet == 4) { + /* Different IP than src, ftp bounce scan */ + ip = SCNtohl(ip); + + if (ip != ip_orig) { + SCLogDebug("Different ip, so Matched ip:%d <-> ip_orig:%d", ip, ip_orig); + return 1; + } + SCLogDebug("Same ip, so no match here"); + return 0; + } + } + } + SCLogDebug("No match"); + return 0; +} + +/** + * \brief This function is used to check matches from the FTP App Layer Parser + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch but we don't use it since ftpbounce + * has no options + * \retval 0 no match + * \retval 1 match + */ +static int DetectFtpbounceALMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + + FtpState *ftp_state = (FtpState *)state; + if (ftp_state == NULL) { + SCLogDebug("no ftp state, no match"); + SCReturnInt(0); + } + + int ret = 0; + if (ftp_state->command == FTP_COMMAND_PORT) { + ret = DetectFtpbounceMatchArgs(ftp_state->port_line, ftp_state->port_line_len, + f->src.address.address_un_data32[0], ftp_state->arg_offset); + } + + SCReturnInt(ret); +} + +/** + * \brief this function is used to add the parsed ftpbounce + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param m pointer to the Current SigMatch + * \param ftpbouncestr pointer to the user provided ftpbounce options + * currently there are no options. + * + * \retval 0 on Success + * \retval -1 on Failure + */ +int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *ftpbouncestr) +{ + SCEnter(); + + if (DetectSignatureSetAppProto(s, ALPROTO_FTP) != 0) + return -1; + + /* We don't need to allocate any data for ftpbounce here. + * + * TODO: As a suggestion, maybe we can add a flag in the flow + * to set the stream as "bounce detected" for fast Match. + * When you do a ftp bounce attack you usually use the same + * communication control stream to "setup" various destinations + * without breaking the connection, so I guess we can make it a bit faster + * with a flow flag set lookup in the Match function. + */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_FTPBOUNCE, NULL, g_ftp_request_list_id) == NULL) { + return -1; + } + SCReturnInt(0); +} diff --git a/src/app-layer/ftp/detect-bounce.h b/src/app-layer/ftp/detect-bounce.h new file mode 100644 index 000000000000..c3aab0840ea4 --- /dev/null +++ b/src/app-layer/ftp/detect-bounce.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + */ + +#ifndef __DETECT_FTPBOUNCE_H__ +#define __DETECT_FTPBOUNCE_H__ + +/* prototypes */ +void DetectFtpbounceRegister(void); + +#endif /* __DETECT_FTPBOUNCE_H__ */ diff --git a/src/app-layer/ftp/detect-data.c b/src/app-layer/ftp/detect-data.c new file mode 100644 index 000000000000..e467bdfaef9c --- /dev/null +++ b/src/app-layer/ftp/detect-data.c @@ -0,0 +1,252 @@ +/* Copyright (C) 2017-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + * Match on ftp command used to trigger a ftp data transfer + */ + +#include "suricata-common.h" +#include "util/unittest.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-state.h" + +#include "app-layer/ftp/parser.h" + +#include "app-layer/ftp/detect-data.h" + +/** + * \brief Regex for parsing our keyword options + */ +#define PARSE_REGEX "^\\s*(stor|retr)\\s*$" +static DetectParseRegex parse_regex; + +/* Prototypes of functions registered in DetectFtpdataRegister below */ +static int DetectFtpdataMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectFtpdataSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectFtpdataFree(DetectEngineCtx *, void *); +#ifdef UNITTESTS +static void DetectFtpdataRegisterTests(void); +#endif +static int g_ftpdata_buffer_id = 0; + +/** + * \brief Registration function for ftpcommand: keyword + * + * This function is called once in the 'lifetime' of the engine. + */ +void DetectFtpdataRegister(void) +{ + /* keyword name: this is how the keyword is used in a rule */ + sigmatch_table[DETECT_FTPDATA].name = "ftpdata_command"; + /* description: listed in "suricata --list-keywords=all" */ + sigmatch_table[DETECT_FTPDATA].desc = "match FTP command triggering a FTP data channel"; + sigmatch_table[DETECT_FTPDATA].url = "/rules/ftp-keywords.html#ftpdata-command"; + sigmatch_table[DETECT_FTPDATA].AppLayerTxMatch = DetectFtpdataMatch; + /* setup function is called during signature parsing, when the ftpcommand + * keyword is encountered in the rule */ + sigmatch_table[DETECT_FTPDATA].Setup = DetectFtpdataSetup; + /* free function is called when the detect engine is freed. Normally at + * shutdown, but also during rule reloads. */ + sigmatch_table[DETECT_FTPDATA].Free = DetectFtpdataFree; + /* registers unittests into the system */ +#ifdef UNITTESTS + sigmatch_table[DETECT_FTPDATA].RegisterTests = DetectFtpdataRegisterTests; +#endif + DetectAppLayerInspectEngineRegister2("ftpdata_command", ALPROTO_FTPDATA, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("ftpdata_command", ALPROTO_FTPDATA, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + g_ftpdata_buffer_id = DetectBufferTypeGetByName("ftpdata_command"); + + /* set up the PCRE for keyword parsing */ + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); +} + +/** + * \brief This function is used to check matches from the FTP App Layer Parser + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch + * \retval 0 no match + * \retval 1 match + */ +static int DetectFtpdataMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *m) +{ + const DetectFtpdataData *ftpcommandd = (const DetectFtpdataData *)m; + const FtpDataState *ftp_state = (const FtpDataState *)state; + + if (ftp_state == NULL) + return 0; + + if (ftpcommandd->command == ftp_state->command) { + /* Only match if the flow is in the good direction */ + if ((flags & STREAM_TOSERVER) && (ftpcommandd->command == FTP_COMMAND_RETR)) { + return 0; + } else if ((flags & STREAM_TOCLIENT) && (ftpcommandd->command == FTP_COMMAND_STOR)) { + return 0; + } + return 1; + } + + return 0; +} + +/** + * \brief This function is used to parse ftpcommand options passed via ftpcommand: keyword + * + * \param ftpcommandstr Pointer to the user provided ftpcommand options + * + * \retval ftpcommandd pointer to DetectFtpdataData on success + * \retval NULL on failure + */ +static DetectFtpdataData *DetectFtpdataParse(const char *ftpcommandstr) +{ + DetectFtpdataData *ftpcommandd = NULL; + char arg1[5] = ""; + size_t pcre2len; + pcre2_match_data *match = NULL; + + int ret = DetectParsePcreExec(&parse_regex, &match, ftpcommandstr, 0, 0); + if (ret != 2) { + SCLogError("parse error, ret %" PRId32 "", ret); + goto error; + } + + pcre2len = sizeof(arg1); + int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + SCLogDebug("Arg1 \"%s\"", arg1); + + ftpcommandd = SCMalloc(sizeof(DetectFtpdataData)); + if (unlikely(ftpcommandd == NULL)) + goto error; + if (!strcmp(arg1, "stor")) { + ftpcommandd->command = FTP_COMMAND_STOR; + } else if (!strcmp(arg1, "retr")) { + ftpcommandd->command = FTP_COMMAND_RETR; + } else { + SCLogError("Invalid command value"); + goto error; + } + + pcre2_match_data_free(match); + return ftpcommandd; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (ftpcommandd) + SCFree(ftpcommandd); + return NULL; +} + +/** + * \brief parse the options from the 'ftpcommand' keyword in the rule into + * the Signature data structure. + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided ftpcommand options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectFtpdataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_FTPDATA) != 0) + return -1; + + DetectFtpdataData *ftpcommandd = DetectFtpdataParse(str); + if (ftpcommandd == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_FTPDATA, (SigMatchCtx *)ftpcommandd, + g_ftpdata_buffer_id) == NULL) { + DetectFtpdataFree(de_ctx, ftpcommandd); + return -1; + } + return 0; +} + +/** + * \brief this function will free memory associated with DetectFtpdataData + * + * \param ptr pointer to DetectFtpdataData + */ +static void DetectFtpdataFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectFtpdataData *ftpcommandd = (DetectFtpdataData *)ptr; + + /* do more specific cleanup here, if needed */ + + SCFree(ftpcommandd); +} + +#ifdef UNITTESTS + +static int DetectFtpdataParseTest01(void) +{ + DetectFtpdataData *ftpcommandd = DetectFtpdataParse("stor"); + FAIL_IF_NULL(ftpcommandd); + FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_STOR)); + DetectFtpdataFree(NULL, ftpcommandd); + PASS; +} + +static int DetectFtpdataSignatureTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (ftpdata_command:stor; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (ftpdata_command:retr; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (ftpdata_command:xxx; sid:3; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \brief this function registers unit tests for DetectFtpdata + */ +static void DetectFtpdataRegisterTests(void) +{ + UtRegisterTest("DetectFtpdataParseTest01", DetectFtpdataParseTest01); + UtRegisterTest("DetectFtpdataSignatureTest01", DetectFtpdataSignatureTest01); +} +#endif /* UNITTESTS */ diff --git a/src/app-layer/ftp/detect-data.h b/src/app-layer/ftp/detect-data.h new file mode 100644 index 000000000000..df434713395a --- /dev/null +++ b/src/app-layer/ftp/detect-data.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#ifndef __DETECT_FTPDATA_H__ +#define __DETECT_FTPDATA_H__ + +#include "app-layer/ftp/parser.h" + +/** Per keyword data. This is set up by the DetectFtpcommandSetup() function. + * Each signature will have an instance of DetectFtpcommandData per occurrence + * of the keyword. + * The structure should be considered static/readonly after initialization. + */ +typedef struct DetectFtpdataData_ { + FtpRequestCommand command; +} DetectFtpdataData; + +/** \brief registers the keyword into the engine. Called from + * detect.c::SigTableSetup() */ +void DetectFtpdataRegister(void); + +#endif /* __DETECT_FTPDATA_H__ */ diff --git a/src/app-layer/ftp/logger.c b/src/app-layer/ftp/logger.c new file mode 100644 index 000000000000..bea3805f75d0 --- /dev/null +++ b/src/app-layer/ftp/logger.c @@ -0,0 +1,210 @@ +/* Copyright (C) 2017-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jeff Lucovsky + * + * Implement JSON/eve logging app-layer FTP. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/mem.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ftp/parser.h" +#include "app-layer/ftp/logger.h" + +bool EveFTPLogCommand(void *vtx, JsonBuilder *jb) +{ + FTPTransaction *tx = vtx; + /* Preallocate array objects to simplify failure case */ + JsonBuilder *js_resplist = NULL; + if (!TAILQ_EMPTY(&tx->response_list)) { + js_resplist = jb_new_array(); + + if (unlikely(js_resplist == NULL)) { + return false; + } + } + jb_open_object(jb, "ftp"); + jb_set_string(jb, "command", tx->command_descriptor->command_name); + uint32_t min_length = tx->command_descriptor->command_length + 1; /* command + space */ + if (tx->request_length > min_length) { + jb_set_string_from_bytes(jb, "command_data", (const uint8_t *)tx->request + min_length, + tx->request_length - min_length - 1); + if (tx->request_truncated) { + JB_SET_TRUE(jb, "command_truncated"); + } else { + JB_SET_FALSE(jb, "command_truncated"); + } + } + + bool reply_truncated = false; + + if (!TAILQ_EMPTY(&tx->response_list)) { + int resp_cnt = 0; + FTPString *response; + bool is_cc_array_open = false; + TAILQ_FOREACH (response, &tx->response_list, next) { + /* handle multiple lines within the response, \r\n delimited */ + uint8_t *where = response->str; + uint16_t length = 0; + uint16_t pos; + if (response->len > 0 && response->len <= UINT16_MAX) { + length = (uint16_t)response->len - 1; + } else if (response->len > UINT16_MAX) { + length = UINT16_MAX; + } + if (!reply_truncated && response->truncated) { + reply_truncated = true; + } + while ((pos = JsonGetNextLineFromBuffer((const char *)where, length)) != UINT16_MAX) { + uint16_t offset = 0; + /* Try to find a completion code for this line */ + if (pos >= 3) { + /* Gather the completion code if present */ + if (isdigit(where[0]) && isdigit(where[1]) && isdigit(where[2])) { + if (!is_cc_array_open) { + jb_open_array(jb, "completion_code"); + is_cc_array_open = true; + } + jb_append_string_from_bytes(jb, (const uint8_t *)where, 3); + offset = 4; + } + } + /* move past 3 character completion code */ + if (pos >= offset) { + jb_append_string_from_bytes( + js_resplist, (const uint8_t *)where + offset, pos - offset); + resp_cnt++; + } + + where += pos; + length -= pos; + } + } + + if (is_cc_array_open) { + jb_close(jb); + } + if (resp_cnt) { + jb_close(js_resplist); + jb_set_object(jb, "reply", js_resplist); + } + jb_free(js_resplist); + } + + if (tx->dyn_port) { + jb_set_uint(jb, "dynamic_port", tx->dyn_port); + } + + if (tx->command_descriptor->command == FTP_COMMAND_PORT || + tx->command_descriptor->command == FTP_COMMAND_EPRT) { + if (tx->active) { + JB_SET_STRING(jb, "mode", "active"); + } else { + JB_SET_STRING(jb, "mode", "passive"); + } + } + + if (tx->done) { + JB_SET_STRING(jb, "reply_received", "yes"); + } else { + JB_SET_STRING(jb, "reply_received", "no"); + } + + if (reply_truncated) { + JB_SET_TRUE(jb, "reply_truncated"); + } else { + JB_SET_FALSE(jb, "reply_truncated"); + } + jb_close(jb); + return true; +} + +static int JsonFTPLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *vtx, uint64_t tx_id) +{ + SCEnter(); + OutputJsonThreadCtx *thread = thread_data; + + const char *event_type; + if (f->alproto == ALPROTO_FTPDATA) { + event_type = "ftp_data"; + } else { + event_type = "ftp"; + } + + JsonBuilder *jb = + CreateEveHeaderWithTxId(p, LOG_DIR_FLOW, event_type, NULL, tx_id, thread->ctx); + if (likely(jb)) { + if (f->alproto == ALPROTO_FTPDATA) { + if (!EveFTPDataAddMetadata(vtx, jb)) { + goto fail; + } + } else { + EveFTPLogCommand(vtx, jb); + } + + OutputJsonBuilderBuffer(jb, thread); + + jb_free(jb); + } + return TM_ECODE_OK; + +fail: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static OutputInitResult OutputFTPLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_FTP); + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_FTPDATA); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonFTPLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonFTPLog", "eve-log.ftp", + OutputFTPLogInitSub, ALPROTO_FTP, JsonFTPLogger, JsonLogThreadInit, JsonLogThreadDeinit, + NULL); + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonFTPLog", "eve-log.ftp", + OutputFTPLogInitSub, ALPROTO_FTPDATA, JsonFTPLogger, JsonLogThreadInit, + JsonLogThreadDeinit, NULL); + + SCLogDebug("FTP JSON logger registered."); +} diff --git a/src/output-json-ftp.h b/src/app-layer/ftp/logger.h similarity index 100% rename from src/output-json-ftp.h rename to src/app-layer/ftp/logger.h diff --git a/src/app-layer/ftp/parser.c b/src/app-layer/ftp/parser.c new file mode 100644 index 000000000000..2e47c2ed5153 --- /dev/null +++ b/src/app-layer/ftp/parser.c @@ -0,0 +1,1560 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * \author Eric Leblond + * \author Jeff Lucovsky + * + * App Layer Parser for FTP + */ + +#include "suricata-common.h" +#include "app-layer/ftp/parser.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-expectation.h" +#include "app-layer-detect-proto.h" + +#include "rust.h" + +#include "util/misc.h" +#include "util/mpm/mpm.h" +#include "util/validate.h" + +typedef struct FTPThreadCtx_ { + MpmThreadCtx *ftp_mpm_thread_ctx; + PrefilterRuleStore *pmq; +} FTPThreadCtx; + +#define FTP_MPM mpm_default_matcher + +static MpmCtx *ftp_mpm_ctx = NULL; + +// clang-format off +const FtpCommand FtpCommands[FTP_COMMAND_MAX + 1] = { + /* Parsed and handled */ + { "PORT", FTP_COMMAND_PORT, 4 }, + { "EPRT", FTP_COMMAND_EPRT, 4 }, + { "AUTH TLS", FTP_COMMAND_AUTH_TLS, 8 }, + { "PASV", FTP_COMMAND_PASV, 4 }, + { "RETR", FTP_COMMAND_RETR, 4 }, + { "EPSV", FTP_COMMAND_EPSV, 4 }, + { "STOR", FTP_COMMAND_STOR, 4 }, + + /* Parsed, but not handled */ + { "ABOR", FTP_COMMAND_ABOR, 4 }, + { "ACCT", FTP_COMMAND_ACCT, 4 }, + { "ALLO", FTP_COMMAND_ALLO, 4 }, + { "APPE", FTP_COMMAND_APPE, 4 }, + { "CDUP", FTP_COMMAND_CDUP, 4 }, + { "CHMOD", FTP_COMMAND_CHMOD, 5 }, + { "CWD", FTP_COMMAND_CWD, 3 }, + { "DELE", FTP_COMMAND_DELE, 4 }, + { "HELP", FTP_COMMAND_HELP, 4 }, + { "IDLE", FTP_COMMAND_IDLE, 4 }, + { "LIST", FTP_COMMAND_LIST, 4 }, + { "MAIL", FTP_COMMAND_MAIL, 4 }, + { "MDTM", FTP_COMMAND_MDTM, 4 }, + { "MKD", FTP_COMMAND_MKD, 3 }, + { "MLFL", FTP_COMMAND_MLFL, 4 }, + { "MODE", FTP_COMMAND_MODE, 4 }, + { "MRCP", FTP_COMMAND_MRCP, 4 }, + { "MRSQ", FTP_COMMAND_MRSQ, 4 }, + { "MSAM", FTP_COMMAND_MSAM, 4 }, + { "MSND", FTP_COMMAND_MSND, 4 }, + { "MSOM", FTP_COMMAND_MSOM, 4 }, + { "NLST", FTP_COMMAND_NLST, 4 }, + { "NOOP", FTP_COMMAND_NOOP, 4 }, + { "PASS", FTP_COMMAND_PASS, 4 }, + { "PWD", FTP_COMMAND_PWD, 3 }, + { "QUIT", FTP_COMMAND_QUIT, 4 }, + { "REIN", FTP_COMMAND_REIN, 4 }, + { "REST", FTP_COMMAND_REST, 4 }, + { "RMD", FTP_COMMAND_RMD, 3 }, + { "RNFR", FTP_COMMAND_RNFR, 4 }, + { "RNTO", FTP_COMMAND_RNTO, 4 }, + { "SITE", FTP_COMMAND_SITE, 4 }, + { "SIZE", FTP_COMMAND_SIZE, 4 }, + { "SMNT", FTP_COMMAND_SMNT, 4 }, + { "STAT", FTP_COMMAND_STAT, 4 }, + { "STOU", FTP_COMMAND_STOU, 4 }, + { "STRU", FTP_COMMAND_STRU, 4 }, + { "SYST", FTP_COMMAND_SYST, 4 }, + { "TYPE", FTP_COMMAND_TYPE, 4 }, + { "UMASK", FTP_COMMAND_UMASK, 5 }, + { "USER", FTP_COMMAND_USER, 4 }, + { NULL, FTP_COMMAND_UNKNOWN, 0 } +}; +// clang-format on + +uint64_t ftp_config_memcap = 0; +uint32_t ftp_config_maxtx = 1024; +uint32_t ftp_max_line_len = 4096; + +SC_ATOMIC_DECLARE(uint64_t, ftp_memuse); +SC_ATOMIC_DECLARE(uint64_t, ftp_memcap); + +static FTPTransaction *FTPGetOldestTx(const FtpState *, FTPTransaction *); + +static void FTPParseMemcap(void) +{ + const char *conf_val; + + /** set config values for memcap, prealloc and hash_size */ + if ((ConfGet("app-layer.protocols.ftp.memcap", &conf_val)) == 1) { + if (ParseSizeStringU64(conf_val, &ftp_config_memcap) < 0) { + SCLogError("Error parsing ftp.memcap " + "from conf file - %s. Killing engine", + conf_val); + exit(EXIT_FAILURE); + } + SCLogInfo("FTP memcap: %" PRIu64, ftp_config_memcap); + } else { + /* default to unlimited */ + ftp_config_memcap = 0; + } + + SC_ATOMIC_INIT(ftp_memuse); + SC_ATOMIC_INIT(ftp_memcap); + + if ((ConfGet("app-layer.protocols.ftp.max-tx", &conf_val)) == 1) { + if (ParseSizeStringU32(conf_val, &ftp_config_maxtx) < 0) { + SCLogError("Error parsing ftp.max-tx " + "from conf file - %s.", + conf_val); + } + SCLogInfo("FTP max tx: %" PRIu32, ftp_config_maxtx); + } + + if ((ConfGet("app-layer.protocols.ftp.max-line-length", &conf_val)) == 1) { + if (ParseSizeStringU32(conf_val, &ftp_max_line_len) < 0) { + SCLogError("Error parsing ftp.max-line-length from conf file - %s.", conf_val); + } + SCLogConfig("FTP max line length: %" PRIu32, ftp_max_line_len); + } +} + +static void FTPIncrMemuse(uint64_t size) +{ + (void)SC_ATOMIC_ADD(ftp_memuse, size); + return; +} + +static void FTPDecrMemuse(uint64_t size) +{ + (void)SC_ATOMIC_SUB(ftp_memuse, size); + return; +} + +uint64_t FTPMemuseGlobalCounter(void) +{ + uint64_t tmpval = SC_ATOMIC_GET(ftp_memuse); + return tmpval; +} + +uint64_t FTPMemcapGlobalCounter(void) +{ + uint64_t tmpval = SC_ATOMIC_GET(ftp_memcap); + return tmpval; +} + +/** + * \brief Check if alloc'ing "size" would mean we're over memcap + * + * \retval 1 if in bounds + * \retval 0 if not in bounds + */ +static int FTPCheckMemcap(uint64_t size) +{ + if (ftp_config_memcap == 0 || size + SC_ATOMIC_GET(ftp_memuse) <= ftp_config_memcap) + return 1; + (void)SC_ATOMIC_ADD(ftp_memcap, 1); + return 0; +} + +static void *FTPCalloc(size_t n, size_t size) +{ + if (FTPCheckMemcap((uint32_t)(n * size)) == 0) + return NULL; + + void *ptr = SCCalloc(n, size); + + if (unlikely(ptr == NULL)) + return NULL; + + FTPIncrMemuse((uint64_t)(n * size)); + return ptr; +} + +static void *FTPRealloc(void *ptr, size_t orig_size, size_t size) +{ + void *rptr = NULL; + + if (FTPCheckMemcap((uint32_t)(size - orig_size)) == 0) + return NULL; + + rptr = SCRealloc(ptr, size); + if (rptr == NULL) + return NULL; + + if (size > orig_size) { + FTPIncrMemuse(size - orig_size); + } else { + FTPDecrMemuse(orig_size - size); + } + + return rptr; +} + +static void FTPFree(void *ptr, size_t size) +{ + SCFree(ptr); + + FTPDecrMemuse((uint64_t)size); +} + +static FTPString *FTPStringAlloc(void) +{ + return FTPCalloc(1, sizeof(FTPString)); +} + +static void FTPStringFree(FTPString *str) +{ + if (str->str) { + FTPFree(str->str, str->len); + } + + FTPFree(str, sizeof(FTPString)); +} + +static void *FTPLocalStorageAlloc(void) +{ + /* needed by the mpm */ + FTPThreadCtx *td = SCCalloc(1, sizeof(*td)); + if (td == NULL) { + exit(EXIT_FAILURE); + } + + td->pmq = SCCalloc(1, sizeof(*td->pmq)); + if (td->pmq == NULL) { + exit(EXIT_FAILURE); + } + PmqSetup(td->pmq); + + td->ftp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx)); + if (unlikely(td->ftp_mpm_thread_ctx == NULL)) { + exit(EXIT_FAILURE); + } + MpmInitThreadCtx(td->ftp_mpm_thread_ctx, FTP_MPM); + return td; +} + +static void FTPLocalStorageFree(void *ptr) +{ + FTPThreadCtx *td = ptr; + if (td != NULL) { + if (td->pmq != NULL) { + PmqFree(td->pmq); + SCFree(td->pmq); + } + + if (td->ftp_mpm_thread_ctx != NULL) { + MpmDestroyThreadCtx(td->ftp_mpm_thread_ctx, FTP_MPM); + SCFree(td->ftp_mpm_thread_ctx); + } + + SCFree(td); + } + + return; +} +static FTPTransaction *FTPTransactionCreate(FtpState *state) +{ + SCEnter(); + FTPTransaction *firsttx = TAILQ_FIRST(&state->tx_list); + if (firsttx && state->tx_cnt - firsttx->tx_id > ftp_config_maxtx) { + // FTP does not set events yet... + return NULL; + } + FTPTransaction *tx = FTPCalloc(1, sizeof(*tx)); + if (tx == NULL) { + return NULL; + } + + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + + TAILQ_INIT(&tx->response_list); + + SCLogDebug("new transaction %p (state tx cnt %" PRIu64 ")", tx, state->tx_cnt); + return tx; +} + +static void FTPTransactionFree(FTPTransaction *tx) +{ + SCEnter(); + + if (tx->tx_data.de_state != NULL) { + DetectEngineStateFree(tx->tx_data.de_state); + } + + if (tx->request) { + FTPFree(tx->request, tx->request_length); + } + + FTPString *str = NULL; + while ((str = TAILQ_FIRST(&tx->response_list))) { + TAILQ_REMOVE(&tx->response_list, str, next); + FTPStringFree(str); + } + + if (tx->tx_data.events) { + AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); + } + + FTPFree(tx, sizeof(*tx)); +} + +typedef struct FtpInput_ { + const uint8_t *buf; + int32_t consumed; + int32_t len; + int32_t orig_len; +} FtpInput; + +static AppLayerResult FTPGetLineForDirection( + FtpState *state, FtpLineState *line, FtpInput *input, bool *current_line_truncated) +{ + SCEnter(); + + /* we have run out of input */ + if (input->len <= 0) + return APP_LAYER_ERROR; + + uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len); + + if (lf_idx == NULL) { + if (!(*current_line_truncated) && (uint32_t)input->len >= ftp_max_line_len) { + *current_line_truncated = true; + line->buf = input->buf; + line->len = ftp_max_line_len; + line->delim_len = 0; + input->len = 0; + SCReturnStruct(APP_LAYER_OK); + } + SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1)); + } else if (*current_line_truncated) { + // Whatever came in with first LF should also get discarded + *current_line_truncated = false; + line->len = 0; + line->delim_len = 0; + input->len = 0; + SCReturnStruct(APP_LAYER_ERROR); + } else { + // There could be one chunk of command data that has LF but post the line limit + // e.g. input_len = 5077 + // lf_idx = 5010 + // max_line_len = 4096 + uint32_t o_consumed = input->consumed; + input->consumed = lf_idx - input->buf + 1; + line->len = input->consumed - o_consumed; + input->len -= line->len; + line->lf_found = true; + DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len); + line->buf = input->buf + o_consumed; + if (line->len >= ftp_max_line_len) { + *current_line_truncated = true; + line->len = ftp_max_line_len; + SCReturnStruct(APP_LAYER_OK); + } + if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) { + line->delim_len = 2; + line->len -= 2; + } else { + line->delim_len = 1; + line->len -= 1; + } + SCReturnStruct(APP_LAYER_OK); + } +} + +/** + * \brief This function is called to determine and set which command is being + * transferred to the ftp server + * \param thread context + * \param input input line of the command + * \param len of the command + * \param cmd_descriptor when the command has been parsed + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static int FTPParseRequestCommand( + FTPThreadCtx *td, FtpLineState *line, const FtpCommand **cmd_descriptor) +{ + SCEnter(); + + /* I don't like this pmq reset here. We'll devise a method later, that + * should make the use of the mpm very efficient */ + PmqReset(td->pmq); + int mpm_cnt = mpm_table[FTP_MPM].Search( + ftp_mpm_ctx, td->ftp_mpm_thread_ctx, td->pmq, line->buf, line->len); + if (mpm_cnt) { + *cmd_descriptor = &FtpCommands[td->pmq->rule_id_array[0]]; + SCReturnInt(1); + } + + *cmd_descriptor = NULL; + SCReturnInt(0); +} + +struct FtpTransferCmd { + /** Need to look like a ExpectationData so DFree must + * be first field . */ + void (*DFree)(void *); + uint64_t flow_id; + uint8_t *file_name; + uint16_t file_len; + uint8_t direction; /**< direction in which the data will flow */ + FtpRequestCommand cmd; +}; + +static void FtpTransferCmdFree(void *data) +{ + struct FtpTransferCmd *cmd = (struct FtpTransferCmd *)data; + if (cmd == NULL) + return; + if (cmd->file_name) { + FTPFree(cmd->file_name, cmd->file_len + 1); + } + FTPFree(cmd, sizeof(struct FtpTransferCmd)); +} + +static uint32_t CopyCommandLine(uint8_t **dest, FtpLineState *line) +{ + if (likely(line->len)) { + uint8_t *where = FTPCalloc(line->len + 1, sizeof(char)); + if (unlikely(where == NULL)) { + return 0; + } + memcpy(where, line->buf, line->len); + + /* Remove trailing newlines/carriage returns */ + while (line->len && isspace((unsigned char)where[line->len - 1])) { + line->len--; + } + + where[line->len] = '\0'; + *dest = where; + } + /* either 0 or actual */ + return line->len ? line->len + 1 : 0; +} + +#include "util/print.h" + +/** + * \brief This function is called to retrieve a ftp request + * \param ftp_state the ftp state structure for the parser + * + * \retval APP_LAYER_OK when input was process successfully + * \retval APP_LAYER_ERROR when a unrecoverable error was encountered + */ +static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + FTPThreadCtx *thread_data = local_data; + + SCEnter(); + /* PrintRawDataFp(stdout, input,input_len); */ + + FtpState *state = (FtpState *)ftp_state; + void *ptmp; + + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) { + SCReturnStruct(APP_LAYER_OK); + } else if (input == NULL || input_len == 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + + FtpInput ftpi = { .buf = input, .len = input_len, .orig_len = input_len, .consumed = 0 }; + FtpLineState line = { .buf = NULL, .len = 0, .delim_len = 0, .lf_found = false }; + + uint8_t direction = STREAM_TOSERVER; + AppLayerResult res; + while (1) { + res = FTPGetLineForDirection(state, &line, &ftpi, &state->current_line_truncated_ts); + if (res.status == 1) { + return res; + } else if (res.status == -1) { + break; + } + const FtpCommand *cmd_descriptor; + + if (!FTPParseRequestCommand(thread_data, &line, &cmd_descriptor)) { + state->command = FTP_COMMAND_UNKNOWN; + continue; + } + + state->command = cmd_descriptor->command; + FTPTransaction *tx = FTPTransactionCreate(state); + if (unlikely(tx == NULL)) + SCReturnStruct(APP_LAYER_ERROR); + state->curr_tx = tx; + + tx->command_descriptor = cmd_descriptor; + tx->request_length = CopyCommandLine(&tx->request, &line); + tx->request_truncated = state->current_line_truncated_ts; + + if (line.lf_found) { + state->current_line_truncated_ts = false; + } + if (tx->request_truncated) { + AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, FtpEventRequestCommandTooLong); + } + + /* change direction (default to server) so expectation will handle + * the correct message when expectation will match. + * For ftp active mode, data connection direction is opposite to + * control direction. + */ + if ((state->active && state->command == FTP_COMMAND_STOR) || + (!state->active && state->command == FTP_COMMAND_RETR)) { + direction = STREAM_TOCLIENT; + } + + switch (state->command) { + case FTP_COMMAND_EPRT: + // fallthrough + case FTP_COMMAND_PORT: + if (line.len + 1 > state->port_line_size) { + /* Allocate an extra byte for a NULL terminator */ + ptmp = FTPRealloc(state->port_line, state->port_line_size, line.len); + if (ptmp == NULL) { + if (state->port_line) { + FTPFree(state->port_line, state->port_line_size); + state->port_line = NULL; + state->port_line_size = 0; + state->port_line_len = 0; + } + SCReturnStruct(APP_LAYER_OK); + } + state->port_line = ptmp; + state->port_line_size = line.len; + } + memcpy(state->port_line, line.buf, line.len); + state->port_line_len = line.len; + break; + case FTP_COMMAND_RETR: + // fallthrough + case FTP_COMMAND_STOR: { + /* Ensure that there is a negotiated dyn port and a file + * name -- need more than 5 chars: cmd [4], space, + */ + if (state->dyn_port == 0 || line.len < 6) { + SCReturnStruct(APP_LAYER_ERROR); + } + struct FtpTransferCmd *data = FTPCalloc(1, sizeof(struct FtpTransferCmd)); + if (data == NULL) + SCReturnStruct(APP_LAYER_ERROR); + data->DFree = FtpTransferCmdFree; + /* + * Min size has been checked in FTPParseRequestCommand + * SC_FILENAME_MAX includes the null + */ + uint32_t file_name_len = MIN(SC_FILENAME_MAX - 1, line.len - 5); +#if SC_FILENAME_MAX > UINT16_MAX +#error SC_FILENAME_MAX is greater than UINT16_MAX +#endif + data->file_name = FTPCalloc(file_name_len + 1, sizeof(char)); + if (data->file_name == NULL) { + FtpTransferCmdFree(data); + SCReturnStruct(APP_LAYER_ERROR); + } + data->file_name[file_name_len] = 0; + data->file_len = (uint16_t)file_name_len; + memcpy(data->file_name, line.buf + 5, file_name_len); + data->cmd = state->command; + data->flow_id = FlowGetId(f); + data->direction = direction; + int ret = AppLayerExpectationCreate( + f, direction, 0, state->dyn_port, ALPROTO_FTPDATA, data); + if (ret == -1) { + FtpTransferCmdFree(data); + SCLogDebug("No expectation created."); + SCReturnStruct(APP_LAYER_ERROR); + } else { + SCLogDebug("Expectation created [direction: %s, dynamic port %" PRIu16 "].", + state->active ? "to server" : "to client", state->dyn_port); + } + + /* reset the dyn port to avoid duplicate */ + state->dyn_port = 0; + /* reset active/passive indicator */ + state->active = false; + } break; + default: + break; + } + if (line.len >= ftp_max_line_len) { + ftpi.consumed = ftpi.len + 1; + break; + } + } + + SCReturnStruct(APP_LAYER_OK); +} + +static int FTPParsePassiveResponse( + Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len) +{ + uint16_t dyn_port = rs_ftp_pasv_response(input, input_len); + if (dyn_port == 0) { + return -1; + } + SCLogDebug("FTP passive mode (v4): dynamic port %" PRIu16 "", dyn_port); + state->active = false; + state->dyn_port = dyn_port; + state->curr_tx->dyn_port = dyn_port; + state->curr_tx->active = false; + + return 0; +} + +static int FTPParsePassiveResponseV6( + Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len) +{ + uint16_t dyn_port = rs_ftp_epsv_response(input, input_len); + if (dyn_port == 0) { + return -1; + } + SCLogDebug("FTP passive mode (v6): dynamic port %" PRIu16 "", dyn_port); + state->active = false; + state->dyn_port = dyn_port; + state->curr_tx->dyn_port = dyn_port; + state->curr_tx->active = false; + return 0; +} + +/** + * \brief Handle preliminary replies -- keep tx open + * \retval bool True for a positive preliminary reply; false otherwise + * + * 1yz Positive Preliminary reply + * + * The requested action is being initiated; expect another + * reply before proceeding with a new command + */ +static inline bool FTPIsPPR(const uint8_t *input, uint32_t input_len) +{ + return input_len >= 4 && isdigit(input[0]) && input[0] == '1' && isdigit(input[1]) && + isdigit(input[2]) && isspace(input[3]); +} + +/** + * \brief This function is called to retrieve a ftp response + * \param ftp_state the ftp state structure for the parser + * \param input input line of the command + * \param input_len length of the request + * \param output the resulting output + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static AppLayerResult FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + FtpState *state = (FtpState *)ftp_state; + + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + if (unlikely(input_len == 0)) { + SCReturnStruct(APP_LAYER_OK); + } + FtpInput ftpi = { .buf = input, .len = input_len, .orig_len = input_len, .consumed = 0 }; + FtpLineState line = { .buf = NULL, .len = 0, .delim_len = 0, .lf_found = false }; + + FTPTransaction *lasttx = TAILQ_FIRST(&state->tx_list); + AppLayerResult res; + while (1) { + res = FTPGetLineForDirection(state, &line, &ftpi, &state->current_line_truncated_tc); + if (res.status == 1) { + return res; + } else if (res.status == -1) { + break; + } + FTPTransaction *tx = FTPGetOldestTx(state, lasttx); + if (tx == NULL) { + tx = FTPTransactionCreate(state); + } + if (unlikely(tx == NULL)) { + SCReturnStruct(APP_LAYER_ERROR); + } + lasttx = tx; + if (state->command == FTP_COMMAND_UNKNOWN || tx->command_descriptor == NULL) { + /* unknown */ + tx->command_descriptor = &FtpCommands[FTP_COMMAND_MAX - 1]; + } + + state->curr_tx = tx; + uint16_t dyn_port; + switch (state->command) { + case FTP_COMMAND_AUTH_TLS: + if (line.len >= 4 && SCMemcmp("234 ", line.buf, 4) == 0) { + AppLayerRequestProtocolTLSUpgrade(f); + } + break; + + case FTP_COMMAND_EPRT: + dyn_port = rs_ftp_active_eprt(state->port_line, state->port_line_len); + if (dyn_port == 0) { + goto tx_complete; + } + state->dyn_port = dyn_port; + state->active = true; + tx->dyn_port = dyn_port; + tx->active = true; + SCLogDebug("FTP active mode (v6): dynamic port %" PRIu16 "", dyn_port); + break; + + case FTP_COMMAND_PORT: + dyn_port = rs_ftp_active_port(state->port_line, state->port_line_len); + if (dyn_port == 0) { + goto tx_complete; + } + state->dyn_port = dyn_port; + state->active = true; + tx->dyn_port = state->dyn_port; + tx->active = true; + SCLogDebug("FTP active mode (v4): dynamic port %" PRIu16 "", dyn_port); + break; + + case FTP_COMMAND_PASV: + if (line.len >= 4 && SCMemcmp("227 ", line.buf, 4) == 0) { + FTPParsePassiveResponse(f, ftp_state, line.buf, line.len); + } + break; + + case FTP_COMMAND_EPSV: + if (line.len >= 4 && SCMemcmp("229 ", line.buf, 4) == 0) { + FTPParsePassiveResponseV6(f, ftp_state, line.buf, line.len); + } + break; + default: + break; + } + + if (likely(line.len)) { + FTPString *response = FTPStringAlloc(); + if (likely(response)) { + response->len = CopyCommandLine(&response->str, &line); + response->truncated = state->current_line_truncated_tc; + if (response->truncated) { + AppLayerDecoderEventsSetEventRaw( + &tx->tx_data.events, FtpEventResponseCommandTooLong); + } + if (line.lf_found) { + state->current_line_truncated_tc = false; + } + TAILQ_INSERT_TAIL(&tx->response_list, response, next); + } + } + + /* Handle preliminary replies -- keep tx open */ + if (FTPIsPPR(line.buf, line.len)) { + continue; + } + tx_complete: + tx->done = true; + + if (line.len >= ftp_max_line_len) { + ftpi.consumed = ftpi.len + 1; + break; + } + } + + SCReturnStruct(APP_LAYER_OK); +} + +#ifdef DEBUG +static SCMutex ftp_state_mem_lock = SCMUTEX_INITIALIZER; +static uint64_t ftp_state_memuse = 0; +static uint64_t ftp_state_memcnt = 0; +#endif + +static void *FTPStateAlloc(void *orig_state, AppProto proto_orig) +{ + void *s = FTPCalloc(1, sizeof(FtpState)); + if (unlikely(s == NULL)) + return NULL; + + FtpState *ftp_state = (FtpState *)s; + TAILQ_INIT(&ftp_state->tx_list); + +#ifdef DEBUG + SCMutexLock(&ftp_state_mem_lock); + ftp_state_memcnt++; + ftp_state_memuse += sizeof(FtpState); + SCMutexUnlock(&ftp_state_mem_lock); +#endif + return s; +} + +static void FTPStateFree(void *s) +{ + FtpState *fstate = (FtpState *)s; + if (fstate->port_line != NULL) + FTPFree(fstate->port_line, fstate->port_line_size); + + FTPTransaction *tx = NULL; + while ((tx = TAILQ_FIRST(&fstate->tx_list))) { + TAILQ_REMOVE(&fstate->tx_list, tx, next); + SCLogDebug("[%s] state %p id %" PRIu64 ", Freeing %d bytes at %p", + tx->command_descriptor->command_name, s, tx->tx_id, tx->request_length, + tx->request); + FTPTransactionFree(tx); + } + + FTPFree(s, sizeof(FtpState)); +#ifdef DEBUG + SCMutexLock(&ftp_state_mem_lock); + ftp_state_memcnt--; + ftp_state_memuse -= sizeof(FtpState); + SCMutexUnlock(&ftp_state_mem_lock); +#endif +} + +/** + * \brief This function returns the oldest open transaction; if none + * are open, then the oldest transaction is returned + * \param ftp_state the ftp state structure for the parser + * \param starttx the ftp transaction where to start looking + * + * \retval transaction pointer when a transaction was found; NULL otherwise. + */ +static FTPTransaction *FTPGetOldestTx(const FtpState *ftp_state, FTPTransaction *starttx) +{ + if (unlikely(!ftp_state)) { + SCLogDebug("NULL state object; no transactions available"); + return NULL; + } + FTPTransaction *tx = starttx; + FTPTransaction *lasttx = NULL; + while (tx != NULL) { + /* Return oldest open tx */ + if (!tx->done) { + SCLogDebug("Returning tx %p id %" PRIu64, tx, tx->tx_id); + return tx; + } + /* save for the end */ + lasttx = tx; + tx = TAILQ_NEXT(tx, next); + } + /* All tx are closed; return last element */ + if (lasttx) + SCLogDebug("Returning OLDEST tx %p id %" PRIu64, lasttx, lasttx->tx_id); + return lasttx; +} + +static void *FTPGetTx(void *state, uint64_t tx_id) +{ + FtpState *ftp_state = (FtpState *)state; + if (ftp_state) { + FTPTransaction *tx = NULL; + + if (ftp_state->curr_tx == NULL) + return NULL; + if (ftp_state->curr_tx->tx_id == tx_id) + return ftp_state->curr_tx; + + TAILQ_FOREACH (tx, &ftp_state->tx_list, next) { + if (tx->tx_id == tx_id) + return tx; + } + } + return NULL; +} + +static AppLayerTxData *FTPGetTxData(void *vtx) +{ + FTPTransaction *tx = (FTPTransaction *)vtx; + return &tx->tx_data; +} + +static AppLayerStateData *FTPGetStateData(void *vstate) +{ + FtpState *s = (FtpState *)vstate; + return &s->state_data; +} + +static void FTPStateTransactionFree(void *state, uint64_t tx_id) +{ + FtpState *ftp_state = state; + FTPTransaction *tx = NULL; + TAILQ_FOREACH (tx, &ftp_state->tx_list, next) { + if (tx_id < tx->tx_id) + break; + else if (tx_id > tx->tx_id) + continue; + + if (tx == ftp_state->curr_tx) + ftp_state->curr_tx = NULL; + TAILQ_REMOVE(&ftp_state->tx_list, tx, next); + FTPTransactionFree(tx); + break; + } +} + +static uint64_t FTPGetTxCnt(void *state) +{ + uint64_t cnt = 0; + FtpState *ftp_state = state; + if (ftp_state) { + cnt = ftp_state->tx_cnt; + } + SCLogDebug("returning state %p %" PRIu64, state, cnt); + return cnt; +} + +static int FTPGetAlstateProgress(void *vtx, uint8_t direction) +{ + SCLogDebug("tx %p", vtx); + FTPTransaction *tx = vtx; + + if (!tx->done) { + if (direction == STREAM_TOSERVER && tx->command_descriptor->command == FTP_COMMAND_PORT) { + return FTP_STATE_PORT_DONE; + } + return FTP_STATE_IN_PROGRESS; + } + + return FTP_STATE_FINISHED; +} + +static int FTPRegisterPatternsForProtocolDetection(void) +{ + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_FTP, "220 (", 5, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_FTP, "FEAT", 4, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_FTP, "USER ", 5, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_FTP, "PASS ", 5, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_FTP, "PORT ", 5, 0, STREAM_TOSERVER) < 0) { + return -1; + } + + return 0; +} + +static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; + +/** + * \brief This function is called to retrieve a ftp request + * \param ftp_state the ftp state structure for the parser + * \param output the resulting output + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static AppLayerResult FTPDataParse(Flow *f, FtpDataState *ftpdata_state, + AppLayerParserState *pstate, StreamSlice stream_slice, void *local_data, uint8_t direction) +{ + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + const bool eof = (direction & STREAM_TOSERVER) + ? AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) != 0 + : AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) != 0; + + ftpdata_state->tx_data.file_flags |= ftpdata_state->state_data.file_flags; + if (ftpdata_state->tx_data.file_tx == 0) + ftpdata_state->tx_data.file_tx = direction & (STREAM_TOSERVER | STREAM_TOCLIENT); + + /* we depend on detection engine for file pruning */ + const uint16_t flags = FileFlowFlagsToFlags(ftpdata_state->tx_data.file_flags, direction); + int ret = 0; + + SCLogDebug("FTP-DATA input_len %u flags %04x dir %d/%s EOF %s", input_len, flags, direction, + (direction & STREAM_TOSERVER) ? "toserver" : "toclient", eof ? "true" : "false"); + + SCLogDebug("FTP-DATA flags %04x dir %d", flags, direction); + if (input_len && ftpdata_state->files == NULL) { + struct FtpTransferCmd *data = + (struct FtpTransferCmd *)FlowGetStorageById(f, AppLayerExpectationGetFlowId()); + if (data == NULL) { + SCReturnStruct(APP_LAYER_ERROR); + } + + /* we shouldn't get data in the wrong dir. Don't set things up for this dir */ + if ((direction & data->direction) == 0) { + // TODO set event for data in wrong direction + SCLogDebug("input %u not for our direction (%s): %s/%s", input_len, + (direction & STREAM_TOSERVER) ? "toserver" : "toclient", + data->cmd == FTP_COMMAND_STOR ? "STOR" : "RETR", + (data->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); + SCReturnStruct(APP_LAYER_OK); + } + + ftpdata_state->files = FileContainerAlloc(); + if (ftpdata_state->files == NULL) { + FlowFreeStorageById(f, AppLayerExpectationGetFlowId()); + SCReturnStruct(APP_LAYER_ERROR); + } + + ftpdata_state->file_name = data->file_name; + ftpdata_state->file_len = data->file_len; + data->file_name = NULL; + data->file_len = 0; + f->parent_id = data->flow_id; + ftpdata_state->command = data->cmd; + switch (data->cmd) { + case FTP_COMMAND_STOR: + ftpdata_state->direction = data->direction; + SCLogDebug("STOR data to %s", + (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); + break; + case FTP_COMMAND_RETR: + ftpdata_state->direction = data->direction; + SCLogDebug("RETR data to %s", + (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); + break; + default: + break; + } + + /* open with fixed track_id 0 as we can have just one + * file per ftp-data flow. */ + if (FileOpenFileWithId(ftpdata_state->files, &sbcfg, 0ULL, + (uint8_t *)ftpdata_state->file_name, ftpdata_state->file_len, input, input_len, + flags) != 0) { + SCLogDebug("Can't open file"); + ret = -1; + } + FlowFreeStorageById(f, AppLayerExpectationGetFlowId()); + ftpdata_state->tx_data.files_opened = 1; + } else { + if (ftpdata_state->state == FTPDATA_STATE_FINISHED) { + SCLogDebug("state is already finished"); + DEBUG_VALIDATE_BUG_ON(input_len); // data after state finished is a bug. + SCReturnStruct(APP_LAYER_OK); + } + if ((direction & ftpdata_state->direction) == 0) { + if (input_len) { + // TODO set event for data in wrong direction + } + SCLogDebug("input %u not for us (%s): %s/%s", input_len, + (direction & STREAM_TOSERVER) ? "toserver" : "toclient", + ftpdata_state->command == FTP_COMMAND_STOR ? "STOR" : "RETR", + (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient"); + SCReturnStruct(APP_LAYER_OK); + } + if (input_len != 0) { + ret = FileAppendData(ftpdata_state->files, &sbcfg, input, input_len); + if (ret == -2) { + ret = 0; + SCLogDebug("FileAppendData() - file no longer being extracted"); + goto out; + } else if (ret < 0) { + SCLogDebug("FileAppendData() failed: %d", ret); + ret = -2; + goto out; + } + } + } + + BUG_ON((direction & ftpdata_state->direction) == 0); // should be unreachable + if (eof) { + ret = FileCloseFile(ftpdata_state->files, &sbcfg, NULL, 0, flags); + ftpdata_state->state = FTPDATA_STATE_FINISHED; + SCLogDebug("closed because of eof: state now FTPDATA_STATE_FINISHED"); + } +out: + if (ret < 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + SCReturnStruct(APP_LAYER_OK); +} + +static AppLayerResult FTPDataParseRequest(Flow *f, void *ftp_state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + return FTPDataParse(f, ftp_state, pstate, stream_slice, local_data, STREAM_TOSERVER); +} + +static AppLayerResult FTPDataParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + return FTPDataParse(f, ftp_state, pstate, stream_slice, local_data, STREAM_TOCLIENT); +} + +#ifdef DEBUG +static SCMutex ftpdata_state_mem_lock = SCMUTEX_INITIALIZER; +static uint64_t ftpdata_state_memuse = 0; +static uint64_t ftpdata_state_memcnt = 0; +#endif + +static void *FTPDataStateAlloc(void *orig_state, AppProto proto_orig) +{ + void *s = FTPCalloc(1, sizeof(FtpDataState)); + if (unlikely(s == NULL)) + return NULL; + + FtpDataState *state = (FtpDataState *)s; + state->state = FTPDATA_STATE_IN_PROGRESS; + +#ifdef DEBUG + SCMutexLock(&ftpdata_state_mem_lock); + ftpdata_state_memcnt++; + ftpdata_state_memuse += sizeof(FtpDataState); + SCMutexUnlock(&ftpdata_state_mem_lock); +#endif + return s; +} + +static void FTPDataStateFree(void *s) +{ + FtpDataState *fstate = (FtpDataState *)s; + + if (fstate->tx_data.de_state != NULL) { + DetectEngineStateFree(fstate->tx_data.de_state); + } + if (fstate->file_name != NULL) { + FTPFree(fstate->file_name, fstate->file_len + 1); + } + + FileContainerFree(fstate->files, &sbcfg); + + FTPFree(s, sizeof(FtpDataState)); +#ifdef DEBUG + SCMutexLock(&ftpdata_state_mem_lock); + ftpdata_state_memcnt--; + ftpdata_state_memuse -= sizeof(FtpDataState); + SCMutexUnlock(&ftpdata_state_mem_lock); +#endif +} + +static AppLayerTxData *FTPDataGetTxData(void *vtx) +{ + FtpDataState *ftp_state = (FtpDataState *)vtx; + return &ftp_state->tx_data; +} + +static AppLayerStateData *FTPDataGetStateData(void *vstate) +{ + FtpDataState *ftp_state = (FtpDataState *)vstate; + return &ftp_state->state_data; +} + +static void FTPDataStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *FTPDataGetTx(void *state, uint64_t tx_id) +{ + FtpDataState *ftp_state = (FtpDataState *)state; + return ftp_state; +} + +static uint64_t FTPDataGetTxCnt(void *state) +{ + /* ftp-data is single tx */ + return 1; +} + +static int FTPDataGetAlstateProgress(void *tx, uint8_t direction) +{ + FtpDataState *ftpdata_state = (FtpDataState *)tx; + if (direction == ftpdata_state->direction) + return ftpdata_state->state; + else + return FTPDATA_STATE_FINISHED; +} + +static AppLayerGetFileState FTPDataStateGetTxFiles(void *_state, void *tx, uint8_t direction) +{ + FtpDataState *ftpdata_state = (FtpDataState *)tx; + AppLayerGetFileState files = { .fc = NULL, .cfg = &sbcfg }; + + if (direction == ftpdata_state->direction) + files.fc = ftpdata_state->files; + + return files; +} + +static void FTPSetMpmState(void) +{ + ftp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx)); + if (unlikely(ftp_mpm_ctx == NULL)) { + exit(EXIT_FAILURE); + } + MpmInitCtx(ftp_mpm_ctx, FTP_MPM); + + uint32_t i = 0; + for (i = 0; i < sizeof(FtpCommands) / sizeof(FtpCommand) - 1; i++) { + const FtpCommand *cmd = &FtpCommands[i]; + if (cmd->command_length == 0) + continue; + + MpmAddPatternCI(ftp_mpm_ctx, (uint8_t *)cmd->command_name, cmd->command_length, + 0 /* defunct */, 0 /* defunct */, i /* id */, i /* rule id */, 0 /* no flags */); + } + + mpm_table[FTP_MPM].Prepare(ftp_mpm_ctx); +} + +static void FTPFreeMpmState(void) +{ + if (ftp_mpm_ctx != NULL) { + mpm_table[FTP_MPM].DestroyCtx(ftp_mpm_ctx); + SCFree(ftp_mpm_ctx); + ftp_mpm_ctx = NULL; + } +} + +/** \brief FTP tx iterator, specialized for its linked list + * + * \retval txptr or NULL if no more txs in list + */ +static AppLayerGetTxIterTuple FTPGetTxIterator(const uint8_t ipproto, const AppProto alproto, + void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) +{ + FtpState *ftp_state = (FtpState *)alstate; + AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; + if (ftp_state) { + FTPTransaction *tx_ptr; + if (state->un.ptr == NULL) { + tx_ptr = TAILQ_FIRST(&ftp_state->tx_list); + } else { + tx_ptr = (FTPTransaction *)state->un.ptr; + } + if (tx_ptr) { + while (tx_ptr->tx_id < min_tx_id) { + tx_ptr = TAILQ_NEXT(tx_ptr, next); + if (!tx_ptr) { + return no_tuple; + } + } + if (tx_ptr->tx_id >= max_tx_id) { + return no_tuple; + } + state->un.ptr = TAILQ_NEXT(tx_ptr, next); + AppLayerGetTxIterTuple tuple = { + .tx_ptr = tx_ptr, + .tx_id = tx_ptr->tx_id, + .has_next = (state->un.ptr != NULL), + }; + return tuple; + } + } + return no_tuple; +} + +void RegisterFTPParsers(void) +{ + const char *proto_name = "ftp"; + const char *proto_data_name = "ftp-data"; + + /** FTP */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_FTP, proto_name); + if (FTPRegisterPatternsForProtocolDetection() < 0) + return; + AppLayerProtoDetectRegisterProtocol(ALPROTO_FTPDATA, proto_data_name); + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER, FTPParseRequest); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOCLIENT, FTPParseResponse); + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree); + AppLayerParserRegisterParserAcceptableDataDirection( + IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER | STREAM_TOCLIENT); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx); + AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxData); + AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxIterator); + AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetStateData); + + AppLayerParserRegisterLocalStorageFunc( + IPPROTO_TCP, ALPROTO_FTP, FTPLocalStorageAlloc, FTPLocalStorageFree); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress); + + AppLayerParserRegisterStateProgressCompletionStatus( + ALPROTO_FTP, FTP_STATE_FINISHED, FTP_STATE_FINISHED); + + AppLayerRegisterExpectationProto(IPPROTO_TCP, ALPROTO_FTPDATA); + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER, FTPDataParseRequest); + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOCLIENT, FTPDataParseResponse); + AppLayerParserRegisterStateFuncs( + IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree); + AppLayerParserRegisterParserAcceptableDataDirection( + IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER | STREAM_TOCLIENT); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree); + + AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetTxFiles); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx); + AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxData); + AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetStateData); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc( + IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress); + + AppLayerParserRegisterStateProgressCompletionStatus( + ALPROTO_FTPDATA, FTPDATA_STATE_FINISHED, FTPDATA_STATE_FINISHED); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info); + AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info_by_id); + + sbcfg.buf_size = 4096; + sbcfg.Calloc = FTPCalloc; + sbcfg.Realloc = FTPRealloc; + sbcfg.Free = FTPFree; + + FTPParseMemcap(); + } else { + SCLogInfo("Parsed disabled for %s protocol. Protocol detection" + "still on.", + proto_name); + } + + FTPSetMpmState(); + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_FTP, FTPParserRegisterTests); +#endif +} + +void FTPAtExitPrintStats(void) +{ +#ifdef DEBUG + SCMutexLock(&ftp_state_mem_lock); + SCLogDebug("ftp_state_memcnt %" PRIu64 ", ftp_state_memuse %" PRIu64 "", ftp_state_memcnt, + ftp_state_memuse); + SCMutexUnlock(&ftp_state_mem_lock); +#endif +} + +/* + * \brief Returns the ending offset of the next line from a multi-line buffer. + * + * "Buffer" refers to a FTP response in a single buffer containing multiple lines. + * Here, "next line" is defined as terminating on + * - Newline character + * - Null character + * + * \param buffer Contains zero or more characters. + * \param len Size, in bytes, of buffer. + * + * \retval Offset from the start of buffer indicating the where the + * next "line ends". The characters between the input buffer and this + * value comprise the line. + * + * NULL is found first or a newline isn't found, then UINT16_MAX is returned. + */ +uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len) +{ + if (!buffer || *buffer == '\0') { + return UINT16_MAX; + } + + char *c = strchr(buffer, '\n'); + return c == NULL ? len : (uint16_t)(c - buffer + 1); +} + +bool EveFTPDataAddMetadata(void *vtx, JsonBuilder *jb) +{ + const FtpDataState *ftp_state = (FtpDataState *)vtx; + jb_open_object(jb, "ftp_data"); + + if (ftp_state->file_name) { + jb_set_string_from_bytes(jb, "filename", ftp_state->file_name, ftp_state->file_len); + } + switch (ftp_state->command) { + case FTP_COMMAND_STOR: + JB_SET_STRING(jb, "command", "STOR"); + break; + case FTP_COMMAND_RETR: + JB_SET_STRING(jb, "command", "RETR"); + break; + default: + break; + } + jb_close(jb); + return true; +} + +/** + * \brief Free memory allocated for global FTP parser state. + */ +void FTPParserCleanup(void) +{ + FTPFreeMpmState(); +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "stream-tcp.h" + +/** \test Send a get request in one chunk. */ +static int FTPParserTest01(void) +{ + Flow f; + uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n"; + uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_FTP; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen); + FAIL_IF(r != 0); + + FtpState *ftp_state = f.alstate; + FAIL_IF_NULL(ftp_state); + FAIL_IF(ftp_state->command != FTP_COMMAND_PORT); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + PASS; +} + +/** \test Supply RETR without a filename */ +static int FTPParserTest11(void) +{ + Flow f; + uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n"; + uint8_t ftpbuf2[] = "RETR\r\n"; + uint8_t ftpbuf3[] = "227 OK\r\n"; + TcpSession ssn; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_FTP; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER | STREAM_START, + ftpbuf1, sizeof(ftpbuf1) - 1); + FAIL_IF(r != 0); + + /* Response */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOCLIENT, ftpbuf3, sizeof(ftpbuf3) - 1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, sizeof(ftpbuf2) - 1); + FAIL_IF(r == 0); + + FtpState *ftp_state = f.alstate; + FAIL_IF_NULL(ftp_state); + + FAIL_IF(ftp_state->command != FTP_COMMAND_RETR); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + PASS; +} + +/** \test Supply STOR without a filename */ +static int FTPParserTest12(void) +{ + Flow f; + uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n"; + uint8_t ftpbuf2[] = "STOR\r\n"; + uint8_t ftpbuf3[] = "227 OK\r\n"; + TcpSession ssn; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_FTP; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER | STREAM_START, + ftpbuf1, sizeof(ftpbuf1) - 1); + FAIL_IF(r != 0); + + /* Response */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOCLIENT, ftpbuf3, sizeof(ftpbuf3) - 1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, sizeof(ftpbuf2) - 1); + FAIL_IF(r == 0); + + FtpState *ftp_state = f.alstate; + FAIL_IF_NULL(ftp_state); + + FAIL_IF(ftp_state->command != FTP_COMMAND_STOR); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + PASS; +} +#endif /* UNITTESTS */ + +void FTPParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("FTPParserTest01", FTPParserTest01); + UtRegisterTest("FTPParserTest11", FTPParserTest11); + UtRegisterTest("FTPParserTest12", FTPParserTest12); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer/ftp/parser.h b/src/app-layer/ftp/parser.h new file mode 100644 index 000000000000..b69894b6c067 --- /dev/null +++ b/src/app-layer/ftp/parser.h @@ -0,0 +1,195 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * \author Jeff Lucovsky + */ + +#ifndef __APP_LAYER_FTP_H__ +#define __APP_LAYER_FTP_H__ + +#include "rust.h" + +enum { + FTP_STATE_IN_PROGRESS, + FTP_STATE_PORT_DONE, + FTP_STATE_FINISHED, +}; + +typedef enum { + FTP_COMMAND_UNKNOWN = 0, + FTP_COMMAND_ABOR, + FTP_COMMAND_ACCT, + FTP_COMMAND_ALLO, + FTP_COMMAND_APPE, + FTP_COMMAND_AUTH_TLS, + FTP_COMMAND_CDUP, + FTP_COMMAND_CHMOD, + FTP_COMMAND_CWD, + FTP_COMMAND_DELE, + FTP_COMMAND_EPSV, + FTP_COMMAND_HELP, + FTP_COMMAND_IDLE, + FTP_COMMAND_LIST, + FTP_COMMAND_MAIL, + FTP_COMMAND_MDTM, + FTP_COMMAND_MKD, + FTP_COMMAND_MLFL, + FTP_COMMAND_MODE, + FTP_COMMAND_MRCP, + FTP_COMMAND_MRSQ, + FTP_COMMAND_MSAM, + FTP_COMMAND_MSND, + FTP_COMMAND_MSOM, + FTP_COMMAND_NLST, + FTP_COMMAND_NOOP, + FTP_COMMAND_PASS, + FTP_COMMAND_PASV, + FTP_COMMAND_PORT, + FTP_COMMAND_PWD, + FTP_COMMAND_QUIT, + FTP_COMMAND_REIN, + FTP_COMMAND_REST, + FTP_COMMAND_RETR, + FTP_COMMAND_RMD, + FTP_COMMAND_RNFR, + FTP_COMMAND_RNTO, + FTP_COMMAND_SITE, + FTP_COMMAND_SIZE, + FTP_COMMAND_SMNT, + FTP_COMMAND_STAT, + FTP_COMMAND_STOR, + FTP_COMMAND_STOU, + FTP_COMMAND_STRU, + FTP_COMMAND_SYST, + FTP_COMMAND_TYPE, + FTP_COMMAND_UMASK, + FTP_COMMAND_USER, + FTP_COMMAND_EPRT, + + /* must be last */ + FTP_COMMAND_MAX + /** \todo more if missing.. */ +} FtpRequestCommand; + +typedef struct FtpCommand_ { + const char *command_name; + FtpRequestCommand command; + const uint8_t command_length; +} FtpCommand; +extern const FtpCommand FtpCommands[FTP_COMMAND_MAX + 1]; + +typedef uint32_t FtpRequestCommandArgOfs; + +/** used to hold the line state when we have fragmentation. */ +typedef struct FtpLineState_ { + /** used to indicate if the current_line buffer is a malloced buffer. We + * use a malloced buffer, if a line is fragmented */ + const uint8_t *buf; + uint32_t len; + uint8_t delim_len; + bool lf_found; +} FtpLineState; + +typedef struct FTPString_ { + uint8_t *str; + uint32_t len; + bool truncated; + TAILQ_ENTRY(FTPString_) next; +} FTPString; + +typedef struct FTPTransaction_ { + /** id of this tx, starting at 0 */ + uint64_t tx_id; + + AppLayerTxData tx_data; + + /* for the request */ + uint32_t request_length; + uint8_t *request; + bool request_truncated; + + /* for the command description */ + const FtpCommand *command_descriptor; + + uint16_t dyn_port; /* dynamic port, if applicable */ + bool done; /* transaction complete? */ + bool active; /* active or passive mode */ + + uint8_t direction; + + /* Handle multiple responses */ + TAILQ_HEAD(, FTPString_) response_list; + + TAILQ_ENTRY(FTPTransaction_) next; +} FTPTransaction; + +/** FTP State for app layer parser */ +typedef struct FtpState_ { + bool active; + + FTPTransaction *curr_tx; + TAILQ_HEAD(, FTPTransaction_) tx_list; /**< transaction list */ + uint64_t tx_cnt; + + bool current_line_truncated_ts; + bool current_line_truncated_tc; + + FtpRequestCommand command; + FtpRequestCommandArgOfs arg_offset; + uint32_t port_line_len; + uint32_t port_line_size; + uint8_t *port_line; + + uint16_t dyn_port; + + AppLayerStateData state_data; +} FtpState; + +enum { + FTPDATA_STATE_IN_PROGRESS, + FTPDATA_STATE_FINISHED, +}; + +/** FTP Data State for app layer parser */ +typedef struct FtpDataState_ { + uint8_t *input; + uint8_t *file_name; + FileContainer *files; + int32_t input_len; + int16_t file_len; + FtpRequestCommand command; + uint8_t state; + uint8_t direction; + AppLayerTxData tx_data; + AppLayerStateData state_data; +} FtpDataState; + +void RegisterFTPParsers(void); +void FTPParserRegisterTests(void); +void FTPAtExitPrintStats(void); +void FTPParserCleanup(void); +uint64_t FTPMemuseGlobalCounter(void); +uint64_t FTPMemcapGlobalCounter(void); + +uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len); +bool EveFTPDataAddMetadata(void *vtx, JsonBuilder *jb); + +#endif /* __APP_LAYER_FTP_H__ */ diff --git a/src/app-layer/http/detect-accept-enc.c b/src/app-layer/http/detect-accept-enc.c new file mode 100644 index 000000000000..c0d85cf06f9b --- /dev/null +++ b/src/app-layer/http/detect-accept-enc.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements http_accept_enc sticky buffer + */ + +#define KEYWORD_NAME_LEGACY "http_accept_enc" +#define KEYWORD_NAME "http.accept_enc" +#define KEYWORD_DOC "http-keywords.html#http-accept-enc" +#define BUFFER_NAME "http_accept_enc" +#define BUFFER_DESC "http accept encoding header" +#define HEADER_NAME "Accept-Encoding" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_ACCEPT_ENC +#define KEYWORD_TOSERVER 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-accept-enc.h" + +void RegisterHttpHeadersAcceptEnc(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-accept-enc.h b/src/app-layer/http/detect-accept-enc.h similarity index 100% rename from src/detect-http-accept-enc.h rename to src/app-layer/http/detect-accept-enc.h diff --git a/src/app-layer/http/detect-accept-lang.c b/src/app-layer/http/detect-accept-lang.c new file mode 100644 index 000000000000..27c94cfcd343 --- /dev/null +++ b/src/app-layer/http/detect-accept-lang.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements http_accept_lang sticky buffer + */ + +#define KEYWORD_NAME_LEGACY "http_accept_lang" +#define KEYWORD_NAME "http.accept_lang" +#define KEYWORD_DOC "http-keywords.html#http-accept-lang" +#define BUFFER_NAME "http_accept_lang" +#define BUFFER_DESC "http accept language header" +#define HEADER_NAME "Accept-Language" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_ACCEPT_LANG +#define KEYWORD_TOSERVER 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-accept-lang.h" + +void RegisterHttpHeadersAcceptLang(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-accept-lang.h b/src/app-layer/http/detect-accept-lang.h similarity index 100% rename from src/detect-http-accept-lang.h rename to src/app-layer/http/detect-accept-lang.h diff --git a/src/app-layer/http/detect-accept.c b/src/app-layer/http/detect-accept.c new file mode 100644 index 000000000000..483cef87f9aa --- /dev/null +++ b/src/app-layer/http/detect-accept.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_header_* + */ + +#define KEYWORD_NAME_LEGACY "http_accept" +#define KEYWORD_NAME "http.accept" +#define KEYWORD_DOC "http-keywords.html#http-accept" +#define BUFFER_NAME "http_accept" +#define BUFFER_DESC "http accept header" +#define HEADER_NAME "Accept" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_ACCEPT +#define KEYWORD_TOSERVER 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-accept.h" + +void RegisterHttpHeadersAccept(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-accept.h b/src/app-layer/http/detect-accept.h similarity index 100% rename from src/detect-http-accept.h rename to src/app-layer/http/detect-accept.h diff --git a/src/app-layer/http/detect-client-body.c b/src/app-layer/http/detect-client-body.c new file mode 100644 index 000000000000..3d243c109580 --- /dev/null +++ b/src/app-layer/http/detect-client-body.c @@ -0,0 +1,398 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Implements support for the http_client_body keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +// PrefilterMpmFiledata +#include "detect-file-data.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-client-body.h" +#include "stream-tcp.h" +#include "util/profiling.h" + +static int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, const char *); +static int DetectHttpClientBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); +#ifdef UNITTESTS +static void DetectHttpClientBodyRegisterTests(void); +#endif +static void DetectHttpClientBodySetupCallback(const DetectEngineCtx *de_ctx, Signature *s); +static int g_http_client_body_buffer_id = 0; + +static uint8_t DetectEngineInspectBufferHttpBody(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +static int PrefilterMpmHttpRequestBodyRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); + +/** + * \brief Registers the keyword handlers for the "http_client_body" keyword. + */ +void DetectHttpClientBodyRegister(void) +{ + /* http_client_body content modifier */ + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].name = "http_client_body"; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].desc = + "content modifier to match only on HTTP request-body"; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = "/rules/http-keywords.html#http-client-body"; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].alternative = DETECT_HTTP_REQUEST_BODY; + + /* http.request_body sticky buffer */ + sigmatch_table[DETECT_HTTP_REQUEST_BODY].name = "http.request_body"; + sigmatch_table[DETECT_HTTP_REQUEST_BODY].desc = + "sticky buffer to match the HTTP request body buffer"; + sigmatch_table[DETECT_HTTP_REQUEST_BODY].url = "/rules/http-keywords.html#http-client-body"; + sigmatch_table[DETECT_HTTP_REQUEST_BODY].Setup = DetectHttpClientBodySetupSticky; + sigmatch_table[DETECT_HTTP_REQUEST_BODY].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_HTTP_REQUEST_BODY].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_client_body", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_BODY, DetectEngineInspectBufferHttpBody, NULL); + + DetectAppLayerMpmRegister2("http_client_body", SIG_FLAG_TOSERVER, 2, + PrefilterMpmHttpRequestBodyRegister, NULL, ALPROTO_HTTP1, HTP_REQUEST_BODY); + + DetectAppLayerInspectEngineRegister2("http_client_body", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectFiledata, NULL); + DetectAppLayerMpmRegister2("http_client_body", SIG_FLAG_TOSERVER, 2, + PrefilterMpmFiledataRegister, NULL, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeSetDescriptionByName("http_client_body", "http request body"); + + DetectBufferTypeRegisterSetupCallback("http_client_body", DetectHttpClientBodySetupCallback); + + g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body"); +} + +static void DetectHttpClientBodySetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + AppLayerHtpEnableRequestBodyCallback(); + + /* client body needs to be inspected in sync with stream if possible */ + s->init_data->init_flags |= SIG_FLAG_INIT_NEED_FLUSH; +} + +/** + * \brief The setup function for the http_client_body keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_CLIENT_BODY, + g_http_client_body_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.request_body keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpClientBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_client_body_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static inline HtpBody *GetRequestBody(htp_tx_t *tx) +{ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) { + SCLogDebug("no htud"); + return NULL; + } + + return &htud->request_body; +} + +typedef struct PrefilterMpmHttpRequestBody { + int list_id; + int base_list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmHttpRequestBody; + +static void PrefilterMpmHttpRequestBodyFree(void *ptr) +{ + SCFree(ptr); +} + +static inline InspectionBuffer *HttpRequestBodyXformsGetDataCallback(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, const int list_id, InspectionBuffer *base_buffer) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect != NULL) + return buffer; + + InspectionBufferSetup(det_ctx, list_id, buffer, base_buffer->inspect, base_buffer->inspect_len); + buffer->inspect_offset = base_buffer->inspect_offset; + InspectionBufferApplyTransforms(buffer, transforms); + SCLogDebug("xformed buffer %p size %u", buffer, buffer->inspect_len); + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static InspectionBuffer *HttpRequestBodyGetDataCallback(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id, const int base_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, base_id); + if (base_id != list_id && buffer->inspect != NULL) + return HttpRequestBodyXformsGetDataCallback(det_ctx, transforms, list_id, buffer); + else if (buffer->inspect != NULL) + return buffer; + + htp_tx_t *tx = txv; + HtpState *htp_state = f->alstate; + const uint8_t flags = flow_flags; + + HtpBody *body = GetRequestBody(tx); + if (body == NULL) { + return NULL; + } + + /* no new data */ + if (body->body_inspected == body->content_len_so_far) { + SCLogDebug("no new data"); + return NULL; + } + + HtpBodyChunk *cur = body->first; + if (cur == NULL) { + SCLogDebug("No http chunks to inspect for this transaction"); + return NULL; + } + + SCLogDebug("request.body_limit %u request_body.content_len_so_far %" PRIu64 + ", request.inspect_min_size %" PRIu32 ", EOF %s, progress > body? %s", + htp_state->cfg->request.body_limit, body->content_len_so_far, + htp_state->cfg->request.inspect_min_size, flags & STREAM_EOF ? "true" : "false", + (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) > + HTP_REQUEST_BODY) + ? "true" + : "false"); + + if (!htp_state->cfg->http_body_inline) { + /* inspect the body if the transfer is complete or we have hit + * our body size limit */ + if ((htp_state->cfg->request.body_limit == 0 || + body->content_len_so_far < htp_state->cfg->request.body_limit) && + body->content_len_so_far < htp_state->cfg->request.inspect_min_size && + !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) > + HTP_REQUEST_BODY) && + !(flags & STREAM_EOF)) { + SCLogDebug("we still haven't seen the entire request body. " + "Let's defer body inspection till we see the " + "entire body."); + return NULL; + } + } + + /* get the inspect buffer + * + * make sure that we have at least the configured inspect_win size. + * If we have more, take at least 1/4 of the inspect win size before + * the new data. + */ + uint64_t offset = 0; + if (body->body_inspected > htp_state->cfg->request.inspect_min_size) { + BUG_ON(body->content_len_so_far < body->body_inspected); + uint64_t inspect_win = body->content_len_so_far - body->body_inspected; + SCLogDebug("inspect_win %" PRIu64, inspect_win); + if (inspect_win < htp_state->cfg->request.inspect_window) { + uint64_t inspect_short = htp_state->cfg->request.inspect_window - inspect_win; + if (body->body_inspected < inspect_short) + offset = 0; + else + offset = body->body_inspected - inspect_short; + } else { + offset = body->body_inspected - (htp_state->cfg->request.inspect_window / 4); + } + } + + const uint8_t *data; + uint32_t data_len; + + StreamingBufferGetDataAtOffset(body->sb, &data, &data_len, offset); + InspectionBufferSetup(det_ctx, base_id, buffer, data, data_len); + buffer->inspect_offset = offset; + body->body_inspected = body->content_len_so_far; + SCLogDebug("body->body_inspected now: %" PRIu64, body->body_inspected); + + if (base_id != list_id) { + buffer = HttpRequestBodyXformsGetDataCallback(det_ctx, transforms, list_id, buffer); + } + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectBufferHttpBody(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + bool eof = + (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress); + const InspectionBuffer *buffer = HttpRequestBodyGetDataCallback( + det_ctx, engine->v2.transforms, f, flags, txv, engine->sm_list, engine->sm_list_base); + if (buffer == NULL || buffer->inspect == NULL) { + return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + + const uint32_t data_len = buffer->inspect_len; + const uint8_t *data = buffer->inspect; + const uint64_t offset = buffer->inspect_offset; + + uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0; + ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0); + ci_flags |= buffer->flags; + + /* Inspect all the uricontents fetched on each + * transaction at the app layer */ + const bool match = + DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, (uint8_t *)data, + data_len, offset, ci_flags, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > + HTP_REQUEST_BODY) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > + HTP_RESPONSE_BODY) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +/** \brief HTTP Request body callback + * + * \param det_ctx detection engine thread ctx + * \param pectx inspection context + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param idx transaction id + * \param flags STREAM_* flags including direction + */ +static void PrefilterTxHttpRequestBody(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmHttpRequestBody *ctx = (const PrefilterMpmHttpRequestBody *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + InspectionBuffer *buffer = HttpRequestBodyGetDataCallback( + det_ctx, ctx->transforms, f, flags, txv, list_id, ctx->base_list_id); + if (buffer == NULL) + return; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } +} + +static int PrefilterMpmHttpRequestBodyRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmHttpRequestBody *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->base_list_id = mpm_reg->sm_list_base; + SCLogDebug("list_id %d base_list_id %d", list_id, pectx->base_list_id); + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttpRequestBody, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmHttpRequestBodyFree, + mpm_reg->pname); +} + +#ifdef UNITTESTS +#include "detect-engine-alert.h" +#include "tests/detect-http-client-body.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/detect-http-client-body.h b/src/app-layer/http/detect-client-body.h similarity index 100% rename from src/detect-http-client-body.h rename to src/app-layer/http/detect-client-body.h diff --git a/src/app-layer/http/detect-connection.c b/src/app-layer/http/detect-connection.c new file mode 100644 index 000000000000..053aaf5b2fc1 --- /dev/null +++ b/src/app-layer/http/detect-connection.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements the http_connection sticky buffer + */ + +#define KEYWORD_NAME_LEGACY "http_connection" +#define KEYWORD_NAME "http.connection" +#define KEYWORD_DOC "http-keywords.html#http-connection" +#define BUFFER_NAME "http_connection" +#define BUFFER_DESC "http connection header" +#define HEADER_NAME "Connection" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_CONNECTION +#define KEYWORD_TOSERVER 1 +#define KEYWORD_TOCLIENT 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-connection.h" + +void RegisterHttpHeadersConnection(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-connection.h b/src/app-layer/http/detect-connection.h similarity index 100% rename from src/detect-http-connection.h rename to src/app-layer/http/detect-connection.h diff --git a/src/app-layer/http/detect-content-len.c b/src/app-layer/http/detect-content-len.c new file mode 100644 index 000000000000..b0b792268bae --- /dev/null +++ b/src/app-layer/http/detect-content-len.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements http_content_len sticky buffer + */ + +#define KEYWORD_NAME_LEGACY "http_content_len" +#define KEYWORD_NAME "http.content_len" +#define KEYWORD_DOC "http-keywords.html#http-content-len" +#define BUFFER_NAME "http_content_len" +#define BUFFER_DESC "http content length header" +#define HEADER_NAME "Content-Length" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_CONTENT_LEN +#define KEYWORD_TOSERVER 1 +#define KEYWORD_TOCLIENT 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-content-len.h" + +void RegisterHttpHeadersContentLen(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-content-len.h b/src/app-layer/http/detect-content-len.h similarity index 100% rename from src/detect-http-content-len.h rename to src/app-layer/http/detect-content-len.h diff --git a/src/app-layer/http/detect-content-type.c b/src/app-layer/http/detect-content-type.c new file mode 100644 index 000000000000..de283487d449 --- /dev/null +++ b/src/app-layer/http/detect-content-type.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implement http_content_type sticky buffer + */ + +#define KEYWORD_NAME_LEGACY "http_content_type" +#define KEYWORD_NAME "http.content_type" +#define KEYWORD_DOC "http-keywords.html#http-content-type" +#define BUFFER_NAME "http_content_type" +#define BUFFER_DESC "http content type header" +#define HEADER_NAME "Content-Type" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_CONTENT_TYPE +#define KEYWORD_TOSERVER 1 +#define KEYWORD_TOCLIENT 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-content-type.h" + +void RegisterHttpHeadersContentType(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-content-type.h b/src/app-layer/http/detect-content-type.h similarity index 100% rename from src/detect-http-content-type.h rename to src/app-layer/http/detect-content-type.h diff --git a/src/app-layer/http/detect-cookie.c b/src/app-layer/http/detect-cookie.c new file mode 100644 index 000000000000..493bdf54f0cd --- /dev/null +++ b/src/app-layer/http/detect-cookie.c @@ -0,0 +1,274 @@ +/* Copyright (C) 2007-2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Gurvinder Singh + * + * Implements the http_cookie keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/error.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-cookie.h" +#include "stream-tcp.h" + +static int DetectHttpCookieSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectHttpCookieSetupSticky(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectHttpCookieRegisterTests(void); +#endif +static int g_http_cookie_buffer_id = 0; + +static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +/** + * \brief Registration function for keyword: http_cookie + */ +void DetectHttpCookieRegister(void) +{ + /* http_cookie content modifier */ + sigmatch_table[DETECT_AL_HTTP_COOKIE].name = "http_cookie"; + sigmatch_table[DETECT_AL_HTTP_COOKIE].desc = + "content modifier to match only on the HTTP cookie-buffer"; + sigmatch_table[DETECT_AL_HTTP_COOKIE].url = "/rules/http-keywords.html#http-cookie"; + sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_COOKIE].alternative = DETECT_HTTP_COOKIE; + + /* http.cookie sticky buffer */ + sigmatch_table[DETECT_HTTP_COOKIE].name = "http.cookie"; + sigmatch_table[DETECT_HTTP_COOKIE].desc = + "sticky buffer to match on the HTTP Cookie/Set-Cookie buffers"; + sigmatch_table[DETECT_HTTP_COOKIE].url = "/rules/http-keywords.html#http-cookie"; + sigmatch_table[DETECT_HTTP_COOKIE].Setup = DetectHttpCookieSetupSticky; + sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetRequestData); + DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetResponseData); + + DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRequestData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetResponseData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + + DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRequestData2); + DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetResponseData2); + + DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRequestData2, ALPROTO_HTTP2, HTTP2StateDataClient); + DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetResponseData2, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectBufferTypeSetDescriptionByName("http_cookie", "http cookie header"); + + g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); +} + +/** + * \brief this function setups the http_cookie modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, str, DETECT_AL_HTTP_COOKIE, g_http_cookie_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.user_agent keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpCookieSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_cookie_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return NULL; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, "Cookie"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP cookie header not present in this request"); + return NULL; + } + + const uint32_t data_len = bstr_len(h->value); + const uint8_t *data = bstr_ptr(h->value); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return NULL; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, "Set-Cookie"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP cookie header not present in this request"); + return NULL; + } + + const uint32_t data_len = bstr_len(h->value); + const uint8_t *data = bstr_ptr(h->value); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_cookie(txv, STREAM_TOSERVER, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_cookie(txv, STREAM_TOCLIENT, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/******************************** UNITESTS **********************************/ + +#ifdef UNITTESTS +#include "tests/detect-http-cookie.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/app-layer/http/detect-cookie.h b/src/app-layer/http/detect-cookie.h new file mode 100644 index 000000000000..10c1d5be1af8 --- /dev/null +++ b/src/app-layer/http/detect-cookie.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + */ + +#ifndef _DETECT_HTTP_COOKIE_H +#define _DETECT_HTTP_COOKIE_H + +/* prototypes */ +void DetectHttpCookieRegister(void); + +#endif /* _DETECT_HTTP_COOKIE_H */ diff --git a/src/app-layer/http/detect-header-common.c b/src/app-layer/http/detect-header-common.c new file mode 100644 index 000000000000..0b48bda339f5 --- /dev/null +++ b/src/app-layer/http/detect-header-common.c @@ -0,0 +1,112 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-header.h" +#include "stream-tcp.h" + +#include "app-layer/http/detect-header-common.h" + +void *HttpHeaderThreadDataInit(void *data) +{ + HttpHeaderThreadData *td = SCCalloc(1, sizeof(*td)); + if (td != NULL) { + if (data == NULL) { + td->size_step = 512; + } else { + HttpHeaderThreadDataConfig *c = data; + td->size_step = c->size_step; + } + + /* initialize minimal buffers */ + (void)HttpHeaderExpandBuffer(td, &td->buffer, 1); + } + return td; +} + +void HttpHeaderThreadDataFree(void *data) +{ + HttpHeaderThreadData *hdrnames = data; + SCFree(hdrnames->buffer.buffer); + SCFree(hdrnames); +} + +int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, HttpHeaderBuffer *buf, uint32_t size) +{ + size_t extra = td->size_step; + while ((buf->size + extra) < (size + buf->len)) { + extra += td->size_step; + } + SCLogDebug("adding %" PRIuMAX " to the buffer", (uintmax_t)extra); + + uint8_t *new_buffer = SCRealloc(buf->buffer, buf->size + extra); + if (unlikely(new_buffer == NULL)) { + buf->len = 0; + return -1; + } + buf->buffer = new_buffer; + buf->size += extra; + return 0; +} + +HttpHeaderBuffer *HttpHeaderGetBufferSpace(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + const int keyword_id, HttpHeaderThreadData **ret_hdr_td) +{ + *ret_hdr_td = NULL; + + HttpHeaderThreadData *hdr_td = DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, keyword_id); + if (hdr_td == NULL) + return NULL; + *ret_hdr_td = hdr_td; + + HttpHeaderBuffer *buf = &hdr_td->buffer; + buf->len = 0; + return buf; +} diff --git a/src/app-layer/http/detect-header-common.h b/src/app-layer/http/detect-header-common.h new file mode 100644 index 000000000000..f83ad15a2d82 --- /dev/null +++ b/src/app-layer/http/detect-header-common.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_HEADER_COMMON_H__ +#define __DETECT_HTTP_HEADER_COMMON_H__ + +typedef struct HttpHeaderBuffer_ { + uint8_t *buffer; + uint32_t size; /**< buffer size */ + uint32_t len; /**< part of buffer in use */ +} HttpHeaderBuffer; + +typedef struct HttpHeaderThreadConfig_ { + uint16_t size_step; +} HttpHeaderThreadDataConfig; + +typedef struct HttpHeaderThreadData_ { + HttpHeaderBuffer buffer; /**< array of buffers */ + uint16_t size_step; /**< increase size of HttpHeaderBuffer::buffer with this */ +} HttpHeaderThreadData; + +void *HttpHeaderThreadDataInit(void *data); +void HttpHeaderThreadDataFree(void *data); + +HttpHeaderBuffer *HttpHeaderGetBufferSpace(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + const int keyword_id, HttpHeaderThreadData **ret_hdr_td); + +int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, HttpHeaderBuffer *buf, uint32_t size); + +#endif /* __DETECT_HTTP_HEADER_COMMON_H__ */ diff --git a/src/app-layer/http/detect-header-names.c b/src/app-layer/http/detect-header-names.c new file mode 100644 index 000000000000..c2e77cc8e9a3 --- /dev/null +++ b/src/app-layer/http/detect-header-names.c @@ -0,0 +1,253 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_header_names + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/http/detect-header-common.h" +#include "app-layer/http/detect-header-names.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-header.h" +#include "stream-tcp.h" + +#define KEYWORD_NAME "http.header_names" +#define KEYWORD_NAME_LEGACY "http_header_names" +#define KEYWORD_DOC "http-keywords.html#http-header-names" +#define BUFFER_NAME "http_header_names" +#define BUFFER_DESC "http header names" +static int g_buffer_id = 0; +static int g_keyword_thread_id = 0; + +#define BUFFER_SIZE_STEP 256 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP }; + +static uint8_t *GetBufferForTX( + htp_tx_t *tx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint32_t *buffer_len) +{ + *buffer_len = 0; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = + HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } + + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= + HTP_REQUEST_HEADERS) + return NULL; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= + HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + } + if (headers == NULL) + return NULL; + + /* fill the buffer. \r\nName1\r\nName2\r\n\r\n */ + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size = bstr_size(h->name) + 2; // for \r\n + if (i == 0) + size += 2; + if (i + 1 == no_of_headers) + size += 2; + + SCLogDebug("size %" PRIuMAX " + buf->len %u vs buf->size %u", (uintmax_t)size, buf->len, + buf->size); + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; + } + } + + /* start with a \r\n */ + if (i == 0) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + + /* end with an extra \r\n */ + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + } + + *buffer_len = buf->len; + return buf->buffer; +} + +static InspectionBuffer *GetBuffer1ForTX(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t rawdata_len = 0; + uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flow_flags, &rawdata_len); + if (rawdata_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetBuffer2ForTX(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_header_names(txv, flow_flags, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief The setup function for the http.header_names keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int DetectHttpHeaderNamesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + + return 0; +} + +/** + * \brief Registers the keyword handlers for the "http.header_names" keyword. + */ +void DetectHttpHeaderNamesRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].alias = KEYWORD_NAME_LEGACY; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].Setup = DetectHttpHeaderNamesSetup; + + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + /* http1 */ + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetBuffer1ForTX, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetBuffer1ForTX, ALPROTO_HTTP1, HTP_RESPONSE_HEADERS); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); + + /* http2 */ + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataClient); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs( + KEYWORD_NAME, HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); + + SCLogDebug("keyword %s registered. Thread id %d. " + "Buffer %s registered. Buffer id %d", + KEYWORD_NAME, g_keyword_thread_id, BUFFER_NAME, g_buffer_id); +} diff --git a/src/detect-http-header-names.h b/src/app-layer/http/detect-header-names.h similarity index 100% rename from src/detect-http-header-names.h rename to src/app-layer/http/detect-header-names.h diff --git a/src/app-layer/http/detect-header.c b/src/app-layer/http/detect-header.c new file mode 100644 index 000000000000..6b221ba6ff5e --- /dev/null +++ b/src/app-layer/http/detect-header.c @@ -0,0 +1,779 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Pablo Rincon + * + * Implements support for http_header keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "util/debug.h" +#include "util/print.h" +#include "util/memcmp.h" +#include "util/profiling.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-header.h" +#include "app-layer/http/detect-header-common.h" + +static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectHttpHeaderRegisterTests(void); +#endif +static int g_http_header_buffer_id = 0; +static int g_keyword_thread_id = 0; + +#define BUFFER_SIZE_STEP 1024 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP }; + +static uint8_t *GetBufferForTX( + htp_tx_t *tx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint32_t *buffer_len) +{ + *buffer_len = 0; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = + HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } + + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= + HTP_REQUEST_HEADERS) + return NULL; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= + HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + } + if (headers == NULL) + return NULL; + + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size1 = bstr_size(h->name); + size_t size2 = bstr_size(h->value); + + if (flags & STREAM_TOSERVER) { + if (size1 == 6 && SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { + continue; + } + } else { + if (size1 == 10 && SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { + continue; + } + } + + size_t size = size1 + size2 + 4; +#if 0 + if (i + 1 == no_of_headers) + size += 2; +#endif + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; + } + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = ':'; + buf->buffer[buf->len++] = ' '; + memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); + buf->len += bstr_size(h->value); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; +#if 0 // looks like this breaks existing rules + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } +#endif + } + + *buffer_len = buf->len; + return buf->buffer; +} + +static InspectionBuffer *GetBuffer2ForTX(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_headers(txv, flow_flags, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** \internal + * \brief custom inspect function to utilize the cached headers + */ +static uint8_t DetectEngineInspectBufferHttpHeader(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + SCEnter(); + + const int list_id = engine->sm_list; + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + SCLogDebug("setting up inspect buffer %d", list_id); + + /* if prefilter didn't already run, we need to consider transformations */ + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + uint32_t rawdata_len = 0; + uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flags, &rawdata_len); + if (rawdata_len == 0) { + SCLogDebug("no data"); + goto end; + } + /* setup buffer and apply transforms */ + InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + const uint32_t data_len = buffer->inspect_len; + const uint8_t *data = buffer->inspect; + const uint64_t offset = buffer->inspect_offset; + + /* Inspect all the uricontents fetched on each + * transaction at the app layer */ + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)data, data_len, offset, DETECT_CI_FLAGS_SINGLE, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } +end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > + HTP_REQUEST_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > + HTP_RESPONSE_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmHttpHeaderCtx { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmHttpHeaderCtx; + +/** \brief Generic Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterMpmHttpHeader(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmHttpHeaderCtx *ctx = pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + SCLogDebug("running on list %d", ctx->list_id); + + const int list_id = ctx->list_id; + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t rawdata_len = 0; + uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flags, &rawdata_len); + if (rawdata_len == 0) + return; + + /* setup buffer and apply transforms */ + InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); + InspectionBufferApplyTransforms(buffer, ctx->transforms); + } + + const uint32_t data_len = buffer->inspect_len; + const uint8_t *data = buffer->inspect; + + SCLogDebug("mpm'ing buffer:"); + // PrintRawDataFp(stdout, data, data_len); + + if (data != NULL && data_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len); + } +} + +static void PrefilterMpmHttpTrailer(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + htp_tx_t *tx = txv; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && (((flags & STREAM_TOSERVER) && !htud->request_has_trailers) || + ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers))) { + SCReturn; + } + PrefilterMpmHttpHeader(det_ctx, pectx, p, f, txv, idx, _txd, flags); + SCReturn; +} + +static void PrefilterMpmHttpHeaderFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmHttpHeaderRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + SCEnter(); + + /* header */ + PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeader, mpm_reg->app_v2.alproto, + HTP_REQUEST_HEADERS, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + return r; + } + + /* trailer */ + pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailer, mpm_reg->app_v2.alproto, + HTP_REQUEST_TRAILER, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + } + return r; +} + +static int PrefilterMpmHttpHeaderResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + SCEnter(); + + /* header */ + PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeader, mpm_reg->app_v2.alproto, + HTP_RESPONSE_HEADERS, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + return r; + } + + /* trailer */ + pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailer, mpm_reg->app_v2.alproto, + HTP_RESPONSE_TRAILER, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + } + return r; +} + +/** + * \brief The setup function for the http_header keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_HEADER, g_http_header_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.header keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_header_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpHeaderRegister(void) +{ + /* http_header content modifier */ + sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; + sigmatch_table[DETECT_AL_HTTP_HEADER].desc = + "content modifier to match only on the HTTP header-buffer"; + sigmatch_table[DETECT_AL_HTTP_HEADER].url = + "/rules/http-keywords.html#http-header-and-http-raw-header"; + sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_HEADER].alternative = DETECT_HTTP_HEADER; + + /* http.header sticky buffer */ + sigmatch_table[DETECT_HTTP_HEADER].name = "http.header"; + sigmatch_table[DETECT_HTTP_HEADER].desc = + "sticky buffer to match on the normalized HTTP header-buffer"; + sigmatch_table[DETECT_HTTP_HEADER].url = + "/rules/http-keywords.html#http-header-and-http-raw-header"; + sigmatch_table[DETECT_HTTP_HEADER].Setup = DetectHttpHeaderSetupSticky; + sigmatch_table[DETECT_HTTP_HEADER].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_HTTP_HEADER].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferHttpHeader, NULL); + DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOSERVER, 2, + PrefilterMpmHttpHeaderRequestRegister, NULL, ALPROTO_HTTP1, + 0); /* not used, registered twice: HEADERS/TRAILER */ + + DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_HEADERS, DetectEngineInspectBufferHttpHeader, NULL); + DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOCLIENT, 2, + PrefilterMpmHttpHeaderResponseRegister, NULL, ALPROTO_HTTP1, + 0); /* not used, registered twice: HEADERS/TRAILER */ + + DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); + DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); + DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectBufferTypeSetDescriptionByName("http_header", "http headers"); + + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs( + "http_header", HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); +} + +static int g_http_request_header_buffer_id = 0; +static int g_http_response_header_buffer_id = 0; + +static InspectionBuffer *GetHttp2HeaderData(DetectEngineThreadCtx *det_ctx, const uint8_t flags, + const DetectEngineTransforms *transforms, Flow *_f, const struct MpmListIdDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_header(cbdata->txv, flags, cbdata->local_id, &b, &b_len) != 1) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + if (b == NULL || b_len == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, b, b_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static void PrefilterTxHttp2Header(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + + while (1) { + // loop until we get a NULL + + struct MpmListIdDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = + GetHttp2HeaderData(det_ctx, flags, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static uint8_t DetectEngineInspectHttp2Header(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct MpmListIdDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + GetHttp2HeaderData(det_ctx, flags, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int PrefilterMpmHttp2HeaderRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp2Header, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->name); +} + +static InspectionBuffer *GetHttp1HeaderData(DetectEngineThreadCtx *det_ctx, const uint8_t flags, + const DetectEngineTransforms *transforms, Flow *f, const struct MpmListIdDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = + HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } + + htp_tx_t *tx = (htp_tx_t *)cbdata->txv; + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + headers = tx->request_headers; + } else { + headers = tx->response_headers; + } + if (cbdata->local_id < htp_table_size(headers)) { + htp_header_t *h = htp_table_get_index(headers, cbdata->local_id, NULL); + size_t size1 = bstr_size(h->name); + size_t size2 = bstr_size(h->value); + size_t b_len = size1 + 2 + size2; + if (b_len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, b_len) != 0) { + return NULL; + } + } + memcpy(buf->buffer, bstr_ptr(h->name), bstr_size(h->name)); + buf->buffer[size1] = ':'; + buf->buffer[size1 + 1] = ' '; + memcpy(buf->buffer + size1 + 2, bstr_ptr(h->value), bstr_size(h->value)); + buf->len = b_len; + } else { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + if (buf->len == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, buf->buffer, buf->len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static void PrefilterTxHttp1Header(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + + while (1) { + // loop until we get a NULL + + struct MpmListIdDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = + GetHttp1HeaderData(det_ctx, flags, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static int PrefilterMpmHttp1HeaderRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp1Header, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->name); +} + +static uint8_t DetectEngineInspectHttp1Header(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct MpmListIdDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + GetHttp1HeaderData(det_ctx, flags, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int DetectHTTPRequestHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_request_header_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) != 0) + return -1; + + return 0; +} + +void DetectHttpRequestHeaderRegister(void) +{ + sigmatch_table[DETECT_HTTP_REQUEST_HEADER].name = "http.request_header"; + sigmatch_table[DETECT_HTTP_REQUEST_HEADER].desc = + "sticky buffer to match on only one HTTP header name and value"; + sigmatch_table[DETECT_HTTP_REQUEST_HEADER].url = "/rules/http-keywords.html#request_header"; + sigmatch_table[DETECT_HTTP_REQUEST_HEADER].Setup = DetectHTTPRequestHeaderSetup; + sigmatch_table[DETECT_HTTP_REQUEST_HEADER].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerMpmRegister2("http_request_header", SIG_FLAG_TOSERVER, 2, + PrefilterMpmHttp2HeaderRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen); + DetectAppLayerInspectEngineRegister2("http_request_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateOpen, DetectEngineInspectHttp2Header, NULL); + DetectAppLayerMpmRegister2("http_request_header", SIG_FLAG_TOSERVER, 2, + PrefilterMpmHttp1HeaderRegister, NULL, ALPROTO_HTTP1, 0); + DetectAppLayerInspectEngineRegister2("http_request_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectHttp1Header, NULL); + + DetectBufferTypeSetDescriptionByName("http_request_header", "HTTP header name and value"); + g_http_request_header_buffer_id = DetectBufferTypeGetByName("http_request_header"); + DetectBufferTypeSupportsMultiInstance("http_request_header"); +} + +static int DetectHTTPResponseHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_response_header_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) != 0) + return -1; + + return 0; +} + +void DetectHttpResponseHeaderRegister(void) +{ + sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].name = "http.response_header"; + sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].desc = + "sticky buffer to match on only one HTTP header name and value"; + sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].url = "/rules/http2-keywords.html#response_header"; + sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].Setup = DetectHTTPResponseHeaderSetup; + sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerMpmRegister2("http_response_header", SIG_FLAG_TOCLIENT, 2, + PrefilterMpmHttp2HeaderRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen); + DetectAppLayerInspectEngineRegister2("http_response_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateOpen, DetectEngineInspectHttp2Header, NULL); + DetectAppLayerMpmRegister2("http_response_header", SIG_FLAG_TOCLIENT, 2, + PrefilterMpmHttp1HeaderRegister, NULL, ALPROTO_HTTP1, 0); + DetectAppLayerInspectEngineRegister2("http_response_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_HEADERS, DetectEngineInspectHttp1Header, NULL); + + DetectBufferTypeSetDescriptionByName("http_response_header", "HTTP header name and value"); + g_http_response_header_buffer_id = DetectBufferTypeGetByName("http_response_header"); + DetectBufferTypeSupportsMultiInstance("http_response_header"); +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS +#include "tests/detect-http-header.c" +#endif + +/** + * @} + */ diff --git a/src/detect-http-header.h b/src/app-layer/http/detect-header.h similarity index 100% rename from src/detect-http-header.h rename to src/app-layer/http/detect-header.h diff --git a/src/app-layer/http/detect-headers-stub.h b/src/app-layer/http/detect-headers-stub.h new file mode 100644 index 000000000000..7e7dd58c464f --- /dev/null +++ b/src/app-layer/http/detect-headers-stub.h @@ -0,0 +1,212 @@ +/* Copyright (C) 2007-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * Stub for per HTTP header detection keyword. Meant to be included into + * a C file. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +#include "suricata-common.h" +#include "flow.h" + +#include + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" + +#include "util/debug.h" +#include "rust.h" + +static int g_buffer_id = 0; + +#ifdef KEYWORD_TOSERVER +static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return NULL; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, HEADER_NAME); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP %s header not present in this request", HEADER_NAME); + return NULL; + } + + const uint32_t data_len = bstr_len(h->value); + const uint8_t *data = bstr_ptr(h->value); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_header_value(txv, STREAM_TOSERVER, HEADER_NAME, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#endif +#ifdef KEYWORD_TOCLIENT +static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return NULL; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, HEADER_NAME); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP %s header not present in this request", HEADER_NAME); + return NULL; + } + + const uint32_t data_len = bstr_len(h->value); + const uint8_t *data = bstr_ptr(h->value); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_header_value(txv, STREAM_TOCLIENT, HEADER_NAME, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} +#endif + +/** + * \brief this function setup the http.header keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpHeadersSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + + return 0; +} + +static void DetectHttpHeadersRegisterStub(void) +{ + sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; +#ifdef KEYWORD_NAME_LEGACY + sigmatch_table[KEYWORD_ID].alias = KEYWORD_NAME_LEGACY; +#endif + sigmatch_table[KEYWORD_ID].desc = KEYWORD_NAME " sticky buffer for the " BUFFER_DESC; + sigmatch_table[KEYWORD_ID].url = "/rules/" KEYWORD_DOC; + sigmatch_table[KEYWORD_ID].Setup = DetectHttpHeadersSetupSticky; + sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + +#ifdef KEYWORD_TOSERVER + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRequestData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRequestData2, ALPROTO_HTTP2, HTTP2StateDataClient); +#endif +#ifdef KEYWORD_TOCLIENT + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetResponseData, ALPROTO_HTTP1, HTP_RESPONSE_HEADERS); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetResponseData2, ALPROTO_HTTP2, HTTP2StateDataServer); +#endif +#ifdef KEYWORD_TOSERVER + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetRequestData); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRequestData2); +#endif +#ifdef KEYWORD_TOCLIENT + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_HEADERS, DetectEngineInspectBufferGeneric, GetResponseData); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetResponseData2); +#endif + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/app-layer/http/detect-headers.c b/src/app-layer/http/detect-headers.c new file mode 100644 index 000000000000..52dec2dcb35e --- /dev/null +++ b/src/app-layer/http/detect-headers.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "app-layer/http/detect-accept.h" +#include "app-layer/http/detect-accept-enc.h" +#include "app-layer/http/detect-accept-lang.h" +#include "app-layer/http/detect-connection.h" +#include "app-layer/http/detect-content-len.h" +#include "app-layer/http/detect-content-type.h" +#include "app-layer/http/detect-location.h" +#include "app-layer/http/detect-server.h" +#include "app-layer/http/detect-referer.h" +#include "app-layer/http/detect-headers.h" + +void DetectHttpHeadersRegister(void) +{ + RegisterHttpHeadersAccept(); + RegisterHttpHeadersAcceptEnc(); + RegisterHttpHeadersAcceptLang(); + RegisterHttpHeadersReferer(); + RegisterHttpHeadersConnection(); + RegisterHttpHeadersContentLen(); + RegisterHttpHeadersContentType(); + RegisterHttpHeadersServer(); + RegisterHttpHeadersLocation(); +} diff --git a/src/detect-http-headers.h b/src/app-layer/http/detect-headers.h similarity index 100% rename from src/detect-http-headers.h rename to src/app-layer/http/detect-headers.h diff --git a/src/app-layer/http/detect-host.c b/src/app-layer/http/detect-host.c new file mode 100644 index 000000000000..6e586937e5b5 --- /dev/null +++ b/src/app-layer/http/detect-host.c @@ -0,0 +1,379 @@ +/* Copyright (C) 2007-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Implements support for the http_host keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "stream-tcp.h" +#include "app-layer/http/detect-host.h" + +static int DetectHttpHHSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectHttpHHRegisterTests(void); +#endif +static bool DetectHttpHostValidateCallback(const Signature *s, const char **sigerror); +static int DetectHttpHostSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, const char *); +static int g_http_raw_host_buffer_id = 0; +static int DetectHttpHostRawSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); +static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetRawData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static int g_http_host_buffer_id = 0; + +/** + * \brief Registers the keyword handlers for the "http_host" keyword. + */ +void DetectHttpHHRegister(void) +{ + /* http_host content modifier */ + sigmatch_table[DETECT_AL_HTTP_HOST].name = "http_host"; + sigmatch_table[DETECT_AL_HTTP_HOST].desc = "content modifier to match on the HTTP hostname"; + sigmatch_table[DETECT_AL_HTTP_HOST].url = + "/rules/http-keywords.html#http-host-and-http-raw-host"; + sigmatch_table[DETECT_AL_HTTP_HOST].Setup = DetectHttpHHSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_HOST].RegisterTests = DetectHttpHHRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_HOST].alternative = DETECT_HTTP_HOST; + + /* http.host sticky buffer */ + sigmatch_table[DETECT_HTTP_HOST].name = "http.host"; + sigmatch_table[DETECT_HTTP_HOST].desc = "sticky buffer to match on the HTTP Host buffer"; + sigmatch_table[DETECT_HTTP_HOST].url = "/rules/http-keywords.html#http-host-and-http-raw-host"; + sigmatch_table[DETECT_HTTP_HOST].Setup = DetectHttpHostSetup; + sigmatch_table[DETECT_HTTP_HOST].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_host", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + + DetectAppLayerInspectEngineRegister2("http_host", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeRegisterValidateCallback("http_host", DetectHttpHostValidateCallback); + + DetectBufferTypeSetDescriptionByName("http_host", "http host"); + + g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); + + /* http_raw_host content modifier */ + sigmatch_table[DETECT_AL_HTTP_RAW_HOST].name = "http_raw_host"; + sigmatch_table[DETECT_AL_HTTP_RAW_HOST].desc = "content modifier to match on the HTTP host " + "header or the raw hostname from the HTTP uri"; + sigmatch_table[DETECT_AL_HTTP_RAW_HOST].url = + "/rules/http-keywords.html#http-host-and-http-raw-host"; + sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Setup = DetectHttpHRHSetup; + sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_RAW_HOST].alternative = DETECT_HTTP_HOST_RAW; + + /* http.host sticky buffer */ + sigmatch_table[DETECT_HTTP_HOST_RAW].name = "http.host.raw"; + sigmatch_table[DETECT_HTTP_HOST_RAW].desc = + "sticky buffer to match on the HTTP host header or the raw hostname from the HTTP uri"; + sigmatch_table[DETECT_HTTP_HOST_RAW].url = + "/rules/http-keywords.html#http-host-and-http-raw-host"; + sigmatch_table[DETECT_HTTP_HOST_RAW].Setup = DetectHttpHostRawSetupSticky; + sigmatch_table[DETECT_HTTP_HOST_RAW].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_raw_host", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetRawData); + + DetectAppLayerMpmRegister2("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRawData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + + DetectAppLayerInspectEngineRegister2("http_raw_host", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRawData2); + + DetectAppLayerMpmRegister2("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRawData2, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeSetDescriptionByName("http_raw_host", "http raw host header"); + + g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); +} + +/** + * \brief The setup function for the http_host keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectHttpHHSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_HOST, g_http_host_buffer_id, ALPROTO_HTTP1); +} + +static bool DetectHttpHostValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_http_host_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type == DETECT_CONTENT) { + DetectContentData *cd = (DetectContentData *)sm->ctx; + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = "http.host keyword " + "specified along with \"nocase\". " + "The hostname buffer is normalized " + "to lowercase, specifying " + "nocase is redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } else { + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) + break; + } + if (u != cd->content_len) { + *sigerror = "A pattern with " + "uppercase characters detected for http.host. " + "The hostname buffer is normalized to lowercase, " + "please specify a lowercase pattern."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + } + } + } + } + + return true; +} + +/** + * \brief this function setup the http.host keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpHostSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_host_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_hostname == NULL) + return NULL; + + const uint32_t data_len = bstr_len(tx->request_hostname); + const uint8_t *data = bstr_ptr(tx->request_hostname); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_host_norm(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetRawData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_host(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief The setup function for the http_raw_host keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpHRHSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_RAW_HOST, g_http_raw_host_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.host keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpHostRawSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_host_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + const uint8_t *data = NULL; + uint32_t data_len = 0; + + if (tx->parsed_uri == NULL || tx->parsed_uri->hostname == NULL) { + if (tx->request_headers == NULL) + return NULL; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, "Host"); + if (h == NULL || h->value == NULL) + return NULL; + + data = (const uint8_t *)bstr_ptr(h->value); + data_len = bstr_len(h->value); + } else { + data = (const uint8_t *)bstr_ptr(tx->parsed_uri->hostname); + data_len = bstr_len(tx->parsed_uri->hostname); + } + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS +#include "tests/detect-http-host.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/detect-http-host.h b/src/app-layer/http/detect-host.h similarity index 100% rename from src/detect-http-host.h rename to src/app-layer/http/detect-host.h diff --git a/src/app-layer/http/detect-location.c b/src/app-layer/http/detect-location.c new file mode 100644 index 000000000000..6320c42c73a6 --- /dev/null +++ b/src/app-layer/http/detect-location.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2007-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Jeff Lucovsky + * + * Implements http.location sticky buffer + * + * "Location" is an HTTP response-header field used to redirect the recipient to + * a location other than the Request-URI for request completion. + */ + +#define KEYWORD_NAME "http.location" +#define KEYWORD_DOC "http-keywords.html#http-location" +#define BUFFER_NAME "http.location" +#define BUFFER_DESC "http location header" +#define HEADER_NAME "Location" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_LOCATION +#define KEYWORD_TOCLIENT 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-location.h" + +void RegisterHttpHeadersLocation(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-location.h b/src/app-layer/http/detect-location.h similarity index 100% rename from src/detect-http-location.h rename to src/app-layer/http/detect-location.h diff --git a/src/app-layer/http/detect-method.c b/src/app-layer/http/detect-method.c new file mode 100644 index 000000000000..c0e52404b798 --- /dev/null +++ b/src/app-layer/http/detect-method.c @@ -0,0 +1,245 @@ +/* Copyright (C) 2007-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Brian Rectanus + * + * Implements the http_method keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-method.h" +#include "stream-tcp.h" + +static int g_http_method_buffer_id = 0; +static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectHttpMethodSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); +#ifdef UNITTESTS +void DetectHttpMethodRegisterTests(void); +#endif +void DetectHttpMethodFree(void *); +static bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); + +/** + * \brief Registration function for keyword: http_method + */ +void DetectHttpMethodRegister(void) +{ + /* http_method content modifier */ + sigmatch_table[DETECT_AL_HTTP_METHOD].name = "http_method"; + sigmatch_table[DETECT_AL_HTTP_METHOD].desc = + "content modifier to match only on the HTTP method-buffer"; + sigmatch_table[DETECT_AL_HTTP_METHOD].url = "/rules/http-keywords.html#http-method"; + sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_METHOD].alternative = DETECT_HTTP_METHOD; + + /* http.method sticky buffer */ + sigmatch_table[DETECT_HTTP_METHOD].name = "http.method"; + sigmatch_table[DETECT_HTTP_METHOD].desc = + "sticky buffer to match specifically and only on the HTTP method buffer"; + sigmatch_table[DETECT_HTTP_METHOD].url = "/rules/http-keywords.html#http-method"; + sigmatch_table[DETECT_HTTP_METHOD].Setup = DetectHttpMethodSetupSticky; + sigmatch_table[DETECT_HTTP_METHOD].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_method", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_method", SIG_FLAG_TOSERVER, 4, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); + + DetectAppLayerInspectEngineRegister2("http_method", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_method", SIG_FLAG_TOSERVER, 4, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeSetDescriptionByName("http_method", "http request method"); + + DetectBufferTypeRegisterValidateCallback("http_method", DetectHttpMethodValidateCallback); + + g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); + + SCLogDebug("registering http_method rule option"); +} + +/** + * \brief This function is used to add the parsed "http_method" option + * into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param str Pointer to the user provided option string. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectHttpMethodSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, str, DETECT_AL_HTTP_METHOD, g_http_method_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.method keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpMethodSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_method_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + + return 0; +} + +/** + * \retval 1 valid + * \retval 0 invalid + */ +static bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_http_method_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + const DetectContentData *cd = (const DetectContentData *)sm->ctx; + if (cd->content && cd->content_len) { + if (cd->content[cd->content_len - 1] == 0x20) { + *sigerror = "http_method pattern with trailing space"; + SCLogError("%s", *sigerror); + return false; + } else if (cd->content[0] == 0x20) { + *sigerror = "http_method pattern with leading space"; + SCLogError("%s", *sigerror); + return false; + } else if (cd->content[cd->content_len - 1] == 0x09) { + *sigerror = "http_method pattern with trailing tab"; + SCLogError("%s", *sigerror); + return false; + } else if (cd->content[0] == 0x09) { + *sigerror = "http_method pattern with leading tab"; + SCLogError("%s", *sigerror); + return false; + } + } + } + } + return true; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_method == NULL) + return NULL; + + const uint32_t data_len = bstr_len(tx->request_method); + const uint8_t *data = bstr_ptr(tx->request_method); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_method(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS +#include "tests/detect-http-method.c" +#endif + +/** + * @} + */ diff --git a/src/app-layer/http/detect-method.h b/src/app-layer/http/detect-method.h new file mode 100644 index 000000000000..afe949a1d8ae --- /dev/null +++ b/src/app-layer/http/detect-method.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Brian Rectanus + */ + +#ifndef __DETECT_HTTP_METHOD_H__ +#define __DETECT_HTTP_METHOD_H__ + +/* prototypes */ +void DetectHttpMethodRegister(void); + +#endif /* __DETECT_HTTP_METHOD_H__ */ diff --git a/src/app-layer/http/detect-protocol.c b/src/app-layer/http/detect-protocol.c new file mode 100644 index 000000000000..7563903bb779 --- /dev/null +++ b/src/app-layer/http/detect-protocol.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_protocol sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/http/detect-header-common.h" +#include "app-layer/http/detect-protocol.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-header.h" +#include "stream-tcp.h" + +#define KEYWORD_NAME "http.protocol" +#define KEYWORD_NAME_LEGACY "http_protocol" +#define KEYWORD_DOC "http-keywords.html#http-protocol" +#define BUFFER_NAME "http_protocol" +#define BUFFER_DESC "http protocol" +static int g_buffer_id = 0; + +static int DetectHttpProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + bstr *str = NULL; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (flow_flags & STREAM_TOSERVER) + str = tx->request_protocol; + else if (flow_flags & STREAM_TOCLIENT) + str = tx->response_protocol; + + if (str == NULL) { + SCLogDebug("HTTP protocol not set"); + return NULL; + } + + uint32_t data_len = bstr_size(str); + uint8_t *data = bstr_ptr(str); + if (data == NULL || data_len == 0) { + SCLogDebug("HTTP protocol not present"); + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + InspectionBufferSetup( + det_ctx, list_id, buffer, (const uint8_t *)"HTTP/2", strlen("HTTP/2")); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief Registers the keyword handlers for the "http.protocol" keyword. + */ +void DetectHttpProtocolRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].alias = KEYWORD_NAME_LEGACY; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].Setup = DetectHttpProtocolSetup; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-http-protocol.h b/src/app-layer/http/detect-protocol.h similarity index 100% rename from src/detect-http-protocol.h rename to src/app-layer/http/detect-protocol.h diff --git a/src/app-layer/http/detect-raw-header.c b/src/app-layer/http/detect-raw-header.c new file mode 100644 index 000000000000..cf5409c3f451 --- /dev/null +++ b/src/app-layer/http/detect-raw-header.c @@ -0,0 +1,374 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Pablo Rincon + * + * Implements support for http_raw_header keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/profiling.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-raw-header.h" + +static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); +#ifdef UNITTESTS +static void DetectHttpRawHeaderRegisterTests(void); +#endif +static bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror); +static int g_http_raw_header_buffer_id = 0; +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id); + +static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); +static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); + +/** + * \brief Registers the keyword handlers for the "http_raw_header" keyword. + */ +void DetectHttpRawHeaderRegister(void) +{ + /* http_raw_header content modifier */ + sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].name = "http_raw_header"; + sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].desc = + "content modifier to match the raw HTTP header buffer"; + sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].url = + "/rules/http-keywords.html#http-header-and-http-raw-header"; + sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].RegisterTests = DetectHttpRawHeaderRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].alternative = DETECT_HTTP_RAW_HEADER; + + /* http.header.raw sticky buffer */ + sigmatch_table[DETECT_HTTP_RAW_HEADER].name = "http.header.raw"; + sigmatch_table[DETECT_HTTP_RAW_HEADER].desc = + "sticky buffer to match the raw HTTP header buffer"; + sigmatch_table[DETECT_HTTP_RAW_HEADER].url = + "/rules/http-keywords.html#http-header-and-http-raw-header"; + sigmatch_table[DETECT_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetupSticky; + sigmatch_table[DETECT_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOSERVER, 2, + PrefilterMpmHttpHeaderRawRequestRegister, NULL, ALPROTO_HTTP1, + 0); /* progress handled in register */ + DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOCLIENT, 2, + PrefilterMpmHttpHeaderRawResponseRegister, NULL, ALPROTO_HTTP1, + 0); /* progress handled in register */ + + DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectBufferTypeSetDescriptionByName("http_raw_header", "raw http headers"); + + DetectBufferTypeRegisterValidateCallback( + "http_raw_header", DetectHttpRawHeaderValidateCallback); + + g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); +} + +/** + * \brief The setup function for the http_raw_header keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_RAW_HEADER, g_http_raw_header_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.header.raw keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_header_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror) +{ + if ((s->flags & (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) == + (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) { + *sigerror = "http_raw_header signature " + "without a flow direction. Use flow:to_server for " + "inspecting request headers or flow:to_client for " + "inspecting response headers."; + + SCLogError("%s", *sigerror); + SCReturnInt(false); + } + return true; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + if (tx_ud == NULL) + return NULL; + + const bool ts = ((flow_flags & STREAM_TOSERVER) != 0); + const uint8_t *data = ts ? tx_ud->request_headers_raw : tx_ud->response_headers_raw; + if (data == NULL) + return NULL; + const uint32_t data_len = + ts ? tx_ud->request_headers_raw_len : tx_ud->response_headers_raw_len; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_headers_raw(txv, flow_flags, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +typedef struct PrefilterMpmHttpHeaderRawCtx { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmHttpHeaderRawCtx; + +/** \brief Generic Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterMpmHttpHeaderRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmHttpHeaderRawCtx *ctx = pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + SCLogDebug("running on list %d", ctx->list_id); + + const int list_id = ctx->list_id; + + InspectionBuffer *buffer = GetData(det_ctx, ctx->transforms, f, flags, txv, list_id); + if (buffer == NULL) + return; + + const uint32_t data_len = buffer->inspect_len; + const uint8_t *data = buffer->inspect; + + SCLogDebug("mpm'ing buffer:"); + // PrintRawDataFp(stdout, data, data_len); + + if (data != NULL && data_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len); + } +} + +static void PrefilterMpmHttpTrailerRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + htp_tx_t *tx = txv; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && (((flags & STREAM_TOSERVER) && !htud->request_has_trailers) || + ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers))) { + SCReturn; + } + PrefilterMpmHttpHeaderRaw(det_ctx, pectx, p, f, txv, idx, _txd, flags); + SCReturn; +} + +static void PrefilterMpmHttpHeaderRawFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + SCEnter(); + + /* header */ + PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, mpm_reg->app_v2.alproto, + HTP_REQUEST_HEADERS + 1, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + return r; + } + + /* trailer */ + pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, mpm_reg->app_v2.alproto, + HTP_REQUEST_TRAILER + 1, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + } + return r; +} + +static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + SCEnter(); + + /* header */ + PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, mpm_reg->app_v2.alproto, + HTP_RESPONSE_HEADERS, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + return r; + } + + /* trailer */ + pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, mpm_reg->app_v2.alproto, + HTP_RESPONSE_TRAILER, pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); + if (r != 0) { + SCFree(pectx); + } + return r; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS +#include "tests/detect-http-raw-header.c" +#endif + +/** + * @} + */ diff --git a/src/detect-http-raw-header.h b/src/app-layer/http/detect-raw-header.h similarity index 100% rename from src/detect-http-raw-header.h rename to src/app-layer/http/detect-raw-header.h diff --git a/src/app-layer/http/detect-referer.c b/src/app-layer/http/detect-referer.c new file mode 100644 index 000000000000..9c1864616324 --- /dev/null +++ b/src/app-layer/http/detect-referer.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_referer sticky buffer + */ + +#define KEYWORD_NAME_LEGACY "http_referer" +#define KEYWORD_NAME "http.referer" +#define KEYWORD_DOC "http-keywords.html#http-referer" +#define BUFFER_NAME "http_referer" +#define BUFFER_DESC "http referer header" +#define HEADER_NAME "Referer" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_REFERER +#define KEYWORD_TOSERVER 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-referer.h" + +void RegisterHttpHeadersReferer(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-referer.h b/src/app-layer/http/detect-referer.h similarity index 100% rename from src/detect-http-referer.h rename to src/app-layer/http/detect-referer.h diff --git a/src/app-layer/http/detect-request-line.c b/src/app-layer/http/detect-request-line.c new file mode 100644 index 000000000000..7a6dcb585384 --- /dev/null +++ b/src/app-layer/http/detect-request-line.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support for the http_request_line keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "stream-tcp.h" +#include "app-layer/http/detect-request-line.h" + +static int DetectHttpRequestLineSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectHttpRequestLineRegisterTests(void); +#endif +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static int g_http_request_line_buffer_id = 0; + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_request_line(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief Registers the keyword handlers for the "http_request_line" keyword. + */ +void DetectHttpRequestLineRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].name = "http.request_line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].alias = "http_request_line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].desc = + "sticky buffer to match on the HTTP request line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].url = "/rules/http-keywords.html#http-request-line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Setup = DetectHttpRequestLineSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].RegisterTests = DetectHttpRequestLineRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_request_line", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_request_line", SIG_FLAG_TOSERVER, 2, + PrefilterGenericMpmRegister, GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); + + DetectAppLayerInspectEngineRegister2("http_request_line", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + DetectAppLayerMpmRegister2("http_request_line", SIG_FLAG_TOSERVER, 2, + PrefilterGenericMpmRegister, GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeSetDescriptionByName("http_request_line", "http request line"); + + g_http_request_line_buffer_id = DetectBufferTypeGetByName("http_request_line"); +} + +/** + * \brief The setup function for the http_request_line keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectHttpRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_request_line_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + if (unlikely(tx->request_line == NULL)) { + return NULL; + } + const uint32_t data_len = bstr_len(tx->request_line); + const uint8_t *data = bstr_ptr(tx->request_line); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containing a http_request_line is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpRequestLineTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(http_request_line; content:\"GET /\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +static void DetectHttpRequestLineRegisterTests(void) +{ + UtRegisterTest("DetectHttpRequestLineTest01", DetectHttpRequestLineTest01); +} +#endif /* UNITTESTS */ +/** + * @} + */ diff --git a/src/detect-http-request-line.h b/src/app-layer/http/detect-request-line.h similarity index 100% rename from src/detect-http-request-line.h rename to src/app-layer/http/detect-request-line.h diff --git a/src/app-layer/http/detect-response-line.c b/src/app-layer/http/detect-response-line.c new file mode 100644 index 000000000000..bc30d43a45c4 --- /dev/null +++ b/src/app-layer/http/detect-response-line.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support for the http_response_line keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "stream-tcp.h" +#include "app-layer/http/detect-response-line.h" + +static int DetectHttpResponseLineSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectHttpResponseLineRegisterTests(void); +#endif +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static int g_http_response_line_id = 0; + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_response_line(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief Registers the keyword handlers for the "http_response_line" keyword. + */ +void DetectHttpResponseLineRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].name = "http.response_line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].alias = "http_response_line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].desc = + "content modifier to match only on the HTTP response line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].url = + "/rules/http-keywords.html#http-response-line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Setup = DetectHttpResponseLineSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].RegisterTests = + DetectHttpResponseLineRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_response_line", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_response_line", SIG_FLAG_TOCLIENT, 2, + PrefilterGenericMpmRegister, GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); + + DetectAppLayerInspectEngineRegister2("http_response_line", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); + DetectAppLayerMpmRegister2("http_response_line", SIG_FLAG_TOCLIENT, 2, + PrefilterGenericMpmRegister, GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectBufferTypeSetDescriptionByName("http_response_line", "http response line"); + + g_http_response_line_id = DetectBufferTypeGetByName("http_response_line"); +} + +/** + * \brief The setup function for the http_response_line keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectHttpResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_response_line_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + if (unlikely(tx->response_line == NULL)) { + return NULL; + } + const uint32_t data_len = bstr_len(tx->response_line); + const uint8_t *data = bstr_ptr(tx->response_line); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containing a http_response_line is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpResponseLineTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(http_response_line; content:\"200 OK\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +void DetectHttpResponseLineRegisterTests(void) +{ + UtRegisterTest("DetectHttpResponseLineTest01", DetectHttpResponseLineTest01); +} +#endif /* UNITTESTS */ +/** + * @} + */ diff --git a/src/detect-http-response-line.h b/src/app-layer/http/detect-response-line.h similarity index 100% rename from src/detect-http-response-line.h rename to src/app-layer/http/detect-response-line.h diff --git a/src/app-layer/http/detect-server-body.c b/src/app-layer/http/detect-server-body.c new file mode 100644 index 000000000000..34803dad066a --- /dev/null +++ b/src/app-layer/http/detect-server-body.c @@ -0,0 +1,139 @@ +/* Copyright (C) 2007-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Anoop Saldanha + * \author Victor Julien + * + * Implements support for the http_server_body keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" + +#include "flow.h" +#include "flow-util.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/profiling.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-server-body.h" +#include "stream-tcp.h" + +static int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, const char *); +static int DetectHttpServerBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); +#ifdef UNITTESTS +static void DetectHttpServerBodyRegisterTests(void); +#endif +static int g_buffer_id = 0; + +/** + * \brief Registers the keyword handlers for the "http_server_body" keyword. + */ +void DetectHttpServerBodyRegister(void) +{ + /* http_server_body content modifier */ + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].name = "http_server_body"; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].desc = + "content modifier to match on the HTTP response-body"; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = "/rules/http-keywords.html#http-server-body"; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].alternative = DETECT_HTTP_RESPONSE_BODY; + + /* http.request_body sticky buffer */ + sigmatch_table[DETECT_HTTP_RESPONSE_BODY].name = "http.response_body"; + sigmatch_table[DETECT_HTTP_RESPONSE_BODY].desc = + "sticky buffer to match the HTTP response body buffer"; + sigmatch_table[DETECT_HTTP_RESPONSE_BODY].url = "/rules/http-keywords.html#http-server-body"; + sigmatch_table[DETECT_HTTP_RESPONSE_BODY].Setup = DetectHttpServerBodySetupSticky; + sigmatch_table[DETECT_HTTP_RESPONSE_BODY].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_HTTP_RESPONSE_BODY].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + g_buffer_id = DetectBufferTypeRegister("file_data"); +} + +/** + * \brief The setup function for the http_server_body keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_SERVER_BODY, g_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.response_body keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpServerBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS +#include "tests/detect-http-server-body.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/detect-http-server-body.h b/src/app-layer/http/detect-server-body.h similarity index 100% rename from src/detect-http-server-body.h rename to src/app-layer/http/detect-server-body.h diff --git a/src/app-layer/http/detect-server.c b/src/app-layer/http/detect-server.c new file mode 100644 index 000000000000..9c6839c46052 --- /dev/null +++ b/src/app-layer/http/detect-server.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2007-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Jeff Lucovsky + * + * Implements http.server sticky buffer + * + * "Server" is an HTTP response-header field containing information about the software + * used by the origin server to handle the request. + */ + +#define KEYWORD_NAME "http.server" +#define KEYWORD_DOC "http-keywords.html#http-server" +#define BUFFER_NAME "http.server" +#define BUFFER_DESC "http server header" +#define HEADER_NAME "Server" +#define KEYWORD_ID DETECT_AL_HTTP_HEADER_SERVER +#define KEYWORD_TOCLIENT 1 + +#include "app-layer/http/detect-headers-stub.h" +#include "app-layer/http/detect-server.h" + +void RegisterHttpHeadersServer(void) +{ + DetectHttpHeadersRegisterStub(); +} diff --git a/src/detect-http-server.h b/src/app-layer/http/detect-server.h similarity index 100% rename from src/detect-http-server.h rename to src/app-layer/http/detect-server.h diff --git a/src/app-layer/http/detect-start.c b/src/app-layer/http/detect-start.c new file mode 100644 index 000000000000..5837b4fd6042 --- /dev/null +++ b/src/app-layer/http/detect-start.c @@ -0,0 +1,211 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements http_start + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/http/detect-header-common.h" +#include "app-layer/http/detect-start.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-header.h" +#include "stream-tcp.h" + +#define KEYWORD_NAME "http.start" +#define KEYWORD_NAME_LEGACY "http_start" +#define KEYWORD_DOC "http-keywords.html#http-start" +#define BUFFER_NAME "http_start" +#define BUFFER_DESC "http start: request/response line + headers" +static int g_buffer_id = 0; +static int g_keyword_thread_id = 0; + +#define BUFFER_SIZE_STEP 2048 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP }; + +static uint8_t *GetBufferForTX( + htp_tx_t *tx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint32_t *buffer_len) +{ + *buffer_len = 0; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = + HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } + + bstr *line = NULL; + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= + HTP_REQUEST_HEADERS) + return NULL; + line = tx->request_line; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= + HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + line = tx->response_line; + } + if (line == NULL || headers == NULL) + return NULL; + + size_t line_size = bstr_len(line) + 2; + if (line_size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, line_size) != 0) { + return NULL; + } + } + memcpy(buf->buffer + buf->len, bstr_ptr(line), bstr_size(line)); + buf->len += bstr_size(line); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size1 = bstr_size(h->name); + size_t size2 = bstr_size(h->value); + size_t size = size1 + size2 + 4; + if (i + 1 == no_of_headers) + size += 2; + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; + } + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = ':'; + buf->buffer[buf->len++] = ' '; + memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); + buf->len += bstr_size(h->value); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + } + + *buffer_len = buf->len; + return buf->buffer; +} + +static InspectionBuffer *GetBuffer1ForTX(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t rawdata_len = 0; + uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flow_flags, &rawdata_len); + if (rawdata_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static int DetectHttpStartSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP1) < 0) + return -1; + + return 0; +} + +/** + * \brief Registers the keyword handlers for the "http_start" keyword. + */ +void DetectHttpStartRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_START].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_START].alias = KEYWORD_NAME_LEGACY; + sigmatch_table[DETECT_AL_HTTP_START].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_START].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_START].Setup = DetectHttpStartSetup; + sigmatch_table[DETECT_AL_HTTP_START].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetBuffer1ForTX, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetBuffer1ForTX, ALPROTO_HTTP1, HTP_RESPONSE_HEADERS); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs( + KEYWORD_NAME, HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); + + SCLogDebug("keyword %s registered. Thread id %d. " + "Buffer %s registered. Buffer id %d", + KEYWORD_NAME, g_keyword_thread_id, BUFFER_NAME, g_buffer_id); +} diff --git a/src/detect-http-start.h b/src/app-layer/http/detect-start.h similarity index 100% rename from src/detect-http-start.h rename to src/app-layer/http/detect-start.h diff --git a/src/app-layer/http/detect-stat-code.c b/src/app-layer/http/detect-stat-code.c new file mode 100644 index 000000000000..d4704e6ef5ea --- /dev/null +++ b/src/app-layer/http/detect-stat-code.c @@ -0,0 +1,207 @@ +/* Copyright (C) 2007-2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Gurvinder Singh + * \author Anoop Saldanha + * + * Implements the http_stat_code keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/error.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-stat-code.h" +#include "stream-tcp-private.h" +#include "stream-tcp.h" + +static int DetectHttpStatCodeSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectHttpStatCodeSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); +#ifdef UNITTESTS +static void DetectHttpStatCodeRegisterTests(void); +#endif +static int g_http_stat_code_buffer_id = 0; +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); + +/** + * \brief Registration function for keyword: http_stat_code + */ +void DetectHttpStatCodeRegister(void) +{ + /* http_stat_code content modifier */ + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].name = "http_stat_code"; + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].desc = + "content modifier to match only on HTTP stat-code-buffer"; + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = "/rules/http-keywords.html#http-stat-code"; + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].alternative = DETECT_HTTP_STAT_CODE; + + /* http.stat_code content modifier */ + sigmatch_table[DETECT_HTTP_STAT_CODE].name = "http.stat_code"; + sigmatch_table[DETECT_HTTP_STAT_CODE].desc = + "sticky buffer to match only on HTTP stat-code-buffer"; + sigmatch_table[DETECT_HTTP_STAT_CODE].url = "/rules/http-keywords.html#http-stat-code"; + sigmatch_table[DETECT_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetupSticky; + sigmatch_table[DETECT_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_stat_code", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_stat_code", SIG_FLAG_TOCLIENT, 4, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); + + DetectAppLayerInspectEngineRegister2("http_stat_code", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_stat_code", SIG_FLAG_TOCLIENT, 4, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectBufferTypeSetDescriptionByName("http_stat_code", "http response status code"); + + g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); +} + +/** + * \brief this function setups the http_stat_code modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectHttpStatCodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_STAT_CODE, g_http_stat_code_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.stat_code keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpStatCodeSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_stat_code_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_status == NULL) + return NULL; + + const uint32_t data_len = bstr_len(tx->response_status); + const uint8_t *data = bstr_ptr(tx->response_status); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_status(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS +#include "tests/detect-http-stat-code.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/app-layer/http/detect-stat-code.h b/src/app-layer/http/detect-stat-code.h new file mode 100644 index 000000000000..dbfe6ca28f3c --- /dev/null +++ b/src/app-layer/http/detect-stat-code.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + */ + +#ifndef _DETECT_HTTP_STAT_CODE_H +#define _DETECT_HTTP_STAT_CODE_H + +/* prototypes */ +void DetectHttpStatCodeRegister(void); + +#endif /* _DETECT_HTTP_STAT_CODE_H */ diff --git a/src/app-layer/http/detect-stat-msg.c b/src/app-layer/http/detect-stat-msg.c new file mode 100644 index 000000000000..aa8f075454dc --- /dev/null +++ b/src/app-layer/http/detect-stat-msg.c @@ -0,0 +1,193 @@ +/* Copyright (C) 2007-2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Gurvinder Singh + * \author Anoop Saldanha + * + * Implements the http_stat_msg keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/error.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-stat-msg.h" +#include "stream-tcp-private.h" +#include "stream-tcp.h" + +static int DetectHttpStatMsgSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectHttpStatMsgRegisterTests(void); +#endif +static int g_http_stat_msg_buffer_id = 0; +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static int DetectHttpStatMsgSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + InspectionBufferSetup(det_ctx, list_id, buffer, (const uint8_t *)"", 0); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief Registration function for keyword: http_stat_msg + */ +void DetectHttpStatMsgRegister(void) +{ + /* http_stat_msg content modifier */ + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].name = "http_stat_msg"; + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].desc = + "content modifier to match on HTTP stat-msg-buffer"; + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = "/rules/http-keywords.html#http-stat-msg"; + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].alternative = DETECT_HTTP_STAT_MSG; + + /* http.stat_msg sticky buffer */ + sigmatch_table[DETECT_HTTP_STAT_MSG].name = "http.stat_msg"; + sigmatch_table[DETECT_HTTP_STAT_MSG].desc = + "sticky buffer to match on the HTTP response status message"; + sigmatch_table[DETECT_HTTP_STAT_MSG].url = "/rules/http-keywords.html#http-stat-msg"; + sigmatch_table[DETECT_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetupSticky; + sigmatch_table[DETECT_HTTP_STAT_MSG].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_stat_msg", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, + HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_stat_msg", SIG_FLAG_TOCLIENT, 3, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); + + DetectAppLayerInspectEngineRegister2("http_stat_msg", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); + DetectAppLayerMpmRegister2("http_stat_msg", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); + + DetectBufferTypeSetDescriptionByName("http_stat_msg", "http response status message"); + + g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); +} + +/** + * \brief this function setups the http_stat_msg modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectHttpStatMsgSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_STAT_MSG, g_http_stat_msg_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.stat_msg keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpStatMsgSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_stat_msg_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_message == NULL) + return NULL; + + const uint32_t data_len = bstr_len(tx->response_message); + const uint8_t *data = bstr_ptr(tx->response_message); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS +#include "tests/detect-http-stat-msg.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/app-layer/http/detect-stat-msg.h b/src/app-layer/http/detect-stat-msg.h new file mode 100644 index 000000000000..34b30a6c618c --- /dev/null +++ b/src/app-layer/http/detect-stat-msg.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + */ + +#ifndef _DETECT_HTTP_STAT_MSG_H +#define _DETECT_HTTP_STAT_MSG_H + +/* prototypes */ +void DetectHttpStatMsgRegister(void); + +#endif /* _DETECT_HTTP_STAT_MSG_H */ diff --git a/src/app-layer/http/detect-ua.c b/src/app-layer/http/detect-ua.c new file mode 100644 index 000000000000..4fcce8244f80 --- /dev/null +++ b/src/app-layer/http/detect-ua.c @@ -0,0 +1,211 @@ +/* Copyright (C) 2007-2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Implements support for the http_user_agent keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "stream-tcp.h" +#include "app-layer/http/detect-ua.h" + +static int DetectHttpUASetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectHttpUARegisterTests(void); +#endif +static int g_http_ua_buffer_id = 0; +static int DetectHttpUserAgentSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); + +/** + * \brief Registers the keyword handlers for the "http_user_agent" keyword. + */ +void DetectHttpUARegister(void) +{ + /* http_user_agent content modifier */ + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].name = "http_user_agent"; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].desc = + "content modifier to match only on the HTTP User-Agent header"; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = "/rules/http-keywords.html#http-user-agent"; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].alternative = DETECT_HTTP_UA; + + /* http.user_agent sticky buffer */ + sigmatch_table[DETECT_HTTP_UA].name = "http.user_agent"; + sigmatch_table[DETECT_HTTP_UA].desc = + "sticky buffer to match specifically and only on the HTTP User Agent buffer"; + sigmatch_table[DETECT_HTTP_UA].url = "/rules/http-keywords.html#http-user-agent"; + sigmatch_table[DETECT_HTTP_UA].Setup = DetectHttpUserAgentSetup; + sigmatch_table[DETECT_HTTP_UA].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_HTTP_UA].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_user_agent", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_user_agent", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); + + DetectAppLayerInspectEngineRegister2("http_user_agent", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_user_agent", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeSetDescriptionByName("http_user_agent", "http user agent"); + + g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); +} + +/** + * \brief The setup function for the http_user_agent keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +int DetectHttpUASetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_USER_AGENT, g_http_ua_buffer_id, ALPROTO_HTTP1); +} + +/** + * \brief this function setup the http.user_agent keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpUserAgentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_ua_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return NULL; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, "User-Agent"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP UA header not present in this request"); + return NULL; + } + + const uint32_t data_len = bstr_len(h->value); + const uint8_t *data = bstr_ptr(h->value); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_useragent(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS +#include "tests/detect-http-user-agent.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/detect-http-ua.h b/src/app-layer/http/detect-ua.h similarity index 100% rename from src/detect-http-ua.h rename to src/app-layer/http/detect-ua.h diff --git a/src/app-layer/http/detect-uri.c b/src/app-layer/http/detect-uri.c new file mode 100644 index 000000000000..b1164ae67a83 --- /dev/null +++ b/src/app-layer/http/detect-uri.c @@ -0,0 +1,334 @@ +/* Copyright (C) 2007-2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Gerardo Iglesias + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/spm.h" +#include "util/print.h" + +#include "app-layer.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/detect-uri.h" +#include "stream-tcp.h" + +#ifdef UNITTESTS +static void DetectHttpUriRegisterTests(void); +#endif +static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx, Signature *s); +static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); +static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx, Signature *s); +static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **); +static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); +static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); + +static int g_http_raw_uri_buffer_id = 0; +static int g_http_uri_buffer_id = 0; + +/** + * \brief Registration function for keywords: http_uri and http.uri + */ +void DetectHttpUriRegister(void) +{ + /* http_uri content modifier */ + sigmatch_table[DETECT_AL_HTTP_URI].name = "http_uri"; + sigmatch_table[DETECT_AL_HTTP_URI].desc = + "content modifier to match specifically and only on the HTTP uri-buffer"; + sigmatch_table[DETECT_AL_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw"; + sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; +#endif + sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_URI].alternative = DETECT_HTTP_URI; + + /* http.uri sticky buffer */ + sigmatch_table[DETECT_HTTP_URI].name = "http.uri"; + sigmatch_table[DETECT_HTTP_URI].alias = "http.uri.normalized"; + sigmatch_table[DETECT_HTTP_URI].desc = + "sticky buffer to match specifically and only on the normalized HTTP URI buffer"; + sigmatch_table[DETECT_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw"; + sigmatch_table[DETECT_HTTP_URI].Setup = DetectHttpUriSetupSticky; + sigmatch_table[DETECT_HTTP_URI].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); + + DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeSetDescriptionByName("http_uri", "http request uri"); + + DetectBufferTypeRegisterSetupCallback("http_uri", DetectHttpUriSetupCallback); + + DetectBufferTypeRegisterValidateCallback("http_uri", DetectHttpUriValidateCallback); + + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); + + /* http_raw_uri content modifier */ + sigmatch_table[DETECT_AL_HTTP_RAW_URI].name = "http_raw_uri"; + sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on the raw HTTP uri"; + sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = + "/rules/http-keywords.html#http_uri-and-http_raw-uri"; + sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; + sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_CONTENT_MODIFIER; + sigmatch_table[DETECT_AL_HTTP_RAW_URI].alternative = DETECT_HTTP_URI_RAW; + + /* http.uri.raw sticky buffer */ + sigmatch_table[DETECT_HTTP_URI_RAW].name = "http.uri.raw"; + sigmatch_table[DETECT_HTTP_URI_RAW].desc = + "sticky buffer to match specifically and only on the raw HTTP URI buffer"; + sigmatch_table[DETECT_HTTP_URI_RAW].url = "/rules/http-keywords.html#http-uri-and-http-raw-uri"; + sigmatch_table[DETECT_HTTP_URI_RAW].Setup = DetectHttpRawUriSetupSticky; + sigmatch_table[DETECT_HTTP_URI_RAW].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, + HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetRawData); + + DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRawData, ALPROTO_HTTP1, HTP_REQUEST_LINE); + + // no difference between raw and decoded uri for HTTP2 + DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + + DetectBufferTypeSetDescriptionByName("http_raw_uri", "raw http uri"); + + DetectBufferTypeRegisterSetupCallback("http_raw_uri", DetectHttpRawUriSetupCallback); + + DetectBufferTypeRegisterValidateCallback("http_raw_uri", DetectHttpRawUriValidateCallback); + + g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri"); +} + +/** + * \brief this function setups the http_uri modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, str, DETECT_AL_HTTP_URI, g_http_uri_buffer_id, ALPROTO_HTTP1); +} + +static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror) +{ + return DetectUrilenValidateContent(s, g_http_uri_buffer_id, sigerror); +} + +static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + DetectUrilenApplyToContent(s, g_http_uri_buffer_id); +} + +/** + * \brief this function setup the http.uri keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_uri_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (!buffer->initialized) { + htp_tx_t *tx = (htp_tx_t *)txv; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + + if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) { + SCLogDebug("no tx_id or uri"); + return NULL; + } + + const uint32_t data_len = bstr_len(tx_ud->request_uri_normalized); + const uint8_t *data = bstr_ptr(tx_ud->request_uri_normalized); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (!buffer->initialized) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_uri(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief Sets up the http_raw_uri modifier keyword. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Signature to which the current keyword belongs. + * \param arg Should hold an empty string always. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + return DetectEngineContentModifierBufferSetup( + de_ctx, s, arg, DETECT_AL_HTTP_RAW_URI, g_http_raw_uri_buffer_id, ALPROTO_HTTP1); +} + +static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **sigerror) +{ + return DetectUrilenValidateContent(s, g_http_raw_uri_buffer_id, sigerror); +} + +static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + DetectUrilenApplyToContent(s, g_http_raw_uri_buffer_id); +} + +/** + * \brief this function setup the http.uri.raw keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_uri_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) + return -1; + return 0; +} + +static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (!buffer->initialized) { + htp_tx_t *tx = (htp_tx_t *)txv; + if (unlikely(tx->request_uri == NULL)) { + return NULL; + } + const uint32_t data_len = bstr_len(tx->request_uri); + const uint8_t *data = bstr_ptr(tx->request_uri); + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "tests/detect-http-uri.c" +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/app-layer/http/detect-uri.h b/src/app-layer/http/detect-uri.h new file mode 100644 index 000000000000..b05b37ed0fa6 --- /dev/null +++ b/src/app-layer/http/detect-uri.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gerardo Iglesias Galvan + */ + +#ifndef _DETECT_HTTP_URI_H +#define _DETECT_HTTP_URI_H + +/* prototypes */ +int DetectHttpUriSetup(DetectEngineCtx *, Signature *, const char *); +void DetectHttpUriRegister(void); + +#endif /* _DETECT_HTTP_URI_H */ diff --git a/src/app-layer/http/log-httplog.c b/src/app-layer/http/log-httplog.c new file mode 100644 index 000000000000..3e9280af5240 --- /dev/null +++ b/src/app-layer/http/log-httplog.c @@ -0,0 +1,620 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Ignacio Sanchez + * + * Implements http logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer/http/log-httplog.h" +#include "app-layer/http/parser.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" + +#include "util/logopenfile.h" +#include "util/time.h" +#include "log-cf-common.h" + +#define DEFAULT_LOG_FILENAME "http.log" + +#define MODULE_NAME "LogHttpLog" + +#define OUTPUT_BUFFER_SIZE 65535 + +TmEcode LogHttpLogThreadInit(ThreadVars *, const void *, void **); +TmEcode LogHttpLogThreadDeinit(ThreadVars *, void *); +static void LogHttpLogDeInitCtx(OutputCtx *); + +int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *, Flow *f, void *state, void *tx, + uint64_t tx_id); + +void LogHttpLogRegister(void) +{ + OutputRegisterTxModule(LOGGER_HTTP, MODULE_NAME, "http-log", LogHttpLogInitCtx, ALPROTO_HTTP1, + LogHttpLogger, LogHttpLogThreadInit, LogHttpLogThreadDeinit, NULL); +} + +#define LOG_HTTP_CF_REQUEST_HOST 'h' +#define LOG_HTTP_CF_REQUEST_PROTOCOL 'H' +#define LOG_HTTP_CF_REQUEST_METHOD 'm' +#define LOG_HTTP_CF_REQUEST_URI 'u' +#define LOG_HTTP_CF_REQUEST_TIME 't' +#define LOG_HTTP_CF_REQUEST_HEADER 'i' +#define LOG_HTTP_CF_REQUEST_COOKIE 'C' +#define LOG_HTTP_CF_REQUEST_LEN 'b' +#define LOG_HTTP_CF_RESPONSE_STATUS 's' +#define LOG_HTTP_CF_RESPONSE_HEADER 'o' +#define LOG_HTTP_CF_RESPONSE_LEN 'B' + +typedef struct LogHttpFileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ + LogCustomFormat *cf; +} LogHttpFileCtx; + +#define LOG_HTTP_DEFAULT 0 +#define LOG_HTTP_EXTENDED 1 +#define LOG_HTTP_CUSTOM 2 + +typedef struct LogHttpLogThread_ { + LogHttpFileCtx *httplog_ctx; + /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ + uint32_t uri_cnt; + + MemBuffer *buffer; +} LogHttpLogThread; + +/* Retrieves the selected cookie value */ +static uint32_t GetCookieValue( + uint8_t *rawcookies, uint32_t rawcookies_len, char *cookiename, uint8_t **cookievalue) +{ + uint8_t *p = rawcookies; + uint8_t *cn = p; /* ptr to cookie name start */ + uint8_t *cv = NULL; /* ptr to cookie value start */ + while (p < rawcookies + rawcookies_len) { + if (cv == NULL && *p == '=') { + cv = p + 1; + } else if (cv != NULL && (*p == ';' || p == rawcookies + rawcookies_len - 1)) { + /* Found end of cookie */ + p++; + if (strlen(cookiename) == (unsigned int)(cv - cn - 1) && + strncmp(cookiename, (char *)cn, cv - cn - 1) == 0) { + *cookievalue = cv; + return (uint32_t)(p - cv); + } + cv = NULL; + cn = p + 1; + } + p++; + } + return 0; +} + +/* Custom format logging */ +static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const SCTime_t ts, char *srcip, + Port sp, char *dstip, Port dp) +{ + LogHttpFileCtx *httplog_ctx = aft->httplog_ctx; + uint32_t i; + uint32_t datalen; + char buf[128]; + + uint8_t *cvalue = NULL; + uint32_t cvalue_len = 0; + + htp_header_t *h_request_hdr; + htp_header_t *h_response_hdr; + + for (i = 0; i < httplog_ctx->cf->cf_n; i++) { + h_request_hdr = NULL; + h_response_hdr = NULL; + + LogCustomFormatNode *node = httplog_ctx->cf->cf_nodes[i]; + if (!node) /* Should never happen */ + continue; + + switch (node->type) { + case LOG_CF_LITERAL: + /* LITERAL */ + MemBufferWriteString(aft->buffer, "%s", node->data); + break; + case LOG_CF_TIMESTAMP: + /* TIMESTAMP */ + LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); + break; + case LOG_CF_TIMESTAMP_U: + /* TIMESTAMP USECONDS */ + snprintf(buf, sizeof(buf), "%06u", (unsigned int)SCTIME_USECS(ts)); + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)buf, MIN(strlen(buf), 6)); + break; + case LOG_CF_CLIENT_IP: + /* CLIENT IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)srcip, strlen(srcip)); + break; + case LOG_CF_SERVER_IP: + /* SERVER IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)dstip, strlen(dstip)); + break; + case LOG_CF_CLIENT_PORT: + /* CLIENT PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); + break; + case LOG_CF_SERVER_PORT: + /* SERVER PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); + break; + case LOG_HTTP_CF_REQUEST_METHOD: + /* METHOD */ + if (tx->request_method != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_method), + bstr_len(tx->request_method)); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_REQUEST_URI: + /* URI */ + if (tx->request_uri != NULL) { + datalen = node->maxlen; + if (datalen == 0 || datalen > bstr_len(tx->request_uri)) { + datalen = bstr_len(tx->request_uri); + } + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_uri), datalen); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_REQUEST_HOST: + /* HOSTNAME */ + if (tx->request_hostname != NULL) { + datalen = node->maxlen; + if (datalen == 0 || datalen > bstr_len(tx->request_hostname)) { + datalen = bstr_len(tx->request_hostname); + } + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_hostname), datalen); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_REQUEST_PROTOCOL: + /* PROTOCOL */ + if (tx->request_protocol != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_protocol), + bstr_len(tx->request_protocol)); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_REQUEST_HEADER: + /* REQUEST HEADER */ + if (tx->request_headers != NULL) { + h_request_hdr = htp_table_get_c(tx->request_headers, node->data); + } + if (h_request_hdr != NULL) { + datalen = node->maxlen; + if (datalen == 0 || datalen > bstr_len(h_request_hdr->value)) { + datalen = bstr_len(h_request_hdr->value); + } + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)bstr_ptr(h_request_hdr->value), datalen); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_REQUEST_COOKIE: + /* REQUEST COOKIE */ + if (tx->request_headers != NULL) { + h_request_hdr = htp_table_get_c(tx->request_headers, "Cookie"); + if (h_request_hdr != NULL) { + cvalue_len = GetCookieValue((uint8_t *)bstr_ptr(h_request_hdr->value), + bstr_len(h_request_hdr->value), (char *)node->data, &cvalue); + } + } + if (cvalue_len > 0 && cvalue != NULL) { + datalen = node->maxlen; + if (datalen == 0 || datalen > cvalue_len) { + datalen = cvalue_len; + } + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, cvalue, datalen); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_REQUEST_LEN: + /* REQUEST LEN */ + MemBufferWriteString( + aft->buffer, "%" PRIuMAX "", (uintmax_t)tx->request_message_len); + break; + case LOG_HTTP_CF_RESPONSE_STATUS: + /* RESPONSE STATUS */ + if (tx->response_status != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)bstr_ptr(tx->response_status), + bstr_len(tx->response_status)); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_RESPONSE_HEADER: + /* RESPONSE HEADER */ + if (tx->response_headers != NULL) { + h_response_hdr = htp_table_get_c(tx->response_headers, node->data); + } + if (h_response_hdr != NULL) { + datalen = node->maxlen; + if (datalen == 0 || datalen > bstr_len(h_response_hdr->value)) { + datalen = bstr_len(h_response_hdr->value); + } + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)bstr_ptr(h_response_hdr->value), datalen); + } else { + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + } + break; + case LOG_HTTP_CF_RESPONSE_LEN: + /* RESPONSE LEN */ + MemBufferWriteString( + aft->buffer, "%" PRIuMAX "", (uintmax_t)tx->response_message_len); + break; + default: + /* NO MATCH */ + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + SCLogDebug("No matching parameter %%%c for custom http log.", node->type); + break; + } + } + MemBufferWriteString(aft->buffer, "\n"); +} + +static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) +{ + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + + /* referer */ + htp_header_t *h_referer = NULL; + if (tx->request_headers != NULL) { + h_referer = htp_table_get_c(tx->request_headers, "referer"); + } + if (h_referer != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(h_referer->value), bstr_len(h_referer->value)); + } else { + MemBufferWriteString(aft->buffer, ""); + } + + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + + /* method */ + if (tx->request_method != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); + } + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + + /* protocol */ + if (tx->request_protocol != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); + } else { + MemBufferWriteString(aft->buffer, ""); + } + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + + /* response status */ + if (tx->response_status != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status)); + /* Redirect? */ + if ((tx->response_status_number > 300) && ((tx->response_status_number) < 303)) { + htp_header_t *h_location = htp_table_get_c(tx->response_headers, "location"); + if (h_location != NULL) { + MemBufferWriteString(aft->buffer, " => "); + + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(h_location->value), bstr_len(h_location->value)); + } + } + } else { + MemBufferWriteString(aft->buffer, ""); + } + + /* length */ + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + MemBufferWriteString(aft->buffer, "%" PRIuMAX " bytes", (uintmax_t)tx->response_message_len); +} + +static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, Flow *f, + HtpState *htp_state, htp_tx_t *tx, uint64_t tx_id, int ipproto) +{ + SCEnter(); + + LogHttpLogThread *aft = (LogHttpLogThread *)data; + LogHttpFileCtx *hlog = aft->httplog_ctx; + char timebuf[64]; + + /* check if we have HTTP state or not */ + CreateTimeString(p->ts, timebuf, sizeof(timebuf)); + + char srcip[46], dstip[46]; + Port sp, dp; + if ((PKT_IS_TOSERVER(p))) { + switch (ipproto) { + case AF_INET: + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + break; + case AF_INET6: + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + break; + default: + goto end; + } + sp = p->sp; + dp = p->dp; + } else { + switch (ipproto) { + case AF_INET: + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip)); + break; + case AF_INET6: + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip)); + break; + default: + goto end; + } + sp = p->dp; + dp = p->sp; + } + + SCLogDebug("got a HTTP request and now logging !!"); + + /* reset */ + MemBufferReset(aft->buffer); + + if (hlog->flags & LOG_HTTP_CUSTOM) { + LogHttpLogCustom(aft, tx, p->ts, srcip, sp, dstip, dp); + } else { + /* time */ + MemBufferWriteString(aft->buffer, "%s ", timebuf); + + /* hostname */ + if (tx->request_hostname != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname)); + } else { + MemBufferWriteString(aft->buffer, ""); + } + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + + /* uri */ + if (tx->request_uri != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); + } + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + + /* user agent */ + htp_header_t *h_user_agent = NULL; + if (tx->request_headers != NULL) { + h_user_agent = htp_table_get_c(tx->request_headers, "user-agent"); + } + if (h_user_agent != NULL) { + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)bstr_ptr(h_user_agent->value), bstr_len(h_user_agent->value)); + } else { + MemBufferWriteString(aft->buffer, ""); + } + if (hlog->flags & LOG_HTTP_EXTENDED) { + LogHttpLogExtended(aft, tx); + } + + /* ip/tcp header info */ + LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); + MemBufferWriteString( + aft->buffer, "%s:%" PRIu16 " -> %s:%" PRIu16 "\n", srcip, sp, dstip, dp); + } + + aft->uri_cnt++; + + hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), + MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); + +end: + SCReturnInt(0); +} + +int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + SCEnter(); + + if (!(PKT_IS_TCP(p))) { + SCReturnInt(TM_ECODE_OK); + } + + int r = 0; + if (PKT_IS_IPV4(p)) { + r = LogHttpLogIPWrapper( + tv, thread_data, p, f, (HtpState *)state, (htp_tx_t *)tx, tx_id, AF_INET); + } else if (PKT_IS_IPV6(p)) { + r = LogHttpLogIPWrapper( + tv, thread_data, p, f, (HtpState *)state, (htp_tx_t *)tx, tx_id, AF_INET6); + } + + SCReturnInt(r); +} + +TmEcode LogHttpLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogHttpLogThread *aft = SCCalloc(1, sizeof(LogHttpLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + + if (initdata == NULL) { + SCLogDebug("Error getting context for LogHTTPLog. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Output Context (file pointer and mutex) */ + aft->httplog_ctx = ((OutputCtx *)initdata)->data; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +TmEcode LogHttpLogThreadDeinit(ThreadVars *t, void *data) +{ + LogHttpLogThread *aft = (LogHttpLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->buffer); + /* clear memory */ + memset(aft, 0, sizeof(LogHttpLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +/** \brief Create a new http log LogFileCtx. + * \param conf Pointer to ConfNode containing this loggers configuration. + * \return NULL if failure, LogFileCtx* to the file_ctx if succesful + * */ +OutputInitResult LogHttpLogInitCtx(ConfNode *conf) +{ + OutputInitResult result = { NULL, false }; + LogFileCtx *file_ctx = LogFileNewCtx(); + if (file_ctx == NULL) { + SCLogError("couldn't create new file_ctx"); + return result; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + LogFileFreeCtx(file_ctx); + return result; + } + + LogHttpFileCtx *httplog_ctx = SCCalloc(1, sizeof(LogHttpFileCtx)); + if (unlikely(httplog_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + return result; + } + + httplog_ctx->file_ctx = file_ctx; + + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + const char *custom = ConfNodeLookupChildValue(conf, "custom"); + const char *customformat = ConfNodeLookupChildValue(conf, "customformat"); + + /* If custom logging format is selected, lets parse it */ + if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { + + httplog_ctx->cf = LogCustomFormatAlloc(); + if (!httplog_ctx->cf) { + goto errorfree; + } + + httplog_ctx->flags |= LOG_HTTP_CUSTOM; + + /* Parsing */ + if (!LogCustomFormatParse(httplog_ctx->cf, customformat)) { + goto parsererror; + } + } else { + if (extended == NULL) { + httplog_ctx->flags |= LOG_HTTP_DEFAULT; + } else { + if (ConfValIsTrue(extended)) { + httplog_ctx->flags |= LOG_HTTP_EXTENDED; + } + } + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + goto parsererror; + } + + output_ctx->data = httplog_ctx; + output_ctx->DeInit = LogHttpLogDeInitCtx; + + SCLogDebug("HTTP log output initialized"); + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP1); + + result.ctx = output_ctx; + result.ok = true; + return result; + +parsererror: + SCLogError("Syntax error in custom http log format string."); +errorfree: + LogCustomFormatFree(httplog_ctx->cf); + LogFileFreeCtx(file_ctx); + SCFree(httplog_ctx); + return result; +} + +static void LogHttpLogDeInitCtx(OutputCtx *output_ctx) +{ + LogHttpFileCtx *httplog_ctx = (LogHttpFileCtx *)output_ctx->data; + LogCustomFormatFree(httplog_ctx->cf); + LogFileFreeCtx(httplog_ctx->file_ctx); + SCFree(httplog_ctx); + SCFree(output_ctx); +} diff --git a/src/log-httplog.h b/src/app-layer/http/log-httplog.h similarity index 99% rename from src/log-httplog.h rename to src/app-layer/http/log-httplog.h index 580191fb99c4..53aaceee7c04 100644 --- a/src/log-httplog.h +++ b/src/app-layer/http/log-httplog.h @@ -28,4 +28,3 @@ void LogHttpLogRegister(void); OutputInitResult LogHttpLogInitCtx(ConfNode *); #endif /* __LOG_HTTPLOG_H__ */ - diff --git a/src/app-layer/http/logger.c b/src/app-layer/http/logger.c new file mode 100644 index 000000000000..fc51d4684c78 --- /dev/null +++ b/src/app-layer/http/logger.c @@ -0,0 +1,651 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + * + * Implements HTTP JSON logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-file.h" +#include "app-layer/http/parser-xff.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-alert.h" +#include "app-layer/http/logger.h" +#include "util/byte.h" + +typedef struct LogHttpFileCtx_ { + uint32_t flags; /** Store mode */ + uint64_t fields; /** Store fields */ + HttpXFFCfg *xff_cfg; + HttpXFFCfg *parent_xff_cfg; + OutputJsonCtx *eve_ctx; +} LogHttpFileCtx; + +typedef struct JsonHttpLogThread_ { + LogHttpFileCtx *httplog_ctx; + uint32_t uri_cnt; + OutputJsonThreadCtx *ctx; +} JsonHttpLogThread; + +#define MAX_SIZE_HEADER_NAME 256 +#define MAX_SIZE_HEADER_VALUE 2048 + +#define LOG_HTTP_DEFAULT 0 +#define LOG_HTTP_EXTENDED 1 +#define LOG_HTTP_REQUEST 2 /* request field */ +#define LOG_HTTP_ARRAY 4 /* require array handling */ +#define LOG_HTTP_REQ_HEADERS 8 +#define LOG_HTTP_RES_HEADERS 16 + +typedef enum { + HTTP_FIELD_ACCEPT = 0, + HTTP_FIELD_ACCEPT_CHARSET, + HTTP_FIELD_ACCEPT_ENCODING, + HTTP_FIELD_ACCEPT_LANGUAGE, + HTTP_FIELD_ACCEPT_DATETIME, + HTTP_FIELD_AUTHORIZATION, + HTTP_FIELD_CACHE_CONTROL, + HTTP_FIELD_COOKIE, + HTTP_FIELD_FROM, + HTTP_FIELD_MAX_FORWARDS, + HTTP_FIELD_ORIGIN, + HTTP_FIELD_PRAGMA, + HTTP_FIELD_PROXY_AUTHORIZATION, + HTTP_FIELD_RANGE, + HTTP_FIELD_TE, + HTTP_FIELD_VIA, + HTTP_FIELD_X_REQUESTED_WITH, + HTTP_FIELD_DNT, + HTTP_FIELD_X_FORWARDED_PROTO, + HTTP_FIELD_X_AUTHENTICATED_USER, + HTTP_FIELD_X_FLASH_VERSION, + HTTP_FIELD_ACCEPT_RANGES, + HTTP_FIELD_AGE, + HTTP_FIELD_ALLOW, + HTTP_FIELD_CONNECTION, + HTTP_FIELD_CONTENT_ENCODING, + HTTP_FIELD_CONTENT_LANGUAGE, + HTTP_FIELD_CONTENT_LENGTH, + HTTP_FIELD_CONTENT_LOCATION, + HTTP_FIELD_CONTENT_MD5, + HTTP_FIELD_CONTENT_RANGE, + HTTP_FIELD_CONTENT_TYPE, + HTTP_FIELD_DATE, + HTTP_FIELD_ETAG, + HTTP_FIELD_EXPIRES, + HTTP_FIELD_LAST_MODIFIED, + HTTP_FIELD_LINK, + HTTP_FIELD_LOCATION, + HTTP_FIELD_PROXY_AUTHENTICATE, + HTTP_FIELD_REFERRER, + HTTP_FIELD_REFRESH, + HTTP_FIELD_RETRY_AFTER, + HTTP_FIELD_SERVER, + HTTP_FIELD_SET_COOKIE, + HTTP_FIELD_TRAILER, + HTTP_FIELD_TRANSFER_ENCODING, + HTTP_FIELD_UPGRADE, + HTTP_FIELD_VARY, + HTTP_FIELD_WARNING, + HTTP_FIELD_WWW_AUTHENTICATE, + HTTP_FIELD_TRUE_CLIENT_IP, + HTTP_FIELD_ORG_SRC_IP, + HTTP_FIELD_X_BLUECOAT_VIA, + HTTP_FIELD_SIZE +} HttpField; + +struct { + const char *config_field; + const char *htp_field; + uint32_t flags; +} http_fields[] = { + { "accept", "accept", LOG_HTTP_REQUEST }, + { "accept_charset", "accept-charset", LOG_HTTP_REQUEST }, + { "accept_encoding", "accept-encoding", LOG_HTTP_REQUEST }, + { "accept_language", "accept-language", LOG_HTTP_REQUEST }, + { "accept_datetime", "accept-datetime", LOG_HTTP_REQUEST }, + { "authorization", "authorization", LOG_HTTP_REQUEST }, + { "cache_control", "cache-control", LOG_HTTP_REQUEST }, + { "cookie", "cookie", LOG_HTTP_REQUEST | LOG_HTTP_ARRAY }, + { "from", "from", LOG_HTTP_REQUEST }, + { "max_forwards", "max-forwards", LOG_HTTP_REQUEST }, + { "origin", "origin", LOG_HTTP_REQUEST }, + { "pragma", "pragma", LOG_HTTP_REQUEST }, + { "proxy_authorization", "proxy-authorization", LOG_HTTP_REQUEST }, + { "range", "range", LOG_HTTP_REQUEST }, + { "te", "te", LOG_HTTP_REQUEST }, + { "via", "via", LOG_HTTP_REQUEST }, + { "x_requested_with", "x-requested-with", LOG_HTTP_REQUEST }, + { "dnt", "dnt", LOG_HTTP_REQUEST }, + { "x_forwarded_proto", "x-forwarded-proto", LOG_HTTP_REQUEST }, + { "x_authenticated_user", "x-authenticated-user", LOG_HTTP_REQUEST }, + { "x_flash_version", "x-flash-version", LOG_HTTP_REQUEST }, + { "accept_range", "accept-range", 0 }, + { "age", "age", 0 }, + { "allow", "allow", 0 }, + { "connection", "connection", 0 }, + { "content_encoding", "content-encoding", 0 }, + { "content_language", "content-language", 0 }, + { "content_length", "content-length", 0 }, + { "content_location", "content-location", 0 }, + { "content_md5", "content-md5", 0 }, + { "content_range", "content-range", 0 }, + { "content_type", "content-type", 0 }, + { "date", "date", 0 }, + { "etag", "etags", 0 }, + { "expires", "expires", 0 }, + { "last_modified", "last-modified", 0 }, + { "link", "link", 0 }, + { "location", "location", 0 }, + { "proxy_authenticate", "proxy-authenticate", 0 }, + { "referer", "referer", LOG_HTTP_EXTENDED }, + { "refresh", "refresh", 0 }, + { "retry_after", "retry-after", 0 }, + { "server", "server", 0 }, + { "set_cookie", "set-cookie", 0 }, + { "trailer", "trailer", 0 }, + { "transfer_encoding", "transfer-encoding", 0 }, + { "upgrade", "upgrade", 0 }, + { "vary", "vary", 0 }, + { "warning", "warning", 0 }, + { "www_authenticate", "www-authenticate", 0 }, + { "true_client_ip", "true-client-ip", LOG_HTTP_REQUEST }, + { "org_src_ip", "org-src-ip", LOG_HTTP_REQUEST }, + { "x_bluecoat_via", "x-bluecoat-via", LOG_HTTP_REQUEST }, +}; + +static void EveHttpLogJSONBasic(JsonBuilder *js, htp_tx_t *tx) +{ + /* hostname */ + if (tx->request_hostname != NULL) { + jb_set_string_from_bytes( + js, "hostname", bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname)); + } + + /* port */ + /* NOTE: this field will be set ONLY if the port is present in the + * hostname. It may be present in the header "Host" or in the URL. + * There is no connection (from the suricata point of view) between this + * port and the TCP destination port of the flow. + */ + if (tx->request_port_number >= 0) { + jb_set_uint(js, "http_port", tx->request_port_number); + } + + /* uri */ + if (tx->request_uri != NULL) { + jb_set_string_from_bytes(js, "url", bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); + } + + if (tx->request_headers != NULL) { + /* user agent */ + htp_header_t *h_user_agent = htp_table_get_c(tx->request_headers, "user-agent"); + if (h_user_agent != NULL) { + jb_set_string_from_bytes(js, "http_user_agent", bstr_ptr(h_user_agent->value), + bstr_len(h_user_agent->value)); + } + + /* x-forwarded-for */ + htp_header_t *h_x_forwarded_for = htp_table_get_c(tx->request_headers, "x-forwarded-for"); + if (h_x_forwarded_for != NULL) { + jb_set_string_from_bytes(js, "xff", bstr_ptr(h_x_forwarded_for->value), + bstr_len(h_x_forwarded_for->value)); + } + } + + /* content-type */ + if (tx->response_headers != NULL) { + htp_header_t *h_content_type = htp_table_get_c(tx->response_headers, "content-type"); + if (h_content_type != NULL) { + const size_t size = bstr_len(h_content_type->value) * 2 + 1; + char string[size]; + BytesToStringBuffer( + bstr_ptr(h_content_type->value), bstr_len(h_content_type->value), string, size); + char *p = strchr(string, ';'); + if (p != NULL) + *p = '\0'; + jb_set_string(js, "http_content_type", string); + } + htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range"); + if (h_content_range != NULL) { + jb_open_object(js, "content_range"); + jb_set_string_from_bytes( + js, "raw", bstr_ptr(h_content_range->value), bstr_len(h_content_range->value)); + HTTPContentRange crparsed; + if (HTPParseContentRange(h_content_range->value, &crparsed) == 0) { + if (crparsed.start >= 0) + jb_set_uint(js, "start", crparsed.start); + if (crparsed.end >= 0) + jb_set_uint(js, "end", crparsed.end); + if (crparsed.size >= 0) + jb_set_uint(js, "size", crparsed.size); + } + jb_close(js); + } + } +} + +static void EveHttpLogJSONExtended(JsonBuilder *js, htp_tx_t *tx) +{ + /* referer */ + htp_header_t *h_referer = NULL; + if (tx->request_headers != NULL) { + h_referer = htp_table_get_c(tx->request_headers, "referer"); + } + if (h_referer != NULL) { + jb_set_string_from_bytes( + js, "http_refer", bstr_ptr(h_referer->value), bstr_len(h_referer->value)); + } + + /* method */ + if (tx->request_method != NULL) { + jb_set_string_from_bytes( + js, "http_method", bstr_ptr(tx->request_method), bstr_len(tx->request_method)); + } + + /* protocol */ + if (tx->request_protocol != NULL) { + jb_set_string_from_bytes( + js, "protocol", bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); + } + + /* response status */ + if (tx->response_status != NULL) { + const size_t status_size = bstr_len(tx->response_status) * 2 + 1; + char status_string[status_size]; + BytesToStringBuffer(bstr_ptr(tx->response_status), bstr_len(tx->response_status), + status_string, status_size); + unsigned int val = strtoul(status_string, NULL, 10); + jb_set_uint(js, "status", val); + + htp_header_t *h_location = htp_table_get_c(tx->response_headers, "location"); + if (h_location != NULL) { + jb_set_string_from_bytes( + js, "redirect", bstr_ptr(h_location->value), bstr_len(h_location->value)); + } + } + + /* length */ + jb_set_uint(js, "length", tx->response_message_len); +} + +static void EveHttpLogJSONHeaders( + JsonBuilder *js, uint32_t direction, htp_tx_t *tx, LogHttpFileCtx *http_ctx) +{ + htp_table_t *headers = + direction & LOG_HTTP_REQ_HEADERS ? tx->request_headers : tx->response_headers; + char name[MAX_SIZE_HEADER_NAME] = { 0 }; + char value[MAX_SIZE_HEADER_VALUE] = { 0 }; + size_t n = htp_table_size(headers); + JsonBuilderMark mark = { 0, 0, 0 }; + jb_get_mark(js, &mark); + bool array_empty = true; + jb_open_array(js, direction & LOG_HTTP_REQ_HEADERS ? "request_headers" : "response_headers"); + for (size_t i = 0; i < n; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + if ((http_ctx->flags & direction) == 0 && http_ctx->fields != 0) { + bool tolog = false; + for (HttpField f = HTTP_FIELD_ACCEPT; f < HTTP_FIELD_SIZE; f++) { + if ((http_ctx->fields & (1ULL << f)) != 0) { + /* prevent logging a field twice if extended logging is + enabled */ + if (((http_ctx->flags & LOG_HTTP_EXTENDED) == 0) || + ((http_ctx->flags & LOG_HTTP_EXTENDED) != + (http_fields[f].flags & LOG_HTTP_EXTENDED))) { + if (bstr_cmp_c_nocase(h->name, http_fields[f].htp_field) == 0) { + tolog = true; + break; + } + } + } + } + if (!tolog) { + continue; + } + } + array_empty = false; + jb_start_object(js); + size_t size_name = bstr_len(h->name) < MAX_SIZE_HEADER_NAME - 1 ? bstr_len(h->name) + : MAX_SIZE_HEADER_NAME - 1; + memcpy(name, bstr_ptr(h->name), size_name); + name[size_name] = '\0'; + jb_set_string(js, "name", name); + size_t size_value = bstr_len(h->value) < MAX_SIZE_HEADER_VALUE - 1 + ? bstr_len(h->value) + : MAX_SIZE_HEADER_VALUE - 1; + memcpy(value, bstr_ptr(h->value), size_value); + value[size_value] = '\0'; + jb_set_string(js, "value", value); + jb_close(js); + } + if (array_empty) { + jb_restore_mark(js, &mark); + } else { + // Close array. + jb_close(js); + } +} + +static void BodyPrintableBuffer(JsonBuilder *js, HtpBody *body, const char *key) +{ + if (body->sb != NULL && body->sb->region.buf != NULL) { + uint32_t offset = 0; + const uint8_t *body_data; + uint32_t body_data_len; + uint64_t body_offset; + + if (StreamingBufferGetData(body->sb, &body_data, &body_data_len, &body_offset) == 0) { + return; + } + + uint8_t printable_buf[body_data_len + 1]; + PrintStringsToBuffer( + printable_buf, &offset, sizeof(printable_buf), body_data, body_data_len); + if (offset > 0) { + jb_set_string(js, key, (char *)printable_buf); + } + } +} + +void EveHttpLogJSONBodyPrintable(JsonBuilder *js, Flow *f, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)FlowGetAppState(f); + if (htp_state) { + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, tx_id); + if (tx) { + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + BodyPrintableBuffer(js, &htud->request_body, "http_request_body_printable"); + BodyPrintableBuffer(js, &htud->response_body, "http_response_body_printable"); + } + } + } +} + +static void BodyBase64Buffer(JsonBuilder *js, HtpBody *body, const char *key) +{ + if (body->sb != NULL && body->sb->region.buf != NULL) { + const uint8_t *body_data; + uint32_t body_data_len; + uint64_t body_offset; + + if (StreamingBufferGetData(body->sb, &body_data, &body_data_len, &body_offset) == 0) { + return; + } + + jb_set_base64(js, key, body_data, body_data_len); + } +} + +void EveHttpLogJSONBodyBase64(JsonBuilder *js, Flow *f, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)FlowGetAppState(f); + if (htp_state) { + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, tx_id); + if (tx) { + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + BodyBase64Buffer(js, &htud->request_body, "http_request_body"); + BodyBase64Buffer(js, &htud->response_body, "http_response_body"); + } + } + } +} + +/* JSON format logging */ +static void EveHttpLogJSON(JsonHttpLogThread *aft, JsonBuilder *js, htp_tx_t *tx, uint64_t tx_id) +{ + LogHttpFileCtx *http_ctx = aft->httplog_ctx; + jb_open_object(js, "http"); + + EveHttpLogJSONBasic(js, tx); + if (http_ctx->flags & LOG_HTTP_EXTENDED) + EveHttpLogJSONExtended(js, tx); + if (http_ctx->flags & LOG_HTTP_REQ_HEADERS || http_ctx->fields != 0) + EveHttpLogJSONHeaders(js, LOG_HTTP_REQ_HEADERS, tx, http_ctx); + if (http_ctx->flags & LOG_HTTP_RES_HEADERS || http_ctx->fields != 0) + EveHttpLogJSONHeaders(js, LOG_HTTP_RES_HEADERS, tx, http_ctx); + + jb_close(js); +} + +static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *alstate, void *txptr, uint64_t tx_id) +{ + SCEnter(); + + htp_tx_t *tx = txptr; + JsonHttpLogThread *jhl = (JsonHttpLogThread *)thread_data; + + JsonBuilder *js = CreateEveHeaderWithTxId( + p, LOG_DIR_FLOW, "http", NULL, tx_id, jhl->httplog_ctx->eve_ctx); + if (unlikely(js == NULL)) + return TM_ECODE_OK; + + SCLogDebug("got a HTTP request and now logging !!"); + + EveHttpLogJSON(jhl, js, tx, tx_id); + HttpXFFCfg *xff_cfg = jhl->httplog_ctx->xff_cfg != NULL ? jhl->httplog_ctx->xff_cfg + : jhl->httplog_ctx->parent_xff_cfg; + + /* xff header */ + if ((xff_cfg != NULL) && !(xff_cfg->flags & XFF_DISABLED) && p->flow != NULL) { + int have_xff_ip = 0; + char buffer[XFF_MAXLEN]; + + have_xff_ip = HttpXFFGetIPFromTx(p->flow, tx_id, xff_cfg, buffer, XFF_MAXLEN); + + if (have_xff_ip) { + if (xff_cfg->flags & XFF_EXTRADATA) { + jb_set_string(js, "xff", buffer); + } else if (xff_cfg->flags & XFF_OVERWRITE) { + if (p->flowflags & FLOW_PKT_TOCLIENT) { + jb_set_string(js, "dest_ip", buffer); + } else { + jb_set_string(js, "src_ip", buffer); + } + } + } + } + + OutputJsonBuilderBuffer(js, jhl->ctx); + jb_free(js); + + SCReturnInt(TM_ECODE_OK); +} + +bool EveHttpAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) +{ + HtpState *htp_state = (HtpState *)FlowGetAppState(f); + if (htp_state) { + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, tx_id); + + if (tx) { + EveHttpLogJSONBasic(js, tx); + EveHttpLogJSONExtended(js, tx); + return true; + } + } + + return false; +} + +static void OutputHttpLogDeinitSub(OutputCtx *output_ctx) +{ + LogHttpFileCtx *http_ctx = output_ctx->data; + if (http_ctx->xff_cfg) { + SCFree(http_ctx->xff_cfg); + } + SCFree(http_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputHttpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ojc = parent_ctx->data; + + LogHttpFileCtx *http_ctx = SCCalloc(1, sizeof(LogHttpFileCtx)); + if (unlikely(http_ctx == NULL)) + return result; + memset(http_ctx, 0x00, sizeof(*http_ctx)); + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(http_ctx); + return result; + } + + http_ctx->flags = LOG_HTTP_DEFAULT; + http_ctx->eve_ctx = ojc; + + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + http_ctx->flags = LOG_HTTP_EXTENDED; + } + } + + const char *all_headers = ConfNodeLookupChildValue(conf, "dump-all-headers"); + if (all_headers != NULL) { + if (strncmp(all_headers, "both", 4) == 0) { + http_ctx->flags |= LOG_HTTP_REQ_HEADERS; + http_ctx->flags |= LOG_HTTP_RES_HEADERS; + } else if (strncmp(all_headers, "request", 7) == 0) { + http_ctx->flags |= LOG_HTTP_REQ_HEADERS; + } else if (strncmp(all_headers, "response", 8) == 0) { + http_ctx->flags |= LOG_HTTP_RES_HEADERS; + } + } + ConfNode *custom; + if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { + if ((http_ctx->flags & (LOG_HTTP_REQ_HEADERS | LOG_HTTP_RES_HEADERS)) == + (LOG_HTTP_REQ_HEADERS | LOG_HTTP_RES_HEADERS)) { + SCLogWarning("No need for custom as dump-all-headers is already present"); + } + ConfNode *field; + TAILQ_FOREACH (field, &custom->head, next) { + HttpField f; + for (f = HTTP_FIELD_ACCEPT; f < HTTP_FIELD_SIZE; f++) { + if ((strcmp(http_fields[f].config_field, field->val) == 0) || + (strcasecmp(http_fields[f].htp_field, field->val) == 0)) { + http_ctx->fields |= (1ULL << f); + break; + } + } + } + } + } + + if (conf != NULL && ConfNodeLookupChild(conf, "xff") != NULL) { + http_ctx->xff_cfg = SCCalloc(1, sizeof(HttpXFFCfg)); + if (http_ctx->xff_cfg != NULL) { + HttpXFFGetCfg(conf, http_ctx->xff_cfg); + } + } else if (ojc->xff_cfg) { + http_ctx->parent_xff_cfg = ojc->xff_cfg; + } + + output_ctx->data = http_ctx; + output_ctx->DeInit = OutputHttpLogDeinitSub; + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP1); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonHttpLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + JsonHttpLogThread *aft = SCCalloc(1, sizeof(JsonHttpLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogHTTP. \"initdata\" argument NULL"); + goto error_exit; + } + + /* Use the Output Context (file pointer and mutex) */ + aft->httplog_ctx = ((OutputCtx *)initdata)->data; // TODO + + aft->ctx = CreateEveThreadCtx(t, aft->httplog_ctx->eve_ctx); + if (!aft->ctx) { + goto error_exit; + } + + *data = (void *)aft; + return TM_ECODE_OK; + +error_exit: + SCFree(aft); + return TM_ECODE_FAILED; +} + +static TmEcode JsonHttpLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonHttpLogThread *aft = (JsonHttpLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + FreeEveThreadCtx(aft->ctx); + + /* clear memory */ + memset(aft, 0, sizeof(JsonHttpLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +void JsonHttpLogRegister(void) +{ + /* register as child of eve-log */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonHttpLog", "eve-log.http", + OutputHttpLogInitSub, ALPROTO_HTTP1, JsonHttpLogger, JsonHttpLogThreadInit, + JsonHttpLogThreadDeinit, NULL); +} diff --git a/src/app-layer/http/logger.h b/src/app-layer/http/logger.h new file mode 100644 index 000000000000..f4eb7a84c2d6 --- /dev/null +++ b/src/app-layer/http/logger.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_HTTP_H__ +#define __OUTPUT_JSON_HTTP_H__ + +void JsonHttpLogRegister(void); + +bool EveHttpAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js); +void EveHttpLogJSONBodyPrintable(JsonBuilder *js, Flow *f, uint64_t tx_id); +void EveHttpLogJSONBodyBase64(JsonBuilder *js, Flow *f, uint64_t tx_id); + +#endif /* __OUTPUT_JSON_HTTP_H__ */ diff --git a/src/app-layer/http/lua.c b/src/app-layer/http/lua.c new file mode 100644 index 000000000000..e41bf5c2bc2c --- /dev/null +++ b/src/app-layer/http/lua.c @@ -0,0 +1,346 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer/http/parser.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/http/lua.h" + +static int HttpGetRequestHost(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + if (tx->request_hostname == NULL) + return LuaCallbackError(luastate, "no request hostname"); + + return LuaPushStringBuffer( + luastate, bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname)); +} + +static int HttpGetRequestUriRaw(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + if (tx->request_uri == NULL) + return LuaCallbackError(luastate, "no request uri"); + + return LuaPushStringBuffer(luastate, bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); +} + +static int HttpGetRequestUriNormalized(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + return LuaCallbackError(luastate, "no htud in tx"); + + if (htud->request_uri_normalized == NULL || bstr_ptr(htud->request_uri_normalized) == NULL || + bstr_len(htud->request_uri_normalized) == 0) + return LuaCallbackError(luastate, "no normalized uri"); + + return LuaPushStringBuffer(luastate, bstr_ptr(htud->request_uri_normalized), + bstr_len(htud->request_uri_normalized)); +} + +static int HttpGetRequestLine(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + if (tx->request_line == NULL) + return LuaCallbackError(luastate, "no request_line"); + + return LuaPushStringBuffer(luastate, bstr_ptr(tx->request_line), bstr_len(tx->request_line)); +} + +static int HttpGetResponseLine(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + if (tx->response_line == NULL) + return LuaCallbackError(luastate, "no response_line"); + + return LuaPushStringBuffer(luastate, bstr_ptr(tx->response_line), bstr_len(tx->response_line)); +} + +static int HttpGetHeader(lua_State *luastate, int dir) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + const char *name = LuaGetStringArgument(luastate, 1); + if (name == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + + htp_table_t *headers = tx->request_headers; + if (dir == 1) + headers = tx->response_headers; + if (headers == NULL) + return LuaCallbackError(luastate, "tx has no headers"); + + htp_header_t *h = (htp_header_t *)htp_table_get_c(headers, name); + if (h == NULL || bstr_len(h->value) == 0) + return LuaCallbackError(luastate, "header not found"); + + return LuaPushStringBuffer(luastate, bstr_ptr(h->value), bstr_len(h->value)); +} + +static int HttpGetRequestHeader(lua_State *luastate) +{ + return HttpGetHeader(luastate, 0 /* request */); +} + +static int HttpGetResponseHeader(lua_State *luastate) +{ + return HttpGetHeader(luastate, 1 /* response */); +} + +static int HttpGetRawHeaders(lua_State *luastate, int dir) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + return LuaCallbackError(luastate, "no htud in tx"); + + uint8_t *raw = htud->request_headers_raw; + uint32_t raw_len = htud->request_headers_raw_len; + if (dir == 1) { + raw = htud->response_headers_raw; + raw_len = htud->response_headers_raw_len; + } + + if (raw == NULL || raw_len == 0) + return LuaCallbackError(luastate, "no raw headers"); + + return LuaPushStringBuffer(luastate, raw, raw_len); +} + +static int HttpGetRawRequestHeaders(lua_State *luastate) +{ + return HttpGetRawHeaders(luastate, 0); +} + +static int HttpGetRawResponseHeaders(lua_State *luastate) +{ + return HttpGetRawHeaders(luastate, 1); +} + +static int HttpGetHeaders(lua_State *luastate, int dir) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + htp_table_t *table = tx->request_headers; + if (dir == 1) + table = tx->response_headers; + if (tx->request_headers == NULL) + return LuaCallbackError(luastate, "no headers"); + + lua_newtable(luastate); + htp_header_t *h = NULL; + size_t i = 0; + size_t no_of_headers = htp_table_size(table); + for (; i < no_of_headers; i++) { + h = htp_table_get_index(table, i, NULL); + LuaPushStringBuffer(luastate, bstr_ptr(h->name), bstr_len(h->name)); + LuaPushStringBuffer(luastate, bstr_ptr(h->value), bstr_len(h->value)); + lua_settable(luastate, -3); + } + return 1; +} + +/** \brief return request headers as lua table */ +static int HttpGetRequestHeaders(lua_State *luastate) +{ + return HttpGetHeaders(luastate, 0); +} + +/** \brief return response headers as lua table */ +static int HttpGetResponseHeaders(lua_State *luastate) +{ + return HttpGetHeaders(luastate, 1); +} + +static int HttpGetBody(lua_State *luastate, int dir) +{ + HtpBody *body = NULL; + + if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) + return LuaCallbackError(luastate, "error: protocol not http"); + + htp_tx_t *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + return LuaCallbackError(luastate, "no htud in tx"); + + if (dir == 0) + body = &htud->request_body; + else + body = &htud->response_body; + + if (body->first == NULL) + return LuaCallbackError(luastate, "no body"); + + int index = 1; + HtpBodyChunk *chunk = body->first; + lua_newtable(luastate); + while (chunk != NULL) { + lua_pushinteger(luastate, index); + + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len); + LuaPushStringBuffer(luastate, data, data_len); + + lua_settable(luastate, -3); + + chunk = chunk->next; + index++; + } + + if (body->first && body->last) { + lua_pushinteger(luastate, body->first->sbseg.stream_offset); + lua_pushinteger(luastate, body->last->sbseg.stream_offset + body->last->sbseg.segment_len); + return 3; + } else { + return 1; + } +} + +static int HttpGetRequestBody(lua_State *luastate) +{ + return HttpGetBody(luastate, 0); +} + +static int HttpGetResponseBody(lua_State *luastate) +{ + return HttpGetBody(luastate, 1); +} + +/** \brief register http lua extensions in a luastate */ +int LuaRegisterHttpFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, HttpGetRequestHeader); + lua_setglobal(luastate, "HttpGetRequestHeader"); + lua_pushcfunction(luastate, HttpGetResponseHeader); + lua_setglobal(luastate, "HttpGetResponseHeader"); + lua_pushcfunction(luastate, HttpGetRequestLine); + lua_setglobal(luastate, "HttpGetRequestLine"); + lua_pushcfunction(luastate, HttpGetResponseLine); + lua_setglobal(luastate, "HttpGetResponseLine"); + lua_pushcfunction(luastate, HttpGetRawRequestHeaders); + lua_setglobal(luastate, "HttpGetRawRequestHeaders"); + lua_pushcfunction(luastate, HttpGetRawResponseHeaders); + lua_setglobal(luastate, "HttpGetRawResponseHeaders"); + lua_pushcfunction(luastate, HttpGetRequestUriRaw); + lua_setglobal(luastate, "HttpGetRequestUriRaw"); + lua_pushcfunction(luastate, HttpGetRequestUriNormalized); + lua_setglobal(luastate, "HttpGetRequestUriNormalized"); + lua_pushcfunction(luastate, HttpGetRequestHeaders); + lua_setglobal(luastate, "HttpGetRequestHeaders"); + lua_pushcfunction(luastate, HttpGetResponseHeaders); + lua_setglobal(luastate, "HttpGetResponseHeaders"); + lua_pushcfunction(luastate, HttpGetRequestHost); + lua_setglobal(luastate, "HttpGetRequestHost"); + + lua_pushcfunction(luastate, HttpGetRequestBody); + lua_setglobal(luastate, "HttpGetRequestBody"); + lua_pushcfunction(luastate, HttpGetResponseBody); + lua_setglobal(luastate, "HttpGetResponseBody"); + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-http.h b/src/app-layer/http/lua.h similarity index 100% rename from src/util-lua-http.h rename to src/app-layer/http/lua.h diff --git a/src/app-layer/http/parser-body.c b/src/app-layer/http/parser-body.c new file mode 100644 index 000000000000..499d74659d2c --- /dev/null +++ b/src/app-layer/http/parser-body.c @@ -0,0 +1,214 @@ +/* Copyright (C) 2007-2011 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Gurvinder Singh + * \author Pablo Rincon + * \author Brian Rectanus + * + * This file provides a HTTP protocol support for the engine using HTP library. + */ + +#include "suricata-common.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-mem.h" +#include "app-layer/http/parser-body.h" +#include "util/streaming-buffer.h" +#include "util/print.h" + +extern StreamingBufferConfig htp_sbcfg; + +/** + * \brief Append a chunk of body to the HtpBody struct + * + * \param body pointer to the HtpBody holding the list + * \param data pointer to the data of the chunk + * \param len length of the chunk pointed by data + * + * \retval 0 ok + * \retval -1 error + */ +int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, const uint8_t *data, uint32_t len) +{ + SCEnter(); + + HtpBodyChunk *bd = NULL; + + if (len == 0 || data == NULL) { + SCReturnInt(0); + } + + if (body->sb == NULL) { + body->sb = StreamingBufferInit(&htp_sbcfg); + if (body->sb == NULL) + SCReturnInt(-1); + } + + /* New chunk */ + bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); + if (bd == NULL) { + SCReturnInt(-1); + } + + if (StreamingBufferAppend(body->sb, &htp_sbcfg, &bd->sbseg, data, len) != 0) { + HTPFree(bd, sizeof(HtpBodyChunk)); + SCReturnInt(-1); + } + + if (body->first == NULL) { + body->first = body->last = bd; + } else { + body->last->next = bd; + body->last = bd; + } + body->content_len_so_far += len; + + SCLogDebug("body %p", body); + + SCReturnInt(0); +} + +/** + * \brief Print the information and chunks of a Body + * \param body pointer to the HtpBody holding the list + * \retval none + */ +void HtpBodyPrint(HtpBody *body) +{ + if (SCLogDebugEnabled() || 1) { + SCEnter(); + + if (body->first == NULL) + return; + + HtpBodyChunk *cur = NULL; + SCLogDebug("--- Start body chunks at %p ---", body); + printf("--- Start body chunks at %p ---\n", body); + for (cur = body->first; cur != NULL; cur = cur->next) { + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &cur->sbseg, &data, &data_len); + SCLogDebug("Body %p; data %p, len %" PRIu32, body, data, data_len); + printf("Body %p; data %p, len %" PRIu32 "\n", body, data, data_len); + PrintRawDataFp(stdout, data, data_len); + } + SCLogDebug("--- End body chunks at %p ---", body); + } +} + +/** + * \brief Free the information held in the request body + * \param body pointer to the HtpBody holding the list + * \retval none + */ +void HtpBodyFree(const HTPCfgDir *hcfg, HtpBody *body) +{ + SCEnter(); + + SCLogDebug("removing chunks of body %p", body); + + HtpBodyChunk *cur = NULL; + HtpBodyChunk *prev = NULL; + + prev = body->first; + while (prev != NULL) { + cur = prev->next; + HTPFree(prev, sizeof(HtpBodyChunk)); + prev = cur; + } + body->first = body->last = NULL; + + StreamingBufferFree(body->sb, &htp_sbcfg); +} + +/** + * \brief Free request body chunks that are already fully parsed. + * + * \param state htp_state, with reference to our config + * \param body the body to prune + * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response) + * + * \retval none + */ +void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) +{ + SCEnter(); + + if (body == NULL || body->first == NULL) { + SCReturn; + } + + if (body->body_parsed == 0) { + SCReturn; + } + + const HTPCfgDir *cfg = + (direction == STREAM_TOCLIENT) ? &state->cfg->response : &state->cfg->request; + uint32_t min_size = cfg->inspect_min_size; + uint32_t window = cfg->inspect_window; + uint64_t max_window = ((min_size > window) ? min_size : window); + uint64_t in_flight = body->content_len_so_far - body->body_inspected; + + /* Special case. If body_inspected is not being updated, we make sure that + * we prune the body. We allow for some extra size/room as we may be called + * multiple times on uninspected body chunk additions if a large block of + * data was ack'd at once. Want to avoid pruning before inspection. */ + if (in_flight > (max_window * 3)) { + body->body_inspected = body->content_len_so_far - max_window; + } else if (body->body_inspected < max_window) { + SCReturn; + } + + uint64_t left_edge = body->body_inspected; + if (left_edge <= min_size || left_edge <= window) + left_edge = 0; + if (left_edge) + left_edge -= window; + + if (left_edge) { + SCLogDebug("sliding body to offset %" PRIu64, left_edge); + StreamingBufferSlideToOffset(body->sb, &htp_sbcfg, left_edge); + } + + SCLogDebug("pruning chunks of body %p", body); + + HtpBodyChunk *cur = body->first; + while (cur != NULL) { + HtpBodyChunk *next = cur->next; + SCLogDebug("cur %p", cur); + + if (!StreamingBufferSegmentIsBeforeWindow(body->sb, &cur->sbseg)) { + SCLogDebug("not removed"); + break; + } + + body->first = next; + if (body->last == cur) { + body->last = next; + } + + HTPFree(cur, sizeof(HtpBodyChunk)); + + cur = next; + SCLogDebug("removed"); + } + + SCReturn; +} diff --git a/src/app-layer-htp-body.h b/src/app-layer/http/parser-body.h similarity index 100% rename from src/app-layer-htp-body.h rename to src/app-layer/http/parser-body.h diff --git a/src/app-layer/http/parser-file.c b/src/app-layer/http/parser-file.c new file mode 100644 index 000000000000..f73623e2e5e4 --- /dev/null +++ b/src/app-layer/http/parser-file.c @@ -0,0 +1,1258 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * This file provides HTTP protocol file handling support for the engine + * using the HTP library. + */ + +#include "suricata-common.h" +#include "app-layer/http/parser-file.h" +#include "app-layer/http/parser-range.h" +#include "app-layer-events.h" +#include "util/validate.h" + +extern StreamingBufferConfig htp_sbcfg; + +/** + * \brief Open the file with "filename" and pass the first chunk + * of data if any. + * + * \param s http state + * \param filename name of the file + * \param filename_len length of the name + * \param data data chunk (if any) + * \param data_len length of the data portion + * \param direction flow direction + * + * \retval 0 ok + * \retval -1 error + * \retval -2 not handling files on this flow + */ +int HTPFileOpen(HtpState *s, HtpTxUserData *tx, const uint8_t *filename, uint16_t filename_len, + const uint8_t *data, uint32_t data_len, uint64_t txid, uint8_t direction) +{ + int retval = 0; + uint16_t flags = 0; + FileContainer *files = NULL; + + SCLogDebug("data %p data_len %" PRIu32, data, data_len); + + if (direction & STREAM_TOCLIENT) { + files = &tx->files_tc; + flags = FileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOCLIENT); + + // we shall not open a new file if there is a current one + DEBUG_VALIDATE_BUG_ON(tx->file_range != NULL); + } else { + files = &tx->files_ts; + flags = FileFlowFlagsToFlags(tx->tx_data.file_flags, STREAM_TOSERVER); + } + + if (FileOpenFileWithId(files, &htp_sbcfg, s->file_track_id++, filename, filename_len, data, + data_len, flags) != 0) { + retval = -1; + } else { + const HTPCfgDir *cfg; + if (direction & STREAM_TOCLIENT) { + cfg = &s->cfg->response; + } else { + cfg = &s->cfg->request; + } + FileSetInspectSizes(files->tail, cfg->inspect_window, cfg->inspect_min_size); + } + + tx->tx_data.files_opened++; + + SCReturnInt(retval); +} + +/** + * Performs parsing of the content-range value + * + * @param[in] rawvalue + * @param[out] range + * + * @return HTP_OK on success, HTP_ERROR on failure. + */ +int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range) +{ + uint32_t len = bstr_len(rawvalue); + return rs_http_parse_content_range(range, bstr_ptr(rawvalue), len); +} + +/** + * Performs parsing + checking of the content-range value + * + * @param[in] rawvalue + * @param[out] range + * + * @return HTP_OK on success, HTP_ERROR, -2, -3 on failure. + */ +static int HTPParseAndCheckContentRange( + bstr *rawvalue, HTTPContentRange *range, HtpState *s, HtpTxUserData *htud) +{ + int r = HTPParseContentRange(rawvalue, range); + if (r != 0) { + AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, HTTP_DECODER_EVENT_RANGE_INVALID); + s->events++; + SCLogDebug("parsing range failed, going back to normal file"); + return r; + } + /* crparsed.end <= 0 means a range with only size + * this is the answer to an unsatisfied range with the whole file + * crparsed.size <= 0 means an unknown size, so we do not know + * when to close it... + */ + if (range->end <= 0 || range->size <= 0) { + SCLogDebug("range without all information"); + return -2; + } else if (range->end == range->size - 1 && range->start == 0) { + SCLogDebug("range without all information"); + return -3; + } else if (range->start > range->end || range->end > range->size - 1) { + AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, HTTP_DECODER_EVENT_RANGE_INVALID); + s->events++; + SCLogDebug("invalid range"); + return -4; + } + return r; +} + +/** + * \brief Sets range for a file + * + * \param s http state + * \param rawvalue raw header value + * + * \retval 0 ok + * \retval -1 error + */ +int HTPFileOpenWithRange(HtpState *s, HtpTxUserData *txud, const uint8_t *filename, + uint16_t filename_len, const uint8_t *data, uint32_t data_len, uint64_t txid, + bstr *rawvalue, HtpTxUserData *htud) +{ + SCEnter(); + uint16_t flags; + + DEBUG_VALIDATE_BUG_ON(s == NULL); + + // This function is only called STREAM_TOCLIENT from HtpResponseBodyHandle + HTTPContentRange crparsed; + if (HTPParseAndCheckContentRange(rawvalue, &crparsed, s, htud) != 0) { + // range is invalid, fall back to classic open + return HTPFileOpen(s, txud, filename, filename_len, data, data_len, txid, STREAM_TOCLIENT); + } + flags = FileFlowToFlags(s->f, STREAM_TOCLIENT); + FileContainer *files = &txud->files_tc; + + // we open a file for this specific range + if (FileOpenFileWithId(files, &htp_sbcfg, s->file_track_id++, filename, filename_len, data, + data_len, flags) != 0) { + SCReturnInt(-1); + } else { + const HTPCfgDir *cfg = &s->cfg->response; + FileSetInspectSizes(files->tail, cfg->inspect_window, cfg->inspect_min_size); + } + txud->tx_data.files_opened++; + + if (FileSetRange(files, crparsed.start, crparsed.end) < 0) { + SCLogDebug("set range failed"); + } + + // Then, we will try to handle reassembly of different ranges of the same file + htp_tx_t *tx = htp_list_get(s->conn->transactions, txid); + if (!tx) { + SCReturnInt(-1); + } + uint8_t *keyurl; + uint32_t keylen; + if (tx->request_hostname != NULL) { + keylen = bstr_len(tx->request_hostname) + filename_len; + keyurl = SCMalloc(keylen); + if (keyurl == NULL) { + SCReturnInt(-1); + } + memcpy(keyurl, bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname)); + memcpy(keyurl + bstr_len(tx->request_hostname), filename, filename_len); + } else { + // do not reassemble file without host info + SCReturnInt(0); + } + DEBUG_VALIDATE_BUG_ON(htud->file_range); + htud->file_range = HttpRangeContainerOpenFile(keyurl, keylen, s->f, &crparsed, &htp_sbcfg, + filename, filename_len, flags, data, data_len); + SCFree(keyurl); + if (htud->file_range == NULL) { + SCReturnInt(-1); + } + SCReturnInt(0); +} + +/** + * \brief Store a chunk of data in the flow + * + * \param s HtpState + * \param tx HtpTxUserData + * \param data data chunk (if any) + * \param data_len length of the data portion + * \param direction flow direction + * + * \retval 0 ok + * \retval -1 error + * \retval -2 file doesn't need storing + */ +int HTPFileStoreChunk( + HtpState *s, HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, uint8_t direction) +{ + SCEnter(); + + int retval = 0; + int result = 0; + FileContainer *files = NULL; + + if (direction & STREAM_TOCLIENT) { + files = &tx->files_tc; + } else { + files = &tx->files_ts; + } + SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len); + + if (files == NULL) { + SCLogDebug("no files in state"); + retval = -1; + goto end; + } + + if (tx->file_range != NULL) { + if (HttpRangeAppendData(&htp_sbcfg, tx->file_range, data, data_len) < 0) { + SCLogDebug("Failed to append data"); + } + } + + result = FileAppendData(files, &htp_sbcfg, data, data_len); + if (result == -1) { + SCLogDebug("appending data failed"); + retval = -1; + } else if (result == -2) { + retval = -2; + } + SCLogDebug("result %u", result); + +end: + SCReturnInt(retval); +} + +/** \brief close range, add reassembled file if possible + * \retval true if reassembled file was added + * \retval false if no reassembled file was added + */ +bool HTPFileCloseHandleRange(const StreamingBufferConfig *sbcfg, FileContainer *files, + const uint16_t flags, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t data_len) +{ + bool added = false; + if (HttpRangeAppendData(sbcfg, c, data, data_len) < 0) { + SCLogDebug("Failed to append data"); + } + if (c->container) { + // we only call HttpRangeClose if we may some new data + // ie we do not call it if we skipped all this range request + THashDataLock(c->container->hdata); + if (c->container->error) { + SCLogDebug("range in ERROR state"); + } + File *ranged = HttpRangeClose(sbcfg, c, flags); + if (ranged && files) { + /* HtpState owns the constructed file now */ + FileContainerAdd(files, ranged); + added = true; + } + DEBUG_VALIDATE_BUG_ON(ranged && !files); + THashDataUnlock(c->container->hdata); + } + return added; +} + +/** + * \brief Close the file in the flow + * + * \param tx HtpTxUserData + * \param data data chunk if any + * \param data_len length of the data portion + * \param flags flags to indicate events + * \param direction flow direction + * + * Currently on the FLOW_FILE_TRUNCATED flag is implemented, indicating + * that the file isn't complete but we're stopping storing it. + * + * \retval 0 ok + * \retval -1 error + * \retval -2 not storing files on this flow/tx + */ +int HTPFileClose(HtpState *s, HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, + uint8_t flags, uint8_t direction) +{ + SCEnter(); + + SCLogDebug("flags %04x FILE_TRUNCATED %s", flags, (flags & FILE_TRUNCATED) ? "true" : "false"); + + int retval = 0; + int result = 0; + FileContainer *files = NULL; + + if (direction & STREAM_TOCLIENT) { + files = &tx->files_tc; + } else { + files = &tx->files_ts; + } + + SCLogDebug("files %p data %p data_len %" PRIu32, files, data, data_len); + + if (files == NULL) { + retval = -1; + goto end; + } + + result = FileCloseFile(files, &htp_sbcfg, data, data_len, flags); + if (result == -1) { + retval = -1; + } else if (result == -2) { + retval = -2; + } + SCLogDebug("result %u", result); + + if (tx->file_range != NULL) { + bool added = + HTPFileCloseHandleRange(&htp_sbcfg, files, flags, tx->file_range, data, data_len); + if (added) { + tx->tx_data.files_opened++; + } + HttpRangeFreeBlock(tx->file_range); + tx->file_range = NULL; + } + +end: + SCReturnInt(retval); +} + +#ifdef UNITTESTS +#include "stream-tcp.h" +#include "app-layer-parser.h" +#include "util/unittest-helper.h" + +static int HTPFileParserTest01(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 215\r\n" + "\r\n" + "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n"; + + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "filecontent\r\n" + "-----------------------------277531038314945--"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + HtpState *http_state = NULL; + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +static int HTPFileParserTest02(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 337\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"email\"\r\n" + "\r\n" + "someaddress@somedomain.lan\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + + uint8_t httpbuf4[] = "filecontent\r\n" + "-----------------------------277531038314945--"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +static int HTPFileParserTest03(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 337\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"email\"\r\n" + "\r\n" + "someaddress@somedomain.lan\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + + uint8_t httpbuf4[] = "file"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + uint8_t httpbuf5[] = "content\r\n"; + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + + uint8_t httpbuf6[] = "-----------------------------277531038314945--"; + uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->files_ts.head); + FAIL_IF_NULL(tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); + FAIL_IF(FileDataSize(tx_ud->files_ts.head) != 11); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +static int HTPFileParserTest04(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 373\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"email\"\r\n" + "\r\n" + "someaddress@somedomain.lan\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + + uint8_t httpbuf4[] = "file0123456789abcdefghijklmnopqrstuvwxyz"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + uint8_t httpbuf5[] = "content\r\n"; + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + + uint8_t httpbuf6[] = "-----------------------------277531038314945--"; + uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->files_ts.head); + FAIL_IF_NULL(tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +static int HTPFileParserTest05(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 544\r\n" + "\r\n" + "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n" + "filecontent\r\n" + "-----------------------------277531038314945\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; " + "filename=\"somepicture2.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n" + "FILECONTENT\r\n" + "-----------------------------277531038314945--"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->files_ts.head); + FAIL_IF_NULL(tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); + + FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail); + + FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) != + 1); + + FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != + 1); + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test first multipart part contains file but doesn't end in first chunk */ +static int HTPFileParserTest06(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 544\r\n" + "\r\n" + "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n" + "filecontent\r\n" + "-----------------------------27753103831494"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "5\r\nContent-Disposition: form-data; name=\"uploadfile_1\"; " + "filename=\"somepicture2.jpg\"\r\n" + "Content-Type: image/jpeg\r\n" + "\r\n" + "FILECONTENT\r\n" + "-----------------------------277531038314945--"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->files_ts.head); + FAIL_IF_NULL(tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); + + FAIL_IF(tx_ud->files_ts.head == tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.head->next != tx_ud->files_ts.tail); + + FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.head->sb, (uint8_t *)"filecontent", 11) != + 1); + + FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != + 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test POST, but not multipart */ +static int HTPFileParserTest07(void) +{ + uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Length: 11\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "FILECONTENT"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->files_ts.head); + FAIL_IF_NULL(tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); + + FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != + 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +static int HTPFileParserTest08(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 215\r\n" + "\r\n" + "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Content-Type: image/jpeg\r\n"; + + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "filecontent\r\n\r\n" + "-----------------------------277531038314945--"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + HtpState *http_state = NULL; + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); + FAIL_IF_NULL(tx); + + AppLayerDecoderEvents *decoder_events = + AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx); + FAIL_IF_NULL(decoder_events); + + FAIL_IF(decoder_events->cnt != 2); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test invalid header: Somereallylongheaderstr: has no value */ +static int HTPFileParserTest09(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 337\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"email\"\r\n" + "\r\n" + "someaddress@somedomain.lan\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Somereallylongheaderstr:\r\n" + "\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + + uint8_t httpbuf4[] = "filecontent\r\n" + "-----------------------------277531038314945--"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); + FAIL_IF_NULL(tx); + + AppLayerDecoderEvents *decoder_events = + AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx); + FAIL_IF_NULL(decoder_events); + + FAIL_IF(decoder_events->cnt != 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test empty entries */ +static int HTPFileParserTest10(void) +{ + uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" + "Content-Length: 337\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + uint8_t httpbuf2[] = "-----------------------------277531038314945\r\n" + "\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + uint8_t httpbuf3[] = "-----------------------------277531038314945\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" + "Somereallylongheaderstr: with a good value\r\n" + "\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + + uint8_t httpbuf4[] = "filecontent\r\n" + "-----------------------------277531038314945--"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); + FAIL_IF_NULL(tx); + AppLayerDecoderEvents *decoder_events = + AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, tx); + FAIL_IF_NOT_NULL(decoder_events); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test filedata cut in two pieces */ +static int HTPFileParserTest11(void) +{ + uint8_t httpbuf1[] = + "POST /upload.cgi HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Length: 1102\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + uint8_t httpbuf2[] = "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + uint8_t httpbuf3[] = + "Content-Disposition: form-data; name=\"PROGRESS_URL\"\r\n" + "\r\n" + "http://somserver.com/" + "progress.php?UPLOAD_IDENTIFIER=XXXXXXXXX.XXXXXXXXXX.XXXXXXXX.XX.X\r\n" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"DESTINATION_DIR\"\r\n" + "\r\n" + "10\r\n" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"js_enabled\"\r\n" + "\r\n" + "1" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"signature\"\r\n" + "\r\n" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"upload_files\"\r\n" + "\r\n" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"terms\"\r\n" + "\r\n" + "1" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"file[]\"\r\n" + "\r\n" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"description[]\"\r\n" + "\r\n" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo\r\n" + "Content-Disposition: form-data; name=\"upload_file[]\"; filename=\"filename.doc\"\r\n" + "Content-Type: application/msword\r\n" + "\r\n" + "FILE"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + + uint8_t httpbuf4[] = "CONTENT\r\n" + "------WebKitFormBoundaryBRDbP74mBhBxsIdo--"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3); + FAIL_IF_NOT(r == 0); + + SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); + FAIL_IF_NOT(r == 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + + void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); + FAIL_IF_NULL(txtmp); + + AppLayerDecoderEvents *decoder_events = + AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); + FAIL_IF_NOT_NULL(decoder_events); + + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NULL(tx->request_method); + + FAIL_IF(memcmp(bstr_util_strdup_to_c(tx->request_method), "POST", 4) != 0); + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->files_ts.head); + FAIL_IF_NULL(tx_ud->files_ts.tail); + FAIL_IF(tx_ud->files_ts.tail->state != FILE_STATE_CLOSED); + + FAIL_IF(StreamingBufferCompareRawData(tx_ud->files_ts.tail->sb, (uint8_t *)"FILECONTENT", 11) != + 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +void AppLayerHtpFileRegisterTests(void); +#include "tests/app-layer-htp-file.c" +#endif /* UNITTESTS */ + +void HTPFileParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01); + UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02); + UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03); + UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04); + UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05); + UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06); + UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07); + UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08); + UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09); + UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10); + UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11); + AppLayerHtpFileRegisterTests(); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer/http/parser-file.h b/src/app-layer/http/parser-file.h new file mode 100644 index 000000000000..5330008a12e0 --- /dev/null +++ b/src/app-layer/http/parser-file.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2007-2011 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#ifndef __APP_LAYER_HTP_FILE_H__ +#define __APP_LAYER_HTP_FILE_H__ + +#include "app-layer/http/parser.h" + +int HTPFileOpen(HtpState *, HtpTxUserData *, const uint8_t *, uint16_t, const uint8_t *, uint32_t, + uint64_t, uint8_t); +int HTPFileOpenWithRange(HtpState *, HtpTxUserData *, const uint8_t *, uint16_t, const uint8_t *, + uint32_t, uint64_t, bstr *rawvalue, HtpTxUserData *htud); +bool HTPFileCloseHandleRange(const StreamingBufferConfig *sbcfg, FileContainer *, const uint16_t, + HttpRangeContainerBlock *, const uint8_t *, uint32_t); +int HTPFileStoreChunk(HtpState *, HtpTxUserData *, const uint8_t *, uint32_t, uint8_t); + +int HTPParseContentRange(bstr *rawvalue, HTTPContentRange *range); +int HTPFileClose(HtpState *, HtpTxUserData *tx, const uint8_t *data, uint32_t data_len, + uint8_t flags, uint8_t direction); + +void HTPFileParserRegisterTests(void); + +#endif /* __APP_LAYER_HTP_FILE_H__ */ diff --git a/src/app-layer/http/parser-libhtp.c b/src/app-layer/http/parser-libhtp.c new file mode 100644 index 000000000000..8a27222740c5 --- /dev/null +++ b/src/app-layer/http/parser-libhtp.c @@ -0,0 +1,174 @@ +/* + * We are using this file to hold APIs copied from libhtp 0.5.x. + */ + +/*************************************************************************** + * Copyright (c) 2009-2010 Open Information Security Foundation + * Copyright (c) 2010-2013 Qualys, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the Qualys, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************************************************************************/ + +/** + * \file + * + * \author Anoop Saldanha + * + * APIs from libhtp 0.5.x. + */ + +#include "suricata-common.h" +#include +#include "app-layer/http/parser-libhtp.h" + +/** + * \brief Generates the normalized uri. + * + * Libhtp doesn't recreate the whole normalized uri and save it. + * That duty has now been passed to us. A lot of this code has been + * copied from libhtp. + * + * Keep an eye out on the tx->parsed_uri struct and how the parameters + * in it are generated, just in case some modifications are made to + * them in the future. + * + * \param uri_include_all boolean to indicate if scheme, username/password, + hostname and port should be part of the buffer + */ +bstr *SCHTPGenerateNormalizedUri(htp_tx_t *tx, htp_uri_t *uri, bool uri_include_all) +{ + if (uri == NULL) + return NULL; + + // On the first pass determine the length of the final string + size_t len = 0; + + if (uri_include_all) { + if (uri->scheme != NULL) { + len += bstr_len(uri->scheme); + len += 3; // "://" + } + + if ((uri->username != NULL) || (uri->password != NULL)) { + if (uri->username != NULL) { + len += bstr_len(uri->username); + } + + len += 1; // ":" + + if (uri->password != NULL) { + len += bstr_len(uri->password); + } + + len += 1; // "@" + } + + if (uri->hostname != NULL) { + len += bstr_len(uri->hostname); + } + + if (uri->port != NULL) { + len += 1; // ":" + len += bstr_len(uri->port); + } + } + + if (uri->path != NULL) { + len += bstr_len(uri->path); + } + + if (uri->query != NULL) { + len += 1; // "?" + len += bstr_len(uri->query); + } + + if (uri->fragment != NULL) { + len += 1; // "#" + len += bstr_len(uri->fragment); + } + + // On the second pass construct the string + /* FIXME in memcap */ + bstr *r = bstr_alloc(len); + if (r == NULL) { + return NULL; + } + + if (uri_include_all) { + if (uri->scheme != NULL) { + bstr_add_noex(r, uri->scheme); + bstr_add_c_noex(r, "://"); + } + + if ((uri->username != NULL) || (uri->password != NULL)) { + if (uri->username != NULL) { + bstr_add_noex(r, uri->username); + } + + bstr_add_c_noex(r, ":"); + + if (uri->password != NULL) { + bstr_add_noex(r, uri->password); + } + + bstr_add_c_noex(r, "@"); + } + + if (uri->hostname != NULL) { + bstr_add_noex(r, uri->hostname); + } + + if (uri->port != NULL) { + bstr_add_c_noex(r, ":"); + bstr_add_noex(r, uri->port); + } + } + + if (uri->path != NULL) { + bstr_add_noex(r, uri->path); + } + + if (uri->query != NULL) { + bstr *query = bstr_dup(uri->query); + if (query) { + uint64_t flags = 0; + htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags); + bstr_add_c_noex(r, "?"); + bstr_add_noex(r, query); + bstr_free(query); + } + } + + if (uri->fragment != NULL) { + bstr_add_c_noex(r, "#"); + bstr_add_noex(r, uri->fragment); + } + + return r; +} diff --git a/src/app-layer-htp-libhtp.h b/src/app-layer/http/parser-libhtp.h similarity index 100% rename from src/app-layer-htp-libhtp.h rename to src/app-layer/http/parser-libhtp.h diff --git a/src/app-layer/http/parser-mem.c b/src/app-layer/http/parser-mem.c new file mode 100644 index 000000000000..659900837469 --- /dev/null +++ b/src/app-layer/http/parser-mem.c @@ -0,0 +1,197 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Eric Leblond + * + * This file provides a memory handling for the HTTP protocol support. + */ + +#include "suricata-common.h" +#include "app-layer/http/parser-mem.h" + +#include "conf.h" +#include "util/misc.h" +#include "util/debug.h" + +SC_ATOMIC_DECLARE(uint64_t, htp_config_memcap); +SC_ATOMIC_DECLARE(uint64_t, htp_memuse); +SC_ATOMIC_DECLARE(uint64_t, htp_memcap); + +void HTPParseMemcap(void) +{ + const char *conf_val; + + SC_ATOMIC_INIT(htp_config_memcap); + + /** set config values for memcap, prealloc and hash_size */ + uint64_t memcap; + if ((ConfGet("app-layer.protocols.http.memcap", &conf_val)) == 1) { + if (ParseSizeStringU64(conf_val, &memcap) < 0) { + SCLogError("Error parsing http.memcap " + "from conf file - %s. Killing engine", + conf_val); + exit(EXIT_FAILURE); + } else { + SC_ATOMIC_SET(htp_config_memcap, memcap); + } + SCLogInfo("HTTP memcap: %" PRIu64, SC_ATOMIC_GET(htp_config_memcap)); + } else { + /* default to unlimited */ + SC_ATOMIC_SET(htp_config_memcap, 0); + } + + SC_ATOMIC_INIT(htp_memuse); + SC_ATOMIC_INIT(htp_memcap); +} + +static void HTPIncrMemuse(uint64_t size) +{ + (void)SC_ATOMIC_ADD(htp_memuse, size); + return; +} + +static void HTPDecrMemuse(uint64_t size) +{ + (void)SC_ATOMIC_SUB(htp_memuse, size); + return; +} + +uint64_t HTPMemuseGlobalCounter(void) +{ + uint64_t tmpval = SC_ATOMIC_GET(htp_memuse); + return tmpval; +} + +uint64_t HTPMemcapGlobalCounter(void) +{ + uint64_t tmpval = SC_ATOMIC_GET(htp_memcap); + return tmpval; +} + +/** + * \brief Check if alloc'ing "size" would mean we're over memcap + * + * \retval 1 if in bounds + * \retval 0 if not in bounds + */ +static int HTPCheckMemcap(uint64_t size) +{ + uint64_t memcapcopy = SC_ATOMIC_GET(htp_config_memcap); + if (memcapcopy == 0 || size + SC_ATOMIC_GET(htp_memuse) <= memcapcopy) + return 1; + (void)SC_ATOMIC_ADD(htp_memcap, 1); + return 0; +} + +/** + * \brief Update memcap value + * + * \param size new memcap value + */ +int HTPSetMemcap(uint64_t size) +{ + if (size == 0 || (uint64_t)SC_ATOMIC_GET(htp_memuse) < size) { + SC_ATOMIC_SET(htp_config_memcap, size); + return 1; + } + return 0; +} + +/** + * \brief Update memcap value + * + * \retval memcap value + */ +uint64_t HTPGetMemcap(void) +{ + uint64_t memcapcopy = SC_ATOMIC_GET(htp_config_memcap); + return memcapcopy; +} + +void *HTPMalloc(size_t size) +{ + void *ptr = NULL; + + if (HTPCheckMemcap((uint32_t)size) == 0) + return NULL; + + ptr = SCMalloc(size); + + if (unlikely(ptr == NULL)) + return NULL; + + HTPIncrMemuse((uint64_t)size); + + return ptr; +} + +void *HTPCalloc(size_t n, size_t size) +{ + void *ptr = NULL; + + if (HTPCheckMemcap((uint32_t)(n * size)) == 0) + return NULL; + + ptr = SCCalloc(n, size); + + if (unlikely(ptr == NULL)) + return NULL; + + HTPIncrMemuse((uint64_t)(n * size)); + + return ptr; +} + +void *HTPRealloc(void *ptr, size_t orig_size, size_t size) +{ + if (size > orig_size) { + if (HTPCheckMemcap((uint32_t)(size - orig_size)) == 0) + return NULL; + } + + void *rptr = SCRealloc(ptr, size); + if (rptr == NULL) + return NULL; + + if (size > orig_size) { + HTPIncrMemuse((uint64_t)(size - orig_size)); + } else { + HTPDecrMemuse((uint64_t)(orig_size - size)); + } + + return rptr; +} + +void HTPFree(void *ptr, size_t size) +{ + SCFree(ptr); + + HTPDecrMemuse((uint64_t)size); +} + +/** + * @} + */ diff --git a/src/app-layer-htp-mem.h b/src/app-layer/http/parser-mem.h similarity index 100% rename from src/app-layer-htp-mem.h rename to src/app-layer/http/parser-mem.h diff --git a/src/app-layer/http/parser-range.c b/src/app-layer/http/parser-range.c new file mode 100644 index 000000000000..74e3d8051344 --- /dev/null +++ b/src/app-layer/http/parser-range.c @@ -0,0 +1,634 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Philippe Antoine + */ + +#include "suricata-common.h" +#include "app-layer/http/parser-range.h" +#include "util/misc.h" //ParseSizeStringU64 +#include "util/thash.h" //HashTable +#include "util/memcmp.h" //SCBufferCmp +#include "util/hash-string.h" //StringHashDjb2 +#include "util/validate.h" //DEBUG_VALIDATE_BUG_ON +#include "util/byte.h" //StringParseUint32 + +typedef struct ContainerTHashTable { + THashTableContext *ht; + uint32_t timeout; +} ContainerTHashTable; + +// globals +ContainerTHashTable ContainerUrlRangeList; + +static void HttpRangeBlockDerefContainer(HttpRangeContainerBlock *b); + +#define CONTAINER_URLRANGE_HASH_SIZE 256 + +int HttpRangeContainerBufferCompare(HttpRangeContainerBuffer *a, HttpRangeContainerBuffer *b) +{ + // lexical order : start, buflen, offset + if (a->start > b->start) + return 1; + if (a->start < b->start) + return -1; + if (a->buflen > b->buflen) + return 1; + if (a->buflen < b->buflen) + return -1; + if (a->offset > b->offset) + return 1; + if (a->offset < b->offset) + return -1; + return 0; +} + +RB_GENERATE(HTTP_RANGES, HttpRangeContainerBuffer, rb, HttpRangeContainerBufferCompare); + +static int ContainerUrlRangeSet(void *dst, void *src) +{ + HttpRangeContainerFile *src_s = src; + HttpRangeContainerFile *dst_s = dst; + dst_s->len = src_s->len; + dst_s->key = SCMalloc(dst_s->len); + if (dst_s->key == NULL) + return -1; + memcpy(dst_s->key, src_s->key, dst_s->len); + dst_s->files = FileContainerAlloc(); + if (dst_s->files == NULL) { + SCFree(dst_s->key); + return -1; + } + RB_INIT(&dst_s->fragment_tree); + dst_s->flags = 0; + dst_s->lastsize = 0; + dst_s->totalsize = 0; + dst_s->hdata = NULL; + dst_s->error = false; + return 0; +} + +static bool ContainerUrlRangeCompare(void *a, void *b) +{ + const HttpRangeContainerFile *as = a; + const HttpRangeContainerFile *bs = b; + + /* ranges in the error state should not be found so they can + * be evicted */ + if (as->error || bs->error) { + return false; + } + + if (SCBufferCmp(as->key, as->len, bs->key, bs->len) == 0) { + return true; + } + return false; +} + +static uint32_t ContainerUrlRangeHash(void *s) +{ + HttpRangeContainerFile *cur = s; + uint32_t h = StringHashDjb2(cur->key, cur->len); + return h; +} + +// base data stays in hash +static void ContainerUrlRangeFree(void *s) +{ + HttpRangeContainerBuffer *range = NULL, *tmp = NULL; + + HttpRangeContainerFile *cu = s; + SCFree(cu->key); + cu->key = NULL; + FileContainerFree(cu->files, cu->sbcfg); + cu->files = NULL; + RB_FOREACH_SAFE (range, HTTP_RANGES, &cu->fragment_tree, tmp) { + RB_REMOVE(HTTP_RANGES, &cu->fragment_tree, range); + SCFree(range->buffer); + (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, range->buflen); + SCFree(range); + } +} + +static inline bool ContainerValueRangeTimeout(HttpRangeContainerFile *cu, const SCTime_t ts) +{ + // we only timeout if we have no flow referencing us + if ((uint32_t)SCTIME_SECS(ts) > cu->expire || cu->error) { + if (SC_ATOMIC_GET(cu->hdata->use_cnt) == 0) { + DEBUG_VALIDATE_BUG_ON(cu->files == NULL); + return true; + } + } + return false; +} + +static void ContainerUrlRangeUpdate(HttpRangeContainerFile *cu, uint32_t expire) +{ + cu->expire = expire; +} + +#define HTTP_RANGE_DEFAULT_TIMEOUT 60 +#define HTTP_RANGE_DEFAULT_MEMCAP 100 * 1024 * 1024 + +void HttpRangeContainersInit(void) +{ + SCLogDebug("containers start"); + const char *str = NULL; + uint64_t memcap = HTTP_RANGE_DEFAULT_MEMCAP; + uint32_t timeout = HTTP_RANGE_DEFAULT_TIMEOUT; + if (ConfGet("app-layer.protocols.http.byterange.memcap", &str) == 1) { + if (ParseSizeStringU64(str, &memcap) < 0) { + SCLogWarning("memcap value cannot be deduced: %s," + " resetting to default", + str); + memcap = 0; + } + } + if (ConfGet("app-layer.protocols.http.byterange.timeout", &str) == 1) { + size_t slen = strlen(str); + if (slen > UINT16_MAX || StringParseUint32(&timeout, 10, (uint16_t)slen, str) <= 0) { + SCLogWarning("timeout value cannot be deduced: %s," + " resetting to default", + str); + timeout = 0; + } + } + + ContainerUrlRangeList.ht = + THashInit("app-layer.protocols.http.byterange", sizeof(HttpRangeContainerFile), + ContainerUrlRangeSet, ContainerUrlRangeFree, ContainerUrlRangeHash, + ContainerUrlRangeCompare, false, memcap, CONTAINER_URLRANGE_HASH_SIZE); + ContainerUrlRangeList.timeout = timeout; + + SCLogDebug("containers started"); +} + +void HttpRangeContainersDestroy(void) +{ + THashShutdown(ContainerUrlRangeList.ht); +} + +uint32_t HttpRangeContainersTimeoutHash(const SCTime_t ts) +{ + SCLogDebug("timeout: starting"); + uint32_t cnt = 0; + + for (uint32_t i = 0; i < ContainerUrlRangeList.ht->config.hash_size; i++) { + THashHashRow *hb = &ContainerUrlRangeList.ht->array[i]; + + if (HRLOCK_TRYLOCK(hb) != 0) + continue; + /* hash bucket is now locked */ + THashData *h = hb->head; + while (h) { + DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(h->use_cnt) > (uint32_t)INT_MAX); + THashData *n = h->next; + THashDataLock(h); + if (ContainerValueRangeTimeout(h->data, ts)) { + /* remove from the hash */ + if (h->prev != NULL) + h->prev->next = h->next; + if (h->next != NULL) + h->next->prev = h->prev; + if (hb->head == h) + hb->head = h->next; + if (hb->tail == h) + hb->tail = h->prev; + h->next = NULL; + h->prev = NULL; + // we should log the timed out file somehow... + // but it does not belong to any flow... + SCLogDebug("timeout: removing range %p", h); + ContainerUrlRangeFree(h->data); // TODO do we need a "RECYCLE" func? + DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(h->use_cnt) > (uint32_t)INT_MAX); + THashDataUnlock(h); + THashDataMoveToSpare(ContainerUrlRangeList.ht, h); + } else { + THashDataUnlock(h); + } + h = n; + } + HRLOCK_UNLOCK(hb); + } + + SCLogDebug("timeout: ending"); + return cnt; +} + +/** + * \returns locked data + */ +static void *HttpRangeContainerUrlGet(const uint8_t *key, uint32_t keylen, const Flow *f) +{ + const SCTime_t ts = f->lastts; + HttpRangeContainerFile lookup; + memset(&lookup, 0, sizeof(lookup)); + // cast so as not to have const in the structure + lookup.key = (uint8_t *)key; + lookup.len = keylen; + struct THashDataGetResult res = THashGetFromHash(ContainerUrlRangeList.ht, &lookup); + if (res.data) { + // nothing more to do if (res.is_new) + ContainerUrlRangeUpdate(res.data->data, SCTIME_SECS(ts) + ContainerUrlRangeList.timeout); + HttpRangeContainerFile *c = res.data->data; + c->hdata = res.data; + SCLogDebug("c %p", c); + return res.data->data; + } + return NULL; +} + +static HttpRangeContainerBlock *HttpRangeOpenFileAux(HttpRangeContainerFile *c, uint64_t start, + uint64_t end, uint64_t total, const StreamingBufferConfig *sbcfg, const uint8_t *name, + uint16_t name_len, uint16_t flags) +{ + if (c->files != NULL && c->files->tail == NULL) { + /* this is the first request, we open a single file in the file container + * this could be part of ContainerUrlRangeSet if we could have + * all the arguments there + */ + if (FileOpenFileWithId(c->files, sbcfg, 0, name, name_len, NULL, 0, flags) != 0) { + SCLogDebug("open file for range failed"); + return NULL; + } + } + HttpRangeContainerBlock *curf = SCCalloc(1, sizeof(HttpRangeContainerBlock)); + if (curf == NULL) { + c->error = true; + return NULL; + } + curf->files = NULL; + if (total > c->totalsize) { + // we grow to the maximum size indicated by different range requests + // we could add some warning/app-layer event in this case where + // different range requests indicate different total sizes + c->totalsize = total; + } + const uint64_t buflen = end - start + 1; + + /* The big part of this function is now to decide which kind of HttpRangeContainerBlock + * we will return : + * - skipping already processed data + * - storing out of order data for later use + * - directly appending to the file if we are at the right offset + */ + if (start == c->lastsize && c->files != NULL) { + // easy case : append to current file + curf->container = c; + // If we see 2 duplicate range requests with the same range, + // the first one takes the ownership of the files container + // protected by the lock from caller HTPFileOpenWithRange + curf->files = c->files; + c->files = NULL; + return curf; + } else if (start < c->lastsize && c->lastsize - start >= buflen) { + // only overlap + // redundant to be explicit that this block is independent + curf->toskip = buflen; + return curf; + } else if (start < c->lastsize && c->lastsize - start < buflen && c->files != NULL) { + // some overlap, then some data to append to the file + curf->toskip = c->lastsize - start; + curf->files = c->files; + c->files = NULL; + curf->container = c; + return curf; + } + // Because we are not in the previous cases, we will store the data for later use + + // block/range to be inserted in ordered linked list + if (!(THASH_CHECK_MEMCAP(ContainerUrlRangeList.ht, buflen))) { + // skips this range + curf->toskip = buflen; + return curf; + } + curf->container = c; + + HttpRangeContainerBuffer *range = SCCalloc(1, sizeof(HttpRangeContainerBuffer)); + if (range == NULL) { + c->error = true; + SCFree(curf); + return NULL; + } + + (void)SC_ATOMIC_ADD(ContainerUrlRangeList.ht->memuse, buflen); + range->buffer = SCMalloc(buflen); + if (range->buffer == NULL) { + c->error = true; + SCFree(curf); + SCFree(range); + (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, buflen); + return NULL; + } + range->buflen = buflen; + range->start = start; + range->offset = 0; + range->gap = 0; + curf->current = range; + return curf; +} + +static HttpRangeContainerBlock *HttpRangeOpenFile(HttpRangeContainerFile *c, uint64_t start, + uint64_t end, uint64_t total, const StreamingBufferConfig *sbcfg, const uint8_t *name, + uint16_t name_len, uint16_t flags, const uint8_t *data, uint32_t len) +{ + HttpRangeContainerBlock *r = + HttpRangeOpenFileAux(c, start, end, total, sbcfg, name, name_len, flags); + if (HttpRangeAppendData(sbcfg, r, data, len) < 0) { + SCLogDebug("Failed to append data while opening"); + } + return r; +} + +HttpRangeContainerBlock *HttpRangeContainerOpenFile(const uint8_t *key, uint32_t keylen, + const Flow *f, const HTTPContentRange *crparsed, const StreamingBufferConfig *sbcfg, + const uint8_t *name, uint16_t name_len, uint16_t flags, const uint8_t *data, + uint32_t data_len) +{ + HttpRangeContainerFile *file_range_container = HttpRangeContainerUrlGet(key, keylen, f); + if (file_range_container == NULL) { + // probably reached memcap + return NULL; + } + file_range_container->sbcfg = sbcfg; + + HttpRangeContainerBlock *r = HttpRangeOpenFile(file_range_container, crparsed->start, + crparsed->end, crparsed->size, sbcfg, name, name_len, flags, data, data_len); + SCLogDebug("s->file_range == %p", r); + if (r == NULL) { + THashDecrUsecnt(file_range_container->hdata); + DEBUG_VALIDATE_BUG_ON( + SC_ATOMIC_GET(file_range_container->hdata->use_cnt) > (uint32_t)INT_MAX); + THashDataUnlock(file_range_container->hdata); + + // probably reached memcap + return NULL; + /* in some cases we don't take a reference, so decr use cnt */ + } else if (r->container == NULL) { + THashDecrUsecnt(file_range_container->hdata); + } else { + SCLogDebug("container %p use_cnt %u", r, SC_ATOMIC_GET(r->container->hdata->use_cnt)); + DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(r->container->hdata->use_cnt) > (uint32_t)INT_MAX); + } + + /* we're done, so unlock. But since we have a reference in s->file_range keep use_cnt. */ + THashDataUnlock(file_range_container->hdata); + return r; +} + +int HttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, + const uint8_t *data, uint32_t len) +{ + if (len == 0) { + return 0; + } + // first check if we need to skip all bytes + if (c->toskip >= len) { + c->toskip -= len; + return 0; + } + // then if we need to skip only some bytes + if (c->toskip > 0) { + int r = 0; + if (c->files) { + if (data == NULL) { + // gap overlapping already known data + r = FileAppendData(c->files, sbcfg, NULL, len - c->toskip); + } else { + r = FileAppendData(c->files, sbcfg, data + c->toskip, len - c->toskip); + } + } + c->toskip = 0; + return r; + } + // If we are owning the file to append to it, let's do it + if (c->files) { + SCLogDebug("update files (FileAppendData)"); + return FileAppendData(c->files, sbcfg, data, len); + } + // Maybe we were in the skipping case, + // but we get more data than expected and had set c->toskip = 0 + // so we need to check for last case with something to do + if (c->current) { + // So we have a current allocated buffer to copy to + // in the case of an unordered range being handled + SCLogDebug("update current: adding %u bytes to block %p", len, c); + // GAP "data" + if (data == NULL) { + // just save the length of the gap + c->current->gap += len; + // data, but we're not yet complete + } else if (c->current->offset + len < c->current->buflen) { + memcpy(c->current->buffer + c->current->offset, data, len); + c->current->offset += len; + // data, we're complete + } else if (c->current->offset + len == c->current->buflen) { + memcpy(c->current->buffer + c->current->offset, data, len); + c->current->offset += len; + // data, more than expected + } else { + memcpy(c->current->buffer + c->current->offset, data, + c->current->buflen - c->current->offset); + c->current->offset = c->current->buflen; + } + } + return 0; +} + +static void HttpRangeFileClose( + const StreamingBufferConfig *sbcfg, HttpRangeContainerFile *c, uint16_t flags) +{ + SCLogDebug("closing range %p flags %04x", c, flags); + DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(c->hdata->use_cnt) == 0); + // move ownership of file c->files->head to caller + FileCloseFile(c->files, sbcfg, NULL, 0, c->flags | flags); + c->files->head = NULL; + c->files->tail = NULL; +} + +/** + * \note if `f` is non-NULL, the ownership of the file is transferred to the caller. + */ +File *HttpRangeClose(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags) +{ + SCLogDebug("c %p c->container %p c->current %p", c, c->container, c->current); + + DEBUG_VALIDATE_BUG_ON(c->container == NULL); + + /* we're processing an OOO chunk, won't be able to get us a full file just yet */ + if (c->current) { + SCLogDebug("processing ooo chunk as c->current is set %p", c->current); + // some out-or-order range is finished + if (c->container->lastsize >= c->current->start + c->current->offset) { + // if the range has become obsolete because we received the data already + // we just free it + (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, c->current->buflen); + SCFree(c->current->buffer); + SCFree(c->current); + c->current = NULL; + SCLogDebug("c->current was obsolete"); + return NULL; + } else { + /* otherwise insert in red and black tree. If res != NULL, the insert + failed because its a dup. */ + HttpRangeContainerBuffer *res = + HTTP_RANGES_RB_INSERT(&c->container->fragment_tree, c->current); + if (res) { + SCLogDebug("duplicate range fragment"); + (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, c->current->buflen); + SCFree(c->current->buffer); + SCFree(c->current); + c->current = NULL; + return NULL; + } + SCLogDebug("inserted range fragment"); + c->current = NULL; + if (c->container->files == NULL) { + // we have to wait for the flow owning the file + return NULL; + } + if (c->container->files->tail == NULL) { + // file has already been closed meanwhile + return NULL; + } + // keep on going, maybe this out of order chunk + // became the missing part between open and close + } + SCLogDebug("c->current was set, file incomplete so return NULL"); + } else if (c->toskip > 0) { + // was only an overlapping range, truncated before new bytes + SCLogDebug("c->toskip %" PRIu64, c->toskip); + if (c->files) { + // if we expected new bytes after overlap + c->container->files = c->files; + c->files = NULL; + } + return NULL; + } else { + // we just finished an in-order block + DEBUG_VALIDATE_BUG_ON(c->files == NULL); + // move back the ownership of the file container to HttpRangeContainerFile + c->container->files = c->files; + c->files = NULL; + DEBUG_VALIDATE_BUG_ON(c->container->files->tail == NULL); + } + + File *f = c->container->files->tail; + + /* See if we can use our stored fragments to (partly) reconstruct the file */ + HttpRangeContainerBuffer *range, *safe = NULL; + RB_FOREACH_SAFE (range, HTTP_RANGES, &c->container->fragment_tree, safe) { + if (f->size < range->start) { + // this next range is not reached yet + break; + } + if (f->size == range->start) { + // a new range just begins where we ended, append it + if (range->gap > 0) { + // if the range had a gap, begin by it + if (FileAppendData(c->container->files, sbcfg, NULL, range->gap) != 0) { + c->container->lastsize = f->size; + HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); + c->container->error = true; + return f; + } + } + if (FileAppendData(c->container->files, sbcfg, range->buffer, range->offset) != 0) { + c->container->lastsize = f->size; + HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); + c->container->error = true; + return f; + } + } else { + // the range starts before where we ended + uint64_t overlap = f->size - range->start; + if (overlap < range->offset) { + if (range->gap > 0) { + // if the range had a gap, begin by it + if (FileAppendData(c->container->files, sbcfg, NULL, range->gap) != 0) { + c->container->lastsize = f->size; + HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); + c->container->error = true; + return f; + } + } + // And the range ends beyond where we ended + // in this case of overlap, only add the extra data + if (FileAppendData(c->container->files, sbcfg, range->buffer + overlap, + range->offset - overlap) != 0) { + c->container->lastsize = f->size; + HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED); + c->container->error = true; + return f; + } + } + } + /* Remove this range from the tree */ + HTTP_RANGES_RB_REMOVE(&c->container->fragment_tree, range); + (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, range->buflen); + SCFree(range->buffer); + SCFree(range); + } + // wait until we merged all the buffers to update known size + c->container->lastsize = f->size; + + if (f->size >= c->container->totalsize) { + // we finished the whole file + HttpRangeFileClose(sbcfg, c->container, flags); + } else { + // we are expecting more ranges + f = NULL; + SCLogDebug("expecting more use_cnt %u", SC_ATOMIC_GET(c->container->hdata->use_cnt)); + } + SCLogDebug("returning f %p (c:%p container:%p)", f, c, c->container); + return f; +} + +static void HttpRangeBlockDerefContainer(HttpRangeContainerBlock *b) +{ + if (b && b->container) { + DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(b->container->hdata->use_cnt) == 0); + THashDecrUsecnt(b->container->hdata); + b->container = NULL; + } +} + +void HttpRangeFreeBlock(HttpRangeContainerBlock *b) +{ + if (b) { + BUG_ON(b->container == NULL && b->files != NULL); + const StreamingBufferConfig *sbcfg = b->container ? b->container->sbcfg : NULL; + + HttpRangeBlockDerefContainer(b); + + if (b->current) { + (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, b->current->buflen); + SCFree(b->current->buffer); + SCFree(b->current); + } + // we did not move ownership of the file container back to HttpRangeContainerFile + DEBUG_VALIDATE_BUG_ON(b->files != NULL); + if (b->files != NULL) { + FileContainerFree(b->files, sbcfg); + b->files = NULL; + } + SCFree(b); + } +} diff --git a/src/app-layer/http/parser-range.h b/src/app-layer/http/parser-range.h new file mode 100644 index 000000000000..dcb69cc5c870 --- /dev/null +++ b/src/app-layer/http/parser-range.h @@ -0,0 +1,114 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __APP_LAYER_HTP_RANGE_H__ +#define __APP_LAYER_HTP_RANGE_H__ + +#include "suricata-common.h" + +#include "util/thash.h" +#include "rust.h" + +void HttpRangeContainersInit(void); +void HttpRangeContainersDestroy(void); +uint32_t HttpRangeContainersTimeoutHash(const SCTime_t ts); + +// linked list of ranges : buffer with offset +typedef struct HttpRangeContainerBuffer { + /** red and black tree */ + RB_ENTRY(HttpRangeContainerBuffer) rb; + /** allocated buffer */ + uint8_t *buffer; + /** length of buffer */ + uint64_t buflen; + /** the start of the range (offset relative to the absolute beginning of the file) */ + uint64_t start; + /** offset of bytes written in buffer (relative to the start of the range) */ + uint64_t offset; + /** number of gaped bytes */ + uint64_t gap; +} HttpRangeContainerBuffer; + +int HttpRangeContainerBufferCompare(HttpRangeContainerBuffer *a, HttpRangeContainerBuffer *b); + +RB_HEAD(HTTP_RANGES, HttpRangeContainerBuffer); +RB_PROTOTYPE(HTTP_RANGES, HttpRangeContainerBuffer, rb, HttpRangeContainerBufferCompare); + +/** Item in hash table for a file in multiple ranges + * Thread-safety is ensured with the thread-safe hash table cf THashData + * The number of use is increased for each flow opening a new HttpRangeContainerBlock + * until it closes this HttpRangeContainerBlock + * The design goal is to have concurrency only on opening and closing a range request + * and have a lock-free data structure belonging to one Flow + * (see HttpRangeContainerBlock below) + * for every append in between (we suppose we have many appends per range request) + */ +typedef struct HttpRangeContainerFile { + /** key for hashtable */ + uint8_t *key; + /** key length */ + uint32_t len; + /** expire time in epoch */ + uint32_t expire; + /** pointer to hashtable data, for locking and use count */ + THashData *hdata; + /** total expected size of the file in ranges */ + uint64_t totalsize; + /** size of the file after last sync */ + uint64_t lastsize; + /** streaming buffer config for files below */ + const StreamingBufferConfig *sbcfg; + /** file container, with only one file */ + FileContainer *files; + /** red and black tree list of ranges which came out of order */ + struct HTTP_RANGES fragment_tree; + /** file flags */ + uint16_t flags; + /** error condition for this range. Its up to timeout handling to cleanup */ + bool error; +} HttpRangeContainerFile; + +/** A structure representing a single range request : + * either skipping, buffering, or appending + * As this belongs to a flow, appending data to it is ensured to be thread-safe + * Only one block per file has the pointer to the container + */ +typedef struct HttpRangeContainerBlock { + /** state where we skip content */ + uint64_t toskip; + /** current out of order range to write into */ + HttpRangeContainerBuffer *current; + /** pointer to the main file container, where to directly append data */ + HttpRangeContainerFile *container; + /** file container we are owning for now */ + FileContainer *files; +} HttpRangeContainerBlock; + +int HttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, + const uint8_t *data, uint32_t len); +File *HttpRangeClose( + const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags); + +// HttpRangeContainerBlock but trouble with headers inclusion order +HttpRangeContainerBlock *HttpRangeContainerOpenFile(const unsigned char *key, uint32_t keylen, + const Flow *f, const HTTPContentRange *cr, const StreamingBufferConfig *sbcfg, + const unsigned char *name, uint16_t name_len, uint16_t flags, const unsigned char *data, + uint32_t data_len); + +void HttpRangeFreeBlock(HttpRangeContainerBlock *b); + +#endif /* __APP_LAYER_HTP_RANGE_H__ */ diff --git a/src/app-layer/http/parser-xff.c b/src/app-layer/http/parser-xff.c new file mode 100644 index 000000000000..e0e3c377fc20 --- /dev/null +++ b/src/app-layer/http/parser-xff.c @@ -0,0 +1,351 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Ignacio Sanchez + * \author Duarte Silva + */ + +#include "suricata-common.h" +#include "conf.h" + +#include "app-layer-parser.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-xff.h" + +#ifndef HAVE_MEMRCHR +#include "util/memrchr.h" +#endif + +#include "util/misc.h" +#include "util/unittest.h" + +/** XFF header value minimal length */ +#define XFF_CHAIN_MINLEN 7 +/** XFF header value maximum length */ +#define XFF_CHAIN_MAXLEN 256 +/** Default XFF header name */ +#define XFF_DEFAULT "X-Forwarded-For" + +/** \internal + * \brief parse XFF string + * \param input input string, might be modified + * \param output output buffer + * \param output_size size of output buffer + * \retval bool 1 ok, 0 fail + */ +static int ParseXFFString(char *input, char *output, int output_size) +{ + size_t len = strlen(input); + if (len == 0) + return 0; + + if (input[0] == '[') { + char *end = strchr(input, ']'); + if (end == NULL) // malformed, not closed + return 0; + + if (end != input + (len - 1)) { + SCLogDebug("data after closing bracket"); + // if we ever want to parse the port, we can do it here + } + + /* done, lets wrap up */ + input++; // skip past [ + *end = '\0'; // overwrite ], ignore anything after + + } else { + /* lets see if the xff string ends in a port */ + int c = 0; + int d = 0; + char *p = input; + while (*p != '\0') { + if (*p == ':') + c++; + if (*p == '.') + d++; + p++; + } + /* 3 dots: ipv4, one ':' port */ + if (d == 3 && c == 1) { + SCLogDebug("XFF w port %s", input); + char *x = strchr(input, ':'); + if (x) { + *x = '\0'; + SCLogDebug("XFF w/o port %s", input); + // if we ever want to parse the port, we can do it here + } + } + } + + SCLogDebug("XFF %s", input); + + /** Sanity check on extracted IP for IPv4 and IPv6 */ + uint32_t ip[4]; + if (inet_pton(AF_INET, input, ip) == 1 || inet_pton(AF_INET6, input, ip) == 1) { + strlcpy(output, input, output_size); + return 1; // OK + } + return 0; +} + +/** + * \brief Function to return XFF IP if any in the selected transaction. The + * caller needs to lock the flow. + * \retval 1 if the IP has been found and returned in dstbuf + * \retval 0 if the IP has not being found or error + */ +int HttpXFFGetIPFromTx( + const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen) +{ + uint8_t xff_chain[XFF_CHAIN_MAXLEN]; + HtpState *htp_state = NULL; + htp_tx_t *tx = NULL; + uint64_t total_txs = 0; + uint8_t *p_xff = NULL; + + htp_state = (HtpState *)FlowGetAppState(f); + + if (htp_state == NULL) { + SCLogDebug("no http state, XFF IP cannot be retrieved"); + return 0; + } + + total_txs = AppLayerParserGetTxCnt(f, htp_state); + if (tx_id >= total_txs) + return 0; + + tx = AppLayerParserGetTx(f->proto, ALPROTO_HTTP1, htp_state, tx_id); + if (tx == NULL) { + SCLogDebug("tx is NULL, XFF cannot be retrieved"); + return 0; + } + + htp_header_t *h_xff = NULL; + if (tx->request_headers != NULL) { + h_xff = htp_table_get_c(tx->request_headers, xff_cfg->header); + } + + if (h_xff != NULL && bstr_len(h_xff->value) >= XFF_CHAIN_MINLEN && + bstr_len(h_xff->value) < XFF_CHAIN_MAXLEN) { + + memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); + xff_chain[bstr_len(h_xff->value)] = 0; + + if (xff_cfg->flags & XFF_REVERSE) { + /** Get the last IP address from the chain */ + p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); + if (p_xff == NULL) { + p_xff = xff_chain; + } else { + p_xff++; + } + } else { + /** Get the first IP address from the chain */ + p_xff = memchr(xff_chain, ',', bstr_len(h_xff->value)); + if (p_xff != NULL) { + *p_xff = 0; + } + p_xff = xff_chain; + } + return ParseXFFString((char *)p_xff, dstbuf, dstbuflen); + } + return 0; +} + +/** + * \brief Function to return XFF IP if any. The caller needs to lock the flow. + * \retval 1 if the IP has been found and returned in dstbuf + * \retval 0 if the IP has not being found or error + */ +int HttpXFFGetIP(const Flow *f, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen) +{ + HtpState *htp_state = NULL; + uint64_t tx_id = 0; + uint64_t total_txs = 0; + + htp_state = (HtpState *)FlowGetAppState(f); + if (htp_state == NULL) { + SCLogDebug("no http state, XFF IP cannot be retrieved"); + goto end; + } + + total_txs = AppLayerParserGetTxCnt(f, htp_state); + for (; tx_id < total_txs; tx_id++) { + if (HttpXFFGetIPFromTx(f, tx_id, xff_cfg, dstbuf, dstbuflen) == 1) + return 1; + } + +end: + return 0; // Not found +} + +/** + * \brief Function to return XFF configuration from a configuration node. + */ +void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) +{ + BUG_ON(result == NULL); + + ConfNode *xff_node = NULL; + + if (conf != NULL) + xff_node = ConfNodeLookupChild(conf, "xff"); + + if (xff_node != NULL && ConfNodeChildValueIsTrue(xff_node, "enabled")) { + const char *xff_mode = ConfNodeLookupChildValue(xff_node, "mode"); + + if (xff_mode != NULL && strcasecmp(xff_mode, "overwrite") == 0) { + result->flags |= XFF_OVERWRITE; + } else { + if (xff_mode == NULL) { + SCLogWarning("The XFF mode hasn't been defined, falling back to extra-data mode"); + } else if (strcasecmp(xff_mode, "extra-data") != 0) { + SCLogWarning( + "The XFF mode %s is invalid, falling back to extra-data mode", xff_mode); + } + result->flags |= XFF_EXTRADATA; + } + + const char *xff_deployment = ConfNodeLookupChildValue(xff_node, "deployment"); + + if (xff_deployment != NULL && strcasecmp(xff_deployment, "forward") == 0) { + result->flags |= XFF_FORWARD; + } else { + if (xff_deployment == NULL) { + SCLogWarning("The XFF deployment hasn't been defined, falling back to reverse " + "proxy deployment"); + } else if (strcasecmp(xff_deployment, "reverse") != 0) { + SCLogWarning("The XFF mode %s is invalid, falling back to reverse proxy deployment", + xff_deployment); + } + result->flags |= XFF_REVERSE; + } + + const char *xff_header = ConfNodeLookupChildValue(xff_node, "header"); + + if (xff_header != NULL) { + result->header = (char *)xff_header; + } else { + SCLogWarning("The XFF header hasn't been defined, using the default %s", XFF_DEFAULT); + result->header = XFF_DEFAULT; + } + } else { + result->flags = XFF_DISABLED; + } +} + +#ifdef UNITTESTS +static int XFFTest01(void) +{ + char input[] = "1.2.3.4:5678"; + char output[16]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 1 && strcmp(output, "1.2.3.4") == 0); + PASS; +} + +static int XFFTest02(void) +{ + char input[] = "[12::34]:1234"; // thanks chort! + char output[16]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 1 && strcmp(output, "12::34") == 0); + PASS; +} + +static int XFFTest03(void) +{ + char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]:80"; // thanks chort! + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0); + PASS; +} + +static int XFFTest04(void) +{ + char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]"; // thanks chort! + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0); + PASS; +} + +static int XFFTest05(void) +{ + char input[] = "[::ffff:1.2.3.4]:1234"; // thanks double-p + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 1 && strcmp(output, "::ffff:1.2.3.4") == 0); + PASS; +} + +static int XFFTest06(void) +{ + char input[] = "12::34"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 1 && strcmp(output, "12::34") == 0); + PASS; +} + +static int XFFTest07(void) +{ + char input[] = "1.2.3.4"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 1 && strcmp(output, "1.2.3.4") == 0); + PASS; +} + +static int XFFTest08(void) +{ + char input[] = "[1.2.3.4:1234"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 0); + PASS; +} + +static int XFFTest09(void) +{ + char input[] = "999.999.999.999:1234"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + FAIL_IF_NOT(r == 0); + PASS; +} + +#endif + +void HTPXFFParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("XFFTest01", XFFTest01); + UtRegisterTest("XFFTest02", XFFTest02); + UtRegisterTest("XFFTest03", XFFTest03); + UtRegisterTest("XFFTest04", XFFTest04); + UtRegisterTest("XFFTest05", XFFTest05); + UtRegisterTest("XFFTest06", XFFTest06); + UtRegisterTest("XFFTest07", XFFTest07); + UtRegisterTest("XFFTest08", XFFTest08); + UtRegisterTest("XFFTest09", XFFTest09); +#endif +} diff --git a/src/app-layer/http/parser-xff.h b/src/app-layer/http/parser-xff.h new file mode 100644 index 000000000000..b4dbd8637576 --- /dev/null +++ b/src/app-layer/http/parser-xff.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Ignacio Sanchez + * \author Duarte Silva + */ + +#ifndef __APP_LAYER_HTP_XFF_H__ +#define __APP_LAYER_HTP_XFF_H__ + +/** XFF is disabled */ +#define XFF_DISABLED 1 +/** XFF extra data mode */ +#define XFF_EXTRADATA 2 +/** XFF overwrite mode */ +#define XFF_OVERWRITE 4 +/** XFF is to be used in a reverse proxy deployment */ +#define XFF_REVERSE 8 +/** XFF is to be used in a forward proxy deployment */ +#define XFF_FORWARD 16 +/** Single XFF IP maximum length (default value based on IPv6 address length) */ +#define XFF_MAXLEN 46 + +typedef struct HttpXFFCfg_ { + uint8_t flags; /**< XFF operation mode and deployment */ + const char *header; /**< XFF header name */ +} HttpXFFCfg; + +void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result); + +int HttpXFFGetIPFromTx( + const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); + +int HttpXFFGetIP(const Flow *f, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); + +void HTPXFFParserRegisterTests(void); + +#endif /* __APP_LAYER_HTP_XFF_H__ */ diff --git a/src/app-layer/http/parser.c b/src/app-layer/http/parser.c new file mode 100644 index 000000000000..b95fde4e3365 --- /dev/null +++ b/src/app-layer/http/parser.c @@ -0,0 +1,7120 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * \author Gurvinder Singh + * \author Pablo Rincon + * \author Brian Rectanus + * \author Anoop Saldanha + * + * This file provides a HTTP protocol support for the engine using HTP library. + */ + +#include "suricata.h" +#include "suricata-common.h" +#include "conf.h" +#include "decode.h" +#include "threads.h" +#include "counters.h" + +#include "util/print.h" +#include "util/pool.h" +#include "util/radix-tree.h" +#include "util/file.h" +#include "util/byte.h" + +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" +#include "stream-tcp.h" +#include "stream.h" + +#include "app-layer-protos.h" +#include "app-layer-parser.h" + +#include "app-layer.h" +#include "app-layer-detect-proto.h" +#include "app-layer-frames.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-body.h" +#include "app-layer/http/parser-file.h" +#include "app-layer/http/parser-libhtp.h" +#include "app-layer/http/parser-xff.h" +#include "app-layer/http/parser-range.h" +#include "app-layer/http/parser-mem.h" + +#include "util/spm.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/misc.h" +#include "util/enum.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "flow-util.h" + +#include "detect-engine.h" +#include "detect-engine-build.h" +#include "detect-engine-state.h" +#include "detect-parse.h" + +#include "decode-events.h" + +#include "util/memcmp.h" +#include "util/random.h" +#include "util/validate.h" + +// #define PRINT + +/** Fast lookup tree (radix) for the various HTP configurations */ +static SCRadixTree *cfgtree; +/** List of HTP configurations. */ +static HTPCfgRec cfglist; + +StreamingBufferConfig htp_sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; + +/** Limit to the number of libhtp messages that can be handled */ +#define HTP_MAX_MESSAGES 512 + +SC_ATOMIC_DECLARE(uint32_t, htp_config_flags); + +#ifdef DEBUG +static SCMutex htp_state_mem_lock = SCMUTEX_INITIALIZER; +static uint64_t htp_state_memuse = 0; +static uint64_t htp_state_memcnt = 0; +#endif + +SCEnumCharMap http_decoder_event_table[] = { + { "UNKNOWN_ERROR", HTTP_DECODER_EVENT_UNKNOWN_ERROR }, + { "GZIP_DECOMPRESSION_FAILED", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED }, + { "REQUEST_FIELD_MISSING_COLON", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON }, + { "RESPONSE_FIELD_MISSING_COLON", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON }, + { "INVALID_REQUEST_CHUNK_LEN", HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN }, + { "INVALID_RESPONSE_CHUNK_LEN", HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN }, + { "INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST", + HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST }, + { "INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE", + HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE }, + { "INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST", + HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST }, + { "INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE", + HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE }, + { "DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST", + HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST }, + { "DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE", + HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE }, + { "100_CONTINUE_ALREADY_SEEN", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN }, + { "UNABLE_TO_MATCH_RESPONSE_TO_REQUEST", + HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST }, + { "INVALID_SERVER_PORT_IN_REQUEST", HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST }, + { "INVALID_AUTHORITY_PORT", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT }, + { "REQUEST_HEADER_INVALID", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID }, + { "RESPONSE_HEADER_INVALID", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID }, + { "MISSING_HOST_HEADER", HTTP_DECODER_EVENT_MISSING_HOST_HEADER }, + { "HOST_HEADER_AMBIGUOUS", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS }, + { "INVALID_REQUEST_FIELD_FOLDING", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING }, + { "INVALID_RESPONSE_FIELD_FOLDING", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING }, + { "REQUEST_FIELD_TOO_LONG", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG }, + { "RESPONSE_FIELD_TOO_LONG", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG }, + { "FILE_NAME_TOO_LONG", HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG }, + { "REQUEST_LINE_INVALID", HTTP_DECODER_EVENT_REQUEST_LINE_INVALID }, + { "REQUEST_BODY_UNEXPECTED", HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED }, + { "REQUEST_SERVER_PORT_TCP_PORT_MISMATCH", + HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH }, + { "REQUEST_URI_HOST_INVALID", HTTP_DECODER_EVENT_URI_HOST_INVALID }, + { "REQUEST_HEADER_HOST_INVALID", HTTP_DECODER_EVENT_HEADER_HOST_INVALID }, + { "REQUEST_AUTH_UNRECOGNIZED", HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED }, + { "REQUEST_HEADER_REPETITION", HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION }, + { "RESPONSE_HEADER_REPETITION", HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION }, + { "DOUBLE_ENCODED_URI", HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI }, + { "URI_DELIM_NON_COMPLIANT", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT }, + { "METHOD_DELIM_NON_COMPLIANT", HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT }, + { "REQUEST_LINE_LEADING_WHITESPACE", HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE }, + { "TOO_MANY_ENCODING_LAYERS", HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS }, + { "ABNORMAL_CE_HEADER", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, + { "RESPONSE_MULTIPART_BYTERANGES", HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES }, + { "RESPONSE_ABNORMAL_TRANSFER_ENCODING", + HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING }, + { "RESPONSE_CHUNKED_OLD_PROTO", HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO }, + { "RESPONSE_INVALID_PROTOCOL", HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL }, + { "RESPONSE_INVALID_STATUS", HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS }, + { "REQUEST_LINE_INCOMPLETE", HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE }, + + { "LZMA_MEMLIMIT_REACHED", HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED }, + { "COMPRESSION_BOMB", HTTP_DECODER_EVENT_COMPRESSION_BOMB }, + + { "RANGE_INVALID", HTTP_DECODER_EVENT_RANGE_INVALID }, + { "REQUEST_CHUNK_EXTENSION", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION }, + + /* suricata warnings/errors */ + { "MULTIPART_GENERIC_ERROR", HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR }, + { "MULTIPART_NO_FILEDATA", HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA }, + { "MULTIPART_INVALID_HEADER", HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER }, + + { "TOO_MANY_WARNINGS", HTTP_DECODER_EVENT_TOO_MANY_WARNINGS }, + { "FAILED_PROTOCOL_CHANGE", HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE }, + + { NULL, -1 }, +}; + +/* app-layer-frame-documentation tag start: HttpFrameTypes */ +enum HttpFrameTypes { + HTTP_FRAME_REQUEST, + HTTP_FRAME_RESPONSE, +}; + +SCEnumCharMap http_frame_table[] = { + { + "request", + HTTP_FRAME_REQUEST, + }, + { + "response", + HTTP_FRAME_RESPONSE, + }, + { NULL, -1 }, +}; +/* app-layer-frame-documentation tag end: HttpFrameTypes */ + +static int HTTPGetFrameIdByName(const char *frame_name) +{ + int id = SCMapEnumNameToValue(frame_name, http_frame_table); + if (id < 0) { + return -1; + } + return id; +} + +static const char *HTTPGetFrameNameById(const uint8_t frame_id) +{ + const char *name = SCMapEnumValueToName(frame_id, http_frame_table); + return name; +} + +static void *HTPStateGetTx(void *alstate, uint64_t tx_id); +static int HTPStateGetAlstateProgress(void *tx, uint8_t direction); +static uint64_t HTPStateGetTxCnt(void *alstate); +#ifdef UNITTESTS +static void HTPParserRegisterTests(void); +#endif + +static inline uint64_t HtpGetActiveRequestTxID(HtpState *s) +{ + uint64_t id = HTPStateGetTxCnt(s); + BUG_ON(id == 0); + return id - 1; +} + +static inline uint64_t HtpGetActiveResponseTxID(HtpState *s) +{ + return s->transaction_cnt; +} + +#ifdef DEBUG +/** + * \internal + * + * \brief Lookup the HTP personality string from the numeric personality. + * + * \todo This needs to be a libhtp function. + */ +static const char *HTPLookupPersonalityString(int p) +{ +#define CASE_HTP_PERSONALITY_STRING(p) \ + case HTP_SERVER_##p: \ + return #p + + switch (p) { + CASE_HTP_PERSONALITY_STRING(MINIMAL); + CASE_HTP_PERSONALITY_STRING(GENERIC); + CASE_HTP_PERSONALITY_STRING(IDS); + CASE_HTP_PERSONALITY_STRING(IIS_4_0); + CASE_HTP_PERSONALITY_STRING(IIS_5_0); + CASE_HTP_PERSONALITY_STRING(IIS_5_1); + CASE_HTP_PERSONALITY_STRING(IIS_6_0); + CASE_HTP_PERSONALITY_STRING(IIS_7_0); + CASE_HTP_PERSONALITY_STRING(IIS_7_5); + CASE_HTP_PERSONALITY_STRING(APACHE_2); + } + + return NULL; +} +#endif /* DEBUG */ + +/** + * \internal + * + * \brief Lookup the numeric HTP personality from a string. + * + * \todo This needs to be a libhtp function. + */ +static int HTPLookupPersonality(const char *str) +{ +#define IF_HTP_PERSONALITY_NUM(p) \ + if (strcasecmp(#p, str) == 0) \ + return HTP_SERVER_##p + + IF_HTP_PERSONALITY_NUM(MINIMAL); + IF_HTP_PERSONALITY_NUM(GENERIC); + IF_HTP_PERSONALITY_NUM(IDS); + IF_HTP_PERSONALITY_NUM(IIS_4_0); + IF_HTP_PERSONALITY_NUM(IIS_5_0); + IF_HTP_PERSONALITY_NUM(IIS_5_1); + IF_HTP_PERSONALITY_NUM(IIS_6_0); + IF_HTP_PERSONALITY_NUM(IIS_7_0); + IF_HTP_PERSONALITY_NUM(IIS_7_5); + IF_HTP_PERSONALITY_NUM(APACHE_2); + if (strcasecmp("TOMCAT_6_0", str) == 0) { + SCLogError("Personality %s no " + "longer supported by libhtp.", + str); + return -1; + } else if ((strcasecmp("APACHE", str) == 0) || (strcasecmp("APACHE_2_2", str) == 0)) { + SCLogWarning("Personality %s no " + "longer supported by libhtp, failing back to " + "Apache2 personality.", + str); + return HTP_SERVER_APACHE_2; + } + + return -1; +} + +static void HTPSetEvent(HtpState *s, HtpTxUserData *htud, const uint8_t dir, const uint8_t e) +{ + SCLogDebug("setting event %u", e); + + if (htud) { + AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, e); + s->events++; + return; + } + + const uint64_t tx_id = + (dir == STREAM_TOSERVER) ? HtpGetActiveRequestTxID(s) : HtpGetActiveResponseTxID(s); + + htp_tx_t *tx = HTPStateGetTx(s, tx_id); + if (tx == NULL && tx_id > 0) + tx = HTPStateGetTx(s, tx_id - 1); + if (tx != NULL) { + htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + AppLayerDecoderEventsSetEventRaw(&htud->tx_data.events, e); + s->events++; + return; + } + } + SCLogDebug("couldn't set event %u", e); +} + +/** \brief Function to allocates the HTTP state memory and also creates the HTTP + * connection parser to be used by the HTP library + */ +static void *HTPStateAlloc(void *orig_state, AppProto proto_orig) +{ + SCEnter(); + + HtpState *s = HTPMalloc(sizeof(HtpState)); + if (unlikely(s == NULL)) { + SCReturnPtr(NULL, "void"); + } + + memset(s, 0x00, sizeof(HtpState)); + +#ifdef DEBUG + SCMutexLock(&htp_state_mem_lock); + htp_state_memcnt++; + htp_state_memuse += sizeof(HtpState); + SCLogDebug("htp memory %" PRIu64 " (%" PRIu64 ")", htp_state_memuse, htp_state_memcnt); + SCMutexUnlock(&htp_state_mem_lock); +#endif + + SCReturnPtr((void *)s, "void"); +} + +static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud) +{ + if (likely(htud)) { + HtpBodyFree(&state->cfg->request, &htud->request_body); + HtpBodyFree(&state->cfg->response, &htud->response_body); + bstr_free(htud->request_uri_normalized); + if (htud->request_headers_raw) + HTPFree(htud->request_headers_raw, htud->request_headers_raw_len); + if (htud->response_headers_raw) + HTPFree(htud->response_headers_raw, htud->response_headers_raw_len); + AppLayerDecoderEventsFreeEvents(&htud->tx_data.events); + if (htud->boundary) + HTPFree(htud->boundary, htud->boundary_len); + if (htud->tx_data.de_state != NULL) { + DetectEngineStateFree(htud->tx_data.de_state); + } + if (htud->file_range) { + HTPFileCloseHandleRange(&htp_sbcfg, &htud->files_tc, 0, htud->file_range, NULL, 0); + HttpRangeFreeBlock(htud->file_range); + } + FileContainerRecycle(&htud->files_ts, &htp_sbcfg); + FileContainerRecycle(&htud->files_tc, &htp_sbcfg); + HTPFree(htud, sizeof(HtpTxUserData)); + } +} + +/** \brief Function to frees the HTTP state memory and also frees the HTTP + * connection parser memory which was used by the HTP library + */ +void HTPStateFree(void *state) +{ + SCEnter(); + + HtpState *s = (HtpState *)state; + if (s == NULL) { + SCReturn; + } + + /* free the connection parser memory used by HTP library */ + if (s->connp != NULL) { + SCLogDebug("freeing HTP state"); + + uint64_t tx_id; + uint64_t total_txs = HTPStateGetTxCnt(state); + /* free the list of body chunks */ + if (s->conn != NULL) { + for (tx_id = 0; tx_id < total_txs; tx_id++) { + htp_tx_t *tx = HTPStateGetTx(s, tx_id); + if (tx != NULL) { + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); + } + } + } + htp_connp_destroy_all(s->connp); + } + + HTPFree(s, sizeof(HtpState)); + +#ifdef DEBUG + SCMutexLock(&htp_state_mem_lock); + htp_state_memcnt--; + htp_state_memuse -= sizeof(HtpState); + SCLogDebug("htp memory %" PRIu64 " (%" PRIu64 ")", htp_state_memuse, htp_state_memcnt); + SCMutexUnlock(&htp_state_mem_lock); +#endif + + SCReturn; +} + +/** + * \brief HTP transaction cleanup callback + * + * \warning We cannot actually free the transactions here. It seems that + * HTP only accepts freeing of transactions in the response callback. + */ +static void HTPStateTransactionFree(void *state, uint64_t id) +{ + SCEnter(); + + HtpState *s = (HtpState *)state; + + SCLogDebug("state %p, id %" PRIu64, s, id); + + htp_tx_t *tx = HTPStateGetTx(s, id); + if (tx != NULL) { + /* This will remove obsolete body chunks */ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); + + /* hack: even if libhtp considers the tx incomplete, we want to + * free it here. htp_tx_destroy however, will refuse to do this. + * As htp_tx_destroy_incomplete isn't available in the public API, + * we hack around it here. */ + if (unlikely(!(tx->request_progress == HTP_REQUEST_COMPLETE && + tx->response_progress == HTP_RESPONSE_COMPLETE))) { + tx->request_progress = HTP_REQUEST_COMPLETE; + tx->response_progress = HTP_RESPONSE_COMPLETE; + } + htp_tx_destroy(tx); + } +} + +/** + * \brief Sets a flag that informs the HTP app layer that some module in the + * engine needs the http request body data. + * \initonly + */ +void AppLayerHtpEnableRequestBodyCallback(void) +{ + SCEnter(); + + SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_BODY); + SCReturn; +} + +/** + * \brief Sets a flag that informs the HTP app layer that some module in the + * engine needs the http request body data. + * \initonly + */ +void AppLayerHtpEnableResponseBodyCallback(void) +{ + SCEnter(); + + SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_RESPONSE_BODY); + SCReturn; +} + +/** + * \brief Sets a flag that informs the HTP app layer that some module in the + * engine needs the http request multi part header. + * + * \initonly + */ +static void AppLayerHtpNeedMultipartHeader(void) +{ + SCEnter(); + AppLayerHtpEnableRequestBodyCallback(); + + SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_MULTIPART); + SCReturn; +} + +/** + * \brief Sets a flag that informs the HTP app layer that some module in the + * engine needs the http request file. + * + * \initonly + */ +void AppLayerHtpNeedFileInspection(void) +{ + SCEnter(); + AppLayerHtpNeedMultipartHeader(); + AppLayerHtpEnableRequestBodyCallback(); + AppLayerHtpEnableResponseBodyCallback(); + + SC_ATOMIC_OR(htp_config_flags, HTP_REQUIRE_REQUEST_FILE); + SCReturn; +} + +static void AppLayerHtpSetStreamDepthFlag(void *tx, const uint8_t flags) +{ + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data((htp_tx_t *)tx); + if (tx_ud) { + SCLogDebug("setting HTP_STREAM_DEPTH_SET, flags %02x", flags); + if (flags & STREAM_TOCLIENT) { + tx_ud->tcflags |= HTP_STREAM_DEPTH_SET; + } else { + tx_ud->tsflags |= HTP_STREAM_DEPTH_SET; + } + } +} + +static bool AppLayerHtpCheckDepth(const HTPCfgDir *cfg, HtpBody *body, uint8_t flags) +{ + SCLogDebug("cfg->body_limit %u stream_depth %u body->content_len_so_far %" PRIu64, + cfg->body_limit, FileReassemblyDepth(), body->content_len_so_far); + if (flags & HTP_STREAM_DEPTH_SET) { + uint32_t stream_depth = FileReassemblyDepth(); + if (body->content_len_so_far < (uint64_t)stream_depth || stream_depth == 0) { + SCLogDebug("true"); + return true; + } + } else { + if (cfg->body_limit == 0 || body->content_len_so_far < cfg->body_limit) { + return true; + } + } + SCLogDebug("false"); + return false; +} + +static uint32_t AppLayerHtpComputeChunkLength(uint64_t content_len_so_far, uint32_t body_limit, + uint32_t stream_depth, uint8_t flags, uint32_t data_len) +{ + uint32_t chunk_len = 0; + if (!(flags & HTP_STREAM_DEPTH_SET) && body_limit > 0 && + (content_len_so_far < (uint64_t)body_limit) && + (content_len_so_far + (uint64_t)data_len) > body_limit) { + chunk_len = body_limit - content_len_so_far; + } else if ((flags & HTP_STREAM_DEPTH_SET) && stream_depth > 0 && + (content_len_so_far < (uint64_t)stream_depth) && + (content_len_so_far + (uint64_t)data_len) > stream_depth) { + chunk_len = stream_depth - content_len_so_far; + } + SCLogDebug("len %u", chunk_len); + return (chunk_len == 0 ? data_len : chunk_len); +} + +/* below error messages updated up to libhtp 0.5.7 (git 379632278b38b9a792183694a4febb9e0dbd1e7a) */ +struct { + const char *msg; + uint8_t de; +} htp_errors[] = { + { "GZip decompressor: inflateInit2 failed", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED }, + { "Request field invalid: colon missing", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON }, + { "Response field invalid: missing colon", HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON }, + { "Request chunk encoding: Invalid chunk length", + HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN }, + { "Response chunk encoding: Invalid chunk length", + HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN }, + /* { "Invalid T-E value in request", + HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST}, <- tx flag + HTP_REQUEST_INVALID_T_E { "Invalid T-E value in response", + HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE}, <- nothing to replace it */ + /* { "Invalid C-L field in request", + HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST}, <- tx flag + HTP_REQUEST_INVALID_C_L */ + { "Invalid C-L field in response", + HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE }, + { "Already seen 100-Continue", HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN }, + { "Unable to match response to request", + HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST }, + { "Invalid server port information in request", + HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST }, + /* { "Invalid authority port", HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT}, htp no longer + returns this error */ + { "Request buffer over", HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG }, + { "Response buffer over", HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG }, + { "C-T multipart/byteranges in responses not supported", + HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES }, + { "Compression bomb:", HTTP_DECODER_EVENT_COMPRESSION_BOMB }, +}; + +struct { + const char *msg; + uint8_t de; +} htp_warnings[] = { + { "GZip decompressor:", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED }, + { "Request field invalid", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID }, + { "Response field invalid", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID }, + { "Request header name is not a token", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID }, + { "Response header name is not a token", HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID }, + /* { "Host information in request headers required by HTTP/1.1", + HTTP_DECODER_EVENT_MISSING_HOST_HEADER}, <- tx flag HTP_HOST_MISSING { "Host information + ambiguous", HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS}, <- tx flag HTP_HOST_AMBIGUOUS */ + { "Invalid request field folding", HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING }, + { "Invalid response field folding", HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING }, + /* line is now: htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request server port=%d number + * differs from the actual TCP port=%d", port, connp->conn->server_port); luckily, "Request + * server port=" is unique */ + /* { "Request server port number differs from the actual TCP port", + HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, */ + { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH }, + { "Request line: URI contains non-compliant delimiter", + HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT }, + { "Request line: non-compliant delimiter between Method and URI", + HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT }, + { "Request line: leading whitespace", HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE }, + { "Too many response content encoding layers", HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS }, + { "C-E gzip has abnormal value", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, + { "C-E deflate has abnormal value", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, + { "C-E unknown setting", HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER }, + { "Excessive request header repetitions", HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION }, + { "Excessive response header repetitions", HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION }, + { "Transfer-encoding has abnormal chunked value", + HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING }, + { "Chunked transfer-encoding on HTTP/0.9 or HTTP/1.0", + HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO }, + { "Invalid response line: invalid protocol", HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL }, + { "Invalid response line: invalid response status", + HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS }, + { "Request line incomplete", HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE }, + { "Unexpected request body", HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED }, + { "LZMA decompressor: memory limit reached", HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED }, + { "Ambiguous request C-L value", HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST }, + { "Ambiguous response C-L value", + HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE }, + { "Request chunk extension", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION }, +}; + +#define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0])) +#define HTP_WARNING_MAX (sizeof(htp_warnings) / sizeof(htp_warnings[0])) + +/** + * \internal + * + * \brief Get the warning id for the warning msg. + * + * \param msg warning message + * + * \retval id the id or 0 in case of not found + */ +static uint8_t HTPHandleWarningGetId(const char *msg) +{ + SCLogDebug("received warning \"%s\"", msg); + size_t idx; + for (idx = 0; idx < HTP_WARNING_MAX; idx++) { + if (strncmp(htp_warnings[idx].msg, msg, strlen(htp_warnings[idx].msg)) == 0) { + return htp_warnings[idx].de; + } + } + + return 0; +} + +/** + * \internal + * + * \brief Get the error id for the error msg. + * + * \param msg error message + * + * \retval id the id or 0 in case of not found + */ +static uint8_t HTPHandleErrorGetId(const char *msg) +{ + SCLogDebug("received error \"%s\"", msg); + + size_t idx; + for (idx = 0; idx < HTP_ERROR_MAX; idx++) { + if (strncmp(htp_errors[idx].msg, msg, strlen(htp_errors[idx].msg)) == 0) { + return htp_errors[idx].de; + } + } + + return 0; +} + +/** + * \internal + * + * \brief Check state for errors, warnings and add any as events + * + * \param s state + * \param dir direction: STREAM_TOSERVER or STREAM_TOCLIENT + */ +static void HTPHandleError(HtpState *s, const uint8_t dir) +{ + if (s == NULL || s->conn == NULL || s->conn->messages == NULL) { + return; + } + + size_t size = htp_list_size(s->conn->messages); + size_t msg; + if (size >= HTP_MAX_MESSAGES) { + if (s->htp_messages_offset < HTP_MAX_MESSAGES) { + // only once per HtpState + HTPSetEvent(s, NULL, dir, HTTP_DECODER_EVENT_TOO_MANY_WARNINGS); + s->htp_messages_offset = HTP_MAX_MESSAGES; + // too noisy in fuzzing + // DEBUG_VALIDATE_BUG_ON("Too many libhtp messages"); + } + // ignore further messages + return; + } + + for (msg = s->htp_messages_offset; msg < size; msg++) { + htp_log_t *log = htp_list_get(s->conn->messages, msg); + if (log == NULL) + continue; + + HtpTxUserData *htud = NULL; + htp_tx_t *tx = log->tx; // will be NULL in <=0.5.9 + if (tx != NULL) + htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + + SCLogDebug("message %s", log->msg); + + uint8_t id = HTPHandleErrorGetId(log->msg); + if (id == 0) { + id = HTPHandleWarningGetId(log->msg); + if (id == 0) + id = HTTP_DECODER_EVENT_UNKNOWN_ERROR; + } + + if (id > 0) { + HTPSetEvent(s, htud, dir, id); + } + } + s->htp_messages_offset = (uint16_t)msg; + SCLogDebug("s->htp_messages_offset %u", s->htp_messages_offset); +} + +static inline void HTPErrorCheckTxRequestFlags(HtpState *s, htp_tx_t *tx) +{ +#ifdef DEBUG + BUG_ON(s == NULL || tx == NULL); +#endif + if (tx->flags & (HTP_REQUEST_INVALID_T_E | HTP_REQUEST_INVALID_C_L | HTP_HOST_MISSING | + HTP_HOST_AMBIGUOUS | HTP_HOSTU_INVALID | HTP_HOSTH_INVALID)) { + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + return; + + if (tx->flags & HTP_REQUEST_INVALID_T_E) + HTPSetEvent(s, htud, STREAM_TOSERVER, + HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST); + if (tx->flags & HTP_REQUEST_INVALID_C_L) + HTPSetEvent(s, htud, STREAM_TOSERVER, + HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST); + if (tx->flags & HTP_HOST_MISSING) + HTPSetEvent(s, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MISSING_HOST_HEADER); + if (tx->flags & HTP_HOST_AMBIGUOUS) + HTPSetEvent(s, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS); + if (tx->flags & HTP_HOSTU_INVALID) + HTPSetEvent(s, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_URI_HOST_INVALID); + if (tx->flags & HTP_HOSTH_INVALID) + HTPSetEvent(s, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_HEADER_HOST_INVALID); + } + if (tx->request_auth_type == HTP_AUTH_UNRECOGNIZED) { + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + return; + HTPSetEvent(s, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED); + } + if (tx->is_protocol_0_9 && tx->request_method_number == HTP_M_UNKNOWN && + (tx->request_protocol_number == HTP_PROTOCOL_INVALID || + tx->request_protocol_number == HTP_PROTOCOL_UNKNOWN)) { + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + return; + HTPSetEvent(s, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_REQUEST_LINE_INVALID); + } +} + +static int Setup(Flow *f, HtpState *hstate) +{ + /* store flow ref in state so callbacks can access it */ + hstate->f = f; + + HTPCfgRec *htp_cfg_rec = &cfglist; + htp_cfg_t *htp = cfglist.cfg; /* Default to the global HTP config */ + void *user_data = NULL; + + if (FLOW_IS_IPV4(f)) { + SCLogDebug("Looking up HTP config for ipv4 %08x", *GET_IPV4_DST_ADDR_PTR(f)); + (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)GET_IPV4_DST_ADDR_PTR(f), cfgtree, &user_data); + } else if (FLOW_IS_IPV6(f)) { + SCLogDebug("Looking up HTP config for ipv6"); + (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)GET_IPV6_DST_ADDR(f), cfgtree, &user_data); + } else { + SCLogError("unknown address family, bug!"); + goto error; + } + + if (user_data != NULL) { + htp_cfg_rec = user_data; + htp = htp_cfg_rec->cfg; + SCLogDebug("LIBHTP using config: %p", htp); + } else { + SCLogDebug("Using default HTP config: %p", htp); + } + + if (NULL == htp) { +#ifdef DEBUG_VALIDATION + BUG_ON(htp == NULL); +#endif + /* should never happen if HTPConfigure is properly invoked */ + goto error; + } + + hstate->connp = htp_connp_create(htp); + if (hstate->connp == NULL) { + goto error; + } + + hstate->conn = htp_connp_get_connection(hstate->connp); + + htp_connp_set_user_data(hstate->connp, (void *)hstate); + hstate->cfg = htp_cfg_rec; + + SCLogDebug("New hstate->connp %p", hstate->connp); + + struct timeval tv = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) }; + htp_connp_open(hstate->connp, NULL, f->sp, NULL, f->dp, &tv); + + StreamTcpReassemblySetMinInspectDepth( + f->protoctx, STREAM_TOSERVER, htp_cfg_rec->request.inspect_min_size); + StreamTcpReassemblySetMinInspectDepth( + f->protoctx, STREAM_TOCLIENT, htp_cfg_rec->response.inspect_min_size); + return 0; +error: + return -1; +} + +/** + * \brief Function to handle the reassembled data from client and feed it to + * the HTP library to process it. + * + * \param flow Pointer to the flow the data belong to + * \param htp_state Pointer the state in which the parsed value to be stored + * \param pstate Application layer parser state for this session + * + * \retval On success returns 1 or on failure returns -1. + */ +static AppLayerResult HTPHandleRequestData(Flow *f, void *htp_state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + SCEnter(); + int ret = 0; + HtpState *hstate = (HtpState *)htp_state; + + /* On the first invocation, create the connection parser structure to + * be used by HTP library. This is looked up via IP in the radix + * tree. Failing that, the default HTP config is used. + */ + if (NULL == hstate->conn) { + if (Setup(f, hstate) != 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + } + DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL); + hstate->slice = &stream_slice; + + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + htp_time_t ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) }; + /* pass the new data to the htp parser */ + if (input_len > 0) { + const int r = htp_connp_req_data(hstate->connp, &ts, input, input_len); + switch (r) { + case HTP_STREAM_ERROR: + ret = -1; + break; + default: + break; + } + HTPHandleError(hstate, STREAM_TOSERVER); + } + + /* if the TCP connection is closed, then close the HTTP connection */ + if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) && + !(hstate->flags & HTP_FLAG_STATE_CLOSED_TS)) { + htp_connp_req_close(hstate->connp, &ts); + hstate->flags |= HTP_FLAG_STATE_CLOSED_TS; + SCLogDebug("stream eof encountered, closing htp handle for ts"); + } + + SCLogDebug("hstate->connp %p", hstate->connp); + hstate->slice = NULL; + + if (ret < 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + SCReturnStruct(APP_LAYER_OK); +} + +/** + * \brief Function to handle the reassembled data from server and feed it to + * the HTP library to process it. + * + * \param flow Pointer to the flow the data belong to + * \param htp_state Pointer the state in which the parsed value to be stored + * \param pstate Application layer parser state for this session + * \param input Pointer the received HTTP server data + * \param input_len Length in bytes of the received data + * \param output Pointer to the output (not used in this function) + * + * \retval On success returns 1 or on failure returns -1 + */ +static AppLayerResult HTPHandleResponseData(Flow *f, void *htp_state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + SCEnter(); + int ret = 0; + HtpState *hstate = (HtpState *)htp_state; + + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + /* On the first invocation, create the connection parser structure to + * be used by HTP library. This is looked up via IP in the radix + * tree. Failing that, the default HTP config is used. + */ + if (NULL == hstate->conn) { + if (Setup(f, hstate) != 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + } + DEBUG_VALIDATE_BUG_ON(hstate->connp == NULL); + hstate->slice = &stream_slice; + + htp_time_t ts = { SCTIME_SECS(f->startts), SCTIME_USECS(f->startts) }; + htp_tx_t *tx = NULL; + size_t consumed = 0; + if (input_len > 0) { + const int r = htp_connp_res_data(hstate->connp, &ts, input, input_len); + switch (r) { + case HTP_STREAM_ERROR: + ret = -1; + break; + case HTP_STREAM_TUNNEL: + tx = htp_connp_get_out_tx(hstate->connp); + if (tx != NULL && tx->response_status_number == 101) { + htp_header_t *h = + (htp_header_t *)htp_table_get_c(tx->response_headers, "Upgrade"); + if (h == NULL || bstr_cmp_c(h->value, "h2c") != 0) { + break; + } + if (AppLayerProtoDetectGetProtoName(ALPROTO_HTTP2) == NULL) { + // if HTTP2 is disabled, keep the HTP_STREAM_TUNNEL mode + break; + } + uint16_t dp = 0; + if (tx->request_port_number != -1) { + dp = (uint16_t)tx->request_port_number; + } + consumed = htp_connp_res_data_consumed(hstate->connp); + hstate->slice = NULL; + if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_HTTP2)) { + HTPSetEvent(hstate, NULL, STREAM_TOCLIENT, + HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE); + } + // During HTTP2 upgrade, we may consume the HTTP1 part of the data + // and we need to parser the remaining part with HTTP2 + if (consumed > 0 && consumed < input_len) { + SCReturnStruct(APP_LAYER_INCOMPLETE(consumed, input_len - consumed)); + } + SCReturnStruct(APP_LAYER_OK); + } + break; + default: + break; + } + HTPHandleError(hstate, STREAM_TOCLIENT); + } + + /* if we the TCP connection is closed, then close the HTTP connection */ + if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) && + !(hstate->flags & HTP_FLAG_STATE_CLOSED_TC)) { + htp_connp_close(hstate->connp, &ts); + hstate->flags |= HTP_FLAG_STATE_CLOSED_TC; + } + + SCLogDebug("hstate->connp %p", hstate->connp); + hstate->slice = NULL; + + if (ret < 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + SCReturnStruct(APP_LAYER_OK); +} + +/** + * \param name /Lowercase/ version of the variable name + */ +static int HTTPParseContentDispositionHeader( + uint8_t *name, size_t name_len, uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen) +{ +#ifdef PRINT + printf("DATA START: \n"); + PrintRawDataFp(stdout, data, len); + printf("DATA END: \n"); +#endif + size_t x; + int quote = 0; + + for (x = 0; x < len; x++) { + if (!(isspace(data[x]))) + break; + } + + if (x >= len) + return 0; + + uint8_t *line = data + x; + size_t line_len = len - x; + size_t offset = 0; +#ifdef PRINT + printf("LINE START: \n"); + PrintRawDataFp(stdout, line, line_len); + printf("LINE END: \n"); +#endif + for (x = 0; x < line_len; x++) { + if (x > 0) { + if (line[x - 1] != '\\' && line[x] == '\"') { + quote++; + } + + if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && + (quote == 0 || quote % 2 == 0)) { + uint8_t *token = line + offset; + size_t token_len = x - offset; + + if ((x + 1) == line_len) { + token_len++; + } + + offset = x + 1; + + while (offset < line_len && isspace(line[offset])) { + x++; + offset++; + } +#ifdef PRINT + printf("TOKEN START: \n"); + PrintRawDataFp(stdout, token, token_len); + printf("TOKEN END: \n"); +#endif + if (token_len > name_len) { + if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) { + uint8_t *value = token + name_len; + size_t value_len = token_len - name_len; + + if (value[0] == '\"') { + value++; + value_len--; + } + if (value[value_len - 1] == '\"') { + value_len--; + } +#ifdef PRINT + printf("VALUE START: \n"); + PrintRawDataFp(stdout, value, value_len); + printf("VALUE END: \n"); +#endif + *retptr = value; + *retlen = value_len; + return 1; + } + } + } + } + } + + return 0; +} + +/** + * \param name /Lowercase/ version of the variable name + */ +static int HTTPParseContentTypeHeader( + uint8_t *name, size_t name_len, uint8_t *data, size_t len, uint8_t **retptr, size_t *retlen) +{ + SCEnter(); +#ifdef PRINT + printf("DATA START: \n"); + PrintRawDataFp(stdout, data, len); + printf("DATA END: \n"); +#endif + size_t x; + int quote = 0; + + for (x = 0; x < len; x++) { + if (!(isspace(data[x]))) + break; + } + + if (x >= len) { + SCReturnInt(0); + } + + uint8_t *line = data + x; + size_t line_len = len - x; + size_t offset = 0; +#ifdef PRINT + printf("LINE START: \n"); + PrintRawDataFp(stdout, line, line_len); + printf("LINE END: \n"); +#endif + for (x = 0; x < line_len; x++) { + if (x > 0) { + if (line[x - 1] != '\\' && line[x] == '\"') { + quote++; + } + + if (((line[x - 1] != '\\' && line[x] == ';') || ((x + 1) == line_len)) && + (quote == 0 || quote % 2 == 0)) { + uint8_t *token = line + offset; + size_t token_len = x - offset; + + if ((x + 1) == line_len) { + token_len++; + } + + offset = x + 1; + + while (offset < line_len && isspace(line[offset])) { + x++; + offset++; + } +#ifdef PRINT + printf("TOKEN START: \n"); + PrintRawDataFp(stdout, token, token_len); + printf("TOKEN END: \n"); +#endif + if (token_len > name_len) { + if (name == NULL || SCMemcmpLowercase(name, token, name_len) == 0) { + uint8_t *value = token + name_len; + size_t value_len = token_len - name_len; + + if (value[0] == '\"') { + value++; + value_len--; + } + if (value[value_len - 1] == '\"') { + value_len--; + } +#ifdef PRINT + printf("VALUE START: \n"); + PrintRawDataFp(stdout, value, value_len); + printf("VALUE END: \n"); +#endif + *retptr = value; + *retlen = value_len; + SCReturnInt(1); + } + } + } + } + } + + SCReturnInt(0); +} + +/** + * \brief setup multipart parsing: extract boundary and store it + * + * \param d HTTP transaction + * \param htud transaction userdata + * + * \retval 1 ok, multipart set up + * \retval 0 ok, not multipart though + * \retval -1 error: problem with the boundary + * + * If the request contains a multipart message, this function will + * set the HTP_BOUNDARY_SET in the transaction. + */ +static int HtpRequestBodySetupMultipart(htp_tx_t *tx, HtpTxUserData *htud) +{ + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, "Content-Type"); + if (h != NULL && bstr_len(h->value) > 0) { + uint8_t *boundary = NULL; + size_t boundary_len = 0; + + int r = HTTPParseContentTypeHeader((uint8_t *)"boundary=", 9, (uint8_t *)bstr_ptr(h->value), + bstr_len(h->value), &boundary, &boundary_len); + if (r == 1) { +#ifdef PRINT + printf("BOUNDARY START: \n"); + PrintRawDataFp(stdout, boundary, boundary_len); + printf("BOUNDARY END: \n"); +#endif + if (boundary_len < HTP_BOUNDARY_MAX) { + htud->boundary = HTPMalloc(boundary_len); + if (htud->boundary == NULL) { + return -1; + } + htud->boundary_len = (uint8_t)boundary_len; + memcpy(htud->boundary, boundary, boundary_len); + + htud->tsflags |= HTP_BOUNDARY_SET; + } else { + SCLogDebug("invalid boundary"); + return -1; + } + SCReturnInt(1); + } + // SCReturnInt(1); + } + SCReturnInt(0); +} + +#define C_D_HDR "content-disposition:" +#define C_D_HDR_LEN 20 +#define C_T_HDR "content-type:" +#define C_T_HDR_LEN 13 + +static void HtpRequestBodyMultipartParseHeader(HtpState *hstate, HtpTxUserData *htud, + uint8_t *header, uint32_t header_len, uint8_t **filename, uint16_t *filename_len, + uint8_t **filetype, uint16_t *filetype_len) +{ + uint8_t *fn = NULL; + size_t fn_len = 0; + uint8_t *ft = NULL; + size_t ft_len = 0; + +#ifdef PRINT + printf("HEADER START: \n"); + PrintRawDataFp(stdout, header, header_len); + printf("HEADER END: \n"); +#endif + + while (header_len > 0) { + uint8_t *next_line = Bs2bmSearch(header, header_len, (uint8_t *)"\r\n", 2); + uint8_t *line = header; + uint32_t line_len; + + if (next_line == NULL) { + line_len = header_len; + } else { + line_len = next_line - header; + } + uint8_t *sc = (uint8_t *)memchr(line, ':', line_len); + if (sc == NULL) { + HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER); + /* if the : we found is the final char, it means we have + * no value */ + } else if (line_len > 0 && sc == &line[line_len - 1]) { + HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER); + } else { +#ifdef PRINT + printf("LINE START: \n"); + PrintRawDataFp(stdout, line, line_len); + printf("LINE END: \n"); +#endif + if (line_len >= C_D_HDR_LEN && SCMemcmpLowercase(C_D_HDR, line, C_D_HDR_LEN) == 0) { + uint8_t *value = line + C_D_HDR_LEN; + uint32_t value_len = line_len - C_D_HDR_LEN; + + /* parse content-disposition */ + (void)HTTPParseContentDispositionHeader( + (uint8_t *)"filename=", 9, value, value_len, &fn, &fn_len); + } else if (line_len >= C_T_HDR_LEN && + SCMemcmpLowercase(C_T_HDR, line, C_T_HDR_LEN) == 0) { + SCLogDebug("content-type line"); + uint8_t *value = line + C_T_HDR_LEN; + uint32_t value_len = line_len - C_T_HDR_LEN; + + (void)HTTPParseContentTypeHeader(NULL, 0, value, value_len, &ft, &ft_len); + } + } + + if (next_line == NULL) { + SCLogDebug("no next_line"); + break; + } + header_len -= ((next_line + 2) - header); + header = next_line + 2; + } /* while (header_len > 0) */ + + if (fn_len > USHRT_MAX) + fn_len = USHRT_MAX; + if (ft_len > USHRT_MAX) + ft_len = USHRT_MAX; + + *filename = fn; + *filename_len = (uint16_t)fn_len; + *filetype = ft; + *filetype_len = (uint16_t)ft_len; +} + +/** + * \brief Create a single buffer from the HtpBodyChunks in our list + * + * \param htud transaction user data + * \param chunks_buffers pointer to pass back the buffer to the caller + * \param chunks_buffer_len pointer to pass back the buffer length to the caller + */ +static void HtpRequestBodyReassemble( + HtpTxUserData *htud, const uint8_t **chunks_buffer, uint32_t *chunks_buffer_len) +{ + StreamingBufferGetDataAtOffset(htud->request_body.sb, chunks_buffer, chunks_buffer_len, + htud->request_body.body_parsed); +} + +static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir) +{ + SCEnter(); + if (tx && tx->tx_data.de_state) { + if (dir == STREAM_TOSERVER) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set"); + tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW; + } else if (STREAM_TOCLIENT) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set"); + tx->tx_data.de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW; + } + } +} + +/** + * \brief Setup boundary buffers + */ +static void HtpRequestBodySetupBoundary( + HtpTxUserData *htud, uint8_t *boundary, uint32_t boundary_len) +{ + memset(boundary, '-', boundary_len); + memcpy(boundary + 2, htud->boundary, htud->boundary_len); +} + +static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, void *tx, + const uint8_t *chunks_buffer, uint32_t chunks_buffer_len) +{ + int result = 0; + uint8_t boundary[htud->boundary_len + 4]; /**< size limited to HTP_BOUNDARY_MAX + 4 */ + uint16_t expected_boundary_len = htud->boundary_len + 2; + uint16_t expected_boundary_end_len = htud->boundary_len + 4; + int tx_progress = 0; + +#ifdef PRINT + printf("CHUNK START: \n"); + PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); + printf("CHUNK END: \n"); +#endif + + HtpRequestBodySetupBoundary(htud, boundary, htud->boundary_len + 4); + + /* search for the header start, header end and form end */ + const uint8_t *header_start = + Bs2bmSearch(chunks_buffer, chunks_buffer_len, boundary, expected_boundary_len); + /* end of the multipart form */ + const uint8_t *form_end = NULL; + /* end marker belonging to header_start */ + const uint8_t *header_end = NULL; + if (header_start != NULL) { + header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), + (uint8_t *)"\r\n\r\n", 4); + form_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), + boundary, expected_boundary_end_len); + } + + SCLogDebug("header_start %p, header_end %p, form_end %p", header_start, header_end, form_end); + + /* we currently only handle multipart for ts. When we support it for tc, + * we will need to supply right direction */ + tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, STREAM_TOSERVER); + /* if we're in the file storage process, deal with that now */ + if (htud->tsflags & HTP_FILENAME_SET) { + if (header_start != NULL || (tx_progress > HTP_REQUEST_BODY)) { + SCLogDebug("reached the end of the file"); + + const uint8_t *filedata = chunks_buffer; + uint32_t filedata_len = 0; + uint8_t flags = 0; + + if (header_start != NULL) { + if (header_start == filedata + 2) { + /* last chunk had all data, but not the boundary */ + SCLogDebug("last chunk had all data, but not the boundary"); + filedata_len = 0; + } else if (header_start > filedata + 2) { + SCLogDebug("some data from last file before the boundary"); + /* some data from last file before the boundary */ + filedata_len = header_start - filedata - 2; + } + } + /* body parsing done, we did not get our form end. Use all data + * we still have and signal to files API we have an issue. */ + if (tx_progress > HTP_REQUEST_BODY) { + filedata_len = chunks_buffer_len; + flags = FILE_TRUNCATED; + } + + if (filedata_len > chunks_buffer_len) { + HTPSetEvent( + hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); + goto end; + } +#ifdef PRINT + printf("FILEDATA (final chunk) START: \n"); + PrintRawDataFp(stdout, filedata, filedata_len); + printf("FILEDATA (final chunk) END: \n"); +#endif + if (!(htud->tsflags & HTP_DONTSTORE)) { + if (HTPFileClose(hstate, htud, filedata, filedata_len, flags, STREAM_TOSERVER) == + -1) { + goto end; + } + } + + htud->tsflags &= ~HTP_FILENAME_SET; + + /* fall through */ + } else { + SCLogDebug("not yet at the end of the file"); + + if (chunks_buffer_len > expected_boundary_end_len) { + const uint8_t *filedata = chunks_buffer; + uint32_t filedata_len = chunks_buffer_len - expected_boundary_len; + for (; filedata_len < chunks_buffer_len; filedata_len++) { + // take as much as we can until the beginning of a new line + if (chunks_buffer[filedata_len] == '\r') { + if (filedata_len + 1 == chunks_buffer_len || + chunks_buffer[filedata_len + 1] == '\n') { + break; + } + } + } + +#ifdef PRINT + printf("FILEDATA (part) START: \n"); + PrintRawDataFp(stdout, filedata, filedata_len); + printf("FILEDATA (part) END: \n"); +#endif + + if (!(htud->tsflags & HTP_DONTSTORE)) { + result = HTPFileStoreChunk( + hstate, htud, filedata, filedata_len, STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + /* we know for sure we're not storing the file */ + htud->tsflags |= HTP_DONTSTORE; + } + } + + htud->request_body.body_parsed += filedata_len; + } else { + SCLogDebug("chunk too small to already process in part"); + } + + goto end; + } + } + + while (header_start != NULL && header_end != NULL && header_end != form_end && + header_start < (chunks_buffer + chunks_buffer_len) && + header_end < (chunks_buffer + chunks_buffer_len) && header_start < header_end) { + uint8_t *filename = NULL; + uint16_t filename_len = 0; + uint8_t *filetype = NULL; + uint16_t filetype_len = 0; + + uint32_t header_len = header_end - header_start; + SCLogDebug("header_len %u", header_len); + uint8_t *header = (uint8_t *)header_start; + + /* skip empty records */ + if (expected_boundary_len == header_len) { + goto next; + } else if ((uint32_t)(expected_boundary_len + 2) <= header_len) { + header_len -= (expected_boundary_len + 2); + header = (uint8_t *)header_start + (expected_boundary_len + 2); // + for 0d 0a + } + + HtpRequestBodyMultipartParseHeader(hstate, htud, header, header_len, &filename, + &filename_len, &filetype, &filetype_len); + + if (filename != NULL) { + const uint8_t *filedata = NULL; + uint32_t filedata_len = 0; + + SCLogDebug("we have a filename"); + + htud->tsflags |= HTP_FILENAME_SET; + htud->tsflags &= ~HTP_DONTSTORE; + + SCLogDebug("header_end %p", header_end); + SCLogDebug("form_end %p", form_end); + + /* everything until the final boundary is the file */ + if (form_end != NULL) { + SCLogDebug("have form_end"); + + filedata = header_end + 4; + if (form_end == filedata) { + HTPSetEvent(hstate, htud, STREAM_TOSERVER, + HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA); + goto end; + } else if (form_end < filedata) { + HTPSetEvent(hstate, htud, STREAM_TOSERVER, + HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); + goto end; + } + + filedata_len = form_end - (header_end + 4 + 2); + SCLogDebug("filedata_len %" PRIuMAX, (uintmax_t)filedata_len); + + /* or is it? */ + uint8_t *header_next = + Bs2bmSearch(filedata, filedata_len, boundary, expected_boundary_len); + if (header_next != NULL) { + filedata_len -= (form_end - header_next); + } + + if (filedata_len > chunks_buffer_len) { + HTPSetEvent(hstate, htud, STREAM_TOSERVER, + HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); + goto end; + } + SCLogDebug("filedata_len %" PRIuMAX, (uintmax_t)filedata_len); +#ifdef PRINT + printf("FILEDATA START: \n"); + PrintRawDataFp(stdout, filedata, filedata_len); + printf("FILEDATA END: \n"); +#endif + + result = HTPFileOpen(hstate, htud, filename, filename_len, filedata, filedata_len, + HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + htud->tsflags |= HTP_DONTSTORE; + } else { + if (HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOSERVER) == -1) { + goto end; + } + } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); + + htud->request_body.body_parsed += (header_end - chunks_buffer); + htud->tsflags &= ~HTP_FILENAME_SET; + } else { + SCLogDebug("chunk doesn't contain form end"); + + filedata = header_end + 4; + filedata_len = chunks_buffer_len - (filedata - chunks_buffer); + SCLogDebug( + "filedata_len %u (chunks_buffer_len %u)", filedata_len, chunks_buffer_len); + + if (filedata_len > chunks_buffer_len) { + HTPSetEvent(hstate, htud, STREAM_TOSERVER, + HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR); + goto end; + } + +#ifdef PRINT + printf("FILEDATA START: \n"); + PrintRawDataFp(stdout, filedata, filedata_len); + printf("FILEDATA END: \n"); +#endif + /* form doesn't end in this chunk, but the part might. Lets + * see if have another coming up */ + uint8_t *header_next = + Bs2bmSearch(filedata, filedata_len, boundary, expected_boundary_len); + SCLogDebug("header_next %p", header_next); + if (header_next == NULL) { + SCLogDebug("more file data to come"); + + uint32_t offset = (header_end + 4) - chunks_buffer; + SCLogDebug("offset %u", offset); + htud->request_body.body_parsed += offset; + + if (filedata_len >= (uint32_t)(expected_boundary_len + 2)) { + filedata_len -= (expected_boundary_len + 2 - 1); + // take as much as we can until start of boundary + for (size_t nb = 0; nb < (size_t)expected_boundary_len + 1; nb++) { + if (filedata[filedata_len] == '\r') { + if (nb == expected_boundary_len || + filedata[filedata_len + 1] == '\n') { + break; + } + } + filedata_len++; + } + SCLogDebug("opening file with partial data"); + } else { + filedata = NULL; + filedata_len = 0; + } + result = HTPFileOpen(hstate, htud, filename, filename_len, filedata, + filedata_len, HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + htud->tsflags |= HTP_DONTSTORE; + } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); + htud->request_body.body_parsed += filedata_len; + SCLogDebug("htud->request_body.body_parsed %" PRIu64, + htud->request_body.body_parsed); + + } else if (header_next - filedata > 2) { + filedata_len = header_next - filedata - 2; + SCLogDebug("filedata_len %u", filedata_len); + + result = HTPFileOpen(hstate, htud, filename, filename_len, filedata, + filedata_len, HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + htud->tsflags |= HTP_DONTSTORE; + } else { + if (HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOSERVER) == -1) { + goto end; + } + } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); + + htud->tsflags &= ~HTP_FILENAME_SET; + htud->request_body.body_parsed += (header_end - chunks_buffer); + } + } + } + next: + SCLogDebug( + "header_start %p, header_end %p, form_end %p", header_start, header_end, form_end); + + /* Search next boundary entry after the start of body */ + uint32_t cursizeread = header_end - chunks_buffer; + header_start = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), boundary, + expected_boundary_len); + if (header_start != NULL) { + header_end = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), + (uint8_t *)"\r\n\r\n", 4); + } + } + + /* if we're parsing the multipart and we're not currently processing a + * file, we move the body pointer forward. */ + if (form_end == NULL && !(htud->tsflags & HTP_FILENAME_SET) && header_start == NULL) { + if (chunks_buffer_len > expected_boundary_end_len) { + uint32_t move = chunks_buffer_len - expected_boundary_end_len + 1; + + htud->request_body.body_parsed += move; + SCLogDebug("form not ready, file not set, parsing non-file " + "record: moved %u", + move); + } + } + +end: + SCLogDebug("htud->request_body.body_parsed %" PRIu64, htud->request_body.body_parsed); + return 0; +} + +/** \internal + * \brief Handle POST or PUT, no multipart body data + */ +static int HtpRequestBodyHandlePOSTorPUT( + HtpState *hstate, HtpTxUserData *htud, htp_tx_t *tx, uint8_t *data, uint32_t data_len) +{ + int result = 0; + + /* see if we need to open the file */ + if (!(htud->tsflags & HTP_FILENAME_SET)) { + uint8_t *filename = NULL; + size_t filename_len = 0; + + /* get the name */ + if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { + filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); + filename_len = bstr_len(tx->parsed_uri->path); + } + + if (filename != NULL) { + if (filename_len > SC_FILENAME_MAX) { + // explicitly truncate the file name if too long + filename_len = SC_FILENAME_MAX; + HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG); + } + result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len, + HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + htud->tsflags |= HTP_DONTSTORE; + } else { + FlagDetectStateNewFile(htud, STREAM_TOSERVER); + htud->tsflags |= HTP_FILENAME_SET; + htud->tsflags &= ~HTP_DONTSTORE; + } + } + } else { + /* otherwise, just store the data */ + + if (!(htud->tsflags & HTP_DONTSTORE)) { + result = HTPFileStoreChunk(hstate, htud, data, data_len, STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + /* we know for sure we're not storing the file */ + htud->tsflags |= HTP_DONTSTORE; + } + } + } + + return 0; +end: + return -1; +} + +static int HtpResponseBodyHandle( + HtpState *hstate, HtpTxUserData *htud, htp_tx_t *tx, uint8_t *data, uint32_t data_len) +{ + SCEnter(); + + int result = 0; + + /* see if we need to open the file + * we check for tx->response_line in case of junk + * interpreted as body before response line + */ + if (!(htud->tcflags & HTP_FILENAME_SET)) { + SCLogDebug("setting up file name"); + + uint8_t *filename = NULL; + size_t filename_len = 0; + + /* try Content-Disposition header first */ + htp_header_t *h = + (htp_header_t *)htp_table_get_c(tx->response_headers, "Content-Disposition"); + if (h != NULL && bstr_len(h->value) > 0) { + /* parse content-disposition */ + (void)HTTPParseContentDispositionHeader((uint8_t *)"filename=", 9, + (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), &filename, &filename_len); + } + + /* fall back to name from the uri */ + if (filename == NULL) { + /* get the name */ + if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { + filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); + filename_len = bstr_len(tx->parsed_uri->path); + } + } + + if (filename != NULL) { + // set range if present + htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range"); + if (filename_len > SC_FILENAME_MAX) { + // explicitly truncate the file name if too long + filename_len = SC_FILENAME_MAX; + HTPSetEvent(hstate, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG); + } + if (h_content_range != NULL) { + result = HTPFileOpenWithRange(hstate, htud, filename, (uint16_t)filename_len, data, + data_len, HtpGetActiveResponseTxID(hstate), h_content_range->value, htud); + } else { + result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len, + HtpGetActiveResponseTxID(hstate), STREAM_TOCLIENT); + } + SCLogDebug("result %d", result); + if (result == -1) { + goto end; + } else if (result == -2) { + htud->tcflags |= HTP_DONTSTORE; + } else { + FlagDetectStateNewFile(htud, STREAM_TOCLIENT); + htud->tcflags |= HTP_FILENAME_SET; + htud->tcflags &= ~HTP_DONTSTORE; + } + } + } else { + /* otherwise, just store the data */ + + if (!(htud->tcflags & HTP_DONTSTORE)) { + result = HTPFileStoreChunk(hstate, htud, data, data_len, STREAM_TOCLIENT); + SCLogDebug("result %d", result); + if (result == -1) { + goto end; + } else if (result == -2) { + /* we know for sure we're not storing the file */ + htud->tcflags |= HTP_DONTSTORE; + } + } + } + + htud->response_body.body_parsed += data_len; + return 0; +end: + return -1; +} + +/** + * \brief Function callback to append chunks for Requests + * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib) + * \retval int HTP_OK if all goes well + */ +static int HTPCallbackRequestBodyData(htp_tx_data_t *d) +{ + SCEnter(); + + if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_REQUEST_BODY)) + SCReturnInt(HTP_OK); + + if (d->len == 0) + SCReturnInt(HTP_OK); + +#ifdef PRINT + printf("HTPBODY START: \n"); + PrintRawDataFp(stdout, (uint8_t *)d->data, d->len); + printf("HTPBODY END: \n"); +#endif + + HtpState *hstate = htp_connp_get_user_data(d->tx->connp); + if (hstate == NULL) { + SCReturnInt(HTP_ERROR); + } + + SCLogDebug("New request body data available at %p -> %p -> %p, bodylen " + "%" PRIu32 "", + hstate, d, d->data, (uint32_t)d->len); + + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(d->tx); + if (tx_ud == NULL) { + SCReturnInt(HTP_OK); + } + tx_ud->tx_data.file_flags |= hstate->state_data.file_flags; + + if (!tx_ud->response_body_init) { + tx_ud->response_body_init = 1; + + if (d->tx->request_method_number == HTP_M_POST) { + SCLogDebug("POST"); + int r = HtpRequestBodySetupMultipart(d->tx, tx_ud); + if (r == 1) { + tx_ud->request_body_type = HTP_BODY_REQUEST_MULTIPART; + } else if (r == 0) { + tx_ud->request_body_type = HTP_BODY_REQUEST_POST; + SCLogDebug("not multipart"); + } + } else if (d->tx->request_method_number == HTP_M_PUT) { + tx_ud->request_body_type = HTP_BODY_REQUEST_PUT; + } + } + + /* see if we can get rid of htp body chunks */ + HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER); + + SCLogDebug("tx_ud->request_body.content_len_so_far %" PRIu64, + tx_ud->request_body.content_len_so_far); + SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit); + + /* within limits, add the body chunk to the state. */ + if (AppLayerHtpCheckDepth(&hstate->cfg->request, &tx_ud->request_body, tx_ud->tsflags)) { + uint32_t stream_depth = FileReassemblyDepth(); + uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->request_body.content_len_so_far, + hstate->cfg->request.body_limit, stream_depth, tx_ud->tsflags, (uint32_t)d->len); + BUG_ON(len > (uint32_t)d->len); + + HtpBodyAppendChunk(&hstate->cfg->request, &tx_ud->request_body, d->data, len); + + const uint8_t *chunks_buffer = NULL; + uint32_t chunks_buffer_len = 0; + + if (tx_ud->request_body_type == HTP_BODY_REQUEST_MULTIPART) { + /* multi-part body handling starts here */ + if (!(tx_ud->tsflags & HTP_BOUNDARY_SET)) { + goto end; + } + + HtpRequestBodyReassemble(tx_ud, &chunks_buffer, &chunks_buffer_len); + if (chunks_buffer == NULL) { + goto end; + } +#ifdef PRINT + printf("REASSCHUNK START: \n"); + PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); + printf("REASSCHUNK END: \n"); +#endif + + HtpRequestBodyHandleMultipart(hstate, tx_ud, d->tx, chunks_buffer, chunks_buffer_len); + + } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST || + tx_ud->request_body_type == HTP_BODY_REQUEST_PUT) { + HtpRequestBodyHandlePOSTorPUT(hstate, tx_ud, d->tx, (uint8_t *)d->data, len); + } + + } else { + if (tx_ud->tsflags & HTP_FILENAME_SET) { + SCLogDebug("closing file that was being stored"); + (void)HTPFileClose(hstate, tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOSERVER); + tx_ud->tsflags &= ~HTP_FILENAME_SET; + } + } + +end: + if (hstate->conn != NULL) { + SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64 + ", last %" PRIu64 ")", + tx_ud->request_body.content_len_so_far, hstate->cfg->request.inspect_min_size, + (uint64_t)hstate->conn->in_data_counter, hstate->last_request_data_stamp); + + /* if we reach the inspect_min_size we'll trigger inspection, + * so make sure that raw stream is also inspected. Set the + * data to be used to the amount of raw bytes we've seen to + * get here. */ + if (tx_ud->request_body.body_inspected == 0 && + tx_ud->request_body.content_len_so_far >= hstate->cfg->request.inspect_min_size) { + if ((uint64_t)hstate->conn->in_data_counter > hstate->last_request_data_stamp && + (uint64_t)hstate->conn->in_data_counter - hstate->last_request_data_stamp < + (uint64_t)UINT_MAX) { + const uint32_t data_size = (uint32_t)( + (uint64_t)hstate->conn->in_data_counter - hstate->last_request_data_stamp); + const uint32_t depth = MIN(data_size, hstate->cfg->request.inspect_min_size); + + /* body still in progress, but due to min inspect size we need to inspect now */ + StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, depth); + AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER); + } + /* after the start of the body, disable the depth logic */ + } else if (tx_ud->request_body.body_inspected > 0) { + StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOSERVER, 0); + } + } + SCReturnInt(HTP_OK); +} + +/** + * \brief Function callback to append chunks for Responses + * \param d pointer to the htp_tx_data_t structure (a chunk from htp lib) + * \retval int HTP_OK if all goes well + */ +static int HTPCallbackResponseBodyData(htp_tx_data_t *d) +{ + SCEnter(); + + if (!(SC_ATOMIC_GET(htp_config_flags) & HTP_REQUIRE_RESPONSE_BODY)) + SCReturnInt(HTP_OK); + + if (d->len == 0) + SCReturnInt(HTP_OK); + + HtpState *hstate = htp_connp_get_user_data(d->tx->connp); + if (hstate == NULL) { + SCReturnInt(HTP_ERROR); + } + + SCLogDebug("New response body data available at %p -> %p -> %p, bodylen " + "%" PRIu32 "", + hstate, d, d->data, (uint32_t)d->len); + + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(d->tx); + if (tx_ud == NULL) { + SCReturnInt(HTP_OK); + } + tx_ud->tx_data.file_flags |= hstate->state_data.file_flags; + if (!tx_ud->request_body_init) { + tx_ud->request_body_init = 1; + } + + /* see if we can get rid of htp body chunks */ + HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT); + + SCLogDebug("tx_ud->response_body.content_len_so_far %" PRIu64, + tx_ud->response_body.content_len_so_far); + SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit); + + /* within limits, add the body chunk to the state. */ + if (AppLayerHtpCheckDepth(&hstate->cfg->response, &tx_ud->response_body, tx_ud->tcflags)) { + uint32_t stream_depth = FileReassemblyDepth(); + uint32_t len = AppLayerHtpComputeChunkLength(tx_ud->response_body.content_len_so_far, + hstate->cfg->response.body_limit, stream_depth, tx_ud->tcflags, (uint32_t)d->len); + BUG_ON(len > (uint32_t)d->len); + + HtpBodyAppendChunk(&hstate->cfg->response, &tx_ud->response_body, d->data, len); + + HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, len); + } else { + if (tx_ud->tcflags & HTP_FILENAME_SET) { + SCLogDebug("closing file that was being stored"); + (void)HTPFileClose(hstate, tx_ud, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT); + tx_ud->tcflags &= ~HTP_FILENAME_SET; + } + } + + if (hstate->conn != NULL) { + SCLogDebug("checking body size %" PRIu64 " against inspect limit %u (cur %" PRIu64 + ", last %" PRIu64 ")", + tx_ud->response_body.content_len_so_far, hstate->cfg->response.inspect_min_size, + (uint64_t)hstate->conn->in_data_counter, hstate->last_response_data_stamp); + /* if we reach the inspect_min_size we'll trigger inspection, + * so make sure that raw stream is also inspected. Set the + * data to be used to the amount of raw bytes we've seen to + * get here. */ + if (tx_ud->response_body.body_inspected == 0 && + tx_ud->response_body.content_len_so_far >= hstate->cfg->response.inspect_min_size) { + if ((uint64_t)hstate->conn->out_data_counter > hstate->last_response_data_stamp && + (uint64_t)hstate->conn->out_data_counter - hstate->last_response_data_stamp < + (uint64_t)UINT_MAX) { + const uint32_t data_size = (uint32_t)((uint64_t)hstate->conn->out_data_counter - + hstate->last_response_data_stamp); + const uint32_t depth = MIN(data_size, hstate->cfg->response.inspect_min_size); + + /* body still in progress, but due to min inspect size we need to inspect now */ + StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, depth); + AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT); + } + /* after the start of the body, disable the depth logic */ + } else if (tx_ud->response_body.body_inspected > 0) { + StreamTcpReassemblySetMinInspectDepth(hstate->f->protoctx, STREAM_TOCLIENT, 0); + } + } + SCReturnInt(HTP_OK); +} + +/** + * \brief Print the stats of the HTTP requests + */ +void HTPAtExitPrintStats(void) +{ +#ifdef DEBUG + SCEnter(); + SCMutexLock(&htp_state_mem_lock); + SCLogDebug("http_state_memcnt %" PRIu64 ", http_state_memuse %" PRIu64 "", htp_state_memcnt, + htp_state_memuse); + SCMutexUnlock(&htp_state_mem_lock); + SCReturn; +#endif +} + +/** \brief Clears the HTTP server configuration memory used by HTP library */ +void HTPFreeConfig(void) +{ + SCEnter(); + + if (!AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "http") || + !AppLayerParserConfParserEnabled("tcp", "http")) { + SCReturn; + } + + HTPCfgRec *nextrec = cfglist.next; + SCRadixReleaseRadixTree(cfgtree); + cfgtree = NULL; + htp_config_destroy(cfglist.cfg); + while (nextrec != NULL) { + HTPCfgRec *htprec = nextrec; + nextrec = nextrec->next; + + htp_config_destroy(htprec->cfg); + SCFree(htprec); + } + SCReturn; +} + +static int HTPCallbackRequestHasTrailer(htp_tx_t *tx) +{ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + htud->request_has_trailers = 1; + } + return HTP_OK; +} + +static int HTPCallbackResponseHasTrailer(htp_tx_t *tx) +{ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + htud->response_has_trailers = 1; + } + return HTP_OK; +} + +/**\internal + * \brief called at start of request + * Set min inspect size. + */ +static int HTPCallbackRequestStart(htp_tx_t *tx) +{ + HtpState *hstate = htp_connp_get_user_data(tx->connp); + if (hstate == NULL) { + SCReturnInt(HTP_ERROR); + } + + uint64_t consumed = hstate->slice->offset + htp_connp_req_data_consumed(hstate->connp); + SCLogDebug("HTTP request start: data offset %" PRIu64 ", in_data_counter %" PRIu64, consumed, + (uint64_t)hstate->conn->in_data_counter); + + /* app-layer-frame-documentation tag start: frame registration http request */ + Frame *frame = AppLayerFrameNewByAbsoluteOffset( + hstate->f, hstate->slice, consumed, -1, 0, HTTP_FRAME_REQUEST); + if (frame) { + SCLogDebug("frame %p/%" PRIi64, frame, frame->id); + hstate->request_frame_id = frame->id; + AppLayerFrameSetTxId(frame, HtpGetActiveRequestTxID(hstate)); + } + /* app-layer-frame-documentation tag end: frame registration http request */ + + if (hstate->cfg) + StreamTcpReassemblySetMinInspectDepth( + hstate->f->protoctx, STREAM_TOSERVER, hstate->cfg->request.inspect_min_size); + + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud == NULL) { + tx_ud = HTPCalloc(1, sizeof(HtpTxUserData)); + if (unlikely(tx_ud == NULL)) { + SCReturnInt(HTP_OK); + } + tx_ud->tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT; // each http tx may xfer files + htp_tx_set_user_data(tx, tx_ud); + } + SCReturnInt(HTP_OK); +} + +/**\internal + * \brief called at start of response + * Set min inspect size. + */ +static int HTPCallbackResponseStart(htp_tx_t *tx) +{ + HtpState *hstate = htp_connp_get_user_data(tx->connp); + if (hstate == NULL) { + SCReturnInt(HTP_ERROR); + } + + uint64_t consumed = hstate->slice->offset + htp_connp_res_data_consumed(hstate->connp); + SCLogDebug("HTTP response start: data offset %" PRIu64 ", out_data_counter %" PRIu64, consumed, + (uint64_t)hstate->conn->out_data_counter); + + Frame *frame = AppLayerFrameNewByAbsoluteOffset( + hstate->f, hstate->slice, consumed, -1, 1, HTTP_FRAME_RESPONSE); + if (frame) { + SCLogDebug("frame %p/%" PRIi64, frame, frame->id); + hstate->response_frame_id = frame->id; + AppLayerFrameSetTxId(frame, HtpGetActiveResponseTxID(hstate)); + } + + if (hstate->cfg) + StreamTcpReassemblySetMinInspectDepth( + hstate->f->protoctx, STREAM_TOCLIENT, hstate->cfg->response.inspect_min_size); + + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud == NULL) { + tx_ud = HTPCalloc(1, sizeof(HtpTxUserData)); + if (unlikely(tx_ud == NULL)) { + SCReturnInt(HTP_OK); + } + tx_ud->tx_data.file_tx = + STREAM_TOCLIENT; // each http tx may xfer files. Toserver already missed. + htp_tx_set_user_data(tx, tx_ud); + } + SCReturnInt(HTP_OK); +} + +/** + * \brief callback for request to store the recent incoming request + into the recent_in_tx for the given htp state + * \param connp pointer to the current connection parser which has the htp + * state in it as user data + */ +static int HTPCallbackRequestComplete(htp_tx_t *tx) +{ + SCEnter(); + + if (tx == NULL) { + SCReturnInt(HTP_ERROR); + } + + HtpState *hstate = htp_connp_get_user_data(tx->connp); + if (hstate == NULL) { + SCReturnInt(HTP_ERROR); + } + + const uint64_t abs_right_edge = + hstate->slice->offset + htp_connp_req_data_consumed(hstate->connp); + + /* app-layer-frame-documentation tag start: updating frame->len */ + if (hstate->request_frame_id > 0) { + Frame *frame = AppLayerFrameGetById(hstate->f, 0, hstate->request_frame_id); + if (frame) { + const uint64_t request_size = abs_right_edge - hstate->last_request_data_stamp; + + SCLogDebug("HTTP request complete: data offset %" PRIu64 ", request_size %" PRIu64, + hstate->last_request_data_stamp, request_size); + SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id, + request_size); + frame->len = (int64_t)request_size; + /* app-layer-frame-documentation tag end: updating frame->len */ + } + hstate->request_frame_id = 0; + } + + SCLogDebug("transaction_cnt %" PRIu64 ", list_size %" PRIu64, hstate->transaction_cnt, + HTPStateGetTxCnt(hstate)); + + SCLogDebug("HTTP request completed"); + + HTPErrorCheckTxRequestFlags(hstate, tx); + + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + if (htud->tsflags & HTP_FILENAME_SET) { + SCLogDebug("closing file that was being stored"); + (void)HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOSERVER); + htud->tsflags &= ~HTP_FILENAME_SET; + if (abs_right_edge < (uint64_t)UINT32_MAX) { + StreamTcpReassemblySetMinInspectDepth( + hstate->f->protoctx, STREAM_TOSERVER, (uint32_t)abs_right_edge); + } + } + } + + hstate->last_request_data_stamp = abs_right_edge; + /* request done, do raw reassembly now to inspect state and stream + * at the same time. */ + AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOSERVER); + SCReturnInt(HTP_OK); +} + +/** + * \brief callback for response to remove the recent received requests + from the recent_in_tx for the given htp state + * \param connp pointer to the current connection parser which has the htp + * state in it as user data + */ +static int HTPCallbackResponseComplete(htp_tx_t *tx) +{ + SCEnter(); + + HtpState *hstate = htp_connp_get_user_data(tx->connp); + if (hstate == NULL) { + SCReturnInt(HTP_ERROR); + } + + /* we have one whole transaction now */ + hstate->transaction_cnt++; + + const uint64_t abs_right_edge = + hstate->slice->offset + htp_connp_res_data_consumed(hstate->connp); + + if (hstate->response_frame_id > 0) { + Frame *frame = AppLayerFrameGetById(hstate->f, 1, hstate->response_frame_id); + if (frame) { + const uint64_t response_size = abs_right_edge - hstate->last_response_data_stamp; + + SCLogDebug("HTTP response complete: data offset %" PRIu64 ", response_size %" PRIu64, + hstate->last_response_data_stamp, response_size); + SCLogDebug("frame %p/%" PRIi64 " setting len to %" PRIu64, frame, frame->id, + response_size); + frame->len = (int64_t)response_size; + } + hstate->response_frame_id = 0; + } + + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + if (htud->tcflags & HTP_FILENAME_SET) { + SCLogDebug("closing file that was being stored"); + (void)HTPFileClose(hstate, htud, NULL, 0, 0, STREAM_TOCLIENT); + htud->tcflags &= ~HTP_FILENAME_SET; + } + } + + /* response done, do raw reassembly now to inspect state and stream + * at the same time. */ + AppLayerParserTriggerRawStreamReassembly(hstate->f, STREAM_TOCLIENT); + + /* handle HTTP CONNECT */ + if (tx->request_method_number == HTP_M_CONNECT) { + /* any 2XX status response implies that the connection will become + a tunnel immediately after this packet (RFC 7230, 3.3.3). */ + if ((tx->response_status_number >= 200) && (tx->response_status_number < 300) && + (hstate->transaction_cnt == 1)) { + uint16_t dp = 0; + if (tx->request_port_number != -1) { + dp = (uint16_t)tx->request_port_number; + } + // both ALPROTO_HTTP1 and ALPROTO_TLS are normal options + if (!AppLayerRequestProtocolChange(hstate->f, dp, ALPROTO_UNKNOWN)) { + HTPSetEvent( + hstate, htud, STREAM_TOCLIENT, HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE); + } + tx->request_progress = HTP_REQUEST_COMPLETE; + tx->response_progress = HTP_RESPONSE_COMPLETE; + } + } + + hstate->last_response_data_stamp = abs_right_edge; + SCReturnInt(HTP_OK); +} + +static int HTPCallbackRequestLine(htp_tx_t *tx) +{ + HtpTxUserData *tx_ud; + bstr *request_uri_normalized; + HtpState *hstate = htp_connp_get_user_data(tx->connp); + const HTPCfgRec *cfg = hstate->cfg; + + request_uri_normalized = SCHTPGenerateNormalizedUri(tx, tx->parsed_uri, cfg->uri_include_all); + if (request_uri_normalized == NULL) + return HTP_OK; + + tx_ud = htp_tx_get_user_data(tx); + if (unlikely(tx_ud == NULL)) { + bstr_free(request_uri_normalized); + return HTP_OK; + } + if (unlikely(tx_ud->request_uri_normalized != NULL)) + bstr_free(tx_ud->request_uri_normalized); + tx_ud->request_uri_normalized = request_uri_normalized; + + if (tx->flags) { + HTPErrorCheckTxRequestFlags(hstate, tx); + } + return HTP_OK; +} + +static int HTPCallbackDoubleDecodeUriPart(htp_tx_t *tx, bstr *part) +{ + if (part == NULL) + return HTP_OK; + + uint64_t flags = 0; + size_t prevlen = bstr_len(part); + htp_status_t res = htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, part, &flags); + // shorter string means that uri was encoded + if (res == HTP_OK && prevlen > bstr_len(part)) { + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud == NULL) + return HTP_OK; + HtpState *s = htp_connp_get_user_data(tx->connp); + if (s == NULL) + return HTP_OK; + HTPSetEvent(s, htud, STREAM_TOSERVER, HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI); + } + + return HTP_OK; +} + +static int HTPCallbackDoubleDecodeQuery(htp_tx_t *tx) +{ + if (tx->parsed_uri == NULL) + return HTP_OK; + + return HTPCallbackDoubleDecodeUriPart(tx, tx->parsed_uri->query); +} + +static int HTPCallbackDoubleDecodePath(htp_tx_t *tx) +{ + if (tx->parsed_uri == NULL) + return HTP_OK; + + return HTPCallbackDoubleDecodeUriPart(tx, tx->parsed_uri->path); +} + +static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) +{ + void *ptmp; + if (tx_data->len == 0 || tx_data->tx == NULL) + return HTP_OK; + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); + if (tx_ud == NULL) { + return HTP_OK; + } + ptmp = HTPRealloc(tx_ud->request_headers_raw, tx_ud->request_headers_raw_len, + tx_ud->request_headers_raw_len + tx_data->len); + if (ptmp == NULL) { + return HTP_OK; + } + tx_ud->request_headers_raw = ptmp; + + memcpy(tx_ud->request_headers_raw + tx_ud->request_headers_raw_len, tx_data->data, + tx_data->len); + tx_ud->request_headers_raw_len += tx_data->len; + + if (tx_data->tx && tx_data->tx->flags) { + HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); + HTPErrorCheckTxRequestFlags(hstate, tx_data->tx); + } + return HTP_OK; +} + +static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) +{ + void *ptmp; + if (tx_data->len == 0 || tx_data->tx == NULL) + return HTP_OK; + + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); + if (tx_ud == NULL) { + return HTP_OK; + } + ptmp = HTPRealloc(tx_ud->response_headers_raw, tx_ud->response_headers_raw_len, + tx_ud->response_headers_raw_len + tx_data->len); + if (ptmp == NULL) { + return HTP_OK; + } + tx_ud->response_headers_raw = ptmp; + + memcpy(tx_ud->response_headers_raw + tx_ud->response_headers_raw_len, tx_data->data, + tx_data->len); + tx_ud->response_headers_raw_len += tx_data->len; + + return HTP_OK; +} + +/* + * We have a similar set function called HTPConfigSetDefaultsPhase1. + */ +static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) +{ + cfg_prec->uri_include_all = false; + cfg_prec->request.body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT; + cfg_prec->response.body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT; + cfg_prec->request.inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE; + cfg_prec->request.inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; + cfg_prec->response.inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; + cfg_prec->response.inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; + + if (!g_disable_randomness) { + cfg_prec->randomize = HTP_CONFIG_DEFAULT_RANDOMIZE; + } else { + cfg_prec->randomize = 0; + } + cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE; + + htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); + htp_config_register_request_trailer_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); + htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); + htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); + + htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer); + htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer); + + htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData); + htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData); + + htp_config_register_request_start(cfg_prec->cfg, HTPCallbackRequestStart); + htp_config_register_request_complete(cfg_prec->cfg, HTPCallbackRequestComplete); + + htp_config_register_response_start(cfg_prec->cfg, HTPCallbackResponseStart); + htp_config_register_response_complete(cfg_prec->cfg, HTPCallbackResponseComplete); + + htp_config_set_parse_request_cookies(cfg_prec->cfg, 0); + + /* don't convert + to space by default */ + htp_config_set_plusspace_decode(cfg_prec->cfg, HTP_DECODER_URLENCODED, 0); + // enables request decompression + htp_config_set_request_decompression(cfg_prec->cfg, 1); +#ifdef HAVE_HTP_CONFIG_SET_LZMA_LAYERS + // disable by default + htp_config_set_lzma_layers(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_LAYERS); +#endif +#ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT + htp_config_set_lzma_memlimit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT); +#endif +#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT + htp_config_set_compression_bomb_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT); +#endif +#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT + htp_config_set_compression_time_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT); +#endif + /* libhtp <= 0.5.9 doesn't use soft limit, but it's impossible to set + * only the hard limit. So we set both here to the (current) htp defaults. + * The reason we do this is that if the user sets the hard limit in the + * config, we have to set the soft limit as well. If libhtp starts using + * the soft limit in the future, we at least make sure we control what + * it's value is. */ + htp_config_set_field_limits(cfg_prec->cfg, (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT, + (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_HARD); + return; +} + +/* hack: htp random range code expects random values in range of 0-RAND_MAX, + * but we can get both <0 and >RAND_MAX values from RandomGet + */ +static int RandomGetWrap(void) +{ + unsigned long r; + + do { + r = RandomGet(); + } while (r >= ULONG_MAX - (ULONG_MAX % RAND_MAX)); + + return r % RAND_MAX; +} + +/* + * We have this splitup so that in case double decoding has been enabled + * for query and path, they would be called first on the callback queue, + * before the callback set by Phase2() is called. We need this, since + * the callback in Phase2() generates the normalized uri which utilizes + * the query and path. */ +static void HTPConfigSetDefaultsPhase2(const char *name, HTPCfgRec *cfg_prec) +{ + /* randomize inspection size if needed */ + if (cfg_prec->randomize) { + int rdrange = cfg_prec->randomize_range; + + long int r = RandomGetWrap(); + cfg_prec->request.inspect_min_size += (int)(cfg_prec->request.inspect_min_size * + ((double)r / RAND_MAX - 0.5) * rdrange / 100); + + r = RandomGetWrap(); + cfg_prec->request.inspect_window += (int)(cfg_prec->request.inspect_window * + ((double)r / RAND_MAX - 0.5) * rdrange / 100); + SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to" + " %u and 'request-body-inspect-window' set to %u after" + " randomization.", + name, cfg_prec->request.inspect_min_size, cfg_prec->request.inspect_window); + + r = RandomGetWrap(); + cfg_prec->response.inspect_min_size += (int)(cfg_prec->response.inspect_min_size * + ((double)r / RAND_MAX - 0.5) * rdrange / 100); + + r = RandomGetWrap(); + cfg_prec->response.inspect_window += (int)(cfg_prec->response.inspect_window * + ((double)r / RAND_MAX - 0.5) * rdrange / 100); + + SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to" + " %u and 'response-body-inspect-window' set to %u after" + " randomization.", + name, cfg_prec->response.inspect_min_size, cfg_prec->response.inspect_window); + } + + htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine); + return; +} + +static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, SCRadixTree *tree) +{ + if (cfg_prec == NULL || s == NULL || tree == NULL) + return; + + ConfNode *p = NULL; + + /* Default Parameters */ + TAILQ_FOREACH (p, &s->head, next) { + + if (strcasecmp("address", p->name) == 0) { + ConfNode *pval; + /* Addresses */ + TAILQ_FOREACH (pval, &p->head, next) { + SCLogDebug("LIBHTP server %s: %s=%s", s->name, p->name, pval->val); + + /* IPV6 or IPV4? */ + if (strchr(pval->val, ':') != NULL) { + SCLogDebug("LIBHTP adding ipv6 server %s at %s: %p", s->name, pval->val, + cfg_prec->cfg); + if (!SCRadixAddKeyIPV6String(pval->val, tree, cfg_prec)) { + SCLogWarning("LIBHTP failed to " + "add ipv6 server %s, ignoring", + pval->val); + } + } else { + SCLogDebug("LIBHTP adding ipv4 server %s at %s: %p", s->name, pval->val, + cfg_prec->cfg); + if (!SCRadixAddKeyIPV4String(pval->val, tree, cfg_prec)) { + SCLogWarning("LIBHTP failed " + "to add ipv4 server %s, ignoring", + pval->val); + } + } /* else - if (strchr(pval->val, ':') != NULL) */ + } /* TAILQ_FOREACH(pval, &p->head, next) */ + + } else if (strcasecmp("personality", p->name) == 0) { + /* Personalities */ + int personality = HTPLookupPersonality(p->val); + SCLogDebug("LIBHTP default: %s = %s", p->name, p->val); + SCLogDebug("LIBHTP default: %s = %s", p->name, p->val); + + if (personality >= 0) { + SCLogDebug("LIBHTP default: %s=%s (%d)", p->name, p->val, personality); + if (htp_config_set_server_personality(cfg_prec->cfg, personality) == HTP_ERROR) { + SCLogWarning("LIBHTP Failed adding " + "personality \"%s\", ignoring", + p->val); + } else { + SCLogDebug("LIBHTP personality set to %s", + HTPLookupPersonalityString(personality)); + } + + /* The IDS personality by default converts the path (and due to + * our query string callback also the query string) to lowercase. + * Signatures do not expect this, so override it. */ + htp_config_set_convert_lowercase(cfg_prec->cfg, HTP_DECODER_URL_PATH, 0); + } else { + SCLogWarning("LIBHTP Unknown personality " + "\"%s\", ignoring", + p->val); + continue; + } + + } else if (strcasecmp("request-body-limit", p->name) == 0 || + strcasecmp("request_body_limit", p->name) == 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) { + SCLogError("Error parsing request-body-limit " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + + } else if (strcasecmp("response-body-limit", p->name) == 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) { + SCLogError("Error parsing response-body-limit " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + + } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) { + SCLogError("Error parsing request-body-minimal-inspect-size " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + + } else if (strcasecmp("request-body-inspect-window", p->name) == 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) { + SCLogError("Error parsing request-body-inspect-window " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + + } else if (strcasecmp("double-decode-query", p->name) == 0) { + if (ConfValIsTrue(p->val)) { + htp_config_register_request_line(cfg_prec->cfg, HTPCallbackDoubleDecodeQuery); + } + + } else if (strcasecmp("double-decode-path", p->name) == 0) { + if (ConfValIsTrue(p->val)) { + htp_config_register_request_line(cfg_prec->cfg, HTPCallbackDoubleDecodePath); + } + + } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) { + SCLogError("Error parsing response-body-minimal-inspect-size " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + + } else if (strcasecmp("response-body-inspect-window", p->name) == 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) { + SCLogError("Error parsing response-body-inspect-window " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + + } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) { + uint32_t value = 2; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError("Error parsing response-body-inspect-window " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + htp_config_set_response_decompression_layer_limit(cfg_prec->cfg, value); +#else + SCLogWarning("can't set response-body-decompress-layer-limit " + "to %u, libhtp version too old", + value); +#endif + } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) { + htp_config_set_backslash_convert_slashes( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("path-bestfit-replacement-char", p->name) == 0) { + if (strlen(p->val) == 1) { + htp_config_set_bestfit_replacement_byte( + cfg_prec->cfg, HTP_DECODER_URL_PATH, p->val[0]); + } else { + SCLogError("Invalid entry " + "for libhtp param path-bestfit-replacement-char"); + } + } else if (strcasecmp("path-convert-lowercase", p->name) == 0) { + htp_config_set_convert_lowercase( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("path-nul-encoded-terminates", p->name) == 0) { + htp_config_set_nul_encoded_terminates( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("path-nul-raw-terminates", p->name) == 0) { + htp_config_set_nul_raw_terminates( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("path-separators-compress", p->name) == 0) { + htp_config_set_path_separators_compress( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("path-separators-decode", p->name) == 0) { + htp_config_set_path_separators_decode( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("path-u-encoding-decode", p->name) == 0) { + htp_config_set_u_encoding_decode( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("path-url-encoding-invalid-handling", p->name) == 0) { + enum htp_url_encoding_handling_t handling; + if (strcasecmp(p->val, "preserve_percent") == 0) { + handling = HTP_URL_DECODE_PRESERVE_PERCENT; + } else if (strcasecmp(p->val, "remove_percent") == 0) { + handling = HTP_URL_DECODE_REMOVE_PERCENT; + } else if (strcasecmp(p->val, "decode_invalid") == 0) { + handling = HTP_URL_DECODE_PROCESS_INVALID; + } else { + SCLogError("Invalid entry " + "for libhtp param path-url-encoding-invalid-handling"); + return; + } + htp_config_set_url_encoding_invalid_handling( + cfg_prec->cfg, HTP_DECODER_URL_PATH, handling); + } else if (strcasecmp("path-utf8-convert-bestfit", p->name) == 0) { + htp_config_set_utf8_convert_bestfit( + cfg_prec->cfg, HTP_DECODER_URL_PATH, ConfValIsTrue(p->val)); + } else if (strcasecmp("uri-include-all", p->name) == 0) { + cfg_prec->uri_include_all = (1 == ConfValIsTrue(p->val)); + SCLogDebug("uri-include-all %s", cfg_prec->uri_include_all ? "enabled" : "disabled"); + } else if (strcasecmp("query-plusspace-decode", p->name) == 0) { + htp_config_set_plusspace_decode( + cfg_prec->cfg, HTP_DECODER_URLENCODED, ConfValIsTrue(p->val)); + } else if (strcasecmp("meta-field-limit", p->name) == 0) { + uint32_t limit = 0; + if (ParseSizeStringU32(p->val, &limit) < 0) { + SCLogError("Error meta-field-limit " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + if (limit == 0) { + FatalError("Error meta-field-limit " + "from conf file cannot be 0. Killing engine"); + } + /* set default soft-limit with our new hard limit */ + htp_config_set_field_limits( + cfg_prec->cfg, (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT, (size_t)limit); +#ifdef HAVE_HTP_CONFIG_SET_LZMA_MEMLIMIT + } else if (strcasecmp("lzma-memlimit", p->name) == 0) { + uint32_t limit = 0; + if (ParseSizeStringU32(p->val, &limit) < 0) { + FatalError("failed to parse 'lzma-memlimit' " + "from conf file - %s.", + p->val); + } + if (limit == 0) { + FatalError("'lzma-memlimit' " + "from conf file cannot be 0."); + } + /* set default soft-limit with our new hard limit */ + SCLogConfig("Setting HTTP LZMA memory limit to %" PRIu32 " bytes", limit); + htp_config_set_lzma_memlimit(cfg_prec->cfg, (size_t)limit); +#endif +#ifdef HAVE_HTP_CONFIG_SET_LZMA_LAYERS + } else if (strcasecmp("lzma-enabled", p->name) == 0) { + if (ConfValIsTrue(p->val)) { + htp_config_set_lzma_layers(cfg_prec->cfg, 1); + } else if (!ConfValIsFalse(p->val)) { + int8_t limit; + if (StringParseInt8(&limit, 10, 0, (const char *)p->val) < 0) { + FatalError("failed to parse 'lzma-enabled' " + "from conf file - %s.", + p->val); + } + SCLogConfig("Setting HTTP LZMA decompression layers to %" PRIu32 "", (int)limit); + htp_config_set_lzma_layers(cfg_prec->cfg, limit); + } +#endif +#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT + } else if (strcasecmp("compression-bomb-limit", p->name) == 0) { + uint32_t limit = 0; + if (ParseSizeStringU32(p->val, &limit) < 0) { + FatalError("failed to parse 'compression-bomb-limit' " + "from conf file - %s.", + p->val); + } + if (limit == 0) { + FatalError("'compression-bomb-limit' " + "from conf file cannot be 0."); + } + /* set default soft-limit with our new hard limit */ + SCLogConfig("Setting HTTP compression bomb limit to %" PRIu32 " bytes", limit); + htp_config_set_compression_bomb_limit(cfg_prec->cfg, (size_t)limit); +#endif +#ifdef HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT + } else if (strcasecmp("decompression-time-limit", p->name) == 0) { + uint32_t limit = 0; + // between 1 usec and 1 second + if (StringParseU32RangeCheck(&limit, 10, 0, p->val, 1, 1000000) < 0) { + FatalError("failed to parse 'decompression-time-limit' " + "from conf file - %s.", + p->val); + } + SCLogConfig("Setting HTTP decompression time limit to %" PRIu32 " usec", limit); + htp_config_set_compression_time_limit(cfg_prec->cfg, (size_t)limit); +#endif + } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) { + if (!g_disable_randomness) { + cfg_prec->randomize = ConfValIsTrue(p->val); + } + } else if (strcasecmp("randomize-inspection-range", p->name) == 0) { + uint32_t range; + if (StringParseU32RangeCheck(&range, 10, 0, (const char *)p->val, 0, 100) < 0) { + SCLogError("Invalid value for randomize" + "-inspection-range setting from conf file - \"%s\"." + " It should be a valid integer less than or equal to 100." + " Killing engine", + p->val); + exit(EXIT_FAILURE); + } + cfg_prec->randomize_range = range; + } else if (strcasecmp("http-body-inline", p->name) == 0) { + if (ConfValIsTrue(p->val)) { + cfg_prec->http_body_inline = 1; + } else if (ConfValIsFalse(p->val)) { + cfg_prec->http_body_inline = 0; + } else { + if (strcmp("auto", p->val) != 0) { + WarnInvalidConfEntry("http_body_inline", "%s", "auto"); + } + if (EngineModeIsIPS()) { + cfg_prec->http_body_inline = 1; + } else { + cfg_prec->http_body_inline = 0; + } + } + } else if (strcasecmp("swf-decompression", p->name) == 0) { + ConfNode *pval; + + TAILQ_FOREACH (pval, &p->head, next) { + if (strcasecmp("enabled", pval->name) == 0) { + if (ConfValIsTrue(pval->val)) { + cfg_prec->swf_decompression_enabled = 1; + SCLogWarning("Flash decompression is deprecated and will be removed in " + "Suricata 8; see ticket #6179"); + } else if (ConfValIsFalse(pval->val)) { + cfg_prec->swf_decompression_enabled = 0; + } else { + WarnInvalidConfEntry("swf-decompression.enabled", "%s", "no"); + } + } else if (strcasecmp("type", pval->name) == 0) { + if (strcasecmp("no", pval->val) == 0) { + cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_NONE; + } else if (strcasecmp("deflate", pval->val) == 0) { + cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_ZLIB; + } else if (strcasecmp("lzma", pval->val) == 0) { + cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_LZMA; + } else if (strcasecmp("both", pval->val) == 0) { + cfg_prec->swf_compression_type = HTTP_SWF_COMPRESSION_BOTH; + } else { + SCLogError("Invalid entry for " + "swf-decompression.type: %s - " + "Killing engine", + pval->val); + exit(EXIT_FAILURE); + } + } else if (strcasecmp("compress-depth", pval->name) == 0) { + if (ParseSizeStringU32(pval->val, &cfg_prec->swf_compress_depth) < 0) { + SCLogError("Error parsing swf-decompression.compression-depth " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + } else if (strcasecmp("decompress-depth", pval->name) == 0) { + if (ParseSizeStringU32(pval->val, &cfg_prec->swf_decompress_depth) < 0) { + SCLogError("Error parsing swf-decompression.decompression-depth " + "from conf file - %s. Killing engine", + p->val); + exit(EXIT_FAILURE); + } + } else { + SCLogWarning("Ignoring unknown param %s", pval->name); + } + } + } else { + SCLogWarning("LIBHTP Ignoring unknown " + "default config: %s", + p->name); + } + } /* TAILQ_FOREACH(p, &default_config->head, next) */ + + return; +} + +void HTPConfigure(void) +{ + SCEnter(); + + cfglist.next = NULL; + + htp_sbcfg.Calloc = HTPCalloc; + htp_sbcfg.Realloc = HTPRealloc; + htp_sbcfg.Free = HTPFree; + + cfgtree = SCRadixCreateRadixTree(NULL, NULL); + if (NULL == cfgtree) + exit(EXIT_FAILURE); + + /* Default Config */ + cfglist.cfg = htp_config_create(); + if (NULL == cfglist.cfg) { + FatalError("Failed to create HTP default config"); + } + SCLogDebug("LIBHTP default config: %p", cfglist.cfg); + HTPConfigSetDefaultsPhase1(&cfglist); + if (ConfGetNode("app-layer.protocols.http.libhtp") == NULL) { + HTPConfigParseParameters(&cfglist, ConfGetNode("libhtp.default-config"), cfgtree); + } else { + HTPConfigParseParameters( + &cfglist, ConfGetNode("app-layer.protocols.http.libhtp.default-config"), cfgtree); + } + HTPConfigSetDefaultsPhase2("default", &cfglist); + + HTPParseMemcap(); + + /* Read server config and create a parser for each IP in radix tree */ + ConfNode *server_config = ConfGetNode("app-layer.protocols.http.libhtp.server-config"); + if (server_config == NULL) { + server_config = ConfGetNode("libhtp.server-config"); + if (server_config == NULL) { + SCLogDebug("LIBHTP Configuring %p", server_config); + SCReturn; + } + } + SCLogDebug("LIBHTP Configuring %p", server_config); + + ConfNode *si; + /* Server Nodes */ + TAILQ_FOREACH (si, &server_config->head, next) { + /* Need the named node, not the index */ + ConfNode *s = TAILQ_FIRST(&si->head); + if (NULL == s) { + SCLogDebug("LIBHTP s NULL"); + continue; + } + + SCLogDebug("LIBHTP server %s", s->name); + + HTPCfgRec *nextrec = cfglist.next; + HTPCfgRec *htprec = SCCalloc(1, sizeof(HTPCfgRec)); + if (NULL == htprec) + exit(EXIT_FAILURE); + + cfglist.next = htprec; + + cfglist.next->next = nextrec; + cfglist.next->cfg = htp_config_create(); + if (NULL == cfglist.next->cfg) { + FatalError("Failed to create HTP server config"); + } + + HTPConfigSetDefaultsPhase1(htprec); + HTPConfigParseParameters(htprec, s, cfgtree); + HTPConfigSetDefaultsPhase2(s->name, htprec); + } + + SCReturn; +} + +void AppLayerHtpPrintStats(void) +{ +#ifdef DEBUG + SCMutexLock(&htp_state_mem_lock); + SCLogPerf("htp memory %" PRIu64 " (%" PRIu64 ")", htp_state_memuse, htp_state_memcnt); + SCMutexUnlock(&htp_state_mem_lock); +#endif +} + +/** \internal + * \brief get files callback + * \param state state ptr + * \param direction flow direction + * \retval files files ptr + */ +static AppLayerGetFileState HTPGetTxFiles(void *state, void *txv, uint8_t direction) +{ + AppLayerGetFileState files = { .fc = NULL, .cfg = &htp_sbcfg }; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + if (tx_ud) { + if (direction & STREAM_TOCLIENT) { + files.fc = &tx_ud->files_tc; + } else { + files.fc = &tx_ud->files_ts; + } + } + return files; +} + +static int HTPStateGetAlstateProgress(void *tx, uint8_t direction) +{ + if (direction & STREAM_TOSERVER) + return ((htp_tx_t *)tx)->request_progress; + else + return ((htp_tx_t *)tx)->response_progress; +} + +static uint64_t HTPStateGetTxCnt(void *alstate) +{ + HtpState *http_state = (HtpState *)alstate; + + if (http_state != NULL && http_state->conn != NULL) { + const int64_t size = (int64_t)htp_list_size(http_state->conn->transactions); + if (size < 0) + return 0ULL; + SCLogDebug("size %" PRIu64, size); + return (uint64_t)size; + } else { + return 0ULL; + } +} + +static void *HTPStateGetTx(void *alstate, uint64_t tx_id) +{ + HtpState *http_state = (HtpState *)alstate; + + if (http_state != NULL && http_state->conn != NULL) + return htp_list_get(http_state->conn->transactions, tx_id); + else + return NULL; +} + +void *HtpGetTxForH2(void *alstate) +{ + // gets last transaction + HtpState *http_state = (HtpState *)alstate; + if (http_state != NULL && http_state->conn != NULL) { + size_t txid = htp_list_array_size(http_state->conn->transactions); + if (txid > 0) { + return htp_list_get(http_state->conn->transactions, txid - 1); + } + } + return NULL; +} + +static int HTPStateGetEventInfo( + const char *event_name, int *event_id, AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, http_decoder_event_table); + if (*event_id == -1) { + SCLogError("event \"%s\" not present in " + "http's enum map table.", + event_name); + /* this should be treated as fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static int HTPStateGetEventInfoById( + int event_id, const char **event_name, AppLayerEventType *event_type) +{ + *event_name = SCMapEnumValueToName(event_id, http_decoder_event_table); + if (*event_name == NULL) { + SCLogError("event \"%d\" not present in " + "http's enum map table.", + event_id); + /* this should be treated as fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static AppLayerTxData *HTPGetTxData(void *vtx) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + if (tx_ud) { + return &tx_ud->tx_data; + } + return NULL; +} + +static AppLayerStateData *HTPGetStateData(void *vstate) +{ + HtpState *s = vstate; + return &s->state_data; +} + +static int HTPRegisterPatternsForProtocolDetection(void) +{ + const char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS", "CONNECT", "DELETE", + "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", + "UNCHECKOUT", "CHECKIN", "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE", + "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL }; + const char *spacings[] = { "|20|", "|09|", NULL }; + const char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL }; + + int methods_pos; + int spacings_pos; + int versions_pos; + int register_result; + char method_buffer[32] = ""; + + /* Loop through all the methods ands spacings and register the patterns */ + for (methods_pos = 0; methods[methods_pos]; methods_pos++) { + for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) { + + /* Combine the method name and the spacing */ + snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], + spacings[spacings_pos]); + + /* Register the new method+spacing pattern + * 3 is subtracted from the length since the spacing is hex typed as |xx| + * but the pattern matching should only be one char + */ + register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1, + method_buffer, (uint16_t)strlen(method_buffer) - 3, 0, STREAM_TOSERVER); + if (register_result < 0) { + return -1; + } + } + } + + /* Loop through all the http version patterns that are TO_CLIENT */ + for (versions_pos = 0; versions[versions_pos]; versions_pos++) { + register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1, + versions[versions_pos], (uint16_t)strlen(versions[versions_pos]), 0, + STREAM_TOCLIENT); + if (register_result < 0) { + return -1; + } + } + + return 0; +} + +/** + * \brief Register the HTTP protocol and state handling functions to APP layer + * of the engine. + */ +void RegisterHTPParsers(void) +{ + SCEnter(); + + const char *proto_name = "http"; + + /** HTTP */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP1, proto_name); + if (HTPRegisterPatternsForProtocolDetection() < 0) + return; + } else { + SCLogInfo("Protocol detection and parser disabled for %s protocol", proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateAlloc, HTPStateFree); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateTransactionFree); + AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxFiles); + AppLayerParserRegisterGetStateProgressFunc( + IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetAlstateProgress); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTxCnt); + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetTx); + + AppLayerParserRegisterStateProgressCompletionStatus( + ALPROTO_HTTP1, HTP_REQUEST_COMPLETE, HTP_RESPONSE_COMPLETE); + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfo); + AppLayerParserRegisterGetEventInfoById( + IPPROTO_TCP, ALPROTO_HTTP1, HTPStateGetEventInfoById); + + AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetTxData); + AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_HTTP1, HTPGetStateData); + + AppLayerParserRegisterSetStreamDepthFlag( + IPPROTO_TCP, ALPROTO_HTTP1, AppLayerHtpSetStreamDepthFlag); + + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER, HTPHandleRequestData); + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOCLIENT, HTPHandleResponseData); + SC_ATOMIC_INIT(htp_config_flags); + /* This parser accepts gaps. */ + AppLayerParserRegisterOptionFlags( + IPPROTO_TCP, ALPROTO_HTTP1, APP_LAYER_PARSER_OPT_ACCEPT_GAPS); + AppLayerParserRegisterParserAcceptableDataDirection( + IPPROTO_TCP, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_TOCLIENT); + /* app-layer-frame-documentation tag start: registering relevant callbacks */ + AppLayerParserRegisterGetFrameFuncs( + IPPROTO_TCP, ALPROTO_HTTP1, HTTPGetFrameIdByName, HTTPGetFrameNameById); + /* app-layer-frame-documentation tag end: registering relevant callbacks */ + HTPConfigure(); + } else { + SCLogInfo("Parsed disabled for %s protocol. Protocol detection" + "still on.", + proto_name); + } +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_HTTP1, HTPParserRegisterTests); +#endif + + SCReturn; +} + +#ifdef UNITTESTS +#include "detect-engine-alert.h" + +static HTPCfgRec cfglist_backup; + +void HtpConfigCreateBackup(void) +{ + cfglist_backup = cfglist; + + return; +} + +void HtpConfigRestoreBackup(void) +{ + cfglist = cfglist_backup; + + return; +} + +/** \test Test case where chunks are sent in smaller chunks and check the + * response of the parser from HTP library. */ +static int HTPParserTest01(void) +{ + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" + " Data is c0oL!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + TcpSession ssn; + memset(&ssn, 0, sizeof(ssn)); + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + FAIL_IF(r != 0); + } + + HtpState *htp_state = f->alstate; + FAIL_IF_NULL(htp_state); + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + FAIL_IF_NULL(tx); + + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")); + FAIL_IF(tx->request_method_number != HTP_M_POST); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test folding in 1 read case */ +static int HTPParserTest01b(void) +{ + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost" + " Data is c0oL!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + TcpSession ssn; + memset(&ssn, 0, sizeof(ssn)); + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF; + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1); + FAIL_IF(r != 0); + + HtpState *htp_state = f->alstate; + FAIL_IF_NULL(htp_state); + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + FAIL_IF_NULL(tx); + + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")); + FAIL_IF(tx->request_method_number != HTP_M_POST); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test folding in 1byte per read case */ +static int HTPParserTest01c(void) +{ + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent:\r\n Victor/1.0\r\n\r\nPost" + " Data is c0oL!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + + TcpSession ssn; + memset(&ssn, 0, sizeof(ssn)); + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + FAIL_IF(r != 0); + } + + HtpState *htp_state = f->alstate; + FAIL_IF_NULL(htp_state); + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + FAIL_IF_NULL(tx); + + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0")); + FAIL_IF(tx->request_method_number != HTP_M_POST); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test case where chunks are sent in smaller chunks and check the + * response of the parser from HTP library. */ +static int HTPParserTest01a(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" + " Data is c0oL!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0") || + tx->request_method_number != HTP_M_POST || + tx->request_protocol_number != HTP_PROTOCOL_1_0) { + printf("expected header value: Victor/1.0 and got %s: and expected" + " method: POST and got %s, expected protocol number HTTP/1.0" + " and got: %s \n", + bstr_util_strdup_to_c(h->value), bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test See how it deals with an incomplete request. */ +static int HTPParserTest02(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "POST"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NOT_NULL(h); + + FAIL_IF_NULL(tx->request_method); + char *method = bstr_util_strdup_to_c(tx->request_method); + FAIL_IF_NULL(method); + + FAIL_IF(strcmp(method, "POST") != 0); + SCFree(method); + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test case where method is invalid and data is sent in smaller chunks + * and check the response of the parser from HTP library. */ +static int HTPParserTest03(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_UNKNOWN || h != NULL || + tx->request_protocol_number != HTP_PROTOCOL_1_0) { + printf("expected method M_UNKNOWN and got %s: , expected protocol " + "HTTP/1.0 and got %s \n", + bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test case where invalid data is sent and check the response of the + * parser from HTP library. */ +static int HTPParserTest04(void) +{ + int result = 0; + Flow *f = NULL; + HtpState *htp_state = NULL; + uint8_t httpbuf1[] = "World!\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1); + if (r != 0) { + goto end; + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_UNKNOWN || h != NULL || + tx->request_protocol_number != HTP_PROTOCOL_0_9) { + printf("expected method M_UNKNOWN and got %s: , expected protocol " + "NULL and got %s \n", + bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test both sides of a http stream mixed up to see if the HTP parser + * properly parsed them and also keeps them separated. */ +static int HTPParserTest05(void) +{ + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\nContent-Length: 17\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "Post D"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint8_t httpbuf3[] = "ata is c0oL!"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + + uint8_t httpbuf4[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + uint8_t httpbuf5[] = "post R"; + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + uint8_t httpbuf6[] = "esults are tha bomb!"; + uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */ + + TcpSession ssn; + memset(&ssn, 0, sizeof(ssn)); + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4); + FAIL_IF(r != 0); + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf5, httplen5); + FAIL_IF(r != 0); + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6); + FAIL_IF(r != 0); + + HtpState *http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NOT(tx->request_method_number == HTP_M_POST); + FAIL_IF_NOT(tx->request_protocol_number == HTP_PROTOCOL_1_0); + + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF_NOT(tx->response_status_number == 200); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test proper chunked encoded response body + */ +static int HTPParserTest06(void) +{ + uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" + "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " + "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nDate: Sat, 03 Oct 2009 10:16:02 " + "GMT\r\n" + "Server: Apache/1.3.37 (Unix) mod_ssl/2.8.28 " + "OpenSSL/0.9.7a PHP/4.4.7 mod_perl/1.29 " + "FrontPage/5.0.2.2510\r\n" + "X-Powered-By: PHP/4.4.7\r\nTransfer-Encoding: " + "chunked\r\n" + "Content-Type: text/html\r\n\r\n" + "580\r\n" + "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu" + "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN" + "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N" + "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk" + "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l" + "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN" + "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt" + "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz" + "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw" + "aG9uZTM9DQpsb2dpbjM9DQpwYXNzd29yZDM9DQpwaG9uZTQ9DQps" + "b2dpbjQ9DQpwYXNzd29yZDQ9DQpwaG9uZTU9DQpsb2dpbjU9DQpw" + "YXNzd29yZDU9DQpwaG9uZTY9DQpsb2dpbjY9DQpwYXNzd29yZDY9" + "DQpjYWxsX3RpbWUxPQ0KY2FsbF90aW1lMj0NCmRheV9saW1pdD0N" + "Cm1vbnRoX2xpbWl0PQ0KW2dyb3VwM10NCnBob25lMT0NCmxvZ2lu" + "MT0NCnBhc3N3b3JkMT0NCnBob25lMj0NCmxvZ2luMj0NCnBhc3N3" + "b3JkMj0NCnBob25lMz0NCmxvZ2luMz0NCnBhc3N3b3JkMz0NCnBo" + "b25lND0NCmxvZ2luND0NCnBhc3N3b3JkND0NCnBob25lNT0NCmxv" + "Z2luNT0NCnBhc3N3b3JkNT0NCnBob25lNj0NCmxvZ2luNj0NCnBh" + "c3N3b3JkNj0NCmNhbGxfdGltZTE9DQpjYWxsX3RpbWUyPQ0KZGF5" + "X2xpbWl0PQ0KbW9udGhfbGltaXQ9DQpbZ3JvdXA0XQ0KcGhvbmUx" + "PQ0KbG9naW4xPQ0KcGFzc3dvcmQxPQ0KcGhvbmUyPQ0KbG9naW4y" + "PQ0KcGFzc3dvcmQyPQ0KcGhvbmUzPQ0KbG9naW4zPQ0KcGFzc3dv" + "cmQzPQ0KcGhvbmU0PQ0KbG9naW40PQ0KcGFzc3dvcmQ0PQ0KcGhv" + "bmU1PQ0KbG9naW41PQ0KcGFzc3dvcmQ1PQ0KcGhvbmU2PQ0KbG9n" + "aW42PQ0KcGFzc3dvcmQ2PQ0KY2FsbF90aW1lMT0NCmNhbGxfdGlt" + "ZTI9DQpkYXlfbGltaXQ9DQptb250aF9saW1pdD0NCltmaWxlc10N" + "Cmxpbms9aHR0cDovLzIwOS4yMDUuMTk2LjE2L2xkL2dldGJvdC5w" + "aHA=\r\n0\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + TcpSession ssn; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF(r != 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); + FAIL_IF(r != 0); + + HtpState *http_state = f->alstate; + FAIL_IF_NULL(http_state); + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + + FAIL_IF(tx->request_method_number != HTP_M_GET); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + FAIL_IF(tx->response_status_number != 200); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test + */ +static int HTPParserTest07(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /awstats.pl?/migratemigrate%20=%20| HTTP/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref[] = "/awstats.pl?/migratemigrate = |"; + size_t reflen = sizeof(ref) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref, reflen); + printf("\": "); + goto end; + } + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +#include "conf-yaml-loader.h" + +/** \test Abort + */ +static int HTPParserTest08(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + HtpState *htp_state = NULL; + int r = 0; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint8_t flags = 0; + flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk returned %" PRId32 ", expected" + " 0: ", + r); + result = 0; + goto end; + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + // printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized)); + PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + UTHFreeFlow(f); + return result; +} + +/** \test Abort + */ +static int HTPParserTest09(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET /secondhouse/image/js/\%ce\%de\%ce\%fd_RentCity.js?v=2011.05.02 HTTP/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: Apache_2_2\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + HtpState *htp_state = NULL; + int r = 0; + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint8_t flags = 0; + flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk returned %" PRId32 ", expected" + " 0: ", + r); + goto end; + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + // printf("uri %s\n", bstr_util_strdup_to_c(tx->request_uri_normalized)); + PrintRawDataFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + UTHFreeFlow(f); + return result; +} + +/** \test Host:www.google.com <- missing space between name:value (rfc violation) + */ +static int HTPParserTest10(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (h == NULL) { + goto end; + } + + char *name = bstr_util_strdup_to_c(h->name); + if (name == NULL) { + goto end; + } + + if (strcmp(name, "Host") != 0) { + printf("header name not \"Host\", instead \"%s\": ", name); + free(name); + goto end; + } + free(name); + + char *value = bstr_util_strdup_to_c(h->value); + if (value == NULL) { + goto end; + } + + if (strcmp(value, "www.google.com") != 0) { + printf("header value not \"www.google.com\", instead \"%s\": ", value); + free(value); + goto end; + } + free(value); + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test double encoding in path + */ +static int HTPParserTest11(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /%2500 HTTP/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx != NULL && tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (4 != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be 2, is %" PRIuMAX, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' || + bstr_ptr(tx_ud->request_uri_normalized)[1] != '%' || + bstr_ptr(tx_ud->request_uri_normalized)[2] != '0' || + bstr_ptr(tx_ud->request_uri_normalized)[3] != '0') { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\": "); + goto end; + } + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test double encoding in query + */ +static int HTPParserTest12(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /?a=%2500 HTTP/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (7 != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be 5, is %" PRIuMAX, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (bstr_ptr(tx_ud->request_uri_normalized)[0] != '/' || + bstr_ptr(tx_ud->request_uri_normalized)[1] != '?' || + bstr_ptr(tx_ud->request_uri_normalized)[2] != 'a' || + bstr_ptr(tx_ud->request_uri_normalized)[3] != '=' || + bstr_ptr(tx_ud->request_uri_normalized)[4] != '%' || + bstr_ptr(tx_ud->request_uri_normalized)[5] != '0' || + bstr_ptr(tx_ud->request_uri_normalized)[6] != '0') { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\": "); + goto end; + } + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Host:www.google.com0dName: Value0d0a <- missing space between name:value (rfc violation) + */ +static int HTPParserTest13(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nHost:www.google.com\rName: Value\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (h == NULL) { + goto end; + } + + char *name = bstr_util_strdup_to_c(h->name); + if (name == NULL) { + goto end; + } + + if (strcmp(name, "Host") != 0) { + printf("header name not \"Host\", instead \"%s\": ", name); + free(name); + goto end; + } + free(name); + + char *value = bstr_util_strdup_to_c(h->value); + if (value == NULL) { + goto end; + } + + if (strcmp(value, "www.google.com\rName: Value") != 0) { + printf("header value not \"www.google.com\", instead \""); + PrintRawUriFp(stdout, (uint8_t *)value, strlen(value)); + printf("\": "); + free(value); + goto end; + } + free(value); + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test basic config */ +static int HTPParserConfigTest01(void) +{ + int ret = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ +\n\ + server-config:\n\ +\n\ + - apache-tomcat:\n\ + address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ + personality: Tomcat_6_0\n\ +\n\ + - iis7:\n\ + address: \n\ + - 192.168.0.0/24\n\ + - 192.168.10.0/24\n\ + personality: IIS_7_0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + + ConfYamlLoadString(input, strlen(input)); + + ConfNode *outputs; + outputs = ConfGetNode("libhtp.default-config.personality"); + if (outputs == NULL) { + goto end; + } + + outputs = ConfGetNode("libhtp.server-config"); + if (outputs == NULL) { + goto end; + } + + ConfNode *node = TAILQ_FIRST(&outputs->head); + if (node == NULL) { + goto end; + } + if (strcmp(node->name, "0") != 0) { + goto end; + } + node = TAILQ_FIRST(&node->head); + if (node == NULL) { + goto end; + } + if (strcmp(node->name, "apache-tomcat") != 0) { + goto end; + } + + int i = 0; + ConfNode *n; + + ConfNode *node2 = ConfNodeLookupChild(node, "personality"); + if (node2 == NULL) { + goto end; + } + if (strcmp(node2->val, "Tomcat_6_0") != 0) { + goto end; + } + + node = ConfNodeLookupChild(node, "address"); + if (node == NULL) { + goto end; + } + TAILQ_FOREACH (n, &node->head, next) { + if (n == NULL) { + goto end; + } + + switch (i) { + case 0: + if (strcmp(n->name, "0") != 0) { + goto end; + } + if (strcmp(n->val, "192.168.1.0/24") != 0) { + goto end; + } + break; + case 1: + if (strcmp(n->name, "1") != 0) { + goto end; + } + if (strcmp(n->val, "127.0.0.0/8") != 0) { + goto end; + } + break; + case 2: + if (strcmp(n->name, "2") != 0) { + goto end; + } + if (strcmp(n->val, "::1") != 0) { + goto end; + } + break; + default: + goto end; + } + i++; + } + + outputs = ConfGetNode("libhtp.server-config"); + if (outputs == NULL) { + goto end; + } + + node = TAILQ_FIRST(&outputs->head); + node = TAILQ_NEXT(node, next); + if (node == NULL) { + goto end; + } + if (strcmp(node->name, "1") != 0) { + goto end; + } + node = TAILQ_FIRST(&node->head); + if (node == NULL) { + goto end; + } + if (strcmp(node->name, "iis7") != 0) { + goto end; + } + + node2 = ConfNodeLookupChild(node, "personality"); + if (node2 == NULL) { + goto end; + } + if (strcmp(node2->val, "IIS_7_0") != 0) { + goto end; + } + + node = ConfNodeLookupChild(node, "address"); + if (node == NULL) { + goto end; + } + + i = 0; + TAILQ_FOREACH (n, &node->head, next) { + if (n == NULL) { + goto end; + } + + switch (i) { + case 0: + if (strcmp(n->name, "0") != 0) { + goto end; + } + if (strcmp(n->val, "192.168.0.0/24") != 0) { + goto end; + } + break; + case 1: + if (strcmp(n->name, "1") != 0) { + goto end; + } + if (strcmp(n->val, "192.168.10.0/24") != 0) { + goto end; + } + break; + default: + goto end; + } + i++; + } + + ret = 1; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + return ret; +} + +/** \test Test config builds radix correctly */ +static int HTPParserConfigTest02(void) +{ + int ret = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ +\n\ + server-config:\n\ +\n\ + - apache-tomcat:\n\ + address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ + personality: Tomcat_6_0\n\ +\n\ + - iis7:\n\ + address: \n\ + - 192.168.0.0/24\n\ + - 192.168.10.0/24\n\ + personality: IIS_7_0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + + HTPConfigure(); + + if (cfglist.cfg == NULL) { + printf("No default config created.\n"); + goto end; + } + + if (cfgtree == NULL) { + printf("No config tree created.\n"); + goto end; + } + + htp_cfg_t *htp = cfglist.cfg; + uint8_t buf[128]; + const char *addr; + void *user_data = NULL; + + addr = "192.168.10.42"; + if (inet_pton(AF_INET, addr, buf) == 1) { + (void)SCRadixFindKeyIPV4BestMatch(buf, cfgtree, &user_data); + if (user_data != NULL) { + HTPCfgRec *htp_cfg_rec = user_data; + htp = htp_cfg_rec->cfg; + SCLogDebug("LIBHTP using config: %p", htp); + } + if (htp == NULL) { + printf("Could not get config for: %s\n", addr); + goto end; + } + } else { + printf("Failed to parse address: %s\n", addr); + goto end; + } + + user_data = NULL; + addr = "::1"; + if (inet_pton(AF_INET6, addr, buf) == 1) { + (void)SCRadixFindKeyIPV6BestMatch(buf, cfgtree, &user_data); + if (user_data != NULL) { + HTPCfgRec *htp_cfg_rec = user_data; + htp = htp_cfg_rec->cfg; + SCLogDebug("LIBHTP using config: %p", htp); + } + if (htp == NULL) { + printf("Could not get config for: %s\n", addr); + goto end; + } + } else { + printf("Failed to parse address: %s\n", addr); + goto end; + } + + ret = 1; + +end: + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + return ret; +} + +/** \test Test traffic is handled by the correct htp config */ +static int HTPParserConfigTest03(void) +{ + int result = 1; + Flow *f = NULL; + uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" + " Data is c0oL!"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ +\n\ + server-config:\n\ +\n\ + - apache-tomcat:\n\ + address: [192.168.1.0/24, 127.0.0.0/8, \"::1\"]\n\ + personality: Tomcat_6_0\n\ +\n\ + - iis7:\n\ + address: \n\ + - 192.168.0.0/24\n\ + - 192.168.10.0/24\n\ + personality: IIS_7_0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + + HTPConfigure(); + + const char *addr = "192.168.10.42"; + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + htp_cfg_t *htp = cfglist.cfg; + + void *user_data = NULL; + (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)f->dst.addr_data32, cfgtree, &user_data); + if (user_data != NULL) { + HTPCfgRec *htp_cfg_rec = user_data; + htp = htp_cfg_rec->cfg; + SCLogDebug("LIBHTP using config: %p", htp); + } + if (htp == NULL) { + printf("Could not get config for: %s\n", addr); + goto end; + } + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + result = 0; + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + if (HTPStateGetTxCnt(htp_state) != 2) { + printf("HTPStateGetTxCnt(htp_state) failure\n"); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + if (tx->cfg != htp) { + printf("wrong HTP config (%p instead of %p - default=%p): ", tx->cfg, htp, cfglist.cfg); + goto end; + } + tx = HTPStateGetTx(htp_state, 1); + if (tx == NULL) + goto end; + if (tx->cfg != htp) { + printf("wrong HTP config (%p instead of %p - default=%p): ", tx->cfg, htp, cfglist.cfg); + goto end; + } + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/* disabled when we upgraded to libhtp 0.5.x */ +#if 0 +static int HTPParserConfigTest04(void) +{ + int result = 0; + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + path-control-char-handling: status_400\n\ + path-convert-utf8: yes\n\ + path-invalid-encoding-handling: remove_percent\n\ +\n\ + server-config:\n\ +\n\ + - apache-tomcat:\n\ + personality: Tomcat_6_0\n\ + path-invalid-utf8-handling: none\n\ + path-nul-encoded-handling: status_404\n\ + path-nul-raw-handling: status_400\n\ +\n\ + - iis7:\n\ + personality: IIS_7_0\n\ + path-replacement-char: o\n\ + path-unicode-mapping: status_400\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(input, strlen(input)); + + HTPConfigure(); + + HTPCfgRec *cfg_rec = &cfglist; + if (cfg_rec->cfg->path_control_char_handling != STATUS_400 || + cfg_rec->cfg->path_convert_utf8 != 1 || + cfg_rec->cfg->path_invalid_encoding_handling != URL_DECODER_REMOVE_PERCENT) { + printf("failed 1\n"); + goto end; + } + + cfg_rec = cfg_rec->next; + if (cfg_rec->cfg->bestfit_replacement_char != 'o' || + cfg_rec->cfg->path_unicode_mapping != STATUS_400) { + printf("failed 2\n"); + goto end; + } + + cfg_rec = cfg_rec->next; + if (cfg_rec->cfg->path_invalid_utf8_handling != NONE || + cfg_rec->cfg->path_nul_encoded_handling != STATUS_404 || + cfg_rec->cfg->path_nul_raw_handling != STATUS_400) { + printf("failed 3\n"); + goto end; + } + + result = 1; + +end: + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + return result; +} +#endif + +/** \test Test %2f decoding in profile Apache_2_2 + * + * %2f in path is left untouched + * %2f in query string is normalized to %2F + * %252f in query string is decoded/normalized to %2F + */ +static int HTPParserDecodingTest01(void) +{ + uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" + "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" + "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: Apache_2\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + for (uint32_t u = 0; u < httplen1; u++) { + uint8_t flags = 0; + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + FAIL_IF(r != 0); + } + + HtpState *htp_state = f->alstate; + FAIL_IF_NULL(htp_state); + + uint8_t ref1[] = "/abc%2fdef"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + FAIL_IF_NULL(tx); + + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->request_uri_normalized); + FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); + FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0); + + uint8_t ref2[] = "/abc/def?ghi/jkl"; + reflen = sizeof(ref2) - 1; + + tx = HTPStateGetTx(htp_state, 1); + FAIL_IF_NULL(tx); + tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->request_uri_normalized); + FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); + + FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, + bstr_len(tx_ud->request_uri_normalized)) != 0); + + uint8_t ref3[] = "/abc/def?ghi%2fjkl"; + reflen = sizeof(ref3) - 1; + tx = HTPStateGetTx(htp_state, 2); + FAIL_IF_NULL(tx); + tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->request_uri_normalized); + FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); + + FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3, + bstr_len(tx_ud->request_uri_normalized)) != 0); + + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +static int HTPParserDecodingTest01a(void) +{ + uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" + "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" + "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: Apache_2\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, + (STREAM_TOSERVER | STREAM_START | STREAM_EOF), httpbuf1, httplen1); + FAIL_IF(r != 0); + + HtpState *htp_state = f->alstate; + FAIL_IF_NULL(htp_state); + + uint8_t ref1[] = "/abc%2fdef"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + FAIL_IF_NULL(tx); + + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->request_uri_normalized); + FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); + FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0); + + uint8_t ref2[] = "/abc/def?ghi/jkl"; + reflen = sizeof(ref2) - 1; + + tx = HTPStateGetTx(htp_state, 1); + FAIL_IF_NULL(tx); + tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->request_uri_normalized); + FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); + + FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, + bstr_len(tx_ud->request_uri_normalized)) != 0); + + uint8_t ref3[] = "/abc/def?ghi%2fjkl"; + reflen = sizeof(ref3) - 1; + tx = HTPStateGetTx(htp_state, 2); + FAIL_IF_NULL(tx); + tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + FAIL_IF_NULL(tx_ud); + FAIL_IF_NULL(tx_ud->request_uri_normalized); + FAIL_IF(reflen != bstr_len(tx_ud->request_uri_normalized)); + + FAIL_IF(memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3, + bstr_len(tx_ud->request_uri_normalized)) != 0); + + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test %2f decoding in profile IDS + * + * %2f in path decoded to / + * %2f in query string is decoded to / + * %252f in query string is decoded to %2F + */ +static int HTPParserDecodingTest02(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /abc%2fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" + "GET /abc/def?ghi%2fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" + "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: no\n\ + double-decode-query: no\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "/abc/def"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + uint8_t ref2[] = "/abc/def?ghi/jkl"; + reflen = sizeof(ref2) - 1; + + tx = HTPStateGetTx(htp_state, 1); + if (tx == NULL) + goto end; + tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref2, reflen); + printf("\": "); + goto end; + } + } + + uint8_t ref3[] = "/abc/def?ghi%2fjkl"; + reflen = sizeof(ref3) - 1; + tx = HTPStateGetTx(htp_state, 2); + if (tx == NULL) + goto end; + tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX " (3): ", + (uintmax_t)reflen, (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref3, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref3, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test %2f decoding in profile IDS with double-decode-* options + * + * %252f in path decoded to / + * %252f in query string is decoded to / + */ +static int HTPParserDecodingTest03(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /abc%252fdef HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n" + "GET /abc/def?ghi%252fjkl HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: yes\n\ + double-decode-query: yes\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "/abc/def"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + uint8_t ref2[] = "/abc/def?ghi/jkl"; + reflen = sizeof(ref2) - 1; + + tx = HTPStateGetTx(htp_state, 1); + if (tx == NULL) + goto end; + tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref2, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref2, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test http:// in query profile IDS + */ +static int HTPParserDecodingTest04(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: yes\n\ + double-decode-query: yes\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "/abc/def?a=http://www.abc.com/"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test \ char in query profile IDS. Bug 739 + */ +static int HTPParserDecodingTest05(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /index?id=\\\" " + "HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: yes\n\ + double-decode-query: yes\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "/index?id=\\\""; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test + char in query. Bug 1035 + */ +static int HTPParserDecodingTest06(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: yes\n\ + double-decode-query: yes\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "/put.php?ip=1.2.3.4&port=+6000"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test + char in query. Bug 1035 + */ +static int HTPParserDecodingTest07(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET /put.php?ip=1.2.3.4&port=+6000 HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: yes\n\ + double-decode-query: yes\n\ + query-plusspace-decode: yes\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "/put.php?ip=1.2.3.4&port= 6000"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test 'proxy' URI normalization. Ticket 1008 + */ +static int HTPParserDecodingTest08(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "/blah/"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test 'proxy' URI normalization. Ticket 1008 + */ +static int HTPParserDecodingTest09(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET http://suricata-ids.org/blah/ HTTP/1.1\r\nHost: suricata-ids.org\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + uri-include-all: true\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + const char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + uint8_t ref1[] = "http://suricata-ids.org/blah/"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL) + goto end; + HtpTxUserData *tx_ud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { + if (reflen != bstr_len(tx_ud->request_uri_normalized)) { + printf("normalized uri len should be %" PRIuMAX ", is %" PRIuMAX, (uintmax_t)reflen, + (uintmax_t)bstr_len(tx_ud->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx_ud->request_uri_normalized), ref1, + bstr_len(tx_ud->request_uri_normalized)) != 0) { + printf("normalized uri \""); + PrintRawUriFp(stdout, bstr_ptr(tx_ud->request_uri_normalized), + bstr_len(tx_ud->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test BG box crash -- chunks are messed up. Observed for real. */ +static int HTPBodyReassemblyTest01(void) +{ + int result = 0; + HtpTxUserData htud; + memset(&htud, 0x00, sizeof(htud)); + HtpState hstate; + memset(&hstate, 0x00, sizeof(hstate)); + Flow flow; + memset(&flow, 0x00, sizeof(flow)); + AppLayerParserState *parser = AppLayerParserStateAlloc(); + htp_tx_t tx; + memset(&tx, 0, sizeof(tx)); + + hstate.f = &flow; + flow.alparser = parser; + + uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; " + "name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; + uint8_t chunk2[] = + "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: " + "utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 " + "Firefox/9.0.1\r\nAccept: " + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: " + "keep-alive\r\nContent-length: 68102\r\nReferer: " + "http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; " + "boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: " + "us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; " + "name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; + + int r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk1, sizeof(chunk1) - 1); + BUG_ON(r != 0); + r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk2, sizeof(chunk2) - 1); + BUG_ON(r != 0); + + const uint8_t *chunks_buffer = NULL; + uint32_t chunks_buffer_len = 0; + + HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len); + if (chunks_buffer == NULL) { + goto end; + } +#ifdef PRINT + printf("REASSCHUNK START: \n"); + PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); + printf("REASSCHUNK END: \n"); +#endif + + HtpRequestBodyHandleMultipart(&hstate, &htud, &tx, chunks_buffer, chunks_buffer_len); + + if (htud.request_body.content_len_so_far != 669) { + printf("htud.request_body.content_len_so_far %" PRIu64 ": ", + htud.request_body.content_len_so_far); + goto end; + } + + FAIL_IF_NOT_NULL(htud.files_ts.head); + + result = 1; +end: + return result; +} + +/** \test BG crash */ +static int HTPSegvTest01(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: " + "utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 " + "Firefox/9.0.1\r\nAccept: " + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: " + "keep-alive\r\nContent-length: 68102\r\nReferer: " + "http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; " + "boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: " + "us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; " + "name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: no\n\ + double-decode-query: no\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + SCLogDebug("\n>>>> processing chunk 1 again <<<<\n"); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(f->alparser); + if (decoder_events != NULL) { + printf("app events: "); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test really long request, this should result in HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG + */ +static int HTPParserTest14(void) +{ + size_t len = 18887; + TcpSession ssn; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: no\n\ + double-decode-query: no\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ +"; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&ssn, 0, sizeof(ssn)); + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + char *httpbuf = SCMalloc(len); + FAIL_IF_NULL(httpbuf); + memset(httpbuf, 0x00, len); + + /* create the request with a longer than 18k cookie */ + strlcpy(httpbuf, + "GET /blah/ HTTP/1.1\r\n" + "Host: myhost.lan\r\n" + "Connection: keep-alive\r\n" + "Accept: */*\r\n" + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like " + "Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" + "Referer: http://blah.lan/\r\n" + "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" + "Cookie: ", + len); + size_t o = strlen(httpbuf); + for (; o < len - 4; o++) { + httpbuf[o] = 'A'; + } + httpbuf[len - 4] = '\r'; + httpbuf[len - 3] = '\n'; + httpbuf[len - 2] = '\r'; + httpbuf[len - 1] = '\n'; + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->alproto = ALPROTO_HTTP1; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < len; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (len - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + (void)AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1); + } + HtpState *htp_state = f->alstate; + FAIL_IF_NULL(htp_state); + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + FAIL_IF_NULL(tx); + FAIL_IF(tx->request_method_number != HTP_M_GET); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); + AppLayerDecoderEvents *decoder_events = + AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); + FAIL_IF_NULL(decoder_events); + + FAIL_IF(decoder_events->events[0] != HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + SCFree(httpbuf); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + PASS; +} + +/** \test Test really long request (same as HTPParserTest14), now with config + * update to allow it */ +static int HTPParserTest15(void) +{ + int result = 0; + Flow *f = NULL; + char *httpbuf = NULL; + size_t len = 18887; + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: no\n\ + double-decode-query: no\n\ + request-body-limit: 0\n\ + response-body-limit: 0\n\ + meta-field-limit: 20000\n\ +"; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + httpbuf = SCMalloc(len); + if (unlikely(httpbuf == NULL)) + goto end; + memset(httpbuf, 0x00, len); + + /* create the request with a longer than 18k cookie */ + strlcpy(httpbuf, + "GET /blah/ HTTP/1.1\r\n" + "Host: myhost.lan\r\n" + "Connection: keep-alive\r\n" + "Accept: */*\r\n" + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like " + "Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" + "Referer: http://blah.lan/\r\n" + "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" + "Cookie: ", + len); + size_t o = strlen(httpbuf); + for (; o < len - 4; o++) { + httpbuf[o] = 'A'; + } + httpbuf[len - 4] = '\r'; + httpbuf[len - 3] = '\n'; + httpbuf[len - 2] = '\r'; + httpbuf[len - 1] = '\n'; + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint32_t u; + for (u = 0; u < len; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER | STREAM_START; + else if (u == (len - 1)) + flags = STREAM_TOSERVER | STREAM_EOF; + else + flags = STREAM_TOSERVER; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)&httpbuf[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", + u, r); + goto end; + } + } + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL || tx->request_method_number != HTP_M_GET || + tx->request_protocol_number != HTP_PROTOCOL_1_1) { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", + bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); + AppLayerDecoderEvents *decoder_events = + AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); + if (decoder_events != NULL) { + printf("app events: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + if (httpbuf != NULL) + SCFree(httpbuf); + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + return result; +} + +/** \test Test unusual delims in request line HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */ +static int HTPParserTest16(void) +{ + int result = 0; + Flow *f = NULL; + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n" + "Host: myhost.lan\r\n" + "Connection: keep-alive\r\n" + "Accept: */*\r\n" + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" + "Referer: http://blah.lan/\r\n" + "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" + "Cookie: blah\r\n\r\n"; + size_t len = sizeof(httpbuf) - 1; + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + uint8_t flags = STREAM_TOSERVER | STREAM_START | STREAM_EOF; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, flags, (uint8_t *)httpbuf, len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL || tx->request_method_number != HTP_M_GET || + tx->request_protocol_number != HTP_PROTOCOL_1_1) { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", + tx ? bstr_util_strdup_to_c(tx->request_method) : "tx null", + tx ? bstr_util_strdup_to_c(tx->request_protocol) : "tx null"); + goto end; + } + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // these events are disabled during fuzzing as they are too noisy and consume much resource + void *txtmp = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0); + AppLayerDecoderEvents *decoder_events = + AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP1, txtmp); + if (decoder_events == NULL) { + printf("no app events: "); + goto end; + } + + if (decoder_events->events[0] != HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT) { + printf("HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT not set: "); + goto end; + } + + if (decoder_events->events[1] != HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT) { + printf("HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT not set: "); + goto end; + } +#endif + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + return result; +} + +/** \test Test response not HTTP + */ +static int HTPParserTest20(void) +{ + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" + "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " + "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "NOTHTTP\r\nSOMEOTHERDATA"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3); + FAIL_IF(r != 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(tx->request_method_number != HTP_M_GET); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + FAIL_IF(tx->response_status_number != 0); + FAIL_IF(tx->response_protocol_number != -1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test response not HTTP + */ +static int HTPParserTest21(void) +{ + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" + "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " + "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "999 NOTHTTP REALLY\r\nSOMEOTHERDATA\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint8_t httpbuf3[] = "STILLNOTHTTP\r\nSOMEMOREOTHERDATA"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf3, httplen3); + FAIL_IF(r != 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(tx->request_method_number != HTP_M_GET); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + FAIL_IF(tx->response_status_number != 0); + FAIL_IF(tx->response_protocol_number != -1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test response not HTTP + */ +static int HTPParserTest22(void) +{ + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" + "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " + "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "\r\n0000=0000000/ASDF3_31.zip, 456723\r\n" + "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); + FAIL_IF(r != 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(tx->request_method_number != HTP_M_GET); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + FAIL_IF(tx->response_status_number != -0); + FAIL_IF(tx->response_protocol_number != -1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test response not HTTP + */ +static int HTPParserTest23(void) +{ + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" + "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " + "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP0000=0000000/ASDF3_31.zip, 456723\r\n" + "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); + FAIL_IF(r != 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(tx->request_method_number != HTP_M_GET); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + FAIL_IF(tx->response_status_number != -1); + FAIL_IF(tx->response_protocol_number != -2); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test Test response not HTTP + */ +static int HTPParserTest24(void) +{ + Flow *f = NULL; + uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" + "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " + "LD-agent\r\nHost: 209.205.196.16\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.0 0000=0000000/ASDF3_31.zip, 456723\r\n" + "AAAAAA_0000=0000000/AAAAAAAA.zip,46725\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1); + FAIL_IF(r != 0); + + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); + FAIL_IF(r != 0); + + http_state = f->alstate; + FAIL_IF_NULL(http_state); + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + FAIL_IF_NULL(tx); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + FAIL_IF_NULL(h); + + FAIL_IF(tx->request_method_number != HTP_M_GET); + FAIL_IF(tx->request_protocol_number != HTP_PROTOCOL_1_1); + + FAIL_IF(tx->response_status_number != -1); + FAIL_IF(tx->response_protocol_number != HTP_PROTOCOL_1_0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + PASS; +} + +/** \test multi transactions and cleanup */ +static int HTPParserTest25(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + StreamTcpInitConfig(true); + TcpSession ssn; + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_HTTP1; + + const char *str = "GET / HTTP/1.1\r\nHost: www.google.com\r\nUser-Agent: Suricata/1.0\r\n\r\n"; + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, + (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + + str = "HTTP 1.1 200 OK\r\nServer: Suricata/1.0\r\nContent-Length: 8\r\n\r\nSuricata"; + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_START, + (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT, (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + + uint64_t ret[4]; + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 8); // log_id + FAIL_IF_NOT(ret[3] == 8); // min_id + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, + (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done + FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 8); // log_id + FAIL_IF_NOT(ret[3] == 8); // min_id + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOCLIENT | STREAM_EOF, + (uint8_t *)str, strlen(str)); + FAIL_IF_NOT(r == 0); + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 9); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 9); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 9); // log_id + FAIL_IF_NOT(ret[3] == 9); // min_id + + HtpState *http_state = f->alstate; + FAIL_IF_NULL(http_state); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + + PASS; +} + +static int HTPParserTest26(void) +{ + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + request-body-limit: 1\n\ + response-body-limit: 1\n\ +"; + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + uint8_t httpbuf1[] = "GET /alice.txt HTTP/1.1\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 228\r\n\r\n" + "Alice was beginning to get very tired of sitting by her sister on the bank." + "Alice was beginning to get very tired of sitting by her sister on the bank."; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + uint8_t httpbuf3[] = + "Alice was beginning to get very tired of sitting by her sister on the bank.\r\n\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP1; + + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(filestore; sid:1; rev:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + + http_state = f.alstate; + FAIL_IF_NULL(http_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + FAIL_IF((PacketAlertCheck(p1, 1))); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + FAIL_IF((PacketAlertCheck(p1, 1))); + + r = AppLayerParserParse( + &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf2, httplen2); + FAIL_IF(r != 0); + + http_state = f.alstate; + FAIL_IF_NULL(http_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + FAIL_IF(!(PacketAlertCheck(p2, 1))); + + r = AppLayerParserParse( + &th_v, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOCLIENT, httpbuf3, httplen3); + FAIL_IF(r != 0); + + http_state = f.alstate; + FAIL_IF_NULL(http_state); + + void *tx_ptr = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, http_state, 0); + FAIL_IF_NULL(tx_ptr); + + AppLayerGetFileState files = HTPGetTxFiles(http_state, tx_ptr, STREAM_TOCLIENT); + FileContainer *ffc = files.fc; + FAIL_IF_NULL(ffc); + + File *ptr = ffc->head; + FAIL_IF(ptr->state != FILE_STATE_CLOSED); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(true); + + HTPFreeConfig(); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + PASS; +} + +static int HTPParserTest27(void) +{ + HTPCfgDir cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.body_limit = 1500; + FileReassemblyDepthEnable(2000); + + uint32_t len = 1000; + + HtpTxUserData *tx_ud = SCMalloc(sizeof(HtpTxUserData)); + FAIL_IF_NULL(tx_ud); + + tx_ud->tsflags |= HTP_STREAM_DEPTH_SET; + tx_ud->request_body.content_len_so_far = 2500; + + FAIL_IF(AppLayerHtpCheckDepth(&cfg, &tx_ud->request_body, tx_ud->tsflags)); + + len = AppLayerHtpComputeChunkLength( + tx_ud->request_body.content_len_so_far, 0, FileReassemblyDepth(), tx_ud->tsflags, len); + FAIL_IF(len != 1000); + + SCFree(tx_ud); + + PASS; +} + +/** + * \brief Register the Unit tests for the HTTP protocol + */ +static void HTPParserRegisterTests(void) +{ + UtRegisterTest("HTPParserTest01", HTPParserTest01); + UtRegisterTest("HTPParserTest01a", HTPParserTest01a); + UtRegisterTest("HTPParserTest01b", HTPParserTest01b); + UtRegisterTest("HTPParserTest01c", HTPParserTest01c); + UtRegisterTest("HTPParserTest02", HTPParserTest02); + UtRegisterTest("HTPParserTest03", HTPParserTest03); + UtRegisterTest("HTPParserTest04", HTPParserTest04); + UtRegisterTest("HTPParserTest05", HTPParserTest05); + UtRegisterTest("HTPParserTest06", HTPParserTest06); + UtRegisterTest("HTPParserTest07", HTPParserTest07); + UtRegisterTest("HTPParserTest08", HTPParserTest08); + UtRegisterTest("HTPParserTest09", HTPParserTest09); + UtRegisterTest("HTPParserTest10", HTPParserTest10); + UtRegisterTest("HTPParserTest11", HTPParserTest11); + UtRegisterTest("HTPParserTest12", HTPParserTest12); + UtRegisterTest("HTPParserTest13", HTPParserTest13); + UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01); + UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02); + UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03); +#if 0 /* disabled when we upgraded to libhtp 0.5.x */ + UtRegisterTest("HTPParserConfigTest04", HTPParserConfigTest04, 1); +#endif + + UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01); + UtRegisterTest("HTPParserDecodingTest01a", HTPParserDecodingTest01a); + UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02); + UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03); + UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04); + UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05); + UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06); + UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07); + UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08); + UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09); + + UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01); + + UtRegisterTest("HTPSegvTest01", HTPSegvTest01); + + UtRegisterTest("HTPParserTest14", HTPParserTest14); + UtRegisterTest("HTPParserTest15", HTPParserTest15); + UtRegisterTest("HTPParserTest16", HTPParserTest16); + UtRegisterTest("HTPParserTest20", HTPParserTest20); + UtRegisterTest("HTPParserTest21", HTPParserTest21); + UtRegisterTest("HTPParserTest22", HTPParserTest22); + UtRegisterTest("HTPParserTest23", HTPParserTest23); + UtRegisterTest("HTPParserTest24", HTPParserTest24); + UtRegisterTest("HTPParserTest25", HTPParserTest25); + UtRegisterTest("HTPParserTest26", HTPParserTest26); + UtRegisterTest("HTPParserTest27", HTPParserTest27); + + HTPFileParserRegisterTests(); + HTPXFFParserRegisterTests(); +} +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/app-layer/http/parser.h b/src/app-layer/http/parser.h new file mode 100644 index 000000000000..965bc4acc329 --- /dev/null +++ b/src/app-layer/http/parser.h @@ -0,0 +1,298 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \defgroup httplayer HTTP layer support + * + * @{ + */ + +/** + * \file + * + * \author Gurvinder Singh + * \author Pablo Rincon + * + * This file provides a HTTP protocol support for the engine using HTP library. + */ + +#ifndef __APP_LAYER_HTP_H__ +#define __APP_LAYER_HTP_H__ + +#include "rust.h" +#include "app-layer-frames.h" + +#include + +/* default request body limit */ +#define HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT 4096U +#define HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT 4096U +#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE 32768U +#define HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW 4096U +#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE 32768U +#define HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW 4096U +#define HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT 9000U +#define HTP_CONFIG_DEFAULT_FIELD_LIMIT_HARD 18000U + +#define HTP_CONFIG_DEFAULT_LZMA_LAYERS 0U +/* default libhtp lzma limit, taken from libhtp. */ +#define HTP_CONFIG_DEFAULT_LZMA_MEMLIMIT 1048576U +#define HTP_CONFIG_DEFAULT_COMPRESSION_BOMB_LIMIT 1048576U +// 100000 usec is 0.1 sec +#define HTP_CONFIG_DEFAULT_COMPRESSION_TIME_LIMIT 100000 + +#define HTP_CONFIG_DEFAULT_RANDOMIZE 1 +#define HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE 10 + +/** a boundary should be smaller in size */ +#define HTP_BOUNDARY_MAX 200U + +// 0x0001 not used +#define HTP_FLAG_STATE_CLOSED_TS \ + 0x0002 /**< Flag to indicate that HTTP \ + connection is closed */ +#define HTP_FLAG_STATE_CLOSED_TC \ + 0x0004 /**< Flag to indicate that HTTP \ + connection is closed */ + +enum { + HTP_BODY_REQUEST_NONE = 0, + HTP_BODY_REQUEST_MULTIPART, /* POST, MP */ + HTP_BODY_REQUEST_POST, /* POST, no MP */ + HTP_BODY_REQUEST_PUT, +}; + +enum { + /* libhtp errors/warnings */ + HTTP_DECODER_EVENT_UNKNOWN_ERROR, + HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED, + HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON, + HTTP_DECODER_EVENT_RESPONSE_FIELD_MISSING_COLON, + HTTP_DECODER_EVENT_INVALID_REQUEST_CHUNK_LEN, + HTTP_DECODER_EVENT_INVALID_RESPONSE_CHUNK_LEN, + HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_REQUEST, + HTTP_DECODER_EVENT_INVALID_TRANSFER_ENCODING_VALUE_IN_RESPONSE, + HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_REQUEST, + HTTP_DECODER_EVENT_INVALID_CONTENT_LENGTH_FIELD_IN_RESPONSE, + HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_REQUEST, + HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE, + HTTP_DECODER_EVENT_100_CONTINUE_ALREADY_SEEN, + HTTP_DECODER_EVENT_UNABLE_TO_MATCH_RESPONSE_TO_REQUEST, + HTTP_DECODER_EVENT_INVALID_SERVER_PORT_IN_REQUEST, + HTTP_DECODER_EVENT_INVALID_AUTHORITY_PORT, + HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID, + HTTP_DECODER_EVENT_RESPONSE_HEADER_INVALID, + HTTP_DECODER_EVENT_MISSING_HOST_HEADER, + HTTP_DECODER_EVENT_HOST_HEADER_AMBIGUOUS, + HTTP_DECODER_EVENT_INVALID_REQUEST_FIELD_FOLDING, + HTTP_DECODER_EVENT_INVALID_RESPONSE_FIELD_FOLDING, + HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG, + HTTP_DECODER_EVENT_RESPONSE_FIELD_TOO_LONG, + HTTP_DECODER_EVENT_FILE_NAME_TOO_LONG, + HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH, + HTTP_DECODER_EVENT_URI_HOST_INVALID, + HTTP_DECODER_EVENT_HEADER_HOST_INVALID, + HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT, + HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT, + HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE, + HTTP_DECODER_EVENT_TOO_MANY_ENCODING_LAYERS, + HTTP_DECODER_EVENT_ABNORMAL_CE_HEADER, + HTTP_DECODER_EVENT_AUTH_UNRECOGNIZED, + HTTP_DECODER_EVENT_REQUEST_HEADER_REPETITION, + HTTP_DECODER_EVENT_RESPONSE_HEADER_REPETITION, + HTTP_DECODER_EVENT_RESPONSE_MULTIPART_BYTERANGES, + HTTP_DECODER_EVENT_RESPONSE_ABNORMAL_TRANSFER_ENCODING, + HTTP_DECODER_EVENT_RESPONSE_CHUNKED_OLD_PROTO, + HTTP_DECODER_EVENT_RESPONSE_INVALID_PROTOCOL, + HTTP_DECODER_EVENT_RESPONSE_INVALID_STATUS, + HTTP_DECODER_EVENT_REQUEST_LINE_INCOMPLETE, + HTTP_DECODER_EVENT_DOUBLE_ENCODED_URI, + HTTP_DECODER_EVENT_REQUEST_LINE_INVALID, + HTTP_DECODER_EVENT_REQUEST_BODY_UNEXPECTED, + + HTTP_DECODER_EVENT_LZMA_MEMLIMIT_REACHED, + HTTP_DECODER_EVENT_COMPRESSION_BOMB, + + HTTP_DECODER_EVENT_RANGE_INVALID, + HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION, + + /* suricata errors/warnings */ + HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR, + HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA, + HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER, + + HTTP_DECODER_EVENT_TOO_MANY_WARNINGS, + + HTTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE, +}; + +typedef enum HtpSwfCompressType_ { + HTTP_SWF_COMPRESSION_NONE = 0, + HTTP_SWF_COMPRESSION_ZLIB, + HTTP_SWF_COMPRESSION_LZMA, + HTTP_SWF_COMPRESSION_BOTH, +} HtpSwfCompressType; + +typedef struct HTPCfgDir_ { + uint32_t body_limit; + uint32_t inspect_min_size; + uint32_t inspect_window; +} HTPCfgDir; + +/** Need a linked list in order to keep track of these */ +typedef struct HTPCfgRec_ { + htp_cfg_t *cfg; + struct HTPCfgRec_ *next; + + /** max size of the client body we inspect */ + int randomize; + int randomize_range; + int http_body_inline; + + int swf_decompression_enabled; + HtpSwfCompressType swf_compression_type; + uint32_t swf_decompress_depth; + uint32_t swf_compress_depth; + + HTPCfgDir request; + HTPCfgDir response; + + bool uri_include_all; /**< use all info in uri (bool) */ +} HTPCfgRec; + +/** Struct used to hold chunks of a body on a request */ +struct HtpBodyChunk_ { + struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */ + int logged; + StreamingBufferSegment sbseg; +} __attribute__((__packed__)); +typedef struct HtpBodyChunk_ HtpBodyChunk; + +/** Struct used to hold all the chunks of a body on a request */ +typedef struct HtpBody_ { + HtpBodyChunk *first; /**< Pointer to the first chunk */ + HtpBodyChunk *last; /**< Pointer to the last chunk */ + + StreamingBuffer *sb; + + /* Holds the length of the htp request body seen so far */ + uint64_t content_len_so_far; + /* parser tracker */ + uint64_t body_parsed; + /* inspection tracker */ + uint64_t body_inspected; +} HtpBody; + +#define HTP_BOUNDARY_SET BIT_U8(1) /**< We have a boundary string */ +#define HTP_FILENAME_SET BIT_U8(3) /**< filename is registered in the flow */ +#define HTP_DONTSTORE BIT_U8(4) /**< not storing this file */ +#define HTP_STREAM_DEPTH_SET BIT_U8(5) /**< stream-depth is set */ + +/** Now the Body Chunks will be stored per transaction, at + * the tx user data */ +typedef struct HtpTxUserData_ { + /* Body of the request (if any) */ + uint8_t request_body_init; + uint8_t response_body_init; + + uint8_t request_has_trailers; + uint8_t response_has_trailers; + + uint8_t boundary_len; + + uint8_t tsflags; + uint8_t tcflags; + + uint8_t request_body_type; + + HtpBody request_body; + HtpBody response_body; + + bstr *request_uri_normalized; + + uint8_t *request_headers_raw; + uint8_t *response_headers_raw; + uint32_t request_headers_raw_len; + uint32_t response_headers_raw_len; + + /** Holds the boundary identification string if any (used on + * multipart/form-data only) + */ + uint8_t *boundary; + + HttpRangeContainerBlock *file_range; /**< used to assign track ids to range file */ + + AppLayerTxData tx_data; + FileContainer files_ts; + FileContainer files_tc; +} HtpTxUserData; + +typedef struct HtpState_ { + /* Connection parser structure for each connection */ + htp_connp_t *connp; + /* Connection structure for each connection */ + htp_conn_t *conn; + Flow *f; /**< Needed to retrieve the original flow when using HTPLib callbacks */ + uint64_t transaction_cnt; + const struct HTPCfgRec_ *cfg; + uint16_t flags; + uint16_t events; + uint16_t htp_messages_offset; /**< offset into conn->messages list */ + uint32_t file_track_id; /**< used to assign file track ids to files */ + uint64_t last_request_data_stamp; + uint64_t last_response_data_stamp; + StreamSlice *slice; + FrameId request_frame_id; + FrameId response_frame_id; + AppLayerStateData state_data; +} HtpState; + +/** part of the engine needs the request body (e.g. http_client_body keyword) */ +#define HTP_REQUIRE_REQUEST_BODY (1 << 0) +/** part of the engine needs the request body multipart header (e.g. filename + * and / or fileext keywords) */ +#define HTP_REQUIRE_REQUEST_MULTIPART (1 << 1) +/** part of the engine needs the request file (e.g. log-file module) */ +#define HTP_REQUIRE_REQUEST_FILE (1 << 2) +/** part of the engine needs the request body (e.g. file_data keyword) */ +#define HTP_REQUIRE_RESPONSE_BODY (1 << 3) + +SC_ATOMIC_EXTERN(uint32_t, htp_config_flags); + +void RegisterHTPParsers(void); +void HTPAtExitPrintStats(void); +void HTPFreeConfig(void); + +/* To free the state from unittests using app-layer-htp */ +void HTPStateFree(void *); +void AppLayerHtpEnableRequestBodyCallback(void); +void AppLayerHtpEnableResponseBodyCallback(void); +void AppLayerHtpNeedFileInspection(void); +void AppLayerHtpPrintStats(void); + +void HTPConfigure(void); + +void HtpConfigCreateBackup(void); +void HtpConfigRestoreBackup(void); + +void *HtpGetTxForH2(void *); + +#endif /* __APP_LAYER_HTP_H__ */ + +/** + * @} + */ diff --git a/src/app-layer/http2/detect.c b/src/app-layer/http2/detect.c new file mode 100644 index 000000000000..6813f1c035f9 --- /dev/null +++ b/src/app-layer/http2/detect.c @@ -0,0 +1,714 @@ +/* Copyright (C) 2020-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Philippe Antoine + * + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" + +#include "detect-engine.h" +#include "detect-engine-uint.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer/http2/detect.h" +#include "util/byte.h" +#include "rust.h" +#include "util/profiling.h" + +#ifdef UNITTESTS +void DetectHTTP2frameTypeRegisterTests(void); +void DetectHTTP2errorCodeRegisterTests(void); +void DetectHTTP2priorityRegisterTests(void); +void DetectHTTP2windowRegisterTests(void); +void DetectHTTP2settingsRegisterTests(void); +void DetectHTTP2sizeUpdateRegisterTests(void); +#endif + +/* prototypes */ +static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectHTTP2frametypeSetup(DetectEngineCtx *, Signature *, const char *); +void DetectHTTP2frametypeFree(DetectEngineCtx *, void *); + +static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectHTTP2errorcodeSetup(DetectEngineCtx *, Signature *, const char *); +void DetectHTTP2errorcodeFree(DetectEngineCtx *, void *); + +static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectHTTP2prioritySetup(DetectEngineCtx *, Signature *, const char *); +void DetectHTTP2priorityFree(DetectEngineCtx *, void *); + +static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectHTTP2windowSetup(DetectEngineCtx *, Signature *, const char *); +void DetectHTTP2windowFree(DetectEngineCtx *, void *); + +static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectHTTP2sizeUpdateSetup(DetectEngineCtx *, Signature *, const char *); +void DetectHTTP2sizeUpdateFree(DetectEngineCtx *, void *); + +static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectHTTP2settingsSetup(DetectEngineCtx *, Signature *, const char *); +void DetectHTTP2settingsFree(DetectEngineCtx *, void *); + +static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg); +static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); +static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +#ifdef UNITTESTS +void DetectHTTP2RegisterTests(void); +#endif + +static int g_http2_match_buffer_id = 0; +static int g_http2_header_name_buffer_id = 0; + +/** + * \brief Registration function for HTTP2 keywords + */ + +void DetectHttp2Register(void) +{ + sigmatch_table[DETECT_HTTP2_FRAMETYPE].name = "http2.frametype"; + sigmatch_table[DETECT_HTTP2_FRAMETYPE].desc = "match on HTTP2 frame type field"; + sigmatch_table[DETECT_HTTP2_FRAMETYPE].url = "/rules/http2-keywords.html#frametype"; + sigmatch_table[DETECT_HTTP2_FRAMETYPE].Match = NULL; + sigmatch_table[DETECT_HTTP2_FRAMETYPE].AppLayerTxMatch = DetectHTTP2frametypeMatch; + sigmatch_table[DETECT_HTTP2_FRAMETYPE].Setup = DetectHTTP2frametypeSetup; + sigmatch_table[DETECT_HTTP2_FRAMETYPE].Free = DetectHTTP2frametypeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_HTTP2_FRAMETYPE].RegisterTests = DetectHTTP2frameTypeRegisterTests; +#endif + + sigmatch_table[DETECT_HTTP2_ERRORCODE].name = "http2.errorcode"; + sigmatch_table[DETECT_HTTP2_ERRORCODE].desc = "match on HTTP2 error code field"; + sigmatch_table[DETECT_HTTP2_ERRORCODE].url = "/rules/http2-keywords.html#errorcode"; + sigmatch_table[DETECT_HTTP2_ERRORCODE].Match = NULL; + sigmatch_table[DETECT_HTTP2_ERRORCODE].AppLayerTxMatch = DetectHTTP2errorcodeMatch; + sigmatch_table[DETECT_HTTP2_ERRORCODE].Setup = DetectHTTP2errorcodeSetup; + sigmatch_table[DETECT_HTTP2_ERRORCODE].Free = DetectHTTP2errorcodeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_HTTP2_ERRORCODE].RegisterTests = DetectHTTP2errorCodeRegisterTests; +#endif + + sigmatch_table[DETECT_HTTP2_PRIORITY].name = "http2.priority"; + sigmatch_table[DETECT_HTTP2_PRIORITY].desc = "match on HTTP2 priority weight field"; + sigmatch_table[DETECT_HTTP2_PRIORITY].url = "/rules/http2-keywords.html#priority"; + sigmatch_table[DETECT_HTTP2_PRIORITY].Match = NULL; + sigmatch_table[DETECT_HTTP2_PRIORITY].AppLayerTxMatch = DetectHTTP2priorityMatch; + sigmatch_table[DETECT_HTTP2_PRIORITY].Setup = DetectHTTP2prioritySetup; + sigmatch_table[DETECT_HTTP2_PRIORITY].Free = DetectHTTP2priorityFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_HTTP2_PRIORITY].RegisterTests = DetectHTTP2priorityRegisterTests; +#endif + + sigmatch_table[DETECT_HTTP2_WINDOW].name = "http2.window"; + sigmatch_table[DETECT_HTTP2_WINDOW].desc = "match on HTTP2 window update size increment field"; + sigmatch_table[DETECT_HTTP2_WINDOW].url = "/rules/http2-keywords.html#window"; + sigmatch_table[DETECT_HTTP2_WINDOW].Match = NULL; + sigmatch_table[DETECT_HTTP2_WINDOW].AppLayerTxMatch = DetectHTTP2windowMatch; + sigmatch_table[DETECT_HTTP2_WINDOW].Setup = DetectHTTP2windowSetup; + sigmatch_table[DETECT_HTTP2_WINDOW].Free = DetectHTTP2windowFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_HTTP2_WINDOW].RegisterTests = DetectHTTP2windowRegisterTests; +#endif + + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].name = "http2.size_update"; + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].desc = + "match on HTTP2 dynamic headers table size update"; + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].url = "/rules/http2-keywords.html#sizeupdate"; + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Match = NULL; + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].AppLayerTxMatch = DetectHTTP2sizeUpdateMatch; + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Setup = DetectHTTP2sizeUpdateSetup; + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Free = DetectHTTP2sizeUpdateFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_HTTP2_SIZEUPDATE].RegisterTests = DetectHTTP2sizeUpdateRegisterTests; +#endif + + sigmatch_table[DETECT_HTTP2_SETTINGS].name = "http2.settings"; + sigmatch_table[DETECT_HTTP2_SETTINGS].desc = + "match on HTTP2 settings identifier and value fields"; + sigmatch_table[DETECT_HTTP2_SETTINGS].url = "/rules/http2-keywords.html#settings"; + sigmatch_table[DETECT_HTTP2_SETTINGS].Match = NULL; + sigmatch_table[DETECT_HTTP2_SETTINGS].AppLayerTxMatch = DetectHTTP2settingsMatch; + sigmatch_table[DETECT_HTTP2_SETTINGS].Setup = DetectHTTP2settingsSetup; + sigmatch_table[DETECT_HTTP2_SETTINGS].Free = DetectHTTP2settingsFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_HTTP2_SETTINGS].RegisterTests = DetectHTTP2settingsRegisterTests; +#endif + + sigmatch_table[DETECT_HTTP2_HEADERNAME].name = "http2.header_name"; + sigmatch_table[DETECT_HTTP2_HEADERNAME].desc = + "sticky buffer to match on one HTTP2 header name"; + sigmatch_table[DETECT_HTTP2_HEADERNAME].url = "/rules/http2-keywords.html#header_name"; + sigmatch_table[DETECT_HTTP2_HEADERNAME].Setup = DetectHTTP2headerNameSetup; + sigmatch_table[DETECT_HTTP2_HEADERNAME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOCLIENT, 2, + PrefilterMpmHttp2HeaderNameRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen); + DetectAppLayerInspectEngineRegister2("http2_header_name", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, + HTTP2StateOpen, DetectEngineInspectHttp2HeaderName, NULL); + DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOSERVER, 2, + PrefilterMpmHttp2HeaderNameRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen); + DetectAppLayerInspectEngineRegister2("http2_header_name", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateOpen, DetectEngineInspectHttp2HeaderName, NULL); + DetectBufferTypeSupportsMultiInstance("http2_header_name"); + DetectBufferTypeSetDescriptionByName("http2_header_name", "HTTP2 header name"); + g_http2_header_name_buffer_id = DetectBufferTypeGetByName("http2_header_name"); + + DetectAppLayerInspectEngineRegister2( + "http2", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + DetectAppLayerInspectEngineRegister2( + "http2", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); + + g_http2_match_buffer_id = DetectBufferTypeRegister("http2"); + return; +} + +/** + * \brief This function is used to match HTTP2 frame type rule option on a transaction with those + * passed via http2.frametype: + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) + +{ + uint8_t *detect = (uint8_t *)ctx; + + return rs_http2_tx_has_frametype(txv, flags, *detect); +} + +static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft) +{ + // first parse numeric value + if (ByteExtractStringUint8(ft, 10, (uint16_t)strlen(str), str) >= 0) { + return 1; + } + + // it it failed so far, parse string value from enumeration + int r = rs_http2_parse_frametype(str); + if (r >= 0 && r <= UINT8_MAX) { + *ft = (uint8_t)r; + return 1; + } + + return 0; +} + +/** + * \brief this function is used to attach the parsed http2.frametype data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided http2.frametype options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectHTTP2frametypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + uint8_t frame_type; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) + return -1; + + if (!DetectHTTP2FuncParseFrameType(str, &frame_type)) { + SCLogError("Invalid argument \"%s\" supplied to http2.frametype keyword.", str); + return -1; + } + + uint8_t *http2ft = SCCalloc(1, sizeof(uint8_t)); + if (http2ft == NULL) + return -1; + *http2ft = frame_type; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_FRAMETYPE, (SigMatchCtx *)http2ft, + g_http2_match_buffer_id) == NULL) { + DetectHTTP2frametypeFree(NULL, http2ft); + return -1; + } + + return 0; +} + +/** + * \brief this function will free memory associated with uint8_t + * + * \param ptr pointer to uint8_t + */ +void DetectHTTP2frametypeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCFree(ptr); +} + +/** + * \brief This function is used to match HTTP2 error code rule option on a transaction with those + * passed via http2.errorcode: + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) + +{ + uint32_t *detect = (uint32_t *)ctx; + + return rs_http2_tx_has_errorcode(txv, flags, *detect); + // TODOask handle negation rules +} + +static int DetectHTTP2FuncParseErrorCode(const char *str, uint32_t *ec) +{ + // first parse numeric value + if (ByteExtractStringUint32(ec, 10, (uint16_t)strlen(str), str) >= 0) { + return 1; + } + + // it it failed so far, parse string value from enumeration + int r = rs_http2_parse_errorcode(str); + if (r >= 0) { + *ec = r; + return 1; + } + + return 0; +} + +/** + * \brief this function is used to attach the parsed http2.errorcode data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided http2.errorcode options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectHTTP2errorcodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + uint32_t error_code; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) + return -1; + + if (!DetectHTTP2FuncParseErrorCode(str, &error_code)) { + SCLogError("Invalid argument \"%s\" supplied to http2.errorcode keyword.", str); + return -1; + } + + uint32_t *http2ec = SCCalloc(1, sizeof(uint32_t)); + if (http2ec == NULL) + return -1; + *http2ec = error_code; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_ERRORCODE, (SigMatchCtx *)http2ec, + g_http2_match_buffer_id) == NULL) { + DetectHTTP2errorcodeFree(NULL, http2ec); + return -1; + } + + return 0; +} + +/** + * \brief this function will free memory associated with uint32_t + * + * \param ptr pointer to uint32_t + */ +void DetectHTTP2errorcodeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCFree(ptr); +} + +/** + * \brief This function is used to match HTTP2 error code rule option on a transaction with those + * passed via http2.priority: + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) + +{ + uint32_t nb = 0; + int value = rs_http2_tx_get_next_priority(txv, flags, nb); + const DetectU8Data *du8 = (const DetectU8Data *)ctx; + while (value >= 0) { + if (DetectU8Match((uint8_t)value, du8)) { + return 1; + } + nb++; + value = rs_http2_tx_get_next_priority(txv, flags, nb); + } + return 0; +} + +/** + * \brief this function is used to attach the parsed http2.priority data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided http2.priority options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectHTTP2prioritySetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) + return -1; + + DetectU8Data *prio = DetectU8Parse(str); + if (prio == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_PRIORITY, (SigMatchCtx *)prio, + g_http2_match_buffer_id) == NULL) { + rs_detect_u8_free(prio); + return -1; + } + + return 0; +} + +/** + * \brief this function will free memory associated with uint32_t + * + * \param ptr pointer to DetectU8Data + */ +void DetectHTTP2priorityFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u8_free(ptr); +} + +/** + * \brief This function is used to match HTTP2 window rule option on a transaction with those passed + * via http2.window: + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) + +{ + uint32_t nb = 0; + int value = rs_http2_tx_get_next_window(txv, flags, nb); + const DetectU32Data *du32 = (const DetectU32Data *)ctx; + while (value >= 0) { + if (DetectU32Match(value, du32)) { + return 1; + } + nb++; + value = rs_http2_tx_get_next_window(txv, flags, nb); + } + return 0; +} + +/** + * \brief this function is used to attach the parsed http2.window data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided http2.window options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectHTTP2windowSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) + return -1; + + DetectU32Data *wu = DetectU32Parse(str); + if (wu == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_WINDOW, (SigMatchCtx *)wu, + g_http2_match_buffer_id) == NULL) { + rs_detect_u32_free(wu); + return -1; + } + + return 0; +} + +/** + * \brief this function will free memory associated with uint32_t + * + * \param ptr pointer to DetectU8Data + */ +void DetectHTTP2windowFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} + +/** + * \brief This function is used to match HTTP2 size update rule option on a transaction with those + * passed via http2.size_update: + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) + +{ + return rs_http2_detect_sizeupdatectx_match(ctx, txv, flags); +} + +/** + * \brief this function is used to attach the parsed http2.size_update data into the current + * signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided http2.size_update options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectHTTP2sizeUpdateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) + return -1; + + void *su = rs_detect_u64_parse(str); + if (su == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_SIZEUPDATE, (SigMatchCtx *)su, + g_http2_match_buffer_id) == NULL) { + DetectHTTP2settingsFree(NULL, su); + return -1; + } + + return 0; +} + +/** + * \brief this function will free memory associated with uint32_t + * + * \param ptr pointer to DetectU8Data + */ +void DetectHTTP2sizeUpdateFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u64_free(ptr); +} + +/** + * \brief This function is used to match HTTP2 error code rule option on a transaction with those + * passed via http2.settings: + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) + +{ + return rs_http2_detect_settingsctx_match(ctx, txv, flags); +} + +/** + * \brief this function is used to attach the parsed http2.settings data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided http2.settings options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectHTTP2settingsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) + return -1; + + void *http2set = rs_http2_detect_settingsctx_parse(str); + if (http2set == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_SETTINGS, (SigMatchCtx *)http2set, + g_http2_match_buffer_id) == NULL) { + DetectHTTP2settingsFree(NULL, http2set); + return -1; + } + + return 0; +} + +/** + * \brief this function will free memory associated with rust signature context + * + * \param ptr pointer to rust signature context + */ +void DetectHTTP2settingsFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_http2_detect_settingsctx_free(ptr); +} + +static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_http2_header_name_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) + return -1; + + return 0; +} + +static void PrefilterMpmHttp2HNameFree(void *ptr) +{ + SCFree(ptr); +} + +static InspectionBuffer *GetHttp2HNameData(DetectEngineThreadCtx *det_ctx, const uint8_t flags, + const DetectEngineTransforms *transforms, Flow *_f, const struct MpmListIdDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_http2_tx_get_header_name(cbdata->txv, flags, cbdata->local_id, &b, &b_len) != 1) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + if (b == NULL || b_len == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, b, b_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static void PrefilterTxHttp2HName(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + + while (1) { + // loop until we get a NULL + + struct MpmListIdDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = + GetHttp2HNameData(det_ctx, flags, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + // TODOask use PrefilterMpmListId elsewhere + PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp2HName, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmHttp2HNameFree, mpm_reg->name); +} + +static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + // TODOask use MpmListIdDataArgs elsewhere + struct MpmListIdDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + GetHttp2HNameData(det_ctx, flags, transforms, f, &cbdata, engine->sm_list); + + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +#ifdef UNITTESTS +#include "tests/detect-http2.c" +#endif diff --git a/src/detect-http2.h b/src/app-layer/http2/detect.h similarity index 100% rename from src/detect-http2.h rename to src/app-layer/http2/detect.h diff --git a/src/app-layer/http2/logger.c b/src/app-layer/http2/logger.c new file mode 100644 index 000000000000..d71bb8a3b5e1 --- /dev/null +++ b/src/app-layer/http2/logger.c @@ -0,0 +1,167 @@ +/* Copyright (C) 2020-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Philippe Antoine + * + * Implements HTTP2 JSON logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" +#include "app-layer-parser.h" +#include "output/output.h" +#include "app-layer/http2/parser.h" +#include "app-layer.h" +#include "util/privs.h" +#include "util/buffer.h" + +#include "util/logopenfile.h" + +#include "output/eve/output-json.h" +#include "app-layer/http2/logger.h" +#include "rust.h" + +#define MODULE_NAME "LogHttp2Log" + +typedef struct OutputHttp2Ctx_ { + OutputJsonCtx *eve_ctx; +} OutputHttp2Ctx; + +typedef struct JsonHttp2LogThread_ { + OutputHttp2Ctx *http2log_ctx; + OutputJsonThreadCtx *ctx; +} JsonHttp2LogThread; + +static int JsonHttp2Logger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *txptr, uint64_t tx_id) +{ + JsonHttp2LogThread *aft = (JsonHttp2LogThread *)thread_data; + + if (unlikely(state == NULL)) { + return 0; + } + + JsonBuilder *js = CreateEveHeaderWithTxId( + p, LOG_DIR_FLOW, "http", NULL, tx_id, aft->http2log_ctx->eve_ctx); + if (unlikely(js == NULL)) + return 0; + + if (!rs_http2_log_json(txptr, js)) { + goto end; + } + OutputJsonBuilderBuffer(js, aft->ctx); +end: + jb_free(js); + return 0; +} + +static TmEcode JsonHttp2LogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + JsonHttp2LogThread *aft = SCCalloc(1, sizeof(JsonHttp2LogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogHTTP2. \"initdata\" argument NULL"); + goto error_exit; + } + + /* Use the Output Context (file pointer and mutex) */ + aft->http2log_ctx = ((OutputCtx *)initdata)->data; + aft->ctx = CreateEveThreadCtx(t, aft->http2log_ctx->eve_ctx); + if (!aft->ctx) { + goto error_exit; + } + + *data = (void *)aft; + return TM_ECODE_OK; + +error_exit: + SCFree(aft); + return TM_ECODE_FAILED; +} + +static TmEcode JsonHttp2LogThreadDeinit(ThreadVars *t, void *data) +{ + JsonHttp2LogThread *aft = (JsonHttp2LogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + FreeEveThreadCtx(aft->ctx); + /* clear memory */ + memset(aft, 0, sizeof(JsonHttp2LogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void OutputHttp2LogDeinitSub(OutputCtx *output_ctx) +{ + OutputHttp2Ctx *http2_ctx = output_ctx->data; + SCFree(http2_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputHttp2LogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ojc = parent_ctx->data; + + OutputHttp2Ctx *http2_ctx = SCCalloc(1, sizeof(OutputHttp2Ctx)); + if (unlikely(http2_ctx == NULL)) + return result; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(http2_ctx); + return result; + } + + http2_ctx->eve_ctx = ojc; + + output_ctx->data = http2_ctx; + output_ctx->DeInit = OutputHttp2LogDeinitSub; + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP2); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +void JsonHttp2LogRegister(void) +{ + /* also register as child of eve-log */ + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_TX, "eve-log", MODULE_NAME, "eve-log.http2", + OutputHttp2LogInitSub, ALPROTO_HTTP2, JsonHttp2Logger, HTTP2StateClosed, + HTTP2StateClosed, JsonHttp2LogThreadInit, JsonHttp2LogThreadDeinit, NULL); +} diff --git a/src/output-json-http2.h b/src/app-layer/http2/logger.h similarity index 100% rename from src/output-json-http2.h rename to src/app-layer/http2/logger.h diff --git a/src/app-layer/http2/parser.c b/src/app-layer/http2/parser.c new file mode 100644 index 000000000000..c4b299036b11 --- /dev/null +++ b/src/app-layer/http2/parser.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Philippe Antoine + * + * Parser for HTTP2, RFC 7540 + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http2/parser.h" +#include "rust.h" + +static int HTTP2RegisterPatternsForProtocolDetection(void) +{ + /* Using the 24 bytes pattern makes AppLayerTest09 fail/leak + * The complete pattern is "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + */ + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_HTTP2, "PRI * HTTP/2.0\r\n", 16, 0, STREAM_TOSERVER) < 0) { + return -1; + } + return 0; +} + +static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; +static SuricataFileContext sfc = { &sbcfg }; + +void RegisterHTTP2Parsers(void) +{ + const char *proto_name = "http2"; + + if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, true)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP2, proto_name); + if (HTTP2RegisterPatternsForProtocolDetection() < 0) + return; + + rs_http2_init(&sfc); + rs_http2_register_parser(); + } + +#ifdef UNITTESTS + // TODOask HTTP2ParserRegisterTests(); +#endif +} + +void HTTP2MimicHttp1Request(void *alstate_orig, void *h2s) +{ + htp_tx_t *h1tx = HtpGetTxForH2(alstate_orig); + if (h2s == NULL || h1tx == NULL) { + return; + } + if (h1tx->request_method == NULL) { + // may happen if we only got the reply, not the HTTP1 request + return; + } + // else + rs_http2_tx_set_method(h2s, bstr_ptr(h1tx->request_method), bstr_len(h1tx->request_method)); + if (h1tx->request_uri != NULL) { + // A request line without spaces gets interpreted as a request_method + // and has request_uri=NULL + rs_http2_tx_set_uri(h2s, bstr_ptr(h1tx->request_uri), bstr_len(h1tx->request_uri)); + } + size_t nbheaders = htp_table_size(h1tx->request_headers); + for (size_t i = 0; i < nbheaders; i++) { + htp_header_t *h = htp_table_get_index(h1tx->request_headers, i, NULL); + rs_http2_tx_add_header( + h2s, bstr_ptr(h->name), bstr_len(h->name), bstr_ptr(h->value), bstr_len(h->value)); + } +} diff --git a/src/app-layer-http2.h b/src/app-layer/http2/parser.h similarity index 100% rename from src/app-layer-http2.h rename to src/app-layer/http2/parser.h diff --git a/src/app-layer/ike/detect-chosen-sa.c b/src/app-layer/ike/detect-chosen-sa.c new file mode 100644 index 000000000000..40885e8b02bc --- /dev/null +++ b/src/app-layer/ike/detect-chosen-sa.c @@ -0,0 +1,275 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/ike/detect-chosen-sa.h" +#include "app-layer-parser.h" +#include "util/byte.h" +#include "util/unittest.h" + +#include "rust.h" + +/** + * [ike.chosen_sa_attribute]:=; + */ + +// support the basic attributes, which are parsed as integer and life_duration, if variable length +// is 4 it is stored as integer too +#define PARSE_REGEX \ + "^\\s*(alg_enc|alg_hash|alg_auth|alg_dh|\ +sa_group_type|sa_life_type|sa_life_duration|alg_prf|sa_key_length|sa_field_size)\ +\\s*=\\s*([0-9]+)\\s*$" + +static DetectParseRegex parse_regex; + +typedef struct { + char *sa_type; + uint32_t sa_value; +} DetectIkeChosenSaData; + +static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *); +static int DetectIkeChosenSaSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectIkeChosenSaFree(DetectEngineCtx *, void *); +static int g_ike_chosen_sa_buffer_id = 0; + +static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +void IKEChosenSaRegisterTests(void); + +/** + * \brief Registration function for ike.ChosenSa keyword. + */ +void DetectIkeChosenSaRegister(void) +{ + sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].name = "ike.chosen_sa_attribute"; + sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].desc = "match IKE chosen SA Attribute"; + sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].url = + "/rules/ike-keywords.html#ike-chosen_sa_attribute"; + sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].AppLayerTxMatch = DetectIkeChosenSaMatch; + sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].Setup = DetectIkeChosenSaSetup; + sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].Free = DetectIkeChosenSaFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].RegisterTests = IKEChosenSaRegisterTests; +#endif + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2("ike.chosen_sa_attribute", ALPROTO_IKE, SIG_FLAG_TOCLIENT, + 1, DetectEngineInspectGenericList, NULL); + + g_ike_chosen_sa_buffer_id = DetectBufferTypeGetByName("ike.chosen_sa_attribute"); +} + +/** + * \internal + * \brief Function to match SA attributes of a IKE state + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the Ike Transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectIkeChosenSaData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + const DetectIkeChosenSaData *dd = (const DetectIkeChosenSaData *)ctx; + + uint32_t value; + if (!rs_ike_state_get_sa_attribute(txv, dd->sa_type, &value)) + SCReturnInt(0); + if (value == dd->sa_value) + SCReturnInt(1); + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to parse options passed via ike.chosen_sa_attribute keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectIkeChosenSaData on success. + * \retval NULL on failure. + */ +static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *rawstr) +{ + /* + * idea: do not implement one c file per type, invent an own syntax: + * ike.chosen_sa_attribute:"encryption_algorithm=4" + * ike.chosen_sa_attribute:"hash_algorithm=8" + */ + DetectIkeChosenSaData *dd = NULL; + int res = 0; + size_t pcre2len; + char attribute[100]; + char value[100]; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); + if (ret < 3 || ret > 5) { + SCLogError( + "pcre match for ike.chosen_sa_attribute failed, should be: =, " + "but was: %s; error code %d", + rawstr, ret); + goto error; + } + + pcre2len = sizeof(attribute); + res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)attribute, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + + pcre2len = sizeof(value); + res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)value, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + + dd = SCCalloc(1, sizeof(DetectIkeChosenSaData)); + if (unlikely(dd == NULL)) + goto error; + + dd->sa_type = SCStrdup(attribute); + if (dd->sa_type == NULL) + goto error; + + if (ByteExtractStringUint32(&dd->sa_value, 10, strlen(value), value) <= 0) { + SCLogError("invalid input as arg " + "to ike.chosen_sa_attribute keyword"); + goto error; + } + + pcre2_match_data_free(match); + return dd; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (dd) { + if (dd->sa_type != NULL) + SCFree(dd->sa_type); + SCFree(dd); + } + return NULL; +} + +/** + * \brief Function to add the parsed IKE SA attribute query into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectIkeChosenSaSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) + return -1; + + DetectIkeChosenSaData *dd = DetectIkeChosenSaParse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_CHOSEN_SA, (SigMatchCtx *)dd, + g_ike_chosen_sa_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectIkeChosenSaFree(de_ctx, dd); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectIkeChosenSaData. + * + * \param de_ptr Pointer to DetectIkeChosenSaData. + */ +static void DetectIkeChosenSaFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectIkeChosenSaData *dd = (DetectIkeChosenSaData *)ptr; + if (dd == NULL) + return; + if (dd->sa_type != NULL) + SCFree(dd->sa_type); + + SCFree(ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS + +/** + * \test IKEChosenSaParserTest is a test for valid values + * + * \retval 1 on success + * \retval 0 on failure + */ +static int IKEChosenSaParserTest(void) +{ + DetectIkeChosenSaData *de = NULL; + de = DetectIkeChosenSaParse("alg_hash=2"); + + FAIL_IF_NULL(de); + FAIL_IF(de->sa_value != 2); + FAIL_IF(strcmp(de->sa_type, "alg_hash") != 0); + + DetectIkeChosenSaFree(NULL, de); + PASS; +} + +#endif /* UNITTESTS */ + +void IKEChosenSaRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("IKEChosenSaParserTest", IKEChosenSaParserTest); +#endif /* UNITTESTS */ +} diff --git a/src/detect-ike-chosen-sa.h b/src/app-layer/ike/detect-chosen-sa.h similarity index 100% rename from src/detect-ike-chosen-sa.h rename to src/app-layer/ike/detect-chosen-sa.h diff --git a/src/app-layer/ike/detect-exch-type.c b/src/app-layer/ike/detect-exch-type.c new file mode 100644 index 000000000000..a96b7e4fc57b --- /dev/null +++ b/src/app-layer/ike/detect-exch-type.c @@ -0,0 +1,139 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/ike/detect-exch-type.h" +#include "app-layer-parser.h" +#include "util/byte.h" +#include "detect-engine-uint.h" + +#include "rust-bindings.h" + +/** + * [ike.exchtype]:[<|>|<=|>=]; + */ + +static int DetectIkeExchTypeSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectIkeExchTypeFree(DetectEngineCtx *, void *); +static int g_ike_exch_type_buffer_id = 0; + +static int DetectIkeExchTypeMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +/** + * \brief Registration function for ike.exchtype keyword. + */ +void DetectIkeExchTypeRegister(void) +{ + sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].name = "ike.exchtype"; + sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].desc = "match IKE exchange type"; + sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].url = "/rules/ike-keywords.html#ike-exchtype"; + sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].Match = NULL; + sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].AppLayerTxMatch = DetectIkeExchTypeMatch; + sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].Setup = DetectIkeExchTypeSetup; + sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].Free = DetectIkeExchTypeFree; + + DetectAppLayerInspectEngineRegister2("ike.exchtype", ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("ike.exchtype", ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectGenericList, NULL); + + g_ike_exch_type_buffer_id = DetectBufferTypeGetByName("ike.exchtype"); +} + +/** + * \internal + * \brief Function to match exchange type of a IKE state + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the Ike Transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectU8Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectIkeExchTypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + uint8_t exch_type; + if (!rs_ike_state_get_exch_type(txv, &exch_type)) + SCReturnInt(0); + + const DetectU8Data *du8 = (const DetectU8Data *)ctx; + SCReturnInt(DetectU8Match(exch_type, du8)); +} + +/** + * \brief Function to add the parsed IKE exchange type field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectIkeExchTypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) + return -1; + + DetectU8Data *ike_exch_type = DetectU8Parse(rawstr); + if (ike_exch_type == NULL) + return -1; + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_EXCH_TYPE, (SigMatchCtx *)ike_exch_type, + g_ike_exch_type_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectIkeExchTypeFree(de_ctx, ike_exch_type); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectU8Data. + * + * \param de_ptr Pointer to DetectU8Data. + */ +static void DetectIkeExchTypeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u8_free(ptr); +} diff --git a/src/detect-ike-exch-type.h b/src/app-layer/ike/detect-exch-type.h similarity index 100% rename from src/detect-ike-exch-type.h rename to src/app-layer/ike/detect-exch-type.h diff --git a/src/app-layer/ike/detect-key-exchange-payload-length.c b/src/app-layer/ike/detect-key-exchange-payload-length.c new file mode 100644 index 000000000000..9e236f8d385f --- /dev/null +++ b/src/app-layer/ike/detect-key-exchange-payload-length.c @@ -0,0 +1,146 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/ike/detect-key-exchange-payload-length.h" +#include "app-layer-parser.h" +#include "util/byte.h" +#include "detect-engine-uint.h" + +#include "rust-bindings.h" + +/** + * [ike.key_exchange_payload_length]:[=|<|>|<=|>=]; + */ +static int DetectIkeKeyExchangePayloadLengthSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectIkeKeyExchangePayloadLengthFree(DetectEngineCtx *, void *); +static int g_ike_key_exch_payload_length_buffer_id = 0; + +static int DetectIkeKeyExchangePayloadLengthMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, + void *, const Signature *, const SigMatchCtx *); + +/** + * \brief Registration function for ike.key_exchange_payload_length keyword. + */ +void DetectIkeKeyExchangePayloadLengthRegister(void) +{ + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].name = + "ike.key_exchange_payload_length"; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].desc = + "match IKE key exchange payload length"; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].url = + "/rules/ike-keywords.html#ike-key-exchange-payload-length"; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].AppLayerTxMatch = + DetectIkeKeyExchangePayloadLengthMatch; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].Setup = + DetectIkeKeyExchangePayloadLengthSetup; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].Free = + DetectIkeKeyExchangePayloadLengthFree; + + DetectAppLayerInspectEngineRegister2("ike.key_exchange_payload_length", ALPROTO_IKE, + SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("ike.key_exchange_payload_length", ALPROTO_IKE, + SIG_FLAG_TOCLIENT, 1, DetectEngineInspectGenericList, NULL); + + g_ike_key_exch_payload_length_buffer_id = + DetectBufferTypeGetByName("ike.key_exchange_payload_length"); +} + +/** + * \internal + * \brief Function to match key exchange payload length of a IKE state + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the Ike Transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectIkeKeyExchangePayloadLengthMatch(DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + uint32_t length; + if (!rs_ike_state_get_key_exchange_payload_length(txv, &length)) + SCReturnInt(0); + const DetectU32Data *du32 = (const DetectU32Data *)ctx; + return DetectU32Match(length, du32); +} + +/** + * \brief Function to add the parsed IKE key exchange payload length query into the current + * signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectIkeKeyExchangePayloadLengthSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) + return -1; + + DetectU32Data *key_exchange_payload_length = DetectU32Parse(rawstr); + if (key_exchange_payload_length == NULL) + return -1; + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH, + (SigMatchCtx *)key_exchange_payload_length, + g_ike_key_exch_payload_length_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectIkeKeyExchangePayloadLengthFree(de_ctx, key_exchange_payload_length); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectU32Data. + * + * \param de_ptr Pointer to DetectU32Data. + */ +static void DetectIkeKeyExchangePayloadLengthFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} diff --git a/src/detect-ike-key-exchange-payload-length.h b/src/app-layer/ike/detect-key-exchange-payload-length.h similarity index 100% rename from src/detect-ike-key-exchange-payload-length.h rename to src/app-layer/ike/detect-key-exchange-payload-length.h diff --git a/src/app-layer/ike/detect-key-exchange-payload.c b/src/app-layer/ike/detect-key-exchange-payload.c new file mode 100644 index 000000000000..38fe628450d5 --- /dev/null +++ b/src/app-layer/ike/detect-key-exchange-payload.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ike/detect-key-exchange-payload.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/ike/parser.h" +#include "rust-bindings.h" + +#define KEYWORD_NAME_KEY_EXCHANGE "ike.key_exchange_payload" +#define KEYWORD_DOC_KEY_EXCHANGE "ike-keywords.html#ike-key_exchange_payload"; +#define BUFFER_NAME_KEY_EXCHANGE "ike.key_exchange_payload" +#define BUFFER_DESC_KEY_EXCHANGE "ike key_exchange payload" + +static int g_buffer_key_exchange_id = 0; + +static int DetectKeyExchangeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_key_exchange_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetKeyExchangeData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_ike_state_get_key_exchange(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectIkeKeyExchangeRegister(void) +{ + // register key_exchange + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].name = KEYWORD_NAME_KEY_EXCHANGE; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].url = + "/rules/" KEYWORD_DOC_KEY_EXCHANGE sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].desc = + "sticky buffer to match on the IKE key_exchange_payload"; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].Setup = DetectKeyExchangeSetup; + sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME_KEY_EXCHANGE, ALPROTO_IKE, SIG_FLAG_TOSERVER, + 1, DetectEngineInspectBufferGeneric, GetKeyExchangeData); + + DetectAppLayerMpmRegister2(BUFFER_NAME_KEY_EXCHANGE, SIG_FLAG_TOSERVER, 1, + PrefilterGenericMpmRegister, GetKeyExchangeData, ALPROTO_IKE, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME_KEY_EXCHANGE, ALPROTO_IKE, SIG_FLAG_TOCLIENT, + 1, DetectEngineInspectBufferGeneric, GetKeyExchangeData); + + DetectAppLayerMpmRegister2(BUFFER_NAME_KEY_EXCHANGE, SIG_FLAG_TOCLIENT, 1, + PrefilterGenericMpmRegister, GetKeyExchangeData, ALPROTO_IKE, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME_KEY_EXCHANGE, BUFFER_DESC_KEY_EXCHANGE); + + g_buffer_key_exchange_id = DetectBufferTypeGetByName(BUFFER_NAME_KEY_EXCHANGE); + SCLogDebug("registering " BUFFER_NAME_KEY_EXCHANGE " rule option"); +} diff --git a/src/detect-ike-key-exchange-payload.h b/src/app-layer/ike/detect-key-exchange-payload.h similarity index 100% rename from src/detect-ike-key-exchange-payload.h rename to src/app-layer/ike/detect-key-exchange-payload.h diff --git a/src/app-layer/ike/detect-nonce-payload-length.c b/src/app-layer/ike/detect-nonce-payload-length.c new file mode 100644 index 000000000000..7f3aa8c0301f --- /dev/null +++ b/src/app-layer/ike/detect-nonce-payload-length.c @@ -0,0 +1,140 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/ike/detect-nonce-payload-length.h" +#include "app-layer-parser.h" +#include "util/byte.h" +#include "detect-engine-uint.h" + +#include "rust-bindings.h" + +/** + * [ike.nonce_payload_length]:[=|<|>|<=|>=]; + */ +static int DetectIkeNoncePayloadLengthSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectIkeNoncePayloadLengthFree(DetectEngineCtx *, void *); +static int g_ike_nonce_payload_length_buffer_id = 0; + +static int DetectIkeNoncePayloadLengthMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, + void *, const Signature *, const SigMatchCtx *); + +/** + * \brief Registration function for ike.nonce_payload_length keyword. + */ +void DetectIkeNoncePayloadLengthRegister(void) +{ + sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].name = "ike.nonce_payload_length"; + sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].desc = "match IKE nonce payload length"; + sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].url = + "/rules/ike-keywords.html#ike-nonce-payload-length"; + sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].AppLayerTxMatch = + DetectIkeNoncePayloadLengthMatch; + sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].Setup = DetectIkeNoncePayloadLengthSetup; + sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].Free = DetectIkeNoncePayloadLengthFree; + + DetectAppLayerInspectEngineRegister2("ike.nonce_payload_length", ALPROTO_IKE, SIG_FLAG_TOSERVER, + 1, DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("ike.nonce_payload_length", ALPROTO_IKE, SIG_FLAG_TOCLIENT, + 1, DetectEngineInspectGenericList, NULL); + + g_ike_nonce_payload_length_buffer_id = DetectBufferTypeGetByName("ike.nonce_payload_length"); +} + +/** + * \internal + * \brief Function to match nonce length of a IKE state + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the Ike Transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectIkeNoncePayloadLengthMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + uint32_t length; + if (!rs_ike_state_get_nonce_payload_length(txv, &length)) + SCReturnInt(0); + const DetectU32Data *du32 = (const DetectU32Data *)ctx; + return DetectU32Match(length, du32); +} + +/** + * \brief Function to add the parsed IKE nonce length field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectIkeNoncePayloadLengthSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) + return -1; + + DetectU32Data *nonce_payload_length = DetectU32Parse(rawstr); + if (nonce_payload_length == NULL) + return -1; + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH, + (SigMatchCtx *)nonce_payload_length, + g_ike_nonce_payload_length_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectIkeNoncePayloadLengthFree(de_ctx, nonce_payload_length); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectU32Data. + * + * \param de_ptr Pointer to DetectU32Data. + */ +static void DetectIkeNoncePayloadLengthFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} diff --git a/src/detect-ike-nonce-payload-length.h b/src/app-layer/ike/detect-nonce-payload-length.h similarity index 100% rename from src/detect-ike-nonce-payload-length.h rename to src/app-layer/ike/detect-nonce-payload-length.h diff --git a/src/app-layer/ike/detect-nonce-payload.c b/src/app-layer/ike/detect-nonce-payload.c new file mode 100644 index 000000000000..4e4ba9d989a5 --- /dev/null +++ b/src/app-layer/ike/detect-nonce-payload.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ike/detect-nonce-payload.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/ike/parser.h" +#include "rust-bindings.h" + +#define KEYWORD_NAME_NONCE "ike.nonce_payload" +#define KEYWORD_DOC_NONCE "ike-keywords.html#ike-nonce_payload"; +#define BUFFER_NAME_NONCE "ike.nonce_payload" +#define BUFFER_DESC_NONCE "ike nonce payload" + +static int g_buffer_nonce_id = 0; + +static int DetectNonceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_nonce_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetNonceData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_ike_state_get_nonce(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectIkeNonceRegister(void) +{ + // register nonce + sigmatch_table[DETECT_AL_IKE_NONCE].name = KEYWORD_NAME_NONCE; + sigmatch_table[DETECT_AL_IKE_NONCE].url = + "/rules/" KEYWORD_DOC_NONCE sigmatch_table[DETECT_AL_IKE_NONCE].desc = + "sticky buffer to match on the IKE nonce_payload"; + sigmatch_table[DETECT_AL_IKE_NONCE].Setup = DetectNonceSetup; + sigmatch_table[DETECT_AL_IKE_NONCE].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME_NONCE, ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, GetNonceData); + + DetectAppLayerMpmRegister2(BUFFER_NAME_NONCE, SIG_FLAG_TOSERVER, 1, PrefilterGenericMpmRegister, + GetNonceData, ALPROTO_IKE, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME_NONCE, ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, GetNonceData); + + DetectAppLayerMpmRegister2(BUFFER_NAME_NONCE, SIG_FLAG_TOCLIENT, 1, PrefilterGenericMpmRegister, + GetNonceData, ALPROTO_IKE, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME_NONCE, BUFFER_DESC_NONCE); + + g_buffer_nonce_id = DetectBufferTypeGetByName(BUFFER_NAME_NONCE); + SCLogDebug("registering " BUFFER_NAME_NONCE " rule option"); +} diff --git a/src/detect-ike-nonce-payload.h b/src/app-layer/ike/detect-nonce-payload.h similarity index 100% rename from src/detect-ike-nonce-payload.h rename to src/app-layer/ike/detect-nonce-payload.h diff --git a/src/app-layer/ike/detect-spi.c b/src/app-layer/ike/detect-spi.c new file mode 100644 index 000000000000..fb82a4813bbc --- /dev/null +++ b/src/app-layer/ike/detect-spi.c @@ -0,0 +1,171 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ike/detect-spi.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/ike/parser.h" +#include "rust-bindings.h" + +#define KEYWORD_NAME_INITIATOR "ike.init_spi" +#define KEYWORD_DOC_INITIATOR "ike-keywords.html#ike-init_spi"; +#define BUFFER_NAME_INITIATOR "ike.init_spi" +#define BUFFER_DESC_INITIATOR "ike init spi" + +#define KEYWORD_NAME_RESPONDER "ike.resp_spi" +#define KEYWORD_DOC_RESPONDER "ike-keywords.html#ike-resp_spi"; +#define BUFFER_NAME_RESPONDER "ike.resp_spi" +#define BUFFER_DESC_RESPONDER "ike resp spi" + +static int g_buffer_initiator_id = 0; +static int g_buffer_responder_id = 0; + +static int DetectSpiInitiatorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_initiator_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) + return -1; + + return 0; +} + +static int DetectSpiResponderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_responder_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetInitiatorData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_ike_state_get_spi_initiator(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetResponderData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_ike_state_get_spi_responder(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectIkeSpiRegister(void) +{ + // register initiator + sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].name = KEYWORD_NAME_INITIATOR; + sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].url = + "/rules/" KEYWORD_DOC_INITIATOR sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].desc = + "sticky buffer to match on the IKE spi initiator"; + sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].Setup = DetectSpiInitiatorSetup; + sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME_INITIATOR, ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, GetInitiatorData); + + DetectAppLayerMpmRegister2(BUFFER_NAME_INITIATOR, SIG_FLAG_TOSERVER, 1, + PrefilterGenericMpmRegister, GetInitiatorData, ALPROTO_IKE, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME_INITIATOR, BUFFER_DESC_INITIATOR); + + g_buffer_initiator_id = DetectBufferTypeGetByName(BUFFER_NAME_INITIATOR); + SCLogDebug("registering " BUFFER_NAME_INITIATOR " rule option"); + + // register responder + sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].name = KEYWORD_NAME_RESPONDER; + sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].url = + "/rules/" KEYWORD_DOC_RESPONDER sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].desc = + "sticky buffer to match on the IKE spi responder"; + sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].Setup = DetectSpiResponderSetup; + sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME_RESPONDER, ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, GetResponderData); + + DetectAppLayerMpmRegister2(BUFFER_NAME_RESPONDER, SIG_FLAG_TOCLIENT, 1, + PrefilterGenericMpmRegister, GetResponderData, ALPROTO_IKE, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME_RESPONDER, BUFFER_DESC_RESPONDER); + + g_buffer_responder_id = DetectBufferTypeGetByName(BUFFER_NAME_RESPONDER); + SCLogDebug("registering " BUFFER_NAME_RESPONDER " rule option"); +} diff --git a/src/detect-ike-spi.h b/src/app-layer/ike/detect-spi.h similarity index 100% rename from src/detect-ike-spi.h rename to src/app-layer/ike/detect-spi.h diff --git a/src/app-layer/ike/detect-vendor.c b/src/app-layer/ike/detect-vendor.c new file mode 100644 index 000000000000..6239d253e780 --- /dev/null +++ b/src/app-layer/ike/detect-vendor.c @@ -0,0 +1,210 @@ +/* Copyright (C) 2020-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Frank Honza + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-mpm.h" +#include "app-layer/ike/detect-vendor.h" +#include "app-layer-parser.h" +#include "util/byte.h" + +#include "rust-bindings.h" +#include "util/profiling.h" + +static int DetectIkeVendorSetup(DetectEngineCtx *, Signature *, const char *); + +typedef struct { + char *vendor; +} DetectIkeVendorData; + +struct IkeVendorGetDataArgs { + uint32_t local_id; + void *txv; +}; + +typedef struct PrefilterMpmIkeVendor { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmIkeVendor; + +static int g_ike_vendor_buffer_id = 0; + +static InspectionBuffer *IkeVendorGetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, struct IkeVendorGetDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + const uint8_t *data; + uint32_t data_len; + if (rs_ike_tx_get_vendor(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +/** \brief IkeVendor Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxIkeVendor(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmIkeVendor *ctx = (const PrefilterMpmIkeVendor *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + while (1) { + struct IkeVendorGetDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = IkeVendorGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + local_id++; + } + + SCReturn; +} + +static void PrefilterMpmIkeVendorFree(void *ptr) +{ + if (ptr != NULL) + SCFree(ptr); +} + +static int PrefilterMpmIkeVendorRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmIkeVendor *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxIkeVendor, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmIkeVendorFree, mpm_reg->pname); +} + +static uint8_t DetectEngineInspectIkeVendor(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct IkeVendorGetDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + IkeVendorGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +/** + * \brief Registration function for ike.vendor keyword. + */ +void DetectIkeVendorRegister(void) +{ + sigmatch_table[DETECT_AL_IKE_VENDOR].name = "ike.vendor"; + sigmatch_table[DETECT_AL_IKE_VENDOR].desc = "match IKE Vendor"; + sigmatch_table[DETECT_AL_IKE_VENDOR].url = "/rules/ike-keywords.html#ike-vendor"; + sigmatch_table[DETECT_AL_IKE_VENDOR].Setup = DetectIkeVendorSetup; + sigmatch_table[DETECT_AL_IKE_VENDOR].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_IKE_VENDOR].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerMpmRegister2("ike.vendor", SIG_FLAG_TOSERVER, 1, PrefilterMpmIkeVendorRegister, + NULL, ALPROTO_IKE, 1); + + DetectAppLayerInspectEngineRegister2( + "ike.vendor", ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, DetectEngineInspectIkeVendor, NULL); + + g_ike_vendor_buffer_id = DetectBufferTypeGetByName("ike.vendor"); + + DetectBufferTypeSupportsMultiInstance("ike.vendor"); +} + +/** + * \brief setup the sticky buffer keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectIkeVendorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_ike_vendor_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) + return -1; + return 0; +} diff --git a/src/detect-ike-vendor.h b/src/app-layer/ike/detect-vendor.h similarity index 100% rename from src/detect-ike-vendor.h rename to src/app-layer/ike/detect-vendor.h diff --git a/src/app-layer/ike/logger.c b/src/app-layer/ike/logger.c new file mode 100644 index 000000000000..131e3376df03 --- /dev/null +++ b/src/app-layer/ike/logger.c @@ -0,0 +1,188 @@ +/* Copyright (C) 2018-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * \author Frank Honza + * + * Implement JSON/eve logging app-layer IKE. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ike/parser.h" +#include "app-layer/ike/logger.h" + +#include "rust.h" + +#define LOG_IKE_DEFAULT 0 +#define LOG_IKE_EXTENDED (1 << 0) + +typedef struct LogIKEFileCtx_ { + uint32_t flags; + OutputJsonCtx *eve_ctx; +} LogIKEFileCtx; + +typedef struct LogIKELogThread_ { + LogIKEFileCtx *ikelog_ctx; + OutputJsonThreadCtx *ctx; +} LogIKELogThread; + +bool EveIKEAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) +{ + IKEState *state = FlowGetAppState(f); + if (state) { + IKETransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_IKE, state, tx_id); + if (tx) { + return rs_ike_logger_log(state, tx, LOG_IKE_EXTENDED, js); + } + } + + return false; +} + +static int JsonIKELogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + LogIKELogThread *thread = thread_data; + JsonBuilder *jb = + CreateEveHeader((Packet *)p, LOG_DIR_PACKET, "ike", NULL, thread->ikelog_ctx->eve_ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_FAILED; + } + + LogIKEFileCtx *ike_ctx = thread->ikelog_ctx; + if (!rs_ike_logger_log(state, tx, ike_ctx->flags, jb)) { + goto error; + } + + OutputJsonBuilderBuffer(jb, thread->ctx); + + jb_free(jb); + return TM_ECODE_OK; + +error: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static void OutputIKELogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogIKEFileCtx *ikelog_ctx = (LogIKEFileCtx *)output_ctx->data; + SCFree(ikelog_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputIKELogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ajt = parent_ctx->data; + + LogIKEFileCtx *ikelog_ctx = SCCalloc(1, sizeof(*ikelog_ctx)); + if (unlikely(ikelog_ctx == NULL)) { + return result; + } + ikelog_ctx->eve_ctx = ajt; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(ikelog_ctx); + return result; + } + + ikelog_ctx->flags = LOG_IKE_DEFAULT; + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + if (extended) { + if (ConfValIsTrue(extended)) { + ikelog_ctx->flags = LOG_IKE_EXTENDED; + } + } + + output_ctx->data = ikelog_ctx; + output_ctx->DeInit = OutputIKELogDeInitCtxSub; + + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_IKE); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonIKELogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogIKELogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogIKE. \"initdata\" is NULL."); + goto error_exit; + } + + thread->ikelog_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->ikelog_ctx->eve_ctx); + if (!thread->ctx) { + goto error_exit; + } + + *data = (void *)thread; + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonIKELogThreadDeinit(ThreadVars *t, void *data) +{ + LogIKELogThread *thread = (LogIKELogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonIKELogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonIKELog", "eve-log.ike", + OutputIKELogInitSub, ALPROTO_IKE, JsonIKELogger, JsonIKELogThreadInit, + JsonIKELogThreadDeinit, NULL); +} diff --git a/src/output-json-ike.h b/src/app-layer/ike/logger.h similarity index 100% rename from src/output-json-ike.h rename to src/app-layer/ike/logger.h diff --git a/src/app-layer/ike/parser.c b/src/app-layer/ike/parser.c new file mode 100644 index 000000000000..cc38318f668c --- /dev/null +++ b/src/app-layer/ike/parser.c @@ -0,0 +1,189 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * \author Frank Honza + * + * IKE application layer detector and parser. + * + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/ike/parser.h" +#include "rust.h" + +void RegisterIKEParsers(void) +{ + rs_ike_register_parser(); +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_IKE, IKEParserRegisterTests); +#endif +} + +#ifdef UNITTESTS +#include "stream-tcp.h" +#include "util/unittest-helper.h" +#include "flow-util.h" + +static int IkeParserTest(void) +{ + uint64_t ret[4]; + + Flow f; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_UDP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_IKE; + + StreamTcpInitConfig(true); + + static const unsigned char initiator_sa[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0d, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x07, 0x80, 0x0e, 0x00, 0x80, 0x80, 0x02, 0x00, 0x02, + 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01, 0x80, 0x0b, 0x00, 0x01, 0x00, 0x0c, 0x00, + 0x04, 0x00, 0x01, 0x51, 0x80, 0x0d, 0x00, 0x00, 0x14, 0x4a, 0x13, 0x1c, 0x81, 0x07, 0x03, + 0x58, 0x45, 0x5c, 0x57, 0x28, 0xf2, 0x0e, 0x95, 0x45, 0x2f, 0x0d, 0x00, 0x00, 0x14, 0x43, + 0x9b, 0x59, 0xf8, 0xba, 0x67, 0x6c, 0x4c, 0x77, 0x37, 0xae, 0x22, 0xea, 0xb8, 0xf5, 0x82, + 0x0d, 0x00, 0x00, 0x14, 0x7d, 0x94, 0x19, 0xa6, 0x53, 0x10, 0xca, 0x6f, 0x2c, 0x17, 0x9d, + 0x92, 0x15, 0x52, 0x9d, 0x56, 0x00, 0x00, 0x00, 0x14, 0x90, 0xcb, 0x80, 0x91, 0x3e, 0xbb, + 0x69, 0x6e, 0x08, 0x63, 0x81, 0xb5, 0xec, 0x42, 0x7b, 0x1f }; + + // the initiator sending the security association with proposals + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOSERVER | STREAM_START, + (uint8_t *)initiator_sa, sizeof(initiator_sa)); + FAIL_IF_NOT(r == 0); + + static const unsigned char responder_sa[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, + 0xa0, 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x01, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x0d, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x07, 0x80, 0x0e, 0x00, 0x80, 0x80, 0x02, 0x00, 0x02, + 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01, 0x80, 0x0b, 0x00, 0x01, 0x00, 0x0c, 0x00, + 0x04, 0x00, 0x01, 0x51, 0x80, 0x00, 0x00, 0x00, 0x14, 0x4a, 0x13, 0x1c, 0x81, 0x07, 0x03, + 0x58, 0x45, 0x5c, 0x57, 0x28, 0xf2, 0x0e, 0x95, 0x45, 0x2f }; + + // responder answering with chosen proposal + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOCLIENT, + (uint8_t *)responder_sa, sizeof(responder_sa)); + FAIL_IF_NOT(r == 0); + + static const unsigned char initiator_key[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, + 0xa0, 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x04, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x1c, 0x0a, 0x00, 0x00, 0x84, 0x35, 0x04, 0xd3, 0xd2, 0xed, 0x14, + 0xe0, 0xca, 0x03, 0xb8, 0x51, 0xa5, 0x1a, 0x9d, 0xa2, 0xe5, 0xa4, 0xc1, 0x4c, 0x1d, 0x7e, + 0xc3, 0xe1, 0xfb, 0xe9, 0x50, 0x02, 0x54, 0x24, 0x51, 0x4b, 0x3c, 0x69, 0xed, 0x7f, 0xbb, + 0x44, 0xe0, 0x92, 0x25, 0xda, 0x52, 0xd2, 0xa9, 0x26, 0x04, 0xa9, 0x9b, 0xf6, 0x1b, 0x7b, + 0xee, 0xd7, 0xfb, 0xfa, 0x63, 0x5e, 0x82, 0xf0, 0x65, 0xf4, 0xfe, 0x78, 0x07, 0x51, 0x35, + 0x4d, 0xbe, 0x47, 0x4c, 0x3d, 0xe7, 0x20, 0x7d, 0xcf, 0x69, 0xfd, 0xbb, 0xed, 0x32, 0xc1, + 0x69, 0x1c, 0xc1, 0x49, 0xb3, 0x18, 0xee, 0xe0, 0x03, 0x70, 0xe6, 0x5f, 0xc3, 0x06, 0x9b, + 0xba, 0xcf, 0xb0, 0x13, 0x46, 0x71, 0x73, 0x96, 0x6e, 0x9d, 0x5f, 0x4b, 0xc4, 0xf3, 0x85, + 0x7e, 0x35, 0x9b, 0xba, 0x3a, 0xdb, 0xb6, 0xef, 0xee, 0xa5, 0x16, 0xf3, 0x89, 0x7d, 0x85, + 0x34, 0xf3, 0x0d, 0x00, 0x00, 0x18, 0x89, 0xd7, 0xc8, 0xfb, 0xf9, 0x4b, 0x51, 0x5b, 0x52, + 0x1d, 0x5d, 0x95, 0x89, 0xc2, 0x60, 0x20, 0x21, 0xe1, 0xa7, 0x09, 0x0d, 0x00, 0x00, 0x14, + 0xaf, 0xca, 0xd7, 0x13, 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, + 0x00, 0x0d, 0x00, 0x00, 0x14, 0x11, 0xbd, 0xfe, 0x02, 0xd0, 0x56, 0x58, 0x7f, 0x2c, 0x18, + 0x12, 0x59, 0x72, 0xc3, 0x24, 0x01, 0x14, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89, 0xdf, + 0xd6, 0xb7, 0x12, 0x14, 0x00, 0x00, 0x18, 0x15, 0x74, 0xd6, 0x4c, 0x01, 0x65, 0xba, 0xd1, + 0x6a, 0x02, 0x3f, 0x03, 0x8d, 0x45, 0xa0, 0x74, 0x98, 0xd8, 0xd0, 0x51, 0x00, 0x00, 0x00, + 0x18, 0xfe, 0xbf, 0x46, 0x2f, 0x1c, 0xd7, 0x58, 0x05, 0xa7, 0xba, 0xa2, 0x87, 0x47, 0xe7, + 0x69, 0xd6, 0x74, 0xf8, 0x56, 0x00 }; + + // the initiator sending key exchange + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOSERVER, + (uint8_t *)initiator_key, sizeof(initiator_key)); + FAIL_IF_NOT(r == 0); + + static const unsigned char responder_key[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, + 0xa0, 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x04, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x30, 0x0a, 0x00, 0x00, 0x84, 0x6d, 0x02, 0x6d, 0x56, 0x16, 0xc4, + 0x5b, 0xe0, 0x5e, 0x5b, 0x89, 0x84, 0x11, 0xe9, 0xf9, 0x5d, 0x19, 0x5c, 0xea, 0x00, 0x9a, + 0xd2, 0x2c, 0x62, 0xbe, 0xf0, 0x6c, 0x57, 0x1b, 0x7c, 0xfb, 0xc4, 0x79, 0x2f, 0x45, 0x56, + 0x4e, 0xc7, 0x10, 0xac, 0x58, 0x4a, 0xa1, 0x8d, 0x20, 0xcb, 0xc8, 0xf5, 0xf8, 0x91, 0x06, + 0x66, 0xb8, 0x9e, 0x4e, 0xe2, 0xf9, 0x5a, 0xbc, 0x02, 0x30, 0xe2, 0xcb, 0xa1, 0xb8, 0x8a, + 0xc4, 0xbb, 0xa7, 0xfc, 0xc8, 0x18, 0xa9, 0x86, 0xc0, 0x1a, 0x4c, 0xa8, 0x65, 0xa5, 0xeb, + 0x82, 0x88, 0x4d, 0xbe, 0xc8, 0x5b, 0xfd, 0x7d, 0x1a, 0x30, 0x3b, 0x09, 0x89, 0x4d, 0xcf, + 0x2e, 0x37, 0x85, 0xfd, 0x79, 0xdb, 0xa2, 0x25, 0x37, 0x7c, 0xf8, 0xcc, 0xa0, 0x09, 0xce, + 0xff, 0xbb, 0x6a, 0xa3, 0x8b, 0x64, 0x8c, 0x4b, 0x05, 0x40, 0x4f, 0x1c, 0xfa, 0xac, 0x36, + 0x1a, 0xff, 0x0d, 0x00, 0x00, 0x18, 0x15, 0xb6, 0x88, 0x42, 0x1e, 0xd5, 0xc3, 0xdd, 0x92, + 0xd3, 0xb8, 0x6e, 0x47, 0xa7, 0x6f, 0x0d, 0x39, 0xcc, 0x09, 0xe0, 0x0d, 0x00, 0x00, 0x14, + 0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2, 0x74, 0xcc, 0x01, + 0x00, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13, 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, + 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x14, 0x55, 0xcc, 0x29, 0xed, 0x90, + 0x2a, 0xb8, 0xec, 0x53, 0xb1, 0xdf, 0x86, 0x7c, 0x61, 0x09, 0x29, 0x14, 0x00, 0x00, 0x0c, + 0x09, 0x00, 0x26, 0x89, 0xdf, 0xd6, 0xb7, 0x12, 0x14, 0x00, 0x00, 0x18, 0xfe, 0xbf, 0x46, + 0x2f, 0x1c, 0xd7, 0x58, 0x05, 0xa7, 0xba, 0xa2, 0x87, 0x47, 0xe7, 0x69, 0xd6, 0x74, 0xf8, + 0x56, 0x00, 0x00, 0x00, 0x00, 0x18, 0x15, 0x74, 0xd6, 0x4c, 0x01, 0x65, 0xba, 0xd1, 0x6a, + 0x02, 0x3f, 0x03, 0x8d, 0x45, 0xa0, 0x74, 0x98, 0xd8, 0xd0, 0x51 }; + + // responder sending key exchange + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOCLIENT, + (uint8_t *)responder_key, sizeof(responder_key)); + FAIL_IF_NOT(r == 0); + + static const unsigned char encrypted[] = { 0xe4, 0x7a, 0x59, 0x1f, 0xd0, 0x57, 0x58, 0x7f, 0xa0, + 0x0b, 0x8e, 0xf0, 0x90, 0x2b, 0xb8, 0xec, 0x05, 0x10, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0xa4, 0x85, 0xa5, 0xd5, 0x86, 0x8a, 0x3c, 0x92, 0x5d, 0xed, 0xf2, + 0xd1, 0x0d, 0x5e, 0x47, 0x11, 0x2b, 0xc2, 0x94, 0x60, 0x18, 0xc7, 0x61, 0x28, 0xed, 0x7b, + 0xb2, 0x9d, 0xb0, 0x61, 0xfd, 0xab, 0xf7, 0x9a, 0x18, 0xe7, 0x56, 0x89, 0x53, 0x6d, 0x27, + 0xcb, 0xe0, 0x92, 0x1d, 0x67, 0xf7, 0x02, 0xf3, 0x47, 0xae, 0x6e, 0x79, 0xde, 0xe1, 0x09, + 0x4d, 0xc8, 0x6a, 0x5a, 0x26, 0x44, 0x8a, 0xde, 0x72, 0x83, 0x06, 0x94, 0xe1, 0x5d, 0xca, + 0x2d, 0x96, 0x03, 0xeb, 0xc5, 0xf7, 0x90, 0x47, 0x3d }; + // the initiator sending encrypted data + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_IKE, STREAM_TOSERVER, (uint8_t *)encrypted, + sizeof(encrypted)); + FAIL_IF_NOT(r == 0); + + AppLayerParserTransactionsCleanup(&f, STREAM_TOCLIENT); + UTHAppLayerParserStateGetIds(f.alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 5); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 5); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 5); // log_id + FAIL_IF_NOT(ret[3] == 5); // min_id + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} +#endif + +void IKEParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("IkeParserTest", IkeParserTest); +#endif +} diff --git a/src/app-layer-ike.h b/src/app-layer/ike/parser.h similarity index 100% rename from src/app-layer-ike.h rename to src/app-layer/ike/parser.h diff --git a/src/app-layer/krb5/detect-cname.c b/src/app-layer/krb5/detect-cname.c new file mode 100644 index 000000000000..e1b3a3fdf641 --- /dev/null +++ b/src/app-layer/krb5/detect-cname.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2018-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#include "suricata-common.h" +#include "util/unittest.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer/krb5/detect-cname.h" + +#include "rust.h" +#include "app-layer/krb5/parser.h" +#include "util/profiling.h" + +static int g_krb5_cname_buffer_id = 0; + +struct Krb5PrincipalNameDataArgs { + uint32_t local_id; /**< used as index into thread inspect array */ + void *txv; +}; + +static int DetectKrb5CNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_krb5_cname_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetKrb5CNameData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, + const struct Krb5PrincipalNameDataArgs *cbdata, int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_krb5_tx_get_cname(cbdata->txv, cbdata->local_id, &b, &b_len) != 1) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + if (b == NULL || b_len == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, b, b_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectKrb5CName(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct Krb5PrincipalNameDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + GetKrb5CNameData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmKrb5Name { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmKrb5Name; + +/** \brief Krb5CName Krb5CName Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxKrb5CName(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmKrb5Name *ctx = (const PrefilterMpmKrb5Name *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + + while (1) { + // loop until we get a NULL + + struct Krb5PrincipalNameDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = GetKrb5CNameData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static void PrefilterMpmKrb5NameFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmKrb5CNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmKrb5Name *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxKrb5CName, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmKrb5NameFree, mpm_reg->name); +} + +void DetectKrb5CNameRegister(void) +{ + sigmatch_table[DETECT_AL_KRB5_CNAME].name = "krb5.cname"; + sigmatch_table[DETECT_AL_KRB5_CNAME].alias = "krb5_cname"; + sigmatch_table[DETECT_AL_KRB5_CNAME].url = "/rules/kerberos-keywords.html#krb5-cname"; + sigmatch_table[DETECT_AL_KRB5_CNAME].Setup = DetectKrb5CNameSetup; + sigmatch_table[DETECT_AL_KRB5_CNAME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[DETECT_AL_KRB5_CNAME].desc = "sticky buffer to match on Kerberos 5 client name"; + + DetectAppLayerMpmRegister2("krb5_cname", SIG_FLAG_TOCLIENT, 2, PrefilterMpmKrb5CNameRegister, + NULL, ALPROTO_KRB5, 1); + + DetectAppLayerInspectEngineRegister2( + "krb5_cname", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectKrb5CName, NULL); + + DetectBufferTypeSetDescriptionByName("krb5_cname", "Kerberos 5 ticket client name"); + + g_krb5_cname_buffer_id = DetectBufferTypeGetByName("krb5_cname"); + + DetectBufferTypeSupportsMultiInstance("krb5_cname"); +} diff --git a/src/detect-krb5-cname.h b/src/app-layer/krb5/detect-cname.h similarity index 100% rename from src/detect-krb5-cname.h rename to src/app-layer/krb5/detect-cname.h diff --git a/src/app-layer/krb5/detect-errcode.c b/src/app-layer/krb5/detect-errcode.c new file mode 100644 index 000000000000..87be909054f8 --- /dev/null +++ b/src/app-layer/krb5/detect-errcode.c @@ -0,0 +1,243 @@ +/* Copyright (C) 2018-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#include "suricata-common.h" +#include "util/unittest.h" +#include "util/byte.h" + +#include "detect-parse.h" +#include "detect-engine.h" + +#include "app-layer/krb5/detect-errcode.h" + +#include "app-layer/krb5/parser.h" +#include "rust.h" + +/** + * \brief Regex for parsing our keyword options + */ +#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9_\\.]+\")\\s*$" +static DetectParseRegex parse_regex; + +/* Prototypes of functions registered in DetectKrb5ErrCodeRegister below */ +static int DetectKrb5ErrCodeMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectKrb5ErrCodeSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectKrb5ErrCodeFree(DetectEngineCtx *, void *); +#ifdef UNITTESTS +static void DetectKrb5ErrCodeRegisterTests(void); +#endif + +static int g_krb5_err_code_list_id = 0; + +/** + * \brief Registration function for krb5_err_code: keyword + * + * This function is called once in the 'lifetime' of the engine. + */ +void DetectKrb5ErrCodeRegister(void) +{ + sigmatch_table[DETECT_AL_KRB5_ERRCODE].name = "krb5_err_code"; + sigmatch_table[DETECT_AL_KRB5_ERRCODE].desc = "match Kerberos 5 error code"; + sigmatch_table[DETECT_AL_KRB5_ERRCODE].url = "/rules/kerberos-keywords.html#krb5-err-code"; + sigmatch_table[DETECT_AL_KRB5_ERRCODE].Match = NULL; + sigmatch_table[DETECT_AL_KRB5_ERRCODE].AppLayerTxMatch = DetectKrb5ErrCodeMatch; + sigmatch_table[DETECT_AL_KRB5_ERRCODE].Setup = DetectKrb5ErrCodeSetup; + sigmatch_table[DETECT_AL_KRB5_ERRCODE].Free = DetectKrb5ErrCodeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_KRB5_ERRCODE].RegisterTests = DetectKrb5ErrCodeRegisterTests; +#endif + + DetectAppLayerInspectEngineRegister2("krb5_err_code", ALPROTO_KRB5, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("krb5_err_code", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + + /* set up the PCRE for keyword parsing */ + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + g_krb5_err_code_list_id = DetectBufferTypeRegister("krb5_err_code"); + SCLogDebug("g_krb5_err_code_list_id %d", g_krb5_err_code_list_id); +} + +/** + * \brief This function is used to match KRB5 rule option on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch with context that we will cast into DetectKrb5Data + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectKrb5ErrCodeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + int32_t err_code; + int ret; + const DetectKrb5ErrCodeData *dd = (const DetectKrb5ErrCodeData *)ctx; + + SCEnter(); + + ret = rs_krb5_tx_get_errcode(txv, &err_code); + if (ret != 0) + SCReturnInt(0); + + if (dd->err_code == err_code) + SCReturnInt(1); + + SCReturnInt(0); +} + +/** + * \brief This function is used to parse options passed via krb5_errcode: keyword + * + * \param krb5str Pointer to the user provided krb5_err_code options + * + * \retval krb5d pointer to DetectKrb5Data on success + * \retval NULL on failure + */ +static DetectKrb5ErrCodeData *DetectKrb5ErrCodeParse(const char *krb5str) +{ + DetectKrb5ErrCodeData *krb5d = NULL; + char arg1[4] = ""; + int res = 0; + size_t pcre2len; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, krb5str, 0, 0); + if (ret != 2) { + SCLogError("parse error, ret %" PRId32 "", ret); + goto error; + } + + pcre2len = sizeof(arg1); + res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + + krb5d = SCMalloc(sizeof(DetectKrb5ErrCodeData)); + if (unlikely(krb5d == NULL)) + goto error; + if (StringParseInt32(&krb5d->err_code, 10, 0, (const char *)arg1) < 0) { + goto error; + } + pcre2_match_data_free(match); + return krb5d; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (krb5d) + SCFree(krb5d); + return NULL; +} + +/** + * \brief parse the options from the 'krb5_err_code' keyword in the rule into + * the Signature data structure. + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param krb5str pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectKrb5ErrCodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *krb5str) +{ + DetectKrb5ErrCodeData *krb5d = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) + return -1; + + krb5d = DetectKrb5ErrCodeParse(krb5str); + if (krb5d == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_KRB5_ERRCODE, (SigMatchCtx *)krb5d, + g_krb5_err_code_list_id) == NULL) { + goto error; + } + + return 0; + +error: + if (krb5d != NULL) + DetectKrb5ErrCodeFree(de_ctx, krb5d); + return -1; +} + +/** + * \brief this function will free memory associated with DetectKrb5Data + * + * \param ptr pointer to DetectKrb5Data + */ +static void DetectKrb5ErrCodeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectKrb5ErrCodeData *krb5d = (DetectKrb5ErrCodeData *)ptr; + + SCFree(krb5d); +} + +#ifdef UNITTESTS +/** + * \test description of the test + */ + +static int DetectKrb5ErrCodeParseTest01(void) +{ + DetectKrb5ErrCodeData *krb5d = DetectKrb5ErrCodeParse("10"); + FAIL_IF_NULL(krb5d); + FAIL_IF(!(krb5d->err_code == 10)); + DetectKrb5ErrCodeFree(NULL, krb5d); + PASS; +} + +static int DetectKrb5ErrCodeSignatureTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert krb5 any any -> any any (krb5_err_code:10; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \brief this function registers unit tests for DetectKrb5ErrCode + */ +static void DetectKrb5ErrCodeRegisterTests(void) +{ + UtRegisterTest("DetectKrb5ErrCodeParseTest01", DetectKrb5ErrCodeParseTest01); + UtRegisterTest("DetectKrb5ErrCodeSignatureTest01", DetectKrb5ErrCodeSignatureTest01); +} +#endif /* UNITTESTS */ diff --git a/src/detect-krb5-errcode.h b/src/app-layer/krb5/detect-errcode.h similarity index 100% rename from src/detect-krb5-errcode.h rename to src/app-layer/krb5/detect-errcode.h diff --git a/src/app-layer/krb5/detect-msgtype.c b/src/app-layer/krb5/detect-msgtype.c new file mode 100644 index 000000000000..ddd9a804852d --- /dev/null +++ b/src/app-layer/krb5/detect-msgtype.c @@ -0,0 +1,241 @@ +/* Copyright (C) 2018-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#include "suricata-common.h" +#include "util/unittest.h" +#include "util/byte.h" + +#include "detect-parse.h" +#include "detect-engine.h" + +#include "app-layer/krb5/detect-msgtype.h" + +#include "app-layer/krb5/parser.h" +#include "rust.h" + +/** + * \brief Regex for parsing our keyword options + */ +#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9_\\.]+\")\\s*$" +static DetectParseRegex parse_regex; + +/* Prototypes of functions registered in DetectKrb5MsgTypeRegister below */ +static int DetectKrb5MsgTypeMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectKrb5MsgTypeSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectKrb5MsgTypeFree(DetectEngineCtx *, void *); +#ifdef UNITTESTS +static void DetectKrb5MsgTypeRegisterTests(void); +#endif + +static int g_krb5_msg_type_list_id = 0; + +/** + * \brief Registration function for krb5_msg_type: keyword + * + * This function is called once in the 'lifetime' of the engine. + */ +void DetectKrb5MsgTypeRegister(void) +{ + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].name = "krb5_msg_type"; + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].desc = "match Kerberos 5 message type"; + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].url = "/rules/kerberos-keywords.html#krb5-msg-type"; + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].Match = NULL; + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].AppLayerTxMatch = DetectKrb5MsgTypeMatch; + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].Setup = DetectKrb5MsgTypeSetup; + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].Free = DetectKrb5MsgTypeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_KRB5_MSGTYPE].RegisterTests = DetectKrb5MsgTypeRegisterTests; +#endif + + DetectAppLayerInspectEngineRegister2("krb5_msg_type", ALPROTO_KRB5, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("krb5_msg_type", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + + /* set up the PCRE for keyword parsing */ + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + g_krb5_msg_type_list_id = DetectBufferTypeRegister("krb5_msg_type"); + SCLogDebug("g_krb5_msg_type_list_id %d", g_krb5_msg_type_list_id); +} + +/** + * \brief This function is used to match KRB5 rule option on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch with context that we will cast into DetectKrb5Data + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectKrb5MsgTypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + uint32_t msg_type; + const DetectKrb5MsgTypeData *dd = (const DetectKrb5MsgTypeData *)ctx; + + SCEnter(); + + rs_krb5_tx_get_msgtype(txv, &msg_type); + + if (dd->msg_type == msg_type) + SCReturnInt(1); + + SCReturnInt(0); +} + +/** + * \brief This function is used to parse options passed via krb5_msgtype: keyword + * + * \param krb5str Pointer to the user provided krb5_msg_type options + * + * \retval krb5d pointer to DetectKrb5Data on success + * \retval NULL on failure + */ +static DetectKrb5MsgTypeData *DetectKrb5MsgTypeParse(const char *krb5str) +{ + DetectKrb5MsgTypeData *krb5d = NULL; + char arg1[4] = ""; + int res = 0; + size_t pcre2len; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, krb5str, 0, 0); + if (ret != 2) { + SCLogError("parse error, ret %" PRId32 "", ret); + goto error; + } + + pcre2len = sizeof(arg1); + res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + + krb5d = SCMalloc(sizeof(DetectKrb5MsgTypeData)); + if (unlikely(krb5d == NULL)) + goto error; + if (StringParseUint8(&krb5d->msg_type, 10, 0, (const char *)arg1) < 0) { + goto error; + } + pcre2_match_data_free(match); + return krb5d; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (krb5d) + SCFree(krb5d); + return NULL; +} + +/** + * \brief parse the options from the 'krb5_msg_type' keyword in the rule into + * the Signature data structure. + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param krb5str pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectKrb5MsgTypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *krb5str) +{ + DetectKrb5MsgTypeData *krb5d = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) + return -1; + + krb5d = DetectKrb5MsgTypeParse(krb5str); + if (krb5d == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_KRB5_MSGTYPE, (SigMatchCtx *)krb5d, + g_krb5_msg_type_list_id) == NULL) { + goto error; + } + + return 0; + +error: + if (krb5d != NULL) + DetectKrb5MsgTypeFree(de_ctx, krb5d); + return -1; +} + +/** + * \brief this function will free memory associated with DetectKrb5Data + * + * \param ptr pointer to DetectKrb5Data + */ +static void DetectKrb5MsgTypeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectKrb5MsgTypeData *krb5d = (DetectKrb5MsgTypeData *)ptr; + + SCFree(krb5d); +} + +#ifdef UNITTESTS + +/** + * \test description of the test + */ + +static int DetectKrb5MsgTypeParseTest01(void) +{ + DetectKrb5MsgTypeData *krb5d = DetectKrb5MsgTypeParse("10"); + FAIL_IF_NULL(krb5d); + FAIL_IF(!(krb5d->msg_type == 10)); + DetectKrb5MsgTypeFree(NULL, krb5d); + PASS; +} + +static int DetectKrb5MsgTypeSignatureTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert krb5 any any -> any any (krb5_msg_type:10; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \brief this function registers unit tests for DetectKrb5MsgType + */ +static void DetectKrb5MsgTypeRegisterTests(void) +{ + UtRegisterTest("DetectKrb5MsgTypeParseTest01", DetectKrb5MsgTypeParseTest01); + UtRegisterTest("DetectKrb5MsgTypeSignatureTest01", DetectKrb5MsgTypeSignatureTest01); +} +#endif /* UNITTESTS */ diff --git a/src/detect-krb5-msgtype.h b/src/app-layer/krb5/detect-msgtype.h similarity index 100% rename from src/detect-krb5-msgtype.h rename to src/app-layer/krb5/detect-msgtype.h diff --git a/src/app-layer/krb5/detect-sname.c b/src/app-layer/krb5/detect-sname.c new file mode 100644 index 000000000000..f2a7bc96e36b --- /dev/null +++ b/src/app-layer/krb5/detect-sname.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2018-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#include "suricata-common.h" +#include "util/unittest.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer/krb5/detect-sname.h" + +#include "rust.h" +#include "app-layer/krb5/parser.h" +#include "util/profiling.h" + +static int g_krb5_sname_buffer_id = 0; + +struct Krb5PrincipalNameDataArgs { + uint32_t local_id; /**< used as index into thread inspect array */ + void *txv; +}; + +static int DetectKrb5SNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_krb5_sname_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetKrb5SNameData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, + const struct Krb5PrincipalNameDataArgs *cbdata, int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_krb5_tx_get_sname(cbdata->txv, cbdata->local_id, &b, &b_len) != 1) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + if (b == NULL || b_len == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, b, b_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectKrb5SName(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct Krb5PrincipalNameDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + GetKrb5SNameData(det_ctx, transforms, f, &cbdata, engine->sm_list); + + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmKrb5Name { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmKrb5Name; + +/** \brief Krb5SName Krb5SName Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxKrb5SName(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmKrb5Name *ctx = (const PrefilterMpmKrb5Name *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + + while (1) { + // loop until we get a NULL + + struct Krb5PrincipalNameDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = GetKrb5SNameData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static void PrefilterMpmKrb5NameFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmKrb5SNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmKrb5Name *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxKrb5SName, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmKrb5NameFree, mpm_reg->name); +} + +void DetectKrb5SNameRegister(void) +{ + sigmatch_table[DETECT_AL_KRB5_SNAME].name = "krb5.sname"; + sigmatch_table[DETECT_AL_KRB5_SNAME].alias = "krb5_sname"; + sigmatch_table[DETECT_AL_KRB5_SNAME].url = "/rules/kerberos-keywords.html#krb5-sname"; + sigmatch_table[DETECT_AL_KRB5_SNAME].Setup = DetectKrb5SNameSetup; + sigmatch_table[DETECT_AL_KRB5_SNAME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[DETECT_AL_KRB5_SNAME].desc = "sticky buffer to match on Kerberos 5 server name"; + + DetectAppLayerMpmRegister2("krb5_sname", SIG_FLAG_TOCLIENT, 2, PrefilterMpmKrb5SNameRegister, + NULL, ALPROTO_KRB5, 1); + + DetectAppLayerInspectEngineRegister2( + "krb5_sname", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectKrb5SName, NULL); + + DetectBufferTypeSetDescriptionByName("krb5_sname", "Kerberos 5 ticket server name"); + + g_krb5_sname_buffer_id = DetectBufferTypeGetByName("krb5_sname"); + + DetectBufferTypeSupportsMultiInstance("krb5_sname"); +} diff --git a/src/detect-krb5-sname.h b/src/app-layer/krb5/detect-sname.h similarity index 100% rename from src/detect-krb5-sname.h rename to src/app-layer/krb5/detect-sname.h diff --git a/src/app-layer/krb5/detect-ticket-encryption.c b/src/app-layer/krb5/detect-ticket-encryption.c new file mode 100644 index 000000000000..7633a9aa44ae --- /dev/null +++ b/src/app-layer/krb5/detect-ticket-encryption.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "rust.h" + +#include "app-layer/krb5/detect-ticket-encryption.h" + +#include "detect-engine.h" +#include "detect-parse.h" + +static int g_krb5_ticket_encryption_list_id = 0; + +static void DetectKrb5TicketEncryptionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_krb5_detect_encryption_free(ptr); +} + +static int DetectKrb5TicketEncryptionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectKrb5TicketEncryptionData *dd = (const DetectKrb5TicketEncryptionData *)ctx; + + SCEnter(); + + SCReturnInt(rs_krb5_detect_encryption_match(txv, dd)); +} + +static int DetectKrb5TicketEncryptionSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *krb5str) +{ + DetectKrb5TicketEncryptionData *krb5d = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) + return -1; + + krb5d = rs_krb5_detect_encryption_parse(krb5str); + if (krb5d == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_KRB5_TICKET_ENCRYPTION, (SigMatchCtx *)krb5d, + g_krb5_ticket_encryption_list_id) == NULL) { + goto error; + } + + return 0; + +error: + if (krb5d != NULL) + DetectKrb5TicketEncryptionFree(de_ctx, krb5d); + return -1; +} + +void DetectKrb5TicketEncryptionRegister(void) +{ + sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].name = "krb5.ticket_encryption"; + sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].desc = "match Kerberos 5 ticket encryption"; + sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].url = + "/rules/kerberos-keywords.html#krb5-ticket-encryption"; + sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].Match = NULL; + sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].AppLayerTxMatch = + DetectKrb5TicketEncryptionMatch; + sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].Setup = DetectKrb5TicketEncryptionSetup; + sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].Free = DetectKrb5TicketEncryptionFree; + + // Tickets are only from server to client + DetectAppLayerInspectEngineRegister2("krb5_ticket_encryption", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, + 0, DetectEngineInspectGenericList, NULL); + + g_krb5_ticket_encryption_list_id = DetectBufferTypeRegister("krb5_ticket_encryption"); + SCLogDebug("g_krb5_ticket_encryption_list_id %d", g_krb5_ticket_encryption_list_id); +} diff --git a/src/detect-krb5-ticket-encryption.h b/src/app-layer/krb5/detect-ticket-encryption.h similarity index 100% rename from src/detect-krb5-ticket-encryption.h rename to src/app-layer/krb5/detect-ticket-encryption.h diff --git a/src/app-layer/krb5/logger.c b/src/app-layer/krb5/logger.c new file mode 100644 index 000000000000..8f93097cbfe0 --- /dev/null +++ b/src/app-layer/krb5/logger.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2018-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * + * Implement JSON/eve logging app-layer KRB5. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/krb5/parser.h" +#include "app-layer/krb5/logger.h" + +#include "rust.h" + +static int JsonKRB5Logger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + KRB5Transaction *krb5tx = tx; + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "krb5", NULL, thread->ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_FAILED; + } + + if (!rs_krb5_log_json_response(krb5tx, jb)) { + goto error; + } + + OutputJsonBuilderBuffer(jb, thread); + + jb_free(jb); + return TM_ECODE_OK; + +error: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static OutputInitResult OutputKRB5LogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_KRB5); + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_KRB5); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonKRB5LogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonKRB5Log", "eve-log.krb5", + OutputKRB5LogInitSub, ALPROTO_KRB5, JsonKRB5Logger, JsonLogThreadInit, + JsonLogThreadDeinit, NULL); + + SCLogDebug("KRB5 JSON logger registered."); +} diff --git a/src/output-json-krb5.h b/src/app-layer/krb5/logger.h similarity index 100% rename from src/output-json-krb5.h rename to src/app-layer/krb5/logger.h diff --git a/src/app-layer/krb5/parser.c b/src/app-layer/krb5/parser.c new file mode 100644 index 000000000000..4a699b7f0257 --- /dev/null +++ b/src/app-layer/krb5/parser.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * + * Parser for Kerberos v5 application layer running on UDP port 88. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/krb5/parser.h" +#include "rust.h" + +void RegisterKRB5Parsers(void) +{ + rs_register_krb5_parser(); + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_KRB5, KRB5ParserRegisterTests); +#endif +} + +#ifdef UNITTESTS +#endif + +void KRB5ParserRegisterTests(void) +{ +#ifdef UNITTESTS +#endif +} diff --git a/src/app-layer-krb5.h b/src/app-layer/krb5/parser.h similarity index 100% rename from src/app-layer-krb5.h rename to src/app-layer/krb5/parser.h diff --git a/src/app-layer/modbus/detect.c b/src/app-layer/modbus/detect.c new file mode 100644 index 000000000000..1981a64f8358 --- /dev/null +++ b/src/app-layer/modbus/detect.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + * + * Implements the Modbus function and access keywords + * You can specify a: + * - concrete function like Modbus: + * function 8, subfunction 4 (diagnostic: Force Listen Only Mode) + * - data (in primary table) register access (r/w) like Modbus: + * access read coils, address 1000 (.i.e Read coils: at address 1000) + * - write data value at specific address Modbus: + * access write, address 1500<>2000, value >2000 (Write multiple coils/register: + * at address between 1500 and 2000 value greater than 2000) + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" + +#include "app-layer/modbus/detect.h" + +#include "util/debug.h" +#include "util/byte.h" + +#include "stream-tcp.h" +#include "rust.h" + +static int g_modbus_buffer_id = 0; + +/** \internal + * + * \brief this function will free memory associated with DetectModbus + * + * \param ptr pointer to DetectModbus + */ +static void DetectModbusFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCEnter(); + if (ptr != NULL) { + rs_modbus_free(ptr); + } + SCReturn; +} + +/** \internal + * + * \brief this function is used to add the parsed "id" option into the current signature + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Current Signature + * \param str Pointer to the user provided "id" option + * + * \retval 0 on Success or -1 on Failure + */ +static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + SCEnter(); + DetectModbusRust *modbus = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MODBUS) != 0) + return -1; + + if ((modbus = rs_modbus_parse(str)) == NULL) { + SCLogError("invalid modbus option"); + goto error; + } + + /* Okay so far so good, lets get this into a SigMatch and put it in the Signature. */ + if (SigMatchAppendSMToList( + de_ctx, s, DETECT_AL_MODBUS, (SigMatchCtx *)modbus, g_modbus_buffer_id) == NULL) { + goto error; + } + + SCReturnInt(0); + +error: + if (modbus != NULL) + DetectModbusFree(de_ctx, modbus); + SCReturnInt(-1); +} + +static int DetectModbusMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + return rs_modbus_inspect(txv, (void *)ctx); +} + +/** + * \brief Registration function for Modbus keyword + */ +void DetectModbusRegister(void) +{ + sigmatch_table[DETECT_AL_MODBUS].name = "modbus"; + sigmatch_table[DETECT_AL_MODBUS].desc = "match on various properties of Modbus requests"; + sigmatch_table[DETECT_AL_MODBUS].url = "/rules/modbus-keyword.html#modbus-keyword"; + sigmatch_table[DETECT_AL_MODBUS].Match = NULL; + sigmatch_table[DETECT_AL_MODBUS].Setup = DetectModbusSetup; + sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree; + sigmatch_table[DETECT_AL_MODBUS].AppLayerTxMatch = DetectModbusMatch; + + DetectAppLayerInspectEngineRegister2( + "modbus", ALPROTO_MODBUS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + + g_modbus_buffer_id = DetectBufferTypeGetByName("modbus"); +} diff --git a/src/detect-modbus.h b/src/app-layer/modbus/detect.h similarity index 100% rename from src/detect-modbus.h rename to src/app-layer/modbus/detect.h diff --git a/src/app-layer/modbus/logger.c b/src/app-layer/modbus/logger.c new file mode 100644 index 000000000000..342368f7c21b --- /dev/null +++ b/src/app-layer/modbus/logger.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2019-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/modbus/logger.h" +#include "rust.h" + +typedef struct LogModbusFileCtx_ { + LogFileCtx *file_ctx; + OutputJsonCtx *eve_ctx; +} LogModbusFileCtx; + +typedef struct JsonModbusLogThread_ { + LogModbusFileCtx *modbuslog_ctx; + OutputJsonThreadCtx *ctx; +} JsonModbusLogThread; + +static int JsonModbusLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *tx, uint64_t tx_id) +{ + JsonModbusLogThread *thread = thread_data; + + JsonBuilder *js = + CreateEveHeader(p, LOG_DIR_FLOW, "modbus", NULL, thread->modbuslog_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + if (!rs_modbus_to_json(tx, js)) { + jb_free(js); + return TM_ECODE_FAILED; + } + OutputJsonBuilderBuffer(js, thread->ctx); + + jb_free(js); + return TM_ECODE_OK; +} + +static void OutputModbusLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogModbusFileCtx *modbuslog_ctx = (LogModbusFileCtx *)output_ctx->data; + SCFree(modbuslog_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputModbusLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ajt = parent_ctx->data; + + LogModbusFileCtx *modbuslog_ctx = SCCalloc(1, sizeof(*modbuslog_ctx)); + if (unlikely(modbuslog_ctx == NULL)) { + return result; + } + modbuslog_ctx->file_ctx = ajt->file_ctx; + modbuslog_ctx->eve_ctx = ajt; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(modbuslog_ctx); + return result; + } + output_ctx->data = modbuslog_ctx; + output_ctx->DeInit = OutputModbusLogDeInitCtxSub; + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_MODBUS); + + SCLogDebug("modbus log sub-module initialized."); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonModbusLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogModbus. \"initdata\" is NULL."); + return TM_ECODE_FAILED; + } + + JsonModbusLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + thread->modbuslog_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->modbuslog_ctx->eve_ctx); + if (thread->ctx == NULL) { + goto error_exit; + } + + *data = (void *)thread; + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonModbusLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonModbusLogThread *thread = (JsonModbusLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonModbusLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonModbusLog", "eve-log.modbus", + OutputModbusLogInitSub, ALPROTO_MODBUS, JsonModbusLogger, JsonModbusLogThreadInit, + JsonModbusLogThreadDeinit, NULL); + + SCLogDebug("modbus json logger registered."); +} diff --git a/src/output-json-modbus.h b/src/app-layer/modbus/logger.h similarity index 100% rename from src/output-json-modbus.h rename to src/app-layer/modbus/logger.h diff --git a/src/app-layer/modbus/parser.c b/src/app-layer/modbus/parser.c new file mode 100644 index 000000000000..4432c7490149 --- /dev/null +++ b/src/app-layer/modbus/parser.c @@ -0,0 +1,1581 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + * + * App-layer parser for Modbus protocol + * + */ + +#include "suricata-common.h" + +#include "util/debug.h" + +#include "app-layer-parser.h" +#include "app-layer/modbus/parser.h" + +void ModbusParserRegisterTests(void); + +/** + * \brief Function to register the Modbus protocol parser + */ +void RegisterModbusParsers(void) +{ + rs_modbus_register_parser(); +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_MODBUS, ModbusParserRegisterTests); +#endif + + SCReturn; +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-engine-build.h" +#include "detect-engine-alert.h" + +#include "flow-util.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "stream-tcp.h" +#include "stream-tcp-private.h" + +#include "rust.h" + +/* Modbus default stream reassembly depth */ +#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH 0 + +/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ +// clang-format off +static uint8_t invalidFunctionCode[] = { + /* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x02, + /* Unit ID */ 0x00, + /* Function code */ 0x00 +}; +// clang-format on + +/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ +/* Example of a request to read discrete outputs 20-38 */ +// clang-format off +static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; +// clang-format on + +// clang-format off +static uint8_t readCoilsRsp[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Byte count */ 0x03, + /* Coil Status */ 0xCD, 0x6B, 0x05 }; +// clang-format on + +// clang-format off +static uint8_t readCoilsErrorRsp[] = { + /* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x03, + /* Unit ID */ 0x00, + /* Function code */ 0x81, + /* Invalid Exception code: should trigger the InvalidExceptionCode ModbusEvent */ + 0xFF +}; +// clang-format on + +/* Modbus Application Protocol Specification V1.1b3 6.6: Write Single register */ +/* Example of a request to write register 2 to 00 03 hex */ +// clang-format off +static uint8_t writeSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01, + /* Register Value */ 0x00, 0x03}; +// clang-format on + +// clang-format off +static uint8_t invalidWriteSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x04, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01}; +// clang-format on + +// clang-format off +static uint8_t writeSingleRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01, + /* Register Value */ 0x00, 0x03}; +// clang-format on + +/* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */ +/* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */ +// clang-format off +static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x0B, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02, + /* Byte count */ 0x04, + /* Registers Value */ 0x00, 0x0A, + 0x01, 0x02}; +// clang-format on + +// clang-format off +static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02}; +// clang-format on + +/* Modbus Application Protocol Specification V1.1b3 6.16: Mask Write Register */ +/* Example of a request to mask write to register 5 */ +// clang-format off +static uint8_t maskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x08, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2, + /* Or_Mask */ 0x00, 0x25}; +// clang-format on + +// clang-format off +static uint8_t invalidMaskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2}; +// clang-format on + +// clang-format off +static uint8_t maskWriteRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x08, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2, + /* Or_Mask */ 0x00, 0x25}; +// clang-format on + +/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */ +/* Example of a request to read six registers starting at register 4, */ +/* and to write three registers starting at register 15 */ +// clang-format off +static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x11, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Read Starting Address */ 0x00, 0x03, + /* Quantity to Read */ 0x00, 0x06, + /* Write Starting Address */ 0x00, 0x0E, + /* Quantity to Write */ 0x00, 0x03, + /* Write Byte count */ 0x06, + /* Write Registers Value */ 0x12, 0x34, + 0x56, 0x78, + 0x9A, 0xBC}; +// clang-format on + +/* Mismatch value in Byte count 0x0B instead of 0x0C */ +// clang-format off +static uint8_t readWriteMultipleRegistersRsp[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x0E, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Byte count */ 0x0B, + /* Read Registers Value */ 0x00, 0xFE, + 0x0A, 0xCD, + 0x00, 0x01, + 0x00, 0x03, + 0x00, 0x0D, + 0x00}; +// clang-format on + +/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */ +/* Example of a request to to remote device to its Listen Only Mode for Modbus Communications. */ +// clang-format off +static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x08, + /* Sub-function code */ 0x00, 0x04, + /* Data */ 0x00, 0x00}; +// clang-format on + +// clang-format off +static uint8_t invalidProtocolIdReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x01, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; +// clang-format on + +// clang-format off +static uint8_t invalidLengthWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x09, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02, + /* Byte count */ 0x04, + /* Registers Value */ 0x00, 0x0A, + 0x01, 0x02}; +// clang-format on + +// clang-format off +static uint8_t exceededLengthWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0xff, 0xfa, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x7f, 0xf9, + /* Byte count */ 0xff}; +// clang-format on + +// clang-format off +static uint8_t invalidLengthPDUWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x02, + /* Unit ID */ 0x00, + /* Function code */ 0x10}; +// clang-format on + +/** \test Send Modbus Read Coils request/response. */ +static int ModbusParserTest01(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1); + FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890); + FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readCoilsRsp, + sizeof(readCoilsRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Send Modbus Write Multiple registers request/response. */ +static int ModbusParserTest02(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 16); + FAIL_IF_NOT(rs_modbus_message_get_write_multreq_address(&request) == 0x01); + FAIL_IF_NOT(rs_modbus_message_get_write_multreq_quantity(&request) == 2); + + size_t data_len; + const uint8_t *data = rs_modbus_message_get_write_multreq_data(&request, &data_len); + FAIL_IF_NOT(data_len == 4); + FAIL_IF_NOT(data[0] == 0x00); + FAIL_IF_NOT(data[1] == 0x0A); + FAIL_IF_NOT(data[2] == 0x01); + FAIL_IF_NOT(data[3] == 0x02); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */ +static int ModbusParserTest03(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus Data mismatch\"; " + "app-layer-event: " + "modbus.value_mismatch; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readWriteMultipleRegistersReq, sizeof(readWriteMultipleRegistersReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 23); + FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_read_address(&request) == 0x03); + FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_read_quantity(&request) == 6); + FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_write_address(&request) == 0x0E); + FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_write_quantity(&request) == 3); + + size_t data_len; + uint8_t const *data = rs_modbus_message_get_rw_multreq_write_data(&request, &data_len); + FAIL_IF_NOT(data_len == 6); + FAIL_IF_NOT(data[0] == 0x12); + FAIL_IF_NOT(data[1] == 0x34); + FAIL_IF_NOT(data[2] == 0x56); + FAIL_IF_NOT(data[3] == 0x78); + FAIL_IF_NOT(data[4] == 0x9A); + FAIL_IF_NOT(data[5] == 0xBC); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + readWriteMultipleRegistersRsp, sizeof(readWriteMultipleRegistersRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Send Modbus Force Listen Only Mode request. */ +static int ModbusParserTest04(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + forceListenOnlyMode, sizeof(forceListenOnlyMode)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 8); + FAIL_IF_NOT(rs_modbus_message_get_subfunction(&request) == 4); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Send Modbus invalid Protocol version in request. */ +static int ModbusParserTest05(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Protocol version\"; " + "app-layer-event: " + "modbus.invalid_protocol_id; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidProtocolIdReq, sizeof(invalidProtocolIdReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Send Modbus unsolicited response. */ +static int ModbusParserTest06(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus unsolicited response\"; " + "app-layer-event: " + "modbus.unsolicited_response; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readCoilsRsp, + sizeof(readCoilsRsp)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Send Modbus invalid Length request. */ +static int ModbusParserTest07(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidLengthWriteMultipleRegistersReq, sizeof(invalidLengthWriteMultipleRegistersReq)); + FAIL_IF_NOT(r == 1); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Send Modbus Read Coils request and error response with Exception code invalid. */ +static int ModbusParserTest08(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus Exception code invalid\"; " + "app-layer-event: " + "modbus.invalid_exception_code; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1); + FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890); + FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readCoilsErrorRsp, + sizeof(readCoilsErrorRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */ +static int ModbusParserTest09(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; + uint8_t *input = readCoilsReq; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len - part2_len); + FAIL_IF_NOT(r == 1); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1); + FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890); + FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19); + + input_len = sizeof(readCoilsRsp); + part2_len = 10; + input = readCoilsRsp; + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len - part2_len); + FAIL_IF_NOT(r == 1); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */ +static int ModbusParserTest10(void) +{ + uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq); + uint8_t *input, *ptr; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF_NULL(alp_tctx); + + input = (uint8_t *)SCMalloc(input_len * sizeof(uint8_t)); + FAIL_IF_NULL(input); + + memcpy(input, readCoilsReq, sizeof(readCoilsReq)); + memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, + sizeof(writeMultipleRegistersReq)); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 2); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 1); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 16); + FAIL_IF_NOT(rs_modbus_message_get_write_multreq_address(&request) == 0x01); + FAIL_IF_NOT(rs_modbus_message_get_write_multreq_quantity(&request) == 2); + + size_t data_len; + uint8_t const *data = rs_modbus_message_get_write_multreq_data(&request, &data_len); + FAIL_IF_NOT(data_len == 4); + FAIL_IF_NOT(data[0] == 0x00); + FAIL_IF_NOT(data[1] == 0x0A); + FAIL_IF_NOT(data[2] == 0x01); + FAIL_IF_NOT(data[3] == 0x02); + + input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp); + + ptr = (uint8_t *)SCRealloc(input, input_len * sizeof(uint8_t)); + FAIL_IF_NULL(ptr); + input = ptr; + + memcpy(input, readCoilsRsp, sizeof(readCoilsRsp)); + memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, + sizeof(writeMultipleRegistersRsp)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len); + FAIL_IF_NOT(r == 0); + + SCFree(input); + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Send Modbus exceed Length request. */ +static int ModbusParserTest11(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + size_t input_len = 65536; + uint8_t *input = SCCalloc(1, input_len); + + FAIL_IF(input == NULL); + + memcpy(input, exceededLengthWriteMultipleRegistersReq, + sizeof(exceededLengthWriteMultipleRegistersReq)); + + FAIL_IF(alp_tctx == NULL); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Send Modbus invalid PDU Length. */ +static int ModbusParserTest12(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidLengthPDUWriteMultipleRegistersReq, + sizeof(invalidLengthPDUWriteMultipleRegistersReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Send Modbus Mask Write register request/response. */ +static int ModbusParserTest13(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + maskWriteRegisterReq, sizeof(maskWriteRegisterReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 22); + FAIL_IF_NOT(rs_modbus_message_get_and_mask(&request) == 0x00F2); + FAIL_IF_NOT(rs_modbus_message_get_or_mask(&request) == 0x0025); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Send Modbus Write single register request/response. */ +static int ModbusParserTest14(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + writeSingleRegisterReq, sizeof(writeSingleRegisterReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 6); + FAIL_IF_NOT(rs_modbus_message_get_write_address(&request) == 0x0001); + FAIL_IF_NOT(rs_modbus_message_get_write_data(&request) == 0x0003); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Send invalid Modbus Mask Write register request. */ +static int ModbusParserTest15(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidMaskWriteRegisterReq, sizeof(invalidMaskWriteRegisterReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 22); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + maskWriteRegisterRsp, sizeof(maskWriteRegisterRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + ModbusMessage response = rs_modbus_state_get_tx_response(modbus_state, 0); + FAIL_IF_NULL(response._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&response) == 22); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Send invalid Modbus Mask Write register request. */ +static int ModbusParserTest16(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidWriteSingleRegisterReq, sizeof(invalidWriteSingleRegisterReq)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0); + FAIL_IF_NULL(request._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 6); + size_t data_len; + const uint8_t *data = rs_modbus_message_get_bytevec_data(&request, &data_len); + FAIL_IF_NOT(data_len == 2); + FAIL_IF_NOT(data[0] == 0x00); + FAIL_IF_NOT(data[1] == 0x01); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + writeSingleRegisterRsp, sizeof(writeSingleRegisterRsp)); + FAIL_IF_NOT(r == 0); + + FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1); + ModbusMessage response = rs_modbus_state_get_tx_response(modbus_state, 0); + FAIL_IF_NULL(response._0); + + FAIL_IF_NOT(rs_modbus_message_get_function(&response) == 6); + FAIL_IF_NOT(rs_modbus_message_get_write_address(&response) == 0x0001); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +/** \test Checks if stream_depth is correct */ +static int ModbusParserTest17(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); + FAIL_IF(r != 0); + + FAIL_IF(f.alstate == NULL); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, readCoilsRsp, + sizeof(readCoilsRsp)); + FAIL_IF(r != 0); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/*/ \test Checks if stream depth is correct over 2 TCP packets */ +static int ModbusParserTest18(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; + uint8_t *input = readCoilsReq; + + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len - part2_len); + FAIL_IF(r != 1); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len); + FAIL_IF(r != 0); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FAIL_IF(f.alstate == NULL); + + input_len = sizeof(readCoilsRsp); + part2_len = 10; + input = readCoilsRsp; + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len - part2_len); + FAIL_IF(r != 1); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len); + FAIL_IF(r != 0); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +/** \test Send Modbus invalid function. */ +static int ModbusParserTest19(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + FAIL_IF_NULL(alp_tctx); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_MODBUS; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(true); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Function code\"; " + "app-layer-event: " + "modbus.invalid_function_code; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + invalidFunctionCode, sizeof(invalidFunctionCode)); + FAIL_IF_NOT(r == 0); + + ModbusState *modbus_state = f.alstate; + FAIL_IF_NULL(modbus_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} +#endif /* UNITTESTS */ + +void ModbusParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request", ModbusParserTest01); + UtRegisterTest( + "ModbusParserTest02 - Modbus Write Multiple registers request", ModbusParserTest02); + UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request", + ModbusParserTest03); + UtRegisterTest( + "ModbusParserTest04 - Modbus Force Listen Only Mode request", ModbusParserTest04); + UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version", ModbusParserTest05); + UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response", ModbusParserTest06); + UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request", ModbusParserTest07); + UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", ModbusParserTest08); + UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", + ModbusParserTest09); + UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", + ModbusParserTest10); + UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", ModbusParserTest11); + UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length", ModbusParserTest12); + UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request", ModbusParserTest13); + UtRegisterTest("ModbusParserTest14 - Modbus Write single register request", ModbusParserTest14); + UtRegisterTest( + "ModbusParserTest15 - Modbus invalid Mask Write register request", ModbusParserTest15); + UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request", + ModbusParserTest16); + UtRegisterTest("ModbusParserTest17 - Modbus stream depth", ModbusParserTest17); + UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets", ModbusParserTest18); + UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code", ModbusParserTest19); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer-modbus.h b/src/app-layer/modbus/parser.h similarity index 100% rename from src/app-layer-modbus.h rename to src/app-layer/modbus/parser.h diff --git a/src/app-layer/mqtt/detect-connack-sessionpresent.c b/src/app-layer/mqtt/detect-connack-sessionpresent.c new file mode 100644 index 000000000000..87589407a3b9 --- /dev/null +++ b/src/app-layer/mqtt/detect-connack-sessionpresent.c @@ -0,0 +1,297 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/mqtt/detect-connack-sessionpresent.h" +#include "util/unittest.h" + +#include "rust.h" + +#define PARSE_REGEX "^true|false|yes|no$" +static DetectParseRegex parse_regex; + +static int mqtt_connack_session_present_id = 0; + +static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectMQTTConnackSessionPresentSetup(DetectEngineCtx *, Signature *, const char *); +void MQTTConnackSessionPresentRegisterTests(void); +void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *); + +/** + * \brief Registration function for mqtt.connack.session_present: keyword + */ +void DetectMQTTConnackSessionPresentRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].name = "mqtt.connack.session_present"; + sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].desc = + "match MQTT CONNACK session present flag"; + sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].url = + "/rules/mqtt-keywords.html#mqtt-connack-session-present"; + sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].AppLayerTxMatch = + DetectMQTTConnackSessionPresentMatch; + sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Setup = + DetectMQTTConnackSessionPresentSetup; + sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Free = + DetectMQTTConnackSessionPresentFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].RegisterTests = + MQTTConnackSessionPresentRegisterTests; +#endif + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2("mqtt.connack.session_present", ALPROTO_MQTT, + SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + + mqtt_connack_session_present_id = DetectBufferTypeGetByName("mqtt.connack.session_present"); +} + +/** + * \internal + * \brief Function to match session_present flag of an MQTT CONNACK message + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into + * DetectMQTTConnackSessionPresentData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx, Flow *f, + uint8_t flags, void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const bool *de = (const bool *)ctx; + bool value = false; + + if (!de) + return 0; + + if (rs_mqtt_tx_get_connack_sessionpresent(txv, &value) == 0) { + return 0; + } + if (value != *de) { + return 0; + } + + return 1; +} + +/** + * \internal + * \brief This function is used to parse options passed via mqtt.connack.session_present: keyword + * + * \param rawstr Pointer to the user provided options + * + * \retval de pointer to DetectMQTTConnackSessionPresentData on success + * \retval NULL on failure + */ +static bool *DetectMQTTConnackSessionPresentParse(const char *rawstr) +{ + bool *de = NULL; + de = SCMalloc(sizeof(bool)); + if (unlikely(de == NULL)) + return NULL; + *de = false; + + if (strcmp(rawstr, "yes") == 0) { + *de = true; + } else if (strcmp(rawstr, "true") == 0) { + *de = true; + } else if (strcmp(rawstr, "no") == 0) { + *de = false; + } else if (strcmp(rawstr, "false") == 0) { + *de = false; + } else { + SCLogError("invalid session_present flag definition: %s", rawstr); + goto error; + } + + return de; + +error: + /* de can't be NULL here */ + SCFree(de); + return NULL; +} + +/** + * \internal + * \brief this function is used to add the parsed type query into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectMQTTConnackSessionPresentSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + bool *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + de = DetectMQTTConnackSessionPresentParse(rawstr); + if (de == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNACK_SESSION_PRESENT, (SigMatchCtx *)de, + mqtt_connack_session_present_id) == NULL) { + goto error; + } + + return 0; + +error: + if (de != NULL) + SCFree(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectMQTTConnackSessionPresentData + * + * \param de pointer to DetectMQTTConnackSessionPresentData + */ +void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + if (de_ptr != NULL) + SCFree(de_ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test MQTTConnackSessionPresentTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnackSessionPresentTestParse01(void) +{ + bool *de = NULL; + + de = DetectMQTTConnackSessionPresentParse("yes"); + FAIL_IF_NULL(de); + DetectMQTTConnackSessionPresentFree(NULL, de); + + de = DetectMQTTConnackSessionPresentParse("true"); + FAIL_IF_NULL(de); + DetectMQTTConnackSessionPresentFree(NULL, de); + + de = DetectMQTTConnackSessionPresentParse("false"); + FAIL_IF_NULL(de); + DetectMQTTConnackSessionPresentFree(NULL, de); + + de = DetectMQTTConnackSessionPresentParse("no"); + FAIL_IF_NULL(de); + DetectMQTTConnackSessionPresentFree(NULL, de); + + PASS; +} + +/** + * \test MQTTConnackSessionPresentTestParse02 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnackSessionPresentTestParse02(void) +{ + bool *de = NULL; + de = DetectMQTTConnackSessionPresentParse("nix"); + if (de) { + DetectMQTTConnackSessionPresentFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTConnackSessionPresentTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnackSessionPresentTestParse03(void) +{ + bool *de = NULL; + de = DetectMQTTConnackSessionPresentParse(""); + if (de) { + DetectMQTTConnackSessionPresentFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTConnackSessionPresentTestParse04 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnackSessionPresentTestParse04(void) +{ + bool *de = NULL; + de = DetectMQTTConnackSessionPresentParse(","); + if (de) { + DetectMQTTConnackSessionPresentFree(NULL, de); + FAIL; + } + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for MQTTConnackSessionPresent + */ +void MQTTConnackSessionPresentRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MQTTConnackSessionPresentTestParse01", MQTTConnackSessionPresentTestParse01); + UtRegisterTest("MQTTConnackSessionPresentTestParse02", MQTTConnackSessionPresentTestParse02); + UtRegisterTest("MQTTConnackSessionPresentTestParse03", MQTTConnackSessionPresentTestParse03); + UtRegisterTest("MQTTConnackSessionPresentTestParse04", MQTTConnackSessionPresentTestParse04); +#endif /* UNITTESTS */ +} diff --git a/src/detect-mqtt-connack-sessionpresent.h b/src/app-layer/mqtt/detect-connack-sessionpresent.h similarity index 100% rename from src/detect-mqtt-connack-sessionpresent.h rename to src/app-layer/mqtt/detect-connack-sessionpresent.h diff --git a/src/app-layer/mqtt/detect-connect-clientid.c b/src/app-layer/mqtt/detect-connect-clientid.c new file mode 100644 index 000000000000..30b224a0261b --- /dev/null +++ b/src/app-layer/mqtt/detect-connect-clientid.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.connect.clientid sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-connect-clientid.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.connect.clientid" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-clientid" +#define BUFFER_NAME "mqtt.connect.clientid" +#define BUFFER_DESC "MQTT CONNECT client ID" +static int g_buffer_id = 0; + +static int DetectMQTTConnectClientIDSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_connect_clientid(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTConnectClientIDRegister(void) +{ + /* mqtt.connect.clientid sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].desc = + "sticky buffer to match on the MQTT CONNECT client ID"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].Setup = DetectMQTTConnectClientIDSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-connect-clientid.h b/src/app-layer/mqtt/detect-connect-clientid.h similarity index 100% rename from src/detect-mqtt-connect-clientid.h rename to src/app-layer/mqtt/detect-connect-clientid.h diff --git a/src/app-layer/mqtt/detect-connect-flags.c b/src/app-layer/mqtt/detect-connect-flags.c new file mode 100644 index 000000000000..c9e4fdd66fb4 --- /dev/null +++ b/src/app-layer/mqtt/detect-connect-flags.c @@ -0,0 +1,377 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/mqtt/detect-connect-flags.h" +#include "util/unittest.h" + +#include "rust.h" + +#define PARSE_REGEX "(?: *,?!?(?:username|password|will|will_retain|clean_session))+" +static DetectParseRegex parse_regex; + +static int mqtt_connect_flags_id = 0; + +static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectMQTTConnectFlagsSetup(DetectEngineCtx *, Signature *, const char *); +void MQTTConnectFlagsRegisterTests(void); +void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *); + +typedef struct DetectMQTTConnectFlagsData_ { + MQTTFlagState username, password, will, will_retain, clean_session; +} DetectMQTTConnectFlagsData; + +/** + * \brief Registration function for mqtt.connect.flags: keyword + */ +void DetectMQTTConnectFlagsRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].name = "mqtt.connect.flags"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].desc = "match MQTT CONNECT variable header flags"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].url = + "/rules/mqtt-keywords.html#mqtt-connect-flags"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].AppLayerTxMatch = DetectMQTTConnectFlagsMatch; + sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Setup = DetectMQTTConnectFlagsSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Free = DetectMQTTConnectFlagsFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].RegisterTests = MQTTConnectFlagsRegisterTests; +#endif + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2("mqtt.connect.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectGenericList, NULL); + + mqtt_connect_flags_id = DetectBufferTypeGetByName("mqtt.connect.flags"); +} + +/** + * \internal + * \brief Function to match variable header flags of an MQTT CONNECT Tx + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnectFlagsData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectMQTTConnectFlagsData *de = (const DetectMQTTConnectFlagsData *)ctx; + + if (!de) + return 0; + + return rs_mqtt_tx_has_connect_flags( + txv, de->username, de->password, de->will, de->will_retain, de->clean_session); +} + +/** + * \internal + * \brief This function is used to parse options passed via mqtt.connect.flags: keyword + * + * \param rawstr Pointer to the user provided options + * + * \retval de pointer to DetectMQTTConnectFlagsData on success + * \retval NULL on failure + */ +static DetectMQTTConnectFlagsData *DetectMQTTConnectFlagsParse(const char *rawstr) +{ + char copy[strlen(rawstr) + 1]; + + DetectMQTTConnectFlagsData *de = SCCalloc(1, sizeof(DetectMQTTConnectFlagsData)); + if (unlikely(de == NULL)) + return NULL; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); + if (ret < 1) { + SCLogError("invalid flag definition: %s", rawstr); + goto error; + } + + de->username = de->password = de->will = MQTT_DONT_CARE; + de->will_retain = de->clean_session = MQTT_DONT_CARE; + + strlcpy(copy, rawstr, sizeof(copy)); + char *xsaveptr = NULL; + char *flagv = strtok_r(copy, ",", &xsaveptr); + while (flagv != NULL) { + while (*flagv != '\0' && isblank(*flagv)) { + flagv++; + } + if (strlen(flagv) < 2) { + SCLogError("malformed flag value: %s", flagv); + goto error; + } else { + int offset = 0; + MQTTFlagState fs_to_set = MQTT_MUST_BE_SET; + if (flagv[0] == '!') { + /* negated flag */ + offset = 1; /* skip negation operator during comparison */ + fs_to_set = MQTT_CANT_BE_SET; + } + if (strcmp(flagv + offset, "username") == 0) { + if (de->username != MQTT_DONT_CARE) { + SCLogError("duplicate flag definition: %s", flagv); + goto error; + } + de->username = fs_to_set; + } else if (strcmp(flagv + offset, "password") == 0) { + if (de->password != MQTT_DONT_CARE) { + SCLogError("duplicate flag definition: %s", flagv); + goto error; + } + de->password = fs_to_set; + } else if (strcmp(flagv + offset, "will") == 0) { + if (de->will != MQTT_DONT_CARE) { + SCLogError("duplicate flag definition: %s", flagv); + goto error; + } + de->will = fs_to_set; + } else if (strcmp(flagv + offset, "will_retain") == 0) { + if (de->will_retain != MQTT_DONT_CARE) { + SCLogError("duplicate flag definition: %s", flagv); + goto error; + } + de->will_retain = fs_to_set; + } else if (strcmp(flagv + offset, "clean_session") == 0) { + if (de->clean_session != MQTT_DONT_CARE) { + SCLogError("duplicate flag definition: %s", flagv); + goto error; + } + de->clean_session = fs_to_set; + } else { + SCLogError("invalid flag definition: %s", flagv); + goto error; + } + } + flagv = strtok_r(NULL, ",", &xsaveptr); + } + + pcre2_match_data_free(match); + return de; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (de) + SCFree(de); + return NULL; +} + +/** + * \internal + * \brief this function is used to add the parsed type query into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectMQTTConnectFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectMQTTConnectFlagsData *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + de = DetectMQTTConnectFlagsParse(rawstr); + if (de == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNECT_FLAGS, (SigMatchCtx *)de, + mqtt_connect_flags_id) == NULL) { + goto error; + } + + return 0; + +error: + if (de != NULL) + SCFree(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectMQTTConnectFlagsData + * + * \param de pointer to DetectMQTTConnectFlagsData + */ +void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + if (de_ptr != NULL) + SCFree(de_ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test MQTTConnectFlagsTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnectFlagsTestParse01(void) +{ + DetectMQTTConnectFlagsData *de = NULL; + de = DetectMQTTConnectFlagsParse("username"); + FAIL_IF_NULL(de); + DetectMQTTConnectFlagsFree(NULL, de); + + de = DetectMQTTConnectFlagsParse("username,password,will,will_retain,clean_session"); + FAIL_IF_NULL(de); + DetectMQTTConnectFlagsFree(NULL, de); + + de = DetectMQTTConnectFlagsParse("!username,!password,!will,!will_retain,!clean_session"); + FAIL_IF_NULL(de); + DetectMQTTConnectFlagsFree(NULL, de); + + de = DetectMQTTConnectFlagsParse(" username,password"); + FAIL_IF_NULL(de); + DetectMQTTConnectFlagsFree(NULL, de); + + PASS; +} + +/** + * \test MQTTConnectFlagsTestParse02 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnectFlagsTestParse02(void) +{ + DetectMQTTConnectFlagsData *de = NULL; + de = DetectMQTTConnectFlagsParse("foobar"); + if (de) { + DetectMQTTConnectFlagsFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTConnectFlagsTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnectFlagsTestParse03(void) +{ + DetectMQTTConnectFlagsData *de = NULL; + de = DetectMQTTConnectFlagsParse("will,!"); + if (de) { + DetectMQTTConnectFlagsFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTConnectFlagsTestParse04 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnectFlagsTestParse04(void) +{ + DetectMQTTConnectFlagsData *de = NULL; + de = DetectMQTTConnectFlagsParse(""); + if (de) { + DetectMQTTConnectFlagsFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTConnectFlagsTestParse05 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTConnectFlagsTestParse05(void) +{ + DetectMQTTConnectFlagsData *de = NULL; + de = DetectMQTTConnectFlagsParse("username, username"); + if (de) { + DetectMQTTConnectFlagsFree(NULL, de); + FAIL; + } + de = DetectMQTTConnectFlagsParse("!username, username"); + if (de) { + DetectMQTTConnectFlagsFree(NULL, de); + FAIL; + } + de = DetectMQTTConnectFlagsParse("!username,password,!password"); + if (de) { + DetectMQTTConnectFlagsFree(NULL, de); + FAIL; + } + de = DetectMQTTConnectFlagsParse("will, username,password, !will, will"); + if (de) { + DetectMQTTConnectFlagsFree(NULL, de); + FAIL; + } + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for MQTTConnectFlags + */ +void MQTTConnectFlagsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MQTTConnectFlagsTestParse01", MQTTConnectFlagsTestParse01); + UtRegisterTest("MQTTConnectFlagsTestParse02", MQTTConnectFlagsTestParse02); + UtRegisterTest("MQTTConnectFlagsTestParse03", MQTTConnectFlagsTestParse03); + UtRegisterTest("MQTTConnectFlagsTestParse04", MQTTConnectFlagsTestParse04); + UtRegisterTest("MQTTConnectFlagsTestParse05", MQTTConnectFlagsTestParse05); +#endif /* UNITTESTS */ +} diff --git a/src/detect-mqtt-connect-flags.h b/src/app-layer/mqtt/detect-connect-flags.h similarity index 100% rename from src/detect-mqtt-connect-flags.h rename to src/app-layer/mqtt/detect-connect-flags.h diff --git a/src/app-layer/mqtt/detect-connect-password.c b/src/app-layer/mqtt/detect-connect-password.c new file mode 100644 index 000000000000..8592e889cda8 --- /dev/null +++ b/src/app-layer/mqtt/detect-connect-password.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.connect.password sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-connect-password.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.connect.password" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-password" +#define BUFFER_NAME "mqtt.connect.password" +#define BUFFER_DESC "MQTT CONNECT password" +static int g_buffer_id = 0; + +static int DetectMQTTConnectPasswordSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_connect_password(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTConnectPasswordRegister(void) +{ + /* mqtt.connect.password sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].desc = + "sticky buffer to match on the MQTT CONNECT password"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].Setup = DetectMQTTConnectPasswordSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-connect-password.h b/src/app-layer/mqtt/detect-connect-password.h similarity index 100% rename from src/detect-mqtt-connect-password.h rename to src/app-layer/mqtt/detect-connect-password.h diff --git a/src/app-layer/mqtt/detect-connect-protocol-string.c b/src/app-layer/mqtt/detect-connect-protocol-string.c new file mode 100644 index 000000000000..6b56ff063a6e --- /dev/null +++ b/src/app-layer/mqtt/detect-connect-protocol-string.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.connect.protocolstring sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-connect-protocol-string.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.connect.protocol_string" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-protocol_string" +#define BUFFER_NAME "mqtt.connect.protocol_string" +#define BUFFER_DESC "MQTT CONNECT protocol string" +static int g_buffer_id = 0; + +static int DetectMQTTConnectProtocolStringSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_connect_protocol_string(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTConnectProtocolStringRegister(void) +{ + /* mqtt.connect.protocol_string sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].desc = + "sticky buffer to match on the MQTT CONNECT protocol string"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].Setup = + DetectMQTTConnectProtocolStringSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-connect-protocol-string.h b/src/app-layer/mqtt/detect-connect-protocol-string.h similarity index 100% rename from src/detect-mqtt-connect-protocol-string.h rename to src/app-layer/mqtt/detect-connect-protocol-string.h diff --git a/src/app-layer/mqtt/detect-connect-username.c b/src/app-layer/mqtt/detect-connect-username.c new file mode 100644 index 000000000000..46f75f68b52c --- /dev/null +++ b/src/app-layer/mqtt/detect-connect-username.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.connect.username sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-connect-username.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.connect.username" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-username" +#define BUFFER_NAME "mqtt.connect.username" +#define BUFFER_DESC "MQTT CONNECT username" +static int g_buffer_id = 0; + +static int DetectMQTTConnectUsernameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_connect_username(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTConnectUsernameRegister(void) +{ + /* mqtt.connect.username sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].desc = + "sticky buffer to match on the MQTT CONNECT username"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].Setup = DetectMQTTConnectUsernameSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-connect-username.h b/src/app-layer/mqtt/detect-connect-username.h similarity index 100% rename from src/detect-mqtt-connect-username.h rename to src/app-layer/mqtt/detect-connect-username.h diff --git a/src/app-layer/mqtt/detect-connect-willmessage.c b/src/app-layer/mqtt/detect-connect-willmessage.c new file mode 100644 index 000000000000..a36761d283da --- /dev/null +++ b/src/app-layer/mqtt/detect-connect-willmessage.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.connect.willmessage sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-connect-willmessage.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.connect.willmessage" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willmessage" +#define BUFFER_NAME "mqtt.connect.willmessage" +#define BUFFER_DESC "MQTT CONNECT will message" +static int g_buffer_id = 0; + +static int DetectMQTTConnectWillMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_connect_willmessage(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTConnectWillMessageRegister(void) +{ + /* mqtt.connect.willmessage sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].desc = + "sticky buffer to match on the MQTT CONNECT will message"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].Setup = DetectMQTTConnectWillMessageSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-connect-willmessage.h b/src/app-layer/mqtt/detect-connect-willmessage.h similarity index 100% rename from src/detect-mqtt-connect-willmessage.h rename to src/app-layer/mqtt/detect-connect-willmessage.h diff --git a/src/app-layer/mqtt/detect-connect-willtopic.c b/src/app-layer/mqtt/detect-connect-willtopic.c new file mode 100644 index 000000000000..302cacc1475e --- /dev/null +++ b/src/app-layer/mqtt/detect-connect-willtopic.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.connect.willtopic sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-connect-willtopic.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.connect.willtopic" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willtopic" +#define BUFFER_NAME "mqtt.connect.willtopic" +#define BUFFER_DESC "MQTT CONNECT will topic" +static int g_buffer_id = 0; + +static int DetectMQTTConnectWillTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_connect_willtopic(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTConnectWillTopicRegister(void) +{ + /* mqtt.connect.willtopic sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].desc = + "sticky buffer to match on the MQTT CONNECT will topic"; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].Setup = DetectMQTTConnectWillTopicSetup; + sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-connect-willtopic.h b/src/app-layer/mqtt/detect-connect-willtopic.h similarity index 100% rename from src/detect-mqtt-connect-willtopic.h rename to src/app-layer/mqtt/detect-connect-willtopic.h diff --git a/src/app-layer/mqtt/detect-flags.c b/src/app-layer/mqtt/detect-flags.c new file mode 100644 index 000000000000..a08ecd80edab --- /dev/null +++ b/src/app-layer/mqtt/detect-flags.c @@ -0,0 +1,354 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/mqtt/detect-flags.h" +#include "util/unittest.h" + +#include "rust.h" + +#define PARSE_REGEX "(?: *,?!?(?:retain|dup))+" +static DetectParseRegex parse_regex; + +static int mqtt_flags_id = 0; + +static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectMQTTFlagsSetup(DetectEngineCtx *, Signature *, const char *); +void MQTTFlagsRegisterTests(void); +void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *); + +typedef struct DetectMQTTFlagsData_ { + MQTTFlagState retain, dup; +} DetectMQTTFlagsData; + +/** + * \brief Registration function for mqtt.flags: keyword + */ +void DetectMQTTFlagsRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_FLAGS].name = "mqtt.flags"; + sigmatch_table[DETECT_AL_MQTT_FLAGS].desc = "match MQTT fixed header flags"; + sigmatch_table[DETECT_AL_MQTT_FLAGS].url = "/rules/mqtt-keywords.html#mqtt-flags"; + sigmatch_table[DETECT_AL_MQTT_FLAGS].AppLayerTxMatch = DetectMQTTFlagsMatch; + sigmatch_table[DETECT_AL_MQTT_FLAGS].Setup = DetectMQTTFlagsSetup; + sigmatch_table[DETECT_AL_MQTT_FLAGS].Free = DetectMQTTFlagsFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_MQTT_FLAGS].RegisterTests = MQTTFlagsRegisterTests; +#endif + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2( + "mqtt.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + + mqtt_flags_id = DetectBufferTypeGetByName("mqtt.flags"); +} + +/** + * \internal + * \brief Function to match fixed header flags of an MQTT Tx + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTFlagsData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectMQTTFlagsData *de = (const DetectMQTTFlagsData *)ctx; + + if (!de) + return 0; + + return rs_mqtt_tx_has_flags(txv, de->retain, de->dup); +} + +/** + * \internal + * \brief This function is used to parse options passed via mqtt.flags: keyword + * + * \param rawstr Pointer to the user provided options + * + * \retval de pointer to DetectMQTTFlagsData on success + * \retval NULL on failure + */ +static DetectMQTTFlagsData *DetectMQTTFlagsParse(const char *rawstr) +{ + + DetectMQTTFlagsData *de = SCCalloc(1, sizeof(DetectMQTTFlagsData)); + if (unlikely(de == NULL)) + return NULL; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); + if (ret < 1) { + SCLogError("invalid flag definition: %s", rawstr); + if (match) { + pcre2_match_data_free(match); + } + SCFree(de); + return NULL; + } + + de->retain = de->dup = MQTT_DONT_CARE; + + char copy[strlen(rawstr) + 1]; + strlcpy(copy, rawstr, sizeof(copy)); + char *xsaveptr = NULL; + + /* Iterate through comma-separated string... */ + char *flagv = strtok_r(copy, ",", &xsaveptr); + while (flagv != NULL) { + /* skip blanks */ + while (*flagv != '\0' && isblank(*flagv)) { + flagv++; + } + if (strlen(flagv) < 2) { + /* flags have a minimum length */ + SCLogError("malformed flag value: %s", flagv); + goto error; + } else { + int offset = 0; + MQTTFlagState fs_to_set = MQTT_MUST_BE_SET; + if (flagv[0] == '!') { + /* negated flag */ + offset = 1; /* skip negation operator during comparison */ + fs_to_set = MQTT_CANT_BE_SET; + } + if (strcmp(flagv + offset, "dup") == 0) { + if (de->dup != MQTT_DONT_CARE) { + SCLogError("duplicate flag definition: %s", flagv); + goto error; + } + de->dup = fs_to_set; + } else if (strcmp(flagv + offset, "retain") == 0) { + if (de->retain != MQTT_DONT_CARE) { + SCLogError("duplicate flag definition: %s", flagv); + goto error; + } + de->retain = fs_to_set; + } else { + SCLogError("invalid flag definition: %s", flagv); + goto error; + } + } + flagv = strtok_r(NULL, ",", &xsaveptr); + } + + pcre2_match_data_free(match); + return de; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (de) + SCFree(de); + return NULL; +} + +/** + * \internal + * \brief this function is used to add the parsed type query into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectMQTTFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectMQTTFlagsData *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + de = DetectMQTTFlagsParse(rawstr); + if (de == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_FLAGS, (SigMatchCtx *)de, mqtt_flags_id) == + NULL) { + goto error; + } + + return 0; + +error: + if (de != NULL) + SCFree(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectMQTTFlagsData + * + * \param de pointer to DetectMQTTFlagsData + */ +void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + if (de_ptr != NULL) + SCFree(de_ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test MQTTFlagsTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTFlagsTestParse01(void) +{ + DetectMQTTFlagsData *de = NULL; + + de = DetectMQTTFlagsParse("retain"); + FAIL_IF_NULL(de); + DetectMQTTFlagsFree(NULL, de); + + de = DetectMQTTFlagsParse("dup"); + FAIL_IF_NULL(de); + DetectMQTTFlagsFree(NULL, de); + + de = DetectMQTTFlagsParse("retain,dup"); + FAIL_IF_NULL(de); + DetectMQTTFlagsFree(NULL, de); + + de = DetectMQTTFlagsParse("dup, retain"); + FAIL_IF_NULL(de); + DetectMQTTFlagsFree(NULL, de); + + PASS; +} + +/** + * \test MQTTFlagsTestParse02 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTFlagsTestParse02(void) +{ + DetectMQTTFlagsData *de = NULL; + de = DetectMQTTFlagsParse("retain,!dup"); + FAIL_IF_NULL(de); + DetectMQTTFlagsFree(NULL, de); + + PASS; +} + +/** + * \test MQTTFlagsTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTFlagsTestParse03(void) +{ + DetectMQTTFlagsData *de = NULL; + de = DetectMQTTFlagsParse("ref"); + if (de) { + DetectMQTTFlagsFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTFlagsTestParse04 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTFlagsTestParse04(void) +{ + DetectMQTTFlagsData *de = NULL; + de = DetectMQTTFlagsParse("dup,!"); + if (de) { + DetectMQTTFlagsFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTFlagsTestParse05 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTFlagsTestParse05(void) +{ + DetectMQTTFlagsData *de = NULL; + de = DetectMQTTFlagsParse("dup,!dup"); + if (de) { + DetectMQTTFlagsFree(NULL, de); + FAIL; + } + + de = DetectMQTTFlagsParse("!retain,retain"); + if (de) { + DetectMQTTFlagsFree(NULL, de); + FAIL; + } + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for MQTTFlags + */ +void MQTTFlagsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MQTTFlagsTestParse01", MQTTFlagsTestParse01); + UtRegisterTest("MQTTFlagsTestParse02", MQTTFlagsTestParse02); + UtRegisterTest("MQTTFlagsTestParse03", MQTTFlagsTestParse03); + UtRegisterTest("MQTTFlagsTestParse04", MQTTFlagsTestParse04); + UtRegisterTest("MQTTFlagsTestParse05", MQTTFlagsTestParse05); +#endif /* UNITTESTS */ +} diff --git a/src/detect-mqtt-flags.h b/src/app-layer/mqtt/detect-flags.h similarity index 100% rename from src/detect-mqtt-flags.h rename to src/app-layer/mqtt/detect-flags.h diff --git a/src/app-layer/mqtt/detect-protocol-version.c b/src/app-layer/mqtt/detect-protocol-version.c new file mode 100644 index 000000000000..21826bbb0470 --- /dev/null +++ b/src/app-layer/mqtt/detect-protocol-version.c @@ -0,0 +1,247 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-uint.h" +#include "app-layer/mqtt/detect-protocol-version.h" +#include "util/byte.h" +#include "util/unittest.h" + +#include "rust.h" + +static int mqtt_protocol_version_id = 0; + +static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectMQTTProtocolVersionSetup(DetectEngineCtx *, Signature *, const char *); +void MQTTProtocolVersionRegisterTests(void); +void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *); + +/** + * \brief Registration function for mqtt.protocol_version: keyword + */ +void DetectMQTTProtocolVersionRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].name = "mqtt.protocol_version"; + sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].desc = "match MQTT protocol version"; + sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].url = + "/rules/mqtt-keywords.html#mqtt-protocol-version"; + sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].AppLayerTxMatch = + DetectMQTTProtocolVersionMatch; + sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Setup = DetectMQTTProtocolVersionSetup; + sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Free = DetectMQTTProtocolVersionFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].RegisterTests = + MQTTProtocolVersionRegisterTests; +#endif + + DetectAppLayerInspectEngineRegister2("mqtt.protocol_version", ALPROTO_MQTT, SIG_FLAG_TOSERVER, + 1, DetectEngineInspectGenericList, NULL); + + mqtt_protocol_version_id = DetectBufferTypeGetByName("mqtt.protocol_version"); +} + +/** + * \internal + * \brief Function to match protocol version of an MQTT Tx + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTProtocolVersionData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectU8Data *de = (const DetectU8Data *)ctx; + uint8_t version; + + version = rs_mqtt_tx_get_protocol_version(state); + + return DetectU8Match(version, de); +} + +/** + * \internal + * \brief this function is used to add the parsed sigmatch into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectMQTTProtocolVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectU8Data *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + de = DetectU8Parse(rawstr); + if (de == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_PROTOCOL_VERSION, (SigMatchCtx *)de, + mqtt_protocol_version_id) == NULL) { + goto error; + } + + return 0; + +error: + if (de != NULL) + rs_detect_u8_free(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectMQTTProtocolVersionData + * + * \param de pointer to DetectMQTTProtocolVersionData + */ +void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + rs_detect_u8_free(de_ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test MQTTProtocolVersionTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:3; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:3; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test MQTTProtocolVersionTestParse02 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse02(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:>3; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:<44; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test MQTTProtocolVersionTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:; sid:1; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test MQTTProtocolVersionTestParse04 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTProtocolVersionTestParse04(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (mqtt.protocol_version:<444; sid:1; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for MQTTProtocolVersion + */ +void MQTTProtocolVersionRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MQTTProtocolVersionTestParse01", MQTTProtocolVersionTestParse01); + UtRegisterTest("MQTTProtocolVersionTestParse02", MQTTProtocolVersionTestParse02); + UtRegisterTest("MQTTProtocolVersionTestParse03", MQTTProtocolVersionTestParse03); + UtRegisterTest("MQTTProtocolVersionTestParse04", MQTTProtocolVersionTestParse04); +#endif /* UNITTESTS */ +} diff --git a/src/detect-mqtt-protocol-version.h b/src/app-layer/mqtt/detect-protocol-version.h similarity index 100% rename from src/detect-mqtt-protocol-version.h rename to src/app-layer/mqtt/detect-protocol-version.h diff --git a/src/app-layer/mqtt/detect-publish-message.c b/src/app-layer/mqtt/detect-publish-message.c new file mode 100644 index 000000000000..eab49e4be575 --- /dev/null +++ b/src/app-layer/mqtt/detect-publish-message.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.publish.message sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-publish-message.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.publish.message" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-message" +#define BUFFER_NAME "mqtt.publish.message" +#define BUFFER_DESC "MQTT PUBLISH message" +static int g_buffer_id = 0; + +static int DetectMQTTPublishMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_publish_message(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTPublishMessageRegister(void) +{ + /* mqtt.publish.message sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].desc = + "sticky buffer to match on the MQTT PUBLISH message"; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].Setup = DetectMQTTPublishMessageSetup; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-publish-message.h b/src/app-layer/mqtt/detect-publish-message.h similarity index 100% rename from src/detect-mqtt-publish-message.h rename to src/app-layer/mqtt/detect-publish-message.h diff --git a/src/app-layer/mqtt/detect-publish-topic.c b/src/app-layer/mqtt/detect-publish-topic.c new file mode 100644 index 000000000000..c6d10d726e18 --- /dev/null +++ b/src/app-layer/mqtt/detect-publish-topic.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + * + * Implements the mqtt.publish.topic sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-publish-topic.h" +#include "rust.h" + +#define KEYWORD_NAME "mqtt.publish.topic" +#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-topic" +#define BUFFER_NAME "mqtt.publish.topic" +#define BUFFER_DESC "MQTT PUBLISH topic" +static int g_buffer_id = 0; + +static int DetectMQTTPublishTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_mqtt_tx_get_publish_topic(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectMQTTPublishTopicRegister(void) +{ + /* mqtt.publish.topic sticky buffer */ + sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].desc = + "sticky buffer to match on the MQTT PUBLISH topic"; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].Setup = DetectMQTTPublishTopicSetup; + sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_MQTT, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-mqtt-publish-topic.h b/src/app-layer/mqtt/detect-publish-topic.h similarity index 100% rename from src/detect-mqtt-publish-topic.h rename to src/app-layer/mqtt/detect-publish-topic.h diff --git a/src/app-layer/mqtt/detect-qos.c b/src/app-layer/mqtt/detect-qos.c new file mode 100644 index 000000000000..15c2b7568d38 --- /dev/null +++ b/src/app-layer/mqtt/detect-qos.c @@ -0,0 +1,253 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/mqtt/detect-qos.h" +#include "util/byte.h" +#include "util/unittest.h" + +#include "rust.h" + +static int mqtt_qos_id = 0; + +static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectMQTTQosSetup(DetectEngineCtx *, Signature *, const char *); +void MQTTQosRegisterTests(void); +void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *); + +/** + * \brief Registration function for mqtt.qos: keyword + */ +void DetectMQTTQosRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_QOS].name = "mqtt.qos"; + sigmatch_table[DETECT_AL_MQTT_QOS].desc = "match MQTT fixed header QOS level"; + sigmatch_table[DETECT_AL_MQTT_QOS].url = "/rules/mqtt-keywords.html#mqtt-qos"; + sigmatch_table[DETECT_AL_MQTT_QOS].AppLayerTxMatch = DetectMQTTQosMatch; + sigmatch_table[DETECT_AL_MQTT_QOS].Setup = DetectMQTTQosSetup; + sigmatch_table[DETECT_AL_MQTT_QOS].Free = DetectMQTTQosFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_MQTT_QOS].RegisterTests = MQTTQosRegisterTests; +#endif + + DetectAppLayerInspectEngineRegister2( + "mqtt.qos", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + + mqtt_qos_id = DetectBufferTypeGetByName("mqtt.qos"); +} + +/** + * \internal + * \brief Function to match fixed header QOS field of an MQTT Tx + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into uint8_t. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const uint8_t *de = (const uint8_t *)ctx; + + if (!de) + return 0; + + return rs_mqtt_tx_has_qos(txv, *de); +} + +/** + * \internal + * \brief This function is used to parse options passed via mqtt.qos: keyword + * + * \param rawstr Pointer to the user provided options + * + * \retval de pointer to DetectMQTTQosData on success + * \retval NULL on failure + */ +static uint8_t *DetectMQTTQosParse(const char *rawstr) +{ + uint8_t *de = NULL; + int ret = 0; + uint8_t val; + + ret = StringParseU8RangeCheck(&val, 10, 0, rawstr, 0, 2); + if (ret < 0) { + SCLogError("invalid MQTT QOS level: %s", rawstr); + return NULL; + } + + de = SCMalloc(sizeof(uint8_t)); + if (unlikely(de == NULL)) + return NULL; + *de = val; + + return de; +} + +/** + * \internal + * \brief this function is used to add the parsed sigmatch into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectMQTTQosSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + uint8_t *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + de = DetectMQTTQosParse(rawstr); + if (de == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_QOS, (SigMatchCtx *)de, mqtt_qos_id) == + NULL) { + goto error; + } + + return 0; + +error: + if (de != NULL) + SCFree(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectMQTTQosData + * + * \param de pointer to DetectMQTTQosData + */ +void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + if (de_ptr != NULL) + SCFree(de_ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test MQTTQosTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTQosTestParse01(void) +{ + uint8_t *de = NULL; + + de = DetectMQTTQosParse("0"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 0); + DetectMQTTQosFree(NULL, de); + + de = DetectMQTTQosParse(" 0"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 0); + DetectMQTTQosFree(NULL, de); + + de = DetectMQTTQosParse("1"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 1); + DetectMQTTQosFree(NULL, de); + + de = DetectMQTTQosParse("2"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 2); + DetectMQTTQosFree(NULL, de); + + PASS; +} + +/** + * \test MQTTQosTestParse02 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTQosTestParse02(void) +{ + uint8_t *de = NULL; + de = DetectMQTTQosParse("3"); + if (de) { + DetectMQTTQosFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTQosTestParse04 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTQosTestParse03(void) +{ + uint8_t *de = NULL; + de = DetectMQTTQosParse("12"); + if (de) { + DetectMQTTQosFree(NULL, de); + FAIL; + } + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for MQTTQos + */ +void MQTTQosRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MQTTQosTestParse01", MQTTQosTestParse01); + UtRegisterTest("MQTTQosTestParse02", MQTTQosTestParse02); + UtRegisterTest("MQTTQosTestParse03", MQTTQosTestParse03); +#endif /* UNITTESTS */ +} diff --git a/src/detect-mqtt-qos.h b/src/app-layer/mqtt/detect-qos.h similarity index 100% rename from src/detect-mqtt-qos.h rename to src/app-layer/mqtt/detect-qos.h diff --git a/src/app-layer/mqtt/detect-reason-code.c b/src/app-layer/mqtt/detect-reason-code.c new file mode 100644 index 000000000000..3ea8c5ef3636 --- /dev/null +++ b/src/app-layer/mqtt/detect-reason-code.c @@ -0,0 +1,288 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/mqtt/detect-reason-code.h" +#include "util/byte.h" +#include "util/unittest.h" + +#include "rust.h" + +#define PARSE_REGEX "^\\s*\\d+\\s*$" +static DetectParseRegex parse_regex; + +static int mqtt_reason_code_id = 0; + +static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectMQTTReasonCodeSetup(DetectEngineCtx *, Signature *, const char *); +void MQTTReasonCodeRegisterTests(void); +void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *); + +/** + * \brief Registration function for mqtt.reason_code: keyword + */ +void DetectMQTTReasonCodeRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].name = "mqtt.reason_code"; + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].alias = "mqtt.connack.return_code"; + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].desc = "match MQTT 5.0+ reason code"; + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].url = "/rules/mqtt-keywords.html#mqtt-reason-code"; + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].AppLayerTxMatch = DetectMQTTReasonCodeMatch; + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Setup = DetectMQTTReasonCodeSetup; + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Free = DetectMQTTReasonCodeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_MQTT_REASON_CODE].RegisterTests = MQTTReasonCodeRegisterTests; +#endif + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2("mqtt.reason_code", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectGenericList, NULL); + + mqtt_reason_code_id = DetectBufferTypeGetByName("mqtt.reason_code"); +} + +/** + * \internal + * \brief Function to match reason code of an MQTT 5.0 Tx + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTReasonCodeData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const uint8_t *de = (const uint8_t *)ctx; + uint8_t code; + + if (!de) + return 0; + + if (rs_mqtt_tx_get_reason_code(txv, &code) == 0) { + /* this function does not return a code that needs to be compared, + so we can just return the result of the check implemented in + Rust */ + return rs_mqtt_tx_unsuback_has_reason_code(txv, *de); + } else { + if (code == *de) + return 1; + } + return 0; +} + +/** + * \internal + * \brief This function is used to parse options passed via mqtt.reason_code: keyword + * + * \param rawstr Pointer to the user provided options + * + * \retval de pointer to DetectMQTTReasonCodeData on success + * \retval NULL on failure + */ +static uint8_t *DetectMQTTReasonCodeParse(const char *rawstr) +{ + uint8_t *de = NULL; + int ret = 0; + uint8_t val; + + ret = StringParseUint8(&val, 10, 0, rawstr); + if (ret < 0) { + SCLogError("invalid MQTT reason code: %s", rawstr); + return NULL; + } + + de = SCMalloc(sizeof(uint8_t)); + if (unlikely(de == NULL)) + return NULL; + *de = (uint8_t)val; + + return de; +} + +/** + * \internal + * \brief this function is used to add the parsed sigmatch into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectMQTTReasonCodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + uint8_t *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + de = DetectMQTTReasonCodeParse(rawstr); + if (de == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_REASON_CODE, (SigMatchCtx *)de, + mqtt_reason_code_id) == NULL) { + goto error; + } + + return 0; + +error: + if (de != NULL) + SCFree(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectMQTTReasonCodeData + * + * \param de pointer to DetectMQTTReasonCodeData + */ +void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + if (de_ptr != NULL) + SCFree(de_ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test MQTTReasonCodeTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTReasonCodeTestParse01(void) +{ + uint8_t *de = NULL; + + de = DetectMQTTReasonCodeParse("3"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 3); + DetectMQTTReasonCodeFree(NULL, de); + + de = DetectMQTTReasonCodeParse(" 4"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 4); + DetectMQTTReasonCodeFree(NULL, de); + + de = DetectMQTTReasonCodeParse(" 5"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 5); + DetectMQTTReasonCodeFree(NULL, de); + + de = DetectMQTTReasonCodeParse("255"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 255); + DetectMQTTReasonCodeFree(NULL, de); + + PASS; +} + +/** + * \test MQTTReasonCodeTestParse02 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTReasonCodeTestParse02(void) +{ + uint8_t *de = NULL; + de = DetectMQTTReasonCodeParse("6X"); + if (de) { + DetectMQTTReasonCodeFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTReasonCodeTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTReasonCodeTestParse03(void) +{ + uint8_t *de = NULL; + de = DetectMQTTReasonCodeParse(""); + if (de) { + DetectMQTTReasonCodeFree(NULL, de); + FAIL; + } + + PASS; +} + +/** + * \test MQTTReasonCodeTestParse04 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTReasonCodeTestParse04(void) +{ + uint8_t *de = NULL; + de = DetectMQTTReasonCodeParse("256"); + if (de) { + DetectMQTTReasonCodeFree(NULL, de); + FAIL; + } + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for MQTTReasonCode + */ +void MQTTReasonCodeRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MQTTReasonCodeTestParse01", MQTTReasonCodeTestParse01); + UtRegisterTest("MQTTReasonCodeTestParse02", MQTTReasonCodeTestParse02); + UtRegisterTest("MQTTReasonCodeTestParse03", MQTTReasonCodeTestParse03); + UtRegisterTest("MQTTReasonCodeTestParse04", MQTTReasonCodeTestParse04); +#endif /* UNITTESTS */ +} diff --git a/src/detect-mqtt-reason-code.h b/src/app-layer/mqtt/detect-reason-code.h similarity index 100% rename from src/detect-mqtt-reason-code.h rename to src/app-layer/mqtt/detect-reason-code.h diff --git a/src/app-layer/mqtt/detect-subscribe-topic.c b/src/app-layer/mqtt/detect-subscribe-topic.c new file mode 100644 index 000000000000..afa7e2d82d83 --- /dev/null +++ b/src/app-layer/mqtt/detect-subscribe-topic.c @@ -0,0 +1,242 @@ +/* Copyright (C) 2020-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "conf.h" +#include "decode.h" +#include "detect.h" +#include "detect-content.h" +#include "detect-parse.h" +#include "detect-pcre.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-subscribe-topic.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "rust-bindings.h" + +#include "threads.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" +#include "util/profiling.h" + +static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *); + +static int g_mqtt_subscribe_topic_buffer_id = 0; + +static uint32_t subscribe_topic_match_limit = 100; + +struct MQTTSubscribeTopicGetDataArgs { + uint32_t local_id; + void *txv; +}; + +static InspectionBuffer *MQTTSubscribeTopicGetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, + struct MQTTSubscribeTopicGetDataArgs *cbdata, int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + const uint8_t *data; + uint32_t data_len; + if (rs_mqtt_tx_get_subscribe_topic(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectMQTTSubscribeTopic(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while ((subscribe_topic_match_limit == 0) || local_id < subscribe_topic_match_limit) { + struct MQTTSubscribeTopicGetDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + MQTTSubscribeTopicGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmMQTTSubscribeTopic { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmMQTTSubscribeTopic; + +/** \brief MQTTSubscribeTopic MQTTSubscribeTopic Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxMQTTSubscribeTopic(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, + const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmMQTTSubscribeTopic *ctx = (const PrefilterMpmMQTTSubscribeTopic *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + while ((subscribe_topic_match_limit == 0) || local_id < subscribe_topic_match_limit) { + struct MQTTSubscribeTopicGetDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = + MQTTSubscribeTopicGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + local_id++; + } +} + +static void PrefilterMpmMQTTSubscribeTopicFree(void *ptr) +{ + if (ptr != NULL) + SCFree(ptr); +} + +static int PrefilterMpmMQTTSubscribeTopicRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmMQTTSubscribeTopic *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxMQTTSubscribeTopic, + mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, pectx, + PrefilterMpmMQTTSubscribeTopicFree, mpm_reg->pname); +} + +/** + * \brief Registration function for keyword: mqtt.subscribe.topic + */ +void DetectMQTTSubscribeTopicRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].name = "mqtt.subscribe.topic"; + sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].desc = + "sticky buffer to match MQTT SUBSCRIBE topic"; + sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].url = + "/rules/mqtt-keywords.html#mqtt-subscribe-topic"; + sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].Setup = DetectMQTTSubscribeTopicSetup; + sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + intmax_t val = 0; + if (ConfGetInt("app-layer.protocols.mqtt.subscribe-topic-match-limit", &val)) { + subscribe_topic_match_limit = val; + } + if (subscribe_topic_match_limit <= 0) { + SCLogDebug("Using unrestricted MQTT SUBSCRIBE topic matching"); + } else { + SCLogDebug("Using MQTT SUBSCRIBE topic match-limit setting of: %u", + subscribe_topic_match_limit); + } + + DetectAppLayerMpmRegister2("mqtt.subscribe.topic", SIG_FLAG_TOSERVER, 1, + PrefilterMpmMQTTSubscribeTopicRegister, NULL, ALPROTO_MQTT, 1); + + DetectAppLayerInspectEngineRegister2("mqtt.subscribe.topic", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectMQTTSubscribeTopic, NULL); + + DetectBufferTypeSetDescriptionByName("mqtt.subscribe.topic", "subscribe topic query"); + + g_mqtt_subscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.subscribe.topic"); + + DetectBufferTypeSupportsMultiInstance("mqtt.subscribe.topic"); +} + +/** + * \brief setup the sticky buffer keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_subscribe_topic_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + return 0; +} diff --git a/src/detect-mqtt-subscribe-topic.h b/src/app-layer/mqtt/detect-subscribe-topic.h similarity index 100% rename from src/detect-mqtt-subscribe-topic.h rename to src/app-layer/mqtt/detect-subscribe-topic.h diff --git a/src/app-layer/mqtt/detect-type.c b/src/app-layer/mqtt/detect-type.c new file mode 100644 index 000000000000..5e15d17a578b --- /dev/null +++ b/src/app-layer/mqtt/detect-type.c @@ -0,0 +1,252 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/mqtt/detect-type.h" +#include "util/unittest.h" + +#include "rust.h" + +static int mqtt_type_id = 0; + +static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectMQTTTypeSetup(DetectEngineCtx *, Signature *, const char *); +void MQTTTypeRegisterTests(void); +void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *); + +/** + * \brief Registration function for mqtt.type: keyword + */ +void DetectMQTTTypeRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_TYPE].name = "mqtt.type"; + sigmatch_table[DETECT_AL_MQTT_TYPE].desc = "match MQTT control packet type"; + sigmatch_table[DETECT_AL_MQTT_TYPE].url = "/rules/mqtt-keywords.html#mqtt-type"; + sigmatch_table[DETECT_AL_MQTT_TYPE].AppLayerTxMatch = DetectMQTTTypeMatch; + sigmatch_table[DETECT_AL_MQTT_TYPE].Setup = DetectMQTTTypeSetup; + sigmatch_table[DETECT_AL_MQTT_TYPE].Free = DetectMQTTTypeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_MQTT_TYPE].RegisterTests = MQTTTypeRegisterTests; +#endif + + DetectAppLayerInspectEngineRegister2( + "mqtt.type", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + + mqtt_type_id = DetectBufferTypeGetByName("mqtt.type"); +} + +/** + * \internal + * \brief Function to match control packet type of an MQTT Tx + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the transaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTTypeData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const uint8_t *de = (const uint8_t *)ctx; + + if (!de) + return 0; + + return rs_mqtt_tx_has_type(txv, *de); +} + +/** + * \internal + * \brief This function is used to parse options passed via mqtt.type: keyword + * + * \param rawstr Pointer to the user provided options + * + * \retval de pointer to DetectMQTTTypeData on success + * \retval NULL on failure + */ +static uint8_t *DetectMQTTTypeParse(const char *rawstr) +{ + uint8_t *de = NULL; + int ret = 0; + + ret = rs_mqtt_cstr_message_code(rawstr); + // negative value denotes invalid input + if (ret < 0) { + SCLogError("unknown mqtt.type value %s", rawstr); + goto error; + } + + de = SCMalloc(sizeof(uint8_t)); + if (unlikely(de == NULL)) + goto error; + + *de = (uint8_t)ret; + + return de; + +error: + if (de != NULL) + SCFree(de); + return NULL; +} + +/** + * \internal + * \brief this function is used to add the parsed type query into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectMQTTTypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + uint8_t *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + + de = DetectMQTTTypeParse(rawstr); + if (de == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_TYPE, (SigMatchCtx *)de, mqtt_type_id) == + NULL) { + goto error; + } + + return 0; + +error: + if (de != NULL) + SCFree(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectMQTTTypeData + * + * \param de pointer to DetectMQTTTypeData + */ +void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + if (de_ptr != NULL) + SCFree(de_ptr); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test MQTTTypeTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTTypeTestParse01(void) +{ + uint8_t *de = NULL; + de = DetectMQTTTypeParse("CONNECT"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 1); + DetectMQTTTypeFree(NULL, de); + + de = DetectMQTTTypeParse("PINGRESP"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 13); + DetectMQTTTypeFree(NULL, de); + + PASS; +} + +/** + * \test MQTTTypeTestParse02 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTTypeTestParse02(void) +{ + uint8_t *de = NULL; + de = DetectMQTTTypeParse("auth"); + FAIL_IF_NULL(de); + FAIL_IF_NOT(*de == 15); + DetectMQTTTypeFree(NULL, de); + + PASS; +} + +/** + * \test MQTTTypeTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int MQTTTypeTestParse03(void) +{ + uint8_t *de = NULL; + de = DetectMQTTTypeParse("invalidopt"); + if (de) { + DetectMQTTTypeFree(NULL, de); + FAIL; + } + + de = DetectMQTTTypeParse("unassigned"); + if (de) { + DetectMQTTTypeFree(NULL, de); + FAIL; + } + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for MQTTType + */ +void MQTTTypeRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MQTTTypeTestParse01", MQTTTypeTestParse01); + UtRegisterTest("MQTTTypeTestParse02", MQTTTypeTestParse02); + UtRegisterTest("MQTTTypeTestParse03", MQTTTypeTestParse03); +#endif /* UNITTESTS */ +} diff --git a/src/detect-mqtt-type.h b/src/app-layer/mqtt/detect-type.h similarity index 100% rename from src/detect-mqtt-type.h rename to src/app-layer/mqtt/detect-type.h diff --git a/src/app-layer/mqtt/detect-unsubscribe-topic.c b/src/app-layer/mqtt/detect-unsubscribe-topic.c new file mode 100644 index 000000000000..2d5f39ce0745 --- /dev/null +++ b/src/app-layer/mqtt/detect-unsubscribe-topic.c @@ -0,0 +1,242 @@ +/* Copyright (C) 2020-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "conf.h" +#include "decode.h" +#include "detect.h" +#include "detect-content.h" +#include "detect-parse.h" +#include "detect-pcre.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "app-layer/mqtt/detect-unsubscribe-topic.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "rust-bindings.h" + +#include "threads.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" +#include "util/profiling.h" + +static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *); + +static int g_mqtt_unsubscribe_topic_buffer_id = 0; + +static uint32_t unsubscribe_topic_match_limit = 100; + +struct MQTTUnsubscribeTopicGetDataArgs { + uint32_t local_id; + void *txv; +}; + +static InspectionBuffer *MQTTUnsubscribeTopicGetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, + struct MQTTUnsubscribeTopicGetDataArgs *cbdata, int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + const uint8_t *data; + uint32_t data_len; + if (rs_mqtt_tx_get_unsubscribe_topic(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectMQTTUnsubscribeTopic(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while ((unsubscribe_topic_match_limit == 0) || local_id < unsubscribe_topic_match_limit) { + struct MQTTUnsubscribeTopicGetDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + MQTTUnsubscribeTopicGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmMQTTUnsubscribeTopic { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmMQTTUnsubscribeTopic; + +/** \brief MQTTUnsubscribeTopic MQTTUnsubscribeTopic Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxMQTTUnsubscribeTopic(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, + const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmMQTTUnsubscribeTopic *ctx = (const PrefilterMpmMQTTUnsubscribeTopic *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + while ((unsubscribe_topic_match_limit == 0) || local_id < unsubscribe_topic_match_limit) { + struct MQTTUnsubscribeTopicGetDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = + MQTTUnsubscribeTopicGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + local_id++; + } +} + +static void PrefilterMpmMQTTUnsubscribeTopicFree(void *ptr) +{ + if (ptr != NULL) + SCFree(ptr); +} + +static int PrefilterMpmMQTTUnsubscribeTopicRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmMQTTUnsubscribeTopic *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxMQTTUnsubscribeTopic, + mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, pectx, + PrefilterMpmMQTTUnsubscribeTopicFree, mpm_reg->pname); +} + +/** + * \brief Registration function for keyword: mqtt.unsubscribe.topic + */ +void DetectMQTTUnsubscribeTopicRegister(void) +{ + sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].name = "mqtt.unsubscribe.topic"; + sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].desc = + "sticky buffer to match MQTT UNSUBSCRIBE topic"; + sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].url = + "/rules/mqtt-keywords.html#mqtt-unsubscribe-topic"; + sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].Setup = DetectMQTTUnsubscribeTopicSetup; + sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + intmax_t val = 0; + if (ConfGetInt("app-layer.protocols.mqtt.unsubscribe-topic-match-limit", &val)) { + unsubscribe_topic_match_limit = val; + } + if (unsubscribe_topic_match_limit <= 0) { + SCLogDebug("Using unrestricted MQTT UNSUBSCRIBE topic matching"); + } else { + SCLogDebug("Using MQTT UNSUBSCRIBE topic match-limit setting of: %i", + unsubscribe_topic_match_limit); + } + + DetectAppLayerMpmRegister2("mqtt.unsubscribe.topic", SIG_FLAG_TOSERVER, 1, + PrefilterMpmMQTTUnsubscribeTopicRegister, NULL, ALPROTO_MQTT, 1); + + DetectAppLayerInspectEngineRegister2("mqtt.unsubscribe.topic", ALPROTO_MQTT, SIG_FLAG_TOSERVER, + 1, DetectEngineInspectMQTTUnsubscribeTopic, NULL); + + DetectBufferTypeSetDescriptionByName("mqtt.unsubscribe.topic", "unsubscribe topic query"); + + g_mqtt_unsubscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.unsubscribe.topic"); + + DetectBufferTypeSupportsMultiInstance("mqtt.unsubscribe.topic"); +} + +/** + * \brief setup the sticky buffer keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_unsubscribe_topic_buffer_id) < 0) + return -1; + if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) + return -1; + return 0; +} diff --git a/src/detect-mqtt-unsubscribe-topic.h b/src/app-layer/mqtt/detect-unsubscribe-topic.h similarity index 100% rename from src/detect-mqtt-unsubscribe-topic.h rename to src/app-layer/mqtt/detect-unsubscribe-topic.h diff --git a/src/app-layer/mqtt/logger.c b/src/app-layer/mqtt/logger.c new file mode 100644 index 000000000000..590ac4299c74 --- /dev/null +++ b/src/app-layer/mqtt/logger.c @@ -0,0 +1,187 @@ +/* Copyright (C) 2020-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/mqtt/parser.h" +#include "app-layer/mqtt/logger.h" +#include "rust.h" + +#define MQTT_LOG_PASSWORDS BIT_U32(0) +#define MQTT_DEFAULTS (MQTT_LOG_PASSWORDS) + +typedef struct LogMQTTFileCtx_ { + uint32_t flags; + OutputJsonCtx *eve_ctx; +} LogMQTTFileCtx; + +typedef struct LogMQTTLogThread_ { + LogMQTTFileCtx *mqttlog_ctx; + uint32_t count; + OutputJsonThreadCtx *ctx; +} LogMQTTLogThread; + +bool JsonMQTTAddMetadata(void *vtx, JsonBuilder *js) +{ + return rs_mqtt_logger_log(vtx, MQTT_DEFAULTS, js); +} + +static int JsonMQTTLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + LogMQTTLogThread *thread = thread_data; + enum OutputJsonLogDirection dir; + + if (rs_mqtt_tx_is_toclient((MQTTTransaction *)tx)) { + dir = LOG_DIR_FLOW_TOCLIENT; + } else { + dir = LOG_DIR_FLOW_TOSERVER; + } + + JsonBuilder *js = CreateEveHeader(p, dir, "mqtt", NULL, thread->mqttlog_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_FAILED; + } + + if (!rs_mqtt_logger_log(tx, thread->mqttlog_ctx->flags, js)) + goto error; + + OutputJsonBuilderBuffer(js, thread->ctx); + jb_free(js); + + return TM_ECODE_OK; + +error: + jb_free(js); + return TM_ECODE_FAILED; +} + +static void OutputMQTTLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogMQTTFileCtx *mqttlog_ctx = (LogMQTTFileCtx *)output_ctx->data; + SCFree(mqttlog_ctx); + SCFree(output_ctx); +} + +static void JsonMQTTLogParseConfig(ConfNode *conf, LogMQTTFileCtx *mqttlog_ctx) +{ + const char *query = ConfNodeLookupChildValue(conf, "passwords"); + if (query != NULL) { + if (ConfValIsTrue(query)) { + mqttlog_ctx->flags |= MQTT_LOG_PASSWORDS; + } else { + mqttlog_ctx->flags &= ~MQTT_LOG_PASSWORDS; + } + } else { + mqttlog_ctx->flags |= MQTT_LOG_PASSWORDS; + } +} + +static OutputInitResult OutputMQTTLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ajt = parent_ctx->data; + + LogMQTTFileCtx *mqttlog_ctx = SCCalloc(1, sizeof(*mqttlog_ctx)); + if (unlikely(mqttlog_ctx == NULL)) { + return result; + } + mqttlog_ctx->eve_ctx = ajt; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(mqttlog_ctx); + return result; + } + output_ctx->data = mqttlog_ctx; + output_ctx->DeInit = OutputMQTTLogDeInitCtxSub; + + JsonMQTTLogParseConfig(conf, mqttlog_ctx); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_MQTT); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonMQTTLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogMQTTLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogMQTT. \"initdata\" is NULL."); + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->mqttlog_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->mqttlog_ctx->eve_ctx); + if (unlikely(thread->ctx == NULL)) { + SCFree(thread); + return TM_ECODE_FAILED; + } + + *data = (void *)thread; + + return TM_ECODE_OK; +} + +static TmEcode JsonMQTTLogThreadDeinit(ThreadVars *t, void *data) +{ + LogMQTTLogThread *thread = (LogMQTTLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonMQTTLogRegister(void) +{ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonMQTTLog", "eve-log.mqtt", + OutputMQTTLogInitSub, ALPROTO_MQTT, JsonMQTTLogger, JsonMQTTLogThreadInit, + JsonMQTTLogThreadDeinit, NULL); +} diff --git a/src/output-json-mqtt.h b/src/app-layer/mqtt/logger.h similarity index 100% rename from src/output-json-mqtt.h rename to src/app-layer/mqtt/logger.h diff --git a/src/app-layer/mqtt/parser.c b/src/app-layer/mqtt/parser.c new file mode 100644 index 000000000000..b881bd6e9df9 --- /dev/null +++ b/src/app-layer/mqtt/parser.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/misc.h" +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/mqtt/parser.h" +#include "rust.h" + +void RegisterMQTTParsers(void) +{ + SCLogDebug("Registering Rust mqtt parser."); + uint32_t max_msg_len = 1048576; /* default: 1MB */ + + if (AppLayerParserConfParserEnabled("tcp", "mqtt")) { + ConfNode *p = ConfGetNode("app-layer.protocols.mqtt.max-msg-length"); + if (p != NULL) { + uint32_t value; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError("invalid value for max-msg-length: %s", p->val); + } else { + max_msg_len = value; + } + } + rs_mqtt_register_parser(max_msg_len); + } +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_MQTT, MQTTParserRegisterTests); +#endif +} + +void MQTTParserRegisterTests(void) +{ +#ifdef UNITTESTS +#endif +} diff --git a/src/app-layer-mqtt.h b/src/app-layer/mqtt/parser.h similarity index 100% rename from src/app-layer-mqtt.h rename to src/app-layer/mqtt/parser.h diff --git a/src/app-layer/nfs/detect-procedure.c b/src/app-layer/nfs/detect-procedure.c new file mode 100644 index 000000000000..7de9677aef1d --- /dev/null +++ b/src/app-layer/nfs/detect-procedure.c @@ -0,0 +1,437 @@ +/* Copyright (C) 2017-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/nfs/detect-procedure.h" +#include "detect-engine-uint.h" + +#include "app-layer-parser.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" + +#include "app-layer/nfs/parser-tcp.h" +#include "rust.h" + +static int DetectNfsProcedureSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectNfsProcedureFree(DetectEngineCtx *, void *); +#ifdef UNITTESTS +static void DetectNfsProcedureRegisterTests(void); +#endif +static int g_nfs_request_buffer_id = 0; + +static int DetectNfsProcedureMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +/** + * \brief Registration function for nfs_procedure keyword. + */ +void DetectNfsProcedureRegister(void) +{ + sigmatch_table[DETECT_AL_NFS_PROCEDURE].name = "nfs_procedure"; + sigmatch_table[DETECT_AL_NFS_PROCEDURE].desc = "match NFS procedure"; + sigmatch_table[DETECT_AL_NFS_PROCEDURE].url = "/rules/nfs-keywords.html#procedure"; + sigmatch_table[DETECT_AL_NFS_PROCEDURE].Match = NULL; + sigmatch_table[DETECT_AL_NFS_PROCEDURE].AppLayerTxMatch = DetectNfsProcedureMatch; + sigmatch_table[DETECT_AL_NFS_PROCEDURE].Setup = DetectNfsProcedureSetup; + sigmatch_table[DETECT_AL_NFS_PROCEDURE].Free = DetectNfsProcedureFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_NFS_PROCEDURE].RegisterTests = DetectNfsProcedureRegisterTests; +#endif + + DetectAppLayerInspectEngineRegister2( + "nfs_request", ALPROTO_NFS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + + g_nfs_request_buffer_id = DetectBufferTypeGetByName("nfs_request"); + + SCLogDebug("g_nfs_request_buffer_id %d", g_nfs_request_buffer_id); +} + +/** + * \internal + * \brief Function to match procedure of a TX + * + * For 'file txs' + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectU32Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectNfsProcedureMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + const DetectU32Data *dd = (const DetectU32Data *)ctx; + uint16_t i; + for (i = 0; i < 256; i++) { + uint32_t procedure; + if (rs_nfs_tx_get_procedures(txv, i, &procedure) == 1) { + SCLogDebug("proc %u mode %u lo %u hi %u", procedure, dd->mode, dd->arg1, dd->arg2); + if (DetectU32Match(procedure, dd)) + SCReturnInt(1); + continue; + } + break; + } + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to parse options passed via tls validity keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectU32Data on success. + * \retval NULL on failure. + */ +static DetectU32Data *DetectNfsProcedureParse(const char *rawstr) +{ + return rs_detect_u32_parse_inclusive(rawstr); +} + +/** + * \brief Function to add the parsed tls validity field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectNfsProcedureSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectU32Data *dd = NULL; + + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_NFS) != 0) + return -1; + + dd = DetectNfsProcedureParse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + SCLogDebug("low %u hi %u", dd->arg1, dd->arg2); + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_NFS_PROCEDURE, (SigMatchCtx *)dd, + g_nfs_request_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectNfsProcedureFree(de_ctx, dd); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectU32Data. + * + * \param de_ptr Pointer to DetectU32Data. + */ +void DetectNfsProcedureFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} + +#ifdef UNITTESTS + +/** + * \test This is a test for a valid value 1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse01(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_EQ); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \test This is a test for a valid value >1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse02(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse(">1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_GT); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \test This is a test for a valid value <1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse03(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("<1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_LT); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \test This is a test for a valid value 1430000000<>1470000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse04(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("1430000001<>1470000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->arg2 == 1470000001 && dd->mode == DETECT_UINT_RA); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \test This is a test for a invalid value A. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse05(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("A"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value >1430000000<>1470000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse06(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse(">1430000000<>1470000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value 1430000000<>. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse07(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("1430000000<>"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value <>1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse08(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("<>1430000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value "". + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse09(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse(""); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value " ". + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse10(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse(" "); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value 1490000000<>1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse11(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("1490000000<>1430000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a valid value 1430000000 <> 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse12(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("1430000001 <> 1490000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->arg2 == 1490000001 && dd->mode == DETECT_UINT_RA); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \test This is a test for a valid value > 1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse13(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("> 1430000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_GT); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \test This is a test for a valid value < 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse14(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse("< 1490000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1490000000 && dd->mode == DETECT_UINT_LT); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \test This is a test for a valid value 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +static int ValidityTestParse15(void) +{ + DetectU32Data *dd = NULL; + dd = DetectNfsProcedureParse(" 1490000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->arg1 == 1490000000 && dd->mode == DETECT_UINT_EQ); + DetectNfsProcedureFree(NULL, dd); + PASS; +} + +/** + * \brief Register unit tests for nfs_procedure. + */ +void DetectNfsProcedureRegisterTests(void) +{ + UtRegisterTest("ValidityTestParse01", ValidityTestParse01); + UtRegisterTest("ValidityTestParse02", ValidityTestParse02); + UtRegisterTest("ValidityTestParse03", ValidityTestParse03); + UtRegisterTest("ValidityTestParse04", ValidityTestParse04); + UtRegisterTest("ValidityTestParse05", ValidityTestParse05); + UtRegisterTest("ValidityTestParse06", ValidityTestParse06); + UtRegisterTest("ValidityTestParse07", ValidityTestParse07); + UtRegisterTest("ValidityTestParse08", ValidityTestParse08); + UtRegisterTest("ValidityTestParse09", ValidityTestParse09); + UtRegisterTest("ValidityTestParse10", ValidityTestParse10); + UtRegisterTest("ValidityTestParse11", ValidityTestParse11); + UtRegisterTest("ValidityTestParse12", ValidityTestParse12); + UtRegisterTest("ValidityTestParse13", ValidityTestParse13); + UtRegisterTest("ValidityTestParse14", ValidityTestParse14); + UtRegisterTest("ValidityTestParse15", ValidityTestParse15); +} +#endif /* UNITTESTS */ diff --git a/src/app-layer/nfs/detect-procedure.h b/src/app-layer/nfs/detect-procedure.h new file mode 100644 index 000000000000..722b0be5cd71 --- /dev/null +++ b/src/app-layer/nfs/detect-procedure.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_NFS_PROCEDURE_H__ +#define __DETECT_NFS_PROCEDURE_H__ + +/* prototypes */ +void DetectNfsProcedureRegister(void); + +#endif /* __DETECT_NFS_PROCEDURE_H__ */ diff --git a/src/app-layer/nfs/detect-version.c b/src/app-layer/nfs/detect-version.c new file mode 100644 index 000000000000..cf638ba3dd78 --- /dev/null +++ b/src/app-layer/nfs/detect-version.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2017-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/nfs/detect-version.h" +#include "detect-engine-uint.h" + +#include "app-layer-parser.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" + +#include "app-layer/nfs/parser-tcp.h" +#include "rust.h" + +static int DetectNfsVersionSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectNfsVersionFree(DetectEngineCtx *de_ctx, void *); +static int g_nfs_request_buffer_id = 0; + +static int DetectNfsVersionMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +/** + * \brief Registration function for nfs_procedure keyword. + */ +void DetectNfsVersionRegister(void) +{ + sigmatch_table[DETECT_AL_NFS_VERSION].name = "nfs.version"; + sigmatch_table[DETECT_AL_NFS_VERSION].alias = "nfs_version"; + sigmatch_table[DETECT_AL_NFS_VERSION].desc = "match NFS version"; + sigmatch_table[DETECT_AL_NFS_VERSION].url = "/rules/nfs-keywords.html#version"; + sigmatch_table[DETECT_AL_NFS_VERSION].AppLayerTxMatch = DetectNfsVersionMatch; + sigmatch_table[DETECT_AL_NFS_VERSION].Setup = DetectNfsVersionSetup; + sigmatch_table[DETECT_AL_NFS_VERSION].Free = DetectNfsVersionFree; + // unit tests were the same as DetectNfsProcedureRegisterTests + DetectAppLayerInspectEngineRegister2( + "nfs_request", ALPROTO_NFS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + + g_nfs_request_buffer_id = DetectBufferTypeGetByName("nfs_request"); + + SCLogDebug("g_nfs_request_buffer_id %d", g_nfs_request_buffer_id); +} + +/** + * \internal + * \brief Function to match version of a TX + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectU32Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectNfsVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + const DetectU32Data *dd = (const DetectU32Data *)ctx; + uint32_t version; + rs_nfs_tx_get_version(txv, &version); + SCLogDebug("version %u mode %u lo %u hi %u", version, dd->mode, dd->arg1, dd->arg2); + if (DetectU32Match(version, dd)) + SCReturnInt(1); + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to parse options passed via tls validity keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectU32Data on success. + * \retval NULL on failure. + */ +static DetectU32Data *DetectNfsVersionParse(const char *rawstr) +{ + return rs_detect_u32_parse_inclusive(rawstr); +} + +/** + * \brief Function to add the parsed tls validity field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectNfsVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_NFS) != 0) + return -1; + + DetectU32Data *dd = DetectNfsVersionParse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed", rawstr); + return -1; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + SCLogDebug("low %u hi %u", dd->arg1, dd->arg2); + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_NFS_VERSION, (SigMatchCtx *)dd, + g_nfs_request_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectNfsVersionFree(de_ctx, dd); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectU32Data. + * + * \param de_ptr Pointer to DetectU32Data. + */ +void DetectNfsVersionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} diff --git a/src/app-layer/nfs/detect-version.h b/src/app-layer/nfs/detect-version.h new file mode 100644 index 000000000000..bba2738d2d99 --- /dev/null +++ b/src/app-layer/nfs/detect-version.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_NFS_VERSION_H__ +#define __DETECT_NFS_VERSION_H__ + +/* prototypes */ +void DetectNfsVersionRegister(void); + +#endif /* __DETECT_NFS_VERSION_H__ */ diff --git a/src/app-layer/nfs/logger.c b/src/app-layer/nfs/logger.c new file mode 100644 index 000000000000..3b7d88227111 --- /dev/null +++ b/src/app-layer/nfs/logger.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2015-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implement JSON/eve logging app-layer NFS. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/nfs/logger.h" + +#include "rust.h" + +bool EveNFSAddMetadataRPC(const Flow *f, uint64_t tx_id, JsonBuilder *jb) +{ + NFSState *state = FlowGetAppState(f); + if (state) { + NFSTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_NFS, state, tx_id); + if (tx) { + return rs_rpc_log_json_response(tx, jb); + } + } + return false; +} + +bool EveNFSAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb) +{ + NFSState *state = FlowGetAppState(f); + if (state) { + NFSTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_NFS, state, tx_id); + if (tx) { + return rs_nfs_log_json_response(state, tx, jb); + } + } + return false; +} + +static int JsonNFSLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + NFSTransaction *nfstx = tx; + OutputJsonThreadCtx *thread = thread_data; + + if (rs_nfs_tx_logging_is_filtered(state, nfstx)) + return TM_ECODE_OK; + + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "nfs", NULL, thread->ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_OK; + } + + jb_open_object(jb, "rpc"); + rs_rpc_log_json_response(tx, jb); + jb_close(jb); + + jb_open_object(jb, "nfs"); + rs_nfs_log_json_response(state, tx, jb); + jb_close(jb); + + MemBufferReset(thread->buffer); + OutputJsonBuilderBuffer(jb, thread); + jb_free(jb); + return TM_ECODE_OK; +} + +static OutputInitResult NFSLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_NFS); + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_NFS); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonNFSLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonNFSLog", "eve-log.nfs", NFSLogInitSub, + ALPROTO_NFS, JsonNFSLogger, JsonLogThreadInit, JsonLogThreadDeinit, NULL); + + SCLogDebug("NFS JSON logger registered."); +} diff --git a/src/output-json-nfs.h b/src/app-layer/nfs/logger.h similarity index 100% rename from src/output-json-nfs.h rename to src/app-layer/nfs/logger.h diff --git a/src/app-layer/nfs/parser-tcp.c b/src/app-layer/nfs/parser-tcp.c new file mode 100644 index 000000000000..95cfc6104d46 --- /dev/null +++ b/src/app-layer/nfs/parser-tcp.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2015-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * NFS application layer detector and parser. + * + * This implements a application layer for the NFS protocol + * running on port 2049. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/nfs/parser-tcp.h" + +#include "rust.h" + +static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; +static SuricataFileContext sfc = { &sbcfg }; + +void RegisterNFSTCPParsers(void) +{ + const char *proto_name = "nfs"; + + /* Check if NFSTCP TCP detection is enabled. If it does not exist in + * the configuration file then it will be enabled by default. */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + + rs_nfs_init(&sfc); + rs_nfs_register_parser(); + } +} diff --git a/src/app-layer-nfs-tcp.h b/src/app-layer/nfs/parser-tcp.h similarity index 100% rename from src/app-layer-nfs-tcp.h rename to src/app-layer/nfs/parser-tcp.h diff --git a/src/app-layer/nfs/parser-udp.c b/src/app-layer/nfs/parser-udp.c new file mode 100644 index 000000000000..225fe7133dbc --- /dev/null +++ b/src/app-layer/nfs/parser-udp.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2015-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * NFS application layer detector and parser + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/nfs/parser-udp.h" +#include "util/enum.h" + +#include "rust.h" + +/* Enum of app-layer events for an echo protocol. Normally you might + * have events for errors in parsing data, like unexpected data being + * received. For echo we'll make something up, and log an app-layer + * level alert if an empty message is received. + * + * Example rule: + * + * alert nfs any any -> any any (msg:"SURICATA NFS empty message"; \ + * app-layer-event:nfs.empty_message; sid:X; rev:Y;) + */ +enum { + NFS_DECODER_EVENT_EMPTY_MESSAGE, +}; + +SCEnumCharMap nfs_udp_decoder_event_table[] = { + { "EMPTY_MESSAGE", NFS_DECODER_EVENT_EMPTY_MESSAGE }, { NULL, 0 } +}; + +static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; +static SuricataFileContext sfc = { &sbcfg }; + +void RegisterNFSUDPParsers(void) +{ + rs_nfs_init(&sfc); + rs_nfs_udp_register_parser(); + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_NFS, NFSUDPParserRegisterTests); +#endif +} + +#ifdef UNITTESTS +#endif + +void NFSUDPParserRegisterTests(void) +{ +#ifdef UNITTESTS +#endif +} diff --git a/src/app-layer-nfs-udp.h b/src/app-layer/nfs/parser-udp.h similarity index 100% rename from src/app-layer-nfs-udp.h rename to src/app-layer/nfs/parser-udp.h diff --git a/src/app-layer/ntp/parser.c b/src/app-layer/ntp/parser.c new file mode 100644 index 000000000000..966bc31799f6 --- /dev/null +++ b/src/app-layer/ntp/parser.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * + * Parser for NTP application layer running on UDP port 123. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/ntp/parser.h" +#include "rust.h" + +void RegisterNTPParsers(void) +{ + rs_register_ntp_parser(); + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_NTP, NTPParserRegisterTests); +#endif +} + +#ifdef UNITTESTS +#endif + +void NTPParserRegisterTests(void) +{ +#ifdef UNITTESTS +#endif +} diff --git a/src/app-layer-ntp.h b/src/app-layer/ntp/parser.h similarity index 100% rename from src/app-layer-ntp.h rename to src/app-layer/ntp/parser.h diff --git a/src/app-layer/pgsql/logger.c b/src/app-layer/pgsql/logger.c new file mode 100644 index 000000000000..0e007ef2d5e1 --- /dev/null +++ b/src/app-layer/pgsql/logger.c @@ -0,0 +1,194 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Juliana Fajardini + * + * Implement JSON/eve logging for app-layer Pgsql. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/pgsql/logger.h" +#include "rust.h" + +#define PGSQL_LOG_PASSWORDS BIT_U32(0) + +typedef struct OutputPgsqlCtx_ { + uint32_t flags; + OutputJsonCtx *eve_ctx; +} OutputPgsqlCtx; + +typedef struct LogPgsqlLogThread_ { + OutputPgsqlCtx *pgsqllog_ctx; + OutputJsonThreadCtx *ctx; +} LogPgsqlLogThread; + +static int JsonPgsqlLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *txptr, uint64_t tx_id) +{ + LogPgsqlLogThread *thread = thread_data; + SCLogDebug("Logging pgsql transaction %" PRIu64 ".", tx_id); + + JsonBuilder *jb = + CreateEveHeader(p, LOG_DIR_FLOW, "pgsql", NULL, thread->pgsqllog_ctx->eve_ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_FAILED; + } + + jb_open_object(jb, "pgsql"); + if (!rs_pgsql_logger(txptr, thread->pgsqllog_ctx->flags, jb)) { + goto error; + } + jb_close(jb); + + OutputJsonBuilderBuffer(jb, thread->ctx); + jb_free(jb); + + return TM_ECODE_OK; + +error: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static void OutputPgsqlLogDeInitCtxSub(OutputCtx *output_ctx) +{ + OutputPgsqlCtx *pgsqllog_ctx = (OutputPgsqlCtx *)output_ctx->data; + SCFree(pgsqllog_ctx); + SCFree(output_ctx); +} + +static void JsonPgsqlLogParseConfig(ConfNode *conf, OutputPgsqlCtx *pgsqllog_ctx) +{ + pgsqllog_ctx->flags = ~0U; + + const char *query = ConfNodeLookupChildValue(conf, "passwords"); + if (query != NULL) { + if (ConfValIsTrue(query)) { + pgsqllog_ctx->flags |= PGSQL_LOG_PASSWORDS; + } else { + pgsqllog_ctx->flags &= ~PGSQL_LOG_PASSWORDS; + } + } else { + pgsqllog_ctx->flags &= ~PGSQL_LOG_PASSWORDS; + } +} + +static OutputInitResult OutputPgsqlLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ojc = parent_ctx->data; + + OutputPgsqlCtx *pgsql_ctx = SCCalloc(1, sizeof(OutputPgsqlCtx)); + if (unlikely(pgsql_ctx == NULL)) + return result; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(pgsql_ctx); + return result; + } + + pgsql_ctx->eve_ctx = ojc; + + output_ctx->data = pgsql_ctx; + output_ctx->DeInit = OutputPgsqlLogDeInitCtxSub; + + JsonPgsqlLogParseConfig(conf, pgsql_ctx); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_PGSQL); + + SCLogDebug("PostgreSQL log sub-module initialized."); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonPgsqlLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogPgsqlLogThread *thread = SCCalloc(1, sizeof(LogPgsqlLogThread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogPgsql. \"initdata\" is NULL."); + goto error_exit; + } + + thread->pgsqllog_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->pgsqllog_ctx->eve_ctx); + if (!thread->ctx) { + goto error_exit; + } + *data = (void *)thread; + + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonPgsqlLogThreadDeinit(ThreadVars *t, void *data) +{ + LogPgsqlLogThread *thread = (LogPgsqlLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonPgsqlLogRegister(void) +{ + /* PGSQL_START_REMOVE */ + if (ConfGetNode("app-layer.protocols.pgsql") == NULL) { + SCLogDebug("Disabling Pgsql eve-logger"); + return; + } + /* PGSQL_END_REMOVE */ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonPgsqlLog", "eve-log.pgsql", + OutputPgsqlLogInitSub, ALPROTO_PGSQL, JsonPgsqlLogger, JsonPgsqlLogThreadInit, + JsonPgsqlLogThreadDeinit, NULL); + + SCLogDebug("PostgreSQL JSON logger registered."); +} diff --git a/src/output-json-pgsql.h b/src/app-layer/pgsql/logger.h similarity index 100% rename from src/output-json-pgsql.h rename to src/app-layer/pgsql/logger.h diff --git a/src/app-layer/quic/detect-cyu-hash.c b/src/app-layer/quic/detect-cyu-hash.c new file mode 100644 index 000000000000..d71424bf42d6 --- /dev/null +++ b/src/app-layer/quic/detect-cyu-hash.c @@ -0,0 +1,434 @@ +/* Copyright (C) 2021-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * Implements the quic.cyu.hash sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/quic/detect-cyu-hash.h" +#include "detect-engine-build.h" +#include "rust.h" +#include "util/profiling.h" + +#ifdef UNITTESTS +static void DetectQuicCyuHashRegisterTests(void); +#endif + +#define KEYWORD_NAME "quic.cyu.hash" +#define KEYWORD_DOC "quic-cyu.html#quic-cyu-hash" +#define BUFFER_NAME "quic.cyu.hash" +#define BUFFER_DESC "QUIC CYU Hash" +static int g_buffer_id = 0; + +struct QuicHashGetDataArgs { + uint32_t local_id; /**< used as index into thread inspect array */ + void *txv; +}; + +static int DetectQuicCyuHashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *QuicHashGetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, struct QuicHashGetDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + const uint8_t *data; + uint32_t data_len; + if (rs_quic_tx_get_cyu_hash(cbdata->txv, (uint16_t)cbdata->local_id, &data, &data_len) == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectQuicHash(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct QuicHashGetDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + QuicHashGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +typedef struct PrefilterMpmQuicHash { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmQuicHash; + +/** \brief QuicHash Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxQuicHash(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmQuicHash *ctx = (const PrefilterMpmQuicHash *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + while (1) { + // loop until we get a NULL + + struct QuicHashGetDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = QuicHashGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static void PrefilterMpmQuicHashFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmQuicHashRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, + const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmQuicHash *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxQuicHash, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmQuicHashFree, mpm_reg->pname); +} + +static bool DetectQuicHashValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = BUFFER_NAME " should not be used together with " + "nocase, since the rule is automatically " + "lowercased anyway which makes nocase redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + } + + if (cd->content_len != 32) { + *sigerror = "Invalid length of the specified" BUFFER_NAME " (should " + "be 32 characters long). This rule will therefore " + "never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + for (size_t i = 0; i < cd->content_len; ++i) { + if (!isxdigit(cd->content[i])) { + *sigerror = "Invalid " BUFFER_NAME + " string (should be string of hexadecimal characters)." + "This rule will therefore never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + } + } + } + return true; +} + +void DetectQuicCyuHashRegister(void) +{ + /* quic.cyu.hash sticky buffer */ + sigmatch_table[DETECT_AL_QUIC_CYU_HASH].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_QUIC_CYU_HASH].desc = "sticky buffer to match on the QUIC CYU hash"; + sigmatch_table[DETECT_AL_QUIC_CYU_HASH].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_QUIC_CYU_HASH].Setup = DetectQuicCyuHashSetup; + sigmatch_table[DETECT_AL_QUIC_CYU_HASH].flags |= SIGMATCH_NOOPT; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_QUIC_CYU_HASH].RegisterTests = DetectQuicCyuHashRegisterTests; +#endif + + DetectAppLayerMpmRegister2( + BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterMpmQuicHashRegister, NULL, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2( + BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 0, DetectEngineInspectQuicHash, NULL); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectQuicHashValidateCallback); + + DetectBufferTypeSupportsMultiInstance(BUFFER_NAME); +} + +#ifdef UNITTESTS +#include "app-layer-parser.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "flow-util.h" +#include "detect-engine-alert.h" + +/** + * \test DetectQuicCyuHashTest01 is a test for a valid quic packet, matching + * on the cyu hash + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DetectQuicCyuHashTest01(void) +{ + /* quic packet */ + // clang-format off + uint8_t buf[] = { 0xc3, 0x51, 0x30, 0x34, 0x36, 0x50, 0x76, 0xd8, 0x63, 0xb7, 0x54, 0xf7, 0xab, + 0x32, 0x00, 0x00, 0x00, 0x01, 0x54, 0xfd, 0xf4, 0x79, 0x48, 0x76, 0xd0, 0x87, 0x58, 0x8d, + 0x26, 0x8f, 0xa0, 0x01, 0x04, 0x00, 0x43, 0x48, 0x4c, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x50, + 0x41, 0x44, 0x00, 0xe4, 0x02, 0x00, 0x00, 0x53, 0x4e, 0x49, 0x00, 0xf7, 0x02, 0x00, 0x00, + 0x56, 0x45, 0x52, 0x00, 0xfb, 0x02, 0x00, 0x00, 0x43, 0x43, 0x53, 0x00, 0x0b, 0x03, 0x00, + 0x00, 0x55, 0x41, 0x49, 0x44, 0x2c, 0x03, 0x00, 0x00, 0x54, 0x43, 0x49, 0x44, 0x30, 0x03, + 0x00, 0x00, 0x50, 0x44, 0x4d, 0x44, 0x34, 0x03, 0x00, 0x00, 0x53, 0x4d, 0x48, 0x4c, 0x38, + 0x03, 0x00, 0x00, 0x49, 0x43, 0x53, 0x4c, 0x3c, 0x03, 0x00, 0x00, 0x4e, 0x4f, 0x4e, 0x50, + 0x5c, 0x03, 0x00, 0x00, 0x4d, 0x49, 0x44, 0x53, 0x60, 0x03, 0x00, 0x00, 0x53, 0x43, 0x4c, + 0x53, 0x64, 0x03, 0x00, 0x00, 0x43, 0x53, 0x43, 0x54, 0x64, 0x03, 0x00, 0x00, 0x43, 0x4f, + 0x50, 0x54, 0x64, 0x03, 0x00, 0x00, 0x49, 0x52, 0x54, 0x54, 0x68, 0x03, 0x00, 0x00, 0x43, + 0x46, 0x43, 0x57, 0x6c, 0x03, 0x00, 0x00, 0x53, 0x46, 0x43, 0x57, 0x70, 0x03, 0x00, 0x00, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x51, 0x30, 0x34, 0x36, 0x01, 0xe8, + 0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8, 0x7e, 0xed, 0x80, 0x86, 0xa2, 0x15, 0x82, 0x91, 0x43, + 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x37, 0x39, 0x2e, 0x30, 0x2e, 0x33, 0x39, 0x34, 0x35, + 0x2e, 0x31, 0x31, 0x37, 0x20, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x78, 0x38, 0x36, 0x5f, + 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x58, 0x35, 0x30, 0x39, 0x01, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x82, 0x88, 0x09, 0x00, 0xfa, 0x0f, 0xde, 0xb7, 0x2e, 0x7e, 0x6c, 0x78, + 0xcc, 0x09, 0x65, 0xab, 0x06, 0x0c, 0x31, 0x05, 0xfa, 0xd9, 0xa2, 0x0b, 0xdd, 0x74, 0x5c, + 0x28, 0xdf, 0x7b, 0x74, 0x23, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x43, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + // clang-format on + + Flow f; + void *quic_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 443); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_UDP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW; + p->flowflags |= FLOW_PKT_TOSERVER; + f.alproto = ALPROTO_QUIC; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, + "alert quic any any -> any any " + "(msg:\"Test QUIC CYU hash\"; " + "quic.cyu.hash; content:\"910a5e3a4d51593bd59a44611544f209\"; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_QUIC, STREAM_TOSERVER, buf, sizeof(buf)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + quic_state = f.alstate; + FAIL_IF_NULL(quic_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert, but it should have: "); + FAIL; + } + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +static void DetectQuicCyuHashRegisterTests(void) +{ + UtRegisterTest("DetectQuicCyuHashTest01", DetectQuicCyuHashTest01); +} + +#endif /* UNITTESTS */ diff --git a/src/detect-quic-cyu-hash.h b/src/app-layer/quic/detect-cyu-hash.h similarity index 100% rename from src/detect-quic-cyu-hash.h rename to src/app-layer/quic/detect-cyu-hash.h diff --git a/src/app-layer/quic/detect-cyu-string.c b/src/app-layer/quic/detect-cyu-string.c new file mode 100644 index 000000000000..56eac16fd842 --- /dev/null +++ b/src/app-layer/quic/detect-cyu-string.c @@ -0,0 +1,391 @@ +/* Copyright (C) 2021-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * Implements the quic.cyu.string sticky buffer + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/quic/detect-cyu-string.h" +#include "detect-engine-build.h" +#include "rust.h" +#include "util/profiling.h" + +#ifdef UNITTESTS +static void DetectQuicCyuStringRegisterTests(void); +#endif + +#define KEYWORD_NAME "quic.cyu.string" +#define KEYWORD_DOC "quic-cyu.html#quic-cyu-string" +#define BUFFER_NAME "quic.cyu.string" +#define BUFFER_DESC "QUIC CYU String" +static int g_buffer_id = 0; + +struct QuicStringGetDataArgs { + uint32_t local_id; /**< used as index into thread inspect array */ + void *txv; +}; + +static int DetectQuicCyuStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *QuicStringGetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, struct QuicStringGetDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL) + return NULL; + if (buffer->initialized) + return buffer; + + const uint8_t *data; + uint32_t data_len; + if (rs_quic_tx_get_cyu_string(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, data, data_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectQuicString(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint32_t local_id = 0; + + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + while (1) { + struct QuicStringGetDataArgs cbdata = { + local_id, + txv, + }; + InspectionBuffer *buffer = + QuicStringGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + local_id++; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +/** \brief QuicString Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxQuicString(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + uint32_t local_id = 0; + while (1) { + // loop until we get a NULL + + struct QuicStringGetDataArgs cbdata = { local_id, txv }; + InspectionBuffer *buffer = QuicStringGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + local_id++; + } +} + +static void PrefilterMpmListIdFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmListIdRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, + const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxQuicString, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmListIdFree, mpm_reg->pname); +} + +void DetectQuicCyuStringRegister(void) +{ + /* quic.cyu.string sticky buffer */ + sigmatch_table[DETECT_AL_QUIC_CYU_STRING].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_QUIC_CYU_STRING].desc = + "sticky buffer to match on the QUIC CYU string"; + sigmatch_table[DETECT_AL_QUIC_CYU_STRING].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_QUIC_CYU_STRING].Setup = DetectQuicCyuStringSetup; + sigmatch_table[DETECT_AL_QUIC_CYU_STRING].flags |= SIGMATCH_NOOPT; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_QUIC_CYU_STRING].RegisterTests = DetectQuicCyuStringRegisterTests; +#endif + + DetectAppLayerMpmRegister2( + BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterMpmListIdRegister, NULL, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2( + BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 0, DetectEngineInspectQuicString, NULL); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + DetectBufferTypeSupportsMultiInstance(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} + +#ifdef UNITTESTS +#include "app-layer-parser.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "flow-util.h" +#include "detect-engine-alert.h" + +/** + * \test DetectQuicCyuStringTest01 is a test for a valid quic packet, matching + * on the cyu string + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DetectQuicCyuStringTest01(void) +{ + /* quic packet */ + // clang-format off + uint8_t buf[] = { 0xc3, 0x51, 0x30, 0x34, 0x36, 0x50, 0x76, 0xd8, 0x63, 0xb7, 0x54, 0xf7, 0xab, + 0x32, 0x00, 0x00, 0x00, 0x01, 0x54, 0xfd, 0xf4, 0x79, 0x48, 0x76, 0xd0, 0x87, 0x58, 0x8d, + 0x26, 0x8f, 0xa0, 0x01, 0x04, 0x00, 0x43, 0x48, 0x4c, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x50, + 0x41, 0x44, 0x00, 0xe4, 0x02, 0x00, 0x00, 0x53, 0x4e, 0x49, 0x00, 0xf7, 0x02, 0x00, 0x00, + 0x56, 0x45, 0x52, 0x00, 0xfb, 0x02, 0x00, 0x00, 0x43, 0x43, 0x53, 0x00, 0x0b, 0x03, 0x00, + 0x00, 0x55, 0x41, 0x49, 0x44, 0x2c, 0x03, 0x00, 0x00, 0x54, 0x43, 0x49, 0x44, 0x30, 0x03, + 0x00, 0x00, 0x50, 0x44, 0x4d, 0x44, 0x34, 0x03, 0x00, 0x00, 0x53, 0x4d, 0x48, 0x4c, 0x38, + 0x03, 0x00, 0x00, 0x49, 0x43, 0x53, 0x4c, 0x3c, 0x03, 0x00, 0x00, 0x4e, 0x4f, 0x4e, 0x50, + 0x5c, 0x03, 0x00, 0x00, 0x4d, 0x49, 0x44, 0x53, 0x60, 0x03, 0x00, 0x00, 0x53, 0x43, 0x4c, + 0x53, 0x64, 0x03, 0x00, 0x00, 0x43, 0x53, 0x43, 0x54, 0x64, 0x03, 0x00, 0x00, 0x43, 0x4f, + 0x50, 0x54, 0x64, 0x03, 0x00, 0x00, 0x49, 0x52, 0x54, 0x54, 0x68, 0x03, 0x00, 0x00, 0x43, + 0x46, 0x43, 0x57, 0x6c, 0x03, 0x00, 0x00, 0x53, 0x46, 0x43, 0x57, 0x70, 0x03, 0x00, 0x00, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x51, 0x30, 0x34, 0x36, 0x01, 0xe8, + 0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8, 0x7e, 0xed, 0x80, 0x86, 0xa2, 0x15, 0x82, 0x91, 0x43, + 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x37, 0x39, 0x2e, 0x30, 0x2e, 0x33, 0x39, 0x34, 0x35, + 0x2e, 0x31, 0x31, 0x37, 0x20, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x78, 0x38, 0x36, 0x5f, + 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x58, 0x35, 0x30, 0x39, 0x01, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x82, 0x88, 0x09, 0x00, 0xfa, 0x0f, 0xde, 0xb7, 0x2e, 0x7e, 0x6c, 0x78, + 0xcc, 0x09, 0x65, 0xab, 0x06, 0x0c, 0x31, 0x05, 0xfa, 0xd9, 0xa2, 0x0b, 0xdd, 0x74, 0x5c, + 0x28, 0xdf, 0x7b, 0x74, 0x23, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x43, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + // clang-format on + + Flow f; + void *quic_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 443); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_UDP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW; + p->flowflags |= FLOW_PKT_TOSERVER; + f.alproto = ALPROTO_QUIC; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert quic any any -> any any " + "(msg:\"Test QUIC CYU string\"; " + "quic.cyu.string; " + "content:\"46,PAD-SNI-VER-CCS-UAID-TCID-PDMD-SMHL-ICSL-NONP-" + "MIDS-SCLS-CSCT-COPT-IRTT-CFCW-SFCW\"; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_QUIC, STREAM_TOSERVER, buf, sizeof(buf)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FAIL; + } + + quic_state = f.alstate; + FAIL_IF_NULL(quic_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sig 1 didn't alert, but it should have: "); + FAIL; + } + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +/** + * \brief this function registers unit tests for Quic Cyu String + */ +static void DetectQuicCyuStringRegisterTests(void) +{ + UtRegisterTest("DetectQuicCyuStringTest01", DetectQuicCyuStringTest01); +} + +#endif /* UNITTESTS */ diff --git a/src/detect-quic-cyu-string.h b/src/app-layer/quic/detect-cyu-string.h similarity index 100% rename from src/detect-quic-cyu-string.h rename to src/app-layer/quic/detect-cyu-string.h diff --git a/src/app-layer/quic/detect-sni.c b/src/app-layer/quic/detect-sni.c new file mode 100644 index 000000000000..a5c74839e24e --- /dev/null +++ b/src/app-layer/quic/detect-sni.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * Implements the quic.sni + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-mpm.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-uint.h" +#include "app-layer/quic/detect-sni.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "rust.h" + +#ifdef UNITTESTS +static void DetectQuicSniRegisterTests(void); +#endif + +#define BUFFER_NAME "quic_sni" +#define KEYWORD_NAME "quic.sni" +#define KEYWORD_ID DETECT_AL_QUIC_SNI + +static int quic_sni_id = 0; + +static int DetectQuicSniSetup(DetectEngineCtx *, Signature *, const char *); + +static InspectionBuffer *GetSniData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_quic_tx_get_sni(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +/** + * \brief Registration function for quic.sni: keyword + */ +void DetectQuicSniRegister(void) +{ + sigmatch_table[DETECT_AL_QUIC_SNI].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_QUIC_SNI].desc = "match Quic sni"; + sigmatch_table[DETECT_AL_QUIC_SNI].url = "/rules/quic-keywords.html#quic-sni"; + sigmatch_table[DETECT_AL_QUIC_SNI].Setup = DetectQuicSniSetup; + sigmatch_table[DETECT_AL_QUIC_SNI].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_QUIC_SNI].RegisterTests = DetectQuicSniRegisterTests; +#endif + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetSniData, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, GetSniData); + + quic_sni_id = DetectBufferTypeGetByName(BUFFER_NAME); +} + +/** + * \internal + * \brief this function is used to add the parsed sigmatch into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectQuicSniSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectBufferSetActiveList(de_ctx, s, quic_sni_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) + return -1; + + return 0; +} + +#ifdef UNITTESTS + +/** + * \test QuicSniTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int QuicSniTestParse01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (quic.sni; content:\"googe.com\"; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (quic.sni; content:\"|00|\"; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test QuicSniTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int QuicSniTestParse03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = + DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (quic.sni:; sid:1; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \brief this function registers unit tests for QuicSni + */ +void DetectQuicSniRegisterTests(void) +{ + UtRegisterTest("QuicSniTestParse01", QuicSniTestParse01); + UtRegisterTest("QuicSniTestParse03", QuicSniTestParse03); +} + +#endif /* UNITTESTS */ diff --git a/src/detect-quic-sni.h b/src/app-layer/quic/detect-sni.h similarity index 100% rename from src/detect-quic-sni.h rename to src/app-layer/quic/detect-sni.h diff --git a/src/app-layer/quic/detect-ua.c b/src/app-layer/quic/detect-ua.c new file mode 100644 index 000000000000..15a4060291a4 --- /dev/null +++ b/src/app-layer/quic/detect-ua.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * Implements the quic.ua + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-mpm.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-uint.h" +#include "app-layer/quic/detect-ua.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "rust.h" + +#ifdef UNITTESTS +static void DetectQuicUaRegisterTests(void); +#endif + +#define BUFFER_NAME "quic_ua" +#define KEYWORD_NAME "quic.ua" +#define KEYWORD_ID DETECT_AL_QUIC_UA + +static int quic_ua_id = 0; + +static int DetectQuicUaSetup(DetectEngineCtx *, Signature *, const char *); + +static InspectionBuffer *GetUaData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_quic_tx_get_ua(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +/** + * \brief Registration function for quic.ua: keyword + */ +void DetectQuicUaRegister(void) +{ + sigmatch_table[DETECT_AL_QUIC_UA].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_QUIC_UA].desc = "match Quic ua"; + sigmatch_table[DETECT_AL_QUIC_UA].url = "/rules/quic-keywords.html#quic-ua"; + sigmatch_table[DETECT_AL_QUIC_UA].Setup = DetectQuicUaSetup; + sigmatch_table[DETECT_AL_QUIC_UA].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_QUIC_UA].RegisterTests = DetectQuicUaRegisterTests; +#endif + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetUaData, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, GetUaData); + + quic_ua_id = DetectBufferTypeGetByName(BUFFER_NAME); +} + +/** + * \internal + * \brief this function is used to add the parsed sigmatch into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectQuicUaSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectBufferSetActiveList(de_ctx, s, quic_ua_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) + return -1; + + return 0; +} + +#ifdef UNITTESTS + +/** + * \test QuicUaTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int QuicUaTestParse01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (quic.ua; content:\"googe.com\"; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (quic.ua; content:\"|00|\"; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test QuicUaTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int QuicUaTestParse03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = + DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (quic.ua:; sid:1; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \brief this function registers unit tests for QuicUa + */ +void DetectQuicUaRegisterTests(void) +{ + UtRegisterTest("QuicUaTestParse01", QuicUaTestParse01); + UtRegisterTest("QuicUaTestParse03", QuicUaTestParse03); +} + +#endif /* UNITTESTS */ diff --git a/src/detect-quic-ua.h b/src/app-layer/quic/detect-ua.h similarity index 100% rename from src/detect-quic-ua.h rename to src/app-layer/quic/detect-ua.h diff --git a/src/app-layer/quic/detect-version.c b/src/app-layer/quic/detect-version.c new file mode 100644 index 000000000000..c20008b4c40f --- /dev/null +++ b/src/app-layer/quic/detect-version.c @@ -0,0 +1,173 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * Implements the quic.version + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-mpm.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-uint.h" +#include "app-layer/quic/detect-version.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "rust.h" + +#ifdef UNITTESTS +static void DetectQuicVersionRegisterTests(void); +#endif + +#define BUFFER_NAME "quic_version" +#define KEYWORD_NAME "quic.version" +#define KEYWORD_ID DETECT_AL_QUIC_VERSION + +static int quic_version_id = 0; + +static int DetectQuicVersionSetup(DetectEngineCtx *, Signature *, const char *); + +static InspectionBuffer *GetVersionData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_quic_tx_get_version(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +/** + * \brief Registration function for quic.version: keyword + */ +void DetectQuicVersionRegister(void) +{ + sigmatch_table[DETECT_AL_QUIC_VERSION].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_QUIC_VERSION].desc = "match Quic version"; + sigmatch_table[DETECT_AL_QUIC_VERSION].url = "/rules/quic-keywords.html#quic-version"; + sigmatch_table[DETECT_AL_QUIC_VERSION].Setup = DetectQuicVersionSetup; + sigmatch_table[DETECT_AL_QUIC_VERSION].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_QUIC_VERSION].RegisterTests = DetectQuicVersionRegisterTests; +#endif + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetVersionData, ALPROTO_QUIC, 1); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetVersionData, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, GetVersionData); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, GetVersionData); + + quic_version_id = DetectBufferTypeGetByName(BUFFER_NAME); +} + +/** + * \internal + * \brief this function is used to add the parsed sigmatch into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectQuicVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectBufferSetActiveList(de_ctx, s, quic_version_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) + return -1; + + return 0; +} + +#ifdef UNITTESTS + +/** + * \test QuicVersionTestParse01 is a test for a valid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int QuicVersionTestParse01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (quic.version; content:\"Q046\"; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (quic.version; content:\"|00|\"; sid:2; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test QuicVersionTestParse03 is a test for an invalid value + * + * \retval 1 on success + * \retval 0 on failure + */ +static int QuicVersionTestParse03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (quic.version:; sid:1; rev:1;)"); + FAIL_IF_NOT_NULL(sig); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \brief this function registers unit tests for QuicVersion + */ +void DetectQuicVersionRegisterTests(void) +{ + UtRegisterTest("QuicVersionTestParse01", QuicVersionTestParse01); + UtRegisterTest("QuicVersionTestParse03", QuicVersionTestParse03); +} + +#endif /* UNITTESTS */ diff --git a/src/detect-quic-version.h b/src/app-layer/quic/detect-version.h similarity index 100% rename from src/detect-quic-version.h rename to src/app-layer/quic/detect-version.h diff --git a/src/app-layer/quic/logger.c b/src/app-layer/quic/logger.c new file mode 100644 index 000000000000..100d8194e678 --- /dev/null +++ b/src/app-layer/quic/logger.c @@ -0,0 +1,151 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * Implements JSON/eve logging for Quic app-layer. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/quic/logger.h" +#include "rust.h" + +typedef struct LogQuicFileCtx_ { + LogFileCtx *file_ctx; + OutputJsonCtx *eve_ctx; +} LogQuicFileCtx; + +typedef struct JsonQuicLogThread_ { + LogQuicFileCtx *quiclog_ctx; + OutputJsonThreadCtx *ctx; +} JsonQuicLogThread; + +static int JsonQuicLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + JsonQuicLogThread *thread = thread_data; + + JsonBuilder *js = + CreateEveHeader(p, LOG_DIR_PACKET, "quic", NULL, thread->quiclog_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + if (!rs_quic_to_json(tx, js)) { + jb_free(js); + return TM_ECODE_FAILED; + } + OutputJsonBuilderBuffer(js, thread->ctx); + + jb_free(js); + return TM_ECODE_OK; +} + +static void OutputQuicLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogQuicFileCtx *quiclog_ctx = (LogQuicFileCtx *)output_ctx->data; + SCFree(quiclog_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputQuicLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ajt = parent_ctx->data; + + LogQuicFileCtx *quiclog_ctx = SCCalloc(1, sizeof(*quiclog_ctx)); + if (unlikely(quiclog_ctx == NULL)) { + return result; + } + quiclog_ctx->file_ctx = ajt->file_ctx; + quiclog_ctx->eve_ctx = ajt; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(quiclog_ctx); + return result; + } + output_ctx->data = quiclog_ctx; + output_ctx->DeInit = OutputQuicLogDeInitCtxSub; + + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_QUIC); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonQuicLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogQuic. \"initdata\" is NULL."); + return TM_ECODE_FAILED; + } + + JsonQuicLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + thread->quiclog_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->quiclog_ctx->eve_ctx); + if (thread->ctx == NULL) { + goto error_exit; + } + + *data = (void *)thread; + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonQuicLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonQuicLogThread *thread = (JsonQuicLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonQuicLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonQuicLog", "eve-log.quic", + OutputQuicLogInitSub, ALPROTO_QUIC, JsonQuicLogger, JsonQuicLogThreadInit, + JsonQuicLogThreadDeinit, NULL); + + SCLogDebug("quic json logger registered."); +} diff --git a/src/output-json-quic.h b/src/app-layer/quic/logger.h similarity index 100% rename from src/output-json-quic.h rename to src/app-layer/quic/logger.h diff --git a/src/app-layer/quic/parser.c b/src/app-layer/quic/parser.c new file mode 100644 index 000000000000..0ec9ac55e1b8 --- /dev/null +++ b/src/app-layer/quic/parser.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * Quic Application Layer + * + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/quic/parser.h" +#include "rust.h" + +void RegisterQuicParsers(void) +{ + rs_quic_register_parser(); +} diff --git a/src/app-layer-quic.h b/src/app-layer/quic/parser.h similarity index 100% rename from src/app-layer-quic.h rename to src/app-layer/quic/parser.h diff --git a/src/app-layer/rdp/logger.c b/src/app-layer/rdp/logger.c new file mode 100644 index 000000000000..584b545880ad --- /dev/null +++ b/src/app-layer/rdp/logger.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2019-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Zach Kelly + * + * Application layer logger for RDP + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/rdp/parser.h" +#include "app-layer/rdp/logger.h" +#include "rust.h" + +static int JsonRdpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *js = CreateEveHeader(p, LOG_DIR_PACKET, "rdp", NULL, thread->ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + if (!rs_rdp_to_json(tx, js)) { + jb_free(js); + return TM_ECODE_FAILED; + } + OutputJsonBuilderBuffer(js, thread); + + jb_free(js); + return TM_ECODE_OK; +} + +static OutputInitResult OutputRdpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_RDP); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonRdpLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonRdpLog", "eve-log.rdp", + OutputRdpLogInitSub, ALPROTO_RDP, JsonRdpLogger, JsonLogThreadInit, JsonLogThreadDeinit, + NULL); + + SCLogDebug("rdp json logger registered."); +} diff --git a/src/output-json-rdp.h b/src/app-layer/rdp/logger.h similarity index 100% rename from src/output-json-rdp.h rename to src/app-layer/rdp/logger.h diff --git a/src/app-layer/rdp/parser.c b/src/app-layer/rdp/parser.c new file mode 100644 index 000000000000..a9d8f3f55eb8 --- /dev/null +++ b/src/app-layer/rdp/parser.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Zach Kelly + * + * Application layer parser for RDP + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" +#include "util/unittest.h" +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" +#include "app-layer/rdp/parser.h" +#include "rust.h" + +void RegisterRdpParsers(void) +{ + SCLogDebug("Registering rdp parser"); + rs_rdp_register_parser(); +} diff --git a/src/app-layer-rdp.h b/src/app-layer/rdp/parser.h similarity index 100% rename from src/app-layer-rdp.h rename to src/app-layer/rdp/parser.h diff --git a/src/app-layer/rfb/detect-name.c b/src/app-layer/rfb/detect-name.c new file mode 100644 index 000000000000..a18ec8d01607 --- /dev/null +++ b/src/app-layer/rfb/detect-name.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/rfb/detect-name.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/rfb/parser.h" +#include "rust-bindings.h" + +#define KEYWORD_NAME "rfb.name" +#define KEYWORD_DOC "rfb-keywords.html#rfb-name"; +#define BUFFER_NAME "rfb.name" +#define BUFFER_DESC "rfb name" +static int g_buffer_id = 0; + +static int DetectRfbNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_RFB) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_rfb_tx_get_name(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectRfbNameRegister(void) +{ + sigmatch_table[DETECT_AL_RFB_NAME].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_RFB_NAME].url = + "/rules/" KEYWORD_DOC sigmatch_table[DETECT_AL_RFB_NAME].desc = + "sticky buffer to match on the RFB desktop name"; + sigmatch_table[DETECT_AL_RFB_NAME].Setup = DetectRfbNameSetup; + sigmatch_table[DETECT_AL_RFB_NAME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_RFB, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 1, PrefilterGenericMpmRegister, + GetData, ALPROTO_RFB, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-rfb-name.h b/src/app-layer/rfb/detect-name.h similarity index 100% rename from src/detect-rfb-name.h rename to src/app-layer/rfb/detect-name.h diff --git a/src/app-layer/rfb/detect-secresult.c b/src/app-layer/rfb/detect-secresult.c new file mode 100644 index 000000000000..dfea3f890a44 --- /dev/null +++ b/src/app-layer/rfb/detect-secresult.c @@ -0,0 +1,290 @@ +/* Copyright (C) 2020-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/rfb/detect-secresult.h" +#include "util/unittest.h" + +#include "rust.h" + +#define PARSE_REGEX "\\S[A-z]" +static DetectParseRegex parse_regex; + +static int rfb_secresult_id = 0; + +static int DetectRfbSecresultMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectRfbSecresultSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void RfbSecresultRegisterTests(void); +#endif +void DetectRfbSecresultFree(DetectEngineCtx *, void *); + +typedef struct DetectRfbSecresultData_ { + uint32_t result; /** result code */ +} DetectRfbSecresultData; + +/** + * \brief Registration function for rfb.secresult: keyword + */ +void DetectRfbSecresultRegister(void) +{ + sigmatch_table[DETECT_AL_RFB_SECRESULT].name = "rfb.secresult"; + sigmatch_table[DETECT_AL_RFB_SECRESULT].desc = "match RFB security result"; + sigmatch_table[DETECT_AL_RFB_SECRESULT].url = "/rules/rfb-keywords.html#rfb-secresult"; + sigmatch_table[DETECT_AL_RFB_SECRESULT].AppLayerTxMatch = DetectRfbSecresultMatch; + sigmatch_table[DETECT_AL_RFB_SECRESULT].Setup = DetectRfbSecresultSetup; + sigmatch_table[DETECT_AL_RFB_SECRESULT].Free = DetectRfbSecresultFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_RFB_SECRESULT].RegisterTests = RfbSecresultRegisterTests; +#endif + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2("rfb.secresult", ALPROTO_RFB, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectGenericList, NULL); + + rfb_secresult_id = DetectBufferTypeGetByName("rfb.secresult"); +} + +enum { RFB_SECRESULT_OK = 0, RFB_SECRESULT_FAIL, RFB_SECRESULT_TOOMANY, RFB_SECRESULT_UNKNOWN }; + +/** + * \struct DetectRfbSecresult_ + * DetectRfbSecresult_ is used to store values + */ + +struct DetectRfbSecresult_ { + const char *result; + uint16_t code; +} results[] = { + { + "ok", + RFB_SECRESULT_OK, + }, + { + "fail", + RFB_SECRESULT_FAIL, + }, + { + "toomany", + RFB_SECRESULT_TOOMANY, + }, + { + "unknown", + RFB_SECRESULT_UNKNOWN, + }, + { NULL, 0 }, +}; + +/** + * \internal + * \brief Function to match security result of a RFB TX + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the RFBTransaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectRfbSecresultData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectRfbSecresultMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectRfbSecresultData *de = (const DetectRfbSecresultData *)ctx; + uint32_t resultcode; + int ret = 0; + + if (!de) + return 0; + + ret = rs_rfb_tx_get_secresult(txv, &resultcode); + if (ret == 0) { + return 0; + } + + if (de->result < 3) { + /* we are asking for a defined code... */ + if (resultcode == de->result) { + /* ... which needs to match */ + return 1; + } + } else { + /* we are asking for an unknown code */ + if (resultcode > 2) { + /* match any unknown code */ + return 1; + } + } + + return 0; +} + +/** + * \internal + * \brief This function is used to parse options passed via rfb.secresults: keyword + * + * \param rawstr Pointer to the user provided secresult options + * + * \retval de pointer to DetectRfbSecresultData on success + * \retval NULL on failure + */ +static DetectRfbSecresultData *DetectRfbSecresultParse(const char *rawstr) +{ + int i; + DetectRfbSecresultData *de = NULL; + int found = 0; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); + if (ret < 1) { + SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); + goto error; + } + + for (i = 0; results[i].result != NULL; i++) { + if ((strcasecmp(results[i].result, rawstr)) == 0) { + found = 1; + break; + } + } + + if (found == 0) { + SCLogError("unknown secresult value %s", rawstr); + goto error; + } + + de = SCMalloc(sizeof(DetectRfbSecresultData)); + if (unlikely(de == NULL)) + goto error; + + de->result = results[i].code; + + pcre2_match_data_free(match); + return de; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (de) + SCFree(de); + return NULL; +} + +/** + * \internal + * \brief this function is used to add the parsed secresult into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rawstr pointer to the user provided secresult options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectRfbSecresultSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectRfbSecresultData *de = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_RFB) < 0) + return -1; + + de = DetectRfbSecresultParse(rawstr); + if (de == NULL) + goto error; + + if (SigMatchAppendSMToList( + de_ctx, s, DETECT_AL_RFB_SECRESULT, (SigMatchCtx *)de, rfb_secresult_id) == NULL) { + goto error; + } + + return 0; + +error: + if (de) + SCFree(de); + return -1; +} + +/** + * \internal + * \brief this function will free memory associated with DetectRfbSecresultData + * + * \param de pointer to DetectRfbSecresultData + */ +void DetectRfbSecresultFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + DetectRfbSecresultData *de = (DetectRfbSecresultData *)de_ptr; + if (de) + SCFree(de); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +/** + * \test RfbSecresultTestParse01 is a test for a valid secresult value + */ +static int RfbSecresultTestParse01(void) +{ + DetectRfbSecresultData *de = DetectRfbSecresultParse("fail"); + + FAIL_IF_NULL(de); + + DetectRfbSecresultFree(NULL, de); + + PASS; +} + +/** + * \test RfbSecresultTestParse02 is a test for an invalid secresult value + */ +static int RfbSecresultTestParse02(void) +{ + DetectRfbSecresultData *de = DetectRfbSecresultParse("invalidopt"); + + FAIL_IF_NOT_NULL(de); + + PASS; +} + +/** + * \brief this function registers unit tests for RfbSecresult + */ +void RfbSecresultRegisterTests(void) +{ + UtRegisterTest("RfbSecresultTestParse01", RfbSecresultTestParse01); + UtRegisterTest("RfbSecresultTestParse02", RfbSecresultTestParse02); +} +#endif /* UNITTESTS */ diff --git a/src/detect-rfb-secresult.h b/src/app-layer/rfb/detect-secresult.h similarity index 100% rename from src/detect-rfb-secresult.h rename to src/app-layer/rfb/detect-secresult.h diff --git a/src/app-layer/rfb/detect-sectype.c b/src/app-layer/rfb/detect-sectype.c new file mode 100644 index 000000000000..0f064d4d340f --- /dev/null +++ b/src/app-layer/rfb/detect-sectype.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Sascha Steinbiss + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/rfb/detect-sectype.h" +#include "detect-engine-uint.h" +#include "app-layer-parser.h" +#include "util/byte.h" + +#include "rust-bindings.h" + +static int DetectRfbSectypeSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectRfbSectypeFree(DetectEngineCtx *, void *); +static int g_rfb_sectype_buffer_id = 0; + +static int DetectRfbSectypeMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +/** + * \brief Registration function for rfb.sectype keyword. + */ +void DetectRfbSectypeRegister(void) +{ + sigmatch_table[DETECT_AL_RFB_SECTYPE].name = "rfb.sectype"; + sigmatch_table[DETECT_AL_RFB_SECTYPE].desc = "match RFB security type"; + sigmatch_table[DETECT_AL_RFB_SECTYPE].url = "/rules/rfb-keywords.html#rfb-sectype"; + sigmatch_table[DETECT_AL_RFB_SECTYPE].AppLayerTxMatch = DetectRfbSectypeMatch; + sigmatch_table[DETECT_AL_RFB_SECTYPE].Setup = DetectRfbSectypeSetup; + sigmatch_table[DETECT_AL_RFB_SECTYPE].Free = DetectRfbSectypeFree; + + DetectAppLayerInspectEngineRegister2( + "rfb.sectype", ALPROTO_RFB, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + + g_rfb_sectype_buffer_id = DetectBufferTypeGetByName("rfb.sectype"); +} + +/** + * \internal + * \brief Function to match security type of a RFB TX + * + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param txv Pointer to the RFBTransaction. + * \param s Pointer to the Signature. + * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectRfbSectypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + const DetectU32Data *dd = (const DetectU32Data *)ctx; + uint32_t version; + rs_rfb_tx_get_sectype(txv, &version); + if (DetectU32Match(version, dd)) + SCReturnInt(1); + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to parse options passed via rfb.sectype keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectU32Data on success. + * \retval NULL on failure. + */ +static DetectU32Data *DetectRfbSectypeParse(const char *rawstr) +{ + return DetectU32Parse(rawstr); +} + +/** + * \brief Function to add the parsed RFB security type field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectRfbSectypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_RFB) != 0) + return -1; + + DetectU32Data *dd = DetectRfbSectypeParse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_RFB_SECTYPE, (SigMatchCtx *)dd, + g_rfb_sectype_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectRfbSectypeFree(de_ctx, dd); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectU32Data. + * + * \param de_ptr Pointer to DetectU32Data. + */ +static void DetectRfbSectypeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} diff --git a/src/detect-rfb-sectype.h b/src/app-layer/rfb/detect-sectype.h similarity index 100% rename from src/detect-rfb-sectype.h rename to src/app-layer/rfb/detect-sectype.h diff --git a/src/app-layer/rfb/logger.c b/src/app-layer/rfb/logger.c new file mode 100644 index 000000000000..a5e0a96539b2 --- /dev/null +++ b/src/app-layer/rfb/logger.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2020-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Frank Honza + * + * Implement JSON/eve logging app-layer RFB. + */ + +#include "suricata-common.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/rfb/parser.h" +#include "app-layer/rfb/logger.h" + +#include "rust-bindings.h" + +static int JsonRFBLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "rfb", NULL, thread->ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_FAILED; + } + + if (!rs_rfb_logger_log(tx, js)) { + goto error; + } + + OutputJsonBuilderBuffer(js, thread); + jb_free(js); + + return TM_ECODE_OK; + +error: + jb_free(js); + return TM_ECODE_FAILED; +} + +static OutputInitResult OutputRFBLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_RFB); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonRFBLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonRFBLog", "eve-log.rfb", + OutputRFBLogInitSub, ALPROTO_RFB, JsonRFBLogger, JsonLogThreadInit, JsonLogThreadDeinit, + NULL); +} diff --git a/src/output-json-rfb.h b/src/app-layer/rfb/logger.h similarity index 100% rename from src/output-json-rfb.h rename to src/app-layer/rfb/logger.h diff --git a/src/app-layer/rfb/parser.c b/src/app-layer/rfb/parser.c new file mode 100644 index 000000000000..c3cfd3f7f25c --- /dev/null +++ b/src/app-layer/rfb/parser.c @@ -0,0 +1,140 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + * + * RFB (VNC) application layer detector and parser. + * + */ + +#include "suricata-common.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" +#include "app-layer/rfb/parser.h" + +#include "rust.h" + +static int RFBRegisterPatternsForProtocolDetection(void) +{ + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_RFB, "RFB ", 4, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_RFB, "RFB ", 4, 0, STREAM_TOSERVER) < 0) { + return -1; + } + return 0; +} + +void RFBParserRegisterTests(void); + +void RegisterRFBParsers(void) +{ + rs_rfb_register_parser(); + if (RFBRegisterPatternsForProtocolDetection() < 0) + return; +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_RFB, RFBParserRegisterTests); +#endif +} + +#ifdef UNITTESTS + +#include "stream-tcp.h" +#include "util/unittest-helper.h" + +static int RFBParserTest(void) +{ + uint64_t ret[4]; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + StreamTcpInitConfig(true); + TcpSession ssn; + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 59001, 5900); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_RFB; + + static const unsigned char rfb_version_str[12] = { 0x52, 0x46, 0x42, 0x20, 0x30, 0x30, 0x33, + 0x2e, 0x30, 0x30, 0x37, 0x0a }; + + // the RFB server sending the first handshake message + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOCLIENT | STREAM_START, + (uint8_t *)rfb_version_str, sizeof(rfb_version_str)); + FAIL_IF_NOT(r == 0); + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOSERVER, + (uint8_t *)rfb_version_str, sizeof(rfb_version_str)); + FAIL_IF_NOT(r == 0); + + static const unsigned char security_types[3] = { 0x02, 0x01, 0x02 }; + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOCLIENT, + (uint8_t *)security_types, sizeof(security_types)); + FAIL_IF_NOT(r == 0); + + static const unsigned char type_selection[1] = { 0x01 }; + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOSERVER, + (uint8_t *)type_selection, sizeof(type_selection)); + FAIL_IF_NOT(r == 0); + + static const unsigned char client_init[1] = { 0x01 }; + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOSERVER, (uint8_t *)client_init, + sizeof(client_init)); + FAIL_IF_NOT(r == 0); + + static const unsigned char server_init[] = { 0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x61, 0x6e, 0x65, 0x61, 0x67, 0x6c, 0x65, 0x73, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x68, 0x6f, 0x73, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, + 0x6e }; + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_RFB, STREAM_TOCLIENT, (uint8_t *)server_init, + sizeof(server_init)); + FAIL_IF_NOT(r == 0); + + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 1); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 1); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 1); // log_id + FAIL_IF_NOT(ret[3] == 1); // min_id + + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + + PASS; +} + +void RFBParserRegisterTests(void) +{ + UtRegisterTest("RFBParserTest", RFBParserTest); +} + +#endif diff --git a/src/app-layer-rfb.h b/src/app-layer/rfb/parser.h similarity index 100% rename from src/app-layer-rfb.h rename to src/app-layer/rfb/parser.h diff --git a/src/app-layer/sip/detect-method.c b/src/app-layer/sip/detect-method.c new file mode 100644 index 000000000000..75381acda722 --- /dev/null +++ b/src/app-layer/sip/detect-method.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Giuseppe Longo + * + * Implements the sip.method sticky buffer + * + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/detect-method.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/sip/parser.h" + +#define KEYWORD_NAME "sip.method" +#define KEYWORD_DOC "sip-keywords.html#sip-method" +#define BUFFER_NAME "sip.method" +#define BUFFER_DESC "sip request method" +static int g_buffer_id = 0; + +static int DetectSipMethodSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) + return -1; + + return 0; +} + +static bool DetectSipMethodValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + const DetectContentData *cd = (const DetectContentData *)sm->ctx; + if (cd->content && cd->content_len) { + if (cd->content[cd->content_len - 1] == 0x20) { + *sigerror = "sip.method pattern with trailing space"; + SCLogError("%s", *sigerror); + return true; + } else if (cd->content[0] == 0x20) { + *sigerror = "sip.method pattern with leading space"; + SCLogError("%s", *sigerror); + return true; + } else if (cd->content[cd->content_len - 1] == 0x09) { + *sigerror = "sip.method pattern with trailing tab"; + SCLogError("%s", *sigerror); + return true; + } else if (cd->content[0] == 0x09) { + *sigerror = "sip.method pattern with leading tab"; + SCLogError("%s", *sigerror); + return true; + } + } + } + } + return true; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_sip_tx_get_method(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectSipMethodRegister(void) +{ + /* sip.method sticky buffer */ + sigmatch_table[DETECT_AL_SIP_METHOD].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SIP_METHOD].desc = "sticky buffer to match on the SIP method buffer"; + sigmatch_table[DETECT_AL_SIP_METHOD].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SIP_METHOD].Setup = DetectSipMethodSetup; + sigmatch_table[DETECT_AL_SIP_METHOD].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectSipMethodValidateCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-sip-method.h b/src/app-layer/sip/detect-method.h similarity index 100% rename from src/detect-sip-method.h rename to src/app-layer/sip/detect-method.h diff --git a/src/app-layer/sip/detect-protocol.c b/src/app-layer/sip/detect-protocol.c new file mode 100644 index 000000000000..4d09bf201e90 --- /dev/null +++ b/src/app-layer/sip/detect-protocol.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Giuseppe Longo + * + * Implements sip.protocol sticky buffer + * + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/detect-protocol.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/sip/parser.h" + +#define KEYWORD_NAME "sip.protocol" +#define KEYWORD_DOC "sip-keywords.html#sip-protocol" +#define BUFFER_NAME "sip.protocol" +#define BUFFER_DESC "sip protocol" +static int g_buffer_id = 0; + +static int DetectSipProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_sip_tx_get_protocol(txv, &b, &b_len, flow_flags) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectSipProtocolRegister(void) +{ + /* sip.protocol sticky buffer */ + sigmatch_table[DETECT_AL_SIP_PROTOCOL].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SIP_PROTOCOL].desc = "sticky buffer to match on the SIP protocol"; + sigmatch_table[DETECT_AL_SIP_PROTOCOL].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SIP_PROTOCOL].Setup = DetectSipProtocolSetup; + sigmatch_table[DETECT_AL_SIP_PROTOCOL].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, GetData); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-sip-protocol.h b/src/app-layer/sip/detect-protocol.h similarity index 100% rename from src/detect-sip-protocol.h rename to src/app-layer/sip/detect-protocol.h diff --git a/src/app-layer/sip/detect-request-line.c b/src/app-layer/sip/detect-request-line.c new file mode 100644 index 000000000000..e67e27272712 --- /dev/null +++ b/src/app-layer/sip/detect-request-line.c @@ -0,0 +1,114 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Giuseppe Longo + * + * Implements the sip.request_line sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/detect-request-line.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/sip/parser.h" + +#define KEYWORD_NAME "sip.request_line" +#define KEYWORD_DOC "sip-keywords.html#sip-request-line" +#define BUFFER_NAME "sip.request_line" +#define BUFFER_DESC "sip request line" +static int g_buffer_id = 0; + +static int DetectSipRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_sip_tx_get_request_line(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectSipRequestLineRegister(void) +{ + /* sip.request_line sticky buffer */ + sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].desc = + "sticky buffer to match on the SIP request line"; + sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].Setup = DetectSipRequestLineSetup; + sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-sip-request-line.h b/src/app-layer/sip/detect-request-line.h similarity index 100% rename from src/detect-sip-request-line.h rename to src/app-layer/sip/detect-request-line.h diff --git a/src/app-layer/sip/detect-response-line.c b/src/app-layer/sip/detect-response-line.c new file mode 100644 index 000000000000..699e5b0d2833 --- /dev/null +++ b/src/app-layer/sip/detect-response-line.c @@ -0,0 +1,114 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Giuseppe Longo + * + * Implements the sip.response_line sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/detect-response-line.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/sip/parser.h" + +#define KEYWORD_NAME "sip.response_line" +#define KEYWORD_DOC "sip-keywords.html#sip-response-line" +#define BUFFER_NAME "sip.response_line" +#define BUFFER_DESC "sip response line" +static int g_buffer_id = 0; + +static int DetectSipResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_sip_tx_get_response_line(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectSipResponseLineRegister(void) +{ + /* sip.response_line sticky buffer */ + sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].desc = + "sticky buffer to match on the SIP response line"; + sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].Setup = DetectSipResponseLineSetup; + sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-sip-response-line.h b/src/app-layer/sip/detect-response-line.h similarity index 100% rename from src/detect-sip-response-line.h rename to src/app-layer/sip/detect-response-line.h diff --git a/src/app-layer/sip/detect-stat-code.c b/src/app-layer/sip/detect-stat-code.c new file mode 100644 index 000000000000..a233a0b2865c --- /dev/null +++ b/src/app-layer/sip/detect-stat-code.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Giuseppe Longo + * + * Implements the sip.stat_code sticky buffer + * + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/detect-stat-code.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/sip/parser.h" + +#define KEYWORD_NAME "sip.stat_code" +#define KEYWORD_DOC "sip-keywords.html#sip-stat-code" +#define BUFFER_NAME "sip.method" +#define BUFFER_DESC "sip response status code" +static int g_buffer_id = 0; + +static int DetectSipStatCodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_sip_tx_get_stat_code(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectSipStatCodeRegister(void) +{ + /* sip.stat_code sticky buffer */ + sigmatch_table[DETECT_AL_SIP_STAT_CODE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SIP_STAT_CODE].desc = "sticky buffer to match on the SIP status code"; + sigmatch_table[DETECT_AL_SIP_STAT_CODE].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SIP_STAT_CODE].Setup = DetectSipStatCodeSetup; + sigmatch_table[DETECT_AL_SIP_STAT_CODE].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 4, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-sip-stat-code.h b/src/app-layer/sip/detect-stat-code.h similarity index 100% rename from src/detect-sip-stat-code.h rename to src/app-layer/sip/detect-stat-code.h diff --git a/src/app-layer/sip/detect-stat-msg.c b/src/app-layer/sip/detect-stat-msg.c new file mode 100644 index 000000000000..f9f2c78ba82d --- /dev/null +++ b/src/app-layer/sip/detect-stat-msg.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Giuseppe Longo + * + * Implements the sip.stat_msg sticky buffer + * + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/detect-stat-msg.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/sip/parser.h" + +#define KEYWORD_NAME "sip.stat_msg" +#define KEYWORD_DOC "sip-keywords.html#sip-stat-msg" +#define BUFFER_NAME "sip.stat_msg" +#define BUFFER_DESC "sip response status message" +static int g_buffer_id = 0; + +static int DetectSipStatMsgSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_sip_tx_get_stat_msg(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectSipStatMsgRegister(void) +{ + /* sip.stat_msg sticky buffer */ + sigmatch_table[DETECT_AL_SIP_STAT_MSG].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SIP_STAT_MSG].desc = + "sticky buffer to match on the SIP status message"; + sigmatch_table[DETECT_AL_SIP_STAT_MSG].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SIP_STAT_MSG].Setup = DetectSipStatMsgSetup; + sigmatch_table[DETECT_AL_SIP_STAT_MSG].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 3, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-sip-stat-msg.h b/src/app-layer/sip/detect-stat-msg.h similarity index 100% rename from src/detect-sip-stat-msg.h rename to src/app-layer/sip/detect-stat-msg.h diff --git a/src/app-layer/sip/detect-uri.c b/src/app-layer/sip/detect-uri.c new file mode 100644 index 000000000000..cb491c692a25 --- /dev/null +++ b/src/app-layer/sip/detect-uri.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * + * \author Giuseppe Longo + * + * Implements the sip.uri sticky buffer + * + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-urilen.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/detect-uri.h" +#include "stream-tcp.h" + +#include "rust.h" +#include "app-layer/sip/parser.h" + +#define KEYWORD_NAME "sip.uri" +#define KEYWORD_DOC "sip-keywords.html#sip-uri" +#define BUFFER_NAME "sip.uri" +#define BUFFER_DESC "sip request uri" +static int g_buffer_id = 0; + +static bool DetectSipUriValidateCallback(const Signature *s, const char **sigerror) +{ + return DetectUrilenValidateContent(s, g_buffer_id, sigerror); +} + +static void DetectSipUriSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + DetectUrilenApplyToContent(s, g_buffer_id); +} + +static int DetectSipUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (rs_sip_tx_get_uri(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectSipUriRegister(void) +{ + sigmatch_table[DETECT_AL_SIP_URI].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SIP_URI].desc = "sticky buffer to match on the SIP URI"; + sigmatch_table[DETECT_AL_SIP_URI].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SIP_URI].Setup = DetectSipUriSetup; + sigmatch_table[DETECT_AL_SIP_URI].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SIP, 1); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, DetectSipUriSetupCallback); + + DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectSipUriValidateCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + SCLogDebug("registering " BUFFER_NAME " rule option"); +} diff --git a/src/detect-sip-uri.h b/src/app-layer/sip/detect-uri.h similarity index 100% rename from src/detect-sip-uri.h rename to src/app-layer/sip/detect-uri.h diff --git a/src/app-layer/sip/logger.c b/src/app-layer/sip/logger.c new file mode 100644 index 000000000000..7f49ba231eb1 --- /dev/null +++ b/src/app-layer/sip/logger.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2018-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Giuseppe Longo + * + * Implement JSON/eve logging app-layer SIP. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/sip/parser.h" +#include "app-layer/sip/logger.h" + +#include "rust.h" + +static int JsonSIPLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + SIPTransaction *siptx = tx; + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *js = CreateEveHeader((Packet *)p, LOG_DIR_PACKET, "sip", NULL, thread->ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + + if (!rs_sip_log_json(siptx, js)) { + goto error; + } + + OutputJsonBuilderBuffer(js, thread); + jb_free(js); + + return TM_ECODE_OK; + +error: + jb_free(js); + return TM_ECODE_FAILED; +} + +static OutputInitResult OutputSIPLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_SIP); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonSIPLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSIPLog", "eve-log.sip", + OutputSIPLogInitSub, ALPROTO_SIP, JsonSIPLogger, JsonLogThreadInit, JsonLogThreadDeinit, + NULL); + + SCLogDebug("SIP JSON logger registered."); +} diff --git a/src/output-json-sip.h b/src/app-layer/sip/logger.h similarity index 100% rename from src/output-json-sip.h rename to src/app-layer/sip/logger.h diff --git a/src/app-layer/sip/parser.c b/src/app-layer/sip/parser.c new file mode 100644 index 000000000000..5bdc1f7f9e03 --- /dev/null +++ b/src/app-layer/sip/parser.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2019-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Giuseppe Longo + * + * Parser for SIP application layer running on UDP port 5060. + */ + +#include "suricata-common.h" +#include "app-layer/sip/parser.h" +#include "rust.h" + +void RegisterSIPParsers(void) +{ + rs_sip_register_parser(); +} diff --git a/src/app-layer-sip.h b/src/app-layer/sip/parser.h similarity index 100% rename from src/app-layer-sip.h rename to src/app-layer/sip/parser.h diff --git a/src/app-layer/smb/detect-ntlmssp.c b/src/app-layer/smb/detect-ntlmssp.c new file mode 100644 index 000000000000..8cab4b4529d9 --- /dev/null +++ b/src/app-layer/smb/detect-ntlmssp.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + */ + +#include "detect-engine-register.h" +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer/smb/detect-ntlmssp.h" +#include "rust.h" + +#define BUFFER_NAME "smb_ntlmssp_user" +#define KEYWORD_NAME "smb.ntlmssp_user" +#define KEYWORD_ID DETECT_SMB_NTLMSSP_USER + +static int g_smb_nltmssp_user_buffer_id = 0; + +static int DetectSmbNtlmsspUserSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_smb_nltmssp_user_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetNtlmsspUserData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_smb_tx_get_ntlmssp_user(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectSmbNtlmsspUserRegister(void) +{ + sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; + sigmatch_table[KEYWORD_ID].Setup = DetectSmbNtlmsspUserSetup; + sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[KEYWORD_ID].desc = "sticky buffer to match on SMB ntlmssp user in session setup"; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetNtlmsspUserData, ALPROTO_SMB, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetNtlmsspUserData); + + g_smb_nltmssp_user_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} + +#undef BUFFER_NAME +#undef KEYWORD_NAME +#undef KEYWORD_ID + +#define BUFFER_NAME "smb_ntlmssp_domain" +#define KEYWORD_NAME "smb.ntlmssp_domain" +#define KEYWORD_ID DETECT_SMB_NTLMSSP_DOMAIN + +static int g_smb_nltmssp_domain_buffer_id = 0; + +static int DetectSmbNtlmsspDomainSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_smb_nltmssp_domain_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetNtlmsspDomainData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_smb_tx_get_ntlmssp_domain(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectSmbNtlmsspDomainRegister(void) +{ + sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; + sigmatch_table[KEYWORD_ID].Setup = DetectSmbNtlmsspDomainSetup; + sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[KEYWORD_ID].desc = + "sticky buffer to match on SMB ntlmssp domain in session setup"; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetNtlmsspDomainData, ALPROTO_SMB, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetNtlmsspDomainData); + + g_smb_nltmssp_domain_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-smb-ntlmssp.h b/src/app-layer/smb/detect-ntlmssp.h similarity index 100% rename from src/detect-smb-ntlmssp.h rename to src/app-layer/smb/detect-ntlmssp.h diff --git a/src/app-layer/smb/detect-share.c b/src/app-layer/smb/detect-share.c new file mode 100644 index 000000000000..326f0212a31c --- /dev/null +++ b/src/app-layer/smb/detect-share.c @@ -0,0 +1,152 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer/smb/detect-share.h" +#include "rust.h" + +#define BUFFER_NAME "smb_named_pipe" +#define KEYWORD_NAME "smb.named_pipe" +#define KEYWORD_NAME_LEGACY BUFFER_NAME +#define KEYWORD_ID DETECT_SMB_NAMED_PIPE + +static int g_smb_named_pipe_buffer_id = 0; + +static int DetectSmbNamedPipeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_smb_named_pipe_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetNamedPipeData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_smb_tx_get_named_pipe(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectSmbNamedPipeRegister(void) +{ + sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; + sigmatch_table[KEYWORD_ID].alias = KEYWORD_NAME_LEGACY; + sigmatch_table[KEYWORD_ID].Setup = DetectSmbNamedPipeSetup; + sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[KEYWORD_ID].desc = "sticky buffer to match on SMB named pipe in tree connect"; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetNamedPipeData, ALPROTO_SMB, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetNamedPipeData); + + g_smb_named_pipe_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} + +#undef BUFFER_NAME +#undef KEYWORD_NAME +#undef KEYWORD_NAME_LEGACY +#undef KEYWORD_ID + +#define BUFFER_NAME "smb_share" +#define KEYWORD_NAME "smb.share" +#define KEYWORD_NAME_LEGACY BUFFER_NAME +#define KEYWORD_ID DETECT_SMB_SHARE + +static int g_smb_share_buffer_id = 0; + +static int DetectSmbShareSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_smb_share_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetShareData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_smb_tx_get_share(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +void DetectSmbShareRegister(void) +{ + sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; + sigmatch_table[KEYWORD_ID].alias = KEYWORD_NAME_LEGACY; + sigmatch_table[KEYWORD_ID].Setup = DetectSmbShareSetup; + sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[KEYWORD_ID].desc = "sticky buffer to match on SMB share name in tree connect"; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetShareData, ALPROTO_SMB, 1); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetShareData); + + g_smb_share_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-smb-share.h b/src/app-layer/smb/detect-share.h similarity index 100% rename from src/detect-smb-share.h rename to src/app-layer/smb/detect-share.h diff --git a/src/app-layer/smb/logger.c b/src/app-layer/smb/logger.c new file mode 100644 index 000000000000..66560f51ed86 --- /dev/null +++ b/src/app-layer/smb/logger.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2017-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implement JSON/eve logging app-layer SMB. + */ + +#include "suricata-common.h" +#include "util/buffer.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "app-layer-parser.h" +#include "app-layer/smb/logger.h" +#include "rust.h" + +bool EveSMBAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb) +{ + SMBState *state = FlowGetAppState(f); + if (state) { + SMBTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_SMB, state, tx_id); + if (tx) { + return rs_smb_log_json_response(jb, state, tx); + } + } + return false; +} + +static int JsonSMBLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "smb", NULL, thread->ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_FAILED; + } + + jb_open_object(jb, "smb"); + if (!rs_smb_log_json_response(jb, state, tx)) { + goto error; + } + jb_close(jb); + + OutputJsonBuilderBuffer(jb, thread); + + jb_free(jb); + return TM_ECODE_OK; + +error: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static OutputInitResult SMBLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMB); + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_SMB); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonSMBLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSMBLog", "eve-log.smb", SMBLogInitSub, + ALPROTO_SMB, JsonSMBLogger, JsonLogThreadInit, JsonLogThreadDeinit, NULL); + + SCLogDebug("SMB JSON logger registered."); +} diff --git a/src/output-json-smb.h b/src/app-layer/smb/logger.h similarity index 100% rename from src/output-json-smb.h rename to src/app-layer/smb/logger.h diff --git a/src/app-layer/smb/parser.c b/src/app-layer/smb/parser.c new file mode 100644 index 000000000000..ce1a177b1c18 --- /dev/null +++ b/src/app-layer/smb/parser.c @@ -0,0 +1,221 @@ +/* Copyright (C) 2017-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * SMB protocol handling + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "app-layer-protos.h" +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "util/unittest.h" + +#include "rust.h" +#include "app-layer/smb/parser.h" +#include "util/misc.h" + +static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; +static SuricataFileContext sfc = { &sbcfg }; + +#ifdef UNITTESTS +static void SMBParserRegisterTests(void); +#endif + +void RegisterSMBParsers(void) +{ + rs_smb_init(&sfc); + rs_smb_register_parser(); + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMB, SMBParserRegisterTests); +#endif + + return; +} + +#ifdef UNITTESTS +#include "stream-tcp.h" +#include "util/unittest-helper.h" + +/** \test multi transactions and cleanup */ +static int SMBParserTxCleanupTest(void) +{ + uint64_t ret[4]; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + StreamTcpInitConfig(true); + TcpSession ssn; + memset(&ssn, 0, sizeof(ssn)); + + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 445); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SMB; + + char req_str[] = "\x00\x00\x00\x79\xfe\x53\x4d\x42\x40\x00\x01\x00\x00\x00\x00\x00" + "\x05\x00\xe0\x1e\x10\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x10\x72\xd2\x9f\x36\xc2\x08\x14" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x39\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00" + "\x00\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" + "\x78\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + req_str[28] = 0x01; + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, + (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER, (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + req_str[28]++; + + AppLayerParserTransactionsCleanup(f, STREAM_TOSERVER); + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 0); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 0); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 0); // log_id + FAIL_IF_NOT(ret[3] == 0); // min_id + + char resp_str[] = "\x00\x00\x00\x98\xfe\x53\x4d\x42\x40\x00\x01\x00\x00\x00\x00\x00" + "\x05\x00\x21\x00\x11\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x10\x72\xd2\x9f\x36\xc2\x08\x14" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x59\x00\x00\x00\x01\x00\x00\x00\x48\x38\x40\xb3" + "\x0f\xa8\xd3\x01\x84\x9a\x2b\x46\xf7\xa8\xd3\x01\x48\x38\x40\xb3" + "\x0f\xa8\xd3\x01\x48\x38\x40\xb3\x0f\xa8\xd3\x01\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00" + "\x00\x00\x00\x00\x9e\x8f\xb8\x91\x00\x00\x00\x00\x01\x5b\x11\xbb" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + + resp_str[28] = 0x01; + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, + (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + resp_str[28] = 0x04; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + resp_str[28] = 0x05; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + resp_str[28] = 0x06; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + resp_str[28] = 0x08; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + resp_str[28] = 0x02; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + resp_str[28] = 0x07; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 2); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 2); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 2); // log_id + FAIL_IF_NOT(ret[3] == 2); // min_id + + resp_str[28] = 0x03; + r = AppLayerParserParse( + NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT, (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 8); // log_id + FAIL_IF_NOT(ret[3] == 8); // min_id + + req_str[28] = 0x09; + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_EOF, + (uint8_t *)req_str, sizeof(req_str)); + FAIL_IF_NOT(r == 0); + AppLayerParserTransactionsCleanup(f, STREAM_TOSERVER); + + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 8); // inspect_id[0] not updated by ..Cleanup() until full tx is done + FAIL_IF_NOT(ret[1] == 8); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 8); // log_id + FAIL_IF_NOT(ret[3] == 8); // min_id + + resp_str[28] = 0x09; + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_EOF, + (uint8_t *)resp_str, sizeof(resp_str)); + FAIL_IF_NOT(r == 0); + AppLayerParserTransactionsCleanup(f, STREAM_TOCLIENT); + + UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]); + FAIL_IF_NOT(ret[0] == 9); // inspect_id[0] + FAIL_IF_NOT(ret[1] == 9); // inspect_id[1] + FAIL_IF_NOT(ret[2] == 9); // log_id + FAIL_IF_NOT(ret[3] == 9); // min_id + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + UTHFreeFlow(f); + + PASS; +} + +static void SMBParserRegisterTests(void) +{ + UtRegisterTest("SMBParserTxCleanupTest", SMBParserTxCleanupTest); +} + +#endif /* UNITTESTS */ diff --git a/src/app-layer-smb.h b/src/app-layer/smb/parser.h similarity index 100% rename from src/app-layer-smb.h rename to src/app-layer/smb/parser.h diff --git a/src/app-layer/smtp/logger.c b/src/app-layer/smtp/logger.c new file mode 100644 index 000000000000..ab9ac970f66c --- /dev/null +++ b/src/app-layer/smtp/logger.c @@ -0,0 +1,198 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + * + * Implements SMTP JSON logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer/smtp/parser.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" + +#include "output/eve/output-json.h" +#include "app-layer/smtp/logger.h" +#include "output/eve/output-json-email-common.h" + +static void EveSmtpDataLogger(void *state, void *vtx, JsonBuilder *js) +{ + SMTPTransaction *tx = vtx; + SMTPString *rcptto_str; + if (((SMTPState *)state)->helo) { + jb_set_string(js, "helo", (const char *)((SMTPState *)state)->helo); + } + if (tx->mail_from) { + jb_set_string(js, "mail_from", (const char *)tx->mail_from); + } + if (!TAILQ_EMPTY(&tx->rcpt_to_list)) { + jb_open_array(js, "rcpt_to"); + TAILQ_FOREACH (rcptto_str, &tx->rcpt_to_list, next) { + jb_append_string(js, (char *)rcptto_str->str); + } + jb_close(js); + } +} + +static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + SCEnter(); + JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; + + JsonBuilder *jb = CreateEveHeaderWithTxId( + p, LOG_DIR_FLOW, "smtp", NULL, tx_id, jhl->emaillog_ctx->eve_ctx); + if (unlikely(jb == NULL)) + return TM_ECODE_OK; + + jb_open_object(jb, "smtp"); + EveSmtpDataLogger(state, tx, jb); + jb_close(jb); + + EveEmailLogJson(jhl, jb, p, f, state, tx, tx_id); + OutputJsonBuilderBuffer(jb, jhl->ctx); + + jb_free(jb); + + SCReturnInt(TM_ECODE_OK); +} + +bool EveSMTPAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) +{ + SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); + if (smtp_state) { + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); + if (tx) { + EveSmtpDataLogger(smtp_state, tx, js); + return true; + } + } + + return false; +} + +static void OutputSmtpLogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + OutputJsonEmailCtx *email_ctx = output_ctx->data; + if (email_ctx != NULL) { + SCFree(email_ctx); + } + SCFree(output_ctx); +} + +static OutputInitResult OutputSmtpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ojc = parent_ctx->data; + + OutputJsonEmailCtx *email_ctx = SCCalloc(1, sizeof(OutputJsonEmailCtx)); + if (unlikely(email_ctx == NULL)) + return result; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(email_ctx); + return result; + } + + email_ctx->eve_ctx = ojc; + + OutputEmailInitConf(conf, email_ctx); + + output_ctx->data = email_ctx; + output_ctx->DeInit = OutputSmtpLogDeInitCtxSub; + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonSmtpLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + JsonEmailLogThread *aft = SCCalloc(1, sizeof(JsonEmailLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogSMTP. \"initdata\" argument NULL"); + goto error_exit; + } + + /* Use the Output Context (file pointer and mutex) */ + aft->emaillog_ctx = ((OutputCtx *)initdata)->data; + + aft->ctx = CreateEveThreadCtx(t, aft->emaillog_ctx->eve_ctx); + if (aft->ctx == NULL) { + goto error_exit; + } + + *data = (void *)aft; + return TM_ECODE_OK; + +error_exit: + SCFree(aft); + return TM_ECODE_FAILED; +} + +static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonEmailLogThread *aft = (JsonEmailLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(aft->ctx); + + /* clear memory */ + memset(aft, 0, sizeof(JsonEmailLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +void JsonSmtpLogRegister(void) +{ + /* register as child of eve-log */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSmtpLog", "eve-log.smtp", + OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, + JsonSmtpLogThreadDeinit, NULL); +} diff --git a/src/output-json-smtp.h b/src/app-layer/smtp/logger.h similarity index 100% rename from src/output-json-smtp.h rename to src/app-layer/smtp/logger.h diff --git a/src/app-layer/smtp/lua.c b/src/app-layer/smtp/lua.c new file mode 100644 index 000000000000..ca2506e1ccbe --- /dev/null +++ b/src/app-layer/smtp/lua.c @@ -0,0 +1,342 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author casec Bachelors group + * \author Lauritz Prag Sømme + * \author Levi Tobiassen + * \author Stian Hoel Bergseth + * \author Vinjar Hillestad + */ + +#include "suricata-common.h" + +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "output/output.h" + +#include "app-layer/smtp/parser.h" + +#ifdef HAVE_LUA + +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/smtp/lua.h" +#include "util/file.h" + +/* + * \brief internal function used by SMTPGetMimeField + * + * \param luastate luastate stack to use and push attributes to + * \param flow network flow of SMTP packets + * \param name name of the attribute to extract from MimeDecField + * + * \retval 1 if success mimefield found and pushed to stack. Returns error + * int and msg pushed to luastate stack if error occurs. + */ + +static int GetMimeDecField(lua_State *luastate, Flow *flow, const char *name) +{ + /* extract state from flow */ + SMTPState *state = (SMTPState *)FlowGetAppState(flow); + /* check that state exists */ + if (state == NULL) { + return LuaCallbackError(luastate, "Internal error: no state in flow"); + } + /* pointer to current transaction in state */ + SMTPTransaction *smtp_tx = state->curr_tx; + if (smtp_tx == NULL) { + return LuaCallbackError(luastate, "Transaction ending or not found"); + } + /* pointer to tail of msg list of MimeDecEntities in current transaction. */ + MimeDecEntity *mime = smtp_tx->msg_tail; + /* check if msg_tail was hit */ + if (mime == NULL) { + return LuaCallbackError(luastate, "Internal error: no fields in transaction"); + } + /* extract MIME field based on specific field name. */ + MimeDecField *field = MimeDecFindField(mime, name); + /* check MIME field */ + if (field == NULL) { + return LuaCallbackError(luastate, "Error: mimefield not found"); + } + /* return extracted field. */ + if (field->value == NULL || field->value_len == 0) { + return LuaCallbackError(luastate, "Error, pointer error"); + } + + return LuaPushStringBuffer(luastate, field->value, field->value_len); +} + +/** + * \brief Function extracts specific MIME field based on argument from luastate + * stack then pushing the attribute onto the luastate stack. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua + * + * \retval 1 if success mimefield found and pushed to stack. Returns error + * int and msg pushed to luastate stack if error occurs. + */ + +static int SMTPGetMimeField(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "error: protocol not SMTP"); + } + Flow *flow = LuaStateGetFlow(luastate); + /* check that flow exist */ + if (flow == NULL) { + return LuaCallbackError(luastate, "Error: no flow found"); + } + const char *name = LuaGetStringArgument(luastate, 1); + if (name == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + + GetMimeDecField(luastate, flow, name); + + return 1; +} + +/** + * \brief Internal function used by SMTPGetMimeList + * + * \param luastate luastate stack to pop and push attributes for I/O to lua + * \param flow network flow of SMTP packets + * + * \retval 1 if the mimelist table is pushed to luastate stack. + * Returns error int and msg pushed to luastate stack if error occurs. + */ + +static int GetMimeList(lua_State *luastate, Flow *flow) +{ + + SMTPState *state = (SMTPState *)FlowGetAppState(flow); + if (state == NULL) { + return LuaCallbackError(luastate, "Error: no SMTP state"); + } + /* Create a pointer to the current SMTPtransaction */ + SMTPTransaction *smtp_tx = state->curr_tx; + if (smtp_tx == NULL) { + return LuaCallbackError(luastate, "Error: no SMTP transaction found"); + } + /* Create a pointer to the tail of MimeDecEntity list */ + MimeDecEntity *mime = smtp_tx->msg_tail; + if (mime == NULL) { + return LuaCallbackError(luastate, "Error: no mime entity found"); + } + MimeDecField *field = mime->field_list; + if (field == NULL) { + return LuaCallbackError(luastate, "Error: no field_list found"); + } + if (field->name == NULL || field->name_len == 0) { + return LuaCallbackError(luastate, "Error: field has no name"); + } + /* Counter of MIME fields found */ + int num = 1; + /* loop trough the list of mimeFields, printing each name found */ + lua_newtable(luastate); + while (field != NULL) { + if (field->name != NULL && field->name_len != 0) { + lua_pushinteger(luastate, num++); + LuaPushStringBuffer(luastate, field->name, field->name_len); + lua_settable(luastate, -3); + } + field = field->next; + } + return 1; +} + +/** + * \brief Lists name and value to all MIME fields which + * is included in a SMTP transaction. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + * + */ + +static int SMTPGetMimeList(lua_State *luastate) +{ + /* Check if right protocol */ + if (!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* Extract network flow */ + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) { + return LuaCallbackError(luastate, "Error: no flow found"); + } + + GetMimeList(luastate, flow); + + return 1; +} + +/** + * \brief internal function used by SMTPGetMailFrom + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * \param flow flow to get state for SMTP + * + * \retval 1 if mailfrom field found. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int GetMailFrom(lua_State *luastate, Flow *flow) +{ + /* Extract SMTPstate from current flow */ + SMTPState *state = (SMTPState *)FlowGetAppState(flow); + + if (state == NULL) { + return LuaCallbackError(luastate, "Internal Error: no state"); + } + SMTPTransaction *smtp_tx = state->curr_tx; + if (smtp_tx == NULL) { + return LuaCallbackError(luastate, "Internal Error: no SMTP transaction"); + } + if (smtp_tx->mail_from == NULL || smtp_tx->mail_from_len == 0) { + return LuaCallbackError(luastate, "MailFrom not found"); + } + return LuaPushStringBuffer(luastate, smtp_tx->mail_from, smtp_tx->mail_from_len); + /* Returns 1 because we never push more then 1 item to the lua stack */ +} + +/** + * \brief Extracts mail_from parameter from SMTPState. + * Attribute may also be available from mimefields, although there is no + * guarantee of it existing as mime. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * + * \retval 1 if mailfrom field found. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int SMTPGetMailFrom(lua_State *luastate) +{ + /* check protocol */ + if (!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* Extract flow, with lockhint to check mutexlocking */ + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) { + return LuaCallbackError(luastate, "Internal Error: no flow"); + } + + GetMailFrom(luastate, flow); + + return 1; +} + +/** + * \brief intern function used by SMTPGetRcpList + * + * \param luastate luastate stack for internal communication with Lua. + * Used to hand over data to the receiving luascript. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int GetRcptList(lua_State *luastate, Flow *flow) +{ + + SMTPState *state = (SMTPState *)FlowGetAppState(flow); + if (state == NULL) { + return LuaCallbackError(luastate, "Internal error, no state"); + } + + SMTPTransaction *smtp_tx = state->curr_tx; + if (smtp_tx == NULL) { + return LuaCallbackError(luastate, "No more tx, or tx not found"); + } + + /* Create a new table in luastate for rcpt list */ + lua_newtable(luastate); + /* rcpt var for iterator */ + int u = 1; + SMTPString *rcpt; + + TAILQ_FOREACH (rcpt, &smtp_tx->rcpt_to_list, next) { + lua_pushinteger(luastate, u++); + LuaPushStringBuffer(luastate, rcpt->str, rcpt->len); + lua_settable(luastate, -3); + } + /* return 1 since we always push one table to luastate */ + return 1; +} + +/** + * \brief function loops through rcpt-list located in + * flow->SMTPState->SMTPTransaction, adding all items to a table. + * Then pushing it to the luastate stack. + * + * \param luastate luastate stack for internal communication with Lua. + * Used to hand over data to the receiving luascript. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int SMTPGetRcptList(lua_State *luastate) +{ + /* check protocol */ + if (!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* Extract flow, with lockhint to check mutexlocking */ + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) { + return LuaCallbackError(luastate, "Internal error: no flow"); + } + + GetRcptList(luastate, flow); + + /* return 1 since we always push one table to luastate */ + return 1; +} + +int LuaRegisterSmtpFunctions(lua_State *luastate) +{ + + lua_pushcfunction(luastate, SMTPGetMimeField); + lua_setglobal(luastate, "SMTPGetMimeField"); + + lua_pushcfunction(luastate, SMTPGetMimeList); + lua_setglobal(luastate, "SMTPGetMimeList"); + + lua_pushcfunction(luastate, SMTPGetMailFrom); + lua_setglobal(luastate, "SMTPGetMailFrom"); + + lua_pushcfunction(luastate, SMTPGetRcptList); + lua_setglobal(luastate, "SMTPGetRcptList"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-smtp.h b/src/app-layer/smtp/lua.h similarity index 100% rename from src/util-lua-smtp.h rename to src/app-layer/smtp/lua.h diff --git a/src/app-layer/smtp/parser.c b/src/app-layer/smtp/parser.c new file mode 100644 index 000000000000..2752bedc39ab --- /dev/null +++ b/src/app-layer/smtp/parser.c @@ -0,0 +1,4369 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata.h" +#include "suricata-common.h" +#include "decode.h" +#include "threads.h" + +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" +#include "stream-tcp.h" +#include "stream.h" + +#include "app-layer.h" +#include "app-layer-detect-proto.h" +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer/smtp/parser.h" + +#include "util/enum.h" +#include "util/mpm/mpm.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/memcmp.h" +#include "flow-util.h" + +#include "detect-engine.h" +#include "detect-engine-state.h" +#include "detect-engine-build.h" +#include "detect-parse.h" + +#include "decode-events.h" +#include "conf.h" + +#include "util/mem.h" +#include "util/misc.h" +#include "util/validate.h" + +/* content-limit default value */ +#define FILEDATA_CONTENT_LIMIT 100000 +/* content-inspect-min-size default value */ +#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768 +/* content-inspect-window default value */ +#define FILEDATA_CONTENT_INSPECT_WINDOW 4096 + +/* raw extraction default value */ +#define SMTP_RAW_EXTRACTION_DEFAULT_VALUE false +#define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510 + +#define SMTP_COMMAND_BUFFER_STEPS 5 + +/* we are in process of parsing a fresh command. Just a placeholder. If we + * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */ +#define SMTP_PARSER_STATE_COMMAND_MODE 0x00 +/* we are in mode of parsing a command's data. Used when we are parsing tls + * or accepting the rfc 2822 mail after DATA command */ +#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01 +/* Used when we are still in the process of parsing a server command. Used + * with multi-line replies and the stream is fragmented before all the lines + * for a response is seen */ +#define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02 +/* Used to indicate that the parser has seen the first reply */ +#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04 +/* Used to indicate that the parser is parsing a multiline reply */ +#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08 +/* Used to indicate that the server supports pipelining */ +#define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10 + +/* Various SMTP commands + * We currently have var-ified just STARTTLS and DATA, since we need to them + * for state transitions. The rest are just indicate as OTHER_CMD. Other + * commands would be introduced as and when needed */ +#define SMTP_COMMAND_STARTTLS 1 +#define SMTP_COMMAND_DATA 2 +#define SMTP_COMMAND_BDAT 3 +/* not an actual command per se, but the mode where we accept the mail after + * DATA has it's own reply code for completion, from the server. We give this + * stage a pseudo command of it's own, so that we can add this to the command + * buffer to match with the reply */ +#define SMTP_COMMAND_DATA_MODE 4 +/* All other commands are represented by this var */ +#define SMTP_COMMAND_OTHER_CMD 5 +#define SMTP_COMMAND_RSET 6 + +/* Different EHLO extensions. Not used now. */ +#define SMTP_EHLO_EXTENSION_PIPELINING +#define SMTP_EHLO_EXTENSION_SIZE +#define SMTP_EHLO_EXTENSION_DSN +#define SMTP_EHLO_EXTENSION_STARTTLS +#define SMTP_EHLO_EXTENSION_8BITMIME + +typedef struct SMTPInput_ { + /* current input that is being parsed */ + const uint8_t *buf; + int32_t len; + + /* original length of an input */ + int32_t orig_len; + + /* Consumed bytes till current line */ + int32_t consumed; +} SMTPInput; + +typedef struct SMTPLine_ { + /** current line extracted by the parser from the call to SMTPGetline() */ + const uint8_t *buf; + /** length of the line in current_line. Doesn't include the delimiter */ + int32_t len; + uint8_t delim_len; + bool lf_found; +} SMTPLine; + +SCEnumCharMap smtp_decoder_event_table[] = { + { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY }, + { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST", SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST }, + { "MAX_COMMAND_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED }, + { "MAX_REPLY_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED }, + { "INVALID_PIPELINED_SEQUENCE", SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE }, + { "BDAT_CHUNK_LEN_EXCEEDED", SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED }, + { "NO_SERVER_WELCOME_MESSAGE", SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE }, + { "TLS_REJECTED", SMTP_DECODER_EVENT_TLS_REJECTED }, + { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED }, + { "FAILED_PROTOCOL_CHANGE", SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE }, + + /* MIME Events */ + { "MIME_PARSE_FAILED", SMTP_DECODER_EVENT_MIME_PARSE_FAILED }, + { "MIME_MALFORMED_MSG", SMTP_DECODER_EVENT_MIME_MALFORMED_MSG }, + { "MIME_INVALID_BASE64", SMTP_DECODER_EVENT_MIME_INVALID_BASE64 }, + { "MIME_INVALID_QP", SMTP_DECODER_EVENT_MIME_INVALID_QP }, + { "MIME_LONG_LINE", SMTP_DECODER_EVENT_MIME_LONG_LINE }, + { "MIME_LONG_ENC_LINE", SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE }, + { "MIME_LONG_HEADER_NAME", SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME }, + { "MIME_LONG_HEADER_VALUE", SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE }, + { "MIME_LONG_BOUNDARY", SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG }, + { "MIME_LONG_FILENAME", SMTP_DECODER_EVENT_MIME_LONG_FILENAME }, + + /* Invalid behavior or content */ + { "DUPLICATE_FIELDS", SMTP_DECODER_EVENT_DUPLICATE_FIELDS }, + { "UNPARSABLE_CONTENT", SMTP_DECODER_EVENT_UNPARSABLE_CONTENT }, + { "TRUNCATED_LINE", SMTP_DECODER_EVENT_TRUNCATED_LINE }, + { NULL, -1 }, +}; + +typedef struct SMTPThreadCtx_ { + MpmThreadCtx *smtp_mpm_thread_ctx; + PrefilterRuleStore *pmq; +} SMTPThreadCtx; + +#define SMTP_MPM mpm_default_matcher + +static MpmCtx *smtp_mpm_ctx = NULL; + +/* smtp reply codes. If an entry is made here, please make a simultaneous + * entry in smtp_reply_map */ +enum SMTPCode { + SMTP_REPLY_211, + SMTP_REPLY_214, + SMTP_REPLY_220, + SMTP_REPLY_221, + SMTP_REPLY_235, + SMTP_REPLY_250, + SMTP_REPLY_251, + SMTP_REPLY_252, + + SMTP_REPLY_334, + SMTP_REPLY_354, + + SMTP_REPLY_421, + SMTP_REPLY_450, + SMTP_REPLY_451, + SMTP_REPLY_452, + SMTP_REPLY_455, + + SMTP_REPLY_500, + SMTP_REPLY_501, + SMTP_REPLY_502, + SMTP_REPLY_503, + SMTP_REPLY_504, + SMTP_REPLY_550, + SMTP_REPLY_551, + SMTP_REPLY_552, + SMTP_REPLY_553, + SMTP_REPLY_554, + SMTP_REPLY_555, +}; + +SCEnumCharMap smtp_reply_map[] = { + { "211", SMTP_REPLY_211 }, + { "214", SMTP_REPLY_214 }, + { "220", SMTP_REPLY_220 }, + { "221", SMTP_REPLY_221 }, + { "235", SMTP_REPLY_235 }, + { "250", SMTP_REPLY_250 }, + { "251", SMTP_REPLY_251 }, + { "252", SMTP_REPLY_252 }, + + { "334", SMTP_REPLY_334 }, + { "354", SMTP_REPLY_354 }, + + { "421", SMTP_REPLY_421 }, + { "450", SMTP_REPLY_450 }, + { "451", SMTP_REPLY_451 }, + { "452", SMTP_REPLY_452 }, + { "455", SMTP_REPLY_455 }, + + { "500", SMTP_REPLY_500 }, + { "501", SMTP_REPLY_501 }, + { "502", SMTP_REPLY_502 }, + { "503", SMTP_REPLY_503 }, + { "504", SMTP_REPLY_504 }, + { "550", SMTP_REPLY_550 }, + { "551", SMTP_REPLY_551 }, + { "552", SMTP_REPLY_552 }, + { "553", SMTP_REPLY_553 }, + { "554", SMTP_REPLY_554 }, + { "555", SMTP_REPLY_555 }, + { NULL, -1 }, +}; + +/* Create SMTP config structure */ +SMTPConfig smtp_config = { + .decode_mime = true, + { + .decode_base64 = true, + .decode_quoted_printable = true, + .extract_urls = true, + .extract_urls_schemes = NULL, + .log_url_scheme = false, + .body_md5 = false, + .header_value_depth = 0, + }, + .content_limit = FILEDATA_CONTENT_LIMIT, + .content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE, + .content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW, + .raw_extraction = SMTP_RAW_EXTRACTION_DEFAULT_VALUE, + STREAMING_BUFFER_CONFIG_INITIALIZER, +}; + +static SMTPString *SMTPStringAlloc(void); + +/** + * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML + * config file + * + * \return none + */ +static void SMTPConfigure(void) +{ + + SCEnter(); + intmax_t imval; + uint32_t content_limit = 0; + uint32_t content_inspect_min_size = 0; + uint32_t content_inspect_window = 0; + + ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime"); + if (config != NULL) { + ConfNode *extract_urls_schemes = NULL; + + int val; + int ret = ConfGetChildValueBool(config, "decode-mime", &val); + if (ret) { + smtp_config.decode_mime = val; + } + + ret = ConfGetChildValueBool(config, "decode-base64", &val); + if (ret) { + smtp_config.mime_config.decode_base64 = val; + } + + ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val); + if (ret) { + smtp_config.mime_config.decode_quoted_printable = val; + } + + ret = ConfGetChildValueInt(config, "header-value-depth", &imval); + if (ret) { + smtp_config.mime_config.header_value_depth = (uint32_t)imval; + } + + ret = ConfGetChildValueBool(config, "extract-urls", &val); + if (ret) { + smtp_config.mime_config.extract_urls = val; + } + + /* Parse extract-urls-schemes from mime config, add '://' suffix to found schemes, + * and provide a default value of 'http' for the schemes to be extracted + * if no schemes are found in the config */ + extract_urls_schemes = ConfNodeLookupChild(config, "extract-urls-schemes"); + if (extract_urls_schemes) { + ConfNode *scheme = NULL; + + TAILQ_FOREACH (scheme, &extract_urls_schemes->head, next) { + /* new_val_len: scheme value from config e.g. 'http' + '://' + null terminator */ + size_t new_val_len = strlen(scheme->val) + 3 + 1; + if (new_val_len > UINT16_MAX) { + FatalError("Too long value for extract-urls-schemes"); + } + char *new_val = SCMalloc(new_val_len); + if (unlikely(new_val == NULL)) { + FatalError("SCMalloc failure."); + } + + int r = snprintf(new_val, new_val_len, "%s://", scheme->val); + if (r < 0 || r >= (int)new_val_len) { + FatalError("snprintf failure."); + } + + /* replace existing scheme value stored on the linked list with new value including + * '://' suffix */ + SCFree(scheme->val); + scheme->val = new_val; + } + + smtp_config.mime_config.extract_urls_schemes = extract_urls_schemes; + } else { + /* Add default extract url scheme 'http' since + * extract-urls-schemes wasn't found in the config */ + ConfNode *seq_node = ConfNodeNew(); + if (unlikely(seq_node == NULL)) { + FatalError("ConfNodeNew failure."); + } + ConfNode *scheme = ConfNodeNew(); + if (unlikely(scheme == NULL)) { + FatalError("ConfNodeNew failure."); + } + + seq_node->name = SCStrdup("extract-urls-schemes"); + if (unlikely(seq_node->name == NULL)) { + FatalError("SCStrdup failure."); + } + scheme->val = SCStrdup("http://"); + if (unlikely(scheme->val == NULL)) { + FatalError("SCStrdup failure."); + } + + seq_node->is_seq = 1; + TAILQ_INSERT_TAIL(&seq_node->head, scheme, next); + TAILQ_INSERT_TAIL(&config->head, seq_node, next); + + smtp_config.mime_config.extract_urls_schemes = seq_node; + } + + ret = ConfGetChildValueBool(config, "log-url-scheme", &val); + if (ret) { + smtp_config.mime_config.log_url_scheme = val; + } + + ret = ConfGetChildValueBool(config, "body-md5", &val); + if (ret) { + smtp_config.mime_config.body_md5 = val; + } + } + + /* Pass mime config data to MimeDec API */ + MimeDecSetConfig(&smtp_config.mime_config); + + ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker"); + ConfNode *p = NULL; + + if (t != NULL) { + TAILQ_FOREACH (p, &t->head, next) { + if (strcasecmp("content-limit", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_limit) < 0) { + SCLogWarning("parsing content-limit %s failed", p->val); + content_limit = FILEDATA_CONTENT_LIMIT; + } + smtp_config.content_limit = content_limit; + } + + if (strcasecmp("content-inspect-min-size", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) { + SCLogWarning("parsing content-inspect-min-size %s failed", p->val); + content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + } + smtp_config.content_inspect_min_size = content_inspect_min_size; + } + + if (strcasecmp("content-inspect-window", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) { + SCLogWarning("parsing content-inspect-window %s failed", p->val); + content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + } + smtp_config.content_inspect_window = content_inspect_window; + } + } + } + + smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256; + + if (ConfGetBool("app-layer.protocols.smtp.raw-extraction", + (int *)&smtp_config.raw_extraction) != 1) { + smtp_config.raw_extraction = SMTP_RAW_EXTRACTION_DEFAULT_VALUE; + } + if (smtp_config.raw_extraction && smtp_config.decode_mime) { + SCLogError("\"decode-mime\" and \"raw-extraction\" " + "options can't be enabled at the same time, " + "disabling raw extraction"); + smtp_config.raw_extraction = 0; + } + + SCReturn; +} + +static void SMTPSetEvent(SMTPState *s, uint8_t e) +{ + SCLogDebug("setting event %u", e); + + if (s->curr_tx != NULL) { + AppLayerDecoderEventsSetEventRaw(&s->curr_tx->tx_data.events, e); + // s->events++; + return; + } + SCLogDebug("couldn't set event %u", e); +} + +static SMTPTransaction *SMTPTransactionCreate(void) +{ + SMTPTransaction *tx = SCCalloc(1, sizeof(*tx)); + if (tx == NULL) { + return NULL; + } + + TAILQ_INIT(&tx->rcpt_to_list); + tx->mime_state = NULL; + tx->tx_data.file_tx = STREAM_TOSERVER; // can xfer files + return tx; +} + +static void FlagDetectStateNewFile(SMTPTransaction *tx) +{ + if (tx && tx->tx_data.de_state) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set"); + tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW; + } else if (tx == NULL) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX"); + } else if (tx->tx_data.de_state == NULL) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX DESTATE"); + } +} + +static void SMTPNewFile(SMTPTransaction *tx, File *file) +{ + DEBUG_VALIDATE_BUG_ON(tx == NULL); + DEBUG_VALIDATE_BUG_ON(file == NULL); +#ifdef UNITTESTS + if (RunmodeIsUnittests()) { + if (tx == NULL || file == NULL) { + return; + } + } +#endif + FlagDetectStateNewFile(tx); + tx->tx_data.files_opened++; + + /* set inspect sizes used in file pruning logic. + * TODO consider moving this to the file.data code that + * would actually have use for this. */ + FileSetInspectSizes( + file, smtp_config.content_inspect_window, smtp_config.content_inspect_min_size); +} + +int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) +{ + SCEnter(); + int ret = MIME_DEC_OK; + Flow *flow = (Flow *)state->data; + SMTPState *smtp_state = (SMTPState *)flow->alstate; + SMTPTransaction *tx = smtp_state->curr_tx; + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + FileContainer *files = NULL; + + DEBUG_VALIDATE_BUG_ON(tx == NULL); + + uint16_t flags = FileFlowToFlags(flow, STREAM_TOSERVER); + + /* Find file */ + if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { + files = &tx->files_ts; + + /* Open file if necessary */ + if (state->body_begin) { + + if (SCLogDebugEnabled()) { + SCLogDebug("Opening file...%u bytes", len); + printf("File - "); + for (uint32_t i = 0; i < entity->filename_len; i++) { + printf("%c", entity->filename[i]); + } + printf("\n"); + } + + /* Set storage flag if applicable since only the first file in the + * flow seems to be processed by the 'filestore' detector */ + if (files->head != NULL && (files->head->flags & FILE_STORE)) { + flags |= FILE_STORE; + } + + uint32_t depth = + smtp_config.content_inspect_min_size + + (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp); + SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32, depth); + StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth); + + uint16_t flen = (uint16_t)entity->filename_len; + if (entity->filename_len > SC_FILENAME_MAX) { + flen = SC_FILENAME_MAX; + SMTPSetEvent(smtp_state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME); + } + if (FileOpenFileWithId(files, &smtp_config.sbcfg, smtp_state->file_track_id++, + (uint8_t *)entity->filename, flen, (uint8_t *)chunk, len, flags) != 0) { + ret = MIME_DEC_ERR_DATA; + SCLogDebug("FileOpenFile() failed"); + } else { + SMTPNewFile(tx, files->tail); + } + + /* If close in the same chunk, then pass in empty bytes */ + if (state->body_end) { + + SCLogDebug("Closing file...%u bytes", len); + + if (files->tail->state == FILE_STATE_OPENED) { + ret = FileCloseFile(files, &smtp_config.sbcfg, (uint8_t *)NULL, 0, flags); + if (ret != 0) { + SCLogDebug("FileCloseFile() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; + } + } else { + SCLogDebug("File already closed"); + } + depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp; + + AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER); + SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth); + StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth); + } + } else if (state->body_end) { + /* Close file */ + SCLogDebug("Closing file...%u bytes", len); + + if (files->tail && files->tail->state == FILE_STATE_OPENED) { + ret = FileCloseFile(files, &smtp_config.sbcfg, (uint8_t *)chunk, len, flags); + if (ret != 0) { + SCLogDebug("FileCloseFile() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; + } + } else { + SCLogDebug("File already closed"); + } + uint32_t depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp; + AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER); + SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth); + StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth); + } else { + /* Append data chunk to file */ + SCLogDebug("Appending file...%u bytes", len); + /* 0 is ok, -2 is not stored, -1 is error */ + ret = FileAppendData(files, &smtp_config.sbcfg, (uint8_t *)chunk, len); + if (ret == -2) { + ret = 0; + SCLogDebug("FileAppendData() - file no longer being extracted"); + } else if (ret < 0) { + SCLogDebug("FileAppendData() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; + } + + if (files->tail && files->tail->content_inspected == 0 && + files->tail->size >= smtp_config.content_inspect_min_size) { + uint32_t depth = + smtp_config.content_inspect_min_size + + (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp); + AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER); + SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth); + StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth); + + /* after the start of the body inspection, disable the depth logic */ + } else if (files->tail && files->tail->content_inspected > 0) { + StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, 0); + + /* expand the limit as long as we get file data, as the file data is bigger on the + * wire due to base64 */ + } else { + uint32_t depth = + smtp_config.content_inspect_min_size + + (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp); + SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32, depth); + StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth); + } + } + + if (ret == 0) { + SCLogDebug("Successfully processed file data!"); + } + } else { + SCLogDebug("Body not a Ctnt_attachment"); + } + SCReturnInt(ret); +} + +/** + * \internal + * \brief Get the next line from input. It doesn't do any length validation. + * + * \param state The smtp state. + * + * \retval 0 On success. + * \retval -1 Either when we don't have any new lines to supply anymore or + * on failure. + */ +static AppLayerResult SMTPGetLine( + SMTPState *state, SMTPInput *input, SMTPLine *line, uint16_t direction) +{ + SCEnter(); + + /* we have run out of input */ + if (input->len <= 0) + return APP_LAYER_ERROR; + + uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len); + bool discard_till_lf = (direction == 0) ? state->discard_till_lf_ts : state->discard_till_lf_tc; + + if (lf_idx == NULL) { + if (!discard_till_lf && input->len >= SMTP_LINE_BUFFER_LIMIT) { + line->buf = input->buf; + line->len = SMTP_LINE_BUFFER_LIMIT; + line->delim_len = 0; + SCReturnStruct(APP_LAYER_OK); + } + SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1)); + } else { + /* There could be one chunk of command data that has LF but post the line limit + * e.g. input_len = 5077 + * lf_idx = 5010 + * max_line_len = 4096 */ + uint32_t o_consumed = input->consumed; + input->consumed = lf_idx - input->buf + 1; + line->len = input->consumed - o_consumed; + line->lf_found = true; + DEBUG_VALIDATE_BUG_ON(line->len < 0); + if (line->len < 0) + SCReturnStruct(APP_LAYER_ERROR); + input->len -= line->len; + DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len); + line->buf = input->buf + o_consumed; + if (line->len >= SMTP_LINE_BUFFER_LIMIT) { + line->len = SMTP_LINE_BUFFER_LIMIT; + line->delim_len = 0; + SCReturnStruct(APP_LAYER_OK); + } + if (discard_till_lf) { + // Whatever came in with first LF should also get discarded + if (direction == 0) { + state->discard_till_lf_ts = false; + } else { + state->discard_till_lf_tc = false; + } + line->len = 0; + line->delim_len = 0; + SCReturnStruct(APP_LAYER_OK); + } + if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) { + line->delim_len = 2; + line->len -= 2; + } else { + line->delim_len = 1; + line->len -= 1; + } + SCReturnStruct(APP_LAYER_OK); + } +} + +static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f) +{ + SCEnter(); + void *ptmp; + + if (state->cmds_cnt >= state->cmds_buffer_len) { + int increment = SMTP_COMMAND_BUFFER_STEPS; + if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) { + increment = USHRT_MAX - state->cmds_buffer_len; + } + + ptmp = SCRealloc(state->cmds, sizeof(uint8_t) * (state->cmds_buffer_len + increment)); + if (ptmp == NULL) { + SCFree(state->cmds); + state->cmds = NULL; + SCLogDebug("SCRealloc failure"); + return -1; + } + state->cmds = ptmp; + + state->cmds_buffer_len += increment; + } + if (state->cmds_cnt >= 1 && ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) || + (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) { + /* decoder event */ + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE); + /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP, + * STARTTLS as the last command in pipelined mode */ + } + + /** \todo decoder event */ + if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) { + SCLogDebug("command buffer overflow"); + return -1; + } + + state->cmds[state->cmds_cnt] = command; + state->cmds_cnt++; + + return 0; +} + +static int SMTPProcessCommandBDAT( + SMTPState *state, Flow *f, AppLayerParserState *pstate, const SMTPLine *line) +{ + SCEnter(); + + state->bdat_chunk_idx += (line->len + line->delim_len); + if (state->bdat_chunk_idx > state->bdat_chunk_len) { + state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; + /* decoder event */ + SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED); + SCReturnInt(-1); + } else if (state->bdat_chunk_idx == state->bdat_chunk_len) { + state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; + } + + SCReturnInt(0); +} + +static void SetMimeEvents(SMTPState *state) +{ + if (state->curr_tx->mime_state->msg == NULL) { + return; + } + + /* Generate decoder events */ + MimeDecEntity *msg = state->curr_tx->mime_state->msg; + if (msg->anomaly_flags & ANOM_INVALID_BASE64) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64); + } + if (msg->anomaly_flags & ANOM_INVALID_QP) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP); + } + if (msg->anomaly_flags & ANOM_LONG_LINE) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE); + } + if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE); + } + if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME); + } + if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE); + } + if (msg->anomaly_flags & ANOM_MALFORMED_MSG) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG); + } + if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG); + } + if (msg->anomaly_flags & ANOM_LONG_FILENAME) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME); + } +} + +static inline void SMTPTransactionComplete(SMTPState *state) +{ + DEBUG_VALIDATE_BUG_ON(state->curr_tx == NULL); + if (state->curr_tx) + state->curr_tx->done = 1; +} + +/** + * \retval 0 ok + * \retval -1 error + */ +static int SMTPProcessCommandDATA(SMTPState *state, SMTPTransaction *tx, Flow *f, + AppLayerParserState *pstate, const SMTPLine *line) +{ + SCEnter(); + DEBUG_VALIDATE_BUG_ON(tx == NULL); + + if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + /* looks like are still waiting for a confirmation from the server */ + return 0; + } + + if (line->len == 1 && line->buf[0] == '.') { + state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; + /* kinda like a hack. The mail sent in DATA mode, would be + * acknowledged with a reply. We insert a dummy command to + * the command buffer to be used by the reply handler to match + * the reply received */ + SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f); + if (smtp_config.raw_extraction) { + /* we use this as the signal that message data is complete. */ + FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, 0); + } else if (smtp_config.decode_mime && tx->mime_state != NULL) { + /* Complete parsing task */ + int ret = MimeDecParseComplete(tx->mime_state); + if (ret != MIME_DEC_OK) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); + SCLogDebug("MimeDecParseComplete() function failed"); + } + + /* Generate decoder events */ + SetMimeEvents(state); + } + SMTPTransactionComplete(state); + SCLogDebug("marked tx as done"); + } else if (smtp_config.raw_extraction) { + // message not over, store the line. This is a substitution of + // ProcessDataChunk + FileAppendData(&tx->files_ts, &smtp_config.sbcfg, line->buf, line->len + line->delim_len); + } + + /* If DATA, then parse out a MIME message */ + if (state->current_command == SMTP_COMMAND_DATA && + (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + if (smtp_config.decode_mime && tx->mime_state != NULL) { + int ret = MimeDecParseLine(line->buf, line->len, line->delim_len, tx->mime_state); + if (ret != MIME_DEC_OK) { + if (ret != MIME_DEC_ERR_STATE) { + /* Generate decoder events */ + SetMimeEvents(state); + + SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret); + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); + } + /* keep the parser in its error state so we can log that, + * the parser will reject new data */ + } + } + } + + return 0; +} + +static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f, AppLayerParserState *pstate) +{ + return 0; +} + +static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd) +{ + return (state->cmds_idx < state->cmds_buffer_len && state->cmds[state->cmds_idx] == cmd); +} + +static int SMTPProcessReply(SMTPState *state, Flow *f, AppLayerParserState *pstate, + SMTPThreadCtx *td, SMTPInput *input, const SMTPLine *line) +{ + SCEnter(); + + /* Line with just LF */ + if (line->len == 0 && input->consumed == 1 && line->delim_len == 1) { + return 0; // to continue processing further + } + + /* the reply code has to contain at least 3 bytes, to hold the 3 digit + * reply code */ + if (line->len < 3) { + /* decoder event */ + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); + return -1; + } + + if (line->len >= 4) { + if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) { + if (line->buf[3] != '-') { + state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; + } + } else { + if (line->buf[3] == '-') { + state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; + } + } + } else { + if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) { + state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY; + } + } + + /* I don't like this pmq reset here. We'll devise a method later, that + * should make the use of the mpm very efficient */ + PmqReset(td->pmq); + int mpm_cnt = mpm_table[SMTP_MPM].Search( + smtp_mpm_ctx, td->smtp_mpm_thread_ctx, td->pmq, line->buf, 3); + if (mpm_cnt == 0) { + /* set decoder event - reply code invalid */ + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); + SCLogDebug("invalid reply code %02x %02x %02x", line->buf[0], line->buf[1], line->buf[2]); + SCReturnInt(-1); + } + enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value; + SCLogDebug("REPLY: reply_code %u / %s", reply_code, smtp_reply_map[reply_code].enum_name); + + if (state->cmds_idx == state->cmds_cnt) { + if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + /* the first server reply can be a multiline message. Let's + * flag the fact that we have seen the first reply only at the end + * of a multiline reply + */ + if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) + state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; + if (reply_code == SMTP_REPLY_220) + SCReturnInt(0); + else { + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); + SCReturnInt(0); + } + } else { + /* decoder event - unable to match reply with request */ + SCLogDebug("unable to match reply with request"); + SCReturnInt(0); + } + } + + if (state->cmds_cnt == 0) { + /* reply but not a command we have stored, fall through */ + } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) { + if (reply_code == SMTP_REPLY_220) { + /* we are entering STARTTLS data mode */ + state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; + if (!AppLayerRequestProtocolTLSUpgrade(f)) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE); + } + if (state->curr_tx) { + SMTPTransactionComplete(state); + } + } else { + /* decoder event */ + SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED); + } + } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) { + if (reply_code == SMTP_REPLY_354) { + /* Next comes the mail for the DATA command in toserver direction */ + state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; + } else { + /* decoder event */ + SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED); + } + } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) { + if (reply_code == SMTP_REPLY_250 && state->curr_tx && + !(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) { + SMTPTransactionComplete(state); + } + } else { + /* we don't care for any other command for now */ + } + + /* if it is a multi-line reply, we need to move the index only once for all + * the line of the reply. We unset the multiline flag on the last + * line of the multiline reply, following which we increment the index */ + if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) { + state->cmds_idx++; + } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + /* we check if the server is indicating pipelining support */ + if (reply_code == SMTP_REPLY_250 && line->len == 14 && + SCMemcmpLowercase("pipelining", line->buf + 4, 10) == 0) { + state->parser_state |= SMTP_PARSER_STATE_PIPELINING_SERVER; + } + } + + /* if we have matched all the buffered commands, reset the cnt and index */ + if (state->cmds_idx == state->cmds_cnt) { + state->cmds_cnt = 0; + state->cmds_idx = 0; + } + + return 0; +} + +static int SMTPParseCommandBDAT(SMTPState *state, const SMTPLine *line) +{ + SCEnter(); + + int i = 4; + while (i < line->len) { + if (line->buf[i] != ' ') { + break; + } + i++; + } + if (i == 4) { + /* decoder event */ + return -1; + } + if (i == line->len) { + /* decoder event */ + return -1; + } + char *endptr = NULL; + // copy in temporary null-terminated buffer to call strtoul + char strbuf[24]; + int len = 23; + if (line->len - i < len) { + len = line->len - i; + } + memcpy(strbuf, line->buf + i, len); + strbuf[len] = '\0'; + state->bdat_chunk_len = strtoul((const char *)strbuf, (char **)&endptr, 10); + if ((uint8_t *)endptr == line->buf + i) { + /* decoder event */ + return -1; + } + + return 0; +} + +static int SMTPParseCommandWithParam(SMTPState *state, const SMTPLine *line, uint8_t prefix_len, + uint8_t **target, uint16_t *target_len) +{ + int i = prefix_len + 1; + + while (i < line->len) { + if (line->buf[i] != ' ') { + break; + } + i++; + } + + /* rfc1870: with the size extension the mail from can be followed by an option. + We use the space separator to detect it. */ + int spc_i = i; + while (spc_i < line->len) { + if (line->buf[spc_i] == ' ') { + break; + } + spc_i++; + } + + *target = SCMalloc(spc_i - i + 1); + if (*target == NULL) + return -1; + memcpy(*target, line->buf + i, spc_i - i); + (*target)[spc_i - i] = '\0'; + if (spc_i - i > UINT16_MAX) { + *target_len = UINT16_MAX; + SMTPSetEvent(state, SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED); + } else { + *target_len = (uint16_t)(spc_i - i); + } + + return 0; +} + +static int SMTPParseCommandHELO(SMTPState *state, const SMTPLine *line) +{ + if (state->helo) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); + return 0; + } + return SMTPParseCommandWithParam(state, line, 4, &state->helo, &state->helo_len); +} + +static int SMTPParseCommandMAILFROM(SMTPState *state, const SMTPLine *line) +{ + if (state->curr_tx->mail_from) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); + return 0; + } + return SMTPParseCommandWithParam( + state, line, 9, &state->curr_tx->mail_from, &state->curr_tx->mail_from_len); +} + +static int SMTPParseCommandRCPTTO(SMTPState *state, const SMTPLine *line) +{ + uint8_t *rcptto; + uint16_t rcptto_len; + + if (SMTPParseCommandWithParam(state, line, 7, &rcptto, &rcptto_len) == 0) { + SMTPString *rcptto_str = SMTPStringAlloc(); + if (rcptto_str) { + rcptto_str->str = rcptto; + rcptto_str->len = rcptto_len; + TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next); + } else { + SCFree(rcptto); + return -1; + } + } else { + return -1; + } + return 0; +} + +/* consider 'rset' and 'quit' to be part of the existing state */ +static int NoNewTx(SMTPState *state, const SMTPLine *line) +{ + if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) { + return 1; + } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) { + return 1; + } + } + return 0; +} + +/* XXX have a better name */ +#define rawmsgname "rawmsg" + +/* + * @brief Process an SMTP Request + * + * Parse and decide the current command and set appropriate variables on the state + * accordingly. Create transactions if needed or update the current transaction + * with the appropriate data/params. Pass the control to the respective command + * parser in the end. + * + * @param state Pointer to current SMTPState + * @param f Pointer to the current Flow + * @param pstate Pointer to the current AppLayerParserState + * @param input Pointer to the current input data to SMTP parser + * @param line Pointer to the current line being parsed by the SMTP parser + * @return 0 for success + * -1 for errors and inconsistent states + * -2 if MIME state could not be allocated + * */ +static int SMTPProcessRequest(SMTPState *state, Flow *f, AppLayerParserState *pstate, + SMTPInput *input, const SMTPLine *line) +{ + SCEnter(); + SMTPTransaction *tx = state->curr_tx; + + /* If current input is to be discarded because it completes a long line, + * line's length and delimiter len are reset to 0. Skip processing this line. + * This line is only to get us out of the state where we should discard any + * data till LF. */ + if (line->len == 0 && line->delim_len == 0) { + return 0; + } + if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state, line))) { + tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + + /* keep track of the start of the tx */ + state->toserver_last_data_stamp = state->toserver_data_count; + StreamTcpReassemblySetMinInspectDepth( + f->protoctx, STREAM_TOSERVER, smtp_config.content_inspect_min_size); + } + + state->toserver_data_count += (line->len + line->delim_len); + + if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE); + } + + /* there are 2 commands that can push it into this COMMAND_DATA mode - + * STARTTLS and DATA */ + if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + int r = 0; + + if (line->len >= 8 && SCMemcmpLowercase("starttls", line->buf, 8) == 0) { + state->current_command = SMTP_COMMAND_STARTTLS; + } else if (line->len >= 4 && SCMemcmpLowercase("data", line->buf, 4) == 0) { + state->current_command = SMTP_COMMAND_DATA; + if (smtp_config.raw_extraction) { + if (state->tx_cnt > 1 && !state->curr_tx->done) { + // we did not close the previous tx, set error + SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT); + FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, FILE_TRUNCATED); + tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + } + if (FileOpenFileWithId(&tx->files_ts, &smtp_config.sbcfg, state->file_track_id++, + (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0, + FILE_NOMD5 | FILE_NOMAGIC) == 0) { + SMTPNewFile(tx, tx->files_ts.tail); + } + } else if (smtp_config.decode_mime) { + if (tx->mime_state) { + /* We have 2 chained mails and did not detect the end + * of first one. So we start a new transaction. */ + tx->mime_state->state_flag = PARSE_ERROR; + SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT); + tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + } + tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk); + if (tx->mime_state == NULL) { + return MIME_DEC_ERR_MEM; + } + + /* Add new MIME message to end of list */ + if (tx->msg_head == NULL) { + tx->msg_head = tx->mime_state->msg; + tx->msg_tail = tx->mime_state->msg; + } else { + tx->msg_tail->next = tx->mime_state->msg; + tx->msg_tail = tx->mime_state->msg; + } + } + /* Enter immediately data mode without waiting for server reply */ + if (state->parser_state & SMTP_PARSER_STATE_PIPELINING_SERVER) { + state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; + } + } else if (line->len >= 4 && SCMemcmpLowercase("bdat", line->buf, 4) == 0) { + r = SMTPParseCommandBDAT(state, line); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_BDAT; + state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; + } else if (line->len >= 4 && ((SCMemcmpLowercase("helo", line->buf, 4) == 0) || + SCMemcmpLowercase("ehlo", line->buf, 4) == 0)) { + r = SMTPParseCommandHELO(state, line); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; + } else if (line->len >= 9 && SCMemcmpLowercase("mail from", line->buf, 9) == 0) { + r = SMTPParseCommandMAILFROM(state, line); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; + } else if (line->len >= 7 && SCMemcmpLowercase("rcpt to", line->buf, 7) == 0) { + r = SMTPParseCommandRCPTTO(state, line); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; + } else if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) { + // Resets chunk index in case of connection reuse + state->bdat_chunk_idx = 0; + state->current_command = SMTP_COMMAND_RSET; + } else { + state->current_command = SMTP_COMMAND_OTHER_CMD; + } + + /* Every command is inserted into a command buffer, to be matched + * against reply(ies) sent by the server */ + if (SMTPInsertCommandIntoCommandBuffer(state->current_command, state, f) == -1) { + SCReturnInt(-1); + } + + SCReturnInt(r); + } + + switch (state->current_command) { + case SMTP_COMMAND_STARTTLS: + return SMTPProcessCommandSTARTTLS(state, f, pstate); + + case SMTP_COMMAND_DATA: + return SMTPProcessCommandDATA(state, tx, f, pstate, line); + + case SMTP_COMMAND_BDAT: + return SMTPProcessCommandBDAT(state, f, pstate, line); + + default: + /* we have nothing to do with any other command at this instant. + * Just let it go through */ + SCReturnInt(0); + } +} + +static inline void ResetLine(SMTPLine *line) +{ + if (line != NULL) { + line->len = 0; + line->delim_len = 0; + line->buf = NULL; + } +} + +/* + * @brief Pre Process the data that comes in DATA mode. + * + * If currently, the command that is being processed is DATA, whatever data + * comes as a part of it must be handled by this function. This is because + * there should be no char limit imposition on the line arriving in the DATA + * mode. Such limits are in place for any lines passed to the GetLine function + * and the lines are capped there at SMTP_LINE_BUFFER_LIMIT. + * One such limit in DATA mode may lead to file data or parts of e-mail being + * truncated if the line were too long. + * + * @param state Pointer to the current SMTPState + * @param f Pointer to the current Flow + * @param pstate Pointer to the current AppLayerParserState + * @param input Pointer to the current input data to SMTP parser + * @param line Pointer to the current line being parsed by the SMTP parser + * @return 0 for success + * 1 for handing control over to GetLine + * -1 for errors and inconsistent states + * */ +static int SMTPPreProcessCommands( + SMTPState *state, Flow *f, AppLayerParserState *pstate, SMTPInput *input, SMTPLine *line) +{ + DEBUG_VALIDATE_BUG_ON((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0); + DEBUG_VALIDATE_BUG_ON(line->len != 0); + DEBUG_VALIDATE_BUG_ON(line->delim_len != 0); + + /* fall back to strict line parsing for mime header parsing */ + if (state->curr_tx && state->curr_tx->mime_state && + state->curr_tx->mime_state->state_flag < HEADER_DONE) + return 1; + + bool line_complete = false; + const int32_t input_len = input->len; + const int32_t offset = input->consumed; + for (int32_t i = 0; i < input_len; i++) { + if (input->buf[offset + i] == 0x0d) { + if (i < input_len - 1 && input->buf[offset + i + 1] == 0x0a) { + i++; + line->delim_len++; + } + /* Line is just ending in CR */ + line->delim_len++; + line_complete = true; + } else if (input->buf[offset + i] == 0x0a) { + /* Line is just ending in LF */ + line->delim_len++; + line_complete = true; + } + /* Either line is complete or fragmented */ + if (line_complete || (i == input_len - 1)) { + DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len); + DEBUG_VALIDATE_BUG_ON(input->len == 0 && input_len != 0); + /* state->input_len reflects data from start of the line in progress. */ + if ((input->len == 1 && input->buf[input->consumed] == '-') || + (input->len > 1 && input->buf[input->consumed] == '-' && + input->buf[input->consumed + 1] == '-')) { + SCLogDebug("Possible boundary, yield to GetLine"); + return 1; + } + /* total_consumed should be input consumed so far + i + 1 */ + int32_t total_consumed = offset + i + 1; + int32_t current_line_consumed = total_consumed - input->consumed; + DEBUG_VALIDATE_BUG_ON(current_line_consumed < line->delim_len); + line->buf = input->buf + input->consumed; + line->len = current_line_consumed - line->delim_len; + DEBUG_VALIDATE_BUG_ON(line->len < 0); + if (line->len < 0) { + return -1; + } + input->consumed = total_consumed; + input->len -= current_line_consumed; + DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len); + if (SMTPProcessRequest(state, f, pstate, input, line) == -1) { + return -1; + } + line_complete = false; + line->buf = NULL; + line->len = 0; + line->delim_len = 0; + + /* bail if `SMTPProcessRequest` ended the data mode */ + if ((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0) + break; + } + } + return 0; +} + +static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state, + AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data) +{ + SCEnter(); + + const uint8_t *input_buf = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + if (input_buf == NULL && + ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) || + (direction == 1 && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) { + SCReturnStruct(APP_LAYER_OK); + } else if (input_buf == NULL || input_len == 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + + SMTPInput input = { .buf = input_buf, .len = input_len, .orig_len = input_len, .consumed = 0 }; + SMTPLine line = { NULL, 0, 0, false }; + + /* toserver */ + if (direction == 0) { + if (((state->current_command == SMTP_COMMAND_DATA) || + (state->current_command == SMTP_COMMAND_BDAT)) && + (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + int ret = SMTPPreProcessCommands(state, f, pstate, &input, &line); + DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1); + if (ret == 0 && input.consumed == input.orig_len) { + SCReturnStruct(APP_LAYER_OK); + } else if (ret < 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + } + AppLayerResult res = SMTPGetLine(state, &input, &line, direction); + while (res.status == 0) { + int retval = SMTPProcessRequest(state, f, pstate, &input, &line); + if (retval != 0) + SCReturnStruct(APP_LAYER_ERROR); + if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) { + if (!line.lf_found) { + state->discard_till_lf_ts = true; + } + input.consumed = input.len + 1; // For the newly found LF + SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE); + break; + } + /* If request was successfully parsed, reset line as it has already been used + * wherever it had to be */ + ResetLine(&line); + + /* If DATA mode was entered in the middle of input parsing, exempt it from GetLine as we + * don't want input limits to be exercised on DATA data. Here, SMTPPreProcessCommands + * should either consume all the data or return in case it encounters another boundary. + * In case of another boundary, the control should be passed to SMTPGetLine */ + if ((input.len > 0) && (state->current_command == SMTP_COMMAND_DATA) && + (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + int ret = SMTPPreProcessCommands(state, f, pstate, &input, &line); + DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1); + if (ret == 0 && input.consumed == input.orig_len) { + SCReturnStruct(APP_LAYER_OK); + } else if (ret < 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + } + res = SMTPGetLine(state, &input, &line, direction); + } + if (res.status == 1) + return res; + /* toclient */ + } else { + AppLayerResult res = SMTPGetLine(state, &input, &line, direction); + while (res.status == 0) { + if (SMTPProcessReply(state, f, pstate, thread_data, &input, &line) != 0) + SCReturnStruct(APP_LAYER_ERROR); + if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) { + if (!line.lf_found) { + state->discard_till_lf_tc = true; + } + input.consumed = input.len + 1; // For the newly found LF + SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE); + break; + } + res = SMTPGetLine(state, &input, &line, direction); + } + if (res.status == 1) + return res; + } + + SCReturnStruct(APP_LAYER_OK); +} + +static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + SCEnter(); + + /* first arg 0 is toserver */ + return SMTPParse(0, f, alstate, pstate, stream_slice, local_data); +} + +static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + SCEnter(); + + /* first arg 1 is toclient */ + return SMTPParse(1, f, alstate, pstate, stream_slice, local_data); +} + +/** + * \internal + * \brief Function to allocate SMTP state memory. + */ +void *SMTPStateAlloc(void *orig_state, AppProto proto_orig) +{ + SMTPState *smtp_state = SCCalloc(1, sizeof(SMTPState)); + if (unlikely(smtp_state == NULL)) + return NULL; + + smtp_state->cmds = SCMalloc(sizeof(uint8_t) * SMTP_COMMAND_BUFFER_STEPS); + if (smtp_state->cmds == NULL) { + SCFree(smtp_state); + return NULL; + } + smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS; + + TAILQ_INIT(&smtp_state->tx_list); + + return smtp_state; +} + +static SMTPString *SMTPStringAlloc(void) +{ + SMTPString *smtp_string = SCCalloc(1, sizeof(SMTPString)); + if (unlikely(smtp_string == NULL)) + return NULL; + + return smtp_string; +} + +static void SMTPStringFree(SMTPString *str) +{ + if (str->str) { + SCFree(str->str); + } + SCFree(str); +} + +static void *SMTPLocalStorageAlloc(void) +{ + /* needed by the mpm */ + SMTPThreadCtx *td = SCCalloc(1, sizeof(*td)); + if (td == NULL) { + exit(EXIT_FAILURE); + } + + td->pmq = SCCalloc(1, sizeof(*td->pmq)); + if (td->pmq == NULL) { + exit(EXIT_FAILURE); + } + PmqSetup(td->pmq); + + td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx)); + if (unlikely(td->smtp_mpm_thread_ctx == NULL)) { + exit(EXIT_FAILURE); + } + MpmInitThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM); + return td; +} + +static void SMTPLocalStorageFree(void *ptr) +{ + SMTPThreadCtx *td = ptr; + if (td != NULL) { + if (td->pmq != NULL) { + PmqFree(td->pmq); + SCFree(td->pmq); + } + + if (td->smtp_mpm_thread_ctx != NULL) { + MpmDestroyThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM); + SCFree(td->smtp_mpm_thread_ctx); + } + + SCFree(td); + } + + return; +} + +static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) +{ + if (tx->mime_state != NULL) { + MimeDecDeInitParser(tx->mime_state); + } + /* Free list of MIME message recursively */ + MimeDecFreeEntity(tx->msg_head); + + if (tx->tx_data.events != NULL) + AppLayerDecoderEventsFreeEvents(&tx->tx_data.events); + + if (tx->tx_data.de_state != NULL) + DetectEngineStateFree(tx->tx_data.de_state); + + if (tx->mail_from) + SCFree(tx->mail_from); + + SMTPString *str = NULL; + while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) { + TAILQ_REMOVE(&tx->rcpt_to_list, str, next); + SMTPStringFree(str); + } + FileContainerRecycle(&tx->files_ts, &smtp_config.sbcfg); + + SCFree(tx); +} + +/** + * \internal + * \brief Function to free SMTP state memory. + */ +static void SMTPStateFree(void *p) +{ + SMTPState *smtp_state = (SMTPState *)p; + + if (smtp_state->cmds != NULL) { + SCFree(smtp_state->cmds); + } + + if (smtp_state->helo) { + SCFree(smtp_state->helo); + } + + SMTPTransaction *tx = NULL; + while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) { + TAILQ_REMOVE(&smtp_state->tx_list, tx, next); + SMTPTransactionFree(tx, smtp_state); + } + + SCFree(smtp_state); + + return; +} + +static void SMTPSetMpmState(void) +{ + smtp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx)); + if (unlikely(smtp_mpm_ctx == NULL)) { + exit(EXIT_FAILURE); + } + MpmInitCtx(smtp_mpm_ctx, SMTP_MPM); + + uint32_t i = 0; + for (i = 0; i < sizeof(smtp_reply_map) / sizeof(SCEnumCharMap) - 1; i++) { + SCEnumCharMap *map = &smtp_reply_map[i]; + /* The third argument is 3, because reply code is always 3 bytes. */ + MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3, 0 /* defunct */, + 0 /* defunct */, i /* pattern id */, i /* rule id */, 0 /* no flags */); + } + + mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); +} + +static void SMTPFreeMpmState(void) +{ + if (smtp_mpm_ctx != NULL) { + mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx); + SCFree(smtp_mpm_ctx); + smtp_mpm_ctx = NULL; + } +} + +static int SMTPStateGetEventInfo( + const char *event_name, int *event_id, AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table); + if (*event_id == -1) { + SCLogError("event \"%s\" not present in " + "smtp's enum map table.", + event_name); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static int SMTPStateGetEventInfoById( + int event_id, const char **event_name, AppLayerEventType *event_type) +{ + *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table); + if (*event_name == NULL) { + SCLogError("event \"%d\" not present in " + "smtp's enum map table.", + event_id); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static int SMTPRegisterPatternsForProtocolDetection(void) +{ + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_SMTP, "QUIT", 4, 0, STREAM_TOSERVER) < 0) { + return -1; + } + + return 0; +} + +static void SMTPStateTransactionFree(void *state, uint64_t tx_id) +{ + SMTPState *smtp_state = state; + SMTPTransaction *tx = NULL; + TAILQ_FOREACH (tx, &smtp_state->tx_list, next) { + if (tx_id < tx->tx_id) + break; + else if (tx_id > tx->tx_id) + continue; + + if (tx == smtp_state->curr_tx) + smtp_state->curr_tx = NULL; + TAILQ_REMOVE(&smtp_state->tx_list, tx, next); + SMTPTransactionFree(tx, state); + break; + } +} + +/** \retval cnt highest tx id */ +static uint64_t SMTPStateGetTxCnt(void *state) +{ + uint64_t cnt = 0; + SMTPState *smtp_state = state; + if (smtp_state) { + cnt = smtp_state->tx_cnt; + } + SCLogDebug("returning %" PRIu64, cnt); + return cnt; +} + +static void *SMTPStateGetTx(void *state, uint64_t id) +{ + SMTPState *smtp_state = state; + if (smtp_state) { + SMTPTransaction *tx = NULL; + + if (smtp_state->curr_tx == NULL) + return NULL; + if (smtp_state->curr_tx->tx_id == id) + return smtp_state->curr_tx; + + TAILQ_FOREACH (tx, &smtp_state->tx_list, next) { + if (tx->tx_id == id) + return tx; + } + } + return NULL; +} + +static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction) +{ + SMTPTransaction *tx = vtx; + return tx->done; +} + +static AppLayerGetFileState SMTPGetTxFiles(void *state, void *txv, uint8_t direction) +{ + AppLayerGetFileState files = { .fc = NULL, .cfg = &smtp_config.sbcfg }; + SMTPTransaction *tx = (SMTPTransaction *)txv; + + if (direction & STREAM_TOSERVER) { + files.fc = &tx->files_ts; + } + return files; +} + +static AppLayerTxData *SMTPGetTxData(void *vtx) +{ + SMTPTransaction *tx = (SMTPTransaction *)vtx; + return &tx->tx_data; +} + +static AppLayerStateData *SMTPGetStateData(void *vstate) +{ + SMTPState *state = (SMTPState *)vstate; + return &state->state_data; +} + +/** \brief SMTP tx iterator, specialized for its linked list + * + * \retval txptr or NULL if no more txs in list + */ +static AppLayerGetTxIterTuple SMTPGetTxIterator(const uint8_t ipproto, const AppProto alproto, + void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state) +{ + SMTPState *smtp_state = (SMTPState *)alstate; + AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; + if (smtp_state) { + SMTPTransaction *tx_ptr; + if (state->un.ptr == NULL) { + tx_ptr = TAILQ_FIRST(&smtp_state->tx_list); + } else { + tx_ptr = (SMTPTransaction *)state->un.ptr; + } + if (tx_ptr) { + while (tx_ptr->tx_id < min_tx_id) { + tx_ptr = TAILQ_NEXT(tx_ptr, next); + if (!tx_ptr) { + return no_tuple; + } + } + if (tx_ptr->tx_id >= max_tx_id) { + return no_tuple; + } + state->un.ptr = TAILQ_NEXT(tx_ptr, next); + AppLayerGetTxIterTuple tuple = { + .tx_ptr = tx_ptr, + .tx_id = tx_ptr->tx_id, + .has_next = (state->un.ptr != NULL), + }; + return tuple; + } + } + return no_tuple; +} + +/** + * \brief Register the SMTP Protocol parser. + */ +void RegisterSMTPParsers(void) +{ + const char *proto_name = "smtp"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_SMTP, proto_name); + if (SMTPRegisterPatternsForProtocolDetection() < 0) + return; + } else { + SCLogInfo("Protocol detection and parser disabled for %s protocol.", proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree); + + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER, SMTPParseClientRecord); + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT, SMTPParseServerRecord); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo); + AppLayerParserRegisterGetEventInfoById( + IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById); + + AppLayerParserRegisterLocalStorageFunc( + IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, SMTPLocalStorageFree); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree); + AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxFiles); + AppLayerParserRegisterGetStateProgressFunc( + IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt); + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx); + AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxIterator); + AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData); + AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetStateData); + AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_SMTP, 1, 1); + } else { + SCLogInfo("Parsed disabled for %s protocol. Protocol detection" + "still on.", + proto_name); + } + + SMTPSetMpmState(); + + SMTPConfigure(); + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests); +#endif + return; +} + +/** + * \brief Free memory allocated for global SMTP parser state. + */ +void SMTPParserCleanup(void) +{ + SMTPFreeMpmState(); +} + +/***************************************Unittests******************************/ + +#ifdef UNITTESTS +#include "detect-engine-alert.h" + +static void SMTPTestInitConfig(void) +{ + MimeDecSetConfig(&smtp_config.mime_config); + + smtp_config.content_limit = FILEDATA_CONTENT_LIMIT; + smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + + smtp_config.sbcfg.buf_size = FILEDATA_CONTENT_INSPECT_WINDOW; +} + +/* + * \test Test STARTTLS. + */ +static int SMTPParserTest01(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ + // clang-format off + uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, + 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, + 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, + 0x0d, 0x0a + }; + // clang-format on + uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO [192.168.0.158] */ + // clang-format off + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39, + 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, + 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a + }; + // clang-format on + uint32_t request1_len = sizeof(request1); + /* 250-mx.google.com at your service, [117.198.115.50] + * 250-SIZE 35882577 + * 250-8BITMIME + * 250-STARTTLS + * 250 ENHANCEDSTATUSCODES + */ + // clang-format off + uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, + 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e, + 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e, + 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, + 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35, + 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a, + 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54, + 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, + 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, + 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f, + 0x44, 0x45, 0x53, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply1_len = sizeof(reply1); + + /* STARTTLS */ + // clang-format off + uint8_t request2[] = { + 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, + 0x0d, 0x0a + }; + // clang-format on + uint32_t request2_len = sizeof(request2); + /* 220 2.0.0 Ready to start TLS */ + // clang-format off + uint8_t reply2[] = { + 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20, + 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply2_len = sizeof(reply2); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + if (!FlowChangeProto(&f)) { + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** + * \test Test multiple DATA commands(full mail transactions). + */ +static int SMTPParserTest02(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ + // clang-format off + uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, + 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, + 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, + 0x0d, 0x0a + }; + // clang-format on + uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO boo.com */ + // clang-format off + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a + }; + // clang-format on + uint32_t request1_len = sizeof(request1); + /* 250-mx.google.com at your service, [117.198.115.50] + * 250-SIZE 35882577 + * 250-8BITMIME + * 250-STARTTLS + * 250 ENHANCEDSTATUSCODES + */ + // clang-format off + uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, + 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, + 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, + 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, + 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, + 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, + 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply1_len = sizeof(reply1); + + /* MAIL FROM:asdff@asdf.com */ + // clang-format off + uint8_t request2[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, + 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a + }; + // clang-format on + uint32_t request2_len = sizeof(request2); + /* 250 2.1.0 Ok */ + // clang-format off + uint8_t reply2[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply2_len = sizeof(reply2); + + /* RCPT TO:bimbs@gmail.com */ + // clang-format off + uint8_t request3[] = { + 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, + 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, + 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, + 0x0a + }; + // clang-format on + uint32_t request3_len = sizeof(request3); + /* 250 2.1.5 Ok */ + // clang-format off + uint8_t reply3[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply3_len = sizeof(reply3); + + /* DATA */ + // clang-format off + uint8_t request4[] = { + 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a + }; + // clang-format on + uint32_t request4_len = sizeof(request4); + /* 354 End data with .|| */ + // clang-format off + uint8_t reply4[] = { + 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, + 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, + 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, + 0x4c, 0x46, 0x3e, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply4_len = sizeof(reply4); + + /* FROM:asdff@asdf.com */ + // clang-format off + uint8_t request5_1[] = { + 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, + 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, + 0x63, 0x6f, 0x6d, 0x0d, 0x0a + }; + // clang-format on + uint32_t request5_1_len = sizeof(request5_1); + /* TO:bimbs@gmail.com */ + // clang-format off + uint8_t request5_2[] = { + 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, + 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x0d, 0x0a + }; + // clang-format on + uint32_t request5_2_len = sizeof(request5_2); + /* */ + // clang-format off + uint8_t request5_3[] = { + 0x0d, 0x0a + }; + // clang-format on + uint32_t request5_3_len = sizeof(request5_3); + /* this is test mail1 */ + // clang-format off + uint8_t request5_4[] = { + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69, + 0x6c, 0x31, 0x0d, 0x0a + }; + // clang-format on + uint32_t request5_4_len = sizeof(request5_4); + /* . */ + // clang-format off + uint8_t request5_5[] = { + 0x2e, 0x0d, 0x0a + }; + // clang-format on + uint32_t request5_5_len = sizeof(request5_5); + /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ + // clang-format off + uint8_t reply5[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, + 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, + 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, + 0x46, 0x32, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply5_len = sizeof(reply5); + + /* MAIL FROM:asdfg@asdf.com */ + // clang-format off + uint8_t request6[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40, + 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a + }; + // clang-format on + uint32_t request6_len = sizeof(request6); + /* 250 2.1.0 Ok */ + // clang-format off + uint8_t reply6[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply6_len = sizeof(reply6); + + /* RCPT TO:bimbs@gmail.com */ + // clang-format off + uint8_t request7[] = { + 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, + 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, + 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, + 0x0a + }; + // clang-format on + uint32_t request7_len = sizeof(request7); + /* 250 2.1.5 Ok */ + // clang-format off + uint8_t reply7[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply7_len = sizeof(reply7); + + /* DATA */ + // clang-format off + uint8_t request8[] = { + 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a + }; + // clang-format on + uint32_t request8_len = sizeof(request8); + /* 354 End data with .|| */ + // clang-format off + uint8_t reply8[] = { + 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, + 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, + 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, + 0x4c, 0x46, 0x3e, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply8_len = sizeof(reply8); + + /* FROM:asdfg@gmail.com */ + // clang-format off + uint8_t request9_1[] = { + 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, + 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a + }; + // clang-format on + uint32_t request9_1_len = sizeof(request9_1); + /* TO:bimbs@gmail.com */ + // clang-format off + uint8_t request9_2[] = { + 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73, + 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x0d, 0x0a + }; + // clang-format on + uint32_t request9_2_len = sizeof(request9_2); + /* */ + // clang-format off + uint8_t request9_3[] = { + 0x0d, 0x0a + }; + // clang-format on + uint32_t request9_3_len = sizeof(request9_3); + /* this is test mail2 */ + // clang-format off + uint8_t request9_4[] = { + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69, + 0x6c, 0x32, 0x0d, 0x0a + }; + // clang-format on + uint32_t request9_4_len = sizeof(request9_4); + /* . */ + // clang-format off + uint8_t request9_5[] = { + 0x2e, 0x0d, 0x0a + }; + // clang-format on + uint32_t request9_5_len = sizeof(request9_5); + /* 250 2.0.0 Ok: queued as 28CFF20BF2 */ + // clang-format off + uint8_t reply9[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, + 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, + 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42, + 0x46, 0x32, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply9_len = sizeof(reply9); + + /* QUIT */ + // clang-format off + uint8_t request10[] = { + 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a + }; + // clang-format on + uint32_t request10_len = sizeof(request10); + /* 221 2.0.0 Bye */ + // clang-format off + uint8_t reply10[] = { + 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply10_len = sizeof(reply10); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4, reply4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_1, request5_1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_2, request5_2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_3, request5_3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_4, request5_4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5_5, request5_5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply5, reply5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request6, request6_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply6, reply6_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request7, request7_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply7, reply7_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request8, request8_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply8, reply8_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_1, request9_1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_2, request9_2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_3, request9_3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_4, request9_4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request9_5, request9_5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply9, reply9_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request10, request10_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply10, reply10_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** + * \test Testing parsing pipelined commands. + */ +static int SMTPParserTest03(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ + // clang-format off + uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, + 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, + 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a + }; + // clang-format on + uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO boo.com */ + // clang-format off + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0a + }; + // clang-format on + uint32_t request1_len = sizeof(request1); + /* 250-poona_slack_vm1.localdomain + * 250-PIPELINING + * 250-SIZE 10240000 + * 250-VRFY + * 250-ETRN + * 250-ENHANCEDSTATUSCODES + * 250-8BITMIME + * 250 DSN + */ + // clang-format off + uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, + 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, + 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, + 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, + 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, + 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, + 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, + 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply1_len = sizeof(reply1); + + /* MAIL FROM:pbsf@asdfs.com + * RCPT TO:pbsf@asdfs.com + * DATA + * Immediate data + */ + // clang-format off + uint8_t request2[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, + 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, + 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, + 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a, + 0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, + 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a, + }; + // clang-format on + uint32_t request2_len = sizeof(request2); + /* 250 2.1.0 Ok + * 250 2.1.5 Ok + * 354 End data with .|| + */ + // clang-format off + uint8_t reply2[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20, + 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20, + 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43, + 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c, + 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d, + 0x0a + }; + // clang-format on + uint32_t reply2_len = sizeof(reply2); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD || + smtp_state->cmds[2] != SMTP_COMMAND_DATA || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/* + * \test Test smtp with just delimiter instead of . + */ +static int SMTPParserTest04(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ + // clang-format off + uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, + 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, + 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a + }; + // clang-format on + uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO boo.com */ + // clang-format off + uint8_t request1[] = { + 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, + 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, + 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a + }; + // clang-format on + uint32_t request1_len = sizeof(request1); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/* + * \test Test STARTTLS fail. + */ +static int SMTPParserTest05(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 poona_slack_vm1.localdomain ESMTP Postfix */ + // clang-format off + uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, + 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f, + 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a + }; + // clang-format on + uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO boo.com */ + // clang-format off + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a + }; + // clang-format on + uint32_t request1_len = sizeof(request1); + /* 250-poona_slack_vm1.localdomain + * 250-PIPELINING + * 250-SIZE 10240000 + * 250-VRFY + * 250-ETRN + * 250-ENHANCEDSTATUSCODES + * 250-8BITMIME + * 250 DSN + */ + // clang-format off + uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, + 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, + 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, + 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, + 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, + 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, + 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, + 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply1_len = sizeof(reply1); + + /* STARTTLS */ + // clang-format off + uint8_t request2[] = { + 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, + 0x0d, 0x0a + }; + // clang-format on + uint32_t request2_len = sizeof(request2); + /* 502 5.5.2 Error: command not recognized */ + // clang-format off + uint8_t reply2[] = { + 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e, + 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, + 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63, + 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d, + 0x0a + }; + // clang-format on + uint32_t reply2_len = sizeof(reply2); + + /* QUIT */ + // clang-format off + uint8_t request3[] = { + 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a + + }; + // clang-format on + uint32_t request3_len = sizeof(request3); + /* 221 2.0.0 Bye */ + // clang-format off + uint8_t reply3[] = { + 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply3_len = sizeof(reply3); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) || (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || + (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || + (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_PIPELINING_SERVER)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** + * \test Test multiple DATA commands(full mail transactions). + */ +static int SMTPParserTest06(void) +{ + int result = 0; + Flow f; + int r = 0; + + // clang-format off + uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30, + 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30, + 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f, + 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69, + 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, + 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b, + 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20, + 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f, + 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69, + 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, + 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f, + 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72, + 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73, + 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e, + 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f, + 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c, + 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70, + 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, + 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, + 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69, + 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62, + 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35, + 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d, + 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a + }; + // clang-format on + uint32_t welcome_reply_len = sizeof(welcome_reply); + + // clang-format off + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43, + 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63, + 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69, + 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d, + 0x0a + }; + // clang-format on + uint32_t request1_len = sizeof(request1); + + // clang-format off + uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30, + 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30, + 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f, + 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31, + 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c, + 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31, + 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39, + 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, + 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39, + 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69, + 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49, + 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47, + 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55, + 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e, + 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55, + 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e, + 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b, + 0x0d, 0x0a + }; + // clang-format on + uint32_t reply1_len = sizeof(reply1); + + /* MAIL FROM:asdff@asdf.com */ + // clang-format off + uint8_t request2[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, + 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a + }; + // clang-format on + uint32_t request2_len = sizeof(request2); + /* 250 2.1.0 Ok */ + // clang-format off + uint8_t reply2[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply2_len = sizeof(reply2); + + /* RCPT TO:bimbs@gmail.com */ + // clang-format off + uint8_t request3[] = { + 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, + 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, + 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, + 0x0a + }; + // clang-format on + uint32_t request3_len = sizeof(request3); + /* 250 2.1.5 Ok */ + // clang-format off + uint8_t reply3[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + uint32_t reply3_len = sizeof(reply3); + + /* BDAT 51 */ + // clang-format off + uint8_t request4[] = { + 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d, + 0x0a, + }; + // clang-format on + uint32_t request4_len = sizeof(request4); + + // clang-format off + uint8_t request5[] = { + 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, + 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, + 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, + 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a, + }; + // clang-format on + uint32_t request5_len = sizeof(request5); + + // clang-format off + uint8_t request6[] = { + 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64, + 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e, + 0x66, 0x0d, 0x0a, + }; + // clang-format on + uint32_t request6_len = sizeof(request6); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_BDAT || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE) || + smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 0) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5, request5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE) || + smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 32) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request6, request6_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN || + smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 51) { + printf("smtp parser in inconsistent state\n"); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +static int SMTPParserTest12(void) +{ + int result = 0; + Signature *s = NULL; + ThreadVars th_v; + Packet *p = NULL; + Flow f; + TcpSession ssn; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + SMTPState *smtp_state = NULL; + int r = 0; + + /* EHLO boo.com */ + // clang-format off + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, + }; + // clang-format on + int32_t request1_len = sizeof(request1); + + /* 388 + */ + // clang-format off + uint8_t reply1[] = { + 0x31, 0x38, 0x38, 0x0d, 0x0a, + }; + // clang-format on + uint32_t reply1_len = sizeof(reply1); + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(msg:\"SMTP event handling\"; " + "app-layer-event: smtp.invalid_reply; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, + request1, request1_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %" PRId32, r); + goto end; + } + + smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched. It shouldn't match: "); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT, + reply1, reply1_len); + if (r == 0) { + printf("AppLayerParse for smtp failed. Returned %" PRId32, r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; + +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +static int SMTPParserTest13(void) +{ + int result = 0; + Signature *s = NULL; + ThreadVars th_v; + Packet *p = NULL; + Flow f; + TcpSession ssn; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + SMTPState *smtp_state = NULL; + int r = 0; + + /* EHLO boo.com */ + // clang-format off + uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, + }; + // clang-format on + int32_t request1_len = sizeof(request1); + + /* 250 + */ + // clang-format off + uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x0d, 0x0a, + }; + // clang-format on + uint32_t reply1_len = sizeof(reply1); + + /* MAIL FROM:pbsf@asdfs.com + * RCPT TO:pbsf@asdfs.com + * DATA + * STARTTLS + */ + // clang-format off + uint8_t request2[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, + 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, + 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, + 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a, + 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53, + 0x0d, 0x0a + }; + // clang-format on + uint32_t request2_len = sizeof(request2); + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(msg:\"SMTP event handling\"; " + "app-layer-event: " + "smtp.invalid_pipelined_sequence; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, + request1, request1_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %" PRId32, r); + goto end; + } + + smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched. It shouldn't match: "); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %" PRId32, r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched. It shouldn't match: "); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %" PRId32, r); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; + +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + * \test Test DATA command w/MIME message. + */ +static int SMTPParserTest14(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ + // clang-format off + static uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, + 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, + 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, + 0x0d, 0x0a + }; + // clang-format on + static uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO boo.com */ + // clang-format off + static uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a + }; + // clang-format on + static uint32_t request1_len = sizeof(request1); + /* 250-mx.google.com at your service, [117.198.115.50] + * 250-SIZE 35882577 + * 250-8BITMIME + * 250-STARTTLS + * 250 ENHANCEDSTATUSCODES + */ + // clang-format off + static uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, + 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, + 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, + 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, + 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, + 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, + 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a + }; + // clang-format on + static uint32_t reply1_len = sizeof(reply1); + + /* MAIL FROM:asdff@asdf.com */ + // clang-format off + static uint8_t request2[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, + 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a + }; + // clang-format on + static uint32_t request2_len = sizeof(request2); + /* 250 2.1.0 Ok */ + // clang-format off + static uint8_t reply2[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + static uint32_t reply2_len = sizeof(reply2); + + /* RCPT TO:bimbs@gmail.com */ + // clang-format off + static uint8_t request3[] = { + 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, + 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, + 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, + 0x0a + }; + // clang-format on + static uint32_t request3_len = sizeof(request3); + /* 250 2.1.5 Ok */ + // clang-format off + static uint8_t reply3[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + // clang-format on + static uint32_t reply3_len = sizeof(reply3); + + /* DATA */ + // clang-format off + static uint8_t request4[] = { + 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a + }; + // clang-format on + static uint32_t request4_len = sizeof(request4); + /* 354 End data with .|| */ + // clang-format off + static uint8_t reply4[] = { + 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, + 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, + 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, + 0x4c, 0x46, 0x3e, 0x0d, 0x0a + }; + // clang-format on + static uint32_t reply4_len = sizeof(reply4); + + /* MIME_MSG */ + static uint64_t filesize = 133; + // clang-format off + static uint8_t request4_msg[] = { + 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, + 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, + 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, + 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, + 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, + 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78, + 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41, + 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61, + 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43, + 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41, + 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65, + 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C, + 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, + 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, + 0x41, 0x3D, 0x3D, 0x0D,0x0A }; + // clang-format on + static uint32_t request4_msg_len = sizeof(request4_msg); + + /* DATA COMPLETED */ + // clang-format off + static uint8_t request4_end[] = { + 0x0d, 0x0a, 0x2e, 0x0d, 0x0a + }; + // clang-format on + static uint32_t request4_end_len = sizeof(request4_end); + /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ + // clang-format off + static uint8_t reply4_end[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, + 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, + 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, + 0x46, 0x32, 0x0d, 0x0a + }; + // clang-format on + static uint32_t reply4_end_len = sizeof(reply4_end); + + /* QUIT */ + // clang-format off + static uint8_t request5[] = { + 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a + }; + // clang-format on + static uint32_t request5_len = sizeof(request5); + /* 221 2.0.0 Bye */ + // clang-format off + static uint8_t reply5[] = { + 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a + }; + // clang-format on + static uint32_t reply5_len = sizeof(reply5); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(true); + SMTPTestInitConfig(); + + /* Welcome reply */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* EHLO Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) { + printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, + smtp_state->helo_len); + goto end; + } + + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* MAIL FROM Request */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* MAIL FROM Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if ((smtp_state->curr_tx->mail_from_len != 14) || + strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) { + printf("incorrect parsing of MAIL FROM field '%s' (%d)\n", smtp_state->curr_tx->mail_from, + smtp_state->curr_tx->mail_from_len); + goto end; + } + + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* RCPT TO Request */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request3, request3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* RCPT TO Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply3, reply3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* Enable mime decoding */ + smtp_config.decode_mime = true; + smtp_config.mime_config.decode_base64 = true; + smtp_config.mime_config.decode_quoted_printable = true; + MimeDecSetConfig(&smtp_config.mime_config); + + /* DATA request */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4, request4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* Data reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4, reply4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* DATA message */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4_msg, request4_msg_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->curr_tx->mime_state == NULL || + smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ + smtp_state->parser_state != + (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* DATA . request */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request4_end, request4_end_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || + smtp_state->curr_tx->mime_state == NULL || + smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + SMTPState *state = (SMTPState *)f.alstate; + FAIL_IF_NULL(state); + FAIL_IF_NULL(state->curr_tx); + + FileContainer *files = &state->curr_tx->files_ts; + if (files != NULL && files->head != NULL) { + File *file = files->head; + + if (strncmp((const char *)file->name, "test.exe", 8) != 0) { + printf("smtp-mime file name is incorrect"); + goto end; + } + if (FileTrackedSize(file) != filesize) { + printf("smtp-mime file size %" PRIu64 " is incorrect", FileDataSize(file)); + goto end; + } + // clang-format off + static uint8_t org_binary[] = { + 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, + 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36, + 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36, + 0x5C, 0x7A, 0x00, 0x00, 0x38,}; + // clang-format on + + if (StreamingBufferCompareRawData(file->sb, org_binary, sizeof(org_binary)) != 1) { + printf("smtp-mime file data incorrect\n"); + goto end; + } + } + + /* DATA . reply */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply4_end, reply4_end_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* QUIT Request */ + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, request5, request5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* QUIT Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, reply5, reply5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + goto end; + } + if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} +#endif /* UNITTESTS */ + +void SMTPParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SMTPParserTest01", SMTPParserTest01); + UtRegisterTest("SMTPParserTest02", SMTPParserTest02); + UtRegisterTest("SMTPParserTest03", SMTPParserTest03); + UtRegisterTest("SMTPParserTest04", SMTPParserTest04); + UtRegisterTest("SMTPParserTest05", SMTPParserTest05); + UtRegisterTest("SMTPParserTest06", SMTPParserTest06); + UtRegisterTest("SMTPParserTest12", SMTPParserTest12); + UtRegisterTest("SMTPParserTest13", SMTPParserTest13); + UtRegisterTest("SMTPParserTest14", SMTPParserTest14); +#endif /* UNITTESTS */ + + return; +} diff --git a/src/app-layer/smtp/parser.h b/src/app-layer/smtp/parser.h new file mode 100644 index 000000000000..11fbc1192b37 --- /dev/null +++ b/src/app-layer/smtp/parser.h @@ -0,0 +1,161 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __APP_LAYER_SMTP_H__ +#define __APP_LAYER_SMTP_H__ + +#include "util/decode-mime.h" +#include "util/streaming-buffer.h" +#include "rust.h" + +/* Limit till the data would be buffered in current line */ +#define SMTP_LINE_BUFFER_LIMIT 4096 + +enum { + SMTP_DECODER_EVENT_INVALID_REPLY, + SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST, + SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED, + SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED, + SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE, + SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED, + SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE, + SMTP_DECODER_EVENT_TLS_REJECTED, + SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED, + SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE, + + /* MIME Events */ + SMTP_DECODER_EVENT_MIME_PARSE_FAILED, + SMTP_DECODER_EVENT_MIME_MALFORMED_MSG, + SMTP_DECODER_EVENT_MIME_INVALID_BASE64, + SMTP_DECODER_EVENT_MIME_INVALID_QP, + SMTP_DECODER_EVENT_MIME_LONG_LINE, + SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE, + SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME, + SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE, + SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG, + SMTP_DECODER_EVENT_MIME_LONG_FILENAME, + + /* Invalid behavior or content */ + SMTP_DECODER_EVENT_DUPLICATE_FIELDS, + SMTP_DECODER_EVENT_UNPARSABLE_CONTENT, + /* For line >= 4KB */ + SMTP_DECODER_EVENT_TRUNCATED_LINE, +}; + +typedef struct SMTPString_ { + uint8_t *str; + uint16_t len; + + TAILQ_ENTRY(SMTPString_) next; +} SMTPString; + +typedef struct SMTPTransaction_ { + /** id of this tx, starting at 0 */ + uint64_t tx_id; + + AppLayerTxData tx_data; + + int done; + /** the first message contained in the session */ + MimeDecEntity *msg_head; + /** the last message contained in the session */ + MimeDecEntity *msg_tail; + /** the mime decoding parser state */ + MimeDecParseState *mime_state; + + /* MAIL FROM parameters */ + uint8_t *mail_from; + uint16_t mail_from_len; + + TAILQ_HEAD(, SMTPString_) rcpt_to_list; /**< rcpt to string list */ + + FileContainer files_ts; + + TAILQ_ENTRY(SMTPTransaction_) next; +} SMTPTransaction; + +typedef struct SMTPConfig { + + bool decode_mime; + MimeDecConfig mime_config; + uint32_t content_limit; + uint32_t content_inspect_min_size; + uint32_t content_inspect_window; + + bool raw_extraction; + + StreamingBufferConfig sbcfg; +} SMTPConfig; + +typedef struct SMTPState_ { + AppLayerStateData state_data; + SMTPTransaction *curr_tx; + TAILQ_HEAD(, SMTPTransaction_) tx_list; /**< transaction list */ + uint64_t tx_cnt; + uint64_t toserver_data_count; + uint64_t toserver_last_data_stamp; + + /* If rest of the bytes should be discarded in case of long line w/o LF */ + bool discard_till_lf_ts; + bool discard_till_lf_tc; + + /** var to indicate parser state */ + uint8_t parser_state; + /** current command in progress */ + uint8_t current_command; + /** bdat chunk len */ + uint32_t bdat_chunk_len; + /** bdat chunk idx */ + uint32_t bdat_chunk_idx; + + /* the request commands are store here and the reply handler uses these + * stored command in the buffer to match the reply(ies) with the command */ + /** the command buffer */ + uint8_t *cmds; + /** the buffer length */ + uint16_t cmds_buffer_len; + /** no of commands stored in the above buffer */ + uint16_t cmds_cnt; + /** index of the command in the buffer, currently in inspection by reply + * handler */ + uint16_t cmds_idx; + + /* HELO of HELO message content */ + uint16_t helo_len; + uint8_t *helo; + + /* SMTP Mime decoding and file extraction */ + /** the list of files sent to the server */ + uint32_t file_track_id; +} SMTPState; + +/* Create SMTP config structure */ +extern SMTPConfig smtp_config; + +int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state); +void *SMTPStateAlloc(void *orig_state, AppProto proto_orig); +void RegisterSMTPParsers(void); +void SMTPParserCleanup(void); +void SMTPParserRegisterTests(void); + +#endif /* __APP_LAYER_SMTP_H__ */ diff --git a/src/app-layer/snmp/detect-community.c b/src/app-layer/snmp/detect-community.c new file mode 100644 index 000000000000..d2daeb9efb51 --- /dev/null +++ b/src/app-layer/snmp/detect-community.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2015-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * + * Set up of the "snmp.community" keyword to allow content + * inspections on the decoded snmp community. + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/snmp/detect-community.h" +#include "app-layer-parser.h" +#include "rust.h" + +static int DetectSNMPCommunitySetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +#ifdef UNITTESTS +static void DetectSNMPCommunityRegisterTests(void); +#endif +static int g_snmp_rust_id = 0; + +void DetectSNMPCommunityRegister(void) +{ + sigmatch_table[DETECT_AL_SNMP_COMMUNITY].name = "snmp.community"; + sigmatch_table[DETECT_AL_SNMP_COMMUNITY].desc = + "SNMP content modifier to match on the SNMP community"; + sigmatch_table[DETECT_AL_SNMP_COMMUNITY].Setup = DetectSNMPCommunitySetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_SNMP_COMMUNITY].RegisterTests = DetectSNMPCommunityRegisterTests; +#endif + sigmatch_table[DETECT_AL_SNMP_COMMUNITY].url = "/rules/snmp-keywords.html#snmp-community"; + + sigmatch_table[DETECT_AL_SNMP_COMMUNITY].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + /* register inspect engines */ + DetectAppLayerInspectEngineRegister2("snmp.community", ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerMpmRegister2("snmp.community", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SNMP, 0); + DetectAppLayerInspectEngineRegister2("snmp.community", ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerMpmRegister2("snmp.community", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SNMP, 0); + + DetectBufferTypeSetDescriptionByName("snmp.community", "SNMP Community identifier"); + + g_snmp_rust_id = DetectBufferTypeGetByName("snmp.community"); +} + +static int DetectSNMPCommunitySetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_snmp_rust_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t data_len = 0; + const uint8_t *data = NULL; + + rs_snmp_tx_get_community(txv, &data, &data_len); + if (data == NULL || data_len == 0) { + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS +#include "tests/detect-snmp-community.c" +#endif /* UNITTESTS */ diff --git a/src/app-layer/snmp/detect-community.h b/src/app-layer/snmp/detect-community.h new file mode 100644 index 000000000000..16243ccc7e57 --- /dev/null +++ b/src/app-layer/snmp/detect-community.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2015-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author FirstName LastName + */ + +#ifndef __DETECT_SNMP_COMMUNITY_H__ +#define __DETECT_SNMP_COMMUNITY_H__ + +void DetectSNMPCommunityRegister(void); + +#endif /* __DETECT_SNMP_COMMUNITY_H__ */ diff --git a/src/app-layer/snmp/detect-pdu_type.c b/src/app-layer/snmp/detect-pdu_type.c new file mode 100644 index 000000000000..84dfa5395e5a --- /dev/null +++ b/src/app-layer/snmp/detect-pdu_type.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2015-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/snmp/detect-pdu_type.h" +#include "app-layer-parser.h" +#include "rust.h" + +/** + * [snmp.pdu_type]:; + */ +#define PARSE_REGEX "^\\s*([0-9]+)\\s*$" +static DetectParseRegex parse_regex; + +typedef struct DetectSNMPPduTypeData_ { + uint32_t pdu_type; +} DetectSNMPPduTypeData; + +static DetectSNMPPduTypeData *DetectSNMPPduTypeParse(const char *); +static int DetectSNMPPduTypeSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectSNMPPduTypeFree(DetectEngineCtx *, void *); +#ifdef UNITTESTS +static void DetectSNMPPduTypeRegisterTests(void); +#endif +static int g_snmp_pdu_type_buffer_id = 0; + +static int DetectSNMPPduTypeMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +void DetectSNMPPduTypeRegister(void) +{ + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].name = "snmp.pdu_type"; + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].desc = "match SNMP PDU type"; + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].url = "/rules/snmp-keywords.html#snmp-pdu-type"; + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Match = NULL; + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].AppLayerTxMatch = DetectSNMPPduTypeMatch; + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Setup = DetectSNMPPduTypeSetup; + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Free = DetectSNMPPduTypeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].RegisterTests = DetectSNMPPduTypeRegisterTests; +#endif + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2("snmp.pdu_type", ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("snmp.pdu_type", ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + + g_snmp_pdu_type_buffer_id = DetectBufferTypeGetByName("snmp.pdu_type"); +} + +/** + * \internal + * \brief Function to match pdu_type of a TX + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectSNMPPduTypeData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectSNMPPduTypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + const DetectSNMPPduTypeData *dd = (const DetectSNMPPduTypeData *)ctx; + uint32_t pdu_type; + rs_snmp_tx_get_pdu_type(txv, &pdu_type); + SCLogDebug("pdu_type %u ref_pdu_type %d", pdu_type, dd->pdu_type); + if (pdu_type == dd->pdu_type) + SCReturnInt(1); + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to parse options passed via snmp.pdu_type keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectSNMPPduTypeData on success. + * \retval NULL on failure. + */ +static DetectSNMPPduTypeData *DetectSNMPPduTypeParse(const char *rawstr) +{ + DetectSNMPPduTypeData *dd = NULL; + int res = 0; + size_t pcre2len; + char value1[20] = ""; + char *endptr = NULL; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); + if (ret != 2) { + SCLogError("Parse error %s", rawstr); + goto error; + } + + pcre2len = sizeof(value1); + res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)value1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + + dd = SCCalloc(1, sizeof(DetectSNMPPduTypeData)); + if (unlikely(dd == NULL)) + goto error; + + /* set the value */ + dd->pdu_type = strtoul(value1, &endptr, 10); + if (endptr == NULL || *endptr != '\0') { + SCLogError("invalid character as arg " + "to snmp.pdu_type keyword"); + goto error; + } + + pcre2_match_data_free(match); + return dd; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (dd) + SCFree(dd); + return NULL; +} + +/** + * \brief Function to add the parsed snmp pdu_type field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectSNMPPduTypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectSNMPPduTypeData *dd = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) + return -1; + + dd = DetectSNMPPduTypeParse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + SCLogDebug("snmp.pdu_type %d", dd->pdu_type); + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SNMP_PDU_TYPE, (SigMatchCtx *)dd, + g_snmp_pdu_type_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectSNMPPduTypeFree(de_ctx, dd); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectSNMPPduTypeData. + * + * \param de_ptr Pointer to DetectSNMPPduTypeData. + */ +static void DetectSNMPPduTypeFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCFree(ptr); +} + +#ifdef UNITTESTS +#include "tests/detect-snmp-pdu_type.c" +#endif /* UNITTESTS */ diff --git a/src/app-layer/snmp/detect-pdu_type.h b/src/app-layer/snmp/detect-pdu_type.h new file mode 100644 index 000000000000..a97992cfeeec --- /dev/null +++ b/src/app-layer/snmp/detect-pdu_type.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2015-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#ifndef __DETECT_SNMP_PDU_TYPE_H__ +#define __DETECT_SNMP_PDU_TYPE_H__ + +void DetectSNMPPduTypeRegister(void); + +#endif /* __DETECT_SNMP_PDU_TYPE_H__ */ diff --git a/src/app-layer/snmp/detect-usm.c b/src/app-layer/snmp/detect-usm.c new file mode 100644 index 000000000000..ebf02beb0300 --- /dev/null +++ b/src/app-layer/snmp/detect-usm.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "rust.h" +#include "app-layer/snmp/detect-usm.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-parse.h" + +static int g_buffer_id = 0; + +static int DetectSNMPUsmSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t data_len = 0; + const uint8_t *data = NULL; + + rs_snmp_tx_get_usm(txv, &data, &data_len); + if (data == NULL || data_len == 0) { + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +void DetectSNMPUsmRegister(void) +{ + sigmatch_table[DETECT_AL_SNMP_USM].name = "snmp.usm"; + sigmatch_table[DETECT_AL_SNMP_USM].desc = "SNMP content modifier to match on the SNMP usm"; + sigmatch_table[DETECT_AL_SNMP_USM].Setup = DetectSNMPUsmSetup; + + sigmatch_table[DETECT_AL_SNMP_USM].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + /* register inspect engines */ + DetectAppLayerInspectEngineRegister2("snmp.usm", ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerMpmRegister2("snmp.usm", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SNMP, 0); + DetectAppLayerInspectEngineRegister2("snmp.usm", ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerMpmRegister2("snmp.usm", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_SNMP, 0); + + DetectBufferTypeSetDescriptionByName("snmp.usm", "SNMP USM"); + + g_buffer_id = DetectBufferTypeGetByName("snmp.usm"); +} diff --git a/src/detect-snmp-usm.h b/src/app-layer/snmp/detect-usm.h similarity index 100% rename from src/detect-snmp-usm.h rename to src/app-layer/snmp/detect-usm.h diff --git a/src/app-layer/snmp/detect-version.c b/src/app-layer/snmp/detect-version.c new file mode 100644 index 000000000000..a75dcc9d9091 --- /dev/null +++ b/src/app-layer/snmp/detect-version.c @@ -0,0 +1,166 @@ +/* Copyright (C) 2015-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/snmp/detect-version.h" +#include "detect-engine-uint.h" +#include "app-layer-parser.h" +#include "rust.h" + +static int DetectSNMPVersionSetup(DetectEngineCtx *, Signature *s, const char *str); +static void DetectSNMPVersionFree(DetectEngineCtx *, void *); +#ifdef UNITTESTS +static void DetectSNMPVersionRegisterTests(void); +#endif +static int g_snmp_version_buffer_id = 0; + +static int DetectSNMPVersionMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +/** + * \brief Registration function for snmp.procedure keyword. + */ +void DetectSNMPVersionRegister(void) +{ + sigmatch_table[DETECT_AL_SNMP_VERSION].name = "snmp.version"; + sigmatch_table[DETECT_AL_SNMP_VERSION].desc = "match SNMP version"; + sigmatch_table[DETECT_AL_SNMP_VERSION].url = "/rules/snmp-keywords.html#snmp-version"; + sigmatch_table[DETECT_AL_SNMP_VERSION].Match = NULL; + sigmatch_table[DETECT_AL_SNMP_VERSION].AppLayerTxMatch = DetectSNMPVersionMatch; + sigmatch_table[DETECT_AL_SNMP_VERSION].Setup = DetectSNMPVersionSetup; + sigmatch_table[DETECT_AL_SNMP_VERSION].Free = DetectSNMPVersionFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_SNMP_VERSION].RegisterTests = DetectSNMPVersionRegisterTests; +#endif + + DetectAppLayerInspectEngineRegister2("snmp.version", ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("snmp.version", ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectGenericList, NULL); + + g_snmp_version_buffer_id = DetectBufferTypeGetByName("snmp.version"); +} + +/** + * \internal + * \brief Function to match version of a TX + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectU32Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectSNMPVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + const DetectU32Data *dd = (const DetectU32Data *)ctx; + uint32_t version; + rs_snmp_tx_get_version(txv, &version); + SCLogDebug("version %u mode %u ref_version %d", version, dd->mode, dd->arg1); + if (DetectU32Match(version, dd)) + SCReturnInt(1); + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to parse options passed via snmp.version keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectU32Data on success. + * \retval NULL on failure. + */ +static DetectU32Data *DetectSNMPVersionParse(const char *rawstr) +{ + return DetectU32Parse(rawstr); +} + +/** + * \brief Function to add the parsed snmp version field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectSNMPVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectU32Data *dd = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) + return -1; + + dd = DetectSNMPVersionParse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + SCLogDebug("snmp.version %d", dd->arg1); + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SNMP_VERSION, (SigMatchCtx *)dd, + g_snmp_version_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectSNMPVersionFree(de_ctx, dd); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectU32Data. + * + * \param de_ptr Pointer to DetectU32Data. + */ +static void DetectSNMPVersionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} + +#ifdef UNITTESTS +#include "tests/detect-snmp-version.c" +#endif /* UNITTESTS */ diff --git a/src/app-layer/snmp/detect-version.h b/src/app-layer/snmp/detect-version.h new file mode 100644 index 000000000000..45fde57e494b --- /dev/null +++ b/src/app-layer/snmp/detect-version.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2015-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#ifndef __DETECT_SNMP_VERSION_H__ +#define __DETECT_SNMP_VERSION_H__ + +void DetectSNMPVersionRegister(void); + +#endif /* __DETECT_SNMP_VERSION_H__ */ diff --git a/src/app-layer/snmp/logger.c b/src/app-layer/snmp/logger.c new file mode 100644 index 000000000000..44ba61341d3f --- /dev/null +++ b/src/app-layer/snmp/logger.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2018-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * + * Implement JSON/eve logging app-layer SNMP. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/snmp/parser.h" +#include "app-layer/snmp/logger.h" + +#include "rust.h" + +static int JsonSNMPLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + SNMPTransaction *snmptx = tx; + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "snmp", NULL, thread->ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_FAILED; + } + + if (!rs_snmp_log_json_response(snmptx, jb)) { + goto error; + } + + OutputJsonBuilderBuffer(jb, thread); + + jb_free(jb); + return TM_ECODE_OK; + +error: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static OutputInitResult OutputSNMPLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_SNMP); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonSNMPLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSNMPLog", "eve-log.snmp", + OutputSNMPLogInitSub, ALPROTO_SNMP, JsonSNMPLogger, JsonLogThreadInit, + JsonLogThreadDeinit, NULL); + + SCLogDebug("SNMP JSON logger registered."); +} diff --git a/src/output-json-snmp.h b/src/app-layer/snmp/logger.h similarity index 100% rename from src/output-json-snmp.h rename to src/app-layer/snmp/logger.h diff --git a/src/app-layer/snmp/parser.c b/src/app-layer/snmp/parser.c new file mode 100644 index 000000000000..946cae44b8ac --- /dev/null +++ b/src/app-layer/snmp/parser.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2015-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pierre Chifflier + * + * Parser for SNMP v2c/v3 application layer running on UDP port 161. + * + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/snmp/parser.h" +#include "rust.h" + +void RegisterSNMPParsers(void) +{ + rs_register_snmp_parser(); +} diff --git a/src/app-layer-snmp.h b/src/app-layer/snmp/parser.h similarity index 100% rename from src/app-layer-snmp.h rename to src/app-layer/snmp/parser.h diff --git a/src/app-layer/ssh/detect-hassh-server-string.c b/src/app-layer/ssh/detect-hassh-server-string.c new file mode 100644 index 000000000000..ddf4ac865b3e --- /dev/null +++ b/src/app-layer/ssh/detect-hassh-server-string.c @@ -0,0 +1,138 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Vadym Malakhatko + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" +#include "stream-tcp.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-hassh-server-string.h" +#include "rust.h" + +#define KEYWORD_NAME "ssh.hassh.server.string" +#define KEYWORD_ALIAS "ssh-hassh-server-string" +#define KEYWORD_DOC "ssh-keywords.html#ssh.hassh.server.string" +#define BUFFER_NAME "ssh.hassh.server.string" +#define BUFFER_DESC "Ssh Client Key Exchange methods For ssh Servers" +static int g_ssh_hassh_server_string_buffer_id = 0; + +static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + + if (buffer->inspect == NULL) { + const uint8_t *hassh = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_hassh_string(txv, &hassh, &b_len, flow_flags) != 1) + return NULL; + if (hassh == NULL || b_len == 0) { + SCLogDebug("SSH hassh string is not set"); + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, hassh, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief this function setup the ssh.hassh.server.string modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + * \retval -2 on failure that should be silent after the first + */ +static int DetectSshHasshServerStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_server_string_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) + return -1; + + /* try to enable Hassh */ + rs_ssh_enable_hassh(); + + /* Check if Hassh is disabled */ + if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH_SERVER_STRING)) { + SCLogError("hassh support is not enabled"); + } + return -2; + } + + return 0; +} + +/** + * \brief Registration function for hasshServer.string keyword. + */ +void DetectSshHasshServerStringRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].alias = KEYWORD_ALIAS; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].Setup = DetectSshHasshServerStringSetup; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].flags |= + SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetSshData, ALPROTO_SSH, SshStateBannerDone); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOCLIENT, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_ssh_hassh_server_string_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/app-layer/ssh/detect-hassh-server-string.h b/src/app-layer/ssh/detect-hassh-server-string.h new file mode 100644 index 000000000000..f79cd33d6af5 --- /dev/null +++ b/src/app-layer/ssh/detect-hassh-server-string.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Malakhatko Vadym + */ + +#ifndef __DETECT_SSH_HASSH_SERVER_STRING_H__ +#define __DETECT_SSH_HASSH_SERVER_STRING_H__ + +/* prototypes */ +void DetectSshHasshServerStringRegister(void); + +#endif /* __DETECT_SSH_HASSH_SERVER_STRING_H__ */ diff --git a/src/app-layer/ssh/detect-hassh-server.c b/src/app-layer/ssh/detect-hassh-server.c new file mode 100644 index 000000000000..91ad922e47b3 --- /dev/null +++ b/src/app-layer/ssh/detect-hassh-server.c @@ -0,0 +1,207 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Vadym Malakhatko + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" +#include "stream-tcp.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-hassh-server.h" +#include "rust.h" + +#define KEYWORD_NAME "ssh.hassh.server" +#define KEYWORD_ALIAS "ssh-hassh-server" +#define KEYWORD_DOC "ssh-keywords.html#ssh.hassh.server" +#define BUFFER_NAME "ssh.hassh.server" +#define BUFFER_DESC "Ssh Client Fingerprinting For Ssh Servers" +static int g_ssh_hassh_buffer_id = 0; + +static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + + if (buffer->inspect == NULL) { + const uint8_t *hasshServer = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_hassh(txv, &hasshServer, &b_len, flow_flags) != 1) + return NULL; + if (hasshServer == NULL || b_len == 0) { + SCLogDebug("SSH hassh not set"); + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, hasshServer, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief this function setup the ssh.hassh.server modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + * \retval -2 on failure that should be silent after the first + */ +static int DetectSshHasshServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) + return -1; + + /* try to enable Hassh */ + rs_ssh_enable_hassh(); + + /* Check if Hassh is disabled */ + if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH_SERVER)) { + SCLogError("hassh support is not enabled"); + } + return -2; + } + + return 0; +} + +static bool DetectSshHasshServerHashValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = "ssh.hassh.server should not be used together with " + "nocase, since the rule is automatically " + "lowercased anyway which makes nocase redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + } + + if (cd->content_len != 32) { + *sigerror = "Invalid length of the specified ssh.hassh.server (should " + "be 32 characters long). This rule will therefore " + "never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + for (size_t i = 0; i < cd->content_len; ++i) { + if (!isxdigit(cd->content[i])) { + *sigerror = "Invalid ssh.hassh.server string (should be string of hexadecimal " + "characters)." + "This rule will therefore never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + } + } + } + return true; +} + +static void DetectSshHasshServerHashSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) + continue; + SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + DetectContentData *cd = (DetectContentData *)sm->ctx; + + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) { + cd->content[u] = u8_tolower(cd->content[u]); + } + } + + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = + SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); + } + } +} + +/** + * \brief Registration function for hasshServer keyword. + */ +void DetectSshHasshServerRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].alias = KEYWORD_ALIAS; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].Setup = DetectSshHasshServerSetup; + sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].flags |= + SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetSshData, ALPROTO_SSH, SshStateBannerDone); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOCLIENT, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_ssh_hassh_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, DetectSshHasshServerHashSetupCallback); + DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectSshHasshServerHashValidateCallback); +} diff --git a/src/app-layer/ssh/detect-hassh-server.h b/src/app-layer/ssh/detect-hassh-server.h new file mode 100644 index 000000000000..040601749da4 --- /dev/null +++ b/src/app-layer/ssh/detect-hassh-server.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Malakhatko Vadym + */ + +#ifndef __DETECT_SSH_HASSH_SERVER_H__ +#define __DETECT_SSH_HASSH_SERVER_H__ + +/* prototypes */ +void DetectSshHasshServerRegister(void); + +#endif /* __DETECT_SSH_HASSH_SERVER_H__ */ diff --git a/src/app-layer/ssh/detect-hassh-string.c b/src/app-layer/ssh/detect-hassh-string.c new file mode 100644 index 000000000000..b4552dda1a8f --- /dev/null +++ b/src/app-layer/ssh/detect-hassh-string.c @@ -0,0 +1,138 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Vadym Malakhatko + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "stream-tcp.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-hassh-string.h" +#include "rust.h" + +#define KEYWORD_NAME "ssh.hassh.string" +#define KEYWORD_ALIAS "ssh-hassh-string" +#define KEYWORD_DOC "ssh-keywords.html#hassh.string" +#define BUFFER_NAME "ssh.hassh.string" +#define BUFFER_DESC "Ssh Client Key Exchange methods For ssh Clients " +static int g_ssh_hassh_string_buffer_id = 0; + +static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + + if (buffer->inspect == NULL) { + const uint8_t *hassh = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_hassh_string(txv, &hassh, &b_len, flow_flags) != 1) + return NULL; + if (hassh == NULL || b_len == 0) { + SCLogDebug("SSH hassh string is not set"); + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, hassh, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief this function setup the hassh.string modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + * \retval -2 on failure that should be silent after the first + */ +static int DetectSshHasshStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_string_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) + return -1; + + /* try to enable Hassh */ + rs_ssh_enable_hassh(); + + /* Check if Hassh is disabled */ + if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH_STRING)) { + SCLogError("hassh support is not enabled"); + } + return -2; + } + + return 0; +} + +/** + * \brief Registration function for hassh.string keyword. + */ +void DetectSshHasshStringRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_HASSH_STRING].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_HASSH_STRING].alias = KEYWORD_ALIAS; + sigmatch_table[DETECT_AL_SSH_HASSH_STRING].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_HASSH_STRING].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_HASSH_STRING].Setup = DetectSshHasshStringSetup; + sigmatch_table[DETECT_AL_SSH_HASSH_STRING].flags |= + SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetSshData, ALPROTO_SSH, SshStateBannerDone); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOSERVER, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_ssh_hassh_string_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/app-layer/ssh/detect-hassh-string.h b/src/app-layer/ssh/detect-hassh-string.h new file mode 100644 index 000000000000..d76533b3725e --- /dev/null +++ b/src/app-layer/ssh/detect-hassh-string.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Vadym Malakhatko + */ + +#ifndef __DETECT_SSH_HASSH_STRING_H__ +#define __DETECT_SSH_HASSH_STRING_H__ + +/* prototypes */ +void DetectSshHasshStringRegister(void); + +#endif /* __DETECT_SSH_HASSH_STRING_H__ */ diff --git a/src/app-layer/ssh/detect-hassh.c b/src/app-layer/ssh/detect-hassh.c new file mode 100644 index 000000000000..023c4fa4723c --- /dev/null +++ b/src/app-layer/ssh/detect-hassh.c @@ -0,0 +1,206 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Vadym Malakhatko + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "stream-tcp.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-hassh.h" +#include "rust.h" + +#define KEYWORD_NAME "ssh.hassh" +#define KEYWORD_ALIAS "ssh-hassh" +#define KEYWORD_DOC "ssh-keywords.html#hassh" +#define BUFFER_NAME "ssh.hassh" +#define BUFFER_DESC "Ssh Client Fingerprinting For Ssh Clients " +static int g_ssh_hassh_buffer_id = 0; + +static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + + if (buffer->inspect == NULL) { + const uint8_t *hassh = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_hassh(txv, &hassh, &b_len, flow_flags) != 1) + return NULL; + if (hassh == NULL || b_len == 0) { + SCLogDebug("SSH hassh not set"); + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, hassh, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +/** + * \brief this function setup the hassh modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + * \retval -2 on failure that should be silent after the first + */ +static int DetectSshHasshSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) + return -1; + + /* try to enable Hassh */ + rs_ssh_enable_hassh(); + + /* Check if Hassh is disabled */ + if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH)) { + SCLogError("hassh support is not enabled"); + } + return -2; + } + + return 0; +} + +static bool DetectSshHasshHashValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = "ssh.hassh should not be used together with " + "nocase, since the rule is automatically " + "lowercased anyway which makes nocase redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + } + + if (cd->content_len != 32) { + *sigerror = "Invalid length of the specified ssh.hassh (should " + "be 32 characters long). This rule will therefore " + "never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + for (size_t i = 0; i < cd->content_len; ++i) { + if (!isxdigit(cd->content[i])) { + *sigerror = + "Invalid ssh.hassh string (should be string of hexadecimal characters)." + "This rule will therefore never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + } + } + } + return true; +} + +static void DetectSshHasshHashSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) + continue; + SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + DetectContentData *cd = (DetectContentData *)sm->ctx; + + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) { + cd->content[u] = u8_tolower(cd->content[u]); + } + } + + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = + SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); + } + } +} + +/** + * \brief Registration function for hassh keyword. + */ +void DetectSshHasshRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_HASSH].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_HASSH].alias = KEYWORD_ALIAS; + sigmatch_table[DETECT_AL_SSH_HASSH].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_HASSH].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_HASSH].Setup = DetectSshHasshSetup; + sigmatch_table[DETECT_AL_SSH_HASSH].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetSshData, ALPROTO_SSH, SshStateBannerDone), + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOSERVER, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_ssh_hassh_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, DetectSshHasshHashSetupCallback); + DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectSshHasshHashValidateCallback); +} diff --git a/src/app-layer/ssh/detect-hassh.h b/src/app-layer/ssh/detect-hassh.h new file mode 100644 index 000000000000..a97dd55a41b2 --- /dev/null +++ b/src/app-layer/ssh/detect-hassh.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Malakhatko Vadym + */ + +#ifndef __DETECT_SSH_HASSH_H__ +#define __DETECT_SSH_HASSH_H__ + +/* prototypes */ +void DetectSshHasshRegister(void); + +#endif /* __DETECT_SSH_HASSH_H__ */ diff --git a/src/app-layer/ssh/detect-proto-version.c b/src/app-layer/ssh/detect-proto-version.c new file mode 100644 index 000000000000..65717a9c9455 --- /dev/null +++ b/src/app-layer/ssh/detect-proto-version.c @@ -0,0 +1,577 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + * + * Implements the ssh.protoversion keyword + * You can specify a concrete version like ssh.protoversion: 1.66 + * or search for protoversion 2 compat (1.99 is considered as 2) like + * ssh.protoversion:2_compat + * or just the beginning of the string like ssh.protoversion:"1." + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-build.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-proto-version.h" +#include "rust.h" + +#include "stream-tcp.h" + +/** + * \brief Regex for parsing the protoversion string + */ +#define PARSE_REGEX "^\\s*\"?\\s*([0-9]+([\\.\\-0-9]+)?|2_compat)\\s*\"?\\s*$" + +static DetectParseRegex parse_regex; + +static int DetectSshVersionMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectSshVersionSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectSshVersionRegisterTests(void); +#endif +static void DetectSshVersionFree(DetectEngineCtx *, void *); +static int g_ssh_banner_list_id = 0; + +/** + * \brief Registration function for keyword: ssh.protoversion + */ +void DetectSshVersionRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion"; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].desc = "match SSH protocol version"; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].url = "/rules/ssh-keywords.html#ssh-protoversion"; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerTxMatch = DetectSshVersionMatch; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; +#endif + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].flags = + SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_INFO_DEPRECATED; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].alternative = DETECT_AL_SSH_PROTOCOL; + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); +} + +/** + * \brief match the specified version on a ssh session + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectSshVersionData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectSshVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + + SCLogDebug("lets see"); + + DetectSshVersionData *ssh = (DetectSshVersionData *)m; + if (state == NULL) { + SCLogDebug("no ssh state, no match"); + SCReturnInt(0); + } + + int ret = 0; + const uint8_t *protocol = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_protocol(txv, &protocol, &b_len, flags) != 1) + SCReturnInt(0); + if (protocol == NULL || b_len == 0) + SCReturnInt(0); + + if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) { + SCLogDebug("looking for ssh protoversion 2 compat"); + if (protocol[0] == '2') { + ret = 1; + } else if (b_len >= 4) { + if (memcmp(protocol, "1.99", 4) == 0) { + ret = 1; + } + } + } else { + SCLogDebug("looking for ssh protoversion %s length %" PRIu16 "", ssh->ver, ssh->len); + if (b_len == ssh->len) { + if (memcmp(protocol, ssh->ver, ssh->len) == 0) { + ret = 1; + } + } + } + SCReturnInt(ret); +} + +/** + * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" + * + * \param de_ctx Pointer to the detection engine context + * \param idstr Pointer to the user provided id option + * + * \retval id_d pointer to DetectSshVersionData on success + * \retval NULL on failure + */ +static DetectSshVersionData *DetectSshVersionParse(DetectEngineCtx *de_ctx, const char *str) +{ + DetectSshVersionData *ssh = NULL; + int res = 0; + size_t pcre2_len; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); + if (ret < 1 || ret > 3) { + SCLogError("invalid ssh.protoversion option"); + goto error; + } + + if (ret > 1) { + const char *str_ptr; + res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); + if (res < 0) { + SCLogError("pcre2_substring_get_bynumber failed"); + goto error; + } + + /* We have a correct id option */ + ssh = SCCalloc(1, sizeof(DetectSshVersionData)); + if (unlikely(ssh == NULL)) { + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + goto error; + } + + /* If we expect a protocol version 2 or 1.99 (considered 2, we + * will compare it with both strings) */ + if (strcmp("2_compat", str_ptr) == 0) { + ssh->flags |= SSH_FLAG_PROTOVERSION_2_COMPAT; + SCLogDebug("will look for ssh protocol version 2 (2, 2.0, 1.99 that's considered as 2"); + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + return ssh; + } + + ssh->ver = (uint8_t *)SCStrdup((char *)str_ptr); + if (ssh->ver == NULL) { + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + goto error; + } + ssh->len = (uint16_t)strlen((char *)ssh->ver); + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + + SCLogDebug("will look for ssh %s", ssh->ver); + } + + pcre2_match_data_free(match); + return ssh; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (ssh != NULL) + DetectSshVersionFree(de_ctx, ssh); + return NULL; +} + +/** + * \brief this function is used to add the parsed "id" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "id" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectSshVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + DetectSshVersionData *ssh = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) + return -1; + + ssh = DetectSshVersionParse(de_ctx, str); + if (ssh == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSH_PROTOVERSION, (SigMatchCtx *)ssh, + g_ssh_banner_list_id) == NULL) { + goto error; + } + return 0; + +error: + if (ssh != NULL) + DetectSshVersionFree(de_ctx, ssh); + return -1; +} + +/** + * \brief this function will free memory associated with DetectSshVersionData + * + * \param id_d pointer to DetectSshVersionData + */ +void DetectSshVersionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectSshVersionData *sshd = (DetectSshVersionData *)ptr; + SCFree(sshd->ver); + SCFree(sshd); +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "detect-engine-alert.h" + +/** + * \test DetectSshVersionTestParse01 is a test to make sure that we parse + * a proto version correctly + */ +static int DetectSshVersionTestParse01(void) +{ + DetectSshVersionData *ssh = NULL; + ssh = DetectSshVersionParse(NULL, "1.0"); + FAIL_IF_NULL(ssh); + FAIL_IF_NOT(strncmp((char *)ssh->ver, "1.0", 3) == 0); + DetectSshVersionFree(NULL, ssh); + + PASS; +} + +/** + * \test DetectSshVersionTestParse02 is a test to make sure that we parse + * the proto version (compatible with proto version 2) correctly + */ +static int DetectSshVersionTestParse02(void) +{ + DetectSshVersionData *ssh = NULL; + ssh = DetectSshVersionParse(NULL, "2_compat"); + FAIL_IF_NOT(ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT); + DetectSshVersionFree(NULL, ssh); + + PASS; +} + +/** + * \test DetectSshVersionTestParse03 is a test to make sure that we + * don't return a ssh_data with an invalid value specified + */ +static int DetectSshVersionTestParse03(void) +{ + DetectSshVersionData *ssh = NULL; + ssh = DetectSshVersionParse(NULL, "2_com"); + FAIL_IF_NOT_NULL(ssh); + ssh = DetectSshVersionParse(NULL, ""); + FAIL_IF_NOT_NULL(ssh); + ssh = DetectSshVersionParse(NULL, ".1"); + FAIL_IF_NOT_NULL(ssh); + ssh = DetectSshVersionParse(NULL, "lalala"); + FAIL_IF_NOT_NULL(ssh); + + PASS; +} + +#include "stream-tcp-reassemble.h" +#include "stream-tcp-util.h" + +/** \test Send a get request in three chunks + more data. */ +static int DetectSshVersionTestDetect01(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-1."; + uint8_t sshbuf2[] = "10-PuTTY_2.123"; + uint8_t sshbuf3[] = "\n"; + uint8_t sshbuf4[] = "whatever..."; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(unlikely(p == NULL)); + p->flow = f; + + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit( + de_ctx, "alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:1.10; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1)); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a get request in three chunks + more data. */ +static int DetectSshVersionTestDetect02(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-1.99-Pu"; + uint8_t sshbuf2[] = "TTY_2.123"; + uint8_t sshbuf3[] = "\n"; + uint8_t sshbuf4[] = "whatever..."; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(unlikely(p == NULL)); + p->flow = f; + + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1)); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a get request in three chunks + more data. */ +static int DetectSshVersionTestDetect03(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-1."; + uint8_t sshbuf2[] = "7-PuTTY_2.123"; + uint8_t sshbuf3[] = "\n"; + uint8_t sshbuf4[] = "whatever..."; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(unlikely(p == NULL)); + p->flow = f; + + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1)); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** + * \brief this function registers unit tests for DetectSshVersion + */ +static void DetectSshVersionRegisterTests(void) +{ + UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01); + UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02); + UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03); + UtRegisterTest("DetectSshVersionTestDetect01", DetectSshVersionTestDetect01); + UtRegisterTest("DetectSshVersionTestDetect02", DetectSshVersionTestDetect02); + UtRegisterTest("DetectSshVersionTestDetect03", DetectSshVersionTestDetect03); +} +#endif /* UNITTESTS */ diff --git a/src/app-layer/ssh/detect-proto-version.h b/src/app-layer/ssh/detect-proto-version.h new file mode 100644 index 000000000000..7edf66ae3f70 --- /dev/null +++ b/src/app-layer/ssh/detect-proto-version.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + */ + +#ifndef __DETECT_SSH_VERSION_H__ +#define __DETECT_SSH_VERSION_H__ + +/** proto version 1.99 is considered proto version 2 */ +#define SSH_FLAG_PROTOVERSION_2_COMPAT 0x01 + +typedef struct DetectSshVersionData_ { + uint8_t *ver; /** ssh version to match */ + uint16_t len; /** ssh version length to match */ + uint8_t flags; +} DetectSshVersionData; + +/* prototypes */ +void DetectSshVersionRegister(void); + +#endif /* __DETECT_SSH_VERSION_H__ */ diff --git a/src/app-layer/ssh/detect-proto.c b/src/app-layer/ssh/detect-proto.c new file mode 100644 index 000000000000..d7a0bf848898 --- /dev/null +++ b/src/app-layer/ssh/detect-proto.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup sshlayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support ssh_proto sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-proto.h" +#include "rust.h" + +#define KEYWORD_NAME "ssh.proto" +#define KEYWORD_NAME_LEGACY "ssh_proto" +#define KEYWORD_DOC "ssh-keywords.html#ssh-proto" +#define BUFFER_NAME "ssh.proto" +#define BUFFER_DESC "ssh protocol version field" +static int g_buffer_id = 0; + +static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + + if (buffer->inspect == NULL) { + const uint8_t *protocol = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_protocol(txv, &protocol, &b_len, flow_flags) != 1) + return NULL; + if (protocol == NULL || b_len == 0) { + SCLogDebug("SSH protocol not set"); + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, protocol, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static int DetectSshProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) + return -1; + + return 0; +} + +void DetectSshProtocolRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_PROTOCOL].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].alias = KEYWORD_NAME_LEGACY; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].Setup = DetectSshProtocolSetup; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetSshData, ALPROTO_SSH, SshStateBannerDone), + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterGenericMpmRegister, GetSshData, ALPROTO_SSH, SshStateBannerDone), + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOSERVER, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOCLIENT, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-ssh-proto.h b/src/app-layer/ssh/detect-proto.h similarity index 100% rename from src/detect-ssh-proto.h rename to src/app-layer/ssh/detect-proto.h diff --git a/src/app-layer/ssh/detect-software-version.c b/src/app-layer/ssh/detect-software-version.c new file mode 100644 index 000000000000..5227cef1d357 --- /dev/null +++ b/src/app-layer/ssh/detect-software-version.c @@ -0,0 +1,571 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + * + * Implements the ssh.softwareversion keyword + * You can match over the software version string of ssh, and it will + * be compared from the beginning of the string so you can say for + * example ssh.softwareversion:"PuTTY" and it can match, or you can + * also specify the version, something like + * ssh.softwareversion:"PuTTY-Release-0.55" + * I find this useful to match over a known vulnerable server/client + * software version in combination to other checks, so you can know + * that the risk is higher + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-build.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-software-version.h" +#include "rust.h" + +#include "stream-tcp.h" + +/** + * \brief Regex for parsing the softwareversion string + */ +#define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\:\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$" + +static DetectParseRegex parse_regex; + +static int DetectSshSoftwareVersionMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectSshSoftwareVersionSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectSshSoftwareVersionRegisterTests(void); +#endif +static void DetectSshSoftwareVersionFree(DetectEngineCtx *de_ctx, void *); +static int g_ssh_banner_list_id = 0; + +/** + * \brief Registration function for keyword: ssh.softwareversion + */ +void DetectSshSoftwareVersionRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion"; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].desc = "match SSH software string"; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].url = + "/rules/ssh-keywords.html#ssh-softwareversion"; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerTxMatch = DetectSshSoftwareVersionMatch; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = + DetectSshSoftwareVersionRegisterTests; +#endif + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].flags = + SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_INFO_DEPRECATED; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].alternative = DETECT_AL_SSH_SOFTWARE; + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); + + DetectAppLayerInspectEngineRegister2("ssh_banner", ALPROTO_SSH, SIG_FLAG_TOSERVER, + SshStateBannerDone, DetectEngineInspectGenericList, NULL); + DetectAppLayerInspectEngineRegister2("ssh_banner", ALPROTO_SSH, SIG_FLAG_TOCLIENT, + SshStateBannerDone, DetectEngineInspectGenericList, NULL); +} + +/** + * \brief match the specified version on a ssh session + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectSshSoftwareVersionData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectSshSoftwareVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + + DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m; + if (state == NULL) { + SCLogDebug("no ssh state, no match"); + SCReturnInt(0); + } + + int ret = 0; + const uint8_t *software = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_software(txv, &software, &b_len, flags) != 1) + SCReturnInt(0); + if (software == NULL || b_len == 0) + SCReturnInt(0); + if (b_len == ssh->len) { + if (memcmp(software, ssh->software_ver, ssh->len) == 0) { + ret = 1; + } + } + + SCReturnInt(ret); +} + +/** + * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" + * + * \param de_ctx Pointer to the detection engine context + * \param idstr Pointer to the user provided id option + * + * \retval id_d pointer to DetectSshSoftwareVersionData on success + * \retval NULL on failure + */ +static DetectSshSoftwareVersionData *DetectSshSoftwareVersionParse( + DetectEngineCtx *de_ctx, const char *str) +{ + DetectSshSoftwareVersionData *ssh = NULL; + int res = 0; + size_t pcre2_len; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); + + if (ret < 1 || ret > 3) { + SCLogError("invalid ssh.softwareversion option"); + goto error; + } + + if (ret > 1) { + const char *str_ptr = NULL; + res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); + if (res < 0) { + SCLogError("pcre2_substring_get_bynumber failed"); + goto error; + } + + /* We have a correct id option */ + ssh = SCMalloc(sizeof(DetectSshSoftwareVersionData)); + if (unlikely(ssh == NULL)) { + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + goto error; + } + ssh->software_ver = (uint8_t *)SCStrdup((char *)str_ptr); + if (ssh->software_ver == NULL) { + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + goto error; + } + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + + ssh->len = (uint16_t)strlen((char *)ssh->software_ver); + + SCLogDebug("will look for ssh %s", ssh->software_ver); + } + + pcre2_match_data_free(match); + return ssh; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (ssh != NULL) + DetectSshSoftwareVersionFree(de_ctx, ssh); + return NULL; +} + +/** + * \brief this function is used to add the parsed "id" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "id" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectSshSoftwareVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + DetectSshSoftwareVersionData *ssh = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) + return -1; + + ssh = DetectSshSoftwareVersionParse(NULL, str); + if (ssh == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSH_SOFTWAREVERSION, (SigMatchCtx *)ssh, + g_ssh_banner_list_id) == NULL) { + goto error; + } + return 0; + +error: + if (ssh != NULL) + DetectSshSoftwareVersionFree(de_ctx, ssh); + return -1; +} + +/** + * \brief this function will free memory associated with DetectSshSoftwareVersionData + * + * \param id_d pointer to DetectSshSoftwareVersionData + */ +static void DetectSshSoftwareVersionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + if (ptr == NULL) + return; + + DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)ptr; + if (ssh->software_ver != NULL) + SCFree(ssh->software_ver); + SCFree(ssh); +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "detect-engine-alert.h" + +/** + * \test DetectSshSoftwareVersionTestParse01 is a test to make sure that we parse + * a software version correctly + */ +static int DetectSshSoftwareVersionTestParse01(void) +{ + DetectSshSoftwareVersionData *ssh = NULL; + ssh = DetectSshSoftwareVersionParse(NULL, "PuTTY_1.0"); + if (ssh != NULL && strncmp((char *)ssh->software_ver, "PuTTY_1.0", 9) == 0) { + DetectSshSoftwareVersionFree(NULL, ssh); + return 1; + } + + return 0; +} + +/** + * \test DetectSshSoftwareVersionTestParse02 is a test to make sure that we parse + * the software version correctly + */ +static int DetectSshSoftwareVersionTestParse02(void) +{ + DetectSshSoftwareVersionData *ssh = NULL; + ssh = DetectSshSoftwareVersionParse(NULL, "\"SecureCRT-4.0\""); + if (ssh != NULL && strncmp((char *)ssh->software_ver, "SecureCRT-4.0", 13) == 0) { + DetectSshSoftwareVersionFree(NULL, ssh); + return 1; + } + + return 0; +} + +/** + * \test DetectSshSoftwareVersionTestParse03 is a test to make sure that we + * don't return a ssh_data with an empty value specified + */ +static int DetectSshSoftwareVersionTestParse03(void) +{ + DetectSshSoftwareVersionData *ssh = NULL; + ssh = DetectSshSoftwareVersionParse(NULL, ""); + if (ssh != NULL) { + DetectSshSoftwareVersionFree(NULL, ssh); + return 0; + } + + return 1; +} + +#include "stream-tcp-reassemble.h" +#include "stream-tcp-util.h" + +/** \test Send a get request in three chunks + more data. */ +static int DetectSshSoftwareVersionTestDetect01(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-1."; + uint8_t sshbuf2[] = "10-PuTTY_2.123"; + uint8_t sshbuf3[] = "\n"; + uint8_t sshbuf4[] = "whatever..."; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(unlikely(p == NULL)); + p->flow = f; + + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1)); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a get request in three chunks + more data. */ +static int DetectSshSoftwareVersionTestDetect02(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-1.99-Pu"; + uint8_t sshbuf2[] = "TTY_2.123"; + uint8_t sshbuf3[] = "\n"; + uint8_t sshbuf4[] = "whatever..."; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(unlikely(p == NULL)); + p->flow = f; + + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1)); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a get request in three chunks + more data. */ +static int DetectSshSoftwareVersionTestDetect03(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-1."; + uint8_t sshbuf2[] = "7-PuTTY_2.123"; + uint8_t sshbuf3[] = "\n"; + uint8_t sshbuf4[] = "whatever..."; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(unlikely(p == NULL)); + p->flow = f; + + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:lalala-3.1.4; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1)); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** + * \brief this function registers unit tests for DetectSshSoftwareVersion + */ +static void DetectSshSoftwareVersionRegisterTests(void) +{ + UtRegisterTest("DetectSshSoftwareVersionTestParse01", DetectSshSoftwareVersionTestParse01); + UtRegisterTest("DetectSshSoftwareVersionTestParse02", DetectSshSoftwareVersionTestParse02); + UtRegisterTest("DetectSshSoftwareVersionTestParse03", DetectSshSoftwareVersionTestParse03); + UtRegisterTest("DetectSshSoftwareVersionTestDetect01", DetectSshSoftwareVersionTestDetect01); + UtRegisterTest("DetectSshSoftwareVersionTestDetect02", DetectSshSoftwareVersionTestDetect02); + UtRegisterTest("DetectSshSoftwareVersionTestDetect03", DetectSshSoftwareVersionTestDetect03); +} +#endif /* UNITTESTS */ diff --git a/src/app-layer/ssh/detect-software-version.h b/src/app-layer/ssh/detect-software-version.h new file mode 100644 index 000000000000..d740c78b146f --- /dev/null +++ b/src/app-layer/ssh/detect-software-version.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + */ + +#ifndef __DETECT_SSH_SOFTWARE_VERSION_H__ +#define __DETECT_SSH_SOFTWARE_VERSION_H__ + +typedef struct DetectSshSoftwareVersionData_ { + uint8_t *software_ver; /** ssh version to match */ + uint16_t len; /** ssh version length to match */ +} DetectSshSoftwareVersionData; + +/* prototypes */ +void DetectSshSoftwareVersionRegister(void); + +#endif /* __DETECT_SSH_SOFTWARE_VERSION_H__ */ diff --git a/src/app-layer/ssh/detect-software.c b/src/app-layer/ssh/detect-software.c new file mode 100644 index 000000000000..646ed15d2dfc --- /dev/null +++ b/src/app-layer/ssh/detect-software.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup sshlayer + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements support ssh_software sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/ssh/detect-software.h" +#include "rust.h" + +#define KEYWORD_NAME "ssh.software" +#define KEYWORD_NAME_LEGACY "ssh_software" +#define KEYWORD_DOC "ssh-keywords.html#ssh-software" +#define BUFFER_NAME "ssh_software" +#define BUFFER_DESC "ssh software field" +static int g_buffer_id = 0; + +static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + + if (buffer->inspect == NULL) { + const uint8_t *software = NULL; + uint32_t b_len = 0; + + if (rs_ssh_tx_get_software(txv, &software, &b_len, flow_flags) != 1) + return NULL; + if (software == NULL || b_len == 0) { + SCLogDebug("SSH software version not set"); + return NULL; + } + + InspectionBufferSetup(det_ctx, list_id, buffer, software, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static int DetectSshSoftwareSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) + return -1; + + return 0; +} + +void DetectSshSoftwareRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_SOFTWARE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].alias = KEYWORD_NAME_LEGACY; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].url = "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].Setup = DetectSshSoftwareSetup; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetSshData, ALPROTO_SSH, SshStateBannerDone), + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterGenericMpmRegister, GetSshData, ALPROTO_SSH, SshStateBannerDone), + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOSERVER, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, SIG_FLAG_TOCLIENT, + SshStateBannerDone, DetectEngineInspectBufferGeneric, GetSshData); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-ssh-software.h b/src/app-layer/ssh/detect-software.h similarity index 100% rename from src/detect-ssh-software.h rename to src/app-layer/ssh/detect-software.h diff --git a/src/app-layer/ssh/logger.c b/src/app-layer/ssh/logger.c new file mode 100644 index 000000000000..f9f7ca605f4c --- /dev/null +++ b/src/app-layer/ssh/logger.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2014-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements SSH JSON logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" +#include "app-layer-parser.h" +#include "output/output.h" +#include "app-layer/ssh/parser.h" +#include "app-layer.h" +#include "util/privs.h" +#include "util/buffer.h" + +#include "util/logopenfile.h" + +#include "output/eve/output-json.h" +#include "app-layer/ssh/logger.h" +#include "rust.h" + +#define MODULE_NAME "LogSshLog" + +static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *txptr, uint64_t tx_id) +{ + OutputJsonThreadCtx *thread = thread_data; + + if (unlikely(state == NULL)) { + return 0; + } + + JsonBuilder *js = CreateEveHeaderWithTxId(p, LOG_DIR_FLOW, "ssh", NULL, tx_id, thread->ctx); + if (unlikely(js == NULL)) + return 0; + + if (!rs_ssh_log_json(txptr, js)) { + goto end; + } + OutputJsonBuilderBuffer(js, thread); + +end: + jb_free(js); + return 0; +} + +static OutputInitResult OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonSshLogRegister(void) +{ + /* register as child of eve-log */ + OutputRegisterTxSubModuleWithCondition(LOGGER_JSON_TX, "eve-log", "JsonSshLog", "eve-log.ssh", + OutputSshLogInitSub, ALPROTO_SSH, JsonSshLogger, SSHTxLogCondition, JsonLogThreadInit, + JsonLogThreadDeinit, NULL); +} diff --git a/src/output-json-ssh.h b/src/app-layer/ssh/logger.h similarity index 100% rename from src/output-json-ssh.h rename to src/app-layer/ssh/logger.h diff --git a/src/app-layer/ssh/lua-hassh.c b/src/app-layer/ssh/lua-hassh.c new file mode 100644 index 000000000000..39b03144045d --- /dev/null +++ b/src/app-layer/ssh/lua-hassh.c @@ -0,0 +1,218 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Vadym Malakhatko + * + */ + +#include "suricata-common.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssl/parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/ssh/lua-hassh.h" + +static int GetHasshServerString(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + const uint8_t *hassh_server_string = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_hassh_string(tx, &hassh_server_string, &b_len, STREAM_TOCLIENT) != 1) + return LuaCallbackError(luastate, "error: no server hassh string"); + if (hassh_server_string == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no server hassh string"); + } + + return LuaPushStringBuffer(luastate, hassh_server_string, b_len); +} + +static int HasshServerGetString(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol is not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no ssh flow"); + + r = GetHasshServerString(luastate, f); + + return r; +} + +static int GetHasshServer(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no ssh app layer state"); + + const uint8_t *hassh_server = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_hassh(tx, &hassh_server, &b_len, STREAM_TOCLIENT) != 1) + return LuaCallbackError(luastate, "error: no server hassh"); + if (hassh_server == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no server hassh"); + } + + return LuaPushStringBuffer(luastate, hassh_server, b_len); +} + +static int HasshServerGet(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol is not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no ssh flow"); + + r = GetHasshServer(luastate, f); + + return r; +} + +static int GetHasshString(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + const uint8_t *hassh_string = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_hassh_string(tx, &hassh_string, &b_len, STREAM_TOSERVER) != 1) + return LuaCallbackError(luastate, "error: no client hassh_string"); + if (hassh_string == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no client hassh_string"); + } + + return LuaPushStringBuffer(luastate, hassh_string, b_len); +} + +static int HasshGetString(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol is not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no ssh flow"); + + r = GetHasshString(luastate, f); + + return r; +} + +static int GetHassh(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + const uint8_t *hassh = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_hassh(tx, &hassh, &b_len, STREAM_TOSERVER) != 1) + return LuaCallbackError(luastate, "error: no client hassh"); + if (hassh == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no client hassh"); + } + + return LuaPushStringBuffer(luastate, hassh, b_len); +} + +static int HasshGet(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol is not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no sshflow"); + + r = GetHassh(luastate, f); + + return r; +} + +/** *\brief Register Hassh Lua extensions */ +int LuaRegisterHasshFunctions(lua_State *luastate) +{ + + lua_pushcfunction(luastate, HasshGet); + lua_setglobal(luastate, "HasshGet"); + + lua_pushcfunction(luastate, HasshGetString); + lua_setglobal(luastate, "HasshGetString"); + + lua_pushcfunction(luastate, HasshServerGet); + lua_setglobal(luastate, "HasshServerGet"); + + lua_pushcfunction(luastate, HasshServerGetString); + lua_setglobal(luastate, "HasshServerGetString"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-hassh.h b/src/app-layer/ssh/lua-hassh.h similarity index 100% rename from src/util-lua-hassh.h rename to src/app-layer/ssh/lua-hassh.h diff --git a/src/app-layer/ssh/lua.c b/src/app-layer/ssh/lua.c new file mode 100644 index 000000000000..543088c6d34b --- /dev/null +++ b/src/app-layer/ssh/lua.c @@ -0,0 +1,218 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "rust.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/ssh/lua.h" + +static int GetServerProtoVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + const uint8_t *protocol = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_protocol(tx, &protocol, &b_len, STREAM_TOCLIENT) != 1) + return LuaCallbackError(luastate, "error: no server proto version"); + if (protocol == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no server proto version"); + } + + return LuaPushStringBuffer(luastate, protocol, b_len); +} + +static int SshGetServerProtoVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetServerProtoVersion(luastate, f); + + return r; +} + +static int GetServerSoftwareVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + const uint8_t *software = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_software(tx, &software, &b_len, STREAM_TOCLIENT) != 1) + return LuaCallbackError(luastate, "error: no server software version"); + if (software == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no server software version"); + } + + return LuaPushStringBuffer(luastate, software, b_len); +} + +static int SshGetServerSoftwareVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetServerSoftwareVersion(luastate, f); + + return r; +} + +static int GetClientProtoVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + const uint8_t *protocol = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_protocol(tx, &protocol, &b_len, STREAM_TOSERVER) != 1) + return LuaCallbackError(luastate, "error: no client proto version"); + if (protocol == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no client proto version"); + } + + return LuaPushStringBuffer(luastate, protocol, b_len); +} + +static int SshGetClientProtoVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetClientProtoVersion(luastate, f); + + return r; +} + +static int GetClientSoftwareVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + const uint8_t *software = NULL; + uint32_t b_len = 0; + + void *tx = rs_ssh_state_get_tx(state, 0); + if (rs_ssh_tx_get_software(tx, &software, &b_len, STREAM_TOSERVER) != 1) + return LuaCallbackError(luastate, "error: no client software version"); + if (software == NULL || b_len == 0) { + return LuaCallbackError(luastate, "error: no client software version"); + } + + return LuaPushStringBuffer(luastate, software, b_len); +} + +static int SshGetClientSoftwareVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetClientSoftwareVersion(luastate, f); + + return r; +} + +/** \brief register ssh lua extensions in a luastate */ +int LuaRegisterSshFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, SshGetServerProtoVersion); + lua_setglobal(luastate, "SshGetServerProtoVersion"); + + lua_pushcfunction(luastate, SshGetServerSoftwareVersion); + lua_setglobal(luastate, "SshGetServerSoftwareVersion"); + + lua_pushcfunction(luastate, SshGetClientProtoVersion); + lua_setglobal(luastate, "SshGetClientProtoVersion"); + + lua_pushcfunction(luastate, SshGetClientSoftwareVersion); + lua_setglobal(luastate, "SshGetClientSoftwareVersion"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-ssh.h b/src/app-layer/ssh/lua.h similarity index 100% rename from src/util-lua-ssh.h rename to src/app-layer/ssh/lua.h diff --git a/src/app-layer/ssh/parser.c b/src/app-layer/ssh/parser.c new file mode 100644 index 000000000000..23b82400e93c --- /dev/null +++ b/src/app-layer/ssh/parser.c @@ -0,0 +1,1625 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + * \author Victor Julien + * + * App-layer parser for SSH protocol + * + */ + +#include "suricata-common.h" +#include "decode.h" +#include "threads.h" + +#include "util/print.h" +#include "util/pool.h" + +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" +#include "stream-tcp.h" +#include "stream.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer/ssh/parser.h" +#include "rust.h" + +#include "conf.h" + +#include "util/spm.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "flow-private.h" + +#include "util/byte.h" +#include "util/memcmp.h" + +/* HASSH fingerprints are disabled by default */ +#define SSH_CONFIG_DEFAULT_HASSH false + +static int SSHRegisterPatternsForProtocolDetection(void) +{ + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI( + IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + return 0; +} + +bool SSHTxLogCondition(ThreadVars *tv, const Packet *p, void *state, void *tx, uint64_t tx_id) +{ + return rs_ssh_tx_get_log_condition(tx); +} + +/** \brief Function to register the SSH protocol parsers and other functions + */ +void RegisterSSHParsers(void) +{ + const char *proto_name = "ssh"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_SSH, proto_name); + if (SSHRegisterPatternsForProtocolDetection() < 0) + return; + + /* Check if we should generate Hassh fingerprints */ + int enable_hassh = SSH_CONFIG_DEFAULT_HASSH; + const char *strval = NULL; + if (ConfGet("app-layer.protocols.ssh.hassh", &strval) != 1) { + enable_hassh = SSH_CONFIG_DEFAULT_HASSH; + } else if (strcmp(strval, "auto") == 0) { + enable_hassh = SSH_CONFIG_DEFAULT_HASSH; + } else if (ConfValIsFalse(strval)) { + enable_hassh = SSH_CONFIG_DEFAULT_HASSH; + } else if (ConfValIsTrue(strval)) { + enable_hassh = true; + } + + if (RunmodeIsUnittests() || enable_hassh) { + rs_ssh_enable_hassh(); + } + } + + SCLogDebug("Registering Rust SSH parser."); + rs_ssh_register_parser(); + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SSH, SSHParserRegisterTests); +#endif +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "flow-util.h" +#include "stream-tcp-util.h" +#include "util/unittest-helper.h" + +static int SSHParserTestUtilCheck( + const char *protoexp, const char *softexp, void *tx, uint8_t flags) +{ + const uint8_t *protocol = NULL; + uint32_t p_len = 0; + const uint8_t *software = NULL; + uint32_t s_len = 0; + + if (rs_ssh_tx_get_protocol(tx, &protocol, &p_len, flags) != 1) { + printf("Version string not parsed correctly return: "); + return 1; + } + if (protocol == NULL) { + printf("Version string not parsed correctly NULL: "); + return 1; + } + + if (p_len != strlen(protoexp)) { + printf("Version string not parsed correctly length: "); + return 1; + } + if (memcmp(protocol, protoexp, strlen(protoexp)) != 0) { + printf("Version string not parsed correctly: "); + return 1; + } + + if (softexp != NULL) { + if (rs_ssh_tx_get_software(tx, &software, &s_len, flags) != 1) + return 1; + if (software == NULL) + return 1; + if (s_len != strlen(softexp)) { + printf("Software string not parsed correctly length: "); + return 1; + } + if (memcmp(software, softexp, strlen(softexp)) != 0) { + printf("Software string not parsed correctly: "); + return 1; + } + } + return 0; +} + +/** \test Send a version string in one chunk (client version str). */ +static int SSHParserTest01(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + if (rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone) { + printf("Client version string not parsed: "); + goto end; + } + + if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a version string in one chunk but multiple lines and comments. + * (client version str) + */ +static int SSHParserTest02(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + + if (rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone) { + printf("Client version string not parsed: "); + goto end; + } + if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a invalid version string in one chunk but multiple lines and comments. + * (client version str) + */ +static int SSHParserTest03(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0 some comments...\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); + if (r == 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + + if (rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) == SshStateBannerDone) { + printf("Client version string parsed? It's not a valid string: "); + goto end; + } + const uint8_t *dummy = NULL; + uint32_t dummy_len = 0; + if (rs_ssh_tx_get_protocol(tx, &dummy, &dummy_len, STREAM_TOSERVER) != 0) + goto end; + if (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOSERVER) != 0) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a version string in one chunk (server version str). */ +static int SSHParserTest04(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + + if (rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone) { + printf("Client version string not parsed: "); + goto end; + } + if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)) + goto end; + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a version string in one chunk (server version str) + */ +static int SSHParserTest05(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + + if (rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone) { + printf("Client version string not parsed: "); + goto end; + } + if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a invalid version string in one chunk (server version str) + */ +static int SSHParserTest06(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0 some comments...\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); + if (r == 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r); + goto end; + } + /* Ok, it returned an error. Let's make sure we didn't parse the string at all */ + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + + if (rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) == SshStateBannerDone) { + printf("Client version string parsed? It's not a valid string: "); + goto end; + } + const uint8_t *dummy = NULL; + uint32_t dummy_len = 0; + if (rs_ssh_tx_get_protocol(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0) + goto end; + if (rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +#define MAX_SSH_TEST_SIZE 512 + +static int SSHParserTest07(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + char sshbufs[2][MAX_SSH_TEST_SIZE] = { "SSH-2.", "0-MySSHClient-0.5.1\r\n" }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 2; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, + (uint8_t *)sshbufs[i], strlen(sshbufs[i])) == -1); + seq += strlen(sshbufs[i]); + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a version banner in three chunks. */ +static int SSHParserTest08(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + char sshbufs[3][MAX_SSH_TEST_SIZE] = { "SSH-", "2.", "0-MySSHClient-0.5.1\r\n" }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 3; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, seq, + (uint8_t *)sshbufs[i], strlen(sshbufs[i])) == -1); + seq += strlen(sshbufs[i]); + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_alstate_progress(tx, STREAM_TOSERVER) != SshStateBannerDone); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +static int SSHParserTest09(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + char sshbufs[2][MAX_SSH_TEST_SIZE] = { "SSH-2.", "0-MySSHClient-0.5.1\r\n" }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 2; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, + (uint8_t *)sshbufs[i], strlen(sshbufs[i])) == -1); + seq += strlen(sshbufs[i]); + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a version banner in three chunks. */ +static int SSHParserTest10(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + char sshbufs[3][MAX_SSH_TEST_SIZE] = { "SSH-", "2.", "0-MySSHClient-0.5.1\r\n" }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 3; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, + (uint8_t *)sshbufs[i], strlen(sshbufs[i])) == -1); + seq += strlen(sshbufs[i]); + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_alstate_progress(tx, STREAM_TOCLIENT) != SshStateBannerDone); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a banner and record in three chunks. */ +static int SSHParserTest11(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; + uint32_t sshlen1 = sizeof(sshbuf1) - 1; + uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; + uint32_t sshlen2 = sizeof(sshbuf2); + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + if (rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished) { + printf("Didn't detect the msg code of new keys (ciphered data starts): "); + goto end; + } + if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a banner and 2 records record in four chunks. */ +static int SSHParserTest12(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; + uint32_t sshlen1 = sizeof(sshbuf1) - 1; + uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00 }; + uint32_t sshlen2 = sizeof(sshbuf2); + uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; + uint32_t sshlen3 = sizeof(sshbuf3); + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + if (rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished) { + printf("Didn't detect the msg code of new keys (ciphered data starts): "); + goto end; + } + if (SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a banner and 2 records record in four chunks. */ +static int SSHParserTest13(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; + uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 17 }; + uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 21 }; + + uint8_t *sshbufs[3] = { sshbuf1, sshbuf2, sshbuf3 }; + uint32_t sshlens[3] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3) }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 3; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a banner and 2 records record in four chunks. */ +static int SSHParserTest14(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; + uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00 }; + uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00 }; + /* first byte of this record in sshbuf4 */ + uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 21 }; + + uint8_t *sshbufs[5] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5 }; + uint32_t sshlens[5] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), + sizeof(sshbuf5) }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 5; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a banner and 2 records record in four chunks. */ +static int SSHParserTest15(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n"; + uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00 }; + uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00 }; + uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 20, 0x00, 0x00, 0x00, 0x02, 0x01, 21 }; + + uint8_t *sshbufs[5] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4, sshbuf5 }; + uint32_t sshlens[5] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2), sizeof(sshbuf3), sizeof(sshbuf4), + sizeof(sshbuf5) }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 5; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.client, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOSERVER)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send toserver a banner and record in three chunks. */ +static int SSHParserTest16(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-"; + uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; + uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; + + uint8_t *sshbufs[3] = { sshbuf1, sshbuf2, sshbuf3 }; + uint32_t sshlens[3] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 3; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send toserver a banner and 2 records record in four chunks. */ +static int SSHParserTest17(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-"; + uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; + uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00 }; + uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3), + sizeof(sshbuf4) }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "MySSHClient-0.5.1", tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test 2 directional test */ +static int SSHParserTest18(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t server1[] = "SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu3\r\n"; + uint8_t sshbuf1[] = "SSH-"; + uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n"; + uint8_t server2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; + uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + uint8_t *sshbufs[5] = { server1, sshbuf1, sshbuf2, server2, sshbuf3 }; + uint32_t sshlens[5] = { sizeof(server1) - 1, sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, + sizeof(server2) - 1, sizeof(sshbuf3) }; + bool sshdirs[5] = { true, false, false, true, false }; + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seqcli = 2; + uint32_t seqsrv = 2; + for (int i = 0; i < 5; i++) { + if (sshdirs[i]) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seqsrv, sshbufs[i], sshlens[i]) == -1); + seqsrv += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer( + &tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); + } else { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.client, seqcli, sshbufs[i], sshlens[i]) == -1); + seqcli += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer( + &tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0); + } + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished); + + FAIL_IF(!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_NO_INSPECTION))); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Really long banner handling: bannel exactly 255 */ +static int SSHParserTest19(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-"; + uint8_t sshbuf2[] = "2.0-"; + uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 60 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 112 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 164 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 216 + "abcdefghijklmnopqrstuvwxyz" // 242 + "abcdefghijkl\r"; // 255 + uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 }; + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished); + + sshbuf3[sizeof(sshbuf3) - 2] = 0; + FAIL_IF(SSHParserTestUtilCheck("2.0", (char *)sshbuf3, tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Really long banner handling: banner exactly 255, + * followed by malformed record */ +static int SSHParserTest20(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-"; + uint8_t sshbuf2[] = "2.0-"; + uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 60 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 112 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 164 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 216 + "abcdefghijklmnopqrstuvwxyz" // 242 + "abcdefghijklm\r"; // 256 + // clang-format off + uint8_t sshbuf4[] = {'a','b','c','d','e','f', '\r', + 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00}; + // clang-format on + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Fragmented banner handling: chunk has final part of bannel plus + * a record. */ +static int SSHParserTest21(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-"; + uint8_t sshbuf2[] = "2.0-"; + uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 60 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 112 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 164 + "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" // 216 + "abcdefghijklmnopqrstuvwxy"; // 241 + // clang-format off + uint8_t sshbuf4[] = {'l','i','b','s','s','h', '\r', + 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00}; + // clang-format on + + uint8_t *sshbufs[4] = { sshbuf1, sshbuf2, sshbuf3, sshbuf4 }; + uint32_t sshlens[4] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, + sizeof(sshbuf4) }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 4; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Fragmented banner handling: chunk has final part of bannel plus + * a record. */ +static int SSHParserTest22(void) +{ + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow *f = NULL; + Packet *p = NULL; + + uint8_t sshbuf1[] = "SSH-"; + uint8_t sshbuf2[] = "2.0-"; + // clang-format off + uint8_t sshbuf3[] = { + 'l', 'i', 'b', 's', 's', 'h', '\r', //7 + + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //50 + + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //100 + + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //150 + + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //200 + + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //250 + + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00, 0x00, //300 + }; + // clang-format on + + uint8_t *sshbufs[3] = { sshbuf1, sshbuf2, sshbuf3 }; + uint32_t sshlens[3] = { sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1 }; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.server, 1); + StreamTcpUTSetupStream(&ssn.client, 1); + + f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); + FAIL_IF_NULL(f); + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_SSH; + + p = PacketGetFromAlloc(); + FAIL_IF(unlikely(p == NULL)); + p->proto = IPPROTO_TCP; + p->flow = f; + + uint32_t seq = 2; + for (int i = 0; i < 3; i++) { + FAIL_IF(StreamTcpUTAddSegmentWithPayload( + &tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); + seq += sshlens[i]; + FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < + 0); + } + + void *ssh_state = f->alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOCLIENT) != SshStateFinished); + + FAIL_IF(SSHParserTestUtilCheck("2.0", "libssh", tx, STREAM_TOCLIENT)); + + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + UTHFreeFlow(f); + PASS; +} + +/** \test Send a version string in one chunk (client version str). */ +static int SSHParserTest23(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0\r-MySSHClient-0.5.1\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); + if (r == 0) { + printf("toclient chunk 1 returned 0 expected non null: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a version string in one chunk (client version str). */ +static int SSHParserTest24(void) +{ + int result = 0; + Flow f; + uint8_t sshbuf[] = "SSH-2.0-\rMySSHClient-0.5.1\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + goto end; + } + + void *ssh_state = f.alstate; + if (ssh_state == NULL) { + printf("no ssh state: "); + goto end; + } + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + if (rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) != SshStateBannerDone) { + printf("Didn't detect the msg code of new keys (ciphered data starts): "); + goto end; + } + if (SSHParserTestUtilCheck("2.0", NULL, tx, STREAM_TOSERVER)) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send a malformed banner */ +static int SSHParserTest25(void) +{ + Flow f; + uint8_t sshbuf[] = "\n"; + uint32_t sshlen = sizeof(sshbuf) - 1; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.alproto = ALPROTO_SSH; + + StreamTcpInitConfig(true); + + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); + FAIL_IF(r != -1); + + void *ssh_state = f.alstate; + FAIL_IF_NULL(ssh_state); + void *tx = rs_ssh_state_get_tx(ssh_state, 0); + FAIL_IF(rs_ssh_tx_get_flags(tx, STREAM_TOSERVER) == SshStateBannerDone); + const uint8_t *dummy = NULL; + uint32_t dummy_len = 0; + FAIL_IF(rs_ssh_tx_get_software(tx, &dummy, &dummy_len, STREAM_TOCLIENT) != 0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + PASS; +} + +#endif /* UNITTESTS */ + +void SSHParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01); + UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02); + UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03); + UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04); + UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05); + UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06); + UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07); + UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08); + UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09); + UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10); + UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11); + UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12); + UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13); + UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14); + UtRegisterTest("SSHParserTest15", SSHParserTest15); + UtRegisterTest("SSHParserTest16", SSHParserTest16); + UtRegisterTest("SSHParserTest17", SSHParserTest17); + UtRegisterTest("SSHParserTest18", SSHParserTest18); + UtRegisterTest("SSHParserTest19", SSHParserTest19); + UtRegisterTest("SSHParserTest20", SSHParserTest20); + UtRegisterTest("SSHParserTest21", SSHParserTest21); + UtRegisterTest("SSHParserTest22", SSHParserTest22); + UtRegisterTest("SSHParserTest23", SSHParserTest23); + UtRegisterTest("SSHParserTest24", SSHParserTest24); + UtRegisterTest("SSHParserTest25", SSHParserTest25); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer/ssh/parser.h b/src/app-layer/ssh/parser.h new file mode 100644 index 000000000000..66aee3b5f90e --- /dev/null +++ b/src/app-layer/ssh/parser.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + * \author Victor Julien + */ + +#ifndef __APP_LAYER_SSH_H__ +#define __APP_LAYER_SSH_H__ + +void RegisterSSHParsers(void); +void SSHParserRegisterTests(void); + +bool SSHTxLogCondition(ThreadVars *, const Packet *, void *state, void *tx, uint64_t tx_id); + +#endif /* __APP_LAYER_SSH_H__ */ diff --git a/src/app-layer/ssl/detect-state.c b/src/app-layer/ssl/detect-state.c new file mode 100644 index 000000000000..2e838fcc4e39 --- /dev/null +++ b/src/app-layer/ssl/detect-state.c @@ -0,0 +1,338 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Implements support for ssl_state keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ssl/detect-state.h" + +#include "stream-tcp.h" +#include "app-layer/ssl/parser.h" + +#define PARSE_REGEX1 "^(!?)([_a-zA-Z0-9]+)(.*)$" +static DetectParseRegex parse_regex1; + +#define PARSE_REGEX2 "^(?:\\s*[|,]\\s*(!?)([_a-zA-Z0-9]+))(.*)$" +static DetectParseRegex parse_regex2; + +static int DetectSslStateMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectSslStateSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectSslStateRegisterTests(void); +#endif +static void DetectSslStateFree(DetectEngineCtx *, void *); + +static int g_tls_generic_list_id = 0; + +/** + * \brief Registers the keyword handlers for the "ssl_state" keyword. + */ +void DetectSslStateRegister(void) +{ + sigmatch_table[DETECT_AL_SSL_STATE].name = "ssl_state"; + sigmatch_table[DETECT_AL_SSL_STATE].desc = "match the state of the SSL connection"; + sigmatch_table[DETECT_AL_SSL_STATE].url = "/rules/tls-keywords.html#ssl-state"; + sigmatch_table[DETECT_AL_SSL_STATE].AppLayerTxMatch = DetectSslStateMatch; + sigmatch_table[DETECT_AL_SSL_STATE].Setup = DetectSslStateSetup; + sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests; +#endif + DetectSetupParseRegexes(PARSE_REGEX1, &parse_regex1); + DetectSetupParseRegexes(PARSE_REGEX2, &parse_regex2); + + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); + + DetectBufferTypeSetDescriptionByName("tls_generic", "generic ssl/tls inspection"); + + DetectAppLayerInspectEngineRegister2( + "tls_generic", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + DetectAppLayerInspectEngineRegister2( + "tls_generic", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); +} + +/** + * \brief App layer match function ssl_state keyword. + * + * \param tv Pointer to threadvars. + * \param det_ctx Pointer to the thread's detection context. + * \param f Pointer to the flow. + * \param flags Flags. + * \param state App layer state. + * \param s Sig we are currently inspecting. + * \param m SigMatch we are currently inspecting. + * + * \retval 1 Match. + * \retval 0 No match. + */ +static int DetectSslStateMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *alstate, void *txv, const Signature *s, const SigMatchCtx *m) +{ + const DetectSslStateData *ssd = (const DetectSslStateData *)m; + SSLState *ssl_state = (SSLState *)alstate; + if (ssl_state == NULL) { + SCLogDebug("no app state, no match"); + return 0; + } + + uint32_t ssl_flags = ssl_state->current_flags; + + if ((ssd->flags & ssl_flags) ^ ssd->mask) { + return 1; + } + + return 0; +} + +/** + * \brief Parse the arg supplied with ssl_state and return it in a + * DetectSslStateData instance. + * + * \param arg Pointer to the string to be parsed. + * + * \retval ssd Pointer to DetectSslStateData on success. + * \retval NULL On failure. + */ +static DetectSslStateData *DetectSslStateParse(const char *arg) +{ + size_t pcre2len; + char str1[64]; + char str2[64]; + int negate = 0; + uint32_t flags = 0, mask = 0; + DetectSslStateData *ssd = NULL; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex1, &match, arg, 0, 0); + if (ret < 1) { + SCLogError("Invalid arg \"%s\" supplied to " + "ssl_state keyword.", + arg); + goto error; + } + + pcre2len = sizeof(str1); + int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)str1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + negate = !strcmp("!", str1); + + pcre2len = sizeof(str1); + res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)str1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + + if (strcmp("client_hello", str1) == 0) { + flags |= DETECT_SSL_STATE_CLIENT_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_HELLO; + } else if (strcmp("server_hello", str1) == 0) { + flags |= DETECT_SSL_STATE_SERVER_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_HELLO; + } else if (strcmp("client_keyx", str1) == 0) { + flags |= DETECT_SSL_STATE_CLIENT_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_KEYX; + } else if (strcmp("server_keyx", str1) == 0) { + flags |= DETECT_SSL_STATE_SERVER_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_KEYX; + } else if (strcmp("unknown", str1) == 0) { + flags |= DETECT_SSL_STATE_UNKNOWN; + if (negate) + mask |= DETECT_SSL_STATE_UNKNOWN; + } else { + SCLogError("Found invalid option \"%s\" " + "in ssl_state keyword.", + str1); + goto error; + } + + pcre2len = sizeof(str1); + res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)str1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + while (res >= 0 && strlen(str1) > 0) { + pcre2_match_data *match2 = NULL; + ret = DetectParsePcreExec(&parse_regex2, &match2, str1, 0, 0); + if (ret < 1) { + SCLogError("Invalid arg \"%s\" supplied to " + "ssl_state keyword.", + arg); + if (match2) { + pcre2_match_data_free(match2); + } + goto error; + } + + pcre2len = sizeof(str2); + res = pcre2_substring_copy_bynumber(match2, 1, (PCRE2_UCHAR8 *)str2, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match2); + goto error; + } + negate = !strcmp("!", str2); + + pcre2len = sizeof(str2); + res = pcre2_substring_copy_bynumber(match2, 2, (PCRE2_UCHAR8 *)str2, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match2); + goto error; + } + if (strcmp("client_hello", str2) == 0) { + flags |= DETECT_SSL_STATE_CLIENT_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_HELLO; + } else if (strcmp("server_hello", str2) == 0) { + flags |= DETECT_SSL_STATE_SERVER_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_HELLO; + } else if (strcmp("client_keyx", str2) == 0) { + flags |= DETECT_SSL_STATE_CLIENT_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_KEYX; + } else if (strcmp("server_keyx", str2) == 0) { + flags |= DETECT_SSL_STATE_SERVER_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_KEYX; + } else if (strcmp("unknown", str2) == 0) { + flags |= DETECT_SSL_STATE_UNKNOWN; + if (negate) + mask |= DETECT_SSL_STATE_UNKNOWN; + } else { + SCLogError("Found invalid option \"%s\" " + "in ssl_state keyword.", + str2); + pcre2_match_data_free(match2); + goto error; + } + + pcre2len = sizeof(str2); + res = pcre2_substring_copy_bynumber(match2, 3, (PCRE2_UCHAR8 *)str2, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match2); + goto error; + } + + memcpy(str1, str2, sizeof(str1)); + pcre2_match_data_free(match2); + } + + if ((ssd = SCMalloc(sizeof(DetectSslStateData))) == NULL) { + goto error; + } + ssd->flags = flags; + ssd->mask = mask; + + pcre2_match_data_free(match); + return ssd; + +error: + if (match) { + pcre2_match_data_free(match); + } + return NULL; +} + +/** + * \internal + * \brief Setup function for ssl_state keyword. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature + * \param arg String holding the arg. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) +{ + DetectSslStateData *ssd = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + ssd = DetectSslStateParse(arg); + if (ssd == NULL) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSL_STATE, (SigMatchCtx *)ssd, + g_tls_generic_list_id) == NULL) { + goto error; + } + return 0; + +error: + if (ssd != NULL) + DetectSslStateFree(de_ctx, ssd); + return -1; +} + +/** + * \brief Free memory associated with DetectSslStateData. + * + * \param ptr pointer to the data to be freed. + */ +static void DetectSslStateFree(DetectEngineCtx *de_ctx, void *ptr) +{ + if (ptr != NULL) + SCFree(ptr); + + return; +} + +#ifdef UNITTESTS +#include "tests/detect-ssl-state.c" +#endif diff --git a/src/app-layer/ssl/detect-state.h b/src/app-layer/ssl/detect-state.h new file mode 100644 index 000000000000..925f27c2f752 --- /dev/null +++ b/src/app-layer/ssl/detect-state.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef DETECT_SSL_STATE_H +#define DETECT_SSL_STATE_H + +/* we pick these flags from the parser */ +#define DETECT_SSL_STATE_CLIENT_HELLO SSL_AL_FLAG_STATE_CLIENT_HELLO +#define DETECT_SSL_STATE_SERVER_HELLO SSL_AL_FLAG_STATE_SERVER_HELLO +#define DETECT_SSL_STATE_CLIENT_KEYX SSL_AL_FLAG_STATE_CLIENT_KEYX +#define DETECT_SSL_STATE_SERVER_KEYX SSL_AL_FLAG_STATE_SERVER_KEYX +#define DETECT_SSL_STATE_UNKNOWN SSL_AL_FLAG_STATE_UNKNOWN + +typedef struct DetectSslStateData_ { + uint32_t flags; + uint32_t mask; +} DetectSslStateData; + +void DetectSslStateRegister(void); + +#endif /* DETECT_SSL_STATE_H */ diff --git a/src/app-layer/ssl/detect-version.c b/src/app-layer/ssl/detect-version.c new file mode 100644 index 000000000000..5c0f47d35d34 --- /dev/null +++ b/src/app-layer/ssl/detect-version.c @@ -0,0 +1,323 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file detect-ssl-version.c + * + * \author Gurvinder Singh + * + * Implements the ssl_version keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ssl/detect-version.h" + +#include "stream-tcp.h" +#include "app-layer/ssl/parser.h" + +static int DetectSslVersionMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectSslVersionRegisterTests(void); +#endif +static void DetectSslVersionFree(DetectEngineCtx *, void *); +static int g_tls_generic_list_id = 0; + +/** + * \brief Registration function for keyword: ssl_version + */ +void DetectSslVersionRegister(void) +{ + sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version"; + sigmatch_table[DETECT_AL_SSL_VERSION].desc = "match version of SSL/TLS record"; + sigmatch_table[DETECT_AL_SSL_VERSION].url = "/rules/tls-keywords.html#ssl-version"; + sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch; + sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup; + sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; +#endif + + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); +} + +/** + * \brief match the specified version on a ssl session + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectSslVersionData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectSslVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + + int ret = 0; + uint16_t ver = 0; + uint8_t sig_ver = TLS_UNKNOWN; + + const DetectSslVersionData *ssl = (const DetectSslVersionData *)m; + SSLState *app_state = (SSLState *)state; + if (app_state == NULL) { + SCLogDebug("no app state, no match"); + SCReturnInt(0); + } + + if (flags & STREAM_TOCLIENT) { + SCLogDebug("server (toclient) version is 0x%02X", app_state->server_connp.version); + ver = app_state->server_connp.version; + } else if (flags & STREAM_TOSERVER) { + SCLogDebug("client (toserver) version is 0x%02X", app_state->client_connp.version); + ver = app_state->client_connp.version; + } + + switch (ver) { + case SSL_VERSION_2: + if (ver == ssl->data[SSLv2].ver) + ret = 1; + sig_ver = SSLv2; + break; + case SSL_VERSION_3: + if (ver == ssl->data[SSLv3].ver) + ret = 1; + sig_ver = SSLv3; + break; + case TLS_VERSION_10: + if (ver == ssl->data[TLS10].ver) + ret = 1; + sig_ver = TLS10; + break; + case TLS_VERSION_11: + if (ver == ssl->data[TLS11].ver) + ret = 1; + sig_ver = TLS11; + break; + case TLS_VERSION_12: + if (ver == ssl->data[TLS12].ver) + ret = 1; + sig_ver = TLS12; + break; + case TLS_VERSION_13_DRAFT28: + case TLS_VERSION_13_DRAFT27: + case TLS_VERSION_13_DRAFT26: + case TLS_VERSION_13_DRAFT25: + case TLS_VERSION_13_DRAFT24: + case TLS_VERSION_13_DRAFT23: + case TLS_VERSION_13_DRAFT22: + case TLS_VERSION_13_DRAFT21: + case TLS_VERSION_13_DRAFT20: + case TLS_VERSION_13_DRAFT19: + case TLS_VERSION_13_DRAFT18: + case TLS_VERSION_13_DRAFT17: + case TLS_VERSION_13_DRAFT16: + case TLS_VERSION_13_PRE_DRAFT16: + if (((ver >> 8) & 0xff) == 0x7f) + ver = TLS_VERSION_13; + /* fall through */ + case TLS_VERSION_13: + if (ver == ssl->data[TLS13].ver) + ret = 1; + sig_ver = TLS13; + break; + } + + if (sig_ver == TLS_UNKNOWN) + SCReturnInt(0); + + SCReturnInt(ret ^ ((ssl->data[sig_ver].flags & DETECT_SSL_VERSION_NEGATED) ? 1 : 0)); +} + +struct SSLVersionKeywords { + const char *word; + int index; + uint16_t value; +}; + +struct SSLVersionKeywords ssl_version_keywords[TLS_SIZE] = { + { "sslv2", SSLv2, SSL_VERSION_2 }, + { "sslv3", SSLv3, SSL_VERSION_3 }, + { "tls1.0", TLS10, TLS_VERSION_10 }, + { "tls1.1", TLS11, TLS_VERSION_11 }, + { "tls1.2", TLS12, TLS_VERSION_12 }, + { "tls1.3", TLS13, TLS_VERSION_13 }, +}; + +/** + * \brief This function is used to parse ssl_version data passed via + * keyword: "ssl_version" + * + * \param de_ctx Pointer to the detection engine context + * \param str Pointer to the user provided options + * + * \retval ssl pointer to DetectSslVersionData on success + * \retval NULL on failure + */ +static DetectSslVersionData *DetectSslVersionParse(DetectEngineCtx *de_ctx, const char *str) +{ + DetectSslVersionData *ssl = NULL; + const char *tmp_str = str; + size_t tmp_len = 0; + uint8_t found = 0; + + /* We have a correct ssl_version options */ + ssl = SCCalloc(1, sizeof(DetectSslVersionData)); + if (unlikely(ssl == NULL)) + goto error; + + // skip leading space + while (tmp_str[0] != 0 && isspace(tmp_str[0])) { + tmp_str++; + } + if (tmp_str[0] == 0) { + SCLogError("Invalid empty value"); + goto error; + } + // iterate every version separated by comma + while (tmp_str[0] != 0) { + uint8_t neg = 0; + if (tmp_str[0] == '!') { + neg = 1; + tmp_str++; + } + // counts word length + tmp_len = 0; + while (tmp_str[tmp_len] != 0 && !isspace(tmp_str[tmp_len]) && tmp_str[tmp_len] != ',') { + tmp_len++; + } + + bool is_keyword = false; + for (size_t i = 0; i < TLS_SIZE; i++) { + if (tmp_len == strlen(ssl_version_keywords[i].word) && + strncasecmp(ssl_version_keywords[i].word, tmp_str, tmp_len) == 0) { + if (ssl->data[ssl_version_keywords[i].index].ver != 0) { + SCLogError("Invalid duplicate value"); + goto error; + } + ssl->data[ssl_version_keywords[i].index].ver = ssl_version_keywords[i].value; + if (neg == 1) + ssl->data[ssl_version_keywords[i].index].flags |= DETECT_SSL_VERSION_NEGATED; + is_keyword = true; + break; + } + } + if (!is_keyword) { + SCLogError("Invalid unknown value"); + goto error; + } + + /* check consistency between negative and positive values : + * if there is a negative value, it overrides positive values + */ + if (found == 0) { + found |= 1 << neg; + } else if (found != 1 << neg) { + SCLogError("Invalid value mixing negative and positive forms"); + goto error; + } + + tmp_str += tmp_len; + while (isspace(tmp_str[0]) || tmp_str[0] == ',') { + tmp_str++; + } + } + + return ssl; + +error: + if (ssl != NULL) + DetectSslVersionFree(de_ctx, ssl); + return NULL; +} + +/** + * \brief this function is used to add the parsed "id" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "id" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectSslVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + DetectSslVersionData *ssl = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + ssl = DetectSslVersionParse(de_ctx, str); + if (ssl == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSL_VERSION, (SigMatchCtx *)ssl, + g_tls_generic_list_id) == NULL) { + goto error; + } + return 0; + +error: + if (ssl != NULL) + DetectSslVersionFree(de_ctx, ssl); + return -1; +} + +/** + * \brief this function will free memory associated with DetectSslVersionData + * + * \param id_d pointer to DetectSslVersionData + */ +void DetectSslVersionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + if (ptr != NULL) + SCFree(ptr); +} + +#ifdef UNITTESTS +#include "tests/detect-ssl-version.c" +#endif diff --git a/src/app-layer/ssl/detect-version.h b/src/app-layer/ssl/detect-version.h new file mode 100644 index 000000000000..1605a9ebf156 --- /dev/null +++ b/src/app-layer/ssl/detect-version.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file detect-ssl-version.h + * + * \author Gurvinder Singh + * + */ + +#ifndef DETECT_SSL_VERSION_H +#define DETECT_SSL_VERSION_H + +#define DETECT_SSL_VERSION_NEGATED 0x01 + +enum { + SSLv2 = 0, + SSLv3 = 1, + TLS10 = 2, + TLS11 = 3, + TLS12 = 4, + TLS13 = 5, + + TLS_SIZE = 6, + TLS_UNKNOWN = 7, +}; + +typedef struct SSLVersionData_ { + uint16_t ver; /** ssl version to match */ + uint8_t flags; +} SSLVersionData; + +typedef struct DetectSslVersionData_ { + SSLVersionData data[TLS_SIZE]; +} DetectSslVersionData; + +/* prototypes */ +void DetectSslVersionRegister(void); + +#endif /* DETECT_SSL_VERSION_H */ diff --git a/src/app-layer/ssl/parser.c b/src/app-layer/ssl/parser.c new file mode 100644 index 000000000000..0ab81b182475 --- /dev/null +++ b/src/app-layer/ssl/parser.c @@ -0,0 +1,3011 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * \author Pierre Chifflier + * \author Mats Klepsland + * + */ + +#include "suricata-common.h" +#include "decode.h" +#include "threads.h" + +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" +#include "stream-tcp.h" +#include "stream.h" + +#include "app-layer.h" +#include "app-layer-detect-proto.h" +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-frames.h" +#include "app-layer/ssl/parser.h" + +#include "decode-events.h" +#include "conf.h" + +#include "util/spm.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/pool.h" +#include "util/byte.h" +#include "util/ja3.h" +#include "util/enum.h" +#include "flow-util.h" +#include "flow-private.h" +#include "util/validate.h" + +SCEnumCharMap tls_frame_table[] = { + { + "pdu", + TLS_FRAME_PDU, + }, + { + "hdr", + TLS_FRAME_HDR, + }, + { + "data", + TLS_FRAME_DATA, + }, + { + "alert", + TLS_FRAME_ALERT_DATA, + }, + { + "heartbeat", + TLS_FRAME_HB_DATA, + }, + { + "ssl2.hdr", + TLS_FRAME_SSLV2_HDR, + }, + { + "ssl2.pdu", + TLS_FRAME_SSLV2_PDU, + }, + { NULL, -1 }, +}; + +SCEnumCharMap tls_decoder_event_table[] = { + /* TLS protocol messages */ + { "INVALID_SSLV2_HEADER", TLS_DECODER_EVENT_INVALID_SSLV2_HEADER }, + { "INVALID_TLS_HEADER", TLS_DECODER_EVENT_INVALID_TLS_HEADER }, + { "INVALID_RECORD_VERSION", TLS_DECODER_EVENT_INVALID_RECORD_VERSION }, + { "INVALID_RECORD_TYPE", TLS_DECODER_EVENT_INVALID_RECORD_TYPE }, + { "INVALID_RECORD_LENGTH", TLS_DECODER_EVENT_INVALID_RECORD_LENGTH }, + { "INVALID_HANDSHAKE_MESSAGE", TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE }, + { "HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_HEARTBEAT }, + { "INVALID_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_INVALID_HEARTBEAT }, + { "OVERFLOW_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT }, + { "DATALEAK_HEARTBEAT_MISMATCH", TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH }, + { "HANDSHAKE_INVALID_LENGTH", TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH }, + { "MULTIPLE_SNI_EXTENSIONS", TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS }, + { "INVALID_SNI_TYPE", TLS_DECODER_EVENT_INVALID_SNI_TYPE }, + { "INVALID_SNI_LENGTH", TLS_DECODER_EVENT_INVALID_SNI_LENGTH }, + { "TOO_MANY_RECORDS_IN_PACKET", TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET }, + /* certificate decoding messages */ + { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, + { "CERTIFICATE_INVALID_LENGTH", TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH }, + { "CERTIFICATE_INVALID_VERSION", TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION }, + { "CERTIFICATE_INVALID_SERIAL", TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL }, + { "CERTIFICATE_INVALID_ALGORITHMIDENTIFIER", + TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER }, + { "CERTIFICATE_INVALID_X509NAME", TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME }, + { "CERTIFICATE_INVALID_DATE", TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE }, + { "CERTIFICATE_INVALID_EXTENSIONS", TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS }, + { "CERTIFICATE_INVALID_DER", TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER }, + { "CERTIFICATE_INVALID_SUBJECT", TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT }, + { "CERTIFICATE_INVALID_ISSUER", TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER }, + { "CERTIFICATE_INVALID_VALIDITY", TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY }, + { "ERROR_MESSAGE_ENCOUNTERED", TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED }, + /* used as a generic error event */ + { "INVALID_SSL_RECORD", TLS_DECODER_EVENT_INVALID_SSL_RECORD }, + { NULL, -1 }, +}; + +enum { + /* X.509 error codes, returned by decoder + * THESE CONSTANTS MUST MATCH rust/src/x509/mod.rs ! */ + ERR_INVALID_CERTIFICATE = 1, + ERR_INVALID_LENGTH, + ERR_INVALID_VERSION, + ERR_INVALID_SERIAL, + ERR_INVALID_ALGORITHMIDENTIFIER, + ERR_INVALID_X509NAME, + ERR_INVALID_DATE, + ERR_INVALID_EXTENSIONS, + ERR_INVALID_DER, + + /* error getting data */ + ERR_EXTRACT_SUBJECT, + ERR_EXTRACT_ISSUER, + ERR_EXTRACT_VALIDITY, +}; + +/* JA3 fingerprints are disabled by default */ +#define SSL_CONFIG_DEFAULT_JA3 0 + +enum SslConfigEncryptHandling { + SSL_CNF_ENC_HANDLE_DEFAULT = 0, /**< disable raw content, continue tracking */ + SSL_CNF_ENC_HANDLE_BYPASS = 1, /**< skip processing of flow, bypass if possible */ + SSL_CNF_ENC_HANDLE_FULL = 2, /**< handle fully like any other proto */ +}; + +typedef struct SslConfig_ { + enum SslConfigEncryptHandling encrypt_mode; + /** dynamic setting for ja3: can be enabled on demand if not explicitly + * disabled. */ + SC_ATOMIC_DECLARE(int, enable_ja3); + bool disable_ja3; /**< ja3 explicitly disabled. Don't enable on demand. */ +} SslConfig; + +SslConfig ssl_config; + +/* SSLv3 record types */ +#define SSLV3_CHANGE_CIPHER_SPEC 20 +#define SSLV3_ALERT_PROTOCOL 21 +#define SSLV3_HANDSHAKE_PROTOCOL 22 +#define SSLV3_APPLICATION_PROTOCOL 23 +#define SSLV3_HEARTBEAT_PROTOCOL 24 + +/* SSLv3 handshake protocol types */ +#define SSLV3_HS_HELLO_REQUEST 0 +#define SSLV3_HS_CLIENT_HELLO 1 +#define SSLV3_HS_SERVER_HELLO 2 +#define SSLV3_HS_NEW_SESSION_TICKET 4 +#define SSLV3_HS_CERTIFICATE 11 +#define SSLV3_HS_SERVER_KEY_EXCHANGE 12 +#define SSLV3_HS_CERTIFICATE_REQUEST 13 +#define SSLV3_HS_SERVER_HELLO_DONE 14 +#define SSLV3_HS_CERTIFICATE_VERIFY 15 +#define SSLV3_HS_CLIENT_KEY_EXCHANGE 16 +#define SSLV3_HS_FINISHED 20 +#define SSLV3_HS_CERTIFICATE_URL 21 +#define SSLV3_HS_CERTIFICATE_STATUS 22 + +/* SSLv2 protocol message types */ +#define SSLV2_MT_ERROR 0 +#define SSLV2_MT_CLIENT_HELLO 1 +#define SSLV2_MT_CLIENT_MASTER_KEY 2 +#define SSLV2_MT_CLIENT_FINISHED 3 +#define SSLV2_MT_SERVER_HELLO 4 +#define SSLV2_MT_SERVER_VERIFY 5 +#define SSLV2_MT_SERVER_FINISHED 6 +#define SSLV2_MT_REQUEST_CERTIFICATE 7 +#define SSLV2_MT_CLIENT_CERTIFICATE 8 + +#define SSLV3_RECORD_HDR_LEN 5 +#define SSLV3_MESSAGE_HDR_LEN 4 +/** max length according to RFC 5246 6.2.2 is 2^14 + 1024 */ +#define SSLV3_RECORD_MAX_LEN ((1 << 14) + 1024) + +#define SSLV3_CLIENT_HELLO_VERSION_LEN 2 +#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32 + +/* TLS heartbeat protocol types */ +#define TLS_HB_REQUEST 1 +#define TLS_HB_RESPONSE 2 + +#define SSL_RECORD_MINIMUM_LENGTH 6 + +#define SHA1_STRING_LENGTH 60 + +#define HAS_SPACE(n) ((uint64_t)(input - initial_input) + (uint64_t)(n) <= (uint64_t)(input_len)) + +struct SSLDecoderResult { + int retval; // nr bytes consumed from input, or < 0 on error + uint32_t needed; // more bytes needed +}; +#define SSL_DECODER_ERROR(e) \ + (struct SSLDecoderResult) \ + { \ + (e), 0 \ + } +#define SSL_DECODER_OK(c) \ + (struct SSLDecoderResult) \ + { \ + (c), 0 \ + } +#define SSL_DECODER_INCOMPLETE(c, n) \ + (struct SSLDecoderResult) \ + { \ + (c), (n) \ + } + +static inline int SafeMemcpy(void *dst, size_t dst_offset, size_t dst_size, const void *src, + size_t src_offset, size_t src_size, size_t src_tocopy) WARN_UNUSED; + +static inline int SafeMemcpy(void *dst, size_t dst_offset, size_t dst_size, const void *src, + size_t src_offset, size_t src_size, size_t src_tocopy) +{ + DEBUG_VALIDATE_BUG_ON(dst_offset >= dst_size); + DEBUG_VALIDATE_BUG_ON(src_offset >= src_size); + DEBUG_VALIDATE_BUG_ON(src_tocopy > (src_size - src_offset)); + DEBUG_VALIDATE_BUG_ON(src_tocopy > (dst_size - dst_offset)); + + if (dst_offset < dst_size && src_offset < src_size && src_tocopy <= (src_size - src_offset) && + src_tocopy <= (dst_size - dst_offset)) { + memcpy(dst + dst_offset, src + src_offset, src_tocopy); + return 0; + } + return -1; +} + +#ifdef DEBUG_VALIDATION +#define ValidateRecordState(connp) \ + do { \ + DEBUG_VALIDATE_BUG_ON( \ + ((connp)->record_length + SSLV3_RECORD_HDR_LEN) < (connp)->bytes_processed); \ + } while (0); +#else +#define ValidateRecordState(...) +#endif + +#define SSLParserHSReset(connp) \ + do { \ + (connp)->handshake_type = 0; \ + (connp)->message_length = 0; \ + } while (0) + +#define SSLParserReset(state) \ + do { \ + SCLogDebug("resetting state"); \ + (state)->curr_connp->bytes_processed = 0; \ + SSLParserHSReset((state)->curr_connp); \ + } while (0) + +#define SSLSetEvent(ssl_state, event) \ + do { \ + SCLogDebug("setting event %u", (event)); \ + if ((ssl_state) == NULL) { \ + SCLogDebug("could not set decoder event %u", event); \ + } else { \ + AppLayerDecoderEventsSetEventRaw(&(ssl_state)->tx_data.events, (event)); \ + (ssl_state)->events++; \ + } \ + } while (0) + +static void *SSLGetTx(void *state, uint64_t tx_id) +{ + SSLState *ssl_state = (SSLState *)state; + return ssl_state; +} + +static uint64_t SSLGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static int SSLGetAlstateProgress(void *tx, uint8_t direction) +{ + SSLState *ssl_state = (SSLState *)tx; + + /* we don't care about direction, only that app-layer parser is done + and have sent an EOF */ + if (ssl_state->flags & SSL_AL_FLAG_STATE_FINISHED) { + return TLS_STATE_FINISHED; + } + + /* we want the logger to log when the handshake is done, even if the + state is not finished */ + if (ssl_state->flags & SSL_AL_FLAG_HANDSHAKE_DONE) { + return TLS_HANDSHAKE_DONE; + } + + if (direction == STREAM_TOSERVER && (ssl_state->server_connp.cert0_subject != NULL || + ssl_state->server_connp.cert0_issuerdn != NULL)) { + return TLS_STATE_CERT_READY; + } + + return TLS_STATE_IN_PROGRESS; +} + +static AppLayerTxData *SSLGetTxData(void *vtx) +{ + SSLState *ssl_state = (SSLState *)vtx; + return &ssl_state->tx_data; +} + +static AppLayerStateData *SSLGetStateData(void *vstate) +{ + SSLState *ssl_state = (SSLState *)vstate; + return &ssl_state->state_data; +} + +void SSLVersionToString(uint16_t version, char *buffer) +{ + buffer[0] = '\0'; + + switch (version) { + case TLS_VERSION_UNKNOWN: + strlcat(buffer, "UNDETERMINED", 13); + break; + case SSL_VERSION_2: + strlcat(buffer, "SSLv2", 6); + break; + case SSL_VERSION_3: + strlcat(buffer, "SSLv3", 6); + break; + case TLS_VERSION_10: + strlcat(buffer, "TLSv1", 6); + break; + case TLS_VERSION_11: + strlcat(buffer, "TLS 1.1", 8); + break; + case TLS_VERSION_12: + strlcat(buffer, "TLS 1.2", 8); + break; + case TLS_VERSION_13: + strlcat(buffer, "TLS 1.3", 8); + break; + case TLS_VERSION_13_DRAFT28: + strlcat(buffer, "TLS 1.3 draft-28", 17); + break; + case TLS_VERSION_13_DRAFT27: + strlcat(buffer, "TLS 1.3 draft-27", 17); + break; + case TLS_VERSION_13_DRAFT26: + strlcat(buffer, "TLS 1.3 draft-26", 17); + break; + case TLS_VERSION_13_DRAFT25: + strlcat(buffer, "TLS 1.3 draft-25", 17); + break; + case TLS_VERSION_13_DRAFT24: + strlcat(buffer, "TLS 1.3 draft-24", 17); + break; + case TLS_VERSION_13_DRAFT23: + strlcat(buffer, "TLS 1.3 draft-23", 17); + break; + case TLS_VERSION_13_DRAFT22: + strlcat(buffer, "TLS 1.3 draft-22", 17); + break; + case TLS_VERSION_13_DRAFT21: + strlcat(buffer, "TLS 1.3 draft-21", 17); + break; + case TLS_VERSION_13_DRAFT20: + strlcat(buffer, "TLS 1.3 draft-20", 17); + break; + case TLS_VERSION_13_DRAFT19: + strlcat(buffer, "TLS 1.3 draft-19", 17); + break; + case TLS_VERSION_13_DRAFT18: + strlcat(buffer, "TLS 1.3 draft-18", 17); + break; + case TLS_VERSION_13_DRAFT17: + strlcat(buffer, "TLS 1.3 draft-17", 17); + break; + case TLS_VERSION_13_DRAFT16: + strlcat(buffer, "TLS 1.3 draft-16", 17); + break; + case TLS_VERSION_13_PRE_DRAFT16: + strlcat(buffer, "TLS 1.3 draft-<16", 18); + break; + case TLS_VERSION_13_DRAFT20_FB: + strlcat(buffer, "TLS 1.3 draft-20-fb", 20); + break; + case TLS_VERSION_13_DRAFT21_FB: + strlcat(buffer, "TLS 1.3 draft-21-fb", 20); + break; + case TLS_VERSION_13_DRAFT22_FB: + strlcat(buffer, "TLS 1.3 draft-22-fb", 20); + break; + case TLS_VERSION_13_DRAFT23_FB: + strlcat(buffer, "TLS 1.3 draft-23-fb", 20); + break; + case TLS_VERSION_13_DRAFT26_FB: + strlcat(buffer, "TLS 1.3 draft-26-fb", 20); + break; + default: + snprintf(buffer, 7, "0x%04x", version); + break; + } +} + +static void TlsDecodeHSCertificateErrSetEvent(SSLState *ssl_state, uint32_t err) +{ + switch (err) { + case ERR_EXTRACT_VALIDITY: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY); + break; + case ERR_EXTRACT_ISSUER: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER); + break; + case ERR_EXTRACT_SUBJECT: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT); + break; + case ERR_INVALID_DER: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER); + break; + case ERR_INVALID_EXTENSIONS: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS); + break; + case ERR_INVALID_DATE: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE); + break; + case ERR_INVALID_X509NAME: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME); + break; + case ERR_INVALID_ALGORITHMIDENTIFIER: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER); + break; + case ERR_INVALID_SERIAL: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL); + break; + case ERR_INVALID_VERSION: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION); + break; + case ERR_INVALID_LENGTH: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH); + break; + case ERR_INVALID_CERTIFICATE: + default: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + break; + } +} + +static inline int TlsDecodeHSCertificateFingerprint( + SSLStateConnp *connp, const uint8_t *input, uint32_t cert_len) +{ + if (unlikely(connp->cert0_fingerprint != NULL)) + return 0; + + connp->cert0_fingerprint = SCCalloc(1, SHA1_STRING_LENGTH); + if (connp->cert0_fingerprint == NULL) + return -1; + + uint8_t hash[SC_SHA1_LEN]; + if (SCSha1HashBuffer(input, cert_len, hash, sizeof(hash)) == 1) { + rs_to_hex_sep( + (uint8_t *)connp->cert0_fingerprint, SHA1_STRING_LENGTH, ':', hash, SC_SHA1_LEN); + } + return 0; +} + +static inline int TlsDecodeHSCertificateAddCertToChain( + SSLStateConnp *connp, const uint8_t *input, uint32_t cert_len) +{ + SSLCertsChain *cert = SCCalloc(1, sizeof(SSLCertsChain)); + if (cert == NULL) + return -1; + + cert->cert_data = (uint8_t *)input; + cert->cert_len = cert_len; + TAILQ_INSERT_TAIL(&connp->certs, cert, next); + + return 0; +} + +static int TlsDecodeHSCertificate(SSLState *ssl_state, SSLStateConnp *connp, + const uint8_t *const initial_input, const uint32_t input_len, const int certn) +{ + const uint8_t *input = (uint8_t *)initial_input; + uint32_t err_code = 0; + X509 *x509 = NULL; + int rc = 0; + + if (!(HAS_SPACE(3))) + goto invalid_cert; + + uint32_t cert_len = *input << 16 | *(input + 1) << 8 | *(input + 2); + input += 3; + + if (!(HAS_SPACE(cert_len))) + goto invalid_cert; + + /* only store fields from the first certificate in the chain */ + if (certn == 0 && connp->cert0_subject == NULL && connp->cert0_issuerdn == NULL && + connp->cert0_serial == NULL) { + x509 = rs_x509_decode(input, cert_len, &err_code); + if (x509 == NULL) { + TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code); + goto next; + } + + char *str = rs_x509_get_subject(x509); + if (str == NULL) { + err_code = ERR_EXTRACT_SUBJECT; + goto error; + } + connp->cert0_subject = str; + + str = rs_x509_get_issuer(x509); + if (str == NULL) { + err_code = ERR_EXTRACT_ISSUER; + goto error; + } + connp->cert0_issuerdn = str; + + str = rs_x509_get_serial(x509); + if (str == NULL) { + err_code = ERR_INVALID_SERIAL; + goto error; + } + connp->cert0_serial = str; + + rc = rs_x509_get_validity(x509, &connp->cert0_not_before, &connp->cert0_not_after); + if (rc != 0) { + err_code = ERR_EXTRACT_VALIDITY; + goto error; + } + + rs_x509_free(x509); + x509 = NULL; + + rc = TlsDecodeHSCertificateFingerprint(connp, input, cert_len); + if (rc != 0) { + SCLogDebug("TlsDecodeHSCertificateFingerprint failed with %d", rc); + goto error; + } + } + + rc = TlsDecodeHSCertificateAddCertToChain(connp, input, cert_len); + if (rc != 0) { + SCLogDebug("TlsDecodeHSCertificateAddCertToChain failed with %d", rc); + goto error; + } + +next: + input += cert_len; + return (input - initial_input); + +error: + if (err_code != 0) + TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code); + if (x509 != NULL) + rs_x509_free(x509); + return -1; + +invalid_cert: + SCLogDebug("TLS invalid certificate"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + return -1; +} + +/** \internal + * \brief parse cert data in a certificate handshake message + * will be called with all data. + * \retval consumed bytes consumed or -1 on error + */ +static int TlsDecodeHSCertificates(SSLState *ssl_state, SSLStateConnp *connp, + const uint8_t *const initial_input, const uint32_t input_len) +{ + const uint8_t *input = (uint8_t *)initial_input; + + if (!(HAS_SPACE(3))) + return -1; + + const uint32_t cert_chain_len = *input << 16 | *(input + 1) << 8 | *(input + 2); + input += 3; + + if (!(HAS_SPACE(cert_chain_len))) + return -1; + + if (connp->certs_buffer != NULL) { + // TODO should we set an event here? + return -1; + } + + connp->certs_buffer = SCCalloc(1, cert_chain_len); + if (connp->certs_buffer == NULL) { + return -1; + } + connp->certs_buffer_size = cert_chain_len; + memcpy(connp->certs_buffer, input, cert_chain_len); + + int cert_cnt = 0; + uint32_t processed_len = 0; + /* coverity[tainted_data] */ + while (processed_len < cert_chain_len) { + int rc = TlsDecodeHSCertificate(ssl_state, connp, connp->certs_buffer + processed_len, + connp->certs_buffer_size - processed_len, cert_cnt); + if (rc <= 0) { // 0 should be impossible, but lets be defensive + return -1; + } + DEBUG_VALIDATE_BUG_ON(processed_len + (uint32_t)rc > cert_chain_len); + if (processed_len + (uint32_t)rc > cert_chain_len) { + return -1; + } + + processed_len += (uint32_t)rc; + } + + return processed_len + 3; +} + +/** + * \inline + * \brief Check if value is GREASE. + * + * http://tools.ietf.org/html/draft-davidben-tls-grease-00 + * + * \param value Value to check. + * + * \retval 1 if is GREASE. + * \retval 0 if not is GREASE. + */ +static inline int TLSDecodeValueIsGREASE(const uint16_t value) +{ + switch (value) { + case 0x0a0a: + case 0x1a1a: + case 0x2a2a: + case 0x3a3a: + case 0x4a4a: + case 0x5a5a: + case 0x6a6a: + case 0x7a7a: + case 0x8a8a: + case 0x9a9a: + case 0xaaaa: + case 0xbaba: + case 0xcaca: + case 0xdada: + case 0xeaea: + case 0xfafa: + return 1; + default: + return 0; + } +} + +static inline int TLSDecodeHSHelloVersion( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + uint8_t *input = (uint8_t *)initial_input; + + if (!(HAS_SPACE(SSLV3_CLIENT_HELLO_VERSION_LEN))) { + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + return -1; + } + + uint16_t version = (uint16_t)(*input << 8) | *(input + 1); + ssl_state->curr_connp->version = version; + + /* TLSv1.3 draft1 to draft21 use the version field as earlier TLS + versions, instead of using the supported versions extension. */ + if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && + ((ssl_state->curr_connp->version == TLS_VERSION_13) || + (((ssl_state->curr_connp->version >> 8) & 0xff) == 0x7f))) { + ssl_state->flags |= SSL_AL_FLAG_LOG_WITHOUT_CERT; + } + + /* Catch some early TLSv1.3 draft implementations that does not conform + to the draft version. */ + if ((ssl_state->curr_connp->version >= 0x7f01) && (ssl_state->curr_connp->version < 0x7f10)) { + ssl_state->curr_connp->version = TLS_VERSION_13_PRE_DRAFT16; + } + + /* TLSv1.3 drafts from draft1 to draft15 use 0x0304 (TLSv1.3) as the + version number, which makes it hard to accurately pinpoint the + exact draft version. */ + else if (ssl_state->curr_connp->version == TLS_VERSION_13) { + ssl_state->curr_connp->version = TLS_VERSION_13_PRE_DRAFT16; + } + + if (SC_ATOMIC_GET(ssl_config.enable_ja3) && ssl_state->curr_connp->ja3_str == NULL) { + ssl_state->curr_connp->ja3_str = Ja3BufferInit(); + if (ssl_state->curr_connp->ja3_str == NULL) + return -1; + + int rc = Ja3BufferAddValue(&ssl_state->curr_connp->ja3_str, version); + if (rc != 0) + return -1; + } + + input += SSLV3_CLIENT_HELLO_VERSION_LEN; + + return (input - initial_input); +} + +static inline int TLSDecodeHSHelloRandom( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + uint8_t *input = (uint8_t *)initial_input; + + if (!(HAS_SPACE(SSLV3_CLIENT_HELLO_RANDOM_LEN))) { + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + return -1; + } + + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { + memcpy(ssl_state->server_connp.random, input, TLS_RANDOM_LEN); + ssl_state->flags |= TLS_TS_RANDOM_SET; + } else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + memcpy(ssl_state->client_connp.random, input, TLS_RANDOM_LEN); + ssl_state->flags |= TLS_TC_RANDOM_SET; + } + + /* Skip random */ + input += SSLV3_CLIENT_HELLO_RANDOM_LEN; + + return (input - initial_input); +} + +static inline int TLSDecodeHSHelloSessionID( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + uint8_t *input = (uint8_t *)initial_input; + + if (!(HAS_SPACE(1))) + goto invalid_length; + + uint8_t session_id_length = *input; + input += 1; + + if (!(HAS_SPACE(session_id_length))) + goto invalid_length; + + if (session_id_length != 0 && ssl_state->curr_connp->session_id == NULL) { + ssl_state->curr_connp->session_id = SCMalloc(session_id_length); + + if (unlikely(ssl_state->curr_connp->session_id == NULL)) { + return -1; + } + + if (SafeMemcpy(ssl_state->curr_connp->session_id, 0, session_id_length, input, 0, input_len, + session_id_length) != 0) { + return -1; + } + ssl_state->curr_connp->session_id_length = session_id_length; + + if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && + ssl_state->client_connp.session_id != NULL && + ssl_state->server_connp.session_id != NULL) { + if ((ssl_state->client_connp.session_id_length == + ssl_state->server_connp.session_id_length) && + (memcmp(ssl_state->server_connp.session_id, ssl_state->client_connp.session_id, + session_id_length) == 0)) { + ssl_state->flags |= SSL_AL_FLAG_SESSION_RESUMED; + } + } + } + + input += session_id_length; + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + return -1; +} + +static inline int TLSDecodeHSHelloCipherSuites( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + const uint8_t *input = initial_input; + + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t cipher_suites_length; + + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { + cipher_suites_length = 2; + } else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + cipher_suites_length = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + } else { + return -1; + } + + if (!(HAS_SPACE(cipher_suites_length))) + goto invalid_length; + + /* Cipher suites length should always be divisible by 2 */ + if ((cipher_suites_length % 2) != 0) { + goto invalid_length; + } + + if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { + JA3Buffer *ja3_cipher_suites = Ja3BufferInit(); + if (ja3_cipher_suites == NULL) + return -1; + + uint16_t processed_len = 0; + /* coverity[tainted_data] */ + while (processed_len < cipher_suites_length) { + if (!(HAS_SPACE(2))) { + Ja3BufferFree(&ja3_cipher_suites); + goto invalid_length; + } + + uint16_t cipher_suite = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + + if (TLSDecodeValueIsGREASE(cipher_suite) != 1) { + int rc = Ja3BufferAddValue(&ja3_cipher_suites, cipher_suite); + if (rc != 0) { + return -1; + } + } + + processed_len += 2; + } + + int rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, &ja3_cipher_suites); + if (rc == -1) { + return -1; + } + + } else { + /* Skip cipher suites */ + input += cipher_suites_length; + } + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + return -1; +} + +static inline int TLSDecodeHSHelloCompressionMethods( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + const uint8_t *input = initial_input; + + if (!(HAS_SPACE(1))) + goto invalid_length; + + /* Skip compression methods */ + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { + input += 1; + } else { + uint8_t compression_methods_length = *input; + input += 1; + + if (!(HAS_SPACE(compression_methods_length))) + goto invalid_length; + + input += compression_methods_length; + } + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid_length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + return -1; +} + +static inline int TLSDecodeHSHelloExtensionSni( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + uint8_t *input = (uint8_t *)initial_input; + + /* Empty extension */ + if (input_len == 0) + return 0; + + if (!(HAS_SPACE(2))) + goto invalid_length; + + /* Skip sni_list_length */ + input += 2; + + if (!(HAS_SPACE(1))) + goto invalid_length; + + uint8_t sni_type = *input; + input += 1; + + /* Currently the only type allowed is host_name + (RFC6066 section 3). */ + if (sni_type != SSL_SNI_TYPE_HOST_NAME) { + SCLogDebug("Unknown SNI type"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SNI_TYPE); + return -1; + } + + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t sni_len = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + + /* host_name contains the fully qualified domain name, + and should therefore be limited by the maximum domain + name length. */ + if (!(HAS_SPACE(sni_len)) || sni_len > 255 || sni_len == 0) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SNI_LENGTH); + return -1; + } + + /* There must not be more than one extension of the same + type (RFC5246 section 7.4.1.4). */ + if (ssl_state->curr_connp->sni) { + SCLogDebug("Multiple SNI extensions"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS); + input += sni_len; + return (input - initial_input); + } + + const size_t sni_strlen = sni_len + 1; + ssl_state->curr_connp->sni = SCMalloc(sni_strlen); + if (unlikely(ssl_state->curr_connp->sni == NULL)) + return -1; + + const size_t consumed = input - initial_input; + if (SafeMemcpy(ssl_state->curr_connp->sni, 0, sni_strlen, initial_input, consumed, input_len, + sni_len) != 0) { + SCFree(ssl_state->curr_connp->sni); + ssl_state->curr_connp->sni = NULL; + return -1; + } + ssl_state->curr_connp->sni[sni_strlen - 1] = 0; + + input += sni_len; + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + + return -1; +} + +static inline int TLSDecodeHSHelloExtensionSupportedVersions( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + const uint8_t *input = initial_input; + + /* Empty extension */ + if (input_len == 0) + return 0; + + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + if (!(HAS_SPACE(1))) + goto invalid_length; + + uint8_t supported_ver_len = *input; + input += 1; + + if (supported_ver_len < 2) + goto invalid_length; + + if (!(HAS_SPACE(supported_ver_len))) + goto invalid_length; + + /* Use the first (and prefered) valid version as client version, + * skip over GREASE and other possible noise. */ + uint16_t i = 0; + while (i + 1 < (uint16_t)supported_ver_len) { + uint16_t ver = (uint16_t)(input[i] << 8) | input[i + 1]; + if (TLSVersionValid(ver)) { + ssl_state->curr_connp->version = ver; + break; + } + i += 2; + } + + /* Set a flag to indicate that we have seen this extension */ + ssl_state->flags |= SSL_AL_FLAG_CH_VERSION_EXTENSION; + + input += supported_ver_len; + } else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) { + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t ver = (uint16_t)(*input << 8) | *(input + 1); + + if ((ssl_state->flags & SSL_AL_FLAG_CH_VERSION_EXTENSION) && (ver > TLS_VERSION_12)) { + ssl_state->flags |= SSL_AL_FLAG_LOG_WITHOUT_CERT; + } + + ssl_state->curr_connp->version = ver; + input += 2; + } + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + + return -1; +} + +static inline int TLSDecodeHSHelloExtensionEllipticCurves(SSLState *ssl_state, + const uint8_t *const initial_input, const uint32_t input_len, + JA3Buffer *ja3_elliptic_curves) +{ + const uint8_t *input = initial_input; + + /* Empty extension */ + if (input_len == 0) + return 0; + + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t elliptic_curves_len = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + + if (!(HAS_SPACE(elliptic_curves_len))) + goto invalid_length; + + if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && + SC_ATOMIC_GET(ssl_config.enable_ja3)) { + uint16_t ec_processed_len = 0; + /* coverity[tainted_data] */ + while (ec_processed_len < elliptic_curves_len) { + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t elliptic_curve = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + + if (TLSDecodeValueIsGREASE(elliptic_curve) != 1) { + int rc = Ja3BufferAddValue(&ja3_elliptic_curves, elliptic_curve); + if (rc != 0) + return -1; + } + + ec_processed_len += 2; + } + + } else { + /* Skip elliptic curves */ + input += elliptic_curves_len; + } + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + + return -1; +} + +static inline int TLSDecodeHSHelloExtensionEllipticCurvePF(SSLState *ssl_state, + const uint8_t *const initial_input, const uint32_t input_len, + JA3Buffer *ja3_elliptic_curves_pf) +{ + const uint8_t *input = initial_input; + + /* Empty extension */ + if (input_len == 0) + return 0; + + if (!(HAS_SPACE(1))) + goto invalid_length; + + uint8_t ec_pf_len = *input; + input += 1; + + if (!(HAS_SPACE(ec_pf_len))) + goto invalid_length; + + if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && + SC_ATOMIC_GET(ssl_config.enable_ja3)) { + uint8_t ec_pf_processed_len = 0; + /* coverity[tainted_data] */ + while (ec_pf_processed_len < ec_pf_len) { + uint8_t elliptic_curve_pf = *input; + input += 1; + + if (TLSDecodeValueIsGREASE(elliptic_curve_pf) != 1) { + int rc = Ja3BufferAddValue(&ja3_elliptic_curves_pf, elliptic_curve_pf); + if (rc != 0) + return -1; + } + + ec_pf_processed_len += 1; + } + + } else { + /* Skip elliptic curve point formats */ + input += ec_pf_len; + } + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + + return -1; +} + +static inline int TLSDecodeHSHelloExtensions( + SSLState *ssl_state, const uint8_t *const initial_input, const uint32_t input_len) +{ + const uint8_t *input = initial_input; + + int ret; + int rc; + const bool ja3 = (SC_ATOMIC_GET(ssl_config.enable_ja3) == 1); + + JA3Buffer *ja3_extensions = NULL; + JA3Buffer *ja3_elliptic_curves = NULL; + JA3Buffer *ja3_elliptic_curves_pf = NULL; + + if (ja3) { + ja3_extensions = Ja3BufferInit(); + if (ja3_extensions == NULL) + goto error; + + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + ja3_elliptic_curves = Ja3BufferInit(); + if (ja3_elliptic_curves == NULL) + goto error; + + ja3_elliptic_curves_pf = Ja3BufferInit(); + if (ja3_elliptic_curves_pf == NULL) + goto error; + } + } + + /* Extensions are optional (RFC5246 section 7.4.1.2) */ + if (!(HAS_SPACE(2))) + goto end; + + uint16_t extensions_len = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + + if (!(HAS_SPACE(extensions_len))) + goto invalid_length; + + uint16_t processed_len = 0; + /* coverity[tainted_data] */ + while (processed_len < extensions_len) { + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t ext_type = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t ext_len = (uint16_t)(*input << 8) | *(input + 1); + input += 2; + + if (!(HAS_SPACE(ext_len))) + goto invalid_length; + + switch (ext_type) { + case SSL_EXTENSION_SNI: { + /* coverity[tainted_data] */ + ret = TLSDecodeHSHelloExtensionSni(ssl_state, input, ext_len); + if (ret < 0) + goto end; + + input += ret; + + break; + } + + case SSL_EXTENSION_ELLIPTIC_CURVES: { + /* coverity[tainted_data] */ + ret = TLSDecodeHSHelloExtensionEllipticCurves( + ssl_state, input, ext_len, ja3_elliptic_curves); + if (ret < 0) + goto end; + + input += ret; + + break; + } + + case SSL_EXTENSION_EC_POINT_FORMATS: { + /* coverity[tainted_data] */ + ret = TLSDecodeHSHelloExtensionEllipticCurvePF( + ssl_state, input, ext_len, ja3_elliptic_curves_pf); + if (ret < 0) + goto end; + + input += ret; + + break; + } + + case SSL_EXTENSION_EARLY_DATA: { + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + /* Used by 0-RTT to indicate that encrypted data will + be sent right after the ClientHello record. */ + ssl_state->flags |= SSL_AL_FLAG_EARLY_DATA; + } + + input += ext_len; + + break; + } + + case SSL_EXTENSION_SUPPORTED_VERSIONS: { + ret = TLSDecodeHSHelloExtensionSupportedVersions(ssl_state, input, ext_len); + if (ret < 0) + goto end; + + input += ret; + + break; + } + + case SSL_EXTENSION_SESSION_TICKET: { + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + /* This has to be verified later on by checking if a + certificate record has been sent by the server. */ + ssl_state->flags |= SSL_AL_FLAG_SESSION_RESUMED; + } + + input += ext_len; + + break; + } + + default: { + input += ext_len; + break; + } + } + + if (ja3) { + if (TLSDecodeValueIsGREASE(ext_type) != 1) { + rc = Ja3BufferAddValue(&ja3_extensions, ext_type); + if (rc != 0) + goto error; + } + } + + processed_len += ext_len + 4; + } + +end: + if (ja3) { + rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, &ja3_extensions); + if (rc == -1) + goto error; + + if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { + rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, &ja3_elliptic_curves); + if (rc == -1) + goto error; + + rc = Ja3BufferAppendBuffer(&ssl_state->curr_connp->ja3_str, &ja3_elliptic_curves_pf); + if (rc == -1) + goto error; + } + } + + return (input - initial_input); + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + +error: + if (ja3_extensions != NULL) + Ja3BufferFree(&ja3_extensions); + if (ja3_elliptic_curves != NULL) + Ja3BufferFree(&ja3_elliptic_curves); + if (ja3_elliptic_curves_pf != NULL) + Ja3BufferFree(&ja3_elliptic_curves_pf); + + return -1; +} + +static int TLSDecodeHandshakeHello( + SSLState *ssl_state, const uint8_t *const input, const uint32_t input_len) +{ + int ret; + uint32_t parsed = 0; + + ret = TLSDecodeHSHelloVersion(ssl_state, input, input_len); + if (ret < 0) + goto end; + + parsed += ret; + + ret = TLSDecodeHSHelloRandom(ssl_state, input + parsed, input_len - parsed); + if (ret < 0) + goto end; + + parsed += ret; + + /* The session id field in the server hello record was removed in + TLSv1.3 draft1, but was readded in draft22. */ + if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) || + ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && + ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0))) { + ret = TLSDecodeHSHelloSessionID(ssl_state, input + parsed, input_len - parsed); + if (ret < 0) + goto end; + + parsed += ret; + } + + ret = TLSDecodeHSHelloCipherSuites(ssl_state, input + parsed, input_len - parsed); + if (ret < 0) + goto end; + + parsed += ret; + + /* The compression methods field in the server hello record was + removed in TLSv1.3 draft1, but was readded in draft22. */ + if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) || + ((ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && + ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0))) { + ret = TLSDecodeHSHelloCompressionMethods(ssl_state, input + parsed, input_len - parsed); + if (ret < 0) + goto end; + + parsed += ret; + } + + ret = TLSDecodeHSHelloExtensions(ssl_state, input + parsed, input_len - parsed); + if (ret < 0) + goto end; + + if (SC_ATOMIC_GET(ssl_config.enable_ja3) && ssl_state->curr_connp->ja3_hash == NULL) { + ssl_state->curr_connp->ja3_hash = Ja3GenerateHash(ssl_state->curr_connp->ja3_str); + } + +end: + return 0; +} + +#ifdef DEBUG_VALIDATION +static inline bool RecordAlreadyProcessed(const SSLStateConnp *curr_connp) +{ + return ((curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < curr_connp->bytes_processed); +} +#endif + +static inline int SSLv3ParseHandshakeTypeCertificate(SSLState *ssl_state, SSLStateConnp *connp, + const uint8_t *const initial_input, const uint32_t input_len) +{ + int rc = TlsDecodeHSCertificates(ssl_state, connp, initial_input, input_len); + SCLogDebug("rc %d", rc); + if (rc > 0) { + DEBUG_VALIDATE_BUG_ON(rc > (int)input_len); + SSLParserHSReset(connp); + } else if (rc < 0) { + SCLogDebug("error parsing cert, reset state"); + SSLParserHSReset(connp); + /* fall through to still consume the cert bytes */ + } + return input_len; +} + +static int SupportedHandshakeType(const uint8_t type) +{ + switch (type) { + case SSLV3_HS_CLIENT_HELLO: + case SSLV3_HS_SERVER_HELLO: + case SSLV3_HS_SERVER_KEY_EXCHANGE: + case SSLV3_HS_CLIENT_KEY_EXCHANGE: + case SSLV3_HS_CERTIFICATE: + case SSLV3_HS_HELLO_REQUEST: + case SSLV3_HS_CERTIFICATE_REQUEST: + case SSLV3_HS_CERTIFICATE_VERIFY: + case SSLV3_HS_FINISHED: + case SSLV3_HS_CERTIFICATE_URL: + case SSLV3_HS_CERTIFICATE_STATUS: + case SSLV3_HS_NEW_SESSION_TICKET: + case SSLV3_HS_SERVER_HELLO_DONE: + return true; + break; + + default: + return false; + break; + } +} + +/** + * \retval parsed number of consumed bytes + * \retval < 0 error + */ +static int SSLv3ParseHandshakeType( + SSLState *ssl_state, const uint8_t *input, uint32_t input_len, uint8_t direction) +{ + const uint8_t *initial_input = input; + int rc; + + if (input_len == 0) { + return 0; + } + DEBUG_VALIDATE_BUG_ON(RecordAlreadyProcessed(ssl_state->curr_connp)); + + switch (ssl_state->curr_connp->handshake_type) { + case SSLV3_HS_CLIENT_HELLO: + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; + + rc = TLSDecodeHandshakeHello(ssl_state, input, input_len); + if (rc < 0) + return rc; + break; + + case SSLV3_HS_SERVER_HELLO: + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; + + DEBUG_VALIDATE_BUG_ON(ssl_state->curr_connp->message_length != input_len); + rc = TLSDecodeHandshakeHello(ssl_state, input, input_len); + if (rc < 0) + return rc; + break; + + case SSLV3_HS_SERVER_KEY_EXCHANGE: + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_KEYX; + break; + + case SSLV3_HS_CLIENT_KEY_EXCHANGE: + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; + break; + + case SSLV3_HS_CERTIFICATE: + + rc = SSLv3ParseHandshakeTypeCertificate(ssl_state, + direction ? &ssl_state->server_connp : &ssl_state->client_connp, initial_input, + input_len); + if (rc < 0) + return rc; + break; + + case SSLV3_HS_HELLO_REQUEST: + break; + case SSLV3_HS_CERTIFICATE_REQUEST: + if (direction) { + ssl_state->current_flags = SSL_AL_FLAG_NEED_CLIENT_CERT; + } + break; + case SSLV3_HS_CERTIFICATE_VERIFY: + case SSLV3_HS_FINISHED: + case SSLV3_HS_CERTIFICATE_URL: + case SSLV3_HS_CERTIFICATE_STATUS: + break; + case SSLV3_HS_NEW_SESSION_TICKET: + SCLogDebug("new session ticket"); + break; + case SSLV3_HS_SERVER_HELLO_DONE: + break; + default: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + return -1; + } + + ssl_state->flags |= ssl_state->current_flags; + + SCLogDebug("message: length %u", ssl_state->curr_connp->message_length); + SCLogDebug("input_len %u ssl_state->curr_connp->bytes_processed %u", input_len, + ssl_state->curr_connp->bytes_processed); + + return input_len; +} + +static int SSLv3ParseHandshakeProtocol( + SSLState *ssl_state, const uint8_t *input, uint32_t input_len, uint8_t direction) +{ + const uint8_t *initial_input = input; + + if (input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { + SCReturnInt(0); + } + + while (input_len) { + SCLogDebug("input_len %u", input_len); + + if (ssl_state->curr_connp->hs_buffer != NULL) { + SCLogDebug("partial handshake record in place"); + const uint32_t need = ssl_state->curr_connp->hs_buffer_message_size - + ssl_state->curr_connp->hs_buffer_offset; + const uint32_t add = MIN(need, input_len); + + /* grow buffer to next multiple of 4k that fits all data we have */ + if (ssl_state->curr_connp->hs_buffer_offset + add > + ssl_state->curr_connp->hs_buffer_size) { + const uint32_t avail = ssl_state->curr_connp->hs_buffer_offset + add; + const uint32_t new_size = avail + (4096 - (avail % 4096)); + SCLogDebug("new_size %u, avail %u", new_size, avail); + void *ptr = SCRealloc(ssl_state->curr_connp->hs_buffer, new_size); + if (ptr == NULL) + return -1; + ssl_state->curr_connp->hs_buffer = ptr; + ssl_state->curr_connp->hs_buffer_size = new_size; + } + + SCLogDebug("ssl_state->curr_connp->hs_buffer_offset %u " + "ssl_state->curr_connp->hs_buffer_size %u", + ssl_state->curr_connp->hs_buffer_offset, ssl_state->curr_connp->hs_buffer_size); + SCLogDebug("to add %u total %u", add, ssl_state->curr_connp->hs_buffer_offset + add); + + if (SafeMemcpy(ssl_state->curr_connp->hs_buffer, + ssl_state->curr_connp->hs_buffer_offset, + ssl_state->curr_connp->hs_buffer_size, input, 0, add, add) != 0) { + SCLogDebug("copy failed"); + return -1; + } + ssl_state->curr_connp->hs_buffer_offset += add; + + if (ssl_state->curr_connp->hs_buffer_message_size <= + ssl_state->curr_connp->hs_buffer_offset) { + DEBUG_VALIDATE_BUG_ON(ssl_state->curr_connp->hs_buffer_message_size != + ssl_state->curr_connp->hs_buffer_offset); + + ssl_state->curr_connp->handshake_type = + ssl_state->curr_connp->hs_buffer_message_type; + ssl_state->curr_connp->message_length = + ssl_state->curr_connp->hs_buffer_message_size; + + SCLogDebug("got all data now: handshake_type %u message_length %u", + ssl_state->curr_connp->handshake_type, + ssl_state->curr_connp->message_length); + + int retval = SSLv3ParseHandshakeType(ssl_state, ssl_state->curr_connp->hs_buffer, + ssl_state->curr_connp->hs_buffer_offset, direction); + if (retval < 0) { + SSLParserHSReset(ssl_state->curr_connp); + return (retval); + } + SCLogDebug("retval %d", retval); + + /* data processed, reset buffer */ + SCFree(ssl_state->curr_connp->hs_buffer); + ssl_state->curr_connp->hs_buffer = NULL; + ssl_state->curr_connp->hs_buffer_size = 0; + ssl_state->curr_connp->hs_buffer_message_size = 0; + ssl_state->curr_connp->hs_buffer_message_type = 0; + ssl_state->curr_connp->hs_buffer_offset = 0; + } else { + SCLogDebug("partial data"); + } + + input += add; + input_len -= add; + SCLogDebug("input_len %u", input_len); + SSLParserHSReset(ssl_state->curr_connp); + continue; + } + + SCLogDebug("bytes_processed %u", ssl_state->curr_connp->bytes_processed); + SCLogDebug("input %p input_len %u", input, input_len); + + if (input_len < 4) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SCReturnInt(-1); + } + + ssl_state->curr_connp->handshake_type = input[0]; + ssl_state->curr_connp->message_length = input[1] << 16 | input[2] << 8 | input[3]; + SCLogDebug("handshake_type %u message len %u input %p input_len %u", + ssl_state->curr_connp->handshake_type, ssl_state->curr_connp->message_length, input, + input_len); + input += 4; + input_len -= 4; + + const uint32_t record_len = ssl_state->curr_connp->message_length; + /* see if we support this type. We check here to not use the fragment + * handling on things we don't support. */ + const bool supported_type = SupportedHandshakeType(ssl_state->curr_connp->handshake_type); + SCLogDebug("supported_type %s handshake_type %u/%02x", supported_type ? "true" : "false", + ssl_state->curr_connp->handshake_type, ssl_state->curr_connp->handshake_type); + if (!supported_type) { + uint32_t avail_record_len = MIN(input_len, record_len); + input += avail_record_len; + input_len -= avail_record_len; + + SSLParserHSReset(ssl_state->curr_connp); + + if ((direction && (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) || + (!direction && (ssl_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC))) { + // after Change Cipher Spec we get Encrypted Handshake Messages + } else { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); + } + continue; + } + + /* if the message length exceeds our input_len, we have a tls fragment. */ + if (record_len > input_len) { + const uint32_t avail = input_len; + const uint32_t size = avail + (4096 - (avail % 4096)); + SCLogDebug("initial buffer size %u, based on input %u", size, avail); + ssl_state->curr_connp->hs_buffer = SCCalloc(1, size); + if (ssl_state->curr_connp->hs_buffer == NULL) { + return -1; + } + ssl_state->curr_connp->hs_buffer_size = size; + ssl_state->curr_connp->hs_buffer_message_size = record_len; + ssl_state->curr_connp->hs_buffer_message_type = ssl_state->curr_connp->handshake_type; + + if (input_len > 0) { + if (SafeMemcpy(ssl_state->curr_connp->hs_buffer, 0, + ssl_state->curr_connp->hs_buffer_size, input, 0, input_len, + input_len) != 0) { + return -1; + } + ssl_state->curr_connp->hs_buffer_offset = input_len; + } + SCLogDebug("opened record buffer %p size %u offset %u type %u msg_size %u", + ssl_state->curr_connp->hs_buffer, ssl_state->curr_connp->hs_buffer_size, + ssl_state->curr_connp->hs_buffer_offset, + ssl_state->curr_connp->hs_buffer_message_type, + ssl_state->curr_connp->hs_buffer_message_size); + input += input_len; + SSLParserHSReset(ssl_state->curr_connp); + return (input - initial_input); + + } else { + /* full record, parse it now */ + int retval = SSLv3ParseHandshakeType( + ssl_state, input, ssl_state->curr_connp->message_length, direction); + if (retval < 0 || retval > (int)input_len) { + DEBUG_VALIDATE_BUG_ON(retval > (int)input_len); + return (retval); + } + SCLogDebug("retval %d input_len %u", retval, input_len); + input += retval; + input_len -= retval; + + SSLParserHSReset(ssl_state->curr_connp); + } + SCLogDebug("input_len left %u", input_len); + } + return (input - initial_input); +} + +/** + * \internal + * \brief TLS Heartbeat parser (see RFC 6520) + * + * \param sslstate Pointer to the SSL state. + * \param input Pointer to the received input data. + * \param input_len Length in bytes of the received data. + * \param direction 1 toclient, 0 toserver + * + * \retval The number of bytes parsed on success, 0 if nothing parsed, -1 on failure. + */ +static int SSLv3ParseHeartbeatProtocol( + SSLState *ssl_state, const uint8_t *input, uint32_t input_len, uint8_t direction) +{ + uint8_t hb_type; + uint16_t payload_len; + uint32_t padding_len; + + /* expect at least 3 bytes: heartbeat type (1) + length (2) */ + if (input_len < 3) { + return 0; + } + + hb_type = *input++; + + if (!(ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { + if (!(hb_type == TLS_HB_REQUEST || hb_type == TLS_HB_RESPONSE)) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + return -1; + } + } + + if ((ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) == 0) { + ssl_state->flags |= SSL_AL_FLAG_HB_INFLIGHT; + + if (direction) { + SCLogDebug("HeartBeat Record type sent in the toclient direction!"); + ssl_state->flags |= SSL_AL_FLAG_HB_SERVER_INIT; + } else { + SCLogDebug("HeartBeat Record type sent in the toserver direction!"); + ssl_state->flags |= SSL_AL_FLAG_HB_CLIENT_INIT; + } + + /* if we reach this point, then we can assume that the HB request + is encrypted. If so, let's set the HB record length */ + if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { + ssl_state->hb_record_len = ssl_state->curr_connp->record_length; + SCLogDebug("Encrypted HeartBeat Request In-flight. Storing len %u", + ssl_state->hb_record_len); + return (ssl_state->curr_connp->record_length - 3); + } + + payload_len = (uint16_t)(*input << 8) | *(input + 1); + + /* check that the requested payload length is really present in + the record (CVE-2014-0160) */ + if ((uint32_t)(payload_len + 3) > ssl_state->curr_connp->record_length) { + SCLogDebug("We have a short record in HeartBeat Request"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); + return -1; + } + + /* check the padding length. It must be at least 16 bytes + (RFC 6520, section 4) */ + padding_len = ssl_state->curr_connp->record_length - payload_len - 3; + if (padding_len < 16) { + SCLogDebug("We have a short record in HeartBeat Request"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + return -1; + } + + /* we don't have the payload */ + if (input_len < payload_len + padding_len) { + return 0; + } + + /* OpenSSL still seems to discard multiple in-flight + heartbeats although some tools send multiple at once */ + } else if (direction == 1 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && + (ssl_state->flags & SSL_AL_FLAG_HB_SERVER_INIT)) { + SCLogDebug("Multiple in-flight server initiated HeartBeats"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + return -1; + + } else if (direction == 0 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && + (ssl_state->flags & SSL_AL_FLAG_HB_CLIENT_INIT)) { + SCLogDebug("Multiple in-flight client initiated HeartBeats"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + return -1; + + } else { + /* we have a HB record in the opposite direction of the request, + let's reset our flags */ + ssl_state->flags &= ~SSL_AL_FLAG_HB_INFLIGHT; + ssl_state->flags &= ~SSL_AL_FLAG_HB_SERVER_INIT; + ssl_state->flags &= ~SSL_AL_FLAG_HB_CLIENT_INIT; + + /* if we reach this point, then we can assume that the HB request + is encrypted. If so, let's set the HB record length */ + if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { + /* check to see if the encrypted response is longer than the + encrypted request */ + if (ssl_state->hb_record_len > 0 && + ssl_state->hb_record_len < ssl_state->curr_connp->record_length) { + SCLogDebug("My heart is bleeding.. OpenSSL HeartBleed response (%u)", + ssl_state->hb_record_len); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH); + ssl_state->hb_record_len = 0; + return -1; + } + } + + /* reset the HB record length in case we have a legit HB followed + by a bad one */ + ssl_state->hb_record_len = 0; + } + + /* skip the HeartBeat, 3 bytes were already parsed, + e.g |18 03 02| for TLS 1.2 */ + return (ssl_state->curr_connp->record_length - 3); +} + +static int SSLv3ParseRecord( + uint8_t direction, SSLState *ssl_state, const uint8_t *input, uint32_t input_len) +{ + const uint8_t *initial_input = input; + + if (input_len == 0) { + return 0; + } + + uint8_t skip_version = 0; + + /* Only set SSL/TLS version here if it has not already been set in + client/server hello. */ + if (direction == 0) { + if ((ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && + (ssl_state->client_connp.version != TLS_VERSION_UNKNOWN)) { + skip_version = 1; + } + } else { + if ((ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && + (ssl_state->server_connp.version != TLS_VERSION_UNKNOWN)) { + skip_version = 1; + } + } + + switch (ssl_state->curr_connp->bytes_processed) { + case 0: + if (input_len >= 5) { + ssl_state->curr_connp->content_type = input[0]; + if (!skip_version) { + ssl_state->curr_connp->version = (uint16_t)(input[1] << 8) | input[2]; + } + ssl_state->curr_connp->record_length = input[3] << 8; + ssl_state->curr_connp->record_length |= input[4]; + ssl_state->curr_connp->bytes_processed += SSLV3_RECORD_HDR_LEN; + return SSLV3_RECORD_HDR_LEN; + } else { + ssl_state->curr_connp->content_type = *(input++); + if (--input_len == 0) + break; + } + + /* fall through */ + case 1: + if (!skip_version) { + ssl_state->curr_connp->version = (uint16_t)(*(input++) << 8); + } else { + input++; + } + if (--input_len == 0) + break; + + /* fall through */ + case 2: + if (!skip_version) { + ssl_state->curr_connp->version |= *(input++); + } else { + input++; + } + if (--input_len == 0) + break; + + /* fall through */ + case 3: + ssl_state->curr_connp->record_length = *(input++) << 8; + if (--input_len == 0) + break; + + /* fall through */ + case 4: + ssl_state->curr_connp->record_length |= *(input++); + if (--input_len == 0) + break; + + /* fall through */ + } + + ssl_state->curr_connp->bytes_processed += (input - initial_input); + + return (input - initial_input); +} + +static int SSLv2ParseRecord( + uint8_t direction, SSLState *ssl_state, const uint8_t *input, uint32_t input_len) +{ + const uint8_t *initial_input = input; + + if (input_len == 0) { + return 0; + } + + if (ssl_state->curr_connp->record_lengths_length == 2) { + switch (ssl_state->curr_connp->bytes_processed) { + case 0: + if (input_len >= ssl_state->curr_connp->record_lengths_length + 1) { + ssl_state->curr_connp->record_length = (0x7f & input[0]) << 8 | input[1]; + ssl_state->curr_connp->content_type = input[2]; + ssl_state->curr_connp->version = SSL_VERSION_2; + ssl_state->curr_connp->bytes_processed += 3; + return 3; + } else { + ssl_state->curr_connp->record_length = (0x7f & *(input++)) << 8; + if (--input_len == 0) + break; + } + + /* fall through */ + case 1: + ssl_state->curr_connp->record_length |= *(input++); + if (--input_len == 0) + break; + + /* fall through */ + case 2: + ssl_state->curr_connp->content_type = *(input++); + ssl_state->curr_connp->version = SSL_VERSION_2; + if (--input_len == 0) + break; + + /* fall through */ + } + + } else { + switch (ssl_state->curr_connp->bytes_processed) { + case 0: + if (input_len >= ssl_state->curr_connp->record_lengths_length + 1) { + ssl_state->curr_connp->record_length = (0x3f & input[0]) << 8 | input[1]; + ssl_state->curr_connp->content_type = input[3]; + ssl_state->curr_connp->version = SSL_VERSION_2; + ssl_state->curr_connp->bytes_processed += 4; + return 4; + } else { + ssl_state->curr_connp->record_length = (0x3f & *(input++)) << 8; + if (--input_len == 0) + break; + } + + /* fall through */ + case 1: + ssl_state->curr_connp->record_length |= *(input++); + if (--input_len == 0) + break; + + /* fall through */ + case 2: + /* padding */ + input++; + if (--input_len == 0) + break; + + /* fall through */ + case 3: + ssl_state->curr_connp->content_type = *(input++); + ssl_state->curr_connp->version = SSL_VERSION_2; + if (--input_len == 0) + break; + + /* fall through */ + } + } + + ssl_state->curr_connp->bytes_processed += (input - initial_input); + + return (input - initial_input); +} + +static struct SSLDecoderResult SSLv2Decode(uint8_t direction, SSLState *ssl_state, + AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len, + const StreamSlice stream_slice) +{ + const uint8_t *initial_input = input; + + if (ssl_state->curr_connp->bytes_processed == 0) { + if (input[0] & 0x80) { + ssl_state->curr_connp->record_lengths_length = 2; + } else { + ssl_state->curr_connp->record_lengths_length = 3; + } + + SCLogDebug("record start: ssl2.hdr frame"); + AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, + ssl_state->curr_connp->record_lengths_length + 1, direction, TLS_FRAME_SSLV2_HDR); + } + + SCLogDebug("direction %u ssl_state->curr_connp->record_lengths_length + 1 %u, " + "ssl_state->curr_connp->bytes_processed %u", + direction, ssl_state->curr_connp->record_lengths_length + 1, + ssl_state->curr_connp->bytes_processed); + /* the +1 is because we read one extra byte inside SSLv2ParseRecord + to read the msg_type */ + if (ssl_state->curr_connp->bytes_processed < + (ssl_state->curr_connp->record_lengths_length + 1)) { + const int retval = SSLv2ParseRecord(direction, ssl_state, input, input_len); + SCLogDebug("retval %d ssl_state->curr_connp->record_length %u", retval, + ssl_state->curr_connp->record_length); + if (retval < 0 || retval > (int)input_len) { + DEBUG_VALIDATE_BUG_ON(retval > (int)input_len); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + return SSL_DECODER_ERROR(-1); + } + + AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, + ssl_state->curr_connp->record_lengths_length + ssl_state->curr_connp->record_length, + direction, TLS_FRAME_SSLV2_PDU); + SCLogDebug("record start: ssl2.pdu frame"); + + input += retval; + input_len -= retval; + } + + /* if we don't have the full record, we return incomplete */ + if (ssl_state->curr_connp->record_lengths_length + ssl_state->curr_connp->record_length > + input_len + ssl_state->curr_connp->bytes_processed) { + uint32_t needed = ssl_state->curr_connp->record_length; + SCLogDebug("record len %u input_len %u parsed %u: need %u bytes more data", + ssl_state->curr_connp->record_length, input_len, (uint32_t)(input - initial_input), + needed); + return SSL_DECODER_INCOMPLETE((input - initial_input), needed); + } + + if (input_len == 0) { + return SSL_DECODER_OK((input - initial_input)); + } + + /* record_length should never be zero */ + if (ssl_state->curr_connp->record_length == 0) { + SCLogDebug("SSLv2 record length is zero"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + return SSL_DECODER_ERROR(-1); + } + + /* record_lengths_length should never be zero */ + if (ssl_state->curr_connp->record_lengths_length == 0) { + SCLogDebug("SSLv2 record lengths length is zero"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + return SSL_DECODER_ERROR(-1); + } + + switch (ssl_state->curr_connp->content_type) { + case SSLV2_MT_ERROR: + SCLogDebug("SSLV2_MT_ERROR msg_type received. Error encountered " + "in establishing the sslv2 session, may be version"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); + + break; + + case SSLV2_MT_CLIENT_HELLO: + if (input_len < 6) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + return SSL_DECODER_ERROR(-1); + } + + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_HS; + + const uint16_t version = (uint16_t)(input[0] << 8) | input[1]; + SCLogDebug("SSLv2: version %04x", version); + ssl_state->curr_connp->version = version; + uint16_t session_id_length = (input[5]) | (uint16_t)(input[4] << 8); + input += 6; + input_len -= 6; + ssl_state->curr_connp->bytes_processed += 6; + if (session_id_length == 0) { + ssl_state->current_flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; + } + break; + + case SSLV2_MT_CLIENT_MASTER_KEY: + if (!(ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS)) { + SCLogDebug("Client hello is not seen before master key " + "message!"); + } + ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; + + break; + + case SSLV2_MT_CLIENT_CERTIFICATE: + if (direction == 1) { + SCLogDebug("Incorrect SSL Record type sent in the toclient " + "direction!"); + } else { + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; + } + + /* fall through */ + case SSLV2_MT_SERVER_VERIFY: + case SSLV2_MT_SERVER_FINISHED: + if (direction == 0 && + !(ssl_state->curr_connp->content_type & SSLV2_MT_CLIENT_CERTIFICATE)) { + SCLogDebug("Incorrect SSL Record type sent in the toserver " + "direction!"); + } + + /* fall through */ + case SSLV2_MT_CLIENT_FINISHED: + case SSLV2_MT_REQUEST_CERTIFICATE: + /* both client hello and server hello must be seen */ + if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) && + (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_HS)) { + + if (direction == 0) { + if (ssl_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) { + ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; + SCLogDebug("SSLv2 client side has started the encryption"); + } else if (ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY) { + ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; + SCLogDebug("SSLv2 client side has started the encryption"); + } + } else { + ssl_state->current_flags = SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED; + SCLogDebug("SSLv2 Server side has started the encryption"); + } + + if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED) && + (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { + if (ssl_config.encrypt_mode != SSL_CNF_ENC_HANDLE_FULL) { + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION); + } + + if (ssl_config.encrypt_mode == SSL_CNF_ENC_HANDLE_BYPASS) { + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_BYPASS_READY); + } + SCLogDebug("SSLv2 No reassembly & inspection has been set"); + } + } + + break; + + case SSLV2_MT_SERVER_HELLO: + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_SERVER_HS; + + break; + } + + ssl_state->flags |= ssl_state->current_flags; + + if (input_len + ssl_state->curr_connp->bytes_processed >= + (ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length)) { + + /* looks like we have another record after this */ + uint32_t diff = ssl_state->curr_connp->record_length + + ssl_state->curr_connp->record_lengths_length + + -ssl_state->curr_connp->bytes_processed; + input += diff; + SSLParserReset(ssl_state); + + /* we still don't have the entire record for the one we are + currently parsing */ + } else { + input += input_len; + ssl_state->curr_connp->bytes_processed += input_len; + } + return SSL_DECODER_OK((input - initial_input)); +} + +static struct SSLDecoderResult SSLv3Decode(uint8_t direction, SSLState *ssl_state, + AppLayerParserState *pstate, const uint8_t *input, const uint32_t input_len, + const StreamSlice stream_slice) +{ + uint32_t parsed = 0; + uint32_t record_len; /* slice of input_len for the current record */ + const bool first_call = (ssl_state->curr_connp->bytes_processed == 0); + + if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { + const uint16_t prev_version = ssl_state->curr_connp->version; + + int retval = SSLv3ParseRecord(direction, ssl_state, input, input_len); + if (retval < 0 || retval > (int)input_len) { + DEBUG_VALIDATE_BUG_ON(retval > (int)input_len); + SCLogDebug("SSLv3ParseRecord returned %d", retval); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_TLS_HEADER); + return SSL_DECODER_ERROR(-1); + } + parsed = retval; + + SCLogDebug("%s input %p record_length %u", (direction == 0) ? "toserver" : "toclient", + input, ssl_state->curr_connp->record_length); + + /* first the hdr frame at our first chance */ + if (first_call) { + AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, SSLV3_RECORD_HDR_LEN, + direction, TLS_FRAME_HDR); + } + + /* parser is streaming for the initial header, then switches to incomplete + * API: so if we don't have the hdr yet, return consumed bytes and wait + * until we are called again with new data. */ + if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { + SCLogDebug( + "incomplete header, return %u bytes consumed and wait for more data", parsed); + return SSL_DECODER_OK(parsed); + } + + /* pdu frame needs record length, so only create it when hdr fully parsed. */ + AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input, + ssl_state->curr_connp->record_length + retval, direction, TLS_FRAME_PDU); + record_len = MIN(input_len - parsed, ssl_state->curr_connp->record_length); + SCLogDebug( + "record_len %u (input_len %u, parsed %u, ssl_state->curr_connp->record_length %u)", + record_len, input_len, parsed, ssl_state->curr_connp->record_length); + + bool unknown_record = false; + switch (ssl_state->curr_connp->content_type) { + case SSLV3_CHANGE_CIPHER_SPEC: + case SSLV3_ALERT_PROTOCOL: + case SSLV3_HANDSHAKE_PROTOCOL: + case SSLV3_APPLICATION_PROTOCOL: + case SSLV3_HEARTBEAT_PROTOCOL: + break; + default: + unknown_record = true; + break; + } + + /* unknown record type. For TLS 1.0, 1.1 and 1.2 this is ok. For the rest it is fatal. Based + * on Wireshark logic. */ + if (prev_version == TLS_VERSION_10 || prev_version == TLS_VERSION_11) { + if (unknown_record) { + SCLogDebug("unknown record, ignore it"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); + + ssl_state->curr_connp->bytes_processed = 0; // TODO review this reset logic + ssl_state->curr_connp->content_type = 0; + ssl_state->curr_connp->record_length = 0; + // restore last good version + ssl_state->curr_connp->version = prev_version; + return SSL_DECODER_OK(input_len); // consume everything + } + } else { + if (unknown_record) { + SCLogDebug("unknown record, fatal"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); + return SSL_DECODER_ERROR(-1); + } + } + + /* record_length should never be zero */ + if (ssl_state->curr_connp->record_length == 0) { + SCLogDebug("SSLv3 Record length is 0"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_LENGTH); + return SSL_DECODER_ERROR(-1); + } + + if (!TLSVersionValid(ssl_state->curr_connp->version)) { + SCLogDebug("ssl_state->curr_connp->version %04x", ssl_state->curr_connp->version); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_VERSION); + return SSL_DECODER_ERROR(-1); + } + + if (ssl_state->curr_connp->bytes_processed == SSLV3_RECORD_HDR_LEN && + ssl_state->curr_connp->record_length > SSLV3_RECORD_MAX_LEN) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_LENGTH); + return SSL_DECODER_ERROR(-1); + } + DEBUG_VALIDATE_BUG_ON(ssl_state->curr_connp->bytes_processed > SSLV3_RECORD_HDR_LEN); + } else { + ValidateRecordState(ssl_state->curr_connp); + + record_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) - + ssl_state->curr_connp->bytes_processed; + record_len = MIN(input_len, record_len); + } + SCLogDebug("record length %u processed %u got %u", ssl_state->curr_connp->record_length, + ssl_state->curr_connp->bytes_processed, record_len); + + /* if we don't have the full record, we return incomplete */ + if (ssl_state->curr_connp->record_length > input_len - parsed) { + /* no need to use incomplete api buffering for application + * records that we'll not use anyway. */ + if (ssl_state->curr_connp->content_type == SSLV3_APPLICATION_PROTOCOL) { + SCLogDebug("application record"); + } else { + uint32_t needed = ssl_state->curr_connp->record_length; + SCLogDebug("record len %u input_len %u parsed %u: need %u bytes more data", + ssl_state->curr_connp->record_length, input_len, parsed, needed); + DEBUG_VALIDATE_BUG_ON(needed > SSLV3_RECORD_MAX_LEN); + return SSL_DECODER_INCOMPLETE(parsed, needed); + } + } + + if (record_len == 0) { + return SSL_DECODER_OK(parsed); + } + + AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input + parsed, + ssl_state->curr_connp->record_length, direction, TLS_FRAME_DATA); + + switch (ssl_state->curr_connp->content_type) { + /* we don't need any data from these types */ + case SSLV3_CHANGE_CIPHER_SPEC: + ssl_state->flags |= SSL_AL_FLAG_CHANGE_CIPHER_SPEC; + + if (direction) { + ssl_state->flags |= SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC; + } else { + ssl_state->flags |= SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC; + } + break; + + case SSLV3_ALERT_PROTOCOL: + AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input + parsed, + ssl_state->curr_connp->record_length, direction, TLS_FRAME_ALERT_DATA); + break; + + case SSLV3_APPLICATION_PROTOCOL: + /* In TLSv1.3 early data (0-RTT) could be sent before the + handshake is complete (rfc8446, section 2.3). We should + therefore not mark the handshake as done before we have + seen the ServerHello record. */ + if ((ssl_state->flags & SSL_AL_FLAG_EARLY_DATA) && + ((ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0)) + break; + + /* if we see (encrypted) application data, then this means the + handshake must be done */ + ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + + if (ssl_config.encrypt_mode != SSL_CNF_ENC_HANDLE_FULL) { + SCLogDebug("setting APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD"); + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD); + } + + /* Encrypted data, reassembly not asked, bypass asked, let's sacrifice + * heartbeat lke inspection to be able to be able to bypass the flow */ + if (ssl_config.encrypt_mode == SSL_CNF_ENC_HANDLE_BYPASS) { + SCLogDebug("setting APP_LAYER_PARSER_NO_REASSEMBLY"); + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION); + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_BYPASS_READY); + } + break; + + case SSLV3_HANDSHAKE_PROTOCOL: { + if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { + /* In TLSv1.3, ChangeCipherSpec is only used for middlebox + compatibility (rfc8446, appendix D.4). */ + // Client hello flags is needed to have a valid version + if ((ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && + (ssl_state->client_connp.version > TLS_VERSION_12) && + ((ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0)) { + /* do nothing */ + } else { + // if we started parsing this, we must stop + break; + } + } + + if (ssl_state->curr_connp->record_length < 4) { + SSLParserReset(ssl_state); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SCLogDebug("record len < 4 => %u", ssl_state->curr_connp->record_length); + return SSL_DECODER_ERROR(-1); + } + + int retval = + SSLv3ParseHandshakeProtocol(ssl_state, input + parsed, record_len, direction); + SCLogDebug("retval %d", retval); + if (retval < 0 || retval > (int)record_len) { + DEBUG_VALIDATE_BUG_ON(retval > (int)record_len); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); + SCLogDebug("SSLv3ParseHandshakeProtocol returned %d", retval); + return SSL_DECODER_ERROR(-1); + } + ValidateRecordState(ssl_state->curr_connp); + break; + } + case SSLV3_HEARTBEAT_PROTOCOL: { + AppLayerFrameNewByPointer(ssl_state->f, &stream_slice, input + parsed, + ssl_state->curr_connp->record_length, direction, TLS_FRAME_HB_DATA); + int retval = + SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, record_len, direction); + if (retval < 0) { + SCLogDebug("SSLv3ParseHeartbeatProtocol returned %d", retval); + return SSL_DECODER_ERROR(-1); + } + break; + } + default: + // should be unreachable now that we check after header parsing + DEBUG_VALIDATE_BUG_ON(1); + SCLogDebug("unsupported record type"); + return SSL_DECODER_ERROR(-1); + } + + parsed += record_len; + ssl_state->curr_connp->bytes_processed += record_len; + + if (ssl_state->curr_connp->bytes_processed >= + ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { + SCLogDebug("record complete, trigger RAW"); + AppLayerParserTriggerRawStreamReassembly( + ssl_state->f, direction == 0 ? STREAM_TOSERVER : STREAM_TOCLIENT); + SSLParserReset(ssl_state); + ValidateRecordState(ssl_state->curr_connp); + return SSL_DECODER_OK(parsed); + + } else { + /* we still don't have the entire record for the one we are + currently parsing */ + ValidateRecordState(ssl_state->curr_connp); + return SSL_DECODER_OK(parsed); + } +} + +/** + * \internal + * \brief SSLv2, SSLv23, SSLv3, TLSv1.1, TLSv1.2, TLSv1.3 parser. + * + * On parsing error, this should be the only function that should reset + * the parser state, to avoid multiple functions in the chain resetting + * the parser state. + * + * \param direction 0 for toserver, 1 for toclient. + * \param alstate Pointer to the state. + * \param pstate Application layer parser state for this session. + * \param output Pointer to the list of parsed output elements. + * + * \todo On reaching an inconsistent state, check if the input has + * another new record, instead of just returning after the reset + * + * \retval >=0 On success. + */ +static AppLayerResult SSLDecode(Flow *f, uint8_t direction, void *alstate, + AppLayerParserState *pstate, StreamSlice stream_slice) +{ + SSLState *ssl_state = (SSLState *)alstate; + uint32_t counter = 0; + ssl_state->f = f; + const uint8_t *input = StreamSliceGetData(&stream_slice); + const uint8_t *init_input = input; + int32_t input_len = (int32_t)StreamSliceGetDataLen(&stream_slice); + + if (input == NULL && + ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) || + (direction == 1 && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) { + /* flag session as finished if APP_LAYER_PARSER_EOF is set */ + ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; + SCReturnStruct(APP_LAYER_OK); + } else if (input == NULL || input_len == 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + + if (direction == 0) + ssl_state->curr_connp = &ssl_state->client_connp; + else + ssl_state->curr_connp = &ssl_state->server_connp; + + /* If entering on a new record, reset the current flags. */ + if (ssl_state->curr_connp->bytes_processed == 0) { + ssl_state->current_flags = 0; + } + + /* if we have more than one record */ + uint32_t max_records = MAX((input_len / SSL_RECORD_MINIMUM_LENGTH), 1); + while (input_len > 0) { + if (counter > max_records) { + SCLogDebug("Looks like we have looped quite a bit. Reset state " + "and get out of here"); + SSLParserReset(ssl_state); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET); + return APP_LAYER_ERROR; + } + + /* ssl_state->bytes_processed is zero for a fresh record or + positive to indicate a record currently being parsed */ + + if (ssl_state->curr_connp->bytes_processed == 0) { + if ((input[0] & 0x80) || (input[0] & 0x40)) { + /* only SSLv2, has one of the top 2 bits set */ + ssl_state->curr_connp->version = SSL_VERSION_2; + SCLogDebug("SSLv2 detected"); + } else if (ssl_state->curr_connp->version == SSL_VERSION_2) { + ssl_state->curr_connp->version = TLS_VERSION_UNKNOWN; + SCLogDebug("SSL/TLS version reset"); + } + } + SCLogDebug("record %u: bytes_processed %u, version %02X, input_len %u", counter, + ssl_state->curr_connp->bytes_processed, ssl_state->curr_connp->version, input_len); + + if (ssl_state->curr_connp->version == SSL_VERSION_2) { + if (ssl_state->curr_connp->bytes_processed == 0) { + SCLogDebug("New SSLv2 record parsing"); + } else { + SCLogDebug("Continuing parsing SSLv2 record"); + } + struct SSLDecoderResult r = + SSLv2Decode(direction, ssl_state, pstate, input, input_len, stream_slice); + if (r.retval < 0 || r.retval > input_len) { + DEBUG_VALIDATE_BUG_ON(r.retval > input_len); + SCLogDebug("Error parsing SSLv2. Resetting parser " + "state. Let's get outta here"); + SSLParserReset(ssl_state); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + return APP_LAYER_ERROR; + } else if (r.needed) { + input += r.retval; + SCLogDebug("returning consumed %" PRIuMAX " needed %u", + (uintmax_t)(input - init_input), r.needed); + SCReturnStruct(APP_LAYER_INCOMPLETE(input - init_input, r.needed)); + } + input_len -= r.retval; + input += r.retval; + SCLogDebug("SSLv2 decoder consumed %d bytes: %u left", r.retval, input_len); + } else { + if (ssl_state->curr_connp->bytes_processed == 0) { + SCLogDebug( + "New TLS record: record_length %u", ssl_state->curr_connp->record_length); + } else { + SCLogDebug("Continuing parsing TLS record: record_length %u, bytes_processed %u", + ssl_state->curr_connp->record_length, + ssl_state->curr_connp->bytes_processed); + } + struct SSLDecoderResult r = + SSLv3Decode(direction, ssl_state, pstate, input, input_len, stream_slice); + if (r.retval < 0 || r.retval > input_len) { + DEBUG_VALIDATE_BUG_ON(r.retval > input_len); + SCLogDebug("Error parsing TLS. Resetting parser " + "state. Let's get outta here"); + SSLParserReset(ssl_state); + return APP_LAYER_ERROR; + } else if (r.needed) { + input += r.retval; + SCLogDebug("returning consumed %" PRIuMAX " needed %u", + (uintmax_t)(input - init_input), r.needed); + SCReturnStruct(APP_LAYER_INCOMPLETE(input - init_input, r.needed)); + } + input_len -= r.retval; + input += r.retval; + SCLogDebug("TLS decoder consumed %d bytes: %u left", r.retval, input_len); + + if (ssl_state->curr_connp->bytes_processed == SSLV3_RECORD_HDR_LEN && + ssl_state->curr_connp->record_length == 0) { + SCLogDebug("TLS empty record"); + /* empty record */ + SSLParserReset(ssl_state); + } + } + counter++; + } /* while (input_len) */ + + /* mark handshake as done if we have subject and issuer */ + if ((ssl_state->flags & SSL_AL_FLAG_NEED_CLIENT_CERT) && + ssl_state->client_connp.cert0_subject && ssl_state->client_connp.cert0_issuerdn) { + SCLogDebug("SSL_AL_FLAG_HANDSHAKE_DONE"); + ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + } else if ((ssl_state->flags & SSL_AL_FLAG_NEED_CLIENT_CERT) == 0 && + ssl_state->server_connp.cert0_subject && ssl_state->server_connp.cert0_issuerdn) { + SCLogDebug("SSL_AL_FLAG_HANDSHAKE_DONE"); + ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + } + + /* flag session as finished if APP_LAYER_PARSER_EOF is set */ + if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)) { + SCLogDebug("SSL_AL_FLAG_STATE_FINISHED"); + ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; + } + + return APP_LAYER_OK; +} + +static AppLayerResult SSLParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + return SSLDecode(f, 0 /* toserver */, alstate, pstate, stream_slice); +} + +static AppLayerResult SSLParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + return SSLDecode(f, 1 /* toclient */, alstate, pstate, stream_slice); +} + +/** + * \internal + * \brief Function to allocate the SSL state memory. + */ +static void *SSLStateAlloc(void *orig_state, AppProto proto_orig) +{ + SSLState *ssl_state = SCCalloc(1, sizeof(SSLState)); + if (unlikely(ssl_state == NULL)) + return NULL; + ssl_state->client_connp.cert_log_flag = 0; + ssl_state->server_connp.cert_log_flag = 0; + memset(ssl_state->client_connp.random, 0, TLS_RANDOM_LEN); + memset(ssl_state->server_connp.random, 0, TLS_RANDOM_LEN); + TAILQ_INIT(&ssl_state->server_connp.certs); + TAILQ_INIT(&ssl_state->client_connp.certs); + + return (void *)ssl_state; +} + +/** + * \internal + * \brief Function to free the SSL state memory. + */ +static void SSLStateFree(void *p) +{ + SSLState *ssl_state = (SSLState *)p; + SSLCertsChain *item; + + if (ssl_state->client_connp.cert0_subject) + rs_cstring_free(ssl_state->client_connp.cert0_subject); + if (ssl_state->client_connp.cert0_issuerdn) + rs_cstring_free(ssl_state->client_connp.cert0_issuerdn); + if (ssl_state->client_connp.cert0_serial) + rs_cstring_free(ssl_state->client_connp.cert0_serial); + if (ssl_state->client_connp.cert0_fingerprint) + SCFree(ssl_state->client_connp.cert0_fingerprint); + if (ssl_state->client_connp.sni) + SCFree(ssl_state->client_connp.sni); + if (ssl_state->client_connp.session_id) + SCFree(ssl_state->client_connp.session_id); + if (ssl_state->client_connp.hs_buffer) + SCFree(ssl_state->client_connp.hs_buffer); + + if (ssl_state->server_connp.cert0_subject) + rs_cstring_free(ssl_state->server_connp.cert0_subject); + if (ssl_state->server_connp.cert0_issuerdn) + rs_cstring_free(ssl_state->server_connp.cert0_issuerdn); + if (ssl_state->server_connp.cert0_serial) + rs_cstring_free(ssl_state->server_connp.cert0_serial); + if (ssl_state->server_connp.cert0_fingerprint) + SCFree(ssl_state->server_connp.cert0_fingerprint); + if (ssl_state->server_connp.sni) + SCFree(ssl_state->server_connp.sni); + if (ssl_state->server_connp.session_id) + SCFree(ssl_state->server_connp.session_id); + + if (ssl_state->client_connp.ja3_str) + Ja3BufferFree(&ssl_state->client_connp.ja3_str); + if (ssl_state->client_connp.ja3_hash) + SCFree(ssl_state->client_connp.ja3_hash); + if (ssl_state->server_connp.ja3_str) + Ja3BufferFree(&ssl_state->server_connp.ja3_str); + if (ssl_state->server_connp.ja3_hash) + SCFree(ssl_state->server_connp.ja3_hash); + if (ssl_state->server_connp.hs_buffer) + SCFree(ssl_state->server_connp.hs_buffer); + + AppLayerDecoderEventsFreeEvents(&ssl_state->tx_data.events); + + if (ssl_state->tx_data.de_state != NULL) { + DetectEngineStateFree(ssl_state->tx_data.de_state); + } + + /* Free certificate chain */ + if (ssl_state->server_connp.certs_buffer) + SCFree(ssl_state->server_connp.certs_buffer); + while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) { + TAILQ_REMOVE(&ssl_state->server_connp.certs, item, next); + SCFree(item); + } + TAILQ_INIT(&ssl_state->server_connp.certs); + /* Free certificate chain */ + if (ssl_state->client_connp.certs_buffer) + SCFree(ssl_state->client_connp.certs_buffer); + while ((item = TAILQ_FIRST(&ssl_state->client_connp.certs))) { + TAILQ_REMOVE(&ssl_state->client_connp.certs, item, next); + SCFree(item); + } + TAILQ_INIT(&ssl_state->client_connp.certs); + + SCFree(ssl_state); + + return; +} + +static void SSLStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static AppProto SSLProbingParser( + Flow *f, uint8_t direction, const uint8_t *input, uint32_t ilen, uint8_t *rdir) +{ + /* probably a rst/fin sending an eof */ + if (ilen < 3) + return ALPROTO_UNKNOWN; + + /* for now just the 3 byte header ones */ + /* \todo Detect the 2 byte ones */ + if ((input[0] & 0x80) && (input[2] == 0x01)) { + return ALPROTO_TLS; + } + + return ALPROTO_FAILED; +} + +static int SSLStateGetFrameIdByName(const char *frame_name) +{ + int id = SCMapEnumNameToValue(frame_name, tls_frame_table); + if (id < 0) { + return -1; + } + return id; +} + +static const char *SSLStateGetFrameNameById(const uint8_t frame_id) +{ + const char *name = SCMapEnumValueToName(frame_id, tls_frame_table); + return name; +} + +static int SSLStateGetEventInfo( + const char *event_name, int *event_id, AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, tls_decoder_event_table); + if (*event_id == -1) { + SCLogError("event \"%s\" not present in " + "ssl's enum map table.", + event_name); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static int SSLStateGetEventInfoById( + int event_id, const char **event_name, AppLayerEventType *event_type) +{ + *event_name = SCMapEnumValueToName(event_id, tls_decoder_event_table); + if (*event_name == NULL) { + SCLogError("event \"%d\" not present in " + "ssl's enum map table.", + event_id); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static int SSLRegisterPatternsForProtocolDetection(void) +{ + if (AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_TLS, "|01 00 02|", 5, 2, + STREAM_TOSERVER, SSLProbingParser, 0, 3) < 0) { + return -1; + } + + /** SSLv3 */ + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|01 03 00|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 00|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + + /** TLSv1 */ + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|01 03 01|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 01|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + + /** TLSv1.1 */ + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|01 03 02|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 02|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + + /** TLSv1.2 */ + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|01 03 03|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 03|", 3, 0, STREAM_TOSERVER) < 0) { + return -1; + } + + /***** toclient direction *****/ + + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|15 03 00|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 00|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|17 03 00|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + + /** TLSv1 */ + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|15 03 01|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 01|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|17 03 01|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + + /** TLSv1.1 */ + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|15 03 02|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 02|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|17 03 02|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + + /** TLSv1.2 */ + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|15 03 03|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|16 03 03|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, ALPROTO_TLS, "|17 03 03|", 3, 0, STREAM_TOCLIENT) < 0) { + return -1; + } + + /* Subsection - SSLv2 style record by client, but informing the server + * the max version it supports. + * Updated by Anoop Saldanha. Disabled it for now. We'll get back to + * it after some tests */ +#if 0 + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, + "|01 03 00|", 5, 2, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_TLS, + "|00 02|", 7, 5, STREAM_TOCLIENT) < 0) + { + return -1; + } +#endif + + return 0; +} + +/** + * \brief Function to register the SSL protocol parser and other functions + */ +void RegisterSSLParsers(void) +{ + const char *proto_name = "tls"; + + SC_ATOMIC_INIT(ssl_config.enable_ja3); + + /** SSLv2 and SSLv23*/ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_TLS, proto_name); + + if (SSLRegisterPatternsForProtocolDetection() < 0) + return; + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister( + IPPROTO_TCP, "443", ALPROTO_TLS, 0, 3, STREAM_TOSERVER, SSLProbingParser, NULL); + } else { + if (AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_TLS, 0, + 3, SSLProbingParser, NULL) == 0) { + SCLogConfig("no TLS config found, " + "enabling TLS detection on port 443."); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "443", ALPROTO_TLS, 0, 3, + STREAM_TOSERVER, SSLProbingParser, NULL); + } + } + } else { + SCLogConfig("Protocol detection and parser disabled for %s protocol", proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER, SSLParseClientRecord); + + AppLayerParserRegisterParser( + IPPROTO_TCP, ALPROTO_TLS, STREAM_TOCLIENT, SSLParseServerRecord); + + AppLayerParserRegisterGetFrameFuncs( + IPPROTO_TCP, ALPROTO_TLS, SSLStateGetFrameIdByName, SSLStateGetFrameNameById); + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfo); + AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfoById); + + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateAlloc, SSLStateFree); + + AppLayerParserRegisterParserAcceptableDataDirection( + IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TLS, SSLStateTransactionFree); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TLS, SSLGetTx); + AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxData); + AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetStateData); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetAlstateProgress); + + AppLayerParserRegisterStateProgressCompletionStatus( + ALPROTO_TLS, TLS_STATE_FINISHED, TLS_STATE_FINISHED); + + ConfNode *enc_handle = ConfGetNode("app-layer.protocols.tls.encryption-handling"); + if (enc_handle != NULL && enc_handle->val != NULL) { + SCLogDebug("have app-layer.protocols.tls.encryption-handling = %s", enc_handle->val); + if (strcmp(enc_handle->val, "full") == 0) { + ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_FULL; + } else if (strcmp(enc_handle->val, "bypass") == 0) { + ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS; + } else if (strcmp(enc_handle->val, "default") == 0) { + ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_DEFAULT; + } else { + ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_DEFAULT; + } + } else { + /* Get the value of no reassembly option from the config file */ + if (ConfGetNode("app-layer.protocols.tls.no-reassemble") == NULL) { + int value = 0; + if (ConfGetBool("tls.no-reassemble", &value) == 1 && value == 1) + ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS; + } else { + int value = 0; + if (ConfGetBool("app-layer.protocols.tls.no-reassemble", &value) == 1 && value == 1) + ssl_config.encrypt_mode = SSL_CNF_ENC_HANDLE_BYPASS; + } + } + SCLogDebug("ssl_config.encrypt_mode %u", ssl_config.encrypt_mode); + + /* Check if we should generate JA3 fingerprints */ + int enable_ja3 = SSL_CONFIG_DEFAULT_JA3; + const char *strval = NULL; + if (ConfGet("app-layer.protocols.tls.ja3-fingerprints", &strval) != 1) { + enable_ja3 = SSL_CONFIG_DEFAULT_JA3; + } else if (strcmp(strval, "auto") == 0) { + enable_ja3 = SSL_CONFIG_DEFAULT_JA3; + } else if (ConfValIsFalse(strval)) { + enable_ja3 = 0; + ssl_config.disable_ja3 = true; + } else if (ConfValIsTrue(strval)) { + enable_ja3 = true; + } + SC_ATOMIC_SET(ssl_config.enable_ja3, enable_ja3); + + if (g_disable_hashing) { + if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { + SCLogWarning("MD5 calculation has been disabled, disabling JA3"); + SC_ATOMIC_SET(ssl_config.enable_ja3, 0); + } + } else { + if (RunmodeIsUnittests()) { + SC_ATOMIC_SET(ssl_config.enable_ja3, 1); + } + } + } else { + SCLogConfig("Parsed disabled for %s protocol. Protocol detection" + "still on.", + proto_name); + } + + return; +} + +/** + * \brief if not explicitly disabled in config, enable ja3 support + * + * Implemented using atomic to allow rule reloads to do this at + * runtime. + */ +void SSLEnableJA3(void) +{ + if (g_disable_hashing || ssl_config.disable_ja3) { + return; + } + if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { + return; + } + SC_ATOMIC_SET(ssl_config.enable_ja3, 1); +} + +bool SSLJA3IsEnabled(void) +{ + if (SC_ATOMIC_GET(ssl_config.enable_ja3)) { + return true; + } + return false; +} diff --git a/src/app-layer/ssl/parser.h b/src/app-layer/ssl/parser.h new file mode 100644 index 000000000000..063c44030844 --- /dev/null +++ b/src/app-layer/ssl/parser.h @@ -0,0 +1,310 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * \author Pierre Chifflier + * + */ + +#ifndef __APP_LAYER_SSL_H__ +#define __APP_LAYER_SSL_H__ + +#include "util/ja3.h" +#include "rust.h" + +enum TlsFrameTypes { + TLS_FRAME_PDU = 0, /**< whole PDU, so header + data */ + TLS_FRAME_HDR, /**< only header portion */ + TLS_FRAME_DATA, /**< only data portion */ + TLS_FRAME_ALERT_DATA, + TLS_FRAME_HB_DATA, + TLS_FRAME_SSLV2_HDR, + TLS_FRAME_SSLV2_PDU, +}; + +enum { + /* TLS protocol messages */ + TLS_DECODER_EVENT_INVALID_SSLV2_HEADER, + TLS_DECODER_EVENT_INVALID_TLS_HEADER, + TLS_DECODER_EVENT_INVALID_RECORD_VERSION, + TLS_DECODER_EVENT_INVALID_RECORD_TYPE, + TLS_DECODER_EVENT_INVALID_RECORD_LENGTH, + TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE, + TLS_DECODER_EVENT_HEARTBEAT, + TLS_DECODER_EVENT_INVALID_HEARTBEAT, + TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT, + TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH, + TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH, + TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS, + TLS_DECODER_EVENT_INVALID_SNI_TYPE, + TLS_DECODER_EVENT_INVALID_SNI_LENGTH, + TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET, + /* Certificates decoding messages */ + TLS_DECODER_EVENT_INVALID_CERTIFICATE, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY, + TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED, + TLS_DECODER_EVENT_INVALID_SSL_RECORD, +}; + +enum { + TLS_STATE_IN_PROGRESS = 0, + TLS_STATE_CERT_READY = 1, + TLS_HANDSHAKE_DONE = 2, + TLS_STATE_FINISHED = 3 +}; + +/* Flag to indicate that server will now on send encrypted msgs */ +#define SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC BIT_U32(0) +/* Flag to indicate that client will now on send encrypted msgs */ +#define SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC BIT_U32(1) +#define SSL_AL_FLAG_CHANGE_CIPHER_SPEC BIT_U32(2) + +/* SSL related flags */ +#define SSL_AL_FLAG_SSL_CLIENT_HS BIT_U32(3) +#define SSL_AL_FLAG_SSL_SERVER_HS BIT_U32(4) +#define SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY BIT_U32(5) +#define SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED BIT_U32(6) +#define SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED BIT_U32(7) +#define SSL_AL_FLAG_SSL_NO_SESSION_ID BIT_U32(8) + +/* flags specific to detect-ssl-state keyword */ +#define SSL_AL_FLAG_STATE_CLIENT_HELLO BIT_U32(9) +#define SSL_AL_FLAG_STATE_SERVER_HELLO BIT_U32(10) +#define SSL_AL_FLAG_STATE_CLIENT_KEYX BIT_U32(11) +#define SSL_AL_FLAG_STATE_SERVER_KEYX BIT_U32(12) +#define SSL_AL_FLAG_STATE_UNKNOWN BIT_U32(13) + +/* flag to indicate that session is finished */ +#define SSL_AL_FLAG_STATE_FINISHED BIT_U32(14) + +/* flags specific to HeartBeat state */ +#define SSL_AL_FLAG_HB_INFLIGHT BIT_U32(15) +#define SSL_AL_FLAG_HB_CLIENT_INIT BIT_U32(16) +#define SSL_AL_FLAG_HB_SERVER_INIT BIT_U32(17) + +/* flag to indicate that handshake is done */ +#define SSL_AL_FLAG_HANDSHAKE_DONE BIT_U32(18) + +/* Session resumed without a full handshake */ +#define SSL_AL_FLAG_SESSION_RESUMED BIT_U32(20) + +/* Encountered a supported_versions extension in client hello */ +#define SSL_AL_FLAG_CH_VERSION_EXTENSION BIT_U32(21) + +/* Log the session even without ever seeing a certificate. This is used + to log TLSv1.3 sessions. */ +#define SSL_AL_FLAG_LOG_WITHOUT_CERT BIT_U32(22) + +/* Encountered a early data extension in client hello. This extension is + used by 0-RTT. */ +#define SSL_AL_FLAG_EARLY_DATA BIT_U32(23) + +/* flag to indicate that server random was filled */ +#define TLS_TS_RANDOM_SET BIT_U32(24) + +/* flag to indicate that client random was filled */ +#define TLS_TC_RANDOM_SET BIT_U32(25) + +#define SSL_AL_FLAG_NEED_CLIENT_CERT BIT_U32(26) + +/* config flags */ +#define SSL_TLS_LOG_PEM (1 << 0) + +/* extensions */ +#define SSL_EXTENSION_SNI 0x0000 +#define SSL_EXTENSION_ELLIPTIC_CURVES 0x000a +#define SSL_EXTENSION_EC_POINT_FORMATS 0x000b +#define SSL_EXTENSION_SESSION_TICKET 0x0023 +#define SSL_EXTENSION_EARLY_DATA 0x002a +#define SSL_EXTENSION_SUPPORTED_VERSIONS 0x002b + +/* SNI types */ +#define SSL_SNI_TYPE_HOST_NAME 0 + +/* Max string length of the TLS version string */ +#define SSL_VERSION_MAX_STRLEN 20 + +/* TLS random bytes for the sticky buffer */ +#define TLS_RANDOM_LEN 32 + +/* SSL versions. We'll use a unified format for all, with the top byte + * holding the major version and the lower byte the minor version */ +enum { + TLS_VERSION_UNKNOWN = 0x0000, + SSL_VERSION_2 = 0x0200, + SSL_VERSION_3 = 0x0300, + TLS_VERSION_10 = 0x0301, + TLS_VERSION_11 = 0x0302, + TLS_VERSION_12 = 0x0303, + TLS_VERSION_13 = 0x0304, + TLS_VERSION_13_DRAFT28 = 0x7f1c, + TLS_VERSION_13_DRAFT27 = 0x7f1b, + TLS_VERSION_13_DRAFT26 = 0x7f1a, + TLS_VERSION_13_DRAFT25 = 0x7f19, + TLS_VERSION_13_DRAFT24 = 0x7f18, + TLS_VERSION_13_DRAFT23 = 0x7f17, + TLS_VERSION_13_DRAFT22 = 0x7f16, + TLS_VERSION_13_DRAFT21 = 0x7f15, + TLS_VERSION_13_DRAFT20 = 0x7f14, + TLS_VERSION_13_DRAFT19 = 0x7f13, + TLS_VERSION_13_DRAFT18 = 0x7f12, + TLS_VERSION_13_DRAFT17 = 0x7f11, + TLS_VERSION_13_DRAFT16 = 0x7f10, + TLS_VERSION_13_PRE_DRAFT16 = 0x7f01, + TLS_VERSION_13_DRAFT20_FB = 0xfb14, + TLS_VERSION_13_DRAFT21_FB = 0xfb15, + TLS_VERSION_13_DRAFT22_FB = 0xfb16, + TLS_VERSION_13_DRAFT23_FB = 0xfb17, + TLS_VERSION_13_DRAFT26_FB = 0xfb1a, +}; + +static inline bool TLSVersionValid(const uint16_t version) +{ + switch (version) { + case TLS_VERSION_13: + case TLS_VERSION_12: + case TLS_VERSION_11: + case TLS_VERSION_10: + case SSL_VERSION_3: + + case TLS_VERSION_13_DRAFT28: + case TLS_VERSION_13_DRAFT27: + case TLS_VERSION_13_DRAFT26: + case TLS_VERSION_13_DRAFT25: + case TLS_VERSION_13_DRAFT24: + case TLS_VERSION_13_DRAFT23: + case TLS_VERSION_13_DRAFT22: + case TLS_VERSION_13_DRAFT21: + case TLS_VERSION_13_DRAFT20: + case TLS_VERSION_13_DRAFT19: + case TLS_VERSION_13_DRAFT18: + case TLS_VERSION_13_DRAFT17: + case TLS_VERSION_13_DRAFT16: + case TLS_VERSION_13_PRE_DRAFT16: + case TLS_VERSION_13_DRAFT20_FB: + case TLS_VERSION_13_DRAFT21_FB: + case TLS_VERSION_13_DRAFT22_FB: + case TLS_VERSION_13_DRAFT23_FB: + case TLS_VERSION_13_DRAFT26_FB: + return true; + } + return false; +} + +typedef struct SSLCertsChain_ { + uint8_t *cert_data; + uint32_t cert_len; + TAILQ_ENTRY(SSLCertsChain_) next; +} SSLCertsChain; + +typedef struct SSLStateConnp_ { + /* record length */ + uint32_t record_length; + /* record length's length for SSLv2 */ + uint32_t record_lengths_length; + + /* offset of the beginning of the current message (including header) */ + uint32_t message_length; + + uint16_t version; + uint8_t content_type; + + uint8_t handshake_type; + + /* the no of bytes processed in the currently parsed record */ + uint32_t bytes_processed; + + uint16_t session_id_length; + + uint8_t random[TLS_RANDOM_LEN]; + char *cert0_subject; + char *cert0_issuerdn; + char *cert0_serial; + int64_t cert0_not_before; + int64_t cert0_not_after; + char *cert0_fingerprint; + + /* ssl server name indication extension */ + char *sni; + + char *session_id; + + TAILQ_HEAD(, SSLCertsChain_) certs; + + uint8_t *certs_buffer; + uint32_t certs_buffer_size; + + uint32_t cert_log_flag; + + JA3Buffer *ja3_str; + char *ja3_hash; + + /* handshake tls fragmentation buffer. Handshake messages can be fragmented over multiple + * TLS records. */ + uint8_t *hs_buffer; + uint8_t hs_buffer_message_type; + uint32_t hs_buffer_message_size; + uint32_t hs_buffer_size; /**< allocation size */ + uint32_t hs_buffer_offset; /**< write offset */ +} SSLStateConnp; + +/** + * \brief SSLv[2.0|3.[0|1|2|3]] state structure. + * + * Structure to store the SSL state values. + */ +typedef struct SSLState_ { + Flow *f; + + AppLayerStateData state_data; + AppLayerTxData tx_data; + + /* holds some state flags we need */ + uint32_t flags; + + /* there might be a better place to store this*/ + uint32_t hb_record_len; + + uint16_t events; + + uint32_t current_flags; + + SSLStateConnp *curr_connp; + + SSLStateConnp client_connp; + SSLStateConnp server_connp; +} SSLState; + +void RegisterSSLParsers(void); +void SSLVersionToString(uint16_t, char *); +void SSLEnableJA3(void); +bool SSLJA3IsEnabled(void); + +#endif /* __APP_LAYER_SSL_H__ */ diff --git a/src/app-layer/template/detect-2.c b/src/app-layer/template/detect-2.c new file mode 100644 index 000000000000..0ff574b8de0a --- /dev/null +++ b/src/app-layer/template/detect-2.c @@ -0,0 +1,188 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author XXX + * + */ + +#include "suricata-common.h" +#include "util/byte.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine-prefilter-common.h" +#include "detect-engine-uint.h" + +#include "app-layer/template/detect-2.h" + +/* prototypes */ +static int DetectTemplate2Match( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectTemplate2Setup(DetectEngineCtx *, Signature *, const char *); +void DetectTemplate2Free(DetectEngineCtx *, void *); +#ifdef UNITTESTS +void DetectTemplate2RegisterTests(void); +#endif +static int PrefilterSetupTemplate2(DetectEngineCtx *de_ctx, SigGroupHead *sgh); +static bool PrefilterTemplate2IsPrefilterable(const Signature *s); + +/** + * \brief Registration function for template2: keyword + */ + +void DetectTemplate2Register(void) +{ + sigmatch_table[DETECT_TEMPLATE2].name = "template2"; + sigmatch_table[DETECT_TEMPLATE2].desc = "TODO describe the keyword"; + sigmatch_table[DETECT_TEMPLATE2].url = "/rules/header-keywords.html#template2"; + sigmatch_table[DETECT_TEMPLATE2].Match = DetectTemplate2Match; + sigmatch_table[DETECT_TEMPLATE2].Setup = DetectTemplate2Setup; + sigmatch_table[DETECT_TEMPLATE2].Free = DetectTemplate2Free; + sigmatch_table[DETECT_TEMPLATE2].SupportsPrefilter = PrefilterTemplate2IsPrefilterable; + sigmatch_table[DETECT_TEMPLATE2].SetupPrefilter = PrefilterSetupTemplate2; + + return; +} + +/** + * \brief This function is used to match TEMPLATE2 rule option on a packet with those passed via + * template2: + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectU8Data + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectTemplate2Match( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) +{ + + if (PKT_IS_PSEUDOPKT(p)) + return 0; + + /* TODO replace this */ + uint8_t ptemplate2; + if (PKT_IS_IPV4(p)) { + ptemplate2 = IPV4_GET_IPTTL(p); + } else if (PKT_IS_IPV6(p)) { + ptemplate2 = IPV6_GET_HLIM(p); + } else { + SCLogDebug("Packet is of not IPv4 or IPv6"); + return 0; + } + + const DetectU8Data *template2d = (const DetectU8Data *)ctx; + return DetectU8Match(ptemplate2, template2d); +} + +/** + * \brief this function is used to add the parsed template2 data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param template2str pointer to the user provided template2 options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTemplate2Setup(DetectEngineCtx *de_ctx, Signature *s, const char *template2str) +{ + DetectU8Data *template2d = DetectU8Parse(template2str); + if (template2d == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_TEMPLATE2, (SigMatchCtx *)template2d, + DETECT_SM_LIST_MATCH) == NULL) { + DetectTemplate2Free(de_ctx, template2d); + return -1; + } + s->flags |= SIG_FLAG_REQUIRE_PACKET; + + return 0; +} + +/** + * \brief this function will free memory associated with DetectU8Data + * + * \param ptr pointer to DetectU8Data + */ +void DetectTemplate2Free(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u8_free(ptr); +} + +/* prefilter code */ + +static void PrefilterPacketTemplate2Match( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + uint8_t ptemplate2; + /* TODO update */ + if (PKT_IS_IPV4(p)) { + ptemplate2 = IPV4_GET_IPTTL(p); + } else if (PKT_IS_IPV6(p)) { + ptemplate2 = IPV6_GET_HLIM(p); + } else { + SCLogDebug("Packet is of not IPv4 or IPv6"); + return; + } + + /* during setup Suricata will automatically see if there is another + * check that can be added: alproto, sport or dport */ + const PrefilterPacketHeaderCtx *ctx = pectx; + if (!PrefilterPacketHeaderExtraMatch(ctx, p)) + return; + + DetectU8Data du8; + du8.mode = ctx->v1.u8[0]; + du8.arg1 = ctx->v1.u8[1]; + du8.arg2 = ctx->v1.u8[2]; + /* if we match, add all the sigs that use this prefilter. This means + * that these will be inspected further */ + if (DetectU8Match(ptemplate2, &du8)) { + SCLogDebug("packet matches template2/hl %u", ptemplate2); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static int PrefilterSetupTemplate2(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_TEMPLATE2, PrefilterPacketU8Set, + PrefilterPacketU8Compare, PrefilterPacketTemplate2Match); +} + +static bool PrefilterTemplate2IsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_TEMPLATE2: + return true; + } + } + return false; +} diff --git a/src/app-layer/template/detect-2.h b/src/app-layer/template/detect-2.h new file mode 100644 index 000000000000..ee290644cd75 --- /dev/null +++ b/src/app-layer/template/detect-2.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author XXX + */ + +#ifndef _DETECT_TEMPLATE2_H +#define _DETECT_TEMPLATE2_H + +void DetectTemplate2Register(void); + +#endif /* _DETECT_TEMPLATE2_H */ diff --git a/src/app-layer/template/detect-rust-buffer.c b/src/app-layer/template/detect-rust-buffer.c new file mode 100644 index 000000000000..c70ac0ae6e06 --- /dev/null +++ b/src/app-layer/template/detect-rust-buffer.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2015-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * TODO: Update the \author in this file and detect-template.h. + * TODO: Update description in the \file section below. + * TODO: Remove SCLogNotice statements or convert to debug. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Set up of the "template_rust" keyword to allow content + * inspections on the decoded template application layer buffers. + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "app-layer/template/detect-rust-buffer.h" +#include "app-layer-parser.h" +#include "detect-engine-build.h" +#include "rust.h" + +static int DetectTemplateRustBufferSetup(DetectEngineCtx *, Signature *, const char *); +static uint8_t DetectEngineInspectTemplateRustBuffer(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +#ifdef UNITTESTS +static void DetectTemplateRustBufferRegisterTests(void); +#endif +static int g_template_rust_id = 0; + +void DetectTemplateRustBufferRegister(void) +{ + /* TEMPLATE_START_REMOVE */ + if (ConfGetNode("app-layer.protocols.template-rust") == NULL) { + return; + } + /* TEMPLATE_END_REMOVE */ + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_rust_buffer"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = + "Template content modifier to match on the template buffers"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].Setup = DetectTemplateRustBufferSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].RegisterTests = DetectTemplateRustBufferRegisterTests; +#endif + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT; + + /* register inspect engines */ + DetectAppLayerInspectEngineRegister2("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectTemplateRustBuffer, NULL); + DetectAppLayerInspectEngineRegister2("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectTemplateRustBuffer, NULL); + + g_template_rust_id = DetectBufferTypeGetByName("template_buffer"); + + SCLogNotice("Template application layer detect registered."); +} + +static int DetectTemplateRustBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + s->init_data->list = g_template_rust_id; + + if (DetectSignatureSetAppProto(s, ALPROTO_TEMPLATE) != 0) + return -1; + + return 0; +} + +static uint8_t DetectEngineInspectTemplateRustBuffer(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, + const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint8_t ret = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + const uint8_t *data = NULL; + uint32_t data_len = 0; + + if (flags & STREAM_TOSERVER) { + rs_template_get_request_buffer(txv, &data, &data_len); + } else if (flags & STREAM_TOCLIENT) { + rs_template_get_response_buffer(txv, &data, &data_len); + } + + if (data != NULL) { + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)data, data_len, 0, DETECT_CI_FLAGS_SINGLE, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + ret = DETECT_ENGINE_INSPECT_SIG_MATCH; + } + } + + SCLogNotice("Returning %u.", ret); + return ret; +} + +#ifdef UNITTESTS + +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "flow-util.h" +#include "stream-tcp.h" +#include "detect-engine-alert.h" + +static int DetectTemplateRustBufferTest(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + Signature *s; + + uint8_t request[] = "12:Hello World!"; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_TEMPLATE; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(true); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + /* This rule should match. */ + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_rust_buffer; content:\"World!\"; " + "sid:1; rev:1;)"); + FAIL_IF_NULL(s); + + /* This rule should not match. */ + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_rust_buffer; content:\"W0rld!\"; " + "sid:2; rev:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, request, sizeof(request)); + + /* Check that we have app-layer state. */ + FAIL_IF_NULL(f.alstate); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + + /* Cleanup. */ + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(true); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + PASS; +} + +static void DetectTemplateRustBufferRegisterTests(void) +{ + UtRegisterTest("DetectTemplateRustBufferTest", DetectTemplateRustBufferTest); +} +#endif /* UNITTESTS */ diff --git a/src/detect-template-rust-buffer.h b/src/app-layer/template/detect-rust-buffer.h similarity index 100% rename from src/detect-template-rust-buffer.h rename to src/app-layer/template/detect-rust-buffer.h diff --git a/src/app-layer/template/detect.c b/src/app-layer/template/detect.c new file mode 100644 index 000000000000..60ab066df1c7 --- /dev/null +++ b/src/app-layer/template/detect.c @@ -0,0 +1,221 @@ +/* Copyright (C) 2015-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author XXX Yourname + * + * XXX Short description of the purpose of this keyword + */ + +#include "suricata-common.h" +#include "util/unittest.h" +#include "util/byte.h" + +#include "detect-parse.h" +#include "detect-engine.h" + +#include "app-layer/template/detect.h" + +/** + * \brief Regex for parsing our keyword options + */ +#define PARSE_REGEX "^\\s*([0-9]+)?\\s*,s*([0-9]+)?\\s*$" +static DetectParseRegex parse_regex; + +/* Prototypes of functions registered in DetectTemplateRegister below */ +static int DetectTemplateMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectTemplateSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectTemplateFree(DetectEngineCtx *, void *); +#ifdef UNITTESTS +static void DetectTemplateRegisterTests(void); +#endif + +/** + * \brief Registration function for template: keyword + * + * This function is called once in the 'lifetime' of the engine. + */ +void DetectTemplateRegister(void) +{ + /* keyword name: this is how the keyword is used in a rule */ + sigmatch_table[DETECT_TEMPLATE].name = "template"; + /* description: listed in "suricata --list-keywords=all" */ + sigmatch_table[DETECT_TEMPLATE].desc = "give an introduction into how a detection module works"; + /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */ + sigmatch_table[DETECT_TEMPLATE].url = "https://redmine.openinfosecfoundation.org/projects/" + "suricata/wiki/Suricata_Developers_Guide"; + /* match function is called when the signature is inspected on a packet */ + sigmatch_table[DETECT_TEMPLATE].Match = DetectTemplateMatch; + /* setup function is called during signature parsing, when the template + * keyword is encountered in the rule */ + sigmatch_table[DETECT_TEMPLATE].Setup = DetectTemplateSetup; + /* free function is called when the detect engine is freed. Normally at + * shutdown, but also during rule reloads. */ + sigmatch_table[DETECT_TEMPLATE].Free = DetectTemplateFree; +#ifdef UNITTESTS + /* registers unittests into the system */ + sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests; +#endif + /* set up the PCRE for keyword parsing */ + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); +} + +/** + * \brief This function is used to match TEMPLATE rule option on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch with context that we will cast into DetectTemplateData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectTemplateMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) +{ + int ret = 0; + const DetectTemplateData *templated = (const DetectTemplateData *)ctx; +#if 0 + if (PKT_IS_PSEUDOPKT(p)) { + /* fake pkt */ + } + + if (PKT_IS_IPV4(p)) { + /* ipv4 pkt */ + } else if (PKT_IS_IPV6(p)) { + /* ipv6 pkt */ + } else { + SCLogDebug("packet is of not IPv4 or IPv6"); + return ret; + } +#endif + /* packet payload access */ + if (p->payload != NULL && p->payload_len > 0) { + if (templated->arg1 == p->payload[0] && templated->arg2 == p->payload[p->payload_len - 1]) { + ret = 1; + } + } + + return ret; +} + +/** + * \brief This function is used to parse template options passed via template: keyword + * + * \param templatestr Pointer to the user provided template options + * + * \retval templated pointer to DetectTemplateData on success + * \retval NULL on failure + */ +static DetectTemplateData *DetectTemplateParse(const char *templatestr) +{ + char arg1[4] = ""; + char arg2[4] = ""; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, templatestr, 0, 0); + if (ret != 3) { + SCLogError("parse error, ret %" PRId32 "", ret); + goto error; + } + + size_t pcre2len = sizeof(arg1); + ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + SCLogDebug("Arg1 \"%s\"", arg1); + + pcre2len = sizeof(arg2); + ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + SCLogDebug("Arg2 \"%s\"", arg2); + + DetectTemplateData *templated = SCMalloc(sizeof(DetectTemplateData)); + if (unlikely(templated == NULL)) + goto error; + + if (ByteExtractStringUint8(&templated->arg1, 10, 0, (const char *)arg1) < 0) { + SCFree(templated); + goto error; + } + if (ByteExtractStringUint8(&templated->arg2, 10, 0, (const char *)arg2) < 0) { + SCFree(templated); + goto error; + } + pcre2_match_data_free(match); + return templated; + +error: + if (match) { + pcre2_match_data_free(match); + } + return NULL; +} + +/** + * \brief parse the options from the 'template' keyword in the rule into + * the Signature data structure. + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param templatestr pointer to the user provided template options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTemplateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *templatestr) +{ + DetectTemplateData *templated = DetectTemplateParse(templatestr); + if (templated == NULL) + return -1; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_TEMPLATE, (SigMatchCtx *)templated, + DETECT_SM_LIST_MATCH) == NULL) { + DetectTemplateFree(de_ctx, templated); + return -1; + } + s->flags |= SIG_FLAG_REQUIRE_PACKET; + + return 0; +} + +/** + * \brief this function will free memory associated with DetectTemplateData + * + * \param ptr pointer to DetectTemplateData + */ +static void DetectTemplateFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectTemplateData *templated = (DetectTemplateData *)ptr; + + /* do more specific cleanup here, if needed */ + + SCFree(templated); +} + +#ifdef UNITTESTS +#include "tests/detect-template.c" +#endif diff --git a/src/detect-template.h b/src/app-layer/template/detect.h similarity index 100% rename from src/detect-template.h rename to src/app-layer/template/detect.h diff --git a/src/app-layer/template/logger.c b/src/app-layer/template/logger.c new file mode 100644 index 000000000000..2ac4fe9110ed --- /dev/null +++ b/src/app-layer/template/logger.c @@ -0,0 +1,176 @@ +/* Copyright (C) 2018-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * TODO: Update \author in this file and in output-json-template.h. + * TODO: Remove SCLogNotice statements, or convert to debug. + * TODO: Implement your app-layers logging. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Implement JSON/eve logging app-layer Template. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/template/logger.h" +#include "rust.h" + +typedef struct LogTemplateFileCtx_ { + uint32_t flags; + OutputJsonCtx *eve_ctx; +} LogTemplateFileCtx; + +typedef struct LogTemplateLogThread_ { + LogTemplateFileCtx *templatelog_ctx; + OutputJsonThreadCtx *ctx; +} LogTemplateLogThread; + +static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *tx, uint64_t tx_id) +{ + SCLogNotice("JsonTemplateLogger"); + LogTemplateLogThread *thread = thread_data; + + JsonBuilder *js = + CreateEveHeader(p, LOG_DIR_PACKET, "template", NULL, thread->templatelog_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return TM_ECODE_FAILED; + } + + if (!rs_template_logger_log(tx, js)) { + goto error; + } + + OutputJsonBuilderBuffer(js, thread->ctx); + jb_free(js); + + return TM_ECODE_OK; + +error: + jb_free(js); + return TM_ECODE_FAILED; +} + +static void OutputTemplateLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogTemplateFileCtx *templatelog_ctx = (LogTemplateFileCtx *)output_ctx->data; + SCFree(templatelog_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputTemplateLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ajt = parent_ctx->data; + + LogTemplateFileCtx *templatelog_ctx = SCCalloc(1, sizeof(*templatelog_ctx)); + if (unlikely(templatelog_ctx == NULL)) { + return result; + } + templatelog_ctx->eve_ctx = ajt; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(templatelog_ctx); + return result; + } + output_ctx->data = templatelog_ctx; + output_ctx->DeInit = OutputTemplateLogDeInitCtxSub; + + SCLogNotice("Template log sub-module initialized."); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TEMPLATE); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +static TmEcode JsonTemplateLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogTemplateLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogTemplate. \"initdata\" is NULL."); + goto error_exit; + } + + thread->templatelog_ctx = ((OutputCtx *)initdata)->data; + thread->ctx = CreateEveThreadCtx(t, thread->templatelog_ctx->eve_ctx); + if (!thread->ctx) { + goto error_exit; + } + *data = (void *)thread; + + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonTemplateLogThreadDeinit(ThreadVars *t, void *data) +{ + LogTemplateLogThread *thread = (LogTemplateLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + FreeEveThreadCtx(thread->ctx); + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonTemplateLogRegister(void) +{ + /* TEMPLATE_START_REMOVE */ + if (ConfGetNode("app-layer.protocols.template") == NULL) { + return; + } + /* TEMPLATE_END_REMOVE */ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonTemplateLog", "eve-log.template", + OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger, + JsonTemplateLogThreadInit, JsonTemplateLogThreadDeinit, NULL); + + SCLogNotice("Template JSON logger registered."); +} diff --git a/src/output-json-template.h b/src/app-layer/template/logger.h similarity index 100% rename from src/output-json-template.h rename to src/app-layer/template/logger.h diff --git a/src/app-layer/tftp/logger.c b/src/app-layer/tftp/logger.c new file mode 100644 index 000000000000..09d8866b71cb --- /dev/null +++ b/src/app-layer/tftp/logger.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2020-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Clément Galland + * + * Implement JSON/eve logging app-layer TFTP. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/unittest.h" +#include "util/buffer.h" +#include "util/debug.h" +#include "util/byte.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/tftp/parser.h" +#include "app-layer/tftp/logger.h" + +#include "rust.h" + +static int JsonTFTPLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + OutputJsonThreadCtx *thread = thread_data; + + JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "tftp", NULL, thread->ctx); + if (unlikely(jb == NULL)) { + return TM_ECODE_FAILED; + } + + if (unlikely(!rs_tftp_log_json_request(tx, jb))) { + goto error; + } + + OutputJsonBuilderBuffer(jb, thread); + + jb_free(jb); + return TM_ECODE_OK; + +error: + jb_free(jb); + return TM_ECODE_FAILED; +} + +static OutputInitResult OutputTFTPLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_TFTP); + return OutputJsonLogInitSub(conf, parent_ctx); +} + +void JsonTFTPLogRegister(void) +{ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonTFTPLog", "eve-log.tftp", + OutputTFTPLogInitSub, ALPROTO_TFTP, JsonTFTPLogger, JsonLogThreadInit, + JsonLogThreadDeinit, NULL); + + SCLogDebug("TFTP JSON logger registered."); +} diff --git a/src/output-json-tftp.h b/src/app-layer/tftp/logger.h similarity index 100% rename from src/output-json-tftp.h rename to src/app-layer/tftp/logger.h diff --git a/src/app-layer/tftp/parser.c b/src/app-layer/tftp/parser.c new file mode 100644 index 000000000000..529822364efe --- /dev/null +++ b/src/app-layer/tftp/parser.c @@ -0,0 +1,223 @@ +/* Copyright (C) 2017-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +/** + * \file + * + * \author Clément Galland + * + * Parser for NTP application layer running on UDP port 69. + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "stream.h" +#include "conf.h" + +#include "util/unittest.h" + +#include "app-layer.h" +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer/tftp/parser.h" +#include "rust.h" + +/* The default port to probe if not provided in the configuration file. */ +#define TFTP_DEFAULT_PORT "69" + +/* The minimum size for an message. For some protocols this might + * be the size of a header. */ +#define TFTP_MIN_FRAME_LEN 4 + +static void *TFTPStateAlloc(void *orig_state, AppProto proto_orig) +{ + return rs_tftp_state_alloc(); +} + +static void TFTPStateFree(void *state) +{ + rs_tftp_state_free(state); +} + +/** + * \brief Callback from the application layer to have a transaction freed. + * + * \param state a void pointer to the TFTPState object. + * \param tx_id the transaction ID to free. + */ +static void TFTPStateTxFree(void *state, uint64_t tx_id) +{ + rs_tftp_state_tx_free(state, tx_id); +} + +static int TFTPStateGetEventInfo( + const char *event_name, int *event_id, AppLayerEventType *event_type) +{ + return -1; +} + +/** + * \brief Probe the input to see if it looks like tftp. + * + * \retval ALPROTO_TFTP if it looks like tftp, otherwise + * ALPROTO_UNKNOWN. + */ +static AppProto TFTPProbingParser( + Flow *f, uint8_t direction, const uint8_t *input, uint32_t input_len, uint8_t *rdir) +{ + /* Very simple test - if there is input, this is tftp. + * Also check if it's starting by a zero */ + if (input_len >= TFTP_MIN_FRAME_LEN && *input == 0) { + SCLogDebug("Detected as ALPROTO_TFTP."); + return ALPROTO_TFTP; + } + + SCLogDebug("Protocol not detected as ALPROTO_TFTP."); + return ALPROTO_UNKNOWN; +} + +static AppLayerResult TFTPParseRequest(Flow *f, void *state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + const uint8_t *input = StreamSliceGetData(&stream_slice); + uint32_t input_len = StreamSliceGetDataLen(&stream_slice); + + SCLogDebug("Parsing tftp request: len=%" PRIu32, input_len); + + /* Likely connection closed, we can just return here. */ + if ((input == NULL || input_len == 0) && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) { + SCReturnStruct(APP_LAYER_OK); + } + + /* Probably don't want to create a transaction in this case + * either. */ + if (input == NULL || input_len == 0) { + SCReturnStruct(APP_LAYER_OK); + } + + int res = rs_tftp_request(state, input, input_len); + if (res < 0) { + SCReturnStruct(APP_LAYER_ERROR); + } + SCReturnStruct(APP_LAYER_OK); +} + +/** + * \brief Response parsing is not implemented + */ +static AppLayerResult TFTPParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + StreamSlice stream_slice, void *local_data) +{ + SCReturnStruct(APP_LAYER_OK); +} + +static uint64_t TFTPGetTxCnt(void *state) +{ + return rs_tftp_get_tx_cnt(state); +} + +static void *TFTPGetTx(void *state, uint64_t tx_id) +{ + return rs_tftp_get_tx(state, tx_id); +} + +/** + * \brief Return the state of a transaction in a given direction. + * + * In the case of the tftp protocol, the existence of a transaction + * means that the request is done. However, some protocols that may + * need multiple chunks of data to complete the request may need more + * than just the existence of a transaction for the request to be + * considered complete. + * + * For the response to be considered done, the response for a request + * needs to be seen. The response_done flag is set on response for + * checking here. + */ +static int TFTPGetStateProgress(void *tx, uint8_t direction) +{ + return 1; +} + +void RegisterTFTPParsers(void) +{ + const char *proto_name = "tftp"; + + /* Check if TFTP UDP detection is enabled. If it does not exist in + * the configuration file then it will be enabled by default. */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) { + + SCLogDebug("TFTP UDP protocol detection enabled."); + + AppLayerProtoDetectRegisterProtocol(ALPROTO_TFTP, proto_name); + + if (RunmodeIsUnittests()) { + SCLogDebug("Unittest mode, registering default configuration."); + AppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT, ALPROTO_TFTP, 0, + TFTP_MIN_FRAME_LEN, STREAM_TOSERVER, TFTPProbingParser, TFTPProbingParser); + } else { + if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, proto_name, ALPROTO_TFTP, + 0, TFTP_MIN_FRAME_LEN, TFTPProbingParser, TFTPProbingParser)) { + SCLogDebug("No tftp app-layer configuration, enabling tftp" + " detection UDP detection on port %s.", + TFTP_DEFAULT_PORT); + AppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT, ALPROTO_TFTP, 0, + TFTP_MIN_FRAME_LEN, STREAM_TOSERVER, TFTPProbingParser, TFTPProbingParser); + } + } + } else { + SCLogDebug("Protocol detector and parser disabled for TFTP."); + return; + } + + if (AppLayerParserConfParserEnabled("udp", proto_name)) { + + SCLogDebug("Registering TFTP protocol parser."); + + /* Register functions for state allocation and freeing. A + * state is allocated for every new TFTP flow. */ + AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_TFTP, TFTPStateAlloc, TFTPStateFree); + + /* Register request parser for parsing frame from server to client. */ + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP, STREAM_TOSERVER, TFTPParseRequest); + + /* Register response parser for parsing frames from server to client. */ + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP, STREAM_TOCLIENT, TFTPParseResponse); + + /* Register a function to be called by the application layer + * when a transaction is to be freed. */ + AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_TFTP, TFTPStateTxFree); + + /* Register a function to return the current transaction count. */ + AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_TFTP, TFTPGetTxCnt); + + /* Transaction handling. */ + AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_TFTP, 1, 1); + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_TFTP, TFTPGetStateProgress); + AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_TFTP, TFTPGetTx); + + AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_TFTP, TFTPStateGetEventInfo); + + AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_TFTP, rs_tftp_get_tx_data); + AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_TFTP, rs_tftp_get_state_data); + } else { + SCLogDebug("TFTP protocol parsing disabled."); + } +} diff --git a/src/app-layer/tftp/parser.h b/src/app-layer/tftp/parser.h new file mode 100644 index 000000000000..15bad2b2e03c --- /dev/null +++ b/src/app-layer/tftp/parser.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Clément Galland + */ + +#ifndef __APP_LAYER_TFTP_H__ +#define __APP_LAYER_TFTP_H__ + +void RegisterTFTPParsers(void); + +/** Opaque Rust types. */ +typedef struct TFTPState_ TFTPState; +typedef struct TFTPTransaction_ TFTPTransaction; + +#endif /* __APP_LAYER_TFTP_H__ */ diff --git a/src/app-layer/tls/detect-cert-fingerprint.c b/src/app-layer/tls/detect-cert-fingerprint.c new file mode 100644 index 000000000000..372a710466be --- /dev/null +++ b/src/app-layer/tls/detect-cert-fingerprint.c @@ -0,0 +1,239 @@ +/* Copyright (C) 2017-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls_cert_fingerprint keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-cert-fingerprint.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsFingerprintSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectTlsFingerprintRegisterTests(void); +#endif +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static void DetectTlsFingerprintSetupCallback(const DetectEngineCtx *de_ctx, Signature *s); +static bool DetectTlsFingerprintValidateCallback(const Signature *s, const char **sigerror); +static int g_tls_cert_fingerprint_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls.cert_fingerprint + */ +void DetectTlsFingerprintRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].name = "tls.cert_fingerprint"; + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].alias = "tls_cert_fingerprint"; + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].desc = + "sticky buffer to match the TLS cert fingerprint buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].url = + "/rules/tls-keywords.html#tls-cert-fingerprint"; + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].Setup = DetectTlsFingerprintSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].RegisterTests = + DetectTlsFingerprintRegisterTests; +#endif + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("tls.cert_fingerprint", ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_fingerprint", SIG_FLAG_TOCLIENT, 2, + PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectAppLayerInspectEngineRegister2("tls.cert_fingerprint", ALPROTO_TLS, SIG_FLAG_TOSERVER, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_fingerprint", SIG_FLAG_TOSERVER, 2, + PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectBufferTypeSetDescriptionByName("tls.cert_fingerprint", "TLS certificate fingerprint"); + + DetectBufferTypeRegisterSetupCallback( + "tls.cert_fingerprint", DetectTlsFingerprintSetupCallback); + + DetectBufferTypeRegisterValidateCallback( + "tls.cert_fingerprint", DetectTlsFingerprintValidateCallback); + + g_tls_cert_fingerprint_buffer_id = DetectBufferTypeGetByName("tls.cert_fingerprint"); +} + +/** + * \brief this function setup the tls_cert_fingerprint modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsFingerprintSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_fingerprint_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + const SSLStateConnp *connp; + + if (flow_flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_fingerprint == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(connp->cert0_fingerprint); + const uint8_t *data = (uint8_t *)connp->cert0_fingerprint; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static bool DetectTlsFingerprintValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_fingerprint_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->content_len != 59) { + *sigerror = "Invalid length of the specified fingerprint. " + "This rule will therefore never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + + bool have_delimiters = false; + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (cd->content[u] == ':') { + have_delimiters = true; + break; + } + } + + if (!have_delimiters) { + *sigerror = "No colon delimiters ':' detected in content after " + "tls.cert_fingerprint. This rule will therefore " + "never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = "tls.cert_fingerprint should not be used together " + "with nocase, since the rule is automatically " + "lowercased anyway which makes nocase redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + } + } + } + return true; +} + +static void DetectTlsFingerprintSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_fingerprint_buffer_id) + continue; + SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + DetectContentData *cd = (DetectContentData *)sm->ctx; + + bool changed = false; + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) { + cd->content[u] = u8_tolower(cd->content[u]); + changed = true; + } + } + + /* recreate the context if changes were made */ + if (changed) { + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = + SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); + } + } + } +} + +#ifdef UNITTESTS +#include "detect-engine-alert.h" +#include "tests/detect-tls-cert-fingerprint.c" +#endif diff --git a/src/detect-tls-cert-fingerprint.h b/src/app-layer/tls/detect-cert-fingerprint.h similarity index 100% rename from src/detect-tls-cert-fingerprint.h rename to src/app-layer/tls/detect-cert-fingerprint.h diff --git a/src/app-layer/tls/detect-cert-issuer.c b/src/app-layer/tls/detect-cert-issuer.c new file mode 100644 index 000000000000..67684c721fbb --- /dev/null +++ b/src/app-layer/tls/detect-cert-issuer.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls.cert_issuer keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" +#include "app-layer/tls/detect-cert-issuer.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsIssuerSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectTlsIssuerRegisterTests(void); +#endif +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static int g_tls_cert_issuer_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls.cert_issuer + */ +void DetectTlsIssuerRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].name = "tls.cert_issuer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].alias = "tls_cert_issuer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].desc = + "sticky buffer to match specifically and only on the TLS cert issuer buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].url = "/rules/tls-keywords.html#tls-cert-issuer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Setup = DetectTlsIssuerSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].RegisterTests = DetectTlsIssuerRegisterTests; +#endif + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("tls.cert_issuer", ALPROTO_TLS, SIG_FLAG_TOSERVER, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_issuer", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectAppLayerInspectEngineRegister2("tls.cert_issuer", ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_issuer", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectBufferTypeSetDescriptionByName("tls.cert_issuer", "TLS certificate issuer"); + + g_tls_cert_issuer_buffer_id = DetectBufferTypeGetByName("tls.cert_issuer"); +} + +/** + * \brief this function setup the tls_cert_issuer modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsIssuerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_issuer_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + const SSLStateConnp *connp; + if (flow_flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_issuerdn == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(connp->cert0_issuerdn); + const uint8_t *data = (uint8_t *)connp->cert0_issuerdn; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS +#include "tests/detect-tls-cert-issuer.c" +#endif diff --git a/src/app-layer/tls/detect-cert-issuer.h b/src/app-layer/tls/detect-cert-issuer.h new file mode 100644 index 000000000000..4fbe9c6557ef --- /dev/null +++ b/src/app-layer/tls/detect-cert-issuer.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_ISSUER_H__ +#define __DETECT_TLS_ISSUER_H__ + +void DetectTlsIssuerRegister(void); + +#endif /* __DETECT_TLS_ISSUER_H__ */ diff --git a/src/app-layer/tls/detect-cert-serial.c b/src/app-layer/tls/detect-cert-serial.c new file mode 100644 index 000000000000..530bb4923021 --- /dev/null +++ b/src/app-layer/tls/detect-cert-serial.c @@ -0,0 +1,226 @@ +/* Copyright (C) 2017-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls.cert_serial keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" +#include "app-layer/tls/detect-cert-serial.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsSerialSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectTlsSerialRegisterTests(void); +#endif +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static void DetectTlsSerialSetupCallback(const DetectEngineCtx *de_ctx, Signature *s); +static bool DetectTlsSerialValidateCallback(const Signature *s, const char **sigerror); +static int g_tls_cert_serial_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls.cert_serial + */ +void DetectTlsSerialRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].name = "tls.cert_serial"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].alias = "tls_cert_serial"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].desc = + "sticky buffer to match the TLS cert serial buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].url = "/rules/tls-keywords.html#tls-cert-serial"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Setup = DetectTlsSerialSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].RegisterTests = DetectTlsSerialRegisterTests; +#endif + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("tls.cert_serial", ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_serial", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectAppLayerInspectEngineRegister2("tls.cert_serial", ALPROTO_TLS, SIG_FLAG_TOSERVER, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_serial", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectBufferTypeSetDescriptionByName("tls.cert_serial", "TLS certificate serial number"); + + DetectBufferTypeRegisterSetupCallback("tls.cert_serial", DetectTlsSerialSetupCallback); + + DetectBufferTypeRegisterValidateCallback("tls.cert_serial", DetectTlsSerialValidateCallback); + + g_tls_cert_serial_buffer_id = DetectBufferTypeGetByName("tls.cert_serial"); +} + +/** + * \brief this function setup the tls_cert_serial modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsSerialSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_serial_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + const SSLStateConnp *connp; + + if (flow_flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_serial == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(connp->cert0_serial); + const uint8_t *data = (uint8_t *)connp->cert0_serial; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static bool DetectTlsSerialValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_serial_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = "tls.cert_serial should not be used together " + "with nocase, since the rule is automatically " + "uppercased anyway which makes nocase redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + } + + /* no need to worry about this if the content is short enough */ + if (cd->content_len <= 2) + return true; + + uint32_t u; + for (u = 0; u < cd->content_len; u++) + if (cd->content[u] == ':') + return true; + + *sigerror = "No colon delimiters ':' detected in content after " + "tls.cert_serial. This rule will therefore never " + "match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + + return false; + } + } + return true; +} + +static void DetectTlsSerialSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_serial_buffer_id) + continue; + SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + DetectContentData *cd = (DetectContentData *)sm->ctx; + + bool changed = false; + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (islower(cd->content[u])) { + cd->content[u] = u8_toupper(cd->content[u]); + changed = true; + } + } + + /* recreate the context if changes were made */ + if (changed) { + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = + SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); + } + } + } +} + +#ifdef UNITTESTS +#include "tests/detect-tls-cert-serial.c" +#endif diff --git a/src/app-layer/tls/detect-cert-serial.h b/src/app-layer/tls/detect-cert-serial.h new file mode 100644 index 000000000000..4fcc89b06a0a --- /dev/null +++ b/src/app-layer/tls/detect-cert-serial.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_CERT_SERIAL_H__ +#define __DETECT_TLS_CERT_SERIAL_H__ + +/* prototypes */ +void DetectTlsSerialRegister(void); + +#endif /* __DETECT_TLS_CERT_SERIAL_H__ */ diff --git a/src/app-layer/tls/detect-cert-subject.c b/src/app-layer/tls/detect-cert-subject.c new file mode 100644 index 000000000000..963c89a5bc03 --- /dev/null +++ b/src/app-layer/tls/detect-cert-subject.c @@ -0,0 +1,152 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls.cert_subject keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-cert-subject.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsSubjectSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectTlsSubjectRegisterTests(void); +#endif +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static int g_tls_cert_subject_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls.cert_subject + */ +void DetectTlsSubjectRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].name = "tls.cert_subject"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].alias = "tls_cert_subject"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].desc = + "sticky buffer to match specifically and only on the TLS cert subject buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].url = "/rules/tls-keywords.html#tls-cert-subject"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Setup = DetectTlsSubjectSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; +#endif + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("tls.cert_subject", ALPROTO_TLS, SIG_FLAG_TOSERVER, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_subject", SIG_FLAG_TOSERVER, 2, + PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectAppLayerInspectEngineRegister2("tls.cert_subject", ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("tls.cert_subject", SIG_FLAG_TOCLIENT, 2, + PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectBufferTypeSupportsMultiInstance("tls.cert_subject"); + + DetectBufferTypeSetDescriptionByName("tls.cert_subject", "TLS certificate subject"); + + g_tls_cert_subject_buffer_id = DetectBufferTypeGetByName("tls.cert_subject"); +} + +/** + * \brief this function setup the tls.cert_subject modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_subject_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + const SSLStateConnp *connp; + + if (flow_flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_subject == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(connp->cert0_subject); + const uint8_t *data = (uint8_t *)connp->cert0_subject; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +#ifdef UNITTESTS +#include "tests/detect-tls-cert-subject.c" +#endif diff --git a/src/app-layer/tls/detect-cert-subject.h b/src/app-layer/tls/detect-cert-subject.h new file mode 100644 index 000000000000..abe7d6e229da --- /dev/null +++ b/src/app-layer/tls/detect-cert-subject.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_SUBJECT_H__ +#define __DETECT_TLS_SUBJECT_H__ + +void DetectTlsSubjectRegister(void); + +#endif /* __DETECT_TLS_SUBJECT_H__ */ diff --git a/src/app-layer/tls/detect-cert-validity.c b/src/app-layer/tls/detect-cert-validity.c new file mode 100644 index 000000000000..2c1d06b322cc --- /dev/null +++ b/src/app-layer/tls/detect-cert-validity.c @@ -0,0 +1,588 @@ +/* Copyright (C) 2015-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements tls certificate validity keywords + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-cert-validity.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/time.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +/** + * [tls_notbefore|tls_notafter]:[<|>][<>]; + */ +#define PARSE_REGEX "^\\s*(<|>)?\\s*([ -:TW0-9]+)\\s*(?:(<>)\\s*([ -:TW0-9]+))?\\s*$" +static DetectParseRegex parse_regex; + +static int DetectTlsValidityMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + +static time_t DateStringToEpoch(char *); +static DetectTlsValidityData *DetectTlsValidityParse(const char *); +static int DetectTlsExpiredSetup(DetectEngineCtx *, Signature *s, const char *str); +static int DetectTlsValidSetup(DetectEngineCtx *, Signature *s, const char *str); +static int DetectTlsNotBeforeSetup(DetectEngineCtx *, Signature *s, const char *str); +static int DetectTlsNotAfterSetup(DetectEngineCtx *, Signature *s, const char *str); +static int DetectTlsValiditySetup(DetectEngineCtx *, Signature *s, const char *str, uint8_t); +#ifdef UNITTESTS +static void TlsNotBeforeRegisterTests(void); +static void TlsNotAfterRegisterTests(void); +static void TlsExpiredRegisterTests(void); +static void TlsValidRegisterTests(void); +#endif /* UNITTESTS */ +static void DetectTlsValidityFree(DetectEngineCtx *, void *); +static int g_tls_validity_buffer_id = 0; + +/** + * \brief Registration function for tls validity keywords. + */ +void DetectTlsValidityRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].name = "tls_cert_notbefore"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].desc = "match TLS certificate notBefore field"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].url = "/rules/tls-keywords.html#tls-cert-notbefore"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Setup = DetectTlsNotBeforeSetup; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Free = DetectTlsValidityFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].RegisterTests = TlsNotBeforeRegisterTests; +#endif + + sigmatch_table[DETECT_AL_TLS_NOTAFTER].name = "tls_cert_notafter"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].desc = "match TLS certificate notAfter field"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].url = "/rules/tls-keywords.html#tls-cert-notafter"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Setup = DetectTlsNotAfterSetup; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Free = DetectTlsValidityFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_NOTAFTER].RegisterTests = TlsNotAfterRegisterTests; +#endif + + sigmatch_table[DETECT_AL_TLS_EXPIRED].name = "tls_cert_expired"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].desc = "match expired TLS certificates"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].url = "/rules/tls-keywords.html#tls-cert-expired"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Setup = DetectTlsExpiredSetup; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_EXPIRED].flags = SIGMATCH_NOOPT; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_EXPIRED].RegisterTests = TlsExpiredRegisterTests; +#endif + + sigmatch_table[DETECT_AL_TLS_VALID].name = "tls_cert_valid"; + sigmatch_table[DETECT_AL_TLS_VALID].desc = "match valid TLS certificates"; + sigmatch_table[DETECT_AL_TLS_VALID].url = "/rules/tls-keywords.html#tls-cert-valid"; + sigmatch_table[DETECT_AL_TLS_VALID].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_VALID].Setup = DetectTlsValidSetup; + sigmatch_table[DETECT_AL_TLS_VALID].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_VALID].flags = SIGMATCH_NOOPT; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_VALID].RegisterTests = TlsValidRegisterTests; +#endif + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + DetectAppLayerInspectEngineRegister2("tls_validity", ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); + + g_tls_validity_buffer_id = DetectBufferTypeGetByName("tls_validity"); +} + +/** + * \internal + * \brief Function to match validity field in a tls certificate. + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectTlsValidityData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectTlsValidityMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + SSLState *ssl_state = (SSLState *)state; + if (ssl_state == NULL) { + SCLogDebug("no tls state, no match"); + SCReturnInt(0); + } + + int ret = 0; + + SSLStateConnp *connp = NULL; + if (flags & STREAM_TOSERVER) + connp = &ssl_state->client_connp; + else + connp = &ssl_state->server_connp; + + const DetectTlsValidityData *dd = (const DetectTlsValidityData *)ctx; + + time_t cert_epoch = 0; + if (dd->type == DETECT_TLS_TYPE_NOTBEFORE) + cert_epoch = connp->cert0_not_before; + else if (dd->type == DETECT_TLS_TYPE_NOTAFTER) + cert_epoch = connp->cert0_not_after; + + if (cert_epoch == 0) + SCReturnInt(0); + + if ((dd->mode & DETECT_TLS_VALIDITY_EQ) && cert_epoch == dd->epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_LT) && cert_epoch <= dd->epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_GT) && cert_epoch >= dd->epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_RA) && cert_epoch >= dd->epoch && + cert_epoch <= dd->epoch2) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_EX) && (time_t)SCTIME_SECS(f->lastts) > cert_epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_VA) && (time_t)SCTIME_SECS(f->lastts) <= cert_epoch) + ret = 1; + + SCReturnInt(ret); +} + +/** + * \internal + * \brief Function to check if string is epoch. + * + * \param string Date string. + * + * \retval epoch time on success. + * \retval LONG_MIN on failure. + */ +static time_t StringIsEpoch(char *string) +{ + if (strlen(string) == 0) + return LONG_MIN; + + /* We assume that the date string is epoch if it consists of only + digits. */ + char *sp = string; + while (*sp) { + if (isdigit(*sp++) == 0) + return LONG_MIN; + } + + return strtol(string, NULL, 10); +} + +/** + * \internal + * \brief Function to convert date string to epoch. + * + * \param string Date string. + * + * \retval epoch on success. + * \retval 0 on failure. + */ +static time_t DateStringToEpoch(char *string) +{ + int r = 0; + struct tm tm; + const char *patterns[] = { + /* ISO 8601 */ + "%Y-%m", + "%Y-%m-%d", + "%Y-%m-%d %H", + "%Y-%m-%d %H:%M", + "%Y-%m-%d %H:%M:%S", + "%Y-%m-%dT%H", + "%Y-%m-%dT%H:%M", + "%Y-%m-%dT%H:%M:%S", + "%H:%M", + "%H:%M:%S", + }; + + /* Skip leading whitespace. */ + while (isspace(*string)) + string++; + + size_t inlen, oldlen; + + oldlen = inlen = strlen(string); + + /* Skip trailing whitespace */ + while (inlen > 0 && isspace(string[inlen - 1])) + inlen--; + + char tmp[inlen + 1]; + + if (inlen < oldlen) { + strlcpy(tmp, string, inlen + 1); + string = tmp; + } + + time_t epoch = StringIsEpoch(string); + if (epoch != LONG_MIN) { + return epoch; + } + + r = SCStringPatternToTime(string, patterns, 10, &tm); + + if (r != 0) + return LONG_MIN; + + return SCMkTimeUtc(&tm); +} + +/** + * \internal + * \brief Function to parse options passed via tls validity keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectTlsValidityData on success. + * \retval NULL on failure. + */ +static DetectTlsValidityData *DetectTlsValidityParse(const char *rawstr) +{ + DetectTlsValidityData *dd = NULL; + char mode[2] = ""; + char value1[20] = ""; + char value2[20] = ""; + char range[3] = ""; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); + if (ret < 3 || ret > 5) { + SCLogError("Parse error %s", rawstr); + goto error; + } + + size_t pcre2len = sizeof(mode); + int res = SC_Pcre2SubstringCopy(match, 1, (PCRE2_UCHAR8 *)mode, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + SCLogDebug("mode \"%s\"", mode); + + pcre2len = sizeof(value1); + res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)value1, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + SCLogDebug("value1 \"%s\"", value1); + + if (ret > 3) { + pcre2len = sizeof(range); + res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)range, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + SCLogDebug("range \"%s\"", range); + + if (ret > 4) { + pcre2len = sizeof(value2); + res = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)value2, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + SCLogDebug("value2 \"%s\"", value2); + } + } + + dd = SCMalloc(sizeof(DetectTlsValidityData)); + if (unlikely(dd == NULL)) + goto error; + + dd->epoch = 0; + dd->epoch2 = 0; + dd->mode = 0; + + if (strlen(mode) > 0) { + if (mode[0] == '<') + dd->mode |= DETECT_TLS_VALIDITY_LT; + else if (mode[0] == '>') + dd->mode |= DETECT_TLS_VALIDITY_GT; + } + + if (strlen(range) > 0) { + if (strcmp("<>", range) == 0) + dd->mode |= DETECT_TLS_VALIDITY_RA; + } + + if (strlen(range) != 0 && strlen(mode) != 0) { + SCLogError("Range specified but mode also set"); + goto error; + } + + if (dd->mode == 0) { + dd->mode |= DETECT_TLS_VALIDITY_EQ; + } + + /* set the first value */ + dd->epoch = DateStringToEpoch(value1); + if (dd->epoch == LONG_MIN) + goto error; + + /* set the second value if specified */ + if (strlen(value2) > 0) { + if (!(dd->mode & DETECT_TLS_VALIDITY_RA)) { + SCLogError("Multiple tls validity values specified but mode is not range"); + goto error; + } + + dd->epoch2 = DateStringToEpoch(value2); + if (dd->epoch2 == LONG_MIN) + goto error; + + if (dd->epoch2 <= dd->epoch) { + SCLogError("Second value in range must not be smaller than the first"); + goto error; + } + } + pcre2_match_data_free(match); + return dd; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (dd) + SCFree(dd); + return NULL; +} + +/** + * \brief Function to add the parsed tls_cert_expired into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsExpiredSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectTlsValidityData *dd = NULL; + + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); + if (dd == NULL) { + SCLogError("Allocation \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + dd->mode = DETECT_TLS_VALIDITY_EX; + dd->type = DETECT_TLS_TYPE_NOTAFTER; + dd->epoch = 0; + dd->epoch2 = 0; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_EXPIRED, (SigMatchCtx *)dd, + g_tls_validity_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectTlsValidityFree(de_ctx, dd); + return -1; +} + +/** + * \brief Function to add the parsed tls_cert_valid into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsValidSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + DetectTlsValidityData *dd = NULL; + + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); + if (dd == NULL) { + SCLogError("Allocation \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + dd->mode = DETECT_TLS_VALIDITY_VA; + dd->type = DETECT_TLS_TYPE_NOTAFTER; + dd->epoch = 0; + dd->epoch2 = 0; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_VALID, (SigMatchCtx *)dd, + g_tls_validity_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectTlsValidityFree(de_ctx, dd); + return -1; +} + +/** + * \brief Function to add the parsed tls_notbefore into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsNotBeforeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + uint8_t type = DETECT_TLS_TYPE_NOTBEFORE; + int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); + + SCReturnInt(r); +} + +/** + * \brief Function to add the parsed tls_notafter into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsNotAfterSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + uint8_t type = DETECT_TLS_TYPE_NOTAFTER; + int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); + + SCReturnInt(r); +} + +/** + * \brief Function to add the parsed tls validity field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsValiditySetup( + DetectEngineCtx *de_ctx, Signature *s, const char *rawstr, uint8_t type) +{ + DetectTlsValidityData *dd = NULL; + + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + dd = DetectTlsValidityParse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (type == DETECT_TLS_TYPE_NOTBEFORE) { + dd->type = DETECT_TLS_TYPE_NOTBEFORE; + } else if (type == DETECT_TLS_TYPE_NOTAFTER) { + dd->type = DETECT_TLS_TYPE_NOTAFTER; + } else { + goto error; + } + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_NOTAFTER, (SigMatchCtx *)dd, + g_tls_validity_buffer_id) == NULL) { + goto error; + } + return 0; + +error: + DetectTlsValidityFree(de_ctx, dd); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectTlsValidityData. + * + * \param de_ptr Pointer to DetectTlsValidityData. + */ +void DetectTlsValidityFree(DetectEngineCtx *de_ctx, void *de_ptr) +{ + DetectTlsValidityData *dd = (DetectTlsValidityData *)de_ptr; + if (dd) + SCFree(dd); +} + +#ifdef UNITTESTS +#include "tests/detect-tls-cert-validity.c" +#endif diff --git a/src/app-layer/tls/detect-cert-validity.h b/src/app-layer/tls/detect-cert-validity.h new file mode 100644 index 000000000000..8d7b3c88355c --- /dev/null +++ b/src/app-layer/tls/detect-cert-validity.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_VALIDITY_H__ +#define __DETECT_TLS_VALIDITY_H__ + +#define DETECT_TLS_VALIDITY_EQ (1) /* equal */ +#define DETECT_TLS_VALIDITY_LT (1 << 1) /* less than */ +#define DETECT_TLS_VALIDITY_GT (1 << 2) /* greater than */ +#define DETECT_TLS_VALIDITY_RA (1 << 3) /* range */ + +/* Used by tls_cert_expired */ +#define DETECT_TLS_VALIDITY_EX (1 << 4) /* expired */ + +/* Used by tls_cert_valid */ +#define DETECT_TLS_VALIDITY_VA (1 << 5) /* valid */ + +#define DETECT_TLS_TYPE_NOTBEFORE 0 +#define DETECT_TLS_TYPE_NOTAFTER 1 + +typedef struct DetectTlsValidityData_ { + time_t epoch; + time_t epoch2; + uint8_t mode; + uint8_t type; +} DetectTlsValidityData; + +/* prototypes */ +void DetectTlsValidityRegister(void); + +#endif /* __DETECT_TLS_VALIDITY_H__ */ diff --git a/src/app-layer/tls/detect-certs.c b/src/app-layer/tls/detect-certs.c new file mode 100644 index 000000000000..08f72bb02b89 --- /dev/null +++ b/src/app-layer/tls/detect-certs.c @@ -0,0 +1,356 @@ +/* Copyright (C) 2019-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls.certs keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-certs.h" +#include "detect-engine-uint.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/profiling.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsCertsSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectTlsCertsRegisterTests(void); +#endif +static uint8_t DetectEngineInspectTlsCerts(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); +static int PrefilterMpmTlsCertsRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, + const DetectBufferMpmRegistry *mpm_reg, int list_id); + +static int g_tls_certs_buffer_id = 0; + +struct TlsCertsGetDataArgs { + uint32_t local_id; /**< used as index into thread inspect array */ + SSLCertsChain *cert; +}; + +typedef struct PrefilterMpmTlsCerts { + int list_id; + const MpmCtx *mpm_ctx; + const DetectEngineTransforms *transforms; +} PrefilterMpmTlsCerts; + +/** + * \brief Registration function for keyword: tls.certs + */ +void DetectTlsCertsRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERTS].name = "tls.certs"; + sigmatch_table[DETECT_AL_TLS_CERTS].desc = "sticky buffer to match the TLS certificate buffer"; + sigmatch_table[DETECT_AL_TLS_CERTS].url = "/rules/tls-keywords.html#tls-certs"; + sigmatch_table[DETECT_AL_TLS_CERTS].Setup = DetectTlsCertsSetup; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_CERTS].RegisterTests = DetectTlsCertsRegisterTests; +#endif + sigmatch_table[DETECT_AL_TLS_CERTS].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_CERTS].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("tls.certs", ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectTlsCerts, NULL); + + DetectAppLayerMpmRegister2("tls.certs", SIG_FLAG_TOCLIENT, 2, PrefilterMpmTlsCertsRegister, + NULL, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectAppLayerInspectEngineRegister2("tls.certs", ALPROTO_TLS, SIG_FLAG_TOSERVER, + TLS_STATE_CERT_READY, DetectEngineInspectTlsCerts, NULL); + + DetectAppLayerMpmRegister2("tls.certs", SIG_FLAG_TOSERVER, 2, PrefilterMpmTlsCertsRegister, + NULL, ALPROTO_TLS, TLS_STATE_CERT_READY); + + DetectBufferTypeSetDescriptionByName("tls.certs", "TLS certificate"); + + DetectBufferTypeSupportsMultiInstance("tls.certs"); + + g_tls_certs_buffer_id = DetectBufferTypeGetByName("tls.certs"); +} + +/** + * \brief This function setup the tls.certs modifier keyword + * + * \param de_ctx Pointer to the Detect Engine Context + * \param s Pointer to the Signature to which the keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsCertsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_certs_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *TlsCertsGetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, struct TlsCertsGetDataArgs *cbdata, + int list_id) +{ + SCEnter(); + + InspectionBuffer *buffer = + InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); + if (buffer == NULL || buffer->initialized) + return buffer; + + const SSLState *ssl_state = (SSLState *)f->alstate; + const SSLStateConnp *connp; + + if (f->flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (TAILQ_EMPTY(&connp->certs)) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + if (cbdata->cert == NULL) { + cbdata->cert = TAILQ_FIRST(&connp->certs); + } else { + cbdata->cert = TAILQ_NEXT(cbdata->cert, next); + } + if (cbdata->cert == NULL) { + InspectionBufferSetupMultiEmpty(buffer); + return NULL; + } + + InspectionBufferSetupMulti(buffer, transforms, cbdata->cert->cert_data, cbdata->cert->cert_len); + + SCReturnPtr(buffer, "InspectionBuffer"); +} + +static uint8_t DetectEngineInspectTlsCerts(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + const DetectEngineTransforms *transforms = NULL; + if (!engine->mpm) { + transforms = engine->v2.transforms; + } + + struct TlsCertsGetDataArgs cbdata = { 0, NULL }; + + while (1) { + InspectionBuffer *buffer = + TlsCertsGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); + if (buffer == NULL || buffer->inspect == NULL) + break; + + const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, + (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); + if (match) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } + + cbdata.local_id++; + } + + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static void PrefilterTxTlsCerts(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) +{ + SCEnter(); + + const PrefilterMpmTlsCerts *ctx = (const PrefilterMpmTlsCerts *)pectx; + const MpmCtx *mpm_ctx = ctx->mpm_ctx; + const int list_id = ctx->list_id; + + struct TlsCertsGetDataArgs cbdata = { 0, NULL }; + + while (1) { + InspectionBuffer *buffer = TlsCertsGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); + if (buffer == NULL) + break; + + if (buffer->inspect_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); + PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); + } + + cbdata.local_id++; + } +} + +static void PrefilterMpmTlsCertsFree(void *ptr) +{ + SCFree(ptr); +} + +static int PrefilterMpmTlsCertsRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, + const DetectBufferMpmRegistry *mpm_reg, int list_id) +{ + PrefilterMpmTlsCerts *pectx = SCCalloc(1, sizeof(*pectx)); + if (pectx == NULL) + return -1; + + pectx->list_id = list_id; + pectx->mpm_ctx = mpm_ctx; + pectx->transforms = &mpm_reg->transforms; + + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxTlsCerts, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmTlsCertsFree, mpm_reg->name); +} + +static int g_tls_cert_buffer_id = 0; +#define BUFFER_NAME "tls_validity" +#define KEYWORD_ID DETECT_AL_TLS_CHAIN_LEN +#define KEYWORD_NAME "tls.cert_chain_len" +#define KEYWORD_DESC "match TLS certificate chain length" +#define KEYWORD_URL "/rules/tls-keywords.html#tls-cert-chain-len" + +/** + * \internal + * \brief Function to match cert chain length in TLS + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectU64Data. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectTLSCertChainLenMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + SSLState *ssl_state = state; + if (flags & STREAM_TOCLIENT) { + SSLStateConnp *connp = &ssl_state->server_connp; + uint32_t cnt = 0; + SSLCertsChain *cert; + TAILQ_FOREACH (cert, &connp->certs, next) { + cnt++; + } + SCLogDebug("%u certs in chain", cnt); + + const DetectU32Data *dd = (const DetectU32Data *)ctx; + if (DetectU32Match(cnt, dd)) { + SCReturnInt(1); + } + } + SCReturnInt(0); +} + +/** + * \internal + * \brief Function to free memory associated with DetectU64Data. + * + * \param de_ptr Pointer to DetectU64Data. + */ +static void DetectTLSCertChainLenFree(DetectEngineCtx *de_ctx, void *ptr) +{ + rs_detect_u32_free(ptr); +} + +/** + * \brief Function to add the parsed tls cert chain len field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTLSCertChainLenSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +{ + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + DetectU32Data *dd = DetectU32Parse(rawstr); + if (dd == NULL) { + SCLogError("Parsing \'%s\' failed for %s", rawstr, sigmatch_table[KEYWORD_ID].name); + return -1; + } + + if (SigMatchAppendSMToList(de_ctx, s, KEYWORD_ID, (SigMatchCtx *)dd, g_tls_cert_buffer_id) == + NULL) { + rs_detect_u32_free(dd); + return -1; + } + return 0; +} + +void DetectTlsCertChainLenRegister(void) +{ + sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; + sigmatch_table[KEYWORD_ID].desc = KEYWORD_DESC; + sigmatch_table[KEYWORD_ID].url = KEYWORD_URL; + sigmatch_table[KEYWORD_ID].AppLayerTxMatch = DetectTLSCertChainLenMatch; + sigmatch_table[KEYWORD_ID].Setup = DetectTLSCertChainLenSetup; + sigmatch_table[KEYWORD_ID].Free = DetectTLSCertChainLenFree; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); + + g_tls_cert_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} + +#ifdef UNITTESTS +#include "tests/detect-tls-certs.c" +#endif diff --git a/src/detect-tls-certs.h b/src/app-layer/tls/detect-certs.h similarity index 100% rename from src/detect-tls-certs.h rename to src/app-layer/tls/detect-certs.h diff --git a/src/app-layer/tls/detect-ja3-hash.c b/src/app-layer/tls/detect-ja3-hash.c new file mode 100644 index 000000000000..c021637db796 --- /dev/null +++ b/src/app-layer/tls/detect-ja3-hash.c @@ -0,0 +1,220 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for ja3.hash keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-ja3-hash.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" +#include "util/ja3.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsJa3HashSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static void DetectTlsJa3HashSetupCallback(const DetectEngineCtx *de_ctx, Signature *s); +static bool DetectTlsJa3HashValidateCallback(const Signature *s, const char **sigerror); +static int g_tls_ja3_hash_buffer_id = 0; + +/** + * \brief Registration function for keyword: ja3_hash + */ +void DetectTlsJa3HashRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_JA3_HASH].name = "ja3.hash"; + sigmatch_table[DETECT_AL_TLS_JA3_HASH].alias = "ja3_hash"; + sigmatch_table[DETECT_AL_TLS_JA3_HASH].desc = "sticky buffer to match the JA3 hash buffer"; + sigmatch_table[DETECT_AL_TLS_JA3_HASH].url = "/rules/ja3-keywords.html#ja3-hash"; + sigmatch_table[DETECT_AL_TLS_JA3_HASH].Setup = DetectTlsJa3HashSetup; + sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("ja3.hash", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2( + "ja3.hash", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0); + + DetectAppLayerMpmRegister2("ja3.hash", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + Ja3DetectGetHash, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2("ja3.hash", ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, Ja3DetectGetHash); + + DetectBufferTypeSetDescriptionByName("ja3.hash", "TLS JA3 hash"); + + DetectBufferTypeRegisterSetupCallback("ja3.hash", DetectTlsJa3HashSetupCallback); + + DetectBufferTypeRegisterValidateCallback("ja3.hash", DetectTlsJa3HashValidateCallback); + + g_tls_ja3_hash_buffer_id = DetectBufferTypeGetByName("ja3.hash"); +} + +/** + * \brief this function setup the ja3.hash modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + * \retval -2 on failure that should be silent after the first + */ +static int DetectTlsJa3HashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3_hash_buffer_id) < 0) + return -1; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { + SCLogError("rule contains conflicting protocols."); + return -1; + } + + /* try to enable JA3 */ + SSLEnableJA3(); + + /* Check if JA3 is disabled */ + if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3_HASH)) { + SCLogError("ja3 support is not enabled"); + } + return -2; + } + s->init_data->init_flags |= SIG_FLAG_INIT_JA3; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + + if (ssl_state->client_connp.ja3_hash == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(ssl_state->client_connp.ja3_hash); + const uint8_t *data = (uint8_t *)ssl_state->client_connp.ja3_hash; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static bool DetectTlsJa3HashValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3_hash_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = "ja3.hash should not be used together with " + "nocase, since the rule is automatically " + "lowercased anyway which makes nocase redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + } + + if (cd->content_len == SC_MD5_HEX_LEN) + return true; + + *sigerror = "Invalid length of the specified JA3 hash (should " + "be 32 characters long). This rule will therefore " + "never match."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + return false; + } + } + return true; +} + +static void DetectTlsJa3HashSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3_hash_buffer_id) + continue; + SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + DetectContentData *cd = (DetectContentData *)sm->ctx; + + bool changed = false; + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) { + cd->content[u] = u8_tolower(cd->content[u]); + changed = true; + } + } + + /* recreate the context if changes were made */ + if (changed) { + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = + SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); + } + } + } +} diff --git a/src/detect-tls-ja3-hash.h b/src/app-layer/tls/detect-ja3-hash.h similarity index 100% rename from src/detect-tls-ja3-hash.h rename to src/app-layer/tls/detect-ja3-hash.h diff --git a/src/app-layer/tls/detect-ja3-string.c b/src/app-layer/tls/detect-ja3-string.c new file mode 100644 index 000000000000..03252d1be4e4 --- /dev/null +++ b/src/app-layer/tls/detect-ja3-string.c @@ -0,0 +1,151 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for ja3.string keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-ja3-string.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" +#include "util/ja3.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsJa3StringSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static int g_tls_ja3_str_buffer_id = 0; + +/** + * \brief Registration function for keyword: ja3.string + */ +void DetectTlsJa3StringRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_JA3_STRING].name = "ja3.string"; + sigmatch_table[DETECT_AL_TLS_JA3_STRING].alias = "ja3_string"; + sigmatch_table[DETECT_AL_TLS_JA3_STRING].desc = "sticky buffer to match the JA3 string buffer"; + sigmatch_table[DETECT_AL_TLS_JA3_STRING].url = "/rules/ja3-keywords.html#ja3-string"; + sigmatch_table[DETECT_AL_TLS_JA3_STRING].Setup = DetectTlsJa3StringSetup; + sigmatch_table[DETECT_AL_TLS_JA3_STRING].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_JA3_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("ja3.string", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("ja3.string", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_TLS, 0); + + DetectAppLayerMpmRegister2("ja3.string", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + Ja3DetectGetString, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2("ja3.string", ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, + DetectEngineInspectBufferGeneric, Ja3DetectGetString); + + DetectBufferTypeSetDescriptionByName("ja3.string", "TLS JA3 string"); + + g_tls_ja3_str_buffer_id = DetectBufferTypeGetByName("ja3.string"); +} + +/** + * \brief this function setup the ja3.string modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsJa3StringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3_str_buffer_id) < 0) + return -1; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { + SCLogError("rule contains conflicting protocols."); + return -1; + } + + /* try to enable JA3 */ + SSLEnableJA3(); + + /* Check if JA3 is disabled */ + if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3_STRING)) { + SCLogError("ja3(s) support is not enabled"); + } + return -2; + } + s->init_data->init_flags |= SIG_FLAG_INIT_JA3; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + + if (ssl_state->client_connp.ja3_str == NULL || + ssl_state->client_connp.ja3_str->data == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(ssl_state->client_connp.ja3_str->data); + const uint8_t *data = (uint8_t *)ssl_state->client_connp.ja3_str->data; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} diff --git a/src/detect-tls-ja3-string.h b/src/app-layer/tls/detect-ja3-string.h similarity index 100% rename from src/detect-tls-ja3-string.h rename to src/app-layer/tls/detect-ja3-string.h diff --git a/src/app-layer/tls/detect-ja3s-hash.c b/src/app-layer/tls/detect-ja3s-hash.c new file mode 100644 index 000000000000..f4219754bd9d --- /dev/null +++ b/src/app-layer/tls/detect-ja3s-hash.c @@ -0,0 +1,218 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for ja3s.hash keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-ja3s-hash.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" +#include "util/ja3.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsJa3SHashSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static void DetectTlsJa3SHashSetupCallback(const DetectEngineCtx *de_ctx, Signature *s); +static bool DetectTlsJa3SHashValidateCallback(const Signature *s, const char **sigerror); +static int g_tls_ja3s_hash_buffer_id = 0; + +/** + * \brief Registration function for keyword: ja3s.hash + */ +void DetectTlsJa3SHashRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_JA3S_HASH].name = "ja3s.hash"; + sigmatch_table[DETECT_AL_TLS_JA3S_HASH].desc = "sticky buffer to match the JA3S hash buffer"; + sigmatch_table[DETECT_AL_TLS_JA3S_HASH].url = "/rules/ja3-keywords.html#ja3s-hash"; + sigmatch_table[DETECT_AL_TLS_JA3S_HASH].Setup = DetectTlsJa3SHashSetup; + sigmatch_table[DETECT_AL_TLS_JA3S_HASH].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_JA3S_HASH].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("ja3s.hash", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("ja3s.hash", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_TLS, 0); + + DetectAppLayerMpmRegister2("ja3s.hash", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + Ja3DetectGetHash, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2("ja3s.hash", ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, Ja3DetectGetHash); + + DetectBufferTypeSetDescriptionByName("ja3s.hash", "TLS JA3S hash"); + + DetectBufferTypeRegisterSetupCallback("ja3s.hash", DetectTlsJa3SHashSetupCallback); + + DetectBufferTypeRegisterValidateCallback("ja3s.hash", DetectTlsJa3SHashValidateCallback); + + g_tls_ja3s_hash_buffer_id = DetectBufferTypeGetByName("ja3s.hash"); +} + +/** + * \brief this function setup the ja3s.hash modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsJa3SHashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3s_hash_buffer_id) < 0) + return -1; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { + SCLogError("rule contains conflicting protocols."); + return -1; + } + + /* try to enable JA3 */ + SSLEnableJA3(); + + /* Check if JA3 is disabled */ + if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3S_HASH)) { + SCLogError("ja3(s) support is not enabled"); + } + return -2; + } + s->init_data->init_flags |= SIG_FLAG_INIT_JA3; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + + if (ssl_state->server_connp.ja3_hash == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(ssl_state->server_connp.ja3_hash); + const uint8_t *data = (uint8_t *)ssl_state->server_connp.ja3_hash; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static bool DetectTlsJa3SHashValidateCallback(const Signature *s, const char **sigerror) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3s_hash_buffer_id) + continue; + const SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_NOCASE) { + *sigerror = "ja3s.hash should not be used together with " + "nocase, since the rule is automatically " + "lowercased anyway which makes nocase redundant."; + SCLogWarning("rule %u: %s", s->id, *sigerror); + } + + if (cd->content_len == SC_MD5_HEX_LEN) + return true; + + *sigerror = "Invalid length of the specified JA3S hash (should " + "be 32 characters long). This rule will therefore " + "never match."; + SCLogError("rule %u: %s", s->id, *sigerror); + return false; + } + } + return true; +} + +static void DetectTlsJa3SHashSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) +{ + for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { + if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3s_hash_buffer_id) + continue; + SigMatch *sm = s->init_data->buffers[x].head; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + DetectContentData *cd = (DetectContentData *)sm->ctx; + + bool changed = false; + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) { + cd->content[u] = u8_tolower(cd->content[u]); + changed = true; + } + } + + /* recreate the context if changes were made */ + if (changed) { + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = + SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); + } + } + } +} diff --git a/src/detect-tls-ja3s-hash.h b/src/app-layer/tls/detect-ja3s-hash.h similarity index 100% rename from src/detect-tls-ja3s-hash.h rename to src/app-layer/tls/detect-ja3s-hash.h diff --git a/src/app-layer/tls/detect-ja3s-string.c b/src/app-layer/tls/detect-ja3s-string.c new file mode 100644 index 000000000000..996cd02257b5 --- /dev/null +++ b/src/app-layer/tls/detect-ja3s-string.c @@ -0,0 +1,151 @@ +/* Copyright (C) 2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for ja3s.string keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "app-layer/tls/detect-ja3s-string.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" +#include "util/ja3.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsJa3SStringSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static int g_tls_ja3s_str_buffer_id = 0; + +/** + * \brief Registration function for keyword: ja3s.string + */ +void DetectTlsJa3SStringRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_JA3S_STRING].name = "ja3s.string"; + sigmatch_table[DETECT_AL_TLS_JA3S_STRING].desc = + "sticky buffer to match the JA3S string buffer"; + sigmatch_table[DETECT_AL_TLS_JA3S_STRING].url = "/rules/ja3-keywords.html#ja3s-string"; + sigmatch_table[DETECT_AL_TLS_JA3S_STRING].Setup = DetectTlsJa3SStringSetup; + sigmatch_table[DETECT_AL_TLS_JA3S_STRING].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_JA3S_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("ja3s.string", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2("ja3s.string", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetData, ALPROTO_TLS, 0); + + DetectAppLayerMpmRegister2("ja3s.string", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + Ja3DetectGetString, ALPROTO_QUIC, 1); + + DetectAppLayerInspectEngineRegister2("ja3s.string", ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectBufferGeneric, Ja3DetectGetString); + + DetectBufferTypeSetDescriptionByName("ja3s.string", "TLS JA3S string"); + + g_tls_ja3s_str_buffer_id = DetectBufferTypeGetByName("ja3s.string"); +} + +/** + * \brief this function setup the ja3s.string modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsJa3SStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3s_str_buffer_id) < 0) + return -1; + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { + SCLogError("rule contains conflicting protocols."); + return -1; + } + + /* try to enable JA3 */ + SSLEnableJA3(); + + /* Check if JA3 is disabled */ + if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { + if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3S_STRING)) { + SCLogError("ja3(s) support is not enabled"); + } + return -2; + } + s->init_data->init_flags |= SIG_FLAG_INIT_JA3; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + + if (ssl_state->server_connp.ja3_str == NULL || + ssl_state->server_connp.ja3_str->data == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(ssl_state->server_connp.ja3_str->data); + const uint8_t *data = (uint8_t *)ssl_state->server_connp.ja3_str->data; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} diff --git a/src/detect-tls-ja3s-string.h b/src/app-layer/tls/detect-ja3s-string.h similarity index 100% rename from src/detect-tls-ja3s-string.h rename to src/app-layer/tls/detect-ja3s-string.h diff --git a/src/app-layer/tls/detect-random.c b/src/app-layer/tls/detect-random.c new file mode 100644 index 000000000000..f888af2b7bac --- /dev/null +++ b/src/app-layer/tls/detect-random.c @@ -0,0 +1,283 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" + +#include "flow.h" +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" +#include "detect-engine-prefilter.h" +#include "app-layer/tls/detect-random.h" + +#define DETECT_TLS_RANDOM_TIME_LEN 4 +#define DETECT_TLS_RANDOM_BYTES_LEN 28 + +static int DetectTlsRandomTimeSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectTlsRandomBytesSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectTlsRandomSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetRandomTimeData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetRandomBytesData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static InspectionBuffer *GetRandomData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); + +static int g_tls_random_time_buffer_id = 0; +static int g_tls_random_bytes_buffer_id = 0; +static int g_tls_random_buffer_id = 0; + +void DetectTlsRandomTimeRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].name = "tls.random_time"; + sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].desc = "sticky buffer to match specifically and only " + "on the first 4 bytes of a TLS random buffer"; + sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].url = "/rules/tls-keywords.html#tls-random-time"; + sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].Setup = DetectTlsRandomTimeSetup; + sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + /* Register engine for Server random */ + DetectAppLayerInspectEngineRegister2("tls.random_time", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetRandomTimeData); + DetectAppLayerMpmRegister2("tls.random_time", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRandomTimeData, ALPROTO_TLS, 0); + + /* Register engine for Client random */ + DetectAppLayerInspectEngineRegister2("tls.random_time", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetRandomTimeData); + DetectAppLayerMpmRegister2("tls.random_time", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetRandomTimeData, ALPROTO_TLS, 0); + + DetectBufferTypeSetDescriptionByName("tls.random_time", "TLS Random Time"); + + g_tls_random_time_buffer_id = DetectBufferTypeGetByName("tls.random_time"); +} + +void DetectTlsRandomBytesRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].name = "tls.random_bytes"; + sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].desc = + "sticky buffer to match specifically and only on the last 28 bytes of a TLS random " + "buffer"; + sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].url = "/rules/tls-keywords.html#tls-random-bytes"; + sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].Setup = DetectTlsRandomBytesSetup; + sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].flags |= + SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + /* Register engine for Server random */ + DetectAppLayerInspectEngineRegister2("tls.random_bytes", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetRandomBytesData); + DetectAppLayerMpmRegister2("tls.random_bytes", SIG_FLAG_TOSERVER, 2, + PrefilterGenericMpmRegister, GetRandomBytesData, ALPROTO_TLS, 0); + + /* Register engine for Client random */ + DetectAppLayerInspectEngineRegister2("tls.random_bytes", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetRandomBytesData); + DetectAppLayerMpmRegister2("tls.random_bytes", SIG_FLAG_TOCLIENT, 2, + PrefilterGenericMpmRegister, GetRandomBytesData, ALPROTO_TLS, 0); + + DetectBufferTypeSetDescriptionByName("tls.random_bytes", "TLS Random Bytes"); + + g_tls_random_bytes_buffer_id = DetectBufferTypeGetByName("tls.random_bytes"); +} + +/** + * \brief Registration function for keyword: tls.random + */ +void DetectTlsRandomRegister(void) +{ + DetectTlsRandomTimeRegister(); + DetectTlsRandomBytesRegister(); + + sigmatch_table[DETECT_AL_TLS_RANDOM].name = "tls.random"; + sigmatch_table[DETECT_AL_TLS_RANDOM].desc = + "sticky buffer to match specifically and only on a TLS random buffer"; + sigmatch_table[DETECT_AL_TLS_RANDOM].url = "/rules/tls-keywords.html#tls-random"; + sigmatch_table[DETECT_AL_TLS_RANDOM].Setup = DetectTlsRandomSetup; + sigmatch_table[DETECT_AL_TLS_RANDOM].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + /* Register engine for Server random */ + DetectAppLayerInspectEngineRegister2("tls.random", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetRandomData); + DetectAppLayerMpmRegister2("tls.random", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetRandomData, ALPROTO_TLS, 0); + + /* Register engine for Client random */ + DetectAppLayerInspectEngineRegister2("tls.random", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetRandomData); + DetectAppLayerMpmRegister2("tls.random", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetRandomData, ALPROTO_TLS, 0); + + DetectBufferTypeSetDescriptionByName("tls.random", "TLS Random"); + + g_tls_random_buffer_id = DetectBufferTypeGetByName("tls.random"); +} + +/** + * \brief this function setup the tls.random_time sticky buffer keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsRandomTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_random_time_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +/** + * \brief this function setup the tls.random_bytes sticky buffer keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsRandomBytesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_random_bytes_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +/** + * \brief this function setup the tls.random sticky buffer keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsRandomSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_random_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetRandomTimeData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + if (flow_flags & STREAM_TOSERVER) { + if (!(ssl_state->flags & TLS_TS_RANDOM_SET)) + return NULL; + } else { + if (!(ssl_state->flags & TLS_TC_RANDOM_SET)) + return NULL; + } + const uint32_t data_len = DETECT_TLS_RANDOM_TIME_LEN; + const uint8_t *data; + if (flow_flags & STREAM_TOSERVER) { + data = ssl_state->server_connp.random; + } else { + data = ssl_state->client_connp.random; + } + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +static InspectionBuffer *GetRandomBytesData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + if (flow_flags & STREAM_TOSERVER) { + if (!(ssl_state->flags & TLS_TS_RANDOM_SET)) + return NULL; + } else { + if (!(ssl_state->flags & TLS_TC_RANDOM_SET)) + return NULL; + } + const uint32_t data_len = DETECT_TLS_RANDOM_BYTES_LEN; + const uint8_t *data; + if (flow_flags & STREAM_TOSERVER) { + data = ssl_state->server_connp.random + DETECT_TLS_RANDOM_TIME_LEN; + } else { + data = ssl_state->client_connp.random + DETECT_TLS_RANDOM_TIME_LEN; + } + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +static InspectionBuffer *GetRandomData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + if (flow_flags & STREAM_TOSERVER) { + if (!(ssl_state->flags & TLS_TS_RANDOM_SET)) + return NULL; + } else { + if (!(ssl_state->flags & TLS_TC_RANDOM_SET)) + return NULL; + } + const uint32_t data_len = TLS_RANDOM_LEN; + const uint8_t *data; + if (flow_flags & STREAM_TOSERVER) { + data = ssl_state->server_connp.random; + } else { + data = ssl_state->client_connp.random; + } + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} diff --git a/src/detect-tls-random.h b/src/app-layer/tls/detect-random.h similarity index 100% rename from src/detect-tls-random.h rename to src/app-layer/tls/detect-random.h diff --git a/src/app-layer/tls/detect-sni.c b/src/app-layer/tls/detect-sni.c new file mode 100644 index 000000000000..5efa9b8279ab --- /dev/null +++ b/src/app-layer/tls/detect-sni.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls.sni keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util/debug.h" +#include "util/spm.h" +#include "util/print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer/ssl/parser.h" +#include "detect-engine-prefilter.h" +#include "app-layer/tls/detect-sni.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" + +static int DetectTlsSniSetup(DetectEngineCtx *, Signature *, const char *); +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); +static int g_tls_sni_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls.sni + */ +void DetectTlsSniRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_SNI].name = "tls.sni"; + sigmatch_table[DETECT_AL_TLS_SNI].alias = "tls_sni"; + sigmatch_table[DETECT_AL_TLS_SNI].desc = + "sticky buffer to match specifically and only on the TLS SNI buffer"; + sigmatch_table[DETECT_AL_TLS_SNI].url = "/rules/tls-keywords.html#tls-sni"; + sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup; + sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT; + sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2("tls.sni", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetData); + + DetectAppLayerMpmRegister2( + "tls.sni", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0); + + DetectBufferTypeSetDescriptionByName("tls.sni", "TLS Server Name Indication (SNI) extension"); + + g_tls_sni_buffer_id = DetectBufferTypeGetByName("tls.sni"); +} + +/** + * \brief this function setup the tls.sni modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectBufferSetActiveList(de_ctx, s, g_tls_sni_buffer_id) < 0) + return -1; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const SSLState *ssl_state = (SSLState *)f->alstate; + + if (ssl_state->client_connp.sni == NULL) { + return NULL; + } + + const uint32_t data_len = strlen(ssl_state->client_connp.sni); + const uint8_t *data = (uint8_t *)ssl_state->client_connp.sni; + + InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} diff --git a/src/detect-tls-sni.h b/src/app-layer/tls/detect-sni.h similarity index 100% rename from src/detect-tls-sni.h rename to src/app-layer/tls/detect-sni.h diff --git a/src/app-layer/tls/detect-version.c b/src/app-layer/tls/detect-version.c new file mode 100644 index 000000000000..285353893da6 --- /dev/null +++ b/src/app-layer/tls/detect-version.c @@ -0,0 +1,268 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements the tls.version keyword + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer/ssl/parser.h" +#include "app-layer/tls/detect-version.h" + +#include "stream-tcp.h" + +/** + * \brief Regex for parsing "id" option, matching number or "number" + */ +#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9\\.]+\")\\s*$" + +static DetectParseRegex parse_regex; + +static int DetectTlsVersionMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectTlsVersionSetup(DetectEngineCtx *, Signature *, const char *); +#ifdef UNITTESTS +static void DetectTlsVersionRegisterTests(void); +#endif +static void DetectTlsVersionFree(DetectEngineCtx *, void *); +static int g_tls_generic_list_id = 0; + +/** + * \brief Registration function for keyword: tls.version + */ +void DetectTlsVersionRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_VERSION].name = "tls.version"; + sigmatch_table[DETECT_AL_TLS_VERSION].desc = "match on TLS/SSL version"; + sigmatch_table[DETECT_AL_TLS_VERSION].url = "/rules/tls-keywords.html#tls-version"; + sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerTxMatch = DetectTlsVersionMatch; + sigmatch_table[DETECT_AL_TLS_VERSION].Setup = DetectTlsVersionSetup; + sigmatch_table[DETECT_AL_TLS_VERSION].Free = DetectTlsVersionFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_AL_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests; +#endif + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); + + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); +} + +/** + * \brief match the specified version on a tls session + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectTlsVersionData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectTlsVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + + const DetectTlsVersionData *tls_data = (const DetectTlsVersionData *)m; + SSLState *ssl_state = (SSLState *)state; + if (ssl_state == NULL) { + SCLogDebug("no tls state, no match"); + SCReturnInt(0); + } + + int ret = 0; + uint16_t version = 0; + SCLogDebug("looking for tls_data->ver 0x%02X (flags 0x%02X)", tls_data->ver, flags); + + if (flags & STREAM_TOCLIENT) { + version = ssl_state->server_connp.version; + SCLogDebug("server (toclient) version is 0x%02X", version); + } else if (flags & STREAM_TOSERVER) { + version = ssl_state->client_connp.version; + SCLogDebug("client (toserver) version is 0x%02X", version); + } + + if ((tls_data->flags & DETECT_TLS_VERSION_FLAG_RAW) == 0) { + /* Match all TLSv1.3 drafts as TLSv1.3 */ + if (((version >> 8) & 0xff) == 0x7f) { + version = TLS_VERSION_13; + } + } + + if (tls_data->ver == version) { + ret = 1; + } + + SCReturnInt(ret); +} + +/** + * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" + * + * \param de_ctx Pointer to the detection engine context + * \param idstr Pointer to the user provided id option + * + * \retval id_d pointer to DetectTlsVersionData on success + * \retval NULL on failure + */ +static DetectTlsVersionData *DetectTlsVersionParse(DetectEngineCtx *de_ctx, const char *str) +{ + uint16_t temp; + DetectTlsVersionData *tls = NULL; + int res = 0; + size_t pcre2len; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); + if (ret < 1 || ret > 3) { + SCLogError("invalid tls.version option"); + goto error; + } + + if (ret > 1) { + char ver_ptr[64]; + char *tmp_str; + pcre2len = sizeof(ver_ptr); + res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)ver_ptr, &pcre2len); + if (res < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + goto error; + } + + /* We have a correct id option */ + tls = SCCalloc(1, sizeof(DetectTlsVersionData)); + if (unlikely(tls == NULL)) + goto error; + + tmp_str = ver_ptr; + + /* Let's see if we need to scape "'s */ + if (tmp_str[0] == '"') { + tmp_str[strlen(tmp_str) - 1] = '\0'; + tmp_str += 1; + } + + if (strncmp("1.0", tmp_str, 3) == 0) { + temp = TLS_VERSION_10; + } else if (strncmp("1.1", tmp_str, 3) == 0) { + temp = TLS_VERSION_11; + } else if (strncmp("1.2", tmp_str, 3) == 0) { + temp = TLS_VERSION_12; + } else if (strncmp("1.3", tmp_str, 3) == 0) { + temp = TLS_VERSION_13; + } else if ((strncmp("0x", tmp_str, 2) == 0) && (strlen(str) == 6)) { + temp = (uint16_t)strtol(tmp_str, NULL, 0); + tls->flags |= DETECT_TLS_VERSION_FLAG_RAW; + } else { + SCLogError("Invalid value"); + goto error; + } + + tls->ver = temp; + + SCLogDebug("will look for tls %" PRIu16 "", tls->ver); + } + + pcre2_match_data_free(match); + return tls; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (tls != NULL) + DetectTlsVersionFree(de_ctx, tls); + return NULL; +} + +/** + * \brief this function is used to add the parsed "id" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "id" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTlsVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + DetectTlsVersionData *tls = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + tls = DetectTlsVersionParse(de_ctx, str); + if (tls == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_VERSION, (SigMatchCtx *)tls, + g_tls_generic_list_id) == NULL) { + goto error; + } + + return 0; + +error: + if (tls != NULL) + DetectTlsVersionFree(de_ctx, tls); + return -1; +} + +/** + * \brief this function will free memory associated with DetectTlsVersionData + * + * \param id_d pointer to DetectTlsVersionData + */ +static void DetectTlsVersionFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectTlsVersionData *id_d = (DetectTlsVersionData *)ptr; + SCFree(id_d); +} + +#ifdef UNITTESTS +#include "tests/detect-tls-version.c" +#endif diff --git a/src/app-layer/tls/detect-version.h b/src/app-layer/tls/detect-version.h new file mode 100644 index 000000000000..bfcfb2466e05 --- /dev/null +++ b/src/app-layer/tls/detect-version.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_TLS_VERSION_H__ +#define __DETECT_TLS_VERSION_H__ + +#define DETECT_TLS_VERSION_FLAG_RAW BIT_U8(0) + +typedef struct DetectTlsVersionData_ { + uint16_t ver; /** tls version to match */ + uint8_t flags; +} DetectTlsVersionData; + +/* prototypes */ +void DetectTlsVersionRegister(void); + +#endif /* __DETECT_TLS_VERSION_H__ */ diff --git a/src/app-layer/tls/detect.c b/src/app-layer/tls/detect.c new file mode 100644 index 000000000000..ae2720dd11e8 --- /dev/null +++ b/src/app-layer/tls/detect.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2011-2012 ANSSI + * Copyright (C) 2022 Open Information Security Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author Pierre Chifflier + * + * Implements the tls.* keywords + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#include "app-layer.h" + +#include "app-layer/ssl/parser.h" +#include "app-layer/tls/detect.h" +#include "app-layer/tls/detect-cert-fingerprint.h" + +#include "stream-tcp.h" + +/** + * \brief Regex for parsing "id" option, matching number or "number" + */ + +#define PARSE_REGEX "^([A-z0-9\\s\\-\\.=,\\*@]+|\"[A-z0-9\\s\\-\\.=,\\*@]+\")\\s*$" +#define PARSE_REGEX_FINGERPRINT "^([A-z0-9\\:\\*]+|\"[A-z0-9\\:\\* ]+\")\\s*$" + +static DetectParseRegex subject_parse_regex; +static DetectParseRegex issuerdn_parse_regex; +static DetectParseRegex fingerprint_parse_regex; + +static int DetectTlsSubjectMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectTlsSubjectSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectTlsSubjectFree(DetectEngineCtx *, void *); + +static int DetectTlsIssuerDNMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectTlsIssuerDNSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectTlsIssuerDNFree(DetectEngineCtx *, void *); + +static int DetectTlsFingerprintSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectTlsFingerprintFree(DetectEngineCtx *, void *); + +static int DetectTlsStoreSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectTlsStorePostMatch( + DetectEngineThreadCtx *det_ctx, Packet *, const Signature *s, const SigMatchCtx *unused); + +static int g_tls_cert_list_id = 0; +static int g_tls_cert_fingerprint_list_id = 0; + +/** + * \brief Registration function for keyword: tls.version + */ +void DetectTlsRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_SUBJECT].name = "tls.subject"; + sigmatch_table[DETECT_AL_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field"; + sigmatch_table[DETECT_AL_TLS_SUBJECT].url = "/rules/tls-keywords.html#tls-subject"; + sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerTxMatch = DetectTlsSubjectMatch; + sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; + sigmatch_table[DETECT_AL_TLS_SUBJECT].Free = DetectTlsSubjectFree; + sigmatch_table[DETECT_AL_TLS_SUBJECT].flags = + SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; + sigmatch_table[DETECT_AL_TLS_SUBJECT].alternative = DETECT_AL_TLS_CERT_SUBJECT; + + sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn"; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = "/rules/tls-keywords.html#tls-issuerdn"; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerTxMatch = DetectTlsIssuerDNMatch; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].flags = + SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].alternative = DETECT_AL_TLS_CERT_ISSUER; + + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint"; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = "/rules/tls-keywords.html#tls-fingerprint"; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].flags = + SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].alternative = DETECT_AL_TLS_CERT_FINGERPRINT; + + sigmatch_table[DETECT_AL_TLS_STORE].name = "tls_store"; + sigmatch_table[DETECT_AL_TLS_STORE].alias = "tls.store"; + sigmatch_table[DETECT_AL_TLS_STORE].desc = "store TLS/SSL certificate on disk"; + sigmatch_table[DETECT_AL_TLS_STORE].url = "/rules/tls-keywords.html#tls-store"; + sigmatch_table[DETECT_AL_TLS_STORE].Match = DetectTlsStorePostMatch; + sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup; + sigmatch_table[DETECT_AL_TLS_STORE].flags |= SIGMATCH_NOOPT; + + DetectSetupParseRegexes(PARSE_REGEX, &subject_parse_regex); + DetectSetupParseRegexes(PARSE_REGEX, &issuerdn_parse_regex); + DetectSetupParseRegexes(PARSE_REGEX_FINGERPRINT, &fingerprint_parse_regex); + + g_tls_cert_list_id = DetectBufferTypeRegister("tls_cert"); + g_tls_cert_fingerprint_list_id = DetectBufferTypeRegister("tls.cert_fingerprint"); + + DetectAppLayerInspectEngineRegister2("tls_cert", ALPROTO_TLS, SIG_FLAG_TOCLIENT, + TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); + + DetectAppLayerInspectEngineRegister2("tls_cert", ALPROTO_TLS, SIG_FLAG_TOSERVER, + TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); +} + +/** + * \brief match the specified Subject on a tls session + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectTlsData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectTlsSubjectMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + + const DetectTlsData *tls_data = (const DetectTlsData *)m; + SSLState *ssl_state = (SSLState *)state; + if (ssl_state == NULL) { + SCLogDebug("no tls state, no match"); + SCReturnInt(0); + } + + int ret = 0; + + SSLStateConnp *connp = NULL; + if (flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_subject != NULL) { + SCLogDebug("TLS: Subject is [%s], looking for [%s]\n", connp->cert0_subject, + tls_data->subject); + + if (strstr(connp->cert0_subject, tls_data->subject) != NULL) { + if (tls_data->flags & DETECT_CONTENT_NEGATED) { + ret = 0; + } else { + ret = 1; + } + } else { + if (tls_data->flags & DETECT_CONTENT_NEGATED) { + ret = 1; + } else { + ret = 0; + } + } + } else { + ret = 0; + } + + SCReturnInt(ret); +} + +/** + * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" + * + * \param de_ctx Pointer to the detection engine context + * \param str Pointer to the user provided id option + * + * \retval id_d pointer to DetectTlsData on success + * \retval NULL on failure + */ +static DetectTlsData *DetectTlsSubjectParse(DetectEngineCtx *de_ctx, const char *str, bool negate) +{ + DetectTlsData *tls = NULL; + size_t pcre2_len; + const char *str_ptr; + char *orig = NULL; + char *tmp_str; + uint32_t flag = 0; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&subject_parse_regex, &match, str, 0, 0); + if (ret != 2) { + SCLogError("invalid tls.subject option"); + goto error; + } + + if (negate) + flag = DETECT_CONTENT_NEGATED; + + int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); + if (res < 0) { + SCLogError("pcre2_substring_get_bynumber failed"); + goto error; + } + + /* We have a correct id option */ + tls = SCMalloc(sizeof(DetectTlsData)); + if (unlikely(tls == NULL)) + goto error; + tls->subject = NULL; + tls->flags = flag; + + orig = SCStrdup((char *)str_ptr); + if (unlikely(orig == NULL)) { + goto error; + } + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + + tmp_str = orig; + + /* Let's see if we need to escape "'s */ + if (tmp_str[0] == '"') { + tmp_str[strlen(tmp_str) - 1] = '\0'; + tmp_str += 1; + } + + tls->subject = SCStrdup(tmp_str); + if (unlikely(tls->subject == NULL)) { + goto error; + } + + pcre2_match_data_free(match); + SCFree(orig); + + SCLogDebug("will look for TLS subject %s", tls->subject); + + return tls; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (orig != NULL) + SCFree(orig); + if (tls != NULL) + DetectTlsSubjectFree(de_ctx, tls); + return NULL; +} + +/** + * \brief this function is used to add the parsed "id" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "id" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + DetectTlsData *tls = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + tls = DetectTlsSubjectParse(de_ctx, str, s->init_data->negated); + if (tls == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList( + de_ctx, s, DETECT_AL_TLS_SUBJECT, (SigMatchCtx *)tls, g_tls_cert_list_id) == NULL) { + goto error; + } + return 0; + +error: + if (tls != NULL) + DetectTlsSubjectFree(de_ctx, tls); + return -1; +} + +/** + * \brief this function will free memory associated with DetectTlsData + * + * \param id_d pointer to DetectTlsData + */ +static void DetectTlsSubjectFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectTlsData *id_d = (DetectTlsData *)ptr; + if (ptr == NULL) + return; + if (id_d->subject != NULL) + SCFree(id_d->subject); + SCFree(id_d); +} + +/** + * \brief match the specified IssuerDN on a tls session + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectTlsData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectTlsIssuerDNMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + + const DetectTlsData *tls_data = (const DetectTlsData *)m; + SSLState *ssl_state = (SSLState *)state; + if (ssl_state == NULL) { + SCLogDebug("no tls state, no match"); + SCReturnInt(0); + } + + int ret = 0; + + SSLStateConnp *connp = NULL; + if (flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_issuerdn != NULL) { + SCLogDebug("TLS: IssuerDN is [%s], looking for [%s]\n", connp->cert0_issuerdn, + tls_data->issuerdn); + + if (strstr(connp->cert0_issuerdn, tls_data->issuerdn) != NULL) { + if (tls_data->flags & DETECT_CONTENT_NEGATED) { + ret = 0; + } else { + ret = 1; + } + } else { + if (tls_data->flags & DETECT_CONTENT_NEGATED) { + ret = 1; + } else { + ret = 0; + } + } + } else { + ret = 0; + } + + SCReturnInt(ret); +} + +/** + * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" + * + * \param de_ctx Pointer to the detection engine context + * \param str Pointer to the user provided id option + * + * \retval id_d pointer to DetectTlsData on success + * \retval NULL on failure + */ +static DetectTlsData *DetectTlsIssuerDNParse(DetectEngineCtx *de_ctx, const char *str, bool negate) +{ + DetectTlsData *tls = NULL; + size_t pcre2_len; + const char *str_ptr; + char *orig = NULL; + char *tmp_str; + uint32_t flag = 0; + + pcre2_match_data *match = NULL; + int ret = DetectParsePcreExec(&issuerdn_parse_regex, &match, str, 0, 0); + if (ret != 2) { + SCLogError("invalid tls.issuerdn option"); + goto error; + } + + if (negate) + flag = DETECT_CONTENT_NEGATED; + + int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); + if (res < 0) { + SCLogError("pcre2_substring_get_bynumber failed"); + goto error; + } + + /* We have a correct id option */ + tls = SCMalloc(sizeof(DetectTlsData)); + if (unlikely(tls == NULL)) + goto error; + tls->issuerdn = NULL; + tls->flags = flag; + + orig = SCStrdup((char *)str_ptr); + if (unlikely(orig == NULL)) { + goto error; + } + pcre2_substring_free((PCRE2_UCHAR *)str_ptr); + + tmp_str = orig; + + /* Let's see if we need to escape "'s */ + if (tmp_str[0] == '"') { + tmp_str[strlen(tmp_str) - 1] = '\0'; + tmp_str += 1; + } + + tls->issuerdn = SCStrdup(tmp_str); + if (unlikely(tls->issuerdn == NULL)) { + goto error; + } + + SCFree(orig); + + pcre2_match_data_free(match); + SCLogDebug("Will look for TLS issuerdn %s", tls->issuerdn); + + return tls; + +error: + if (match) { + pcre2_match_data_free(match); + } + if (orig != NULL) + SCFree(orig); + if (tls != NULL) + DetectTlsIssuerDNFree(de_ctx, tls); + return NULL; +} + +/** + * \brief this function is used to add the parsed "id" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "id" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTlsIssuerDNSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + DetectTlsData *tls = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + tls = DetectTlsIssuerDNParse(de_ctx, str, s->init_data->negated); + if (tls == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_ISSUERDN, (SigMatchCtx *)tls, + g_tls_cert_list_id) == NULL) { + goto error; + } + return 0; + +error: + if (tls != NULL) + DetectTlsIssuerDNFree(de_ctx, tls); + return -1; +} + +/** + * \brief this function will free memory associated with DetectTlsData + * + * \param id_d pointer to DetectTlsData + */ +static void DetectTlsIssuerDNFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectTlsData *id_d = (DetectTlsData *)ptr; + SCFree(id_d->issuerdn); + SCFree(id_d); +} + +/** + * \brief This function is used to parse fingerprint passed via keyword: "fingerprint" + * + * \param de_ctx Pointer to the detection engine context + * \param str Pointer to the user provided fingerprint option + * + * \retval pointer to DetectTlsData on success + * \retval NULL on failure + */ + +/** + * \brief this function is used to add the parsed "fingerprint" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param id pointer to the user provided "fingerprint" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTlsFingerprintSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (DetectContentSetup(de_ctx, s, str) < 0) { + return -1; + } + + if (DetectEngineContentModifierBufferSetup(de_ctx, s, NULL, DETECT_AL_TLS_CERT_FINGERPRINT, + g_tls_cert_fingerprint_list_id, ALPROTO_TLS) < 0) + return -1; + + return 0; +} + +/** + * \brief this function will free memory associated with DetectTlsData + * + * \param pointer to DetectTlsData + */ +static void DetectTlsFingerprintFree(DetectEngineCtx *de_ctx, void *ptr) +{ + DetectTlsData *id_d = (DetectTlsData *)ptr; + SCFree(id_d); +} + +/** + * \brief this function is used to add the parsed "store" option + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param idstr pointer to the user provided "store" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTlsStoreSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + s->flags |= SIG_FLAG_TLSSTORE; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_STORE, NULL, DETECT_SM_LIST_POSTMATCH) == + NULL) { + return -1; + } + return 0; +} + +/** \warning modifies Flow::alstate */ +static int DetectTlsStorePostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *unused) +{ + SCEnter(); + + if (p->flow == NULL) + return 0; + + SSLState *ssl_state = FlowGetAppState(p->flow); + if (ssl_state == NULL) { + SCLogDebug("no tls state, no match"); + SCReturnInt(0); + } + + SSLStateConnp *connp; + + if (p->flow->flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + connp->cert_log_flag |= SSL_TLS_LOG_PEM; + SCReturnInt(1); +} diff --git a/src/app-layer/tls/detect.h b/src/app-layer/tls/detect.h new file mode 100644 index 000000000000..d5b2442d1f53 --- /dev/null +++ b/src/app-layer/tls/detect.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011-2012 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author Pierre Chifflier + */ + +#ifndef __DETECT_TLS_H__ +#define __DETECT_TLS_H__ + +typedef struct DetectTlsData_ { + uint16_t ver; /** tls version to match */ + uint32_t flags; /** flags containing match variant (Negation for example) */ + char *subject; /** tls certificate subject substring to match */ + char *issuerdn; /** tls certificate issuerDN substring to match */ +} DetectTlsData; + +/* prototypes */ +void DetectTlsRegister(void); + +#endif /* __DETECT_TLS_H__ */ diff --git a/src/app-layer/tls/log-tlslog.c b/src/app-layer/tls/log-tlslog.c new file mode 100644 index 000000000000..800051a38989 --- /dev/null +++ b/src/app-layer/tls/log-tlslog.c @@ -0,0 +1,499 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Roliers Jean-Paul + * \author Eric Leblond + * \author Victor Julien + * \author Paulo Pacheco + * + * Implements TLS logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer/tls/log-tlslog.h" +#include "app-layer/ssl/parser.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" + +#include "util/logopenfile.h" +#include "util/time.h" +#include "log-cf-common.h" + +#define DEFAULT_LOG_FILENAME "tls.log" + +#define MODULE_NAME "LogTlsLog" + +#define PRINT_BUF_LEN 46 + +#define OUTPUT_BUFFER_SIZE 65535 +#define CERT_ENC_BUFFER_SIZE 2048 + +#define LOG_TLS_DEFAULT 0 +#define LOG_TLS_EXTENDED 1 +#define LOG_TLS_CUSTOM 2 + +#define LOG_TLS_SESSION_RESUMPTION 4 + +#define LOG_TLS_CF_VERSION 'v' +#define LOG_TLS_CF_DATE_NOT_BEFORE 'd' +#define LOG_TLS_CF_DATE_NOT_AFTER 'D' +#define LOG_TLS_CF_SHA1 'f' +#define LOG_TLS_CF_SNI 'n' +#define LOG_TLS_CF_SUBJECT 's' +#define LOG_TLS_CF_ISSUER 'i' +#define LOG_TLS_CF_EXTENDED 'E' + +typedef struct LogTlsFileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ + LogCustomFormat *cf; +} LogTlsFileCtx; + +typedef struct LogTlsLogThread_ { + LogTlsFileCtx *tlslog_ctx; + + /* LogTlsFileCtx has the pointer to the file and a mutex to allow + multithreading. */ + uint32_t tls_cnt; + + MemBuffer *buffer; +} LogTlsLogThread; + +int TLSGetIPInformations(const Packet *p, char *srcip, size_t srcip_len, Port *sp, char *dstip, + size_t dstip_len, Port *dp, int ipproto) +{ + if ((PKT_IS_TOSERVER(p))) { + switch (ipproto) { + case AF_INET: + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, srcip_len); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, dstip_len); + break; + case AF_INET6: + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, srcip_len); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, dstip_len); + break; + default: + return 0; + } + *sp = p->sp; + *dp = p->dp; + } else { + switch (ipproto) { + case AF_INET: + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, srcip_len); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, dstip_len); + break; + case AF_INET6: + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, srcip_len); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, dstip_len); + break; + default: + return 0; + } + *sp = p->dp; + *dp = p->sp; + } + return 1; +} + +static TmEcode LogTlsLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + LogTlsLogThread *aft = SCCalloc(1, sizeof(LogTlsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + + if (initdata == NULL) { + SCLogDebug("Error getting context for TLSLog. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Output Context (file pointer and mutex) */ + aft->tlslog_ctx = ((OutputCtx *)initdata)->data; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode LogTlsLogThreadDeinit(ThreadVars *t, void *data) +{ + LogTlsLogThread *aft = (LogTlsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->buffer); + memset(aft, 0, sizeof(LogTlsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void LogTlsLogDeInitCtx(OutputCtx *output_ctx) +{ + LogTlsFileCtx *tlslog_ctx = (LogTlsFileCtx *)output_ctx->data; + LogFileFreeCtx(tlslog_ctx->file_ctx); + LogCustomFormatFree(tlslog_ctx->cf); + SCFree(tlslog_ctx); + SCFree(output_ctx); +} + +static void LogTlsLogExitPrintStats(ThreadVars *tv, void *data) +{ + LogTlsLogThread *aft = (LogTlsLogThread *)data; + if (aft == NULL) { + return; + } + + SCLogInfo("TLS logger logged %" PRIu32 " requests", aft->tls_cnt); +} + +/** \brief Create a new tls log LogFileCtx. + * \param conf Pointer to ConfNode containing this loggers configuration. + * \return NULL if failure, LogFileCtx* to the file_ctx if succesful + * */ +static OutputInitResult LogTlsLogInitCtx(ConfNode *conf) +{ + OutputInitResult result = { NULL, false }; + LogFileCtx *file_ctx = LogFileNewCtx(); + + if (file_ctx == NULL) { + SCLogError("LogTlsLogInitCtx: Couldn't " + "create new file_ctx"); + return result; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + goto filectx_error; + } + + LogTlsFileCtx *tlslog_ctx = SCCalloc(1, sizeof(LogTlsFileCtx)); + if (unlikely(tlslog_ctx == NULL)) { + goto filectx_error; + } + tlslog_ctx->file_ctx = file_ctx; + + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + const char *custom = ConfNodeLookupChildValue(conf, "custom"); + const char *customformat = ConfNodeLookupChildValue(conf, "customformat"); + + /* If custom logging format is selected, lets parse it */ + if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { + tlslog_ctx->cf = LogCustomFormatAlloc(); + if (!tlslog_ctx->cf) { + goto tlslog_error; + } + + tlslog_ctx->flags |= LOG_TLS_CUSTOM; + + if (!LogCustomFormatParse(tlslog_ctx->cf, customformat)) { + goto parser_error; + } + } else { + if (extended == NULL) { + tlslog_ctx->flags |= LOG_TLS_DEFAULT; + } else { + if (ConfValIsTrue(extended)) { + tlslog_ctx->flags |= LOG_TLS_EXTENDED; + } + } + } + + const char *resumption = ConfNodeLookupChildValue(conf, "session-resumption"); + if (resumption == NULL || ConfValIsTrue(resumption)) { + tlslog_ctx->flags |= LOG_TLS_SESSION_RESUMPTION; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + goto tlslog_error; + } + output_ctx->data = tlslog_ctx; + output_ctx->DeInit = LogTlsLogDeInitCtx; + + SCLogDebug("TLS log output initialized"); + + /* Enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); + + result.ctx = output_ctx; + result.ok = true; + return result; + +parser_error: + SCLogError("Syntax error in custom tls log " + "format string."); +tlslog_error: + LogCustomFormatFree(tlslog_ctx->cf); + SCFree(tlslog_ctx); +filectx_error: + LogFileFreeCtx(file_ctx); + return result; +} + +static void LogTlsLogVersion(MemBuffer *buffer, uint16_t version) +{ + char ssl_version[SSL_VERSION_MAX_STRLEN]; + SSLVersionToString(version, ssl_version); + MemBufferWriteString(buffer, "VERSION='%s'", ssl_version); +} + +static void LogTlsLogDate(MemBuffer *buffer, const char *title, int64_t *date) +{ + char timebuf[64] = { 0 }; + if (sc_x509_format_timestamp(*date, timebuf, sizeof(timebuf))) { + MemBufferWriteString(buffer, "%s='%s'", title, timebuf); + } +} + +static void LogTlsLogString(MemBuffer *buffer, const char *title, const char *value) +{ + MemBufferWriteString(buffer, "%s='%s'", title, value); +} + +static void LogTlsLogBasic(LogTlsLogThread *aft, SSLState *ssl_state, const SCTime_t ts, + char *srcip, Port sp, char *dstip, Port dp) +{ + char timebuf[64]; + CreateTimeString(ts, timebuf, sizeof(timebuf)); + MemBufferWriteString(aft->buffer, "%s %s:%d -> %s:%d TLS:", timebuf, srcip, sp, dstip, dp); + + if (ssl_state->server_connp.cert0_subject != NULL) { + MemBufferWriteString(aft->buffer, " Subject='%s'", ssl_state->server_connp.cert0_subject); + } + + if (ssl_state->server_connp.cert0_issuerdn != NULL) { + MemBufferWriteString(aft->buffer, " Issuerdn='%s'", ssl_state->server_connp.cert0_issuerdn); + } + + if (ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) { + /* Only log a session as 'resumed' if a certificate has not + been seen. */ + if ((ssl_state->server_connp.cert0_issuerdn == NULL) && + (ssl_state->server_connp.cert0_subject == NULL) && + (ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && + ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { + MemBufferWriteString(aft->buffer, " Session='resumed'"); + } + } +} + +static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState *ssl_state, const SCTime_t ts, + char *srcip, Port sp, char *dstip, Port dp) +{ + if (ssl_state->server_connp.cert0_fingerprint != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SHA1", ssl_state->server_connp.cert0_fingerprint); + } + if (ssl_state->client_connp.sni != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SNI", ssl_state->client_connp.sni); + } + if (ssl_state->server_connp.cert0_serial != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SERIAL", ssl_state->server_connp.cert0_serial); + } + + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogVersion(aft->buffer, ssl_state->server_connp.version); + + if (ssl_state->server_connp.cert0_not_before != 0) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogDate(aft->buffer, "NOTBEFORE", &ssl_state->server_connp.cert0_not_before); + } + if (ssl_state->server_connp.cert0_not_after != 0) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogDate(aft->buffer, "NOTAFTER", &ssl_state->server_connp.cert0_not_after); + } +} + +/* Custom format logging */ +static void LogTlsLogCustom(LogTlsLogThread *aft, SSLState *ssl_state, const SCTime_t ts, + char *srcip, Port sp, char *dstip, Port dp) +{ + LogTlsFileCtx *tlslog_ctx = aft->tlslog_ctx; + uint32_t i; + char buf[64]; + + for (i = 0; i < tlslog_ctx->cf->cf_n; i++) { + LogCustomFormatNode *node = tlslog_ctx->cf->cf_nodes[i]; + if (!node) /* Should never happen */ + continue; + + switch (node->type) { + case LOG_CF_LITERAL: + /* LITERAL */ + MemBufferWriteString(aft->buffer, "%s", node->data); + break; + case LOG_CF_TIMESTAMP: + /* TIMESTAMP */ + LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); + break; + case LOG_CF_TIMESTAMP_U: + /* TIMESTAMP USECONDS */ + snprintf(buf, sizeof(buf), "%06u", (unsigned int)SCTIME_USECS(ts)); + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)buf, MIN(strlen(buf), 6)); + break; + case LOG_CF_CLIENT_IP: + /* CLIENT IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)srcip, strlen(srcip)); + break; + case LOG_CF_SERVER_IP: + /* SERVER IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)dstip, strlen(dstip)); + break; + case LOG_CF_CLIENT_PORT: + /* CLIENT PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); + break; + case LOG_CF_SERVER_PORT: + /* SERVER PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); + break; + case LOG_TLS_CF_VERSION: + LogTlsLogVersion(aft->buffer, ssl_state->server_connp.version); + break; + case LOG_TLS_CF_DATE_NOT_BEFORE: + LogTlsLogDate(aft->buffer, "NOTBEFORE", &ssl_state->server_connp.cert0_not_before); + break; + case LOG_TLS_CF_DATE_NOT_AFTER: + LogTlsLogDate(aft->buffer, "NOTAFTER", &ssl_state->server_connp.cert0_not_after); + break; + case LOG_TLS_CF_SHA1: + if (ssl_state->server_connp.cert0_fingerprint != NULL) { + MemBufferWriteString( + aft->buffer, "%s", ssl_state->server_connp.cert0_fingerprint); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_SNI: + if (ssl_state->client_connp.sni != NULL) { + MemBufferWriteString(aft->buffer, "%s", ssl_state->client_connp.sni); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_SUBJECT: + if (ssl_state->server_connp.cert0_subject != NULL) { + MemBufferWriteString(aft->buffer, "%s", ssl_state->server_connp.cert0_subject); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_ISSUER: + if (ssl_state->server_connp.cert0_issuerdn != NULL) { + MemBufferWriteString(aft->buffer, "%s", ssl_state->server_connp.cert0_issuerdn); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_EXTENDED: + /* Extended format */ + LogTlsLogExtended(aft, ssl_state, ts, srcip, sp, dstip, dp); + break; + default: + /* NO MATCH */ + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + SCLogDebug("No matching parameter %%%c for custom tls log.", node->type); + break; + } + } +} + +static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *tx, uint64_t tx_id) +{ + LogTlsLogThread *aft = (LogTlsLogThread *)thread_data; + LogTlsFileCtx *hlog = aft->tlslog_ctx; + int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; + + SSLState *ssl_state = (SSLState *)state; + if (unlikely(ssl_state == NULL)) { + return 0; + } + + if (((hlog->flags & LOG_TLS_SESSION_RESUMPTION) == 0 || + (ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) == 0) && + (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) && + ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { + return 0; + } + + char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; + + Port sp, dp; + if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) { + return 0; + } + + MemBufferReset(aft->buffer); + + if (hlog->flags & LOG_TLS_CUSTOM) { + LogTlsLogCustom(aft, ssl_state, p->ts, srcip, sp, dstip, dp); + } else if (hlog->flags & LOG_TLS_EXTENDED) { + LogTlsLogBasic(aft, ssl_state, p->ts, srcip, sp, dstip, dp); + LogTlsLogExtended(aft, ssl_state, p->ts, srcip, sp, dstip, dp); + } else { + LogTlsLogBasic(aft, ssl_state, p->ts, srcip, sp, dstip, dp); + } + + MemBufferWriteString(aft->buffer, "\n"); + + aft->tls_cnt++; + + hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), + MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); + + return 0; +} + +void LogTlsLogRegister(void) +{ + OutputRegisterTxModuleWithProgress(LOGGER_TLS, MODULE_NAME, "tls-log", LogTlsLogInitCtx, + ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, LogTlsLogThreadInit, + LogTlsLogThreadDeinit, LogTlsLogExitPrintStats); +} diff --git a/src/log-tlslog.h b/src/app-layer/tls/log-tlslog.h similarity index 82% rename from src/log-tlslog.h rename to src/app-layer/tls/log-tlslog.h index 87c2fbcf5db7..8fef9d146ca3 100644 --- a/src/log-tlslog.h +++ b/src/app-layer/tls/log-tlslog.h @@ -27,9 +27,7 @@ void LogTlsLogRegister(void); -int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, - Port* sp, char* dstip, size_t dstip_len, - Port* dp, int ipproto); +int TLSGetIPInformations(const Packet *p, char *srcip, size_t srcip_len, Port *sp, char *dstip, + size_t dstip_len, Port *dp, int ipproto); #endif /* __LOG_TLSLOG_H__ */ - diff --git a/src/log-tlsstore.c b/src/app-layer/tls/log-tlsstore.c similarity index 86% rename from src/log-tlsstore.c rename to src/app-layer/tls/log-tlsstore.c index 50e6c6e5c481..afdb6e48ea85 100644 --- a/src/log-tlsstore.c +++ b/src/app-layer/tls/log-tlsstore.c @@ -27,19 +27,19 @@ */ #include "suricata-common.h" -#include "log-tlsstore.h" +#include "app-layer/tls/log-tlsstore.h" #include "decode.h" #include "app-layer-parser.h" -#include "app-layer-ssl.h" +#include "app-layer/ssl/parser.h" -#include "output.h" -#include "log-tlslog.h" +#include "output/output.h" +#include "app-layer/tls/log-tlslog.h" -#include "util-conf.h" -#include "util-path.h" -#include "util-time.h" +#include "util/conf.h" +#include "util/path.h" +#include "util/time.h" #define MODULE_NAME "LogTlsStoreLog" @@ -52,8 +52,8 @@ static char logging_dir_not_writable; typedef struct LogTlsStoreLogThread_ { uint32_t tls_cnt; - uint8_t* enc_buf; - size_t enc_buf_len; + uint8_t *enc_buf; + size_t enc_buf_len; } LogTlsStoreLogThread; static int CreateFileName(const Packet *p, SSLState *state, char *filename, size_t filename_size) @@ -77,12 +77,12 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s { #define PEMHEADER "-----BEGIN CERTIFICATE-----\n" #define PEMFOOTER "-----END CERTIFICATE-----\n" - //Logging pem certificate + // Logging pem certificate char filename[PATH_MAX] = ""; - FILE* fp = NULL; - FILE* fpmeta = NULL; + FILE *fp = NULL; + FILE *fpmeta = NULL; unsigned long pemlen; - unsigned char* pembase64ptr = NULL; + unsigned char *pembase64ptr = NULL; int ret; uint8_t *ptmp; SSLCertsChain *cert; @@ -106,10 +106,10 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s SCReturn; } - TAILQ_FOREACH(cert, &state->server_connp.certs, next) { + TAILQ_FOREACH (cert, &state->server_connp.certs, next) { pemlen = Base64EncodeBufferSize(cert->cert_len); if (pemlen > aft->enc_buf_len) { - ptmp = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen); + ptmp = (uint8_t *)SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen); if (ptmp == NULL) { SCFree(aft->enc_buf); aft->enc_buf = NULL; @@ -123,7 +123,7 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s memset(aft->enc_buf, 0, aft->enc_buf_len); - ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen); + ret = Base64Encode((unsigned char *)cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen); if (ret != SC_BASE64_OK) { SCLogWarning("Invalid return of Base64Encode function"); goto end_fwrite_fp; @@ -150,11 +150,11 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s } fclose(fp); - //Logging certificate informations + // Logging certificate informations memcpy(filename + (strlen(filename) - 3), "meta", 4); fpmeta = fopen(filename, "w"); if (fpmeta != NULL) { - #define PRINT_BUF_LEN 46 +#define PRINT_BUF_LEN 46 char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; char timebuf[64]; Port sp, dp; @@ -164,7 +164,7 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s if (fprintf(fpmeta, "TIME: %s\n", timebuf) < 0) goto end_fwrite_fpmeta; if (p->pcap_cnt > 0) { - if (fprintf(fpmeta, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt) < 0) + if (fprintf(fpmeta, "PCAP PKT NUM: %" PRIu64 "\n", p->pcap_cnt) < 0) goto end_fwrite_fpmeta; } if (fprintf(fpmeta, "SRC IP: %s\n", srcip) < 0) @@ -180,12 +180,12 @@ static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *s goto end_fwrite_fpmeta; } - if (fprintf(fpmeta, "TLS SUBJECT: %s\n" + if (fprintf(fpmeta, + "TLS SUBJECT: %s\n" "TLS ISSUERDN: %s\n" "TLS FINGERPRINT: %s\n", - state->server_connp.cert0_subject, - state->server_connp.cert0_issuerdn, - state->server_connp.cert0_fingerprint) < 0) + state->server_connp.cert0_subject, state->server_connp.cert0_issuerdn, + state->server_connp.cert0_fingerprint) < 0) goto end_fwrite_fpmeta; fclose(fpmeta); @@ -255,8 +255,8 @@ static bool LogTlsStoreCondition( return false; } -static int LogTlsStoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, - Flow *f, void *state, void *tx, uint64_t tx_id) +static int LogTlsStoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *tx, uint64_t tx_id) { LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)thread_data; int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; @@ -290,7 +290,7 @@ static TmEcode LogTlsStoreLogThreadInit(ThreadVars *t, const void *initdata, voi if (stat(tls_logfile_base_dir, &stat_buf) != 0) { int ret; /* coverity[toctou] */ - ret = SCMkDir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP); + ret = SCMkDir(tls_logfile_base_dir, S_IRWXU | S_IXGRP | S_IRGRP); if (ret != 0) { int err = errno; if (err != EEXIST) { @@ -299,10 +299,8 @@ static TmEcode LogTlsStoreLogThreadInit(ThreadVars *t, const void *initdata, voi exit(EXIT_FAILURE); } } else { - SCLogInfo("Created certs drop directory %s", - tls_logfile_base_dir); + SCLogInfo("Created certs drop directory %s", tls_logfile_base_dir); } - } *data = (void *)aft; @@ -369,15 +367,13 @@ static OutputInitResult LogTlsStoreLogInitCtx(ConfNode *conf) const char *s_base_dir = NULL; s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir"); if (s_base_dir == NULL || strlen(s_base_dir) == 0) { - strlcpy(tls_logfile_base_dir, - s_default_log_dir, sizeof(tls_logfile_base_dir)); + strlcpy(tls_logfile_base_dir, s_default_log_dir, sizeof(tls_logfile_base_dir)); } else { if (PathIsAbsolute(s_base_dir)) { - strlcpy(tls_logfile_base_dir, - s_base_dir, sizeof(tls_logfile_base_dir)); + strlcpy(tls_logfile_base_dir, s_base_dir, sizeof(tls_logfile_base_dir)); } else { - snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir), - "%s/%s", s_default_log_dir, s_base_dir); + snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir), "%s/%s", s_default_log_dir, + s_base_dir); } } @@ -391,12 +387,11 @@ static OutputInitResult LogTlsStoreLogInitCtx(ConfNode *conf) SCReturnCT(result, "OutputInitResult"); } -void LogTlsStoreRegister (void) +void LogTlsStoreRegister(void) { - OutputRegisterTxModuleWithCondition(LOGGER_TLS_STORE, MODULE_NAME, - "tls-store", LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, - LogTlsStoreCondition, LogTlsStoreLogThreadInit, - LogTlsStoreLogThreadDeinit, LogTlsStoreLogExitPrintStats); + OutputRegisterTxModuleWithCondition(LOGGER_TLS_STORE, MODULE_NAME, "tls-store", + LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, LogTlsStoreCondition, + LogTlsStoreLogThreadInit, LogTlsStoreLogThreadDeinit, LogTlsStoreLogExitPrintStats); SC_ATOMIC_INIT(cert_id); SC_ATOMIC_SET(cert_id, 1); diff --git a/src/log-tlsstore.h b/src/app-layer/tls/log-tlsstore.h similarity index 100% rename from src/log-tlsstore.h rename to src/app-layer/tls/log-tlsstore.h diff --git a/src/app-layer/tls/logger.c b/src/app-layer/tls/logger.c new file mode 100644 index 000000000000..e00839c3bcbd --- /dev/null +++ b/src/app-layer/tls/logger.c @@ -0,0 +1,649 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + * + * Implements TLS JSON logging portion of the engine. + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/time.h" +#include "util/unittest.h" + +#include "util/debug.h" +#include "app-layer-parser.h" +#include "output/output.h" +#include "app-layer/ssl/parser.h" +#include "app-layer.h" +#include "util/privs.h" +#include "util/buffer.h" + +#include "util/logopenfile.h" +#include "util/ja3.h" + +#include "output/eve/output-json.h" +#include "app-layer/tls/logger.h" + +SC_ATOMIC_EXTERN(unsigned int, cert_id); + +#define MODULE_NAME "LogTlsLog" +#define DEFAULT_LOG_FILENAME "tls.json" + +#define LOG_TLS_DEFAULT 0 +#define LOG_TLS_EXTENDED (1 << 0) +#define LOG_TLS_CUSTOM (1 << 1) +#define LOG_TLS_SESSION_RESUMPTION (1 << 2) + +#define LOG_TLS_FIELD_VERSION (1 << 0) +#define LOG_TLS_FIELD_SUBJECT (1 << 1) +#define LOG_TLS_FIELD_ISSUER (1 << 2) +#define LOG_TLS_FIELD_SERIAL (1 << 3) +#define LOG_TLS_FIELD_FINGERPRINT (1 << 4) +#define LOG_TLS_FIELD_NOTBEFORE (1 << 5) +#define LOG_TLS_FIELD_NOTAFTER (1 << 6) +#define LOG_TLS_FIELD_SNI (1 << 7) +#define LOG_TLS_FIELD_CERTIFICATE (1 << 8) +#define LOG_TLS_FIELD_CHAIN (1 << 9) +#define LOG_TLS_FIELD_SESSION_RESUMED (1 << 10) +#define LOG_TLS_FIELD_JA3 (1 << 11) +#define LOG_TLS_FIELD_JA3S (1 << 12) +#define LOG_TLS_FIELD_CLIENT (1 << 13) /**< client fields (issuer, subject, etc) */ +#define LOG_TLS_FIELD_CLIENT_CERT (1 << 14) +#define LOG_TLS_FIELD_CLIENT_CHAIN (1 << 15) + +typedef struct { + const char *name; + uint64_t flag; +} TlsFields; + +TlsFields tls_fields[] = { { "version", LOG_TLS_FIELD_VERSION }, + { "subject", LOG_TLS_FIELD_SUBJECT }, { "issuer", LOG_TLS_FIELD_ISSUER }, + { "serial", LOG_TLS_FIELD_SERIAL }, { "fingerprint", LOG_TLS_FIELD_FINGERPRINT }, + { "not_before", LOG_TLS_FIELD_NOTBEFORE }, { "not_after", LOG_TLS_FIELD_NOTAFTER }, + { "sni", LOG_TLS_FIELD_SNI }, { "certificate", LOG_TLS_FIELD_CERTIFICATE }, + { "chain", LOG_TLS_FIELD_CHAIN }, { "session_resumed", LOG_TLS_FIELD_SESSION_RESUMED }, + { "ja3", LOG_TLS_FIELD_JA3 }, { "ja3s", LOG_TLS_FIELD_JA3S }, + { "client", LOG_TLS_FIELD_CLIENT }, { "client_certificate", LOG_TLS_FIELD_CLIENT_CERT }, + { "client_chain", LOG_TLS_FIELD_CLIENT_CHAIN }, { NULL, -1 } }; + +typedef struct OutputTlsCtx_ { + uint32_t flags; /** Store mode */ + uint64_t fields; /** Store fields */ + OutputJsonCtx *eve_ctx; +} OutputTlsCtx; + +typedef struct JsonTlsLogThread_ { + OutputTlsCtx *tlslog_ctx; + OutputJsonThreadCtx *ctx; +} JsonTlsLogThread; + +static void JsonTlsLogSubject(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_subject) { + jb_set_string(js, "subject", ssl_state->server_connp.cert0_subject); + } +} + +static void JsonTlsLogIssuer(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_issuerdn) { + jb_set_string(js, "issuerdn", ssl_state->server_connp.cert0_issuerdn); + } +} + +static void JsonTlsLogSessionResumed(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) { + /* Only log a session as 'resumed' if a certificate has not + been seen, and the session is not TLSv1.3 or later. */ + if ((ssl_state->server_connp.cert0_issuerdn == NULL && + ssl_state->server_connp.cert0_subject == NULL) && + (ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && + ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { + jb_set_bool(js, "session_resumed", true); + } + } +} + +static void JsonTlsLogFingerprint(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_fingerprint) { + jb_set_string(js, "fingerprint", ssl_state->server_connp.cert0_fingerprint); + } +} + +static void JsonTlsLogSni(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->client_connp.sni) { + jb_set_string(js, "sni", ssl_state->client_connp.sni); + } +} + +static void JsonTlsLogSerial(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_serial) { + jb_set_string(js, "serial", ssl_state->server_connp.cert0_serial); + } +} + +static void JsonTlsLogVersion(JsonBuilder *js, SSLState *ssl_state) +{ + char ssl_version[SSL_VERSION_MAX_STRLEN]; + SSLVersionToString(ssl_state->server_connp.version, ssl_version); + jb_set_string(js, "version", ssl_version); +} + +static void JsonTlsLogNotBefore(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_not_before != 0) { + sc_x509_log_timestamp(js, "notbefore", ssl_state->server_connp.cert0_not_before); + } +} + +static void JsonTlsLogNotAfter(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_not_after != 0) { + sc_x509_log_timestamp(js, "notafter", ssl_state->server_connp.cert0_not_after); + } +} + +static void JsonTlsLogJa3Hash(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->client_connp.ja3_hash != NULL) { + jb_set_string(js, "hash", ssl_state->client_connp.ja3_hash); + } +} + +static void JsonTlsLogJa3String(JsonBuilder *js, SSLState *ssl_state) +{ + if ((ssl_state->client_connp.ja3_str != NULL) && + ssl_state->client_connp.ja3_str->data != NULL) { + jb_set_string(js, "string", ssl_state->client_connp.ja3_str->data); + } +} + +static void JsonTlsLogJa3(JsonBuilder *js, SSLState *ssl_state) +{ + if ((ssl_state->client_connp.ja3_hash != NULL) || + ((ssl_state->client_connp.ja3_str != NULL) && + ssl_state->client_connp.ja3_str->data != NULL)) { + jb_open_object(js, "ja3"); + + JsonTlsLogJa3Hash(js, ssl_state); + JsonTlsLogJa3String(js, ssl_state); + + jb_close(js); + } +} + +static void JsonTlsLogJa3SHash(JsonBuilder *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.ja3_hash != NULL) { + jb_set_string(js, "hash", ssl_state->server_connp.ja3_hash); + } +} + +static void JsonTlsLogJa3SString(JsonBuilder *js, SSLState *ssl_state) +{ + if ((ssl_state->server_connp.ja3_str != NULL) && + ssl_state->server_connp.ja3_str->data != NULL) { + jb_set_string(js, "string", ssl_state->server_connp.ja3_str->data); + } +} + +static void JsonTlsLogJa3S(JsonBuilder *js, SSLState *ssl_state) +{ + if ((ssl_state->server_connp.ja3_hash != NULL) || + ((ssl_state->server_connp.ja3_str != NULL) && + ssl_state->server_connp.ja3_str->data != NULL)) { + jb_open_object(js, "ja3s"); + + JsonTlsLogJa3SHash(js, ssl_state); + JsonTlsLogJa3SString(js, ssl_state); + + jb_close(js); + } +} + +static void JsonTlsLogCertificate(JsonBuilder *js, SSLStateConnp *connp) +{ + if (TAILQ_EMPTY(&connp->certs)) { + return; + } + + SSLCertsChain *cert = TAILQ_FIRST(&connp->certs); + if (cert == NULL) { + return; + } + + jb_set_base64(js, "certificate", cert->cert_data, cert->cert_len); +} + +static void JsonTlsLogChain(JsonBuilder *js, SSLStateConnp *connp) +{ + if (TAILQ_EMPTY(&connp->certs)) { + return; + } + + jb_open_array(js, "chain"); + + SSLCertsChain *cert; + TAILQ_FOREACH (cert, &connp->certs, next) { + jb_append_base64(js, cert->cert_data, cert->cert_len); + } + + jb_close(js); +} + +static bool HasClientCert(SSLStateConnp *connp) +{ + if (connp->cert0_subject || connp->cert0_issuerdn) + return true; + return false; +} + +static void JsonTlsLogClientCert( + JsonBuilder *js, SSLStateConnp *connp, const bool log_cert, const bool log_chain) +{ + if (connp->cert0_subject != NULL) { + jb_set_string(js, "subject", connp->cert0_subject); + } + if (connp->cert0_issuerdn != NULL) { + jb_set_string(js, "issuerdn", connp->cert0_issuerdn); + } + if (connp->cert0_fingerprint) { + jb_set_string(js, "fingerprint", connp->cert0_fingerprint); + } + if (connp->cert0_serial) { + jb_set_string(js, "serial", connp->cert0_serial); + } + if (connp->cert0_not_before != 0) { + char timebuf[64]; + SCTime_t ts = SCTIME_FROM_SECS(connp->cert0_not_before); + CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf)); + jb_set_string(js, "notbefore", timebuf); + } + if (connp->cert0_not_after != 0) { + char timebuf[64]; + SCTime_t ts = SCTIME_FROM_SECS(connp->cert0_not_after); + CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf)); + jb_set_string(js, "notafter", timebuf); + } + + if (log_cert) { + JsonTlsLogCertificate(js, connp); + } + if (log_chain) { + JsonTlsLogChain(js, connp); + } +} + +void JsonTlsLogJSONBasic(JsonBuilder *js, SSLState *ssl_state) +{ + /* tls subject */ + JsonTlsLogSubject(js, ssl_state); + + /* tls issuerdn */ + JsonTlsLogIssuer(js, ssl_state); + + /* tls session resumption */ + JsonTlsLogSessionResumed(js, ssl_state); +} + +static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, JsonBuilder *js, SSLState *ssl_state) +{ + /* tls subject */ + if (tls_ctx->fields & LOG_TLS_FIELD_SUBJECT) + JsonTlsLogSubject(js, ssl_state); + + /* tls issuerdn */ + if (tls_ctx->fields & LOG_TLS_FIELD_ISSUER) + JsonTlsLogIssuer(js, ssl_state); + + /* tls session resumption */ + if (tls_ctx->fields & LOG_TLS_FIELD_SESSION_RESUMED) + JsonTlsLogSessionResumed(js, ssl_state); + + /* tls serial */ + if (tls_ctx->fields & LOG_TLS_FIELD_SERIAL) + JsonTlsLogSerial(js, ssl_state); + + /* tls fingerprint */ + if (tls_ctx->fields & LOG_TLS_FIELD_FINGERPRINT) + JsonTlsLogFingerprint(js, ssl_state); + + /* tls sni */ + if (tls_ctx->fields & LOG_TLS_FIELD_SNI) + JsonTlsLogSni(js, ssl_state); + + /* tls version */ + if (tls_ctx->fields & LOG_TLS_FIELD_VERSION) + JsonTlsLogVersion(js, ssl_state); + + /* tls notbefore */ + if (tls_ctx->fields & LOG_TLS_FIELD_NOTBEFORE) + JsonTlsLogNotBefore(js, ssl_state); + + /* tls notafter */ + if (tls_ctx->fields & LOG_TLS_FIELD_NOTAFTER) + JsonTlsLogNotAfter(js, ssl_state); + + /* tls certificate */ + if (tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) + JsonTlsLogCertificate(js, &ssl_state->server_connp); + + /* tls chain */ + if (tls_ctx->fields & LOG_TLS_FIELD_CHAIN) + JsonTlsLogChain(js, &ssl_state->server_connp); + + /* tls ja3_hash */ + if (tls_ctx->fields & LOG_TLS_FIELD_JA3) + JsonTlsLogJa3(js, ssl_state); + + /* tls ja3s */ + if (tls_ctx->fields & LOG_TLS_FIELD_JA3S) + JsonTlsLogJa3S(js, ssl_state); + + if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT) { + const bool log_cert = (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) != 0; + const bool log_chain = (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN) != 0; + if (HasClientCert(&ssl_state->client_connp)) { + jb_open_object(js, "client"); + JsonTlsLogClientCert(js, &ssl_state->client_connp, log_cert, log_chain); + jb_close(js); + } + } +} + +static bool JsonTlsLogJSONExtendedAux(void *vtx, JsonBuilder *tjs) +{ + SSLState *state = (SSLState *)vtx; + JsonTlsLogJSONBasic(tjs, state); + + /* tls serial */ + JsonTlsLogSerial(tjs, state); + + /* tls fingerprint */ + JsonTlsLogFingerprint(tjs, state); + + /* tls sni */ + JsonTlsLogSni(tjs, state); + + /* tls version */ + JsonTlsLogVersion(tjs, state); + + /* tls notbefore */ + JsonTlsLogNotBefore(tjs, state); + + /* tls notafter */ + JsonTlsLogNotAfter(tjs, state); + + /* tls ja3 */ + JsonTlsLogJa3(tjs, state); + + /* tls ja3s */ + JsonTlsLogJa3S(tjs, state); + + if (HasClientCert(&state->client_connp)) { + jb_open_object(tjs, "client"); + JsonTlsLogClientCert(tjs, &state->client_connp, false, false); + jb_close(tjs); + } + return true; +} + +bool JsonTlsLogJSONExtended(void *vtx, JsonBuilder *tjs) +{ + jb_open_object(tjs, "tls"); + bool r = JsonTlsLogJSONExtendedAux(vtx, tjs); + jb_close(tjs); + return r; +} + +static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, + void *txptr, uint64_t tx_id) +{ + JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data; + OutputTlsCtx *tls_ctx = aft->tlslog_ctx; + + SSLState *ssl_state = (SSLState *)state; + if (unlikely(ssl_state == NULL)) { + return 0; + } + + if ((ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) && + ((ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) == 0 || + (tls_ctx->flags & LOG_TLS_SESSION_RESUMPTION) == 0) && + ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { + return 0; + } + + JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "tls", NULL, aft->tlslog_ctx->eve_ctx); + if (unlikely(js == NULL)) { + return 0; + } + + jb_open_object(js, "tls"); + + /* log custom fields */ + if (tls_ctx->flags & LOG_TLS_CUSTOM) { + JsonTlsLogJSONCustom(tls_ctx, js, ssl_state); + } + /* log extended */ + else if (tls_ctx->flags & LOG_TLS_EXTENDED) { + JsonTlsLogJSONExtendedAux(ssl_state, js); + } + /* log basic */ + else { + JsonTlsLogJSONBasic(js, ssl_state); + } + + /* print original application level protocol when it have been changed + because of STARTTLS, HTTP CONNECT, or similar. */ + if (f->alproto_orig != ALPROTO_UNKNOWN) { + jb_set_string(js, "from_proto", AppLayerGetProtoName(f->alproto_orig)); + } + + /* Close the tls object. */ + jb_close(js); + + OutputJsonBuilderBuffer(js, aft->ctx); + jb_free(js); + + return 0; +} + +static TmEcode JsonTlsLogThreadInit(ThreadVars *t, const void *initdata, void **data) +{ + JsonTlsLogThread *aft = SCCalloc(1, sizeof(JsonTlsLogThread)); + if (unlikely(aft == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for eve-log tls 'initdata' argument NULL"); + goto error_exit; + } + + /* use the Output Context (file pointer and mutex) */ + aft->tlslog_ctx = ((OutputCtx *)initdata)->data; + + aft->ctx = CreateEveThreadCtx(t, aft->tlslog_ctx->eve_ctx); + if (!aft->ctx) { + goto error_exit; + } + *data = (void *)aft; + return TM_ECODE_OK; + +error_exit: + SCFree(aft); + return TM_ECODE_FAILED; +} + +static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonTlsLogThread *aft = (JsonTlsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + FreeEveThreadCtx(aft->ctx); + + /* clear memory */ + memset(aft, 0, sizeof(JsonTlsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf) +{ + OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + if (unlikely(tls_ctx == NULL)) + return NULL; + + tls_ctx->flags = LOG_TLS_DEFAULT; + tls_ctx->fields = 0; + + if (conf == NULL) + return tls_ctx; + + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + if (extended) { + if (ConfValIsTrue(extended)) { + tls_ctx->flags = LOG_TLS_EXTENDED; + } + } + + ConfNode *custom = ConfNodeLookupChild(conf, "custom"); + if (custom) { + tls_ctx->flags = LOG_TLS_CUSTOM; + ConfNode *field; + TAILQ_FOREACH (field, &custom->head, next) { + bool valid = false; + TlsFields *valid_fields = tls_fields; + for (; valid_fields->name != NULL; valid_fields++) { + if (strcasecmp(field->val, valid_fields->name) == 0) { + tls_ctx->fields |= valid_fields->flag; + SCLogDebug("enabled %s", field->val); + valid = true; + break; + } + } + if (!valid) { + SCLogWarning("eve.tls: unknown 'custom' field '%s'", field->val); + } + } + } + + const char *session_resumption = ConfNodeLookupChildValue(conf, "session-resumption"); + if (session_resumption == NULL || ConfValIsTrue(session_resumption)) { + tls_ctx->flags |= LOG_TLS_SESSION_RESUMPTION; + } + + if ((tls_ctx->fields & LOG_TLS_FIELD_JA3) && Ja3IsDisabled("fields")) { + /* JA3 is disabled, so don't log any JA3 fields */ + tls_ctx->fields &= ~LOG_TLS_FIELD_JA3; + tls_ctx->fields &= ~LOG_TLS_FIELD_JA3S; + } + + if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { + SCLogWarning("Both 'certificate' and 'chain' contains the top " + "certificate, so only one of them should be enabled " + "at a time"); + } + if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) && + (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN)) { + SCLogWarning("Both 'client_certificate' and 'client_chain' contains the top " + "certificate, so only one of them should be enabled " + "at a time"); + } + + if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT) == 0) { + if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) { + SCLogConfig("enabling \"client\" as a dependency of \"client_certificate\""); + tls_ctx->fields |= LOG_TLS_FIELD_CLIENT; + } + if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN) { + SCLogConfig("enabling \"client\" as a dependency of \"client_chain\""); + tls_ctx->fields |= LOG_TLS_FIELD_CLIENT; + } + } + + return tls_ctx; +} + +static void OutputTlsLogDeinitSub(OutputCtx *output_ctx) +{ + OutputTlsCtx *tls_ctx = output_ctx->data; + SCFree(tls_ctx); + SCFree(output_ctx); +} + +static OutputInitResult OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ojc = parent_ctx->data; + + OutputTlsCtx *tls_ctx = OutputTlsInitCtx(conf); + if (unlikely(tls_ctx == NULL)) + return result; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(tls_ctx); + return result; + } + + tls_ctx->eve_ctx = ojc; + + if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { + SCLogWarning("Both 'certificate' and 'chain' contains the top " + "certificate, so only one of them should be enabled " + "at a time"); + } + + output_ctx->data = tls_ctx; + output_ctx->DeInit = OutputTlsLogDeinitSub; + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); + + result.ctx = output_ctx; + result.ok = true; + return result; +} + +void JsonTlsLogRegister(void) +{ + /* register as child of eve-log */ + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_TX, "eve-log", "JsonTlsLog", "eve-log.tls", + OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, + JsonTlsLogThreadInit, JsonTlsLogThreadDeinit, NULL); +} diff --git a/src/app-layer/tls/logger.h b/src/app-layer/tls/logger.h new file mode 100644 index 000000000000..8a76f361078c --- /dev/null +++ b/src/app-layer/tls/logger.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_TLS_H__ +#define __OUTPUT_JSON_TLS_H__ + +void JsonTlsLogRegister(void); + +#include "app-layer/ssl/parser.h" + +void JsonTlsLogJSONBasic(JsonBuilder *js, SSLState *ssl_state); +bool JsonTlsLogJSONExtended(void *vtx, JsonBuilder *js); + +#endif /* __OUTPUT_JSON_TLS_H__ */ diff --git a/src/app-layer/tls/lua.c b/src/app-layer/tls/lua.c new file mode 100644 index 000000000000..a471cb90e6de --- /dev/null +++ b/src/app-layer/tls/lua.c @@ -0,0 +1,366 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssl/parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/tls/lua.h" + +static int GetCertNotBefore(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_not_before == 0) + return LuaCallbackError(luastate, "error: no certificate NotBefore"); + + int r = LuaPushInteger(luastate, connp->cert0_not_before); + + return r; +} + +static int TlsGetCertNotBefore(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertNotBefore(luastate, f, direction); + + return r; +} + +static int GetCertNotAfter(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_not_after == 0) + return LuaCallbackError(luastate, "error: no certificate NotAfter"); + + int r = LuaPushInteger(luastate, connp->cert0_not_after); + + return r; +} + +static int TlsGetCertNotAfter(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertNotAfter(luastate, f, direction); + + return r; +} + +static int GetCertInfo(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_subject == NULL) + return LuaCallbackError(luastate, "error: no cert"); + + /* tls.version */ + char ssl_version[SSL_VERSION_MAX_STRLEN]; + SSLVersionToString(ssl_state->server_connp.version, ssl_version); + + int r = LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, strlen(ssl_version)); + r += LuaPushStringBuffer( + luastate, (uint8_t *)connp->cert0_subject, strlen(connp->cert0_subject)); + r += LuaPushStringBuffer( + luastate, (uint8_t *)connp->cert0_issuerdn, strlen(connp->cert0_issuerdn)); + r += LuaPushStringBuffer( + luastate, (uint8_t *)connp->cert0_fingerprint, strlen(connp->cert0_fingerprint)); + return r; +} + +static int TlsGetCertInfo(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertInfo(luastate, f, direction); + + return r; +} + +static int GetAgreedVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + char ssl_version[SSL_VERSION_MAX_STRLEN]; + SSLVersionToString(ssl_state->server_connp.version, ssl_version); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, strlen(ssl_version)); +} + +static int TlsGetVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetAgreedVersion(luastate, f); + + return r; +} + +static int GetSNI(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->client_connp.sni == NULL) + return LuaCallbackError(luastate, "error: no server name indication"); + + return LuaPushStringBuffer( + luastate, (uint8_t *)ssl_state->client_connp.sni, strlen(ssl_state->client_connp.sni)); +} + +static int TlsGetSNI(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetSNI(luastate, f); + + return r; +} + +static int GetCertSerial(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->server_connp.cert0_serial == NULL) + return LuaCallbackError(luastate, "error: no certificate serial"); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->server_connp.cert0_serial, + strlen(ssl_state->server_connp.cert0_serial)); +} + +static int TlsGetCertSerial(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertSerial(luastate, f); + + return r; +} + +static int GetCertChain(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + uint32_t u = 0; + lua_newtable(luastate); + SSLCertsChain *cert = NULL; + TAILQ_FOREACH (cert, &connp->certs, next) { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + + lua_pushstring(luastate, "length"); + lua_pushinteger(luastate, cert->cert_len); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "data"); + LuaPushStringBuffer(luastate, cert->cert_data, cert->cert_len); + + lua_settable(luastate, -3); + lua_settable(luastate, -3); + } + + return 1; +} + +static int TlsGetCertChain(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertChain(luastate, f, direction); + + return r; +} + +/** \brief register tls lua extensions in a luastate */ +int LuaRegisterTlsFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, TlsGetCertNotBefore); + lua_setglobal(luastate, "TlsGetCertNotBefore"); + + lua_pushcfunction(luastate, TlsGetCertNotAfter); + lua_setglobal(luastate, "TlsGetCertNotAfter"); + + lua_pushcfunction(luastate, TlsGetVersion); + lua_setglobal(luastate, "TlsGetVersion"); + + lua_pushcfunction(luastate, TlsGetCertInfo); + lua_setglobal(luastate, "TlsGetCertInfo"); + + lua_pushcfunction(luastate, TlsGetSNI); + lua_setglobal(luastate, "TlsGetSNI"); + + lua_pushcfunction(luastate, TlsGetCertSerial); + lua_setglobal(luastate, "TlsGetCertSerial"); + + lua_pushcfunction(luastate, TlsGetCertChain); + lua_setglobal(luastate, "TlsGetCertChain"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-tls.h b/src/app-layer/tls/lua.h similarity index 100% rename from src/util-lua-tls.h rename to src/app-layer/tls/lua.h diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index 1bd107e0c1c9..36e87de25486 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -27,9 +27,9 @@ #include "conf.h" #include "conf-yaml-loader.h" #include -#include "util-path.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/path.h" +#include "util/debug.h" +#include "util/unittest.h" #define YAML_VERSION_MAJOR 1 #define YAML_VERSION_MINOR 1 @@ -64,8 +64,7 @@ enum conf_state { * * \retval none */ -static void -Mangle(char *string) +static void Mangle(char *string) { char *c; @@ -80,8 +79,7 @@ Mangle(char *string) * * \param filename The configuration filename. */ -static void -ConfYamlSetConfDirname(const char *filename) +static void ConfYamlSetConfDirname(const char *filename) { char *ep; @@ -94,8 +92,7 @@ ConfYamlSetConfDirname(const char *filename) if (conf_dirname == NULL) { FatalError("ERROR: Failed to allocate memory while loading configuration."); } - } - else { + } else { conf_dirname = SCStrdup(filename); if (conf_dirname == NULL) { FatalError("ERROR: Failed to allocate memory while loading configuration."); @@ -127,10 +124,8 @@ int ConfYamlHandleInclude(ConfNode *parent, const char *filename) if (PathIsAbsolute(filename)) { strlcpy(include_filename, filename, sizeof(include_filename)); - } - else { - snprintf(include_filename, sizeof(include_filename), "%s/%s", - conf_dirname, filename); + } else { + snprintf(include_filename, sizeof(include_filename), "%s/%s", conf_dirname, filename); } file = fopen(include_filename, "r"); @@ -196,8 +191,7 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int /* Verify YAML version - its more likely to be a valid * Suricata configuration file if the version is * correct. */ - yaml_version_directive_t *ver = - event.data.document_start.version_directive; + yaml_version_directive_t *ver = event.data.document_start.version_directive; if (ver == NULL) { SCLogError("ERROR: Invalid configuration file."); SCLogError("The configuration file must begin with the following two lines: %%YAML " @@ -210,12 +204,12 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int SCLogError("ERROR: Invalid YAML version. Must be 1.1"); goto fail; } - } - else if (event.type == YAML_SCALAR_EVENT) { + } else if (event.type == YAML_SCALAR_EVENT) { char *value = (char *)event.data.scalar.value; char *tag = (char *)event.data.scalar.tag; SCLogDebug("event.type=YAML_SCALAR_EVENT; state=%d; value=%s; " - "tag=%s; inseq=%d", state, value, tag, inseq); + "tag=%s; inseq=%d", + state, value, tag, inseq); /* Skip over empty scalar values while in KEY state. This * tends to only happen on an empty file, where a scalar @@ -264,8 +258,7 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int * re-added in the expected order for iteration. */ TAILQ_REMOVE(&parent->head, seq_node, next); - } - else { + } else { seq_node = ConfNodeNew(); if (unlikely(seq_node == NULL)) { goto fail; @@ -286,16 +279,14 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int } } TAILQ_INSERT_TAIL(&parent->head, seq_node, next); - } - else { + } else { if (state == CONF_INCLUDE) { SCLogInfo("Including configuration file %s.", value); if (ConfYamlHandleInclude(parent, value) != 0) { goto fail; } state = CONF_KEY; - } - else if (state == CONF_KEY) { + } else if (state == CONF_KEY) { if (strcmp(value, "include") == 0) { state = CONF_INCLUDE; @@ -356,11 +347,11 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int } } state = CONF_VAL; - } - else { + } else { if (value != NULL && (tag != NULL) && (strcmp(tag, "!include") == 0)) { SCLogInfo("Including configuration file %s at " - "parent node %s.", value, node->name); + "parent node %s.", + value, node->name); if (ConfYamlHandleInclude(node, value) != 0) goto fail; } else if (!node->final && value != NULL) { @@ -371,8 +362,7 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int state = CONF_KEY; } } - } - else if (event.type == YAML_SEQUENCE_START_EVENT) { + } else if (event.type == YAML_SEQUENCE_START_EVENT) { SCLogDebug("event.type=YAML_SEQUENCE_START_EVENT; state=%d", state); /* If we're processing a list of includes, use the current parent. */ if (ConfYamlParse(parser, state == CONF_INCLUDE ? parent : node, 1, rlevel, @@ -380,12 +370,10 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int goto fail; node->is_seq = 1; state = CONF_KEY; - } - else if (event.type == YAML_SEQUENCE_END_EVENT) { + } else if (event.type == YAML_SEQUENCE_END_EVENT) { SCLogDebug("event.type=YAML_SEQUENCE_END_EVENT; state=%d", state); done = 1; - } - else if (event.type == YAML_MAPPING_START_EVENT) { + } else if (event.type == YAML_MAPPING_START_EVENT) { SCLogDebug("event.type=YAML_MAPPING_START_EVENT; state=%d", state); if (state == CONF_INCLUDE) { SCLogError("Include fields cannot be a mapping: line %zu", parser->mark.line); @@ -394,16 +382,14 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int if (inseq) { char sequence_node_name[DEFAULT_NAME_LEN]; snprintf(sequence_node_name, DEFAULT_NAME_LEN, "%d", seq_idx++); - ConfNode *seq_node = ConfNodeLookupChild(node, - sequence_node_name); + ConfNode *seq_node = ConfNodeLookupChild(node, sequence_node_name); if (seq_node != NULL) { /* The sequence node has already been set, probably * from the command line. Remove it so it gets * re-added in the expected order for iteration. */ TAILQ_REMOVE(&node->head, seq_node, next); - } - else { + } else { seq_node = ConfNodeNew(); if (unlikely(seq_node == NULL)) { goto fail; @@ -418,18 +404,15 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int TAILQ_INSERT_TAIL(&node->head, seq_node, next); if (ConfYamlParse(parser, seq_node, 0, rlevel, 0) != 0) goto fail; - } - else { + } else { if (ConfYamlParse(parser, node, inseq, rlevel, 0) != 0) goto fail; } state = CONF_KEY; - } - else if (event.type == YAML_MAPPING_END_EVENT) { + } else if (event.type == YAML_MAPPING_END_EVENT) { SCLogDebug("event.type=YAML_MAPPING_END_EVENT; state=%d", state); done = 1; - } - else if (event.type == YAML_STREAM_END_EVENT) { + } else if (event.type == YAML_STREAM_END_EVENT) { SCLogDebug("event.type=YAML_STREAM_END_EVENT; state=%d", state); done = 1; } @@ -460,8 +443,7 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int * * \retval 0 on success, -1 on failure. */ -int -ConfYamlLoadFile(const char *filename) +int ConfYamlLoadFile(const char *filename) { FILE *infile; yaml_parser_t parser; @@ -507,8 +489,7 @@ ConfYamlLoadFile(const char *filename) /** * \brief Load configuration from a YAML string. */ -int -ConfYamlLoadString(const char *string, size_t len) +int ConfYamlLoadString(const char *string, size_t len) { ConfNode *root = ConfGetRootNode(); yaml_parser_t parser; @@ -538,8 +519,7 @@ ConfYamlLoadString(const char *string, size_t len) * * \retval 0 on success, -1 on failure. */ -int -ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix) +int ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix) { FILE *infile; yaml_parser_t parser; @@ -594,8 +574,7 @@ ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix) #ifdef UNITTESTS -static int -ConfYamlSequenceTest(void) +static int ConfYamlSequenceTest(void) { char input[] = "\ %YAML 1.1\n\ @@ -619,13 +598,12 @@ default-log-dir: /tmp\n\ FAIL_IF(TAILQ_EMPTY(&node->head)); int i = 0; ConfNode *filename; - TAILQ_FOREACH(filename, &node->head, next) { + TAILQ_FOREACH (filename, &node->head, next) { if (i == 0) { FAIL_IF(strcmp(filename->val, "netbios.rules") != 0); FAIL_IF(ConfNodeIsSequence(filename)); FAIL_IF(filename->is_seq != 0); - } - else if (i == 1) { + } else if (i == 1) { FAIL_IF(strcmp(filename->val, "x11.rules") != 0); FAIL_IF(ConfNodeIsSequence(filename)); } @@ -638,8 +616,7 @@ default-log-dir: /tmp\n\ PASS; } -static int -ConfYamlLoggingOutputTest(void) +static int ConfYamlLoggingOutputTest(void) { char input[] = "\ %YAML 1.1\n\ @@ -704,8 +681,7 @@ logging:\n\ /** * Try to load something that is not a valid YAML file. */ -static int -ConfYamlNonYamlFileTest(void) +static int ConfYamlNonYamlFileTest(void) { ConfCreateContextBackup(); ConfInit(); @@ -718,8 +694,7 @@ ConfYamlNonYamlFileTest(void) PASS; } -static int -ConfYamlBadYamlVersionTest(void) +static int ConfYamlBadYamlVersionTest(void) { char input[] = "\ %YAML 9.9\n\ @@ -744,8 +719,7 @@ logging:\n\ PASS; } -static int -ConfYamlSecondLevelSequenceTest(void) +static int ConfYamlSecondLevelSequenceTest(void) { char input[] = "\ %YAML 1.1\n\ @@ -804,27 +778,24 @@ libhtp:\n\ /** * Test file inclusion support. */ -static int -ConfYamlFileIncludeTest(void) +static int ConfYamlFileIncludeTest(void) { FILE *config_file; const char config_filename[] = "ConfYamlFileIncludeTest-config.yaml"; - const char config_file_contents[] = - "%YAML 1.1\n" - "---\n" - "# Include something at the root level.\n" - "include: ConfYamlFileIncludeTest-include.yaml\n" - "# Test including under a mapping.\n" - "mapping: !include ConfYamlFileIncludeTest-include.yaml\n"; + const char config_file_contents[] = "%YAML 1.1\n" + "---\n" + "# Include something at the root level.\n" + "include: ConfYamlFileIncludeTest-include.yaml\n" + "# Test including under a mapping.\n" + "mapping: !include ConfYamlFileIncludeTest-include.yaml\n"; const char include_filename[] = "ConfYamlFileIncludeTest-include.yaml"; - const char include_file_contents[] = - "%YAML 1.1\n" - "---\n" - "host-mode: auto\n" - "unix-command:\n" - " enabled: no\n"; + const char include_file_contents[] = "%YAML 1.1\n" + "---\n" + "host-mode: auto\n" + "unix-command:\n" + " enabled: no\n"; ConfCreateContextBackup(); ConfInit(); @@ -879,8 +850,7 @@ ConfYamlFileIncludeTest(void) * Test that a configuration section is overridden but subsequent * occurrences. */ -static int -ConfYamlOverrideTest(void) +static int ConfYamlOverrideTest(void) { char config[] = "%YAML 1.1\n" "---\n" @@ -940,16 +910,14 @@ ConfYamlOverrideTest(void) * Test that a configuration parameter loaded from YAML doesn't * override a 'final' value that may be set on the command line. */ -static int -ConfYamlOverrideFinalTest(void) +static int ConfYamlOverrideFinalTest(void) { ConfCreateContextBackup(); ConfInit(); - char config[] = - "%YAML 1.1\n" - "---\n" - "default-log-dir: /var/log\n"; + char config[] = "%YAML 1.1\n" + "---\n" + "default-log-dir: /var/log\n"; /* Set the log directory as if it was set on the command line. */ FAIL_IF_NOT(ConfSetFinal("default-log-dir", "/tmp")); @@ -1041,16 +1009,14 @@ static int ConfYamlNull(void) #endif /* UNITTESTS */ -void -ConfYamlRegisterTests(void) +void ConfYamlRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("ConfYamlSequenceTest", ConfYamlSequenceTest); UtRegisterTest("ConfYamlLoggingOutputTest", ConfYamlLoggingOutputTest); UtRegisterTest("ConfYamlNonYamlFileTest", ConfYamlNonYamlFileTest); UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest); - UtRegisterTest("ConfYamlSecondLevelSequenceTest", - ConfYamlSecondLevelSequenceTest); + UtRegisterTest("ConfYamlSecondLevelSequenceTest", ConfYamlSecondLevelSequenceTest); UtRegisterTest("ConfYamlFileIncludeTest", ConfYamlFileIncludeTest); UtRegisterTest("ConfYamlOverrideTest", ConfYamlOverrideTest); UtRegisterTest("ConfYamlOverrideFinalTest", ConfYamlOverrideFinalTest); diff --git a/src/conf.c b/src/conf.c index f2bf978e8c25..f1559217264f 100644 --- a/src/conf.c +++ b/src/conf.c @@ -38,10 +38,10 @@ #include "suricata-common.h" #include "conf.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-path.h" -#include "util-conf.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/path.h" +#include "util/conf.h" /** Maximum size of a complete domain name. */ #define NODE_NAME_MAX 1024 @@ -271,8 +271,7 @@ int ConfSetFromString(const char *input, int final) if (!ConfSetFinal(name, val)) { goto done; } - } - else { + } else { if (!ConfSet(name, val)) { goto done; } @@ -338,8 +337,7 @@ int ConfGet(const char *name, const char **vptr) if (node == NULL) { SCLogDebug("failed to lookup configuration parameter '%s'", name); return 0; - } - else { + } else { *vptr = node->val; return 1; } @@ -352,8 +350,7 @@ int ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr) if (node == NULL) { SCLogDebug("failed to lookup configuration parameter '%s'", name); return 0; - } - else { + } else { if (node->val == NULL) return 0; *vptr = node->val; @@ -361,8 +358,7 @@ int ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr) } } -ConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt, - const char *name) +ConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name) { ConfNode *node = ConfNodeLookupChild(base, name); if (node != NULL) @@ -375,8 +371,8 @@ ConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt, return NULL; } -int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, - const char *name, const char **vptr) +int ConfGetChildValueWithDefault( + const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr) { int ret = ConfGetChildValue(base, name, vptr); /* Get 'default' value */ @@ -456,11 +452,10 @@ int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val) *val = tmpint; return 1; - } -int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, - const char *name, intmax_t *val) +int ConfGetChildValueIntWithDefault( + const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val) { int ret = ConfGetChildValueInt(base, name, val); /* Get 'default' value */ @@ -511,8 +506,8 @@ int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val) return 1; } -int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, - const char *name, int *val) +int ConfGetChildValueBoolWithDefault( + const ConfNode *base, const ConfNode *dflt, const char *name, int *val) { int ret = ConfGetChildValueBool(base, name, val); /* Get 'default' value */ @@ -522,7 +517,6 @@ int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, return ret; } - /** * \brief Check if a value is true. * @@ -536,7 +530,7 @@ int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, */ int ConfValIsTrue(const char *val) { - const char *trues[] = {"1", "yes", "true", "on"}; + const char *trues[] = { "1", "yes", "true", "on" }; size_t u; for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) { @@ -561,7 +555,7 @@ int ConfValIsTrue(const char *val) */ int ConfValIsFalse(const char *val) { - const char *falses[] = {"0", "no", "false", "off"}; + const char *falses[] = { "0", "no", "false", "off" }; size_t u; for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) { @@ -702,7 +696,7 @@ void ConfDeInit(void) static char *ConfPrintNameArray(char **name_arr, int level) { - static char name[128*128]; + static char name[128 * 128]; int i; name[0] = '\0'; @@ -726,18 +720,15 @@ void ConfNodeDump(const ConfNode *node, const char *prefix) static int level = -1; level++; - TAILQ_FOREACH(child, &node->head, next) { + TAILQ_FOREACH (child, &node->head, next) { name[level] = SCStrdup(child->name); if (unlikely(name[level] == NULL)) { continue; } if (prefix == NULL) { - printf("%s = %s\n", ConfPrintNameArray(name, level), - child->val); - } - else { - printf("%s.%s = %s\n", prefix, - ConfPrintNameArray(name, level), child->val); + printf("%s = %s\n", ConfPrintNameArray(name, level), child->val); + } else { + printf("%s.%s = %s\n", prefix, ConfPrintNameArray(name, level), child->val); } ConfNodeDump(child, prefix); SCFree(name[level]); @@ -791,7 +782,7 @@ ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *name) return NULL; } - TAILQ_FOREACH(child, &node->head, next) { + TAILQ_FOREACH (child, &node->head, next) { if (child->name != NULL && strcmp(child->name, name) == 0) return child; } @@ -828,15 +819,14 @@ const char *ConfNodeLookupChildValue(const ConfNode *node, const char *name) * \return the ConfNode matching or NULL */ -ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, - const char *value) +ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value) { ConfNode *child; - TAILQ_FOREACH(child, &base->head, next) { + TAILQ_FOREACH (child, &base->head, next) { if (!strncmp(child->val, key, strlen(child->val))) { ConfNode *subchild; - TAILQ_FOREACH(subchild, &child->head, next) { + TAILQ_FOREACH (subchild, &child->head, next) { if ((!strcmp(subchild->name, key)) && (!strcmp(subchild->val, value))) { return child; } @@ -879,8 +869,7 @@ char *ConfLoadCompleteIncludePath(const char *file) if (PathIsRelative(file)) { if (ConfGet("include-path", &defaultpath) == 1) { SCLogDebug("Default path: %s", defaultpath); - size_t path_len = sizeof(char) * (strlen(defaultpath) + - strlen(file) + 2); + size_t path_len = sizeof(char) * (strlen(defaultpath) + strlen(file) + 2); path = SCMalloc(path_len); if (unlikely(path == NULL)) return NULL; @@ -888,7 +877,7 @@ char *ConfLoadCompleteIncludePath(const char *file) if (path[strlen(path) - 1] != '/') strlcat(path, "/", path_len); strlcat(path, file, path_len); - } else { + } else { path = SCStrdup(file); if (unlikely(path == NULL)) return NULL; @@ -1115,16 +1104,22 @@ static int ConfTestGetBool(void) char name[] = "some-bool"; const char *trues[] = { "1", - "on", "ON", - "yes", "YeS", - "true", "TRUE", + "on", + "ON", + "yes", + "YeS", + "true", + "TRUE", }; const char *falses[] = { "0", "something", - "off", "OFF", - "false", "FalSE", - "no", "NO", + "off", + "OFF", + "false", + "FalSE", + "no", + "NO", }; int val; size_t u; @@ -1152,7 +1147,7 @@ static int ConfNodeLookupChildTest(void) ConfNode *parent = ConfNodeNew(); ConfNode *child; - for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) { + for (u = 0; u < sizeof(test_vals) / sizeof(test_vals[0]); u++) { child = ConfNodeNew(); child->name = SCStrdup(test_vals[u]); child->val = SCStrdup(test_vals[u]); @@ -1195,7 +1190,7 @@ static int ConfNodeLookupChildValueTest(void) ConfNode *child; const char *value; - for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) { + for (u = 0; u < sizeof(test_vals) / sizeof(test_vals[0]); u++) { child = ConfNodeNew(); child->name = SCStrdup(test_vals[u]); child->val = SCStrdup(test_vals[u]); @@ -1224,7 +1219,7 @@ static int ConfNodeLookupChildValueTest(void) static int ConfGetChildValueWithDefaultTest(void) { - const char *val = ""; + const char *val = ""; ConfCreateContextBackup(); ConfInit(); ConfSet("af-packet.0.interface", "eth0"); @@ -1499,15 +1494,11 @@ void ConfRegisterTests(void) UtRegisterTest("ConfTestGetInt", ConfTestGetInt); UtRegisterTest("ConfTestGetBool", ConfTestGetBool); UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest); - UtRegisterTest("ConfNodeLookupChildValueTest", - ConfNodeLookupChildValueTest); + UtRegisterTest("ConfNodeLookupChildValueTest", ConfNodeLookupChildValueTest); UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest); - UtRegisterTest("ConfGetChildValueWithDefaultTest", - ConfGetChildValueWithDefaultTest); - UtRegisterTest("ConfGetChildValueIntWithDefaultTest", - ConfGetChildValueIntWithDefaultTest); - UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", - ConfGetChildValueBoolWithDefaultTest); + UtRegisterTest("ConfGetChildValueWithDefaultTest", ConfGetChildValueWithDefaultTest); + UtRegisterTest("ConfGetChildValueIntWithDefaultTest", ConfGetChildValueIntWithDefaultTest); + UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", ConfGetChildValueBoolWithDefaultTest); UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest); UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest); UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest); diff --git a/src/conf.h b/src/conf.h index 0b278a0f608e..16d2cfb31cff 100644 --- a/src/conf.h +++ b/src/conf.h @@ -43,15 +43,14 @@ typedef struct ConfNode_ { TAILQ_ENTRY(ConfNode_) next; } ConfNode; - /** * The default log directory. */ #ifdef OS_WIN32 -#define DEFAULT_LOG_DIR "C:\\WINDOWS\\Temp" +#define DEFAULT_LOG_DIR "C:\\WINDOWS\\Temp" #define DEFAULT_DATA_DIR "C:\\WINDOWS\\Temp" #else -#define DEFAULT_LOG_DIR "/var/log/suricata" +#define DEFAULT_LOG_DIR "/var/log/suricata" #define DEFAULT_DATA_DIR DATA_DIR #endif /* OS_WIN32 */ @@ -89,9 +88,12 @@ ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const ch int ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr); int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val); int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val); -int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr); -int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val); -int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val); +int ConfGetChildValueWithDefault( + const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr); +int ConfGetChildValueIntWithDefault( + const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val); +int ConfGetChildValueBoolWithDefault( + const ConfNode *base, const ConfNode *dflt, const char *name, int *val); char *ConfLoadCompleteIncludePath(const char *); int ConfNodeIsSequence(const ConfNode *node); ConfNode *ConfSetIfaceNode(const char *ifaces_node_name, const char *iface); diff --git a/src/counters.c b/src/counters.c index 790f416ba050..f1a3fb6eadad 100644 --- a/src/counters.c +++ b/src/counters.c @@ -30,16 +30,16 @@ #include "suricata.h" #include "threadvars.h" -#include "output.h" -#include "output-json-stats.h" +#include "output/output.h" +#include "output/eve/output-json-stats.h" -#include "util-byte.h" -#include "util-conf.h" -#include "util-hash.h" -#include "util-time.h" +#include "util/byte.h" +#include "util/conf.h" +#include "util/hash.h" +#include "util/time.h" #include "tm-threads.h" -#include "util-privs.h" +#include "util/privs.h" /* Time interval for syncing the local counters with the global ones */ #define STATS_WUT_TTS 3 @@ -109,7 +109,7 @@ void StatsReleaseCounters(StatsCounter *head); /** stats table is filled each interval and passed to the * loggers. Initialized at first use. */ -static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; +static StatsTable stats_table = { NULL, NULL, 0, 0, 0, { 0, 0 } }; static SCMutex stats_table_mutex = SCMUTEX_INITIALIZER; static int stats_loggers_active = 1; @@ -146,12 +146,12 @@ static void StatsPublicThreadContextCleanup(StatsPublicThreadContext *t) void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) { StatsPrivateThreadContext *pca = &tv->perf_private_ctx; -#if defined (UNITTESTS) || defined (FUZZ) +#if defined(UNITTESTS) || defined(FUZZ) if (pca->initialized == 0) return; #endif #ifdef DEBUG - BUG_ON ((id < 1) || (id > pca->size)); + BUG_ON((id < 1) || (id > pca->size)); #endif pca->head[id].value += x; pca->head[id].updates++; @@ -167,12 +167,12 @@ void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) void StatsIncr(ThreadVars *tv, uint16_t id) { StatsPrivateThreadContext *pca = &tv->perf_private_ctx; -#if defined (UNITTESTS) || defined (FUZZ) +#if defined(UNITTESTS) || defined(FUZZ) if (pca->initialized == 0) return; #endif #ifdef DEBUG - BUG_ON ((id < 1) || (id > pca->size)); + BUG_ON((id < 1) || (id > pca->size)); #endif pca->head[id].value++; pca->head[id].updates++; @@ -210,12 +210,12 @@ void StatsDecr(ThreadVars *tv, uint16_t id) void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) { StatsPrivateThreadContext *pca = &tv->perf_private_ctx; -#if defined (UNITTESTS) || defined (FUZZ) +#if defined(UNITTESTS) || defined(FUZZ) if (pca->initialized == 0) return; #endif #ifdef DEBUG - BUG_ON ((id < 1) || (id > pca->size)); + BUG_ON((id < 1) || (id > pca->size)); #endif if ((pca->head[id].pc->type == STATS_TYPE_MAXIMUM) && ((int64_t)x > pca->head[id].value)) { @@ -229,7 +229,8 @@ void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) return; } -static ConfNode *GetConfig(void) { +static ConfNode *GetConfig(void) +{ ConfNode *stats = ConfGetNode("stats"); if (stats != NULL) return stats; @@ -237,7 +238,7 @@ static ConfNode *GetConfig(void) { ConfNode *root = ConfGetNode("outputs"); ConfNode *node = NULL; if (root != NULL) { - TAILQ_FOREACH(node, &root->head, next) { + TAILQ_FOREACH (node, &root->head, next) { if (strcmp(node->val, "stats") == 0) { return node->head.tqh_first; } @@ -585,8 +586,7 @@ static void StatsReleaseCounter(StatsCounter *pc) * \retval 0 on failure */ static uint16_t StatsRegisterQualifiedCounter(const char *name, const char *tm_name, - StatsPublicThreadContext *pctx, - int type_q, uint64_t (*Func)(void)) + StatsPublicThreadContext *pctx, int type_q, uint64_t (*Func)(void)) { StatsCounter **head = &pctx->head; StatsCounter *temp = NULL; @@ -611,7 +611,7 @@ static uint16_t StatsRegisterQualifiedCounter(const char *name, const char *tm_n /* We already have a counter registered by this name */ if (temp != NULL) - return(temp->id); + return (temp->id); /* if we reach this point we don't have a counter registered by this name */ if ((pc = SCCalloc(1, sizeof(StatsCounter))) == NULL) @@ -704,8 +704,7 @@ static int StatsOutput(ThreadVars *tv) int64_t value; uint64_t updates; } merge_table[max_id]; - memset(&merge_table, 0x00, - max_id * sizeof(struct CountersMergeTable)); + memset(&merge_table, 0x00, max_id * sizeof(struct CountersMergeTable)); int thread = stats_ctx->sts_cnt - 1; StatsRecord *table = stats_table.stats; @@ -723,14 +722,12 @@ static int StatsOutput(ThreadVars *tv) * thread store, so that we can post process them outside * of the thread store lock */ struct CountersMergeTable thread_table[max_id]; - memset(&thread_table, 0x00, - max_id * sizeof(struct CountersMergeTable)); + memset(&thread_table, 0x00, max_id * sizeof(struct CountersMergeTable)); SCMutexLock(&sts->ctx->m); pc = sts->ctx->head; while (pc != NULL) { - SCLogDebug("Counter %s (%u:%u) value %"PRIu64, - pc->name, pc->id, pc->gid, pc->value); + SCLogDebug("Counter %s (%u:%u) value %" PRIu64, pc->name, pc->id, pc->gid, pc->value); thread_table[pc->gid].type = pc->type; switch (pc->type) { @@ -843,8 +840,7 @@ static int StatsOutput(ThreadVars *tv) #ifdef BUILD_UNIX_SOCKET /** \brief callback for getting stats into unix socket */ -TmEcode StatsOutputCounterSocket(json_t *cmd, - json_t *answer, void *data) +TmEcode StatsOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { json_t *message = NULL; TmEcode r = TM_ECODE_OK; @@ -858,7 +854,7 @@ TmEcode StatsOutputCounterSocket(json_t *cmd, r = TM_ECODE_FAILED; message = json_string("stats not yet synchronized"); } else { - message = StatsToJSON(&stats_table, JSON_STATS_TOTALS|JSON_STATS_THREADS); + message = StatsToJSON(&stats_table, JSON_STATS_TOTALS | JSON_STATS_THREADS); } SCMutexUnlock(&stats_table_mutex); } @@ -885,7 +881,7 @@ static void StatsLogSummary(void) } } SCMutexUnlock(&stats_table_mutex); - SCLogInfo("Alerts: %"PRIu64, alerts); + SCLogInfo("Alerts: %" PRIu64, alerts); } /** @@ -912,7 +908,6 @@ void StatsSetupPostConfigPostOutput(void) StatsInitCtxPostOutput(); } - /** * \brief Spawns the wakeup, and the management thread used by the stats api * @@ -931,8 +926,7 @@ void StatsSpawnThreads(void) ThreadVars *tv_mgmt = NULL; /* spawn the stats wakeup thread */ - tv_wakeup = TmThreadCreateMgmtThread(thread_name_counter_wakeup, - StatsWakeupThread, 1); + tv_wakeup = TmThreadCreateMgmtThread(thread_name_counter_wakeup, StatsWakeupThread, 1); if (tv_wakeup == NULL) { FatalError("TmThreadCreateMgmtThread " "failed"); @@ -944,8 +938,7 @@ void StatsSpawnThreads(void) } /* spawn the stats mgmt thread */ - tv_mgmt = TmThreadCreateMgmtThread(thread_name_counter_stats, - StatsMgmtThread, 1); + tv_mgmt = TmThreadCreateMgmtThread(thread_name_counter_stats, StatsMgmtThread, 1); if (tv_mgmt == NULL) { FatalError("TmThreadCreateMgmtThread failed"); } @@ -972,8 +965,7 @@ uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv) { uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->printable_name, - &tv->perf_public_ctx, - STATS_TYPE_NORMAL, NULL); + &tv->perf_public_ctx, STATS_TYPE_NORMAL, NULL); return id; } @@ -992,8 +984,7 @@ uint16_t StatsRegisterAvgCounter(const char *name, struct ThreadVars_ *tv) { uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->printable_name, - &tv->perf_public_ctx, - STATS_TYPE_AVERAGE, NULL); + &tv->perf_public_ctx, STATS_TYPE_AVERAGE, NULL); return id; } @@ -1012,8 +1003,7 @@ uint16_t StatsRegisterMaxCounter(const char *name, struct ThreadVars_ *tv) { uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->printable_name, - &tv->perf_public_ctx, - STATS_TYPE_MAXIMUM, NULL); + &tv->perf_public_ctx, STATS_TYPE_MAXIMUM, NULL); return id; } @@ -1028,16 +1018,14 @@ uint16_t StatsRegisterMaxCounter(const char *name, struct ThreadVars_ *tv) */ uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t (*Func)(void)) { -#if defined (UNITTESTS) || defined (FUZZ) +#if defined(UNITTESTS) || defined(FUZZ) if (stats_ctx == NULL) return 0; #else BUG_ON(stats_ctx == NULL); #endif - uint16_t id = StatsRegisterQualifiedCounter(name, NULL, - &(stats_ctx->global_counter_ctx), - STATS_TYPE_FUNC, - Func); + uint16_t id = StatsRegisterQualifiedCounter( + name, NULL, &(stats_ctx->global_counter_ctx), STATS_TYPE_FUNC, Func); return id; } @@ -1059,8 +1047,8 @@ static uint32_t CountersIdHashFunc(HashTable *ht, void *data, uint16_t datalen) return hash; } -static char CountersIdHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2) +static char CountersIdHashCompareFunc( + void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) { CountersIdType *t1 = (CountersIdType *)data1; CountersIdType *t2 = (CountersIdType *)data2; @@ -1088,7 +1076,6 @@ static void CountersIdHashFreeFunc(void *data) SCFree(data); } - /** \internal * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM * are stacked together in a PCTMI container. @@ -1112,9 +1099,8 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext SCMutexLock(&stats_ctx->sts_lock); if (stats_ctx->counters_id_hash == NULL) { - stats_ctx->counters_id_hash = HashTableInit(256, CountersIdHashFunc, - CountersIdHashCompareFunc, - CountersIdHashFreeFunc); + stats_ctx->counters_id_hash = HashTableInit( + 256, CountersIdHashFunc, CountersIdHashCompareFunc, CountersIdHashFreeFunc); BUG_ON(stats_ctx->counters_id_hash == NULL); } StatsCounter *pc = pctx->head; @@ -1132,7 +1118,6 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext pc = pc->next; } - StatsThreadStore *temp = NULL; if ((temp = SCCalloc(1, sizeof(StatsThreadStore))) == NULL) { SCMutexUnlock(&stats_ctx->sts_lock); @@ -1160,9 +1145,8 @@ static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext * * \retval a counter-array in this(s_id-e_id) range for this TM instance */ -static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id, - StatsPublicThreadContext *pctx, - StatsPrivateThreadContext *pca) +static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id, StatsPublicThreadContext *pctx, + StatsPrivateThreadContext *pca) { StatsCounter *pc = NULL; uint32_t i = 0; @@ -1212,7 +1196,8 @@ static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id, * \retval pca Pointer to a counter-array for all counter of this tm instance * on success; NULL on failure */ -static int StatsGetAllCountersArray(StatsPublicThreadContext *pctx, StatsPrivateThreadContext *private) +static int StatsGetAllCountersArray( + StatsPublicThreadContext *pctx, StatsPrivateThreadContext *private) { if (pctx == NULL || private == NULL) return -1; @@ -1220,13 +1205,11 @@ static int StatsGetAllCountersArray(StatsPublicThreadContext *pctx, StatsPrivate return StatsGetCounterArrayRange(1, pctx->curr_id, pctx, private); } - int StatsSetupPrivate(ThreadVars *tv) { StatsGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); - StatsThreadRegister(tv->printable_name ? tv->printable_name : tv->name, - &(tv)->perf_public_ctx); + StatsThreadRegister(tv->printable_name ? tv->printable_name : tv->name, &(tv)->perf_public_ctx); return 0; } @@ -1271,7 +1254,7 @@ uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id) { StatsPrivateThreadContext *pca = &tv->perf_private_ctx; #ifdef DEBUG - BUG_ON ((id < 1) || (id > pca->size)); + BUG_ON((id < 1) || (id > pca->size)); #endif return pca->head[id].value; } @@ -1342,11 +1325,10 @@ void StatsThreadCleanup(ThreadVars *tv) * \retval id Counter id for the newly registered counter, or the already * present counter */ -static uint16_t RegisterCounter(const char *name, const char *tm_name, - StatsPublicThreadContext *pctx) +static uint16_t RegisterCounter( + const char *name, const char *tm_name, StatsPublicThreadContext *pctx) { - uint16_t id = StatsRegisterQualifiedCounter(name, tm_name, pctx, - STATS_TYPE_NORMAL, NULL); + uint16_t id = StatsRegisterQualifiedCounter(name, tm_name, pctx, STATS_TYPE_NORMAL, NULL); return id; } @@ -1436,7 +1418,7 @@ static int StatsTestCntArraySize07(void) memset(&tv, 0, sizeof(ThreadVars)); - //pca = (StatsPrivateThreadContext *)&tv.perf_private_ctx; + // pca = (StatsPrivateThreadContext *)&tv.perf_private_ctx; RegisterCounter("t1", "c1", &tv.perf_public_ctx); RegisterCounter("t2", "c2", &tv.perf_public_ctx); @@ -1592,8 +1574,7 @@ void StatsRegisterTests(void) UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07); UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08); UtRegisterTest("StatsTestUpdateCounter09", StatsTestUpdateCounter09); - UtRegisterTest("StatsTestUpdateGlobalCounter10", - StatsTestUpdateGlobalCounter10); + UtRegisterTest("StatsTestUpdateGlobalCounter10", StatsTestUpdateGlobalCounter10); UtRegisterTest("StatsTestCounterValues11", StatsTestCounterValues11); #endif } diff --git a/src/counters.h b/src/counters.h index b3ffddbd569f..d73a8f711f01 100644 --- a/src/counters.h +++ b/src/counters.h @@ -43,8 +43,8 @@ typedef struct StatsCounter_ { uint16_t gid; /* counter value(s): copies from the 'private' counter */ - int64_t value; /**< sum of updates/increments, or 'set' value */ - uint64_t updates; /**< number of updates (for avg) */ + int64_t value; /**< sum of updates/increments, or 'set' value */ + uint64_t updates; /**< number of updates (for avg) */ /* when using type STATS_TYPE_Q_FUNC this function is called once * to get the counter value, regardless of how many threads there are. */ @@ -139,9 +139,7 @@ void StatsSyncCounters(struct ThreadVars_ *tv); void StatsSyncCountersIfSignalled(struct ThreadVars_ *tv); #ifdef BUILD_UNIX_SOCKET -TmEcode StatsOutputCounterSocket(json_t *cmd, - json_t *answer, void *data); +TmEcode StatsOutputCounterSocket(json_t *cmd, json_t *answer, void *data); #endif #endif /* __COUNTERS_H__ */ - diff --git a/src/datasets-ipv4.c b/src/datasets-ipv4.c index f1192a0db5d1..3c18cabfa393 100644 --- a/src/datasets-ipv4.c +++ b/src/datasets-ipv4.c @@ -25,8 +25,8 @@ #include "conf.h" #include "datasets.h" #include "datasets-ipv4.h" -#include "util-thash.h" -#include "util-print.h" +#include "util/thash.h" +#include "util/print.h" int IPv4Set(void *dst, void *src) { diff --git a/src/datasets-ipv6.c b/src/datasets-ipv6.c index f907320f007d..1bd2d944353a 100644 --- a/src/datasets-ipv6.c +++ b/src/datasets-ipv6.c @@ -25,8 +25,8 @@ #include "conf.h" #include "datasets.h" #include "datasets-ipv6.h" -#include "util-thash.h" -#include "util-print.h" +#include "util/thash.h" +#include "util/print.h" int IPv6Set(void *dst, void *src) { diff --git a/src/datasets-md5.c b/src/datasets-md5.c index 3b1d8f3fc02c..cbfd6a17b0d7 100644 --- a/src/datasets-md5.c +++ b/src/datasets-md5.c @@ -25,9 +25,9 @@ #include "conf.h" #include "datasets.h" #include "datasets-md5.h" -#include "util-thash.h" -#include "util-print.h" -#include "util-base64.h" // decode base64 +#include "util/thash.h" +#include "util/print.h" +#include "util/base64.h" // decode base64 int Md5StrSet(void *dst, void *src) { diff --git a/src/datasets-sha256.c b/src/datasets-sha256.c index 346397d6d6fa..e74c7b934b37 100644 --- a/src/datasets-sha256.c +++ b/src/datasets-sha256.c @@ -25,9 +25,9 @@ #include "conf.h" #include "datasets.h" #include "datasets-sha256.h" -#include "util-thash.h" -#include "util-print.h" -#include "util-base64.h" // decode base64 +#include "util/thash.h" +#include "util/print.h" +#include "util/base64.h" // decode base64 int Sha256StrSet(void *dst, void *src) { diff --git a/src/datasets-string.c b/src/datasets-string.c index 4a572898ceb3..f8e775f4a6a7 100644 --- a/src/datasets-string.c +++ b/src/datasets-string.c @@ -25,9 +25,9 @@ #include "conf.h" #include "datasets.h" #include "datasets-string.h" -#include "util-thash.h" -#include "util-print.h" -#include "util-base64.h" // decode base64 +#include "util/thash.h" +#include "util/print.h" +#include "util/base64.h" // decode base64 #include "rust.h" #if 0 @@ -49,8 +49,7 @@ int StringAsBase64(const void *s, char *out, size_t out_size) unsigned long len = Base64EncodeBufferSize(str->len); uint8_t encoded_data[len]; - if (Base64Encode((unsigned char *)str->ptr, str->len, - encoded_data, &len) != SC_BASE64_OK) + if (Base64Encode((unsigned char *)str->ptr, str->len, encoded_data, &len) != SC_BASE64_OK) return 0; strlcpy(out, (const char *)encoded_data, out_size); diff --git a/src/datasets.c b/src/datasets.c index d89ed8df59da..ad6f3e566bad 100644 --- a/src/datasets.c +++ b/src/datasets.c @@ -31,25 +31,25 @@ #include "datasets-md5.h" #include "datasets-sha256.h" #include "datasets-reputation.h" -#include "util-conf.h" -#include "util-thash.h" -#include "util-print.h" -#include "util-base64.h" // decode base64 -#include "util-byte.h" -#include "util-misc.h" -#include "util-path.h" -#include "util-debug.h" +#include "util/conf.h" +#include "util/thash.h" +#include "util/print.h" +#include "util/base64.h" // decode base64 +#include "util/byte.h" +#include "util/misc.h" +#include "util/path.h" +#include "util/debug.h" SCMutex sets_lock = SCMUTEX_INITIALIZER; static Dataset *sets = NULL; static uint32_t set_ids = 0; -static int DatasetAddwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, - DataRepType *rep); +static int DatasetAddwRep( + Dataset *set, const uint8_t *data, const uint32_t data_len, DataRepType *rep); static inline void DatasetUnlockData(THashData *d) { - (void) THashDecrUsecnt(d); + (void)THashDecrUsecnt(d); THashDataUnlock(d); } static bool DatasetIsStatic(const char *save, const char *load); @@ -103,10 +103,10 @@ static int HexToRaw(const uint8_t *in, size_t ins, uint8_t *out, size_t outs) uint8_t hash[outs]; memset(hash, 0, outs); size_t i, x; - for (x = 0, i = 0; i < ins; i+=2, x++) { + for (x = 0, i = 0; i < ins; i += 2, x++) { char buf[3] = { 0, 0, 0 }; buf[0] = in[i]; - buf[1] = in[i+1]; + buf[1] = in[i + 1]; long value = strtol(buf, NULL, 16); if (value >= 0 && value <= 255) @@ -129,7 +129,7 @@ static int ParseRepLine(const char *in, size_t ins, DataRepType *rep_out) raw[ins] = '\0'; char *line = raw; - char *ptrs[1] = {NULL}; + char *ptrs[1] = { NULL }; int idx = 0; size_t i = 0; @@ -159,7 +159,7 @@ static int ParseRepLine(const char *in, size_t ins, DataRepType *rep_out) SCLogError("'%s' is not a valid reputation value (0-65535)", ptrs[0]); return -1; } - SCLogDebug("v %"PRIu16" raw %s", v, ptrs[0]); + SCLogDebug("v %" PRIu16 " raw %s", v, ptrs[0]); rep_out->value = v; return 0; @@ -383,7 +383,7 @@ static int DatasetLoadMd5(Dataset *set) } cnt++; - /* list with rep data */ + /* list with rep data */ } else if (strlen(line) > 33 && line[32] == ',') { line[strlen(line) - 1] = '\0'; SCLogDebug("MD5 with REP line: '%s'", line); @@ -394,7 +394,7 @@ static int DatasetLoadMd5(Dataset *set) continue; } - DataRepType rep = { .value = 0}; + DataRepType rep = { .value = 0 }; if (ParseRepLine(line + 33, strlen(line) - 33, &rep) < 0) { FatalErrorOnInit("bad rep for dataset %s/%s", set->name, set->load); continue; @@ -407,8 +407,7 @@ static int DatasetLoadMd5(Dataset *set) } cnt++; - } - else { + } else { FatalErrorOnInit("MD5 bad line len %u: '%s'", (uint32_t)strlen(line), line); continue; } @@ -582,8 +581,8 @@ enum DatasetGetPathType { TYPE_LOAD, }; -static void DatasetGetPath(const char *in_path, - char *out_path, size_t out_size, enum DatasetGetPathType type) +static void DatasetGetPath( + const char *in_path, char *out_path, size_t out_size, enum DatasetGetPathType type) { char path[PATH_MAX]; struct stat st; @@ -649,8 +648,7 @@ Dataset *DatasetGet(const char *name, enum DatasetTypes type, const char *save, return NULL; } - if ((save == NULL || strlen(save) == 0) && - (load == NULL || strlen(load) == 0)) { + if ((save == NULL || strlen(save) == 0) && (load == NULL || strlen(load) == 0)) { // OK, rule keyword doesn't have to set state/load, // even when yaml set has set it. } else { @@ -746,8 +744,8 @@ Dataset *DatasetGet(const char *name, enum DatasetTypes type, const char *save, break; } - SCLogDebug("set %p/%s type %u save %s load %s", - set, set->name, set->type, set->save, set->load); + SCLogDebug( + "set %p/%s type %u save %s load %s", set, set->name, set->type, set->save, set->load); set->next = sets; sets = set; @@ -770,8 +768,7 @@ static bool DatasetIsStatic(const char *save, const char *load) /* A set is static if it does not have any dynamic properties like * save and/or state defined but has load defined. * */ - if ((load != NULL && strlen(load) > 0) && - (save == NULL || strlen(save) == 0)) { + if ((load != NULL && strlen(load) > 0) && (save == NULL || strlen(save) == 0)) { return true; } return false; @@ -856,7 +853,7 @@ int DatasetsInit(void) if (datasets != NULL) { int list_pos = 0; ConfNode *iter = NULL; - TAILQ_FOREACH(iter, &datasets->head, next) { + TAILQ_FOREACH (iter, &datasets->head, next) { if (iter->name == NULL) { list_pos++; continue; @@ -874,21 +871,18 @@ int DatasetsInit(void) continue; } - ConfNode *set_type = - ConfNodeLookupChild(iter, "type"); + ConfNode *set_type = ConfNodeLookupChild(iter, "type"); if (set_type == NULL) { list_pos++; continue; } - ConfNode *set_save = - ConfNodeLookupChild(iter, "state"); + ConfNode *set_save = ConfNodeLookupChild(iter, "state"); if (set_save) { DatasetGetPath(set_save->val, save, sizeof(save), TYPE_STATE); strlcpy(load, save, sizeof(load)); } else { - ConfNode *set_load = - ConfNodeLookupChild(iter, "load"); + ConfNode *set_load = ConfNodeLookupChild(iter, "load"); if (set_load) { DatasetGetPath(set_load->val, load, sizeof(load), TYPE_LOAD); } @@ -1000,7 +994,7 @@ void DatasetsDestroy(void) static int SaveCallback(void *ctx, const uint8_t *data, const uint32_t data_len) { FILE *fp = ctx; - //PrintRawDataFp(fp, data, data_len); + // PrintRawDataFp(fp, data, data_len); if (fp) { return fwrite(data, data_len, 1, fp); } @@ -1113,10 +1107,10 @@ static int DatasetLookupString(Dataset *set, const uint8_t *data, const uint32_t return 0; } -static DataRepResultType DatasetLookupStringwRep(Dataset *set, - const uint8_t *data, const uint32_t data_len, const DataRepType *rep) +static DataRepResultType DatasetLookupStringwRep( + Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep) { - DataRepResultType rrep = { .found = false, .rep = { .value = 0 }}; + DataRepResultType rrep = { .found = false, .rep = { .value = 0 } }; if (set == NULL) return rrep; @@ -1235,10 +1229,10 @@ static int DatasetLookupMd5(Dataset *set, const uint8_t *data, const uint32_t da return 0; } -static DataRepResultType DatasetLookupMd5wRep(Dataset *set, - const uint8_t *data, const uint32_t data_len, const DataRepType *rep) +static DataRepResultType DatasetLookupMd5wRep( + Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep) { - DataRepResultType rrep = { .found = false, .rep = { .value = 0 }}; + DataRepResultType rrep = { .found = false, .rep = { .value = 0 } }; if (set == NULL) return rrep; @@ -1246,7 +1240,7 @@ static DataRepResultType DatasetLookupMd5wRep(Dataset *set, if (data_len != 16) return rrep; - Md5Type lookup = { .rep.value = 0}; + Md5Type lookup = { .rep.value = 0 }; memcpy(lookup.md5, data, data_len); THashData *rdata = THashLookupFromHash(set->hash, &lookup); if (rdata) { @@ -1277,10 +1271,10 @@ static int DatasetLookupSha256(Dataset *set, const uint8_t *data, const uint32_t return 0; } -static DataRepResultType DatasetLookupSha256wRep(Dataset *set, - const uint8_t *data, const uint32_t data_len, const DataRepType *rep) +static DataRepResultType DatasetLookupSha256wRep( + Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep) { - DataRepResultType rrep = { .found = false, .rep = { .value = 0 }}; + DataRepResultType rrep = { .found = false, .rep = { .value = 0 } }; if (set == NULL) return rrep; @@ -1330,10 +1324,10 @@ int DatasetLookup(Dataset *set, const uint8_t *data, const uint32_t data_len) return -1; } -DataRepResultType DatasetLookupwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, - const DataRepType *rep) +DataRepResultType DatasetLookupwRep( + Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep) { - DataRepResultType rrep = { .found = false, .rep = { .value = 0 }}; + DataRepResultType rrep = { .found = false, .rep = { .value = 0 } }; if (set == NULL) return rrep; @@ -1362,8 +1356,7 @@ static int DatasetAddString(Dataset *set, const uint8_t *data, const uint32_t da if (set == NULL) return -1; - StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, - .rep.value = 0 }; + StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, .rep.value = 0 }; struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup); if (res.data) { DatasetUnlockData(res.data); @@ -1383,8 +1376,7 @@ static int DatasetAddStringwRep( if (set == NULL) return -1; - StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, - .rep = *rep }; + StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, .rep = *rep }; struct THashDataGetResult res = THashGetFromHash(set->hash, &lookup); if (res.data) { DatasetUnlockData(res.data); @@ -1565,8 +1557,8 @@ int DatasetAdd(Dataset *set, const uint8_t *data, const uint32_t data_len) return -1; } -static int DatasetAddwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, - DataRepType *rep) +static int DatasetAddwRep( + Dataset *set, const uint8_t *data, const uint32_t data_len, DataRepType *rep) { if (set == NULL) return -1; @@ -1674,8 +1666,7 @@ static int DatasetRemoveString(Dataset *set, const uint8_t *data, const uint32_t if (set == NULL) return -1; - StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, - .rep.value = 0 }; + StringType lookup = { .ptr = (uint8_t *)data, .len = data_len, .rep.value = 0 }; return THashRemoveFromHash(set->hash, &lookup); } diff --git a/src/datasets.h b/src/datasets.h index af4fc173f194..ec5b397c60fe 100644 --- a/src/datasets.h +++ b/src/datasets.h @@ -18,7 +18,7 @@ #ifndef __DATASETS_H__ #define __DATASETS_H__ -#include "util-thash.h" +#include "util/thash.h" #include "datasets-reputation.h" int DatasetsInit(void); @@ -41,8 +41,8 @@ typedef struct Dataset { char name[DATASET_NAME_MAX_LEN + 1]; enum DatasetTypes type; uint32_t id; - bool from_yaml; /* Mark whether the set was retrieved from YAML */ - bool hidden; /* Mark the old sets hidden in case of reload */ + bool from_yaml; /* Mark whether the set was retrieved from YAML */ + bool hidden; /* Mark the old sets hidden in case of reload */ THashTableContext *hash; char load[PATH_MAX]; @@ -57,8 +57,8 @@ Dataset *DatasetGet(const char *name, enum DatasetTypes type, const char *save, uint64_t memcap, uint32_t hashsize); int DatasetAdd(Dataset *set, const uint8_t *data, const uint32_t data_len); int DatasetLookup(Dataset *set, const uint8_t *data, const uint32_t data_len); -DataRepResultType DatasetLookupwRep(Dataset *set, const uint8_t *data, const uint32_t data_len, - const DataRepType *rep); +DataRepResultType DatasetLookupwRep( + Dataset *set, const uint8_t *data, const uint32_t data_len, const DataRepType *rep); int DatasetAddSerialized(Dataset *set, const char *string); int DatasetRemoveSerialized(Dataset *set, const char *string); diff --git a/src/decode-chdlc.c b/src/decode-chdlc.c index 1306114b8d7d..c53bfbfccf19 100644 --- a/src/decode-chdlc.c +++ b/src/decode-chdlc.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -35,12 +34,11 @@ #include "decode-chdlc.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" -int DecodeCHDLC(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeCHDLC(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -62,21 +60,23 @@ int DecodeCHDLC(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCLogDebug("p %p pkt %p ether type %04x", p, pkt, SCNtohs(hdr->protocol)); - DecodeNetworkLayer(tv, dtv, SCNtohs(hdr->protocol), p, - pkt + CHDLC_HEADER_LEN, len - CHDLC_HEADER_LEN); + DecodeNetworkLayer( + tv, dtv, SCNtohs(hdr->protocol), p, pkt + CHDLC_HEADER_LEN, len - CHDLC_HEADER_LEN); return TM_ECODE_OK; } #ifdef UNITTESTS -static int DecodeCHDLCTest01 (void) +static int DecodeCHDLCTest01(void) { + // clang-format off uint8_t raw[] = { 0x0f,0x00,0x08,0x00, // HDLC 0x45,0x00,0x00,0x30,0x15,0x5a,0x40,0x00,0x80,0x06, 0x6c,0xd0,0xc0,0xa8,0x02,0x07,0x41,0x37,0x74,0xb7, 0x13,0x4a,0x00,0x50,0x9c,0x34,0x09,0x6c,0x00,0x00, 0x00,0x00,0x70,0x02,0x40,0x00,0x11,0x47,0x00,0x00, 0x02,0x04,0x05,0xb4,0x01,0x01,0x04,0x02 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -84,7 +84,7 @@ static int DecodeCHDLCTest01 (void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeCHDLC(&tv, &dtv, p, raw, sizeof(raw)); @@ -97,7 +97,6 @@ static int DecodeCHDLCTest01 (void) } #endif /* UNITTESTS */ - /** * \brief Registers Ethernet unit tests * \todo More Ethernet tests diff --git a/src/decode-chdlc.h b/src/decode-chdlc.h index 47e0d7c1a3ef..9af4aa01e4c4 100644 --- a/src/decode-chdlc.h +++ b/src/decode-chdlc.h @@ -24,7 +24,7 @@ #ifndef __DECODE_CHDLC_H__ #define __DECODE_CHDLC_H__ -#define CHDLC_HEADER_LEN 4 +#define CHDLC_HEADER_LEN 4 typedef struct CHDLCHdr_ { uint8_t address; diff --git a/src/decode-erspan.c b/src/decode-erspan.c index ccdf64aeaef9..36e4a82b6746 100644 --- a/src/decode-erspan.c +++ b/src/decode-erspan.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -36,9 +35,9 @@ #include "decode-events.h" #include "decode-erspan.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" /** * \brief Functions to decode ERSPAN Type I and II packets @@ -61,8 +60,8 @@ void DecodeERSPANConfig(void) /** * \brief ERSPAN Type I */ -int DecodeERSPANTypeI(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeERSPANTypeI( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { StatsIncr(tv, dtv->counter_erspan); @@ -79,7 +78,7 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t StatsIncr(tv, dtv->counter_erspan); if (len < sizeof(ErspanHdr)) { - ENGINE_SET_EVENT(p,ERSPAN_HEADER_TOO_SMALL); + ENGINE_SET_EVENT(p, ERSPAN_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } if (!PacketIncreaseCheckLayers(p)) { @@ -94,13 +93,13 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t /* only v1 is tested at this time */ if (version != 1) { - ENGINE_SET_EVENT(p,ERSPAN_UNSUPPORTED_VERSION); + ENGINE_SET_EVENT(p, ERSPAN_UNSUPPORTED_VERSION); return TM_ECODE_FAILED; } if (vlan_id > 0) { if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { - ENGINE_SET_EVENT(p,ERSPAN_TOO_MANY_VLAN_LAYERS); + ENGINE_SET_EVENT(p, ERSPAN_TOO_MANY_VLAN_LAYERS); return TM_ECODE_FAILED; } p->vlan_id[p->vlan_idx] = vlan_id; diff --git a/src/decode-erspan.h b/src/decode-erspan.h index d92965db027f..a095ae0f025c 100644 --- a/src/decode-erspan.h +++ b/src/decode-erspan.h @@ -25,7 +25,6 @@ #ifndef __DECODE_ERSPAN_H__ #define __DECODE_ERSPAN_H__ - typedef struct ErspanHdr_ { uint16_t ver_vlan; uint16_t flags_spanid; diff --git a/src/decode-esp.c b/src/decode-esp.c index 1dd5b739b0d0..fc1712e3d55f 100644 --- a/src/decode-esp.c +++ b/src/decode-esp.c @@ -31,7 +31,7 @@ #include "decode-esp.h" #include "flow.h" -#include "util-validate.h" +#include "util/validate.h" static int DecodeESPPacket(ThreadVars *tv, Packet *p, const uint8_t *pkt, uint16_t len) { @@ -84,7 +84,7 @@ int DecodeESP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p #ifdef UNITTESTS -#include "util-unittest.h" +#include "util/unittest.h" /** \test Successful decoding */ static int DecodeESPTest01(void) diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index 62115b9fd490..4c11e9690f27 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -35,12 +34,12 @@ #include "decode-ethernet.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" -int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeEthernet( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -58,8 +57,8 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCLogDebug("p %p pkt %p ether type %04x", p, pkt, SCNtohs(p->ethh->eth_type)); - DecodeNetworkLayer(tv, dtv, SCNtohs(p->ethh->eth_type), p, - pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN); + DecodeNetworkLayer(tv, dtv, SCNtohs(p->ethh->eth_type), p, pkt + ETHERNET_HEADER_LEN, + len - ETHERNET_HEADER_LEN); return TM_ECODE_OK; } @@ -69,9 +68,10 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, * \brief Valid Ethernet packet * \retval 0 Expected test value */ -static int DecodeEthernetTest01 (void) +static int DecodeEthernetTest01(void) { /* ICMP packet wrapped in PPPOE */ + // clang-format off uint8_t raw_eth[] = { 0x00, 0x10, 0x94, 0x55, 0x00, 0x01, 0x00, 0x10, 0x94, 0x56, 0x00, 0x01, 0x88, 0x64, 0x11, 0x00, @@ -89,6 +89,7 @@ static int DecodeEthernetTest01 (void) 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -97,7 +98,7 @@ static int DecodeEthernetTest01 (void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth)); @@ -110,10 +111,12 @@ static int DecodeEthernetTest01 (void) */ static int DecodeEthernetTestDceTooSmall(void) { + // clang-format off uint8_t raw_eth[] = { 0x00, 0x10, 0x94, 0x55, 0x00, 0x01, 0x00, 0x10, 0x94, 0x56, 0x00, 0x01, 0x89, 0x03, }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -121,7 +124,7 @@ static int DecodeEthernetTestDceTooSmall(void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth)); @@ -140,6 +143,7 @@ static int DecodeEthernetTestDceTooSmall(void) */ static int DecodeEthernetTestDceNextTooSmall(void) { + // clang-format off uint8_t raw_eth[] = { 0x00, 0x10, 0x94, 0x55, 0x00, 0x01, 0x00, 0x10, 0x94, 0x56, 0x00, 0x01, 0x89, 0x03, //0x88, 0x64, @@ -149,6 +153,7 @@ static int DecodeEthernetTestDceNextTooSmall(void) 0x00, 0x10, 0x94, 0x55, 0x00, 0x01, 0x00, 0x10, 0x94, 0x56, 0x00, 0x01, }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -156,7 +161,7 @@ static int DecodeEthernetTestDceNextTooSmall(void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth)); @@ -168,7 +173,6 @@ static int DecodeEthernetTestDceNextTooSmall(void) #endif /* UNITTESTS */ - /** * \brief Registers Ethernet unit tests * \todo More Ethernet tests @@ -177,10 +181,8 @@ void DecodeEthernetRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01); - UtRegisterTest("DecodeEthernetTestDceNextTooSmall", - DecodeEthernetTestDceNextTooSmall); - UtRegisterTest("DecodeEthernetTestDceTooSmall", - DecodeEthernetTestDceTooSmall); + UtRegisterTest("DecodeEthernetTestDceNextTooSmall", DecodeEthernetTestDceNextTooSmall); + UtRegisterTest("DecodeEthernetTestDceTooSmall", DecodeEthernetTestDceTooSmall); #endif /* UNITTESTS */ } /** diff --git a/src/decode-ethernet.h b/src/decode-ethernet.h index aa077056d672..30794c69a0ef 100644 --- a/src/decode-ethernet.h +++ b/src/decode-ethernet.h @@ -24,31 +24,32 @@ #ifndef __DECODE_ETHERNET_H__ #define __DECODE_ETHERNET_H__ -#define ETHERNET_HEADER_LEN 14 +#define ETHERNET_HEADER_LEN 14 /* Cisco Fabric Path / DCE header length. */ -#define ETHERNET_DCE_HEADER_LEN (ETHERNET_HEADER_LEN + 2) +#define ETHERNET_DCE_HEADER_LEN (ETHERNET_HEADER_LEN + 2) /* Ethernet types -- taken from Snort and Libdnet */ -#define ETHERNET_TYPE_PUP 0x0200 /* PUP protocol */ -#define ETHERNET_TYPE_IP 0x0800 -#define ETHERNET_TYPE_ARP 0x0806 -#define ETHERNET_TYPE_BRIDGE 0x6558 /* transparent ethernet bridge (GRE) */ -#define ETHERNET_TYPE_REVARP 0x8035 -#define ETHERNET_TYPE_EAPOL 0x888e -#define ETHERNET_TYPE_IPV6 0x86dd -#define ETHERNET_TYPE_IPX 0x8137 -#define ETHERNET_TYPE_PPPOE_DISC 0x8863 /* discovery stage */ -#define ETHERNET_TYPE_PPPOE_SESS 0x8864 /* session stage */ -#define ETHERNET_TYPE_8021AD 0x88a8 -#define ETHERNET_TYPE_8021AH 0x88e7 -#define ETHERNET_TYPE_8021Q 0x8100 -#define ETHERNET_TYPE_LOOP 0x9000 -#define ETHERNET_TYPE_8021QINQ 0x9100 -#define ETHERNET_TYPE_ERSPAN 0x88BE -#define ETHERNET_TYPE_DCE 0x8903 /* Data center ethernet, - * Cisco Fabric Path */ -#define ETHERNET_TYPE_NSH 0x894F +#define ETHERNET_TYPE_PUP 0x0200 /* PUP protocol */ +#define ETHERNET_TYPE_IP 0x0800 +#define ETHERNET_TYPE_ARP 0x0806 +#define ETHERNET_TYPE_BRIDGE 0x6558 /* transparent ethernet bridge (GRE) */ +#define ETHERNET_TYPE_REVARP 0x8035 +#define ETHERNET_TYPE_EAPOL 0x888e +#define ETHERNET_TYPE_IPV6 0x86dd +#define ETHERNET_TYPE_IPX 0x8137 +#define ETHERNET_TYPE_PPPOE_DISC 0x8863 /* discovery stage */ +#define ETHERNET_TYPE_PPPOE_SESS 0x8864 /* session stage */ +#define ETHERNET_TYPE_8021AD 0x88a8 +#define ETHERNET_TYPE_8021AH 0x88e7 +#define ETHERNET_TYPE_8021Q 0x8100 +#define ETHERNET_TYPE_LOOP 0x9000 +#define ETHERNET_TYPE_8021QINQ 0x9100 +#define ETHERNET_TYPE_ERSPAN 0x88BE +#define ETHERNET_TYPE_DCE \ + 0x8903 /* Data center ethernet, \ + * Cisco Fabric Path */ +#define ETHERNET_TYPE_NSH 0x894F #define ETHERNET_TYPE_VNTAG 0x8926 /* 802.1Qbh */ typedef struct EthernetHdr_ { @@ -60,4 +61,3 @@ typedef struct EthernetHdr_ { void DecodeEthernetRegisterTests(void); #endif /* __DECODE_ETHERNET_H__ */ - diff --git a/src/decode-events.h b/src/decode-events.h index 5547866fa59b..2340b718a4ab 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -301,8 +301,7 @@ enum { DECODE_EVENT_MAX, }; -#define EVENT_IS_DECODER_PACKET_ERROR(e) \ - ((e) < (DECODE_EVENT_PACKET_MAX)) +#define EVENT_IS_DECODER_PACKET_ERROR(e) ((e) < (DECODE_EVENT_PACKET_MAX)) /* supported decoder events */ diff --git a/src/decode-geneve.c b/src/decode-geneve.c index 29038f8ce692..857d21506e34 100644 --- a/src/decode-geneve.c +++ b/src/decode-geneve.c @@ -36,12 +36,12 @@ #include "flow.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" #include "pkt-var.h" -#include "util-profiling.h" +#include "util/profiling.h" #include "host.h" #define VALID_GENEVE_VERSIONS \ @@ -272,6 +272,7 @@ int DecodeGeneve(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t */ static int DecodeGeneveTest01(void) { + // clang-format off uint8_t raw_geneve[] = { 0x32, 0x10, 0x17, 0xc1, 0x00, 0xc1, 0x87, 0x51, /* UDP header */ 0x04, 0x00, 0x65, 0x58, 0x00, 0x00, 0x25, 0x00, /* Geneve fixed header */ 0x01, 0x08, 0x00, 0x01, 0x11, 0x11, 0x11, 0x11, /* Geneve variable options */ @@ -291,6 +292,7 @@ static int DecodeGeneveTest01(void) 0x15, 0x18, 0x00, 0x1a, 0x00, 0x19, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x1d, 0x4c, 0x40, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -324,6 +326,7 @@ static int DecodeGeneveTest01(void) */ static int DecodeGeneveTest02(void) { + // clang-format off uint8_t raw_geneve[] = { 0x32, 0x10, 0x17, 0xc1, 0x00, 0x3c, 0x87, 0x51, /* UDP header */ 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x25, 0x00, /* Geneve fixed header */ @@ -333,6 +336,7 @@ static int DecodeGeneveTest02(void) 0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06, 0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */ }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -367,6 +371,7 @@ static int DecodeGeneveTest02(void) */ static int DecodeGeneveTest03(void) { + // clang-format off uint8_t raw_geneve[] = { 0x32, 0x10, 0x17, 0xc1, 0x00, 0x4e, 0x87, 0x51, /* UDP header */ 0x04, 0x00, 0x65, 0x58, 0x00, 0x00, 0x25, 0x00, /* Geneve fixed header */ @@ -380,6 +385,7 @@ static int DecodeGeneveTest03(void) 0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06, 0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */ }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -412,6 +418,7 @@ static int DecodeGeneveTest03(void) */ static int DecodeGeneveTest04(void) { + // clang-format off uint8_t raw_geneve[] = { 0x32, 0x10, 0x17, 0xc1, 0x00, 0x4a, 0x87, 0x51, /* UDP header */ 0x04, 0x00, 0x65, 0x58, 0x00, 0x00, 0x25, 0x00, /* Geneve fixed header */ @@ -424,6 +431,7 @@ static int DecodeGeneveTest04(void) 0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06, 0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */ }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -452,6 +460,7 @@ static int DecodeGeneveTest04(void) */ static int DecodeGeneveTest05(void) { + // clang-format off uint8_t raw_geneve[] = { 0x32, 0x10, 0x17, 0xc1, 0x00, 0x4a, 0x87, 0x51, /* UDP header */ 0x04, 0x00, 0x65, 0x58, 0x00, 0x00, 0x25, 0x00, /* Geneve fixed header */ @@ -464,6 +473,7 @@ static int DecodeGeneveTest05(void) 0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06, 0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */ }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); diff --git a/src/decode-gre.c b/src/decode-gre.c index 6919f0544deb..6a701a48e992 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -36,9 +35,9 @@ #include "decode-events.h" #include "decode-gre.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" /** * \brief Function to decode GRE packets @@ -54,7 +53,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p StatsIncr(tv, dtv->counter_gre); - if(len < GRE_HDR_LEN) { + if (len < GRE_HDR_LEN) { ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); return TM_ECODE_FAILED; } @@ -64,11 +63,10 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p p->greh = (GREHdr *)pkt; - SCLogDebug("p %p pkt %p GRE protocol %04x Len: %d GRE version %x", - p, pkt, GRE_GET_PROTO(p->greh), len,GRE_GET_VERSION(p->greh)); + SCLogDebug("p %p pkt %p GRE protocol %04x Len: %d GRE version %x", p, pkt, + GRE_GET_PROTO(p->greh), len, GRE_GET_VERSION(p->greh)); - switch (GRE_GET_VERSION(p->greh)) - { + switch (GRE_GET_VERSION(p->greh)) { case GRE_VERSION_0: /* GRE version 0 doesn't support the fields below RFC 1701 */ @@ -85,7 +83,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p return TM_ECODE_OK; } - if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { + if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_FLAGS); return TM_ECODE_OK; } @@ -101,18 +99,15 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p if (GRE_FLAG_ISSET_CHKSUM(p->greh) || GRE_FLAG_ISSET_ROUTE(p->greh)) header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN; - if (header_len > len) { + if (header_len > len) { ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_HDR_TOO_BIG); return TM_ECODE_OK; } - if (GRE_FLAG_ISSET_ROUTE(p->greh)) - { - while (1) - { + if (GRE_FLAG_ISSET_ROUTE(p->greh)) { + while (1) { if ((header_len + GRE_SRE_HDR_LEN) > len) { - ENGINE_SET_INVALID_EVENT(p, - GRE_VERSION0_MALFORMED_SRE_HDR); + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return TM_ECODE_OK; } @@ -125,8 +120,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p header_len += gsre->sre_length; if (header_len > len) { - ENGINE_SET_INVALID_EVENT(p, - GRE_VERSION0_MALFORMED_SRE_HDR); + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return TM_ECODE_OK; } } @@ -144,38 +138,38 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p * further into it. */ - if (GRE_FLAG_ISSET_CHKSUM(p->greh)) { - ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_CHKSUM); + if (GRE_FLAG_ISSET_CHKSUM(p->greh)) { + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_CHKSUM); return TM_ECODE_OK; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { - ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_ROUTE); + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_ROUTE); return TM_ECODE_OK; } - if (GRE_FLAG_ISSET_SSR(p->greh)) { - ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_SSR); + if (GRE_FLAG_ISSET_SSR(p->greh)) { + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_SSR); return TM_ECODE_OK; } if (GRE_FLAG_ISSET_RECUR(p->greh)) { - ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_RECUR); + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_RECUR); return TM_ECODE_OK; } - if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { - ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_FLAGS); + if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_FLAGS); return TM_ECODE_OK; } - if (GRE_GET_PROTO(p->greh) != GRE_PROTO_PPP) { - ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL); + if (GRE_GET_PROTO(p->greh) != GRE_PROTO_PPP) { + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_WRONG_PROTOCOL); return TM_ECODE_OK; } if (!(GRE_FLAG_ISSET_KY(p->greh))) { - ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_NO_KEY); + ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_NO_KEY); return TM_ECODE_OK; } @@ -191,7 +185,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p if (GREV1_FLAG_ISSET_ACK(p->greh)) header_len += GREV1_ACK_LEN; - if (header_len > len) { + if (header_len > len) { ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_HDR_TOO_BIG); return TM_ECODE_OK; } @@ -202,80 +196,71 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p return TM_ECODE_OK; } - switch (GRE_GET_PROTO(p->greh)) - { - case ETHERNET_TYPE_IP: - { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, DECODE_TUNNEL_IPV4); + switch (GRE_GET_PROTO(p->greh)) { + case ETHERNET_TYPE_IP: { + Packet *tp = PacketTunnelPktSetup( + tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_IPV4); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); } break; } - case GRE_PROTO_PPP: - { + case GRE_PROTO_PPP: { if (gre_pptp_h && !gre_pptp_h->payload_length) return TM_ECODE_OK; - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, DECODE_TUNNEL_PPP); + Packet *tp = PacketTunnelPktSetup( + tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_PPP); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); } break; } - case ETHERNET_TYPE_IPV6: - { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, DECODE_TUNNEL_IPV6); + case ETHERNET_TYPE_IPV6: { + Packet *tp = PacketTunnelPktSetup( + tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_IPV6); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); } break; } - case ETHERNET_TYPE_VLAN: - { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, DECODE_TUNNEL_VLAN); + case ETHERNET_TYPE_VLAN: { + Packet *tp = PacketTunnelPktSetup( + tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_VLAN); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); } break; } - case ETHERNET_TYPE_ERSPAN: - { + case ETHERNET_TYPE_ERSPAN: { // Determine if it's Type I or Type II based on the flags in the GRE header. // Type I: 0|0|0|0|0|00000|000000000|00000 // Type II: 0|0|0|1|0|00000|000000000|00000 // Seq - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, - GRE_FLAG_ISSET_SQ(p->greh) == 0 ? - DECODE_TUNNEL_ERSPANI : - DECODE_TUNNEL_ERSPANII); + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, + GRE_FLAG_ISSET_SQ(p->greh) == 0 ? DECODE_TUNNEL_ERSPANI + : DECODE_TUNNEL_ERSPANII); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); } break; } - case ETHERNET_TYPE_BRIDGE: - { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, DECODE_TUNNEL_ETHERNET); + case ETHERNET_TYPE_BRIDGE: { + Packet *tp = PacketTunnelPktSetup( + tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_ETHERNET); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); } break; } @@ -286,15 +271,14 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p return TM_ECODE_OK; } - #ifdef UNITTESTS /** * \test DecodeGRETest01 is a test for small gre packet */ -static int DecodeGREtest01 (void) +static int DecodeGREtest01(void) { - uint8_t raw_gre[] = { 0x00 ,0x6e ,0x62 }; + uint8_t raw_gre[] = { 0x00, 0x6e, 0x62 }; Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; @@ -314,8 +298,9 @@ static int DecodeGREtest01 (void) * \test DecodeGRETest02 is a test for wrong gre version */ -static int DecodeGREtest02 (void) +static int DecodeGREtest02(void) { + // clang-format off uint8_t raw_gre[] = { 0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f, 0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00, @@ -331,6 +316,7 @@ static int DecodeGREtest02 (void) 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; @@ -346,13 +332,13 @@ static int DecodeGREtest02 (void) PASS; } - /** * \test DecodeGRETest03 is a test for valid gre packet */ -static int DecodeGREtest03 (void) +static int DecodeGREtest03(void) { + // clang-format off uint8_t raw_gre[] = { 0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f, 0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00, @@ -368,6 +354,7 @@ static int DecodeGREtest03 (void) 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; diff --git a/src/decode-gre.h b/src/decode-gre.h index adf576fbd980..c9b383902732 100644 --- a/src/decode-gre.h +++ b/src/decode-gre.h @@ -30,11 +30,9 @@ #define IPPROTO_GRE 47 #endif - -typedef struct GREHdr_ -{ - uint8_t flags; /**< GRE packet flags */ - uint8_t version; /**< GRE version */ +typedef struct GREHdr_ { + uint8_t flags; /**< GRE packet flags */ + uint8_t version; /**< GRE version */ uint16_t ether_type; /**< ether type of the encapsulated traffic */ } __attribute__((__packed__)) GREHdr; @@ -49,40 +47,38 @@ typedef struct GREPPtPHdr_ { /* Generic Routing Encapsulation Source Route Entries (SREs). * The header is followed by a variable amount of Routing Information. */ -typedef struct GRESreHdr_ -{ +typedef struct GRESreHdr_ { uint16_t af; /**< Address family */ uint8_t sre_offset; uint8_t sre_length; } __attribute__((__packed__)) GRESreHdr; -#define GRE_VERSION_0 0x0000 -#define GRE_VERSION_1 0x0001 +#define GRE_VERSION_0 0x0000 +#define GRE_VERSION_1 0x0001 -#define GRE_HDR_LEN 4 -#define GRE_CHKSUM_LEN 2 -#define GRE_OFFSET_LEN 2 -#define GRE_KEY_LEN 4 -#define GRE_SEQ_LEN 4 -#define GRE_SRE_HDR_LEN 4 -#define GRE_PROTO_PPP 0x880b +#define GRE_HDR_LEN 4 +#define GRE_CHKSUM_LEN 2 +#define GRE_OFFSET_LEN 2 +#define GRE_KEY_LEN 4 +#define GRE_SEQ_LEN 4 +#define GRE_SRE_HDR_LEN 4 +#define GRE_PROTO_PPP 0x880b -#define GRE_FLAG_ISSET_CHKSUM(r) (r->flags & 0x80) -#define GRE_FLAG_ISSET_ROUTE(r) (r->flags & 0x40) -#define GRE_FLAG_ISSET_KY(r) (r->flags & 0x20) -#define GRE_FLAG_ISSET_SQ(r) (r->flags & 0x10) -#define GRE_FLAG_ISSET_SSR(r) (r->flags & 0x08) -#define GRE_FLAG_ISSET_RECUR(r) (r->flags & 0x07) -#define GRE_GET_VERSION(r) (r->version & 0x07) -#define GRE_GET_FLAGS(r) (r->version & 0xF8) -#define GRE_GET_PROTO(r) SCNtohs(r->ether_type) +#define GRE_FLAG_ISSET_CHKSUM(r) (r->flags & 0x80) +#define GRE_FLAG_ISSET_ROUTE(r) (r->flags & 0x40) +#define GRE_FLAG_ISSET_KY(r) (r->flags & 0x20) +#define GRE_FLAG_ISSET_SQ(r) (r->flags & 0x10) +#define GRE_FLAG_ISSET_SSR(r) (r->flags & 0x08) +#define GRE_FLAG_ISSET_RECUR(r) (r->flags & 0x07) +#define GRE_GET_VERSION(r) (r->version & 0x07) +#define GRE_GET_FLAGS(r) (r->version & 0xF8) +#define GRE_GET_PROTO(r) SCNtohs(r->ether_type) -#define GREV1_HDR_LEN 8 -#define GREV1_ACK_LEN 4 -#define GREV1_FLAG_ISSET_FLAGS(r) (r->version & 0x78) -#define GREV1_FLAG_ISSET_ACK(r) (r->version & 0x80) +#define GREV1_HDR_LEN 8 +#define GREV1_ACK_LEN 4 +#define GREV1_FLAG_ISSET_FLAGS(r) (r->version & 0x78) +#define GREV1_FLAG_ISSET_ACK(r) (r->version & 0x80) void DecodeGRERegisterTests(void); #endif /* __DECODE_GRE_H__ */ - diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 06209c743b12..f9e3305aa4aa 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -39,16 +38,16 @@ #include "flow.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-validate.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/validate.h" /** * Note, this is the IP header, plus a bit of the original packet, not the whole thing! */ -static int DecodePartialIPV4(Packet* p, uint8_t* partial_packet, uint16_t len) +static int DecodePartialIPV4(Packet *p, uint8_t *partial_packet, uint16_t len) { /** Check the sizes, the header must fit at least */ if (len < IPV4_HEADER_LEN) { @@ -57,7 +56,7 @@ static int DecodePartialIPV4(Packet* p, uint8_t* partial_packet, uint16_t len) return -1; } - IPV4Hdr *icmp4_ip4h = (IPV4Hdr*)partial_packet; + IPV4Hdr *icmp4_ip4h = (IPV4Hdr *)partial_packet; /** Check the embedded version */ if (IPV4_GET_RAW_VER(icmp4_ip4h) != 4) { @@ -79,26 +78,26 @@ static int DecodePartialIPV4(Packet* p, uint8_t* partial_packet, uint16_t len) switch (IPV4_GET_RAW_IPPROTO(icmp4_ip4h)) { case IPPROTO_TCP: - if (len >= IPV4_HEADER_LEN + TCP_HEADER_LEN ) { - p->icmpv4vars.emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); + if (len >= IPV4_HEADER_LEN + TCP_HEADER_LEN) { + p->icmpv4vars.emb_tcph = (TCPHdr *)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = SCNtohs(p->icmpv4vars.emb_tcph->th_sport); p->icmpv4vars.emb_dport = SCNtohs(p->icmpv4vars.emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP header sport: " - "%"PRIu16" dport %"PRIu16"", p->icmpv4vars.emb_sport, - p->icmpv4vars.emb_dport); + "%" PRIu16 " dport %" PRIu16 "", + p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else if (len >= IPV4_HEADER_LEN + 4) { /* only access th_sport and th_dport */ - TCPHdr *emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); + TCPHdr *emb_tcph = (TCPHdr *)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_tcph = NULL; p->icmpv4vars.emb_sport = SCNtohs(emb_tcph->th_sport); p->icmpv4vars.emb_dport = SCNtohs(emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP partial header sport: " - "%"PRIu16" dport %"PRIu16"", p->icmpv4vars.emb_sport, - p->icmpv4vars.emb_dport); + "%" PRIu16 " dport %" PRIu16 "", + p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->TCP " "header Didn't fit in the packet!"); @@ -108,15 +107,15 @@ static int DecodePartialIPV4(Packet* p, uint8_t* partial_packet, uint16_t len) break; case IPPROTO_UDP: - if (len >= IPV4_HEADER_LEN + UDP_HEADER_LEN ) { - p->icmpv4vars.emb_udph = (UDPHdr*)(partial_packet + IPV4_HEADER_LEN); + if (len >= IPV4_HEADER_LEN + UDP_HEADER_LEN) { + p->icmpv4vars.emb_udph = (UDPHdr *)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = SCNtohs(p->icmpv4vars.emb_udph->uh_sport); p->icmpv4vars.emb_dport = SCNtohs(p->icmpv4vars.emb_udph->uh_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_UDP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->UDP header sport: " - "%"PRIu16" dport %"PRIu16"", p->icmpv4vars.emb_sport, - p->icmpv4vars.emb_dport); + "%" PRIu16 " dport %" PRIu16 "", + p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->UDP " "header Didn't fit in the packet!"); @@ -126,8 +125,8 @@ static int DecodePartialIPV4(Packet* p, uint8_t* partial_packet, uint16_t len) break; case IPPROTO_ICMP: - if (len >= IPV4_HEADER_LEN + ICMPV4_HEADER_LEN ) { - p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); + if (len >= IPV4_HEADER_LEN + ICMPV4_HEADER_LEN) { + p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr *)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; @@ -138,12 +137,12 @@ static int DecodePartialIPV4(Packet* p, uint8_t* partial_packet, uint16_t len) break; } - /* debug print */ + /* debug print */ #ifdef DEBUG char s[16], d[16]; PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_src), s, sizeof(s)); PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_dst), d, sizeof(d)); - SCLogDebug("ICMPv4 embedding IPV4 %s->%s - PROTO: %" PRIu32 " ID: %" PRIu32 "", s,d, + SCLogDebug("ICMPv4 embedding IPV4 %s->%s - PROTO: %" PRIu32 " ID: %" PRIu32 "", s, d, IPV4_GET_RAW_IPPROTO(icmp4_ip4h), IPV4_GET_RAW_IPID(icmp4_ip4h)); #endif @@ -175,22 +174,21 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t p->icmp_d.type = (uint8_t)ctype; } - ICMPV4ExtHdr* icmp4eh = (ICMPV4ExtHdr*) p->icmpv4h; + ICMPV4ExtHdr *icmp4eh = (ICMPV4ExtHdr *)p->icmpv4h; p->icmpv4vars.hlen = ICMPV4_HEADER_LEN; - switch (p->icmpv4h->type) - { + switch (p->icmpv4h->type) { case ICMP_ECHOREPLY: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } break; case ICMP_DEST_UNREACH: if (p->icmpv4h->code > NR_ICMP_UNREACH) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } else { /* parse IP header plus 64 bytes */ if (len > ICMPV4_HEADER_PKT_OFFSET) { @@ -204,8 +202,8 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t break; case ICMP_SOURCE_QUENCH: - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len >= ICMPV4_HEADER_PKT_OFFSET) { @@ -219,8 +217,8 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t break; case ICMP_REDIRECT: - if (p->icmpv4h->code>ICMP_REDIR_HOSTTOS) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + if (p->icmpv4h->code > ICMP_REDIR_HOSTTOS) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) { @@ -234,16 +232,16 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t break; case ICMP_ECHO: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } break; case ICMP_TIME_EXCEEDED: - if (p->icmpv4h->code>ICMP_EXC_FRAGTIME) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + if (p->icmpv4h->code > ICMP_EXC_FRAGTIME) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) { @@ -257,8 +255,8 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t break; case ICMP_PARAMETERPROB: - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) { @@ -272,10 +270,10 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t break; case ICMP_TIMESTAMP: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } if (len < (sizeof(ICMPV4Timestamp) + ICMPV4_HEADER_LEN)) { @@ -286,10 +284,10 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t break; case ICMP_TIMESTAMPREPLY: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } if (len < (sizeof(ICMPV4Timestamp) + ICMPV4_HEADER_LEN)) { @@ -300,18 +298,18 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t break; case ICMP_INFO_REQUEST: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } break; case ICMP_INFO_REPLY: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } break; @@ -328,24 +326,23 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t } break; case ICMP_ADDRESS: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } break; case ICMP_ADDRESSREPLY: - p->icmpv4vars.id=icmp4eh->id; - p->icmpv4vars.seq=icmp4eh->seq; - if (p->icmpv4h->code!=0) { - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + p->icmpv4vars.id = icmp4eh->id; + p->icmpv4vars.seq = icmp4eh->seq; + if (p->icmpv4h->code != 0) { + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_CODE); } break; default: - ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_TYPE); - + ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_TYPE); } p->payload = (uint8_t *)pkt + p->icmpv4vars.hlen; @@ -359,13 +356,17 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t /** \retval type counterpart type or -1 */ int ICMPv4GetCounterpart(uint8_t type) { -#define CASE_CODE(t,r) case (t): return r; case (r): return t; +#define CASE_CODE(t, r) \ + case (t): \ + return r; \ + case (r): \ + return t; switch (type) { - CASE_CODE(ICMP_ECHO, ICMP_ECHOREPLY); - CASE_CODE(ICMP_TIMESTAMP, ICMP_TIMESTAMPREPLY); - CASE_CODE(ICMP_INFO_REQUEST, ICMP_INFO_REPLY); - CASE_CODE(ICMP_ROUTERSOLICIT, ICMP_ROUTERADVERT); - CASE_CODE(ICMP_ADDRESS, ICMP_ADDRESSREPLY); + CASE_CODE(ICMP_ECHO, ICMP_ECHOREPLY); + CASE_CODE(ICMP_TIMESTAMP, ICMP_TIMESTAMPREPLY); + CASE_CODE(ICMP_INFO_REQUEST, ICMP_INFO_REPLY); + CASE_CODE(ICMP_ROUTERSOLICIT, ICMP_ROUTERADVERT); + CASE_CODE(ICMP_ADDRESS, ICMP_ADDRESSREPLY); default: return -1; } @@ -380,6 +381,7 @@ int ICMPv4GetCounterpart(uint8_t type) */ static int DecodeICMPV4test01(void) { + // clang-format off uint8_t raw_icmpv4[] = { 0x08, 0x00, 0x78, 0x47, 0xfc, 0x55, 0x00, 0x04, 0x52, 0xab, 0x86, 0x4a, 0x84, 0x50, 0x0e, 0x00, @@ -388,6 +390,7 @@ static int DecodeICMPV4test01(void) 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -414,8 +417,8 @@ static int DecodeICMPV4test01(void) DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); - if (NULL!=p->icmpv4h) { - if (p->icmpv4h->type==8 && p->icmpv4h->code==0) { + if (NULL != p->icmpv4h) { + if (p->icmpv4h->type == 8 && p->icmpv4h->code == 0) { ret = 1; } } @@ -431,6 +434,7 @@ static int DecodeICMPV4test01(void) */ static int DecodeICMPV4test02(void) { + // clang-format off uint8_t raw_icmpv4[] = { 0x00, 0x00, 0x57, 0x64, 0xfb, 0x55, 0x00, 0x03, 0x43, 0xab, 0x86, 0x4a, 0xf6, 0x49, 0x02, 0x00, @@ -439,6 +443,7 @@ static int DecodeICMPV4test02(void) 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -464,8 +469,8 @@ static int DecodeICMPV4test02(void) DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); - if (NULL!=p->icmpv4h) { - if (p->icmpv4h->type==0 && p->icmpv4h->code==0) { + if (NULL != p->icmpv4h) { + if (p->icmpv4h->type == 0 && p->icmpv4h->code == 0) { ret = 1; } } @@ -481,12 +486,14 @@ static int DecodeICMPV4test02(void) */ static int DecodeICMPV4test03(void) { + // clang-format off uint8_t raw_icmpv4[] = { 0x0b, 0x00, 0x6a, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x64, 0x15, 0x00, 0x00, 0x01, 0x11, 0xde, 0xfd, 0xc0, 0xa8, 0x01, 0x0d, 0xd1, 0x55, 0xe3, 0x93, 0x8b, 0x12, 0x82, 0xaa, 0x00, 0x28, 0x7c, 0xdd }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -513,22 +520,20 @@ static int DecodeICMPV4test03(void) DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); if (NULL == p->icmpv4h) { - printf("NULL == p->icmpv4h: "); + printf("NULL == p->icmpv4h: "); goto end; } /* check it's type 11 code 0 */ if (p->icmpv4h->type != 11 || p->icmpv4h->code != 0) { - printf("p->icmpv4h->type %u, p->icmpv4h->code %u: ", - p->icmpv4h->type, p->icmpv4h->code); + printf("p->icmpv4h->type %u, p->icmpv4h->code %u: ", p->icmpv4h->type, p->icmpv4h->code); goto end; } /* check it's source port 35602 to port 33450 */ - if (p->icmpv4vars.emb_sport != 35602 || - p->icmpv4vars.emb_dport != 33450) { - printf("p->icmpv4vars.emb_sport %u, p->icmpv4vars.emb_dport %u: ", - p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); + if (p->icmpv4vars.emb_sport != 35602 || p->icmpv4vars.emb_dport != 33450) { + printf("p->icmpv4vars.emb_sport %u, p->icmpv4vars.emb_dport %u: ", p->icmpv4vars.emb_sport, + p->icmpv4vars.emb_dport); goto end; } @@ -541,9 +546,8 @@ static int DecodeICMPV4test03(void) /* ICMPv4 embedding IPV4 192.168.1.13->209.85.227.147 pass */ if (strcmp(s, "192.168.1.13") == 0 && strcmp(d, "209.85.227.147") == 0) { ret = 1; - } - else { - printf("s %s, d %s: ", s, d); + } else { + printf("s %s, d %s: ", s, d); } end: @@ -558,6 +562,7 @@ static int DecodeICMPV4test03(void) */ static int DecodeICMPV4test04(void) { + // clang-format off uint8_t raw_icmpv4[] = { 0x03, 0x0a, 0x36, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x62, 0xee, 0x40, 0x00, @@ -566,6 +571,7 @@ static int DecodeICMPV4test04(void) 0x3e, 0x36, 0x38, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x72, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0x8a, 0x04, 0x02, 0x08, 0x0a }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -601,8 +607,7 @@ static int DecodeICMPV4test04(void) } /* check it's src port 45322 to dst port 50 */ - if (p->icmpv4vars.emb_sport != 45322 || - p->icmpv4vars.emb_dport != 50) { + if (p->icmpv4vars.emb_sport != 45322 || p->icmpv4vars.emb_dport != 50) { goto end; } @@ -629,12 +634,14 @@ static int DecodeICMPV4test04(void) */ static int DecodeICMPV4test05(void) { + // clang-format off uint8_t raw_icmpv4[] = { 0x0b, 0x00, 0x5c, 0x46, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x30, 0x02, 0x17, 0x40, 0x00, 0x01, 0x06, 0xd6, 0xbd, 0xc0, 0xa8, 0x02, 0x05, 0x3d, 0x23, 0xa1, 0x23, 0x04, 0x18, 0x00, 0x50, 0xd2, 0x08, 0xc2, 0x48, }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -670,8 +677,7 @@ static int DecodeICMPV4test05(void) } /* check it's src port 1048 to dst port 80 */ - if (p->icmpv4vars.emb_sport != 1048 || - p->icmpv4vars.emb_dport != 80) { + if (p->icmpv4vars.emb_sport != 1048 || p->icmpv4vars.emb_dport != 80) { goto end; } @@ -696,6 +702,7 @@ static int ICMPV4CalculateValidChecksumtest05(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_icmpv4[] = { 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, @@ -705,8 +712,9 @@ static int ICMPV4CalculateValidChecksumtest05(void) 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; + // clang-format on - csum = *( ((uint16_t *)raw_icmpv4) + 1); + csum = *(((uint16_t *)raw_icmpv4) + 1); return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); } @@ -714,6 +722,7 @@ static int ICMPV4CalculateInvalidChecksumtest06(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_icmpv4[] = { 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, @@ -723,14 +732,16 @@ static int ICMPV4CalculateInvalidChecksumtest06(void) 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; + // clang-format on - csum = *( ((uint16_t *)raw_icmpv4) + 1); + csum = *(((uint16_t *)raw_icmpv4) + 1); return (csum != ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); } static int ICMPV4InvalidType07(void) { + // clang-format off uint8_t raw_icmpv4[] = { 0xff, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, @@ -740,10 +751,11 @@ static int ICMPV4InvalidType07(void) 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) - return 0; + return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; @@ -766,7 +778,7 @@ static int ICMPV4InvalidType07(void) DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); - if(ENGINE_ISSET_EVENT(p,ICMPV4_UNKNOWN_TYPE)) { + if (ENGINE_ISSET_EVENT(p, ICMPV4_UNKNOWN_TYPE)) { ret = 1; } @@ -781,9 +793,11 @@ static int ICMPV4InvalidType07(void) */ static int DecodeICMPV4test08(void) { + // clang-format off uint8_t raw_icmpv4[] = { 0x08, 0x00, 0x78, 0x47, 0xfc, 0x55, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -809,8 +823,8 @@ static int DecodeICMPV4test08(void) DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); - if (NULL!=p->icmpv4h) { - if (p->icmpv4h->type==8 && p->icmpv4h->code==0) { + if (NULL != p->icmpv4h) { + if (p->icmpv4h->type == 8 && p->icmpv4h->code == 0) { ret = 1; } } @@ -832,10 +846,8 @@ void DecodeICMPV4RegisterTests(void) UtRegisterTest("DecodeICMPV4test03", DecodeICMPV4test03); UtRegisterTest("DecodeICMPV4test04", DecodeICMPV4test04); UtRegisterTest("DecodeICMPV4test05", DecodeICMPV4test05); - UtRegisterTest("ICMPV4CalculateValidChecksumtest05", - ICMPV4CalculateValidChecksumtest05); - UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", - ICMPV4CalculateInvalidChecksumtest06); + UtRegisterTest("ICMPV4CalculateValidChecksumtest05", ICMPV4CalculateValidChecksumtest05); + UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", ICMPV4CalculateInvalidChecksumtest06); UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07); UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08); #endif /* UNITTESTS */ diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index f3a94ad2e594..90977a9b2452 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -27,162 +27,158 @@ #include "decode-tcp.h" #include "decode-udp.h" -#define ICMPV4_HEADER_LEN 8 +#define ICMPV4_HEADER_LEN 8 #ifndef ICMP_ECHOREPLY -#define ICMP_ECHOREPLY 0 /* Echo Reply */ +#define ICMP_ECHOREPLY 0 /* Echo Reply */ #endif #ifndef ICMP_DEST_UNREACH -#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ +#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ #endif #ifndef ICMP_SOURCE_QUENCH -#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ +#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ #endif #ifndef ICMP_REDIRECT -#define ICMP_REDIRECT 5 /* Redirect (change route) */ +#define ICMP_REDIRECT 5 /* Redirect (change route) */ #endif #ifndef ICMP_ECHO -#define ICMP_ECHO 8 /* Echo Request */ +#define ICMP_ECHO 8 /* Echo Request */ #endif #ifndef ICMP_ROUTERADVERT -#define ICMP_ROUTERADVERT 9 +#define ICMP_ROUTERADVERT 9 #endif #ifndef ICMP_ROUTERSOLICIT -#define ICMP_ROUTERSOLICIT 10 +#define ICMP_ROUTERSOLICIT 10 #endif #ifndef ICMP_TIME_EXCEEDED -#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ #endif #ifndef ICMP_PARAMETERPROB -#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ +#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ #endif #ifndef ICMP_TIMESTAMP -#define ICMP_TIMESTAMP 13 /* Timestamp Request */ +#define ICMP_TIMESTAMP 13 /* Timestamp Request */ #endif #ifndef ICMP_TIMESTAMPREPLY -#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ +#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ #endif #ifndef ICMP_INFO_REQUEST -#define ICMP_INFO_REQUEST 15 /* Information Request */ +#define ICMP_INFO_REQUEST 15 /* Information Request */ #endif #ifndef ICMP_INFO_REPLY -#define ICMP_INFO_REPLY 16 /* Information Reply */ +#define ICMP_INFO_REPLY 16 /* Information Reply */ #endif #ifndef ICMP_ADDRESS -#define ICMP_ADDRESS 17 /* Address Mask Request */ +#define ICMP_ADDRESS 17 /* Address Mask Request */ #endif #ifndef ICMP_ADDRESSREPLY -#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ +#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ #endif #ifndef NR_ICMP_TYPES -#define NR_ICMP_TYPES 18 +#define NR_ICMP_TYPES 18 #endif - /* Codes for UNREACH. */ #ifndef ICMP_NET_UNREACH -#define ICMP_NET_UNREACH 0 /* Network Unreachable */ +#define ICMP_NET_UNREACH 0 /* Network Unreachable */ #endif #ifndef ICMP_HOST_UNREACH -#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ +#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ #endif #ifndef ICMP_PROT_UNREACH -#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ +#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ #endif #ifndef ICMP_PORT_UNREACH -#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ +#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ #endif #ifndef ICMP_FRAG_NEEDED -#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ +#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ #endif #ifndef ICMP_SR_FAILED -#define ICMP_SR_FAILED 5 /* Source Route failed */ +#define ICMP_SR_FAILED 5 /* Source Route failed */ #endif #ifndef ICMP_NET_UNKNOWN -#define ICMP_NET_UNKNOWN 6 +#define ICMP_NET_UNKNOWN 6 #endif #ifndef ICMP_HOST_UNKNOWN -#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_UNKNOWN 7 #endif #ifndef ICMP_HOST_ISOLATED -#define ICMP_HOST_ISOLATED 8 +#define ICMP_HOST_ISOLATED 8 #endif #ifndef ICMP_NET_ANO -#define ICMP_NET_ANO 9 +#define ICMP_NET_ANO 9 #endif #ifndef ICMP_HOST_ANO -#define ICMP_HOST_ANO 10 +#define ICMP_HOST_ANO 10 #endif #ifndef ICMP_NET_UNR_TOS -#define ICMP_NET_UNR_TOS 11 +#define ICMP_NET_UNR_TOS 11 #endif #ifndef ICMP_HOST_UNR_TOS -#define ICMP_HOST_UNR_TOS 12 +#define ICMP_HOST_UNR_TOS 12 #endif #ifndef ICMP_PKT_FILTERED -#define ICMP_PKT_FILTERED 13 /* Packet filtered */ +#define ICMP_PKT_FILTERED 13 /* Packet filtered */ #endif #ifndef ICMP_PREC_VIOLATION -#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ +#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ #endif #ifndef ICMP_PREC_CUTOFF -#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ +#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ #endif #ifndef NR_ICMP_UNREACH -#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ +#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ #endif /* Codes for REDIRECT. */ #ifndef ICMP_REDIR_NET -#define ICMP_REDIR_NET 0 /* Redirect Net */ +#define ICMP_REDIR_NET 0 /* Redirect Net */ #endif #ifndef ICMP_REDIR_HOST -#define ICMP_REDIR_HOST 1 /* Redirect Host */ +#define ICMP_REDIR_HOST 1 /* Redirect Host */ #endif #ifndef ICMP_REDIR_NETTOS -#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ +#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ #endif #ifndef ICMP_REDIR_HOSTTOS -#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ +#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ #endif /* Codes for TIME_EXCEEDED. */ #ifndef ICMP_EXC_TTL -#define ICMP_EXC_TTL 0 /* TTL count exceeded */ +#define ICMP_EXC_TTL 0 /* TTL count exceeded */ #endif #ifndef ICMP_EXC_FRAGTIME -#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ +#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ #endif /** marco for icmpv4 type access */ -#define ICMPV4_GET_TYPE(p) (p)->icmpv4h->type +#define ICMPV4_GET_TYPE(p) (p)->icmpv4h->type /** marco for icmpv4 code access */ -#define ICMPV4_GET_CODE(p) (p)->icmpv4h->code +#define ICMPV4_GET_CODE(p) (p)->icmpv4h->code /* ICMPv4 header structure */ -typedef struct ICMPV4Hdr_ -{ - uint8_t type; - uint8_t code; +typedef struct ICMPV4Hdr_ { + uint8_t type; + uint8_t code; uint16_t checksum; } __attribute__((__packed__)) ICMPV4Hdr; /* ICMPv4 header structure */ -typedef struct ICMPV4ExtHdr_ -{ - uint8_t type; - uint8_t code; +typedef struct ICMPV4ExtHdr_ { + uint8_t type; + uint8_t code; uint16_t checksum; uint16_t id; uint16_t seq; } ICMPV4ExtHdr; /* ICMPv4 vars */ -typedef struct ICMPV4Vars_ -{ - uint16_t id; - uint16_t seq; +typedef struct ICMPV4Vars_ { + uint16_t id; + uint16_t seq; /** Actual header length **/ uint16_t hlen; @@ -221,56 +217,54 @@ typedef struct ICMPV4Timestamp_ { uint32_t tx_ts; } __attribute__((__packed__)) ICMPV4Timestamp; -#define CLEAR_ICMPV4_PACKET(p) do { \ - (p)->level4_comp_csum = -1; \ - PACKET_CLEAR_L4VARS((p)); \ - (p)->icmpv4h = NULL; \ -} while(0) +#define CLEAR_ICMPV4_PACKET(p) \ + do { \ + (p)->level4_comp_csum = -1; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->icmpv4h = NULL; \ + } while (0) #define ICMPV4_HEADER_PKT_OFFSET 8 /** macro for icmpv4 "type" access */ -#define ICMPV4_GET_TYPE(p) (p)->icmpv4h->type +#define ICMPV4_GET_TYPE(p) (p)->icmpv4h->type /** macro for icmpv4 "code" access */ -#define ICMPV4_GET_CODE(p) (p)->icmpv4h->code +#define ICMPV4_GET_CODE(p) (p)->icmpv4h->code /** macro for icmpv4 "csum" access */ -#define ICMPV4_GET_RAW_CSUM(p) SCNtohs((p)->icmpv4h->checksum) -#define ICMPV4_GET_CSUM(p) (p)->icmpv4h->checksum +#define ICMPV4_GET_RAW_CSUM(p) SCNtohs((p)->icmpv4h->checksum) +#define ICMPV4_GET_CSUM(p) (p)->icmpv4h->checksum /* If message is informational */ /** macro for icmpv4 "id" access */ -#define ICMPV4_GET_ID(p) ((p)->icmpv4vars.id) +#define ICMPV4_GET_ID(p) ((p)->icmpv4vars.id) /** macro for icmpv4 "seq" access */ -#define ICMPV4_GET_SEQ(p) ((p)->icmpv4vars.seq) +#define ICMPV4_GET_SEQ(p) ((p)->icmpv4vars.seq) /* If message is Error */ /** macro for icmpv4 embedded "protocol" access */ -#define ICMPV4_GET_EMB_PROTO(p) (p)->icmpv4vars.emb_ip4_proto +#define ICMPV4_GET_EMB_PROTO(p) (p)->icmpv4vars.emb_ip4_proto /** macro for icmpv4 embedded "ipv4h" header access */ -#define ICMPV4_GET_EMB_IPV4(p) (p)->icmpv4vars.emb_ipv4h +#define ICMPV4_GET_EMB_IPV4(p) (p)->icmpv4vars.emb_ipv4h /** macro for icmpv4 embedded "tcph" header access */ -#define ICMPV4_GET_EMB_TCP(p) (p)->icmpv4vars.emb_tcph +#define ICMPV4_GET_EMB_TCP(p) (p)->icmpv4vars.emb_tcph /** macro for icmpv4 embedded "udph" header access */ -#define ICMPV4_GET_EMB_UDP(p) (p)->icmpv4vars.emb_udph +#define ICMPV4_GET_EMB_UDP(p) (p)->icmpv4vars.emb_udph /** macro for icmpv4 embedded "icmpv4h" header access */ -#define ICMPV4_GET_EMB_ICMPV4H(p) (p)->icmpv4vars.emb_icmpv4h +#define ICMPV4_GET_EMB_ICMPV4H(p) (p)->icmpv4vars.emb_icmpv4h /** macro for icmpv4 header length */ #define ICMPV4_GET_HLEN_ICMPV4H(p) (p)->icmpv4vars.hlen /** macro for checking if a ICMP DEST UNREACH packet is valid for use - * in other parts of the engine, such as the flow engine. + * in other parts of the engine, such as the flow engine. * * \warning use only _after_ the decoder has processed the packet */ -#define ICMPV4_DEST_UNREACH_IS_VALID(p) ( \ - (!((p)->flags & PKT_IS_INVALID)) && \ - ((p)->icmpv4h != NULL) && \ - (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH) && \ - (ICMPV4_GET_EMB_IPV4((p)) != NULL) && \ - ((ICMPV4_GET_EMB_TCP((p)) != NULL) || \ - (ICMPV4_GET_EMB_UDP((p)) != NULL))) +#define ICMPV4_DEST_UNREACH_IS_VALID(p) \ + ((!((p)->flags & PKT_IS_INVALID)) && ((p)->icmpv4h != NULL) && \ + (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH) && (ICMPV4_GET_EMB_IPV4((p)) != NULL) && \ + ((ICMPV4_GET_EMB_TCP((p)) != NULL) || (ICMPV4_GET_EMB_UDP((p)) != NULL))) /** * marco for checking if a ICMP packet is an error message or an @@ -281,11 +275,10 @@ typedef struct ICMPV4Timestamp_ { * stage so we can to a bit check instead of the more expensive * check below. */ -#define ICMPV4_IS_ERROR_MSG(p) (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH || \ - ICMPV4_GET_TYPE((p)) == ICMP_SOURCE_QUENCH || \ - ICMPV4_GET_TYPE((p)) == ICMP_REDIRECT || \ - ICMPV4_GET_TYPE((p)) == ICMP_TIME_EXCEEDED || \ - ICMPV4_GET_TYPE((p)) == ICMP_PARAMETERPROB) +#define ICMPV4_IS_ERROR_MSG(p) \ + (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH || ICMPV4_GET_TYPE((p)) == ICMP_SOURCE_QUENCH || \ + ICMPV4_GET_TYPE((p)) == ICMP_REDIRECT || ICMPV4_GET_TYPE((p)) == ICMP_TIME_EXCEEDED || \ + ICMPV4_GET_TYPE((p)) == ICMP_PARAMETERPROB) void DecodeICMPV4RegisterTests(void); @@ -308,20 +301,19 @@ static inline uint16_t ICMPV4CalculateChecksum(const uint16_t *pkt, uint16_t tle pkt += 2; while (tlen >= 32) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } - while(tlen >= 8) { + while (tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } - while(tlen >= 4) { + while (tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; @@ -341,7 +333,7 @@ static inline uint16_t ICMPV4CalculateChecksum(const uint16_t *pkt, uint16_t tle csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); - return (uint16_t) ~csum; + return (uint16_t)~csum; } int ICMPv4GetCounterpart(uint8_t type); diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index e52279ff573a..174b62a69994 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -34,8 +33,8 @@ #include "decode-icmpv6.h" #include "decode.h" #include "flow.h" -#include "util-print.h" -#include "util-validate.h" +#include "util/print.h" +#include "util/validate.h" /** * \brief Get variables and do some checks of the embedded IPV6 packet @@ -46,7 +45,7 @@ * * \retval void No return value */ -static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) +static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len) { /** Check the sizes, the header must fit at least */ if (len < IPV6_HEADER_LEN) { @@ -55,13 +54,12 @@ static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) return; } - IPV6Hdr *icmp6_ip6h = (IPV6Hdr*)partial_packet; + IPV6Hdr *icmp6_ip6h = (IPV6Hdr *)partial_packet; /** Check the embedded version */ - if(((icmp6_ip6h->s_ip6_vfc & 0xf0) >> 4) != 6) - { + if (((icmp6_ip6h->s_ip6_vfc & 0xf0) >> 4) != 6) { SCLogDebug("ICMPv6 contains Unknown IPV6 version " - "ICMPV6_IPV6_UNKNOWN_VER"); + "ICMPV6_IPV6_UNKNOWN_VER"); ENGINE_SET_INVALID_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER); return; } @@ -85,14 +83,14 @@ static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) switch (icmp6_ip6h->s_ip6_nxt) { case IPPROTO_TCP: - if (len >= IPV6_HEADER_LEN + TCP_HEADER_LEN ) { - p->icmpv6vars.emb_tcph = (TCPHdr*)(partial_packet + IPV6_HEADER_LEN); + if (len >= IPV6_HEADER_LEN + TCP_HEADER_LEN) { + p->icmpv6vars.emb_tcph = (TCPHdr *)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_tcph->th_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_tcph->th_dport; SCLogDebug("ICMPV6->IPV6->TCP header sport: " - "%"PRIu16" dport %"PRIu16"", p->icmpv6vars.emb_sport, - p->icmpv6vars.emb_dport); + "%" PRIu16 " dport %" PRIu16 "", + p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->TCP " "header Didn't fit in the packet!"); @@ -102,14 +100,14 @@ static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) break; case IPPROTO_UDP: - if (len >= IPV6_HEADER_LEN + UDP_HEADER_LEN ) { - p->icmpv6vars.emb_udph = (UDPHdr*)(partial_packet + IPV6_HEADER_LEN); + if (len >= IPV6_HEADER_LEN + UDP_HEADER_LEN) { + p->icmpv6vars.emb_udph = (UDPHdr *)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_udph->uh_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_udph->uh_dport; SCLogDebug("ICMPV6->IPV6->UDP header sport: " - "%"PRIu16" dport %"PRIu16"", p->icmpv6vars.emb_sport, - p->icmpv6vars.emb_dport); + "%" PRIu16 " dport %" PRIu16 "", + p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->UDP " "header Didn't fit in the packet!"); @@ -119,7 +117,7 @@ static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) break; case IPPROTO_ICMPV6: - p->icmpv6vars.emb_icmpv6h = (ICMPV6Hdr*)(partial_packet + IPV6_HEADER_LEN); + p->icmpv6vars.emb_icmpv6h = (ICMPV6Hdr *)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; @@ -128,15 +126,16 @@ static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) break; } - /* debug print */ + /* debug print */ #ifdef DEBUG char s[46], d[46]; PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_src, s, sizeof(s)); PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_dst, d, sizeof(d)); SCLogDebug("ICMPv6 embedding IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: " "%" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32, - s, d, IPV6_GET_RAW_CLASS(icmp6_ip6h), IPV6_GET_RAW_FLOW(icmp6_ip6h), - IPV6_GET_RAW_NH(icmp6_ip6h), IPV6_GET_RAW_PLEN(icmp6_ip6h), IPV6_GET_RAW_HLIM(icmp6_ip6h)); + s, d, IPV6_GET_RAW_CLASS(icmp6_ip6h), IPV6_GET_RAW_FLOW(icmp6_ip6h), + IPV6_GET_RAW_NH(icmp6_ip6h), IPV6_GET_RAW_PLEN(icmp6_ip6h), + IPV6_GET_RAW_HLIM(icmp6_ip6h)); #endif return; @@ -145,19 +144,23 @@ static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) /** \retval type counterpart type or -1 */ int ICMPv6GetCounterpart(uint8_t type) { -#define CASE_CODE(t,r) case (t): return r; case (r): return t; +#define CASE_CODE(t, r) \ + case (t): \ + return r; \ + case (r): \ + return t; switch (type) { - CASE_CODE(ICMP6_ECHO_REQUEST, ICMP6_ECHO_REPLY); - CASE_CODE(ND_NEIGHBOR_SOLICIT, ND_NEIGHBOR_ADVERT); - CASE_CODE(ND_ROUTER_SOLICIT, ND_ROUTER_ADVERT); - CASE_CODE(MLD_LISTENER_QUERY, MLD_LISTENER_REPORT); - CASE_CODE(ICMP6_NI_QUERY, ICMP6_NI_REPLY); - CASE_CODE(HOME_AGENT_AD_REQUEST,HOME_AGENT_AD_REPLY); - - CASE_CODE(MOBILE_PREFIX_SOLICIT,MOBILE_PREFIX_ADVERT); - CASE_CODE(CERT_PATH_SOLICIT, CERT_PATH_ADVERT); - CASE_CODE(MC_ROUTER_ADVERT, MC_ROUTER_SOLICIT); - CASE_CODE(DUPL_ADDR_REQUEST, DUPL_ADDR_CONFIRM); + CASE_CODE(ICMP6_ECHO_REQUEST, ICMP6_ECHO_REPLY); + CASE_CODE(ND_NEIGHBOR_SOLICIT, ND_NEIGHBOR_ADVERT); + CASE_CODE(ND_ROUTER_SOLICIT, ND_ROUTER_ADVERT); + CASE_CODE(MLD_LISTENER_QUERY, MLD_LISTENER_REPORT); + CASE_CODE(ICMP6_NI_QUERY, ICMP6_NI_REPLY); + CASE_CODE(HOME_AGENT_AD_REQUEST, HOME_AGENT_AD_REPLY); + + CASE_CODE(MOBILE_PREFIX_SOLICIT, MOBILE_PREFIX_ADVERT); + CASE_CODE(CERT_PATH_SOLICIT, CERT_PATH_ADVERT); + CASE_CODE(MC_ROUTER_ADVERT, MC_ROUTER_SOLICIT); + CASE_CODE(DUPL_ADDR_REQUEST, DUPL_ADDR_CONFIRM); default: return -1; } @@ -175,8 +178,7 @@ int ICMPv6GetCounterpart(uint8_t type) * * \retval void No return value */ -int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { int full_hdr = 0; StatsIncr(tv, dtv->counter_icmpv6); @@ -200,8 +202,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, p->icmp_d.type = (uint8_t)ctype; } - SCLogDebug("ICMPV6 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv6h->type, - p->icmpv6h->code); + SCLogDebug("ICMPV6 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv6h->type, p->icmpv6h->code); switch (ICMPV6_GET_TYPE(p)) { case ICMP6_DST_UNREACH: @@ -259,7 +260,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, if (unlikely(len > ICMPV6_HEADER_LEN + USHRT_MAX)) { return TM_ECODE_FAILED; } - p->icmpv6vars.error_ptr= ICMPV6_GET_ERROR_PTR(p); + p->icmpv6vars.error_ptr = ICMPV6_GET_ERROR_PTR(p); DecodePartialIPV6(p, (uint8_t *)(pkt + ICMPV6_HEADER_LEN), (uint16_t)(len - ICMPV6_HEADER_LEN)); full_hdr = 1; @@ -267,8 +268,8 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; case ICMP6_ECHO_REQUEST: - SCLogDebug("ICMP6_ECHO_REQUEST id: %u seq: %u", - p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); + SCLogDebug("ICMP6_ECHO_REQUEST id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, + p->icmpv6h->icmpv6b.icmpv6i.seq); if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); @@ -280,8 +281,8 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; case ICMP6_ECHO_REPLY: - SCLogDebug("ICMP6_ECHO_REPLY id: %u seq: %u", - p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); + SCLogDebug("ICMP6_ECHO_REPLY id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, + p->icmpv6h->icmpv6b.icmpv6i.seq); if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); @@ -476,21 +477,22 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /* Various range taken from: * http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2 */ - if ((ICMPV6_GET_TYPE(p) > 4) && (ICMPV6_GET_TYPE(p) < 100)) { + if ((ICMPV6_GET_TYPE(p) > 4) && (ICMPV6_GET_TYPE(p) < 100)) { ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); - } else if ((ICMPV6_GET_TYPE(p) >= 100) && (ICMPV6_GET_TYPE(p) < 102)) { + } else if ((ICMPV6_GET_TYPE(p) >= 100) && (ICMPV6_GET_TYPE(p) < 102)) { ENGINE_SET_EVENT(p, ICMPV6_EXPERIMENTATION_TYPE); - } else if ((ICMPV6_GET_TYPE(p) >= 102) && (ICMPV6_GET_TYPE(p) < 127)) { + } else if ((ICMPV6_GET_TYPE(p) >= 102) && (ICMPV6_GET_TYPE(p) < 127)) { ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); - } else if ((ICMPV6_GET_TYPE(p) >= 160) && (ICMPV6_GET_TYPE(p) < 200)) { + } else if ((ICMPV6_GET_TYPE(p) >= 160) && (ICMPV6_GET_TYPE(p) < 200)) { ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); - } else if ((ICMPV6_GET_TYPE(p) >= 200) && (ICMPV6_GET_TYPE(p) < 202)) { + } else if ((ICMPV6_GET_TYPE(p) >= 200) && (ICMPV6_GET_TYPE(p) < 202)) { ENGINE_SET_EVENT(p, ICMPV6_EXPERIMENTATION_TYPE); } else if (ICMPV6_GET_TYPE(p) >= 202) { ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); } else { SCLogDebug("ICMPV6 Message type %" PRIu8 " not " - "implemented yet", ICMPV6_GET_TYPE(p)); + "implemented yet", + ICMPV6_GET_TYPE(p)); ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_TYPE); } } @@ -521,12 +523,13 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, #ifdef UNITTESTS #include "packet.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" static int ICMPV6CalculateValidChecksumtest01(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, @@ -544,11 +547,12 @@ static int ICMPV6CalculateValidChecksumtest01(void) 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x00}; + // clang-format on - csum = *( ((uint16_t *)(raw_ipv6 + 56))); + csum = *(((uint16_t *)(raw_ipv6 + 56))); - FAIL_IF(csum != ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 68)); + FAIL_IF(csum != ICMPV6CalculateChecksum( + (uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); PASS; } @@ -556,6 +560,7 @@ static int ICMPV6CalculateInvalidChecksumtest02(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipv6[] = { 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, @@ -573,11 +578,12 @@ static int ICMPV6CalculateInvalidChecksumtest02(void) 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, 0x08, 0x01}; + // clang-format on - csum = *( ((uint16_t *)(raw_ipv6 + 56))); + csum = *(((uint16_t *)(raw_ipv6 + 56))); - FAIL_IF(csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 68)); + FAIL_IF(csum == ICMPV6CalculateChecksum( + (uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); PASS; } @@ -587,6 +593,7 @@ static int ICMPV6CalculateInvalidChecksumtest02(void) */ static int ICMPV6ParamProbTest01(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -600,6 +607,7 @@ static int ICMPV6ParamProbTest01(void) 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -608,8 +616,8 @@ static int ICMPV6ParamProbTest01(void) DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; - ipv6src = (uint32_t*) &raw_ipv6[8]; - ipv6dst = (uint32_t*) &raw_ipv6[24]; + ipv6src = (uint32_t *)&raw_ipv6[8]; + ipv6dst = (uint32_t *)&raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -622,13 +630,13 @@ static int ICMPV6ParamProbTest01(void) /* ICMPv6 not processed at all? */ FAIL_IF(ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_PROTO(p) != IPPROTO_ICMPV6); + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_ICMPV6); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ - uint32_t i=0; + uint32_t i = 0; for (i = 0; i < 4; i++) { FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } PacketRecycle(p); @@ -643,6 +651,7 @@ static int ICMPV6ParamProbTest01(void) */ static int ICMPV6PktTooBigTest01(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -655,6 +664,7 @@ static int ICMPV6PktTooBigTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -663,8 +673,8 @@ static int ICMPV6PktTooBigTest01(void) DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; - ipv6src = (uint32_t*) &raw_ipv6[8]; - ipv6dst = (uint32_t*) &raw_ipv6[24]; + ipv6src = (uint32_t *)&raw_ipv6[8]; + ipv6dst = (uint32_t *)&raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -678,13 +688,13 @@ static int ICMPV6PktTooBigTest01(void) /* Note: it has an embedded ipv6 packet but no protocol after ipv6 * (IPPROTO_NONE) */ /* Check if ICMPv6 header was processed at all. */ - FAIL_IF(ICMPV6_GET_TYPE(p) != 2 || ICMPV6_GET_CODE(p) != 0 ); + FAIL_IF(ICMPV6_GET_TYPE(p) != 2 || ICMPV6_GET_CODE(p) != 0); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ - uint32_t i=0; + uint32_t i = 0; for (i = 0; i < 4; i++) { FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); @@ -701,6 +711,7 @@ static int ICMPV6PktTooBigTest01(void) */ static int ICMPV6TimeExceedTest01(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -713,6 +724,7 @@ static int ICMPV6TimeExceedTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -721,8 +733,8 @@ static int ICMPV6TimeExceedTest01(void) DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; - ipv6src = (uint32_t*) &raw_ipv6[8]; - ipv6dst = (uint32_t*) &raw_ipv6[24]; + ipv6src = (uint32_t *)&raw_ipv6[8]; + ipv6dst = (uint32_t *)&raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -734,15 +746,14 @@ static int ICMPV6TimeExceedTest01(void) FAIL_IF_NULL(p->icmpv6h); /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - FAIL_IF(ICMPV6_GET_TYPE(p) != 3 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_IPV6(p) == NULL || - ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); + FAIL_IF(ICMPV6_GET_TYPE(p) != 3 || ICMPV6_GET_CODE(p) != 0 || ICMPV6_GET_EMB_IPV6(p) == NULL || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ - uint32_t i=0; + uint32_t i = 0; for (i = 0; i < 4; i++) { FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); @@ -759,6 +770,7 @@ static int ICMPV6TimeExceedTest01(void) */ static int ICMPV6DestUnreachTest01(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -771,6 +783,7 @@ static int ICMPV6DestUnreachTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -779,8 +792,8 @@ static int ICMPV6DestUnreachTest01(void) DecodeThreadVars dtv; uint32_t *ipv6src; uint32_t *ipv6dst; - ipv6src = (uint32_t*) &raw_ipv6[8]; - ipv6dst = (uint32_t*) &raw_ipv6[24]; + ipv6src = (uint32_t *)&raw_ipv6[8]; + ipv6dst = (uint32_t *)&raw_ipv6[24]; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -792,15 +805,14 @@ static int ICMPV6DestUnreachTest01(void) FAIL_IF_NULL(p->icmpv6h); /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - FAIL_IF(ICMPV6_GET_TYPE(p) != 1 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_IPV6(p) == NULL || - ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); + FAIL_IF(ICMPV6_GET_TYPE(p) != 1 || ICMPV6_GET_CODE(p) != 0 || ICMPV6_GET_EMB_IPV6(p) == NULL || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ - uint32_t i=0; + uint32_t i = 0; for (i = 0; i < 4; i++) { FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } PacketRecycle(p); @@ -814,6 +826,7 @@ static int ICMPV6DestUnreachTest01(void) */ static int ICMPV6EchoReqTest01(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -821,6 +834,7 @@ static int ICMPV6EchoReqTest01(void) 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -839,8 +853,8 @@ static int ICMPV6EchoReqTest01(void) SCLogDebug("ID: %u seq: %u", ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); - if (ICMPV6_GET_TYPE(p) != 128 || ICMPV6_GET_CODE(p) != 0 || - SCNtohs(ICMPV6_GET_ID(p)) != 9712 || SCNtohs(ICMPV6_GET_SEQ(p)) != 29987) { + if (ICMPV6_GET_TYPE(p) != 128 || ICMPV6_GET_CODE(p) != 0 || SCNtohs(ICMPV6_GET_ID(p)) != 9712 || + SCNtohs(ICMPV6_GET_SEQ(p)) != 29987) { printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), SCNtohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), SCNtohs(ICMPV6_GET_SEQ(p))); @@ -858,6 +872,7 @@ static int ICMPV6EchoReqTest01(void) */ static int ICMPV6EchoRepTest01(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -866,6 +881,7 @@ static int ICMPV6EchoRepTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x81, 0x00, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -882,11 +898,11 @@ static int ICMPV6EchoRepTest01(void) FAIL_IF_NULL(p->icmpv6h); - SCLogDebug("type: %u code %u ID: %u seq: %u", ICMPV6_GET_TYPE(p), - ICMPV6_GET_CODE(p),ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); + SCLogDebug("type: %u code %u ID: %u seq: %u", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), + ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); - if (ICMPV6_GET_TYPE(p) != 129 || ICMPV6_GET_CODE(p) != 0 || - SCNtohs(ICMPV6_GET_ID(p)) != 9712 || SCNtohs(ICMPV6_GET_SEQ(p)) != 29987) { + if (ICMPV6_GET_TYPE(p) != 129 || ICMPV6_GET_CODE(p) != 0 || SCNtohs(ICMPV6_GET_ID(p)) != 9712 || + SCNtohs(ICMPV6_GET_SEQ(p)) != 29987) { printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), SCNtohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), SCNtohs(ICMPV6_GET_SEQ(p))); @@ -900,11 +916,12 @@ static int ICMPV6EchoRepTest01(void) } /** \test icmpv6 message type: parameter problem, invalid packet - * \brief set the event ICMPV6_IPV6_UNKNOWN_VER properly when the embedded packet has an unknown version - * \retval retval 0 = Error ; 1 = ok + * \brief set the event ICMPV6_IPV6_UNKNOWN_VER properly when the embedded packet has an unknown + * version \retval retval 0 = Error ; 1 = ok */ static int ICMPV6ParamProbTest02(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -918,6 +935,7 @@ static int ICMPV6ParamProbTest02(void) 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -948,6 +966,7 @@ static int ICMPV6ParamProbTest02(void) */ static int ICMPV6PktTooBigTest02(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -960,6 +979,7 @@ static int ICMPV6PktTooBigTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -989,6 +1009,7 @@ static int ICMPV6PktTooBigTest02(void) */ static int ICMPV6TimeExceedTest02(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -996,6 +1017,7 @@ static int ICMPV6TimeExceedTest02(void) 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x10, 0x5c }; + // clang-format on /* The icmpv6 header is broken in the checksum (so we dont have a complete header) */ @@ -1026,6 +1048,7 @@ static int ICMPV6TimeExceedTest02(void) */ static int ICMPV6DestUnreachTest02(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1038,6 +1061,7 @@ static int ICMPV6DestUnreachTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1066,6 +1090,7 @@ static int ICMPV6DestUnreachTest02(void) */ static int ICMPV6EchoReqTest02(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1074,6 +1099,7 @@ static int ICMPV6EchoReqTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1102,6 +1128,7 @@ static int ICMPV6EchoReqTest02(void) */ static int ICMPV6EchoRepTest02(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1110,6 +1137,7 @@ static int ICMPV6EchoRepTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x81, 0x01, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1137,6 +1165,7 @@ static int ICMPV6EchoRepTest02(void) */ static int ICMPV6PayloadTest01(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1149,6 +1178,7 @@ static int ICMPV6PayloadTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1174,6 +1204,7 @@ static int ICMPV6PayloadTest01(void) static int ICMPV6RouterSolicitTestKnownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1182,6 +1213,7 @@ static int ICMPV6RouterSolicitTestKnownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x85, 0x00, 0xbe, 0xb0, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1206,6 +1238,7 @@ static int ICMPV6RouterSolicitTestKnownCode(void) static int ICMPV6RouterSolicitTestUnknownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1214,6 +1247,7 @@ static int ICMPV6RouterSolicitTestUnknownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x85, 0x01, 0xbe, 0xaf, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1238,6 +1272,7 @@ static int ICMPV6RouterSolicitTestUnknownCode(void) static int ICMPV6RouterAdvertTestKnownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1246,6 +1281,7 @@ static int ICMPV6RouterAdvertTestKnownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x86, 0x00, 0xbd, 0xb0, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1270,6 +1306,7 @@ static int ICMPV6RouterAdvertTestKnownCode(void) static int ICMPV6RouterAdvertTestUnknownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1278,6 +1315,7 @@ static int ICMPV6RouterAdvertTestUnknownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x86, 0x01, 0xbd, 0xaf, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1302,6 +1340,7 @@ static int ICMPV6RouterAdvertTestUnknownCode(void) static int ICMPV6NeighbourSolicitTestKnownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1310,6 +1349,7 @@ static int ICMPV6NeighbourSolicitTestKnownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0xbc, 0xb0, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1334,6 +1374,7 @@ static int ICMPV6NeighbourSolicitTestKnownCode(void) static int ICMPV6NeighbourSolicitTestUnknownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1342,6 +1383,7 @@ static int ICMPV6NeighbourSolicitTestUnknownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x01, 0xbc, 0xaf, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1366,6 +1408,7 @@ static int ICMPV6NeighbourSolicitTestUnknownCode(void) static int ICMPV6NeighbourAdvertTestKnownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1374,6 +1417,7 @@ static int ICMPV6NeighbourAdvertTestKnownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x00, 0xbb, 0xb0, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1398,6 +1442,7 @@ static int ICMPV6NeighbourAdvertTestKnownCode(void) static int ICMPV6NeighbourAdvertTestUnknownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1406,6 +1451,7 @@ static int ICMPV6NeighbourAdvertTestUnknownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x01, 0xbb, 0xaf, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1430,6 +1476,7 @@ static int ICMPV6NeighbourAdvertTestUnknownCode(void) static int ICMPV6RedirectTestKnownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1438,6 +1485,7 @@ static int ICMPV6RedirectTestKnownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x89, 0x00, 0xba, 0xb0, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1462,6 +1510,7 @@ static int ICMPV6RedirectTestKnownCode(void) static int ICMPV6RedirectTestUnknownCode(void) { + // clang-format off static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1470,6 +1519,7 @@ static int ICMPV6RedirectTestUnknownCode(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x89, 0x01, 0xba, 0xaf, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1504,6 +1554,7 @@ static int ICMPV6CalculateValidChecksumWithFCS(void) /* IPV6/ICMPv6 packet with ethernet header. * - IPv6 payload length: 36 */ + // clang-format off uint8_t raw_ipv6[] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x16, 0x00, 0x50, 0x56, 0xa6, 0x6a, 0x7d, 0x86, 0xdd, 0x60, 0x00, @@ -1518,6 +1569,7 @@ static int ICMPV6CalculateValidChecksumWithFCS(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x1f, 0x34, 0xf6, 0xa4 }; + // clang-format on uint16_t csum = *(((uint16_t *)(raw_ipv6 + 64))); Packet *p = PacketGetFromAlloc(); @@ -1535,10 +1587,10 @@ static int ICMPV6CalculateValidChecksumWithFCS(void) FAIL_IF_NULL(p->icmpv6h); uint16_t icmpv6_len = IPV6_GET_RAW_PLEN(p->ip6h) - - ((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); + ((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); FAIL_IF(icmpv6_len != 28); - FAIL_IF(ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->icmpv6h, icmpv6_len) != csum); + FAIL_IF(ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->icmpv6h, icmpv6_len) != + csum); PacketRecycle(p); FlowShutdown(); @@ -1554,8 +1606,7 @@ static int ICMPV6CalculateValidChecksumWithFCS(void) void DecodeICMPV6RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ICMPV6CalculateValidChecksumtest01", - ICMPV6CalculateValidChecksumtest01); + UtRegisterTest("ICMPV6CalculateValidChecksumtest01", ICMPV6CalculateValidChecksumtest01); UtRegisterTest("ICMPV6CalculateInvalidChecksumtest02", ICMPV6CalculateInvalidChecksumtest02); UtRegisterTest("ICMPV6ParamProbTest01 (Valid)", ICMPV6ParamProbTest01); @@ -1566,8 +1617,7 @@ void DecodeICMPV6RegisterTests(void) UtRegisterTest("ICMPV6EchoRepTest01 (Valid)", ICMPV6EchoRepTest01); UtRegisterTest("ICMPV6ParamProbTest02 (Invalid)", ICMPV6ParamProbTest02); - UtRegisterTest("ICMPV6DestUnreachTest02 (Invalid)", - ICMPV6DestUnreachTest02); + UtRegisterTest("ICMPV6DestUnreachTest02 (Invalid)", ICMPV6DestUnreachTest02); UtRegisterTest("ICMPV6PktTooBigTest02 (Invalid)", ICMPV6PktTooBigTest02); UtRegisterTest("ICMPV6TimeExceedTest02 (Invalid)", ICMPV6TimeExceedTest02); UtRegisterTest("ICMPV6EchoReqTest02 (Invalid)", ICMPV6EchoReqTest02); @@ -1575,29 +1625,19 @@ void DecodeICMPV6RegisterTests(void) UtRegisterTest("ICMPV6PayloadTest01", ICMPV6PayloadTest01); - UtRegisterTest("ICMPV6RouterSolicitTestKnownCode", - ICMPV6RouterSolicitTestKnownCode); - UtRegisterTest("ICMPV6RouterSolicitTestUnknownCode", - ICMPV6RouterSolicitTestUnknownCode); - UtRegisterTest("ICMPV6RouterAdvertTestKnownCode", - ICMPV6RouterAdvertTestKnownCode); - UtRegisterTest("ICMPV6RouterAdvertTestUnknownCode", - ICMPV6RouterAdvertTestUnknownCode); - - UtRegisterTest("ICMPV6NeighbourSolicitTestKnownCode", - ICMPV6NeighbourSolicitTestKnownCode); - UtRegisterTest("ICMPV6NeighbourSolicitTestUnknownCode", - ICMPV6NeighbourSolicitTestUnknownCode); - UtRegisterTest("ICMPV6NeighbourAdvertTestKnownCode", - ICMPV6NeighbourAdvertTestKnownCode); - UtRegisterTest("ICMPV6NeighbourAdvertTestUnknownCode", - ICMPV6NeighbourAdvertTestUnknownCode); + UtRegisterTest("ICMPV6RouterSolicitTestKnownCode", ICMPV6RouterSolicitTestKnownCode); + UtRegisterTest("ICMPV6RouterSolicitTestUnknownCode", ICMPV6RouterSolicitTestUnknownCode); + UtRegisterTest("ICMPV6RouterAdvertTestKnownCode", ICMPV6RouterAdvertTestKnownCode); + UtRegisterTest("ICMPV6RouterAdvertTestUnknownCode", ICMPV6RouterAdvertTestUnknownCode); + + UtRegisterTest("ICMPV6NeighbourSolicitTestKnownCode", ICMPV6NeighbourSolicitTestKnownCode); + UtRegisterTest("ICMPV6NeighbourSolicitTestUnknownCode", ICMPV6NeighbourSolicitTestUnknownCode); + UtRegisterTest("ICMPV6NeighbourAdvertTestKnownCode", ICMPV6NeighbourAdvertTestKnownCode); + UtRegisterTest("ICMPV6NeighbourAdvertTestUnknownCode", ICMPV6NeighbourAdvertTestUnknownCode); UtRegisterTest("ICMPV6RedirectTestKnownCode", ICMPV6RedirectTestKnownCode); - UtRegisterTest("ICMPV6RedirectTestUnknownCode", - ICMPV6RedirectTestUnknownCode); - UtRegisterTest("ICMPV6CalculateValidChecksumWithFCS", - ICMPV6CalculateValidChecksumWithFCS); + UtRegisterTest("ICMPV6RedirectTestUnknownCode", ICMPV6RedirectTestUnknownCode); + UtRegisterTest("ICMPV6CalculateValidChecksumWithFCS", ICMPV6CalculateValidChecksumWithFCS); #endif /* UNITTESTS */ } /** diff --git a/src/decode-icmpv6.h b/src/decode-icmpv6.h index aa66c1f64a3e..c0326a5191bf 100644 --- a/src/decode-icmpv6.h +++ b/src/decode-icmpv6.h @@ -28,142 +28,137 @@ #include "decode-udp.h" #include "decode-ipv6.h" -#define ICMPV6_HEADER_LEN 8 +#define ICMPV6_HEADER_LEN 8 #define ICMPV6_HEADER_PKT_OFFSET 8 /** ICMPV6 Message Types: */ /** Error Messages: (type <128) */ -#define ICMP6_DST_UNREACH 1 -#define ICMP6_PACKET_TOO_BIG 2 -#define ICMP6_TIME_EXCEEDED 3 -#define ICMP6_PARAM_PROB 4 +#define ICMP6_DST_UNREACH 1 +#define ICMP6_PACKET_TOO_BIG 2 +#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_PARAM_PROB 4 /** Informational Messages (type>=128) */ -#define ICMP6_ECHO_REQUEST 128 -#define ICMP6_ECHO_REPLY 129 - -#define MLD_LISTENER_QUERY 130 -#define MLD_LISTENER_REPORT 131 -#define MLD_LISTENER_REDUCTION 132 - -#define ND_ROUTER_SOLICIT 133 -#define ND_ROUTER_ADVERT 134 -#define ND_NEIGHBOR_SOLICIT 135 -#define ND_NEIGHBOR_ADVERT 136 -#define ND_REDIRECT 137 - -#define ICMP6_RR 138 -#define ICMP6_NI_QUERY 139 -#define ICMP6_NI_REPLY 140 -#define ND_INVERSE_SOLICIT 141 -#define ND_INVERSE_ADVERT 142 -#define MLD_V2_LIST_REPORT 143 -#define HOME_AGENT_AD_REQUEST 144 -#define HOME_AGENT_AD_REPLY 145 -#define MOBILE_PREFIX_SOLICIT 146 -#define MOBILE_PREFIX_ADVERT 147 -#define CERT_PATH_SOLICIT 148 -#define CERT_PATH_ADVERT 149 -#define ICMP6_MOBILE_EXPERIMENTAL 150 -#define MC_ROUTER_ADVERT 151 -#define MC_ROUTER_SOLICIT 152 -#define MC_ROUTER_TERMINATE 153 -#define FMIPV6_MSG 154 -#define RPL_CONTROL_MSG 155 -#define LOCATOR_UDATE_MSG 156 -#define DUPL_ADDR_REQUEST 157 -#define DUPL_ADDR_CONFIRM 158 -#define MPL_CONTROL_MSG 159 +#define ICMP6_ECHO_REQUEST 128 +#define ICMP6_ECHO_REPLY 129 + +#define MLD_LISTENER_QUERY 130 +#define MLD_LISTENER_REPORT 131 +#define MLD_LISTENER_REDUCTION 132 + +#define ND_ROUTER_SOLICIT 133 +#define ND_ROUTER_ADVERT 134 +#define ND_NEIGHBOR_SOLICIT 135 +#define ND_NEIGHBOR_ADVERT 136 +#define ND_REDIRECT 137 + +#define ICMP6_RR 138 +#define ICMP6_NI_QUERY 139 +#define ICMP6_NI_REPLY 140 +#define ND_INVERSE_SOLICIT 141 +#define ND_INVERSE_ADVERT 142 +#define MLD_V2_LIST_REPORT 143 +#define HOME_AGENT_AD_REQUEST 144 +#define HOME_AGENT_AD_REPLY 145 +#define MOBILE_PREFIX_SOLICIT 146 +#define MOBILE_PREFIX_ADVERT 147 +#define CERT_PATH_SOLICIT 148 +#define CERT_PATH_ADVERT 149 +#define ICMP6_MOBILE_EXPERIMENTAL 150 +#define MC_ROUTER_ADVERT 151 +#define MC_ROUTER_SOLICIT 152 +#define MC_ROUTER_TERMINATE 153 +#define FMIPV6_MSG 154 +#define RPL_CONTROL_MSG 155 +#define LOCATOR_UDATE_MSG 156 +#define DUPL_ADDR_REQUEST 157 +#define DUPL_ADDR_CONFIRM 158 +#define MPL_CONTROL_MSG 159 /** Destination Unreachable Message (type=1) Code: */ -#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ -#define ICMP6_DST_UNREACH_ADMIN 1 /* communication with destination */ - /* administratively prohibited */ -#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */ -#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */ -#define ICMP6_DST_UNREACH_NOPORT 4 /* bad port */ -#define ICMP6_DST_UNREACH_FAILEDPOLICY 5 /* Source address failed ingress/egress policy */ -#define ICMP6_DST_UNREACH_REJECTROUTE 6 /* Reject route to destination */ - +#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ +#define ICMP6_DST_UNREACH_ADMIN 1 /* communication with destination */ + /* administratively prohibited */ +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */ +#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */ +#define ICMP6_DST_UNREACH_NOPORT 4 /* bad port */ +#define ICMP6_DST_UNREACH_FAILEDPOLICY 5 /* Source address failed ingress/egress policy */ +#define ICMP6_DST_UNREACH_REJECTROUTE 6 /* Reject route to destination */ /** Time Exceeded Message (type=3) Code: */ -#define ICMP6_TIME_EXCEED_TRANSIT 0 /* Hop Limit == 0 in transit */ -#define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* Reassembly time out */ +#define ICMP6_TIME_EXCEED_TRANSIT 0 /* Hop Limit == 0 in transit */ +#define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* Reassembly time out */ /** Parameter Problem Message (type=4) Code: */ -#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */ -#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */ -#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized IPv6 option */ - +#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */ +#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */ +#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized IPv6 option */ /** macro for icmpv6 "type" access */ -#define ICMPV6_GET_TYPE(p) (p)->icmpv6h->type +#define ICMPV6_GET_TYPE(p) (p)->icmpv6h->type /** macro for icmpv6 "code" access */ -#define ICMPV6_GET_CODE(p) (p)->icmpv6h->code +#define ICMPV6_GET_CODE(p) (p)->icmpv6h->code /** macro for icmpv6 "csum" access */ -#define ICMPV6_GET_RAW_CSUM(p) SCNtohs((p)->icmpv6h->csum) -#define ICMPV6_GET_CSUM(p) (p)->icmpv6h->csum +#define ICMPV6_GET_RAW_CSUM(p) SCNtohs((p)->icmpv6h->csum) +#define ICMPV6_GET_CSUM(p) (p)->icmpv6h->csum /** If message is informational */ /** macro for icmpv6 "id" access */ -#define ICMPV6_GET_ID(p) (p)->icmpv6vars.id +#define ICMPV6_GET_ID(p) (p)->icmpv6vars.id /** macro for icmpv6 "seq" access */ -#define ICMPV6_GET_SEQ(p) (p)->icmpv6vars.seq +#define ICMPV6_GET_SEQ(p) (p)->icmpv6vars.seq /** If message is Error */ /** macro for icmpv6 "unused" access */ -#define ICMPV6_GET_UNUSED(p) (p)->icmpv6h->icmpv6b.icmpv6e.unused +#define ICMPV6_GET_UNUSED(p) (p)->icmpv6h->icmpv6b.icmpv6e.unused /** macro for icmpv6 "error_ptr" access */ -#define ICMPV6_GET_ERROR_PTR(p) (p)->icmpv6h->icmpv6b.icmpv6e.error_ptr +#define ICMPV6_GET_ERROR_PTR(p) (p)->icmpv6h->icmpv6b.icmpv6e.error_ptr /** macro for icmpv6 "mtu" accessibility */ // ICMPv6 has MTU only for type too big -#define ICMPV6_HAS_MTU(p) ((p)->icmpv6h->type == ICMP6_PACKET_TOO_BIG) +#define ICMPV6_HAS_MTU(p) ((p)->icmpv6h->type == ICMP6_PACKET_TOO_BIG) /** macro for icmpv6 "mtu" access */ -#define ICMPV6_GET_MTU(p) SCNtohl((p)->icmpv6h->icmpv6b.icmpv6e.mtu) +#define ICMPV6_GET_MTU(p) SCNtohl((p)->icmpv6h->icmpv6b.icmpv6e.mtu) /** macro for icmpv6 embedded "protocol" access */ -#define ICMPV6_GET_EMB_PROTO(p) (p)->icmpv6vars.emb_ip6_proto_next +#define ICMPV6_GET_EMB_PROTO(p) (p)->icmpv6vars.emb_ip6_proto_next /** macro for icmpv6 embedded "ipv6h" header access */ -#define ICMPV6_GET_EMB_IPV6(p) (p)->icmpv6vars.emb_ipv6h +#define ICMPV6_GET_EMB_IPV6(p) (p)->icmpv6vars.emb_ipv6h /** macro for icmpv6 embedded "tcph" header access */ -#define ICMPV6_GET_EMB_TCP(p) (p)->icmpv6vars.emb_tcph +#define ICMPV6_GET_EMB_TCP(p) (p)->icmpv6vars.emb_tcph /** macro for icmpv6 embedded "udph" header access */ -#define ICMPV6_GET_EMB_UDP(p) (p)->icmpv6vars.emb_udph +#define ICMPV6_GET_EMB_UDP(p) (p)->icmpv6vars.emb_udph /** macro for icmpv6 embedded "icmpv6h" header access */ -#define ICMPV6_GET_EMB_icmpv6h(p) (p)->icmpv6vars.emb_icmpv6h +#define ICMPV6_GET_EMB_icmpv6h(p) (p)->icmpv6vars.emb_icmpv6h -typedef struct ICMPV6Info_ -{ - uint16_t id; - uint16_t seq; +typedef struct ICMPV6Info_ { + uint16_t id; + uint16_t seq; } ICMPV6Info; /** ICMPv6 header structure */ -typedef struct ICMPV6Hdr_ -{ - uint8_t type; - uint8_t code; +typedef struct ICMPV6Hdr_ { + uint8_t type; + uint8_t code; uint16_t csum; union { ICMPV6Info icmpv6i; /** Informational message */ - union - { - uint32_t unused; /** for types 1 and 3, should be zero */ - uint32_t error_ptr; /** for type 4, pointer to the octet that originate the error */ - uint32_t mtu; /** for type 2, the Maximum Transmission Unit of the next-hop link */ - } icmpv6e; /** Error Message */ + union { + uint32_t unused; /** for types 1 and 3, should be zero */ + uint32_t error_ptr; /** for type 4, pointer to the octet that originate the error */ + uint32_t mtu; /** for type 2, the Maximum Transmission Unit of the next-hop link */ + } icmpv6e; /** Error Message */ } icmpv6b; } ICMPV6Hdr; /** Data available from the decoded packet */ typedef struct ICMPV6Vars_ { /* checksum of the icmpv6 packet */ - uint16_t id; - uint16_t seq; - uint32_t mtu; - uint32_t error_ptr; + uint16_t id; + uint16_t seq; + uint32_t mtu; + uint32_t error_ptr; /** Pointers to the embedded packet headers */ IPV6Hdr *emb_ipv6h; @@ -182,12 +177,12 @@ typedef struct ICMPV6Vars_ { } ICMPV6Vars; - -#define CLEAR_ICMPV6_PACKET(p) do { \ - (p)->level4_comp_csum = -1; \ - PACKET_CLEAR_L4VARS((p)); \ - (p)->icmpv6h = NULL; \ -} while(0) +#define CLEAR_ICMPV6_PACKET(p) \ + do { \ + (p)->level4_comp_csum = -1; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->icmpv6h = NULL; \ + } while (0) void DecodeICMPV6RegisterTests(void); @@ -211,9 +206,9 @@ static inline uint16_t ICMPV6CalculateChecksum( uint16_t pad = 0; uint32_t csum = shdr[0]; - csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + - shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + - shdr[13] + shdr[14] + shdr[15] + htons(58 + tlen); + csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + shdr[8] + + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + + htons(58 + tlen); csum += pkt[0]; @@ -221,30 +216,28 @@ static inline uint16_t ICMPV6CalculateChecksum( pkt += 2; while (tlen >= 64) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19] + - pkt[20] + pkt[21] + pkt[22] + pkt[23] + pkt[24] + pkt[25] + - pkt[26] + pkt[27] + pkt[28] + pkt[29] + pkt[30] + pkt[31]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15] + pkt[16] + + pkt[17] + pkt[18] + pkt[19] + pkt[20] + pkt[21] + pkt[22] + pkt[23] + pkt[24] + + pkt[25] + pkt[26] + pkt[27] + pkt[28] + pkt[29] + pkt[30] + pkt[31]; tlen -= 64; pkt += 32; } while (tlen >= 32) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } - while(tlen >= 8) { + while (tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } - while(tlen >= 4) { + while (tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; @@ -264,7 +257,7 @@ static inline uint16_t ICMPV6CalculateChecksum( csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); - return (uint16_t) ~csum; + return (uint16_t)~csum; } #endif /* __DECODE_ICMPV6_H__ */ diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 92d0c6ecfd5c..d48af55f6536 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -36,7 +35,7 @@ #include "decode.h" #include "defrag.h" #include "flow.h" -#include "util-print.h" +#include "util/print.h" /* Generic validation * @@ -178,7 +177,7 @@ static int IPV4OptValidateTimestamp(Packet *p, const IPV4Opt *o) */ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) { -// uint32_t doi; + // uint32_t doi; const uint8_t *tag; uint16_t len; @@ -193,11 +192,10 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_MALFORMED); return -1; } -// doi = *o->data; + // doi = *o->data; tag = o->data + 4; len = o->len - 1 - 1 - 4; /* Length of tags after header */ - #if 0 /* Domain of Interest (DOI) of 0 is reserved and thus invalid */ /** \todo Apparently a DOI of zero is fine in practice - verify. */ @@ -218,7 +216,7 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) /* Tag header must fit within option length */ if (unlikely(len < 2)) { - //printf("CIPSO tag header too large %" PRIu16 " < 2\n", len); + // printf("CIPSO tag header too large %" PRIu16 " < 2\n", len); ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_MALFORMED); return -1; } @@ -229,12 +227,12 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) /* Tag length must fit within the option length */ if (unlikely(tlen > len)) { - //printf("CIPSO tag len too large %" PRIu8 " > %" PRIu16 "\n", tlen, len); + // printf("CIPSO tag len too large %" PRIu8 " > %" PRIu16 "\n", tlen, len); ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_MALFORMED); return -1; } - switch(ttype) { + switch (ttype) { case 1: case 2: case 5: @@ -242,7 +240,8 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) case 7: /* Tag is at least 4 and at most the remainder of option len */ if (unlikely((tlen < 4) || (tlen > len))) { - //printf("CIPSO tag %" PRIu8 " bad tlen=%" PRIu8 " len=%" PRIu8 "\n", ttype, tlen, len); + // printf("CIPSO tag %" PRIu8 " bad tlen=%" PRIu8 " len=%" PRIu8 "\n", ttype, + // tlen, len); ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_MALFORMED); return -1; } @@ -251,7 +250,7 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) * type 7, which has no such field. */ if (unlikely((ttype != 7) && (*tag != 0))) { - //printf("CIPSO tag %" PRIu8 " ao=%" PRIu8 "\n", ttype, tlen); + // printf("CIPSO tag %" PRIu8 " ao=%" PRIu8 "\n", ttype, tlen); ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_MALFORMED); return -1; } @@ -264,12 +263,13 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) case 0: /* Tag type 0 is reserved and thus invalid */ /** \todo Wireshark marks this a padding, but spec says reserved. */ - ENGINE_SET_INVALID_EVENT(p,IPV4_OPT_MALFORMED); + ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_MALFORMED); return -1; default: - //printf("CIPSO tag %" PRIu8 " unknown tag\n", ttype); + // printf("CIPSO tag %" PRIu8 " unknown tag\n", ttype); ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_MALFORMED); - /** \todo May not want to return error here on unknown tag type (at least not for 3|4) */ + /** \todo May not want to return error here on unknown tag type (at least not for + * 3|4) */ return -1; } } @@ -312,45 +312,43 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op /* Options length must be padded to 8byte boundary */ if (plen % 8) { - ENGINE_SET_EVENT(p,IPV4_OPT_PAD_REQUIRED); + ENGINE_SET_EVENT(p, IPV4_OPT_PAD_REQUIRED); /* Warn - we can keep going */ } - while (plen) - { + while (plen) { p->ip4vars.opt_cnt++; /* single byte options */ if (*pkt == IPV4_OPT_EOL) { - /** \todo What if more data exist after EOL (possible covert channel or data leakage)? */ - SCLogDebug("IPV4OPT %" PRIu8 " len 1 @ %d/%d", - *pkt, (len - plen), (len - 1)); + /** \todo What if more data exist after EOL (possible covert channel or data leakage)? + */ + SCLogDebug("IPV4OPT %" PRIu8 " len 1 @ %d/%d", *pkt, (len - plen), (len - 1)); p->ip4vars.opts_set |= IPV4_OPT_FLAG_EOL; break; } else if (*pkt == IPV4_OPT_NOP) { - SCLogDebug("IPV4OPT %" PRIu8 " len 1 @ %d/%d", - *pkt, (len - plen), (len - 1)); + SCLogDebug("IPV4OPT %" PRIu8 " len 1 @ %d/%d", *pkt, (len - plen), (len - 1)); pkt++; plen--; p->ip4vars.opts_set |= IPV4_OPT_FLAG_NOP; - /* multibyte options */ + /* multibyte options */ } else { if (unlikely(plen < 2)) { /** \todo What if padding is non-zero (possible covert channel or data leakage)? */ /** \todo Spec seems to indicate EOL required if there is padding */ - ENGINE_SET_EVENT(p,IPV4_OPT_EOL_REQUIRED); + ENGINE_SET_EVENT(p, IPV4_OPT_EOL_REQUIRED); break; } /* Option length is too big for packet */ - if (unlikely(*(pkt+1) > plen)) { + if (unlikely(*(pkt + 1) > plen)) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } - IPV4Opt opt = {*pkt, *(pkt+1), plen > 2 ? (pkt + 2) : NULL }; + IPV4Opt opt = { *pkt, *(pkt + 1), plen > 2 ? (pkt + 2) : NULL }; /* we already know that the total options len is valid, * so here the len of the specific option must be bad. @@ -366,7 +364,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op switch (opt.type) { case IPV4_OPT_TS: if (opts->o_ts.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateTimestamp(p, &opt) == 0) { opts->o_ts = opt; @@ -375,7 +373,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_RR: if (opts->o_rr.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateRoute(p, &opt) == 0) { opts->o_rr = opt; @@ -384,7 +382,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_QS: if (opts->o_qs.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateGeneric(p, &opt) == 0) { opts->o_qs = opt; @@ -393,7 +391,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_SEC: if (opts->o_sec.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateGeneric(p, &opt) == 0) { opts->o_sec = opt; @@ -402,7 +400,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_LSRR: if (opts->o_lsrr.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateRoute(p, &opt) == 0) { opts->o_lsrr = opt; @@ -420,7 +418,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_CIPSO: if (opts->o_cipso.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateCIPSO(p, &opt) == 0) { opts->o_cipso = opt; @@ -429,7 +427,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_SID: if (opts->o_sid.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateGeneric(p, &opt) == 0) { opts->o_sid = opt; @@ -438,7 +436,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_SSRR: if (opts->o_ssrr.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateRoute(p, &opt) == 0) { opts->o_ssrr = opt; @@ -447,7 +445,7 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op break; case IPV4_OPT_RTRALT: if (opts->o_rtralt.type != 0) { - ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ } else if (IPV4OptValidateGeneric(p, &opt) == 0) { opts->o_rtralt = opt; @@ -455,9 +453,8 @@ static int DecodeIPV4Options(Packet *p, const uint8_t *pkt, uint16_t len, IPV4Op } break; default: - SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8, - opt.type, opt.len); - ENGINE_SET_EVENT(p,IPV4_OPT_INVALID); + SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8, opt.type, opt.len); + ENGINE_SET_EVENT(p, IPV4_OPT_INVALID); /* Warn - we can keep going */ break; } @@ -478,7 +475,7 @@ static int DecodeIPV4Packet(Packet *p, const uint8_t *pkt, uint16_t len) } if (unlikely(IP_GET_RAW_VER(pkt) != 4)) { - SCLogDebug("wrong ip version %d",IP_GET_RAW_VER(pkt)); + SCLogDebug("wrong ip version %d", IP_GET_RAW_VER(pkt)); ENGINE_SET_INVALID_EVENT(p, IPV4_WRONG_IP_VER); return -1; } @@ -501,8 +498,8 @@ static int DecodeIPV4Packet(Packet *p, const uint8_t *pkt, uint16_t len) } /* set the address struct */ - SET_IPV4_SRC_ADDR(p,&p->src); - SET_IPV4_DST_ADDR(p,&p->dst); + SET_IPV4_SRC_ADDR(p, &p->src); + SET_IPV4_DST_ADDR(p, &p->dst); /* save the options len */ uint8_t ip_opt_len = IPV4_GET_HLEN(p) - IPV4_HEADER_LEN; @@ -517,18 +514,17 @@ static int DecodeIPV4Packet(Packet *p, const uint8_t *pkt, uint16_t len) return 0; } -int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t len) +int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) { StatsIncr(tv, dtv->counter_ipv4); - SCLogDebug("pkt %p len %"PRIu16"", pkt, len); + SCLogDebug("pkt %p len %" PRIu16 "", pkt, len); if (!PacketIncreaseCheckLayers(p)) { return TM_ECODE_FAILED; } /* do the actual decoding */ - if (unlikely(DecodeIPV4Packet (p, pkt, len) < 0)) { + if (unlikely(DecodeIPV4Packet(p, pkt, len) < 0)) { SCLogDebug("decoding IPv4 packet failed"); CLEAR_IPV4_PACKET((p)); return TM_ECODE_FAILED; @@ -553,57 +549,50 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, char s[16], d[16]; PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), s, sizeof(s)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), d, sizeof(d)); - SCLogDebug("IPV4 %s->%s PROTO: %" PRIu32 " OFFSET: %" PRIu32 " RF: %" PRIu32 " DF: %" PRIu32 " MF: %" PRIu32 " ID: %" PRIu32 "", s,d, - IPV4_GET_IPPROTO(p), IPV4_GET_IPOFFSET(p), IPV4_GET_RF(p), - IPV4_GET_DF(p), IPV4_GET_MF(p), IPV4_GET_IPID(p)); + SCLogDebug("IPV4 %s->%s PROTO: %" PRIu32 " OFFSET: %" PRIu32 " RF: %" PRIu32 " DF: %" PRIu32 + " MF: %" PRIu32 " ID: %" PRIu32 "", + s, d, IPV4_GET_IPPROTO(p), IPV4_GET_IPOFFSET(p), IPV4_GET_RF(p), IPV4_GET_DF(p), + IPV4_GET_MF(p), IPV4_GET_IPID(p)); } #endif /* DEBUG */ /* check what next decoder to invoke */ switch (IPV4_GET_IPPROTO(p)) { case IPPROTO_TCP: - DecodeTCP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), - IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); + DecodeTCP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); break; case IPPROTO_UDP: - DecodeUDP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), - IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); + DecodeUDP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); break; case IPPROTO_ICMP: - DecodeICMPV4(tv, dtv, p, pkt + IPV4_GET_HLEN(p), - IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); + DecodeICMPV4(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); break; case IPPROTO_GRE: - DecodeGRE(tv, dtv, p, pkt + IPV4_GET_HLEN(p), - IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); + DecodeGRE(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); break; case IPPROTO_SCTP: - DecodeSCTP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), - IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); + DecodeSCTP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); break; case IPPROTO_ESP: DecodeESP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); break; - case IPPROTO_IPV6: - { - /* spawn off tunnel packet */ - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + IPV4_GET_HLEN(p), - IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), - DECODE_TUNNEL_IPV6); - if (tp != NULL) { - PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV4); - PacketEnqueueNoLock(&tv->decode_pq,tp); - } - FlowSetupPacket(p); - break; + case IPPROTO_IPV6: { + /* spawn off tunnel packet */ + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + IPV4_GET_HLEN(p), + IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), DECODE_TUNNEL_IPV6); + if (tp != NULL) { + PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV4); + PacketEnqueueNoLock(&tv->decode_pq, tp); } + FlowSetupPacket(p); + break; + } case IPPROTO_IP: /* check PPP VJ uncompressed packets and decode tcp dummy */ - if(p->ppph != NULL && SCNtohs(p->ppph->protocol) == PPP_VJ_UCOMP) { - DecodeTCP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), - IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); + if (p->ppph != NULL && SCNtohs(p->ppph->protocol) == PPP_VJ_UCOMP) { + DecodeTCP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); } break; case IPPROTO_ICMPV6: @@ -621,7 +610,7 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /** \test IPV4 with no options. */ static int DecodeIPV4OptionsNONETest01(void) { - uint8_t raw_opts[] = { }; + uint8_t raw_opts[] = {}; Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -637,9 +626,11 @@ static int DecodeIPV4OptionsNONETest01(void) /** \test IPV4 with EOL option. */ static int DecodeIPV4OptionsEOLTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_EOL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); IPV4Options opts; @@ -653,9 +644,11 @@ static int DecodeIPV4OptionsEOLTest01(void) /** \test IPV4 with NOP option. */ static int DecodeIPV4OptionsNOPTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_NOP, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); IPV4Options opts; @@ -669,6 +662,7 @@ static int DecodeIPV4OptionsNOPTest01(void) /** \test IPV4 with RR option. */ static int DecodeIPV4OptionsRRTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_RR, 0x27, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -676,6 +670,7 @@ static int DecodeIPV4OptionsRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -691,6 +686,7 @@ static int DecodeIPV4OptionsRRTest01(void) /** \test IPV4 with RR option (len too large). */ static int DecodeIPV4OptionsRRTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_RR, 0xff, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -698,6 +694,7 @@ static int DecodeIPV4OptionsRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -713,6 +710,7 @@ static int DecodeIPV4OptionsRRTest02(void) /** \test IPV4 with RR option (ptr too large). */ static int DecodeIPV4OptionsRRTest03(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_RR, 0x27, 0xff, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -720,6 +718,7 @@ static int DecodeIPV4OptionsRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -735,6 +734,7 @@ static int DecodeIPV4OptionsRRTest03(void) /** \test IPV4 with RR option (ptr not in 4 byte increment). */ static int DecodeIPV4OptionsRRTest04(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_RR, 0x27, 0x05, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -742,6 +742,7 @@ static int DecodeIPV4OptionsRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -757,9 +758,11 @@ static int DecodeIPV4OptionsRRTest04(void) /** \test IPV4 with QS option. */ static int DecodeIPV4OptionsQSTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_QS, 0x08, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -775,9 +778,11 @@ static int DecodeIPV4OptionsQSTest01(void) /** \test IPV4 with QS option (len too small) */ static int DecodeIPV4OptionsQSTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_QS, 0x07, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -793,6 +798,7 @@ static int DecodeIPV4OptionsQSTest02(void) /** \test IPV4 with TS option. */ static int DecodeIPV4OptionsTSTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0x0d, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -800,6 +806,7 @@ static int DecodeIPV4OptionsTSTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -815,6 +822,7 @@ static int DecodeIPV4OptionsTSTest01(void) /** \test IPV4 with TS option (ptr too small). */ static int DecodeIPV4OptionsTSTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0x04, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -822,6 +830,7 @@ static int DecodeIPV4OptionsTSTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -837,6 +846,7 @@ static int DecodeIPV4OptionsTSTest02(void) /** \test IPV4 with TS option (ptr too large). */ static int DecodeIPV4OptionsTSTest03(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0xff, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -844,6 +854,7 @@ static int DecodeIPV4OptionsTSTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -859,6 +870,7 @@ static int DecodeIPV4OptionsTSTest03(void) /** \test IPV4 with TS option (ptr not valid). */ static int DecodeIPV4OptionsTSTest04(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_TS, 0x24, 0x0a, 0x01, 0x0a, 0x0a, 0x0a, 0x69, 0x04, 0xce, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -866,6 +878,7 @@ static int DecodeIPV4OptionsTSTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -881,10 +894,12 @@ static int DecodeIPV4OptionsTSTest04(void) /** \test IPV4 with SEC option. */ static int DecodeIPV4OptionsSECTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SEC, 0x0b, 0xf1, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -900,8 +915,10 @@ static int DecodeIPV4OptionsSECTest01(void) /** \test IPV4 with SEC option (invalid length). */ static int DecodeIPV4OptionsSECTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SEC, 0x02, 0xf1, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -917,8 +934,10 @@ static int DecodeIPV4OptionsSECTest02(void) /** \test IPV4 with ESEC option. */ static int DecodeIPV4OptionsESECTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_ESEC, 0x0b, 0xf1, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -934,8 +953,10 @@ static int DecodeIPV4OptionsESECTest01(void) /** \test IPV4 with ESEC option (invalid length). */ static int DecodeIPV4OptionsESECTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_ESEC, 0x02, 0xf1, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -951,6 +972,7 @@ static int DecodeIPV4OptionsESECTest02(void) /** \test IPV4 with LSRR option. */ static int DecodeIPV4OptionsLSRRTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0x27, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -958,6 +980,7 @@ static int DecodeIPV4OptionsLSRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -973,6 +996,7 @@ static int DecodeIPV4OptionsLSRRTest01(void) /** \test IPV4 with LSRR option (len too large). */ static int DecodeIPV4OptionsLSRRTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0xff, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -980,6 +1004,7 @@ static int DecodeIPV4OptionsLSRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -995,6 +1020,7 @@ static int DecodeIPV4OptionsLSRRTest02(void) /** \test IPV4 with LSRR option (ptr too large). */ static int DecodeIPV4OptionsLSRRTest03(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0x27, 0xff, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1002,6 +1028,7 @@ static int DecodeIPV4OptionsLSRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1017,6 +1044,7 @@ static int DecodeIPV4OptionsLSRRTest03(void) /** \test IPV4 with LSRR option (ptr not in 4 byte increment). */ static int DecodeIPV4OptionsLSRRTest04(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_LSRR, 0x27, 0x05, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1024,6 +1052,7 @@ static int DecodeIPV4OptionsLSRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1039,11 +1068,13 @@ static int DecodeIPV4OptionsLSRRTest04(void) /** \test IPV4 with CIPSO option. */ static int DecodeIPV4OptionsCIPSOTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_CIPSO, 0x18, 0x00, 0x00, 0x00, 0x05, 0x05, 0x12, 0x00, 0x03, 0x00, 0xef, 0x00, 0xef, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1059,9 +1090,11 @@ static int DecodeIPV4OptionsCIPSOTest01(void) /** \test IPV4 with SID option. */ static int DecodeIPV4OptionsSIDTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SID, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1077,9 +1110,11 @@ static int DecodeIPV4OptionsSIDTest01(void) /** \test IPV4 with SID option (len invalid. */ static int DecodeIPV4OptionsSIDTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SID, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1095,6 +1130,7 @@ static int DecodeIPV4OptionsSIDTest02(void) /** \test IPV4 with SSRR option. */ static int DecodeIPV4OptionsSSRRTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0x27, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1102,6 +1138,7 @@ static int DecodeIPV4OptionsSSRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1117,6 +1154,7 @@ static int DecodeIPV4OptionsSSRRTest01(void) /** \test IPV4 with SSRR option (len too large). */ static int DecodeIPV4OptionsSSRRTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0xff, 0x08, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1124,6 +1162,7 @@ static int DecodeIPV4OptionsSSRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1139,6 +1178,7 @@ static int DecodeIPV4OptionsSSRRTest02(void) /** \test IPV4 with SSRR option (ptr too large). */ static int DecodeIPV4OptionsSSRRTest03(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0x27, 0xff, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1146,6 +1186,7 @@ static int DecodeIPV4OptionsSSRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1161,6 +1202,7 @@ static int DecodeIPV4OptionsSSRRTest03(void) /** \test IPV4 with SSRR option (ptr not in 4 byte increment). */ static int DecodeIPV4OptionsSSRRTest04(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_SSRR, 0x27, 0x05, 0xc0, 0xa8, 0x2a, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1168,6 +1210,7 @@ static int DecodeIPV4OptionsSSRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1183,9 +1226,11 @@ static int DecodeIPV4OptionsSSRRTest04(void) /** \test IPV4 with RTRALT option. */ static int DecodeIPV4OptionsRTRALTTest01(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_RTRALT, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1201,9 +1246,11 @@ static int DecodeIPV4OptionsRTRALTTest01(void) /** \test IPV4 with RTRALT option (len invalid. */ static int DecodeIPV4OptionsRTRALTTest02(void) { + // clang-format off uint8_t raw_opts[] = { IPV4_OPT_RTRALT, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -1220,12 +1267,14 @@ static int IPV4CalculateValidChecksumtest01(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on - csum = *( ((uint16_t *)raw_ipv4) + 5); + csum = *(((uint16_t *)raw_ipv4) + 5); FAIL_IF(IPV4Checksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4), csum) != 0); PASS; @@ -1235,12 +1284,14 @@ static int IPV4CalculateInvalidChecksumtest02(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x07}; + // clang-format on - csum = *( ((uint16_t *)raw_ipv4) + 5); + csum = *(((uint16_t *)raw_ipv4) + 5); FAIL_IF(IPV4Checksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4), csum) == 0); PASS; @@ -1251,6 +1302,7 @@ static int IPV4CalculateInvalidChecksumtest02(void) */ static int DecodeIPV4DefragTest01(void) { + // clang-format off uint8_t pkt1[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1259,6 +1311,8 @@ static int DecodeIPV4DefragTest01(void) 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e }; + // clang-format on + // clang-format off uint8_t pkt2[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1267,6 +1321,8 @@ static int DecodeIPV4DefragTest01(void) 0xe1, 0x0c, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00 }; + // clang-format on + // clang-format off uint8_t pkt3[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1274,6 +1330,8 @@ static int DecodeIPV4DefragTest01(void) 0xba, 0xca, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0xb1, 0xa3, 0x00, 0x00 }; + // clang-format on + // clang-format off uint8_t tunnel_pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1283,6 +1341,7 @@ static int DecodeIPV4DefragTest01(void) 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1299,7 +1358,7 @@ static int DecodeIPV4DefragTest01(void) PacketCopyData(p, pkt1, sizeof(pkt1)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; @@ -1309,7 +1368,7 @@ static int DecodeIPV4DefragTest01(void) PacketCopyData(p, pkt2, sizeof(pkt2)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; @@ -1319,7 +1378,7 @@ static int DecodeIPV4DefragTest01(void) PacketCopyData(p, pkt3, sizeof(pkt3)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; @@ -1334,7 +1393,7 @@ static int DecodeIPV4DefragTest01(void) if (tp->recursion_level != p->recursion_level) { printf("defragged pseudo packet's and parent packet's recursion " "level don't match\n %d != %d", - tp->recursion_level, p->recursion_level); + tp->recursion_level, p->recursion_level); result = 0; goto end; } @@ -1346,14 +1405,14 @@ static int DecodeIPV4DefragTest01(void) } if (GET_PKT_LEN(tp) != sizeof(tunnel_pkt)) { printf("defragged pseudo packet's and parent packet's pkt lens " - "don't match\n %u != %"PRIuMAX, - GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); + "don't match\n %u != %" PRIuMAX, + GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); result = 0; goto end; } if (memcmp(GET_PKT_DATA(tp), tunnel_pkt, sizeof(tunnel_pkt)) != 0) { - result = 0; - goto end; + result = 0; + goto end; } PacketRecycle(tp); @@ -1373,6 +1432,7 @@ static int DecodeIPV4DefragTest01(void) */ static int DecodeIPV4DefragTest02(void) { + // clang-format off uint8_t pkt1[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1384,6 +1444,8 @@ static int DecodeIPV4DefragTest02(void) 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, }; + // clang-format on + // clang-format off uint8_t pkt2[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1395,6 +1457,8 @@ static int DecodeIPV4DefragTest02(void) 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04 }; + // clang-format on + // clang-format off uint8_t pkt3[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1404,7 +1468,9 @@ static int DecodeIPV4DefragTest02(void) /* final frag */ 0xb1, 0xa3, }; + // clang-format on + // clang-format off uint8_t tunnel_pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1418,6 +1484,7 @@ static int DecodeIPV4DefragTest02(void) 0xb1, 0xa3, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04, 0xb1, 0xa3, }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1434,7 +1501,7 @@ static int DecodeIPV4DefragTest02(void) PacketCopyData(p, pkt1, sizeof(pkt1)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); goto end; @@ -1443,7 +1510,7 @@ static int DecodeIPV4DefragTest02(void) PacketCopyData(p, pkt2, sizeof(pkt2)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); goto end; @@ -1453,7 +1520,7 @@ static int DecodeIPV4DefragTest02(void) p->recursion_level = 3; PacketCopyData(p, pkt3, sizeof(pkt3)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); goto end; @@ -1466,7 +1533,7 @@ static int DecodeIPV4DefragTest02(void) if (tp->recursion_level != p->recursion_level) { printf("defragged pseudo packet's and parent packet's recursion " "level don't match %d != %d: ", - tp->recursion_level, p->recursion_level); + tp->recursion_level, p->recursion_level); goto end; } if (tp->ip4h == NULL || tp->tcph == NULL) { @@ -1476,8 +1543,8 @@ static int DecodeIPV4DefragTest02(void) } if (GET_PKT_LEN(tp) != sizeof(tunnel_pkt)) { printf("defragged pseudo packet's and parent packet's pkt lens " - "don't match %u != %"PRIuMAX": ", - GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); + "don't match %u != %" PRIuMAX ": ", + GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); goto end; } @@ -1502,6 +1569,7 @@ static int DecodeIPV4DefragTest02(void) */ static int DecodeIPV4DefragTest03(void) { + // clang-format off uint8_t pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1511,6 +1579,8 @@ static int DecodeIPV4DefragTest03(void) 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x80, 0x00, 0x0c, 0xee, 0x00, 0x00 }; + // clang-format on + // clang-format off uint8_t pkt1[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1519,6 +1589,8 @@ static int DecodeIPV4DefragTest03(void) 0xe1, 0x0c, 0x6e, 0x12, 0x01, 0xbd, 0x5b, 0xa3, 0x81, 0x5e }; + // clang-format on + // clang-format off uint8_t pkt2[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1527,6 +1599,8 @@ static int DecodeIPV4DefragTest03(void) 0xe1, 0x0c, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00 }; + // clang-format on + // clang-format off uint8_t pkt3[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1534,6 +1608,8 @@ static int DecodeIPV4DefragTest03(void) 0xba, 0xca, 0x0a, 0x00, 0xe1, 0x17, 0x0a, 0x00, 0xe1, 0x0c, 0xb1, 0xa3, 0x00, 0x00 }; + // clang-format on + // clang-format off uint8_t tunnel_pkt[] = { 0x00, 0x50, 0x56, 0x00, 0x03, 0x05, 0xde, 0xad, 0x01, 0xa3, 0xa2, 0x2f, 0x08, 0x00, 0x45, 0x00, @@ -1543,6 +1619,7 @@ static int DecodeIPV4DefragTest03(void) 0x81, 0x5e, 0xac, 0xb0, 0xae, 0x8a, 0x50, 0x10, 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1559,7 +1636,7 @@ static int DecodeIPV4DefragTest03(void) PacketCopyData(p, pkt, sizeof(pkt)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph == NULL) { printf("tcp header shouldn't be NULL, but it is\n"); result = 0; @@ -1574,7 +1651,7 @@ static int DecodeIPV4DefragTest03(void) PacketCopyData(p, pkt1, sizeof(pkt1)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; @@ -1584,7 +1661,7 @@ static int DecodeIPV4DefragTest03(void) PacketCopyData(p, pkt2, sizeof(pkt2)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; @@ -1594,7 +1671,7 @@ static int DecodeIPV4DefragTest03(void) PacketCopyData(p, pkt3, sizeof(pkt3)); DecodeIPV4(&tv, &dtv, p, GET_PKT_DATA(p) + ETHERNET_HEADER_LEN, - GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); + GET_PKT_LEN(p) - ETHERNET_HEADER_LEN); if (p->tcph != NULL) { printf("tcp header should be NULL for ip fragment, but it isn't\n"); result = 0; @@ -1618,7 +1695,7 @@ static int DecodeIPV4DefragTest03(void) if (tp->recursion_level != p->recursion_level) { printf("defragged pseudo packet's and parent packet's recursion " "level don't match\n %d != %d", - tp->recursion_level, p->recursion_level); + tp->recursion_level, p->recursion_level); result = 0; goto end; } @@ -1630,15 +1707,15 @@ static int DecodeIPV4DefragTest03(void) } if (GET_PKT_LEN(tp) != sizeof(tunnel_pkt)) { printf("defragged pseudo packet's and parent packet's pkt lens " - "don't match\n %u != %"PRIuMAX, - GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); + "don't match\n %u != %" PRIuMAX, + GET_PKT_LEN(tp), (uintmax_t)sizeof(tunnel_pkt)); result = 0; goto end; } if (memcmp(GET_PKT_DATA(tp), tunnel_pkt, sizeof(tunnel_pkt)) != 0) { - result = 0; - goto end; + result = 0; + goto end; } PacketRecycle(tp); @@ -1656,6 +1733,7 @@ static int DecodeIPV4DefragTest03(void) */ static int DecodeEthernetTestIPv4Opt(void) { + // clang-format off uint8_t raw_eth[] = { 0xae, 0x71, 0x00, 0x00, 0x00, 0x4b, 0x06, 0x90, 0x61, 0x02, 0x00, 0xcd, 0x88, 0x64, 0x11, 0x00, 0x15, 0x00, 0x80, 0x64, 0x00, 0x21, 0x4c, 0x00, 0x00, 0x30, 0x42, 0xd6, 0xff, 0xff, 0xbd, 0x2f, @@ -1663,6 +1741,7 @@ static int DecodeEthernetTestIPv4Opt(void) 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x44, 0x05, 0x22, 0x02, 0x01 }; + // clang-format on DefragInit(); @@ -1672,7 +1751,7 @@ static int DecodeEthernetTestIPv4Opt(void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth)); @@ -1707,22 +1786,17 @@ void DecodeIPV4RegisterTests(void) UtRegisterTest("DecodeIPV4OptionsLSRRTest02", DecodeIPV4OptionsLSRRTest02); UtRegisterTest("DecodeIPV4OptionsLSRRTest03", DecodeIPV4OptionsLSRRTest03); UtRegisterTest("DecodeIPV4OptionsLSRRTest04", DecodeIPV4OptionsLSRRTest04); - UtRegisterTest("DecodeIPV4OptionsCIPSOTest01", - DecodeIPV4OptionsCIPSOTest01); + UtRegisterTest("DecodeIPV4OptionsCIPSOTest01", DecodeIPV4OptionsCIPSOTest01); UtRegisterTest("DecodeIPV4OptionsSIDTest01", DecodeIPV4OptionsSIDTest01); UtRegisterTest("DecodeIPV4OptionsSIDTest02", DecodeIPV4OptionsSIDTest02); UtRegisterTest("DecodeIPV4OptionsSSRRTest01", DecodeIPV4OptionsSSRRTest01); UtRegisterTest("DecodeIPV4OptionsSSRRTest02", DecodeIPV4OptionsSSRRTest02); UtRegisterTest("DecodeIPV4OptionsSSRRTest03", DecodeIPV4OptionsSSRRTest03); UtRegisterTest("DecodeIPV4OptionsSSRRTest04", DecodeIPV4OptionsSSRRTest04); - UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", - DecodeIPV4OptionsRTRALTTest01); - UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", - DecodeIPV4OptionsRTRALTTest02); - UtRegisterTest("IPV4CalculateValidChecksumtest01", - IPV4CalculateValidChecksumtest01); - UtRegisterTest("IPV4CalculateInvalidChecksumtest02", - IPV4CalculateInvalidChecksumtest02); + UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", DecodeIPV4OptionsRTRALTTest01); + UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", DecodeIPV4OptionsRTRALTTest02); + UtRegisterTest("IPV4CalculateValidChecksumtest01", IPV4CalculateValidChecksumtest01); + UtRegisterTest("IPV4CalculateInvalidChecksumtest02", IPV4CalculateInvalidChecksumtest02); UtRegisterTest("DecodeIPV4DefragTest01", DecodeIPV4DefragTest01); UtRegisterTest("DecodeIPV4DefragTest02", DecodeIPV4DefragTest02); UtRegisterTest("DecodeIPV4DefragTest03", DecodeIPV4DefragTest03); diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index d247fa9f0033..59fefa3e6fe9 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -25,92 +25,92 @@ #ifndef __DECODE_IPV4_H__ #define __DECODE_IPV4_H__ -#define IPV4_HEADER_LEN 20 /**< Header length */ -#define IPV4_OPTMAX 40 /**< Max options length */ -#define IPV4_MAXPACKET_LEN 65535 /**< Maximum packet size */ +#define IPV4_HEADER_LEN 20 /**< Header length */ +#define IPV4_OPTMAX 40 /**< Max options length */ +#define IPV4_MAXPACKET_LEN 65535 /**< Maximum packet size */ /** IP Option Types */ -#define IPV4_OPT_EOL 0x00 /**< Option: End of List */ -#define IPV4_OPT_NOP 0x01 /**< Option: No op */ -#define IPV4_OPT_RR 0x07 /**< Option: Record Route */ -#define IPV4_OPT_QS 0x19 /**< Option: Quick Start */ -#define IPV4_OPT_TS 0x44 /**< Option: Timestamp */ -#define IPV4_OPT_SEC 0x82 /**< Option: Security */ -#define IPV4_OPT_LSRR 0x83 /**< Option: Loose Source Route */ -#define IPV4_OPT_ESEC 0x85 /**< Option: Extended Security */ -#define IPV4_OPT_CIPSO 0x86 /**< Option: Commercial IP Security */ -#define IPV4_OPT_SID 0x88 /**< Option: Stream Identifier */ -#define IPV4_OPT_SSRR 0x89 /**< Option: Strict Source Route */ -#define IPV4_OPT_RTRALT 0x94 /**< Option: Router Alert */ +#define IPV4_OPT_EOL 0x00 /**< Option: End of List */ +#define IPV4_OPT_NOP 0x01 /**< Option: No op */ +#define IPV4_OPT_RR 0x07 /**< Option: Record Route */ +#define IPV4_OPT_QS 0x19 /**< Option: Quick Start */ +#define IPV4_OPT_TS 0x44 /**< Option: Timestamp */ +#define IPV4_OPT_SEC 0x82 /**< Option: Security */ +#define IPV4_OPT_LSRR 0x83 /**< Option: Loose Source Route */ +#define IPV4_OPT_ESEC 0x85 /**< Option: Extended Security */ +#define IPV4_OPT_CIPSO 0x86 /**< Option: Commercial IP Security */ +#define IPV4_OPT_SID 0x88 /**< Option: Stream Identifier */ +#define IPV4_OPT_SSRR 0x89 /**< Option: Strict Source Route */ +#define IPV4_OPT_RTRALT 0x94 /**< Option: Router Alert */ /** IP Option Lengths (fixed) */ -#define IPV4_OPT_SID_LEN 4 /**< SID Option Fixed Length */ -#define IPV4_OPT_RTRALT_LEN 4 /**< RTRALT Option Fixed Length */ +#define IPV4_OPT_SID_LEN 4 /**< SID Option Fixed Length */ +#define IPV4_OPT_RTRALT_LEN 4 /**< RTRALT Option Fixed Length */ /** IP Option Lengths (variable) */ -#define IPV4_OPT_SEC_MIN 3 /**< SEC, ESEC Option Min Length */ -#define IPV4_OPT_ROUTE_MIN 3 /**< RR, SRR, LTRR Option Min Length */ -#define IPV4_OPT_QS_MIN 8 /**< QS Option Min Length */ -#define IPV4_OPT_TS_MIN 5 /**< TS Option Min Length */ -#define IPV4_OPT_CIPSO_MIN 10 /**< CIPSO Option Min Length */ +#define IPV4_OPT_SEC_MIN 3 /**< SEC, ESEC Option Min Length */ +#define IPV4_OPT_ROUTE_MIN 3 /**< RR, SRR, LTRR Option Min Length */ +#define IPV4_OPT_QS_MIN 8 /**< QS Option Min Length */ +#define IPV4_OPT_TS_MIN 5 /**< TS Option Min Length */ +#define IPV4_OPT_CIPSO_MIN 10 /**< CIPSO Option Min Length */ /** IP Option fields */ -#define IPV4_OPTS ip4vars.ip_opts -#define IPV4_OPTS_CNT ip4vars.ip_opt_cnt +#define IPV4_OPTS ip4vars.ip_opts +#define IPV4_OPTS_CNT ip4vars.ip_opt_cnt typedef struct IPV4Opt_ { /** \todo We may want to break type up into its 3 fields * as the reassembler may want to know which options * must be copied to each fragment. */ - uint8_t type; /**< option type */ - uint8_t len; /**< option length (type+len+data) */ - const uint8_t *data; /**< option data */ + uint8_t type; /**< option type */ + uint8_t len; /**< option length (type+len+data) */ + const uint8_t *data; /**< option data */ } IPV4Opt; -typedef struct IPV4Hdr_ -{ - uint8_t ip_verhl; /**< version & header length */ - uint8_t ip_tos; /**< type of service */ - uint16_t ip_len; /**< length */ - uint16_t ip_id; /**< id */ - uint16_t ip_off; /**< frag offset */ - uint8_t ip_ttl; /**< time to live */ - uint8_t ip_proto; /**< protocol (tcp, udp, etc) */ - uint16_t ip_csum; /**< checksum */ +typedef struct IPV4Hdr_ { + uint8_t ip_verhl; /**< version & header length */ + uint8_t ip_tos; /**< type of service */ + uint16_t ip_len; /**< length */ + uint16_t ip_id; /**< id */ + uint16_t ip_off; /**< frag offset */ + uint8_t ip_ttl; /**< time to live */ + uint8_t ip_proto; /**< protocol (tcp, udp, etc) */ + uint16_t ip_csum; /**< checksum */ union { struct { - struct in_addr ip_src;/**< source address */ - struct in_addr ip_dst;/**< destination address */ + struct in_addr ip_src; /**< source address */ + struct in_addr ip_dst; /**< destination address */ } ip4_un1; uint16_t ip_addrs[4]; } ip4_hdrun1; } IPV4Hdr; - -#define s_ip_src ip4_hdrun1.ip4_un1.ip_src -#define s_ip_dst ip4_hdrun1.ip4_un1.ip_dst -#define s_ip_addrs ip4_hdrun1.ip_addrs - -#define IPV4_GET_RAW_VER(ip4h) (((ip4h)->ip_verhl & 0xf0) >> 4) -#define IPV4_GET_RAW_HLEN(ip4h) ((ip4h)->ip_verhl & 0x0f) -#define IPV4_GET_RAW_IPTOS(ip4h) ((ip4h)->ip_tos) -#define IPV4_GET_RAW_IPLEN(ip4h) ((ip4h)->ip_len) -#define IPV4_GET_RAW_IPID(ip4h) ((ip4h)->ip_id) -#define IPV4_GET_RAW_IPOFFSET(ip4h) ((ip4h)->ip_off) -#define IPV4_GET_RAW_IPTTL(ip4h) ((ip4h)->ip_ttl) -#define IPV4_GET_RAW_IPPROTO(ip4h) ((ip4h)->ip_proto) -#define IPV4_GET_RAW_IPSRC(ip4h) ((ip4h)->s_ip_src) -#define IPV4_GET_RAW_IPDST(ip4h) ((ip4h)->s_ip_dst) +#define s_ip_src ip4_hdrun1.ip4_un1.ip_src +#define s_ip_dst ip4_hdrun1.ip4_un1.ip_dst +#define s_ip_addrs ip4_hdrun1.ip_addrs + +#define IPV4_GET_RAW_VER(ip4h) (((ip4h)->ip_verhl & 0xf0) >> 4) +#define IPV4_GET_RAW_HLEN(ip4h) ((ip4h)->ip_verhl & 0x0f) +#define IPV4_GET_RAW_IPTOS(ip4h) ((ip4h)->ip_tos) +#define IPV4_GET_RAW_IPLEN(ip4h) ((ip4h)->ip_len) +#define IPV4_GET_RAW_IPID(ip4h) ((ip4h)->ip_id) +#define IPV4_GET_RAW_IPOFFSET(ip4h) ((ip4h)->ip_off) +#define IPV4_GET_RAW_IPTTL(ip4h) ((ip4h)->ip_ttl) +#define IPV4_GET_RAW_IPPROTO(ip4h) ((ip4h)->ip_proto) +#define IPV4_GET_RAW_IPSRC(ip4h) ((ip4h)->s_ip_src) +#define IPV4_GET_RAW_IPDST(ip4h) ((ip4h)->s_ip_dst) /** return the raw (directly from the header) src ip as uint32_t */ -#define IPV4_GET_RAW_IPSRC_U32(ip4h) (uint32_t)((ip4h)->s_ip_src.s_addr) +#define IPV4_GET_RAW_IPSRC_U32(ip4h) (uint32_t)((ip4h)->s_ip_src.s_addr) /** return the raw (directly from the header) dst ip as uint32_t */ -#define IPV4_GET_RAW_IPDST_U32(ip4h) (uint32_t)((ip4h)->s_ip_dst.s_addr) +#define IPV4_GET_RAW_IPDST_U32(ip4h) (uint32_t)((ip4h)->s_ip_dst.s_addr) /* we need to change them as well as get them */ -#define IPV4_SET_RAW_VER(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0x0f) | (value << 4))) -#define IPV4_SET_RAW_HLEN(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0xf0) | (value & 0x0f))) +#define IPV4_SET_RAW_VER(ip4h, value) \ + ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0x0f) | (value << 4))) +#define IPV4_SET_RAW_HLEN(ip4h, value) \ + ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0xf0) | (value & 0x0f))) #define IPV4_SET_RAW_IPTOS(ip4h, value) ((ip4h)->ip_tos = value) #define IPV4_SET_RAW_IPLEN(ip4h, value) ((ip4h)->ip_len = value) #define IPV4_SET_RAW_IPPROTO(ip4h, value) ((ip4h)->ip_proto = value) @@ -119,40 +119,30 @@ typedef struct IPV4Hdr_ * 1. p->ip4h is set * 2. p->ip4h is valid (len is correct) */ -#define IPV4_GET_VER(p) \ - IPV4_GET_RAW_VER((p)->ip4h) -#define IPV4_GET_HLEN(p) ((uint8_t)(IPV4_GET_RAW_HLEN((p)->ip4h) << 2)) -#define IPV4_GET_IPTOS(p) \ - IPV4_GET_RAW_IPTOS((p)->ip4h) -#define IPV4_GET_IPLEN(p) \ - (SCNtohs(IPV4_GET_RAW_IPLEN((p)->ip4h))) -#define IPV4_GET_IPID(p) \ - (SCNtohs(IPV4_GET_RAW_IPID((p)->ip4h))) +#define IPV4_GET_VER(p) IPV4_GET_RAW_VER((p)->ip4h) +#define IPV4_GET_HLEN(p) ((uint8_t)(IPV4_GET_RAW_HLEN((p)->ip4h) << 2)) +#define IPV4_GET_IPTOS(p) IPV4_GET_RAW_IPTOS((p)->ip4h) +#define IPV4_GET_IPLEN(p) (SCNtohs(IPV4_GET_RAW_IPLEN((p)->ip4h))) +#define IPV4_GET_IPID(p) (SCNtohs(IPV4_GET_RAW_IPID((p)->ip4h))) /* _IPV4_GET_IPOFFSET: get the content of the offset header field in host order */ -#define _IPV4_GET_IPOFFSET(p) \ - (SCNtohs(IPV4_GET_RAW_IPOFFSET((p)->ip4h))) +#define _IPV4_GET_IPOFFSET(p) (SCNtohs(IPV4_GET_RAW_IPOFFSET((p)->ip4h))) /* IPV4_GET_IPOFFSET: get the final offset */ -#define IPV4_GET_IPOFFSET(p) \ - (_IPV4_GET_IPOFFSET(p) & 0x1fff) +#define IPV4_GET_IPOFFSET(p) (_IPV4_GET_IPOFFSET(p) & 0x1fff) /* IPV4_GET_RF: get the RF flag. Use _IPV4_GET_IPOFFSET to save a SCNtohs call. */ -#define IPV4_GET_RF(p) \ - (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x8000) >> 15) +#define IPV4_GET_RF(p) (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x8000) >> 15) /* IPV4_GET_DF: get the DF flag. Use _IPV4_GET_IPOFFSET to save a SCNtohs call. */ -#define IPV4_GET_DF(p) \ - (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x4000) >> 14) +#define IPV4_GET_DF(p) (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x4000) >> 14) /* IPV4_GET_MF: get the MF flag. Use _IPV4_GET_IPOFFSET to save a SCNtohs call. */ -#define IPV4_GET_MF(p) \ - (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x2000) >> 13) -#define IPV4_GET_IPTTL(p) \ - IPV4_GET_RAW_IPTTL(p->ip4h) -#define IPV4_GET_IPPROTO(p) \ - IPV4_GET_RAW_IPPROTO((p)->ip4h) - -#define CLEAR_IPV4_PACKET(p) do { \ - (p)->ip4h = NULL; \ - (p)->level3_comp_csum = -1; \ - memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \ -} while (0) +#define IPV4_GET_MF(p) (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x2000) >> 13) +#define IPV4_GET_IPTTL(p) IPV4_GET_RAW_IPTTL(p->ip4h) +#define IPV4_GET_IPPROTO(p) IPV4_GET_RAW_IPPROTO((p)->ip4h) + +#define CLEAR_IPV4_PACKET(p) \ + do { \ + (p)->ip4h = NULL; \ + (p)->level3_comp_csum = -1; \ + memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \ + } while (0) enum IPV4OptionFlags { IPV4_OPT_FLAG_EOL = 0, @@ -170,15 +160,13 @@ enum IPV4OptionFlags { }; /* helper structure with parsed ipv4 info */ -typedef struct IPV4Vars_ -{ - int32_t comp_csum; /* checksum computed over the ipv4 packet */ +typedef struct IPV4Vars_ { + int32_t comp_csum; /* checksum computed over the ipv4 packet */ uint16_t opt_cnt; uint16_t opts_set; } IPV4Vars; - void DecodeIPV4RegisterTests(void); /** ----- Inline functions ----- */ @@ -197,8 +185,7 @@ static inline uint16_t IPV4Checksum(const uint16_t *pkt, uint16_t hlen, uint16_t { uint32_t csum = init; - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + - pkt[8] + pkt[9]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + pkt[8] + pkt[9]; hlen -= 20; pkt += 10; @@ -212,35 +199,33 @@ static inline uint16_t IPV4Checksum(const uint16_t *pkt, uint16_t hlen, uint16_t } else if (hlen == 12) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5]; } else if (hlen == 16) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7]; } else if (hlen == 20) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9]; } else if (hlen == 24) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11]; } else if (hlen == 28) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13]; } else if (hlen == 32) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; } else if (hlen == 36) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15] + pkt[16] + pkt[17]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15] + pkt[16] + + pkt[17]; } else if (hlen == 40) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15] + pkt[16] + + pkt[17] + pkt[18] + pkt[19]; } csum = (csum >> 16) + (csum & 0x0000FFFF); csum += (csum >> 16); - return (uint16_t) ~csum; + return (uint16_t)~csum; } #endif /* __DECODE_IPV4_H__ */ diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index 4becd063380a..4eb5bf333819 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -34,14 +33,15 @@ #include "decode-ipv6.h" #include "decode.h" #include "defrag.h" -#include "util-print.h" -#include "util-validate.h" +#include "util/print.h" +#include "util/validate.h" /** * \brief Function to decode IPv4 in IPv6 packets * */ -static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t plen) +static void DecodeIPv4inIPv6( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t plen) { if (unlikely(plen < IPV4_HEADER_LEN)) { @@ -52,7 +52,7 @@ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, c Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV4); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); StatsIncr(tv, dtv->counter_ipv4inipv6); return; } @@ -66,8 +66,8 @@ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, c * \brief Function to decode IPv6 in IPv6 packets * */ -static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t plen) +static int DecodeIP6inIP6( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t plen) { if (unlikely(plen < IPV6_HEADER_LEN)) { @@ -78,7 +78,7 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV6); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); StatsIncr(tv, dtv->counter_ipv6inipv6); } } else { @@ -90,26 +90,24 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, #ifndef UNITTESTS // ugly, but we need this in defrag tests static inline #endif -void DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt, - uint16_t hdrextlen, uint16_t plen, - uint16_t prev_hdrextlen) + void + DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt, uint16_t hdrextlen, uint16_t plen, + uint16_t prev_hdrextlen) { uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8; - int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; + int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; p->ip6eh.fh_offset = frag_offset; p->ip6eh.fh_more_frags_set = frag_morefrags ? true : false; p->ip6eh.fh_nh = *pkt; uint32_t fh_id; - memcpy(&fh_id, pkt+4, 4); + memcpy(&fh_id, pkt + 4, 4); p->ip6eh.fh_id = SCNtohl(fh_id); - SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", - p->ip6eh.fh_offset, - p->ip6eh.fh_more_frags_set ? "true" : "false", - p->ip6eh.fh_nh, - p->ip6eh.fh_id, p->ip6eh.fh_id); + SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", p->ip6eh.fh_offset, + p->ip6eh.fh_more_frags_set ? "true" : "false", p->ip6eh.fh_nh, p->ip6eh.fh_id, + p->ip6eh.fh_id); // store header offset, data offset uint16_t frag_hdr_offset = (uint16_t)(pkt - GET_PKT_DATA(p)); @@ -126,13 +124,11 @@ void DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt, } SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u", - p->ip6eh.fh_header_offset, p->ip6eh.fh_data_offset, - p->ip6eh.fh_data_len); + p->ip6eh.fh_header_offset, p->ip6eh.fh_data_offset, p->ip6eh.fh_data_len); } -static void -DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t len) +static void DecodeIPV6ExtHdrs( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) { SCEnter(); @@ -146,8 +142,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, int rh = 0; int ah = 0; - while(1) - { + while (1) { IPV6_SET_EXTHDRS_LEN(p, (len - plen)); if (nh == IPPROTO_NONE) { @@ -163,33 +158,32 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCReturn; } - switch(nh) - { + switch (nh) { case IPPROTO_TCP: - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); DecodeTCP(tv, dtv, p, pkt, plen); SCReturn; case IPPROTO_UDP: - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); DecodeUDP(tv, dtv, p, pkt, plen); SCReturn; case IPPROTO_ICMPV6: - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); DecodeICMPV6(tv, dtv, p, pkt, plen); SCReturn; case IPPROTO_SCTP: - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); DecodeSCTP(tv, dtv, p, pkt, plen); SCReturn; case IPPROTO_ROUTING: - IPV6_SET_L4PROTO(p,nh); - hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ + IPV6_SET_L4PROTO(p, nh); + hdrextlen = 8 + (*(pkt + 1) * 8); /* 8 bytes + length in 8 octet units */ - SCLogDebug("hdrextlen %"PRIu16, hdrextlen); + SCLogDebug("hdrextlen %" PRIu16, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR); @@ -221,14 +215,13 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: - { + case IPPROTO_DSTOPTS: { IPV6OptHAO hao_s, *hao = &hao_s; IPV6OptRA ra_s, *ra = &ra_s; IPV6OptJumbo jumbo_s, *jumbo = &jumbo_s; uint16_t optslen = 0; - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); hdrextlen = (uint16_t)((*(pkt + 1) + 1) << 3); if (hdrextlen > plen) { ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR); @@ -253,9 +246,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, hh = 1; optslen = (uint16_t)((*(pkt + 1) + 1) << 3) - 2; - } - else if (nh == IPPROTO_DSTOPTS) - { + } else if (nh == IPPROTO_DSTOPTS) { if (dstopts == 0) { optslen = (uint16_t)((*(pkt + 1) + 1) << 3) - 2; dstopts = 1; @@ -284,14 +275,12 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, plen -= hdrextlen; break; } -/** \todo move into own function to loaded on demand */ + /** \todo move into own function to loaded on demand */ uint16_t padn_cnt = 0; uint16_t other_cnt = 0; uint16_t offset = 0; - while(offset < optslen) - { - if (*ptr == IPV6OPT_PAD1) - { + while (offset < optslen) { + if (*ptr == IPV6OPT_PAD1) { padn_cnt++; offset++; ptr++; @@ -314,17 +303,16 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, if (*ptr == IPV6OPT_PADN) /* PadN */ { - //printf("PadN option\n"); + // printf("PadN option\n"); padn_cnt++; /* a zero padN len would be weird */ if (ip6_optlen == 0) ENGINE_SET_EVENT(p, IPV6_EXTHDR_ZERO_LEN_PADN); - } - else if (*ptr == IPV6OPT_RA) /* RA */ + } else if (*ptr == IPV6OPT_RA) /* RA */ { ra->ip6ra_type = *(ptr); - ra->ip6ra_len = ip6_optlen; + ra->ip6ra_len = ip6_optlen; if (ip6_optlen < sizeof(ra->ip6ra_value)) { ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); @@ -333,42 +321,42 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, memcpy(&ra->ip6ra_value, (ptr + 2), sizeof(ra->ip6ra_value)); ra->ip6ra_value = SCNtohs(ra->ip6ra_value); - //printf("RA option: type %" PRIu32 " len %" PRIu32 " value %" PRIu32 "\n", - // ra->ip6ra_type, ra->ip6ra_len, ra->ip6ra_value); + // printf("RA option: type %" PRIu32 " len %" PRIu32 " value %" PRIu32 "\n", + // ra->ip6ra_type, ra->ip6ra_len, ra->ip6ra_value); other_cnt++; - } - else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */ + } else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */ { jumbo->ip6j_type = *(ptr); - jumbo->ip6j_len = ip6_optlen; + jumbo->ip6j_len = ip6_optlen; if (ip6_optlen < sizeof(jumbo->ip6j_payload_len)) { ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } - memcpy(&jumbo->ip6j_payload_len, (ptr+2), sizeof(jumbo->ip6j_payload_len)); + memcpy(&jumbo->ip6j_payload_len, (ptr + 2), + sizeof(jumbo->ip6j_payload_len)); jumbo->ip6j_payload_len = SCNtohl(jumbo->ip6j_payload_len); - //printf("Jumbo option: type %" PRIu32 " len %" PRIu32 " payload len %" PRIu32 "\n", - // jumbo->ip6j_type, jumbo->ip6j_len, jumbo->ip6j_payload_len); - } - else if (*ptr == IPV6OPT_HAO) /* HAO */ + // printf("Jumbo option: type %" PRIu32 " len %" PRIu32 " payload len %" + // PRIu32 "\n", + // jumbo->ip6j_type, jumbo->ip6j_len, jumbo->ip6j_payload_len); + } else if (*ptr == IPV6OPT_HAO) /* HAO */ { hao->ip6hao_type = *(ptr); - hao->ip6hao_len = ip6_optlen; + hao->ip6hao_len = ip6_optlen; if (ip6_optlen < sizeof(hao->ip6hao_hoa)) { ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } - memcpy(&hao->ip6hao_hoa, (ptr+2), sizeof(hao->ip6hao_hoa)); - //printf("HAO option: type %" PRIu32 " len %" PRIu32 " ", - // hao->ip6hao_type, hao->ip6hao_len); - //char addr_buf[46]; - //PrintInet(AF_INET6, (char *)&(hao->ip6hao_hoa), - // addr_buf,sizeof(addr_buf)); - //printf("home addr %s\n", addr_buf); + memcpy(&hao->ip6hao_hoa, (ptr + 2), sizeof(hao->ip6hao_hoa)); + // printf("HAO option: type %" PRIu32 " len %" PRIu32 " ", + // hao->ip6hao_type, hao->ip6hao_len); + // char addr_buf[46]; + // PrintInet(AF_INET6, (char *)&(hao->ip6hao_hoa), + // addr_buf,sizeof(addr_buf)); + // printf("home addr %s\n", addr_buf); other_cnt++; } else { if (nh == IPPROTO_HOPOPTS) @@ -396,9 +384,8 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; } - case IPPROTO_FRAGMENT: - { - IPV6_SET_L4PROTO(p,nh); + case IPPROTO_FRAGMENT: { + IPV6_SET_L4PROTO(p, nh); /* store the offset of this extension into the packet * past the ipv6 header. We use it in defrag for creating * a defragmented packet without the frag header */ @@ -458,23 +445,21 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, p->flags |= PKT_IS_FRAGMENT; SCReturn; } - case IPPROTO_ESP: - { - IPV6_SET_L4PROTO(p,nh); + case IPPROTO_ESP: { + IPV6_SET_L4PROTO(p, nh); DecodeESP(tv, dtv, p, pkt, plen); SCReturn; } - case IPPROTO_AH: - { - IPV6_SET_L4PROTO(p,nh); + case IPPROTO_AH: { + IPV6_SET_L4PROTO(p, nh); /* we need the header as a minimum */ hdrextlen = sizeof(IPV6AuthHdr); /* the payload len field is the number of extra 4 byte fields, * IPV6AuthHdr already contains the first */ - if (*(pkt+1) > 0) - hdrextlen += ((*(pkt+1) - 1) * 4); + if (*(pkt + 1) > 0) + hdrextlen += ((*(pkt + 1) - 1) * 4); - SCLogDebug("hdrextlen %"PRIu16, hdrextlen); + SCLogDebug("hdrextlen %" PRIu16, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR); @@ -502,21 +487,21 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; } case IPPROTO_IPIP: - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); DecodeIPv4inIPv6(tv, dtv, p, pkt, plen); SCReturn; /* none, last header */ case IPPROTO_NONE: - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); SCReturn; case IPPROTO_ICMP: - ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); + ENGINE_SET_EVENT(p, IPV6_WITH_ICMPV4); SCReturn; /* no parsing yet, just skip it */ case IPPROTO_MH: case IPPROTO_HIP: case IPPROTO_SHIM6: - hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ + hdrextlen = 8 + (*(pkt + 1) * 8); /* 8 bytes + length in 8 octet units */ if (hdrextlen > plen) { ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; @@ -527,7 +512,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; default: ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER); - IPV6_SET_L4PROTO(p,nh); + IPV6_SET_L4PROTO(p, nh); SCReturn; } } @@ -535,28 +520,28 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCReturn; } -static int DecodeIPV6Packet (ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) +static int DecodeIPV6Packet( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) { if (unlikely(len < IPV6_HEADER_LEN)) { return -1; } if (unlikely(IP_GET_RAW_VER(pkt) != 6)) { - SCLogDebug("wrong ip version %d",IP_GET_RAW_VER(pkt)); + SCLogDebug("wrong ip version %d", IP_GET_RAW_VER(pkt)); ENGINE_SET_INVALID_EVENT(p, IPV6_WRONG_IP_VER); return -1; } p->ip6h = (IPV6Hdr *)pkt; - if (unlikely(len < (IPV6_HEADER_LEN + IPV6_GET_PLEN(p)))) - { + if (unlikely(len < (IPV6_HEADER_LEN + IPV6_GET_PLEN(p)))) { ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_PKT); return -1; } - SET_IPV6_SRC_ADDR(p,&p->src); - SET_IPV6_DST_ADDR(p,&p->dst); + SET_IPV6_SRC_ADDR(p, &p->src); + SET_IPV6_DST_ADDR(p, &p->dst); return 0; } @@ -569,7 +554,7 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t * return TM_ECODE_FAILED; } /* do the actual decoding */ - int ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); + int ret = DecodeIPV6Packet(tv, dtv, p, pkt, len); if (unlikely(ret < 0)) { CLEAR_IPV6_PACKET(p); return TM_ECODE_FAILED; @@ -582,28 +567,29 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t * char s[46], d[46]; PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), s, sizeof(s)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), d, sizeof(d)); - SCLogDebug("IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: %" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32 "", s,d, - IPV6_GET_CLASS(p), IPV6_GET_FLOW(p), IPV6_GET_NH(p), IPV6_GET_PLEN(p), + SCLogDebug("IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: %" PRIu32 " NH: %" PRIu32 + " PLEN: %" PRIu32 " HLIM: %" PRIu32 "", + s, d, IPV6_GET_CLASS(p), IPV6_GET_FLOW(p), IPV6_GET_NH(p), IPV6_GET_PLEN(p), IPV6_GET_HLIM(p)); } #endif /* DEBUG */ /* now process the Ext headers and/or the L4 Layer */ - switch(IPV6_GET_NH(p)) { + switch (IPV6_GET_NH(p)) { case IPPROTO_TCP: - IPV6_SET_L4PROTO (p, IPPROTO_TCP); + IPV6_SET_L4PROTO(p, IPPROTO_TCP); DecodeTCP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p)); return TM_ECODE_OK; case IPPROTO_UDP: - IPV6_SET_L4PROTO (p, IPPROTO_UDP); + IPV6_SET_L4PROTO(p, IPPROTO_UDP); DecodeUDP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p)); return TM_ECODE_OK; case IPPROTO_ICMPV6: - IPV6_SET_L4PROTO (p, IPPROTO_ICMPV6); + IPV6_SET_L4PROTO(p, IPPROTO_ICMPV6); DecodeICMPV6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p)); return TM_ECODE_OK; case IPPROTO_SCTP: - IPV6_SET_L4PROTO (p, IPPROTO_SCTP); + IPV6_SET_L4PROTO(p, IPPROTO_SCTP); DecodeSCTP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p)); return TM_ECODE_OK; case IPPROTO_IPIP: @@ -630,20 +616,20 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t * DecodeIPV6ExtHdrs(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p)); break; case IPPROTO_ICMP: - ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); + ENGINE_SET_EVENT(p, IPV6_WITH_ICMPV4); break; default: ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER); - IPV6_SET_L4PROTO (p, IPV6_GET_NH(p)); + IPV6_SET_L4PROTO(p, IPV6_GET_NH(p)); break; } - p->proto = IPV6_GET_L4PROTO (p); + p->proto = IPV6_GET_L4PROTO(p); /* Pass to defragger if a fragment. */ if (IPV6_EXTHDR_ISSET_FH(p)) { Packet *rp = Defrag(tv, dtv, p); if (rp != NULL) { - PacketEnqueueNoLock(&tv->decode_pq,rp); + PacketEnqueueNoLock(&tv->decode_pq, rp); } } @@ -651,15 +637,16 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t * } #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "packet.h" /** * \test fragment decoding */ -static int DecodeIPV6FragTest01 (void) +static int DecodeIPV6FragTest01(void) { + // clang-format off uint8_t raw_frag1[] = { 0x60, 0x0f, 0x1a, 0xcf, 0x05, 0xa8, 0x2c, 0x36, 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x09, 0x80, 0x32, 0xb2, 0x00, 0x01, @@ -755,6 +742,8 @@ static int DecodeIPV6FragTest01 (void) 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, }; + // clang-format on + // clang-format off uint8_t raw_frag2[] = { 0x60, 0x0f, 0x1a, 0xcf, 0x00, 0x1c, 0x2c, 0x36, 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x09, 0x80, 0x32, 0xb2, 0x00, 0x01, @@ -762,6 +751,7 @@ static int DecodeIPV6FragTest01 (void) 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, }; + // clang-format on Packet *pkt; Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -823,8 +813,9 @@ static int DecodeIPV6FragTest01 (void) /** * \test routing header decode */ -static int DecodeIPV6RouteTest01 (void) +static int DecodeIPV6RouteTest01(void) { + // clang-format off uint8_t raw_pkt1[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x2b, 0x40, 0x20, 0x01, 0xaa, 0xaa, 0x00, 0x01, 0x00, 0x00, @@ -837,6 +828,7 @@ static int DecodeIPV6RouteTest01 (void) 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x20, 0x00, 0xfa, 0x87, 0x00, 0x00, }; + // clang-format on Packet *p1 = PacketGetFromAlloc(); FAIL_IF(unlikely(p1 == NULL)); ThreadVars tv; @@ -851,8 +843,8 @@ static int DecodeIPV6RouteTest01 (void) DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1)); - FAIL_IF (!(IPV6_EXTHDR_ISSET_RH(p1))); - FAIL_IF (p1->ip6eh.rh_type != 0); + FAIL_IF(!(IPV6_EXTHDR_ISSET_RH(p1))); + FAIL_IF(p1->ip6eh.rh_type != 0); PacketRecycle(p1); SCFree(p1); FlowShutdown(); @@ -862,14 +854,16 @@ static int DecodeIPV6RouteTest01 (void) /** * \test HOP header decode */ -static int DecodeIPV6HopTest01 (void) +static int DecodeIPV6HopTest01(void) { + // clang-format off uint8_t raw_pkt1[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xfe, 0xff, 0xfe, 0x98, 0x3d, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x00, 0xff, /* 0xff is a nonsense opt */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x1c, 0x6f, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p1 = PacketGetFromAlloc(); FAIL_IF(unlikely(p1 == NULL)); ThreadVars tv; @@ -884,7 +878,7 @@ static int DecodeIPV6HopTest01 (void) DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1)); - FAIL_IF (!(ENGINE_ISSET_EVENT(p1, IPV6_HOPOPTS_UNKNOWN_OPT))); + FAIL_IF(!(ENGINE_ISSET_EVENT(p1, IPV6_HOPOPTS_UNKNOWN_OPT))); PacketRecycle(p1); SCFree(p1); diff --git a/src/decode-ipv6.h b/src/decode-ipv6.h index 651939ae567f..23f355aff417 100644 --- a/src/decode-ipv6.h +++ b/src/decode-ipv6.h @@ -24,20 +24,19 @@ #ifndef __DECODE_IPV6_H__ #define __DECODE_IPV6_H__ -#define IPV6_HEADER_LEN 40 -#define IPV6_MAXPACKET 65535 /* maximum packet size */ -#define IPV6_MAX_OPT 40 +#define IPV6_HEADER_LEN 40 +#define IPV6_MAXPACKET 65535 /* maximum packet size */ +#define IPV6_MAX_OPT 40 -typedef struct IPV6Hdr_ -{ +typedef struct IPV6Hdr_ { union { struct ip6_un1_ { uint32_t ip6_un1_flow; /* 20 bits of flow-ID */ uint16_t ip6_un1_plen; /* payload length */ - uint8_t ip6_un1_nxt; /* next header */ - uint8_t ip6_un1_hlim; /* hop limit */ + uint8_t ip6_un1_nxt; /* next header */ + uint8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; - uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ + uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_hdrun; union { @@ -49,170 +48,150 @@ typedef struct IPV6Hdr_ } ip6_hdrun2; } IPV6Hdr; -#define s_ip6_src ip6_hdrun2.ip6_un2.ip6_src -#define s_ip6_dst ip6_hdrun2.ip6_un2.ip6_dst -#define s_ip6_addrs ip6_hdrun2.ip6_addrs +#define s_ip6_src ip6_hdrun2.ip6_un2.ip6_src +#define s_ip6_dst ip6_hdrun2.ip6_un2.ip6_dst +#define s_ip6_addrs ip6_hdrun2.ip6_addrs -#define s_ip6_vfc ip6_hdrun.ip6_un2_vfc -#define s_ip6_flow ip6_hdrun.ip6_un1.ip6_un1_flow -#define s_ip6_plen ip6_hdrun.ip6_un1.ip6_un1_plen -#define s_ip6_nxt ip6_hdrun.ip6_un1.ip6_un1_nxt -#define s_ip6_hlim ip6_hdrun.ip6_un1.ip6_un1_hlim +#define s_ip6_vfc ip6_hdrun.ip6_un2_vfc +#define s_ip6_flow ip6_hdrun.ip6_un1.ip6_un1_flow +#define s_ip6_plen ip6_hdrun.ip6_un1.ip6_un1_plen +#define s_ip6_nxt ip6_hdrun.ip6_un1.ip6_un1_nxt +#define s_ip6_hlim ip6_hdrun.ip6_un1.ip6_un1_hlim -#define IPV6_GET_RAW_VER(ip6h) (((ip6h)->s_ip6_vfc & 0xf0) >> 4) -#define IPV6_GET_RAW_CLASS(ip6h) ((SCNtohl((ip6h)->s_ip6_flow) & 0x0FF00000) >> 20) -#define IPV6_GET_RAW_FLOW(ip6h) (SCNtohl((ip6h)->s_ip6_flow) & 0x000FFFFF) -#define IPV6_GET_RAW_NH(ip6h) ((ip6h)->s_ip6_nxt) -#define IPV6_GET_RAW_PLEN(ip6h) (SCNtohs((ip6h)->s_ip6_plen)) -#define IPV6_GET_RAW_HLIM(ip6h) ((ip6h)->s_ip6_hlim) +#define IPV6_GET_RAW_VER(ip6h) (((ip6h)->s_ip6_vfc & 0xf0) >> 4) +#define IPV6_GET_RAW_CLASS(ip6h) ((SCNtohl((ip6h)->s_ip6_flow) & 0x0FF00000) >> 20) +#define IPV6_GET_RAW_FLOW(ip6h) (SCNtohl((ip6h)->s_ip6_flow) & 0x000FFFFF) +#define IPV6_GET_RAW_NH(ip6h) ((ip6h)->s_ip6_nxt) +#define IPV6_GET_RAW_PLEN(ip6h) (SCNtohs((ip6h)->s_ip6_plen)) +#define IPV6_GET_RAW_HLIM(ip6h) ((ip6h)->s_ip6_hlim) -#define IPV6_SET_RAW_VER(ip6h, value) ((ip6h)->s_ip6_vfc = (((ip6h)->s_ip6_vfc & 0x0f) | (value << 4))) -#define IPV6_SET_RAW_NH(ip6h, value) ((ip6h)->s_ip6_nxt = (value)) - -#define IPV6_SET_L4PROTO(p,proto) (p)->ip6vars.l4proto = (proto) -#define IPV6_SET_EXTHDRS_LEN(p,len) (p)->ip6vars.exthdrs_len = (len) +#define IPV6_SET_RAW_VER(ip6h, value) \ + ((ip6h)->s_ip6_vfc = (((ip6h)->s_ip6_vfc & 0x0f) | (value << 4))) +#define IPV6_SET_RAW_NH(ip6h, value) ((ip6h)->s_ip6_nxt = (value)) +#define IPV6_SET_L4PROTO(p, proto) (p)->ip6vars.l4proto = (proto) +#define IPV6_SET_EXTHDRS_LEN(p, len) (p)->ip6vars.exthdrs_len = (len) /* ONLY call these functions after making sure that: * 1. p->ip6h is set * 2. p->ip6h is valid (len is correct) */ -#define IPV6_GET_VER(p) \ - IPV6_GET_RAW_VER((p)->ip6h) -#define IPV6_GET_CLASS(p) \ - IPV6_GET_RAW_CLASS((p)->ip6h) -#define IPV6_GET_FLOW(p) \ - IPV6_GET_RAW_FLOW((p)->ip6h) -#define IPV6_GET_NH(p) \ - (IPV6_GET_RAW_NH((p)->ip6h)) -#define IPV6_GET_PLEN(p) \ - IPV6_GET_RAW_PLEN((p)->ip6h) -#define IPV6_GET_HLIM(p) \ - (IPV6_GET_RAW_HLIM((p)->ip6h)) - -#define IPV6_GET_L4PROTO(p) \ - ((p)->ip6vars.l4proto) -#define IPV6_GET_EXTHDRS_LEN(p) \ - ((p)->ip6vars.exthdrs_len) +#define IPV6_GET_VER(p) IPV6_GET_RAW_VER((p)->ip6h) +#define IPV6_GET_CLASS(p) IPV6_GET_RAW_CLASS((p)->ip6h) +#define IPV6_GET_FLOW(p) IPV6_GET_RAW_FLOW((p)->ip6h) +#define IPV6_GET_NH(p) (IPV6_GET_RAW_NH((p)->ip6h)) +#define IPV6_GET_PLEN(p) IPV6_GET_RAW_PLEN((p)->ip6h) +#define IPV6_GET_HLIM(p) (IPV6_GET_RAW_HLIM((p)->ip6h)) + +#define IPV6_GET_L4PROTO(p) ((p)->ip6vars.l4proto) +#define IPV6_GET_EXTHDRS_LEN(p) ((p)->ip6vars.exthdrs_len) /** \brief get the highest proto/next header field we know */ -//#define IPV6_GET_UPPER_PROTO(p) (p)->ip6eh.ip6_exthdrs_cnt ? -// (p)->ip6eh.ip6_exthdrs[(p)->ip6eh.ip6_exthdrs_cnt - 1].next : IPV6_GET_NH((p)) +// #define IPV6_GET_UPPER_PROTO(p) (p)->ip6eh.ip6_exthdrs_cnt ? +// (p)->ip6eh.ip6_exthdrs[(p)->ip6eh.ip6_exthdrs_cnt - 1].next : IPV6_GET_NH((p)) /* helper structure with parsed ipv6 info */ -typedef struct IPV6Vars_ -{ - uint8_t l4proto; /**< the proto after the extension headers - * store while decoding so we don't have - * to loop through the exthdrs all the time */ - uint16_t exthdrs_len; /**< length of the exthdrs */ +typedef struct IPV6Vars_ { + uint8_t l4proto; /**< the proto after the extension headers + * store while decoding so we don't have + * to loop through the exthdrs all the time */ + uint16_t exthdrs_len; /**< length of the exthdrs */ } IPV6Vars; -#define CLEAR_IPV6_PACKET(p) do { \ - (p)->ip6h = NULL; \ - (p)->ip6vars.l4proto = 0; \ - (p)->ip6vars.exthdrs_len = 0; \ - memset(&(p)->ip6eh, 0x00, sizeof((p)->ip6eh)); \ -} while (0) +#define CLEAR_IPV6_PACKET(p) \ + do { \ + (p)->ip6h = NULL; \ + (p)->ip6vars.l4proto = 0; \ + (p)->ip6vars.exthdrs_len = 0; \ + memset(&(p)->ip6eh, 0x00, sizeof((p)->ip6eh)); \ + } while (0) /* Fragment header */ -typedef struct IPV6FragHdr_ -{ - uint8_t ip6fh_nxt; /* next header */ - uint8_t ip6fh_reserved; /* reserved field */ - uint16_t ip6fh_offlg; /* offset, reserved, and flag */ - uint32_t ip6fh_ident; /* identification */ +typedef struct IPV6FragHdr_ { + uint8_t ip6fh_nxt; /* next header */ + uint8_t ip6fh_reserved; /* reserved field */ + uint16_t ip6fh_offlg; /* offset, reserved, and flag */ + uint32_t ip6fh_ident; /* identification */ } __attribute__((__packed__)) IPV6FragHdr; -#define IPV6_EXTHDR_GET_FH_NH(p) (p)->ip6eh.fh_nh -#define IPV6_EXTHDR_GET_FH_OFFSET(p) (p)->ip6eh.fh_offset -#define IPV6_EXTHDR_GET_FH_FLAG(p) (p)->ip6eh.fh_more_frags_set -#define IPV6_EXTHDR_GET_FH_ID(p) (p)->ip6eh.fh_id +#define IPV6_EXTHDR_GET_FH_NH(p) (p)->ip6eh.fh_nh +#define IPV6_EXTHDR_GET_FH_OFFSET(p) (p)->ip6eh.fh_offset +#define IPV6_EXTHDR_GET_FH_FLAG(p) (p)->ip6eh.fh_more_frags_set +#define IPV6_EXTHDR_GET_FH_ID(p) (p)->ip6eh.fh_id /* rfc 1826 */ -typedef struct IPV6AuthHdr_ -{ - uint8_t ip6ah_nxt; /* next header */ - uint8_t ip6ah_len; /* header length in units of 8 bytes, not - including first 8 bytes. */ - uint16_t ip6ah_reserved; /* reserved for future use */ - uint32_t ip6ah_spi; /* SECURITY PARAMETERS INDEX (SPI) */ - uint32_t ip6ah_seq; /* sequence number */ +typedef struct IPV6AuthHdr_ { + uint8_t ip6ah_nxt; /* next header */ + uint8_t ip6ah_len; /* header length in units of 8 bytes, not + including first 8 bytes. */ + uint16_t ip6ah_reserved; /* reserved for future use */ + uint32_t ip6ah_spi; /* SECURITY PARAMETERS INDEX (SPI) */ + uint32_t ip6ah_seq; /* sequence number */ } __attribute__((__packed__)) IPV6AuthHdr; -typedef struct IPV6EspHdr_ -{ - uint32_t ip6esph_spi; /* SECURITY PARAMETERS INDEX (SPI) */ - uint32_t ip6esph_seq; /* sequence number */ +typedef struct IPV6EspHdr_ { + uint32_t ip6esph_spi; /* SECURITY PARAMETERS INDEX (SPI) */ + uint32_t ip6esph_seq; /* sequence number */ } __attribute__((__packed__)) IPV6EspHdr; -typedef struct IPV6RouteHdr_ -{ - uint8_t ip6rh_nxt; /* next header */ - uint8_t ip6rh_len; /* header length in units of 8 bytes, not - including first 8 bytes. */ - uint8_t ip6rh_type; /* routing type */ - uint8_t ip6rh_segsleft; /* segments left */ +typedef struct IPV6RouteHdr_ { + uint8_t ip6rh_nxt; /* next header */ + uint8_t ip6rh_len; /* header length in units of 8 bytes, not + including first 8 bytes. */ + uint8_t ip6rh_type; /* routing type */ + uint8_t ip6rh_segsleft; /* segments left */ } __attribute__((__packed__)) IPV6RouteHdr; - /* Hop-by-Hop header and Destination Options header use options that are * defined here. */ -#define IPV6OPT_PAD1 0x00 -#define IPV6OPT_PADN 0x01 -#define IPV6OPT_RA 0x05 -#define IPV6OPT_JUMBO 0xC2 -#define IPV6OPT_HAO 0xC9 +#define IPV6OPT_PAD1 0x00 +#define IPV6OPT_PADN 0x01 +#define IPV6OPT_RA 0x05 +#define IPV6OPT_JUMBO 0xC2 +#define IPV6OPT_HAO 0xC9 /* Home Address Option */ -typedef struct IPV6OptHAO_ -{ - uint8_t ip6hao_type; /* Option type */ - uint8_t ip6hao_len; /* Option Data len (excludes type and len) */ - struct in6_addr ip6hao_hoa; /* Home address. */ +typedef struct IPV6OptHAO_ { + uint8_t ip6hao_type; /* Option type */ + uint8_t ip6hao_len; /* Option Data len (excludes type and len) */ + struct in6_addr ip6hao_hoa; /* Home address. */ } IPV6OptHAO; /* Router Alert Option */ -typedef struct IPV6OptRA_ -{ - uint8_t ip6ra_type; /* Option type */ - uint8_t ip6ra_len; /* Option Data len (excludes type and len) */ - uint16_t ip6ra_value; /* Router Alert value */ +typedef struct IPV6OptRA_ { + uint8_t ip6ra_type; /* Option type */ + uint8_t ip6ra_len; /* Option Data len (excludes type and len) */ + uint16_t ip6ra_value; /* Router Alert value */ } IPV6OptRA; /* Jumbo Option */ -typedef struct IPV6OptJumbo_ -{ - uint8_t ip6j_type; /* Option type */ - uint8_t ip6j_len; /* Option Data len (excludes type and len) */ - uint32_t ip6j_payload_len; /* Jumbo Payload Length */ +typedef struct IPV6OptJumbo_ { + uint8_t ip6j_type; /* Option type */ + uint8_t ip6j_len; /* Option Data len (excludes type and len) */ + uint32_t ip6j_payload_len; /* Jumbo Payload Length */ } IPV6OptJumbo; -typedef struct IPV6HopOptsHdr_ -{ - uint8_t ip6hh_nxt; /* next header */ - uint8_t ip6hh_len; /* header length in units of 8 bytes, not - including first 8 bytes. */ +typedef struct IPV6HopOptsHdr_ { + uint8_t ip6hh_nxt; /* next header */ + uint8_t ip6hh_len; /* header length in units of 8 bytes, not + including first 8 bytes. */ } __attribute__((__packed__)) IPV6HopOptsHdr; -typedef struct IPV6DstOptsHdr_ -{ - uint8_t ip6dh_nxt; /* next header */ - uint8_t ip6dh_len; /* header length in units of 8 bytes, not - including first 8 bytes. */ +typedef struct IPV6DstOptsHdr_ { + uint8_t ip6dh_nxt; /* next header */ + uint8_t ip6dh_len; /* header length in units of 8 bytes, not + including first 8 bytes. */ } __attribute__((__packed__)) IPV6DstOptsHdr; -typedef struct IPV6GenOptHdr_ -{ +typedef struct IPV6GenOptHdr_ { uint8_t type; uint8_t next; uint8_t len; uint8_t *data; -} IPV6GenOptHdr; +} IPV6GenOptHdr; -typedef struct IPV6ExtHdrs_ -{ +typedef struct IPV6ExtHdrs_ { bool rh_set; uint8_t rh_type; @@ -235,10 +214,10 @@ typedef struct IPV6ExtHdrs_ } IPV6ExtHdrs; -#define IPV6_EXTHDR_SET_FH(p) (p)->ip6eh.fh_set = true -#define IPV6_EXTHDR_ISSET_FH(p) (p)->ip6eh.fh_set -#define IPV6_EXTHDR_SET_RH(p) (p)->ip6eh.rh_set = true -#define IPV6_EXTHDR_ISSET_RH(p) (p)->ip6eh.rh_set +#define IPV6_EXTHDR_SET_FH(p) (p)->ip6eh.fh_set = true +#define IPV6_EXTHDR_ISSET_FH(p) (p)->ip6eh.fh_set +#define IPV6_EXTHDR_SET_RH(p) (p)->ip6eh.rh_set = true +#define IPV6_EXTHDR_ISSET_RH(p) (p)->ip6eh.rh_set void DecodeIPV6RegisterTests(void); diff --git a/src/decode-mpls.c b/src/decode-mpls.c index 09b7c14b1d03..e0999bd8b2ee 100644 --- a/src/decode-mpls.c +++ b/src/decode-mpls.c @@ -26,8 +26,8 @@ #include "suricata-common.h" #include "decode.h" -#include "util-validate.h" -#include "util-unittest.h" +#include "util/validate.h" +#include "util/unittest.h" #define MPLS_HEADER_LEN 4 #define MPLS_PW_LEN 4 @@ -38,16 +38,15 @@ #define MPLS_LABEL_IPV6 2 #define MPLS_LABEL_NULL 3 -#define MPLS_LABEL(shim) SCNtohl(shim) >> 12 -#define MPLS_BOTTOM(shim) ((SCNtohl(shim) >> 8) & 0x1) +#define MPLS_LABEL(shim) SCNtohl(shim) >> 12 +#define MPLS_BOTTOM(shim) ((SCNtohl(shim) >> 8) & 0x1) /* Inner protocol guessing values. */ -#define MPLS_PROTO_ETHERNET_PW 0 -#define MPLS_PROTO_IPV4 4 -#define MPLS_PROTO_IPV6 6 +#define MPLS_PROTO_ETHERNET_PW 0 +#define MPLS_PROTO_IPV4 4 +#define MPLS_PROTO_IPV6 6 -int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -76,22 +75,18 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, return TM_ECODE_FAILED; } return DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len); - } - else if (label == MPLS_LABEL_ROUTER_ALERT) { + } else if (label == MPLS_LABEL_ROUTER_ALERT) { /* Not valid at the bottom of the stack. */ event = MPLS_BAD_LABEL_ROUTER_ALERT; - } - else if (label == MPLS_LABEL_IPV6) { + } else if (label == MPLS_LABEL_IPV6) { if (len > USHRT_MAX) { return TM_ECODE_FAILED; } return DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len); - } - else if (label == MPLS_LABEL_NULL) { + } else if (label == MPLS_LABEL_NULL) { /* Shouldn't appear on the wire. */ event = MPLS_BAD_LABEL_IMPLICIT_NULL; - } - else if (label < MPLS_MAX_RESERVED_LABEL) { + } else if (label < MPLS_MAX_RESERVED_LABEL) { event = MPLS_BAD_LABEL_RESERVED; } @@ -108,24 +103,24 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /* Best guess at inner packet. */ switch (pkt[0] >> 4) { - case MPLS_PROTO_IPV4: - if (len > USHRT_MAX) { - return TM_ECODE_FAILED; - } - DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len); - break; - case MPLS_PROTO_IPV6: - if (len > USHRT_MAX) { - return TM_ECODE_FAILED; - } - DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len); - break; - case MPLS_PROTO_ETHERNET_PW: - DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN); - break; - default: - ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE); - return TM_ECODE_OK; + case MPLS_PROTO_IPV4: + if (len > USHRT_MAX) { + return TM_ECODE_FAILED; + } + DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len); + break; + case MPLS_PROTO_IPV6: + if (len > USHRT_MAX) { + return TM_ECODE_FAILED; + } + DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len); + break; + case MPLS_PROTO_ETHERNET_PW: + DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN); + break; + default: + ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE); + return TM_ECODE_OK; } end: @@ -140,16 +135,18 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, static int DecodeMPLSTestHeaderTooSmall(void) { /* A packet that is too small to have a complete MPLS header. */ + // clang-format off uint8_t pkt[] = { 0x00, 0x00, 0x11 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_HEADER_TOO_SMALL)); @@ -163,7 +160,7 @@ static int DecodeMPLSTestPacketTooSmall(void) ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -207,6 +204,7 @@ static int DecodeMPLSTestPacketTooSmall(void) static int DecodeMPLSTestBadLabelRouterAlert(void) { + // clang-format off uint8_t pkt[] = { 0x00, 0x00, 0x11, 0xff, 0x45, 0x00, 0x00, 0x64, 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, @@ -222,6 +220,7 @@ static int DecodeMPLSTestBadLabelRouterAlert(void) 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -229,7 +228,7 @@ static int DecodeMPLSTestBadLabelRouterAlert(void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_ROUTER_ALERT)); @@ -240,6 +239,7 @@ static int DecodeMPLSTestBadLabelRouterAlert(void) static int DecodeMPLSTestBadLabelImplicitNull(void) { + // clang-format off uint8_t pkt[] = { 0x00, 0x00, 0x31, 0xff, 0x45, 0x00, 0x00, 0x64, 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, @@ -255,13 +255,14 @@ static int DecodeMPLSTestBadLabelImplicitNull(void) 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_IMPLICIT_NULL)); @@ -272,6 +273,7 @@ static int DecodeMPLSTestBadLabelImplicitNull(void) static int DecodeMPLSTestBadLabelReserved(void) { + // clang-format off uint8_t pkt[] = { 0x00, 0x00, 0x51, 0xff, 0x45, 0x00, 0x00, 0x64, 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, @@ -287,13 +289,14 @@ static int DecodeMPLSTestBadLabelReserved(void) 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_RESERVED)); @@ -307,6 +310,7 @@ static int DecodeMPLSTestUnknownPayloadType(void) /* Valid label: 21. * Unknown payload type: 1. */ + // clang-format off uint8_t pkt[] = { 0x00, 0x01, 0x51, 0xff, 0x15, 0x00, 0x00, 0x64, 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, @@ -322,13 +326,14 @@ static int DecodeMPLSTestUnknownPayloadType(void) 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE)); @@ -342,17 +347,11 @@ static int DecodeMPLSTestUnknownPayloadType(void) void DecodeMPLSRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeMPLSTestHeaderTooSmall", - DecodeMPLSTestHeaderTooSmall); - UtRegisterTest("DecodeMPLSTestPacketTooSmall", - DecodeMPLSTestPacketTooSmall); - UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert", - DecodeMPLSTestBadLabelRouterAlert); - UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull", - DecodeMPLSTestBadLabelImplicitNull); - UtRegisterTest("DecodeMPLSTestBadLabelReserved", - DecodeMPLSTestBadLabelReserved); - UtRegisterTest("DecodeMPLSTestUnknownPayloadType", - DecodeMPLSTestUnknownPayloadType); + UtRegisterTest("DecodeMPLSTestHeaderTooSmall", DecodeMPLSTestHeaderTooSmall); + UtRegisterTest("DecodeMPLSTestPacketTooSmall", DecodeMPLSTestPacketTooSmall); + UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert", DecodeMPLSTestBadLabelRouterAlert); + UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull", DecodeMPLSTestBadLabelImplicitNull); + UtRegisterTest("DecodeMPLSTestBadLabelReserved", DecodeMPLSTestBadLabelReserved); + UtRegisterTest("DecodeMPLSTestUnknownPayloadType", DecodeMPLSTestUnknownPayloadType); #endif /* UNITTESTS */ } diff --git a/src/decode-nsh.c b/src/decode-nsh.c index 64a99ca580a7..cf8e97647803 100644 --- a/src/decode-nsh.c +++ b/src/decode-nsh.c @@ -35,9 +35,9 @@ #include "decode-events.h" #include "decode-nsh.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" /** * \brief Function to decode NSH packets @@ -130,11 +130,13 @@ int DecodeNSH(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p #ifdef UNITTESTS +// clang-format off static uint8_t valid_nsh_packet[] = { 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02, 0x45, 0x10, 0x00, 0x3c, 0x78, 0x8f, 0x40, 0x00, 0x3f, 0x06, 0x79, 0x05, 0x0b, 0x06, 0x06, 0x06, 0x33, 0x06, 0x06, 0x06, 0xbd, 0x2e, 0x00, 0x16, 0xc9, 0xee, 0x07, 0x62, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x2f, 0x36, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xa9, 0x5f, 0x7f, 0xed, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 }; +// clang-format on static int DecodeNSHTestHeaderTooSmall(void) { diff --git a/src/decode-nsh.h b/src/decode-nsh.h index a45cce3029e0..534c8f83e3e8 100644 --- a/src/decode-nsh.h +++ b/src/decode-nsh.h @@ -25,7 +25,6 @@ #ifndef __DECODE_NSH_H__ #define __DECODE_NSH_H__ - #define NSH_NEXT_PROTO_UNASSIGNED 0x0 #define NSH_NEXT_PROTO_IPV4 0x1 #define NSH_NEXT_PROTO_IPV6 0x2 diff --git a/src/decode-null.c b/src/decode-null.c index 5bf934045766..e6ae7724cb9d 100644 --- a/src/decode-null.c +++ b/src/decode-null.c @@ -35,9 +35,9 @@ #include "decode-raw.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" #define HDR_SIZE 4 @@ -48,8 +48,7 @@ #define AF_INET6_SOLARIS 26 #define AF_INET6_WINSOCK 23 -int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -68,7 +67,7 @@ int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, #else uint32_t type = *((uint32_t *)pkt); #endif - switch(type) { + switch (type) { case AF_INET: SCLogDebug("IPV4 Packet"); if (GET_PKT_LEN(p) - HDR_SIZE > USHRT_MAX) { diff --git a/src/decode-ppp.c b/src/decode-ppp.c index 5bf682bd2fc6..e992f231f813 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -37,12 +36,11 @@ #include "flow.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" -int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -58,14 +56,13 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, p->ppph = (PPPHdr *)pkt; - SCLogDebug("p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", - p, pkt, SCNtohs(p->ppph->protocol), len); + SCLogDebug("p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", p, pkt, SCNtohs(p->ppph->protocol), + len); - switch (SCNtohs(p->ppph->protocol)) - { + switch (SCNtohs(p->ppph->protocol)) { case PPP_VJ_UCOMP: if (unlikely(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN))) { - ENGINE_SET_INVALID_EVENT(p,PPPVJU_PKT_TOO_SMALL); + ENGINE_SET_INVALID_EVENT(p, PPPVJU_PKT_TOO_SMALL); p->ppph = NULL; return TM_ECODE_FAILED; } @@ -83,7 +80,7 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, case PPP_IP: if (unlikely(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN))) { - ENGINE_SET_INVALID_EVENT(p,PPPIPV4_PKT_TOO_SMALL); + ENGINE_SET_INVALID_EVENT(p, PPPIPV4_PKT_TOO_SMALL); p->ppph = NULL; return TM_ECODE_FAILED; } @@ -96,7 +93,7 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /* PPP IPv6 was not tested */ case PPP_IPV6: if (unlikely(len < (PPP_HEADER_LEN + IPV6_HEADER_LEN))) { - ENGINE_SET_INVALID_EVENT(p,PPPIPV6_PKT_TOO_SMALL); + ENGINE_SET_INVALID_EVENT(p, PPPIPV6_PKT_TOO_SMALL); p->ppph = NULL; return TM_ECODE_FAILED; } @@ -134,15 +131,14 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, case PPP_PAP: case PPP_LQM: case PPP_CHAP: - ENGINE_SET_EVENT(p,PPP_UNSUP_PROTO); + ENGINE_SET_EVENT(p, PPP_UNSUP_PROTO); return TM_ECODE_OK; default: - SCLogDebug("unknown PPP protocol: %" PRIx32 "",SCNtohs(p->ppph->protocol)); + SCLogDebug("unknown PPP protocol: %" PRIx32 "", SCNtohs(p->ppph->protocol)); ENGINE_SET_INVALID_EVENT(p, PPP_WRONG_TYPE); return TM_ECODE_OK; } - } /* TESTS BELOW */ @@ -152,7 +148,7 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, * Decode malformed ip layer PPP packet * Expected test value: 1 */ -static int DecodePPPtest01 (void) +static int DecodePPPtest01(void) { uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00 }; Packet *p = PacketGetFromAlloc(); @@ -168,7 +164,7 @@ static int DecodePPPtest01 (void) /* Function my returns here with expected value */ - if(ENGINE_ISSET_EVENT(p,PPPIPV4_PKT_TOO_SMALL)) { + if (ENGINE_ISSET_EVENT(p, PPPIPV4_PKT_TOO_SMALL)) { SCFree(p); return 1; } @@ -181,13 +177,15 @@ static int DecodePPPtest01 (void) * Decode malformed ppp layer packet * Expected test value: 1 */ -static int DecodePPPtest02 (void) +static int DecodePPPtest02(void) { + // clang-format off uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0xff, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -201,7 +199,7 @@ static int DecodePPPtest02 (void) /* Function must returns here */ - if(ENGINE_ISSET_EVENT(p,PPP_WRONG_TYPE)) { + if (ENGINE_ISSET_EVENT(p, PPP_WRONG_TYPE)) { SCFree(p); return 1; } @@ -216,13 +214,15 @@ static int DecodePPPtest02 (void) * \retval 0 Test failed * \retval 1 Test succeeded */ -static int DecodePPPtest03 (void) +static int DecodePPPtest03(void) { + // clang-format off uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -238,27 +238,27 @@ static int DecodePPPtest03 (void) FlowShutdown(); - if(p->ppph == NULL) { + if (p->ppph == NULL) { SCFree(p); return 0; } - if(ENGINE_ISSET_EVENT(p,PPP_PKT_TOO_SMALL)) { + if (ENGINE_ISSET_EVENT(p, PPP_PKT_TOO_SMALL)) { SCFree(p); return 0; } - if(ENGINE_ISSET_EVENT(p,PPPIPV4_PKT_TOO_SMALL)) { + if (ENGINE_ISSET_EVENT(p, PPPIPV4_PKT_TOO_SMALL)) { SCFree(p); return 0; } - if(ENGINE_ISSET_EVENT(p,PPP_WRONG_TYPE)) { + if (ENGINE_ISSET_EVENT(p, PPP_WRONG_TYPE)) { SCFree(p); return 0; } - if (!(ENGINE_ISSET_EVENT(p,IPV4_TRUNC_PKT))) { + if (!(ENGINE_ISSET_EVENT(p, IPV4_TRUNC_PKT))) { SCFree(p); return 0; } @@ -268,19 +268,20 @@ static int DecodePPPtest03 (void) return 1; } - /* DecodePPPtest04 * Check if ppp header is null * Expected test value: 1 */ -static int DecodePPPtest04 (void) +static int DecodePPPtest04(void) { + // clang-format off uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00, 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -296,12 +297,12 @@ static int DecodePPPtest04 (void) FlowShutdown(); - if(p->ppph == NULL) { + if (p->ppph == NULL) { SCFree(p); return 0; } - if (!(ENGINE_ISSET_EVENT(p,IPV4_TRUNC_PKT))) { + if (!(ENGINE_ISSET_EVENT(p, IPV4_TRUNC_PKT))) { SCFree(p); return 0; } diff --git a/src/decode-ppp.h b/src/decode-ppp.h index f8914cf2e77d..c40aef23bd6a 100644 --- a/src/decode-ppp.h +++ b/src/decode-ppp.h @@ -25,40 +25,40 @@ #define __DECODE_PPP_H__ /** Point to Point Protocol RFC1331 - Supported tyes */ -#define PPP_IP 0x0021 /* Internet Protocol */ -#define PPP_IPV6 0x0057 /* Internet Protocol version 6 */ -#define PPP_VJ_UCOMP 0x002f /* VJ uncompressed TCP/IP */ +#define PPP_IP 0x0021 /* Internet Protocol */ +#define PPP_IPV6 0x0057 /* Internet Protocol version 6 */ +#define PPP_VJ_UCOMP 0x002f /* VJ uncompressed TCP/IP */ /** Unsupported PPP types (libpcap source reference) */ -#define PPP_IPX 0x002b /* Novell IPX Protocol */ -#define PPP_VJ_COMP 0x002d /* VJ compressed TCP/IP */ -#define PPP_IPX 0x002b /* Novell IPX Protocol */ -#define PPP_OSI 0x0023 /* OSI Network Layer */ -#define PPP_NS 0x0025 /* Xerox NS IDP */ -#define PPP_DECNET 0x0027 /* DECnet Phase IV */ -#define PPP_APPLE 0x0029 /* Appletalk */ -#define PPP_BRPDU 0x0031 /* Bridging PDU */ -#define PPP_STII 0x0033 /* Stream Protocol (ST-II) */ -#define PPP_VINES 0x0035 /* Banyan Vines */ -#define PPP_HELLO 0x0201 /* 802.1d Hello Packets */ -#define PPP_LUXCOM 0x0231 /* Luxcom */ -#define PPP_SNS 0x0233 /* Sigma Network Systems */ -#define PPP_MPLS_UCAST 0x0281 /* rfc 3032 */ -#define PPP_MPLS_MCAST 0x0283 /* rfc 3022 */ -#define PPP_IPCP 0x8021 /* IP Control Protocol */ -#define PPP_OSICP 0x8023 /* OSI Network Layer Control Protocol */ -#define PPP_NSCP 0x8025 /* Xerox NS IDP Control Protocol */ -#define PPP_DECNETCP 0x8027 /* DECnet Control Protocol */ -#define PPP_APPLECP 0x8029 /* Appletalk Control Protocol */ -#define PPP_IPXCP 0x802b /* Novell IPX Control Protocol */ -#define PPP_STIICP 0x8033 /* Stream Protocol Control Protocol */ -#define PPP_VINESCP 0x8035 /* Banyan Vines Control Protocol */ -#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ -#define PPP_MPLSCP 0x8281 /* rfc 3022 */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_PAP 0xc023 /* Password Authentication Protocol */ -#define PPP_LQM 0xc025 /* Link Quality Monitoring */ -#define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */ +#define PPP_IPX 0x002b /* Novell IPX Protocol */ +#define PPP_VJ_COMP 0x002d /* VJ compressed TCP/IP */ +#define PPP_IPX 0x002b /* Novell IPX Protocol */ +#define PPP_OSI 0x0023 /* OSI Network Layer */ +#define PPP_NS 0x0025 /* Xerox NS IDP */ +#define PPP_DECNET 0x0027 /* DECnet Phase IV */ +#define PPP_APPLE 0x0029 /* Appletalk */ +#define PPP_BRPDU 0x0031 /* Bridging PDU */ +#define PPP_STII 0x0033 /* Stream Protocol (ST-II) */ +#define PPP_VINES 0x0035 /* Banyan Vines */ +#define PPP_HELLO 0x0201 /* 802.1d Hello Packets */ +#define PPP_LUXCOM 0x0231 /* Luxcom */ +#define PPP_SNS 0x0233 /* Sigma Network Systems */ +#define PPP_MPLS_UCAST 0x0281 /* rfc 3032 */ +#define PPP_MPLS_MCAST 0x0283 /* rfc 3022 */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_OSICP 0x8023 /* OSI Network Layer Control Protocol */ +#define PPP_NSCP 0x8025 /* Xerox NS IDP Control Protocol */ +#define PPP_DECNETCP 0x8027 /* DECnet Control Protocol */ +#define PPP_APPLECP 0x8029 /* Appletalk Control Protocol */ +#define PPP_IPXCP 0x802b /* Novell IPX Control Protocol */ +#define PPP_STIICP 0x8033 /* Stream Protocol Control Protocol */ +#define PPP_VINESCP 0x8035 /* Banyan Vines Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_MPLSCP 0x8281 /* rfc 3022 */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQM 0xc025 /* Link Quality Monitoring */ +#define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */ /** PPP Packet header */ typedef struct PPPHdr_ { @@ -73,4 +73,3 @@ typedef struct PPPHdr_ { void DecodePPPRegisterTests(void); #endif /* __DECODE_PPP_H__ */ - diff --git a/src/decode-pppoe.c b/src/decode-pppoe.c index f884085c650f..5ee104b64b1c 100644 --- a/src/decode-pppoe.c +++ b/src/decode-pppoe.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -40,15 +39,15 @@ #include "decode-events.h" #include "flow.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" /** * \brief Main decoding function for PPPOE Discovery packets */ -int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodePPPOEDiscovery( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -62,20 +61,19 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, p->pppoedh = (PPPOEDiscoveryHdr *)pkt; /* parse the PPPOE code */ - switch (p->pppoedh->pppoe_code) - { - case PPPOE_CODE_PADI: + switch (p->pppoedh->pppoe_code) { + case PPPOE_CODE_PADI: break; - case PPPOE_CODE_PADO: + case PPPOE_CODE_PADO: break; - case PPPOE_CODE_PADR: + case PPPOE_CODE_PADR: break; case PPPOE_CODE_PADS: break; case PPPOE_CODE_PADT: break; default: - SCLogDebug("unknown PPPOE code: 0x%0"PRIX8"", p->pppoedh->pppoe_code); + SCLogDebug("unknown PPPOE code: 0x%0" PRIX8 "", p->pppoedh->pppoe_code); ENGINE_SET_INVALID_EVENT(p, PPPOE_WRONG_CODE); return TM_ECODE_OK; } @@ -83,13 +81,12 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /* parse any tags we have in the packet */ uint32_t tag_length = 0; - PPPOEDiscoveryTag* pppoedt = (PPPOEDiscoveryTag*) (p->pppoedh + PPPOE_DISCOVERY_HEADER_MIN_LEN); + PPPOEDiscoveryTag *pppoedt = (PPPOEDiscoveryTag *)(p->pppoedh + PPPOE_DISCOVERY_HEADER_MIN_LEN); uint32_t pppoe_length = SCNtohs(p->pppoedh->pppoe_length); - uint32_t packet_length = len - PPPOE_DISCOVERY_HEADER_MIN_LEN ; + uint32_t packet_length = len - PPPOE_DISCOVERY_HEADER_MIN_LEN; - SCLogDebug("pppoe_length %"PRIu32", packet_length %"PRIu32"", - pppoe_length, packet_length); + SCLogDebug("pppoe_length %" PRIu32 ", packet_length %" PRIu32 "", pppoe_length, packet_length); if (pppoe_length > packet_length) { SCLogDebug("malformed PPPOE tags"); @@ -97,14 +94,14 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, return TM_ECODE_OK; } - while (pppoedt < (PPPOEDiscoveryTag*) (pkt + (len - sizeof(PPPOEDiscoveryTag))) && pppoe_length >=4 && packet_length >=4) - { + while (pppoedt < (PPPOEDiscoveryTag *)(pkt + (len - sizeof(PPPOEDiscoveryTag))) && + pppoe_length >= 4 && packet_length >= 4) { #ifdef DEBUG uint16_t tag_type = SCNtohs(pppoedt->pppoe_tag_type); #endif tag_length = SCNtohs(pppoedt->pppoe_tag_length); - SCLogDebug ("PPPoE Tag type %x, length %"PRIu32, tag_type, tag_length); + SCLogDebug("PPPoE Tag type %x, length %" PRIu32, tag_type, tag_length); if (pppoe_length >= (4 + tag_length)) { pppoe_length -= (4 + tag_length); @@ -127,8 +124,8 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /** * \brief Main decoding function for PPPOE Session packets */ -int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodePPPOESession( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -141,10 +138,14 @@ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, p->pppoesh = (PPPOESessionHdr *)pkt; - SCLogDebug("PPPOE VERSION %" PRIu32 " TYPE %" PRIu32 " CODE %" PRIu32 " SESSIONID %" PRIu32 " LENGTH %" PRIu32 "", - PPPOE_SESSION_GET_VERSION(p->pppoesh), PPPOE_SESSION_GET_TYPE(p->pppoesh), p->pppoesh->pppoe_code, SCNtohs(p->pppoesh->session_id), SCNtohs(p->pppoesh->pppoe_length)); + SCLogDebug("PPPOE VERSION %" PRIu32 " TYPE %" PRIu32 " CODE %" PRIu32 " SESSIONID %" PRIu32 + " LENGTH %" PRIu32 "", + PPPOE_SESSION_GET_VERSION(p->pppoesh), PPPOE_SESSION_GET_TYPE(p->pppoesh), + p->pppoesh->pppoe_code, SCNtohs(p->pppoesh->session_id), + SCNtohs(p->pppoesh->pppoe_length)); - /* can't use DecodePPP() here because we only get a single 2-byte word to indicate protocol instead of the full PPP header */ + /* can't use DecodePPP() here because we only get a single 2-byte word to indicate protocol + * instead of the full PPP header */ if (SCNtohs(p->pppoesh->pppoe_length) > 0) { /* decode contained PPP packet */ @@ -198,7 +199,7 @@ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, case PPP_PAP: case PPP_LQM: case PPP_CHAP: - ENGINE_SET_EVENT(p,PPP_UNSUP_PROTO); + ENGINE_SET_EVENT(p, PPP_UNSUP_PROTO); break; case PPP_VJ_UCOMP: @@ -254,7 +255,7 @@ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, * \brief Decode malformed PPPOE packet (too short) * \retval 1 Expected test value */ -static int DecodePPPOEtest01 (void) +static int DecodePPPOEtest01(void) { uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x00, 0x00 }; @@ -278,9 +279,10 @@ static int DecodePPPOEtest01 (void) * \brief Valid PPPOE packet - check the invalid ICMP type encapsulated is flagged * \retval 0 Expected test value */ -static int DecodePPPOEtest02 (void) +static int DecodePPPOEtest02(void) { + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x21, 0x45, 0x00, 0x00, 0x3c, 0x05, 0x5c, 0x00, 0x00, @@ -291,6 +293,7 @@ static int DecodePPPOEtest02 (void) 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -314,15 +317,15 @@ static int DecodePPPOEtest02 (void) PASS; } - /** DecodePPPOEtest03 * \brief Valid example PADO packet PPPOE packet taken from RFC2516 * \retval 0 Expected test value */ -static int DecodePPPOEtest03 (void) +static int DecodePPPOEtest03(void) { /* example PADO packet taken from RFC2516 */ + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f, @@ -330,6 +333,7 @@ static int DecodePPPOEtest03 (void) 0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68, 0x65, 0x73, 0x68, 0x6f, 0x6f, 0x74 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -350,14 +354,16 @@ static int DecodePPPOEtest03 (void) * \brief Valid example PPPOE packet taken from RFC2516 - but with wrong PPPOE code * \retval 1 Expected test value */ -static int DecodePPPOEtest04 (void) +static int DecodePPPOEtest04(void) { /* example PADI packet taken from RFC2516, but with wrong code */ + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0xbb, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -379,16 +385,18 @@ static int DecodePPPOEtest04 (void) * \brief Valid example PADO PPPOE packet taken from RFC2516, but too short for given length * \retval 0 Expected test value */ -static int DecodePPPOEtest05 (void) +static int DecodePPPOEtest05(void) { /* example PADI packet taken from RFC2516 */ + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f, 0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -412,7 +420,7 @@ static int DecodePPPOEtest05 (void) * should extract the first 4 bits for version and the second 4 bits for type * \retval 1 Expected test value */ -static int DecodePPPOEtest06 (void) +static int DecodePPPOEtest06(void) { PPPOESessionHdr pppoesh; @@ -434,10 +442,12 @@ static int DecodePPPOEtest06 (void) static int DecodePPPOEtest07(void) { + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x2d, 0x00, 0x1c, 0x21, 0x45, 0x00, 0x00, 0x1d, 0x97, 0xc3, 0x00, 0x00, 0x40, 0x01, 0x47, 0x0f, 0x0a, 0x64, 0x00, 0x00, 0xc0, 0xa8, 0xd1, 0x01, 0x08, 0x00, 0xd4, 0x4c, 0x1f, 0x32, 0x04, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -461,11 +471,13 @@ static int DecodePPPOEtest07(void) static int DecodePPPOEtest08(void) { + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x2d, 0x00, 0x3d, 0x21, 0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, 0xed, 0xda, 0x0a, 0x64, 0x00, 0x00, 0x8e, 0xfa, 0xb3, 0x83, 0xde, 0xb5, 0x00, 0x50, 0xd4, 0xbd, 0x76, 0x54, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfe, 0xcc, 0x74, 0x2f, 0x00, 0x00, 0x02, 0x04, 0x05, 0xac, 0x01, 0x03, 0x03, 0x07, 0x04, 0x02, 0x08, 0x0a, 0xcb, 0xae, 0x92, 0x63, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -489,10 +501,12 @@ static int DecodePPPOEtest08(void) static int DecodePPPOEtest09(void) { + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x2d, 0x00, 0x1c, 0x00, 0x21, 0x45, 0x00, 0x00, 0x1d, 0x97, 0xc3, 0x00, 0x00, 0x40, 0x01, 0x47, 0x0f, 0x0a, 0x64, 0x00, 0x00, 0xc0, 0xa8, 0xd1, 0x01, 0x08, 0x00, 0xd4, 0x4c, 0x1f, 0x32, 0x04, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -516,11 +530,13 @@ static int DecodePPPOEtest09(void) static int DecodePPPOEtest10(void) { + // clang-format off uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x2d, 0x00, 0x3d, 0x00, 0x21, 0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, 0xed, 0xda, 0x0a, 0x64, 0x00, 0x00, 0x8e, 0xfa, 0xb3, 0x83, 0xde, 0xb5, 0x00, 0x50, 0xd4, 0xbd, 0x76, 0x54, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfe, 0xcc, 0x74, 0x2f, 0x00, 0x00, 0x02, 0x04, 0x05, 0xac, 0x01, 0x03, 0x03, 0x07, 0x04, 0x02, 0x08, 0x0a, 0xcb, 0xae, 0x92, 0x63, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); diff --git a/src/decode-pppoe.h b/src/decode-pppoe.h index 836d4a30c350..a755c6cf07eb 100644 --- a/src/decode-pppoe.h +++ b/src/decode-pppoe.h @@ -24,17 +24,15 @@ #ifndef __DECODE_PPPOE_H__ #define __DECODE_PPPOE_H__ - // Session header length minus the protocol field #define PPPOE_SESSION_HEADER_MIN_LEN 7 -#define PPPOE_DISCOVERY_HEADER_MIN_LEN 6 -#define PPPOE_SESSION_GET_VERSION(hdr) ((hdr)->pppoe_version_type & 0xF0) >> 4 -#define PPPOE_SESSION_GET_TYPE(hdr) ((hdr)->pppoe_version_type & 0x0F) +#define PPPOE_DISCOVERY_HEADER_MIN_LEN 6 +#define PPPOE_SESSION_GET_VERSION(hdr) ((hdr)->pppoe_version_type & 0xF0) >> 4 +#define PPPOE_SESSION_GET_TYPE(hdr) ((hdr)->pppoe_version_type & 0x0F) #define PPPOE_DISCOVERY_GET_VERSION(hdr) ((hdr)->pppoe_version_type & 0xF0) >> 4 -#define PPPOE_DISCOVERY_GET_TYPE(hdr) ((hdr)->pppoe_version_type & 0x0F) +#define PPPOE_DISCOVERY_GET_TYPE(hdr) ((hdr)->pppoe_version_type & 0x0F) -typedef struct PPPOESessionHdr_ -{ +typedef struct PPPOESessionHdr_ { uint8_t pppoe_version_type; uint8_t pppoe_code; uint16_t session_id; @@ -42,14 +40,12 @@ typedef struct PPPOESessionHdr_ uint16_t protocol; } PPPOESessionHdr; -typedef struct PPPOEDiscoveryTag_ -{ +typedef struct PPPOEDiscoveryTag_ { uint16_t pppoe_tag_type; uint16_t pppoe_tag_length; } __attribute__((__packed__)) PPPOEDiscoveryTag; -typedef struct PPPOEDiscoveryHdr_ -{ +typedef struct PPPOEDiscoveryHdr_ { uint8_t pppoe_version_type; uint8_t pppoe_code; uint16_t discovery_id; @@ -64,18 +60,17 @@ typedef struct PPPOEDiscoveryHdr_ #define PPPOE_CODE_PADT 0xa7 /* see RFC 2516 Appendix A */ -#define PPPOE_TAG_END_OF_LIST 0x0000 /* End-Of-List */ -#define PPPOE_TAG_SERVICE_NAME 0x0101 /* Service-Name */ -#define PPPOE_TAG_AC_NAME 0x0102 /* AC-Name */ -#define PPPOE_TAG_HOST_UNIQ 0x0103 /* Host-Uniq */ -#define PPPOE_TAG_AC_COOKIE 0x0104 /* AC-Cookie */ -#define PPPOE_TAG_VENDOR_SPECIFIC 0x0105 /* Vendor-Specific */ -#define PPPOE_TAG_RELAY_SESSION_ID 0x0110 /* Relay-Session-Id */ -#define PPPOE_TAG_SERVICE_NAME_ERROR 0x0201 /* Service-Name-Error */ -#define PPPOE_TAG_AC_SYS_ERROR 0x0202 /* AC-System Error */ -#define PPPOE_TAG_GEN_ERROR 0x0203 /* Generic-Error */ +#define PPPOE_TAG_END_OF_LIST 0x0000 /* End-Of-List */ +#define PPPOE_TAG_SERVICE_NAME 0x0101 /* Service-Name */ +#define PPPOE_TAG_AC_NAME 0x0102 /* AC-Name */ +#define PPPOE_TAG_HOST_UNIQ 0x0103 /* Host-Uniq */ +#define PPPOE_TAG_AC_COOKIE 0x0104 /* AC-Cookie */ +#define PPPOE_TAG_VENDOR_SPECIFIC 0x0105 /* Vendor-Specific */ +#define PPPOE_TAG_RELAY_SESSION_ID 0x0110 /* Relay-Session-Id */ +#define PPPOE_TAG_SERVICE_NAME_ERROR 0x0201 /* Service-Name-Error */ +#define PPPOE_TAG_AC_SYS_ERROR 0x0202 /* AC-System Error */ +#define PPPOE_TAG_GEN_ERROR 0x0203 /* Generic-Error */ void DecodePPPOERegisterTests(void); #endif /* __DECODE_PPPOE_H__ */ - diff --git a/src/decode-raw.c b/src/decode-raw.c index 1a64f1adf903..f7ac4854d426 100644 --- a/src/decode-raw.c +++ b/src/decode-raw.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -35,12 +34,11 @@ #include "decode.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" -int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -52,8 +50,6 @@ int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, return TM_ECODE_FAILED; } - - if (IP_GET_RAW_VER(pkt) == 4) { if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) { return TM_ECODE_FAILED; @@ -68,23 +64,24 @@ int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), (uint16_t)(GET_PKT_LEN(p))); } else { SCLogDebug("Unknown ip version %d", IP_GET_RAW_VER(pkt)); - ENGINE_SET_EVENT(p,IPRAW_INVALID_IPV); + ENGINE_SET_EVENT(p, IPRAW_INVALID_IPV); } return TM_ECODE_OK; } #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "packet.h" /** DecodeRawtest01 * \brief Valid Raw packet * \retval 0 Expected test value */ -static int DecodeRawTest01 (void) +static int DecodeRawTest01(void) { /* IPV6/TCP/no eth header */ + // clang-format off uint8_t raw_ip[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0x06, 0x40, 0x20, 0x01, 0x06, 0x18, 0x04, 0x00, 0x00, 0x00, @@ -96,6 +93,7 @@ static int DecodeRawTest01 (void) 0x29, 0x9c, 0x00, 0x00, 0x02, 0x04, 0x05, 0x8c, 0x04, 0x02, 0x08, 0x0a, 0x00, 0xdd, 0x1a, 0x39, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -103,11 +101,11 @@ static int DecodeRawTest01 (void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { - SCFree(p); - return 0; + SCFree(p); + return 0; } FlowInitConfig(FLOW_QUIET); @@ -124,16 +122,16 @@ static int DecodeRawTest01 (void) FlowShutdown(); SCFree(p); return 1; - } /** DecodeRawtest02 * \brief Valid Raw packet * \retval 0 Expected test value */ -static int DecodeRawTest02 (void) +static int DecodeRawTest02(void) { /* IPV4/TCP/no eth header */ + // clang-format off uint8_t raw_ip[] = { 0x45, 0x00, 0x00, 0x30, 0x00, 0xad, 0x40, 0x00, 0x7f, 0x06, 0xac, 0xc5, 0xc0, 0xa8, 0x67, 0x02, @@ -141,6 +139,7 @@ static int DecodeRawTest02 (void) 0x1d, 0xb3, 0x12, 0x37, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, 0x40, 0x00, 0xb8, 0xc8, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -149,11 +148,11 @@ static int DecodeRawTest02 (void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { - SCFree(p); - return 0; + SCFree(p); + return 0; } FlowInitConfig(FLOW_QUIET); @@ -176,10 +175,11 @@ static int DecodeRawTest02 (void) * \brief Valid Raw packet * \retval 0 Expected test value */ -static int DecodeRawTest03 (void) +static int DecodeRawTest03(void) { /* IPV13 */ + // clang-format off uint8_t raw_ip[] = { 0xdf, 0x00, 0x00, 0x3d, 0x49, 0x42, 0x40, 0x00, 0x40, 0x06, 0xcf, 0x8a, 0x0a, 0x1f, 0x03, 0xaf, @@ -189,6 +189,7 @@ static int DecodeRawTest03 (void) 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xab, 0x4f, 0x34, 0x40, 0x67, 0x31, 0x3b, 0x63, 0x61, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x3b }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -197,7 +198,7 @@ static int DecodeRawTest03 (void) DecodeThreadVars dtv; memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&tv, 0, sizeof(ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); @@ -207,7 +208,7 @@ static int DecodeRawTest03 (void) FlowInitConfig(FLOW_QUIET); DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p)); - if (!ENGINE_ISSET_EVENT(p,IPRAW_INVALID_IPV)) { + if (!ENGINE_ISSET_EVENT(p, IPRAW_INVALID_IPV)) { printf("expected IPRAW_INVALID_IPV to be set but it wasn't: "); FlowShutdown(); SCFree(p); diff --git a/src/decode-raw.h b/src/decode-raw.h index ff637870ad14..a546b6c076ef 100644 --- a/src/decode-raw.h +++ b/src/decode-raw.h @@ -25,4 +25,3 @@ #define __DECODE_RAW_H__ void DecodeRawRegisterTests(void); #endif /* __DECODE_RAW_H__ */ - diff --git a/src/decode-sctp.c b/src/decode-sctp.c index 9a6c4e8ead2a..2ed3cb95db1f 100644 --- a/src/decode-sctp.c +++ b/src/decode-sctp.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -35,10 +34,10 @@ #include "decode-sctp.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-optimize.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/optimize.h" #include "flow.h" static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, const uint8_t *pkt, uint16_t len) @@ -52,8 +51,8 @@ static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, const uint8_t *pkt, uint1 p->sctph = (SCTPHdr *)pkt; - SET_SCTP_SRC_PORT(p,&p->sp); - SET_SCTP_DST_PORT(p,&p->dp); + SET_SCTP_SRC_PORT(p, &p->sp); + SET_SCTP_DST_PORT(p, &p->dp); p->payload = (uint8_t *)pkt + sizeof(SCTPHdr); p->payload_len = len - sizeof(SCTPHdr); @@ -63,19 +62,17 @@ static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, const uint8_t *pkt, uint1 return 0; } -int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t len) +int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) { StatsIncr(tv, dtv->counter_sctp); - if (unlikely(DecodeSCTPPacket(tv, p,pkt,len) < 0)) { + if (unlikely(DecodeSCTPPacket(tv, p, pkt, len) < 0)) { CLEAR_SCTP_PACKET(p); return TM_ECODE_FAILED; } #ifdef DEBUG - SCLogDebug("SCTP sp: %" PRIu32 " -> dp: %" PRIu32, - SCTP_GET_SRC_PORT(p), SCTP_GET_DST_PORT(p)); + SCLogDebug("SCTP sp: %" PRIu32 " -> dp: %" PRIu32, SCTP_GET_SRC_PORT(p), SCTP_GET_DST_PORT(p)); #endif FlowSetupPacket(p); diff --git a/src/decode-sctp.h b/src/decode-sctp.h index 53aa007dbbc0..03edd22ffb38 100644 --- a/src/decode-sctp.h +++ b/src/decode-sctp.h @@ -25,26 +25,27 @@ #define __DECODE_SCTP_H__ /** size of the packet header without any chunk headers */ -#define SCTP_HEADER_LEN 12 +#define SCTP_HEADER_LEN 12 /* XXX RAW* needs to be really 'raw', so no SCNtohs there */ -#define SCTP_GET_RAW_SRC_PORT(sctph) SCNtohs((sctph)->sh_sport) -#define SCTP_GET_RAW_DST_PORT(sctph) SCNtohs((sctph)->sh_dport) - -#define SCTP_GET_SRC_PORT(p) SCTP_GET_RAW_SRC_PORT(p->sctph) -#define SCTP_GET_DST_PORT(p) SCTP_GET_RAW_DST_PORT(p->sctph) - -typedef struct SCTPHdr_ -{ - uint16_t sh_sport; /* source port */ - uint16_t sh_dport; /* destination port */ - uint32_t sh_vtag; /* verification tag, defined per flow */ - uint32_t sh_sum; /* checksum, computed via crc32 */ +#define SCTP_GET_RAW_SRC_PORT(sctph) SCNtohs((sctph)->sh_sport) +#define SCTP_GET_RAW_DST_PORT(sctph) SCNtohs((sctph)->sh_dport) + +#define SCTP_GET_SRC_PORT(p) SCTP_GET_RAW_SRC_PORT(p->sctph) +#define SCTP_GET_DST_PORT(p) SCTP_GET_RAW_DST_PORT(p->sctph) + +typedef struct SCTPHdr_ { + uint16_t sh_sport; /* source port */ + uint16_t sh_dport; /* destination port */ + uint32_t sh_vtag; /* verification tag, defined per flow */ + uint32_t sh_sum; /* checksum, computed via crc32 */ } __attribute__((__packed__)) SCTPHdr; -#define CLEAR_SCTP_PACKET(p) { \ - (p)->sctph = NULL; \ -} while (0) +#define CLEAR_SCTP_PACKET(p) \ + { \ + (p)->sctph = NULL; \ + } \ + while (0) void DecodeSCTPRegisterTests(void); diff --git a/src/decode-sll.c b/src/decode-sll.c index f26950fffead..2a63b422dd66 100644 --- a/src/decode-sll.c +++ b/src/decode-sll.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -35,11 +34,10 @@ #include "decode-sll.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/debug.h" -int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -57,8 +55,8 @@ int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCLogDebug("p %p pkt %p sll_protocol %04x", p, pkt, SCNtohs(sllh->sll_protocol)); - DecodeNetworkLayer(tv, dtv, SCNtohs(sllh->sll_protocol), p, - pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN); + DecodeNetworkLayer( + tv, dtv, SCNtohs(sllh->sll_protocol), p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN); return TM_ECODE_OK; } diff --git a/src/decode-sll.h b/src/decode-sll.h index babdd7ac2109..cb43021cafc8 100644 --- a/src/decode-sll.h +++ b/src/decode-sll.h @@ -24,15 +24,14 @@ #ifndef __DECODE_SLL_H__ #define __DECODE_SLL_H__ -#define SLL_HEADER_LEN 16 +#define SLL_HEADER_LEN 16 typedef struct SllHdr_ { - uint16_t sll_pkttype; /* packet type */ - uint16_t sll_hatype; /* link-layer address type */ - uint16_t sll_halen; /* link-layer address length */ - uint8_t sll_addr[8]; /* link-layer address */ - uint16_t sll_protocol; /* protocol */ + uint16_t sll_pkttype; /* packet type */ + uint16_t sll_hatype; /* link-layer address type */ + uint16_t sll_halen; /* link-layer address length */ + uint8_t sll_addr[8]; /* link-layer address */ + uint16_t sll_protocol; /* protocol */ } __attribute__((__packed__)) SllHdr; #endif /* __DECODE_SLL_H__ */ - diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 49bb882d58fc..b3320795c716 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -34,14 +33,14 @@ #include "decode-tcp.h" #include "decode.h" #include "decode-events.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-optimize.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/optimize.h" #include "flow.h" -#define SET_OPTS(dst, src) \ - (dst).type = (src).type; \ - (dst).len = (src).len; \ +#define SET_OPTS(dst, src) \ + (dst).type = (src).type; \ + (dst).len = (src).len; \ (dst).data = (src).data static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) @@ -50,8 +49,7 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) TCPOpt tcp_opts[TCP_OPTMAX]; uint16_t plen = pktlen; - while (plen) - { + while (plen) { const uint8_t type = *pkt; /* single byte options */ @@ -61,13 +59,13 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) pkt++; plen--; - /* multibyte options */ + /* multibyte options */ } else { if (plen < 2) { break; } - const uint8_t olen = *(pkt+1); + const uint8_t olen = *(pkt + 1); /* we already know that the total options len is valid, * so here the len of the specific option must be bad. @@ -78,8 +76,8 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) } tcp_opts[tcp_opt_cnt].type = type; - tcp_opts[tcp_opt_cnt].len = olen; - tcp_opts[tcp_opt_cnt].data = (olen > 2) ? (pkt+2) : NULL; + tcp_opts[tcp_opt_cnt].len = olen; + tcp_opts[tcp_opt_cnt].data = (olen > 2) ? (pkt + 2) : NULL; /* we are parsing the most commonly used opts to prevent * us from having to walk the opts list for these all the @@ -87,10 +85,10 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) switch (type) { case TCP_OPT_WS: if (olen != TCP_OPT_WS_LEN) { - ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_EVENT(p, TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ws.type != 0) { - ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.ws, tcp_opts[tcp_opt_cnt]); } @@ -98,10 +96,10 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) break; case TCP_OPT_MSS: if (olen != TCP_OPT_MSS_LEN) { - ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_EVENT(p, TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.mss.type != 0) { - ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.mss, tcp_opts[tcp_opt_cnt]); } @@ -109,10 +107,10 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) break; case TCP_OPT_SACKOK: if (olen != TCP_OPT_SACKOK_LEN) { - ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_EVENT(p, TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sackok.type != 0) { - ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.sackok, tcp_opts[tcp_opt_cnt]); } @@ -120,10 +118,10 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) break; case TCP_OPT_TS: if (olen != TCP_OPT_TS_LEN) { - ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_EVENT(p, TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ts_set) { - ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, TCP_OPT_DUPLICATE); } else { uint32_t values[2]; memcpy(&values, tcp_opts[tcp_opt_cnt].data, sizeof(values)); @@ -136,14 +134,12 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) case TCP_OPT_SACK: SCLogDebug("SACK option, len %u", olen); if ((olen != 2) && - (olen < TCP_OPT_SACK_MIN_LEN || - olen > TCP_OPT_SACK_MAX_LEN || - !((olen - 2) % 8 == 0))) - { - ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); + (olen < TCP_OPT_SACK_MIN_LEN || olen > TCP_OPT_SACK_MAX_LEN || + !((olen - 2) % 8 == 0))) { + ENGINE_SET_EVENT(p, TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sack.type != 0) { - ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.sack, tcp_opts[tcp_opt_cnt]); } @@ -153,10 +149,10 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) SCLogDebug("TFO option, len %u", olen); if ((olen != 2) && (olen < TCP_OPT_TFO_MIN_LEN || olen > TCP_OPT_TFO_MAX_LEN || !(((olen - 2) & 0x1) == 0))) { - ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_EVENT(p, TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.tfo.type != 0) { - ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.tfo, tcp_opts[tcp_opt_cnt]); } @@ -170,21 +166,21 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) uint16_t magic = SCNtohs(*(uint16_t *)tcp_opts[tcp_opt_cnt].data); if (magic == 0xf989) { if (p->tcpvars.tfo.type != 0) { - ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); + ENGINE_SET_EVENT(p, TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.tfo, tcp_opts[tcp_opt_cnt]); p->tcpvars.tfo.type = TCP_OPT_TFO; // treat as regular TFO } } } else { - ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_EVENT(p, TCP_OPT_INVALID_LEN); } break; /* RFC 2385 MD5 option */ case TCP_OPT_MD5: SCLogDebug("MD5 option, len %u", olen); if (olen != 18) { - ENGINE_SET_INVALID_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_INVALID_EVENT(p, TCP_OPT_INVALID_LEN); } else { /* we can't validate the option as the key is out of band */ p->tcpvars.md5_option_present = true; @@ -194,7 +190,7 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen) case TCP_OPT_AO: SCLogDebug("AU option, len %u", olen); if (olen < 4) { - ENGINE_SET_INVALID_EVENT(p,TCP_OPT_INVALID_LEN); + ENGINE_SET_INVALID_EVENT(p, TCP_OPT_INVALID_LEN); } else { /* we can't validate the option as the key is out of band */ p->tcpvars.ao_option_present = true; @@ -234,8 +230,8 @@ static int DecodeTCPPacket(ThreadVars *tv, Packet *p, const uint8_t *pkt, uint16 DecodeTCPOptions(p, pkt + TCP_HEADER_LEN, tcp_opt_len); } - SET_TCP_SRC_PORT(p,&p->sp); - SET_TCP_DST_PORT(p,&p->dp); + SET_TCP_SRC_PORT(p, &p->sp); + SET_TCP_DST_PORT(p, &p->dp); p->proto = IPPROTO_TCP; @@ -245,12 +241,11 @@ static int DecodeTCPPacket(ThreadVars *tv, Packet *p, const uint8_t *pkt, uint16 return 0; } -int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t len) +int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) { StatsIncr(tv, dtv->counter_tcp); - if (unlikely(DecodeTCPPacket(tv, p, pkt,len) < 0)) { + if (unlikely(DecodeTCPPacket(tv, p, pkt, len) < 0)) { SCLogDebug("invalid TCP packet"); CLEAR_TCP_PACKET(p); return TM_ECODE_FAILED; @@ -266,11 +261,12 @@ int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, StatsIncr(tv, dtv->counter_tcp_rst); } #ifdef DEBUG - SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 " %s%s%s%s%s%s", - GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len, - TCP_HAS_SACKOK(p) ? "SACKOK " : "", TCP_HAS_SACK(p) ? "SACK " : "", - TCP_HAS_WSCALE(p) ? "WS " : "", TCP_HAS_TS(p) ? "TS " : "", - TCP_HAS_MSS(p) ? "MSS " : "", TCP_HAS_TFO(p) ? "TFO " : ""); + SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 + " %s%s%s%s%s%s", + GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len, + TCP_HAS_SACKOK(p) ? "SACKOK " : "", TCP_HAS_SACK(p) ? "SACK " : "", + TCP_HAS_WSCALE(p) ? "WS " : "", TCP_HAS_TS(p) ? "TS " : "", + TCP_HAS_MSS(p) ? "MSS " : "", TCP_HAS_TFO(p) ? "TFO " : ""); #endif FlowSetupPacket(p); @@ -279,27 +275,30 @@ int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, } #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "packet.h" static int TCPCalculateValidChecksumtest01(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipshdr[] = { 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 02}; + // clang-format on - csum = *( ((uint16_t *)raw_tcp) + 8); + csum = *(((uint16_t *)raw_tcp) + 8); - FAIL_IF(TCPChecksum((uint16_t *)raw_ipshdr, - (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) != 0); + FAIL_IF(TCPChecksum((uint16_t *)raw_ipshdr, (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) != 0); PASS; } @@ -307,20 +306,23 @@ static int TCPCalculateInvalidChecksumtest02(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipshdr[] = { 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 03}; + // clang-format on - csum = *( ((uint16_t *)raw_tcp) + 8); + csum = *(((uint16_t *)raw_tcp) + 8); - FAIL_IF(TCPChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) == 0); + FAIL_IF(TCPChecksum((uint16_t *)raw_ipshdr, (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) == 0); PASS; } @@ -328,6 +330,7 @@ static int TCPV6CalculateValidChecksumtest03(void) { uint16_t csum = 0; + // clang-format off static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -340,11 +343,12 @@ static int TCPV6CalculateValidChecksumtest03(void) 0x08, 0x77, 0x80, 0x10, 0x21, 0x5c, 0xc2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x27}; + // clang-format on - csum = *( ((uint16_t *)(raw_ipv6 + 70))); + csum = *(((uint16_t *)(raw_ipv6 + 70))); - FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 32, csum) != 0); + FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 32, csum) != + 0); PASS; } @@ -352,6 +356,7 @@ static int TCPV6CalculateInvalidChecksumtest04(void) { uint16_t csum = 0; + // clang-format off static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -364,11 +369,12 @@ static int TCPV6CalculateInvalidChecksumtest04(void) 0x08, 0x77, 0x80, 0x10, 0x21, 0x5c, 0xc2, 0xf1, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x28}; + // clang-format on - csum = *( ((uint16_t *)(raw_ipv6 + 70))); + csum = *(((uint16_t *)(raw_ipv6 + 70))); - FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 32, csum) == 0); + FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 32, csum) == + 0); PASS; } @@ -376,11 +382,13 @@ static int TCPV6CalculateInvalidChecksumtest04(void) static int TCPGetWscaleTest01(void) { int retval = 0; + // clang-format off static uint8_t raw_tcp[] = {0xda, 0xc1, 0x00, 0x50, 0xb6, 0x21, 0x7f, 0x58, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x8a, 0xaf, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x62, 0x88, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02}; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -396,7 +404,6 @@ static int TCPGetWscaleTest01(void) p->dst.family = AF_INET; p->ip4h = &ip4h; - FlowInitConfig(FLOW_QUIET); DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp)); @@ -407,7 +414,7 @@ static int TCPGetWscaleTest01(void) uint8_t wscale = TCP_GET_WSCALE(p); if (wscale != 2) { - printf("wscale %"PRIu8", expected 2: ", wscale); + printf("wscale %" PRIu8 ", expected 2: ", wscale); goto end; } @@ -423,11 +430,13 @@ static int TCPGetWscaleTest01(void) static int TCPGetWscaleTest02(void) { int retval = 0; + // clang-format off static uint8_t raw_tcp[] = {0xda, 0xc1, 0x00, 0x50, 0xb6, 0x21, 0x7f, 0x58, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0xd0, 0x8a, 0xaf, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x00, 0x62, 0x88, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x0f}; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -453,7 +462,7 @@ static int TCPGetWscaleTest02(void) uint8_t wscale = TCP_GET_WSCALE(p); if (wscale != 0) { - printf("wscale %"PRIu8", expected 0: ", wscale); + printf("wscale %" PRIu8 ", expected 0: ", wscale); goto end; } @@ -469,10 +478,12 @@ static int TCPGetWscaleTest02(void) static int TCPGetWscaleTest03(void) { int retval = 0; + // clang-format off static uint8_t raw_tcp[] = {0xda, 0xc1, 0x00, 0x50, 0xb6, 0x21, 0x7f, 0x59, 0xdd, 0xa3, 0x6f, 0xf8, 0x80, 0x10, 0x05, 0xb4, 0x7c, 0x70, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x62, 0x88, 0x9e, 0x00, 0x00, 0x00, 0x00}; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -498,7 +509,7 @@ static int TCPGetWscaleTest03(void) uint8_t wscale = TCP_GET_WSCALE(p); if (wscale != 0) { - printf("wscale %"PRIu8", expected 0: ", wscale); + printf("wscale %" PRIu8 ", expected 0: ", wscale); goto end; } @@ -513,15 +524,19 @@ static int TCPGetWscaleTest03(void) static int TCPGetSackTest01(void) { int retval = 0; + // clang-format off static uint8_t raw_tcp[] = { 0x00, 0x50, 0x06, 0xa6, 0xfa, 0x87, 0x0b, 0xf5, 0xf1, 0x59, 0x02, 0xe0, 0xa0, 0x10, 0x3e, 0xbc, 0x1d, 0xe7, 0x00, 0x00, 0x01, 0x01, 0x05, 0x12, 0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64, 0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 }; + // clang-format on + // clang-format off static uint8_t raw_tcp_sack[] = { 0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64, 0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -579,14 +594,10 @@ static int TCPGetSackTest01(void) void DecodeTCPRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("TCPCalculateValidChecksumtest01", - TCPCalculateValidChecksumtest01); - UtRegisterTest("TCPCalculateInvalidChecksumtest02", - TCPCalculateInvalidChecksumtest02); - UtRegisterTest("TCPV6CalculateValidChecksumtest03", - TCPV6CalculateValidChecksumtest03); - UtRegisterTest("TCPV6CalculateInvalidChecksumtest04", - TCPV6CalculateInvalidChecksumtest04); + UtRegisterTest("TCPCalculateValidChecksumtest01", TCPCalculateValidChecksumtest01); + UtRegisterTest("TCPCalculateInvalidChecksumtest02", TCPCalculateInvalidChecksumtest02); + UtRegisterTest("TCPV6CalculateValidChecksumtest03", TCPV6CalculateValidChecksumtest03); + UtRegisterTest("TCPV6CalculateInvalidChecksumtest04", TCPV6CalculateInvalidChecksumtest04); UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01); UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02); UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03); diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 4b26df5c26f4..971ce73419f5 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -25,108 +25,113 @@ #ifndef __DECODE_TCP_H__ #define __DECODE_TCP_H__ -#define TCP_HEADER_LEN 20 -#define TCP_OPTLENMAX 40 -#define TCP_OPTMAX 20 /* every opt is at least 2 bytes - * (type + len), except EOL and NOP */ +#define TCP_HEADER_LEN 20 +#define TCP_OPTLENMAX 40 +#define TCP_OPTMAX \ + 20 /* every opt is at least 2 bytes \ + * (type + len), except EOL and NOP */ /* TCP flags */ -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 /** Establish a new connection reducing window */ -#define TH_ECN 0x40 +#define TH_ECN 0x40 /** Echo Congestion flag */ -#define TH_CWR 0x80 +#define TH_CWR 0x80 /* tcp option codes */ -#define TCP_OPT_EOL 0x00 -#define TCP_OPT_NOP 0x01 -#define TCP_OPT_MSS 0x02 -#define TCP_OPT_WS 0x03 -#define TCP_OPT_SACKOK 0x04 -#define TCP_OPT_SACK 0x05 -#define TCP_OPT_TS 0x08 -#define TCP_OPT_TFO 0x22 /* TCP Fast Open */ -#define TCP_OPT_EXP1 0xfd /* Experimental, could be TFO */ -#define TCP_OPT_EXP2 0xfe /* Experimental, could be TFO */ -#define TCP_OPT_MD5 0x13 /* 19: RFC 2385 TCP MD5 option */ -#define TCP_OPT_AO 0x1d /* 29: RFC 5925 TCP AO option */ - -#define TCP_OPT_SACKOK_LEN 2 -#define TCP_OPT_WS_LEN 3 -#define TCP_OPT_TS_LEN 10 -#define TCP_OPT_MSS_LEN 4 -#define TCP_OPT_SACK_MIN_LEN 10 /* hdr 2, 1 pair 8 = 10 */ -#define TCP_OPT_SACK_MAX_LEN 34 /* hdr 2, 4 pair 32= 34 */ -#define TCP_OPT_TFO_MIN_LEN 4 /* kind, len, 2 bytes cookie: 4 */ -#define TCP_OPT_TFO_MAX_LEN 18 /* kind, len, 18 */ +#define TCP_OPT_EOL 0x00 +#define TCP_OPT_NOP 0x01 +#define TCP_OPT_MSS 0x02 +#define TCP_OPT_WS 0x03 +#define TCP_OPT_SACKOK 0x04 +#define TCP_OPT_SACK 0x05 +#define TCP_OPT_TS 0x08 +#define TCP_OPT_TFO 0x22 /* TCP Fast Open */ +#define TCP_OPT_EXP1 0xfd /* Experimental, could be TFO */ +#define TCP_OPT_EXP2 0xfe /* Experimental, could be TFO */ +#define TCP_OPT_MD5 0x13 /* 19: RFC 2385 TCP MD5 option */ +#define TCP_OPT_AO 0x1d /* 29: RFC 5925 TCP AO option */ + +#define TCP_OPT_SACKOK_LEN 2 +#define TCP_OPT_WS_LEN 3 +#define TCP_OPT_TS_LEN 10 +#define TCP_OPT_MSS_LEN 4 +#define TCP_OPT_SACK_MIN_LEN 10 /* hdr 2, 1 pair 8 = 10 */ +#define TCP_OPT_SACK_MAX_LEN 34 /* hdr 2, 4 pair 32= 34 */ +#define TCP_OPT_TFO_MIN_LEN 4 /* kind, len, 2 bytes cookie: 4 */ +#define TCP_OPT_TFO_MAX_LEN 18 /* kind, len, 18 */ /** Max valid wscale value. */ -#define TCP_WSCALE_MAX 14 +#define TCP_WSCALE_MAX 14 -#define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4) -#define TCP_GET_RAW_X2(tcph) (unsigned char)((tcph)->th_offx2 & 0x0f) -#define TCP_GET_RAW_SRC_PORT(tcph) SCNtohs((tcph)->th_sport) -#define TCP_GET_RAW_DST_PORT(tcph) SCNtohs((tcph)->th_dport) +#define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4) +#define TCP_GET_RAW_X2(tcph) (unsigned char)((tcph)->th_offx2 & 0x0f) +#define TCP_GET_RAW_SRC_PORT(tcph) SCNtohs((tcph)->th_sport) +#define TCP_GET_RAW_DST_PORT(tcph) SCNtohs((tcph)->th_dport) -#define TCP_SET_RAW_TCP_OFFSET(tcph, value) ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0x0f) | (value << 4))) -#define TCP_SET_RAW_TCP_X2(tcph, value) ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0xf0) | (value & 0x0f))) +#define TCP_SET_RAW_TCP_OFFSET(tcph, value) \ + ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0x0f) | (value << 4))) +#define TCP_SET_RAW_TCP_X2(tcph, value) \ + ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0xf0) | (value & 0x0f))) -#define TCP_GET_RAW_SEQ(tcph) SCNtohl((tcph)->th_seq) -#define TCP_GET_RAW_ACK(tcph) SCNtohl((tcph)->th_ack) +#define TCP_GET_RAW_SEQ(tcph) SCNtohl((tcph)->th_seq) +#define TCP_GET_RAW_ACK(tcph) SCNtohl((tcph)->th_ack) -#define TCP_GET_RAW_WINDOW(tcph) SCNtohs((tcph)->th_win) -#define TCP_GET_RAW_URG_POINTER(tcph) SCNtohs((tcph)->th_urp) -#define TCP_GET_RAW_SUM(tcph) SCNtohs((tcph)->th_sum) +#define TCP_GET_RAW_WINDOW(tcph) SCNtohs((tcph)->th_win) +#define TCP_GET_RAW_URG_POINTER(tcph) SCNtohs((tcph)->th_urp) +#define TCP_GET_RAW_SUM(tcph) SCNtohs((tcph)->th_sum) /** macro for getting the first timestamp from the packet in host order */ -#define TCP_GET_TSVAL(p) ((p)->tcpvars.ts_val) +#define TCP_GET_TSVAL(p) ((p)->tcpvars.ts_val) /** macro for getting the second timestamp from the packet in host order. */ -#define TCP_GET_TSECR(p) ((p)->tcpvars.ts_ecr) +#define TCP_GET_TSECR(p) ((p)->tcpvars.ts_ecr) -#define TCP_HAS_WSCALE(p) ((p)->tcpvars.ws.type == TCP_OPT_WS) -#define TCP_HAS_SACK(p) ((p)->tcpvars.sack.type == TCP_OPT_SACK) -#define TCP_HAS_SACKOK(p) ((p)->tcpvars.sackok.type == TCP_OPT_SACKOK) -#define TCP_HAS_TS(p) ((p)->tcpvars.ts_set) -#define TCP_HAS_MSS(p) ((p)->tcpvars.mss.type == TCP_OPT_MSS) -#define TCP_HAS_TFO(p) ((p)->tcpvars.tfo.type == TCP_OPT_TFO) +#define TCP_HAS_WSCALE(p) ((p)->tcpvars.ws.type == TCP_OPT_WS) +#define TCP_HAS_SACK(p) ((p)->tcpvars.sack.type == TCP_OPT_SACK) +#define TCP_HAS_SACKOK(p) ((p)->tcpvars.sackok.type == TCP_OPT_SACKOK) +#define TCP_HAS_TS(p) ((p)->tcpvars.ts_set) +#define TCP_HAS_MSS(p) ((p)->tcpvars.mss.type == TCP_OPT_MSS) +#define TCP_HAS_TFO(p) ((p)->tcpvars.tfo.type == TCP_OPT_TFO) /** macro for getting the wscale from the packet. */ -#define TCP_GET_WSCALE(p) (TCP_HAS_WSCALE((p)) ? \ - (((*(uint8_t *)(p)->tcpvars.ws.data) <= TCP_WSCALE_MAX) ? \ - (*(uint8_t *)((p)->tcpvars.ws.data)) : 0) : 0) - -#define TCP_GET_SACKOK(p) (TCP_HAS_SACKOK((p)) ? 1 : 0) -#define TCP_GET_SACK_PTR(p) TCP_HAS_SACK((p)) ? (p)->tcpvars.sack.data : NULL -#define TCP_GET_SACK_CNT(p) (TCP_HAS_SACK((p)) ? (((p)->tcpvars.sack.len - 2) / 8) : 0) -#define TCP_GET_MSS(p) SCNtohs(*(uint16_t *)((p)->tcpvars.mss.data)) - -#define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET((p)->tcph) -#define TCP_GET_X2(p) TCP_GET_RAW_X2((p)->tcph) -#define TCP_GET_HLEN(p) ((uint8_t)(TCP_GET_OFFSET((p)) << 2)) -#define TCP_GET_SRC_PORT(p) TCP_GET_RAW_SRC_PORT((p)->tcph) -#define TCP_GET_DST_PORT(p) TCP_GET_RAW_DST_PORT((p)->tcph) -#define TCP_GET_SEQ(p) TCP_GET_RAW_SEQ((p)->tcph) -#define TCP_GET_ACK(p) TCP_GET_RAW_ACK((p)->tcph) -#define TCP_GET_WINDOW(p) TCP_GET_RAW_WINDOW((p)->tcph) -#define TCP_GET_URG_POINTER(p) TCP_GET_RAW_URG_POINTER((p)->tcph) -#define TCP_GET_SUM(p) TCP_GET_RAW_SUM((p)->tcph) -#define TCP_GET_FLAGS(p) (p)->tcph->th_flags - -#define TCP_ISSET_FLAG_FIN(p) ((p)->tcph->th_flags & TH_FIN) -#define TCP_ISSET_FLAG_SYN(p) ((p)->tcph->th_flags & TH_SYN) -#define TCP_ISSET_FLAG_RST(p) ((p)->tcph->th_flags & TH_RST) -#define TCP_ISSET_FLAG_PUSH(p) ((p)->tcph->th_flags & TH_PUSH) -#define TCP_ISSET_FLAG_ACK(p) ((p)->tcph->th_flags & TH_ACK) -#define TCP_ISSET_FLAG_URG(p) ((p)->tcph->th_flags & TH_URG) -#define TCP_ISSET_FLAG_RES2(p) ((p)->tcph->th_flags & TH_RES2) -#define TCP_ISSET_FLAG_RES1(p) ((p)->tcph->th_flags & TH_RES1) +#define TCP_GET_WSCALE(p) \ + (TCP_HAS_WSCALE((p)) ? (((*(uint8_t *)(p)->tcpvars.ws.data) <= TCP_WSCALE_MAX) \ + ? (*(uint8_t *)((p)->tcpvars.ws.data)) \ + : 0) \ + : 0) + +#define TCP_GET_SACKOK(p) (TCP_HAS_SACKOK((p)) ? 1 : 0) +#define TCP_GET_SACK_PTR(p) TCP_HAS_SACK((p)) ? (p)->tcpvars.sack.data : NULL +#define TCP_GET_SACK_CNT(p) (TCP_HAS_SACK((p)) ? (((p)->tcpvars.sack.len - 2) / 8) : 0) +#define TCP_GET_MSS(p) SCNtohs(*(uint16_t *)((p)->tcpvars.mss.data)) + +#define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET((p)->tcph) +#define TCP_GET_X2(p) TCP_GET_RAW_X2((p)->tcph) +#define TCP_GET_HLEN(p) ((uint8_t)(TCP_GET_OFFSET((p)) << 2)) +#define TCP_GET_SRC_PORT(p) TCP_GET_RAW_SRC_PORT((p)->tcph) +#define TCP_GET_DST_PORT(p) TCP_GET_RAW_DST_PORT((p)->tcph) +#define TCP_GET_SEQ(p) TCP_GET_RAW_SEQ((p)->tcph) +#define TCP_GET_ACK(p) TCP_GET_RAW_ACK((p)->tcph) +#define TCP_GET_WINDOW(p) TCP_GET_RAW_WINDOW((p)->tcph) +#define TCP_GET_URG_POINTER(p) TCP_GET_RAW_URG_POINTER((p)->tcph) +#define TCP_GET_SUM(p) TCP_GET_RAW_SUM((p)->tcph) +#define TCP_GET_FLAGS(p) (p)->tcph->th_flags + +#define TCP_ISSET_FLAG_FIN(p) ((p)->tcph->th_flags & TH_FIN) +#define TCP_ISSET_FLAG_SYN(p) ((p)->tcph->th_flags & TH_SYN) +#define TCP_ISSET_FLAG_RST(p) ((p)->tcph->th_flags & TH_RST) +#define TCP_ISSET_FLAG_PUSH(p) ((p)->tcph->th_flags & TH_PUSH) +#define TCP_ISSET_FLAG_ACK(p) ((p)->tcph->th_flags & TH_ACK) +#define TCP_ISSET_FLAG_URG(p) ((p)->tcph->th_flags & TH_URG) +#define TCP_ISSET_FLAG_RES2(p) ((p)->tcph->th_flags & TH_RES2) +#define TCP_ISSET_FLAG_RES1(p) ((p)->tcph->th_flags & TH_RES1) typedef struct TCPOpt_ { uint8_t type; @@ -135,44 +140,43 @@ typedef struct TCPOpt_ { } TCPOpt; typedef struct TCPOptSackRecord_ { - uint32_t le; /**< left edge, network order */ - uint32_t re; /**< right edge, network order */ + uint32_t le; /**< left edge, network order */ + uint32_t re; /**< right edge, network order */ } TCPOptSackRecord; -typedef struct TCPHdr_ -{ - uint16_t th_sport; /**< source port */ - uint16_t th_dport; /**< destination port */ - uint32_t th_seq; /**< sequence number */ - uint32_t th_ack; /**< acknowledgement number */ - uint8_t th_offx2; /**< offset and reserved */ - uint8_t th_flags; /**< pkt flags */ - uint16_t th_win; /**< pkt window */ - uint16_t th_sum; /**< checksum */ - uint16_t th_urp; /**< urgent pointer */ +typedef struct TCPHdr_ { + uint16_t th_sport; /**< source port */ + uint16_t th_dport; /**< destination port */ + uint32_t th_seq; /**< sequence number */ + uint32_t th_ack; /**< acknowledgement number */ + uint8_t th_offx2; /**< offset and reserved */ + uint8_t th_flags; /**< pkt flags */ + uint16_t th_win; /**< pkt window */ + uint16_t th_sum; /**< checksum */ + uint16_t th_urp; /**< urgent pointer */ } __attribute__((__packed__)) TCPHdr; -typedef struct TCPVars_ -{ +typedef struct TCPVars_ { /* commonly used and needed opts */ bool md5_option_present; bool ao_option_present; bool ts_set; - uint32_t ts_val; /* host-order */ - uint32_t ts_ecr; /* host-order */ + uint32_t ts_val; /* host-order */ + uint32_t ts_ecr; /* host-order */ uint16_t stream_pkt_flags; TCPOpt sack; TCPOpt sackok; TCPOpt ws; TCPOpt mss; - TCPOpt tfo; /* tcp fast open */ + TCPOpt tfo; /* tcp fast open */ } TCPVars; -#define CLEAR_TCP_PACKET(p) { \ - (p)->level4_comp_csum = -1; \ - PACKET_CLEAR_L4VARS((p)); \ - (p)->tcph = NULL; \ -} +#define CLEAR_TCP_PACKET(p) \ + { \ + (p)->level4_comp_csum = -1; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->tcph = NULL; \ + } void DecodeTCPRegisterTests(void); @@ -198,29 +202,25 @@ static inline uint16_t TCPChecksum( csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + htons(6) + htons(tlen); - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[9]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; tlen -= 20; pkt += 10; while (tlen >= 32) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + - pkt[8] + - pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } - while(tlen >= 8) { + while (tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } - while(tlen >= 4) { + while (tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; @@ -261,31 +261,29 @@ static inline uint16_t TCPV6Checksum( uint16_t pad = 0; uint32_t csum = init; - csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + - shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + - shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(6) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + + htons(6) + htons(tlen); - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[9]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; tlen -= 20; pkt += 10; while (tlen >= 32) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } - while(tlen >= 8) { + while (tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } - while(tlen >= 4) { + while (tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; diff --git a/src/decode-template.c b/src/decode-template.c index fdaee0a77fd5..f0bc6a96807d 100644 --- a/src/decode-template.c +++ b/src/decode-template.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -36,7 +35,7 @@ #include "decode-events.h" #include "decode-template.h" -#include "util-validate.h" +#include "util/validate.h" /** * \brief Function to decode TEMPLATE packets @@ -48,14 +47,14 @@ * \retval TM_ECODE_OK or TM_ECODE_FAILED on serious error */ -int DecodeTEMPLATE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeTEMPLATE( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); /* TODO add counter for your type of packet to DecodeThreadVars, * and register it in DecodeRegisterPerfCounters */ - //StatsIncr(tv, dtv->counter_template); + // StatsIncr(tv, dtv->counter_template); /* Validation: make sure that the input data is big enough to hold * the header */ @@ -63,7 +62,7 @@ int DecodeTEMPLATE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /* in case of errors, we set events. Events are defined in * decode-events.h, and are then exposed to the detection * engine through detect-engine-events.h */ - //ENGINE_SET_EVENT(p,TEMPLATE_HEADER_TOO_SMALL); + // ENGINE_SET_EVENT(p,TEMPLATE_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } /* Each packet keeps a count of decoded layers @@ -100,7 +99,7 @@ int DecodeTEMPLATE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, /* invoke the next decoder on the remainder of the data */ return DecodeUDP(tv, dtv, p, (uint8_t *)pkt + hdr_len, (uint16_t)(len - hdr_len)); } else { - //ENGINE_SET_EVENT(p,TEMPLATE_UNSUPPORTED_PROTOCOL); + // ENGINE_SET_EVENT(p,TEMPLATE_UNSUPPORTED_PROTOCOL); return TM_ECODE_FAILED; } diff --git a/src/decode-teredo.c b/src/decode-teredo.c index bbeda3efa398..355f5700af21 100644 --- a/src/decode-teredo.c +++ b/src/decode-teredo.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -37,16 +36,16 @@ #include "decode-ipv6.h" #include "decode-teredo.h" -#include "util-validate.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/debug.h" #include "conf.h" #include "detect.h" #include "detect-engine-port.h" -#define TEREDO_ORIG_INDICATION_LENGTH 8 -#define TEREDO_MAX_PORTS 4 -#define TEREDO_UNSET_PORT -1 +#define TEREDO_ORIG_INDICATION_LENGTH 8 +#define TEREDO_MAX_PORTS 4 +#define TEREDO_UNSET_PORT -1 static bool g_teredo_enabled = true; static bool g_teredo_ports_any = true; @@ -124,8 +123,7 @@ void DecodeTeredoConfig(void) * * \retval TM_ECODE_FAILED if packet is not a Teredo packet, TM_ECODE_OK if it is */ -int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t len) +int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -180,16 +178,14 @@ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, if (IPV6_GET_RAW_NH(thdr) == 0 && IPV6_GET_RAW_PLEN(thdr) < 8) return TM_ECODE_FAILED; - if (len == IPV6_HEADER_LEN + - IPV6_GET_RAW_PLEN(thdr) + (start - pkt)) { + if (len == IPV6_HEADER_LEN + IPV6_GET_RAW_PLEN(thdr) + (start - pkt)) { int blen = len - (start - pkt); /* spawn off tunnel packet */ - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, start, blen, - DECODE_TUNNEL_IPV6_TEREDO); + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, start, blen, DECODE_TUNNEL_IPV6_TEREDO); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* add the tp to the packet queue. */ - PacketEnqueueNoLock(&tv->decode_pq,tp); + PacketEnqueueNoLock(&tv->decode_pq, tp); StatsIncr(tv, dtv->counter_teredo); return TM_ECODE_OK; } diff --git a/src/decode-teredo.h b/src/decode-teredo.h index bbd9dc816383..fb7024330698 100644 --- a/src/decode-teredo.h +++ b/src/decode-teredo.h @@ -18,8 +18,8 @@ #ifndef __DECODE_TEREDO_H__ #define __DECODE_TEREDO_H__ -int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t len); +int DecodeTeredo( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len); void DecodeTeredoConfig(void); bool DecodeTeredoEnabledForPort(const uint16_t sp, const uint16_t dp); diff --git a/src/decode-udp.c b/src/decode-udp.c index 1ecaf54f6f1a..0e01e28d9e65 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -37,8 +36,8 @@ #include "decode-teredo.h" #include "decode-vxlan.h" #include "decode-events.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/debug.h" #include "flow.h" #include "app-layer.h" @@ -61,8 +60,8 @@ static int DecodeUDPPacket(ThreadVars *t, Packet *p, const uint8_t *pkt, uint16_ return -1; } - SET_UDP_SRC_PORT(p,&p->sp); - SET_UDP_DST_PORT(p,&p->dp); + SET_UDP_SRC_PORT(p, &p->sp); + SET_UDP_DST_PORT(p, &p->dp); p->payload = (uint8_t *)pkt + UDP_HEADER_LEN; p->payload_len = UDP_GET_LEN(p) - UDP_HEADER_LEN; @@ -72,18 +71,17 @@ static int DecodeUDPPacket(ThreadVars *t, Packet *p, const uint8_t *pkt, uint16_ return 0; } -int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint16_t len) +int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len) { StatsIncr(tv, dtv->counter_udp); - if (unlikely(DecodeUDPPacket(tv, p, pkt,len) < 0)) { + if (unlikely(DecodeUDPPacket(tv, p, pkt, len) < 0)) { CLEAR_UDP_PACKET(p); return TM_ECODE_FAILED; } SCLogDebug("UDP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 "", - UDP_GET_SRC_PORT(p), UDP_GET_DST_PORT(p), UDP_HEADER_LEN, p->payload_len); + UDP_GET_SRC_PORT(p), UDP_GET_DST_PORT(p), UDP_HEADER_LEN, p->payload_len); if (DecodeTeredoEnabledForPort(p->sp, p->dp) && likely(DecodeTeredo(tv, dtv, p, p->payload, p->payload_len) == TM_ECODE_OK)) { @@ -121,9 +119,12 @@ static int UDPV4CalculateValidChecksumtest01(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipshdr[] = { 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x3}; + // clang-format on + // clang-format off uint8_t raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, @@ -136,11 +137,11 @@ static int UDPV4CalculateValidChecksumtest01(void) 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x26}; + // clang-format on - csum = *( ((uint16_t *)raw_udp) + 3); + csum = *(((uint16_t *)raw_udp) + 3); - FAIL_IF(UDPV4Checksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_udp, sizeof(raw_udp), csum) != 0); + FAIL_IF(UDPV4Checksum((uint16_t *)raw_ipshdr, (uint16_t *)raw_udp, sizeof(raw_udp), csum) != 0); PASS; } @@ -148,9 +149,12 @@ static int UDPV4CalculateInvalidChecksumtest02(void) { uint16_t csum = 0; + // clang-format off uint8_t raw_ipshdr[] = { 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x3}; + // clang-format on + // clang-format off uint8_t raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, @@ -163,11 +167,11 @@ static int UDPV4CalculateInvalidChecksumtest02(void) 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x27}; + // clang-format on - csum = *( ((uint16_t *)raw_udp) + 3); + csum = *(((uint16_t *)raw_udp) + 3); - FAIL_IF(UDPV4Checksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_udp, sizeof(raw_udp), csum) == 0); + FAIL_IF(UDPV4Checksum((uint16_t *)raw_ipshdr, (uint16_t *)raw_udp, sizeof(raw_udp), csum) == 0); PASS; } @@ -175,6 +179,7 @@ static int UDPV6CalculateValidChecksumtest03(void) { uint16_t csum = 0; + // clang-format off static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -186,11 +191,12 @@ static int UDPV6CalculateValidChecksumtest03(void) 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x00}; + // clang-format on - csum = *( ((uint16_t *)(raw_ipv6 + 60))); + csum = *(((uint16_t *)(raw_ipv6 + 60))); - FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 20, csum) != 0); + FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 20, csum) != + 0); PASS; } @@ -198,6 +204,7 @@ static int UDPV6CalculateInvalidChecksumtest04(void) { uint16_t csum = 0; + // clang-format off static uint8_t raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -209,11 +216,12 @@ static int UDPV6CalculateInvalidChecksumtest04(void) 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x01}; + // clang-format on - csum = *( ((uint16_t *)(raw_ipv6 + 60))); + csum = *(((uint16_t *)(raw_ipv6 + 60))); - FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 20, csum) == 0); + FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 20, csum) == + 0); PASS; } #endif /* UNITTESTS */ @@ -221,14 +229,10 @@ static int UDPV6CalculateInvalidChecksumtest04(void) void DecodeUDPV4RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UDPV4CalculateValidChecksumtest01", - UDPV4CalculateValidChecksumtest01); - UtRegisterTest("UDPV4CalculateInvalidChecksumtest02", - UDPV4CalculateInvalidChecksumtest02); - UtRegisterTest("UDPV6CalculateValidChecksumtest03", - UDPV6CalculateValidChecksumtest03); - UtRegisterTest("UDPV6CalculateInvalidChecksumtest04", - UDPV6CalculateInvalidChecksumtest04); + UtRegisterTest("UDPV4CalculateValidChecksumtest01", UDPV4CalculateValidChecksumtest01); + UtRegisterTest("UDPV4CalculateInvalidChecksumtest02", UDPV4CalculateInvalidChecksumtest02); + UtRegisterTest("UDPV6CalculateValidChecksumtest03", UDPV6CalculateValidChecksumtest03); + UtRegisterTest("UDPV6CalculateInvalidChecksumtest04", UDPV6CalculateInvalidChecksumtest04); #endif /* UNITTESTS */ } /** diff --git a/src/decode-udp.h b/src/decode-udp.h index 6f695bd1779e..6f70e303f7a0 100644 --- a/src/decode-udp.h +++ b/src/decode-udp.h @@ -24,32 +24,32 @@ #ifndef __DECODE_UDP_H__ #define __DECODE_UDP_H__ -#define UDP_HEADER_LEN 8 +#define UDP_HEADER_LEN 8 /* XXX RAW* needs to be really 'raw', so no SCNtohs there */ -#define UDP_GET_RAW_LEN(udph) SCNtohs((udph)->uh_len) -#define UDP_GET_RAW_SRC_PORT(udph) SCNtohs((udph)->uh_sport) -#define UDP_GET_RAW_DST_PORT(udph) SCNtohs((udph)->uh_dport) -#define UDP_GET_RAW_SUM(udph) SCNtohs((udph)->uh_sum) +#define UDP_GET_RAW_LEN(udph) SCNtohs((udph)->uh_len) +#define UDP_GET_RAW_SRC_PORT(udph) SCNtohs((udph)->uh_sport) +#define UDP_GET_RAW_DST_PORT(udph) SCNtohs((udph)->uh_dport) +#define UDP_GET_RAW_SUM(udph) SCNtohs((udph)->uh_sum) -#define UDP_GET_LEN(p) UDP_GET_RAW_LEN(p->udph) -#define UDP_GET_SRC_PORT(p) UDP_GET_RAW_SRC_PORT(p->udph) -#define UDP_GET_DST_PORT(p) UDP_GET_RAW_DST_PORT(p->udph) -#define UDP_GET_SUM(p) UDP_GET_RAW_SUM(p->udph) +#define UDP_GET_LEN(p) UDP_GET_RAW_LEN(p->udph) +#define UDP_GET_SRC_PORT(p) UDP_GET_RAW_SRC_PORT(p->udph) +#define UDP_GET_DST_PORT(p) UDP_GET_RAW_DST_PORT(p->udph) +#define UDP_GET_SUM(p) UDP_GET_RAW_SUM(p->udph) /* UDP header structure */ -typedef struct UDPHdr_ -{ - uint16_t uh_sport; /* source port */ - uint16_t uh_dport; /* destination port */ - uint16_t uh_len; /* length */ - uint16_t uh_sum; /* checksum */ +typedef struct UDPHdr_ { + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_len; /* length */ + uint16_t uh_sum; /* checksum */ } __attribute__((__packed__)) UDPHdr; -#define CLEAR_UDP_PACKET(p) do { \ - (p)->level4_comp_csum = -1; \ - (p)->udph = NULL; \ -} while (0) +#define CLEAR_UDP_PACKET(p) \ + do { \ + (p)->level4_comp_csum = -1; \ + (p)->udph = NULL; \ + } while (0) void DecodeUDPV4RegisterTests(void); @@ -82,20 +82,19 @@ static inline uint16_t UDPV4Checksum( pkt += 4; while (tlen >= 32) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } - while(tlen >= 8) { + while (tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } - while(tlen >= 4) { + while (tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; @@ -141,9 +140,9 @@ static inline uint16_t UDPV6Checksum( uint16_t pad = 0; uint32_t csum = init; - csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + - shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + - shdr[13] + shdr[14] + shdr[15] + htons(17) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + + htons(17) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2]; @@ -151,20 +150,19 @@ static inline uint16_t UDPV6Checksum( pkt += 4; while (tlen >= 32) { - csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + - pkt[14] + pkt[15]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; } - while(tlen >= 8) { + while (tlen >= 8) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3]; tlen -= 8; pkt += 4; } - while(tlen >= 4) { + while (tlen >= 4) { csum += pkt[0] + pkt[1]; tlen -= 4; pkt += 2; diff --git a/src/decode-vlan.c b/src/decode-vlan.c index 2ec8e2ad9706..95638bc8771d 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -35,9 +34,9 @@ #include "decode-vlan.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" /** * \internal @@ -51,8 +50,7 @@ * \param pq pointer to the packet queue * */ -int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -65,7 +63,7 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, else if (p->vlan_idx == 2) StatsIncr(tv, dtv->counter_vlan_qinqinq); - if(len < VLAN_HEADER_LEN) { + if (len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } @@ -73,7 +71,7 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, return TM_ECODE_FAILED; } if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { - ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); + ENGINE_SET_EVENT(p, VLAN_HEADER_TOO_MANY_LAYERS); return TM_ECODE_FAILED; } @@ -87,8 +85,8 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, p->vlan_id[p->vlan_idx++] = (uint16_t)GET_VLAN_ID(vlan_hdr); - if (DecodeNetworkLayer(tv, dtv, proto, p, - pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN) == false) { + if (DecodeNetworkLayer(tv, dtv, proto, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN) == + false) { ENGINE_SET_INVALID_EVENT(p, VLAN_UNKNOWN_TYPE); return TM_ECODE_FAILED; } @@ -99,13 +97,13 @@ typedef struct IEEE8021ahHdr_ { uint32_t flags; uint8_t c_destination[6]; uint8_t c_source[6]; - uint16_t type; /**< next protocol */ -} __attribute__((__packed__)) IEEE8021ahHdr; + uint16_t type; /**< next protocol */ +} __attribute__((__packed__)) IEEE8021ahHdr; #define IEEE8021AH_HEADER_LEN sizeof(IEEE8021ahHdr) -int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeIEEE8021ah( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -119,14 +117,14 @@ int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, IEEE8021ahHdr *hdr = (IEEE8021ahHdr *)pkt; const uint16_t next_proto = SCNtohs(hdr->type); - DecodeNetworkLayer(tv, dtv, next_proto, p, - pkt + IEEE8021AH_HEADER_LEN, len - IEEE8021AH_HEADER_LEN); + DecodeNetworkLayer( + tv, dtv, next_proto, p, pkt + IEEE8021AH_HEADER_LEN, len - IEEE8021AH_HEADER_LEN); return TM_ECODE_OK; } #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "packet.h" /** \todo Must GRE+VLAN and Multi-Vlan packets to @@ -139,7 +137,7 @@ int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, * \retval 1 on success * \retval 0 on failure */ -static int DecodeVLANtest01 (void) +static int DecodeVLANtest01(void) { uint8_t raw_vlan[] = { 0x00, 0x20, 0x08 }; Packet *p = PacketGetFromAlloc(); @@ -153,7 +151,7 @@ static int DecodeVLANtest01 (void) DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan)); - if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL)) { + if (ENGINE_ISSET_EVENT(p, VLAN_HEADER_TOO_SMALL)) { SCFree(p); return 1; } @@ -168,8 +166,9 @@ static int DecodeVLANtest01 (void) * \retval 1 on success * \retval 0 on failure */ -static int DecodeVLANtest02 (void) +static int DecodeVLANtest02(void) { + // clang-format off uint8_t raw_vlan[] = { 0x00, 0x20, 0x01, 0x00, 0x45, 0x00, 0x00, 0x34, 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, @@ -178,6 +177,7 @@ static int DecodeVLANtest02 (void) 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -189,8 +189,7 @@ static int DecodeVLANtest02 (void) DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan)); - - if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE)) { + if (ENGINE_ISSET_EVENT(p, VLAN_UNKNOWN_TYPE)) { SCFree(p); return 1; } @@ -205,8 +204,9 @@ static int DecodeVLANtest02 (void) * \retval 1 on success * \retval 0 on failure */ -static int DecodeVLANtest03 (void) +static int DecodeVLANtest03(void) { + // clang-format off uint8_t raw_vlan[] = { 0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, @@ -215,6 +215,7 @@ static int DecodeVLANtest03 (void) 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -228,16 +229,15 @@ static int DecodeVLANtest03 (void) DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan)); - - if(p->vlan_id[0] == 0) { + if (p->vlan_id[0] == 0) { goto error; } - if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL)) { + if (ENGINE_ISSET_EVENT(p, VLAN_HEADER_TOO_SMALL)) { goto error; } - if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE)) { + if (ENGINE_ISSET_EVENT(p, VLAN_UNKNOWN_TYPE)) { goto error; } diff --git a/src/decode-vlan.h b/src/decode-vlan.h index 809038dbe6fc..9c45fe99e856 100644 --- a/src/decode-vlan.h +++ b/src/decode-vlan.h @@ -28,18 +28,18 @@ uint16_t DecodeVLANGetId(const struct Packet_ *, uint8_t layer); /** Vlan type */ -#define ETHERNET_TYPE_VLAN 0x8100 +#define ETHERNET_TYPE_VLAN 0x8100 /** Vlan macros to access Vlan priority, Vlan CFI and VID */ -#define GET_VLAN_PRIORITY(vlanh) ((SCNtohs((vlanh)->vlan_cfi) & 0xe000) >> 13) -#define GET_VLAN_CFI(vlanh) ((SCNtohs((vlanh)->vlan_cfi) & 0x0100) >> 12) -#define GET_VLAN_ID(vlanh) ((uint16_t)(SCNtohs((vlanh)->vlan_cfi) & 0x0FFF)) -#define GET_VLAN_PROTO(vlanh) ((SCNtohs((vlanh)->protocol))) +#define GET_VLAN_PRIORITY(vlanh) ((SCNtohs((vlanh)->vlan_cfi) & 0xe000) >> 13) +#define GET_VLAN_CFI(vlanh) ((SCNtohs((vlanh)->vlan_cfi) & 0x0100) >> 12) +#define GET_VLAN_ID(vlanh) ((uint16_t)(SCNtohs((vlanh)->vlan_cfi) & 0x0FFF)) +#define GET_VLAN_PROTO(vlanh) ((SCNtohs((vlanh)->protocol))) /** Vlan header struct */ typedef struct VLANHdr_ { uint16_t vlan_cfi; - uint16_t protocol; /**< protocol field */ + uint16_t protocol; /**< protocol field */ } __attribute__((__packed__)) VLANHdr; /** VLAN header length */ @@ -52,4 +52,3 @@ void DecodeVLANRegisterTests(void); #define VLAN_MAX_LAYER_IDX (VLAN_MAX_LAYERS - 1) #endif /* __DECODE_VLAN_H__ */ - diff --git a/src/decode-vntag.c b/src/decode-vntag.c index 581f2570a31f..42c721299c27 100644 --- a/src/decode-vntag.c +++ b/src/decode-vntag.c @@ -34,9 +34,9 @@ #include "decode.h" #include "decode-events.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" /** * \internal @@ -83,7 +83,7 @@ int DecodeVNTag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t } #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "packet.h" /** @@ -115,6 +115,7 @@ static int DecodeVNTagtest01(void) */ static int DecodeVNTagtest02(void) { + // clang-format off uint8_t raw_vntag[] = { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x45, 0x00, 0x00, 0x64, 0xac, 0xe6, 0x00, 0x00, 0xff, 0xfd, 0x08, 0xb3, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0xe5, 0xa3, 0x95, 0x5c, 0x5d, 0x82, 0x50, 0x24, 0x6f, 0x56, 0xac, 0xf4, @@ -123,6 +124,7 @@ static int DecodeVNTagtest02(void) 0xe6, 0x4f, 0x5f, 0xa0, 0xb6, 0xa8, 0x93, 0x38, 0x8a, 0x17, 0xac, 0x6e, 0x3b, 0xbc, 0xad, 0x67, 0xad, 0xfc, 0x91, 0xf0, 0x16, 0x9d, 0xe2, 0xe1, 0xdf, 0x4f, 0x8c, 0xcb, 0xd3, 0xdc, 0xd9, 0xed, 0x3c, 0x0c, 0x92, 0xad, 0x8b, 0xf0, 0x2c, 0x2d, 0x55, 0x41 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -143,6 +145,7 @@ static int DecodeVNTagtest02(void) */ static int DecodeVNTagtest03(void) { + // clang-format off uint8_t raw_vntag[] = { 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x45, 0x00, 0x00, 0x64, 0xac, 0xe6, 0x00, 0x00, 0xff, 0xfd, 0x08, 0xb3, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0xe5, 0xa3, 0x95, 0x5c, 0x5d, 0x82, 0x50, 0x24, 0x6f, 0x56, 0xac, 0xf4, @@ -151,6 +154,7 @@ static int DecodeVNTagtest03(void) 0xe6, 0x4f, 0x5f, 0xa0, 0xb6, 0xa8, 0x93, 0x38, 0x8a, 0x17, 0xac, 0x6e, 0x3b, 0xbc, 0xad, 0x67, 0xad, 0xfc, 0x91, 0xf0, 0x16, 0x9d, 0xe2, 0xe1, 0xdf, 0x4f, 0x8c, 0xcb, 0xd3, 0xdc, 0xd9, 0xed, 0x3c, 0x0c, 0x92, 0xad, 0x8b, 0xf0, 0x2c, 0x2d, 0x55, 0x41 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); diff --git a/src/decode-vxlan.c b/src/decode-vxlan.c index 61dae9cfc235..0ab3fc1fc324 100644 --- a/src/decode-vxlan.c +++ b/src/decode-vxlan.c @@ -36,16 +36,16 @@ #include "flow.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/debug.h" #define VXLAN_HEADER_LEN sizeof(VXLANHeader) -#define VXLAN_MAX_PORTS 4 -#define VXLAN_UNSET_PORT -1 -#define VXLAN_DEFAULT_PORT 4789 -#define VXLAN_DEFAULT_PORT_S "4789" +#define VXLAN_MAX_PORTS 4 +#define VXLAN_UNSET_PORT -1 +#define VXLAN_DEFAULT_PORT 4789 +#define VXLAN_DEFAULT_PORT_S "4789" static bool g_vxlan_enabled = true; static int g_vxlan_ports_idx = 0; @@ -119,8 +119,7 @@ void DecodeVXLANConfig(void) /** \param pkt payload data directly above UDP header * \param len length in bytes of pkt */ -int DecodeVXLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len) +int DecodeVXLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) { DEBUG_VALIDATE_BUG_ON(pkt == NULL); @@ -195,8 +194,9 @@ int DecodeVXLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, * \test DecodeVXLANTest01 test a good vxlan header. * Contains a DNS request packet. */ -static int DecodeVXLANtest01 (void) +static int DecodeVXLANtest01(void) { + // clang-format off uint8_t raw_vxlan[] = { 0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, /* VXLAN header */ @@ -207,6 +207,7 @@ static int DecodeVXLANtest01 (void) 0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06, /* IPv4 hdr */ 0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */ }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; @@ -234,8 +235,9 @@ static int DecodeVXLANtest01 (void) /** * \test DecodeVXLANtest02 tests default port disabled by the config. */ -static int DecodeVXLANtest02 (void) +static int DecodeVXLANtest02(void) { + // clang-format off uint8_t raw_vxlan[] = { 0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, /* VXLAN header */ @@ -246,6 +248,7 @@ static int DecodeVXLANtest02 (void) 0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06, /* IPv4 hdr */ 0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */ }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); ThreadVars tv; @@ -270,9 +273,7 @@ static int DecodeVXLANtest02 (void) void DecodeVXLANRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeVXLANtest01", - DecodeVXLANtest01); - UtRegisterTest("DecodeVXLANtest02", - DecodeVXLANtest02); + UtRegisterTest("DecodeVXLANtest01", DecodeVXLANtest01); + UtRegisterTest("DecodeVXLANtest02", DecodeVXLANtest02); #endif /* UNITTESTS */ } diff --git a/src/decode.c b/src/decode.c index d302c7654675..8c8c99764a0b 100644 --- a/src/decode.c +++ b/src/decode.c @@ -38,7 +38,6 @@ * @{ */ - /** * \file * @@ -55,18 +54,18 @@ #include "flow-storage.h" #include "tmqh-packetpool.h" #include "app-layer.h" -#include "output.h" +#include "output/output.h" #include "decode-vxlan.h" #include "decode-geneve.h" #include "decode-erspan.h" #include "decode-teredo.h" -#include "util-hash.h" -#include "util-hash-string.h" -#include "util-print.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/hash.h" +#include "util/hash-string.h" +#include "util/print.h" +#include "util/profiling.h" +#include "util/validate.h" #include "action-globals.h" uint32_t default_packet_size = 0; @@ -151,8 +150,7 @@ void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) } } -void PacketUpdateEngineEventCounters(ThreadVars *tv, - DecodeThreadVars *dtv, Packet *p) +void PacketUpdateEngineEventCounters(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { for (uint8_t i = 0; i < p->events.cnt; i++) { const uint8_t e = p->events.events[i]; @@ -223,7 +221,7 @@ Packet *PacketGetFromQueueOrAlloc(void) inline int PacketCallocExtPkt(Packet *p, int datalen) { - if (! p->ext_pkt) { + if (!p->ext_pkt) { p->ext_pkt = SCCalloc(1, datalen); if (unlikely(p->ext_pkt == NULL)) { SET_PKT_LEN(p, 0); @@ -256,7 +254,7 @@ inline int PacketCopyDataOffset(Packet *p, uint32_t offset, const uint8_t *data, } /* Do we have already an packet with allocated data */ - if (! p->ext_pkt) { + if (!p->ext_pkt) { uint32_t newsize = offset + datalen; // check overflow if (newsize < offset) @@ -306,7 +304,7 @@ inline int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen) * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, - const uint8_t *pkt, uint32_t len, enum DecodeTunnelProto proto) + const uint8_t *pkt, uint32_t len, enum DecodeTunnelProto proto) { int ret; @@ -343,12 +341,10 @@ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *pare /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); - ret = DecodeTunnel(tv, dtv, p, GET_PKT_DATA(p), - GET_PKT_LEN(p), proto); + ret = DecodeTunnel(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), proto); if (unlikely(ret != TM_ECODE_OK) || - (proto == DECODE_TUNNEL_IPV6_TEREDO && (p->flags & PKT_IS_INVALID))) - { + (proto == DECODE_TUNNEL_IPV6_TEREDO && (p->flags & PKT_IS_INVALID))) { /* Not a (valid) tunnel packet */ SCLogDebug("tunnel packet is invalid"); @@ -358,7 +354,6 @@ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *pare SCReturnPtr(NULL, "Packet"); } - /* tell parent packet it's part of a tunnel */ SET_TUNNEL_PKT(parent); @@ -450,8 +445,7 @@ void PacketBypassCallback(Packet *p) * if we have failed to do it once */ if (p->flow) { int state = p->flow->flow_state; - if ((state == FLOW_STATE_LOCAL_BYPASSED) || - (state == FLOW_STATE_CAPTURE_BYPASSED)) { + if ((state == FLOW_STATE_LOCAL_BYPASSED) || (state == FLOW_STATE_CAPTURE_BYPASSED)) { return; } @@ -586,17 +580,15 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) dtv->counter_flow_spare_sync_avg = StatsRegisterAvgCounter("flow.wrk.spare_sync_avg", tv); dtv->counter_flow_spare_sync = StatsRegisterCounter("flow.wrk.spare_sync", tv); - dtv->counter_flow_spare_sync_incomplete = StatsRegisterCounter("flow.wrk.spare_sync_incomplete", tv); + dtv->counter_flow_spare_sync_incomplete = + StatsRegisterCounter("flow.wrk.spare_sync_incomplete", tv); dtv->counter_flow_spare_sync_empty = StatsRegisterCounter("flow.wrk.spare_sync_empty", tv); - dtv->counter_defrag_ipv4_fragments = - StatsRegisterCounter("defrag.ipv4.fragments", tv); + dtv->counter_defrag_ipv4_fragments = StatsRegisterCounter("defrag.ipv4.fragments", tv); dtv->counter_defrag_ipv4_reassembled = StatsRegisterCounter("defrag.ipv4.reassembled", tv); - dtv->counter_defrag_ipv6_fragments = - StatsRegisterCounter("defrag.ipv6.fragments", tv); + dtv->counter_defrag_ipv6_fragments = StatsRegisterCounter("defrag.ipv6.fragments", tv); dtv->counter_defrag_ipv6_reassembled = StatsRegisterCounter("defrag.ipv6.reassembled", tv); - dtv->counter_defrag_max_hit = - StatsRegisterCounter("defrag.max_frag_hits", tv); + dtv->counter_defrag_max_hit = StatsRegisterCounter("defrag.max_frag_hits", tv); for (int i = 0; i < DECODE_EVENT_MAX; i++) { BUG_ON(i != (int)DEvents[i].code); @@ -606,14 +598,11 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) else if (i > DECODE_EVENT_PACKET_MAX && !stats_stream_events) continue; - if (i < DECODE_EVENT_PACKET_MAX && - strncmp(DEvents[i].event_name, "decoder.", 8) == 0) - { + if (i < DECODE_EVENT_PACKET_MAX && strncmp(DEvents[i].event_name, "decoder.", 8) == 0) { SCMutexLock(&g_counter_table_mutex); if (g_counter_table == NULL) { - g_counter_table = HashTableInit(256, StringHashFunc, - StringHashCompareFunc, - StringHashFreeFunc); + g_counter_table = HashTableInit( + 256, StringHashFunc, StringHashCompareFunc, StringHashFreeFunc); if (g_counter_table == NULL) { FatalError("decoder counter hash " "table init failed"); @@ -623,8 +612,7 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) char name[256]; char *dot = strchr(DEvents[i].event_name, '.'); BUG_ON(!dot); - snprintf(name, sizeof(name), "%s.%s", - stats_decoder_events_prefix, dot+1); + snprintf(name, sizeof(name), "%s.%s", stats_decoder_events_prefix, dot + 1); const char *found = HashTableLookup(g_counter_table, name, 0); if (!found) { @@ -638,24 +626,21 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) "table name add failed"); found = add; } - dtv->counter_engine_events[i] = StatsRegisterCounter( - found, tv); + dtv->counter_engine_events[i] = StatsRegisterCounter(found, tv); SCMutexUnlock(&g_counter_table_mutex); } else { - dtv->counter_engine_events[i] = StatsRegisterCounter( - DEvents[i].event_name, tv); + dtv->counter_engine_events[i] = StatsRegisterCounter(DEvents[i].event_name, tv); } } return; } -void DecodeUpdatePacketCounters(ThreadVars *tv, - const DecodeThreadVars *dtv, const Packet *p) +void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p) { StatsIncr(tv, dtv->counter_pkts); - //StatsIncr(tv, dtv->counter_pkts_per_sec); + // StatsIncr(tv, dtv->counter_pkts_per_sec); StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); @@ -674,8 +659,7 @@ void AddressDebugPrint(Address *a) return; switch (a->family) { - case AF_INET: - { + case AF_INET: { char s[16]; PrintInet(AF_INET, (const void *)&a->addr_data32[0], s, sizeof(s)); SCLogDebug("%s", s); @@ -730,7 +714,7 @@ inline int PacketSetData(Packet *p, const uint8_t *pktdata, uint32_t pktlen) return -1; } // ext_pkt cannot be const (because we sometimes copy) - p->ext_pkt = (uint8_t *) pktdata; + p->ext_pkt = (uint8_t *)pktdata; p->flags |= PKT_ZERO_COPY; return 0; diff --git a/src/decode.h b/src/decode.h index 6392f3361e58..6b57b24d1495 100644 --- a/src/decode.h +++ b/src/decode.h @@ -24,13 +24,13 @@ #ifndef __DECODE_H__ #define __DECODE_H__ -//#define DBG_THREADS +// #define DBG_THREADS #define COUNTERS #include "suricata-common.h" #include "suricata-plugin.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" #include "decode-events.h" #ifdef PROFILING #include "flow-worker.h" @@ -38,7 +38,7 @@ #endif #ifdef HAVE_NAPATECH -#include "util-napatech.h" +#include "util/napatech.h" #endif /* HAVE_NAPATECH */ typedef enum { @@ -98,7 +98,6 @@ enum PktSrcEnum { #include "decode-vlan.h" #include "decode-mpls.h" - /* forward declarations */ struct DetectionEngineThreadCtx_; typedef struct AppLayerThreadCtx_ AppLayerThreadCtx; @@ -115,24 +114,25 @@ void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events); typedef struct Address_ { char family; union { - uint32_t address_un_data32[4]; /* type-specific field */ - uint16_t address_un_data16[8]; /* type-specific field */ - uint8_t address_un_data8[16]; /* type-specific field */ + uint32_t address_un_data32[4]; /* type-specific field */ + uint16_t address_un_data16[8]; /* type-specific field */ + uint8_t address_un_data8[16]; /* type-specific field */ struct in6_addr address_un_in6; } address; } Address; -#define addr_data32 address.address_un_data32 -#define addr_data16 address.address_un_data16 -#define addr_data8 address.address_un_data8 -#define addr_in6addr address.address_un_in6 - -#define COPY_ADDRESS(a, b) do { \ - (b)->family = (a)->family; \ - (b)->addr_data32[0] = (a)->addr_data32[0]; \ - (b)->addr_data32[1] = (a)->addr_data32[1]; \ - (b)->addr_data32[2] = (a)->addr_data32[2]; \ - (b)->addr_data32[3] = (a)->addr_data32[3]; \ +#define addr_data32 address.address_un_data32 +#define addr_data16 address.address_un_data16 +#define addr_data8 address.address_un_data8 +#define addr_in6addr address.address_un_in6 + +#define COPY_ADDRESS(a, b) \ + do { \ + (b)->family = (a)->family; \ + (b)->addr_data32[0] = (a)->addr_data32[0]; \ + (b)->addr_data32[1] = (a)->addr_data32[1]; \ + (b)->addr_data32[2] = (a)->addr_data32[2]; \ + (b)->addr_data32[3] = (a)->addr_data32[3]; \ } while (0) /* Set the IPv4 addresses into the Addrs of the Packet. @@ -140,70 +140,79 @@ typedef struct Address_ { * * We set the rest of the struct to 0 so we can * prevent using memset. */ -#define SET_IPV4_SRC_ADDR(p, a) do { \ - (a)->family = AF_INET; \ - (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \ - (a)->addr_data32[1] = 0; \ - (a)->addr_data32[2] = 0; \ - (a)->addr_data32[3] = 0; \ +#define SET_IPV4_SRC_ADDR(p, a) \ + do { \ + (a)->family = AF_INET; \ + (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \ + (a)->addr_data32[1] = 0; \ + (a)->addr_data32[2] = 0; \ + (a)->addr_data32[3] = 0; \ } while (0) -#define SET_IPV4_DST_ADDR(p, a) do { \ - (a)->family = AF_INET; \ - (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \ - (a)->addr_data32[1] = 0; \ - (a)->addr_data32[2] = 0; \ - (a)->addr_data32[3] = 0; \ +#define SET_IPV4_DST_ADDR(p, a) \ + do { \ + (a)->family = AF_INET; \ + (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \ + (a)->addr_data32[1] = 0; \ + (a)->addr_data32[2] = 0; \ + (a)->addr_data32[3] = 0; \ } while (0) /* Set the IPv6 addresses into the Addrs of the Packet. * Make sure p->ip6h is initialized and validated. */ -#define SET_IPV6_SRC_ADDR(p, a) do { \ - (a)->family = AF_INET6; \ - (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \ - (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \ - (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \ - (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \ +#define SET_IPV6_SRC_ADDR(p, a) \ + do { \ + (a)->family = AF_INET6; \ + (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \ + (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \ + (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \ + (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \ } while (0) -#define SET_IPV6_DST_ADDR(p, a) do { \ - (a)->family = AF_INET6; \ - (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \ - (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \ - (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \ - (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \ +#define SET_IPV6_DST_ADDR(p, a) \ + do { \ + (a)->family = AF_INET6; \ + (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \ + (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \ + (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \ + (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \ } while (0) /* Set the TCP ports into the Ports of the Packet. * Make sure p->tcph is initialized and validated. */ -#define SET_TCP_SRC_PORT(pkt, prt) do { \ - SET_PORT(TCP_GET_SRC_PORT((pkt)), *(prt)); \ +#define SET_TCP_SRC_PORT(pkt, prt) \ + do { \ + SET_PORT(TCP_GET_SRC_PORT((pkt)), *(prt)); \ } while (0) -#define SET_TCP_DST_PORT(pkt, prt) do { \ - SET_PORT(TCP_GET_DST_PORT((pkt)), *(prt)); \ +#define SET_TCP_DST_PORT(pkt, prt) \ + do { \ + SET_PORT(TCP_GET_DST_PORT((pkt)), *(prt)); \ } while (0) /* Set the UDP ports into the Ports of the Packet. * Make sure p->udph is initialized and validated. */ -#define SET_UDP_SRC_PORT(pkt, prt) do { \ - SET_PORT(UDP_GET_SRC_PORT((pkt)), *(prt)); \ +#define SET_UDP_SRC_PORT(pkt, prt) \ + do { \ + SET_PORT(UDP_GET_SRC_PORT((pkt)), *(prt)); \ } while (0) -#define SET_UDP_DST_PORT(pkt, prt) do { \ - SET_PORT(UDP_GET_DST_PORT((pkt)), *(prt)); \ +#define SET_UDP_DST_PORT(pkt, prt) \ + do { \ + SET_PORT(UDP_GET_DST_PORT((pkt)), *(prt)); \ } while (0) /* Set the SCTP ports into the Ports of the Packet. * Make sure p->sctph is initialized and validated. */ -#define SET_SCTP_SRC_PORT(pkt, prt) do { \ - SET_PORT(SCTP_GET_SRC_PORT((pkt)), *(prt)); \ +#define SET_SCTP_SRC_PORT(pkt, prt) \ + do { \ + SET_PORT(SCTP_GET_SRC_PORT((pkt)), *(prt)); \ } while (0) -#define SET_SCTP_DST_PORT(pkt, prt) do { \ - SET_PORT(SCTP_GET_DST_PORT((pkt)), *(prt)); \ +#define SET_SCTP_DST_PORT(pkt, prt) \ + do { \ + SET_PORT(SCTP_GET_DST_PORT((pkt)), *(prt)); \ } while (0) - #define GET_IPV4_SRC_ADDR_U32(p) ((p)->src.addr_data32[0]) #define GET_IPV4_DST_ADDR_U32(p) ((p)->dst.addr_data32[0]) #define GET_IPV4_SRC_ADDR_PTR(p) ((p)->src.addr_data32) @@ -211,57 +220,58 @@ typedef struct Address_ { #define GET_IPV6_SRC_IN6ADDR(p) ((p)->src.addr_in6addr) #define GET_IPV6_DST_IN6ADDR(p) ((p)->dst.addr_in6addr) -#define GET_IPV6_SRC_ADDR(p) ((p)->src.addr_data32) -#define GET_IPV6_DST_ADDR(p) ((p)->dst.addr_data32) -#define GET_TCP_SRC_PORT(p) ((p)->sp) -#define GET_TCP_DST_PORT(p) ((p)->dp) +#define GET_IPV6_SRC_ADDR(p) ((p)->src.addr_data32) +#define GET_IPV6_DST_ADDR(p) ((p)->dst.addr_data32) +#define GET_TCP_SRC_PORT(p) ((p)->sp) +#define GET_TCP_DST_PORT(p) ((p)->dp) #define GET_PKT_LEN(p) (p)->pktlen #define GET_PKT_DATA(p) (((p)->ext_pkt == NULL) ? GET_PKT_DIRECT_DATA(p) : (p)->ext_pkt) #define GET_PKT_DIRECT_DATA(p) (p)->pkt_data #define GET_PKT_DIRECT_MAX_SIZE(p) (default_packet_size) -#define SET_PKT_LEN(p, len) do { \ - (p)->pktlen = (len); \ +#define SET_PKT_LEN(p, len) \ + do { \ + (p)->pktlen = (len); \ } while (0) /* Port is just a uint16_t */ typedef uint16_t Port; -#define SET_PORT(v, p) ((p) = (v)) -#define COPY_PORT(a,b) ((b) = (a)) +#define SET_PORT(v, p) ((p) = (v)) +#define COPY_PORT(a, b) ((b) = (a)) -#define CMP_ADDR(a1, a2) \ - (((a1)->addr_data32[3] == (a2)->addr_data32[3] && \ - (a1)->addr_data32[2] == (a2)->addr_data32[2] && \ - (a1)->addr_data32[1] == (a2)->addr_data32[1] && \ - (a1)->addr_data32[0] == (a2)->addr_data32[0])) -#define CMP_PORT(p1, p2) \ - ((p1) == (p2)) +#define CMP_ADDR(a1, a2) \ + (((a1)->addr_data32[3] == (a2)->addr_data32[3] && \ + (a1)->addr_data32[2] == (a2)->addr_data32[2] && \ + (a1)->addr_data32[1] == (a2)->addr_data32[1] && \ + (a1)->addr_data32[0] == (a2)->addr_data32[0])) +#define CMP_PORT(p1, p2) ((p1) == (p2)) /*Given a packet pkt offset to the start of the ip header in a packet *We determine the ip version. */ #define IP_GET_RAW_VER(pkt) ((((pkt)[0] & 0xf0) >> 4)) -#define PKT_IS_IPV4(p) (((p)->ip4h != NULL)) -#define PKT_IS_IPV6(p) (((p)->ip6h != NULL)) -#define PKT_IS_TCP(p) (((p)->tcph != NULL)) -#define PKT_IS_UDP(p) (((p)->udph != NULL)) -#define PKT_IS_ICMPV4(p) (((p)->icmpv4h != NULL)) -#define PKT_IS_ICMPV6(p) (((p)->icmpv6h != NULL)) -#define PKT_IS_TOSERVER(p) (((p)->flowflags & FLOW_PKT_TOSERVER)) -#define PKT_IS_TOCLIENT(p) (((p)->flowflags & FLOW_PKT_TOCLIENT)) +#define PKT_IS_IPV4(p) (((p)->ip4h != NULL)) +#define PKT_IS_IPV6(p) (((p)->ip6h != NULL)) +#define PKT_IS_TCP(p) (((p)->tcph != NULL)) +#define PKT_IS_UDP(p) (((p)->udph != NULL)) +#define PKT_IS_ICMPV4(p) (((p)->icmpv4h != NULL)) +#define PKT_IS_ICMPV6(p) (((p)->icmpv6h != NULL)) +#define PKT_IS_TOSERVER(p) (((p)->flowflags & FLOW_PKT_TOSERVER)) +#define PKT_IS_TOCLIENT(p) (((p)->flowflags & FLOW_PKT_TOCLIENT)) #define IPH_IS_VALID(p) (PKT_IS_IPV4((p)) || PKT_IS_IPV6((p))) /* Retrieve proto regardless of IP version */ -#define IP_GET_IPPROTO(p) \ - (p->proto ? p->proto : \ - (PKT_IS_IPV4((p))? IPV4_GET_IPPROTO((p)) : (PKT_IS_IPV6((p))? IPV6_GET_L4PROTO((p)) : 0))) +#define IP_GET_IPPROTO(p) \ + (p->proto ? p->proto \ + : (PKT_IS_IPV4((p)) ? IPV4_GET_IPPROTO((p)) \ + : (PKT_IS_IPV6((p)) ? IPV6_GET_L4PROTO((p)) : 0))) /* structure to store the sids/gids/etc the detection engine * found in this packet */ typedef struct PacketAlert_ { - SigIntId num; /* Internal num, used for sorting */ + SigIntId num; /* Internal num, used for sorting */ uint8_t action; /* Internal num, used for thresholding */ uint8_t flags; const struct Signature_ *s; @@ -272,13 +282,13 @@ typedef struct PacketAlert_ { /* flag to indicate the rule action (drop/pass) needs to be applied to the flow */ #define PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW 0x1 /** alert was generated based on state */ -#define PACKET_ALERT_FLAG_STATE_MATCH 0x02 +#define PACKET_ALERT_FLAG_STATE_MATCH 0x02 /** alert was generated based on stream */ -#define PACKET_ALERT_FLAG_STREAM_MATCH 0x04 +#define PACKET_ALERT_FLAG_STREAM_MATCH 0x04 /** alert is in a tx, tx_id set */ -#define PACKET_ALERT_FLAG_TX 0x08 +#define PACKET_ALERT_FLAG_TX 0x08 /** action was changed by rate_filter */ -#define PACKET_ALERT_RATE_FILTER_MODIFIED 0x10 +#define PACKET_ALERT_RATE_FILTER_MODIFIED 0x10 /** alert is in a frame, frame_id set */ #define PACKET_ALERT_FLAG_FRAME 0x20 @@ -305,8 +315,8 @@ void PacketAlertFree(PacketAlert *pa); /** data structure to store decoder, defrag and stream events */ typedef struct PacketEngineEvents_ { - uint8_t cnt; /**< number of events */ - uint8_t events[PACKET_ENGINE_EVENT_MAX]; /**< array of events */ + uint8_t cnt; /**< number of events */ + uint8_t events[PACKET_ENGINE_EVENT_MAX]; /**< array of events */ } PacketEngineEvents; typedef struct PktVar_ { @@ -369,7 +379,7 @@ typedef struct PktProfilingPrefilterEngine_ { typedef struct PktProfilingPrefilterData_ { PktProfilingPrefilterEngine *engines; - uint32_t size; /**< array size */ + uint32_t size; /**< array size */ } PktProfilingPrefilterData; /** \brief Per pkt stats storage */ @@ -426,8 +436,7 @@ struct PacketQueue_; * * sum of above 44/48 bytes */ -typedef struct Packet_ -{ +typedef struct Packet_ { /* Addresses, Ports and protocol * these are on top so we can use * the Packet as a hash key */ @@ -550,9 +559,9 @@ typedef struct Packet_ ICMPV4Vars icmpv4vars; ICMPV6Vars icmpv6vars; } l4vars; -#define tcpvars l4vars.tcpvars -#define icmpv4vars l4vars.icmpv4vars -#define icmpv6vars l4vars.icmpv6vars +#define tcpvars l4vars.tcpvars +#define icmpv4vars l4vars.icmpv4vars +#define icmpv6vars l4vars.icmpv6vars TCPHdr *tcph; @@ -597,7 +606,6 @@ typedef struct Packet_ /** packet number in the pcap file, matches wireshark */ uint64_t pcap_cnt; - /* engine events */ PacketEngineEvents events; @@ -660,7 +668,7 @@ typedef struct Packet_ /** highest mtu of the interfaces we monitor */ #define DEFAULT_MTU 1500 -#define MINIMUM_MTU 68 /**< ipv4 minimum: rfc791 */ +#define MINIMUM_MTU 68 /**< ipv4 minimum: rfc791 */ #define DEFAULT_PACKET_SIZE (DEFAULT_MTU + ETHERNET_HEADER_LEN) /* storage: maximum ip packet size + link header */ @@ -669,8 +677,7 @@ extern uint32_t default_packet_size; #define SIZE_OF_PACKET (default_packet_size + sizeof(Packet)) /** \brief Structure to hold thread specific data for all decode modules */ -typedef struct DecodeThreadVars_ -{ +typedef struct DecodeThreadVars_ { /** Specific context for udp protocol detection (here atm) */ AppLayerThreadCtx *app_tctx; @@ -759,30 +766,34 @@ typedef struct DecodeThreadVars_ void CaptureStatsUpdate(ThreadVars *tv, const Packet *p); void CaptureStatsSetup(ThreadVars *tv); -#define PACKET_CLEAR_L4VARS(p) do { \ - memset(&(p)->l4vars, 0x00, sizeof((p)->l4vars)); \ +#define PACKET_CLEAR_L4VARS(p) \ + do { \ + memset(&(p)->l4vars, 0x00, sizeof((p)->l4vars)); \ } while (0) /** * \brief reset these to -1(indicates that the packet is fresh from the queue) */ -#define PACKET_RESET_CHECKSUMS(p) do { \ - (p)->level3_comp_csum = -1; \ - (p)->level4_comp_csum = -1; \ +#define PACKET_RESET_CHECKSUMS(p) \ + do { \ + (p)->level3_comp_csum = -1; \ + (p)->level4_comp_csum = -1; \ } while (0) /* if p uses extended data, free them */ -#define PACKET_FREE_EXTDATA(p) do { \ - if ((p)->ext_pkt) { \ - if (!((p)->flags & PKT_ZERO_COPY)) { \ - SCFree((p)->ext_pkt); \ - } \ - (p)->ext_pkt = NULL; \ - } \ - } while(0) - -#define TUNNEL_INCR_PKT_RTV_NOLOCK(p) do { \ - ((p)->root ? (p)->root->tunnel_rtv_cnt++ : (p)->tunnel_rtv_cnt++); \ +#define PACKET_FREE_EXTDATA(p) \ + do { \ + if ((p)->ext_pkt) { \ + if (!((p)->flags & PKT_ZERO_COPY)) { \ + SCFree((p)->ext_pkt); \ + } \ + (p)->ext_pkt = NULL; \ + } \ + } while (0) + +#define TUNNEL_INCR_PKT_RTV_NOLOCK(p) \ + do { \ + ((p)->root ? (p)->root->tunnel_rtv_cnt++ : (p)->tunnel_rtv_cnt++); \ } while (0) static inline void TUNNEL_INCR_PKT_TPR(Packet *p) @@ -796,10 +807,10 @@ static inline void TUNNEL_INCR_PKT_TPR(Packet *p) #define TUNNEL_PKT_RTV(p) ((p)->root ? (p)->root->tunnel_rtv_cnt : (p)->tunnel_rtv_cnt) #define TUNNEL_PKT_TPR(p) ((p)->root ? (p)->root->tunnel_tpr_cnt : (p)->tunnel_tpr_cnt) -#define IS_TUNNEL_PKT(p) (((p)->flags & PKT_TUNNEL)) -#define SET_TUNNEL_PKT(p) ((p)->flags |= PKT_TUNNEL) -#define UNSET_TUNNEL_PKT(p) ((p)->flags &= ~PKT_TUNNEL) -#define IS_TUNNEL_ROOT_PKT(p) (IS_TUNNEL_PKT(p) && (p)->root == NULL) +#define IS_TUNNEL_PKT(p) (((p)->flags & PKT_TUNNEL)) +#define SET_TUNNEL_PKT(p) ((p)->flags |= PKT_TUNNEL) +#define UNSET_TUNNEL_PKT(p) ((p)->flags &= ~PKT_TUNNEL) +#define IS_TUNNEL_ROOT_PKT(p) (IS_TUNNEL_PKT(p) && (p)->root == NULL) #define IS_TUNNEL_PKT_VERDICTED(p) (((p)->flags & PKT_TUNNEL_VERDICTED)) #define SET_TUNNEL_PKT_VERDICTED(p) ((p)->flags |= PKT_TUNNEL_VERDICTED) @@ -818,15 +829,14 @@ enum DecodeTunnelProto { }; Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, - const uint8_t *pkt, uint32_t len, enum DecodeTunnelProto proto); + const uint8_t *pkt, uint32_t len, enum DecodeTunnelProto proto); Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, uint8_t proto); void PacketDefragPktSetupParent(Packet *parent); void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *); Packet *PacketGetFromQueueOrAlloc(void); Packet *PacketGetFromAlloc(void); void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p); -void PacketUpdateEngineEventCounters(ThreadVars *tv, - DecodeThreadVars *dtv, Packet *p); +void PacketUpdateEngineEventCounters(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p); void PacketFree(Packet *p); void PacketFreeOrRelease(Packet *p); int PacketCallocExtPkt(Packet *p, int datalen); @@ -839,8 +849,7 @@ void PacketSwap(Packet *p); DecodeThreadVars *DecodeThreadVarsAlloc(ThreadVars *); void DecodeThreadVarsFree(ThreadVars *, DecodeThreadVars *); -void DecodeUpdatePacketCounters(ThreadVars *tv, - const DecodeThreadVars *dtv, const Packet *p); +void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p); const char *PacketDropReasonToString(enum PacketDropReason r); /* decoder functions */ @@ -873,45 +882,45 @@ int DecodeTEMPLATE(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, int DecodeNSH(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); #ifdef UNITTESTS -void DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt, - uint16_t hdrextlen, uint16_t plen, - uint16_t prev_hdrextlen); +void DecodeIPV6FragHeader( + Packet *p, const uint8_t *pkt, uint16_t hdrextlen, uint16_t plen, uint16_t prev_hdrextlen); #endif void AddressDebugPrint(Address *); -typedef int (*DecoderFunc)(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - const uint8_t *pkt, uint32_t len); +typedef int (*DecoderFunc)( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len); void DecodeGlobalConfig(void); void PacketAlertGetMaxConfig(void); void DecodeUnregisterCounters(void); -#define ENGINE_SET_EVENT(p, e) do { \ - SCLogDebug("p %p event %d", (p), e); \ - if ((p)->events.cnt < PACKET_ENGINE_EVENT_MAX) { \ - (p)->events.events[(p)->events.cnt] = e; \ - (p)->events.cnt++; \ - } \ -} while(0) - -#define ENGINE_SET_INVALID_EVENT(p, e) do { \ - p->flags |= PKT_IS_INVALID; \ - ENGINE_SET_EVENT(p, e); \ -} while(0) - - - -#define ENGINE_ISSET_EVENT(p, e) ({ \ - int r = 0; \ - uint8_t u; \ - for (u = 0; u < (p)->events.cnt; u++) { \ - if ((p)->events.events[u] == (e)) { \ - r = 1; \ - break; \ - } \ - } \ - r; \ -}) +#define ENGINE_SET_EVENT(p, e) \ + do { \ + SCLogDebug("p %p event %d", (p), e); \ + if ((p)->events.cnt < PACKET_ENGINE_EVENT_MAX) { \ + (p)->events.events[(p)->events.cnt] = e; \ + (p)->events.cnt++; \ + } \ + } while (0) + +#define ENGINE_SET_INVALID_EVENT(p, e) \ + do { \ + p->flags |= PKT_IS_INVALID; \ + ENGINE_SET_EVENT(p, e); \ + } while (0) + +#define ENGINE_ISSET_EVENT(p, e) \ + ({ \ + int r = 0; \ + uint8_t u; \ + for (u = 0; u < (p)->events.cnt; u++) { \ + if ((p)->events.events[u] == (e)) { \ + r = 1; \ + break; \ + } \ + } \ + r; \ + }) #ifndef IPPROTO_IPIP #define IPPROTO_IPIP 4 @@ -958,9 +967,9 @@ void DecodeUnregisterCounters(void); /* taken from pcap's bpf.h */ #ifndef DLT_RAW #ifdef __OpenBSD__ -#define DLT_RAW 14 /* raw IP */ +#define DLT_RAW 14 /* raw IP */ #else -#define DLT_RAW 12 /* raw IP */ +#define DLT_RAW 12 /* raw IP */ #endif #endif @@ -970,11 +979,11 @@ void DecodeUnregisterCounters(void); /** libpcap shows us the way to linktype codes * \todo we need more & maybe put them in a separate file? */ -#define LINKTYPE_NULL DLT_NULL -#define LINKTYPE_ETHERNET DLT_EN10MB -#define LINKTYPE_LINUX_SLL 113 -#define LINKTYPE_PPP 9 -#define LINKTYPE_RAW DLT_RAW +#define LINKTYPE_NULL DLT_NULL +#define LINKTYPE_ETHERNET DLT_EN10MB +#define LINKTYPE_LINUX_SLL 113 +#define LINKTYPE_PPP 9 +#define LINKTYPE_RAW DLT_RAW /* http://www.tcpdump.org/linktypes.html defines DLT_RAW as 101, yet others don't. * Libpcap on at least OpenBSD returns 101 as datalink type for RAW pcaps though. */ #define LINKTYPE_RAW2 101 @@ -1055,8 +1064,7 @@ void DecodeUnregisterCounters(void); #define PKT_FIRST_TAG BIT_U32(30) /** \brief return 1 if the packet is a pseudo packet */ -#define PKT_IS_PSEUDOPKT(p) \ - ((p)->flags & (PKT_PSEUDO_STREAM_END|PKT_PSEUDO_DETECTLOG_FLUSH)) +#define PKT_IS_PSEUDOPKT(p) ((p)->flags & (PKT_PSEUDO_STREAM_END | PKT_PSEUDO_DETECTLOG_FLUSH)) #define PKT_SET_SRC(p, src_val) ((p)->pkt_src = src_val) @@ -1113,7 +1121,8 @@ static inline bool VerdictTunnelPacket(Packet *p) if (IS_TUNNEL_ROOT_PKT(p) && !IS_TUNNEL_PKT_VERDICTED(p) && !outstanding) { // verdict SCLogDebug("root %p: verdict", p); - } else if (!IS_TUNNEL_ROOT_PKT(p) && outstanding == 1 && p->root && IS_TUNNEL_PKT_VERDICTED(p->root)) { + } else if (!IS_TUNNEL_ROOT_PKT(p) && outstanding == 1 && p->root && + IS_TUNNEL_PKT_VERDICTED(p->root)) { // verdict SCLogDebug("tunnel %p: verdict", p); } else { @@ -1123,8 +1132,8 @@ static inline bool VerdictTunnelPacket(Packet *p) return verdict; } -static inline void DecodeLinkLayer(ThreadVars *tv, DecodeThreadVars *dtv, - const int datalink, Packet *p, const uint8_t *data, const uint32_t len) +static inline void DecodeLinkLayer(ThreadVars *tv, DecodeThreadVars *dtv, const int datalink, + Packet *p, const uint8_t *data, const uint32_t len) { /* call the decoder */ switch (datalink) { @@ -1144,7 +1153,7 @@ static inline void DecodeLinkLayer(ThreadVars *tv, DecodeThreadVars *dtv, case LINKTYPE_NULL: DecodeNull(tv, dtv, p, data, len); break; - case LINKTYPE_CISCO_HDLC: + case LINKTYPE_CISCO_HDLC: DecodeCHDLC(tv, dtv, p, data, len); break; default: @@ -1157,8 +1166,8 @@ static inline void DecodeLinkLayer(ThreadVars *tv, DecodeThreadVars *dtv, /** \brief decode network layer * \retval bool true if successful, false if unknown */ -static inline bool DecodeNetworkLayer(ThreadVars *tv, DecodeThreadVars *dtv, - const uint16_t proto, Packet *p, const uint8_t *data, const uint32_t len) +static inline bool DecodeNetworkLayer(ThreadVars *tv, DecodeThreadVars *dtv, const uint16_t proto, + Packet *p, const uint8_t *data, const uint32_t len) { switch (proto) { case ETHERNET_TYPE_IP: { @@ -1181,7 +1190,7 @@ static inline bool DecodeNetworkLayer(ThreadVars *tv, DecodeThreadVars *dtv, case ETHERNET_TYPE_8021AD: case ETHERNET_TYPE_8021QINQ: if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { - ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); + ENGINE_SET_EVENT(p, VLAN_HEADER_TOO_MANY_LAYERS); } else { DecodeVLAN(tv, dtv, p, data, len); } diff --git a/src/defrag-config.c b/src/defrag-config.c index 7e2ae0cde96a..ae3044556fda 100644 --- a/src/defrag-config.c +++ b/src/defrag-config.c @@ -24,8 +24,8 @@ #include "suricata-common.h" #include "defrag-config.h" -#include "util-misc.h" -#include "util-radix-tree.h" +#include "util/misc.h" +#include "util/radix-tree.h" static SCRadixTree *defrag_tree = NULL; @@ -43,7 +43,7 @@ static void DefragPolicyAddHostInfo(char *host_ip_range, uint64_t timeout) { uint64_t *user_data = NULL; - if ( (user_data = SCMalloc(sizeof(uint64_t))) == NULL) { + if ((user_data = SCMalloc(sizeof(uint64_t))) == NULL) { FatalError("Error allocating memory. Exiting"); } @@ -108,7 +108,7 @@ static void DefragParseParameters(ConfNode *n) ConfNode *si; uint64_t timeout = 0; - TAILQ_FOREACH(si, &n->head, next) { + TAILQ_FOREACH (si, &n->head, next) { if (strcasecmp("timeout", si->name) == 0) { SCLogDebug("timeout value %s", si->val); if (ParseSizeStringU64(si->val, &timeout) < 0) { @@ -118,7 +118,7 @@ static void DefragParseParameters(ConfNode *n) } if (strcasecmp("address", si->name) == 0) { ConfNode *pval; - TAILQ_FOREACH(pval, &si->head, next) { + TAILQ_FOREACH (pval, &si->head, next) { DefragPolicyAddHostInfo(pval->val, timeout); } } @@ -149,10 +149,10 @@ void DefragPolicyLoadFromConfig(void) SCLogDebug("configuring host config %p", server_config); ConfNode *sc; - TAILQ_FOREACH(sc, &server_config->head, next) { + TAILQ_FOREACH (sc, &server_config->head, next) { ConfNode *p = NULL; - TAILQ_FOREACH(p, &sc->head, next) { + TAILQ_FOREACH (p, &sc->head, next) { SCLogDebug("parsing configuration for %s", p->name); DefragParseParameters(p); } diff --git a/src/defrag-hash.c b/src/defrag-hash.c index eb754d6eface..985a77d4ab17 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -20,17 +20,17 @@ #include "defrag-hash.h" #include "defrag-queue.h" #include "defrag-config.h" -#include "util-random.h" -#include "util-byte.h" -#include "util-misc.h" -#include "util-hash-lookup3.h" +#include "util/random.h" +#include "util/byte.h" +#include "util/misc.h" +#include "util/hash-lookup3.h" /** defrag tracker hash table */ DefragTrackerHashRow *defragtracker_hash; DefragConfig defrag_config; -SC_ATOMIC_DECLARE(uint64_t,defrag_memuse); -SC_ATOMIC_DECLARE(unsigned int,defragtracker_counter); -SC_ATOMIC_DECLARE(unsigned int,defragtracker_prune_idx); +SC_ATOMIC_DECLARE(uint64_t, defrag_memuse); +SC_ATOMIC_DECLARE(unsigned int, defragtracker_counter); +SC_ATOMIC_DECLARE(unsigned int, defragtracker_prune_idx); static DefragTracker *DefragTrackerGetUsedDefragTracker(void); @@ -82,7 +82,7 @@ uint32_t DefragTrackerSpareQueueGetSize(void) void DefragTrackerMoveToSpare(DefragTracker *h) { DefragTrackerEnqueue(&defragtracker_spare_q, h); - (void) SC_ATOMIC_SUB(defragtracker_counter, 1); + (void)SC_ATOMIC_SUB(defragtracker_counter, 1); } static DefragTracker *DefragTrackerAlloc(void) @@ -91,7 +91,7 @@ static DefragTracker *DefragTrackerAlloc(void) return NULL; } - (void) SC_ATOMIC_ADD(defrag_memuse, sizeof(DefragTracker)); + (void)SC_ATOMIC_ADD(defrag_memuse, sizeof(DefragTracker)); DefragTracker *dt = SCCalloc(1, sizeof(DefragTracker)); if (unlikely(dt == NULL)) @@ -112,14 +112,12 @@ static void DefragTrackerFree(DefragTracker *dt) SCMutexDestroy(&dt->lock); SCFree(dt); - (void) SC_ATOMIC_SUB(defrag_memuse, sizeof(DefragTracker)); + (void)SC_ATOMIC_SUB(defrag_memuse, sizeof(DefragTracker)); } } -#define DefragTrackerIncrUsecnt(dt) \ - SC_ATOMIC_ADD((dt)->use_cnt, 1) -#define DefragTrackerDecrUsecnt(dt) \ - SC_ATOMIC_SUB((dt)->use_cnt, 1) +#define DefragTrackerIncrUsecnt(dt) SC_ATOMIC_ADD((dt)->use_cnt, 1) +#define DefragTrackerDecrUsecnt(dt) SC_ATOMIC_SUB((dt)->use_cnt, 1) static void DefragTrackerInit(DefragTracker *dt, Packet *p) { @@ -141,12 +139,12 @@ static void DefragTrackerInit(DefragTracker *dt, Packet *p) dt->remove = 0; dt->seen_last = 0; - (void) DefragTrackerIncrUsecnt(dt); + (void)DefragTrackerIncrUsecnt(dt); } void DefragTrackerRelease(DefragTracker *t) { - (void) DefragTrackerDecrUsecnt(t); + (void)DefragTrackerDecrUsecnt(t); SCMutexUnlock(&t->lock); } @@ -156,7 +154,7 @@ void DefragTrackerClearMemory(DefragTracker *dt) } #define DEFRAG_DEFAULT_HASHSIZE 4096 -#define DEFRAG_DEFAULT_MEMCAP 16777216 +#define DEFRAG_DEFAULT_MEMCAP 16777216 #define DEFRAG_DEFAULT_PREALLOC 1000 /** \brief initialize the configuration @@ -165,8 +163,8 @@ void DefragInitConfig(bool quiet) { SCLogDebug("initializing defrag engine..."); - memset(&defrag_config, 0, sizeof(defrag_config)); - //SC_ATOMIC_INIT(flow_flags); + memset(&defrag_config, 0, sizeof(defrag_config)); + // SC_ATOMIC_INIT(flow_flags); SC_ATOMIC_INIT(defragtracker_counter); SC_ATOMIC_INIT(defrag_memuse); SC_ATOMIC_INIT(defragtracker_prune_idx); @@ -174,9 +172,9 @@ void DefragInitConfig(bool quiet) DefragTrackerQueueInit(&defragtracker_spare_q); /* set defaults */ - defrag_config.hash_rand = (uint32_t)RandomGet(); - defrag_config.hash_size = DEFRAG_DEFAULT_HASHSIZE; - defrag_config.prealloc = DEFRAG_DEFAULT_PREALLOC; + defrag_config.hash_rand = (uint32_t)RandomGet(); + defrag_config.hash_size = DEFRAG_DEFAULT_HASHSIZE; + defrag_config.prealloc = DEFRAG_DEFAULT_PREALLOC; SC_ATOMIC_SET(defrag_config.memcap, DEFRAG_DEFAULT_MEMCAP); defrag_config.memcap_policy = ExceptionPolicyParse("defrag.memcap-policy", false); @@ -186,8 +184,7 @@ void DefragInitConfig(bool quiet) uint64_t defrag_memcap; /** set config values for memcap, prealloc and hash_size */ - if ((ConfGet("defrag.memcap", &conf_val)) == 1) - { + if ((ConfGet("defrag.memcap", &conf_val)) == 1) { if (ParseSizeStringU64(conf_val, &defrag_memcap) < 0) { SCLogError("Error parsing defrag.memcap " "from conf file - %s. Killing engine", @@ -197,29 +194,24 @@ void DefragInitConfig(bool quiet) SC_ATOMIC_SET(defrag_config.memcap, defrag_memcap); } } - if ((ConfGet("defrag.hash-size", &conf_val)) == 1) - { - if (StringParseUint32(&configval, 10, strlen(conf_val), - conf_val) > 0) { + if ((ConfGet("defrag.hash-size", &conf_val)) == 1) { + if (StringParseUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { defrag_config.hash_size = configval; } else { - WarnInvalidConfEntry("defrag.hash-size", "%"PRIu32, defrag_config.hash_size); + WarnInvalidConfEntry("defrag.hash-size", "%" PRIu32, defrag_config.hash_size); } } - - if ((ConfGet("defrag.trackers", &conf_val)) == 1) - { - if (StringParseUint32(&configval, 10, strlen(conf_val), - conf_val) > 0) { + if ((ConfGet("defrag.trackers", &conf_val)) == 1) { + if (StringParseUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { defrag_config.prealloc = configval; } else { - WarnInvalidConfEntry("defrag.trackers", "%"PRIu32, defrag_config.prealloc); + WarnInvalidConfEntry("defrag.trackers", "%" PRIu32, defrag_config.prealloc); } } - SCLogDebug("DefragTracker config from suricata.yaml: memcap: %"PRIu64", hash-size: " - "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(defrag_config.memcap), - defrag_config.hash_size, defrag_config.prealloc); + SCLogDebug("DefragTracker config from suricata.yaml: memcap: %" PRIu64 ", hash-size: " + "%" PRIu32 ", prealloc: %" PRIu32, + SC_ATOMIC_GET(defrag_config.memcap), defrag_config.hash_size, defrag_config.prealloc); /* alloc hash memory */ uint64_t hash_size = defrag_config.hash_size * sizeof(DefragTrackerHashRow); @@ -243,17 +235,16 @@ void DefragInitConfig(bool quiet) for (i = 0; i < defrag_config.hash_size; i++) { DRLOCK_INIT(&defragtracker_hash[i]); } - (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow))); + (void)SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow))); if (!quiet) { - SCLogConfig("allocated %"PRIu64" bytes of memory for the defrag hash... " - "%" PRIu32 " buckets of size %" PRIuMAX "", - SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size, - (uintmax_t)sizeof(DefragTrackerHashRow)); + SCLogConfig("allocated %" PRIu64 " bytes of memory for the defrag hash... " + "%" PRIu32 " buckets of size %" PRIuMAX "", + SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size, + (uintmax_t)sizeof(DefragTrackerHashRow)); } - if ((ConfGet("defrag.prealloc", &conf_val)) == 1) - { + if ((ConfGet("defrag.prealloc", &conf_val)) == 1) { if (ConfValIsTrue(conf_val)) { /* pre allocate defrag trackers */ for (i = 0; i < defrag_config.prealloc; i++) { @@ -272,7 +263,7 @@ void DefragInitConfig(bool quiet) SCLogError("preallocating defrag failed: %s", strerror(errno)); exit(EXIT_FAILURE); } - DefragTrackerEnqueue(&defragtracker_spare_q,h); + DefragTrackerEnqueue(&defragtracker_spare_q, h); } if (!quiet) { SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "", @@ -282,7 +273,7 @@ void DefragInitConfig(bool quiet) } if (!quiet) { - SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64, + SCLogConfig("defrag memory usage: %" PRIu64 " bytes, maximum: %" PRIu64, SC_ATOMIC_GET(defrag_memuse), SC_ATOMIC_GET(defrag_config.memcap)); } @@ -291,7 +282,7 @@ void DefragInitConfig(bool quiet) /** \brief print some defrag stats * \warning Not thread safe */ -static void DefragTrackerPrintStats (void) +static void DefragTrackerPrintStats(void) { } @@ -305,7 +296,7 @@ void DefragHashShutdown(void) DefragTrackerPrintStats(); /* free spare queue */ - while((dt = DefragTrackerDequeue(&defragtracker_spare_q))) { + while ((dt = DefragTrackerDequeue(&defragtracker_spare_q))) { BUG_ON(SC_ATOMIC_GET(dt->use_cnt) > 0); DefragTrackerFree(dt); } @@ -326,7 +317,7 @@ void DefragHashShutdown(void) SCFree(defragtracker_hash); defragtracker_hash = NULL; } - (void) SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow)); + (void)SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow)); DefragTrackerQueueDestroy(&defragtracker_spare_q); return; } @@ -485,12 +476,12 @@ static DefragTracker *DefragTrackerGetNew(Packet *p) /* If we reached the max memcap, we get a used tracker */ if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) { /* declare state of emergency */ - //if (!(SC_ATOMIC_GET(defragtracker_flags) & DEFRAG_EMERGENCY)) { - // SC_ATOMIC_OR(defragtracker_flags, DEFRAG_EMERGENCY); + // if (!(SC_ATOMIC_GET(defragtracker_flags) & DEFRAG_EMERGENCY)) { + // SC_ATOMIC_OR(defragtracker_flags, DEFRAG_EMERGENCY); - /* under high load, waking up the flow mgr each time leads - * to high cpu usage. Flows are not timed out much faster if - * we check a 1000 times a second. */ + /* under high load, waking up the flow mgr each time leads + * to high cpu usage. Flows are not timed out much faster if + * we check a 1000 times a second. */ // FlowWakeupFlowManagerThread(); //} @@ -517,7 +508,7 @@ static DefragTracker *DefragTrackerGetNew(Packet *p) /* tracker is initialized (recycled) but *unlocked* */ } - (void) SC_ATOMIC_ADD(defragtracker_counter, 1); + (void)SC_ATOMIC_ADD(defragtracker_counter, 1); SCMutexLock(&dt->lock); return dt; } @@ -530,7 +521,7 @@ static DefragTracker *DefragTrackerGetNew(Packet *p) * * returns a *LOCKED* tracker or NULL */ -DefragTracker *DefragGetTrackerFromHash (Packet *p) +DefragTracker *DefragGetTrackerFromHash(Packet *p) { DefragTracker *dt = NULL; @@ -553,7 +544,7 @@ DefragTracker *DefragGetTrackerFromHash (Packet *p) hb->tail = dt; /* got one, now lock, initialize and return */ - DefragTrackerInit(dt,p); + DefragTrackerInit(dt, p); DRLOCK_UNLOCK(hb); return dt; @@ -583,7 +574,7 @@ DefragTracker *DefragGetTrackerFromHash (Packet *p) dt->hprev = pdt; /* initialize and return */ - DefragTrackerInit(dt,p); + DefragTrackerInit(dt, p); DRLOCK_UNLOCK(hb); return dt; @@ -609,7 +600,7 @@ DefragTracker *DefragGetTrackerFromHash (Packet *p) /* found our tracker, lock & return */ SCMutexLock(&dt->lock); - (void) DefragTrackerIncrUsecnt(dt); + (void)DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } @@ -618,7 +609,7 @@ DefragTracker *DefragGetTrackerFromHash (Packet *p) /* lock & return */ SCMutexLock(&dt->lock); - (void) DefragTrackerIncrUsecnt(dt); + (void)DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } @@ -629,7 +620,7 @@ DefragTracker *DefragGetTrackerFromHash (Packet *p) * * \retval h *LOCKED* tracker or NULL */ -DefragTracker *DefragLookupTrackerFromHash (Packet *p) +DefragTracker *DefragLookupTrackerFromHash(Packet *p) { DefragTracker *dt = NULL; @@ -678,7 +669,7 @@ DefragTracker *DefragLookupTrackerFromHash (Packet *p) /* found our tracker, lock & return */ SCMutexLock(&dt->lock); - (void) DefragTrackerIncrUsecnt(dt); + (void)DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } @@ -687,7 +678,7 @@ DefragTracker *DefragLookupTrackerFromHash (Packet *p) /* lock & return */ SCMutexLock(&dt->lock); - (void) DefragTrackerIncrUsecnt(dt); + (void)DefragTrackerIncrUsecnt(dt); DRLOCK_UNLOCK(hb); return dt; } @@ -754,11 +745,9 @@ static DefragTracker *DefragTrackerGetUsedDefragTracker(void) SCMutexUnlock(&dt->lock); - (void) SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt)); + (void)SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt)); return dt; } return NULL; } - - diff --git a/src/defrag-hash.h b/src/defrag-hash.h index b115b13a91d7..bbe80d05415c 100644 --- a/src/defrag-hash.h +++ b/src/defrag-hash.h @@ -26,34 +26,34 @@ #include "decode.h" #include "defrag.h" -#include "util-exception-policy.h" +#include "util/exception-policy.h" /** Spinlocks or Mutex for the flow buckets. */ -//#define DRLOCK_SPIN +// #define DRLOCK_SPIN #define DRLOCK_MUTEX #ifdef DRLOCK_SPIN - #ifdef DRLOCK_MUTEX - #error Cannot enable both DRLOCK_SPIN and DRLOCK_MUTEX - #endif +#ifdef DRLOCK_MUTEX +#error Cannot enable both DRLOCK_SPIN and DRLOCK_MUTEX +#endif #endif #ifdef DRLOCK_SPIN - #define DRLOCK_TYPE SCSpinlock - #define DRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) - #define DRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) - #define DRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) - #define DRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) - #define DRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) +#define DRLOCK_TYPE SCSpinlock +#define DRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) +#define DRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) +#define DRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) +#define DRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) +#define DRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) #elif defined DRLOCK_MUTEX - #define DRLOCK_TYPE SCMutex - #define DRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) - #define DRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) - #define DRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) - #define DRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) - #define DRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) +#define DRLOCK_TYPE SCMutex +#define DRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) +#define DRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) +#define DRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) +#define DRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) +#define DRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) #else - #error Enable DRLOCK_SPIN or DRLOCK_MUTEX +#error Enable DRLOCK_SPIN or DRLOCK_MUTEX #endif typedef struct DefragTrackerHashRow_ { @@ -80,19 +80,20 @@ typedef struct DefragConfig_ { * \retval 1 it fits * \retval 0 no fit */ -#define DEFRAG_CHECK_MEMCAP(size) \ - ((((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)(size)) <= SC_ATOMIC_GET(defrag_config.memcap))) +#define DEFRAG_CHECK_MEMCAP(size) \ + ((((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)(size)) <= \ + SC_ATOMIC_GET(defrag_config.memcap))) extern DefragConfig defrag_config; -SC_ATOMIC_EXTERN(uint64_t,defrag_memuse); -SC_ATOMIC_EXTERN(unsigned int,defragtracker_counter); -SC_ATOMIC_EXTERN(unsigned int,defragtracker_prune_idx); +SC_ATOMIC_EXTERN(uint64_t, defrag_memuse); +SC_ATOMIC_EXTERN(unsigned int, defragtracker_counter); +SC_ATOMIC_EXTERN(unsigned int, defragtracker_prune_idx); void DefragInitConfig(bool quiet); void DefragHashShutdown(void); -DefragTracker *DefragLookupTrackerFromHash (Packet *); -DefragTracker *DefragGetTrackerFromHash (Packet *); +DefragTracker *DefragLookupTrackerFromHash(Packet *); +DefragTracker *DefragGetTrackerFromHash(Packet *); void DefragTrackerRelease(DefragTracker *); void DefragTrackerClearMemory(DefragTracker *); void DefragTrackerMoveToSpare(DefragTracker *); @@ -103,4 +104,3 @@ uint64_t DefragTrackerGetMemcap(void); uint64_t DefragTrackerGetMemuse(void); #endif /* __DEFRAG_HASH_H__ */ - diff --git a/src/defrag-queue.c b/src/defrag-queue.c index dccff8871f95..66b0c11fc596 100644 --- a/src/defrag-queue.c +++ b/src/defrag-queue.c @@ -25,11 +25,11 @@ #include "suricata-common.h" #include "defrag-queue.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-print.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/print.h" -DefragTrackerQueue *DefragTrackerQueueInit (DefragTrackerQueue *q) +DefragTrackerQueue *DefragTrackerQueueInit(DefragTrackerQueue *q) { if (q != NULL) { memset(q, 0, sizeof(DefragTrackerQueue)); @@ -54,7 +54,7 @@ DefragTrackerQueue *DefragTrackerQueueNew(void) * * \param q the tracker queue to destroy */ -void DefragTrackerQueueDestroy (DefragTrackerQueue *q) +void DefragTrackerQueueDestroy(DefragTrackerQueue *q) { DQLOCK_DESTROY(q); } @@ -65,7 +65,7 @@ void DefragTrackerQueueDestroy (DefragTrackerQueue *q) * \param q queue * \param dt tracker */ -void DefragTrackerEnqueue (DefragTrackerQueue *q, DefragTracker *dt) +void DefragTrackerEnqueue(DefragTrackerQueue *q, DefragTracker *dt) { #ifdef DEBUG BUG_ON(q == NULL || dt == NULL); @@ -78,7 +78,7 @@ void DefragTrackerEnqueue (DefragTrackerQueue *q, DefragTracker *dt) dt->lnext = q->top; q->top->lprev = dt; q->top = dt; - /* only tracker */ + /* only tracker */ } else { q->top = dt; q->bot = dt; @@ -98,7 +98,7 @@ void DefragTrackerEnqueue (DefragTrackerQueue *q, DefragTracker *dt) * * \retval dt tracker or NULL if empty list. */ -DefragTracker *DefragTrackerDequeue (DefragTrackerQueue *q) +DefragTracker *DefragTrackerDequeue(DefragTrackerQueue *q) { DQLOCK_LOCK(q); @@ -112,7 +112,7 @@ DefragTracker *DefragTrackerDequeue (DefragTrackerQueue *q) if (q->bot->lprev != NULL) { q->bot = q->bot->lprev; q->bot->lnext = NULL; - /* just the one we remove, so now empty */ + /* just the one we remove, so now empty */ } else { q->top = NULL; q->bot = NULL; @@ -139,4 +139,3 @@ uint32_t DefragTrackerQueueLen(DefragTrackerQueue *q) DQLOCK_UNLOCK(q); return len; } - diff --git a/src/defrag-queue.h b/src/defrag-queue.h index 63a58d078645..520a06065989 100644 --- a/src/defrag-queue.h +++ b/src/defrag-queue.h @@ -28,18 +28,17 @@ #include "defrag.h" /** Spinlocks or Mutex for the defrag tracker queues. */ -//#define DQLOCK_SPIN +// #define DQLOCK_SPIN #define DQLOCK_MUTEX #ifdef DQLOCK_SPIN - #ifdef DQLOCK_MUTEX - #error Cannot enable both DQLOCK_SPIN and DQLOCK_MUTEX - #endif +#ifdef DQLOCK_MUTEX +#error Cannot enable both DQLOCK_SPIN and DQLOCK_MUTEX +#endif #endif /* Define a queue for storing defrag trackers */ -typedef struct DefragTrackerQueue_ -{ +typedef struct DefragTrackerQueue_ { DefragTracker *top; DefragTracker *bot; uint32_t len; @@ -51,34 +50,33 @@ typedef struct DefragTrackerQueue_ #elif defined DQLOCK_SPIN SCSpinlock s; #else - #error Enable DQLOCK_SPIN or DQLOCK_MUTEX +#error Enable DQLOCK_SPIN or DQLOCK_MUTEX #endif } DefragTrackerQueue; #ifdef DQLOCK_SPIN - #define DQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) - #define DQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) - #define DQLOCK_LOCK(q) SCSpinLock(&(q)->s) - #define DQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) - #define DQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) +#define DQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) +#define DQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) +#define DQLOCK_LOCK(q) SCSpinLock(&(q)->s) +#define DQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) +#define DQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) #elif defined DQLOCK_MUTEX - #define DQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) - #define DQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) - #define DQLOCK_LOCK(q) SCMutexLock(&(q)->m) - #define DQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) - #define DQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) +#define DQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) +#define DQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) +#define DQLOCK_LOCK(q) SCMutexLock(&(q)->m) +#define DQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) +#define DQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) #else - #error Enable DQLOCK_SPIN or DQLOCK_MUTEX +#error Enable DQLOCK_SPIN or DQLOCK_MUTEX #endif /* prototypes */ DefragTrackerQueue *DefragTrackerQueueNew(void); DefragTrackerQueue *DefragTrackerQueueInit(DefragTrackerQueue *); -void DefragTrackerQueueDestroy (DefragTrackerQueue *); +void DefragTrackerQueueDestroy(DefragTrackerQueue *); -void DefragTrackerEnqueue (DefragTrackerQueue *, DefragTracker *); -DefragTracker *DefragTrackerDequeue (DefragTrackerQueue *); +void DefragTrackerEnqueue(DefragTrackerQueue *, DefragTracker *); +DefragTracker *DefragTrackerDequeue(DefragTrackerQueue *); uint32_t DefragTrackerQueueLen(DefragTrackerQueue *); #endif /* __DEFRAG_QUEUE_H__ */ - diff --git a/src/defrag-timeout.c b/src/defrag-timeout.c index 2d7c96f028cc..4699eea92927 100644 --- a/src/defrag-timeout.c +++ b/src/defrag-timeout.c @@ -143,4 +143,3 @@ uint32_t DefragTimeoutHash(SCTime_t ts) return cnt; } - diff --git a/src/defrag-timeout.h b/src/defrag-timeout.h index baece4516e87..a6b36a33bd72 100644 --- a/src/defrag-timeout.h +++ b/src/defrag-timeout.h @@ -27,4 +27,3 @@ uint32_t DefragTimeoutHash(SCTime_t ts); #endif - diff --git a/src/defrag.c b/src/defrag.c index 71cf4204c17a..6908d4d368f0 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -39,17 +39,17 @@ #include "threads.h" #include "conf.h" #include "decode-ipv6.h" -#include "util-hashlist.h" -#include "util-pool.h" -#include "util-time.h" -#include "util-print.h" -#include "util-debug.h" -#include "util-fix_checksum.h" -#include "util-random.h" +#include "util/hashlist.h" +#include "util/pool.h" +#include "util/time.h" +#include "util/print.h" +#include "util/debug.h" +#include "util/fix_checksum.h" +#include "util/random.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" -#include "util-host-os-info.h" -#include "util-validate.h" +#include "util/host-os-info.h" +#include "util/validate.h" #include "defrag.h" #include "defrag-hash.h" @@ -60,7 +60,7 @@ #include "decode.h" #ifdef UNITTESTS -#include "util-unittest.h" +#include "util/unittest.h" #endif #define DEFAULT_DEFRAG_HASH_SIZE 0xffff @@ -126,8 +126,7 @@ DumpFrags(DefragTracker *tracker) /** * \brief Reset a frag for reuse in a pool. */ -static void -DefragFragReset(Frag *frag) +static void DefragFragReset(Frag *frag) { if (frag->pkt != NULL) SCFree(frag->pkt); @@ -137,8 +136,7 @@ DefragFragReset(Frag *frag) /** * \brief Allocate a new frag for use in a pool. */ -static int -DefragFragInit(void *data, void *initdata) +static int DefragFragInit(void *data, void *initdata) { Frag *frag = data; @@ -149,15 +147,14 @@ DefragFragInit(void *data, void *initdata) /** * \brief Free all frags associated with a tracker. */ -void -DefragTrackerFreeFrags(DefragTracker *tracker) +void DefragTrackerFreeFrags(DefragTracker *tracker) { Frag *frag, *tmp; /* Lock the frag pool as we'll be return items to it. */ SCMutexLock(&defrag_context->frag_pool_lock); - RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) { + RB_FOREACH_SAFE (frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) { RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag); DefragFragReset(frag); PoolReturn(defrag_context->frag_pool, frag); @@ -172,8 +169,7 @@ DefragTrackerFreeFrags(DefragTracker *tracker) * \retval On success a return an initialized DefragContext, otherwise * NULL will be returned. */ -static DefragContext * -DefragContextNew(void) +static DefragContext *DefragContextNew(void) { DefragContext *dc; @@ -193,9 +189,8 @@ DefragContextNew(void) frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE; } intmax_t frag_pool_prealloc = frag_pool_size / 2; - dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc, - sizeof(Frag), - NULL, DefragFragInit, dc, NULL, NULL); + dc->frag_pool = PoolInit( + frag_pool_size, frag_pool_prealloc, sizeof(Frag), NULL, DefragFragInit, dc, NULL, NULL); if (dc->frag_pool == NULL) { FatalError("Defrag: Failed to initialize fragment pool."); } @@ -207,29 +202,26 @@ DefragContextNew(void) intmax_t timeout; if (!ConfGetInt("defrag.timeout", &timeout)) { dc->timeout = TIMEOUT_DEFAULT; - } - else { + } else { if (timeout < TIMEOUT_MIN) { FatalError("defrag: Timeout less than minimum allowed value."); - } - else if (timeout > TIMEOUT_MAX) { + } else if (timeout > TIMEOUT_MAX) { FatalError("defrag: Timeout greater than maximum allowed value."); } dc->timeout = timeout; } SCLogDebug("Defrag Initialized:"); - SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout); - SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size); - SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size); - SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size); - SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc); + SCLogDebug("\tTimeout: %" PRIuMAX, (uintmax_t)dc->timeout); + SCLogDebug("\tMaximum defrag trackers: %" PRIuMAX, tracker_pool_size); + SCLogDebug("\tPreallocated defrag trackers: %" PRIuMAX, tracker_pool_size); + SCLogDebug("\tMaximum fragments: %" PRIuMAX, (uintmax_t)frag_pool_size); + SCLogDebug("\tPreallocated fragments: %" PRIuMAX, (uintmax_t)frag_pool_prealloc); return dc; } -static void -DefragContextDestroy(DefragContext *dc) +static void DefragContextDestroy(DefragContext *dc) { if (dc == NULL) return; @@ -243,8 +235,7 @@ DefragContextDestroy(DefragContext *dc) * * \param tracker The defragmentation tracker to reassemble from. */ -static Packet * -Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) +static Packet *Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) { Packet *rp = NULL; @@ -269,13 +260,12 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * fragments are inserted if frag_offset order. */ Frag *frag = NULL; size_t len = 0; - RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) { + RB_FOREACH_FROM (frag, IP_FRAGMENTS, first) { if (frag->offset > len) { /* This fragment starts after the end of the previous * fragment. We have a hole. */ goto done; - } - else { + } else { len += frag->data_len; } } @@ -295,9 +285,10 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) uint16_t hlen = 0; int ip_hdr_offset = 0; - RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) { - SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64, - frag, frag->data_len, frag->offset, frag->pcap_cnt); + RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) + { + SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %" PRIu64, frag, frag->data_len, + frag->offset, frag->pcap_cnt); if (frag->skip) continue; @@ -316,18 +307,16 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * this. */ fragmentable_offset = frag->ip_hdr_offset + frag->hlen; fragmentable_len = frag->data_len; - } - else { + } else { int pkt_end = fragmentable_offset + frag->offset + frag->data_len; if (pkt_end > (int)MAX_PAYLOAD_SIZE) { SCLogDebug("Failed re-assemble " "fragmented packet, exceeds size of packet buffer."); goto error_remove_tracker; } - if (PacketCopyDataOffset(rp, - fragmentable_offset + frag->offset + frag->ltrim, - frag->pkt + frag->data_offset + frag->ltrim, - frag->data_len - frag->ltrim) == -1) { + if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, + frag->pkt + frag->data_offset + frag->ltrim, + frag->data_len - frag->ltrim) == -1) { goto error_remove_tracker; } if (frag->offset > UINT16_MAX - frag->data_len) { @@ -352,8 +341,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) DEBUG_VALIDATE_BUG_ON(hlen > UINT16_MAX - fragmentable_len); rp->ip4h->ip_len = htons(fragmentable_len + hlen); rp->ip4h->ip_off = 0; - rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum, - old, rp->ip4h->ip_len + rp->ip4h->ip_off); + rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum, old, rp->ip4h->ip_len + rp->ip4h->ip_off); SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len); tracker->remove = 1; @@ -374,8 +362,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * * \param tracker The defragmentation tracker to reassemble from. */ -static Packet * -Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) +static Packet *Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) { Packet *rp = NULL; @@ -399,7 +386,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * fragments are inserted if frag_offset order. */ size_t len = 0; Frag *frag = NULL; - RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) { + RB_FOREACH_FROM (frag, IP_FRAGMENTS, first) { if (frag->skip) { continue; } @@ -409,14 +396,12 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) goto done; } len = frag->data_len; - } - else { + } else { if (frag->offset > len) { /* This fragment starts after the end of the previous * fragment. We have a hole. */ goto done; - } - else { + } else { len += frag->data_len; } } @@ -424,8 +409,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) /* Allocate a Packet for the reassembled packet. On failure we * SCFree all the resources held by this tracker. */ - rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h, - IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0); + rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h, IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0); if (rp == NULL) { goto error_remove_tracker; } @@ -436,14 +420,14 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) uint16_t fragmentable_len = 0; int ip_hdr_offset = 0; uint8_t next_hdr = 0; - RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) { + RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) + { if (frag->skip) continue; if (frag->data_len - frag->ltrim <= 0) continue; if (frag->offset == 0) { - IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt + - frag->frag_hdr_offset); + IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt + frag->frag_hdr_offset); next_hdr = frag_hdr->ip6fh_nxt; /* This is the first packet, we use this packets link and @@ -452,8 +436,8 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1) goto error_remove_tracker; if (PacketCopyDataOffset(rp, frag->frag_hdr_offset, - frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr), - frag->data_len) == -1) + frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr), + frag->data_len) == -1) goto error_remove_tracker; ip_hdr_offset = frag->ip_hdr_offset; @@ -471,11 +455,10 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) unfragmentable_len = (uint16_t)(fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN); if (unfragmentable_len >= fragmentable_offset) goto error_remove_tracker; - } - else { + } else { if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, - frag->pkt + frag->data_offset + frag->ltrim, - frag->data_len - frag->ltrim) == -1) + frag->pkt + frag->data_offset + frag->ltrim, + frag->data_len - frag->ltrim) == -1) goto error_remove_tracker; if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; @@ -495,8 +478,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * directly after the frag header. */ if (unfragmentable_len == 0) rp->ip6h->s_ip6_nxt = next_hdr; - SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) + - unfragmentable_len + fragmentable_len); + SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) + unfragmentable_len + fragmentable_len); tracker->remove = 1; DefragTrackerFreeFrags(tracker); @@ -518,7 +500,8 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * same offset to be treated as greater than, so we don't have an * equal return value here. */ -int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) { +int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) +{ if (a->offset < b->offset) { return -1; } @@ -530,8 +513,8 @@ int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) { * * \todo Allocate packet buffers from a pool. */ -static Packet * -DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p) +static Packet *DefragInsertFrag( + ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p) { Packet *r = NULL; uint16_t ltrim = 0; @@ -586,8 +569,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE); return NULL; } - } - else if (tracker->af == AF_INET6) { + } else if (tracker->af == AF_INET6) { more_frags = IPV6_EXTHDR_GET_FH_FLAG(p); frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p); data_offset = p->ip6eh.fh_data_offset; @@ -597,9 +579,9 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, frag_hdr_offset = p->ip6eh.fh_header_offset; SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, " - "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u", - more_frags ? "true" : "false", frag_offset, data_offset, - data_len, frag_end, ip_hdr_offset, frag_hdr_offset); + "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u", + more_frags ? "true" : "false", frag_offset, data_offset, data_len, frag_end, + ip_hdr_offset, frag_hdr_offset); /* handle unfragmentable exthdrs */ if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) { @@ -621,8 +603,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE); return NULL; } - } - else { + } else { DEBUG_VALIDATE_BUG_ON(1); return NULL; } @@ -658,132 +639,132 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, } switch (tracker->policy) { - case DEFRAG_POLICY_BSD: - if (frag_offset < prev->offset + prev->data_len) { - if (frag_offset >= prev->offset) { - ltrim = prev->offset + prev->data_len - frag_offset; + case DEFRAG_POLICY_BSD: + if (frag_offset < prev->offset + prev->data_len) { + if (frag_offset >= prev->offset) { + ltrim = prev->offset + prev->data_len - frag_offset; + } + if ((next != NULL) && (frag_end > next->offset)) { + next->ltrim = frag_end - next->offset; + } + if ((frag_offset < prev->offset) && + (frag_end >= prev->offset + prev->data_len)) { + prev->skip = 1; + } + goto insert; } - if ((next != NULL) && (frag_end > next->offset)) { - next->ltrim = frag_end - next->offset; + break; + case DEFRAG_POLICY_LINUX: + /* Check if new fragment overlaps the end of previous + * fragment, if it does, trim the new fragment. + * + * Old: AAAAAAAA AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB + */ + if (prev->offset + prev->ltrim < frag_offset + ltrim && + prev->offset + prev->data_len > frag_offset + ltrim) { + ltrim += prev->offset + prev->data_len - frag_offset; } - if ((frag_offset < prev->offset) && - (frag_end >= prev->offset + prev->data_len)) { - prev->skip = 1; - } - goto insert; - } - break; - case DEFRAG_POLICY_LINUX: - /* Check if new fragment overlaps the end of previous - * fragment, if it does, trim the new fragment. - * - * Old: AAAAAAAA AAAAAAAA AAAAAAAA - * New: BBBBBBBB BBBBBBBB BBBBBBBB - * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB - */ - if (prev->offset + prev->ltrim < frag_offset + ltrim && - prev->offset + prev->data_len > frag_offset + ltrim) { - ltrim += prev->offset + prev->data_len - frag_offset; - } - /* Check if new fragment overlaps the beginning of - * previous fragment, if it does, tim the previous - * fragment. - * - * Old: AAAAAAAA AAAAAAAA - * New: BBBBBBBB BBBBBBBB BBBBBBBB - * Res: BBBBBBBB BBBBBBBB BBBBBBBB - */ - if (frag_offset + ltrim < prev->offset + prev->ltrim && - frag_end > prev->offset + prev->ltrim) { - prev->ltrim += frag_end - (prev->offset + prev->ltrim); - goto insert; - } + /* Check if new fragment overlaps the beginning of + * previous fragment, if it does, tim the previous + * fragment. + * + * Old: AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: BBBBBBBB BBBBBBBB BBBBBBBB + */ + if (frag_offset + ltrim < prev->offset + prev->ltrim && + frag_end > prev->offset + prev->ltrim) { + prev->ltrim += frag_end - (prev->offset + prev->ltrim); + goto insert; + } - /* If the new fragment completely overlaps the - * previous fragment, mark the previous to be - * skipped. Re-assembly would succeed without doing - * this, but this will prevent the bytes from being - * copied just to be overwritten. */ - if (frag_offset + ltrim <= prev->offset + prev->ltrim && - frag_end >= prev->offset + prev->data_len) { - prev->skip = 1; - goto insert; - } + /* If the new fragment completely overlaps the + * previous fragment, mark the previous to be + * skipped. Re-assembly would succeed without doing + * this, but this will prevent the bytes from being + * copied just to be overwritten. */ + if (frag_offset + ltrim <= prev->offset + prev->ltrim && + frag_end >= prev->offset + prev->data_len) { + prev->skip = 1; + goto insert; + } - break; - case DEFRAG_POLICY_WINDOWS: - /* If new fragment fits inside a previous fragment, drop it. */ - if (frag_offset + ltrim >= prev->offset + ltrim && - frag_end <= prev->offset + prev->data_len) { - goto done; - } + break; + case DEFRAG_POLICY_WINDOWS: + /* If new fragment fits inside a previous fragment, drop it. */ + if (frag_offset + ltrim >= prev->offset + ltrim && + frag_end <= prev->offset + prev->data_len) { + goto done; + } - /* If new fragment starts before and ends after - * previous fragment, drop the previous fragment. */ - if (frag_offset + ltrim < prev->offset + ltrim && - frag_end > prev->offset + prev->data_len) { - prev->skip = 1; - goto insert; - } + /* If new fragment starts before and ends after + * previous fragment, drop the previous fragment. */ + if (frag_offset + ltrim < prev->offset + ltrim && + frag_end > prev->offset + prev->data_len) { + prev->skip = 1; + goto insert; + } - /* Check if new fragment overlaps the end of previous - * fragment, if it does, trim the new fragment. - * - * Old: AAAAAAAA AAAAAAAA AAAAAAAA - * New: BBBBBBBB BBBBBBBB BBBBBBBB - * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB - */ - if (frag_offset + ltrim > prev->offset + prev->ltrim && - frag_offset + ltrim < prev->offset + prev->data_len) { - ltrim += prev->offset + prev->data_len - frag_offset; - goto insert; - } + /* Check if new fragment overlaps the end of previous + * fragment, if it does, trim the new fragment. + * + * Old: AAAAAAAA AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB + */ + if (frag_offset + ltrim > prev->offset + prev->ltrim && + frag_offset + ltrim < prev->offset + prev->data_len) { + ltrim += prev->offset + prev->data_len - frag_offset; + goto insert; + } - /* If new fragment starts at same offset as an - * existing fragment, but ends after it, trim the new - * fragment. */ - if (frag_offset + ltrim == prev->offset + ltrim && - frag_end > prev->offset + prev->data_len) { - ltrim += prev->offset + prev->data_len - frag_offset; - goto insert; - } - break; - case DEFRAG_POLICY_SOLARIS: - if (frag_offset < prev->offset + prev->data_len) { - if (frag_offset >= prev->offset) { - ltrim = prev->offset + prev->data_len - frag_offset; + /* If new fragment starts at same offset as an + * existing fragment, but ends after it, trim the new + * fragment. */ + if (frag_offset + ltrim == prev->offset + ltrim && + frag_end > prev->offset + prev->data_len) { + ltrim += prev->offset + prev->data_len - frag_offset; + goto insert; } - if ((frag_offset < prev->offset) && - (frag_end >= prev->offset + prev->data_len)) { - prev->skip = 1; + break; + case DEFRAG_POLICY_SOLARIS: + if (frag_offset < prev->offset + prev->data_len) { + if (frag_offset >= prev->offset) { + ltrim = prev->offset + prev->data_len - frag_offset; + } + if ((frag_offset < prev->offset) && + (frag_end >= prev->offset + prev->data_len)) { + prev->skip = 1; + } + goto insert; } - goto insert; - } - break; - case DEFRAG_POLICY_FIRST: - if ((frag_offset >= prev->offset) && - (frag_end <= prev->offset + prev->data_len)) { - goto done; - } - if (frag_offset < prev->offset) { - goto insert; - } - if (frag_offset < prev->offset + prev->data_len) { - ltrim = prev->offset + prev->data_len - frag_offset; - goto insert; - } - break; - case DEFRAG_POLICY_LAST: - if (frag_offset <= prev->offset) { - if (frag_end > prev->offset) { - prev->ltrim = frag_end - prev->offset; + break; + case DEFRAG_POLICY_FIRST: + if ((frag_offset >= prev->offset) && + (frag_end <= prev->offset + prev->data_len)) { + goto done; } - goto insert; - } - break; - default: - break; + if (frag_offset < prev->offset) { + goto insert; + } + if (frag_offset < prev->offset + prev->data_len) { + ltrim = prev->offset + prev->data_len - frag_offset; + goto insert; + } + break; + case DEFRAG_POLICY_LAST: + if (frag_offset <= prev->offset) { + if (frag_end > prev->offset) { + prev->ltrim = frag_end - prev->offset; + } + goto insert; + } + break; + default: + break; } next: @@ -873,8 +854,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, r = Defrag4Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled); - if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h, - IPV4_GET_IPLEN(r)) != TM_ECODE_OK) { + if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h, IPV4_GET_IPLEN(r)) != TM_ECODE_OK) { UNSET_TUNNEL_PKT(r); r->root = NULL; @@ -884,14 +864,12 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, PacketDefragPktSetupParent(p); } } - } - else if (tracker->af == AF_INET6) { + } else if (tracker->af == AF_INET6) { r = Defrag6Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled); if (DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h, - IPV6_GET_PLEN(r) + IPV6_HEADER_LEN) - != TM_ECODE_OK) { + IPV6_GET_PLEN(r) + IPV6_HEADER_LEN) != TM_ECODE_OK) { UNSET_TUNNEL_PKT(r); r->root = NULL; @@ -904,13 +882,11 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, } } - done: if (overlap) { if (af == AF_INET) { ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP); - } - else { + } else { ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP); } } @@ -925,15 +901,13 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, * * \retval The defrag policy to use. */ -uint8_t -DefragGetOsPolicy(Packet *p) +uint8_t DefragGetOsPolicy(Packet *p) { int policy = -1; if (PKT_IS_IPV4(p)) { policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p)); - } - else if (PKT_IS_IPV6(p)) { + } else if (PKT_IS_IPV6(p)) { policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p)); } @@ -944,52 +918,51 @@ DefragGetOsPolicy(Packet *p) /* Map the OS policies returned from the configured host info to * defrag specific policies. */ switch (policy) { - /* BSD. */ - case OS_POLICY_BSD: - case OS_POLICY_HPUX10: - case OS_POLICY_IRIX: - return DEFRAG_POLICY_BSD; - - /* BSD-Right. */ - case OS_POLICY_BSD_RIGHT: - return DEFRAG_POLICY_BSD_RIGHT; - - /* Linux. */ - case OS_POLICY_OLD_LINUX: - case OS_POLICY_LINUX: - return DEFRAG_POLICY_LINUX; - - /* First. */ - case OS_POLICY_OLD_SOLARIS: - case OS_POLICY_HPUX11: - case OS_POLICY_MACOS: - case OS_POLICY_FIRST: - return DEFRAG_POLICY_FIRST; - - /* Solaris. */ - case OS_POLICY_SOLARIS: - return DEFRAG_POLICY_SOLARIS; - - /* Windows. */ - case OS_POLICY_WINDOWS: - case OS_POLICY_VISTA: - case OS_POLICY_WINDOWS2K3: - return DEFRAG_POLICY_WINDOWS; - - /* Last. */ - case OS_POLICY_LAST: - return DEFRAG_POLICY_LAST; - - default: - return default_policy; + /* BSD. */ + case OS_POLICY_BSD: + case OS_POLICY_HPUX10: + case OS_POLICY_IRIX: + return DEFRAG_POLICY_BSD; + + /* BSD-Right. */ + case OS_POLICY_BSD_RIGHT: + return DEFRAG_POLICY_BSD_RIGHT; + + /* Linux. */ + case OS_POLICY_OLD_LINUX: + case OS_POLICY_LINUX: + return DEFRAG_POLICY_LINUX; + + /* First. */ + case OS_POLICY_OLD_SOLARIS: + case OS_POLICY_HPUX11: + case OS_POLICY_MACOS: + case OS_POLICY_FIRST: + return DEFRAG_POLICY_FIRST; + + /* Solaris. */ + case OS_POLICY_SOLARIS: + return DEFRAG_POLICY_SOLARIS; + + /* Windows. */ + case OS_POLICY_WINDOWS: + case OS_POLICY_VISTA: + case OS_POLICY_WINDOWS2K3: + return DEFRAG_POLICY_WINDOWS; + + /* Last. */ + case OS_POLICY_LAST: + return DEFRAG_POLICY_LAST; + + default: + return default_policy; } } /** \internal * * \retval NULL or a *LOCKED* tracker */ -static DefragTracker * -DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) +static DefragTracker *DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { return DefragGetTrackerFromHash(p); } @@ -1004,8 +977,7 @@ DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) * recent fragment allowed the packet to be re-assembled, otherwise * NULL is returned. */ -Packet * -Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) +Packet *Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { uint16_t frag_offset; uint8_t more_frags; @@ -1016,13 +988,11 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) af = AF_INET; more_frags = IPV4_GET_MF(p); frag_offset = IPV4_GET_IPOFFSET(p); - } - else if (PKT_IS_IPV6(p)) { + } else if (PKT_IS_IPV6(p)) { af = AF_INET6; frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p); more_frags = IPV6_EXTHDR_GET_FH_FLAG(p); - } - else { + } else { return NULL; } @@ -1033,8 +1003,7 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) if (tv != NULL && dtv != NULL) { if (af == AF_INET) { StatsIncr(tv, dtv->counter_defrag_ipv4_fragments); - } - else if (af == AF_INET6) { + } else if (af == AF_INET6) { StatsIncr(tv, dtv->counter_defrag_ipv6_fragments); } } @@ -1054,8 +1023,7 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) return rp; } -void -DefragInit(void) +void DefragInit(void) { intmax_t tracker_pool_size; if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) { @@ -1084,7 +1052,7 @@ void DefragDestroy(void) } #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "packet.h" #define IP_MF 0x2000 @@ -1093,8 +1061,8 @@ void DefragDestroy(void) * Allocate a test packet. Nothing to fancy, just a simple IP packet * with some payload of no particular protocol. */ -static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, - const char content, int content_len) +static Packet *BuildTestPacket( + uint8_t proto, uint16_t id, uint16_t off, int mf, const char content, int content_len) { Packet *p = NULL; int hlen = 20; @@ -1111,7 +1079,7 @@ static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, struct timeval tval; gettimeofday(&tval, NULL); p->ts = SCTIME_FROM_TIMEVAL(&tval); - //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); + // p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); ip4h.ip_verhl = 4 << 4; ip4h.ip_verhl |= hlen >> 2; ip4h.ip_len = htons(hlen + content_len); @@ -1167,8 +1135,8 @@ static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, return NULL; } -static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, - int mf, const char content, int content_len) +static Packet *IPV6BuildTestPacket( + uint8_t proto, uint32_t id, uint16_t off, int mf, const char content, int content_len) { Packet *p = NULL; uint8_t *pcontent; @@ -1444,8 +1412,7 @@ static int IPV6DefragReverseSimpleTest(void) PASS; } -static int DefragDoSturgesNovakTest(int policy, u_char *expected, - size_t expected_len) +static int DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) { int i; @@ -1556,8 +1523,7 @@ static int DefragDoSturgesNovakTest(int policy, u_char *expected, PASS; } -static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, - size_t expected_len) +static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) { int i; @@ -1667,424 +1633,386 @@ static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, PASS; } -static int -DefragSturgesNovakBsdTest(void) +static int DefragSturgesNovakBsdTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "JJJJJJJJ" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "JJJJJJJJ" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected))); PASS; } static int IPV6DefragSturgesNovakBsdTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "JJJJJJJJ" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "JJJJJJJJ" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected))); PASS; } static int DefragSturgesNovakLinuxIpv4Test(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "JJJJJJJJ" - "BBBBBBBB" - "KKKKKKKK" - "KKKKKKKK" - "KKKKKKKK" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "PPPPPPPP" - "HHHHHHHH" - "QQQQQQQQ" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "JJJJJJJJ" + "BBBBBBBB" + "KKKKKKKK" + "KKKKKKKK" + "KKKKKKKK" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "PPPPPPPP" + "HHHHHHHH" + "QQQQQQQQ" + "QQQQQQQQ" }; + + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, sizeof(expected))); PASS; } static int IPV6DefragSturgesNovakLinuxTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "JJJJJJJJ" - "BBBBBBBB" - "KKKKKKKK" - "KKKKKKKK" - "KKKKKKKK" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "PPPPPPPP" - "HHHHHHHH" - "QQQQQQQQ" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "JJJJJJJJ" + "BBBBBBBB" + "KKKKKKKK" + "KKKKKKKK" + "KKKKKKKK" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "PPPPPPPP" + "HHHHHHHH" + "QQQQQQQQ" + "QQQQQQQQ" }; + + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, sizeof(expected))); PASS; } static int DefragSturgesNovakWindowsIpv4Test(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "BBBBBBBB" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "EEEEEEEE" - "EEEEEEEE" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "BBBBBBBB" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "EEEEEEEE" + "EEEEEEEE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected))); PASS; } static int IPV6DefragSturgesNovakWindowsTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "BBBBBBBB" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "EEEEEEEE" - "EEEEEEEE" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "BBBBBBBB" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "EEEEEEEE" + "EEEEEEEE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected))); PASS; } static int DefragSturgesNovakSolarisTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "BBBBBBBB" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "BBBBBBBB" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected))); PASS; } static int IPV6DefragSturgesNovakSolarisTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "BBBBBBBB" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "BBBBBBBB" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected))); PASS; } static int DefragSturgesNovakFirstTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "BBBBBBBB" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "DDDDDDDD" - "LLLLLLLL" - "MMMMMMMM" - "EEEEEEEE" - "EEEEEEEE" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "BBBBBBBB" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "DDDDDDDD" + "LLLLLLLL" + "MMMMMMMM" + "EEEEEEEE" + "EEEEEEEE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, sizeof(expected))); PASS; } static int IPV6DefragSturgesNovakFirstTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "JJJJJJJJ" - "BBBBBBBB" - "BBBBBBBB" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "LLLLLLLL" - "DDDDDDDD" - "LLLLLLLL" - "MMMMMMMM" - "EEEEEEEE" - "EEEEEEEE" - "FFFFFFFF" - "FFFFFFFF" - "FFFFFFFF" - "GGGGGGGG" - "GGGGGGGG" - "HHHHHHHH" - "HHHHHHHH" - "IIIIIIII" - "QQQQQQQQ" - }; - - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, - sizeof(expected)); + u_char expected[] = { "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "JJJJJJJJ" + "BBBBBBBB" + "BBBBBBBB" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "LLLLLLLL" + "DDDDDDDD" + "LLLLLLLL" + "MMMMMMMM" + "EEEEEEEE" + "EEEEEEEE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "GGGGGGGG" + "GGGGGGGG" + "HHHHHHHH" + "HHHHHHHH" + "IIIIIIII" + "QQQQQQQQ" }; + + return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, sizeof(expected)); } -static int -DefragSturgesNovakLastTest(void) +static int DefragSturgesNovakLastTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "JJJJJJJJ" - "JJJJJJJJ" - "JJJJJJJJ" - "JJJJJJJJ" - "BBBBBBBB" - "KKKKKKKK" - "KKKKKKKK" - "KKKKKKKK" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "NNNNNNNN" - "FFFFFFFF" - "GGGGGGGG" - "OOOOOOOO" - "PPPPPPPP" - "HHHHHHHH" - "QQQQQQQQ" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "JJJJJJJJ" + "JJJJJJJJ" + "JJJJJJJJ" + "JJJJJJJJ" + "BBBBBBBB" + "KKKKKKKK" + "KKKKKKKK" + "KKKKKKKK" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "NNNNNNNN" + "FFFFFFFF" + "GGGGGGGG" + "OOOOOOOO" + "PPPPPPPP" + "HHHHHHHH" + "QQQQQQQQ" + "QQQQQQQQ" }; + + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, sizeof(expected))); PASS; } static int IPV6DefragSturgesNovakLastTest(void) { /* Expected data. */ - u_char expected[] = { - "AAAAAAAA" - "JJJJJJJJ" - "JJJJJJJJ" - "JJJJJJJJ" - "JJJJJJJJ" - "BBBBBBBB" - "KKKKKKKK" - "KKKKKKKK" - "KKKKKKKK" - "LLLLLLLL" - "LLLLLLLL" - "LLLLLLLL" - "MMMMMMMM" - "MMMMMMMM" - "MMMMMMMM" - "FFFFFFFF" - "NNNNNNNN" - "FFFFFFFF" - "GGGGGGGG" - "OOOOOOOO" - "PPPPPPPP" - "HHHHHHHH" - "QQQQQQQQ" - "QQQQQQQQ" - }; - - FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, - sizeof(expected))); + u_char expected[] = { "AAAAAAAA" + "JJJJJJJJ" + "JJJJJJJJ" + "JJJJJJJJ" + "JJJJJJJJ" + "BBBBBBBB" + "KKKKKKKK" + "KKKKKKKK" + "KKKKKKKK" + "LLLLLLLL" + "LLLLLLLL" + "LLLLLLLL" + "MMMMMMMM" + "MMMMMMMM" + "MMMMMMMM" + "FFFFFFFF" + "NNNNNNNN" + "FFFFFFFF" + "GGGGGGGG" + "OOOOOOOO" + "PPPPPPPP" + "HHHHHHHH" + "QQQQQQQQ" + "QQQQQQQQ" }; + + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, sizeof(expected))); PASS; } @@ -2099,7 +2027,7 @@ static int DefragTimeoutTest(void) /* Load in 16 packets. */ for (i = 0; i < 16; i++) { - Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16); + Packet *p = BuildTestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16); FAIL_IF_NULL(p); Packet *tp = Defrag(NULL, NULL, p); @@ -2462,18 +2390,18 @@ static int DefragTestBadProto(void) static int DefragTestJeremyLinux(void) { char expected[] = "AAAAAAAA" - "AAAAAAAA" - "AAAAAAAA" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "CCCCCCCC" - "BBBBBBBB" - "BBBBBBBB" - "DDDDDDDD" - "DDDDDD"; + "AAAAAAAA" + "AAAAAAAA" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "BBBBBBBB" + "BBBBBBBB" + "DDDDDDDD" + "DDDDDD"; DefragInit(); default_policy = DEFRAG_POLICY_LINUX; @@ -2518,12 +2446,9 @@ void DefragRegisterTests(void) UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest); UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest); UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest); - UtRegisterTest("DefragSturgesNovakLinuxIpv4Test", - DefragSturgesNovakLinuxIpv4Test); - UtRegisterTest("DefragSturgesNovakWindowsIpv4Test", - DefragSturgesNovakWindowsIpv4Test); - UtRegisterTest("DefragSturgesNovakSolarisTest", - DefragSturgesNovakSolarisTest); + UtRegisterTest("DefragSturgesNovakLinuxIpv4Test", DefragSturgesNovakLinuxIpv4Test); + UtRegisterTest("DefragSturgesNovakWindowsIpv4Test", DefragSturgesNovakWindowsIpv4Test); + UtRegisterTest("DefragSturgesNovakSolarisTest", DefragSturgesNovakSolarisTest); UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest); UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest); @@ -2532,18 +2457,12 @@ void DefragRegisterTests(void) UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest); UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest); - UtRegisterTest("IPV6DefragSturgesNovakBsdTest", - IPV6DefragSturgesNovakBsdTest); - UtRegisterTest("IPV6DefragSturgesNovakLinuxTest", - IPV6DefragSturgesNovakLinuxTest); - UtRegisterTest("IPV6DefragSturgesNovakWindowsTest", - IPV6DefragSturgesNovakWindowsTest); - UtRegisterTest("IPV6DefragSturgesNovakSolarisTest", - IPV6DefragSturgesNovakSolarisTest); - UtRegisterTest("IPV6DefragSturgesNovakFirstTest", - IPV6DefragSturgesNovakFirstTest); - UtRegisterTest("IPV6DefragSturgesNovakLastTest", - IPV6DefragSturgesNovakLastTest); + UtRegisterTest("IPV6DefragSturgesNovakBsdTest", IPV6DefragSturgesNovakBsdTest); + UtRegisterTest("IPV6DefragSturgesNovakLinuxTest", IPV6DefragSturgesNovakLinuxTest); + UtRegisterTest("IPV6DefragSturgesNovakWindowsTest", IPV6DefragSturgesNovakWindowsTest); + UtRegisterTest("IPV6DefragSturgesNovakSolarisTest", IPV6DefragSturgesNovakSolarisTest); + UtRegisterTest("IPV6DefragSturgesNovakFirstTest", IPV6DefragSturgesNovakFirstTest); + UtRegisterTest("IPV6DefragSturgesNovakLastTest", IPV6DefragSturgesNovakLastTest); UtRegisterTest("DefragVlanTest", DefragVlanTest); UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest); diff --git a/src/defrag.h b/src/defrag.h index 11e6a619b2f1..594431fa19ea 100644 --- a/src/defrag.h +++ b/src/defrag.h @@ -25,7 +25,7 @@ #define __DEFRAG_H__ #include "threads.h" -#include "util-pool.h" +#include "util/pool.h" #include "threadvars.h" #include "decode.h" @@ -44,31 +44,31 @@ typedef struct DefragContext_ { * Storage for an individual fragment. */ typedef struct Frag_ { - uint16_t offset; /**< The offset of this fragment, already - * multiplied by 8. */ + uint16_t offset; /**< The offset of this fragment, already + * multiplied by 8. */ uint32_t len; /**< The length of this fragment. */ - uint8_t hlen; /**< The length of this fragments IP header. */ + uint8_t hlen; /**< The length of this fragments IP header. */ - uint8_t more_frags:4; /**< More frags? */ - uint8_t skip:4; /**< Skip this fragment during re-assembly. */ + uint8_t more_frags : 4; /**< More frags? */ + uint8_t skip : 4; /**< Skip this fragment during re-assembly. */ - uint16_t ip_hdr_offset; /**< Offset in the packet where the IP - * header starts. */ - uint16_t frag_hdr_offset; /**< Offset in the packet where the frag - * header starts. */ + uint16_t ip_hdr_offset; /**< Offset in the packet where the IP + * header starts. */ + uint16_t frag_hdr_offset; /**< Offset in the packet where the frag + * header starts. */ - uint16_t data_offset; /**< Offset to the packet data. */ - uint16_t data_len; /**< Length of data. */ + uint16_t data_offset; /**< Offset to the packet data. */ + uint16_t data_len; /**< Length of data. */ - uint16_t ltrim; /**< Number of leading bytes to trim when - * re-assembling the packet. */ + uint16_t ltrim; /**< Number of leading bytes to trim when + * re-assembling the packet. */ - uint8_t *pkt; /**< The actual packet. */ + uint8_t *pkt; /**< The actual packet. */ #ifdef DEBUG - uint64_t pcap_cnt; /**< pcap_cnt of original packet */ + uint64_t pcap_cnt; /**< pcap_cnt of original packet */ #endif RB_ENTRY(Frag_) rb; @@ -85,7 +85,7 @@ RB_PROTOTYPE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare); */ typedef struct DefragTracker_ { SCMutex lock; /**< Mutex for locking list operations on - * this tracker. */ + * this tracker. */ uint16_t vlan_id[VLAN_MAX_LAYERS]; /**< VLAN ID tracker applies to. */ @@ -106,8 +106,8 @@ typedef struct DefragTracker_ { Address src_addr; /**< Source address for this tracker. */ Address dst_addr; /**< Destination address for this tracker. */ - SCTime_t timeout; /**< When this tracker will timeout. */ - uint32_t host_timeout; /**< Host timeout, statically assigned from the yaml */ + SCTime_t timeout; /**< When this tracker will timeout. */ + uint32_t host_timeout; /**< Host timeout, statically assigned from the yaml */ /** use cnt, reference counter */ SC_ATOMIC_DECLARE(unsigned int, use_cnt); diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 9c323359b577..5f37d590051a 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -28,7 +28,7 @@ #include "app-layer.h" #include "app-layer-protos.h" #include "app-layer-parser.h" -#include "app-layer-smtp.h" +#include "app-layer/smtp/parser.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" @@ -41,12 +41,12 @@ #include "flow-util.h" #include "decode-events.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-enum.h" -#include "util-profiling.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/enum.h" +#include "util/profiling.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "stream-tcp-util.h" #define MAX_ALPROTO_NAME 50 @@ -56,8 +56,8 @@ typedef struct DetectAppLayerEventData_ { uint8_t event_id; } DetectAppLayerEventData; -static int DetectAppLayerEventPktMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx); +static int DetectAppLayerEventPktMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); static int DetectAppLayerEventSetup(DetectEngineCtx *, Signature *, const char *); static void DetectAppLayerEventFree(DetectEngineCtx *, void *); static uint8_t DetectEngineAptEventInspect(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, @@ -71,10 +71,10 @@ static int g_applayer_events_list_id = 0; void DetectAppLayerEventRegister(void) { sigmatch_table[DETECT_AL_APP_LAYER_EVENT].name = "app-layer-event"; - sigmatch_table[DETECT_AL_APP_LAYER_EVENT].desc = "match on events generated by the App Layer Parsers and the protocol detection engine"; + sigmatch_table[DETECT_AL_APP_LAYER_EVENT].desc = + "match on events generated by the App Layer Parsers and the protocol detection engine"; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].url = "/rules/app-layer.html#app-layer-event"; - sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Match = - DetectAppLayerEventPktMatch; + sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Match = DetectAppLayerEventPktMatch; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Setup = DetectAppLayerEventSetup; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Free = DetectAppLayerEventFree; @@ -117,13 +117,12 @@ static uint8_t DetectEngineAptEventInspect(DetectEngineCtx *de_ctx, DetectEngine r = 1; - end: +end: if (r == 1) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) == - AppLayerParserGetStateProgressCompletionStatus(alproto, flags)) - { + AppLayerParserGetStateProgressCompletionStatus(alproto, flags)) { return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -131,18 +130,16 @@ static uint8_t DetectEngineAptEventInspect(DetectEngineCtx *de_ctx, DetectEngine } } - -static int DetectAppLayerEventPktMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectAppLayerEventPktMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectAppLayerEventData *aled = (const DetectAppLayerEventData *)ctx; - return AppLayerDecoderEventsIsEventSet(p->app_layer_events, - aled->event_id); + return AppLayerDecoderEventsIsEventSet(p->app_layer_events, aled->event_id); } -static DetectAppLayerEventData *DetectAppLayerEventParsePkt(const char *arg, - AppLayerEventType *event_type) +static DetectAppLayerEventData *DetectAppLayerEventParsePkt( + const char *arg, AppLayerEventType *event_type) { int event_id = 0; int r = AppLayerGetPktEventInfo(arg, &event_id); diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 182f6d0faeb3..5b8fe5f5e995 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -30,9 +30,9 @@ #include "detect-app-layer-protocol.h" #include "app-layer.h" #include "app-layer-parser.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #ifdef UNITTESTS static void DetectAppLayerProtocolRegisterTests(void); @@ -44,8 +44,7 @@ typedef struct DetectAppLayerProtocolData_ { } DetectAppLayerProtocolData; static int DetectAppLayerProtocolPacketMatch( - DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); @@ -55,37 +54,33 @@ static int DetectAppLayerProtocolPacketMatch( /* if the sig is PD-only we only match when PD packet flags are set */ if (s->type == SIG_TYPE_PDONLY && (p->flags & (PKT_PROTO_DETECT_TS_DONE | PKT_PROTO_DETECT_TC_DONE)) == 0) { - SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt); + SCLogDebug("packet %" PRIu64 ": flags not set", p->pcap_cnt); SCReturnInt(0); } const Flow *f = p->flow; if (f == NULL) { - SCLogDebug("packet %"PRIu64": no flow", p->pcap_cnt); + SCLogDebug("packet %" PRIu64 ": no flow", p->pcap_cnt); SCReturnInt(0); } /* unknown means protocol detection isn't ready yet */ - if ((f->alproto_ts != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOSERVER)) - { - SCLogDebug("toserver packet %"PRIu64": looking for %u/neg %u, got %u", - p->pcap_cnt, data->alproto, data->negated, f->alproto_ts); + if ((f->alproto_ts != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOSERVER)) { + SCLogDebug("toserver packet %" PRIu64 ": looking for %u/neg %u, got %u", p->pcap_cnt, + data->alproto, data->negated, f->alproto_ts); r = AppProtoEquals(data->alproto, f->alproto_ts); - } else if ((f->alproto_tc != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOCLIENT)) - { - SCLogDebug("toclient packet %"PRIu64": looking for %u/neg %u, got %u", - p->pcap_cnt, data->alproto, data->negated, f->alproto_tc); + } else if ((f->alproto_tc != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOCLIENT)) { + SCLogDebug("toclient packet %" PRIu64 ": looking for %u/neg %u, got %u", p->pcap_cnt, + data->alproto, data->negated, f->alproto_tc); r = AppProtoEquals(data->alproto, f->alproto_tc); - } - else { - SCLogDebug("packet %"PRIu64": default case: direction %02x, approtos %u/%u/%u", - p->pcap_cnt, - p->flowflags & (FLOW_PKT_TOCLIENT|FLOW_PKT_TOSERVER), - f->alproto, f->alproto_ts, f->alproto_tc); + } else { + SCLogDebug("packet %" PRIu64 ": default case: direction %02x, approtos %u/%u/%u", + p->pcap_cnt, p->flowflags & (FLOW_PKT_TOCLIENT | FLOW_PKT_TOSERVER), f->alproto, + f->alproto_ts, f->alproto_tc); } r = r ^ data->negated; if (r) { @@ -120,8 +115,8 @@ static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg, return data; } -static bool HasConflicts(const DetectAppLayerProtocolData *us, - const DetectAppLayerProtocolData *them) +static bool HasConflicts( + const DetectAppLayerProtocolData *us, const DetectAppLayerProtocolData *them) { /* mixing negated and non negated is illegal */ if (them->negated ^ us->negated) @@ -137,8 +132,7 @@ static bool HasConflicts(const DetectAppLayerProtocolData *us, return false; } -static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, - Signature *s, const char *arg) +static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) { DetectAppLayerProtocolData *data = NULL; @@ -155,7 +149,7 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, goto error; SigMatch *tsm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; - for ( ; tsm != NULL; tsm = tsm->next) { + for (; tsm != NULL; tsm = tsm->next) { if (tsm->type == DETECT_AL_APP_LAYER_PROTOCOL) { const DetectAppLayerProtocolData *them = (const DetectAppLayerProtocolData *)tsm->ctx; @@ -189,34 +183,32 @@ static void DetectAppLayerProtocolFree(DetectEngineCtx *de_ctx, void *ptr) /** \internal * \brief prefilter function for protocol detect matching */ -static void -PrefilterPacketAppProtoMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketAppProtoMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; if (!PrefilterPacketHeaderExtraMatch(ctx, p)) { - SCLogDebug("packet %"PRIu64": extra match failed", p->pcap_cnt); + SCLogDebug("packet %" PRIu64 ": extra match failed", p->pcap_cnt); SCReturn; } if (p->flow == NULL) { - SCLogDebug("packet %"PRIu64": no flow, no alproto", p->pcap_cnt); + SCLogDebug("packet %" PRIu64 ": no flow, no alproto", p->pcap_cnt); SCReturn; } - if ((p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) { - SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt); + if ((p->flags & (PKT_PROTO_DETECT_TS_DONE | PKT_PROTO_DETECT_TC_DONE)) == 0) { + SCLogDebug("packet %" PRIu64 ": flags not set", p->pcap_cnt); SCReturn; } - if ((p->flags & PKT_PROTO_DETECT_TS_DONE) && (p->flowflags & FLOW_PKT_TOSERVER)) - { + if ((p->flags & PKT_PROTO_DETECT_TS_DONE) && (p->flowflags & FLOW_PKT_TOSERVER)) { int r = (ctx->v1.u16[0] == p->flow->alproto_ts) ^ ctx->v1.u8[2]; if (r) { PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } - } else if ((p->flags & PKT_PROTO_DETECT_TC_DONE) && (p->flowflags & FLOW_PKT_TOCLIENT)) - { + } else if ((p->flags & PKT_PROTO_DETECT_TC_DONE) && (p->flowflags & FLOW_PKT_TOCLIENT)) { int r = (ctx->v1.u16[0] == p->flow->alproto_tc) ^ ctx->v1.u8[2]; if (r) { PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); @@ -224,20 +216,17 @@ PrefilterPacketAppProtoMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const vo } } -static void -PrefilterPacketAppProtoSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketAppProtoSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectAppLayerProtocolData *a = smctx; v->u16[0] = a->alproto; v->u8[2] = (uint8_t)a->negated; } -static bool -PrefilterPacketAppProtoCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketAppProtoCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectAppLayerProtocolData *a = smctx; - if (v.u16[0] == a->alproto && - v.u8[2] == (uint8_t)a->negated) + if (v.u16[0] == a->alproto && v.u8[2] == (uint8_t)a->negated) return true; return false; } @@ -245,9 +234,8 @@ PrefilterPacketAppProtoCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupAppProto(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_AL_APP_LAYER_PROTOCOL, - PrefilterPacketAppProtoSet, - PrefilterPacketAppProtoCompare, - PrefilterPacketAppProtoMatch); + PrefilterPacketAppProtoSet, PrefilterPacketAppProtoCompare, + PrefilterPacketAppProtoMatch); } static bool PrefilterAppProtoIsPrefilterable(const Signature *s) @@ -264,23 +252,19 @@ void DetectAppLayerProtocolRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].name = "app-layer-protocol"; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].desc = "match on the detected app-layer protocol"; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].url = "/rules/app-layer.html#app-layer-protocol"; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = - DetectAppLayerProtocolPacketMatch; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Setup = - DetectAppLayerProtocolSetup; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Free = - DetectAppLayerProtocolFree; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = DetectAppLayerProtocolPacketMatch; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Setup = DetectAppLayerProtocolSetup; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Free = DetectAppLayerProtocolFree; #ifdef UNITTESTS sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].RegisterTests = - DetectAppLayerProtocolRegisterTests; + DetectAppLayerProtocolRegisterTests; #endif sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].flags = - (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION); + (SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_HANDLE_NEGATION); - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].SetupPrefilter = - PrefilterSetupAppProto; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].SetupPrefilter = PrefilterSetupAppProto; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].SupportsPrefilter = - PrefilterAppProtoIsPrefilterable; + PrefilterAppProtoIsPrefilterable; return; } @@ -317,7 +301,7 @@ static int DetectAppLayerProtocolTest03(void) de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:http; sid:1;)"); + "(app-layer-protocol:http; sid:1;)"); FAIL_IF_NULL(s); FAIL_IF(s->alproto != ALPROTO_UNKNOWN); @@ -341,7 +325,7 @@ static int DetectAppLayerProtocolTest04(void) de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:!http; sid:1;)"); + "(app-layer-protocol:!http; sid:1;)"); FAIL_IF_NULL(s); FAIL_IF(s->alproto != ALPROTO_UNKNOWN); FAIL_IF(s->flags & SIG_FLAG_APPLAYER); @@ -366,7 +350,8 @@ static int DetectAppLayerProtocolTest05(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(app-layer-protocol:!http; app-layer-protocol:!smtp; sid:1;)"); FAIL_IF_NULL(s); FAIL_IF(s->alproto != ALPROTO_UNKNOWN); @@ -397,7 +382,7 @@ static int DetectAppLayerProtocolTest06(void) de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(app-layer-protocol:smtp; sid:1;)"); + "(app-layer-protocol:smtp; sid:1;)"); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); PASS; @@ -411,7 +396,7 @@ static int DetectAppLayerProtocolTest07(void) de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(app-layer-protocol:!smtp; sid:1;)"); + "(app-layer-protocol:!smtp; sid:1;)"); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); PASS; @@ -424,7 +409,8 @@ static int DetectAppLayerProtocolTest08(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(app-layer-protocol:!smtp; app-layer-protocol:http; sid:1;)"); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); @@ -438,7 +424,8 @@ static int DetectAppLayerProtocolTest09(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(app-layer-protocol:http; app-layer-protocol:!smtp; sid:1;)"); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); @@ -452,7 +439,8 @@ static int DetectAppLayerProtocolTest10(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(app-layer-protocol:smtp; app-layer-protocol:!http; sid:1;)"); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); @@ -488,7 +476,7 @@ static int DetectAppLayerProtocolTest13(void) de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:failed; sid:1;)"); + "(app-layer-protocol:failed; sid:1;)"); FAIL_IF_NULL(s); FAIL_IF(s->alproto != ALPROTO_UNKNOWN); @@ -510,8 +498,9 @@ static int DetectAppLayerProtocolTest14(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s1 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:http; flowbits:set,blah; sid:1;)"); + Signature *s1 = + DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flowbits:set,blah; sid:1;)"); FAIL_IF_NULL(s1); FAIL_IF(s1->alproto != ALPROTO_UNKNOWN); FAIL_IF_NULL(s1->init_data->smlists[DETECT_SM_LIST_MATCH]); @@ -520,8 +509,9 @@ static int DetectAppLayerProtocolTest14(void) FAIL_IF(data->alproto != ALPROTO_HTTP); FAIL_IF(data->negated); - Signature *s2 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:http; flow:to_client; sid:2;)"); + Signature *s2 = + DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flow:to_client; sid:2;)"); FAIL_IF_NULL(s2); FAIL_IF(s2->alproto != ALPROTO_UNKNOWN); FAIL_IF_NULL(s2->init_data->smlists[DETECT_SM_LIST_MATCH]); @@ -531,7 +521,8 @@ static int DetectAppLayerProtocolTest14(void) FAIL_IF(data->negated); /* flow:established and other options not supported for PD-only */ - Signature *s3 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + Signature *s3 = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(app-layer-protocol:http; flow:to_client,established; sid:3;)"); FAIL_IF_NULL(s3); FAIL_IF(s3->alproto != ALPROTO_UNKNOWN); @@ -550,36 +541,21 @@ static int DetectAppLayerProtocolTest14(void) PASS; } - static void DetectAppLayerProtocolRegisterTests(void) { - UtRegisterTest("DetectAppLayerProtocolTest01", - DetectAppLayerProtocolTest01); - UtRegisterTest("DetectAppLayerProtocolTest02", - DetectAppLayerProtocolTest02); - UtRegisterTest("DetectAppLayerProtocolTest03", - DetectAppLayerProtocolTest03); - UtRegisterTest("DetectAppLayerProtocolTest04", - DetectAppLayerProtocolTest04); - UtRegisterTest("DetectAppLayerProtocolTest05", - DetectAppLayerProtocolTest05); - UtRegisterTest("DetectAppLayerProtocolTest06", - DetectAppLayerProtocolTest06); - UtRegisterTest("DetectAppLayerProtocolTest07", - DetectAppLayerProtocolTest07); - UtRegisterTest("DetectAppLayerProtocolTest08", - DetectAppLayerProtocolTest08); - UtRegisterTest("DetectAppLayerProtocolTest09", - DetectAppLayerProtocolTest09); - UtRegisterTest("DetectAppLayerProtocolTest10", - DetectAppLayerProtocolTest10); - UtRegisterTest("DetectAppLayerProtocolTest11", - DetectAppLayerProtocolTest11); - UtRegisterTest("DetectAppLayerProtocolTest12", - DetectAppLayerProtocolTest12); - UtRegisterTest("DetectAppLayerProtocolTest13", - DetectAppLayerProtocolTest13); - UtRegisterTest("DetectAppLayerProtocolTest14", - DetectAppLayerProtocolTest14); + UtRegisterTest("DetectAppLayerProtocolTest01", DetectAppLayerProtocolTest01); + UtRegisterTest("DetectAppLayerProtocolTest02", DetectAppLayerProtocolTest02); + UtRegisterTest("DetectAppLayerProtocolTest03", DetectAppLayerProtocolTest03); + UtRegisterTest("DetectAppLayerProtocolTest04", DetectAppLayerProtocolTest04); + UtRegisterTest("DetectAppLayerProtocolTest05", DetectAppLayerProtocolTest05); + UtRegisterTest("DetectAppLayerProtocolTest06", DetectAppLayerProtocolTest06); + UtRegisterTest("DetectAppLayerProtocolTest07", DetectAppLayerProtocolTest07); + UtRegisterTest("DetectAppLayerProtocolTest08", DetectAppLayerProtocolTest08); + UtRegisterTest("DetectAppLayerProtocolTest09", DetectAppLayerProtocolTest09); + UtRegisterTest("DetectAppLayerProtocolTest10", DetectAppLayerProtocolTest10); + UtRegisterTest("DetectAppLayerProtocolTest11", DetectAppLayerProtocolTest11); + UtRegisterTest("DetectAppLayerProtocolTest12", DetectAppLayerProtocolTest12); + UtRegisterTest("DetectAppLayerProtocolTest13", DetectAppLayerProtocolTest13); + UtRegisterTest("DetectAppLayerProtocolTest14", DetectAppLayerProtocolTest14); } #endif /* UNITTESTS */ diff --git a/src/detect-asn1.c b/src/detect-asn1.c index c70bf8921fd3..8a8af68d2464 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -31,12 +31,12 @@ #include "flow.h" #include "detect-asn1.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" +#include "util/debug.h" -static int DetectAsn1Setup (DetectEngineCtx *, Signature *, const char *); +static int DetectAsn1Setup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectAsn1RegisterTests(void); #endif @@ -49,7 +49,7 @@ void DetectAsn1Register(void) { sigmatch_table[DETECT_ASN1].name = "asn1"; sigmatch_table[DETECT_ASN1].Setup = DetectAsn1Setup; - sigmatch_table[DETECT_ASN1].Free = DetectAsn1Free; + sigmatch_table[DETECT_ASN1].Free = DetectAsn1Free; #ifdef UNITTESTS sigmatch_table[DETECT_ASN1].RegisterTests = DetectAsn1RegisterTests; #endif @@ -130,42 +130,140 @@ static void DetectAsn1Free(DetectEngineCtx *de_ctx, void *ptr) */ static int DetectAsn1TestReal01(void) { - uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717" - "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" - "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" - "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones" - "\xA0\x0A\x43\x08""19590717"; + uint8_t *buf = (uint8_t *)"\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717" + "\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F" + "\x61\x11\x1A\x05" + "Pablo" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717"; uint16_t buflen = strlen((char *)buf) - 1; /* Check the start with AA (this is to test the relative_offset keyword) */ - uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717" - "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" - "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" - "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones" - "\xA0\x0A\x43\x08""19590717"; + uint8_t *buf2 = (uint8_t *)"AA\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717" + "\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F" + "\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717"; uint16_t buflen2 = strlen((char *)buf2) - 1; @@ -177,21 +275,21 @@ static int DetectAsn1TestReal01(void) FAIL_IF_NULL(p[1]); const char *sigs[3]; - sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " - "content:\"Pablo\"; asn1:absolute_offset 0, " - "oversize_length 130; sid:1;)"; - sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " - "content:\"AA\"; asn1:relative_offset 0, " - "oversize_length 130; sid:2;)"; - sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " - "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; - - uint32_t sid[3] = {1, 2, 3}; - uint32_t results[2][3] = { - /* packet 0 match sid 1 */ - {1, 0, 0}, - /* packet 1 match sid 2 */ - {0, 1, 0}}; + sigs[0] = "alert ip any any -> any any (msg:\"Testing id 1\"; " + "content:\"Pablo\"; asn1:absolute_offset 0, " + "oversize_length 130; sid:1;)"; + sigs[1] = "alert ip any any -> any any (msg:\"Testing id 2\"; " + "content:\"AA\"; asn1:relative_offset 0, " + "oversize_length 130; sid:2;)"; + sigs[2] = "alert ip any any -> any any (msg:\"Testing id 3\"; " + "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; + + uint32_t sid[3] = { 1, 2, 3 }; + uint32_t results[2][3] = { /* packet 0 match sid 1 */ + { 1, 0, 0 }, + /* packet 1 match sid 2 */ + { 0, 1, 0 } + }; /* None of the packets should match sid 3 */ FAIL_IF_NOT(UTHGenericTest(p, 2, sigs, sid, (uint32_t *)results, 3) == 1); @@ -205,42 +303,140 @@ static int DetectAsn1TestReal01(void) static int DetectAsn1TestReal02(void) { int result = 0; - uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717" - "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" - "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" - "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones" - "\xA0\x0A\x43\x08""19590717"; + uint8_t *buf = (uint8_t *)"\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717" + "\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F" + "\x61\x11\x1A\x05" + "Pablo" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717"; uint16_t buflen = strlen((char *)buf) - 1; /* Check the start with AA (this is to test the relative_offset keyword) */ - uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717" - "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" - "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" - "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones" - "\xA0\x0A\x43\x08""19590717"; + uint8_t *buf2 = (uint8_t *)"AA\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717" + "\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F" + "\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717"; uint16_t buflen2 = strlen((char *)buf2) - 1; @@ -253,23 +449,21 @@ static int DetectAsn1TestReal02(void) goto end; const char *sigs[3]; - sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " - "content:\"Pablo\"; asn1:absolute_offset 0, " - "oversize_length 140; sid:1;)"; - sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " - "content:\"AA\"; asn1:relative_offset 0, " - "oversize_length 140; sid:2;)"; - sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " - "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; - - uint32_t sid[3] = {1, 2, 3}; - - uint32_t results[2][3] = { - {0, 0, 0}, - {0, 0, 0}}; + sigs[0] = "alert ip any any -> any any (msg:\"Testing id 1\"; " + "content:\"Pablo\"; asn1:absolute_offset 0, " + "oversize_length 140; sid:1;)"; + sigs[1] = "alert ip any any -> any any (msg:\"Testing id 2\"; " + "content:\"AA\"; asn1:relative_offset 0, " + "oversize_length 140; sid:2;)"; + sigs[2] = "alert ip any any -> any any (msg:\"Testing id 3\"; " + "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; + + uint32_t sid[3] = { 1, 2, 3 }; + + uint32_t results[2][3] = { { 0, 0, 0 }, { 0, 0, 0 } }; /* None of the packets should match */ - result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3); + result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *)results, 3); UTHFreePackets(p, 2); end: @@ -293,13 +487,13 @@ static int DetectAsn1TestReal03(void) /* Fill the content of the number */ uint16_t i = 4; - for (; i < 257;i++) + for (; i < 257; i++) buf[i] = '\x05'; uint16_t buflen = 261; /* Check the start with AA (this is to test the relative_offset keyword) */ - uint8_t *buf2 = (uint8_t *) "AA\x03\x01\xFF"; + uint8_t *buf2 = (uint8_t *)"AA\x03\x01\xFF"; uint16_t buflen2 = 5; @@ -312,23 +506,22 @@ static int DetectAsn1TestReal03(void) goto end; const char *sigs[3]; - /* This should match the first packet */ - sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " - "asn1:absolute_offset 0, double_overflow; sid:1;)"; - /* This should match the second packet */ - sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " - "asn1:relative_offset 2, bitstring_overflow," - "oversize_length 140; sid:2;)"; - /* This should match no packet */ - sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " - "asn1: oversize_length 2000; sid:3;)"; + /* This should match the first packet */ + sigs[0] = "alert ip any any -> any any (msg:\"Testing id 1\"; " + "asn1:absolute_offset 0, double_overflow; sid:1;)"; + /* This should match the second packet */ + sigs[1] = "alert ip any any -> any any (msg:\"Testing id 2\"; " + "asn1:relative_offset 2, bitstring_overflow," + "oversize_length 140; sid:2;)"; + /* This should match no packet */ + sigs[2] = "alert ip any any -> any any (msg:\"Testing id 3\"; " + "asn1: oversize_length 2000; sid:3;)"; - uint32_t sid[3] = {1, 2, 3}; + uint32_t sid[3] = { 1, 2, 3 }; - uint32_t results[2][3] = {{1, 0, 0}, - {0, 1, 0}}; + uint32_t results[2][3] = { { 1, 0, 0 }, { 0, 1, 0 } }; - result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3); + result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *)results, 3); UTHFreePackets(p, 2); end: @@ -343,42 +536,140 @@ static int DetectAsn1TestReal03(void) static int DetectAsn1TestReal04(void) { int result = 0; - uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717" - "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" - "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" - "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones" - "\xA0\x0A\x43\x08""19590717"; + uint8_t *buf = (uint8_t *)"\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717" + "\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F" + "\x61\x11\x1A\x05" + "Pablo" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717"; uint16_t buflen = strlen((char *)buf) - 1; /* Check the start with AA (this is to test the relative_offset keyword) */ - uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717" - "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P" - "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F" - "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones" - "\xA0\x0A\x43\x08""19590717"; + uint8_t *buf2 = (uint8_t *)"AA\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717" + "\x60\x81\x85\x61\x10\x1A\x04" + "John" + "\x1A\x01" + "P" + "\x1A\x05" + "Smith" + "\xA0\x0A\x1A\x08" + "Director" + "\x42\x01\x33\xA1\x0A\x43\x08" + "19710917" + "\xA2\x12\x61\x10\x1A\x04" + "Mary" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA3\x42\x31\x1F\x61\x11\x1A\x05" + "Ralph" + "\x1A\x01" + "T" + "\x1A\x05" + "Smith" + "\xA0\x0A\x43\x08" + "19571111" + "\x31\x1F" + "\x61\x11\x1A\x05" + "Susan" + "\x1A\x01" + "B" + "\x1A\x05" + "Jones" + "\xA0\x0A\x43\x08" + "19590717"; uint16_t buflen2 = strlen((char *)buf2) - 1; @@ -391,23 +682,21 @@ static int DetectAsn1TestReal04(void) goto end; const char *sigs[3]; - sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; " - "content:\"Pablo\"; asn1:absolute_offset 0, " - "oversize_length 140; sid:1;)"; - sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; " - "content:\"John\"; asn1:relative_offset -11, " - "oversize_length 140; sid:2;)"; - sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; " - "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; - - uint32_t sid[3] = {1, 2, 3}; - - uint32_t results[2][3] = { - {0, 0, 0}, - {0, 0, 0}}; + sigs[0] = "alert ip any any -> any any (msg:\"Testing id 1\"; " + "content:\"Pablo\"; asn1:absolute_offset 0, " + "oversize_length 140; sid:1;)"; + sigs[1] = "alert ip any any -> any any (msg:\"Testing id 2\"; " + "content:\"John\"; asn1:relative_offset -11, " + "oversize_length 140; sid:2;)"; + sigs[2] = "alert ip any any -> any any (msg:\"Testing id 3\"; " + "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)"; + + uint32_t sid[3] = { 1, 2, 3 }; + + uint32_t results[2][3] = { { 0, 0, 0 }, { 0, 0, 0 } }; /* None of the packets should match */ - result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3); + result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *)results, 3); UTHFreePackets(p, 2); end: diff --git a/src/detect-asn1.h b/src/detect-asn1.h index 8c81ddcb305b..e3c2961ad083 100644 --- a/src/detect-asn1.h +++ b/src/detect-asn1.h @@ -24,7 +24,7 @@ #define __DETECT_ASN1_H__ /* prototypes */ -void DetectAsn1Register (void); +void DetectAsn1Register(void); bool DetectAsn1Match(const SigMatchData *smd, const uint8_t *buffer, const uint32_t buffer_len, const uint32_t offset); diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c index 09d89113d675..562aac93c14d 100644 --- a/src/detect-base64-data.c +++ b/src/detect-base64-data.c @@ -23,7 +23,7 @@ #include "detect-base64-data.h" #include "detect-engine-build.h" -#include "util-unittest.h" +#include "util/unittest.h" static int DetectBase64DataSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS @@ -33,20 +33,16 @@ static void DetectBase64DataRegisterTests(void); void DetectBase64DataRegister(void) { sigmatch_table[DETECT_BASE64_DATA].name = "base64_data"; - sigmatch_table[DETECT_BASE64_DATA].desc = - "Content match base64 decoded data."; - sigmatch_table[DETECT_BASE64_DATA].url = - "/rules/base64-keywords.html#base64-data"; + sigmatch_table[DETECT_BASE64_DATA].desc = "Content match base64 decoded data."; + sigmatch_table[DETECT_BASE64_DATA].url = "/rules/base64-keywords.html#base64-data"; sigmatch_table[DETECT_BASE64_DATA].Setup = DetectBase64DataSetup; #ifdef UNITTESTS - sigmatch_table[DETECT_BASE64_DATA].RegisterTests = - DetectBase64DataRegisterTests; + sigmatch_table[DETECT_BASE64_DATA].RegisterTests = DetectBase64DataRegisterTests; #endif sigmatch_table[DETECT_BASE64_DATA].flags |= SIGMATCH_NOOPT; } -static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *str) +static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { SigMatch *pm = NULL; @@ -61,8 +57,8 @@ static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, return 0; } -int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f) +int DetectBase64DataDoMatch( + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f) { if (det_ctx->base64_decoded_len) { return DetectEngineContentInspectionInternal(de_ctx, det_ctx, s, @@ -90,9 +86,9 @@ static int DetectBase64DataSetupTest01(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert smtp any any -> any any (msg:\"DetectBase64DataSetupTest\"; " - "base64_decode; base64_data; content:\"content\"; sid:1; rev:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert smtp any any -> any any (msg:\"DetectBase64DataSetupTest\"; " + "base64_decode; base64_data; content:\"content\"; sid:1; rev:1;)"); if (de_ctx->sig_list == NULL) { printf("SigInit failed: "); goto end; @@ -110,7 +106,7 @@ static int DetectBase64DataSetupTest01(void) if (de_ctx->sig_list->init_data->smlists[DETECT_SM_LIST_BASE64_DATA] == NULL) { printf("DETECT_SM_LIST_BASE64_DATA should not be NULL: "); - goto end; + goto end; } retval = 1; @@ -139,7 +135,9 @@ static int DetectBase64DataSetupTest04(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"some b64thing\"; flow:established,from_server; file_data; content:\"sometext\"; fast_pattern; base64_decode:relative; base64_data; content:\"foobar\"; nocase; tag:session,120,seconds; sid:1111111; rev:1;)"); + "alert tcp any any -> any any (msg:\"some b64thing\"; flow:established,from_server; " + "file_data; content:\"sometext\"; fast_pattern; base64_decode:relative; base64_data; " + "content:\"foobar\"; nocase; tag:session,120,seconds; sid:1111111; rev:1;)"); if (de_ctx->sig_list == NULL) { printf("SigInit failed: "); goto end; diff --git a/src/detect-base64-data.h b/src/detect-base64-data.h index 38bb93fc0691..4e5196e5f56f 100644 --- a/src/detect-base64-data.h +++ b/src/detect-base64-data.h @@ -19,7 +19,6 @@ #define __DETECT_BASE64_DATA_H__ void DetectBase64DataRegister(void); -int DetectBase64DataDoMatch(DetectEngineCtx *, DetectEngineThreadCtx *, - const Signature *, Flow *); +int DetectBase64DataDoMatch(DetectEngineCtx *, DetectEngineThreadCtx *, const Signature *, Flow *); #endif /* __DETECT_BASE64_DATA_H__ */ diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c index 2794509a430f..cfb2d2d874af 100644 --- a/src/detect-base64-decode.c +++ b/src/detect-base64-decode.c @@ -19,9 +19,9 @@ #include "detect.h" #include "detect-parse.h" #include "detect-base64-decode.h" -#include "util-base64.h" -#include "util-byte.h" -#include "util-print.h" +#include "util/base64.h" +#include "util/byte.h" +#include "util/print.h" #include "detect-engine-build.h" /* Arbitrary maximum buffer size for decoded base64 data. */ @@ -34,8 +34,8 @@ typedef struct DetectBase64Decode_ { } DetectBase64Decode; static const char decode_pattern[] = "\\s*(bytes\\s+(\\d+),?)?" - "\\s*(offset\\s+(\\d+),?)?" - "\\s*(\\w+)?"; + "\\s*(offset\\s+(\\d+),?)?" + "\\s*(\\w+)?"; static DetectParseRegex decode_pcre; @@ -48,15 +48,12 @@ static void DetectBase64DecodeRegisterTests(void); void DetectBase64DecodeRegister(void) { sigmatch_table[DETECT_BASE64_DECODE].name = "base64_decode"; - sigmatch_table[DETECT_BASE64_DECODE].desc = - "Decodes base64 encoded data."; - sigmatch_table[DETECT_BASE64_DECODE].url = - "/rules/base64-keywords.html#base64-decode"; + sigmatch_table[DETECT_BASE64_DECODE].desc = "Decodes base64 encoded data."; + sigmatch_table[DETECT_BASE64_DECODE].url = "/rules/base64-keywords.html#base64-decode"; sigmatch_table[DETECT_BASE64_DECODE].Setup = DetectBase64DecodeSetup; sigmatch_table[DETECT_BASE64_DECODE].Free = DetectBase64DecodeFree; #ifdef UNITTESTS - sigmatch_table[DETECT_BASE64_DECODE].RegisterTests = - DetectBase64DecodeRegisterTests; + sigmatch_table[DETECT_BASE64_DECODE].RegisterTests = DetectBase64DecodeRegisterTests; #endif sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_OPTIONAL_OPT; @@ -64,7 +61,7 @@ void DetectBase64DecodeRegister(void) } int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, - const SigMatchData *smd, const uint8_t *payload, uint32_t payload_len) + const SigMatchData *smd, const uint8_t *payload, uint32_t payload_len) { DetectBase64Decode *data = (DetectBase64Decode *)smd->ctx; int decode_len; @@ -98,8 +95,7 @@ int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s (void)DecodeBase64(det_ctx->base64_decoded, det_ctx->base64_decoded_len_max, payload, decode_len, &consumed, &num_decoded, BASE64_MODE_RFC4648); det_ctx->base64_decoded_len = num_decoded; - SCLogDebug("Decoded %d bytes from base64 data.", - det_ctx->base64_decoded_len); + SCLogDebug("Decoded %d bytes from base64 data.", det_ctx->base64_decoded_len); #if 0 if (det_ctx->base64_decoded_len) { printf("Decoded data:\n"); @@ -111,8 +107,8 @@ int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s return det_ctx->base64_decoded_len > 0; } -static int DetectBase64DecodeParse(const char *str, uint32_t *bytes, - uint32_t *offset, uint8_t *relative) +static int DetectBase64DecodeParse( + const char *str, uint32_t *bytes, uint32_t *offset, uint8_t *relative) { const char *bytes_str = NULL; const char *offset_str = NULL; @@ -137,7 +133,7 @@ static int DetectBase64DecodeParse(const char *str, uint32_t *bytes, goto error; } } - } + } if (pcre_rc >= 5) { if (pcre2_substring_get_bynumber(match, 4, (PCRE2_UCHAR8 **)&offset_str, &pcre2_len) == 0) { @@ -153,8 +149,7 @@ static int DetectBase64DecodeParse(const char *str, uint32_t *bytes, 0) { if (strcmp(relative_str, "relative") == 0) { *relative = 1; - } - else { + } else { SCLogError("Invalid argument: \"%s\"", relative_str); goto error; } @@ -183,8 +178,7 @@ static int DetectBase64DecodeParse(const char *str, uint32_t *bytes, return retval; } -static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *str) +static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { uint32_t bytes = 0; uint32_t offset = 0; @@ -208,16 +202,12 @@ static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, if (s->init_data->list != DETECT_SM_LIST_NOTSET) { sm_list = s->init_data->list; - } - else { - pm = DetectGetLastSMFromLists(s, - DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_ISDATAAT, -1); + } else { + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, -1); if (pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; - } - else { + } else { sm_list = SigMatchListSMBelongsTo(s, pm); if (sm_list < 0) { goto error; @@ -254,11 +244,10 @@ static void DetectBase64DecodeFree(DetectEngineCtx *de_ctx, void *ptr) SCFree(data); } - #ifdef UNITTESTS #include "detect-engine.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer-parser.h" #include "flow-util.h" #include "stream-tcp.h" @@ -293,24 +282,21 @@ static int DetectBase64TestDecodeParse(void) goto end; } - if (!DetectBase64DecodeParse("bytes 1, offset 2", &bytes, &offset, - &relative)) { + if (!DetectBase64DecodeParse("bytes 1, offset 2", &bytes, &offset, &relative)) { goto end; } if (bytes != 1 || offset != 2 || relative != 0) { goto end; } - if (!DetectBase64DecodeParse("bytes 1, offset 2, relative", &bytes, &offset, - &relative)) { + if (!DetectBase64DecodeParse("bytes 1, offset 2, relative", &bytes, &offset, &relative)) { goto end; } if (bytes != 1 || offset != 2 || relative != 1) { goto end; } - if (!DetectBase64DecodeParse("offset 2, relative", &bytes, &offset, - &relative)) { + if (!DetectBase64DecodeParse("offset 2, relative", &bytes, &offset, &relative)) { goto end; } if (bytes != 0 || offset != 2 || relative != 1) { @@ -318,20 +304,17 @@ static int DetectBase64TestDecodeParse(void) } /* Misspelled relative. */ - if (DetectBase64DecodeParse("bytes 1, offset 2, relatve", &bytes, &offset, - &relative)) { + if (DetectBase64DecodeParse("bytes 1, offset 2, relatve", &bytes, &offset, &relative)) { goto end; } /* Misspelled bytes. */ - if (DetectBase64DecodeParse("byts 1, offset 2, relatve", &bytes, &offset, - &relative)) { + if (DetectBase64DecodeParse("byts 1, offset 2, relatve", &bytes, &offset, &relative)) { goto end; } /* Misspelled offset. */ - if (DetectBase64DecodeParse("bytes 1, offst 2, relatve", &bytes, &offset, - &relative)) { + if (DetectBase64DecodeParse("bytes 1, offst 2, relatve", &bytes, &offset, &relative)) { goto end; } @@ -371,10 +354,12 @@ static int DetectBase64DecodeTestDecode(void) Packet *p = NULL; int retval = 0; + // clang-format off uint8_t payload[] = { 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', }; + // clang-format on memset(&tv, 0, sizeof(tv)); @@ -382,10 +367,9 @@ static int DetectBase64DecodeTestDecode(void) goto end; } - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"base64 test\"; " - "base64_decode; " - "sid:1; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode; " + "sid:1; rev:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -426,11 +410,13 @@ static int DetectBase64DecodeTestDecodeWithOffset(void) Packet *p = NULL; int retval = 0; + // clang-format off uint8_t payload[] = { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', }; + // clang-format on char decoded[] = "Hello World"; memset(&tv, 0, sizeof(tv)); @@ -439,10 +425,9 @@ static int DetectBase64DecodeTestDecodeWithOffset(void) goto end; } - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"base64 test\"; " - "base64_decode: offset 8; " - "sid:1; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode: offset 8; " + "sid:1; rev:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -486,10 +471,12 @@ static int DetectBase64DecodeTestDecodeLargeOffset(void) Packet *p = NULL; int retval = 0; + // clang-format off uint8_t payload[] = { 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', }; + // clang-format on memset(&tv, 0, sizeof(tv)); @@ -498,10 +485,9 @@ static int DetectBase64DecodeTestDecodeLargeOffset(void) } /* Offset is out of range. */ - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"base64 test\"; " - "base64_decode: bytes 16, offset 32; " - "sid:1; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode: bytes 16, offset 32; " + "sid:1; rev:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -542,11 +528,13 @@ static int DetectBase64DecodeTestDecodeRelative(void) Packet *p = NULL; int retval = 0; + // clang-format off uint8_t payload[] = { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', }; + // clang-format on char decoded[] = "Hello World"; memset(&tv, 0, sizeof(tv)); @@ -555,11 +543,10 @@ static int DetectBase64DecodeTestDecodeRelative(void) goto end; } - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"base64 test\"; " - "content:\"aaaaaaaa\"; " - "base64_decode: relative; " - "sid:1; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"base64 test\"; " + "content:\"aaaaaaaa\"; " + "base64_decode: relative; " + "sid:1; rev:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -601,13 +588,11 @@ static void DetectBase64DecodeRegisterTests(void) UtRegisterTest("DetectBase64TestDecodeParse", DetectBase64TestDecodeParse); UtRegisterTest("DetectBase64DecodeTestSetup", DetectBase64DecodeTestSetup); - UtRegisterTest("DetectBase64DecodeTestDecode", - DetectBase64DecodeTestDecode); - UtRegisterTest("DetectBase64DecodeTestDecodeWithOffset", - DetectBase64DecodeTestDecodeWithOffset); - UtRegisterTest("DetectBase64DecodeTestDecodeLargeOffset", - DetectBase64DecodeTestDecodeLargeOffset); - UtRegisterTest("DetectBase64DecodeTestDecodeRelative", - DetectBase64DecodeTestDecodeRelative); + UtRegisterTest("DetectBase64DecodeTestDecode", DetectBase64DecodeTestDecode); + UtRegisterTest( + "DetectBase64DecodeTestDecodeWithOffset", DetectBase64DecodeTestDecodeWithOffset); + UtRegisterTest( + "DetectBase64DecodeTestDecodeLargeOffset", DetectBase64DecodeTestDecodeLargeOffset); + UtRegisterTest("DetectBase64DecodeTestDecodeRelative", DetectBase64DecodeTestDecodeRelative); } #endif /* UNITTESTS */ diff --git a/src/detect-base64-decode.h b/src/detect-base64-decode.h index 58f4e526884c..9cd12f89e8fe 100644 --- a/src/detect-base64-decode.h +++ b/src/detect-base64-decode.h @@ -19,7 +19,7 @@ #define __DETECT_BASE64_DECODE_H__ void DetectBase64DecodeRegister(void); -int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, const Signature *, - const SigMatchData *, const uint8_t *, uint32_t); +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchData *, + const uint8_t *, uint32_t); #endif /* __DETECT_BASE64_DECODE_H__ */ diff --git a/src/detect-bsize.c b/src/detect-bsize.c index f69e20851839..eb1c6be2d669 100644 --- a/src/detect-bsize.c +++ b/src/detect-bsize.c @@ -24,8 +24,8 @@ */ #include "suricata-common.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect.h" #include "detect-parse.h" @@ -35,14 +35,14 @@ #include "detect-bsize.h" -#include "util-misc.h" +#include "util/misc.h" /*prototypes*/ -static int DetectBsizeSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectBsizeFree (DetectEngineCtx *, void *); +static int DetectBsizeSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectBsizeFree(DetectEngineCtx *, void *); static int SigParseGetMaxBsize(DetectU64Data *bsz); #ifdef UNITTESTS -static void DetectBsizeRegisterTests (void); +static void DetectBsizeRegisterTests(void); #endif bool DetectBsizeValidateContentCallback(Signature *s, const SignatureInitDataBuffer *b) @@ -196,7 +196,7 @@ static int SigParseGetMaxBsize(DetectU64Data *bsz) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectBsizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *sizestr) +static int DetectBsizeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *sizestr) { SCEnter(); diff --git a/src/detect-bsize.h b/src/detect-bsize.h index ac0b72e5893d..f6758fe64ce7 100644 --- a/src/detect-bsize.h +++ b/src/detect-bsize.h @@ -22,7 +22,7 @@ */ #ifndef __DETECT_BSIZE_H__ -#define __DETECT_BSIZE_H__ +#define __DETECT_BSIZE_H__ void DetectBsizeRegister(void); int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eof); diff --git a/src/detect-bypass.c b/src/detect-bypass.c index 51c5d2835160..f1d66076731e 100644 --- a/src/detect-bypass.c +++ b/src/detect-bypass.c @@ -43,14 +43,14 @@ #include "stream-tcp.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-device.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/device.h" -static int DetectBypassMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectBypassMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectBypassSetup(DetectEngineCtx *, Signature *, const char *); /** @@ -59,11 +59,12 @@ static int DetectBypassSetup(DetectEngineCtx *, Signature *, const char *); void DetectBypassRegister(void) { sigmatch_table[DETECT_BYPASS].name = "bypass"; - sigmatch_table[DETECT_BYPASS].desc = "call the bypass callback when the match of a sig is complete"; + sigmatch_table[DETECT_BYPASS].desc = + "call the bypass callback when the match of a sig is complete"; sigmatch_table[DETECT_BYPASS].url = "/rules/bypass-keyword.html"; sigmatch_table[DETECT_BYPASS].Match = DetectBypassMatch; sigmatch_table[DETECT_BYPASS].Setup = DetectBypassSetup; - sigmatch_table[DETECT_BYPASS].Free = NULL; + sigmatch_table[DETECT_BYPASS].Free = NULL; sigmatch_table[DETECT_BYPASS].flags = SIGMATCH_NOOPT; } @@ -83,8 +84,8 @@ static int DetectBypassSetup(DetectEngineCtx *de_ctx, Signature *s, const char * return 0; } -static int DetectBypassMatch(DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectBypassMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { PacketBypassCallback(p); diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index cf9b24348e5e..f208ebfbb3ab 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -44,11 +44,11 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" /* the default value of endianness to be used, if none's specified */ #define DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT DETECT_BYTE_EXTRACT_ENDIAN_BIG @@ -58,7 +58,7 @@ #define DETECT_BYTE_EXTRACT_BASE_NONE 0 #define DETECT_BYTE_EXTRACT_BASE_HEX 16 #define DETECT_BYTE_EXTRACT_BASE_DEC 10 -#define DETECT_BYTE_EXTRACT_BASE_OCT 8 +#define DETECT_BYTE_EXTRACT_BASE_OCT 8 /* the default value for multiplier. Either ways we always store a * multiplier, 1 or otherwise, so that we can always multiply the extracted @@ -76,15 +76,16 @@ /* the max no of bytes that can be extracted in non-string mode */ #define NO_STRING_MAX_BYTES_TO_EXTRACT 8 -#define PARSE_REGEX "^" \ - "\\s*([0-9]+)\\s*" \ - ",\\s*(-?[0-9]+)\\s*" \ - ",\\s*([^\\s,]+)\\s*" \ - "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ - "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ - "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ - "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ - "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ +#define PARSE_REGEX \ + "^" \ + "\\s*([0-9]+)\\s*" \ + ",\\s*(-?[0-9]+)\\s*" \ + ",\\s*([^\\s,]+)\\s*" \ + "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ + "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ + "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ + "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ + "(?:(?:,\\s*([^\\s,]+)\\s*)|(?:,\\s*([^\\s,]+)\\s+([^\\s,]+)\\s*))?" \ "$" static DetectParseRegex parse_regex; @@ -101,7 +102,8 @@ static void DetectByteExtractFree(DetectEngineCtx *, void *); void DetectByteExtractRegister(void) { sigmatch_table[DETECT_BYTE_EXTRACT].name = "byte_extract"; - sigmatch_table[DETECT_BYTE_EXTRACT].desc = "extract at a particular and store it in "; + sigmatch_table[DETECT_BYTE_EXTRACT].desc = + "extract at a particular and store it in "; sigmatch_table[DETECT_BYTE_EXTRACT].url = "/rules/payload-keywords.html#byte-extract"; sigmatch_table[DETECT_BYTE_EXTRACT].Match = NULL; sigmatch_table[DETECT_BYTE_EXTRACT].Setup = DetectByteExtractSetup; @@ -130,8 +132,9 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData * the packet from that point. */ if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - SCLogDebug("relative, working with det_ctx->buffer_offset %"PRIu32", " - "data->offset %"PRIu32"", det_ctx->buffer_offset, data->offset); + SCLogDebug("relative, working with det_ctx->buffer_offset %" PRIu32 ", " + "data->offset %" PRIu32 "", + det_ctx->buffer_offset, data->offset); ptr = payload + det_ctx->buffer_offset; len = payload_len - det_ctx->buffer_offset; @@ -143,9 +146,9 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData if (len <= 0) { return 0; } - //PrintRawDataFp(stdout,ptr,len); + // PrintRawDataFp(stdout,ptr,len); } else { - SCLogDebug("absolute, data->offset %"PRIu32"", data->offset); + SCLogDebug("absolute, data->offset %" PRIu32 "", data->offset); ptr = payload + data->offset; len = payload_len - data->offset; @@ -153,33 +156,30 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData /* Validate that the to-be-extracted is within the packet */ if (ptr < payload || data->nbytes > len) { - SCLogDebug("Data not within payload pkt=%p, ptr=%p, len=%"PRIu32", nbytes=%d", - payload, ptr, len, data->nbytes); + SCLogDebug("Data not within payload pkt=%p, ptr=%p, len=%" PRIu32 ", nbytes=%d", payload, + ptr, len, data->nbytes); return 0; } /* Extract the byte data */ if (data->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) { - extbytes = ByteExtractStringUint64(&val, data->base, - data->nbytes, (const char *)ptr); + extbytes = ByteExtractStringUint64(&val, data->base, data->nbytes, (const char *)ptr); if (extbytes <= 0) { /* strtoull() return 0 if there is no numeric value in data string */ if (val == 0) { SCLogDebug("No Numeric value"); return 0; } else { - SCLogDebug("error extracting %d bytes of string data: %d", - data->nbytes, extbytes); + SCLogDebug("error extracting %d bytes of string data: %d", data->nbytes, extbytes); return -1; } } } else { - int endianness = (endian == DETECT_BYTE_EXTRACT_ENDIAN_BIG) ? - BYTE_BIG_ENDIAN : BYTE_LITTLE_ENDIAN; + int endianness = + (endian == DETECT_BYTE_EXTRACT_ENDIAN_BIG) ? BYTE_BIG_ENDIAN : BYTE_LITTLE_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr); if (extbytes != data->nbytes) { - SCLogDebug("error extracting %d bytes of numeric data: %d", - data->nbytes, extbytes); + SCLogDebug("error extracting %d bytes of numeric data: %d", data->nbytes, extbytes); return 0; } } @@ -197,7 +197,7 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData det_ctx->buffer_offset = ptr - payload; *value = val; - SCLogDebug("extracted value is %"PRIu64, val); + SCLogDebug("extracted value is %" PRIu64, val); return 1; } @@ -211,7 +211,8 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData * \param bed On success an instance containing the parsed data. * On failure, NULL. */ -static inline DetectByteExtractData *DetectByteExtractParse(DetectEngineCtx *de_ctx, const char *arg) +static inline DetectByteExtractData *DetectByteExtractParse( + DetectEngineCtx *de_ctx, const char *arg) { DetectByteExtractData *bed = NULL; int res = 0; @@ -241,8 +242,7 @@ static inline DetectByteExtractData *DetectByteExtractParse(DetectEngineCtx *de_ "for arg 1 for byte_extract"); goto error; } - if (StringParseUint8(&bed->nbytes, 10, 0, - (const char *)nbytes_str) < 0) { + if (StringParseUint8(&bed->nbytes, 10, 0, (const char *)nbytes_str) < 0) { SCLogError("Invalid value for number of bytes" " to be extracted: \"%s\".", nbytes_str); @@ -420,8 +420,7 @@ static inline DetectByteExtractData *DetectByteExtractParse(DetectEngineCtx *de_ i); goto error; } - if (StringParseUint8(&bed->align_value, 10, 0, - (const char *)align_str) < 0) { + if (StringParseUint8(&bed->align_value, 10, 0, (const char *)align_str) < 0) { SCLogError("Invalid align_value: " "\"%s\".", align_str); @@ -506,7 +505,7 @@ static inline DetectByteExtractData *DetectByteExtractParse(DetectEngineCtx *de_ pcre2_match_data_free(match); return bed; - error: +error: if (bed != NULL) DetectByteExtractFree(de_ctx, bed); if (match) { @@ -547,9 +546,8 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, const c } } else if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_BYTEMATH, DETECT_ISDATAAT, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_BYTEMATH, DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -566,10 +564,8 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, const c s->flags |= SIG_FLAG_APPLAYER; } else if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, - DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_BYTEMATH, DETECT_ISDATAAT, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_BYTEMATH, DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -589,17 +585,16 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, const c goto error; if ((data->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) || - (data->base == DETECT_BYTE_EXTRACT_BASE_DEC) || - (data->base == DETECT_BYTE_EXTRACT_BASE_HEX) || - (data->base == DETECT_BYTE_EXTRACT_BASE_OCT) ) { + (data->base == DETECT_BYTE_EXTRACT_BASE_DEC) || + (data->base == DETECT_BYTE_EXTRACT_BASE_HEX) || + (data->base == DETECT_BYTE_EXTRACT_BASE_OCT)) { SCLogError("Invalid option. " "A byte_jump keyword with dce holds other invalid modifiers."); goto error; } } - SigMatch *prev_bed_sm = DetectGetLastSMByListId(s, sm_list, - DETECT_BYTE_EXTRACT, -1); + SigMatch *prev_bed_sm = DetectGetLastSMByListId(s, sm_list, DETECT_BYTE_EXTRACT, -1); if (prev_bed_sm == NULL) data->local_id = 0; else @@ -626,10 +621,10 @@ static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, const c pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } - okay: +okay: ret = 0; return ret; - error: +error: DetectByteExtractFree(de_ctx, data); return ret; } @@ -705,19 +700,15 @@ static int DetectByteExtractTest01(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != 0 || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || bed->flags != 0 || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -731,19 +722,16 @@ static int DetectByteExtractTest02(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_RELATIVE || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_RELATIVE || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -757,19 +745,16 @@ static int DetectByteExtractTest03(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != 10) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != 10) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -783,20 +768,17 @@ static int DetectByteExtractTest04(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != 10) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != + (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != 10) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -810,19 +792,16 @@ static int DetectByteExtractTest05(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_BIG || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_BIG || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -836,19 +815,16 @@ static int DetectByteExtractTest06(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -862,19 +838,16 @@ static int DetectByteExtractTest07(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DCE || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_ENDIAN || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DCE || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -888,19 +861,16 @@ static int DetectByteExtractTest08(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -914,19 +884,16 @@ static int DetectByteExtractTest09(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_OCT || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_OCT || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -940,19 +907,16 @@ static int DetectByteExtractTest10(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_DEC || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_DEC || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -966,19 +930,16 @@ static int DetectByteExtractTest11(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_ALIGN || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 4 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_ALIGN || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -992,20 +953,16 @@ static int DetectByteExtractTest12(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 4 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1019,21 +976,17 @@ static int DetectByteExtractTest13(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | - DETECT_BYTE_EXTRACT_FLAG_ENDIAN | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_BIG || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 4 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_ENDIAN | + DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_BIG || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1047,21 +1000,17 @@ static int DetectByteExtractTest14(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | - DETECT_BYTE_EXTRACT_FLAG_ENDIAN | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DCE || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 4 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_ENDIAN | + DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DCE || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1071,25 +1020,22 @@ static int DetectByteExtractTest15(void) { int result = 0; - DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, relative, little"); + DetectByteExtractData *bed = + DetectByteExtractParse(NULL, "4, 2, one, align 4, relative, little"); if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | - DETECT_BYTE_EXTRACT_FLAG_ENDIAN | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 4 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_ENDIAN | + DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1099,26 +1045,23 @@ static int DetectByteExtractTest16(void) { int result = 0; - DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, relative, little, multiplier 2"); + DetectByteExtractData *bed = + DetectByteExtractParse(NULL, "4, 2, one, align 4, relative, little, multiplier 2"); if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != 2 || - strcmp(bed->name, "one") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_ENDIAN | - DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 4 || - bed->multiplier_value != 2) { + if (bed->nbytes != 4 || bed->offset != 2 || strcmp(bed->name, "one") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_ALIGN | DETECT_BYTE_EXTRACT_FLAG_RELATIVE | + DETECT_BYTE_EXTRACT_FLAG_ENDIAN | + DETECT_BYTE_EXTRACT_FLAG_MULTIPLIER) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_LITTLE || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 4 || + bed->multiplier_value != 2) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1129,13 +1072,13 @@ static int DetectByteExtractTest17(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "relative, little, " - "multiplier 2, string hex"); + "relative, little, " + "multiplier 2, string hex"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1146,14 +1089,14 @@ static int DetectByteExtractTest18(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "relative, little, " - "multiplier 2, " - "relative"); + "relative, little, " + "multiplier 2, " + "relative"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1164,14 +1107,14 @@ static int DetectByteExtractTest19(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "relative, little, " - "multiplier 2, " - "little"); + "relative, little, " + "multiplier 2, " + "little"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1182,14 +1125,14 @@ static int DetectByteExtractTest20(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "relative, " - "multiplier 2, " - "align 2"); + "relative, " + "multiplier 2, " + "align 2"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1200,14 +1143,14 @@ static int DetectByteExtractTest21(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "multiplier 2, " - "relative, " - "multiplier 2"); + "multiplier 2, " + "relative, " + "multiplier 2"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1218,14 +1161,14 @@ static int DetectByteExtractTest22(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "string hex, " - "relative, " - "string hex"); + "string hex, " + "relative, " + "string hex"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1236,14 +1179,14 @@ static int DetectByteExtractTest23(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "string hex, " - "relative, " - "string oct"); + "string hex, " + "relative, " + "string oct"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1254,13 +1197,13 @@ static int DetectByteExtractTest24(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "24, 2, one, align 4, " - "string hex, " - "relative"); + "string hex, " + "relative"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1271,13 +1214,13 @@ static int DetectByteExtractTest25(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "9, 2, one, align 4, " - "little, " - "relative"); + "little, " + "relative"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1288,14 +1231,14 @@ static int DetectByteExtractTest26(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "little, " - "relative, " - "multiplier 65536"); + "little, " + "relative, " + "multiplier 65536"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1306,14 +1249,14 @@ static int DetectByteExtractTest27(void) int result = 0; DetectByteExtractData *bed = DetectByteExtractParse(NULL, "4, 2, one, align 4, " - "little, " - "relative, " - "multiplier 0"); + "little, " + "relative, " + "multiplier 0"); if (bed != NULL) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1328,7 +1271,7 @@ static int DetectByteExtractTest28(void) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1343,7 +1286,7 @@ static int DetectByteExtractTest29(void) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1358,7 +1301,7 @@ static int DetectByteExtractTest30(void) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1373,7 +1316,7 @@ static int DetectByteExtractTest31(void) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1388,7 +1331,7 @@ static int DetectByteExtractTest32(void) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1403,7 +1346,7 @@ static int DetectByteExtractTest33(void) goto end; result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -1424,10 +1367,10 @@ static int DetectByteExtractTest34(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,2,two,relative,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,2,two,relative,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1445,13 +1388,10 @@ static int DetectByteExtractTest34(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -1463,21 +1403,17 @@ static int DetectByteExtractTest34(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 2 || - strncmp(bed->name, "two", cd->content_len) != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_STRING) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strncmp(bed->name, "two", cd->content_len) != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -1501,10 +1437,10 @@ static int DetectByteExtractTest35(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; pcre:/asf/; " - "byte_extract:4,0,two,relative,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; pcre:/asf/; " + "byte_extract:4,0,two,relative,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1522,13 +1458,10 @@ static int DetectByteExtractTest35(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -1551,21 +1484,17 @@ static int DetectByteExtractTest35(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_STRING) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -1589,10 +1518,10 @@ static int DetectByteExtractTest36(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; byte_jump:1,13; " - "byte_extract:4,0,two,relative,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; byte_jump:1,13; " + "byte_extract:4,0,two,relative,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1610,13 +1539,10 @@ static int DetectByteExtractTest36(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -1639,21 +1565,17 @@ static int DetectByteExtractTest36(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_STRING) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -1677,10 +1599,10 @@ static int DetectByteExtractTest37(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; uricontent:\"two\"; " - "byte_extract:4,0,two,relative,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; uricontent:\"two\"; " + "byte_extract:4,0,two,relative,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1698,13 +1620,10 @@ static int DetectByteExtractTest37(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -1722,13 +1641,10 @@ static int DetectByteExtractTest37(void) } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)ud->content, "two", cd->content_len) != 0 || - ud->flags & DETECT_CONTENT_NOCASE || - ud->flags & DETECT_CONTENT_WITHIN || - ud->flags & DETECT_CONTENT_DISTANCE || - ud->flags & DETECT_CONTENT_FAST_PATTERN || - !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || - ud->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)ud->content, "two", cd->content_len) != 0 || + ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || + ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || + !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || ud->flags & DETECT_CONTENT_NEGATED) { printf("two failed\n"); result = 0; goto end; @@ -1740,21 +1656,17 @@ static int DetectByteExtractTest37(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_STRING) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -1778,10 +1690,10 @@ static int DetectByteExtractTest38(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; uricontent:\"two\"; " - "byte_extract:4,0,two,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; uricontent:\"two\"; " + "byte_extract:4,0,two,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1799,13 +1711,10 @@ static int DetectByteExtractTest38(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -1817,14 +1726,11 @@ static int DetectByteExtractTest38(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags !=DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } @@ -1835,13 +1741,10 @@ static int DetectByteExtractTest38(void) } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)ud->content, "two", cd->content_len) != 0 || - ud->flags & DETECT_CONTENT_NOCASE || - ud->flags & DETECT_CONTENT_WITHIN || - ud->flags & DETECT_CONTENT_DISTANCE || - ud->flags & DETECT_CONTENT_FAST_PATTERN || - ud->flags & DETECT_CONTENT_RELATIVE_NEXT || - ud->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)ud->content, "two", cd->content_len) != 0 || + ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || + ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || + ud->flags & DETECT_CONTENT_RELATIVE_NEXT || ud->flags & DETECT_CONTENT_NEGATED) { printf("two failed\n"); result = 0; goto end; @@ -1854,7 +1757,7 @@ static int DetectByteExtractTest38(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -1878,10 +1781,10 @@ static int DetectByteExtractTest39(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; content:\"two\"; http_uri; " - "byte_extract:4,0,two,relative,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; content:\"two\"; http_uri; " + "byte_extract:4,0,two,relative,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1899,13 +1802,10 @@ static int DetectByteExtractTest39(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -1923,13 +1823,10 @@ static int DetectByteExtractTest39(void) } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)ud->content, "two", cd->content_len) != 0 || - ud->flags & DETECT_CONTENT_NOCASE || - ud->flags & DETECT_CONTENT_WITHIN || - ud->flags & DETECT_CONTENT_DISTANCE || - ud->flags & DETECT_CONTENT_FAST_PATTERN || - !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || - ud->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)ud->content, "two", cd->content_len) != 0 || + ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || + ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || + !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || ud->flags & DETECT_CONTENT_NEGATED) { printf("two failed\n"); result = 0; goto end; @@ -1941,21 +1838,17 @@ static int DetectByteExtractTest39(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_STRING) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -1979,10 +1872,10 @@ static int DetectByteExtractTest40(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; content:\"two\"; http_uri; " - "byte_extract:4,0,two,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; content:\"two\"; http_uri; " + "byte_extract:4,0,two,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2000,13 +1893,10 @@ static int DetectByteExtractTest40(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2018,14 +1908,11 @@ static int DetectByteExtractTest40(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags !=DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } @@ -2036,13 +1923,10 @@ static int DetectByteExtractTest40(void) } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)ud->content, "two", cd->content_len) != 0 || - ud->flags & DETECT_CONTENT_NOCASE || - ud->flags & DETECT_CONTENT_WITHIN || - ud->flags & DETECT_CONTENT_DISTANCE || - ud->flags & DETECT_CONTENT_FAST_PATTERN || - ud->flags & DETECT_CONTENT_RELATIVE_NEXT || - ud->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)ud->content, "two", cd->content_len) != 0 || + ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || + ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || + ud->flags & DETECT_CONTENT_RELATIVE_NEXT || ud->flags & DETECT_CONTENT_NEGATED) { printf("two failed\n"); result = 0; goto end; @@ -2055,7 +1939,7 @@ static int DetectByteExtractTest40(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2078,11 +1962,11 @@ static int DetectByteExtractTest41(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2100,13 +1984,10 @@ static int DetectByteExtractTest41(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2118,14 +1999,11 @@ static int DetectByteExtractTest41(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -2139,14 +2017,11 @@ static int DetectByteExtractTest41(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "three") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "three") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 1) { @@ -2156,7 +2031,7 @@ static int DetectByteExtractTest41(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2180,13 +2055,13 @@ static int DetectByteExtractTest42(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "uricontent: \"three\"; " - "byte_extract:4,0,four,string,hex,relative; " - "byte_extract:4,0,five,string,hex; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "uricontent: \"three\"; " + "byte_extract:4,0,four,string,hex,relative; " + "byte_extract:4,0,five,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2204,13 +2079,10 @@ static int DetectByteExtractTest42(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2222,14 +2094,11 @@ static int DetectByteExtractTest42(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -2243,14 +2112,11 @@ static int DetectByteExtractTest42(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "five") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "five") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 1) { @@ -2268,13 +2134,10 @@ static int DetectByteExtractTest42(void) } ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)ud->content, "three", cd->content_len) != 0 || - ud->flags & DETECT_CONTENT_NOCASE || - ud->flags & DETECT_CONTENT_WITHIN || - ud->flags & DETECT_CONTENT_DISTANCE || - ud->flags & DETECT_CONTENT_FAST_PATTERN || - !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || - ud->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)ud->content, "three", cd->content_len) != 0 || + ud->flags & DETECT_CONTENT_NOCASE || ud->flags & DETECT_CONTENT_WITHIN || + ud->flags & DETECT_CONTENT_DISTANCE || ud->flags & DETECT_CONTENT_FAST_PATTERN || + !(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) || ud->flags & DETECT_CONTENT_NEGATED) { printf("two failed\n"); result = 0; goto end; @@ -2286,15 +2149,11 @@ static int DetectByteExtractTest42(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "four") != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | - DETECT_BYTE_EXTRACT_FLAG_STRING) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "four") != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_RELATIVE | DETECT_BYTE_EXTRACT_FLAG_STRING) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -2307,7 +2166,7 @@ static int DetectByteExtractTest42(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2330,11 +2189,11 @@ static int DetectByteExtractTest43(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "content: \"three\"; offset:two; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "content: \"three\"; offset:two; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2352,13 +2211,10 @@ static int DetectByteExtractTest43(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2370,14 +2226,11 @@ static int DetectByteExtractTest43(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -2392,9 +2245,8 @@ static int DetectByteExtractTest43(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_OFFSET_VAR | - DETECT_CONTENT_OFFSET) || - cd->offset != bed->local_id) { + cd->flags != (DETECT_CONTENT_OFFSET_VAR | DETECT_CONTENT_OFFSET) || + cd->offset != bed->local_id) { printf("three failed\n"); result = 0; goto end; @@ -2405,7 +2257,7 @@ static int DetectByteExtractTest43(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2429,13 +2281,13 @@ static int DetectByteExtractTest44(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "content: \"four\"; offset:two; " - "content: \"five\"; offset:three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "content: \"four\"; offset:two; " + "content: \"five\"; offset:three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2453,13 +2305,10 @@ static int DetectByteExtractTest44(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2471,14 +2320,11 @@ static int DetectByteExtractTest44(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -2500,9 +2346,8 @@ static int DetectByteExtractTest44(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_OFFSET_VAR | - DETECT_CONTENT_OFFSET) || - cd->offset != bed1->local_id) { + cd->flags != (DETECT_CONTENT_OFFSET_VAR | DETECT_CONTENT_OFFSET) || + cd->offset != bed1->local_id) { printf("four failed\n"); result = 0; goto end; @@ -2515,9 +2360,8 @@ static int DetectByteExtractTest44(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_OFFSET_VAR | - DETECT_CONTENT_OFFSET) || - cd->offset != bed2->local_id) { + cd->flags != (DETECT_CONTENT_OFFSET_VAR | DETECT_CONTENT_OFFSET) || + cd->offset != bed2->local_id) { printf("five failed\n"); result = 0; goto end; @@ -2528,7 +2372,7 @@ static int DetectByteExtractTest44(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2551,11 +2395,11 @@ static int DetectByteExtractTest45(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "content: \"three\"; depth:two; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "content: \"three\"; depth:two; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2573,13 +2417,10 @@ static int DetectByteExtractTest45(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2591,14 +2432,11 @@ static int DetectByteExtractTest45(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -2613,10 +2451,8 @@ static int DetectByteExtractTest45(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DEPTH_VAR | - DETECT_CONTENT_DEPTH) || - cd->depth != bed->local_id || - cd->offset != 0) { + cd->flags != (DETECT_CONTENT_DEPTH_VAR | DETECT_CONTENT_DEPTH) || + cd->depth != bed->local_id || cd->offset != 0) { printf("three failed\n"); result = 0; goto end; @@ -2627,7 +2463,7 @@ static int DetectByteExtractTest45(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2651,13 +2487,13 @@ static int DetectByteExtractTest46(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "content: \"four\"; depth:two; " - "content: \"five\"; depth:three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "content: \"four\"; depth:two; " + "content: \"five\"; depth:three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2675,13 +2511,10 @@ static int DetectByteExtractTest46(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2693,14 +2526,11 @@ static int DetectByteExtractTest46(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -2722,9 +2552,8 @@ static int DetectByteExtractTest46(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DEPTH_VAR | - DETECT_CONTENT_DEPTH) || - cd->depth != bed1->local_id) { + cd->flags != (DETECT_CONTENT_DEPTH_VAR | DETECT_CONTENT_DEPTH) || + cd->depth != bed1->local_id) { printf("four failed\n"); result = 0; goto end; @@ -2737,9 +2566,8 @@ static int DetectByteExtractTest46(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DEPTH_VAR | - DETECT_CONTENT_DEPTH) || - cd->depth != bed2->local_id) { + cd->flags != (DETECT_CONTENT_DEPTH_VAR | DETECT_CONTENT_DEPTH) || + cd->depth != bed2->local_id) { printf("five failed\n"); result = 0; goto end; @@ -2750,7 +2578,7 @@ static int DetectByteExtractTest46(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2773,11 +2601,11 @@ static int DetectByteExtractTest47(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "content: \"three\"; distance:two; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "content: \"three\"; distance:two; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2795,13 +2623,10 @@ static int DetectByteExtractTest47(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2813,14 +2638,11 @@ static int DetectByteExtractTest47(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -2835,11 +2657,8 @@ static int DetectByteExtractTest47(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DISTANCE_VAR | - DETECT_CONTENT_DISTANCE) || - cd->distance != bed->local_id || - cd->offset != 0 || - cd->depth != 0) { + cd->flags != (DETECT_CONTENT_DISTANCE_VAR | DETECT_CONTENT_DISTANCE) || + cd->distance != bed->local_id || cd->offset != 0 || cd->depth != 0) { printf("three failed\n"); result = 0; goto end; @@ -2850,7 +2669,7 @@ static int DetectByteExtractTest47(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -2874,13 +2693,13 @@ static int DetectByteExtractTest48(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "content: \"four\"; distance:two; " - "content: \"five\"; distance:three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "content: \"four\"; distance:two; " + "content: \"five\"; distance:three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -2898,13 +2717,10 @@ static int DetectByteExtractTest48(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -2916,14 +2732,11 @@ static int DetectByteExtractTest48(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -2945,12 +2758,9 @@ static int DetectByteExtractTest48(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DISTANCE_VAR | - DETECT_CONTENT_DISTANCE | - DETECT_CONTENT_DISTANCE_NEXT) || - cd->distance != bed1->local_id || - cd->depth != 0 || - cd->offset != 0) { + cd->flags != (DETECT_CONTENT_DISTANCE_VAR | DETECT_CONTENT_DISTANCE | + DETECT_CONTENT_DISTANCE_NEXT) || + cd->distance != bed1->local_id || cd->depth != 0 || cd->offset != 0) { printf("four failed\n"); result = 0; goto end; @@ -2963,11 +2773,8 @@ static int DetectByteExtractTest48(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DISTANCE_VAR | - DETECT_CONTENT_DISTANCE) || - cd->distance != bed2->local_id || - cd->depth != 0 || - cd->offset != 0) { + cd->flags != (DETECT_CONTENT_DISTANCE_VAR | DETECT_CONTENT_DISTANCE) || + cd->distance != bed2->local_id || cd->depth != 0 || cd->offset != 0) { printf("five failed\n"); result = 0; goto end; @@ -2978,7 +2785,7 @@ static int DetectByteExtractTest48(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3001,11 +2808,11 @@ static int DetectByteExtractTest49(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "content: \"three\"; within:two; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "content: \"three\"; within:two; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3023,13 +2830,10 @@ static int DetectByteExtractTest49(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3041,14 +2845,11 @@ static int DetectByteExtractTest49(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -3063,12 +2864,8 @@ static int DetectByteExtractTest49(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "three", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_WITHIN_VAR | - DETECT_CONTENT_WITHIN) || - cd->within != bed->local_id || - cd->offset != 0 || - cd->depth != 0 || - cd->distance != 0) { + cd->flags != (DETECT_CONTENT_WITHIN_VAR | DETECT_CONTENT_WITHIN) || + cd->within != bed->local_id || cd->offset != 0 || cd->depth != 0 || cd->distance != 0) { printf("three failed\n"); result = 0; goto end; @@ -3079,7 +2876,7 @@ static int DetectByteExtractTest49(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3103,13 +2900,13 @@ static int DetectByteExtractTest50(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "content: \"four\"; within:two; " - "content: \"five\"; within:three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "content: \"four\"; within:two; " + "content: \"five\"; within:three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3127,13 +2924,10 @@ static int DetectByteExtractTest50(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3145,14 +2939,11 @@ static int DetectByteExtractTest50(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -3174,13 +2965,10 @@ static int DetectByteExtractTest50(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_WITHIN_VAR | - DETECT_CONTENT_WITHIN| - DETECT_CONTENT_WITHIN_NEXT) || - cd->within != bed1->local_id || - cd->depth != 0 || - cd->offset != 0 || - cd->distance != 0) { + cd->flags != (DETECT_CONTENT_WITHIN_VAR | DETECT_CONTENT_WITHIN | + DETECT_CONTENT_WITHIN_NEXT) || + cd->within != bed1->local_id || cd->depth != 0 || cd->offset != 0 || + cd->distance != 0) { printf("four failed\n"); result = 0; goto end; @@ -3193,12 +2981,9 @@ static int DetectByteExtractTest50(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "five", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_WITHIN_VAR | - DETECT_CONTENT_WITHIN) || - cd->within != bed2->local_id || - cd->depth != 0 || - cd->offset != 0 || - cd->distance != 0) { + cd->flags != (DETECT_CONTENT_WITHIN_VAR | DETECT_CONTENT_WITHIN) || + cd->within != bed2->local_id || cd->depth != 0 || cd->offset != 0 || + cd->distance != 0) { printf("five failed\n"); result = 0; goto end; @@ -3209,7 +2994,7 @@ static int DetectByteExtractTest50(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3233,11 +3018,11 @@ static int DetectByteExtractTest51(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_test: 2,=,10, two; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_test: 2,=,10, two; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3255,13 +3040,10 @@ static int DetectByteExtractTest51(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3273,14 +3055,11 @@ static int DetectByteExtractTest51(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -3294,9 +3073,7 @@ static int DetectByteExtractTest51(void) goto end; } btd = (DetectBytetestData *)sm->ctx; - if (btd->flags != DETECT_BYTETEST_OFFSET_VAR || - btd->value != 10 || - btd->offset != 0) { + if (btd->flags != DETECT_BYTETEST_OFFSET_VAR || btd->value != 10 || btd->offset != 0) { printf("three failed\n"); result = 0; goto end; @@ -3307,7 +3084,7 @@ static int DetectByteExtractTest51(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3331,13 +3108,13 @@ static int DetectByteExtractTest52(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "byte_test: 2,=,two,three; " - "byte_test: 3,=,10,three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "byte_test: 2,=,two,three; " + "byte_test: 3,=,10,three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3355,13 +3132,10 @@ static int DetectByteExtractTest52(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3373,14 +3147,11 @@ static int DetectByteExtractTest52(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -3400,10 +3171,8 @@ static int DetectByteExtractTest52(void) goto end; } btd = (DetectBytetestData *)sm->ctx; - if (btd->flags != (DETECT_BYTETEST_OFFSET_VAR | - DETECT_BYTETEST_VALUE_VAR) || - btd->value != 0 || - btd->offset != 1) { + if (btd->flags != (DETECT_BYTETEST_OFFSET_VAR | DETECT_BYTETEST_VALUE_VAR) || btd->value != 0 || + btd->offset != 1) { printf("three failed\n"); result = 0; goto end; @@ -3415,9 +3184,7 @@ static int DetectByteExtractTest52(void) goto end; } btd = (DetectBytetestData *)sm->ctx; - if (btd->flags != DETECT_BYTETEST_OFFSET_VAR || - btd->value != 10 || - btd->offset != 1) { + if (btd->flags != DETECT_BYTETEST_OFFSET_VAR || btd->value != 10 || btd->offset != 1) { printf("four failed\n"); result = 0; goto end; @@ -3428,7 +3195,7 @@ static int DetectByteExtractTest52(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3452,11 +3219,11 @@ static int DetectByteExtractTest53(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_jump: 2,two; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_jump: 2,two; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3474,13 +3241,10 @@ static int DetectByteExtractTest53(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3492,14 +3256,11 @@ static int DetectByteExtractTest53(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 0 || - strcmp(bed->name, "two") != 0 || - bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 0 || strcmp(bed->name, "two") != 0 || + bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed->local_id != 0) { @@ -3513,8 +3274,7 @@ static int DetectByteExtractTest53(void) goto end; } bjd = (DetectBytejumpData *)sm->ctx; - if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || - bjd->offset != 0) { + if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; @@ -3525,7 +3285,7 @@ static int DetectByteExtractTest53(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3549,13 +3309,13 @@ static int DetectByteExtractTest54(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "byte_jump: 2,two; " - "byte_jump: 3,three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "byte_jump: 2,two; " + "byte_jump: 3,three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3573,13 +3333,10 @@ static int DetectByteExtractTest54(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3591,14 +3348,11 @@ static int DetectByteExtractTest54(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -3618,8 +3372,7 @@ static int DetectByteExtractTest54(void) goto end; } bjd = (DetectBytejumpData *)sm->ctx; - if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || - bjd->offset != 0) { + if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; @@ -3631,8 +3384,7 @@ static int DetectByteExtractTest54(void) goto end; } bjd = (DetectBytejumpData *)sm->ctx; - if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || - bjd->offset != 1) { + if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || bjd->offset != 1) { printf("four failed\n"); result = 0; goto end; @@ -3643,7 +3395,7 @@ static int DetectByteExtractTest54(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3667,14 +3419,14 @@ static int DetectByteExtractTest55(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing byte_extract\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "byte_extract:4,0,four,string,hex; " - "byte_extract:4,0,five,string,hex; " - "content: \"four\"; within:two; distance:three; " - "sid:1;)"); + "(msg:\"Testing byte_extract\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "byte_extract:4,0,four,string,hex; " + "byte_extract:4,0,five,string,hex; " + "content: \"four\"; within:two; distance:three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3689,13 +3441,10 @@ static int DetectByteExtractTest55(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed: "); goto end; } @@ -3705,14 +3454,11 @@ static int DetectByteExtractTest55(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -3741,12 +3487,9 @@ static int DetectByteExtractTest55(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DISTANCE_VAR | - DETECT_CONTENT_WITHIN_VAR | - DETECT_CONTENT_DISTANCE | - DETECT_CONTENT_WITHIN) || - cd->within != bed1->local_id || - cd->distance != bed2->local_id) { + cd->flags != (DETECT_CONTENT_DISTANCE_VAR | DETECT_CONTENT_WITHIN_VAR | + DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + cd->within != bed1->local_id || cd->distance != bed2->local_id) { printf("four failed: "); goto end; } @@ -3757,7 +3500,7 @@ static int DetectByteExtractTest55(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3781,15 +3524,15 @@ static int DetectByteExtractTest56(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "uricontent:\"urione\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "byte_extract:4,0,four,string,hex; " - "byte_extract:4,0,five,string,hex; " - "content: \"four\"; within:two; distance:three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "uricontent:\"urione\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "byte_extract:4,0,four,string,hex; " + "byte_extract:4,0,five,string,hex; " + "content: \"four\"; within:two; distance:three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3807,13 +3550,10 @@ static int DetectByteExtractTest56(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "urione", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "urione", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3829,13 +3569,10 @@ static int DetectByteExtractTest56(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3847,14 +3584,11 @@ static int DetectByteExtractTest56(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -3888,12 +3622,9 @@ static int DetectByteExtractTest56(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DISTANCE_VAR | - DETECT_CONTENT_WITHIN_VAR | - DETECT_CONTENT_DISTANCE | - DETECT_CONTENT_WITHIN) || - cd->within != bed1->local_id || - cd->distance != bed2->local_id ) { + cd->flags != (DETECT_CONTENT_DISTANCE_VAR | DETECT_CONTENT_WITHIN_VAR | + DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + cd->within != bed1->local_id || cd->distance != bed2->local_id) { printf("four failed\n"); result = 0; goto end; @@ -3905,7 +3636,7 @@ static int DetectByteExtractTest56(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -3931,15 +3662,15 @@ static int DetectByteExtractTest57(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "uricontent: \"urione\"; " - "byte_extract:4,0,two,string,hex,relative; " - "byte_extract:4,0,three,string,hex,relative; " - "byte_extract:4,0,four,string,hex,relative; " - "byte_extract:4,0,five,string,hex,relative; " - "uricontent: \"four\"; within:two; distance:three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "uricontent: \"urione\"; " + "byte_extract:4,0,two,string,hex,relative; " + "byte_extract:4,0,three,string,hex,relative; " + "byte_extract:4,0,four,string,hex,relative; " + "byte_extract:4,0,five,string,hex,relative; " + "uricontent: \"four\"; within:two; distance:three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3957,13 +3688,10 @@ static int DetectByteExtractTest57(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3979,13 +3707,10 @@ static int DetectByteExtractTest57(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "urione", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "urione", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -3997,15 +3722,11 @@ static int DetectByteExtractTest57(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -4053,12 +3774,9 @@ static int DetectByteExtractTest57(void) } cd = (DetectContentData *)sm->ctx; if (strncmp((char *)cd->content, "four", cd->content_len) != 0 || - cd->flags != (DETECT_CONTENT_DISTANCE_VAR | - DETECT_CONTENT_WITHIN_VAR | - DETECT_CONTENT_DISTANCE | - DETECT_CONTENT_WITHIN) || - cd->within != bed1->local_id || - cd->distance != bed2->local_id) { + cd->flags != (DETECT_CONTENT_DISTANCE_VAR | DETECT_CONTENT_WITHIN_VAR | + DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + cd->within != bed1->local_id || cd->distance != bed2->local_id) { printf("four failed\n"); result = 0; goto end; @@ -4070,7 +3788,7 @@ static int DetectByteExtractTest57(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -4095,14 +3813,14 @@ static int DetectByteExtractTest58(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "byte_jump: 2,two; " - "byte_jump: 3,three; " - "isdataat: three; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "byte_jump: 2,two; " + "byte_jump: 3,three; " + "isdataat: three; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -4120,13 +3838,10 @@ static int DetectByteExtractTest58(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -4138,14 +3853,11 @@ static int DetectByteExtractTest58(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -4165,8 +3877,7 @@ static int DetectByteExtractTest58(void) goto end; } bjd = (DetectBytejumpData *)sm->ctx; - if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || - bjd->offset != 0) { + if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; @@ -4178,8 +3889,7 @@ static int DetectByteExtractTest58(void) goto end; } bjd = (DetectBytejumpData *)sm->ctx; - if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || - bjd->offset != 1) { + if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || bjd->offset != 1) { printf("four failed\n"); result = 0; goto end; @@ -4191,8 +3901,7 @@ static int DetectByteExtractTest58(void) goto end; } isdd = (DetectIsdataatData *)sm->ctx; - if (isdd->flags != ISDATAAT_OFFSET_VAR || - isdd->dataat != 1) { + if (isdd->flags != ISDATAAT_OFFSET_VAR || isdd->dataat != 1) { printf("isdataat failed\n"); result = 0; goto end; @@ -4203,7 +3912,7 @@ static int DetectByteExtractTest58(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -4228,14 +3937,14 @@ static int DetectByteExtractTest59(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex; " - "byte_extract:4,0,three,string,hex; " - "byte_jump: 2,two; " - "byte_jump: 3,three; " - "isdataat: three,relative; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex; " + "byte_extract:4,0,three,string,hex; " + "byte_jump: 2,two; " + "byte_jump: 3,three; " + "isdataat: three,relative; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -4253,13 +3962,10 @@ static int DetectByteExtractTest59(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - cd->flags & DETECT_CONTENT_RELATIVE_NEXT || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + cd->flags & DETECT_CONTENT_RELATIVE_NEXT || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -4271,14 +3977,11 @@ static int DetectByteExtractTest59(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != DETECT_BYTE_EXTRACT_FLAG_STRING || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -4298,8 +4001,7 @@ static int DetectByteExtractTest59(void) goto end; } bjd = (DetectBytejumpData *)sm->ctx; - if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || - bjd->offset != 0) { + if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || bjd->offset != 0) { printf("three failed\n"); result = 0; goto end; @@ -4311,8 +4013,7 @@ static int DetectByteExtractTest59(void) goto end; } bjd = (DetectBytejumpData *)sm->ctx; - if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || - bjd->offset != 1) { + if (bjd->flags != DETECT_CONTENT_OFFSET_VAR || bjd->offset != 1) { printf("four failed\n"); result = 0; goto end; @@ -4324,9 +4025,7 @@ static int DetectByteExtractTest59(void) goto end; } isdd = (DetectIsdataatData *)sm->ctx; - if (isdd->flags != (ISDATAAT_OFFSET_VAR | - ISDATAAT_RELATIVE) || - isdd->dataat != 1) { + if (isdd->flags != (ISDATAAT_OFFSET_VAR | ISDATAAT_RELATIVE) || isdd->dataat != 1) { printf("isdataat failed\n"); result = 0; goto end; @@ -4337,7 +4036,7 @@ static int DetectByteExtractTest59(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -4361,13 +4060,13 @@ static int DetectByteExtractTest60(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex,relative; " - "uricontent: \"three\"; " - "byte_extract:4,0,four,string,hex,relative; " - "isdataat: two; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex,relative; " + "uricontent: \"three\"; " + "byte_extract:4,0,four,string,hex,relative; " + "isdataat: two; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -4385,13 +4084,10 @@ static int DetectByteExtractTest60(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -4403,15 +4099,11 @@ static int DetectByteExtractTest60(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -4425,8 +4117,7 @@ static int DetectByteExtractTest60(void) goto end; } isdd = (DetectIsdataatData *)sm->ctx; - if (isdd->flags != (ISDATAAT_OFFSET_VAR) || - isdd->dataat != bed1->local_id) { + if (isdd->flags != (ISDATAAT_OFFSET_VAR) || isdd->dataat != bed1->local_id) { printf("isdataat failed\n"); result = 0; goto end; @@ -4446,7 +4137,7 @@ static int DetectByteExtractTest60(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags != DETECT_CONTENT_RELATIVE_NEXT || - strncmp((char *)cd->content, "three", cd->content_len) != 0) { + strncmp((char *)cd->content, "three", cd->content_len) != 0) { printf("one failed\n"); result = 0; goto end; @@ -4458,15 +4149,11 @@ static int DetectByteExtractTest60(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "four") != 0 || - bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "four") != 0 || + bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -4479,7 +4166,7 @@ static int DetectByteExtractTest60(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -4503,13 +4190,13 @@ static int DetectByteExtractTest61(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "byte_extract:4,0,two,string,hex,relative; " - "uricontent: \"three\"; " - "byte_extract:4,0,four,string,hex,relative; " - "isdataat: four, relative; " - "sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "byte_extract:4,0,two,string,hex,relative; " + "uricontent: \"three\"; " + "byte_extract:4,0,four,string,hex,relative; " + "isdataat: four, relative; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -4527,13 +4214,10 @@ static int DetectByteExtractTest61(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags & DETECT_CONTENT_RAWBYTES || - strncmp((char *)cd->content, "one", cd->content_len) != 0 || - cd->flags & DETECT_CONTENT_NOCASE || - cd->flags & DETECT_CONTENT_WITHIN || - cd->flags & DETECT_CONTENT_DISTANCE || - cd->flags & DETECT_CONTENT_FAST_PATTERN || - !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || - cd->flags & DETECT_CONTENT_NEGATED ) { + strncmp((char *)cd->content, "one", cd->content_len) != 0 || + cd->flags & DETECT_CONTENT_NOCASE || cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_DISTANCE || cd->flags & DETECT_CONTENT_FAST_PATTERN || + !(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) || cd->flags & DETECT_CONTENT_NEGATED) { printf("one failed\n"); result = 0; goto end; @@ -4545,15 +4229,11 @@ static int DetectByteExtractTest61(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "two") != 0 || - bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "two") != 0 || + bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -4575,7 +4255,7 @@ static int DetectByteExtractTest61(void) } cd = (DetectContentData *)sm->ctx; if (cd->flags != DETECT_CONTENT_RELATIVE_NEXT || - strncmp((char *)cd->content, "three", cd->content_len) != 0) { + strncmp((char *)cd->content, "three", cd->content_len) != 0) { printf("one failed\n"); result = 0; goto end; @@ -4587,15 +4267,11 @@ static int DetectByteExtractTest61(void) goto end; } bed1 = (DetectByteExtractData *)sm->ctx; - if (bed1->nbytes != 4 || - bed1->offset != 0 || - strcmp(bed1->name, "four") != 0 || - bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | - DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed1->align_value != 0 || - bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed1->nbytes != 4 || bed1->offset != 0 || strcmp(bed1->name, "four") != 0 || + bed1->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed1->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed1->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed1->align_value != 0 || + bed1->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } if (bed1->local_id != 0) { @@ -4609,9 +4285,8 @@ static int DetectByteExtractTest61(void) goto end; } isdd = (DetectIsdataatData *)sm->ctx; - if (isdd->flags != (ISDATAAT_OFFSET_VAR | - ISDATAAT_RELATIVE) || - isdd->dataat != bed1->local_id) { + if (isdd->flags != (ISDATAAT_OFFSET_VAR | ISDATAAT_RELATIVE) || + isdd->dataat != bed1->local_id) { printf("isdataat failed\n"); result = 0; goto end; @@ -4622,7 +4297,7 @@ static int DetectByteExtractTest61(void) result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -4644,8 +4319,8 @@ static int DetectByteExtractTest62(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(file_data; byte_extract:4,2,two,relative,string,hex; " - "sid:1;)"); + "(file_data; byte_extract:4,2,two,relative,string,hex; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -4658,20 +4333,17 @@ static int DetectByteExtractTest62(void) goto end; } bed = (DetectByteExtractData *)sm->ctx; - if (bed->nbytes != 4 || - bed->offset != 2 || - strncmp(bed->name, "two", 3) != 0 || - bed->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || - bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != 2 || strncmp(bed->name, "two", 3) != 0 || + bed->flags != (DETECT_BYTE_EXTRACT_FLAG_STRING | DETECT_BYTE_EXTRACT_FLAG_RELATIVE) || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE || + bed->base != DETECT_BYTE_EXTRACT_BASE_HEX || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); @@ -4687,19 +4359,15 @@ static int DetectByteExtractTest63(void) if (bed == NULL) goto end; - if (bed->nbytes != 4 || - bed->offset != -2 || - strcmp(bed->name, "one") != 0 || - bed->flags != 0 || - bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || - bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || - bed->align_value != 0 || - bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + if (bed->nbytes != 4 || bed->offset != -2 || strcmp(bed->name, "one") != 0 || bed->flags != 0 || + bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_DEFAULT || + bed->base != DETECT_BYTE_EXTRACT_BASE_NONE || bed->align_value != 0 || + bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { goto end; } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -4739,7 +4407,7 @@ static int DetectByteExtractTestParseNoBase(void) } result = 1; - end: +end: if (bed != NULL) DetectByteExtractFree(NULL, bed); return result; @@ -4822,7 +4490,6 @@ static void DetectByteExtractRegisterTests(void) UtRegisterTest("DetectByteExtractTest62", DetectByteExtractTest62); UtRegisterTest("DetectByteExtractTest63", DetectByteExtractTest63); - UtRegisterTest("DetectByteExtractTestParseNoBase", - DetectByteExtractTestParseNoBase); + UtRegisterTest("DetectByteExtractTestParseNoBase", DetectByteExtractTestParseNoBase); } #endif /* UNITTESTS */ diff --git a/src/detect-byte-extract.h b/src/detect-byte-extract.h index 71b433d3405f..a3036cf6c485 100644 --- a/src/detect-byte-extract.h +++ b/src/detect-byte-extract.h @@ -32,10 +32,10 @@ #define DETECT_BYTE_EXTRACT_FLAG_ENDIAN 0x10 /* endian value to be used. Would be stored in DetectByteParseData->endian */ -#define DETECT_BYTE_EXTRACT_ENDIAN_NONE 0 -#define DETECT_BYTE_EXTRACT_ENDIAN_BIG 1 -#define DETECT_BYTE_EXTRACT_ENDIAN_LITTLE 2 -#define DETECT_BYTE_EXTRACT_ENDIAN_DCE 3 +#define DETECT_BYTE_EXTRACT_ENDIAN_NONE 0 +#define DETECT_BYTE_EXTRACT_ENDIAN_BIG 1 +#define DETECT_BYTE_EXTRACT_ENDIAN_LITTLE 2 +#define DETECT_BYTE_EXTRACT_ENDIAN_DCE 3 /** * \brief Holds data related to byte_extract keyword. diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 3e7ae4f5e000..8b3079f36bce 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -36,47 +36,50 @@ #include "detect-content.h" #include "detect-uricontent.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-validate.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/validate.h" #include "detect-pcre.h" #include "detect-engine-build.h" /** * \brief Regex for parsing our options */ -#define PARSE_REGEX "^\\s*" \ - "([^\\s,]+\\s*,\\s*[^\\s,]+)" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ - "\\s*$" +#define PARSE_REGEX \ + "^\\s*" \ + "([^\\s,]+\\s*,\\s*[^\\s,]+)" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "(?:\\s*,\\s*((?:multiplier|post_offset)\\s+[^\\s,]+|[^\\s,]+))?" \ + "\\s*$" static DetectParseRegex parse_regex; static DetectBytejumpData *DetectBytejumpParse( DetectEngineCtx *de_ctx, const char *optstr, char **nbytes, char **offset); static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr); -static void DetectBytejumpFree(DetectEngineCtx*, void *ptr); +static void DetectBytejumpFree(DetectEngineCtx *, void *ptr); #ifdef UNITTESTS static void DetectBytejumpRegisterTests(void); #endif -void DetectBytejumpRegister (void) +void DetectBytejumpRegister(void) { sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump"; - sigmatch_table[DETECT_BYTEJUMP].desc = "allow the ability to select a from an and move the detection pointer to that position"; + sigmatch_table[DETECT_BYTEJUMP].desc = + "allow the ability to select a from an and move the detection " + "pointer to that position"; sigmatch_table[DETECT_BYTEJUMP].url = "/rules/payload-keywords.html#byte-jump"; sigmatch_table[DETECT_BYTEJUMP].Match = NULL; sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup; - sigmatch_table[DETECT_BYTEJUMP].Free = DetectBytejumpFree; + sigmatch_table[DETECT_BYTEJUMP].Free = DetectBytejumpFree; #ifdef UNITTESTS sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests; #endif @@ -191,12 +194,11 @@ bool DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, /* Extract the byte data */ if (flags & DETECT_BYTEJUMP_STRING) { extbytes = ByteExtractStringUint64(&val, data->base, nbytes, (const char *)ptr); - if(extbytes <= 0) { + if (extbytes <= 0) { SCLogDebug("error extracting %d bytes of string data: %d", nbytes, extbytes); SCReturnBool(false); } - } - else { + } else { int endianness = (flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, (uint16_t)nbytes, ptr); if (extbytes != nbytes) { @@ -300,13 +302,15 @@ static DetectBytejumpData *DetectBytejumpParse( * and *yes* this *is* ugly. */ end_ptr = str; - while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++; + while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) + end_ptr++; *(end_ptr++) = '\0'; strlcpy(args[0], str, sizeof(args[0])); numargs++; str_ptr = end_ptr; - while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++; + while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) + str_ptr++; end_ptr = str_ptr; while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0')) end_ptr++; @@ -491,10 +495,8 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char } } else if (data->flags & DETECT_BYTEJUMP_DCE) { if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, - DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_ISDATAAT, DETECT_BYTEMATH, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, DETECT_BYTEMATH, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -510,10 +512,8 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char goto error; } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, - DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_ISDATAAT, DETECT_BYTEMATH, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, DETECT_BYTEMATH, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -527,14 +527,11 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char } if (data->flags & DETECT_BYTEJUMP_DCE) { - if ((data->flags & DETECT_BYTEJUMP_STRING) || - (data->flags & DETECT_BYTEJUMP_LITTLE) || - (data->flags & DETECT_BYTEJUMP_BIG) || - (data->flags & DETECT_BYTEJUMP_BEGIN) || - (data->flags & DETECT_BYTEJUMP_END) || - (data->base == DETECT_BYTEJUMP_BASE_DEC) || - (data->base == DETECT_BYTEJUMP_BASE_HEX) || - (data->base == DETECT_BYTEJUMP_BASE_OCT) ) { + if ((data->flags & DETECT_BYTEJUMP_STRING) || (data->flags & DETECT_BYTEJUMP_LITTLE) || + (data->flags & DETECT_BYTEJUMP_BIG) || (data->flags & DETECT_BYTEJUMP_BEGIN) || + (data->flags & DETECT_BYTEJUMP_END) || (data->base == DETECT_BYTEJUMP_BASE_DEC) || + (data->base == DETECT_BYTEJUMP_BASE_HEX) || + (data->base == DETECT_BYTEJUMP_BASE_OCT)) { SCLogError("Invalid option. " "A byte_jump keyword with dce holds other invalid modifiers."); goto error; @@ -586,14 +583,14 @@ static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, const char pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } - okay: +okay: ret = 0; return ret; - error: - if (nbytes != NULL) { - SCFree(nbytes); - } +error: + if (nbytes != NULL) { + SCFree(nbytes); + } if (offset != NULL) { SCFree(offset); } @@ -615,10 +612,9 @@ static void DetectBytejumpFree(DetectEngineCtx *de_ctx, void *ptr) SCFree(data); } - /* UNITTESTS */ #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" static int g_file_data_buffer_id = 0; static int g_dce_stub_data_buffer_id = 0; @@ -887,59 +883,59 @@ static int DetectBytejumpTestParse11(void) de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; byte_jump:4,0,align,multiplier 2, " - "post_offset -16,string,dce; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; byte_jump:4,0,align,multiplier 2, " + "post_offset -16,string,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_sub_data; " - "content:\"one\"; byte_jump:4,0,align,multiplier 2, " - "post_offset -16,big,dce; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_sub_data; " + "content:\"one\"; byte_jump:4,0,align,multiplier 2, " + "post_offset -16,big,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; byte_jump:4,0,align,multiplier 2, " - "post_offset -16,little,dce; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; byte_jump:4,0,align,multiplier 2, " + "post_offset -16,little,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; byte_jump:4,0,align,multiplier 2, " - "post_offset -16,string,hex,dce; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; byte_jump:4,0,align,multiplier 2, " + "post_offset -16,string,hex,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; byte_jump:4,0,align,multiplier 2, " - "post_offset -16,string,dec,dce; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; byte_jump:4,0,align,multiplier 2, " + "post_offset -16,string,dec,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; byte_jump:4,0,align,multiplier 2, " - "post_offset -16,string,oct,dce; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; byte_jump:4,0,align,multiplier 2, " + "post_offset -16,string,oct,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; byte_jump:4,0,align,multiplier 2, " - "post_offset -16,from_beginning,dce; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; byte_jump:4,0,align,multiplier 2, " + "post_offset -16,from_beginning,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); SigGroupCleanup(de_ctx); @@ -1007,14 +1003,14 @@ static int DetectBytejumpTestParse14(void) * byte_jump and byte_jump relative works if the previous keyword is pcre * (bug 142) */ -static int DetectByteJumpTestPacket01 (void) +static int DetectByteJumpTestPacket01(void) { uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" - "User-Agent: Wget/1.11.4" - "Accept: */*" - "Host: www.google.com" - "Connection: Keep-Alive" - "Date: Mon, 04 Jan 2010 17:29:39 GMT"; + "User-Agent: Wget/1.11.4" + "Accept: */*" + "Host: www.google.com" + "Connection: Keep-Alive" + "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); @@ -1022,8 +1018,8 @@ static int DetectByteJumpTestPacket01 (void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"pcre + byte_test + " - "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_jump:1,6," - "relative,string,dec; content:\"0\"; sid:134; rev:1;)"; + "relative\"; pcre:\"/AllWorkAndNoPlayMakesWillADullBoy/\"; byte_jump:1,6," + "relative,string,dec; content:\"0\"; sid:134; rev:1;)"; FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); @@ -1036,8 +1032,9 @@ static int DetectByteJumpTestPacket01 (void) * byte_jump and byte_jump relative works if the previous keyword is byte_jump * (bug 165) */ -static int DetectByteJumpTestPacket02 (void) +static int DetectByteJumpTestPacket02(void) { + // clang-format off uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53, 0x4d, 0x42, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1045,6 +1042,7 @@ static int DetectByteJumpTestPacket02 (void) 0x92, 0xa4, 0x01, 0x08, 0x17, 0x5c, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x01, 0x40, 0x48, 0x00, 0x00, 0x00, 0xff }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); @@ -1079,7 +1077,7 @@ static int DetectByteJumpTestPacket03(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"byte_jump\"; " - "byte_jump:1,214748364; sid:1; rev:1;)"; + "byte_jump:1,214748364; sid:1; rev:1;)"; FAIL_IF(UTHPacketMatchSig(p, sig)); @@ -1093,7 +1091,7 @@ static int DetectByteJumpTestPacket03(void) /** * \test check matches of with from_beginning (bug 626/627) */ -static int DetectByteJumpTestPacket04 (void) +static int DetectByteJumpTestPacket04(void) { uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; uint16_t buflen = strlen((char *)buf); @@ -1102,7 +1100,9 @@ static int DetectByteJumpTestPacket04 (void) FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"ABCD\"; distance:0; within:4; sid:1; rev:1;)"; + char sig[] = + "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; " + "content:\"ABCD\"; distance:0; within:4; sid:1; rev:1;)"; FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); @@ -1113,7 +1113,7 @@ static int DetectByteJumpTestPacket04 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -static int DetectByteJumpTestPacket05 (void) +static int DetectByteJumpTestPacket05(void) { uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; uint16_t buflen = strlen((char *)buf); @@ -1122,7 +1122,8 @@ static int DetectByteJumpTestPacket05 (void) FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; byte_jump:2,0,relative,string,dec; content:\"cdABCD\"; within:6; sid:1; rev:1;)"; + char sig[] = "alert tcp any any -> any any (content:\"XYZ\"; " + "byte_jump:2,0,relative,string,dec; content:\"cdABCD\"; within:6; sid:1; rev:1;)"; FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 0 : 1); @@ -1133,7 +1134,7 @@ static int DetectByteJumpTestPacket05 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -static int DetectByteJumpTestPacket06 (void) +static int DetectByteJumpTestPacket06(void) { uint8_t *buf = (uint8_t *)"XX04abcdABCD"; uint16_t buflen = strlen((char *)buf); @@ -1142,7 +1143,9 @@ static int DetectByteJumpTestPacket06 (void) FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"ABCD\"; distance:4; within:4; sid:1; rev:1;)"; + char sig[] = "alert tcp any any -> any any (content:\"XX\"; " + "byte_jump:2,0,relative,string,dec,from_beginning; content:\"ABCD\"; distance:4; " + "within:4; sid:1; rev:1;)"; FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); @@ -1153,7 +1156,7 @@ static int DetectByteJumpTestPacket06 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -static int DetectByteJumpTestPacket07 (void) +static int DetectByteJumpTestPacket07(void) { uint8_t *buf = (uint8_t *)"XX04abcdABCD"; uint16_t buflen = strlen((char *)buf); @@ -1162,7 +1165,9 @@ static int DetectByteJumpTestPacket07 (void) FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0,relative,string,dec,from_beginning; content:\"abcdABCD\"; distance:0; within:8; sid:1; rev:1;)"; + char sig[] = "alert tcp any any -> any any (content:\"XX\"; " + "byte_jump:2,0,relative,string,dec,from_beginning; content:\"abcdABCD\"; " + "distance:0; within:8; sid:1; rev:1;)"; FAIL_IF_NOT(UTHPacketMatchSig(p, sig) ? 1 : 0); @@ -1173,7 +1178,7 @@ static int DetectByteJumpTestPacket07 (void) /** * \test check matches of with from_end */ -static int DetectByteJumpTestPacket08 (void) +static int DetectByteJumpTestPacket08(void) { uint8_t *buf = (uint8_t *)"XX04abcdABCD"; uint16_t buflen = strlen((char *)buf); @@ -1182,7 +1187,7 @@ static int DetectByteJumpTestPacket08 (void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (content:\"XX\"; byte_jump:2,0," - "relative,string,dec,from_end, post_offset -8; content:\"ABCD\"; sid:1; rev:1;)"; + "relative,string,dec,from_end, post_offset -8; content:\"ABCD\"; sid:1; rev:1;)"; FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); diff --git a/src/detect-bytejump.h b/src/detect-bytejump.h index f8ee530b3864..8f912bfb20b4 100644 --- a/src/detect-bytejump.h +++ b/src/detect-bytejump.h @@ -25,30 +25,30 @@ #define __DETECT_BYTEJUMP_H__ /** Bytejump Base */ -#define DETECT_BYTEJUMP_BASE_UNSET 0 /**< Unset type value string (automatic)*/ -#define DETECT_BYTEJUMP_BASE_OCT 8 /**< "oct" type value string */ +#define DETECT_BYTEJUMP_BASE_UNSET 0 /**< Unset type value string (automatic)*/ +#define DETECT_BYTEJUMP_BASE_OCT 8 /**< "oct" type value string */ #define DETECT_BYTEJUMP_BASE_DEC 10 /**< "dec" type value string */ #define DETECT_BYTEJUMP_BASE_HEX 16 /**< "hex" type value string */ /** Bytejump Flags */ -#define DETECT_BYTEJUMP_BEGIN BIT_U16(0) /**< "from_beginning" jump */ -#define DETECT_BYTEJUMP_LITTLE BIT_U16(1) /**< "little" endian value */ -#define DETECT_BYTEJUMP_BIG BIT_U16(2) /**< "big" endian value */ -#define DETECT_BYTEJUMP_STRING BIT_U16(3) /**< "string" value */ -#define DETECT_BYTEJUMP_RELATIVE BIT_U16(4) /**< "relative" offset */ -#define DETECT_BYTEJUMP_ALIGN BIT_U16(5) /**< "align" offset */ -#define DETECT_BYTEJUMP_DCE BIT_U16(6) /**< "dce" enabled */ -#define DETECT_BYTEJUMP_OFFSET_BE BIT_U16(7) /**< "byte extract" enabled */ -#define DETECT_BYTEJUMP_END BIT_U16(8) /**< "from_end" jump */ +#define DETECT_BYTEJUMP_BEGIN BIT_U16(0) /**< "from_beginning" jump */ +#define DETECT_BYTEJUMP_LITTLE BIT_U16(1) /**< "little" endian value */ +#define DETECT_BYTEJUMP_BIG BIT_U16(2) /**< "big" endian value */ +#define DETECT_BYTEJUMP_STRING BIT_U16(3) /**< "string" value */ +#define DETECT_BYTEJUMP_RELATIVE BIT_U16(4) /**< "relative" offset */ +#define DETECT_BYTEJUMP_ALIGN BIT_U16(5) /**< "align" offset */ +#define DETECT_BYTEJUMP_DCE BIT_U16(6) /**< "dce" enabled */ +#define DETECT_BYTEJUMP_OFFSET_BE BIT_U16(7) /**< "byte extract" enabled */ +#define DETECT_BYTEJUMP_END BIT_U16(8) /**< "from_end" jump */ #define DETECT_BYTEJUMP_NBYTES_VAR BIT_U16(9) /**< nbytes string*/ typedef struct DetectBytejumpData_ { - uint8_t nbytes; /**< Number of bytes to compare */ - uint8_t base; /**< String value base (oct|dec|hex) */ - uint16_t flags; /**< Flags (big|little|relative|string) */ - int32_t offset; /**< Offset in payload to extract value */ - int32_t post_offset; /**< Offset to adjust post-jump */ - uint16_t multiplier; /**< Multiplier for nbytes (multiplier n)*/ + uint8_t nbytes; /**< Number of bytes to compare */ + uint8_t base; /**< String value base (oct|dec|hex) */ + uint16_t flags; /**< Flags (big|little|relative|string) */ + int32_t offset; /**< Offset in payload to extract value */ + int32_t post_offset; /**< Offset to adjust post-jump */ + uint16_t multiplier; /**< Multiplier for nbytes (multiplier n)*/ } DetectBytejumpData; /* prototypes */ @@ -58,7 +58,7 @@ typedef struct DetectBytejumpData_ { * * \todo add support for no_stream and stream_only */ -void DetectBytejumpRegister (void); +void DetectBytejumpRegister(void); /** * This function is used to match byte_jump @@ -75,4 +75,3 @@ bool DetectBytejumpDoMatch(DetectEngineThreadCtx *, const Signature *, const Sig const uint8_t *, uint32_t, uint16_t, int32_t, int32_t); #endif /* __DETECT_BYTEJUMP_H__ */ - diff --git a/src/detect-bytemath.c b/src/detect-bytemath.c index a2880216cffa..ecf8e1f97338 100644 --- a/src/detect-bytemath.c +++ b/src/detect-bytemath.c @@ -48,11 +48,11 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" static int DetectByteMathSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS @@ -251,7 +251,7 @@ static DetectByteMathData *DetectByteMathParse( if (bmd->flags & DETECT_BYTEMATH_FLAG_BITMASK) { if (bmd->bitmask_val) { uint32_t bmask = bmd->bitmask_val; - while (!(bmask & 0x1)){ + while (!(bmask & 0x1)) { bmask = bmask >> 1; bmd->bitmask_shift_count++; } @@ -260,7 +260,7 @@ static DetectByteMathData *DetectByteMathParse( return bmd; - error: +error: if (bmd != NULL) DetectByteMathFree(de_ctx, bmd); return NULL; @@ -306,11 +306,8 @@ static int DetectByteMathSetup(DetectEngineCtx *de_ctx, Signature *s, const char } } else if (data->endian == EndianDCE) { if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, - DETECT_BYTE_EXTRACT, - DETECT_BYTEMATH, - DETECT_ISDATAAT, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_BYTEMATH, DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -327,10 +324,8 @@ static int DetectByteMathSetup(DetectEngineCtx *de_ctx, Signature *s, const char s->flags |= SIG_FLAG_APPLAYER; } else if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, - DETECT_BYTE_EXTRACT, DETECT_BYTEMATH, - DETECT_ISDATAAT, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_BYTEMATH, DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -381,8 +376,7 @@ static int DetectByteMathSetup(DetectEngineCtx *de_ctx, Signature *s, const char rvalue = NULL; } - SigMatch *prev_bmd_sm = DetectGetLastSMByListId(s, sm_list, - DETECT_BYTEMATH, -1); + SigMatch *prev_bmd_sm = DetectGetLastSMByListId(s, sm_list, DETECT_BYTEMATH, -1); if (prev_bmd_sm == NULL) { data->local_id = 0; } else { @@ -410,10 +404,10 @@ static int DetectByteMathSetup(DetectEngineCtx *de_ctx, Signature *s, const char pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } - okay: +okay: return 0; - error: +error: if (rvalue) SCFree(rvalue); if (nbytes) @@ -710,8 +704,7 @@ static int DetectByteMathParseTest12(void) static int DetectByteMathParseTest13(void) { - uint8_t flags = DETECT_BYTEMATH_FLAG_STRING | - DETECT_BYTEMATH_FLAG_RELATIVE | + uint8_t flags = DETECT_BYTEMATH_FLAG_STRING | DETECT_BYTEMATH_FLAG_RELATIVE | DETECT_BYTEMATH_FLAG_BITMASK; DetectByteMathData *bmd = DetectByteMathParse(NULL, @@ -738,7 +731,6 @@ static int DetectByteMathParseTest13(void) PASS; } - static int DetectByteMathParseTest14(void) { /* incomplete */ @@ -797,9 +789,11 @@ static int DetectByteMathParseTest16(void) static int DetectByteMathPacket01(void) { + // clang-format off uint8_t buf[] = { 0x38, 0x35, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x01, 0x00 }; + // clang-format on Flow f; void *dns_state = NULL; Packet *p = NULL; @@ -811,9 +805,7 @@ static int DetectByteMathPacket01(void) memset(&tv, 0, sizeof(ThreadVars)); memset(&f, 0, sizeof(Flow)); - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53); FAIL_IF_NULL(p); FLOW_INITIALIZE(&f); @@ -839,41 +831,43 @@ static int DetectByteMathPacket01(void) * byte_test: Compare 2 bytes at offset 13 bytes from last * match and compare with 0x6d */ - s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any " - "(byte_extract: 1, 0, extracted_val, relative;" - "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;" - "byte_test: 2, =, var, 13;" - "msg:\"Byte extract and byte math with byte test verification\";" - "sid:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert udp any any -> any any " + "(byte_extract: 1, 0, extracted_val, relative;" + "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;" + "byte_test: 2, =, var, 13;" + "msg:\"Byte extract and byte math with byte test verification\";" + "sid:1;)"); FAIL_IF_NULL(s); /* this rule should not alert */ - s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any " - "(byte_extract: 1, 0, extracted_val, relative;" - "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;" - "byte_test: 2, !=, var, 13;" - "msg:\"Byte extract and byte math with byte test verification\";" - "sid:2;)"); + s = DetectEngineAppendSig(de_ctx, + "alert udp any any -> any any " + "(byte_extract: 1, 0, extracted_val, relative;" + "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;" + "byte_test: 2, !=, var, 13;" + "msg:\"Byte extract and byte math with byte test verification\";" + "sid:2;)"); FAIL_IF_NULL(s); /* * this rule should alert: * compares offset 15 with var ... 1 (offset 15) < 0x6d (var) */ - s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any " - "(byte_extract: 1, 0, extracted_val, relative;" - "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;" - "byte_test: 2, <, var, 15;" - "msg:\"Byte extract and byte math with byte test verification\";" - "sid:3;)"); + s = DetectEngineAppendSig(de_ctx, + "alert udp any any -> any any " + "(byte_extract: 1, 0, extracted_val, relative;" + "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;" + "byte_test: 2, <, var, 15;" + "msg:\"Byte extract and byte math with byte test verification\";" + "sid:3;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FAIL_IF_NULL(det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf, sizeof(buf)); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); FAIL_IF_NOT(r == 0); dns_state = f.alstate; @@ -899,8 +893,10 @@ static int DetectByteMathPacket01(void) static int DetectByteMathPacket02(void) { + // clang-format off uint8_t buf[] = { 0x38, 0x35, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x00 }; + // clang-format on Flow f; void *dns_state = NULL; Packet *p = NULL; diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 481eb51136db..da5aa0ed68f9 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -39,12 +39,11 @@ #include "detect-byte-extract.h" #include "app-layer.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/debug.h" #include "detect-pcre.h" - /** * \brief Regex for parsing our options */ @@ -54,36 +53,39 @@ * 4th and 5th (test value, offset) are combined */ #define VALID_KW "relative|big|little|string|oct|dec|hex|dce|bitmask" -#define PARSE_REGEX "^\\s*" \ - "([^\\s,]+)\\s*,\\s*" \ - "(\\!?\\s*[^\\s,]*)" \ - "\\s*,\\s*([^\\s,]+\\s*,\\s*[^\\s,]+)" \ - "(?:\\s*,\\s*((?:"VALID_KW")\\s+[^\\s,]+|["VALID_KW"]+))?" \ - "(?:\\s*,\\s*((?:"VALID_KW")\\s+[^\\s,]+|["VALID_KW"]+))?" \ - "(?:\\s*,\\s*((?:"VALID_KW")\\s+[^\\s,]+|["VALID_KW"]+))?" \ - "(?:\\s*,\\s*((?:"VALID_KW")\\s+[^\\s,]+|["VALID_KW"]+))?" \ - "(?:\\s*,\\s*((?:"VALID_KW")\\s+[^\\s,]+|["VALID_KW"]+))?" \ - "(?:\\s*,\\s*((?:"VALID_KW")\\s+[^\\s,]+|["VALID_KW"]+))?" \ - "\\s*$" +#define PARSE_REGEX \ + "^\\s*" \ + "([^\\s,]+)\\s*,\\s*" \ + "(\\!?\\s*[^\\s,]*)" \ + "\\s*,\\s*([^\\s,]+\\s*,\\s*[^\\s,]+)" \ + "(?:\\s*,\\s*((?:" VALID_KW ")\\s+[^\\s,]+|[" VALID_KW "]+))?" \ + "(?:\\s*,\\s*((?:" VALID_KW ")\\s+[^\\s,]+|[" VALID_KW "]+))?" \ + "(?:\\s*,\\s*((?:" VALID_KW ")\\s+[^\\s,]+|[" VALID_KW "]+))?" \ + "(?:\\s*,\\s*((?:" VALID_KW ")\\s+[^\\s,]+|[" VALID_KW "]+))?" \ + "(?:\\s*,\\s*((?:" VALID_KW ")\\s+[^\\s,]+|[" VALID_KW "]+))?" \ + "(?:\\s*,\\s*((?:" VALID_KW ")\\s+[^\\s,]+|[" VALID_KW "]+))?" \ + "\\s*$" static DetectParseRegex parse_regex; -static int DetectBytetestMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx); +static int DetectBytetestMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr); static void DetectBytetestFree(DetectEngineCtx *, void *ptr); #ifdef UNITTESTS static void DetectBytetestRegisterTests(void); #endif -void DetectBytetestRegister (void) +void DetectBytetestRegister(void) { sigmatch_table[DETECT_BYTETEST].name = "byte_test"; - sigmatch_table[DETECT_BYTETEST].desc = "extract and perform an operation selected with against the value in at a particular "; + sigmatch_table[DETECT_BYTETEST].desc = + "extract and perform an operation selected with against the " + "value in at a particular "; sigmatch_table[DETECT_BYTETEST].url = "/rules/payload-keywords.html#byte-test"; sigmatch_table[DETECT_BYTETEST].Match = DetectBytetestMatch; sigmatch_table[DETECT_BYTETEST].Setup = DetectBytetestSetup; - sigmatch_table[DETECT_BYTETEST].Free = DetectBytetestFree; + sigmatch_table[DETECT_BYTETEST].Free = DetectBytetestFree; #ifdef UNITTESTS sigmatch_table[DETECT_BYTETEST].RegisterTests = DetectBytetestRegisterTests; #endif @@ -183,8 +185,9 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, * the packet from that point. */ if (flags & DETECT_BYTETEST_RELATIVE) { - SCLogDebug("relative, working with det_ctx->buffer_offset %"PRIu32", " - "data->offset %"PRIi32"", det_ctx->buffer_offset, data->offset); + SCLogDebug("relative, working with det_ctx->buffer_offset %" PRIu32 ", " + "data->offset %" PRIi32 "", + det_ctx->buffer_offset, data->offset); ptr = payload + det_ctx->buffer_offset; len = payload_len - det_ctx->buffer_offset; @@ -196,9 +199,8 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, if (ptr == NULL || len <= 0) { SCReturnInt(0); } - } - else { - SCLogDebug("absolute, data->offset %"PRIi32"", data->offset); + } else { + SCLogDebug("absolute, data->offset %" PRIi32 "", data->offset); ptr = payload + offset; len = payload_len - offset; @@ -231,12 +233,10 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, } } - SCLogDebug("comparing base %d string 0x%" PRIx64 " %s%u 0x%" PRIx64, - data->base, val, (neg ? "!" : ""), data->op, data->value); - } - else { - int endianness = (flags & DETECT_BYTETEST_LITTLE) ? - BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; + SCLogDebug("comparing base %d string 0x%" PRIx64 " %s%u 0x%" PRIx64, data->base, val, + (neg ? "!" : ""), data->op, data->value); + } else { + int endianness = (flags & DETECT_BYTETEST_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, (uint16_t)nbytes, ptr); if (extbytes != nbytes) { SCLogDebug("error extracting %d bytes " @@ -245,8 +245,8 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, SCReturnInt(-1); } - SCLogDebug("comparing numeric 0x%" PRIx64 " %s%u 0x%" PRIx64, - val, (neg ? "!" : ""), data->op, data->value); + SCLogDebug("comparing numeric 0x%" PRIx64 " %s%u 0x%" PRIx64, val, (neg ? "!" : ""), + data->op, data->value); } /* apply bitmask, if any and then right-shift 1 bit for each trailing 0 in @@ -304,17 +304,16 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, /* A successful match depends on negation */ if ((!neg && match) || (neg && !match)) { - SCLogDebug("MATCH [bt] extracted value is %"PRIu64, val); + SCLogDebug("MATCH [bt] extracted value is %" PRIu64, val); SCReturnInt(1); } SCLogDebug("NO MATCH"); SCReturnInt(0); - } -static int DetectBytetestMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectBytetestMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { return DetectBytetestDoMatch(det_ctx, s, ctx, p->payload, p->payload_len, ((DetectBytetestData *)ctx)->flags, 0, 0, 0); @@ -324,11 +323,8 @@ static DetectBytetestData *DetectBytetestParse( const char *optstr, char **value, char **offset, char **nbytes_str) { DetectBytetestData *data = NULL; - char *args[9] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL - }; - char *test_value = NULL; + char *args[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + char *test_value = NULL; char *data_offset = NULL; int res = 0; size_t pcre2_len; @@ -355,8 +351,8 @@ static DetectBytetestData *DetectBytetestParse( } /* args[2] is comma separated test value, offset */ if (i == 2) { - test_value = (char *) str_ptr; - data_offset = SCStrdup((char *) str_ptr); + test_value = (char *)str_ptr; + data_offset = SCStrdup((char *)str_ptr); if (data_offset == NULL) { goto error; } @@ -410,14 +406,14 @@ static DetectBytetestData *DetectBytetestParse( if (args[1][op_offset] == '!') { data->neg_op = true; op_ptr = &args[1][1]; - while (isspace((char)*op_ptr) || (*op_ptr == ',')) op_ptr++; + while (isspace((char)*op_ptr) || (*op_ptr == ',')) + op_ptr++; op_offset = op_ptr - &args[1][0]; } else { data->neg_op = false; } op_ptr = args[1] + op_offset; - if ((strcmp("=", op_ptr) == 0) || (data->neg_op - && strcmp("", op_ptr) == 0)) { + if ((strcmp("=", op_ptr) == 0) || (data->neg_op && strcmp("", op_ptr) == 0)) { data->op |= DETECT_BYTETEST_OP_EQ; } else if (strcmp("<", op_ptr) == 0) { data->op |= DETECT_BYTETEST_OP_LT; @@ -444,7 +440,8 @@ static DetectBytetestData *DetectBytetestParse( * and data_offset (SCStrdup), respectively; e.g., test_value,offset */ char *end_ptr = test_value; - while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++; + while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) + end_ptr++; *end_ptr = '\0'; if (test_value[0] != '-' && isalpha((unsigned char)test_value[0])) { @@ -468,14 +465,16 @@ static DetectBytetestData *DetectBytetestParse( /* Offset -- note that this *also* contains test_value, offset so parse accordingly */ if (data_offset) { char *end_ptr = data_offset; - while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++; + while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) + end_ptr++; str_ptr = ++end_ptr; - while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++; + while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) + str_ptr++; end_ptr = (char *)str_ptr; while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0')) end_ptr++; memmove(data_offset, str_ptr, end_ptr - str_ptr); - data_offset[end_ptr-str_ptr] = '\0'; + data_offset[end_ptr - str_ptr] = '\0'; if (data_offset[0] != '-' && isalpha((unsigned char)data_offset[0])) { if (data_offset == NULL) { SCLogError("byte_test supplied with " @@ -538,7 +537,8 @@ static DetectBytetestData *DetectBytetestParse( } if (bitmask_index != -1 && data->flags & DETECT_BYTETEST_BITMASK) { - if (ByteExtractStringUint32(&data->bitmask, 0, 0, args[bitmask_index]+strlen("bitmask")) <= 0) { + if (ByteExtractStringUint32( + &data->bitmask, 0, 0, args[bitmask_index] + strlen("bitmask")) <= 0) { SCLogError("Malformed bitmask value: %s", args[bitmask_index] + strlen("bitmask")); goto error; } @@ -548,32 +548,35 @@ static DetectBytetestData *DetectBytetestParse( data->bitmask_shift_count = 0; if (data->bitmask) { uint32_t bmask = data->bitmask; - while (!(bmask & 0x1)){ + while (!(bmask & 0x1)) { bmask = bmask >> 1; data->bitmask_shift_count++; } } } - for (i = 0; i < (ret - 1); i++){ + for (i = 0; i < (ret - 1); i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } - if (data_offset) SCFree(data_offset); + if (data_offset) + SCFree(data_offset); if (test_value) pcre2_substring_free((PCRE2_UCHAR8 *)test_value); pcre2_match_data_free(match); return data; error: - for (i = 0; i < (ret - 1); i++){ + for (i = 0; i < (ret - 1); i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } - if (data_offset) SCFree(data_offset); + if (data_offset) + SCFree(data_offset); if (test_value) pcre2_substring_free((PCRE2_UCHAR8 *)test_value); - if (data) SCFree(data); + if (data) + SCFree(data); if (match) { pcre2_match_data_free(match); } @@ -605,10 +608,8 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, const char } else if (data->flags & DETECT_BYTETEST_DCE) { if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, - DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_ISDATAAT, DETECT_BYTEMATH, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, DETECT_BYTEMATH, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -624,10 +625,8 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, const char goto error; } else if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, - DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_ISDATAAT, DETECT_BYTEMATH, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, DETECT_BYTEMATH, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -641,12 +640,10 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, const char } if (data->flags & DETECT_BYTETEST_DCE) { - if ((data->flags & DETECT_BYTETEST_STRING) || - (data->flags & DETECT_BYTETEST_LITTLE) || - (data->flags & DETECT_BYTETEST_BIG) || - (data->base == DETECT_BYTETEST_BASE_DEC) || - (data->base == DETECT_BYTETEST_BASE_HEX) || - (data->base == DETECT_BYTETEST_BASE_OCT) ) { + if ((data->flags & DETECT_BYTETEST_STRING) || (data->flags & DETECT_BYTETEST_LITTLE) || + (data->flags & DETECT_BYTETEST_BIG) || (data->base == DETECT_BYTETEST_BASE_DEC) || + (data->base == DETECT_BYTETEST_BASE_HEX) || + (data->base == DETECT_BYTETEST_BASE_OCT)) { SCLogError("Invalid option. " "A byte_test keyword with dce holds other invalid modifiers."); goto error; @@ -712,10 +709,10 @@ static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, const char pd->flags |= DETECT_PCRE_RELATIVE_NEXT; } - okay: +okay: ret = 0; return ret; - error: +error: if (offset) SCFree(offset); if (value) @@ -740,10 +737,9 @@ static void DetectBytetestFree(DetectEngineCtx *de_ctx, void *ptr) SCFree(data); } - /* UNITTESTS */ #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "app-layer-parser.h" #include "flow-util.h" static int g_file_data_buffer_id = 0; @@ -1090,11 +1086,11 @@ static int DetectBytetestTestParse20(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; distance:0; " - "byte_test:1,=,1,6,relative,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; distance:0; " + "byte_test:1,=,1,6,relative,dce; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); s = de_ctx->sig_list; @@ -1113,11 +1109,11 @@ static int DetectBytetestTestParse20(void) FAIL_IF(bd->neg_op); s->next = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; distance:0; " - "byte_test:1,=,1,6,relative,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; distance:0; " + "byte_test:1,=,1,6,relative,dce; sid:1;)"); FAIL_IF_NULL(s->next); s = s->next; @@ -1135,11 +1131,11 @@ static int DetectBytetestTestParse20(void) FAIL_IF(bd->neg_op); s->next = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; " - "content:\"one\"; distance:0; " - "byte_test:1,=,1,6,relative; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "dce_stub_data; " + "content:\"one\"; distance:0; " + "byte_test:1,=,1,6,relative; sid:1;)"); FAIL_IF_NULL(s->next); s = s->next; @@ -1175,69 +1171,69 @@ static int DetectBytetestTestParse21(void) de_ctx->flags |= DE_QUIET; s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,string,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,string,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,big,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,big,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,little,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,little,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,hex,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,hex,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,dec,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,dec,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,oct,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,oct,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,string,hex,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,string,hex,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,big,string,hex,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,big,string,hex,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,big,string,oct,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,big,string,oct,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,little,string,hex,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,little,string,hex,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); s = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytetest_body\"; " - "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "content:\"one\"; byte_test:1,=,1,6,big,string,dec,dce; sid:1;)"); + "(msg:\"Testing bytetest_body\"; " + "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " + "content:\"one\"; byte_test:1,=,1,6,big,string,dec,dce; sid:1;)"); FAIL_IF_NOT_NULL(s); SigGroupCleanup(de_ctx); @@ -1261,7 +1257,7 @@ static int DetectBytetestTestParse22(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(file_data; byte_test:1,=,1,6,relative; sid:1;)"); + "(file_data; byte_test:1,=,1,6,relative; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); s = de_ctx->sig_list; diff --git a/src/detect-bytetest.h b/src/detect-bytetest.h index 4b4684972b91..1ee0999ecf8c 100644 --- a/src/detect-bytetest.h +++ b/src/detect-bytetest.h @@ -25,17 +25,17 @@ #define __DETECT_BYTETEST_H__ /** Bytetest Operators */ -#define DETECT_BYTETEST_OP_LT 1 /**< "less than" operator */ -#define DETECT_BYTETEST_OP_GT 2 /**< "greater than" operator */ -#define DETECT_BYTETEST_OP_EQ 3 /**< "equals" operator */ -#define DETECT_BYTETEST_OP_AND 4 /**< "bitwise and" operator */ -#define DETECT_BYTETEST_OP_OR 5 /**< "bitwise or" operator */ -#define DETECT_BYTETEST_OP_GE 6 /**< greater than equal operator */ -#define DETECT_BYTETEST_OP_LE 7 /**< less than equal operator */ +#define DETECT_BYTETEST_OP_LT 1 /**< "less than" operator */ +#define DETECT_BYTETEST_OP_GT 2 /**< "greater than" operator */ +#define DETECT_BYTETEST_OP_EQ 3 /**< "equals" operator */ +#define DETECT_BYTETEST_OP_AND 4 /**< "bitwise and" operator */ +#define DETECT_BYTETEST_OP_OR 5 /**< "bitwise or" operator */ +#define DETECT_BYTETEST_OP_GE 6 /**< greater than equal operator */ +#define DETECT_BYTETEST_OP_LE 7 /**< less than equal operator */ /** Bytetest Base */ -#define DETECT_BYTETEST_BASE_UNSET 0 /**< Unset type value string (automatic)*/ -#define DETECT_BYTETEST_BASE_OCT 8 /**< "oct" type value string */ +#define DETECT_BYTETEST_BASE_UNSET 0 /**< Unset type value string (automatic)*/ +#define DETECT_BYTETEST_BASE_OCT 8 /**< "oct" type value string */ #define DETECT_BYTETEST_BASE_DEC 10 /**< "dec" type value string */ #define DETECT_BYTETEST_BASE_HEX 16 /**< "hex" type value string */ @@ -51,15 +51,15 @@ #define DETECT_BYTETEST_NBYTES_VAR BIT_U16(8) /**< byte extract value enabled */ typedef struct DetectBytetestData_ { - uint8_t nbytes; /**< Number of bytes to compare */ - uint8_t op; /**< Operator used to compare */ - uint8_t base; /**< String value base (oct|dec|hex) */ - uint8_t bitmask_shift_count; /**< bitmask trailing 0 count */ - uint16_t flags; /**< Flags (big|little|relative|string|bitmask) */ + uint8_t nbytes; /**< Number of bytes to compare */ + uint8_t op; /**< Operator used to compare */ + uint8_t base; /**< String value base (oct|dec|hex) */ + uint8_t bitmask_shift_count; /**< bitmask trailing 0 count */ + uint16_t flags; /**< Flags (big|little|relative|string|bitmask) */ bool neg_op; - int32_t offset; /**< Offset in payload */ - uint32_t bitmask; /**< bitmask value */ - uint64_t value; /**< Value to compare against */ + int32_t offset; /**< Offset in payload */ + uint32_t bitmask; /**< bitmask value */ + uint64_t value; /**< Value to compare against */ } DetectBytetestData; /* prototypes */ @@ -69,7 +69,7 @@ typedef struct DetectBytetestData_ { * * \todo add support for no_stream and stream_only */ -void DetectBytetestRegister (void); +void DetectBytetestRegister(void); int DetectBytetestDoMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchCtx *ctx, const uint8_t *, uint32_t, uint16_t, int32_t, int32_t, uint64_t); diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c index 494e1e17520f..72514ac40664 100644 --- a/src/detect-cipservice.c +++ b/src/detect-cipservice.c @@ -24,12 +24,12 @@ */ #include "suricata-common.h" -#include "util-unittest.h" +#include "util/unittest.h" #include "detect-parse.h" #include "detect-engine.h" -#include "util-byte.h" +#include "util/byte.h" -#include "app-layer-enip-common.h" +#include "app-layer/enip/parser-common.h" #include "detect-cipservice.h" #include "detect-engine-enip.h" @@ -53,15 +53,14 @@ static int g_cip_buffer_id = 0; void DetectCipServiceRegister(void) { SCEnter(); - sigmatch_table[DETECT_CIPSERVICE].name = "cip_service"; //rule keyword + sigmatch_table[DETECT_CIPSERVICE].name = "cip_service"; // rule keyword sigmatch_table[DETECT_CIPSERVICE].desc = "match on CIP Service"; sigmatch_table[DETECT_CIPSERVICE].url = "/rules/enip-keyword.html#enip-cip-keywords"; sigmatch_table[DETECT_CIPSERVICE].Match = NULL; sigmatch_table[DETECT_CIPSERVICE].Setup = DetectCipServiceSetup; sigmatch_table[DETECT_CIPSERVICE].Free = DetectCipServiceFree; #ifdef UNITTESTS - sigmatch_table[DETECT_CIPSERVICE].RegisterTests - = DetectCipServiceRegisterTests; + sigmatch_table[DETECT_CIPSERVICE].RegisterTests = DetectCipServiceRegisterTests; #endif DetectAppLayerInspectEngineRegister2( "cip", ALPROTO_ENIP, SIG_FLAG_TOSERVER, 0, DetectEngineInspectCIP, NULL); @@ -87,7 +86,7 @@ static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) const char delims[] = ","; DetectCipServiceData *cipserviced = NULL; - //SCLogDebug("DetectCipServiceParse - rule string %s", rulestr); + // SCLogDebug("DetectCipServiceParse - rule string %s", rulestr); /* strtok_r modifies the string so work with a copy */ char *rulestr = SCStrdup(rulestrc); @@ -103,55 +102,50 @@ static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) cipserviced->matchattribute = 1; cipserviced->cipattribute = 0; - char* token; + char *token; char *save; uint8_t var; uint8_t input[3] = { 0, 0, 0 }; uint8_t i = 0; token = strtok_r(rulestr, delims, &save); - while (token != NULL) - { - if (i > 2) //for now only need 3 parameters + while (token != NULL) { + if (i > 2) // for now only need 3 parameters { SCLogError("too many parameters"); goto error; } - if (i < 2) //if on service or class + if (i < 2) // if on service or class { - if (!isdigit((int) *token)) - { + if (!isdigit((int)*token)) { SCLogError("parameter error %s", token); goto error; } - } else //if on attribute + } else // if on attribute { - if (token[0] == '!') - { + if (token[0] == '!') { cipserviced->matchattribute = 0; token++; } - if (!isdigit((int) *token)) - { + if (!isdigit((int)*token)) { SCLogError("attribute error %s", token); goto error; } - } unsigned long num = atol(token); - if ((num > MAX_CIP_SERVICE) && (i == 0))//if service greater than 7 bit + if ((num > MAX_CIP_SERVICE) && (i == 0)) // if service greater than 7 bit { SCLogError("invalid CIP service %lu", num); goto error; - } else if ((num > MAX_CIP_CLASS) && (i == 1))//if service greater than 16 bit + } else if ((num > MAX_CIP_CLASS) && (i == 1)) // if service greater than 16 bit { SCLogError("invalid CIP class %lu", num); goto error; - } else if ((num > MAX_CIP_ATTRIBUTE) && (i == 2))//if service greater than 16 bit + } else if ((num > MAX_CIP_ATTRIBUTE) && (i == 2)) // if service greater than 16 bit { SCLogError("invalid CIP attribute %lu", num); goto error; @@ -176,10 +170,8 @@ static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) SCLogDebug("DetectCipServiceParse - tokens %d", cipserviced->tokens); SCLogDebug("DetectCipServiceParse - service %d", cipserviced->cipservice); SCLogDebug("DetectCipServiceParse - class %d", cipserviced->cipclass); - SCLogDebug("DetectCipServiceParse - match attribute %d", - cipserviced->matchattribute); - SCLogDebug("DetectCipServiceParse - attribute %d", - cipserviced->cipattribute); + SCLogDebug("DetectCipServiceParse - match attribute %d", cipserviced->matchattribute); + SCLogDebug("DetectCipServiceParse - attribute %d", cipserviced->cipattribute); SCFree(rulestr); SCReturnPtr(cipserviced, "DetectENIPFunction"); @@ -193,7 +185,8 @@ static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) } /** - * \brief this function is used to a cipserviced the parsed cip_service data into the current signature + * \brief this function is used to a cipserviced the parsed cip_service data into the current + * signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature @@ -202,8 +195,7 @@ static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *rulestr) +static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rulestr) { SCEnter(); @@ -235,7 +227,7 @@ static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, */ static void DetectCipServiceFree(DetectEngineCtx *de_ctx, void *ptr) { - DetectCipServiceData *cipserviced = (DetectCipServiceData *) ptr; + DetectCipServiceData *cipserviced = (DetectCipServiceData *)ptr; SCFree(cipserviced); } @@ -244,7 +236,7 @@ static void DetectCipServiceFree(DetectEngineCtx *de_ctx, void *ptr) /** * \test Test CIP Command parameter parsing */ -static int DetectCipServiceParseTest01 (void) +static int DetectCipServiceParseTest01(void) { DetectCipServiceData *cipserviced = NULL; cipserviced = DetectCipServiceParse("7"); @@ -257,11 +249,12 @@ static int DetectCipServiceParseTest01 (void) /** * \test Test CIP Service signature */ -static int DetectCipServiceSignatureTest01 (void) +static int DetectCipServiceSignatureTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (cip_service:1; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (cip_service:1; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); PASS; @@ -272,10 +265,8 @@ static int DetectCipServiceSignatureTest01 (void) */ static void DetectCipServiceRegisterTests(void) { - UtRegisterTest("DetectCipServiceParseTest01", - DetectCipServiceParseTest01); - UtRegisterTest("DetectCipServiceSignatureTest01", - DetectCipServiceSignatureTest01); + UtRegisterTest("DetectCipServiceParseTest01", DetectCipServiceParseTest01); + UtRegisterTest("DetectCipServiceSignatureTest01", DetectCipServiceSignatureTest01); } #endif /* UNITTESTS */ @@ -298,16 +289,14 @@ static int g_enip_buffer_id = 0; */ void DetectEnipCommandRegister(void) { - sigmatch_table[DETECT_ENIPCOMMAND].name = "enip_command"; //rule keyword - sigmatch_table[DETECT_ENIPCOMMAND].desc - = "rules for detecting EtherNet/IP command"; + sigmatch_table[DETECT_ENIPCOMMAND].name = "enip_command"; // rule keyword + sigmatch_table[DETECT_ENIPCOMMAND].desc = "rules for detecting EtherNet/IP command"; sigmatch_table[DETECT_ENIPCOMMAND].url = "/rules/enip-keyword.html#enip-cip-keywords"; sigmatch_table[DETECT_ENIPCOMMAND].Match = NULL; sigmatch_table[DETECT_ENIPCOMMAND].Setup = DetectEnipCommandSetup; sigmatch_table[DETECT_ENIPCOMMAND].Free = DetectEnipCommandFree; #ifdef UNITTESTS - sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests - = DetectEnipCommandRegisterTests; + sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests = DetectEnipCommandRegisterTests; #endif DetectAppLayerInspectEngineRegister2( "enip", ALPROTO_ENIP, SIG_FLAG_TOSERVER, 0, DetectEngineInspectENIP, NULL); @@ -334,7 +323,7 @@ static DetectEnipCommandData *DetectEnipCommandParse(const char *rulestr) if (unlikely(enipcmdd == NULL)) goto error; - if (!(isdigit((int) *rulestr))) { + if (!(isdigit((int)*rulestr))) { SCLogError("invalid ENIP command %s", rulestr); goto error; } @@ -367,8 +356,7 @@ static DetectEnipCommandData *DetectEnipCommandParse(const char *rulestr) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *rulestr) +static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rulestr) { DetectEnipCommandData *enipcmdd = NULL; @@ -398,7 +386,7 @@ static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, */ static void DetectEnipCommandFree(DetectEngineCtx *de_ctx, void *ptr) { - DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) ptr; + DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *)ptr; SCFree(enipcmdd); } @@ -408,7 +396,7 @@ static void DetectEnipCommandFree(DetectEngineCtx *de_ctx, void *ptr) * \test ENIP parameter test */ -static int DetectEnipCommandParseTest01 (void) +static int DetectEnipCommandParseTest01(void) { DetectEnipCommandData *enipcmdd = NULL; @@ -423,12 +411,13 @@ static int DetectEnipCommandParseTest01 (void) /** * \test ENIP Command signature test */ -static int DetectEnipCommandSignatureTest01 (void) +static int DetectEnipCommandSignatureTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (enip_command:1; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (enip_command:1; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -440,9 +429,7 @@ static int DetectEnipCommandSignatureTest01 (void) */ static void DetectEnipCommandRegisterTests(void) { - UtRegisterTest("DetectEnipCommandParseTest01", - DetectEnipCommandParseTest01); - UtRegisterTest("DetectEnipCommandSignatureTest01", - DetectEnipCommandSignatureTest01); + UtRegisterTest("DetectEnipCommandParseTest01", DetectEnipCommandParseTest01); + UtRegisterTest("DetectEnipCommandSignatureTest01", DetectEnipCommandSignatureTest01); } #endif /* UNITTESTS */ diff --git a/src/detect-cipservice.h b/src/detect-cipservice.h index 6a9c500cc9fa..964a203ef8ce 100644 --- a/src/detect-cipservice.h +++ b/src/detect-cipservice.h @@ -22,14 +22,13 @@ */ #ifndef _DETECT_CIPSERVICE_H -#define _DETECT_CIPSERVICE_H +#define _DETECT_CIPSERVICE_H /** * CIP Service rule data structure */ -typedef struct DetectCipServiceData_ -{ - uint8_t cipservice; /* cip service type */ +typedef struct DetectCipServiceData_ { + uint8_t cipservice; /* cip service type */ uint16_t cipclass; uint16_t cipattribute; uint8_t matchattribute; /* whether to match on attribute*/ @@ -39,8 +38,7 @@ typedef struct DetectCipServiceData_ /** * ENIP Command rule data structure */ -typedef struct DetectEnipCommandData_ -{ +typedef struct DetectEnipCommandData_ { uint16_t enipcommand; /* enip command */ } DetectEnipCommandData; @@ -50,22 +48,18 @@ void DetectEnipCommandRegister(void); /** * link list node for storing CIP service data */ -typedef struct CIPServiceData_ -{ - uint8_t service; //cip service - union - { - struct - { - uint8_t path_size; //cip path size - uint16_t path_offset; //offset to cip path +typedef struct CIPServiceData_ { + uint8_t service; // cip service + union { + struct { + uint8_t path_size; // cip path size + uint16_t path_offset; // offset to cip path } request; - struct - { + struct { uint8_t status; } response; }; - struct CIPServiceData* next; + struct CIPServiceData *next; } CIPServiceData; -#endif /* _DETECT_CIPSERVICE_H */ +#endif /* _DETECT_CIPSERVICE_H */ diff --git a/src/detect-classtype.c b/src/detect-classtype.c index bec179e72bc8..aa88b85c6615 100644 --- a/src/detect-classtype.c +++ b/src/detect-classtype.c @@ -31,10 +31,10 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-classtype.h" -#include "util-classification-config.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/classification-config.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/unittest.h" #define PARSE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$" @@ -51,7 +51,8 @@ static void DetectClasstypeRegisterTests(void); void DetectClasstypeRegister(void) { sigmatch_table[DETECT_CLASSTYPE].name = "classtype"; - sigmatch_table[DETECT_CLASSTYPE].desc = "information about the classification of rules and alerts"; + sigmatch_table[DETECT_CLASSTYPE].desc = + "information about the classification of rules and alerts"; sigmatch_table[DETECT_CLASSTYPE].url = "/rules/meta.html#classtype"; sigmatch_table[DETECT_CLASSTYPE].Setup = DetectClasstypeSetup; #ifdef UNITTESTS @@ -163,8 +164,7 @@ static int DetectClasstypeSetup(DetectEngineCtx *de_ctx, Signature *s, const cha } char str[256]; - snprintf(str, sizeof(str), - "config classification: %s,Unknown Classtype,%d\n", + snprintf(str, sizeof(str), "config classification: %s,Unknown Classtype,%d\n", parsed_ct_name, DETECT_DEFAULT_PRIO); if (SCClassConfAddClasstype(de_ctx, str, 0) < 0) @@ -215,8 +215,8 @@ static int DetectClasstypeTest01(void) FAIL_IF_NULL(fd); SCClassConfLoadClassificationConfigFile(de_ctx, fd); Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Classtype test\"; " - "Classtype:not_available; sid:1;)"); + "(msg:\"Classtype test\"; " + "Classtype:not_available; sid:1;)"); FAIL_IF_NULL(s); FAIL_IF_NOT(s->prio == 3); @@ -239,29 +239,29 @@ static int DetectClasstypeTest02(void) SCClassConfLoadClassificationConfigFile(de_ctx, fd); Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(Classtype:bad-unknown; sid:1;)"); + "(Classtype:bad-unknown; sid:1;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(Classtype:not-there; sid:2;)"); + "(Classtype:not-there; sid:2;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(Classtype:Bad-UnkNown; sid:3;)"); + "(Classtype:Bad-UnkNown; sid:3;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(Classtype:nothing-wrong; sid:4;)"); + "(Classtype:nothing-wrong; sid:4;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(Classtype:attempted_dos; Classtype:bad-unknown; sid:5;)"); + "(Classtype:attempted_dos; Classtype:bad-unknown; sid:5;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 2); /* duplicate test */ sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(Classtype:nothing-wrong; Classtype:Bad-UnkNown; sid:6;)"); + "(Classtype:nothing-wrong; Classtype:Bad-UnkNown; sid:6;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 2); @@ -282,24 +282,26 @@ static int DetectClasstypeTest03(void) FAIL_IF_NULL(fd); SCClassConfLoadClassificationConfigFile(de_ctx, fd); - Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Classtype test\"; Classtype:bad-unknown; priority:1; sid:1;)"); + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Classtype test\"; Classtype:bad-unknown; priority:1; sid:1;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 1); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Classtype test\"; Classtype:unKnoWn; " - "priority:3; sid:2;)"); + "(msg:\"Classtype test\"; Classtype:unKnoWn; " + "priority:3; sid:2;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 3); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; " - "Classtype:nothing-wrong; priority:1; sid:3;)"); + "Classtype:nothing-wrong; priority:1; sid:3;)"); FAIL_IF_NOT(sig->prio == 1); - sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Classtype test\"; Classtype:bad-unknown; Classtype:undefined; " - "priority:5; sid:4;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " + "(msg:\"Classtype test\"; Classtype:bad-unknown; Classtype:undefined; " + "priority:5; sid:4;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 5); diff --git a/src/detect-classtype.h b/src/detect-classtype.h index 6e0dd509cf48..5a45e2296418 100644 --- a/src/detect-classtype.h +++ b/src/detect-classtype.h @@ -28,4 +28,3 @@ void DetectClasstypeRegister(void); #endif /* __DETECT_CLASSTYPE_H__ */ - diff --git a/src/detect-config.c b/src/detect-config.c index 7ad8c88dca68..6c2c632c3702 100644 --- a/src/detect-config.c +++ b/src/detect-config.c @@ -40,31 +40,33 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "stream-tcp.h" #include "detect-config.h" -#include "output.h" +#include "output/output.h" /** * \brief Regex for parsing our flow options */ -#define PARSE_REGEX "^\\s*([A-z_]+)\\s*\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+)\\s+([A-z_]+))?\\s*(?:,\\s*([A-z_]+)\\s+([A-z_]+))?$" +#define PARSE_REGEX \ + "^\\s*([A-z_]+)\\s*\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+)\\s+([A-z_]+))?\\s*(?:,\\s*([A-z_]+)\\s+" \ + "([A-z_]+))?$" static DetectParseRegex parse_regex; -static int DetectConfigPostMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx); -static int DetectConfigSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectConfigPostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); +static int DetectConfigSetup(DetectEngineCtx *, Signature *, const char *); static void DetectConfigFree(DetectEngineCtx *, void *); #ifdef UNITTESTS static void DetectConfigRegisterTests(void); @@ -78,15 +80,14 @@ void DetectConfigRegister(void) sigmatch_table[DETECT_CONFIG].name = "config"; sigmatch_table[DETECT_CONFIG].Match = DetectConfigPostMatch; sigmatch_table[DETECT_CONFIG].Setup = DetectConfigSetup; - sigmatch_table[DETECT_CONFIG].Free = DetectConfigFree; + sigmatch_table[DETECT_CONFIG].Free = DetectConfigFree; #ifdef UNITTESTS sigmatch_table[DETECT_CONFIG].RegisterTests = DetectConfigRegisterTests; #endif DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static void ConfigApplyTx(Flow *f, - const uint64_t tx_id, const DetectConfigData *config) +static void ConfigApplyTx(Flow *f, const uint64_t tx_id, const DetectConfigData *config) { if (f->alstate == NULL) { return; @@ -120,8 +121,7 @@ static void ConfigApplyTx(Flow *f, /** * \brief apply the post match filestore with options */ -static int ConfigApply(DetectEngineThreadCtx *det_ctx, - Packet *p, const DetectConfigData *config) +static int ConfigApply(DetectEngineThreadCtx *det_ctx, Packet *p, const DetectConfigData *config) { bool this_tx = false; bool this_flow = false; @@ -136,7 +136,7 @@ static int ConfigApply(DetectEngineThreadCtx *det_ctx, } if (this_tx) { - SCLogDebug("tx logic here: tx_id %"PRIu64, det_ctx->tx_id); + SCLogDebug("tx logic here: tx_id %" PRIu64, det_ctx->tx_id); ConfigApplyTx(p->flow, det_ctx->tx_id, config); } else if (this_flow) { SCLogDebug("flow logic here"); @@ -145,8 +145,8 @@ static int ConfigApply(DetectEngineThreadCtx *det_ctx, SCReturnInt(0); } -static int DetectConfigPostMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectConfigPostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); const DetectConfigData *config = (const DetectConfigData *)ctx; @@ -165,7 +165,7 @@ static int DetectConfigPostMatch(DetectEngineThreadCtx *det_ctx, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectConfigSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectConfigSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { SCEnter(); @@ -245,7 +245,7 @@ static int DetectConfigSetup (DetectEngineCtx *de_ctx, Signature *s, const char goto error; } - if (!(strcmp(typeval, "tx") == 0 ||strcmp(typeval, "flow") == 0)) { + if (!(strcmp(typeval, "tx") == 0 || strcmp(typeval, "flow") == 0)) { SCLogError("only 'tx' and 'flow' supported at this time"); goto error; } @@ -271,7 +271,7 @@ static int DetectConfigSetup (DetectEngineCtx *de_ctx, Signature *s, const char goto error; } - if (!(strcmp(scopeval, "tx") == 0 ||strcmp(scopeval, "flow") == 0)) { + if (!(strcmp(scopeval, "tx") == 0 || strcmp(scopeval, "flow") == 0)) { SCLogError("only 'tx' and 'flow' supported at this time"); goto error; } @@ -325,11 +325,10 @@ static int DetectConfigTest01(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "config dns any any -> any any (" - "dns.query; content:\"common.domain.com\"; " - "config:logging disable, type tx, scope tx; " - "sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, "config dns any any -> any any (" + "dns.query; content:\"common.domain.com\"; " + "config:logging disable, type tx, scope tx; " + "sid:1;)"); FAIL_IF_NULL(s); DetectEngineCtxFree(de_ctx); PASS; diff --git a/src/detect-config.h b/src/detect-config.h index d6948a3f4e29..295e9b08daee 100644 --- a/src/detect-config.h +++ b/src/detect-config.h @@ -24,7 +24,7 @@ #ifndef __DETECT_CONFIG_H__ #define __DETECT_CONFIG_H__ -#include "util-config.h" +#include "util/config.h" typedef struct DetectConfigData_ { enum ConfigSubsys subsys; @@ -33,6 +33,6 @@ typedef struct DetectConfigData_ { } DetectConfigData; /* prototypes */ -void DetectConfigRegister (void); +void DetectConfigRegister(void); #endif /* __DETECT_CONFIG_H__ */ diff --git a/src/detect-content.c b/src/detect-content.c index c7a240d7e01d..af6e947fc47d 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -34,39 +34,39 @@ #include "detect-engine-state.h" #include "detect-parse.h" #include "detect-pcre.h" -#include "util-mpm.h" +#include "util/mpm/mpm.h" #include "flow.h" #include "flow-util.h" #include "flow-var.h" #include "detect-flow.h" #include "app-layer.h" -#include "util-unittest.h" -#include "util-print.h" -#include "util-debug.h" -#include "util-spm.h" +#include "util/unittest.h" +#include "util/print.h" +#include "util/debug.h" +#include "util/spm.h" #include "threads.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" +#include "util/profiling.h" #include "detect-dsize.h" #ifdef UNITTESTS static void DetectContentRegisterTests(void); #endif -void DetectContentRegister (void) +void DetectContentRegister(void) { sigmatch_table[DETECT_CONTENT].name = "content"; sigmatch_table[DETECT_CONTENT].desc = "match on payload content"; sigmatch_table[DETECT_CONTENT].url = "/rules/payload-keywords.html#content"; sigmatch_table[DETECT_CONTENT].Match = NULL; sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup; - sigmatch_table[DETECT_CONTENT].Free = DetectContentFree; + sigmatch_table[DETECT_CONTENT].Free = DetectContentFree; #ifdef UNITTESTS sigmatch_table[DETECT_CONTENT].RegisterTests = DetectContentRegisterTests; #endif - sigmatch_table[DETECT_CONTENT].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION); + sigmatch_table[DETECT_CONTENT].flags = (SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION); } /** @@ -80,8 +80,8 @@ void DetectContentRegister (void) * \retval -1 error * \retval 0 ok */ -int DetectContentDataParse(const char *keyword, const char *contentstr, - uint8_t **pstr, uint16_t *plen) +int DetectContentDataParse( + const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen) { char *str = NULL; size_t slen = 0; @@ -96,7 +96,7 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, SCLogDebug("\"%s\", len %" PRIuMAX, str, (uintmax_t)slen); - //SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len); + // SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len); char converted = 0; { @@ -121,25 +121,21 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, } else { bin = 1; } - } else if(!escape && str[i] == '\\') { + } else if (!escape && str[i] == '\\') { escape = 1; } else { if (bin) { - if (isdigit((unsigned char)str[i]) || - str[i] == 'A' || str[i] == 'a' || - str[i] == 'B' || str[i] == 'b' || - str[i] == 'C' || str[i] == 'c' || - str[i] == 'D' || str[i] == 'd' || - str[i] == 'E' || str[i] == 'e' || - str[i] == 'F' || str[i] == 'f') - { + if (isdigit((unsigned char)str[i]) || str[i] == 'A' || str[i] == 'a' || + str[i] == 'B' || str[i] == 'b' || str[i] == 'C' || str[i] == 'c' || + str[i] == 'D' || str[i] == 'd' || str[i] == 'E' || str[i] == 'e' || + str[i] == 'F' || str[i] == 'f') { // SCLogDebug("part of binary: %c", str[i]); binstr[binpos] = (char)str[i]; binpos++; if (binpos == 2) { - uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF; + uint8_t c = strtol((char *)binstr, (char **)NULL, 16) & 0xFF; binpos = 0; str[x] = c; x++; @@ -147,19 +143,14 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, } } else if (str[i] == ' ') { // SCLogDebug("space as part of binary string"); - } - else if (str[i] != ',') { + } else if (str[i] != ',') { SCLogError("Invalid hex code in " "content - %s, hex %c. Invalidating signature.", contentstr, str[i]); goto error; } } else if (escape) { - if (str[i] == ':' || - str[i] == ';' || - str[i] == '\\' || - str[i] == '\"') - { + if (str[i] == ':' || str[i] == ';' || str[i] == '\\' || str[i] == '\"') { str[x] = str[i]; x++; } else { @@ -208,8 +199,8 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, * \brief DetectContentParse * \initonly */ -DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, - const char *contentstr) +DetectContentData *DetectContentParse( + SpmGlobalThreadCtx *spm_global_thread_ctx, const char *contentstr) { DetectContentData *cd = NULL; uint8_t *content = NULL; @@ -232,8 +223,7 @@ DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, cd->content_len = len; /* Prepare SPM search context. */ - cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 0, - spm_global_thread_ctx); + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 0, spm_global_thread_ctx); if (cd->spm_ctx == NULL) { SCFree(content); SCFree(cd); @@ -247,11 +237,10 @@ DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, SCFree(content); return cd; - } -DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, - const char *contentstr) +DetectContentData *DetectContentParseEncloseQuotes( + SpmGlobalThreadCtx *spm_global_thread_ctx, const char *contentstr) { return DetectContentParse(spm_global_thread_ctx, contentstr); } @@ -283,15 +272,16 @@ void DetectContentPrint(DetectContentData *cd) SCLogDebug("%c", cd->content[i]); } - SCLogDebug("Content_id: %"PRIu32, cd->id); - SCLogDebug("Content_len: %"PRIu16, cd->content_len); - SCLogDebug("Depth: %"PRIu16, cd->depth); - SCLogDebug("Offset: %"PRIu16, cd->offset); - SCLogDebug("Within: %"PRIi32, cd->within); - SCLogDebug("Distance: %"PRIi32, cd->distance); + SCLogDebug("Content_id: %" PRIu32, cd->id); + SCLogDebug("Content_len: %" PRIu16, cd->content_len); + SCLogDebug("Depth: %" PRIu16, cd->depth); + SCLogDebug("Offset: %" PRIu16, cd->offset); + SCLogDebug("Within: %" PRIi32, cd->within); + SCLogDebug("Distance: %" PRIi32, cd->distance); SCLogDebug("flags: %u ", cd->flags); SCLogDebug("negated: %s ", cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); - SCLogDebug("relative match next: %s ", cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false"); + SCLogDebug("relative match next: %s ", + cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false"); if (cd->replace && cd->replace_len) { char *tmprstr = SCMalloc(sizeof(char) * cd->replace_len + 1); @@ -342,8 +332,7 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *conten int sm_list = s->init_data->list; if (sm_list == DETECT_SM_LIST_NOTSET) { sm_list = DETECT_SM_LIST_PMATCH; - } else if (sm_list > DETECT_SM_LIST_MAX && - 0 == (cd->flags & DETECT_CONTENT_NEGATED)) { + } else if (sm_list > DETECT_SM_LIST_MAX && 0 == (cd->flags & DETECT_CONTENT_NEGATED)) { /* Check transform compatibility */ const char *tstr; if (!DetectEngineBufferTypeValidateTransform( @@ -817,8 +806,7 @@ static bool TestLastContent(const Signature *s, uint16_t o, uint16_t d) DetectEngineCtxFree(de_ctx); \ } -#define TEST_DONE \ - PASS +#define TEST_DONE PASS /** \test test propagation of depth/offset/distance/within */ static int DetectContentDepthTest01(void) @@ -837,37 +825,62 @@ static int DetectContentDepthTest01(void) TEST_RUN("content:\"abc\"; depth:6; content:\"xyz\"; distance:0; within:3; ", 3, 9); // multiple relative matches after anchored content - TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; within:3; content:\"xyz\"; distance:0; within:3; ", 6, 9); + TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; within:3; content:\"xyz\"; " + "distance:0; within:3; ", + 6, 9); // test 'reset' due to unanchored content - TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; content:\"xyz\"; distance:0; within:3; ", 3, 0); + TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; content:\"xyz\"; distance:0; within:3; ", + 3, 0); // test 'reset' due to unanchored pcre - TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/; content:\"xyz\"; distance:0; within:3; ", 0, 0); + TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/; content:\"xyz\"; distance:0; within:3; ", 0, + 0); // test relative pcre. We can use previous offset+pattern len - TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; within:3; ", 3, 0); - TEST_RUN("content:\"abc\"; offset:3; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; within:3; ", 6, 0); + TEST_RUN("content:\"abc\"; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; within:3; ", + 3, 0); + TEST_RUN("content:\"abc\"; offset:3; depth:3; pcre:/\"klm\"/R; content:\"xyz\"; distance:0; " + "within:3; ", + 6, 0); - TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; ", 0, 9); + TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; ", 0, + 9); - TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; content:\"xyz\"; distance:0; ", 6, 0); + TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; distance:0; content:\"xyz\"; distance:0; ", + 6, 0); // tests to see if anchored 'ends_with' is applied to other content as depth TEST_RUN("content:\"abc\"; depth:6; isdataat:!1,relative; content:\"klm\";", 0, 6); - TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; isdataat:!1,relative; content:\"def\"; ", 0, 9); + TEST_RUN("content:\"abc\"; depth:3; content:\"klm\"; within:3; content:\"xyz\"; within:3; " + "isdataat:!1,relative; content:\"def\"; ", + 0, 9); TEST_RUN("content:\"|03|\"; depth:1; content:\"|e0|\"; distance:4; within:1;", 5, 6); - TEST_RUN("content:\"|03|\"; depth:1; content:\"|e0|\"; distance:4; within:1; content:\"Cookie|3a|\"; distance:5; within:7;", 11, 18); + TEST_RUN("content:\"|03|\"; depth:1; content:\"|e0|\"; distance:4; within:1; " + "content:\"Cookie|3a|\"; distance:5; within:7;", + 11, 18); - TEST_RUN("content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; content:\"string\"; within:8;", 0, 0); + TEST_RUN("content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; " + "content:\"string\"; within:8;", + 0, 0); - TEST_RUN("dsize:<80; content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; within:3; content:\"|00 00 00 00 00|\"; distance:6; within:5;", 17, 80); - TEST_RUN("content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; within:3; content:\"|00 00 00 00 00|\"; distance:6; within:5;", 17, 0); + TEST_RUN("dsize:<80; content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; " + "within:3; content:\"|00 00 00 00 00|\"; distance:6; within:5;", + 17, 80); + TEST_RUN("content:!\"|00 22 02 00|\"; depth: 4; content:\"|00 00 04|\"; distance:8; within:3; " + "content:\"|00 00 00 00 00|\"; distance:6; within:5;", + 17, 0); TEST_RUN("content:\"|0d 0a 0d 0a|\"; content:\"code=\"; distance:0;", 4, 0); - TEST_RUN("content:\"|0d 0a 0d 0a|\"; content:\"code=\"; distance:0; content:\"xploit.class\"; distance:2; within:18;", 11, 0); + TEST_RUN("content:\"|0d 0a 0d 0a|\"; content:\"code=\"; distance:0; content:\"xploit.class\"; " + "distance:2; within:18;", + 11, 0); TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0;", 2, 0); - TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14;", 6, 0); - TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14; content:\".app\";", 0, 0); + TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; " + "content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14;", + 6, 0); + TEST_RUN("content:\"|16 03|\"; depth:2; content:\"|55 04 0a|\"; distance:0; " + "content:\"|0d|LogMeIn, Inc.\"; distance:1; within:14; content:\".app\";", + 0, 0); TEST_RUN("content:\"=\"; offset:4; depth:9;", 4, 13); // low end: offset 4 + patlen 1 = 5. So 5 + distance 55 = 60. @@ -909,11 +922,11 @@ static void DetectContentPrintAll(SigMatch *sm) SigMatch *first_sm = sm; - /* Print all of them */ + /* Print all of them */ for (; first_sm != NULL; first_sm = first_sm->next) { if (first_sm->type == DETECT_CONTENT) { SCLogDebug("Printing SigMatch DETECT_CONTENT %d", ++i); - DetectContentPrint((DetectContentData*)first_sm->ctx); + DetectContentPrint((DetectContentData *)first_sm->ctx); } } } @@ -926,7 +939,7 @@ static int g_dce_stub_data_buffer_id = 0; /** * \test DetectContentParseTest01 this is a test to make sure we can deal with escaped colons */ -static int DetectContentParseTest01 (void) +static int DetectContentParseTest01(void) { int result = 1; DetectContentData *cd = NULL; @@ -941,7 +954,7 @@ static int DetectContentParseTest01 (void) if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); - PrintRawUriFp(stdout,cd->content,cd->content_len); + PrintRawUriFp(stdout, cd->content, cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(NULL, cd); @@ -957,7 +970,7 @@ static int DetectContentParseTest01 (void) /** * \test DetectContentParseTest02 this is a test to make sure we can deal with escaped semi-colons */ -static int DetectContentParseTest02 (void) +static int DetectContentParseTest02(void) { int result = 1; DetectContentData *cd = NULL; @@ -972,7 +985,7 @@ static int DetectContentParseTest02 (void) if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); - PrintRawUriFp(stdout,cd->content,cd->content_len); + PrintRawUriFp(stdout, cd->content, cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(NULL, cd); @@ -988,7 +1001,7 @@ static int DetectContentParseTest02 (void) /** * \test DetectContentParseTest03 this is a test to make sure we can deal with escaped double-quotes */ -static int DetectContentParseTest03 (void) +static int DetectContentParseTest03(void) { int result = 1; DetectContentData *cd = NULL; @@ -1003,7 +1016,7 @@ static int DetectContentParseTest03 (void) if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); - PrintRawUriFp(stdout,cd->content,cd->content_len); + PrintRawUriFp(stdout, cd->content, cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(NULL, cd); @@ -1019,7 +1032,7 @@ static int DetectContentParseTest03 (void) /** * \test DetectContentParseTest04 this is a test to make sure we can deal with escaped backslashes */ -static int DetectContentParseTest04 (void) +static int DetectContentParseTest04(void) { int result = 1; DetectContentData *cd = NULL; @@ -1035,7 +1048,7 @@ static int DetectContentParseTest04 (void) uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { SCLogDebug("expected %s got ", teststringparsed); - PrintRawUriFp(stdout,cd->content,cd->content_len); + PrintRawUriFp(stdout, cd->content, cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(NULL, cd); @@ -1051,7 +1064,7 @@ static int DetectContentParseTest04 (void) /** * \test DetectContentParseTest05 test illegal escape */ -static int DetectContentParseTest05 (void) +static int DetectContentParseTest05(void) { int result = 1; DetectContentData *cd = NULL; @@ -1064,7 +1077,7 @@ static int DetectContentParseTest05 (void) cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { SCLogDebug("expected NULL got "); - PrintRawUriFp(stdout,cd->content,cd->content_len); + PrintRawUriFp(stdout, cd->content, cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(NULL, cd); @@ -1076,7 +1089,7 @@ static int DetectContentParseTest05 (void) /** * \test DetectContentParseTest06 test a binary content */ -static int DetectContentParseTest06 (void) +static int DetectContentParseTest06(void) { int result = 1; DetectContentData *cd = NULL; @@ -1092,7 +1105,7 @@ static int DetectContentParseTest06 (void) uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { SCLogDebug("expected %s got ", teststringparsed); - PrintRawUriFp(stdout,cd->content,cd->content_len); + PrintRawUriFp(stdout, cd->content, cd->content_len); SCLogDebug(": "); result = 0; DetectContentFree(NULL, cd); @@ -1108,7 +1121,7 @@ static int DetectContentParseTest06 (void) /** * \test DetectContentParseTest07 test an empty content */ -static int DetectContentParseTest07 (void) +static int DetectContentParseTest07(void) { int result = 1; DetectContentData *cd = NULL; @@ -1131,7 +1144,7 @@ static int DetectContentParseTest07 (void) /** * \test DetectContentParseTest08 test an empty content */ -static int DetectContentParseTest08 (void) +static int DetectContentParseTest08(void) { int result = 1; DetectContentData *cd = NULL; @@ -1160,8 +1173,8 @@ static int DetectContentParseTest08 (void) * \retval return 1 if match * \retval return 0 if not */ -static int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig, - uint32_t sid) +static int DetectContentLongPatternMatchTest( + uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig, uint32_t sid) { Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1216,6 +1229,7 @@ static int DetectContentLongPatternMatchTestWrp(const char *sig, uint32_t sid) * "patterns between multiple chunks!" * (without quotes! :) ) */ + // clang-format off uint8_t raw_eth_pkt[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00, @@ -1235,7 +1249,8 @@ static int DetectContentLongPatternMatchTestWrp(const char *sig, uint32_t sid) 0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65, 0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69, 0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e, - 0x6b,0x73,0x21 }; /* end raw_eth_pkt */ + 0x6b,0x73,0x21 }; + // clang-format on /* end raw_eth_pkt */ return DetectContentLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), sig, sid); @@ -2647,17 +2662,19 @@ static int SigTest76TestBug134(void) static int SigTest77TestBug139(void) { + // clang-format off uint8_t buf[] = { 0x12, 0x23, 0x34, 0x35, 0x52, 0x52, 0x24, 0x42, 0x22, 0x24, 0x52, 0x24, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x34 }; + // clang-format on uint16_t buflen = sizeof(buf); - Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_UDP); + Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_UDP); int result = 0; p->dp = 53; char sig[] = "alert udp any any -> any 53 (msg:\"dns testing\";" - " content:\"|00 00|\"; depth:5; offset:13; sid:9436601;" - " rev:1;)"; + " content:\"|00 00|\"; depth:5; offset:13; sid:9436601;" + " rev:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; @@ -2673,110 +2690,69 @@ static int SigTest77TestBug139(void) static int DetectLongContentTestCommon(const char *sig, uint32_t sid) { /* Packet with 512 A's in it for testing long content. */ - static uint8_t pkt[739] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, - 0x02, 0xd5, 0x4a, 0x18, 0x40, 0x00, 0x40, 0x06, - 0xd7, 0xd6, 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10, - 0x01, 0x0a, 0xdb, 0x36, 0x00, 0x50, 0xca, 0xc5, - 0xcc, 0xd1, 0x95, 0x77, 0x0f, 0x7d, 0x80, 0x18, - 0x00, 0xe5, 0x77, 0x9d, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x1d, 0xe0, 0x86, 0xc6, 0xfc, 0x73, - 0x49, 0xf3, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, - 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, - 0x31, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x63, - 0x75, 0x72, 0x6c, 0x2f, 0x37, 0x2e, 0x33, 0x37, - 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, - 0x3a, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x36, 0x2e, - 0x31, 0x2e, 0x31, 0x30, 0x0d, 0x0a, 0x41, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, - 0x2a, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x3a, 0x20, 0x35, 0x32, 0x38, 0x0d, 0x0a, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, - 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x78, 0x2d, 0x77, 0x77, 0x77, 0x2d, - 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x75, 0x72, 0x6c, - 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x0d, - 0x0a, 0x0d, 0x0a, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x58, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x58 - }; - - return DetectContentLongPatternMatchTest(pkt, (uint16_t)sizeof(pkt), sig, - sid); + static uint8_t pkt[739] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x45, 0x00, 0x02, 0xd5, 0x4a, 0x18, 0x40, 0x00, 0x40, 0x06, 0xd7, 0xd6, + 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10, 0x01, 0x0a, 0xdb, 0x36, 0x00, 0x50, 0xca, 0xc5, 0xcc, + 0xd1, 0x95, 0x77, 0x0f, 0x7d, 0x80, 0x18, 0x00, 0xe5, 0x77, 0x9d, 0x00, 0x00, 0x01, 0x01, + 0x08, 0x0a, 0x1d, 0xe0, 0x86, 0xc6, 0xfc, 0x73, 0x49, 0xf3, 0x50, 0x4f, 0x53, 0x54, 0x20, + 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x73, 0x65, + 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x75, 0x72, 0x6c, 0x2f, 0x37, + 0x2e, 0x33, 0x37, 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x30, + 0x2e, 0x31, 0x36, 0x2e, 0x31, 0x2e, 0x31, 0x30, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x35, 0x32, 0x38, 0x0d, 0x0a, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x77, 0x77, 0x77, + 0x2d, 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x75, 0x72, 0x6c, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, + 0x64, 0x0d, 0x0a, 0x0d, 0x0a, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58 }; + + return DetectContentLongPatternMatchTest(pkt, (uint16_t)sizeof(pkt), sig, sid); } static int DetectLongContentTest1(void) { /* Signature with 256 A's. */ - const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; " + "content:" + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; return DetectLongContentTestCommon(sig, 1); } @@ -2784,7 +2760,15 @@ static int DetectLongContentTest1(void) static int DetectLongContentTest2(void) { /* Signature with 512 A's. */ - const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; " + "content:" + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; return DetectLongContentTestCommon(sig, 1); } @@ -2792,7 +2776,15 @@ static int DetectLongContentTest2(void) static int DetectLongContentTest3(void) { /* Signature with 513 A's. */ - const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + const char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; " + "content:" + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; return !DetectLongContentTestCommon(sig, 1); } @@ -2861,33 +2853,21 @@ static void DetectContentRegisterTests(void) UtRegisterTest("DetectContentParseTest45", DetectContentParseTest45); /* The reals */ - UtRegisterTest("DetectContentLongPatternMatchTest01", - DetectContentLongPatternMatchTest01); - UtRegisterTest("DetectContentLongPatternMatchTest02", - DetectContentLongPatternMatchTest02); - UtRegisterTest("DetectContentLongPatternMatchTest03", - DetectContentLongPatternMatchTest03); - UtRegisterTest("DetectContentLongPatternMatchTest04", - DetectContentLongPatternMatchTest04); - UtRegisterTest("DetectContentLongPatternMatchTest05", - DetectContentLongPatternMatchTest05); - UtRegisterTest("DetectContentLongPatternMatchTest06", - DetectContentLongPatternMatchTest06); - UtRegisterTest("DetectContentLongPatternMatchTest07", - DetectContentLongPatternMatchTest07); - UtRegisterTest("DetectContentLongPatternMatchTest08", - DetectContentLongPatternMatchTest08); - UtRegisterTest("DetectContentLongPatternMatchTest09", - DetectContentLongPatternMatchTest09); - UtRegisterTest("DetectContentLongPatternMatchTest10", - DetectContentLongPatternMatchTest10); - UtRegisterTest("DetectContentLongPatternMatchTest11", - DetectContentLongPatternMatchTest11); + UtRegisterTest("DetectContentLongPatternMatchTest01", DetectContentLongPatternMatchTest01); + UtRegisterTest("DetectContentLongPatternMatchTest02", DetectContentLongPatternMatchTest02); + UtRegisterTest("DetectContentLongPatternMatchTest03", DetectContentLongPatternMatchTest03); + UtRegisterTest("DetectContentLongPatternMatchTest04", DetectContentLongPatternMatchTest04); + UtRegisterTest("DetectContentLongPatternMatchTest05", DetectContentLongPatternMatchTest05); + UtRegisterTest("DetectContentLongPatternMatchTest06", DetectContentLongPatternMatchTest06); + UtRegisterTest("DetectContentLongPatternMatchTest07", DetectContentLongPatternMatchTest07); + UtRegisterTest("DetectContentLongPatternMatchTest08", DetectContentLongPatternMatchTest08); + UtRegisterTest("DetectContentLongPatternMatchTest09", DetectContentLongPatternMatchTest09); + UtRegisterTest("DetectContentLongPatternMatchTest10", DetectContentLongPatternMatchTest10); + UtRegisterTest("DetectContentLongPatternMatchTest11", DetectContentLongPatternMatchTest11); /* Negated content tests */ UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent); - UtRegisterTest("SigTest41aTestNegatedContent", - SigTest41aTestNegatedContent); + UtRegisterTest("SigTest41aTestNegatedContent", SigTest41aTestNegatedContent); UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent); UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent); UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent); diff --git a/src/detect-content.h b/src/detect-content.h index bc47562a96f8..27e74ea23a0d 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -35,52 +35,49 @@ #define DETECT_CONTENT_FAST_PATTERN_ONLY BIT_U32(6) #define DETECT_CONTENT_FAST_PATTERN_CHOP BIT_U32(7) /** content applies to a "raw"/undecoded field if applicable */ -#define DETECT_CONTENT_RAWBYTES BIT_U32(8) +#define DETECT_CONTENT_RAWBYTES BIT_U32(8) /** content is negated */ -#define DETECT_CONTENT_NEGATED BIT_U32(9) +#define DETECT_CONTENT_NEGATED BIT_U32(9) -#define DETECT_CONTENT_ENDS_WITH BIT_U32(10) +#define DETECT_CONTENT_ENDS_WITH BIT_U32(10) /* BE - byte extract */ -#define DETECT_CONTENT_OFFSET_VAR BIT_U32(11) -#define DETECT_CONTENT_DEPTH_VAR BIT_U32(12) -#define DETECT_CONTENT_DISTANCE_VAR BIT_U32(13) -#define DETECT_CONTENT_WITHIN_VAR BIT_U32(14) +#define DETECT_CONTENT_OFFSET_VAR BIT_U32(11) +#define DETECT_CONTENT_DEPTH_VAR BIT_U32(12) +#define DETECT_CONTENT_DISTANCE_VAR BIT_U32(13) +#define DETECT_CONTENT_WITHIN_VAR BIT_U32(14) /* replace data */ -#define DETECT_CONTENT_REPLACE BIT_U32(15) +#define DETECT_CONTENT_REPLACE BIT_U32(15) /* this flag is set during the staging phase. It indicates that a content * has been added to the mpm phase and requires no further inspection inside * the inspection phase */ #define DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED BIT_U32(16) -#define DETECT_CONTENT_WITHIN_NEXT BIT_U32(17) -#define DETECT_CONTENT_DISTANCE_NEXT BIT_U32(18) -#define DETECT_CONTENT_STARTS_WITH BIT_U32(19) +#define DETECT_CONTENT_WITHIN_NEXT BIT_U32(17) +#define DETECT_CONTENT_DISTANCE_NEXT BIT_U32(18) +#define DETECT_CONTENT_STARTS_WITH BIT_U32(19) /** MPM pattern selected by the engine or forced by fast_pattern keyword */ -#define DETECT_CONTENT_MPM BIT_U32(20) -#define DETECT_CONTENT_WITHIN2DEPTH BIT_U32(21) -#define DETECT_CONTENT_DISTANCE2OFFSET BIT_U32(22) +#define DETECT_CONTENT_MPM BIT_U32(20) +#define DETECT_CONTENT_WITHIN2DEPTH BIT_U32(21) +#define DETECT_CONTENT_DISTANCE2OFFSET BIT_U32(22) /** a relative match to this content is next, used in matching phase */ -#define DETECT_CONTENT_RELATIVE_NEXT (DETECT_CONTENT_WITHIN_NEXT|DETECT_CONTENT_DISTANCE_NEXT) +#define DETECT_CONTENT_RELATIVE_NEXT (DETECT_CONTENT_WITHIN_NEXT | DETECT_CONTENT_DISTANCE_NEXT) -#define DETECT_CONTENT_IS_SINGLE(c) (!( ((c)->flags & DETECT_CONTENT_DISTANCE) || \ - ((c)->flags & DETECT_CONTENT_WITHIN) || \ - ((c)->flags & DETECT_CONTENT_RELATIVE_NEXT) || \ - ((c)->flags & DETECT_CONTENT_DEPTH) || \ - ((c)->flags & DETECT_CONTENT_OFFSET) )) +#define DETECT_CONTENT_IS_SINGLE(c) \ + (!(((c)->flags & DETECT_CONTENT_DISTANCE) || ((c)->flags & DETECT_CONTENT_WITHIN) || \ + ((c)->flags & DETECT_CONTENT_RELATIVE_NEXT) || ((c)->flags & DETECT_CONTENT_DEPTH) || \ + ((c)->flags & DETECT_CONTENT_OFFSET))) /* if a pattern has no depth/offset limits, no relative specifiers and isn't * chopped for the mpm, we can take the mpm and consider this pattern a match * w/o further inspection. Warning: this may still mean other patterns depend * on this pattern that force match validation anyway. */ -#define DETECT_CONTENT_MPM_IS_CONCLUSIVE(c) \ - !( ((c)->flags & DETECT_CONTENT_DISTANCE) || \ - ((c)->flags & DETECT_CONTENT_WITHIN) || \ - ((c)->flags & DETECT_CONTENT_DEPTH) || \ - ((c)->flags & DETECT_CONTENT_OFFSET) || \ - ((c)->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)) +#define DETECT_CONTENT_MPM_IS_CONCLUSIVE(c) \ + !(((c)->flags & DETECT_CONTENT_DISTANCE) || ((c)->flags & DETECT_CONTENT_WITHIN) || \ + ((c)->flags & DETECT_CONTENT_DEPTH) || ((c)->flags & DETECT_CONTENT_OFFSET) || \ + ((c)->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)) /* * Values for distance, and within must be less than or equal @@ -88,7 +85,7 @@ */ #define DETECT_CONTENT_VALUE_MAX 1024 * 1024 -#include "util-spm.h" +#include "util/spm.h" typedef struct DetectContentData_ { uint8_t *content; @@ -115,12 +112,12 @@ typedef struct DetectContentData_ { /* prototypes */ void DetectContentRegister(void); -DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, - const char *contentstr); -int DetectContentDataParse(const char *keyword, const char *contentstr, - uint8_t **pstr, uint16_t *plen); -DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, - const char *contentstr); +DetectContentData *DetectContentParse( + SpmGlobalThreadCtx *spm_global_thread_ctx, const char *contentstr); +int DetectContentDataParse( + const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen); +DetectContentData *DetectContentParseEncloseQuotes( + SpmGlobalThreadCtx *spm_global_thread_ctx, const char *contentstr); int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *contentstr); void DetectContentPrint(DetectContentData *); diff --git a/src/detect-csum.c b/src/detect-csum.c index ba2088a61e99..d482dec30aed 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -31,12 +31,12 @@ #include "detect-csum.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/debug.h" #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" +#include "util/profiling.h" #include "detect-engine-build.h" #define DETECT_CSUM_VALID "valid" @@ -49,44 +49,44 @@ typedef struct DetectCsumData_ { } DetectCsumData; /* prototypes for the "ipv4-csum" rule keyword */ -static int DetectIPV4CsumMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectIPV4CsumMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectIPV4CsumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectIPV4CsumFree(DetectEngineCtx *, void *); /* prototypes for the "tcpv4-csum" rule keyword */ -static int DetectTCPV4CsumMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectTCPV4CsumMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV4CsumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectTCPV4CsumFree(DetectEngineCtx *, void *); /* prototypes for the "tcpv6-csum" rule keyword */ -static int DetectTCPV6CsumMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectTCPV6CsumMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV6CsumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectTCPV6CsumFree(DetectEngineCtx *, void *); /* prototypes for the "udpv4-csum" rule keyword */ -static int DetectUDPV4CsumMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectUDPV4CsumMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV4CsumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectUDPV4CsumFree(DetectEngineCtx *, void *); /* prototypes for the "udpv6-csum" rule keyword */ -static int DetectUDPV6CsumMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectUDPV6CsumMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV6CsumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectUDPV6CsumFree(DetectEngineCtx *de_ctx, void *); /* prototypes for the "icmpv4-csum" rule keyword */ -static int DetectICMPV4CsumMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectICMPV4CsumMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV4CsumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectICMPV4CsumFree(DetectEngineCtx *, void *); /* prototypes for the "icmpv6-csum" rule keyword */ -static int DetectICMPV6CsumMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectICMPV6CsumMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV6CsumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectICMPV6CsumFree(DetectEngineCtx *, void *); @@ -136,12 +136,12 @@ static void DetectCsumRegisterTests(void); * * void * (ptr) - Pointer to the DetectCsumData for a keyword */ -void DetectCsumRegister (void) +void DetectCsumRegister(void) { sigmatch_table[DETECT_IPV4_CSUM].name = "ipv4-csum"; sigmatch_table[DETECT_IPV4_CSUM].Match = DetectIPV4CsumMatch; sigmatch_table[DETECT_IPV4_CSUM].Setup = DetectIPV4CsumSetup; - sigmatch_table[DETECT_IPV4_CSUM].Free = DetectIPV4CsumFree; + sigmatch_table[DETECT_IPV4_CSUM].Free = DetectIPV4CsumFree; #ifdef UNITTESTS sigmatch_table[DETECT_IPV4_CSUM].RegisterTests = DetectCsumRegisterTests; #endif @@ -149,32 +149,32 @@ void DetectCsumRegister (void) sigmatch_table[DETECT_TCPV4_CSUM].name = "tcpv4-csum"; sigmatch_table[DETECT_TCPV4_CSUM].Match = DetectTCPV4CsumMatch; sigmatch_table[DETECT_TCPV4_CSUM].Setup = DetectTCPV4CsumSetup; - sigmatch_table[DETECT_TCPV4_CSUM].Free = DetectTCPV4CsumFree; + sigmatch_table[DETECT_TCPV4_CSUM].Free = DetectTCPV4CsumFree; sigmatch_table[DETECT_TCPV6_CSUM].name = "tcpv6-csum"; sigmatch_table[DETECT_TCPV6_CSUM].Match = DetectTCPV6CsumMatch; sigmatch_table[DETECT_TCPV6_CSUM].Setup = DetectTCPV6CsumSetup; - sigmatch_table[DETECT_TCPV6_CSUM].Free = DetectTCPV6CsumFree; + sigmatch_table[DETECT_TCPV6_CSUM].Free = DetectTCPV6CsumFree; sigmatch_table[DETECT_UDPV4_CSUM].name = "udpv4-csum"; sigmatch_table[DETECT_UDPV4_CSUM].Match = DetectUDPV4CsumMatch; sigmatch_table[DETECT_UDPV4_CSUM].Setup = DetectUDPV4CsumSetup; - sigmatch_table[DETECT_UDPV4_CSUM].Free = DetectUDPV4CsumFree; + sigmatch_table[DETECT_UDPV4_CSUM].Free = DetectUDPV4CsumFree; sigmatch_table[DETECT_UDPV6_CSUM].name = "udpv6-csum"; sigmatch_table[DETECT_UDPV6_CSUM].Match = DetectUDPV6CsumMatch; sigmatch_table[DETECT_UDPV6_CSUM].Setup = DetectUDPV6CsumSetup; - sigmatch_table[DETECT_UDPV6_CSUM].Free = DetectUDPV6CsumFree; + sigmatch_table[DETECT_UDPV6_CSUM].Free = DetectUDPV6CsumFree; sigmatch_table[DETECT_ICMPV4_CSUM].name = "icmpv4-csum"; sigmatch_table[DETECT_ICMPV4_CSUM].Match = DetectICMPV4CsumMatch; sigmatch_table[DETECT_ICMPV4_CSUM].Setup = DetectICMPV4CsumSetup; - sigmatch_table[DETECT_ICMPV4_CSUM].Free = DetectICMPV4CsumFree; + sigmatch_table[DETECT_ICMPV4_CSUM].Free = DetectICMPV4CsumFree; sigmatch_table[DETECT_ICMPV6_CSUM].name = "icmpv6-csum"; sigmatch_table[DETECT_ICMPV6_CSUM].Match = DetectICMPV6CsumMatch; sigmatch_table[DETECT_ICMPV6_CSUM].Setup = DetectICMPV6CsumSetup; - sigmatch_table[DETECT_ICMPV6_CSUM].Free = DetectICMPV6CsumFree; + sigmatch_table[DETECT_ICMPV6_CSUM].Free = DetectICMPV6CsumFree; } /** @@ -206,8 +206,7 @@ static int DetectCsumParseArg(const char *key, DetectCsumData *cd) } } - if (strcasecmp(str, DETECT_CSUM_VALID) == 0 || - strcasecmp(str, DETECT_CSUM_INVALID) == 0) { + if (strcasecmp(str, DETECT_CSUM_VALID) == 0 || strcasecmp(str, DETECT_CSUM_INVALID) == 0) { cd->valid = (strcasecmp(key, DETECT_CSUM_VALID) == 0); SCFree(str); return 1; @@ -234,8 +233,8 @@ static int DetectCsumParseArg(const char *key, DetectCsumData *cd) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -static int DetectIPV4CsumMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectIPV4CsumMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -247,9 +246,7 @@ static int DetectIPV4CsumMatch(DetectEngineThreadCtx *det_ctx, } if (p->level3_comp_csum == -1) - p->level3_comp_csum = IPV4Checksum((uint16_t *)p->ip4h, - IPV4_GET_HLEN(p), - p->ip4h->ip_csum); + p->level3_comp_csum = IPV4Checksum((uint16_t *)p->ip4h, IPV4_GET_HLEN(p), p->ip4h->ip_csum); if (p->level3_comp_csum == 0 && cd->valid == 1) return 1; @@ -275,7 +272,7 @@ static int DetectIPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char { DetectCsumData *cd = NULL; - //printf("DetectCsumSetup: \'%s\'\n", csum_str); + // printf("DetectCsumSetup: \'%s\'\n", csum_str); if ((cd = SCCalloc(1, sizeof(DetectCsumData))) == NULL) goto error; @@ -322,8 +319,8 @@ static void DetectIPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -static int DetectTCPV4CsumMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectTCPV4CsumMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -335,11 +332,8 @@ static int DetectTCPV4CsumMatch(DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, + (p->payload_len + TCP_GET_HLEN(p)), p->tcph->th_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; @@ -365,7 +359,7 @@ static int DetectTCPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const cha { DetectCsumData *cd = NULL; - //printf("DetectCsumSetup: \'%s\'\n", csum_str); + // printf("DetectCsumSetup: \'%s\'\n", csum_str); if ((cd = SCCalloc(1, sizeof(DetectCsumData))) == NULL) goto error; @@ -412,8 +406,8 @@ static void DetectTCPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -static int DetectTCPV6CsumMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectTCPV6CsumMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -425,11 +419,8 @@ static int DetectTCPV6CsumMatch(DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, + (p->payload_len + TCP_GET_HLEN(p)), p->tcph->th_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; @@ -455,7 +446,7 @@ static int DetectTCPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const cha { DetectCsumData *cd = NULL; - //printf("DetectCsumSetup: \'%s\'\n", csum_str); + // printf("DetectCsumSetup: \'%s\'\n", csum_str); if ((cd = SCCalloc(1, sizeof(DetectCsumData))) == NULL) goto error; @@ -502,12 +493,13 @@ static void DetectTCPV6CsumFree(DetectEngineCtx *de_ctx, void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -static int DetectUDPV4CsumMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectUDPV4CsumMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; - if (p->ip4h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p) || p->udph->uh_sum == 0) + if (p->ip4h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p) || + p->udph->uh_sum == 0) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { @@ -515,11 +507,8 @@ static int DetectUDPV4CsumMatch(DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = UDPV4Checksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->udph, - (p->payload_len + - UDP_HEADER_LEN), - p->udph->uh_sum); + p->level4_comp_csum = UDPV4Checksum(p->ip4h->s_ip_addrs, (uint16_t *)p->udph, + (p->payload_len + UDP_HEADER_LEN), p->udph->uh_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; @@ -545,7 +534,7 @@ static int DetectUDPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const cha { DetectCsumData *cd = NULL; - //printf("DetectCsumSetup: \'%s\'\n", csum_str); + // printf("DetectCsumSetup: \'%s\'\n", csum_str); if ((cd = SCCalloc(1, sizeof(DetectCsumData))) == NULL) goto error; @@ -592,8 +581,8 @@ static void DetectUDPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -static int DetectUDPV6CsumMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectUDPV6CsumMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -605,11 +594,8 @@ static int DetectUDPV6CsumMatch(DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = UDPV6Checksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->udph, - (p->payload_len + - UDP_HEADER_LEN), - p->udph->uh_sum); + p->level4_comp_csum = UDPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->udph, + (p->payload_len + UDP_HEADER_LEN), p->udph->uh_sum); if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; @@ -635,7 +621,7 @@ static int DetectUDPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const cha { DetectCsumData *cd = NULL; - //printf("DetectCsumSetup: \'%s\'\n", csum_str); + // printf("DetectCsumSetup: \'%s\'\n", csum_str); if ((cd = SCCalloc(1, sizeof(DetectCsumData))) == NULL) goto error; @@ -682,8 +668,8 @@ static void DetectUDPV6CsumFree(DetectEngineCtx *de_ctx, void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -static int DetectICMPV4CsumMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectICMPV4CsumMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; @@ -696,8 +682,7 @@ static int DetectICMPV4CsumMatch(DetectEngineThreadCtx *det_ctx, if (p->level4_comp_csum == -1) p->level4_comp_csum = ICMPV4CalculateChecksum((uint16_t *)p->icmpv4h, - SCNtohs(IPV4_GET_RAW_IPLEN(p->ip4h)) - - IPV4_GET_RAW_HLEN(p->ip4h) * 4); + SCNtohs(IPV4_GET_RAW_IPLEN(p->ip4h)) - IPV4_GET_RAW_HLEN(p->ip4h) * 4); if (p->level4_comp_csum == p->icmpv4h->checksum && cd->valid == 1) return 1; @@ -723,7 +708,7 @@ static int DetectICMPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const ch { DetectCsumData *cd = NULL; - //printf("DetectCsumSetup: \'%s\'\n", csum_str); + // printf("DetectCsumSetup: \'%s\'\n", csum_str); if ((cd = SCCalloc(1, sizeof(DetectCsumData))) == NULL) goto error; @@ -770,13 +755,14 @@ static void DetectICMPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -static int DetectICMPV6CsumMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectICMPV6CsumMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; - if (p->ip6h == NULL || p->icmpv6h == NULL || p->proto != IPPROTO_ICMPV6 || PKT_IS_PSEUDOPKT(p) || - (GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))) <= 0) { + if (p->ip6h == NULL || p->icmpv6h == NULL || p->proto != IPPROTO_ICMPV6 || + PKT_IS_PSEUDOPKT(p) || + (GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))) <= 0) { return 0; } @@ -787,9 +773,8 @@ static int DetectICMPV6CsumMatch(DetectEngineThreadCtx *det_ctx, if (p->level4_comp_csum == -1) { uint16_t len = IPV6_GET_RAW_PLEN(p->ip6h) - (uint16_t)((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); - p->level4_comp_csum = ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->icmpv6h, - len); + p->level4_comp_csum = + ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->icmpv6h, len); } if (p->level4_comp_csum == p->icmpv6h->csum && cd->valid == 1) @@ -849,30 +834,35 @@ static void DetectICMPV6CsumFree(DetectEngineCtx *de_ctx, void *ptr) /* ---------------------------------- Unit Tests --------------------------- */ #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "detect-engine.h" #include "detect-engine-alert.h" #include "packet.h" #define mystr(s) #s -#define TEST1(kwstr) {\ - DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ - FAIL_IF_NULL(de_ctx);\ - de_ctx->flags = DE_QUIET;\ - \ - Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\ - FAIL_IF_NULL(s);\ - s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:invalid; sid:2;)");\ - FAIL_IF_NULL(s);\ - s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaLid; sid:3;)");\ - FAIL_IF_NULL(s);\ - s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:VALID; sid:4;)");\ - FAIL_IF_NULL(s);\ - s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:iNvaLid; sid:5;)");\ - FAIL_IF_NULL(s);\ - DetectEngineCtxFree(de_ctx);\ -} - +#define TEST1(kwstr) \ + { \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \ + FAIL_IF_NULL(de_ctx); \ + de_ctx->flags = DE_QUIET; \ + \ + Signature *s = DetectEngineAppendSig( \ + de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:valid; sid:1;)"); \ + FAIL_IF_NULL(s); \ + s = DetectEngineAppendSig( \ + de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:invalid; sid:2;)"); \ + FAIL_IF_NULL(s); \ + s = DetectEngineAppendSig( \ + de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:vaLid; sid:3;)"); \ + FAIL_IF_NULL(s); \ + s = DetectEngineAppendSig( \ + de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:VALID; sid:4;)"); \ + FAIL_IF_NULL(s); \ + s = DetectEngineAppendSig( \ + de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:iNvaLid; sid:5;)"); \ + FAIL_IF_NULL(s); \ + DetectEngineCtxFree(de_ctx); \ + } static int DetectCsumValidArgsTestParse01(void) { @@ -922,23 +912,26 @@ static int DetectCsumInvalidArgsTestParse02(void) } #undef TEST2 -#define TEST3(kwstr, kwtype) { \ - DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ - FAIL_IF_NULL(de_ctx);\ - Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\ - FAIL_IF_NULL(s);\ - SigMatch *sm = DetectGetLastSMFromLists(s, (kwtype), -1);\ - FAIL_IF_NULL(sm);\ - FAIL_IF_NULL(sm->ctx);\ - FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 1);\ - s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:INVALID; sid:2;)");\ - FAIL_IF_NULL(s);\ - sm = DetectGetLastSMFromLists(s, (kwtype), -1);\ - FAIL_IF_NULL(sm);\ - FAIL_IF_NULL(sm->ctx);\ - FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 0);\ - DetectEngineCtxFree(de_ctx);\ -} +#define TEST3(kwstr, kwtype) \ + { \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \ + FAIL_IF_NULL(de_ctx); \ + Signature *s = DetectEngineAppendSig( \ + de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:valid; sid:1;)"); \ + FAIL_IF_NULL(s); \ + SigMatch *sm = DetectGetLastSMFromLists(s, (kwtype), -1); \ + FAIL_IF_NULL(sm); \ + FAIL_IF_NULL(sm->ctx); \ + FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 1); \ + s = DetectEngineAppendSig( \ + de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:INVALID; sid:2;)"); \ + FAIL_IF_NULL(s); \ + sm = DetectGetLastSMFromLists(s, (kwtype), -1); \ + FAIL_IF_NULL(sm); \ + FAIL_IF_NULL(sm->ctx); \ + FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 0); \ + DetectEngineCtxFree(de_ctx); \ + } static int DetectCsumValidArgsTestParse03(void) { @@ -967,6 +960,7 @@ static int DetectCsumICMPV6Test01(void) Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); + // clang-format off uint8_t pkt[] = { 0x00, 0x30, 0x18, 0xa8, 0x7c, 0x23, 0x2c, 0x41, 0x38, 0xa7, 0xea, 0xeb, 0x86, 0xdd, 0x60, 0x00, @@ -983,6 +977,7 @@ static int DetectCsumICMPV6Test01(void) 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x63, 0xc2, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on PacketCopyData(p, pkt, sizeof(pkt)); @@ -998,7 +993,7 @@ static int DetectCsumICMPV6Test01(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " - "(icmpv6-csum:valid; sid:1;)"); + "(icmpv6-csum:valid; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1022,14 +1017,10 @@ static int DetectCsumICMPV6Test01(void) static void DetectCsumRegisterTests(void) { - UtRegisterTest("DetectCsumValidArgsTestParse01", - DetectCsumValidArgsTestParse01); - UtRegisterTest("DetectCsumInvalidArgsTestParse02", - DetectCsumInvalidArgsTestParse02); - UtRegisterTest("DetectCsumValidArgsTestParse03", - DetectCsumValidArgsTestParse03); - - UtRegisterTest("DetectCsumICMPV6Test01", - DetectCsumICMPV6Test01); + UtRegisterTest("DetectCsumValidArgsTestParse01", DetectCsumValidArgsTestParse01); + UtRegisterTest("DetectCsumInvalidArgsTestParse02", DetectCsumInvalidArgsTestParse02); + UtRegisterTest("DetectCsumValidArgsTestParse03", DetectCsumValidArgsTestParse03); + + UtRegisterTest("DetectCsumICMPV6Test01", DetectCsumICMPV6Test01); } #endif /* UNITTESTS */ diff --git a/src/detect-csum.h b/src/detect-csum.h index 64914912fe8f..f97c84c7113c 100644 --- a/src/detect-csum.h +++ b/src/detect-csum.h @@ -27,4 +27,3 @@ void DetectCsumRegister(void); #endif /* __DETECT_CSUM_H__ */ - diff --git a/src/detect-datarep.c b/src/detect-datarep.c index 5b959b4023a3..72778b710cdc 100644 --- a/src/detect-datarep.c +++ b/src/detect-datarep.c @@ -35,27 +35,27 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-misc.h" -#include "util-path.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/misc.h" +#include "util/path.h" -#define PARSE_REGEX "([a-z]+)(?:,\\s*([\\-_A-z0-9\\s\\.]+)){1,4}" +#define PARSE_REGEX "([a-z]+)(?:,\\s*([\\-_A-z0-9\\s\\.]+)){1,4}" static DetectParseRegex parse_regex; -int DetectDatarepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectDatarepSetup (DetectEngineCtx *, Signature *, const char *); -void DetectDatarepFree (DetectEngineCtx *, void *); +int DetectDatarepMatch( + ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectDatarepSetup(DetectEngineCtx *, Signature *, const char *); +void DetectDatarepFree(DetectEngineCtx *, void *); -void DetectDatarepRegister (void) +void DetectDatarepRegister(void) { sigmatch_table[DETECT_DATAREP].name = "datarep"; sigmatch_table[DETECT_DATAREP].desc = "operate on datasets (experimental)"; sigmatch_table[DETECT_DATAREP].url = "/rules/dataset-keywords.html#datarep"; sigmatch_table[DETECT_DATAREP].Setup = DetectDatarepSetup; - sigmatch_table[DETECT_DATAREP].Free = DetectDatarepFree; + sigmatch_table[DETECT_DATAREP].Free = DetectDatarepFree; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } @@ -65,9 +65,8 @@ void DetectDatarepRegister (void) 0 no match -1 can't match */ -int DetectDatarepBufferMatch(DetectEngineThreadCtx *det_ctx, - const DetectDatarepData *sd, - const uint8_t *data, const uint32_t data_len) +int DetectDatarepBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatarepData *sd, + const uint8_t *data, const uint32_t data_len) { if (data == NULL || data_len == 0) return 0; @@ -101,7 +100,7 @@ static int DetectDatarepParse(const char *str, char *cmd, int cmd_len, char *nam bool name_set = false; bool value_set = false; - char copy[strlen(str)+1]; + char copy[strlen(str) + 1]; strlcpy(copy, str, sizeof(copy)); char *xsaveptr = NULL; char *key = strtok_r(copy, ",", &xsaveptr); @@ -241,8 +240,7 @@ static void GetDirName(const char *in, char *out, size_t outs) return; } -static int SetupLoadPath(const DetectEngineCtx *de_ctx, - char *load, size_t load_size) +static int SetupLoadPath(const DetectEngineCtx *de_ctx, char *load, size_t load_size) { SCLogDebug("load %s", load); @@ -290,7 +288,7 @@ static int SetupLoadPath(const DetectEngineCtx *de_ctx, return 0; } -static int DetectDatarepSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectDatarepSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { char cmd_str[16] = "", name[64] = ""; enum DatasetTypes type = DATASET_TYPE_NOTSET; @@ -321,11 +319,11 @@ static int DetectDatarepSetup (DetectEngineCtx *de_ctx, Signature *s, const char } enum DetectDatarepOp op; - if (strcmp(cmd_str,">") == 0) { + if (strcmp(cmd_str, ">") == 0) { op = DATAREP_OP_GT; - } else if (strcmp(cmd_str,"<") == 0) { + } else if (strcmp(cmd_str, "<") == 0) { op = DATAREP_OP_LT; - } else if (strcmp(cmd_str,"==") == 0) { + } else if (strcmp(cmd_str, "==") == 0) { op = DATAREP_OP_EQ; } else { SCLogError("datarep operation \"%s\" is not supported.", cmd_str); @@ -346,8 +344,7 @@ static int DetectDatarepSetup (DetectEngineCtx *de_ctx, Signature *s, const char cd->op = op; cd->rep.value = value; - SCLogDebug("cmd %s, name %s", - cmd_str, strlen(name) ? name : "(none)"); + SCLogDebug("cmd %s, name %s", cmd_str, strlen(name) ? name : "(none)"); /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ @@ -363,7 +360,7 @@ static int DetectDatarepSetup (DetectEngineCtx *de_ctx, Signature *s, const char return -1; } -void DetectDatarepFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectDatarepFree(DetectEngineCtx *de_ctx, void *ptr) { DetectDatarepData *fd = (DetectDatarepData *)ptr; diff --git a/src/detect-datarep.h b/src/detect-datarep.h index b6191588240c..f6836138daa1 100644 --- a/src/detect-datarep.h +++ b/src/detect-datarep.h @@ -28,9 +28,9 @@ #include "datasets-reputation.h" enum DetectDatarepOp { - DATAREP_OP_GT, /* rep is greater than requested */ - DATAREP_OP_LT, /* rep is smaller than requested */ - DATAREP_OP_EQ, /* rep is smaller than requested */ + DATAREP_OP_GT, /* rep is greater than requested */ + DATAREP_OP_LT, /* rep is smaller than requested */ + DATAREP_OP_EQ, /* rep is smaller than requested */ }; typedef struct DetectDatarepData_ { @@ -40,11 +40,10 @@ typedef struct DetectDatarepData_ { DataRepType rep; } DetectDatarepData; -int DetectDatarepBufferMatch(DetectEngineThreadCtx *det_ctx, - const DetectDatarepData *sd, - const uint8_t *data, const uint32_t data_len); +int DetectDatarepBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatarepData *sd, + const uint8_t *data, const uint32_t data_len); /* prototypes */ -void DetectDatarepRegister (void); +void DetectDatarepRegister(void); #endif /* __DETECT_DATAREP_H__ */ diff --git a/src/detect-dataset.c b/src/detect-dataset.c index f6d0d844e2e5..79ad0e70ca26 100644 --- a/src/detect-dataset.c +++ b/src/detect-dataset.c @@ -35,24 +35,24 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-misc.h" -#include "util-path.h" -#include "util-conf.h" - -int DetectDatasetMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectDatasetSetup (DetectEngineCtx *, Signature *, const char *); -void DetectDatasetFree (DetectEngineCtx *, void *); - -void DetectDatasetRegister (void) +#include "util/debug.h" +#include "util/print.h" +#include "util/misc.h" +#include "util/path.h" +#include "util/conf.h" + +int DetectDatasetMatch( + ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectDatasetSetup(DetectEngineCtx *, Signature *, const char *); +void DetectDatasetFree(DetectEngineCtx *, void *); + +void DetectDatasetRegister(void) { sigmatch_table[DETECT_DATASET].name = "dataset"; sigmatch_table[DETECT_DATASET].desc = "match sticky buffer against datasets (experimental)"; sigmatch_table[DETECT_DATASET].url = "/rules/dataset-keywords.html#dataset"; sigmatch_table[DETECT_DATASET].Setup = DetectDatasetSetup; - sigmatch_table[DETECT_DATASET].Free = DetectDatasetFree; + sigmatch_table[DETECT_DATASET].Free = DetectDatasetFree; } /* @@ -60,16 +60,15 @@ void DetectDatasetRegister (void) 0 no match -1 can't match */ -int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, - const DetectDatasetData *sd, - const uint8_t *data, const uint32_t data_len) +int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatasetData *sd, + const uint8_t *data, const uint32_t data_len) { if (data == NULL || data_len == 0) return 0; switch (sd->cmd) { case DETECT_DATASET_CMD_ISSET: { - //PrintRawDataFp(stdout, data, data_len); + // PrintRawDataFp(stdout, data, data_len); int r = DatasetLookup(sd->set, data, data_len); SCLogDebug("r %d", r); if (r == 1) @@ -77,7 +76,7 @@ int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, break; } case DETECT_DATASET_CMD_ISNOTSET: { - //PrintRawDataFp(stdout, data, data_len); + // PrintRawDataFp(stdout, data, data_len); int r = DatasetLookup(sd->set, data, data_len); SCLogDebug("r %d", r); if (r < 1) @@ -85,7 +84,7 @@ int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, break; } case DETECT_DATASET_CMD_SET: { - //PrintRawDataFp(stdout, data, data_len); + // PrintRawDataFp(stdout, data, data_len); int r = DatasetAdd(sd->set, data, data_len); if (r == 1) return 1; @@ -107,7 +106,7 @@ static int DetectDatasetParse(const char *str, char *cmd, int cmd_len, char *nam bool save_set = false; bool state_set = false; - char copy[strlen(str)+1]; + char copy[strlen(str) + 1]; strlcpy(copy, str, sizeof(copy)); char *xsaveptr = NULL; char *key = strtok_r(copy, ",", &xsaveptr); @@ -255,8 +254,7 @@ static void GetDirName(const char *in, char *out, size_t outs) return; } -static int SetupLoadPath(const DetectEngineCtx *de_ctx, - char *load, size_t load_size) +static int SetupLoadPath(const DetectEngineCtx *de_ctx, char *load, size_t load_size) { SCLogDebug("load %s", load); @@ -298,8 +296,7 @@ static int SetupLoadPath(const DetectEngineCtx *de_ctx, return 0; } -static int SetupSavePath(const DetectEngineCtx *de_ctx, - char *save, size_t save_size) +static int SetupSavePath(const DetectEngineCtx *de_ctx, char *save, size_t save_size) { SCLogDebug("save %s", save); @@ -341,7 +338,7 @@ static int SetupSavePath(const DetectEngineCtx *de_ctx, return 0; } -int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +int DetectDatasetSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectDatasetData *cd = NULL; uint8_t cmd = 0; @@ -368,13 +365,13 @@ int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst return -1; } - if (strcmp(cmd_str,"isset") == 0) { + if (strcmp(cmd_str, "isset") == 0) { cmd = DETECT_DATASET_CMD_ISSET; - } else if (strcmp(cmd_str,"isnotset") == 0) { + } else if (strcmp(cmd_str, "isnotset") == 0) { cmd = DETECT_DATASET_CMD_ISNOTSET; - } else if (strcmp(cmd_str,"set") == 0) { + } else if (strcmp(cmd_str, "set") == 0) { cmd = DETECT_DATASET_CMD_SET; - } else if (strcmp(cmd_str,"unset") == 0) { + } else if (strcmp(cmd_str, "unset") == 0) { cmd = DETECT_DATASET_CMD_UNSET; } else { SCLogError("dataset action \"%s\" is not supported.", cmd_str); @@ -386,15 +383,14 @@ int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst if (strlen(save) == 0 && strlen(load) != 0) { if (SetupLoadPath(de_ctx, load, sizeof(load)) != 0) return -1; - /* if just 'save' is set, we use either full path or the - * data-dir */ + /* if just 'save' is set, we use either full path or the + * data-dir */ } else if (strlen(save) != 0 && strlen(load) == 0) { if (SetupSavePath(de_ctx, save, sizeof(save)) != 0) return -1; - /* use 'save' logic for 'state', but put the resulting - * path into 'load' as well. */ - } else if (strlen(save) != 0 && strlen(load) != 0 && - strcmp(save, load) == 0) { + /* use 'save' logic for 'state', but put the resulting + * path into 'load' as well. */ + } else if (strlen(save) != 0 && strlen(load) != 0 && strcmp(save, load) == 0) { if (SetupSavePath(de_ctx, save, sizeof(save)) != 0) return -1; strlcpy(load, save, sizeof(load)); @@ -418,8 +414,7 @@ int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst cd->set = set; cd->cmd = cmd; - SCLogDebug("cmd %s, name %s", - cmd_str, strlen(name) ? name : "(none)"); + SCLogDebug("cmd %s, name %s", cmd_str, strlen(name) ? name : "(none)"); /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ @@ -435,7 +430,7 @@ int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst return -1; } -void DetectDatasetFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectDatasetFree(DetectEngineCtx *de_ctx, void *ptr) { DetectDatasetData *fd = (DetectDatasetData *)ptr; if (fd == NULL) diff --git a/src/detect-dataset.h b/src/detect-dataset.h index ca83267d1592..a73243158e4b 100644 --- a/src/detect-dataset.h +++ b/src/detect-dataset.h @@ -36,11 +36,10 @@ typedef struct DetectDatasetData_ { uint8_t cmd; } DetectDatasetData; -int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, - const DetectDatasetData *sd, - const uint8_t *data, const uint32_t data_len); +int DetectDatasetBufferMatch(DetectEngineThreadCtx *det_ctx, const DetectDatasetData *sd, + const uint8_t *data, const uint32_t data_len); /* prototypes */ -void DetectDatasetRegister (void); +void DetectDatasetRegister(void); #endif /* __DETECT_DATASET_H__ */ diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index a85248e0afc7..180a43c75db1 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -42,20 +42,21 @@ #include "queue.h" #include "stream-tcp-reassemble.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "stream-tcp.h" #include "rust.h" -#define PARSE_REGEX "^\\s*([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12})(?:\\s*,\\s*(<|>|=|!)([0-9]{1,5}))?(?:\\s*,\\s*(any_frag))?\\s*$" +#define PARSE_REGEX \ + "^\\s*([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12})(?:\\s*," \ + "\\s*(<|>|=|!)([0-9]{1,5}))?(?:\\s*,\\s*(any_frag))?\\s*$" static DetectParseRegex parse_regex; -static int DetectDceIfaceMatchRust(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m); +static int DetectDceIfaceMatchRust(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m); static int DetectDceIfaceSetup(DetectEngineCtx *, Signature *, const char *); static void DetectDceIfaceFree(DetectEngineCtx *, void *); #ifdef UNITTESTS @@ -72,7 +73,7 @@ void DetectDceIfaceRegister(void) sigmatch_table[DETECT_DCE_IFACE].alias = "dce_iface"; sigmatch_table[DETECT_DCE_IFACE].AppLayerTxMatch = DetectDceIfaceMatchRust; sigmatch_table[DETECT_DCE_IFACE].Setup = DetectDceIfaceSetup; - sigmatch_table[DETECT_DCE_IFACE].Free = DetectDceIfaceFree; + sigmatch_table[DETECT_DCE_IFACE].Free = DetectDceIfaceFree; #ifdef UNITTESTS sigmatch_table[DETECT_DCE_IFACE].RegisterTests = DetectDceIfaceRegisterTests; #endif @@ -105,9 +106,8 @@ void DetectDceIfaceRegister(void) * \retval 1 On Match. * \retval 0 On no match. */ -static int DetectDceIfaceMatchRust(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) +static int DetectDceIfaceMatchRust(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) { SCEnter(); @@ -194,6 +194,7 @@ static int DetectDceIfaceTestParse13(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -205,7 +206,9 @@ static int DetectDceIfaceTestParse13(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -217,7 +220,9 @@ static int DetectDceIfaceTestParse13(void) 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -225,7 +230,9 @@ static int DetectDceIfaceTestParse13(void) 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; + // clang-format on + // clang-format off uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -234,7 +241,9 @@ static int DetectDceIfaceTestParse13(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -258,7 +267,9 @@ static int DetectDceIfaceTestParse13(void) 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -267,7 +278,9 @@ static int DetectDceIfaceTestParse13(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, @@ -284,13 +297,16 @@ static int DetectDceIfaceTestParse13(void) 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); diff --git a/src/detect-dce-iface.h b/src/detect-dce-iface.h index edaded404442..0990602d8e34 100644 --- a/src/detect-dce-iface.h +++ b/src/detect-dce-iface.h @@ -18,7 +18,6 @@ #ifndef __DETECT_DCE_IFACE_H__ #define __DETECT_DCE_IFACE_H__ - void DetectDceIfaceRegister(void); #endif /* __DETECT_DCE_IFACE_H__ */ diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 782d33666655..cf8ba556c90a 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -43,20 +43,20 @@ #include "detect-dce-opnum.h" #include "detect-dce-iface.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "stream-tcp.h" #include "rust.h" -#define PARSE_REGEX "^\\s*([0-9]{1,5}(\\s*-\\s*[0-9]{1,5}\\s*)?)(,\\s*[0-9]{1,5}(\\s*-\\s*[0-9]{1,5})?\\s*)*$" +#define PARSE_REGEX \ + "^\\s*([0-9]{1,5}(\\s*-\\s*[0-9]{1,5}\\s*)?)(,\\s*[0-9]{1,5}(\\s*-\\s*[0-9]{1,5})?\\s*)*$" static DetectParseRegex parse_regex; -static int DetectDceOpnumMatchRust(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m); +static int DetectDceOpnumMatchRust(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m); static int DetectDceOpnumSetup(DetectEngineCtx *, Signature *, const char *); static void DetectDceOpnumFree(DetectEngineCtx *, void *); #ifdef UNITTESTS @@ -73,7 +73,7 @@ void DetectDceOpnumRegister(void) sigmatch_table[DETECT_DCE_OPNUM].alias = "dce_opnum"; sigmatch_table[DETECT_DCE_OPNUM].AppLayerTxMatch = DetectDceOpnumMatchRust; sigmatch_table[DETECT_DCE_OPNUM].Setup = DetectDceOpnumSetup; - sigmatch_table[DETECT_DCE_OPNUM].Free = DetectDceOpnumFree; + sigmatch_table[DETECT_DCE_OPNUM].Free = DetectDceOpnumFree; #ifdef UNITTESTS sigmatch_table[DETECT_DCE_OPNUM].RegisterTests = DetectDceOpnumRegisterTests; #endif @@ -96,9 +96,8 @@ void DetectDceOpnumRegister(void) * \retval 1 On Match. * \retval 0 On no match. */ -static int DetectDceOpnumMatchRust(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) +static int DetectDceOpnumMatchRust(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, const SigMatchCtx *m) { SCEnter(); @@ -184,6 +183,7 @@ static int DetectDceOpnumTestParse10(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -195,7 +195,9 @@ static int DetectDceOpnumTestParse10(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -207,7 +209,9 @@ static int DetectDceOpnumTestParse10(void) 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -215,7 +219,9 @@ static int DetectDceOpnumTestParse10(void) 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; + // clang-format on + // clang-format off uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -224,7 +230,9 @@ static int DetectDceOpnumTestParse10(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -248,7 +256,9 @@ static int DetectDceOpnumTestParse10(void) 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -257,7 +267,9 @@ static int DetectDceOpnumTestParse10(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, @@ -274,13 +286,16 @@ static int DetectDceOpnumTestParse10(void) 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); @@ -506,6 +521,7 @@ static int DetectDceOpnumTestParse11(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -513,7 +529,9 @@ static int DetectDceOpnumTestParse11(void) 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; + // clang-format on + // clang-format off uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -522,7 +540,9 @@ static int DetectDceOpnumTestParse11(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -546,7 +566,9 @@ static int DetectDceOpnumTestParse11(void) 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -555,7 +577,9 @@ static int DetectDceOpnumTestParse11(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, @@ -572,13 +596,16 @@ static int DetectDceOpnumTestParse11(void) 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); @@ -769,6 +796,7 @@ static int DetectDceOpnumTestParse12(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -780,7 +808,9 @@ static int DetectDceOpnumTestParse12(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -792,7 +822,9 @@ static int DetectDceOpnumTestParse12(void) 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -815,14 +847,18 @@ static int DetectDceOpnumTestParse12(void) 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00 }; + // clang-format on + // clang-format off uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -836,7 +872,9 @@ static int DetectDceOpnumTestParse12(void) 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65 }; + // clang-format on + // clang-format off uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -857,6 +895,7 @@ static int DetectDceOpnumTestParse12(void) 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); @@ -1083,6 +1122,7 @@ static int DetectDceOpnumTestParse13(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1105,14 +1145,18 @@ static int DetectDceOpnumTestParse13(void) 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00 }; + // clang-format on + // clang-format off uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1126,7 +1170,9 @@ static int DetectDceOpnumTestParse13(void) 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65 }; + // clang-format on + // clang-format off uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1147,6 +1193,7 @@ static int DetectDceOpnumTestParse13(void) 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); diff --git a/src/detect-dce-opnum.h b/src/detect-dce-opnum.h index 1072a60bba62..61120c1f5c3e 100644 --- a/src/detect-dce-opnum.h +++ b/src/detect-dce-opnum.h @@ -24,7 +24,6 @@ #ifndef __DETECT_DCE_OPNUM_H__ #define __DETECT_DCE_OPNUM_H__ - void DetectDceOpnumRegister(void); #endif /* __DETECT_DCE_OPNUM_H__ */ diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index 50d0387b0758..236c941e8d47 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -48,16 +48,16 @@ #include "detect-dce-stub-data.h" #include "detect-dce-iface.h" -#include "util-debug.h" +#include "util/debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "stream-tcp.h" #include "rust.h" -#define BUFFER_NAME "dce_stub_data" +#define BUFFER_NAME "dce_stub_data" #define KEYWORD_NAME "dce_stub_data" static int DetectDceStubDataSetup(DetectEngineCtx *, Signature *, const char *); @@ -67,15 +67,14 @@ static void DetectDceStubDataRegisterTests(void); static int g_dce_stub_data_buffer_id = 0; static InspectionBuffer *GetSMBData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t flow_flags, - void *txv, const int list_id) + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) { InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); if (!buffer->initialized) { uint32_t data_len = 0; const uint8_t *data = NULL; - uint8_t dir = flow_flags & (STREAM_TOSERVER|STREAM_TOCLIENT); + uint8_t dir = flow_flags & (STREAM_TOSERVER | STREAM_TOCLIENT); if (rs_smb_tx_get_stub_data(txv, dir, &data, &data_len) != 1) return NULL; SCLogDebug("have data!"); @@ -87,9 +86,8 @@ static InspectionBuffer *GetSMBData(DetectEngineThreadCtx *det_ctx, } static InspectionBuffer *GetDCEData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t flow_flags, - void *txv, const int list_id) + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, + const int list_id) { InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); if (!buffer->initialized) { @@ -123,37 +121,25 @@ void DetectDceStubDataRegister(void) #ifdef UNITTESTS sigmatch_table[DETECT_DCE_STUB_DATA].RegisterTests = DetectDceStubDataRegisterTests; #endif - sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, - GetSMBData); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetSMBData, - ALPROTO_SMB, 0); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SMB, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, - GetSMBData); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetSMBData, - ALPROTO_SMB, 0); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_DCERPC, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, - GetDCEData); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetDCEData, - ALPROTO_DCERPC, 0); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_DCERPC, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, - GetDCEData); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetDCEData, - ALPROTO_DCERPC, 0); + sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetSMBData); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetSMBData, ALPROTO_SMB, 0); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetSMBData); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetSMBData, ALPROTO_SMB, 0); + + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_DCERPC, SIG_FLAG_TOSERVER, 0, + DetectEngineInspectBufferGeneric, GetDCEData); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetDCEData, ALPROTO_DCERPC, 0); + DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_DCERPC, SIG_FLAG_TOCLIENT, 0, + DetectEngineInspectBufferGeneric, GetDCEData); + DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, + GetDCEData, ALPROTO_DCERPC, 0); g_dce_stub_data_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); } @@ -199,6 +185,7 @@ static int DetectDceStubDataTestParse02(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -210,7 +197,9 @@ static int DetectDceStubDataTestParse02(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -222,9 +211,11 @@ static int DetectDceStubDataTestParse02(void) 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; + // clang-format on /* todo chop the request frag length and change the * length related parameters in the frag */ + // clang-format off uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -641,6 +632,7 @@ static int DetectDceStubDataTestParse02(void) 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x01, 0x02, 0x03, 0x04 }; + // clang-format on uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); @@ -659,7 +651,7 @@ static int DetectDceStubDataTestParse02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(true); @@ -670,20 +662,18 @@ static int DetectDceStubDataTestParse02(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"DCERPC\"; " - "dce_stub_data; content:\"|42 42 42 42|\";" - "sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"DCERPC\"; " + "dce_stub_data; content:\"|42 42 42 42|\";" + "sid:1;)"); if (s == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER | STREAM_START, dcerpc_bind, - dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, + dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; @@ -695,7 +685,7 @@ static int DetectDceStubDataTestParse02(void) goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -705,15 +695,14 @@ static int DetectDceStubDataTestParse02(void) goto end; /* do detect */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT, dcerpc_bindack, - dcerpc_bindack_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -722,15 +711,14 @@ static int DetectDceStubDataTestParse02(void) if (PacketAlertCheck(p, 1)) goto end; - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER | STREAM_EOF, dcerpc_request, - dcerpc_request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, + dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -741,7 +729,7 @@ static int DetectDceStubDataTestParse02(void) result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); @@ -774,6 +762,7 @@ static int DetectDceStubDataTestParse03(void) /* todo chop the request frag length and change the * length related parameters in the frag */ + // clang-format off uint8_t dcerpc_request[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1190,6 +1179,7 @@ static int DetectDceStubDataTestParse03(void) 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x01, 0x02, 0x03, 0x04 }; + // clang-format on uint32_t dcerpc_request_len = sizeof(dcerpc_request); @@ -1207,7 +1197,7 @@ static int DetectDceStubDataTestParse03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(true); @@ -1217,25 +1207,23 @@ static int DetectDceStubDataTestParse03(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"DCERPC\"; " - "dce_stub_data; content:\"|42 42 42 42|\";" - "sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"DCERPC\"; " + "dce_stub_data; content:\"|42 42 42 42|\";" + "sid:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER | STREAM_START, dcerpc_request, - dcerpc_request_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, + dcerpc_request, dcerpc_request_len); FAIL_IF(r != 0); dcerpc_state = f.alstate; - FAIL_IF (dcerpc_state == NULL); + FAIL_IF(dcerpc_state == NULL); - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1265,6 +1253,7 @@ static int DetectDceStubDataTestParse04(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1276,7 +1265,9 @@ static int DetectDceStubDataTestParse04(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_bindack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1288,7 +1279,9 @@ static int DetectDceStubDataTestParse04(void) 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1296,7 +1289,9 @@ static int DetectDceStubDataTestParse04(void) 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; + // clang-format on + // clang-format off uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1305,7 +1300,9 @@ static int DetectDceStubDataTestParse04(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -1329,7 +1326,9 @@ static int DetectDceStubDataTestParse04(void) 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -1338,7 +1337,9 @@ static int DetectDceStubDataTestParse04(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, @@ -1355,13 +1356,16 @@ static int DetectDceStubDataTestParse04(void) 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t dcerpc_bind_len = sizeof(dcerpc_bind); uint32_t dcerpc_bindack_len = sizeof(dcerpc_bindack); @@ -1389,7 +1393,7 @@ static int DetectDceStubDataTestParse04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(true); @@ -1400,15 +1404,18 @@ static int DetectDceStubDataTestParse04(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(msg:\"DCERPC\"; dce_stub_data; content:\"|00 02|\"; sid:1;)"); if (s == NULL) goto end; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(msg:\"DCERPC\"; dce_stub_data; content:\"|00 75|\"; sid:2;)"); if (s == NULL) goto end; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " "(msg:\"DCERPC\"; dce_stub_data; content:\"|00 18|\"; sid:3;)"); if (s == NULL) goto end; @@ -1416,14 +1423,13 @@ static int DetectDceStubDataTestParse04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER | STREAM_START, dcerpc_bind, - dcerpc_bind_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, + dcerpc_bind, dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1433,27 +1439,25 @@ static int DetectDceStubDataTestParse04(void) goto end; } - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT, dcerpc_bindack, - dcerpc_bindack_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* request1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, dcerpc_request1, - dcerpc_request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, + dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1462,15 +1466,14 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT, dcerpc_response1, - dcerpc_response1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, + dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1479,15 +1482,14 @@ static int DetectDceStubDataTestParse04(void) goto end; /* request2 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, dcerpc_request2, - dcerpc_request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, + dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1496,15 +1498,14 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response2 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT, dcerpc_response2, - dcerpc_response2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, + dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1512,15 +1513,14 @@ static int DetectDceStubDataTestParse04(void) if (PacketAlertCheck(p, 1) || PacketAlertCheck(p, 2) || PacketAlertCheck(p, 3)) goto end; /* request3 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, dcerpc_request3, - dcerpc_request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, + dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1529,15 +1529,14 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response3 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, - dcerpc_response3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, + dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1547,7 +1546,7 @@ static int DetectDceStubDataTestParse04(void) result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); @@ -1576,6 +1575,7 @@ static int DetectDceStubDataTestParse05(void) DCERPCState *dcerpc_state = NULL; int r = 0; + // clang-format off uint8_t dcerpc_request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1583,7 +1583,9 @@ static int DetectDceStubDataTestParse05(void) 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, }; + // clang-format on + // clang-format off uint8_t dcerpc_response1[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -1592,7 +1594,9 @@ static int DetectDceStubDataTestParse05(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request2[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -1616,7 +1620,9 @@ static int DetectDceStubDataTestParse05(void) 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response2[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -1625,7 +1631,9 @@ static int DetectDceStubDataTestParse05(void) 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_request3[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, @@ -1642,13 +1650,16 @@ static int DetectDceStubDataTestParse05(void) 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }; + // clang-format on + // clang-format off uint8_t dcerpc_response3[] = { 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t dcerpc_request1_len = sizeof(dcerpc_request1); uint32_t dcerpc_response1_len = sizeof(dcerpc_response1); @@ -1673,7 +1684,7 @@ static int DetectDceStubDataTestParse05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_DCERPC; StreamTcpInitConfig(true); @@ -1684,25 +1695,22 @@ static int DetectDceStubDataTestParse05(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"DCERPC\"; " - "dce_stub_data; content:\"|00 02|\"; " - "sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"DCERPC\"; " + "dce_stub_data; content:\"|00 02|\"; " + "sid:1;)"); if (s == NULL) goto end; - s = de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"DCERPC\"; " - "dce_stub_data; content:\"|00 75|\"; " - "sid:2;)"); + s = de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"DCERPC\"; " + "dce_stub_data; content:\"|00 75|\"; " + "sid:2;)"); if (s == NULL) goto end; - s = de_ctx->sig_list->next->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"DCERPC\"; " - "dce_stub_data; content:\"|00 18|\"; " - "sid:3;)"); + s = de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"DCERPC\"; " + "dce_stub_data; content:\"|00 18|\"; " + "sid:3;)"); if (s == NULL) goto end; @@ -1710,9 +1718,8 @@ static int DetectDceStubDataTestParse05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER | STREAM_START, dcerpc_request1, - dcerpc_request1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, + dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; @@ -1724,7 +1731,7 @@ static int DetectDceStubDataTestParse05(void) goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1733,15 +1740,14 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT, dcerpc_response1, - dcerpc_response1_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, + dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1750,15 +1756,14 @@ static int DetectDceStubDataTestParse05(void) goto end; /* request2 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, dcerpc_request2, - dcerpc_request2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, + dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1767,15 +1772,14 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response2 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT, dcerpc_response2, - dcerpc_response2_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, + dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1784,15 +1788,14 @@ static int DetectDceStubDataTestParse05(void) goto end; /* request3 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, dcerpc_request3, - dcerpc_request3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, + dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOCLIENT; + p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1801,15 +1804,14 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response3 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, - dcerpc_response3_len); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, + dcerpc_response3, dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); goto end; } - p->flowflags &=~ FLOW_PKT_TOSERVER; + p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1819,7 +1821,7 @@ static int DetectDceStubDataTestParse05(void) result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -1842,8 +1844,8 @@ static int DetectDceStubDataTestParse06(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); de_ctx->flags = DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert dns any any -> any any dce_stub_data;content:\"0\";"); + Signature *s = DetectEngineAppendSig( + de_ctx, "alert dns any any -> any any dce_stub_data;content:\"0\";"); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); PASS; @@ -1851,15 +1853,10 @@ static int DetectDceStubDataTestParse06(void) static void DetectDceStubDataRegisterTests(void) { - UtRegisterTest("DetectDceStubDataTestParse02", - DetectDceStubDataTestParse02); - UtRegisterTest("DetectDceStubDataTestParse03", - DetectDceStubDataTestParse03); - UtRegisterTest("DetectDceStubDataTestParse04", - DetectDceStubDataTestParse04); - UtRegisterTest("DetectDceStubDataTestParse05", - DetectDceStubDataTestParse05); - UtRegisterTest("DetectDceStubDataTestParse06", - DetectDceStubDataTestParse06); + UtRegisterTest("DetectDceStubDataTestParse02", DetectDceStubDataTestParse02); + UtRegisterTest("DetectDceStubDataTestParse03", DetectDceStubDataTestParse03); + UtRegisterTest("DetectDceStubDataTestParse04", DetectDceStubDataTestParse04); + UtRegisterTest("DetectDceStubDataTestParse05", DetectDceStubDataTestParse05); + UtRegisterTest("DetectDceStubDataTestParse06", DetectDceStubDataTestParse06); } #endif diff --git a/src/detect-dce-stub-data.h b/src/detect-dce-stub-data.h index 035fa258a558..80c82145c0e8 100644 --- a/src/detect-dce-stub-data.h +++ b/src/detect-dce-stub-data.h @@ -24,7 +24,6 @@ #ifndef __DETECT_DCE_STUB_DATA_H__ #define __DETECT_DCE_STUB_DATA_H__ - void DetectDceStubDataRegister(void); #endif /* __DETECT_DCE_STUB_DATA_H__ */ diff --git a/src/detect-depth.c b/src/detect-depth.c index 1c4f94a396f0..80c47cc47eef 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -39,29 +39,31 @@ #include "flow-var.h" #include "app-layer.h" -#include "util-byte.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/debug.h" -static int DetectDepthSetup (DetectEngineCtx *, Signature *, const char *); -static int DetectStartsWithSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectDepthSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectStartsWithSetup(DetectEngineCtx *, Signature *, const char *); -void DetectDepthRegister (void) +void DetectDepthRegister(void) { sigmatch_table[DETECT_DEPTH].name = "depth"; - sigmatch_table[DETECT_DEPTH].desc = "designate how many bytes from the beginning of the payload will be checked"; + sigmatch_table[DETECT_DEPTH].desc = + "designate how many bytes from the beginning of the payload will be checked"; sigmatch_table[DETECT_DEPTH].url = "/rules/payload-keywords.html#depth"; sigmatch_table[DETECT_DEPTH].Match = NULL; sigmatch_table[DETECT_DEPTH].Setup = DetectDepthSetup; - sigmatch_table[DETECT_DEPTH].Free = NULL; + sigmatch_table[DETECT_DEPTH].Free = NULL; sigmatch_table[DETECT_STARTS_WITH].name = "startswith"; - sigmatch_table[DETECT_STARTS_WITH].desc = "pattern must be at the start of a buffer (same as 'depth:')"; + sigmatch_table[DETECT_STARTS_WITH].desc = + "pattern must be at the start of a buffer (same as 'depth:')"; sigmatch_table[DETECT_STARTS_WITH].url = "/rules/payload-keywords.html#startswith"; sigmatch_table[DETECT_STARTS_WITH].Setup = DetectStartsWithSetup; sigmatch_table[DETECT_STARTS_WITH].flags |= SIGMATCH_NOOPT; } -static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, const char *depthstr) +static int DetectDepthSetup(DetectEngineCtx *de_ctx, Signature *s, const char *depthstr) { const char *str = depthstr; SigMatch *pm = NULL; @@ -115,8 +117,7 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, const char * cd->depth = index; cd->flags |= DETECT_CONTENT_DEPTH_VAR; } else { - if (StringParseUint16(&cd->depth, 0, 0, str) < 0) - { + if (StringParseUint16(&cd->depth, 0, 0, str) < 0) { SCLogError("invalid value for depth: %s.", str); goto end; } @@ -133,11 +134,11 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, const char * cd->flags |= DETECT_CONTENT_DEPTH; ret = 0; - end: +end: return ret; } -static int DetectStartsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *unused) +static int DetectStartsWithSetup(DetectEngineCtx *de_ctx, Signature *s, const char *unused) { SigMatch *pm = NULL; int ret = -1; @@ -186,6 +187,6 @@ static int DetectStartsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const c cd->flags |= DETECT_CONTENT_STARTS_WITH; ret = 0; - end: +end: return ret; } diff --git a/src/detect-depth.h b/src/detect-depth.h index b864f62175d8..c7e54858ce61 100644 --- a/src/detect-depth.h +++ b/src/detect-depth.h @@ -25,7 +25,6 @@ #define __DETECT_DEPTH_H__ /* prototypes */ -void DetectDepthRegister (void); +void DetectDepthRegister(void); #endif /* __DETECT_DEPTH_H__ */ - diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index cbd1898a31a4..441f93fe0ec0 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -34,10 +34,10 @@ #include "detect-threshold.h" #include "detect-parse.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" #include "detect-engine-build.h" #define TRACK_DST 1 @@ -271,8 +271,8 @@ static void DetectDetectionFilterFree(DetectEngineCtx *de_ctx, void *df_ptr) #include "detect-engine-mpm.h" #include "detect-engine-threshold.h" #include "detect-engine-alert.h" -#include "util-time.h" -#include "util-hashlist.h" +#include "util/time.h" +#include "util/hashlist.h" #include "action-globals.h" #include "packet.h" diff --git a/src/detect-detection-filter.h b/src/detect-detection-filter.h index f136d3aca5f9..787ed48f1a83 100644 --- a/src/detect-detection-filter.h +++ b/src/detect-detection-filter.h @@ -28,7 +28,6 @@ * Registration function for detection_filter: keyword */ -void DetectDetectionFilterRegister (void); +void DetectDetectionFilterRegister(void); #endif /*__DETECT_DETECTION_FILTER_H__ */ - diff --git a/src/detect-dhcp-leasetime.c b/src/detect-dhcp-leasetime.c deleted file mode 100644 index fea0d108fd58..000000000000 --- a/src/detect-dhcp-leasetime.c +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "rust.h" -#include "detect-dhcp-leasetime.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-uint.h" -#include "detect-parse.h" - -static int g_buffer_id = 0; - -/** - * \internal - * \brief Function to match leasetime of a TX - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectU64Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectDHCPLeaseTimeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint64_t leasetime; - if (rs_dhcp_tx_get_leasetime(txv, &leasetime)) { - const DetectU64Data *dd = (const DetectU64Data *)ctx; - if (DetectU64Match(leasetime, dd)) { - SCReturnInt(1); - } - } - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to free memory associated with DetectU64Data. - * - * \param de_ptr Pointer to DetectU64Data. - */ -static void DetectDHCPLeaseTimeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u64_free(ptr); -} - -/** - * \brief Function to add the parsed dhcp leasetime field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectDHCPLeaseTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_DHCP) != 0) - return -1; - - DetectU64Data *dd = DetectU64Parse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed for %s", rawstr, - sigmatch_table[DETECT_AL_DHCP_LEASETIME].name); - return -1; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_AL_DHCP_LEASETIME, (SigMatchCtx *)dd, g_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectDHCPLeaseTimeFree(de_ctx, dd); - return -1; -} - -/** - * \brief Registration function for dhcp.procedure keyword. - */ -void DetectDHCPLeaseTimeRegister(void) -{ - sigmatch_table[DETECT_AL_DHCP_LEASETIME].name = "dhcp.leasetime"; - sigmatch_table[DETECT_AL_DHCP_LEASETIME].desc = "match DHCP leasetime"; - sigmatch_table[DETECT_AL_DHCP_LEASETIME].url = "/rules/dhcp-keywords.html#dhcp-leasetime"; - sigmatch_table[DETECT_AL_DHCP_LEASETIME].AppLayerTxMatch = DetectDHCPLeaseTimeMatch; - sigmatch_table[DETECT_AL_DHCP_LEASETIME].Setup = DetectDHCPLeaseTimeSetup; - sigmatch_table[DETECT_AL_DHCP_LEASETIME].Free = DetectDHCPLeaseTimeFree; - - DetectAppLayerInspectEngineRegister2("dhcp.leasetime", ALPROTO_DHCP, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("dhcp.leasetime", ALPROTO_DHCP, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - g_buffer_id = DetectBufferTypeGetByName("dhcp.leasetime"); -} diff --git a/src/detect-dhcp-rebinding-time.c b/src/detect-dhcp-rebinding-time.c deleted file mode 100644 index 8d546376a394..000000000000 --- a/src/detect-dhcp-rebinding-time.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "rust.h" -#include "detect-dhcp-rebinding-time.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-uint.h" -#include "detect-parse.h" - -static int g_buffer_id = 0; - -/** - * \internal - * \brief Function to match rebinding time of a TX - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectU64Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectDHCPRebindingTimeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint64_t res; - if (rs_dhcp_tx_get_rebinding_time(txv, &res)) { - const DetectU64Data *dd = (const DetectU64Data *)ctx; - if (DetectU64Match(res, dd)) { - SCReturnInt(1); - } - } - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to free memory associated with DetectU64Data. - * - * \param de_ptr Pointer to DetectU64Data. - */ -static void DetectDHCPRebindingTimeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u64_free(ptr); -} - -/** - * \brief Function to add the parsed dhcp rebinding time field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectDHCPRebindingTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_DHCP) != 0) - return -1; - - DetectU64Data *dd = DetectU64Parse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed for %s", rawstr, - sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].name); - return -1; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_AL_DHCP_REBINDING_TIME, (SigMatchCtx *)dd, g_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectDHCPRebindingTimeFree(de_ctx, dd); - return -1; -} - -/** - * \brief Registration function for dhcp.procedure keyword. - */ -void DetectDHCPRebindingTimeRegister(void) -{ - sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].name = "dhcp.rebinding_time"; - sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].desc = "match DHCP rebinding time"; - sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].url = - "/rules/dhcp-keywords.html#dhcp-rebinding-time"; - sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].AppLayerTxMatch = DetectDHCPRebindingTimeMatch; - sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].Setup = DetectDHCPRebindingTimeSetup; - sigmatch_table[DETECT_AL_DHCP_REBINDING_TIME].Free = DetectDHCPRebindingTimeFree; - - DetectAppLayerInspectEngineRegister2("dhcp.rebinding-time", ALPROTO_DHCP, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("dhcp.rebinding-time", ALPROTO_DHCP, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - g_buffer_id = DetectBufferTypeGetByName("dhcp.rebinding-time"); -} diff --git a/src/detect-dhcp-renewal-time.c b/src/detect-dhcp-renewal-time.c deleted file mode 100644 index 20ee763d9b90..000000000000 --- a/src/detect-dhcp-renewal-time.c +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "rust.h" -#include "detect-dhcp-renewal-time.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-uint.h" -#include "detect-parse.h" - -static int g_buffer_id = 0; - -/** - * \internal - * \brief Function to match renewal time of a TX - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectU64Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectDHCPRenewalTimeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint64_t res; - if (rs_dhcp_tx_get_renewal_time(txv, &res)) { - const DetectU64Data *dd = (const DetectU64Data *)ctx; - if (DetectU64Match(res, dd)) { - SCReturnInt(1); - } - } - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to free memory associated with DetectU64Data. - * - * \param de_ptr Pointer to DetectU64Data. - */ -static void DetectDHCPRenewalTimeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u64_free(ptr); -} - -/** - * \brief Function to add the parsed dhcp renewal time field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectDHCPRenewalTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_DHCP) != 0) - return -1; - - DetectU64Data *dd = DetectU64Parse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed for %s", rawstr, - sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].name); - return -1; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_AL_DHCP_RENEWAL_TIME, (SigMatchCtx *)dd, g_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectDHCPRenewalTimeFree(de_ctx, dd); - return -1; -} - -/** - * \brief Registration function for dhcp.procedure keyword. - */ -void DetectDHCPRenewalTimeRegister(void) -{ - sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].name = "dhcp.renewal_time"; - sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].desc = "match DHCP renewal time"; - sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].url = "/rules/dhcp-keywords.html#dhcp-renewal-time"; - sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].AppLayerTxMatch = DetectDHCPRenewalTimeMatch; - sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].Setup = DetectDHCPRenewalTimeSetup; - sigmatch_table[DETECT_AL_DHCP_RENEWAL_TIME].Free = DetectDHCPRenewalTimeFree; - - DetectAppLayerInspectEngineRegister2("dhcp.renewal-time", ALPROTO_DHCP, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("dhcp.renewal-time", ALPROTO_DHCP, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - g_buffer_id = DetectBufferTypeGetByName("dhcp.renewal-time"); -} diff --git a/src/detect-distance.c b/src/detect-distance.c index 1ed66b1245f0..fdc4e34e7326 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -42,11 +42,11 @@ #include "flow-var.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/unittest.h" #include "detect-bytejump.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" static int DetectDistanceSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS @@ -56,18 +56,18 @@ static void DetectDistanceRegisterTests(void); void DetectDistanceRegister(void) { sigmatch_table[DETECT_DISTANCE].name = "distance"; - sigmatch_table[DETECT_DISTANCE].desc = "indicates a relation between this content keyword and the content preceding it"; + sigmatch_table[DETECT_DISTANCE].desc = + "indicates a relation between this content keyword and the content preceding it"; sigmatch_table[DETECT_DISTANCE].url = "/rules/payload-keywords.html#distance"; sigmatch_table[DETECT_DISTANCE].Match = NULL; sigmatch_table[DETECT_DISTANCE].Setup = DetectDistanceSetup; - sigmatch_table[DETECT_DISTANCE].Free = NULL; + sigmatch_table[DETECT_DISTANCE].Free = NULL; #ifdef UNITTESTS sigmatch_table[DETECT_DISTANCE].RegisterTests = DetectDistanceRegisterTests; #endif } -static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *distancestr) +static int DetectDistanceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *distancestr) { const char *str = distancestr; @@ -125,8 +125,7 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } cd->flags |= DETECT_CONTENT_DISTANCE; - SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, - DETECT_CONTENT, DETECT_PCRE, -1); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, DETECT_CONTENT, DETECT_PCRE, -1); if (prev_pm == NULL) { return 0; } @@ -190,7 +189,7 @@ static int DetectDistanceTest01(void) * distance works, if the previous keyword is byte_jump and content * (bug 163) */ -static int DetectDistanceTestPacket01 (void) +static int DetectDistanceTestPacket01(void) { uint8_t buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint16_t buflen = sizeof(buf); @@ -198,8 +197,8 @@ static int DetectDistanceTestPacket01 (void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"suricata test\"; " - "byte_jump:1,2; content:\"|00|\"; " - "within:1; distance:2; sid:98711212; rev:1;)"; + "byte_jump:1,2; content:\"|00|\"; " + "within:1; distance:2; sid:98711212; rev:1;)"; p->flowflags = FLOW_PKT_ESTABLISHED | FLOW_PKT_TOCLIENT; FAIL_IF_NOT(UTHPacketMatchSig(p, sig)); @@ -211,8 +210,7 @@ static int DetectDistanceTestPacket01 (void) static void DetectDistanceRegisterTests(void) { - UtRegisterTest("DetectDistanceTest01 -- distance / within mix", - DetectDistanceTest01); + UtRegisterTest("DetectDistanceTest01 -- distance / within mix", DetectDistanceTest01); UtRegisterTest("DetectDistanceTestPacket01", DetectDistanceTestPacket01); } #endif /* UNITTESTS */ diff --git a/src/detect-distance.h b/src/detect-distance.h index 80aebe4f71e2..b135cf403b1d 100644 --- a/src/detect-distance.h +++ b/src/detect-distance.h @@ -25,7 +25,6 @@ #define __DETECT_DISTANCE_H__ /* prototypes */ -void DetectDistanceRegister (void); +void DetectDistanceRegister(void); #endif /* __DETECT_DISTANCE_H__ */ - diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c deleted file mode 100644 index 6d92596c1d73..000000000000 --- a/src/detect-dnp3.c +++ /dev/null @@ -1,732 +0,0 @@ -/* Copyright (C) 2015-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" - -#include "stream.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-dnp3.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "app-layer-dnp3.h" -#include "util-byte.h" - -static int g_dnp3_match_buffer_id = 0; -static int g_dnp3_data_buffer_id = 0; - -/** - * The detection struct. - */ -typedef struct DetectDNP3_ { - union { - struct { - /* Function code for function code detection. */ - uint8_t function_code; - }; - struct { - /* Internal indicator flags for IIN detection. */ - uint16_t ind_flags; - }; - struct { - /* Object info for object detection. */ - uint8_t obj_group; - uint8_t obj_variation; - }; - }; -} DetectDNP3; - -/** - * Indicator names to value mappings (Snort compatible). - */ -DNP3Mapping DNP3IndicatorsMap[] = { - {"device_restart", 0x8000}, - {"device_trouble", 0x4000}, - {"local_control", 0x2000}, - {"need_time", 0x1000}, - {"class_3_events", 0x0800}, - {"class_2_events", 0x0400}, - {"class_1_events", 0x0200}, - {"all_stations", 0x0100}, - - {"reserved_1", 0x0080}, - {"reserved_2", 0x0040}, - {"config_corrupt", 0x0020}, - {"already_executing", 0x0010}, - {"event_buffer_overflow", 0x0008}, - {"parameter_error", 0x0004}, - {"object_unknown", 0x0002}, - {"no_func_code_support", 0x0001}, - - {NULL, 0}, -}; - -/** - * Application function code name to code mappings (Snort compatible). - */ -DNP3Mapping DNP3FunctionNameMap[] = { - {"confirm", 0}, - {"read", 1}, - {"write", 2}, - {"select", 3}, - {"operate", 4}, - {"direct_operate", 5}, - {"direct_operate_nr", 6}, - {"immed_freeze", 7}, - {"immed_freeze_nr", 8}, - {"freeze_clear", 9}, - {"freeze_clear_nr", 10}, - {"freeze_at_time", 11}, - {"freeze_at_time_nr", 12}, - {"cold_restart", 13}, - {"warm_restart", 14}, - {"initialize_data", 15}, - {"initialize_appl", 16}, - {"start_appl", 17}, - {"stop_appl", 18}, - {"save_config", 19}, - {"enable_unsolicited", 20}, - {"disable_unsolicited", 21}, - {"assign_class", 22}, - {"delay_measure", 23}, - {"record_current_time", 24}, - {"open_file", 25}, - {"close_file", 26}, - {"delete_file", 27}, - {"get_file_info", 28}, - {"authenticate_file", 29}, - {"abort_file", 30}, - {"activate_config", 31}, - {"authenticate_req", 32}, - {"authenticate_err", 33}, - {"response", 129}, - {"unsolicited_response", 130}, - {"authenticate_resp", 131} -}; - -#ifdef UNITTESTS -static void DetectDNP3FuncRegisterTests(void); -static void DetectDNP3IndRegisterTests(void); -static void DetectDNP3ObjRegisterTests(void); -#endif - -/** - * \brief Utility function to trim leading and trailing whitespace - * from a string. - */ -static char *TrimString(char *str) -{ - char *end = str + strlen(str) - 1; - while (isspace(*str)) { - str++; - } - while (end > str && isspace(*end)) { - end--; - } - *(end + 1) = '\0'; - return str; -} - -static InspectionBuffer *GetDNP3Data(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t flow_flags, - void *txv, const int list_id) -{ - SCLogDebug("list_id %d", list_id); - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - DNP3Transaction *tx = (DNP3Transaction *)txv; - SCLogDebug("tx %p", tx); - - if ((flow_flags & STREAM_TOSERVER && !tx->is_request) || - (flow_flags & STREAM_TOCLIENT && tx->is_request)) { - return NULL; - } - - if (tx->buffer == NULL || tx->buffer_len == 0) { - return NULL; - } - - SCLogDebug("tx %p data %p data_len %u", tx, tx->buffer, tx->buffer_len); - InspectionBufferSetup(det_ctx, list_id, buffer, tx->buffer, tx->buffer_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -/** - * \brief Parse the provided function name or code to its integer - * value. - * - * If the value passed is a number, it will be checked that it falls - * within the range of valid function codes. If function name is - * passed it will be resolved to its function code. - * - * \retval The function code as an integer if successful, -1 on - * failure. - */ -static int DetectDNP3FuncParseFunctionCode(const char *str, uint8_t *fc) -{ - if (StringParseUint8(fc, 10, (uint16_t)strlen(str), str) >= 0) { - return 1; - } - - /* Lookup by name. */ - for (size_t i = 0; - i < sizeof(DNP3FunctionNameMap) / sizeof(DNP3Mapping); i++) { - if (strcasecmp(str, DNP3FunctionNameMap[i].name) == 0) { - *fc = (uint8_t)(DNP3FunctionNameMap[i].value); - return 1; - } - } - - return 0; -} - -static int DetectDNP3FuncSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - SCEnter(); - DetectDNP3 *dnp3 = NULL; - uint8_t function_code; - - if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) - return -1; - - if (!DetectDNP3FuncParseFunctionCode(str, &function_code)) { - SCLogError("Invalid argument \"%s\" supplied to dnp3_func keyword.", str); - return -1; - } - - dnp3 = SCCalloc(1, sizeof(DetectDNP3)); - if (unlikely(dnp3 == NULL)) { - goto error; - } - dnp3->function_code = function_code; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNP3FUNC, (SigMatchCtx *)dnp3, - g_dnp3_match_buffer_id) == NULL) { - goto error; - } - - SCReturnInt(0); -error: - if (dnp3 != NULL) { - SCFree(dnp3); - } - SCReturnInt(-1); -} - -static int DetectDNP3IndParseByName(const char *str, uint16_t *flags) -{ - char tmp[strlen(str) + 1]; - char *p, *last = NULL; - - strlcpy(tmp, str, sizeof(tmp)); - - for ((p = strtok_r(tmp, ",", &last)); p; (p = strtok_r(NULL, ",", &last))) { - p = TrimString(p); - int found = 0; - int i = 0; - while (DNP3IndicatorsMap[i].name != NULL) { - if (strcasecmp(p, DNP3IndicatorsMap[i].name) == 0) { - *flags |= DNP3IndicatorsMap[i].value; - found = 1; - break; - } - i++; - } - - if (!found) { - SCLogError("Bad argument \"%s\" supplied to dnp3.ind keyword.", p); - return 0; - } - } - - return 1; -} - -static int DetectDNP3IndParse(const char *str, uint16_t *flags) -{ - *flags = 0; - - if (StringParseUint16(flags, 0, (uint16_t)strlen(str), str) > 0) { - return 1; - } - - /* Parse by name - will log a more specific error message on error. */ - if (DetectDNP3IndParseByName(str, flags)) { - return 1; - } - - return 0; -} - -static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - SCEnter(); - DetectDNP3 *detect = NULL; - uint16_t flags; - - if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) - return -1; - - if (!DetectDNP3IndParse(str, &flags)) { - SCLogError("Invalid argument \"%s\" supplied to dnp3.ind keyword.", str); - return -1; - } - - detect = SCCalloc(1, sizeof(DetectDNP3)); - if (unlikely(detect == NULL)) { - goto error; - } - detect->ind_flags = flags; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNP3IND, (SigMatchCtx *)detect, - g_dnp3_match_buffer_id) == NULL) { - goto error; - } - - SCReturnInt(0); -error: - if (detect != NULL) { - SCFree(detect); - } - SCReturnInt(-1); -} - -/** - * \brief Parse the value of string of the dnp3_obj keyword. - * - * \param str the input string - * \param gout pointer to variable to store the parsed group integer - * \param vout pointer to variable to store the parsed variation integer - * - * \retval 1 if parsing successful otherwise 0. - */ -static int DetectDNP3ObjParse(const char *str, uint8_t *group, uint8_t *var) -{ - size_t size = strlen(str) + 1; - char groupstr[size], *varstr, *sep; - strlcpy(groupstr, str, size); - - sep = strchr(groupstr, ','); - if (sep == NULL) { - return 0; - } - *sep = '\0'; - varstr = sep + 1; - - if (StringParseUint8(group, 0, (uint16_t)strlen(groupstr), groupstr) < 0) { - return 0; - } - - if (StringParseUint8(var, 0, (uint16_t)strlen(varstr), varstr) < 0) { - return 0; - } - - return 1; -} - -static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - SCEnter(); - uint8_t group; - uint8_t variation; - DetectDNP3 *detect = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) - return -1; - - if (!DetectDNP3ObjParse(str, &group, &variation)) { - goto fail; - } - - detect = SCCalloc(1, sizeof(*detect)); - if (unlikely(detect == NULL)) { - goto fail; - } - detect->obj_group = group; - detect->obj_variation = variation; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNP3OBJ, (SigMatchCtx *)detect, - g_dnp3_match_buffer_id) == NULL) { - goto fail; - } - - SCReturnInt(1); -fail: - if (detect != NULL) { - SCFree(detect); - } - SCReturnInt(0); -} - -static void DetectDNP3Free(DetectEngineCtx *de_ctx, void *ptr) -{ - SCEnter(); - if (ptr != NULL) { - SCFree(ptr); - } - SCReturn; -} - -static int DetectDNP3FuncMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - DNP3Transaction *tx = (DNP3Transaction *)txv; - DetectDNP3 *detect = (DetectDNP3 *)ctx; - int match = 0; - - if (flags & STREAM_TOSERVER && tx->is_request) { - match = detect->function_code == tx->ah.function_code; - } else if (flags & STREAM_TOCLIENT && !tx->is_request) { - match = detect->function_code == tx->ah.function_code; - } - - return match; -} - -static int DetectDNP3ObjMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - DNP3Transaction *tx = (DNP3Transaction *)txv; - DetectDNP3 *detect = (DetectDNP3 *)ctx; - DNP3ObjectList *objects = NULL; - - if (flags & STREAM_TOSERVER && tx->is_request) { - objects = &tx->objects; - } else if (flags & STREAM_TOCLIENT && !tx->is_request) { - objects = &tx->objects; - } - - if (objects != NULL) { - DNP3Object *object; - TAILQ_FOREACH(object, objects, next) { - if (object->group == detect->obj_group && - object->variation == detect->obj_variation) { - return 1; - } - } - } - - return 0; -} - -static int DetectDNP3IndMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - DNP3Transaction *tx = (DNP3Transaction *)txv; - DetectDNP3 *detect = (DetectDNP3 *)ctx; - - if (flags & STREAM_TOCLIENT) { - if ((tx->iin.iin1 & (detect->ind_flags >> 8)) || - (tx->iin.iin2 & (detect->ind_flags & 0xf))) { - return 1; - } - } - - return 0; -} - -static void DetectDNP3FuncRegister(void) -{ - SCEnter(); - - sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3_func"; - sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3.func"; - sigmatch_table[DETECT_AL_DNP3FUNC].desc = "match on the application function code found in DNP3 request and responses"; - sigmatch_table[DETECT_AL_DNP3FUNC].url = "/rules/dnp3-keywords.html#dnp3-func"; - sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL; - sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerTxMatch = DetectDNP3FuncMatch; - sigmatch_table[DETECT_AL_DNP3FUNC].Setup = DetectDNP3FuncSetup; - sigmatch_table[DETECT_AL_DNP3FUNC].Free = DetectDNP3Free; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_DNP3FUNC].RegisterTests = - DetectDNP3FuncRegisterTests; -#endif - SCReturn; -} - -static void DetectDNP3IndRegister(void) -{ - SCEnter(); - - sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3_ind"; - sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3.ind"; - sigmatch_table[DETECT_AL_DNP3IND].desc = "match on the DNP3 internal indicator flags in the response application header"; - sigmatch_table[DETECT_AL_DNP3IND].url = "/rules/dnp3-keywords.html#dnp3-ind"; - sigmatch_table[DETECT_AL_DNP3IND].Match = NULL; - sigmatch_table[DETECT_AL_DNP3IND].AppLayerTxMatch = DetectDNP3IndMatch; - sigmatch_table[DETECT_AL_DNP3IND].Setup = DetectDNP3IndSetup; - sigmatch_table[DETECT_AL_DNP3IND].Free = DetectDNP3Free; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_DNP3IND].RegisterTests = - DetectDNP3IndRegisterTests; -#endif - SCReturn; -} - -static void DetectDNP3ObjRegister(void) -{ - SCEnter(); - - sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3_obj"; - sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3.obj"; - sigmatch_table[DETECT_AL_DNP3OBJ].desc = "match on the DNP3 application data objects"; - sigmatch_table[DETECT_AL_DNP3OBJ].url = "/rules/dnp3-keywords.html#dnp3-obj"; - sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL; - sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerTxMatch = DetectDNP3ObjMatch; - sigmatch_table[DETECT_AL_DNP3OBJ].Setup = DetectDNP3ObjSetup; - sigmatch_table[DETECT_AL_DNP3OBJ].Free = DetectDNP3Free; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_DNP3OBJ].RegisterTests = - DetectDNP3ObjRegisterTests; -#endif - SCReturn; -} - -static int DetectDNP3DataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - SCEnter(); - if (DetectSignatureSetAppProto(s, ALPROTO_DNP3) != 0) - return -1; - - if (DetectBufferSetActiveList(de_ctx, s, g_dnp3_data_buffer_id) != 0) - return -1; - - SCReturnInt(0); -} - -static void DetectDNP3DataRegister(void) -{ - SCEnter(); - - sigmatch_table[DETECT_AL_DNP3DATA].name = "dnp3.data"; - sigmatch_table[DETECT_AL_DNP3DATA].alias = "dnp3_data"; - sigmatch_table[DETECT_AL_DNP3DATA].desc = "make the following content options to match on the re-assembled application buffer"; - sigmatch_table[DETECT_AL_DNP3DATA].url = "/rules/dnp3-keywords.html#dnp3-data"; - sigmatch_table[DETECT_AL_DNP3DATA].Setup = DetectDNP3DataSetup; - sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("dnp3_data", - ALPROTO_DNP3, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, - GetDNP3Data); - DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetDNP3Data, - ALPROTO_DNP3, 0); - - DetectAppLayerInspectEngineRegister2("dnp3_data", - ALPROTO_DNP3, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, - GetDNP3Data); - DetectAppLayerMpmRegister2("dnp3_data", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetDNP3Data, - ALPROTO_DNP3, 0); - - g_dnp3_data_buffer_id = DetectBufferTypeGetByName("dnp3_data"); - SCReturn; -} - -void DetectDNP3Register(void) -{ - DetectDNP3DataRegister(); - - DetectDNP3FuncRegister(); - DetectDNP3IndRegister(); - DetectDNP3ObjRegister(); - - /* Register the list of func, ind and obj. */ - DetectAppLayerInspectEngineRegister2( - "dnp3", ALPROTO_DNP3, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - DetectAppLayerInspectEngineRegister2( - "dnp3", ALPROTO_DNP3, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); - - g_dnp3_match_buffer_id = DetectBufferTypeRegister("dnp3"); - -} - -#ifdef UNITTESTS - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "app-layer-parser.h" -#include "flow-util.h" -#include "stream-tcp.h" - -static int DetectDNP3FuncParseFunctionCodeTest(void) -{ - uint8_t fc; - - /* Valid. */ - FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("0", &fc)); - FAIL_IF(fc != 0); - - FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("1", &fc)); - FAIL_IF(fc != 1); - - FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("254", &fc)); - FAIL_IF(fc != 254); - - FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("255", &fc)); - FAIL_IF(fc != 255); - - FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("confirm", &fc)); - FAIL_IF(fc != 0); - - FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("CONFIRM", &fc)); - FAIL_IF(fc != 0); - - /* Invalid. */ - FAIL_IF(DetectDNP3FuncParseFunctionCode("", &fc)); - FAIL_IF(DetectDNP3FuncParseFunctionCode("-1", &fc)); - FAIL_IF(DetectDNP3FuncParseFunctionCode("-2", &fc)); - FAIL_IF(DetectDNP3FuncParseFunctionCode("256", &fc)); - FAIL_IF(DetectDNP3FuncParseFunctionCode("unknown_function_code", &fc)); - - PASS; -} - -static int DetectDNP3FuncTest01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *s = DetectEngineAppendSig(de_ctx, "alert dnp3 any any -> any any " - "(msg:\"SURICATA DNP3 Write request\"; " - "dnp3_func:2; sid:5000009; rev:1;)"); - FAIL_IF_NULL(de_ctx->sig_list); - - SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dnp3_match_buffer_id); - FAIL_IF_NULL(sm); - FAIL_IF_NULL(sm->ctx); - - DetectDNP3 *dnp3func = (DetectDNP3 *)sm->ctx; - FAIL_IF(dnp3func->function_code != 2); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -static int DetectDNP3IndTestParseAsInteger(void) -{ - uint16_t flags = 0; - - FAIL_IF(!DetectDNP3IndParse("0", &flags)); - FAIL_IF(flags != 0); - FAIL_IF(!DetectDNP3IndParse("1", &flags)); - FAIL_IF(flags != 0x0001); - - FAIL_IF(!DetectDNP3IndParse("0x0", &flags)); - FAIL_IF(flags != 0); - FAIL_IF(!DetectDNP3IndParse("0x0000", &flags)); - FAIL_IF(flags != 0); - FAIL_IF(!DetectDNP3IndParse("0x0001", &flags)); - FAIL_IF(flags != 0x0001); - - FAIL_IF(!DetectDNP3IndParse("0x8421", &flags)); - FAIL_IF(flags != 0x8421); - - FAIL_IF(DetectDNP3IndParse("a", &flags)); - - PASS; -} - -static int DetectDNP3IndTestParseByName(void) -{ - uint16_t flags = 0; - - FAIL_IF(!DetectDNP3IndParse("all_stations", &flags)); - FAIL_IF(!(flags & 0x0100)); - FAIL_IF(!DetectDNP3IndParse("class_1_events , class_2_events", &flags)); - FAIL_IF(!(flags & 0x0200)); - FAIL_IF(!(flags & 0x0400)); - FAIL_IF((flags & 0xf9ff)); - - FAIL_IF(DetectDNP3IndParse("something", &flags)); - - PASS; -} - -static int DetectDNP3ObjSetupTest(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF(de_ctx == NULL); - - Signature *s = DetectEngineAppendSig(de_ctx, "alert dnp3 any any -> any any " - "(msg:\"SURICATA DNP3 Object Test\"; " - "dnp3_obj:99,99; sid:1; rev:1;)"); - FAIL_IF(de_ctx->sig_list == NULL); - - SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dnp3_match_buffer_id); - FAIL_IF_NULL(sm); - FAIL_IF_NULL(sm->ctx); - - DetectDNP3 *detect = (DetectDNP3 *)sm->ctx; - FAIL_IF(detect->obj_group != 99); - FAIL_IF(detect->obj_variation != 99); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -static int DetectDNP3ObjParseTest(void) -{ - uint8_t group, var; - - FAIL_IF(!DetectDNP3ObjParse("0,0", &group, &var)); - FAIL_IF(group != 0 || var != 0); - - FAIL_IF(!DetectDNP3ObjParse("255,255", &group, &var)); - FAIL_IF(group != 255 || var != 255); - - FAIL_IF(DetectDNP3ObjParse("-1,-1", &group, &var)); - FAIL_IF(DetectDNP3ObjParse("256,256", &group, &var)); - FAIL_IF(DetectDNP3ObjParse("a,1", &group, &var)); - FAIL_IF(DetectDNP3ObjParse("1,a", &group, &var)); - - PASS; -} - -static void DetectDNP3FuncRegisterTests(void) -{ - UtRegisterTest("DetectDNP3FuncParseFunctionCodeTest", - DetectDNP3FuncParseFunctionCodeTest); - UtRegisterTest("DetectDNP3FuncTest01", DetectDNP3FuncTest01); -} - -static void DetectDNP3IndRegisterTests(void) -{ - UtRegisterTest("DetectDNP3IndTestParseAsInteger", - DetectDNP3IndTestParseAsInteger); - UtRegisterTest("DetectDNP3IndTestParseByName", - DetectDNP3IndTestParseByName); -} - -static void DetectDNP3ObjRegisterTests(void) -{ - UtRegisterTest("DetectDNP3ObjParseTest", DetectDNP3ObjParseTest); - UtRegisterTest("DetectDNP3ObjSetupTest", DetectDNP3ObjSetupTest); -} -#endif diff --git a/src/detect-dnp3.h b/src/detect-dnp3.h deleted file mode 100644 index 7479d7841aa2..000000000000 --- a/src/detect-dnp3.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __DETECT_DNP3_H__ -#define __DETECT_DNP3_H__ - -/** - * Struct for mapping symbolic names to values. - */ -typedef struct DNP3Mapping_ { - const char *name; - uint16_t value; -} DNP3Mapping; - -/* Map of internal indicators to value for external use. */ -extern DNP3Mapping DNP3IndicatorsMap[]; - -void DetectDNP3Register(void); - -#endif /* __DETECT_DNP3_H__ */ diff --git a/src/detect-dns-opcode.c b/src/detect-dns-opcode.c deleted file mode 100644 index 853b01f0097d..000000000000 --- a/src/detect-dns-opcode.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-dns-opcode.h" -#include "rust.h" - -static int dns_opcode_list_id = 0; - -static void DetectDnsOpcodeFree(DetectEngineCtx *, void *ptr); - -static int DetectDnsOpcodeSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *str) -{ - SCEnter(); - - if (DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0) { - return -1; - } - - void *detect = rs_detect_dns_opcode_parse(str); - if (detect == NULL) { - SCLogError("failed to parse dns.opcode: %s", str); - return -1; - } - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNS_OPCODE, (SigMatchCtx *)detect, - dns_opcode_list_id) == NULL) { - goto error; - } - - SCReturnInt(0); - -error: - DetectDnsOpcodeFree(de_ctx, detect); - SCReturnInt(-1); -} - -static void DetectDnsOpcodeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCEnter(); - if (ptr != NULL) { - rs_dns_detect_opcode_free(ptr); - } - SCReturn; -} - -static int DetectDnsOpcodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - return rs_dns_opcode_match(txv, (void *)ctx, flags); -} - -void DetectDnsOpcodeRegister(void) -{ - sigmatch_table[DETECT_AL_DNS_OPCODE].name = "dns.opcode"; - sigmatch_table[DETECT_AL_DNS_OPCODE].desc = "Match the DNS header opcode flag."; - sigmatch_table[DETECT_AL_DNS_OPCODE].Setup = DetectDnsOpcodeSetup; - sigmatch_table[DETECT_AL_DNS_OPCODE].Free = DetectDnsOpcodeFree; - sigmatch_table[DETECT_AL_DNS_OPCODE].Match = NULL; - sigmatch_table[DETECT_AL_DNS_OPCODE].AppLayerTxMatch = - DetectDnsOpcodeMatch; - - DetectAppLayerInspectEngineRegister2( - "dns.opcode", ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2( - "dns.opcode", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); - - dns_opcode_list_id = DetectBufferTypeGetByName("dns.opcode"); -} diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c deleted file mode 100644 index d2dbe8e99021..000000000000 --- a/src/detect-dns-query.c +++ /dev/null @@ -1,871 +0,0 @@ -/* Copyright (C) 2013-2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup dnslayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-build.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "detect-dns-query.h" - -#include "util-profiling.h" -#include "util-unittest-helper.h" -#include "rust.h" - -static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectDnsQueryRegisterTests(void); -#endif -static int g_dns_query_buffer_id = 0; - -struct DnsQueryGetDataArgs { - uint32_t local_id; /**< used as index into thread inspect array */ - void *txv; -}; - -static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, struct DnsQueryGetDataArgs *cbdata, - int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_dns_tx_get_query_name(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectDnsQuery(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while(1) { - struct DnsQueryGetDataArgs cbdata = { local_id, txv, }; - InspectionBuffer *buffer = - DnsQueryGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -typedef struct PrefilterMpmDnsQuery { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmDnsQuery; - -/** \brief DnsQuery DnsQuery Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxDnsQuery(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmDnsQuery *ctx = (const PrefilterMpmDnsQuery *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - while(1) { - // loop until we get a NULL - - struct DnsQueryGetDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = DnsQueryGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static void PrefilterMpmDnsQueryFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmDnsQueryRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, - const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmDnsQuery *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxDnsQuery, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmDnsQueryFree, mpm_reg->pname); -} - -/** - * \brief Registration function for keyword: dns_query - */ -void DetectDnsQueryRegister (void) -{ - sigmatch_table[DETECT_AL_DNS_QUERY].name = "dns.query"; - sigmatch_table[DETECT_AL_DNS_QUERY].alias = "dns_query"; - sigmatch_table[DETECT_AL_DNS_QUERY].desc = "sticky buffer to match DNS query-buffer"; - sigmatch_table[DETECT_AL_DNS_QUERY].url = "/rules/dns-keywords.html#dns-query"; - sigmatch_table[DETECT_AL_DNS_QUERY].Setup = DetectDnsQuerySetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_DNS_QUERY].RegisterTests = DetectDnsQueryRegisterTests; -#endif - sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerMpmRegister2("dns_query", SIG_FLAG_TOSERVER, 2, - PrefilterMpmDnsQueryRegister, NULL, - ALPROTO_DNS, 1); - - DetectAppLayerInspectEngineRegister2("dns_query", - ALPROTO_DNS, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectDnsQuery, NULL); - - DetectBufferTypeSetDescriptionByName("dns_query", - "dns request query"); - DetectBufferTypeSupportsMultiInstance("dns_query"); - - g_dns_query_buffer_id = DetectBufferTypeGetByName("dns_query"); - -#ifdef HAVE_LUA - /* register these generic engines from here for now */ - DetectAppLayerInspectEngineRegister2( - "dns_request", ALPROTO_DNS, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - DetectAppLayerInspectEngineRegister2("dns_response", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectGenericList, NULL); - - DetectBufferTypeSetDescriptionByName("dns_request", - "dns requests"); - DetectBufferTypeSetDescriptionByName("dns_response", - "dns responses"); -#endif -} - - -/** - * \brief setup the dns_query sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_dns_query_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_DNS) < 0) - return -1; - return 0; -} - -#ifdef UNITTESTS -#include "detect-isdataat.h" -#include "detect-engine-alert.h" - -/** \test simple google.com query matching */ -static int DetectDnsQueryTest01(void) -{ - /* google.com */ - uint8_t buf[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW; - p->flowflags |= FLOW_PKT_TOSERVER; - f.alproto = ALPROTO_DNS; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - -/** \test multi tx google.(com|net) query matching */ -static int DetectDnsQueryTest02(void) -{ - /* google.com */ - uint8_t buf1[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x01, 0x00, 0x01, }; - - uint8_t buf2[] = { 0x10, 0x32, /* tx id */ - 0x81, 0x80, /* flags: resp, recursion desired, recursion available */ - 0x00, 0x01, /* 1 query */ - 0x00, 0x01, /* 1 answer */ - 0x00, 0x00, 0x00, 0x00, /* no auth rr, additional rr */ - /* query record */ - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, /* name */ - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* name cont */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - /* answer */ - 0xc0, 0x0c, /* ref to name in query above */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - 0x00, 0x01, 0x40, 0xef, /* ttl */ - 0x00, 0x04, /* data len */ - 0x01, 0x02, 0x03, 0x04 }; /* addr */ - - /* google.net */ - uint8_t buf3[] = { 0x11, 0x33, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x6E, 0x65, 0x74, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p1 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p2 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p3 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - f.alproto = ALPROTO_DNS; - - p1->flow = &f; - p1->flags |= PKT_HAS_FLOW; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->pcap_cnt = 1; - - p2->flow = &f; - p2->flags |= PKT_HAS_FLOW; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->pcap_cnt = 2; - - p3->flow = &f; - p3->flags |= PKT_HAS_FLOW; - p3->flowflags |= FLOW_PKT_TOSERVER; - p3->pcap_cnt = 3; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.com\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.net\"; nocase; sid:2;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf1, sizeof(buf1)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("(p1) sig 1 didn't alert, but it should have: "); - FAIL; - } - if (PacketAlertCheck(p1, 2)) { - printf("(p1) sig 2 did alert, but it should not have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, - buf2, sizeof(buf2)); - if (r != 0) { - printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("(p2) sig 1 alerted, but it should not have: "); - FAIL; - } - if (PacketAlertCheck(p2, 2)) { - printf("(p2) sig 2 alerted, but it should not have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, - buf3, sizeof(buf3)); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p3); - - if (PacketAlertCheck(p3, 1)) { - printf("(p3) sig 1 alerted, but it should not have: "); - FAIL; - } - if (!(PacketAlertCheck(p3, 2))) { - printf("(p3) sig 2 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p1); - UTHFreePacket(p2); - UTHFreePacket(p3); - PASS; -} - -/** \test simple google.com query matching (TCP) */ -static int DetectDnsQueryTest03(void) -{ - /* google.com */ - uint8_t buf[] = { 0x00, 28, - 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_TCP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_DNS; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - - -/** \test simple google.com query matching, pcre */ -static int DetectDnsQueryTest04(void) -{ - /* google.com */ - uint8_t buf[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW; - p->flowflags |= FLOW_PKT_TOSERVER; - f.alproto = ALPROTO_DNS; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; " - "pcre:\"/google\\.com$/i\"; sid:1;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; " - "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - if (!(PacketAlertCheck(p, 2))) { - printf("sig 2 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - -/** \test multi tx google.(com|net) query matching + - * app layer event */ -static int DetectDnsQueryTest05(void) -{ - /* google.com */ - uint8_t buf1[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x01, 0x00, 0x01, }; - - uint8_t buf2[] = { 0x10, 0x32, /* tx id */ - 0x81, 0x80|0x40, /* flags: resp, recursion desired, recursion available */ - 0x00, 0x01, /* 1 query */ - 0x00, 0x01, /* 1 answer */ - 0x00, 0x00, 0x00, 0x00, /* no auth rr, additional rr */ - /* query record */ - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, /* name */ - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* name cont */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - /* answer */ - 0xc0, 0x0c, /* ref to name in query above */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - 0x00, 0x01, 0x40, 0xef, /* ttl */ - 0x00, 0x04, /* data len */ - 0x01, 0x02, 0x03, 0x04 }; /* addr */ - - /* google.net */ - uint8_t buf3[] = { 0x11, 0x33, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x6E, 0x65, 0x74, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p1 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p2 = UTHBuildPacketReal(buf2, sizeof(buf2), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p3 = UTHBuildPacketReal(buf3, sizeof(buf3), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - f.alproto = ALPROTO_DNS; - - p1->flow = &f; - p1->flags |= PKT_HAS_FLOW; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->pcap_cnt = 1; - - p2->flow = &f; - p2->flags |= PKT_HAS_FLOW; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->pcap_cnt = 2; - - p3->flow = &f; - p3->flags |= PKT_HAS_FLOW; - p3->flowflags |= FLOW_PKT_TOSERVER; - p3->pcap_cnt = 3; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.com\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.net\"; nocase; sid:2;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test Z flag event\"; " - "app-layer-event:dns.z_flag_set; sid:3;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf1, sizeof(buf1)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("(p1) sig 1 didn't alert, but it should have: "); - FAIL; - } - if (PacketAlertCheck(p1, 2)) { - printf("(p1) sig 2 did alert, but it should not have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, - buf2, sizeof(buf2)); - if (r != 0) { - printf("toserver client 1 returned %" PRId32 ", expected 0\n", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("(p2) sig 1 alerted, but it should not have: "); - FAIL; - } - if (PacketAlertCheck(p2, 2)) { - printf("(p2) sig 2 alerted, but it should not have: "); - FAIL; - } - if (!(PacketAlertCheck(p2, 3))) { - printf("(p2) sig 3 didn't alert, but it should have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, - buf3, sizeof(buf3)); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p3); - - if (PacketAlertCheck(p3, 1)) { - printf("(p3) sig 1 alerted, but it should not have: "); - FAIL; - } - if (!(PacketAlertCheck(p3, 2))) { - printf("(p3) sig 2 didn't alert, but it should have: "); - FAIL; - } - /** \todo should not alert, bug #839 - if (PacketAlertCheck(p3, 3)) { - printf("(p3) sig 3 did alert, but it should not have: "); - goto end; - } - */ - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p1); - UTHFreePacket(p2); - UTHFreePacket(p3); - PASS; -} - -static void DetectDnsQueryRegisterTests(void) -{ - UtRegisterTest("DetectDnsQueryTest01", DetectDnsQueryTest01); - UtRegisterTest("DetectDnsQueryTest02", DetectDnsQueryTest02); - UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03); - UtRegisterTest("DetectDnsQueryTest04 -- pcre", DetectDnsQueryTest04); - UtRegisterTest("DetectDnsQueryTest05 -- app layer event", DetectDnsQueryTest05); -} -#endif diff --git a/src/detect-dns-query.h b/src/detect-dns-query.h deleted file mode 100644 index c894b878dbfb..000000000000 --- a/src/detect-dns-query.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __DETECT_DNS_QUERY_H__ -#define __DETECT_DNS_QUERY_H__ - -void DetectDnsQueryRegister (void); - -#endif /* __DETECT_DNS_QUERY_H__ */ diff --git a/src/detect-dsize.c b/src/detect-dsize.c index bf095cd4fda5..16f779bf8408 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -36,17 +36,17 @@ #include "detect-content.h" #include "detect-dsize.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-byte.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/byte.h" #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" +#include "util/profiling.h" -static int DetectDsizeMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, const char *str); +static int DetectDsizeMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectDsizeSetup(DetectEngineCtx *, Signature *s, const char *str); #ifdef UNITTESTS static void DsizeRegisterTests(void); #endif @@ -58,14 +58,14 @@ static bool PrefilterDsizeIsPrefilterable(const Signature *s); /** * \brief Registration function for dsize: keyword */ -void DetectDsizeRegister (void) +void DetectDsizeRegister(void) { sigmatch_table[DETECT_DSIZE].name = "dsize"; sigmatch_table[DETECT_DSIZE].desc = "match on the size of the packet payload"; sigmatch_table[DETECT_DSIZE].url = "/rules/payload-keywords.html#dsize"; sigmatch_table[DETECT_DSIZE].Match = DetectDsizeMatch; sigmatch_table[DETECT_DSIZE].Setup = DetectDsizeSetup; - sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; + sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; #ifdef UNITTESTS sigmatch_table[DETECT_DSIZE].RegisterTests = DsizeRegisterTests; #endif @@ -86,8 +86,8 @@ void DetectDsizeRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectDsizeMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectDsizeMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; @@ -98,7 +98,7 @@ static int DetectDsizeMatch (DetectEngineThreadCtx *det_ctx, Packet *p, const DetectU16Data *dd = (const DetectU16Data *)ctx; - SCLogDebug("p->payload_len %"PRIu16"", p->payload_len); + SCLogDebug("p->payload_len %" PRIu16 "", p->payload_len); ret = DetectU16Match(p->payload_len, dd); @@ -116,7 +116,7 @@ static int DetectDsizeMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectDsizeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectU16Data *dd = NULL; @@ -172,8 +172,7 @@ void DetectDsizeFree(DetectEngineCtx *de_ctx, void *de_ptr) /* prefilter code */ -static void -PrefilterPacketDsizeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketDsizeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { if (PKT_IS_PSEUDOPKT(p)) { SCReturn; @@ -204,7 +203,7 @@ static int PrefilterSetupDsize(DetectEngineCtx *de_ctx, SigGroupHead *sgh) static bool PrefilterDsizeIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_DSIZE: return true; @@ -344,7 +343,7 @@ void SigParseApplyDsizeToContent(Signature *s) } SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; - for ( ; sm != NULL; sm = sm->next) { + for (; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) { continue; } @@ -358,7 +357,8 @@ void SigParseApplyDsizeToContent(Signature *s) cd->flags |= DETECT_CONTENT_DEPTH; cd->depth = (uint16_t)dsize; SCLogDebug("updated %u, content %u to have depth %u " - "because of dsize.", s->id, cd->id, cd->depth); + "because of dsize.", + s->id, cd->id, cd->depth); } } } @@ -369,7 +369,7 @@ void SigParseApplyDsizeToContent(Signature *s) */ #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "detect-engine.h" #include "detect-engine-alert.h" #include "packet.h" @@ -578,6 +578,7 @@ static int DsizeTestMatch02(void) */ static int DetectDsizeIcmpv6Test01(void) { + // clang-format off static uint8_t raw_icmpv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -590,6 +591,7 @@ static int DetectDsizeIcmpv6Test01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); diff --git a/src/detect-dsize.h b/src/detect-dsize.h index c262a31186fe..b7bd0d7b0b46 100644 --- a/src/detect-dsize.h +++ b/src/detect-dsize.h @@ -27,7 +27,7 @@ #include "detect-engine-uint.h" /* prototypes */ -void DetectDsizeRegister (void); +void DetectDsizeRegister(void); int SigParseMaxRequiredDsize(const Signature *s); int SigParseGetMaxDsize(const Signature *s); @@ -51,4 +51,3 @@ static inline bool SigDsizePrefilter(const Packet *p, const Signature *s, uint32 } #endif /* __DETECT_DSIZE_H__ */ - diff --git a/src/detect-engine-address-ipv4.c b/src/detect-engine-address-ipv4.c index 80d29012988f..6f59dba62153 100644 --- a/src/detect-engine-address-ipv4.c +++ b/src/detect-engine-address-ipv4.c @@ -29,16 +29,16 @@ #include "detect.h" #include "flow-var.h" -#include "util-cidr.h" -#include "util-unittest.h" +#include "util/cidr.h" +#include "util/unittest.h" #include "detect-engine-address.h" #include "detect-engine-address-ipv4.h" #include "detect-engine-siggroup.h" #include "detect-engine-port.h" -#include "util-error.h" -#include "util-debug.h" +#include "util/error.h" +#include "util/debug.h" /** * \brief Compares 2 addresses(address ranges) and returns the relationship @@ -110,8 +110,8 @@ int DetectAddressCmpIPv4(DetectAddress *a, DetectAddress *b) * \retval 0 On success. * \retval -1 On failure. */ -int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, - DetectAddress *b, DetectAddress **c) +int DetectAddressCutIPv4( + DetectEngineCtx *de_ctx, DetectAddress *a, DetectAddress *b, DetectAddress **c) { uint32_t a_ip1 = SCNtohl(a->ip.addr_data32[0]); uint32_t a_ip2 = SCNtohl(a->ip2.addr_data32[0]); @@ -143,10 +143,10 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, if (r == ADDRESS_LE) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_LE"); - a->ip.addr_data32[0] = htonl(a_ip1); + a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); - b->ip.addr_data32[0] = htonl(b_ip1); + b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); tmp_c = DetectAddressInit(); @@ -158,11 +158,11 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; - /* we have 3 parts: [bbb[baba]aaa] - * part a: b_ip1 <-> a_ip1 - 1 - * part b: a_ip1 <-> b_ip2 - * part c: b_ip2 + 1 <-> a_ip2 - */ + /* we have 3 parts: [bbb[baba]aaa] + * part a: b_ip1 <-> a_ip1 - 1 + * part b: a_ip1 <-> b_ip2 + * part c: b_ip2 + 1 <-> a_ip2 + */ } else if (r == ADDRESS_GE) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_GE"); @@ -177,7 +177,7 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, goto error; tmp_c->ip.family = AF_INET; - tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); + tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; @@ -212,19 +212,19 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); - a->ip.addr_data32[0] = htonl(b_ip1); + a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); - b->ip.addr_data32[0] = htonl(a_ip1); + b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); } else { SCLogDebug("3"); - a->ip.addr_data32[0] = htonl(b_ip1); + a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); - b->ip.addr_data32[0] = htonl(a_ip1); + b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); tmp_c = DetectAddressInit(); @@ -266,10 +266,10 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); - a->ip.addr_data32[0] = htonl(a_ip1); + a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); - b->ip.addr_data32[0] = htonl(b_ip1); + b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); } else { SCLogDebug("DetectAddressCutIPv4: 3"); @@ -330,7 +330,7 @@ int DetectAddressIsCompleteIPSpaceIPv4(DetectAddress *ag) next_ip = htonl(SCNtohl(ag->ip2.addr_data32[0]) + 1); ag = ag->next; - for ( ; ag != NULL; ag = ag->next) { + for (; ag != NULL; ag = ag->next) { if (ag->ip.addr_data32[0] != next_ip) return 0; @@ -375,7 +375,7 @@ int DetectAddressCutNotIPv4(DetectAddress *a, DetectAddress **b) *b = NULL; if (a_ip1 != 0x00000000 && a_ip2 != 0xFFFFFFFF) { - a->ip.addr_data32[0] = htonl(0x00000000); + a->ip.addr_data32[0] = htonl(0x00000000); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); tmp_b = DetectAddressInit(); @@ -383,7 +383,7 @@ int DetectAddressCutNotIPv4(DetectAddress *a, DetectAddress **b) goto error; tmp_b->ip.family = AF_INET; - tmp_b->ip.addr_data32[0] = htonl(a_ip2 + 1); + tmp_b->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_b->ip2.addr_data32[0] = htonl(0xFFFFFFFF); *b = tmp_b; } else if (a_ip1 == 0x00000000 && a_ip2 != 0xFFFFFFFF) { @@ -394,7 +394,7 @@ int DetectAddressCutNotIPv4(DetectAddress *a, DetectAddress **b) a->ip2.addr_data32[0] = htonl(a_ip1 - 1); } else { goto error; - } + } return 0; @@ -847,7 +847,7 @@ static int DetectAddressIPv4TestAddressCmp01(void) DetectAddressFree(b); return result; - error: +error: DetectAddressFree(a); DetectAddressFree(b); return 0; @@ -859,7 +859,7 @@ static int DetectAddressIPv4IsCompleteIPSpace02(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) @@ -880,7 +880,7 @@ static int DetectAddressIPv4IsCompleteIPSpace02(void) DetectAddressFree(a); - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) @@ -895,7 +895,7 @@ static int DetectAddressIPv4IsCompleteIPSpace02(void) return result; - error: +error: if (a != NULL) DetectAddressFree(a); return 0; @@ -908,7 +908,7 @@ static int DetectAddressIPv4IsCompleteIPSpace03(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; temp = a; @@ -920,7 +920,7 @@ static int DetectAddressIPv4IsCompleteIPSpace03(void) a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -932,7 +932,7 @@ static int DetectAddressIPv4IsCompleteIPSpace03(void) temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -944,7 +944,7 @@ static int DetectAddressIPv4IsCompleteIPSpace03(void) temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -956,7 +956,7 @@ static int DetectAddressIPv4IsCompleteIPSpace03(void) temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -972,7 +972,7 @@ static int DetectAddressIPv4IsCompleteIPSpace03(void) return result; - error: +error: if (a != NULL) DetectAddressFree(a); return 0; @@ -985,7 +985,7 @@ static int DetectAddressIPv4IsCompleteIPSpace04(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; temp = a; @@ -997,7 +997,7 @@ static int DetectAddressIPv4IsCompleteIPSpace04(void) a->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -1009,7 +1009,7 @@ static int DetectAddressIPv4IsCompleteIPSpace04(void) temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -1021,7 +1021,7 @@ static int DetectAddressIPv4IsCompleteIPSpace04(void) temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -1033,7 +1033,7 @@ static int DetectAddressIPv4IsCompleteIPSpace04(void) temp->ip2.addr_data32[0] = in.s_addr; result &= (DetectAddressIsCompleteIPSpaceIPv4(a) == 0); - if ( (temp->next = DetectAddressInit()) == NULL) + if ((temp->next = DetectAddressInit()) == NULL) goto error; temp = temp->next; @@ -1049,7 +1049,7 @@ static int DetectAddressIPv4IsCompleteIPSpace04(void) return result; - error: +error: if (a != NULL) DetectAddressFree(a); return 0; @@ -1062,7 +1062,7 @@ static int DetectAddressIPv4CutNot05(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) @@ -1078,7 +1078,7 @@ static int DetectAddressIPv4CutNot05(void) DetectAddressFree(b); return result; - error: +error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); @@ -1092,7 +1092,7 @@ static int DetectAddressIPv4CutNot06(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "0.0.0.0", &in) < 0) @@ -1115,7 +1115,7 @@ static int DetectAddressIPv4CutNot06(void) DetectAddressFree(b); return result; - error: +error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); @@ -1129,7 +1129,7 @@ static int DetectAddressIPv4CutNot07(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) @@ -1152,7 +1152,7 @@ static int DetectAddressIPv4CutNot07(void) DetectAddressFree(b); return result; - error: +error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); @@ -1166,7 +1166,7 @@ static int DetectAddressIPv4CutNot08(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) @@ -1202,7 +1202,7 @@ static int DetectAddressIPv4CutNot08(void) DetectAddressFree(b); return result; - error: +error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); @@ -1216,7 +1216,7 @@ static int DetectAddressIPv4CutNot09(void) struct in_addr in; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) return 0; if (inet_pton(AF_INET, "1.2.3.4", &in) < 0) @@ -1252,7 +1252,7 @@ static int DetectAddressIPv4CutNot09(void) DetectAddressFree(b); return result; - error: +error: DetectAddressFree(a); if (b != NULL) DetectAddressFree(b); @@ -1264,14 +1264,10 @@ static int DetectAddressIPv4CutNot09(void) void DetectAddressIPv4Tests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectAddressIPv4TestAddressCmp01", - DetectAddressIPv4TestAddressCmp01); - UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace02", - DetectAddressIPv4IsCompleteIPSpace02); - UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace03", - DetectAddressIPv4IsCompleteIPSpace03); - UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace04", - DetectAddressIPv4IsCompleteIPSpace04); + UtRegisterTest("DetectAddressIPv4TestAddressCmp01", DetectAddressIPv4TestAddressCmp01); + UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace02", DetectAddressIPv4IsCompleteIPSpace02); + UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace03", DetectAddressIPv4IsCompleteIPSpace03); + UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace04", DetectAddressIPv4IsCompleteIPSpace04); UtRegisterTest("DetectAddressIPv4CutNot05", DetectAddressIPv4CutNot05); UtRegisterTest("DetectAddressIPv4CutNot06", DetectAddressIPv4CutNot06); UtRegisterTest("DetectAddressIPv4CutNot07", DetectAddressIPv4CutNot07); diff --git a/src/detect-engine-address-ipv4.h b/src/detect-engine-address-ipv4.h index 5f2780a3c066..87df4f82ce2a 100644 --- a/src/detect-engine-address-ipv4.h +++ b/src/detect-engine-address-ipv4.h @@ -27,11 +27,9 @@ int DetectAddressCutNotIPv4(DetectAddress *, DetectAddress **); int DetectAddressCmpIPv4(DetectAddress *a, DetectAddress *b); -int DetectAddressCutIPv4(DetectEngineCtx *, DetectAddress *, - DetectAddress *, DetectAddress **); +int DetectAddressCutIPv4(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); int DetectAddressIsCompleteIPSpaceIPv4(DetectAddress *); void DetectAddressIPv4Tests(void); #endif /* __DETECT_ENGINE_ADDRESS_IPV4_H__ */ - diff --git a/src/detect-engine-address-ipv6.c b/src/detect-engine-address-ipv6.c index 3179628c6d55..2a74bd9611ef 100644 --- a/src/detect-engine-address-ipv6.c +++ b/src/detect-engine-address-ipv6.c @@ -29,15 +29,15 @@ #include "detect.h" #include "flow-var.h" -#include "util-cidr.h" -#include "util-unittest.h" +#include "util/cidr.h" +#include "util/unittest.h" #include "detect-engine-address.h" #include "detect-engine-address-ipv6.h" #include "detect-engine-siggroup.h" #include "detect-engine-port.h" -#include "util-debug.h" +#include "util/debug.h" /** * \brief Compares 2 ipv6 addresses and returns if the first address(a) is less @@ -231,25 +231,19 @@ int AddressIPv6GeU32(uint32_t *a, uint32_t *b) */ int DetectAddressCmpIPv6(DetectAddress *a, DetectAddress *b) { - if (AddressIPv6Eq(&a->ip, &b->ip) == 1 && - AddressIPv6Eq(&a->ip2, &b->ip2) == 1) { + if (AddressIPv6Eq(&a->ip, &b->ip) == 1 && AddressIPv6Eq(&a->ip2, &b->ip2) == 1) { return ADDRESS_EQ; - } else if (AddressIPv6Ge(&a->ip, &b->ip) == 1 && - AddressIPv6Le(&a->ip, &b->ip2) == 1 && + } else if (AddressIPv6Ge(&a->ip, &b->ip) == 1 && AddressIPv6Le(&a->ip, &b->ip2) == 1 && AddressIPv6Le(&a->ip2, &b->ip2) == 1) { return ADDRESS_ES; - } else if (AddressIPv6Le(&a->ip, &b->ip) == 1 && - AddressIPv6Ge(&a->ip2, &b->ip2) == 1) { + } else if (AddressIPv6Le(&a->ip, &b->ip) == 1 && AddressIPv6Ge(&a->ip2, &b->ip2) == 1) { return ADDRESS_EB; - } else if (AddressIPv6Lt(&a->ip, &b->ip) == 1 && - AddressIPv6Lt(&a->ip2, &b->ip2) == 1 && + } else if (AddressIPv6Lt(&a->ip, &b->ip) == 1 && AddressIPv6Lt(&a->ip2, &b->ip2) == 1 && AddressIPv6Ge(&a->ip2, &b->ip) == 1) { return ADDRESS_LE; - } else if (AddressIPv6Lt(&a->ip, &b->ip) == 1 && - AddressIPv6Lt(&a->ip2, &b->ip2) == 1) { + } else if (AddressIPv6Lt(&a->ip, &b->ip) == 1 && AddressIPv6Lt(&a->ip2, &b->ip2) == 1) { return ADDRESS_LT; - } else if (AddressIPv6Gt(&a->ip, &b->ip) == 1 && - AddressIPv6Le(&a->ip, &b->ip2) == 1 && + } else if (AddressIPv6Gt(&a->ip, &b->ip) == 1 && AddressIPv6Le(&a->ip, &b->ip2) == 1 && AddressIPv6Gt(&a->ip2, &b->ip2) == 1) { return ADDRESS_GE; } else if (AddressIPv6Gt(&a->ip, &b->ip2) == 1) { @@ -356,17 +350,17 @@ static void AddressCutIPv6Copy(uint32_t *a, uint32_t *b) return; } -int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, - DetectAddress *b, DetectAddress **c) +int DetectAddressCutIPv6( + DetectEngineCtx *de_ctx, DetectAddress *a, DetectAddress *b, DetectAddress **c) { uint32_t a_ip1[4] = { SCNtohl(a->ip.addr_data32[0]), SCNtohl(a->ip.addr_data32[1]), - SCNtohl(a->ip.addr_data32[2]), SCNtohl(a->ip.addr_data32[3]) }; + SCNtohl(a->ip.addr_data32[2]), SCNtohl(a->ip.addr_data32[3]) }; uint32_t a_ip2[4] = { SCNtohl(a->ip2.addr_data32[0]), SCNtohl(a->ip2.addr_data32[1]), - SCNtohl(a->ip2.addr_data32[2]), SCNtohl(a->ip2.addr_data32[3]) }; + SCNtohl(a->ip2.addr_data32[2]), SCNtohl(a->ip2.addr_data32[3]) }; uint32_t b_ip1[4] = { SCNtohl(b->ip.addr_data32[0]), SCNtohl(b->ip.addr_data32[1]), - SCNtohl(b->ip.addr_data32[2]), SCNtohl(b->ip.addr_data32[3]) }; + SCNtohl(b->ip.addr_data32[2]), SCNtohl(b->ip.addr_data32[3]) }; uint32_t b_ip2[4] = { SCNtohl(b->ip2.addr_data32[0]), SCNtohl(b->ip2.addr_data32[1]), - SCNtohl(b->ip2.addr_data32[2]), SCNtohl(b->ip2.addr_data32[3]) }; + SCNtohl(b->ip2.addr_data32[2]), SCNtohl(b->ip2.addr_data32[3]) }; /* default to NULL */ *c = NULL; @@ -392,18 +386,18 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; - tmp_c->ip.family = AF_INET6; + tmp_c->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(a_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(b_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - /* we have 3 parts: [bbb[baba]aaa] - * part a: b_ip1 <-> a_ip1 - 1 - * part b: a_ip1 <-> b_ip2 - * part c: b_ip2 + 1 <-> a_ip2 - */ + /* we have 3 parts: [bbb[baba]aaa] + * part a: b_ip1 <-> a_ip1 - 1 + * part b: a_ip1 <-> b_ip2 + * part c: b_ip2 + 1 <-> a_ip2 + */ } else if (r == ADDRESS_GE) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -415,26 +409,26 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; - tmp_c->ip.family = AF_INET6; + tmp_c->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - /* we have 2 or three parts: - * - * 2 part: [[abab]bbb] or [bbb[baba]] - * part a: a_ip1 <-> a_ip2 - * part b: a_ip2 + 1 <-> b_ip2 - * - * part a: b_ip1 <-> a_ip1 - 1 - * part b: a_ip1 <-> a_ip2 - * - * 3 part [bbb[aaa]bbb] - * part a: b_ip1 <-> a_ip1 - 1 - * part b: a_ip1 <-> a_ip2 - * part c: a_ip2 + 1 <-> b_ip2 - */ + /* we have 2 or three parts: + * + * 2 part: [[abab]bbb] or [bbb[baba]] + * part a: a_ip1 <-> a_ip2 + * part b: a_ip2 + 1 <-> b_ip2 + * + * part a: b_ip1 <-> a_ip1 - 1 + * part b: a_ip1 <-> a_ip2 + * + * 3 part [bbb[aaa]bbb] + * part a: b_ip1 <-> a_ip1 - 1 + * part b: a_ip1 <-> a_ip2 + * part c: a_ip2 + 1 <-> b_ip2 + */ } else if (r == ADDRESS_ES) { if (AddressIPv6EqU32(a_ip1, b_ip1) == 1) { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); @@ -466,22 +460,21 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6CopyAddOne(a_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(b_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - } - /* we have 2 or three parts: - * - * 2 part: [[baba]aaa] or [aaa[abab]] - * part a: b_ip1 <-> b_ip2 - * part b: b_ip2 + 1 <-> a_ip2 - * - * part a: a_ip1 <-> b_ip1 - 1 - * part b: b_ip1 <-> b_ip2 - * - * 3 part [aaa[bbb]aaa] - * part a: a_ip1 <-> b_ip2 - 1 - * part b: b_ip1 <-> b_ip2 - * part c: b_ip2 + 1 <-> a_ip2 - */ + /* we have 2 or three parts: + * + * 2 part: [[baba]aaa] or [aaa[abab]] + * part a: b_ip1 <-> b_ip2 + * part b: b_ip2 + 1 <-> a_ip2 + * + * part a: a_ip1 <-> b_ip1 - 1 + * part b: b_ip1 <-> b_ip2 + * + * 3 part [aaa[bbb]aaa] + * part a: a_ip1 <-> b_ip2 - 1 + * part b: b_ip1 <-> b_ip2 + * part c: b_ip2 + 1 <-> a_ip2 + */ } else if (r == ADDRESS_EB) { if (AddressIPv6EqU32(a_ip1, b_ip1) == 1) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); @@ -507,7 +500,7 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, if (tmp_c == NULL) goto error; - tmp_c->ip.family = AF_INET6; + tmp_c->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; @@ -710,19 +703,19 @@ int DetectAddressCutIPv6(DetectAddressData *a, DetectAddressData *b, int DetectAddressCutNotIPv6(DetectAddress *a, DetectAddress **b) { uint32_t a_ip1[4] = { SCNtohl(a->ip.addr_data32[0]), SCNtohl(a->ip.addr_data32[1]), - SCNtohl(a->ip.addr_data32[2]), SCNtohl(a->ip.addr_data32[3]) }; + SCNtohl(a->ip.addr_data32[2]), SCNtohl(a->ip.addr_data32[3]) }; uint32_t a_ip2[4] = { SCNtohl(a->ip2.addr_data32[0]), SCNtohl(a->ip2.addr_data32[1]), - SCNtohl(a->ip2.addr_data32[2]), SCNtohl(a->ip2.addr_data32[3]) }; + SCNtohl(a->ip2.addr_data32[2]), SCNtohl(a->ip2.addr_data32[3]) }; uint32_t ip_nul[4] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; uint32_t ip_max[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; /* default to NULL */ *b = NULL; - if (!(a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && - a_ip1[2] == 0x00000000 && a_ip1[3] == 0x00000000) && - !(a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && - a_ip2[2] == 0xFFFFFFFF && a_ip2[3] == 0xFFFFFFFF)) { + if (!(a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && a_ip1[2] == 0x00000000 && + a_ip1[3] == 0x00000000) && + !(a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && a_ip2[2] == 0xFFFFFFFF && + a_ip2[3] == 0xFFFFFFFF)) { AddressCutIPv6Copy(ip_nul, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -730,20 +723,20 @@ int DetectAddressCutNotIPv6(DetectAddress *a, DetectAddress **b) if (tmp_b == NULL) goto error; - tmp_b->ip.family = AF_INET6; + tmp_b->ip.family = AF_INET6; AddressCutIPv6CopyAddOne(a_ip2, tmp_b->ip.addr_data32); AddressCutIPv6Copy(ip_max, tmp_b->ip2.addr_data32); *b = tmp_b; - } else if ((a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && - a_ip1[2] == 0x00000000 && a_ip1[3] == 0x00000000) && - !(a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && - a_ip2[2] == 0xFFFFFFFF && a_ip2[3] == 0xFFFFFFFF)) { + } else if ((a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && a_ip1[2] == 0x00000000 && + a_ip1[3] == 0x00000000) && + !(a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && a_ip2[2] == 0xFFFFFFFF && + a_ip2[3] == 0xFFFFFFFF)) { AddressCutIPv6CopyAddOne(a_ip2, a->ip.addr_data32); AddressCutIPv6Copy(ip_max, a->ip2.addr_data32); - } else if (!(a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && - a_ip1[2] == 0x00000000 && a_ip1[3] == 0x00000000) && - (a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && - a_ip2[2] == 0xFFFFFFFF && a_ip2[3] == 0xFFFFFFFF)) { + } else if (!(a_ip1[0] == 0x00000000 && a_ip1[1] == 0x00000000 && a_ip1[2] == 0x00000000 && + a_ip1[3] == 0x00000000) && + (a_ip2[0] == 0xFFFFFFFF && a_ip2[1] == 0xFFFFFFFF && a_ip2[2] == 0xFFFFFFFF && + a_ip2[3] == 0xFFFFFFFF)) { AddressCutIPv6Copy(ip_nul, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); } else { @@ -756,7 +749,6 @@ int DetectAddressCutNotIPv6(DetectAddress *a, DetectAddress **b) return -1; } - /***************************************Unittests******************************/ #ifdef UNITTESTS @@ -1086,8 +1078,7 @@ static int AddressTestIPv6SubOne01(void) if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); - if (b[0] == a[0] && b[1] == a[1] && - b[2] == a[2] && b[3] == a[3]) { + if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } @@ -1115,8 +1106,7 @@ static int AddressTestIPv6SubOne02(void) if (inet_pton(AF_INET6, "1FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); - if (b[0] == a[0] && b[1] == a[1] && - b[2] == a[2] && b[3] == a[3]) { + if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } @@ -1144,8 +1134,7 @@ static int AddressTestIPv6AddOne01(void) if (inet_pton(AF_INET6, "2000::1", &in6) != 1) return 0; memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); - if (b[0] == a[0] && b[1] == a[1] && - b[2] == a[2] && b[3] == a[3]) { + if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } @@ -1172,9 +1161,8 @@ static int AddressTestIPv6AddOne02(void) if (inet_pton(AF_INET6, "2000::0", &in6) != 1) return 0; - memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); - if (b[0] == a[0] && b[1] == a[1] && - b[2] == a[2] && b[3] == a[3]) { + memcpy(a, in6.s6_addr, sizeof(in6.s6_addr)); + if (b[0] == a[0] && b[1] == a[1] && b[2] == a[2] && b[3] == a[3]) { result = 1; } @@ -1619,7 +1607,7 @@ static int AddressTestIPv6AddressCmp01(void) DetectAddressFree(b); return result; - error: +error: if (a != NULL) DetectAddressFree(a); if (b != NULL) @@ -1634,7 +1622,7 @@ static int AddressTestIPv6CutNot01(void) struct in6_addr in6; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "::", &in6) != 1) @@ -1651,7 +1639,7 @@ static int AddressTestIPv6CutNot01(void) DetectAddressFree(b); return result; - error: +error: if (a != NULL) DetectAddressFree(a); if (b != NULL) @@ -1667,9 +1655,9 @@ static int AddressTestIPv6CutNot02(void) struct in6_addr in6; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; - if ( (temp = DetectAddressInit()) == NULL) + if ((temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "::", &in6) != 1) @@ -1699,7 +1687,7 @@ static int AddressTestIPv6CutNot02(void) DetectAddressFree(temp); return result; - error: +error: if (a != NULL) DetectAddressFree(a); if (b != NULL) @@ -1717,9 +1705,9 @@ static int AddressTestIPv6CutNot03(void) struct in6_addr in6; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; - if ( (temp = DetectAddressInit()) == NULL) + if ((temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) @@ -1749,7 +1737,7 @@ static int AddressTestIPv6CutNot03(void) DetectAddressFree(temp); return result; - error: +error: if (a != NULL) DetectAddressFree(a); if (b != NULL) @@ -1767,9 +1755,9 @@ static int AddressTestIPv6CutNot04(void) struct in6_addr in6; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; - if ( (temp = DetectAddressInit()) == NULL) + if ((temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) @@ -1807,7 +1795,7 @@ static int AddressTestIPv6CutNot04(void) DetectAddressFree(temp); return result; - error: +error: if (a != NULL) DetectAddressFree(a); if (b != NULL) @@ -1825,9 +1813,9 @@ static int AddressTestIPv6CutNot05(void) struct in6_addr in6; int result = 1; - if ( (a = DetectAddressInit()) == NULL) + if ((a = DetectAddressInit()) == NULL) goto error; - if ( (temp = DetectAddressInit()) == NULL) + if ((temp = DetectAddressInit()) == NULL) goto error; if (inet_pton(AF_INET6, "2000::1", &in6) != 1) @@ -1865,7 +1853,7 @@ static int AddressTestIPv6CutNot05(void) DetectAddressFree(temp); return result; - error: +error: if (a != NULL) DetectAddressFree(a); if (b != NULL) diff --git a/src/detect-engine-address-ipv6.h b/src/detect-engine-address-ipv6.h index b8c573d0ce44..0edcba64ed17 100644 --- a/src/detect-engine-address-ipv6.h +++ b/src/detect-engine-address-ipv6.h @@ -39,10 +39,8 @@ int AddressIPv6GeU32(uint32_t *a, uint32_t *b); int DetectAddressCutNotIPv6(DetectAddress *, DetectAddress **); int DetectAddressCmpIPv6(DetectAddress *a, DetectAddress *b); -int DetectAddressCutIPv6(DetectEngineCtx *, DetectAddress *, DetectAddress *, - DetectAddress **); +int DetectAddressCutIPv6(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); void DetectAddressIPv6Tests(void); #endif /* __DETECT_ENGINE_ADDRESS_IPV6_H__ */ - diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 7819969e6ef3..69548fe4cff5 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -28,9 +28,9 @@ #include "detect.h" #include "flow-var.h" -#include "util-cidr.h" -#include "util-unittest.h" -#include "util-rule-vars.h" +#include "util/cidr.h" +#include "util/unittest.h" +#include "util/rule-vars.h" #include "conf.h" #include "conf-yaml-loader.h" @@ -40,10 +40,10 @@ #include "detect-engine-address-ipv6.h" #include "detect-engine-port.h" -#include "util-debug.h" -#include "util-byte.h" -#include "util-print.h" -#include "util-var.h" +#include "util/debug.h" +#include "util/byte.h" +#include "util/print.h" +#include "util/var.h" /* prototypes */ #ifdef DEBUG @@ -52,8 +52,7 @@ static void DetectAddressPrint(DetectAddress *); #define DetectAddressPrint(...) #endif static int DetectAddressCutNot(DetectAddress *, DetectAddress **); -static int DetectAddressCut(DetectEngineCtx *, DetectAddress *, DetectAddress *, - DetectAddress **); +static int DetectAddressCut(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); static int DetectAddressParse2(const DetectEngineCtx *de_ctx, DetectAddressHead *gh, DetectAddressHead *ghn, const char *s, int negate, ResolvedVariablesList *var_list, int recur); @@ -162,7 +161,7 @@ void DetectAddressPrintList(DetectAddress *head) */ static void DetectAddressCleanupList(DetectAddress *head) { - for (DetectAddress *cur = head; cur != NULL; ) { + for (DetectAddress *cur = head; cur != NULL;) { DetectAddress *next = cur->next; cur->next = NULL; DetectAddressFree(cur); @@ -232,8 +231,7 @@ static DetectAddress *GetHeadPtr(DetectAddressHead *gh, DetectAddress *new) * \retval -1 On error. * \retval 0 Not inserted, memory of new is freed. */ -static int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, - DetectAddress *new) +static int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, DetectAddress *new) { DetectAddress *head = NULL; DetectAddress *cur = NULL; @@ -290,8 +288,8 @@ static int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, } return 1; - /* alright, those were the simple cases, lets handle the more - * complex ones now */ + /* alright, those were the simple cases, lets handle the more + * complex ones now */ } else if (r == ADDRESS_ES) { c = NULL; r = DetectAddressCut(de_ctx, cur, new, &c); @@ -327,7 +325,7 @@ static int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, return 1; } else if (r == ADDRESS_GE) { c = NULL; - r = DetectAddressCut(de_ctx, cur,new,&c); + r = DetectAddressCut(de_ctx, cur, new, &c); if (r == -1) goto error; @@ -339,7 +337,7 @@ static int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, } } - /* head is NULL, so get a group and set head to it */ + /* head is NULL, so get a group and set head to it */ } else { head = new; if (SetHeadPtr(gh, head) < 0) { @@ -430,18 +428,18 @@ static int DetectAddressParseString(DetectAddress *dd, const char *str) dd->ip.family = AF_INET; - if ((mask = strchr(ip, '/')) != NULL) { + if ((mask = strchr(ip, '/')) != NULL) { /* 1.2.3.4/xxx format (either dotted or cidr notation */ ip[mask - ip] = '\0'; mask++; uint32_t ip4addr = 0; uint32_t netmask = 0; - if ((strchr (mask, '.')) == NULL) { + if ((strchr(mask, '.')) == NULL) { /* 1.2.3.4/24 format */ for (size_t u = 0; u < strlen(mask); u++) { - if(!isdigit((unsigned char)mask[u])) + if (!isdigit((unsigned char)mask[u])) goto error; } @@ -475,8 +473,8 @@ static int DetectAddressParseString(DetectAddress *dd, const char *str) ip4addr = in.s_addr; dd->ip.addr_data32[0] = dd->ip2.addr_data32[0] = ip4addr & netmask; - dd->ip2.addr_data32[0] |=~ netmask; - } else if ((ip2 = strchr(ip, '-')) != NULL) { + dd->ip2.addr_data32[0] |= ~netmask; + } else if ((ip2 = strchr(ip, '-')) != NULL) { /* 1.2.3.4-1.2.3.6 range format */ ip[ip2 - ip] = '\0'; ip2++; @@ -510,7 +508,7 @@ static int DetectAddressParseString(DetectAddress *dd, const char *str) dd->ip.family = AF_INET6; - if ((mask = strchr(ip, '/')) != NULL) { + if ((mask = strchr(ip, '/')) != NULL) { ip[mask - ip] = '\0'; mask++; @@ -531,11 +529,11 @@ static int DetectAddressParseString(DetectAddress *dd, const char *str) dd->ip2.addr_data32[2] = dd->ip.addr_data32[2] = ip6addr[2] & netmask[2]; dd->ip2.addr_data32[3] = dd->ip.addr_data32[3] = ip6addr[3] & netmask[3]; - dd->ip2.addr_data32[0] |=~ netmask[0]; - dd->ip2.addr_data32[1] |=~ netmask[1]; - dd->ip2.addr_data32[2] |=~ netmask[2]; - dd->ip2.addr_data32[3] |=~ netmask[3]; - } else if ((ip2 = strchr(ip, '-')) != NULL) { + dd->ip2.addr_data32[0] |= ~netmask[0]; + dd->ip2.addr_data32[1] |= ~netmask[1]; + dd->ip2.addr_data32[2] |= ~netmask[2]; + dd->ip2.addr_data32[3] |= ~netmask[3]; + } else if ((ip2 = strchr(ip, '-')) != NULL) { /* 2001::1-2001::4 range format */ ip[ip2 - ip] = '\0'; ip2++; @@ -561,7 +559,6 @@ static int DetectAddressParseString(DetectAddress *dd, const char *str) memcpy(&dd->ip.address, &in6.s6_addr, sizeof(dd->ip.address)); memcpy(&dd->ip2.address, &in6.s6_addr, sizeof(dd->ip2.address)); } - } BUG_ON(dd->ip.family == 0); @@ -682,7 +679,7 @@ static int DetectAddressSetup(DetectAddressHead *gh, const char *s) DetectAddressFree(ad); return -1; } - SCLogDebug("r %d",r); + SCLogDebug("r %d", r); return 0; } @@ -760,7 +757,8 @@ static int DetectAddressParseInternal(const DetectEngineCtx *de_ctx, DetectAddre /* normal block */ SCLogDebug("normal block"); - if (DetectAddressParse2(de_ctx, gh, ghn, address, (negate + n_set) % 2, var_list, recur) < 0) + if (DetectAddressParse2(de_ctx, gh, ghn, address, (negate + n_set) % 2, + var_list, recur) < 0) goto error; } else { /* negated block @@ -773,7 +771,8 @@ static int DetectAddressParseInternal(const DetectEngineCtx *de_ctx, DetectAddre DetectAddressHead tmp_gh = { NULL, NULL }; DetectAddressHead tmp_ghn = { NULL, NULL }; - if (DetectAddressParse2(de_ctx, &tmp_gh, &tmp_ghn, address, 0, var_list, recur) < 0) { + if (DetectAddressParse2( + de_ctx, &tmp_gh, &tmp_ghn, address, 0, var_list, recur) < 0) { DetectAddressHeadCleanup(&tmp_gh); DetectAddressHeadCleanup(&tmp_ghn); goto error; @@ -845,8 +844,8 @@ static int DetectAddressParseInternal(const DetectEngineCtx *de_ctx, DetectAddre } else if (d_set == 1) { address[x - 1] = '\0'; - rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, - SC_RULE_VARS_ADDRESS_GROUPS); + rule_var_address = + SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -864,8 +863,8 @@ static int DetectAddressParseInternal(const DetectEngineCtx *de_ctx, DetectAddre temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3); if (unlikely(temp_rule_var_address == NULL)) goto error; - snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, - "[%s]", rule_var_address); + snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", + rule_var_address); } else { temp_rule_var_address = SCStrdup(rule_var_address); if (unlikely(temp_rule_var_address == NULL)) @@ -913,8 +912,8 @@ static int DetectAddressParseInternal(const DetectEngineCtx *de_ctx, DetectAddre } if (d_set == 1) { - rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, - SC_RULE_VARS_ADDRESS_GROUPS); + rule_var_address = + SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -932,8 +931,8 @@ static int DetectAddressParseInternal(const DetectEngineCtx *de_ctx, DetectAddre temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3); if (unlikely(temp_rule_var_address == NULL)) goto error; - snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, - "[%s]", rule_var_address); + snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", + rule_var_address); } else { temp_rule_var_address = SCStrdup(rule_var_address); if (unlikely(temp_rule_var_address == NULL)) @@ -1056,8 +1055,7 @@ int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn) DetectAddress *ag, *ag2; int r = 0; - SCLogDebug("gh->ipv4_head %p, ghn->ipv4_head %p", gh->ipv4_head, - ghn->ipv4_head); + SCLogDebug("gh->ipv4_head %p, ghn->ipv4_head %p", gh->ipv4_head, ghn->ipv4_head); /* check if the negated list covers the entire ip space. If so * the user screwed up the rules/vars. */ @@ -1133,7 +1131,7 @@ int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn) DetectAddressPrint(ag); int applied = 0; - for (ag2 = gh->ipv4_head; ag2 != NULL; ) { + for (ag2 = gh->ipv4_head; ag2 != NULL;) { SCLogDebug("ag2 %p", ag2); DetectAddressPrint(ag2); @@ -1163,7 +1161,7 @@ int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn) /* ... and the same for ipv6 */ for (ag = ghn->ipv6_head; ag != NULL; ag = ag->next) { int applied = 0; - for (ag2 = gh->ipv6_head; ag2 != NULL; ) { + for (ag2 = gh->ipv6_head; ag2 != NULL;) { r = DetectAddressCmp(ag, ag2); if (r == ADDRESS_EQ || r == ADDRESS_EB) { /* XXX more ??? */ if (ag2->prev != NULL) @@ -1247,7 +1245,7 @@ int DetectAddressTestConfVars(void) DetectAddressHead *ghn = NULL; ConfNode *seq_node; - TAILQ_FOREACH(seq_node, &address_vars_node->head, next) { + TAILQ_FOREACH (seq_node, &address_vars_node->head, next) { SCLogDebug("Testing %s - %s", seq_node->name, seq_node->val); gh = DetectAddressHeadInit(); @@ -1294,7 +1292,7 @@ int DetectAddressTestConfVars(void) } return 0; - error: +error: if (gh != NULL) DetectAddressHeadFree(gh); if (ghn != NULL) @@ -1302,7 +1300,7 @@ int DetectAddressTestConfVars(void) return -1; } -#include "util-hash-lookup3.h" +#include "util/hash-lookup3.h" typedef struct DetectAddressMap_ { char *string; @@ -1321,8 +1319,7 @@ static uint32_t DetectAddressMapHashFunc(HashListTable *ht, void *data, uint16_t return hash; } -static char DetectAddressMapCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) +static char DetectAddressMapCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { DetectAddressMap *map1 = (DetectAddressMap *)data1; DetectAddressMap *map2 = (DetectAddressMap *)data2; @@ -1343,9 +1340,8 @@ static void DetectAddressMapFreeFunc(void *data) int DetectAddressMapInit(DetectEngineCtx *de_ctx) { - de_ctx->address_table = HashListTableInit(4096, DetectAddressMapHashFunc, - DetectAddressMapCompareFunc, - DetectAddressMapFreeFunc); + de_ctx->address_table = HashListTableInit( + 4096, DetectAddressMapHashFunc, DetectAddressMapCompareFunc, DetectAddressMapFreeFunc); if (de_ctx->address_table == NULL) return -1; @@ -1363,7 +1359,7 @@ void DetectAddressMapFree(DetectEngineCtx *de_ctx) } static int DetectAddressMapAdd(DetectEngineCtx *de_ctx, const char *string, - DetectAddressHead *address, bool contains_negation) + DetectAddressHead *address, bool contains_negation) { DetectAddressMap *map = SCCalloc(1, sizeof(*map)); if (map == NULL) @@ -1381,13 +1377,11 @@ static int DetectAddressMapAdd(DetectEngineCtx *de_ctx, const char *string, return 0; } -static const DetectAddressMap *DetectAddressMapLookup(DetectEngineCtx *de_ctx, - const char *string) +static const DetectAddressMap *DetectAddressMapLookup(DetectEngineCtx *de_ctx, const char *string) { DetectAddressMap map = { (char *)string, NULL, false }; - const DetectAddressMap *res = HashListTableLookup(de_ctx->address_table, - &map, 0); + const DetectAddressMap *res = HashListTableLookup(de_ctx->address_table, &map, 0); return res; } @@ -1405,8 +1399,7 @@ static const DetectAddressMap *DetectAddressMapLookup(DetectEngineCtx *de_ctx, * \retval 0 On success. Did not contain negation. * \retval -1 On failure. */ -int DetectAddressParse(const DetectEngineCtx *de_ctx, - DetectAddressHead *gh, const char *str) +int DetectAddressParse(const DetectEngineCtx *de_ctx, DetectAddressHead *gh, const char *str) { SCLogDebug("gh %p, str %s", gh, str); @@ -1428,8 +1421,7 @@ int DetectAddressParse(const DetectEngineCtx *de_ctx, return -1; } - SCLogDebug("gh->ipv4_head %p, ghn->ipv4_head %p", gh->ipv4_head, - ghn->ipv4_head); + SCLogDebug("gh->ipv4_head %p, ghn->ipv4_head %p", gh->ipv4_head, ghn->ipv4_head); bool contains_negation = (ghn->ipv4_head != NULL || ghn->ipv6_head != NULL); @@ -1445,8 +1437,8 @@ int DetectAddressParse(const DetectEngineCtx *de_ctx, return contains_negation ? 1 : 0; } -const DetectAddressHead *DetectParseAddress(DetectEngineCtx *de_ctx, - const char *string, bool *contains_negation) +const DetectAddressHead *DetectParseAddress( + DetectEngineCtx *de_ctx, const char *string, bool *contains_negation) { const DetectAddressMap *res = DetectAddressMapLookup(de_ctx, string); if (res != NULL) { @@ -1471,8 +1463,7 @@ const DetectAddressHead *DetectParseAddress(DetectEngineCtx *de_ctx, *contains_negation = false; } - DetectAddressMapAdd((DetectEngineCtx *)de_ctx, string, head, - *contains_negation); + DetectAddressMapAdd((DetectEngineCtx *)de_ctx, string, head, *contains_negation); return head; } @@ -1514,8 +1505,7 @@ void DetectAddressHeadCleanup(DetectAddressHead *gh) * \retval 0 On success. * \retval -1 On failure. */ -int DetectAddressCut(DetectEngineCtx *de_ctx, DetectAddress *a, - DetectAddress *b, DetectAddress **c) +int DetectAddressCut(DetectEngineCtx *de_ctx, DetectAddress *a, DetectAddress *b, DetectAddress **c) { if (a->ip.family == AF_INET) return DetectAddressCutIPv4(de_ctx, a, b, c); @@ -1599,8 +1589,8 @@ int DetectAddressCmp(DetectAddress *a, DetectAddress *b) * * \todo array should be ordered, so we can break out of the loop */ -int DetectAddressMatchIPv4(const DetectMatchAddressIPv4 *addrs, - uint16_t addrs_cnt, const Address *a) +int DetectAddressMatchIPv4( + const DetectMatchAddressIPv4 *addrs, uint16_t addrs_cnt, const Address *a) { SCEnter(); @@ -1632,8 +1622,8 @@ int DetectAddressMatchIPv4(const DetectMatchAddressIPv4 *addrs, * * \todo array should be ordered, so we can break out of the loop */ -int DetectAddressMatchIPv6(const DetectMatchAddressIPv6 *addrs, - uint16_t addrs_cnt, const Address *a) +int DetectAddressMatchIPv6( + const DetectMatchAddressIPv6 *addrs, uint16_t addrs_cnt, const Address *a) { SCEnter(); @@ -1724,8 +1714,8 @@ static int DetectAddressMatch(DetectAddress *dd, Address *a) SCReturnInt(0); } - //DetectAddressPrint(dd); - //AddressDebugPrint(a); + // DetectAddressPrint(dd); + // AddressDebugPrint(a); switch (a->family) { case AF_INET: @@ -1733,8 +1723,7 @@ static int DetectAddressMatch(DetectAddress *dd, Address *a) /* XXX figure out a way to not need to do this SCNtohl if we switch to * Address inside DetectAddressData we can do uint8_t checks */ if (SCNtohl(a->addr_data32[0]) >= SCNtohl(dd->ip.addr_data32[0]) && - SCNtohl(a->addr_data32[0]) <= SCNtohl(dd->ip2.addr_data32[0])) - { + SCNtohl(a->addr_data32[0]) <= SCNtohl(dd->ip2.addr_data32[0])) { SCReturnInt(1); } else { SCReturnInt(0); @@ -1742,9 +1731,7 @@ static int DetectAddressMatch(DetectAddress *dd, Address *a) break; case AF_INET6: - if (AddressIPv6Ge(a, &dd->ip) == 1 && - AddressIPv6Le(a, &dd->ip2) == 1) - { + if (AddressIPv6Ge(a, &dd->ip) == 1 && AddressIPv6Le(a, &dd->ip2) == 1) { SCReturnInt(1); } else { SCReturnInt(0); @@ -1783,7 +1770,7 @@ static void DetectAddressPrint(DetectAddress *gr) PrintInet(AF_INET, &in, mask, sizeof(mask)); SCLogDebug("%s/%s", ip, mask); -// printf("%s/%s", ip, mask); + // printf("%s/%s", ip, mask); } else if (gr->ip.family == AF_INET6) { struct in6_addr in6; char ip[66], mask[66]; @@ -1794,7 +1781,7 @@ static void DetectAddressPrint(DetectAddress *gr) PrintInet(AF_INET6, &in6, mask, sizeof(mask)); SCLogDebug("%s/%s", ip, mask); -// printf("%s/%s", ip, mask); + // printf("%s/%s", ip, mask); } return; @@ -1829,8 +1816,8 @@ DetectAddress *DetectAddressLookupInHead(const DetectAddressHead *gh, Address *a g = gh->ipv6_head; } - for ( ; g != NULL; g = g->next) { - if (DetectAddressMatch(g,a) == 1) { + for (; g != NULL; g = g->next) { + if (DetectAddressMatch(g, a) == 1) { SCReturnPtr(g, "DetectAddress"); } } @@ -1849,7 +1836,7 @@ static bool UTHValidateDetectAddress(DetectAddress *ad, const char *one, const c if (ad == NULL) return false; - switch(ad->ip.family) { + switch (ad->ip.family) { case AF_INET: PrintInet(AF_INET, (const void *)&ad->ip.addr_data32[0], str1, sizeof(str1)); SCLogDebug("%s", str1); @@ -1897,7 +1884,8 @@ typedef struct UTHValidateDetectAddressHeadRange_ { const char *two; } UTHValidateDetectAddressHeadRange; -static int UTHValidateDetectAddressHead(DetectAddressHead *gh, int nranges, UTHValidateDetectAddressHeadRange *expectations) +static int UTHValidateDetectAddressHead( + DetectAddressHead *gh, int nranges, UTHValidateDetectAddressHeadRange *expectations) { int expect = nranges; int have = 0; @@ -1944,11 +1932,11 @@ static int AddressTestParse02(void) if (dd) { if (dd->ip2.addr_data32[0] != SCNtohl(16909060) || - dd->ip.addr_data32[0] != SCNtohl(16909060)) { + dd->ip.addr_data32[0] != SCNtohl(16909060)) { result = 0; } - printf("ip %"PRIu32", ip2 %"PRIu32"\n", dd->ip.addr_data32[0], dd->ip2.addr_data32[0]); + printf("ip %" PRIu32 ", ip2 %" PRIu32 "\n", dd->ip.addr_data32[0], dd->ip2.addr_data32[0]); DetectAddressFree(dd); return result; } @@ -2022,7 +2010,7 @@ static int AddressTestParse06(void) if (dd) { if (dd->ip2.addr_data32[0] != SCNtohl(16909311) || - dd->ip.addr_data32[0] != SCNtohl(16909056)) { + dd->ip.addr_data32[0] != SCNtohl(16909056)) { result = 0; } @@ -2052,10 +2040,11 @@ static int AddressTestParse08(void) if (dd) { if (dd->ip.addr_data32[0] != SCNtohl(536870912) || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || - dd->ip2.addr_data32[0] != SCNtohl(1073741823) || dd->ip2.addr_data32[1] != 0xFFFFFFFF || - dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { + dd->ip2.addr_data32[0] != SCNtohl(1073741823) || + dd->ip2.addr_data32[1] != 0xFFFFFFFF || dd->ip2.addr_data32[2] != 0xFFFFFFFF || + dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; } @@ -2084,12 +2073,13 @@ static int AddressTestParse10(void) int result = 1; DetectAddress *dd = DetectAddressParseSingle("2001::/128"); - if (dd) { + if (dd) { if (dd->ip.addr_data32[0] != SCNtohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || - dd->ip2.addr_data32[0] != SCNtohl(536936448) || dd->ip2.addr_data32[1] != 0x00000000 || - dd->ip2.addr_data32[2] != 0x00000000 || dd->ip2.addr_data32[3] != 0x00000000) { + dd->ip2.addr_data32[0] != SCNtohl(536936448) || + dd->ip2.addr_data32[1] != 0x00000000 || dd->ip2.addr_data32[2] != 0x00000000 || + dd->ip2.addr_data32[3] != 0x00000000) { DetectAddressPrint(dd); result = 0; } @@ -2120,10 +2110,11 @@ static int AddressTestParse12(void) if (dd) { if (dd->ip.addr_data32[0] != SCNtohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || - dd->ip2.addr_data32[0] != SCNtohl(536936448) || dd->ip2.addr_data32[1] != SCNtohl(65535) || - dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { + dd->ip2.addr_data32[0] != SCNtohl(536936448) || + dd->ip2.addr_data32[1] != SCNtohl(65535) || dd->ip2.addr_data32[2] != 0xFFFFFFFF || + dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; } @@ -2153,10 +2144,11 @@ static int AddressTestParse14(void) if (dd) { if (dd->ip.addr_data32[0] != SCNtohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || - dd->ip2.addr_data32[0] != SCNtohl(537001983) || dd->ip2.addr_data32[1] != 0xFFFFFFFF || - dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { + dd->ip2.addr_data32[0] != SCNtohl(537001983) || + dd->ip2.addr_data32[1] != 0xFFFFFFFF || dd->ip2.addr_data32[2] != 0xFFFFFFFF || + dd->ip2.addr_data32[3] != 0xFFFFFFFF) { result = 0; } @@ -2186,10 +2178,10 @@ static int AddressTestParse16(void) if (dd) { if (dd->ip.addr_data32[0] != 0x00000000 || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || - dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || - dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { + dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || + dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { result = 0; } @@ -2219,7 +2211,7 @@ static int AddressTestParse18(void) if (dd) { if (dd->ip2.addr_data32[0] != SCNtohl(16909062) || - dd->ip.addr_data32[0] != SCNtohl(16909060)) { + dd->ip.addr_data32[0] != SCNtohl(16909060)) { result = 0; } @@ -2261,10 +2253,11 @@ static int AddressTestParse21(void) if (dd) { if (dd->ip.addr_data32[0] != SCNtohl(536936448) || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != SCNtohl(1) || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != SCNtohl(1) || - dd->ip2.addr_data32[0] != SCNtohl(536936448) || dd->ip2.addr_data32[1] != 0x00000000 || - dd->ip2.addr_data32[2] != 0x00000000 || dd->ip2.addr_data32[3] != SCNtohl(4)) { + dd->ip2.addr_data32[0] != SCNtohl(536936448) || + dd->ip2.addr_data32[1] != 0x00000000 || dd->ip2.addr_data32[2] != 0x00000000 || + dd->ip2.addr_data32[3] != SCNtohl(4)) { result = 0; } @@ -2326,8 +2319,7 @@ static int AddressTestParse26(void) int r = DetectAddressParse(NULL, gh, "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[" "1.2.3.4" - "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" - ); + "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"); FAIL_IF_NOT(r == 0); DetectAddressHeadFree(gh); gh = DetectAddressHeadInit(); @@ -2336,8 +2328,7 @@ static int AddressTestParse26(void) r = DetectAddressParse(NULL, gh, "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[" "1.2.3.4" - "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" - ); + "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"); FAIL_IF(r == 0); DetectAddressHeadFree(gh); PASS; @@ -2361,8 +2352,7 @@ static int AddressTestParse28(void) DetectAddress *dd = DetectAddressParseSingle("!1.2.3.4"); if (dd) { - if (dd->flags & ADDRESS_FLAG_NOT && - dd->ip.addr_data32[0] == SCNtohl(16909060)) { + if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == SCNtohl(16909060)) { result = 1; } @@ -2391,9 +2381,8 @@ static int AddressTestParse30(void) DetectAddress *dd = DetectAddressParseSingle("!1.2.3.4/24"); if (dd) { - if (dd->flags & ADDRESS_FLAG_NOT && - dd->ip.addr_data32[0] == SCNtohl(16909056) && - dd->ip2.addr_data32[0] == SCNtohl(16909311)) { + if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == SCNtohl(16909056) && + dd->ip2.addr_data32[0] == SCNtohl(16909311)) { result = 1; } @@ -2437,9 +2426,9 @@ static int AddressTestParse33(void) DetectAddress *dd = DetectAddressParseSingle("!2001::1"); if (dd) { - if (dd->flags & ADDRESS_FLAG_NOT && - dd->ip.addr_data32[0] == SCNtohl(536936448) && dd->ip.addr_data32[1] == 0x00000000 && - dd->ip.addr_data32[2] == 0x00000000 && dd->ip.addr_data32[3] == SCNtohl(1)) { + if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == SCNtohl(536936448) && + dd->ip.addr_data32[1] == 0x00000000 && dd->ip.addr_data32[2] == 0x00000000 && + dd->ip.addr_data32[3] == SCNtohl(1)) { result = 1; } @@ -2468,12 +2457,13 @@ static int AddressTestParse35(void) DetectAddress *dd = DetectAddressParseSingle("!2001::/16"); if (dd) { - if (dd->flags & ADDRESS_FLAG_NOT && - dd->ip.addr_data32[0] == SCNtohl(536936448) && dd->ip.addr_data32[1] == 0x00000000 && - dd->ip.addr_data32[2] == 0x00000000 && dd->ip.addr_data32[3] == 0x00000000 && + if (dd->flags & ADDRESS_FLAG_NOT && dd->ip.addr_data32[0] == SCNtohl(536936448) && + dd->ip.addr_data32[1] == 0x00000000 && dd->ip.addr_data32[2] == 0x00000000 && + dd->ip.addr_data32[3] == 0x00000000 && - dd->ip2.addr_data32[0] == SCNtohl(537001983) && dd->ip2.addr_data32[1] == 0xFFFFFFFF && - dd->ip2.addr_data32[2] == 0xFFFFFFFF && dd->ip2.addr_data32[3] == 0xFFFFFFFF) { + dd->ip2.addr_data32[0] == SCNtohl(537001983) && + dd->ip2.addr_data32[1] == 0xFFFFFFFF && dd->ip2.addr_data32[2] == 0xFFFFFFFF && + dd->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } @@ -2491,10 +2481,10 @@ static int AddressTestParse36(void) if (dd) { if (dd->ip.addr_data32[0] != SCNtohl(0xFFFF0000) || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || - dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || - dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { + dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || + dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; @@ -2515,10 +2505,10 @@ static int AddressTestParse37(void) if (dd) { if (dd->ip.addr_data32[0] != 0x00000000 || dd->ip.addr_data32[1] != 0x00000000 || - dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || + dd->ip.addr_data32[2] != 0x00000000 || dd->ip.addr_data32[3] != 0x00000000 || - dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || - dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { + dd->ip2.addr_data32[0] != 0xFFFFFFFF || dd->ip2.addr_data32[1] != 0xFFFFFFFF || + dd->ip2.addr_data32[2] != 0xFFFFFFFF || dd->ip2.addr_data32[3] != 0xFFFFFFFF) { DetectAddressPrint(dd); result = 0; } @@ -2812,9 +2802,11 @@ static int AddressTestCmp01(void) int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; @@ -2824,8 +2816,10 @@ static int AddressTestCmp01(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2835,9 +2829,11 @@ static int AddressTestCmp02(void) int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.0.0"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_EB) result = 0; @@ -2847,8 +2843,10 @@ static int AddressTestCmp02(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2858,9 +2856,11 @@ static int AddressTestCmp03(void) int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.0.0"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_ES) result = 0; @@ -2870,8 +2870,10 @@ static int AddressTestCmp03(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2881,9 +2883,11 @@ static int AddressTestCmp04(void) int result = 1; da = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_LT) result = 0; @@ -2893,8 +2897,10 @@ static int AddressTestCmp04(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2904,9 +2910,11 @@ static int AddressTestCmp05(void) int result = 1; da = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.255.0"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_GT) result = 0; @@ -2916,8 +2924,10 @@ static int AddressTestCmp05(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2927,9 +2937,11 @@ static int AddressTestCmp06(void) int result = 1; da = DetectAddressParseSingle("192.168.1.0/255.255.0.0"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.0.0/255.255.0.0"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; @@ -2939,8 +2951,10 @@ static int AddressTestCmp06(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2950,9 +2964,11 @@ static int AddressTestCmpIPv407(void) int result = 1; da = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.1.128-192.168.2.128"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_LE) result = 0; @@ -2962,8 +2978,10 @@ static int AddressTestCmpIPv407(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2973,9 +2991,11 @@ static int AddressTestCmpIPv408(void) int result = 1; da = DetectAddressParseSingle("192.168.1.128-192.168.2.128"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("192.168.1.0/255.255.255.0"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_GE) result = 0; @@ -2985,8 +3005,10 @@ static int AddressTestCmpIPv408(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -2996,9 +3018,11 @@ static int AddressTestCmp07(void) int result = 1; da = DetectAddressParseSingle("2001::/3"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("2001::1/3"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; @@ -3008,8 +3032,10 @@ static int AddressTestCmp07(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -3019,9 +3045,11 @@ static int AddressTestCmp08(void) int result = 1; da = DetectAddressParseSingle("2001::/3"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("2001::/8"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_EB) result = 0; @@ -3031,8 +3059,10 @@ static int AddressTestCmp08(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -3042,9 +3072,11 @@ static int AddressTestCmp09(void) int result = 1; da = DetectAddressParseSingle("2001::/8"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("2001::/3"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_ES) result = 0; @@ -3054,8 +3086,10 @@ static int AddressTestCmp09(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -3065,9 +3099,11 @@ static int AddressTestCmp10(void) int result = 1; da = DetectAddressParseSingle("2001:1:2:3:0:0:0:0/64"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("2001:1:2:4:0:0:0:0/64"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_LT) result = 0; @@ -3077,8 +3113,10 @@ static int AddressTestCmp10(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -3088,9 +3126,11 @@ static int AddressTestCmp11(void) int result = 1; da = DetectAddressParseSingle("2001:1:2:4:0:0:0:0/64"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("2001:1:2:3:0:0:0:0/64"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_GT) result = 0; @@ -3100,8 +3140,10 @@ static int AddressTestCmp11(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -3111,9 +3153,11 @@ static int AddressTestCmp12(void) int result = 1; da = DetectAddressParseSingle("2001:1:2:3:1:0:0:0/64"); - if (da == NULL) goto error; + if (da == NULL) + goto error; db = DetectAddressParseSingle("2001:1:2:3:2:0:0:0/64"); - if (db == NULL) goto error; + if (db == NULL) + goto error; if (DetectAddressCmp(da, db) != ADDRESS_EQ) result = 0; @@ -3123,8 +3167,10 @@ static int AddressTestCmp12(void) return result; error: - if (da) DetectAddressFree(da); - if (db) DetectAddressFree(db); + if (da) + DetectAddressFree(da); + if (db) + DetectAddressFree(db); return 0; } @@ -3169,8 +3215,8 @@ static int AddressTestAddressGroupSetup03(void) DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.3"); - if (r == 0 && gh->ipv4_head != prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { + if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && + gh->ipv4_head->next == prev_head) { result = 1; } } @@ -3191,13 +3237,13 @@ static int AddressTestAddressGroupSetup04(void) DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.3"); - if (r == 0 && gh->ipv4_head != prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { + if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && + gh->ipv4_head->next == prev_head) { DetectAddress *ph = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.2"); - if (r == 0 && gh->ipv4_head != ph && - gh->ipv4_head != NULL && gh->ipv4_head->next == ph) { + if (r == 0 && gh->ipv4_head != ph && gh->ipv4_head != NULL && + gh->ipv4_head->next == ph) { result = 1; } } @@ -3219,13 +3265,13 @@ static int AddressTestAddressGroupSetup05(void) DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.3"); - if (r == 0 && gh->ipv4_head == prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { + if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && + gh->ipv4_head->next != prev_head) { DetectAddress *ph = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.4"); - if (r == 0 && gh->ipv4_head == ph && - gh->ipv4_head != NULL && gh->ipv4_head->next != ph) { + if (r == 0 && gh->ipv4_head == ph && gh->ipv4_head != NULL && + gh->ipv4_head->next != ph) { result = 1; } } @@ -3247,8 +3293,8 @@ static int AddressTestAddressGroupSetup06(void) DetectAddress *prev_head = gh->ipv4_head; r = DetectAddressParse(NULL, gh, "1.2.3.2"); - if (r == 0 && gh->ipv4_head == prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next == NULL) { + if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && + gh->ipv4_head->next == NULL) { result = 1; } } @@ -3267,9 +3313,8 @@ static int AddressTestAddressGroupSetup07(void) int r = DetectAddressParse(NULL, gh, "10.0.0.0/8"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(NULL, gh, "10.10.10.10"); - if (r == 0 && gh->ipv4_head != NULL && - gh->ipv4_head->next != NULL && - gh->ipv4_head->next->next != NULL) { + if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && + gh->ipv4_head->next->next != NULL) { result = 1; } } @@ -3288,9 +3333,8 @@ static int AddressTestAddressGroupSetup08(void) int r = DetectAddressParse(NULL, gh, "10.10.10.10"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(NULL, gh, "10.0.0.0/8"); - if (r == 0 && gh->ipv4_head != NULL && - gh->ipv4_head->next != NULL && - gh->ipv4_head->next->next != NULL) { + if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && + gh->ipv4_head->next->next != NULL) { result = 1; } } @@ -3309,9 +3353,8 @@ static int AddressTestAddressGroupSetup09(void) int r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); - if (r == 0 && gh->ipv4_head != NULL && - gh->ipv4_head->next != NULL && - gh->ipv4_head->next->next != NULL) { + if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && + gh->ipv4_head->next->next != NULL) { result = 1; } } @@ -3330,9 +3373,8 @@ static int AddressTestAddressGroupSetup10(void) int r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0 && gh->ipv4_head != NULL) { r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); - if (r == 0 && gh->ipv4_head != NULL && - gh->ipv4_head->next != NULL && - gh->ipv4_head->next->next != NULL) { + if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && + gh->ipv4_head->next->next != NULL) { result = 1; } } @@ -3354,9 +3396,8 @@ static int AddressTestAddressGroupSetup11(void) if (r == 0) { r = DetectAddressParse(NULL, gh, "0.0.0.0/0"); if (r == 0) { - DetectAddress *one = gh->ipv4_head, *two = one->next, - *three = two->next, *four = three->next, - *five = four->next; + DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, + *four = three->next, *five = four->next; /* result should be: * 0.0.0.0/10.10.9.255 @@ -3365,11 +3406,16 @@ static int AddressTestAddressGroupSetup11(void) * 10.10.11.0/10.10.11.1 * 10.10.11.2/255.255.255.255 */ - if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == SCNtohl(168430079) && - two->ip.addr_data32[0] == SCNtohl(168430080) && two->ip2.addr_data32[0] == SCNtohl(168430089) && - three->ip.addr_data32[0] == SCNtohl(168430090) && three->ip2.addr_data32[0] == SCNtohl(168430335) && - four->ip.addr_data32[0] == SCNtohl(168430336) && four->ip2.addr_data32[0] == SCNtohl(168430337) && - five->ip.addr_data32[0] == SCNtohl(168430338) && five->ip2.addr_data32[0] == 0xFFFFFFFF) { + if (one->ip.addr_data32[0] == 0x00000000 && + one->ip2.addr_data32[0] == SCNtohl(168430079) && + two->ip.addr_data32[0] == SCNtohl(168430080) && + two->ip2.addr_data32[0] == SCNtohl(168430089) && + three->ip.addr_data32[0] == SCNtohl(168430090) && + three->ip2.addr_data32[0] == SCNtohl(168430335) && + four->ip.addr_data32[0] == SCNtohl(168430336) && + four->ip2.addr_data32[0] == SCNtohl(168430337) && + five->ip.addr_data32[0] == SCNtohl(168430338) && + five->ip2.addr_data32[0] == 0xFFFFFFFF) { result = 1; } } @@ -3381,7 +3427,7 @@ static int AddressTestAddressGroupSetup11(void) return result; } -static int AddressTestAddressGroupSetup12 (void) +static int AddressTestAddressGroupSetup12(void) { int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); @@ -3393,9 +3439,8 @@ static int AddressTestAddressGroupSetup12 (void) if (r == 0) { r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { - DetectAddress *one = gh->ipv4_head, *two = one->next, - *three = two->next, *four = three->next, - *five = four->next; + DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, + *four = three->next, *five = four->next; /* result should be: * 0.0.0.0/10.10.9.255 @@ -3404,11 +3449,16 @@ static int AddressTestAddressGroupSetup12 (void) * 10.10.11.0/10.10.11.1 * 10.10.11.2/255.255.255.255 */ - if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == SCNtohl(168430079) && - two->ip.addr_data32[0] == SCNtohl(168430080) && two->ip2.addr_data32[0] == SCNtohl(168430089) && - three->ip.addr_data32[0] == SCNtohl(168430090) && three->ip2.addr_data32[0] == SCNtohl(168430335) && - four->ip.addr_data32[0] == SCNtohl(168430336) && four->ip2.addr_data32[0] == SCNtohl(168430337) && - five->ip.addr_data32[0] == SCNtohl(168430338) && five->ip2.addr_data32[0] == 0xFFFFFFFF) { + if (one->ip.addr_data32[0] == 0x00000000 && + one->ip2.addr_data32[0] == SCNtohl(168430079) && + two->ip.addr_data32[0] == SCNtohl(168430080) && + two->ip2.addr_data32[0] == SCNtohl(168430089) && + three->ip.addr_data32[0] == SCNtohl(168430090) && + three->ip2.addr_data32[0] == SCNtohl(168430335) && + four->ip.addr_data32[0] == SCNtohl(168430336) && + four->ip2.addr_data32[0] == SCNtohl(168430337) && + five->ip.addr_data32[0] == SCNtohl(168430338) && + five->ip2.addr_data32[0] == 0xFFFFFFFF) { result = 1; } } @@ -3432,9 +3482,8 @@ static int AddressTestAddressGroupSetup13(void) if (r == 0) { r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { - DetectAddress *one = gh->ipv4_head, *two = one->next, - *three = two->next, *four = three->next, - *five = four->next; + DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, + *four = three->next, *five = four->next; /* result should be: * 0.0.0.0/10.10.9.255 @@ -3443,11 +3492,16 @@ static int AddressTestAddressGroupSetup13(void) * 10.10.11.0/10.10.11.1 * 10.10.11.2/255.255.255.255 */ - if (one->ip.addr_data32[0] == 0x00000000 && one->ip2.addr_data32[0] == SCNtohl(168430079) && - two->ip.addr_data32[0] == SCNtohl(168430080) && two->ip2.addr_data32[0] == SCNtohl(168430089) && - three->ip.addr_data32[0] == SCNtohl(168430090) && three->ip2.addr_data32[0] == SCNtohl(168430335) && - four->ip.addr_data32[0] == SCNtohl(168430336) && four->ip2.addr_data32[0] == SCNtohl(168430337) && - five->ip.addr_data32[0] == SCNtohl(168430338) && five->ip2.addr_data32[0] == 0xFFFFFFFF) { + if (one->ip.addr_data32[0] == 0x00000000 && + one->ip2.addr_data32[0] == SCNtohl(168430079) && + two->ip.addr_data32[0] == SCNtohl(168430080) && + two->ip2.addr_data32[0] == SCNtohl(168430089) && + three->ip.addr_data32[0] == SCNtohl(168430090) && + three->ip2.addr_data32[0] == SCNtohl(168430335) && + four->ip.addr_data32[0] == SCNtohl(168430336) && + four->ip2.addr_data32[0] == SCNtohl(168430337) && + five->ip.addr_data32[0] == SCNtohl(168430338) && + five->ip2.addr_data32[0] == 0xFFFFFFFF) { result = 1; } } @@ -3570,8 +3624,8 @@ static int AddressTestAddressGroupSetup16(void) DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::3"); - if (r == 0 && gh->ipv6_head != prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { + if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && + gh->ipv6_head->next == prev_head) { result = 1; } } @@ -3592,13 +3646,13 @@ static int AddressTestAddressGroupSetup17(void) DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::3"); - if (r == 0 && gh->ipv6_head != prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { + if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && + gh->ipv6_head->next == prev_head) { DetectAddress *ph = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::2"); - if (r == 0 && gh->ipv6_head != ph && - gh->ipv6_head != NULL && gh->ipv6_head->next == ph) { + if (r == 0 && gh->ipv6_head != ph && gh->ipv6_head != NULL && + gh->ipv6_head->next == ph) { result = 1; } } @@ -3620,13 +3674,13 @@ static int AddressTestAddressGroupSetup18(void) DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::3"); - if (r == 0 && gh->ipv6_head == prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { + if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && + gh->ipv6_head->next != prev_head) { DetectAddress *ph = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::4"); - if (r == 0 && gh->ipv6_head == ph && - gh->ipv6_head != NULL && gh->ipv6_head->next != ph) { + if (r == 0 && gh->ipv6_head == ph && gh->ipv6_head != NULL && + gh->ipv6_head->next != ph) { result = 1; } } @@ -3648,8 +3702,8 @@ static int AddressTestAddressGroupSetup19(void) DetectAddress *prev_head = gh->ipv6_head; r = DetectAddressParse(NULL, gh, "2001::2"); - if (r == 0 && gh->ipv6_head == prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next == NULL) { + if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && + gh->ipv6_head->next == NULL) { result = 1; } } @@ -3668,9 +3722,8 @@ static int AddressTestAddressGroupSetup20(void) int r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(NULL, gh, "2001::4"); - if (r == 0 && gh->ipv6_head != NULL && - gh->ipv6_head->next != NULL && - gh->ipv6_head->next->next != NULL) { + if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && + gh->ipv6_head->next->next != NULL) { result = 1; } } @@ -3689,9 +3742,8 @@ static int AddressTestAddressGroupSetup21(void) int r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(NULL, gh, "2000::/3"); - if (r == 0 && gh->ipv6_head != NULL && - gh->ipv6_head->next != NULL && - gh->ipv6_head->next->next != NULL) { + if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && + gh->ipv6_head->next->next != NULL) { result = 1; } } @@ -3710,9 +3762,8 @@ static int AddressTestAddressGroupSetup22(void) int r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); - if (r == 0 && gh->ipv6_head != NULL && - gh->ipv6_head->next != NULL && - gh->ipv6_head->next->next != NULL) { + if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && + gh->ipv6_head->next->next != NULL) { result = 1; } } @@ -3731,9 +3782,8 @@ static int AddressTestAddressGroupSetup23(void) int r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0 && gh->ipv6_head != NULL) { r = DetectAddressParse(NULL, gh, "2000::/3"); - if (r == 0 && gh->ipv6_head != NULL && - gh->ipv6_head->next != NULL && - gh->ipv6_head->next->next != NULL) { + if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && + gh->ipv6_head->next->next != NULL) { result = 1; } } @@ -3755,53 +3805,52 @@ static int AddressTestAddressGroupSetup24(void) if (r == 0) { r = DetectAddressParse(NULL, gh, "::/0"); if (r == 0) { - DetectAddress *one = gh->ipv6_head, *two = one->next, - *three = two->next, *four = three->next, - *five = four->next; + DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, + *four = three->next, *five = four->next; if (one->ip.addr_data32[0] == 0x00000000 && - one->ip.addr_data32[1] == 0x00000000 && - one->ip.addr_data32[2] == 0x00000000 && - one->ip.addr_data32[3] == 0x00000000 && - one->ip2.addr_data32[0] == SCNtohl(536870911) && - one->ip2.addr_data32[1] == 0xFFFFFFFF && - one->ip2.addr_data32[2] == 0xFFFFFFFF && - one->ip2.addr_data32[3] == 0xFFFFFFFF && - - two->ip.addr_data32[0] == SCNtohl(536870912) && - two->ip.addr_data32[1] == 0x00000000 && - two->ip.addr_data32[2] == 0x00000000 && - two->ip.addr_data32[3] == 0x00000000 && - two->ip2.addr_data32[0] == SCNtohl(536936448) && - two->ip2.addr_data32[1] == 0x00000000 && - two->ip2.addr_data32[2] == 0x00000000 && - two->ip2.addr_data32[3] == SCNtohl(3) && - - three->ip.addr_data32[0] == SCNtohl(536936448) && - three->ip.addr_data32[1] == 0x00000000 && - three->ip.addr_data32[2] == 0x00000000 && - three->ip.addr_data32[3] == SCNtohl(4) && - three->ip2.addr_data32[0] == SCNtohl(536936448) && - three->ip2.addr_data32[1] == 0x00000000 && - three->ip2.addr_data32[2] == 0x00000000 && - three->ip2.addr_data32[3] == SCNtohl(6) && - - four->ip.addr_data32[0] == SCNtohl(536936448) && - four->ip.addr_data32[1] == 0x00000000 && - four->ip.addr_data32[2] == 0x00000000 && - four->ip.addr_data32[3] == SCNtohl(7) && - four->ip2.addr_data32[0] == SCNtohl(1073741823) && - four->ip2.addr_data32[1] == 0xFFFFFFFF && - four->ip2.addr_data32[2] == 0xFFFFFFFF && - four->ip2.addr_data32[3] == 0xFFFFFFFF && - - five->ip.addr_data32[0] == SCNtohl(1073741824) && - five->ip.addr_data32[1] == 0x00000000 && - five->ip.addr_data32[2] == 0x00000000 && - five->ip.addr_data32[3] == 0x00000000 && - five->ip2.addr_data32[0] == 0xFFFFFFFF && - five->ip2.addr_data32[1] == 0xFFFFFFFF && - five->ip2.addr_data32[2] == 0xFFFFFFFF && - five->ip2.addr_data32[3] == 0xFFFFFFFF) { + one->ip.addr_data32[1] == 0x00000000 && + one->ip.addr_data32[2] == 0x00000000 && + one->ip.addr_data32[3] == 0x00000000 && + one->ip2.addr_data32[0] == SCNtohl(536870911) && + one->ip2.addr_data32[1] == 0xFFFFFFFF && + one->ip2.addr_data32[2] == 0xFFFFFFFF && + one->ip2.addr_data32[3] == 0xFFFFFFFF && + + two->ip.addr_data32[0] == SCNtohl(536870912) && + two->ip.addr_data32[1] == 0x00000000 && + two->ip.addr_data32[2] == 0x00000000 && + two->ip.addr_data32[3] == 0x00000000 && + two->ip2.addr_data32[0] == SCNtohl(536936448) && + two->ip2.addr_data32[1] == 0x00000000 && + two->ip2.addr_data32[2] == 0x00000000 && + two->ip2.addr_data32[3] == SCNtohl(3) && + + three->ip.addr_data32[0] == SCNtohl(536936448) && + three->ip.addr_data32[1] == 0x00000000 && + three->ip.addr_data32[2] == 0x00000000 && + three->ip.addr_data32[3] == SCNtohl(4) && + three->ip2.addr_data32[0] == SCNtohl(536936448) && + three->ip2.addr_data32[1] == 0x00000000 && + three->ip2.addr_data32[2] == 0x00000000 && + three->ip2.addr_data32[3] == SCNtohl(6) && + + four->ip.addr_data32[0] == SCNtohl(536936448) && + four->ip.addr_data32[1] == 0x00000000 && + four->ip.addr_data32[2] == 0x00000000 && + four->ip.addr_data32[3] == SCNtohl(7) && + four->ip2.addr_data32[0] == SCNtohl(1073741823) && + four->ip2.addr_data32[1] == 0xFFFFFFFF && + four->ip2.addr_data32[2] == 0xFFFFFFFF && + four->ip2.addr_data32[3] == 0xFFFFFFFF && + + five->ip.addr_data32[0] == SCNtohl(1073741824) && + five->ip.addr_data32[1] == 0x00000000 && + five->ip.addr_data32[2] == 0x00000000 && + five->ip.addr_data32[3] == 0x00000000 && + five->ip2.addr_data32[0] == 0xFFFFFFFF && + five->ip2.addr_data32[1] == 0xFFFFFFFF && + five->ip2.addr_data32[2] == 0xFFFFFFFF && + five->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } } @@ -3825,53 +3874,52 @@ static int AddressTestAddressGroupSetup25(void) if (r == 0) { r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { - DetectAddress *one = gh->ipv6_head, *two = one->next, - *three = two->next, *four = three->next, - *five = four->next; + DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, + *four = three->next, *five = four->next; if (one->ip.addr_data32[0] == 0x00000000 && - one->ip.addr_data32[1] == 0x00000000 && - one->ip.addr_data32[2] == 0x00000000 && - one->ip.addr_data32[3] == 0x00000000 && - one->ip2.addr_data32[0] == SCNtohl(536870911) && - one->ip2.addr_data32[1] == 0xFFFFFFFF && - one->ip2.addr_data32[2] == 0xFFFFFFFF && - one->ip2.addr_data32[3] == 0xFFFFFFFF && - - two->ip.addr_data32[0] == SCNtohl(536870912) && - two->ip.addr_data32[1] == 0x00000000 && - two->ip.addr_data32[2] == 0x00000000 && - two->ip.addr_data32[3] == 0x00000000 && - two->ip2.addr_data32[0] == SCNtohl(536936448) && - two->ip2.addr_data32[1] == 0x00000000 && - two->ip2.addr_data32[2] == 0x00000000 && - two->ip2.addr_data32[3] == SCNtohl(3) && - - three->ip.addr_data32[0] == SCNtohl(536936448) && - three->ip.addr_data32[1] == 0x00000000 && - three->ip.addr_data32[2] == 0x00000000 && - three->ip.addr_data32[3] == SCNtohl(4) && - three->ip2.addr_data32[0] == SCNtohl(536936448) && - three->ip2.addr_data32[1] == 0x00000000 && - three->ip2.addr_data32[2] == 0x00000000 && - three->ip2.addr_data32[3] == SCNtohl(6) && - - four->ip.addr_data32[0] == SCNtohl(536936448) && - four->ip.addr_data32[1] == 0x00000000 && - four->ip.addr_data32[2] == 0x00000000 && - four->ip.addr_data32[3] == SCNtohl(7) && - four->ip2.addr_data32[0] == SCNtohl(1073741823) && - four->ip2.addr_data32[1] == 0xFFFFFFFF && - four->ip2.addr_data32[2] == 0xFFFFFFFF && - four->ip2.addr_data32[3] == 0xFFFFFFFF && - - five->ip.addr_data32[0] == SCNtohl(1073741824) && - five->ip.addr_data32[1] == 0x00000000 && - five->ip.addr_data32[2] == 0x00000000 && - five->ip.addr_data32[3] == 0x00000000 && - five->ip2.addr_data32[0] == 0xFFFFFFFF && - five->ip2.addr_data32[1] == 0xFFFFFFFF && - five->ip2.addr_data32[2] == 0xFFFFFFFF && - five->ip2.addr_data32[3] == 0xFFFFFFFF) { + one->ip.addr_data32[1] == 0x00000000 && + one->ip.addr_data32[2] == 0x00000000 && + one->ip.addr_data32[3] == 0x00000000 && + one->ip2.addr_data32[0] == SCNtohl(536870911) && + one->ip2.addr_data32[1] == 0xFFFFFFFF && + one->ip2.addr_data32[2] == 0xFFFFFFFF && + one->ip2.addr_data32[3] == 0xFFFFFFFF && + + two->ip.addr_data32[0] == SCNtohl(536870912) && + two->ip.addr_data32[1] == 0x00000000 && + two->ip.addr_data32[2] == 0x00000000 && + two->ip.addr_data32[3] == 0x00000000 && + two->ip2.addr_data32[0] == SCNtohl(536936448) && + two->ip2.addr_data32[1] == 0x00000000 && + two->ip2.addr_data32[2] == 0x00000000 && + two->ip2.addr_data32[3] == SCNtohl(3) && + + three->ip.addr_data32[0] == SCNtohl(536936448) && + three->ip.addr_data32[1] == 0x00000000 && + three->ip.addr_data32[2] == 0x00000000 && + three->ip.addr_data32[3] == SCNtohl(4) && + three->ip2.addr_data32[0] == SCNtohl(536936448) && + three->ip2.addr_data32[1] == 0x00000000 && + three->ip2.addr_data32[2] == 0x00000000 && + three->ip2.addr_data32[3] == SCNtohl(6) && + + four->ip.addr_data32[0] == SCNtohl(536936448) && + four->ip.addr_data32[1] == 0x00000000 && + four->ip.addr_data32[2] == 0x00000000 && + four->ip.addr_data32[3] == SCNtohl(7) && + four->ip2.addr_data32[0] == SCNtohl(1073741823) && + four->ip2.addr_data32[1] == 0xFFFFFFFF && + four->ip2.addr_data32[2] == 0xFFFFFFFF && + four->ip2.addr_data32[3] == 0xFFFFFFFF && + + five->ip.addr_data32[0] == SCNtohl(1073741824) && + five->ip.addr_data32[1] == 0x00000000 && + five->ip.addr_data32[2] == 0x00000000 && + five->ip.addr_data32[3] == 0x00000000 && + five->ip2.addr_data32[0] == 0xFFFFFFFF && + five->ip2.addr_data32[1] == 0xFFFFFFFF && + five->ip2.addr_data32[2] == 0xFFFFFFFF && + five->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } } @@ -3895,53 +3943,52 @@ static int AddressTestAddressGroupSetup26(void) if (r == 0) { r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { - DetectAddress *one = gh->ipv6_head, *two = one->next, - *three = two->next, *four = three->next, - *five = four->next; + DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, + *four = three->next, *five = four->next; if (one->ip.addr_data32[0] == 0x00000000 && - one->ip.addr_data32[1] == 0x00000000 && - one->ip.addr_data32[2] == 0x00000000 && - one->ip.addr_data32[3] == 0x00000000 && - one->ip2.addr_data32[0] == SCNtohl(536870911) && - one->ip2.addr_data32[1] == 0xFFFFFFFF && - one->ip2.addr_data32[2] == 0xFFFFFFFF && - one->ip2.addr_data32[3] == 0xFFFFFFFF && - - two->ip.addr_data32[0] == SCNtohl(536870912) && - two->ip.addr_data32[1] == 0x00000000 && - two->ip.addr_data32[2] == 0x00000000 && - two->ip.addr_data32[3] == 0x00000000 && - two->ip2.addr_data32[0] == SCNtohl(536936448) && - two->ip2.addr_data32[1] == 0x00000000 && - two->ip2.addr_data32[2] == 0x00000000 && - two->ip2.addr_data32[3] == SCNtohl(3) && - - three->ip.addr_data32[0] == SCNtohl(536936448) && - three->ip.addr_data32[1] == 0x00000000 && - three->ip.addr_data32[2] == 0x00000000 && - three->ip.addr_data32[3] == SCNtohl(4) && - three->ip2.addr_data32[0] == SCNtohl(536936448) && - three->ip2.addr_data32[1] == 0x00000000 && - three->ip2.addr_data32[2] == 0x00000000 && - three->ip2.addr_data32[3] == SCNtohl(6) && - - four->ip.addr_data32[0] == SCNtohl(536936448) && - four->ip.addr_data32[1] == 0x00000000 && - four->ip.addr_data32[2] == 0x00000000 && - four->ip.addr_data32[3] == SCNtohl(7) && - four->ip2.addr_data32[0] == SCNtohl(1073741823) && - four->ip2.addr_data32[1] == 0xFFFFFFFF && - four->ip2.addr_data32[2] == 0xFFFFFFFF && - four->ip2.addr_data32[3] == 0xFFFFFFFF && - - five->ip.addr_data32[0] == SCNtohl(1073741824) && - five->ip.addr_data32[1] == 0x00000000 && - five->ip.addr_data32[2] == 0x00000000 && - five->ip.addr_data32[3] == 0x00000000 && - five->ip2.addr_data32[0] == 0xFFFFFFFF && - five->ip2.addr_data32[1] == 0xFFFFFFFF && - five->ip2.addr_data32[2] == 0xFFFFFFFF && - five->ip2.addr_data32[3] == 0xFFFFFFFF) { + one->ip.addr_data32[1] == 0x00000000 && + one->ip.addr_data32[2] == 0x00000000 && + one->ip.addr_data32[3] == 0x00000000 && + one->ip2.addr_data32[0] == SCNtohl(536870911) && + one->ip2.addr_data32[1] == 0xFFFFFFFF && + one->ip2.addr_data32[2] == 0xFFFFFFFF && + one->ip2.addr_data32[3] == 0xFFFFFFFF && + + two->ip.addr_data32[0] == SCNtohl(536870912) && + two->ip.addr_data32[1] == 0x00000000 && + two->ip.addr_data32[2] == 0x00000000 && + two->ip.addr_data32[3] == 0x00000000 && + two->ip2.addr_data32[0] == SCNtohl(536936448) && + two->ip2.addr_data32[1] == 0x00000000 && + two->ip2.addr_data32[2] == 0x00000000 && + two->ip2.addr_data32[3] == SCNtohl(3) && + + three->ip.addr_data32[0] == SCNtohl(536936448) && + three->ip.addr_data32[1] == 0x00000000 && + three->ip.addr_data32[2] == 0x00000000 && + three->ip.addr_data32[3] == SCNtohl(4) && + three->ip2.addr_data32[0] == SCNtohl(536936448) && + three->ip2.addr_data32[1] == 0x00000000 && + three->ip2.addr_data32[2] == 0x00000000 && + three->ip2.addr_data32[3] == SCNtohl(6) && + + four->ip.addr_data32[0] == SCNtohl(536936448) && + four->ip.addr_data32[1] == 0x00000000 && + four->ip.addr_data32[2] == 0x00000000 && + four->ip.addr_data32[3] == SCNtohl(7) && + four->ip2.addr_data32[0] == SCNtohl(1073741823) && + four->ip2.addr_data32[1] == 0xFFFFFFFF && + four->ip2.addr_data32[2] == 0xFFFFFFFF && + four->ip2.addr_data32[3] == 0xFFFFFFFF && + + five->ip.addr_data32[0] == SCNtohl(1073741824) && + five->ip.addr_data32[1] == 0x00000000 && + five->ip.addr_data32[2] == 0x00000000 && + five->ip.addr_data32[3] == 0x00000000 && + five->ip2.addr_data32[0] == 0xFFFFFFFF && + five->ip2.addr_data32[1] == 0xFFFFFFFF && + five->ip2.addr_data32[2] == 0xFFFFFFFF && + five->ip2.addr_data32[3] == 0xFFFFFFFF) { result = 1; } } @@ -4004,7 +4051,8 @@ static int AddressTestAddressGroupSetup30(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,2.3.4.5],4.3.2.1,[10.10.10.10,11.11.11.11]]"); + int r = DetectAddressParse( + NULL, gh, "[[1.2.3.4,2.3.4.5],4.3.2.1,[10.10.10.10,11.11.11.11]]"); if (r == 0) result = 1; @@ -4019,7 +4067,8 @@ static int AddressTestAddressGroupSetup31(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,[2.3.4.5,3.4.5.6]],4.3.2.1,[10.10.10.10,[11.11.11.11,12.12.12.12]]]"); + int r = DetectAddressParse(NULL, gh, + "[[1.2.3.4,[2.3.4.5,3.4.5.6]],4.3.2.1,[10.10.10.10,[11.11.11.11,12.12.12.12]]]"); if (r == 0) result = 1; @@ -4034,7 +4083,9 @@ static int AddressTestAddressGroupSetup32(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,[2.3.4.5,[3.4.5.6,4.5.6.7]]],4.3.2.1,[10.10.10.10,[11.11.11.11,[12.12.12.12,13.13.13.13]]]]"); + int r = DetectAddressParse(NULL, gh, + "[[1.2.3.4,[2.3.4.5,[3.4.5.6,4.5.6.7]]],4.3.2.1,[10.10.10.10,[11.11.11.11,[12.12." + "12.12,13.13.13.13]]]]"); if (r == 0) result = 1; @@ -4088,7 +4139,7 @@ static int AddressTestAddressGroupSetup35(void) return result; } -static int AddressTestAddressGroupSetup36 (void) +static int AddressTestAddressGroupSetup36(void) { int result = 0; @@ -4120,10 +4171,8 @@ static int AddressTestAddressGroupSetup37(void) static int AddressTestAddressGroupSetup38(void) { - UTHValidateDetectAddressHeadRange expectations[3] = { - { "0.0.0.0", "192.167.255.255" }, - { "192.168.14.0", "192.168.14.255" }, - { "192.169.0.0", "255.255.255.255" } }; + UTHValidateDetectAddressHeadRange expectations[3] = { { "0.0.0.0", "192.167.255.255" }, + { "192.168.14.0", "192.168.14.255" }, { "192.169.0.0", "255.255.255.255" } }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); @@ -4141,10 +4190,8 @@ static int AddressTestAddressGroupSetup38(void) static int AddressTestAddressGroupSetup39(void) { - UTHValidateDetectAddressHeadRange expectations[3] = { - { "0.0.0.0", "192.167.255.255" }, - { "192.168.14.0", "192.168.14.255" }, - { "192.169.0.0", "255.255.255.255" } }; + UTHValidateDetectAddressHeadRange expectations[3] = { { "0.0.0.0", "192.167.255.255" }, + { "192.168.14.0", "192.168.14.255" }, { "192.169.0.0", "255.255.255.255" } }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); @@ -4162,10 +4209,8 @@ static int AddressTestAddressGroupSetup39(void) static int AddressTestAddressGroupSetup40(void) { - UTHValidateDetectAddressHeadRange expectations[3] = { - { "0.0.0.0", "192.167.255.255" }, - { "192.168.14.0", "192.168.14.255" }, - { "192.169.0.0", "255.255.255.255" } }; + UTHValidateDetectAddressHeadRange expectations[3] = { { "0.0.0.0", "192.167.255.255" }, + { "192.168.14.0", "192.168.14.255" }, { "192.169.0.0", "255.255.255.255" } }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { @@ -4182,10 +4227,8 @@ static int AddressTestAddressGroupSetup40(void) static int AddressTestAddressGroupSetup41(void) { - UTHValidateDetectAddressHeadRange expectations[3] = { - { "0.0.0.0", "192.167.255.255" }, - { "192.168.14.0", "192.168.14.255" }, - { "192.169.0.0", "255.255.255.255" } }; + UTHValidateDetectAddressHeadRange expectations[3] = { { "0.0.0.0", "192.167.255.255" }, + { "192.168.14.0", "192.168.14.255" }, { "192.169.0.0", "255.255.255.255" } }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { @@ -4203,7 +4246,8 @@ static int AddressTestAddressGroupSetup41(void) static int AddressTestAddressGroupSetup42(void) { UTHValidateDetectAddressHeadRange expectations[1] = { - { "2000:0000:0000:0000:0000:0000:0000:0000", "3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" } }; + { "2000:0000:0000:0000:0000:0000:0000:0000", "3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" } + }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { @@ -4222,7 +4266,8 @@ static int AddressTestAddressGroupSetup43(void) { UTHValidateDetectAddressHeadRange expectations[2] = { { "2000:0000:0000:0000:0000:0000:0000:0000", "2fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" }, - { "3800:0000:0000:0000:0000:0000:0000:0000", "3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" } }; + { "3800:0000:0000:0000:0000:0000:0000:0000", "3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" } + }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { @@ -4240,7 +4285,8 @@ static int AddressTestAddressGroupSetup43(void) static int AddressTestAddressGroupSetup44(void) { UTHValidateDetectAddressHeadRange expectations[2] = { - { "3ffe:ffff:7654:feda:1245:ba98:0000:0000", "3ffe:ffff:7654:feda:1245:ba98:ffff:ffff" }}; + { "3ffe:ffff:7654:feda:1245:ba98:0000:0000", "3ffe:ffff:7654:feda:1245:ba98:ffff:ffff" } + }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { @@ -4272,15 +4318,14 @@ static int AddressTestAddressGroupSetup45(void) static int AddressTestAddressGroupSetup46(void) { - UTHValidateDetectAddressHeadRange expectations[4] = { - { "0.0.0.0", "192.167.255.255" }, - { "192.168.1.0", "192.168.1.255" }, - { "192.168.3.0", "192.168.3.255" }, + UTHValidateDetectAddressHeadRange expectations[4] = { { "0.0.0.0", "192.167.255.255" }, + { "192.168.1.0", "192.168.1.255" }, { "192.168.3.0", "192.168.3.255" }, { "192.169.0.0", "255.255.255.255" } }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24]]]"); + int r = DetectAddressParse( + NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24]]]"); if (r == 1) { if (UTHValidateDetectAddressHead(gh, 4, expectations)) result = 1; @@ -4294,16 +4339,14 @@ static int AddressTestAddressGroupSetup46(void) /** \test net with some negations, then all negated */ static int AddressTestAddressGroupSetup47(void) { - UTHValidateDetectAddressHeadRange expectations[5] = { - { "0.0.0.0", "192.167.255.255" }, - { "192.168.1.0", "192.168.1.255" }, - { "192.168.3.0", "192.168.3.255" }, - { "192.168.5.0", "192.168.5.255" }, - { "192.169.0.0", "255.255.255.255" } }; + UTHValidateDetectAddressHeadRange expectations[5] = { { "0.0.0.0", "192.167.255.255" }, + { "192.168.1.0", "192.168.1.255" }, { "192.168.3.0", "192.168.3.255" }, + { "192.168.5.0", "192.168.5.255" }, { "192.169.0.0", "255.255.255.255" } }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]]"); + int r = DetectAddressParse( + NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]]"); if (r == 1) { if (UTHValidateDetectAddressHead(gh, 5, expectations)) result = 1; @@ -4317,15 +4360,14 @@ static int AddressTestAddressGroupSetup47(void) /** \test same as AddressTestAddressGroupSetup47, but not negated */ static int AddressTestAddressGroupSetup48(void) { - UTHValidateDetectAddressHeadRange expectations[4] = { - { "192.168.0.0", "192.168.0.255" }, - { "192.168.2.0", "192.168.2.255" }, - { "192.168.4.0", "192.168.4.255" }, + UTHValidateDetectAddressHeadRange expectations[4] = { { "192.168.0.0", "192.168.0.255" }, + { "192.168.2.0", "192.168.2.255" }, { "192.168.4.0", "192.168.4.255" }, { "192.168.6.0", "192.168.255.255" } }; int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(NULL, gh, "[192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]"); + int r = DetectAddressParse( + NULL, gh, "[192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]"); if (r == 1) { if (UTHValidateDetectAddressHead(gh, 4, expectations)) result = 1; @@ -4426,7 +4468,6 @@ static int AddressTestCutIPv404(void) if (c->ip.addr_data32[0] != SCNtohl(16909062) || c->ip2.addr_data32[0] != SCNtohl(16909062)) goto error; - DetectAddressFree(a); DetectAddressFree(b); DetectAddressFree(c); @@ -4605,7 +4646,8 @@ static int AddressTestCutIPv410(void) if (b->ip.addr_data32[0] != SCNtohl(16909059) || b->ip2.addr_data32[0] != SCNtohl(16909065)) goto error; - printf("ip %u ip2 %u ", (uint32_t)htonl(a->ip.addr_data32[0]), (uint32_t)htonl(a->ip2.addr_data32[0])); + printf("ip %u ip2 %u ", (uint32_t)htonl(a->ip.addr_data32[0]), + (uint32_t)htonl(a->ip2.addr_data32[0])); DetectAddressFree(a); DetectAddressFree(b); @@ -4660,24 +4702,23 @@ static int AddressTestParseInvalidMask03(void) static int AddressConfVarsTest01(void) { - static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"any\"\n" - "\n" - " EXTERNAL_NET: \"!any\"\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"any\"\n" - "\n" - " SHELLCODE_PORTS: \"!any\"\n" - "\n"; + static const char *dummy_conf_string = "%YAML 1.1\n" + "---\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"any\"\n" + "\n" + " EXTERNAL_NET: \"!any\"\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"any\"\n" + "\n" + " SHELLCODE_PORTS: \"!any\"\n" + "\n"; int result = 0; @@ -4696,24 +4737,23 @@ static int AddressConfVarsTest01(void) static int AddressConfVarsTest02(void) { - static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"any\"\n" - "\n" - " EXTERNAL_NET: \"any\"\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"any\"\n" - "\n" - " SHELLCODE_PORTS: \"!any\"\n" - "\n"; + static const char *dummy_conf_string = "%YAML 1.1\n" + "---\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"any\"\n" + "\n" + " EXTERNAL_NET: \"any\"\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"any\"\n" + "\n" + " SHELLCODE_PORTS: \"!any\"\n" + "\n"; int result = 0; @@ -4732,24 +4772,23 @@ static int AddressConfVarsTest02(void) static int AddressConfVarsTest03(void) { - static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"any\"\n" - "\n" - " EXTERNAL_NET: \"!$HOME_NET\"\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"any\"\n" - "\n" - " SHELLCODE_PORTS: \"!$HTTP_PORTS\"\n" - "\n"; + static const char *dummy_conf_string = "%YAML 1.1\n" + "---\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"any\"\n" + "\n" + " EXTERNAL_NET: \"!$HOME_NET\"\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"any\"\n" + "\n" + " SHELLCODE_PORTS: \"!$HTTP_PORTS\"\n" + "\n"; int result = 0; @@ -4768,24 +4807,23 @@ static int AddressConfVarsTest03(void) static int AddressConfVarsTest04(void) { - static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"any\"\n" - "\n" - " EXTERNAL_NET: \"$HOME_NET\"\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"any\"\n" - "\n" - " SHELLCODE_PORTS: \"$HTTP_PORTS\"\n" - "\n"; + static const char *dummy_conf_string = "%YAML 1.1\n" + "---\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"any\"\n" + "\n" + " EXTERNAL_NET: \"$HOME_NET\"\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"any\"\n" + "\n" + " SHELLCODE_PORTS: \"$HTTP_PORTS\"\n" + "\n"; int result = 0; @@ -4804,24 +4842,23 @@ static int AddressConfVarsTest04(void) static int AddressConfVarsTest05(void) { - static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"any\"\n" - "\n" - " EXTERNAL_NET: [192.168.0.1]\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"any\"\n" - "\n" - " SHELLCODE_PORTS: [80]\n" - "\n"; + static const char *dummy_conf_string = "%YAML 1.1\n" + "---\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"any\"\n" + "\n" + " EXTERNAL_NET: [192.168.0.1]\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"any\"\n" + "\n" + " SHELLCODE_PORTS: [80]\n" + "\n"; int result = 0; @@ -4834,7 +4871,7 @@ static int AddressConfVarsTest05(void) result = 1; - end: +end: ConfDeInit(); ConfRestoreContextBackup(); @@ -5079,110 +5116,59 @@ void DetectAddressTests(void) UtRegisterTest("AddressTestCmp11", AddressTestCmp11); UtRegisterTest("AddressTestCmp12", AddressTestCmp12); - UtRegisterTest("AddressTestAddressGroupSetup01", - AddressTestAddressGroupSetup01); - UtRegisterTest("AddressTestAddressGroupSetup02", - AddressTestAddressGroupSetup02); - UtRegisterTest("AddressTestAddressGroupSetup03", - AddressTestAddressGroupSetup03); - UtRegisterTest("AddressTestAddressGroupSetup04", - AddressTestAddressGroupSetup04); - UtRegisterTest("AddressTestAddressGroupSetup05", - AddressTestAddressGroupSetup05); - UtRegisterTest("AddressTestAddressGroupSetup06", - AddressTestAddressGroupSetup06); - UtRegisterTest("AddressTestAddressGroupSetup07", - AddressTestAddressGroupSetup07); - UtRegisterTest("AddressTestAddressGroupSetup08", - AddressTestAddressGroupSetup08); - UtRegisterTest("AddressTestAddressGroupSetup09", - AddressTestAddressGroupSetup09); - UtRegisterTest("AddressTestAddressGroupSetup10", - AddressTestAddressGroupSetup10); - UtRegisterTest("AddressTestAddressGroupSetup11", - AddressTestAddressGroupSetup11); - UtRegisterTest("AddressTestAddressGroupSetup12", - AddressTestAddressGroupSetup12); - UtRegisterTest("AddressTestAddressGroupSetup13", - AddressTestAddressGroupSetup13); - UtRegisterTest("AddressTestAddressGroupSetupIPv414", - AddressTestAddressGroupSetupIPv414); - UtRegisterTest("AddressTestAddressGroupSetupIPv415", - AddressTestAddressGroupSetupIPv415); - UtRegisterTest("AddressTestAddressGroupSetupIPv416", - AddressTestAddressGroupSetupIPv416); - - UtRegisterTest("AddressTestAddressGroupSetup14", - AddressTestAddressGroupSetup14); - UtRegisterTest("AddressTestAddressGroupSetup15", - AddressTestAddressGroupSetup15); - UtRegisterTest("AddressTestAddressGroupSetup16", - AddressTestAddressGroupSetup16); - UtRegisterTest("AddressTestAddressGroupSetup17", - AddressTestAddressGroupSetup17); - UtRegisterTest("AddressTestAddressGroupSetup18", - AddressTestAddressGroupSetup18); - UtRegisterTest("AddressTestAddressGroupSetup19", - AddressTestAddressGroupSetup19); - UtRegisterTest("AddressTestAddressGroupSetup20", - AddressTestAddressGroupSetup20); - UtRegisterTest("AddressTestAddressGroupSetup21", - AddressTestAddressGroupSetup21); - UtRegisterTest("AddressTestAddressGroupSetup22", - AddressTestAddressGroupSetup22); - UtRegisterTest("AddressTestAddressGroupSetup23", - AddressTestAddressGroupSetup23); - UtRegisterTest("AddressTestAddressGroupSetup24", - AddressTestAddressGroupSetup24); - UtRegisterTest("AddressTestAddressGroupSetup25", - AddressTestAddressGroupSetup25); - UtRegisterTest("AddressTestAddressGroupSetup26", - AddressTestAddressGroupSetup26); - - UtRegisterTest("AddressTestAddressGroupSetup27", - AddressTestAddressGroupSetup27); - UtRegisterTest("AddressTestAddressGroupSetup28", - AddressTestAddressGroupSetup28); - UtRegisterTest("AddressTestAddressGroupSetup29", - AddressTestAddressGroupSetup29); - UtRegisterTest("AddressTestAddressGroupSetup30", - AddressTestAddressGroupSetup30); - UtRegisterTest("AddressTestAddressGroupSetup31", - AddressTestAddressGroupSetup31); - UtRegisterTest("AddressTestAddressGroupSetup32", - AddressTestAddressGroupSetup32); - UtRegisterTest("AddressTestAddressGroupSetup33", - AddressTestAddressGroupSetup33); - UtRegisterTest("AddressTestAddressGroupSetup34", - AddressTestAddressGroupSetup34); - UtRegisterTest("AddressTestAddressGroupSetup35", - AddressTestAddressGroupSetup35); - UtRegisterTest("AddressTestAddressGroupSetup36", - AddressTestAddressGroupSetup36); - UtRegisterTest("AddressTestAddressGroupSetup37", - AddressTestAddressGroupSetup37); - UtRegisterTest("AddressTestAddressGroupSetup38", - AddressTestAddressGroupSetup38); - UtRegisterTest("AddressTestAddressGroupSetup39", - AddressTestAddressGroupSetup39); - UtRegisterTest("AddressTestAddressGroupSetup40", - AddressTestAddressGroupSetup40); - UtRegisterTest("AddressTestAddressGroupSetup41", - AddressTestAddressGroupSetup41); - UtRegisterTest("AddressTestAddressGroupSetup42", - AddressTestAddressGroupSetup42); - UtRegisterTest("AddressTestAddressGroupSetup43", - AddressTestAddressGroupSetup43); - UtRegisterTest("AddressTestAddressGroupSetup44", - AddressTestAddressGroupSetup44); - UtRegisterTest("AddressTestAddressGroupSetup45", - AddressTestAddressGroupSetup45); - UtRegisterTest("AddressTestAddressGroupSetup46", - AddressTestAddressGroupSetup46); - UtRegisterTest("AddressTestAddressGroupSetup47", - AddressTestAddressGroupSetup47); - UtRegisterTest("AddressTestAddressGroupSetup48", - AddressTestAddressGroupSetup48); + UtRegisterTest("AddressTestAddressGroupSetup01", AddressTestAddressGroupSetup01); + UtRegisterTest("AddressTestAddressGroupSetup02", AddressTestAddressGroupSetup02); + UtRegisterTest("AddressTestAddressGroupSetup03", AddressTestAddressGroupSetup03); + UtRegisterTest("AddressTestAddressGroupSetup04", AddressTestAddressGroupSetup04); + UtRegisterTest("AddressTestAddressGroupSetup05", AddressTestAddressGroupSetup05); + UtRegisterTest("AddressTestAddressGroupSetup06", AddressTestAddressGroupSetup06); + UtRegisterTest("AddressTestAddressGroupSetup07", AddressTestAddressGroupSetup07); + UtRegisterTest("AddressTestAddressGroupSetup08", AddressTestAddressGroupSetup08); + UtRegisterTest("AddressTestAddressGroupSetup09", AddressTestAddressGroupSetup09); + UtRegisterTest("AddressTestAddressGroupSetup10", AddressTestAddressGroupSetup10); + UtRegisterTest("AddressTestAddressGroupSetup11", AddressTestAddressGroupSetup11); + UtRegisterTest("AddressTestAddressGroupSetup12", AddressTestAddressGroupSetup12); + UtRegisterTest("AddressTestAddressGroupSetup13", AddressTestAddressGroupSetup13); + UtRegisterTest("AddressTestAddressGroupSetupIPv414", AddressTestAddressGroupSetupIPv414); + UtRegisterTest("AddressTestAddressGroupSetupIPv415", AddressTestAddressGroupSetupIPv415); + UtRegisterTest("AddressTestAddressGroupSetupIPv416", AddressTestAddressGroupSetupIPv416); + + UtRegisterTest("AddressTestAddressGroupSetup14", AddressTestAddressGroupSetup14); + UtRegisterTest("AddressTestAddressGroupSetup15", AddressTestAddressGroupSetup15); + UtRegisterTest("AddressTestAddressGroupSetup16", AddressTestAddressGroupSetup16); + UtRegisterTest("AddressTestAddressGroupSetup17", AddressTestAddressGroupSetup17); + UtRegisterTest("AddressTestAddressGroupSetup18", AddressTestAddressGroupSetup18); + UtRegisterTest("AddressTestAddressGroupSetup19", AddressTestAddressGroupSetup19); + UtRegisterTest("AddressTestAddressGroupSetup20", AddressTestAddressGroupSetup20); + UtRegisterTest("AddressTestAddressGroupSetup21", AddressTestAddressGroupSetup21); + UtRegisterTest("AddressTestAddressGroupSetup22", AddressTestAddressGroupSetup22); + UtRegisterTest("AddressTestAddressGroupSetup23", AddressTestAddressGroupSetup23); + UtRegisterTest("AddressTestAddressGroupSetup24", AddressTestAddressGroupSetup24); + UtRegisterTest("AddressTestAddressGroupSetup25", AddressTestAddressGroupSetup25); + UtRegisterTest("AddressTestAddressGroupSetup26", AddressTestAddressGroupSetup26); + + UtRegisterTest("AddressTestAddressGroupSetup27", AddressTestAddressGroupSetup27); + UtRegisterTest("AddressTestAddressGroupSetup28", AddressTestAddressGroupSetup28); + UtRegisterTest("AddressTestAddressGroupSetup29", AddressTestAddressGroupSetup29); + UtRegisterTest("AddressTestAddressGroupSetup30", AddressTestAddressGroupSetup30); + UtRegisterTest("AddressTestAddressGroupSetup31", AddressTestAddressGroupSetup31); + UtRegisterTest("AddressTestAddressGroupSetup32", AddressTestAddressGroupSetup32); + UtRegisterTest("AddressTestAddressGroupSetup33", AddressTestAddressGroupSetup33); + UtRegisterTest("AddressTestAddressGroupSetup34", AddressTestAddressGroupSetup34); + UtRegisterTest("AddressTestAddressGroupSetup35", AddressTestAddressGroupSetup35); + UtRegisterTest("AddressTestAddressGroupSetup36", AddressTestAddressGroupSetup36); + UtRegisterTest("AddressTestAddressGroupSetup37", AddressTestAddressGroupSetup37); + UtRegisterTest("AddressTestAddressGroupSetup38", AddressTestAddressGroupSetup38); + UtRegisterTest("AddressTestAddressGroupSetup39", AddressTestAddressGroupSetup39); + UtRegisterTest("AddressTestAddressGroupSetup40", AddressTestAddressGroupSetup40); + UtRegisterTest("AddressTestAddressGroupSetup41", AddressTestAddressGroupSetup41); + UtRegisterTest("AddressTestAddressGroupSetup42", AddressTestAddressGroupSetup42); + UtRegisterTest("AddressTestAddressGroupSetup43", AddressTestAddressGroupSetup43); + UtRegisterTest("AddressTestAddressGroupSetup44", AddressTestAddressGroupSetup44); + UtRegisterTest("AddressTestAddressGroupSetup45", AddressTestAddressGroupSetup45); + UtRegisterTest("AddressTestAddressGroupSetup46", AddressTestAddressGroupSetup46); + UtRegisterTest("AddressTestAddressGroupSetup47", AddressTestAddressGroupSetup47); + UtRegisterTest("AddressTestAddressGroupSetup48", AddressTestAddressGroupSetup48); UtRegisterTest("AddressTestCutIPv401", AddressTestCutIPv401); UtRegisterTest("AddressTestCutIPv402", AddressTestCutIPv402); @@ -5195,12 +5181,9 @@ void DetectAddressTests(void) UtRegisterTest("AddressTestCutIPv409", AddressTestCutIPv409); UtRegisterTest("AddressTestCutIPv410", AddressTestCutIPv410); - UtRegisterTest("AddressTestParseInvalidMask01", - AddressTestParseInvalidMask01); - UtRegisterTest("AddressTestParseInvalidMask02", - AddressTestParseInvalidMask02); - UtRegisterTest("AddressTestParseInvalidMask03", - AddressTestParseInvalidMask03); + UtRegisterTest("AddressTestParseInvalidMask01", AddressTestParseInvalidMask01); + UtRegisterTest("AddressTestParseInvalidMask02", AddressTestParseInvalidMask02); + UtRegisterTest("AddressTestParseInvalidMask03", AddressTestParseInvalidMask03); UtRegisterTest("AddressConfVarsTest01 ", AddressConfVarsTest01); UtRegisterTest("AddressConfVarsTest02 ", AddressConfVarsTest02); diff --git a/src/detect-engine-address.h b/src/detect-engine-address.h index 3c8221e630b4..930059217a16 100644 --- a/src/detect-engine-address.h +++ b/src/detect-engine-address.h @@ -24,8 +24,6 @@ #ifndef __DETECT_ADDRESS_H__ #define __DETECT_ADDRESS_H__ - - DetectAddress *DetectAddressInit(void); void DetectAddressFree(DetectAddress *); DetectAddress *DetectAddressCopy(DetectAddress *); @@ -47,8 +45,8 @@ void DetectAddressTests(void); int DetectAddressMapInit(DetectEngineCtx *de_ctx); void DetectAddressMapFree(DetectEngineCtx *de_ctx); -const DetectAddressHead *DetectParseAddress(DetectEngineCtx *de_ctx, - const char *string, bool *contains_negation); +const DetectAddressHead *DetectParseAddress( + DetectEngineCtx *de_ctx, const char *string, bool *contains_negation); #ifdef DEBUG void DetectAddressPrintList(DetectAddress *); diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index f9cbed1564c5..ad511a74346f 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -29,11 +29,11 @@ #include "flow-private.h" #ifdef DEBUG -#include "util-exception-policy.h" +#include "util/exception-policy.h" #endif -#include "util-profiling.h" -#include "util-validate.h" +#include "util/profiling.h" +#include "util/validate.h" #include "action-globals.h" @@ -70,7 +70,7 @@ void PacketAlertTagInit(void) * \retval 0 alert is suppressed */ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const Signature *s, Packet *p, PacketAlert *pa) + const Signature *s, Packet *p, PacketAlert *pa) { SCEnter(); int ret = 1; @@ -118,7 +118,7 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det KEYWORD_PROFILING_START; ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa); if (ret == 0 || ret == 2) { - KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD ,0); + KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 0); /* It doesn't match threshold, remove it */ SCReturnInt(ret); } diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index a37afabb0f00..f844610a7c09 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -41,21 +41,21 @@ #include "detect-tcp-flags.h" #include "detect-ipopts.h" #include "feature.h" -#include "util-print.h" -#include "util-time.h" -#include "util-validate.h" -#include "util-conf.h" +#include "util/print.h" +#include "util/time.h" +#include "util/validate.h" +#include "util/conf.h" static int rule_warnings_only = 0; /* Details for each buffer being tracked */ typedef struct DetectEngineAnalyzerItems { - int16_t item_id; - bool item_seen; - bool export_item_seen; - bool check_encoding_match; - const char *item_name; - const char *display_name; + int16_t item_id; + bool item_seen; + bool export_item_seen; + bool check_encoding_match; + const char *item_name; + const char *display_name; } DetectEngineAnalyzerItems; typedef struct FpPatternStats_ { @@ -67,8 +67,8 @@ typedef struct FpPatternStats_ { /* Track which items require the item_seen value to be exposed */ struct ExposedItemSeen { - const char *bufname; - bool *item_seen_ptr; + const char *bufname; + bool *item_seen_ptr; }; typedef struct EngineAnalysisCtx_ { @@ -213,7 +213,8 @@ void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, char *l if (fp_cd->flags & DETECT_CONTENT_OFFSET) { fprintf(fp, " Offset"); flags_set = 1; - } if (fp_cd->flags & DETECT_CONTENT_DEPTH) { + } + if (fp_cd->flags & DETECT_CONTENT_DEPTH) { fprintf(fp, " Depth"); flags_set = 1; } @@ -293,8 +294,7 @@ static int SetupFPAnalyzer(DetectEngineCtx *de_ctx) { int fp_engine_analysis_set = 0; - if ((ConfGetBool("engine-analysis.rules-fast-pattern", - &fp_engine_analysis_set)) == 0) { + if ((ConfGetBool("engine-analysis.rules-fast-pattern", &fp_engine_analysis_set)) == 0) { return false; } @@ -318,8 +318,7 @@ static int SetupFPAnalyzer(DetectEngineCtx *de_ctx) de_ctx->ea->fp_engine_analysis_fp = fp; - SCLogInfo("Engine-Analysis for fast_pattern printed to file - %s", - log_path); + SCLogInfo("Engine-Analysis for fast_pattern printed to file - %s", log_path); SCFree(log_path); struct timeval tval; @@ -393,8 +392,7 @@ static int SetupRuleAnalyzer(DetectEngineCtx *de_ctx) return 0; } - SCLogInfo("Engine-Analysis for rules printed to file - %s", - log_path); + SCLogInfo("Engine-Analysis for rules printed to file - %s", log_path); struct timeval tval; gettimeofday(&tval, NULL); @@ -419,10 +417,9 @@ static int SetupRuleAnalyzer(DetectEngineCtx *de_ctx) "http content.\n"); } } - } - else { + } else { SCLogInfo("Conf parameter \"engine-analysis.rules\" not found. " - "Defaulting to not printing the rules analysis report."); + "Defaulting to not printing the rules analysis report."); } if (!enabled) { SCLogInfo("Engine-Analysis for rules disabled in conf file."); @@ -594,8 +591,7 @@ static void EngineAnalysisRulesPrintFP(const DetectEngineCtx *de_ctx, const Sign fprintf(ea_ctx->rule_engine_analysis_fp, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); - } - else { + } else { const char *desc = DetectEngineBufferTypeGetDescriptionById(de_ctx, list_type); const char *name = DetectEngineBufferTypeGetNameById(de_ctx, list_type); if (desc && name) { @@ -603,7 +599,6 @@ static void EngineAnalysisRulesPrintFP(const DetectEngineCtx *de_ctx, const Sign } else if (desc || name) { fprintf(ea_ctx->rule_engine_analysis_fp, "%s", desc ? desc : name); } - } fprintf(ea_ctx->rule_engine_analysis_fp, "\" "); @@ -663,7 +658,9 @@ static void ATTR_FMT_PRINTF(2, 3) AnalyzerWarning(RuleAnalyzer *ctx, char *fmt, jb_append_string(ctx->js_warnings, str); } -#define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true; +#define CHECK(pat) \ + if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) \ + return true; static bool LooksLikeHTTPMethod(const uint8_t *buf, uint16_t len) { @@ -1019,7 +1016,7 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s) jb_open_array(ctx.js, "pkt_engines"); const DetectEnginePktInspectionEngine *pkt = s->pkt_inspect; - for ( ; pkt != NULL; pkt = pkt->next) { + for (; pkt != NULL; pkt = pkt->next) { const char *name = DetectEngineBufferTypeGetNameById(de_ctx, pkt->sm_list); if (name == NULL) { switch (pkt->sm_list) { @@ -1083,7 +1080,7 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s) jb_open_array(ctx.js, "engines"); const DetectEngineAppInspectionEngine *app = s->app_inspect; - for ( ; app != NULL; app = app->next) { + for (; app != NULL; app = app->next) { const char *name = DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list); if (name == NULL) { switch (app->sm_list) { @@ -1131,9 +1128,11 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s) jb_close(ctx.js); if (has_stream && has_client_body_mpm) - AnalyzerNote(&ctx, (char *)"mpm in http_client_body combined with stream match leads to stream buffering"); + AnalyzerNote(&ctx, (char *)"mpm in http_client_body combined with stream match leads " + "to stream buffering"); if (has_stream && has_file_data_mpm) - AnalyzerNote(&ctx, (char *)"mpm in file_data combined with stream match leads to stream buffering"); + AnalyzerNote(&ctx, (char *)"mpm in file_data combined with stream match leads to " + "stream buffering"); } jb_open_object(ctx.js, "lists"); @@ -1364,8 +1363,7 @@ static void EngineAnalysisItemsInit(EngineAnalysisCtx *ea_ctx) * * \param s Pointer to the signature. */ -void EngineAnalysisRules(const DetectEngineCtx *de_ctx, - const Signature *s, const char *line) +void EngineAnalysisRules(const DetectEngineCtx *de_ctx, const Signature *s, const char *line) { uint32_t rule_bidirectional = 0; uint32_t rule_pcre = 0; @@ -1466,13 +1464,11 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, warn_encoding_norm_http_buf += 1; } } - } - else if (sm->type == DETECT_FLOW) { + } else if (sm->type == DETECT_FLOW) { rule_flow += 1; if ((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { rule_flow_toserver = 1; - } - else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) { + } else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) { rule_flow_toclient = 1; } DetectFlowData *fd = (DetectFlowData *)sm->ctx; @@ -1480,18 +1476,15 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) rule_flow_nostream = 1; } - } - else if (sm->type == DETECT_FLOWBITS) { + } else if (sm->type == DETECT_FLOWBITS) { if (list_id == DETECT_SM_LIST_MATCH) { rule_flowbits += 1; } - } - else if (sm->type == DETECT_FLOWINT) { + } else if (sm->type == DETECT_FLOWINT) { if (list_id == DETECT_SM_LIST_MATCH) { rule_flowint += 1; } - } - else if (sm->type == DETECT_FLAGS) { + } else if (sm->type == DETECT_FLAGS) { DetectFlagsData *fd = (DetectFlagsData *)sm->ctx; if (fd != NULL) { rule_flags = 1; @@ -1528,7 +1521,7 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, warn_content_http = 1; } if (rule_content == 1) { - //todo: warning if content is weak, separate warning for pcre + weak content + // todo: warning if content is weak, separate warning for pcre + weak content } if (rule_flow == 0 && rule_flags == 0 && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP) && @@ -1537,10 +1530,12 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, rule_warning += 1; warn_tcp_no_flow = 1; } - if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient) - && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) { - if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)) - || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))) { + if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient) && + !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) { + if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && + (s->flags & SIG_FLAG_DP_ANY)) || + ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && + (s->flags & SIG_FLAG_SP_ANY))) { rule_warning += 1; warn_client_ports = 1; } @@ -1568,7 +1563,8 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, rule_warning += 1; warn_offset_depth_pkt_stream = 1; } - if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && s->alproto != ALPROTO_UNKNOWN) { + if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && + s->alproto != ALPROTO_UNKNOWN) { rule_warning += 1; warn_offset_depth_alproto = 1; } @@ -1578,14 +1574,16 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, warn_non_alproto_fp_for_alproto_sig = 1; } - if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) { + if ((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == 0) { warn_no_direction += 1; rule_warning += 1; } /* No warning about direction for ICMP protos */ - if (!(DetectProtoContainsProto(&s->proto, IPPROTO_ICMPV6) && DetectProtoContainsProto(&s->proto, IPPROTO_ICMP))) { - if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) { + if (!(DetectProtoContainsProto(&s->proto, IPPROTO_ICMPV6) && + DetectProtoContainsProto(&s->proto, IPPROTO_ICMP))) { + if ((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == + (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) { warn_both_direction += 1; rule_warning += 1; } @@ -1639,7 +1637,7 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, (rule_flow || rule_flowbits || rule_flowint || rule_content || rule_pcre)) { fprintf(fp, " Rule matches on reassembled stream.\n"); } - for(size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) { + for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) { DetectEngineAnalyzerItems *ai = &de_ctx->ea->analyzer_items[i]; if (ai->item_seen) { fprintf(fp, " Rule matches on %s buffer.\n", ai->display_name); @@ -1690,7 +1688,7 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, " -Consider adding http content modifiers.\n"); } if (rule_content == 1) { - //todo: warning if content is weak, separate warning for pcre + weak content + // todo: warning if content is weak, separate warning for pcre + weak content } if (warn_encoding_norm_http_buf) { fprintf(fp, " Warning: Rule may contain percent encoded content for a normalized " diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index 33b8ca206b22..2492cd74aedf 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -38,10 +38,10 @@ #include "detect-config.h" #include "detect-flowbits.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-var-name.h" -#include "util-conf.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/var-name.h" +#include "util/conf.h" /* Magic numbers to make the rules of a certain order fall in the same group */ #define DETECT_PGSCORE_RULE_PORT_WHITELISTED 111 /* Rule port group contains a whitelisted port */ @@ -217,9 +217,9 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) return 0; /* if flow dir is set we can't process it in ip-only */ - if (!(((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) || - (s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == - (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT))) + if (!(((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == 0) || + (s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == + (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT))) return 0; /* for now assume that all registered buffer types are incompatible */ @@ -242,13 +242,13 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) } } sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; - for ( ; sm != NULL; sm = sm->next) { - if ( !(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) + for (; sm != NULL; sm = sm->next) { + if (!(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) return 0; /* we have enabled flowbits to be compatible with ip only sigs, as long * as the sig only has a "set" flowbits */ if (sm->type == DETECT_FLOWBITS && - (((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET) ) { + (((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET)) { return 0; } } @@ -259,8 +259,8 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) } if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("IP-ONLY (%" PRIu32 "): source %s, dest %s", s->id, - s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET", - s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET"); + s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET", + s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET"); } return 1; } @@ -296,24 +296,27 @@ static int SignatureIsPDOnly(const DetectEngineCtx *de_ctx, const Signature *s) return 0; int pd = 0; - for ( ; sm != NULL; sm = sm->next) { + for (; sm != NULL; sm = sm->next) { if (sm->type == DETECT_AL_APP_LAYER_PROTOCOL) { pd = 1; } else { /* flowbits are supported for dp only sigs, as long * as the sig only has a "set" flowbits */ if (sm->type == DETECT_FLOWBITS) { - if ((((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET) ) { + if ((((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET)) { SCLogDebug("%u: not PD-only: flowbit settings other than 'set'", s->id); return 0; } } else if (sm->type == DETECT_FLOW) { - if (((DetectFlowData *)sm->ctx)->flags & ~(DETECT_FLOW_FLAG_TOSERVER|DETECT_FLOW_FLAG_TOCLIENT)) { - SCLogDebug("%u: not PD-only: flow settings other than toserver/toclient", s->id); + if (((DetectFlowData *)sm->ctx)->flags & + ~(DETECT_FLOW_FLAG_TOSERVER | DETECT_FLOW_FLAG_TOCLIENT)) { + SCLogDebug( + "%u: not PD-only: flow settings other than toserver/toclient", s->id); return 0; } - } else if ( !(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) { - SCLogDebug("%u: not PD-only: %s not PD/IP-only compat", s->id, sigmatch_table[sm->type].name); + } else if (!(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) { + SCLogDebug("%u: not PD-only: %s not PD/IP-only compat", s->id, + sigmatch_table[sm->type].name); return 0; } } @@ -356,8 +359,7 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) SCReturnInt(0); } - if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) - { + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { SCReturnInt(0); } @@ -368,14 +370,14 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) /* check for conflicting keywords */ SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; - for ( ;sm != NULL; sm = sm->next) { - if ( !(sigmatch_table[sm->type].flags & SIGMATCH_DEONLY_COMPAT)) + for (; sm != NULL; sm = sm->next) { + if (!(sigmatch_table[sm->type].flags & SIGMATCH_DEONLY_COMPAT)) SCReturnInt(0); } /* need at least one decode event keyword to be considered decode event. */ sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; - for ( ;sm != NULL; sm = sm->next) { + for (; sm != NULL; sm = sm->next) { if (sm->type == DETECT_DECODE_EVENT) goto deonly; if (sm->type == DETECT_ENGINE_EVENT) @@ -389,21 +391,19 @@ static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) deonly: if (!(de_ctx->flags & DE_QUIET)) { SCLogDebug("DE-ONLY (%" PRIu32 "): source %s, dest %s", s->id, - s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET", - s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET"); + s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET", + s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET"); } SCReturnInt(1); } -#define MASK_TCP_INITDEINIT_FLAGS (TH_SYN|TH_RST|TH_FIN) -#define MASK_TCP_UNUSUAL_FLAGS (TH_URG|TH_ECN|TH_CWR) +#define MASK_TCP_INITDEINIT_FLAGS (TH_SYN | TH_RST | TH_FIN) +#define MASK_TCP_UNUSUAL_FLAGS (TH_URG | TH_ECN | TH_CWR) /* Create mask for this packet + it's flow if it has one */ -void -PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, - bool app_decoder_events) +void PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, bool app_decoder_events) { if (!(p->flags & PKT_NOPAYLOAD_INSPECTION) && p->payload_len > 0) { SCLogDebug("packet has payload"); @@ -478,10 +478,9 @@ static int SignatureCreateMask(Signature *s) } SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { - switch(sm->type) { - case DETECT_FLOWBITS: - { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLOWBITS: { /* figure out what flowbit action */ DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx; if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { @@ -489,23 +488,22 @@ static int SignatureCreateMask(Signature *s) s->flags |= SIG_FLAG_REQUIRE_FLOWVAR; SCLogDebug("SIG_FLAG_REQUIRE_FLOWVAR set as sig has " - "flowbit isset option."); + "flowbit isset option."); } /* flow is required for any flowbit manipulation */ s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow to be able to manipulate " - "flowbit(s)"); + "flowbit(s)"); break; } case DETECT_FLOWINT: /* flow is required for any flowint manipulation */ s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow to be able to manipulate " - "flowint(s)"); + "flowint(s)"); break; - case DETECT_FLAGS: - { + case DETECT_FLAGS: { DetectFlagsData *fl = (DetectFlagsData *)sm->ctx; if (fl->flags & TH_SYN) { @@ -534,8 +532,7 @@ static int SignatureCreateMask(Signature *s) } break; } - case DETECT_DSIZE: - { + case DETECT_DSIZE: { DetectU16Data *ds = (DetectU16Data *)sm->ctx; /* LT will include 0, so no payload. * if GT is used in the same rule the @@ -657,7 +654,7 @@ 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[ALPROTO_MAX] = { 0 }; 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]; @@ -737,16 +734,22 @@ static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigG DetectPort *dp = s->dp; if (s->flags & SIG_FLAG_TOSERVER) { if (dp->port == 0 && dp->port2 == 65535) { - SCLogDebug("SGH %p toserver 1byte fast_pattern to ANY. Rule %u", sgh, s->id); + SCLogDebug("SGH %p toserver 1byte fast_pattern to ANY. Rule %u", sgh, + s->id); } else { - SCLogDebug("SGH %p toserver 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, dp->port, dp->port2, s->id); + SCLogDebug( + "SGH %p toserver 1byte fast_pattern to port(s) %u-%u. Rule %u", + sgh, dp->port, dp->port2, s->id); } } if (s->flags & SIG_FLAG_TOCLIENT) { if (sp->port == 0 && sp->port2 == 65535) { - SCLogDebug("SGH %p toclient 1byte fast_pattern to ANY. Rule %u", sgh, s->id); + SCLogDebug("SGH %p toclient 1byte fast_pattern to ANY. Rule %u", sgh, + s->id); } else { - SCLogDebug("SGH %p toclient 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, sp->port, sp->port2, s->id); + SCLogDebug( + "SGH %p toclient 1byte fast_pattern to port(s) %u-%u. Rule %u", + sgh, sp->port, sp->port2, s->id); } } } @@ -771,14 +774,17 @@ static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigG mpm_cnt++; if (w < 10) { - SCLogDebug("SGH %p Weak MPM Pattern on %s. Rule %u", sgh, DetectListToString(mpm_list), s->id); + SCLogDebug("SGH %p Weak MPM Pattern on %s. Rule %u", sgh, + DetectListToString(mpm_list), s->id); } if (w < 10 && any == 5) { - SCLogDebug("SGH %p Weak MPM Pattern on %s, rule is 5xAny. Rule %u", sgh, DetectListToString(mpm_list), s->id); + SCLogDebug("SGH %p Weak MPM Pattern on %s, rule is 5xAny. Rule %u", sgh, + DetectListToString(mpm_list), s->id); } if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("SGH %p MPM Pattern on %s, is negated. Rule %u", sgh, DetectListToString(mpm_list), s->id); + SCLogDebug("SGH %p MPM Pattern on %s, is negated. Rule %u", sgh, + DetectListToString(mpm_list), s->id); negmpm_cnt++; } if (cd->flags & DETECT_CONTENT_ENDS_WITH) { @@ -864,7 +870,8 @@ static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigG json_t *buf = json_object(); json_object_set_new(buf, "total", json_integer(mpm_stats[i].cnt)); - json_object_set_new(buf, "avg_strength", json_integer(mpm_stats[i].total / mpm_stats[i].cnt)); + json_object_set_new( + buf, "avg_strength", json_integer(mpm_stats[i].total / mpm_stats[i].cnt)); json_object_set_new(buf, "min_strength", json_integer(mpm_stats[i].min)); json_object_set_new(buf, "max_strength", json_integer(mpm_stats[i].max)); @@ -889,8 +896,8 @@ static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigG return js; } -static void RulesDumpGrouping(const DetectEngineCtx *de_ctx, - const int add_rules, const int add_mpm_stats) +static void RulesDumpGrouping( + const DetectEngineCtx *de_ctx, const int add_rules, const int add_mpm_stats) { json_t *js = json_object(); if (unlikely(js == NULL)) @@ -904,8 +911,7 @@ static void RulesDumpGrouping(const DetectEngineCtx *de_ctx, json_t *tcp = json_object(); json_t *ts_array = json_array(); - DetectPort *list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[1].tcp : - de_ctx->flow_gh[1].udp; + DetectPort *list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[1].tcp : de_ctx->flow_gh[1].udp; while (list != NULL) { json_t *port = json_object(); json_object_set_new(port, "port", json_integer(list->port)); @@ -921,8 +927,7 @@ static void RulesDumpGrouping(const DetectEngineCtx *de_ctx, json_object_set_new(tcp, "toserver", ts_array); json_t *tc_array = json_array(); - list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[0].tcp : - de_ctx->flow_gh[0].udp; + list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[0].tcp : de_ctx->flow_gh[0].udp; while (list != NULL) { json_t *port = json_object(); json_object_set_new(port, "port", json_integer(list->port)); @@ -970,8 +975,7 @@ static void RulesDumpGrouping(const DetectEngineCtx *de_ctx, return; } - char *js_s = json_dumps(js, - JSON_PRESERVE_ORDER|JSON_ESCAPE_SLASH); + char *js_s = json_dumps(js, JSON_PRESERVE_ORDER | JSON_ESCAPE_SLASH); if (unlikely(js_s == NULL)) { fclose(fp); return; @@ -991,10 +995,10 @@ static int RulesGroupByProto(DetectEngineCtx *de_ctx) Signature *s = de_ctx->sig_list; uint32_t max_idx = 0; - SigGroupHead *sgh_ts[256] = {NULL}; - SigGroupHead *sgh_tc[256] = {NULL}; + SigGroupHead *sgh_ts[256] = { NULL }; + SigGroupHead *sgh_tc[256] = { NULL }; - for ( ; s != NULL; s = s->next) { + for (; s != NULL; s = s->next) { if (s->type == SIG_TYPE_IPONLY) continue; @@ -1003,7 +1007,7 @@ static int RulesGroupByProto(DetectEngineCtx *de_ctx) if (p == IPPROTO_TCP || p == IPPROTO_UDP) { continue; } - if (!(s->proto.proto[p / 8] & (1<<(p % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) { + if (!(s->proto.proto[p / 8] & (1 << (p % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) { continue; } @@ -1053,8 +1057,7 @@ static int RulesGroupByProto(DetectEngineCtx *de_ctx) ref++; } } - SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", - "toserver", cnt, own, ref); + SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", "toserver", cnt, own, ref); cnt = 0; own = 0; @@ -1086,8 +1089,7 @@ static int RulesGroupByProto(DetectEngineCtx *de_ctx) ref++; } } - SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", - "toclient", cnt, own, ref); + SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", "toclient", cnt, own, ref); for (p = 0; p < 256; p++) { if (p == IPPROTO_TCP || p == IPPROTO_UDP) @@ -1100,8 +1102,7 @@ static int RulesGroupByProto(DetectEngineCtx *de_ctx) return 0; } -static int PortIsWhitelisted(const DetectEngineCtx *de_ctx, - const DetectPort *a, int ipproto) +static int PortIsWhitelisted(const DetectEngineCtx *de_ctx, const DetectPort *a, int ipproto) { DetectPort *w = de_ctx->tcp_whitelist; if (ipproto == IPPROTO_UDP) @@ -1159,7 +1160,8 @@ static int RuleSetWhitelist(Signature *s) return wl; } -int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx); +int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, + uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx); int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b); static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, uint32_t direction) @@ -1177,7 +1179,8 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u if (s->type == SIG_TYPE_IPONLY) goto next; /* Protocol does not match the Signature protocol and is neither IP or pkthdr */ - if (!(s->proto.proto[ipproto / 8] & (1<<(ipproto % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) + if (!(s->proto.proto[ipproto / 8] & (1 << (ipproto % 8)) || + (s->proto.flags & DETECT_PROTO_ANY))) goto next; /* Direction does not match Signature direction */ if (direction == SIG_FLAG_TOSERVER) { @@ -1212,7 +1215,7 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u while (p) { int pwl = PortIsWhitelisted(de_ctx, p, ipproto) ? DETECT_PGSCORE_RULE_PORT_WHITELISTED : 0; - pwl = MAX(wl,pwl); + pwl = MAX(wl, pwl); DetectPort *lookup = DetectPortHashLookup(de_ctx, p); if (lookup) { @@ -1235,14 +1238,12 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u /* step 2: create a list of DetectPort objects */ HashListTableBucket *htb = NULL; - for (htb = HashListTableGetListHead(de_ctx->dport_hash_table); - htb != NULL; - htb = HashListTableGetListNext(htb)) - { + for (htb = HashListTableGetListHead(de_ctx->dport_hash_table); htb != NULL; + htb = HashListTableGetListNext(htb)) { DetectPort *p = HashListTableGetListData(htb); DetectPort *tmp = DetectPortCopySingle(de_ctx, p); BUG_ON(tmp == NULL); - int r = DetectPortInsert(de_ctx, &list , tmp); + int r = DetectPortInsert(de_ctx, &list, tmp); BUG_ON(r == -1); } DetectPortHashFree(de_ctx); @@ -1251,8 +1252,8 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u /* step 3: group the list and shrink it if necessary */ DetectPort *newlist = NULL; - uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_groups : - de_ctx->max_uniq_toserver_groups; + uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_groups + : de_ctx->max_uniq_toserver_groups; CreateGroupedPortList(de_ctx, list, &newlist, groupmax, CreateGroupedPortListCmpCnt, max_idx); list = newlist; @@ -1264,8 +1265,8 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u uint32_t own = 0; uint32_t ref = 0; DetectPort *iter; - for (iter = list ; iter != NULL; iter = iter->next) { - BUG_ON (iter->sh == NULL); + for (iter = list; iter != NULL; iter = iter->next) { + BUG_ON(iter->sh == NULL); DEBUG_VALIDATE_BUG_ON(own + ref != cnt); cnt++; @@ -1298,10 +1299,8 @@ static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, uint8_t ipproto, u iter->sh->init->whitelist); } #endif - SCLogPerf("%s %s: %u port groups, %u unique SGH's, %u copies", - ipproto == 6 ? "TCP" : "UDP", - direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", - cnt, own, ref); + SCLogPerf("%s %s: %u port groups, %u unique SGH's, %u copies", ipproto == 6 ? "TCP" : "UDP", + direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", cnt, own, ref); return list; } @@ -1395,28 +1394,29 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) if (de_ctx->sig_array == NULL) goto error; - SCLogDebug("signature lookup array: %" PRIu32 " sigs, %" PRIu32 " bytes", - de_ctx->sig_array_len, de_ctx->sig_array_size); + SCLogDebug("signature lookup array: %" PRIu32 " sigs, %" PRIu32 " bytes", de_ctx->sig_array_len, + de_ctx->sig_array_size); /* now for every rule add the source group */ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) { de_ctx->sig_array[s->num] = s; - SCLogDebug("Signature %" PRIu32 ", internal id %" PRIu32 ", ptrs %p %p ", s->id, s->num, s, de_ctx->sig_array[s->num]); + SCLogDebug("Signature %" PRIu32 ", internal id %" PRIu32 ", ptrs %p %p ", s->id, s->num, s, + de_ctx->sig_array[s->num]); if (s->type == SIG_TYPE_PDONLY) { - SCLogDebug("Signature %"PRIu32" is considered \"PD only\"", s->id); + SCLogDebug("Signature %" PRIu32 " is considered \"PD only\"", s->id); } else if (s->type == SIG_TYPE_IPONLY) { - SCLogDebug("Signature %"PRIu32" is considered \"IP only\"", s->id); + SCLogDebug("Signature %" PRIu32 " is considered \"IP only\"", s->id); cnt_iponly++; } else if (SignatureIsInspectingPayload(de_ctx, s) == 1) { - SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", s->id); + SCLogDebug("Signature %" PRIu32 " is considered \"Payload inspecting\"", s->id); cnt_payload++; } else if (s->type == SIG_TYPE_DEONLY) { - SCLogDebug("Signature %"PRIu32" is considered \"Decoder Event only\"", s->id); + SCLogDebug("Signature %" PRIu32 " is considered \"Decoder Event only\"", s->id); cnt_deonly++; } else if (s->flags & SIG_FLAG_APPLAYER) { - SCLogDebug("Signature %"PRIu32" is considered \"Applayer inspecting\"", s->id); + SCLogDebug("Signature %" PRIu32 " is considered \"Applayer inspecting\"", s->id); cnt_applayer++; } @@ -1439,7 +1439,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) if (copresent && colen == 1) { SCLogDebug("signature %8u content maxlen 1", s->id); for (int proto = 0; proto < 256; proto++) { - if (s->proto.proto[(proto/8)] & (1<<(proto%8))) + if (s->proto.proto[(proto / 8)] & (1 << (proto % 8))) SCLogDebug("=> proto %" PRId32 "", proto); } } @@ -1458,8 +1458,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) /* if keyword engines are enabled in the config, handle them here */ if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO && - !(s->flags & SIG_FLAG_PREFILTER)) - { + !(s->flags & SIG_FLAG_PREFILTER)) { int prefilter_list = DETECT_TBLSIZE; // TODO buffers? @@ -1482,7 +1481,8 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) if (sm->type == prefilter_list) { s->init_data->prefilter_sm = sm; s->flags |= SIG_FLAG_PREFILTER; - SCLogConfig("sid %u: prefilter is on \"%s\"", s->id, sigmatch_table[sm->type].name); + SCLogConfig("sid %u: prefilter is on \"%s\"", s->id, + sigmatch_table[sm->type].name); break; } } @@ -1516,7 +1516,7 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) de_ctx->sig_cnt, cnt_iponly, cnt_payload, cnt_applayer, cnt_deonly); SCLogConfig("building signature grouping structure, stage 1: " - "preprocessing rules... complete"); + "preprocessing rules... complete"); } if (DetectFlowbitsAnalyze(de_ctx) != 0) @@ -1575,7 +1575,8 @@ int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) * The joingr is meant to be a catch all. * */ -int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) +int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, + uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) { DetectPort *tmplist = NULL, *joingr = NULL; char insert = 0; @@ -1604,7 +1605,7 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect tmplist = list; } else { /* look for the place to insert */ - for ( ; tmpgr != NULL && !insert; tmpgr = tmpgr->next) { + for (; tmpgr != NULL && !insert; tmpgr = tmpgr->next) { if (CompareFunc(list, tmpgr) == 1) { if (tmpgr == tmplist) { list->next = tmplist; @@ -1636,7 +1637,7 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect * count. The rest is added to the 'join' group. */ DetectPort *tmplist2 = NULL, *tmplist2_tail = NULL; DetectPort *gr, *next_gr; - for (gr = tmplist; gr != NULL; ) { + for (gr = tmplist; gr != NULL;) { next_gr = gr->next; SCLogDebug("temp list gr %p %u:%u", gr, gr->port, gr->port2); @@ -1653,12 +1654,12 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect SCLogDebug("joingr => %u-%u", joingr->port, joingr->port2); joingr->next = NULL; } - SigGroupHeadCopySigs(de_ctx,gr->sh,&joingr->sh); + SigGroupHeadCopySigs(de_ctx, gr->sh, &joingr->sh); /* when a group's sigs are added to the joingr, we can free it */ gr->next = NULL; DetectPortFree(de_ctx, gr); - /* append */ + /* append */ } else { gr->next = NULL; @@ -1683,10 +1684,10 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect if (tmplist2 == NULL) { tmplist2 = joingr; - //tmplist2_tail = joingr; + // tmplist2_tail = joingr; } else { tmplist2_tail->next = joingr; - //tmplist2_tail = joingr; + // tmplist2_tail = joingr; } } else { SCLogDebug("no joingr"); @@ -1707,7 +1708,7 @@ int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, Detect */ static void DetectEngineAddDecoderEventSig(DetectEngineCtx *de_ctx, Signature *s) { - SCLogDebug("adding signature %"PRIu32" to the decoder event sgh", s->id); + SCLogDebug("adding signature %" PRIu32 " to the decoder event sgh", s->id); SigGroupHeadAppendSig(de_ctx, &de_ctx->decoder_event_sgh, s); } @@ -1723,7 +1724,7 @@ static void DetectEngineAddDecoderEventSig(DetectEngineCtx *de_ctx, Signature *s int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) { SCLogDebug("building signature grouping structure, stage 2: " - "building source address lists..."); + "building source address lists..."); IPOnlyInit(de_ctx, &de_ctx->io_ctx); @@ -1737,7 +1738,7 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) /* now for every rule add the source group to our temp lists */ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) { - SCLogDebug("s->id %"PRIu32, s->id); + SCLogDebug("s->id %" PRIu32, s->id); if (s->type == SIG_TYPE_IPONLY) { IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, s); } else if (s->type == SIG_TYPE_DEONLY) { @@ -1845,7 +1846,7 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) { SCEnter(); - //SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt); + // SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt); uint32_t cnt = 0; for (uint32_t idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { @@ -1926,7 +1927,8 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx) /* built-ins */ for (int type = 0; type < DETECT_SM_LIST_MAX; type++) { /* skip PMATCH if it is used in a stream 'app engine' instead */ - if (type == DETECT_SM_LIST_PMATCH && (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH)) + if (type == DETECT_SM_LIST_PMATCH && + (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH)) continue; SigMatch *sm = s->init_data->smlists[type]; s->sm_arrays[type] = SigMatchList2DataArray(sm); @@ -2050,7 +2052,7 @@ int SigGroupBuild(DetectEngineCtx *de_ctx) return 0; } -int SigGroupCleanup (DetectEngineCtx *de_ctx) +int SigGroupCleanup(DetectEngineCtx *de_ctx) { SigAddressCleanupStage1(de_ctx); diff --git a/src/detect-engine-build.h b/src/detect-engine-build.h index 2c9c48792856..80ac67062ef4 100644 --- a/src/detect-engine-build.h +++ b/src/detect-engine-build.h @@ -18,8 +18,7 @@ #ifndef __DETECT_ENGINE_BUILD_H__ #define __DETECT_ENGINE_BUILD_H__ -void PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, - bool app_decoder_events); +void PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, bool app_decoder_events); int SignatureIsFilestoring(const Signature *); int SignatureIsFilemagicInspecting(const Signature *); @@ -38,6 +37,6 @@ int SigAddressCleanupStage1(DetectEngineCtx *de_ctx); void SigCleanSignatures(DetectEngineCtx *); int SigGroupBuild(DetectEngineCtx *); -int SigGroupCleanup (DetectEngineCtx *de_ctx); +int SigGroupCleanup(DetectEngineCtx *de_ctx); #endif /* __DETECT_ENGINE_BUILD_H__ */ diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index 0070494380c2..c12603d4a0e7 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -51,19 +51,19 @@ #include "detect-dataset.h" #include "detect-datarep.h" -#include "util-spm.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-validate.h" +#include "util/spm.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/validate.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-profiling.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/profiling.h" #include "rust.h" #ifdef HAVE_LUA -#include "util-lua.h" +#include "util/lua/lua.h" #endif /** @@ -117,14 +117,14 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT if (smd->type == DETECT_CONTENT) { const DetectContentData *cd = (const DetectContentData *)smd->ctx; - SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); + SCLogDebug("inspecting content %" PRIu32 " buffer_len %" PRIu32, cd->id, buffer_len); /* we might have already have this content matched by the mpm. * (if there is any other reason why we'd want to avoid checking * it here, please fill it in) */ - //if (cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED) { - // goto match; - //} + // if (cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED) { + // goto match; + // } /* rule parsers should take care of this */ #ifdef DEBUG @@ -140,8 +140,7 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT uint32_t prev_buffer_offset = det_ctx->buffer_offset; do { - if ((cd->flags & DETECT_CONTENT_DISTANCE) || - (cd->flags & DETECT_CONTENT_WITHIN)) { + if ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN)) { SCLogDebug("det_ctx->buffer_offset %" PRIu32, det_ctx->buffer_offset); offset = prev_buffer_offset; @@ -155,22 +154,27 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT else offset += distance; - SCLogDebug("cd->distance %"PRIi32", offset %"PRIu32", depth %"PRIu32, - distance, offset, depth); + SCLogDebug("cd->distance %" PRIi32 ", offset %" PRIu32 ", depth %" PRIu32, + distance, offset, depth); } if (cd->flags & DETECT_CONTENT_WITHIN) { if (cd->flags & DETECT_CONTENT_WITHIN_VAR) { - if ((int32_t)depth > (int32_t)(prev_buffer_offset + det_ctx->byte_values[cd->within] + distance)) { - depth = prev_buffer_offset + det_ctx->byte_values[cd->within] + distance; + if ((int32_t)depth > + (int32_t)(prev_buffer_offset + det_ctx->byte_values[cd->within] + + distance)) { + depth = prev_buffer_offset + det_ctx->byte_values[cd->within] + + distance; } } else { - if ((int32_t)depth > (int32_t)(prev_buffer_offset + cd->within + distance)) { + if ((int32_t)depth > + (int32_t)(prev_buffer_offset + cd->within + distance)) { depth = prev_buffer_offset + cd->within + distance; } - SCLogDebug("cd->within %"PRIi32", det_ctx->buffer_offset %"PRIu32", depth %"PRIu32, - cd->within, prev_buffer_offset, depth); + SCLogDebug("cd->within %" PRIi32 ", det_ctx->buffer_offset %" PRIu32 + ", depth %" PRIu32, + cd->within, prev_buffer_offset, depth); } if (stream_start_offset != 0 && prev_buffer_offset == 0) { @@ -194,7 +198,7 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT depth = prev_buffer_offset + cd->depth; } - SCLogDebug("cd->depth %"PRIu32", depth %"PRIu32, cd->depth, depth); + SCLogDebug("cd->depth %" PRIu32 ", depth %" PRIu32, cd->depth, depth); } } @@ -204,7 +208,7 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT } else { if (cd->offset > offset) { offset = cd->offset; - SCLogDebug("setting offset %"PRIu32, offset); + SCLogDebug("setting offset %" PRIu32, offset); } } } else { /* implied no relative matches */ @@ -238,17 +242,18 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT /* If the value came from a variable, make sure to adjust the depth so it's relative * to the offset value. */ - if (cd->flags & (DETECT_CONTENT_DISTANCE_VAR|DETECT_CONTENT_OFFSET_VAR|DETECT_CONTENT_DEPTH_VAR)) { - depth += offset; + if (cd->flags & (DETECT_CONTENT_DISTANCE_VAR | DETECT_CONTENT_OFFSET_VAR | + DETECT_CONTENT_DEPTH_VAR)) { + depth += offset; } /* update offset with prev_offset if we're searching for * matches after the first occurrence. */ - SCLogDebug("offset %"PRIu32", prev_offset %"PRIu32, offset, prev_offset); + SCLogDebug("offset %" PRIu32 ", prev_offset %" PRIu32, offset, prev_offset); if (prev_offset != 0) offset = prev_offset; - SCLogDebug("offset %"PRIu32", depth %"PRIu32, offset, depth); + SCLogDebug("offset %" PRIu32 ", depth %" PRIu32, offset, depth); if (depth > buffer_len) depth = buffer_len; @@ -271,19 +276,20 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT BUG_ON(sbuffer_len > buffer_len); #endif if (cd->flags & DETECT_CONTENT_ENDS_WITH && depth < buffer_len) { - SCLogDebug("depth < buffer_len while DETECT_CONTENT_ENDS_WITH is set. Can't possibly match."); + SCLogDebug("depth < buffer_len while DETECT_CONTENT_ENDS_WITH is set. Can't " + "possibly match."); found = NULL; } else if (cd->content_len > sbuffer_len) { found = NULL; } else { /* do the actual search */ - found = SpmScan(cd->spm_ctx, det_ctx->spm_thread_ctx, sbuffer, - sbuffer_len); + found = SpmScan(cd->spm_ctx, det_ctx->spm_thread_ctx, sbuffer, sbuffer_len); } /* next we evaluate the result in combination with the * negation flag. */ - SCLogDebug("found %p cd negated %s", found, cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); + SCLogDebug("found %p cd negated %s", found, + cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); if (found == NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) { @@ -374,7 +380,7 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT } } - } while(1); + } while (1); } else if (smd->type == DETECT_ISDATAAT) { SCLogDebug("inspecting isdataat"); @@ -385,19 +391,21 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT uint64_t be_value = det_ctx->byte_values[dataat]; if (be_value >= 100000000) { if ((id->flags & ISDATAAT_NEGATED) == 0) { - SCLogDebug("extracted value %"PRIu64" very big: no match", be_value); + SCLogDebug("extracted value %" PRIu64 " very big: no match", be_value); goto no_match; } - SCLogDebug("extracted value way %"PRIu64" very big: match", be_value); + SCLogDebug("extracted value way %" PRIu64 " very big: match", be_value); goto match; } dataat = (uint32_t)be_value; - SCLogDebug("isdataat: using value %u from byte_extract local_id %u", dataat, id->dataat); + SCLogDebug( + "isdataat: using value %u from byte_extract local_id %u", dataat, id->dataat); } if (id->flags & ISDATAAT_RELATIVE) { if (det_ctx->buffer_offset + dataat > buffer_len) { - SCLogDebug("det_ctx->buffer_offset + dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + dataat, buffer_len); + SCLogDebug("det_ctx->buffer_offset + dataat %" PRIu32 " > %" PRIu32, + det_ctx->buffer_offset + dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; goto no_match; @@ -414,7 +422,9 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT goto no_match; goto match; } else { - SCLogDebug("absolute isdataat mismatch, id->isdataat %"PRIu32", buffer_len %"PRIu32"", dataat, buffer_len); + SCLogDebug("absolute isdataat mismatch, id->isdataat %" PRIu32 + ", buffer_len %" PRIu32 "", + dataat, buffer_len); if (id->flags & ISDATAAT_NEGATED) goto match; goto no_match; @@ -479,8 +489,7 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT if (btflags & DETECT_BYTETEST_DCE) { /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ - btflags |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? - DETECT_BYTETEST_LITTLE: 0); + btflags |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? DETECT_BYTETEST_LITTLE : 0); } if (DetectBytetestDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, btflags, offset, nbytes, @@ -511,8 +520,7 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT if (bjflags & DETECT_BYTEJUMP_DCE) { /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ - bjflags |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? - DETECT_BYTEJUMP_LITTLE: 0); + bjflags |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? DETECT_BYTEJUMP_LITTLE : 0); } if (!DetectBytejumpDoMatch( @@ -530,13 +538,13 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && - endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE && - flags & (DETECT_CI_FLAGS_DCE_LE|DETECT_CI_FLAGS_DCE_BE)) { + endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE && + flags & (DETECT_CI_FLAGS_DCE_LE | DETECT_CI_FLAGS_DCE_BE)) { /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ - endian |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? - DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); + endian |= ((flags & DETECT_CI_FLAGS_DCE_LE) ? DETECT_BYTE_EXTRACT_ENDIAN_LITTLE + : DETECT_BYTE_EXTRACT_ENDIAN_BIG); } if (DetectByteExtractDoMatch(det_ctx, smd, s, buffer, buffer_len, @@ -544,8 +552,8 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT goto no_match; } - SCLogDebug("[BE] Fetched value for index %d: %"PRIu64, - bed->local_id, det_ctx->byte_values[bed->local_id]); + SCLogDebug("[BE] Fetched value for index %d: %" PRIu64, bed->local_id, + det_ctx->byte_values[bed->local_id]); goto match; } else if (smd->type == DETECT_BYTEMATH) { @@ -582,8 +590,8 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT goto no_match; } - SCLogDebug("[BM] Fetched value for index %d: %"PRIu64, - bmd->local_id, det_ctx->byte_values[bmd->local_id]); + SCLogDebug("[BM] Fetched value for index %d: %" PRIu64, bmd->local_id, + det_ctx->byte_values[bmd->local_id]); goto match; } else if (smd->type == DETECT_BSIZE) { @@ -600,9 +608,9 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT } else if (smd->type == DETECT_DATASET) { - //PrintRawDataFp(stdout, buffer, buffer_len); - const DetectDatasetData *sd = (const DetectDatasetData *) smd->ctx; - int r = DetectDatasetBufferMatch(det_ctx, sd, buffer, buffer_len); //TODO buffer offset? + // PrintRawDataFp(stdout, buffer, buffer_len); + const DetectDatasetData *sd = (const DetectDatasetData *)smd->ctx; + int r = DetectDatasetBufferMatch(det_ctx, sd, buffer, buffer_len); // TODO buffer offset? if (r == 1) { goto match; } @@ -610,9 +618,9 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT } else if (smd->type == DETECT_DATAREP) { - //PrintRawDataFp(stdout, buffer, buffer_len); - const DetectDatarepData *sd = (const DetectDatarepData *) smd->ctx; - int r = DetectDatarepBufferMatch(det_ctx, sd, buffer, buffer_len); //TODO buffer offset? + // PrintRawDataFp(stdout, buffer, buffer_len); + const DetectDatarepData *sd = (const DetectDatarepData *)smd->ctx; + int r = DetectDatarepBufferMatch(det_ctx, sd, buffer, buffer_len); // TODO buffer offset? if (r == 1) { goto match; } @@ -634,13 +642,11 @@ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineT } goto no_match_discontinue; #ifdef HAVE_LUA - } - else if (smd->type == DETECT_LUA) { + } else if (smd->type == DETECT_LUA) { SCLogDebug("lua starting"); - if (DetectLuaMatchBuffer(det_ctx, s, smd, buffer, buffer_len, - det_ctx->buffer_offset, f) != 1) - { + if (DetectLuaMatchBuffer(det_ctx, s, smd, buffer, buffer_len, det_ctx->buffer_offset, f) != + 1) { SCLogDebug("lua no_match"); goto no_match; } diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 188ebef2d881..34677dea7588 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -36,15 +36,16 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, }; -#define DETECT_CI_FLAGS_START BIT_U8(0) /**< unused, reserved for future use */ -#define DETECT_CI_FLAGS_END BIT_U8(1) /**< indication that current buffer - * is the end of the data */ -#define DETECT_CI_FLAGS_DCE_LE BIT_U8(2) /**< DCERPC record in little endian */ -#define DETECT_CI_FLAGS_DCE_BE BIT_U8(3) /**< DCERPC record in big endian */ +#define DETECT_CI_FLAGS_START BIT_U8(0) /**< unused, reserved for future use */ +#define DETECT_CI_FLAGS_END \ + BIT_U8(1) /**< indication that current buffer \ + * is the end of the data */ +#define DETECT_CI_FLAGS_DCE_LE BIT_U8(2) /**< DCERPC record in little endian */ +#define DETECT_CI_FLAGS_DCE_BE BIT_U8(3) /**< DCERPC record in big endian */ /** buffer is a single, non-streaming, buffer. Data sent to the content * inspection function contains both start and end of the data. */ -#define DETECT_CI_FLAGS_SINGLE (DETECT_CI_FLAGS_START|DETECT_CI_FLAGS_END) +#define DETECT_CI_FLAGS_SINGLE (DETECT_CI_FLAGS_START | DETECT_CI_FLAGS_END) /* "internal" returns 1 match, 0 no match, -1 can't match */ int DetectEngineContentInspectionInternal(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index f624b11e39b6..f586584b774c 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -44,16 +44,15 @@ #include "app-layer.h" #include "flow-util.h" -#include "util-debug.h" +#include "util/debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-dce-iface.h" static int g_dce_stub_data_buffer_id = 0; - /**************************************Unittests*******************************/ #ifdef UNITTESTS @@ -66,6 +65,7 @@ static int DcePayloadTest15(void) { int result = 0; + // clang-format off uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -81,6 +81,7 @@ static int DcePayloadTest15(void) 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on uint32_t request1_len = sizeof(request1); TcpSession ssn; @@ -92,11 +93,11 @@ static int DcePayloadTest15(void) int r; const char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_test:2,=,14080,0,relative,dce; sid:1;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_test:2,=,14080,0,relative,dce; sid:1;)"; const char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_test:2,=,46,5,relative,dce; sid:2;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_test:2,=,46,5,relative,dce; sid:2;)"; Signature *s; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -107,7 +108,7 @@ static int DcePayloadTest15(void) p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -136,8 +137,8 @@ static int DcePayloadTest15(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -180,6 +181,7 @@ static int DcePayloadTest16(void) { int result = 0; + // clang-format off uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -195,6 +197,7 @@ static int DcePayloadTest16(void) 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on uint32_t request1_len = sizeof(request1); TcpSession ssn; @@ -206,11 +209,11 @@ static int DcePayloadTest16(void) int r; const char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_test:2,=,55,0,relative; sid:1;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_test:2,=,55,0,relative; sid:1;)"; const char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_test:2,=,11776,5,relative; sid:2;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_test:2,=,11776,5,relative; sid:2;)"; Signature *s; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -221,7 +224,7 @@ static int DcePayloadTest16(void) p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -250,8 +253,8 @@ static int DcePayloadTest16(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -294,6 +297,7 @@ static int DcePayloadTest17(void) { int result = 0; + // clang-format off uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -309,6 +313,7 @@ static int DcePayloadTest17(void) 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on uint32_t request1_len = sizeof(request1); TcpSession ssn; @@ -320,11 +325,11 @@ static int DcePayloadTest17(void) int r; const char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_test:2,=,55,0,relative,big; sid:1;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_test:2,=,55,0,relative,big; sid:1;)"; const char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_test:2,=,46,5,relative,little; sid:2;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_test:2,=,46,5,relative,little; sid:2;)"; Signature *s; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -335,7 +340,7 @@ static int DcePayloadTest17(void) p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -364,8 +369,8 @@ static int DcePayloadTest17(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -408,6 +413,7 @@ static int DcePayloadTest18(void) { int result = 0; + // clang-format off uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -423,6 +429,7 @@ static int DcePayloadTest18(void) 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on uint32_t request1_len = sizeof(request1); TcpSession ssn; @@ -434,11 +441,11 @@ static int DcePayloadTest18(void) int r; const char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_jump:2,0,relative,dce; byte_test:2,=,46,0,relative,dce; sid:1;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_jump:2,0,relative,dce; byte_test:2,=,46,0,relative,dce; sid:1;)"; const char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_jump:2,2,relative,dce; byte_test:2,=,14080,0,relative; sid:2;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_jump:2,2,relative,dce; byte_test:2,=,14080,0,relative; sid:2;)"; Signature *s; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -449,7 +456,7 @@ static int DcePayloadTest18(void) p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -478,8 +485,8 @@ static int DcePayloadTest18(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -522,6 +529,7 @@ static int DcePayloadTest19(void) { int result = 0; + // clang-format off uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -537,6 +545,7 @@ static int DcePayloadTest19(void) 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on uint32_t request1_len = sizeof(request1); TcpSession ssn; @@ -548,11 +557,11 @@ static int DcePayloadTest19(void) int r; const char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_jump:2,0,relative; byte_test:2,=,46,0,relative,dce; sid:1;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_jump:2,0,relative; byte_test:2,=,46,0,relative,dce; sid:1;)"; const char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_jump:2,2,relative; byte_test:2,=,14080,0,relative; sid:2;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_jump:2,2,relative; byte_test:2,=,14080,0,relative; sid:2;)"; Signature *s; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -563,7 +572,7 @@ static int DcePayloadTest19(void) p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -592,8 +601,8 @@ static int DcePayloadTest19(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -636,6 +645,7 @@ static int DcePayloadTest20(void) { int result = 0; + // clang-format off uint8_t request1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -651,6 +661,7 @@ static int DcePayloadTest20(void) 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 }; + // clang-format on uint32_t request1_len = sizeof(request1); TcpSession ssn; @@ -662,11 +673,11 @@ static int DcePayloadTest20(void) int r; const char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_jump:2,0,relative,big; byte_test:2,=,46,0,relative,dce; sid:1;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_jump:2,0,relative,big; byte_test:2,=,46,0,relative,dce; sid:1;)"; const char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " - "byte_jump:2,2,little,relative; byte_test:2,=,14080,0,relative; sid:2;)"; + "(dce_stub_data; content:\"|5c 00 5c 00 31|\"; distance:0; " + "byte_jump:2,2,little,relative; byte_test:2,=,14080,0,relative; sid:2;)"; Signature *s; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -677,7 +688,7 @@ static int DcePayloadTest20(void) p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -706,8 +717,8 @@ static int DcePayloadTest20(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, - STREAM_TOSERVER, request1, request1_len); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c index 0c5fb0a81cbe..faee8e7567ea 100644 --- a/src/detect-engine-enip.c +++ b/src/detect-engine-enip.c @@ -25,7 +25,7 @@ #include "suricata-common.h" #include "app-layer.h" -#include "app-layer-enip-common.h" +#include "app-layer/enip/parser-common.h" #include "detect.h" #include "detect-cipservice.h" @@ -33,7 +33,7 @@ #include "flow.h" -#include "util-debug.h" +#include "util/debug.h" #if 0 /** @@ -80,50 +80,39 @@ static int CIPPathMatch(CIPServiceEntry *svc, DetectCipServiceData *cipserviced) int found_class = 0; SegmentEntry *seg = NULL; - TAILQ_FOREACH(seg, &svc->segment_list, next) - { - switch(seg->segment) - { + TAILQ_FOREACH (seg, &svc->segment_list, next) { + switch (seg->segment) { case PATH_CLASS_8BIT: class = seg->value; - if (cipserviced->cipclass == class) - { - if (cipserviced->tokens == 2) - {// if rule only has class + if (cipserviced->cipclass == class) { + if (cipserviced->tokens == 2) { // if rule only has class return 1; - } else - { + } else { found_class = 1; } } break; case PATH_INSTANCE_8BIT: break; - case PATH_ATTR_8BIT: //single attribute + case PATH_ATTR_8BIT: // single attribute attrib = seg->value; - if ((cipserviced->tokens == 3) && - (cipserviced->cipclass == class) && + if ((cipserviced->tokens == 3) && (cipserviced->cipclass == class) && (cipserviced->cipattribute == attrib) && - (cipserviced->matchattribute == 1)) - { // if rule has class & attribute, matched all here + (cipserviced->matchattribute == + 1)) { // if rule has class & attribute, matched all here return 1; } - if ((cipserviced->tokens == 3) && - (cipserviced->cipclass == class) && - (cipserviced->matchattribute == 0)) - { // for negation rule on attribute + if ((cipserviced->tokens == 3) && (cipserviced->cipclass == class) && + (cipserviced->matchattribute == 0)) { // for negation rule on attribute return 1; } break; case PATH_CLASS_16BIT: class = seg->value; - if (cipserviced->cipclass == class) - { - if (cipserviced->tokens == 2) - {// if rule only has class + if (cipserviced->cipclass == class) { + if (cipserviced->tokens == 2) { // if rule only has class return 1; - } else - { + } else { found_class = 1; } } @@ -135,19 +124,14 @@ static int CIPPathMatch(CIPServiceEntry *svc, DetectCipServiceData *cipserviced) } } - if (found_class == 0) - { // if haven't matched class yet, no need to check attribute + if (found_class == 0) { // if haven't matched class yet, no need to check attribute return 0; } - if ((svc->service == CIP_SET_ATTR_LIST) || - (svc->service == CIP_GET_ATTR_LIST)) - { + if ((svc->service == CIP_SET_ATTR_LIST) || (svc->service == CIP_GET_ATTR_LIST)) { AttributeEntry *attr = NULL; - TAILQ_FOREACH (attr, &svc->attrib_list, next) - { - if (cipserviced->cipattribute == attr->attribute) - { + TAILQ_FOREACH (attr, &svc->attrib_list, next) { + if (cipserviced->cipattribute == attr->attribute) { return 1; } } @@ -162,42 +146,35 @@ static int CIPPathMatch(CIPServiceEntry *svc, DetectCipServiceData *cipserviced) * * @param cipserviced - the CIP service rule */ -static int CIPServiceMatch(ENIPTransaction *enip_data, - DetectCipServiceData *cipserviced) +static int CIPServiceMatch(ENIPTransaction *enip_data, DetectCipServiceData *cipserviced) { #ifdef DEBUG int count = 1; #endif CIPServiceEntry *svc = NULL; - //SCLogDebug("CIPServiceMatchAL"); - TAILQ_FOREACH(svc, &enip_data->service_list, next) - { - SCLogDebug("CIPServiceMatchAL service #%d : 0x%x dir %d", - count, svc->service, svc->direction); - - if (cipserviced->cipservice == svc->service) - { // compare service - //SCLogDebug("Rule Match for cip service %d",cipserviced->cipservice ); + // SCLogDebug("CIPServiceMatchAL"); + TAILQ_FOREACH (svc, &enip_data->service_list, next) { + SCLogDebug( + "CIPServiceMatchAL service #%d : 0x%x dir %d", count, svc->service, svc->direction); - if (cipserviced->tokens > 1) - { //if rule params have class and attribute + if (cipserviced->cipservice == svc->service) { // compare service + // SCLogDebug("Rule Match for cip service %d",cipserviced->cipservice ); + if (cipserviced->tokens > 1) { // if rule params have class and attribute - if ((svc->service == CIP_SET_ATTR_LIST) || (svc->service - == CIP_SET_ATTR_SINGLE) || (svc->service - == CIP_GET_ATTR_LIST) || (svc->service - == CIP_GET_ATTR_SINGLE)) - { //decode path - if (CIPPathMatch(svc, cipserviced) == 1) - { - if (svc->direction == 1) return 0; //don't match responses + if ((svc->service == CIP_SET_ATTR_LIST) || (svc->service == CIP_SET_ATTR_SINGLE) || + (svc->service == CIP_GET_ATTR_LIST) || + (svc->service == CIP_GET_ATTR_SINGLE)) { // decode path + if (CIPPathMatch(svc, cipserviced) == 1) { + if (svc->direction == 1) + return 0; // don't match responses return 1; } } - } else - { - if (svc->direction == 1) return 0; //don't match responses + } else { + if (svc->direction == 1) + return 0; // don't match responses // SCLogDebug("CIPServiceMatchAL found"); return 1; @@ -228,20 +205,17 @@ uint8_t DetectEngineInspectCIP(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *d { SCEnter(); - - ENIPTransaction *tx = (ENIPTransaction *) txv; + ENIPTransaction *tx = (ENIPTransaction *)txv; DetectCipServiceData *cipserviced = (DetectCipServiceData *)engine->smd->ctx; - if (cipserviced == NULL) - { + if (cipserviced == NULL) { SCLogDebug("no cipservice state, no match"); SCReturnInt(0); } - //SCLogDebug("DetectEngineInspectCIP %d", cipserviced->cipservice); + // SCLogDebug("DetectEngineInspectCIP %d", cipserviced->cipservice); - if (CIPServiceMatch(tx, cipserviced) == 1) - { - //SCLogDebug("DetectCIPServiceMatchAL found"); + if (CIPServiceMatch(tx, cipserviced) == 1) { + // SCLogDebug("DetectCIPServiceMatchAL found"); SCReturnInt(1); } @@ -267,19 +241,17 @@ uint8_t DetectEngineInspectENIP(DetectEngineCtx *de_ctx, DetectEngineThreadCtx * { SCEnter(); - ENIPTransaction *tx = (ENIPTransaction *) txv; + ENIPTransaction *tx = (ENIPTransaction *)txv; DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *)engine->smd->ctx; - if (enipcmdd == NULL) - { + if (enipcmdd == NULL) { SCLogDebug("no enipcommand state, no match"); SCReturnInt(0); } - //SCLogDebug("DetectEngineInspectENIP %d, %d", enipcmdd->enipcommand, tx->header.command); + // SCLogDebug("DetectEngineInspectENIP %d, %d", enipcmdd->enipcommand, tx->header.command); - if (enipcmdd->enipcommand == tx->header.command) - { + if (enipcmdd->enipcommand == tx->header.command) { // SCLogDebug("DetectENIPCommandMatchAL found!"); SCReturnInt(1); } diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index 5bbd5711259f..b31a665064ca 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -32,26 +32,25 @@ #include "flow-var.h" #include "decode-events.h" -#include "util-debug.h" +#include "util/debug.h" #include "stream-tcp.h" - /* Need to get the DEvents[] array */ #include "detect-engine-event.h" -#include "util-unittest.h" +#include "util/unittest.h" #define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z0-9_+.]+$" static DetectParseRegex parse_regex; -static int DetectEngineEventMatch (DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); -static int DetectEngineEventSetup (DetectEngineCtx *, Signature *, const char *); -static int DetectDecodeEventSetup (DetectEngineCtx *, Signature *, const char *); -static int DetectStreamEventSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectEngineEventFree (DetectEngineCtx *, void *); +static int DetectEngineEventMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectEngineEventSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectDecodeEventSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectStreamEventSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectEngineEventFree(DetectEngineCtx *, void *); #ifdef UNITTESTS void EngineEventRegisterTests(void); #endif @@ -59,12 +58,12 @@ void EngineEventRegisterTests(void); /** * \brief Registration function for decode-event: keyword */ -void DetectEngineEventRegister (void) +void DetectEngineEventRegister(void) { sigmatch_table[DETECT_ENGINE_EVENT].name = "engine-event"; sigmatch_table[DETECT_ENGINE_EVENT].Match = DetectEngineEventMatch; sigmatch_table[DETECT_ENGINE_EVENT].Setup = DetectEngineEventSetup; - sigmatch_table[DETECT_ENGINE_EVENT].Free = DetectEngineEventFree; + sigmatch_table[DETECT_ENGINE_EVENT].Free = DetectEngineEventFree; #ifdef UNITTESTS sigmatch_table[DETECT_ENGINE_EVENT].RegisterTests = EngineEventRegisterTests; #endif @@ -72,19 +71,20 @@ void DetectEngineEventRegister (void) sigmatch_table[DETECT_DECODE_EVENT].name = "decode-event"; sigmatch_table[DETECT_DECODE_EVENT].Match = DetectEngineEventMatch; sigmatch_table[DETECT_DECODE_EVENT].Setup = DetectDecodeEventSetup; - sigmatch_table[DETECT_DECODE_EVENT].Free = DetectEngineEventFree; + sigmatch_table[DETECT_DECODE_EVENT].Free = DetectEngineEventFree; sigmatch_table[DETECT_DECODE_EVENT].flags |= SIGMATCH_DEONLY_COMPAT; sigmatch_table[DETECT_STREAM_EVENT].name = "stream-event"; sigmatch_table[DETECT_STREAM_EVENT].Match = DetectEngineEventMatch; sigmatch_table[DETECT_STREAM_EVENT].Setup = DetectStreamEventSetup; - sigmatch_table[DETECT_STREAM_EVENT].Free = DetectEngineEventFree; + sigmatch_table[DETECT_STREAM_EVENT].Free = DetectEngineEventFree; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } /** - * \brief This function is used to match decoder event flags set on a packet with those passed via decode-event: + * \brief This function is used to match decoder event flags set on a packet with those passed via + * decode-event: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread @@ -95,8 +95,8 @@ void DetectEngineEventRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectEngineEventMatch (DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectEngineEventMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); @@ -126,7 +126,7 @@ static bool OutdatedEvent(const char *raw) * \retval de pointer to DetectFlowData on success * \retval NULL on failure */ -static DetectEngineEventData *DetectEngineEventParse (const char *rawstr) +static DetectEngineEventData *DetectEngineEventParse(const char *rawstr) { int i; DetectEngineEventData *de = NULL; @@ -150,7 +150,7 @@ static DetectEngineEventData *DetectEngineEventParse (const char *rawstr) } for (i = 0; DEvents[i].event_name != NULL; i++) { - if (strcasecmp(DEvents[i].event_name,copy_str) == 0) { + if (strcasecmp(DEvents[i].event_name, copy_str) == 0) { found = 1; break; } @@ -219,10 +219,9 @@ static int DetectEngineEventSetupDo( return 0; } - -static int DetectEngineEventSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectEngineEventSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { - return DetectEngineEventSetupDo (de_ctx, s, rawstr, DETECT_ENGINE_EVENT); + return DetectEngineEventSetupDo(de_ctx, s, rawstr, DETECT_ENGINE_EVENT); } /** @@ -237,12 +236,11 @@ static void DetectEngineEventFree(DetectEngineCtx *de_ctx, void *ptr) SCFree(de); } - /** * \brief this function Setup the 'decode-event' keyword by setting the correct * signature type -*/ -static int DetectDecodeEventSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) + */ +static int DetectDecodeEventSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { char drawstr[64] = "decoder."; @@ -254,8 +252,8 @@ static int DetectDecodeEventSetup (DetectEngineCtx *de_ctx, Signature *s, const /** * \brief this function Setup the 'stream-event' keyword by resolving the alias -*/ -static int DetectStreamEventSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) + */ +static int DetectStreamEventSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { char srawstr[64] = "stream."; @@ -279,7 +277,7 @@ static int DetectStreamEventSetup (DetectEngineCtx *de_ctx, Signature *s, const /** * \test EngineEventTestParse01 is a test for a valid decode-event value */ -static int EngineEventTestParse01 (void) +static int EngineEventTestParse01(void) { DetectEngineEventData *de = DetectEngineEventParse("decoder.ipv4.pkt_too_small"); @@ -290,11 +288,10 @@ static int EngineEventTestParse01 (void) PASS; } - /** * \test EngineEventTestParse02 is a test for a valid upper + lower case decode-event value */ -static int EngineEventTestParse02 (void) +static int EngineEventTestParse02(void) { DetectEngineEventData *de = DetectEngineEventParse("decoder.PPP.pkt_too_small"); @@ -308,7 +305,7 @@ static int EngineEventTestParse02 (void) /** * \test EngineEventTestParse03 is a test for a valid upper case decode-event value */ -static int EngineEventTestParse03 (void) +static int EngineEventTestParse03(void) { DetectEngineEventData *de = DetectEngineEventParse("decoder.IPV6.PKT_TOO_SMALL"); @@ -322,7 +319,7 @@ static int EngineEventTestParse03 (void) /** * \test EngineEventTestParse04 is a test for an invalid upper case decode-event value */ -static int EngineEventTestParse04 (void) +static int EngineEventTestParse04(void) { DetectEngineEventData *de = DetectEngineEventParse("decoder.IPV6.INVALID_EVENT"); @@ -336,7 +333,7 @@ static int EngineEventTestParse04 (void) /** * \test EngineEventTestParse05 is a test for an invalid char into the decode-event value */ -static int EngineEventTestParse05 (void) +static int EngineEventTestParse05(void) { DetectEngineEventData *de = DetectEngineEventParse("decoder.IPV-6,INVALID_CHAR"); @@ -350,7 +347,7 @@ static int EngineEventTestParse05 (void) /** * \test EngineEventTestParse06 is a test for match function with valid decode-event value */ -static int EngineEventTestParse06 (void) +static int EngineEventTestParse06(void) { Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -359,7 +356,7 @@ static int EngineEventTestParse06 (void) memset(&tv, 0, sizeof(ThreadVars)); - ENGINE_SET_EVENT(p,PPP_PKT_TOO_SMALL); + ENGINE_SET_EVENT(p, PPP_PKT_TOO_SMALL); DetectEngineEventData *de = DetectEngineEventParse("decoder.ppp.pkt_too_small"); FAIL_IF_NULL(de); diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 178af0472ffb..e8c4e7ef36b5 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -24,13 +24,11 @@ #ifndef __DETECT_ENGINE_EVENT_H__ #define __DETECT_ENGINE_EVENT_H__ - typedef struct DetectEngineEventData_ { uint8_t event; } DetectEngineEventData; /* prototypes */ -void DetectEngineEventRegister (void); +void DetectEngineEventRegister(void); #endif /*__DETECT_ENGINE_EVENT_H__ */ - diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index e7fd9e0c4ad7..efc578f1c4e4 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -41,13 +41,13 @@ #include "app-layer-parser.h" #include "app-layer-protos.h" -#include "app-layer-htp.h" -#include "app-layer-smtp.h" +#include "app-layer/http/parser.h" +#include "app-layer/smtp/parser.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/profiling.h" +#include "util/validate.h" /** * \brief Inspect the file inspecting keywords. @@ -186,7 +186,7 @@ uint8_t DetectFileInspectGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx SCEnter(); DEBUG_VALIDATE_BUG_ON(f->alstate != alstate); - const uint8_t direction = flags & (STREAM_TOSERVER|STREAM_TOCLIENT); + const uint8_t direction = flags & (STREAM_TOSERVER | STREAM_TOCLIENT); AppLayerGetFileState files = AppLayerParserGetTxFiles(f, alstate, tx, direction); FileContainer *ffc = files.fc; SCLogDebug("tx %p tx_id %" PRIu64 " ffc %p ffc->head %p sid %u", tx, tx_id, ffc, diff --git a/src/detect-engine-frame.c b/src/detect-engine-frame.c index 0ed70757d599..83b77d74f0ea 100644 --- a/src/detect-engine-frame.c +++ b/src/detect-engine-frame.c @@ -36,9 +36,9 @@ #include "stream-tcp.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-print.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/print.h" struct FrameStreamData { // shared between prefilter and inspect diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 63261ee716d5..a40ed64f4460 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -45,18 +45,18 @@ #include "detect-engine-threshold.h" #include "detect-engine-iponly.h" #include "detect-threshold.h" -#include "util-classification-config.h" -#include "util-rule-vars.h" +#include "util/classification-config.h" +#include "util/rule-vars.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-print.h" -#include "util-byte.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-cidr.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/print.h" +#include "util/byte.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/cidr.h" #ifdef OS_WIN32 #include @@ -81,21 +81,19 @@ static IPOnlyCIDRItem *IPOnlyCIDRItemNew(void) SCReturnPtr(item, "IPOnlyCIDRItem"); } -static uint8_t IPOnlyCIDRItemCompare(IPOnlyCIDRItem *head, - IPOnlyCIDRItem *item) +static uint8_t IPOnlyCIDRItemCompare(IPOnlyCIDRItem *head, IPOnlyCIDRItem *item) { uint8_t i = 0; for (; i < head->netmask / 32 || i < 1; i++) { if (item->ip[i] < head->ip[i]) - //if (*(uint8_t *)(item->ip + i) < *(uint8_t *)(head->ip + i)) + // if (*(uint8_t *)(item->ip + i) < *(uint8_t *)(head->ip + i)) return 1; } return 0; } -//declaration for using it already -static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head, - IPOnlyCIDRItem *item); +// declaration for using it already +static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head, IPOnlyCIDRItem *item); static int InsertRange( IPOnlyCIDRItem **pdd, IPOnlyCIDRItem *dd, const uint32_t first_in, const uint32_t last_in) @@ -189,7 +187,7 @@ static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem **pdd, const char *str) /* handle the negation case */ if (ip[0] == '!') { - dd->negated = (dd->negated)? 0 : 1; + dd->negated = (dd->negated) ? 0 : 1; ip++; } @@ -207,11 +205,11 @@ static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem **pdd, const char *str) uint32_t netmask = 0; size_t u = 0; - if ((strchr (mask, '.')) == NULL) { + if ((strchr(mask, '.')) == NULL) { /* 1.2.3.4/24 format */ for (u = 0; u < strlen(mask); u++) { - if(!isdigit((unsigned char)mask[u])) + if (!isdigit((unsigned char)mask[u])) goto error; } @@ -280,7 +278,7 @@ static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem **pdd, const char *str) dd->family = AF_INET6; - if ((mask = strchr(ip, '/')) != NULL) { + if ((mask = strchr(ip, '/')) != NULL) { mask[0] = '\0'; mask++; @@ -289,8 +287,7 @@ static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem **pdd, const char *str) goto error; /* Format is cidr val */ - if (StringParseU8RangeCheck(&dd->netmask, 10, 0, - (const char *)mask, 0, 128) < 0) { + if (StringParseU8RangeCheck(&dd->netmask, 10, 0, (const char *)mask, 0, 128) < 0) { goto error; } @@ -310,7 +307,6 @@ static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem **pdd, const char *str) memcpy(dd->ip, &in6.s6_addr, sizeof(dd->ip)); dd->netmask = 128; } - } BUG_ON(dd->family == 0); @@ -348,7 +344,6 @@ static int IPOnlyCIDRItemSetup(IPOnlyCIDRItem **gh, char *s) return -1; } - /** * \brief This function insert a IPOnlyCIDRItem * to a list of IPOnlyCIDRItems sorted by netmask @@ -358,8 +353,7 @@ static int IPOnlyCIDRItemSetup(IPOnlyCIDRItem **gh, char *s) * * \retval IPOnlyCIDRItem address of the new head if apply */ -static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head, - IPOnlyCIDRItem *item) +static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head, IPOnlyCIDRItem *item) { IPOnlyCIDRItem *it, *prev = NULL; @@ -367,7 +361,8 @@ static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head, return head; /* Compare with the head */ - if (item->netmask < head->netmask || (item->netmask == head->netmask && IPOnlyCIDRItemCompare(head, item))) { + if (item->netmask < head->netmask || + (item->netmask == head->netmask && IPOnlyCIDRItemCompare(head, item))) { item->next = head; return item; } @@ -378,9 +373,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head, return head; } - for (prev = it = head; - it != NULL && it->netmask < item->netmask; - it = it->next) + for (prev = it = head; it != NULL && it->netmask < item->netmask; it = it->next) prev = it; if (it == NULL) { @@ -403,14 +396,13 @@ static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head, * * \retval IPOnlyCIDRItem address of the new head if apply */ -static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head, - IPOnlyCIDRItem *item) +static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head, IPOnlyCIDRItem *item) { IPOnlyCIDRItem *it, *prev = NULL; /* The first element */ if (head == NULL) { - SCLogDebug("Head is NULL to insert item (%p)",item); + SCLogDebug("Head is NULL to insert item (%p)", item); return item; } @@ -428,11 +420,11 @@ static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head, /* Separate from the item list */ prev->next = NULL; - //SCLogDebug("Before:"); - //IPOnlyCIDRListPrint(head); + // SCLogDebug("Before:"); + // IPOnlyCIDRListPrint(head); head = IPOnlyCIDRItemInsertReal(head, prev); - //SCLogDebug("After:"); - //IPOnlyCIDRListPrint(head); + // SCLogDebug("After:"); + // IPOnlyCIDRListPrint(head); prev = it; } @@ -462,7 +454,7 @@ void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead) while (it != NULL) { #ifdef DEBUG i++; - SCLogDebug("Item(%p) %"PRIu32" removed", it, i); + SCLogDebug("Item(%p) %" PRIu32 " removed", it, i); #endif SCFree(it); it = next; @@ -500,11 +492,10 @@ static void IPOnlyCIDRListPrint(IPOnlyCIDRItem *tmphead) while (tmphead != NULL) { i++; - SCLogDebug("Item %"PRIu32" has netmask %"PRIu8" negated:" - " %s; IP: %s; signum: %"PRIu32, i, tmphead->netmask, - (tmphead->negated) ? "yes":"no", - inet_ntoa(*(struct in_addr*)&tmphead->ip[0]), - tmphead->signum); + SCLogDebug("Item %" PRIu32 " has netmask %" PRIu8 " negated:" + " %s; IP: %s; signum: %" PRIu32, + i, tmphead->netmask, (tmphead->negated) ? "yes" : "no", + inet_ntoa(*(struct in_addr *)&tmphead->ip[0]), tmphead->signum); tmphead = tmphead->next; } #endif @@ -546,8 +537,7 @@ static void SigNumArrayPrint(void *tmp) * * \retval SigNumArray address of the new instance */ -static SigNumArray *SigNumArrayNew(DetectEngineCtx *de_ctx, - DetectEngineIPOnlyCtx *io_ctx) +static SigNumArray *SigNumArrayNew(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) { SigNumArray *new = SCCalloc(1, sizeof(SigNumArray)); @@ -557,7 +547,7 @@ static SigNumArray *SigNumArrayNew(DetectEngineCtx *de_ctx, new->array = SCCalloc(1, io_ctx->max_idx / 8 + 1); if (new->array == NULL) { - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } new->size = io_ctx->max_idx / 8 + 1; @@ -656,8 +646,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2( address[x - 1] = '\0'; x = 0; - if ( (subhead = IPOnlyCIDRListParse2(de_ctx, address, - (negate + n_set) % 2)) == NULL) + if ((subhead = IPOnlyCIDRListParse2(de_ctx, address, (negate + n_set) % 2)) == NULL) goto error; head = IPOnlyCIDRItemInsert(head, subhead); @@ -670,8 +659,8 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2( } else if (d_set == 1) { address[x - 1] = '\0'; - rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, - SC_RULE_VARS_ADDRESS_GROUPS); + rule_var_address = + SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -681,8 +670,8 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2( goto error; } - snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, - "[%s]", rule_var_address); + snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", + rule_var_address); } else { temp_rule_var_address = SCStrdup(rule_var_address); if (unlikely(temp_rule_var_address == NULL)) { @@ -690,8 +679,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2( } } - subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, - (negate + n_set) % 2); + subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); d_set = 0; @@ -732,8 +720,8 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2( x = 0; if (d_set == 1) { - rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, - SC_RULE_VARS_ADDRESS_GROUPS); + rule_var_address = + SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -742,16 +730,15 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2( if (unlikely(temp_rule_var_address == NULL)) { goto error; } - snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, - "[%s]", rule_var_address); + snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", + rule_var_address); } else { temp_rule_var_address = SCStrdup(rule_var_address); if (unlikely(temp_rule_var_address == NULL)) { goto error; } } - subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, - (negate + n_set) % 2); + subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); d_set = 0; @@ -785,7 +772,6 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2( return head; } - /** * \brief Parses an address group sent as a character string and updates the * IPOnlyCIDRItem list @@ -828,8 +814,8 @@ static int IPOnlyCIDRListParse(const DetectEngineCtx *de_ctx, IPOnlyCIDRItem **g * \retval 0 On success. * \retval -1 On failure. */ -int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, - Signature *s, const char *addrstr, char flag) +int IPOnlySigParseAddress( + const DetectEngineCtx *de_ctx, Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); @@ -937,10 +923,8 @@ void IPOnlyDeinit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx) io_ctx->sig_mapping = NULL; } -static inline -int IPOnlyMatchCompatSMs(ThreadVars *tv, - DetectEngineThreadCtx *det_ctx, - Signature *s, Packet *p) +static inline int IPOnlyMatchCompatSMs( + ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH); SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH]; @@ -980,19 +964,19 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, SCEnter(); if (p->src.family == AF_INET) { - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), - io_ctx->tree_ipv4src, &user_data_src); + (void)SCRadixFindKeyIPV4BestMatch( + (uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), io_ctx->tree_ipv4src, &user_data_src); } else if (p->src.family == AF_INET6) { - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_SRC_ADDR(p), - io_ctx->tree_ipv6src, &user_data_src); + (void)SCRadixFindKeyIPV6BestMatch( + (uint8_t *)&GET_IPV6_SRC_ADDR(p), io_ctx->tree_ipv6src, &user_data_src); } if (p->dst.family == AF_INET) { - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_DST_ADDR_U32(p), - io_ctx->tree_ipv4dst, &user_data_dst); + (void)SCRadixFindKeyIPV4BestMatch( + (uint8_t *)&GET_IPV4_DST_ADDR_U32(p), io_ctx->tree_ipv4dst, &user_data_dst); } else if (p->dst.family == AF_INET6) { - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_DST_ADDR(p), - io_ctx->tree_ipv6dst, &user_data_dst); + (void)SCRadixFindKeyIPV6BestMatch( + (uint8_t *)&GET_IPV6_DST_ADDR(p), io_ctx->tree_ipv6dst, &user_data_dst); } src = user_data_src; @@ -1003,7 +987,7 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, uint32_t u; for (u = 0; u < src->size; u++) { - SCLogDebug("And %"PRIu8" & %"PRIu8, src->array[u], dst->array[u]); + SCLogDebug("And %" PRIu8 " & %" PRIu8, src->array[u], dst->array[u]); uint8_t bitarray = dst->array[u] & src->array[u]; @@ -1033,12 +1017,13 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, } /* check the source & dst port in the sig */ - if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { + if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || + p->proto == IPPROTO_SCTP) { if (!(s->flags & SIG_FLAG_DP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) continue; - DetectPort *dport = DetectPortLookupGroup(s->dp,p->dp); + DetectPort *dport = DetectPortLookupGroup(s->dp, p->dp); if (dport == NULL) { SCLogDebug("dport didn't match."); continue; @@ -1048,13 +1033,14 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, if (p->flags & PKT_IS_FRAGMENT) continue; - DetectPort *sport = DetectPortLookupGroup(s->sp,p->sp); + DetectPort *sport = DetectPortLookupGroup(s->sp, p->sp); if (sport == NULL) { SCLogDebug("sport didn't match."); continue; } } - } else if ((s->flags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) { + } else if ((s->flags & (SIG_FLAG_DP_ANY | SIG_FLAG_SP_ANY)) != + (SIG_FLAG_DP_ANY | SIG_FLAG_SP_ANY)) { SCLogDebug("port-less protocol and sig needs ports"); continue; } @@ -1063,8 +1049,8 @@ void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx, continue; } - SCLogDebug("Signum %"PRIu32" match (sid: %"PRIu32", msg: %s)", - u * 8 + i, s->id, s->msg); + SCLogDebug("Signum %" PRIu32 " match (sid: %" PRIu32 ", msg: %s)", u * 8 + i, + s->id, s->msg); if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH); @@ -1112,34 +1098,31 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) SCRadixNode *node = NULL; /* Prepare Src radix trees */ - for (src = (de_ctx->io_ctx).ip_src; src != NULL; ) { + for (src = (de_ctx->io_ctx).ip_src; src != NULL;) { if (src->family == AF_INET) { - /* - SCLogDebug("To IPv4"); - SCLogDebug("Item has netmask %"PRIu16" negated: %s; IP: %s; " - "signum: %"PRIu16, src->netmask, - (src->negated) ? "yes":"no", - inet_ntoa( *(struct in_addr*)&src->ip[0]), - src->signum); - */ + /* + SCLogDebug("To IPv4"); + SCLogDebug("Item has netmask %"PRIu16" negated: %s; IP: %s; " + "signum: %"PRIu16, src->netmask, + (src->negated) ? "yes":"no", + inet_ntoa( *(struct in_addr*)&src->ip[0]), + src->signum); + */ void *user_data = NULL; if (src->netmask == 32) - (void)SCRadixFindKeyIPV4ExactMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - &user_data); + (void)SCRadixFindKeyIPV4ExactMatch( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, &user_data); else (void)SCRadixFindKeyIPV4Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - src->netmask, &user_data); + (de_ctx->io_ctx).tree_ipv4src, src->netmask, &user_data); if (user_data == NULL) { SCLogDebug("Exact match not found"); /** Not found, look if there's a subnet of this range with * bigger netmask */ - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - &user_data); + (void)SCRadixFindKeyIPV4BestMatch( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, &user_data); if (user_data == NULL) { SCLogDebug("best match not found"); @@ -1157,12 +1140,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, sna); + node = SCRadixAddKeyIPV4( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, - sna, src->netmask); + (de_ctx->io_ctx).tree_ipv4src, sna, src->netmask); if (node == NULL) SCLogError("Error inserting in the " @@ -1172,7 +1154,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) /* Found, copy the sig num table, add this signum and insert */ SigNumArray *sna = NULL; - sna = SigNumArrayCopy((SigNumArray *) user_data); + sna = SigNumArrayCopy((SigNumArray *)user_data); /* Update the sig */ uint8_t tmp = (uint8_t)(1 << (src->signum % 8)); @@ -1185,12 +1167,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, sna); + node = SCRadixAddKeyIPV4( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv4src, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv4src, sna, - src->netmask); + (de_ctx->io_ctx).tree_ipv4src, sna, src->netmask); if (node == NULL) { char tmpstr[64]; @@ -1198,7 +1179,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) SCLogError("Error inserting in the" " src ipv4 radix tree ip %s netmask %" PRIu8, tmpstr, src->netmask); - //SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src); + // SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src); exit(-1); } } @@ -1223,19 +1204,16 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) void *user_data = NULL; if (src->netmask == 128) - (void)SCRadixFindKeyIPV6ExactMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - &user_data); + (void)SCRadixFindKeyIPV6ExactMatch( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, &user_data); else (void)SCRadixFindKeyIPV6Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - src->netmask, &user_data); + (de_ctx->io_ctx).tree_ipv6src, src->netmask, &user_data); if (user_data == NULL) { /* Not found, look if there's a subnet of this range with bigger netmask */ - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - &user_data); + (void)SCRadixFindKeyIPV6BestMatch( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, &user_data); if (user_data == NULL) { /* Not found, insert a new one */ @@ -1252,12 +1230,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, sna); + node = SCRadixAddKeyIPV6( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - sna, src->netmask); + (de_ctx->io_ctx).tree_ipv6src, sna, src->netmask); if (node == NULL) SCLogError("Error inserting in the src " "ipv6 radix tree"); @@ -1276,12 +1253,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[src->signum / 8] |= tmp; if (src->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, sna); + node = SCRadixAddKeyIPV6( + (uint8_t *)&src->ip[0], (de_ctx->io_ctx).tree_ipv6src, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0], - (de_ctx->io_ctx).tree_ipv6src, - sna, src->netmask); + (de_ctx->io_ctx).tree_ipv6src, sna, src->netmask); if (node == NULL) SCLogError("Error inserting in the src " "ipv6 radix tree"); @@ -1308,24 +1284,22 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) SCLogDebug("dsts:"); /* Prepare Dst radix trees */ - for (dst = (de_ctx->io_ctx).ip_dst; dst != NULL; ) { + for (dst = (de_ctx->io_ctx).ip_dst; dst != NULL;) { if (dst->family == AF_INET) { SCLogDebug("To IPv4"); - SCLogDebug("Item has netmask %"PRIu8" negated: %s; IP: %s; signum:" - " %"PRIu32"", dst->netmask, (dst->negated)?"yes":"no", - inet_ntoa(*(struct in_addr*)&dst->ip[0]), dst->signum); + SCLogDebug("Item has netmask %" PRIu8 " negated: %s; IP: %s; signum:" + " %" PRIu32 "", + dst->netmask, (dst->negated) ? "yes" : "no", + inet_ntoa(*(struct in_addr *)&dst->ip[0]), dst->signum); void *user_data = NULL; if (dst->netmask == 32) - (void) SCRadixFindKeyIPV4ExactMatch((uint8_t *) &dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - &user_data); + (void)SCRadixFindKeyIPV4ExactMatch( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, &user_data); else - (void) SCRadixFindKeyIPV4Netblock((uint8_t *) &dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - dst->netmask, - &user_data); + (void)SCRadixFindKeyIPV4Netblock((uint8_t *)&dst->ip[0], + (de_ctx->io_ctx).tree_ipv4dst, dst->netmask, &user_data); if (user_data == NULL) { SCLogDebug("Exact match not found"); @@ -1334,9 +1308,8 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) * Not found, look if there's a subnet of this range * with bigger netmask */ - (void) SCRadixFindKeyIPV4BestMatch((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - &user_data); + (void)SCRadixFindKeyIPV4BestMatch( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, &user_data); if (user_data == NULL) { SCLogDebug("Best match not found"); @@ -1353,12 +1326,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, sna); + node = SCRadixAddKeyIPV4( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - sna, dst->netmask); + (de_ctx->io_ctx).tree_ipv4dst, sna, dst->netmask); if (node == NULL) SCLogError("Error inserting in the dst " @@ -1368,7 +1340,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) /* Found, copy the sig num table, add this signum and insert */ SigNumArray *sna = NULL; - sna = SigNumArrayCopy((SigNumArray *) user_data); + sna = SigNumArrayCopy((SigNumArray *)user_data); /* Update the sig */ uint8_t tmp = (uint8_t)(1 << (dst->signum % 8)); @@ -1380,12 +1352,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 32) - node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, sna); + node = SCRadixAddKeyIPV4( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv4dst, sna); else node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv4dst, - sna, dst->netmask); + (de_ctx->io_ctx).tree_ipv4dst, sna, dst->netmask); if (node == NULL) SCLogError("Error inserting in the dst " @@ -1411,21 +1382,18 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) void *user_data = NULL; if (dst->netmask == 128) - (void) SCRadixFindKeyIPV6ExactMatch((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - &user_data); + (void)SCRadixFindKeyIPV6ExactMatch( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, &user_data); else - (void) SCRadixFindKeyIPV6Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - dst->netmask, &user_data); + (void)SCRadixFindKeyIPV6Netblock((uint8_t *)&dst->ip[0], + (de_ctx->io_ctx).tree_ipv6dst, dst->netmask, &user_data); if (user_data == NULL) { /** Not found, look if there's a subnet of this range with * bigger netmask */ - (void) SCRadixFindKeyIPV6BestMatch((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - &user_data); + (void)SCRadixFindKeyIPV6BestMatch( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, &user_data); if (user_data == NULL) { /* Not found, insert a new one */ @@ -1441,12 +1409,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, sna); + node = SCRadixAddKeyIPV6( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - sna, dst->netmask); + (de_ctx->io_ctx).tree_ipv6dst, sna, dst->netmask); if (node == NULL) SCLogError("Error inserting in the dst " @@ -1466,12 +1433,11 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) sna->array[dst->signum / 8] |= tmp; if (dst->netmask == 128) - node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, sna); + node = SCRadixAddKeyIPV6( + (uint8_t *)&dst->ip[0], (de_ctx->io_ctx).tree_ipv6dst, sna); else node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0], - (de_ctx->io_ctx).tree_ipv6dst, - sna, dst->netmask); + (de_ctx->io_ctx).tree_ipv6dst, sna, dst->netmask); if (node == NULL) SCLogError("Error inserting in the dst " @@ -1519,8 +1485,7 @@ void IPOnlyPrepare(DetectEngineCtx *de_ctx) * \param de_ctx Pointer to the current ip only detection engine contest * \param s Pointer to the current signature */ -void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, - Signature *s) +void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, Signature *s) { if (!(s->type == SIG_TYPE_IPONLY)) return; @@ -1560,7 +1525,7 @@ static int IPOnlyTestSig01(void) FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(de_ctx,"alert tcp any any -> any any (sid:400001; rev:1;)"); + Signature *s = SigInit(de_ctx, "alert tcp any any -> any any (sid:400001; rev:1;)"); FAIL_IF(s == NULL); FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); @@ -1574,13 +1539,13 @@ static int IPOnlyTestSig01(void) * option appending a SigMatch but a port is fixed */ -static int IPOnlyTestSig02 (void) +static int IPOnlyTestSig02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(de_ctx,"alert tcp any any -> any 80 (sid:400001; rev:1;)"); + Signature *s = SigInit(de_ctx, "alert tcp any any -> any 80 (sid:400001; rev:1;)"); FAIL_IF(s == NULL); FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); @@ -1594,11 +1559,11 @@ static int IPOnlyTestSig02 (void) * because it has rule options appending a SigMatch like content, and pcre */ -static int IPOnlyTestSig03 (void) +static int IPOnlyTestSig03(void) { int result = 1; DetectEngineCtx *de_ctx; - Signature *s=NULL; + Signature *s = NULL; de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) @@ -1606,110 +1571,117 @@ static int IPOnlyTestSig03 (void) de_ctx->flags |= DE_QUIET; /* combination of pcre and content */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre and content) \"; content:\"php\"; pcre:\"/require(_once)?/i\"; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre " + "and content) \"; content:\"php\"; pcre:\"/require(_once)?/i\"; " + "classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (content): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* content */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (content) \"; content:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (content) \"; " + "content:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (content): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* uricontent */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (uricontent) \"; uricontent:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (uricontent) \"; " + "uricontent:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (uricontent): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* pcre */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre) \"; pcre:\"/e?idps rule[sz]/i\"; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre) \"; " + "pcre:\"/e?idps rule[sz]/i\"; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (pcre): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* flow */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flow) \"; flow:to_server; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flow) " + "\"; flow:to_server; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (flow): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* dsize */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (dsize) \"; dsize:100; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly " + "(dsize) \"; dsize:100; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (dsize): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* flowbits */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowbits) \"; flowbits:unset; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowbits) " + "\"; flowbits:unset; classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (flowbits): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* flowvar */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowvar) \"; pcre:\"/(?.*)/i\"; flowvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly " + "(flowvar) \"; pcre:\"/(?.*)/i\"; flowvar:var,\"str\"; " + "classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (flowvar): "); - result=0; + result = 0; } SigFree(de_ctx, s); /* pktvar */ - s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pktvar) \"; pcre:\"/(?.*)/i\"; pktvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)"); + s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly " + "(pktvar) \"; pcre:\"/(?.*)/i\"; pktvar:var,\"str\"; " + "classtype:misc-activity; sid:400001; rev:1;)"); if (s == NULL) { goto end; } - if(SignatureIsIPOnly(de_ctx, s)) - { + if (SignatureIsIPOnly(de_ctx, s)) { printf("got a IPOnly signature (pktvar): "); - result=0; + result = 0; } SigFree(de_ctx, s); @@ -1722,7 +1694,7 @@ static int IPOnlyTestSig03 (void) /** * \test */ -static int IPOnlyTestSig04 (void) +static int IPOnlyTestSig04(void) { int result = 1; @@ -1730,27 +1702,27 @@ static int IPOnlyTestSig04 (void) IPOnlyCIDRItem *new; new = IPOnlyCIDRItemNew(); - new->netmask= 10; + new->netmask = 10; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); - new->netmask= 11; + new->netmask = 11; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); - new->netmask= 9; + new->netmask = 9; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); - new->netmask= 10; + new->netmask = 10; head = IPOnlyCIDRItemInsert(head, new); new = IPOnlyCIDRItemNew(); - new->netmask= 10; + new->netmask = 10; head = IPOnlyCIDRItemInsert(head, new); @@ -1804,19 +1776,24 @@ static int IPOnlyTestSig05(void) p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); const char *sigs[numsigs]; - sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; - sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; - sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; - sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; - sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; - sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; + sigs[0] = "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; + sigs[1] = "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; + sigs[2] = "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; " + "sid:3;)"; + sigs[3] = "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; " + "sid:4;)"; + sigs[4] = + "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; + sigs[5] = + "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; + sigs[6] = "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid " + "7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; - uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1}; + uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7 }; + uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1 }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -1841,19 +1818,24 @@ static int IPOnlyTestSig06(void) p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "80.58.0.33", "195.235.113.3"); const char *sigs[numsigs]; - sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; - sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; - sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; - sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; - sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; - sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; + sigs[0] = "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; + sigs[1] = "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; + sigs[2] = "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; " + "sid:3;)"; + sigs[3] = "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; " + "sid:4;)"; + sigs[4] = + "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; + sigs[5] = + "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; + sigs[6] = "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid " + "7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; - uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0}; + uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7 }; + uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0 }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -1917,22 +1899,34 @@ static int IPOnlyTestSig08(void) Packet *p[1]; - p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"192.168.1.1","192.168.1.5"); + p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "192.168.1.1", "192.168.1.5"); const char *sigs[numsigs]; - sigs[0]= "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; - sigs[2]= "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; - sigs[3]= "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> [192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; - sigs[4]= "alert tcp any any -> !192.168.1.5 any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; - sigs[5]= "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; - sigs[6]= "alert tcp [78.129.202.0/24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ + sigs[0] = "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid " + "1)\"; sid:1;)"; + sigs[1] = "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any " + "(msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; + sigs[2] = "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing " + "src/dst ip (sid 3)\"; sid:3;)"; + sigs[3] = "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> " + "[192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; + sigs[4] = "alert tcp any any -> !192.168.1.5 any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; + sigs[5] = "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any " + "(msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; + sigs[6] = + "alert tcp " + "[78.129.202.0/" + "24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33," + "78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141." + "114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16." + "7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian " + "Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; - uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0}; + uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7 }; + uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0 }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -1954,22 +1948,32 @@ static int IPOnlyTestSig09(void) Packet *p[1]; - p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562"); + p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, + "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562"); const char *sigs[numsigs]; - sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; - sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; - sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:0/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; - sigs[4]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; - sigs[5]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; - sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; + sigs[0] = "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src " + "ip (sid 1)\"; sid:1;)"; + sigs[1] = "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst " + "ip (sid 2)\"; sid:2;)"; + sigs[2] = "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> " + "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; " + "sid:3;)"; + sigs[3] = "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> " + "3FFE:FFFF:7654:FEDA:1245:BA98:3210:0/96 any (msg:\"Testing src/dst ip (sid 4)\"; " + "sid:4;)"; + sigs[4] = "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip " + "(sid 5)\"; sid:5;)"; + sigs[5] = "alert tcp any any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip " + "(sid 6)\"; sid:6;)"; + sigs[6] = "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any " + "(msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; - uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1}; + uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7 }; + uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1 }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -1991,22 +1995,32 @@ static int IPOnlyTestSig10(void) Packet *p[1]; - p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565"); + p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, + "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565"); const char *sigs[numsigs]; - sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; - sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; - sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> !3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; - sigs[4]= "alert tcp !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; - sigs[5]= "alert tcp any any -> !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; - sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDB:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; + sigs[0] = "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src " + "ip (sid 1)\"; sid:1;)"; + sigs[1] = "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst " + "ip (sid 2)\"; sid:2;)"; + sigs[2] = "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> " + "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; " + "sid:3;)"; + sigs[3] = "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> " + "!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562/96 any (msg:\"Testing src/dst ip (sid " + "4)\"; sid:4;)"; + sigs[4] = "alert tcp !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip " + "(sid 5)\"; sid:5;)"; + sigs[5] = "alert tcp any any -> !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip " + "(sid 6)\"; sid:6;)"; + sigs[6] = "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDB:0:0:0:0/64 any " + "(msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)"; /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; - uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0}; + uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7 }; + uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0 }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -2071,23 +2085,51 @@ static int IPOnlyTestSig12(void) Packet *p[2]; - p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"3FBE:FFFF:7654:FEDA:1245:BA98:3210:4562","3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565"); - p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"195.85.1.1","80.198.1.5"); + p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, + "3FBE:FFFF:7654:FEDA:1245:BA98:3210:4562", "3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565"); + p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "195.85.1.1", "80.198.1.5"); const char *sigs[numsigs]; - sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert tcp [192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192.168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; - sigs[2]= "alert tcp [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)"; - sigs[3]= "alert tcp [3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)"; - sigs[4]= "alert tcp any any -> [!3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565,!80.198.1.5] any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; - sigs[5]= "alert tcp any any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)"; - sigs[6]= "alert tcp [78.129.202.0/24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ + sigs[0] = "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> " + "3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; " + "sid:1;)"; + sigs[1] = "alert tcp " + "[192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192." + "168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any " + "(msg:\"Testing src/dst ip (sid 2)\"; sid:2;)"; + sigs[2] = + "alert tcp " + "[3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] " + "any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing " + "src/dst ip (sid 3)\"; sid:3;)"; + sigs[3] = + "alert tcp " + "[3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/" + "64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> " + "[3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/" + "24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; " + "sid:4;)"; + sigs[4] = "alert tcp any any -> [!3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565,!80.198.1.5] any " + "(msg:\"Testing src/dst ip (sid 5)\"; sid:5;)"; + sigs[5] = "alert tcp any any -> " + "[3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/" + "64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst " + "ip (sid 6)\"; sid:6;)"; + sigs[6] = + "alert tcp " + "[78.129.202.0/" + "24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103," + "78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105," + "78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145." + "144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> " + "[3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian " + "Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */ /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; - uint32_t results[2][7] = {{ 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}}; + uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7 }; + uint32_t results[2][7] = { { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 } }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -2100,9 +2142,8 @@ static int IPOnlyTestSig13(void) FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " - "flowbits:set,myflow1; sid:1; rev:1;)"); + Signature *s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " + "flowbits:set,myflow1; sid:1; rev:1;)"); FAIL_IF(s == NULL); FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); @@ -2117,9 +2158,8 @@ static int IPOnlyTestSig14(void) FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " - "flowbits:set,myflow1; flowbits:isset,myflow2; sid:1; rev:1;)"); + Signature *s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " + "flowbits:set,myflow1; flowbits:isset,myflow2; sid:1; rev:1;)"); FAIL_IF(s == NULL); FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 1); @@ -2152,26 +2192,27 @@ static int IPOnlyTestSig15(void) p[0]->flowflags |= FLOW_PKT_TOSERVER; const char *sigs[numsigs]; - sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; " - "flowbits:set,one; sid:1;)"; - sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; " - "flowbits:set,two; sid:2;)"; - sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; " - "flowbits:set,three; sid:3;)"; - sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; " - "flowbits:set,four; sid:4;)"; - sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; " - "flowbits:set,five; sid:5;)"; - sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; " - "flowbits:set,six; sid:6;)"; - sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; " - "flowbits:set,seven; content:\"Hi all\"; sid:7;)"; + sigs[0] = "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; " + "flowbits:set,one; sid:1;)"; + sigs[1] = "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; " + "flowbits:set,two; sid:2;)"; + sigs[2] = "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; " + "flowbits:set,three; sid:3;)"; + sigs[3] = "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; " + "flowbits:set,four; sid:4;)"; + sigs[4] = "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; " + "flowbits:set,five; sid:5;)"; + sigs[5] = "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; " + "flowbits:set,six; sid:6;)"; + sigs[6] = "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid " + "7)\"; " + "flowbits:set,seven; content:\"Hi all\"; sid:7;)"; /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7}; - uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1}; + uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7 }; + uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1 }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -2196,14 +2237,14 @@ static int IPOnlyTestSig16(void) p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "100.100.0.0", "50.0.0.0"); const char *sigs[numsigs]; - sigs[0]= "alert tcp !100.100.0.1 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert tcp any any -> !50.0.0.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; + sigs[0] = "alert tcp !100.100.0.1 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; + sigs[1] = "alert tcp any any -> !50.0.0.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; /* Sid numbers (we could extract them from the sig) */ - uint32_t sid[2] = { 1, 2}; - uint32_t results[2] = { 1, 1}; + uint32_t sid[2] = { 1, 2 }; + uint32_t results[2] = { 1, 1 }; - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -2227,13 +2268,13 @@ static int IPOnlyTestSig17(void) p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_ICMP, "100.100.0.0", "50.0.0.0"); const char *sigs[numsigs]; - sigs[0]= "alert ip 100.100.0.0 80 -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; - sigs[1]= "alert ip any any -> 50.0.0.0 123 (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; + sigs[0] = "alert ip 100.100.0.0 80 -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)"; + sigs[1] = "alert ip any any -> 50.0.0.0 123 (msg:\"Testing dst ip (sid 2)\"; sid:2;)"; - uint32_t sid[2] = { 1, 2}; - uint32_t results[2] = { 0, 0}; /* neither should match */ + uint32_t sid[2] = { 1, 2 }; + uint32_t results[2] = { 0, 0 }; /* neither should match */ - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -2261,16 +2302,26 @@ static int IPOnlyTestSig18(void) const char *sigs[numsigs]; // really many IP addresses - sigs[0]= "alert ip 1.2.3.4-219.6.7.8 any -> any any (sid:1;)"; - sigs[1]= "alert ip 51.2.3.4-253.1.2.3 any -> any any (sid:2;)"; - sigs[2]= "alert ip 0.0.0.0-50.0.0.2 any -> any any (sid:3;)"; - sigs[3]= "alert ip 50.0.0.0-255.255.255.255 any -> any any (sid:4;)"; - - uint32_t sid[4] = { 1, 2, 3, 4, }; - uint32_t results[4][4] = { - { 1, 0, 1, 0, }, { 0, 1, 0, 1}, { 0, 0, 1, 0 }, { 0, 0, 0, 1}}; - - result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs); + sigs[0] = "alert ip 1.2.3.4-219.6.7.8 any -> any any (sid:1;)"; + sigs[1] = "alert ip 51.2.3.4-253.1.2.3 any -> any any (sid:2;)"; + sigs[2] = "alert ip 0.0.0.0-50.0.0.2 any -> any any (sid:3;)"; + sigs[3] = "alert ip 50.0.0.0-255.255.255.255 any -> any any (sid:4;)"; + + uint32_t sid[4] = { + 1, + 2, + 3, + 4, + }; + uint32_t results[4][4] = { { + 1, + 0, + 1, + 0, + }, + { 0, 1, 0, 1 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; + + result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *)results, numsigs); UTHFreePackets(p, numpkts); @@ -2446,4 +2497,3 @@ void IPOnlyRegisterTests(void) return; } - diff --git a/src/detect-engine-iponly.h b/src/detect-engine-iponly.h index 7fa9e223e743..dbc372587fbb 100644 --- a/src/detect-engine-iponly.h +++ b/src/detect-engine-iponly.h @@ -37,4 +37,3 @@ void IPOnlyAddSignature(DetectEngineCtx *, DetectEngineIPOnlyCtx *, Signature *) void IPOnlyRegisterTests(void); #endif /* __DETECT_ENGINE_IPONLY_H__ */ - diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c index 40919568503a..ba311eaeac36 100644 --- a/src/detect-engine-loader.c +++ b/src/detect-engine-loader.c @@ -32,7 +32,7 @@ #include "threadvars.h" #include "tm-threads.h" #include "queue.h" -#include "util-signal.h" +#include "util/signal.h" #include "detect-engine-loader.h" #include "detect-engine-build.h" @@ -40,9 +40,9 @@ #include "detect-engine-mpm.h" #include "detect-engine-sigorder.h" -#include "util-detect.h" -#include "util-threshold-config.h" -#include "util-path.h" +#include "util/detect.h" +#include "util/threshold-config.h" +#include "util/path.h" #ifdef HAVE_GLOB_H #include @@ -74,8 +74,7 @@ char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, const char *sig_f * a --set. */ ConfNode *default_rule_path = ConfGetNode("default-rule-path"); if ((!default_rule_path || !default_rule_path->final) && strlen(de_ctx->config_prefix) > 0) { - snprintf(varname, sizeof(varname), "%s.default-rule-path", - de_ctx->config_prefix); + snprintf(varname, sizeof(varname), "%s.default-rule-path", de_ctx->config_prefix); default_rule_path = ConfGetNode(varname); } if (default_rule_path) { @@ -109,8 +108,7 @@ char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, const char *sig_f * \param badsigs_tot Will store number of invalid signatures in the file * \retval 0 on success, -1 on error */ -static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, - int *goodsigs, int *badsigs) +static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *goodsigs, int *badsigs) { Signature *sig = NULL; int good = 0, bad = 0; @@ -129,16 +127,18 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, return -1; } - while(fgets(line + offset, (int)sizeof(line) - offset, fp) != NULL) { + while (fgets(line + offset, (int)sizeof(line) - offset, fp) != NULL) { lineno++; size_t len = strlen(line); /* ignore comments and empty lines */ - if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') + if (line[0] == '\n' || line[0] == '\r' || line[0] == ' ' || line[0] == '#' || + line[0] == '\t') continue; /* Check for multiline rules. */ - while (len > 0 && isspace((unsigned char)line[--len])); + while (len > 0 && isspace((unsigned char)line[--len])) + ; if (line[len] == '\\') { multiline++; offset = len; @@ -173,7 +173,7 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, EngineAnalysisRules(de_ctx, sig, line); } } - SCLogDebug("signature %"PRIu32" loaded", sig->id); + SCLogDebug("signature %" PRIu32 " loaded", sig->id); good++; } else { if (!de_ctx->sigerror_silent) { @@ -181,7 +181,8 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, "file %s at line %" PRId32 "", line, sig_file, lineno - multiline); - if (!SigStringAppend(&de_ctx->sig_stat, sig_file, line, de_ctx->sigerror, (lineno - multiline))) { + if (!SigStringAppend(&de_ctx->sig_stat, sig_file, line, de_ctx->sigerror, + (lineno - multiline))) { SCLogError("Error adding sig \"%s\" from " "file %s at line %" PRId32 "", line, sig_file, lineno - multiline); @@ -212,8 +213,8 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, * \param sig_file Filename (or pattern) holding signatures * \retval -1 on error */ -static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, - SigFileLoaderStat *st, int *good_sigs, int *bad_sigs) +static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, SigFileLoaderStat *st, + int *good_sigs, int *bad_sigs) { int r = 0; @@ -241,9 +242,9 @@ static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, if (strcmp("/dev/null", fname) == 0) continue; #else - char *fname = pattern; - if (strcmp("/dev/null", fname) == 0) - return 0; + char *fname = pattern; + if (strcmp("/dev/null", fname) == 0) + return 0; #endif if (strlen(de_ctx->config_prefix) > 0) { SCLogConfig("tenant id %d: Loading rule file: %s", de_ctx->tenant_id, fname); @@ -288,8 +289,7 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, bool sig_file_exc int bad_sigs = 0; if (strlen(de_ctx->config_prefix) > 0) { - snprintf(varname, sizeof(varname), "%s.rule-files", - de_ctx->config_prefix); + snprintf(varname, sizeof(varname), "%s.rule-files", de_ctx->config_prefix); } if (RunmodeGetCurrent() == RUNMODE_ENGINE_ANALYSIS) { @@ -303,9 +303,8 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, bool sig_file_exc if (!ConfNodeIsSequence(rule_files)) { SCLogWarning("Invalid rule-files configuration section: " "expected a list of filenames."); - } - else { - TAILQ_FOREACH(file, &rule_files->head, next) { + } else { + TAILQ_FOREACH (file, &rule_files->head, next) { sfile = DetectLoadCompleteSigPath(de_ctx, file->val); good_sigs = bad_sigs = 0; ret = ProcessSigFiles(de_ctx, sfile, sig_stat, &good_sigs, &bad_sigs); @@ -382,7 +381,7 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, bool sig_file_exc ret = 0; - end: +end: gettimeofday(&de_ctx->last_reload, NULL); if (RunmodeGetCurrent() == RUNMODE_ENGINE_ANALYSIS) { CleanupEngineAnalysis(de_ctx); @@ -501,7 +500,7 @@ static void TmThreadWakeupDetectLoaderThreads(void) for (int i = 0; i < TVT_MAX; i++) { ThreadVars *tv = tv_root[i]; while (tv != NULL) { - if (strncmp(tv->name,"DL#",3) == 0) { + if (strncmp(tv->name, "DL#", 3) == 0) { BUG_ON(tv->ctrl_cond == NULL); pthread_cond_broadcast(tv->ctrl_cond); } @@ -520,7 +519,7 @@ void TmThreadContinueDetectLoaderThreads(void) for (int i = 0; i < TVT_MAX; i++) { ThreadVars *tv = tv_root[i]; while (tv != NULL) { - if (strncmp(tv->name,"DL#",3) == 0) + if (strncmp(tv->name, "DL#", 3) == 0) TmThreadContinue(tv); tv = tv->next; @@ -556,7 +555,6 @@ static TmEcode DetectLoaderThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } - static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) { DetectLoaderThreadData *ftd = (DetectLoaderThreadData *)thread_data; @@ -564,8 +562,7 @@ static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) TmThreadsSetFlag(th_v, THV_INIT_DONE | THV_RUNNING); SCLogDebug("loader thread started"); - while (1) - { + while (1) { if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { TmThreadsSetFlag(th_v, THV_PAUSED); TmThreadTestThreadUnPaused(th_v); @@ -578,7 +575,7 @@ static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) SCMutexLock(&loader->m); DetectLoaderTask *task = NULL, *tmptask = NULL; - TAILQ_FOREACH_SAFE(task, &loader->task_list, next, tmptask) { + TAILQ_FOREACH_SAFE (task, &loader->task_list, next, tmptask) { int r = task->Func(task->ctx, ftd->instance); loader->result |= r; TAILQ_REMOVE(&loader->task_list, task, next); @@ -612,7 +609,7 @@ void DetectLoaderThreadSpawn(void) { for (int i = 0; i < num_loaders; i++) { char name[TM_THREAD_NAME_MAX]; - snprintf(name, sizeof(name), "%s#%02d", thread_name_detect_loader, i+1); + snprintf(name, sizeof(name), "%s#%02d", thread_name_detect_loader, i + 1); ThreadVars *tv_loader = TmThreadCreateCmdThreadByName(name, "DetectLoader", 1); if (tv_loader == NULL) { @@ -624,7 +621,7 @@ void DetectLoaderThreadSpawn(void) } } -void TmModuleDetectLoaderRegister (void) +void TmModuleDetectLoaderRegister(void) { tmm_modules[TMM_DETECTLOADER].name = "DetectLoader"; tmm_modules[TMM_DETECTLOADER].ThreadInit = DetectLoaderThreadInit; diff --git a/src/detect-engine-loader.h b/src/detect-engine-loader.h index 7ffb8c8648a0..806a25555a04 100644 --- a/src/detect-engine-loader.h +++ b/src/detect-engine-loader.h @@ -43,7 +43,7 @@ typedef struct DetectLoaderTask_ { typedef struct DetectLoaderControl_ { int id; - int result; /* 0 for ok, error otherwise */ + int result; /* 0 for ok, error otherwise */ SCMutex m; TAILQ_HEAD(, DetectLoaderTask_) task_list; } DetectLoaderControl; @@ -54,6 +54,6 @@ void DetectLoadersInit(void); void TmThreadContinueDetectLoaderThreads(void); void DetectLoaderThreadSpawn(void); -void TmModuleDetectLoaderRegister (void); +void TmModuleDetectLoaderRegister(void); #endif /* __DETECT_ENGINE_LOADER_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 849930a7a9cf..10880a35619c 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -37,9 +37,9 @@ #include "detect-engine-iponly.h" #include "detect-parse.h" #include "detect-engine-prefilter.h" -#include "util-mpm.h" -#include "util-memcmp.h" -#include "util-memcpy.h" +#include "util/mpm/mpm.h" +#include "util/memcmp.h" +#include "util/memcpy.h" #include "conf.h" #include "detect-fast-pattern.h" @@ -56,21 +56,15 @@ #include "stream.h" -#include "util-misc.h" -#include "util-enum.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-validate.h" -#include "util-hash-string.h" - -const char *builtin_mpms[] = { - "toserver TCP packet", - "toclient TCP packet", - "toserver TCP stream", - "toclient TCP stream", - "toserver UDP packet", - "toclient UDP packet", - "other IP packet", +#include "util/misc.h" +#include "util/enum.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/validate.h" +#include "util/hash-string.h" + +const char *builtin_mpms[] = { "toserver TCP packet", "toclient TCP packet", "toserver TCP stream", + "toclient TCP stream", "toserver UDP packet", "toclient UDP packet", "other IP packet", NULL }; @@ -90,8 +84,8 @@ void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress) { - SCLogDebug("registering %s/%d/%d/%p/%p/%u/%d", name, direction, priority, - PrefilterRegister, GetData, alproto, tx_min_progress); + SCLogDebug("registering %s/%d/%d/%p/%p/%u/%d", name, direction, priority, PrefilterRegister, + GetData, alproto, tx_min_progress); BUG_ON(tx_min_progress >= 48); @@ -140,8 +134,7 @@ void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, } /** \brief copy a mpm engine from parent_id, add in transforms */ -void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, - const int id, const int parent_id, +void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id, DetectEngineTransforms *transforms) { SCLogDebug("registering %d/%d", id, parent_id); @@ -175,11 +168,11 @@ void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, char xforms[1024] = ""; for (int i = 0; i < transforms->cnt; i++) { char ttstr[64]; - (void)snprintf(ttstr,sizeof(ttstr), "%s,", + (void)snprintf(ttstr, sizeof(ttstr), "%s,", sigmatch_table[transforms->transforms[i].transform].name); strlcat(xforms, ttstr, sizeof(xforms)); } - xforms[strlen(xforms)-1] = '\0'; + xforms[strlen(xforms) - 1] = '\0'; size_t space = sizeof(am->pname) - strlen(am->name) - 3; char toprint[space + 1]; @@ -187,20 +180,18 @@ void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, if (space < strlen(xforms)) { ShortenString(xforms, toprint, space, '~'); } else { - strlcpy(toprint, xforms,sizeof(toprint)); + strlcpy(toprint, xforms, sizeof(toprint)); } - (void)snprintf(am->pname, sizeof(am->pname), "%s#%d (%s)", - am->name, id, toprint); + (void)snprintf(am->pname, sizeof(am->pname), "%s#%d (%s)", am->name, id, toprint); } else { - (void)snprintf(am->pname, sizeof(am->pname), "%s#%d", - am->name, id); + (void)snprintf(am->pname, sizeof(am->pname), "%s#%d", am->name, id); } am->id = de_ctx->app_mpms_list_cnt++; DetectEngineRegisterFastPatternForId(de_ctx, am->sm_list, am->priority); t->next = am; SCLogDebug("copied mpm registration for %s id %u " - "with parent %u and GetData %p", + "with parent %u and GetData %p", t->name, id, parent_id, am->app_v2.GetData); t = am; } @@ -250,8 +241,7 @@ void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) list = list->next; } de_ctx->app_mpms_list_cnt = g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_APP]; - SCLogDebug("mpm: de_ctx app_mpms_list %p %u", - de_ctx->app_mpms_list, de_ctx->app_mpms_list_cnt); + SCLogDebug("mpm: de_ctx app_mpms_list %p %u", de_ctx->app_mpms_list, de_ctx->app_mpms_list_cnt); } /** @@ -265,8 +255,7 @@ int DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) while (am != NULL) { int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0; - if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) - { + if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir); if (mpm_ctx != NULL) { if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { @@ -518,8 +507,7 @@ void DetectPktMpmRegister(const char *name, int priority, const DetectBufferMpmRegistry *mpm_reg, int list_id), InspectionBufferGetPktDataPtr GetData) { - SCLogDebug("registering %s/%d/%p/%p", name, priority, - PrefilterRegister, GetData); + SCLogDebug("registering %s/%d/%p/%p", name, priority, PrefilterRegister, GetData); if (PrefilterRegister == PrefilterGenericMpmPktRegister && GetData == NULL) { // must register GetData with PrefilterGenericMpmRegister @@ -562,8 +550,7 @@ void DetectPktMpmRegister(const char *name, int priority, } /** \brief copy a mpm engine from parent_id, add in transforms */ -void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx, - const int id, const int parent_id, +void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id, DetectEngineTransforms *transforms) { SCLogDebug("registering %d/%d", id, parent_id); @@ -592,7 +579,7 @@ void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx, DetectEngineRegisterFastPatternForId(de_ctx, am->sm_list, am->priority); t->next = am; SCLogDebug("copied mpm registration for %s id %u " - "with parent %u and GetData %p", + "with parent %u and GetData %p", t->name, id, parent_id, am->pkt_v1.GetData); t = am; } @@ -644,8 +631,7 @@ void DetectMpmInitializePktMpms(DetectEngineCtx *de_ctx) list = list->next; } de_ctx->pkt_mpms_list_cnt = g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_PKT]; - SCLogDebug("mpm: de_ctx pkt_mpms_list %p %u", - de_ctx->pkt_mpms_list, de_ctx->pkt_mpms_list_cnt); + SCLogDebug("mpm: de_ctx pkt_mpms_list %p %u", de_ctx->pkt_mpms_list, de_ctx->pkt_mpms_list_cnt); } /** @@ -659,8 +645,7 @@ int DetectMpmPreparePktMpms(DetectEngineCtx *de_ctx) const DetectBufferMpmRegistry *am = de_ctx->pkt_mpms_list; while (am != NULL) { SCLogDebug("%s", am->name); - if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) - { + if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, 0); if (mpm_ctx != NULL) { if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { @@ -717,29 +702,34 @@ int DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx) MpmCtx *mpm_ctx = NULL; if (de_ctx->sgh_mpm_context_proto_tcp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); + mpm_ctx = + MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); + mpm_ctx = + MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } } if (de_ctx->sgh_mpm_context_proto_udp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); + mpm_ctx = + MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); + mpm_ctx = + MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } } if (de_ctx->sgh_mpm_context_proto_other_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); + mpm_ctx = MpmFactoryGetMpmCtxForProfile( + de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); } @@ -781,8 +771,7 @@ int SignatureHasPacketContent(const Signature *s) } if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) || - (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) - { + (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) { SCLogDebug("no mpm"); SCReturnInt(0); } @@ -817,8 +806,7 @@ int SignatureHasStreamContent(const Signature *s) } if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) || - (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) - { + (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) { SCLogDebug("no mpm"); SCReturnInt(0); } @@ -830,7 +818,6 @@ int SignatureHasStreamContent(const Signature *s) SCReturnInt(1); } - /** * \brief Function to return the multi pattern matcher algorithm to be * used by the engine, based on the mpm-algo setting in yaml @@ -880,29 +867,29 @@ uint8_t PatternMatchDefaultMatcher(void) mpm_algo); } - done: +done: return mpm_algo_val; } void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher) { - SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); + SCLogDebug("mpm_ctx %p, mpm_matcher %" PRIu16 "", mpm_ctx, mpm_matcher); mpm_table[mpm_matcher].DestroyCtx(mpm_ctx); } void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) { - SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16" defunct", mpm_thread_ctx, mpm_matcher); - //mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx); + SCLogDebug("mpm_thread_ctx %p, mpm_matcher %" PRIu16 " defunct", mpm_thread_ctx, mpm_matcher); + // mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx); } void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) { - SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher); + SCLogDebug("mpm_thread_ctx %p, mpm_matcher %" PRIu16 "", mpm_thread_ctx, mpm_matcher); MpmDestroyThreadCtx(mpm_thread_ctx, mpm_matcher); } void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) { - SCLogDebug("mpm_thread_ctx %p, type %"PRIu16, mpm_thread_ctx, mpm_matcher); + SCLogDebug("mpm_thread_ctx %p, type %" PRIu16, mpm_thread_ctx, mpm_matcher); MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher); } @@ -922,7 +909,7 @@ void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matche uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) { uint8_t a[256]; - memset(&a, 0 ,sizeof(a)); + memset(&a, 0, sizeof(a)); uint32_t s = 0; uint16_t u = 0; @@ -944,10 +931,8 @@ uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) return s; } -static void PopulateMpmHelperAddPattern(MpmCtx *mpm_ctx, - const DetectContentData *cd, - const Signature *s, uint8_t flags, - int chop) +static void PopulateMpmHelperAddPattern( + MpmCtx *mpm_ctx, const DetectContentData *cd, const Signature *s, uint8_t flags, int chop) { uint16_t pat_offset = cd->offset; uint16_t pat_depth = cd->depth; @@ -970,34 +955,26 @@ static void PopulateMpmHelperAddPattern(MpmCtx *mpm_ctx, if (cd->flags & DETECT_CONTENT_NOCASE) { if (chop) { - MpmAddPatternCI(mpm_ctx, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - pat_offset, pat_depth, - cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + MpmAddPatternCI(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, pat_offset, + pat_depth, cd->id, s->num, flags | MPM_PATTERN_CTX_OWNS_ID); } else { - MpmAddPatternCI(mpm_ctx, - cd->content, cd->content_len, - pat_offset, pat_depth, - cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + MpmAddPatternCI(mpm_ctx, cd->content, cd->content_len, pat_offset, pat_depth, cd->id, + s->num, flags | MPM_PATTERN_CTX_OWNS_ID); } } else { if (chop) { - MpmAddPatternCS(mpm_ctx, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - pat_offset, pat_depth, - cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + MpmAddPatternCS(mpm_ctx, cd->content + cd->fp_chop_offset, cd->fp_chop_len, pat_offset, + pat_depth, cd->id, s->num, flags | MPM_PATTERN_CTX_OWNS_ID); } else { - MpmAddPatternCS(mpm_ctx, - cd->content, cd->content_len, - pat_offset, pat_depth, - cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + MpmAddPatternCS(mpm_ctx, cd->content, cd->content_len, pat_offset, pat_depth, cd->id, + s->num, flags | MPM_PATTERN_CTX_OWNS_ID); } } return; } -#define SGH_PROTO(sgh, p) ((sgh)->init->protos[(p)] == 1) +#define SGH_PROTO(sgh, p) ((sgh)->init->protos[(p)] == 1) #define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER) #define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT) @@ -1008,18 +985,13 @@ static void SetMpm(Signature *s, SigMatch *mpm_sm, const int mpm_sm_list) DetectContentData *cd = (DetectContentData *)mpm_sm->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE) && - cd->content_len == cd->fp_chop_len) - { + if (DETECT_CONTENT_IS_SINGLE(cd) && !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE) && cd->content_len == cd->fp_chop_len) { cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } } else { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE)) - { + if (DETECT_CONTENT_IS_SINGLE(cd) && !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE)) { cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; } } @@ -1161,10 +1133,7 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s) const SCFPSupportSMList *tmp = de_ctx->fp_support_smlist_list; while (tmp != NULL) { - for (priority = tmp->priority; - tmp != NULL && priority == tmp->priority; - tmp = tmp->next) - { + for (priority = tmp->priority; tmp != NULL && priority == tmp->priority; tmp = tmp->next) { SCLogDebug("tmp->list_id %d tmp->priority %d", tmp->list_id, tmp->priority); if (tmp->list_id >= nlists) continue; @@ -1297,8 +1266,7 @@ static uint32_t MpmStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen * \retval 1 If the 2 MpmStores sent as args match. * \retval 0 If the 2 MpmStores sent as args do not match. */ -static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) +static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { const MpmStore *ms1 = (MpmStore *)data1; const MpmStore *ms2 = (MpmStore *)data2; @@ -1318,9 +1286,7 @@ static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2, if (ms1->sm_list != ms2->sm_list) return 0; - if (SCMemcmp(ms1->sid_array, ms2->sid_array, - ms1->sid_array_size) != 0) - { + if (SCMemcmp(ms1->sid_array, ms2->sid_array, ms1->sid_array_size) != 0) { return 0; } @@ -1331,8 +1297,7 @@ static void MpmStoreFreeFunc(void *ptr) { MpmStore *ms = ptr; if (ms != NULL) { - if (ms->mpm_ctx != NULL && !(ms->mpm_ctx->flags & MPMCTX_FLAGS_GLOBAL)) - { + if (ms->mpm_ctx != NULL && !(ms->mpm_ctx->flags & MPMCTX_FLAGS_GLOBAL)) { SCLogDebug("destroying mpm_ctx %p", ms->mpm_ctx); mpm_table[ms->mpm_ctx->mpm_type].DestroyCtx(ms->mpm_ctx); SCFree(ms->mpm_ctx); @@ -1355,10 +1320,8 @@ static void MpmStoreFreeFunc(void *ptr) */ int MpmStoreInit(DetectEngineCtx *de_ctx) { - de_ctx->mpm_hash_table = HashListTableInit(4096, - MpmStoreHashFunc, - MpmStoreCompareFunc, - MpmStoreFreeFunc); + de_ctx->mpm_hash_table = + HashListTableInit(4096, MpmStoreHashFunc, MpmStoreCompareFunc, MpmStoreFreeFunc); if (de_ctx->mpm_hash_table == NULL) goto error; @@ -1393,8 +1356,7 @@ static int MpmStoreAdd(DetectEngineCtx *de_ctx, MpmStore *s) */ static MpmStore *MpmStoreLookup(DetectEngineCtx *de_ctx, MpmStore *s) { - MpmStore *rs = HashListTableLookup(de_ctx->mpm_hash_table, - (void *)s, 0); + MpmStore *rs = HashListTableLookup(de_ctx->mpm_hash_table, (void *)s, 0); return rs; } @@ -1403,8 +1365,7 @@ static const DetectBufferMpmRegistry *GetByMpmStore( { const DetectBufferMpmRegistry *am = de_ctx->app_mpms_list; while (am != NULL) { - if (ms->sm_list == am->sm_list && - ms->direction == am->direction) { + if (ms->sm_list == am->sm_list && ms->direction == am->direction) { return am; } am = am->next; @@ -1423,21 +1384,19 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) { HashListTableBucket *htb = NULL; - uint32_t stats[MPMB_MAX] = {0}; + uint32_t stats[MPMB_MAX] = { 0 }; int app_mpms_cnt = de_ctx->buffer_type_id; - uint32_t appstats[app_mpms_cnt + 1]; // +1 to silence scan-build + uint32_t appstats[app_mpms_cnt + 1]; // +1 to silence scan-build memset(&appstats, 0x00, sizeof(appstats)); int pkt_mpms_cnt = de_ctx->buffer_type_id; - uint32_t pktstats[pkt_mpms_cnt + 1]; // +1 to silence scan-build + uint32_t pktstats[pkt_mpms_cnt + 1]; // +1 to silence scan-build memset(&pktstats, 0x00, sizeof(pktstats)); int frame_mpms_cnt = de_ctx->buffer_type_id; uint32_t framestats[frame_mpms_cnt + 1]; // +1 to silence scan-build memset(&framestats, 0x00, sizeof(framestats)); - for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table); - htb != NULL; - htb = HashListTableGetListNext(htb)) - { + for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table); htb != NULL; + htb = HashListTableGetListNext(htb)) { const MpmStore *ms = (MpmStore *)HashListTableGetListData(htb); if (ms == NULL || ms->mpm_ctx == NULL) { continue; @@ -1449,10 +1408,8 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) if (am != NULL) { switch (am->type) { case DETECT_BUFFER_MPM_TYPE_PKT: - SCLogDebug("%s: %u patterns. Min %u, Max %u. Ctx %p", - am->name, - ms->mpm_ctx->pattern_cnt, - ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen, + SCLogDebug("%s: %u patterns. Min %u, Max %u. Ctx %p", am->name, + ms->mpm_ctx->pattern_cnt, ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen, ms->mpm_ctx); pktstats[am->sm_list]++; break; @@ -1485,7 +1442,8 @@ void MpmStoreReportStats(const DetectEngineCtx *de_ctx) while (am != NULL) { if (appstats[am->sm_list] > 0) { const char *name = am->name; - const char *direction = am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; + const char *direction = + am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; SCLogPerf("AppLayer MPM \"%s %s (%s)\": %u", direction, name, AppProtoToString(am->app_v2.alproto), appstats[am->sm_list]); } @@ -1548,7 +1506,7 @@ static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) case MPMB_UDP_TC: case MPMB_TCP_STREAM_TC: case MPMB_TCP_PKT_TC: - case MPMB_OTHERIP: /**< use 0 for other */ + case MPMB_OTHERIP: /**< use 0 for other */ dir = 0; break; } @@ -1586,16 +1544,14 @@ static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) * match. So in this case there is no point of adding it at all. * The non-mpm list entry for the sig will make sure the sig is * inspected. */ - if ((cd->flags & DETECT_CONTENT_NEGATED) && - !(DETECT_CONTENT_MPM_IS_CONCLUSIVE(cd))) - { + if ((cd->flags & DETECT_CONTENT_NEGATED) && !(DETECT_CONTENT_MPM_IS_CONCLUSIVE(cd))) { skip = 1; SCLogDebug("not adding negated mpm as it's not 'single'"); } if (!skip) { - PopulateMpmHelperAddPattern(ms->mpm_ctx, - cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + PopulateMpmHelperAddPattern( + ms->mpm_ctx, cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); } } } @@ -1612,12 +1568,11 @@ static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) } } - /** \brief Get MpmStore for a built-in buffer type * */ -MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - enum MpmBuiltinBuffers buf) +MpmStore *MpmStorePrepareBuffer( + DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf) { const Signature *s = NULL; uint32_t sig; @@ -1649,7 +1604,7 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, break; } - switch(buf) { + switch (buf) { case MPMB_TCP_PKT_TS: case MPMB_TCP_STREAM_TS: case MPMB_UDP_TS: @@ -1663,7 +1618,7 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, break; case MPMB_OTHERIP: - direction = (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER); + direction = (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER); break; case MPMB_MAX: @@ -1689,16 +1644,14 @@ MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, switch (buf) { case MPMB_TCP_PKT_TS: case MPMB_TCP_PKT_TC: - if (SignatureHasPacketContent(s) == 1) - { + if (SignatureHasPacketContent(s) == 1) { sids_array[s->num / 8] |= 1 << (s->num % 8); cnt++; } break; case MPMB_TCP_STREAM_TS: case MPMB_TCP_STREAM_TC: - if (SignatureHasStreamContent(s) == 1) - { + if (SignatureHasStreamContent(s) == 1) { sids_array[s->num / 8] |= 1 << (s->num % 8); cnt++; } @@ -1765,8 +1718,7 @@ static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx, SigGroup return NULL; SCLogDebug("handling %s direction %s for list %d", am->name, - am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", - am->sm_list); + am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", am->sm_list); MpmStore lookup = { sa->sids_array, sa->sids_array_size, am->direction, MPMB_MAX, am->sm_list, 0, am->app_v2.alproto, NULL }; @@ -1809,8 +1761,7 @@ static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx, SigGroup static MpmStore *MpmStorePrepareBufferPkt(DetectEngineCtx *de_ctx, SigGroupHead *sgh, const DetectBufferMpmRegistry *am, const struct SidsArray *sa) { - SCLogDebug("handling %s for list %d", am->name, - am->sm_list); + SCLogDebug("handling %s for list %d", am->name, am->sm_list); if (sa->sids_array_size == 0 || sa->sids_array == NULL) return NULL; @@ -1836,7 +1787,7 @@ static MpmStore *MpmStorePrepareBufferPkt(DetectEngineCtx *de_ctx, SigGroupHead copy->sid_array = sids; copy->sid_array_size = sa->sids_array_size; copy->buffer = MPMB_MAX; - copy->direction = SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT; + copy->direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT; copy->sm_list = am->sm_list; copy->sgh_mpm_context = am->sgh_mpm_context; @@ -2123,15 +2074,14 @@ static void PrepareMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh) sh->init->pkt_mpms[a->id] = mpm_store->mpm_ctx; SCLogDebug("a %p a->name %s a->reg->PrefilterRegisterWithListId %p " - "mpm_store->mpm_ctx %p", a, a->name, - a->PrefilterRegisterWithListId, mpm_store->mpm_ctx); + "mpm_store->mpm_ctx %p", + a, a->name, a->PrefilterRegisterWithListId, mpm_store->mpm_ctx); /* if we have just certain types of negated patterns, * mpm_ctx can be NULL */ if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) { - BUG_ON(a->PrefilterRegisterWithListId(de_ctx, - sh, mpm_store->mpm_ctx, - a, a->sm_list) != 0); + BUG_ON(a->PrefilterRegisterWithListId( + de_ctx, sh, mpm_store->mpm_ctx, a, a->sm_list) != 0); SCLogDebug("mpm %s %d set up", a->name, a->sm_list); } } @@ -2237,7 +2187,7 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) } SetRawReassemblyFlag(de_ctx, sh); - } + } } else if (SGH_PROTO(sh, IPPROTO_UDP)) { if (SGH_DIRECTION_TS(sh)) { mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS); diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index adb40297190f..9b98c5b7504b 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -24,10 +24,8 @@ #ifndef __DETECT_ENGINE_MPM_H__ #define __DETECT_ENGINE_MPM_H__ - #include "detect.h" - void DetectMpmInitializeFrameMpms(DetectEngineCtx *de_ctx); int DetectMpmPrepareFrameMpms(DetectEngineCtx *de_ctx); void DetectMpmInitializePktMpms(DetectEngineCtx *de_ctx); @@ -62,7 +60,8 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s); int MpmStoreInit(DetectEngineCtx *); void MpmStoreFree(DetectEngineCtx *); void MpmStoreReportStats(const DetectEngineCtx *de_ctx); -MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf); +MpmStore *MpmStorePrepareBuffer( + DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf); /** * \brief Figure out the FP and their respective content ids for all the @@ -93,15 +92,12 @@ typedef int (*PrefilterRegisterFunc)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void DetectAppLayerMpmRegister2(const char *name, int direction, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetDataPtr GetData, AppProto alproto, int tx_min_progress); -void DetectAppLayerMpmRegisterByParentId( - DetectEngineCtx *de_ctx, - const int id, const int parent_id, +void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id, DetectEngineTransforms *transforms); void DetectPktMpmRegister(const char *name, int priority, PrefilterRegisterFunc PrefilterRegister, InspectionBufferGetPktDataPtr GetData); -void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx, - const int id, const int parent_id, +void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id, DetectEngineTransforms *transforms); void DetectFrameMpmRegister(const char *name, int direction, int priority, @@ -136,4 +132,3 @@ struct MpmListIdDataArgs { void EngineAnalysisAddAllRulePatterns(DetectEngineCtx *de_ctx, const Signature *s); #endif /* __DETECT_ENGINE_MPM_H__ */ - diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index 7da3c3b81f93..56caea8e56b2 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -41,14 +41,14 @@ #include "stream.h" #include "stream-tcp.h" -#include "util-debug.h" -#include "util-print.h" +#include "util/debug.h" +#include "util/print.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-validate.h" -#include "util-profiling.h" -#include "util-mpm-ac.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/validate.h" +#include "util/profiling.h" +#include "util/mpm/mpm-ac.h" struct StreamMpmData { DetectEngineThreadCtx *det_ctx; @@ -71,8 +71,7 @@ static int StreamMpmFunc( return 0; } -static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx) +static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { SCEnter(); @@ -80,15 +79,11 @@ static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, /* for established packets inspect any stream we may have queued up */ if (p->flags & PKT_DETECT_HAS_STREAMDATA) { - SCLogDebug("PRE det_ctx->raw_stream_progress %"PRIu64, - det_ctx->raw_stream_progress); + SCLogDebug("PRE det_ctx->raw_stream_progress %" PRIu64, det_ctx->raw_stream_progress); struct StreamMpmData stream_mpm_data = { det_ctx, mpm_ctx }; - StreamReassembleRaw(p->flow->protoctx, p, - StreamMpmFunc, &stream_mpm_data, - &det_ctx->raw_stream_progress, - false /* mpm doesn't use min inspect depth */); - SCLogDebug("POST det_ctx->raw_stream_progress %"PRIu64, - det_ctx->raw_stream_progress); + StreamReassembleRaw(p->flow->protoctx, p, StreamMpmFunc, &stream_mpm_data, + &det_ctx->raw_stream_progress, false /* mpm doesn't use min inspect depth */); + SCLogDebug("POST det_ctx->raw_stream_progress %" PRIu64, det_ctx->raw_stream_progress); /* packets that have not been added to the stream will be inspected as if they are stream * chunks */ @@ -98,23 +93,19 @@ static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, det_ctx->payload_mpm_cnt++; det_ctx->payload_mpm_size += p->payload_len; #endif - (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); PREFILTER_PROFILING_ADD_BYTES(det_ctx, p->payload_len); } } } -int PrefilterPktStreamRegister(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, MpmCtx *mpm_ctx) +int PrefilterPktStreamRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx) { - return PrefilterAppendPayloadEngine(de_ctx, sgh, - PrefilterPktStream, mpm_ctx, NULL, "stream"); + return PrefilterAppendPayloadEngine(de_ctx, sgh, PrefilterPktStream, mpm_ctx, NULL, "stream"); } -static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx) +static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { SCEnter(); @@ -122,21 +113,17 @@ static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, if (p->payload_len < mpm_ctx->minlen) SCReturn; - (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); + (void)mpm_table[mpm_ctx->mpm_type].Search( + mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, p->payload, p->payload_len); PREFILTER_PROFILING_ADD_BYTES(det_ctx, p->payload_len); } -int PrefilterPktPayloadRegister(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, MpmCtx *mpm_ctx) +int PrefilterPktPayloadRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx) { - return PrefilterAppendPayloadEngine(de_ctx, sgh, - PrefilterPktPayload, mpm_ctx, NULL, "payload"); + return PrefilterAppendPayloadEngine(de_ctx, sgh, PrefilterPktPayload, mpm_ctx, NULL, "payload"); } - /** * \brief Do the content inspection & validation for a signature * @@ -249,17 +236,15 @@ static int StreamContentInspectFunc( * \retval 0 no match * \retval 1 match */ -int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const Signature *s, - Flow *f, Packet *p) +int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, Flow *f, Packet *p) { SCEnter(); - SCLogDebug("FLUSH? %s", (s->flags & SIG_FLAG_FLUSH)?"true":"false"); + SCLogDebug("FLUSH? %s", (s->flags & SIG_FLAG_FLUSH) ? "true" : "false"); uint64_t unused; struct StreamContentInspectData inspect_data = { de_ctx, det_ctx, s, f }; - int r = StreamReassembleRaw(f->protoctx, p, - StreamContentInspectFunc, &inspect_data, - &unused, ((s->flags & SIG_FLAG_FLUSH) != 0)); + int r = StreamReassembleRaw(f->protoctx, p, StreamContentInspectFunc, &inspect_data, &unused, + ((s->flags & SIG_FLAG_FLUSH) != 0)); return r; } @@ -317,13 +302,11 @@ uint8_t DetectEngineInspectStream(DetectEngineCtx *de_ctx, DetectEngineThreadCtx if (ssn == NULL) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - SCLogDebug("pre-inspect det_ctx->raw_stream_progress %"PRIu64" FLUSH? %s", - det_ctx->raw_stream_progress, - (s->flags & SIG_FLAG_FLUSH)?"true":"false"); + SCLogDebug("pre-inspect det_ctx->raw_stream_progress %" PRIu64 " FLUSH? %s", + det_ctx->raw_stream_progress, (s->flags & SIG_FLAG_FLUSH) ? "true" : "false"); uint64_t unused; struct StreamContentInspectEngineData inspect_data = { de_ctx, det_ctx, s, engine->smd, f }; - int match = StreamReassembleRaw(f->protoctx, p, - StreamContentInspectEngineFunc, &inspect_data, + int match = StreamReassembleRaw(f->protoctx, p, StreamContentInspectEngineFunc, &inspect_data, &unused, ((s->flags & SIG_FLAG_FLUSH) != 0)); bool is_last = false; @@ -337,15 +320,14 @@ uint8_t DetectEngineInspectStream(DetectEngineCtx *de_ctx, DetectEngineThreadCtx is_last = true; } - SCLogDebug("%s ran stream for sid %u on packet %"PRIu64" and we %s", - is_last? "LAST:" : "normal:", s->id, p->pcap_cnt, - match ? "matched" : "didn't match"); + SCLogDebug("%s ran stream for sid %u on packet %" PRIu64 " and we %s", + is_last ? "LAST:" : "normal:", s->id, p->pcap_cnt, match ? "matched" : "didn't match"); if (match) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { if (is_last) { - //SCLogNotice("last, so DETECT_ENGINE_INSPECT_SIG_CANT_MATCH"); + // SCLogNotice("last, so DETECT_ENGINE_INSPECT_SIG_CANT_MATCH"); return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } /* TODO maybe we can set 'CANT_MATCH' for EOF too? */ @@ -358,16 +340,16 @@ uint8_t DetectEngineInspectStream(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /** \test Not the first but the second occurrence of "abc" should be used * for the 2nd match */ -static int PayloadTestSig01 (void) +static int PayloadTestSig01(void) { - uint8_t *buf = (uint8_t *) - "abcabcd"; + uint8_t *buf = (uint8_t *)"abcabcd"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"abc\"; content:\"d\"; distance:0; within:1; sid:1;)"; + char sig[] = "alert tcp any any -> any any (content:\"abc\"; content:\"d\"; distance:0; " + "within:1; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -377,16 +359,16 @@ static int PayloadTestSig01 (void) } /** \test Nocase matching */ -static int PayloadTestSig02 (void) +static int PayloadTestSig02(void) { - uint8_t *buf = (uint8_t *) - "abcaBcd"; + uint8_t *buf = (uint8_t *)"abcaBcd"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"abc\"; nocase; content:\"d\"; distance:0; within:1; sid:1;)"; + char sig[] = "alert tcp any any -> any any (content:\"abc\"; nocase; content:\"d\"; " + "distance:0; within:1; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -396,16 +378,16 @@ static int PayloadTestSig02 (void) } /** \test Negative distance matching */ -static int PayloadTestSig03 (void) +static int PayloadTestSig03(void) { - uint8_t *buf = (uint8_t *) - "abcaBcd"; + uint8_t *buf = (uint8_t *)"abcaBcd"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"aBc\"; nocase; content:\"abca\"; distance:-10; within:4; sid:1;)"; + char sig[] = "alert tcp any any -> any any (content:\"aBc\"; nocase; content:\"abca\"; " + "distance:-10; within:4; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -426,8 +408,8 @@ static int PayloadTestSig04(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; " - "content:\"string\"; within:8; sid:1;)"; + "content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; " + "content:\"string\"; within:8; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -448,8 +430,8 @@ static int PayloadTestSig05(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"this\"; content:\"is\"; within:9; content:\"big\"; within:12; " - "content:\"string\"; within:8; sid:1;)"; + "content:\"this\"; content:\"is\"; within:9; content:\"big\"; within:12; " + "content:\"string\"; within:8; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -470,8 +452,9 @@ static int PayloadTestSig06(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"now\"; content:\"this\"; content:\"is\"; within:12; content:\"big\"; within:8; " - "content:\"string\"; within:8; sid:1;)"; + "content:\"now\"; content:\"this\"; content:\"is\"; within:12; content:\"big\"; " + "within:8; " + "content:\"string\"; within:8; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -492,7 +475,8 @@ static int PayloadTestSig07(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"thus\"; offset:8; content:\"is\"; within:6; content:\"big\"; within:8; sid:1;)"; + "content:\"thus\"; offset:8; content:\"is\"; within:6; content:\"big\"; within:8; " + "sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -513,8 +497,9 @@ static int PayloadTestSig08(void) FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"fix\"; content:\"this\"; within:6; content:!\"and\"; distance:0; sid:1;)"; + char sig[] = + "alert tcp any any -> any any (msg:\"dummy\"; " + "content:\"fix\"; content:\"this\"; within:6; content:!\"and\"; distance:0; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1); @@ -535,7 +520,7 @@ static int PayloadTestSig09(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "pcre:/super/; content:\"nova\"; within:7; sid:1;)"; + "pcre:/super/; content:\"nova\"; within:7; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -556,7 +541,7 @@ static int PayloadTestSig10(void) FAIL_IF_NULL(p); char sig[] = "alert udp any any -> any any (msg:\"crash\"; " - "byte_test:4,>,2,0,relative; sid:11;)"; + "byte_test:4,>,2,0,relative; sid:11;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1); @@ -577,7 +562,7 @@ static int PayloadTestSig11(void) FAIL_IF_NULL(p); char sig[] = "alert udp any any -> any any (msg:\"crash\"; " - "byte_jump:1,0,relative; sid:11;)"; + "byte_jump:1,0,relative; sid:11;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1); @@ -598,7 +583,7 @@ static int PayloadTestSig12(void) FAIL_IF_NULL(p); char sig[] = "alert udp any any -> any any (msg:\"crash\"; " - "isdataat:10,relative; sid:11;)"; + "isdataat:10,relative; sid:11;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1); @@ -613,25 +598,25 @@ static int PayloadTestSig12(void) static int PayloadTestSig13(void) { uint8_t *buf = (uint8_t *)"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); @@ -640,8 +625,8 @@ static int PayloadTestSig13(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"aa\"; content:\"aa\"; distance:0; content:\"aa\"; distance:0; " - "byte_test:1,>,200,0,relative; sid:1;)"; + "content:\"aa\"; content:\"aa\"; distance:0; content:\"aa\"; distance:0; " + "byte_test:1,>,200,0,relative; sid:1;)"; DecodeThreadVars dtv; ThreadVars th_v; @@ -681,15 +666,23 @@ static int PayloadTestSig13(void) */ static int PayloadTestSig14(void) { - uint8_t *buf = (uint8_t *)"User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5"; + uint8_t *buf = (uint8_t *)"User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; " + "rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); - char sig[] = "alert tcp any any -> any any (content:\"User-Agent|3A| Mozilla/5.0 |28|Macintosh|3B| \"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; content:!\"Mozilla/5.0 |28|Macintosh|3B| U|3B| Intel Mac OS X 10.5|3B| en-US|3B| rv|3A|1.9.1b4|29| Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; + char sig[] = + "alert tcp any any -> any any (content:\"User-Agent|3A| Mozilla/5.0 |28|Macintosh|3B| " + "\"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; " + "content:!\"Mozilla/5.0 |28|Macintosh|3B| U|3B| Intel Mac OS X 10.5|3B| en-US|3B| " + "rv|3A|1.9.1b4|29| Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; - //char sig[] = "alert tcp any any -> any any (content:\"User-Agent: Mozilla/5.0 (Macintosh; \"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; content:!\"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; + // char sig[] = "alert tcp any any -> any any (content:\"User-Agent: Mozilla/5.0 (Macintosh; \"; + // content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; + // content:!\"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 + // Firefox/3.6 GTB5\"; sid:1; rev:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1); @@ -707,7 +700,7 @@ static int PayloadTestSig15(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"nova\"; isdataat:18,relative; sid:1;)"; + "content:\"nova\"; isdataat:18,relative; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -725,7 +718,7 @@ static int PayloadTestSig16(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"nova\"; isdataat:!20,relative; sid:1;)"; + "content:\"nova\"; isdataat:!20,relative; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -743,8 +736,8 @@ static int PayloadTestSig17(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"%\"; depth:4; offset:0; " - "content:\"%\"; within:2; distance:1; sid:1;)"; + "content:\"%\"; depth:4; offset:0; " + "content:\"%\"; within:2; distance:1; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -755,20 +748,22 @@ static int PayloadTestSig17(void) static int PayloadTestSig18(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|01 02 03 04|\"; " - "byte_extract:1,2,one,string,dec,relative; " - "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; + "content:\"|01 02 03 04|\"; " + "byte_extract:1,2,one,string,dec,relative; " + "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -779,20 +774,22 @@ static int PayloadTestSig18(void) static int PayloadTestSig19(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|01 02 03 04|\"; " - "byte_extract:1,2,one,string,hex,relative; " - "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; + "content:\"|01 02 03 04|\"; " + "byte_extract:1,2,one,string,hex,relative; " + "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -803,20 +800,22 @@ static int PayloadTestSig19(void) static int PayloadTestSig20(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|01 02 03 04|\"; " - "byte_extract:1,2,one,string,dec,relative; " - "content:\"|06 35 07 08|\"; offset:one; sid:1;)"; + "content:\"|01 02 03 04|\"; " + "byte_extract:1,2,one,string,dec,relative; " + "content:\"|06 35 07 08|\"; offset:one; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -827,20 +826,22 @@ static int PayloadTestSig20(void) static int PayloadTestSig21(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x36, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|01 02 03 04|\"; " - "byte_extract:1,2,one,string,dec,relative; " - "content:\"|03 04 05 06|\"; depth:one; sid:1;)"; + "content:\"|01 02 03 04|\"; " + "byte_extract:1,2,one,string,dec,relative; " + "content:\"|03 04 05 06|\"; depth:one; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -851,20 +852,22 @@ static int PayloadTestSig21(void) static int PayloadTestSig22(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x36, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|01 02 03 04|\"; " - "byte_extract:1,2,one,string,dec,relative; " - "content:\"|09 0A 0B 0C|\"; within:one; sid:1;)"; + "content:\"|01 02 03 04|\"; " + "byte_extract:1,2,one,string,dec,relative; " + "content:\"|09 0A 0B 0C|\"; within:one; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -875,21 +878,23 @@ static int PayloadTestSig22(void) static int PayloadTestSig23(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x32, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x33, 0x0B, 0x0C, 0x0D, 0x32, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|01 02 03 04|\"; " - "byte_extract:1,2,one,string,dec,relative; " - "byte_extract:1,3,two,string,dec,relative; " - "byte_test:1,=,one,two,string,dec,relative; sid:1;)"; + "content:\"|01 02 03 04|\"; " + "byte_extract:1,2,one,string,dec,relative; " + "byte_extract:1,3,two,string,dec,relative; " + "byte_test:1,=,one,two,string,dec,relative; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -900,21 +905,23 @@ static int PayloadTestSig23(void) static int PayloadTestSig24(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x32, /* the last byte is 2 */ 0x07, 0x08, 0x33, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|01 02 03 04|\"; " - "byte_extract:1,2,one,string,dec,relative; " - "byte_jump:1,one,string,dec,relative; " - "content:\"|0D 0E 0F|\"; distance:0; sid:1;)"; + "content:\"|01 02 03 04|\"; " + "byte_extract:1,2,one,string,dec,relative; " + "byte_jump:1,one,string,dec,relative; " + "content:\"|0D 0E 0F|\"; distance:0; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -928,20 +935,22 @@ static int PayloadTestSig24(void) */ static int PayloadTestSig25(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|35 07 08 09|\"; " - "byte_extract:1,-4,one,string,dec,relative; " - "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; + "content:\"|35 07 08 09|\"; " + "byte_extract:1,-4,one,string,dec,relative; " + "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -955,20 +964,22 @@ static int PayloadTestSig25(void) */ static int PayloadTestSig26(void) { + // clang-format off uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x35, /* the last byte is 2 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"|35 07 08 09|\"; " - "byte_extract:1,-3000,one,string,dec,relative; " - "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; + "content:\"|35 07 08 09|\"; " + "byte_extract:1,-3000,one,string,dec,relative; " + "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 0); @@ -989,7 +1000,7 @@ static int PayloadTestSig27(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (content:\"dummy\"; " - "depth:5; sid:1;)"; + "depth:5; sid:1;)"; p->flags |= PKT_STREAM_ADD; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1); @@ -1011,7 +1022,7 @@ static int PayloadTestSig28(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (content:\"payload\"; " - "offset:4; depth:12; sid:1;)"; + "offset:4; depth:12; sid:1;)"; p->flags |= PKT_STREAM_ADD; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1); @@ -1033,7 +1044,7 @@ static int PayloadTestSig29(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " - "pcre:/^.{4}/; content:\"nova\"; within:4; sid:1;)"; + "pcre:/^.{4}/; content:\"nova\"; within:4; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1); @@ -1044,8 +1055,7 @@ static int PayloadTestSig29(void) static int PayloadTestSig30(void) { - uint8_t *buf = (uint8_t *) - "xyonexxxxxxtwojunkonetwo"; + uint8_t *buf = (uint8_t *)"xyonexxxxxxtwojunkonetwo"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); @@ -1062,8 +1072,7 @@ static int PayloadTestSig30(void) static int PayloadTestSig31(void) { - uint8_t *buf = (uint8_t *) - "xyonexxxxxxtwojunkonetwo"; + uint8_t *buf = (uint8_t *)"xyonexxxxxxtwojunkonetwo"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); @@ -1090,7 +1099,8 @@ static int PayloadTestSig32(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " - "content:\"message\"; byte_jump:2,-14,string,dec,relative; content:\"card\"; within:4; sid:1;)"; + "content:\"message\"; byte_jump:2,-14,string,dec,relative; content:\"card\"; " + "within:4; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -1111,7 +1121,7 @@ static int PayloadTestSig33(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " - "content:\"message\"; byte_test:1,=,2,-14,string,dec,relative; sid:1;)"; + "content:\"message\"; byte_test:1,=,2,-14,string,dec,relative; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); @@ -1132,7 +1142,7 @@ static int PayloadTestSig34(void) FAIL_IF_NULL(p); char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " - "content:\"message\"; byte_extract:1,-14,boom,string,dec,relative; sid:1;)"; + "content:\"message\"; byte_extract:1,-14,boom,string,dec,relative; sid:1;)"; FAIL_IF(UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0); diff --git a/src/detect-engine-payload.h b/src/detect-engine-payload.h index 7ef29db6c666..eb0bf98e9ca9 100644 --- a/src/detect-engine-payload.h +++ b/src/detect-engine-payload.h @@ -24,16 +24,13 @@ #ifndef __DETECT_ENGINE_PAYLOAD_H__ #define __DETECT_ENGINE_PAYLOAD_H__ -int PrefilterPktPayloadRegister(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, MpmCtx *mpm_ctx); -int PrefilterPktStreamRegister(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterPktPayloadRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterPktStreamRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx); uint8_t DetectEngineInspectPacketPayload( DetectEngineCtx *, DetectEngineThreadCtx *, const Signature *, Flow *, Packet *); -int DetectEngineInspectStreamPayload(DetectEngineCtx *, - DetectEngineThreadCtx *, const Signature *, Flow *, - Packet *); +int DetectEngineInspectStreamPayload( + DetectEngineCtx *, DetectEngineThreadCtx *, const Signature *, Flow *, Packet *); uint8_t DetectEngineInspectStream(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); @@ -41,4 +38,3 @@ uint8_t DetectEngineInspectStream(DetectEngineCtx *de_ctx, DetectEngineThreadCtx void PayloadRegisterTests(void); #endif /* __DETECT_ENGINE_PAYLOAD_H__ */ - diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 86a367d376cd..17e87e073585 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -31,10 +31,10 @@ #include "detect.h" #include "flow-var.h" -#include "util-cidr.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-rule-vars.h" +#include "util/cidr.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/rule-vars.h" #include "detect-parse.h" #include "detect-engine.h" @@ -44,18 +44,17 @@ #include "detect-engine-port.h" #include "conf.h" -#include "util-debug.h" -#include "util-error.h" +#include "util/debug.h" +#include "util/error.h" #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" -#include "util-var.h" -#include "util-byte.h" +#include "util/profiling.h" +#include "util/var.h" +#include "util/byte.h" static int DetectPortCutNot(DetectPort *, DetectPort **); -static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *, - DetectPort **); +static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *, DetectPort **); DetectPort *PortParse(const char *str); static bool DetectPortIsValidRange(char *, uint16_t *); @@ -106,9 +105,9 @@ void DetectPortPrintList(DetectPort *head) SCLogDebug("= list start:"); if (head != NULL) { for (cur = head; cur != NULL; cur = cur->next) { - DetectPortPrint(cur); + DetectPortPrint(cur); #ifdef DEBUG - cnt++; + cnt++; #endif } SCLogDebug(" "); @@ -121,14 +120,14 @@ void DetectPortPrintList(DetectPort *head) * * \param head Pointer to the DetectPort list head */ -void DetectPortCleanupList (const DetectEngineCtx *de_ctx, DetectPort *head) +void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head) { if (head == NULL) return; DetectPort *cur, *next; - for (cur = head; cur != NULL; ) { + for (cur = head; cur != NULL;) { next = cur->next; cur->next = NULL; DetectPortFree(de_ctx, cur); @@ -150,14 +149,13 @@ void DetectPortCleanupList (const DetectEngineCtx *de_ctx, DetectPort *head) * * \todo rewrite to avoid recursive calls * */ -int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, - DetectPort *new) +int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, DetectPort *new) { if (new == NULL) return 0; - //BUG_ON(new->next != NULL); - //BUG_ON(new->prev != NULL); + // BUG_ON(new->next != NULL); + // BUG_ON(new->prev != NULL); /* see if it already exists or overlaps with existing ports */ if (*head != NULL) { @@ -165,7 +163,7 @@ int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, int r = 0; for (cur = *head; cur != NULL; cur = cur->next) { - r = DetectPortCmp(new,cur); + r = DetectPortCmp(new, cur); BUG_ON(r == PORT_ER); /* if so, handle that */ @@ -206,8 +204,8 @@ int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, } return 1; - /* alright, those were the simple cases, - * lets handle the more complex ones now */ + /* alright, those were the simple cases, + * lets handle the more complex ones now */ } else { DetectPort *c = NULL; @@ -233,11 +231,10 @@ int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, goto error; } return 1; - } } - /* head is NULL, so get a group and set head to it */ + /* head is NULL, so get a group and set head to it */ } else { SCLogDebug("setting new head %p", new); *head = new; @@ -260,8 +257,7 @@ int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, * \retval 0 ok * \retval -1 error * */ -static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, - DetectPort *b, DetectPort **c) +static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, DetectPort *b, DetectPort **c) { uint16_t a_port1 = a->port; uint16_t a_port2 = a->port2; @@ -271,7 +267,7 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, /* default to NULL */ *c = NULL; - int r = DetectPortCmp(a,b); + int r = DetectPortCmp(a, b); BUG_ON(r != PORT_ES && r != PORT_EB && r != PORT_LE && r != PORT_GE); /* get a place to temporary put sigs lists */ @@ -303,15 +299,15 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, tmp_c->port = a_port2 + 1; tmp_c->port2 = b_port2; - SigGroupHeadCopySigs(de_ctx,b->sh,&tmp_c->sh); /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); /* copy a to b */ + SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); /* copy old b to c */ + SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); /* copy a to b */ - /** - * We have 3 parts: [bbb[baba]aaa] - * part a: b_port1 <-> a_port1 - 1 - * part b: a_port1 <-> b_port2 - * part c: b_port2 + 1 <-> a_port2 - */ + /** + * We have 3 parts: [bbb[baba]aaa] + * part a: b_port1 <-> a_port1 - 1 + * part b: a_port1 <-> b_port2 + * part c: b_port2 + 1 <-> a_port2 + */ } else if (r == PORT_GE) { SCLogDebug("cut r == PORT_GE"); a->port = b_port1; @@ -334,31 +330,31 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'a' sigs */ - SigGroupHeadCopySigs(de_ctx,a->sh,&tmp->sh); /* store old a list */ - SigGroupHeadClearSigs(a->sh); /* clean a list */ - SigGroupHeadCopySigs(de_ctx,tmp->sh,&tmp_c->sh); /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx,tmp->sh,&b->sh);/* prepend old a before b */ + SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); /* store old a list */ + SigGroupHeadClearSigs(a->sh); /* clean a list */ + SigGroupHeadCopySigs(de_ctx, tmp->sh, &tmp_c->sh); /* copy old b to c */ + SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); /* copy old b to a */ + SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* prepend old a before b */ SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ - /** - * We have 2 or three parts: - * - * 2 part: [[abab]bbb] or [bbb[baba]] - * part a: a_port1 <-> a_port2 - * part b: a_port2 + 1 <-> b_port2 - * - * part a: b_port1 <-> a_port1 - 1 - * part b: a_port1 <-> a_port2 - * - * 3 part [bbb[aaa]bbb] - * becomes[aaa[bbb]ccc] - * - * part a: b_port1 <-> a_port1 - 1 - * part b: a_port1 <-> a_port2 - * part c: a_port2 + 1 <-> b_port2 - */ + /** + * We have 2 or three parts: + * + * 2 part: [[abab]bbb] or [bbb[baba]] + * part a: a_port1 <-> a_port2 + * part b: a_port2 + 1 <-> b_port2 + * + * part a: b_port1 <-> a_port1 - 1 + * part b: a_port1 <-> a_port2 + * + * 3 part [bbb[aaa]bbb] + * becomes[aaa[bbb]ccc] + * + * part a: b_port1 <-> a_port1 - 1 + * part b: a_port1 <-> a_port2 + * part c: a_port2 + 1 <-> b_port2 + */ } else if (r == PORT_ES) { SCLogDebug("cut r == PORT_ES"); if (a_port1 == b_port1) { @@ -366,11 +362,11 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, a->port = a_port1; a->port2 = a_port2; - b->port = a_port2 + 1; + b->port = a_port2 + 1; b->port2 = b_port2; /** 'b' overlaps 'a' so 'a' needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); + SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); } else if (a_port2 == b_port2) { SCLogDebug("2"); @@ -386,11 +382,11 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, * a overlaps b, so copy a to b * clear a * copy tmp to a */ - SigGroupHeadCopySigs(de_ctx,b->sh,&tmp->sh); /* store old a list */ - SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); - SigGroupHeadClearSigs(a->sh); /* clean a list */ - SigGroupHeadCopySigs(de_ctx,tmp->sh,&a->sh);/* merge old a with b */ - SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ + SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); /* store old a list */ + SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); + SigGroupHeadClearSigs(a->sh); /* clean a list */ + SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); /* merge old a with b */ + SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ } else { SCLogDebug("3"); a->port = b_port1; @@ -413,31 +409,31 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, * 'b' gets clean, then 'a' then 'b' sigs * 'c' gets 'b' sigs */ - SigGroupHeadCopySigs(de_ctx,a->sh,&tmp->sh); /* store old a list */ - SigGroupHeadClearSigs(a->sh); /* clean a list */ - SigGroupHeadCopySigs(de_ctx,b->sh,&tmp_c->sh); /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx,tmp->sh,&b->sh);/* merge old a with b */ + SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); /* store old a list */ + SigGroupHeadClearSigs(a->sh); /* clean a list */ + SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); /* copy old b to c */ + SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); /* copy old b to a */ + SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); /* merge old a with b */ SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ } - /** - * We have 2 or three parts: - * - * 2 part: [[baba]aaa] or [aaa[abab]] - * part a: b_port1 <-> b_port2 - * part b: b_port2 + 1 <-> a_port2 - * - * part a: a_port1 <-> b_port1 - 1 - * part b: b_port1 <-> b_port2 - * - * 3 part [aaa[bbb]aaa] - * becomes[aaa[bbb]ccc] - * - * part a: a_port1 <-> b_port2 - 1 - * part b: b_port1 <-> b_port2 - * part c: b_port2 + 1 <-> a_port2 - */ + /** + * We have 2 or three parts: + * + * 2 part: [[baba]aaa] or [aaa[abab]] + * part a: b_port1 <-> b_port2 + * part b: b_port2 + 1 <-> a_port2 + * + * part a: a_port1 <-> b_port1 - 1 + * part b: b_port1 <-> b_port2 + * + * 3 part [aaa[bbb]aaa] + * becomes[aaa[bbb]ccc] + * + * part a: a_port1 <-> b_port2 - 1 + * part b: b_port1 <-> b_port2 + * part c: b_port2 + 1 <-> a_port2 + */ } else if (r == PORT_EB) { SCLogDebug("cut r == PORT_EB"); if (a_port1 == b_port1) { @@ -449,10 +445,10 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, b->port2 = a_port2; /** 'b' overlaps 'a' so 'a' needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx,b->sh,&tmp->sh); + SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); SigGroupHeadClearSigs(b->sh); - SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); - SigGroupHeadCopySigs(de_ctx,tmp->sh,&a->sh); + SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); + SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); SigGroupHeadClearSigs(tmp->sh); @@ -466,7 +462,7 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, b->port2 = b_port2; /** 'a' overlaps 'b' so 'b' needs the 'a' sigs */ - SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); + SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); } else { SCLogDebug("3"); @@ -485,8 +481,8 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, tmp_c->port = b_port2 + 1; tmp_c->port2 = a_port2; - SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); - SigGroupHeadCopySigs(de_ctx,a->sh,&tmp_c->sh); + SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); + SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); } } @@ -572,27 +568,27 @@ int DetectPortCmp(DetectPort *a, DetectPort *b) /* PORT_EQ */ if (a_port1 == b_port1 && a_port2 == b_port2) { - //SCLogDebug("PORT_EQ"); + // SCLogDebug("PORT_EQ"); return PORT_EQ; - /* PORT_ES */ + /* PORT_ES */ } else if (a_port1 >= b_port1 && a_port1 <= b_port2 && a_port2 <= b_port2) { - //SCLogDebug("PORT_ES"); + // SCLogDebug("PORT_ES"); return PORT_ES; - /* PORT_EB */ + /* PORT_EB */ } else if (a_port1 <= b_port1 && a_port2 >= b_port2) { - //SCLogDebug("PORT_EB"); + // SCLogDebug("PORT_EB"); return PORT_EB; } else if (a_port1 < b_port1 && a_port2 < b_port2 && a_port2 >= b_port1) { - //SCLogDebug("PORT_LE"); + // SCLogDebug("PORT_LE"); return PORT_LE; } else if (a_port1 < b_port1 && a_port2 < b_port2) { - //SCLogDebug("PORT_LT"); + // SCLogDebug("PORT_LT"); return PORT_LT; } else if (a_port1 > b_port1 && a_port1 <= b_port2 && a_port2 > b_port2) { - //SCLogDebug("PORT_GE"); + // SCLogDebug("PORT_GE"); return PORT_GE; } else if (a_port1 > b_port2) { - //SCLogDebug("PORT_GT"); + // SCLogDebug("PORT_GT"); return PORT_GT; } @@ -608,7 +604,7 @@ int DetectPortCmp(DetectPort *a, DetectPort *b) * \retval Pointer to a DetectPort instance (copy of src) * \retval NULL on error * */ -DetectPort *DetectPortCopySingle(DetectEngineCtx *de_ctx,DetectPort *src) +DetectPort *DetectPortCopySingle(DetectEngineCtx *de_ctx, DetectPort *src) { if (src == NULL) return NULL; @@ -621,7 +617,7 @@ DetectPort *DetectPortCopySingle(DetectEngineCtx *de_ctx,DetectPort *src) dst->port = src->port; dst->port2 = src->port2; - SigGroupHeadCopySigs(de_ctx,src->sh,&dst->sh); + SigGroupHeadCopySigs(de_ctx, src->sh, &dst->sh); return dst; } @@ -636,8 +632,7 @@ DetectPort *DetectPortCopySingle(DetectEngineCtx *de_ctx,DetectPort *src) * */ static int DetectPortMatch(DetectPort *dp, uint16_t port) { - if (port >= dp->port && - port <= dp->port2) { + if (port >= dp->port && port <= dp->port2) { return 1; } @@ -655,10 +650,10 @@ void DetectPortPrint(DetectPort *dp) if (dp->flags & PORT_FLAG_ANY) { SCLogDebug("=> port %p: ANY", dp); -// printf("ANY"); + // printf("ANY"); } else { SCLogDebug("=> port %p %" PRIu32 "-%" PRIu32 "", dp, dp->port, dp->port2); -// printf("%" PRIu32 "-%" PRIu32 "", dp->port, dp->port2); + // printf("%" PRIu32 "-%" PRIu32 "", dp->port, dp->port2); } } @@ -678,8 +673,8 @@ DetectPort *DetectPortLookupGroup(DetectPort *dp, uint16_t port) for (DetectPort *p = dp; p != NULL; p = p->next) { if (DetectPortMatch(p, port) == 1) { - //SCLogDebug("match, port %" PRIu32 ", dp ", port); - //DetectPortPrint(p); SCLogDebug(""); + // SCLogDebug("match, port %" PRIu32 ", dp ", port); + // DetectPortPrint(p); SCLogDebug(""); return p; } } @@ -745,8 +740,8 @@ static int DetectPortParseInsert(DetectPort **head, DetectPort *new) * \retval 0 on success * \retval -1 on error */ -static int DetectPortParseInsertString(const DetectEngineCtx *de_ctx, - DetectPort **head, const char *s) +static int DetectPortParseInsertString( + const DetectEngineCtx *de_ctx, DetectPort **head, const char *s) { DetectPort *ad = NULL, *ad_any = NULL; int r = 0; @@ -778,7 +773,8 @@ static int DetectPortParseInsertString(const DetectEngineCtx *de_ctx, */ if (ad2 != NULL) { if (DetectPortParseInsert(head, ad2) < 0) { - if (ad2 != NULL) SCFree(ad2); + if (ad2 != NULL) + SCFree(ad2); goto error; } } @@ -797,7 +793,7 @@ static int DetectPortParseInsertString(const DetectEngineCtx *de_ctx, goto error; if (DetectPortParseInsert(head, ad_any) < 0) - goto error; + goto error; } return 0; @@ -833,10 +829,8 @@ static int DetectPortParseInsertString(const DetectEngineCtx *de_ctx, * \retval 0 On successfully parsing. * \retval -1 On failure. */ -static int DetectPortParseDo(const DetectEngineCtx *de_ctx, - DetectPort **head, DetectPort **nhead, - const char *s, int negate, - ResolvedVariablesList *var_list, int recur) +static int DetectPortParseDo(const DetectEngineCtx *de_ctx, DetectPort **head, DetectPort **nhead, + const char *s, int negate, ResolvedVariablesList *var_list, int recur) { size_t u = 0; size_t x = 0; @@ -882,8 +876,8 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, SCLogDebug("Parsed port from DetectPortParseDo - %s", address); x = 0; - r = DetectPortParseDo(de_ctx, head, nhead, address, - negate? negate: n_set, var_list, recur); + r = DetectPortParseDo( + de_ctx, head, nhead, address, negate ? negate : n_set, var_list, recur); if (r == -1) goto error; @@ -895,13 +889,11 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, if (o_set == 1) { o_set = 0; } else if (d_set == 1) { - char *temp_rule_var_port = NULL, - *alloc_rule_var_port = NULL; + char *temp_rule_var_port = NULL, *alloc_rule_var_port = NULL; address[x - 1] = '\0'; - rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, - SC_RULE_VARS_PORT_GROUPS); + rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; if (strlen(rule_var_port) == 0) { @@ -916,16 +908,15 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, alloc_rule_var_port = SCMalloc(strlen(rule_var_port) + 3); if (unlikely(alloc_rule_var_port == NULL)) goto error; - snprintf(alloc_rule_var_port, strlen(rule_var_port) + 3, - "[%s]", rule_var_port); + snprintf(alloc_rule_var_port, strlen(rule_var_port) + 3, "[%s]", rule_var_port); } else { alloc_rule_var_port = SCStrdup(rule_var_port); if (unlikely(alloc_rule_var_port == NULL)) goto error; } temp_rule_var_port = alloc_rule_var_port; - r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, - (negate + n_set) % 2, var_list, recur); + r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, (negate + n_set) % 2, + var_list, recur); if (r == -1) { SCFree(alloc_rule_var_port); goto error; @@ -951,7 +942,7 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, range = 0; } else if (depth == 0 && s[u] == '$') { d_set = 1; - } else if (depth == 0 && u == size-1) { + } else if (depth == 0 && u == size - 1) { range = 0; if (x == 1024) { address[x - 1] = '\0'; @@ -968,11 +959,9 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, x = 0; if (d_set == 1) { - char *temp_rule_var_port = NULL, - *alloc_rule_var_port = NULL; + char *temp_rule_var_port = NULL, *alloc_rule_var_port = NULL; - rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, - SC_RULE_VARS_PORT_GROUPS); + rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; if (strlen(rule_var_port) == 0) { @@ -987,16 +976,15 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, alloc_rule_var_port = SCMalloc(strlen(rule_var_port) + 3); if (unlikely(alloc_rule_var_port == NULL)) goto error; - snprintf(alloc_rule_var_port, strlen(rule_var_port) + 3, - "[%s]", rule_var_port); + snprintf(alloc_rule_var_port, strlen(rule_var_port) + 3, "[%s]", rule_var_port); } else { alloc_rule_var_port = SCStrdup(rule_var_port); if (unlikely(alloc_rule_var_port == NULL)) goto error; } temp_rule_var_port = alloc_rule_var_port; - r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, - (negate + n_set) % 2, var_list, recur); + r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, (negate + n_set) % 2, + var_list, recur); SCFree(alloc_rule_var_port); if (r == -1) goto error; @@ -1004,9 +992,9 @@ static int DetectPortParseDo(const DetectEngineCtx *de_ctx, d_set = 0; } else { if (!((negate + n_set) % 2)) { - r = DetectPortParseInsertString(de_ctx, head,address); + r = DetectPortParseInsertString(de_ctx, head, address); } else { - r = DetectPortParseInsertString(de_ctx, nhead,address); + r = DetectPortParseInsertString(de_ctx, nhead, address); } if (r == -1) goto error; @@ -1059,7 +1047,7 @@ static int DetectPortIsCompletePortSpace(DetectPort *p) next_port = p->port2 + 1; p = p->next; - for ( ; p != NULL; p = p->next) { + for (; p != NULL; p = p->next) { if (p->port != next_port) return 0; @@ -1081,8 +1069,8 @@ static int DetectPortIsCompletePortSpace(DetectPort *p) * \retval 0 on success * \retval -1 on error */ -static int DetectPortParseMergeNotPorts(const DetectEngineCtx *de_ctx, - DetectPort **head, DetectPort **nhead) +static int DetectPortParseMergeNotPorts( + const DetectEngineCtx *de_ctx, DetectPort **head, DetectPort **nhead) { DetectPort *ad = NULL; DetectPort *ag, *ag2; @@ -1101,7 +1089,7 @@ static int DetectPortParseMergeNotPorts(const DetectEngineCtx *de_ctx, */ if (*head == NULL && *nhead != NULL) { SCLogDebug("inserting 0:65535 into head"); - r = DetectPortParseInsertString(de_ctx, head,"0:65535"); + r = DetectPortParseInsertString(de_ctx, head, "0:65535"); if (r < 0) { goto error; } @@ -1128,7 +1116,7 @@ static int DetectPortParseMergeNotPorts(const DetectEngineCtx *de_ctx, SCLogDebug("ag %p", ag); DetectPortPrint(ag); - for (ag2 = *head; ag2 != NULL; ) { + for (ag2 = *head; ag2 != NULL;) { SCLogDebug("ag2 %p", ag2); DetectPortPrint(ag2); @@ -1142,7 +1130,7 @@ static int DetectPortParseMergeNotPorts(const DetectEngineCtx *de_ctx, *head = ag2->next; /** store the next ptr and remove the group */ DetectPort *next_ag2 = ag2->next; - DetectPortFree(de_ctx,ag2); + DetectPortFree(de_ctx, ag2); ag2 = next_ag2; } else { ag2 = ag2->next; @@ -1179,10 +1167,10 @@ int DetectPortTestConfVars(void) } ConfNode *seq_node; - TAILQ_FOREACH(seq_node, &port_vars_node->head, next) { + TAILQ_FOREACH (seq_node, &port_vars_node->head, next) { SCLogDebug("Testing %s - %s\n", seq_node->name, seq_node->val); - DetectPort *gh = DetectPortInit(); + DetectPort *gh = DetectPortInit(); if (gh == NULL) { goto error; } @@ -1198,7 +1186,7 @@ int DetectPortTestConfVars(void) } int r = DetectPortParseDo(NULL, &gh, &ghn, seq_node->val, - /* start with negate no */0, &var_list, 0); + /* start with negate no */ 0, &var_list, 0); CleanVariableResolveList(&var_list); @@ -1228,11 +1216,10 @@ int DetectPortTestConfVars(void) } return 0; - error: +error: return -1; } - /** * \brief Function for parsing port strings * @@ -1243,8 +1230,7 @@ int DetectPortTestConfVars(void) * \retval 0 on success * \retval -1 on error */ -int DetectPortParse(const DetectEngineCtx *de_ctx, - DetectPort **head, const char *str) +int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str) { SCLogDebug("Port string to be parsed - str %s", str); @@ -1328,7 +1314,7 @@ DetectPort *PortParse(const char *str) if (dp->port > dp->port2) goto error; } else { - if (strcasecmp(port,"any") == 0) { + if (strcasecmp(port, "any") == 0) { dp->port = 0; dp->port2 = 65535; } else { @@ -1386,7 +1372,7 @@ static uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datal uint32_t hash = ((uint32_t)p->port << 16) | p->port2; hash %= ht->array_size; - SCLogDebug("hash %"PRIu32, hash); + SCLogDebug("hash %" PRIu32, hash); return hash; } @@ -1402,8 +1388,7 @@ static uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datal * \retval 1 If the 2 DetectPort sent as args match. * \retval 0 If the 2 DetectPort sent as args do not match. */ -static char DetectPortCompareFunc(void *data1, uint16_t len1, - void *data2, uint16_t len2) +static char DetectPortCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { DetectPort *dp1 = (DetectPort *)data1; DetectPort *dp2 = (DetectPort *)data2; @@ -1434,9 +1419,8 @@ static void DetectPortHashFreeFunc(void *ptr) */ int DetectPortHashInit(DetectEngineCtx *de_ctx) { - de_ctx->dport_hash_table = HashListTableInit(4096, DetectPortHashFunc, - DetectPortCompareFunc, - DetectPortHashFreeFunc); + de_ctx->dport_hash_table = HashListTableInit( + 4096, DetectPortHashFunc, DetectPortCompareFunc, DetectPortHashFreeFunc); if (de_ctx->dport_hash_table == NULL) return -1; @@ -1513,12 +1497,12 @@ static int PortTestDetectPortAdd(DetectPort **head, DetectPort *dp) { DetectPort *cur, *prev_cur = NULL; - //SCLogDebug("DetectPortAdd: adding "); DetectPortPrint(ag); SCLogDebug(""); + // SCLogDebug("DetectPortAdd: adding "); DetectPortPrint(ag); SCLogDebug(""); if (*head != NULL) { for (cur = *head; cur != NULL; cur = cur->next) { prev_cur = cur; - int r = DetectPortCmp(dp,cur); + int r = DetectPortCmp(dp, cur); if (r == PORT_EB) { /* insert here */ dp->prev = cur->prev; @@ -1543,14 +1527,13 @@ static int PortTestDetectPortAdd(DetectPort **head, DetectPort *dp) return 0; } - /** * \test Check if a DetectPort is properly allocated */ -static int PortTestParse01 (void) +static int PortTestParse01(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"80"); + int r = DetectPortParse(NULL, &dd, "80"); FAIL_IF_NOT(r == 0); DetectPortFree(NULL, dd); PASS; @@ -1559,12 +1542,12 @@ static int PortTestParse01 (void) /** * \test Check if two ports are properly allocated in the DetectPort group */ -static int PortTestParse02 (void) +static int PortTestParse02(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"80"); + int r = DetectPortParse(NULL, &dd, "80"); FAIL_IF_NOT(r == 0); - r = DetectPortParse(NULL,&dd,"22"); + r = DetectPortParse(NULL, &dd, "22"); FAIL_IF_NOT(r == 0); DetectPortCleanupList(NULL, dd); PASS; @@ -1573,12 +1556,12 @@ static int PortTestParse02 (void) /** * \test Check if two port ranges are properly allocated in the DetectPort group */ -static int PortTestParse03 (void) +static int PortTestParse03(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"80:88"); + int r = DetectPortParse(NULL, &dd, "80:88"); FAIL_IF_NOT(r == 0); - r = DetectPortParse(NULL,&dd,"85:100"); + r = DetectPortParse(NULL, &dd, "85:100"); FAIL_IF_NOT(r == 0); DetectPortCleanupList(NULL, dd); PASS; @@ -1587,10 +1570,10 @@ static int PortTestParse03 (void) /** * \test Check if a negated port range is properly allocated in the DetectPort */ -static int PortTestParse04 (void) +static int PortTestParse04(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"!80:81"); + int r = DetectPortParse(NULL, &dd, "!80:81"); FAIL_IF_NOT(r == 0); DetectPortCleanupList(NULL, dd); PASS; @@ -1600,10 +1583,10 @@ static int PortTestParse04 (void) * \test Check if a negated port range is properly fragmented in the allowed * real groups, ex !80:81 should allow 0:79 and 82:65535 */ -static int PortTestParse05 (void) +static int PortTestParse05(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"!80:81"); + int r = DetectPortParse(NULL, &dd, "!80:81"); FAIL_IF_NOT(r == 0); FAIL_IF_NULL(dd->next); FAIL_IF_NOT(dd->port == 0); @@ -1618,11 +1601,11 @@ static int PortTestParse05 (void) * \test Check if a negated port range is properly fragmented in the allowed * real groups */ -static int PortTestParse07 (void) +static int PortTestParse07(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"!21:902"); + int r = DetectPortParse(NULL, &dd, "!21:902"); FAIL_IF_NOT(r == 0); FAIL_IF_NULL(dd->next); @@ -1638,11 +1621,11 @@ static int PortTestParse07 (void) /** * \test Check if we dont allow invalid port range specification */ -static int PortTestParse08 (void) +static int PortTestParse08(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"[80:!80]"); + int r = DetectPortParse(NULL, &dd, "[80:!80]"); FAIL_IF(r == 0); DetectPortCleanupList(NULL, dd); @@ -1652,11 +1635,11 @@ static int PortTestParse08 (void) /** * \test Check if we autocomplete correctly an open range */ -static int PortTestParse09 (void) +static int PortTestParse09(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"1024:"); + int r = DetectPortParse(NULL, &dd, "1024:"); FAIL_IF_NOT(r == 0); FAIL_IF_NULL(dd); @@ -1670,10 +1653,10 @@ static int PortTestParse09 (void) /** * \test Test we don't allow a port that is too big */ -static int PortTestParse10 (void) +static int PortTestParse10(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"77777777777777777777777777777777777777777777"); + int r = DetectPortParse(NULL, &dd, "77777777777777777777777777777777777777777777"); FAIL_IF(r == 0); PASS; } @@ -1681,11 +1664,11 @@ static int PortTestParse10 (void) /** * \test Test second port of range being too big */ -static int PortTestParse11 (void) +static int PortTestParse11(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"1024:65536"); + int r = DetectPortParse(NULL, &dd, "1024:65536"); FAIL_IF(r == 0); PASS; } @@ -1693,10 +1676,10 @@ static int PortTestParse11 (void) /** * \test Test second port of range being just right */ -static int PortTestParse12 (void) +static int PortTestParse12(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"1024:65535"); + int r = DetectPortParse(NULL, &dd, "1024:65535"); FAIL_IF_NOT(r == 0); DetectPortFree(NULL, dd); PASS; @@ -1705,10 +1688,10 @@ static int PortTestParse12 (void) /** * \test Test first port of range being too big */ -static int PortTestParse13 (void) +static int PortTestParse13(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"65536:65535"); + int r = DetectPortParse(NULL, &dd, "65536:65535"); FAIL_IF(r == 0); PASS; } @@ -1716,7 +1699,7 @@ static int PortTestParse13 (void) /** * \test Test merging port groups */ -static int PortTestParse14 (void) +static int PortTestParse14(void) { DetectPort *dd = NULL; @@ -1738,11 +1721,11 @@ static int PortTestParse14 (void) /** * \test Test merging negated port groups */ -static int PortTestParse15 (void) +static int PortTestParse15(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"![0:100,1000:3000]"); + int r = DetectPortParse(NULL, &dd, "![0:100,1000:3000]"); FAIL_IF_NOT(r == 0); FAIL_IF_NULL(dd->next); @@ -1755,10 +1738,10 @@ static int PortTestParse15 (void) PASS; } -static int PortTestParse16 (void) +static int PortTestParse16(void) { DetectPort *dd = NULL; - int r = DetectPortParse(NULL,&dd,"\ + int r = DetectPortParse(NULL, &dd, "\ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\ 1:65535\ ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\ @@ -1766,7 +1749,7 @@ static int PortTestParse16 (void) FAIL_IF_NOT(r == 0); DetectPortFree(NULL, dd); dd = NULL; - r = DetectPortParse(NULL,&dd,"\ + r = DetectPortParse(NULL, &dd, "\ [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\ 1:65535\ ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\ @@ -1781,11 +1764,11 @@ static int PortTestParse16 (void) static int PortTestFunctions01(void) { DetectPort *head = NULL; - DetectPort *dp1= NULL; + DetectPort *dp1 = NULL; int result = 0; /* Parse */ - int r = DetectPortParse(NULL,&head,"![0:100,1000:65535]"); + int r = DetectPortParse(NULL, &head, "![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; @@ -1797,7 +1780,7 @@ static int PortTestFunctions01(void) if (!(head->next == NULL)) goto end; - r = DetectPortParse(NULL, &dp1,"2000:3000"); + r = DetectPortParse(NULL, &dp1, "2000:3000"); if (r != 0 || dp1->next != NULL) goto end; if (!(dp1->port == 2000)) @@ -1843,12 +1826,12 @@ static int PortTestFunctions01(void) static int PortTestFunctions02(void) { DetectPort *head = NULL; - DetectPort *dp1= NULL; - DetectPort *dp2= NULL; + DetectPort *dp1 = NULL; + DetectPort *dp2 = NULL; int result = 0; /* Parse */ - int r = DetectPortParse(NULL,&head, "![0:100,1000:65535]"); + int r = DetectPortParse(NULL, &head, "![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; @@ -1892,9 +1875,9 @@ static int PortTestFunctions02(void) */ static int PortTestFunctions03(void) { - DetectPort *dp1= NULL; - DetectPort *dp2= NULL; - DetectPort *dp3= NULL; + DetectPort *dp1 = NULL; + DetectPort *dp2 = NULL; + DetectPort *dp3 = NULL; int result = 0; int r = DetectPortParse(NULL, &dp1, "200:300"); @@ -1958,8 +1941,8 @@ static int PortTestFunctions03(void) */ static int PortTestFunctions04(void) { - DetectPort *dp1= NULL; - DetectPort *dp2= NULL; + DetectPort *dp1 = NULL; + DetectPort *dp2 = NULL; int result = 0; int r = DetectPortParse(NULL, &dp1, "200:300"); @@ -2004,7 +1987,7 @@ static int PortTestFunctions05(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; - memset(s,0x00,sizeof(s)); + memset(s, 0x00, sizeof(s)); s[0].num = 0; s[1].num = 1; @@ -2036,9 +2019,9 @@ static int PortTestFunctions05(void) SCLogDebug("dp3"); DetectPort *x = dp3; - for ( ; x != NULL; x = x->next) { + for (; x != NULL; x = x->next) { DetectPortPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); + // SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectPort *one = dp3; @@ -2082,7 +2065,7 @@ static int PortTestFunctions06(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); Signature s[2]; - memset(s,0x00,sizeof(s)); + memset(s, 0x00, sizeof(s)); s[0].num = 0; s[1].num = 1; @@ -2114,9 +2097,9 @@ static int PortTestFunctions06(void) SCLogDebug("dp3"); DetectPort *x = dp3; - for ( ; x != NULL; x = x->next) { + for (; x != NULL; x = x->next) { DetectPortPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); + // SigGroupHeadPrintSigs(de_ctx, x->sh); } DetectPort *one = dp3; @@ -2184,8 +2167,7 @@ static int PortTestFunctions07(void) * \retval return 1 if match * \retval return 0 if not */ -static int PortTestMatchReal(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig, - uint32_t sid) +static int PortTestMatchReal(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig, uint32_t sid) { int result = 0; FlowInitConfig(FLOW_QUIET); @@ -2205,6 +2187,7 @@ static int PortTestMatchRealWrp(const char *sig, uint32_t sid) * tcp.sport=47370 tcp.dport=80 * ip.src=192.168.28.131 ip.dst=192.168.1.1 */ + // clang-format off uint8_t raw_eth_pkt[] = { 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, @@ -2261,10 +2244,10 @@ static int PortTestMatchRealWrp(const char *sig, uint32_t sid) 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; - /* end raw_eth_pkt */ + // clang-format on + /* end raw_eth_pkt */ - return PortTestMatchReal(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), - sig, sid); + return PortTestMatchReal(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), sig, sid); } /** @@ -2283,7 +2266,7 @@ static int PortTestMatchReal01(void) static int PortTestMatchReal02(void) { const char *sig = "alert tcp any 47370 -> any any (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2293,7 +2276,7 @@ static int PortTestMatchReal02(void) static int PortTestMatchReal03(void) { const char *sig = "alert tcp any 47370 -> any 80 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2303,8 +2286,8 @@ static int PortTestMatchReal03(void) static int PortTestMatchReal04(void) { const char *sig = "alert tcp any any -> any !80 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + " content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2313,8 +2296,8 @@ static int PortTestMatchReal04(void) static int PortTestMatchReal05(void) { const char *sig = "alert tcp any !47370 -> any any (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + " content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2323,8 +2306,8 @@ static int PortTestMatchReal05(void) static int PortTestMatchReal06(void) { const char *sig = "alert tcp any !47370 -> any !80 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + " content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2333,7 +2316,7 @@ static int PortTestMatchReal06(void) static int PortTestMatchReal07(void) { const char *sig = "alert tcp any any -> any 70:100 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2343,7 +2326,7 @@ static int PortTestMatchReal07(void) static int PortTestMatchReal08(void) { const char *sig = "alert tcp any 47000:50000 -> any any (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2353,7 +2336,7 @@ static int PortTestMatchReal08(void) static int PortTestMatchReal09(void) { const char *sig = "alert tcp any 47000:50000 -> any 70:100 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2363,8 +2346,8 @@ static int PortTestMatchReal09(void) static int PortTestMatchReal10(void) { const char *sig = "alert tcp any any -> any !70:100 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + " content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2373,8 +2356,8 @@ static int PortTestMatchReal10(void) static int PortTestMatchReal11(void) { const char *sig = "alert tcp any !47000:50000 -> any any (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + " content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2383,8 +2366,8 @@ static int PortTestMatchReal11(void) static int PortTestMatchReal12(void) { const char *sig = "alert tcp any !47000:50000 -> any !70:100 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + " content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2393,7 +2376,7 @@ static int PortTestMatchReal12(void) static int PortTestMatchReal13(void) { const char *sig = "alert tcp any 47000:50000 -> any !81: (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2403,7 +2386,7 @@ static int PortTestMatchReal13(void) static int PortTestMatchReal14(void) { const char *sig = "alert tcp any !48000:50000 -> any :100 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2413,8 +2396,8 @@ static int PortTestMatchReal14(void) static int PortTestMatchReal15(void) { const char *sig = "alert tcp any :50000 -> any 81:100 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + " content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2423,7 +2406,7 @@ static int PortTestMatchReal15(void) static int PortTestMatchReal16(void) { const char *sig = "alert tcp any 100: -> any ![0:79,81:65535] (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2433,8 +2416,8 @@ static int PortTestMatchReal16(void) static int PortTestMatchReal17(void) { const char *sig = "alert tcp any ![0:39999,48000:50000] -> any ![0:80,82:65535] " - "(msg:\"Nothing..\"; content:\"GET\"; sid:1;)"; - return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0; + "(msg:\"Nothing..\"; content:\"GET\"; sid:1;)"; + return (PortTestMatchRealWrp(sig, 1) == 0) ? 1 : 0; } /** @@ -2443,7 +2426,7 @@ static int PortTestMatchReal17(void) static int PortTestMatchReal18(void) { const char *sig = "alert tcp any ![0:39999,48000:50000] -> any 80 (msg:\"Nothing" - " at all\"; content:\"GET\"; sid:1;)"; + " at all\"; content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2453,7 +2436,7 @@ static int PortTestMatchReal18(void) static int PortTestMatchReal19(void) { const char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\";" - " content:\"GET\"; sid:1;)"; + " content:\"GET\"; sid:1;)"; return PortTestMatchRealWrp(sig, 1); } @@ -2597,4 +2580,3 @@ void DetectPortTests(void) } #endif /* UNITTESTS */ - diff --git a/src/detect-engine-port.h b/src/detect-engine-port.h index d27dff3d307f..82b621d2f18d 100644 --- a/src/detect-engine-port.h +++ b/src/detect-engine-port.h @@ -28,8 +28,8 @@ int DetectPortParse(const DetectEngineCtx *, DetectPort **head, const char *str); DetectPort *DetectPortCopySingle(DetectEngineCtx *, DetectPort *); -int DetectPortInsert(DetectEngineCtx *,DetectPort **, DetectPort *); -void DetectPortCleanupList (const DetectEngineCtx *de_ctx, DetectPort *head); +int DetectPortInsert(DetectEngineCtx *, DetectPort **, DetectPort *); +void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head); DetectPort *DetectPortLookupGroup(DetectPort *dp, uint16_t port); @@ -52,4 +52,3 @@ void DetectPortTests(void); #endif #endif /* __DETECT_PORT_H__ */ - diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c index 15df839b0c94..269c9af0509e 100644 --- a/src/detect-engine-prefilter-common.c +++ b/src/detect-engine-prefilter-common.c @@ -22,7 +22,7 @@ typedef struct PrefilterPacketHeaderHashCtx_ { PrefilterPacketHeaderValue v1; - uint16_t type; /**< PREFILTER_EXTRA_MATCH_* */ + uint16_t type; /**< PREFILTER_EXTRA_MATCH_* */ uint16_t value; uint32_t cnt; @@ -36,15 +36,12 @@ static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uin return hash; } -static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1, - void *data2, uint16_t len2) +static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { PrefilterPacketHeaderHashCtx *ctx1 = data1; PrefilterPacketHeaderHashCtx *ctx2 = data2; - return (ctx1->v1.u64[0] == ctx2->v1.u64[0] && - ctx1->v1.u64[1] == ctx2->v1.u64[1] && - ctx1->type == ctx2->type && - ctx1->value == ctx2->value); + return (ctx1->v1.u64[0] == ctx2->v1.u64[0] && ctx1->v1.u64[1] == ctx2->v1.u64[1] && + ctx1->type == ctx2->type && ctx1->value == ctx2->value); } static void PrefilterPacketHeaderFreeFunc(void *ptr) @@ -76,16 +73,14 @@ static void PrefilterPacketU8HashCtxFree(void *vctx) static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value) { if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 && - !(s->sp->flags & PORT_FLAG_NOT)) - { + !(s->sp->flags & PORT_FLAG_NOT)) { *type = PREFILTER_EXTRA_MATCH_SRCPORT; *value = s->sp->port; } else if (s->alproto != ALPROTO_UNKNOWN) { *type = PREFILTER_EXTRA_MATCH_ALPROTO; *value = s->alproto; } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 && - !(s->dp->flags & PORT_FLAG_NOT)) - { + !(s->dp->flags & PORT_FLAG_NOT)) { *type = PREFILTER_EXTRA_MATCH_DSTPORT; *value = s->dp->port; } @@ -93,10 +88,8 @@ static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value) /** \internal */ -static int -SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - int sm_type, PrefilterPacketHeaderHashCtx *hctx, - bool (*Compare)(PrefilterPacketHeaderValue v, void *), +static int SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, + PrefilterPacketHeaderHashCtx *hctx, bool (*Compare)(PrefilterPacketHeaderValue v, void *), void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { Signature *s = NULL; @@ -129,9 +122,8 @@ SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint16_t value = 0; GetExtraMatch(s, &type, &value); - if (Compare(ctx->v1, s->init_data->prefilter_sm->ctx) && - ctx->type == type && ctx->value == value) - { + if (Compare(ctx->v1, s->init_data->prefilter_sm->ctx) && ctx->type == type && + ctx->value == value) { SCLogDebug("appending sid %u on %u", s->id, sig_offset); ctx->sigs_array[sig_offset] = s->num; sig_offset++; @@ -140,11 +132,10 @@ SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, } } - SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u", - sigmatch_table[sm_type].name, ctx, ctx->type, ctx->value, - ctx->sigs_cnt); - PrefilterAppendEngine(de_ctx, sgh, Match, ctx, - PrefilterPacketHeaderFree, sigmatch_table[sm_type].name); + SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u", sigmatch_table[sm_type].name, + ctx, ctx->type, ctx->value, ctx->sigs_cnt); + PrefilterAppendEngine( + de_ctx, sgh, Match, ctx, PrefilterPacketHeaderFree, sigmatch_table[sm_type].name); return 0; } @@ -153,42 +144,38 @@ SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderValue v, Signature *s) { switch (v.u8[0]) { - case PREFILTER_U8HASH_MODE_EQ: - { - SigsArray *sa = ctx->array[v.u8[1]]; + case PREFILTER_U8HASH_MODE_EQ: { + SigsArray *sa = ctx->array[v.u8[1]]; + sa->sigs[sa->offset++] = s->num; + break; + } + case PREFILTER_U8HASH_MODE_LT: { + uint8_t x = v.u8[1] - 1; + do { + SigsArray *sa = ctx->array[x]; sa->sigs[sa->offset++] = s->num; - break; - } - case PREFILTER_U8HASH_MODE_LT: - { - uint8_t x = v.u8[1] - 1; - do { - SigsArray *sa = ctx->array[x]; - sa->sigs[sa->offset++] = s->num; - } while (x--); + } while (x--); - break; - } - case PREFILTER_U8HASH_MODE_GT: - { - int x = v.u8[1] + 1; - do { - SigsArray *sa = ctx->array[x]; - sa->sigs[sa->offset++] = s->num; - } while (++x < 256); + break; + } + case PREFILTER_U8HASH_MODE_GT: { + int x = v.u8[1] + 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (++x < 256); - break; - } - case PREFILTER_U8HASH_MODE_RA: - { - int x = v.u8[1] + 1; - do { - SigsArray *sa = ctx->array[x]; - sa->sigs[sa->offset++] = s->num; - } while (++x < v.u8[2]); + break; + } + case PREFILTER_U8HASH_MODE_RA: { + int x = v.u8[1] + 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (++x < v.u8[2]); - break; - } + break; + } } } @@ -197,8 +184,7 @@ static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderVa * \todo improve error handling * \todo deduplicate sigs arrays */ -static int -SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx, +static int SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, uint32_t *counts, void (*Set)(PrefilterPacketHeaderValue *v, void *), bool (*Compare)(PrefilterPacketHeaderValue v, void *), @@ -247,8 +233,7 @@ SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx, } if (cnt) { - PrefilterAppendEngine(de_ctx, sgh, Match, ctx, - PrefilterPacketU8HashCtxFree, + PrefilterAppendEngine(de_ctx, sgh, Match, ctx, PrefilterPacketU8HashCtxFree, sigmatch_table[sm_type].name); } else { PrefilterPacketU8HashCtxFree(ctx); @@ -259,44 +244,38 @@ SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx, /** \internal * \brief setup a engine for each unique value */ -static void SetupSingle(DetectEngineCtx *de_ctx, HashListTable *hash_table, - SigGroupHead *sgh, int sm_type, - bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx)) +static void SetupSingle(DetectEngineCtx *de_ctx, HashListTable *hash_table, SigGroupHead *sgh, + int sm_type, bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { HashListTableBucket *hb = HashListTableGetListHead(hash_table); - for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + for (; hb != NULL; hb = HashListTableGetListNext(hb)) { PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); - SetupEngineForPacketHeader(de_ctx, sgh, sm_type, - ctx, Compare, Match); + SetupEngineForPacketHeader(de_ctx, sgh, sm_type, ctx, Compare, Match); } } /** \internal * \brief setup a single engine with a hash map for u8 values */ -static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table, - SigGroupHead *sgh, int sm_type, - void (*Set)(PrefilterPacketHeaderValue *v, void *), +static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table, SigGroupHead *sgh, + int sm_type, void (*Set)(PrefilterPacketHeaderValue *v, void *), bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx)) + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { uint32_t counts[256]; memset(&counts, 0, sizeof(counts)); HashListTableBucket *hb = HashListTableGetListHead(hash_table); - for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + for (; hb != NULL; hb = HashListTableGetListNext(hb)) { PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); switch (ctx->v1.u8[0]) { case PREFILTER_U8HASH_MODE_EQ: counts[ctx->v1.u8[1]] += ctx->cnt; break; - case PREFILTER_U8HASH_MODE_LT: - { + case PREFILTER_U8HASH_MODE_LT: { uint8_t v = ctx->v1.u8[1]; while (v > 0) { v--; @@ -305,8 +284,7 @@ static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table, break; } - case PREFILTER_U8HASH_MODE_GT: - { + case PREFILTER_U8HASH_MODE_GT: { uint8_t v = ctx->v1.u8[1]; while (v < UINT8_MAX) { v++; @@ -315,8 +293,7 @@ static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table, break; } - case PREFILTER_U8HASH_MODE_RA: - { + case PREFILTER_U8HASH_MODE_RA: { if (ctx->v1.u8[1] < ctx->v1.u8[2]) { // ctx->v1.u8[1] is not UINT8_MAX uint8_t v = ctx->v1.u8[1] + 1; @@ -330,17 +307,14 @@ static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table, } } - SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(de_ctx, sgh, sm_type, - counts, Set, Compare, Match); + SetupEngineForPacketHeaderPrefilterPacketU8HashCtx( + de_ctx, sgh, sm_type, counts, Set, Compare, Match); } -static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, int sm_type, +static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void (*Set)(PrefilterPacketHeaderValue *v, void *), bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx), - bool u8hash) + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), bool u8hash) { Signature *s = NULL; uint32_t sig = 0; @@ -350,10 +324,8 @@ static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx, /* first count how many engines we will need */ - HashListTable *hash_table = HashListTableInit(4096, - PrefilterPacketHeaderHashFunc, - PrefilterPacketHeaderCompareFunc, - PrefilterPacketHeaderFreeFunc); + HashListTable *hash_table = HashListTableInit(4096, PrefilterPacketHeaderHashFunc, + PrefilterPacketHeaderCompareFunc, PrefilterPacketHeaderFreeFunc); if (hash_table == NULL) return -1; @@ -404,22 +376,18 @@ static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx, return -1; } -int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, int sm_type, +int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void (*Set)(PrefilterPacketHeaderValue *v, void *), bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx)) + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, Set, Compare, Match, true); } -int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, int sm_type, +int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void (*Set)(PrefilterPacketHeaderValue *v, void *), bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx)) + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, Set, Compare, Match, false); } diff --git a/src/detect-engine-prefilter-common.h b/src/detect-engine-prefilter-common.h index f5ea76521527..31302f80ad4d 100644 --- a/src/detect-engine-prefilter-common.h +++ b/src/detect-engine-prefilter-common.h @@ -58,26 +58,20 @@ typedef struct PrefilterPacketU8HashCtx_ { #define PREFILTER_U8HASH_MODE_GT DetectUintModeGt #define PREFILTER_U8HASH_MODE_RA DetectUintModeRange -int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, int sm_type, +int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void (*Set)(PrefilterPacketHeaderValue *v, void *), bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx)); + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)); -int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, int sm_type, +int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void (*Set)(PrefilterPacketHeaderValue *v, void *), bool (*Compare)(PrefilterPacketHeaderValue v, void *), - void (*Match)(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx)); + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)); -static inline bool -PrefilterPacketHeaderExtraMatch(const PrefilterPacketHeaderCtx *ctx, - const Packet *p) +static inline bool PrefilterPacketHeaderExtraMatch( + const PrefilterPacketHeaderCtx *ctx, const Packet *p) { - switch (ctx->type) - { + switch (ctx->type) { case PREFILTER_EXTRA_MATCH_UNUSED: break; case PREFILTER_EXTRA_MATCH_ALPROTO: @@ -99,7 +93,7 @@ PrefilterPacketHeaderExtraMatch(const PrefilterPacketHeaderCtx *ctx, static inline bool PrefilterIsPrefilterableById(const Signature *s, enum DetectKeywordId kid) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { if (sm->type == kid) { return true; } diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index e40a5175dafb..f536dca2675c 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -53,15 +53,14 @@ #include "detect-engine-frame.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/profiling.h" +#include "util/validate.h" -static int PrefilterStoreGetId(DetectEngineCtx *de_ctx, - const char *name, void (*FreeFunc)(void *)); -static const PrefilterStore *PrefilterStoreGetStore(const DetectEngineCtx *de_ctx, - const uint32_t id); +static int PrefilterStoreGetId(DetectEngineCtx *de_ctx, const char *name, void (*FreeFunc)(void *)); +static const PrefilterStore *PrefilterStoreGetStore( + const DetectEngineCtx *de_ctx, const uint32_t id); static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n) { @@ -90,13 +89,8 @@ static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n) /** * \brief run prefilter engines on a transaction */ -void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, - const SigGroupHead *sgh, - Packet *p, - const uint8_t ipproto, - const uint8_t flow_flags, - const AppProto alproto, - void *alstate, +void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, + const uint8_t ipproto, const uint8_t flow_flags, const AppProto alproto, void *alstate, DetectTransaction *tx) { /* reset rule store */ @@ -140,8 +134,8 @@ void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, } } -void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, - Packet *p, const uint8_t flags) +void Prefilter( + DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, const uint8_t flags) { SCEnter(); #if 0 @@ -171,10 +165,8 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, } /* run payload inspecting engines */ - if (sgh->payload_engines && - (p->payload_len || (p->flags & PKT_DETECT_HAS_STREAMDATA)) && - !(p->flags & PKT_NOPAYLOAD_INSPECTION)) - { + if (sgh->payload_engines && (p->payload_len || (p->flags & PKT_DETECT_HAS_STREAMDATA)) && + !(p->flags & PKT_NOPAYLOAD_INSPECTION)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD); PrefilterEngine *engine = sgh->payload_engines; while (1) { @@ -201,8 +193,7 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), - void *pectx, void (*FreeFunc)(void *pectx), - const char *name) + void *pectx, void (*FreeFunc)(void *pectx), const char *name) { if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL) return -1; @@ -235,8 +226,7 @@ int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), - void *pectx, void (*FreeFunc)(void *pectx), - const char *name) + void *pectx, void (*FreeFunc)(void *pectx), const char *name) { if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL) return -1; @@ -421,12 +411,9 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) * all engines, otherwise only those that have been forced by the * prefilter keyword. */ const enum DetectEnginePrefilterSetting setting = de_ctx->prefilter_setting; - for (int i = 0; i < DETECT_TBLSIZE; i++) - { + for (int i = 0; i < DETECT_TBLSIZE; i++) { if (sigmatch_table[i].SetupPrefilter != NULL && - (setting == DETECT_PREFILTER_AUTO || - de_ctx->sm_types_prefilter[i])) - { + (setting == DETECT_PREFILTER_AUTO || de_ctx->sm_types_prefilter[i])) { sigmatch_table[i].SetupPrefilter(de_ctx, sgh); } } @@ -436,7 +423,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) PrefilterEngineList *el; if (sgh->init->pkt_engines != NULL) { uint32_t cnt = 0; - for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) { + for (el = sgh->init->pkt_engines; el != NULL; el = el->next) { cnt++; } sgh->pkt_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); @@ -446,7 +433,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) memset(sgh->pkt_engines, 0x00, (cnt * sizeof(PrefilterEngine))); PrefilterEngine *e = sgh->pkt_engines; - for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) { + for (el = sgh->init->pkt_engines; el != NULL; el = el->next) { e->local_id = el->id; e->cb.Prefilter = el->Prefilter; e->pectx = el->pectx; @@ -460,7 +447,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } if (sgh->init->payload_engines != NULL) { uint32_t cnt = 0; - for (el = sgh->init->payload_engines ; el != NULL; el = el->next) { + for (el = sgh->init->payload_engines; el != NULL; el = el->next) { cnt++; } sgh->payload_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); @@ -470,7 +457,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) memset(sgh->payload_engines, 0x00, (cnt * sizeof(PrefilterEngine))); PrefilterEngine *e = sgh->payload_engines; - for (el = sgh->init->payload_engines ; el != NULL; el = el->next) { + for (el = sgh->init->payload_engines; el != NULL; el = el->next) { e->local_id = el->id; e->cb.Prefilter = el->Prefilter; e->pectx = el->pectx; @@ -484,7 +471,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } if (sgh->init->tx_engines != NULL) { uint32_t cnt = 0; - for (el = sgh->init->tx_engines ; el != NULL; el = el->next) { + for (el = sgh->init->tx_engines; el != NULL; el = el->next) { cnt++; } sgh->tx_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); @@ -495,7 +482,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) uint16_t local_id = 0; PrefilterEngine *e = sgh->tx_engines; - for (el = sgh->init->tx_engines ; el != NULL; el = el->next) { + for (el = sgh->init->tx_engines; el != NULL; el = el->next) { e->local_id = local_id++; e->alproto = el->alproto; e->ctx.tx_min_progress = el->tx_min_progress; @@ -602,8 +589,7 @@ static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t d return hash; } -static char PrefilterStoreCompareFunc(void *data1, uint16_t len1, - void *data2, uint16_t len2) +static char PrefilterStoreCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { PrefilterStore *ctx1 = data1; PrefilterStore *ctx2 = data2; @@ -626,15 +612,12 @@ void PrefilterInit(DetectEngineCtx *de_ctx) { BUG_ON(de_ctx->prefilter_hash_table != NULL); - de_ctx->prefilter_hash_table = HashListTableInit(256, - PrefilterStoreHashFunc, - PrefilterStoreCompareFunc, - PrefilterStoreFreeFunc); + de_ctx->prefilter_hash_table = HashListTableInit( + 256, PrefilterStoreHashFunc, PrefilterStoreCompareFunc, PrefilterStoreFreeFunc); BUG_ON(de_ctx->prefilter_hash_table == NULL); } -static int PrefilterStoreGetId(DetectEngineCtx *de_ctx, - const char *name, void (*FreeFunc)(void *)) +static int PrefilterStoreGetId(DetectEngineCtx *de_ctx, const char *name, void (*FreeFunc)(void *)) { PrefilterStore ctx = { name, FreeFunc, 0 }; @@ -668,14 +651,14 @@ static int PrefilterStoreGetId(DetectEngineCtx *de_ctx, } /** \warning slow */ -static const PrefilterStore *PrefilterStoreGetStore(const DetectEngineCtx *de_ctx, - const uint32_t id) +static const PrefilterStore *PrefilterStoreGetStore( + const DetectEngineCtx *de_ctx, const uint32_t id) { const PrefilterStore *store = NULL; if (de_ctx->prefilter_hash_table != NULL) { HashListTableBucket *hb = HashListTableGetListHead(de_ctx->prefilter_hash_table); - for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + for (; hb != NULL; hb = HashListTableGetListNext(hb)) { PrefilterStore *ctx = HashListTableGetListData(hb); if (ctx->id == id) { store = ctx; @@ -693,7 +676,7 @@ const char *PrefilterStoreGetName(const uint32_t id) } #endif -#include "util-print.h" +#include "util/print.h" typedef struct PrefilterMpmCtx { int list_id; @@ -719,8 +702,7 @@ static void PrefilterMpm(DetectEngineThreadCtx *det_ctx, const void *pectx, Pack const MpmCtx *mpm_ctx = ctx->mpm_ctx; SCLogDebug("running on list %d", ctx->list_id); - InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms, - f, flags, txv, ctx->list_id); + InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms, f, flags, txv, ctx->list_id); if (buffer == NULL) return; @@ -728,7 +710,7 @@ static void PrefilterMpm(DetectEngineThreadCtx *det_ctx, const void *pectx, Pack const uint8_t *data = buffer->inspect; SCLogDebug("mpm'ing buffer:"); - //PrintRawDataFp(stdout, data, data_len); + // PrintRawDataFp(stdout, data, data_len); if (data != NULL && data_len >= mpm_ctx->minlen) { (void)mpm_table[mpm_ctx->mpm_type].Search( @@ -754,9 +736,8 @@ int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmC pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpm, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterGenericMpmFree, mpm_reg->pname); + int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpm, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterGenericMpmFree, mpm_reg->pname); if (r != 0) { SCFree(pectx); } @@ -780,8 +761,7 @@ typedef struct PrefilterMpmPktCtx { * \param txv tx to inspect * \param pectx inspection context */ -static void PrefilterMpmPkt(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx) +static void PrefilterMpmPkt(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { SCEnter(); @@ -789,8 +769,7 @@ static void PrefilterMpmPkt(DetectEngineThreadCtx *det_ctx, const MpmCtx *mpm_ctx = ctx->mpm_ctx; SCLogDebug("running on list %d", ctx->list_id); - InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms, - p, ctx->list_id); + InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms, p, ctx->list_id); if (buffer == NULL) return; @@ -798,7 +777,7 @@ static void PrefilterMpmPkt(DetectEngineThreadCtx *det_ctx, const uint8_t *data = buffer->inspect; SCLogDebug("mpm'ing buffer:"); - //PrintRawDataFp(stdout, data, data_len); + // PrintRawDataFp(stdout, data, data_len); if (data != NULL && data_len >= mpm_ctx->minlen) { (void)mpm_table[mpm_ctx->mpm_type].Search( @@ -824,8 +803,8 @@ int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, M pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - int r = PrefilterAppendEngine(de_ctx, sgh, PrefilterMpmPkt, - pectx, PrefilterMpmPktFree, mpm_reg->pname); + int r = PrefilterAppendEngine( + de_ctx, sgh, PrefilterMpmPkt, pectx, PrefilterMpmPktFree, mpm_reg->pname); if (r != 0) { SCFree(pectx); } diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h index 1f6143fd1545..2b06423dfaf3 100644 --- a/src/detect-engine-prefilter.h +++ b/src/detect-engine-prefilter.h @@ -47,17 +47,14 @@ typedef struct PrefilterStore_ { uint32_t id; } PrefilterStore; -void Prefilter(DetectEngineThreadCtx *, const SigGroupHead *, Packet *p, - const uint8_t flags); +void Prefilter(DetectEngineThreadCtx *, const SigGroupHead *, Packet *p, const uint8_t flags); int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), - void *pectx, void (*FreeFunc)(void *pectx), - const char *name); + void *pectx, void (*FreeFunc)(void *pectx), const char *name); int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), - void *pectx, void (*FreeFunc)(void *pectx), - const char *name); + void *pectx, void (*FreeFunc)(void *pectx), const char *name); int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterTxFn PrefilterTxFunc, const AppProto alproto, const int tx_min_progress, void *pectx, void (*FreeFunc)(void *pectx), const char *name); @@ -65,13 +62,8 @@ int PrefilterAppendFrameEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterFrameFn PrefilterFrameFunc, AppProto alproto, uint8_t frame_type, void *pectx, void (*FreeFunc)(void *pectx), const char *name); -void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, - const SigGroupHead *sgh, - Packet *p, - const uint8_t ipproto, - const uint8_t flow_flags, - const AppProto alproto, - void *alstate, +void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, Packet *p, + const uint8_t ipproto, const uint8_t flow_flags, const AppProto alproto, void *alstate, DetectTransaction *tx); void PrefilterFreeEnginesList(PrefilterEngineList *list); diff --git a/src/detect-engine-profile.c b/src/detect-engine-profile.c index 36cf6e106b05..fa270b38cf8d 100644 --- a/src/detect-engine-profile.c +++ b/src/detect-engine-profile.c @@ -26,8 +26,8 @@ #include "detect-engine-profile.h" #ifdef PROFILING -#include "output-json.h" -#include "util-conf.h" +#include "output/eve/output-json.h" +#include "util/conf.h" SCMutex g_rule_dump_write_m = SCMUTEX_INITIALIZER; @@ -76,8 +76,8 @@ void RulesDumpTxMatchArray(const DetectEngineThreadCtx *det_ctx, const SigGroupH jb_free(js); } -void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, - const SigGroupHead *sgh, const Packet *p) +void RulesDumpMatchArray( + const DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, const Packet *p) { JsonBuilder *js = CreateEveHeader(p, LOG_DIR_PACKET, "inspectedrules", NULL, NULL); if (js == NULL) @@ -99,7 +99,6 @@ void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, if (s == NULL) continue; jb_append_uint(js, s->id); - } jb_close(js); // close array jb_close(js); // close inspectedrules object diff --git a/src/detect-engine-profile.h b/src/detect-engine-profile.h index 2699a2435769..177e880d4c44 100644 --- a/src/detect-engine-profile.h +++ b/src/detect-engine-profile.h @@ -22,14 +22,14 @@ */ #ifndef _DETECT_ENGINE_PROFILE_H -#define _DETECT_ENGINE_PROFILE_H +#define _DETECT_ENGINE_PROFILE_H #include "detect.h" void RulesDumpTxMatchArray(const DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, const Packet *p, const uint64_t tx_id, const uint32_t rule_cnt, const uint32_t pkt_prefilter_cnt); -void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, - const SigGroupHead *sgh, const Packet *p); +void RulesDumpMatchArray( + const DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, const Packet *p); -#endif /* _DETECT_ENGINE_PROFILE_H */ +#endif /* _DETECT_ENGINE_PROFILE_H */ diff --git a/src/detect-engine-proto.c b/src/detect-engine-proto.c index 5ead3d8d93be..a6d8aab90df7 100644 --- a/src/detect-engine-proto.c +++ b/src/detect-engine-proto.c @@ -38,11 +38,11 @@ #include "detect-engine-siggroup.h" #include "detect-engine-state.h" -#include "util-cidr.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/cidr.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" /** * \brief Parses a protocol sent as a string. @@ -82,18 +82,15 @@ int DetectProtoParse(DetectProto *dp, const char *str) } else if (strcasecmp(str, "sctp") == 0) { dp->proto[IPPROTO_SCTP / 8] |= 1 << (IPPROTO_SCTP % 8); SCLogDebug("SCTP protocol detected"); - } else if (strcasecmp(str,"ipv4") == 0 || - strcasecmp(str,"ip4") == 0 ) { + } else if (strcasecmp(str, "ipv4") == 0 || strcasecmp(str, "ip4") == 0) { dp->flags |= (DETECT_PROTO_IPV4 | DETECT_PROTO_ANY); memset(dp->proto, 0xff, sizeof(dp->proto)); SCLogDebug("IPv4 protocol detected"); - } else if (strcasecmp(str,"ipv6") == 0 || - strcasecmp(str,"ip6") == 0 ) { + } else if (strcasecmp(str, "ipv6") == 0 || strcasecmp(str, "ip6") == 0) { dp->flags |= (DETECT_PROTO_IPV6 | DETECT_PROTO_ANY); memset(dp->proto, 0xff, sizeof(dp->proto)); SCLogDebug("IPv6 protocol detected"); - } else if (strcasecmp(str,"ip") == 0 || - strcasecmp(str,"pkthdr") == 0) { + } else if (strcasecmp(str, "ip") == 0 || strcasecmp(str, "pkthdr") == 0) { /* Proto "ip" is treated as an "any" */ dp->flags |= DETECT_PROTO_ANY; memset(dp->proto, 0xff, sizeof(dp->proto)); @@ -137,7 +134,7 @@ int DetectProtoContainsProto(const DetectProto *dp, int proto) if (dp->flags & DETECT_PROTO_ANY) return 1; - if (dp->proto[proto / 8] & (1<<(proto % 8))) + if (dp->proto[proto / 8] & (1 << (proto % 8))) return 1; return 0; @@ -153,8 +150,8 @@ int DetectProtoContainsProto(const DetectProto *dp, int proto) * \brief this function is used to initialize the detection engine context and * setup the signature with passed values. */ -static int DetectProtoInitTest(DetectEngineCtx **de_ctx, Signature **sig, - DetectProto *dp, const char *str) +static int DetectProtoInitTest( + DetectEngineCtx **de_ctx, Signature **sig, DetectProto *dp, const char *str) { char fullstr[1024]; int result = 0; @@ -162,9 +159,10 @@ static int DetectProtoInitTest(DetectEngineCtx **de_ctx, Signature **sig, *de_ctx = NULL; *sig = NULL; - if (snprintf(fullstr, 1024, "alert %s any any -> any any (msg:\"DetectProto" - " test\"; sid:1;)", str) >= 1024) - { + if (snprintf(fullstr, 1024, + "alert %s any any -> any any (msg:\"DetectProto" + " test\"; sid:1;)", + str) >= 1024) { goto end; } @@ -195,10 +193,10 @@ static int DetectProtoInitTest(DetectEngineCtx **de_ctx, Signature **sig, * \test ProtoTestParse01 is a test to make sure that we parse the * protocol correctly, when given valid proto option. */ -static int ProtoTestParse01 (void) +static int ProtoTestParse01(void) { DetectProto dp; - memset(&dp,0,sizeof(DetectProto)); + memset(&dp, 0, sizeof(DetectProto)); int r = DetectProtoParse(&dp, "6"); @@ -210,10 +208,10 @@ static int ProtoTestParse01 (void) * \test ProtoTestParse02 is a test to make sure that we parse the * protocol correctly, when given "tcp" as proto option. */ -static int ProtoTestParse02 (void) +static int ProtoTestParse02(void) { DetectProto dp; - memset(&dp,0,sizeof(DetectProto)); + memset(&dp, 0, sizeof(DetectProto)); int r = DetectProtoParse(&dp, "tcp"); @@ -226,10 +224,10 @@ static int ProtoTestParse02 (void) * \test ProtoTestParse03 is a test to make sure that we parse the * protocol correctly, when given "ip" as proto option. */ -static int ProtoTestParse03 (void) +static int ProtoTestParse03(void) { DetectProto dp; - memset(&dp,0,sizeof(DetectProto)); + memset(&dp, 0, sizeof(DetectProto)); int r = DetectProtoParse(&dp, "ip"); @@ -243,10 +241,10 @@ static int ProtoTestParse03 (void) * \test ProtoTestParse04 is a test to make sure that we do not parse the * protocol, when given an invalid proto option. */ -static int ProtoTestParse04 (void) +static int ProtoTestParse04(void) { DetectProto dp; - memset(&dp,0,sizeof(DetectProto)); + memset(&dp, 0, sizeof(DetectProto)); /* Check for a bad number */ int r = DetectProtoParse(&dp, "4242"); @@ -260,10 +258,10 @@ static int ProtoTestParse04 (void) * \test ProtoTestParse05 is a test to make sure that we do not parse the * protocol, when given an invalid proto option. */ -static int ProtoTestParse05 (void) +static int ProtoTestParse05(void) { DetectProto dp; - memset(&dp,0,sizeof(DetectProto)); + memset(&dp, 0, sizeof(DetectProto)); /* Check for a bad string */ int r = DetectProtoParse(&dp, "tcp/udp"); @@ -276,10 +274,10 @@ static int ProtoTestParse05 (void) /** * \test make sure that we properly parse tcp-pkt */ -static int ProtoTestParse06 (void) +static int ProtoTestParse06(void) { DetectProto dp; - memset(&dp,0,sizeof(DetectProto)); + memset(&dp, 0, sizeof(DetectProto)); /* Check for a bad string */ int r = DetectProtoParse(&dp, "tcp-pkt"); @@ -293,10 +291,10 @@ static int ProtoTestParse06 (void) /** * \test make sure that we properly parse tcp-stream */ -static int ProtoTestParse07 (void) +static int ProtoTestParse07(void) { DetectProto dp; - memset(&dp,0,sizeof(DetectProto)); + memset(&dp, 0, sizeof(DetectProto)); /* Check for a bad string */ int r = DetectProtoParse(&dp, "tcp-stream"); @@ -408,4 +406,3 @@ void DetectProtoTests(void) UtRegisterTest("DetectProtoTestSig01", DetectProtoTestSig01); #endif /* UNITTESTS */ } - diff --git a/src/detect-engine-proto.h b/src/detect-engine-proto.h index 4e4c031110db..ffa061a63fa6 100644 --- a/src/detect-engine-proto.h +++ b/src/detect-engine-proto.h @@ -24,17 +24,20 @@ #ifndef __DETECT_PROTO_H__ #define __DETECT_PROTO_H__ -#define DETECT_PROTO_ANY (1 << 0) /**< Indicate that given protocol - is considered as IP */ -#define DETECT_PROTO_ONLY_PKT (1 << 1) /**< Indicate that we only care - about packet payloads. */ -#define DETECT_PROTO_ONLY_STREAM (1 << 2) /**< Indicate that we only care - about stream payloads. */ -#define DETECT_PROTO_IPV4 (1 << 3) /**< IPv4 only */ -#define DETECT_PROTO_IPV6 (1 << 4) /**< IPv6 only */ +#define DETECT_PROTO_ANY \ + (1 << 0) /**< Indicate that given protocol \ + is considered as IP */ +#define DETECT_PROTO_ONLY_PKT \ + (1 << 1) /**< Indicate that we only care \ + about packet payloads. */ +#define DETECT_PROTO_ONLY_STREAM \ + (1 << 2) /**< Indicate that we only care \ + about stream payloads. */ +#define DETECT_PROTO_IPV4 (1 << 3) /**< IPv4 only */ +#define DETECT_PROTO_IPV6 (1 << 4) /**< IPv6 only */ typedef struct DetectProto_ { - uint8_t proto[256/8]; /**< bit array for 256 protocol bits */ + uint8_t proto[256 / 8]; /**< bit array for 256 protocol bits */ uint8_t flags; } DetectProto; @@ -45,4 +48,3 @@ int DetectProtoContainsProto(const DetectProto *, int); void DetectProtoTests(void); #endif /* __DETECT_PROTO_H__ */ - diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 0f459eccb67b..b5fb5ee65247 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -21,7 +21,7 @@ * \author Victor Julien */ -#include "detect-smb-ntlmssp.h" +#include "app-layer/smb/detect-ntlmssp.h" #include "suricata-common.h" #include "suricata.h" #include "detect.h" @@ -45,37 +45,37 @@ #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" -#include "detect-dns-opcode.h" -#include "detect-dns-query.h" -#include "detect-tls-sni.h" -#include "detect-tls-certs.h" -#include "detect-tls-cert-fingerprint.h" -#include "detect-tls-cert-issuer.h" -#include "detect-tls-cert-subject.h" -#include "detect-tls-cert-serial.h" -#include "detect-tls-random.h" -#include "detect-tls-ja3-hash.h" -#include "detect-tls-ja3-string.h" -#include "detect-tls-ja3s-hash.h" -#include "detect-tls-ja3s-string.h" +#include "app-layer/dns/detect-opcode.h" +#include "app-layer/dns/detect-query.h" +#include "app-layer/tls/detect-sni.h" +#include "app-layer/tls/detect-certs.h" +#include "app-layer/tls/detect-cert-fingerprint.h" +#include "app-layer/tls/detect-cert-issuer.h" +#include "app-layer/tls/detect-cert-subject.h" +#include "app-layer/tls/detect-cert-serial.h" +#include "app-layer/tls/detect-random.h" +#include "app-layer/tls/detect-ja3-hash.h" +#include "app-layer/tls/detect-ja3-string.h" +#include "app-layer/tls/detect-ja3s-hash.h" +#include "app-layer/tls/detect-ja3s-string.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" -#include "detect-http-cookie.h" -#include "detect-http-method.h" -#include "detect-http-ua.h" -#include "detect-http-host.h" +#include "app-layer/http/detect-cookie.h" +#include "app-layer/http/detect-method.h" +#include "app-layer/http/detect-ua.h" +#include "app-layer/http/detect-host.h" #include "detect-mark.h" -#include "detect-nfs-procedure.h" -#include "detect-nfs-version.h" +#include "app-layer/nfs/detect-procedure.h" +#include "app-layer/nfs/detect-version.h" #include "detect-engine-event.h" #include "decode.h" #include "detect-config.h" -#include "detect-smb-share.h" +#include "app-layer/smb/detect-share.h" #include "detect-base64-decode.h" #include "detect-base64-data.h" @@ -116,7 +116,7 @@ #include "detect-flow-age.h" #include "detect-flow-pkts.h" #include "detect-tcp-window.h" -#include "detect-ftpbounce.h" +#include "app-layer/ftp/detect-bounce.h" #include "detect-isdataat.h" #include "detect-id.h" #include "detect-rpc.h" @@ -154,19 +154,19 @@ #include "detect-urilen.h" #include "detect-bsize.h" #include "detect-detection-filter.h" -#include "detect-http-client-body.h" -#include "detect-http-server-body.h" -#include "detect-http-header.h" -#include "detect-http-header-names.h" -#include "detect-http-headers.h" -#include "detect-http-raw-header.h" -#include "detect-http-uri.h" -#include "detect-http-protocol.h" -#include "detect-http-start.h" -#include "detect-http-stat-msg.h" -#include "detect-http-request-line.h" -#include "detect-http-response-line.h" -#include "detect-http2.h" +#include "app-layer/http/detect-client-body.h" +#include "app-layer/http/detect-server-body.h" +#include "app-layer/http/detect-header.h" +#include "app-layer/http/detect-header-names.h" +#include "app-layer/http/detect-headers.h" +#include "app-layer/http/detect-raw-header.h" +#include "app-layer/http/detect-uri.h" +#include "app-layer/http/detect-protocol.h" +#include "app-layer/http/detect-start.h" +#include "app-layer/http/detect-stat-msg.h" +#include "app-layer/http/detect-request-line.h" +#include "app-layer/http/detect-response-line.h" +#include "app-layer/http2/detect.h" #include "detect-byte-extract.h" #include "detect-file-data.h" #include "detect-pkt-data.h" @@ -177,8 +177,8 @@ #include "detect-iprep.h" #include "detect-geoip.h" #include "detect-app-layer-protocol.h" -#include "detect-template.h" -#include "detect-template2.h" +#include "app-layer/template/detect.h" +#include "app-layer/template/detect-2.h" #include "detect-tcphdr.h" #include "detect-tcpmss.h" #include "detect-udphdr.h" @@ -186,55 +186,55 @@ #include "detect-icmpv6-mtu.h" #include "detect-ipv4hdr.h" #include "detect-ipv6hdr.h" -#include "detect-krb5-cname.h" -#include "detect-krb5-errcode.h" -#include "detect-krb5-msgtype.h" -#include "detect-krb5-sname.h" -#include "detect-krb5-ticket-encryption.h" -#include "detect-sip-method.h" -#include "detect-sip-uri.h" -#include "detect-sip-protocol.h" -#include "detect-sip-stat-code.h" -#include "detect-sip-stat-msg.h" -#include "detect-sip-request-line.h" -#include "detect-sip-response-line.h" -#include "detect-rfb-secresult.h" -#include "detect-rfb-sectype.h" -#include "detect-rfb-name.h" +#include "app-layer/krb5/detect-cname.h" +#include "app-layer/krb5/detect-errcode.h" +#include "app-layer/krb5/detect-msgtype.h" +#include "app-layer/krb5/detect-sname.h" +#include "app-layer/krb5/detect-ticket-encryption.h" +#include "app-layer/sip/detect-method.h" +#include "app-layer/sip/detect-uri.h" +#include "app-layer/sip/detect-protocol.h" +#include "app-layer/sip/detect-stat-code.h" +#include "app-layer/sip/detect-stat-msg.h" +#include "app-layer/sip/detect-request-line.h" +#include "app-layer/sip/detect-response-line.h" +#include "app-layer/rfb/detect-secresult.h" +#include "app-layer/rfb/detect-sectype.h" +#include "app-layer/rfb/detect-name.h" #include "detect-target.h" -#include "detect-template-rust-buffer.h" -#include "detect-dhcp-leasetime.h" -#include "detect-dhcp-rebinding-time.h" -#include "detect-dhcp-renewal-time.h" -#include "detect-snmp-usm.h" -#include "detect-snmp-version.h" -#include "detect-snmp-community.h" -#include "detect-snmp-pdu_type.h" -#include "detect-mqtt-type.h" -#include "detect-mqtt-flags.h" -#include "detect-mqtt-qos.h" -#include "detect-mqtt-protocol-version.h" -#include "detect-mqtt-reason-code.h" -#include "detect-mqtt-connect-flags.h" -#include "detect-mqtt-connect-clientid.h" -#include "detect-mqtt-connect-username.h" -#include "detect-mqtt-connect-password.h" -#include "detect-mqtt-connect-protocol-string.h" -#include "detect-mqtt-connect-willtopic.h" -#include "detect-mqtt-connect-willmessage.h" -#include "detect-mqtt-connack-sessionpresent.h" -#include "detect-mqtt-publish-topic.h" -#include "detect-mqtt-publish-message.h" -#include "detect-mqtt-subscribe-topic.h" -#include "detect-mqtt-unsubscribe-topic.h" -#include "detect-quic-sni.h" -#include "detect-quic-ua.h" -#include "detect-quic-version.h" -#include "detect-quic-cyu-hash.h" -#include "detect-quic-cyu-string.h" +#include "app-layer/template/detect-rust-buffer.h" +#include "app-layer/dhcp/detect-leasetime.h" +#include "app-layer/dhcp/detect-rebinding-time.h" +#include "app-layer/dhcp/detect-renewal-time.h" +#include "app-layer/snmp/detect-usm.h" +#include "app-layer/snmp/detect-version.h" +#include "app-layer/snmp/detect-community.h" +#include "app-layer/snmp/detect-pdu_type.h" +#include "app-layer/mqtt/detect-type.h" +#include "app-layer/mqtt/detect-flags.h" +#include "app-layer/mqtt/detect-qos.h" +#include "app-layer/mqtt/detect-protocol-version.h" +#include "app-layer/mqtt/detect-reason-code.h" +#include "app-layer/mqtt/detect-connect-flags.h" +#include "app-layer/mqtt/detect-connect-clientid.h" +#include "app-layer/mqtt/detect-connect-username.h" +#include "app-layer/mqtt/detect-connect-password.h" +#include "app-layer/mqtt/detect-connect-protocol-string.h" +#include "app-layer/mqtt/detect-connect-willtopic.h" +#include "app-layer/mqtt/detect-connect-willmessage.h" +#include "app-layer/mqtt/detect-connack-sessionpresent.h" +#include "app-layer/mqtt/detect-publish-topic.h" +#include "app-layer/mqtt/detect-publish-message.h" +#include "app-layer/mqtt/detect-subscribe-topic.h" +#include "app-layer/mqtt/detect-unsubscribe-topic.h" +#include "app-layer/quic/detect-sni.h" +#include "app-layer/quic/detect-ua.h" +#include "app-layer/quic/detect-version.h" +#include "app-layer/quic/detect-cyu-hash.h" +#include "app-layer/quic/detect-cyu-string.h" #include "detect-bypass.h" -#include "detect-ftpdata.h" +#include "app-layer/ftp/detect-data.h" #include "detect-engine-content-inspection.h" #include "detect-transform-compress-whitespace.h" @@ -249,38 +249,38 @@ #include "detect-transform-casechange.h" #include "detect-transform-header-lowercase.h" -#include "util-rule-vars.h" +#include "util/rule-vars.h" #include "app-layer.h" #include "app-layer-protos.h" -#include "app-layer-htp.h" -#include "app-layer-smtp.h" +#include "app-layer/http/parser.h" +#include "app-layer/smtp/parser.h" #include "detect-frame.h" -#include "detect-tls.h" -#include "detect-tls-cert-validity.h" -#include "detect-tls-version.h" -#include "detect-ssh-proto.h" -#include "detect-ssh-proto-version.h" -#include "detect-ssh-software.h" -#include "detect-ssh-software-version.h" -#include "detect-ssh-hassh.h" -#include "detect-ssh-hassh-server.h" -#include "detect-ssh-hassh-string.h" -#include "detect-ssh-hassh-server-string.h" -#include "detect-http-stat-code.h" -#include "detect-ssl-version.h" -#include "detect-ssl-state.h" -#include "detect-modbus.h" +#include "app-layer/tls/detect.h" +#include "app-layer/tls/detect-cert-validity.h" +#include "app-layer/tls/detect-version.h" +#include "app-layer/ssh/detect-proto.h" +#include "app-layer/ssh/detect-proto-version.h" +#include "app-layer/ssh/detect-software.h" +#include "app-layer/ssh/detect-software-version.h" +#include "app-layer/ssh/detect-hassh.h" +#include "app-layer/ssh/detect-hassh-server.h" +#include "app-layer/ssh/detect-hassh-string.h" +#include "app-layer/ssh/detect-hassh-server-string.h" +#include "app-layer/http/detect-stat-code.h" +#include "app-layer/ssl/detect-version.h" +#include "app-layer/ssl/detect-state.h" +#include "app-layer/modbus/detect.h" #include "detect-cipservice.h" -#include "detect-dnp3.h" -#include "detect-ike-exch-type.h" -#include "detect-ike-spi.h" -#include "detect-ike-vendor.h" -#include "detect-ike-chosen-sa.h" -#include "detect-ike-key-exchange-payload-length.h" -#include "detect-ike-nonce-payload-length.h" -#include "detect-ike-nonce-payload.h" -#include "detect-ike-key-exchange-payload.h" +#include "app-layer/dnp3/detect.h" +#include "app-layer/ike/detect-exch-type.h" +#include "app-layer/ike/detect-spi.h" +#include "app-layer/ike/detect-vendor.h" +#include "app-layer/ike/detect-chosen-sa.h" +#include "app-layer/ike/detect-key-exchange-payload-length.h" +#include "app-layer/ike/detect-nonce-payload-length.h" +#include "app-layer/ike/detect-nonce-payload.h" +#include "app-layer/ike/detect-key-exchange-payload.h" #include "action-globals.h" #include "tm-threads.h" @@ -293,21 +293,21 @@ #include "stream-tcp.h" #include "stream-tcp-inline.h" -#include "util-lua.h" -#include "util-var-name.h" -#include "util-classification-config.h" -#include "util-threshold-config.h" -#include "util-print.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" -#include "util-hashlist.h" -#include "util-privs.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-optimize.h" -#include "util-path.h" -#include "util-mpm-ac.h" +#include "util/lua/lua.h" +#include "util/var-name.h" +#include "util/classification-config.h" +#include "util/threshold-config.h" +#include "util/print.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" +#include "util/hashlist.h" +#include "util/privs.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/optimize.h" +#include "util/path.h" +#include "util/mpm/mpm-ac.h" #include "runmodes.h" static void PrintFeatureList(const SigTableElmt *e, char sep) @@ -434,8 +434,7 @@ int SigTableList(const char *keyword) } } else { for (i = 0; i < size; i++) { - if ((sigmatch_table[i].name != NULL) && - strcmp(sigmatch_table[i].name, keyword) == 0) { + if ((sigmatch_table[i].name != NULL) && strcmp(sigmatch_table[i].name, keyword) == 0) { printf("= %s =\n", sigmatch_table[i].name); if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { printf("Not built-in\n"); @@ -726,7 +725,8 @@ void SigTableRegisterTests(void) g_ut_covered++; } else { SCLogDebug("detection plugin %s has no unittest " - "registration function.", sigmatch_table[i].name); + "registration function.", + sigmatch_table[i].name); if (coverage_unittests) SCLogWarning("detection plugin %s has no unittest " diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index b063fda8a614..b6c7e16ba21d 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -43,15 +43,15 @@ #include "detect-uricontent.h" #include "detect-tcp-flags.h" -#include "util-hash.h" -#include "util-hashlist.h" +#include "util/hash.h" +#include "util/hashlist.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-cidr.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-memcmp.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/cidr.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/memcmp.h" /* prototypes */ int SigGroupHeadClearSigs(SigGroupHead *); @@ -104,13 +104,14 @@ static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { void *ptmp; - //printf("de_ctx->sgh_array_cnt %u, de_ctx->sgh_array_size %u, de_ctx->sgh_array %p\n", de_ctx->sgh_array_cnt, de_ctx->sgh_array_size, de_ctx->sgh_array); + // printf("de_ctx->sgh_array_cnt %u, de_ctx->sgh_array_size %u, de_ctx->sgh_array %p\n", + // de_ctx->sgh_array_cnt, de_ctx->sgh_array_size, de_ctx->sgh_array); if (de_ctx->sgh_array_cnt < de_ctx->sgh_array_size) { de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; } else { int increase = 16; - ptmp = SCRealloc(de_ctx->sgh_array, - sizeof(SigGroupHead *) * (increase + de_ctx->sgh_array_size)); + ptmp = SCRealloc( + de_ctx->sgh_array, sizeof(SigGroupHead *) * (increase + de_ctx->sgh_array_size)); if (ptmp == NULL) { SCFree(de_ctx->sgh_array); de_ctx->sgh_array = NULL; @@ -207,7 +208,7 @@ static uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t dat hash += sgh->init->sig_array[b]; hash %= ht->array_size; - SCLogDebug("hash %"PRIu32" (sig_size %"PRIu32")", hash, sgh->init->sig_size); + SCLogDebug("hash %" PRIu32 " (sig_size %" PRIu32 ")", hash, sgh->init->sig_size); return hash; } @@ -223,8 +224,7 @@ static uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t dat * \retval 1 If the 2 SigGroupHeads sent as args match. * \retval 0 If the 2 SigGroupHeads sent as args do not match. */ -static char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) +static char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { SigGroupHead *sgh1 = (SigGroupHead *)data1; SigGroupHead *sgh2 = (SigGroupHead *)data2; @@ -252,8 +252,8 @@ static char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2, */ int SigGroupHeadHashInit(DetectEngineCtx *de_ctx) { - de_ctx->sgh_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, - SigGroupHeadCompareFunc, NULL); + de_ctx->sgh_hash_table = + HashListTableInit(4096, SigGroupHeadHashFunc, SigGroupHeadCompareFunc, NULL); if (de_ctx->sgh_hash_table == NULL) goto error; @@ -298,8 +298,7 @@ SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table, - (void *)sgh, 0); + SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table, (void *)sgh, 0); SCReturnPtr(rsgh, "SigGroupHead"); } @@ -332,8 +331,7 @@ void SigGroupHeadHashFree(DetectEngineCtx *de_ctx) * \retval 0 On success. * \retval -1 On failure. */ -int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, - const Signature *s) +int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, const Signature *s) { if (de_ctx == NULL) return 0; @@ -432,8 +430,7 @@ void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx) return; } -void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, - uint8_t ipproto, int dir) +void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, uint8_t ipproto, int dir) { if (sgh && sgh->init) { SCLogDebug("setting proto %u and dir %d on sgh %p", ipproto, dir, sgh); @@ -463,7 +460,7 @@ void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) for (u = 0; u < (sgh->init->sig_size * 8); u++) { if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) { SCLogDebug("%" PRIu32, u); - printf("s->num %"PRIu32" ", u); + printf("s->num %" PRIu32 " ", u); } } @@ -481,8 +478,7 @@ void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) * \retval 0 success * \retval -1 error */ -int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - uint32_t max_idx) +int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx) { Signature *s = NULL; uint32_t idx = 0; @@ -498,7 +494,7 @@ int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, return -1; for (sig = 0; sig < max_idx + 1; sig++) { - if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8))) ) + if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8)))) continue; s = de_ctx->sig_array[sig]; @@ -725,8 +721,7 @@ int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sg * \retval 1 On successfully finding the sid in the SigGroupHead. * \retval 0 If the sid is not found in the SigGroupHead */ -int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - uint32_t sid) +int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid) { SCEnter(); @@ -744,7 +739,7 @@ int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, } /* Check if the SigGroupHead has an entry for the sid */ - if ( !(sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) ) + if (!(sgh->init->sig_array[sig / 8] & (1 << (sig % 8)))) continue; /* If we have reached here, we have an entry for sid in the SigGroupHead. diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index d4c9e93c6771..995b38c8523d 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -42,12 +42,10 @@ int SigGroupHeadHashRemove(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid); void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx); -void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, - uint8_t ipproto, int dir); +void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, uint8_t ipproto, int dir); int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx); -int SigGroupHeadContainsSigId (DetectEngineCtx *de_ctx, SigGroupHead *sgh, - uint32_t sid); +int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid); void SigGroupHeadRegisterTests(void); void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh); diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index ea51e191ecee..1d6dbe1ac6ab 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -33,13 +33,13 @@ #include "detect-pcre.h" #include "detect-engine-build.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" -#include "util-action.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" +#include "util/action.h" #include "action-globals.h" #include "flow-util.h" -#include "util-validate.h" +#include "util/validate.h" #define DETECT_FLOWVAR_NOT_USED 1 #define DETECT_FLOWVAR_TYPE_READ 2 @@ -66,7 +66,6 @@ #define DETECT_XBITS_TYPE_SET_READ 3 #define DETECT_XBITS_TYPE_SET 4 - /** * \brief Registers a keyword-based, signature ordering function * @@ -78,7 +77,7 @@ * anything */ static void SCSigRegisterSignatureOrderingFunc(DetectEngineCtx *de_ctx, - int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2)) + int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2)) { SCSigOrderFunc *curr = NULL; SCSigOrderFunc *prev = NULL; @@ -138,8 +137,7 @@ static inline int SCSigGetFlowbitsType(Signature *sig) while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { fb = (DetectFlowbitsData *)sm->ctx; - if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET || - fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { + if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET || fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { read++; } else { #ifdef DEBUG @@ -155,9 +153,8 @@ static inline int SCSigGetFlowbitsType(Signature *sig) while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { fb = (DetectFlowbitsData *)sm->ctx; - if (fb->cmd == DETECT_FLOWBITS_CMD_SET || - fb->cmd == DETECT_FLOWBITS_CMD_UNSET || - fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) { + if (fb->cmd == DETECT_FLOWBITS_CMD_SET || fb->cmd == DETECT_FLOWBITS_CMD_UNSET || + fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) { write++; } else { #ifdef DEBUG @@ -193,14 +190,11 @@ static inline int SCSigGetFlowintType(Signature *sig) while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { fi = (DetectFlowintData *)sm->ctx; - if (fi->modifier == FLOWINT_MODIFIER_LT || - fi->modifier == FLOWINT_MODIFIER_LE || - fi->modifier == FLOWINT_MODIFIER_EQ || - fi->modifier == FLOWINT_MODIFIER_NE || - fi->modifier == FLOWINT_MODIFIER_GE || - fi->modifier == FLOWINT_MODIFIER_GT || - fi->modifier == FLOWINT_MODIFIER_NOTSET || - fi->modifier == FLOWINT_MODIFIER_ISSET) { + if (fi->modifier == FLOWINT_MODIFIER_LT || fi->modifier == FLOWINT_MODIFIER_LE || + fi->modifier == FLOWINT_MODIFIER_EQ || fi->modifier == FLOWINT_MODIFIER_NE || + fi->modifier == FLOWINT_MODIFIER_GE || fi->modifier == FLOWINT_MODIFIER_GT || + fi->modifier == FLOWINT_MODIFIER_NOTSET || + fi->modifier == FLOWINT_MODIFIER_ISSET) { read++; } else { #ifdef DEBUG @@ -216,9 +210,8 @@ static inline int SCSigGetFlowintType(Signature *sig) while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { fi = (DetectFlowintData *)sm->ctx; - if (fi->modifier == FLOWINT_MODIFIER_SET || - fi->modifier == FLOWINT_MODIFIER_ADD || - fi->modifier == FLOWINT_MODIFIER_SUB) { + if (fi->modifier == FLOWINT_MODIFIER_SET || fi->modifier == FLOWINT_MODIFIER_ADD || + fi->modifier == FLOWINT_MODIFIER_SUB) { write++; } else { #ifdef DEBUG @@ -385,8 +378,7 @@ static inline int SCSigGetXbitsType(Signature *sig, enum VarTypes type) if (sm->type == DETECT_XBITS) { fb = (DetectXbitsData *)sm->ctx; if (fb->type == type) { - if (fb->cmd == DETECT_XBITS_CMD_ISNOTSET || - fb->cmd == DETECT_XBITS_CMD_ISSET) { + if (fb->cmd == DETECT_XBITS_CMD_ISNOTSET || fb->cmd == DETECT_XBITS_CMD_ISSET) { read++; } else { #ifdef DEBUG @@ -404,8 +396,7 @@ static inline int SCSigGetXbitsType(Signature *sig, enum VarTypes type) if (sm->type == DETECT_HOSTBITS) { fb = (DetectXbitsData *)sm->ctx; if (fb->type == type) { - if (fb->cmd == DETECT_XBITS_CMD_SET || - fb->cmd == DETECT_XBITS_CMD_UNSET || + if (fb->cmd == DETECT_XBITS_CMD_SET || fb->cmd == DETECT_XBITS_CMD_UNSET || fb->cmd == DETECT_XBITS_CMD_TOGGLE) { write++; } else { @@ -498,9 +489,8 @@ static inline void SCSigProcessUserDataForIPPairbits(SCSigSignatureWrapper *sw) } /* Return 1 if sw1 comes before sw2 in the final list. */ -static int SCSigLessThan(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2, - SCSigOrderFunc *cmp_func_list) +static int SCSigLessThan( + SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2, SCSigOrderFunc *cmp_func_list) { SCSigOrderFunc *funcs = cmp_func_list; @@ -519,8 +509,7 @@ static int SCSigLessThan(SCSigSignatureWrapper *sw1, /* Merge sort based on a list of compare functions * debug asserts are here to guide scan-build */ -static SCSigSignatureWrapper *SCSigOrder(SCSigSignatureWrapper *sw, - SCSigOrderFunc *cmp_func_list) +static SCSigSignatureWrapper *SCSigOrder(SCSigSignatureWrapper *sw, SCSigOrderFunc *cmp_func_list) { DEBUG_VALIDATE_BUG_ON(sw == NULL); @@ -595,8 +584,7 @@ static SCSigSignatureWrapper *SCSigOrder(SCSigSignatureWrapper *sw, * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its action */ -static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { return ActionOrderVal(sw2->sig->action) - ActionOrderVal(sw1->sig->action); } @@ -608,11 +596,9 @@ static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1, * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its flowbits */ -static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_FLOWBITS] - - sw2->user[SC_RADIX_USER_DATA_FLOWBITS]; + return sw1->user[SC_RADIX_USER_DATA_FLOWBITS] - sw2->user[SC_RADIX_USER_DATA_FLOWBITS]; } /** @@ -622,11 +608,9 @@ static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1, * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its flowvar */ -static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_FLOWVAR] - - sw2->user[SC_RADIX_USER_DATA_FLOWVAR]; + return sw1->user[SC_RADIX_USER_DATA_FLOWVAR] - sw2->user[SC_RADIX_USER_DATA_FLOWVAR]; } /** @@ -636,18 +620,14 @@ static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1, * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its pktvar */ -static int SCSigOrderByPktvarCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByPktvarCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_PKTVAR] - - sw2->user[SC_RADIX_USER_DATA_PKTVAR]; + return sw1->user[SC_RADIX_USER_DATA_PKTVAR] - sw2->user[SC_RADIX_USER_DATA_PKTVAR]; } -static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_FLOWINT] - - sw2->user[SC_RADIX_USER_DATA_FLOWINT]; + return sw1->user[SC_RADIX_USER_DATA_FLOWINT] - sw2->user[SC_RADIX_USER_DATA_FLOWINT]; } /** @@ -657,11 +637,9 @@ static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its hostbits */ -static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_HOSTBITS] - - sw2->user[SC_RADIX_USER_DATA_HOSTBITS]; + return sw1->user[SC_RADIX_USER_DATA_HOSTBITS] - sw2->user[SC_RADIX_USER_DATA_HOSTBITS]; } /** @@ -671,11 +649,9 @@ static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its bits */ -static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { - return sw1->user[SC_RADIX_USER_DATA_IPPAIRBITS] - - sw2->user[SC_RADIX_USER_DATA_IPPAIRBITS]; + return sw1->user[SC_RADIX_USER_DATA_IPPAIRBITS] - sw2->user[SC_RADIX_USER_DATA_IPPAIRBITS]; } /** @@ -685,8 +661,7 @@ static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1, * signatures have to be ordered. * \param sw The new signature that has to be ordered based on its priority */ -static int SCSigOrderByPriorityCompare(SCSigSignatureWrapper *sw1, - SCSigSignatureWrapper *sw2) +static int SCSigOrderByPriorityCompare(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2) { if (sw1->sig->prio > sw2->sig->prio) { return -1; @@ -762,7 +737,8 @@ void SCSigOrderSignatures(DetectEngineCtx *de_ctx) sigw_list = SCSigOrder(sigw_list, de_ctx->sc_sig_order_funcs); SCLogDebug("Total Signatures to be processed by the" - "sigordering module: %d", i); + "sigordering module: %d", + i); /* Recreate the sig list in order */ de_ctx->sig_list = NULL; @@ -887,59 +863,78 @@ static int SCSigOrderingTest02(void) FAIL_IF(de_ctx == NULL); sig = DetectEngineAppendSig(de_ctx, - "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:1;)"); + "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:1;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:2;)"); + "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:2;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:3;)"); + "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:3;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; flowvar:http_host,\"www.oisf.net\"; rev:4; priority:1; sid:4;)"); + "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; " + "flowvar:http_host,\"www.oisf.net\"; rev:4; priority:1; sid:4;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:1; sid:5;)"); + "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; " + "offset:0; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:1; sid:5;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; content:\"220\"; offset:10; depth:4; rev:4; priority:3; sid:6;)"); + "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; content:\"220\"; " + "offset:10; depth:4; rev:4; priority:3; sid:6;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:7;)"); + "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; " + "offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:7;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:8;)"); + "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; " + "offset:10; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; sid:8;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; priority:3; flowbits:set,TEST.one; flowbits:noalert; sid:9;)"); + "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; " + "offset:10; depth:4; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; rev:4; " + "priority:3; flowbits:set,TEST.one; flowbits:noalert; sid:9;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:10;)"); + "pass tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; " + "offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:3; sid:10;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:11;)"); + "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:11;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:12;)"); + "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "content:\"220\"; offset:11; depth:4; pcre:\"/220[- ]/\"; rev:4; sid:12;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; pktvar:http_host,\"www.oisf.net\"; priority:2; flowbits:isnotset,TEST.two; sid:13;)"); + "drop tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; " + "offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; pktvar:http_host,\"www.oisf.net\"; " + "priority:2; flowbits:isnotset,TEST.two; sid:13;)"); FAIL_IF_NULL(sig); sig = DetectEngineAppendSig(de_ctx, - "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; flowbits:set,TEST.two; sid:14;)"); + "alert tcp any !21:902 -> any any (msg:\"Testing sigordering\"; " + "content:\"220\"; offset:12; depth:4; pcre:\"/220[- ]/\"; rev:4; priority:2; " + "flowbits:set,TEST.two; sid:14;)"); FAIL_IF_NULL(sig); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByActionCompare); @@ -1303,12 +1298,12 @@ static int SCSigOrderingTest05(void) sig = de_ctx->sig_list; - //#ifdef DEBUG + // #ifdef DEBUG while (sig != NULL) { printf("sid: %d\n", sig->id); sig = sig->next; } - //#endif + // #endif sig = de_ctx->sig_list; @@ -1894,7 +1889,8 @@ static int SCSigOrderingTest12(void) de_ctx->flags |= DE_QUIET; const char *sigs[2]; - sigs[0] = "alert tcp any any -> any any (content:\"test\"; dsize:>0; flowbits:isset,one; flowbits:set,two; sid:1;)"; + sigs[0] = "alert tcp any any -> any any (content:\"test\"; dsize:>0; flowbits:isset,one; " + "flowbits:set,two; sid:1;)"; sigs[1] = "alert tcp any any -> any any (content:\"test\"; dsize:>0; flowbits:set,one; sid:2;)"; UTHAppendSigs(de_ctx, sigs, 2); @@ -1915,8 +1911,8 @@ static int SCSigOrderingTest12(void) UTHMatchPackets(de_ctx, &p, 1); - uint32_t sids[2] = {1, 2}; - uint32_t results[2] = {1, 1}; + uint32_t sids[2] = { 1, 2 }; + uint32_t results[2] = { 1, 1 }; FAIL_IF_NOT(UTHCheckPacketMatchResults(p, sids, results, 2)); UTHFreePackets(&p, 1); @@ -1937,11 +1933,14 @@ static int SCSigOrderingTest13(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); - sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:isset,bit1; flowbits:set,bit2; flowbits:set,bit3; sid:6;)"); + sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:isset,bit1; " + "flowbits:set,bit2; flowbits:set,bit3; sid:6;)"); FAIL_IF_NULL(sig); - sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:set,bit1; flowbits:set,bit2; sid:7;)"); + sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (flowbits:set,bit1; flowbits:set,bit2; sid:7;)"); FAIL_IF_NULL(sig); - sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:isset,bit1; flowbits:isset,bit2; flowbits:isset,bit3; sid:5;)"); + sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flowbits:isset,bit1; " + "flowbits:isset,bit2; flowbits:isset,bit3; sid:5;)"); FAIL_IF_NULL(sig); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowbitsCompare); diff --git a/src/detect-engine-sigorder.h b/src/detect-engine-sigorder.h index 7d7e10536171..93c53f3286c8 100644 --- a/src/detect-engine-sigorder.h +++ b/src/detect-engine-sigorder.h @@ -28,7 +28,7 @@ * \brief Different kinds of helper data that can be used by the signature * ordering module. Used by the "user" field in SCSigSignatureWrapper */ -typedef enum{ +typedef enum { SC_RADIX_USER_DATA_FLOWBITS, SC_RADIX_USER_DATA_FLOWVAR, SC_RADIX_USER_DATA_PKTVAR, diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 74f87ff938f1..035556f5fae5 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -56,16 +56,18 @@ #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-protos.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-profiling.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/profiling.h" #include "flow-util.h" /** convert enum to string */ -#define CASE_CODE(E) case E: return #E +#define CASE_CODE(E) \ + case E: \ + return #E static inline int StateIsValid(uint16_t alproto, void *alstate) { @@ -101,15 +103,13 @@ static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIn for (; tx_store != NULL; tx_store = tx_store->next) { SCLogDebug("tx_store %p", tx_store); - for (store_cnt = 0; - store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; - store_cnt++, state_cnt++) - { + for (store_cnt = 0; store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; + store_cnt++, state_cnt++) { DeStateStoreItem *item = &tx_store->store[store_cnt]; if (item->sid == num) { - SCLogDebug("sid %u already in state: %p %p %p %u %u, direction %s", - num, state, dir_state, tx_store, state_cnt, - store_cnt, direction & STREAM_TOSERVER ? "toserver" : "toclient"); + SCLogDebug("sid %u already in state: %p %p %p %u %u, direction %s", num, state, + dir_state, tx_store, state_cnt, store_cnt, + direction & STREAM_TOSERVER ? "toserver" : "toclient"); return 1; } } @@ -118,8 +118,8 @@ static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIn } #endif -static void DeStateSignatureAppend(DetectEngineState *state, - const Signature *s, uint32_t inspect_flags, uint8_t direction) +static void DeStateSignatureAppend( + DetectEngineState *state, const Signature *s, uint32_t inspect_flags, uint8_t direction) { SCEnter(); @@ -188,14 +188,16 @@ void DetectEngineStateFree(DetectEngineState *state) return; } -static void StoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t file_no_match, uint8_t direction) +static void StoreFileNoMatchCnt( + DetectEngineState *de_state, uint16_t file_no_match, uint8_t direction) { de_state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1].filestore_cnt += file_no_match; return; } -static bool StoreFilestoreSigsCantMatch(const SigGroupHead *sgh, const DetectEngineState *de_state, uint8_t direction) +static bool StoreFilestoreSigsCantMatch( + const SigGroupHead *sgh, const DetectEngineState *de_state, uint8_t direction) { if (de_state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1].filestore_cnt == sgh->filestore_cnt) @@ -207,7 +209,7 @@ static bool StoreFilestoreSigsCantMatch(const SigGroupHead *sgh, const DetectEng static void StoreStateTxHandleFiles(const SigGroupHead *sgh, Flow *f, DetectEngineState *destate, const uint8_t flow_flags, void *tx, const uint64_t tx_id, const uint16_t file_no_match) { - SCLogDebug("tx %"PRIu64", file_no_match %u", tx_id, file_no_match); + SCLogDebug("tx %" PRIu64 ", file_no_match %u", tx_id, file_no_match); StoreFileNoMatchCnt(destate, file_no_match, flow_flags); if (StoreFilestoreSigsCantMatch(sgh, destate, flow_flags)) { SCLogDebug("filestore sigs can't match"); @@ -218,11 +220,8 @@ static void StoreStateTxHandleFiles(const SigGroupHead *sgh, Flow *f, DetectEngi } } -void DetectRunStoreStateTx( - const SigGroupHead *sgh, - Flow *f, void *tx, uint64_t tx_id, - const Signature *s, - uint32_t inspect_flags, uint8_t flow_flags, +void DetectRunStoreStateTx(const SigGroupHead *sgh, Flow *f, void *tx, uint64_t tx_id, + const Signature *s, uint32_t inspect_flags, uint8_t flow_flags, const uint16_t file_no_match) { AppLayerTxData *tx_data = AppLayerParserGetTxData(f->proto, f->alproto, tx); @@ -235,12 +234,12 @@ void DetectRunStoreStateTx( tx_data->de_state = DetectEngineStateAlloc(); if (tx_data->de_state == NULL) return; - SCLogDebug("destate created for %"PRIu64, tx_id); + SCLogDebug("destate created for %" PRIu64, tx_id); } DeStateSignatureAppend(tx_data->de_state, s, inspect_flags, flow_flags); StoreStateTxHandleFiles(sgh, f, tx_data->de_state, flow_flags, tx, tx_id, file_no_match); - SCLogDebug("Stored for TX %"PRIu64, tx_id); + SCLogDebug("Stored for TX %" PRIu64, tx_id); } static inline void ResetTxState(DetectEngineState *s) @@ -278,7 +277,7 @@ void DetectEngineStateResetTxs(Flow *f) uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate); - for ( ; inspect_tx_id < total_txs; inspect_tx_id++) { + for (; inspect_tx_id < total_txs; inspect_tx_id++) { void *inspect_tx = AppLayerParserGetTx(f->proto, f->alproto, alstate, inspect_tx_id); if (inspect_tx != NULL) { AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, inspect_tx); @@ -297,12 +296,9 @@ void DetectEngineStateResetTxs(Flow *f) static int DeStateTest01(void) { - SCLogDebug("sizeof(DetectEngineState)\t\t%"PRIuMAX, - (uintmax_t)sizeof(DetectEngineState)); - SCLogDebug("sizeof(DeStateStore)\t\t\t%"PRIuMAX, - (uintmax_t)sizeof(DeStateStore)); - SCLogDebug("sizeof(DeStateStoreItem)\t\t%"PRIuMAX"", - (uintmax_t)sizeof(DeStateStoreItem)); + SCLogDebug("sizeof(DetectEngineState)\t\t%" PRIuMAX, (uintmax_t)sizeof(DetectEngineState)); + SCLogDebug("sizeof(DeStateStore)\t\t\t%" PRIuMAX, (uintmax_t)sizeof(DeStateStore)); + SCLogDebug("sizeof(DeStateStoreItem)\t\t%" PRIuMAX "", (uintmax_t)sizeof(DeStateStoreItem)); return 1; } @@ -449,9 +445,11 @@ static int DeStateTest03(void) FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL); FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11); - FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & BIT_U32(DE_STATE_FLAG_BASE)); + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & + BIT_U32(DE_STATE_FLAG_BASE)); FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22); - FAIL_IF(!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & BIT_U32(DE_STATE_FLAG_BASE))); + FAIL_IF(!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & + BIT_U32(DE_STATE_FLAG_BASE))); DetectEngineStateFree(state); PASS; @@ -490,7 +488,7 @@ static int DeStateSigTest01(void) f.alproto = ALPROTO_HTTP1; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -500,7 +498,9 @@ static int DeStateSigTest01(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy\"; http_cookie; sid:1; rev:1;)"); + Signature *s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; " + "content:\"dummy\"; http_cookie; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -574,7 +574,7 @@ static int DeStateSigTest02(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -586,9 +586,14 @@ static int DeStateSigTest02(void) de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"POST\"; http_method; content:\"/\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"body\"; nocase; http_client_body; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (flow:to_server; content:\"POST\"; http_method; " + "content:\"/\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy\"; " + "http_cookie; content:\"body\"; nocase; http_client_body; sid:1; rev:1;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (flow:to_server; content:\"GET\"; http_method; " + "content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -656,11 +661,13 @@ static int DeStateSigTest03(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" @@ -682,7 +689,9 @@ static int DeStateSigTest03(void) de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (flow:to_server; content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (flow:to_server; content:\"POST\"; http_method; " + "content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -698,7 +707,7 @@ static int DeStateSigTest03(void) FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -740,11 +749,13 @@ static int DeStateSigTest04(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" @@ -763,7 +774,9 @@ static int DeStateSigTest04(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (content:\"GET\"; http_method; " + "content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -779,7 +792,7 @@ static int DeStateSigTest04(void) Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -818,11 +831,13 @@ static int DeStateSigTest05(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" @@ -842,7 +857,9 @@ static int DeStateSigTest05(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (content:\"GET\"; http_method; " + "content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -857,7 +874,7 @@ static int DeStateSigTest05(void) Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -900,11 +917,13 @@ static int DeStateSigTest06(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent\r\n" @@ -924,7 +943,9 @@ static int DeStateSigTest06(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; filestore; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; " + "http_uri; filename:\"nomatch\"; filestore; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -940,7 +961,7 @@ static int DeStateSigTest06(void) Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -981,11 +1002,13 @@ static int DeStateSigTest07(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 215\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; @@ -1007,7 +1030,9 @@ static int DeStateSigTest07(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (content:\"GET\"; http_method; " + "content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1022,7 +1047,7 @@ static int DeStateSigTest07(void) Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -1069,11 +1094,13 @@ static int DeStateSigTest08(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 440\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"AAAApicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"AAAApicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; @@ -1084,7 +1111,8 @@ static int DeStateSigTest08(void) "-----------------------------277531038314945\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"BBBBpicture2.jpg\"\r\n" + uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; " + "filename=\"BBBBpicture2.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent2\r\n" @@ -1105,7 +1133,9 @@ static int DeStateSigTest08(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"BBBBpicture\"; filestore; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; " + "http_uri; filename:\"BBBBpicture\"; filestore; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1120,7 +1150,7 @@ static int DeStateSigTest08(void) Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -1197,11 +1227,13 @@ static int DeStateSigTest09(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 440\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; @@ -1212,7 +1244,8 @@ static int DeStateSigTest09(void) "-----------------------------277531038314945\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n" + uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; " + "filename=\"somepicture2.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent2\r\n" @@ -1233,7 +1266,9 @@ static int DeStateSigTest09(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"somepicture\"; filestore; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; " + "http_uri; filename:\"somepicture\"; filestore; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1248,7 +1283,7 @@ static int DeStateSigTest09(void) Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -1323,11 +1358,13 @@ static int DeStateSigTest10(void) { uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n" "Host: www.server.lan\r\n" - "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n" + "Content-Type: multipart/form-data; " + "boundary=---------------------------277531038314945\r\n" "Content-Length: 440\r\n" "\r\n" "-----------------------------277531038314945\r\n" - "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n" + "Content-Disposition: form-data; name=\"uploadfile_0\"; " + "filename=\"somepicture1.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n"; @@ -1338,7 +1375,8 @@ static int DeStateSigTest10(void) "-----------------------------277531038314945\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n" + uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; " + "filename=\"somepicture2.jpg\"\r\n" "Content-Type: image/jpeg\r\n" "\r\n" "filecontent2\r\n" @@ -1359,7 +1397,8 @@ static int DeStateSigTest10(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (filename:\"somepicture\"; filestore; sid:1; rev:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (filename:\"somepicture\"; filestore; sid:1; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1374,7 +1413,7 @@ static int DeStateSigTest10(void) Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); FAIL_IF_NULL(p); p->flow = f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 25cd679a0dae..91379074b61d 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -31,12 +31,11 @@ * \author Anoop Saldanha */ - #ifndef __DETECT_ENGINE_STATE_H__ #define __DETECT_ENGINE_STATE_H__ -#define DETECT_ENGINE_INSPECT_SIG_NO_MATCH 0 -#define DETECT_ENGINE_INSPECT_SIG_MATCH 1 +#define DETECT_ENGINE_INSPECT_SIG_NO_MATCH 0 +#define DETECT_ENGINE_INSPECT_SIG_MATCH 1 #define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH 2 /** indicate that the file inspection portion of a sig didn't match. * This is used to handle state keeping as the detect engine is still @@ -50,25 +49,25 @@ #define DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES 4 /** number of DeStateStoreItem's in one DeStateStore object */ -#define DE_STATE_CHUNK_SIZE 15 +#define DE_STATE_CHUNK_SIZE 15 /* per sig flags */ -#define DE_STATE_FLAG_FULL_INSPECT BIT_U32(0) -#define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(1) +#define DE_STATE_FLAG_FULL_INSPECT BIT_U32(0) +#define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(1) /* flag set if file inspecting sig did not match, but might need to be * re-evaluated for a new file in a tx */ -#define DE_STATE_ID_FILE_INSPECT 2UL -#define DE_STATE_FLAG_FILE_INSPECT BIT_U32(DE_STATE_ID_FILE_INSPECT) +#define DE_STATE_ID_FILE_INSPECT 2UL +#define DE_STATE_FLAG_FILE_INSPECT BIT_U32(DE_STATE_ID_FILE_INSPECT) /* first bit position after the built-ins */ -#define DE_STATE_FLAG_BASE 3UL +#define DE_STATE_FLAG_BASE 3UL /* state flags * * Used by app-layer-parsers to notify us that new files * are available in the tx. */ -#define DETECT_ENGINE_STATE_FLAG_FILE_NEW BIT_U8(0) +#define DETECT_ENGINE_STATE_FLAG_FILE_NEW BIT_U8(0) typedef struct DeStateStoreItem_ { uint32_t flags; diff --git a/src/detect-engine-tag.c b/src/detect-engine-tag.c index 21610264ef5b..b640f0925b3f 100644 --- a/src/detect-engine-tag.c +++ b/src/detect-engine-tag.c @@ -27,10 +27,10 @@ #include "suricata-common.h" #include "detect-engine.h" -#include "util-hash.h" -#include "util-atomic.h" -#include "util-time.h" -#include "util-hashlist.h" +#include "util/hash.h" +#include "util/atomic.h" +#include "util/time.h" +#include "util/hashlist.h" #include "detect-engine-tag.h" #include "detect-engine-build.h" #include "detect-tag.h" @@ -38,14 +38,14 @@ #include "host-storage.h" #include "flow-storage.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "flow-util.h" #include "stream-tcp-private.h" -SC_ATOMIC_DECLARE(unsigned int, num_tags); /**< Atomic counter, to know if we - have tagged hosts/sessions, - to avoid locking */ +SC_ATOMIC_DECLARE(unsigned int, num_tags); /**< Atomic counter, to know if we + have tagged hosts/sessions, + to avoid locking */ static HostStorageId host_tag_id = { .id = -1 }; /**< Host storage id for tags */ static FlowStorageId flow_tag_id = { .id = -1 }; /**< Flow storage id for tags */ @@ -159,10 +159,10 @@ int TagFlowAdd(Packet *p, DetectTagDataEntry *tde) new_tde->next = FlowGetStorageById(p->flow, flow_tag_id); FlowSetStorageById(p->flow, flow_tag_id, new_tde); SCLogDebug("adding tag with first_ts %u", new_tde->first_ts); - (void) SC_ATOMIC_ADD(num_tags, 1); + (void)SC_ATOMIC_ADD(num_tags, 1); } } else if (tag_cnt == DETECT_TAG_MAX_TAGS) { - SCLogDebug("Max tags for sessions reached (%"PRIu16")", tag_cnt); + SCLogDebug("Max tags for sessions reached (%" PRIu16 ")", tag_cnt); } return updated; @@ -204,7 +204,7 @@ int TagHashAddTag(DetectTagDataEntry *tde, Packet *p) DetectTagDataEntry *new_tde = DetectTagDataCopy(tde); if (new_tde != NULL) { HostSetStorageById(host, host_tag_id, new_tde); - (void) SC_ATOMIC_ADD(num_tags, 1); + (void)SC_ATOMIC_ADD(num_tags, 1); SCLogDebug("host tag added"); } } else { @@ -236,13 +236,13 @@ int TagHashAddTag(DetectTagDataEntry *tde, Packet *p) /* get a new tde as the one we have is on the stack */ DetectTagDataEntry *new_tde = DetectTagDataCopy(tde); if (new_tde != NULL) { - (void) SC_ATOMIC_ADD(num_tags, 1); + (void)SC_ATOMIC_ADD(num_tags, 1); new_tde->next = tag; HostSetStorageById(host, host_tag_id, new_tde); } } else if (ntags == DETECT_TAG_MAX_TAGS) { - SCLogDebug("Max tags for sessions reached (%"PRIu16")", ntags); + SCLogDebug("Max tags for sessions reached (%" PRIu16 ")", ntags); } } @@ -282,22 +282,21 @@ static void TagHandlePacketFlow(Flow *f, Packet *p) switch (iter->metric) { case DETECT_TAG_METRIC_PACKET: if (iter->packets > iter->count) { - SCLogDebug("flow tag expired: packets %u > %u", - iter->packets, iter->count); + SCLogDebug("flow tag expired: packets %u > %u", iter->packets, iter->count); /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } else { FlowSetStorageById(p->flow, flow_tag_id, iter->next); tde = iter; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { @@ -310,21 +309,20 @@ static void TagHandlePacketFlow(Flow *f, Packet *p) case DETECT_TAG_METRIC_BYTES: if (iter->bytes > iter->count) { /* tag expired */ - SCLogDebug("flow tag expired: bytes %u > %u", - iter->bytes, iter->count); + SCLogDebug("flow tag expired: bytes %u > %u", iter->bytes, iter->count); if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } else { FlowSetStorageById(p->flow, flow_tag_id, iter->next); tde = iter; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { @@ -338,23 +336,22 @@ static void TagHandlePacketFlow(Flow *f, Packet *p) /* last_ts handles this metric, but also a generic time based * expiration to prevent dead sessions/hosts */ if (iter->last_ts - iter->first_ts > iter->count) { - SCLogDebug("flow tag expired: %u - %u = %u > %u", - iter->last_ts, iter->first_ts, - (iter->last_ts - iter->first_ts), iter->count); + SCLogDebug("flow tag expired: %u - %u = %u > %u", iter->last_ts, + iter->first_ts, (iter->last_ts - iter->first_ts), iter->count); /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } else { FlowSetStorageById(p->flow, flow_tag_id, iter->next); tde = iter; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } } else if (flag_added == 0) { @@ -365,7 +362,6 @@ static void TagHandlePacketFlow(Flow *f, Packet *p) } break; } - } prev = iter; @@ -410,13 +406,13 @@ static void TagHandlePacketHost(Host *host, Packet *p) prev->next = iter->next; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } else { tde = iter; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); HostSetStorageById(host, host_tag_id, iter); continue; } @@ -436,13 +432,13 @@ static void TagHandlePacketHost(Host *host, Packet *p) prev->next = iter->next; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } else { tde = iter; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); HostSetStorageById(host, host_tag_id, iter); continue; } @@ -457,22 +453,21 @@ static void TagHandlePacketHost(Host *host, Packet *p) /* last_ts handles this metric, but also a generic time based * expiration to prevent dead sessions/hosts */ if (iter->last_ts - iter->first_ts > iter->count) { - SCLogDebug("host tag expired: %u - %u = %u > %u", - iter->last_ts, iter->first_ts, - (iter->last_ts - iter->first_ts), iter->count); + SCLogDebug("host tag expired: %u - %u = %u > %u", iter->last_ts, + iter->first_ts, (iter->last_ts - iter->first_ts), iter->count); /* tag expired */ if (prev != NULL) { tde = iter; prev->next = iter->next; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); continue; } else { tde = iter; iter = iter->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); HostSetStorageById(host, host_tag_id, iter); continue; } @@ -484,7 +479,6 @@ static void TagHandlePacketHost(Host *host, Packet *p) } break; } - } prev = iter; @@ -520,8 +514,7 @@ static Host *GetLockedDstHost(Packet *p) * \param p packet * */ -void TagHandlePacket(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Packet *p) +void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { SCEnter(); @@ -593,7 +586,7 @@ int TagTimeoutCheck(Host *host, SCTime_t ts) tmp = tde->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); } else { HostSetStorageById(host, host_tag_id, tmp->next); @@ -601,7 +594,7 @@ int TagTimeoutCheck(Host *host, SCTime_t ts) tmp = tde->next; SCFree(tde); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); } } return retval; @@ -612,7 +605,7 @@ int TagTimeoutCheck(Host *host, SCTime_t ts) /** * \test host tagging: packets */ -static int DetectTagTestPacket01 (void) +static int DetectTagTestPacket01(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; @@ -620,47 +613,30 @@ static int DetectTagTestPacket01 (void) uint16_t buf_len2 = strlen((char *)buf2); Packet *p[7]; - p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.9", - 41424, 80); - p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.9", - 41424, 80); - p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.9", - 41424, 80); - p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.11", - 41424, 80); - p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.11", - 41424, 80); + p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); + p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); + p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.9", 41424, 80); + p[5] = UTHBuildPacketReal( + buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.11", 41424, 80); + p[6] = UTHBuildPacketReal( + buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.11", 41424, 80); const char *sigs[5]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host,3,packets,src; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host,4,packets,dst; sid:2;)"; - sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; - sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; - sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; " + "tag:host,3,packets,src; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; " + "tag:host,4,packets,dst; sid:2;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; + sigs[4] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ - uint32_t sid[5] = {1,2,3,4,5}; - - int32_t results[7][5] = { - {1, 1, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0} - }; + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; + + int32_t results[7][5] = { { 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; StorageInit(); TagInitCtx(); StorageFinalize(); @@ -702,7 +678,7 @@ static int DetectTagTestPacket01 (void) /** * \test host tagging: seconds */ -static int DetectTagTestPacket02 (void) +static int DetectTagTestPacket02(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; @@ -725,52 +701,35 @@ static int DetectTagTestPacket02 (void) de_ctx->flags |= DE_QUIET; Packet *p[7]; - p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.9", - 41424, 80); - p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.9", - 41424, 80); - p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.9", - 41424, 80); - p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.11", - 41424, 80); - p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.11", - 41424, 80); + p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); + p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); + p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.9", 41424, 80); + p[5] = UTHBuildPacketReal( + buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.11", 41424, 80); + p[6] = UTHBuildPacketReal( + buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.11", 41424, 80); const char *sigs[5]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host,3,seconds,src; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host,8,seconds,dst; sid:2;)"; - sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; - sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; - sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; " + "tag:host,3,seconds,src; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; " + "tag:host,8,seconds,dst; sid:2;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; + sigs[4] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ - uint32_t sid[5] = {1,2,3,4,5}; + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; int numsigs = 5; FAIL_IF(UTHAppendSigs(de_ctx, sigs, numsigs) == 0); - //de_ctx->flags |= DE_QUIET; + // de_ctx->flags |= DE_QUIET; - int32_t results[7][5] = { - {1, 1, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0} - }; + int32_t results[7][5] = { { 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; int num_packets = 7; SigGroupBuild(de_ctx); @@ -804,7 +763,7 @@ static int DetectTagTestPacket02 (void) /** * \test host tagging: bytes */ -static int DetectTagTestPacket03 (void) +static int DetectTagTestPacket03(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; @@ -828,50 +787,33 @@ static int DetectTagTestPacket03 (void) de_ctx->flags |= DE_QUIET; Packet *p[7]; - p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.9", - 41424, 80); - p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.9", - 41424, 80); - p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.9", - 41424, 80); - p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.11", - 41424, 80); - p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.11", - 41424, 80); + p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); + p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.9", 41424, 80); + p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.9", 41424, 80); + p[5] = UTHBuildPacketReal( + buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.11", 41424, 80); + p[6] = UTHBuildPacketReal( + buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.11", 41424, 80); const char *sigs[5]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, 150, bytes, src; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, 150, bytes, dst; sid:2;)"; - sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; - sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; - sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:host, " + "150, bytes, src; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"Hi all\"; tag:host, " + "150, bytes, dst; sid:2;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; + sigs[4] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ - uint32_t sid[5] = {1,2,3,4,5}; + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; int numsigs = 5; FAIL_IF(UTHAppendSigs(de_ctx, sigs, numsigs) == 0); - int32_t results[7][5] = { - {1, 1, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0} - }; + int32_t results[7][5] = { { 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; int num_packets = 7; SigGroupBuild(de_ctx); @@ -903,7 +845,7 @@ static int DetectTagTestPacket03 (void) /** * \test session tagging: packets */ -static int DetectTagTestPacket04 (void) +static int DetectTagTestPacket04(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; @@ -941,50 +883,30 @@ static int DetectTagTestPacket04 (void) de_ctx->flags |= DE_QUIET; Packet *p[7]; - p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 80, 41424); + p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 80, 41424); const char *sigs[5]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:session,4,packets; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; - sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; - sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; - sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; " + "tag:session,4,packets; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; + sigs[4] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ - uint32_t sid[5] = {1,2,3,4,5}; + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; int numsigs = 5; FAIL_IF(UTHAppendSigs(de_ctx, sigs, numsigs) == 0); - int32_t results[7][5] = { - {1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0} - }; + int32_t results[7][5] = { { 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; int num_packets = 7; SigGroupBuild(de_ctx); @@ -1024,7 +946,7 @@ static int DetectTagTestPacket04 (void) /** * \test session tagging: seconds */ -static int DetectTagTestPacket05 (void) +static int DetectTagTestPacket05(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; @@ -1062,50 +984,30 @@ static int DetectTagTestPacket05 (void) de_ctx->flags |= DE_QUIET; Packet *p[7]; - p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 80, 41424); + p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 80, 41424); const char *sigs[5]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:session,8,seconds; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; - sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; - sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; - sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; " + "tag:session,8,seconds; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; + sigs[4] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ - uint32_t sid[5] = {1,2,3,4,5}; + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; int numsigs = 5; FAIL_IF(UTHAppendSigs(de_ctx, sigs, numsigs) == 0); - int32_t results[7][5] = { - {1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0} - }; + int32_t results[7][5] = { { 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; int num_packets = 7; SigGroupBuild(de_ctx); @@ -1150,7 +1052,7 @@ static int DetectTagTestPacket05 (void) /** * \test session tagging: bytes */ -static int DetectTagTestPacket06 (void) +static int DetectTagTestPacket06(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; @@ -1188,50 +1090,30 @@ static int DetectTagTestPacket06 (void) de_ctx->flags |= DE_QUIET; Packet *p[7]; - p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 80, 41424); + p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[3] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 80, 41424); const char *sigs[5]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:session,150,bytes; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; - sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; - sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; - sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; " + "tag:session,150,bytes; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; + sigs[4] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ - uint32_t sid[5] = {1,2,3,4,5}; + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; int numsigs = 5; FAIL_IF(UTHAppendSigs(de_ctx, sigs, numsigs) == 0); - int32_t results[7][5] = { - {1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0} - }; + int32_t results[7][5] = { { 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; int num_packets = 7; SigGroupBuild(de_ctx); @@ -1272,7 +1154,7 @@ static int DetectTagTestPacket06 (void) /** * \test session tagging: bytes, where a 2nd match makes us tag more */ -static int DetectTagTestPacket07 (void) +static int DetectTagTestPacket07(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint8_t *buf2 = (uint8_t *)"lalala!"; @@ -1310,49 +1192,29 @@ static int DetectTagTestPacket07 (void) de_ctx->flags |= DE_QUIET; Packet *p[7]; - p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[3] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 80); - p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", - 80, 41424); - p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 80, 41424); + p[0] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[1] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[2] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[3] = UTHBuildPacketReal(buf, buf_len, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + p[4] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[5] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.1", "192.168.1.5", 80, 41424); + p[6] = UTHBuildPacketReal(buf2, buf_len2, IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 80, 41424); const char *sigs[5]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; tag:session,150,bytes; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; - sigs[2]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; - sigs[3]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; - sigs[4]= "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing tag 1\"; content:\"Hi all\"; " + "tag:session,150,bytes; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"blahblah\"; sid:2;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:3;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:4;)"; + sigs[4] = "alert tcp any any -> any any (msg:\"Testing tag 2\"; content:\"no match\"; sid:5;)"; /* Please, Notice that tagged data goes with sig_id = 1 and tag sig generator = 2 */ - uint32_t sid[5] = {1,2,3,4,5}; + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; int numsigs = 5; FAIL_IF(UTHAppendSigs(de_ctx, sigs, numsigs) == 0); - int32_t results[7][5] = { - {1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {1, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0} - }; + int32_t results[7][5] = { { 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; int num_packets = 7; SigGroupBuild(de_ctx); @@ -1407,4 +1269,3 @@ void DetectEngineTagRegisterTests(void) UtRegisterTest("DetectTagTestPacket07", DetectTagTestPacket07); #endif /* UNITTESTS */ } - diff --git a/src/detect-engine-tag.h b/src/detect-engine-tag.h index 73f3fd871a35..448295a625f3 100644 --- a/src/detect-engine-tag.h +++ b/src/detect-engine-tag.h @@ -38,8 +38,8 @@ /* Used for tagged data (sid and gid of the packets that * follow the one that triggered the rule with tag option) */ -#define TAG_SIG_GEN 2 -#define TAG_SIG_ID 1 +#define TAG_SIG_GEN 2 +#define TAG_SIG_ID 1 int TagHashAddTag(DetectTagDataEntry *, Packet *); int TagFlowAdd(Packet *, DetectTagDataEntry *); @@ -57,5 +57,3 @@ int TagHostHasTag(Host *host); void DetectEngineTagRegisterTests(void); #endif /* __DETECT_ENGINE_TAG_H__ */ - - diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index b5ac8670d0bb..09815730a97f 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -60,12 +60,12 @@ #include "detect-content.h" #include "detect-uricontent.h" -#include "util-hash.h" -#include "util-time.h" -#include "util-error.h" -#include "util-debug.h" +#include "util/hash.h" +#include "util/time.h" +#include "util/error.h" +#include "util/debug.h" -#include "util-var-name.h" +#include "util/var-name.h" #include "tm-threads.h" #include "action-globals.h" @@ -84,7 +84,8 @@ void ThresholdInit(void) if (host_threshold_id.id == -1) { FatalError("Can't initiate host storage for thresholding"); } - ippair_threshold_id = IPPairStorageRegister("threshold", sizeof(void *), NULL, ThresholdListFree); + ippair_threshold_id = + IPPairStorageRegister("threshold", sizeof(void *), NULL, ThresholdListFree); if (ippair_threshold_id.id == -1) { FatalError("Can't initiate IP pair storage for thresholding"); } @@ -178,8 +179,7 @@ static DetectThresholdEntry *ThresholdTimeoutCheck(DetectThresholdEntry *head, S DetectThresholdEntry *tde = tmp; if (prev != NULL) { prev->next = tmp->next; - } - else { + } else { new_head = tmp->next; } tmp = tde->next; @@ -191,7 +191,7 @@ static DetectThresholdEntry *ThresholdTimeoutCheck(DetectThresholdEntry *head, S int ThresholdHostTimeoutCheck(Host *host, SCTime_t ts) { - DetectThresholdEntry* head = HostGetStorageById(host, host_threshold_id); + DetectThresholdEntry *head = HostGetStorageById(host, host_threshold_id); DetectThresholdEntry *new_head = ThresholdTimeoutCheck(head, ts); if (new_head != head) { HostSetStorageById(host, host_threshold_id, new_head); @@ -201,7 +201,7 @@ int ThresholdHostTimeoutCheck(Host *host, SCTime_t ts) int ThresholdIPPairTimeoutCheck(IPPair *pair, SCTime_t ts) { - DetectThresholdEntry* head = IPPairGetStorageById(pair, ippair_threshold_id); + DetectThresholdEntry *head = IPPairGetStorageById(pair, ippair_threshold_id); DetectThresholdEntry *new_head = ThresholdTimeoutCheck(head, ts); if (new_head != head) { IPPairSetStorageById(pair, ippair_threshold_id, new_head); @@ -209,9 +209,8 @@ int ThresholdIPPairTimeoutCheck(IPPair *pair, SCTime_t ts) return new_head == NULL; } -static DetectThresholdEntry * -DetectThresholdEntryAlloc(const DetectThresholdData *td, Packet *p, - uint32_t sid, uint32_t gid) +static DetectThresholdEntry *DetectThresholdEntryAlloc( + const DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) { SCEnter(); @@ -228,8 +227,7 @@ DetectThresholdEntryAlloc(const DetectThresholdData *td, Packet *p, SCReturnPtr(ste, "DetectThresholdEntry"); } -static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, - uint32_t sid, uint32_t gid) +static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, uint32_t sid, uint32_t gid) { DetectThresholdEntry *e; @@ -241,8 +239,7 @@ static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, return e; } -static DetectThresholdEntry *ThresholdIPPairLookupEntry(IPPair *pair, - uint32_t sid, uint32_t gid) +static DetectThresholdEntry *ThresholdIPPairLookupEntry(IPPair *pair, uint32_t sid, uint32_t gid) { DetectThresholdEntry *e; @@ -254,8 +251,8 @@ static DetectThresholdEntry *ThresholdIPPairLookupEntry(IPPair *pair, return e; } -static int ThresholdHandlePacketSuppress(Packet *p, - const DetectThresholdData *td, uint32_t sid, uint32_t gid) +static int ThresholdHandlePacketSuppress( + Packet *p, const DetectThresholdData *td, uint32_t sid, uint32_t gid) { int ret = 0; DetectAddress *m = NULL; @@ -315,22 +312,22 @@ static inline void RateFilterSetAction(Packet *p, PacketAlert *pa, uint8_t new_a } /** -* \brief Check if the entry reached threshold count limit -* -* \param lookup_tsh Current threshold entry -* \param td Threshold settings -* \param packet_time used to compare against previous detection and to set timeouts -* -* \retval int 1 if threshold reached for this entry -* -*/ + * \brief Check if the entry reached threshold count limit + * + * \param lookup_tsh Current threshold entry + * \param td Threshold settings + * \param packet_time used to compare against previous detection and to set timeouts + * + * \retval int 1 if threshold reached for this entry + * + */ static int IsThresholdReached( DetectThresholdEntry *lookup_tsh, const DetectThresholdData *td, SCTime_t packet_time) { int ret = 0; /* Check if we have a timeout enabled, if so, - * we still matching (and enabling the new_action) */ + * we still matching (and enabling the new_action) */ if (lookup_tsh->tv_timeout != 0) { if ((SCTIME_SECS(packet_time) - lookup_tsh->tv_timeout) > td->timeout) { /* Ok, we are done, timeout reached */ @@ -340,15 +337,14 @@ static int IsThresholdReached( ret = 1; } /* else - if ((packet_time - lookup_tsh->tv_timeout) > td->timeout) */ - } - else { + } else { /* Update the matching state with the timeout interval */ SCTime_t entry = SCTIME_ADD_SECS(lookup_tsh->tv1, td->seconds); if (SCTIME_CMP_LTE(packet_time, entry)) { lookup_tsh->current_count++; if (lookup_tsh->current_count > td->count) { /* Then we must enable the new action by setting a - * timeout */ + * timeout */ lookup_tsh->tv_timeout = SCTIME_SECS(packet_time); ret = 1; } @@ -392,17 +388,16 @@ static void AddEntryToIPPairStorage(IPPair *pair, DetectThresholdEntry *e, SCTim * for this rule, then it will be returned in new_tsh. */ static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh, - DetectThresholdEntry **new_tsh, const DetectThresholdData *td, - uint32_t sid, uint32_t gid, PacketAlert *pa) + DetectThresholdEntry **new_tsh, const DetectThresholdData *td, uint32_t sid, uint32_t gid, + PacketAlert *pa) { int ret = 0; - switch(td->type) { - case TYPE_LIMIT: - { + switch (td->type) { + case TYPE_LIMIT: { SCLogDebug("limit"); - if (lookup_tsh != NULL) { + if (lookup_tsh != NULL) { SCTime_t entry = SCTIME_ADD_SECS(lookup_tsh->tv1, td->seconds); if (SCTIME_CMP_LTE(p->ts, entry)) { lookup_tsh->current_count++; @@ -425,11 +420,10 @@ static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh, } break; } - case TYPE_THRESHOLD: - { + case TYPE_THRESHOLD: { SCLogDebug("threshold"); - if (lookup_tsh != NULL) { + if (lookup_tsh != NULL) { SCTime_t entry = SCTIME_ADD_SECS(lookup_tsh->tv1, td->seconds); if (SCTIME_CMP_LTE(p->ts, entry)) { lookup_tsh->current_count++; @@ -443,7 +437,7 @@ static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh, lookup_tsh->current_count = 1; } } else { - if (td->count == 1) { + if (td->count == 1) { ret = 1; } else { *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid); @@ -451,8 +445,7 @@ static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh, } break; } - case TYPE_BOTH: - { + case TYPE_BOTH: { SCLogDebug("both"); if (lookup_tsh != NULL) { @@ -482,15 +475,14 @@ static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh, /* for the first match we return 1 to * indicate we should alert */ - if (td->count == 1) { + if (td->count == 1) { ret = 1; } } break; } /* detection_filter */ - case TYPE_DETECTION: - { + case TYPE_DETECTION: { SCLogDebug("detection_filter"); if (lookup_tsh != NULL) { @@ -512,8 +504,7 @@ static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh, break; } /* rate_filter */ - case TYPE_RATE: - { + case TYPE_RATE: { SCLogDebug("rate_filter"); ret = 1; if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts)) { @@ -531,7 +522,7 @@ static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh, } static int ThresholdHandlePacketIPPair(IPPair *pair, Packet *p, const DetectThresholdData *td, - uint32_t sid, uint32_t gid, PacketAlert *pa) + uint32_t sid, uint32_t gid, PacketAlert *pa) { int ret = 0; @@ -572,7 +563,7 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, { int ret = 0; - DetectThresholdEntry* lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num]; + DetectThresholdEntry *lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num]; SCLogDebug("by_rule lookup_tsh %p num %u", lookup_tsh, s->num); DetectThresholdEntry *new_tsh = NULL; @@ -610,17 +601,17 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx } if (td->type == TYPE_SUPPRESS) { - ret = ThresholdHandlePacketSuppress(p,td,s->id,s->gid); + ret = ThresholdHandlePacketSuppress(p, td, s->id, s->gid); } else if (td->track == TRACK_SRC) { Host *src = HostGetHostFromHash(&p->src); if (src) { - ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid,pa); + ret = ThresholdHandlePacketHost(src, p, td, s->id, s->gid, pa); HostRelease(src); } } else if (td->track == TRACK_DST) { Host *dst = HostGetHostFromHash(&p->dst); if (dst) { - ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid,pa); + ret = ThresholdHandlePacketHost(dst, p, td, s->id, s->gid, pa); HostRelease(dst); } } else if (td->track == TRACK_BOTH) { @@ -631,7 +622,7 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx } } else if (td->track == TRACK_RULE) { SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock); - ret = ThresholdHandlePacketRule(de_ctx,p,td,s,pa); + ret = ThresholdHandlePacketRule(de_ctx, p, td, s, pa); SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock); } diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index 6fd7a9feaa58..5bedb17ad53b 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -39,9 +39,8 @@ int ThresholdIPPairHasThreshold(IPPair *pair); const DetectThresholdData *SigGetThresholdTypeIter( const Signature *, const SigMatchData **, int list); -int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, - const DetectThresholdData *, Packet *, - const Signature *, PacketAlert *); +int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, const DetectThresholdData *, + Packet *, const Signature *, PacketAlert *); void ThresholdHashInit(DetectEngineCtx *); void ThresholdHashAllocate(DetectEngineCtx *); diff --git a/src/detect-engine-uint.c b/src/detect-engine-uint.c index a02552bcd9de..006afc5d900a 100644 --- a/src/detect-engine-uint.c +++ b/src/detect-engine-uint.c @@ -24,7 +24,7 @@ #include "suricata-common.h" -#include "util-byte.h" +#include "util/byte.h" #include "detect-parse.h" #include "detect-engine-uint.h" @@ -47,8 +47,7 @@ DetectUintData_u32 *DetectU32Parse(const char *u32str) return rs_detect_u32_parse(u32str); } -void -PrefilterPacketU32Set(PrefilterPacketHeaderValue *v, void *smctx) +void PrefilterPacketU32Set(PrefilterPacketHeaderValue *v, void *smctx) { const DetectUintData_u32 *a = smctx; v->u8[0] = a->mode; @@ -56,18 +55,15 @@ PrefilterPacketU32Set(PrefilterPacketHeaderValue *v, void *smctx) v->u32[2] = a->arg2; } -bool -PrefilterPacketU32Compare(PrefilterPacketHeaderValue v, void *smctx) +bool PrefilterPacketU32Compare(PrefilterPacketHeaderValue v, void *smctx) { const DetectUintData_u32 *a = smctx; - if (v.u8[0] == a->mode && - v.u32[1] == a->arg1 && - v.u32[2] == a->arg2) + if (v.u8[0] == a->mode && v.u32[1] == a->arg1 && v.u32[2] == a->arg2) return true; return false; } -//same as u32 but with u8 +// same as u32 but with u8 int DetectU8Match(const uint8_t parg, const DetectUintData_u8 *du8) { return rs_detect_u8_match(parg, du8); diff --git a/src/detect-engine.c b/src/detect-engine.c index a4ce2126544d..dc7afd7a4cbd 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -33,7 +33,7 @@ #include "datasets.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "detect-parse.h" #include "detect-engine-sigorder.h" @@ -63,26 +63,26 @@ #include "detect-engine-loader.h" -#include "util-classification-config.h" -#include "util-reference-config.h" -#include "util-threshold-config.h" -#include "util-error.h" -#include "util-hash.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-action.h" -#include "util-magic.h" -#include "util-signal.h" -#include "util-spm.h" -#include "util-device.h" -#include "util-var-name.h" -#include "util-path.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-hash-string.h" -#include "util-enum.h" -#include "util-conf.h" +#include "util/classification-config.h" +#include "util/reference-config.h" +#include "util/threshold-config.h" +#include "util/error.h" +#include "util/hash.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/action.h" +#include "util/magic.h" +#include "util/signal.h" +#include "util/spm.h" +#include "util/device.h" +#include "util/var-name.h" +#include "util/path.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/hash-string.h" +#include "util/enum.h" +#include "util/conf.h" #include "tm-threads.h" #include "runmodes.h" @@ -93,8 +93,8 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *); -static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, - 0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0}; +static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, 99, NULL, NULL, + TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0 }; static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len); static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len); @@ -125,8 +125,7 @@ const struct SignatureProperties signature_properties[SIG_TYPE_MAX] = { /** \brief register inspect engine at start up time * * \note errors are fatal */ -void DetectPktInspectEngineRegister(const char *name, - InspectionBufferGetPktDataPtr GetPktData, +void DetectPktInspectEngineRegister(const char *name, InspectionBufferGetPktDataPtr GetPktData, InspectionBufferPktInspectFunc Callback) { DetectBufferTypeRegister(name); @@ -135,9 +134,7 @@ void DetectPktInspectEngineRegister(const char *name, FatalError("failed to register inspect engine %s", name); } - if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || - (Callback == NULL)) - { + if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (Callback == NULL)) { SCLogError("Invalid arguments"); BUG_ON(1); } @@ -213,10 +210,8 @@ void DetectFrameInspectEngineRegister(const char *name, int dir, /** \brief register inspect engine at start up time * * \note errors are fatal */ -void DetectAppLayerInspectEngineRegister2(const char *name, - AppProto alproto, uint32_t dir, int progress, - InspectEngineFuncPtr2 Callback2, - InspectionBufferGetDataPtr GetData) +void DetectAppLayerInspectEngineRegister2(const char *name, AppProto alproto, uint32_t dir, + int progress, InspectEngineFuncPtr2 Callback2, InspectionBufferGetDataPtr GetData) { BUG_ON(progress >= 48); @@ -227,12 +222,9 @@ void DetectAppLayerInspectEngineRegister2(const char *name, } SCLogDebug("name %s id %d", name, sm_list); - 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) || - (Callback2 == NULL)) - { + 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) || (Callback2 == NULL)) { SCLogError("Invalid arguments"); BUG_ON(1); } else if (Callback2 == DetectEngineInspectBufferGeneric && GetData == NULL) { @@ -274,15 +266,14 @@ void DetectAppLayerInspectEngineRegister2(const char *name, } /* copy an inspect engine with transforms to a new list id. */ -static void DetectAppLayerInspectEngineCopy( - DetectEngineCtx *de_ctx, - int sm_list, int new_list, +static void DetectAppLayerInspectEngineCopy(DetectEngineCtx *de_ctx, int sm_list, int new_list, const DetectEngineTransforms *transforms) { const DetectEngineAppInspectionEngine *t = g_app_inspect_engines; while (t) { if (t->sm_list == sm_list) { - DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); + DetectEngineAppInspectionEngine *new_engine = + SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } @@ -317,7 +308,8 @@ static void DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_c const DetectEngineAppInspectionEngine *t = g_app_inspect_engines; DetectEngineAppInspectionEngine *list = de_ctx->app_inspect_engines; while (t) { - DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); + DetectEngineAppInspectionEngine *new_engine = + SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } @@ -340,15 +332,14 @@ static void DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_c } /* copy an inspect engine with transforms to a new list id. */ -static void DetectPktInspectEngineCopy( - DetectEngineCtx *de_ctx, - int sm_list, int new_list, +static void DetectPktInspectEngineCopy(DetectEngineCtx *de_ctx, int sm_list, int new_list, const DetectEngineTransforms *transforms) { const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines; while (t) { if (t->sm_list == sm_list) { - DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine)); + DetectEnginePktInspectionEngine *new_engine = + SCCalloc(1, sizeof(DetectEnginePktInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } @@ -380,7 +371,8 @@ static void DetectPktInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx) const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines; while (t) { SCLogDebug("engine %p", t); - DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine)); + DetectEnginePktInspectionEngine *new_engine = + SCCalloc(1, sizeof(DetectEnginePktInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } @@ -528,7 +520,8 @@ static void AppendStreamInspectEngine( { bool prepend = false; - DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); + DetectEngineAppInspectionEngine *new_engine = + SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); if (unlikely(new_engine == NULL)) { exit(EXIT_FAILURE); } @@ -801,8 +794,7 @@ int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature } if ((s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) && - s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) - { + s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { /* if engine is added multiple times, we pass it the same list */ SigMatchData *stream = SigMatchList2DataArray(s->init_data->smlists[DETECT_SM_LIST_PMATCH]); BUG_ON(stream == NULL); @@ -942,7 +934,7 @@ void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signa /* code for registering buffers */ -#include "util-hash-lookup3.h" +#include "util/hash-lookup3.h" static HashListTable *g_buffer_type_hash = NULL; static int g_buffer_type_id = DETECT_SM_LIST_DYNAMIC_START; @@ -976,7 +968,8 @@ static char DetectBufferTypeCompareNameFunc(void *data1, uint16_t len1, void *da DetectBufferType *map2 = (DetectBufferType *)data2; char r = (strcmp(map1->name, map2->name) == 0); - r &= (memcmp((uint8_t *)&map1->transforms, (uint8_t *)&map2->transforms, sizeof(map2->transforms)) == 0); + r &= (memcmp((uint8_t *)&map1->transforms, (uint8_t *)&map2->transforms, + sizeof(map2->transforms)) == 0); return r; } @@ -1004,7 +997,8 @@ static void DetectBufferTypeFreeFunc(void *data) sigmatch_table[map->transforms.transforms[i].transform].name); continue; } - sigmatch_table[map->transforms.transforms[i].transform].Free(NULL, map->transforms.transforms[i].options); + sigmatch_table[map->transforms.transforms[i].transform].Free( + NULL, map->transforms.transforms[i].options); } SCFree(map); @@ -1315,8 +1309,8 @@ bool DetectEngineBufferTypeSupportsFramesGetById(const DetectEngineCtx *de_ctx, return map->frame; } -void DetectBufferTypeRegisterSetupCallback(const char *name, - void (*SetupCallback)(const DetectEngineCtx *, Signature *)) +void DetectBufferTypeRegisterSetupCallback( + const char *name, void (*SetupCallback)(const DetectEngineCtx *, Signature *)) { BUG_ON(g_buffer_type_reg_closed); DetectBufferTypeRegister(name); @@ -1333,8 +1327,8 @@ void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int } } -void DetectBufferTypeRegisterValidateCallback(const char *name, - bool (*ValidateCallback)(const Signature *, const char **sigerror)) +void DetectBufferTypeRegisterValidateCallback( + const char *name, bool (*ValidateCallback)(const Signature *, const char **sigerror)) { BUG_ON(g_buffer_type_reg_closed); DetectBufferTypeRegister(name); @@ -1458,15 +1452,15 @@ int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s) if (s->init_data->list && s->init_data->transforms.cnt) { if (s->init_data->list == DETECT_SM_LIST_NOTSET || - s->init_data->list < DETECT_SM_LIST_DYNAMIC_START) { + s->init_data->list < DETECT_SM_LIST_DYNAMIC_START) { SCLogError("previous transforms not consumed " "(list: %u, transform_cnt %u)", s->init_data->list, s->init_data->transforms.cnt); SCReturnInt(-1); } - SCLogDebug("buffer %d has transform(s) registered: %d", - s->init_data->list, s->init_data->transforms.cnt); + SCLogDebug("buffer %d has transform(s) registered: %d", s->init_data->list, + s->init_data->transforms.cnt); int new_list = DetectEngineBufferTypeGetByIdTransforms(de_ctx, s->init_data->list, s->init_data->transforms.transforms, s->init_data->transforms.cnt); if (new_list == -1) { @@ -1503,8 +1497,7 @@ int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s) void InspectionBufferClean(DetectEngineThreadCtx *det_ctx) { /* single buffers */ - for (uint32_t i = 0; i < det_ctx->inspect.to_clear_idx; i++) - { + for (uint32_t i = 0; i < det_ctx->inspect.to_clear_idx; i++) { const uint32_t idx = det_ctx->inspect.to_clear_queue[i]; InspectionBuffer *buffer = &det_ctx->inspect.buffers[idx]; buffer->inspect = NULL; @@ -1513,8 +1506,7 @@ void InspectionBufferClean(DetectEngineThreadCtx *det_ctx) det_ctx->inspect.to_clear_idx = 0; /* multi buffers */ - for (uint32_t i = 0; i < det_ctx->multi_inspect.to_clear_idx; i++) - { + for (uint32_t i = 0; i < det_ctx->multi_inspect.to_clear_idx; i++) { const uint32_t idx = det_ctx->multi_inspect.to_clear_queue[i]; InspectionBufferMultipleForList *mbuffer = &det_ctx->multi_inspect.buffers[idx]; for (uint32_t x = 0; x <= mbuffer->max; x++) { @@ -1727,8 +1719,8 @@ bool DetectEngineBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_lis return true; } -void InspectionBufferApplyTransforms(InspectionBuffer *buffer, - const DetectEngineTransforms *transforms) +void InspectionBufferApplyTransforms( + InspectionBuffer *buffer, const DetectEngineTransforms *transforms) { if (transforms) { for (int i = 0; i < DETECT_TRANSFORMS_MAX; i++) { @@ -1888,11 +1880,9 @@ int DetectEngineBufferTypeGetByIdTransforms( if (map->frame) { DetectFrameMpmRegisterByParentId(de_ctx, map->id, map->parent_id, &map->transforms); } else if (map->packet) { - DetectPktMpmRegisterByParentId(de_ctx, - map->id, map->parent_id, &map->transforms); + DetectPktMpmRegisterByParentId(de_ctx, map->id, map->parent_id, &map->transforms); } else { - DetectAppLayerMpmRegisterByParentId(de_ctx, - map->id, map->parent_id, &map->transforms); + DetectAppLayerMpmRegisterByParentId(de_ctx, map->id, map->parent_id, &map->transforms); } BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_name, (void *)map, 0) != 0); @@ -1910,11 +1900,9 @@ int DetectEngineBufferTypeGetByIdTransforms( } /* returns false if no match, true if match */ -static int DetectEngineInspectRulePacketMatches( - DetectEngineThreadCtx *det_ctx, - const DetectEnginePktInspectionEngine *engine, - const Signature *s, - Packet *p, uint8_t *_alert_flags) +static int DetectEngineInspectRulePacketMatches(DetectEngineThreadCtx *det_ctx, + const DetectEnginePktInspectionEngine *engine, const Signature *s, Packet *p, + uint8_t *_alert_flags) { SCEnter(); @@ -1940,10 +1928,9 @@ static int DetectEngineInspectRulePacketMatches( return DETECT_ENGINE_INSPECT_SIG_MATCH; } -static int DetectEngineInspectRulePayloadMatches( - DetectEngineThreadCtx *det_ctx, - const DetectEnginePktInspectionEngine *engine, - const Signature *s, Packet *p, uint8_t *alert_flags) +static int DetectEngineInspectRulePayloadMatches(DetectEngineThreadCtx *det_ctx, + const DetectEnginePktInspectionEngine *engine, const Signature *s, Packet *p, + uint8_t *alert_flags) { SCEnter(); @@ -1986,10 +1973,8 @@ static int DetectEngineInspectRulePayloadMatches( return DETECT_ENGINE_INSPECT_SIG_MATCH; } -bool DetectEnginePktInspectionRun(ThreadVars *tv, - DetectEngineThreadCtx *det_ctx, const Signature *s, - Flow *f, Packet *p, - uint8_t *alert_flags) +bool DetectEnginePktInspectionRun(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, + const Signature *s, Flow *f, Packet *p, uint8_t *alert_flags) { SCEnter(); @@ -2037,7 +2022,8 @@ static int DetectEnginePktInspectionAppend(Signature *s, InspectionBufferPktInsp int DetectEnginePktInspectionSetup(Signature *s) { /* only handle PMATCH here if we're not an app inspect rule */ - if (s->sm_arrays[DETECT_SM_LIST_PMATCH] && (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) == 0) { + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] && + (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) == 0) { if (DetectEnginePktInspectionAppend( s, DetectEngineInspectRulePayloadMatches, NULL, DETECT_SM_LIST_PMATCH) < 0) return -1; @@ -2061,7 +2047,6 @@ enum DetectEngineSyncState { RELOAD, /**< command main thread to do the reload */ }; - typedef struct DetectEngineSyncer_ { SCMutex m; enum DetectEngineSyncState state; @@ -2138,8 +2123,8 @@ uint8_t DetectEngineInspectGenericList(DetectEngineCtx *de_ctx, DetectEngineThre while (1) { int match = 0; KEYWORD_PROFILING_START; - match = sigmatch_table[smd->type]. - AppLayerTxMatch(det_ctx, f, flags, alstate, txv, s, smd->ctx); + match = sigmatch_table[smd->type].AppLayerTxMatch( + det_ctx, f, flags, alstate, txv, s, smd->ctx); KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); if (match == 0) return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -2156,7 +2141,6 @@ uint8_t DetectEngineInspectGenericList(DetectEngineCtx *de_ctx, DetectEngineThre return DETECT_ENGINE_INSPECT_SIG_MATCH; } - /** * \brief Do the content inspection & validation for a signature * @@ -2178,10 +2162,11 @@ uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineTh const int list_id = engine->sm_list; SCLogDebug("running inspect on %d", list_id); - const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress); + const bool eof = + (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress); - SCLogDebug("list %d mpm? %s transforms %p", - engine->sm_list, engine->mpm ? "true" : "false", engine->v2.transforms); + SCLogDebug("list %d mpm? %s transforms %p", engine->sm_list, engine->mpm ? "true" : "false", + engine->v2.transforms); /* if prefilter didn't already run, we need to consider transformations */ const DetectEngineTransforms *transforms = NULL; @@ -2189,11 +2174,10 @@ uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineTh transforms = engine->v2.transforms; } - const InspectionBuffer *buffer = engine->v2.GetData(det_ctx, transforms, - f, flags, txv, list_id); + const InspectionBuffer *buffer = + engine->v2.GetData(det_ctx, transforms, f, flags, txv, list_id); if (unlikely(buffer == NULL)) { - return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : - DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } const uint32_t data_len = buffer->inspect_len; @@ -2212,8 +2196,7 @@ uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineTh if (match) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { - return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : - DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } } @@ -2228,16 +2211,14 @@ uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineTh * \retval 0 no match. * \retval 1 match. */ -int DetectEngineInspectPktBufferGeneric( - DetectEngineThreadCtx *det_ctx, - const DetectEnginePktInspectionEngine *engine, - const Signature *s, Packet *p, uint8_t *_alert_flags) +int DetectEngineInspectPktBufferGeneric(DetectEngineThreadCtx *det_ctx, + const DetectEnginePktInspectionEngine *engine, const Signature *s, Packet *p, + uint8_t *_alert_flags) { const int list_id = engine->sm_list; SCLogDebug("running inspect on %d", list_id); - SCLogDebug("list %d transforms %p", - engine->sm_list, engine->v1.transforms); + SCLogDebug("list %d transforms %p", engine->sm_list, engine->v1.transforms); /* if prefilter didn't already run, we need to consider transformations */ const DetectEngineTransforms *transforms = NULL; @@ -2245,13 +2226,12 @@ int DetectEngineInspectPktBufferGeneric( transforms = engine->v1.transforms; } - const InspectionBuffer *buffer = engine->v1.GetData(det_ctx, transforms, p, - list_id); + const InspectionBuffer *buffer = engine->v1.GetData(det_ctx, transforms, p, list_id); if (unlikely(buffer == NULL)) { return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } - uint8_t ci_flags = DETECT_CI_FLAGS_START|DETECT_CI_FLAGS_END; + uint8_t ci_flags = DETECT_CI_FLAGS_START | DETECT_CI_FLAGS_END; ci_flags |= buffer->flags; /* Inspect all the uricontents fetched on each @@ -2270,9 +2250,8 @@ int DetectEngineInspectPktBufferGeneric( * \brief inject a pseudo packet into each detect thread that doesn't use the * new det_ctx yet */ -static void InjectPackets(ThreadVars **detect_tvs, - DetectEngineThreadCtx **new_det_ctx, - int no_of_detect_tvs) +static void InjectPackets( + ThreadVars **detect_tvs, DetectEngineThreadCtx **new_det_ctx, int no_of_detect_tvs) { /* inject a fake packet if the detect thread isn't using the new ctx yet, * this speeds up the process */ @@ -2357,7 +2336,8 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) goto error; } SCLogDebug("live rule swap created new det_ctx - %p and de_ctx " - "- %p\n", new_det_ctx[i], new_de_ctx); + "- %p\n", + new_det_ctx[i], new_de_ctx); i++; break; } @@ -2375,8 +2355,8 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) if (!(tm->flags & TM_FLAG_DETECT_TM)) { continue; } - SCLogDebug("swapping new det_ctx - %p with older one - %p", - new_det_ctx[i], SC_ATOMIC_GET(s->slot_data)); + SCLogDebug("swapping new det_ctx - %p with older one - %p", new_det_ctx[i], + SC_ATOMIC_GET(s->slot_data)); FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(s->slot_data), new_det_ctx[i++]); break; } @@ -2387,7 +2367,8 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) * it and may still use the old data */ SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, " - "along with the new de_ctx", no_of_detect_tvs); + "along with the new de_ctx", + no_of_detect_tvs); InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs); @@ -2433,8 +2414,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) /* free all the ctxs */ for (i = 0; i < no_of_detect_tvs; i++) { - SCLogDebug("Freeing old_det_ctx - %p used by detect", - old_det_ctx[i]); + SCLogDebug("Freeing old_det_ctx - %p used by detect", old_det_ctx[i]); DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]); } @@ -2442,7 +2422,7 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) return 1; - error: +error: for (i = 0; i < no_of_detect_tvs; i++) { if (new_det_ctx[i] != NULL) DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]); @@ -2482,9 +2462,8 @@ static DetectEngineCtx *DetectEngineCtxInitReal( de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher(); - SCLogConfig("pattern matchers: MPM: %s, SPM: %s", - mpm_table[de_ctx->mpm_matcher].name, - spm_table[de_ctx->spm_matcher].name); + SCLogConfig("pattern matchers: MPM: %s, SPM: %s", mpm_table[de_ctx->mpm_matcher].name, + spm_table[de_ctx->spm_matcher].name); de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher); if (de_ctx->spm_global_thread_ctx == NULL) { @@ -2531,7 +2510,6 @@ static DetectEngineCtx *DetectEngineCtxInitReal( DetectEngineCtxFree(de_ctx); } return NULL; - } DetectEngineCtx *DetectEngineCtxInitStubForMT(void) @@ -2567,7 +2545,7 @@ static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx) SigString *item = NULL; SigString *sitem; - TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) { + TAILQ_FOREACH_SAFE (item, &de_ctx->sig_stat.failed_sigs, next, sitem) { SCFree(item->filename); SCFree(item->sig_str); if (item->sig_error) { @@ -2597,8 +2575,8 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) #endif #ifdef PROFILING if (de_ctx->profile_keyword_ctx != NULL) { - SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx); -// de_ctx->profile_keyword_ctx = NULL; + SCProfilingKeywordDestroyCtx(de_ctx); //->profile_keyword_ctx); + // de_ctx->profile_keyword_ctx = NULL; } if (de_ctx->profile_sgh_ctx != NULL) { SCProfilingSghDestroyCtx(de_ctx); @@ -2659,9 +2637,9 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) } SCFree(de_ctx); - //DetectAddressGroupPrintMemory(); - //DetectSigGroupPrintMemory(); - //DetectPortPrintMemory(); + // DetectAddressGroupPrintMemory(); + // DetectSigGroupPrintMemory(); + // DetectPortPrintMemory(); } /** \brief Function that load DetectEngineCtx config for grouping sigs @@ -2684,7 +2662,7 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) ConfNode *opt = NULL; if (de_ctx_custom != NULL) { - TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { + TAILQ_FOREACH (opt, &de_ctx_custom->head, next) { if (de_ctx_profile == NULL) { if (opt->val && strcmp(opt->val, "profile") == 0) { de_ctx_profile = opt->head.tqh_first->val; @@ -2700,8 +2678,7 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } if (de_ctx_profile != NULL) { - if (strcmp(de_ctx_profile, "low") == 0 || - strcmp(de_ctx_profile, "lowest") == 0) { // legacy + if (strcmp(de_ctx_profile, "low") == 0 || strcmp(de_ctx_profile, "lowest") == 0) { // legacy profile = ENGINE_PROFILE_LOW; } else if (strcmp(de_ctx_profile, "medium") == 0) { profile = ENGINE_PROFILE_MEDIUM; @@ -2765,29 +2742,27 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) break; case ENGINE_PROFILE_CUSTOM: - (void)ConfGet("detect.custom-values.toclient-groups", - &max_uniq_toclient_groups_str); - (void)ConfGet("detect.custom-values.toserver-groups", - &max_uniq_toserver_groups_str); + (void)ConfGet("detect.custom-values.toclient-groups", &max_uniq_toclient_groups_str); + (void)ConfGet("detect.custom-values.toserver-groups", &max_uniq_toserver_groups_str); if (de_ctx_custom != NULL) { - TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { + TAILQ_FOREACH (opt, &de_ctx_custom->head, next) { if (opt->val && strcmp(opt->val, "custom-values") == 0) { if (max_uniq_toclient_groups_str == NULL) { - max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-sp-groups"); + max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue( + opt->head.tqh_first, "toclient-sp-groups"); } if (max_uniq_toclient_groups_str == NULL) { - max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-groups"); + max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue( + opt->head.tqh_first, "toclient-groups"); } if (max_uniq_toserver_groups_str == NULL) { - max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-dp-groups"); + max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue( + opt->head.tqh_first, "toserver-dp-groups"); } if (max_uniq_toserver_groups_str == NULL) { - max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-groups"); + max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue( + opt->head.tqh_first, "toserver-groups"); } } } @@ -2833,20 +2808,19 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } intmax_t value = 0; - if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1) - { + if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1) { if (value >= 0 && value <= INT_MAX) { de_ctx->inspection_recursion_limit = (int)value; } - /* fall back to old config parsing */ + /* fall back to old config parsing */ } else { ConfNode *insp_recursion_limit_node = NULL; char *insp_recursion_limit = NULL; if (de_ctx_custom != NULL) { opt = NULL; - TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { + TAILQ_FOREACH (opt, &de_ctx_custom->head, next) { if (opt->val && strcmp(opt->val, "inspection-recursion-limit") != 0) continue; @@ -2863,18 +2837,18 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } if (insp_recursion_limit != NULL) { - if (StringParseInt32(&de_ctx->inspection_recursion_limit, 10, - 0, (const char *)insp_recursion_limit) < 0) { + if (StringParseInt32(&de_ctx->inspection_recursion_limit, 10, 0, + (const char *)insp_recursion_limit) < 0) { SCLogWarning("Invalid value for " "detect-engine.inspection-recursion-limit: %s " "resetting to %d", insp_recursion_limit, DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT); de_ctx->inspection_recursion_limit = - DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; + DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; } } else { de_ctx->inspection_recursion_limit = - DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; + DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; } } } @@ -2882,8 +2856,7 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) if (de_ctx->inspection_recursion_limit == 0) de_ctx->inspection_recursion_limit = -1; - SCLogDebug("de_ctx->inspection_recursion_limit: %d", - de_ctx->inspection_recursion_limit); + SCLogDebug("de_ctx->inspection_recursion_limit: %d", de_ctx->inspection_recursion_limit); /* parse port grouping whitelisting settings */ @@ -2894,7 +2867,6 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } else { ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080"; SCLogConfig("grouping: tcp-whitelist (default) %s", ports); - } if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) { SCLogWarning("'%s' is not a valid value " @@ -2902,7 +2874,7 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) ports); } DetectPort *x = de_ctx->tcp_whitelist; - for ( ; x != NULL; x = x->next) { + for (; x != NULL; x = x->next) { if (x->port != x->port2) { SCLogWarning("'%s' is not a valid value " "for detect.grouping.tcp-whitelist: only single ports allowed", @@ -2920,14 +2892,13 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) } else { ports = "53, 135, 5060"; SCLogConfig("grouping: udp-whitelist (default) %s", ports); - } if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) { SCLogWarning("'%s' is not a valid value " "for detect.grouping.udp-whitelist", ports); } - for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) { + for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) { if (x->port != x->port2) { SCLogWarning("'%s' is not a valid value " "for detect.grouping.udp-whitelist: only single ports allowed", @@ -2963,10 +2934,10 @@ static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) * getting & (re)setting the internal sig i */ -//inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx) +// inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx) //{ -// return de_ctx->signum; -//} +// return de_ctx->signum; +// } void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx) { @@ -3003,8 +2974,7 @@ static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ct static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx) { - if (det_ctx->global_keyword_ctxs_array == NULL || - det_ctx->global_keyword_ctxs_size == 0) { + if (det_ctx->global_keyword_ctxs_array == NULL || det_ctx->global_keyword_ctxs_size == 0) { return; } @@ -3023,7 +2993,8 @@ static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det } } -static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) +static int DetectEngineThreadCtxInitKeywords( + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { if (de_ctx->keyword_id > 0) { // coverity[suspicious_sizeof : FALSE] @@ -3051,7 +3022,8 @@ static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngi return TM_ECODE_OK; } -static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) +static void DetectEngineThreadCtxDeinitKeywords( + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { if (de_ctx->keyword_id > 0) { HashListTableBucket *hb = HashListTableGetListHead(de_ctx->keyword_hash); @@ -3128,7 +3100,6 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread map_cnt++; map = map->next; } - } /* set up hash for tenant lookup */ @@ -3186,7 +3157,7 @@ static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThread /** \internal * \brief Helper for DetectThread setup functions */ -static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) +static TmEcode ThreadCtxDoInit(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher); @@ -3200,7 +3171,7 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * /* sized to the max of our sgh settings. A max setting of 0 implies that all * sgh's have: sgh->non_pf_store_cnt == 0 */ if (de_ctx->non_pf_store_cnt_max > 0) { - det_ctx->non_pf_id_array = SCCalloc(de_ctx->non_pf_store_cnt_max, sizeof(SigIntId)); + det_ctx->non_pf_id_array = SCCalloc(de_ctx->non_pf_store_cnt_max, sizeof(SigIntId)); BUG_ON(det_ctx->non_pf_id_array == NULL); } @@ -3219,8 +3190,8 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * AlertQueueInit(det_ctx); /* byte_extract storage */ - det_ctx->byte_values = SCMalloc(sizeof(*det_ctx->byte_values) * - (de_ctx->byte_extract_max_local_id + 1)); + det_ctx->byte_values = + SCMalloc(sizeof(*det_ctx->byte_values) * (de_ctx->byte_extract_max_local_id + 1)); if (det_ctx->byte_values == NULL) { return TM_ECODE_FAILED; } @@ -3247,17 +3218,18 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * det_ctx->inspect.to_clear_idx = 0; det_ctx->multi_inspect.buffers_size = de_ctx->buffer_type_id; - det_ctx->multi_inspect.buffers = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(InspectionBufferMultipleForList)); + det_ctx->multi_inspect.buffers = + SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(InspectionBufferMultipleForList)); if (det_ctx->multi_inspect.buffers == NULL) { return TM_ECODE_FAILED; } - det_ctx->multi_inspect.to_clear_queue = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t)); + det_ctx->multi_inspect.to_clear_queue = + SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t)); if (det_ctx->multi_inspect.to_clear_queue == NULL) { return TM_ECODE_FAILED; } det_ctx->multi_inspect.to_clear_idx = 0; - DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx); DetectEngineThreadCtxInitGlobalKeywords(det_ctx); #ifdef PROFILE_RULES @@ -3313,8 +3285,7 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) } if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL || - det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT) - { + det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT) { if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { DetectEngineThreadCtxDeinit(tv, det_ctx); return TM_ECODE_FAILED; @@ -3371,8 +3342,7 @@ DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( /* most of the init happens here */ if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL || - det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT) - { + det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT) { if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { DetectEngineDeReference(&det_ctx->de_ctx); SCFree(det_ctx); @@ -3408,14 +3378,18 @@ DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) { -#if DEBUG - SCLogDebug("PACKET PKT_STREAM_ADD: %"PRIu64, det_ctx->pkt_stream_add_cnt); +#if DEBUG + SCLogDebug("PACKET PKT_STREAM_ADD: %" PRIu64, det_ctx->pkt_stream_add_cnt); - SCLogDebug("PAYLOAD MPM %"PRIu64"/%"PRIu64, det_ctx->payload_mpm_cnt, det_ctx->payload_mpm_size); - SCLogDebug("STREAM MPM %"PRIu64"/%"PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size); + SCLogDebug("PAYLOAD MPM %" PRIu64 "/%" PRIu64, det_ctx->payload_mpm_cnt, + det_ctx->payload_mpm_size); + SCLogDebug( + "STREAM MPM %" PRIu64 "/%" PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size); - SCLogDebug("PAYLOAD SIG %"PRIu64"/%"PRIu64, det_ctx->payload_persig_cnt, det_ctx->payload_persig_size); - SCLogDebug("STREAM SIG %"PRIu64"/%"PRIu64, det_ctx->stream_persig_cnt, det_ctx->stream_persig_size); + SCLogDebug("PAYLOAD SIG %" PRIu64 "/%" PRIu64, det_ctx->payload_persig_cnt, + det_ctx->payload_persig_size); + SCLogDebug("STREAM SIG %" PRIu64 "/%" PRIu64, det_ctx->stream_persig_cnt, + det_ctx->stream_persig_size); #endif if (det_ctx->tenant_array != NULL) { @@ -3563,7 +3537,8 @@ static void DetectKeywordCtxFreeFunc(void *ptr) * recommended to store it in the keywords global ctx so that * it's freed when the de_ctx is freed. */ -int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode) +int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, + void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode) { BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL); @@ -3641,7 +3616,6 @@ void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) return det_ctx->keyword_ctxs_array[id]; } - /** \brief Register Thread keyword context Funcs (Global) * * IDs stay static over reloads and between tenants @@ -3653,8 +3627,8 @@ void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) * \retval id for retrieval of ctx at runtime * \retval -1 on error */ -int DetectRegisterThreadCtxGlobalFuncs(const char *name, - void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)) +int DetectRegisterThreadCtxGlobalFuncs( + const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)) { int id; BUG_ON(InitFunc == NULL || FreeFunc == NULL); @@ -3700,7 +3674,7 @@ int DetectRegisterThreadCtxGlobalFuncs(const char *name, void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) { if (id < 0 || id > det_ctx->global_keyword_ctxs_size || - det_ctx->global_keyword_ctxs_array == NULL) { + det_ctx->global_keyword_ctxs_array == NULL) { return NULL; } @@ -3750,9 +3724,8 @@ DetectEngineCtx *DetectEngineGetCurrent(void) DetectEngineCtx *de_ctx = master->list; while (de_ctx) { if (de_ctx->type == DETECT_ENGINE_TYPE_NORMAL || - de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB || - de_ctx->type == DETECT_ENGINE_TYPE_MT_STUB) - { + de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB || + de_ctx->type == DETECT_ENGINE_TYPE_MT_STUB) { de_ctx->ref_cnt++; SCLogDebug("de_ctx %p ref_cnt %u", de_ctx, de_ctx->ref_cnt); SCMutexUnlock(&master->lock); @@ -3790,7 +3763,8 @@ int DetectEngineMultiTenantEnabled(void) * \retval 0 ok * \retval -1 failed */ -static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id) +static int DetectEngineMultiTenantLoadTenant( + uint32_t tenant_id, const char *filename, int loader_id) { DetectEngineCtx *de_ctx = NULL; char prefix[64]; @@ -3849,7 +3823,8 @@ static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *fil return -1; } -static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt) +static int DetectEngineMultiTenantReloadTenant( + uint32_t tenant_id, const char *filename, int reload_cnt) { DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id); if (old_de_ctx == NULL) { @@ -3910,7 +3885,6 @@ static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *f return -1; } - typedef struct TenantLoaderCtx_ { uint32_t tenant_id; int reload_cnt; /**< used by reload */ @@ -4068,14 +4042,14 @@ int DetectEngineReloadTenantsBlocking(const int reload_cnt) return 0; } -static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node, - bool failure_fatal) +static int DetectEngineMultiTenantSetupLoadLivedevMappings( + const ConfNode *mappings_root_node, bool failure_fatal) { ConfNode *mapping_node = NULL; int mapping_cnt = 0; if (mappings_root_node != NULL) { - TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) { + TAILQ_FOREACH (mapping_node, &mappings_root_node->head, next) { ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id"); if (tenant_id_node == NULL) goto bad_mapping; @@ -4127,14 +4101,14 @@ static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappi return 0; } -static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node, - bool failure_fatal) +static int DetectEngineMultiTenantSetupLoadVlanMappings( + const ConfNode *mappings_root_node, bool failure_fatal) { ConfNode *mapping_node = NULL; int mapping_cnt = 0; if (mappings_root_node != NULL) { - TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) { + TAILQ_FOREACH (mapping_node, &mappings_root_node->head, next) { ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id"); if (tenant_id_node == NULL) goto bad_mapping; @@ -4249,8 +4223,8 @@ int DetectEngineMultiTenantSetup(const bool unix_socket) ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings"); if (tenant_selector == TENANT_SELECTOR_VLAN) { - int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node, - failure_fatal); + int mapping_cnt = + DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node, failure_fatal); if (mapping_cnt == 0) { /* no mappings are valid when we're in unix socket mode, * they can be added on the fly. Otherwise warn/error @@ -4258,7 +4232,7 @@ int DetectEngineMultiTenantSetup(const bool unix_socket) if (unix_socket) { SCLogNotice("no tenant traffic mappings defined, " - "tenants won't be used until mappings are added"); + "tenants won't be used until mappings are added"); } else { if (failure_fatal) { SCLogError("no multi-detect mappings defined"); @@ -4269,8 +4243,8 @@ int DetectEngineMultiTenantSetup(const bool unix_socket) } } } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) { - int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node, - failure_fatal); + int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings( + mappings_root_node, failure_fatal); if (mapping_cnt == 0) { if (failure_fatal) { SCLogError("no multi-detect mappings defined"); @@ -4293,7 +4267,7 @@ int DetectEngineMultiTenantSetup(const bool unix_socket) SCLogConfig("tenants config path: %s", path); } - TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) { + TAILQ_FOREACH (tenant_node, &tenants_root_node->head, next) { ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id"); if (id_node == NULL) { goto bad_tenant; @@ -4400,7 +4374,8 @@ static int DetectEngineTenantRegisterSelector( DetectEngineMasterCtx *master = &g_master_de_ctx; SCMutexLock(&master->lock); - if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) { + if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || + master->tenant_selector == selector)) { SCLogInfo("conflicting selector already set"); SCMutexUnlock(&master->lock); return -1; @@ -4449,9 +4424,7 @@ static int DetectEngineTenantUnregisterSelector( DetectEngineTenantMapping *prev = NULL; DetectEngineTenantMapping *map = master->tenant_mapping_list; while (map) { - if (map->traffic_id == traffic_id && - map->tenant_id == tenant_id) - { + if (map->traffic_id == traffic_id && map->tenant_id == tenant_id) { if (prev != NULL) prev->next = map->next; else @@ -4516,9 +4489,7 @@ DetectEngineCtx *DetectEngineGetByTenantId(uint32_t tenant_id) DetectEngineCtx *de_ctx = master->list; while (de_ctx) { - if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT && - de_ctx->tenant_id == tenant_id) - { + if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT && de_ctx->tenant_id == tenant_id) { de_ctx->ref_cnt++; break; } @@ -4726,8 +4697,7 @@ int DetectEngineReload(const SCInstance *suri) /* only reload a regular 'normal' and 'delayed detect stub' detect engines */ if (!(old_de_ctx->type == DETECT_ENGINE_TYPE_NORMAL || - old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB)) - { + old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB)) { DetectEngineDeReference(&old_de_ctx); SCLogNotice("rule reload complete"); return -1; @@ -4741,8 +4711,7 @@ int DetectEngineReload(const SCInstance *suri) DetectEngineDeReference(&old_de_ctx); return -1; } - if (SigLoadSignatures(new_de_ctx, - suri->sig_file, suri->sig_file_exclusive) != 0) { + if (SigLoadSignatures(new_de_ctx, suri->sig_file, suri->sig_file_exclusive) != 0) { DetectEngineCtxFree(new_de_ctx); DetectEngineDeReference(&old_de_ctx); return -1; @@ -4814,13 +4783,11 @@ int DetectEngineMTApply(void) DetectEngineCtx *stub_de_ctx = NULL; DetectEngineCtx *list = master->list; - for ( ; list != NULL; list = list->next) { + for (; list != NULL; list = list->next) { SCLogDebug("list %p tenant %u", list, list->tenant_id); - if (list->type == DETECT_ENGINE_TYPE_NORMAL || - list->type == DETECT_ENGINE_TYPE_MT_STUB || - list->type == DETECT_ENGINE_TYPE_DD_STUB) - { + if (list->type == DETECT_ENGINE_TYPE_NORMAL || list->type == DETECT_ENGINE_TYPE_MT_STUB || + list->type == DETECT_ENGINE_TYPE_DD_STUB) { stub_de_ctx = list; break; } @@ -4934,21 +4901,20 @@ static void DetectEngineDeInitYamlConf(void) static int DetectEngineTest01(void) { - const char *conf = - "%YAML 1.1\n" - "---\n" - "detect-engine:\n" - " - profile: medium\n" - " - custom-values:\n" - " toclient_src_groups: 2\n" - " toclient_dst_groups: 2\n" - " toclient_sp_groups: 2\n" - " toclient_dp_groups: 3\n" - " toserver_src_groups: 2\n" - " toserver_dst_groups: 4\n" - " toserver_sp_groups: 2\n" - " toserver_dp_groups: 25\n" - " - inspection-recursion-limit: 0\n"; + const char *conf = "%YAML 1.1\n" + "---\n" + "detect-engine:\n" + " - profile: medium\n" + " - custom-values:\n" + " toclient_src_groups: 2\n" + " toclient_dst_groups: 2\n" + " toclient_sp_groups: 2\n" + " toclient_dp_groups: 3\n" + " toserver_src_groups: 2\n" + " toserver_dst_groups: 4\n" + " toserver_sp_groups: 2\n" + " toserver_dp_groups: 25\n" + " - inspection-recursion-limit: 0\n"; FAIL_IF(DetectEngineInitYamlConf(conf) == -1); @@ -4966,21 +4932,20 @@ static int DetectEngineTest01(void) static int DetectEngineTest02(void) { - const char *conf = - "%YAML 1.1\n" - "---\n" - "detect-engine:\n" - " - profile: medium\n" - " - custom-values:\n" - " toclient_src_groups: 2\n" - " toclient_dst_groups: 2\n" - " toclient_sp_groups: 2\n" - " toclient_dp_groups: 3\n" - " toserver_src_groups: 2\n" - " toserver_dst_groups: 4\n" - " toserver_sp_groups: 2\n" - " toserver_dp_groups: 25\n" - " - inspection-recursion-limit:\n"; + const char *conf = "%YAML 1.1\n" + "---\n" + "detect-engine:\n" + " - profile: medium\n" + " - custom-values:\n" + " toclient_src_groups: 2\n" + " toclient_dst_groups: 2\n" + " toclient_sp_groups: 2\n" + " toclient_dp_groups: 3\n" + " toserver_src_groups: 2\n" + " toserver_dst_groups: 4\n" + " toserver_sp_groups: 2\n" + " toserver_dp_groups: 25\n" + " - inspection-recursion-limit:\n"; FAIL_IF(DetectEngineInitYamlConf(conf) == -1); @@ -4999,20 +4964,19 @@ static int DetectEngineTest02(void) static int DetectEngineTest03(void) { - const char *conf = - "%YAML 1.1\n" - "---\n" - "detect-engine:\n" - " - profile: medium\n" - " - custom-values:\n" - " toclient_src_groups: 2\n" - " toclient_dst_groups: 2\n" - " toclient_sp_groups: 2\n" - " toclient_dp_groups: 3\n" - " toserver_src_groups: 2\n" - " toserver_dst_groups: 4\n" - " toserver_sp_groups: 2\n" - " toserver_dp_groups: 25\n"; + const char *conf = "%YAML 1.1\n" + "---\n" + "detect-engine:\n" + " - profile: medium\n" + " - custom-values:\n" + " toclient_src_groups: 2\n" + " toclient_dst_groups: 2\n" + " toclient_sp_groups: 2\n" + " toclient_dp_groups: 3\n" + " toserver_src_groups: 2\n" + " toserver_dst_groups: 4\n" + " toserver_sp_groups: 2\n" + " toserver_dp_groups: 25\n"; FAIL_IF(DetectEngineInitYamlConf(conf) == -1); @@ -5031,21 +4995,20 @@ static int DetectEngineTest03(void) static int DetectEngineTest04(void) { - const char *conf = - "%YAML 1.1\n" - "---\n" - "detect-engine:\n" - " - profile: medium\n" - " - custom-values:\n" - " toclient_src_groups: 2\n" - " toclient_dst_groups: 2\n" - " toclient_sp_groups: 2\n" - " toclient_dp_groups: 3\n" - " toserver_src_groups: 2\n" - " toserver_dst_groups: 4\n" - " toserver_sp_groups: 2\n" - " toserver_dp_groups: 25\n" - " - inspection-recursion-limit: 10\n"; + const char *conf = "%YAML 1.1\n" + "---\n" + "detect-engine:\n" + " - profile: medium\n" + " - custom-values:\n" + " toclient_src_groups: 2\n" + " toclient_dst_groups: 2\n" + " toclient_sp_groups: 2\n" + " toclient_dp_groups: 3\n" + " toserver_src_groups: 2\n" + " toserver_dst_groups: 4\n" + " toserver_sp_groups: 2\n" + " toserver_dp_groups: 25\n" + " - inspection-recursion-limit: 10\n"; FAIL_IF(DetectEngineInitYamlConf(conf) == -1); @@ -5063,14 +5026,13 @@ static int DetectEngineTest04(void) static int DetectEngineTest08(void) { - const char *conf = - "%YAML 1.1\n" - "---\n" - "detect-engine:\n" - " - profile: custom\n" - " - custom-values:\n" - " toclient-groups: 23\n" - " toserver-groups: 27\n"; + const char *conf = "%YAML 1.1\n" + "---\n" + "detect-engine:\n" + " - profile: custom\n" + " - custom-values:\n" + " toclient-groups: 23\n" + " toserver-groups: 27\n"; FAIL_IF(DetectEngineInitYamlConf(conf) == -1); @@ -5090,15 +5052,14 @@ static int DetectEngineTest08(void) /** \test bug 892 bad values */ static int DetectEngineTest09(void) { - const char *conf = - "%YAML 1.1\n" - "---\n" - "detect-engine:\n" - " - profile: custom\n" - " - custom-values:\n" - " toclient-groups: BA\n" - " toserver-groups: BA\n" - " - inspection-recursion-limit: 10\n"; + const char *conf = "%YAML 1.1\n" + "---\n" + "detect-engine:\n" + " - profile: custom\n" + " - custom-values:\n" + " toclient-groups: BA\n" + " toserver-groups: BA\n" + " - inspection-recursion-limit: 10\n"; FAIL_IF(DetectEngineInitYamlConf(conf) == -1); diff --git a/src/detect-engine.h b/src/detect-engine.h index 02e784ee973c..9e16f74392e2 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -33,8 +33,8 @@ void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id, void InspectionBufferFree(InspectionBuffer *buffer); void InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size); void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len); -void InspectionBufferApplyTransforms(InspectionBuffer *buffer, - const DetectEngineTransforms *transforms); +void InspectionBufferApplyTransforms( + InspectionBuffer *buffer, const DetectEngineTransforms *transforms); void InspectionBufferClean(DetectEngineThreadCtx *det_ctx); InspectionBuffer *InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id); void InspectionBufferSetupMultiEmpty(InspectionBuffer *buffer); @@ -56,10 +56,10 @@ int DetectBufferTypeMaxId(void); void DetectBufferTypeCloseRegistration(void); void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc); const char *DetectBufferTypeGetDescriptionByName(const char *name); -void DetectBufferTypeRegisterSetupCallback(const char *name, - void (*Callback)(const DetectEngineCtx *, Signature *)); -void DetectBufferTypeRegisterValidateCallback(const char *name, - bool (*ValidateCallback)(const Signature *, const char **sigerror)); +void DetectBufferTypeRegisterSetupCallback( + const char *name, void (*Callback)(const DetectEngineCtx *, Signature *)); +void DetectBufferTypeRegisterValidateCallback( + const char *name, bool (*ValidateCallback)(const Signature *, const char **sigerror)); /* detect engine related buffer funcs */ @@ -94,13 +94,13 @@ DetectEngineCtx *DetectEngineCtxInitStubForDD(void); DetectEngineCtx *DetectEngineCtxInitStubForMT(void); void DetectEngineCtxFree(DetectEngineCtx *); -int DetectRegisterThreadCtxGlobalFuncs(const char *name, - void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)); +int DetectRegisterThreadCtxGlobalFuncs( + const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)); void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id); TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); -//inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *); +// inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *); /* faster as a macro than a inline function on my box -- VJ */ #define DetectEngineGetMaxSigId(de_ctx) ((de_ctx)->signum) void DetectEngineResetMaxSigId(DetectEngineCtx *); @@ -146,10 +146,9 @@ uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineTh const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); -int DetectEngineInspectPktBufferGeneric( - DetectEngineThreadCtx *det_ctx, - const DetectEnginePktInspectionEngine *engine, - const Signature *s, Packet *p, uint8_t *alert_flags); +int DetectEngineInspectPktBufferGeneric(DetectEngineThreadCtx *det_ctx, + const DetectEnginePktInspectionEngine *engine, const Signature *s, Packet *p, + uint8_t *alert_flags); /** * \brief Registers an app inspection engine. @@ -161,13 +160,10 @@ int DetectEngineInspectPktBufferGeneric( * \param progress Minimal progress value for inspect engine to run * \param Callback The engine callback. */ -void DetectAppLayerInspectEngineRegister2(const char *name, - AppProto alproto, uint32_t dir, int progress, - InspectEngineFuncPtr2 Callback2, - InspectionBufferGetDataPtr GetData); +void DetectAppLayerInspectEngineRegister2(const char *name, AppProto alproto, uint32_t dir, + int progress, InspectEngineFuncPtr2 Callback2, InspectionBufferGetDataPtr GetData); -void DetectPktInspectEngineRegister(const char *name, - InspectionBufferGetPktDataPtr GetPktData, +void DetectPktInspectEngineRegister(const char *name, InspectionBufferGetPktDataPtr GetPktData, InspectionBufferPktInspectFunc Callback); void DetectFrameInspectEngineRegister(const char *name, int dir, @@ -178,10 +174,8 @@ void DetectEngineFrameInspectEngineRegister(DetectEngineCtx *de_ctx, const char int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s); void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *, Signature *s); -bool DetectEnginePktInspectionRun(ThreadVars *tv, - DetectEngineThreadCtx *det_ctx, const Signature *s, - Flow *f, Packet *p, - uint8_t *alert_flags); +bool DetectEnginePktInspectionRun(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, + const Signature *s, Flow *f, Packet *p, uint8_t *alert_flags); int DetectEnginePktInspectionSetup(Signature *s); void DetectEngineSetParseMetadata(void); diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 6748186727c9..fa9e53cf2042 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -33,11 +33,11 @@ #include "detect-engine-build.h" #include "detect-fast-pattern.h" -#include "util-error.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/error.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #define PARSE_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" @@ -61,8 +61,7 @@ static SCFPSupportSMList *g_fp_support_smlist_list = NULL; * \retval 1 If supported. * \retval 0 If not. */ -int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, - const int list_id) +int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, const int list_id) { if (de_ctx->fp_support_smlist_list == NULL) { return 0; @@ -185,11 +184,12 @@ void DetectEngineFreeFastPatternList(DetectEngineCtx *de_ctx) void DetectFastPatternRegister(void) { sigmatch_table[DETECT_FAST_PATTERN].name = "fast_pattern"; - sigmatch_table[DETECT_FAST_PATTERN].desc = "force using preceding content in the multi pattern matcher"; + sigmatch_table[DETECT_FAST_PATTERN].desc = + "force using preceding content in the multi pattern matcher"; sigmatch_table[DETECT_FAST_PATTERN].url = "/rules/prefilter-keywords.html#fast-pattern"; sigmatch_table[DETECT_FAST_PATTERN].Match = NULL; sigmatch_table[DETECT_FAST_PATTERN].Setup = DetectFastPatternSetup; - sigmatch_table[DETECT_FAST_PATTERN].Free = NULL; + sigmatch_table[DETECT_FAST_PATTERN].Free = NULL; #ifdef UNITTESTS sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests; #endif @@ -240,10 +240,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c cd = (DetectContentData *)pm->ctx; if ((cd->flags & DETECT_CONTENT_NEGATED) && - ((cd->flags & DETECT_CONTENT_DISTANCE) || - (cd->flags & DETECT_CONTENT_WITHIN) || - (cd->flags & DETECT_CONTENT_OFFSET) || - (cd->flags & DETECT_CONTENT_DEPTH))) { + ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || + (cd->flags & DETECT_CONTENT_OFFSET) || (cd->flags & DETECT_CONTENT_DEPTH))) { /* we can't have any of these if we are having "only" */ SCLogError("fast_pattern; cannot be " @@ -251,13 +249,12 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c goto error; } - if (arg == NULL|| strcmp(arg, "") == 0) { + if (arg == NULL || strcmp(arg, "") == 0) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError("can't use multiple fast_pattern " "options for the same content"); goto error; - } - else { /*allow only one content to have fast_pattern modifier*/ + } else { /*allow only one content to have fast_pattern modifier*/ for (uint32_t list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { SigMatch *sm = NULL; for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { @@ -280,11 +277,9 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c int ret = DetectParsePcreExec(&parse_regex, &match, arg, 0, 0); /* fast pattern only */ if (ret == 2) { - if ((cd->flags & DETECT_CONTENT_NEGATED) || - (cd->flags & DETECT_CONTENT_DISTANCE) || - (cd->flags & DETECT_CONTENT_WITHIN) || - (cd->flags & DETECT_CONTENT_OFFSET) || - (cd->flags & DETECT_CONTENT_DEPTH)) { + if ((cd->flags & DETECT_CONTENT_NEGATED) || (cd->flags & DETECT_CONTENT_DISTANCE) || + (cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_OFFSET) || + (cd->flags & DETECT_CONTENT_DEPTH)) { /* we can't have any of these if we are having "only" */ SCLogError("fast_pattern: only; cannot be " @@ -304,8 +299,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c goto error; } uint16_t offset; - if (StringParseUint16(&offset, 10, 0, - (const char *)arg_substr) < 0) { + if (StringParseUint16(&offset, 10, 0, (const char *)arg_substr) < 0) { SCLogError("Invalid fast pattern offset:" " \"%s\"", arg_substr); @@ -320,8 +314,7 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c goto error; } uint16_t length; - if (StringParseUint16(&length, 10, 0, - (const char *)arg_substr) < 0) { + if (StringParseUint16(&length, 10, 0, (const char *)arg_substr) < 0) { SCLogError("Invalid value for fast " "pattern: \"%s\"", arg_substr); @@ -356,10 +349,10 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c pcre2_match_data_free(match); return 0; - error: - if (match) { - pcre2_match_data_free(match); - } +error: + if (match) { + pcre2_match_data_free(match); + } return -1; } diff --git a/src/detect-fast-pattern.h b/src/detect-fast-pattern.h index af57540c74f1..2e7de2706e1f 100644 --- a/src/detect-fast-pattern.h +++ b/src/detect-fast-pattern.h @@ -25,8 +25,7 @@ #define __DETECT_FAST_PATTERN_H__ void SupportFastPatternForSigMatchList(int list_id, int priority); -int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, - const int list_id); +int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, const int list_id); void SupportFastPatternForSigMatchTypes(void); void DetectEngineRegisterFastPatternForId(DetectEngineCtx *de_ctx, int list_id, int priority); @@ -37,4 +36,3 @@ void DetectEngineFreeFastPatternList(DetectEngineCtx *de_ctx); void DetectFastPatternRegister(void); #endif /* __DETECT_FAST_PATTERN_H__ */ - diff --git a/src/detect-file-data.c b/src/detect-file-data.c index f31715adda01..626a80225290 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -39,26 +39,25 @@ #include "app-layer.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" -#include "app-layer-smtp.h" +#include "app-layer/http/parser.h" +#include "app-layer/smtp/parser.h" #include "flow.h" #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-file-decompression.h" -#include "util-profiling.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/file-decompression.h" +#include "util/profiling.h" -static int DetectFiledataSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectFiledataSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectFiledataRegisterTests(void); #endif -static void DetectFiledataSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); +static void DetectFiledataSetupCallback(const DetectEngineCtx *de_ctx, Signature *s); static int g_file_data_buffer_id = 0; /* file API */ @@ -93,7 +92,8 @@ void DetectFiledataRegister(void) g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); } -static void SetupDetectEngineConfig(DetectEngineCtx *de_ctx) { +static void SetupDetectEngineConfig(DetectEngineCtx *de_ctx) +{ if (de_ctx->filedata_config_initialized) return; @@ -108,8 +108,10 @@ static void SetupDetectEngineConfig(DetectEngineCtx *de_ctx) { /* SMTP */ de_ctx->filedata_config[ALPROTO_SMTP].content_limit = smtp_config.content_limit; - de_ctx->filedata_config[ALPROTO_SMTP].content_inspect_min_size = smtp_config.content_inspect_min_size; - de_ctx->filedata_config[ALPROTO_SMTP].content_inspect_window = smtp_config.content_inspect_window; + de_ctx->filedata_config[ALPROTO_SMTP].content_inspect_min_size = + smtp_config.content_inspect_min_size; + de_ctx->filedata_config[ALPROTO_SMTP].content_inspect_window = + smtp_config.content_inspect_window; de_ctx->filedata_config_initialized = true; } @@ -125,7 +127,7 @@ static void SetupDetectEngineConfig(DetectEngineCtx *de_ctx) { * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFiledataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { SCEnter(); @@ -141,7 +143,7 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, const cha } if (s->alproto == ALPROTO_SMTP && (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) && - !(s->flags & SIG_FLAG_TOSERVER) && (s->flags & SIG_FLAG_TOCLIENT)) { + !(s->flags & SIG_FLAG_TOSERVER) && (s->flags & SIG_FLAG_TOCLIENT)) { SCLogError("The 'file-data' keyword cannot be used with SMTP flow:to_client or " "flow:from_server."); return -1; @@ -155,8 +157,7 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, const cha return 0; } -static void DetectFiledataSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) +static void DetectFiledataSetupCallback(const DetectEngineCtx *de_ctx, Signature *s) { if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_UNKNOWN || s->alproto == ALPROTO_HTTP) { @@ -486,9 +487,8 @@ int PrefilterMpmFiledataRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, Mpm pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxFiledata, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmFiledataFree, mpm_reg->pname); + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxFiledata, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmFiledataFree, mpm_reg->pname); } #ifdef UNITTESTS diff --git a/src/detect-file-data.h b/src/detect-file-data.h index 1be9b4001049..ff793da09cba 100644 --- a/src/detect-file-data.h +++ b/src/detect-file-data.h @@ -25,7 +25,7 @@ #define __DETECT_FILEDATA_H__ /* prototypes */ -void DetectFiledataRegister (void); +void DetectFiledataRegister(void); typedef struct PrefilterMpmFiledata { int list_id; diff --git a/src/detect-file-hash-common.c b/src/detect-file-hash-common.c index f81ce4be29ea..574fa439944b 100644 --- a/src/detect-file-hash-common.c +++ b/src/detect-file-hash-common.c @@ -30,7 +30,7 @@ #include "detect-file-hash-common.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" /** * \brief Read the bytes of a hash from an hexadecimal string @@ -44,8 +44,8 @@ * \retval -1 the hexadecimal string is invalid * \retval 1 the hexadecimal string was read successfully */ -int ReadHashString(uint8_t *hash, const char *string, const char *filename, int line_no, - uint16_t expected_len) +int ReadHashString( + uint8_t *hash, const char *string, const char *filename, int line_no, uint16_t expected_len) { if (strlen(string) != expected_len) { SCLogError("%s:%d hash string not %d characters", filename, line_no, expected_len); @@ -53,10 +53,10 @@ int ReadHashString(uint8_t *hash, const char *string, const char *filename, int } int i, x; - for (x = 0, i = 0; i < expected_len; i+=2, x++) { + for (x = 0, i = 0; i < expected_len; i += 2, x++) { char buf[3] = { 0, 0, 0 }; buf[0] = string[i]; - buf[1] = string[i+1]; + buf[1] = string[i + 1]; long value = strtol(buf, NULL, 16); if (value >= 0 && value <= 255) @@ -82,8 +82,8 @@ int ReadHashString(uint8_t *hash, const char *string, const char *filename, int * \retval -1 failed to load the hash into the hash table * \retval 1 successfully loaded the has into the hash table */ -int LoadHashTable(ROHashTable *hash_table, const char *string, const char *filename, - int line_no, uint32_t type) +int LoadHashTable(ROHashTable *hash_table, const char *string, const char *filename, int line_no, + uint32_t type) { /* allocate the maximum size a hash can have (in this case is SHA256, 32 bytes) */ uint8_t hash[32]; @@ -92,8 +92,7 @@ int LoadHashTable(ROHashTable *hash_table, const char *string, const char *filen if (type == DETECT_FILEMD5) { size = 16; - } - else if (type == DETECT_FILESHA1) { + } else if (type == DETECT_FILESHA1) { size = 20; } @@ -118,8 +117,7 @@ int LoadHashTable(ROHashTable *hash_table, const char *string, const char *filen * \retval 0 didn't find the specified hash * \retval 1 the hash matched a stored value */ -static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, - size_t hash_len) +static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, size_t hash_len) { void *ptr = ROHashLookup(hash_table, hash, (uint16_t)hash_len); if (ptr == NULL) @@ -141,8 +139,8 @@ static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, * \retval 0 no match * \retval 1 match */ -int DetectFileHashMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) +int DetectFileHashMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, + const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; @@ -156,11 +154,9 @@ int DetectFileHashMatch (DetectEngineThreadCtx *det_ctx, if (s->file_flags & FILE_SIG_NEED_MD5 && file->flags & FILE_MD5) { match = HashMatchHashTable(filehash->hash, file->md5, sizeof(file->md5)); - } - else if (s->file_flags & FILE_SIG_NEED_SHA1 && file->flags & FILE_SHA1) { + } else if (s->file_flags & FILE_SIG_NEED_SHA1 && file->flags & FILE_SHA1) { match = HashMatchHashTable(filehash->hash, file->sha1, sizeof(file->sha1)); - } - else if (s->file_flags & FILE_SIG_NEED_SHA256 && file->flags & FILE_SHA256) { + } else if (s->file_flags & FILE_SIG_NEED_SHA256 && file->flags & FILE_SHA256) { match = HashMatchHashTable(filehash->hash, file->sha256, sizeof(file->sha256)); } @@ -169,8 +165,7 @@ int DetectFileHashMatch (DetectEngineThreadCtx *det_ctx, ret = 1; else ret = 0; - } - else if (match == 0) { + } else if (match == 0) { if (filehash->negated == 0) ret = 0; else @@ -192,8 +187,8 @@ static const char *hexcodes = "ABCDEFabcdef0123456789"; * \retval hash pointer to DetectFileHashData on success * \retval NULL on failure */ -static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, - const char *str, uint32_t type) +static DetectFileHashData *DetectFileHashParse( + const DetectEngineCtx *de_ctx, const char *str, uint32_t type) { DetectFileHashData *filehash = NULL; FILE *fp = NULL; @@ -212,11 +207,9 @@ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, if (type == DETECT_FILEMD5) { filehash->hash = ROHashInit(18, 16); - } - else if (type == DETECT_FILESHA1) { + } else if (type == DETECT_FILESHA1) { filehash->hash = ROHashInit(18, 20); - } - else if (type == DETECT_FILESHA256) { + } else if (type == DETECT_FILESHA256) { filehash->hash = ROHashInit(18, 32); } @@ -261,11 +254,12 @@ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, } int line_no = 0; - while(fgets(line, (int)sizeof(line), fp) != NULL) { + while (fgets(line, (int)sizeof(line), fp) != NULL) { size_t valid = 0, len = strlen(line); line_no++; - while (strchr(hexcodes, line[valid]) != NULL && valid++ < len); + while (strchr(hexcodes, line[valid]) != NULL && valid++ < len) + ; /* lines that do not contain sequentially any valid character are ignored */ if (valid == 0) @@ -284,7 +278,8 @@ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, if (ROHashInitFinalize(filehash->hash) != 1) { goto error; } - SCLogInfo("Hash hash table size %u bytes%s", ROHashMemorySize(filehash->hash), filehash->negated ? ", negated match" : ""); + SCLogInfo("Hash hash table size %u bytes%s", ROHashMemorySize(filehash->hash), + filehash->negated ? ", negated match" : ""); SCFree(rule_filename); SCFree(filename); @@ -292,7 +287,7 @@ static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, error: if (filehash != NULL) - DetectFileHashFree((DetectEngineCtx *) de_ctx, filehash); + DetectFileHashFree((DetectEngineCtx *)de_ctx, filehash); if (fp != NULL) fclose(fp); if (filename != NULL) diff --git a/src/detect-file-hash-common.h b/src/detect-file-hash-common.h index b547e03677f2..1ca58c09af7a 100644 --- a/src/detect-file-hash-common.h +++ b/src/detect-file-hash-common.h @@ -26,7 +26,7 @@ #ifndef __UTIL_DETECT_FILE_HASH_H__ #define __UTIL_DETECT_FILE_HASH_H__ -#include "util-rohash.h" +#include "util/rohash.h" typedef struct DetectFileHashData_ { ROHashTable *hash; @@ -37,8 +37,8 @@ typedef struct DetectFileHashData_ { int ReadHashString(uint8_t *, const char *, const char *, int, uint16_t); int LoadHashTable(ROHashTable *, const char *, const char *, int, uint32_t); -int DetectFileHashMatch(DetectEngineThreadCtx *, Flow *, uint8_t, - File *, const Signature *, const SigMatchCtx *); +int DetectFileHashMatch( + DetectEngineThreadCtx *, Flow *, uint8_t, File *, const Signature *, const SigMatchCtx *); int DetectFileHashSetup(DetectEngineCtx *, Signature *, const char *, uint16_t, int); void DetectFileHashFree(DetectEngineCtx *, void *); diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 7ade159fb52d..052aed54b110 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -40,14 +40,14 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-magic.h" -#include "util-print.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/magic.h" +#include "util/print.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-profiling.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/profiling.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -61,7 +61,7 @@ #ifndef HAVE_MAGIC -static int DetectFilemagicSetupNoSupport (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFilemagicSetupNoSupport(DetectEngineCtx *de_ctx, Signature *s, const char *str) { SCLogError("no libmagic support built in, needed for filemagic keyword"); return -1; @@ -73,10 +73,11 @@ static int DetectFilemagicSetupNoSupport (DetectEngineCtx *de_ctx, Signature *s, void DetectFilemagicRegister(void) { sigmatch_table[DETECT_FILEMAGIC].name = "filemagic"; - sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; + sigmatch_table[DETECT_FILEMAGIC].desc = + "match on the information libmagic returns about a file"; sigmatch_table[DETECT_FILEMAGIC].url = "/rules/file-keywords.html#filemagic"; sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetupNoSupport; - sigmatch_table[DETECT_FILEMAGIC].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; + sigmatch_table[DETECT_FILEMAGIC].flags = SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; } #else /* HAVE_MAGIC */ @@ -103,17 +104,18 @@ static uint8_t DetectEngineInspectFilemagic(DetectEngineCtx *de_ctx, DetectEngin void DetectFilemagicRegister(void) { sigmatch_table[DETECT_FILEMAGIC].name = "filemagic"; - sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; + sigmatch_table[DETECT_FILEMAGIC].desc = + "match on the information libmagic returns about a file"; sigmatch_table[DETECT_FILEMAGIC].url = "/rules/file-keywords.html#filemagic"; sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetup; - sigmatch_table[DETECT_FILEMAGIC].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; + sigmatch_table[DETECT_FILEMAGIC].flags = SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; sigmatch_table[DETECT_FILEMAGIC].alternative = DETECT_FILE_MAGIC; sigmatch_table[DETECT_FILE_MAGIC].name = "file.magic"; sigmatch_table[DETECT_FILE_MAGIC].desc = "sticky buffer to match on the file magic"; sigmatch_table[DETECT_FILE_MAGIC].url = "/rules/file-keywords.html#filemagic"; sigmatch_table[DETECT_FILE_MAGIC].Setup = DetectFilemagicSetupSticky; - sigmatch_table[DETECT_FILE_MAGIC].flags = SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[DETECT_FILE_MAGIC].flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; filehandler_table[DETECT_FILE_MAGIC].name = "file.magic", filehandler_table[DETECT_FILE_MAGIC].priority = 2; @@ -126,11 +128,11 @@ void DetectFilemagicRegister(void) DetectBufferTypeSupportsMultiInstance("file.magic"); g_file_magic_buffer_id = DetectBufferTypeGetByName("file.magic"); - SCLogDebug("registering filemagic rule option"); + SCLogDebug("registering filemagic rule option"); return; } -#define FILEMAGIC_MIN_SIZE 512 +#define FILEMAGIC_MIN_SIZE 512 /** * \brief run the magic check @@ -150,8 +152,7 @@ int FilemagicThreadLookup(magic_t *ctx, File *file) uint32_t data_len = 0; uint64_t offset = 0; - StreamingBufferGetData(file->sb, - &data, &data_len, &offset); + StreamingBufferGetData(file->sb, &data, &data_len, &offset); if (offset == 0) { if (FileDataSize(file) >= FILEMAGIC_MIN_SIZE) { file->magic = MagicThreadLookup(ctx, data, data_len); @@ -204,7 +205,7 @@ static void DetectFilemagicThreadFree(void *ctx) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFilemagicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { if (s->init_data->transforms.cnt) { SCLogError("previous transforms not consumed before 'filemagic'"); @@ -394,9 +395,8 @@ static int PrefilterMpmFilemagicRegister(DetectEngineCtx *de_ctx, SigGroupHead * pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxFilemagic, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmFilemagicFree, mpm_reg->pname); + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxFilemagic, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmFilemagicFree, mpm_reg->pname); } #endif /* HAVE_MAGIC */ diff --git a/src/detect-filemagic.h b/src/detect-filemagic.h index d005597fca34..50a984df940a 100644 --- a/src/detect-filemagic.h +++ b/src/detect-filemagic.h @@ -28,6 +28,6 @@ /* prototypes */ int FilemagicThreadLookup(magic_t *ctx, File *file); #endif -void DetectFilemagicRegister (void); +void DetectFilemagicRegister(void); #endif /* __DETECT_FILEMAGIC_H__ */ diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index 9ea08803d8b8..098ba201ad05 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -26,14 +26,14 @@ #include "detect-engine.h" #include "detect-file-hash-common.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-filemd5.h" static int g_file_match_list_id = 0; -static int DetectFileMd5Setup (DetectEngineCtx *, Signature *, const char *); +static int DetectFileMd5Setup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectFileMd5RegisterTests(void); #endif @@ -48,7 +48,7 @@ void DetectFileMd5Register(void) sigmatch_table[DETECT_FILEMD5].url = "/rules/file-keywords.html#filemd5"; sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5Setup; - sigmatch_table[DETECT_FILEMD5].Free = DetectFileHashFree; + sigmatch_table[DETECT_FILEMD5].Free = DetectFileHashFree; #ifdef UNITTESTS sigmatch_table[DETECT_FILEMD5].RegisterTests = DetectFileMd5RegisterTests; #endif @@ -69,7 +69,7 @@ void DetectFileMd5Register(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFileMd5Setup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { return DetectFileHashSetup(de_ctx, s, str, DETECT_FILEMD5, g_file_match_list_id); } diff --git a/src/detect-filemd5.h b/src/detect-filemd5.h index 0905fc4ce02b..47ca8c9fb194 100644 --- a/src/detect-filemd5.h +++ b/src/detect-filemd5.h @@ -25,6 +25,6 @@ #define __DETECT_FILEMD5_H__ /* prototypes */ -void DetectFileMd5Register (void); +void DetectFileMd5Register(void); #endif /* __DETECT_FILEMD5_H__ */ diff --git a/src/detect-filename.c b/src/detect-filename.c index 88e580862452..1701c465c032 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -44,14 +44,14 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-profiling.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/profiling.h" #include "app-layer.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "stream-tcp.h" @@ -59,7 +59,7 @@ #include "app-layer-parser.h" static int DetectFileextSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str); -static int DetectFilenameSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectFilenameSetup(DetectEngineCtx *, Signature *, const char *); static int DetectFilenameSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); #ifdef UNITTESTS static void DetectFilenameRegisterTests(void); @@ -85,7 +85,7 @@ void DetectFilenameRegister(void) #ifdef UNITTESTS sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; #endif - sigmatch_table[DETECT_FILENAME].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION; + sigmatch_table[DETECT_FILENAME].flags = SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_HANDLE_NEGATION; sigmatch_table[DETECT_FILENAME].alternative = DETECT_FILE_NAME; sigmatch_table[DETECT_FILEEXT].name = "fileext"; @@ -99,7 +99,7 @@ void DetectFilenameRegister(void) sigmatch_table[DETECT_FILE_NAME].desc = "sticky buffer to match on the file name"; sigmatch_table[DETECT_FILE_NAME].url = "/rules/file-keywords.html#filename"; sigmatch_table[DETECT_FILE_NAME].Setup = DetectFilenameSetupSticky; - sigmatch_table[DETECT_FILE_NAME].flags = SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; + sigmatch_table[DETECT_FILE_NAME].flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; DetectBufferTypeSetDescriptionByName("file.name", "file name"); @@ -168,7 +168,7 @@ static int DetectFileextSetup(DetectEngineCtx *de_ctx, Signature *s, const char * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFilenameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { if (s->init_data->transforms.cnt) { SCLogError("previous transforms not consumed before 'filename'"); @@ -331,9 +331,8 @@ static int PrefilterMpmFilenameRegister(DetectEngineCtx *de_ctx, SigGroupHead *s pectx->mpm_ctx = mpm_ctx; pectx->transforms = &mpm_reg->transforms; - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxFilename, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmFilenameFree, mpm_reg->pname); + return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxFilename, mpm_reg->app_v2.alproto, + mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmFilenameFree, mpm_reg->pname); } #ifdef UNITTESTS /* UNITTESTS */ @@ -343,16 +342,31 @@ static int PrefilterMpmFilenameRegister(DetectEngineCtx *de_ctx, SigGroupHead *s */ static int DetectFilenameSignatureParseTest01(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; nocase; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; startswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; startswith; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; bsize:10; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; rawbytes; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_client; file.name; sid:1;)", false)); - //FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_client; file.name; content:\"abc\"; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (flow:to_client; file.name; content:\"abc\"; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; " + "content:\"abc\"; nocase; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; " + "content:\"abc\"; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; " + "content:\"abc\"; startswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; " + "content:\"abc\"; startswith; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (flow:to_client; file.name; bsize:10; sid:1;)", true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; file.name; " + "content:\"abc\"; rawbytes; sid:1;)", + false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tcp any any -> any any (flow:to_client; file.name; sid:1;)", false)); + // FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_client; file.name; + // content:\"abc\"; sid:1;)", false)); PASS; } /** diff --git a/src/detect-filename.h b/src/detect-filename.h index 02684fcea416..9dda2b762543 100644 --- a/src/detect-filename.h +++ b/src/detect-filename.h @@ -25,6 +25,6 @@ #define __DETECT_FILENAME_H__ /* prototypes */ -void DetectFilenameRegister (void); +void DetectFilenameRegister(void); #endif /* __DETECT_FILENAME_H__ */ diff --git a/src/detect-filesha1.c b/src/detect-filesha1.c index 6eef33c60824..a5b182e9f172 100644 --- a/src/detect-filesha1.c +++ b/src/detect-filesha1.c @@ -27,12 +27,12 @@ #include "detect-engine.h" #include "detect-file-hash-common.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-filesha1.h" -static int DetectFileSha1Setup (DetectEngineCtx *, Signature *, const char *); +static int DetectFileSha1Setup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectFileSha1RegisterTests(void); #endif @@ -48,7 +48,7 @@ void DetectFileSha1Register(void) sigmatch_table[DETECT_FILESHA1].url = "/rules/file-keywords.html#filesha1"; sigmatch_table[DETECT_FILESHA1].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILESHA1].Setup = DetectFileSha1Setup; - sigmatch_table[DETECT_FILESHA1].Free = DetectFileHashFree; + sigmatch_table[DETECT_FILESHA1].Free = DetectFileHashFree; #ifdef UNITTESTS sigmatch_table[DETECT_FILESHA1].RegisterTests = DetectFileSha1RegisterTests; #endif @@ -66,7 +66,7 @@ void DetectFileSha1Register(void) * \param s pointer to the Current Signature * \param str pointer to the user provided "filesha1" option */ -static int DetectFileSha1Setup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFileSha1Setup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA1, g_file_match_list_id); } diff --git a/src/detect-filesha1.h b/src/detect-filesha1.h index d7504344c606..bf0140cd65b8 100644 --- a/src/detect-filesha1.h +++ b/src/detect-filesha1.h @@ -26,6 +26,6 @@ #define __DETECT_FILESHA1_H__ /* prototypes */ -void DetectFileSha1Register (void); +void DetectFileSha1Register(void); #endif /* __DETECT_FILESHA1_H__ */ diff --git a/src/detect-filesha256.c b/src/detect-filesha256.c index 3b41f42f9573..75816c4076ea 100644 --- a/src/detect-filesha256.c +++ b/src/detect-filesha256.c @@ -27,12 +27,12 @@ #include "detect-engine.h" #include "detect-file-hash-common.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-filesha256.h" -static int DetectFileSha256Setup (DetectEngineCtx *, Signature *, const char *); +static int DetectFileSha256Setup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectFileSha256RegisterTests(void); #endif @@ -48,7 +48,7 @@ void DetectFileSha256Register(void) sigmatch_table[DETECT_FILESHA256].url = "/rules/file-keywords.html#filesha256"; sigmatch_table[DETECT_FILESHA256].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256Setup; - sigmatch_table[DETECT_FILESHA256].Free = DetectFileHashFree; + sigmatch_table[DETECT_FILESHA256].Free = DetectFileHashFree; #ifdef UNITTESTS sigmatch_table[DETECT_FILESHA256].RegisterTests = DetectFileSha256RegisterTests; #endif @@ -70,7 +70,7 @@ void DetectFileSha256Register(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFileSha256Setup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFileSha256Setup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA256, g_file_match_list_id); } diff --git a/src/detect-filesha256.h b/src/detect-filesha256.h index a205b48699a0..71b5cb32fdb7 100644 --- a/src/detect-filesha256.h +++ b/src/detect-filesha256.h @@ -26,6 +26,6 @@ #define __DETECT_FILESHA256_H__ /* prototypes */ -void DetectFileSha256Register (void); +void DetectFileSha256Register(void); #endif /* __DETECT_FILESHA256_H__ */ diff --git a/src/detect-filesize.c b/src/detect-filesize.c index c29957d2870b..ca02e56759a0 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -25,10 +25,10 @@ #include "suricata-common.h" #include "app-layer-protos.h" -#include "app-layer-htp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-misc.h" +#include "app-layer/http/parser.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/misc.h" #include "detect.h" #include "detect-parse.h" @@ -38,19 +38,18 @@ #include "detect-engine-build.h" #include "detect-filesize.h" -#include "util-debug.h" -#include "util-byte.h" +#include "util/debug.h" +#include "util/byte.h" #include "flow-util.h" #include "stream-tcp.h" - /*prototypes*/ -static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m); -static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectFilesizeFree (DetectEngineCtx *, void *); +static int DetectFilesizeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, + const Signature *s, const SigMatchCtx *m); +static int DetectFilesizeSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectFilesizeFree(DetectEngineCtx *, void *); #ifdef UNITTESTS -static void DetectFilesizeRegisterTests (void); +static void DetectFilesizeRegisterTests(void); #endif static int g_file_match_list_id = 0; @@ -61,7 +60,8 @@ static int g_file_match_list_id = 0; void DetectFilesizeRegister(void) { sigmatch_table[DETECT_FILESIZE].name = "filesize"; - sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred"; + sigmatch_table[DETECT_FILESIZE].desc = + "match on the size of the file as it is being transferred"; sigmatch_table[DETECT_FILESIZE].url = "/rules/file-keywords.html#filesize"; sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch; sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; @@ -87,8 +87,8 @@ void DetectFilesizeRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) +static int DetectFilesizeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, + const Signature *s, const SigMatchCtx *m) { SCEnter(); @@ -119,7 +119,7 @@ static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFilesizeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { SCEnter(); DetectU64Data *fsd = NULL; @@ -133,7 +133,7 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, const cha goto error; } - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); + s->file_flags |= (FILE_SIG_NEED_FILE | FILE_SIG_NEED_SIZE); SCReturnInt(0); error: diff --git a/src/detect-filesize.h b/src/detect-filesize.h index 803b0a3607d6..5e6a8eb1ebdc 100644 --- a/src/detect-filesize.h +++ b/src/detect-filesize.h @@ -22,8 +22,8 @@ */ #ifndef __DETECT_FILESIZE_H__ -#define __DETECT_FILESIZE_H__ +#define __DETECT_FILESIZE_H__ void DetectFilesizeRegister(void); -#endif /* _DETECT_URILEN_H */ +#endif /* _DETECT_URILEN_H */ diff --git a/src/detect-filestore.c b/src/detect-filestore.c index 07bbd91ff199..a5bdc14de348 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -40,33 +40,33 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "stream-tcp.h" #include "detect-filestore.h" -#include "util-validate.h" +#include "util/validate.h" /** * \brief Regex for parsing our flow options */ -#define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$" +#define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$" static DetectParseRegex parse_regex; -static int DetectFilestoreMatch (DetectEngineThreadCtx *, - Flow *, uint8_t, File *, const Signature *, const SigMatchCtx *); -static int DetectFilestorePostMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx); -static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectFilestoreMatch( + DetectEngineThreadCtx *, Flow *, uint8_t, File *, const Signature *, const SigMatchCtx *); +static int DetectFilestorePostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); +static int DetectFilestoreSetup(DetectEngineCtx *, Signature *, const char *); static void DetectFilestoreFree(DetectEngineCtx *, void *); #ifdef UNITTESTS static void DetectFilestoreRegisterTests(void); @@ -83,7 +83,7 @@ void DetectFilestoreRegister(void) sigmatch_table[DETECT_FILESTORE].url = "/rules/file-keywords.html#filestore"; sigmatch_table[DETECT_FILESTORE].FileMatch = DetectFilestoreMatch; sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup; - sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; + sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; #ifdef UNITTESTS sigmatch_table[DETECT_FILESTORE].RegisterTests = DetectFilestoreRegisterTests; #endif @@ -91,7 +91,7 @@ void DetectFilestoreRegister(void) sigmatch_table[DETECT_FILESTORE_POSTMATCH].name = "__filestore__postmatch__"; sigmatch_table[DETECT_FILESTORE_POSTMATCH].Match = DetectFilestorePostMatch; - sigmatch_table[DETECT_FILESTORE_POSTMATCH].Free = DetectFilestoreFree; + sigmatch_table[DETECT_FILESTORE_POSTMATCH].Free = DetectFilestoreFree; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); @@ -149,7 +149,7 @@ static int FilestorePostMatchWithOptions(Packet *p, Flow *f, const DetectFilesto break; } - if (this_file) { + if (this_file) { FileStoreFileById(fc, file_id); } else if (this_tx) { /* set in AppLayerTxData. Parsers and logger will propagate it to the @@ -189,8 +189,8 @@ static int FilestorePostMatchWithOptions(Packet *p, Flow *f, const DetectFilesto * When we are sure all parts of the signature matched, we run this function * to finalize the filestore. */ -static int DetectFilestorePostMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectFilestorePostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); @@ -261,8 +261,8 @@ static int DetectFilestorePostMatch(DetectEngineThreadCtx *det_ctx, * \todo when we start supporting more protocols, the logic in this function * needs to be put behind a api. */ -static int DetectFilestoreMatch (DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) +static int DetectFilestoreMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, File *file, + const Signature *s, const SigMatchCtx *m) { uint32_t file_id = 0; @@ -307,9 +307,9 @@ static int DetectFilestoreMatch (DetectEngineThreadCtx *det_ctx, Flow *f, det_ctx->filestore[det_ctx->filestore_cnt].file_id = file_id; det_ctx->filestore[det_ctx->filestore_cnt].tx_id = det_ctx->tx_id; - SCLogDebug("%u, file %u, tx %"PRIu64, det_ctx->filestore_cnt, - det_ctx->filestore[det_ctx->filestore_cnt].file_id, - det_ctx->filestore[det_ctx->filestore_cnt].tx_id); + SCLogDebug("%u, file %u, tx %" PRIu64, det_ctx->filestore_cnt, + det_ctx->filestore[det_ctx->filestore_cnt].file_id, + det_ctx->filestore[det_ctx->filestore_cnt].tx_id); det_ctx->filestore_cnt++; SCReturnInt(1); @@ -326,7 +326,7 @@ static int DetectFilestoreMatch (DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectFilestoreSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { SCEnter(); @@ -336,8 +336,8 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, const ch /* Check on first-time loads (includes following a reload) */ if (!warn_not_configured || (de_ctx->version != de_version)) { if (de_version != de_ctx->version) { - SCLogDebug("reload-detected; re-checking feature presence; DE version now %"PRIu32, - de_ctx->version); + SCLogDebug("reload-detected; re-checking feature presence; DE version now %" PRIu32, + de_ctx->version); } if (!RequiresFeature(FEATURE_OUTPUT_FILESTORE)) { SCLogWarning("One or more rule(s) depends on the " @@ -349,7 +349,7 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, const ch } DetectFilestoreData *fd = NULL; - char *args[3] = {NULL,NULL,NULL}; + char *args[3] = { NULL, NULL, NULL }; int res = 0; size_t pcre2len; pcre2_match_data *match = NULL; @@ -408,20 +408,14 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, const ch if (args[0] != NULL) { SCLogDebug("first arg %s", args[0]); - if (strcasecmp(args[0], "request") == 0 || - strcasecmp(args[0], "to_server") == 0) - { + if (strcasecmp(args[0], "request") == 0 || strcasecmp(args[0], "to_server") == 0) { fd->direction = FILESTORE_DIR_TOSERVER; fd->scope = FILESTORE_SCOPE_TX; - } - else if (strcasecmp(args[0], "response") == 0 || - strcasecmp(args[0], "to_client") == 0) - { + } else if (strcasecmp(args[0], "response") == 0 || + strcasecmp(args[0], "to_client") == 0) { fd->direction = FILESTORE_DIR_TOCLIENT; fd->scope = FILESTORE_SCOPE_TX; - } - else if (strcasecmp(args[0], "both") == 0) - { + } else if (strcasecmp(args[0], "both") == 0) { fd->direction = FILESTORE_DIR_BOTH; fd->scope = FILESTORE_SCOPE_TX; } @@ -432,15 +426,11 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, const ch if (args[1] != NULL) { SCLogDebug("second arg %s", args[1]); - if (strcasecmp(args[1], "file") == 0) - { + if (strcasecmp(args[1], "file") == 0) { fd->scope = FILESTORE_SCOPE_DEFAULT; - } else if (strcasecmp(args[1], "tx") == 0) - { + } else if (strcasecmp(args[1], "tx") == 0) { fd->scope = FILESTORE_SCOPE_TX; - } else if (strcasecmp(args[1], "ssn") == 0 || - strcasecmp(args[1], "flow") == 0) - { + } else if (strcasecmp(args[1], "ssn") == 0 || strcasecmp(args[1], "flow") == 0) { fd->scope = FILESTORE_SCOPE_SSN; } } else { @@ -502,10 +492,10 @@ static int DetectFilestoreTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(bypass; filestore; " - "content:\"message\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(bypass; filestore; " + "content:\"message\"; http_host; " + "sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); DetectEngineCtxFree(de_ctx); diff --git a/src/detect-filestore.h b/src/detect-filestore.h index f394842fbd8b..632b679fb351 100644 --- a/src/detect-filestore.h +++ b/src/detect-filestore.h @@ -24,14 +24,14 @@ #ifndef __DETECT_FILESTORE_H__ #define __DETECT_FILESTORE_H__ -#define FILESTORE_DIR_DEFAULT 0 /* rule dir */ -#define FILESTORE_DIR_TOSERVER 1 -#define FILESTORE_DIR_TOCLIENT 2 -#define FILESTORE_DIR_BOTH 3 +#define FILESTORE_DIR_DEFAULT 0 /* rule dir */ +#define FILESTORE_DIR_TOSERVER 1 +#define FILESTORE_DIR_TOCLIENT 2 +#define FILESTORE_DIR_BOTH 3 -#define FILESTORE_SCOPE_DEFAULT 0 /* per file */ -#define FILESTORE_SCOPE_TX 1 /* per transaction */ -#define FILESTORE_SCOPE_SSN 2 /* per flow/ssn */ +#define FILESTORE_SCOPE_DEFAULT 0 /* per file */ +#define FILESTORE_SCOPE_TX 1 /* per transaction */ +#define FILESTORE_SCOPE_SSN 2 /* per flow/ssn */ typedef struct DetectFilestoreData_ { int16_t direction; @@ -39,6 +39,6 @@ typedef struct DetectFilestoreData_ { } DetectFilestoreData; /* prototypes */ -void DetectFilestoreRegister (void); +void DetectFilestoreRegister(void); #endif /* __DETECT_FILESTORE_H__ */ diff --git a/src/detect-flow.c b/src/detect-flow.c index 696e5013a03e..d36171fe36e3 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -37,20 +37,19 @@ #include "detect-flow.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" /** * \brief Regex for parsing our flow options */ -#define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$" +#define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$" static DetectParseRegex parse_regex; -int DetectFlowMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectFlowSetup (DetectEngineCtx *, Signature *, const char *); +int DetectFlowMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectFlowSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectFlowRegisterTests(void); #endif @@ -62,14 +61,14 @@ static bool PrefilterFlowIsPrefilterable(const Signature *s); /** * \brief Registration function for flow: keyword */ -void DetectFlowRegister (void) +void DetectFlowRegister(void) { sigmatch_table[DETECT_FLOW].name = "flow"; sigmatch_table[DETECT_FLOW].desc = "match on direction and state of the flow"; sigmatch_table[DETECT_FLOW].url = "/rules/flow-keywords.html#flow"; sigmatch_table[DETECT_FLOW].Match = DetectFlowMatch; sigmatch_table[DETECT_FLOW].Setup = DetectFlowSetup; - sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; + sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; #ifdef UNITTESTS sigmatch_table[DETECT_FLOW].RegisterTests = DetectFlowRegisterTests; #endif @@ -90,11 +89,9 @@ static inline int FlowMatch(const uint32_t pflags, const uint8_t pflowflags, con { uint8_t cnt = 0; - if ((dflags & DETECT_FLOW_FLAG_NO_FRAG) && - (!(pflags & PKT_REBUILT_FRAGMENT))) { + if ((dflags & DETECT_FLOW_FLAG_NO_FRAG) && (!(pflags & PKT_REBUILT_FRAGMENT))) { cnt++; - } else if ((dflags & DETECT_FLOW_FLAG_ONLY_FRAG) && - (pflags & PKT_REBUILT_FRAGMENT)) { + } else if ((dflags & DETECT_FLOW_FLAG_ONLY_FRAG) && (pflags & PKT_REBUILT_FRAGMENT)) { cnt++; } @@ -106,7 +103,8 @@ static inline int FlowMatch(const uint32_t pflags, const uint8_t pflowflags, con if ((dflags & DETECT_FLOW_FLAG_ESTABLISHED) && (pflowflags & FLOW_PKT_ESTABLISHED)) { cnt++; - } else if (dflags & DETECT_FLOW_FLAG_NOT_ESTABLISHED && (!(pflowflags & FLOW_PKT_ESTABLISHED))) { + } else if (dflags & DETECT_FLOW_FLAG_NOT_ESTABLISHED && + (!(pflowflags & FLOW_PKT_ESTABLISHED))) { cnt++; } else if (dflags & DETECT_FLOW_FLAG_STATELESS) { cnt++; @@ -126,8 +124,8 @@ static inline int FlowMatch(const uint32_t pflags, const uint8_t pflowflags, con * \retval 0 no match * \retval 1 match */ -int DetectFlowMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +int DetectFlowMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); @@ -146,8 +144,9 @@ int DetectFlowMatch (DetectEngineThreadCtx *det_ctx, Packet *p, const DetectFlowData *fd = (const DetectFlowData *)ctx; const int ret = FlowMatch(p->flags, p->flowflags, fd->flags, fd->match_cnt); - SCLogDebug("returning %" PRId32 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", - ret, fd->match_cnt, fd->flags, p->flowflags); + SCLogDebug("returning %" PRId32 " fd->match_cnt %" PRId32 + " fd->flags 0x%02X p->flowflags 0x%02X", + ret, fd->match_cnt, fd->flags, p->flowflags); SCReturnInt(ret); } @@ -165,7 +164,7 @@ static DetectFlowData *DetectFlowParse( DetectEngineCtx *de_ctx, const char *flowstr, uint16_t *parse_flags) { DetectFlowData *fd = NULL; - char *args[3] = {NULL,NULL,NULL}; + char *args[3] = { NULL, NULL, NULL }; int res = 0; size_t pcre2len; char str1[16] = "", str2[16] = "", str3[16] = ""; @@ -251,7 +250,8 @@ static DetectFlowData *DetectFlowParse( } fd->flags |= DETECT_FLOW_FLAG_STATELESS; fd->match_cnt++; - } else if (strcasecmp(args[i], "to_client") == 0 || strcasecmp(args[i], "from_server") == 0) { + } else if (strcasecmp(args[i], "to_client") == 0 || + strcasecmp(args[i], "from_server") == 0) { if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) { SCLogError("cannot set DETECT_FLOW_FLAG_TOCLIENT flag is already set"); goto error; @@ -261,7 +261,8 @@ static DetectFlowData *DetectFlowParse( } fd->flags |= DETECT_FLOW_FLAG_TOCLIENT; fd->match_cnt++; - } else if (strcasecmp(args[i], "to_server") == 0 || strcasecmp(args[i], "from_client") == 0){ + } else if (strcasecmp(args[i], "to_server") == 0 || + strcasecmp(args[i], "from_client") == 0) { if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) { SCLogError("cannot set DETECT_FLOW_FLAG_TOSERVER flag is already set"); goto error; @@ -330,12 +331,11 @@ static DetectFlowData *DetectFlowParse( if (fd != NULL) DetectFlowFree(de_ctx, fd); return NULL; - } int DetectFlowSetupImplicit(Signature *s, uint32_t flags) { -#define SIG_FLAG_BOTH (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT) +#define SIG_FLAG_BOTH (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT) BUG_ON(flags == 0); BUG_ON(flags & ~SIG_FLAG_BOTH); BUG_ON((flags & SIG_FLAG_BOTH) == SIG_FLAG_BOTH); @@ -374,7 +374,7 @@ int DetectFlowSetupImplicit(Signature *s, uint32_t flags) * \retval 0 on Success * \retval -1 on Failure */ -int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *flowstr) +int DetectFlowSetup(DetectEngineCtx *de_ctx, Signature *s, const char *flowstr) { uint16_t parse_flags = 0; @@ -428,7 +428,6 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *flowstr) if (fd != NULL) DetectFlowFree(de_ctx, fd); return -1; - } /** @@ -442,8 +441,7 @@ void DetectFlowFree(DetectEngineCtx *de_ctx, void *ptr) SCFree(fd); } -static void -PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; @@ -455,16 +453,14 @@ PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void * } } -static void -PrefilterPacketFlowSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketFlowSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectFlowData *fb = smctx; v->u16[0] = fb->flags; v->u16[1] = fb->match_cnt; } -static bool -PrefilterPacketFlowCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketFlowCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectFlowData *fb = smctx; if (v.u16[0] == fb->flags && v.u16[1] == fb->match_cnt) { @@ -475,16 +471,14 @@ PrefilterPacketFlowCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupFlow(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FLOW, - PrefilterPacketFlowSet, - PrefilterPacketFlowCompare, - PrefilterPacketFlowMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FLOW, PrefilterPacketFlowSet, + PrefilterPacketFlowCompare, PrefilterPacketFlowMatch); } static bool PrefilterFlowIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FLOW: return true; @@ -500,7 +494,7 @@ static bool PrefilterFlowIsPrefilterable(const Signature *s) * \test DetectFlowTestParse01 is a test to make sure that we return "something" * when given valid flow opt */ -static int DetectFlowTestParse01 (void) +static int DetectFlowTestParse01(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "established", &parsed_flags); @@ -513,20 +507,19 @@ static int DetectFlowTestParse01 (void) /** * \test DetectFlowTestParse02 is a test for setting the established flow opt */ -static int DetectFlowTestParse02 (void) +static int DetectFlowTestParse02(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "established", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && - fd->match_cnt == 1); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && fd->match_cnt == 1); PASS; } /** * \test DetectFlowTestParse03 is a test for setting the stateless flow opt */ -static int DetectFlowTestParse03 (void) +static int DetectFlowTestParse03(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "stateless", &parsed_flags); @@ -539,7 +532,7 @@ static int DetectFlowTestParse03 (void) /** * \test DetectFlowTestParse04 is a test for setting the to_client flow opt */ -static int DetectFlowTestParse04 (void) +static int DetectFlowTestParse04(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "to_client", &parsed_flags); @@ -552,7 +545,7 @@ static int DetectFlowTestParse04 (void) /** * \test DetectFlowTestParse05 is a test for setting the to_server flow opt */ -static int DetectFlowTestParse05 (void) +static int DetectFlowTestParse05(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "to_server", &parsed_flags); @@ -565,7 +558,7 @@ static int DetectFlowTestParse05 (void) /** * \test DetectFlowTestParse06 is a test for setting the from_server flow opt */ -static int DetectFlowTestParse06 (void) +static int DetectFlowTestParse06(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "from_server", &parsed_flags); @@ -578,7 +571,7 @@ static int DetectFlowTestParse06 (void) /** * \test DetectFlowTestParse07 is a test for setting the from_client flow opt */ -static int DetectFlowTestParse07 (void) +static int DetectFlowTestParse07(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "from_client", &parsed_flags); @@ -591,57 +584,58 @@ static int DetectFlowTestParse07 (void) /** * \test DetectFlowTestParse08 is a test for setting the established,to_client flow opts */ -static int DetectFlowTestParse08 (void) +static int DetectFlowTestParse08(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "established,to_client", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } /** - * \test DetectFlowTestParse09 is a test for setting the to_client,stateless flow opts (order of state,dir reversed) + * \test DetectFlowTestParse09 is a test for setting the to_client,stateless flow opts (order of + * state,dir reversed) */ -static int DetectFlowTestParse09 (void) +static int DetectFlowTestParse09(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "to_client,stateless", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && - fd->flags & DETECT_FLOW_FLAG_TOCLIENT && - fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } /** - * \test DetectFlowTestParse10 is a test for setting the from_server,stateless flow opts (order of state,dir reversed) + * \test DetectFlowTestParse10 is a test for setting the from_server,stateless flow opts (order of + * state,dir reversed) */ -static int DetectFlowTestParse10 (void) +static int DetectFlowTestParse10(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "from_server,stateless", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && - fd->flags & DETECT_FLOW_FLAG_TOCLIENT && - fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } /** - * \test DetectFlowTestParse11 is a test for setting the from_server,stateless flow opts with spaces all around + * \test DetectFlowTestParse11 is a test for setting the from_server,stateless flow opts with spaces + * all around */ -static int DetectFlowTestParse11 (void) +static int DetectFlowTestParse11(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, " from_server , stateless ", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && - fd->flags & DETECT_FLOW_FLAG_TOCLIENT && - fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } @@ -650,7 +644,7 @@ static int DetectFlowTestParse11 (void) * \test DetectFlowTestParseNocase01 is a test to make sure that we return "something" * when given valid flow opt */ -static int DetectFlowTestParseNocase01 (void) +static int DetectFlowTestParseNocase01(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "ESTABLISHED", &parsed_flags); @@ -662,13 +656,12 @@ static int DetectFlowTestParseNocase01 (void) /** * \test DetectFlowTestParseNocase02 is a test for setting the established flow opt */ -static int DetectFlowTestParseNocase02 (void) +static int DetectFlowTestParseNocase02(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "ESTABLISHED", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && - fd->match_cnt == 1); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && fd->match_cnt == 1); DetectFlowFree(NULL, fd); PASS; } @@ -676,7 +669,7 @@ static int DetectFlowTestParseNocase02 (void) /** * \test DetectFlowTestParseNocase03 is a test for setting the stateless flow opt */ -static int DetectFlowTestParseNocase03 (void) +static int DetectFlowTestParseNocase03(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "STATELESS", &parsed_flags); @@ -689,7 +682,7 @@ static int DetectFlowTestParseNocase03 (void) /** * \test DetectFlowTestParseNocase04 is a test for setting the to_client flow opt */ -static int DetectFlowTestParseNocase04 (void) +static int DetectFlowTestParseNocase04(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "TO_CLIENT", &parsed_flags); @@ -702,7 +695,7 @@ static int DetectFlowTestParseNocase04 (void) /** * \test DetectFlowTestParseNocase05 is a test for setting the to_server flow opt */ -static int DetectFlowTestParseNocase05 (void) +static int DetectFlowTestParseNocase05(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "TO_SERVER", &parsed_flags); @@ -715,7 +708,7 @@ static int DetectFlowTestParseNocase05 (void) /** * \test DetectFlowTestParseNocase06 is a test for setting the from_server flow opt */ -static int DetectFlowTestParseNocase06 (void) +static int DetectFlowTestParseNocase06(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "FROM_SERVER", &parsed_flags); @@ -728,7 +721,7 @@ static int DetectFlowTestParseNocase06 (void) /** * \test DetectFlowTestParseNocase07 is a test for setting the from_client flow opt */ -static int DetectFlowTestParseNocase07 (void) +static int DetectFlowTestParseNocase07(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "FROM_CLIENT", &parsed_flags); @@ -741,59 +734,58 @@ static int DetectFlowTestParseNocase07 (void) /** * \test DetectFlowTestParseNocase08 is a test for setting the established,to_client flow opts */ -static int DetectFlowTestParseNocase08 (void) +static int DetectFlowTestParseNocase08(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "ESTABLISHED,TO_CLIENT", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && - fd->flags & DETECT_FLOW_FLAG_TOCLIENT && - fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } /** - * \test DetectFlowTestParseNocase09 is a test for setting the to_client,stateless flow opts (order of state,dir reversed) + * \test DetectFlowTestParseNocase09 is a test for setting the to_client,stateless flow opts (order + * of state,dir reversed) */ -static int DetectFlowTestParseNocase09 (void) +static int DetectFlowTestParseNocase09(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "TO_CLIENT,STATELESS", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && - fd->flags & DETECT_FLOW_FLAG_TOCLIENT && - fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } /** - * \test DetectFlowTestParseNocase10 is a test for setting the from_server,stateless flow opts (order of state,dir reversed) + * \test DetectFlowTestParseNocase10 is a test for setting the from_server,stateless flow opts + * (order of state,dir reversed) */ -static int DetectFlowTestParseNocase10 (void) +static int DetectFlowTestParseNocase10(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "FROM_SERVER,STATELESS", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && - fd->flags & DETECT_FLOW_FLAG_TOCLIENT && - fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } /** - * \test DetectFlowTestParseNocase11 is a test for setting the from_server,stateless flow opts with spaces all around + * \test DetectFlowTestParseNocase11 is a test for setting the from_server,stateless flow opts with + * spaces all around */ -static int DetectFlowTestParseNocase11 (void) +static int DetectFlowTestParseNocase11(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, " FROM_SERVER , STATELESS ", &parsed_flags); FAIL_IF_NULL(fd); - FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && - fd->flags & DETECT_FLOW_FLAG_TOCLIENT && - fd->match_cnt == 2); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); DetectFlowFree(NULL, fd); PASS; } @@ -801,7 +793,7 @@ static int DetectFlowTestParseNocase11 (void) /** * \test DetectFlowTestParse12 is a test for setting an invalid separator : */ -static int DetectFlowTestParse12 (void) +static int DetectFlowTestParse12(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "from_server:stateless", &parsed_flags); @@ -812,7 +804,7 @@ static int DetectFlowTestParse12 (void) /** * \test DetectFlowTestParse13 is a test for an invalid option */ -static int DetectFlowTestParse13 (void) +static int DetectFlowTestParse13(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "invalidoptiontest", &parsed_flags); @@ -823,7 +815,7 @@ static int DetectFlowTestParse13 (void) /** * \test DetectFlowTestParse14 is a test for a empty option */ -static int DetectFlowTestParse14 (void) +static int DetectFlowTestParse14(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "", &parsed_flags); @@ -834,7 +826,7 @@ static int DetectFlowTestParse14 (void) /** * \test DetectFlowTestParse15 is a test for an invalid combo of options established,stateless */ -static int DetectFlowTestParse15 (void) +static int DetectFlowTestParse15(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "established,stateless", &parsed_flags); @@ -845,7 +837,7 @@ static int DetectFlowTestParse15 (void) /** * \test DetectFlowTestParse16 is a test for an invalid combo of options to_client,to_server */ -static int DetectFlowTestParse16 (void) +static int DetectFlowTestParse16(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "to_client,to_server", &parsed_flags); @@ -857,7 +849,7 @@ static int DetectFlowTestParse16 (void) * \test DetectFlowTestParse16 is a test for an invalid combo of options to_client,from_server * flowbit flags are the same */ -static int DetectFlowTestParse17 (void) +static int DetectFlowTestParse17(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "to_client,from_server", &parsed_flags); @@ -866,9 +858,10 @@ static int DetectFlowTestParse17 (void) } /** - * \test DetectFlowTestParse18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed) + * \test DetectFlowTestParse18 is a test for setting the from_server,stateless,only_stream flow opts + * (order of state,dir reversed) */ -static int DetectFlowTestParse18 (void) +static int DetectFlowTestParse18(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = @@ -882,9 +875,10 @@ static int DetectFlowTestParse18 (void) } /** - * \test DetectFlowTestParseNocase18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed) + * \test DetectFlowTestParseNocase18 is a test for setting the from_server,stateless,only_stream + * flow opts (order of state,dir reversed) */ -static int DetectFlowTestParseNocase18 (void) +static int DetectFlowTestParseNocase18(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = @@ -897,11 +891,10 @@ static int DetectFlowTestParseNocase18 (void) PASS; } - /** * \test DetectFlowTestParse19 is a test for one to many options passed to DetectFlowParse */ -static int DetectFlowTestParse19 (void) +static int DetectFlowTestParse19(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = @@ -913,7 +906,7 @@ static int DetectFlowTestParse19 (void) /** * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream */ -static int DetectFlowTestParse20 (void) +static int DetectFlowTestParse20(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "from_server,established,no_stream", &parsed_flags); @@ -928,7 +921,7 @@ static int DetectFlowTestParse20 (void) /** * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream */ -static int DetectFlowTestParseNocase20 (void) +static int DetectFlowTestParseNocase20(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "FROM_SERVER,ESTABLISHED,NO_STREAM", &parsed_flags); @@ -943,7 +936,7 @@ static int DetectFlowTestParseNocase20 (void) /** * \test DetectFlowTestParse21 is a test for an invalid opt between to valid opts */ -static int DetectFlowTestParse21 (void) +static int DetectFlowTestParse21(void) { uint16_t parsed_flags = 0; DetectFlowData *fd = DetectFlowParse(NULL, "from_server,a,no_stream", &parsed_flags); @@ -977,7 +970,7 @@ static int DetectFlowSigTest01(void) FAIL_IF_NULL(p); const char *sig1 = "alert tcp any any -> any any (msg:\"dummy\"; " - "content:\"nova\"; flow:no_stream; sid:1;)"; + "content:\"nova\"; flow:no_stream; sid:1;)"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); @@ -1125,13 +1118,10 @@ static void DetectFlowRegisterTests(void) UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20); UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21); UtRegisterTest("DetectFlowTestParse22", DetectFlowTestParse22); - UtRegisterTest("DetectFlowTestParseNotEstablished", - DetectFlowTestParseNotEstablished); + UtRegisterTest("DetectFlowTestParseNotEstablished", DetectFlowTestParseNotEstablished); UtRegisterTest("DetectFlowTestParseNoFrag", DetectFlowTestParseNoFrag); - UtRegisterTest("DetectFlowTestParseOnlyFrag", - DetectFlowTestParseOnlyFrag); - UtRegisterTest("DetectFlowTestParseNoFragOnlyFrag", - DetectFlowTestParseNoFragOnlyFrag); + UtRegisterTest("DetectFlowTestParseOnlyFrag", DetectFlowTestParseOnlyFrag); + UtRegisterTest("DetectFlowTestParseNoFragOnlyFrag", DetectFlowTestParseNoFragOnlyFrag); UtRegisterTest("DetectFlowTestNoFragMatch", DetectFlowTestNoFragMatch); UtRegisterTest("DetectFlowTestOnlyFragMatch", DetectFlowTestOnlyFragMatch); diff --git a/src/detect-flow.h b/src/detect-flow.h index 0fee4bf8c17a..d289795dba08 100644 --- a/src/detect-flow.h +++ b/src/detect-flow.h @@ -35,14 +35,13 @@ #define DETECT_FLOW_FLAG_ONLY_FRAG BIT_U16(8) typedef struct DetectFlowData_ { - uint16_t flags; /* flags to match */ - uint8_t match_cnt; /* number of matches we need */ + uint16_t flags; /* flags to match */ + uint8_t match_cnt; /* number of matches we need */ } DetectFlowData; int DetectFlowSetupImplicit(Signature *s, uint32_t flags); /* prototypes */ -void DetectFlowRegister (void); +void DetectFlowRegister(void); #endif /* __DETECT_FLOW_H__ */ - diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index b04c271dc548..428999d294a5 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -32,7 +32,7 @@ #include "flow-bit.h" #include "flow-util.h" #include "detect-flowbits.h" -#include "util-spm.h" +#include "util/spm.h" #include "app-layer-parser.h" @@ -42,33 +42,32 @@ #include "detect-engine-state.h" #include "detect-engine-build.h" -#include "util-var-name.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-conf.h" +#include "util/var-name.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/conf.h" -#define PARSE_REGEX "^([a-z]+)(?:,\\s*(.*))?" +#define PARSE_REGEX "^([a-z]+)(?:,\\s*(.*))?" static DetectParseRegex parse_regex; #define MAX_TOKENS 100 -int DetectFlowbitMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, const char *); +int DetectFlowbitMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectFlowbitSetup(DetectEngineCtx *, Signature *, const char *); static int FlowbitOrAddData(DetectEngineCtx *, DetectFlowbitsData *, char *); -void DetectFlowbitFree (DetectEngineCtx *, void *); +void DetectFlowbitFree(DetectEngineCtx *, void *); #ifdef UNITTESTS void FlowBitsRegisterTests(void); #endif -void DetectFlowbitsRegister (void) +void DetectFlowbitsRegister(void) { sigmatch_table[DETECT_FLOWBITS].name = "flowbits"; sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag"; sigmatch_table[DETECT_FLOWBITS].url = "/rules/flow-keywords.html#flowbits"; sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch; sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup; - sigmatch_table[DETECT_FLOWBITS].Free = DetectFlowbitFree; + sigmatch_table[DETECT_FLOWBITS].Free = DetectFlowbitFree; #ifdef UNITTESTS sigmatch_table[DETECT_FLOWBITS].RegisterTests = FlowBitsRegisterTests; #endif @@ -87,12 +86,12 @@ static int FlowbitOrAddData(DetectEngineCtx *de_ctx, DetectFlowbitsData *cd, cha while ((token = strtok_r(arrptr, "|", &saveptr))) { // Check for leading/trailing spaces in the token - while(isspace((unsigned char)*token)) + while (isspace((unsigned char)*token)) token++; if (*token == 0) goto next; char *end = token + strlen(token) - 1; - while(end > token && isspace((unsigned char)*end)) + while (end > token && isspace((unsigned char)*end)) *(end--) = '\0'; // Check for spaces in between the flowbit names @@ -120,7 +119,7 @@ static int FlowbitOrAddData(DetectEngineCtx *de_ctx, DetectFlowbitsData *cd, cha cd->or_list = SCCalloc(cd->or_list_size, sizeof(uint32_t)); if (unlikely(cd->or_list == NULL)) return -1; - for (uint8_t j = 0; j < cd->or_list_size ; j++) { + for (uint8_t j = 0; j < cd->or_list_size; j++) { cd->or_list[j] = VarNameStoreRegister(strarr[j], VAR_TYPE_FLOW_BIT); de_ctx->max_fb_id = MAX(cd->or_list[j], de_ctx->max_fb_id); } @@ -128,37 +127,37 @@ static int FlowbitOrAddData(DetectEngineCtx *de_ctx, DetectFlowbitsData *cd, cha return 1; } -static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchToggle(Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; - FlowBitToggle(p->flow,fd->idx); + FlowBitToggle(p->flow, fd->idx); return 1; } -static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchUnset(Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; - FlowBitUnset(p->flow,fd->idx); + FlowBitUnset(p->flow, fd->idx); return 1; } -static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchSet(Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; - FlowBitSet(p->flow,fd->idx); + FlowBitSet(p->flow, fd->idx); return 1; } -static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchIsset(Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -170,10 +169,10 @@ static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd) return 0; } - return FlowBitIsset(p->flow,fd->idx); + return FlowBitIsset(p->flow, fd->idx); } -static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd) +static int DetectFlowbitMatchIsnotset(Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -184,7 +183,7 @@ static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd) } return 0; } - return FlowBitIsnotset(p->flow,fd->idx); + return FlowBitIsnotset(p->flow, fd->idx); } /* @@ -193,8 +192,8 @@ static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd) * -1: error */ -int DetectFlowbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +int DetectFlowbitMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx; if (fd == NULL) @@ -202,15 +201,15 @@ int DetectFlowbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, switch (fd->cmd) { case DETECT_FLOWBITS_CMD_ISSET: - return DetectFlowbitMatchIsset(p,fd); + return DetectFlowbitMatchIsset(p, fd); case DETECT_FLOWBITS_CMD_ISNOTSET: - return DetectFlowbitMatchIsnotset(p,fd); + return DetectFlowbitMatchIsnotset(p, fd); case DETECT_FLOWBITS_CMD_SET: - return DetectFlowbitMatchSet(p,fd); + return DetectFlowbitMatchSet(p, fd); case DETECT_FLOWBITS_CMD_UNSET: - return DetectFlowbitMatchUnset(p,fd); + return DetectFlowbitMatchUnset(p, fd); case DETECT_FLOWBITS_CMD_TOGGLE: - return DetectFlowbitMatchToggle(p,fd); + return DetectFlowbitMatchToggle(p, fd); default: SCLogError("unknown cmd %" PRIu32 "", fd->cmd); return 0; @@ -219,8 +218,7 @@ int DetectFlowbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, return 0; } -static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name, - int name_len) +static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name, int name_len) { int rc; size_t pcre2len; @@ -273,28 +271,27 @@ static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *nam return 0; } -int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +int DetectFlowbitSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectFlowbitsData *cd = NULL; uint8_t fb_cmd = 0; char fb_cmd_str[16] = "", fb_name[256] = ""; - if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name, - sizeof(fb_name))) { + if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name, sizeof(fb_name))) { return -1; } - if (strcmp(fb_cmd_str,"noalert") == 0) { + if (strcmp(fb_cmd_str, "noalert") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_NOALERT; - } else if (strcmp(fb_cmd_str,"isset") == 0) { + } else if (strcmp(fb_cmd_str, "isset") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_ISSET; - } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + } else if (strcmp(fb_cmd_str, "isnotset") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET; - } else if (strcmp(fb_cmd_str,"set") == 0) { + } else if (strcmp(fb_cmd_str, "set") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_SET; - } else if (strcmp(fb_cmd_str,"unset") == 0) { + } else if (strcmp(fb_cmd_str, "unset") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_UNSET; - } else if (strcmp(fb_cmd_str,"toggle") == 0) { + } else if (strcmp(fb_cmd_str, "toggle") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE; } else { SCLogError("ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); @@ -333,14 +330,14 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst cd->cmd = fb_cmd; cd->or_list_size = 0; cd->or_list = NULL; - SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", - cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, + strlen(fb_name) ? fb_name : "(none)"); } /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ switch (fb_cmd) { - /* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */ + /* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */ case DETECT_FLOWBITS_CMD_ISNOTSET: case DETECT_FLOWBITS_CMD_ISSET: @@ -375,7 +372,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst return -1; } -void DetectFlowbitFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectFlowbitFree(DetectEngineCtx *de_ctx, void *ptr) { DetectFlowbitsData *fd = (DetectFlowbitsData *)ptr; if (fd == NULL) @@ -416,8 +413,8 @@ struct FBAnalyze { }; extern bool rule_engine_analysis_set; -static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx, - struct FBAnalyze *array, uint32_t elements); +static void DetectFlowbitsAnalyzeDump( + const DetectEngineCtx *de_ctx, struct FBAnalyze *array, uint32_t elements); int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) { @@ -434,8 +431,8 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) return -1; } - SCLogDebug("fb analyzer array size: %"PRIu64, - (uint64_t)(array_size * sizeof(struct FBAnalyze))); + SCLogDebug( + "fb analyzer array size: %" PRIu64, (uint64_t)(array_size * sizeof(struct FBAnalyze))); /* fill flowbit array, updating counters per sig */ for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) { @@ -444,10 +441,10 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) /* see if the signature uses stateful matching */ bool has_state = (s->init_data->buffer_index != 0); - for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; + sm = sm->next) { switch (sm->type) { - case DETECT_FLOWBITS: - { + case DETECT_FLOWBITS: { /* figure out the flowbit action */ const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx; // Handle flowbit array in case of ORed flowbits @@ -456,32 +453,39 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) if (has_state) array[fb->or_list[k]].state_cnts[fb->cmd]++; if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { - if (array[fb->or_list[k]].isset_sids_idx >= array[fb->or_list[k]].isset_sids_size) { + if (array[fb->or_list[k]].isset_sids_idx >= + array[fb->or_list[k]].isset_sids_size) { uint32_t old_size = array[fb->or_list[k]].isset_sids_size; uint32_t new_size = MAX(2 * old_size, MAX_SIDS); - void *ptr = SCRealloc(array[fb->or_list[k]].isset_sids, new_size * sizeof(uint32_t)); + void *ptr = SCRealloc(array[fb->or_list[k]].isset_sids, + new_size * sizeof(uint32_t)); if (ptr == NULL) goto end; array[fb->or_list[k]].isset_sids_size = new_size; array[fb->or_list[k]].isset_sids = ptr; } - array[fb->or_list[k]].isset_sids[array[fb->or_list[k]].isset_sids_idx] = s->num; + array[fb->or_list[k]].isset_sids[array[fb->or_list[k]].isset_sids_idx] = + s->num; array[fb->or_list[k]].isset_sids_idx++; } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) { - if (array[fb->or_list[k]].isnotset_sids_idx >= array[fb->or_list[k]].isnotset_sids_size) { + if (array[fb->or_list[k]].isnotset_sids_idx >= + array[fb->or_list[k]].isnotset_sids_size) { uint32_t old_size = array[fb->or_list[k]].isnotset_sids_size; uint32_t new_size = MAX(2 * old_size, MAX_SIDS); - void *ptr = SCRealloc(array[fb->or_list[k]].isnotset_sids, new_size * sizeof(uint32_t)); + void *ptr = SCRealloc(array[fb->or_list[k]].isnotset_sids, + new_size * sizeof(uint32_t)); if (ptr == NULL) goto end; array[fb->or_list[k]].isnotset_sids_size = new_size; array[fb->or_list[k]].isnotset_sids = ptr; } - array[fb->or_list[k]].isnotset_sids[array[fb->or_list[k]].isnotset_sids_idx] = s->num; + array[fb->or_list[k]] + .isnotset_sids[array[fb->or_list[k]].isnotset_sids_idx] = + s->num; array[fb->or_list[k]].isnotset_sids_idx++; } } @@ -494,7 +498,8 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) uint32_t old_size = array[fb->idx].isset_sids_size; uint32_t new_size = MAX(2 * old_size, MAX_SIDS); - void *ptr = SCRealloc(array[fb->idx].isset_sids, new_size * sizeof(uint32_t)); + void *ptr = SCRealloc( + array[fb->idx].isset_sids, new_size * sizeof(uint32_t)); if (ptr == NULL) goto end; array[fb->idx].isset_sids_size = new_size; @@ -504,11 +509,13 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) array[fb->idx].isset_sids[array[fb->idx].isset_sids_idx] = s->num; array[fb->idx].isset_sids_idx++; } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) { - if (array[fb->idx].isnotset_sids_idx >= array[fb->idx].isnotset_sids_size) { + if (array[fb->idx].isnotset_sids_idx >= + array[fb->idx].isnotset_sids_size) { uint32_t old_size = array[fb->idx].isnotset_sids_size; uint32_t new_size = MAX(2 * old_size, MAX_SIDS); - void *ptr = SCRealloc(array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t)); + void *ptr = SCRealloc( + array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t)); if (ptr == NULL) goto end; array[fb->idx].isnotset_sids_size = new_size; @@ -522,10 +529,10 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) } } } - for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH] ; sm != NULL; sm = sm->next) { + for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; sm != NULL; + sm = sm->next) { switch (sm->type) { - case DETECT_FLOWBITS: - { + case DETECT_FLOWBITS: { /* figure out what flowbit action */ const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx; array[fb->idx].cnts[fb->cmd]++; @@ -536,7 +543,8 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) uint32_t old_size = array[fb->idx].set_sids_size; uint32_t new_size = MAX(2 * old_size, MAX_SIDS); - void *ptr = SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t)); + void *ptr = + SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t)); if (ptr == NULL) goto end; array[fb->idx].set_sids_size = new_size; @@ -545,13 +553,13 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) array[fb->idx].set_sids[array[fb->idx].set_sids_idx] = s->num; array[fb->idx].set_sids_idx++; - } - else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) { + } else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) { if (array[fb->idx].unset_sids_idx >= array[fb->idx].unset_sids_size) { uint32_t old_size = array[fb->idx].unset_sids_size; uint32_t new_size = MAX(2 * old_size, MAX_SIDS); - void *ptr = SCRealloc(array[fb->idx].unset_sids, new_size * sizeof(uint32_t)); + void *ptr = SCRealloc( + array[fb->idx].unset_sids, new_size * sizeof(uint32_t)); if (ptr == NULL) goto end; array[fb->idx].unset_sids_size = new_size; @@ -560,13 +568,13 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) array[fb->idx].unset_sids[array[fb->idx].unset_sids_idx] = s->num; array[fb->idx].unset_sids_idx++; - } - else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) { + } else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) { if (array[fb->idx].toggle_sids_idx >= array[fb->idx].toggle_sids_size) { uint32_t old_size = array[fb->idx].toggle_sids_size; uint32_t new_size = MAX(2 * old_size, MAX_SIDS); - void *ptr = SCRealloc(array[fb->idx].toggle_sids, new_size * sizeof(uint32_t)); + void *ptr = SCRealloc( + array[fb->idx].toggle_sids, new_size * sizeof(uint32_t)); if (ptr == NULL) goto end; array[fb->idx].toggle_sids_size = new_size; @@ -590,8 +598,8 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) bool to_state = false; if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] && - array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 && - array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) { + array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 && + array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) { const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]]; SCLogWarning("flowbit '%s' is checked but not " @@ -599,28 +607,29 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) varname, s->id, array[i].isset_sids_idx - 1); } if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] && - array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0) - { + array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0) { SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i); } /* if signature depends on 'stateful' flowbits, then turn the * sig into a stateful sig itself */ if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 && - array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 && - array[i].state_cnts[DETECT_FLOWBITS_CMD_SET]) - { + array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 && + array[i].state_cnts[DETECT_FLOWBITS_CMD_SET]) { SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i); to_state = true; } - SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i, - array[i].cnts[DETECT_FLOWBITS_CMD_SET], array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE], - array[i].cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].cnts[DETECT_FLOWBITS_CMD_ISNOTSET], + SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", + varname, i, array[i].cnts[DETECT_FLOWBITS_CMD_SET], + array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE], array[i].cnts[DETECT_FLOWBITS_CMD_UNSET], + array[i].cnts[DETECT_FLOWBITS_CMD_ISNOTSET], array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]); - SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i, - array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE], - array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET], + SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", + varname, i, array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], + array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE], + array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], + array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET]); for (uint32_t x = 0; x < array[i].set_sids_idx; x++) { SCLogDebug("SET flowbit %s/%u: SID %u", varname, i, @@ -633,7 +642,8 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) if (to_state) { s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH; SCLogDebug("made SID %u stateful because it depends on " - "stateful rules that set flowbit %s", s->id, varname); + "stateful rules that set flowbit %s", + s->id, varname); } } } @@ -656,8 +666,8 @@ int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx) } SCMutex g_flowbits_dump_write_m = SCMUTEX_INITIALIZER; -static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx, - struct FBAnalyze *array, uint32_t elements) +static void DetectFlowbitsAnalyzeDump( + const DetectEngineCtx *de_ctx, struct FBAnalyze *array, uint32_t elements) { JsonBuilder *js = jb_new_object(); if (js == NULL) @@ -754,37 +764,31 @@ static int FlowBitsTestParse01(void) char command[16] = "", name[16] = ""; /* Single argument version. */ - FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name, - sizeof(name))); + FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name, sizeof(name))); FAIL_IF(strcmp(command, "noalert") != 0); /* No leading or trailing spaces. */ - FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name, - sizeof(name))); + FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name, sizeof(name))); FAIL_IF(strcmp(command, "set") != 0); FAIL_IF(strcmp(name, "flowbit") != 0); /* Leading space. */ - FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name, - sizeof(name))); + FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name, sizeof(name))); FAIL_IF(strcmp(command, "set") != 0); FAIL_IF(strcmp(name, "flowbit") != 0); /* Trailing space. */ - FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name, - sizeof(name))); + FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name, sizeof(name))); FAIL_IF(strcmp(command, "set") != 0); FAIL_IF(strcmp(name, "flowbit") != 0); /* Leading and trailing space. */ - FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name, - sizeof(name))); + FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name, sizeof(name))); FAIL_IF(strcmp(command, "set") != 0); FAIL_IF(strcmp(name, "flowbit") != 0); /* Spaces are not allowed in the name. */ - FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command), - name, sizeof(name))); + FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command), name, sizeof(name))); PASS; } @@ -806,7 +810,9 @@ static int FlowBitsTestSig01(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert ip any any -> any any (msg:\"Noalert\"; " + "flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)"); FAIL_IF_NOT_NULL(s); SigGroupBuild(de_ctx); @@ -834,22 +840,30 @@ static int FlowBitsTestSig02(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"isset rule need an " + "option\"; flowbits:isset; content:\"GET \"; sid:1;)"); FAIL_IF_NOT_NULL(s); - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert ip any any -> any any (msg:\"isnotset rule need an option\"; " + "flowbits:isnotset; content:\"GET \"; sid:2;)"); FAIL_IF_NOT_NULL(s); - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"set rule need an " + "option\"; flowbits:set; content:\"GET \"; sid:3;)"); FAIL_IF_NOT_NULL(s); - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"unset rule need an " + "option\"; flowbits:unset; content:\"GET \"; sid:4;)"); FAIL_IF_NOT_NULL(s); - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"toggle rule need an " + "option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); FAIL_IF_NOT_NULL(s); - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"!set is not an option\"; flowbits:!set,myerr; content:\"GET \"; sid:6;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert ip any any -> any any (msg:\"!set is not an option\"; " + "flowbits:!set,myerr; content:\"GET \"; sid:6;)"); FAIL_IF_NOT_NULL(s); SigGroupBuild(de_ctx); @@ -875,7 +889,8 @@ static int FlowBitsTestSig03(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"Unknown cmd\"; " + "flowbits:wrongcmd; content:\"GET \"; sid:1;)"); FAIL_IF_NOT_NULL(s); SigGroupBuild(de_ctx); @@ -900,7 +915,8 @@ static int FlowBitsTestSig04(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"isset option\"; " + "flowbits:isset,fbt; content:\"GET \"; sid:1;)"); FAIL_IF_NULL(s); idx = VarNameStoreRegister("fbt", VAR_TYPE_FLOW_BIT); @@ -928,7 +944,8 @@ static int FlowBitsTestSig05(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"Noalert\"; " + "flowbits:noalert; content:\"GET \"; sid:1;)"); FAIL_IF_NULL(s); FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT); @@ -946,10 +963,9 @@ static int FlowBitsTestSig05(void) static int FlowBitsTestSig06(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -983,7 +999,8 @@ static int FlowBitsTestSig06(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); FAIL_IF_NULL(s); idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT); @@ -994,9 +1011,9 @@ static int FlowBitsTestSig06(void) gv = p->flow->flowvar; FAIL_IF_NULL(gv); - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { - result = 1; + result = 1; } } FAIL_IF_NOT(result); @@ -1019,10 +1036,9 @@ static int FlowBitsTestSig06(void) static int FlowBitsTestSig07(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -1054,10 +1070,12 @@ static int FlowBitsTestSig07(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); FAIL_IF_NULL(s); - s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); + s = s->next = SigInit(de_ctx, + "alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); FAIL_IF_NULL(s); idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT); @@ -1069,9 +1087,9 @@ static int FlowBitsTestSig07(void) gv = p->flow->flowvar; FAIL_IF_NULL(gv); - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { - result = 1; + result = 1; } } FAIL_IF(result); @@ -1094,10 +1112,9 @@ static int FlowBitsTestSig07(void) static int FlowBitsTestSig08(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1130,10 +1147,12 @@ static int FlowBitsTestSig08(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); FAIL_IF_NULL(s); - s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)"); + s = s->next = SigInit(de_ctx, "alert ip any any -> any any (msg:\"Flowbit unset\"; " + "flowbits:toggle,myflow2; sid:11;)"); FAIL_IF_NULL(s); idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT); @@ -1145,9 +1164,9 @@ static int FlowBitsTestSig08(void) gv = p->flow->flowvar; FAIL_IF_NULL(gv); - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { - result = 1; + result = 1; } } FAIL_IF(result); diff --git a/src/detect-flowbits.h b/src/detect-flowbits.h index 5ecd6cf87296..1f9b6d693a7c 100644 --- a/src/detect-flowbits.h +++ b/src/detect-flowbits.h @@ -41,7 +41,6 @@ typedef struct DetectFlowbitsData_ { } DetectFlowbitsData; /* prototypes */ -void DetectFlowbitsRegister (void); +void DetectFlowbitsRegister(void); #endif /* __DETECT_FLOWBITS_H__ */ - diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 224eb650dc64..11ae5dfd2339 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -31,11 +31,11 @@ #include "flow.h" #include "flow-var.h" #include "detect-flowint.h" -#include "util-spm.h" -#include "util-var-name.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/spm.h" +#include "util/var-name.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" @@ -45,16 +45,18 @@ #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" +#include "util/profiling.h" /* name modifiers value */ -#define PARSE_REGEX "^\\s*([a-zA-Z][\\w\\d_./]+)\\s*,\\s*([+=-]{1}|==|!=|<|<=|>|>=|isset|notset)\\s*,?\\s*([a-zA-Z][\\w\\d]+|[\\d]{1,10})?\\s*$" +#define PARSE_REGEX \ + "^\\s*([a-zA-Z][\\w\\d_./" \ + "]+)\\s*,\\s*([+=-]{1}|==|!=|<|<=|>|>=|isset|notset)\\s*,?\\s*([a-zA-Z][\\w\\d]+|[\\d]{1,10})" \ + "?\\s*$" /* Varnames must begin with a letter */ static DetectParseRegex parse_regex; -int DetectFlowintMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +int DetectFlowintMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectFlowintSetup(DetectEngineCtx *, Signature *, const char *); void DetectFlowintFree(DetectEngineCtx *, void *); #ifdef UNITTESTS @@ -89,8 +91,8 @@ void DetectFlowintRegister(void) * \retval 1 match, when a var is initialized well, add/subtracted, or a true * condition */ -int DetectFlowintMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +int DetectFlowintMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectFlowintData *sfd = (const DetectFlowintData *)ctx; FlowVar *fv; @@ -113,7 +115,7 @@ int DetectFlowintMatch(DetectEngineThreadCtx *det_ctx, uint32_t tvar_idx = VarNameStoreLookupByName(sfd->target.tvar.name, VAR_TYPE_FLOW_INT); fvt = FlowVarGet(p->flow, tvar_idx); - /* We don't have that variable initialized yet */ + /* We don't have that variable initialized yet */ if (fvt == NULL) targetval = 0; else @@ -122,7 +124,7 @@ int DetectFlowintMatch(DetectEngineThreadCtx *det_ctx, targetval = sfd->target.value; } - SCLogDebug("Our var %s is at idx: %"PRIu32"", sfd->name, sfd->idx); + SCLogDebug("Our var %s is at idx: %" PRIu32 "", sfd->name, sfd->idx); if (sfd->modifier == FLOWINT_MODIFIER_SET) { FlowVarAddIntNoLock(p->flow, sfd->idx, targetval); @@ -134,14 +136,14 @@ int DetectFlowintMatch(DetectEngineThreadCtx *det_ctx, fv = FlowVarGet(p->flow, sfd->idx); if (sfd->modifier == FLOWINT_MODIFIER_ISSET) { - SCLogDebug(" Isset %s? = %u", sfd->name,(fv) ? 1 : 0); + SCLogDebug(" Isset %s? = %u", sfd->name, (fv) ? 1 : 0); if (fv != NULL) ret = 1; goto end; } if (sfd->modifier == FLOWINT_MODIFIER_NOTSET) { - SCLogDebug(" Not set %s? = %u", sfd->name,(fv) ? 0 : 1); + SCLogDebug(" Not set %s? = %u", sfd->name, (fv) ? 0 : 1); if (fv == NULL) ret = 1; goto end; @@ -150,21 +152,19 @@ int DetectFlowintMatch(DetectEngineThreadCtx *det_ctx, if (fv != NULL && fv->datatype == FLOWVAR_TYPE_INT) { if (sfd->modifier == FLOWINT_MODIFIER_ADD) { SCLogDebug("Adding %u to %s", targetval, sfd->name); - FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value + - targetval); + FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value + targetval); ret = 1; goto end; } if (sfd->modifier == FLOWINT_MODIFIER_SUB) { SCLogDebug("Subtracting %u to %s", targetval, sfd->name); - FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value - - targetval); + FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value - targetval); ret = 1; goto end; } - switch(sfd->modifier) { + switch (sfd->modifier) { case FLOWINT_MODIFIER_EQ: SCLogDebug("( %u EQ %u )", fv->data.fv_int.value, targetval); ret = (fv->data.fv_int.value == targetval); @@ -309,10 +309,11 @@ static DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, const char value_long = atoll(varval); if (value_long > UINT32_MAX) { SCLogDebug("DetectFlowintParse: Cannot load this value." - " Values should be between 0 and %"PRIu32, UINT32_MAX); + " Values should be between 0 and %" PRIu32, + UINT32_MAX); goto error; } - sfd->target.value = (uint32_t) value_long; + sfd->target.value = (uint32_t)value_long; } else { sfd->targettype = FLOWINT_TARGET_VAR; sfd->target.tvar.name = SCStrdup(varval); @@ -417,7 +418,7 @@ static int DetectFlowintSetup(DetectEngineCtx *de_ctx, Signature *s, const char */ void DetectFlowintFree(DetectEngineCtx *de_ctx, void *tmp) { - DetectFlowintData *sfd =(DetectFlowintData*) tmp; + DetectFlowintData *sfd = (DetectFlowintData *)tmp; if (sfd != NULL) { VarNameStoreUnregister(sfd->idx, VAR_TYPE_FLOW_INT); if (sfd->name != NULL) @@ -441,17 +442,16 @@ static void DetectFlowintPrintData(DetectFlowintData *sfd) return; } - SCLogDebug("Varname: %s, modifier: %"PRIu8", idx: %"PRIu32" Target: ", - sfd->name, sfd->modifier, sfd->idx); - switch(sfd->targettype) { + SCLogDebug("Varname: %s, modifier: %" PRIu8 ", idx: %" PRIu32 " Target: ", sfd->name, + sfd->modifier, sfd->idx); + switch (sfd->targettype) { case FLOWINT_TARGET_VAR: - SCLogDebug("target_var: %s", - sfd->target.tvar.name); + SCLogDebug("target_var: %s", sfd->target.tvar.name); break; case FLOWINT_TARGET_VAL: - SCLogDebug("Value: %"PRIu32"; ", sfd->target.value); + SCLogDebug("Value: %" PRIu32 "; ", sfd->target.value); break; - default : + default: SCLogDebug("DetectFlowintPrintData: Error, Targettype not known!"); } } @@ -472,11 +472,12 @@ static int DetectFlowintTestParseVal01(void) sfd = DetectFlowintParse(de_ctx, "myvar,=,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_SET) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_SET) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -499,15 +500,14 @@ static int DetectFlowintTestParseVar01(void) sfd = DetectFlowintParse(de_ctx, "myvar,=,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_SET) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_SET) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -529,11 +529,12 @@ static int DetectFlowintTestParseVal02(void) sfd = DetectFlowintParse(de_ctx, "myvar,+,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_ADD) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_ADD) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -556,15 +557,14 @@ static int DetectFlowintTestParseVar02(void) sfd = DetectFlowintParse(de_ctx, "myvar,+,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_ADD) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_ADD) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -586,11 +586,12 @@ static int DetectFlowintTestParseVal03(void) sfd = DetectFlowintParse(de_ctx, "myvar,-,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_SUB) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_SUB) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -613,21 +614,19 @@ static int DetectFlowintTestParseVar03(void) sfd = DetectFlowintParse(de_ctx, "myvar,-,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_SUB) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_SUB) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; } - /** * \test DetectFlowintTestParseVal04 is a test to make sure that we set the * DetectFlowint correctly for checking if equal to a valid target value @@ -644,11 +643,12 @@ static int DetectFlowintTestParseVal04(void) sfd = DetectFlowintParse(de_ctx, "myvar,==,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_EQ) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_EQ) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -671,15 +671,14 @@ static int DetectFlowintTestParseVar04(void) sfd = DetectFlowintParse(de_ctx, "myvar,==,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_EQ) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_EQ) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -701,11 +700,12 @@ static int DetectFlowintTestParseVal05(void) sfd = DetectFlowintParse(de_ctx, "myvar,!=,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_NE) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_NE) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -728,15 +728,14 @@ static int DetectFlowintTestParseVar05(void) sfd = DetectFlowintParse(de_ctx, "myvar,!=,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_NE) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_NE) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -758,11 +757,12 @@ static int DetectFlowintTestParseVal06(void) sfd = DetectFlowintParse(de_ctx, "myvar, >,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_GT) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_GT) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -785,15 +785,14 @@ static int DetectFlowintTestParseVar06(void) sfd = DetectFlowintParse(de_ctx, "myvar, >,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_GT) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_GT) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -815,11 +814,12 @@ static int DetectFlowintTestParseVal07(void) sfd = DetectFlowintParse(de_ctx, "myvar, >= ,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_GE) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_GE) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -842,15 +842,14 @@ static int DetectFlowintTestParseVar07(void) sfd = DetectFlowintParse(de_ctx, "myvar, >= ,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_GE) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_GE) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -872,11 +871,12 @@ static int DetectFlowintTestParseVal08(void) sfd = DetectFlowintParse(de_ctx, "myvar, <= ,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_LE) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_LE) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -899,15 +899,14 @@ static int DetectFlowintTestParseVar08(void) sfd = DetectFlowintParse(de_ctx, "myvar, <= ,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_LE) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_LE) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -929,11 +928,12 @@ static int DetectFlowintTestParseVal09(void) sfd = DetectFlowintParse(de_ctx, "myvar, < ,35"); DetectFlowintPrintData(sfd); - if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") - && sfd->modifier == FLOWINT_MODIFIER_LT) { + if (sfd != NULL && sfd->target.value == 35 && !strcmp(sfd->name, "myvar") && + sfd->modifier == FLOWINT_MODIFIER_LT) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -956,15 +956,14 @@ static int DetectFlowintTestParseVar09(void) sfd = DetectFlowintParse(de_ctx, "myvar, < ,targetvar"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_VAR - && sfd->target.tvar.name != NULL - && !strcmp(sfd->target.tvar.name, "targetvar") - && sfd->modifier == FLOWINT_MODIFIER_LT) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_VAR && + sfd->target.tvar.name != NULL && !strcmp(sfd->target.tvar.name, "targetvar") && + sfd->modifier == FLOWINT_MODIFIER_LT) { result = 1; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -986,28 +985,28 @@ static int DetectFlowintTestParseIsset10(void) sfd = DetectFlowintParse(de_ctx, "myvar, isset"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_SELF - && sfd->modifier == FLOWINT_MODIFIER_ISSET) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_SELF && + sfd->modifier == FLOWINT_MODIFIER_ISSET) { result &= 1; } else { result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "myvar, notset"); DetectFlowintPrintData(sfd); - if (sfd != NULL && !strcmp(sfd->name, "myvar") - && sfd->targettype == FLOWINT_TARGET_SELF - && sfd->modifier == FLOWINT_MODIFIER_NOTSET) { + if (sfd != NULL && !strcmp(sfd->name, "myvar") && sfd->targettype == FLOWINT_TARGET_SELF && + sfd->modifier == FLOWINT_MODIFIER_NOTSET) { result &= 1; } else { result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); return result; @@ -1029,59 +1028,72 @@ static int DetectFlowintTestParseInvalidSyntaxis01(void) sfd = DetectFlowintParse(de_ctx, "myvar,=,9999999999"); if (sfd != NULL) { - SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=,9532458716234857"); + SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at " + "myvar,=,9532458716234857"); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "myvar,=,45targetvar"); if (sfd != NULL) { - SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=,45targetvar "); + SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at " + "myvar,=,45targetvar "); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "657myvar,=,targetvar"); if (sfd != NULL) { - SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at 657myvar,=,targetvar "); + SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at " + "657myvar,=,targetvar "); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "myvar,=<,targetvar"); if (sfd != NULL) { - SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=<,targetvar "); + SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at " + "myvar,=<,targetvar "); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "myvar,===,targetvar"); if (sfd != NULL) { - SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,===,targetvar "); + SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at " + "myvar,===,targetvar "); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "myvar,=="); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,=="); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "myvar,"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar,"); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); sfd = DetectFlowintParse(de_ctx, "myvar"); if (sfd != NULL) { SCLogDebug("DetectFlowintTestParseInvalidSyntaxis01: ERROR: invalid option at myvar"); result = 0; } - if (sfd) DetectFlowintFree(NULL, sfd); + if (sfd) + DetectFlowintFree(NULL, sfd); DetectEngineCtxFree(de_ctx); @@ -1116,21 +1128,27 @@ static int DetectFlowintTestPacket01Real(void) de_ctx->flags |= DE_QUIET; const char *sigs[5]; - sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint:myvar,=,1; flowint:maxvar,=,6; sid:101;)"; - sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint: myvar,+,2; sid:102;)"; - sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar,==,3; flowint: cntpackets, =, 0; sid:103;)"; - sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: myvar,==,3; flowint: cntpackets, +, 1; noalert;sid:104;)"; - sigs[4] = "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, ==, maxvar; sid:105;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; " + "flowint:myvar,=,1; flowint:maxvar,=,6; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; " + "content:\"Unauthorized\"; flowint: myvar,+,2; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new " + "counter\"; content:\"Unauthorized\"; flowint: myvar,==,3; flowint: cntpackets, =, " + "0; sid:103;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received " + "without generating alerts!!!\"; flowint: myvar,==,3; flowint: cntpackets, +, 1; " + "noalert;sid:104;)"; + sigs[4] = "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: " + "cntpackets, ==, maxvar; sid:105;)"; FAIL_IF(UTHAppendSigs(de_ctx, sigs, 5) == 0); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", - 41424, 80); + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", 41424, 80); FAIL_IF(f == NULL); f->proto = IPPROTO_TCP; @@ -1166,7 +1184,7 @@ static int DetectFlowintTestPacket01Real(void) UTHFreePacket(p); UTHFreeFlow(f); - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); PASS; @@ -1189,21 +1207,29 @@ static int DetectFlowintTestPacket02Real(void) de_ctx->flags |= DE_QUIET; const char *sigs[5]; - sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint: myvar, notset; flowint:maxvar,notset; flowint: myvar,=,1; flowint: maxvar,=,6; sid:101;)"; - sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: myvar,+,2; sid:102;)"; - sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar, isset; flowint: myvar,==,3; flowint:cntpackets,notset; flowint: cntpackets, =, 0; sid:103;)"; - sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: cntpackets,isset; flowint: cntpackets, +, 1; noalert;sid:104;)"; - sigs[4] = "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, isset; flowint: maxvar,isset; flowint: cntpackets, ==, maxvar; sid:105;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; " + "flowint: myvar, notset; flowint:maxvar,notset; flowint: myvar,=,1; flowint: " + "maxvar,=,6; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; " + "content:\"Unauthorized\"; flowint:myvar,isset; flowint: myvar,+,2; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new " + "counter\"; content:\"Unauthorized\"; flowint: myvar, isset; flowint: myvar,==,3; " + "flowint:cntpackets,notset; flowint: cntpackets, =, 0; sid:103;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received " + "without generating alerts!!!\"; flowint: cntpackets,isset; flowint: cntpackets, +, " + "1; noalert;sid:104;)"; + sigs[4] = + "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: " + "cntpackets, isset; flowint: maxvar,isset; flowint: cntpackets, ==, maxvar; sid:105;)"; FAIL_IF(UTHAppendSigs(de_ctx, sigs, 5) == 0); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", - 41424, 80); + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", 41424, 80); FAIL_IF(f == NULL); f->proto = IPPROTO_TCP; @@ -1239,7 +1265,7 @@ static int DetectFlowintTestPacket02Real(void) UTHFreePacket(p); UTHFreeFlow(f); - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); PASS; @@ -1262,19 +1288,21 @@ static int DetectFlowintTestPacket03Real(void) de_ctx->flags |= DE_QUIET; const char *sigs[3]; - sigs[0] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"GET\"; flowint: myvar, notset; flowint: myvar,=,0; flowint: other,=,10; sid:101;)"; - sigs[1] = "alert tcp any any -> any any (msg:\"check isset\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: other,isset; sid:102;)"; - sigs[2] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"Unauthorized\"; flowint:lala,isset; sid:103;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"GET\"; flowint: " + "myvar, notset; flowint: myvar,=,0; flowint: other,=,10; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"check isset\"; content:\"Unauthorized\"; " + "flowint:myvar,isset; flowint: other,isset; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"Unauthorized\"; " + "flowint:lala,isset; sid:103;)"; FAIL_IF(UTHAppendSigs(de_ctx, sigs, 3) == 0); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", - 41424, 80); + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", 41424, 80); FAIL_IF(f == NULL); f->proto = IPPROTO_TCP; @@ -1302,7 +1330,7 @@ static int DetectFlowintTestPacket03Real(void) UTHFreePacket(p); UTHFreeFlow(f); - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); PASS; @@ -1331,15 +1359,11 @@ void DetectFlowintRegisterTests(void) UtRegisterTest("DetectFlowintTestParseVar08", DetectFlowintTestParseVar08); UtRegisterTest("DetectFlowintTestParseVal09", DetectFlowintTestParseVal09); UtRegisterTest("DetectFlowintTestParseVar09", DetectFlowintTestParseVar09); - UtRegisterTest("DetectFlowintTestParseIsset10", - DetectFlowintTestParseIsset10); - UtRegisterTest("DetectFlowintTestParseInvalidSyntaxis01", - DetectFlowintTestParseInvalidSyntaxis01); - UtRegisterTest("DetectFlowintTestPacket01Real", - DetectFlowintTestPacket01Real); - UtRegisterTest("DetectFlowintTestPacket02Real", - DetectFlowintTestPacket02Real); - UtRegisterTest("DetectFlowintTestPacket03Real", - DetectFlowintTestPacket03Real); + UtRegisterTest("DetectFlowintTestParseIsset10", DetectFlowintTestParseIsset10); + UtRegisterTest( + "DetectFlowintTestParseInvalidSyntaxis01", DetectFlowintTestParseInvalidSyntaxis01); + UtRegisterTest("DetectFlowintTestPacket01Real", DetectFlowintTestPacket01Real); + UtRegisterTest("DetectFlowintTestPacket02Real", DetectFlowintTestPacket02Real); + UtRegisterTest("DetectFlowintTestPacket03Real", DetectFlowintTestPacket03Real); } #endif /* UNITTESTS */ diff --git a/src/detect-flowint.h b/src/detect-flowint.h index 6ffa1f093026..b1f683857330 100644 --- a/src/detect-flowint.h +++ b/src/detect-flowint.h @@ -60,13 +60,13 @@ typedef struct TargetVar_ { /** Context data for flowint vars */ typedef struct DetectFlowintData_ { /* This is the main var we are going to use - * against the target */ + * against the target */ char *name; /* Internal id of the var */ uint32_t idx; /* The modifier/operation/condition we are - * going to execute */ + * going to execute */ uint8_t modifier; uint8_t targettype; @@ -79,7 +79,6 @@ typedef struct DetectFlowintData_ { } DetectFlowintData; /* prototypes */ -void DetectFlowintRegister (void); +void DetectFlowintRegister(void); #endif /* __DETECT_FLOWINT_H__ */ - diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index c923be5d0b77..644c905163af 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -36,33 +36,32 @@ #include "pkt-var.h" #include "detect-flowvar.h" -#include "util-spm.h" -#include "util-var-name.h" -#include "util-debug.h" -#include "util-print.h" +#include "util/spm.h" +#include "util/var-name.h" +#include "util/debug.h" +#include "util/print.h" -#define PARSE_REGEX "(.*),(.*)" +#define PARSE_REGEX "(.*),(.*)" static DetectParseRegex parse_regex; -int DetectFlowvarMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectFlowvarSetup (DetectEngineCtx *, Signature *, const char *); -static int DetectFlowvarPostMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx); +int DetectFlowvarMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectFlowvarSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectFlowvarPostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); static void DetectFlowvarDataFree(DetectEngineCtx *, void *ptr); -void DetectFlowvarRegister (void) +void DetectFlowvarRegister(void) { sigmatch_table[DETECT_FLOWVAR].name = "flowvar"; sigmatch_table[DETECT_FLOWVAR].Match = DetectFlowvarMatch; sigmatch_table[DETECT_FLOWVAR].Setup = DetectFlowvarSetup; - sigmatch_table[DETECT_FLOWVAR].Free = DetectFlowvarDataFree; + sigmatch_table[DETECT_FLOWVAR].Free = DetectFlowvarDataFree; /* post-match for flowvar storage */ sigmatch_table[DETECT_FLOWVAR_POSTMATCH].name = "__flowvar__postmatch__"; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Match = DetectFlowvarPostMatch; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Setup = NULL; - sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Free = DetectFlowvarDataFree; + sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Free = DetectFlowvarDataFree; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } @@ -96,17 +95,16 @@ static void DetectFlowvarDataFree(DetectEngineCtx *de_ctx, void *ptr) * -1: error */ -int DetectFlowvarMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +int DetectFlowvarMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { int ret = 0; DetectFlowvarData *fd = (DetectFlowvarData *)ctx; FlowVar *fv = FlowVarGet(p->flow, fd->idx); if (fv != NULL) { - uint8_t *ptr = SpmSearch(fv->data.fv_str.value, - fv->data.fv_str.value_len, - fd->content, fd->content_len); + uint8_t *ptr = SpmSearch( + fv->data.fv_str.value, fv->data.fv_str.value_len, fd->content, fd->content_len); if (ptr != NULL) ret = 1; } @@ -114,7 +112,7 @@ int DetectFlowvarMatch (DetectEngineThreadCtx *det_ctx, Packet *p, return ret; } -static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectFlowvarSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectFlowvarData *fd = NULL; char varname[64], varcontent[64]; @@ -154,8 +152,8 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, const char if (strlen(varcontent) >= 2) { if (varcontent[0] == '"') varcontent_index++; - if (varcontent[strlen(varcontent)-1] == '"') - varcontent[strlen(varcontent)-1] = '\0'; + if (varcontent[strlen(varcontent) - 1] == '"') + varcontent[strlen(varcontent) - 1] = '\0'; } SCLogDebug("varcontent %s", &varcontent[varcontent_index]); @@ -200,8 +198,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, const char } /** \brief Store flowvar in det_ctx so we can exec it post-match */ -int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, - uint8_t *key, uint16_t key_len, +int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, uint8_t *key, uint16_t key_len, uint8_t *buffer, uint16_t len, int type) { DetectVarList *fs = SCCalloc(1, sizeof(*fs)); @@ -220,14 +217,13 @@ int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, } /** \brief Store flowvar in det_ctx so we can exec it post-match */ -int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, - uint32_t idx, - uint8_t *buffer, uint16_t len, int type) +int DetectVarStoreMatch( + DetectEngineThreadCtx *det_ctx, uint32_t idx, uint8_t *buffer, uint16_t len, int type) { DetectVarList *fs = det_ctx->varlist; /* first check if we have had a previous match for this idx */ - for ( ; fs != NULL; fs = fs->next) { + for (; fs != NULL; fs = fs->next) { if (fs->idx == idx) { /* we're replacing the older store */ SCFree(fs->buffer); @@ -285,8 +281,7 @@ int DetectFlowvarPostMatchSetup(DetectEngineCtx *de_ctx, Signature *s, uint32_t * \retval 1 or -1 in case of error */ static int DetectFlowvarPostMatch( - DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { DetectVarList *fs, *prev; const DetectFlowvarData *fd; @@ -301,7 +296,7 @@ static int DetectFlowvarPostMatch( while (fs != NULL) { if (fd->idx == 0 || fd->idx == fs->idx) { SCLogDebug("adding to the flow %u:", fs->idx); - //PrintRawDataFp(stdout, fs->buffer, fs->len); + // PrintRawDataFp(stdout, fs->buffer, fs->len); if (fs->type == DETECT_VAR_TYPE_FLOW_POSTMATCH && p && p->flow) { FlowVarAddIdValue(p->flow, fs->idx, fs->buffer, fs->len); @@ -309,9 +304,8 @@ static int DetectFlowvarPostMatch( * the flowvar code. */ } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && fs->key && p) { /* pkt key/value */ - if (PktVarAddKeyValue(p, (uint8_t *)fs->key, fs->key_len, - (uint8_t *)fs->buffer, fs->len) == -1) - { + if (PktVarAddKeyValue(p, (uint8_t *)fs->key, fs->key_len, (uint8_t *)fs->buffer, + fs->len) == -1) { SCFree(fs->key); SCFree(fs->buffer); /* the rest of fs is freed below */ diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index b2988a63517a..0b745651c99d 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -35,13 +35,12 @@ typedef struct DetectFlowvarData_ { } DetectFlowvarData; /* prototypes */ -void DetectFlowvarRegister (void); +void DetectFlowvarRegister(void); int DetectFlowvarPostMatchSetup(DetectEngineCtx *de_ctx, Signature *s, uint32_t idx); -int DetectVarStoreMatch(DetectEngineThreadCtx *, - uint32_t, uint8_t *, uint16_t, int); -int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *, - uint8_t *, uint16_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatch(DetectEngineThreadCtx *, uint32_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatchKeyValue( + DetectEngineThreadCtx *, uint8_t *, uint16_t, uint8_t *, uint16_t, int); /* For use only by DetectFlowvarProcessList() */ void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p); diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index e8e8b78057bb..8850efe1750f 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -39,12 +39,12 @@ #include "app-layer-detect-proto.h" #include "detect-fragbits.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/debug.h" #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" +#include "util/profiling.h" /** * Regex @@ -61,15 +61,15 @@ #define MODIFIER_PLUS 2 #define MODIFIER_ANY 3 -#define FRAGBITS_HAVE_MF 0x01 -#define FRAGBITS_HAVE_DF 0x02 -#define FRAGBITS_HAVE_RF 0x04 +#define FRAGBITS_HAVE_MF 0x01 +#define FRAGBITS_HAVE_DF 0x02 +#define FRAGBITS_HAVE_RF 0x04 static DetectParseRegex parse_regex; -static int DetectFragBitsMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectFragBitsSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectFragBitsMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectFragBitsSetup(DetectEngineCtx *, Signature *, const char *); static void DetectFragBitsFree(DetectEngineCtx *, void *); static int PrefilterSetupFragBits(DetectEngineCtx *de_ctx, SigGroupHead *sgh); @@ -82,14 +82,15 @@ static void FragBitsRegisterTests(void); * \brief Registration function for fragbits: keyword */ -void DetectFragBitsRegister (void) +void DetectFragBitsRegister(void) { sigmatch_table[DETECT_FRAGBITS].name = "fragbits"; - sigmatch_table[DETECT_FRAGBITS].desc = "check if the fragmentation and reserved bits are set in the IP header"; + sigmatch_table[DETECT_FRAGBITS].desc = + "check if the fragmentation and reserved bits are set in the IP header"; sigmatch_table[DETECT_FRAGBITS].url = "/rules/header-keywords.html#fragbits-ip-fragmentation"; sigmatch_table[DETECT_FRAGBITS].Match = DetectFragBitsMatch; sigmatch_table[DETECT_FRAGBITS].Setup = DetectFragBitsSetup; - sigmatch_table[DETECT_FRAGBITS].Free = DetectFragBitsFree; + sigmatch_table[DETECT_FRAGBITS].Free = DetectFragBitsFree; #ifdef UNITTESTS sigmatch_table[DETECT_FRAGBITS].RegisterTests = FragBitsRegisterTests; #endif @@ -99,9 +100,7 @@ void DetectFragBitsRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static inline int -FragBitsMatch(const uint8_t pbits, const uint8_t modifier, - const uint8_t dbits) +static inline int FragBitsMatch(const uint8_t pbits, const uint8_t modifier, const uint8_t dbits) { switch (modifier) { case MODIFIER_ANY: @@ -139,19 +138,19 @@ FragBitsMatch(const uint8_t pbits, const uint8_t modifier, * \retval 0 no match * \retval 1 match */ -static int DetectFragBitsMatch (DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectFragBitsMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { if (!ctx || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) return 0; uint8_t fragbits = 0; const DetectFragBitsData *de = (const DetectFragBitsData *)ctx; - if(IPV4_GET_MF(p)) + if (IPV4_GET_MF(p)) fragbits |= FRAGBITS_HAVE_MF; - if(IPV4_GET_DF(p)) + if (IPV4_GET_DF(p)) fragbits |= FRAGBITS_HAVE_DF; - if(IPV4_GET_RF(p)) + if (IPV4_GET_RF(p)) fragbits |= FRAGBITS_HAVE_RF; return FragBitsMatch(fragbits, de->modifier, de->fragbits); @@ -166,13 +165,13 @@ static int DetectFragBitsMatch (DetectEngineThreadCtx *det_ctx, * \retval de pointer to DetectFragBitsData on success * \retval NULL on failure */ -static DetectFragBitsData *DetectFragBitsParse (const char *rawstr) +static DetectFragBitsData *DetectFragBitsParse(const char *rawstr) { DetectFragBitsData *de = NULL; int found = 0, res = 0; size_t pcre2_len; const char *str_ptr = NULL; - char *args[2] = { NULL, NULL}; + char *args[2] = { NULL, NULL }; char *ptr; int i; pcre2_match_data *match = NULL; @@ -247,7 +246,7 @@ static DetectFragBitsData *DetectFragBitsParse (const char *rawstr) ptr++; } - if(found == 0) + if (found == 0) goto error; for (i = 0; i < 2; i++) { @@ -282,7 +281,7 @@ static DetectFragBitsData *DetectFragBitsParse (const char *rawstr) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFragBitsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectFragBitsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectFragBitsData *de = NULL; @@ -313,11 +312,12 @@ static int DetectFragBitsSetup (DetectEngineCtx *de_ctx, Signature *s, const cha static void DetectFragBitsFree(DetectEngineCtx *de_ctx, void *de_ptr) { DetectFragBitsData *de = (DetectFragBitsData *)de_ptr; - if(de) SCFree(de); + if (de) + SCFree(de); } -static void -PrefilterPacketFragBitsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketFragBitsMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; @@ -332,27 +332,22 @@ PrefilterPacketFragBitsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const vo if (IPV4_GET_RF(p)) fragbits |= FRAGBITS_HAVE_RF; - if (FragBitsMatch(fragbits, ctx->v1.u8[0], ctx->v1.u8[1])) - { + if (FragBitsMatch(fragbits, ctx->v1.u8[0], ctx->v1.u8[1])) { PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketFragBitsSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketFragBitsSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectFragBitsData *fb = smctx; v->u8[0] = fb->modifier; v->u8[1] = fb->fragbits; } -static bool -PrefilterPacketFragBitsCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketFragBitsCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectFragBitsData *fb = smctx; - if (v.u8[0] == fb->modifier && - v.u8[1] == fb->fragbits) - { + if (v.u8[0] == fb->modifier && v.u8[1] == fb->fragbits) { return true; } return false; @@ -360,16 +355,14 @@ PrefilterPacketFragBitsCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupFragBits(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FRAGBITS, - PrefilterPacketFragBitsSet, - PrefilterPacketFragBitsCompare, - PrefilterPacketFragBitsMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FRAGBITS, PrefilterPacketFragBitsSet, + PrefilterPacketFragBitsCompare, PrefilterPacketFragBitsMatch); } static bool PrefilterFragBitsIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FRAGBITS: return true; @@ -383,7 +376,7 @@ static bool PrefilterFragBitsIsPrefilterable(const Signature *s) */ #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "packet.h" /** @@ -392,11 +385,11 @@ static bool PrefilterFragBitsIsPrefilterable(const Signature *s) * \retval 1 on success * \retval 0 on failure */ -static int FragBitsTestParse01 (void) +static int FragBitsTestParse01(void) { DetectFragBitsData *de = NULL; de = DetectFragBitsParse("M"); - if (de && (de->fragbits == FRAGBITS_HAVE_MF) ) { + if (de && (de->fragbits == FRAGBITS_HAVE_MF)) { DetectFragBitsFree(NULL, de); return 1; } @@ -410,7 +403,7 @@ static int FragBitsTestParse01 (void) * \retval 1 on success * \retval 0 on failure */ -static int FragBitsTestParse02 (void) +static int FragBitsTestParse02(void) { DetectFragBitsData *de = NULL; de = DetectFragBitsParse("G"); @@ -428,8 +421,9 @@ static int FragBitsTestParse02 (void) * \retval 1 on success * \retval 0 on failure */ -static int FragBitsTestParse03 (void) +static int FragBitsTestParse03(void) { + // clang-format off uint8_t raw_eth[] = { 0x00 ,0x40 ,0x33 ,0xd9 ,0x7c ,0xfd ,0x00 ,0x00, 0x39 ,0xcf ,0xd9 ,0xcd ,0x08 ,0x00 ,0x45 ,0x00, @@ -468,6 +462,7 @@ static int FragBitsTestParse03 (void) 0x0b ,0xc0 ,0x9f ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x0b, 0x51}; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); ThreadVars tv; @@ -514,8 +509,9 @@ static int FragBitsTestParse03 (void) * \retval 1 on success * \retval 0 on failure */ -static int FragBitsTestParse04 (void) +static int FragBitsTestParse04(void) { + // clang-format off uint8_t raw_eth[] = { 0x00 ,0x40 ,0x33 ,0xd9 ,0x7c ,0xfd ,0x00 ,0x00, 0x39 ,0xcf ,0xd9 ,0xcd ,0x08 ,0x00 ,0x45 ,0x00, @@ -554,6 +550,7 @@ static int FragBitsTestParse04 (void) 0x0b ,0xc0 ,0x9f ,0x00 ,0x01 ,0x00 ,0x01 ,0x00, 0x00 ,0x0e ,0x10 ,0x00 ,0x04 ,0x81 ,0x6f ,0x0b, 0x51}; + // clang-format on Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); ThreadVars tv; @@ -574,7 +571,6 @@ static int FragBitsTestParse04 (void) DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth)); - de = DetectFragBitsParse("!D"); FAIL_IF(de == NULL); diff --git a/src/detect-fragbits.h b/src/detect-fragbits.h index 1ab6cae310e3..72333790cca9 100644 --- a/src/detect-fragbits.h +++ b/src/detect-fragbits.h @@ -24,7 +24,6 @@ #ifndef __DETECT_FRAGBITS_H__ #define __DETECT_FRAGBITS_H__ - /** * \struct DetectFragBitsData_ * DetectFragBitsData_ is used to store fragbits: input value @@ -44,6 +43,6 @@ typedef struct DetectFragBitsData_ { * Registration function for fragbits: keyword */ -void DetectFragBitsRegister (void); +void DetectFragBitsRegister(void); #endif /*__DETECT_FRAGBITS_H__ */ diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index b4b21ff58ede..674d1f9db435 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -35,16 +35,16 @@ #include "detect-fragoffset.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/debug.h" #define PARSE_REGEX "^\\s*(?:(<|>))?\\s*([0-9]+)" static DetectParseRegex parse_regex; -static int DetectFragOffsetMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectFragOffsetMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectFragOffsetSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS void DetectFragOffsetRegisterTests(void); @@ -57,10 +57,11 @@ static bool PrefilterFragOffsetIsPrefilterable(const Signature *s); /** * \brief Registration function for fragoffset */ -void DetectFragOffsetRegister (void) +void DetectFragOffsetRegister(void) { sigmatch_table[DETECT_FRAGOFFSET].name = "fragoffset"; - sigmatch_table[DETECT_FRAGOFFSET].desc = "match on specific decimal values of the IP fragment offset field"; + sigmatch_table[DETECT_FRAGOFFSET].desc = + "match on specific decimal values of the IP fragment offset field"; sigmatch_table[DETECT_FRAGOFFSET].url = "/rules/header-keywords.html#fragoffset"; sigmatch_table[DETECT_FRAGOFFSET].Match = DetectFragOffsetMatch; sigmatch_table[DETECT_FRAGOFFSET].Setup = DetectFragOffsetSetup; @@ -74,10 +75,10 @@ void DetectFragOffsetRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static inline int FragOffsetMatch(const uint16_t poffset, const uint8_t mode, - const uint16_t doffset) +static inline int FragOffsetMatch( + const uint16_t poffset, const uint8_t mode, const uint16_t doffset) { - switch (mode) { + switch (mode) { case FRAG_LESS: if (poffset < doffset) return 1; @@ -105,8 +106,8 @@ static inline int FragOffsetMatch(const uint16_t poffset, const uint8_t mode, * \retval 1 match * */ -static int DetectFragOffsetMatch (DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectFragOffsetMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { uint16_t frag = 0; const DetectFragOffsetData *fragoff = (const DetectFragOffsetData *)ctx; @@ -139,10 +140,11 @@ static int DetectFragOffsetMatch (DetectEngineThreadCtx *det_ctx, * \retval fragoff pointer to DetectFragOffsetData on success * \retval NULL on failure */ -static DetectFragOffsetData *DetectFragOffsetParse (DetectEngineCtx *de_ctx, const char *fragoffsetstr) +static DetectFragOffsetData *DetectFragOffsetParse( + DetectEngineCtx *de_ctx, const char *fragoffsetstr) { DetectFragOffsetData *fragoff = NULL; - char *substr[3] = {NULL, NULL, NULL}; + char *substr[3] = { NULL, NULL, NULL }; int res = 0; size_t pcre2_len; int i; @@ -162,7 +164,7 @@ static DetectFragOffsetData *DetectFragOffsetParse (DetectEngineCtx *de_ctx, con SCLogError("pcre2_substring_get_bynumber failed"); goto error; } - substr[i-1] = (char *)str_ptr; + substr[i - 1] = (char *)str_ptr; } fragoff = SCMalloc(sizeof(DetectFragOffsetData)); @@ -174,10 +176,10 @@ static DetectFragOffsetData *DetectFragOffsetParse (DetectEngineCtx *de_ctx, con mode = substr[0]; - if(mode != NULL) { + if (mode != NULL) { - while(*mode != '\0') { - switch(*mode) { + while (*mode != '\0') { + switch (*mode) { case '>': fragoff->mode = FRAG_MORE; break; @@ -212,9 +214,9 @@ static DetectFragOffsetData *DetectFragOffsetParse (DetectEngineCtx *de_ctx, con if (substr[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)substr[i]); } - if (fragoff != NULL) DetectFragOffsetFree(de_ctx, fragoff); + if (fragoff != NULL) + DetectFragOffsetFree(de_ctx, fragoff); return NULL; - } /** @@ -227,12 +229,13 @@ static DetectFragOffsetData *DetectFragOffsetParse (DetectEngineCtx *de_ctx, con * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFragOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *fragoffsetstr) +static int DetectFragOffsetSetup(DetectEngineCtx *de_ctx, Signature *s, const char *fragoffsetstr) { DetectFragOffsetData *fragoff = NULL; fragoff = DetectFragOffsetParse(de_ctx, fragoffsetstr); - if (fragoff == NULL) goto error; + if (fragoff == NULL) + goto error; if (SigMatchAppendSMToList(de_ctx, s, DETECT_FRAGOFFSET, (SigMatchCtx *)fragoff, DETECT_SM_LIST_MATCH) == NULL) { @@ -246,7 +249,6 @@ static int DetectFragOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, const c if (fragoff != NULL) DetectFragOffsetFree(de_ctx, fragoff); return -1; - } /** @@ -254,14 +256,14 @@ static int DetectFragOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, const c * * \param ptr pointer to DetectFragOffsetData */ -void DetectFragOffsetFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectFragOffsetFree(DetectEngineCtx *de_ctx, void *ptr) { DetectFragOffsetData *fragoff = (DetectFragOffsetData *)ptr; SCFree(fragoff); } -static void -PrefilterPacketFragOffsetMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketFragOffsetMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { if (PKT_IS_PSEUDOPKT(p)) return; @@ -282,27 +284,22 @@ PrefilterPacketFragOffsetMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const } const PrefilterPacketHeaderCtx *ctx = pectx; - if (FragOffsetMatch(frag, ctx->v1.u8[0], ctx->v1.u16[1])) - { + if (FragOffsetMatch(frag, ctx->v1.u8[0], ctx->v1.u16[1])) { PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketFragOffsetSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketFragOffsetSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectFragOffsetData *fb = smctx; v->u8[0] = fb->mode; v->u16[1] = fb->frag_off; } -static bool -PrefilterPacketFragOffsetCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketFragOffsetCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectFragOffsetData *fb = smctx; - if (v.u8[0] == fb->mode && - v.u16[1] == fb->frag_off) - { + if (v.u8[0] == fb->mode && v.u16[1] == fb->frag_off) { return true; } return false; @@ -310,16 +307,14 @@ PrefilterPacketFragOffsetCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupFragOffset(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FRAGOFFSET, - PrefilterPacketFragOffsetSet, - PrefilterPacketFragOffsetCompare, - PrefilterPacketFragOffsetMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FRAGOFFSET, PrefilterPacketFragOffsetSet, + PrefilterPacketFragOffsetCompare, PrefilterPacketFragOffsetMatch); } static bool PrefilterFragOffsetIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FRAGOFFSET: return true; @@ -329,14 +324,14 @@ static bool PrefilterFragOffsetIsPrefilterable(const Signature *s) } #ifdef UNITTESTS -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "detect-engine.h" #include "detect-engine-alert.h" /** * \test DetectFragOffsetParseTest01 is a test for setting a valid fragoffset value */ -static int DetectFragOffsetParseTest01 (void) +static int DetectFragOffsetParseTest01(void) { DetectFragOffsetData *fragoff = DetectFragOffsetParse(NULL, "300"); @@ -352,7 +347,7 @@ static int DetectFragOffsetParseTest01 (void) * \test DetectFragOffsetParseTest02 is a test for setting a valid fragoffset value * with spaces all around */ -static int DetectFragOffsetParseTest02 (void) +static int DetectFragOffsetParseTest02(void) { DetectFragOffsetData *fragoff = DetectFragOffsetParse(NULL, ">300"); @@ -368,7 +363,7 @@ static int DetectFragOffsetParseTest02 (void) /** * \test DetectFragOffsetParseTest03 is a test for setting an invalid fragoffset value */ -static int DetectFragOffsetParseTest03 (void) +static int DetectFragOffsetParseTest03(void) { DetectFragOffsetData *fragoff = DetectFragOffsetParse(NULL, "badc"); @@ -382,7 +377,7 @@ static int DetectFragOffsetParseTest03 (void) * fragoffset keyword by creating 2 rules and matching a crafted packet * against them. Only the first one shall trigger. */ -static int DetectFragOffsetMatchTest01 (void) +static int DetectFragOffsetMatchTest01(void) { Packet *p = PacketGetFromAlloc(); @@ -437,7 +432,7 @@ static int DetectFragOffsetMatchTest01 (void) PASS; } -void DetectFragOffsetRegisterTests (void) +void DetectFragOffsetRegisterTests(void) { UtRegisterTest("DetectFragOffsetParseTest01", DetectFragOffsetParseTest01); UtRegisterTest("DetectFragOffsetParseTest02", DetectFragOffsetParseTest02); diff --git a/src/detect-frame.c b/src/detect-frame.c index d2f7461f7579..0839b046d273 100644 --- a/src/detect-frame.c +++ b/src/detect-frame.c @@ -42,10 +42,10 @@ #include "conf.h" #include "conf-yaml-loader.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-spm.h" -#include "util-print.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/spm.h" +#include "util/print.h" static int DetectFrameSetup(DetectEngineCtx *, Signature *, const char *); diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c deleted file mode 100644 index 79b0f1b579e2..000000000000 --- a/src/detect-ftpbounce.c +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - * - * ftpbounce keyword, part of the detection engine. - */ - -#include "suricata-common.h" -#include "decode.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-content.h" -#include "detect-engine-build.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ftp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" -#include "threads.h" -#include "detect-ftpbounce.h" -#include "stream-tcp.h" -#include "util-byte.h" - -static int DetectFtpbounceALMatch(DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); - -static int DetectFtpbounceSetup(DetectEngineCtx *, Signature *, const char *); -static int g_ftp_request_list_id = 0; - -/** - * \brief Registration function for ftpbounce: keyword - * \todo add support for no_stream and stream_only - */ -void DetectFtpbounceRegister(void) -{ - sigmatch_table[DETECT_FTPBOUNCE].name = "ftpbounce"; - sigmatch_table[DETECT_FTPBOUNCE].desc = "detect FTP bounce attacks"; - sigmatch_table[DETECT_FTPBOUNCE].Setup = DetectFtpbounceSetup; - sigmatch_table[DETECT_FTPBOUNCE].AppLayerTxMatch = DetectFtpbounceALMatch; - sigmatch_table[DETECT_FTPBOUNCE].url = "/rules/ftp-keywords.html#ftpbounce"; - sigmatch_table[DETECT_FTPBOUNCE].flags = SIGMATCH_NOOPT; - - g_ftp_request_list_id = DetectBufferTypeRegister("ftp_request"); - - DetectAppLayerInspectEngineRegister2( - "ftp_request", ALPROTO_FTP, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); -} - -/** - * \brief This function is used to match ftpbounce attacks - * - * \param payload Payload of the PORT command - * \param payload_len Length of the payload - * \param ip_orig IP source to check the ftpbounce condition - * \param offset offset to the arguments of the PORT command - * - * \retval 1 if ftpbounce detected, 0 if not - */ -static int DetectFtpbounceMatchArgs( - uint8_t *payload, uint32_t payload_len, uint32_t ip_orig, uint32_t offset) -{ - SCEnter(); - SCLogDebug("Checking ftpbounce condition"); - char *c = NULL; - uint32_t i = 0; - int octet = 0; - int octet_ascii_len = 0; - int noctet = 0; - uint32_t ip = 0; - /* PrintRawDataFp(stdout, payload, payload_len); */ - - if (payload_len < 7) { - /* we need at least a different ip address - * in the format 1,2,3,4,x,y where x,y is the port - * in two byte representation so let's look at - * least for the IP octets in comma separated */ - return 0; - } - - if (offset + 7 >= payload_len) - return 0; - - c =(char*) payload; - if (c == NULL) { - SCLogDebug("No payload to check"); - return 0; - } - - i = offset; - /* Search for the first IP octect(Skips "PORT ") */ - while (i < payload_len && !isdigit((unsigned char)c[i])) i++; - - for (;i < payload_len && octet_ascii_len < 4 ;i++) { - if (isdigit((unsigned char)c[i])) { - octet =(c[i] - '0') + octet * 10; - octet_ascii_len++; - } else { - if (octet > 256) { - SCLogDebug("Octet not in ip format"); - return 0; - } - - if (isspace((unsigned char)c[i])) - while (i < payload_len && isspace((unsigned char)c[i]) ) i++; - - if (i < payload_len && c[i] == ',') { /* we have an octet */ - noctet++; - octet_ascii_len = 0; - ip =(ip << 8) + octet; - octet = 0; - } else { - SCLogDebug("Unrecognized character '%c'", c[i]); - return 0; - } - if (noctet == 4) { - /* Different IP than src, ftp bounce scan */ - ip = SCNtohl(ip); - - if (ip != ip_orig) { - SCLogDebug("Different ip, so Matched ip:%d <-> ip_orig:%d", - ip, ip_orig); - return 1; - } - SCLogDebug("Same ip, so no match here"); - return 0; - } - } - } - SCLogDebug("No match"); - return 0; -} - -/** - * \brief This function is used to check matches from the FTP App Layer Parser - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch but we don't use it since ftpbounce - * has no options - * \retval 0 no match - * \retval 1 match - */ -static int DetectFtpbounceALMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, - void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - SCEnter(); - - FtpState *ftp_state = (FtpState *)state; - if (ftp_state == NULL) { - SCLogDebug("no ftp state, no match"); - SCReturnInt(0); - } - - int ret = 0; - if (ftp_state->command == FTP_COMMAND_PORT) { - ret = DetectFtpbounceMatchArgs(ftp_state->port_line, - ftp_state->port_line_len, f->src.address.address_un_data32[0], - ftp_state->arg_offset); - } - - SCReturnInt(ret); -} - -/** - * \brief this function is used to add the parsed ftpbounce - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param m pointer to the Current SigMatch - * \param ftpbouncestr pointer to the user provided ftpbounce options - * currently there are no options. - * - * \retval 0 on Success - * \retval -1 on Failure - */ -int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *ftpbouncestr) -{ - SCEnter(); - - if (DetectSignatureSetAppProto(s, ALPROTO_FTP) != 0) - return -1; - - /* We don't need to allocate any data for ftpbounce here. - * - * TODO: As a suggestion, maybe we can add a flag in the flow - * to set the stream as "bounce detected" for fast Match. - * When you do a ftp bounce attack you usually use the same - * communication control stream to "setup" various destinations - * without breaking the connection, so I guess we can make it a bit faster - * with a flow flag set lookup in the Match function. - */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_FTPBOUNCE, NULL, g_ftp_request_list_id) == NULL) { - return -1; - } - SCReturnInt(0); -} diff --git a/src/detect-ftpbounce.h b/src/detect-ftpbounce.h deleted file mode 100644 index f9cdfe390c11..000000000000 --- a/src/detect-ftpbounce.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - */ - -#ifndef __DETECT_FTPBOUNCE_H__ -#define __DETECT_FTPBOUNCE_H__ - -/* prototypes */ -void DetectFtpbounceRegister (void); - -#endif /* __DETECT_FTPBOUNCE_H__ */ - diff --git a/src/detect-ftpdata.c b/src/detect-ftpdata.c deleted file mode 100644 index ce9e5c3c211c..000000000000 --- a/src/detect-ftpdata.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (C) 2017-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * - * Match on ftp command used to trigger a ftp data transfer - */ - -#include "suricata-common.h" -#include "util-unittest.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-state.h" - -#include "app-layer-ftp.h" - -#include "detect-ftpdata.h" - -/** - * \brief Regex for parsing our keyword options - */ -#define PARSE_REGEX "^\\s*(stor|retr)\\s*$" -static DetectParseRegex parse_regex; - -/* Prototypes of functions registered in DetectFtpdataRegister below */ -static int DetectFtpdataMatch(DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectFtpdataSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectFtpdataFree (DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectFtpdataRegisterTests (void); -#endif -static int g_ftpdata_buffer_id = 0; - -/** - * \brief Registration function for ftpcommand: keyword - * - * This function is called once in the 'lifetime' of the engine. - */ -void DetectFtpdataRegister(void) { - /* keyword name: this is how the keyword is used in a rule */ - sigmatch_table[DETECT_FTPDATA].name = "ftpdata_command"; - /* description: listed in "suricata --list-keywords=all" */ - sigmatch_table[DETECT_FTPDATA].desc = "match FTP command triggering a FTP data channel"; - sigmatch_table[DETECT_FTPDATA].url = "/rules/ftp-keywords.html#ftpdata-command"; - sigmatch_table[DETECT_FTPDATA].AppLayerTxMatch = DetectFtpdataMatch; - /* setup function is called during signature parsing, when the ftpcommand - * keyword is encountered in the rule */ - sigmatch_table[DETECT_FTPDATA].Setup = DetectFtpdataSetup; - /* free function is called when the detect engine is freed. Normally at - * shutdown, but also during rule reloads. */ - sigmatch_table[DETECT_FTPDATA].Free = DetectFtpdataFree; - /* registers unittests into the system */ -#ifdef UNITTESTS - sigmatch_table[DETECT_FTPDATA].RegisterTests = DetectFtpdataRegisterTests; -#endif - DetectAppLayerInspectEngineRegister2("ftpdata_command", ALPROTO_FTPDATA, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("ftpdata_command", ALPROTO_FTPDATA, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - g_ftpdata_buffer_id = DetectBufferTypeGetByName("ftpdata_command"); - - /* set up the PCRE for keyword parsing */ - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); -} - -/** - * \brief This function is used to check matches from the FTP App Layer Parser - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch - * \retval 0 no match - * \retval 1 match - */ -static int DetectFtpdataMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, - void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - const DetectFtpdataData *ftpcommandd = (const DetectFtpdataData *) m; - const FtpDataState *ftp_state = (const FtpDataState *)state; - - if (ftp_state == NULL) - return 0; - - if (ftpcommandd->command == ftp_state->command) { - /* Only match if the flow is in the good direction */ - if ((flags & STREAM_TOSERVER) && (ftpcommandd->command == FTP_COMMAND_RETR)) { - return 0; - } else if ((flags & STREAM_TOCLIENT) && (ftpcommandd->command == FTP_COMMAND_STOR)) { - return 0; - } - return 1; - } - - return 0; -} - -/** - * \brief This function is used to parse ftpcommand options passed via ftpcommand: keyword - * - * \param ftpcommandstr Pointer to the user provided ftpcommand options - * - * \retval ftpcommandd pointer to DetectFtpdataData on success - * \retval NULL on failure - */ -static DetectFtpdataData *DetectFtpdataParse(const char *ftpcommandstr) -{ - DetectFtpdataData *ftpcommandd = NULL; - char arg1[5] = ""; - size_t pcre2len; - pcre2_match_data *match = NULL; - - int ret = DetectParsePcreExec(&parse_regex, &match, ftpcommandstr, 0, 0); - if (ret != 2) { - SCLogError("parse error, ret %" PRId32 "", ret); - goto error; - } - - pcre2len = sizeof(arg1); - int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("Arg1 \"%s\"", arg1); - - ftpcommandd = SCMalloc(sizeof (DetectFtpdataData)); - if (unlikely(ftpcommandd == NULL)) - goto error; - if (!strcmp(arg1, "stor")) { - ftpcommandd->command = FTP_COMMAND_STOR; - } else if (!strcmp(arg1, "retr")) { - ftpcommandd->command = FTP_COMMAND_RETR; - } else { - SCLogError("Invalid command value"); - goto error; - } - - pcre2_match_data_free(match); - return ftpcommandd; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (ftpcommandd) - SCFree(ftpcommandd); - return NULL; -} - -/** - * \brief parse the options from the 'ftpcommand' keyword in the rule into - * the Signature data structure. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param str pointer to the user provided ftpcommand options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectFtpdataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_FTPDATA) != 0) - return -1; - - DetectFtpdataData *ftpcommandd = DetectFtpdataParse(str); - if (ftpcommandd == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_FTPDATA, (SigMatchCtx *)ftpcommandd, - g_ftpdata_buffer_id) == NULL) { - DetectFtpdataFree(de_ctx, ftpcommandd); - return -1; - } - return 0; -} - -/** - * \brief this function will free memory associated with DetectFtpdataData - * - * \param ptr pointer to DetectFtpdataData - */ -static void DetectFtpdataFree(DetectEngineCtx *de_ctx, void *ptr) { - DetectFtpdataData *ftpcommandd = (DetectFtpdataData *)ptr; - - /* do more specific cleanup here, if needed */ - - SCFree(ftpcommandd); -} - -#ifdef UNITTESTS - -static int DetectFtpdataParseTest01(void) -{ - DetectFtpdataData *ftpcommandd = DetectFtpdataParse("stor"); - FAIL_IF_NULL(ftpcommandd); - FAIL_IF(!(ftpcommandd->command == FTP_COMMAND_STOR)); - DetectFtpdataFree(NULL, ftpcommandd); - PASS; -} - -static int DetectFtpdataSignatureTest01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (ftpdata_command:stor; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (ftpdata_command:retr; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (ftpdata_command:xxx; sid:3; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \brief this function registers unit tests for DetectFtpdata - */ -static void DetectFtpdataRegisterTests(void) -{ - UtRegisterTest("DetectFtpdataParseTest01", DetectFtpdataParseTest01); - UtRegisterTest("DetectFtpdataSignatureTest01", - DetectFtpdataSignatureTest01); -} -#endif /* UNITTESTS */ diff --git a/src/detect-ftpdata.h b/src/detect-ftpdata.h deleted file mode 100644 index 9345c68e8205..000000000000 --- a/src/detect-ftpdata.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - */ - -#ifndef __DETECT_FTPDATA_H__ -#define __DETECT_FTPDATA_H__ - -#include "app-layer-ftp.h" - -/** Per keyword data. This is set up by the DetectFtpcommandSetup() function. - * Each signature will have an instance of DetectFtpcommandData per occurrence - * of the keyword. - * The structure should be considered static/readonly after initialization. - */ -typedef struct DetectFtpdataData_ { - FtpRequestCommand command; -} DetectFtpdataData; - -/** \brief registers the keyword into the engine. Called from - * detect.c::SigTableSetup() */ -void DetectFtpdataRegister(void); - -#endif /* __DETECT_FTPDATA_H__ */ diff --git a/src/detect-geoip.c b/src/detect-geoip.c index 9198b9e45129..d6b3df5dd5b0 100644 --- a/src/detect-geoip.c +++ b/src/detect-geoip.c @@ -35,13 +35,13 @@ #include "detect-geoip.h" -#include "util-mem.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/mem.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #ifndef HAVE_GEOIP -static int DetectGeoipSetupNoSupport (DetectEngineCtx *a, Signature *b, const char *c) +static int DetectGeoipSetupNoSupport(DetectEngineCtx *a, Signature *b, const char *c) { SCLogError("no GeoIP support built in, needed for geoip keyword"); return -1; @@ -54,7 +54,9 @@ static int DetectGeoipSetupNoSupport (DetectEngineCtx *a, Signature *b, const ch void DetectGeoipRegister(void) { sigmatch_table[DETECT_GEOIP].name = "geoip"; - sigmatch_table[DETECT_GEOIP].desc = "match on the source, destination or source and destination IP addresses of network traffic, and to see to which country it belongs"; + sigmatch_table[DETECT_GEOIP].desc = + "match on the source, destination or source and destination IP addresses of network " + "traffic, and to see to which country it belongs"; sigmatch_table[DETECT_GEOIP].url = "/rules/header-keywords.html#geoip"; sigmatch_table[DETECT_GEOIP].Setup = DetectGeoipSetupNoSupport; sigmatch_table[DETECT_GEOIP].Free = NULL; @@ -64,8 +66,8 @@ void DetectGeoipRegister(void) #include -static int DetectGeoipMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectGeoipMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectGeoipSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectGeoipRegisterTests(void); @@ -149,24 +151,22 @@ static const char *GeolocateIPv4(const DetectGeoipData *geoipdata, uint32_t ip) return NULL; /* Attempt to find the IPv4 address in the database */ - result = MMDB_lookup_sockaddr((MMDB_s *)&geoipdata->mmdb, - (struct sockaddr*)&sa, &mmdb_error); + result = MMDB_lookup_sockaddr((MMDB_s *)&geoipdata->mmdb, (struct sockaddr *)&sa, &mmdb_error); if (mmdb_error != MMDB_SUCCESS) return NULL; /* The IPv4 address was found, so grab ISO country code if available */ if (result.found_entry) { - mmdb_error = MMDB_get_value(&result.entry, &entry_data, "country", - "iso_code", NULL); + mmdb_error = MMDB_get_value(&result.entry, &entry_data, "country", "iso_code", NULL); if (mmdb_error != MMDB_SUCCESS) return NULL; /* If ISO country code was found, then return it */ if (entry_data.has_data) { if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) { - char *country_code = SCStrndup((char *)entry_data.utf8_string, - entry_data.data_size); - return country_code; + char *country_code = + SCStrndup((char *)entry_data.utf8_string, entry_data.data_size); + return country_code; } } } @@ -176,17 +176,17 @@ static const char *GeolocateIPv4(const DetectGeoipData *geoipdata, uint32_t ip) } /* Match-on conditions supported */ -#define GEOIP_MATCH_SRC_STR "src" -#define GEOIP_MATCH_DST_STR "dst" -#define GEOIP_MATCH_BOTH_STR "both" -#define GEOIP_MATCH_ANY_STR "any" - -#define GEOIP_MATCH_NO_FLAG 0 -#define GEOIP_MATCH_SRC_FLAG 1 -#define GEOIP_MATCH_DST_FLAG 2 -#define GEOIP_MATCH_ANY_FLAG 3 /* default src and dst*/ -#define GEOIP_MATCH_BOTH_FLAG 4 -#define GEOIP_MATCH_NEGATED 8 +#define GEOIP_MATCH_SRC_STR "src" +#define GEOIP_MATCH_DST_STR "dst" +#define GEOIP_MATCH_BOTH_STR "both" +#define GEOIP_MATCH_ANY_STR "any" + +#define GEOIP_MATCH_NO_FLAG 0 +#define GEOIP_MATCH_SRC_FLAG 1 +#define GEOIP_MATCH_DST_FLAG 2 +#define GEOIP_MATCH_ANY_FLAG 3 /* default src and dst*/ +#define GEOIP_MATCH_BOTH_FLAG 4 +#define GEOIP_MATCH_NEGATED 8 /** * \internal @@ -209,10 +209,9 @@ static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) return 0; /* Check if NOT NEGATED match-on condition */ - if ((geoipdata->flags & GEOIP_MATCH_NEGATED) == 0) - { + if ((geoipdata->flags & GEOIP_MATCH_NEGATED) == 0) { for (i = 0; i < geoipdata->nlocations; i++) { - if (strcmp(country, (char *)geoipdata->location[i])==0) { + if (strcmp(country, (char *)geoipdata->location[i]) == 0) { SCFree((void *)country); return 1; } @@ -220,7 +219,7 @@ static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) } else { /* Check if NEGATED match-on condition */ for (i = 0; i < geoipdata->nlocations; i++) { - if (strcmp(country, (char *)geoipdata->location[i])==0) { + if (strcmp(country, (char *)geoipdata->location[i]) == 0) { SCFree((void *)country); return 0; /* if one matches, rule does NOT match (negated) */ } @@ -244,8 +243,8 @@ static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) * \retval 0 no match * \retval 1 match */ -static int DetectGeoipMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectGeoipMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectGeoipData *geoipdata = (const DetectGeoipData *)ctx; int matches = 0; @@ -253,22 +252,17 @@ static int DetectGeoipMatch(DetectEngineThreadCtx *det_ctx, if (PKT_IS_PSEUDOPKT(p)) return 0; - if (PKT_IS_IPV4(p)) - { - if (geoipdata->flags & ( GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG )) - { - if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_SRC_ADDR_U32(p))) - { + if (PKT_IS_IPV4(p)) { + if (geoipdata->flags & (GEOIP_MATCH_SRC_FLAG | GEOIP_MATCH_BOTH_FLAG)) { + if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_SRC_ADDR_U32(p))) { if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG) matches++; else return 1; } } - if (geoipdata->flags & ( GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG )) - { - if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_DST_ADDR_U32(p))) - { + if (geoipdata->flags & (GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_BOTH_FLAG)) { + if (CheckGeoMatchIPv4(geoipdata, GET_IPV4_DST_ADDR_U32(p))) { if (geoipdata->flags & GEOIP_MATCH_BOTH_FLAG) matches++; else @@ -292,7 +286,7 @@ static int DetectGeoipMatch(DetectEngineThreadCtx *det_ctx, * \retval pointer to DetectGeoipData on success * \retval NULL on failure */ -static DetectGeoipData *DetectGeoipDataParse (DetectEngineCtx *de_ctx, const char *str) +static DetectGeoipData *DetectGeoipDataParse(DetectEngineCtx *de_ctx, const char *str) { DetectGeoipData *geoipdata = NULL; uint16_t pos = 0; @@ -310,13 +304,10 @@ static DetectGeoipData *DetectGeoipDataParse (DetectEngineCtx *de_ctx, const cha goto error; /* Parse the geoip option string */ - while (pos <= slen) - { + while (pos <= slen) { /* search for ',' or end of string */ - if (str[pos] == ',' || pos == slen) - { - if (geoipdata->flags == GEOIP_MATCH_NO_FLAG) - { + if (str[pos] == ',' || pos == slen) { + if (geoipdata->flags == GEOIP_MATCH_NO_FLAG) { /* Parse match-on condition */ if (pos == slen) /* if end of option str then there are no match-on cond. */ { @@ -325,13 +316,13 @@ static DetectGeoipData *DetectGeoipDataParse (DetectEngineCtx *de_ctx, const cha geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; } else { skiplocationparsing = 1; - if (strncmp(&str[prevpos], GEOIP_MATCH_SRC_STR, pos-prevpos) == 0) + if (strncmp(&str[prevpos], GEOIP_MATCH_SRC_STR, pos - prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_SRC_FLAG; - else if (strncmp(&str[prevpos], GEOIP_MATCH_DST_STR, pos-prevpos) == 0) + else if (strncmp(&str[prevpos], GEOIP_MATCH_DST_STR, pos - prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_DST_FLAG; - else if (strncmp(&str[prevpos], GEOIP_MATCH_BOTH_STR, pos-prevpos) == 0) + else if (strncmp(&str[prevpos], GEOIP_MATCH_BOTH_STR, pos - prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_BOTH_FLAG; - else if (strncmp(&str[prevpos], GEOIP_MATCH_ANY_STR, pos-prevpos) == 0) + else if (strncmp(&str[prevpos], GEOIP_MATCH_ANY_STR, pos - prevpos) == 0) geoipdata->flags |= GEOIP_MATCH_ANY_FLAG; else { /* There was NO match-on condition! we default to ANY*/ @@ -340,8 +331,7 @@ static DetectGeoipData *DetectGeoipDataParse (DetectEngineCtx *de_ctx, const cha } } } - if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0) - { + if (geoipdata->flags != GEOIP_MATCH_NO_FLAG && skiplocationparsing == 0) { /* Parse location string: for now just the country code(s) */ if (str[prevpos] == '!') { geoipdata->flags |= GEOIP_MATCH_NEGATED; @@ -353,24 +343,24 @@ static DetectGeoipData *DetectGeoipDataParse (DetectEngineCtx *de_ctx, const cha goto error; } - if (pos-prevpos > GEOOPTION_MAXSIZE) + if (pos - prevpos > GEOOPTION_MAXSIZE) strlcpy((char *)geoipdata->location[geoipdata->nlocations], &str[prevpos], - GEOOPTION_MAXSIZE); + GEOOPTION_MAXSIZE); else strlcpy((char *)geoipdata->location[geoipdata->nlocations], &str[prevpos], - pos-prevpos+1); + pos - prevpos + 1); if (geoipdata->nlocations < GEOOPTION_MAXLOCATIONS) geoipdata->nlocations++; } - prevpos = pos+1; + prevpos = pos + 1; skiplocationparsing = 0; /* match-on condition for sure has been parsed already */ } pos++; } - SCLogDebug("GeoIP: %"PRIu32" countries loaded", geoipdata->nlocations); - for (int i=0; inlocations; i++) + SCLogDebug("GeoIP: %" PRIu32 " countries loaded", geoipdata->nlocations); + for (int i = 0; i < geoipdata->nlocations; i++) SCLogDebug("GeoIP country code: %s", geoipdata->location[i]); SCLogDebug("flags %02X", geoipdata->flags); @@ -426,7 +416,6 @@ static int DetectGeoipSetup(DetectEngineCtx *de_ctx, Signature *s, const char *o if (geoipdata != NULL) DetectGeoipDataFree(de_ctx, geoipdata); return -1; - } /** @@ -467,11 +456,10 @@ static int GeoipParseTest(const char *rule, int ncountries, const char **countri data = (DetectGeoipData *)s->init_data->smlists_tail[DETECT_SM_LIST_MATCH]->ctx; FAIL_IF(data->flags != flags); - FAIL_IF(data->nlocations!=ncountries); + FAIL_IF(data->nlocations != ncountries); - for (int i=0; ilocation[i],countries[i])!=0); + for (int i = 0; i < ncountries; i++) { + FAIL_IF(strcmp((char *)data->location[i], countries[i]) != 0); } DetectEngineCtxFree(de_ctx); @@ -480,51 +468,51 @@ static int GeoipParseTest(const char *rule, int ncountries, const char **countri static int GeoipParseTest01(void) { - const char *ccodes[1] = {"US"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes, - GEOIP_MATCH_ANY_FLAG); + const char *ccodes[1] = { "US" }; + return GeoipParseTest( + "alert tcp any any -> any any (geoip:US;sid:1;)", 1, ccodes, GEOIP_MATCH_ANY_FLAG); } static int GeoipParseTest02(void) { - const char *ccodes[1] = {"US"}; + const char *ccodes[1] = { "US" }; return GeoipParseTest("alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes, - GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); + GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); } static int GeoipParseTest03(void) { - const char *ccodes[1] = {"US"}; + const char *ccodes[1] = { "US" }; return GeoipParseTest("alert tcp any any -> any any (geoip:!US;sid:1;)", 1, ccodes, - GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); + GEOIP_MATCH_ANY_FLAG | GEOIP_MATCH_NEGATED); } static int GeoipParseTest04(void) { - const char *ccodes[1] = {"US"}; - return GeoipParseTest("alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes, - GEOIP_MATCH_SRC_FLAG); + const char *ccodes[1] = { "US" }; + return GeoipParseTest( + "alert tcp any any -> any any (geoip:src,US;sid:1;)", 1, ccodes, GEOIP_MATCH_SRC_FLAG); } static int GeoipParseTest05(void) { - const char *ccodes[1] = {"US"}; + const char *ccodes[1] = { "US" }; return GeoipParseTest("alert tcp any any -> any any (geoip:dst,!US;sid:1;)", 1, ccodes, - GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED); + GEOIP_MATCH_DST_FLAG | GEOIP_MATCH_NEGATED); } static int GeoipParseTest06(void) { - const char *ccodes[3] = {"US", "ES", "UK"}; + const char *ccodes[3] = { "US", "ES", "UK" }; return GeoipParseTest("alert tcp any any -> any any (geoip:US,ES,UK;sid:1;)", 3, ccodes, - GEOIP_MATCH_ANY_FLAG); + GEOIP_MATCH_ANY_FLAG); } static int GeoipParseTest07(void) { - const char *ccodes[3] = {"US", "ES", "UK"}; + const char *ccodes[3] = { "US", "ES", "UK" }; return GeoipParseTest("alert tcp any any -> any any (geoip:both,!US,ES,UK;sid:1;)", 3, ccodes, - GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED); + GEOIP_MATCH_BOTH_FLAG | GEOIP_MATCH_NEGATED); } /** diff --git a/src/detect-geoip.h b/src/detect-geoip.h index 4ec97b5df868..911c89f5d2b7 100644 --- a/src/detect-geoip.h +++ b/src/detect-geoip.h @@ -29,12 +29,13 @@ #include -#define GEOOPTION_MAXSIZE 3 /* Country Code (2 chars) + NULL */ +#define GEOOPTION_MAXSIZE 3 /* Country Code (2 chars) + NULL */ #define GEOOPTION_MAXLOCATIONS 64 typedef struct DetectGeoipData_ { - uint8_t location[GEOOPTION_MAXLOCATIONS][GEOOPTION_MAXSIZE]; /** country code for now, null term.*/ - int nlocations; /** number of location strings parsed */ + uint8_t location[GEOOPTION_MAXLOCATIONS] + [GEOOPTION_MAXSIZE]; /** country code for now, null term.*/ + int nlocations; /** number of location strings parsed */ uint32_t flags; int mmdb_status; /** Status of DB open call, MMDB_SUCCESS or error */ MMDB_s mmdb; /** MaxMind DB file handle structure */ diff --git a/src/detect-gid.c b/src/detect-gid.c index a278edbc2666..69d4ce61965c 100644 --- a/src/detect-gid.c +++ b/src/detect-gid.c @@ -33,10 +33,10 @@ #include "decode-events.h" #include "detect-gid.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/debug.h" -static int DetectGidSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectGidSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void GidRegisterTests(void); #endif @@ -45,14 +45,14 @@ static void GidRegisterTests(void); * \brief Registration function for gid: keyword */ -void DetectGidRegister (void) +void DetectGidRegister(void) { sigmatch_table[DETECT_GID].name = "gid"; sigmatch_table[DETECT_GID].desc = "give different groups of signatures another id value"; sigmatch_table[DETECT_GID].url = "/rules/meta.html#gid-group-id"; sigmatch_table[DETECT_GID].Match = NULL; sigmatch_table[DETECT_GID].Setup = DetectGidSetup; - sigmatch_table[DETECT_GID].Free = NULL; + sigmatch_table[DETECT_GID].Free = NULL; #ifdef UNITTESTS sigmatch_table[DETECT_GID].RegisterTests = GidRegisterTests; #endif @@ -69,7 +69,7 @@ void DetectGidRegister (void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectGidSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { unsigned long gid = 0; char *endptr = NULL; @@ -88,7 +88,7 @@ static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ra return 0; - error: +error: return -1; } @@ -100,7 +100,7 @@ static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ra /** * \test GidTestParse01 is a test for a valid gid value */ -static int GidTestParse01 (void) +static int GidTestParse01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); @@ -118,7 +118,7 @@ static int GidTestParse01 (void) /** * \test GidTestParse02 is a test for an invalid gid value */ -static int GidTestParse02 (void) +static int GidTestParse02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); @@ -133,7 +133,7 @@ static int GidTestParse02 (void) /** * \test Test a gid consisting of a single quote. */ -static int GidTestParse03 (void) +static int GidTestParse03(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); diff --git a/src/detect-gid.h b/src/detect-gid.h index fa714ef8f5cf..f952d8cbc78f 100644 --- a/src/detect-gid.h +++ b/src/detect-gid.h @@ -26,11 +26,10 @@ #ifndef __DETECT_GID_H__ #define __DETECT_GID_H__ - /** * Registration function for gid: keyword */ -void DetectGidRegister (void); +void DetectGidRegister(void); #endif /*__DETECT_GID_H__ */ \ No newline at end of file diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c index 571510325aea..c1ac9abdfb55 100644 --- a/src/detect-hostbits.c +++ b/src/detect-hostbits.c @@ -30,7 +30,7 @@ #include "flow.h" #include "flow-util.h" #include "detect-hostbits.h" -#include "util-spm.h" +#include "util/spm.h" #include "detect-engine-sigorder.h" @@ -44,9 +44,9 @@ #include "flow-bit.h" #include "host-bit.h" -#include "util-var-name.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/var-name.h" +#include "util/unittest.h" +#include "util/debug.h" /* hostbits:isset,bitname; @@ -69,22 +69,22 @@ "(.+)?" /* Any remaining data. */ static DetectParseRegex parse_regex; -static int DetectHostbitMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectHostbitSetup (DetectEngineCtx *, Signature *, const char *); -void DetectHostbitFree (DetectEngineCtx *, void *); +static int DetectHostbitMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectHostbitSetup(DetectEngineCtx *, Signature *, const char *); +void DetectHostbitFree(DetectEngineCtx *, void *); #ifdef UNITTESTS void HostBitsRegisterTests(void); #endif -void DetectHostbitsRegister (void) +void DetectHostbitsRegister(void) { sigmatch_table[DETECT_HOSTBITS].name = "hostbits"; sigmatch_table[DETECT_HOSTBITS].desc = "operate on host flag"; -// sigmatch_table[DETECT_HOSTBITS].url = "/rules/flow-keywords.html#flowbits"; + // sigmatch_table[DETECT_HOSTBITS].url = "/rules/flow-keywords.html#flowbits"; sigmatch_table[DETECT_HOSTBITS].Match = DetectHostbitMatch; sigmatch_table[DETECT_HOSTBITS].Setup = DetectHostbitSetup; - sigmatch_table[DETECT_HOSTBITS].Free = DetectHostbitFree; + sigmatch_table[DETECT_HOSTBITS].Free = DetectHostbitFree; #ifdef UNITTESTS sigmatch_table[DETECT_HOSTBITS].RegisterTests = HostBitsRegisterTests; #endif @@ -94,7 +94,7 @@ void DetectHostbitsRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) +static int DetectHostbitMatchToggle(Packet *p, const DetectXbitsData *fd) { switch (fd->tracker) { case DETECT_XBITS_TRACK_IPSRC: @@ -102,8 +102,7 @@ static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) p->host_src = HostGetHostFromHash(&p->src); if (p->host_src == NULL) return 0; - } - else + } else HostLock(p->host_src); HostBitToggle(p->host_src, fd->idx, SCTIME_SECS(p->ts) + fd->expire); @@ -114,8 +113,7 @@ static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) p->host_dst = HostGetHostFromHash(&p->dst); if (p->host_dst == NULL) return 0; - } - else + } else HostLock(p->host_dst); HostBitToggle(p->host_dst, fd->idx, SCTIME_SECS(p->ts) + fd->expire); @@ -126,7 +124,7 @@ static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) } /* return true even if bit not found */ -static int DetectHostbitMatchUnset (Packet *p, const DetectXbitsData *fd) +static int DetectHostbitMatchUnset(Packet *p, const DetectXbitsData *fd) { switch (fd->tracker) { case DETECT_XBITS_TRACK_IPSRC: @@ -137,7 +135,7 @@ static int DetectHostbitMatchUnset (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_src); - HostBitUnset(p->host_src,fd->idx); + HostBitUnset(p->host_src, fd->idx); HostUnlock(p->host_src); break; case DETECT_XBITS_TRACK_IPDST: @@ -148,14 +146,14 @@ static int DetectHostbitMatchUnset (Packet *p, const DetectXbitsData *fd) } else HostLock(p->host_dst); - HostBitUnset(p->host_dst,fd->idx); + HostBitUnset(p->host_dst, fd->idx); HostUnlock(p->host_dst); break; } return 1; } -static int DetectHostbitMatchSet (Packet *p, const DetectXbitsData *fd) +static int DetectHostbitMatchSet(Packet *p, const DetectXbitsData *fd) { switch (fd->tracker) { case DETECT_XBITS_TRACK_IPSRC: @@ -184,7 +182,7 @@ static int DetectHostbitMatchSet (Packet *p, const DetectXbitsData *fd) return 1; } -static int DetectHostbitMatchIsset (Packet *p, const DetectXbitsData *fd) +static int DetectHostbitMatchIsset(Packet *p, const DetectXbitsData *fd) { int r = 0; switch (fd->tracker) { @@ -214,7 +212,7 @@ static int DetectHostbitMatchIsset (Packet *p, const DetectXbitsData *fd) return 0; } -static int DetectHostbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) +static int DetectHostbitMatchIsnotset(Packet *p, const DetectXbitsData *fd) { int r = 0; switch (fd->tracker) { @@ -248,15 +246,15 @@ int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd) { switch (xd->cmd) { case DETECT_XBITS_CMD_ISSET: - return DetectHostbitMatchIsset(p,xd); + return DetectHostbitMatchIsset(p, xd); case DETECT_XBITS_CMD_ISNOTSET: - return DetectHostbitMatchIsnotset(p,xd); + return DetectHostbitMatchIsnotset(p, xd); case DETECT_XBITS_CMD_SET: - return DetectHostbitMatchSet(p,xd); + return DetectHostbitMatchSet(p, xd); case DETECT_XBITS_CMD_UNSET: - return DetectHostbitMatchUnset(p,xd); + return DetectHostbitMatchUnset(p, xd); case DETECT_XBITS_CMD_TOGGLE: - return DetectHostbitMatchToggle(p,xd); + return DetectHostbitMatchToggle(p, xd); default: SCLogError("unknown cmd %" PRIu32 "", xd->cmd); return 0; @@ -271,8 +269,8 @@ int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd) * -1: error */ -static int DetectHostbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectHostbitMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectXbitsData *xd = (const DetectXbitsData *)ctx; if (xd == NULL) @@ -281,8 +279,8 @@ static int DetectHostbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, return DetectXbitMatchHost(p, xd); } -static int DetectHostbitParse(const char *str, char *cmd, int cmd_len, - char *name, int name_len, char *dir, int dir_len) +static int DetectHostbitParse( + const char *str, char *cmd, int cmd_len, char *name, int name_len, char *dir, int dir_len) { int rc; size_t pcre2len; @@ -328,7 +326,7 @@ static int DetectHostbitParse(const char *str, char *cmd, int cmd_len, return 0; } -int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +int DetectHostbitSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectXbitsData *cd = NULL; uint8_t fb_cmd = 0; @@ -336,8 +334,8 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst char fb_cmd_str[16] = "", fb_name[256] = ""; char hb_dir_str[16] = ""; - if (!DetectHostbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), - fb_name, sizeof(fb_name), hb_dir_str, sizeof(hb_dir_str))) { + if (!DetectHostbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name, sizeof(fb_name), + hb_dir_str, sizeof(hb_dir_str))) { return -1; } @@ -347,7 +345,7 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst else if (strcmp(hb_dir_str, "dst") == 0) hb_dir = DETECT_XBITS_TRACK_IPDST; else if (strcmp(hb_dir_str, "both") == 0) { - //hb_dir = DETECT_XBITS_TRACK_IPBOTH; + // hb_dir = DETECT_XBITS_TRACK_IPBOTH; SCLogError("'both' not implemented"); goto error; } else { @@ -356,17 +354,17 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst } } - if (strcmp(fb_cmd_str,"noalert") == 0) { + if (strcmp(fb_cmd_str, "noalert") == 0) { fb_cmd = DETECT_XBITS_CMD_NOALERT; - } else if (strcmp(fb_cmd_str,"isset") == 0) { + } else if (strcmp(fb_cmd_str, "isset") == 0) { fb_cmd = DETECT_XBITS_CMD_ISSET; - } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + } else if (strcmp(fb_cmd_str, "isnotset") == 0) { fb_cmd = DETECT_XBITS_CMD_ISNOTSET; - } else if (strcmp(fb_cmd_str,"set") == 0) { + } else if (strcmp(fb_cmd_str, "set") == 0) { fb_cmd = DETECT_XBITS_CMD_SET; - } else if (strcmp(fb_cmd_str,"unset") == 0) { + } else if (strcmp(fb_cmd_str, "unset") == 0) { fb_cmd = DETECT_XBITS_CMD_UNSET; - } else if (strcmp(fb_cmd_str,"toggle") == 0) { + } else if (strcmp(fb_cmd_str, "toggle") == 0) { fb_cmd = DETECT_XBITS_CMD_TOGGLE; } else { SCLogError("ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); @@ -400,14 +398,14 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst cd->type = VAR_TYPE_HOST_BIT; cd->expire = 300; - SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", - cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, + strlen(fb_name) ? fb_name : "(none)"); /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ switch (fb_cmd) { - /* case DETECT_XBITS_CMD_NOALERT can't happen here */ + /* case DETECT_XBITS_CMD_NOALERT can't happen here */ case DETECT_XBITS_CMD_ISNOTSET: case DETECT_XBITS_CMD_ISSET: @@ -442,7 +440,7 @@ int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst return -1; } -void DetectHostbitFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectHostbitFree(DetectEngineCtx *de_ctx, void *ptr) { DetectXbitsData *fd = (DetectXbitsData *)ptr; @@ -474,8 +472,8 @@ static int HostBitsTestParse01(void) char cmd[16] = "", name[256] = "", dir[16] = ""; /* No direction. */ - FAIL_IF(!DetectHostbitParse("isset,name", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(!DetectHostbitParse( + "isset,name", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); FAIL_IF(strcmp(cmd, "isset") != 0); FAIL_IF(strcmp(name, "name") != 0); FAIL_IF(strlen(dir)); @@ -484,8 +482,8 @@ static int HostBitsTestParse01(void) *cmd = '\0'; *name = '\0'; *dir = '\0'; - FAIL_IF(!DetectHostbitParse("isset, name", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(!DetectHostbitParse( + "isset, name", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); FAIL_IF(strcmp(cmd, "isset") != 0); FAIL_IF(strcmp(name, "name") != 0); @@ -493,8 +491,8 @@ static int HostBitsTestParse01(void) *cmd = '\0'; *name = '\0'; *dir = '\0'; - FAIL_IF(!DetectHostbitParse("isset,name ", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(!DetectHostbitParse( + "isset,name ", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); FAIL_IF(strcmp(cmd, "isset") != 0); FAIL_IF(strcmp(name, "name") != 0); @@ -502,8 +500,8 @@ static int HostBitsTestParse01(void) *cmd = '\0'; *name = '\0'; *dir = '\0'; - FAIL_IF(!DetectHostbitParse("isset, name ", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(!DetectHostbitParse( + "isset, name ", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); FAIL_IF(strcmp(cmd, "isset") != 0); FAIL_IF(strcmp(name, "name") != 0); @@ -511,8 +509,8 @@ static int HostBitsTestParse01(void) *cmd = '\0'; *name = '\0'; *dir = '\0'; - FAIL_IF(!DetectHostbitParse("isset,name,src", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(!DetectHostbitParse( + "isset,name,src", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); FAIL_IF(strcmp(cmd, "isset") != 0); FAIL_IF(strcmp(name, "name") != 0); FAIL_IF(strcmp(dir, "src") != 0); @@ -521,8 +519,8 @@ static int HostBitsTestParse01(void) *cmd = '\0'; *name = '\0'; *dir = '\0'; - FAIL_IF(!DetectHostbitParse("isset, name ,src", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(!DetectHostbitParse( + "isset, name ,src", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); FAIL_IF(strcmp(cmd, "isset") != 0); FAIL_IF(strcmp(name, "name") != 0); FAIL_IF(strcmp(dir, "src") != 0); @@ -531,8 +529,8 @@ static int HostBitsTestParse01(void) *cmd = '\0'; *name = '\0'; *dir = '\0'; - FAIL_IF(!DetectHostbitParse("isset, name , src ", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(!DetectHostbitParse( + "isset, name , src ", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); FAIL_IF(strcmp(cmd, "isset") != 0); FAIL_IF(strcmp(name, "name") != 0); FAIL_IF(strcmp(dir, "src") != 0); @@ -541,8 +539,8 @@ static int HostBitsTestParse01(void) *cmd = '\0'; *name = '\0'; *dir = '\0'; - FAIL_IF(DetectHostbitParse("isset, name withspace ", cmd, sizeof(cmd), name, - sizeof(name), dir, sizeof(dir))); + FAIL_IF(DetectHostbitParse( + "isset, name withspace ", cmd, sizeof(cmd), name, sizeof(name), dir, sizeof(dir))); PASS; } @@ -556,10 +554,9 @@ static int HostBitsTestParse01(void) static int HostBitsTestSig01(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -582,7 +579,8 @@ static int HostBitsTestSig01(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (hostbits:set,abc; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = SigInit( + de_ctx, "alert ip any any -> any any (hostbits:set,abc; content:\"GET \"; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -629,11 +627,11 @@ static int HostBitsTestSig02(void) "alert ip any any -> any any (hostbits:!isset,abc,dst; content:\"GET \"; sid:3;)"); FAIL_IF_NOT_NULL(s); -/* TODO reenable after both is supported - s = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (hostbits:set,abc,both; content:\"GET \"; sid:3;)"); - FAIL_IF_NULL(s); -*/ + /* TODO reenable after both is supported + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:set,abc,both; content:\"GET \"; sid:3;)"); + FAIL_IF_NULL(s); + */ s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (hostbits:unset,abc,src; content:\"GET \"; sid:4;)"); FAIL_IF_NULL(s); @@ -655,10 +653,9 @@ static int HostBitsTestSig02(void) static int HostBitsTestSig03(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -683,7 +680,8 @@ static int HostBitsTestSig03(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"isset option\"; " + "hostbits:isset,fbt; content:\"GET \"; sid:1;)"); FAIL_IF_NULL(s); idx = VarNameStoreRegister("fbt", VAR_TYPE_HOST_BIT); diff --git a/src/detect-hostbits.h b/src/detect-hostbits.h index 6e9c7f5f0e42..f6df2143b27f 100644 --- a/src/detect-hostbits.h +++ b/src/detect-hostbits.h @@ -29,6 +29,6 @@ int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd); /* prototypes */ -void DetectHostbitsRegister (void); +void DetectHostbitsRegister(void); #endif /* __DETECT_HOSTBITS_H__ */ diff --git a/src/detect-http-accept-enc.c b/src/detect-http-accept-enc.c deleted file mode 100644 index 277e7142a278..000000000000 --- a/src/detect-http-accept-enc.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements http_accept_enc sticky buffer - */ - -#define KEYWORD_NAME_LEGACY "http_accept_enc" -#define KEYWORD_NAME "http.accept_enc" -#define KEYWORD_DOC "http-keywords.html#http-accept-enc" -#define BUFFER_NAME "http_accept_enc" -#define BUFFER_DESC "http accept encoding header" -#define HEADER_NAME "Accept-Encoding" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_ACCEPT_ENC -#define KEYWORD_TOSERVER 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-accept-enc.h" - -void RegisterHttpHeadersAcceptEnc(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-accept-lang.c b/src/detect-http-accept-lang.c deleted file mode 100644 index c83847e69a9e..000000000000 --- a/src/detect-http-accept-lang.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements http_accept_lang sticky buffer - */ - -#define KEYWORD_NAME_LEGACY "http_accept_lang" -#define KEYWORD_NAME "http.accept_lang" -#define KEYWORD_DOC "http-keywords.html#http-accept-lang" -#define BUFFER_NAME "http_accept_lang" -#define BUFFER_DESC "http accept language header" -#define HEADER_NAME "Accept-Language" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_ACCEPT_LANG -#define KEYWORD_TOSERVER 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-accept-lang.h" - -void RegisterHttpHeadersAcceptLang(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-accept.c b/src/detect-http-accept.c deleted file mode 100644 index db6bec4455ca..000000000000 --- a/src/detect-http-accept.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support http_header_* - */ - -#define KEYWORD_NAME_LEGACY "http_accept" -#define KEYWORD_NAME "http.accept" -#define KEYWORD_DOC "http-keywords.html#http-accept" -#define BUFFER_NAME "http_accept" -#define BUFFER_DESC "http accept header" -#define HEADER_NAME "Accept" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_ACCEPT -#define KEYWORD_TOSERVER 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-accept.h" - -void RegisterHttpHeadersAccept(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c deleted file mode 100644 index 1d3d7a87cc88..000000000000 --- a/src/detect-http-client-body.c +++ /dev/null @@ -1,402 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Anoop Saldanha - * - * Implements support for the http_client_body keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" -// PrefilterMpmFiledata -#include "detect-file-data.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-htp.h" -#include "detect-http-client-body.h" -#include "stream-tcp.h" -#include "util-profiling.h" - -static int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, const char *); -static int DetectHttpClientBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); -#ifdef UNITTESTS -static void DetectHttpClientBodyRegisterTests(void); -#endif -static void DetectHttpClientBodySetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); -static int g_http_client_body_buffer_id = 0; - -static uint8_t DetectEngineInspectBufferHttpBody(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); - -static int PrefilterMpmHttpRequestBodyRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); - -/** - * \brief Registers the keyword handlers for the "http_client_body" keyword. - */ -void DetectHttpClientBodyRegister(void) -{ - /* http_client_body content modifier */ - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].name = "http_client_body"; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].desc = "content modifier to match only on HTTP request-body"; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = "/rules/http-keywords.html#http-client-body"; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].alternative = DETECT_HTTP_REQUEST_BODY; - - /* http.request_body sticky buffer */ - sigmatch_table[DETECT_HTTP_REQUEST_BODY].name = "http.request_body"; - sigmatch_table[DETECT_HTTP_REQUEST_BODY].desc = "sticky buffer to match the HTTP request body buffer"; - sigmatch_table[DETECT_HTTP_REQUEST_BODY].url = "/rules/http-keywords.html#http-client-body"; - sigmatch_table[DETECT_HTTP_REQUEST_BODY].Setup = DetectHttpClientBodySetupSticky; - sigmatch_table[DETECT_HTTP_REQUEST_BODY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_HTTP_REQUEST_BODY].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_client_body", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_BODY, DetectEngineInspectBufferHttpBody, NULL); - - DetectAppLayerMpmRegister2("http_client_body", SIG_FLAG_TOSERVER, 2, - PrefilterMpmHttpRequestBodyRegister, NULL, ALPROTO_HTTP1, HTP_REQUEST_BODY); - - DetectAppLayerInspectEngineRegister2("http_client_body", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectFiledata, NULL); - DetectAppLayerMpmRegister2("http_client_body", SIG_FLAG_TOSERVER, 2, - PrefilterMpmFiledataRegister, NULL, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeSetDescriptionByName("http_client_body", - "http request body"); - - DetectBufferTypeRegisterSetupCallback("http_client_body", - DetectHttpClientBodySetupCallback); - - g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body"); -} - -static void DetectHttpClientBodySetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - SCLogDebug("callback invoked by %u", s->id); - AppLayerHtpEnableRequestBodyCallback(); - - /* client body needs to be inspected in sync with stream if possible */ - s->init_data->init_flags |= SIG_FLAG_INIT_NEED_FLUSH; -} - -/** - * \brief The setup function for the http_client_body keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to signature for the current Signature being parsed - * from the rules. - * \param m Pointer to the head of the SigMatchs for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success - * \retval -1 On failure - */ -int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_CLIENT_BODY, - g_http_client_body_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.request_body keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpClientBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_client_body_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static inline HtpBody *GetRequestBody(htp_tx_t *tx) -{ - HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (htud == NULL) { - SCLogDebug("no htud"); - return NULL; - } - - return &htud->request_body; -} - -typedef struct PrefilterMpmHttpRequestBody { - int list_id; - int base_list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmHttpRequestBody; - -static void PrefilterMpmHttpRequestBodyFree(void *ptr) -{ - SCFree(ptr); -} - -static inline InspectionBuffer *HttpRequestBodyXformsGetDataCallback(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, const int list_id, InspectionBuffer *base_buffer) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect != NULL) - return buffer; - - InspectionBufferSetup(det_ctx, list_id, buffer, base_buffer->inspect, base_buffer->inspect_len); - buffer->inspect_offset = base_buffer->inspect_offset; - InspectionBufferApplyTransforms(buffer, transforms); - SCLogDebug("xformed buffer %p size %u", buffer, buffer->inspect_len); - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static InspectionBuffer *HttpRequestBodyGetDataCallback(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id, const int base_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, base_id); - if (base_id != list_id && buffer->inspect != NULL) - return HttpRequestBodyXformsGetDataCallback(det_ctx, transforms, list_id, buffer); - else if (buffer->inspect != NULL) - return buffer; - - htp_tx_t *tx = txv; - HtpState *htp_state = f->alstate; - const uint8_t flags = flow_flags; - - HtpBody *body = GetRequestBody(tx); - if (body == NULL) { - return NULL; - } - - /* no new data */ - if (body->body_inspected == body->content_len_so_far) { - SCLogDebug("no new data"); - return NULL; - } - - HtpBodyChunk *cur = body->first; - if (cur == NULL) { - SCLogDebug("No http chunks to inspect for this transaction"); - return NULL; - } - - SCLogDebug("request.body_limit %u request_body.content_len_so_far %" PRIu64 - ", request.inspect_min_size %" PRIu32 ", EOF %s, progress > body? %s", - htp_state->cfg->request.body_limit, body->content_len_so_far, - htp_state->cfg->request.inspect_min_size, flags & STREAM_EOF ? "true" : "false", - (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) > - HTP_REQUEST_BODY) - ? "true" - : "false"); - - if (!htp_state->cfg->http_body_inline) { - /* inspect the body if the transfer is complete or we have hit - * our body size limit */ - if ((htp_state->cfg->request.body_limit == 0 || - body->content_len_so_far < htp_state->cfg->request.body_limit) && - body->content_len_so_far < htp_state->cfg->request.inspect_min_size && - !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) > - HTP_REQUEST_BODY) && - !(flags & STREAM_EOF)) { - SCLogDebug("we still haven't seen the entire request body. " - "Let's defer body inspection till we see the " - "entire body."); - return NULL; - } - } - - /* get the inspect buffer - * - * make sure that we have at least the configured inspect_win size. - * If we have more, take at least 1/4 of the inspect win size before - * the new data. - */ - uint64_t offset = 0; - if (body->body_inspected > htp_state->cfg->request.inspect_min_size) { - BUG_ON(body->content_len_so_far < body->body_inspected); - uint64_t inspect_win = body->content_len_so_far - body->body_inspected; - SCLogDebug("inspect_win %"PRIu64, inspect_win); - if (inspect_win < htp_state->cfg->request.inspect_window) { - uint64_t inspect_short = htp_state->cfg->request.inspect_window - inspect_win; - if (body->body_inspected < inspect_short) - offset = 0; - else - offset = body->body_inspected - inspect_short; - } else { - offset = body->body_inspected - (htp_state->cfg->request.inspect_window / 4); - } - } - - const uint8_t *data; - uint32_t data_len; - - StreamingBufferGetDataAtOffset(body->sb, - &data, &data_len, offset); - InspectionBufferSetup(det_ctx, base_id, buffer, data, data_len); - buffer->inspect_offset = offset; - body->body_inspected = body->content_len_so_far; - SCLogDebug("body->body_inspected now: %" PRIu64, body->body_inspected); - - if (base_id != list_id) { - buffer = HttpRequestBodyXformsGetDataCallback(det_ctx, transforms, list_id, buffer); - } - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectBufferHttpBody(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - bool eof = - (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress); - const InspectionBuffer *buffer = HttpRequestBodyGetDataCallback( - det_ctx, engine->v2.transforms, f, flags, txv, engine->sm_list, engine->sm_list_base); - if (buffer == NULL || buffer->inspect == NULL) { - return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH; - } - - const uint32_t data_len = buffer->inspect_len; - const uint8_t *data = buffer->inspect; - const uint64_t offset = buffer->inspect_offset; - - uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0; - ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0); - ci_flags |= buffer->flags; - - /* Inspect all the uricontents fetched on each - * transaction at the app layer */ - const bool match = - DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, (uint8_t *)data, - data_len, offset, ci_flags, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > - HTP_REQUEST_BODY) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > - HTP_RESPONSE_BODY) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -/** \brief HTTP Request body callback - * - * \param det_ctx detection engine thread ctx - * \param pectx inspection context - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param idx transaction id - * \param flags STREAM_* flags including direction - */ -static void PrefilterTxHttpRequestBody(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmHttpRequestBody *ctx = (const PrefilterMpmHttpRequestBody *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - InspectionBuffer *buffer = HttpRequestBodyGetDataCallback( - det_ctx, ctx->transforms, f, flags, txv, list_id, ctx->base_list_id); - if (buffer == NULL) - return; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } -} - -static int PrefilterMpmHttpRequestBodyRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmHttpRequestBody *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->base_list_id = mpm_reg->sm_list_base; - SCLogDebug("list_id %d base_list_id %d", list_id, pectx->base_list_id); - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttpRequestBody, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmHttpRequestBodyFree, - mpm_reg->pname); -} - -#ifdef UNITTESTS -#include "detect-engine-alert.h" -#include "tests/detect-http-client-body.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-connection.c b/src/detect-http-connection.c deleted file mode 100644 index 2db451236721..000000000000 --- a/src/detect-http-connection.c +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements the http_connection sticky buffer - */ - -#define KEYWORD_NAME_LEGACY "http_connection" -#define KEYWORD_NAME "http.connection" -#define KEYWORD_DOC "http-keywords.html#http-connection" -#define BUFFER_NAME "http_connection" -#define BUFFER_DESC "http connection header" -#define HEADER_NAME "Connection" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_CONNECTION -#define KEYWORD_TOSERVER 1 -#define KEYWORD_TOCLIENT 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-connection.h" - -void RegisterHttpHeadersConnection(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-content-len.c b/src/detect-http-content-len.c deleted file mode 100644 index b9203e2c738d..000000000000 --- a/src/detect-http-content-len.c +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements http_content_len sticky buffer - */ - -#define KEYWORD_NAME_LEGACY "http_content_len" -#define KEYWORD_NAME "http.content_len" -#define KEYWORD_DOC "http-keywords.html#http-content-len" -#define BUFFER_NAME "http_content_len" -#define BUFFER_DESC "http content length header" -#define HEADER_NAME "Content-Length" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_CONTENT_LEN -#define KEYWORD_TOSERVER 1 -#define KEYWORD_TOCLIENT 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-content-len.h" - -void RegisterHttpHeadersContentLen(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-content-type.c b/src/detect-http-content-type.c deleted file mode 100644 index 66d5b9567519..000000000000 --- a/src/detect-http-content-type.c +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implement http_content_type sticky buffer - */ - -#define KEYWORD_NAME_LEGACY "http_content_type" -#define KEYWORD_NAME "http.content_type" -#define KEYWORD_DOC "http-keywords.html#http-content-type" -#define BUFFER_NAME "http_content_type" -#define BUFFER_DESC "http content type header" -#define HEADER_NAME "Content-Type" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_CONTENT_TYPE -#define KEYWORD_TOSERVER 1 -#define KEYWORD_TOCLIENT 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-content-type.h" - -void RegisterHttpHeadersContentType(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c deleted file mode 100644 index e2754138fd44..000000000000 --- a/src/detect-http-cookie.c +++ /dev/null @@ -1,278 +0,0 @@ -/* Copyright (C) 2007-2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Gurvinder Singh - * - * Implements the http_cookie keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-error.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-cookie.h" -#include "stream-tcp.h" - -static int DetectHttpCookieSetup (DetectEngineCtx *, Signature *, const char *); -static int DetectHttpCookieSetupSticky (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectHttpCookieRegisterTests(void); -#endif -static int g_http_cookie_buffer_id = 0; - -static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); -static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); -/** - * \brief Registration function for keyword: http_cookie - */ -void DetectHttpCookieRegister(void) -{ - /* http_cookie content modifier */ - sigmatch_table[DETECT_AL_HTTP_COOKIE].name = "http_cookie"; - sigmatch_table[DETECT_AL_HTTP_COOKIE].desc = "content modifier to match only on the HTTP cookie-buffer"; - sigmatch_table[DETECT_AL_HTTP_COOKIE].url = "/rules/http-keywords.html#http-cookie"; - sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_COOKIE].alternative = DETECT_HTTP_COOKIE; - - /* http.cookie sticky buffer */ - sigmatch_table[DETECT_HTTP_COOKIE].name = "http.cookie"; - sigmatch_table[DETECT_HTTP_COOKIE].desc = "sticky buffer to match on the HTTP Cookie/Set-Cookie buffers"; - sigmatch_table[DETECT_HTTP_COOKIE].url = "/rules/http-keywords.html#http-cookie"; - sigmatch_table[DETECT_HTTP_COOKIE].Setup = DetectHttpCookieSetupSticky; - sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_HTTP_COOKIE].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetRequestData); - DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetResponseData); - - DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRequestData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetResponseData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - - DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRequestData2); - DetectAppLayerInspectEngineRegister2("http_cookie", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetResponseData2); - - DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRequestData2, ALPROTO_HTTP2, HTTP2StateDataClient); - DetectAppLayerMpmRegister2("http_cookie", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetResponseData2, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectBufferTypeSetDescriptionByName("http_cookie", - "http cookie header"); - - g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); -} - -/** - * \brief this function setups the http_cookie modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, str, DETECT_AL_HTTP_COOKIE, g_http_cookie_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.user_agent keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpCookieSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_cookie_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_headers == NULL) - return NULL; - - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "Cookie"); - if (h == NULL || h->value == NULL) { - SCLogDebug("HTTP cookie header not present in this request"); - return NULL; - } - - const uint32_t data_len = bstr_len(h->value); - const uint8_t *data = bstr_ptr(h->value); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->response_headers == NULL) - return NULL; - - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, - "Set-Cookie"); - if (h == NULL || h->value == NULL) { - SCLogDebug("HTTP cookie header not present in this request"); - return NULL; - } - - const uint32_t data_len = bstr_len(h->value); - const uint8_t *data = bstr_ptr(h->value); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_cookie(txv, STREAM_TOSERVER, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_cookie(txv, STREAM_TOCLIENT, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/******************************** UNITESTS **********************************/ - -#ifdef UNITTESTS -#include "tests/detect-http-cookie.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-cookie.h b/src/detect-http-cookie.h deleted file mode 100644 index 0ed3fa5c66c7..000000000000 --- a/src/detect-http-cookie.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - */ - -#ifndef _DETECT_HTTP_COOKIE_H -#define _DETECT_HTTP_COOKIE_H - -/* prototypes */ -void DetectHttpCookieRegister(void); - -#endif /* _DETECT_HTTP_COOKIE_H */ - diff --git a/src/detect-http-header-common.c b/src/detect-http-header-common.c deleted file mode 100644 index 401a50fcf54d..000000000000 --- a/src/detect-http-header-common.c +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-header.h" -#include "stream-tcp.h" - -#include "detect-http-header-common.h" - -void *HttpHeaderThreadDataInit(void *data) -{ - HttpHeaderThreadData *td = SCCalloc(1, sizeof(*td)); - if (td != NULL) { - if (data == NULL) { - td->size_step = 512; - } else { - HttpHeaderThreadDataConfig *c = data; - td->size_step = c->size_step; - } - - /* initialize minimal buffers */ - (void)HttpHeaderExpandBuffer(td, &td->buffer, 1); - } - return td; -} - -void HttpHeaderThreadDataFree(void *data) -{ - HttpHeaderThreadData *hdrnames = data; - SCFree(hdrnames->buffer.buffer); - SCFree(hdrnames); -} - -int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, - HttpHeaderBuffer *buf, uint32_t size) -{ - size_t extra = td->size_step; - while ((buf->size + extra) < (size + buf->len)) { - extra += td->size_step; - } - SCLogDebug("adding %"PRIuMAX" to the buffer", (uintmax_t)extra); - - uint8_t *new_buffer = SCRealloc(buf->buffer, buf->size + extra); - if (unlikely(new_buffer == NULL)) { - buf->len = 0; - return -1; - } - buf->buffer = new_buffer; - buf->size += extra; - return 0; -} - -HttpHeaderBuffer *HttpHeaderGetBufferSpace(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - const int keyword_id, HttpHeaderThreadData **ret_hdr_td) -{ - *ret_hdr_td = NULL; - - HttpHeaderThreadData *hdr_td = - DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, keyword_id); - if (hdr_td == NULL) - return NULL; - *ret_hdr_td = hdr_td; - - HttpHeaderBuffer *buf = &hdr_td->buffer; - buf->len = 0; - return buf; -} diff --git a/src/detect-http-header-common.h b/src/detect-http-header-common.h deleted file mode 100644 index a9c830e2a235..000000000000 --- a/src/detect-http-header-common.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __DETECT_HTTP_HEADER_COMMON_H__ -#define __DETECT_HTTP_HEADER_COMMON_H__ - -typedef struct HttpHeaderBuffer_ { - uint8_t *buffer; - uint32_t size; /**< buffer size */ - uint32_t len; /**< part of buffer in use */ -} HttpHeaderBuffer; - -typedef struct HttpHeaderThreadConfig_ { - uint16_t size_step; -} HttpHeaderThreadDataConfig; - -typedef struct HttpHeaderThreadData_ { - HttpHeaderBuffer buffer; /**< array of buffers */ - uint16_t size_step; /**< increase size of HttpHeaderBuffer::buffer with this */ -} HttpHeaderThreadData; - -void *HttpHeaderThreadDataInit(void *data); -void HttpHeaderThreadDataFree(void *data); - -HttpHeaderBuffer *HttpHeaderGetBufferSpace(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - const int keyword_id, HttpHeaderThreadData **ret_hdr_td); - -int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, - HttpHeaderBuffer *buf, uint32_t size); - -#endif /* __DETECT_HTTP_HEADER_COMMON_H__ */ diff --git a/src/detect-http-header-names.c b/src/detect-http-header-names.c deleted file mode 100644 index 58989a1825df..000000000000 --- a/src/detect-http-header-names.c +++ /dev/null @@ -1,255 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support http_header_names - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-http-header-common.h" -#include "detect-http-header-names.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-header.h" -#include "stream-tcp.h" - -#define KEYWORD_NAME "http.header_names" -#define KEYWORD_NAME_LEGACY "http_header_names" -#define KEYWORD_DOC "http-keywords.html#http-header-names" -#define BUFFER_NAME "http_header_names" -#define BUFFER_DESC "http header names" -static int g_buffer_id = 0; -static int g_keyword_thread_id = 0; - -#define BUFFER_SIZE_STEP 256 -static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP }; - -static uint8_t *GetBufferForTX( - htp_tx_t *tx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint32_t *buffer_len) -{ - *buffer_len = 0; - - HttpHeaderThreadData *hdr_td = NULL; - HttpHeaderBuffer *buf = - HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); - if (unlikely(buf == NULL)) { - return NULL; - } - - htp_table_t *headers; - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= - HTP_REQUEST_HEADERS) - return NULL; - headers = tx->request_headers; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= - HTP_RESPONSE_HEADERS) - return NULL; - headers = tx->response_headers; - } - if (headers == NULL) - return NULL; - - /* fill the buffer. \r\nName1\r\nName2\r\n\r\n */ - size_t i = 0; - size_t no_of_headers = htp_table_size(headers); - for (; i < no_of_headers; i++) { - htp_header_t *h = htp_table_get_index(headers, i, NULL); - size_t size = bstr_size(h->name) + 2; // for \r\n - if (i == 0) - size += 2; - if (i + 1 == no_of_headers) - size += 2; - - SCLogDebug("size %"PRIuMAX" + buf->len %u vs buf->size %u", - (uintmax_t)size, buf->len, buf->size); - if (size + buf->len > buf->size) { - if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { - return NULL; - } - } - - /* start with a \r\n */ - if (i == 0) { - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; - } - - memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); - buf->len += bstr_size(h->name); - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; - - /* end with an extra \r\n */ - if (i + 1 == no_of_headers) { - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; - } - } - - *buffer_len = buf->len; - return buf->buffer; -} - -static InspectionBuffer *GetBuffer1ForTX(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t rawdata_len = 0; - uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flow_flags, &rawdata_len); - if (rawdata_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetBuffer2ForTX(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_header_names(txv, flow_flags, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief The setup function for the http.header_names keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to signature for the current Signature being parsed - * from the rules. - * \param m Pointer to the head of the SigMatchs for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int DetectHttpHeaderNamesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - - return 0; -} - -/** - * \brief Registers the keyword handlers for the "http.header_names" keyword. - */ -void DetectHttpHeaderNamesRegister(void) -{ - sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].alias = KEYWORD_NAME_LEGACY; - sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].Setup = DetectHttpHeaderNamesSetup; - - sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - /* http1 */ - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetBuffer1ForTX, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetBuffer1ForTX, ALPROTO_HTTP1, HTP_RESPONSE_HEADERS); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); - - /* http2 */ - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataClient); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, - BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, - HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); - - SCLogDebug("keyword %s registered. Thread id %d. " - "Buffer %s registered. Buffer id %d", - KEYWORD_NAME, g_keyword_thread_id, - BUFFER_NAME, g_buffer_id); -} diff --git a/src/detect-http-header.c b/src/detect-http-header.c deleted file mode 100644 index a4596c4085f2..000000000000 --- a/src/detect-http-header.c +++ /dev/null @@ -1,784 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Pablo Rincon - * - * Implements support for http_header keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "util-debug.h" -#include "util-print.h" -#include "util-memcmp.h" -#include "util-profiling.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-header.h" -#include "detect-http-header-common.h" - -static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectHttpHeaderRegisterTests(void); -#endif -static int g_http_header_buffer_id = 0; -static int g_keyword_thread_id = 0; - -#define BUFFER_SIZE_STEP 1024 -static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP }; - -static uint8_t *GetBufferForTX( - htp_tx_t *tx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint32_t *buffer_len) -{ - *buffer_len = 0; - - HttpHeaderThreadData *hdr_td = NULL; - HttpHeaderBuffer *buf = - HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); - if (unlikely(buf == NULL)) { - return NULL; - } - - htp_table_t *headers; - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= - HTP_REQUEST_HEADERS) - return NULL; - headers = tx->request_headers; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= - HTP_RESPONSE_HEADERS) - return NULL; - headers = tx->response_headers; - } - if (headers == NULL) - return NULL; - - size_t i = 0; - size_t no_of_headers = htp_table_size(headers); - for (; i < no_of_headers; i++) { - htp_header_t *h = htp_table_get_index(headers, i, NULL); - size_t size1 = bstr_size(h->name); - size_t size2 = bstr_size(h->value); - - if (flags & STREAM_TOSERVER) { - if (size1 == 6 && - SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { - continue; - } - } else { - if (size1 == 10 && - SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { - continue; - } - } - - size_t size = size1 + size2 + 4; -#if 0 - if (i + 1 == no_of_headers) - size += 2; -#endif - if (size + buf->len > buf->size) { - if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { - return NULL; - } - } - - memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); - buf->len += bstr_size(h->name); - buf->buffer[buf->len++] = ':'; - buf->buffer[buf->len++] = ' '; - memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); - buf->len += bstr_size(h->value); - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; -#if 0 // looks like this breaks existing rules - if (i + 1 == no_of_headers) { - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; - } -#endif - } - - *buffer_len = buf->len; - return buf->buffer; -} - -static InspectionBuffer *GetBuffer2ForTX(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_headers(txv, flow_flags, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** \internal - * \brief custom inspect function to utilize the cached headers - */ -static uint8_t DetectEngineInspectBufferHttpHeader(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - SCEnter(); - - const int list_id = engine->sm_list; - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - SCLogDebug("setting up inspect buffer %d", list_id); - - /* if prefilter didn't already run, we need to consider transformations */ - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - uint32_t rawdata_len = 0; - uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flags, &rawdata_len); - if (rawdata_len == 0) { - SCLogDebug("no data"); - goto end; - } - /* setup buffer and apply transforms */ - InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - const uint32_t data_len = buffer->inspect_len; - const uint8_t *data = buffer->inspect; - const uint64_t offset = buffer->inspect_offset; - - /* Inspect all the uricontents fetched on each - * transaction at the app layer */ - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)data, data_len, offset, DETECT_CI_FLAGS_SINGLE, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } -end: - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > - HTP_REQUEST_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, txv, flags) > - HTP_RESPONSE_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -typedef struct PrefilterMpmHttpHeaderCtx { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmHttpHeaderCtx; - -/** \brief Generic Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterMpmHttpHeader(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmHttpHeaderCtx *ctx = pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - SCLogDebug("running on list %d", ctx->list_id); - - const int list_id = ctx->list_id; - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t rawdata_len = 0; - uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flags, &rawdata_len); - if (rawdata_len == 0) - return; - - /* setup buffer and apply transforms */ - InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); - InspectionBufferApplyTransforms(buffer, ctx->transforms); - } - - const uint32_t data_len = buffer->inspect_len; - const uint8_t *data = buffer->inspect; - - SCLogDebug("mpm'ing buffer:"); - //PrintRawDataFp(stdout, data, data_len); - - if (data != NULL && data_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len); - } -} - -static void PrefilterMpmHttpTrailer(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - htp_tx_t *tx = txv; - const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); - /* if the request wasn't flagged as having a trailer, we skip */ - if (htud && ( - ((flags & STREAM_TOSERVER) && !htud->request_has_trailers) || - ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers))) { - SCReturn; - } - PrefilterMpmHttpHeader(det_ctx, pectx, p, f, txv, idx, _txd, flags); - SCReturn; -} - -static void PrefilterMpmHttpHeaderFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmHttpHeaderRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - SCEnter(); - - /* header */ - PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeader, - mpm_reg->app_v2.alproto, HTP_REQUEST_HEADERS, - pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - return r; - } - - /* trailer */ - pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailer, - mpm_reg->app_v2.alproto, HTP_REQUEST_TRAILER, - pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - } - return r; -} - -static int PrefilterMpmHttpHeaderResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - SCEnter(); - - /* header */ - PrefilterMpmHttpHeaderCtx *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeader, - mpm_reg->app_v2.alproto, HTP_RESPONSE_HEADERS, - pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - return r; - } - - /* trailer */ - pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailer, - mpm_reg->app_v2.alproto, HTP_RESPONSE_TRAILER, - pectx, PrefilterMpmHttpHeaderFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - } - return r; -} - -/** - * \brief The setup function for the http_header keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to signature for the current Signature being parsed - * from the rules. - * \param m Pointer to the head of the SigMatchs for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_HEADER, g_http_header_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.header keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_header_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -/** - * \brief Registers the keyword handlers for the "http_header" keyword. - */ -void DetectHttpHeaderRegister(void) -{ - /* http_header content modifier */ - sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; - sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer"; - sigmatch_table[DETECT_AL_HTTP_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header"; - sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_HEADER].alternative = DETECT_HTTP_HEADER; - - /* http.header sticky buffer */ - sigmatch_table[DETECT_HTTP_HEADER].name = "http.header"; - sigmatch_table[DETECT_HTTP_HEADER].desc = "sticky buffer to match on the normalized HTTP header-buffer"; - sigmatch_table[DETECT_HTTP_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header"; - sigmatch_table[DETECT_HTTP_HEADER].Setup = DetectHttpHeaderSetupSticky; - sigmatch_table[DETECT_HTTP_HEADER].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_HTTP_HEADER].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferHttpHeader, NULL); - DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOSERVER, 2, - PrefilterMpmHttpHeaderRequestRegister, NULL, ALPROTO_HTTP1, - 0); /* not used, registered twice: HEADERS/TRAILER */ - - DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_HEADERS, DetectEngineInspectBufferHttpHeader, NULL); - DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmHttpHeaderResponseRegister, NULL, ALPROTO_HTTP1, - 0); /* not used, registered twice: HEADERS/TRAILER */ - - DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); - DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectAppLayerInspectEngineRegister2("http_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetBuffer2ForTX); - DetectAppLayerMpmRegister2("http_header", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetBuffer2ForTX, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectBufferTypeSetDescriptionByName("http_header", - "http headers"); - - g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); - - g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs("http_header", - HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); -} - -static int g_http_request_header_buffer_id = 0; -static int g_http_response_header_buffer_id = 0; - -static InspectionBuffer *GetHttp2HeaderData(DetectEngineThreadCtx *det_ctx, const uint8_t flags, - const DetectEngineTransforms *transforms, Flow *_f, const struct MpmListIdDataArgs *cbdata, - int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_header(cbdata->txv, flags, cbdata->local_id, &b, &b_len) != 1) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - if (b == NULL || b_len == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, b, b_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static void PrefilterTxHttp2Header(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - - while (1) { - // loop until we get a NULL - - struct MpmListIdDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = - GetHttp2HeaderData(det_ctx, flags, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static uint8_t DetectEngineInspectHttp2Header(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - struct MpmListIdDataArgs cbdata = { - local_id, - txv, - }; - InspectionBuffer *buffer = - GetHttp2HeaderData(det_ctx, flags, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -static int PrefilterMpmHttp2HeaderRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp2Header, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->name); -} - -static InspectionBuffer *GetHttp1HeaderData(DetectEngineThreadCtx *det_ctx, const uint8_t flags, - const DetectEngineTransforms *transforms, Flow *f, const struct MpmListIdDataArgs *cbdata, - int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - HttpHeaderThreadData *hdr_td = NULL; - HttpHeaderBuffer *buf = - HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); - if (unlikely(buf == NULL)) { - return NULL; - } - - htp_tx_t *tx = (htp_tx_t *)cbdata->txv; - htp_table_t *headers; - if (flags & STREAM_TOSERVER) { - headers = tx->request_headers; - } else { - headers = tx->response_headers; - } - if (cbdata->local_id < htp_table_size(headers)) { - htp_header_t *h = htp_table_get_index(headers, cbdata->local_id, NULL); - size_t size1 = bstr_size(h->name); - size_t size2 = bstr_size(h->value); - size_t b_len = size1 + 2 + size2; - if (b_len > buf->size) { - if (HttpHeaderExpandBuffer(hdr_td, buf, b_len) != 0) { - return NULL; - } - } - memcpy(buf->buffer, bstr_ptr(h->name), bstr_size(h->name)); - buf->buffer[size1] = ':'; - buf->buffer[size1 + 1] = ' '; - memcpy(buf->buffer + size1 + 2, bstr_ptr(h->value), bstr_size(h->value)); - buf->len = b_len; - } else { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - if (buf->len == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, buf->buffer, buf->len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static void PrefilterTxHttp1Header(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - - while (1) { - // loop until we get a NULL - - struct MpmListIdDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = - GetHttp1HeaderData(det_ctx, flags, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static int PrefilterMpmHttp1HeaderRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp1Header, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmHttpHeaderFree, mpm_reg->name); -} - -static uint8_t DetectEngineInspectHttp1Header(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - struct MpmListIdDataArgs cbdata = { - local_id, - txv, - }; - InspectionBuffer *buffer = - GetHttp1HeaderData(det_ctx, flags, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -static int DetectHTTPRequestHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_request_header_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) != 0) - return -1; - - return 0; -} - -void DetectHttpRequestHeaderRegister(void) -{ - sigmatch_table[DETECT_HTTP_REQUEST_HEADER].name = "http.request_header"; - sigmatch_table[DETECT_HTTP_REQUEST_HEADER].desc = - "sticky buffer to match on only one HTTP header name and value"; - sigmatch_table[DETECT_HTTP_REQUEST_HEADER].url = "/rules/http-keywords.html#request_header"; - sigmatch_table[DETECT_HTTP_REQUEST_HEADER].Setup = DetectHTTPRequestHeaderSetup; - sigmatch_table[DETECT_HTTP_REQUEST_HEADER].flags |= - SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerMpmRegister2("http_request_header", SIG_FLAG_TOSERVER, 2, - PrefilterMpmHttp2HeaderRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen); - DetectAppLayerInspectEngineRegister2("http_request_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateOpen, DetectEngineInspectHttp2Header, NULL); - DetectAppLayerMpmRegister2("http_request_header", SIG_FLAG_TOSERVER, 2, - PrefilterMpmHttp1HeaderRegister, NULL, ALPROTO_HTTP1, 0); - DetectAppLayerInspectEngineRegister2("http_request_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectHttp1Header, NULL); - - DetectBufferTypeSetDescriptionByName("http_request_header", "HTTP header name and value"); - g_http_request_header_buffer_id = DetectBufferTypeGetByName("http_request_header"); - DetectBufferTypeSupportsMultiInstance("http_request_header"); -} - -static int DetectHTTPResponseHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_response_header_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) != 0) - return -1; - - return 0; -} - -void DetectHttpResponseHeaderRegister(void) -{ - sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].name = "http.response_header"; - sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].desc = - "sticky buffer to match on only one HTTP header name and value"; - sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].url = "/rules/http2-keywords.html#response_header"; - sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].Setup = DetectHTTPResponseHeaderSetup; - sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].flags |= - SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerMpmRegister2("http_response_header", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmHttp2HeaderRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen); - DetectAppLayerInspectEngineRegister2("http_response_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateOpen, DetectEngineInspectHttp2Header, NULL); - DetectAppLayerMpmRegister2("http_response_header", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmHttp1HeaderRegister, NULL, ALPROTO_HTTP1, 0); - DetectAppLayerInspectEngineRegister2("http_response_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_HEADERS, DetectEngineInspectHttp1Header, NULL); - - DetectBufferTypeSetDescriptionByName("http_response_header", "HTTP header name and value"); - g_http_response_header_buffer_id = DetectBufferTypeGetByName("http_response_header"); - DetectBufferTypeSupportsMultiInstance("http_response_header"); -} - -/************************************Unittests*********************************/ - -#ifdef UNITTESTS -#include "tests/detect-http-header.c" -#endif - -/** - * @} - */ diff --git a/src/detect-http-headers-stub.h b/src/detect-http-headers-stub.h deleted file mode 100644 index 3a036d62209e..000000000000 --- a/src/detect-http-headers-stub.h +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * Stub for per HTTP header detection keyword. Meant to be included into - * a C file. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - -#include "suricata-common.h" -#include "flow.h" - -#include - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" - -#include "util-debug.h" -#include "rust.h" - -static int g_buffer_id = 0; - -#ifdef KEYWORD_TOSERVER -static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_headers == NULL) - return NULL; - - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, - HEADER_NAME); - if (h == NULL || h->value == NULL) { - SCLogDebug("HTTP %s header not present in this request", - HEADER_NAME); - return NULL; - } - - const uint32_t data_len = bstr_len(h->value); - const uint8_t *data = bstr_ptr(h->value); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_header_value(txv, STREAM_TOSERVER, HEADER_NAME, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#endif -#ifdef KEYWORD_TOCLIENT -static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->response_headers == NULL) - return NULL; - - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, - HEADER_NAME); - if (h == NULL || h->value == NULL) { - SCLogDebug("HTTP %s header not present in this request", - HEADER_NAME); - return NULL; - } - - const uint32_t data_len = bstr_len(h->value); - const uint8_t *data = bstr_ptr(h->value); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_header_value(txv, STREAM_TOCLIENT, HEADER_NAME, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} -#endif - -/** - * \brief this function setup the http.header keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpHeadersSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - - return 0; -} - -static void DetectHttpHeadersRegisterStub(void) -{ - sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; -#ifdef KEYWORD_NAME_LEGACY - sigmatch_table[KEYWORD_ID].alias = KEYWORD_NAME_LEGACY; -#endif - sigmatch_table[KEYWORD_ID].desc = KEYWORD_NAME " sticky buffer for the " BUFFER_DESC; - sigmatch_table[KEYWORD_ID].url = "/rules/" KEYWORD_DOC; - sigmatch_table[KEYWORD_ID].Setup = DetectHttpHeadersSetupSticky; - sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - -#ifdef KEYWORD_TOSERVER - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRequestData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRequestData2, ALPROTO_HTTP2, HTTP2StateDataClient); -#endif -#ifdef KEYWORD_TOCLIENT - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetResponseData, ALPROTO_HTTP1, HTP_RESPONSE_HEADERS); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetResponseData2, ALPROTO_HTTP2, HTTP2StateDataServer); -#endif -#ifdef KEYWORD_TOSERVER - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetRequestData); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRequestData2); -#endif -#ifdef KEYWORD_TOCLIENT - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_HEADERS, DetectEngineInspectBufferGeneric, GetResponseData); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetResponseData2); -#endif - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-http-headers.c b/src/detect-http-headers.c deleted file mode 100644 index f9e8580606bb..000000000000 --- a/src/detect-http-headers.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "detect-http-accept.h" -#include "detect-http-accept-enc.h" -#include "detect-http-accept-lang.h" -#include "detect-http-connection.h" -#include "detect-http-content-len.h" -#include "detect-http-content-type.h" -#include "detect-http-location.h" -#include "detect-http-server.h" -#include "detect-http-referer.h" -#include "detect-http-headers.h" - -void DetectHttpHeadersRegister(void) -{ - RegisterHttpHeadersAccept(); - RegisterHttpHeadersAcceptEnc(); - RegisterHttpHeadersAcceptLang(); - RegisterHttpHeadersReferer(); - RegisterHttpHeadersConnection(); - RegisterHttpHeadersContentLen(); - RegisterHttpHeadersContentType(); - RegisterHttpHeadersServer(); - RegisterHttpHeadersLocation(); -} - diff --git a/src/detect-http-host.c b/src/detect-http-host.c deleted file mode 100644 index 6f32044a112c..000000000000 --- a/src/detect-http-host.c +++ /dev/null @@ -1,379 +0,0 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Anoop Saldanha - * - * Implements support for the http_host keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "stream-tcp.h" -#include "detect-http-host.h" - -static int DetectHttpHHSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectHttpHHRegisterTests(void); -#endif -static bool DetectHttpHostValidateCallback(const Signature *s, const char **sigerror); -static int DetectHttpHostSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); -static int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, const char *); -static int g_http_raw_host_buffer_id = 0; -static int DetectHttpHostRawSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); -static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id); -static InspectionBuffer *GetRawData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); -static int g_http_host_buffer_id = 0; - -/** - * \brief Registers the keyword handlers for the "http_host" keyword. - */ -void DetectHttpHHRegister(void) -{ - /* http_host content modifier */ - sigmatch_table[DETECT_AL_HTTP_HOST].name = "http_host"; - sigmatch_table[DETECT_AL_HTTP_HOST].desc = "content modifier to match on the HTTP hostname"; - sigmatch_table[DETECT_AL_HTTP_HOST].url = "/rules/http-keywords.html#http-host-and-http-raw-host"; - sigmatch_table[DETECT_AL_HTTP_HOST].Setup = DetectHttpHHSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_HOST].RegisterTests = DetectHttpHHRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_HOST].alternative = DETECT_HTTP_HOST; - - /* http.host sticky buffer */ - sigmatch_table[DETECT_HTTP_HOST].name = "http.host"; - sigmatch_table[DETECT_HTTP_HOST].desc = "sticky buffer to match on the HTTP Host buffer"; - sigmatch_table[DETECT_HTTP_HOST].url = "/rules/http-keywords.html#http-host-and-http-raw-host"; - sigmatch_table[DETECT_HTTP_HOST].Setup = DetectHttpHostSetup; - sigmatch_table[DETECT_HTTP_HOST].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_host", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - - DetectAppLayerInspectEngineRegister2("http_host", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - - DetectAppLayerMpmRegister2("http_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeRegisterValidateCallback("http_host", - DetectHttpHostValidateCallback); - - DetectBufferTypeSetDescriptionByName("http_host", - "http host"); - - g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); - - /* http_raw_host content modifier */ - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].name = "http_raw_host"; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].desc = "content modifier to match on the HTTP host header or the raw hostname from the HTTP uri"; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].url = "/rules/http-keywords.html#http-host-and-http-raw-host"; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Setup = DetectHttpHRHSetup; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].alternative = DETECT_HTTP_HOST_RAW; - - /* http.host sticky buffer */ - sigmatch_table[DETECT_HTTP_HOST_RAW].name = "http.host.raw"; - sigmatch_table[DETECT_HTTP_HOST_RAW].desc = "sticky buffer to match on the HTTP host header or the raw hostname from the HTTP uri"; - sigmatch_table[DETECT_HTTP_HOST_RAW].url = "/rules/http-keywords.html#http-host-and-http-raw-host"; - sigmatch_table[DETECT_HTTP_HOST_RAW].Setup = DetectHttpHostRawSetupSticky; - sigmatch_table[DETECT_HTTP_HOST_RAW].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_raw_host", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetRawData); - - DetectAppLayerMpmRegister2("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRawData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - - DetectAppLayerInspectEngineRegister2("http_raw_host", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRawData2); - - DetectAppLayerMpmRegister2("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRawData2, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeSetDescriptionByName("http_raw_host", - "http raw host header"); - - g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); -} - -/** - * \brief The setup function for the http_host keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to the signature for the current Signature being - * parsed from the rules. - * \param m Pointer to the head of the SigMatch for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectHttpHHSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_HOST, g_http_host_buffer_id, ALPROTO_HTTP1); -} - -static bool DetectHttpHostValidateCallback(const Signature *s, const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_http_host_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = "http.host keyword " - "specified along with \"nocase\". " - "The hostname buffer is normalized " - "to lowercase, specifying " - "nocase is redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } else { - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) - break; - } - if (u != cd->content_len) { - *sigerror = "A pattern with " - "uppercase characters detected for http.host. " - "The hostname buffer is normalized to lowercase, " - "please specify a lowercase pattern."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - } - } - } - } - - return true; -} - -/** - * \brief this function setup the http.host keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpHostSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_host_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_hostname == NULL) - return NULL; - - const uint32_t data_len = bstr_len(tx->request_hostname); - const uint8_t *data = bstr_ptr(tx->request_hostname); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_host_norm(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetRawData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_host(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief The setup function for the http_raw_host keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to the signature for the current Signature being - * parsed from the rules. - * \param m Pointer to the head of the SigMatch for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success - * \retval -1 On failure - */ -int DetectHttpHRHSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_RAW_HOST, g_http_raw_host_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.host keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpHostRawSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_host_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - const uint8_t *data = NULL; - uint32_t data_len = 0; - - if (tx->parsed_uri == NULL || tx->parsed_uri->hostname == NULL) { - if (tx->request_headers == NULL) - return NULL; - - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "Host"); - if (h == NULL || h->value == NULL) - return NULL; - - data = (const uint8_t *)bstr_ptr(h->value); - data_len = bstr_len(h->value); - } else { - data = (const uint8_t *)bstr_ptr(tx->parsed_uri->hostname); - data_len = bstr_len(tx->parsed_uri->hostname); - } - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/************************************Unittests*********************************/ - -#ifdef UNITTESTS -#include "tests/detect-http-host.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-location.c b/src/detect-http-location.c deleted file mode 100644 index bd4eb15dc9c3..000000000000 --- a/src/detect-http-location.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Jeff Lucovsky - * - * Implements http.location sticky buffer - * - * "Location" is an HTTP response-header field used to redirect the recipient to - * a location other than the Request-URI for request completion. - */ - -#define KEYWORD_NAME "http.location" -#define KEYWORD_DOC "http-keywords.html#http-location" -#define BUFFER_NAME "http.location" -#define BUFFER_DESC "http location header" -#define HEADER_NAME "Location" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_LOCATION -#define KEYWORD_TOCLIENT 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-location.h" - -void RegisterHttpHeadersLocation(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-method.c b/src/detect-http-method.c deleted file mode 100644 index 0ce246359ce9..000000000000 --- a/src/detect-http-method.c +++ /dev/null @@ -1,246 +0,0 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Brian Rectanus - * - * Implements the http_method keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-method.h" -#include "stream-tcp.h" - -static int g_http_method_buffer_id = 0; -static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectHttpMethodSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); -#ifdef UNITTESTS -void DetectHttpMethodRegisterTests(void); -#endif -void DetectHttpMethodFree(void *); -static bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id); -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); - -/** - * \brief Registration function for keyword: http_method - */ -void DetectHttpMethodRegister(void) -{ - /* http_method content modifier */ - sigmatch_table[DETECT_AL_HTTP_METHOD].name = "http_method"; - sigmatch_table[DETECT_AL_HTTP_METHOD].desc = "content modifier to match only on the HTTP method-buffer"; - sigmatch_table[DETECT_AL_HTTP_METHOD].url = "/rules/http-keywords.html#http-method"; - sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_METHOD].alternative = DETECT_HTTP_METHOD; - - /* http.method sticky buffer */ - sigmatch_table[DETECT_HTTP_METHOD].name = "http.method"; - sigmatch_table[DETECT_HTTP_METHOD].desc = "sticky buffer to match specifically and only on the HTTP method buffer"; - sigmatch_table[DETECT_HTTP_METHOD].url = "/rules/http-keywords.html#http-method"; - sigmatch_table[DETECT_HTTP_METHOD].Setup = DetectHttpMethodSetupSticky; - sigmatch_table[DETECT_HTTP_METHOD].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_method", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_method", SIG_FLAG_TOSERVER, 4, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); - - DetectAppLayerInspectEngineRegister2("http_method", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - - DetectAppLayerMpmRegister2("http_method", SIG_FLAG_TOSERVER, 4, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeSetDescriptionByName("http_method", - "http request method"); - - DetectBufferTypeRegisterValidateCallback("http_method", - DetectHttpMethodValidateCallback); - - g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); - - SCLogDebug("registering http_method rule option"); -} - -/** - * \brief This function is used to add the parsed "http_method" option - * into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param str Pointer to the user provided option string. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectHttpMethodSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, str, DETECT_AL_HTTP_METHOD, g_http_method_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.method keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpMethodSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_method_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - - return 0; -} - -/** - * \retval 1 valid - * \retval 0 invalid - */ -static bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_http_method_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - const DetectContentData *cd = (const DetectContentData *)sm->ctx; - if (cd->content && cd->content_len) { - if (cd->content[cd->content_len - 1] == 0x20) { - *sigerror = "http_method pattern with trailing space"; - SCLogError("%s", *sigerror); - return false; - } else if (cd->content[0] == 0x20) { - *sigerror = "http_method pattern with leading space"; - SCLogError("%s", *sigerror); - return false; - } else if (cd->content[cd->content_len - 1] == 0x09) { - *sigerror = "http_method pattern with trailing tab"; - SCLogError("%s", *sigerror); - return false; - } else if (cd->content[0] == 0x09) { - *sigerror = "http_method pattern with leading tab"; - SCLogError("%s", *sigerror); - return false; - } - } - } - } - return true; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_method == NULL) - return NULL; - - const uint32_t data_len = bstr_len(tx->request_method); - const uint8_t *data = bstr_ptr(tx->request_method); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_method(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS -#include "tests/detect-http-method.c" -#endif - -/** - * @} - */ diff --git a/src/detect-http-method.h b/src/detect-http-method.h deleted file mode 100644 index 871177b58749..000000000000 --- a/src/detect-http-method.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Brian Rectanus - */ - -#ifndef __DETECT_HTTP_METHOD_H__ -#define __DETECT_HTTP_METHOD_H__ - -/* prototypes */ -void DetectHttpMethodRegister(void); - -#endif /* __DETECT_HTTP_METHOD_H__ */ - diff --git a/src/detect-http-protocol.c b/src/detect-http-protocol.c deleted file mode 100644 index 9dc3455d2149..000000000000 --- a/src/detect-http-protocol.c +++ /dev/null @@ -1,165 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support http_protocol sticky buffer - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-http-header-common.h" -#include "detect-http-protocol.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-header.h" -#include "stream-tcp.h" - -#define KEYWORD_NAME "http.protocol" -#define KEYWORD_NAME_LEGACY "http_protocol" -#define KEYWORD_DOC "http-keywords.html#http-protocol" -#define BUFFER_NAME "http_protocol" -#define BUFFER_DESC "http protocol" -static int g_buffer_id = 0; - -static int DetectHttpProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - bstr *str = NULL; - htp_tx_t *tx = (htp_tx_t *)txv; - - if (flow_flags & STREAM_TOSERVER) - str = tx->request_protocol; - else if (flow_flags & STREAM_TOCLIENT) - str = tx->response_protocol; - - if (str == NULL) { - SCLogDebug("HTTP protocol not set"); - return NULL; - } - - uint32_t data_len = bstr_size(str); - uint8_t *data = bstr_ptr(str); - if (data == NULL || data_len == 0) { - SCLogDebug("HTTP protocol not present"); - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - InspectionBufferSetup( - det_ctx, list_id, buffer, (const uint8_t *)"HTTP/2", strlen("HTTP/2")); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief Registers the keyword handlers for the "http.protocol" keyword. - */ -void DetectHttpProtocolRegister(void) -{ - sigmatch_table[DETECT_AL_HTTP_PROTOCOL].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_HTTP_PROTOCOL].alias = KEYWORD_NAME_LEGACY; - sigmatch_table[DETECT_AL_HTTP_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_HTTP_PROTOCOL].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_HTTP_PROTOCOL].Setup = DetectHttpProtocolSetup; - sigmatch_table[DETECT_AL_HTTP_PROTOCOL].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, - BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c deleted file mode 100644 index 1494f02d22d7..000000000000 --- a/src/detect-http-raw-header.c +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Pablo Rincon - * - * Implements support for http_raw_header keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-profiling.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-htp.h" -#include "detect-http-raw-header.h" - -static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); -#ifdef UNITTESTS -static void DetectHttpRawHeaderRegisterTests(void); -#endif -static bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror); -static int g_http_raw_header_buffer_id = 0; -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id); -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, - const int list_id); - -static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); -static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); - -/** - * \brief Registers the keyword handlers for the "http_raw_header" keyword. - */ -void DetectHttpRawHeaderRegister(void) -{ - /* http_raw_header content modifier */ - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].name = "http_raw_header"; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].desc = "content modifier to match the raw HTTP header buffer"; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header"; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].RegisterTests = DetectHttpRawHeaderRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].alternative = DETECT_HTTP_RAW_HEADER; - - /* http.header.raw sticky buffer */ - sigmatch_table[DETECT_HTTP_RAW_HEADER].name = "http.header.raw"; - sigmatch_table[DETECT_HTTP_RAW_HEADER].desc = "sticky buffer to match the raw HTTP header buffer"; - sigmatch_table[DETECT_HTTP_RAW_HEADER].url = "/rules/http-keywords.html#http-header-and-http-raw-header"; - sigmatch_table[DETECT_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetupSticky; - sigmatch_table[DETECT_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData); - DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_HEADERS + 1, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOSERVER, 2, - PrefilterMpmHttpHeaderRawRequestRegister, NULL, ALPROTO_HTTP1, - 0); /* progress handled in register */ - DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmHttpHeaderRawResponseRegister, NULL, ALPROTO_HTTP1, - 0); /* progress handled in register */ - - DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - DetectAppLayerInspectEngineRegister2("http_raw_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); - - DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - DetectAppLayerMpmRegister2("http_raw_header", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectBufferTypeSetDescriptionByName("http_raw_header", - "raw http headers"); - - DetectBufferTypeRegisterValidateCallback("http_raw_header", - DetectHttpRawHeaderValidateCallback); - - g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); -} - -/** - * \brief The setup function for the http_raw_header keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to signature for the current Signature being parsed - * from the rules. - * \param m Pointer to the head of the SigMatchs for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_RAW_HEADER, g_http_raw_header_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.header.raw keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpRawHeaderSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_header_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror) -{ - if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { - *sigerror = "http_raw_header signature " - "without a flow direction. Use flow:to_server for " - "inspecting request headers or flow:to_client for " - "inspecting response headers."; - - SCLogError("%s", *sigerror); - SCReturnInt(false); - } - return true; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud == NULL) - return NULL; - - const bool ts = ((flow_flags & STREAM_TOSERVER) != 0); - const uint8_t *data = ts ? - tx_ud->request_headers_raw : tx_ud->response_headers_raw; - if (data == NULL) - return NULL; - const uint32_t data_len = ts ? - tx_ud->request_headers_raw_len : tx_ud->response_headers_raw_len; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_headers_raw(txv, flow_flags, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -typedef struct PrefilterMpmHttpHeaderRawCtx { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmHttpHeaderRawCtx; - -/** \brief Generic Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterMpmHttpHeaderRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmHttpHeaderRawCtx *ctx = pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - SCLogDebug("running on list %d", ctx->list_id); - - const int list_id = ctx->list_id; - - InspectionBuffer *buffer = GetData(det_ctx, ctx->transforms, f, - flags, txv, list_id); - if (buffer == NULL) - return; - - const uint32_t data_len = buffer->inspect_len; - const uint8_t *data = buffer->inspect; - - SCLogDebug("mpm'ing buffer:"); - //PrintRawDataFp(stdout, data, data_len); - - if (data != NULL && data_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, data, data_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, data_len); - } -} - -static void PrefilterMpmHttpTrailerRaw(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - htp_tx_t *tx = txv; - const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); - /* if the request wasn't flagged as having a trailer, we skip */ - if (htud && ( - ((flags & STREAM_TOSERVER) && !htud->request_has_trailers) || - ((flags & STREAM_TOCLIENT) && !htud->response_has_trailers))) { - SCReturn; - } - PrefilterMpmHttpHeaderRaw(det_ctx, pectx, p, f, txv, idx, _txd, flags); - SCReturn; -} - -static void PrefilterMpmHttpHeaderRawFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmHttpHeaderRawRequestRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - SCEnter(); - - /* header */ - PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, - mpm_reg->app_v2.alproto, HTP_REQUEST_HEADERS+1, - pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - return r; - } - - /* trailer */ - pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, - mpm_reg->app_v2.alproto, HTP_REQUEST_TRAILER+1, - pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - } - return r; -} - -static int PrefilterMpmHttpHeaderRawResponseRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - SCEnter(); - - /* header */ - PrefilterMpmHttpHeaderRawCtx *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpHeaderRaw, - mpm_reg->app_v2.alproto, HTP_RESPONSE_HEADERS, - pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - return r; - } - - /* trailer */ - pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpmHttpTrailerRaw, - mpm_reg->app_v2.alproto, HTP_RESPONSE_TRAILER, - pectx, PrefilterMpmHttpHeaderRawFree, mpm_reg->pname); - if (r != 0) { - SCFree(pectx); - } - return r; -} - -/************************************Unittests*********************************/ - -#ifdef UNITTESTS -#include "tests/detect-http-raw-header.c" -#endif - -/** - * @} - */ diff --git a/src/detect-http-referer.c b/src/detect-http-referer.c deleted file mode 100644 index 5ade2071a314..000000000000 --- a/src/detect-http-referer.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support http_referer sticky buffer - */ - -#define KEYWORD_NAME_LEGACY "http_referer" -#define KEYWORD_NAME "http.referer" -#define KEYWORD_DOC "http-keywords.html#http-referer" -#define BUFFER_NAME "http_referer" -#define BUFFER_DESC "http referer header" -#define HEADER_NAME "Referer" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_REFERER -#define KEYWORD_TOSERVER 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-referer.h" - -void RegisterHttpHeadersReferer(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c deleted file mode 100644 index 89d38cbd0a8a..000000000000 --- a/src/detect-http-request-line.c +++ /dev/null @@ -1,204 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support for the http_request_line keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "stream-tcp.h" -#include "detect-http-request-line.h" - -static int DetectHttpRequestLineSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectHttpRequestLineRegisterTests(void); -#endif -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static int g_http_request_line_buffer_id = 0; - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_request_line(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief Registers the keyword handlers for the "http_request_line" keyword. - */ -void DetectHttpRequestLineRegister(void) -{ - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].name = "http.request_line"; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].alias = "http_request_line"; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].desc = "sticky buffer to match on the HTTP request line"; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].url = "/rules/http-keywords.html#http-request-line"; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Setup = DetectHttpRequestLineSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].RegisterTests = DetectHttpRequestLineRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_request_line", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_request_line", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); - - DetectAppLayerInspectEngineRegister2("http_request_line", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - DetectAppLayerMpmRegister2("http_request_line", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeSetDescriptionByName("http_request_line", - "http request line"); - - g_http_request_line_buffer_id = DetectBufferTypeGetByName("http_request_line"); -} - -/** - * \brief The setup function for the http_request_line keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to the signature for the current Signature being - * parsed from the rules. - * \param m Pointer to the head of the SigMatch for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectHttpRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_request_line_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - if (unlikely(tx->request_line == NULL)) { - return NULL; - } - const uint32_t data_len = bstr_len(tx->request_line); - const uint8_t *data = bstr_ptr(tx->request_line); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -/************************************Unittests*********************************/ - -#ifdef UNITTESTS - -#include "stream-tcp-reassemble.h" - -/** - * \test Test that a signature containing a http_request_line is correctly parsed - * and the keyword is registered. - */ -static int DetectHttpRequestLineTest01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(http_request_line; content:\"GET /\"; sid:1;)"); - FAIL_IF_NULL(de_ctx->sig_list); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -static void DetectHttpRequestLineRegisterTests(void) -{ - UtRegisterTest("DetectHttpRequestLineTest01", DetectHttpRequestLineTest01); -} -#endif /* UNITTESTS */ -/** - * @} - */ diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c deleted file mode 100644 index 8758644681c7..000000000000 --- a/src/detect-http-response-line.c +++ /dev/null @@ -1,203 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support for the http_response_line keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "stream-tcp.h" -#include "detect-http-response-line.h" - -static int DetectHttpResponseLineSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectHttpResponseLineRegisterTests(void); -#endif -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static int g_http_response_line_id = 0; - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_response_line(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief Registers the keyword handlers for the "http_response_line" keyword. - */ -void DetectHttpResponseLineRegister(void) -{ - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].name = "http.response_line"; - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].alias = "http_response_line"; - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].desc = "content modifier to match only on the HTTP response line"; - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].url = "/rules/http-keywords.html#http-response-line"; - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Setup = DetectHttpResponseLineSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].RegisterTests = DetectHttpResponseLineRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_response_line", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_response_line", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); - - DetectAppLayerInspectEngineRegister2("http_response_line", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); - DetectAppLayerMpmRegister2("http_response_line", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectBufferTypeSetDescriptionByName("http_response_line", - "http response line"); - - g_http_response_line_id = DetectBufferTypeGetByName("http_response_line"); -} - -/** - * \brief The setup function for the http_response_line keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to the signature for the current Signature being - * parsed from the rules. - * \param m Pointer to the head of the SigMatch for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectHttpResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_response_line_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - if (unlikely(tx->response_line == NULL)) { - return NULL; - } - const uint32_t data_len = bstr_len(tx->response_line); - const uint8_t *data = bstr_ptr(tx->response_line); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -/************************************Unittests*********************************/ - -#ifdef UNITTESTS - -#include "stream-tcp-reassemble.h" - -/** - * \test Test that a signature containing a http_response_line is correctly parsed - * and the keyword is registered. - */ -static int DetectHttpResponseLineTest01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(http_response_line; content:\"200 OK\"; sid:1;)"); - FAIL_IF_NULL(de_ctx->sig_list); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -void DetectHttpResponseLineRegisterTests(void) -{ - UtRegisterTest("DetectHttpResponseLineTest01", DetectHttpResponseLineTest01); -} -#endif /* UNITTESTS */ -/** - * @} - */ diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c deleted file mode 100644 index 98f0ec581e94..000000000000 --- a/src/detect-http-server-body.c +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (C) 2007-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Anoop Saldanha - * \author Victor Julien - * - * Implements support for the http_server_body keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" - -#include "flow.h" -#include "flow-util.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-profiling.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-server-body.h" -#include "stream-tcp.h" - -static int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, const char *); -static int DetectHttpServerBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); -#ifdef UNITTESTS -static void DetectHttpServerBodyRegisterTests(void); -#endif -static int g_buffer_id = 0; - -/** - * \brief Registers the keyword handlers for the "http_server_body" keyword. - */ -void DetectHttpServerBodyRegister(void) -{ - /* http_server_body content modifier */ - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].name = "http_server_body"; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].desc = "content modifier to match on the HTTP response-body"; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = "/rules/http-keywords.html#http-server-body"; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].alternative = DETECT_HTTP_RESPONSE_BODY; - - /* http.request_body sticky buffer */ - sigmatch_table[DETECT_HTTP_RESPONSE_BODY].name = "http.response_body"; - sigmatch_table[DETECT_HTTP_RESPONSE_BODY].desc = "sticky buffer to match the HTTP response body buffer"; - sigmatch_table[DETECT_HTTP_RESPONSE_BODY].url = "/rules/http-keywords.html#http-server-body"; - sigmatch_table[DETECT_HTTP_RESPONSE_BODY].Setup = DetectHttpServerBodySetupSticky; - sigmatch_table[DETECT_HTTP_RESPONSE_BODY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_HTTP_RESPONSE_BODY].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - g_buffer_id = DetectBufferTypeRegister("file_data"); -} - -/** - * \brief The setup function for the http_server_body keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to signature for the current Signature being parsed - * from the rules. - * \param m Pointer to the head of the SigMatchs for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success - * \retval -1 On failure - */ -int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_SERVER_BODY, g_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.response_body keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpServerBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -/************************************Unittests*********************************/ - -#ifdef UNITTESTS -#include "tests/detect-http-server-body.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-server.c b/src/detect-http-server.c deleted file mode 100644 index d0d598419acb..000000000000 --- a/src/detect-http-server.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Jeff Lucovsky - * - * Implements http.server sticky buffer - * - * "Server" is an HTTP response-header field containing information about the software - * used by the origin server to handle the request. - */ - -#define KEYWORD_NAME "http.server" -#define KEYWORD_DOC "http-keywords.html#http-server" -#define BUFFER_NAME "http.server" -#define BUFFER_DESC "http server header" -#define HEADER_NAME "Server" -#define KEYWORD_ID DETECT_AL_HTTP_HEADER_SERVER -#define KEYWORD_TOCLIENT 1 - -#include "detect-http-headers-stub.h" -#include "detect-http-server.h" - -void RegisterHttpHeadersServer(void) -{ - DetectHttpHeadersRegisterStub(); -} diff --git a/src/detect-http-start.c b/src/detect-http-start.c deleted file mode 100644 index fed1abc96256..000000000000 --- a/src/detect-http-start.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - -/** - * \file - * - * \author Victor Julien - * - * Implements http_start - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-http-header-common.h" -#include "detect-http-start.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-header.h" -#include "stream-tcp.h" - -#define KEYWORD_NAME "http.start" -#define KEYWORD_NAME_LEGACY "http_start" -#define KEYWORD_DOC "http-keywords.html#http-start" -#define BUFFER_NAME "http_start" -#define BUFFER_DESC "http start: request/response line + headers" -static int g_buffer_id = 0; -static int g_keyword_thread_id = 0; - -#define BUFFER_SIZE_STEP 2048 -static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP }; - -static uint8_t *GetBufferForTX( - htp_tx_t *tx, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, uint32_t *buffer_len) -{ - *buffer_len = 0; - - HttpHeaderThreadData *hdr_td = NULL; - HttpHeaderBuffer *buf = - HttpHeaderGetBufferSpace(det_ctx, f, flags, g_keyword_thread_id, &hdr_td); - if (unlikely(buf == NULL)) { - return NULL; - } - - bstr *line = NULL; - htp_table_t *headers; - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= - HTP_REQUEST_HEADERS) - return NULL; - line = tx->request_line; - headers = tx->request_headers; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP1, tx, flags) <= - HTP_RESPONSE_HEADERS) - return NULL; - headers = tx->response_headers; - line = tx->response_line; - } - if (line == NULL || headers == NULL) - return NULL; - - size_t line_size = bstr_len(line) + 2; - if (line_size + buf->len > buf->size) { - if (HttpHeaderExpandBuffer(hdr_td, buf, line_size) != 0) { - return NULL; - } - } - memcpy(buf->buffer + buf->len, bstr_ptr(line), bstr_size(line)); - buf->len += bstr_size(line); - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; - - size_t i = 0; - size_t no_of_headers = htp_table_size(headers); - for (; i < no_of_headers; i++) { - htp_header_t *h = htp_table_get_index(headers, i, NULL); - size_t size1 = bstr_size(h->name); - size_t size2 = bstr_size(h->value); - size_t size = size1 + size2 + 4; - if (i + 1 == no_of_headers) - size += 2; - if (size + buf->len > buf->size) { - if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { - return NULL; - } - } - - memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); - buf->len += bstr_size(h->name); - buf->buffer[buf->len++] = ':'; - buf->buffer[buf->len++] = ' '; - memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); - buf->len += bstr_size(h->value); - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; - if (i + 1 == no_of_headers) { - buf->buffer[buf->len++] = '\r'; - buf->buffer[buf->len++] = '\n'; - } - } - - *buffer_len = buf->len; - return buf->buffer; -} - -static InspectionBuffer *GetBuffer1ForTX(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t rawdata_len = 0; - uint8_t *rawdata = GetBufferForTX(txv, det_ctx, f, flow_flags, &rawdata_len); - if (rawdata_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, rawdata, rawdata_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static int DetectHttpStartSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP1) < 0) - return -1; - - return 0; -} - -/** - * \brief Registers the keyword handlers for the "http_start" keyword. - */ -void DetectHttpStartRegister(void) -{ - sigmatch_table[DETECT_AL_HTTP_START].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_HTTP_START].alias = KEYWORD_NAME_LEGACY; - sigmatch_table[DETECT_AL_HTTP_START].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_HTTP_START].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_HTTP_START].Setup = DetectHttpStartSetup; - sigmatch_table[DETECT_AL_HTTP_START].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetBuffer1ForTX, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetBuffer1ForTX, ALPROTO_HTTP1, HTP_RESPONSE_HEADERS); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_HEADERS, DetectEngineInspectBufferGeneric, GetBuffer1ForTX); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, - BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, - HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); - - SCLogDebug("keyword %s registered. Thread id %d. " - "Buffer %s registered. Buffer id %d", - KEYWORD_NAME, g_keyword_thread_id, - BUFFER_NAME, g_buffer_id); -} diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c deleted file mode 100644 index 1e7087a318b3..000000000000 --- a/src/detect-http-stat-code.c +++ /dev/null @@ -1,206 +0,0 @@ -/* Copyright (C) 2007-2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Gurvinder Singh - * \author Anoop Saldanha - * - * Implements the http_stat_code keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-error.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-stat-code.h" -#include "stream-tcp-private.h" -#include "stream-tcp.h" - -static int DetectHttpStatCodeSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectHttpStatCodeSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); -#ifdef UNITTESTS -static void DetectHttpStatCodeRegisterTests(void); -#endif -static int g_http_stat_code_buffer_id = 0; -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id); -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); - -/** - * \brief Registration function for keyword: http_stat_code - */ -void DetectHttpStatCodeRegister (void) -{ - /* http_stat_code content modifier */ - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].name = "http_stat_code"; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].desc = "content modifier to match only on HTTP stat-code-buffer"; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = "/rules/http-keywords.html#http-stat-code"; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].alternative = DETECT_HTTP_STAT_CODE; - - /* http.stat_code content modifier */ - sigmatch_table[DETECT_HTTP_STAT_CODE].name = "http.stat_code"; - sigmatch_table[DETECT_HTTP_STAT_CODE].desc = "sticky buffer to match only on HTTP stat-code-buffer"; - sigmatch_table[DETECT_HTTP_STAT_CODE].url = "/rules/http-keywords.html#http-stat-code"; - sigmatch_table[DETECT_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetupSticky; - sigmatch_table[DETECT_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_stat_code", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_stat_code", SIG_FLAG_TOCLIENT, 4, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); - - DetectAppLayerInspectEngineRegister2("http_stat_code", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); - - DetectAppLayerMpmRegister2("http_stat_code", SIG_FLAG_TOCLIENT, 4, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectBufferTypeSetDescriptionByName("http_stat_code", - "http response status code"); - - g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); -} - -/** - * \brief this function setups the http_stat_code modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectHttpStatCodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_STAT_CODE, g_http_stat_code_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.stat_code keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpStatCodeSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_stat_code_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->response_status == NULL) - return NULL; - - const uint32_t data_len = bstr_len(tx->response_status); - const uint8_t *data = bstr_ptr(tx->response_status); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_status(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS -#include "tests/detect-http-stat-code.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-stat-code.h b/src/detect-http-stat-code.h deleted file mode 100644 index e813b6a75fc0..000000000000 --- a/src/detect-http-stat-code.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - */ - -#ifndef _DETECT_HTTP_STAT_CODE_H -#define _DETECT_HTTP_STAT_CODE_H - -/* prototypes */ -void DetectHttpStatCodeRegister(void); - -#endif /* _DETECT_HTTP_STAT_CODE_H */ - diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c deleted file mode 100644 index 6be7de64f756..000000000000 --- a/src/detect-http-stat-msg.c +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright (C) 2007-2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Gurvinder Singh - * \author Anoop Saldanha - * - * Implements the http_stat_msg keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-error.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "detect-http-stat-msg.h" -#include "stream-tcp-private.h" -#include "stream-tcp.h" - -static int DetectHttpStatMsgSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectHttpStatMsgRegisterTests(void); -#endif -static int g_http_stat_msg_buffer_id = 0; -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id); -static int DetectHttpStatMsgSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - InspectionBufferSetup(det_ctx, list_id, buffer, (const uint8_t *)"", 0); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief Registration function for keyword: http_stat_msg - */ -void DetectHttpStatMsgRegister (void) -{ - /* http_stat_msg content modifier */ - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].name = "http_stat_msg"; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].desc = "content modifier to match on HTTP stat-msg-buffer"; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = "/rules/http-keywords.html#http-stat-msg"; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].alternative = DETECT_HTTP_STAT_MSG; - - /* http.stat_msg sticky buffer */ - sigmatch_table[DETECT_HTTP_STAT_MSG].name = "http.stat_msg"; - sigmatch_table[DETECT_HTTP_STAT_MSG].desc = "sticky buffer to match on the HTTP response status message"; - sigmatch_table[DETECT_HTTP_STAT_MSG].url = "/rules/http-keywords.html#http-stat-msg"; - sigmatch_table[DETECT_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetupSticky; - sigmatch_table[DETECT_HTTP_STAT_MSG].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_stat_msg", ALPROTO_HTTP1, SIG_FLAG_TOCLIENT, - HTP_RESPONSE_LINE, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_stat_msg", SIG_FLAG_TOCLIENT, 3, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_RESPONSE_LINE); - - DetectAppLayerInspectEngineRegister2("http_stat_msg", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, - HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetData2); - DetectAppLayerMpmRegister2("http_stat_msg", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataServer); - - DetectBufferTypeSetDescriptionByName("http_stat_msg", - "http response status message"); - - g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); -} - -/** - * \brief this function setups the http_stat_msg modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectHttpStatMsgSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_STAT_MSG, g_http_stat_msg_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.stat_msg keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpStatMsgSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_stat_msg_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->response_message == NULL) - return NULL; - - const uint32_t data_len = bstr_len(tx->response_message); - const uint8_t *data = bstr_ptr(tx->response_message); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS -#include "tests/detect-http-stat-msg.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-stat-msg.h b/src/detect-http-stat-msg.h deleted file mode 100644 index fe82089db4bf..000000000000 --- a/src/detect-http-stat-msg.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - */ - -#ifndef _DETECT_HTTP_STAT_MSG_H -#define _DETECT_HTTP_STAT_MSG_H - -/* prototypes */ -void DetectHttpStatMsgRegister(void); - -#endif /* _DETECT_HTTP_STAT_MSG_H */ - diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c deleted file mode 100644 index 7138cf93fea4..000000000000 --- a/src/detect-http-ua.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (C) 2007-2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Anoop Saldanha - * - * Implements support for the http_user_agent keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-htp.h" -#include "stream-tcp.h" -#include "detect-http-ua.h" - -static int DetectHttpUASetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectHttpUARegisterTests(void); -#endif -static int g_http_ua_buffer_id = 0; -static int DetectHttpUserAgentSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); - -/** - * \brief Registers the keyword handlers for the "http_user_agent" keyword. - */ -void DetectHttpUARegister(void) -{ - /* http_user_agent content modifier */ - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].name = "http_user_agent"; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].desc = "content modifier to match only on the HTTP User-Agent header"; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = "/rules/http-keywords.html#http-user-agent"; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].alternative = DETECT_HTTP_UA; - - /* http.user_agent sticky buffer */ - sigmatch_table[DETECT_HTTP_UA].name = "http.user_agent"; - sigmatch_table[DETECT_HTTP_UA].desc = "sticky buffer to match specifically and only on the HTTP User Agent buffer"; - sigmatch_table[DETECT_HTTP_UA].url = "/rules/http-keywords.html#http-user-agent"; - sigmatch_table[DETECT_HTTP_UA].Setup = DetectHttpUserAgentSetup; - sigmatch_table[DETECT_HTTP_UA].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_HTTP_UA].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_user_agent", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_user_agent", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_REQUEST_HEADERS); - - DetectAppLayerInspectEngineRegister2("http_user_agent", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - - DetectAppLayerMpmRegister2("http_user_agent", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeSetDescriptionByName("http_user_agent", - "http user agent"); - - g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); -} - -/** - * \brief The setup function for the http_user_agent keyword for a signature. - * - * \param de_ctx Pointer to the detection engine context. - * \param s Pointer to the signature for the current Signature being - * parsed from the rules. - * \param m Pointer to the head of the SigMatch for the current rule - * being parsed. - * \param arg Pointer to the string holding the keyword value. - * - * \retval 0 On success - * \retval -1 On failure - */ -int DetectHttpUASetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_USER_AGENT, g_http_ua_buffer_id, ALPROTO_HTTP1); -} - -/** - * \brief this function setup the http.user_agent keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpUserAgentSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_ua_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - htp_tx_t *tx = (htp_tx_t *)txv; - - if (tx->request_headers == NULL) - return NULL; - - htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "User-Agent"); - if (h == NULL || h->value == NULL) { - SCLogDebug("HTTP UA header not present in this request"); - return NULL; - } - - const uint32_t data_len = bstr_len(h->value); - const uint8_t *data = bstr_ptr(h->value); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_useragent(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS -#include "tests/detect-http-user-agent.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c deleted file mode 100644 index cc43023a783a..000000000000 --- a/src/detect-http-uri.c +++ /dev/null @@ -1,343 +0,0 @@ -/* Copyright (C) 2007-2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** - * \file - * - * \author Gerardo Iglesias - * \author Victor Julien - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-spm.h" -#include "util-print.h" - -#include "app-layer.h" - -#include "app-layer-htp.h" -#include "detect-http-uri.h" -#include "stream-tcp.h" - -#ifdef UNITTESTS -static void DetectHttpUriRegisterTests(void); -#endif -static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); -static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); -static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); -static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, const char *); -static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); -static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **); -static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id); -static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str); - -static int g_http_raw_uri_buffer_id = 0; -static int g_http_uri_buffer_id = 0; - -/** - * \brief Registration function for keywords: http_uri and http.uri - */ -void DetectHttpUriRegister (void) -{ - /* http_uri content modifier */ - sigmatch_table[DETECT_AL_HTTP_URI].name = "http_uri"; - sigmatch_table[DETECT_AL_HTTP_URI].desc = "content modifier to match specifically and only on the HTTP uri-buffer"; - sigmatch_table[DETECT_AL_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw"; - sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; -#endif - sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_URI].alternative = DETECT_HTTP_URI; - - /* http.uri sticky buffer */ - sigmatch_table[DETECT_HTTP_URI].name = "http.uri"; - sigmatch_table[DETECT_HTTP_URI].alias = "http.uri.normalized"; - sigmatch_table[DETECT_HTTP_URI].desc = "sticky buffer to match specifically and only on the normalized HTTP URI buffer"; - sigmatch_table[DETECT_HTTP_URI].url = "/rules/http-keywords.html#http-uri-and-http-uri-raw"; - sigmatch_table[DETECT_HTTP_URI].Setup = DetectHttpUriSetupSticky; - sigmatch_table[DETECT_HTTP_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_HTTP1, HTP_REQUEST_LINE); - - DetectAppLayerInspectEngineRegister2("http_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - - DetectAppLayerMpmRegister2("http_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeSetDescriptionByName("http_uri", - "http request uri"); - - DetectBufferTypeRegisterSetupCallback("http_uri", - DetectHttpUriSetupCallback); - - DetectBufferTypeRegisterValidateCallback("http_uri", - DetectHttpUriValidateCallback); - - g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); - - /* http_raw_uri content modifier */ - sigmatch_table[DETECT_AL_HTTP_RAW_URI].name = "http_raw_uri"; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on the raw HTTP uri"; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = "/rules/http-keywords.html#http_uri-and-http_raw-uri"; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_CONTENT_MODIFIER; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].alternative = DETECT_HTTP_URI_RAW; - - /* http.uri.raw sticky buffer */ - sigmatch_table[DETECT_HTTP_URI_RAW].name = "http.uri.raw"; - sigmatch_table[DETECT_HTTP_URI_RAW].desc = "sticky buffer to match specifically and only on the raw HTTP URI buffer"; - sigmatch_table[DETECT_HTTP_URI_RAW].url = "/rules/http-keywords.html#http-uri-and-http-raw-uri"; - sigmatch_table[DETECT_HTTP_URI_RAW].Setup = DetectHttpRawUriSetupSticky; - sigmatch_table[DETECT_HTTP_URI_RAW].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP1, SIG_FLAG_TOSERVER, - HTP_REQUEST_LINE, DetectEngineInspectBufferGeneric, GetRawData); - - DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRawData, ALPROTO_HTTP1, HTP_REQUEST_LINE); - - // no difference between raw and decoded uri for HTTP2 - DetectAppLayerInspectEngineRegister2("http_raw_uri", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); - - DetectAppLayerMpmRegister2("http_raw_uri", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); - - DetectBufferTypeSetDescriptionByName("http_raw_uri", - "raw http uri"); - - DetectBufferTypeRegisterSetupCallback("http_raw_uri", - DetectHttpRawUriSetupCallback); - - DetectBufferTypeRegisterValidateCallback("http_raw_uri", - DetectHttpRawUriValidateCallback); - - g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri"); -} - -/** - * \brief this function setups the http_uri modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, str, DETECT_AL_HTTP_URI, g_http_uri_buffer_id, ALPROTO_HTTP1); -} - -static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror) -{ - return DetectUrilenValidateContent(s, g_http_uri_buffer_id, sigerror); -} - -static void DetectHttpUriSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - SCLogDebug("callback invoked by %u", s->id); - DetectUrilenApplyToContent(s, g_http_uri_buffer_id); -} - -/** - * \brief this function setup the http.uri keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_uri_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (!buffer->initialized) { - htp_tx_t *tx = (htp_tx_t *)txv; - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - - if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) { - SCLogDebug("no tx_id or uri"); - return NULL; - } - - const uint32_t data_len = bstr_len(tx_ud->request_uri_normalized); - const uint8_t *data = bstr_ptr(tx_ud->request_uri_normalized); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (!buffer->initialized) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_uri(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief Sets up the http_raw_uri modifier keyword. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Signature to which the current keyword belongs. - * \param arg Should hold an empty string always. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - return DetectEngineContentModifierBufferSetup( - de_ctx, s, arg, DETECT_AL_HTTP_RAW_URI, g_http_raw_uri_buffer_id, ALPROTO_HTTP1); -} - -static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **sigerror) -{ - return DetectUrilenValidateContent(s, g_http_raw_uri_buffer_id, sigerror); -} - -static void DetectHttpRawUriSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - SCLogDebug("callback invoked by %u", s->id); - DetectUrilenApplyToContent(s, g_http_raw_uri_buffer_id); -} - -/** - * \brief this function setup the http.uri.raw keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - */ -static int DetectHttpRawUriSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http_raw_uri_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; - return 0; -} - -static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (!buffer->initialized) { - htp_tx_t *tx = (htp_tx_t *)txv; - if (unlikely(tx->request_uri == NULL)) { - return NULL; - } - const uint32_t data_len = bstr_len(tx->request_uri); - const uint8_t *data = bstr_ptr(tx->request_uri); - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS /* UNITTESTS */ -#include "tests/detect-http-uri.c" -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/detect-http-uri.h b/src/detect-http-uri.h deleted file mode 100644 index 4db00ac2d5c3..000000000000 --- a/src/detect-http-uri.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gerardo Iglesias Galvan - */ - -#ifndef _DETECT_HTTP_URI_H -#define _DETECT_HTTP_URI_H - -/* prototypes */ -int DetectHttpUriSetup (DetectEngineCtx *, Signature *, const char *); -void DetectHttpUriRegister (void); - -#endif /* _DETECT_HTTP_URI_H */ diff --git a/src/detect-http2.c b/src/detect-http2.c deleted file mode 100644 index a1ede963825e..000000000000 --- a/src/detect-http2.c +++ /dev/null @@ -1,719 +0,0 @@ -/* Copyright (C) 2020-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Philippe Antoine - * - */ - -#include "suricata-common.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-content.h" - -#include "detect-engine.h" -#include "detect-engine-uint.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "detect-http2.h" -#include "util-byte.h" -#include "rust.h" -#include "util-profiling.h" - -#ifdef UNITTESTS -void DetectHTTP2frameTypeRegisterTests (void); -void DetectHTTP2errorCodeRegisterTests (void); -void DetectHTTP2priorityRegisterTests (void); -void DetectHTTP2windowRegisterTests (void); -void DetectHTTP2settingsRegisterTests (void); -void DetectHTTP2sizeUpdateRegisterTests (void); -#endif - -/* prototypes */ -static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectHTTP2frametypeSetup (DetectEngineCtx *, Signature *, const char *); -void DetectHTTP2frametypeFree (DetectEngineCtx *, void *); - -static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectHTTP2errorcodeSetup (DetectEngineCtx *, Signature *, const char *); -void DetectHTTP2errorcodeFree (DetectEngineCtx *, void *); - -static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectHTTP2prioritySetup (DetectEngineCtx *, Signature *, const char *); -void DetectHTTP2priorityFree (DetectEngineCtx *, void *); - -static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectHTTP2windowSetup (DetectEngineCtx *, Signature *, const char *); -void DetectHTTP2windowFree (DetectEngineCtx *, void *); - -static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectHTTP2sizeUpdateSetup (DetectEngineCtx *, Signature *, const char *); -void DetectHTTP2sizeUpdateFree (DetectEngineCtx *, void *); - -static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectHTTP2settingsSetup (DetectEngineCtx *, Signature *, const char *); -void DetectHTTP2settingsFree (DetectEngineCtx *, void *); - -static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg); -static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id); -static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); - -#ifdef UNITTESTS -void DetectHTTP2RegisterTests (void); -#endif - -static int g_http2_match_buffer_id = 0; -static int g_http2_header_name_buffer_id = 0; - -/** - * \brief Registration function for HTTP2 keywords - */ - -void DetectHttp2Register(void) -{ - sigmatch_table[DETECT_HTTP2_FRAMETYPE].name = "http2.frametype"; - sigmatch_table[DETECT_HTTP2_FRAMETYPE].desc = "match on HTTP2 frame type field"; - sigmatch_table[DETECT_HTTP2_FRAMETYPE].url = "/rules/http2-keywords.html#frametype"; - sigmatch_table[DETECT_HTTP2_FRAMETYPE].Match = NULL; - sigmatch_table[DETECT_HTTP2_FRAMETYPE].AppLayerTxMatch = DetectHTTP2frametypeMatch; - sigmatch_table[DETECT_HTTP2_FRAMETYPE].Setup = DetectHTTP2frametypeSetup; - sigmatch_table[DETECT_HTTP2_FRAMETYPE].Free = DetectHTTP2frametypeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_HTTP2_FRAMETYPE].RegisterTests = DetectHTTP2frameTypeRegisterTests; -#endif - - sigmatch_table[DETECT_HTTP2_ERRORCODE].name = "http2.errorcode"; - sigmatch_table[DETECT_HTTP2_ERRORCODE].desc = "match on HTTP2 error code field"; - sigmatch_table[DETECT_HTTP2_ERRORCODE].url = "/rules/http2-keywords.html#errorcode"; - sigmatch_table[DETECT_HTTP2_ERRORCODE].Match = NULL; - sigmatch_table[DETECT_HTTP2_ERRORCODE].AppLayerTxMatch = DetectHTTP2errorcodeMatch; - sigmatch_table[DETECT_HTTP2_ERRORCODE].Setup = DetectHTTP2errorcodeSetup; - sigmatch_table[DETECT_HTTP2_ERRORCODE].Free = DetectHTTP2errorcodeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_HTTP2_ERRORCODE].RegisterTests = DetectHTTP2errorCodeRegisterTests; -#endif - - sigmatch_table[DETECT_HTTP2_PRIORITY].name = "http2.priority"; - sigmatch_table[DETECT_HTTP2_PRIORITY].desc = "match on HTTP2 priority weight field"; - sigmatch_table[DETECT_HTTP2_PRIORITY].url = "/rules/http2-keywords.html#priority"; - sigmatch_table[DETECT_HTTP2_PRIORITY].Match = NULL; - sigmatch_table[DETECT_HTTP2_PRIORITY].AppLayerTxMatch = DetectHTTP2priorityMatch; - sigmatch_table[DETECT_HTTP2_PRIORITY].Setup = DetectHTTP2prioritySetup; - sigmatch_table[DETECT_HTTP2_PRIORITY].Free = DetectHTTP2priorityFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_HTTP2_PRIORITY].RegisterTests = DetectHTTP2priorityRegisterTests; -#endif - - sigmatch_table[DETECT_HTTP2_WINDOW].name = "http2.window"; - sigmatch_table[DETECT_HTTP2_WINDOW].desc = "match on HTTP2 window update size increment field"; - sigmatch_table[DETECT_HTTP2_WINDOW].url = "/rules/http2-keywords.html#window"; - sigmatch_table[DETECT_HTTP2_WINDOW].Match = NULL; - sigmatch_table[DETECT_HTTP2_WINDOW].AppLayerTxMatch = DetectHTTP2windowMatch; - sigmatch_table[DETECT_HTTP2_WINDOW].Setup = DetectHTTP2windowSetup; - sigmatch_table[DETECT_HTTP2_WINDOW].Free = DetectHTTP2windowFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_HTTP2_WINDOW].RegisterTests = DetectHTTP2windowRegisterTests; -#endif - - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].name = "http2.size_update"; - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].desc = "match on HTTP2 dynamic headers table size update"; - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].url = "/rules/http2-keywords.html#sizeupdate"; - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Match = NULL; - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].AppLayerTxMatch = DetectHTTP2sizeUpdateMatch; - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Setup = DetectHTTP2sizeUpdateSetup; - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Free = DetectHTTP2sizeUpdateFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_HTTP2_SIZEUPDATE].RegisterTests = DetectHTTP2sizeUpdateRegisterTests; -#endif - - sigmatch_table[DETECT_HTTP2_SETTINGS].name = "http2.settings"; - sigmatch_table[DETECT_HTTP2_SETTINGS].desc = "match on HTTP2 settings identifier and value fields"; - sigmatch_table[DETECT_HTTP2_SETTINGS].url = "/rules/http2-keywords.html#settings"; - sigmatch_table[DETECT_HTTP2_SETTINGS].Match = NULL; - sigmatch_table[DETECT_HTTP2_SETTINGS].AppLayerTxMatch = DetectHTTP2settingsMatch; - sigmatch_table[DETECT_HTTP2_SETTINGS].Setup = DetectHTTP2settingsSetup; - sigmatch_table[DETECT_HTTP2_SETTINGS].Free = DetectHTTP2settingsFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_HTTP2_SETTINGS].RegisterTests = DetectHTTP2settingsRegisterTests; -#endif - - sigmatch_table[DETECT_HTTP2_HEADERNAME].name = "http2.header_name"; - sigmatch_table[DETECT_HTTP2_HEADERNAME].desc = "sticky buffer to match on one HTTP2 header name"; - sigmatch_table[DETECT_HTTP2_HEADERNAME].url = "/rules/http2-keywords.html#header_name"; - sigmatch_table[DETECT_HTTP2_HEADERNAME].Setup = DetectHTTP2headerNameSetup; - sigmatch_table[DETECT_HTTP2_HEADERNAME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmHttp2HeaderNameRegister, NULL, - ALPROTO_HTTP2, HTTP2StateOpen); - DetectAppLayerInspectEngineRegister2("http2_header_name", - ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, HTTP2StateOpen, - DetectEngineInspectHttp2HeaderName, NULL); - DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOSERVER, 2, - PrefilterMpmHttp2HeaderNameRegister, NULL, - ALPROTO_HTTP2, HTTP2StateOpen); - DetectAppLayerInspectEngineRegister2("http2_header_name", - ALPROTO_HTTP2, SIG_FLAG_TOSERVER, HTTP2StateOpen, - DetectEngineInspectHttp2HeaderName, NULL); - DetectBufferTypeSupportsMultiInstance("http2_header_name"); - DetectBufferTypeSetDescriptionByName("http2_header_name", - "HTTP2 header name"); - g_http2_header_name_buffer_id = DetectBufferTypeGetByName("http2_header_name"); - - DetectAppLayerInspectEngineRegister2( - "http2", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - DetectAppLayerInspectEngineRegister2( - "http2", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); - - g_http2_match_buffer_id = DetectBufferTypeRegister("http2"); - return; -} - -/** - * \brief This function is used to match HTTP2 frame type rule option on a transaction with those passed via http2.frametype: - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) - -{ - uint8_t *detect = (uint8_t *)ctx; - - return rs_http2_tx_has_frametype(txv, flags, *detect); -} - -static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft) -{ - // first parse numeric value - if (ByteExtractStringUint8(ft, 10, (uint16_t)strlen(str), str) >= 0) { - return 1; - } - - // it it failed so far, parse string value from enumeration - int r = rs_http2_parse_frametype(str); - if (r >= 0 && r <= UINT8_MAX) { - *ft = (uint8_t)r; - return 1; - } - - return 0; -} - -/** - * \brief this function is used to attach the parsed http2.frametype data into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param str pointer to the user provided http2.frametype options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - uint8_t frame_type; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) - return -1; - - if (!DetectHTTP2FuncParseFrameType(str, &frame_type)) { - SCLogError("Invalid argument \"%s\" supplied to http2.frametype keyword.", str); - return -1; - } - - uint8_t *http2ft = SCCalloc(1, sizeof(uint8_t)); - if (http2ft == NULL) - return -1; - *http2ft = frame_type; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_FRAMETYPE, (SigMatchCtx *)http2ft, - g_http2_match_buffer_id) == NULL) { - DetectHTTP2frametypeFree(NULL, http2ft); - return -1; - } - - return 0; -} - -/** - * \brief this function will free memory associated with uint8_t - * - * \param ptr pointer to uint8_t - */ -void DetectHTTP2frametypeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCFree(ptr); -} - -/** - * \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.errorcode: - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) - -{ - uint32_t *detect = (uint32_t *)ctx; - - return rs_http2_tx_has_errorcode(txv, flags, *detect); - //TODOask handle negation rules -} - -static int DetectHTTP2FuncParseErrorCode(const char *str, uint32_t *ec) -{ - // first parse numeric value - if (ByteExtractStringUint32(ec, 10, (uint16_t)strlen(str), str) >= 0) { - return 1; - } - - // it it failed so far, parse string value from enumeration - int r = rs_http2_parse_errorcode(str); - if (r >= 0) { - *ec = r; - return 1; - } - - return 0; -} - -/** - * \brief this function is used to attach the parsed http2.errorcode data into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param str pointer to the user provided http2.errorcode options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectHTTP2errorcodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - uint32_t error_code; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) - return -1; - - if (!DetectHTTP2FuncParseErrorCode(str, &error_code)) { - SCLogError("Invalid argument \"%s\" supplied to http2.errorcode keyword.", str); - return -1; - } - - uint32_t *http2ec = SCCalloc(1, sizeof(uint32_t)); - if (http2ec == NULL) - return -1; - *http2ec = error_code; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_ERRORCODE, (SigMatchCtx *)http2ec, - g_http2_match_buffer_id) == NULL) { - DetectHTTP2errorcodeFree(NULL, http2ec); - return -1; - } - - return 0; -} - -/** - * \brief this function will free memory associated with uint32_t - * - * \param ptr pointer to uint32_t - */ -void DetectHTTP2errorcodeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCFree(ptr); -} - -/** - * \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.priority: - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) - -{ - uint32_t nb = 0; - int value = rs_http2_tx_get_next_priority(txv, flags, nb); - const DetectU8Data *du8 = (const DetectU8Data *)ctx; - while (value >= 0) { - if (DetectU8Match((uint8_t)value, du8)) { - return 1; - } - nb++; - value = rs_http2_tx_get_next_priority(txv, flags, nb); - } - return 0; -} - -/** - * \brief this function is used to attach the parsed http2.priority data into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param str pointer to the user provided http2.priority options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectHTTP2prioritySetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) - return -1; - - DetectU8Data *prio = DetectU8Parse(str); - if (prio == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_PRIORITY, (SigMatchCtx *)prio, - g_http2_match_buffer_id) == NULL) { - rs_detect_u8_free(prio); - return -1; - } - - return 0; -} - -/** - * \brief this function will free memory associated with uint32_t - * - * \param ptr pointer to DetectU8Data - */ -void DetectHTTP2priorityFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u8_free(ptr); -} - -/** - * \brief This function is used to match HTTP2 window rule option on a transaction with those passed via http2.window: - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) - -{ - uint32_t nb = 0; - int value = rs_http2_tx_get_next_window(txv, flags, nb); - const DetectU32Data *du32 = (const DetectU32Data *)ctx; - while (value >= 0) { - if (DetectU32Match(value, du32)) { - return 1; - } - nb++; - value = rs_http2_tx_get_next_window(txv, flags, nb); - } - return 0; -} - -/** - * \brief this function is used to attach the parsed http2.window data into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param str pointer to the user provided http2.window options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectHTTP2windowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) - return -1; - - DetectU32Data *wu = DetectU32Parse(str); - if (wu == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_WINDOW, (SigMatchCtx *)wu, - g_http2_match_buffer_id) == NULL) { - rs_detect_u32_free(wu); - return -1; - } - - return 0; -} - -/** - * \brief this function will free memory associated with uint32_t - * - * \param ptr pointer to DetectU8Data - */ -void DetectHTTP2windowFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} - -/** - * \brief This function is used to match HTTP2 size update rule option on a transaction with those passed via http2.size_update: - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) - -{ - return rs_http2_detect_sizeupdatectx_match(ctx, txv, flags); -} - -/** - * \brief this function is used to attach the parsed http2.size_update data into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param str pointer to the user provided http2.size_update options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectHTTP2sizeUpdateSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) - return -1; - - void *su = rs_detect_u64_parse(str); - if (su == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_SIZEUPDATE, (SigMatchCtx *)su, - g_http2_match_buffer_id) == NULL) { - DetectHTTP2settingsFree(NULL, su); - return -1; - } - - return 0; -} - -/** - * \brief this function will free memory associated with uint32_t - * - * \param ptr pointer to DetectU8Data - */ -void DetectHTTP2sizeUpdateFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u64_free(ptr); -} - -/** - * \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.settings: - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) - -{ - return rs_http2_detect_settingsctx_match(ctx, txv, flags); -} - -/** - * \brief this function is used to attach the parsed http2.settings data into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param str pointer to the user provided http2.settings options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectHTTP2settingsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) - return -1; - - void *http2set = rs_http2_detect_settingsctx_parse(str); - if (http2set == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_SETTINGS, (SigMatchCtx *)http2set, - g_http2_match_buffer_id) == NULL) { - DetectHTTP2settingsFree(NULL, http2set); - return -1; - } - - return 0; -} - -/** - * \brief this function will free memory associated with rust signature context - * - * \param ptr pointer to rust signature context - */ -void DetectHTTP2settingsFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_http2_detect_settingsctx_free(ptr); -} - -static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_http2_header_name_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) - return -1; - - return 0; -} - -static void PrefilterMpmHttp2HNameFree(void *ptr) -{ - SCFree(ptr); -} - -static InspectionBuffer *GetHttp2HNameData(DetectEngineThreadCtx *det_ctx, const uint8_t flags, - const DetectEngineTransforms *transforms, Flow *_f, const struct MpmListIdDataArgs *cbdata, - int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_http2_tx_get_header_name(cbdata->txv, flags, cbdata->local_id, &b, &b_len) != 1) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - if (b == NULL || b_len == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, b, b_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static void PrefilterTxHttp2HName(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - - while(1) { - // loop until we get a NULL - - struct MpmListIdDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = - GetHttp2HNameData(det_ctx, flags, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - //TODOask use PrefilterMpmListId elsewhere - PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp2HName, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmHttp2HNameFree, mpm_reg->name); -} - -static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - //TODOask use MpmListIdDataArgs elsewhere - struct MpmListIdDataArgs cbdata = { local_id, txv, }; - InspectionBuffer *buffer = - GetHttp2HNameData(det_ctx, flags, transforms, f, &cbdata, engine->sm_list); - - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -#ifdef UNITTESTS -#include "tests/detect-http2.c" -#endif diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 301b2e76830f..a937e4160039 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -34,17 +34,17 @@ #include "detect-icmp-id.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" #define PARSE_REGEX "^\\s*(\"\\s*)?([0-9]+)(\\s*\")?\\s*$" static DetectParseRegex parse_regex; -static int DetectIcmpIdMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectIcmpIdMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectIcmpIdSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectIcmpIdRegisterTests(void); @@ -56,7 +56,7 @@ static bool PrefilterIcmpIdIsPrefilterable(const Signature *s); /** * \brief Registration function for icode: icmp_id */ -void DetectIcmpIdRegister (void) +void DetectIcmpIdRegister(void) { sigmatch_table[DETECT_ICMP_ID].name = "icmp_id"; sigmatch_table[DETECT_ICMP_ID].desc = "check for a ICMP ID"; @@ -80,7 +80,7 @@ static inline bool GetIcmpId(Packet *p, uint16_t *id) uint16_t pid; if (PKT_IS_ICMPV4(p)) { - switch (ICMPV4_GET_TYPE(p)){ + switch (ICMPV4_GET_TYPE(p)) { case ICMP_ECHOREPLY: case ICMP_ECHO: case ICMP_TIMESTAMP: @@ -89,9 +89,9 @@ static inline bool GetIcmpId(Packet *p, uint16_t *id) case ICMP_INFO_REPLY: case ICMP_ADDRESS: case ICMP_ADDRESSREPLY: - SCLogDebug("ICMPV4_GET_ID(p) %"PRIu16" (network byte order), " - "%"PRIu16" (host byte order)", ICMPV4_GET_ID(p), - SCNtohs(ICMPV4_GET_ID(p))); + SCLogDebug("ICMPV4_GET_ID(p) %" PRIu16 " (network byte order), " + "%" PRIu16 " (host byte order)", + ICMPV4_GET_ID(p), SCNtohs(ICMPV4_GET_ID(p))); pid = ICMPV4_GET_ID(p); break; @@ -103,9 +103,9 @@ static inline bool GetIcmpId(Packet *p, uint16_t *id) switch (ICMPV6_GET_TYPE(p)) { case ICMP6_ECHO_REQUEST: case ICMP6_ECHO_REPLY: - SCLogDebug("ICMPV6_GET_ID(p) %"PRIu16" (network byte order), " - "%"PRIu16" (host byte order)", ICMPV6_GET_ID(p), - SCNtohs(ICMPV6_GET_ID(p))); + SCLogDebug("ICMPV6_GET_ID(p) %" PRIu16 " (network byte order), " + "%" PRIu16 " (host byte order)", + ICMPV6_GET_ID(p), SCNtohs(ICMPV6_GET_ID(p))); pid = ICMPV6_GET_ID(p); break; @@ -133,8 +133,8 @@ static inline bool GetIcmpId(Packet *p, uint16_t *id) * \retval 0 no match * \retval 1 match */ -static int DetectIcmpIdMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectIcmpIdMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { uint16_t pid; @@ -157,10 +157,10 @@ static int DetectIcmpIdMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval iid pointer to DetectIcmpIdData on success * \retval NULL on failure */ -static DetectIcmpIdData *DetectIcmpIdParse (DetectEngineCtx *de_ctx, const char *icmpidstr) +static DetectIcmpIdData *DetectIcmpIdParse(DetectEngineCtx *de_ctx, const char *icmpidstr) { DetectIcmpIdData *iid = NULL; - char *substr[3] = {NULL, NULL, NULL}; + char *substr[3] = { NULL, NULL, NULL }; int res = 0; size_t pcre2_len; @@ -179,7 +179,7 @@ static DetectIcmpIdData *DetectIcmpIdParse (DetectEngineCtx *de_ctx, const char SCLogError("pcre2_substring_get_bynumber failed"); goto error; } - substr[i-1] = (char *)str_ptr; + substr[i - 1] = (char *)str_ptr; } iid = SCMalloc(sizeof(DetectIcmpIdData)); @@ -187,7 +187,7 @@ static DetectIcmpIdData *DetectIcmpIdParse (DetectEngineCtx *de_ctx, const char goto error; iid->id = 0; - if (substr[0]!= NULL && strlen(substr[0]) != 0) { + if (substr[0] != NULL && strlen(substr[0]) != 0) { if (substr[2] == NULL) { SCLogError("Missing close quote in input"); goto error; @@ -223,9 +223,9 @@ static DetectIcmpIdData *DetectIcmpIdParse (DetectEngineCtx *de_ctx, const char if (substr[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)substr[i]); } - if (iid != NULL) DetectIcmpIdFree(de_ctx, iid); + if (iid != NULL) + DetectIcmpIdFree(de_ctx, iid); return NULL; - } /** @@ -238,12 +238,13 @@ static DetectIcmpIdData *DetectIcmpIdParse (DetectEngineCtx *de_ctx, const char * \retval 0 on Success * \retval -1 on Failure */ -static int DetectIcmpIdSetup (DetectEngineCtx *de_ctx, Signature *s, const char *icmpidstr) +static int DetectIcmpIdSetup(DetectEngineCtx *de_ctx, Signature *s, const char *icmpidstr) { DetectIcmpIdData *iid = NULL; iid = DetectIcmpIdParse(de_ctx, icmpidstr); - if (iid == NULL) goto error; + if (iid == NULL) + goto error; if (SigMatchAppendSMToList( de_ctx, s, DETECT_ICMP_ID, (SigMatchCtx *)iid, DETECT_SM_LIST_MATCH) == NULL) { @@ -257,7 +258,6 @@ static int DetectIcmpIdSetup (DetectEngineCtx *de_ctx, Signature *s, const char if (iid != NULL) DetectIcmpIdFree(de_ctx, iid); return -1; - } /** @@ -265,7 +265,7 @@ static int DetectIcmpIdSetup (DetectEngineCtx *de_ctx, Signature *s, const char * * \param ptr pointer to DetectIcmpIdData */ -void DetectIcmpIdFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectIcmpIdFree(DetectEngineCtx *de_ctx, void *ptr) { DetectIcmpIdData *iid = (DetectIcmpIdData *)ptr; SCFree(iid); @@ -273,8 +273,7 @@ void DetectIcmpIdFree (DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketIcmpIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketIcmpIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; @@ -282,22 +281,19 @@ PrefilterPacketIcmpIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void if (!GetIcmpId(p, &pid)) return; - if (pid == ctx->v1.u16[0]) - { + if (pid == ctx->v1.u16[0]) { SCLogDebug("packet matches ICMP ID %u", ctx->v1.u16[0]); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketIcmpIdSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketIcmpIdSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectIcmpIdData *a = smctx; v->u16[0] = a->id; } -static bool -PrefilterPacketIcmpIdCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketIcmpIdCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectIcmpIdData *a = smctx; if (v.u16[0] == a->id) @@ -307,16 +303,14 @@ PrefilterPacketIcmpIdCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupIcmpId(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMP_ID, - PrefilterPacketIcmpIdSet, - PrefilterPacketIcmpIdCompare, - PrefilterPacketIcmpIdMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMP_ID, PrefilterPacketIcmpIdSet, + PrefilterPacketIcmpIdCompare, PrefilterPacketIcmpIdMatch); } static bool PrefilterIcmpIdIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ICMP_ID: return true; @@ -332,7 +326,7 @@ static bool PrefilterIcmpIdIsPrefilterable(const Signature *s) /** * \test DetectIcmpIdParseTest01 is a test for setting a valid icmp_id value */ -static int DetectIcmpIdParseTest01 (void) +static int DetectIcmpIdParseTest01(void) { DetectIcmpIdData *iid = DetectIcmpIdParse(NULL, "300"); FAIL_IF_NULL(iid); @@ -345,7 +339,7 @@ static int DetectIcmpIdParseTest01 (void) * \test DetectIcmpIdParseTest02 is a test for setting a valid icmp_id value * with spaces all around */ -static int DetectIcmpIdParseTest02 (void) +static int DetectIcmpIdParseTest02(void) { DetectIcmpIdData *iid = DetectIcmpIdParse(NULL, " 300 "); FAIL_IF_NULL(iid); @@ -358,7 +352,7 @@ static int DetectIcmpIdParseTest02 (void) * \test DetectIcmpIdParseTest03 is a test for setting a valid icmp_id value * with quotation marks */ -static int DetectIcmpIdParseTest03 (void) +static int DetectIcmpIdParseTest03(void) { DetectIcmpIdData *iid = DetectIcmpIdParse(NULL, "\"300\""); FAIL_IF_NULL(iid); @@ -371,7 +365,7 @@ static int DetectIcmpIdParseTest03 (void) * \test DetectIcmpIdParseTest04 is a test for setting a valid icmp_id value * with quotation marks and spaces all around */ -static int DetectIcmpIdParseTest04 (void) +static int DetectIcmpIdParseTest04(void) { DetectIcmpIdData *iid = DetectIcmpIdParse(NULL, " \" 300 \""); FAIL_IF_NULL(iid); @@ -384,7 +378,7 @@ static int DetectIcmpIdParseTest04 (void) * \test DetectIcmpIdParseTest05 is a test for setting an invalid icmp_id * value with missing quotation marks */ -static int DetectIcmpIdParseTest05 (void) +static int DetectIcmpIdParseTest05(void) { DetectIcmpIdData *iid = DetectIcmpIdParse(NULL, "\"300"); FAIL_IF_NOT_NULL(iid); @@ -396,7 +390,7 @@ static int DetectIcmpIdParseTest05 (void) * icmp_id keyword by creating 2 rules and matching a crafted packet * against them. Only the first one shall trigger. */ -static int DetectIcmpIdMatchTest01 (void) +static int DetectIcmpIdMatchTest01(void) { int result = 0; Packet *p = NULL; @@ -450,7 +444,6 @@ static int DetectIcmpIdMatchTest01 (void) UTHFreePackets(&p, 1); end: return result; - } /** @@ -459,16 +452,18 @@ static int DetectIcmpIdMatchTest01 (void) * against them. The packet is an ICMP packet with no "id" field, * therefore the rule should not trigger. */ -static int DetectIcmpIdMatchTest02 (void) +static int DetectIcmpIdMatchTest02(void) { int result = 0; + // clang-format off uint8_t raw_icmpv4[] = { 0x0b, 0x00, 0x8a, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x14, 0x25, 0x0c, 0x00, 0x00, 0xff, 0x11, 0x00, 0x00, 0x85, 0x64, 0xea, 0x5b, 0x51, 0xa6, 0xbb, 0x35, 0x59, 0x8a, 0x5a, 0xe2, 0x00, 0x14, 0x00, 0x00 }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -530,7 +525,7 @@ static int DetectIcmpIdMatchTest02 (void) return result; } -static void DetectIcmpIdRegisterTests (void) +static void DetectIcmpIdRegisterTests(void) { UtRegisterTest("DetectIcmpIdParseTest01", DetectIcmpIdParseTest01); UtRegisterTest("DetectIcmpIdParseTest02", DetectIcmpIdParseTest02); diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index ca32d2cec7ac..f7d81e5ceea7 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -33,17 +33,17 @@ #include "detect-icmp-seq.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" #define PARSE_REGEX "^\\s*(\"\\s*)?([0-9]+)(\\s*\")?\\s*$" static DetectParseRegex parse_regex; -static int DetectIcmpSeqMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectIcmpSeqMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectIcmpSeqSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectIcmpSeqRegisterTests(void); @@ -55,7 +55,7 @@ static bool PrefilterIcmpSeqIsPrefilterable(const Signature *s); /** * \brief Registration function for icmp_seq */ -void DetectIcmpSeqRegister (void) +void DetectIcmpSeqRegister(void) { sigmatch_table[DETECT_ICMP_SEQ].name = "icmp_seq"; sigmatch_table[DETECT_ICMP_SEQ].desc = "check for a ICMP sequence number"; @@ -80,7 +80,7 @@ static inline bool GetIcmpSeq(Packet *p, uint16_t *seq) return false; if (PKT_IS_ICMPV4(p)) { - switch (ICMPV4_GET_TYPE(p)){ + switch (ICMPV4_GET_TYPE(p)) { case ICMP_ECHOREPLY: case ICMP_ECHO: case ICMP_TIMESTAMP: @@ -89,9 +89,9 @@ static inline bool GetIcmpSeq(Packet *p, uint16_t *seq) case ICMP_INFO_REPLY: case ICMP_ADDRESS: case ICMP_ADDRESSREPLY: - SCLogDebug("ICMPV4_GET_SEQ(p) %"PRIu16" (network byte order), " - "%"PRIu16" (host byte order)", ICMPV4_GET_SEQ(p), - SCNtohs(ICMPV4_GET_SEQ(p))); + SCLogDebug("ICMPV4_GET_SEQ(p) %" PRIu16 " (network byte order), " + "%" PRIu16 " (host byte order)", + ICMPV4_GET_SEQ(p), SCNtohs(ICMPV4_GET_SEQ(p))); seqn = ICMPV4_GET_SEQ(p); break; @@ -104,9 +104,9 @@ static inline bool GetIcmpSeq(Packet *p, uint16_t *seq) switch (ICMPV6_GET_TYPE(p)) { case ICMP6_ECHO_REQUEST: case ICMP6_ECHO_REPLY: - SCLogDebug("ICMPV6_GET_SEQ(p) %"PRIu16" (network byte order), " - "%"PRIu16" (host byte order)", ICMPV6_GET_SEQ(p), - SCNtohs(ICMPV6_GET_SEQ(p))); + SCLogDebug("ICMPV6_GET_SEQ(p) %" PRIu16 " (network byte order), " + "%" PRIu16 " (host byte order)", + ICMPV6_GET_SEQ(p), SCNtohs(ICMPV6_GET_SEQ(p))); seqn = ICMPV6_GET_SEQ(p); break; @@ -134,8 +134,8 @@ static inline bool GetIcmpSeq(Packet *p, uint16_t *seq) * \retval 0 no match * \retval 1 match */ -static int DetectIcmpSeqMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectIcmpSeqMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { uint16_t seqn; @@ -158,10 +158,10 @@ static int DetectIcmpSeqMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval iseq pointer to DetectIcmpSeqData on success * \retval NULL on failure */ -static DetectIcmpSeqData *DetectIcmpSeqParse (DetectEngineCtx *de_ctx, const char *icmpseqstr) +static DetectIcmpSeqData *DetectIcmpSeqParse(DetectEngineCtx *de_ctx, const char *icmpseqstr) { DetectIcmpSeqData *iseq = NULL; - char *substr[3] = {NULL, NULL, NULL}; + char *substr[3] = { NULL, NULL, NULL }; int res = 0; size_t pcre2_len; int i; @@ -180,7 +180,7 @@ static DetectIcmpSeqData *DetectIcmpSeqParse (DetectEngineCtx *de_ctx, const cha SCLogError("pcre2_substring_get_bynumber failed"); goto error; } - substr[i-1] = (char *)str_ptr; + substr[i - 1] = (char *)str_ptr; } iseq = SCMalloc(sizeof(DetectIcmpSeqData)); @@ -226,9 +226,9 @@ static DetectIcmpSeqData *DetectIcmpSeqParse (DetectEngineCtx *de_ctx, const cha if (substr[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)substr[i]); } - if (iseq != NULL) DetectIcmpSeqFree(de_ctx, iseq); + if (iseq != NULL) + DetectIcmpSeqFree(de_ctx, iseq); return NULL; - } /** @@ -241,12 +241,13 @@ static DetectIcmpSeqData *DetectIcmpSeqParse (DetectEngineCtx *de_ctx, const cha * \retval 0 on Success * \retval -1 on Failure */ -static int DetectIcmpSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char *icmpseqstr) +static int DetectIcmpSeqSetup(DetectEngineCtx *de_ctx, Signature *s, const char *icmpseqstr) { DetectIcmpSeqData *iseq = NULL; iseq = DetectIcmpSeqParse(de_ctx, icmpseqstr); - if (iseq == NULL) goto error; + if (iseq == NULL) + goto error; if (SigMatchAppendSMToList( de_ctx, s, DETECT_ICMP_SEQ, (SigMatchCtx *)iseq, DETECT_SM_LIST_MATCH) == NULL) { @@ -259,7 +260,6 @@ static int DetectIcmpSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char if (iseq != NULL) DetectIcmpSeqFree(de_ctx, iseq); return -1; - } /** @@ -267,7 +267,7 @@ static int DetectIcmpSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char * * \param ptr pointer to DetectIcmpSeqData */ -void DetectIcmpSeqFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectIcmpSeqFree(DetectEngineCtx *de_ctx, void *ptr) { DetectIcmpSeqData *iseq = (DetectIcmpSeqData *)ptr; SCFree(iseq); @@ -275,8 +275,8 @@ void DetectIcmpSeqFree (DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketIcmpSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketIcmpSeqMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; @@ -285,22 +285,19 @@ PrefilterPacketIcmpSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const voi if (!GetIcmpSeq(p, &seqn)) return; - if (seqn == ctx->v1.u16[0]) - { + if (seqn == ctx->v1.u16[0]) { SCLogDebug("packet matches ICMP SEQ %u", ctx->v1.u16[0]); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketIcmpSeqSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketIcmpSeqSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectIcmpSeqData *a = smctx; v->u16[0] = a->seq; } -static bool -PrefilterPacketIcmpSeqCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketIcmpSeqCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectIcmpSeqData *a = smctx; if (v.u16[0] == a->seq) @@ -310,16 +307,14 @@ PrefilterPacketIcmpSeqCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupIcmpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMP_SEQ, - PrefilterPacketIcmpSeqSet, - PrefilterPacketIcmpSeqCompare, - PrefilterPacketIcmpSeqMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMP_SEQ, PrefilterPacketIcmpSeqSet, + PrefilterPacketIcmpSeqCompare, PrefilterPacketIcmpSeqMatch); } static bool PrefilterIcmpSeqIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ICMP_SEQ: return true; @@ -336,7 +331,7 @@ static bool PrefilterIcmpSeqIsPrefilterable(const Signature *s) /** * \test DetectIcmpSeqParseTest01 is a test for setting a valid icmp_seq value */ -static int DetectIcmpSeqParseTest01 (void) +static int DetectIcmpSeqParseTest01(void) { DetectIcmpSeqData *iseq = NULL; iseq = DetectIcmpSeqParse(NULL, "300"); @@ -350,7 +345,7 @@ static int DetectIcmpSeqParseTest01 (void) * \test DetectIcmpSeqParseTest02 is a test for setting a valid icmp_seq value * with spaces all around */ -static int DetectIcmpSeqParseTest02 (void) +static int DetectIcmpSeqParseTest02(void) { DetectIcmpSeqData *iseq = NULL; iseq = DetectIcmpSeqParse(NULL, " 300 "); @@ -363,14 +358,14 @@ static int DetectIcmpSeqParseTest02 (void) /** * \test DetectIcmpSeqParseTest03 is a test for setting an invalid icmp_seq value */ -static int DetectIcmpSeqParseTest03 (void) +static int DetectIcmpSeqParseTest03(void) { DetectIcmpSeqData *iseq = DetectIcmpSeqParse(NULL, "badc"); FAIL_IF_NOT_NULL(iseq); PASS; } -static void DetectIcmpSeqRegisterTests (void) +static void DetectIcmpSeqRegisterTests(void) { UtRegisterTest("DetectIcmpSeqParseTest01", DetectIcmpSeqParseTest01); UtRegisterTest("DetectIcmpSeqParseTest02", DetectIcmpSeqParseTest02); diff --git a/src/detect-icmp-seq.h b/src/detect-icmp-seq.h index e148177b8dad..569552d65702 100644 --- a/src/detect-icmp-seq.h +++ b/src/detect-icmp-seq.h @@ -13,7 +13,7 @@ * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. -*/ + */ /** * \file diff --git a/src/detect-icmpv6-mtu.c b/src/detect-icmpv6-mtu.c index f84e484e90ae..2ac3c7577948 100644 --- a/src/detect-icmpv6-mtu.c +++ b/src/detect-icmpv6-mtu.c @@ -31,12 +31,12 @@ #include "detect-engine-uint.h" /* prototypes */ -static int DetectICMPv6mtuMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectICMPv6mtuSetup (DetectEngineCtx *, Signature *, const char *); -void DetectICMPv6mtuFree (DetectEngineCtx *de_ctx, void *); +static int DetectICMPv6mtuMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectICMPv6mtuSetup(DetectEngineCtx *, Signature *, const char *); +void DetectICMPv6mtuFree(DetectEngineCtx *de_ctx, void *); #ifdef UNITTESTS -void DetectICMPv6mtuRegisterTests (void); +void DetectICMPv6mtuRegisterTests(void); #endif static int PrefilterSetupIcmpv6mtu(DetectEngineCtx *de_ctx, SigGroupHead *sgh); static bool PrefilterIcmpv6mtuIsPrefilterable(const Signature *s); @@ -76,7 +76,8 @@ static inline int DetectICMPv6mtuGetValue(Packet *p, uint32_t *picmpv6mtu) } /** - * \brief This function is used to match ICMPV6 MTU rule option on a packet with those passed via icmpv6.mtu: + * \brief This function is used to match ICMPV6 MTU rule option on a packet with those passed via + * icmpv6.mtu: * * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet @@ -86,8 +87,8 @@ static inline int DetectICMPv6mtuGetValue(Packet *p, uint32_t *picmpv6mtu) * \retval 0 no match * \retval 1 match */ -static int DetectICMPv6mtuMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectICMPv6mtuMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { uint32_t picmpv6mtu; if (DetectICMPv6mtuGetValue(p, &picmpv6mtu) == 0) { @@ -108,7 +109,7 @@ static int DetectICMPv6mtuMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectICMPv6mtuSetup (DetectEngineCtx *de_ctx, Signature *s, const char *icmpv6mtustr) +static int DetectICMPv6mtuSetup(DetectEngineCtx *de_ctx, Signature *s, const char *icmpv6mtustr) { DetectU32Data *icmpv6mtud = DetectU32Parse(icmpv6mtustr); if (icmpv6mtud == NULL) @@ -137,8 +138,8 @@ void DetectICMPv6mtuFree(DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketIcmpv6mtuMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketIcmpv6mtuMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { uint32_t picmpv6mtu; if (DetectICMPv6mtuGetValue(p, &picmpv6mtu) == 0) { @@ -157,8 +158,7 @@ PrefilterPacketIcmpv6mtuMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const v du32.mode = ctx->v1.u8[0]; du32.arg1 = ctx->v1.u32[1]; du32.arg2 = ctx->v1.u32[2]; - if (DetectU32Match(picmpv6mtu, &du32)) - { + if (DetectU32Match(picmpv6mtu, &du32)) { SCLogDebug("packet matches icmpv6.mtu/hl %u", picmpv6mtu); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } @@ -166,10 +166,8 @@ PrefilterPacketIcmpv6mtuMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const v static int PrefilterSetupIcmpv6mtu(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMPV6MTU, - PrefilterPacketU32Set, - PrefilterPacketU32Compare, - PrefilterPacketIcmpv6mtuMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMPV6MTU, PrefilterPacketU32Set, + PrefilterPacketU32Compare, PrefilterPacketIcmpv6mtuMatch); } static bool PrefilterIcmpv6mtuIsPrefilterable(const Signature *s) diff --git a/src/detect-icmpv6hdr.c b/src/detect-icmpv6hdr.c index 0d990e110866..941775c1bdde 100644 --- a/src/detect-icmpv6hdr.c +++ b/src/detect-icmpv6hdr.c @@ -32,12 +32,12 @@ #include "detect-engine-content-inspection.h" #include "detect-fast-pattern.h" #include "detect-icmpv6hdr.h" -#include "util-validate.h" +#include "util/validate.h" /* prototypes */ -static int DetectICMPv6hdrSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectICMPv6hdrSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS -void DetectICMPv6hdrRegisterTests (void); +void DetectICMPv6hdrRegisterTests(void); #endif static int g_icmpv6hdr_buffer_id = 0; @@ -66,8 +66,7 @@ void DetectICMPv6hdrRegister(void) DetectPktMpmRegister("icmpv6.hdr", 2, PrefilterGenericMpmPktRegister, GetData); - DetectPktInspectEngineRegister("icmpv6.hdr", GetData, - DetectEngineInspectPktBufferGeneric); + DetectPktInspectEngineRegister("icmpv6.hdr", GetData, DetectEngineInspectPktBufferGeneric); return; } @@ -82,7 +81,7 @@ void DetectICMPv6hdrRegister(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectICMPv6hdrSetup (DetectEngineCtx *de_ctx, Signature *s, const char *_unused) +static int DetectICMPv6hdrSetup(DetectEngineCtx *de_ctx, Signature *s, const char *_unused) { // ICMPv6 comes only with IPv6 s->proto.flags |= DETECT_PROTO_IPV6; @@ -110,10 +109,8 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, return NULL; } if (((uint8_t *)p->icmpv6h + (ptrdiff_t)hlen) > - ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) - { - SCLogDebug("data out of range: %p > %p", - ((uint8_t *)p->icmpv6h + (ptrdiff_t)hlen), + ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) { + SCLogDebug("data out of range: %p > %p", ((uint8_t *)p->icmpv6h + (ptrdiff_t)hlen), ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))); SCReturnPtr(NULL, "InspectionBuffer"); } diff --git a/src/detect-icmpv6hdr.h b/src/detect-icmpv6hdr.h index 18e91ae3c3c0..ad47f6395d98 100644 --- a/src/detect-icmpv6hdr.h +++ b/src/detect-icmpv6hdr.h @@ -26,4 +26,4 @@ void DetectICMPv6hdrRegister(void); -#endif /* _DETECT_ICMPV6HDR_H */ +#endif /* _DETECT_ICMPV6HDR_H */ diff --git a/src/detect-icode.c b/src/detect-icode.c index 1e7d1cc060af..b39b630e86c6 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -34,17 +34,17 @@ #include "detect-icode.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" /** *\brief Regex for parsing our icode options */ -static int DetectICodeMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectICodeMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectICodeSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectICodeRegisterTests(void); @@ -57,7 +57,7 @@ static bool PrefilterICodeIsPrefilterable(const Signature *s); /** * \brief Registration function for icode: keyword */ -void DetectICodeRegister (void) +void DetectICodeRegister(void) { sigmatch_table[DETECT_ICODE].name = "icode"; sigmatch_table[DETECT_ICODE].desc = "match on specific ICMP id-value"; @@ -84,8 +84,8 @@ void DetectICodeRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectICodeMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectICodeMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -120,7 +120,8 @@ static int DetectICodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *i DetectU8Data *icd = NULL; icd = DetectU8Parse(icodestr); - if (icd == NULL) goto error; + if (icd == NULL) + goto error; if (SigMatchAppendSMToList(de_ctx, s, DETECT_ICODE, (SigMatchCtx *)icd, DETECT_SM_LIST_MATCH) == NULL) { @@ -148,8 +149,7 @@ void DetectICodeFree(DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx) +static void PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { if (PKT_IS_PSEUDOPKT(p)) { SCReturn; @@ -181,7 +181,7 @@ static int PrefilterSetupICode(DetectEngineCtx *de_ctx, SigGroupHead *sgh) static bool PrefilterICodeIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ICODE: return true; diff --git a/src/detect-id.c b/src/detect-id.c index 6725b7c1367e..dce44a94fbcb 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -36,21 +36,20 @@ #include "flow.h" #include "flow-var.h" -#include "util-debug.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" /** * \brief Regex for parsing "id" option, matching number or "number" */ -#define PARSE_REGEX "^\\s*([0-9]{1,5}|\"[0-9]{1,5}\")\\s*$" +#define PARSE_REGEX "^\\s*([0-9]{1,5}|\"[0-9]{1,5}\")\\s*$" static DetectParseRegex parse_regex; -static int DetectIdMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectIdSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectIdMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectIdSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectIdRegisterTests(void); #endif @@ -62,14 +61,14 @@ static bool PrefilterIdIsPrefilterable(const Signature *s); /** * \brief Registration function for keyword: id */ -void DetectIdRegister (void) +void DetectIdRegister(void) { sigmatch_table[DETECT_ID].name = "id"; sigmatch_table[DETECT_ID].desc = "match on a specific IP ID value"; sigmatch_table[DETECT_ID].url = "/rules/header-keywords.html#id"; sigmatch_table[DETECT_ID].Match = DetectIdMatch; sigmatch_table[DETECT_ID].Setup = DetectIdSetup; - sigmatch_table[DETECT_ID].Free = DetectIdFree; + sigmatch_table[DETECT_ID].Free = DetectIdFree; #ifdef UNITTESTS sigmatch_table[DETECT_ID].RegisterTests = DetectIdRegisterTests; #endif @@ -90,8 +89,8 @@ void DetectIdRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectIdMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectIdMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectIdData *id_d = (const DetectIdData *)ctx; @@ -103,8 +102,7 @@ static int DetectIdMatch (DetectEngineThreadCtx *det_ctx, Packet *p, } if (id_d->id == IPV4_GET_IPID(p)) { - SCLogDebug("IPV4 Proto and matched with ip_id: %u.\n", - id_d->id); + SCLogDebug("IPV4 Proto and matched with ip_id: %u.\n", id_d->id); return 1; } @@ -119,7 +117,7 @@ static int DetectIdMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval id_d pointer to DetectIdData on success * \retval NULL on failure */ -static DetectIdData *DetectIdParse (const char *idstr) +static DetectIdData *DetectIdParse(const char *idstr) { uint16_t temp; DetectIdData *id_d = NULL; @@ -147,8 +145,7 @@ static DetectIdData *DetectIdParse (const char *idstr) tmp_str = copy_str; /* Let's see if we need to scape "'s */ - if (tmp_str[0] == '"') - { + if (tmp_str[0] == '"') { tmp_str[strlen(tmp_str) - 1] = '\0'; tmp_str += 1; } @@ -188,7 +185,7 @@ static DetectIdData *DetectIdParse (const char *idstr) * \retval 0 on Success * \retval -1 on Failure */ -int DetectIdSetup (DetectEngineCtx *de_ctx, Signature *s, const char *idstr) +int DetectIdSetup(DetectEngineCtx *de_ctx, Signature *s, const char *idstr) { DetectIdData *id_d = NULL; @@ -220,8 +217,7 @@ void DetectIdFree(DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; @@ -232,22 +228,19 @@ PrefilterPacketIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pe if (!PrefilterPacketHeaderExtraMatch(ctx, p)) return; - if (IPV4_GET_IPID(p) == ctx->v1.u16[0]) - { + if (IPV4_GET_IPID(p) == ctx->v1.u16[0]) { SCLogDebug("packet matches IP id %u", ctx->v1.u16[0]); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketIdSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketIdSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectIdData *a = smctx; v->u16[0] = a->id; } -static bool -PrefilterPacketIdCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketIdCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectIdData *a = smctx; if (v.u16[0] == a->id) @@ -257,16 +250,14 @@ PrefilterPacketIdCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupId(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ID, - PrefilterPacketIdSet, - PrefilterPacketIdCompare, - PrefilterPacketIdMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ID, PrefilterPacketIdSet, + PrefilterPacketIdCompare, PrefilterPacketIdMatch); } static bool PrefilterIdIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ID: return true; @@ -281,7 +272,7 @@ static bool PrefilterIdIsPrefilterable(const Signature *s) * \test DetectIdTestParse01 is a test to make sure that we parse the "id" * option correctly when given valid id option */ -static int DetectIdTestParse01 (void) +static int DetectIdTestParse01(void) { DetectIdData *id_d = DetectIdParse(" 35402 "); @@ -298,7 +289,7 @@ static int DetectIdTestParse01 (void) * option correctly when given an invalid id option * it should return id_d = NULL */ -static int DetectIdTestParse02 (void) +static int DetectIdTestParse02(void) { DetectIdData *id_d = DetectIdParse("65537"); @@ -312,7 +303,7 @@ static int DetectIdTestParse02 (void) * option correctly when given an invalid id option * it should return id_d = NULL */ -static int DetectIdTestParse03 (void) +static int DetectIdTestParse03(void) { DetectIdData *id_d = DetectIdParse("12what?"); @@ -325,7 +316,7 @@ static int DetectIdTestParse03 (void) * \test DetectIdTestParse04 is a test to make sure that we parse the "id" * option correctly when given valid id option but wrapped with "'s */ -static int DetectIdTestParse04 (void) +static int DetectIdTestParse04(void) { /* yep, look if we trim blank spaces correctly and ignore "'s */ DetectIdData *id_d = DetectIdParse(" \"35402\" "); @@ -365,19 +356,19 @@ static int DetectIdTestMatch01(void) p[2]->ip4h->ip_id = htons(5101); const char *sigs[3]; - sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; id:1234; sid:1;)"; - sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; id:5678; sid:2;)"; - sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; id:5101; sid:3;)"; + sigs[0] = "alert ip any any -> any any (msg:\"Testing id 1\"; id:1234; sid:1;)"; + sigs[1] = "alert ip any any -> any any (msg:\"Testing id 2\"; id:5678; sid:2;)"; + sigs[2] = "alert ip any any -> any any (msg:\"Testing id 3\"; id:5101; sid:3;)"; - uint32_t sid[3] = {1, 2, 3}; + uint32_t sid[3] = { 1, 2, 3 }; - uint32_t results[3][3] = { - /* packet 0 match sid 1 but should not match sid 2 */ - {1, 0, 0}, - /* packet 1 should not match */ - {0, 1, 0}, - /* packet 2 should not match */ - {0, 0, 1} }; + uint32_t results[3][3] = { /* packet 0 match sid 1 but should not match sid 2 */ + { 1, 0, 0 }, + /* packet 1 should not match */ + { 0, 1, 0 }, + /* packet 2 should not match */ + { 0, 0, 1 } + }; FAIL_IF_NOT(UTHGenericTest(p, 3, sigs, sid, (uint32_t *)results, 3)); @@ -396,6 +387,5 @@ void DetectIdRegisterTests(void) UtRegisterTest("DetectIdTestParse03", DetectIdTestParse03); UtRegisterTest("DetectIdTestParse04", DetectIdTestParse04); UtRegisterTest("DetectIdTestMatch01", DetectIdTestMatch01); - } #endif /* UNITTESTS */ diff --git a/src/detect-id.h b/src/detect-id.h index 3198c9c31e0d..f5d58ee9fd04 100644 --- a/src/detect-id.h +++ b/src/detect-id.h @@ -24,16 +24,14 @@ #ifndef __DETECT_ID_H__ #define __DETECT_ID_H__ - #define DETECT_IPID_MIN 0 #define DETECT_IPID_MAX 65536 typedef struct DetectIdData_ { - uint16_t id; /** ip->id to match */ + uint16_t id; /** ip->id to match */ } DetectIdData; /* prototypes */ -void DetectIdRegister (void); +void DetectIdRegister(void); #endif /* __DETECT_ID_H__ */ - diff --git a/src/detect-ike-chosen-sa.c b/src/detect-ike-chosen-sa.c deleted file mode 100644 index 0ae8d400cba6..000000000000 --- a/src/detect-ike-chosen-sa.c +++ /dev/null @@ -1,275 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-chosen-sa.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -/** - * [ike.chosen_sa_attribute]:=; - */ - -// support the basic attributes, which are parsed as integer and life_duration, if variable length -// is 4 it is stored as integer too -#define PARSE_REGEX \ - "^\\s*(alg_enc|alg_hash|alg_auth|alg_dh|\ -sa_group_type|sa_life_type|sa_life_duration|alg_prf|sa_key_length|sa_field_size)\ -\\s*=\\s*([0-9]+)\\s*$" - -static DetectParseRegex parse_regex; - -typedef struct { - char *sa_type; - uint32_t sa_value; -} DetectIkeChosenSaData; - -static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *); -static int DetectIkeChosenSaSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeChosenSaFree(DetectEngineCtx *, void *); -static int g_ike_chosen_sa_buffer_id = 0; - -static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -void IKEChosenSaRegisterTests(void); - -/** - * \brief Registration function for ike.ChosenSa keyword. - */ -void DetectIkeChosenSaRegister(void) -{ - sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].name = "ike.chosen_sa_attribute"; - sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].desc = "match IKE chosen SA Attribute"; - sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].url = - "/rules/ike-keywords.html#ike-chosen_sa_attribute"; - sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].AppLayerTxMatch = DetectIkeChosenSaMatch; - sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].Setup = DetectIkeChosenSaSetup; - sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].Free = DetectIkeChosenSaFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_IKE_CHOSEN_SA].RegisterTests = IKEChosenSaRegisterTests; -#endif - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2("ike.chosen_sa_attribute", ALPROTO_IKE, SIG_FLAG_TOCLIENT, - 1, DetectEngineInspectGenericList, NULL); - - g_ike_chosen_sa_buffer_id = DetectBufferTypeGetByName("ike.chosen_sa_attribute"); -} - -/** - * \internal - * \brief Function to match SA attributes of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectIkeChosenSaData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - const DetectIkeChosenSaData *dd = (const DetectIkeChosenSaData *)ctx; - - uint32_t value; - if (!rs_ike_state_get_sa_attribute(txv, dd->sa_type, &value)) - SCReturnInt(0); - if (value == dd->sa_value) - SCReturnInt(1); - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to parse options passed via ike.chosen_sa_attribute keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectIkeChosenSaData on success. - * \retval NULL on failure. - */ -static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *rawstr) -{ - /* - * idea: do not implement one c file per type, invent an own syntax: - * ike.chosen_sa_attribute:"encryption_algorithm=4" - * ike.chosen_sa_attribute:"hash_algorithm=8" - */ - DetectIkeChosenSaData *dd = NULL; - int res = 0; - size_t pcre2len; - char attribute[100]; - char value[100]; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 3 || ret > 5) { - SCLogError( - "pcre match for ike.chosen_sa_attribute failed, should be: =, " - "but was: %s; error code %d", - rawstr, ret); - goto error; - } - - pcre2len = sizeof(attribute); - res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)attribute, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - pcre2len = sizeof(value); - res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)value, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - dd = SCCalloc(1, sizeof(DetectIkeChosenSaData)); - if (unlikely(dd == NULL)) - goto error; - - dd->sa_type = SCStrdup(attribute); - if (dd->sa_type == NULL) - goto error; - - if (ByteExtractStringUint32(&dd->sa_value, 10, strlen(value), value) <= 0) { - SCLogError("invalid input as arg " - "to ike.chosen_sa_attribute keyword"); - goto error; - } - - pcre2_match_data_free(match); - return dd; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (dd) { - if (dd->sa_type != NULL) - SCFree(dd->sa_type); - SCFree(dd); - } - return NULL; -} - -/** - * \brief Function to add the parsed IKE SA attribute query into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeChosenSaSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectIkeChosenSaData *dd = DetectIkeChosenSaParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_CHOSEN_SA, (SigMatchCtx *)dd, - g_ike_chosen_sa_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeChosenSaFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectIkeChosenSaData. - * - * \param de_ptr Pointer to DetectIkeChosenSaData. - */ -static void DetectIkeChosenSaFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectIkeChosenSaData *dd = (DetectIkeChosenSaData *)ptr; - if (dd == NULL) - return; - if (dd->sa_type != NULL) - SCFree(dd->sa_type); - - SCFree(ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS - -/** - * \test IKEChosenSaParserTest is a test for valid values - * - * \retval 1 on success - * \retval 0 on failure - */ -static int IKEChosenSaParserTest(void) -{ - DetectIkeChosenSaData *de = NULL; - de = DetectIkeChosenSaParse("alg_hash=2"); - - FAIL_IF_NULL(de); - FAIL_IF(de->sa_value != 2); - FAIL_IF(strcmp(de->sa_type, "alg_hash") != 0); - - DetectIkeChosenSaFree(NULL, de); - PASS; -} - -#endif /* UNITTESTS */ - -void IKEChosenSaRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("IKEChosenSaParserTest", IKEChosenSaParserTest); -#endif /* UNITTESTS */ -} diff --git a/src/detect-ike-exch-type.c b/src/detect-ike-exch-type.c deleted file mode 100644 index 38d4218d7faa..000000000000 --- a/src/detect-ike-exch-type.c +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-exch-type.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "detect-engine-uint.h" - -#include "rust-bindings.h" - -/** - * [ike.exchtype]:[<|>|<=|>=]; - */ - -static int DetectIkeExchTypeSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeExchTypeFree(DetectEngineCtx *, void *); -static int g_ike_exch_type_buffer_id = 0; - -static int DetectIkeExchTypeMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); - -/** - * \brief Registration function for ike.exchtype keyword. - */ -void DetectIkeExchTypeRegister(void) -{ - sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].name = "ike.exchtype"; - sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].desc = "match IKE exchange type"; - sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].url = "/rules/ike-keywords.html#ike-exchtype"; - sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].Match = NULL; - sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].AppLayerTxMatch = DetectIkeExchTypeMatch; - sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].Setup = DetectIkeExchTypeSetup; - sigmatch_table[DETECT_AL_IKE_EXCH_TYPE].Free = DetectIkeExchTypeFree; - - DetectAppLayerInspectEngineRegister2("ike.exchtype", ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("ike.exchtype", ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectGenericList, NULL); - - g_ike_exch_type_buffer_id = DetectBufferTypeGetByName("ike.exchtype"); -} - -/** - * \internal - * \brief Function to match exchange type of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectU8Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeExchTypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint8_t exch_type; - if (!rs_ike_state_get_exch_type(txv, &exch_type)) - SCReturnInt(0); - - const DetectU8Data *du8 = (const DetectU8Data *)ctx; - SCReturnInt(DetectU8Match(exch_type, du8)); -} - -/** - * \brief Function to add the parsed IKE exchange type field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeExchTypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectU8Data *ike_exch_type = DetectU8Parse(rawstr); - if (ike_exch_type == NULL) - return -1; - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_EXCH_TYPE, (SigMatchCtx *)ike_exch_type, - g_ike_exch_type_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeExchTypeFree(de_ctx, ike_exch_type); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU8Data. - * - * \param de_ptr Pointer to DetectU8Data. - */ -static void DetectIkeExchTypeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u8_free(ptr); -} diff --git a/src/detect-ike-key-exchange-payload-length.c b/src/detect-ike-key-exchange-payload-length.c deleted file mode 100644 index 4caad8038717..000000000000 --- a/src/detect-ike-key-exchange-payload-length.c +++ /dev/null @@ -1,146 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-key-exchange-payload-length.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "detect-engine-uint.h" - -#include "rust-bindings.h" - -/** - * [ike.key_exchange_payload_length]:[=|<|>|<=|>=]; - */ -static int DetectIkeKeyExchangePayloadLengthSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeKeyExchangePayloadLengthFree(DetectEngineCtx *, void *); -static int g_ike_key_exch_payload_length_buffer_id = 0; - -static int DetectIkeKeyExchangePayloadLengthMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, - void *, const Signature *, const SigMatchCtx *); - -/** - * \brief Registration function for ike.key_exchange_payload_length keyword. - */ -void DetectIkeKeyExchangePayloadLengthRegister(void) -{ - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].name = - "ike.key_exchange_payload_length"; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].desc = - "match IKE key exchange payload length"; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].url = - "/rules/ike-keywords.html#ike-key-exchange-payload-length"; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].AppLayerTxMatch = - DetectIkeKeyExchangePayloadLengthMatch; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].Setup = - DetectIkeKeyExchangePayloadLengthSetup; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].Free = - DetectIkeKeyExchangePayloadLengthFree; - - DetectAppLayerInspectEngineRegister2("ike.key_exchange_payload_length", ALPROTO_IKE, - SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("ike.key_exchange_payload_length", ALPROTO_IKE, - SIG_FLAG_TOCLIENT, 1, DetectEngineInspectGenericList, NULL); - - g_ike_key_exch_payload_length_buffer_id = - DetectBufferTypeGetByName("ike.key_exchange_payload_length"); -} - -/** - * \internal - * \brief Function to match key exchange payload length of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeKeyExchangePayloadLengthMatch(DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint32_t length; - if (!rs_ike_state_get_key_exchange_payload_length(txv, &length)) - SCReturnInt(0); - const DetectU32Data *du32 = (const DetectU32Data *)ctx; - return DetectU32Match(length, du32); -} - -/** - * \brief Function to add the parsed IKE key exchange payload length query into the current - * signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeKeyExchangePayloadLengthSetup( - DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectU32Data *key_exchange_payload_length = DetectU32Parse(rawstr); - if (key_exchange_payload_length == NULL) - return -1; - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH, - (SigMatchCtx *)key_exchange_payload_length, - g_ike_key_exch_payload_length_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeKeyExchangePayloadLengthFree(de_ctx, key_exchange_payload_length); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -static void DetectIkeKeyExchangePayloadLengthFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} diff --git a/src/detect-ike-key-exchange-payload.c b/src/detect-ike-key-exchange-payload.c deleted file mode 100644 index 813e5bf080cd..000000000000 --- a/src/detect-ike-key-exchange-payload.c +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ike-key-exchange-payload.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-ike.h" -#include "rust-bindings.h" - -#define KEYWORD_NAME_KEY_EXCHANGE "ike.key_exchange_payload" -#define KEYWORD_DOC_KEY_EXCHANGE "ike-keywords.html#ike-key_exchange_payload"; -#define BUFFER_NAME_KEY_EXCHANGE "ike.key_exchange_payload" -#define BUFFER_DESC_KEY_EXCHANGE "ike key_exchange payload" - -static int g_buffer_key_exchange_id = 0; - -static int DetectKeyExchangeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_key_exchange_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetKeyExchangeData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_ike_state_get_key_exchange(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectIkeKeyExchangeRegister(void) -{ - // register key_exchange - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].name = KEYWORD_NAME_KEY_EXCHANGE; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].url = - "/rules/" KEYWORD_DOC_KEY_EXCHANGE sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].desc = - "sticky buffer to match on the IKE key_exchange_payload"; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].Setup = DetectKeyExchangeSetup; - sigmatch_table[DETECT_AL_IKE_KEY_EXCHANGE].flags |= - SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME_KEY_EXCHANGE, ALPROTO_IKE, SIG_FLAG_TOSERVER, - 1, DetectEngineInspectBufferGeneric, GetKeyExchangeData); - - DetectAppLayerMpmRegister2(BUFFER_NAME_KEY_EXCHANGE, SIG_FLAG_TOSERVER, 1, - PrefilterGenericMpmRegister, GetKeyExchangeData, ALPROTO_IKE, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME_KEY_EXCHANGE, ALPROTO_IKE, SIG_FLAG_TOCLIENT, - 1, DetectEngineInspectBufferGeneric, GetKeyExchangeData); - - DetectAppLayerMpmRegister2(BUFFER_NAME_KEY_EXCHANGE, SIG_FLAG_TOCLIENT, 1, - PrefilterGenericMpmRegister, GetKeyExchangeData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_KEY_EXCHANGE, BUFFER_DESC_KEY_EXCHANGE); - - g_buffer_key_exchange_id = DetectBufferTypeGetByName(BUFFER_NAME_KEY_EXCHANGE); - SCLogDebug("registering " BUFFER_NAME_KEY_EXCHANGE " rule option"); -} diff --git a/src/detect-ike-nonce-payload-length.c b/src/detect-ike-nonce-payload-length.c deleted file mode 100644 index fbb3a903366a..000000000000 --- a/src/detect-ike-nonce-payload-length.c +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-nonce-payload-length.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "detect-engine-uint.h" - -#include "rust-bindings.h" - -/** - * [ike.nonce_payload_length]:[=|<|>|<=|>=]; - */ -static int DetectIkeNoncePayloadLengthSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeNoncePayloadLengthFree(DetectEngineCtx *, void *); -static int g_ike_nonce_payload_length_buffer_id = 0; - -static int DetectIkeNoncePayloadLengthMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, - void *, const Signature *, const SigMatchCtx *); - -/** - * \brief Registration function for ike.nonce_payload_length keyword. - */ -void DetectIkeNoncePayloadLengthRegister(void) -{ - sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].name = "ike.nonce_payload_length"; - sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].desc = "match IKE nonce payload length"; - sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].url = - "/rules/ike-keywords.html#ike-nonce-payload-length"; - sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].AppLayerTxMatch = - DetectIkeNoncePayloadLengthMatch; - sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].Setup = DetectIkeNoncePayloadLengthSetup; - sigmatch_table[DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH].Free = DetectIkeNoncePayloadLengthFree; - - DetectAppLayerInspectEngineRegister2("ike.nonce_payload_length", ALPROTO_IKE, SIG_FLAG_TOSERVER, - 1, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("ike.nonce_payload_length", ALPROTO_IKE, SIG_FLAG_TOCLIENT, - 1, DetectEngineInspectGenericList, NULL); - - g_ike_nonce_payload_length_buffer_id = DetectBufferTypeGetByName("ike.nonce_payload_length"); -} - -/** - * \internal - * \brief Function to match nonce length of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeNoncePayloadLengthMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint32_t length; - if (!rs_ike_state_get_nonce_payload_length(txv, &length)) - SCReturnInt(0); - const DetectU32Data *du32 = (const DetectU32Data *)ctx; - return DetectU32Match(length, du32); -} - -/** - * \brief Function to add the parsed IKE nonce length field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeNoncePayloadLengthSetup( - DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectU32Data *nonce_payload_length = DetectU32Parse(rawstr); - if (nonce_payload_length == NULL) - return -1; - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_IKE_NONCE_PAYLOAD_LENGTH, - (SigMatchCtx *)nonce_payload_length, - g_ike_nonce_payload_length_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeNoncePayloadLengthFree(de_ctx, nonce_payload_length); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -static void DetectIkeNoncePayloadLengthFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} diff --git a/src/detect-ike-nonce-payload.c b/src/detect-ike-nonce-payload.c deleted file mode 100644 index a6b73cdf8487..000000000000 --- a/src/detect-ike-nonce-payload.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ike-nonce-payload.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-ike.h" -#include "rust-bindings.h" - -#define KEYWORD_NAME_NONCE "ike.nonce_payload" -#define KEYWORD_DOC_NONCE "ike-keywords.html#ike-nonce_payload"; -#define BUFFER_NAME_NONCE "ike.nonce_payload" -#define BUFFER_DESC_NONCE "ike nonce payload" - -static int g_buffer_nonce_id = 0; - -static int DetectNonceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_nonce_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetNonceData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_ike_state_get_nonce(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectIkeNonceRegister(void) -{ - // register nonce - sigmatch_table[DETECT_AL_IKE_NONCE].name = KEYWORD_NAME_NONCE; - sigmatch_table[DETECT_AL_IKE_NONCE].url = - "/rules/" KEYWORD_DOC_NONCE sigmatch_table[DETECT_AL_IKE_NONCE].desc = - "sticky buffer to match on the IKE nonce_payload"; - sigmatch_table[DETECT_AL_IKE_NONCE].Setup = DetectNonceSetup; - sigmatch_table[DETECT_AL_IKE_NONCE].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME_NONCE, ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetNonceData); - - DetectAppLayerMpmRegister2(BUFFER_NAME_NONCE, SIG_FLAG_TOSERVER, 1, PrefilterGenericMpmRegister, - GetNonceData, ALPROTO_IKE, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME_NONCE, ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetNonceData); - - DetectAppLayerMpmRegister2(BUFFER_NAME_NONCE, SIG_FLAG_TOCLIENT, 1, PrefilterGenericMpmRegister, - GetNonceData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_NONCE, BUFFER_DESC_NONCE); - - g_buffer_nonce_id = DetectBufferTypeGetByName(BUFFER_NAME_NONCE); - SCLogDebug("registering " BUFFER_NAME_NONCE " rule option"); -} diff --git a/src/detect-ike-spi.c b/src/detect-ike-spi.c deleted file mode 100644 index 5514d0202cb5..000000000000 --- a/src/detect-ike-spi.c +++ /dev/null @@ -1,171 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ike-spi.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-ike.h" -#include "rust-bindings.h" - -#define KEYWORD_NAME_INITIATOR "ike.init_spi" -#define KEYWORD_DOC_INITIATOR "ike-keywords.html#ike-init_spi"; -#define BUFFER_NAME_INITIATOR "ike.init_spi" -#define BUFFER_DESC_INITIATOR "ike init spi" - -#define KEYWORD_NAME_RESPONDER "ike.resp_spi" -#define KEYWORD_DOC_RESPONDER "ike-keywords.html#ike-resp_spi"; -#define BUFFER_NAME_RESPONDER "ike.resp_spi" -#define BUFFER_DESC_RESPONDER "ike resp spi" - -static int g_buffer_initiator_id = 0; -static int g_buffer_responder_id = 0; - -static int DetectSpiInitiatorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_initiator_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static int DetectSpiResponderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_responder_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetInitiatorData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_ike_state_get_spi_initiator(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetResponderData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_ike_state_get_spi_responder(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectIkeSpiRegister(void) -{ - // register initiator - sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].name = KEYWORD_NAME_INITIATOR; - sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].url = - "/rules/" KEYWORD_DOC_INITIATOR sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].desc = - "sticky buffer to match on the IKE spi initiator"; - sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].Setup = DetectSpiInitiatorSetup; - sigmatch_table[DETECT_AL_IKE_SPI_INITIATOR].flags |= - SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME_INITIATOR, ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetInitiatorData); - - DetectAppLayerMpmRegister2(BUFFER_NAME_INITIATOR, SIG_FLAG_TOSERVER, 1, - PrefilterGenericMpmRegister, GetInitiatorData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_INITIATOR, BUFFER_DESC_INITIATOR); - - g_buffer_initiator_id = DetectBufferTypeGetByName(BUFFER_NAME_INITIATOR); - SCLogDebug("registering " BUFFER_NAME_INITIATOR " rule option"); - - // register responder - sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].name = KEYWORD_NAME_RESPONDER; - sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].url = - "/rules/" KEYWORD_DOC_RESPONDER sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].desc = - "sticky buffer to match on the IKE spi responder"; - sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].Setup = DetectSpiResponderSetup; - sigmatch_table[DETECT_AL_IKE_SPI_RESPONDER].flags |= - SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME_RESPONDER, ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetResponderData); - - DetectAppLayerMpmRegister2(BUFFER_NAME_RESPONDER, SIG_FLAG_TOCLIENT, 1, - PrefilterGenericMpmRegister, GetResponderData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_RESPONDER, BUFFER_DESC_RESPONDER); - - g_buffer_responder_id = DetectBufferTypeGetByName(BUFFER_NAME_RESPONDER); - SCLogDebug("registering " BUFFER_NAME_RESPONDER " rule option"); -} diff --git a/src/detect-ike-vendor.c b/src/detect-ike-vendor.c deleted file mode 100644 index f5c5b94f35d5..000000000000 --- a/src/detect-ike-vendor.c +++ /dev/null @@ -1,210 +0,0 @@ -/* Copyright (C) 2020-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-mpm.h" -#include "detect-ike-vendor.h" -#include "app-layer-parser.h" -#include "util-byte.h" - -#include "rust-bindings.h" -#include "util-profiling.h" - -static int DetectIkeVendorSetup(DetectEngineCtx *, Signature *, const char *); - -typedef struct { - char *vendor; -} DetectIkeVendorData; - -struct IkeVendorGetDataArgs { - uint32_t local_id; - void *txv; -}; - -typedef struct PrefilterMpmIkeVendor { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmIkeVendor; - -static int g_ike_vendor_buffer_id = 0; - -static InspectionBuffer *IkeVendorGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, struct IkeVendorGetDataArgs *cbdata, - int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_ike_tx_get_vendor(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -/** \brief IkeVendor Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxIkeVendor(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmIkeVendor *ctx = (const PrefilterMpmIkeVendor *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - while (1) { - struct IkeVendorGetDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = IkeVendorGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - local_id++; - } - - SCReturn; -} - -static void PrefilterMpmIkeVendorFree(void *ptr) -{ - if (ptr != NULL) - SCFree(ptr); -} - -static int PrefilterMpmIkeVendorRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmIkeVendor *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxIkeVendor, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmIkeVendorFree, mpm_reg->pname); -} - -static uint8_t DetectEngineInspectIkeVendor(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - struct IkeVendorGetDataArgs cbdata = { - local_id, - txv, - }; - InspectionBuffer *buffer = - IkeVendorGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -/** - * \brief Registration function for ike.vendor keyword. - */ -void DetectIkeVendorRegister(void) -{ - sigmatch_table[DETECT_AL_IKE_VENDOR].name = "ike.vendor"; - sigmatch_table[DETECT_AL_IKE_VENDOR].desc = "match IKE Vendor"; - sigmatch_table[DETECT_AL_IKE_VENDOR].url = "/rules/ike-keywords.html#ike-vendor"; - sigmatch_table[DETECT_AL_IKE_VENDOR].Setup = DetectIkeVendorSetup; - sigmatch_table[DETECT_AL_IKE_VENDOR].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_IKE_VENDOR].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerMpmRegister2("ike.vendor", SIG_FLAG_TOSERVER, 1, PrefilterMpmIkeVendorRegister, - NULL, ALPROTO_IKE, 1); - - DetectAppLayerInspectEngineRegister2( - "ike.vendor", ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, DetectEngineInspectIkeVendor, NULL); - - g_ike_vendor_buffer_id = DetectBufferTypeGetByName("ike.vendor"); - - DetectBufferTypeSupportsMultiInstance("ike.vendor"); -} - -/** - * \brief setup the sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectIkeVendorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_ike_vendor_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - return 0; -} diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index e4e9e22a36a3..93451ad210a9 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -33,18 +33,18 @@ #include "flow-var.h" #include "decode-events.h" -#include "util-debug.h" +#include "util/debug.h" #include "detect-ipopts.h" -#include "util-unittest.h" +#include "util/unittest.h" #define PARSE_REGEX "\\S[A-z]" static DetectParseRegex parse_regex; -static int DetectIpOptsMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectIpOptsMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectIpOptsSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void IpOptsRegisterTests(void); #endif @@ -53,14 +53,14 @@ void DetectIpOptsFree(DetectEngineCtx *, void *); /** * \brief Registration function for ipopts: keyword */ -void DetectIpOptsRegister (void) +void DetectIpOptsRegister(void) { sigmatch_table[DETECT_IPOPTS].name = "ipopts"; sigmatch_table[DETECT_IPOPTS].desc = "check if a specific IP option is set"; sigmatch_table[DETECT_IPOPTS].url = "/rules/header-keywords.html#ipopts"; sigmatch_table[DETECT_IPOPTS].Match = DetectIpOptsMatch; sigmatch_table[DETECT_IPOPTS].Setup = DetectIpOptsSetup; - sigmatch_table[DETECT_IPOPTS].Free = DetectIpOptsFree; + sigmatch_table[DETECT_IPOPTS].Free = DetectIpOptsFree; #ifdef UNITTESTS sigmatch_table[DETECT_IPOPTS].RegisterTests = IpOptsRegisterTests; #endif @@ -73,8 +73,8 @@ void DetectIpOptsRegister (void) */ struct DetectIpOpts_ { - const char *ipopt_name; /**< ip option name */ - uint16_t code; /**< ip option flag value */ + const char *ipopt_name; /**< ip option name */ + uint16_t code; /**< ip option flag value */ } ipopts[] = { { "rr", @@ -165,8 +165,8 @@ const char *IpOptsFlagToString(uint16_t flag) * \retval 0 no match * \retval 1 match */ -static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectIpOptsMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectIpOptsData *de = (const DetectIpOptsData *)ctx; @@ -189,7 +189,7 @@ static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval de pointer to DetectIpOptsData on success * \retval NULL on failure */ -static DetectIpOptsData *DetectIpOptsParse (const char *rawstr) +static DetectIpOptsData *DetectIpOptsParse(const char *rawstr) { int i; DetectIpOptsData *de = NULL; @@ -202,14 +202,14 @@ static DetectIpOptsData *DetectIpOptsParse (const char *rawstr) goto error; } - for(i = 0; ipopts[i].ipopt_name != NULL; i++) { - if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) { + for (i = 0; ipopts[i].ipopt_name != NULL; i++) { + if ((strcasecmp(ipopts[i].ipopt_name, rawstr)) == 0) { found = 1; break; } } - if(found == 0) + if (found == 0) goto error; de = SCMalloc(sizeof(DetectIpOptsData)); @@ -225,7 +225,8 @@ static DetectIpOptsData *DetectIpOptsParse (const char *rawstr) if (match) { pcre2_match_data_free(match); } - if (de) SCFree(de); + if (de) + SCFree(de); return NULL; } @@ -240,7 +241,7 @@ static DetectIpOptsData *DetectIpOptsParse (const char *rawstr) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectIpOptsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectIpOptsData *de = NULL; @@ -271,7 +272,8 @@ static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char void DetectIpOptsFree(DetectEngineCtx *de_ctx, void *de_ptr) { DetectIpOptsData *de = (DetectIpOptsData *)de_ptr; - if(de) SCFree(de); + if (de) + SCFree(de); } /* @@ -282,7 +284,7 @@ void DetectIpOptsFree(DetectEngineCtx *de_ctx, void *de_ptr) /** * \test IpOptsTestParse01 is a test for a valid ipopts value */ -static int IpOptsTestParse01 (void) +static int IpOptsTestParse01(void) { DetectIpOptsData *de = DetectIpOptsParse("lsrr"); @@ -296,7 +298,7 @@ static int IpOptsTestParse01 (void) /** * \test IpOptsTestParse02 is a test for an invalid ipopts value */ -static int IpOptsTestParse02 (void) +static int IpOptsTestParse02(void) { DetectIpOptsData *de = DetectIpOptsParse("invalidopt"); @@ -310,7 +312,7 @@ static int IpOptsTestParse02 (void) /** * \test IpOptsTestParse03 test the match function on a packet that needs to match */ -static int IpOptsTestParse03 (void) +static int IpOptsTestParse03(void) { Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -344,7 +346,7 @@ static int IpOptsTestParse03 (void) /** * \test IpOptsTestParse04 test the match function on a packet that needs to not match */ -static int IpOptsTestParse04 (void) +static int IpOptsTestParse04(void) { Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); diff --git a/src/detect-ipopts.h b/src/detect-ipopts.h index a4009252d0b5..99757f38c46b 100644 --- a/src/detect-ipopts.h +++ b/src/detect-ipopts.h @@ -24,7 +24,6 @@ #ifndef __DETECT_IPOPTS_H__ #define __DETECT_IPOPTS_H__ - /** * \struct DetectIpOptsData_ * DetectIpOptsData_ is used to store ipopts: input value @@ -43,9 +42,8 @@ typedef struct DetectIpOptsData_ { * Registration function for ipopts: keyword */ -void DetectIpOptsRegister (void); +void DetectIpOptsRegister(void); const char *IpOptsFlagToString(uint16_t flag); #endif /*__DETECT_IPOPTS_H__ */ - diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index e5a0c7969b2f..da79c9c5c65a 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -37,17 +37,17 @@ #include "detect-engine-siggroup.h" #include "detect-engine-address.h" -#include "util-byte.h" -#include "util-proto-name.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/byte.h" +#include "util/proto-name.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" -#include "util-debug.h" +#include "util/debug.h" /** * \brief Regex for parsing our options */ -#define PARSE_REGEX "^([!<>]?)\\s*([^\\s]+)$" +#define PARSE_REGEX "^([!<>]?)\\s*([^\\s]+)$" static DetectParseRegex parse_regex; @@ -64,7 +64,7 @@ void DetectIPProtoRegister(void) sigmatch_table[DETECT_IPPROTO].url = "/rules/header-keywords.html#ip-proto"; sigmatch_table[DETECT_IPPROTO].Match = NULL; sigmatch_table[DETECT_IPPROTO].Setup = DetectIPProtoSetup; - sigmatch_table[DETECT_IPPROTO].Free = DetectIPProtoFree; + sigmatch_table[DETECT_IPPROTO].Free = DetectIPProtoFree; #ifdef UNITTESTS sigmatch_table[DETECT_IPPROTO].RegisterTests = DetectIPProtoRegisterTests; #endif @@ -129,15 +129,14 @@ static DetectIPProtoData *DetectIPProtoParse(const char *optstr) goto error; } data->proto = proto; - } - else { + } else { if (StringParseUint8(&data->proto, 10, 0, args[1]) <= 0) { SCLogError("Malformed protocol number: %s", str_ptr); goto error; } } - for (i = 0; i < (ret - 1); i++){ + for (i = 0; i < (ret - 1); i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } @@ -149,7 +148,7 @@ static DetectIPProtoData *DetectIPProtoParse(const char *optstr) if (match) { pcre2_match_data_free(match); } - for (i = 0; i < (ret - 1) && i < 2; i++){ + for (i = 0; i < (ret - 1) && i < 2; i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } @@ -257,7 +256,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, const char temp_sm = temp_sm->next; } if (temp_sm != NULL) { - DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; + DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto <= data->proto) { SCLogError("can't have " "both gt and lt ipprotos, with the lt being " @@ -286,7 +285,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, const char SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && - ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_LT) { + ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_LT) { break; } temp_sm = temp_sm->next; @@ -332,7 +331,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, const char temp_sm = temp_sm->next; } if (temp_sm != NULL) { - DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; + DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto >= data->proto) { SCLogError("can't use a have " "both gt and lt ipprotos, with the lt being " @@ -361,13 +360,13 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, const char SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && - ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_GT) { + ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_GT) { break; } temp_sm = temp_sm->next; } if (temp_sm != NULL) { - data_temp = (DetectIPProtoData *)temp_sm->ctx; + data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto >= data->proto) { SCLogError("can't have " "both gt and lt ipprotos, with the lt being " @@ -421,7 +420,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, const char return 0; - error: +error: DetectIPProtoFree(de_ctx, data); return -1; @@ -539,7 +538,7 @@ static int DetectIPProtoTestSetup02(void) result = 1; - end: +end: if (sig != NULL) SigFree(NULL, sig); return result; @@ -576,7 +575,7 @@ static int DetectIPProtoTestSetup03(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -612,7 +611,7 @@ static int DetectIPProtoTestSetup04(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -648,7 +647,7 @@ static int DetectIPProtoTestSetup05(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -675,7 +674,7 @@ static int DetectIPProtoTestSetup06(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -702,7 +701,7 @@ static int DetectIPProtoTestSetup07(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -729,7 +728,7 @@ static int DetectIPProtoTestSetup08(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -756,7 +755,7 @@ static int DetectIPProtoTestSetup09(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -783,7 +782,7 @@ static int DetectIPProtoTestSetup10(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -810,7 +809,7 @@ static int DetectIPProtoTestSetup11(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -837,7 +836,7 @@ static int DetectIPProtoTestSetup12(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -864,7 +863,7 @@ static int DetectIPProtoTestSetup13(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -888,7 +887,7 @@ static int DetectIPProtoTestSetup14(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -925,10 +924,9 @@ static int DetectIPProtoTestSetup15(void) result = 1; - end: +end: SigFree(NULL, sig); return result; - } static int DetectIPProtoTestSetup16(void) @@ -963,10 +961,9 @@ static int DetectIPProtoTestSetup16(void) result = 1; - end: +end: SigFree(NULL, sig); return result; - } static int DetectIPProtoTestSetup17(void) @@ -1001,10 +998,9 @@ static int DetectIPProtoTestSetup17(void) result = 1; - end: +end: SigFree(NULL, sig); return result; - } static int DetectIPProtoTestSetup18(void) @@ -1039,10 +1035,9 @@ static int DetectIPProtoTestSetup18(void) result = 1; - end: +end: SigFree(NULL, sig); return result; - } static int DetectIPProtoTestSetup19(void) @@ -1080,7 +1075,7 @@ static int DetectIPProtoTestSetup19(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1117,7 +1112,7 @@ static int DetectIPProtoTestSetup20(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1157,7 +1152,7 @@ static int DetectIPProtoTestSetup21(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1197,7 +1192,7 @@ static int DetectIPProtoTestSetup22(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1234,7 +1229,7 @@ static int DetectIPProtoTestSetup23(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1274,7 +1269,7 @@ static int DetectIPProtoTestSetup24(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1314,7 +1309,7 @@ static int DetectIPProtoTestSetup33(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1355,7 +1350,7 @@ static int DetectIPProtoTestSetup34(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1395,7 +1390,7 @@ static int DetectIPProtoTestSetup36(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1439,7 +1434,7 @@ static int DetectIPProtoTestSetup43(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1479,7 +1474,7 @@ static int DetectIPProtoTestSetup44(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1523,7 +1518,7 @@ static int DetectIPProtoTestSetup45(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1563,7 +1558,7 @@ static int DetectIPProtoTestSetup56(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1600,7 +1595,7 @@ static int DetectIPProtoTestSetup75(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1637,7 +1632,7 @@ static int DetectIPProtoTestSetup76(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1674,7 +1669,7 @@ static int DetectIPProtoTestSetup129(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1711,7 +1706,7 @@ static int DetectIPProtoTestSetup130(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1748,7 +1743,7 @@ static int DetectIPProtoTestSetup131(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1785,7 +1780,7 @@ static int DetectIPProtoTestSetup132(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1855,7 +1850,7 @@ static int DetectIPProtoTestSetup145(void) result = 1; - end: +end: SigFree(NULL, sig); return result; } @@ -1863,10 +1858,9 @@ static int DetectIPProtoTestSetup145(void) static int DetectIPProtoTestSig1(void) { int result = 0; - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) @@ -1874,18 +1868,18 @@ static int DetectIPProtoTestSig1(void) const char *sigs[4]; sigs[0] = "alert ip any any -> any any " - "(msg:\"Not tcp\"; ip_proto:!tcp; content:\"GET \"; sid:1;)"; + "(msg:\"Not tcp\"; ip_proto:!tcp; content:\"GET \"; sid:1;)"; sigs[1] = "alert ip any any -> any any " - "(msg:\"Less than 7\"; content:\"GET \"; ip_proto:<7; sid:2;)"; + "(msg:\"Less than 7\"; content:\"GET \"; ip_proto:<7; sid:2;)"; sigs[2] = "alert ip any any -> any any " - "(msg:\"Greater than 5\"; content:\"GET \"; ip_proto:>5; sid:3;)"; + "(msg:\"Greater than 5\"; content:\"GET \"; ip_proto:>5; sid:3;)"; sigs[3] = "alert ip any any -> any any " - "(msg:\"Equals tcp\"; content:\"GET \"; ip_proto:tcp; sid:4;)"; + "(msg:\"Equals tcp\"; content:\"GET \"; ip_proto:tcp; sid:4;)"; /* sids to match */ - uint32_t sid[4] = {1, 2, 3, 4}; + uint32_t sid[4] = { 1, 2, 3, 4 }; /* expected matches for each sid within this packet we are testing */ - uint32_t results[4] = {0, 1, 1, 1}; + uint32_t results[4] = { 0, 1, 1, 1 }; /* remember that UTHGenericTest expect the first parameter * as an array of packet pointers. And also a bidimensional array of results @@ -1904,6 +1898,7 @@ static int DetectIPProtoTestSig2(void) { int result = 0; + // clang-format off uint8_t raw_eth[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x0d, 0x00, 0x26, 0x88, 0x61, 0x3a, 0x80, 0x08, 0x00, 0x45, 0xc0, @@ -1915,6 +1910,7 @@ static int DetectIPProtoTestSig2(void) 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x04, 0x4a, 0xea, 0x7a, 0x8e, }; + // clang-format on Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1939,9 +1935,8 @@ static int DetectIPProtoTestSig2(void) de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any (msg:\"Check ipproto usage\"; " - "ip_proto:!103; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"Check ipproto usage\"; " + "ip_proto:!103; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1989,6 +1984,7 @@ static int DetectIPProtoTestSig3(void) { int result = 0; + // clang-format off uint8_t raw_eth[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x0d, 0x00, 0x26, 0x88, 0x61, 0x3a, 0x80, 0x08, 0x00, 0x45, 0xc0, @@ -2000,6 +1996,7 @@ static int DetectIPProtoTestSig3(void) 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x04, 0x4a, 0xea, 0x7a, 0x8e, }; + // clang-format on Packet *p = UTHBuildPacket((uint8_t *)"boom", 4, IPPROTO_TCP); if (p == NULL) @@ -2024,9 +2021,8 @@ static int DetectIPProtoTestSig3(void) de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any (msg:\"Check ipproto usage\"; " - "ip_proto:103; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any (msg:\"Check ipproto usage\"; " + "ip_proto:103; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; diff --git a/src/detect-ipproto.h b/src/detect-ipproto.h index eeac35a5c14b..d2c1de1f406e 100644 --- a/src/detect-ipproto.h +++ b/src/detect-ipproto.h @@ -25,15 +25,15 @@ #define __DETECT_IPPROTO_H__ /** IPProto Operators */ -#define DETECT_IPPROTO_OP_EQ '=' /**< "equals" operator (default) */ -#define DETECT_IPPROTO_OP_NOT '!' /**< "not" operator */ -#define DETECT_IPPROTO_OP_LT '<' /**< "less than" operator */ -#define DETECT_IPPROTO_OP_GT '>' /**< "greater than" operator */ +#define DETECT_IPPROTO_OP_EQ '=' /**< "equals" operator (default) */ +#define DETECT_IPPROTO_OP_NOT '!' /**< "not" operator */ +#define DETECT_IPPROTO_OP_LT '<' /**< "less than" operator */ +#define DETECT_IPPROTO_OP_GT '>' /**< "greater than" operator */ /** ip_proto data */ typedef struct DetectIPProtoData_ { - uint8_t op; /**< Operator used to compare */ - uint8_t proto; /**< Protocol used to compare */ + uint8_t op; /**< Operator used to compare */ + uint8_t proto; /**< Protocol used to compare */ } DetectIPProtoData; /* prototypes */ @@ -41,8 +41,7 @@ typedef struct DetectIPProtoData_ { /** * \brief Registration function for ip_proto keyword. */ -void DetectIPProtoRegister (void); +void DetectIPProtoRegister(void); void DetectIPProtoRemoveAllSMs(DetectEngineCtx *, Signature *); #endif /* __DETECT_IPPROTO_H__ */ - diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 068619405bce..74840337f692 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -31,7 +31,7 @@ #include "flow-bit.h" #include "flow-util.h" #include "detect-iprep.h" -#include "util-spm.h" +#include "util/spm.h" #include "app-layer-parser.h" @@ -42,32 +42,32 @@ #include "detect-engine-uint.h" #include "detect-engine-build.h" -#include "util-debug.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-fmemopen.h" -#include "util-validate.h" +#include "util/debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/fmemopen.h" +#include "util/validate.h" #include "reputation.h" #include "host.h" -static int DetectIPRepMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectIPRepSetup (DetectEngineCtx *, Signature *, const char *); -void DetectIPRepFree (DetectEngineCtx *, void *); +static int DetectIPRepMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectIPRepSetup(DetectEngineCtx *, Signature *, const char *); +void DetectIPRepFree(DetectEngineCtx *, void *); #ifdef UNITTESTS static void IPRepRegisterTests(void); #endif -void DetectIPRepRegister (void) +void DetectIPRepRegister(void) { sigmatch_table[DETECT_IPREP].name = "iprep"; sigmatch_table[DETECT_IPREP].desc = "match on the IP reputation information for a host"; sigmatch_table[DETECT_IPREP].url = "/rules/ip-reputation-rules.html#iprep"; sigmatch_table[DETECT_IPREP].Match = DetectIPRepMatch; sigmatch_table[DETECT_IPREP].Setup = DetectIPRepSetup; - sigmatch_table[DETECT_IPREP].Free = DetectIPRepFree; + sigmatch_table[DETECT_IPREP].Free = DetectIPRepFree; #ifdef UNITTESTS sigmatch_table[DETECT_IPREP].RegisterTests = IPRepRegisterTests; #endif @@ -144,8 +144,8 @@ static uint8_t GetHostRepDst(Packet *p, uint8_t cat, uint32_t version) * 1: match * -1: error */ -static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectIPRepMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectIPRepData *rd = (const DetectIPRepData *)ctx; if (rd == NULL) @@ -155,7 +155,7 @@ static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p, uint8_t val = 0; SCLogDebug("rd->cmd %u", rd->cmd); - switch(rd->cmd) { + switch (rd->cmd) { case IPRepCmdAny: val = GetHostRepSrc(p, rd->cat, version); if (val == 0) @@ -211,7 +211,7 @@ static int DetectIPRepMatch (DetectEngineThreadCtx *det_ctx, Packet *p, return 0; } -int DetectIPRepSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +int DetectIPRepSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectIPRepData *cd = rs_detect_iprep_parse(rawstr); @@ -238,7 +238,7 @@ int DetectIPRepSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) return -1; } -void DetectIPRepFree (DetectEngineCtx *de_ctx, void *ptr) +void DetectIPRepFree(DetectEngineCtx *de_ctx, void *ptr) { DetectIPRepData *fd = (DetectIPRepData *)ptr; @@ -267,9 +267,8 @@ static FILE *DetectIPRepGenerateCategoriesDummy(void) static FILE *DetectIPRepGenerateCategoriesDummy2(void) { FILE *fd = NULL; - const char *buffer = - "1,BadHosts,Know bad hosts\n" - "2,GoodHosts,Know good hosts\n"; + const char *buffer = "1,BadHosts,Know bad hosts\n" + "2,GoodHosts,Know good hosts\n"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) @@ -293,9 +292,8 @@ static FILE *DetectIPRepGenerateNetworksDummy(void) static FILE *DetectIPRepGenerateNetworksDummy2(void) { FILE *fd = NULL; - const char *buffer = - "0.0.0.0/0,1,10\n" - "192.168.0.0/16,2,127"; + const char *buffer = "0.0.0.0/0,1,10\n" + "192.168.0.0/16,2,127"; fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) diff --git a/src/detect-iprep.h b/src/detect-iprep.h index 07cd5c7f606f..2fe3d47a37d3 100644 --- a/src/detect-iprep.h +++ b/src/detect-iprep.h @@ -25,6 +25,6 @@ #define __DETECT_IPREP_H__ /* prototypes */ -void DetectIPRepRegister (void); +void DetectIPRepRegister(void); #endif /* __DETECT_IPREP_H__ */ diff --git a/src/detect-ipv4hdr.c b/src/detect-ipv4hdr.c index 76334410e33f..50acd08e6624 100644 --- a/src/detect-ipv4hdr.c +++ b/src/detect-ipv4hdr.c @@ -34,9 +34,9 @@ #include "detect-ipv4hdr.h" /* prototypes */ -static int DetectIpv4hdrSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectIpv4hdrSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS -void DetectIpv4hdrRegisterTests (void); +void DetectIpv4hdrRegisterTests(void); #endif static int g_ipv4hdr_buffer_id = 0; @@ -65,8 +65,7 @@ void DetectIpv4hdrRegister(void) DetectPktMpmRegister("ipv4.hdr", 2, PrefilterGenericMpmPktRegister, GetData); - DetectPktInspectEngineRegister("ipv4.hdr", GetData, - DetectEngineInspectPktBufferGeneric); + DetectPktInspectEngineRegister("ipv4.hdr", GetData, DetectEngineInspectPktBufferGeneric); return; } @@ -81,7 +80,7 @@ void DetectIpv4hdrRegister(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectIpv4hdrSetup (DetectEngineCtx *de_ctx, Signature *s, const char *_unused) +static int DetectIpv4hdrSetup(DetectEngineCtx *de_ctx, Signature *s, const char *_unused) { s->proto.flags |= DETECT_PROTO_IPV4; // TODO @@ -106,10 +105,8 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, } uint32_t hlen = IPV4_GET_HLEN(p); if (((uint8_t *)p->ip4h + (ptrdiff_t)hlen) > - ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) - { - SCLogDebug("data out of range: %p > %p", - ((uint8_t *)p->ip4h + (ptrdiff_t)hlen), + ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) { + SCLogDebug("data out of range: %p > %p", ((uint8_t *)p->ip4h + (ptrdiff_t)hlen), ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))); return NULL; } diff --git a/src/detect-ipv4hdr.h b/src/detect-ipv4hdr.h index aa30c45a3277..bd9279896527 100644 --- a/src/detect-ipv4hdr.h +++ b/src/detect-ipv4hdr.h @@ -26,4 +26,4 @@ void DetectIpv4hdrRegister(void); -#endif /* _DETECT_IPV4HDR_H */ +#endif /* _DETECT_IPV4HDR_H */ diff --git a/src/detect-ipv6hdr.c b/src/detect-ipv6hdr.c index eacff043a9f1..b1f60b5ac764 100644 --- a/src/detect-ipv6hdr.c +++ b/src/detect-ipv6hdr.c @@ -34,9 +34,9 @@ #include "detect-ipv6hdr.h" /* prototypes */ -static int DetectIpv6hdrSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectIpv6hdrSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS -void DetectIpv6hdrRegisterTests (void); +void DetectIpv6hdrRegisterTests(void); #endif static int g_ipv6hdr_buffer_id = 0; @@ -65,8 +65,7 @@ void DetectIpv6hdrRegister(void) DetectPktMpmRegister("ipv6.hdr", 2, PrefilterGenericMpmPktRegister, GetData); - DetectPktInspectEngineRegister("ipv6.hdr", GetData, - DetectEngineInspectPktBufferGeneric); + DetectPktInspectEngineRegister("ipv6.hdr", GetData, DetectEngineInspectPktBufferGeneric); return; } @@ -81,7 +80,7 @@ void DetectIpv6hdrRegister(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectIpv6hdrSetup (DetectEngineCtx *de_ctx, Signature *s, const char *_unused) +static int DetectIpv6hdrSetup(DetectEngineCtx *de_ctx, Signature *s, const char *_unused) { s->proto.flags |= DETECT_PROTO_IPV6; // TODO @@ -106,8 +105,7 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, } uint32_t hlen = IPV6_HEADER_LEN + IPV6_GET_EXTHDRS_LEN(p); if (((uint8_t *)p->ip6h + (ptrdiff_t)hlen) > - ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) - { + ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) { SCLogDebug("data out of range: %p > %p (exthdrs_len %u)", ((uint8_t *)p->ip6h + (ptrdiff_t)hlen), ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p)), diff --git a/src/detect-ipv6hdr.h b/src/detect-ipv6hdr.h index 0ff454d6bc3b..6b0c9d61acb8 100644 --- a/src/detect-ipv6hdr.h +++ b/src/detect-ipv6hdr.h @@ -26,4 +26,4 @@ void DetectIpv6hdrRegister(void); -#endif /* _DETECT_IPV6HDR_H */ +#endif /* _DETECT_IPV6HDR_H */ diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index 7b4d629ad3a1..c0d29a8d8264 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -30,8 +30,8 @@ #include "detect-parse.h" #include "app-layer.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-isdataat.h" #include "detect-content.h" @@ -41,25 +41,25 @@ #include "flow.h" #include "flow-var.h" -#include "util-debug.h" -#include "util-byte.h" +#include "util/debug.h" +#include "util/byte.h" #include "detect-pcre.h" #include "detect-byte.h" /** * \brief Regex for parsing our isdataat options */ -#define PARSE_REGEX "^\\s*!?([^\\s,]+)\\s*(,\\s*relative)?\\s*(,\\s*rawbytes\\s*)?\\s*$" +#define PARSE_REGEX "^\\s*!?([^\\s,]+)\\s*(,\\s*relative)?\\s*(,\\s*rawbytes\\s*)?\\s*$" static DetectParseRegex parse_regex; -int DetectIsdataatSetup (DetectEngineCtx *, Signature *, const char *); +int DetectIsdataatSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectIsdataatRegisterTests(void); #endif void DetectIsdataatFree(DetectEngineCtx *, void *); -static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr); +static int DetectEndsWithSetup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr); /** * \brief Registration function for isdataat: keyword @@ -67,17 +67,19 @@ static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const cha void DetectIsdataatRegister(void) { sigmatch_table[DETECT_ISDATAAT].name = "isdataat"; - sigmatch_table[DETECT_ISDATAAT].desc = "check if there is still data at a specific part of the payload"; + sigmatch_table[DETECT_ISDATAAT].desc = + "check if there is still data at a specific part of the payload"; sigmatch_table[DETECT_ISDATAAT].url = "/rules/payload-keywords.html#isdataat"; /* match is handled in DetectEngineContentInspection() */ sigmatch_table[DETECT_ISDATAAT].Match = NULL; sigmatch_table[DETECT_ISDATAAT].Setup = DetectIsdataatSetup; - sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; + sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; #ifdef UNITTESTS sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests; #endif sigmatch_table[DETECT_ENDS_WITH].name = "endswith"; - sigmatch_table[DETECT_ENDS_WITH].desc = "make sure the previous content matches exactly at the end of the buffer"; + sigmatch_table[DETECT_ENDS_WITH].desc = + "make sure the previous content matches exactly at the end of the buffer"; sigmatch_table[DETECT_ENDS_WITH].url = "/rules/payload-keywords.html#endswith"; sigmatch_table[DETECT_ENDS_WITH].Setup = DetectEndsWithSetup; sigmatch_table[DETECT_ENDS_WITH].flags = SIGMATCH_NOOPT; @@ -94,13 +96,14 @@ void DetectIsdataatRegister(void) * \retval idad pointer to DetectIsdataatData on success * \retval NULL on failure */ -static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const char *isdataatstr, char **offset) +static DetectIsdataatData *DetectIsdataatParse( + DetectEngineCtx *de_ctx, const char *isdataatstr, char **offset) { DetectIsdataatData *idad = NULL; - char *args[3] = {NULL,NULL,NULL}; + char *args[3] = { NULL, NULL, NULL }; int res = 0; size_t pcre2_len; - int i=0; + int i = 0; pcre2_match_data *match = NULL; int ret = DetectParsePcreExec(&parse_regex, &match, isdataatstr, 0, 0); @@ -118,7 +121,6 @@ static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const c } args[0] = (char *)str_ptr; - if (ret > 2) { res = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); if (res < 0) { @@ -154,8 +156,7 @@ static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const c if (*offset == NULL) goto error; } else { - if (StringParseUint16(&idad->dataat, 10, - strlen(args[0]), args[0]) < 0 ) { + if (StringParseUint16(&idad->dataat, 10, strlen(args[0]), args[0]) < 0) { SCLogError("isdataat out of range"); SCFree(idad); idad = NULL; @@ -163,10 +164,10 @@ static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const c } } - if (args[1] !=NULL) { + if (args[1] != NULL) { idad->flags |= ISDATAAT_RELATIVE; - if(args[2] !=NULL) + if (args[2] != NULL) idad->flags |= ISDATAAT_RAWBYTES; } @@ -174,21 +175,20 @@ static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const c idad->flags |= ISDATAAT_NEGATED; } - for (i = 0; i < (ret -1); i++) { + for (i = 0; i < (ret - 1); i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } pcre2_match_data_free(match); return idad; - } error: if (match) { pcre2_match_data_free(match); } - for (i = 0; i < (ret -1) && i < 3; i++){ + for (i = 0; i < (ret - 1) && i < 3; i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } @@ -196,7 +196,6 @@ static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const c if (idad != NULL) DetectIsdataatFree(de_ctx, idad); return NULL; - } /** @@ -209,7 +208,7 @@ static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const c * \retval 0 on Success * \retval -1 on Failure */ -int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, const char *isdataatstr) +int DetectIsdataatSetup(DetectEngineCtx *de_ctx, Signature *s, const char *isdataatstr) { SigMatch *prev_pm = NULL; DetectIsdataatData *idad = NULL; @@ -230,10 +229,8 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, const char *isda prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (idad->flags & ISDATAAT_RELATIVE) { - prev_pm = DetectGetLastSMFromLists(s, - DETECT_CONTENT, DETECT_PCRE, - DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, - DETECT_ISDATAAT, DETECT_BYTEMATH, -1); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, DETECT_BYTETEST, + DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, DETECT_ISDATAAT, DETECT_BYTEMATH, -1); if (prev_pm == NULL) sm_list = DETECT_SM_LIST_PMATCH; else { @@ -261,10 +258,9 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, const char *isda } /* 'ends with' scenario */ - if (prev_pm != NULL && prev_pm->type == DETECT_CONTENT && - idad->dataat == 1 && - (idad->flags & (ISDATAAT_RELATIVE|ISDATAAT_NEGATED)) == (ISDATAAT_RELATIVE|ISDATAAT_NEGATED)) - { + if (prev_pm != NULL && prev_pm->type == DETECT_CONTENT && idad->dataat == 1 && + (idad->flags & (ISDATAAT_RELATIVE | ISDATAAT_NEGATED)) == + (ISDATAAT_RELATIVE | ISDATAAT_NEGATED)) { DetectIsdataatFree(de_ctx, idad); DetectContentData *cd = (DetectContentData *)prev_pm->ctx; cd->flags |= DETECT_CONTENT_ENDS_WITH; @@ -315,7 +311,7 @@ void DetectIsdataatFree(DetectEngineCtx *de_ctx, void *ptr) SCFree(idad); } -static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectEndsWithSetup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SigMatch *pm = NULL; int ret = -1; @@ -334,7 +330,7 @@ static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const cha cd->flags |= DETECT_CONTENT_ENDS_WITH; ret = 0; - end: +end: return ret; } @@ -342,10 +338,10 @@ static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const cha static int g_dce_stub_data_buffer_id = 0; /** - * \test DetectIsdataatTestParse01 is a test to make sure that we return a correct IsdataatData structure - * when given valid isdataat opt + * \test DetectIsdataatTestParse01 is a test to make sure that we return a correct IsdataatData + * structure when given valid isdataat opt */ -static int DetectIsdataatTestParse01 (void) +static int DetectIsdataatTestParse01(void) { int result = 0; DetectIsdataatData *idad = NULL; @@ -359,10 +355,10 @@ static int DetectIsdataatTestParse01 (void) } /** - * \test DetectIsdataatTestParse02 is a test to make sure that we return a correct IsdataatData structure - * when given valid isdataat opt + * \test DetectIsdataatTestParse02 is a test to make sure that we return a correct IsdataatData + * structure when given valid isdataat opt */ -static int DetectIsdataatTestParse02 (void) +static int DetectIsdataatTestParse02(void) { int result = 0; DetectIsdataatData *idad = NULL; @@ -376,10 +372,10 @@ static int DetectIsdataatTestParse02 (void) } /** - * \test DetectIsdataatTestParse03 is a test to make sure that we return a correct IsdataatData structure - * when given valid isdataat opt + * \test DetectIsdataatTestParse03 is a test to make sure that we return a correct IsdataatData + * structure when given valid isdataat opt */ -static int DetectIsdataatTestParse03 (void) +static int DetectIsdataatTestParse03(void) { int result = 0; DetectIsdataatData *idad = NULL; @@ -428,9 +424,9 @@ static int DetectIsdataatTestParse06(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "isdataat:!4,relative; sid:1;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "isdataat:!4,relative; sid:1;)"); FAIL_IF(s == NULL); FAIL_IF(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL); @@ -444,9 +440,9 @@ static int DetectIsdataatTestParse06(void) FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "isdataat: !4,relative; sid:2;)"); + "(msg:\"Testing bytejump_body\"; " + "content:\"one\"; " + "isdataat: !4,relative; sid:2;)"); FAIL_IF(s == NULL); FAIL_IF(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL); @@ -466,7 +462,7 @@ static int DetectIsdataatTestParse06(void) * \test DetectIsdataatTestPacket01 is a test to check matches of * isdataat, and isdataat relative */ -static int DetectIsdataatTestPacket01 (void) +static int DetectIsdataatTestPacket01(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -476,27 +472,30 @@ static int DetectIsdataatTestPacket01 (void) p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_UDP); p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); - if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) + if (p[0] == NULL || p[1] == NULL || p[2] == NULL) goto end; const char *sigs[5]; - sigs[0]= "alert ip any any -> any any (msg:\"Testing window 1\"; isdataat:6; sid:1;)"; - sigs[1]= "alert ip any any -> any any (msg:\"Testing window 2\"; content:\"all\"; isdataat:1, relative; isdataat:6; sid:2;)"; - sigs[2]= "alert ip any any -> any any (msg:\"Testing window 3\"; isdataat:8; sid:3;)"; - sigs[3]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:5, relative; sid:4;)"; - sigs[4]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:6, relative; sid:5;)"; - - uint32_t sid[5] = {1, 2, 3, 4, 5}; - - uint32_t results[3][5] = { - /* packet 0 match sid 1 but should not match sid 2 */ - {1, 1, 0, 1, 0}, - /* packet 1 should not match */ - {1, 1, 0, 1, 0}, - /* packet 2 should not match */ - {1, 1, 0, 1, 0} }; - - result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 5); + sigs[0] = "alert ip any any -> any any (msg:\"Testing window 1\"; isdataat:6; sid:1;)"; + sigs[1] = "alert ip any any -> any any (msg:\"Testing window 2\"; content:\"all\"; isdataat:1, " + "relative; isdataat:6; sid:2;)"; + sigs[2] = "alert ip any any -> any any (msg:\"Testing window 3\"; isdataat:8; sid:3;)"; + sigs[3] = "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:5, " + "relative; sid:4;)"; + sigs[4] = "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:6, " + "relative; sid:5;)"; + + uint32_t sid[5] = { 1, 2, 3, 4, 5 }; + + uint32_t results[3][5] = { /* packet 0 match sid 1 but should not match sid 2 */ + { 1, 1, 0, 1, 0 }, + /* packet 1 should not match */ + { 1, 1, 0, 1, 0 }, + /* packet 2 should not match */ + { 1, 1, 0, 1, 0 } + }; + + result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *)results, 5); UTHFreePackets(p, 3); end: @@ -508,15 +507,15 @@ static int DetectIsdataatTestPacket01 (void) * isdataat, and isdataat relative works if the previous keyword is pcre * (bug 144) */ -static int DetectIsdataatTestPacket02 (void) +static int DetectIsdataatTestPacket02(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" - "User-Agent: Wget/1.11.4" - "Accept: */*" - "Host: www.google.com" - "Connection: Keep-Alive" - "Date: Mon, 04 Jan 2010 17:29:39 GMT"; + "User-Agent: Wget/1.11.4" + "Accept: */*" + "Host: www.google.com" + "Connection: Keep-Alive" + "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); @@ -525,8 +524,8 @@ static int DetectIsdataatTestPacket02 (void) goto end; char sig[] = "alert tcp any any -> any any (msg:\"pcre with" - " isdataat + relative\"; pcre:\"/A(ll|pp)WorkAndNoPlayMakesWillA" - "DullBoy/\"; isdataat:96,relative; sid:1;)"; + " isdataat + relative\"; pcre:\"/A(ll|pp)WorkAndNoPlayMakesWillA" + "DullBoy/\"; isdataat:96,relative; sid:1;)"; result = UTHPacketMatchSig(p, sig); @@ -540,15 +539,15 @@ static int DetectIsdataatTestPacket02 (void) * isdataat, and isdataat relative works if the previous keyword is byte_jump * (bug 146) */ -static int DetectIsdataatTestPacket03 (void) +static int DetectIsdataatTestPacket03(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" - "User-Agent: Wget/1.11.4" - "Accept: */*" - "Host: www.google.com" - "Connection: Keep-Alive" - "Date: Mon, 04 Jan 2010 17:29:39 GMT"; + "User-Agent: Wget/1.11.4" + "Accept: */*" + "Host: www.google.com" + "Connection: Keep-Alive" + "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p; p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); @@ -557,8 +556,8 @@ static int DetectIsdataatTestPacket03 (void) goto end; char sig[] = "alert tcp any any -> any any (msg:\"byte_jump match = 0 " - "with distance content HTTP/1. relative against HTTP/1.0\"; byte_jump:1," - "46,string,dec; isdataat:87,relative; sid:109; rev:1;)"; + "with distance content HTTP/1. relative against HTTP/1.0\"; byte_jump:1," + "46,string,dec; isdataat:87,relative; sid:109; rev:1;)"; result = UTHPacketMatchSig(p, sig); diff --git a/src/detect-isdataat.h b/src/detect-isdataat.h index 60b138822921..b4493fdfa6a3 100644 --- a/src/detect-isdataat.h +++ b/src/detect-isdataat.h @@ -30,12 +30,11 @@ #define ISDATAAT_OFFSET_VAR 0x08 typedef struct DetectIsdataatData_ { - uint16_t dataat; /* data offset to match */ - uint8_t flags; /* isdataat options*/ + uint16_t dataat; /* data offset to match */ + uint8_t flags; /* isdataat options*/ } DetectIsdataatData; /* prototypes */ -void DetectIsdataatRegister (void); +void DetectIsdataatRegister(void); #endif /* __DETECT_ISDATAAT_H__ */ - diff --git a/src/detect-itype.c b/src/detect-itype.c index 3f8da9568aec..555856cb3272 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -34,14 +34,13 @@ #include "detect-itype.h" #include "detect-engine-uint.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" - -static int DetectITypeMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectITypeMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectITypeSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectITypeRegisterTests(void); @@ -54,7 +53,7 @@ static bool PrefilterITypeIsPrefilterable(const Signature *s); /** * \brief Registration function for itype: keyword */ -void DetectITypeRegister (void) +void DetectITypeRegister(void) { sigmatch_table[DETECT_ITYPE].name = "itype"; sigmatch_table[DETECT_ITYPE].desc = "match on a specific ICMP type"; @@ -81,8 +80,8 @@ void DetectITypeRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectITypeMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectITypeMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -131,7 +130,8 @@ static int DetectITypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *i DetectU8Data *itd = NULL; itd = DetectITypeParse(de_ctx, itypestr); - if (itd == NULL) goto error; + if (itd == NULL) + goto error; if (SigMatchAppendSMToList(de_ctx, s, DETECT_ITYPE, (SigMatchCtx *)itd, DETECT_SM_LIST_MATCH) == NULL) { @@ -164,8 +164,7 @@ void DetectITypeFree(DetectEngineCtx *de_ctx, void *ptr) * for each ICMP type. Each array element has the list of signatures * that need to be inspected. */ -static void PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const void *pectx) +static void PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { if (PKT_IS_PSEUDOPKT(p)) { SCReturn; @@ -197,7 +196,7 @@ static int PrefilterSetupIType(DetectEngineCtx *de_ctx, SigGroupHead *sgh) static bool PrefilterITypeIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ITYPE: return true; diff --git a/src/detect-krb5-cname.c b/src/detect-krb5-cname.c deleted file mode 100644 index 8664f2bc2877..000000000000 --- a/src/detect-krb5-cname.c +++ /dev/null @@ -1,204 +0,0 @@ -/* Copyright (C) 2018-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#include "suricata-common.h" -#include "util-unittest.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "detect-krb5-cname.h" - -#include "rust.h" -#include "app-layer-krb5.h" -#include "util-profiling.h" - -static int g_krb5_cname_buffer_id = 0; - -struct Krb5PrincipalNameDataArgs { - uint32_t local_id; /**< used as index into thread inspect array */ - void *txv; -}; - -static int DetectKrb5CNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_krb5_cname_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetKrb5CNameData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const struct Krb5PrincipalNameDataArgs *cbdata, int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_krb5_tx_get_cname(cbdata->txv, cbdata->local_id, &b, &b_len) != 1) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - if (b == NULL || b_len == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, b, b_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectKrb5CName(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - struct Krb5PrincipalNameDataArgs cbdata = { local_id, txv, }; - InspectionBuffer *buffer = - GetKrb5CNameData(det_ctx, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -typedef struct PrefilterMpmKrb5Name { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmKrb5Name; - -/** \brief Krb5CName Krb5CName Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxKrb5CName(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmKrb5Name *ctx = (const PrefilterMpmKrb5Name *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - - while(1) { - // loop until we get a NULL - - struct Krb5PrincipalNameDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = GetKrb5CNameData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static void PrefilterMpmKrb5NameFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmKrb5CNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmKrb5Name *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxKrb5CName, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmKrb5NameFree, mpm_reg->name); -} - -void DetectKrb5CNameRegister(void) -{ - sigmatch_table[DETECT_AL_KRB5_CNAME].name = "krb5.cname"; - sigmatch_table[DETECT_AL_KRB5_CNAME].alias = "krb5_cname"; - sigmatch_table[DETECT_AL_KRB5_CNAME].url = "/rules/kerberos-keywords.html#krb5-cname"; - sigmatch_table[DETECT_AL_KRB5_CNAME].Setup = DetectKrb5CNameSetup; - sigmatch_table[DETECT_AL_KRB5_CNAME].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - sigmatch_table[DETECT_AL_KRB5_CNAME].desc = "sticky buffer to match on Kerberos 5 client name"; - - DetectAppLayerMpmRegister2("krb5_cname", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmKrb5CNameRegister, NULL, - ALPROTO_KRB5, 1); - - DetectAppLayerInspectEngineRegister2("krb5_cname", - ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectKrb5CName, NULL); - - DetectBufferTypeSetDescriptionByName("krb5_cname", - "Kerberos 5 ticket client name"); - - g_krb5_cname_buffer_id = DetectBufferTypeGetByName("krb5_cname"); - - DetectBufferTypeSupportsMultiInstance("krb5_cname"); -} diff --git a/src/detect-krb5-errcode.c b/src/detect-krb5-errcode.c deleted file mode 100644 index f9d22cbede5d..000000000000 --- a/src/detect-krb5-errcode.c +++ /dev/null @@ -1,246 +0,0 @@ -/* Copyright (C) 2018-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#include "suricata-common.h" -#include "util-unittest.h" -#include "util-byte.h" - -#include "detect-parse.h" -#include "detect-engine.h" - -#include "detect-krb5-errcode.h" - -#include "app-layer-krb5.h" -#include "rust.h" - -/** - * \brief Regex for parsing our keyword options - */ -#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9_\\.]+\")\\s*$" -static DetectParseRegex parse_regex; - -/* Prototypes of functions registered in DetectKrb5ErrCodeRegister below */ -static int DetectKrb5ErrCodeMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); -static int DetectKrb5ErrCodeSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectKrb5ErrCodeFree (DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectKrb5ErrCodeRegisterTests (void); -#endif - -static int g_krb5_err_code_list_id = 0; - -/** - * \brief Registration function for krb5_err_code: keyword - * - * This function is called once in the 'lifetime' of the engine. - */ -void DetectKrb5ErrCodeRegister(void) -{ - sigmatch_table[DETECT_AL_KRB5_ERRCODE].name = "krb5_err_code"; - sigmatch_table[DETECT_AL_KRB5_ERRCODE].desc = "match Kerberos 5 error code"; - sigmatch_table[DETECT_AL_KRB5_ERRCODE].url = "/rules/kerberos-keywords.html#krb5-err-code"; - sigmatch_table[DETECT_AL_KRB5_ERRCODE].Match = NULL; - sigmatch_table[DETECT_AL_KRB5_ERRCODE].AppLayerTxMatch = DetectKrb5ErrCodeMatch; - sigmatch_table[DETECT_AL_KRB5_ERRCODE].Setup = DetectKrb5ErrCodeSetup; - sigmatch_table[DETECT_AL_KRB5_ERRCODE].Free = DetectKrb5ErrCodeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_KRB5_ERRCODE].RegisterTests = DetectKrb5ErrCodeRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister2("krb5_err_code", ALPROTO_KRB5, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("krb5_err_code", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - /* set up the PCRE for keyword parsing */ - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - g_krb5_err_code_list_id = DetectBufferTypeRegister("krb5_err_code"); - SCLogDebug("g_krb5_err_code_list_id %d", g_krb5_err_code_list_id); -} - -/** - * \brief This function is used to match KRB5 rule option on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch with context that we will cast into DetectKrb5Data - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectKrb5ErrCodeMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - int32_t err_code; - int ret; - const DetectKrb5ErrCodeData *dd = (const DetectKrb5ErrCodeData *)ctx; - - SCEnter(); - - ret = rs_krb5_tx_get_errcode(txv, &err_code); - if (ret != 0) - SCReturnInt(0); - - if (dd->err_code == err_code) - SCReturnInt(1); - - SCReturnInt(0); -} - -/** - * \brief This function is used to parse options passed via krb5_errcode: keyword - * - * \param krb5str Pointer to the user provided krb5_err_code options - * - * \retval krb5d pointer to DetectKrb5Data on success - * \retval NULL on failure - */ -static DetectKrb5ErrCodeData *DetectKrb5ErrCodeParse (const char *krb5str) -{ - DetectKrb5ErrCodeData *krb5d = NULL; - char arg1[4] = ""; - int res = 0; - size_t pcre2len; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, krb5str, 0, 0); - if (ret != 2) { - SCLogError("parse error, ret %" PRId32 "", ret); - goto error; - } - - pcre2len = sizeof(arg1); - res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - krb5d = SCMalloc(sizeof (DetectKrb5ErrCodeData)); - if (unlikely(krb5d == NULL)) - goto error; - if (StringParseInt32(&krb5d->err_code, 10, 0, - (const char *)arg1) < 0) { - goto error; - } - pcre2_match_data_free(match); - return krb5d; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (krb5d) - SCFree(krb5d); - return NULL; -} - -/** - * \brief parse the options from the 'krb5_err_code' keyword in the rule into - * the Signature data structure. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param krb5str pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectKrb5ErrCodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *krb5str) -{ - DetectKrb5ErrCodeData *krb5d = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) - return -1; - - krb5d = DetectKrb5ErrCodeParse(krb5str); - if (krb5d == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_KRB5_ERRCODE, (SigMatchCtx *)krb5d, - g_krb5_err_code_list_id) == NULL) { - goto error; - } - - return 0; - -error: - if (krb5d != NULL) - DetectKrb5ErrCodeFree(de_ctx, krb5d); - return -1; -} - -/** - * \brief this function will free memory associated with DetectKrb5Data - * - * \param ptr pointer to DetectKrb5Data - */ -static void DetectKrb5ErrCodeFree(DetectEngineCtx *de_ctx, void *ptr) { - DetectKrb5ErrCodeData *krb5d = (DetectKrb5ErrCodeData *)ptr; - - SCFree(krb5d); -} - -#ifdef UNITTESTS -/** - * \test description of the test - */ - -static int DetectKrb5ErrCodeParseTest01 (void) -{ - DetectKrb5ErrCodeData *krb5d = DetectKrb5ErrCodeParse("10"); - FAIL_IF_NULL(krb5d); - FAIL_IF(!(krb5d->err_code == 10)); - DetectKrb5ErrCodeFree(NULL, krb5d); - PASS; -} - -static int DetectKrb5ErrCodeSignatureTest01 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, "alert krb5 any any -> any any (krb5_err_code:10; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \brief this function registers unit tests for DetectKrb5ErrCode - */ -static void DetectKrb5ErrCodeRegisterTests(void) -{ - UtRegisterTest("DetectKrb5ErrCodeParseTest01", DetectKrb5ErrCodeParseTest01); - UtRegisterTest("DetectKrb5ErrCodeSignatureTest01", - DetectKrb5ErrCodeSignatureTest01); -} -#endif /* UNITTESTS */ diff --git a/src/detect-krb5-msgtype.c b/src/detect-krb5-msgtype.c deleted file mode 100644 index 4e2ae85848ed..000000000000 --- a/src/detect-krb5-msgtype.c +++ /dev/null @@ -1,244 +0,0 @@ -/* Copyright (C) 2018-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#include "suricata-common.h" -#include "util-unittest.h" -#include "util-byte.h" - -#include "detect-parse.h" -#include "detect-engine.h" - -#include "detect-krb5-msgtype.h" - -#include "app-layer-krb5.h" -#include "rust.h" - -/** - * \brief Regex for parsing our keyword options - */ -#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9_\\.]+\")\\s*$" -static DetectParseRegex parse_regex; - -/* Prototypes of functions registered in DetectKrb5MsgTypeRegister below */ -static int DetectKrb5MsgTypeMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); -static int DetectKrb5MsgTypeSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectKrb5MsgTypeFree (DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectKrb5MsgTypeRegisterTests (void); -#endif - -static int g_krb5_msg_type_list_id = 0; - -/** - * \brief Registration function for krb5_msg_type: keyword - * - * This function is called once in the 'lifetime' of the engine. - */ -void DetectKrb5MsgTypeRegister(void) -{ - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].name = "krb5_msg_type"; - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].desc = "match Kerberos 5 message type"; - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].url = "/rules/kerberos-keywords.html#krb5-msg-type"; - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].Match = NULL; - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].AppLayerTxMatch = DetectKrb5MsgTypeMatch; - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].Setup = DetectKrb5MsgTypeSetup; - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].Free = DetectKrb5MsgTypeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_KRB5_MSGTYPE].RegisterTests = DetectKrb5MsgTypeRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister2("krb5_msg_type", ALPROTO_KRB5, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("krb5_msg_type", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - /* set up the PCRE for keyword parsing */ - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - g_krb5_msg_type_list_id = DetectBufferTypeRegister("krb5_msg_type"); - SCLogDebug("g_krb5_msg_type_list_id %d", g_krb5_msg_type_list_id); -} - -/** - * \brief This function is used to match KRB5 rule option on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch with context that we will cast into DetectKrb5Data - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectKrb5MsgTypeMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - uint32_t msg_type; - const DetectKrb5MsgTypeData *dd = (const DetectKrb5MsgTypeData *)ctx; - - SCEnter(); - - rs_krb5_tx_get_msgtype(txv, &msg_type); - - if (dd->msg_type == msg_type) - SCReturnInt(1); - - SCReturnInt(0); -} - -/** - * \brief This function is used to parse options passed via krb5_msgtype: keyword - * - * \param krb5str Pointer to the user provided krb5_msg_type options - * - * \retval krb5d pointer to DetectKrb5Data on success - * \retval NULL on failure - */ -static DetectKrb5MsgTypeData *DetectKrb5MsgTypeParse (const char *krb5str) -{ - DetectKrb5MsgTypeData *krb5d = NULL; - char arg1[4] = ""; - int res = 0; - size_t pcre2len; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, krb5str, 0, 0); - if (ret != 2) { - SCLogError("parse error, ret %" PRId32 "", ret); - goto error; - } - - pcre2len = sizeof(arg1); - res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - krb5d = SCMalloc(sizeof (DetectKrb5MsgTypeData)); - if (unlikely(krb5d == NULL)) - goto error; - if (StringParseUint8(&krb5d->msg_type, 10, 0, - (const char *)arg1) < 0) { - goto error; - } - pcre2_match_data_free(match); - return krb5d; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (krb5d) - SCFree(krb5d); - return NULL; -} - -/** - * \brief parse the options from the 'krb5_msg_type' keyword in the rule into - * the Signature data structure. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param krb5str pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectKrb5MsgTypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *krb5str) -{ - DetectKrb5MsgTypeData *krb5d = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) - return -1; - - krb5d = DetectKrb5MsgTypeParse(krb5str); - if (krb5d == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_KRB5_MSGTYPE, (SigMatchCtx *)krb5d, - g_krb5_msg_type_list_id) == NULL) { - goto error; - } - - return 0; - -error: - if (krb5d != NULL) - DetectKrb5MsgTypeFree(de_ctx, krb5d); - return -1; -} - -/** - * \brief this function will free memory associated with DetectKrb5Data - * - * \param ptr pointer to DetectKrb5Data - */ -static void DetectKrb5MsgTypeFree(DetectEngineCtx *de_ctx, void *ptr) { - DetectKrb5MsgTypeData *krb5d = (DetectKrb5MsgTypeData *)ptr; - - SCFree(krb5d); -} - -#ifdef UNITTESTS - -/** - * \test description of the test - */ - -static int DetectKrb5MsgTypeParseTest01 (void) -{ - DetectKrb5MsgTypeData *krb5d = DetectKrb5MsgTypeParse("10"); - FAIL_IF_NULL(krb5d); - FAIL_IF(!(krb5d->msg_type == 10)); - DetectKrb5MsgTypeFree(NULL, krb5d); - PASS; -} - -static int DetectKrb5MsgTypeSignatureTest01 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, "alert krb5 any any -> any any (krb5_msg_type:10; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \brief this function registers unit tests for DetectKrb5MsgType - */ -static void DetectKrb5MsgTypeRegisterTests(void) -{ - UtRegisterTest("DetectKrb5MsgTypeParseTest01", DetectKrb5MsgTypeParseTest01); - UtRegisterTest("DetectKrb5MsgTypeSignatureTest01", - DetectKrb5MsgTypeSignatureTest01); -} -#endif /* UNITTESTS */ diff --git a/src/detect-krb5-sname.c b/src/detect-krb5-sname.c deleted file mode 100644 index 1e4ae24a4bd1..000000000000 --- a/src/detect-krb5-sname.c +++ /dev/null @@ -1,205 +0,0 @@ -/* Copyright (C) 2018-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#include "suricata-common.h" -#include "util-unittest.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "detect-krb5-sname.h" - -#include "rust.h" -#include "app-layer-krb5.h" -#include "util-profiling.h" - -static int g_krb5_sname_buffer_id = 0; - -struct Krb5PrincipalNameDataArgs { - uint32_t local_id; /**< used as index into thread inspect array */ - void *txv; -}; - -static int DetectKrb5SNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_krb5_sname_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetKrb5SNameData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const struct Krb5PrincipalNameDataArgs *cbdata, int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_krb5_tx_get_sname(cbdata->txv, cbdata->local_id, &b, &b_len) != 1) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - if (b == NULL || b_len == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, b, b_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectKrb5SName(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - struct Krb5PrincipalNameDataArgs cbdata = { local_id, txv, }; - InspectionBuffer *buffer = - GetKrb5SNameData(det_ctx, transforms, f, &cbdata, engine->sm_list); - - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -typedef struct PrefilterMpmKrb5Name { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmKrb5Name; - -/** \brief Krb5SName Krb5SName Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxKrb5SName(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmKrb5Name *ctx = (const PrefilterMpmKrb5Name *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - - while(1) { - // loop until we get a NULL - - struct Krb5PrincipalNameDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = GetKrb5SNameData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static void PrefilterMpmKrb5NameFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmKrb5SNameRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmKrb5Name *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxKrb5SName, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmKrb5NameFree, mpm_reg->name); -} - -void DetectKrb5SNameRegister(void) -{ - sigmatch_table[DETECT_AL_KRB5_SNAME].name = "krb5.sname"; - sigmatch_table[DETECT_AL_KRB5_SNAME].alias = "krb5_sname"; - sigmatch_table[DETECT_AL_KRB5_SNAME].url = "/rules/kerberos-keywords.html#krb5-sname"; - sigmatch_table[DETECT_AL_KRB5_SNAME].Setup = DetectKrb5SNameSetup; - sigmatch_table[DETECT_AL_KRB5_SNAME].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - sigmatch_table[DETECT_AL_KRB5_SNAME].desc = "sticky buffer to match on Kerberos 5 server name"; - - DetectAppLayerMpmRegister2("krb5_sname", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmKrb5SNameRegister, NULL, - ALPROTO_KRB5, 1); - - DetectAppLayerInspectEngineRegister2("krb5_sname", - ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectKrb5SName, NULL); - - DetectBufferTypeSetDescriptionByName("krb5_sname", - "Kerberos 5 ticket server name"); - - g_krb5_sname_buffer_id = DetectBufferTypeGetByName("krb5_sname"); - - DetectBufferTypeSupportsMultiInstance("krb5_sname"); -} diff --git a/src/detect-krb5-ticket-encryption.c b/src/detect-krb5-ticket-encryption.c deleted file mode 100644 index e3550084ffb6..000000000000 --- a/src/detect-krb5-ticket-encryption.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "rust.h" - -#include "detect-krb5-ticket-encryption.h" - -#include "detect-engine.h" -#include "detect-parse.h" - -static int g_krb5_ticket_encryption_list_id = 0; - -static void DetectKrb5TicketEncryptionFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_krb5_detect_encryption_free(ptr); -} - -static int DetectKrb5TicketEncryptionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - const DetectKrb5TicketEncryptionData *dd = (const DetectKrb5TicketEncryptionData *)ctx; - - SCEnter(); - - SCReturnInt(rs_krb5_detect_encryption_match(txv, dd)); -} - -static int DetectKrb5TicketEncryptionSetup( - DetectEngineCtx *de_ctx, Signature *s, const char *krb5str) -{ - DetectKrb5TicketEncryptionData *krb5d = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0) - return -1; - - krb5d = rs_krb5_detect_encryption_parse(krb5str); - if (krb5d == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_KRB5_TICKET_ENCRYPTION, (SigMatchCtx *)krb5d, - g_krb5_ticket_encryption_list_id) == NULL) { - goto error; - } - - return 0; - -error: - if (krb5d != NULL) - DetectKrb5TicketEncryptionFree(de_ctx, krb5d); - return -1; -} - -void DetectKrb5TicketEncryptionRegister(void) -{ - sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].name = "krb5.ticket_encryption"; - sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].desc = "match Kerberos 5 ticket encryption"; - sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].url = - "/rules/kerberos-keywords.html#krb5-ticket-encryption"; - sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].Match = NULL; - sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].AppLayerTxMatch = - DetectKrb5TicketEncryptionMatch; - sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].Setup = DetectKrb5TicketEncryptionSetup; - sigmatch_table[DETECT_AL_KRB5_TICKET_ENCRYPTION].Free = DetectKrb5TicketEncryptionFree; - - // Tickets are only from server to client - DetectAppLayerInspectEngineRegister2("krb5_ticket_encryption", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, - 0, DetectEngineInspectGenericList, NULL); - - g_krb5_ticket_encryption_list_id = DetectBufferTypeRegister("krb5_ticket_encryption"); - SCLogDebug("g_krb5_ticket_encryption_list_id %d", g_krb5_ticket_encryption_list_id); -} diff --git a/src/detect-l3proto.c b/src/detect-l3proto.c index 6e08cf978b78..a3dc379a8cfa 100644 --- a/src/detect-l3proto.c +++ b/src/detect-l3proto.c @@ -40,11 +40,11 @@ #include "detect-l3proto.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" -#include "util-debug.h" +#include "util/debug.h" static int DetectL3ProtoSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS @@ -56,7 +56,7 @@ void DetectL3ProtoRegister(void) sigmatch_table[DETECT_L3PROTO].name = "l3_proto"; sigmatch_table[DETECT_L3PROTO].Match = NULL; sigmatch_table[DETECT_L3PROTO].Setup = DetectL3ProtoSetup; - sigmatch_table[DETECT_L3PROTO].Free = NULL; + sigmatch_table[DETECT_L3PROTO].Free = NULL; #ifdef UNITTESTS sigmatch_table[DETECT_L3PROTO].RegisterTests = DetectL3protoRegisterTests; #endif @@ -81,16 +81,14 @@ static int DetectL3ProtoSetup(DetectEngineCtx *de_ctx, Signature *s, const char } /* authorized value, ip, any, ip4, ipv4, ip6, ipv6 */ - if (strcasecmp(str,"ipv4") == 0 || - strcasecmp(str,"ip4") == 0 ) { + if (strcasecmp(str, "ipv4") == 0 || strcasecmp(str, "ip4") == 0) { if (s->proto.flags & DETECT_PROTO_IPV6) { SCLogError("Conflicting l3 proto specified"); goto error; } s->proto.flags |= DETECT_PROTO_IPV4; SCLogDebug("IPv4 protocol detected"); - } else if (strcasecmp(str,"ipv6") == 0 || - strcasecmp(str,"ip6") == 0 ) { + } else if (strcasecmp(str, "ipv6") == 0 || strcasecmp(str, "ip6") == 0) { if (s->proto.flags & DETECT_PROTO_IPV6) { SCLogError("Conflicting l3 proto specified"); goto error; diff --git a/src/detect-l3proto.h b/src/detect-l3proto.h index 447cd95d0925..3b8e4c1c9881 100644 --- a/src/detect-l3proto.h +++ b/src/detect-l3proto.h @@ -28,6 +28,6 @@ /** * \brief Registration function for ip_proto keyword. */ -void DetectL3ProtoRegister (void); +void DetectL3ProtoRegister(void); #endif /* __DETECT_L3PROTO_H__ */ diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 897b0874021a..933481eb4494 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -41,12 +41,12 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-print.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/print.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer.h" @@ -55,22 +55,22 @@ #include "detect-lua.h" #include "queue.h" -#include "util-cpu.h" +#include "util/cpu.h" #include "app-layer-parser.h" #ifdef HAVE_LUA -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-http.h" -#include "util-lua-dns.h" -#include "util-lua-ja3.h" -#include "util-lua-tls.h" -#include "util-lua-ssh.h" -#include "util-lua-hassh.h" -#include "util-lua-smtp.h" -#include "util-lua-dnp3.h" +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/http/lua.h" +#include "app-layer/dns/lua.h" +#include "util/lua/lua-ja3.h" +#include "app-layer/tls/lua.h" +#include "app-layer/ssh/lua.h" +#include "app-layer/ssh/lua-hassh.h" +#include "app-layer/smtp/lua.h" +#include "app-layer/dnp3/lua.h" #include "detect-lua-extensions.h" static const char luaext_key_ld[] = "suricata:luadata"; @@ -78,8 +78,8 @@ static const char luaext_key_ld[] = "suricata:luadata"; /* hack to please scan-build. Even though LuaCallbackError *always* * returns 2, scan-build doesn't accept it and generates false * positives */ -#define LUA_ERROR(msg) \ - LuaCallbackError(luastate, (msg)); \ +#define LUA_ERROR(msg) \ + LuaCallbackError(luastate, (msg)); \ return 2 static int GetLuaData(lua_State *luastate, DetectLuaData **ret_ld) @@ -107,8 +107,8 @@ static int GetFlow(lua_State *luastate, Flow **ret_f) return 0; } -static int GetFlowVarById(lua_State *luastate, Flow *f, - FlowVar **ret_fv, bool fv_may_be_null, uint32_t *ret_idx) +static int GetFlowVarById( + lua_State *luastate, Flow *f, FlowVar **ret_fv, bool fv_may_be_null, uint32_t *ret_idx) { DetectLuaData *ld = NULL; if (ret_idx) @@ -168,8 +168,8 @@ static int GetFlowVarByKey(lua_State *luastate, Flow *f, FlowVar **ret_fv) return 0; } -static int GetFlowIntById(lua_State *luastate, Flow *f, - FlowVar **ret_fv, bool fv_may_be_null, uint32_t *ret_idx) +static int GetFlowIntById( + lua_State *luastate, Flow *f, FlowVar **ret_fv, bool fv_may_be_null, uint32_t *ret_idx) { DetectLuaData *ld = NULL; if (ret_idx) @@ -225,9 +225,8 @@ static int LuaGetFlowvar(lua_State *luastate) LUA_ERROR("invalid data type as first argument"); } - LuaPushStringBuffer(luastate, - (const uint8_t *)fv->data.fv_str.value, - (size_t)fv->data.fv_str.value_len); + LuaPushStringBuffer( + luastate, (const uint8_t *)fv->data.fv_str.value, (size_t)fv->data.fv_str.value_len); return 1; } @@ -265,7 +264,7 @@ static int LuaSetFlowvarById(lua_State *luastate) LUA_ERROR("len out of range: max 64k"); } - buffer = SCMalloc(len+1); + buffer = SCMalloc(len + 1); if (unlikely(buffer == NULL)) { LUA_ERROR("out of memory"); } @@ -319,14 +318,14 @@ static int LuaSetFlowvarByKey(lua_State *luastate) LUA_ERROR("len out of range: max 64k"); } - buffer = SCMalloc(len+1); + buffer = SCMalloc(len + 1); if (unlikely(buffer == NULL)) { LUA_ERROR("out of memory"); } memcpy(buffer, str, len); buffer[len] = '\0'; - uint8_t *keybuf = SCMalloc(keylen+1); + uint8_t *keybuf = SCMalloc(keylen + 1); if (unlikely(keybuf == NULL)) { SCFree(buffer); LUA_ERROR("out of memory"); @@ -367,7 +366,6 @@ static int LuaGetFlowint(lua_State *luastate) /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); return 1; - } static int LuaSetFlowint(lua_State *luastate) @@ -401,7 +399,7 @@ static int LuaSetFlowint(lua_State *luastate) lua_Number luanumber = lua_tonumber(luastate, 2); if (luanumber < 0 || id > (double)UINT_MAX) { LUA_ERROR("value out of range, " - "value must be unsigned 32bit int"); + "value must be unsigned 32bit int"); } uint32_t number = (uint32_t)luanumber; @@ -445,7 +443,6 @@ static int LuaIncrFlowint(lua_State *luastate) lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("incremented flow:%p idx:%u value:%u", f, idx, number); return 1; - } static int LuaDecrFlowint(lua_State *luastate) @@ -477,7 +474,6 @@ static int LuaDecrFlowint(lua_State *luastate) lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("decremented flow:%p idx:%u value:%u", f, idx, number); return 1; - } static int LuaGetByteVar(lua_State *luastate) diff --git a/src/detect-lua.c b/src/detect-lua.c index 0ea74452739e..3587ba518cd6 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -42,17 +42,17 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-print.h" -#include "util-byte.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/print.h" +#include "util/byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "stream-tcp.h" @@ -60,12 +60,12 @@ #include "detect-lua-extensions.h" #include "queue.h" -#include "util-cpu.h" -#include "util-var-name.h" +#include "util/cpu.h" +#include "util/var-name.h" #ifndef HAVE_LUA -static int DetectLuaSetupNoSupport (DetectEngineCtx *a, Signature *b, const char *c) +static int DetectLuaSetupNoSupport(DetectEngineCtx *a, Signature *b, const char *c) { SCLogError("no Lua support built in, needed for lua/luajit keyword"); return -1; @@ -81,24 +81,22 @@ void DetectLuaRegister(void) sigmatch_table[DETECT_LUA].desc = "support for lua scripting"; sigmatch_table[DETECT_LUA].url = "/rules/rule-lua-scripting.html"; sigmatch_table[DETECT_LUA].Setup = DetectLuaSetupNoSupport; - sigmatch_table[DETECT_LUA].Free = NULL; + sigmatch_table[DETECT_LUA].Free = NULL; sigmatch_table[DETECT_LUA].flags = SIGMATCH_NOT_BUILT; - SCLogDebug("registering lua rule option"); + SCLogDebug("registering lua rule option"); return; } #else /* HAVE_LUA */ -#include "util-lua.h" +#include "util/lua/lua.h" -static int DetectLuaMatch (DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); -static int DetectLuaAppTxMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectLuaSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectLuaMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectLuaAppTxMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx); +static int DetectLuaSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectLuaRegisterTests(void); #endif @@ -117,7 +115,7 @@ void DetectLuaRegister(void) sigmatch_table[DETECT_LUA].Match = DetectLuaMatch; sigmatch_table[DETECT_LUA].AppLayerTxMatch = DetectLuaAppTxMatch; sigmatch_table[DETECT_LUA].Setup = DetectLuaSetup; - sigmatch_table[DETECT_LUA].Free = DetectLuaFree; + sigmatch_table[DETECT_LUA].Free = DetectLuaFree; #ifdef UNITTESTS sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests; #endif @@ -202,9 +200,8 @@ void LuaDumpStack(lua_State *state) } #endif -int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatchData *smd, - const uint8_t *buffer, uint32_t buffer_len, uint32_t offset, +int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, const Signature *s, + const SigMatchData *smd, const uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f) { SCEnter(); @@ -217,7 +214,8 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + DetectLuaThreadData *tlua = + (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); if (tlua == NULL) SCReturnInt(0); @@ -227,11 +225,11 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, lua_getglobal(tlua->luastate, "match"); lua_newtable(tlua->luastate); /* stack at -1 */ - lua_pushliteral (tlua->luastate, "offset"); /* stack at -2 */ - lua_pushnumber (tlua->luastate, (int)(offset + 1)); + lua_pushliteral(tlua->luastate, "offset"); /* stack at -2 */ + lua_pushnumber(tlua->luastate, (int)(offset + 1)); lua_settable(tlua->luastate, -3); - lua_pushstring (tlua->luastate, lua->buffername); /* stack at -2 */ + lua_pushstring(tlua->luastate, lua->buffername); /* stack at -2 */ LuaPushStringBuffer(tlua->luastate, (const uint8_t *)buffer, (size_t)buffer_len); lua_settable(tlua->luastate, -3); @@ -251,7 +249,7 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, if (script_ret == 1.0) ret = 1; - /* script returns a table */ + /* script returns a table */ } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { lua_pushnil(tlua->luastate); const char *k, *v; @@ -272,8 +270,7 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, "for \"retval\" from LUA return table: '%s'", v); ret = 0; - } - else if (val == 1) { + } else if (val == 1) { ret = 1; } } else { @@ -315,8 +312,8 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, * \retval 0 no match * \retval 1 match */ -static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectLuaMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; @@ -324,7 +321,8 @@ static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx, if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + DetectLuaThreadData *tlua = + (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); if (tlua == NULL) SCReturnInt(0); @@ -357,32 +355,33 @@ static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx, if ((tlua->flags & DATATYPE_PAYLOAD) && p->payload_len) { lua_pushliteral(tlua->luastate, "payload"); /* stack at -2 */ - LuaPushStringBuffer (tlua->luastate, (const uint8_t *)p->payload, (size_t)p->payload_len); /* stack at -3 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)p->payload, + (size_t)p->payload_len); /* stack at -3 */ lua_settable(tlua->luastate, -3); } if ((tlua->flags & DATATYPE_PACKET) && GET_PKT_LEN(p)) { lua_pushliteral(tlua->luastate, "packet"); /* stack at -2 */ - LuaPushStringBuffer (tlua->luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)GET_PKT_DATA(p), + (size_t)GET_PKT_LEN(p)); /* stack at -3 */ lua_settable(tlua->luastate, -3); } if (tlua->alproto == ALPROTO_HTTP1) { HtpState *htp_state = p->flow->alstate; if (htp_state != NULL && htp_state->connp != NULL) { htp_tx_t *tx = NULL; - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, - STREAM_TOSERVER); - uint64_t total_txs= AppLayerParserGetTxCnt(p->flow, htp_state); - for ( ; idx < total_txs; idx++) { + uint64_t idx = + AppLayerParserGetTransactionInspectId(p->flow->alparser, STREAM_TOSERVER); + uint64_t total_txs = AppLayerParserGetTxCnt(p->flow, htp_state); + for (; idx < total_txs; idx++) { tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, idx); if (tx == NULL) continue; if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && - bstr_len(tx->request_line) > 0) { + bstr_len(tx->request_line) > 0) { lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */ - LuaPushStringBuffer(tlua->luastate, - (const uint8_t *)bstr_ptr(tx->request_line), - bstr_len(tx->request_line)); + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)bstr_ptr(tx->request_line), + bstr_len(tx->request_line)); lua_settable(tlua->luastate, -3); } } @@ -406,7 +405,7 @@ static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx, if (script_ret == 1.0) ret = 1; - /* script returns a table */ + /* script returns a table */ } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { lua_pushnil(tlua->luastate); const char *k, *v; @@ -422,14 +421,12 @@ static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx, if (strcmp(k, "retval") == 0) { int val; - if (StringParseInt32(&val, 10, 0, - (const char *)v) < 0) { + if (StringParseInt32(&val, 10, 0, (const char *)v) < 0) { SCLogError("Invalid value " "for \"retval\" from LUA return table: '%s'", v); ret = 0; - } - else if (val == 1) { + } else if (val == 1) { ret = 1; } } else { @@ -455,9 +452,8 @@ static int DetectLuaMatch (DetectEngineThreadCtx *det_ctx, SCReturnInt(ret); } -static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - const Signature *s, const SigMatchCtx *ctx) +static int DetectLuaAppMatchCommon(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, + void *state, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; @@ -465,7 +461,8 @@ static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx, if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + DetectLuaThreadData *tlua = + (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); if (tlua == NULL) SCReturnInt(0); @@ -488,11 +485,10 @@ static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx, tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, det_ctx->tx_id); if (tx != NULL) { if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && - bstr_len(tx->request_line) > 0) { + bstr_len(tx->request_line) > 0) { lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */ - LuaPushStringBuffer(tlua->luastate, - (const uint8_t *)bstr_ptr(tx->request_line), - bstr_len(tx->request_line)); + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)bstr_ptr(tx->request_line), + bstr_len(tx->request_line)); lua_settable(tlua->luastate, -3); } } @@ -516,7 +512,7 @@ static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx, if (script_ret == 1.0) ret = 1; - /* script returns a table */ + /* script returns a table */ } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { lua_pushnil(tlua->luastate); const char *k, *v; @@ -532,14 +528,12 @@ static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx, if (strcmp(k, "retval") == 0) { int val; - if (StringParseInt32(&val, 10, 0, - (const char *)v) < 0) { + if (StringParseInt32(&val, 10, 0, (const char *)v) < 0) { SCLogError("Invalid value " "for \"retval\" from LUA return table: '%s'", v); ret = 0; - } - else if (val == 1) { + } else if (val == 1) { ret = 1; } } else { @@ -576,10 +570,8 @@ static int DetectLuaAppMatchCommon (DetectEngineThreadCtx *det_ctx, * \retval 0 no match * \retval 1 match */ -static int DetectLuaAppTxMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) +static int DetectLuaAppTxMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, const SigMatchCtx *ctx) { return DetectLuaAppMatchCommon(det_ctx, f, flags, state, s, ctx); } @@ -675,7 +667,7 @@ static void DetectLuaThreadFree(void *ctx) * \retval lua pointer to DetectLuaData on success * \retval NULL on failure */ -static DetectLuaData *DetectLuaParse (DetectEngineCtx *de_ctx, const char *str) +static DetectLuaData *DetectLuaParse(DetectEngineCtx *de_ctx, const char *str) { DetectLuaData *lua = NULL; @@ -750,7 +742,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const } lua_pushliteral(luastate, "script_api_ver"); /* stack at -2 */ - lua_pushnumber (luastate, 1); /* stack at -3 */ + lua_pushnumber(luastate, 1); /* stack at -3 */ lua_settable(luastate, -3); if (lua_pcall(luastate, 1, 1, 0) != 0) { @@ -1007,7 +999,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const * \retval 0 on Success * \retval -1 on Failure */ -static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) +static int DetectLuaSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) { DetectLuaData *lua = NULL; @@ -1028,9 +1020,8 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, const char *st goto error; } - lua->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "lua", - DetectLuaThreadInit, (void *)lua, - DetectLuaThreadFree, 0); + lua->thread_ctx_id = DetectRegisterThreadCtxFuncs( + de_ctx, "lua", DetectLuaThreadInit, (void *)lua, DetectLuaThreadFree, 0); if (lua->thread_ctx_id == -1) goto error; @@ -1070,14 +1061,14 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, const char *st } else if (lua->flags & DATATYPE_HTTP_URI_RAW) { list = DetectBufferTypeGetByName("http_raw_uri"); } else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE || - lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) - { + lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) { list = DetectBufferTypeGetByName("http_cookie"); } else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) { list = DetectBufferTypeGetByName("http_user_agent"); - } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) { + } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS | DATATYPE_HTTP_RESPONSE_HEADERS)) { list = DetectBufferTypeGetByName("http_header"); - } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) { + } else if (lua->flags & + (DATATYPE_HTTP_REQUEST_HEADERS_RAW | DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) { list = DetectBufferTypeGetByName("http_raw_header"); } else { list = DetectBufferTypeGetByName("http_request_line"); @@ -1177,41 +1168,38 @@ static int LuaMatchTest01(void) { ConfSetFinal("security.lua.allow-rules", "true"); - const char script[] = - "function init (args)\n" - " local needs = {}\n" - " needs[\"http.request_headers\"] = tostring(true)\n" - " needs[\"flowvar\"] = {\"cnt\"}\n" - " return needs\n" - "end\n" - "\n" - "function match(args)\n" - " a = ScFlowvarGet(0)\n" - " if a then\n" - " a = tostring(tonumber(a)+1)\n" - " print (a)\n" - " ScFlowvarSet(0, a, #a)\n" - " else\n" - " a = tostring(1)\n" - " print (a)\n" - " ScFlowvarSet(0, a, #a)\n" - " end\n" - " \n" - " print (\"pre check: \" .. (a))\n" - " if tonumber(a) == 2 then\n" - " print \"match\"\n" - " return 1\n" - " end\n" - " return 0\n" - "end\n" - "return 0\n"; + const char script[] = "function init (args)\n" + " local needs = {}\n" + " needs[\"http.request_headers\"] = tostring(true)\n" + " needs[\"flowvar\"] = {\"cnt\"}\n" + " return needs\n" + "end\n" + "\n" + "function match(args)\n" + " a = ScFlowvarGet(0)\n" + " if a then\n" + " a = tostring(tonumber(a)+1)\n" + " print (a)\n" + " ScFlowvarSet(0, a, #a)\n" + " else\n" + " a = tostring(1)\n" + " print (a)\n" + " ScFlowvarSet(0, a, #a)\n" + " end\n" + " \n" + " print (\"pre check: \" .. (a))\n" + " if tonumber(a) == 2 then\n" + " print \"match\"\n" + " return 1\n" + " end\n" + " return 0\n" + "end\n" + "return 0\n"; char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; - uint8_t httpbuf1[] = - "POST / HTTP/1.1\r\n" - "Host: www.emergingthreats.net\r\n\r\n"; - uint8_t httpbuf2[] = - "POST / HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n\r\n"; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" + "Host: www.emergingthreats.net\r\n\r\n"; + uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; @@ -1239,11 +1227,11 @@ static int LuaMatchTest01(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -1986,12 +1974,10 @@ static int LuaMatchTest04a(void) "end\n" "return 0\n"; char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; - uint8_t httpbuf1[] = - "POST / HTTP/1.1\r\n" - "Host: www.emergingthreats.net\r\n\r\n"; - uint8_t httpbuf2[] = - "POST / HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n\r\n"; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" + "Host: www.emergingthreats.net\r\n\r\n"; + uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; @@ -2019,12 +2005,12 @@ static int LuaMatchTest04a(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -2097,12 +2083,10 @@ static int LuaMatchTest05(void) "end\n" "return 0\n"; char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; - uint8_t httpbuf1[] = - "POST / HTTP/1.1\r\n" - "Host: www.emergingthreats.net\r\n\r\n"; - uint8_t httpbuf2[] = - "POST / HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n\r\n"; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" + "Host: www.emergingthreats.net\r\n\r\n"; + uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; @@ -2130,12 +2114,12 @@ static int LuaMatchTest05(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -2208,12 +2192,10 @@ static int LuaMatchTest05a(void) "end\n" "return 0\n"; char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; - uint8_t httpbuf1[] = - "POST / HTTP/1.1\r\n" - "Host: www.emergingthreats.net\r\n\r\n"; - uint8_t httpbuf2[] = - "POST / HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n\r\n"; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" + "Host: www.emergingthreats.net\r\n\r\n"; + uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; @@ -2241,12 +2223,12 @@ static int LuaMatchTest05a(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -2324,12 +2306,10 @@ static int LuaMatchTest06(void) "end\n" "return 0\n"; char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; - uint8_t httpbuf1[] = - "POST / HTTP/1.1\r\n" - "Host: www.emergingthreats.net\r\n\r\n"; - uint8_t httpbuf2[] = - "POST / HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n\r\n"; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" + "Host: www.emergingthreats.net\r\n\r\n"; + uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; @@ -2357,12 +2337,12 @@ static int LuaMatchTest06(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -2440,12 +2420,10 @@ static int LuaMatchTest06a(void) "end\n" "return 0\n"; char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; - uint8_t httpbuf1[] = - "POST / HTTP/1.1\r\n" - "Host: www.emergingthreats.net\r\n\r\n"; - uint8_t httpbuf2[] = - "POST / HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n\r\n"; + uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" + "Host: www.emergingthreats.net\r\n\r\n"; + uint8_t httpbuf2[] = "POST / HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ TcpSession ssn; @@ -2473,12 +2451,12 @@ static int LuaMatchTest06a(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); diff --git a/src/detect-lua.h b/src/detect-lua.h index dcf99b6c3f43..3085e2fd3c13 100644 --- a/src/detect-lua.h +++ b/src/detect-lua.h @@ -26,7 +26,7 @@ #ifdef HAVE_LUA -#include "util-lua.h" +#include "util/lua/lua.h" typedef struct DetectLuaThreadData { lua_State *luastate; @@ -34,9 +34,9 @@ typedef struct DetectLuaThreadData { int alproto; } DetectLuaThreadData; -#define DETECT_LUAJIT_MAX_FLOWVARS 15 -#define DETECT_LUAJIT_MAX_FLOWINTS 15 -#define DETECT_LUAJIT_MAX_BYTEVARS 15 +#define DETECT_LUAJIT_MAX_FLOWVARS 15 +#define DETECT_LUAJIT_MAX_FLOWINTS 15 +#define DETECT_LUAJIT_MAX_BYTEVARS 15 typedef struct DetectLuaData { int thread_ctx_id; @@ -59,10 +59,9 @@ typedef struct DetectLuaData { #endif /* HAVE_LUA */ /* prototypes */ -void DetectLuaRegister (void); -int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, - const Signature *s, const SigMatchData *smd, - const uint8_t *buffer, uint32_t buffer_len, uint32_t offset, +void DetectLuaRegister(void); +int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, const Signature *s, + const SigMatchData *smd, const uint8_t *buffer, uint32_t buffer_len, uint32_t offset, Flow *f); void DetectLuaPostSetup(Signature *s); diff --git a/src/detect-mark.c b/src/detect-mark.c index 90ed7750a4e5..7ca19e2b5649 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -34,16 +34,16 @@ #include "detect-mark.h" #include "detect-parse.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/debug.h" #define PARSE_REGEX "([0x]*[0-9a-f]+)/([0x]*[0-9a-f]+)" static DetectParseRegex parse_regex; -static int DetectMarkSetup (DetectEngineCtx *, Signature *, const char *); -static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx); +static int DetectMarkSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectMarkPacket( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); void DetectMarkDataFree(DetectEngineCtx *, void *ptr); #if defined UNITTESTS && defined NFQ static void MarkRegisterTests(void); @@ -53,12 +53,12 @@ static void MarkRegisterTests(void); * \brief Registration function for nfq_set_mark: keyword */ -void DetectMarkRegister (void) +void DetectMarkRegister(void) { sigmatch_table[DETECT_MARK].name = "nfq_set_mark"; sigmatch_table[DETECT_MARK].Match = DetectMarkPacket; sigmatch_table[DETECT_MARK].Setup = DetectMarkSetup; - sigmatch_table[DETECT_MARK].Free = DetectMarkDataFree; + sigmatch_table[DETECT_MARK].Free = DetectMarkDataFree; #if defined UNITTESTS && defined NFQ sigmatch_table[DETECT_MARK].RegisterTests = MarkRegisterTests; #endif @@ -75,7 +75,7 @@ void DetectMarkRegister (void) * \retval 0 on success * \retval < 0 on failure */ -static void * DetectMarkParse (const char *rawstr) +static void *DetectMarkParse(const char *rawstr) { int res = 0; size_t pcre2_len; @@ -111,8 +111,8 @@ static void * DetectMarkParse (const char *rawstr) SCLogError("Numeric value out of range"); pcre2_substring_free((PCRE2_UCHAR8 *)ptr); goto error; - } /* If there is no numeric value in the given string then strtoull(), makes - endptr equals to ptr and return 0 as result */ + } /* If there is no numeric value in the given string then strtoull(), makes + endptr equals to ptr and return 0 as result */ else if (endptr == ptr && mark == 0) { SCLogError("No numeric value"); pcre2_substring_free((PCRE2_UCHAR8 *)ptr); @@ -149,14 +149,13 @@ static void * DetectMarkParse (const char *rawstr) SCLogError("Numeric value out of range"); pcre2_substring_free((PCRE2_UCHAR8 *)ptr); goto error; - } /* If there is no numeric value in the given string then strtoull(), makes - endptr equals to ptr and return 0 as result */ + } /* If there is no numeric value in the given string then strtoull(), makes + endptr equals to ptr and return 0 as result */ else if (endptr == ptr && mask == 0) { SCLogError("No numeric value"); pcre2_substring_free((PCRE2_UCHAR8 *)ptr); goto error; - } - else if (endptr == ptr) { + } else if (endptr == ptr) { SCLogError("Invalid numeric value"); pcre2_substring_free((PCRE2_UCHAR8 *)ptr); goto error; @@ -194,7 +193,7 @@ static void * DetectMarkParse (const char *rawstr) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectMarkSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { #ifndef NFQ return 0; @@ -221,17 +220,15 @@ void DetectMarkDataFree(DetectEngineCtx *de_ctx, void *ptr) SCFree(data); } - -static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectMarkPacket( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { #ifdef NFQ const DetectMarkData *nf_data = (const DetectMarkData *)ctx; if (nf_data->mask) { if (!(IS_TUNNEL_PKT(p))) { /* coverity[missing_lock] */ - p->nfq_v.mark = (nf_data->mark & nf_data->mask) - | (p->nfq_v.mark & ~(nf_data->mask)); + p->nfq_v.mark = (nf_data->mark & nf_data->mask) | (p->nfq_v.mark & ~(nf_data->mask)); p->flags |= PKT_MARK_MODIFIED; } else { /* real tunnels may have multiple flows inside them, so marking @@ -240,8 +237,8 @@ static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p, if (p->flags & PKT_REBUILT_FRAGMENT) { Packet *tp = p->root ? p->root : p; SCSpinLock(&tp->persistent.tunnel_lock); - tp->nfq_v.mark = (nf_data->mark & nf_data->mask) - | (tp->nfq_v.mark & ~(nf_data->mask)); + tp->nfq_v.mark = + (nf_data->mark & nf_data->mask) | (tp->nfq_v.mark & ~(nf_data->mask)); tp->flags |= PKT_MARK_MODIFIED; SCSpinUnlock(&tp->persistent.tunnel_lock); } @@ -260,7 +257,7 @@ static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p, * \test MarkTestParse01 is a test for a valid mark value * */ -static int MarkTestParse01 (void) +static int MarkTestParse01(void) { DetectMarkData *data; @@ -276,7 +273,7 @@ static int MarkTestParse01 (void) * \test MarkTestParse02 is a test for an invalid mark value * */ -static int MarkTestParse02 (void) +static int MarkTestParse02(void) { DetectMarkData *data; @@ -292,7 +289,7 @@ static int MarkTestParse02 (void) * \test MarkTestParse03 is a test for a valid mark value * */ -static int MarkTestParse03 (void) +static int MarkTestParse03(void) { DetectMarkData *data; @@ -308,7 +305,7 @@ static int MarkTestParse03 (void) * \test MarkTestParse04 is a test for a invalid mark value * */ -static int MarkTestParse04 (void) +static int MarkTestParse04(void) { DetectMarkData *data; diff --git a/src/detect-mark.h b/src/detect-mark.h index b8de378fd20d..f97299b5fff0 100644 --- a/src/detect-mark.h +++ b/src/detect-mark.h @@ -28,7 +28,6 @@ #ifndef __DETECT_MARK_H__ #define __DETECT_MARK_H__ - /** * \struct DetectMarkData_ * DetectMarkData_ is used to store nfq_set_mark: input value @@ -40,14 +39,14 @@ */ typedef struct DetectMarkData_ { - uint32_t mark; /**< Rule mark */ - uint32_t mask; /**< Rule mask */ + uint32_t mark; /**< Rule mark */ + uint32_t mask; /**< Rule mask */ } DetectMarkData; /** * Registration function for nfq_set_mark: keyword */ -void DetectMarkRegister (void); +void DetectMarkRegister(void); #endif /*__DETECT_MARK_H__ */ diff --git a/src/detect-metadata.c b/src/detect-metadata.c index 6c6c8de7ff72..0f00685f00bb 100644 --- a/src/detect-metadata.c +++ b/src/detect-metadata.c @@ -31,24 +31,24 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-metadata.h" -#include "util-hash-string.h" -#include "util-unittest.h" +#include "util/hash-string.h" +#include "util/unittest.h" #include "rust.h" -#include "util-validate.h" +#include "util/validate.h" -static int DetectMetadataSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectMetadataSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectMetadataRegisterTests(void); #endif -void DetectMetadataRegister (void) +void DetectMetadataRegister(void) { sigmatch_table[DETECT_METADATA].name = "metadata"; sigmatch_table[DETECT_METADATA].desc = "used for logging"; sigmatch_table[DETECT_METADATA].url = "/rules/meta.html#metadata"; sigmatch_table[DETECT_METADATA].Match = NULL; sigmatch_table[DETECT_METADATA].Setup = DetectMetadataSetup; - sigmatch_table[DETECT_METADATA].Free = NULL; + sigmatch_table[DETECT_METADATA].Free = NULL; #ifdef UNITTESTS sigmatch_table[DETECT_METADATA].RegisterTests = DetectMetadataRegisterTests; #endif @@ -68,10 +68,11 @@ void DetectMetadataFree(DetectMetadata *mdata) int DetectMetadataHashInit(DetectEngineCtx *de_ctx) { - if (! DetectEngineMustParseMetadata()) + if (!DetectEngineMustParseMetadata()) return 0; - de_ctx->metadata_table = HashTableInit(4096, StringHashFunc, StringHashCompareFunc, StringHashFreeFunc); + de_ctx->metadata_table = + HashTableInit(4096, StringHashFunc, StringHashCompareFunc, StringHashFreeFunc); if (de_ctx->metadata_table == NULL) return -1; return 0; @@ -159,7 +160,7 @@ static char *CraftPreformattedJSON(const DetectMetadata *head) jb_close(js); /* we have a complete json builder. Now store it as a C string */ const size_t len = jb_len(js); -#define MD_STR "\"metadata\":" +#define MD_STR "\"metadata\":" #define MD_STR_LEN (sizeof(MD_STR) - 1) char *str = SCMalloc(len + MD_STR_LEN + 1); if (str == NULL) { @@ -181,7 +182,7 @@ static char *CraftPreformattedJSON(const DetectMetadata *head) static int DetectMetadataParse(DetectEngineCtx *de_ctx, Signature *s, const char *metadatastr) { DetectMetadata *head = s->metadata ? s->metadata->list : NULL; - char copy[strlen(metadatastr)+1]; + char copy[strlen(metadatastr) + 1]; strlcpy(copy, metadatastr, sizeof(copy)); char *xsaveptr = NULL; char *key = strtok_r(copy, ",", &xsaveptr); @@ -235,7 +236,7 @@ static int DetectMetadataParse(DetectEngineCtx *de_ctx, Signature *s, const char if (s->metadata == NULL) { s->metadata = SCCalloc(1, sizeof(*s->metadata)); if (s->metadata == NULL) { - for (DetectMetadata *m = head; m != NULL; ) { + for (DetectMetadata *m = head; m != NULL;) { DetectMetadata *next_m = m->next; DetectMetadataFree(m); m = next_m; @@ -267,11 +268,10 @@ static int DetectMetadataParseTest01(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any " - "(metadata: toto 1; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(metadata: toto 1; sid:1; rev:1;)"); FAIL_IF_NULL(sig); - FAIL_IF(sig->metadata); + FAIL_IF(sig->metadata); DetectEngineCtxFree(de_ctx); PASS; @@ -282,25 +282,24 @@ static int DetectMetadataParseTest02(void) DetectEngineSetParseMetadata(); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any " - "(metadata: toto 1; " - "metadata: titi 2, jaivu gros_minet;" - "sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(metadata: toto 1; " + "metadata: titi 2, jaivu gros_minet;" + "sid:1; rev:1;)"); FAIL_IF_NULL(sig); - FAIL_IF_NULL(sig->metadata); - FAIL_IF_NULL(sig->metadata->list); - FAIL_IF_NULL(sig->metadata->list->key); + FAIL_IF_NULL(sig->metadata); + FAIL_IF_NULL(sig->metadata->list); + FAIL_IF_NULL(sig->metadata->list->key); FAIL_IF(strcmp("jaivu", sig->metadata->list->key)); FAIL_IF(strcmp("gros_minet", sig->metadata->list->value)); - FAIL_IF_NULL(sig->metadata->list->next); + FAIL_IF_NULL(sig->metadata->list->next); DetectMetadata *dm = sig->metadata->list->next; FAIL_IF(strcmp("titi", dm->key)); dm = dm->next; FAIL_IF_NULL(dm); FAIL_IF(strcmp("toto", dm->key)); - FAIL_IF_NOT(strcmp(sig->metadata->json_str, - "\"metadata\":{\"jaivu\":[\"gros_minet\"],\"titi\":[\"2\"],\"toto\":[\"1\"]}") == 0); + FAIL_IF_NOT(strcmp(sig->metadata->json_str, "\"metadata\":{\"jaivu\":[\"gros_minet\"],\"titi\":" + "[\"2\"],\"toto\":[\"1\"]}") == 0); DetectEngineCtxFree(de_ctx); PASS; } diff --git a/src/detect-metadata.h b/src/detect-metadata.h index fafa63f5ae80..c0b0663a4ea4 100644 --- a/src/detect-metadata.h +++ b/src/detect-metadata.h @@ -42,9 +42,8 @@ typedef struct DetectMetadataHead { } DetectMetadataHead; /* prototypes */ -void DetectMetadataRegister (void); +void DetectMetadataRegister(void); void DetectMetadataFree(DetectMetadata *mdata); #endif /* __DETECT_METADATA_H__ */ - diff --git a/src/detect-modbus.c b/src/detect-modbus.c deleted file mode 100644 index f4e6d4fd03ff..000000000000 --- a/src/detect-modbus.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2014 ANSSI - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * \author David DIALLO - * - * Implements the Modbus function and access keywords - * You can specify a: - * - concrete function like Modbus: - * function 8, subfunction 4 (diagnostic: Force Listen Only Mode) - * - data (in primary table) register access (r/w) like Modbus: - * access read coils, address 1000 (.i.e Read coils: at address 1000) - * - write data value at specific address Modbus: - * access write, address 1500<>2000, value >2000 (Write multiple coils/register: - * at address between 1500 and 2000 value greater than 2000) - */ - -#include "suricata-common.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" - -#include "detect-modbus.h" - -#include "util-debug.h" -#include "util-byte.h" - -#include "stream-tcp.h" -#include "rust.h" - -static int g_modbus_buffer_id = 0; - -/** \internal - * - * \brief this function will free memory associated with DetectModbus - * - * \param ptr pointer to DetectModbus - */ -static void DetectModbusFree(DetectEngineCtx *de_ctx, void *ptr) { - SCEnter(); - if (ptr != NULL) { - rs_modbus_free(ptr); - } - SCReturn; -} - -/** \internal - * - * \brief this function is used to add the parsed "id" option into the current signature - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Current Signature - * \param str Pointer to the user provided "id" option - * - * \retval 0 on Success or -1 on Failure - */ -static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - SCEnter(); - DetectModbusRust *modbus = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MODBUS) != 0) - return -1; - - if ((modbus = rs_modbus_parse(str)) == NULL) { - SCLogError("invalid modbus option"); - goto error; - } - - /* Okay so far so good, lets get this into a SigMatch and put it in the Signature. */ - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_AL_MODBUS, (SigMatchCtx *)modbus, g_modbus_buffer_id) == NULL) { - goto error; - } - - SCReturnInt(0); - -error: - if (modbus != NULL) - DetectModbusFree(de_ctx, modbus); - SCReturnInt(-1); -} - -static int DetectModbusMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - return rs_modbus_inspect(txv, (void *)ctx); -} - -/** - * \brief Registration function for Modbus keyword - */ -void DetectModbusRegister(void) -{ - sigmatch_table[DETECT_AL_MODBUS].name = "modbus"; - sigmatch_table[DETECT_AL_MODBUS].desc = "match on various properties of Modbus requests"; - sigmatch_table[DETECT_AL_MODBUS].url = "/rules/modbus-keyword.html#modbus-keyword"; - sigmatch_table[DETECT_AL_MODBUS].Match = NULL; - sigmatch_table[DETECT_AL_MODBUS].Setup = DetectModbusSetup; - sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree; - sigmatch_table[DETECT_AL_MODBUS].AppLayerTxMatch = DetectModbusMatch; - - DetectAppLayerInspectEngineRegister2( - "modbus", ALPROTO_MODBUS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - - g_modbus_buffer_id = DetectBufferTypeGetByName("modbus"); -} diff --git a/src/detect-mqtt-connack-sessionpresent.c b/src/detect-mqtt-connack-sessionpresent.c deleted file mode 100644 index 4b29158b1f89..000000000000 --- a/src/detect-mqtt-connack-sessionpresent.c +++ /dev/null @@ -1,294 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-connack-sessionpresent.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "^true|false|yes|no$" -static DetectParseRegex parse_regex; - -static int mqtt_connack_session_present_id = 0; - -static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTConnackSessionPresentRegisterTests(void); -void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.connack.session_present: keyword - */ -void DetectMQTTConnackSessionPresentRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].name = "mqtt.connack.session_present"; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].desc = "match MQTT CONNACK session present flag"; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].url = "/rules/mqtt-keywords.html#mqtt-connack-session-present"; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].AppLayerTxMatch = DetectMQTTConnackSessionPresentMatch; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Setup = DetectMQTTConnackSessionPresentSetup; - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Free = DetectMQTTConnackSessionPresentFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].RegisterTests = MQTTConnackSessionPresentRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2("mqtt.connack.session_present", ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_connack_session_present_id = DetectBufferTypeGetByName("mqtt.connack.session_present"); -} - -/** - * \internal - * \brief Function to match session_present flag of an MQTT CONNACK message - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnackSessionPresentData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const bool *de = (const bool *)ctx; - bool value = false; - - if (!de) - return 0; - - if (rs_mqtt_tx_get_connack_sessionpresent(txv, &value) ==0 ) { - return 0; - } - if (value != *de) { - return 0; - } - - return 1; -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.connack.session_present: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTConnackSessionPresentData on success - * \retval NULL on failure - */ -static bool *DetectMQTTConnackSessionPresentParse(const char *rawstr) -{ - bool *de = NULL; - de = SCMalloc(sizeof(bool)); - if (unlikely(de == NULL)) - return NULL; - *de = false; - - if (strcmp(rawstr, "yes") == 0) { - *de = true; - } else if (strcmp(rawstr, "true") == 0) { - *de = true; - } else if (strcmp(rawstr, "no") == 0) { - *de = false; - } else if (strcmp(rawstr, "false") == 0) { - *de = false; - } else { - SCLogError("invalid session_present flag definition: %s", rawstr); - goto error; - } - - return de; - -error: - /* de can't be NULL here */ - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - bool *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTConnackSessionPresentParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNACK_SESSION_PRESENT, (SigMatchCtx *)de, - mqtt_connack_session_present_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTConnackSessionPresentData - * - * \param de pointer to DetectMQTTConnackSessionPresentData - */ -void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTConnackSessionPresentTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse01 (void) -{ - bool *de = NULL; - - de = DetectMQTTConnackSessionPresentParse("yes"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - de = DetectMQTTConnackSessionPresentParse("true"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - de = DetectMQTTConnackSessionPresentParse("false"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - de = DetectMQTTConnackSessionPresentParse("no"); - FAIL_IF_NULL(de); - DetectMQTTConnackSessionPresentFree(NULL, de); - - PASS; -} - -/** - * \test MQTTConnackSessionPresentTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse02 (void) -{ - bool *de = NULL; - de = DetectMQTTConnackSessionPresentParse("nix"); - if (de) { - DetectMQTTConnackSessionPresentFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnackSessionPresentTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse03 (void) -{ - bool *de = NULL; - de = DetectMQTTConnackSessionPresentParse(""); - if (de) { - DetectMQTTConnackSessionPresentFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnackSessionPresentTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnackSessionPresentTestParse04 (void) -{ - bool *de = NULL; - de = DetectMQTTConnackSessionPresentParse(","); - if (de) { - DetectMQTTConnackSessionPresentFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTConnackSessionPresent - */ -void MQTTConnackSessionPresentRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTConnackSessionPresentTestParse01", MQTTConnackSessionPresentTestParse01); - UtRegisterTest("MQTTConnackSessionPresentTestParse02", MQTTConnackSessionPresentTestParse02); - UtRegisterTest("MQTTConnackSessionPresentTestParse03", MQTTConnackSessionPresentTestParse03); - UtRegisterTest("MQTTConnackSessionPresentTestParse04", MQTTConnackSessionPresentTestParse04); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-connect-clientid.c b/src/detect-mqtt-connect-clientid.c deleted file mode 100644 index 1acebf9943bc..000000000000 --- a/src/detect-mqtt-connect-clientid.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.clientid sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-clientid.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.clientid" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-clientid" -#define BUFFER_NAME "mqtt.connect.clientid" -#define BUFFER_DESC "MQTT CONNECT client ID" -static int g_buffer_id = 0; - -static int DetectMQTTConnectClientIDSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_clientid(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectClientIDRegister(void) -{ - /* mqtt.connect.clientid sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].desc = "sticky buffer to match on the MQTT CONNECT client ID"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].Setup = DetectMQTTConnectClientIDSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_MQTT, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-flags.c b/src/detect-mqtt-connect-flags.c deleted file mode 100644 index ce543ecdaa41..000000000000 --- a/src/detect-mqtt-connect-flags.c +++ /dev/null @@ -1,385 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-connect-flags.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "(?: *,?!?(?:username|password|will|will_retain|clean_session))+" -static DetectParseRegex parse_regex; - -static int mqtt_connect_flags_id = 0; - -static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTConnectFlagsSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTConnectFlagsRegisterTests(void); -void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *); - -typedef struct DetectMQTTConnectFlagsData_ { - MQTTFlagState username, - password, - will, - will_retain, - clean_session; -} DetectMQTTConnectFlagsData; - -/** - * \brief Registration function for mqtt.connect.flags: keyword - */ -void DetectMQTTConnectFlagsRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].name = "mqtt.connect.flags"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].desc = "match MQTT CONNECT variable header flags"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].url = "/rules/mqtt-keywords.html#mqtt-connect-flags"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].AppLayerTxMatch = DetectMQTTConnectFlagsMatch; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Setup = DetectMQTTConnectFlagsSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Free = DetectMQTTConnectFlagsFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].RegisterTests = MQTTConnectFlagsRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2("mqtt.connect.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectGenericList, NULL); - - mqtt_connect_flags_id = DetectBufferTypeGetByName("mqtt.connect.flags"); -} - -/** - * \internal - * \brief Function to match variable header flags of an MQTT CONNECT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnectFlagsData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const DetectMQTTConnectFlagsData *de = (const DetectMQTTConnectFlagsData *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_connect_flags(txv, de->username, de->password, de->will, - de->will_retain, de->clean_session); - } - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.connect.flags: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTConnectFlagsData on success - * \retval NULL on failure - */ -static DetectMQTTConnectFlagsData *DetectMQTTConnectFlagsParse(const char *rawstr) -{ - char copy[strlen(rawstr) + 1]; - - DetectMQTTConnectFlagsData *de = SCCalloc(1, sizeof(DetectMQTTConnectFlagsData)); - if (unlikely(de == NULL)) - return NULL; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 1) { - SCLogError("invalid flag definition: %s", rawstr); - goto error; - } - - de->username = de->password = de->will = MQTT_DONT_CARE; - de->will_retain = de->clean_session = MQTT_DONT_CARE; - - strlcpy(copy, rawstr, sizeof(copy)); - char *xsaveptr = NULL; - char *flagv = strtok_r(copy, ",", &xsaveptr); - while (flagv != NULL) { - while (*flagv != '\0' && isblank(*flagv)) { - flagv++; - } - if (strlen(flagv) < 2) { - SCLogError("malformed flag value: %s", flagv); - goto error; - } else { - int offset = 0; - MQTTFlagState fs_to_set = MQTT_MUST_BE_SET; - if (flagv[0] == '!') { - /* negated flag */ - offset = 1; /* skip negation operator during comparison */ - fs_to_set = MQTT_CANT_BE_SET; - } - if (strcmp(flagv+offset, "username") == 0) { - if (de->username != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->username = fs_to_set; - } else if (strcmp(flagv+offset, "password") == 0) { - if (de->password != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->password = fs_to_set; - } else if (strcmp(flagv+offset, "will") == 0) { - if (de->will != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->will = fs_to_set; - } else if (strcmp(flagv+offset, "will_retain") == 0) { - if (de->will_retain != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->will_retain = fs_to_set; - } else if (strcmp(flagv+offset, "clean_session") == 0) { - if (de->clean_session != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->clean_session = fs_to_set; - } else { - SCLogError("invalid flag definition: %s", flagv); - goto error; - } - } - flagv = strtok_r(NULL, ",", &xsaveptr); - } - - pcre2_match_data_free(match); - return de; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (de) - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTConnectFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - DetectMQTTConnectFlagsData *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTConnectFlagsParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNECT_FLAGS, (SigMatchCtx *)de, - mqtt_connect_flags_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTConnectFlagsData - * - * \param de pointer to DetectMQTTConnectFlagsData - */ -void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTConnectFlagsTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse01 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("username"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - de = DetectMQTTConnectFlagsParse("username,password,will,will_retain,clean_session"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - de = DetectMQTTConnectFlagsParse("!username,!password,!will,!will_retain,!clean_session"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - de = DetectMQTTConnectFlagsParse(" username,password"); - FAIL_IF_NULL(de); - DetectMQTTConnectFlagsFree(NULL, de); - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse02 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("foobar"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse03 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("will,!"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse04 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse(""); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTConnectFlagsTestParse05 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTConnectFlagsTestParse05 (void) -{ - DetectMQTTConnectFlagsData *de = NULL; - de = DetectMQTTConnectFlagsParse("username, username"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - de = DetectMQTTConnectFlagsParse("!username, username"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - de = DetectMQTTConnectFlagsParse("!username,password,!password"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - de = DetectMQTTConnectFlagsParse("will, username,password, !will, will"); - if (de) { - DetectMQTTConnectFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTConnectFlags - */ -void MQTTConnectFlagsRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTConnectFlagsTestParse01", MQTTConnectFlagsTestParse01); - UtRegisterTest("MQTTConnectFlagsTestParse02", MQTTConnectFlagsTestParse02); - UtRegisterTest("MQTTConnectFlagsTestParse03", MQTTConnectFlagsTestParse03); - UtRegisterTest("MQTTConnectFlagsTestParse04", MQTTConnectFlagsTestParse04); - UtRegisterTest("MQTTConnectFlagsTestParse05", MQTTConnectFlagsTestParse05); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-connect-password.c b/src/detect-mqtt-connect-password.c deleted file mode 100644 index c08390748fe0..000000000000 --- a/src/detect-mqtt-connect-password.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.password sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-password.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.password" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-password" -#define BUFFER_NAME "mqtt.connect.password" -#define BUFFER_DESC "MQTT CONNECT password" -static int g_buffer_id = 0; - -static int DetectMQTTConnectPasswordSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_password(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectPasswordRegister(void) -{ - /* mqtt.connect.password sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].desc = "sticky buffer to match on the MQTT CONNECT password"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].Setup = DetectMQTTConnectPasswordSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_MQTT, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-protocol-string.c b/src/detect-mqtt-connect-protocol-string.c deleted file mode 100644 index 421b293845b7..000000000000 --- a/src/detect-mqtt-connect-protocol-string.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.protocolstring sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-protocol-string.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.protocol_string" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-protocol_string" -#define BUFFER_NAME "mqtt.connect.protocol_string" -#define BUFFER_DESC "MQTT CONNECT protocol string" -static int g_buffer_id = 0; - -static int DetectMQTTConnectProtocolStringSetup( - DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_protocol_string(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectProtocolStringRegister(void) -{ - /* mqtt.connect.protocol_string sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].desc = - "sticky buffer to match on the MQTT CONNECT protocol string"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].Setup = - DetectMQTTConnectProtocolStringSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_MQTT, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-username.c b/src/detect-mqtt-connect-username.c deleted file mode 100644 index dbc772d22058..000000000000 --- a/src/detect-mqtt-connect-username.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.username sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-username.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.username" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-username" -#define BUFFER_NAME "mqtt.connect.username" -#define BUFFER_DESC "MQTT CONNECT username" -static int g_buffer_id = 0; - -static int DetectMQTTConnectUsernameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_username(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectUsernameRegister(void) -{ - /* mqtt.connect.username sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].desc = "sticky buffer to match on the MQTT CONNECT username"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].Setup = DetectMQTTConnectUsernameSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_MQTT, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-willmessage.c b/src/detect-mqtt-connect-willmessage.c deleted file mode 100644 index 48d851d3209e..000000000000 --- a/src/detect-mqtt-connect-willmessage.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.willmessage sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-willmessage.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.willmessage" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willmessage" -#define BUFFER_NAME "mqtt.connect.willmessage" -#define BUFFER_DESC "MQTT CONNECT will message" -static int g_buffer_id = 0; - -static int DetectMQTTConnectWillMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_willmessage(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectWillMessageRegister(void) -{ - /* mqtt.connect.willmessage sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].desc = "sticky buffer to match on the MQTT CONNECT will message"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].Setup = DetectMQTTConnectWillMessageSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_MQTT, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-connect-willtopic.c b/src/detect-mqtt-connect-willtopic.c deleted file mode 100644 index da3d2640dd96..000000000000 --- a/src/detect-mqtt-connect-willtopic.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.connect.willtopic sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-connect-willtopic.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.connect.willtopic" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willtopic" -#define BUFFER_NAME "mqtt.connect.willtopic" -#define BUFFER_DESC "MQTT CONNECT will topic" -static int g_buffer_id = 0; - -static int DetectMQTTConnectWillTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_connect_willtopic(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTConnectWillTopicRegister(void) -{ - /* mqtt.connect.willtopic sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].desc = "sticky buffer to match on the MQTT CONNECT will topic"; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].Setup = DetectMQTTConnectWillTopicSetup; - sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_MQTT, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-flags.c b/src/detect-mqtt-flags.c deleted file mode 100644 index d0614061416d..000000000000 --- a/src/detect-mqtt-flags.c +++ /dev/null @@ -1,359 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-flags.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "(?: *,?!?(?:retain|dup))+" -static DetectParseRegex parse_regex; - -static int mqtt_flags_id = 0; - -static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTFlagsSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTFlagsRegisterTests(void); -void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *); - -typedef struct DetectMQTTFlagsData_ { - MQTTFlagState retain, dup; -} DetectMQTTFlagsData; - -/** - * \brief Registration function for mqtt.flags: keyword - */ -void DetectMQTTFlagsRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_FLAGS].name = "mqtt.flags"; - sigmatch_table[DETECT_AL_MQTT_FLAGS].desc = "match MQTT fixed header flags"; - sigmatch_table[DETECT_AL_MQTT_FLAGS].url = "/rules/mqtt-keywords.html#mqtt-flags"; - sigmatch_table[DETECT_AL_MQTT_FLAGS].AppLayerTxMatch = DetectMQTTFlagsMatch; - sigmatch_table[DETECT_AL_MQTT_FLAGS].Setup = DetectMQTTFlagsSetup; - sigmatch_table[DETECT_AL_MQTT_FLAGS].Free = DetectMQTTFlagsFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_FLAGS].RegisterTests = MQTTFlagsRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2( - "mqtt.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_flags_id = DetectBufferTypeGetByName("mqtt.flags"); -} - -/** - * \internal - * \brief Function to match fixed header flags of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTFlagsData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const DetectMQTTFlagsData *de = (const DetectMQTTFlagsData *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_flags(txv, de->retain, de->dup); -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.flags: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTFlagsData on success - * \retval NULL on failure - */ -static DetectMQTTFlagsData *DetectMQTTFlagsParse(const char *rawstr) -{ - - DetectMQTTFlagsData *de = SCCalloc(1, sizeof(DetectMQTTFlagsData)); - if (unlikely(de == NULL)) - return NULL; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 1) { - SCLogError("invalid flag definition: %s", rawstr); - if (match) { - pcre2_match_data_free(match); - } - SCFree(de); - return NULL; - } - - de->retain = de->dup = MQTT_DONT_CARE; - - char copy[strlen(rawstr)+1]; - strlcpy(copy, rawstr, sizeof(copy)); - char *xsaveptr = NULL; - - /* Iterate through comma-separated string... */ - char *flagv = strtok_r(copy, ",", &xsaveptr); - while (flagv != NULL) { - /* skip blanks */ - while (*flagv != '\0' && isblank(*flagv)) { - flagv++; - } - if (strlen(flagv) < 2) { - /* flags have a minimum length */ - SCLogError("malformed flag value: %s", flagv); - goto error; - } else { - int offset = 0; - MQTTFlagState fs_to_set = MQTT_MUST_BE_SET; - if (flagv[0] == '!') { - /* negated flag */ - offset = 1; /* skip negation operator during comparison */ - fs_to_set = MQTT_CANT_BE_SET; - } - if (strcmp(flagv+offset, "dup") == 0) { - if (de->dup != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->dup = fs_to_set; - } else if (strcmp(flagv+offset, "retain") == 0) { - if (de->retain != MQTT_DONT_CARE) { - SCLogError("duplicate flag definition: %s", flagv); - goto error; - } - de->retain = fs_to_set; - } else { - SCLogError("invalid flag definition: %s", flagv); - goto error; - } - } - flagv = strtok_r(NULL, ",", &xsaveptr); - } - - pcre2_match_data_free(match); - return de; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (de) - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - DetectMQTTFlagsData *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTFlagsParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_FLAGS, (SigMatchCtx *)de, mqtt_flags_id) == - NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTFlagsData - * - * \param de pointer to DetectMQTTFlagsData - */ -void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTFlagsTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse01 (void) -{ - DetectMQTTFlagsData *de = NULL; - - de = DetectMQTTFlagsParse("retain"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - de = DetectMQTTFlagsParse("dup"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - de = DetectMQTTFlagsParse("retain,dup"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - de = DetectMQTTFlagsParse("dup, retain"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - PASS; -} - -/** - * \test MQTTFlagsTestParse02 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse02 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("retain,!dup"); - FAIL_IF_NULL(de); - DetectMQTTFlagsFree(NULL, de); - - PASS; -} - -/** - * \test MQTTFlagsTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse03 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("ref"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTFlagsTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse04 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("dup,!"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTFlagsTestParse05 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTFlagsTestParse05 (void) -{ - DetectMQTTFlagsData *de = NULL; - de = DetectMQTTFlagsParse("dup,!dup"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - de = DetectMQTTFlagsParse("!retain,retain"); - if (de) { - DetectMQTTFlagsFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTFlags - */ -void MQTTFlagsRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTFlagsTestParse01", MQTTFlagsTestParse01); - UtRegisterTest("MQTTFlagsTestParse02", MQTTFlagsTestParse02); - UtRegisterTest("MQTTFlagsTestParse03", MQTTFlagsTestParse03); - UtRegisterTest("MQTTFlagsTestParse04", MQTTFlagsTestParse04); - UtRegisterTest("MQTTFlagsTestParse05", MQTTFlagsTestParse05); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-protocol-version.c b/src/detect-mqtt-protocol-version.c deleted file mode 100644 index 6ba183d75c8a..000000000000 --- a/src/detect-mqtt-protocol-version.c +++ /dev/null @@ -1,248 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-uint.h" -#include "detect-mqtt-protocol-version.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -static int mqtt_protocol_version_id = 0; - -static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTProtocolVersionSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTProtocolVersionRegisterTests(void); -void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.protocol_version: keyword - */ -void DetectMQTTProtocolVersionRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].name = "mqtt.protocol_version"; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].desc = "match MQTT protocol version"; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].url = "/rules/mqtt-keywords.html#mqtt-protocol-version"; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].AppLayerTxMatch = DetectMQTTProtocolVersionMatch; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Setup = DetectMQTTProtocolVersionSetup; - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Free = DetectMQTTProtocolVersionFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].RegisterTests = MQTTProtocolVersionRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister2("mqtt.protocol_version", ALPROTO_MQTT, SIG_FLAG_TOSERVER, - 1, DetectEngineInspectGenericList, NULL); - - mqtt_protocol_version_id = DetectBufferTypeGetByName("mqtt.protocol_version"); -} - -/** - * \internal - * \brief Function to match protocol version of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTProtocolVersionData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const DetectU8Data *de = (const DetectU8Data *)ctx; - uint8_t version; - - version = rs_mqtt_tx_get_protocol_version(state); - - return DetectU8Match(version, de); -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTProtocolVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - DetectU8Data *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectU8Parse(rawstr); - if (de == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_PROTOCOL_VERSION, (SigMatchCtx *)de, - mqtt_protocol_version_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - rs_detect_u8_free(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTProtocolVersionData - * - * \param de pointer to DetectMQTTProtocolVersionData - */ -void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - rs_detect_u8_free(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTProtocolVersionTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse01 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:3; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:3; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test MQTTProtocolVersionTestParse02 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse02 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:>3; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:<44; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test MQTTProtocolVersionTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse03 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:; sid:1; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test MQTTProtocolVersionTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTProtocolVersionTestParse04 (void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (mqtt.protocol_version:<444; sid:1; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTProtocolVersion - */ -void MQTTProtocolVersionRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTProtocolVersionTestParse01", MQTTProtocolVersionTestParse01); - UtRegisterTest("MQTTProtocolVersionTestParse02", MQTTProtocolVersionTestParse02); - UtRegisterTest("MQTTProtocolVersionTestParse03", MQTTProtocolVersionTestParse03); - UtRegisterTest("MQTTProtocolVersionTestParse04", MQTTProtocolVersionTestParse04); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-publish-message.c b/src/detect-mqtt-publish-message.c deleted file mode 100644 index 32f3bd6460ad..000000000000 --- a/src/detect-mqtt-publish-message.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.publish.message sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-publish-message.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.publish.message" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-message" -#define BUFFER_NAME "mqtt.publish.message" -#define BUFFER_DESC "MQTT PUBLISH message" -static int g_buffer_id = 0; - -static int DetectMQTTPublishMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_publish_message(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTPublishMessageRegister(void) -{ - /* mqtt.publish.message sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].desc = "sticky buffer to match on the MQTT PUBLISH message"; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].Setup = DetectMQTTPublishMessageSetup; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_MQTT, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-publish-topic.c b/src/detect-mqtt-publish-topic.c deleted file mode 100644 index c03a47b5eda7..000000000000 --- a/src/detect-mqtt-publish-topic.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - * - * Implements the mqtt.publish.topic sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-publish-topic.h" -#include "rust.h" - -#define KEYWORD_NAME "mqtt.publish.topic" -#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-topic" -#define BUFFER_NAME "mqtt.publish.topic" -#define BUFFER_DESC "MQTT PUBLISH topic" -static int g_buffer_id = 0; - -static int DetectMQTTPublishTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_mqtt_tx_get_publish_topic(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectMQTTPublishTopicRegister(void) -{ - /* mqtt.publish.topic sticky buffer */ - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].desc = "sticky buffer to match on the MQTT PUBLISH topic"; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].Setup = DetectMQTTPublishTopicSetup; - sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_MQTT, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_MQTT, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-mqtt-qos.c b/src/detect-mqtt-qos.c deleted file mode 100644 index a00eaee185a2..000000000000 --- a/src/detect-mqtt-qos.c +++ /dev/null @@ -1,258 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-qos.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -static int mqtt_qos_id = 0; - -static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTQosSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTQosRegisterTests(void); -void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.qos: keyword - */ -void DetectMQTTQosRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_QOS].name = "mqtt.qos"; - sigmatch_table[DETECT_AL_MQTT_QOS].desc = "match MQTT fixed header QOS level"; - sigmatch_table[DETECT_AL_MQTT_QOS].url = "/rules/mqtt-keywords.html#mqtt-qos"; - sigmatch_table[DETECT_AL_MQTT_QOS].AppLayerTxMatch = DetectMQTTQosMatch; - sigmatch_table[DETECT_AL_MQTT_QOS].Setup = DetectMQTTQosSetup; - sigmatch_table[DETECT_AL_MQTT_QOS].Free = DetectMQTTQosFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_QOS].RegisterTests = MQTTQosRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister2( - "mqtt.qos", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_qos_id = DetectBufferTypeGetByName("mqtt.qos"); -} - -/** - * \internal - * \brief Function to match fixed header QOS field of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into uint8_t. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const uint8_t *de = (const uint8_t *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_qos(txv, *de); -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.qos: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTQosData on success - * \retval NULL on failure - */ -static uint8_t *DetectMQTTQosParse(const char *rawstr) -{ - uint8_t *de = NULL; - int ret = 0; - uint8_t val; - - ret = StringParseU8RangeCheck(&val, 10, 0, rawstr, 0, 2); - if (ret < 0) { - SCLogError("invalid MQTT QOS level: %s", rawstr); - return NULL; - } - - de = SCMalloc(sizeof(uint8_t)); - if (unlikely(de == NULL)) - return NULL; - *de = val; - - return de; -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTQosSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - uint8_t *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTQosParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_QOS, (SigMatchCtx *)de, mqtt_qos_id) == - NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTQosData - * - * \param de pointer to DetectMQTTQosData - */ -void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTQosTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTQosTestParse01 (void) -{ - uint8_t *de = NULL; - - de = DetectMQTTQosParse("0"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 0); - DetectMQTTQosFree(NULL, de); - - de = DetectMQTTQosParse(" 0"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 0); - DetectMQTTQosFree(NULL, de); - - de = DetectMQTTQosParse("1"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 1); - DetectMQTTQosFree(NULL, de); - - de = DetectMQTTQosParse("2"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 2); - DetectMQTTQosFree(NULL, de); - - PASS; -} - -/** - * \test MQTTQosTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTQosTestParse02 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTQosParse("3"); - if (de) { - DetectMQTTQosFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTQosTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTQosTestParse03 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTQosParse("12"); - if (de) { - DetectMQTTQosFree(NULL, de); - FAIL; - } - - PASS; -} - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTQos - */ -void MQTTQosRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTQosTestParse01", MQTTQosTestParse01); - UtRegisterTest("MQTTQosTestParse02", MQTTQosTestParse02); - UtRegisterTest("MQTTQosTestParse03", MQTTQosTestParse03); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-reason-code.c b/src/detect-mqtt-reason-code.c deleted file mode 100644 index e6ecba44cc26..000000000000 --- a/src/detect-mqtt-reason-code.c +++ /dev/null @@ -1,294 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-reason-code.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "^\\s*\\d+\\s*$" -static DetectParseRegex parse_regex; - -static int mqtt_reason_code_id = 0; - -static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTReasonCodeSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTReasonCodeRegisterTests(void); -void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.reason_code: keyword - */ -void DetectMQTTReasonCodeRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].name = "mqtt.reason_code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].alias = "mqtt.connack.return_code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].desc = "match MQTT 5.0+ reason code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].url = "/rules/mqtt-keywords.html#mqtt-reason-code"; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].AppLayerTxMatch = DetectMQTTReasonCodeMatch; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Setup = DetectMQTTReasonCodeSetup; - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Free = DetectMQTTReasonCodeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_REASON_CODE].RegisterTests = MQTTReasonCodeRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2("mqtt.reason_code", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectGenericList, NULL); - - mqtt_reason_code_id = DetectBufferTypeGetByName("mqtt.reason_code"); -} - -/** - * \internal - * \brief Function to match reason code of an MQTT 5.0 Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTReasonCodeData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const uint8_t *de = (const uint8_t *)ctx; - uint8_t code; - - if (!de) - return 0; - - if (rs_mqtt_tx_get_reason_code(txv, &code) == 0) { - /* this function does not return a code that needs to be compared, - so we can just return the result of the check implemented in - Rust */ - return rs_mqtt_tx_unsuback_has_reason_code(txv, *de); - } else { - if (code == *de) - return 1; - } - return 0; -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.reason_code: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTReasonCodeData on success - * \retval NULL on failure - */ -static uint8_t *DetectMQTTReasonCodeParse(const char *rawstr) -{ - uint8_t *de = NULL; - int ret = 0; - uint8_t val; - - ret = StringParseUint8(&val, 10, 0, rawstr); - if (ret < 0) { - SCLogError("invalid MQTT reason code: %s", rawstr); - return NULL; - } - - de = SCMalloc(sizeof(uint8_t)); - if (unlikely(de == NULL)) - return NULL; - *de = (uint8_t) val; - - return de; -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTReasonCodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - uint8_t *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTReasonCodeParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_REASON_CODE, (SigMatchCtx *)de, - mqtt_reason_code_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTReasonCodeData - * - * \param de pointer to DetectMQTTReasonCodeData - */ -void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTReasonCodeTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse01 (void) -{ - uint8_t *de = NULL; - - de = DetectMQTTReasonCodeParse("3"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 3); - DetectMQTTReasonCodeFree(NULL, de); - - de = DetectMQTTReasonCodeParse(" 4"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 4); - DetectMQTTReasonCodeFree(NULL, de); - - de = DetectMQTTReasonCodeParse(" 5"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 5); - DetectMQTTReasonCodeFree(NULL, de); - - de = DetectMQTTReasonCodeParse("255"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 255); - DetectMQTTReasonCodeFree(NULL, de); - - PASS; -} - -/** - * \test MQTTReasonCodeTestParse02 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse02 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTReasonCodeParse("6X"); - if (de) { - DetectMQTTReasonCodeFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTReasonCodeTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse03 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTReasonCodeParse(""); - if (de) { - DetectMQTTReasonCodeFree(NULL, de); - FAIL; - } - - PASS; -} - -/** - * \test MQTTReasonCodeTestParse04 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTReasonCodeTestParse04 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTReasonCodeParse("256"); - if (de) { - DetectMQTTReasonCodeFree(NULL, de); - FAIL; - } - - PASS; -} - - - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTReasonCode - */ -void MQTTReasonCodeRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTReasonCodeTestParse01", MQTTReasonCodeTestParse01); - UtRegisterTest("MQTTReasonCodeTestParse02", MQTTReasonCodeTestParse02); - UtRegisterTest("MQTTReasonCodeTestParse03", MQTTReasonCodeTestParse03); - UtRegisterTest("MQTTReasonCodeTestParse04", MQTTReasonCodeTestParse04); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-subscribe-topic.c b/src/detect-mqtt-subscribe-topic.c deleted file mode 100644 index 9eaf39d3029c..000000000000 --- a/src/detect-mqtt-subscribe-topic.c +++ /dev/null @@ -1,240 +0,0 @@ -/* Copyright (C) 2020-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "conf.h" -#include "decode.h" -#include "detect.h" -#include "detect-content.h" -#include "detect-parse.h" -#include "detect-pcre.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-subscribe-topic.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "rust-bindings.h" - -#include "threads.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-profiling.h" - -static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *); - -static int g_mqtt_subscribe_topic_buffer_id = 0; - -static uint32_t subscribe_topic_match_limit = 100; - -struct MQTTSubscribeTopicGetDataArgs { - uint32_t local_id; - void *txv; -}; - -static InspectionBuffer *MQTTSubscribeTopicGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - struct MQTTSubscribeTopicGetDataArgs *cbdata, int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_mqtt_tx_get_subscribe_topic(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectMQTTSubscribeTopic(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while ((subscribe_topic_match_limit == 0) || local_id < subscribe_topic_match_limit) { - struct MQTTSubscribeTopicGetDataArgs cbdata = { local_id, txv, }; - InspectionBuffer *buffer = - MQTTSubscribeTopicGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -typedef struct PrefilterMpmMQTTSubscribeTopic { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmMQTTSubscribeTopic; - -/** \brief MQTTSubscribeTopic MQTTSubscribeTopic Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxMQTTSubscribeTopic(DetectEngineThreadCtx *det_ctx, const void *pectx, - Packet *p, Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, - const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmMQTTSubscribeTopic *ctx = (const PrefilterMpmMQTTSubscribeTopic *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - while ((subscribe_topic_match_limit == 0) || local_id < subscribe_topic_match_limit) { - struct MQTTSubscribeTopicGetDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = - MQTTSubscribeTopicGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - local_id++; - } -} - -static void PrefilterMpmMQTTSubscribeTopicFree(void *ptr) -{ - if (ptr != NULL) - SCFree(ptr); -} - -static int PrefilterMpmMQTTSubscribeTopicRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmMQTTSubscribeTopic *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxMQTTSubscribeTopic, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmMQTTSubscribeTopicFree, mpm_reg->pname); -} - -/** - * \brief Registration function for keyword: mqtt.subscribe.topic - */ -void DetectMQTTSubscribeTopicRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].name = "mqtt.subscribe.topic"; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].desc = "sticky buffer to match MQTT SUBSCRIBE topic"; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].url = "/rules/mqtt-keywords.html#mqtt-subscribe-topic"; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].Setup = DetectMQTTSubscribeTopicSetup; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - intmax_t val = 0; - if (ConfGetInt("app-layer.protocols.mqtt.subscribe-topic-match-limit", &val)) { - subscribe_topic_match_limit = val; - } - if (subscribe_topic_match_limit <= 0) { - SCLogDebug("Using unrestricted MQTT SUBSCRIBE topic matching"); - } else { - SCLogDebug("Using MQTT SUBSCRIBE topic match-limit setting of: %u", - subscribe_topic_match_limit); - } - - DetectAppLayerMpmRegister2("mqtt.subscribe.topic", SIG_FLAG_TOSERVER, 1, - PrefilterMpmMQTTSubscribeTopicRegister, NULL, - ALPROTO_MQTT, 1); - - DetectAppLayerInspectEngineRegister2("mqtt.subscribe.topic", - ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectMQTTSubscribeTopic, NULL); - - DetectBufferTypeSetDescriptionByName("mqtt.subscribe.topic", - "subscribe topic query"); - - g_mqtt_subscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.subscribe.topic"); - - DetectBufferTypeSupportsMultiInstance("mqtt.subscribe.topic"); -} - -/** - * \brief setup the sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_subscribe_topic_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - return 0; -} diff --git a/src/detect-mqtt-type.c b/src/detect-mqtt-type.c deleted file mode 100644 index 5e23a509ca7c..000000000000 --- a/src/detect-mqtt-type.c +++ /dev/null @@ -1,256 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-mqtt-type.h" -#include "util-unittest.h" - -#include "rust.h" - -static int mqtt_type_id = 0; - -static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectMQTTTypeSetup (DetectEngineCtx *, Signature *, const char *); -void MQTTTypeRegisterTests(void); -void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *); - -/** - * \brief Registration function for mqtt.type: keyword - */ -void DetectMQTTTypeRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_TYPE].name = "mqtt.type"; - sigmatch_table[DETECT_AL_MQTT_TYPE].desc = "match MQTT control packet type"; - sigmatch_table[DETECT_AL_MQTT_TYPE].url = "/rules/mqtt-keywords.html#mqtt-type"; - sigmatch_table[DETECT_AL_MQTT_TYPE].AppLayerTxMatch = DetectMQTTTypeMatch; - sigmatch_table[DETECT_AL_MQTT_TYPE].Setup = DetectMQTTTypeSetup; - sigmatch_table[DETECT_AL_MQTT_TYPE].Free = DetectMQTTTypeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_MQTT_TYPE].RegisterTests = MQTTTypeRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister2( - "mqtt.type", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - mqtt_type_id = DetectBufferTypeGetByName("mqtt.type"); -} - -/** - * \internal - * \brief Function to match control packet type of an MQTT Tx - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTTypeData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const uint8_t *de = (const uint8_t *)ctx; - - if (!de) - return 0; - - return rs_mqtt_tx_has_type(txv, *de); -} - -/** - * \internal - * \brief This function is used to parse options passed via mqtt.type: keyword - * - * \param rawstr Pointer to the user provided options - * - * \retval de pointer to DetectMQTTTypeData on success - * \retval NULL on failure - */ -static uint8_t *DetectMQTTTypeParse(const char *rawstr) -{ - uint8_t *de = NULL; - int ret = 0; - - ret = rs_mqtt_cstr_message_code(rawstr); - // negative value denotes invalid input - if(ret < 0) { - SCLogError("unknown mqtt.type value %s", rawstr); - goto error; - } - - de = SCMalloc(sizeof(uint8_t)); - if (unlikely(de == NULL)) - goto error; - - *de = (uint8_t) ret; - - return de; - -error: - if (de != NULL) - SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed type query into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectMQTTTypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - uint8_t *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - - de = DetectMQTTTypeParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_TYPE, (SigMatchCtx *)de, mqtt_type_id) == - NULL) { - goto error; - } - - return 0; - -error: - if (de != NULL) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectMQTTTypeData - * - * \param de pointer to DetectMQTTTypeData - */ -void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - if (de_ptr != NULL) - SCFree(de_ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test MQTTTypeTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTTypeTestParse01 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTTypeParse("CONNECT"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 1); - DetectMQTTTypeFree(NULL, de); - - de = DetectMQTTTypeParse("PINGRESP"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 13); - DetectMQTTTypeFree(NULL, de); - - PASS; -} - -/** - * \test MQTTTypeTestParse02 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTTypeTestParse02 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTTypeParse("auth"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(*de == 15); - DetectMQTTTypeFree(NULL, de); - - PASS; -} - -/** - * \test MQTTTypeTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int MQTTTypeTestParse03 (void) -{ - uint8_t *de = NULL; - de = DetectMQTTTypeParse("invalidopt"); - if (de) { - DetectMQTTTypeFree(NULL, de); - FAIL; - } - - de = DetectMQTTTypeParse("unassigned"); - if (de) { - DetectMQTTTypeFree(NULL, de); - FAIL; - } - - PASS; -} - -#endif /* UNITTESTS */ - -/** - * \brief this function registers unit tests for MQTTType - */ -void MQTTTypeRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MQTTTypeTestParse01", MQTTTypeTestParse01); - UtRegisterTest("MQTTTypeTestParse02", MQTTTypeTestParse02); - UtRegisterTest("MQTTTypeTestParse03", MQTTTypeTestParse03); -#endif /* UNITTESTS */ -} diff --git a/src/detect-mqtt-unsubscribe-topic.c b/src/detect-mqtt-unsubscribe-topic.c deleted file mode 100644 index 268d72bc8789..000000000000 --- a/src/detect-mqtt-unsubscribe-topic.c +++ /dev/null @@ -1,240 +0,0 @@ -/* Copyright (C) 2020-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "conf.h" -#include "decode.h" -#include "detect.h" -#include "detect-content.h" -#include "detect-parse.h" -#include "detect-pcre.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-mqtt-unsubscribe-topic.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "rust-bindings.h" - -#include "threads.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-profiling.h" - -static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *); - -static int g_mqtt_unsubscribe_topic_buffer_id = 0; - -static uint32_t unsubscribe_topic_match_limit = 100; - -struct MQTTUnsubscribeTopicGetDataArgs { - uint32_t local_id; - void *txv; -}; - -static InspectionBuffer *MQTTUnsubscribeTopicGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - struct MQTTUnsubscribeTopicGetDataArgs *cbdata, int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_mqtt_tx_get_unsubscribe_topic(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectMQTTUnsubscribeTopic(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while ((unsubscribe_topic_match_limit == 0) || local_id < unsubscribe_topic_match_limit) { - struct MQTTUnsubscribeTopicGetDataArgs cbdata = { local_id, txv, }; - InspectionBuffer *buffer = - MQTTUnsubscribeTopicGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -typedef struct PrefilterMpmMQTTUnsubscribeTopic { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmMQTTUnsubscribeTopic; - -/** \brief MQTTUnsubscribeTopic MQTTUnsubscribeTopic Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxMQTTUnsubscribeTopic(DetectEngineThreadCtx *det_ctx, const void *pectx, - Packet *p, Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, - const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmMQTTUnsubscribeTopic *ctx = (const PrefilterMpmMQTTUnsubscribeTopic *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - while ((unsubscribe_topic_match_limit == 0) || local_id < unsubscribe_topic_match_limit) { - struct MQTTUnsubscribeTopicGetDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = - MQTTUnsubscribeTopicGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - local_id++; - } -} - -static void PrefilterMpmMQTTUnsubscribeTopicFree(void *ptr) -{ - if (ptr != NULL) - SCFree(ptr); -} - -static int PrefilterMpmMQTTUnsubscribeTopicRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, - MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmMQTTUnsubscribeTopic *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxMQTTUnsubscribeTopic, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmMQTTUnsubscribeTopicFree, mpm_reg->pname); -} - -/** - * \brief Registration function for keyword: mqtt.unsubscribe.topic - */ -void DetectMQTTUnsubscribeTopicRegister (void) -{ - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].name = "mqtt.unsubscribe.topic"; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].desc = "sticky buffer to match MQTT UNSUBSCRIBE topic"; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].url = "/rules/mqtt-keywords.html#mqtt-unsubscribe-topic"; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].Setup = DetectMQTTUnsubscribeTopicSetup; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - intmax_t val = 0; - if (ConfGetInt("app-layer.protocols.mqtt.unsubscribe-topic-match-limit", &val)) { - unsubscribe_topic_match_limit = val; - } - if (unsubscribe_topic_match_limit <= 0) { - SCLogDebug("Using unrestricted MQTT UNSUBSCRIBE topic matching"); - } else { - SCLogDebug("Using MQTT UNSUBSCRIBE topic match-limit setting of: %i", - unsubscribe_topic_match_limit); - } - - DetectAppLayerMpmRegister2("mqtt.unsubscribe.topic", SIG_FLAG_TOSERVER, 1, - PrefilterMpmMQTTUnsubscribeTopicRegister, NULL, - ALPROTO_MQTT, 1); - - DetectAppLayerInspectEngineRegister2("mqtt.unsubscribe.topic", - ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectMQTTUnsubscribeTopic, NULL); - - DetectBufferTypeSetDescriptionByName("mqtt.unsubscribe.topic", - "unsubscribe topic query"); - - g_mqtt_unsubscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.unsubscribe.topic"); - - DetectBufferTypeSupportsMultiInstance("mqtt.unsubscribe.topic"); -} - -/** - * \brief setup the sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_unsubscribe_topic_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) - return -1; - return 0; -} diff --git a/src/detect-msg.c b/src/detect-msg.c index 7f67d62497e2..d1ec783b45eb 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -25,21 +25,21 @@ #include "suricata-common.h" #include "detect.h" -#include "util-classification-config.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/classification-config.h" +#include "util/debug.h" +#include "util/unittest.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-msg.h" -static int DetectMsgSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectMsgSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectMsgRegisterTests(void); #endif -void DetectMsgRegister (void) +void DetectMsgRegister(void) { sigmatch_table[DETECT_MSG].name = "msg"; sigmatch_table[DETECT_MSG].desc = "information about the rule and the possible alert"; @@ -53,7 +53,7 @@ void DetectMsgRegister (void) sigmatch_table[DETECT_MSG].flags = SIGMATCH_QUOTES_MANDATORY; } -static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, const char *msgstr) +static int DetectMsgSetup(DetectEngineCtx *de_ctx, Signature *s, const char *msgstr) { size_t slen = strlen(msgstr); if (slen == 0) @@ -70,29 +70,24 @@ static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ms /* it doesn't matter if we need to escape or not we remove the extra "\" to mimic snort */ for (i = 0, x = 0; i < slen; i++) { - //printf("str[%02u]: %c\n", i, str[i]); - if(!escape && str[i] == '\\') { + // printf("str[%02u]: %c\n", i, str[i]); + if (!escape && str[i] == '\\') { escape = 1; } else if (escape) { - if (str[i] != ':' && - str[i] != ';' && - str[i] != '\\' && - str[i] != '\"') - { - SCLogDebug("character \"%c\" does not need to be escaped but is" ,str[i]); + if (str[i] != ':' && str[i] != ';' && str[i] != '\\' && str[i] != '\"') { + SCLogDebug("character \"%c\" does not need to be escaped but is", str[i]); } escape = 0; converted = 1; str[x] = str[i]; x++; - }else{ + } else { str[x] = str[i]; x++; } - } -#if 0 //def DEBUG +#if 0 // def DEBUG if (SCLogDebugEnabled()) { for (i = 0; i < x; i++) { printf("%c", str[i]); diff --git a/src/detect-msg.h b/src/detect-msg.h index a21d51103524..ca571c0b3c5a 100644 --- a/src/detect-msg.h +++ b/src/detect-msg.h @@ -25,7 +25,6 @@ #define __DETECT_MSG_H__ /* prototypes */ -void DetectMsgRegister (void); +void DetectMsgRegister(void); #endif /* __DETECT_MSG_H__ */ - diff --git a/src/detect-nfs-procedure.c b/src/detect-nfs-procedure.c deleted file mode 100644 index 24c1563df18f..000000000000 --- a/src/detect-nfs-procedure.c +++ /dev/null @@ -1,443 +0,0 @@ -/* Copyright (C) 2017-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-nfs-procedure.h" -#include "detect-engine-uint.h" - -#include "app-layer-parser.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" - -#include "app-layer-nfs-tcp.h" -#include "rust.h" - -static int DetectNfsProcedureSetup (DetectEngineCtx *, Signature *s, const char *str); -static void DetectNfsProcedureFree(DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectNfsProcedureRegisterTests(void); -#endif -static int g_nfs_request_buffer_id = 0; - -static int DetectNfsProcedureMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); - -/** - * \brief Registration function for nfs_procedure keyword. - */ -void DetectNfsProcedureRegister (void) -{ - sigmatch_table[DETECT_AL_NFS_PROCEDURE].name = "nfs_procedure"; - sigmatch_table[DETECT_AL_NFS_PROCEDURE].desc = "match NFS procedure"; - sigmatch_table[DETECT_AL_NFS_PROCEDURE].url = "/rules/nfs-keywords.html#procedure"; - sigmatch_table[DETECT_AL_NFS_PROCEDURE].Match = NULL; - sigmatch_table[DETECT_AL_NFS_PROCEDURE].AppLayerTxMatch = DetectNfsProcedureMatch; - sigmatch_table[DETECT_AL_NFS_PROCEDURE].Setup = DetectNfsProcedureSetup; - sigmatch_table[DETECT_AL_NFS_PROCEDURE].Free = DetectNfsProcedureFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_NFS_PROCEDURE].RegisterTests = DetectNfsProcedureRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister2( - "nfs_request", ALPROTO_NFS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - - g_nfs_request_buffer_id = DetectBufferTypeGetByName("nfs_request"); - - SCLogDebug("g_nfs_request_buffer_id %d", g_nfs_request_buffer_id); -} - -/** - * \internal - * \brief Function to match procedure of a TX - * - * For 'file txs' - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectNfsProcedureMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - SCEnter(); - - const DetectU32Data *dd = (const DetectU32Data *)ctx; - uint16_t i; - for (i = 0; i < 256; i++) { - uint32_t procedure; - if (rs_nfs_tx_get_procedures(txv, i, &procedure) == 1) { - SCLogDebug("proc %u mode %u lo %u hi %u", procedure, dd->mode, dd->arg1, dd->arg2); - if (DetectU32Match(procedure, dd)) - SCReturnInt(1); - continue; - } - break; - } - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to parse options passed via tls validity keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectU32Data on success. - * \retval NULL on failure. - */ -static DetectU32Data *DetectNfsProcedureParse(const char *rawstr) -{ - return rs_detect_u32_parse_inclusive(rawstr); -} - - - -/** - * \brief Function to add the parsed tls validity field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectNfsProcedureSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - DetectU32Data *dd = NULL; - - SCLogDebug("\'%s\'", rawstr); - - if (DetectSignatureSetAppProto(s, ALPROTO_NFS) != 0) - return -1; - - dd = DetectNfsProcedureParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - SCLogDebug("low %u hi %u", dd->arg1, dd->arg2); - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_NFS_PROCEDURE, (SigMatchCtx *)dd, - g_nfs_request_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectNfsProcedureFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -void DetectNfsProcedureFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} - -#ifdef UNITTESTS - -/** - * \test This is a test for a valid value 1430000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse01 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("1430000000"); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_EQ); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \test This is a test for a valid value >1430000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse02 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse(">1430000000"); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_GT); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \test This is a test for a valid value <1430000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse03 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("<1430000000"); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_LT); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \test This is a test for a valid value 1430000000<>1470000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse04 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("1430000001<>1470000000"); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->arg2 == 1470000001 && dd->mode == DETECT_UINT_RA); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \test This is a test for a invalid value A. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse05 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("A"); - FAIL_IF_NOT_NULL(dd); - PASS; -} - -/** - * \test This is a test for a invalid value >1430000000<>1470000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse06 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse(">1430000000<>1470000000"); - FAIL_IF_NOT_NULL(dd); - PASS; -} - -/** - * \test This is a test for a invalid value 1430000000<>. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse07 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("1430000000<>"); - FAIL_IF_NOT_NULL(dd); - PASS; -} - -/** - * \test This is a test for a invalid value <>1430000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse08 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("<>1430000000"); - FAIL_IF_NOT_NULL(dd); - PASS; -} - -/** - * \test This is a test for a invalid value "". - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse09 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse(""); - FAIL_IF_NOT_NULL(dd); - PASS; -} - -/** - * \test This is a test for a invalid value " ". - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse10 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse(" "); - FAIL_IF_NOT_NULL(dd); - PASS; -} - -/** - * \test This is a test for a invalid value 1490000000<>1430000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse11 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("1490000000<>1430000000"); - FAIL_IF_NOT_NULL(dd); - PASS; -} - -/** - * \test This is a test for a valid value 1430000000 <> 1490000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse12 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("1430000001 <> 1490000000"); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->arg2 == 1490000001 && dd->mode == DETECT_UINT_RA); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \test This is a test for a valid value > 1430000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse13 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("> 1430000000 "); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_GT); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \test This is a test for a valid value < 1490000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse14 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse("< 1490000000 "); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1490000000 && dd->mode == DETECT_UINT_LT); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \test This is a test for a valid value 1490000000. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int ValidityTestParse15 (void) -{ - DetectU32Data *dd = NULL; - dd = DetectNfsProcedureParse(" 1490000000 "); - FAIL_IF_NULL(dd); - FAIL_IF_NOT(dd->arg1 == 1490000000 && dd->mode == DETECT_UINT_EQ); - DetectNfsProcedureFree(NULL, dd); - PASS; -} - -/** - * \brief Register unit tests for nfs_procedure. - */ -void DetectNfsProcedureRegisterTests(void) -{ - UtRegisterTest("ValidityTestParse01", ValidityTestParse01); - UtRegisterTest("ValidityTestParse02", ValidityTestParse02); - UtRegisterTest("ValidityTestParse03", ValidityTestParse03); - UtRegisterTest("ValidityTestParse04", ValidityTestParse04); - UtRegisterTest("ValidityTestParse05", ValidityTestParse05); - UtRegisterTest("ValidityTestParse06", ValidityTestParse06); - UtRegisterTest("ValidityTestParse07", ValidityTestParse07); - UtRegisterTest("ValidityTestParse08", ValidityTestParse08); - UtRegisterTest("ValidityTestParse09", ValidityTestParse09); - UtRegisterTest("ValidityTestParse10", ValidityTestParse10); - UtRegisterTest("ValidityTestParse11", ValidityTestParse11); - UtRegisterTest("ValidityTestParse12", ValidityTestParse12); - UtRegisterTest("ValidityTestParse13", ValidityTestParse13); - UtRegisterTest("ValidityTestParse14", ValidityTestParse14); - UtRegisterTest("ValidityTestParse15", ValidityTestParse15); -} -#endif /* UNITTESTS */ diff --git a/src/detect-nfs-procedure.h b/src/detect-nfs-procedure.h deleted file mode 100644 index e7b225677899..000000000000 --- a/src/detect-nfs-procedure.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __DETECT_NFS_PROCEDURE_H__ -#define __DETECT_NFS_PROCEDURE_H__ - -/* prototypes */ -void DetectNfsProcedureRegister (void); - -#endif /* __DETECT_NFS_PROCEDURE_H__ */ diff --git a/src/detect-nfs-version.c b/src/detect-nfs-version.c deleted file mode 100644 index 99c88149a73e..000000000000 --- a/src/detect-nfs-version.c +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (C) 2017-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-nfs-version.h" -#include "detect-engine-uint.h" - -#include "app-layer-parser.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" - -#include "app-layer-nfs-tcp.h" -#include "rust.h" - - -static int DetectNfsVersionSetup (DetectEngineCtx *, Signature *s, const char *str); -static void DetectNfsVersionFree(DetectEngineCtx *de_ctx, void *); -static int g_nfs_request_buffer_id = 0; - -static int DetectNfsVersionMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); - -/** - * \brief Registration function for nfs_procedure keyword. - */ -void DetectNfsVersionRegister (void) -{ - sigmatch_table[DETECT_AL_NFS_VERSION].name = "nfs.version"; - sigmatch_table[DETECT_AL_NFS_VERSION].alias = "nfs_version"; - sigmatch_table[DETECT_AL_NFS_VERSION].desc = "match NFS version"; - sigmatch_table[DETECT_AL_NFS_VERSION].url = "/rules/nfs-keywords.html#version"; - sigmatch_table[DETECT_AL_NFS_VERSION].AppLayerTxMatch = DetectNfsVersionMatch; - sigmatch_table[DETECT_AL_NFS_VERSION].Setup = DetectNfsVersionSetup; - sigmatch_table[DETECT_AL_NFS_VERSION].Free = DetectNfsVersionFree; - // unit tests were the same as DetectNfsProcedureRegisterTests - DetectAppLayerInspectEngineRegister2( - "nfs_request", ALPROTO_NFS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - - g_nfs_request_buffer_id = DetectBufferTypeGetByName("nfs_request"); - - SCLogDebug("g_nfs_request_buffer_id %d", g_nfs_request_buffer_id); -} - -/** - * \internal - * \brief Function to match version of a TX - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectNfsVersionMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - SCEnter(); - - const DetectU32Data *dd = (const DetectU32Data *)ctx; - uint32_t version; - rs_nfs_tx_get_version(txv, &version); - SCLogDebug("version %u mode %u lo %u hi %u", version, dd->mode, dd->arg1, dd->arg2); - if (DetectU32Match(version, dd)) - SCReturnInt(1); - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to parse options passed via tls validity keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectU32Data on success. - * \retval NULL on failure. - */ -static DetectU32Data *DetectNfsVersionParse(const char *rawstr) -{ - return rs_detect_u32_parse_inclusive(rawstr); -} - - - -/** - * \brief Function to add the parsed tls validity field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectNfsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - SCLogDebug("\'%s\'", rawstr); - - if (DetectSignatureSetAppProto(s, ALPROTO_NFS) != 0) - return -1; - - DetectU32Data *dd = DetectNfsVersionParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - return -1; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - SCLogDebug("low %u hi %u", dd->arg1, dd->arg2); - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_NFS_VERSION, (SigMatchCtx *)dd, - g_nfs_request_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectNfsVersionFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -void DetectNfsVersionFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} diff --git a/src/detect-nfs-version.h b/src/detect-nfs-version.h deleted file mode 100644 index 84eda946119b..000000000000 --- a/src/detect-nfs-version.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __DETECT_NFS_VERSION_H__ -#define __DETECT_NFS_VERSION_H__ - -/* prototypes */ -void DetectNfsVersionRegister (void); - -#endif /* __DETECT_NFS_VERSION_H__ */ diff --git a/src/detect-noalert.c b/src/detect-noalert.c index dda060a4f069..edcf51214269 100644 --- a/src/detect-noalert.c +++ b/src/detect-noalert.c @@ -26,11 +26,11 @@ #include "suricata-common.h" #include "detect.h" #include "detect-noalert.h" -#include "util-debug.h" +#include "util/debug.h" -static int DetectNoalertSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectNoalertSetup(DetectEngineCtx *, Signature *, const char *); -void DetectNoalertRegister (void) +void DetectNoalertRegister(void) { sigmatch_table[DETECT_NOALERT].name = "noalert"; sigmatch_table[DETECT_NOALERT].desc = "no alert will be generated by the rule"; @@ -39,7 +39,7 @@ void DetectNoalertRegister (void) sigmatch_table[DETECT_NOALERT].flags |= SIGMATCH_NOOPT; } -static int DetectNoalertSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectNoalertSetup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { if (nullstr != NULL) { SCLogError("nocase has no value"); @@ -49,4 +49,3 @@ static int DetectNoalertSetup (DetectEngineCtx *de_ctx, Signature *s, const char s->flags |= SIG_FLAG_NOALERT; return 0; } - diff --git a/src/detect-noalert.h b/src/detect-noalert.h index abe39efcb9b9..ba8f2d4917d5 100644 --- a/src/detect-noalert.h +++ b/src/detect-noalert.h @@ -25,7 +25,6 @@ #define __DETECT_NOALERT_H__ /* prototypes */ -void DetectNoalertRegister (void); +void DetectNoalertRegister(void); #endif /* __DETECT_NOALERT_H__ */ - diff --git a/src/detect-nocase.c b/src/detect-nocase.c index deed7b2513da..c14f4adb2ef5 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -32,9 +32,9 @@ #include "detect-content.h" #include "detect-nocase.h" -#include "util-debug.h" +#include "util/debug.h" -static int DetectNocaseSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectNocaseSetup(DetectEngineCtx *, Signature *, const char *); void DetectNocaseRegister(void) { @@ -54,7 +54,7 @@ void DetectNocaseRegister(void) * \retval 0 ok * \retval -1 failure */ -static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectNocaseSetup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); @@ -76,6 +76,6 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, const char DetectContentData *cd = (DetectContentData *)pm->ctx; ret = DetectContentConvertToNocase(de_ctx, cd); - end: +end: SCReturnInt(ret); } diff --git a/src/detect-nocase.h b/src/detect-nocase.h index 4ba6723eb7f2..b84c23121ecb 100644 --- a/src/detect-nocase.h +++ b/src/detect-nocase.h @@ -25,7 +25,6 @@ #define __DETECT_NOCASE_H__ /* prototypes */ -void DetectNocaseRegister (void); +void DetectNocaseRegister(void); #endif /* __DETECT_NOCASE_H__ */ - diff --git a/src/detect-offset.c b/src/detect-offset.c index dd56e9a48260..5ca48240d5f1 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -38,20 +38,21 @@ #include "flow-var.h" -#include "util-byte.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/debug.h" static int DetectOffsetSetup(DetectEngineCtx *, Signature *, const char *); -void DetectOffsetRegister (void) +void DetectOffsetRegister(void) { sigmatch_table[DETECT_OFFSET].name = "offset"; - sigmatch_table[DETECT_OFFSET].desc = "designate from which byte in the payload will be checked to find a match"; + sigmatch_table[DETECT_OFFSET].desc = + "designate from which byte in the payload will be checked to find a match"; sigmatch_table[DETECT_OFFSET].url = "/rules/payload-keywords.html#offset"; sigmatch_table[DETECT_OFFSET].Setup = DetectOffsetSetup; } -int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *offsetstr) +int DetectOffsetSetup(DetectEngineCtx *de_ctx, Signature *s, const char *offsetstr) { const char *str = offsetstr; @@ -101,15 +102,13 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *offset cd->offset = index; cd->flags |= DETECT_CONTENT_OFFSET_VAR; } else { - if (StringParseUint16(&cd->offset, 0, 0, str) < 0) - { + if (StringParseUint16(&cd->offset, 0, 0, str) < 0) { SCLogError("invalid value for offset: %s.", str); return -1; } if (cd->depth != 0) { if (cd->depth < cd->content_len) { - SCLogDebug("depth increased to %"PRIu32" to match pattern len", - cd->content_len); + SCLogDebug("depth increased to %" PRIu32 " to match pattern len", cd->content_len); cd->depth = cd->content_len; } /* Updating the depth as is relative to the offset */ @@ -119,4 +118,3 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *offset cd->flags |= DETECT_CONTENT_OFFSET; return 0; } - diff --git a/src/detect-offset.h b/src/detect-offset.h index 76befe17de3a..96f5ba064742 100644 --- a/src/detect-offset.h +++ b/src/detect-offset.h @@ -25,7 +25,6 @@ #define __DETECT_OFFSET_H__ /* prototypes */ -void DetectOffsetRegister (void); +void DetectOffsetRegister(void); #endif /* __DETECT_OFFSET_H__ */ - diff --git a/src/detect-parse.c b/src/detect-parse.c index e1ac5f74b5a4..dd6eb87994a5 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -43,35 +43,35 @@ #include "detect-app-layer-protocol.h" #include "detect-lua.h" #include "detect-app-layer-event.h" -#include "detect-http-method.h" +#include "app-layer/http/detect-method.h" #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" +#include "util/profiling.h" #include "decode.h" #include "flow.h" -#include "util-rule-vars.h" +#include "util/rule-vars.h" #include "conf.h" #include "conf-yaml-loader.h" #include "app-layer.h" #include "app-layer-protos.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" -#include "util-classification-config.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/classification-config.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" #include "string.h" #include "detect-parse.h" #include "detect-engine-iponly.h" #include "app-layer-detect-proto.h" #include "action-globals.h" -#include "util-validate.h" +#include "util/validate.h" /* Table with all filehandler registrations */ DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE]; @@ -130,9 +130,8 @@ SigTableElmt sigmatch_table[DETECT_TBLSIZE]; extern bool sc_set_caps; -static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, - SigMatch **src_sm_list, SigMatch **src_sm_list_tail, - SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail); +static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, SigMatch **src_sm_list, + SigMatch **src_sm_list_tail, SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail); /** * \brief Registration table for file handlers @@ -172,7 +171,10 @@ typedef struct SignatureParser_ { const char *DetectListToHumanString(int list) { -#define CASE_CODE_STRING(E, S) case E: return S; break +#define CASE_CODE_STRING(E, S) \ + case E: \ + return S; \ + break switch (list) { CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); @@ -187,7 +189,9 @@ const char *DetectListToHumanString(int list) return "unknown"; } -#define CASE_CODE(E) case E: return #E +#define CASE_CODE(E) \ + case E: \ + return #E const char *DetectListToString(int list) { switch (list) { @@ -204,9 +208,8 @@ const char *DetectListToString(int list) } /** \param arg NULL or empty string */ -int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, - Signature *s, const char *arg, int sm_type, int sm_list, - AppProto alproto) +int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, + int sm_type, int sm_list, AppProto alproto) { SigMatch *sm = NULL; int ret = -1; @@ -231,8 +234,7 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, goto end; } - sm = DetectGetLastSMByListId(s, - DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1); + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1); if (sm == NULL) { SCLogError("\"%s\" keyword " "found inside the rule without a content context. " @@ -255,8 +257,7 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, goto end; } if (cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) { - SigMatch *pm = DetectGetLastSMByListPtr(s, sm->prev, - DETECT_CONTENT, DETECT_PCRE, -1); + SigMatch *pm = DetectGetLastSMByListPtr(s, sm->prev, DETECT_CONTENT, DETECT_PCRE, -1); if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; @@ -328,7 +329,7 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, } ret = 0; - end: +end: return ret; } @@ -378,9 +379,9 @@ static SigTableElmt *SigTableGet(char *name) st = &sigmatch_table[i]; if (st->name != NULL) { - if (strcasecmp(name,st->name) == 0) + if (strcasecmp(name, st->name) == 0) return st; - if (st->alias != NULL && strcasecmp(name,st->alias) == 0) + if (st->alias != NULL && strcasecmp(name, st->alias) == 0) return st; } } @@ -388,8 +389,7 @@ static SigTableElmt *SigTableGet(char *name) return NULL; } -bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, - const enum DetectKeywordId id) +bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, const enum DetectKeywordId id) { return de_ctx->sm_types_silent_error[id]; } @@ -649,16 +649,14 @@ SigMatch *DetectGetLastSMFromLists(const Signature *s, ...) for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) { if (s->init_data->smlists[buf_type] == NULL) continue; - if (s->init_data->list != DETECT_SM_LIST_NOTSET && - buf_type != s->init_data->list) + if (s->init_data->list != DETECT_SM_LIST_NOTSET && buf_type != s->init_data->list) continue; int sm_type; va_list ap; va_start(ap, s); - for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) - { + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) { sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type); if (sm_new == NULL) continue; @@ -689,8 +687,7 @@ SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...) va_list ap; va_start(ap, sm_list); - for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) - { + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) { sm_new = SigMatchGetLastSMByType(sm_list, sm_type); if (sm_new == NULL) continue; @@ -787,9 +784,8 @@ SigMatch *DetectGetLastSM(const Signature *s) return sm_last; } -static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, - SigMatch **src_sm_list, SigMatch **src_sm_list_tail, - SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) +static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, SigMatch **src_sm_list, + SigMatch **src_sm_list_tail, SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) { /* we won't do any checks for args */ @@ -847,7 +843,8 @@ int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm) return -1; } -static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output, size_t output_size) +static int SigParseOptions( + DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output, size_t output_size) { SigTableElmt *st = NULL; char *optname = NULL; @@ -865,8 +862,7 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, if (optend == NULL) { SCLogError("no terminating \";\" found"); goto error; - } - else if (optend > optstr && *(optend -1 ) == '\\') { + } else if (optend > optstr && *(optend - 1) == '\\') { optend++; } else { break; @@ -908,7 +904,7 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, goto error; } - if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) { + if (!(st->flags & (SIGMATCH_NOOPT | SIGMATCH_OPTIONAL_OPT))) { if (optvalue == NULL || strlen(optvalue) == 0) { SCLogError( "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr); @@ -982,9 +978,8 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, goto error; } - if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY)) - && ovlen && *ptr == '"') - { + if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_QUOTES_MANDATORY)) && ovlen && + *ptr == '"') { for (; ovlen > 0; ovlen--) { if (isblank(ptr[ovlen - 1])) { ptr[ovlen - 1] = '\0'; @@ -1055,8 +1050,7 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, * * \retval 0 ok, -1 error */ -static int SigParseAddress(DetectEngineCtx *de_ctx, - Signature *s, const char *addrstr, char flag) +static int SigParseAddress(DetectEngineCtx *de_ctx, Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); @@ -1065,16 +1059,16 @@ static int SigParseAddress(DetectEngineCtx *de_ctx, if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_SRC_ANY; - s->init_data->src = DetectParseAddress(de_ctx, addrstr, - &s->init_data->src_contains_negation); + s->init_data->src = + DetectParseAddress(de_ctx, addrstr, &s->init_data->src_contains_negation); if (s->init_data->src == NULL) goto error; } else { if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_DST_ANY; - s->init_data->dst = DetectParseAddress(de_ctx, addrstr, - &s->init_data->dst_contains_negation); + s->init_data->dst = + DetectParseAddress(de_ctx, addrstr, &s->init_data->dst_contains_negation); if (s->init_data->dst == NULL) goto error; } @@ -1109,8 +1103,7 @@ static int SigParseProto(Signature *s, const char *protostr) s->flags |= SIG_FLAG_APPLAYER; AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto); - } - else { + } else { SCLogError("protocol \"%s\" cannot be used " "in a signature. Either detection for this protocol " "is not yet supported OR detection has been disabled for " @@ -1144,8 +1137,7 @@ static int SigParseProto(Signature *s, const char *protostr) * \retval 0 On success. * \retval -1 On failure. */ -static int SigParsePort(const DetectEngineCtx *de_ctx, - Signature *s, const char *portstr, char flag) +static int SigParsePort(const DetectEngineCtx *de_ctx, Signature *s, const char *portstr, char flag) { int r = 0; @@ -1213,20 +1205,18 @@ static int SigParseAction(Signature *s, const char *action) s->action = ACTION_DROP; } else if (strcasecmp(action, "pass") == 0) { s->action = ACTION_PASS; - } else if (strcasecmp(action, "reject") == 0 || - strcasecmp(action, "rejectsrc") == 0) - { + } else if (strcasecmp(action, "reject") == 0 || strcasecmp(action, "rejectsrc") == 0) { if (!(SigParseActionRejectValidate(action))) return -1; - s->action = ACTION_REJECT|ACTION_DROP; + s->action = ACTION_REJECT | ACTION_DROP; } else if (strcasecmp(action, "rejectdst") == 0) { if (!(SigParseActionRejectValidate(action))) return -1; - s->action = ACTION_REJECT_DST|ACTION_DROP; + s->action = ACTION_REJECT_DST | ACTION_DROP; } else if (strcasecmp(action, "rejectboth") == 0) { if (!(SigParseActionRejectValidate(action))) return -1; - s->action = ACTION_REJECT_BOTH|ACTION_DROP; + s->action = ACTION_REJECT_BOTH | ACTION_DROP; } else if (strcasecmp(action, "config") == 0) { s->action = ACTION_CONFIG; s->flags |= SIG_FLAG_NOALERT; @@ -1248,8 +1238,7 @@ static int SigParseAction(Signature *s, const char *action) * \param output buffer to copy token into. * \param output_size length of output buffer. */ -static inline int SigParseToken(char **input, char *output, - const size_t output_size) +static inline int SigParseToken(char **input, char *output, const size_t output_size) { size_t len = *input == NULL ? 0 : strlen(*input); @@ -1283,8 +1272,7 @@ static inline int SigParseToken(char **input, char *output, * \param output buffer to copy token into. * \param output_size length of output buffer. */ -static inline int SigParseList(char **input, char *output, - const size_t output_size) +static inline int SigParseList(char **input, char *output, const size_t output_size) { int in_list = 0; size_t len = *input != NULL ? strlen(*input) : 0; @@ -1326,8 +1314,8 @@ static inline int SigParseList(char **input, char *output, * \internal * \brief split a signature string into a few blocks for further parsing */ -static int SigParseBasics(DetectEngineCtx *de_ctx, - Signature *s, const char *sigstr, SignatureParser *parser, uint8_t addrs_direction) +static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr, + SignatureParser *parser, uint8_t addrs_direction) { char *index, dup[DETECT_MAX_RULE_SIZE]; @@ -1390,7 +1378,7 @@ static int SigParseBasics(DetectEngineCtx *de_ctx, /* Parse Address & Ports */ if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) - goto error; + goto error; if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) goto error; @@ -1437,8 +1425,8 @@ static inline bool CheckAscii(const char *str) * \param -1 parse error * \param 0 ok */ -static int SigParse(DetectEngineCtx *de_ctx, Signature *s, - const char *sigstr, uint8_t addrs_direction, SignatureParser *parser) +static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr, + uint8_t addrs_direction, SignatureParser *parser) { SCEnter(); @@ -1469,7 +1457,7 @@ static int SigParse(DetectEngineCtx *de_ctx, Signature *s, char input[buffer_size]; char output[buffer_size]; memset(input, 0x00, buffer_size); - memcpy(input, parser->opts, strlen(parser->opts)+1); + memcpy(input, parser->opts, strlen(parser->opts) + 1); /* loop the option parsing. Each run processes one option * and returns the rest of the option string through the @@ -1511,7 +1499,7 @@ int SignatureInitDataBufferCheckExpand(Signature *s) return 0; } -Signature *SigAlloc (void) +Signature *SigAlloc(void) { Signature *sig = SCCalloc(1, sizeof(Signature)); if (unlikely(sig == NULL)) @@ -1559,7 +1547,7 @@ static void SigMetadataFree(Signature *s) SCLogDebug("s %p, s->metadata %p", s, s->metadata); - for (mdata = s->metadata->list; mdata != NULL;) { + for (mdata = s->metadata->list; mdata != NULL;) { next_mdata = mdata->next; DetectMetadataFree(mdata); mdata = next_mdata; @@ -1577,7 +1565,7 @@ static void SigMetadataFree(Signature *s) * * \param s Pointer to the signature */ -static void SigRefFree (Signature *s) +static void SigRefFree(Signature *s) { SCEnter(); @@ -1590,7 +1578,7 @@ static void SigRefFree (Signature *s) SCLogDebug("s %p, s->references %p", s, s->references); - for (ref = s->references; ref != NULL;) { + for (ref = s->references; ref != NULL;) { next_ref = ref->next; DetectReferenceFree(ref); ref = next_ref; @@ -1609,7 +1597,7 @@ static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs) if (s->sm_arrays[type] != NULL) { if (ctxs) { SigMatchData *smd = s->sm_arrays[type]; - while(1) { + while (1) { if (sigmatch_table[smd->type].Free != NULL) { sigmatch_table[smd->type].Free(de_ctx, smd->ctx); } @@ -1639,7 +1627,7 @@ void SigFree(DetectEngineCtx *de_ctx, Signature *s) int i; if (s->init_data && s->init_data->transforms.cnt) { - for(i = 0; i < s->init_data->transforms.cnt; i++) { + for (i = 0; i < s->init_data->transforms.cnt; i++) { if (s->init_data->transforms.transforms[i].options) { int transform = s->init_data->transforms.transforms[i].transform; sigmatch_table[transform].Free( @@ -1727,17 +1715,14 @@ int DetectSignatureAddTransform(Signature *s, int transform, void *options) s->init_data->transforms.transforms[s->init_data->transforms.cnt].options = options; s->init_data->transforms.cnt++; - SCLogDebug("Added transform #%d [%s]", - s->init_data->transforms.cnt, - s->sig_str); + SCLogDebug("Added transform #%d [%s]", s->init_data->transforms.cnt, s->sig_str); SCReturnInt(0); } int DetectSignatureSetAppProto(Signature *s, AppProto alproto) { - if (alproto == ALPROTO_UNKNOWN || - alproto >= ALPROTO_FAILED) { + if (alproto == ALPROTO_UNKNOWN || alproto >= ALPROTO_FAILED) { SCLogError("invalid alproto %u", alproto); return -1; } @@ -1783,7 +1768,7 @@ static void SigBuildAddressMatchArray(Signature *s) uint16_t cnt = 0; uint16_t idx = 0; DetectAddress *da = s->init_data->src->ipv4_head; - for ( ; da != NULL; da = da->next) { + for (; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { @@ -1804,7 +1789,7 @@ static void SigBuildAddressMatchArray(Signature *s) cnt = 0; idx = 0; da = s->init_data->dst->ipv4_head; - for ( ; da != NULL; da = da->next) { + for (; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { @@ -1825,7 +1810,7 @@ static void SigBuildAddressMatchArray(Signature *s) cnt = 0; idx = 0; da = s->init_data->src->ipv6_head; - for ( ; da != NULL; da = da->next) { + for (; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { @@ -1852,7 +1837,7 @@ static void SigBuildAddressMatchArray(Signature *s) cnt = 0; idx = 0; da = s->init_data->dst->ipv6_head; - for ( ; da != NULL; da = da->next) { + for (; da != NULL; da = da->next) { cnt++; } if (cnt > 0) { @@ -1888,7 +1873,7 @@ static int SigMatchListLen(SigMatch *sm) /** \brief convert SigMatch list to SigMatchData array * \note ownership of sm->ctx is transferred to smd->ctx */ -SigMatchData* SigMatchList2DataArray(SigMatch *head) +SigMatchData *SigMatchList2DataArray(SigMatch *head) { int len = SigMatchListLen(head); if (len == 0) @@ -2040,14 +2025,14 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id); } - if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && - (s->flags & SIG_FLAG_REQUIRE_STREAM)) { + if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && (s->flags & SIG_FLAG_REQUIRE_STREAM)) { SCLogError("can't mix packet keywords with " "tcp-stream or flow:only_stream. Invalidating signature."); SCReturnInt(0); } - if ((sig_flags & (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) { + if ((sig_flags & (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) == + (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) { SCLogError("You seem to have mixed keywords " "that require inspection in both directions. Atm we only " "support keywords in one direction within a rule."); @@ -2079,7 +2064,7 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s) sm = sm->next) { if (sm->type == DETECT_CONTENT && (((DetectContentData *)(sm->ctx))->flags & - (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) { + (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) { s->flags |= SIG_FLAG_REQUIRE_PACKET; break; } @@ -2105,10 +2090,9 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 || - (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA)) { + (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA)) { if (s->alproto != ALPROTO_UNKNOWN && - !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) - { + !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) { SCLogError("protocol %s doesn't " "support file matching", AppProtoToString(s->alproto)); @@ -2134,8 +2118,7 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s) * \internal * \brief Helper function for SigInit(). */ -static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr, - uint8_t dir) +static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir) { SignatureParser parser; memset(&parser, 0x00, sizeof(parser)); @@ -2152,8 +2135,7 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr, de_ctx->sigerror_silent = true; de_ctx->sigerror_ok = true; goto error; - } - else if (ret == -2) { + } else if (ret == -2) { de_ctx->sigerror_silent = true; goto error; } else if (ret < 0) { @@ -2197,7 +2179,7 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr, if (!(sig->flags & SIG_FLAG_APPLAYER)) { if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) { SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; - for ( ; sm != NULL; sm = sm->next) { + for (; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].Match != NULL) sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET; } @@ -2207,15 +2189,15 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr, } if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) { - if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) { + if ((sig->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == 0) { sig->flags |= SIG_FLAG_TOSERVER; sig->flags |= SIG_FLAG_TOCLIENT; } } - SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s", - sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set", - sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); + SCLogDebug("sig %" PRIu32 " SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s", sig->id, + sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set", + sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); SigBuildAddressMatchArray(sig); @@ -2311,7 +2293,8 @@ Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr) if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { if (SigHasSameSourceAndDestination(sig)) { SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, " - "treating the rule as unidirectional", sig->id); + "treating the rule as unidirectional", + sig->id); sig->init_data->init_flags &= ~SIG_FLAG_INIT_BIDIREC; } else { @@ -2378,18 +2361,17 @@ static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_ * \retval 1 If the 2 SigDuplWrappers sent as args match. * \retval 0 If the 2 SigDuplWrappers sent as args do not match. */ -static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) +static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) { SigDuplWrapper *sw1 = (SigDuplWrapper *)data1; SigDuplWrapper *sw2 = (SigDuplWrapper *)data2; - if (sw1 == NULL || sw2 == NULL || - sw1->s == NULL || sw2->s == NULL) + if (sw1 == NULL || sw2 == NULL || sw1->s == NULL || sw2->s == NULL) return 0; /* sid and gid match required */ - if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1; + if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) + return 1; return 0; } @@ -2404,10 +2386,8 @@ static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2 */ int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx) { - de_ctx->dup_sig_hash_table = HashListTableInit(15000, - DetectParseDupSigHashFunc, - DetectParseDupSigCompareFunc, - DetectParseDupSigFreeFunc); + de_ctx->dup_sig_hash_table = HashListTableInit(15000, DetectParseDupSigHashFunc, + DetectParseDupSigCompareFunc, DetectParseDupSigFreeFunc); if (de_ctx->dup_sig_hash_table == NULL) return -1; @@ -2449,8 +2429,7 @@ void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx) * \retval 1 If Signature is duplicate, and should be chucked out. * \retval 0 If Signature is not a duplicate. */ -static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, - Signature *sig) +static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, Signature *sig) { /* we won't do any NULL checks on the args */ @@ -2482,8 +2461,7 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, /* the topmost sig would be the last loaded sig */ sw_tmp.s = de_ctx->sig_list; - sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table, - (void *)&sw_tmp, 0); + sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)&sw_tmp, 0); /* sw_old == NULL case is impossible */ sw_old->s_prev = sig; } @@ -2517,8 +2495,7 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, } SigDuplWrapper *sw_next = NULL; if (sw_temp.s != NULL) { - sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, - (void *)&sw_temp, 0); + sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)&sw_temp, 0); sw_next->s_prev = sw_dup->s_prev; } SigFree(de_ctx, sw_dup->s); @@ -2547,8 +2524,7 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, } SigDuplWrapper *sw_next = NULL; if (sw_temp.s != NULL) { - sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, - (void *)&sw_temp, 0); + sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)&sw_temp, 0); sw_next->s_prev = sw_dup->s_prev; } SigFree(de_ctx, sw_dup->s); @@ -2562,8 +2538,8 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, SigDuplWrapper sw_tmp; memset(&sw_tmp, 0, sizeof(SigDuplWrapper)); sw_tmp.s = de_ctx->sig_list; - SigDuplWrapper *sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table, - (void *)&sw_tmp, 0); + SigDuplWrapper *sw_old = + HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)&sw_tmp, 0); if (sw_old->s != sw_dup->s) { // Link on top of the list if there was another element sw_old->s_prev = sig; @@ -2784,7 +2760,6 @@ void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_par } } - /* * TESTS */ @@ -2793,7 +2768,7 @@ void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_par #include "detect-engine-alert.h" #include "packet.h" -static int SigParseTest01 (void) +static int SigParseTest01(void) { int result = 1; Signature *sig = NULL; @@ -2807,12 +2782,14 @@ static int SigParseTest01 (void) result = 0; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } -static int SigParseTest02 (void) +static int SigParseTest02(void) { int result = 0; Signature *sig = NULL; @@ -2826,7 +2803,9 @@ static int SigParseTest02 (void) FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); SCClassConfLoadClassificationConfigFile(de_ctx, fd); - sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); + sig = SigInit(de_ctx, + "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local " + "Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); if (sig == NULL) { goto end; } @@ -2838,7 +2817,10 @@ static int SigParseTest02 (void) if (DetectPortCmp(sig->sp, port) == PORT_EQ) { result = 1; } else { - DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": "); + DetectPortPrint(port); + printf(" != "); + DetectPortPrint(sig->sp); + printf(": "); } end: @@ -2854,7 +2836,7 @@ static int SigParseTest02 (void) /** * \test SigParseTest03 test for invalid direction operator in rule */ -static int SigParseTest03 (void) +static int SigParseTest03(void) { int result = 1; Signature *sig = NULL; @@ -2866,16 +2848,18 @@ static int SigParseTest03 (void) sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)"); if (sig != NULL) { result = 0; - printf("expected NULL got sig ptr %p: ",sig); + printf("expected NULL got sig ptr %p: ", sig); } end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } -static int SigParseTest04 (void) +static int SigParseTest04(void) { int result = 1; Signature *sig = NULL; @@ -2884,18 +2868,21 @@ static int SigParseTest04 (void) if (de_ctx == NULL) goto end; - sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)"); + sig = SigInit( + de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)"); if (sig == NULL) result = 0; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Port validation */ -static int SigParseTest05 (void) +static int SigParseTest05(void) { int result = 0; Signature *sig = NULL; @@ -2904,7 +2891,8 @@ static int SigParseTest05 (void) if (de_ctx == NULL) goto end; - sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)"); + sig = SigInit(de_ctx, + "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)"); if (sig == NULL) { result = 1; } else { @@ -2912,13 +2900,15 @@ static int SigParseTest05 (void) } end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Parsing bug debugging at 2010-03-18 */ -static int SigParseTest06 (void) +static int SigParseTest06(void) { int result = 0; Signature *sig = NULL; @@ -2927,7 +2917,9 @@ static int SigParseTest06 (void) if (de_ctx == NULL) goto end; - sig = SigInit(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)"); + sig = SigInit(de_ctx, + "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; " + "uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)"); if (sig != NULL) { result = 1; } else { @@ -3003,8 +2995,7 @@ static int SigParseTest09(void) DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)"); - result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && - de_ctx->sig_list->rev == 2); + result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && de_ctx->sig_list->rev == 2); if (result == 0) goto end; result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && @@ -3013,8 +3004,7 @@ static int SigParseTest09(void) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)"); - result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && - de_ctx->sig_list->rev == 2); + result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && de_ctx->sig_list->rev == 2); if (result == 0) goto end; result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && @@ -3023,8 +3013,7 @@ static int SigParseTest09(void) goto end; DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)"); - result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && - de_ctx->sig_list->rev == 4); + result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 && de_ctx->sig_list->rev == 4); if (result == 0) goto end; result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 && @@ -3057,8 +3046,7 @@ static int SigParseTest10(void) DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)"); DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)"); - result &= ((de_ctx->sig_list->id == 2) && - (de_ctx->sig_list->next->id == 3) && + result &= ((de_ctx->sig_list->id == 2) && (de_ctx->sig_list->next->id == 3) && (de_ctx->sig_list->next->next->id == 5) && (de_ctx->sig_list->next->next->next->id == 4) && (de_ctx->sig_list->next->next->next->next->id == 1)); @@ -3117,7 +3105,8 @@ static int SigParseTest12(void) Signature *s = NULL; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)"); + s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)"); if (s != NULL) { printf("sig 1 should have given an error: "); goto end; @@ -3180,7 +3169,8 @@ static int SigParseTest14(void) Signature *s = NULL; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)"); + s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; @@ -3217,7 +3207,8 @@ static int SigParseTest15(void) Signature *s = NULL; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)"); + s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; @@ -3254,7 +3245,8 @@ static int SigParseTest16(void) Signature *s = NULL; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)"); + s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; @@ -3291,7 +3283,8 @@ static int SigParseTest17(void) Signature *s = NULL; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)"); + s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)"); if (s == NULL) { printf("sig 1 invalidated: failure"); goto end; @@ -3316,7 +3309,7 @@ static int SigParseTest17(void) } /** \test sid value too large. Bug #779 */ -static int SigParseTest18 (void) +static int SigParseTest18(void) { int result = 0; @@ -3324,7 +3317,9 @@ static int SigParseTest18 (void) if (de_ctx == NULL) goto end; - if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL) + if (DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 any -> !1.2.3.4 any " + "(msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL) goto end; result = 1; @@ -3335,7 +3330,7 @@ static int SigParseTest18 (void) } /** \test gid value too large. Related to bug #779 */ -static int SigParseTest19 (void) +static int SigParseTest19(void) { int result = 0; @@ -3343,7 +3338,9 @@ static int SigParseTest19 (void) if (de_ctx == NULL) goto end; - if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL) + if (DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; " + "gid:99999999999999999999;)") != NULL) goto end; result = 1; @@ -3354,7 +3351,7 @@ static int SigParseTest19 (void) } /** \test rev value too large. Related to bug #779 */ -static int SigParseTest20 (void) +static int SigParseTest20(void) { int result = 0; @@ -3362,7 +3359,9 @@ static int SigParseTest20 (void) if (de_ctx == NULL) goto end; - if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL) + if (DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; " + "rev:99999999999999999999;)") != NULL) goto end; result = 1; @@ -3373,7 +3372,7 @@ static int SigParseTest20 (void) } /** \test address parsing */ -static int SigParseTest21 (void) +static int SigParseTest21(void) { int result = 0; @@ -3381,7 +3380,8 @@ static int SigParseTest21 (void) if (de_ctx == NULL) goto end; - if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL) + if (DetectEngineAppendSig( + de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL) goto end; result = 1; @@ -3392,7 +3392,7 @@ static int SigParseTest21 (void) } /** \test address parsing */ -static int SigParseTest22 (void) +static int SigParseTest22(void) { int result = 0; @@ -3400,7 +3400,8 @@ static int SigParseTest22 (void) if (de_ctx == NULL) goto end; - if (DetectEngineAppendSig(de_ctx, "alert tcp [10.10.10.0/24, !10.10.10.247] any -> [10.10.10.0/24, !10.10.10.247] any (sid:1;)") == NULL) + if (DetectEngineAppendSig(de_ctx, "alert tcp [10.10.10.0/24, !10.10.10.247] any -> " + "[10.10.10.0/24, !10.10.10.247] any (sid:1;)") == NULL) goto end; result = 1; @@ -3420,7 +3421,8 @@ static int SigParseTest23(void) Signature *s = NULL; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r"); + s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r"); FAIL_IF_NULL(s); DetectEngineCtxFree(de_ctx); @@ -3428,7 +3430,7 @@ static int SigParseTest23(void) } /** \test Direction operator validation (invalid) */ -static int SigParseBidirecTest06 (void) +static int SigParseBidirecTest06(void) { int result = 1; Signature *sig = NULL; @@ -3437,18 +3439,21 @@ static int SigParseBidirecTest06 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ -static int SigParseBidirecTest07 (void) +static int SigParseBidirecTest07(void) { int result = 1; Signature *sig = NULL; @@ -3457,18 +3462,21 @@ static int SigParseBidirecTest07 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ -static int SigParseBidirecTest08 (void) +static int SigParseBidirecTest08(void) { int result = 1; Signature *sig = NULL; @@ -3477,18 +3485,21 @@ static int SigParseBidirecTest08 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ -static int SigParseBidirecTest09 (void) +static int SigParseBidirecTest09(void) { int result = 1; Signature *sig = NULL; @@ -3497,18 +3508,21 @@ static int SigParseBidirecTest09 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ -static int SigParseBidirecTest10 (void) +static int SigParseBidirecTest10(void) { int result = 1; Signature *sig = NULL; @@ -3517,18 +3531,21 @@ static int SigParseBidirecTest10 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ -static int SigParseBidirecTest11 (void) +static int SigParseBidirecTest11(void) { int result = 1; Signature *sig = NULL; @@ -3537,18 +3554,21 @@ static int SigParseBidirecTest11 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (invalid) */ -static int SigParseBidirecTest12 (void) +static int SigParseBidirecTest12(void) { int result = 1; Signature *sig = NULL; @@ -3557,18 +3577,21 @@ static int SigParseBidirecTest12 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig == NULL) result = 1; end: - if (sig != NULL) SigFree(de_ctx, sig); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (sig != NULL) + SigFree(de_ctx, sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (valid) */ -static int SigParseBidirecTest13 (void) +static int SigParseBidirecTest13(void) { int result = 1; Signature *sig = NULL; @@ -3577,17 +3600,19 @@ static int SigParseBidirecTest13 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig != NULL) result = 1; end: - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Direction operator validation (valid) */ -static int SigParseBidirecTest14 (void) +static int SigParseBidirecTest14(void) { int result = 1; Signature *sig = NULL; @@ -3596,19 +3621,21 @@ static int SigParseBidirecTest14 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)"); if (sig != NULL) result = 1; end: - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); return result; } /** \test Ensure that we don't set bidirectional in a * normal (one direction) Signature */ -static int SigTestBidirec01 (void) +static int SigTestBidirec01(void) { Signature *sig = NULL; int result = 0; @@ -3617,7 +3644,8 @@ static int SigTestBidirec01 (void) if (de_ctx == NULL) goto end; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)"); if (sig == NULL) goto end; if (sig->next != NULL) @@ -3639,7 +3667,7 @@ static int SigTestBidirec01 (void) } /** \test Ensure that we set a bidirectional Signature correctly */ -static int SigTestBidirec02 (void) +static int SigTestBidirec02(void) { int result = 0; Signature *sig = NULL; @@ -3651,7 +3679,8 @@ static int SigTestBidirec02 (void) de_ctx->flags |= DE_QUIET; - sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)"); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)"); if (sig == NULL) goto end; if (de_ctx->sig_list != sig) @@ -3681,10 +3710,10 @@ static int SigTestBidirec02 (void) } /** \test Ensure that we set a bidirectional Signature correctly -* and we install it with the rest of the signatures, checking -* also that it match with the correct addr directions -*/ -static int SigTestBidirec03 (void) + * and we install it with the rest of the signatures, checking + * also that it match with the correct addr directions + */ +static int SigTestBidirec03(void) { int result = 0; Signature *sig = NULL; @@ -3698,7 +3727,8 @@ static int SigTestBidirec03 (void) const char *sigs[3]; sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)"; - sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)"; + sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; " + "sid:2;)"; sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)"; UTHAppendSigs(de_ctx, sigs, 3); @@ -3717,6 +3747,7 @@ static int SigTestBidirec03 (void) if (de_ctx->signum != 4) goto end; + // clang-format off uint8_t rawpkt1_ether[] = { 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, @@ -3772,7 +3803,8 @@ static int SigTestBidirec03 (void) 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e, 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, - 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */ + 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; + // clang-format on /* end rawpkt1_ether */ FlowInitConfig(FLOW_QUIET); p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether)); @@ -3842,6 +3874,7 @@ static int SigTestBidirec04 (void) if (de_ctx->signum != 4) goto end; + // clang-format off uint8_t rawpkt1_ether[] = { 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c, 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00, @@ -3897,7 +3930,8 @@ static int SigTestBidirec04 (void) 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e, 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20, 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69, - 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */ + 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; + // clang-format on /* end rawpkt1_ether */ p = PacketGetFromAlloc(); if (unlikely(p == NULL)) diff --git a/src/detect-parse.h b/src/detect-parse.h index 2eecd286f631..524e42194910 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -45,19 +45,13 @@ void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *entry); extern DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE]; /** Flags to indicate if the Signature parsing must be done -* switching the source and dest (for ip addresses and ports) -* or otherwise as normal */ -enum { - SIG_DIREC_NORMAL, - SIG_DIREC_SWITCHED -}; + * switching the source and dest (for ip addresses and ports) + * or otherwise as normal */ +enum { SIG_DIREC_NORMAL, SIG_DIREC_SWITCHED }; /** Flags to indicate if are referencing the source of the Signature -* or the destination (for ip addresses and ports)*/ -enum { - SIG_DIREC_SRC, - SIG_DIREC_DST -}; + * or the destination (for ip addresses and ports)*/ +enum { SIG_DIREC_SRC, SIG_DIREC_DST }; typedef struct DetectParseRegex { pcre2_code *regex; @@ -71,7 +65,7 @@ int SignatureInitDataBufferCheckExpand(Signature *s); Signature *SigAlloc(void); void SigFree(DetectEngineCtx *de_ctx, Signature *s); Signature *SigInit(DetectEngineCtx *, const char *sigstr); -SigMatchData* SigMatchList2DataArray(SigMatch *head); +SigMatchData *SigMatchList2DataArray(SigMatch *head); void SigParseRegisterTests(void); Signature *DetectEngineAppendSig(DetectEngineCtx *, const char *); @@ -82,12 +76,10 @@ int SigMatchListSMBelongsTo(const Signature *, const SigMatch *); int DetectParseDupSigHashInit(DetectEngineCtx *); void DetectParseDupSigHashFree(DetectEngineCtx *); -int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, - Signature *s, const char *arg, int sm_type, int sm_list, - AppProto alproto); +int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, + int sm_type, int sm_list, AppProto alproto); -bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, - const enum DetectKeywordId id); +bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, const enum DetectKeywordId id); bool SigMatchStrictEnabled(const enum DetectKeywordId id); const char *DetectListToHumanString(int list); diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 848f6b9680fe..bb2a724ce9cd 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -42,23 +42,23 @@ #include "detect-engine-state.h" #include "detect-engine-build.h" -#include "util-var-name.h" -#include "util-unittest-helper.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-print.h" -#include "util-pool.h" +#include "util/var-name.h" +#include "util/unittest-helper.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/print.h" +#include "util/pool.h" #include "conf.h" #include "app-layer.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "stream.h" #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "app-layer-protos.h" #include "app-layer-parser.h" -#include "util-pages.h" +#include "util/pages.h" /* pcre named substring capture supports only 32byte names, A-z0-9 plus _ * and needs to start with non-numeric. */ @@ -87,32 +87,32 @@ static inline int DetectPcreExec(DetectEngineThreadCtx *det_ctx, const DetectPcr match, pd->parse_regex.context); } -static int DetectPcreSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectPcreSetup(DetectEngineCtx *, Signature *, const char *); static void DetectPcreFree(DetectEngineCtx *, void *); #ifdef UNITTESTS static void DetectPcreRegisterTests(void); #endif -void DetectPcreRegister (void) +void DetectPcreRegister(void) { sigmatch_table[DETECT_PCRE].name = "pcre"; sigmatch_table[DETECT_PCRE].desc = "match on regular expression"; - sigmatch_table[DETECT_PCRE].url = "/rules/payload-keywords.html#pcre-perl-compatible-regular-expressions"; + sigmatch_table[DETECT_PCRE].url = + "/rules/payload-keywords.html#pcre-perl-compatible-regular-expressions"; sigmatch_table[DETECT_PCRE].Match = NULL; sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup; - sigmatch_table[DETECT_PCRE].Free = DetectPcreFree; + sigmatch_table[DETECT_PCRE].Free = DetectPcreFree; #ifdef UNITTESTS - sigmatch_table[DETECT_PCRE].RegisterTests = DetectPcreRegisterTests; + sigmatch_table[DETECT_PCRE].RegisterTests = DetectPcreRegisterTests; #endif - sigmatch_table[DETECT_PCRE].flags = (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION); + sigmatch_table[DETECT_PCRE].flags = (SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_HANDLE_NEGATION); intmax_t val = 0; if (!ConfGetInt("pcre.match-limit", &val)) { pcre_match_limit = SC_MATCH_LIMIT_DEFAULT; SCLogDebug("Using PCRE match-limit setting of: %i", pcre_match_limit); - } - else { + } else { pcre_match_limit = val; if (pcre_match_limit != SC_MATCH_LIMIT_DEFAULT) { SCLogInfo("Using PCRE match-limit setting of: %i", pcre_match_limit); @@ -126,13 +126,14 @@ void DetectPcreRegister (void) if (!ConfGetInt("pcre.match-limit-recursion", &val)) { pcre_match_limit_recursion = SC_MATCH_LIMIT_RECURSION_DEFAULT; SCLogDebug("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion); - } - else { + } else { pcre_match_limit_recursion = val; if (pcre_match_limit_recursion != SC_MATCH_LIMIT_RECURSION_DEFAULT) { - SCLogInfo("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion); + SCLogInfo( + "Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion); } else { - SCLogDebug("Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion); + SCLogDebug( + "Using PCRE match-limit-recursion setting of: %i", pcre_match_limit_recursion); } } @@ -173,8 +174,7 @@ void DetectPcreRegister (void) * \retval 0 No match. */ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, - const SigMatchData *smd, Packet *p, Flow *f, - const uint8_t *payload, uint32_t payload_len) + const SigMatchData *smd, Packet *p, Flow *f, const uint8_t *payload, uint32_t payload_len) { SCEnter(); int ret = 0; @@ -245,8 +245,8 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, memcpy(str_ptr, pcre2_str_ptr, capture_len); pcre2_substring_free((PCRE2_UCHAR8 *)pcre2_str_ptr); - SCLogDebug("data %p/%u, type %u id %u p %p", - str_ptr, ret, pe->captypes[x], pe->capids[x], p); + SCLogDebug("data %p/%u, type %u id %u p %p", str_ptr, ret, pe->captypes[x], + pe->capids[x], p); if (pe->captypes[x] == VAR_TYPE_PKT_VAR_KV) { /* get the value, as first capture is the key */ @@ -334,11 +334,9 @@ static int DetectPcreHasUpperCase(const char *re) } else { is_meta = false; } - } - else if (re[i] == '\\') { + } else if (re[i] == '\\') { is_meta = true; - } - else if (isupper((unsigned char)re[i])) { + } else if (isupper((unsigned char)re[i])) { return 1; } } @@ -346,9 +344,8 @@ static int DetectPcreHasUpperCase(const char *re) return 0; } -static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, - const char *regexstr, int *sm_list, char *capture_names, - size_t capture_names_size, bool negate, AppProto *alproto) +static DetectPcreData *DetectPcreParse(DetectEngineCtx *de_ctx, const char *regexstr, int *sm_list, + char *capture_names, size_t capture_names_size, bool negate, AppProto *alproto) { pcre2_match_data *match = NULL; int en; @@ -387,8 +384,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, SCLogDebug("regexstr[offset] %c", regexstr[offset]); if (regexstr[offset] == ',' || regexstr[offset] == ' ') { offset--; - } - else + } else break; } @@ -396,9 +392,9 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, SCLogDebug("missing separators, assume it's part of the regex"); } else { slen = offset + 1; - strlcpy(capture_names, regexstr+cut_capture, capture_names_size); - if (capture_names[strlen(capture_names)-1] == '"') - capture_names[strlen(capture_names)-1] = '\0'; + strlcpy(capture_names, regexstr + cut_capture, capture_names_size); + if (capture_names[strlen(capture_names) - 1] == '"') + capture_names[strlen(capture_names) - 1] = '\0'; } } } @@ -433,7 +429,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, } op = op_str; } - //printf("ret %" PRId32 " re \'%s\', op \'%s\'\n", ret, re, op); + // printf("ret %" PRId32 " re \'%s\', op \'%s\'\n", ret, re, op); pd = SCCalloc(1, sizeof(DetectPcreData)); if (unlikely(pd == NULL)) @@ -486,7 +482,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, pd->flags |= DETECT_PCRE_RELATIVE; break; - /* buffer selection */ + /* buffer selection */ case 'U': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { @@ -538,7 +534,8 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, *sm_list = DetectPcreSetList(*sm_list, list); *alproto = ALPROTO_HTTP1; break; - } case 'I': { /* snort's option */ + } + case 'I': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError("regex modifier 'I' inconsistent with 'B'"); goto error; @@ -622,8 +619,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, "Since the hostname buffer we match against " "is actually lowercase, having a " "nocase is redundant."); - } - else if (DetectPcreHasUpperCase(re)) { + } else if (DetectPcreHasUpperCase(re)) { SCLogError("pcre host(\"W\") " "specified has an uppercase char. " "Since the hostname buffer we match against " @@ -648,7 +644,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, pd->parse_regex.regex = pcre2_compile((PCRE2_SPTR8)re, PCRE2_ZERO_TERMINATED, opts, &en, &eo2, NULL); } - if (pd->parse_regex.regex == NULL) { + if (pd->parse_regex.regex == NULL) { PCRE2_UCHAR errbuffer[256]; pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); SCLogError("pcre2 compile of \"%s\" failed at " @@ -703,8 +699,8 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, /** \internal * \brief check if we need to extract capture settings and set them up if needed */ -static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd, - char *capture_names) +static int DetectPcreParseCapture( + const char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd, char *capture_names) { int ret = 0, res = 0; char type_str[16] = ""; @@ -720,10 +716,10 @@ static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx, ret = pcre2_pattern_info(pd->parse_regex.regex, PCRE2_INFO_CAPTURECOUNT, &capture_cnt); SCLogDebug("ret %d capture_cnt %d", ret, capture_cnt); - if (ret == 0 && capture_cnt && strlen(capture_names) > 0) - { + if (ret == 0 && capture_cnt && strlen(capture_names) > 0) { char *ptr = NULL; - while ((name_array[name_idx] = strtok_r(name_idx == 0 ? capture_names : NULL, " ,", &ptr))){ + while ((name_array[name_idx] = + strtok_r(name_idx == 0 ? capture_names : NULL, " ,", &ptr))) { if (name_idx > (capture_cnt - 1)) { SCLogError("more pkt/flow " "var capture names than capturing substrings"); @@ -743,7 +739,7 @@ static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx, SCLogDebug("key-value/value"); key = 0; - /* kv error conditions */ + /* kv error conditions */ } else if (key == 0 && strcmp(name_array[name_idx], "pkt:value") == 0) { return -1; } else if (key == 1) { @@ -829,7 +825,7 @@ static int DetectPcreParseCapture(const char *regexstr, DetectEngineCtx *de_ctx, pd->idx++; } - //SCLogNotice("pd->capname %s", pd->capname); + // SCLogNotice("pd->capname %s", pd->capname); PCRE2_SIZE *ov = pcre2_get_ovector_pointer(match); regexstr += ov[1]; @@ -861,7 +857,7 @@ static void DetectPcreThreadFree(void *ctx) } } -static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *regexstr) +static int DetectPcreSetup(DetectEngineCtx *de_ctx, Signature *s, const char *regexstr) { SCEnter(); DetectPcreData *pd = NULL; @@ -869,9 +865,8 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *r char capture_names[1024] = ""; AppProto alproto = ALPROTO_UNKNOWN; - pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list, - capture_names, sizeof(capture_names), s->init_data->negated, - &alproto); + pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list, capture_names, sizeof(capture_names), + s->init_data->negated, &alproto); if (pd == NULL) goto error; if (DetectPcreParseCapture(regexstr, de_ctx, pd, capture_names) < 0) @@ -932,13 +927,12 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *r /* errors below shouldn't free pd */ - SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, - DETECT_CONTENT, DETECT_PCRE, -1); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, DETECT_CONTENT, DETECT_PCRE, -1); if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { SCLogError("pcre with /R (relative) needs " "preceding match in the same buffer"); goto error_nofree; - /* null is allowed when we use a sticky buffer */ + /* null is allowed when we use a sticky buffer */ } else if (prev_pm == NULL) { goto okay; } @@ -950,11 +944,11 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *r tmp->flags |= DETECT_PCRE_RELATIVE_NEXT; } - okay: +okay: SCReturnInt(0); - error: +error: DetectPcreFree(de_ctx, pd); - error_nofree: +error_nofree: SCReturnInt(-1); } @@ -984,7 +978,7 @@ static int g_dce_stub_data_buffer_id = 0; /** * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7. */ -static int DetectPcreParseTest01 (void) +static int DetectPcreParseTest01(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1004,7 +998,7 @@ static int DetectPcreParseTest01 (void) /** * \test DetectPcreParseTest02 make sure we don't allow invalid opts Ui$. */ -static int DetectPcreParseTest02 (void) +static int DetectPcreParseTest02(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1025,7 +1019,7 @@ static int DetectPcreParseTest02 (void) /** * \test DetectPcreParseTest03 make sure we don't allow invalid opts UZi. */ -static int DetectPcreParseTest03 (void) +static int DetectPcreParseTest03(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1045,7 +1039,7 @@ static int DetectPcreParseTest03 (void) /** * \test DetectPcreParseTest04 make sure we allow escaped " */ -static int DetectPcreParseTest04 (void) +static int DetectPcreParseTest04(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1067,7 +1061,7 @@ static int DetectPcreParseTest04 (void) /** * \test DetectPcreParseTest05 make sure we parse pcre with no opts */ -static int DetectPcreParseTest05 (void) +static int DetectPcreParseTest05(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1089,7 +1083,7 @@ static int DetectPcreParseTest05 (void) /** * \test DetectPcreParseTest06 make sure we parse pcre with smi opts */ -static int DetectPcreParseTest06 (void) +static int DetectPcreParseTest06(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1111,7 +1105,7 @@ static int DetectPcreParseTest06 (void) /** * \test DetectPcreParseTest07 make sure we parse pcre with /Ui opts */ -static int DetectPcreParseTest07 (void) +static int DetectPcreParseTest07(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1133,7 +1127,7 @@ static int DetectPcreParseTest07 (void) /** * \test DetectPcreParseTest08 make sure we parse pcre with O opts */ -static int DetectPcreParseTest08 (void) +static int DetectPcreParseTest08(void) { int result = 1; DetectPcreData *pd = NULL; @@ -1156,7 +1150,7 @@ static int DetectPcreParseTest08 (void) * \test DetectPcreParseTest09 make sure we parse pcre with a content * that has slashes */ -static int DetectPcreParseTest09 (void) +static int DetectPcreParseTest09(void) { DetectPcreData *pd = NULL; const char *teststring = "/lala\\\\/"; @@ -1209,14 +1203,13 @@ static int DetectPcreParseTest15(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing pcre relative http_method\"; " - "content:\"GET\"; " - "http_method; pcre:\"/abc/RM\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing pcre relative http_method\"; " + "content:\"GET\"; " + "http_method; pcre:\"/abc/RM\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1226,20 +1219,18 @@ static int DetectPcreParseTest15(void) PASS; } - /** \test Check a signature with pcre relative cookie */ static int DetectPcreParseTest16(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing pcre relative http_cookie\"; " - "content:\"test\"; " - "http_cookie; pcre:\"/abc/RC\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing pcre relative http_cookie\"; " + "content:\"test\"; " + "http_cookie; pcre:\"/abc/RC\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1254,14 +1245,13 @@ static int DetectPcreParseTest17(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing pcre relative http_raw_header\"; " - "flow:to_server; content:\"test\"; " - "http_raw_header; pcre:\"/abc/RD\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing pcre relative http_raw_header\"; " + "flow:to_server; content:\"test\"; " + "http_raw_header; pcre:\"/abc/RD\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1276,14 +1266,13 @@ static int DetectPcreParseTest18(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing pcre relative http_header\"; " - "content:\"test\"; " - "http_header; pcre:\"/abc/RH\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing pcre relative http_header\"; " + "content:\"test\"; " + "http_header; pcre:\"/abc/RH\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1298,14 +1287,13 @@ static int DetectPcreParseTest19(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing pcre relative http_client_body\"; " - "content:\"test\"; " - "http_client_body; pcre:\"/abc/RP\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing pcre relative http_client_body\"; " + "content:\"test\"; " + "http_client_body; pcre:\"/abc/RP\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1320,14 +1308,13 @@ static int DetectPcreParseTest20(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_raw_uri\"; " - "content:\"test\"; " - "http_raw_uri; pcre:\"/abc/RI\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_raw_uri\"; " + "content:\"test\"; " + "http_raw_uri; pcre:\"/abc/RI\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1342,14 +1329,13 @@ static int DetectPcreParseTest21(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing pcre relative uricontent\"; " - "uricontent:\"test\"; " - "pcre:\"/abc/RU\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing pcre relative uricontent\"; " + "uricontent:\"test\"; " + "pcre:\"/abc/RU\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1364,14 +1350,13 @@ static int DetectPcreParseTest22(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing pcre relative http_uri\"; " - "content:\"test\"; " - "http_uri; pcre:\"/abc/RU\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing pcre relative http_uri\"; " + "content:\"test\"; " + "http_uri; pcre:\"/abc/RU\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1386,14 +1371,13 @@ static int DetectPcreParseTest23(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing inconsistent pcre relative\"; " - "content:\"GET\"; " - "http_cookie; pcre:\"/abc/RM\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing inconsistent pcre relative\"; " + "content:\"GET\"; " + "http_cookie; pcre:\"/abc/RM\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1408,13 +1392,12 @@ static int DetectPcreParseTest24(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing inconsistent pcre modifiers\"; " - "pcre:\"/abc/UI\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing inconsistent pcre modifiers\"; " + "pcre:\"/abc/UI\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1429,13 +1412,12 @@ static int DetectPcreParseTest25(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing inconsistent pcre modifiers\"; " - "pcre:\"/abc/DH\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing inconsistent pcre modifiers\"; " + "pcre:\"/abc/DH\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1450,13 +1432,12 @@ static int DetectPcreParseTest26(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert http any any -> any any " - "(msg:\"Testing inconsistent pcre modifiers\"; " - "pcre:\"/abc/F\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"Testing inconsistent pcre modifiers\"; " + "pcre:\"/abc/F\"; sid:1;)"); FAIL_IF_NOT_NULL(de_ctx->sig_list); if (de_ctx != NULL) @@ -1471,12 +1452,12 @@ static int DetectPcreParseTest27(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any 80 " - "(content:\"baduricontent\"; http_raw_uri; " - "pcre:\"/^[a-z]{5}\\.html/R\"; sid:2; rev:2;)"); + "(content:\"baduricontent\"; http_raw_uri; " + "pcre:\"/^[a-z]{5}\\.html/R\"; sid:2; rev:2;)"); FAIL_IF_NOT(de_ctx->sig_list == NULL); if (de_ctx != NULL) @@ -1491,12 +1472,13 @@ static int DetectPcreParseTest28(void) { DetectEngineCtx *de_ctx = NULL; - FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); + FAIL_IF((de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any 80 " - "(content:\"|2E|suricata\"; http_host; pcre:\"/\\x2Esuricata$/W\"; " - "sid:2; rev:2;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 " + "(content:\"|2E|suricata\"; http_host; pcre:\"/\\x2Esuricata$/W\"; " + "sid:2; rev:2;)"); FAIL_IF_NULL(de_ctx->sig_list); DetectEngineCtxFree(de_ctx); @@ -1592,7 +1574,7 @@ static int DetectPcreTxBodyChunksTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1633,20 +1615,22 @@ static int DetectPcreTxBodyChunksTest01(void) htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 1); - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(t1); FAIL_IF(htud == NULL); HtpBodyChunk *cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); - FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); + FAIL_IF(StreamingBufferSegmentCompareRawData( + htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); - htud = (HtpTxUserData *) htp_tx_get_user_data(t2); + htud = (HtpTxUserData *)htp_tx_get_user_data(t2); cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); - FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); + FAIL_IF(StreamingBufferSegmentCompareRawData( + htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -1695,7 +1679,7 @@ static int DetectPcreTxBodyChunksTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1705,9 +1689,13 @@ static int DetectPcreTxBodyChunksTest02(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; " + "http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); FAIL_IF(s == NULL); - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; " + "http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); @@ -1781,19 +1769,21 @@ static int DetectPcreTxBodyChunksTest02(void) htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 1); - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(t1); HtpBodyChunk *cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); - FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); + FAIL_IF(StreamingBufferSegmentCompareRawData( + htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); - htud = (HtpTxUserData *) htp_tx_get_user_data(t2); + htud = (HtpTxUserData *)htp_tx_get_user_data(t2); cur = htud->request_body.first; FAIL_IF(htud->request_body.first == NULL); - FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); + FAIL_IF(StreamingBufferSegmentCompareRawData( + htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -1850,7 +1840,7 @@ static int DetectPcreTxBodyChunksTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1860,9 +1850,13 @@ static int DetectPcreTxBodyChunksTest03(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; " + "http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); FAIL_IF(s == NULL); - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; " + "http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); FAIL_IF(s == NULL); SigGroupBuild(de_ctx); @@ -1959,7 +1953,8 @@ static int DetectPcreParseHttpHost(void) FAIL_IF(de_ctx == NULL); - DetectPcreData *pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0, false, &alproto); + DetectPcreData *pd = + DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0, false, &alproto); FAIL_IF(pd == NULL); DetectPcreFree(de_ctx, pd); @@ -1991,14 +1986,20 @@ static int DetectPcreParseCaptureTest(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF(de_ctx == NULL); - Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(content:\"Server: \"; http_header; pcre:\"/(.*)\\r\\n/HR, flow:somecapture\"; content:\"xyz\"; http_header; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/(.*)\\r\\n/HR, flow:somecapture\"; " + "content:\"xyz\"; http_header; sid:1;)"); FAIL_IF(s == NULL); - s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(content:\"Server: \"; http_header; pcre:\"/(flow:.*)\\r\\n/HR\"; content:\"xyz\"; http_header; sid:2;)"); + s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/(flow:.*)\\r\\n/HR\"; content:\"xyz\"; " + "http_header; sid:2;)"); FAIL_IF(s == NULL); - s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(content:\"Server: \"; http_header; pcre:\"/([a-z]+)([0-9]+)\\r\\n/HR, flow:somecapture, pkt:anothercap\"; content:\"xyz\"; http_header; sid:3;)"); + s = DetectEngineAppendSig(de_ctx, + "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/([a-z]+)([0-9]+)\\r\\n/HR, " + "flow:somecapture, pkt:anothercap\"; content:\"xyz\"; http_header; sid:3;)"); FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " @@ -2056,15 +2057,13 @@ static void DetectPcreRegisterTests(void) UtRegisterTest("DetectPcreTestSig02 -- anchored pcre", DetectPcreTestSig02); UtRegisterTest("DetectPcreTestSig03 -- anchored pcre", DetectPcreTestSig03); - UtRegisterTest("DetectPcreTxBodyChunksTest01", - DetectPcreTxBodyChunksTest01); + UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01); UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", - DetectPcreTxBodyChunksTest02); + DetectPcreTxBodyChunksTest02); UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", - DetectPcreTxBodyChunksTest03); + DetectPcreTxBodyChunksTest03); UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost); UtRegisterTest("DetectPcreParseCaptureTest", DetectPcreParseCaptureTest); - } #endif /* UNITTESTS */ diff --git a/src/detect-pcre.h b/src/detect-pcre.h index 79fd1af74ae2..ea95a06fa662 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -26,16 +26,16 @@ #include "detect-parse.h" -#define DETECT_PCRE_RELATIVE 0x00001 +#define DETECT_PCRE_RELATIVE 0x00001 /* no-op other than in parsing */ -#define DETECT_PCRE_RAWBYTES 0x00002 -#define DETECT_PCRE_CASELESS 0x00004 +#define DETECT_PCRE_RAWBYTES 0x00002 +#define DETECT_PCRE_CASELESS 0x00004 -#define DETECT_PCRE_MATCH_LIMIT 0x00020 -#define DETECT_PCRE_RELATIVE_NEXT 0x00040 -#define DETECT_PCRE_NEGATE 0x00080 +#define DETECT_PCRE_MATCH_LIMIT 0x00020 +#define DETECT_PCRE_RELATIVE_NEXT 0x00040 +#define DETECT_PCRE_NEGATE 0x00080 -#define DETECT_PCRE_CAPTURE_MAX 8 +#define DETECT_PCRE_CAPTURE_MAX 8 #define SC_MATCH_LIMIT_DEFAULT 3500 #define SC_MATCH_LIMIT_RECURSION_DEFAULT 1500 @@ -54,11 +54,9 @@ typedef struct DetectPcreData_ { /* prototypes */ -int DetectPcrePayloadMatch(DetectEngineThreadCtx *, - const Signature *, const SigMatchData *, +int DetectPcrePayloadMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchData *, Packet *, Flow *, const uint8_t *, uint32_t); -void DetectPcreRegister (void); +void DetectPcreRegister(void); #endif /* __DETECT_PCRE_H__ */ - diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index 80673979ad11..2fc4fc62497f 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -37,12 +37,12 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/debug.h" +#include "util/spm-bm.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" -static int DetectPktDataSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectPktDataSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectPktDataTestRegister(void); #endif @@ -71,7 +71,7 @@ void DetectPktDataRegister(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectPktDataSetup (DetectEngineCtx *de_ctx, Signature *s, const char *unused) +static int DetectPktDataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *unused) { SCEnter(); if (s->init_data->transforms.cnt) { @@ -92,8 +92,8 @@ static int DetectPktDataTest02(void) de_ctx->flags |= DE_QUIET; Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(file_data; compress_whitespace; " - " pkt_data; content:\"in pkt data\"; sid:1;)"); + "(file_data; compress_whitespace; " + " pkt_data; content:\"in pkt data\"; sid:1;)"); FAIL_IF_NOT_NULL(sig); DetectEngineCtxFree(de_ctx); PASS; diff --git a/src/detect-pkt-data.h b/src/detect-pkt-data.h index fbaf8b98e6a3..1d0681e34524 100644 --- a/src/detect-pkt-data.h +++ b/src/detect-pkt-data.h @@ -25,6 +25,6 @@ #define __DETECT_PKTDATA_H__ /* prototypes */ -void DetectPktDataRegister (void); +void DetectPktDataRegister(void); #endif /* __DETECT_PKTDATA_H__ */ diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index 7166188eb256..8b255dbb03b4 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -33,24 +33,24 @@ #include "pkt-var.h" #include "detect-pktvar.h" #include "detect-content.h" -#include "util-spm.h" -#include "util-debug.h" -#include "util-var-name.h" +#include "util/spm.h" +#include "util/debug.h" +#include "util/var-name.h" -#define PARSE_REGEX "(.*),(.*)" +#define PARSE_REGEX "(.*),(.*)" static DetectParseRegex parse_regex; -static int DetectPktvarMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectPktvarSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectPktvarMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectPktvarSetup(DetectEngineCtx *, Signature *, const char *); static void DetectPktvarFree(DetectEngineCtx *, void *data); -void DetectPktvarRegister (void) +void DetectPktvarRegister(void) { sigmatch_table[DETECT_PKTVAR].name = "pktvar"; sigmatch_table[DETECT_PKTVAR].Match = DetectPktvarMatch; sigmatch_table[DETECT_PKTVAR].Setup = DetectPktvarSetup; - sigmatch_table[DETECT_PKTVAR].Free = DetectPktvarFree; + sigmatch_table[DETECT_PKTVAR].Free = DetectPktvarFree; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } @@ -61,8 +61,8 @@ void DetectPktvarRegister (void) * -1: error */ -static int DetectPktvarMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectPktvarMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { int ret = 0; const DetectPktvarData *pd = (const DetectPktvarData *)ctx; @@ -87,7 +87,7 @@ static void DetectPktvarFree(DetectEngineCtx *de_ctx, void *ptr) } } -static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectPktvarSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { char *varname = NULL, *varcontent = NULL; int res = 0; @@ -122,8 +122,7 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, const char char *parse_content; if (strlen(varcontent) >= 2 && varcontent[0] == '"' && - varcontent[strlen(varcontent) - 1] == '"') - { + varcontent[strlen(varcontent) - 1] == '"') { parse_content = varcontent + 1; varcontent[strlen(varcontent) - 1] = '\0'; } else { diff --git a/src/detect-pktvar.h b/src/detect-pktvar.h index ecd0243904a7..94de8a0466b4 100644 --- a/src/detect-pktvar.h +++ b/src/detect-pktvar.h @@ -32,7 +32,6 @@ typedef struct DetectPktvarData_ { } DetectPktvarData; /* prototypes */ -void DetectPktvarRegister (void); +void DetectPktvarRegister(void); #endif /* __DETECT_PKTVAR_H__ */ - diff --git a/src/detect-prefilter.c b/src/detect-prefilter.c index f38b56bf8b9c..580d54079bdb 100644 --- a/src/detect-prefilter.c +++ b/src/detect-prefilter.c @@ -30,9 +30,9 @@ #include "detect-parse.h" #include "detect-content.h" #include "detect-prefilter.h" -#include "util-debug.h" +#include "util/debug.h" -static int DetectPrefilterSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectPrefilterSetup(DetectEngineCtx *, Signature *, const char *); void DetectPrefilterRegister(void) { @@ -52,7 +52,7 @@ void DetectPrefilterRegister(void) * \retval 0 ok * \retval -1 failure */ -static int DetectPrefilterSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectPrefilterSetup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); @@ -77,11 +77,9 @@ static int DetectPrefilterSetup (DetectEngineCtx *de_ctx, Signature *s, const ch if (sm->type == DETECT_CONTENT) { DetectContentData *cd = (DetectContentData *)sm->ctx; if ((cd->flags & DETECT_CONTENT_NEGATED) && - ((cd->flags & DETECT_CONTENT_DISTANCE) || - (cd->flags & DETECT_CONTENT_WITHIN) || - (cd->flags & DETECT_CONTENT_OFFSET) || - (cd->flags & DETECT_CONTENT_DEPTH))) - { + ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || + (cd->flags & DETECT_CONTENT_OFFSET) || + (cd->flags & DETECT_CONTENT_DEPTH))) { SCLogError("prefilter; cannot be " "used with negated content, along with relative modifiers"); SCReturnInt(-1); diff --git a/src/detect-prefilter.h b/src/detect-prefilter.h index afc64db43f8f..3884faaa3045 100644 --- a/src/detect-prefilter.h +++ b/src/detect-prefilter.h @@ -25,6 +25,6 @@ #define __DETECT_PREFILTER_H__ /* prototypes */ -void DetectPrefilterRegister (void); +void DetectPrefilterRegister(void); #endif /* __DETECT_PREFILTER_H__ */ diff --git a/src/detect-priority.c b/src/detect-priority.c index 81ee72966fb5..3a1069b8f65b 100644 --- a/src/detect-priority.c +++ b/src/detect-priority.c @@ -30,15 +30,15 @@ #include "detect-priority.h" #include "detect-engine.h" #include "detect-engine-mpm.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/unittest.h" #define PARSE_REGEX "^\\s*(\\d+|\"\\d+\")\\s*$" static DetectParseRegex parse_regex; -static int DetectPrioritySetup (DetectEngineCtx *, Signature *, const char *); +static int DetectPrioritySetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void PriorityRegisterTests(void); #endif @@ -46,7 +46,7 @@ static void PriorityRegisterTests(void); /** * \brief Registers the handler functions for the "priority" keyword */ -void DetectPriorityRegister (void) +void DetectPriorityRegister(void) { sigmatch_table[DETECT_PRIORITY].name = "priority"; sigmatch_table[DETECT_PRIORITY].desc = "rules with a higher priority will be examined first"; @@ -58,7 +58,7 @@ void DetectPriorityRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectPrioritySetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { char copy_str[128] = ""; size_t pcre2len; @@ -112,7 +112,7 @@ static int DetectPriorityTest01(void) FAIL_IF_NULL(de_ctx); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:2; sid:1;)"); + "(msg:\"Priority test\"; priority:2; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); FAIL_IF_NOT(de_ctx->sig_list->prio == 2); @@ -127,43 +127,43 @@ static int DetectPriorityTest02(void) FAIL_IF_NULL(de_ctx); Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:1; sid:1;)"); + "(msg:\"Priority test\"; priority:1; sid:1;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 1); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:boo; sid:2;)"); + "(msg:\"Priority test\"; priority:boo; sid:2;)"); FAIL_IF_NOT_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:10boo; sid:3;)"); + "(msg:\"Priority test\"; priority:10boo; sid:3;)"); FAIL_IF_NOT_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:b10oo; sid:4;)"); + "(msg:\"Priority test\"; priority:b10oo; sid:4;)"); FAIL_IF_NOT_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:boo10; sid:5;)"); + "(msg:\"Priority test\"; priority:boo10; sid:5;)"); FAIL_IF_NOT_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:-1; sid:6;)"); + "(msg:\"Priority test\"; priority:-1; sid:6;)"); FAIL_IF_NOT_NULL(sig); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; sid:7;)"); + "(msg:\"Priority test\"; sid:7;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 3); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:5; priority:4; sid:8;)"); + "(msg:\"Priority test\"; priority:5; priority:4; sid:8;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 4); sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " - "(msg:\"Priority test\"; priority:5; priority:4; " - "priority:1; sid:9;)"); + "(msg:\"Priority test\"; priority:5; priority:4; " + "priority:1; sid:9;)"); FAIL_IF_NULL(sig); FAIL_IF_NOT(sig->prio == 1); diff --git a/src/detect-priority.h b/src/detect-priority.h index 0ec877e521b8..09f020015adc 100644 --- a/src/detect-priority.h +++ b/src/detect-priority.h @@ -28,7 +28,6 @@ #define __DETECT_PRIORITY_H__ /* prototypes */ -void DetectPriorityRegister (void); +void DetectPriorityRegister(void); #endif /* __DETECT_PRIORITY_H__ */ - diff --git a/src/detect-quic-cyu-hash.c b/src/detect-quic-cyu-hash.c deleted file mode 100644 index 88197a5e382a..000000000000 --- a/src/detect-quic-cyu-hash.c +++ /dev/null @@ -1,432 +0,0 @@ -/* Copyright (C) 2021-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * Implements the quic.cyu.hash sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-content.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-quic-cyu-hash.h" -#include "detect-engine-build.h" -#include "rust.h" -#include "util-profiling.h" - -#ifdef UNITTESTS -static void DetectQuicCyuHashRegisterTests(void); -#endif - -#define KEYWORD_NAME "quic.cyu.hash" -#define KEYWORD_DOC "quic-cyu.html#quic-cyu-hash" -#define BUFFER_NAME "quic.cyu.hash" -#define BUFFER_DESC "QUIC CYU Hash" -static int g_buffer_id = 0; - -struct QuicHashGetDataArgs { - uint32_t local_id; /**< used as index into thread inspect array */ - void *txv; -}; - -static int DetectQuicCyuHashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *QuicHashGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, struct QuicHashGetDataArgs *cbdata, - int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_quic_tx_get_cyu_hash(cbdata->txv, (uint16_t)cbdata->local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectQuicHash(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - struct QuicHashGetDataArgs cbdata = { - local_id, - txv, - }; - InspectionBuffer *buffer = - QuicHashGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -typedef struct PrefilterMpmQuicHash { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmQuicHash; - -/** \brief QuicHash Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxQuicHash(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmQuicHash *ctx = (const PrefilterMpmQuicHash *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - while (1) { - // loop until we get a NULL - - struct QuicHashGetDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = QuicHashGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static void PrefilterMpmQuicHashFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmQuicHashRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, - const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmQuicHash *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxQuicHash, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmQuicHashFree, mpm_reg->pname); -} - -static bool DetectQuicHashValidateCallback(const Signature *s, const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - const DetectContentData *cd = (DetectContentData *)sm->ctx; - - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = BUFFER_NAME " should not be used together with " - "nocase, since the rule is automatically " - "lowercased anyway which makes nocase redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - } - - if (cd->content_len != 32) { - *sigerror = "Invalid length of the specified" BUFFER_NAME " (should " - "be 32 characters long). This rule will therefore " - "never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - for (size_t i = 0; i < cd->content_len; ++i) { - if (!isxdigit(cd->content[i])) { - *sigerror = "Invalid " BUFFER_NAME - " string (should be string of hexadecimal characters)." - "This rule will therefore never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - } - } - } - return true; -} - -void DetectQuicCyuHashRegister(void) -{ - /* quic.cyu.hash sticky buffer */ - sigmatch_table[DETECT_AL_QUIC_CYU_HASH].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_QUIC_CYU_HASH].desc = "sticky buffer to match on the QUIC CYU hash"; - sigmatch_table[DETECT_AL_QUIC_CYU_HASH].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_QUIC_CYU_HASH].Setup = DetectQuicCyuHashSetup; - sigmatch_table[DETECT_AL_QUIC_CYU_HASH].flags |= SIGMATCH_NOOPT; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_QUIC_CYU_HASH].RegisterTests = DetectQuicCyuHashRegisterTests; -#endif - - DetectAppLayerMpmRegister2( - BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterMpmQuicHashRegister, NULL, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2( - BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 0, DetectEngineInspectQuicHash, NULL); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectQuicHashValidateCallback); - - DetectBufferTypeSupportsMultiInstance(BUFFER_NAME); -} - -#ifdef UNITTESTS -#include "app-layer-parser.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "flow-util.h" -#include "detect-engine-alert.h" - -/** - * \test DetectQuicCyuHashTest01 is a test for a valid quic packet, matching - * on the cyu hash - * - * \retval 1 on success - * \retval 0 on failure - */ -static int DetectQuicCyuHashTest01(void) -{ - /* quic packet */ - uint8_t buf[] = { 0xc3, 0x51, 0x30, 0x34, 0x36, 0x50, 0x76, 0xd8, 0x63, 0xb7, 0x54, 0xf7, 0xab, - 0x32, 0x00, 0x00, 0x00, 0x01, 0x54, 0xfd, 0xf4, 0x79, 0x48, 0x76, 0xd0, 0x87, 0x58, 0x8d, - 0x26, 0x8f, 0xa0, 0x01, 0x04, 0x00, 0x43, 0x48, 0x4c, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x50, - 0x41, 0x44, 0x00, 0xe4, 0x02, 0x00, 0x00, 0x53, 0x4e, 0x49, 0x00, 0xf7, 0x02, 0x00, 0x00, - 0x56, 0x45, 0x52, 0x00, 0xfb, 0x02, 0x00, 0x00, 0x43, 0x43, 0x53, 0x00, 0x0b, 0x03, 0x00, - 0x00, 0x55, 0x41, 0x49, 0x44, 0x2c, 0x03, 0x00, 0x00, 0x54, 0x43, 0x49, 0x44, 0x30, 0x03, - 0x00, 0x00, 0x50, 0x44, 0x4d, 0x44, 0x34, 0x03, 0x00, 0x00, 0x53, 0x4d, 0x48, 0x4c, 0x38, - 0x03, 0x00, 0x00, 0x49, 0x43, 0x53, 0x4c, 0x3c, 0x03, 0x00, 0x00, 0x4e, 0x4f, 0x4e, 0x50, - 0x5c, 0x03, 0x00, 0x00, 0x4d, 0x49, 0x44, 0x53, 0x60, 0x03, 0x00, 0x00, 0x53, 0x43, 0x4c, - 0x53, 0x64, 0x03, 0x00, 0x00, 0x43, 0x53, 0x43, 0x54, 0x64, 0x03, 0x00, 0x00, 0x43, 0x4f, - 0x50, 0x54, 0x64, 0x03, 0x00, 0x00, 0x49, 0x52, 0x54, 0x54, 0x68, 0x03, 0x00, 0x00, 0x43, - 0x46, 0x43, 0x57, 0x6c, 0x03, 0x00, 0x00, 0x53, 0x46, 0x43, 0x57, 0x70, 0x03, 0x00, 0x00, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x51, 0x30, 0x34, 0x36, 0x01, 0xe8, - 0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8, 0x7e, 0xed, 0x80, 0x86, 0xa2, 0x15, 0x82, 0x91, 0x43, - 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x37, 0x39, 0x2e, 0x30, 0x2e, 0x33, 0x39, 0x34, 0x35, - 0x2e, 0x31, 0x31, 0x37, 0x20, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x78, 0x38, 0x36, 0x5f, - 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x58, 0x35, 0x30, 0x39, 0x01, 0x00, 0x00, 0x00, 0x1e, - 0x00, 0x00, 0x00, 0x82, 0x88, 0x09, 0x00, 0xfa, 0x0f, 0xde, 0xb7, 0x2e, 0x7e, 0x6c, 0x78, - 0xcc, 0x09, 0x65, 0xab, 0x06, 0x0c, 0x31, 0x05, 0xfa, 0xd9, 0xa2, 0x0b, 0xdd, 0x74, 0x5c, - 0x28, 0xdf, 0x7b, 0x74, 0x23, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x43, - 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; - - Flow f; - void *quic_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 443); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW; - p->flowflags |= FLOW_PKT_TOSERVER; - f.alproto = ALPROTO_QUIC; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, - "alert quic any any -> any any " - "(msg:\"Test QUIC CYU hash\"; " - "quic.cyu.hash; content:\"910a5e3a4d51593bd59a44611544f209\"; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse( - NULL, alp_tctx, &f, ALPROTO_QUIC, STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - quic_state = f.alstate; - FAIL_IF_NULL(quic_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - -static void DetectQuicCyuHashRegisterTests(void) -{ - UtRegisterTest("DetectQuicCyuHashTest01", DetectQuicCyuHashTest01); -} - -#endif /* UNITTESTS */ diff --git a/src/detect-quic-cyu-string.c b/src/detect-quic-cyu-string.c deleted file mode 100644 index 9290fa41233c..000000000000 --- a/src/detect-quic-cyu-string.c +++ /dev/null @@ -1,389 +0,0 @@ -/* Copyright (C) 2021-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * Implements the quic.cyu.string sticky buffer - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-quic-cyu-string.h" -#include "detect-engine-build.h" -#include "rust.h" -#include "util-profiling.h" - -#ifdef UNITTESTS -static void DetectQuicCyuStringRegisterTests(void); -#endif - -#define KEYWORD_NAME "quic.cyu.string" -#define KEYWORD_DOC "quic-cyu.html#quic-cyu-string" -#define BUFFER_NAME "quic.cyu.string" -#define BUFFER_DESC "QUIC CYU String" -static int g_buffer_id = 0; - -struct QuicStringGetDataArgs { - uint32_t local_id; /**< used as index into thread inspect array */ - void *txv; -}; - -static int DetectQuicCyuStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *QuicStringGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, struct QuicStringGetDataArgs *cbdata, - int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (rs_quic_tx_get_cyu_string(cbdata->txv, cbdata->local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectQuicString(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - uint32_t local_id = 0; - - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - while (1) { - struct QuicStringGetDataArgs cbdata = { - local_id, - txv, - }; - InspectionBuffer *buffer = - QuicStringGetData(det_ctx, transforms, f, &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - local_id++; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -/** \brief QuicString Mpm prefilter callback - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * \param f flow to inspect - * \param txv tx to inspect - * \param pectx inspection context - */ -static void PrefilterTxQuicString(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - uint32_t local_id = 0; - while (1) { - // loop until we get a NULL - - struct QuicStringGetDataArgs cbdata = { local_id, txv }; - InspectionBuffer *buffer = QuicStringGetData(det_ctx, ctx->transforms, f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - local_id++; - } -} - -static void PrefilterMpmListIdFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmListIdRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, - const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxQuicString, mpm_reg->app_v2.alproto, - mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmListIdFree, mpm_reg->pname); -} - -void DetectQuicCyuStringRegister(void) -{ - /* quic.cyu.string sticky buffer */ - sigmatch_table[DETECT_AL_QUIC_CYU_STRING].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_QUIC_CYU_STRING].desc = - "sticky buffer to match on the QUIC CYU string"; - sigmatch_table[DETECT_AL_QUIC_CYU_STRING].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_QUIC_CYU_STRING].Setup = DetectQuicCyuStringSetup; - sigmatch_table[DETECT_AL_QUIC_CYU_STRING].flags |= SIGMATCH_NOOPT; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_QUIC_CYU_STRING].RegisterTests = DetectQuicCyuStringRegisterTests; -#endif - - DetectAppLayerMpmRegister2( - BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterMpmListIdRegister, NULL, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2( - BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 0, DetectEngineInspectQuicString, NULL); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - DetectBufferTypeSupportsMultiInstance(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} - -#ifdef UNITTESTS -#include "app-layer-parser.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "flow-util.h" -#include "detect-engine-alert.h" - -/** - * \test DetectQuicCyuStringTest01 is a test for a valid quic packet, matching - * on the cyu string - * - * \retval 1 on success - * \retval 0 on failure - */ -static int DetectQuicCyuStringTest01(void) -{ - /* quic packet */ - uint8_t buf[] = { 0xc3, 0x51, 0x30, 0x34, 0x36, 0x50, 0x76, 0xd8, 0x63, 0xb7, 0x54, 0xf7, 0xab, - 0x32, 0x00, 0x00, 0x00, 0x01, 0x54, 0xfd, 0xf4, 0x79, 0x48, 0x76, 0xd0, 0x87, 0x58, 0x8d, - 0x26, 0x8f, 0xa0, 0x01, 0x04, 0x00, 0x43, 0x48, 0x4c, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x50, - 0x41, 0x44, 0x00, 0xe4, 0x02, 0x00, 0x00, 0x53, 0x4e, 0x49, 0x00, 0xf7, 0x02, 0x00, 0x00, - 0x56, 0x45, 0x52, 0x00, 0xfb, 0x02, 0x00, 0x00, 0x43, 0x43, 0x53, 0x00, 0x0b, 0x03, 0x00, - 0x00, 0x55, 0x41, 0x49, 0x44, 0x2c, 0x03, 0x00, 0x00, 0x54, 0x43, 0x49, 0x44, 0x30, 0x03, - 0x00, 0x00, 0x50, 0x44, 0x4d, 0x44, 0x34, 0x03, 0x00, 0x00, 0x53, 0x4d, 0x48, 0x4c, 0x38, - 0x03, 0x00, 0x00, 0x49, 0x43, 0x53, 0x4c, 0x3c, 0x03, 0x00, 0x00, 0x4e, 0x4f, 0x4e, 0x50, - 0x5c, 0x03, 0x00, 0x00, 0x4d, 0x49, 0x44, 0x53, 0x60, 0x03, 0x00, 0x00, 0x53, 0x43, 0x4c, - 0x53, 0x64, 0x03, 0x00, 0x00, 0x43, 0x53, 0x43, 0x54, 0x64, 0x03, 0x00, 0x00, 0x43, 0x4f, - 0x50, 0x54, 0x64, 0x03, 0x00, 0x00, 0x49, 0x52, 0x54, 0x54, 0x68, 0x03, 0x00, 0x00, 0x43, - 0x46, 0x43, 0x57, 0x6c, 0x03, 0x00, 0x00, 0x53, 0x46, 0x43, 0x57, 0x70, 0x03, 0x00, 0x00, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x51, 0x30, 0x34, 0x36, 0x01, 0xe8, - 0x81, 0x60, 0x92, 0x92, 0x1a, 0xe8, 0x7e, 0xed, 0x80, 0x86, 0xa2, 0x15, 0x82, 0x91, 0x43, - 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x37, 0x39, 0x2e, 0x30, 0x2e, 0x33, 0x39, 0x34, 0x35, - 0x2e, 0x31, 0x31, 0x37, 0x20, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x78, 0x38, 0x36, 0x5f, - 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x58, 0x35, 0x30, 0x39, 0x01, 0x00, 0x00, 0x00, 0x1e, - 0x00, 0x00, 0x00, 0x82, 0x88, 0x09, 0x00, 0xfa, 0x0f, 0xde, 0xb7, 0x2e, 0x7e, 0x6c, 0x78, - 0xcc, 0x09, 0x65, 0xab, 0x06, 0x0c, 0x31, 0x05, 0xfa, 0xd9, 0xa2, 0x0b, 0xdd, 0x74, 0x5c, - 0x28, 0xdf, 0x7b, 0x74, 0x23, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x43, - 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; - - Flow f; - void *quic_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 443); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW; - p->flowflags |= FLOW_PKT_TOSERVER; - f.alproto = ALPROTO_QUIC; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert quic any any -> any any " - "(msg:\"Test QUIC CYU string\"; " - "quic.cyu.string; " - "content:\"46,PAD-SNI-VER-CCS-UAID-TCID-PDMD-SMHL-ICSL-NONP-" - "MIDS-SCLS-CSCT-COPT-IRTT-CFCW-SFCW\"; " - "sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse( - NULL, alp_tctx, &f, ALPROTO_QUIC, STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - quic_state = f.alstate; - FAIL_IF_NULL(quic_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - -/** - * \brief this function registers unit tests for Quic Cyu String - */ -static void DetectQuicCyuStringRegisterTests(void) -{ - UtRegisterTest("DetectQuicCyuStringTest01", DetectQuicCyuStringTest01); -} - -#endif /* UNITTESTS */ diff --git a/src/detect-quic-sni.c b/src/detect-quic-sni.c deleted file mode 100644 index 722f50d04697..000000000000 --- a/src/detect-quic-sni.c +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * Implements the quic.sni - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-mpm.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-uint.h" -#include "detect-quic-sni.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "rust.h" - -#ifdef UNITTESTS -static void DetectQuicSniRegisterTests(void); -#endif - -#define BUFFER_NAME "quic_sni" -#define KEYWORD_NAME "quic.sni" -#define KEYWORD_ID DETECT_AL_QUIC_SNI - -static int quic_sni_id = 0; - -static int DetectQuicSniSetup(DetectEngineCtx *, Signature *, const char *); - -static InspectionBuffer *GetSniData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_quic_tx_get_sni(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -/** - * \brief Registration function for quic.sni: keyword - */ -void DetectQuicSniRegister(void) -{ - sigmatch_table[DETECT_AL_QUIC_SNI].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_QUIC_SNI].desc = "match Quic sni"; - sigmatch_table[DETECT_AL_QUIC_SNI].url = "/rules/quic-keywords.html#quic-sni"; - sigmatch_table[DETECT_AL_QUIC_SNI].Setup = DetectQuicSniSetup; - sigmatch_table[DETECT_AL_QUIC_SNI].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_QUIC_SNI].RegisterTests = DetectQuicSniRegisterTests; -#endif - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetSniData, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetSniData); - - quic_sni_id = DetectBufferTypeGetByName(BUFFER_NAME); -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectQuicSniSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectBufferSetActiveList(de_ctx, s, quic_sni_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) - return -1; - - return 0; -} - -#ifdef UNITTESTS - -/** - * \test QuicSniTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int QuicSniTestParse01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig( - de_ctx, "alert ip any any -> any any (quic.sni; content:\"googe.com\"; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig( - de_ctx, "alert ip any any -> any any (quic.sni; content:\"|00|\"; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test QuicSniTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int QuicSniTestParse03(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = - DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (quic.sni:; sid:1; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \brief this function registers unit tests for QuicSni - */ -void DetectQuicSniRegisterTests(void) -{ - UtRegisterTest("QuicSniTestParse01", QuicSniTestParse01); - UtRegisterTest("QuicSniTestParse03", QuicSniTestParse03); -} - -#endif /* UNITTESTS */ diff --git a/src/detect-quic-ua.c b/src/detect-quic-ua.c deleted file mode 100644 index c491d05b06a2..000000000000 --- a/src/detect-quic-ua.c +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * Implements the quic.ua - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-mpm.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-uint.h" -#include "detect-quic-ua.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "rust.h" - -#ifdef UNITTESTS -static void DetectQuicUaRegisterTests(void); -#endif - -#define BUFFER_NAME "quic_ua" -#define KEYWORD_NAME "quic.ua" -#define KEYWORD_ID DETECT_AL_QUIC_UA - -static int quic_ua_id = 0; - -static int DetectQuicUaSetup(DetectEngineCtx *, Signature *, const char *); - -static InspectionBuffer *GetUaData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_quic_tx_get_ua(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -/** - * \brief Registration function for quic.ua: keyword - */ -void DetectQuicUaRegister(void) -{ - sigmatch_table[DETECT_AL_QUIC_UA].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_QUIC_UA].desc = "match Quic ua"; - sigmatch_table[DETECT_AL_QUIC_UA].url = "/rules/quic-keywords.html#quic-ua"; - sigmatch_table[DETECT_AL_QUIC_UA].Setup = DetectQuicUaSetup; - sigmatch_table[DETECT_AL_QUIC_UA].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_QUIC_UA].RegisterTests = DetectQuicUaRegisterTests; -#endif - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetUaData, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetUaData); - - quic_ua_id = DetectBufferTypeGetByName(BUFFER_NAME); -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectQuicUaSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectBufferSetActiveList(de_ctx, s, quic_ua_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) - return -1; - - return 0; -} - -#ifdef UNITTESTS - -/** - * \test QuicUaTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int QuicUaTestParse01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig( - de_ctx, "alert ip any any -> any any (quic.ua; content:\"googe.com\"; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig( - de_ctx, "alert ip any any -> any any (quic.ua; content:\"|00|\"; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test QuicUaTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int QuicUaTestParse03(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = - DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (quic.ua:; sid:1; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \brief this function registers unit tests for QuicUa - */ -void DetectQuicUaRegisterTests(void) -{ - UtRegisterTest("QuicUaTestParse01", QuicUaTestParse01); - UtRegisterTest("QuicUaTestParse03", QuicUaTestParse03); -} - -#endif /* UNITTESTS */ diff --git a/src/detect-quic-version.c b/src/detect-quic-version.c deleted file mode 100644 index fcd99545aad5..000000000000 --- a/src/detect-quic-version.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * Implements the quic.version - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-mpm.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-uint.h" -#include "detect-quic-version.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "rust.h" - -#ifdef UNITTESTS -static void DetectQuicVersionRegisterTests(void); -#endif - -#define BUFFER_NAME "quic_version" -#define KEYWORD_NAME "quic.version" -#define KEYWORD_ID DETECT_AL_QUIC_VERSION - -static int quic_version_id = 0; - -static int DetectQuicVersionSetup(DetectEngineCtx *, Signature *, const char *); - -static InspectionBuffer *GetVersionData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_quic_tx_get_version(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -/** - * \brief Registration function for quic.version: keyword - */ -void DetectQuicVersionRegister(void) -{ - sigmatch_table[DETECT_AL_QUIC_VERSION].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_QUIC_VERSION].desc = "match Quic version"; - sigmatch_table[DETECT_AL_QUIC_VERSION].url = "/rules/quic-keywords.html#quic-version"; - sigmatch_table[DETECT_AL_QUIC_VERSION].Setup = DetectQuicVersionSetup; - sigmatch_table[DETECT_AL_QUIC_VERSION].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_QUIC_VERSION].RegisterTests = DetectQuicVersionRegisterTests; -#endif - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetVersionData, ALPROTO_QUIC, 1); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetVersionData, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetVersionData); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetVersionData); - - quic_version_id = DetectBufferTypeGetByName(BUFFER_NAME); -} - -/** - * \internal - * \brief this function is used to add the parsed sigmatch into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectQuicVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectBufferSetActiveList(de_ctx, s, quic_version_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0) - return -1; - - return 0; -} - -#ifdef UNITTESTS - -/** - * \test QuicVersionTestParse01 is a test for a valid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int QuicVersionTestParse01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig( - de_ctx, "alert ip any any -> any any (quic.version; content:\"Q046\"; sid:1; rev:1;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig( - de_ctx, "alert ip any any -> any any (quic.version; content:\"|00|\"; sid:2; rev:1;)"); - FAIL_IF_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test QuicVersionTestParse03 is a test for an invalid value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int QuicVersionTestParse03(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - Signature *sig = DetectEngineAppendSig( - de_ctx, "alert ip any any -> any any (quic.version:; sid:1; rev:1;)"); - FAIL_IF_NOT_NULL(sig); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \brief this function registers unit tests for QuicVersion - */ -void DetectQuicVersionRegisterTests(void) -{ - UtRegisterTest("QuicVersionTestParse01", QuicVersionTestParse01); - UtRegisterTest("QuicVersionTestParse03", QuicVersionTestParse03); -} - -#endif /* UNITTESTS */ diff --git a/src/detect-rawbytes.c b/src/detect-rawbytes.c index 1047e1340ba4..4b098dd1ac42 100644 --- a/src/detect-rawbytes.c +++ b/src/detect-rawbytes.c @@ -36,7 +36,7 @@ #include "detect-content.h" #include "detect-pcre.h" -#include "util-debug.h" +#include "util/debug.h" static int DetectRawbytesSetup(DetectEngineCtx *, Signature *, const char *); diff --git a/src/detect-rawbytes.h b/src/detect-rawbytes.h index 8716e56a31f0..8b79a02bcfe0 100644 --- a/src/detect-rawbytes.h +++ b/src/detect-rawbytes.h @@ -25,7 +25,6 @@ #define __DETECT_RAWBYTES_H__ /* prototypes */ -void DetectRawbytesRegister (void); +void DetectRawbytesRegister(void); #endif /* __DETECT_RAWBYTES_H__ */ - diff --git a/src/detect-reference.c b/src/detect-reference.c index aaa723db4963..f31a8b0fae4c 100644 --- a/src/detect-reference.c +++ b/src/detect-reference.c @@ -36,12 +36,12 @@ #include "decode-events.h" #include "stream-tcp.h" -#include "util-reference-config.h" +#include "util/reference-config.h" #include "detect-reference.h" -#include "util-unittest.h" -#include "util-byte.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/byte.h" +#include "util/debug.h" #define PARSE_REGEX "^\\s*([A-Za-z0-9]+)\\s*,\"?\\s*\"?\\s*([a-zA-Z0-9\\-_\\.\\/\\?\\=]+)\"?\\s*\"?" @@ -58,7 +58,8 @@ static int DetectReferenceSetup(DetectEngineCtx *, Signature *s, const char *str void DetectReferenceRegister(void) { sigmatch_table[DETECT_REFERENCE].name = "reference"; - sigmatch_table[DETECT_REFERENCE].desc = "direct to places where information about the rule can be found"; + sigmatch_table[DETECT_REFERENCE].desc = + "direct to places where information about the rule can be found"; sigmatch_table[DETECT_REFERENCE].url = "/rules/meta.html#reference"; sigmatch_table[DETECT_REFERENCE].Setup = DetectReferenceSetup; #ifdef UNITTESTS @@ -187,8 +188,7 @@ static DetectReference *DetectReferenceParse(const char *rawstr, DetectEngineCtx * \retval 0 On Success. * \retval -1 On Failure. */ -static int DetectReferenceSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) +static int DetectReferenceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { SCEnter(); @@ -200,7 +200,7 @@ static int DetectReferenceSetup(DetectEngineCtx *de_ctx, Signature *s, SCLogDebug("ref %s %s", ref->key, ref->reference); - if (s->references == NULL) { + if (s->references == NULL) { s->references = ref; } else { sig_refs = s->references; @@ -234,14 +234,15 @@ static int DetectReferenceParseTest01(void) FAIL_IF_NULL(fd); SCRConfLoadReferenceConfigFile(de_ctx, fd); - Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " + Signature *s = DetectEngineAppendSig(de_ctx, + "alert icmp any any -> any any " "(msg:\"One reference\"; reference:one,001-2010; sid:2;)"); FAIL_IF_NULL(s); FAIL_IF_NULL(s->references); DetectReference *ref = s->references; - FAIL_IF (strcmp(ref->key, "http://www.one.com") != 0); - FAIL_IF (strcmp(ref->reference, "001-2010") != 0); + FAIL_IF(strcmp(ref->key, "http://www.one.com") != 0); + FAIL_IF(strcmp(ref->reference, "001-2010") != 0); DetectEngineCtxFree(de_ctx); PASS; @@ -264,20 +265,20 @@ static int DetectReferenceParseTest02(void) SCRConfLoadReferenceConfigFile(de_ctx, fd); Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " - "(msg:\"Two references\"; " - "reference:one,openinfosecdoundation.txt; " - "reference:two,001-2010; sid:2;)"); + "(msg:\"Two references\"; " + "reference:one,openinfosecdoundation.txt; " + "reference:two,001-2010; sid:2;)"); FAIL_IF_NULL(s); FAIL_IF_NULL(s->references); FAIL_IF_NULL(s->references->next); DetectReference *ref = s->references; - FAIL_IF (strcmp(ref->key, "http://www.one.com") != 0); - FAIL_IF (strcmp(ref->reference, "openinfosecdoundation.txt") != 0); + FAIL_IF(strcmp(ref->key, "http://www.one.com") != 0); + FAIL_IF(strcmp(ref->reference, "openinfosecdoundation.txt") != 0); ref = s->references->next; - FAIL_IF (strcmp(ref->key, "http://www.two.com") != 0); - FAIL_IF (strcmp(ref->reference, "001-2010") != 0); + FAIL_IF(strcmp(ref->key, "http://www.two.com") != 0); + FAIL_IF(strcmp(ref->reference, "001-2010") != 0); DetectEngineCtxFree(de_ctx); PASS; @@ -300,8 +301,8 @@ static int DetectReferenceParseTest03(void) SCRConfLoadReferenceConfigFile(de_ctx, fd); Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> any any " - "(msg:\"invalid ref\"; " - "reference:unknownkey,001-2010; sid:2;)"); + "(msg:\"invalid ref\"; " + "reference:unknownkey,001-2010; sid:2;)"); FAIL_IF_NULL(s); DetectEngineCtxFree(de_ctx); PASS; diff --git a/src/detect-reference.h b/src/detect-reference.h index ddf9233987cb..d8ecc604dab9 100644 --- a/src/detect-reference.h +++ b/src/detect-reference.h @@ -24,7 +24,6 @@ #ifndef __DETECT_REFERENCE_H__ #define __DETECT_REFERENCE_H__ - /** * \brief Signature reference list. */ diff --git a/src/detect-replace.c b/src/detect-replace.c index a5d0387457e5..9bef935f910c 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -47,41 +47,42 @@ extern int run_mode; #include "detect-engine-state.h" #include "detect-engine-build.h" -#include "util-checksum.h" +#include "util/checksum.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "flow-var.h" -#include "util-debug.h" +#include "util/debug.h" #include "pkt-var.h" #include "host.h" -#include "util-profiling.h" +#include "util/profiling.h" static int DetectReplaceSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectReplaceRegisterTests(void); #endif -static int DetectReplacePostMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx); +static int DetectReplacePostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx); -void DetectReplaceRegister (void) +void DetectReplaceRegister(void) { sigmatch_table[DETECT_REPLACE].name = "replace"; - sigmatch_table[DETECT_REPLACE].desc = "only to be used in IPS-mode. Change the following content into another"; + sigmatch_table[DETECT_REPLACE].desc = + "only to be used in IPS-mode. Change the following content into another"; sigmatch_table[DETECT_REPLACE].url = "/rules/payload-keywords.html#replace"; sigmatch_table[DETECT_REPLACE].Match = DetectReplacePostMatch; sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup; #ifdef UNITTESTS sigmatch_table[DETECT_REPLACE].RegisterTests = DetectReplaceRegisterTests; #endif - sigmatch_table[DETECT_REPLACE].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION); + sigmatch_table[DETECT_REPLACE].flags = (SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION); } -static int DetectReplacePostMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectReplacePostMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { if (det_ctx->replist) { DetectReplaceExecuteInternal(p, det_ctx->replist); @@ -115,8 +116,7 @@ int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *replac return -1; /* add to the latest "content" keyword from pmatch */ - const SigMatch *pm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH, - DETECT_CONTENT, -1); + const SigMatch *pm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError("replace needs" "preceding content option for raw sig"); @@ -209,7 +209,6 @@ void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist) } } - void DetectReplaceFreeInternal(DetectReplaceList *replist) { DetectReplaceList *tlist = NULL; @@ -234,10 +233,8 @@ void DetectReplaceFreeInternal(DetectReplaceList *replist) * \retval return 1 if match * \retval return 0 if not */ -static -int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, - const char *sig, uint32_t sid, uint8_t *pp, - uint16_t *len) +static int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, + const char *sig, uint32_t sid, uint8_t *pp, uint16_t *len) { int result = 0; @@ -303,7 +300,6 @@ int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, SCLogDebug("replace: copying %d on %p", *len, pp); } - result = 1; end: if (dtv.app_tctx != NULL) @@ -315,15 +311,14 @@ int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, FlowShutdown(); SCFree(p); - return result; } - /** * \brief Wrapper for DetectContentLongPatternMatchTest */ -static int DetectReplaceLongPatternMatchTestWrp(const char *sig, uint32_t sid, const char *sig_rep, uint32_t sid_rep) +static int DetectReplaceLongPatternMatchTestWrp( + const char *sig, uint32_t sid, const char *sig_rep, uint32_t sid_rep) { int ret; /** Real packet with the following tcp data: @@ -331,6 +326,7 @@ static int DetectReplaceLongPatternMatchTestWrp(const char *sig, uint32_t sid, c * "patterns between multiple chunks!" * (without quotes! :) ) */ + // clang-format off uint8_t raw_eth_pkt[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00, 0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00, @@ -350,7 +346,8 @@ static int DetectReplaceLongPatternMatchTestWrp(const char *sig, uint32_t sid, c 0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65, 0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69, 0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e, - 0x6b,0x73,0x21 }; /* end raw_eth_pkt */ + 0x6b,0x73,0x21 }; + // clang-format on /* end raw_eth_pkt */ uint8_t p[sizeof(raw_eth_pkt)]; uint16_t psize = sizeof(raw_eth_pkt); @@ -376,6 +373,7 @@ static int DetectReplaceLongPatternMatchTestUDPWrp(const char *sig, uint32_t sid int ret; /** Real UDP DNS packet with a request A to a1.twimg.com */ + // clang-format off uint8_t raw_eth_pkt[] = { 0x8c, 0xa9, 0x82, 0x75, 0x5d, 0x62, 0xb4, 0x07, 0xf9, 0xf3, 0xc7, 0x0a, 0x08, 0x00, 0x45, 0x00, @@ -386,16 +384,18 @@ static int DetectReplaceLongPatternMatchTestUDPWrp(const char *sig, uint32_t sid 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x61, 0x31, 0x05, 0x74, 0x77, 0x69, 0x6d, 0x67, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 }; + // clang-format on uint8_t p[sizeof(raw_eth_pkt)]; uint16_t psize = sizeof(raw_eth_pkt); int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; - ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), - sig, sid, p, &psize); + ret = DetectReplaceLongPatternMatchTest( + raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt), sig, sid, p, &psize); if (ret == 1) { - SCLogDebug("replace: test1 phase1 ok: %" PRIuMAX" vs %d",(uintmax_t)sizeof(raw_eth_pkt),psize); + SCLogDebug("replace: test1 phase1 ok: %" PRIuMAX " vs %d", (uintmax_t)sizeof(raw_eth_pkt), + psize); ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL); } run_mode = run_mode_backup; @@ -408,9 +408,9 @@ static int DetectReplaceLongPatternMatchTestUDPWrp(const char *sig, uint32_t sid static int DetectReplaceMatchTest01(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; replace:\"pig\"; sid:1;)"; + " content:\"big\"; replace:\"pig\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"this is a pig test\"; sid:2;)"; + " content:\"this is a pig test\"; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -421,9 +421,9 @@ static int DetectReplaceMatchTest01(void) static int DetectReplaceMatchTest02(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)"; + " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"THis\"; offset:4; sid:2;)"; + " content:\"THis\"; offset:4; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -434,9 +434,9 @@ static int DetectReplaceMatchTest02(void) static int DetectReplaceMatchTest03(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)"; + " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"THis\"; offset:4; sid:2;)"; + " content:\"THis\"; offset:4; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -446,10 +446,11 @@ static int DetectReplaceMatchTest03(void) */ static int DetectReplaceMatchTest04(void) { - const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)"; + const char *sig = + "alert tcp any any -> any any (msg:\"Nothing..\";" + " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"THis\"; content:\"matterns\"; sid:2;)"; + " content:\"THis\"; content:\"matterns\"; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -460,9 +461,9 @@ static int DetectReplaceMatchTest04(void) static int DetectReplaceMatchTest05(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)"; + " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"TH\"; sid:2;)"; + " content:\"TH\"; sid:2;)"; FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -474,9 +475,9 @@ static int DetectReplaceMatchTest05(void) static int DetectReplaceMatchTest06(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)"; + " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"commode\"; sid:2;)"; + " content:\"commode\"; sid:2;)"; FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -487,9 +488,9 @@ static int DetectReplaceMatchTest06(void) static int DetectReplaceMatchTest07(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)"; + " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"this is a pig test\"; sid:2;)"; + " content:\"this is a pig test\"; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -500,9 +501,9 @@ static int DetectReplaceMatchTest07(void) static int DetectReplaceMatchTest08(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)"; + " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"this is a pig test\"; sid:2;)"; + " content:\"this is a pig test\"; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -513,9 +514,9 @@ static int DetectReplaceMatchTest08(void) static int DetectReplaceMatchTest09(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)"; + " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"this is a pig test\"; sid:2;)"; + " content:\"this is a pig test\"; sid:2;)"; FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -526,9 +527,9 @@ static int DetectReplaceMatchTest09(void) static int DetectReplaceMatchTest10(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)"; + " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"pig\"; depth:17; offset:14; sid:2;)"; + " content:\"pig\"; depth:17; offset:14; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -539,9 +540,9 @@ static int DetectReplaceMatchTest10(void) static int DetectReplaceMatchTest11(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)"; + " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"pig\"; depth:17; offset:14; sid:2;)"; + " content:\"pig\"; depth:17; offset:14; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; @@ -553,9 +554,9 @@ static int DetectReplaceMatchTest11(void) static int DetectReplaceMatchTest12(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)"; + " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"pig\"; depth:17; offset:14; sid:2;)"; + " content:\"pig\"; depth:17; offset:14; sid:2;)"; FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -566,9 +567,9 @@ static int DetectReplaceMatchTest12(void) static int DetectReplaceMatchTest13(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; sid:1;)"; + " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"pig\"; depth:17; offset:14; sid:2;)"; + " content:\"pig\"; depth:17; offset:14; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -579,9 +580,9 @@ static int DetectReplaceMatchTest13(void) static int DetectReplaceMatchTest14(void) { const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" - " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)"; + " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)"; const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" - " content:\"pig\"; depth:17; offset:14; sid:2;)"; + " content:\"pig\"; depth:17; offset:14; sid:2;)"; FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2)); PASS; } @@ -592,14 +593,13 @@ static int DetectReplaceMatchTest14(void) static int DetectReplaceMatchTest15(void) { const char *sig = "alert udp any any -> any any (msg:\"Nothing..\";" - " content:\"com\"; replace:\"org\"; sid:1;)"; + " content:\"com\"; replace:\"org\"; sid:1;)"; const char *sig_rep = "alert udp any any -> any any (msg:\"replace worked\";" - " content:\"twimg|03|org\"; sid:2;)"; + " content:\"twimg|03|org\"; sid:2;)"; FAIL_IF_NOT(DetectReplaceLongPatternMatchTestUDPWrp(sig, 1, sig_rep, 2)); PASS; } - /** * \test Parsing test */ @@ -754,7 +754,7 @@ static int DetectReplaceParseTest07(void) */ void DetectReplaceRegisterTests(void) { -/* matching */ + /* matching */ UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01); UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02); UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03); @@ -770,7 +770,7 @@ void DetectReplaceRegisterTests(void) UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13); UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14); UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15); -/* parsing */ + /* parsing */ UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01); UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02); UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03); diff --git a/src/detect-replace.h b/src/detect-replace.h index 4944420527e8..b95b06a6042b 100644 --- a/src/detect-replace.h +++ b/src/detect-replace.h @@ -41,6 +41,6 @@ static inline void DetectReplaceFree(DetectEngineThreadCtx *det_ctx) } } -void DetectReplaceRegister (void); +void DetectReplaceRegister(void); #endif diff --git a/src/detect-rev.c b/src/detect-rev.c index dda513cc0a9f..006c3f622d0c 100644 --- a/src/detect-rev.c +++ b/src/detect-rev.c @@ -26,12 +26,12 @@ #include "suricata-common.h" #include "detect.h" #include "detect-rev.h" -#include "util-debug.h" -#include "util-error.h" +#include "util/debug.h" +#include "util/error.h" -static int DetectRevSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectRevSetup(DetectEngineCtx *, Signature *, const char *); -void DetectRevRegister (void) +void DetectRevRegister(void) { sigmatch_table[DETECT_REV].name = "rev"; sigmatch_table[DETECT_REV].desc = "set version of the rule"; @@ -39,7 +39,7 @@ void DetectRevRegister (void) sigmatch_table[DETECT_REV].Setup = DetectRevSetup; } -static int DetectRevSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectRevSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { unsigned long rev = 0; char *endptr = NULL; @@ -66,6 +66,6 @@ static int DetectRevSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ra return 0; - error: +error: return -1; } \ No newline at end of file diff --git a/src/detect-rev.h b/src/detect-rev.h index 24ae202f1274..e0324b64394f 100644 --- a/src/detect-rev.h +++ b/src/detect-rev.h @@ -25,7 +25,6 @@ #define __DETECT_REV_H__ /* prototypes */ -void DetectRevRegister (void); +void DetectRevRegister(void); #endif /* __DETECT_REV_H__ */ - diff --git a/src/detect-rfb-name.c b/src/detect-rfb-name.c deleted file mode 100644 index 5e8251d51a5a..000000000000 --- a/src/detect-rfb-name.c +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-rfb-name.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-rfb.h" -#include "rust-bindings.h" - -#define KEYWORD_NAME "rfb.name" -#define KEYWORD_DOC "rfb-keywords.html#rfb-name"; -#define BUFFER_NAME "rfb.name" -#define BUFFER_DESC "rfb name" -static int g_buffer_id = 0; - -static int DetectRfbNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_RFB) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_rfb_tx_get_name(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectRfbNameRegister(void) -{ - sigmatch_table[DETECT_AL_RFB_NAME].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_RFB_NAME].url = "/rules/" KEYWORD_DOC - sigmatch_table[DETECT_AL_RFB_NAME].desc = "sticky buffer to match on the RFB desktop name"; - sigmatch_table[DETECT_AL_RFB_NAME].Setup = DetectRfbNameSetup; - sigmatch_table[DETECT_AL_RFB_NAME].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_RFB, - SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 1, - PrefilterGenericMpmRegister, GetData, ALPROTO_RFB, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-rfb-secresult.c b/src/detect-rfb-secresult.c deleted file mode 100644 index 403c16d08aa5..000000000000 --- a/src/detect-rfb-secresult.c +++ /dev/null @@ -1,285 +0,0 @@ -/* Copyright (C) 2020-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-rfb-secresult.h" -#include "util-unittest.h" - -#include "rust.h" - -#define PARSE_REGEX "\\S[A-z]" -static DetectParseRegex parse_regex; - -static int rfb_secresult_id = 0; - -static int DetectRfbSecresultMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx); -static int DetectRfbSecresultSetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void RfbSecresultRegisterTests(void); -#endif -void DetectRfbSecresultFree(DetectEngineCtx *, void *); - -typedef struct DetectRfbSecresultData_ { - uint32_t result; /** result code */ -} DetectRfbSecresultData; - -/** - * \brief Registration function for rfb.secresult: keyword - */ -void DetectRfbSecresultRegister (void) -{ - sigmatch_table[DETECT_AL_RFB_SECRESULT].name = "rfb.secresult"; - sigmatch_table[DETECT_AL_RFB_SECRESULT].desc = "match RFB security result"; - sigmatch_table[DETECT_AL_RFB_SECRESULT].url = "/rules/rfb-keywords.html#rfb-secresult"; - sigmatch_table[DETECT_AL_RFB_SECRESULT].AppLayerTxMatch = DetectRfbSecresultMatch; - sigmatch_table[DETECT_AL_RFB_SECRESULT].Setup = DetectRfbSecresultSetup; - sigmatch_table[DETECT_AL_RFB_SECRESULT].Free = DetectRfbSecresultFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_RFB_SECRESULT].RegisterTests = RfbSecresultRegisterTests; -#endif - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2("rfb.secresult", ALPROTO_RFB, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectGenericList, NULL); - - rfb_secresult_id = DetectBufferTypeGetByName("rfb.secresult"); -} - -enum { - RFB_SECRESULT_OK = 0, - RFB_SECRESULT_FAIL, - RFB_SECRESULT_TOOMANY, - RFB_SECRESULT_UNKNOWN -}; - -/** - * \struct DetectRfbSecresult_ - * DetectRfbSecresult_ is used to store values - */ - -struct DetectRfbSecresult_ { - const char *result; - uint16_t code; -} results[] = { - { "ok", RFB_SECRESULT_OK, }, - { "fail", RFB_SECRESULT_FAIL, }, - { "toomany", RFB_SECRESULT_TOOMANY, }, - { "unknown", RFB_SECRESULT_UNKNOWN, }, - { NULL, 0 }, -}; - -/** - * \internal - * \brief Function to match security result of a RFB TX - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the RFBTransaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectRfbSecresultData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectRfbSecresultMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - const DetectRfbSecresultData *de = (const DetectRfbSecresultData *)ctx; - uint32_t resultcode; - int ret = 0; - - if (!de) - return 0; - - ret = rs_rfb_tx_get_secresult(txv, &resultcode); - if (ret == 0) { - return 0; - } - - if (de->result < 3) { - /* we are asking for a defined code... */ - if (resultcode == de->result) { - /* ... which needs to match */ - return 1; - } - } else { - /* we are asking for an unknown code */ - if (resultcode > 2) { - /* match any unknown code */ - return 1; - } - } - - return 0; -} - -/** - * \internal - * \brief This function is used to parse options passed via rfb.secresults: keyword - * - * \param rawstr Pointer to the user provided secresult options - * - * \retval de pointer to DetectRfbSecresultData on success - * \retval NULL on failure - */ -static DetectRfbSecresultData *DetectRfbSecresultParse (const char *rawstr) -{ - int i; - DetectRfbSecresultData *de = NULL; - int found = 0; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 1) { - SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); - goto error; - } - - for(i = 0; results[i].result != NULL; i++) { - if((strcasecmp(results[i].result,rawstr)) == 0) { - found = 1; - break; - } - } - - if(found == 0) { - SCLogError("unknown secresult value %s", rawstr); - goto error; - } - - de = SCMalloc(sizeof(DetectRfbSecresultData)); - if (unlikely(de == NULL)) - goto error; - - de->result = results[i].code; - - pcre2_match_data_free(match); - return de; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (de) SCFree(de); - return NULL; -} - -/** - * \internal - * \brief this function is used to add the parsed secresult into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param rawstr pointer to the user provided secresult options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectRfbSecresultSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - DetectRfbSecresultData *de = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_RFB) < 0) - return -1; - - de = DetectRfbSecresultParse(rawstr); - if (de == NULL) - goto error; - - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_AL_RFB_SECRESULT, (SigMatchCtx *)de, rfb_secresult_id) == NULL) { - goto error; - } - - return 0; - -error: - if (de) - SCFree(de); - return -1; -} - -/** - * \internal - * \brief this function will free memory associated with DetectRfbSecresultData - * - * \param de pointer to DetectRfbSecresultData - */ -void DetectRfbSecresultFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - DetectRfbSecresultData *de = (DetectRfbSecresultData *)de_ptr; - if(de) SCFree(de); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -/** - * \test RfbSecresultTestParse01 is a test for a valid secresult value - */ -static int RfbSecresultTestParse01 (void) -{ - DetectRfbSecresultData *de = DetectRfbSecresultParse("fail"); - - FAIL_IF_NULL(de); - - DetectRfbSecresultFree(NULL, de); - - PASS; -} - -/** - * \test RfbSecresultTestParse02 is a test for an invalid secresult value - */ -static int RfbSecresultTestParse02 (void) -{ - DetectRfbSecresultData *de = DetectRfbSecresultParse("invalidopt"); - - FAIL_IF_NOT_NULL(de); - - PASS; -} - -/** - * \brief this function registers unit tests for RfbSecresult - */ -void RfbSecresultRegisterTests(void) -{ - UtRegisterTest("RfbSecresultTestParse01", RfbSecresultTestParse01); - UtRegisterTest("RfbSecresultTestParse02", RfbSecresultTestParse02); -} -#endif /* UNITTESTS */ diff --git a/src/detect-rfb-sectype.c b/src/detect-rfb-sectype.c deleted file mode 100644 index d942a4503a49..000000000000 --- a/src/detect-rfb-sectype.c +++ /dev/null @@ -1,151 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-rfb-sectype.h" -#include "detect-engine-uint.h" -#include "app-layer-parser.h" -#include "util-byte.h" - -#include "rust-bindings.h" - - -static int DetectRfbSectypeSetup (DetectEngineCtx *, Signature *s, const char *str); -static void DetectRfbSectypeFree(DetectEngineCtx *, void *); -static int g_rfb_sectype_buffer_id = 0; - -static int DetectRfbSectypeMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); - -/** - * \brief Registration function for rfb.sectype keyword. - */ -void DetectRfbSectypeRegister (void) -{ - sigmatch_table[DETECT_AL_RFB_SECTYPE].name = "rfb.sectype"; - sigmatch_table[DETECT_AL_RFB_SECTYPE].desc = "match RFB security type"; - sigmatch_table[DETECT_AL_RFB_SECTYPE].url = "/rules/rfb-keywords.html#rfb-sectype"; - sigmatch_table[DETECT_AL_RFB_SECTYPE].AppLayerTxMatch = DetectRfbSectypeMatch; - sigmatch_table[DETECT_AL_RFB_SECTYPE].Setup = DetectRfbSectypeSetup; - sigmatch_table[DETECT_AL_RFB_SECTYPE].Free = DetectRfbSectypeFree; - - DetectAppLayerInspectEngineRegister2( - "rfb.sectype", ALPROTO_RFB, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - g_rfb_sectype_buffer_id = DetectBufferTypeGetByName("rfb.sectype"); -} - -/** - * \internal - * \brief Function to match security type of a RFB TX - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the RFBTransaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectRfbSectypeMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - SCEnter(); - - const DetectU32Data *dd = (const DetectU32Data *)ctx; - uint32_t version; - rs_rfb_tx_get_sectype(txv, &version); - if (DetectU32Match(version, dd)) - SCReturnInt(1); - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to parse options passed via rfb.sectype keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectU32Data on success. - * \retval NULL on failure. - */ -static DetectU32Data *DetectRfbSectypeParse(const char *rawstr) -{ - return DetectU32Parse(rawstr); -} - -/** - * \brief Function to add the parsed RFB security type field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectRfbSectypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_RFB) != 0) - return -1; - - DetectU32Data *dd = DetectRfbSectypeParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_RFB_SECTYPE, (SigMatchCtx *)dd, - g_rfb_sectype_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectRfbSectypeFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -static void DetectRfbSectypeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} diff --git a/src/detect-rpc.c b/src/detect-rpc.c index 07f29569000f..5672c871191d 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -35,21 +35,22 @@ #include "detect-engine-address.h" #include "detect-engine-build.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" -#include "util-byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" +#include "util/byte.h" /** * \brief Regex for parsing our rpc options */ -#define PARSE_REGEX "^\\s*([0-9]{0,10})\\s*(?:,\\s*([0-9]{0,10}|[*])\\s*(?:,\\s*([0-9]{0,10}|[*]))?)?\\s*$" +#define PARSE_REGEX \ + "^\\s*([0-9]{0,10})\\s*(?:,\\s*([0-9]{0,10}|[*])\\s*(?:,\\s*([0-9]{0,10}|[*]))?)?\\s*$" static DetectParseRegex parse_regex; -static int DetectRpcMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectRpcSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectRpcMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectRpcSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectRpcRegisterTests(void); #endif @@ -58,14 +59,14 @@ void DetectRpcFree(DetectEngineCtx *, void *); /** * \brief Registration function for rpc keyword */ -void DetectRpcRegister (void) +void DetectRpcRegister(void) { sigmatch_table[DETECT_RPC].name = "rpc"; sigmatch_table[DETECT_RPC].desc = "match RPC procedure numbers and RPC version"; sigmatch_table[DETECT_RPC].url = "/rules/payload-keywords.html#rpc"; sigmatch_table[DETECT_RPC].Match = DetectRpcMatch; sigmatch_table[DETECT_RPC].Setup = DetectRpcSetup; - sigmatch_table[DETECT_RPC].Free = DetectRpcFree; + sigmatch_table[DETECT_RPC].Free = DetectRpcFree; #ifdef UNITTESTS sigmatch_table[DETECT_RPC].RegisterTests = DetectRpcRegisterTests; #endif @@ -89,8 +90,8 @@ void DetectRpcRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectRpcMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectRpcMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { /* PrintRawDataFp(stdout, p->payload, p->payload_len); */ const DetectRpcData *rd = (const DetectRpcData *)ctx; @@ -132,7 +133,8 @@ static int DetectRpcMatch (DetectEngineThreadCtx *det_ctx, Packet *p, if ((rd->flags & DETECT_RPC_CHECK_PROCEDURE) && SCNtohl(msg->proc) != rd->procedure) return 0; - SCLogDebug("prog:%u pver:%u proc:%u matched", SCNtohl(msg->prog), SCNtohl(msg->vers), SCNtohl(msg->proc)); + SCLogDebug("prog:%u pver:%u proc:%u matched", SCNtohl(msg->prog), SCNtohl(msg->vers), + SCNtohl(msg->proc)); return 1; } @@ -145,10 +147,10 @@ static int DetectRpcMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval rd pointer to DetectRpcData on success * \retval NULL on failure */ -static DetectRpcData *DetectRpcParse (DetectEngineCtx *de_ctx, const char *rpcstr) +static DetectRpcData *DetectRpcParse(DetectEngineCtx *de_ctx, const char *rpcstr) { DetectRpcData *rd = NULL; - char *args[3] = {NULL,NULL,NULL}; + char *args[3] = { NULL, NULL, NULL }; int res = 0; size_t pcre2_len; @@ -207,7 +209,8 @@ static DetectRpcData *DetectRpcParse (DetectEngineCtx *de_ctx, const char *rpcst break; case 1: if (args[i][0] != '*') { - if (StringParseUint32(&rd->program_version, 10, strlen(args[i]), args[i]) <= 0) { + if (StringParseUint32(&rd->program_version, 10, strlen(args[i]), args[i]) <= + 0) { SCLogError( "Invalid size specified for the rpc version:\"%s\"", args[i]); goto error; @@ -224,14 +227,14 @@ static DetectRpcData *DetectRpcParse (DetectEngineCtx *de_ctx, const char *rpcst } rd->flags |= DETECT_RPC_CHECK_PROCEDURE; } - break; + break; } } else { SCLogError("invalid rpc option %s", rpcstr); goto error; } } - for (i = 0; i < (ret -1); i++){ + for (i = 0; i < (ret - 1); i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } @@ -242,14 +245,13 @@ static DetectRpcData *DetectRpcParse (DetectEngineCtx *de_ctx, const char *rpcst if (match) { pcre2_match_data_free(match); } - for (i = 0; i < (ret -1) && i < 3; i++){ + for (i = 0; i < (ret - 1) && i < 3; i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } if (rd != NULL) DetectRpcFree(de_ctx, rd); return NULL; - } /** @@ -263,12 +265,13 @@ static DetectRpcData *DetectRpcParse (DetectEngineCtx *de_ctx, const char *rpcst * \retval 0 on Success * \retval -1 on Failure */ -int DetectRpcSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rpcstr) +int DetectRpcSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rpcstr) { DetectRpcData *rd = NULL; rd = DetectRpcParse(de_ctx, rpcstr); - if (rd == NULL) goto error; + if (rd == NULL) + goto error; if (SigMatchAppendSMToList(de_ctx, s, DETECT_RPC, (SigMatchCtx *)rd, DETECT_SM_LIST_MATCH) == NULL) { @@ -282,7 +285,6 @@ int DetectRpcSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rpcstr) if (rd != NULL) DetectRpcFree(de_ctx, rd); return -1; - } /** @@ -310,7 +312,7 @@ void DetectRpcFree(DetectEngineCtx *de_ctx, void *ptr) * \test DetectRpcTestParse01 is a test to make sure that we return "something" * when given valid rpc opt */ -static int DetectRpcTestParse01 (void) +static int DetectRpcTestParse01(void) { DetectRpcData *rd = DetectRpcParse(NULL, "123,444,555"); FAIL_IF_NULL(rd); @@ -322,7 +324,7 @@ static int DetectRpcTestParse01 (void) /** * \test DetectRpcTestParse02 is a test for setting the established rpc opt */ -static int DetectRpcTestParse02 (void) +static int DetectRpcTestParse02(void) { DetectRpcData *rd = NULL; rd = DetectRpcParse(NULL, "111,222,333"); @@ -343,7 +345,7 @@ static int DetectRpcTestParse02 (void) * \test DetectRpcTestParse03 is a test for checking the wildcards * and not specified fields */ -static int DetectRpcTestParse03 (void) +static int DetectRpcTestParse03(void) { DetectRpcData *rd = NULL; @@ -412,7 +414,7 @@ static int DetectRpcTestParse03 (void) /** * \test DetectRpcTestParse04 is a test for check the discarding of empty options */ -static int DetectRpcTestParse04 (void) +static int DetectRpcTestParse04(void) { DetectRpcData *rd = NULL; rd = DetectRpcParse(NULL, ""); @@ -426,7 +428,7 @@ static int DetectRpcTestParse04 (void) /** * \test DetectRpcTestParse05 is a test for check invalid values */ -static int DetectRpcTestParse05 (void) +static int DetectRpcTestParse05(void) { DetectRpcData *rd = NULL; rd = DetectRpcParse(NULL, "111,aaa,*"); @@ -443,6 +445,7 @@ static int DetectRpcTestParse05 (void) static int DetectRpcTestSig01(void) { /* RPC Call */ + // clang-format off uint8_t buf[] = { /* XID */ 0x64,0xb2,0xb3,0x75, @@ -472,6 +475,7 @@ static int DetectRpcTestSig01(void) 0x00,0x00,0x00,0x11, /* Port 0 */ 0x00,0x00,0x00,0x00 }; + // clang-format on uint16_t buflen = sizeof(buf); Packet *p = NULL; Signature *s = NULL; diff --git a/src/detect-rpc.h b/src/detect-rpc.h index 4b4e60b1603d..bae6ce5ae2de 100644 --- a/src/detect-rpc.h +++ b/src/detect-rpc.h @@ -27,18 +27,18 @@ /* At least we check the program, the version is optional, * and the procedure is optional if we are checking the version. * If we parse the wildcard "*" we will allow any value (no check) */ -#define DETECT_RPC_CHECK_PROGRAM 0x01 -#define DETECT_RPC_CHECK_VERSION 0x02 -#define DETECT_RPC_CHECK_PROCEDURE 0x04 +#define DETECT_RPC_CHECK_PROGRAM 0x01 +#define DETECT_RPC_CHECK_VERSION 0x02 +#define DETECT_RPC_CHECK_PROCEDURE 0x04 /** Simple struct for a rpc msg call */ typedef struct RpcMsg_ { - uint32_t xid; - uint32_t type; /**< CALL = 0 (We only search for CALLS */ - uint32_t rpcvers; /**< must be equal to two (2) */ - uint32_t prog; - uint32_t vers; - uint32_t proc; + uint32_t xid; + uint32_t type; /**< CALL = 0 (We only search for CALLS */ + uint32_t rpcvers; /**< must be equal to two (2) */ + uint32_t prog; + uint32_t vers; + uint32_t proc; } RpcMsg; typedef struct DetectRpcData_ { @@ -49,7 +49,6 @@ typedef struct DetectRpcData_ { } DetectRpcData; /* prototypes */ -void DetectRpcRegister (void); +void DetectRpcRegister(void); #endif /* __DETECT_RPC_H__ */ - diff --git a/src/detect-sameip.c b/src/detect-sameip.c index 2ed72cf00e3a..713f8e4a3218 100644 --- a/src/detect-sameip.c +++ b/src/detect-sameip.c @@ -34,11 +34,11 @@ #include "detect-sameip.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" -static int DetectSameipMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectSameipMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectSameipSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectSameipRegisterTests(void); @@ -51,7 +51,8 @@ static void DetectSameipRegisterTests(void); void DetectSameipRegister(void) { sigmatch_table[DETECT_SAMEIP].name = "sameip"; - sigmatch_table[DETECT_SAMEIP].desc = "check if the IP address of the source is the same as the IP address of the destination"; + sigmatch_table[DETECT_SAMEIP].desc = "check if the IP address of the source is the same as the " + "IP address of the destination"; sigmatch_table[DETECT_SAMEIP].url = "/rules/header-keywords.html#sameip"; sigmatch_table[DETECT_SAMEIP].Match = DetectSameipMatch; sigmatch_table[DETECT_SAMEIP].Setup = DetectSameipSetup; @@ -73,8 +74,8 @@ void DetectSameipRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectSameipMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectSameipMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { return CMP_ADDR(&p->src, &p->dst) ? 1 : 0; } @@ -117,9 +118,8 @@ static int DetectSameipSetup(DetectEngineCtx *de_ctx, Signature *s, const char * */ static int DetectSameipSigTest01(void) { - uint8_t *buf = (uint8_t *) - "GET / HTTP/1.0\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET / HTTP/1.0\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p1 = NULL; Packet *p2 = NULL; @@ -139,9 +139,8 @@ static int DetectSameipSigTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing sameip\"; sameip; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing sameip\"; sameip; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); diff --git a/src/detect-sid.c b/src/detect-sid.c index 0002e1066384..a5cc876ede78 100644 --- a/src/detect-sid.c +++ b/src/detect-sid.c @@ -28,16 +28,16 @@ #include "detect-engine.h" #include "detect-parse.h" #include "detect-sid.h" -#include "util-debug.h" -#include "util-error.h" -#include "util-unittest.h" +#include "util/debug.h" +#include "util/error.h" +#include "util/unittest.h" -static int DetectSidSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectSidSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectSidRegisterTests(void); #endif -void DetectSidRegister (void) +void DetectSidRegister(void) { sigmatch_table[DETECT_SID].name = "sid"; sigmatch_table[DETECT_SID].desc = "set rule ID"; @@ -49,7 +49,7 @@ void DetectSidRegister (void) #endif } -static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, const char *sidstr) +static int DetectSidSetup(DetectEngineCtx *de_ctx, Signature *s, const char *sidstr) { unsigned long id = 0; char *endptr = NULL; @@ -75,7 +75,7 @@ static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, const char *si s->id = (uint32_t)id; return 0; - error: +error: return -1; } diff --git a/src/detect-sid.h b/src/detect-sid.h index f7389d105ded..e74cf871df97 100644 --- a/src/detect-sid.h +++ b/src/detect-sid.h @@ -25,7 +25,6 @@ #define __DETECT_SID_H__ /* prototypes */ -void DetectSidRegister (void); +void DetectSidRegister(void); #endif /* __DETECT_SID_H__ */ - diff --git a/src/detect-sip-method.c b/src/detect-sip-method.c deleted file mode 100644 index fccc8a73f9fc..000000000000 --- a/src/detect-sip-method.c +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Giuseppe Longo - * - * Implements the sip.method sticky buffer - * - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-sip-method.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-sip.h" - -#define KEYWORD_NAME "sip.method" -#define KEYWORD_DOC "sip-keywords.html#sip-method" -#define BUFFER_NAME "sip.method" -#define BUFFER_DESC "sip request method" -static int g_buffer_id = 0; - -static int DetectSipMethodSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) - return -1; - - return 0; -} - -static bool DetectSipMethodValidateCallback(const Signature *s, const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - const DetectContentData *cd = (const DetectContentData *)sm->ctx; - if (cd->content && cd->content_len) { - if (cd->content[cd->content_len - 1] == 0x20) { - *sigerror = "sip.method pattern with trailing space"; - SCLogError("%s", *sigerror); - return true; - } else if (cd->content[0] == 0x20) { - *sigerror = "sip.method pattern with leading space"; - SCLogError("%s", *sigerror); - return true; - } else if (cd->content[cd->content_len - 1] == 0x09) { - *sigerror = "sip.method pattern with trailing tab"; - SCLogError("%s", *sigerror); - return true; - } else if (cd->content[0] == 0x09) { - *sigerror = "sip.method pattern with leading tab"; - SCLogError("%s", *sigerror); - return true; - } - } - } - } - return true; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_sip_tx_get_method(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectSipMethodRegister(void) -{ - /* sip.method sticky buffer */ - sigmatch_table[DETECT_AL_SIP_METHOD].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SIP_METHOD].desc = "sticky buffer to match on the SIP method buffer"; - sigmatch_table[DETECT_AL_SIP_METHOD].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SIP_METHOD].Setup = DetectSipMethodSetup; - sigmatch_table[DETECT_AL_SIP_METHOD].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, - DetectSipMethodValidateCallback); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-sip-protocol.c b/src/detect-sip-protocol.c deleted file mode 100644 index 41fdcac538b3..000000000000 --- a/src/detect-sip-protocol.c +++ /dev/null @@ -1,121 +0,0 @@ - /* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Giuseppe Longo - * - * Implements sip.protocol sticky buffer - * - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-sip-protocol.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-sip.h" - -#define KEYWORD_NAME "sip.protocol" -#define KEYWORD_DOC "sip-keywords.html#sip-protocol" -#define BUFFER_NAME "sip.protocol" -#define BUFFER_DESC "sip protocol" -static int g_buffer_id = 0; - -static int DetectSipProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_sip_tx_get_protocol(txv, &b, &b_len, flow_flags) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectSipProtocolRegister(void) -{ - /* sip.protocol sticky buffer */ - sigmatch_table[DETECT_AL_SIP_PROTOCOL].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SIP_PROTOCOL].desc = "sticky buffer to match on the SIP protocol"; - sigmatch_table[DETECT_AL_SIP_PROTOCOL].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SIP_PROTOCOL].Setup = DetectSipProtocolSetup; - sigmatch_table[DETECT_AL_SIP_PROTOCOL].flags |= SIGMATCH_NOOPT; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SIP, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetData); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SIP, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetData); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-sip-request-line.c b/src/detect-sip-request-line.c deleted file mode 100644 index 9d9f4c9c5fe5..000000000000 --- a/src/detect-sip-request-line.c +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Giuseppe Longo - * - * Implements the sip.request_line sticky buffer - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-sip-request-line.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-sip.h" - -#define KEYWORD_NAME "sip.request_line" -#define KEYWORD_DOC "sip-keywords.html#sip-request-line" -#define BUFFER_NAME "sip.request_line" -#define BUFFER_DESC "sip request line" -static int g_buffer_id = 0; - -static int DetectSipRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_sip_tx_get_request_line(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectSipRequestLineRegister(void) -{ - /* sip.request_line sticky buffer */ - sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].desc = "sticky buffer to match on the SIP request line"; - sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].Setup = DetectSipRequestLineSetup; - sigmatch_table[DETECT_AL_SIP_REQUEST_LINE].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-sip-response-line.c b/src/detect-sip-response-line.c deleted file mode 100644 index 99061f951d5a..000000000000 --- a/src/detect-sip-response-line.c +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Giuseppe Longo - * - * Implements the sip.response_line sticky buffer - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-sip-response-line.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-sip.h" - -#define KEYWORD_NAME "sip.response_line" -#define KEYWORD_DOC "sip-keywords.html#sip-response-line" -#define BUFFER_NAME "sip.response_line" -#define BUFFER_DESC "sip response line" -static int g_buffer_id = 0; - -static int DetectSipResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_sip_tx_get_response_line(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectSipResponseLineRegister(void) -{ - /* sip.response_line sticky buffer */ - sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].desc = "sticky buffer to match on the SIP response line"; - sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].Setup = DetectSipResponseLineSetup; - sigmatch_table[DETECT_AL_SIP_RESPONSE_LINE].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, - SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-sip-stat-code.c b/src/detect-sip-stat-code.c deleted file mode 100644 index 9b663c971e8e..000000000000 --- a/src/detect-sip-stat-code.c +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Giuseppe Longo - * - * Implements the sip.stat_code sticky buffer - * - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-sip-stat-code.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-sip.h" - -#define KEYWORD_NAME "sip.stat_code" -#define KEYWORD_DOC "sip-keywords.html#sip-stat-code" -#define BUFFER_NAME "sip.method" -#define BUFFER_DESC "sip response status code" -static int g_buffer_id = 0; - -static int DetectSipStatCodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_sip_tx_get_stat_code(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectSipStatCodeRegister (void) -{ - /* sip.stat_code sticky buffer */ - sigmatch_table[DETECT_AL_SIP_STAT_CODE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SIP_STAT_CODE].desc = "sticky buffer to match on the SIP status code"; - sigmatch_table[DETECT_AL_SIP_STAT_CODE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SIP_STAT_CODE].Setup = DetectSipStatCodeSetup; - sigmatch_table[DETECT_AL_SIP_STAT_CODE].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, - SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 4, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-sip-stat-msg.c b/src/detect-sip-stat-msg.c deleted file mode 100644 index a9b9247a5d70..000000000000 --- a/src/detect-sip-stat-msg.c +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Giuseppe Longo - * - * Implements the sip.stat_msg sticky buffer - * - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-sip-stat-msg.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-sip.h" - -#define KEYWORD_NAME "sip.stat_msg" -#define KEYWORD_DOC "sip-keywords.html#sip-stat-msg" -#define BUFFER_NAME "sip.stat_msg" -#define BUFFER_DESC "sip response status message" -static int g_buffer_id = 0; - -static int DetectSipStatMsgSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_sip_tx_get_stat_msg(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectSipStatMsgRegister (void) -{ - /* sip.stat_msg sticky buffer */ - sigmatch_table[DETECT_AL_SIP_STAT_MSG].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SIP_STAT_MSG].desc = "sticky buffer to match on the SIP status message"; - sigmatch_table[DETECT_AL_SIP_STAT_MSG].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SIP_STAT_MSG].Setup = DetectSipStatMsgSetup; - sigmatch_table[DETECT_AL_SIP_STAT_MSG].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, - SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 3, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-sip-uri.c b/src/detect-sip-uri.c deleted file mode 100644 index 1a000fdb543a..000000000000 --- a/src/detect-sip-uri.c +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Giuseppe Longo - * - * Implements the sip.uri sticky buffer - * - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-sip-uri.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-sip.h" - -#define KEYWORD_NAME "sip.uri" -#define KEYWORD_DOC "sip-keywords.html#sip-uri" -#define BUFFER_NAME "sip.uri" -#define BUFFER_DESC "sip request uri" -static int g_buffer_id = 0; - -static bool DetectSipUriValidateCallback(const Signature *s, const char **sigerror) -{ - return DetectUrilenValidateContent(s, g_buffer_id, sigerror); -} - -static void DetectSipUriSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - SCLogDebug("callback invoked by %u", s->id); - DetectUrilenApplyToContent(s, g_buffer_id); -} - -static int DetectSipUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SIP) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t _flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (rs_sip_tx_get_uri(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectSipUriRegister(void) -{ - sigmatch_table[DETECT_AL_SIP_URI].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SIP_URI].desc = "sticky buffer to match on the SIP URI"; - sigmatch_table[DETECT_AL_SIP_URI].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SIP_URI].Setup = DetectSipUriSetup; - sigmatch_table[DETECT_AL_SIP_URI].flags |= SIGMATCH_NOOPT; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SIP, - SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SIP, - 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, - DetectSipUriSetupCallback); - - DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, - DetectSipUriValidateCallback); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - SCLogDebug("registering " BUFFER_NAME " rule option"); -} diff --git a/src/detect-smb-ntlmssp.c b/src/detect-smb-ntlmssp.c deleted file mode 100644 index a88b89c6f473..000000000000 --- a/src/detect-smb-ntlmssp.c +++ /dev/null @@ -1,149 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * - */ - -#include "detect-engine-register.h" -#include "suricata-common.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "detect-smb-ntlmssp.h" -#include "rust.h" - -#define BUFFER_NAME "smb_ntlmssp_user" -#define KEYWORD_NAME "smb.ntlmssp_user" -#define KEYWORD_ID DETECT_SMB_NTLMSSP_USER - -static int g_smb_nltmssp_user_buffer_id = 0; - -static int DetectSmbNtlmsspUserSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_smb_nltmssp_user_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetNtlmsspUserData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_smb_tx_get_ntlmssp_user(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectSmbNtlmsspUserRegister(void) -{ - sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; - sigmatch_table[KEYWORD_ID].Setup = DetectSmbNtlmsspUserSetup; - sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - sigmatch_table[KEYWORD_ID].desc = "sticky buffer to match on SMB ntlmssp user in session setup"; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetNtlmsspUserData, ALPROTO_SMB, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetNtlmsspUserData); - - g_smb_nltmssp_user_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} - -#undef BUFFER_NAME -#undef KEYWORD_NAME -#undef KEYWORD_ID - -#define BUFFER_NAME "smb_ntlmssp_domain" -#define KEYWORD_NAME "smb.ntlmssp_domain" -#define KEYWORD_ID DETECT_SMB_NTLMSSP_DOMAIN - -static int g_smb_nltmssp_domain_buffer_id = 0; - -static int DetectSmbNtlmsspDomainSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_smb_nltmssp_domain_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetNtlmsspDomainData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_smb_tx_get_ntlmssp_domain(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectSmbNtlmsspDomainRegister(void) -{ - sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; - sigmatch_table[KEYWORD_ID].Setup = DetectSmbNtlmsspDomainSetup; - sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - sigmatch_table[KEYWORD_ID].desc = - "sticky buffer to match on SMB ntlmssp domain in session setup"; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetNtlmsspDomainData, ALPROTO_SMB, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetNtlmsspDomainData); - - g_smb_nltmssp_domain_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-smb-share.c b/src/detect-smb-share.c deleted file mode 100644 index 8d4d145fad8c..000000000000 --- a/src/detect-smb-share.c +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#include "suricata-common.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "detect-smb-share.h" -#include "rust.h" - -#define BUFFER_NAME "smb_named_pipe" -#define KEYWORD_NAME "smb.named_pipe" -#define KEYWORD_NAME_LEGACY BUFFER_NAME -#define KEYWORD_ID DETECT_SMB_NAMED_PIPE - -static int g_smb_named_pipe_buffer_id = 0; - -static int DetectSmbNamedPipeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_smb_named_pipe_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetNamedPipeData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_smb_tx_get_named_pipe(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectSmbNamedPipeRegister(void) -{ - sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; - sigmatch_table[KEYWORD_ID].alias = KEYWORD_NAME_LEGACY; - sigmatch_table[KEYWORD_ID].Setup = DetectSmbNamedPipeSetup; - sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - sigmatch_table[KEYWORD_ID].desc = "sticky buffer to match on SMB named pipe in tree connect"; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetNamedPipeData, - ALPROTO_SMB, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetNamedPipeData); - - g_smb_named_pipe_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} - -#undef BUFFER_NAME -#undef KEYWORD_NAME -#undef KEYWORD_NAME_LEGACY -#undef KEYWORD_ID - -#define BUFFER_NAME "smb_share" -#define KEYWORD_NAME "smb.share" -#define KEYWORD_NAME_LEGACY BUFFER_NAME -#define KEYWORD_ID DETECT_SMB_SHARE - -static int g_smb_share_buffer_id = 0; - -static int DetectSmbShareSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_smb_share_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SMB) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetShareData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *_f, const uint8_t _flow_flags, - void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_smb_tx_get_share(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -void DetectSmbShareRegister(void) -{ - sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; - sigmatch_table[KEYWORD_ID].alias = KEYWORD_NAME_LEGACY; - sigmatch_table[KEYWORD_ID].Setup = DetectSmbShareSetup; - sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - sigmatch_table[KEYWORD_ID].desc = "sticky buffer to match on SMB share name in tree connect"; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetShareData, - ALPROTO_SMB, 1); - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SMB, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetShareData); - - g_smb_share_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-snmp-community.c b/src/detect-snmp-community.c deleted file mode 100644 index 93e7d21671ab..000000000000 --- a/src/detect-snmp-community.c +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (C) 2015-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * - * Set up of the "snmp.community" keyword to allow content - * inspections on the decoded snmp community. - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-snmp-community.h" -#include "app-layer-parser.h" -#include "rust.h" - -static int DetectSNMPCommunitySetup(DetectEngineCtx *, Signature *, - const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -#ifdef UNITTESTS -static void DetectSNMPCommunityRegisterTests(void); -#endif -static int g_snmp_rust_id = 0; - -void DetectSNMPCommunityRegister(void) -{ - sigmatch_table[DETECT_AL_SNMP_COMMUNITY].name = "snmp.community"; - sigmatch_table[DETECT_AL_SNMP_COMMUNITY].desc = - "SNMP content modifier to match on the SNMP community"; - sigmatch_table[DETECT_AL_SNMP_COMMUNITY].Setup = - DetectSNMPCommunitySetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_SNMP_COMMUNITY].RegisterTests = DetectSNMPCommunityRegisterTests; -#endif - sigmatch_table[DETECT_AL_SNMP_COMMUNITY].url = "/rules/snmp-keywords.html#snmp-community"; - - sigmatch_table[DETECT_AL_SNMP_COMMUNITY].flags |= SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER; - - /* register inspect engines */ - DetectAppLayerInspectEngineRegister2("snmp.community", - ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - DetectAppLayerMpmRegister2("snmp.community", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SNMP, 0); - DetectAppLayerInspectEngineRegister2("snmp.community", - ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetData); - DetectAppLayerMpmRegister2("snmp.community", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_SNMP, 0); - - DetectBufferTypeSetDescriptionByName("snmp.community", "SNMP Community identifier"); - - g_snmp_rust_id = DetectBufferTypeGetByName("snmp.community"); -} - -static int DetectSNMPCommunitySetup(DetectEngineCtx *de_ctx, Signature *s, - const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_snmp_rust_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t data_len = 0; - const uint8_t *data = NULL; - - rs_snmp_tx_get_community(txv, &data, &data_len); - if (data == NULL || data_len == 0) { - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS -#include "tests/detect-snmp-community.c" -#endif /* UNITTESTS */ diff --git a/src/detect-snmp-community.h b/src/detect-snmp-community.h deleted file mode 100644 index 11de2abbf99a..000000000000 --- a/src/detect-snmp-community.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2015-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author FirstName LastName - */ - -#ifndef __DETECT_SNMP_COMMUNITY_H__ -#define __DETECT_SNMP_COMMUNITY_H__ - - -void DetectSNMPCommunityRegister(void); - -#endif /* __DETECT_SNMP_COMMUNITY_H__ */ diff --git a/src/detect-snmp-pdu_type.c b/src/detect-snmp-pdu_type.c deleted file mode 100644 index 243d6c323be8..000000000000 --- a/src/detect-snmp-pdu_type.c +++ /dev/null @@ -1,221 +0,0 @@ -/* Copyright (C) 2015-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-snmp-pdu_type.h" -#include "app-layer-parser.h" -#include "rust.h" - -/** - * [snmp.pdu_type]:; - */ -#define PARSE_REGEX "^\\s*([0-9]+)\\s*$" -static DetectParseRegex parse_regex; - -typedef struct DetectSNMPPduTypeData_ { - uint32_t pdu_type; -} DetectSNMPPduTypeData; - -static DetectSNMPPduTypeData *DetectSNMPPduTypeParse (const char *); -static int DetectSNMPPduTypeSetup (DetectEngineCtx *, Signature *s, const char *str); -static void DetectSNMPPduTypeFree(DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectSNMPPduTypeRegisterTests(void); -#endif -static int g_snmp_pdu_type_buffer_id = 0; - -static int DetectSNMPPduTypeMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); - -void DetectSNMPPduTypeRegister(void) -{ - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].name = "snmp.pdu_type"; - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].desc = "match SNMP PDU type"; - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].url = "/rules/snmp-keywords.html#snmp-pdu-type"; - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Match = NULL; - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].AppLayerTxMatch = DetectSNMPPduTypeMatch; - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Setup = DetectSNMPPduTypeSetup; - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].Free = DetectSNMPPduTypeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_SNMP_PDU_TYPE].RegisterTests = DetectSNMPPduTypeRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2("snmp.pdu_type", ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("snmp.pdu_type", ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - g_snmp_pdu_type_buffer_id = DetectBufferTypeGetByName("snmp.pdu_type"); -} - -/** - * \internal - * \brief Function to match pdu_type of a TX - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectSNMPPduTypeData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectSNMPPduTypeMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - SCEnter(); - - const DetectSNMPPduTypeData *dd = (const DetectSNMPPduTypeData *)ctx; - uint32_t pdu_type; - rs_snmp_tx_get_pdu_type(txv, &pdu_type); - SCLogDebug("pdu_type %u ref_pdu_type %d", - pdu_type, dd->pdu_type); - if (pdu_type == dd->pdu_type) - SCReturnInt(1); - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to parse options passed via snmp.pdu_type keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectSNMPPduTypeData on success. - * \retval NULL on failure. - */ -static DetectSNMPPduTypeData *DetectSNMPPduTypeParse (const char *rawstr) -{ - DetectSNMPPduTypeData *dd = NULL; - int res = 0; - size_t pcre2len; - char value1[20] = ""; - char *endptr = NULL; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret != 2) { - SCLogError("Parse error %s", rawstr); - goto error; - } - - pcre2len = sizeof(value1); - res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)value1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - dd = SCCalloc(1, sizeof(DetectSNMPPduTypeData)); - if (unlikely(dd == NULL)) - goto error; - - /* set the value */ - dd->pdu_type = strtoul(value1, &endptr, 10); - if (endptr == NULL || *endptr != '\0') { - SCLogError("invalid character as arg " - "to snmp.pdu_type keyword"); - goto error; - } - - pcre2_match_data_free(match); - return dd; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (dd) - SCFree(dd); - return NULL; -} - -/** - * \brief Function to add the parsed snmp pdu_type field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectSNMPPduTypeSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - DetectSNMPPduTypeData *dd = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) - return -1; - - dd = DetectSNMPPduTypeParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - SCLogDebug("snmp.pdu_type %d", dd->pdu_type); - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SNMP_PDU_TYPE, (SigMatchCtx *)dd, - g_snmp_pdu_type_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectSNMPPduTypeFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectSNMPPduTypeData. - * - * \param de_ptr Pointer to DetectSNMPPduTypeData. - */ -static void DetectSNMPPduTypeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCFree(ptr); -} - -#ifdef UNITTESTS -#include "tests/detect-snmp-pdu_type.c" -#endif /* UNITTESTS */ diff --git a/src/detect-snmp-pdu_type.h b/src/detect-snmp-pdu_type.h deleted file mode 100644 index 5197885a588b..000000000000 --- a/src/detect-snmp-pdu_type.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2015-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#ifndef __DETECT_SNMP_PDU_TYPE_H__ -#define __DETECT_SNMP_PDU_TYPE_H__ - - -void DetectSNMPPduTypeRegister(void); - -#endif /* __DETECT_SNMP_PDU_TYPE_H__ */ diff --git a/src/detect-snmp-usm.c b/src/detect-snmp-usm.c deleted file mode 100644 index 2e03fca16b94..000000000000 --- a/src/detect-snmp-usm.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "rust.h" -#include "detect-snmp-usm.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-parse.h" - -static int g_buffer_id = 0; - -static int DetectSNMPUsmSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t data_len = 0; - const uint8_t *data = NULL; - - rs_snmp_tx_get_usm(txv, &data, &data_len); - if (data == NULL || data_len == 0) { - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -void DetectSNMPUsmRegister(void) -{ - sigmatch_table[DETECT_AL_SNMP_USM].name = "snmp.usm"; - sigmatch_table[DETECT_AL_SNMP_USM].desc = "SNMP content modifier to match on the SNMP usm"; - sigmatch_table[DETECT_AL_SNMP_USM].Setup = DetectSNMPUsmSetup; - - sigmatch_table[DETECT_AL_SNMP_USM].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - /* register inspect engines */ - DetectAppLayerInspectEngineRegister2("snmp.usm", ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - DetectAppLayerMpmRegister2("snmp.usm", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_SNMP, 0); - DetectAppLayerInspectEngineRegister2("snmp.usm", ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetData); - DetectAppLayerMpmRegister2("snmp.usm", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_SNMP, 0); - - DetectBufferTypeSetDescriptionByName("snmp.usm", "SNMP USM"); - - g_buffer_id = DetectBufferTypeGetByName("snmp.usm"); -} diff --git a/src/detect-snmp-version.c b/src/detect-snmp-version.c deleted file mode 100644 index 64029659381e..000000000000 --- a/src/detect-snmp-version.c +++ /dev/null @@ -1,174 +0,0 @@ -/* Copyright (C) 2015-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-snmp-version.h" -#include "detect-engine-uint.h" -#include "app-layer-parser.h" -#include "rust.h" - - -static int DetectSNMPVersionSetup (DetectEngineCtx *, Signature *s, const char *str); -static void DetectSNMPVersionFree(DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectSNMPVersionRegisterTests(void); -#endif -static int g_snmp_version_buffer_id = 0; - -static int DetectSNMPVersionMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); - -/** - * \brief Registration function for snmp.procedure keyword. - */ -void DetectSNMPVersionRegister (void) -{ - sigmatch_table[DETECT_AL_SNMP_VERSION].name = "snmp.version"; - sigmatch_table[DETECT_AL_SNMP_VERSION].desc = "match SNMP version"; - sigmatch_table[DETECT_AL_SNMP_VERSION].url = "/rules/snmp-keywords.html#snmp-version"; - sigmatch_table[DETECT_AL_SNMP_VERSION].Match = NULL; - sigmatch_table[DETECT_AL_SNMP_VERSION].AppLayerTxMatch = DetectSNMPVersionMatch; - sigmatch_table[DETECT_AL_SNMP_VERSION].Setup = DetectSNMPVersionSetup; - sigmatch_table[DETECT_AL_SNMP_VERSION].Free = DetectSNMPVersionFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_SNMP_VERSION].RegisterTests = DetectSNMPVersionRegisterTests; -#endif - - DetectAppLayerInspectEngineRegister2("snmp.version", ALPROTO_SNMP, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("snmp.version", ALPROTO_SNMP, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectGenericList, NULL); - - g_snmp_version_buffer_id = DetectBufferTypeGetByName("snmp.version"); -} - -/** - * \internal - * \brief Function to match version of a TX - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectSNMPVersionMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - SCEnter(); - - const DetectU32Data *dd = (const DetectU32Data *)ctx; - uint32_t version; - rs_snmp_tx_get_version(txv, &version); - SCLogDebug("version %u mode %u ref_version %d", version, dd->mode, dd->arg1); - if (DetectU32Match(version, dd)) - SCReturnInt(1); - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to parse options passed via snmp.version keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectU32Data on success. - * \retval NULL on failure. - */ -static DetectU32Data *DetectSNMPVersionParse(const char *rawstr) -{ - return DetectU32Parse(rawstr); -} - - - -/** - * \brief Function to add the parsed snmp version field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectSNMPVersionSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - DetectU32Data *dd = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0) - return -1; - - dd = DetectSNMPVersionParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - SCLogDebug("snmp.version %d", dd->arg1); - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SNMP_VERSION, (SigMatchCtx *)dd, - g_snmp_version_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectSNMPVersionFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -static void DetectSNMPVersionFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} - - -#ifdef UNITTESTS -#include "tests/detect-snmp-version.c" -#endif /* UNITTESTS */ diff --git a/src/detect-snmp-version.h b/src/detect-snmp-version.h deleted file mode 100644 index 3c8d5915d82e..000000000000 --- a/src/detect-snmp-version.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2015-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#ifndef __DETECT_SNMP_VERSION_H__ -#define __DETECT_SNMP_VERSION_H__ - - -void DetectSNMPVersionRegister(void); - -#endif /* __DETECT_SNMP_VERSION_H__ */ diff --git a/src/detect-ssh-hassh-server-string.c b/src/detect-ssh-hassh-server-string.c deleted file mode 100644 index 27b0e0cb7595..000000000000 --- a/src/detect-ssh-hassh-server-string.c +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Vadym Malakhatko - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" -#include "stream-tcp.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-hassh-server-string.h" -#include "rust.h" - - -#define KEYWORD_NAME "ssh.hassh.server.string" -#define KEYWORD_ALIAS "ssh-hassh-server-string" -#define KEYWORD_DOC "ssh-keywords.html#ssh.hassh.server.string" -#define BUFFER_NAME "ssh.hassh.server.string" -#define BUFFER_DESC "Ssh Client Key Exchange methods For ssh Servers" -static int g_ssh_hassh_server_string_buffer_id = 0; - - -static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - - if (buffer->inspect == NULL) { - const uint8_t *hassh = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_hassh_string(txv, &hassh, &b_len, flow_flags) != 1) - return NULL; - if (hassh == NULL || b_len == 0) { - SCLogDebug("SSH hassh string is not set"); - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, hassh, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief this function setup the ssh.hassh.server.string modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - * \retval -2 on failure that should be silent after the first - */ -static int DetectSshHasshServerStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_server_string_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) - return -1; - - /* try to enable Hassh */ - rs_ssh_enable_hassh(); - - /* Check if Hassh is disabled */ - if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH_SERVER_STRING)) { - SCLogError("hassh support is not enabled"); - } - return -2; - } - - return 0; - -} - -/** - * \brief Registration function for hasshServer.string keyword. - */ -void DetectSshHasshServerStringRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].alias = KEYWORD_ALIAS; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].Setup = DetectSshHasshServerStringSetup; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; - - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, - SIG_FLAG_TOCLIENT, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_ssh_hassh_server_string_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-ssh-hassh-server-string.h b/src/detect-ssh-hassh-server-string.h deleted file mode 100644 index 4c2adbb097de..000000000000 --- a/src/detect-ssh-hassh-server-string.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Malakhatko Vadym - */ - -#ifndef __DETECT_SSH_HASSH_SERVER_STRING_H__ -#define __DETECT_SSH_HASSH_SERVER_STRING_H__ - -/* prototypes */ -void DetectSshHasshServerStringRegister (void); - -#endif /* __DETECT_SSH_HASSH_SERVER_STRING_H__ */ diff --git a/src/detect-ssh-hassh-server.c b/src/detect-ssh-hassh-server.c deleted file mode 100644 index 295284108f10..000000000000 --- a/src/detect-ssh-hassh-server.c +++ /dev/null @@ -1,212 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Vadym Malakhatko - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-content.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" -#include "stream-tcp.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-hassh-server.h" -#include "rust.h" - - -#define KEYWORD_NAME "ssh.hassh.server" -#define KEYWORD_ALIAS "ssh-hassh-server" -#define KEYWORD_DOC "ssh-keywords.html#ssh.hassh.server" -#define BUFFER_NAME "ssh.hassh.server" -#define BUFFER_DESC "Ssh Client Fingerprinting For Ssh Servers" -static int g_ssh_hassh_buffer_id = 0; - - -static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - - if (buffer->inspect == NULL) { - const uint8_t *hasshServer = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_hassh(txv, &hasshServer, &b_len, flow_flags) != 1) - return NULL; - if (hasshServer == NULL || b_len == 0) { - SCLogDebug("SSH hassh not set"); - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, hasshServer, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief this function setup the ssh.hassh.server modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - * \retval -2 on failure that should be silent after the first - */ -static int DetectSshHasshServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) - return -1; - - /* try to enable Hassh */ - rs_ssh_enable_hassh(); - - /* Check if Hassh is disabled */ - if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH_SERVER)) { - SCLogError("hassh support is not enabled"); - } - return -2; - } - - return 0; - -} - -static bool DetectSshHasshServerHashValidateCallback(const Signature *s, const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - const DetectContentData *cd = (DetectContentData *)sm->ctx; - - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = "ssh.hassh.server should not be used together with " - "nocase, since the rule is automatically " - "lowercased anyway which makes nocase redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - } - - if (cd->content_len != 32) { - *sigerror = "Invalid length of the specified ssh.hassh.server (should " - "be 32 characters long). This rule will therefore " - "never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - for (size_t i = 0; i < cd->content_len; ++i) { - if (!isxdigit(cd->content[i])) { - *sigerror = "Invalid ssh.hassh.server string (should be string of hexadecimal " - "characters)." - "This rule will therefore never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - } - } - } - return true; -} - -static void DetectSshHasshServerHashSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) - continue; - SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) { - cd->content[u] = u8_tolower(cd->content[u]); - } - } - - SpmDestroyCtx(cd->spm_ctx); - cd->spm_ctx = - SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); - } - } -} - -/** - * \brief Registration function for hasshServer keyword. - */ -void DetectSshHasshServerRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].alias = KEYWORD_ALIAS; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].Setup = DetectSshHasshServerSetup; - sigmatch_table[DETECT_AL_SSH_HASSH_SERVER].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, - SIG_FLAG_TOCLIENT, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_ssh_hassh_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, DetectSshHasshServerHashSetupCallback); - DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectSshHasshServerHashValidateCallback); -} diff --git a/src/detect-ssh-hassh-server.h b/src/detect-ssh-hassh-server.h deleted file mode 100644 index 6be1055ae159..000000000000 --- a/src/detect-ssh-hassh-server.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Malakhatko Vadym - */ - -#ifndef __DETECT_SSH_HASSH_SERVER_H__ -#define __DETECT_SSH_HASSH_SERVER_H__ - -/* prototypes */ -void DetectSshHasshServerRegister (void); - -#endif /* __DETECT_SSH_HASSH_SERVER_H__ */ - diff --git a/src/detect-ssh-hassh-string.c b/src/detect-ssh-hassh-string.c deleted file mode 100644 index e639e64b134f..000000000000 --- a/src/detect-ssh-hassh-string.c +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Vadym Malakhatko - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "stream-tcp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-hassh-string.h" -#include "rust.h" - - -#define KEYWORD_NAME "ssh.hassh.string" -#define KEYWORD_ALIAS "ssh-hassh-string" -#define KEYWORD_DOC "ssh-keywords.html#hassh.string" -#define BUFFER_NAME "ssh.hassh.string" -#define BUFFER_DESC "Ssh Client Key Exchange methods For ssh Clients " -static int g_ssh_hassh_string_buffer_id = 0; - - -static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - - if (buffer->inspect == NULL) { - const uint8_t *hassh = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_hassh_string(txv, &hassh, &b_len, flow_flags) != 1) - return NULL; - if (hassh == NULL || b_len == 0) { - SCLogDebug("SSH hassh string is not set"); - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, hassh, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief this function setup the hassh.string modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - * \retval -2 on failure that should be silent after the first - */ -static int DetectSshHasshStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_string_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) - return -1; - - /* try to enable Hassh */ - rs_ssh_enable_hassh(); - - /* Check if Hassh is disabled */ - if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH_STRING)) { - SCLogError("hassh support is not enabled"); - } - return -2; - } - - return 0; - -} - -/** - * \brief Registration function for hassh.string keyword. - */ -void DetectSshHasshStringRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_HASSH_STRING].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SSH_HASSH_STRING].alias = KEYWORD_ALIAS; - sigmatch_table[DETECT_AL_SSH_HASSH_STRING].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_SSH_HASSH_STRING].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SSH_HASSH_STRING].Setup = DetectSshHasshStringSetup; - sigmatch_table[DETECT_AL_SSH_HASSH_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; - - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, - SIG_FLAG_TOSERVER, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_ssh_hassh_string_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-ssh-hassh-string.h b/src/detect-ssh-hassh-string.h deleted file mode 100644 index b3cebcd709c7..000000000000 --- a/src/detect-ssh-hassh-string.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Vadym Malakhatko - */ - -#ifndef __DETECT_SSH_HASSH_STRING_H__ -#define __DETECT_SSH_HASSH_STRING_H__ - -/* prototypes */ -void DetectSshHasshStringRegister (void); - -#endif /* __DETECT_SSH_HASSH_STRING_H__ */ diff --git a/src/detect-ssh-hassh.c b/src/detect-ssh-hassh.c deleted file mode 100644 index b410a5ffee84..000000000000 --- a/src/detect-ssh-hassh.c +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Vadym Malakhatko - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-content.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "stream-tcp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-hassh.h" -#include "rust.h" - - -#define KEYWORD_NAME "ssh.hassh" -#define KEYWORD_ALIAS "ssh-hassh" -#define KEYWORD_DOC "ssh-keywords.html#hassh" -#define BUFFER_NAME "ssh.hassh" -#define BUFFER_DESC "Ssh Client Fingerprinting For Ssh Clients " -static int g_ssh_hassh_buffer_id = 0; - - -static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - - if (buffer->inspect == NULL) { - const uint8_t *hassh = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_hassh(txv, &hassh, &b_len, flow_flags) != 1) - return NULL; - if (hassh == NULL || b_len == 0) { - SCLogDebug("SSH hassh not set"); - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, hassh, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -/** - * \brief this function setup the hassh modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - * \retval -2 on failure that should be silent after the first - */ -static int DetectSshHasshSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_ssh_hassh_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) - return -1; - - /* try to enable Hassh */ - rs_ssh_enable_hassh(); - - /* Check if Hassh is disabled */ - if (!RunmodeIsUnittests() && !rs_ssh_hassh_is_enabled()) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_SSH_HASSH)) { - SCLogError("hassh support is not enabled"); - } - return -2; - } - - return 0; - -} - - -static bool DetectSshHasshHashValidateCallback(const Signature *s, - const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - const DetectContentData *cd = (DetectContentData *)sm->ctx; - - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = "ssh.hassh should not be used together with " - "nocase, since the rule is automatically " - "lowercased anyway which makes nocase redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - } - - if (cd->content_len != 32) { - *sigerror = "Invalid length of the specified ssh.hassh (should " - "be 32 characters long). This rule will therefore " - "never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - for (size_t i = 0; i < cd->content_len; ++i) { - if (!isxdigit(cd->content[i])) { - *sigerror = - "Invalid ssh.hassh string (should be string of hexadecimal characters)." - "This rule will therefore never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - } - } - } - return true; -} - -static void DetectSshHasshHashSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_ssh_hassh_buffer_id) - continue; - SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) { - cd->content[u] = u8_tolower(cd->content[u]); - } - } - - SpmDestroyCtx(cd->spm_ctx); - cd->spm_ctx = - SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); - } - } -} - -/** - * \brief Registration function for hassh keyword. - */ -void DetectSshHasshRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_HASSH].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SSH_HASSH].alias = KEYWORD_ALIAS; - sigmatch_table[DETECT_AL_SSH_HASSH].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_SSH_HASSH].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SSH_HASSH].Setup = DetectSshHasshSetup; - sigmatch_table[DETECT_AL_SSH_HASSH].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; - - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone), - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_SSH, - SIG_FLAG_TOSERVER, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_ssh_hassh_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); - - DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, DetectSshHasshHashSetupCallback); - DetectBufferTypeRegisterValidateCallback(BUFFER_NAME, DetectSshHasshHashValidateCallback); -} - diff --git a/src/detect-ssh-hassh.h b/src/detect-ssh-hassh.h deleted file mode 100644 index 07eb091258c0..000000000000 --- a/src/detect-ssh-hassh.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Malakhatko Vadym - */ - -#ifndef __DETECT_SSH_HASSH_H__ -#define __DETECT_SSH_HASSH_H__ - -/* prototypes */ -void DetectSshHasshRegister (void); - -#endif /* __DETECT_SSH_HASSH_H__ */ diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c deleted file mode 100644 index 6a852f89ef13..000000000000 --- a/src/detect-ssh-proto-version.c +++ /dev/null @@ -1,572 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - * - * Implements the ssh.protoversion keyword - * You can specify a concrete version like ssh.protoversion: 1.66 - * or search for protoversion 2 compat (1.99 is considered as 2) like - * ssh.protoversion:2_compat - * or just the beginning of the string like ssh.protoversion:"1." - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-build.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-proto-version.h" -#include "rust.h" - -#include "stream-tcp.h" - -/** - * \brief Regex for parsing the protoversion string - */ -#define PARSE_REGEX "^\\s*\"?\\s*([0-9]+([\\.\\-0-9]+)?|2_compat)\\s*\"?\\s*$" - -static DetectParseRegex parse_regex; - -static int DetectSshVersionMatch (DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectSshVersionRegisterTests(void); -#endif -static void DetectSshVersionFree(DetectEngineCtx *, void *); -static int g_ssh_banner_list_id = 0; - -/** - * \brief Registration function for keyword: ssh.protoversion - */ -void DetectSshVersionRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion"; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].desc = "match SSH protocol version"; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].url = "/rules/ssh-keywords.html#ssh-protoversion"; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerTxMatch = DetectSshVersionMatch; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; -#endif - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_INFO_DEPRECATED; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].alternative = DETECT_AL_SSH_PROTOCOL; - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); -} - -/** - * \brief match the specified version on a ssh session - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectSshVersionData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectSshVersionMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - SCEnter(); - - SCLogDebug("lets see"); - - DetectSshVersionData *ssh = (DetectSshVersionData *)m; - if (state == NULL) { - SCLogDebug("no ssh state, no match"); - SCReturnInt(0); - } - - int ret = 0; - const uint8_t *protocol = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_protocol(txv, &protocol, &b_len, flags) != 1) - SCReturnInt(0); - if (protocol == NULL || b_len == 0) - SCReturnInt(0); - - if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) { - SCLogDebug("looking for ssh protoversion 2 compat"); - if (protocol[0] == '2') { - ret = 1; - } else if (b_len >= 4) { - if (memcmp(protocol, "1.99", 4) == 0) { - ret = 1; - } - } - } else { - SCLogDebug("looking for ssh protoversion %s length %"PRIu16"", ssh->ver, ssh->len); - if (b_len == ssh->len) { - if (memcmp(protocol, ssh->ver, ssh->len) == 0) { - ret = 1; - } - } - } - SCReturnInt(ret); -} - -/** - * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" - * - * \param de_ctx Pointer to the detection engine context - * \param idstr Pointer to the user provided id option - * - * \retval id_d pointer to DetectSshVersionData on success - * \retval NULL on failure - */ -static DetectSshVersionData *DetectSshVersionParse (DetectEngineCtx *de_ctx, const char *str) -{ - DetectSshVersionData *ssh = NULL; - int res = 0; - size_t pcre2_len; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); - if (ret < 1 || ret > 3) { - SCLogError("invalid ssh.protoversion option"); - goto error; - } - - if (ret > 1) { - const char *str_ptr; - res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); - if (res < 0) { - SCLogError("pcre2_substring_get_bynumber failed"); - goto error; - } - - /* We have a correct id option */ - ssh = SCCalloc(1, sizeof(DetectSshVersionData)); - if (unlikely(ssh == NULL)) { - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - goto error; - } - - /* If we expect a protocol version 2 or 1.99 (considered 2, we - * will compare it with both strings) */ - if (strcmp("2_compat", str_ptr) == 0) { - ssh->flags |= SSH_FLAG_PROTOVERSION_2_COMPAT; - SCLogDebug("will look for ssh protocol version 2 (2, 2.0, 1.99 that's considered as 2"); - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - return ssh; - } - - ssh->ver = (uint8_t *)SCStrdup((char*)str_ptr); - if (ssh->ver == NULL) { - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - goto error; - } - ssh->len = (uint16_t)strlen((char *)ssh->ver); - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - - SCLogDebug("will look for ssh %s", ssh->ver); - } - - pcre2_match_data_free(match); - return ssh; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (ssh != NULL) - DetectSshVersionFree(de_ctx, ssh); - return NULL; - -} - -/** - * \brief this function is used to add the parsed "id" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param idstr pointer to the user provided "id" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - DetectSshVersionData *ssh = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) - return -1; - - ssh = DetectSshVersionParse(de_ctx, str); - if (ssh == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSH_PROTOVERSION, (SigMatchCtx *)ssh, - g_ssh_banner_list_id) == NULL) { - goto error; - } - return 0; - -error: - if (ssh != NULL) - DetectSshVersionFree(de_ctx, ssh); - return -1; - -} - -/** - * \brief this function will free memory associated with DetectSshVersionData - * - * \param id_d pointer to DetectSshVersionData - */ -void DetectSshVersionFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectSshVersionData *sshd = (DetectSshVersionData *)ptr; - SCFree(sshd->ver); - SCFree(sshd); -} - -#ifdef UNITTESTS /* UNITTESTS */ -#include "detect-engine-alert.h" - -/** - * \test DetectSshVersionTestParse01 is a test to make sure that we parse - * a proto version correctly - */ -static int DetectSshVersionTestParse01 (void) -{ - DetectSshVersionData *ssh = NULL; - ssh = DetectSshVersionParse(NULL, "1.0"); - FAIL_IF_NULL(ssh); - FAIL_IF_NOT(strncmp((char *)ssh->ver, "1.0", 3) == 0); - DetectSshVersionFree(NULL, ssh); - - PASS; -} - -/** - * \test DetectSshVersionTestParse02 is a test to make sure that we parse - * the proto version (compatible with proto version 2) correctly - */ -static int DetectSshVersionTestParse02 (void) -{ - DetectSshVersionData *ssh = NULL; - ssh = DetectSshVersionParse(NULL, "2_compat"); - FAIL_IF_NOT(ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT); - DetectSshVersionFree(NULL, ssh); - - PASS; -} - -/** - * \test DetectSshVersionTestParse03 is a test to make sure that we - * don't return a ssh_data with an invalid value specified - */ -static int DetectSshVersionTestParse03 (void) -{ - DetectSshVersionData *ssh = NULL; - ssh = DetectSshVersionParse(NULL, "2_com"); - FAIL_IF_NOT_NULL(ssh); - ssh = DetectSshVersionParse(NULL, ""); - FAIL_IF_NOT_NULL(ssh); - ssh = DetectSshVersionParse(NULL, ".1"); - FAIL_IF_NOT_NULL(ssh); - ssh = DetectSshVersionParse(NULL, "lalala"); - FAIL_IF_NOT_NULL(ssh); - - PASS; -} - - -#include "stream-tcp-reassemble.h" -#include "stream-tcp-util.h" - -/** \test Send a get request in three chunks + more data. */ -static int DetectSshVersionTestDetect01(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-1."; - uint8_t sshbuf2[] = "10-PuTTY_2.123" ; - uint8_t sshbuf3[] = "\n"; - uint8_t sshbuf4[] = "whatever..."; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - FAIL_IF(unlikely(p == NULL)); - p->flow = f; - - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:1.10; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - FAIL_IF(PacketAlertCheck(p, 1)); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a get request in three chunks + more data. */ -static int DetectSshVersionTestDetect02(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-1.99-Pu"; - uint8_t sshbuf2[] = "TTY_2.123" ; - uint8_t sshbuf3[] = "\n"; - uint8_t sshbuf4[] = "whatever..."; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - FAIL_IF(unlikely(p == NULL)); - p->flow = f; - - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - FAIL_IF(PacketAlertCheck(p, 1)); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a get request in three chunks + more data. */ -static int DetectSshVersionTestDetect03(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-1."; - uint8_t sshbuf2[] = "7-PuTTY_2.123" ; - uint8_t sshbuf3[] = "\n"; - uint8_t sshbuf4[] = "whatever..."; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - FAIL_IF(unlikely(p == NULL)); - p->flow = f; - - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - FAIL_IF(PacketAlertCheck(p, 1)); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** - * \brief this function registers unit tests for DetectSshVersion - */ -static void DetectSshVersionRegisterTests(void) -{ - UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01); - UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02); - UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03); - UtRegisterTest("DetectSshVersionTestDetect01", - DetectSshVersionTestDetect01); - UtRegisterTest("DetectSshVersionTestDetect02", - DetectSshVersionTestDetect02); - UtRegisterTest("DetectSshVersionTestDetect03", - DetectSshVersionTestDetect03); -} -#endif /* UNITTESTS */ diff --git a/src/detect-ssh-proto-version.h b/src/detect-ssh-proto-version.h deleted file mode 100644 index a4c8eddbbe34..000000000000 --- a/src/detect-ssh-proto-version.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - */ - -#ifndef __DETECT_SSH_VERSION_H__ -#define __DETECT_SSH_VERSION_H__ - -/** proto version 1.99 is considered proto version 2 */ -#define SSH_FLAG_PROTOVERSION_2_COMPAT 0x01 - -typedef struct DetectSshVersionData_ { - uint8_t *ver; /** ssh version to match */ - uint16_t len; /** ssh version length to match */ - uint8_t flags; -} DetectSshVersionData; - -/* prototypes */ -void DetectSshVersionRegister (void); - -#endif /* __DETECT_SSH_VERSION_H__ */ - diff --git a/src/detect-ssh-proto.c b/src/detect-ssh-proto.c deleted file mode 100644 index a979190de1a9..000000000000 --- a/src/detect-ssh-proto.c +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup sshlayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support ssh_proto sticky buffer - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-proto.h" -#include "rust.h" - -#define KEYWORD_NAME "ssh.proto" -#define KEYWORD_NAME_LEGACY "ssh_proto" -#define KEYWORD_DOC "ssh-keywords.html#ssh-proto" -#define BUFFER_NAME "ssh.proto" -#define BUFFER_DESC "ssh protocol version field" -static int g_buffer_id = 0; - -static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - - if (buffer->inspect == NULL) { - const uint8_t *protocol = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_protocol(txv, &protocol, &b_len, flow_flags) != 1) - return NULL; - if (protocol == NULL || b_len == 0) { - SCLogDebug("SSH protocol not set"); - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, protocol, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static int DetectSshProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) - return -1; - - return 0; -} - -void DetectSshProtocolRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_PROTOCOL].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SSH_PROTOCOL].alias = KEYWORD_NAME_LEGACY; - sigmatch_table[DETECT_AL_SSH_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_SSH_PROTOCOL].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SSH_PROTOCOL].Setup = DetectSshProtocolSetup; - sigmatch_table[DETECT_AL_SSH_PROTOCOL].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; - - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone), - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone), - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SSH, SIG_FLAG_TOSERVER, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SSH, SIG_FLAG_TOCLIENT, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c deleted file mode 100644 index c2ba4ba888ef..000000000000 --- a/src/detect-ssh-software-version.c +++ /dev/null @@ -1,567 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - * - * Implements the ssh.softwareversion keyword - * You can match over the software version string of ssh, and it will - * be compared from the beginning of the string so you can say for - * example ssh.softwareversion:"PuTTY" and it can match, or you can - * also specify the version, something like - * ssh.softwareversion:"PuTTY-Release-0.55" - * I find this useful to match over a known vulnerable server/client - * software version in combination to other checks, so you can know - * that the risk is higher - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-build.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-software-version.h" -#include "rust.h" - -#include "stream-tcp.h" - -/** - * \brief Regex for parsing the softwareversion string - */ -#define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\:\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$" - -static DetectParseRegex parse_regex; - -static int DetectSshSoftwareVersionMatch (DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectSshSoftwareVersionRegisterTests(void); -#endif -static void DetectSshSoftwareVersionFree(DetectEngineCtx *de_ctx, void *); -static int g_ssh_banner_list_id = 0; - - -/** - * \brief Registration function for keyword: ssh.softwareversion - */ -void DetectSshSoftwareVersionRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion"; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].desc = "match SSH software string"; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].url = "/rules/ssh-keywords.html#ssh-softwareversion"; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerTxMatch = DetectSshSoftwareVersionMatch; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; -#endif - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].flags = SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_INFO_DEPRECATED; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].alternative = DETECT_AL_SSH_SOFTWARE; - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); - - DetectAppLayerInspectEngineRegister2("ssh_banner", ALPROTO_SSH, SIG_FLAG_TOSERVER, - SshStateBannerDone, DetectEngineInspectGenericList, NULL); - DetectAppLayerInspectEngineRegister2("ssh_banner", ALPROTO_SSH, SIG_FLAG_TOCLIENT, - SshStateBannerDone, DetectEngineInspectGenericList, NULL); -} - -/** - * \brief match the specified version on a ssh session - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectSshSoftwareVersionData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectSshSoftwareVersionMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - SCEnter(); - - DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m; - if (state == NULL) { - SCLogDebug("no ssh state, no match"); - SCReturnInt(0); - } - - int ret = 0; - const uint8_t *software = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_software(txv, &software, &b_len, flags) != 1) - SCReturnInt(0); - if (software == NULL || b_len == 0) - SCReturnInt(0); - if (b_len == ssh->len) { - if (memcmp(software, ssh->software_ver, ssh->len) == 0) { - ret = 1; - } - } - - SCReturnInt(ret); -} - -/** - * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" - * - * \param de_ctx Pointer to the detection engine context - * \param idstr Pointer to the user provided id option - * - * \retval id_d pointer to DetectSshSoftwareVersionData on success - * \retval NULL on failure - */ -static DetectSshSoftwareVersionData *DetectSshSoftwareVersionParse (DetectEngineCtx *de_ctx, const char *str) -{ - DetectSshSoftwareVersionData *ssh = NULL; - int res = 0; - size_t pcre2_len; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); - - if (ret < 1 || ret > 3) { - SCLogError("invalid ssh.softwareversion option"); - goto error; - } - - if (ret > 1) { - const char *str_ptr = NULL; - res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); - if (res < 0) { - SCLogError("pcre2_substring_get_bynumber failed"); - goto error; - } - - /* We have a correct id option */ - ssh = SCMalloc(sizeof(DetectSshSoftwareVersionData)); - if (unlikely(ssh == NULL)) { - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - goto error; - } - ssh->software_ver = (uint8_t *)SCStrdup((char *)str_ptr); - if (ssh->software_ver == NULL) { - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - goto error; - } - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - - ssh->len = (uint16_t)strlen((char *)ssh->software_ver); - - SCLogDebug("will look for ssh %s", ssh->software_ver); - } - - pcre2_match_data_free(match); - return ssh; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (ssh != NULL) - DetectSshSoftwareVersionFree(de_ctx, ssh); - return NULL; - -} - -/** - * \brief this function is used to add the parsed "id" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param idstr pointer to the user provided "id" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - DetectSshSoftwareVersionData *ssh = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) - return -1; - - ssh = DetectSshSoftwareVersionParse(NULL, str); - if (ssh == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSH_SOFTWAREVERSION, (SigMatchCtx *)ssh, - g_ssh_banner_list_id) == NULL) { - goto error; - } - return 0; - -error: - if (ssh != NULL) - DetectSshSoftwareVersionFree(de_ctx, ssh); - return -1; - -} - -/** - * \brief this function will free memory associated with DetectSshSoftwareVersionData - * - * \param id_d pointer to DetectSshSoftwareVersionData - */ -static void DetectSshSoftwareVersionFree(DetectEngineCtx *de_ctx, void *ptr) -{ - if (ptr == NULL) - return; - - DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)ptr; - if (ssh->software_ver != NULL) - SCFree(ssh->software_ver); - SCFree(ssh); -} - -#ifdef UNITTESTS /* UNITTESTS */ -#include "detect-engine-alert.h" - -/** - * \test DetectSshSoftwareVersionTestParse01 is a test to make sure that we parse - * a software version correctly - */ -static int DetectSshSoftwareVersionTestParse01 (void) -{ - DetectSshSoftwareVersionData *ssh = NULL; - ssh = DetectSshSoftwareVersionParse(NULL, "PuTTY_1.0"); - if (ssh != NULL && strncmp((char *) ssh->software_ver, "PuTTY_1.0", 9) == 0) { - DetectSshSoftwareVersionFree(NULL, ssh); - return 1; - } - - return 0; -} - -/** - * \test DetectSshSoftwareVersionTestParse02 is a test to make sure that we parse - * the software version correctly - */ -static int DetectSshSoftwareVersionTestParse02 (void) -{ - DetectSshSoftwareVersionData *ssh = NULL; - ssh = DetectSshSoftwareVersionParse(NULL, "\"SecureCRT-4.0\""); - if (ssh != NULL && strncmp((char *) ssh->software_ver, "SecureCRT-4.0", 13) == 0) { - DetectSshSoftwareVersionFree(NULL, ssh); - return 1; - } - - return 0; -} - -/** - * \test DetectSshSoftwareVersionTestParse03 is a test to make sure that we - * don't return a ssh_data with an empty value specified - */ -static int DetectSshSoftwareVersionTestParse03 (void) -{ - DetectSshSoftwareVersionData *ssh = NULL; - ssh = DetectSshSoftwareVersionParse(NULL, ""); - if (ssh != NULL) { - DetectSshSoftwareVersionFree(NULL, ssh); - return 0; - } - - return 1; -} - - -#include "stream-tcp-reassemble.h" -#include "stream-tcp-util.h" - -/** \test Send a get request in three chunks + more data. */ -static int DetectSshSoftwareVersionTestDetect01(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-1."; - uint8_t sshbuf2[] = "10-PuTTY_2.123" ; - uint8_t sshbuf3[] = "\n"; - uint8_t sshbuf4[] = "whatever..."; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - FAIL_IF(unlikely(p == NULL)); - p->flow = f; - - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - FAIL_IF(PacketAlertCheck(p, 1)); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a get request in three chunks + more data. */ -static int DetectSshSoftwareVersionTestDetect02(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-1.99-Pu"; - uint8_t sshbuf2[] = "TTY_2.123" ; - uint8_t sshbuf3[] = "\n"; - uint8_t sshbuf4[] = "whatever..."; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - FAIL_IF(unlikely(p == NULL)); - p->flow = f; - - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - FAIL_IF(PacketAlertCheck(p, 1)); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** \test Send a get request in three chunks + more data. */ -static int DetectSshSoftwareVersionTestDetect03(void) -{ - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - uint8_t sshbuf1[] = "SSH-1."; - uint8_t sshbuf2[] = "7-PuTTY_2.123" ; - uint8_t sshbuf3[] = "\n"; - uint8_t sshbuf4[] = "whatever..."; - - uint8_t* sshbufs[4] = {sshbuf1, sshbuf2, sshbuf3, sshbuf4}; - uint32_t sshlens[4] = {sizeof(sshbuf1) - 1, sizeof(sshbuf2) - 1, sizeof(sshbuf3) - 1, sizeof(sshbuf4) - 1}; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - StreamTcpUTSetupStream(&ssn.client, 1); - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1234, 2222); - FAIL_IF_NULL(f); - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - f->alproto = ALPROTO_SSH; - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - FAIL_IF(unlikely(p == NULL)); - p->flow = f; - - Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:lalala-3.1.4; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - uint32_t seq = 2; - for (int i=0; i<4; i++) { - FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, seq, sshbufs[i], sshlens[i]) == -1); - seq += sshlens[i]; - FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p, UPDATE_DIR_PACKET) < 0); - } - - void *ssh_state = f->alstate; - FAIL_IF_NULL(ssh_state); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - FAIL_IF(PacketAlertCheck(p, 1)); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - UTHFreeFlow(f); - PASS; -} - -/** - * \brief this function registers unit tests for DetectSshSoftwareVersion - */ -static void DetectSshSoftwareVersionRegisterTests(void) -{ - UtRegisterTest("DetectSshSoftwareVersionTestParse01", - DetectSshSoftwareVersionTestParse01); - UtRegisterTest("DetectSshSoftwareVersionTestParse02", - DetectSshSoftwareVersionTestParse02); - UtRegisterTest("DetectSshSoftwareVersionTestParse03", - DetectSshSoftwareVersionTestParse03); - UtRegisterTest("DetectSshSoftwareVersionTestDetect01", - DetectSshSoftwareVersionTestDetect01); - UtRegisterTest("DetectSshSoftwareVersionTestDetect02", - DetectSshSoftwareVersionTestDetect02); - UtRegisterTest("DetectSshSoftwareVersionTestDetect03", - DetectSshSoftwareVersionTestDetect03); -} -#endif /* UNITTESTS */ diff --git a/src/detect-ssh-software-version.h b/src/detect-ssh-software-version.h deleted file mode 100644 index 7cf311167731..000000000000 --- a/src/detect-ssh-software-version.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - */ - -#ifndef __DETECT_SSH_SOFTWARE_VERSION_H__ -#define __DETECT_SSH_SOFTWARE_VERSION_H__ - -typedef struct DetectSshSoftwareVersionData_ { - uint8_t *software_ver; /** ssh version to match */ - uint16_t len; /** ssh version length to match */ -} DetectSshSoftwareVersionData; - -/* prototypes */ -void DetectSshSoftwareVersionRegister(void); - -#endif /* __DETECT_SSH_SOFTWARE_VERSION_H__ */ - diff --git a/src/detect-ssh-software.c b/src/detect-ssh-software.c deleted file mode 100644 index cd11c5c20904..000000000000 --- a/src/detect-ssh-software.c +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup sshlayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - * - * Implements support ssh_software sticky buffer - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "detect-ssh-software.h" -#include "rust.h" - -#define KEYWORD_NAME "ssh.software" -#define KEYWORD_NAME_LEGACY "ssh_software" -#define KEYWORD_DOC "ssh-keywords.html#ssh-software" -#define BUFFER_NAME "ssh_software" -#define BUFFER_DESC "ssh software field" -static int g_buffer_id = 0; - -static InspectionBuffer *GetSshData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - - if (buffer->inspect == NULL) { - const uint8_t *software = NULL; - uint32_t b_len = 0; - - if (rs_ssh_tx_get_software(txv, &software, &b_len, flow_flags) != 1) - return NULL; - if (software == NULL || b_len == 0) { - SCLogDebug("SSH software version not set"); - return NULL; - } - - InspectionBufferSetup(det_ctx, list_id, buffer, software, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static int DetectSshSoftwareSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_SSH) < 0) - return -1; - - return 0; -} - - -void DetectSshSoftwareRegister(void) -{ - sigmatch_table[DETECT_AL_SSH_SOFTWARE].name = KEYWORD_NAME; - sigmatch_table[DETECT_AL_SSH_SOFTWARE].alias = KEYWORD_NAME_LEGACY; - sigmatch_table[DETECT_AL_SSH_SOFTWARE].desc = BUFFER_NAME " sticky buffer"; - sigmatch_table[DETECT_AL_SSH_SOFTWARE].url = "/rules/" KEYWORD_DOC; - sigmatch_table[DETECT_AL_SSH_SOFTWARE].Setup = DetectSshSoftwareSetup; - sigmatch_table[DETECT_AL_SSH_SOFTWARE].flags |= SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_NOOPT; - - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone), - DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetSshData, - ALPROTO_SSH, SshStateBannerDone), - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SSH, SIG_FLAG_TOSERVER, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, - ALPROTO_SSH, SIG_FLAG_TOCLIENT, SshStateBannerDone, - DetectEngineInspectBufferGeneric, GetSshData); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC); - - g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c deleted file mode 100644 index fd60f045a4c3..000000000000 --- a/src/detect-ssl-state.c +++ /dev/null @@ -1,341 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Implements support for ssl_state keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ssl-state.h" - -#include "stream-tcp.h" -#include "app-layer-ssl.h" - -#define PARSE_REGEX1 "^(!?)([_a-zA-Z0-9]+)(.*)$" -static DetectParseRegex parse_regex1; - -#define PARSE_REGEX2 "^(?:\\s*[|,]\\s*(!?)([_a-zA-Z0-9]+))(.*)$" -static DetectParseRegex parse_regex2; - -static int DetectSslStateMatch(DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectSslStateSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectSslStateRegisterTests(void); -#endif -static void DetectSslStateFree(DetectEngineCtx *, void *); - -static int g_tls_generic_list_id = 0; - -/** - * \brief Registers the keyword handlers for the "ssl_state" keyword. - */ -void DetectSslStateRegister(void) -{ - sigmatch_table[DETECT_AL_SSL_STATE].name = "ssl_state"; - sigmatch_table[DETECT_AL_SSL_STATE].desc = "match the state of the SSL connection"; - sigmatch_table[DETECT_AL_SSL_STATE].url = "/rules/tls-keywords.html#ssl-state"; - sigmatch_table[DETECT_AL_SSL_STATE].AppLayerTxMatch = DetectSslStateMatch; - sigmatch_table[DETECT_AL_SSL_STATE].Setup = DetectSslStateSetup; - sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests; -#endif - DetectSetupParseRegexes(PARSE_REGEX1, &parse_regex1); - DetectSetupParseRegexes(PARSE_REGEX2, &parse_regex2); - - g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); - - DetectBufferTypeSetDescriptionByName("tls_generic", - "generic ssl/tls inspection"); - - DetectAppLayerInspectEngineRegister2( - "tls_generic", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - DetectAppLayerInspectEngineRegister2( - "tls_generic", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); -} - -/** - * \brief App layer match function ssl_state keyword. - * - * \param tv Pointer to threadvars. - * \param det_ctx Pointer to the thread's detection context. - * \param f Pointer to the flow. - * \param flags Flags. - * \param state App layer state. - * \param s Sig we are currently inspecting. - * \param m SigMatch we are currently inspecting. - * - * \retval 1 Match. - * \retval 0 No match. - */ -static int DetectSslStateMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *alstate, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - const DetectSslStateData *ssd = (const DetectSslStateData *)m; - SSLState *ssl_state = (SSLState *)alstate; - if (ssl_state == NULL) { - SCLogDebug("no app state, no match"); - return 0; - } - - uint32_t ssl_flags = ssl_state->current_flags; - - if ((ssd->flags & ssl_flags) ^ ssd->mask) { - return 1; - } - - return 0; -} - -/** - * \brief Parse the arg supplied with ssl_state and return it in a - * DetectSslStateData instance. - * - * \param arg Pointer to the string to be parsed. - * - * \retval ssd Pointer to DetectSslStateData on success. - * \retval NULL On failure. - */ -static DetectSslStateData *DetectSslStateParse(const char *arg) -{ - size_t pcre2len; - char str1[64]; - char str2[64]; - int negate = 0; - uint32_t flags = 0, mask = 0; - DetectSslStateData *ssd = NULL; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex1, &match, arg, 0, 0); - if (ret < 1) { - SCLogError("Invalid arg \"%s\" supplied to " - "ssl_state keyword.", - arg); - goto error; - } - - pcre2len = sizeof(str1); - int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)str1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - negate = !strcmp("!", str1); - - pcre2len = sizeof(str1); - res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)str1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - if (strcmp("client_hello", str1) == 0) { - flags |= DETECT_SSL_STATE_CLIENT_HELLO; - if (negate) - mask |= DETECT_SSL_STATE_CLIENT_HELLO; - } else if (strcmp("server_hello", str1) == 0) { - flags |= DETECT_SSL_STATE_SERVER_HELLO; - if (negate) - mask |= DETECT_SSL_STATE_SERVER_HELLO; - } else if (strcmp("client_keyx", str1) == 0) { - flags |= DETECT_SSL_STATE_CLIENT_KEYX; - if (negate) - mask |= DETECT_SSL_STATE_CLIENT_KEYX; - } else if (strcmp("server_keyx", str1) == 0) { - flags |= DETECT_SSL_STATE_SERVER_KEYX; - if (negate) - mask |= DETECT_SSL_STATE_SERVER_KEYX; - } else if (strcmp("unknown", str1) == 0) { - flags |= DETECT_SSL_STATE_UNKNOWN; - if (negate) - mask |= DETECT_SSL_STATE_UNKNOWN; - } else { - SCLogError("Found invalid option \"%s\" " - "in ssl_state keyword.", - str1); - goto error; - } - - pcre2len = sizeof(str1); - res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)str1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - while (res >= 0 && strlen(str1) > 0) { - pcre2_match_data *match2 = NULL; - ret = DetectParsePcreExec(&parse_regex2, &match2, str1, 0, 0); - if (ret < 1) { - SCLogError("Invalid arg \"%s\" supplied to " - "ssl_state keyword.", - arg); - if (match2) { - pcre2_match_data_free(match2); - } - goto error; - } - - pcre2len = sizeof(str2); - res = pcre2_substring_copy_bynumber(match2, 1, (PCRE2_UCHAR8 *)str2, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match2); - goto error; - } - negate = !strcmp("!", str2); - - pcre2len = sizeof(str2); - res = pcre2_substring_copy_bynumber(match2, 2, (PCRE2_UCHAR8 *)str2, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match2); - goto error; - } - if (strcmp("client_hello", str2) == 0) { - flags |= DETECT_SSL_STATE_CLIENT_HELLO; - if (negate) - mask |= DETECT_SSL_STATE_CLIENT_HELLO; - } else if (strcmp("server_hello", str2) == 0) { - flags |= DETECT_SSL_STATE_SERVER_HELLO; - if (negate) - mask |= DETECT_SSL_STATE_SERVER_HELLO; - } else if (strcmp("client_keyx", str2) == 0) { - flags |= DETECT_SSL_STATE_CLIENT_KEYX; - if (negate) - mask |= DETECT_SSL_STATE_CLIENT_KEYX; - } else if (strcmp("server_keyx", str2) == 0) { - flags |= DETECT_SSL_STATE_SERVER_KEYX; - if (negate) - mask |= DETECT_SSL_STATE_SERVER_KEYX; - } else if (strcmp("unknown", str2) == 0) { - flags |= DETECT_SSL_STATE_UNKNOWN; - if (negate) - mask |= DETECT_SSL_STATE_UNKNOWN; - } else { - SCLogError("Found invalid option \"%s\" " - "in ssl_state keyword.", - str2); - pcre2_match_data_free(match2); - goto error; - } - - pcre2len = sizeof(str2); - res = pcre2_substring_copy_bynumber(match2, 3, (PCRE2_UCHAR8 *)str2, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match2); - goto error; - } - - memcpy(str1, str2, sizeof(str1)); - pcre2_match_data_free(match2); - } - - if ( (ssd = SCMalloc(sizeof(DetectSslStateData))) == NULL) { - goto error; - } - ssd->flags = flags; - ssd->mask = mask; - - pcre2_match_data_free(match); - return ssd; - -error: - if (match) { - pcre2_match_data_free(match); - } - return NULL; -} - - /** - * \internal - * \brief Setup function for ssl_state keyword. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature - * \param arg String holding the arg. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) -{ - DetectSslStateData *ssd = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - ssd = DetectSslStateParse(arg); - if (ssd == NULL) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSL_STATE, (SigMatchCtx *)ssd, - g_tls_generic_list_id) == NULL) { - goto error; - } - return 0; - -error: - if (ssd != NULL) - DetectSslStateFree(de_ctx, ssd); - return -1; -} - -/** - * \brief Free memory associated with DetectSslStateData. - * - * \param ptr pointer to the data to be freed. - */ -static void DetectSslStateFree(DetectEngineCtx *de_ctx, void *ptr) -{ - if (ptr != NULL) - SCFree(ptr); - - return; -} - -#ifdef UNITTESTS -#include "tests/detect-ssl-state.c" -#endif diff --git a/src/detect-ssl-state.h b/src/detect-ssl-state.h deleted file mode 100644 index 2196ae019de5..000000000000 --- a/src/detect-ssl-state.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef DETECT_SSL_STATE_H -#define DETECT_SSL_STATE_H - -/* we pick these flags from the parser */ -#define DETECT_SSL_STATE_CLIENT_HELLO SSL_AL_FLAG_STATE_CLIENT_HELLO -#define DETECT_SSL_STATE_SERVER_HELLO SSL_AL_FLAG_STATE_SERVER_HELLO -#define DETECT_SSL_STATE_CLIENT_KEYX SSL_AL_FLAG_STATE_CLIENT_KEYX -#define DETECT_SSL_STATE_SERVER_KEYX SSL_AL_FLAG_STATE_SERVER_KEYX -#define DETECT_SSL_STATE_UNKNOWN SSL_AL_FLAG_STATE_UNKNOWN - -typedef struct DetectSslStateData_ { - uint32_t flags; - uint32_t mask; -} DetectSslStateData; - -void DetectSslStateRegister(void); - -#endif /* DETECT_SSL_STATE_H */ diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c deleted file mode 100644 index 1326da49dd1c..000000000000 --- a/src/detect-ssl-version.c +++ /dev/null @@ -1,329 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file detect-ssl-version.c - * - * \author Gurvinder Singh - * - * Implements the ssl_version keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ssl-version.h" - -#include "stream-tcp.h" -#include "app-layer-ssl.h" - - -static int DetectSslVersionMatch(DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectSslVersionRegisterTests(void); -#endif -static void DetectSslVersionFree(DetectEngineCtx *, void *); -static int g_tls_generic_list_id = 0; - -/** - * \brief Registration function for keyword: ssl_version - */ -void DetectSslVersionRegister(void) -{ - sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version"; - sigmatch_table[DETECT_AL_SSL_VERSION].desc = "match version of SSL/TLS record"; - sigmatch_table[DETECT_AL_SSL_VERSION].url = "/rules/tls-keywords.html#ssl-version"; - sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch; - sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup; - sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; -#endif - - g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); -} - -/** - * \brief match the specified version on a ssl session - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectSslVersionData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectSslVersionMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - SCEnter(); - - int ret = 0; - uint16_t ver = 0; - uint8_t sig_ver = TLS_UNKNOWN; - - const DetectSslVersionData *ssl = (const DetectSslVersionData *)m; - SSLState *app_state = (SSLState *)state; - if (app_state == NULL) { - SCLogDebug("no app state, no match"); - SCReturnInt(0); - } - - if (flags & STREAM_TOCLIENT) { - SCLogDebug("server (toclient) version is 0x%02X", - app_state->server_connp.version); - ver = app_state->server_connp.version; - } else if (flags & STREAM_TOSERVER) { - SCLogDebug("client (toserver) version is 0x%02X", - app_state->client_connp.version); - ver = app_state->client_connp.version; - } - - switch (ver) { - case SSL_VERSION_2: - if (ver == ssl->data[SSLv2].ver) - ret = 1; - sig_ver = SSLv2; - break; - case SSL_VERSION_3: - if (ver == ssl->data[SSLv3].ver) - ret = 1; - sig_ver = SSLv3; - break; - case TLS_VERSION_10: - if (ver == ssl->data[TLS10].ver) - ret = 1; - sig_ver = TLS10; - break; - case TLS_VERSION_11: - if (ver == ssl->data[TLS11].ver) - ret = 1; - sig_ver = TLS11; - break; - case TLS_VERSION_12: - if (ver == ssl->data[TLS12].ver) - ret = 1; - sig_ver = TLS12; - break; - case TLS_VERSION_13_DRAFT28: - case TLS_VERSION_13_DRAFT27: - case TLS_VERSION_13_DRAFT26: - case TLS_VERSION_13_DRAFT25: - case TLS_VERSION_13_DRAFT24: - case TLS_VERSION_13_DRAFT23: - case TLS_VERSION_13_DRAFT22: - case TLS_VERSION_13_DRAFT21: - case TLS_VERSION_13_DRAFT20: - case TLS_VERSION_13_DRAFT19: - case TLS_VERSION_13_DRAFT18: - case TLS_VERSION_13_DRAFT17: - case TLS_VERSION_13_DRAFT16: - case TLS_VERSION_13_PRE_DRAFT16: - if (((ver >> 8) & 0xff) == 0x7f) - ver = TLS_VERSION_13; - /* fall through */ - case TLS_VERSION_13: - if (ver == ssl->data[TLS13].ver) - ret = 1; - sig_ver = TLS13; - break; - } - - if (sig_ver == TLS_UNKNOWN) - SCReturnInt(0); - - SCReturnInt(ret ^ ((ssl->data[sig_ver].flags & DETECT_SSL_VERSION_NEGATED) ? 1 : 0)); -} - -struct SSLVersionKeywords { - const char *word; - int index; - uint16_t value; -}; - -struct SSLVersionKeywords ssl_version_keywords[TLS_SIZE] = { - { "sslv2", SSLv2, SSL_VERSION_2 }, - { "sslv3", SSLv3, SSL_VERSION_3 }, - { "tls1.0", TLS10, TLS_VERSION_10 }, - { "tls1.1", TLS11, TLS_VERSION_11 }, - { "tls1.2", TLS12, TLS_VERSION_12 }, - { "tls1.3", TLS13, TLS_VERSION_13 }, -}; - -/** - * \brief This function is used to parse ssl_version data passed via - * keyword: "ssl_version" - * - * \param de_ctx Pointer to the detection engine context - * \param str Pointer to the user provided options - * - * \retval ssl pointer to DetectSslVersionData on success - * \retval NULL on failure - */ -static DetectSslVersionData *DetectSslVersionParse(DetectEngineCtx *de_ctx, const char *str) -{ - DetectSslVersionData *ssl = NULL; - const char *tmp_str = str; - size_t tmp_len = 0; - uint8_t found = 0; - - /* We have a correct ssl_version options */ - ssl = SCCalloc(1, sizeof(DetectSslVersionData)); - if (unlikely(ssl == NULL)) - goto error; - - // skip leading space - while (tmp_str[0] != 0 && isspace(tmp_str[0])) { - tmp_str++; - } - if (tmp_str[0] == 0) { - SCLogError("Invalid empty value"); - goto error; - } - // iterate every version separated by comma - while (tmp_str[0] != 0) { - uint8_t neg = 0; - if (tmp_str[0] == '!') { - neg = 1; - tmp_str++; - } - // counts word length - tmp_len = 0; - while (tmp_str[tmp_len] != 0 && !isspace(tmp_str[tmp_len]) && tmp_str[tmp_len] != ',') { - tmp_len++; - } - - bool is_keyword = false; - for (size_t i = 0; i < TLS_SIZE; i++) { - if (tmp_len == strlen(ssl_version_keywords[i].word) && - strncasecmp(ssl_version_keywords[i].word, tmp_str, tmp_len) == 0) { - if (ssl->data[ssl_version_keywords[i].index].ver != 0) { - SCLogError("Invalid duplicate value"); - goto error; - } - ssl->data[ssl_version_keywords[i].index].ver = ssl_version_keywords[i].value; - if (neg == 1) - ssl->data[ssl_version_keywords[i].index].flags |= DETECT_SSL_VERSION_NEGATED; - is_keyword = true; - break; - } - } - if (!is_keyword) { - SCLogError("Invalid unknown value"); - goto error; - } - - /* check consistency between negative and positive values : - * if there is a negative value, it overrides positive values - */ - if (found == 0) { - found |= 1 << neg; - } else if (found != 1 << neg) { - SCLogError("Invalid value mixing negative and positive forms"); - goto error; - } - - tmp_str += tmp_len; - while (isspace(tmp_str[0]) || tmp_str[0] == ',') { - tmp_str++; - } - } - - return ssl; - -error: - if (ssl != NULL) - DetectSslVersionFree(de_ctx, ssl); - return NULL; - -} - -/** - * \brief this function is used to add the parsed "id" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param idstr pointer to the user provided "id" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - DetectSslVersionData *ssl = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - ssl = DetectSslVersionParse(de_ctx, str); - if (ssl == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_SSL_VERSION, (SigMatchCtx *)ssl, - g_tls_generic_list_id) == NULL) { - goto error; - } - return 0; - -error: - if (ssl != NULL) - DetectSslVersionFree(de_ctx, ssl); - return -1; -} - -/** - * \brief this function will free memory associated with DetectSslVersionData - * - * \param id_d pointer to DetectSslVersionData - */ -void DetectSslVersionFree(DetectEngineCtx *de_ctx, void *ptr) -{ - if (ptr != NULL) - SCFree(ptr); -} - -#ifdef UNITTESTS -#include "tests/detect-ssl-version.c" -#endif diff --git a/src/detect-ssl-version.h b/src/detect-ssl-version.h deleted file mode 100644 index 6809178c5f0f..000000000000 --- a/src/detect-ssl-version.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file detect-ssl-version.h - * - * \author Gurvinder Singh - * - */ - -#ifndef DETECT_SSL_VERSION_H -#define DETECT_SSL_VERSION_H - -#define DETECT_SSL_VERSION_NEGATED 0x01 - -enum { - SSLv2 = 0, - SSLv3 = 1, - TLS10 = 2, - TLS11 = 3, - TLS12 = 4, - TLS13 = 5, - - TLS_SIZE = 6, - TLS_UNKNOWN = 7, -}; - -typedef struct SSLVersionData_ { - uint16_t ver; /** ssl version to match */ - uint8_t flags; -} SSLVersionData; - -typedef struct DetectSslVersionData_ { - SSLVersionData data[TLS_SIZE]; -} DetectSslVersionData; - -/* prototypes */ -void DetectSslVersionRegister (void); - -#endif /* DETECT_SSL_VERSION_H */ diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index 196439aa3131..874ed8c67940 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -25,7 +25,7 @@ #include "suricata-common.h" #include "stream-tcp.h" -#include "util-unittest.h" +#include "util/unittest.h" #include "detect.h" #include "detect-parse.h" @@ -35,14 +35,13 @@ #include "stream-tcp-private.h" #include "detect-engine-prefilter-common.h" #include "detect-engine-uint.h" -#include "util-debug.h" -#include "util-byte.h" - +#include "util/debug.h" +#include "util/byte.h" /*prototypes*/ -static int DetectStreamSizeMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectStreamSizeSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectStreamSizeMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectStreamSizeSetup(DetectEngineCtx *, Signature *, const char *); void DetectStreamSizeFree(DetectEngineCtx *de_ctx, void *); #ifdef UNITTESTS static void DetectStreamSizeRegisterTests(void); @@ -140,7 +139,7 @@ static int DetectStreamSizeMatch( * \retval 0 on Success * \retval -1 on Failure */ -static int DetectStreamSizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *streamstr) +static int DetectStreamSizeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *streamstr) { DetectStreamSizeData *sd = rs_detect_stream_size_parse(streamstr); if (sd == NULL) @@ -233,7 +232,7 @@ static bool PrefilterStreamSizeIsPrefilterable(const Signature *s) * user options correctly, when given valid stream_size options. */ -static int DetectStreamSizeParseTest01 (void) +static int DetectStreamSizeParseTest01(void) { int result = 0; DetectStreamSizeData *sd = NULL; @@ -252,7 +251,7 @@ static int DetectStreamSizeParseTest01 (void) * invalid stream_size options. */ -static int DetectStreamSizeParseTest02 (void) +static int DetectStreamSizeParseTest02(void) { int result = 1; DetectStreamSizeData *sd = NULL; @@ -271,7 +270,7 @@ static int DetectStreamSizeParseTest02 (void) * packet correctly provided valid stream size. */ -static int DetectStreamSizeParseTest03 (void) +static int DetectStreamSizeParseTest03(void) { int result = 0; @@ -331,7 +330,7 @@ static int DetectStreamSizeParseTest03 (void) f.protoctx = &ssn; p->flow = &f; p->tcph = &tcph; - sm.ctx = (SigMatchCtx*)sd; + sm.ctx = (SigMatchCtx *)sd; result = DetectStreamSizeMatch(&dtx, p, &s, sm.ctx); if (result == 0) { @@ -347,7 +346,7 @@ static int DetectStreamSizeParseTest03 (void) * stream_size against invalid packet parameters. */ -static int DetectStreamSizeParseTest04 (void) +static int DetectStreamSizeParseTest04(void) { int result = 0; @@ -380,11 +379,10 @@ static int DetectStreamSizeParseTest04 (void) SCFree(p); return 0; } - } else - { + } else { SCFree(p); return 0; - } + } client.next_seq = 20; client.isn = 12; @@ -392,7 +390,7 @@ static int DetectStreamSizeParseTest04 (void) f.protoctx = &ssn; p->flow = &f; p->ip4h = &ip4h; - sm.ctx = (SigMatchCtx*)sd; + sm.ctx = (SigMatchCtx *)sd; if (!DetectStreamSizeMatch(&dtx, p, &s, sm.ctx)) result = 1; diff --git a/src/detect-stream_size.h b/src/detect-stream_size.h index 3a460bf5e28b..8a12d4e671cb 100644 --- a/src/detect-stream_size.h +++ b/src/detect-stream_size.h @@ -22,9 +22,8 @@ */ #ifndef _DETECT_STREAM_SIZE_H -#define _DETECT_STREAM_SIZE_H +#define _DETECT_STREAM_SIZE_H void DetectStreamSizeRegister(void); -#endif /* _DETECT_STREAM_SIZE_H */ - +#endif /* _DETECT_STREAM_SIZE_H */ diff --git a/src/detect-tag.c b/src/detect-tag.c index bab756b3b601..49e4af9a0d55 100644 --- a/src/detect-tag.c +++ b/src/detect-tag.c @@ -41,22 +41,24 @@ #include "flow-util.h" #include "stream-tcp-private.h" -#include "util-time.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/time.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" #include "threads.h" SC_ATOMIC_EXTERN(unsigned int, num_tags); /* format: tag: , , , [direction]; */ -#define PARSE_REGEX "^\\s*(host|session)\\s*(,\\s*(\\d+)\\s*,\\s*(packets|bytes|seconds)\\s*(,\\s*(src|dst))?\\s*)?$" +#define PARSE_REGEX \ + "^\\s*(host|session)\\s*(,\\s*(\\d+)\\s*,\\s*(packets|bytes|seconds)\\s*(,\\s*(src|dst))?\\s*" \ + ")?$" static DetectParseRegex parse_regex; -static int DetectTagMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectTagMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectTagSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTagRegisterTests(void); @@ -71,7 +73,7 @@ void DetectTagRegister(void) sigmatch_table[DETECT_TAG].name = "tag"; sigmatch_table[DETECT_TAG].Match = DetectTagMatch; sigmatch_table[DETECT_TAG].Setup = DetectTagSetup; - sigmatch_table[DETECT_TAG].Free = DetectTagDataFree; + sigmatch_table[DETECT_TAG].Free = DetectTagDataFree; #ifdef UNITTESTS sigmatch_table[DETECT_TAG].RegisterTests = DetectTagRegisterTests; #endif @@ -91,8 +93,8 @@ void DetectTagRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectTagMatch(DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectTagMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectTagData *td = (const DetectTagData *)ctx; DetectTagDataEntry tde; @@ -114,7 +116,7 @@ static int DetectTagMatch(DetectEngineThreadCtx *det_ctx, Packet *p, else if (td->direction == DETECT_TAG_DIR_DST) tde.flags |= TAG_ENTRY_FLAG_DIR_DST; - SCLogDebug("Tagging Host with sid %"PRIu32":%"PRIu32"", s->id, s->gid); + SCLogDebug("Tagging Host with sid %" PRIu32 ":%" PRIu32 "", s->id, s->gid); TagHashAddTag(&tde, p); break; case DETECT_TAG_TYPE_SESSION: @@ -127,8 +129,8 @@ static int DetectTagMatch(DetectEngineThreadCtx *det_ctx, Packet *p, tde.metric = td->metric; tde.count = td->count; - SCLogDebug("Adding to or updating flow; first_ts %u count %u", - tde.first_ts, tde.count); + SCLogDebug("Adding to or updating flow; first_ts %u count %u", tde.first_ts, + tde.count); TagFlowAdd(p, &tde); } else { SCLogDebug("No flow to append the session tag"); @@ -197,8 +199,7 @@ static DetectTagData *DetectTagParse(const char *tagstr) } /* count */ - if (StringParseUint32(&td.count, 10, strlen(str_ptr), - str_ptr) <= 0) { + if (StringParseUint32(&td.count, 10, strlen(str_ptr), str_ptr) <= 0) { SCLogError("Invalid argument for count. Must be a value in the range of 0 to %" PRIu32 " (%s)", UINT32_MAX, tagstr); @@ -326,7 +327,6 @@ static void DetectTagDataEntryFree(void *ptr) } } - /** * \brief this function will free all the entries of a list * DetectTagDataEntry @@ -341,7 +341,7 @@ void DetectTagDataListFree(void *ptr) while (entry != NULL) { DetectTagDataEntry *next_entry = entry->next; DetectTagDataEntryFree(entry); - (void) SC_ATOMIC_SUB(num_tags, 1); + (void)SC_ATOMIC_SUB(num_tags, 1); entry = next_entry; } } @@ -369,9 +369,8 @@ static int DetectTagTestParse01(void) int result = 0; DetectTagData *td = NULL; td = DetectTagParse("session, 123, packets"); - if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION - && td->count == 123 - && td->metric == DETECT_TAG_METRIC_PACKET) { + if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION && td->count == 123 && + td->metric == DETECT_TAG_METRIC_PACKET) { DetectTagDataFree(NULL, td); result = 1; } @@ -387,11 +386,9 @@ static int DetectTagTestParse02(void) int result = 0; DetectTagData *td = NULL; td = DetectTagParse("host, 200, bytes, src"); - if (td != NULL && td->type == DETECT_TAG_TYPE_HOST - && td->count == 200 - && td->metric == DETECT_TAG_METRIC_BYTES - && td->direction == DETECT_TAG_DIR_SRC) { - result = 1; + if (td != NULL && td->type == DETECT_TAG_TYPE_HOST && td->count == 200 && + td->metric == DETECT_TAG_METRIC_BYTES && td->direction == DETECT_TAG_DIR_SRC) { + result = 1; DetectTagDataFree(NULL, td); } @@ -406,11 +403,9 @@ static int DetectTagTestParse03(void) int result = 0; DetectTagData *td = NULL; td = DetectTagParse("host, 200, bytes, dst"); - if (td != NULL && td->type == DETECT_TAG_TYPE_HOST - && td->count == 200 - && td->metric == DETECT_TAG_METRIC_BYTES - && td->direction == DETECT_TAG_DIR_DST) { - result = 1; + if (td != NULL && td->type == DETECT_TAG_TYPE_HOST && td->count == 200 && + td->metric == DETECT_TAG_METRIC_BYTES && td->direction == DETECT_TAG_DIR_DST) { + result = 1; DetectTagDataFree(NULL, td); } @@ -425,10 +420,9 @@ static int DetectTagTestParse04(void) int result = 0; DetectTagData *td = NULL; td = DetectTagParse("session"); - if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION - && td->count == DETECT_TAG_MAX_PKTS - && td->metric == DETECT_TAG_METRIC_PACKET) { - result = 1; + if (td != NULL && td->type == DETECT_TAG_TYPE_SESSION && td->count == DETECT_TAG_MAX_PKTS && + td->metric == DETECT_TAG_METRIC_PACKET) { + result = 1; DetectTagDataFree(NULL, td); } @@ -443,11 +437,9 @@ static int DetectTagTestParse05(void) int result = 0; DetectTagData *td = NULL; td = DetectTagParse("host"); - if (td != NULL && td->type == DETECT_TAG_TYPE_HOST - && td->count == DETECT_TAG_MAX_PKTS - && td->metric == DETECT_TAG_METRIC_PACKET - && td->direction == DETECT_TAG_DIR_DST) { - result = 1; + if (td != NULL && td->type == DETECT_TAG_TYPE_HOST && td->count == DETECT_TAG_MAX_PKTS && + td->metric == DETECT_TAG_METRIC_PACKET && td->direction == DETECT_TAG_DIR_DST) { + result = 1; DetectTagDataFree(NULL, td); } diff --git a/src/detect-tag.h b/src/detect-tag.h index 0a03584b610c..8053e5a61d27 100644 --- a/src/detect-tag.h +++ b/src/detect-tag.h @@ -40,11 +40,7 @@ #define DETECT_TAG_MAX_PKTS 256 /* Type of tag: session or host */ -enum { - DETECT_TAG_TYPE_SESSION, - DETECT_TAG_TYPE_HOST, - DETECT_TAG_TYPE_MAX -}; +enum { DETECT_TAG_TYPE_SESSION, DETECT_TAG_TYPE_HOST, DETECT_TAG_TYPE_MAX }; enum { DETECT_TAG_DIR_SRC, @@ -59,44 +55,43 @@ enum { /** This will be the rule options/parameters */ typedef struct DetectTagData_ { - uint8_t type; /**< tag type */ - uint8_t direction; /**< host direction */ - uint32_t count; /**< count */ - uint8_t metric; /**< metric */ + uint8_t type; /**< tag type */ + uint8_t direction; /**< host direction */ + uint32_t count; /**< count */ + uint8_t metric; /**< metric */ } DetectTagData; /** This is the installed data at the session/global or host table */ typedef struct DetectTagDataEntry_ { - uint8_t flags:3; - uint8_t metric:5; + uint8_t flags : 3; + uint8_t metric : 5; uint8_t pad0; - uint16_t cnt_match; /**< number of times this tag was reset/updated */ + uint16_t cnt_match; /**< number of times this tag was reset/updated */ - uint32_t count; /**< count setting from rule */ - uint32_t sid; /**< sid originating the tag */ - uint32_t gid; /**< gid originating the tag */ + uint32_t count; /**< count setting from rule */ + uint32_t sid; /**< sid originating the tag */ + uint32_t gid; /**< gid originating the tag */ union { - uint32_t packets; /**< number of packets (metric packets) */ - uint32_t bytes; /**< number of bytes (metric bytes) */ + uint32_t packets; /**< number of packets (metric packets) */ + uint32_t bytes; /**< number of bytes (metric bytes) */ }; - uint32_t first_ts; /**< First time seen (for metric = seconds) */ - uint32_t last_ts; /**< Last time seen (to prune old sessions) */ + uint32_t first_ts; /**< First time seen (for metric = seconds) */ + uint32_t last_ts; /**< Last time seen (to prune old sessions) */ #if __WORDSIZE == 64 uint32_t pad1; #endif - struct DetectTagDataEntry_ *next; /**< Pointer to the next tag of this - * session/src_host/dst_host (if any from other rule) */ + struct DetectTagDataEntry_ *next; /**< Pointer to the next tag of this + * session/src_host/dst_host (if any from other rule) */ } DetectTagDataEntry; -#define TAG_ENTRY_FLAG_DIR_SRC 0x01 -#define TAG_ENTRY_FLAG_DIR_DST 0x02 -#define TAG_ENTRY_FLAG_SKIPPED_FIRST 0x04 +#define TAG_ENTRY_FLAG_DIR_SRC 0x01 +#define TAG_ENTRY_FLAG_DIR_DST 0x02 +#define TAG_ENTRY_FLAG_SKIPPED_FIRST 0x04 /* prototypes */ -struct DetectEngineCtx_ ; +struct DetectEngineCtx_; void DetectTagRegister(void); void DetectTagDataFree(struct DetectEngineCtx_ *, void *ptr); void DetectTagDataListFree(void *ptr); #endif /* __DETECT_TAG_H__ */ - diff --git a/src/detect-target.c b/src/detect-target.c index b34b6e0d7066..990b9c4af1ca 100644 --- a/src/detect-target.c +++ b/src/detect-target.c @@ -24,7 +24,7 @@ */ #include "suricata-common.h" -#include "util-unittest.h" +#include "util/unittest.h" #include "detect-parse.h" #include "detect-engine.h" @@ -34,27 +34,29 @@ /** * \brief Regex for parsing our keyword options */ -#define PARSE_REGEX "^\\s*(src_ip|dest_ip)\\s*$" +#define PARSE_REGEX "^\\s*(src_ip|dest_ip)\\s*$" static DetectParseRegex parse_regex; /* Prototypes of functions registered in DetectTargetRegister below */ -static int DetectTargetSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectTargetSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS -static void DetectTargetRegisterTests (void); +static void DetectTargetRegisterTests(void); #endif /** * \brief Registration function for target keyword * */ -void DetectTargetRegister(void) { +void DetectTargetRegister(void) +{ /* keyword name: this is how the keyword is used in a rule */ sigmatch_table[DETECT_TARGET].name = "target"; /* description: listed in "suricata --list-keywords=all" */ - sigmatch_table[DETECT_TARGET].desc = "indicate to output module which side is the target of the attack"; + sigmatch_table[DETECT_TARGET].desc = + "indicate to output module which side is the target of the attack"; /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */ - sigmatch_table[DETECT_TARGET].url = "/rules/meta.html#target"; + sigmatch_table[DETECT_TARGET].url = "/rules/meta.html#target"; /* match function is called when the signature is inspected on a packet */ sigmatch_table[DETECT_TARGET].Match = NULL; /* setup function is called during signature parsing, when the target @@ -152,7 +154,8 @@ static int DetectTargetSignatureTest01(void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (target: dest_ip; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (target: dest_ip; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -164,7 +167,6 @@ static int DetectTargetSignatureTest01(void) */ static void DetectTargetRegisterTests(void) { - UtRegisterTest("DetectTargetSignatureTest01", - DetectTargetSignatureTest01); + UtRegisterTest("DetectTargetSignatureTest01", DetectTargetSignatureTest01); } #endif /* UNITTESTS */ diff --git a/src/detect-tcp-ack.c b/src/detect-tcp-ack.c index b2e35ca813d2..5bf150a15d37 100644 --- a/src/detect-tcp-ack.c +++ b/src/detect-tcp-ack.c @@ -37,15 +37,15 @@ #include "detect-tcp-ack.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" /* prototypes */ static int DetectAckSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectAckMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectAckMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); #ifdef UNITTESTS static void DetectAckRegisterTests(void); #endif @@ -82,8 +82,8 @@ void DetectAckRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectAckMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectAckMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectAckData *data = (const DetectAckData *)ctx; @@ -131,7 +131,6 @@ static int DetectAckSetup(DetectEngineCtx *de_ctx, Signature *s, const char *opt if (data) SCFree(data); return -1; - } /** @@ -148,31 +147,27 @@ static void DetectAckFree(DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketAckMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketAckMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; if (!PrefilterPacketHeaderExtraMatch(ctx, p)) return; - if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && - (p->tcph != NULL) && (TCP_GET_ACK(p) == ctx->v1.u32[0])) - { + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && (p->tcph != NULL) && + (TCP_GET_ACK(p) == ctx->v1.u32[0])) { SCLogDebug("packet matches TCP ack %u", ctx->v1.u32[0]); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketAckSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketAckSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectAckData *a = smctx; v->u32[0] = a->ack; } -static bool -PrefilterPacketAckCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketAckCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectAckData *a = smctx; if (v.u32[0] == a->ack) @@ -182,16 +177,14 @@ PrefilterPacketAckCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupTcpAck(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ACK, - PrefilterPacketAckSet, - PrefilterPacketAckCompare, - PrefilterPacketAckMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ACK, PrefilterPacketAckSet, + PrefilterPacketAckCompare, PrefilterPacketAckMatch); } static bool PrefilterTcpAckIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_ACK: return true; @@ -236,38 +229,30 @@ static int DetectAckSigTest01(void) de_ctx->flags |= DE_QUIET; /* These three are crammed in here as there is no Parse */ - if (SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing ack\";ack:foo;sid:1;)") != NULL) - { + if (SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing ack\";ack:foo;sid:1;)") != NULL) { printf("invalid ack accepted: "); goto cleanup_engine; } - if (SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing ack\";ack:9999999999;sid:1;)") != NULL) - { + if (SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing ack\";ack:9999999999;sid:1;)") != NULL) { printf("overflowing ack accepted: "); goto cleanup_engine; } - if (SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing ack\";ack:-100;sid:1;)") != NULL) - { + if (SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing ack\";ack:-100;sid:1;)") != NULL) { printf("negative ack accepted: "); goto cleanup_engine; } - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing ack\";ack:41;sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing ack\";ack:41;sid:1;)"); if (de_ctx->sig_list == NULL) { goto cleanup_engine; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing ack\";ack:42;sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing ack\";ack:42;sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto cleanup_engine; } diff --git a/src/detect-tcp-ack.h b/src/detect-tcp-ack.h index e1bb7c710c77..24a23517bca0 100644 --- a/src/detect-tcp-ack.h +++ b/src/detect-tcp-ack.h @@ -28,7 +28,7 @@ * \brief ack data */ typedef struct DetectAckData_ { - uint32_t ack; /**< ack to match */ + uint32_t ack; /**< ack to match */ } DetectAckData; /** diff --git a/src/detect-tcp-flags.c b/src/detect-tcp-flags.c index 5809a5dce983..5c011d95cbd1 100644 --- a/src/detect-tcp-flags.c +++ b/src/detect-tcp-flags.c @@ -36,15 +36,16 @@ #include "decode-events.h" #include "detect-tcp-flags.h" -#include "util-unittest.h" +#include "util/unittest.h" -#include "util-debug.h" +#include "util/debug.h" /** * Regex (by Brian Rectanus) * flags: [!+*](SAPRFU120)[,SAPRFU12] */ -#define PARSE_REGEX "^\\s*(?:([\\+\\*!]))?\\s*([SAPRFU120CE\\+\\*!]+)(?:\\s*,\\s*([SAPRFU12CE]+))?\\s*$" +#define PARSE_REGEX \ + "^\\s*(?:([\\+\\*!]))?\\s*([SAPRFU120CE\\+\\*!]+)(?:\\s*,\\s*([SAPRFU12CE]+))?\\s*$" /** * Flags args[0] *(3) +(2) !(1) @@ -57,9 +58,9 @@ static DetectParseRegex parse_regex; -static int DetectFlagsMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectFlagsSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectFlagsMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectFlagsSetup(DetectEngineCtx *, Signature *, const char *); static void DetectFlagsFree(DetectEngineCtx *, void *); static bool PrefilterTcpFlagsIsPrefilterable(const Signature *s); @@ -72,7 +73,7 @@ static void FlagsRegisterTests(void); * \brief Registration function for flags: keyword */ -void DetectFlagsRegister (void) +void DetectFlagsRegister(void) { sigmatch_table[DETECT_FLAGS].name = "tcp.flags"; sigmatch_table[DETECT_FLAGS].alias = "flags"; @@ -80,7 +81,7 @@ void DetectFlagsRegister (void) sigmatch_table[DETECT_FLAGS].url = "/rules/header-keywords.html#tcp-flags"; sigmatch_table[DETECT_FLAGS].Match = DetectFlagsMatch; sigmatch_table[DETECT_FLAGS].Setup = DetectFlagsSetup; - sigmatch_table[DETECT_FLAGS].Free = DetectFlagsFree; + sigmatch_table[DETECT_FLAGS].Free = DetectFlagsFree; #ifdef UNITTESTS sigmatch_table[DETECT_FLAGS].RegisterTests = FlagsRegisterTests; #endif @@ -90,11 +91,11 @@ void DetectFlagsRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier, - const uint8_t dflags, const uint8_t iflags) +static inline int FlagsMatch( + const uint8_t pflags, const uint8_t modifier, const uint8_t dflags, const uint8_t iflags) { if (!dflags && pflags) { - if(modifier == MODIFIER_NOT) { + if (modifier == MODIFIER_NOT) { SCReturnInt(1); } @@ -123,7 +124,7 @@ static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier, SCReturnInt(0); default: - SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"", flags, dflags); + SCLogDebug("flags %" PRIu8 " and de->flags %" PRIu8 "", flags, dflags); if (flags == dflags) { SCReturnInt(1); } @@ -145,8 +146,8 @@ static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier, * \retval 0 no match * \retval 1 match */ -static int DetectFlagsMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectFlagsMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); @@ -169,7 +170,7 @@ static int DetectFlagsMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval de pointer to DetectFlagsData on success * \retval NULL on failure */ -static DetectFlagsData *DetectFlagsParse (const char *rawstr) +static DetectFlagsData *DetectFlagsParse(const char *rawstr) { SCEnter(); @@ -451,7 +452,7 @@ static DetectFlagsData *DetectFlagsParse (const char *rawstr) } pcre2_match_data_free(match); - SCLogDebug("found %"PRId32" ignore %"PRId32"", found, ignore); + SCLogDebug("found %" PRId32 " ignore %" PRId32 "", found, ignore); SCReturnPtr(de, "DetectFlagsData"); error: @@ -476,7 +477,7 @@ static DetectFlagsData *DetectFlagsParse (const char *rawstr) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +static int DetectFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectFlagsData *de = NULL; @@ -507,16 +508,16 @@ static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, const char * static void DetectFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) { DetectFlagsData *de = (DetectFlagsData *)de_ptr; - if(de) SCFree(de); + if (de) + SCFree(de); } int DetectFlagsSignatureNeedsSynPackets(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { - case DETECT_FLAGS: - { + case DETECT_FLAGS: { const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; if (!(fl->modifier == MODIFIER_NOT) && (fl->flags & TH_SYN)) { @@ -532,10 +533,9 @@ int DetectFlagsSignatureNeedsSynPackets(const Signature *s) int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { - case DETECT_FLAGS: - { + case DETECT_FLAGS: { const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; if (!(fl->modifier == MODIFIER_NOT) && (fl->flags == TH_SYN)) { @@ -548,8 +548,7 @@ int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s) return 0; } -static void -PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { SCReturn; @@ -560,15 +559,13 @@ PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void return; const uint8_t flags = p->tcph->th_flags; - if (FlagsMatch(flags, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) - { + if (FlagsMatch(flags, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) { SCLogDebug("packet matches TCP flags %02x", ctx->v1.u8[1]); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketFlagsSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketFlagsSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectFlagsData *a = smctx; v->u8[0] = a->modifier; @@ -577,30 +574,24 @@ PrefilterPacketFlagsSet(PrefilterPacketHeaderValue *v, void *smctx) SCLogDebug("v->u8[0] = %02x", v->u8[0]); } -static bool -PrefilterPacketFlagsCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketFlagsCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectFlagsData *a = smctx; - if (v.u8[0] == a->modifier && - v.u8[1] == a->flags && - v.u8[2] == a->ignored_flags) + if (v.u8[0] == a->modifier && v.u8[1] == a->flags && v.u8[2] == a->ignored_flags) return true; return false; } static int PrefilterSetupTcpFlags(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FLAGS, - PrefilterPacketFlagsSet, - PrefilterPacketFlagsCompare, - PrefilterPacketFlagsMatch); - + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_FLAGS, PrefilterPacketFlagsSet, + PrefilterPacketFlagsCompare, PrefilterPacketFlagsMatch); } static bool PrefilterTcpFlagsIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_FLAGS: return true; @@ -620,7 +611,7 @@ static bool PrefilterTcpFlagsIsPrefilterable(const Signature *s) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse01 (void) +static int FlagsTestParse01(void) { DetectFlagsData *de = DetectFlagsParse("S"); FAIL_IF_NULL(de); @@ -635,7 +626,7 @@ static int FlagsTestParse01 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse02 (void) +static int FlagsTestParse02(void) { DetectFlagsData *de = NULL; de = DetectFlagsParse("G"); @@ -653,7 +644,7 @@ static int FlagsTestParse02 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse03 (void) +static int FlagsTestParse03(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -671,11 +662,11 @@ static int FlagsTestParse03 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST; + p->tcph->th_flags = TH_ACK | TH_PUSH | TH_SYN | TH_RST; de = DetectFlagsParse("AP+"); - if (de == NULL || (de->flags != (TH_ACK|TH_PUSH)) ) + if (de == NULL || (de->flags != (TH_ACK | TH_PUSH))) goto error; sm = SigMatchAlloc(); @@ -687,16 +678,20 @@ static int FlagsTestParse03 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } @@ -707,7 +702,7 @@ static int FlagsTestParse03 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse04 (void) +static int FlagsTestParse04(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -741,17 +736,21 @@ static int FlagsTestParse04 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } /* Error expected. */ error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } @@ -762,7 +761,7 @@ static int FlagsTestParse04 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse05 (void) +static int FlagsTestParse05(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -780,11 +779,12 @@ static int FlagsTestParse05 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST; + p->tcph->th_flags = TH_ACK | TH_PUSH | TH_SYN | TH_RST; de = DetectFlagsParse("+AP,SR"); - if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK|TH_PUSH)) || (de->ignored_flags != (TH_SYN|TH_RST))) + if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK | TH_PUSH)) || + (de->ignored_flags != (TH_SYN | TH_RST))) goto error; sm = SigMatchAlloc(); @@ -796,17 +796,21 @@ static int FlagsTestParse05 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } /* Error expected. */ error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } @@ -817,7 +821,7 @@ static int FlagsTestParse05 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse06 (void) +static int FlagsTestParse06(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -835,11 +839,12 @@ static int FlagsTestParse06 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_ACK|TH_PUSH|TH_SYN|TH_RST; + p->tcph->th_flags = TH_ACK | TH_PUSH | TH_SYN | TH_RST; de = DetectFlagsParse("+AP,UR"); - if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK|TH_PUSH)) || ((0xff - de->ignored_flags) != (TH_URG|TH_RST))) + if (de == NULL || (de->modifier != MODIFIER_PLUS) || (de->flags != (TH_ACK | TH_PUSH)) || + ((0xff - de->ignored_flags) != (TH_URG | TH_RST))) goto error; sm = SigMatchAlloc(); @@ -851,16 +856,20 @@ static int FlagsTestParse06 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } @@ -871,7 +880,7 @@ static int FlagsTestParse06 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse07 (void) +static int FlagsTestParse07(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -889,11 +898,11 @@ static int FlagsTestParse07 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_SYN|TH_RST; + p->tcph->th_flags = TH_SYN | TH_RST; de = DetectFlagsParse("*AP"); - if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_PUSH))) + if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK | TH_PUSH))) goto error; sm = SigMatchAlloc(); @@ -905,17 +914,21 @@ static int FlagsTestParse07 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } /* Error expected. */ error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } @@ -926,7 +939,7 @@ static int FlagsTestParse07 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse08 (void) +static int FlagsTestParse08(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -944,11 +957,11 @@ static int FlagsTestParse08 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_SYN|TH_RST; + p->tcph->th_flags = TH_SYN | TH_RST; de = DetectFlagsParse("*SA"); - if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_SYN))) + if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK | TH_SYN))) goto error; sm = SigMatchAlloc(); @@ -960,16 +973,20 @@ static int FlagsTestParse08 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } @@ -980,7 +997,7 @@ static int FlagsTestParse08 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse09 (void) +static int FlagsTestParse09(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -998,11 +1015,11 @@ static int FlagsTestParse09 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_SYN|TH_RST; + p->tcph->th_flags = TH_SYN | TH_RST; de = DetectFlagsParse("!PA"); - if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK|TH_PUSH))) + if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK | TH_PUSH))) goto error; sm = SigMatchAlloc(); @@ -1014,16 +1031,20 @@ static int FlagsTestParse09 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } @@ -1034,7 +1055,7 @@ static int FlagsTestParse09 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse10 (void) +static int FlagsTestParse10(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1052,11 +1073,11 @@ static int FlagsTestParse10 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_SYN|TH_RST; + p->tcph->th_flags = TH_SYN | TH_RST; de = DetectFlagsParse("!AP"); - if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK|TH_PUSH))) + if (de == NULL || (de->modifier != MODIFIER_NOT) || (de->flags != (TH_ACK | TH_PUSH))) goto error; sm = SigMatchAlloc(); @@ -1068,16 +1089,20 @@ static int FlagsTestParse10 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } @@ -1088,7 +1113,7 @@ static int FlagsTestParse10 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse11 (void) +static int FlagsTestParse11(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1106,11 +1131,12 @@ static int FlagsTestParse11 (void) p->ip4h = &ipv4h; p->tcph = &tcph; - p->tcph->th_flags = TH_SYN|TH_RST|TH_URG; + p->tcph->th_flags = TH_SYN | TH_RST | TH_URG; de = DetectFlagsParse("*AP,SR"); - if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK|TH_PUSH)) || ((0xff - de->ignored_flags) != (TH_SYN|TH_RST))) + if (de == NULL || (de->modifier != MODIFIER_ANY) || (de->flags != (TH_ACK | TH_PUSH)) || + ((0xff - de->ignored_flags) != (TH_SYN | TH_RST))) goto error; sm = SigMatchAlloc(); @@ -1122,17 +1148,21 @@ static int FlagsTestParse11 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } /* Expected. */ error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } @@ -1143,7 +1173,7 @@ static int FlagsTestParse11 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse12 (void) +static int FlagsTestParse12(void) { Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1179,17 +1209,21 @@ static int FlagsTestParse12 (void) ret = DetectFlagsMatch(NULL, p, NULL, sm->ctx); - if(ret) { - if (de) SCFree(de); - if (sm) SCFree(sm); + if (ret) { + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 0; } /* Expected. */ error: - if (de) SCFree(de); - if (sm) SCFree(sm); + if (de) + SCFree(de); + if (sm) + SCFree(sm); SCFree(p); return 1; } @@ -1200,7 +1234,7 @@ static int FlagsTestParse12 (void) * \retval 1 on success * \retval 0 on failure */ -static int FlagsTestParse13 (void) +static int FlagsTestParse13(void) { DetectFlagsData *de = NULL; de = DetectFlagsParse("+S*"); @@ -1221,7 +1255,7 @@ static int FlagsTestParse13 (void) static int FlagsTestParse14(void) { DetectFlagsData *de = DetectFlagsParse("CE"); - if (de != NULL && (de->flags == (TH_CWR | TH_ECN)) ) { + if (de != NULL && (de->flags == (TH_CWR | TH_ECN))) { DetectFlagsFree(NULL, de); return 1; } @@ -1251,7 +1285,7 @@ static int FlagsTestParse15(void) de = DetectFlagsParse("EC+"); - if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) ) + if (de == NULL || (de->flags != (TH_ECN | TH_CWR))) goto error; sm = SigMatchAlloc(); @@ -1303,7 +1337,7 @@ static int FlagsTestParse16(void) de = DetectFlagsParse("EC*"); - if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) ) + if (de == NULL || (de->flags != (TH_ECN | TH_CWR))) goto error; sm = SigMatchAlloc(); @@ -1358,7 +1392,7 @@ static int FlagsTestParse17(void) de = DetectFlagsParse("EC+"); - if (de == NULL || (de->flags != (TH_ECN | TH_CWR)) ) + if (de == NULL || (de->flags != (TH_ECN | TH_CWR))) goto error; sm = SigMatchAlloc(); diff --git a/src/detect-tcp-flags.h b/src/detect-tcp-flags.h index e5920b9c5555..585244d4d184 100644 --- a/src/detect-tcp-flags.h +++ b/src/detect-tcp-flags.h @@ -24,7 +24,6 @@ #ifndef __DETECT_FLAGS_H__ #define __DETECT_FLAGS_H__ - /** * \struct DetectFlagsData_ * DetectFlagsData_ is used to store flags: input value @@ -36,8 +35,8 @@ */ typedef struct DetectFlagsData_ { - uint8_t flags; /**< TCP flags */ - uint8_t modifier; /**< !(1) +(2) *(3) modifiers */ + uint8_t flags; /**< TCP flags */ + uint8_t modifier; /**< !(1) +(2) *(3) modifiers */ uint8_t ignored_flags; /**< Ignored TCP flags defined by modifier , */ } DetectFlagsData; @@ -45,7 +44,7 @@ typedef struct DetectFlagsData_ { * Registration function for flags: keyword */ -void DetectFlagsRegister (void); +void DetectFlagsRegister(void); int DetectFlagsSignatureNeedsSynPackets(const Signature *s); int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s); diff --git a/src/detect-tcp-seq.c b/src/detect-tcp-seq.c index 0a34f5633de9..09086563ea4d 100644 --- a/src/detect-tcp-seq.c +++ b/src/detect-tcp-seq.c @@ -35,14 +35,14 @@ #include "detect-tcp-seq.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/debug.h" static int DetectSeqSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectSeqMatch(DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); +static int DetectSeqMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); #ifdef UNITTESTS static void DetectSeqRegisterTests(void); #endif @@ -78,8 +78,8 @@ void DetectSeqRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectSeqMatch(DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectSeqMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectSeqData *data = (const DetectSeqData *)ctx; @@ -102,7 +102,7 @@ static int DetectSeqMatch(DetectEngineThreadCtx *det_ctx, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char *optstr) +static int DetectSeqSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr) { DetectSeqData *data = NULL; @@ -126,7 +126,6 @@ static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, const char *op if (data) SCFree(data); return -1; - } /** @@ -143,31 +142,27 @@ static void DetectSeqFree(DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { const PrefilterPacketHeaderCtx *ctx = pectx; if (!PrefilterPacketHeaderExtraMatch(ctx, p)) return; - if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && - (p->tcph != NULL) && (TCP_GET_SEQ(p) == ctx->v1.u32[0])) - { + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && (p->tcph != NULL) && + (TCP_GET_SEQ(p) == ctx->v1.u32[0])) { SCLogDebug("packet matches TCP seq %u", ctx->v1.u32[0]); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } } -static void -PrefilterPacketSeqSet(PrefilterPacketHeaderValue *v, void *smctx) +static void PrefilterPacketSeqSet(PrefilterPacketHeaderValue *v, void *smctx) { const DetectSeqData *a = smctx; v->u32[0] = a->seq; } -static bool -PrefilterPacketSeqCompare(PrefilterPacketHeaderValue v, void *smctx) +static bool PrefilterPacketSeqCompare(PrefilterPacketHeaderValue v, void *smctx) { const DetectSeqData *a = smctx; if (v.u32[0] == a->seq) @@ -177,16 +172,14 @@ PrefilterPacketSeqCompare(PrefilterPacketHeaderValue v, void *smctx) static int PrefilterSetupTcpSeq(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_SEQ, - PrefilterPacketSeqSet, - PrefilterPacketSeqCompare, - PrefilterPacketSeqMatch); + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_SEQ, PrefilterPacketSeqSet, + PrefilterPacketSeqCompare, PrefilterPacketSeqMatch); } static bool PrefilterTcpSeqIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_SEQ: return true; @@ -195,7 +188,6 @@ static bool PrefilterTcpSeqIsPrefilterable(const Signature *s) return false; } - #ifdef UNITTESTS /** @@ -209,24 +201,18 @@ static int DetectSeqSigTest01(void) goto end; /* These three are crammed in here as there is no Parse */ - if (SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing seq\";seq:foo;sid:1;)") != NULL) - { + if (SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing seq\";seq:foo;sid:1;)") != NULL) { printf("invalid seq accepted: "); goto cleanup; } - if (SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing seq\";seq:9999999999;sid:1;)") != NULL) - { + if (SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing seq\";seq:9999999999;sid:1;)") != NULL) { printf("overflowing seq accepted: "); goto cleanup; } - if (SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing seq\";seq:-100;sid:1;)") != NULL) - { + if (SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing seq\";seq:-100;sid:1;)") != NULL) { printf("negative seq accepted: "); goto cleanup; } @@ -254,7 +240,7 @@ static int DetectSeqSigTest02(void) p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); - if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) + if (p[0] == NULL || p[1] == NULL || p[2] == NULL) goto end; /* TCP w/seq=42 */ @@ -264,20 +250,20 @@ static int DetectSeqSigTest02(void) p[1]->tcph->th_seq = htonl(100); const char *sigs[2]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:41; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:42; sid:2;)"; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing seq\"; seq:41; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing seq\"; seq:42; sid:2;)"; - uint32_t sid[2] = {1, 2}; + uint32_t sid[2] = { 1, 2 }; - uint32_t results[3][2] = { - /* packet 0 match sid 1 but should not match sid 2 */ - {0, 1}, - /* packet 1 should not match */ - {0, 0}, - /* packet 2 should not match */ - {0, 0} }; + uint32_t results[3][2] = { /* packet 0 match sid 1 but should not match sid 2 */ + { 0, 1 }, + /* packet 1 should not match */ + { 0, 0 }, + /* packet 2 should not match */ + { 0, 0 } + }; - result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2); + result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *)results, 2); UTHFreePackets(p, 3); end: return result; diff --git a/src/detect-tcp-seq.h b/src/detect-tcp-seq.h index 688b6c2c39da..2f52f157e3b3 100644 --- a/src/detect-tcp-seq.h +++ b/src/detect-tcp-seq.h @@ -28,7 +28,7 @@ * \brief seq data */ typedef struct DetectSeqData_ { - uint32_t seq; /**< seq to match */ + uint32_t seq; /**< seq to match */ } DetectSeqData; /** diff --git a/src/detect-tcp-window.c b/src/detect-tcp-window.c index c0a7bb7e1b05..24f56c210803 100644 --- a/src/detect-tcp-window.c +++ b/src/detect-tcp-window.c @@ -33,20 +33,20 @@ #include "flow.h" #include "flow-var.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" /** * \brief Regex for parsing our window option */ -#define PARSE_REGEX "^\\s*([!])?\\s*([0-9]{1,9}+)\\s*$" +#define PARSE_REGEX "^\\s*([!])?\\s*([0-9]{1,9}+)\\s*$" static DetectParseRegex parse_regex; -static int DetectWindowMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectWindowMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectWindowSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectWindowRegisterTests(void); @@ -56,7 +56,7 @@ void DetectWindowFree(DetectEngineCtx *, void *); /** * \brief Registration function for window: keyword */ -void DetectWindowRegister (void) +void DetectWindowRegister(void) { sigmatch_table[DETECT_WINDOW].name = "tcp.window"; sigmatch_table[DETECT_WINDOW].alias = "window"; @@ -64,7 +64,7 @@ void DetectWindowRegister (void) sigmatch_table[DETECT_WINDOW].url = "/rules/header-keywords.html#window"; sigmatch_table[DETECT_WINDOW].Match = DetectWindowMatch; sigmatch_table[DETECT_WINDOW].Setup = DetectWindowSetup; - sigmatch_table[DETECT_WINDOW].Free = DetectWindowFree; + sigmatch_table[DETECT_WINDOW].Free = DetectWindowFree; #ifdef UNITTESTS sigmatch_table[DETECT_WINDOW].RegisterTests = DetectWindowRegisterTests; #endif @@ -82,16 +82,17 @@ void DetectWindowRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectWindowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectWindowMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectWindowData *wd = (const DetectWindowData *)ctx; - if ( !(PKT_IS_TCP(p)) || wd == NULL || PKT_IS_PSEUDOPKT(p)) { + if (!(PKT_IS_TCP(p)) || wd == NULL || PKT_IS_PSEUDOPKT(p)) { return 0; } - if ( (!wd->negated && wd->size == TCP_GET_WINDOW(p)) || (wd->negated && wd->size != TCP_GET_WINDOW(p))) { + if ((!wd->negated && wd->size == TCP_GET_WINDOW(p)) || + (wd->negated && wd->size != TCP_GET_WINDOW(p))) { return 1; } @@ -165,7 +166,6 @@ static DetectWindowData *DetectWindowParse(DetectEngineCtx *de_ctx, const char * if (wd != NULL) DetectWindowFree(de_ctx, wd); return NULL; - } /** @@ -178,12 +178,13 @@ static DetectWindowData *DetectWindowParse(DetectEngineCtx *de_ctx, const char * * \retval 0 on Success * \retval -1 on Failure */ -static int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *windowstr) +static int DetectWindowSetup(DetectEngineCtx *de_ctx, Signature *s, const char *windowstr) { DetectWindowData *wd = NULL; wd = DetectWindowParse(de_ctx, windowstr); - if (wd == NULL) goto error; + if (wd == NULL) + goto error; /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ @@ -200,7 +201,6 @@ static int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, const char if (wd != NULL) DetectWindowFree(de_ctx, wd); return -1; - } /** @@ -220,7 +220,7 @@ void DetectWindowFree(DetectEngineCtx *de_ctx, void *ptr) * \test DetectWindowTestParse01 is a test to make sure that we set the size correctly * when given valid window opt */ -static int DetectWindowTestParse01 (void) +static int DetectWindowTestParse01(void) { DetectWindowData *wd = NULL; wd = DetectWindowParse(NULL, "35402"); @@ -234,7 +234,7 @@ static int DetectWindowTestParse01 (void) /** * \test DetectWindowTestParse02 is a test for setting the window opt negated */ -static int DetectWindowTestParse02 (void) +static int DetectWindowTestParse02(void) { DetectWindowData *wd = NULL; wd = DetectWindowParse(NULL, "!35402"); @@ -249,7 +249,7 @@ static int DetectWindowTestParse02 (void) /** * \test DetectWindowTestParse03 is a test to check for an empty value */ -static int DetectWindowTestParse03 (void) +static int DetectWindowTestParse03(void) { DetectWindowData *wd = NULL; wd = DetectWindowParse(NULL, ""); @@ -262,7 +262,7 @@ static int DetectWindowTestParse03 (void) /** * \test DetectWindowTestParse03 is a test to check for a big value */ -static int DetectWindowTestParse04 (void) +static int DetectWindowTestParse04(void) { DetectWindowData *wd = NULL; wd = DetectWindowParse(NULL, "1235402"); @@ -275,7 +275,7 @@ static int DetectWindowTestParse04 (void) /** * \test DetectWindowTestPacket01 is a test to check window with constructed packets */ -static int DetectWindowTestPacket01 (void) +static int DetectWindowTestPacket01(void) { uint8_t *buf = (uint8_t *)"Hi all!"; uint16_t buflen = strlen((char *)buf); @@ -293,18 +293,18 @@ static int DetectWindowTestPacket01 (void) p[1]->tcph->th_win = htons(41); const char *sigs[2]; - sigs[0]= "alert tcp any any -> any any (msg:\"Testing window 1\"; window:40; sid:1;)"; - sigs[1]= "alert tcp any any -> any any (msg:\"Testing window 2\"; window:41; sid:2;)"; - - uint32_t sid[2] = {1, 2}; - - uint32_t results[3][2] = { - /* packet 0 match sid 1 but should not match sid 2 */ - {1, 0}, - /* packet 1 should not match */ - {0, 1}, - /* packet 2 should not match */ - {0, 0} }; + sigs[0] = "alert tcp any any -> any any (msg:\"Testing window 1\"; window:40; sid:1;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Testing window 2\"; window:41; sid:2;)"; + + uint32_t sid[2] = { 1, 2 }; + + uint32_t results[3][2] = { /* packet 0 match sid 1 but should not match sid 2 */ + { 1, 0 }, + /* packet 1 should not match */ + { 0, 1 }, + /* packet 2 should not match */ + { 0, 0 } + }; FAIL_IF(UTHGenericTest(p, 3, sigs, sid, (uint32_t *)results, 2) == 0); UTHFreePackets(p, 3); diff --git a/src/detect-tcp-window.h b/src/detect-tcp-window.h index 51f85398dbe5..a418a25ae37b 100644 --- a/src/detect-tcp-window.h +++ b/src/detect-tcp-window.h @@ -19,11 +19,11 @@ #define __DETECT_WINDOW_H__ typedef struct DetectWindowData_ { - uint8_t negated; /** negated? 1=True : 0=False */ - uint16_t size; /** window size to match */ + uint8_t negated; /** negated? 1=True : 0=False */ + uint16_t size; /** window size to match */ } DetectWindowData; /* prototypes */ -void DetectWindowRegister (void); +void DetectWindowRegister(void); #endif /* __DETECT_WINDOW_H__ */ diff --git a/src/detect-tcphdr.c b/src/detect-tcphdr.c index f054e3550970..bcc4d51251d0 100644 --- a/src/detect-tcphdr.c +++ b/src/detect-tcphdr.c @@ -34,9 +34,9 @@ #include "detect-tcphdr.h" /* prototypes */ -static int DetectTcphdrSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectTcphdrSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS -void DetectTcphdrRegisterTests (void); +void DetectTcphdrRegisterTests(void); #endif static int g_tcphdr_buffer_id = 0; @@ -65,8 +65,7 @@ void DetectTcphdrRegister(void) DetectPktMpmRegister("tcp.hdr", 2, PrefilterGenericMpmPktRegister, GetData); - DetectPktInspectEngineRegister("tcp.hdr", GetData, - DetectEngineInspectPktBufferGeneric); + DetectPktInspectEngineRegister("tcp.hdr", GetData, DetectEngineInspectPktBufferGeneric); return; } @@ -81,7 +80,7 @@ void DetectTcphdrRegister(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectTcphdrSetup (DetectEngineCtx *de_ctx, Signature *s, const char *_unused) +static int DetectTcphdrSetup(DetectEngineCtx *de_ctx, Signature *s, const char *_unused) { if (!(DetectProtoContainsProto(&s->proto, IPPROTO_TCP))) return -1; @@ -108,10 +107,8 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, } uint32_t hlen = TCP_GET_HLEN(p); if (((uint8_t *)p->tcph + (ptrdiff_t)hlen) > - ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) - { - SCLogDebug("data out of range: %p > %p", - ((uint8_t *)p->tcph + (ptrdiff_t)hlen), + ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) { + SCLogDebug("data out of range: %p > %p", ((uint8_t *)p->tcph + (ptrdiff_t)hlen), ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))); return NULL; } diff --git a/src/detect-tcphdr.h b/src/detect-tcphdr.h index 2f83f1734b09..147f397fe8d6 100644 --- a/src/detect-tcphdr.h +++ b/src/detect-tcphdr.h @@ -26,4 +26,4 @@ void DetectTcphdrRegister(void); -#endif /* _DETECT_TCPHDR_H */ +#endif /* _DETECT_TCPHDR_H */ diff --git a/src/detect-tcpmss.c b/src/detect-tcpmss.c index c04a9be09ecc..1ac26e15e7ec 100644 --- a/src/detect-tcpmss.c +++ b/src/detect-tcpmss.c @@ -28,18 +28,17 @@ #include "detect-parse.h" #include "detect-engine-prefilter-common.h" #include "detect-engine-uint.h" -#include "util-byte.h" +#include "util/byte.h" #include "detect-tcpmss.h" - /* prototypes */ -static int DetectTcpmssMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectTcpmssSetup (DetectEngineCtx *, Signature *, const char *); -void DetectTcpmssFree (DetectEngineCtx *, void *); +static int DetectTcpmssMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectTcpmssSetup(DetectEngineCtx *, Signature *, const char *); +void DetectTcpmssFree(DetectEngineCtx *, void *); #ifdef UNITTESTS -void DetectTcpmssRegisterTests (void); +void DetectTcpmssRegisterTests(void); #endif static int PrefilterSetupTcpmss(DetectEngineCtx *de_ctx, SigGroupHead *sgh); static bool PrefilterTcpmssIsPrefilterable(const Signature *s); @@ -73,8 +72,8 @@ void DetectTcpmssRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectTcpmssMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectTcpmssMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) @@ -99,7 +98,7 @@ static int DetectTcpmssMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectTcpmssSetup (DetectEngineCtx *de_ctx, Signature *s, const char *tcpmssstr) +static int DetectTcpmssSetup(DetectEngineCtx *de_ctx, Signature *s, const char *tcpmssstr) { DetectU16Data *tcpmssd = DetectU16Parse(tcpmssstr); if (tcpmssd == NULL) @@ -127,8 +126,7 @@ void DetectTcpmssFree(DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketTcpmssMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketTcpmssMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) return; @@ -165,7 +163,7 @@ static int PrefilterSetupTcpmss(DetectEngineCtx *de_ctx, SigGroupHead *sgh) static bool PrefilterTcpmssIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_TCPMSS: return true; diff --git a/src/detect-tcpmss.h b/src/detect-tcpmss.h index d01f2819b563..93f2b395db29 100644 --- a/src/detect-tcpmss.h +++ b/src/detect-tcpmss.h @@ -22,8 +22,8 @@ */ #ifndef _DETECT_TCPMSS_H -#define _DETECT_TCPMSS_H +#define _DETECT_TCPMSS_H void DetectTcpmssRegister(void); -#endif /* _DETECT_TCPMSS_H */ +#endif /* _DETECT_TCPMSS_H */ diff --git a/src/detect-template-rust-buffer.c b/src/detect-template-rust-buffer.c deleted file mode 100644 index f1c8c97bb278..000000000000 --- a/src/detect-template-rust-buffer.c +++ /dev/null @@ -1,204 +0,0 @@ -/* Copyright (C) 2015-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/* - * TODO: Update the \author in this file and detect-template.h. - * TODO: Update description in the \file section below. - * TODO: Remove SCLogNotice statements or convert to debug. - */ - -/** - * \file - * - * \author FirstName LastName - * - * Set up of the "template_rust" keyword to allow content - * inspections on the decoded template application layer buffers. - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-template-rust-buffer.h" -#include "app-layer-parser.h" -#include "detect-engine-build.h" -#include "rust.h" - -static int DetectTemplateRustBufferSetup(DetectEngineCtx *, Signature *, const char *); -static uint8_t DetectEngineInspectTemplateRustBuffer(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); -#ifdef UNITTESTS -static void DetectTemplateRustBufferRegisterTests(void); -#endif -static int g_template_rust_id = 0; - -void DetectTemplateRustBufferRegister(void) -{ - /* TEMPLATE_START_REMOVE */ - if (ConfGetNode("app-layer.protocols.template-rust") == NULL) { - return; - } - /* TEMPLATE_END_REMOVE */ - sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_rust_buffer"; - sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = - "Template content modifier to match on the template buffers"; - sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].Setup = DetectTemplateRustBufferSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].RegisterTests = DetectTemplateRustBufferRegisterTests; -#endif - sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT; - - /* register inspect engines */ - DetectAppLayerInspectEngineRegister2("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectTemplateRustBuffer, NULL); - DetectAppLayerInspectEngineRegister2("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectTemplateRustBuffer, NULL); - - g_template_rust_id = DetectBufferTypeGetByName("template_buffer"); - - SCLogNotice("Template application layer detect registered."); -} - -static int DetectTemplateRustBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - s->init_data->list = g_template_rust_id; - - if (DetectSignatureSetAppProto(s, ALPROTO_TEMPLATE) != 0) - return -1; - - return 0; -} - -static uint8_t DetectEngineInspectTemplateRustBuffer(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, - const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) -{ - uint8_t ret = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; - const uint8_t *data = NULL; - uint32_t data_len = 0; - - if (flags & STREAM_TOSERVER) { - rs_template_get_request_buffer(txv, &data, &data_len); - } else if (flags & STREAM_TOCLIENT) { - rs_template_get_response_buffer(txv, &data, &data_len); - } - - if (data != NULL) { - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)data, data_len, 0, DETECT_CI_FLAGS_SINGLE, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - ret = DETECT_ENGINE_INSPECT_SIG_MATCH; - } - } - - SCLogNotice("Returning %u.", ret); - return ret; -} - -#ifdef UNITTESTS - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "flow-util.h" -#include "stream-tcp.h" -#include "detect-engine-alert.h" - -static int DetectTemplateRustBufferTest(void) -{ - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - DetectEngineThreadCtx *det_ctx = NULL; - DetectEngineCtx *de_ctx = NULL; - Flow f; - Packet *p; - TcpSession tcp; - ThreadVars tv; - Signature *s; - - uint8_t request[] = "12:Hello World!"; - - /* Setup flow. */ - memset(&f, 0, sizeof(Flow)); - memset(&tcp, 0, sizeof(TcpSession)); - memset(&tv, 0, sizeof(ThreadVars)); - p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP); - FLOW_INITIALIZE(&f); - f.alproto = ALPROTO_TEMPLATE; - f.protoctx = (void *)&tcp; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; - StreamTcpInitConfig(true); - - de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - - /* This rule should match. */ - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" - "msg:\"TEMPLATE Test Rule\"; " - "template_rust_buffer; content:\"World!\"; " - "sid:1; rev:1;)"); - FAIL_IF_NULL(s); - - /* This rule should not match. */ - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" - "msg:\"TEMPLATE Test Rule\"; " - "template_rust_buffer; content:\"W0rld!\"; " - "sid:2; rev:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - AppLayerParserParse( - NULL, alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, request, sizeof(request)); - - /* Check that we have app-layer state. */ - FAIL_IF_NULL(f.alstate); - - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - FAIL_IF(!PacketAlertCheck(p, 1)); - FAIL_IF(PacketAlertCheck(p, 2)); - - /* Cleanup. */ - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePacket(p); - - PASS; -} - -static void DetectTemplateRustBufferRegisterTests(void) -{ - UtRegisterTest("DetectTemplateRustBufferTest", - DetectTemplateRustBufferTest); -} -#endif /* UNITTESTS */ diff --git a/src/detect-template.c b/src/detect-template.c deleted file mode 100644 index 5e09170d82a3..000000000000 --- a/src/detect-template.c +++ /dev/null @@ -1,221 +0,0 @@ -/* Copyright (C) 2015-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author XXX Yourname - * - * XXX Short description of the purpose of this keyword - */ - -#include "suricata-common.h" -#include "util-unittest.h" -#include "util-byte.h" - -#include "detect-parse.h" -#include "detect-engine.h" - -#include "detect-template.h" - -/** - * \brief Regex for parsing our keyword options - */ -#define PARSE_REGEX "^\\s*([0-9]+)?\\s*,s*([0-9]+)?\\s*$" -static DetectParseRegex parse_regex; - -/* Prototypes of functions registered in DetectTemplateRegister below */ -static int DetectTemplateMatch (DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); -static int DetectTemplateSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectTemplateFree (DetectEngineCtx *, void *); -#ifdef UNITTESTS -static void DetectTemplateRegisterTests (void); -#endif - -/** - * \brief Registration function for template: keyword - * - * This function is called once in the 'lifetime' of the engine. - */ -void DetectTemplateRegister(void) { - /* keyword name: this is how the keyword is used in a rule */ - sigmatch_table[DETECT_TEMPLATE].name = "template"; - /* description: listed in "suricata --list-keywords=all" */ - sigmatch_table[DETECT_TEMPLATE].desc = "give an introduction into how a detection module works"; - /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */ - sigmatch_table[DETECT_TEMPLATE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Developers_Guide"; - /* match function is called when the signature is inspected on a packet */ - sigmatch_table[DETECT_TEMPLATE].Match = DetectTemplateMatch; - /* setup function is called during signature parsing, when the template - * keyword is encountered in the rule */ - sigmatch_table[DETECT_TEMPLATE].Setup = DetectTemplateSetup; - /* free function is called when the detect engine is freed. Normally at - * shutdown, but also during rule reloads. */ - sigmatch_table[DETECT_TEMPLATE].Free = DetectTemplateFree; -#ifdef UNITTESTS - /* registers unittests into the system */ - sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests; -#endif - /* set up the PCRE for keyword parsing */ - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); -} - -/** - * \brief This function is used to match TEMPLATE rule option on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch with context that we will cast into DetectTemplateData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectTemplateMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) -{ - int ret = 0; - const DetectTemplateData *templated = (const DetectTemplateData *) ctx; -#if 0 - if (PKT_IS_PSEUDOPKT(p)) { - /* fake pkt */ - } - - if (PKT_IS_IPV4(p)) { - /* ipv4 pkt */ - } else if (PKT_IS_IPV6(p)) { - /* ipv6 pkt */ - } else { - SCLogDebug("packet is of not IPv4 or IPv6"); - return ret; - } -#endif - /* packet payload access */ - if (p->payload != NULL && p->payload_len > 0) { - if (templated->arg1 == p->payload[0] && - templated->arg2 == p->payload[p->payload_len - 1]) - { - ret = 1; - } - } - - return ret; -} - -/** - * \brief This function is used to parse template options passed via template: keyword - * - * \param templatestr Pointer to the user provided template options - * - * \retval templated pointer to DetectTemplateData on success - * \retval NULL on failure - */ -static DetectTemplateData *DetectTemplateParse (const char *templatestr) -{ - char arg1[4] = ""; - char arg2[4] = ""; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, templatestr, 0, 0); - if (ret != 3) { - SCLogError("parse error, ret %" PRId32 "", ret); - goto error; - } - - size_t pcre2len = sizeof(arg1); - ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("Arg1 \"%s\"", arg1); - - pcre2len = sizeof(arg2); - ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("Arg2 \"%s\"", arg2); - - DetectTemplateData *templated = SCMalloc(sizeof (DetectTemplateData)); - if (unlikely(templated == NULL)) - goto error; - - if (ByteExtractStringUint8(&templated->arg1, 10, 0, (const char *)arg1) < 0) { - SCFree(templated); - goto error; - } - if (ByteExtractStringUint8(&templated->arg2, 10, 0, (const char *)arg2) < 0) { - SCFree(templated); - goto error; - } - pcre2_match_data_free(match); - return templated; - -error: - if (match) { - pcre2_match_data_free(match); - } - return NULL; -} - -/** - * \brief parse the options from the 'template' keyword in the rule into - * the Signature data structure. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param templatestr pointer to the user provided template options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectTemplateSetup (DetectEngineCtx *de_ctx, Signature *s, const char *templatestr) -{ - DetectTemplateData *templated = DetectTemplateParse(templatestr); - if (templated == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_TEMPLATE, (SigMatchCtx *)templated, - DETECT_SM_LIST_MATCH) == NULL) { - DetectTemplateFree(de_ctx, templated); - return -1; - } - s->flags |= SIG_FLAG_REQUIRE_PACKET; - - return 0; -} - -/** - * \brief this function will free memory associated with DetectTemplateData - * - * \param ptr pointer to DetectTemplateData - */ -static void DetectTemplateFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectTemplateData *templated = (DetectTemplateData *)ptr; - - /* do more specific cleanup here, if needed */ - - SCFree(templated); -} - -#ifdef UNITTESTS -#include "tests/detect-template.c" -#endif diff --git a/src/detect-template2.c b/src/detect-template2.c deleted file mode 100644 index df93a535e6b9..000000000000 --- a/src/detect-template2.c +++ /dev/null @@ -1,189 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author XXX - * - */ - -#include "suricata-common.h" -#include "util-byte.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine-prefilter-common.h" -#include "detect-engine-uint.h" - -#include "detect-template2.h" - - -/* prototypes */ -static int DetectTemplate2Match (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectTemplate2Setup (DetectEngineCtx *, Signature *, const char *); -void DetectTemplate2Free (DetectEngineCtx *, void *); -#ifdef UNITTESTS -void DetectTemplate2RegisterTests (void); -#endif -static int PrefilterSetupTemplate2(DetectEngineCtx *de_ctx, SigGroupHead *sgh); -static bool PrefilterTemplate2IsPrefilterable(const Signature *s); - -/** - * \brief Registration function for template2: keyword - */ - -void DetectTemplate2Register(void) -{ - sigmatch_table[DETECT_TEMPLATE2].name = "template2"; - sigmatch_table[DETECT_TEMPLATE2].desc = "TODO describe the keyword"; - sigmatch_table[DETECT_TEMPLATE2].url = "/rules/header-keywords.html#template2"; - sigmatch_table[DETECT_TEMPLATE2].Match = DetectTemplate2Match; - sigmatch_table[DETECT_TEMPLATE2].Setup = DetectTemplate2Setup; - sigmatch_table[DETECT_TEMPLATE2].Free = DetectTemplate2Free; - sigmatch_table[DETECT_TEMPLATE2].SupportsPrefilter = PrefilterTemplate2IsPrefilterable; - sigmatch_table[DETECT_TEMPLATE2].SetupPrefilter = PrefilterSetupTemplate2; - - return; -} - -/** - * \brief This function is used to match TEMPLATE2 rule option on a packet with those passed via - * template2: - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectU8Data - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectTemplate2Match (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) -{ - - if (PKT_IS_PSEUDOPKT(p)) - return 0; - - /* TODO replace this */ - uint8_t ptemplate2; - if (PKT_IS_IPV4(p)) { - ptemplate2 = IPV4_GET_IPTTL(p); - } else if (PKT_IS_IPV6(p)) { - ptemplate2 = IPV6_GET_HLIM(p); - } else { - SCLogDebug("Packet is of not IPv4 or IPv6"); - return 0; - } - - const DetectU8Data *template2d = (const DetectU8Data *)ctx; - return DetectU8Match(ptemplate2, template2d); -} - -/** - * \brief this function is used to add the parsed template2 data into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param template2str pointer to the user provided template2 options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectTemplate2Setup (DetectEngineCtx *de_ctx, Signature *s, const char *template2str) -{ - DetectU8Data *template2d = DetectU8Parse(template2str); - if (template2d == NULL) - return -1; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_TEMPLATE2, (SigMatchCtx *)template2d, - DETECT_SM_LIST_MATCH) == NULL) { - DetectTemplate2Free(de_ctx, template2d); - return -1; - } - s->flags |= SIG_FLAG_REQUIRE_PACKET; - - return 0; -} - -/** - * \brief this function will free memory associated with DetectU8Data - * - * \param ptr pointer to DetectU8Data - */ -void DetectTemplate2Free(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u8_free(ptr); -} - -/* prefilter code */ - -static void -PrefilterPacketTemplate2Match(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) -{ - if (PKT_IS_PSEUDOPKT(p)) { - SCReturn; - } - - uint8_t ptemplate2; -/* TODO update */ - if (PKT_IS_IPV4(p)) { - ptemplate2 = IPV4_GET_IPTTL(p); - } else if (PKT_IS_IPV6(p)) { - ptemplate2 = IPV6_GET_HLIM(p); - } else { - SCLogDebug("Packet is of not IPv4 or IPv6"); - return; - } - - /* during setup Suricata will automatically see if there is another - * check that can be added: alproto, sport or dport */ - const PrefilterPacketHeaderCtx *ctx = pectx; - if (!PrefilterPacketHeaderExtraMatch(ctx, p)) - return; - - DetectU8Data du8; - du8.mode = ctx->v1.u8[0]; - du8.arg1 = ctx->v1.u8[1]; - du8.arg2 = ctx->v1.u8[2]; - /* if we match, add all the sigs that use this prefilter. This means - * that these will be inspected further */ - if (DetectU8Match(ptemplate2, &du8)) { - SCLogDebug("packet matches template2/hl %u", ptemplate2); - PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); - } -} - -static int PrefilterSetupTemplate2(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_TEMPLATE2, PrefilterPacketU8Set, - PrefilterPacketU8Compare, PrefilterPacketTemplate2Match); -} - -static bool PrefilterTemplate2IsPrefilterable(const Signature *s) -{ - const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { - switch (sm->type) { - case DETECT_TEMPLATE2: - return true; - } - } - return false; -} diff --git a/src/detect-template2.h b/src/detect-template2.h deleted file mode 100644 index b7ea8af34a6d..000000000000 --- a/src/detect-template2.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author XXX - */ - -#ifndef _DETECT_TEMPLATE2_H -#define _DETECT_TEMPLATE2_H - - -void DetectTemplate2Register(void); - -#endif /* _DETECT_TEMPLATE2_H */ - diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 98eb3ce8dc03..daaaaa737467 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -51,21 +51,26 @@ #include "detect-engine-address.h" #include "detect-engine-build.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" +#include "util/debug.h" #ifdef UNITTESTS -#include "util-cpu.h" +#include "util/cpu.h" #endif -#define PARSE_REGEX "^\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_both|by_rule|\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_both|by_rule|\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_both|by_rule|\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_both|by_rule|\\d+)\\s*" +#define PARSE_REGEX \ + "^\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_both|by_rule|\\d+)" \ + "\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_both|by_rule|" \ + "\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_both|by_" \ + "rule|\\d+)\\s*,\\s*(track|type|count|seconds)\\s+(limit|both|threshold|by_dst|by_src|by_" \ + "both|by_rule|\\d+)\\s*" static DetectParseRegex parse_regex; -static int DetectThresholdMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectThresholdMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectThresholdSetup(DetectEngineCtx *, Signature *, const char *); static void DetectThresholdFree(DetectEngineCtx *, void *); #ifdef UNITTESTS @@ -83,7 +88,7 @@ void DetectThresholdRegister(void) sigmatch_table[DETECT_THRESHOLD].url = "/rules/thresholding.html#threshold"; sigmatch_table[DETECT_THRESHOLD].Match = DetectThresholdMatch; sigmatch_table[DETECT_THRESHOLD].Setup = DetectThresholdSetup; - sigmatch_table[DETECT_THRESHOLD].Free = DetectThresholdFree; + sigmatch_table[DETECT_THRESHOLD].Free = DetectThresholdFree; #ifdef UNITTESTS sigmatch_table[DETECT_THRESHOLD].RegisterTests = ThresholdRegisterTests; #endif @@ -93,8 +98,8 @@ void DetectThresholdRegister(void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static int DetectThresholdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectThresholdMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { return 1; } @@ -129,23 +134,22 @@ static DetectThresholdData *DetectThresholdParse(const char *rawstr) } char *saveptr = NULL; - for (pos = 0, threshold_opt = strtok_r(copy_str,",", &saveptr); - pos < strlen(copy_str) && threshold_opt != NULL; - pos++, threshold_opt = strtok_r(NULL,"," , &saveptr)) - { - if(strstr(threshold_opt,"count")) + for (pos = 0, threshold_opt = strtok_r(copy_str, ",", &saveptr); + pos < strlen(copy_str) && threshold_opt != NULL; + pos++, threshold_opt = strtok_r(NULL, ",", &saveptr)) { + if (strstr(threshold_opt, "count")) count_found++; - if(strstr(threshold_opt,"second")) + if (strstr(threshold_opt, "second")) second_found++; - if(strstr(threshold_opt,"type")) + if (strstr(threshold_opt, "type")) type_found++; - if(strstr(threshold_opt,"track")) + if (strstr(threshold_opt, "track")) track_found++; } SCFree(copy_str); copy_str = NULL; - if(count_found != 1 || second_found != 1 || type_found != 1 || track_found != 1) + if (count_found != 1 || second_found != 1 || type_found != 1 || track_found != 1) goto error; ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); @@ -169,41 +173,39 @@ static DetectThresholdData *DetectThresholdParse(const char *rawstr) args[i] = (char *)str_ptr; - if (strncasecmp(args[i],"limit",strlen("limit")) == 0) + if (strncasecmp(args[i], "limit", strlen("limit")) == 0) de->type = TYPE_LIMIT; - if (strncasecmp(args[i],"both",strlen("both")) == 0) + if (strncasecmp(args[i], "both", strlen("both")) == 0) de->type = TYPE_BOTH; - if (strncasecmp(args[i],"threshold",strlen("threshold")) == 0) + if (strncasecmp(args[i], "threshold", strlen("threshold")) == 0) de->type = TYPE_THRESHOLD; - if (strncasecmp(args[i],"by_dst",strlen("by_dst")) == 0) + if (strncasecmp(args[i], "by_dst", strlen("by_dst")) == 0) de->track = TRACK_DST; - if (strncasecmp(args[i],"by_src",strlen("by_src")) == 0) + if (strncasecmp(args[i], "by_src", strlen("by_src")) == 0) de->track = TRACK_SRC; - if (strncasecmp(args[i],"by_both",strlen("by_both")) == 0) + if (strncasecmp(args[i], "by_both", strlen("by_both")) == 0) de->track = TRACK_BOTH; - if (strncasecmp(args[i],"by_rule",strlen("by_rule")) == 0) + if (strncasecmp(args[i], "by_rule", strlen("by_rule")) == 0) de->track = TRACK_RULE; - if (strncasecmp(args[i],"count",strlen("count")) == 0) - count_pos = i+1; - if (strncasecmp(args[i],"seconds",strlen("seconds")) == 0) - second_pos = i+1; + if (strncasecmp(args[i], "count", strlen("count")) == 0) + count_pos = i + 1; + if (strncasecmp(args[i], "seconds", strlen("seconds")) == 0) + second_pos = i + 1; } if (args[count_pos] == NULL || args[second_pos] == NULL) { goto error; } - if (StringParseUint32(&de->count, 10, strlen(args[count_pos]), - args[count_pos]) <= 0) { + if (StringParseUint32(&de->count, 10, strlen(args[count_pos]), args[count_pos]) <= 0) { goto error; } - if (StringParseUint32(&de->seconds, 10, strlen(args[second_pos]), - args[second_pos]) <= 0) { + if (StringParseUint32(&de->seconds, 10, strlen(args[second_pos]), args[second_pos]) <= 0) { goto error; } - for (i = 0; i < (ret - 1); i++){ + for (i = 0; i < (ret - 1); i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } @@ -214,7 +216,7 @@ static DetectThresholdData *DetectThresholdParse(const char *rawstr) if (match) { pcre2_match_data_free(match); } - for (i = 0; i < (ret - 1); i++){ + for (i = 0; i < (ret - 1); i++) { if (args[i] != NULL) pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); } @@ -338,8 +340,8 @@ DetectThresholdData *DetectThresholdDataCopy(DetectThresholdData *de) #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-alert.h" -#include "util-time.h" -#include "util-hashlist.h" +#include "util/time.h" +#include "util/hashlist.h" #include "packet.h" #include "action-globals.h" /** @@ -352,7 +354,8 @@ static int ThresholdTestParse01(void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("type limit,track by_dst,count 10,seconds 60"); - if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { + if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && + (de->seconds == 60)) { DetectThresholdFree(NULL, de); return 1; } @@ -370,7 +373,8 @@ static int ThresholdTestParse02(void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("type any,track by_dst,count 10,seconds 60"); - if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { + if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && + (de->seconds == 60)) { DetectThresholdFree(NULL, de); return 0; } @@ -388,7 +392,8 @@ static int ThresholdTestParse03(void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("track by_dst, type limit, seconds 60, count 10"); - if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { + if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && + (de->seconds == 60)) { DetectThresholdFree(NULL, de); return 1; } @@ -396,7 +401,6 @@ static int ThresholdTestParse03(void) return 0; } - /** * \test ThresholdTestParse04 is a test for an invalid threshold options in any order * @@ -407,7 +411,8 @@ static int ThresholdTestParse04(void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both, count 10"); - if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { + if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && + (de->seconds == 60)) { DetectThresholdFree(NULL, de); return 0; } @@ -425,7 +430,8 @@ static int ThresholdTestParse05(void) { DetectThresholdData *de = NULL; de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both"); - if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { + if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && + (de->seconds == 60)) { DetectThresholdFree(NULL, de); return 1; } @@ -493,7 +499,7 @@ static int DetectThresholdTestSig1(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -502,7 +508,9 @@ static int DetectThresholdTestSig1(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; content:\"A\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit\"; content:\"A\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } @@ -516,48 +524,48 @@ static int DetectThresholdTestSig1(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); if (alerts != 1) { - printf("alerts %"PRIi32", expected 1: ", alerts); + printf("alerts %" PRIi32 ", expected 1: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 2) { - printf("alerts %"PRIi32", expected 2: ", alerts); + printf("alerts %" PRIi32 ", expected 2: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 3) { - printf("alerts %"PRIi32", expected 3: ", alerts); + printf("alerts %" PRIi32 ", expected 3: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 4) { - printf("alerts %"PRIi32", expected 4: ", alerts); + printf("alerts %" PRIi32 ", expected 4: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { - printf("alerts %"PRIi32", expected 5: ", alerts); + printf("alerts %" PRIi32 ", expected 5: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { - printf("alerts %"PRIi32", expected 5: ", alerts); + printf("alerts %" PRIi32 ", expected 5: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { - printf("alerts %"PRIi32", expected 5: ", alerts); + printf("alerts %" PRIi32 ", expected 5: ", alerts); } SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { - printf("alerts %"PRIi32", expected 5: ", alerts); + printf("alerts %" PRIi32 ", expected 5: ", alerts); } - if(alerts == 5) + if (alerts == 5) result = 1; else - printf("alerts %"PRIi32", expected 5: ", alerts); + printf("alerts %" PRIi32 ", expected 5: ", alerts); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -594,7 +602,7 @@ static int DetectThresholdTestSig2(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -603,7 +611,9 @@ static int DetectThresholdTestSig2(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold\"; threshold: type threshold, track by_dst, count 5, seconds 60; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold\"; threshold: type " + "threshold, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } @@ -673,7 +683,7 @@ static int DetectThresholdTestSig3(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -682,7 +692,9 @@ static int DetectThresholdTestSig3(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:10;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit\"; threshold: type " + "limit, track by_dst, count 5, seconds 60; sid:10;)"); if (s == NULL) { goto end; } @@ -773,7 +785,7 @@ static int DetectThresholdTestSig4(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -782,7 +794,9 @@ static int DetectThresholdTestSig4(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold both\"; threshold: type both, track by_dst, count 2, seconds 60; sid:10;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold both\"; threshold: type " + "both, track by_dst, count 2, seconds 60; sid:10;)"); if (s == NULL) { goto end; } @@ -846,7 +860,7 @@ static int DetectThresholdTestSig5(void) HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -855,12 +869,16 @@ static int DetectThresholdTestSig5(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } - s = s->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + s = s->next = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); if (s == NULL) { goto end; } @@ -893,7 +911,7 @@ static int DetectThresholdTestSig5(void) alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - if(alerts == 10) + if (alerts == 10) result = 1; else { printf("alerts %d != 10: ", alerts); @@ -925,7 +943,7 @@ static int DetectThresholdTestSig6Ticks(void) HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -934,12 +952,16 @@ static int DetectThresholdTestSig6Ticks(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); if (s == NULL) { goto end; } - s = s->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + s = s->next = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); if (s == NULL) { goto end; } @@ -976,9 +998,9 @@ static int DetectThresholdTestSig6Ticks(void) alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); ticks_end = UtilCpuGetTicks(); - printf("test run %"PRIu64"\n", (ticks_end - ticks_start)); + printf("test run %" PRIu64 "\n", (ticks_end - ticks_start)); - if(alerts == 10) + if (alerts == 10) result = 1; else goto cleanup; @@ -1013,7 +1035,7 @@ static int DetectThresholdTestSig7(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1022,7 +1044,8 @@ static int DetectThresholdTestSig7(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type limit, track by_src, count 1, seconds 300; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, " + "track by_src, count 1, seconds 300; sid:10;)"); if (s == NULL) { goto end; } @@ -1103,7 +1126,7 @@ static int DetectThresholdTestSig8(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1112,7 +1135,8 @@ static int DetectThresholdTestSig8(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type limit, track by_src, count 2, seconds 300; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, " + "track by_src, count 2, seconds 300; sid:10;)"); if (s == NULL) { goto end; } @@ -1193,7 +1217,7 @@ static int DetectThresholdTestSig9(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1202,7 +1226,8 @@ static int DetectThresholdTestSig9(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type threshold, track by_src, count 3, seconds 100; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, " + "track by_src, count 3, seconds 100; sid:10;)"); if (s == NULL) { goto end; } @@ -1283,7 +1308,7 @@ static int DetectThresholdTestSig10(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1292,7 +1317,8 @@ static int DetectThresholdTestSig10(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type threshold, track by_src, count 5, seconds 300; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, " + "track by_src, count 5, seconds 300; sid:10;)"); if (s == NULL) { goto end; } @@ -1373,7 +1399,7 @@ static int DetectThresholdTestSig11(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1382,7 +1408,8 @@ static int DetectThresholdTestSig11(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type both, track by_src, count 3, seconds 300; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type both, " + "track by_src, count 3, seconds 300; sid:10;)"); if (s == NULL) { goto end; } @@ -1463,7 +1490,7 @@ static int DetectThresholdTestSig12(void) memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1472,7 +1499,8 @@ static int DetectThresholdTestSig12(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any 80 (threshold: type both, track by_src, count 5, seconds 300; sid:10;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type both, " + "track by_src, count 5, seconds 300; sid:10;)"); if (s == NULL) { goto end; } @@ -1528,7 +1556,7 @@ static int DetectThresholdTestSig12(void) SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void*)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); @@ -1556,7 +1584,7 @@ static int DetectThresholdTestSig13(void) HostInitConfig(HOST_QUIET); memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); @@ -1564,7 +1592,9 @@ static int DetectThresholdTestSig13(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; threshold: type limit, track by_rule, count 2, seconds 60; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_rule, count 2, seconds 60; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1628,8 +1658,8 @@ static int DetectThresholdTestSig14(void) IPPairInitConfig(IPPAIR_QUIET); memset(&th_v, 0, sizeof(th_v)); - p1 = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); - p2 = UTHBuildPacketReal((uint8_t *)"A",1,IPPROTO_TCP, "1.1.1.1", "3.3.3.3", 1024, 80); + p1 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + p2 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "3.3.3.3", 1024, 80); FAIL_IF_NULL(p1); FAIL_IF_NULL(p2); @@ -1638,7 +1668,9 @@ static int DetectThresholdTestSig14(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; threshold: type limit, track by_both, count 2, seconds 60; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_both, count 2, seconds 60; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1703,8 +1735,7 @@ static void ThresholdRegisterTests(void) UtRegisterTest("DetectThresholdTestSig3", DetectThresholdTestSig3); UtRegisterTest("DetectThresholdTestSig4", DetectThresholdTestSig4); UtRegisterTest("DetectThresholdTestSig5", DetectThresholdTestSig5); - UtRegisterTest("DetectThresholdTestSig6Ticks", - DetectThresholdTestSig6Ticks); + UtRegisterTest("DetectThresholdTestSig6Ticks", DetectThresholdTestSig6Ticks); UtRegisterTest("DetectThresholdTestSig7", DetectThresholdTestSig7); UtRegisterTest("DetectThresholdTestSig8", DetectThresholdTestSig8); UtRegisterTest("DetectThresholdTestSig9", DetectThresholdTestSig9); diff --git a/src/detect-threshold.h b/src/detect-threshold.h index 751c0e1ac762..55c9548cd7c8 100644 --- a/src/detect-threshold.h +++ b/src/detect-threshold.h @@ -24,7 +24,6 @@ #ifndef __DETECT_THRESHOLD_H__ #define __DETECT_THRESHOLD_H__ - #define TYPE_LIMIT 1 #define TYPE_BOTH 2 #define TYPE_THRESHOLD 3 @@ -32,19 +31,19 @@ #define TYPE_RATE 5 #define TYPE_SUPPRESS 6 -#define TRACK_DST 1 -#define TRACK_SRC 2 -#define TRACK_RULE 3 -#define TRACK_EITHER 4 /**< either src or dst: only used by suppress */ -#define TRACK_BOTH 5 /* used by rate_filter to match detections by both src and dst addresses */ +#define TRACK_DST 1 +#define TRACK_SRC 2 +#define TRACK_RULE 3 +#define TRACK_EITHER 4 /**< either src or dst: only used by suppress */ +#define TRACK_BOTH 5 /* used by rate_filter to match detections by both src and dst addresses */ /* Get the new action to take */ -#define TH_ACTION_ALERT 0x01 -#define TH_ACTION_DROP 0x02 -#define TH_ACTION_PASS 0x04 -#define TH_ACTION_LOG 0x08 -#define TH_ACTION_SDROP 0x10 -#define TH_ACTION_REJECT 0x20 +#define TH_ACTION_ALERT 0x01 +#define TH_ACTION_DROP 0x02 +#define TH_ACTION_PASS 0x04 +#define TH_ACTION_LOG 0x08 +#define TH_ACTION_SDROP 0x10 +#define TH_ACTION_REJECT 0x20 /** * \typedef DetectThresholdData @@ -63,20 +62,19 @@ typedef struct DetectThresholdData_ { } DetectThresholdData; typedef struct DetectThresholdEntry_ { - uint32_t sid; /**< Signature id */ - uint32_t gid; /**< Signature group id */ + uint32_t sid; /**< Signature id */ + uint32_t gid; /**< Signature group id */ uint32_t tv_timeout; /**< Timeout for new_action (for rate_filter) its not "seconds", that define the time interval */ uint32_t seconds; /**< Event seconds */ uint32_t current_count; /**< Var for count control */ - int track; /**< Track type: by_src, by_src */ + int track; /**< Track type: by_src, by_src */ SCTime_t tv1; /**< Var for time control */ struct DetectThresholdEntry_ *next; } DetectThresholdEntry; - /** * Registration function for threshold: keyword */ diff --git a/src/detect-tls-cert-fingerprint.c b/src/detect-tls-cert-fingerprint.c deleted file mode 100644 index 98ba46143db4..000000000000 --- a/src/detect-tls-cert-fingerprint.c +++ /dev/null @@ -1,246 +0,0 @@ -/* Copyright (C) 2017-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for tls_cert_fingerprint keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-cert-fingerprint.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsFingerprintSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTlsFingerprintRegisterTests(void); -#endif -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static void DetectTlsFingerprintSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); -static bool DetectTlsFingerprintValidateCallback(const Signature *s, - const char **sigerror); -static int g_tls_cert_fingerprint_buffer_id = 0; - -/** - * \brief Registration function for keyword: tls.cert_fingerprint - */ -void DetectTlsFingerprintRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].name = "tls.cert_fingerprint"; - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].alias = "tls_cert_fingerprint"; - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].desc = - "sticky buffer to match the TLS cert fingerprint buffer"; - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].url = "/rules/tls-keywords.html#tls-cert-fingerprint"; - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].Setup = DetectTlsFingerprintSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].RegisterTests = DetectTlsFingerprintRegisterTests; -#endif - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_CERT_FINGERPRINT].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("tls.cert_fingerprint", ALPROTO_TLS, - SIG_FLAG_TOCLIENT, TLS_STATE_CERT_READY, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_fingerprint", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, - TLS_STATE_CERT_READY); - - DetectAppLayerInspectEngineRegister2("tls.cert_fingerprint", ALPROTO_TLS, SIG_FLAG_TOSERVER, - TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_fingerprint", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); - - DetectBufferTypeSetDescriptionByName("tls.cert_fingerprint", - "TLS certificate fingerprint"); - - DetectBufferTypeRegisterSetupCallback("tls.cert_fingerprint", - DetectTlsFingerprintSetupCallback); - - DetectBufferTypeRegisterValidateCallback("tls.cert_fingerprint", - DetectTlsFingerprintValidateCallback); - - g_tls_cert_fingerprint_buffer_id = DetectBufferTypeGetByName("tls.cert_fingerprint"); -} - -/** - * \brief this function setup the tls_cert_fingerprint modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsFingerprintSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_fingerprint_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - const SSLStateConnp *connp; - - if (flow_flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_fingerprint == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(connp->cert0_fingerprint); - const uint8_t *data = (uint8_t *)connp->cert0_fingerprint; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static bool DetectTlsFingerprintValidateCallback(const Signature *s, - const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_fingerprint_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - const DetectContentData *cd = (DetectContentData *)sm->ctx; - - if (cd->content_len != 59) { - *sigerror = "Invalid length of the specified fingerprint. " - "This rule will therefore never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - - bool have_delimiters = false; - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (cd->content[u] == ':') { - have_delimiters = true; - break; - } - } - - if (!have_delimiters) { - *sigerror = "No colon delimiters ':' detected in content after " - "tls.cert_fingerprint. This rule will therefore " - "never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = "tls.cert_fingerprint should not be used together " - "with nocase, since the rule is automatically " - "lowercased anyway which makes nocase redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - } - } - } - return true; -} - -static void DetectTlsFingerprintSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_fingerprint_buffer_id) - continue; - SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - - bool changed = false; - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) { - cd->content[u] = u8_tolower(cd->content[u]); - changed = true; - } - } - - /* recreate the context if changes were made */ - if (changed) { - SpmDestroyCtx(cd->spm_ctx); - cd->spm_ctx = - SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); - } - } - } -} - -#ifdef UNITTESTS -#include "detect-engine-alert.h" -#include "tests/detect-tls-cert-fingerprint.c" -#endif diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c deleted file mode 100644 index 9146f8d0f40b..000000000000 --- a/src/detect-tls-cert-issuer.c +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for tls.cert_issuer keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" -#include "detect-tls-cert-issuer.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsIssuerSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTlsIssuerRegisterTests(void); -#endif -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static int g_tls_cert_issuer_buffer_id = 0; - -/** - * \brief Registration function for keyword: tls.cert_issuer - */ -void DetectTlsIssuerRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].name = "tls.cert_issuer"; - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].alias = "tls_cert_issuer"; - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].desc = - "sticky buffer to match specifically and only on the TLS cert issuer buffer"; - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].url = "/rules/tls-keywords.html#tls-cert-issuer"; - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Setup = DetectTlsIssuerSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].RegisterTests = DetectTlsIssuerRegisterTests; -#endif - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("tls.cert_issuer", ALPROTO_TLS, SIG_FLAG_TOSERVER, - TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_issuer", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); - - DetectAppLayerInspectEngineRegister2("tls.cert_issuer", ALPROTO_TLS, - SIG_FLAG_TOCLIENT, TLS_STATE_CERT_READY, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_issuer", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, - TLS_STATE_CERT_READY); - - DetectBufferTypeSetDescriptionByName("tls.cert_issuer", - "TLS certificate issuer"); - - g_tls_cert_issuer_buffer_id = DetectBufferTypeGetByName("tls.cert_issuer"); -} - - -/** - * \brief this function setup the tls_cert_issuer modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsIssuerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_issuer_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - const SSLStateConnp *connp; - if (flow_flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_issuerdn == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(connp->cert0_issuerdn); - const uint8_t *data = (uint8_t *)connp->cert0_issuerdn; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS -#include "tests/detect-tls-cert-issuer.c" -#endif diff --git a/src/detect-tls-cert-issuer.h b/src/detect-tls-cert-issuer.h deleted file mode 100644 index fdfda510da26..000000000000 --- a/src/detect-tls-cert-issuer.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - */ - -#ifndef __DETECT_TLS_ISSUER_H__ -#define __DETECT_TLS_ISSUER_H__ - - -void DetectTlsIssuerRegister(void); - -#endif /* __DETECT_TLS_ISSUER_H__ */ diff --git a/src/detect-tls-cert-serial.c b/src/detect-tls-cert-serial.c deleted file mode 100644 index 19c86be80e24..000000000000 --- a/src/detect-tls-cert-serial.c +++ /dev/null @@ -1,236 +0,0 @@ -/* Copyright (C) 2017-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for tls.cert_serial keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" -#include "detect-tls-cert-serial.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsSerialSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTlsSerialRegisterTests(void); -#endif -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static void DetectTlsSerialSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); -static bool DetectTlsSerialValidateCallback(const Signature *s, - const char **sigerror); -static int g_tls_cert_serial_buffer_id = 0; - -/** - * \brief Registration function for keyword: tls.cert_serial - */ -void DetectTlsSerialRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].name = "tls.cert_serial"; - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].alias = "tls_cert_serial"; - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].desc = - "sticky buffer to match the TLS cert serial buffer"; - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].url = "/rules/tls-keywords.html#tls-cert-serial"; - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Setup = DetectTlsSerialSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].RegisterTests = DetectTlsSerialRegisterTests; -#endif - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("tls.cert_serial", ALPROTO_TLS, - SIG_FLAG_TOCLIENT, TLS_STATE_CERT_READY, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_serial", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, - TLS_STATE_CERT_READY); - - DetectAppLayerInspectEngineRegister2("tls.cert_serial", ALPROTO_TLS, SIG_FLAG_TOSERVER, - TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_serial", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); - - DetectBufferTypeSetDescriptionByName("tls.cert_serial", - "TLS certificate serial number"); - - DetectBufferTypeRegisterSetupCallback("tls.cert_serial", - DetectTlsSerialSetupCallback); - - DetectBufferTypeRegisterValidateCallback("tls.cert_serial", - DetectTlsSerialValidateCallback); - - g_tls_cert_serial_buffer_id = DetectBufferTypeGetByName("tls.cert_serial"); -} - -/** - * \brief this function setup the tls_cert_serial modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsSerialSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_serial_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - const SSLStateConnp *connp; - - if (flow_flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_serial == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(connp->cert0_serial); - const uint8_t *data = (uint8_t *)connp->cert0_serial; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static bool DetectTlsSerialValidateCallback(const Signature *s, - const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_serial_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - const DetectContentData *cd = (DetectContentData *)sm->ctx; - - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = "tls.cert_serial should not be used together " - "with nocase, since the rule is automatically " - "uppercased anyway which makes nocase redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - } - - /* no need to worry about this if the content is short enough */ - if (cd->content_len <= 2) - return true; - - uint32_t u; - for (u = 0; u < cd->content_len; u++) - if (cd->content[u] == ':') - return true; - - *sigerror = "No colon delimiters ':' detected in content after " - "tls.cert_serial. This rule will therefore never " - "match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - - return false; - } - } - return true; -} - -static void DetectTlsSerialSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_cert_serial_buffer_id) - continue; - SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - - bool changed = false; - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (islower(cd->content[u])) { - cd->content[u] = u8_toupper(cd->content[u]); - changed = true; - } - } - - /* recreate the context if changes were made */ - if (changed) { - SpmDestroyCtx(cd->spm_ctx); - cd->spm_ctx = - SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); - } - } - } -} - -#ifdef UNITTESTS -#include "tests/detect-tls-cert-serial.c" -#endif diff --git a/src/detect-tls-cert-serial.h b/src/detect-tls-cert-serial.h deleted file mode 100644 index 9fe018e90872..000000000000 --- a/src/detect-tls-cert-serial.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - */ - -#ifndef __DETECT_TLS_CERT_SERIAL_H__ -#define __DETECT_TLS_CERT_SERIAL_H__ - -/* prototypes */ -void DetectTlsSerialRegister (void); - -#endif /* __DETECT_TLS_CERT_SERIAL_H__ */ diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c deleted file mode 100644 index 9ec7fb96fb1f..000000000000 --- a/src/detect-tls-cert-subject.c +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for tls.cert_subject keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-cert-subject.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsSubjectSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTlsSubjectRegisterTests(void); -#endif -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static int g_tls_cert_subject_buffer_id = 0; - -/** - * \brief Registration function for keyword: tls.cert_subject - */ -void DetectTlsSubjectRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].name = "tls.cert_subject"; - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].alias = "tls_cert_subject"; - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].desc = - "sticky buffer to match specifically and only on the TLS cert subject buffer"; - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].url = "/rules/tls-keywords.html#tls-cert-subject"; - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Setup = DetectTlsSubjectSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; -#endif - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("tls.cert_subject", ALPROTO_TLS, SIG_FLAG_TOSERVER, - TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_subject", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, TLS_STATE_CERT_READY); - - DetectAppLayerInspectEngineRegister2("tls.cert_subject", ALPROTO_TLS, SIG_FLAG_TOCLIENT, - TLS_STATE_CERT_READY, DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.cert_subject", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, - TLS_STATE_CERT_READY); - - DetectBufferTypeSupportsMultiInstance("tls.cert_subject"); - - DetectBufferTypeSetDescriptionByName("tls.cert_subject", - "TLS certificate subject"); - - g_tls_cert_subject_buffer_id = DetectBufferTypeGetByName("tls.cert_subject"); -} - -/** - * \brief this function setup the tls.cert_subject modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_cert_subject_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - const SSLStateConnp *connp; - - if (flow_flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_subject == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(connp->cert0_subject); - const uint8_t *data = (uint8_t *)connp->cert0_subject; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -#ifdef UNITTESTS -#include "tests/detect-tls-cert-subject.c" -#endif diff --git a/src/detect-tls-cert-subject.h b/src/detect-tls-cert-subject.h deleted file mode 100644 index 23f3e77859c7..000000000000 --- a/src/detect-tls-cert-subject.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - */ - -#ifndef __DETECT_TLS_SUBJECT_H__ -#define __DETECT_TLS_SUBJECT_H__ - - -void DetectTlsSubjectRegister(void); - -#endif /* __DETECT_TLS_SUBJECT_H__ */ diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c deleted file mode 100644 index 3720d287db5c..000000000000 --- a/src/detect-tls-cert-validity.c +++ /dev/null @@ -1,597 +0,0 @@ -/* Copyright (C) 2015-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements tls certificate validity keywords - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-cert-validity.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-time.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -/** - * [tls_notbefore|tls_notafter]:[<|>][<>]; - */ -#define PARSE_REGEX "^\\s*(<|>)?\\s*([ -:TW0-9]+)\\s*(?:(<>)\\s*([ -:TW0-9]+))?\\s*$" -static DetectParseRegex parse_regex; - -static int DetectTlsValidityMatch (DetectEngineThreadCtx *, Flow *, - uint8_t, void *, void *, const Signature *, - const SigMatchCtx *); - -static time_t DateStringToEpoch (char *); -static DetectTlsValidityData *DetectTlsValidityParse (const char *); -static int DetectTlsExpiredSetup (DetectEngineCtx *, Signature *s, const char *str); -static int DetectTlsValidSetup (DetectEngineCtx *, Signature *s, const char *str); -static int DetectTlsNotBeforeSetup (DetectEngineCtx *, Signature *s, const char *str); -static int DetectTlsNotAfterSetup (DetectEngineCtx *, Signature *s, const char *str); -static int DetectTlsValiditySetup (DetectEngineCtx *, Signature *s, const char *str, uint8_t); -#ifdef UNITTESTS -static void TlsNotBeforeRegisterTests(void); -static void TlsNotAfterRegisterTests(void); -static void TlsExpiredRegisterTests(void); -static void TlsValidRegisterTests(void); -#endif /* UNITTESTS */ -static void DetectTlsValidityFree(DetectEngineCtx *, void *); -static int g_tls_validity_buffer_id = 0; - -/** - * \brief Registration function for tls validity keywords. - */ -void DetectTlsValidityRegister (void) -{ - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].name = "tls_cert_notbefore"; - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].desc = "match TLS certificate notBefore field"; - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].url = "/rules/tls-keywords.html#tls-cert-notbefore"; - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].AppLayerTxMatch = DetectTlsValidityMatch; - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Setup = DetectTlsNotBeforeSetup; - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Free = DetectTlsValidityFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_NOTBEFORE].RegisterTests = TlsNotBeforeRegisterTests; -#endif - - sigmatch_table[DETECT_AL_TLS_NOTAFTER].name = "tls_cert_notafter"; - sigmatch_table[DETECT_AL_TLS_NOTAFTER].desc = "match TLS certificate notAfter field"; - sigmatch_table[DETECT_AL_TLS_NOTAFTER].url = "/rules/tls-keywords.html#tls-cert-notafter"; - sigmatch_table[DETECT_AL_TLS_NOTAFTER].AppLayerTxMatch = DetectTlsValidityMatch; - sigmatch_table[DETECT_AL_TLS_NOTAFTER].Setup = DetectTlsNotAfterSetup; - sigmatch_table[DETECT_AL_TLS_NOTAFTER].Free = DetectTlsValidityFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_NOTAFTER].RegisterTests = TlsNotAfterRegisterTests; -#endif - - sigmatch_table[DETECT_AL_TLS_EXPIRED].name = "tls_cert_expired"; - sigmatch_table[DETECT_AL_TLS_EXPIRED].desc = "match expired TLS certificates"; - sigmatch_table[DETECT_AL_TLS_EXPIRED].url = "/rules/tls-keywords.html#tls-cert-expired"; - sigmatch_table[DETECT_AL_TLS_EXPIRED].AppLayerTxMatch = DetectTlsValidityMatch; - sigmatch_table[DETECT_AL_TLS_EXPIRED].Setup = DetectTlsExpiredSetup; - sigmatch_table[DETECT_AL_TLS_EXPIRED].Free = DetectTlsValidityFree; - sigmatch_table[DETECT_AL_TLS_EXPIRED].flags = SIGMATCH_NOOPT; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_EXPIRED].RegisterTests = TlsExpiredRegisterTests; -#endif - - sigmatch_table[DETECT_AL_TLS_VALID].name = "tls_cert_valid"; - sigmatch_table[DETECT_AL_TLS_VALID].desc = "match valid TLS certificates"; - sigmatch_table[DETECT_AL_TLS_VALID].url = "/rules/tls-keywords.html#tls-cert-valid"; - sigmatch_table[DETECT_AL_TLS_VALID].AppLayerTxMatch = DetectTlsValidityMatch; - sigmatch_table[DETECT_AL_TLS_VALID].Setup = DetectTlsValidSetup; - sigmatch_table[DETECT_AL_TLS_VALID].Free = DetectTlsValidityFree; - sigmatch_table[DETECT_AL_TLS_VALID].flags = SIGMATCH_NOOPT; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_VALID].RegisterTests = TlsValidRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister2("tls_validity", ALPROTO_TLS, SIG_FLAG_TOCLIENT, - TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); - - g_tls_validity_buffer_id = DetectBufferTypeGetByName("tls_validity"); -} - -/** - * \internal - * \brief Function to match validity field in a tls certificate. - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectTlsValidityData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectTlsValidityMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - SCEnter(); - - SSLState *ssl_state = (SSLState *)state; - if (ssl_state == NULL) { - SCLogDebug("no tls state, no match"); - SCReturnInt(0); - } - - int ret = 0; - - SSLStateConnp *connp = NULL; - if (flags & STREAM_TOSERVER) - connp = &ssl_state->client_connp; - else - connp = &ssl_state->server_connp; - - const DetectTlsValidityData *dd = (const DetectTlsValidityData *)ctx; - - time_t cert_epoch = 0; - if (dd->type == DETECT_TLS_TYPE_NOTBEFORE) - cert_epoch = connp->cert0_not_before; - else if (dd->type == DETECT_TLS_TYPE_NOTAFTER) - cert_epoch = connp->cert0_not_after; - - if (cert_epoch == 0) - SCReturnInt(0); - - if ((dd->mode & DETECT_TLS_VALIDITY_EQ) && cert_epoch == dd->epoch) - ret = 1; - else if ((dd->mode & DETECT_TLS_VALIDITY_LT) && cert_epoch <= dd->epoch) - ret = 1; - else if ((dd->mode & DETECT_TLS_VALIDITY_GT) && cert_epoch >= dd->epoch) - ret = 1; - else if ((dd->mode & DETECT_TLS_VALIDITY_RA) && - cert_epoch >= dd->epoch && cert_epoch <= dd->epoch2) - ret = 1; - else if ((dd->mode & DETECT_TLS_VALIDITY_EX) && (time_t)SCTIME_SECS(f->lastts) > cert_epoch) - ret = 1; - else if ((dd->mode & DETECT_TLS_VALIDITY_VA) && (time_t)SCTIME_SECS(f->lastts) <= cert_epoch) - ret = 1; - - SCReturnInt(ret); -} - -/** - * \internal - * \brief Function to check if string is epoch. - * - * \param string Date string. - * - * \retval epoch time on success. - * \retval LONG_MIN on failure. - */ -static time_t StringIsEpoch (char *string) -{ - if (strlen(string) == 0) - return LONG_MIN; - - /* We assume that the date string is epoch if it consists of only - digits. */ - char *sp = string; - while (*sp) { - if (isdigit(*sp++) == 0) - return LONG_MIN; - } - - return strtol(string, NULL, 10); -} - -/** - * \internal - * \brief Function to convert date string to epoch. - * - * \param string Date string. - * - * \retval epoch on success. - * \retval 0 on failure. - */ -static time_t DateStringToEpoch (char *string) -{ - int r = 0; - struct tm tm; - const char *patterns[] = { - /* ISO 8601 */ - "%Y-%m", - "%Y-%m-%d", - "%Y-%m-%d %H", - "%Y-%m-%d %H:%M", - "%Y-%m-%d %H:%M:%S", - "%Y-%m-%dT%H", - "%Y-%m-%dT%H:%M", - "%Y-%m-%dT%H:%M:%S", - "%H:%M", - "%H:%M:%S", - }; - - /* Skip leading whitespace. */ - while (isspace(*string)) - string++; - - size_t inlen, oldlen; - - oldlen = inlen = strlen(string); - - /* Skip trailing whitespace */ - while (inlen > 0 && isspace(string[inlen - 1])) - inlen--; - - char tmp[inlen + 1]; - - if (inlen < oldlen) { - strlcpy(tmp, string, inlen + 1); - string = tmp; - } - - time_t epoch = StringIsEpoch(string); - if (epoch != LONG_MIN) { - return epoch; - } - - r = SCStringPatternToTime(string, patterns, 10, &tm); - - if (r != 0) - return LONG_MIN; - - return SCMkTimeUtc(&tm); -} - -/** - * \internal - * \brief Function to parse options passed via tls validity keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectTlsValidityData on success. - * \retval NULL on failure. - */ -static DetectTlsValidityData *DetectTlsValidityParse (const char *rawstr) -{ - DetectTlsValidityData *dd = NULL; - char mode[2] = ""; - char value1[20] = ""; - char value2[20] = ""; - char range[3] = ""; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 3 || ret > 5) { - SCLogError("Parse error %s", rawstr); - goto error; - } - - size_t pcre2len = sizeof(mode); - int res = SC_Pcre2SubstringCopy(match, 1, (PCRE2_UCHAR8 *)mode, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("mode \"%s\"", mode); - - pcre2len = sizeof(value1); - res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)value1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("value1 \"%s\"", value1); - - if (ret > 3) { - pcre2len = sizeof(range); - res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)range, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("range \"%s\"", range); - - if (ret > 4) { - pcre2len = sizeof(value2); - res = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)value2, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("value2 \"%s\"", value2); - } - } - - dd = SCMalloc(sizeof(DetectTlsValidityData)); - if (unlikely(dd == NULL)) - goto error; - - dd->epoch = 0; - dd->epoch2 = 0; - dd->mode = 0; - - if (strlen(mode) > 0) { - if (mode[0] == '<') - dd->mode |= DETECT_TLS_VALIDITY_LT; - else if (mode[0] == '>') - dd->mode |= DETECT_TLS_VALIDITY_GT; - } - - if (strlen(range) > 0) { - if (strcmp("<>", range) == 0) - dd->mode |= DETECT_TLS_VALIDITY_RA; - } - - if (strlen(range) != 0 && strlen(mode) != 0) { - SCLogError("Range specified but mode also set"); - goto error; - } - - if (dd->mode == 0) { - dd->mode |= DETECT_TLS_VALIDITY_EQ; - } - - /* set the first value */ - dd->epoch = DateStringToEpoch(value1); - if (dd->epoch == LONG_MIN) - goto error; - - /* set the second value if specified */ - if (strlen(value2) > 0) { - if (!(dd->mode & DETECT_TLS_VALIDITY_RA)) { - SCLogError("Multiple tls validity values specified but mode is not range"); - goto error; - } - - dd->epoch2 = DateStringToEpoch(value2); - if (dd->epoch2 == LONG_MIN) - goto error; - - if (dd->epoch2 <= dd->epoch) { - SCLogError("Second value in range must not be smaller than the first"); - goto error; - } - } - pcre2_match_data_free(match); - return dd; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (dd) - SCFree(dd); - return NULL; -} - -/** - * \brief Function to add the parsed tls_cert_expired into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - DetectTlsValidityData *dd = NULL; - - SCLogDebug("\'%s\'", rawstr); - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - dd = SCCalloc(1, sizeof(DetectTlsValidityData)); - if (dd == NULL) { - SCLogError("Allocation \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - dd->mode = DETECT_TLS_VALIDITY_EX; - dd->type = DETECT_TLS_TYPE_NOTAFTER; - dd->epoch = 0; - dd->epoch2 = 0; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_EXPIRED, (SigMatchCtx *)dd, - g_tls_validity_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectTlsValidityFree(de_ctx, dd); - return -1; -} - -/** - * \brief Function to add the parsed tls_cert_valid into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - DetectTlsValidityData *dd = NULL; - - SCLogDebug("\'%s\'", rawstr); - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - dd = SCCalloc(1, sizeof(DetectTlsValidityData)); - if (dd == NULL) { - SCLogError("Allocation \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - dd->mode = DETECT_TLS_VALIDITY_VA; - dd->type = DETECT_TLS_TYPE_NOTAFTER; - dd->epoch = 0; - dd->epoch2 = 0; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_VALID, (SigMatchCtx *)dd, - g_tls_validity_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectTlsValidityFree(de_ctx, dd); - return -1; -} - -/** - * \brief Function to add the parsed tls_notbefore into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectTlsNotBeforeSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - uint8_t type = DETECT_TLS_TYPE_NOTBEFORE; - int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); - - SCReturnInt(r); -} - -/** - * \brief Function to add the parsed tls_notafter into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectTlsNotAfterSetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr) -{ - uint8_t type = DETECT_TLS_TYPE_NOTAFTER; - int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); - - SCReturnInt(r); -} - -/** - * \brief Function to add the parsed tls validity field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, - const char *rawstr, uint8_t type) -{ - DetectTlsValidityData *dd = NULL; - - SCLogDebug("\'%s\'", rawstr); - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - dd = DetectTlsValidityParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (type == DETECT_TLS_TYPE_NOTBEFORE) { - dd->type = DETECT_TLS_TYPE_NOTBEFORE; - } - else if (type == DETECT_TLS_TYPE_NOTAFTER) { - dd->type = DETECT_TLS_TYPE_NOTAFTER; - } - else { - goto error; - } - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_NOTAFTER, (SigMatchCtx *)dd, - g_tls_validity_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectTlsValidityFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectTlsValidityData. - * - * \param de_ptr Pointer to DetectTlsValidityData. - */ -void DetectTlsValidityFree(DetectEngineCtx *de_ctx, void *de_ptr) -{ - DetectTlsValidityData *dd = (DetectTlsValidityData *)de_ptr; - if (dd) - SCFree(dd); -} - -#ifdef UNITTESTS -#include "tests/detect-tls-cert-validity.c" -#endif diff --git a/src/detect-tls-cert-validity.h b/src/detect-tls-cert-validity.h deleted file mode 100644 index 256be6b4b2b5..000000000000 --- a/src/detect-tls-cert-validity.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - */ - -#ifndef __DETECT_TLS_VALIDITY_H__ -#define __DETECT_TLS_VALIDITY_H__ - -#define DETECT_TLS_VALIDITY_EQ (1) /* equal */ -#define DETECT_TLS_VALIDITY_LT (1<<1) /* less than */ -#define DETECT_TLS_VALIDITY_GT (1<<2) /* greater than */ -#define DETECT_TLS_VALIDITY_RA (1<<3) /* range */ - -/* Used by tls_cert_expired */ -#define DETECT_TLS_VALIDITY_EX (1<<4) /* expired */ - -/* Used by tls_cert_valid */ -#define DETECT_TLS_VALIDITY_VA (1<<5) /* valid */ - -#define DETECT_TLS_TYPE_NOTBEFORE 0 -#define DETECT_TLS_TYPE_NOTAFTER 1 - -typedef struct DetectTlsValidityData_ { - time_t epoch; - time_t epoch2; - uint8_t mode; - uint8_t type; -} DetectTlsValidityData; - -/* prototypes */ -void DetectTlsValidityRegister (void); - -#endif /* __DETECT_TLS_VALIDITY_H__ */ diff --git a/src/detect-tls-certs.c b/src/detect-tls-certs.c deleted file mode 100644 index 9ff185c494d6..000000000000 --- a/src/detect-tls-certs.c +++ /dev/null @@ -1,363 +0,0 @@ -/* Copyright (C) 2019-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for tls.certs keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-certs.h" -#include "detect-engine-uint.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-profiling.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsCertsSetup(DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTlsCertsRegisterTests(void); -#endif -static uint8_t DetectEngineInspectTlsCerts(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id); -static int PrefilterMpmTlsCertsRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, - const DetectBufferMpmRegistry *mpm_reg, int list_id); - -static int g_tls_certs_buffer_id = 0; - -struct TlsCertsGetDataArgs { - uint32_t local_id; /**< used as index into thread inspect array */ - SSLCertsChain *cert; -}; - -typedef struct PrefilterMpmTlsCerts { - int list_id; - const MpmCtx *mpm_ctx; - const DetectEngineTransforms *transforms; -} PrefilterMpmTlsCerts; - -/** - * \brief Registration function for keyword: tls.certs - */ -void DetectTlsCertsRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_CERTS].name = "tls.certs"; - sigmatch_table[DETECT_AL_TLS_CERTS].desc = "sticky buffer to match the TLS certificate buffer"; - sigmatch_table[DETECT_AL_TLS_CERTS].url = "/rules/tls-keywords.html#tls-certs"; - sigmatch_table[DETECT_AL_TLS_CERTS].Setup = DetectTlsCertsSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_CERTS].RegisterTests = DetectTlsCertsRegisterTests; -#endif - sigmatch_table[DETECT_AL_TLS_CERTS].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_CERTS].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("tls.certs", ALPROTO_TLS, - SIG_FLAG_TOCLIENT, TLS_STATE_CERT_READY, - DetectEngineInspectTlsCerts, NULL); - - DetectAppLayerMpmRegister2("tls.certs", SIG_FLAG_TOCLIENT, 2, - PrefilterMpmTlsCertsRegister, NULL, ALPROTO_TLS, - TLS_STATE_CERT_READY); - - DetectAppLayerInspectEngineRegister2("tls.certs", ALPROTO_TLS, SIG_FLAG_TOSERVER, - TLS_STATE_CERT_READY, DetectEngineInspectTlsCerts, NULL); - - DetectAppLayerMpmRegister2("tls.certs", SIG_FLAG_TOSERVER, 2, PrefilterMpmTlsCertsRegister, - NULL, ALPROTO_TLS, TLS_STATE_CERT_READY); - - DetectBufferTypeSetDescriptionByName("tls.certs", "TLS certificate"); - - DetectBufferTypeSupportsMultiInstance("tls.certs"); - - g_tls_certs_buffer_id = DetectBufferTypeGetByName("tls.certs"); -} - -/** - * \brief This function setup the tls.certs modifier keyword - * - * \param de_ctx Pointer to the Detect Engine Context - * \param s Pointer to the Signature to which the keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsCertsSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_certs_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *TlsCertsGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - struct TlsCertsGetDataArgs *cbdata, int list_id) -{ - SCEnter(); - - InspectionBuffer *buffer = - InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id); - if (buffer == NULL || buffer->initialized) - return buffer; - - const SSLState *ssl_state = (SSLState *)f->alstate; - const SSLStateConnp *connp; - - if (f->flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (TAILQ_EMPTY(&connp->certs)) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - if (cbdata->cert == NULL) { - cbdata->cert = TAILQ_FIRST(&connp->certs); - } else { - cbdata->cert = TAILQ_NEXT(cbdata->cert, next); - } - if (cbdata->cert == NULL) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - - InspectionBufferSetupMulti(buffer, transforms, cbdata->cert->cert_data, cbdata->cert->cert_len); - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -static uint8_t DetectEngineInspectTlsCerts(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) -{ - const DetectEngineTransforms *transforms = NULL; - if (!engine->mpm) { - transforms = engine->v2.transforms; - } - - struct TlsCertsGetDataArgs cbdata = { 0, NULL }; - - while (1) - { - InspectionBuffer *buffer = TlsCertsGetData(det_ctx, transforms, f, - &cbdata, engine->sm_list); - if (buffer == NULL || buffer->inspect == NULL) - break; - - const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, - (uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset, - DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE); - if (match) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } - - cbdata.local_id++; - } - - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -static void PrefilterTxTlsCerts(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, - Flow *f, void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags) -{ - SCEnter(); - - const PrefilterMpmTlsCerts *ctx = (const PrefilterMpmTlsCerts *)pectx; - const MpmCtx *mpm_ctx = ctx->mpm_ctx; - const int list_id = ctx->list_id; - - struct TlsCertsGetDataArgs cbdata = { 0, NULL }; - - while (1) - { - InspectionBuffer *buffer = TlsCertsGetData(det_ctx, ctx->transforms, - f, &cbdata, list_id); - if (buffer == NULL) - break; - - if (buffer->inspect_len >= mpm_ctx->minlen) { - (void)mpm_table[mpm_ctx->mpm_type].Search( - mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len); - PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len); - } - - cbdata.local_id++; - } -} - -static void PrefilterMpmTlsCertsFree(void *ptr) -{ - SCFree(ptr); -} - -static int PrefilterMpmTlsCertsRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, - const DetectBufferMpmRegistry *mpm_reg, int list_id) -{ - PrefilterMpmTlsCerts *pectx = SCCalloc(1, sizeof(*pectx)); - if (pectx == NULL) - return -1; - - pectx->list_id = list_id; - pectx->mpm_ctx = mpm_ctx; - pectx->transforms = &mpm_reg->transforms; - - return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxTlsCerts, - mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress, - pectx, PrefilterMpmTlsCertsFree, mpm_reg->name); -} - -static int g_tls_cert_buffer_id = 0; -#define BUFFER_NAME "tls_validity" -#define KEYWORD_ID DETECT_AL_TLS_CHAIN_LEN -#define KEYWORD_NAME "tls.cert_chain_len" -#define KEYWORD_DESC "match TLS certificate chain length" -#define KEYWORD_URL "/rules/tls-keywords.html#tls-cert-chain-len" - -/** - * \internal - * \brief Function to match cert chain length in TLS - * - * \param t Pointer to thread vars. - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param s Pointer to the Signature. - * \param m Pointer to the sigmatch that we will cast into - * DetectU64Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectTLSCertChainLenMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - SSLState *ssl_state = state; - if (flags & STREAM_TOCLIENT) { - SSLStateConnp *connp = &ssl_state->server_connp; - uint32_t cnt = 0; - SSLCertsChain *cert; - TAILQ_FOREACH (cert, &connp->certs, next) { - cnt++; - } - SCLogDebug("%u certs in chain", cnt); - - const DetectU32Data *dd = (const DetectU32Data *)ctx; - if (DetectU32Match(cnt, dd)) { - SCReturnInt(1); - } - } - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to free memory associated with DetectU64Data. - * - * \param de_ptr Pointer to DetectU64Data. - */ -static void DetectTLSCertChainLenFree(DetectEngineCtx *de_ctx, void *ptr) -{ - rs_detect_u32_free(ptr); -} - -/** - * \brief Function to add the parsed tls cert chain len field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * \param type Defines if this is notBefore or notAfter. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectTLSCertChainLenSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - DetectU32Data *dd = DetectU32Parse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed for %s", rawstr, sigmatch_table[KEYWORD_ID].name); - return -1; - } - - if (SigMatchAppendSMToList(de_ctx, s, KEYWORD_ID, (SigMatchCtx *)dd, g_tls_cert_buffer_id) == - NULL) { - rs_detect_u32_free(dd); - return -1; - } - return 0; -} - -void DetectTlsCertChainLenRegister(void) -{ - sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME; - sigmatch_table[KEYWORD_ID].desc = KEYWORD_DESC; - sigmatch_table[KEYWORD_ID].url = KEYWORD_URL; - sigmatch_table[KEYWORD_ID].AppLayerTxMatch = DetectTLSCertChainLenMatch; - sigmatch_table[KEYWORD_ID].Setup = DetectTLSCertChainLenSetup; - sigmatch_table[KEYWORD_ID].Free = DetectTLSCertChainLenFree; - - DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_TLS, SIG_FLAG_TOCLIENT, - TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); - - g_tls_cert_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); -} - -#ifdef UNITTESTS -#include "tests/detect-tls-certs.c" -#endif diff --git a/src/detect-tls-ja3-hash.c b/src/detect-tls-ja3-hash.c deleted file mode 100644 index 7660fde4c2a0..000000000000 --- a/src/detect-tls-ja3-hash.c +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for ja3.hash keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-ja3-hash.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "conf.h" -#include "conf-yaml-loader.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-ja3.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsJa3HashSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static void DetectTlsJa3HashSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); -static bool DetectTlsJa3HashValidateCallback(const Signature *s, - const char **sigerror); -static int g_tls_ja3_hash_buffer_id = 0; - -/** - * \brief Registration function for keyword: ja3_hash - */ -void DetectTlsJa3HashRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_JA3_HASH].name = "ja3.hash"; - sigmatch_table[DETECT_AL_TLS_JA3_HASH].alias = "ja3_hash"; - sigmatch_table[DETECT_AL_TLS_JA3_HASH].desc = "sticky buffer to match the JA3 hash buffer"; - sigmatch_table[DETECT_AL_TLS_JA3_HASH].url = "/rules/ja3-keywords.html#ja3-hash"; - sigmatch_table[DETECT_AL_TLS_JA3_HASH].Setup = DetectTlsJa3HashSetup; - sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("ja3.hash", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("ja3.hash", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0); - - DetectAppLayerMpmRegister2("ja3.hash", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - Ja3DetectGetHash, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2("ja3.hash", ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, Ja3DetectGetHash); - - DetectBufferTypeSetDescriptionByName("ja3.hash", "TLS JA3 hash"); - - DetectBufferTypeRegisterSetupCallback("ja3.hash", - DetectTlsJa3HashSetupCallback); - - DetectBufferTypeRegisterValidateCallback("ja3.hash", - DetectTlsJa3HashValidateCallback); - - g_tls_ja3_hash_buffer_id = DetectBufferTypeGetByName("ja3.hash"); -} - -/** - * \brief this function setup the ja3.hash modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - * \retval -2 on failure that should be silent after the first - */ -static int DetectTlsJa3HashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3_hash_buffer_id) < 0) - return -1; - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { - SCLogError("rule contains conflicting protocols."); - return -1; - } - - /* try to enable JA3 */ - SSLEnableJA3(); - - /* Check if JA3 is disabled */ - if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3_HASH)) { - SCLogError("ja3 support is not enabled"); - } - return -2; - } - s->init_data->init_flags |= SIG_FLAG_INIT_JA3; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - - if (ssl_state->client_connp.ja3_hash == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(ssl_state->client_connp.ja3_hash); - const uint8_t *data = (uint8_t *)ssl_state->client_connp.ja3_hash; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static bool DetectTlsJa3HashValidateCallback(const Signature *s, - const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3_hash_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - const DetectContentData *cd = (DetectContentData *)sm->ctx; - - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = "ja3.hash should not be used together with " - "nocase, since the rule is automatically " - "lowercased anyway which makes nocase redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - } - - if (cd->content_len == SC_MD5_HEX_LEN) - return true; - - *sigerror = "Invalid length of the specified JA3 hash (should " - "be 32 characters long). This rule will therefore " - "never match."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - return false; - } - } - return true; -} - -static void DetectTlsJa3HashSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3_hash_buffer_id) - continue; - SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - - bool changed = false; - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) { - cd->content[u] = u8_tolower(cd->content[u]); - changed = true; - } - } - - /* recreate the context if changes were made */ - if (changed) { - SpmDestroyCtx(cd->spm_ctx); - cd->spm_ctx = - SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); - } - } - } -} diff --git a/src/detect-tls-ja3-string.c b/src/detect-tls-ja3-string.c deleted file mode 100644 index 87a61bfd8738..000000000000 --- a/src/detect-tls-ja3-string.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for ja3.string keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-ja3-string.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "conf.h" -#include "conf-yaml-loader.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-ja3.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsJa3StringSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static int g_tls_ja3_str_buffer_id = 0; - -/** - * \brief Registration function for keyword: ja3.string - */ -void DetectTlsJa3StringRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_JA3_STRING].name = "ja3.string"; - sigmatch_table[DETECT_AL_TLS_JA3_STRING].alias = "ja3_string"; - sigmatch_table[DETECT_AL_TLS_JA3_STRING].desc = "sticky buffer to match the JA3 string buffer"; - sigmatch_table[DETECT_AL_TLS_JA3_STRING].url = "/rules/ja3-keywords.html#ja3-string"; - sigmatch_table[DETECT_AL_TLS_JA3_STRING].Setup = DetectTlsJa3StringSetup; - sigmatch_table[DETECT_AL_TLS_JA3_STRING].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_JA3_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("ja3.string", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("ja3.string", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0); - - DetectAppLayerMpmRegister2("ja3.string", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - Ja3DetectGetString, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2("ja3.string", ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, Ja3DetectGetString); - - DetectBufferTypeSetDescriptionByName("ja3.string", "TLS JA3 string"); - - g_tls_ja3_str_buffer_id = DetectBufferTypeGetByName("ja3.string"); -} - -/** - * \brief this function setup the ja3.string modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsJa3StringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3_str_buffer_id) < 0) - return -1; - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { - SCLogError("rule contains conflicting protocols."); - return -1; - } - - /* try to enable JA3 */ - SSLEnableJA3(); - - /* Check if JA3 is disabled */ - if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3_STRING)) { - SCLogError("ja3(s) support is not enabled"); - } - return -2; - } - s->init_data->init_flags |= SIG_FLAG_INIT_JA3; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - - if (ssl_state->client_connp.ja3_str == NULL || - ssl_state->client_connp.ja3_str->data == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(ssl_state->client_connp.ja3_str->data); - const uint8_t *data = (uint8_t *)ssl_state->client_connp.ja3_str->data; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} diff --git a/src/detect-tls-ja3s-hash.c b/src/detect-tls-ja3s-hash.c deleted file mode 100644 index 583566012d08..000000000000 --- a/src/detect-tls-ja3s-hash.c +++ /dev/null @@ -1,225 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for ja3s.hash keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-ja3s-hash.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "conf.h" -#include "conf-yaml-loader.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-ja3.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsJa3SHashSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static void DetectTlsJa3SHashSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s); -static bool DetectTlsJa3SHashValidateCallback(const Signature *s, - const char **sigerror); -static int g_tls_ja3s_hash_buffer_id = 0; - -/** - * \brief Registration function for keyword: ja3s.hash - */ -void DetectTlsJa3SHashRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_JA3S_HASH].name = "ja3s.hash"; - sigmatch_table[DETECT_AL_TLS_JA3S_HASH].desc = "sticky buffer to match the JA3S hash buffer"; - sigmatch_table[DETECT_AL_TLS_JA3S_HASH].url = "/rules/ja3-keywords.html#ja3s-hash"; - sigmatch_table[DETECT_AL_TLS_JA3S_HASH].Setup = DetectTlsJa3SHashSetup; - sigmatch_table[DETECT_AL_TLS_JA3S_HASH].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_JA3S_HASH].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("ja3s.hash", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("ja3s.hash", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0); - - DetectAppLayerMpmRegister2("ja3s.hash", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - Ja3DetectGetHash, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2("ja3s.hash", ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, Ja3DetectGetHash); - - DetectBufferTypeSetDescriptionByName("ja3s.hash", "TLS JA3S hash"); - - DetectBufferTypeRegisterSetupCallback("ja3s.hash", - DetectTlsJa3SHashSetupCallback); - - DetectBufferTypeRegisterValidateCallback("ja3s.hash", - DetectTlsJa3SHashValidateCallback); - - g_tls_ja3s_hash_buffer_id = DetectBufferTypeGetByName("ja3s.hash"); -} - -/** - * \brief this function setup the ja3s.hash modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsJa3SHashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3s_hash_buffer_id) < 0) - return -1; - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { - SCLogError("rule contains conflicting protocols."); - return -1; - } - - /* try to enable JA3 */ - SSLEnableJA3(); - - /* Check if JA3 is disabled */ - if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3S_HASH)) { - SCLogError("ja3(s) support is not enabled"); - } - return -2; - } - s->init_data->init_flags |= SIG_FLAG_INIT_JA3; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - - if (ssl_state->server_connp.ja3_hash == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(ssl_state->server_connp.ja3_hash); - const uint8_t *data = (uint8_t *)ssl_state->server_connp.ja3_hash; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} - -static bool DetectTlsJa3SHashValidateCallback(const Signature *s, - const char **sigerror) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3s_hash_buffer_id) - continue; - const SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - const DetectContentData *cd = (DetectContentData *)sm->ctx; - - if (cd->flags & DETECT_CONTENT_NOCASE) { - *sigerror = "ja3s.hash should not be used together with " - "nocase, since the rule is automatically " - "lowercased anyway which makes nocase redundant."; - SCLogWarning("rule %u: %s", s->id, *sigerror); - } - - if (cd->content_len == SC_MD5_HEX_LEN) - return true; - - *sigerror = "Invalid length of the specified JA3S hash (should " - "be 32 characters long). This rule will therefore " - "never match."; - SCLogError("rule %u: %s", s->id, *sigerror); - return false; - } - } - return true; -} - -static void DetectTlsJa3SHashSetupCallback(const DetectEngineCtx *de_ctx, - Signature *s) -{ - for (uint32_t x = 0; x < s->init_data->buffer_index; x++) { - if (s->init_data->buffers[x].id != (uint32_t)g_tls_ja3s_hash_buffer_id) - continue; - SigMatch *sm = s->init_data->buffers[x].head; - for (; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - - bool changed = false; - uint32_t u; - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) { - cd->content[u] = u8_tolower(cd->content[u]); - changed = true; - } - } - - /* recreate the context if changes were made */ - if (changed) { - SpmDestroyCtx(cd->spm_ctx); - cd->spm_ctx = - SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx); - } - } - } -} diff --git a/src/detect-tls-ja3s-string.c b/src/detect-tls-ja3s-string.c deleted file mode 100644 index 0f7f7d61d067..000000000000 --- a/src/detect-tls-ja3s-string.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright (C) 2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for ja3s.string keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-content.h" -#include "detect-pcre.h" -#include "detect-tls-ja3s-string.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "conf.h" -#include "conf-yaml-loader.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" -#include "util-ja3.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsJa3SStringSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static int g_tls_ja3s_str_buffer_id = 0; - -/** - * \brief Registration function for keyword: ja3s.string - */ -void DetectTlsJa3SStringRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_JA3S_STRING].name = "ja3s.string"; - sigmatch_table[DETECT_AL_TLS_JA3S_STRING].desc = - "sticky buffer to match the JA3S string buffer"; - sigmatch_table[DETECT_AL_TLS_JA3S_STRING].url = "/rules/ja3-keywords.html#ja3s-string"; - sigmatch_table[DETECT_AL_TLS_JA3S_STRING].Setup = DetectTlsJa3SStringSetup; - sigmatch_table[DETECT_AL_TLS_JA3S_STRING].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_JA3S_STRING].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("ja3s.string", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("ja3s.string", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0); - - DetectAppLayerMpmRegister2("ja3s.string", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - Ja3DetectGetString, ALPROTO_QUIC, 1); - - DetectAppLayerInspectEngineRegister2("ja3s.string", ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, Ja3DetectGetString); - - DetectBufferTypeSetDescriptionByName("ja3s.string", "TLS JA3S string"); - - g_tls_ja3s_str_buffer_id = DetectBufferTypeGetByName("ja3s.string"); -} - -/** - * \brief this function setup the ja3s.string modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsJa3SStringSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_ja3s_str_buffer_id) < 0) - return -1; - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) { - SCLogError("rule contains conflicting protocols."); - return -1; - } - - /* try to enable JA3 */ - SSLEnableJA3(); - - /* Check if JA3 is disabled */ - if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) { - if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3S_STRING)) { - SCLogError("ja3(s) support is not enabled"); - } - return -2; - } - s->init_data->init_flags |= SIG_FLAG_INIT_JA3; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - - if (ssl_state->server_connp.ja3_str == NULL || - ssl_state->server_connp.ja3_str->data == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(ssl_state->server_connp.ja3_str->data); - const uint8_t *data = (uint8_t *)ssl_state->server_connp.ja3_str->data; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} diff --git a/src/detect-tls-random.c b/src/detect-tls-random.c deleted file mode 100644 index fc4369ab1861..000000000000 --- a/src/detect-tls-random.c +++ /dev/null @@ -1,283 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-content.h" - -#include "flow.h" -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" -#include "detect-engine-prefilter.h" -#include "detect-tls-random.h" - -#define DETECT_TLS_RANDOM_TIME_LEN 4 -#define DETECT_TLS_RANDOM_BYTES_LEN 28 - -static int DetectTlsRandomTimeSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectTlsRandomBytesSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectTlsRandomSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetRandomTimeData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id); -static InspectionBuffer *GetRandomBytesData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id); -static InspectionBuffer *GetRandomData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id); - -static int g_tls_random_time_buffer_id = 0; -static int g_tls_random_bytes_buffer_id = 0; -static int g_tls_random_buffer_id = 0; - -void DetectTlsRandomTimeRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].name = "tls.random_time"; - sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].desc = "sticky buffer to match specifically and only " - "on the first 4 bytes of a TLS random buffer"; - sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].url = "/rules/tls-keywords.html#tls-random-time"; - sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].Setup = DetectTlsRandomTimeSetup; - sigmatch_table[DETECT_AL_TLS_RANDOM_TIME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - /* Register engine for Server random */ - DetectAppLayerInspectEngineRegister2("tls.random_time", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetRandomTimeData); - DetectAppLayerMpmRegister2("tls.random_time", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRandomTimeData, ALPROTO_TLS, 0); - - /* Register engine for Client random */ - DetectAppLayerInspectEngineRegister2("tls.random_time", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetRandomTimeData); - DetectAppLayerMpmRegister2("tls.random_time", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetRandomTimeData, ALPROTO_TLS, 0); - - DetectBufferTypeSetDescriptionByName("tls.random_time", "TLS Random Time"); - - g_tls_random_time_buffer_id = DetectBufferTypeGetByName("tls.random_time"); -} - -void DetectTlsRandomBytesRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].name = "tls.random_bytes"; - sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].desc = - "sticky buffer to match specifically and only on the last 28 bytes of a TLS random " - "buffer"; - sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].url = "/rules/tls-keywords.html#tls-random-bytes"; - sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].Setup = DetectTlsRandomBytesSetup; - sigmatch_table[DETECT_AL_TLS_RANDOM_BYTES].flags |= - SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - /* Register engine for Server random */ - DetectAppLayerInspectEngineRegister2("tls.random_bytes", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetRandomBytesData); - DetectAppLayerMpmRegister2("tls.random_bytes", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetRandomBytesData, ALPROTO_TLS, 0); - - /* Register engine for Client random */ - DetectAppLayerInspectEngineRegister2("tls.random_bytes", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetRandomBytesData); - DetectAppLayerMpmRegister2("tls.random_bytes", SIG_FLAG_TOCLIENT, 2, - PrefilterGenericMpmRegister, GetRandomBytesData, ALPROTO_TLS, 0); - - DetectBufferTypeSetDescriptionByName("tls.random_bytes", "TLS Random Bytes"); - - g_tls_random_bytes_buffer_id = DetectBufferTypeGetByName("tls.random_bytes"); -} - -/** - * \brief Registration function for keyword: tls.random - */ -void DetectTlsRandomRegister(void) -{ - DetectTlsRandomTimeRegister(); - DetectTlsRandomBytesRegister(); - - sigmatch_table[DETECT_AL_TLS_RANDOM].name = "tls.random"; - sigmatch_table[DETECT_AL_TLS_RANDOM].desc = - "sticky buffer to match specifically and only on a TLS random buffer"; - sigmatch_table[DETECT_AL_TLS_RANDOM].url = "/rules/tls-keywords.html#tls-random"; - sigmatch_table[DETECT_AL_TLS_RANDOM].Setup = DetectTlsRandomSetup; - sigmatch_table[DETECT_AL_TLS_RANDOM].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - /* Register engine for Server random */ - DetectAppLayerInspectEngineRegister2("tls.random", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetRandomData); - DetectAppLayerMpmRegister2("tls.random", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetRandomData, ALPROTO_TLS, 0); - - /* Register engine for Client random */ - DetectAppLayerInspectEngineRegister2("tls.random", ALPROTO_TLS, SIG_FLAG_TOCLIENT, 0, - DetectEngineInspectBufferGeneric, GetRandomData); - DetectAppLayerMpmRegister2("tls.random", SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, - GetRandomData, ALPROTO_TLS, 0); - - DetectBufferTypeSetDescriptionByName("tls.random", "TLS Random"); - - g_tls_random_buffer_id = DetectBufferTypeGetByName("tls.random"); -} - -/** - * \brief this function setup the tls.random_time sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsRandomTimeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_random_time_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -/** - * \brief this function setup the tls.random_bytes sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsRandomBytesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_random_bytes_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -/** - * \brief this function setup the tls.random sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsRandomSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_random_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetRandomTimeData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - if (flow_flags & STREAM_TOSERVER) { - if (!(ssl_state->flags & TLS_TS_RANDOM_SET)) - return NULL; - } else { - if (!(ssl_state->flags & TLS_TC_RANDOM_SET)) - return NULL; - } - const uint32_t data_len = DETECT_TLS_RANDOM_TIME_LEN; - const uint8_t *data; - if (flow_flags & STREAM_TOSERVER) { - data = ssl_state->server_connp.random; - } else { - data = ssl_state->client_connp.random; - } - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -static InspectionBuffer *GetRandomBytesData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - if (flow_flags & STREAM_TOSERVER) { - if (!(ssl_state->flags & TLS_TS_RANDOM_SET)) - return NULL; - } else { - if (!(ssl_state->flags & TLS_TC_RANDOM_SET)) - return NULL; - } - const uint32_t data_len = DETECT_TLS_RANDOM_BYTES_LEN; - const uint8_t *data; - if (flow_flags & STREAM_TOSERVER) { - data = ssl_state->server_connp.random + DETECT_TLS_RANDOM_TIME_LEN; - } else { - data = ssl_state->client_connp.random + DETECT_TLS_RANDOM_TIME_LEN; - } - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -static InspectionBuffer *GetRandomData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - if (flow_flags & STREAM_TOSERVER) { - if (!(ssl_state->flags & TLS_TS_RANDOM_SET)) - return NULL; - } else { - if (!(ssl_state->flags & TLS_TC_RANDOM_SET)) - return NULL; - } - const uint32_t data_len = TLS_RANDOM_LEN; - const uint8_t *data; - if (flow_flags & STREAM_TOSERVER) { - data = ssl_state->server_connp.random; - } else { - data = ssl_state->client_connp.random; - } - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c deleted file mode 100644 index 69b066e8e979..000000000000 --- a/src/detect-tls-sni.c +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Implements support for tls.sni keyword. - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-ssl.h" -#include "detect-engine-prefilter.h" -#include "detect-tls-sni.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" - -static int DetectTlsSniSetup(DetectEngineCtx *, Signature *, const char *); -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); -static int g_tls_sni_buffer_id = 0; - -/** - * \brief Registration function for keyword: tls.sni - */ -void DetectTlsSniRegister(void) -{ - sigmatch_table[DETECT_AL_TLS_SNI].name = "tls.sni"; - sigmatch_table[DETECT_AL_TLS_SNI].alias = "tls_sni"; - sigmatch_table[DETECT_AL_TLS_SNI].desc = - "sticky buffer to match specifically and only on the TLS SNI buffer"; - sigmatch_table[DETECT_AL_TLS_SNI].url = "/rules/tls-keywords.html#tls-sni"; - sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup; - sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister2("tls.sni", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0, - DetectEngineInspectBufferGeneric, GetData); - - DetectAppLayerMpmRegister2("tls.sni", SIG_FLAG_TOSERVER, 2, - PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0); - - DetectBufferTypeSetDescriptionByName("tls.sni", - "TLS Server Name Indication (SNI) extension"); - - g_tls_sni_buffer_id = DetectBufferTypeGetByName("tls.sni"); -} - - -/** - * \brief this function setup the tls.sni modifier keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ -static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_tls_sni_buffer_id) < 0) - return -1; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, - const uint8_t flow_flags, void *txv, const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const SSLState *ssl_state = (SSLState *)f->alstate; - - if (ssl_state->client_connp.sni == NULL) { - return NULL; - } - - const uint32_t data_len = strlen(ssl_state->client_connp.sni); - const uint8_t *data = (uint8_t *)ssl_state->client_connp.sni; - - InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - - return buffer; -} diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c deleted file mode 100644 index f3a119d5a226..000000000000 --- a/src/detect-tls-version.c +++ /dev/null @@ -1,273 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implements the tls.version keyword - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-ssl.h" -#include "detect-tls-version.h" - -#include "stream-tcp.h" - -/** - * \brief Regex for parsing "id" option, matching number or "number" - */ -#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9\\.]+\")\\s*$" - -static DetectParseRegex parse_regex; - -static int DetectTlsVersionMatch (DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTlsVersionRegisterTests(void); -#endif -static void DetectTlsVersionFree(DetectEngineCtx *, void *); -static int g_tls_generic_list_id = 0; - -/** - * \brief Registration function for keyword: tls.version - */ -void DetectTlsVersionRegister (void) -{ - sigmatch_table[DETECT_AL_TLS_VERSION].name = "tls.version"; - sigmatch_table[DETECT_AL_TLS_VERSION].desc = "match on TLS/SSL version"; - sigmatch_table[DETECT_AL_TLS_VERSION].url = "/rules/tls-keywords.html#tls-version"; - sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerTxMatch = DetectTlsVersionMatch; - sigmatch_table[DETECT_AL_TLS_VERSION].Setup = DetectTlsVersionSetup; - sigmatch_table[DETECT_AL_TLS_VERSION].Free = DetectTlsVersionFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_AL_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests; -#endif - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); -} - -/** - * \brief match the specified version on a tls session - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectTlsVersionData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectTlsVersionMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - SCEnter(); - - const DetectTlsVersionData *tls_data = (const DetectTlsVersionData *)m; - SSLState *ssl_state = (SSLState *)state; - if (ssl_state == NULL) { - SCLogDebug("no tls state, no match"); - SCReturnInt(0); - } - - int ret = 0; - uint16_t version = 0; - SCLogDebug("looking for tls_data->ver 0x%02X (flags 0x%02X)", tls_data->ver, flags); - - if (flags & STREAM_TOCLIENT) { - version = ssl_state->server_connp.version; - SCLogDebug("server (toclient) version is 0x%02X", version); - } else if (flags & STREAM_TOSERVER) { - version = ssl_state->client_connp.version; - SCLogDebug("client (toserver) version is 0x%02X", version); - } - - if ((tls_data->flags & DETECT_TLS_VERSION_FLAG_RAW) == 0) { - /* Match all TLSv1.3 drafts as TLSv1.3 */ - if (((version >> 8) & 0xff) == 0x7f) { - version = TLS_VERSION_13; - } - } - - if (tls_data->ver == version) { - ret = 1; - } - - SCReturnInt(ret); -} - -/** - * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" - * - * \param de_ctx Pointer to the detection engine context - * \param idstr Pointer to the user provided id option - * - * \retval id_d pointer to DetectTlsVersionData on success - * \retval NULL on failure - */ -static DetectTlsVersionData *DetectTlsVersionParse (DetectEngineCtx *de_ctx, const char *str) -{ - uint16_t temp; - DetectTlsVersionData *tls = NULL; - int res = 0; - size_t pcre2len; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); - if (ret < 1 || ret > 3) { - SCLogError("invalid tls.version option"); - goto error; - } - - if (ret > 1) { - char ver_ptr[64]; - char *tmp_str; - pcre2len = sizeof(ver_ptr); - res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)ver_ptr, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - /* We have a correct id option */ - tls = SCCalloc(1, sizeof(DetectTlsVersionData)); - if (unlikely(tls == NULL)) - goto error; - - tmp_str = ver_ptr; - - /* Let's see if we need to scape "'s */ - if (tmp_str[0] == '"') - { - tmp_str[strlen(tmp_str) - 1] = '\0'; - tmp_str += 1; - } - - if (strncmp("1.0", tmp_str, 3) == 0) { - temp = TLS_VERSION_10; - } else if (strncmp("1.1", tmp_str, 3) == 0) { - temp = TLS_VERSION_11; - } else if (strncmp("1.2", tmp_str, 3) == 0) { - temp = TLS_VERSION_12; - } else if (strncmp("1.3", tmp_str, 3) == 0) { - temp = TLS_VERSION_13; - } else if ((strncmp("0x", tmp_str, 2) == 0) && (strlen(str) == 6)) { - temp = (uint16_t)strtol(tmp_str, NULL, 0); - tls->flags |= DETECT_TLS_VERSION_FLAG_RAW; - } else { - SCLogError("Invalid value"); - goto error; - } - - tls->ver = temp; - - SCLogDebug("will look for tls %"PRIu16"", tls->ver); - } - - pcre2_match_data_free(match); - return tls; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (tls != NULL) - DetectTlsVersionFree(de_ctx, tls); - return NULL; - -} - -/** - * \brief this function is used to add the parsed "id" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param idstr pointer to the user provided "id" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - DetectTlsVersionData *tls = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - tls = DetectTlsVersionParse(de_ctx, str); - if (tls == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_VERSION, (SigMatchCtx *)tls, - g_tls_generic_list_id) == NULL) { - goto error; - } - - return 0; - -error: - if (tls != NULL) - DetectTlsVersionFree(de_ctx, tls); - return -1; - -} - -/** - * \brief this function will free memory associated with DetectTlsVersionData - * - * \param id_d pointer to DetectTlsVersionData - */ -static void DetectTlsVersionFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectTlsVersionData *id_d = (DetectTlsVersionData *)ptr; - SCFree(id_d); -} - -#ifdef UNITTESTS -#include "tests/detect-tls-version.c" -#endif diff --git a/src/detect-tls-version.h b/src/detect-tls-version.h deleted file mode 100644 index fa808f39409d..000000000000 --- a/src/detect-tls-version.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __DETECT_TLS_VERSION_H__ -#define __DETECT_TLS_VERSION_H__ - -#define DETECT_TLS_VERSION_FLAG_RAW BIT_U8(0) - -typedef struct DetectTlsVersionData_ { - uint16_t ver; /** tls version to match */ - uint8_t flags; -} DetectTlsVersionData; - -/* prototypes */ -void DetectTlsVersionRegister (void); - -#endif /* __DETECT_TLS_VERSION_H__ */ - diff --git a/src/detect-tls.c b/src/detect-tls.c deleted file mode 100644 index 8a9c98fac795..000000000000 --- a/src/detect-tls.c +++ /dev/null @@ -1,623 +0,0 @@ -/* - * Copyright (C) 2011-2012 ANSSI - * Copyright (C) 2022 Open Information Security Foundation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * \author Pierre Chifflier - * - * Implements the tls.* keywords - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-content.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#include "app-layer.h" - -#include "app-layer-ssl.h" -#include "detect-tls.h" -#include "detect-tls-cert-fingerprint.h" - -#include "stream-tcp.h" - -/** - * \brief Regex for parsing "id" option, matching number or "number" - */ - -#define PARSE_REGEX "^([A-z0-9\\s\\-\\.=,\\*@]+|\"[A-z0-9\\s\\-\\.=,\\*@]+\")\\s*$" -#define PARSE_REGEX_FINGERPRINT "^([A-z0-9\\:\\*]+|\"[A-z0-9\\:\\* ]+\")\\s*$" - -static DetectParseRegex subject_parse_regex; -static DetectParseRegex issuerdn_parse_regex; -static DetectParseRegex fingerprint_parse_regex; - -static int DetectTlsSubjectMatch (DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectTlsSubjectFree(DetectEngineCtx *, void *); - -static int DetectTlsIssuerDNMatch (DetectEngineThreadCtx *, - Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectTlsIssuerDNFree(DetectEngineCtx *, void *); - -static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectTlsFingerprintFree(DetectEngineCtx *, void *); - -static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, const char *); -static int DetectTlsStorePostMatch (DetectEngineThreadCtx *det_ctx, - Packet *, const Signature *s, const SigMatchCtx *unused); - -static int g_tls_cert_list_id = 0; -static int g_tls_cert_fingerprint_list_id = 0; - -/** - * \brief Registration function for keyword: tls.version - */ -void DetectTlsRegister (void) -{ - sigmatch_table[DETECT_AL_TLS_SUBJECT].name = "tls.subject"; - sigmatch_table[DETECT_AL_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field"; - sigmatch_table[DETECT_AL_TLS_SUBJECT].url = "/rules/tls-keywords.html#tls-subject"; - sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerTxMatch = DetectTlsSubjectMatch; - sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; - sigmatch_table[DETECT_AL_TLS_SUBJECT].Free = DetectTlsSubjectFree; - sigmatch_table[DETECT_AL_TLS_SUBJECT].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; - sigmatch_table[DETECT_AL_TLS_SUBJECT].alternative = DETECT_AL_TLS_CERT_SUBJECT; - - sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn"; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = "/rules/tls-keywords.html#tls-issuerdn"; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerTxMatch = DetectTlsIssuerDNMatch; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].alternative = DETECT_AL_TLS_CERT_ISSUER; - - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint"; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = "/rules/tls-keywords.html#tls-fingerprint"; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].alternative = DETECT_AL_TLS_CERT_FINGERPRINT; - - sigmatch_table[DETECT_AL_TLS_STORE].name = "tls_store"; - sigmatch_table[DETECT_AL_TLS_STORE].alias = "tls.store"; - sigmatch_table[DETECT_AL_TLS_STORE].desc = "store TLS/SSL certificate on disk"; - sigmatch_table[DETECT_AL_TLS_STORE].url = "/rules/tls-keywords.html#tls-store"; - sigmatch_table[DETECT_AL_TLS_STORE].Match = DetectTlsStorePostMatch; - sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup; - sigmatch_table[DETECT_AL_TLS_STORE].flags |= SIGMATCH_NOOPT; - - DetectSetupParseRegexes(PARSE_REGEX, &subject_parse_regex); - DetectSetupParseRegexes(PARSE_REGEX, &issuerdn_parse_regex); - DetectSetupParseRegexes(PARSE_REGEX_FINGERPRINT, &fingerprint_parse_regex); - - g_tls_cert_list_id = DetectBufferTypeRegister("tls_cert"); - g_tls_cert_fingerprint_list_id = DetectBufferTypeRegister("tls.cert_fingerprint"); - - DetectAppLayerInspectEngineRegister2("tls_cert", ALPROTO_TLS, SIG_FLAG_TOCLIENT, - TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister2("tls_cert", ALPROTO_TLS, SIG_FLAG_TOSERVER, - TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL); -} - -/** - * \brief match the specified Subject on a tls session - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectTlsData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectTlsSubjectMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - SCEnter(); - - const DetectTlsData *tls_data = (const DetectTlsData *)m; - SSLState *ssl_state = (SSLState *)state; - if (ssl_state == NULL) { - SCLogDebug("no tls state, no match"); - SCReturnInt(0); - } - - int ret = 0; - - SSLStateConnp *connp = NULL; - if (flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_subject != NULL) { - SCLogDebug("TLS: Subject is [%s], looking for [%s]\n", - connp->cert0_subject, tls_data->subject); - - if (strstr(connp->cert0_subject, tls_data->subject) != NULL) { - if (tls_data->flags & DETECT_CONTENT_NEGATED) { - ret = 0; - } else { - ret = 1; - } - } else { - if (tls_data->flags & DETECT_CONTENT_NEGATED) { - ret = 1; - } else { - ret = 0; - } - } - } else { - ret = 0; - } - - SCReturnInt(ret); -} - -/** - * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" - * - * \param de_ctx Pointer to the detection engine context - * \param str Pointer to the user provided id option - * - * \retval id_d pointer to DetectTlsData on success - * \retval NULL on failure - */ -static DetectTlsData *DetectTlsSubjectParse (DetectEngineCtx *de_ctx, const char *str, bool negate) -{ - DetectTlsData *tls = NULL; - size_t pcre2_len; - const char *str_ptr; - char *orig = NULL; - char *tmp_str; - uint32_t flag = 0; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&subject_parse_regex, &match, str, 0, 0); - if (ret != 2) { - SCLogError("invalid tls.subject option"); - goto error; - } - - if (negate) - flag = DETECT_CONTENT_NEGATED; - - int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); - if (res < 0) { - SCLogError("pcre2_substring_get_bynumber failed"); - goto error; - } - - /* We have a correct id option */ - tls = SCMalloc(sizeof(DetectTlsData)); - if (unlikely(tls == NULL)) - goto error; - tls->subject = NULL; - tls->flags = flag; - - orig = SCStrdup((char*)str_ptr); - if (unlikely(orig == NULL)) { - goto error; - } - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - - tmp_str=orig; - - /* Let's see if we need to escape "'s */ - if (tmp_str[0] == '"') { - tmp_str[strlen(tmp_str) - 1] = '\0'; - tmp_str += 1; - } - - tls->subject = SCStrdup(tmp_str); - if (unlikely(tls->subject == NULL)) { - goto error; - } - - pcre2_match_data_free(match); - SCFree(orig); - - SCLogDebug("will look for TLS subject %s", tls->subject); - - return tls; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (orig != NULL) - SCFree(orig); - if (tls != NULL) - DetectTlsSubjectFree(de_ctx, tls); - return NULL; - -} - -/** - * \brief this function is used to add the parsed "id" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param idstr pointer to the user provided "id" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - DetectTlsData *tls = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - tls = DetectTlsSubjectParse(de_ctx, str, s->init_data->negated); - if (tls == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_AL_TLS_SUBJECT, (SigMatchCtx *)tls, g_tls_cert_list_id) == NULL) { - goto error; - } - return 0; - -error: - if (tls != NULL) - DetectTlsSubjectFree(de_ctx, tls); - return -1; - -} - -/** - * \brief this function will free memory associated with DetectTlsData - * - * \param id_d pointer to DetectTlsData - */ -static void DetectTlsSubjectFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectTlsData *id_d = (DetectTlsData *)ptr; - if (ptr == NULL) - return; - if (id_d->subject != NULL) - SCFree(id_d->subject); - SCFree(id_d); -} - -/** - * \brief match the specified IssuerDN on a tls session - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectTlsData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectTlsIssuerDNMatch (DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, - const Signature *s, const SigMatchCtx *m) -{ - SCEnter(); - - const DetectTlsData *tls_data = (const DetectTlsData *)m; - SSLState *ssl_state = (SSLState *)state; - if (ssl_state == NULL) { - SCLogDebug("no tls state, no match"); - SCReturnInt(0); - } - - int ret = 0; - - SSLStateConnp *connp = NULL; - if (flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_issuerdn != NULL) { - SCLogDebug("TLS: IssuerDN is [%s], looking for [%s]\n", - connp->cert0_issuerdn, tls_data->issuerdn); - - if (strstr(connp->cert0_issuerdn, tls_data->issuerdn) != NULL) { - if (tls_data->flags & DETECT_CONTENT_NEGATED) { - ret = 0; - } else { - ret = 1; - } - } else { - if (tls_data->flags & DETECT_CONTENT_NEGATED) { - ret = 1; - } else { - ret = 0; - } - } - } else { - ret = 0; - } - - SCReturnInt(ret); -} - -/** - * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" - * - * \param de_ctx Pointer to the detection engine context - * \param str Pointer to the user provided id option - * - * \retval id_d pointer to DetectTlsData on success - * \retval NULL on failure - */ -static DetectTlsData *DetectTlsIssuerDNParse(DetectEngineCtx *de_ctx, const char *str, bool negate) -{ - DetectTlsData *tls = NULL; - size_t pcre2_len; - const char *str_ptr; - char *orig = NULL; - char *tmp_str; - uint32_t flag = 0; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&issuerdn_parse_regex, &match, str, 0, 0); - if (ret != 2) { - SCLogError("invalid tls.issuerdn option"); - goto error; - } - - if (negate) - flag = DETECT_CONTENT_NEGATED; - - int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); - if (res < 0) { - SCLogError("pcre2_substring_get_bynumber failed"); - goto error; - } - - /* We have a correct id option */ - tls = SCMalloc(sizeof(DetectTlsData)); - if (unlikely(tls == NULL)) - goto error; - tls->issuerdn = NULL; - tls->flags = flag; - - orig = SCStrdup((char*)str_ptr); - if (unlikely(orig == NULL)) { - goto error; - } - pcre2_substring_free((PCRE2_UCHAR *)str_ptr); - - tmp_str=orig; - - /* Let's see if we need to escape "'s */ - if (tmp_str[0] == '"') - { - tmp_str[strlen(tmp_str) - 1] = '\0'; - tmp_str += 1; - } - - tls->issuerdn = SCStrdup(tmp_str); - if (unlikely(tls->issuerdn == NULL)) { - goto error; - } - - SCFree(orig); - - pcre2_match_data_free(match); - SCLogDebug("Will look for TLS issuerdn %s", tls->issuerdn); - - return tls; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (orig != NULL) - SCFree(orig); - if (tls != NULL) - DetectTlsIssuerDNFree(de_ctx, tls); - return NULL; - -} - -/** - * \brief this function is used to add the parsed "id" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param idstr pointer to the user provided "id" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - DetectTlsData *tls = NULL; - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - tls = DetectTlsIssuerDNParse(de_ctx, str, s->init_data->negated); - if (tls == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_ISSUERDN, (SigMatchCtx *)tls, - g_tls_cert_list_id) == NULL) { - goto error; - } - return 0; - -error: - if (tls != NULL) - DetectTlsIssuerDNFree(de_ctx, tls); - return -1; - -} - -/** - * \brief this function will free memory associated with DetectTlsData - * - * \param id_d pointer to DetectTlsData - */ -static void DetectTlsIssuerDNFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectTlsData *id_d = (DetectTlsData *)ptr; - SCFree(id_d->issuerdn); - SCFree(id_d); -} - -/** - * \brief This function is used to parse fingerprint passed via keyword: "fingerprint" - * - * \param de_ctx Pointer to the detection engine context - * \param str Pointer to the user provided fingerprint option - * - * \retval pointer to DetectTlsData on success - * \retval NULL on failure - */ - -/** - * \brief this function is used to add the parsed "fingerprint" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param id pointer to the user provided "fingerprint" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectContentSetup(de_ctx, s, str) < 0) { - return -1; - } - - if (DetectEngineContentModifierBufferSetup(de_ctx, s, NULL, DETECT_AL_TLS_CERT_FINGERPRINT, - g_tls_cert_fingerprint_list_id, ALPROTO_TLS) < 0) - return -1; - - return 0; -} - -/** - * \brief this function will free memory associated with DetectTlsData - * - * \param pointer to DetectTlsData - */ -static void DetectTlsFingerprintFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectTlsData *id_d = (DetectTlsData *)ptr; - SCFree(id_d); -} - -/** - * \brief this function is used to add the parsed "store" option - * \brief into the current signature - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param idstr pointer to the user provided "store" option - * - * \retval 0 on Success - * \retval -1 on Failure - */ -static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - - if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) - return -1; - - s->flags |= SIG_FLAG_TLSSTORE; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_TLS_STORE, NULL, DETECT_SM_LIST_POSTMATCH) == - NULL) { - return -1; - } - return 0; -} - -/** \warning modifies Flow::alstate */ -static int DetectTlsStorePostMatch (DetectEngineThreadCtx *det_ctx, - Packet *p, const Signature *s, const SigMatchCtx *unused) -{ - SCEnter(); - - if (p->flow == NULL) - return 0; - - SSLState *ssl_state = FlowGetAppState(p->flow); - if (ssl_state == NULL) { - SCLogDebug("no tls state, no match"); - SCReturnInt(0); - } - - SSLStateConnp *connp; - - if (p->flow->flags & STREAM_TOSERVER) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - connp->cert_log_flag |= SSL_TLS_LOG_PEM; - SCReturnInt(1); -} diff --git a/src/detect-tls.h b/src/detect-tls.h deleted file mode 100644 index 70d58d56c1de..000000000000 --- a/src/detect-tls.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2011-2012 ANSSI - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * \author Pierre Chifflier - */ - -#ifndef __DETECT_TLS_H__ -#define __DETECT_TLS_H__ - -typedef struct DetectTlsData_ { - uint16_t ver; /** tls version to match */ - uint32_t flags; /** flags containing match variant (Negation for example) */ - char * subject; /** tls certificate subject substring to match */ - char *issuerdn; /** tls certificate issuerDN substring to match */ -} DetectTlsData; - -/* prototypes */ -void DetectTlsRegister (void); - -#endif /* __DETECT_TLS_H__ */ diff --git a/src/detect-tos.c b/src/detect-tos.c index e8c1fe6f62d7..b6b9462a40fa 100644 --- a/src/detect-tos.c +++ b/src/detect-tos.c @@ -38,18 +38,18 @@ #include "flow-var.h" #include "flow-util.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" -#define PARSE_REGEX "^\\s*(!?\\s*[0-9]{1,3}|!?\\s*[xX][0-9a-fA-F]{1,2})\\s*$" +#define PARSE_REGEX "^\\s*(!?\\s*[0-9]{1,3}|!?\\s*[xX][0-9a-fA-F]{1,2})\\s*$" static DetectParseRegex parse_regex; static int DetectTosSetup(DetectEngineCtx *, Signature *, const char *); -static int DetectTosMatch(DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); +static int DetectTosMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); #ifdef UNITTESTS static void DetectTosRegisterTests(void); #endif @@ -71,10 +71,8 @@ void DetectTosRegister(void) #ifdef UNITTESTS sigmatch_table[DETECT_TOS].RegisterTests = DetectTosRegisterTests; #endif - sigmatch_table[DETECT_TOS].flags = - (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_HANDLE_NEGATION); - sigmatch_table[DETECT_TOS].url = - "/rules/header-keywords.html#tos"; + sigmatch_table[DETECT_TOS].flags = (SIGMATCH_QUOTES_OPTIONAL | SIGMATCH_HANDLE_NEGATION); + sigmatch_table[DETECT_TOS].url = "/rules/header-keywords.html#tos"; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } @@ -90,8 +88,8 @@ void DetectTosRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectTosMatch(DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectTosMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectTosData *tosd = (const DetectTosData *)ctx; int result = 0; @@ -331,19 +329,18 @@ static int DetectTosTest12(void) IPV4_SET_RAW_IPTOS(p->ip4h, 10); const char *sigs[4]; - sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; tos: 10 ; sid:1;)"; - sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; tos: ! 10; sid:2;)"; - sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:20 ; sid:3;)"; - sigs[3]= "alert ip any any -> any any (msg:\"Testing id 3\"; tos:! 20; sid:4;)"; + sigs[0] = "alert ip any any -> any any (msg:\"Testing id 1\"; tos: 10 ; sid:1;)"; + sigs[1] = "alert ip any any -> any any (msg:\"Testing id 2\"; tos: ! 10; sid:2;)"; + sigs[2] = "alert ip any any -> any any (msg:\"Testing id 3\"; tos:20 ; sid:3;)"; + sigs[3] = "alert ip any any -> any any (msg:\"Testing id 3\"; tos:! 20; sid:4;)"; - uint32_t sid[4] = {1, 2, 3, 4}; + uint32_t sid[4] = { 1, 2, 3, 4 }; - uint32_t results[1][4] = - { - {1, 0, 0, 1}, - }; + uint32_t results[1][4] = { + { 1, 0, 0, 1 }, + }; - result = UTHGenericTest(&p, 1, sigs, sid, (uint32_t *) results, 4); + result = UTHGenericTest(&p, 1, sigs, sid, (uint32_t *)results, 4); UTHFreePackets(&p, 1); diff --git a/src/detect-transform-compress-whitespace.c b/src/detect-transform-compress-whitespace.c index 5cbf0fd896f5..0268d63fe6ae 100644 --- a/src/detect-transform-compress-whitespace.c +++ b/src/detect-transform-compress-whitespace.c @@ -31,10 +31,10 @@ #include "detect-parse.h" #include "detect-transform-compress-whitespace.h" -#include "util-unittest.h" -#include "util-print.h" +#include "util/unittest.h" +#include "util/print.h" -static int DetectTransformCompressWhitespaceSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformCompressWhitespaceSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTransformCompressWhitespaceRegisterTests(void); #endif @@ -46,19 +46,18 @@ void DetectTransformCompressWhitespaceRegister(void) { sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].name = "compress_whitespace"; sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].desc = - "modify buffer to compress consecutive whitespace characters " - "into a single one before inspection"; + "modify buffer to compress consecutive whitespace characters " + "into a single one before inspection"; sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].url = - "/rules/transforms.html#compress-whitespace"; - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].Transform = - TransformCompressWhitespace; + "/rules/transforms.html#compress-whitespace"; + sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].Transform = TransformCompressWhitespace; sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].TransformValidate = TransformCompressWhitespaceValidate; sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].Setup = - DetectTransformCompressWhitespaceSetup; + DetectTransformCompressWhitespaceSetup; #ifdef UNITTESTS sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].RegisterTests = - DetectTransformCompressWhitespaceRegisterTests; + DetectTransformCompressWhitespaceRegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].flags |= SIGMATCH_NOOPT; } @@ -72,7 +71,8 @@ void DetectTransformCompressWhitespaceRegister(void) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformCompressWhitespaceSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectTransformCompressWhitespaceSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_COMPRESS_WHITESPACE, NULL); @@ -114,8 +114,8 @@ static void TransformCompressWhitespace(InspectionBuffer *buffer, void *options) uint8_t output[input_len]; // we can only shrink uint8_t *oi = output, *os = output; - //PrintRawDataFp(stdout, input, input_len); - for (uint32_t i = 0; i < input_len; ) { + // PrintRawDataFp(stdout, input, input_len); + for (uint32_t i = 0; i < input_len;) { if (!(isspace(*input))) { *oi++ = *input++; i++; @@ -130,7 +130,7 @@ static void TransformCompressWhitespace(InspectionBuffer *buffer, void *options) } } uint32_t output_size = oi - os; - //PrintRawDataFp(stdout, output, output_size); + // PrintRawDataFp(stdout, output, output_size); InspectionBufferCopy(buffer, os, output_size); } @@ -221,10 +221,10 @@ static int DetectTransformCompressWhitespaceTest04(void) static void DetectTransformCompressWhitespaceRegisterTests(void) { - UtRegisterTest("DetectTransformCompressWhitespaceTest01", - DetectTransformCompressWhitespaceTest01); - UtRegisterTest("DetectTransformCompressWhitespaceTest02", - DetectTransformCompressWhitespaceTest02); + UtRegisterTest( + "DetectTransformCompressWhitespaceTest01", DetectTransformCompressWhitespaceTest01); + UtRegisterTest( + "DetectTransformCompressWhitespaceTest02", DetectTransformCompressWhitespaceTest02); UtRegisterTest( "DetectTransformCompressWhitespaceTest03", DetectTransformCompressWhitespaceTest03); UtRegisterTest( diff --git a/src/detect-transform-compress-whitespace.h b/src/detect-transform-compress-whitespace.h index 800d9a7272c1..adaeea07694c 100644 --- a/src/detect-transform-compress-whitespace.h +++ b/src/detect-transform-compress-whitespace.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_COMPRESS_WHITESPACE_H__ /* prototypes */ -void DetectTransformCompressWhitespaceRegister (void); +void DetectTransformCompressWhitespaceRegister(void); #endif /* __DETECT_TRANSFORM_COMPRESS_WHITESPACE_H__ */ diff --git a/src/detect-transform-dotprefix.c b/src/detect-transform-dotprefix.c index 52a263372b43..ebbb28e2bdaf 100644 --- a/src/detect-transform-dotprefix.c +++ b/src/detect-transform-dotprefix.c @@ -32,12 +32,12 @@ #include "detect-transform-dotprefix.h" #include "detect-engine-build.h" -#include "util-unittest.h" -#include "util-print.h" -#include "util-memrchr.h" -#include "util-memcpy.h" +#include "util/unittest.h" +#include "util/print.h" +#include "util/memrchr.h" +#include "util/memcpy.h" -static int DetectTransformDotPrefixSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformDotPrefixSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTransformDotPrefixRegisterTests(void); #endif @@ -46,15 +46,13 @@ static void TransformDotPrefix(InspectionBuffer *buffer, void *options); void DetectTransformDotPrefixRegister(void) { sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].name = "dotprefix"; - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].desc = - "modify buffer to extract the dotprefix"; - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].url = - "/rules/transforms.html#dotprefix"; + sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].desc = "modify buffer to extract the dotprefix"; + sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].url = "/rules/transforms.html#dotprefix"; sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].Transform = TransformDotPrefix; sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].Setup = DetectTransformDotPrefixSetup; #ifdef UNITTESTS sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].RegisterTests = - DetectTransformDotPrefixRegisterTests; + DetectTransformDotPrefixRegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].flags |= SIGMATCH_NOOPT; } @@ -68,7 +66,7 @@ void DetectTransformDotPrefixRegister(void) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformDotPrefixSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectTransformDotPrefixSetup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_DOTPREFIX, NULL); @@ -88,7 +86,8 @@ static int DetectTransformDotPrefixSetup (DetectEngineCtx *de_ctx, Signature *s, * 5. google.com --> match * * To match on the dotprefix only: - * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".google.com"; endswith; sid:1;)" + * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".google.com"; endswith; + * sid:1;)" * * 1. hello.google.com --> match * 2. hey.agoogle.com --> no match @@ -161,7 +160,8 @@ static int DetectTransformDotPrefixTest02(void) static int DetectTransformDotPrefixTest03(void) { - const char rule[] = "alert dns any any -> any any (dns.query; dotprefix; content:\".google.com\"; sid:1;)"; + const char rule[] = + "alert dns any any -> any any (dns.query; dotprefix; content:\".google.com\"; sid:1;)"; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); diff --git a/src/detect-transform-dotprefix.h b/src/detect-transform-dotprefix.h index 3512689b644e..ec124c948281 100644 --- a/src/detect-transform-dotprefix.h +++ b/src/detect-transform-dotprefix.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_DOTPREFIX_H__ /* prototypes */ -void DetectTransformDotPrefixRegister (void); +void DetectTransformDotPrefixRegister(void); #endif /* __DETECT_TRANSFORM_DOTPREFIX_H__ */ diff --git a/src/detect-transform-md5.c b/src/detect-transform-md5.c index 9e6ee1986a5b..692425197555 100644 --- a/src/detect-transform-md5.c +++ b/src/detect-transform-md5.c @@ -31,11 +31,11 @@ #include "detect-parse.h" #include "detect-transform-md5.h" -#include "util-unittest.h" -#include "util-print.h" +#include "util/unittest.h" +#include "util/print.h" #include "rust.h" -static int DetectTransformToMd5Setup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformToMd5Setup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTransformToMd5RegisterTests(void); #endif @@ -44,17 +44,12 @@ static void TransformToMd5(InspectionBuffer *buffer, void *options); void DetectTransformMd5Register(void) { sigmatch_table[DETECT_TRANSFORM_MD5].name = "to_md5"; - sigmatch_table[DETECT_TRANSFORM_MD5].desc = - "convert to md5 hash of the buffer"; - sigmatch_table[DETECT_TRANSFORM_MD5].url = - "/rules/transforms.html#to-md5"; - sigmatch_table[DETECT_TRANSFORM_MD5].Setup = - DetectTransformToMd5Setup; - sigmatch_table[DETECT_TRANSFORM_MD5].Transform = - TransformToMd5; + sigmatch_table[DETECT_TRANSFORM_MD5].desc = "convert to md5 hash of the buffer"; + sigmatch_table[DETECT_TRANSFORM_MD5].url = "/rules/transforms.html#to-md5"; + sigmatch_table[DETECT_TRANSFORM_MD5].Setup = DetectTransformToMd5Setup; + sigmatch_table[DETECT_TRANSFORM_MD5].Transform = TransformToMd5; #ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_MD5].RegisterTests = - DetectTransformToMd5RegisterTests; + sigmatch_table[DETECT_TRANSFORM_MD5].RegisterTests = DetectTransformToMd5RegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_MD5].flags |= SIGMATCH_NOOPT; } @@ -68,7 +63,7 @@ void DetectTransformMd5Register(void) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformToMd5Setup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectTransformToMd5Setup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); if (g_disable_hashing) { @@ -86,7 +81,7 @@ static void TransformToMd5(InspectionBuffer *buffer, void *options) const uint32_t input_len = buffer->inspect_len; uint8_t output[SC_MD5_LEN]; - //PrintRawDataFp(stdout, input, input_len); + // PrintRawDataFp(stdout, input, input_len); SCMd5HashBuffer(input, input_len, output, sizeof(output)); InspectionBufferCopy(buffer, output, sizeof(output)); } @@ -109,7 +104,6 @@ static int DetectTransformToMd5Test01(void) static void DetectTransformToMd5RegisterTests(void) { - UtRegisterTest("DetectTransformToMd5Test01", - DetectTransformToMd5Test01); + UtRegisterTest("DetectTransformToMd5Test01", DetectTransformToMd5Test01); } #endif diff --git a/src/detect-transform-md5.h b/src/detect-transform-md5.h index a65bb387f233..c3e00023520a 100644 --- a/src/detect-transform-md5.h +++ b/src/detect-transform-md5.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_MD5_H__ /* prototypes */ -void DetectTransformMd5Register (void); +void DetectTransformMd5Register(void); #endif /* __DETECT_TRANSFORM_MD5_H__ */ diff --git a/src/detect-transform-pcrexform.c b/src/detect-transform-pcrexform.c index c517175b8722..22a6aabe1c27 100644 --- a/src/detect-transform-pcrexform.c +++ b/src/detect-transform-pcrexform.c @@ -36,27 +36,24 @@ typedef struct DetectTransformPcrexformData { pcre2_match_context *context; } DetectTransformPcrexformData; -static int DetectTransformPcrexformSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformPcrexformSetup(DetectEngineCtx *, Signature *, const char *); static void DetectTransformPcrexformFree(DetectEngineCtx *, void *); static void DetectTransformPcrexform(InspectionBuffer *buffer, void *options); #ifdef UNITTESTS -void DetectTransformPcrexformRegisterTests (void); +void DetectTransformPcrexformRegisterTests(void); #endif void DetectTransformPcrexformRegister(void) { sigmatch_table[DETECT_TRANSFORM_PCREXFORM].name = "pcrexform"; - sigmatch_table[DETECT_TRANSFORM_PCREXFORM].desc = - "modify buffer via PCRE before inspection"; + sigmatch_table[DETECT_TRANSFORM_PCREXFORM].desc = "modify buffer via PCRE before inspection"; sigmatch_table[DETECT_TRANSFORM_PCREXFORM].url = "/rules/transforms.html#pcre-xform"; - sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Transform = - DetectTransformPcrexform; - sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Free = - DetectTransformPcrexformFree; - sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Setup = - DetectTransformPcrexformSetup; + sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Transform = DetectTransformPcrexform; + sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Free = DetectTransformPcrexformFree; + sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Setup = DetectTransformPcrexformSetup; #ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_PCREXFORM].RegisterTests = DetectTransformPcrexformRegisterTests; + sigmatch_table[DETECT_TRANSFORM_PCREXFORM].RegisterTests = + DetectTransformPcrexformRegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_PCREXFORM].flags |= SIGMATCH_QUOTES_MANDATORY; } @@ -64,7 +61,7 @@ void DetectTransformPcrexformRegister(void) static void DetectTransformPcrexformFree(DetectEngineCtx *de_ctx, void *ptr) { if (ptr != NULL) { - DetectTransformPcrexformData *pxd = (DetectTransformPcrexformData *) ptr; + DetectTransformPcrexformData *pxd = (DetectTransformPcrexformData *)ptr; pcre2_match_context_free(pxd->context); pcre2_code_free(pxd->regex); SCFree(pxd); @@ -80,7 +77,8 @@ static void DetectTransformPcrexformFree(DetectEngineCtx *de_ctx, void *ptr) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformPcrexformSetup (DetectEngineCtx *de_ctx, Signature *s, const char *regexstr) +static int DetectTransformPcrexformSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *regexstr) { SCEnter(); diff --git a/src/detect-transform-pcrexform.h b/src/detect-transform-pcrexform.h index 0a807d751b8d..18db68ee6122 100644 --- a/src/detect-transform-pcrexform.h +++ b/src/detect-transform-pcrexform.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_PCREXFORM_H__ /* prototypes */ -void DetectTransformPcrexformRegister (void); +void DetectTransformPcrexformRegister(void); #endif /* __DETECT_TRANSFORM_PCREXFORM_H__ */ diff --git a/src/detect-transform-sha1.c b/src/detect-transform-sha1.c index 927b25e97abd..e699b280f574 100644 --- a/src/detect-transform-sha1.c +++ b/src/detect-transform-sha1.c @@ -31,12 +31,12 @@ #include "detect-parse.h" #include "detect-transform-sha1.h" -#include "util-unittest.h" -#include "util-print.h" +#include "util/unittest.h" +#include "util/print.h" #include "rust.h" -static int DetectTransformToSha1Setup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformToSha1Setup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTransformToSha1RegisterTests(void); #endif @@ -45,17 +45,12 @@ static void TransformToSha1(InspectionBuffer *buffer, void *options); void DetectTransformSha1Register(void) { sigmatch_table[DETECT_TRANSFORM_SHA1].name = "to_sha1"; - sigmatch_table[DETECT_TRANSFORM_SHA1].desc = - "convert to sha1 hash of the buffer"; - sigmatch_table[DETECT_TRANSFORM_SHA1].url = - "/rules/transforms.html#to-sha1"; - sigmatch_table[DETECT_TRANSFORM_SHA1].Setup = - DetectTransformToSha1Setup; - sigmatch_table[DETECT_TRANSFORM_SHA1].Transform = - TransformToSha1; + sigmatch_table[DETECT_TRANSFORM_SHA1].desc = "convert to sha1 hash of the buffer"; + sigmatch_table[DETECT_TRANSFORM_SHA1].url = "/rules/transforms.html#to-sha1"; + sigmatch_table[DETECT_TRANSFORM_SHA1].Setup = DetectTransformToSha1Setup; + sigmatch_table[DETECT_TRANSFORM_SHA1].Transform = TransformToSha1; #ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_SHA1].RegisterTests = - DetectTransformToSha1RegisterTests; + sigmatch_table[DETECT_TRANSFORM_SHA1].RegisterTests = DetectTransformToSha1RegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_SHA1].flags |= SIGMATCH_NOOPT; } @@ -69,7 +64,7 @@ void DetectTransformSha1Register(void) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformToSha1Setup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectTransformToSha1Setup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); if (g_disable_hashing) { @@ -87,7 +82,7 @@ static void TransformToSha1(InspectionBuffer *buffer, void *options) const uint32_t input_len = buffer->inspect_len; uint8_t output[SC_SHA1_LEN]; - //PrintRawDataFp(stdout, input, input_len); + // PrintRawDataFp(stdout, input, input_len); SCSha1HashBuffer(input, input_len, output, sizeof(output)); InspectionBufferCopy(buffer, output, sizeof(output)); } @@ -110,7 +105,6 @@ static int DetectTransformToSha1Test01(void) static void DetectTransformToSha1RegisterTests(void) { - UtRegisterTest("DetectTransformToSha1Test01", - DetectTransformToSha1Test01); + UtRegisterTest("DetectTransformToSha1Test01", DetectTransformToSha1Test01); } #endif diff --git a/src/detect-transform-sha1.h b/src/detect-transform-sha1.h index 4d53caedf911..6e39dfbc3d45 100644 --- a/src/detect-transform-sha1.h +++ b/src/detect-transform-sha1.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_SHA1_H__ /* prototypes */ -void DetectTransformSha1Register (void); +void DetectTransformSha1Register(void); #endif /* __DETECT_TRANSFORM_SHA1_H__ */ diff --git a/src/detect-transform-sha256.c b/src/detect-transform-sha256.c index 3eeb582a8361..d8c1507e62f5 100644 --- a/src/detect-transform-sha256.c +++ b/src/detect-transform-sha256.c @@ -31,12 +31,12 @@ #include "detect-parse.h" #include "detect-transform-sha256.h" -#include "util-unittest.h" -#include "util-print.h" +#include "util/unittest.h" +#include "util/print.h" #include "rust.h" -static int DetectTransformToSha256Setup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformToSha256Setup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTransformToSha256RegisterTests(void); #endif @@ -45,17 +45,12 @@ static void TransformToSha256(InspectionBuffer *buffer, void *options); void DetectTransformSha256Register(void) { sigmatch_table[DETECT_TRANSFORM_SHA256].name = "to_sha256"; - sigmatch_table[DETECT_TRANSFORM_SHA256].desc = - "convert to sha256 hash of the buffer"; - sigmatch_table[DETECT_TRANSFORM_SHA256].url = - "/rules/transforms.html#to-sha256"; - sigmatch_table[DETECT_TRANSFORM_SHA256].Setup = - DetectTransformToSha256Setup; - sigmatch_table[DETECT_TRANSFORM_SHA256].Transform = - TransformToSha256; + sigmatch_table[DETECT_TRANSFORM_SHA256].desc = "convert to sha256 hash of the buffer"; + sigmatch_table[DETECT_TRANSFORM_SHA256].url = "/rules/transforms.html#to-sha256"; + sigmatch_table[DETECT_TRANSFORM_SHA256].Setup = DetectTransformToSha256Setup; + sigmatch_table[DETECT_TRANSFORM_SHA256].Transform = TransformToSha256; #ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_SHA256].RegisterTests = - DetectTransformToSha256RegisterTests; + sigmatch_table[DETECT_TRANSFORM_SHA256].RegisterTests = DetectTransformToSha256RegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_SHA256].flags |= SIGMATCH_NOOPT; } @@ -69,7 +64,7 @@ void DetectTransformSha256Register(void) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformToSha256Setup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectTransformToSha256Setup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); if (g_disable_hashing) { @@ -87,7 +82,7 @@ static void TransformToSha256(InspectionBuffer *buffer, void *options) const uint32_t input_len = buffer->inspect_len; uint8_t output[SC_SHA256_LEN]; - //PrintRawDataFp(stdout, input, input_len); + // PrintRawDataFp(stdout, input, input_len); SCSha256HashBuffer(input, input_len, output, sizeof(output)); InspectionBufferCopy(buffer, output, sizeof(output)); } @@ -110,7 +105,6 @@ static int DetectTransformToSha256Test01(void) static void DetectTransformToSha256RegisterTests(void) { - UtRegisterTest("DetectTransformToSha256Test01", - DetectTransformToSha256Test01); + UtRegisterTest("DetectTransformToSha256Test01", DetectTransformToSha256Test01); } #endif diff --git a/src/detect-transform-sha256.h b/src/detect-transform-sha256.h index e8b4f0b3b027..34279d90d65e 100644 --- a/src/detect-transform-sha256.h +++ b/src/detect-transform-sha256.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_SHA256_H__ /* prototypes */ -void DetectTransformSha256Register (void); +void DetectTransformSha256Register(void); #endif /* __DETECT_TRANSFORM_SHA256_H__ */ diff --git a/src/detect-transform-strip-whitespace.c b/src/detect-transform-strip-whitespace.c index 32fb96f06ea0..2eaa687ecb06 100644 --- a/src/detect-transform-strip-whitespace.c +++ b/src/detect-transform-strip-whitespace.c @@ -32,32 +32,31 @@ #include "detect-parse.h" #include "detect-transform-strip-whitespace.h" -#include "util-unittest.h" -#include "util-print.h" +#include "util/unittest.h" +#include "util/print.h" -static int DetectTransformStripWhitespaceSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformStripWhitespaceSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTransformStripWhitespaceRegisterTests(void); #endif static void TransformStripWhitespace(InspectionBuffer *buffer, void *options); -static bool TransformStripWhitespaceValidate(const uint8_t *content, uint16_t content_len, void *options); +static bool TransformStripWhitespaceValidate( + const uint8_t *content, uint16_t content_len, void *options); void DetectTransformStripWhitespaceRegister(void) { sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].name = "strip_whitespace"; sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].desc = - "modify buffer to strip whitespace before inspection"; + "modify buffer to strip whitespace before inspection"; sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].url = - "/rules/transforms.html#strip-whitespace"; - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Transform = - TransformStripWhitespace; + "/rules/transforms.html#strip-whitespace"; + sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Transform = TransformStripWhitespace; sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].TransformValidate = - TransformStripWhitespaceValidate; - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Setup = - DetectTransformStripWhitespaceSetup; + TransformStripWhitespaceValidate; + sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Setup = DetectTransformStripWhitespaceSetup; #ifdef UNITTESTS sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].RegisterTests = - DetectTransformStripWhitespaceRegisterTests; + DetectTransformStripWhitespaceRegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].flags |= SIGMATCH_NOOPT; } @@ -71,7 +70,8 @@ void DetectTransformStripWhitespaceRegister(void) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformStripWhitespaceSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectTransformStripWhitespaceSetup( + DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_STRIP_WHITESPACE, NULL); @@ -86,8 +86,8 @@ static int DetectTransformStripWhitespaceSetup (DetectEngineCtx *de_ctx, Signatu * \retval false If the string contains spaces * \retval true Otherwise. */ -static bool TransformStripWhitespaceValidate(const uint8_t *content, - uint16_t content_len, void *options) +static bool TransformStripWhitespaceValidate( + const uint8_t *content, uint16_t content_len, void *options) { if (content) { for (uint32_t i = 0; i < content_len; i++) { @@ -109,7 +109,7 @@ static void TransformStripWhitespace(InspectionBuffer *buffer, void *options) uint8_t output[input_len]; // we can only shrink uint8_t *oi = output, *os = output; - //PrintRawDataFp(stdout, input, input_len); + // PrintRawDataFp(stdout, input, input_len); for (uint32_t i = 0; i < input_len; i++) { if (!isspace(*input)) { *oi++ = *input; @@ -117,7 +117,7 @@ static void TransformStripWhitespace(InspectionBuffer *buffer, void *options) input++; } uint32_t output_size = oi - os; - //PrintRawDataFp(stdout, output, output_size); + // PrintRawDataFp(stdout, output, output_size); InspectionBufferCopy(buffer, os, output_size); } @@ -181,7 +181,8 @@ static int DetectTransformStripWhitespaceTest02(void) static int DetectTransformStripWhitespaceTest03(void) { - const char rule[] = "alert http any any -> any any (http_request_line; strip_whitespace; content:\"GET/HTTP\"; sid:1;)"; + const char rule[] = "alert http any any -> any any (http_request_line; strip_whitespace; " + "content:\"GET/HTTP\"; sid:1;)"; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); @@ -199,11 +200,8 @@ static int DetectTransformStripWhitespaceTest03(void) static void DetectTransformStripWhitespaceRegisterTests(void) { - UtRegisterTest("DetectTransformStripWhitespaceTest01", - DetectTransformStripWhitespaceTest01); - UtRegisterTest("DetectTransformStripWhitespaceTest02", - DetectTransformStripWhitespaceTest02); - UtRegisterTest("DetectTransformStripWhitespaceTest03", - DetectTransformStripWhitespaceTest03); + UtRegisterTest("DetectTransformStripWhitespaceTest01", DetectTransformStripWhitespaceTest01); + UtRegisterTest("DetectTransformStripWhitespaceTest02", DetectTransformStripWhitespaceTest02); + UtRegisterTest("DetectTransformStripWhitespaceTest03", DetectTransformStripWhitespaceTest03); } #endif diff --git a/src/detect-transform-strip-whitespace.h b/src/detect-transform-strip-whitespace.h index 274f24100ccc..cc74c03a849f 100644 --- a/src/detect-transform-strip-whitespace.h +++ b/src/detect-transform-strip-whitespace.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_STRIPWHITESPACE_H__ /* prototypes */ -void DetectTransformStripWhitespaceRegister (void); +void DetectTransformStripWhitespaceRegister(void); #endif /* __DETECT_TRANSFORM_STRIPWHITESPACE_H__ */ diff --git a/src/detect-transform-urldecode.c b/src/detect-transform-urldecode.c index 13ef03372f5f..63637c3c3a58 100644 --- a/src/detect-transform-urldecode.c +++ b/src/detect-transform-urldecode.c @@ -32,10 +32,10 @@ #include "detect-parse.h" #include "detect-transform-urldecode.h" -#include "util-unittest.h" -#include "util-print.h" +#include "util/unittest.h" +#include "util/print.h" -static int DetectTransformUrlDecodeSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectTransformUrlDecodeSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectTransformUrlDecodeRegisterTests(void); #endif @@ -46,15 +46,13 @@ void DetectTransformUrlDecodeRegister(void) { sigmatch_table[DETECT_TRANSFORM_URL_DECODE].name = "url_decode"; sigmatch_table[DETECT_TRANSFORM_URL_DECODE].desc = - "modify buffer to decode urlencoded data before inspection"; + "modify buffer to decode urlencoded data before inspection"; sigmatch_table[DETECT_TRANSFORM_URL_DECODE].url = "/rules/transforms.html#url-decode"; - sigmatch_table[DETECT_TRANSFORM_URL_DECODE].Transform = - TransformUrlDecode; - sigmatch_table[DETECT_TRANSFORM_URL_DECODE].Setup = - DetectTransformUrlDecodeSetup; + sigmatch_table[DETECT_TRANSFORM_URL_DECODE].Transform = TransformUrlDecode; + sigmatch_table[DETECT_TRANSFORM_URL_DECODE].Setup = DetectTransformUrlDecodeSetup; #ifdef UNITTESTS sigmatch_table[DETECT_TRANSFORM_URL_DECODE].RegisterTests = - DetectTransformUrlDecodeRegisterTests; + DetectTransformUrlDecodeRegisterTests; #endif sigmatch_table[DETECT_TRANSFORM_URL_DECODE].flags |= SIGMATCH_NOOPT; @@ -69,7 +67,7 @@ void DetectTransformUrlDecodeRegister(void) * \retval 0 ok * \retval -1 failure */ -static int DetectTransformUrlDecodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) +static int DetectTransformUrlDecodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) { SCEnter(); int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_URL_DECODE, NULL); @@ -77,20 +75,22 @@ static int DetectTransformUrlDecodeSetup (DetectEngineCtx *de_ctx, Signature *s, } // util function so as to ease reuse sometimes -static bool BufferUrlDecode(const uint8_t *input, const uint32_t input_len, uint8_t *output, uint32_t *output_size) +static bool BufferUrlDecode( + const uint8_t *input, const uint32_t input_len, uint8_t *output, uint32_t *output_size) { bool changed = false; uint8_t *oi = output; - //PrintRawDataFp(stdout, input, input_len); + // PrintRawDataFp(stdout, input, input_len); for (uint32_t i = 0; i < input_len; i++) { if (input[i] == '%') { if (i + 2 < input_len) { - if ((isxdigit(input[i+1])) && (isxdigit(input[i+2]))) { + if ((isxdigit(input[i + 1])) && (isxdigit(input[i + 2]))) { // Decode %HH encoding. *oi = (uint8_t)((input[i + 1] >= 'A' ? ((input[i + 1] & 0xdf) - 'A') + 10 : (input[i + 1] - '0')) << 4); - *oi |= (input[i+2] >= 'A' ? ((input[i+2] & 0xdf) - 'A') + 10 : (input[i+2] - '0')); + *oi |= (input[i + 2] >= 'A' ? ((input[i + 2] & 0xdf) - 'A') + 10 + : (input[i + 2] - '0')); oi++; // one more increment before looping i += 2; @@ -146,15 +146,16 @@ static int DetectTransformUrlDecodeTest01(void) PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); TransformUrlDecode(&buffer, NULL); PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - FAIL_IF (buffer.inspect_len != strlen("Suricata is 'awesome!'%00%ZZ%4")); - FAIL_IF (memcmp(buffer.inspect, "Suricata is 'awesome!'%00%ZZ%4", buffer.inspect_len) != 0); + FAIL_IF(buffer.inspect_len != strlen("Suricata is 'awesome!'%00%ZZ%4")); + FAIL_IF(memcmp(buffer.inspect, "Suricata is 'awesome!'%00%ZZ%4", buffer.inspect_len) != 0); InspectionBufferFree(&buffer); PASS; } static int DetectTransformUrlDecodeTest02(void) { - const char rule[] = "alert http any any -> any any (http.request_body; url_decode; content:\"mail=test@oisf.net\"; sid:1;)"; + const char rule[] = "alert http any any -> any any (http.request_body; url_decode; " + "content:\"mail=test@oisf.net\"; sid:1;)"; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); @@ -172,9 +173,7 @@ static int DetectTransformUrlDecodeTest02(void) static void DetectTransformUrlDecodeRegisterTests(void) { - UtRegisterTest("DetectTransformUrlDecodeTest01", - DetectTransformUrlDecodeTest01); - UtRegisterTest("DetectTransformUrlDecodeTest02", - DetectTransformUrlDecodeTest02); + UtRegisterTest("DetectTransformUrlDecodeTest01", DetectTransformUrlDecodeTest01); + UtRegisterTest("DetectTransformUrlDecodeTest02", DetectTransformUrlDecodeTest02); } #endif diff --git a/src/detect-transform-urldecode.h b/src/detect-transform-urldecode.h index 79f886f94da7..71d37a30e70f 100644 --- a/src/detect-transform-urldecode.h +++ b/src/detect-transform-urldecode.h @@ -25,6 +25,6 @@ #define __DETECT_TRANSFORM_URLDECODE_H__ /* prototypes */ -void DetectTransformUrlDecodeRegister (void); +void DetectTransformUrlDecodeRegister(void); #endif /* __DETECT_TRANSFORM_URLDECODE_H__ */ diff --git a/src/detect-ttl.c b/src/detect-ttl.c index 6d0a25311803..1fef3ff29837 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -33,16 +33,16 @@ #include "detect-engine-uint.h" #include "detect-ttl.h" -#include "util-debug.h" -#include "util-byte.h" +#include "util/debug.h" +#include "util/byte.h" /* prototypes */ -static int DetectTtlMatch (DetectEngineThreadCtx *, Packet *, - const Signature *, const SigMatchCtx *); -static int DetectTtlSetup (DetectEngineCtx *, Signature *, const char *); -void DetectTtlFree (DetectEngineCtx *, void *); +static int DetectTtlMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectTtlSetup(DetectEngineCtx *, Signature *, const char *); +void DetectTtlFree(DetectEngineCtx *, void *); #ifdef UNITTESTS -void DetectTtlRegisterTests (void); +void DetectTtlRegisterTests(void); #endif static int PrefilterSetupTtl(DetectEngineCtx *de_ctx, SigGroupHead *sgh); static bool PrefilterTtlIsPrefilterable(const Signature *s); @@ -80,8 +80,8 @@ void DetectTtlRegister(void) * \retval 0 no match * \retval 1 match */ -static int DetectTtlMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectTtlMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -110,7 +110,7 @@ static int DetectTtlMatch (DetectEngineThreadCtx *det_ctx, Packet *p, * \retval 0 on Success * \retval -1 on Failure */ -static int DetectTtlSetup (DetectEngineCtx *de_ctx, Signature *s, const char *ttlstr) +static int DetectTtlSetup(DetectEngineCtx *de_ctx, Signature *s, const char *ttlstr) { DetectU8Data *ttld = DetectU8Parse(ttlstr); if (ttld == NULL) @@ -137,8 +137,7 @@ void DetectTtlFree(DetectEngineCtx *de_ctx, void *ptr) /* prefilter code */ -static void -PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +static void PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { if (PKT_IS_PSEUDOPKT(p)) { SCReturn; @@ -177,7 +176,7 @@ static int PrefilterSetupTtl(DetectEngineCtx *de_ctx, SigGroupHead *sgh) static bool PrefilterTtlIsPrefilterable(const Signature *s) { const SigMatch *sm; - for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { switch (sm->type) { case DETECT_TTL: return true; diff --git a/src/detect-ttl.h b/src/detect-ttl.h index 0e561a1efe16..c2878c8f3954 100644 --- a/src/detect-ttl.h +++ b/src/detect-ttl.h @@ -22,10 +22,8 @@ */ #ifndef _DETECT_TTL_H -#define _DETECT_TTL_H - +#define _DETECT_TTL_H void DetectTtlRegister(void); -#endif /* _DETECT_TTL_H */ - +#endif /* _DETECT_TTL_H */ diff --git a/src/detect-udphdr.c b/src/detect-udphdr.c index 8aa645b92641..90e8f42cadb6 100644 --- a/src/detect-udphdr.c +++ b/src/detect-udphdr.c @@ -34,9 +34,9 @@ #include "detect-udphdr.h" /* prototypes */ -static int DetectUdphdrSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectUdphdrSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS -void DetectUdphdrRegisterTests (void); +void DetectUdphdrRegisterTests(void); #endif static int g_udphdr_buffer_id = 0; @@ -64,8 +64,7 @@ void DetectUdphdrRegister(void) DetectPktMpmRegister("udp.hdr", 2, PrefilterGenericMpmPktRegister, GetData); - DetectPktInspectEngineRegister("udp.hdr", GetData, - DetectEngineInspectPktBufferGeneric); + DetectPktInspectEngineRegister("udp.hdr", GetData, DetectEngineInspectPktBufferGeneric); return; } @@ -79,7 +78,7 @@ void DetectUdphdrRegister(void) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectUdphdrSetup (DetectEngineCtx *de_ctx, Signature *s, const char *_unused) +static int DetectUdphdrSetup(DetectEngineCtx *de_ctx, Signature *s, const char *_unused) { if (!(DetectProtoContainsProto(&s->proto, IPPROTO_UDP))) return -1; @@ -103,8 +102,7 @@ static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx, return NULL; } if (((uint8_t *)p->udph + (ptrdiff_t)UDP_HEADER_LEN) > - ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) - { + ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) { SCLogDebug("data out of range: %p > %p", ((uint8_t *)p->udph + (ptrdiff_t)UDP_HEADER_LEN), ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))); diff --git a/src/detect-udphdr.h b/src/detect-udphdr.h index 85aff554101e..e6ce8b533130 100644 --- a/src/detect-udphdr.h +++ b/src/detect-udphdr.h @@ -26,4 +26,4 @@ void DetectUdphdrRegister(void); -#endif /* _DETECT_UDPHDR_H */ +#endif /* _DETECT_UDPHDR_H */ diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 65d2c868f7e3..31597b21695b 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -28,7 +28,7 @@ #include "decode.h" #include "detect.h" #include "detect-content.h" -#include "detect-http-uri.h" +#include "app-layer/http/detect-uri.h" #include "detect-uricontent.h" #include "detect-engine-mpm.h" #include "detect-parse.h" @@ -45,14 +45,14 @@ #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-protos.h" -#include "app-layer-htp.h" - -#include "util-mpm.h" -#include "util-print.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" +#include "app-layer/http/parser.h" + +#include "util/mpm/mpm.h" +#include "util/print.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/spm.h" #include "conf.h" /* prototypes */ @@ -64,7 +64,7 @@ static int g_http_uri_buffer_id = 0; /** * \brief Registration function for uricontent: keyword */ -void DetectUricontentRegister (void) +void DetectUricontentRegister(void) { sigmatch_table[DETECT_URICONTENT].name = "uricontent"; sigmatch_table[DETECT_URICONTENT].desc = "legacy keyword to match on the request URI buffer"; @@ -72,7 +72,8 @@ void DetectUricontentRegister (void) sigmatch_table[DETECT_URICONTENT].Match = NULL; sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup; sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; - sigmatch_table[DETECT_URICONTENT].flags = (SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION); + sigmatch_table[DETECT_URICONTENT].flags = + (SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION); sigmatch_table[DETECT_URICONTENT].alternative = DETECT_HTTP_URI; g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); diff --git a/src/detect-uricontent.h b/src/detect-uricontent.h index 289afff33a4f..6f0e5a65f83a 100644 --- a/src/detect-uricontent.h +++ b/src/detect-uricontent.h @@ -26,6 +26,6 @@ #define __DETECT_URICONTENT_H__ /* prototypes */ -void DetectUricontentRegister (void); +void DetectUricontentRegister(void); #endif /* __DETECT_URICONTENT_H__ */ diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 67acda5d5c58..b2af053c6a66 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -26,9 +26,9 @@ #include "suricata-common.h" #include "app-layer.h" #include "app-layer-protos.h" -#include "app-layer-htp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "app-layer/http/parser.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect.h" #include "detect-parse.h" @@ -39,17 +39,16 @@ #include "detect-engine-uint.h" #include "detect-urilen.h" -#include "util-debug.h" -#include "util-byte.h" +#include "util/debug.h" +#include "util/byte.h" #include "flow-util.h" #include "stream-tcp.h" - /*prototypes*/ -static int DetectUrilenSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectUrilenFree (DetectEngineCtx *, void *); +static int DetectUrilenSetup(DetectEngineCtx *, Signature *, const char *); +static void DetectUrilenFree(DetectEngineCtx *, void *); #ifdef UNITTESTS -static void DetectUrilenRegisterTests (void); +static void DetectUrilenRegisterTests(void); #endif static int g_http_uri_buffer_id = 0; static int g_http_raw_uri_buffer_id = 0; @@ -83,7 +82,7 @@ void DetectUrilenRegister(void) * \retval NULL on failure */ -static DetectUrilenData *DetectUrilenParse (const char *urilenstr) +static DetectUrilenData *DetectUrilenParse(const char *urilenstr) { return rs_detect_urilen_parse(urilenstr); } @@ -98,7 +97,7 @@ static DetectUrilenData *DetectUrilenParse (const char *urilenstr) * \retval 0 on Success * \retval -1 on Failure */ -static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, const char *urilenstr) +static int DetectUrilenSetup(DetectEngineCtx *de_ctx, Signature *s, const char *urilenstr) { SCEnter(); DetectUrilenData *urilend = NULL; @@ -423,8 +422,8 @@ static int DetectUrilenParseTest10(void) * */ -static int DetectUrilenInitTest(DetectEngineCtx **de_ctx, Signature **sig, - DetectUrilenData **urilend, const char *str) +static int DetectUrilenInitTest( + DetectEngineCtx **de_ctx, Signature **sig, DetectUrilenData **urilend, const char *str) { char fullstr[1024]; int result = 0; @@ -432,8 +431,10 @@ static int DetectUrilenInitTest(DetectEngineCtx **de_ctx, Signature **sig, *de_ctx = NULL; *sig = NULL; - if (snprintf(fullstr, 1024, "alert ip any any -> any any (msg:\"Urilen " - "test\"; urilen:%s; sid:1;)", str) >= 1024) { + if (snprintf(fullstr, 1024, + "alert ip any any -> any any (msg:\"Urilen " + "test\"; urilen:%s; sid:1;)", + str) >= 1024) { goto end; } @@ -479,7 +480,7 @@ static int DetectUrilenSetpTest01(void) goto end; } - if(urilend == NULL) + if (urilend == NULL) goto cleanup; if (urilend != NULL) { @@ -528,7 +529,7 @@ static int DetectUrilenSigTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -540,18 +541,16 @@ static int DetectUrilenSigTest01(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing urilen\"; " - "urilen: <5; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing urilen\"; " + "urilen: <5; sid:1;)"); if (s == NULL) { goto end; } - s = s->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "urilen: >5; sid:2;)"); + s = s->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "urilen: >5; sid:2;)"); if (s == NULL) { goto end; } @@ -588,9 +587,12 @@ static int DetectUrilenSigTest01(void) end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) SigGroupCleanup(de_ctx); - if (de_ctx != NULL) SigCleanSignatures(de_ctx); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(true); FLOW_DESTROY(&f); diff --git a/src/detect-urilen.h b/src/detect-urilen.h index ccd319c75513..752255fb9dcb 100644 --- a/src/detect-urilen.h +++ b/src/detect-urilen.h @@ -22,11 +22,10 @@ */ #ifndef _DETECT_URILEN_H -#define _DETECT_URILEN_H +#define _DETECT_URILEN_H bool DetectUrilenValidateContent(const Signature *s, int list, const char **); void DetectUrilenApplyToContent(Signature *s, int list); void DetectUrilenRegister(void); -#endif /* _DETECT_URILEN_H */ - +#endif /* _DETECT_URILEN_H */ diff --git a/src/detect-within.c b/src/detect-within.c index 91662e070fde..81494d42de36 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -38,11 +38,11 @@ #include "flow-var.h" -#include "util-byte.h" -#include "util-debug.h" +#include "util/byte.h" +#include "util/debug.h" #include "detect-pcre.h" #include "detect-within.h" -#include "util-unittest.h" +#include "util/unittest.h" static int DetectWithinSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS @@ -52,7 +52,8 @@ static void DetectWithinRegisterTests(void); void DetectWithinRegister(void) { sigmatch_table[DETECT_WITHIN].name = "within"; - sigmatch_table[DETECT_WITHIN].desc = "indicate that this content match has to be within a certain distance of the previous content keyword match"; + sigmatch_table[DETECT_WITHIN].desc = "indicate that this content match has to be within a " + "certain distance of the previous content keyword match"; sigmatch_table[DETECT_WITHIN].url = "/rules/payload-keywords.html#within"; sigmatch_table[DETECT_WITHIN].Match = NULL; sigmatch_table[DETECT_WITHIN].Setup = DetectWithinSetup; @@ -132,8 +133,7 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, const char * /* these are the only ones against which we set a flag. We have other * relative keywords like byttest, isdataat, bytejump, but we don't * set a flag against them */ - SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, - DETECT_CONTENT, DETECT_PCRE, -1); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, DETECT_CONTENT, DETECT_PCRE, -1); if (prev_pm == NULL) { return 0; } @@ -157,19 +157,19 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, const char * /***********************************Unittests**********************************/ #ifdef UNITTESTS -#include "util-unittest-helper.h" - /** +#include "util/unittest-helper.h" +/** * \test DetectWithinTestPacket01 is a test to check matches of * within, if the previous keyword is pcre (bug 145) */ -static int DetectWithinTestPacket01 (void) +static int DetectWithinTestPacket01(void) { uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" - "User-Agent: Wget/1.11.4" - "Accept: */*" - "Host: www.google.com" - "Connection: Keep-Alive" - "Date: Mon, 04 Jan 2010 17:29:39 GMT"; + "User-Agent: Wget/1.11.4" + "Accept: */*" + "Host: www.google.com" + "Connection: Keep-Alive" + "Date: Mon, 04 Jan 2010 17:29:39 GMT"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); @@ -185,8 +185,7 @@ static int DetectWithinTestPacket01 (void) PASS; } - -static int DetectWithinTestPacket02 (void) +static int DetectWithinTestPacket02(void) { uint8_t *buf = (uint8_t *)"Zero Five Ten Fourteen"; uint16_t buflen = strlen((char *)buf); @@ -207,14 +206,14 @@ static int DetectWithinTestPacket02 (void) static int DetectWithinTestVarSetup(void) { char sig[] = "alert tcp any any -> any any ( " - "msg:\"test rule\"; " - "content:\"abc\"; " - "http_client_body; " - "byte_extract:2,0,somevar,relative; " - "content:\"def\"; " - "within:somevar; " - "http_client_body; " - "sid:4; rev:1;)"; + "msg:\"test rule\"; " + "content:\"abc\"; " + "http_client_body; " + "byte_extract:2,0,somevar,relative; " + "content:\"def\"; " + "within:somevar; " + "http_client_body; " + "sid:4; rev:1;)"; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); diff --git a/src/detect-within.h b/src/detect-within.h index 7ccaf2648ae3..c5ec8c06f2f2 100644 --- a/src/detect-within.h +++ b/src/detect-within.h @@ -25,7 +25,6 @@ #define __DETECT_WITHIN_H__ /* prototypes */ -void DetectWithinRegister (void); +void DetectWithinRegister(void); #endif /* __DETECT_WITHIN_H__ */ - diff --git a/src/detect-xbits.c b/src/detect-xbits.c index a3f67dbfc9b7..f90aeebf7a23 100644 --- a/src/detect-xbits.c +++ b/src/detect-xbits.c @@ -31,8 +31,8 @@ #include "flow-util.h" #include "detect-xbits.h" #include "detect-hostbits.h" -#include "util-spm.h" -#include "util-byte.h" +#include "util/spm.h" +#include "util/byte.h" #include "detect-engine-sigorder.h" @@ -47,32 +47,37 @@ #include "flow-bit.h" #include "host-bit.h" #include "ippair-bit.h" -#include "util-var-name.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/var-name.h" +#include "util/unittest.h" +#include "util/debug.h" /* xbits:set,bitname,track ip_pair,expire 60 */ -#define PARSE_REGEX "^([a-z]+)" "(?:,\\s*([^,]+))?" "(?:,\\s*(?:track\\s+([^,]+)))" "(?:,\\s*(?:expire\\s+([^,]+)))?" +#define PARSE_REGEX \ + "^([a-z]+)" \ + "(?:,\\s*([^,]+))?" \ + "(?:,\\s*(?:track\\s+([^,]+)))" \ + "(?:,\\s*(?:expire\\s+([^,]+)))?" static DetectParseRegex parse_regex; -static int DetectXbitMatch (DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); -static int DetectXbitSetup (DetectEngineCtx *, Signature *, const char *); +static int DetectXbitMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectXbitSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void XBitsRegisterTests(void); #endif -static void DetectXbitFree (DetectEngineCtx *, void *); +static void DetectXbitFree(DetectEngineCtx *, void *); -void DetectXbitsRegister (void) +void DetectXbitsRegister(void) { sigmatch_table[DETECT_XBITS].name = "xbits"; sigmatch_table[DETECT_XBITS].desc = "operate on bits"; sigmatch_table[DETECT_XBITS].url = "/rules/xbits.html"; sigmatch_table[DETECT_XBITS].Match = DetectXbitMatch; sigmatch_table[DETECT_XBITS].Setup = DetectXbitSetup; - sigmatch_table[DETECT_XBITS].Free = DetectXbitFree; + sigmatch_table[DETECT_XBITS].Free = DetectXbitFree; #ifdef UNITTESTS sigmatch_table[DETECT_XBITS].RegisterTests = XBitsRegisterTests; #endif @@ -82,7 +87,7 @@ void DetectXbitsRegister (void) DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } -static int DetectIPPairbitMatchToggle (Packet *p, const DetectXbitsData *fd) +static int DetectIPPairbitMatchToggle(Packet *p, const DetectXbitsData *fd) { IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); if (pair == NULL) @@ -94,18 +99,18 @@ static int DetectIPPairbitMatchToggle (Packet *p, const DetectXbitsData *fd) } /* return true even if bit not found */ -static int DetectIPPairbitMatchUnset (Packet *p, const DetectXbitsData *fd) +static int DetectIPPairbitMatchUnset(Packet *p, const DetectXbitsData *fd) { IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); if (pair == NULL) return 1; - IPPairBitUnset(pair,fd->idx); + IPPairBitUnset(pair, fd->idx); IPPairRelease(pair); return 1; } -static int DetectIPPairbitMatchSet (Packet *p, const DetectXbitsData *fd) +static int DetectIPPairbitMatchSet(Packet *p, const DetectXbitsData *fd) { IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); if (pair == NULL) @@ -116,7 +121,7 @@ static int DetectIPPairbitMatchSet (Packet *p, const DetectXbitsData *fd) return 1; } -static int DetectIPPairbitMatchIsset (Packet *p, const DetectXbitsData *fd) +static int DetectIPPairbitMatchIsset(Packet *p, const DetectXbitsData *fd) { int r = 0; IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); @@ -128,7 +133,7 @@ static int DetectIPPairbitMatchIsset (Packet *p, const DetectXbitsData *fd) return r; } -static int DetectIPPairbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) +static int DetectIPPairbitMatchIsnotset(Packet *p, const DetectXbitsData *fd) { int r = 0; IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); @@ -144,15 +149,15 @@ static int DetectXbitMatchIPPair(Packet *p, const DetectXbitsData *xd) { switch (xd->cmd) { case DETECT_XBITS_CMD_ISSET: - return DetectIPPairbitMatchIsset(p,xd); + return DetectIPPairbitMatchIsset(p, xd); case DETECT_XBITS_CMD_ISNOTSET: - return DetectIPPairbitMatchIsnotset(p,xd); + return DetectIPPairbitMatchIsnotset(p, xd); case DETECT_XBITS_CMD_SET: - return DetectIPPairbitMatchSet(p,xd); + return DetectIPPairbitMatchSet(p, xd); case DETECT_XBITS_CMD_UNSET: - return DetectIPPairbitMatchUnset(p,xd); + return DetectIPPairbitMatchUnset(p, xd); case DETECT_XBITS_CMD_TOGGLE: - return DetectIPPairbitMatchToggle(p,xd); + return DetectIPPairbitMatchToggle(p, xd); } return 0; } @@ -163,7 +168,8 @@ static int DetectXbitMatchIPPair(Packet *p, const DetectXbitsData *xd) * -1: error */ -static int DetectXbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) +static int DetectXbitMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectXbitsData *fd = (const DetectXbitsData *)ctx; if (fd == NULL) @@ -188,8 +194,7 @@ static int DetectXbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, const Sig * \retval -1 bad * \param[out] cdout return DetectXbitsData structure or NULL if noalert */ -static int DetectXbitParse(DetectEngineCtx *de_ctx, - const char *rawstr, DetectXbitsData **cdout) +static int DetectXbitParse(DetectEngineCtx *de_ctx, const char *rawstr, DetectXbitsData **cdout) { DetectXbitsData *cd = NULL; uint8_t fb_cmd = 0; @@ -281,17 +286,17 @@ static int DetectXbitParse(DetectEngineCtx *de_ctx, } pcre2_match_data_free(match); - if (strcmp(fb_cmd_str,"noalert") == 0) { + if (strcmp(fb_cmd_str, "noalert") == 0) { fb_cmd = DETECT_XBITS_CMD_NOALERT; - } else if (strcmp(fb_cmd_str,"isset") == 0) { + } else if (strcmp(fb_cmd_str, "isset") == 0) { fb_cmd = DETECT_XBITS_CMD_ISSET; - } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + } else if (strcmp(fb_cmd_str, "isnotset") == 0) { fb_cmd = DETECT_XBITS_CMD_ISNOTSET; - } else if (strcmp(fb_cmd_str,"set") == 0) { + } else if (strcmp(fb_cmd_str, "set") == 0) { fb_cmd = DETECT_XBITS_CMD_SET; - } else if (strcmp(fb_cmd_str,"unset") == 0) { + } else if (strcmp(fb_cmd_str, "unset") == 0) { fb_cmd = DETECT_XBITS_CMD_UNSET; - } else if (strcmp(fb_cmd_str,"toggle") == 0) { + } else if (strcmp(fb_cmd_str, "toggle") == 0) { fb_cmd = DETECT_XBITS_CMD_TOGGLE; } else { SCLogError("xbits action \"%s\" is not supported.", fb_cmd_str); @@ -326,14 +331,14 @@ static int DetectXbitParse(DetectEngineCtx *de_ctx, cd->type = var_type; cd->expire = expire; - SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", - cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", cd->idx, fb_cmd_str, + strlen(fb_name) ? fb_name : "(none)"); *cdout = cd; return 0; } -int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) +int DetectXbitSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { DetectXbitsData *cd = NULL; @@ -375,7 +380,7 @@ int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) return 0; } -static void DetectXbitFree (DetectEngineCtx *de_ctx, void *ptr) +static void DetectXbitFree(DetectEngineCtx *de_ctx, void *ptr) { DetectXbitsData *fd = (DetectXbitsData *)ptr; @@ -405,7 +410,6 @@ static void XBitsTestShutdown(void) StorageCleanup(); } - static int XBitsTestParse01(void) { DetectEngineCtx *de_ctx = NULL; @@ -414,8 +418,7 @@ static int XBitsTestParse01(void) de_ctx->flags |= DE_QUIET; DetectXbitsData *cd = NULL; -#define BAD_INPUT(str) \ - FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == -1); +#define BAD_INPUT(str) FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == -1); BAD_INPUT("alert"); BAD_INPUT("n0alert"); @@ -427,28 +430,22 @@ static int XBitsTestParse01(void) #undef BAD_INPUT -#define GOOD_INPUT(str, command, trk, typ, exp) \ - FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == 0); \ - FAIL_IF_NULL(cd); \ - FAIL_IF_NOT(cd->cmd == (command)); \ - FAIL_IF_NOT(cd->tracker == (trk)); \ - FAIL_IF_NOT(cd->type == (typ)); \ - FAIL_IF_NOT(cd->expire == (exp)); \ - DetectXbitFree(NULL, cd); \ +#define GOOD_INPUT(str, command, trk, typ, exp) \ + FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == 0); \ + FAIL_IF_NULL(cd); \ + FAIL_IF_NOT(cd->cmd == (command)); \ + FAIL_IF_NOT(cd->tracker == (trk)); \ + FAIL_IF_NOT(cd->type == (typ)); \ + FAIL_IF_NOT(cd->expire == (exp)); \ + DetectXbitFree(NULL, cd); \ cd = NULL; - GOOD_INPUT("set,abc,track ip_pair", - DETECT_XBITS_CMD_SET, - DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, - DETECT_XBITS_EXPIRE_DEFAULT); - GOOD_INPUT("set,abc,track ip_pair, expire 3600", - DETECT_XBITS_CMD_SET, - DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, - 3600); - GOOD_INPUT("set,abc,track ip_src, expire 1234", - DETECT_XBITS_CMD_SET, - DETECT_XBITS_TRACK_IPSRC, VAR_TYPE_HOST_BIT, - 1234); + GOOD_INPUT("set,abc,track ip_pair", DETECT_XBITS_CMD_SET, DETECT_XBITS_TRACK_IPPAIR, + VAR_TYPE_IPPAIR_BIT, DETECT_XBITS_EXPIRE_DEFAULT); + GOOD_INPUT("set,abc,track ip_pair, expire 3600", DETECT_XBITS_CMD_SET, + DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, 3600); + GOOD_INPUT("set,abc,track ip_src, expire 1234", DETECT_XBITS_CMD_SET, DETECT_XBITS_TRACK_IPSRC, + VAR_TYPE_HOST_BIT, 1234); #undef GOOD_INPUT @@ -462,10 +459,9 @@ static int XBitsTestParse01(void) static int XBitsTestSig01(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); @@ -522,8 +518,8 @@ static int XBitsTestSig02(void) "alert ip any any -> any any (xbits:isset,abc,track ip_src; content:\"GET \"; sid:1;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (xbits:isnotset,abc,track ip_dst; content:\"GET \"; sid:2;)"); + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:isnotset,abc,track " + "ip_dst; content:\"GET \"; sid:2;)"); FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, @@ -534,8 +530,8 @@ static int XBitsTestSig02(void) "alert ip any any -> any any (xbits:unset,abc,track ip_src; content:\"GET \"; sid:4;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (xbits:toggle,abc,track ip_dst; content:\"GET \"; sid:5;)"); + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (xbits:toggle,abc,track ip_dst; " + "content:\"GET \"; sid:5;)"); FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, diff --git a/src/detect-xbits.h b/src/detect-xbits.h index 516bfdcfd1bc..b8cacf1f4114 100644 --- a/src/detect-xbits.h +++ b/src/detect-xbits.h @@ -47,6 +47,6 @@ typedef struct DetectXbitsData_ { } DetectXbitsData; /* prototypes */ -void DetectXbitsRegister (void); +void DetectXbitsRegister(void); #endif /* __DETECT_XBITS_H__ */ diff --git a/src/detect.c b/src/detect.c index 5cb4e6bfbc44..607a5941d335 100644 --- a/src/detect.c +++ b/src/detect.c @@ -61,9 +61,9 @@ #include "detect-flowvar.h" #include "detect-replace.h" -#include "util-validate.h" -#include "util-detect.h" -#include "util-profiling.h" +#include "util/validate.h" +#include "util/detect.h" +#include "util/profiling.h" #include "action-globals.h" @@ -77,33 +77,29 @@ typedef struct DetectRunScratchpad { /* prototypes */ static DetectRunScratchpad DetectRunSetup(const DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Packet * const p, Flow * const pflow); + DetectEngineThreadCtx *det_ctx, Packet *const p, Flow *const pflow); static void DetectRunInspectIPOnly(ThreadVars *tv, const DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow * const pflow, Packet * const p); -static inline void DetectRunGetRuleGroup(const DetectEngineCtx *de_ctx, - Packet * const p, Flow * const pflow, DetectRunScratchpad *scratch); -static inline void DetectRunPrefilterPkt(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, - DetectRunScratchpad *scratch); -static inline void DetectRulePacketRules(ThreadVars * const tv, - DetectEngineCtx * const de_ctx, DetectEngineThreadCtx * const det_ctx, - Packet * const p, Flow * const pflow, const DetectRunScratchpad *scratch); -static void DetectRunTx(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Packet *p, - Flow *f, DetectRunScratchpad *scratch); + DetectEngineThreadCtx *det_ctx, Flow *const pflow, Packet *const p); +static inline void DetectRunGetRuleGroup(const DetectEngineCtx *de_ctx, Packet *const p, + Flow *const pflow, DetectRunScratchpad *scratch); +static inline void DetectRunPrefilterPkt(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Packet *p, DetectRunScratchpad *scratch); +static inline void DetectRulePacketRules(ThreadVars *const tv, DetectEngineCtx *const de_ctx, + DetectEngineThreadCtx *const det_ctx, Packet *const p, Flow *const pflow, + const DetectRunScratchpad *scratch); +static void DetectRunTx(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Packet *p, Flow *f, DetectRunScratchpad *scratch); static void DetectRunFrames(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, DetectRunScratchpad *scratch); static inline void DetectRunPostRules(ThreadVars *tv, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Packet * const p, Flow * const pflow, + DetectEngineThreadCtx *det_ctx, Packet *const p, Flow *const pflow, DetectRunScratchpad *scratch); -static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx, - Packet *p, Flow * const pflow); +static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx, Packet *p, Flow *const pflow); /** \internal */ -static void DetectRun(ThreadVars *th_v, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Packet *p) +static void DetectRun( + ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { SCEnter(); SCLogDebug("p->pcap_cnt %" PRIu64 " direction %s pkt_src %s", p->pcap_cnt, @@ -119,7 +115,7 @@ static void DetectRun(ThreadVars *th_v, /* Load the Packet's flow early, even though it might not be needed. * Mark as a constant pointer, although the flow itself can change. */ - Flow * const pflow = p->flow; + Flow *const pflow = p->flow; DetectRunScratchpad scratch = DetectRunSetup(de_ctx, det_ctx, p, pflow); @@ -168,9 +164,8 @@ static void DetectRun(ThreadVars *th_v, SCReturn; } -static void DetectRunPostMatch(ThreadVars *tv, - DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s) +static void DetectRunPostMatch( + ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s) { /* run the packet match functions */ const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; @@ -198,8 +193,7 @@ static void DetectRunPostMatch(ThreadVars *tv, * * \retval sgh the SigGroupHead or NULL if non applies to the packet */ -const SigGroupHead *SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, - const Packet *p) +const SigGroupHead *SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, const Packet *p) { SCEnter(); @@ -226,23 +220,23 @@ const SigGroupHead *SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, int proto = IP_GET_IPPROTO(p); if (proto == IPPROTO_TCP) { DetectPort *list = de_ctx->flow_gh[f].tcp; - SCLogDebug("tcp toserver %p, tcp toclient %p: going to use %p", - de_ctx->flow_gh[1].tcp, de_ctx->flow_gh[0].tcp, de_ctx->flow_gh[f].tcp); + SCLogDebug("tcp toserver %p, tcp toclient %p: going to use %p", de_ctx->flow_gh[1].tcp, + de_ctx->flow_gh[0].tcp, de_ctx->flow_gh[f].tcp); uint16_t port = f ? p->dp : p->sp; SCLogDebug("tcp port %u -> %u:%u", port, p->sp, p->dp); DetectPort *sghport = DetectPortLookupGroup(list, port); if (sghport != NULL) sgh = sghport->sh; - SCLogDebug("TCP list %p, port %u, direction %s, sghport %p, sgh %p", - list, port, f ? "toserver" : "toclient", sghport, sgh); + SCLogDebug("TCP list %p, port %u, direction %s, sghport %p, sgh %p", list, port, + f ? "toserver" : "toclient", sghport, sgh); } else if (proto == IPPROTO_UDP) { DetectPort *list = de_ctx->flow_gh[f].udp; uint16_t port = f ? p->dp : p->sp; DetectPort *sghport = DetectPortLookupGroup(list, port); if (sghport != NULL) sgh = sghport->sh; - SCLogDebug("UDP list %p, port %u, direction %s, sghport %p, sgh %p", - list, port, f ? "toserver" : "toclient", sghport, sgh); + SCLogDebug("UDP list %p, port %u, direction %s, sghport %p, sgh %p", list, port, + f ? "toserver" : "toclient", sghport, sgh); } else { sgh = de_ctx->flow_gh[f].sgh[proto]; } @@ -250,8 +244,7 @@ const SigGroupHead *SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, SCReturnPtr(sgh, "SigGroupHead"); } -static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx) +static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { SigIntId mpm, nonmpm; SigIntId *mpm_ptr = det_ctx->pmq.rule_id_array; @@ -301,25 +294,25 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, final_ptr = nonmpm_ptr; final_cnt = n_cnt; goto final; - } - mpm_ptr++; - mpm = *mpm_ptr; - } else if (mpm > nonmpm) { - id = nonmpm; - - s = sig_array[id]; - /* As the mpm list can contain duplicates, check for that here. */ - if (likely(id != previous_id)) { - *match_array++ = s; - previous_id = id; - } - if (unlikely(--n_cnt == 0)) { - final_ptr = mpm_ptr; - final_cnt = m_cnt; - goto final; - } - nonmpm_ptr++; - nonmpm = *nonmpm_ptr; + } + mpm_ptr++; + mpm = *mpm_ptr; + } else if (mpm > nonmpm) { + id = nonmpm; + + s = sig_array[id]; + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; + } + if (unlikely(--n_cnt == 0)) { + final_ptr = mpm_ptr; + final_cnt = m_cnt; + goto final; + } + nonmpm_ptr++; + nonmpm = *nonmpm_ptr; } else { /* implied mpm == nonmpm */ /* special case: if on both lists, it's a negated mpm pattern */ @@ -355,7 +348,7 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, } } - final: /* Only one list remaining. Just walk that list. */ +final: /* Only one list remaining. Just walk that list. */ while (final_cnt-- > 0) { id = *final_ptr++; @@ -369,7 +362,8 @@ static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, } det_ctx->match_array_cnt = match_array - det_ctx->match_array; - DEBUG_VALIDATE_BUG_ON((det_ctx->pmq.rule_id_array_cnt + det_ctx->non_pf_id_cnt) < det_ctx->match_array_cnt); + DEBUG_VALIDATE_BUG_ON( + (det_ctx->pmq.rule_id_array_cnt + det_ctx->non_pf_id_cnt) < det_ctx->match_array_cnt); PMQ_RESET(&det_ctx->pmq); } @@ -395,8 +389,8 @@ static inline void DetectPrefilterBuildNonPrefilterList( * \brief select non-mpm list * Based on the packet properties, select the non-mpm list to use * \todo move non_pf_store* into scratchpad */ -static inline void -DetectPrefilterSetNonPrefilterList(const Packet *p, DetectEngineThreadCtx *det_ctx, DetectRunScratchpad *scratch) +static inline void DetectPrefilterSetNonPrefilterList( + const Packet *p, DetectEngineThreadCtx *det_ctx, DetectRunScratchpad *scratch) { if ((p->proto == IPPROTO_TCP) && (p->tcph != NULL) && (p->tcph->th_flags & TH_SYN)) { det_ctx->non_pf_store_ptr = scratch->sgh->non_pf_syn_store_array; @@ -405,10 +399,10 @@ DetectPrefilterSetNonPrefilterList(const Packet *p, DetectEngineThreadCtx *det_c det_ctx->non_pf_store_ptr = scratch->sgh->non_pf_other_store_array; det_ctx->non_pf_store_cnt = scratch->sgh->non_pf_other_store_cnt; } - SCLogDebug("sgh non_pf ptr %p cnt %u (syn %p/%u, other %p/%u)", - det_ctx->non_pf_store_ptr, det_ctx->non_pf_store_cnt, - scratch->sgh->non_pf_syn_store_array, scratch->sgh->non_pf_syn_store_cnt, - scratch->sgh->non_pf_other_store_array, scratch->sgh->non_pf_other_store_cnt); + SCLogDebug("sgh non_pf ptr %p cnt %u (syn %p/%u, other %p/%u)", det_ctx->non_pf_store_ptr, + det_ctx->non_pf_store_cnt, scratch->sgh->non_pf_syn_store_array, + scratch->sgh->non_pf_syn_store_cnt, scratch->sgh->non_pf_other_store_array, + scratch->sgh->non_pf_other_store_cnt); } /** \internal @@ -416,8 +410,8 @@ DetectPrefilterSetNonPrefilterList(const Packet *p, DetectEngineThreadCtx *det_c * A set of flags is prepared that is sent to the File API. The File API may reject one or more based on the global force settings. */ -static inline void -DetectPostInspectFileFlagsUpdate(Flow *f, const SigGroupHead *sgh, uint8_t direction) +static inline void DetectPostInspectFileFlagsUpdate( + Flow *f, const SigGroupHead *sgh, uint8_t direction) { uint16_t flow_file_flags = FLOWFILE_INIT; @@ -427,29 +421,29 @@ DetectPostInspectFileFlagsUpdate(Flow *f, const SigGroupHead *sgh, uint8_t direc } else { if (sgh->filestore_cnt == 0) { SCLogDebug("requesting disabling filestore for flow"); - flow_file_flags |= (FLOWFILE_NO_STORE_TS|FLOWFILE_NO_STORE_TC); + flow_file_flags |= (FLOWFILE_NO_STORE_TS | FLOWFILE_NO_STORE_TC); } #ifdef HAVE_MAGIC if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC)) { SCLogDebug("requesting disabling magic for flow"); - flow_file_flags |= (FLOWFILE_NO_MAGIC_TS|FLOWFILE_NO_MAGIC_TC); + flow_file_flags |= (FLOWFILE_NO_MAGIC_TS | FLOWFILE_NO_MAGIC_TC); } #endif if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMD5)) { SCLogDebug("requesting disabling md5 for flow"); - flow_file_flags |= (FLOWFILE_NO_MD5_TS|FLOWFILE_NO_MD5_TC); + flow_file_flags |= (FLOWFILE_NO_MD5_TS | FLOWFILE_NO_MD5_TC); } if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA1)) { SCLogDebug("requesting disabling sha1 for flow"); - flow_file_flags |= (FLOWFILE_NO_SHA1_TS|FLOWFILE_NO_SHA1_TC); + flow_file_flags |= (FLOWFILE_NO_SHA1_TS | FLOWFILE_NO_SHA1_TC); } if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA256)) { SCLogDebug("requesting disabling sha256 for flow"); - flow_file_flags |= (FLOWFILE_NO_SHA256_TS|FLOWFILE_NO_SHA256_TC); + flow_file_flags |= (FLOWFILE_NO_SHA256_TS | FLOWFILE_NO_SHA256_TC); } if (!(sgh->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) { SCLogDebug("requesting disabling filesize for flow"); - flow_file_flags |= (FLOWFILE_NO_SIZE_TS|FLOWFILE_NO_SIZE_TC); + flow_file_flags |= (FLOWFILE_NO_SIZE_TS | FLOWFILE_NO_SIZE_TC); } } if (flow_file_flags != 0) { @@ -457,15 +451,16 @@ DetectPostInspectFileFlagsUpdate(Flow *f, const SigGroupHead *sgh, uint8_t direc } } -static inline void -DetectRunPostGetFirstRuleGroup(const Packet *p, Flow *pflow, const SigGroupHead *sgh) +static inline void DetectRunPostGetFirstRuleGroup( + const Packet *p, Flow *pflow, const SigGroupHead *sgh) { if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) { /* first time we see this toserver sgh, store it */ pflow->sgh_toserver = sgh; pflow->flags |= FLOW_SGH_TOSERVER; - if (p->proto == IPPROTO_TCP && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) { + if (p->proto == IPPROTO_TCP && + (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) { if (pflow->protoctx != NULL) { TcpSession *ssn = pflow->protoctx; SCLogDebug("STREAMTCP_STREAM_FLAG_DISABLE_RAW ssn.client"); @@ -473,14 +468,14 @@ DetectRunPostGetFirstRuleGroup(const Packet *p, Flow *pflow, const SigGroupHead } } - DetectPostInspectFileFlagsUpdate(pflow, - pflow->sgh_toserver, STREAM_TOSERVER); + DetectPostInspectFileFlagsUpdate(pflow, pflow->sgh_toserver, STREAM_TOSERVER); } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) { pflow->sgh_toclient = sgh; pflow->flags |= FLOW_SGH_TOCLIENT; - if (p->proto == IPPROTO_TCP && (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) { + if (p->proto == IPPROTO_TCP && + (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVERAWSTREAM))) { if (pflow->protoctx != NULL) { TcpSession *ssn = pflow->protoctx; SCLogDebug("STREAMTCP_STREAM_FLAG_DISABLE_RAW ssn.server"); @@ -488,15 +483,12 @@ DetectRunPostGetFirstRuleGroup(const Packet *p, Flow *pflow, const SigGroupHead } } - DetectPostInspectFileFlagsUpdate(pflow, - pflow->sgh_toclient, STREAM_TOCLIENT); + DetectPostInspectFileFlagsUpdate(pflow, pflow->sgh_toclient, STREAM_TOCLIENT); } } -static inline void DetectRunGetRuleGroup( - const DetectEngineCtx *de_ctx, - Packet * const p, Flow * const pflow, - DetectRunScratchpad *scratch) +static inline void DetectRunGetRuleGroup(const DetectEngineCtx *de_ctx, Packet *const p, + Flow *const pflow, DetectRunScratchpad *scratch) { const SigGroupHead *sgh = NULL; @@ -546,8 +538,7 @@ static inline void DetectRunGetRuleGroup( } static void DetectRunInspectIPOnly(ThreadVars *tv, const DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Flow * const pflow, Packet * const p) + DetectEngineThreadCtx *det_ctx, Flow *const pflow, Packet *const p) { if (pflow) { /* set the iponly stuff */ @@ -556,9 +547,10 @@ static void DetectRunInspectIPOnly(ThreadVars *tv, const DetectEngineCtx *de_ctx if (pflow->flags & FLOW_TOSERVER_IPONLY_SET) p->flowflags |= FLOW_PKT_TOSERVER_IPONLY_SET; - if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || - ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) - { + if (((p->flowflags & FLOW_PKT_TOSERVER) && + !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || + ((p->flowflags & FLOW_PKT_TOCLIENT) && + !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) { SCLogDebug("testing against \"ip-only\" signatures"); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_IPONLY); @@ -579,12 +571,8 @@ static void DetectRunInspectIPOnly(ThreadVars *tv, const DetectEngineCtx *de_ctx } /* returns 0 if no match, 1 if match */ -static inline int DetectRunInspectRuleHeader( - const Packet *p, - const Flow *f, - const Signature *s, - const uint32_t sflags, - const uint8_t s_proto_flags) +static inline int DetectRunInspectRuleHeader(const Packet *p, const Flow *f, const Signature *s, + const uint32_t sflags, const uint8_t s_proto_flags) { /* check if this signature has a requirement for flowvars of some type * and if so, if we actually have any in the flow. If not, the sig @@ -592,12 +580,12 @@ static inline int DetectRunInspectRuleHeader( if ((p->flags & PKT_HAS_FLOW) && (sflags & SIG_FLAG_REQUIRE_FLOWVAR)) { DEBUG_VALIDATE_BUG_ON(f == NULL); - int m = f->flowvar ? 1 : 0; + int m = f->flowvar ? 1 : 0; /* no flowvars? skip this sig */ if (m == 0) { SCLogDebug("skipping sig as the flow has no flowvars and sig " - "has SIG_FLAG_REQUIRE_FLOWVAR flag set."); + "has SIG_FLAG_REQUIRE_FLOWVAR flag set."); return 0; } } @@ -621,7 +609,7 @@ static inline int DetectRunInspectRuleHeader( if (!(sflags & SIG_FLAG_DP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) return 0; - DetectPort *dport = DetectPortLookupGroup(s->dp,p->dp); + DetectPort *dport = DetectPortLookupGroup(s->dp, p->dp); if (dport == NULL) { SCLogDebug("dport didn't match."); return 0; @@ -630,13 +618,14 @@ static inline int DetectRunInspectRuleHeader( if (!(sflags & SIG_FLAG_SP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) return 0; - DetectPort *sport = DetectPortLookupGroup(s->sp,p->sp); + DetectPort *sport = DetectPortLookupGroup(s->sp, p->sp); if (sport == NULL) { SCLogDebug("sport didn't match."); return 0; } } - } else if ((sflags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) { + } else if ((sflags & (SIG_FLAG_DP_ANY | SIG_FLAG_SP_ANY)) != + (SIG_FLAG_DP_ANY | SIG_FLAG_SP_ANY)) { SCLogDebug("port-less protocol and sig needs ports"); return 0; } @@ -668,13 +657,8 @@ static inline int DetectRunInspectRuleHeader( /** \internal * \brief run packet/stream prefilter engines */ -static inline void DetectRunPrefilterPkt( - ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Packet *p, - DetectRunScratchpad *scratch -) +static inline void DetectRunPrefilterPkt(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Packet *p, DetectRunScratchpad *scratch) { DetectPrefilterSetNonPrefilterList(p, det_ctx, scratch); @@ -705,23 +689,16 @@ static inline void DetectRunPrefilterPkt( #ifdef PROFILING if (tv) { - StatsAddUI64(tv, det_ctx->counter_nonmpm_list, - (uint64_t)det_ctx->non_pf_store_cnt); + StatsAddUI64(tv, det_ctx->counter_nonmpm_list, (uint64_t)det_ctx->non_pf_store_cnt); /* non mpm sigs after mask prefilter */ - StatsAddUI64(tv, det_ctx->counter_fnonmpm_list, - (uint64_t)det_ctx->non_pf_id_cnt); + StatsAddUI64(tv, det_ctx->counter_fnonmpm_list, (uint64_t)det_ctx->non_pf_id_cnt); } #endif } -static inline void DetectRulePacketRules( - ThreadVars * const tv, - DetectEngineCtx * const de_ctx, - DetectEngineThreadCtx * const det_ctx, - Packet * const p, - Flow * const pflow, - const DetectRunScratchpad *scratch -) +static inline void DetectRulePacketRules(ThreadVars *const tv, DetectEngineCtx *const de_ctx, + DetectEngineThreadCtx *const det_ctx, Packet *const p, Flow *const pflow, + const DetectRunScratchpad *scratch) { const Signature *s = NULL; const Signature *next_s = NULL; @@ -731,8 +708,7 @@ static inline void DetectRulePacketRules( SigIntId match_cnt = det_ctx->match_array_cnt; #ifdef PROFILING if (tv) { - StatsAddUI64(tv, det_ctx->counter_match_list, - (uint64_t)match_cnt); + StatsAddUI64(tv, det_ctx->counter_match_list, (uint64_t)match_cnt); } #endif Signature **match_array = det_ctx->match_array; @@ -762,7 +738,7 @@ static inline void DetectRulePacketRules( } const uint8_t s_proto_flags = s->proto.flags; - SCLogDebug("inspecting signature id %"PRIu32"", s->id); + SCLogDebug("inspecting signature id %" PRIu32 "", s->id); if (s->app_inspect != NULL) { goto next; // handle sig in DetectRunTx @@ -803,7 +779,7 @@ static inline void DetectRulePacketRules( DetectRunPostMatch(tv, det_ctx, p, s); AlertQueueAppend(det_ctx, s, p, 0, alert_flags); -next: + next: DetectVarProcessList(det_ctx, pflow, p); DetectReplaceFree(det_ctx); RULE_PROFILING_END(det_ctx, s, smatch, p); @@ -813,10 +789,8 @@ static inline void DetectRulePacketRules( } } -static DetectRunScratchpad DetectRunSetup( - const DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Packet * const p, Flow * const pflow) +static DetectRunScratchpad DetectRunSetup(const DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Packet *const p, Flow *const pflow) { AppProto alproto = ALPROTO_UNKNOWN; uint8_t flow_flags = 0; /* flow/state flags */ @@ -887,10 +861,8 @@ static DetectRunScratchpad DetectRunSetup( /* Retrieve the app layer state and protocol and the tcp reassembled * stream chunks. */ - if ((p->proto == IPPROTO_TCP && (p->flags & PKT_STREAM_EST)) || - (p->proto == IPPROTO_UDP) || - (p->proto == IPPROTO_SCTP && (p->flowflags & FLOW_PKT_ESTABLISHED))) - { + if ((p->proto == IPPROTO_TCP && (p->flags & PKT_STREAM_EST)) || (p->proto == IPPROTO_UDP) || + (p->proto == IPPROTO_SCTP && (p->flowflags & FLOW_PKT_ESTABLISHED))) { /* update flow flags with knowledge on disruptions */ flow_flags = FlowGetDisruptionFlags(pflow, flow_flags); alproto = FlowGetAppProtocol(pflow); @@ -911,13 +883,9 @@ static DetectRunScratchpad DetectRunSetup( return pad; } -static inline void DetectRunPostRules( - ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Packet * const p, - Flow * const pflow, - DetectRunScratchpad *scratch) +static inline void DetectRunPostRules(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Packet *const p, Flow *const pflow, + DetectRunScratchpad *scratch) { /* see if we need to increment the inspect_id and reset the de_state */ if (pflow && pflow->alstate) { @@ -945,8 +913,7 @@ static inline void DetectRunPostRules( PACKET_PROFILING_DETECT_END(p, PROF_DETECT_ALERT); } -static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx, - Packet *p, Flow * const pflow) +static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx, Packet *p, Flow *const pflow) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_CLEANUP); InspectionBufferClean(det_ctx); @@ -955,8 +922,7 @@ static void DetectRunCleanup(DetectEngineThreadCtx *det_ctx, /* update inspected tracker for raw reassembly */ if (p->proto == IPPROTO_TCP && pflow->protoctx != NULL && (p->flags & PKT_DETECT_HAS_STREAMDATA)) { - StreamReassembleRawUpdateProgress(pflow->protoctx, p, - det_ctx->raw_stream_progress); + StreamReassembleRawUpdateProgress(pflow->protoctx, p, det_ctx->raw_stream_progress); } } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_CLEANUP); @@ -972,8 +938,8 @@ void RuleMatchCandidateTxArrayInit(DetectEngineThreadCtx *det_ctx, uint32_t size (uint64_t)(size * sizeof(RuleMatchCandidateTx))); } det_ctx->tx_candidates_size = size; - SCLogDebug("array initialized to %u elements (%"PRIu64" bytes)", - size, (uint64_t)(size * sizeof(RuleMatchCandidateTx))); + SCLogDebug("array initialized to %u elements (%" PRIu64 " bytes)", size, + (uint64_t)(size * sizeof(RuleMatchCandidateTx))); } void RuleMatchCandidateTxArrayFree(DetectEngineThreadCtx *det_ctx) @@ -983,8 +949,8 @@ void RuleMatchCandidateTxArrayFree(DetectEngineThreadCtx *det_ctx) } /* if size >= cur_space */ -static inline bool RuleMatchCandidateTxArrayHasSpace(const DetectEngineThreadCtx *det_ctx, - const uint32_t need) +static inline bool RuleMatchCandidateTxArrayHasSpace( + const DetectEngineThreadCtx *det_ctx, const uint32_t need) { if (det_ctx->tx_candidates_size >= need) return 1; @@ -1004,9 +970,10 @@ static int RuleMatchCandidateTxArrayExpand(DetectEngineThreadCtx *det_ctx, const } det_ctx->tx_candidates = ptmp; det_ctx->tx_candidates_size = new_size; - SCLogDebug("array expanded from %u to %u elements (%"PRIu64" bytes -> %"PRIu64" bytes)", + SCLogDebug("array expanded from %u to %u elements (%" PRIu64 " bytes -> %" PRIu64 " bytes)", old_size, new_size, (uint64_t)(old_size * sizeof(RuleMatchCandidateTx)), - (uint64_t)(new_size * sizeof(RuleMatchCandidateTx))); (void)old_size; + (uint64_t)(new_size * sizeof(RuleMatchCandidateTx))); + (void)old_size; return 1; } @@ -1016,8 +983,7 @@ static int RuleMatchCandidateTxArrayExpand(DetectEngineThreadCtx *det_ctx, const * The id field is set from Signature::num, so we sort the candidates to match the signature * sort order (ascending), where candidates that have flags go first. */ -static int -DetectRunTxSortHelper(const void *a, const void *b) +static int DetectRunTxSortHelper(const void *a, const void *b) { const RuleMatchCandidateTx *s0 = a; const RuleMatchCandidateTx *s1 = b; @@ -1032,14 +998,14 @@ DetectRunTxSortHelper(const void *a, const void *b) } #if 0 -#define TRACE_SID_TXS(sid,txs,...) \ - do { \ - char _trace_buf[2048]; \ - snprintf(_trace_buf, sizeof(_trace_buf), __VA_ARGS__); \ - SCLogNotice("%p/%"PRIu64"/%u: %s", txs->tx_ptr, txs->tx_id, sid, _trace_buf); \ - } while(0) +#define TRACE_SID_TXS(sid, txs, ...) \ + do { \ + char _trace_buf[2048]; \ + snprintf(_trace_buf, sizeof(_trace_buf), __VA_ARGS__); \ + SCLogNotice("%p/%" PRIu64 "/%u: %s", txs->tx_ptr, txs->tx_id, sid, _trace_buf); \ + } while (0) #else -#define TRACE_SID_TXS(sid,txs,...) +#define TRACE_SID_TXS(sid, txs, ...) #endif /** \internal @@ -1054,18 +1020,11 @@ DetectRunTxSortHelper(const void *a, const void *b) * * \retval bool true sig matched, false didn't match */ -static bool DetectRunTxInspectRule(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Packet *p, - Flow *f, - const uint8_t in_flow_flags, // direction, EOF, etc - void *alstate, - DetectTransaction *tx, - const Signature *s, - uint32_t *stored_flags, - RuleMatchCandidateTx *can, - DetectRunScratchpad *scratch) +static bool DetectRunTxInspectRule(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, + const uint8_t in_flow_flags, // direction, EOF, etc + void *alstate, DetectTransaction *tx, const Signature *s, uint32_t *stored_flags, + RuleMatchCandidateTx *can, DetectRunScratchpad *scratch) { uint8_t flow_flags = in_flow_flags; const int direction = (flow_flags & STREAM_TOSERVER) ? 0 : 1; @@ -1073,8 +1032,8 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, int total_matches = 0; uint16_t file_no_match = 0; bool retval = false; - bool mpm_before_progress = false; // is mpm engine before progress? - bool mpm_in_progress = false; // is mpm engine in a buffer we will revisit? + bool mpm_before_progress = false; // is mpm engine before progress? + bool mpm_in_progress = false; // is mpm engine in a buffer we will revisit? TRACE_SID_TXS(s->id, tx, "starting %s", direction ? "toclient" : "toserver"); @@ -1099,9 +1058,7 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, const DetectEngineAppInspectionEngine *engine = s->app_inspect; while (engine != NULL) { // TODO could be do {} while as s->app_inspect cannot be null TRACE_SID_TXS(s->id, tx, "engine %p inspect_flags %x", engine, inspect_flags); - if (!(inspect_flags & BIT_U32(engine->id)) && - direction == engine->dir) - { + if (!(inspect_flags & BIT_U32(engine->id)) && direction == engine->dir) { const bool skip_engine = (engine->alproto != 0 && engine->alproto != f->alproto); /* special case: file_data on 'alert tcp' will have engines * in the list that are not for us. */ @@ -1113,8 +1070,8 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, /* engines are sorted per progress, except that the one with * mpm/prefilter enabled is first */ if (tx->tx_progress < engine->progress) { - SCLogDebug("tx progress %d < engine progress %d", - tx->tx_progress, engine->progress); + SCLogDebug( + "tx progress %d < engine progress %d", tx->tx_progress, engine->progress); break; } if (engine->mpm) { @@ -1147,7 +1104,8 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, if (engine->stream) { can->stream_stored = true; can->stream_result = match; - TRACE_SID_TXS(s->id, tx, "stream ran, store result %d for next tx (if any)", match); + TRACE_SID_TXS( + s->id, tx, "stream ran, store result %d for next tx (if any)", match); } } if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { @@ -1179,8 +1137,8 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, } engine = engine->next; } - TRACE_SID_TXS(s->id, tx, "inspect_flags %x, total_matches %u, engine %p", - inspect_flags, total_matches, engine); + TRACE_SID_TXS(s->id, tx, "inspect_flags %x, total_matches %u, engine %p", inspect_flags, + total_matches, engine); if (engine == NULL && total_matches) { inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; @@ -1207,26 +1165,29 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, * other matches? E.g. 'POST + filename', is different than * just 'filename'. */ - DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s, - inspect_flags, flow_flags, file_no_match); + DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s, inspect_flags, + flow_flags, file_no_match); } } else if ((inspect_flags & DE_STATE_FLAG_FULL_INSPECT) && mpm_before_progress) { - TRACE_SID_TXS(s->id, tx, "no need to store match sig, " + TRACE_SID_TXS(s->id, tx, + "no need to store match sig, " "mpm won't trigger for it anymore"); if (inspect_flags & DE_STATE_FLAG_FILE_INSPECT) { - TRACE_SID_TXS(s->id, tx, "except that for new files, " + TRACE_SID_TXS(s->id, tx, + "except that for new files, " "we may have to revisit anyway"); - DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s, - inspect_flags, flow_flags, file_no_match); + DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s, inspect_flags, + flow_flags, file_no_match); } } else if ((inspect_flags & DE_STATE_FLAG_FULL_INSPECT) == 0 && mpm_in_progress) { - TRACE_SID_TXS(s->id, tx, "no need to store no-match sig, " + TRACE_SID_TXS(s->id, tx, + "no need to store no-match sig, " "mpm will revisit it"); } else { TRACE_SID_TXS(s->id, tx, "storing state: flags %08x", inspect_flags); - DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s, - inspect_flags, flow_flags, file_no_match); + DetectRunStoreStateTx(scratch->sgh, f, tx->tx_ptr, tx->tx_id, s, inspect_flags, + flow_flags, file_no_match); } } @@ -1242,9 +1203,8 @@ static bool DetectRunTxInspectRule(ThreadVars *tv, * \brief get a DetectTransaction object * \retval struct filled with relevant info or all nulls/0s */ -static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alproto, - void *alstate, const uint64_t tx_id, void *tx_ptr, const int tx_end_state, - const uint8_t flow_flags) +static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alproto, void *alstate, + const uint64_t tx_id, void *tx_ptr, const int tx_end_state, const uint8_t flow_flags) { AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx_ptr); if (unlikely(txd == NULL)) { @@ -1254,9 +1214,8 @@ static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alpro uint64_t detect_flags = (flow_flags & STREAM_TOSERVER) ? txd->detect_flags_ts : txd->detect_flags_tc; if (detect_flags & APP_LAYER_TX_INSPECTED_FLAG) { - SCLogDebug("%"PRIu64" tx already fully inspected for %s. Flags %016"PRIx64, - tx_id, flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", - detect_flags); + SCLogDebug("%" PRIu64 " tx already fully inspected for %s. Flags %016" PRIx64, tx_id, + flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags); DetectTransaction no_tx = NO_TX; return no_tx; } @@ -1270,21 +1229,22 @@ static DetectTransaction GetDetectTx(const uint8_t ipproto, const AppProto alpro const int tx_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx_ptr, flow_flags); const int dir_int = (flow_flags & STREAM_TOSERVER) ? 0 : 1; DetectEngineState *tx_de_state = txd->de_state; - DetectEngineStateDirection *tx_dir_state = tx_de_state ? &tx_de_state->dir_state[dir_int] : NULL; + DetectEngineStateDirection *tx_dir_state = + tx_de_state ? &tx_de_state->dir_state[dir_int] : NULL; uint64_t prefilter_flags = detect_flags & APP_LAYER_TX_PREFILTER_MASK; DEBUG_VALIDATE_BUG_ON(prefilter_flags & APP_LAYER_TX_RESERVED_FLAGS); DetectTransaction tx = { - .tx_ptr = tx_ptr, - .tx_id = tx_id, - .tx_data_ptr = (struct AppLayerTxData *)txd, - .de_state = tx_dir_state, - .detect_flags = detect_flags, - .prefilter_flags = prefilter_flags, - .prefilter_flags_orig = prefilter_flags, - .tx_progress = tx_progress, - .tx_end_state = tx_end_state, - }; + .tx_ptr = tx_ptr, + .tx_id = tx_id, + .tx_data_ptr = (struct AppLayerTxData *)txd, + .de_state = tx_dir_state, + .detect_flags = detect_flags, + .prefilter_flags = prefilter_flags, + .prefilter_flags_orig = prefilter_flags, + .tx_progress = tx_progress, + .tx_end_state = tx_end_state, + }; return tx; } @@ -1301,16 +1261,12 @@ static inline void StoreDetectFlags(DetectTransaction *tx, const uint8_t flow_fl } } -static void DetectRunTx(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Packet *p, - Flow *f, - DetectRunScratchpad *scratch) +static void DetectRunTx(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Packet *p, Flow *f, DetectRunScratchpad *scratch) { const uint8_t flow_flags = scratch->flow_flags; - const SigGroupHead * const sgh = scratch->sgh; - void * const alstate = f->alstate; + const SigGroupHead *const sgh = scratch->sgh; + void *const alstate = f->alstate; const uint8_t ipproto = f->proto; const AppProto alproto = f->alproto; @@ -1323,15 +1279,15 @@ static void DetectRunTx(ThreadVars *tv, memset(&state, 0, sizeof(state)); while (1) { - AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, tx_id_min, total_txs, &state); + AppLayerGetTxIterTuple ires = + IterFunc(ipproto, alproto, alstate, tx_id_min, total_txs, &state); if (ires.tx_ptr == NULL) break; - DetectTransaction tx = GetDetectTx(ipproto, alproto, - alstate, ires.tx_id, ires.tx_ptr, tx_end_state, flow_flags); + DetectTransaction tx = GetDetectTx( + ipproto, alproto, alstate, ires.tx_id, ires.tx_ptr, tx_end_state, flow_flags); if (tx.tx_ptr == NULL) { - SCLogDebug("%p/%"PRIu64" no transaction to inspect", - tx.tx_ptr, tx_id_min); + SCLogDebug("%p/%" PRIu64 " no transaction to inspect", tx.tx_ptr, tx_id_min); tx_id_min++; // next (if any) run look for +1 goto next; @@ -1346,11 +1302,10 @@ static void DetectRunTx(ThreadVars *tv, /* run prefilter engines and merge results into a candidates array */ if (sgh->tx_engines) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_TX); - DetectRunPrefilterTx(det_ctx, sgh, p, ipproto, flow_flags, alproto, - alstate, &tx); + DetectRunPrefilterTx(det_ctx, sgh, p, ipproto, flow_flags, alproto, alstate, &tx); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_TX); - SCLogDebug("%p/%"PRIu64" rules added from prefilter: %u candidates", - tx.tx_ptr, tx.tx_id, det_ctx->pmq.rule_id_array_cnt); + SCLogDebug("%p/%" PRIu64 " rules added from prefilter: %u candidates", tx.tx_ptr, + tx.tx_id, det_ctx->pmq.rule_id_array_cnt); total_rules += det_ctx->pmq.rule_id_array_cnt; if (!(RuleMatchCandidateTxArrayHasSpace(det_ctx, total_rules))) { @@ -1385,8 +1340,8 @@ static void DetectRunTx(ThreadVars *tv, det_ctx->tx_candidates[array_idx].stream_reset = 0; array_idx++; - SCLogDebug("%p/%"PRIu64" rule %u (%u) added from 'match' list", - tx.tx_ptr, tx.tx_id, s->id, id); + SCLogDebug("%p/%" PRIu64 " rule %u (%u) added from 'match' list", tx.tx_ptr, + tx.tx_id, s->id, id); } } do_sort = (array_idx > x); // sort if match added anything @@ -1401,8 +1356,8 @@ static void DetectRunTx(ThreadVars *tv, * 'file inspected' flag, reset the file part of the state */ const bool have_new_file = (tx.de_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_NEW); if (have_new_file) { - SCLogDebug("%p/%"PRIu64" destate: need to consider new file", - tx.tx_ptr, tx.tx_id); + SCLogDebug( + "%p/%" PRIu64 " destate: need to consider new file", tx.tx_ptr, tx.tx_id); tx.de_state->flags &= ~DETECT_ENGINE_STATE_FLAG_FILE_NEW; } @@ -1412,17 +1367,17 @@ static void DetectRunTx(ThreadVars *tv, SCLogDebug("tx_store %p", tx_store); SigIntId store_cnt = 0; - for (store_cnt = 0; - store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < tx.de_state->cnt; - store_cnt++, state_cnt++) - { + for (store_cnt = 0; store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < tx.de_state->cnt; + store_cnt++, state_cnt++) { DeStateStoreItem *item = &tx_store->store[store_cnt]; SCLogDebug("rule id %u, inspect_flags %u", item->sid, item->flags); if (have_new_file && (item->flags & DE_STATE_FLAG_FILE_INSPECT)) { /* remove part of the state. File inspect engine will now * be able to run again */ - item->flags &= ~(DE_STATE_FLAG_SIG_CANT_MATCH|DE_STATE_FLAG_FULL_INSPECT|DE_STATE_FLAG_FILE_INSPECT); - SCLogDebug("rule id %u, post file reset inspect_flags %u", item->sid, item->flags); + item->flags &= ~(DE_STATE_FLAG_SIG_CANT_MATCH | DE_STATE_FLAG_FULL_INSPECT | + DE_STATE_FLAG_FILE_INSPECT); + SCLogDebug("rule id %u, post file reset inspect_flags %u", item->sid, + item->flags); } det_ctx->tx_candidates[array_idx].s = de_ctx->sig_array[item->sid]; det_ctx->tx_candidates[array_idx].id = item->sid; @@ -1473,12 +1428,13 @@ static void DetectRunTx(ThreadVars *tv, i++; } - SCLogDebug("%p/%"PRIu64" inspecting: sid %u (%u), flags %08x", - tx.tx_ptr, tx.tx_id, s->id, s->num, inspect_flags ? *inspect_flags : 0); + SCLogDebug("%p/%" PRIu64 " inspecting: sid %u (%u), flags %08x", tx.tx_ptr, tx.tx_id, + s->id, s->num, inspect_flags ? *inspect_flags : 0); if (inspect_flags) { - if (*inspect_flags & (DE_STATE_FLAG_FULL_INSPECT|DE_STATE_FLAG_SIG_CANT_MATCH)) { - SCLogDebug("%p/%"PRIu64" inspecting: sid %u (%u), flags %08x ALREADY COMPLETE", + if (*inspect_flags & (DE_STATE_FLAG_FULL_INSPECT | DE_STATE_FLAG_SIG_CANT_MATCH)) { + SCLogDebug("%p/%" PRIu64 + " inspecting: sid %u (%u), flags %08x ALREADY COMPLETE", tx.tx_ptr, tx.tx_id, s->id, s->num, *inspect_flags); continue; } @@ -1489,19 +1445,20 @@ static void DetectRunTx(ThreadVars *tv, SCLogDebug("%p/%" PRIu64 " Continuing sid %u", tx.tx_ptr, tx.tx_id, s->id); } else { /* start new inspection */ - SCLogDebug("%p/%"PRIu64" Start sid %u", tx.tx_ptr, tx.tx_id, s->id); + SCLogDebug("%p/%" PRIu64 " Start sid %u", tx.tx_ptr, tx.tx_id, s->id); } /* call individual rule inspection */ RULE_PROFILING_START(p); - const int r = DetectRunTxInspectRule(tv, de_ctx, det_ctx, p, f, flow_flags, - alstate, &tx, s, inspect_flags, can, scratch); + const int r = DetectRunTxInspectRule(tv, de_ctx, det_ctx, p, f, flow_flags, alstate, + &tx, s, inspect_flags, can, scratch); if (r == 1) { /* match */ DetectRunPostMatch(tv, det_ctx, p, s); const uint8_t alert_flags = (PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_TX); - SCLogDebug("%p/%"PRIu64" sig %u (%u) matched", tx.tx_ptr, tx.tx_id, s->id, s->num); + SCLogDebug( + "%p/%" PRIu64 " sig %u (%u) matched", tx.tx_ptr, tx.tx_id, s->id, s->num); AlertQueueAppend(det_ctx, s, p, tx.tx_id, alert_flags); } DetectVarProcessList(det_ctx, p->flow, p); @@ -1518,31 +1475,27 @@ static void DetectRunTx(ThreadVars *tv, /* this side of the tx is done */ if (tx.tx_progress >= tx.tx_end_state) { new_detect_flags |= APP_LAYER_TX_INSPECTED_FLAG; - SCLogDebug("%p/%"PRIu64" tx is done for direction %s. Flag %016"PRIx64, - tx.tx_ptr, tx.tx_id, - flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", + SCLogDebug("%p/%" PRIu64 " tx is done for direction %s. Flag %016" PRIx64, tx.tx_ptr, + tx.tx_id, flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", new_detect_flags); } if (tx.prefilter_flags != tx.prefilter_flags_orig) { new_detect_flags |= tx.prefilter_flags; DEBUG_VALIDATE_BUG_ON(new_detect_flags & APP_LAYER_TX_RESERVED_FLAGS); - SCLogDebug("%p/%"PRIu64" updated prefilter flags %016"PRIx64" " - "(was: %016"PRIx64") for direction %s. Flag %016"PRIx64, + SCLogDebug("%p/%" PRIu64 " updated prefilter flags %016" PRIx64 " " + "(was: %016" PRIx64 ") for direction %s. Flag %016" PRIx64, tx.tx_ptr, tx.tx_id, tx.prefilter_flags, tx.prefilter_flags_orig, - flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", - new_detect_flags); + flow_flags & STREAM_TOSERVER ? "toserver" : "toclient", new_detect_flags); } - if (new_detect_flags != 0 && - (new_detect_flags | tx.detect_flags) != tx.detect_flags) - { + if (new_detect_flags != 0 && (new_detect_flags | tx.detect_flags) != tx.detect_flags) { new_detect_flags |= tx.detect_flags; DEBUG_VALIDATE_BUG_ON(new_detect_flags & APP_LAYER_TX_RESERVED_FLAGS); - SCLogDebug("%p/%"PRIu64" Storing new flags %016"PRIx64" (was %016"PRIx64")", + SCLogDebug("%p/%" PRIu64 " Storing new flags %016" PRIx64 " (was %016" PRIx64 ")", tx.tx_ptr, tx.tx_id, new_detect_flags, tx.detect_flags); StoreDetectFlags(&tx, flow_flags, ipproto, alproto, new_detect_flags); } -next: + next: InspectionBufferClean(det_ctx); if (!ires.has_next) @@ -1686,9 +1639,8 @@ static DetectEngineThreadCtx *GetTenantById(HashTable *h, uint32_t id) return HashTableLookup(h, &id, 0); } -static void DetectFlow(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Packet *p) +static void DetectFlow( + ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { Flow *const f = p->flow; @@ -1704,8 +1656,9 @@ static void DetectFlow(ThreadVars *tv, AppLayerParserSetTransactionInspectId(f, f->alparser, f->alstate, flags, true); } } - SCLogDebug("p->pcap %"PRIu64": no detection on packet, " - "PKT_NOPACKET_INSPECTION is set", p->pcap_cnt); + SCLogDebug("p->pcap %" PRIu64 ": no detection on packet, " + "PKT_NOPACKET_INSPECTION is set", + p->pcap_cnt); return; } @@ -1721,10 +1674,8 @@ static void DetectFlow(ThreadVars *tv, (void)DetectRun(tv, de_ctx, det_ctx, p); } - -static void DetectNoFlow(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Packet *p) +static void DetectNoFlow( + ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) { /* No need to perform any detection on this packet, if the given flag is set.*/ if ((p->flags & PKT_NOPACKET_INSPECTION) || (PacketCheckAction(p, ACTION_DROP))) { @@ -1757,14 +1708,12 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data) if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) { (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); - SCLogDebug("Detect Engine using new det_ctx - %p", - det_ctx); + SCLogDebug("Detect Engine using new det_ctx - %p", det_ctx); } /* if in MT mode _and_ we have tenants registered, use * MT logic. */ - if (det_ctx->mt_det_ctxs_cnt > 0 && det_ctx->TenantGetId != NULL) - { + if (det_ctx->mt_det_ctxs_cnt > 0 && det_ctx->TenantGetId != NULL) { uint32_t tenant_id = p->tenant_id; if (tenant_id == 0) tenant_id = det_ctx->TenantGetId(det_ctx, p); @@ -1839,4 +1788,3 @@ void SigMatchSignatures( #ifdef UNITTESTS #include "tests/detect.c" #endif - diff --git a/src/detect.h b/src/detect.h index 3861b603d801..2ce5c682893f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -32,13 +32,13 @@ #include "detect-metadata.h" #include "detect-engine-register.h" -#include "util-prefilter.h" -#include "util-mpm.h" -#include "util-spm.h" -#include "util-hash.h" -#include "util-hashlist.h" -#include "util-radix-tree.h" -#include "util-file.h" +#include "util/prefilter.h" +#include "util/mpm/mpm.h" +#include "util/spm.h" +#include "util/hash.h" +#include "util/hashlist.h" +#include "util/radix-tree.h" +#include "util/file.h" #include "reputation.h" #define DETECT_MAX_RULE_SIZE 8192 @@ -150,7 +150,7 @@ enum { ADDRESS_GT, /**< bigger [bbb] [aaa] */ }; -#define ADDRESS_FLAG_NOT 0x01 /**< address is negated */ +#define ADDRESS_FLAG_NOT 0x01 /**< address is negated */ /** \brief address structure for use in the detection engine. * @@ -176,10 +176,9 @@ typedef struct DetectAddressHead_ { DetectAddress *ipv6_head; } DetectAddressHead; - typedef struct DetectMatchAddressIPv4_ { - uint32_t ip; /**< address in host order, start of range */ - uint32_t ip2; /**< address in host order, end of range */ + uint32_t ip; /**< address in host order, start of range */ + uint32_t ip2; /**< address in host order, end of range */ } DetectMatchAddressIPv4; typedef struct DetectMatchAddressIPv6_ { @@ -203,16 +202,16 @@ enum { PORT_GT, /* bigger [bbb] [aaa] */ }; -#define PORT_FLAG_ANY 0x01 /**< 'any' special port */ -#define PORT_FLAG_NOT 0x02 /**< negated port */ -#define PORT_SIGGROUPHEAD_COPY 0x04 /**< sgh is a ptr copy */ +#define PORT_FLAG_ANY 0x01 /**< 'any' special port */ +#define PORT_FLAG_NOT 0x02 /**< negated port */ +#define PORT_SIGGROUPHEAD_COPY 0x04 /**< sgh is a ptr copy */ /** \brief Port structure for detection engine */ typedef struct DetectPort_ { uint16_t port; uint16_t port2; - uint8_t flags; /**< flags for this port */ + uint8_t flags; /**< flags for this port */ /* signatures that belong in this group * @@ -228,23 +227,23 @@ typedef struct DetectPort_ { /* Signature flags */ /** \note: additions should be added to the rule analyzer as well */ -#define SIG_FLAG_SRC_ANY BIT_U32(0) /**< source is any */ -#define SIG_FLAG_DST_ANY BIT_U32(1) /**< destination is any */ -#define SIG_FLAG_SP_ANY BIT_U32(2) /**< source port is any */ -#define SIG_FLAG_DP_ANY BIT_U32(3) /**< destination port is any */ +#define SIG_FLAG_SRC_ANY BIT_U32(0) /**< source is any */ +#define SIG_FLAG_DST_ANY BIT_U32(1) /**< destination is any */ +#define SIG_FLAG_SP_ANY BIT_U32(2) /**< source port is any */ +#define SIG_FLAG_DP_ANY BIT_U32(3) /**< destination port is any */ -#define SIG_FLAG_NOALERT BIT_U32(4) /**< no alert flag is set */ -#define SIG_FLAG_DSIZE BIT_U32(5) /**< signature has a dsize setting */ -#define SIG_FLAG_APPLAYER BIT_U32(6) /**< signature applies to app layer instead of packets */ +#define SIG_FLAG_NOALERT BIT_U32(4) /**< no alert flag is set */ +#define SIG_FLAG_DSIZE BIT_U32(5) /**< signature has a dsize setting */ +#define SIG_FLAG_APPLAYER BIT_U32(6) /**< signature applies to app layer instead of packets */ // vacancy -#define SIG_FLAG_REQUIRE_PACKET BIT_U32(9) /**< signature is requiring packet match */ -#define SIG_FLAG_REQUIRE_STREAM BIT_U32(10) /**< signature is requiring stream match */ +#define SIG_FLAG_REQUIRE_PACKET BIT_U32(9) /**< signature is requiring packet match */ +#define SIG_FLAG_REQUIRE_STREAM BIT_U32(10) /**< signature is requiring stream match */ -#define SIG_FLAG_MPM_NEG BIT_U32(11) +#define SIG_FLAG_MPM_NEG BIT_U32(11) -#define SIG_FLAG_FLUSH BIT_U32(12) /**< detection logic needs stream flush notification */ +#define SIG_FLAG_FLUSH BIT_U32(12) /**< detection logic needs stream flush notification */ #define SIG_FLAG_REQUIRE_STREAM_ONLY \ BIT_U32(13) /**< signature is requiring stream match. Stream match is not optional, so no \ @@ -252,52 +251,55 @@ typedef struct DetectPort_ { // vacancies -#define SIG_FLAG_REQUIRE_FLOWVAR BIT_U32(17) /**< signature can only match if a flowbit, flowvar or flowint is available. */ +#define SIG_FLAG_REQUIRE_FLOWVAR \ + BIT_U32(17) /**< signature can only match if a flowbit, flowvar or flowint is available. */ -#define SIG_FLAG_FILESTORE BIT_U32(18) /**< signature has filestore keyword */ +#define SIG_FLAG_FILESTORE BIT_U32(18) /**< signature has filestore keyword */ -#define SIG_FLAG_TOSERVER BIT_U32(19) -#define SIG_FLAG_TOCLIENT BIT_U32(20) +#define SIG_FLAG_TOSERVER BIT_U32(19) +#define SIG_FLAG_TOCLIENT BIT_U32(20) -#define SIG_FLAG_TLSSTORE BIT_U32(21) +#define SIG_FLAG_TLSSTORE BIT_U32(21) -#define SIG_FLAG_BYPASS BIT_U32(22) +#define SIG_FLAG_BYPASS BIT_U32(22) -#define SIG_FLAG_PREFILTER BIT_U32(23) /**< sig is part of a prefilter engine */ +#define SIG_FLAG_PREFILTER BIT_U32(23) /**< sig is part of a prefilter engine */ // vacancy /** Info for Source and Target identification */ -#define SIG_FLAG_SRC_IS_TARGET BIT_U32(25) +#define SIG_FLAG_SRC_IS_TARGET BIT_U32(25) /** Info for Source and Target identification */ -#define SIG_FLAG_DEST_IS_TARGET BIT_U32(26) +#define SIG_FLAG_DEST_IS_TARGET BIT_U32(26) -#define SIG_FLAG_HAS_TARGET (SIG_FLAG_DEST_IS_TARGET|SIG_FLAG_SRC_IS_TARGET) +#define SIG_FLAG_HAS_TARGET (SIG_FLAG_DEST_IS_TARGET | SIG_FLAG_SRC_IS_TARGET) /* signature init flags */ // available 0 -#define SIG_FLAG_INIT_PACKET BIT_U32(1) /**< signature has matches against a packet (as opposed to app layer) */ -#define SIG_FLAG_INIT_FLOW BIT_U32(2) /**< signature has a flow setting */ -#define SIG_FLAG_INIT_BIDIREC BIT_U32(3) /**< signature has bidirectional operator */ +#define SIG_FLAG_INIT_PACKET \ + BIT_U32(1) /**< signature has matches against a packet (as opposed to app layer) */ +#define SIG_FLAG_INIT_FLOW BIT_U32(2) /**< signature has a flow setting */ +#define SIG_FLAG_INIT_BIDIREC BIT_U32(3) /**< signature has bidirectional operator */ #define SIG_FLAG_INIT_FIRST_IPPROTO_SEEN \ BIT_U32(4) /** < signature has seen the first ip_proto keyword */ -#define SIG_FLAG_INIT_STATE_MATCH BIT_U32(6) /**< signature has matches that require stateful inspection */ -#define SIG_FLAG_INIT_NEED_FLUSH BIT_U32(7) +#define SIG_FLAG_INIT_STATE_MATCH \ + BIT_U32(6) /**< signature has matches that require stateful inspection */ +#define SIG_FLAG_INIT_NEED_FLUSH BIT_U32(7) #define SIG_FLAG_INIT_PRIO_EXPLICIT \ - BIT_U32(8) /**< priority is explicitly set by the priority keyword */ -#define SIG_FLAG_INIT_FILEDATA BIT_U32(9) /**< signature has filedata keyword */ -#define SIG_FLAG_INIT_JA3 BIT_U32(10) /**< signature has ja3 keyword */ + BIT_U32(8) /**< priority is explicitly set by the priority keyword */ +#define SIG_FLAG_INIT_FILEDATA BIT_U32(9) /**< signature has filedata keyword */ +#define SIG_FLAG_INIT_JA3 BIT_U32(10) /**< signature has ja3 keyword */ /* signature mask flags */ /** \note: additions should be added to the rule analyzer as well */ -#define SIG_MASK_REQUIRE_PAYLOAD BIT_U8(0) -#define SIG_MASK_REQUIRE_FLOW BIT_U8(1) -#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT BIT_U8(2) /* SYN, FIN, RST */ -#define SIG_MASK_REQUIRE_FLAGS_UNUSUAL BIT_U8(3) /* URG, ECN, CWR */ -#define SIG_MASK_REQUIRE_NO_PAYLOAD BIT_U8(4) -#define SIG_MASK_REQUIRE_DCERPC BIT_U8(5) /* require either SMB+DCE or raw DCE */ +#define SIG_MASK_REQUIRE_PAYLOAD BIT_U8(0) +#define SIG_MASK_REQUIRE_FLOW BIT_U8(1) +#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT BIT_U8(2) /* SYN, FIN, RST */ +#define SIG_MASK_REQUIRE_FLAGS_UNUSUAL BIT_U8(3) /* URG, ECN, CWR */ +#define SIG_MASK_REQUIRE_NO_PAYLOAD BIT_U8(4) +#define SIG_MASK_REQUIRE_DCERPC BIT_U8(5) /* require either SMB+DCE or raw DCE */ // vacancy -#define SIG_MASK_REQUIRE_ENGINE_EVENT BIT_U8(7) +#define SIG_MASK_REQUIRE_ENGINE_EVENT BIT_U8(7) /* for now a uint8_t is enough */ #define SignatureMask uint8_t @@ -305,17 +307,17 @@ typedef struct DetectPort_ { #define DETECT_ENGINE_THREAD_CTX_FRAME_ID_SET 0x0001 #define DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH 0x0004 -#define FILE_SIG_NEED_FILE 0x01 -#define FILE_SIG_NEED_FILENAME 0x02 -#define FILE_SIG_NEED_MAGIC 0x04 /**< need the start of the file */ -#define FILE_SIG_NEED_FILECONTENT 0x08 -#define FILE_SIG_NEED_MD5 0x10 -#define FILE_SIG_NEED_SHA1 0x20 -#define FILE_SIG_NEED_SHA256 0x40 -#define FILE_SIG_NEED_SIZE 0x80 +#define FILE_SIG_NEED_FILE 0x01 +#define FILE_SIG_NEED_FILENAME 0x02 +#define FILE_SIG_NEED_MAGIC 0x04 /**< need the start of the file */ +#define FILE_SIG_NEED_FILECONTENT 0x08 +#define FILE_SIG_NEED_MD5 0x10 +#define FILE_SIG_NEED_SHA1 0x20 +#define FILE_SIG_NEED_SHA256 0x40 +#define FILE_SIG_NEED_SIZE 0x80 /* Detection Engine flags */ -#define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */ +#define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */ typedef struct IPOnlyCIDRItem_ { /* address data for this item */ @@ -342,8 +344,8 @@ typedef struct SigMatchCtx_ { /** \brief a single match condition for a signature */ typedef struct SigMatch_ { - uint16_t type; /**< match type */ - uint16_t idx; /**< position in the signature */ + uint16_t type; /**< match type */ + uint16_t idx; /**< position in the signature */ SigMatchCtx *ctx; /**< plugin specific data */ struct SigMatch_ *next; struct SigMatch_ *prev; @@ -351,12 +353,12 @@ typedef struct SigMatch_ { /** \brief Data needed for Match() */ typedef struct SigMatchData_ { - uint16_t type; /**< match type */ - uint8_t is_last; /**< Last element of the list */ + uint16_t type; /**< match type */ + uint8_t is_last; /**< Last element of the list */ SigMatchCtx *ctx; /**< plugin specific data */ } SigMatchData; -struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; +struct DetectEngineThreadCtx_; // DetectEngineThreadCtx; /* inspection buffer is a simple structure that is passed between prefilter, * transformation functions and inspection functions. @@ -368,15 +370,15 @@ struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; typedef struct InspectionBuffer { const uint8_t *inspect; /**< active pointer, points either to ::buf or ::orig */ uint64_t inspect_offset; - uint32_t inspect_len; /**< size of active data. See to ::len or ::orig_len */ + uint32_t inspect_len; /**< size of active data. See to ::len or ::orig_len */ bool initialized; /**< is initialized. ::inspect might be NULL if transform lead to 0 size */ - uint8_t flags; /**< DETECT_CI_FLAGS_* for use with DetectEngineContentInspection */ + uint8_t flags; /**< DETECT_CI_FLAGS_* for use with DetectEngineContentInspection */ #ifdef DEBUG_VALIDATION bool multi; #endif - uint32_t len; /**< how much is in use */ + uint32_t len; /**< how much is in use */ uint8_t *buf; - uint32_t size; /**< size of the memory allocation */ + uint32_t size; /**< size of the memory allocation */ uint32_t orig_len; const uint8_t *orig; @@ -390,9 +392,9 @@ typedef struct InspectionBuffer { typedef struct InspectionBufferMultipleForList { InspectionBuffer *inspection_buffers; - uint32_t size; /**< size in number of elements */ - uint32_t max:31; /**< max id in use in this run */ - uint32_t init:1; /**< first time used this run. Used for clean logic */ + uint32_t size; /**< size in number of elements */ + uint32_t max : 31; /**< max id in use in this run */ + uint32_t init : 1; /**< first time used this run. Used for clean logic */ } InspectionBufferMultipleForList; typedef struct TransformData_ { @@ -406,11 +408,9 @@ typedef struct DetectEngineTransforms { } DetectEngineTransforms; /** callback for getting the buffer we need to prefilter/inspect */ -typedef InspectionBuffer *(*InspectionBufferGetDataPtr)( - struct DetectEngineThreadCtx_ *det_ctx, - const DetectEngineTransforms *transforms, - Flow *f, const uint8_t flow_flags, - void *txv, const int list_id); +typedef InspectionBuffer *(*InspectionBufferGetDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id); struct DetectEngineAppInspectionEngine_; typedef uint8_t (*InspectEngineFuncPtr2)(struct DetectEngineCtx_ *de_ctx, @@ -421,7 +421,7 @@ typedef uint8_t (*InspectEngineFuncPtr2)(struct DetectEngineCtx_ *de_ctx, typedef struct DetectEngineAppInspectionEngine_ { AppProto alproto; uint8_t dir; - uint8_t id; /**< per sig id used in state keeping */ + uint8_t id; /**< per sig id used in state keeping */ bool mpm; bool stream; uint16_t sm_list; @@ -460,17 +460,13 @@ struct DetectEnginePktInspectionEngine; /** * \param alert_flags[out] for setting PACKET_ALERT_FLAG_* */ -typedef int (*InspectionBufferPktInspectFunc)( - struct DetectEngineThreadCtx_ *, - const struct DetectEnginePktInspectionEngine *engine, - const struct Signature_ *s, - Packet *p, uint8_t *alert_flags); +typedef int (*InspectionBufferPktInspectFunc)(struct DetectEngineThreadCtx_ *, + const struct DetectEnginePktInspectionEngine *engine, const struct Signature_ *s, Packet *p, + uint8_t *alert_flags); /** callback for getting the buffer we need to prefilter/inspect */ -typedef InspectionBuffer *(*InspectionBufferGetPktDataPtr)( - struct DetectEngineThreadCtx_ *det_ctx, - const DetectEngineTransforms *transforms, - Packet *p, const int list_id); +typedef InspectionBuffer *(*InspectionBufferGetPktDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Packet *p, const int list_id); typedef struct DetectEnginePktInspectionEngine { SigMatchData *smd; @@ -673,12 +669,12 @@ enum DetectBufferMpmType { /** \brief one time registration of keywords at start up */ typedef struct DetectBufferMpmRegistry_ { const char *name; - char pname[32]; /**< name used in profiling */ - int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ + char pname[32]; /**< name used in profiling */ + int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ int16_t sm_list; int16_t sm_list_base; int priority; - int id; /**< index into this array and result arrays */ + int id; /**< index into this array and result arrays */ enum DetectBufferMpmType type; int sgh_mpm_context; @@ -727,19 +723,19 @@ typedef struct DetectReplaceList_ { } DetectReplaceList; /** only execute flowvar storage if rule matched */ -#define DETECT_VAR_TYPE_FLOW_POSTMATCH 1 -#define DETECT_VAR_TYPE_PKT_POSTMATCH 2 +#define DETECT_VAR_TYPE_FLOW_POSTMATCH 1 +#define DETECT_VAR_TYPE_PKT_POSTMATCH 2 /** list for flowvar store candidates, to be stored from * post-match function */ typedef struct DetectVarList_ { - uint32_t idx; /**< flowvar name idx */ - uint16_t len; /**< data len */ + uint32_t idx; /**< flowvar name idx */ + uint16_t len; /**< data len */ uint16_t key_len; - int type; /**< type of store candidate POSTMATCH or ALWAYS */ + int type; /**< type of store candidate POSTMATCH or ALWAYS */ uint8_t *key; - uint8_t *buffer; /**< alloc'd buffer, may be freed by - post-match, post-non-match */ + uint8_t *buffer; /**< alloc'd buffer, may be freed by + post-match, post-non-match */ struct DetectVarList_ *next; } DetectVarList; @@ -774,8 +770,8 @@ typedef struct DetectEngineLookupFlow_ { #include "detect-threshold.h" /** \brief threshold ctx */ -typedef struct ThresholdCtx_ { - SCMutex threshold_table_lock; /**< Mutex for hash table */ +typedef struct ThresholdCtx_ { + SCMutex threshold_table_lock; /**< Mutex for hash table */ /** to support rate_filter "by_rule" option */ DetectThresholdEntry **th_entry; @@ -808,14 +804,12 @@ typedef struct DetectEngineThreadKeywordCtxItem_ { const char *name; /* keyword name, for error printing */ } DetectEngineThreadKeywordCtxItem; -enum DetectEnginePrefilterSetting -{ - DETECT_PREFILTER_MPM = 0, /**< use only mpm / fast_pattern */ - DETECT_PREFILTER_AUTO = 1, /**< use mpm + keyword prefilters */ +enum DetectEnginePrefilterSetting { + DETECT_PREFILTER_MPM = 0, /**< use only mpm / fast_pattern */ + DETECT_PREFILTER_AUTO = 1, /**< use mpm + keyword prefilters */ }; -enum DetectEngineType -{ +enum DetectEngineType { DETECT_ENGINE_TYPE_NORMAL = 0, DETECT_ENGINE_TYPE_DD_STUB = 1, /* delayed detect stub: can be reloaded */ DETECT_ENGINE_TYPE_MT_STUB = 2, /* multi-tenant stub: cannot be reloaded */ @@ -1061,8 +1055,8 @@ typedef struct SignatureNonPrefilterStore_ { /** array of TX inspect rule candidates */ typedef struct RuleMatchCandidateTx { - SigIntId id; /**< internal signature id */ - uint32_t *flags; /**< inspect flags ptr */ + SigIntId id; /**< internal signature id */ + uint32_t *flags; /**< inspect flags ptr */ union { struct { bool stream_stored; @@ -1071,12 +1065,12 @@ typedef struct RuleMatchCandidateTx { uint32_t stream_reset; }; - const Signature *s; /**< ptr to sig */ + const Signature *s; /**< ptr to sig */ } RuleMatchCandidateTx; /** - * Detection engine thread data. - */ + * Detection engine thread data. + */ typedef struct DetectEngineThreadCtx_ { /** \note multi-tenant hash lookup code from Detect() *depends* * on this being the first member */ @@ -1128,7 +1122,7 @@ typedef struct DetectEngineThreadCtx_ { struct { InspectionBuffer *buffers; - uint32_t buffers_size; /**< in number of elements */ + uint32_t buffers_size; /**< in number of elements */ uint32_t to_clear_idx; uint32_t *to_clear_queue; } inspect; @@ -1137,7 +1131,7 @@ typedef struct DetectEngineThreadCtx_ { /** inspection buffers for more complex case. As we can inspect multiple * buffers in parallel, we need this extra wrapper struct */ InspectionBufferMultipleForList *buffers; - uint32_t buffers_size; /**< in number of elements */ + uint32_t buffers_size; /**< in number of elements */ uint32_t to_clear_idx; uint32_t *to_clear_queue; } multi_inspect; @@ -1252,14 +1246,12 @@ typedef struct SigTableElmt_ { int (*Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); /** AppLayer TX match function pointer */ - int (*AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, - uint8_t flags, void *alstate, void *txv, + int (*AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *); /** File match function pointer */ - int (*FileMatch)(DetectEngineThreadCtx *, - Flow *, /**< *LOCKED* flow */ - uint8_t flags, File *, const Signature *, const SigMatchCtx *); + int (*FileMatch)(DetectEngineThreadCtx *, Flow *, /**< *LOCKED* flow */ + uint8_t flags, File *, const Signature *, const SigMatchCtx *); /** InspectionBuffer transformation callback */ void (*Transform)(InspectionBuffer *, void *context); @@ -1281,8 +1273,8 @@ typedef struct SigTableElmt_ { /** better keyword to replace the current one */ uint16_t alternative; - const char *name; /**< keyword name alias */ - const char *alias; /**< name alias */ + const char *name; /**< keyword name alias */ + const char *alias; /**< name alias */ const char *desc; const char *url; @@ -1307,14 +1299,14 @@ enum { DETECT_EVENT_TOO_MANY_BUFFERS, }; -#define SIG_GROUP_HEAD_HAVERAWSTREAM BIT_U32(0) +#define SIG_GROUP_HEAD_HAVERAWSTREAM BIT_U32(0) #ifdef HAVE_MAGIC -#define SIG_GROUP_HEAD_HAVEFILEMAGIC BIT_U32(20) +#define SIG_GROUP_HEAD_HAVEFILEMAGIC BIT_U32(20) #endif -#define SIG_GROUP_HEAD_HAVEFILEMD5 BIT_U32(21) -#define SIG_GROUP_HEAD_HAVEFILESIZE BIT_U32(22) -#define SIG_GROUP_HEAD_HAVEFILESHA1 BIT_U32(23) -#define SIG_GROUP_HEAD_HAVEFILESHA256 BIT_U32(24) +#define SIG_GROUP_HEAD_HAVEFILEMD5 BIT_U32(21) +#define SIG_GROUP_HEAD_HAVEFILESIZE BIT_U32(22) +#define SIG_GROUP_HEAD_HAVEFILESHA1 BIT_U32(23) +#define SIG_GROUP_HEAD_HAVEFILESHA256 BIT_U32(24) enum MpmBuiltinBuffers { MPMB_TCP_PKT_TS, @@ -1409,11 +1401,11 @@ typedef struct SigGroupHeadInitData_ { MpmStore mpm_store[MPMB_MAX]; uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ - uint32_t sig_size; /**< size in bytes */ + uint32_t sig_size; /**< size in bytes */ - uint8_t protos[256]; /**< proto(s) this sgh is for */ - uint32_t direction; /**< set to SIG_FLAG_TOSERVER, SIG_FLAG_TOCLIENT or both */ - int score; /**< try to make this group a unique one */ + uint8_t protos[256]; /**< proto(s) this sgh is for */ + uint32_t direction; /**< set to SIG_FLAG_TOSERVER, SIG_FLAG_TOCLIENT or both */ + int score; /**< try to make this group a unique one */ MpmCtx **app_mpms; MpmCtx **pkt_mpms; @@ -1442,9 +1434,11 @@ typedef struct SigGroupHead_ { /* non prefilter list excluding SYN rules */ uint32_t non_pf_other_store_cnt; uint32_t non_pf_syn_store_cnt; - SignatureNonPrefilterStore *non_pf_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonPrefilterStore) + SignatureNonPrefilterStore *non_pf_other_store_array; // size is non_mpm_store_cnt * + // sizeof(SignatureNonPrefilterStore) /* non mpm list including SYN rules */ - SignatureNonPrefilterStore *non_pf_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonPrefilterStore) + SignatureNonPrefilterStore *non_pf_syn_store_array; // size is non_mpm_syn_store_cnt * + // sizeof(SignatureNonPrefilterStore) /** the number of signatures in this sgh that have the filestore keyword * set. */ @@ -1463,42 +1457,41 @@ typedef struct SigGroupHead_ { } SigGroupHead; /** sigmatch has no options, so the parser shouldn't expect any */ -#define SIGMATCH_NOOPT BIT_U16(0) +#define SIGMATCH_NOOPT BIT_U16(0) /** sigmatch is compatible with a ip only rule */ -#define SIGMATCH_IPONLY_COMPAT BIT_U16(1) +#define SIGMATCH_IPONLY_COMPAT BIT_U16(1) /** sigmatch is compatible with a decode event only rule */ -#define SIGMATCH_DEONLY_COMPAT BIT_U16(2) +#define SIGMATCH_DEONLY_COMPAT BIT_U16(2) /**< Flag to indicate that the signature is not built-in */ -#define SIGMATCH_NOT_BUILT BIT_U16(3) +#define SIGMATCH_NOT_BUILT BIT_U16(3) /** sigmatch may have options, so the parser should be ready to * deal with both cases */ -#define SIGMATCH_OPTIONAL_OPT BIT_U16(4) +#define SIGMATCH_OPTIONAL_OPT BIT_U16(4) /** input may be wrapped in double quotes. They will be stripped before * input data is passed to keyword parser */ -#define SIGMATCH_QUOTES_OPTIONAL BIT_U16(5) +#define SIGMATCH_QUOTES_OPTIONAL BIT_U16(5) /** input MUST be wrapped in double quotes. They will be stripped before * input data is passed to keyword parser. Missing double quotes lead to * error and signature invalidation. */ -#define SIGMATCH_QUOTES_MANDATORY BIT_U16(6) +#define SIGMATCH_QUOTES_MANDATORY BIT_U16(6) /** negation parsing is handled by the rule parser. Signature::init_data::negated * will be set to true or false prior to calling the keyword parser. Exclamation * mark is stripped from the input to the keyword parser. */ -#define SIGMATCH_HANDLE_NEGATION BIT_U16(7) +#define SIGMATCH_HANDLE_NEGATION BIT_U16(7) /** keyword is a content modifier */ -#define SIGMATCH_INFO_CONTENT_MODIFIER BIT_U16(8) +#define SIGMATCH_INFO_CONTENT_MODIFIER BIT_U16(8) /** keyword is a sticky buffer */ -#define SIGMATCH_INFO_STICKY_BUFFER BIT_U16(9) +#define SIGMATCH_INFO_STICKY_BUFFER BIT_U16(9) /** keyword is deprecated: used to suggest an alternative */ -#define SIGMATCH_INFO_DEPRECATED BIT_U16(10) +#define SIGMATCH_INFO_DEPRECATED BIT_U16(10) /** strict parsing is enabled */ -#define SIGMATCH_STRICT_PARSING BIT_U16(11) - -enum DetectEngineTenantSelectors -{ - TENANT_SELECTOR_UNKNOWN = 0, /**< not set */ - TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */ - TENANT_SELECTOR_VLAN, /**< map vlan to tenant id */ - TENANT_SELECTOR_LIVEDEV, /**< map livedev to tenant id */ +#define SIGMATCH_STRICT_PARSING BIT_U16(11) + +enum DetectEngineTenantSelectors { + TENANT_SELECTOR_UNKNOWN = 0, /**< not set */ + TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */ + TENANT_SELECTOR_VLAN, /**< map vlan to tenant id */ + TENANT_SELECTOR_LIVEDEV, /**< map livedev to tenant id */ }; typedef struct DetectEngineTenantMapping_ { @@ -1544,7 +1537,8 @@ typedef struct DetectEngineMasterCtx_ { /* Table with all SigMatch registrations */ extern SigTableElmt sigmatch_table[DETECT_TBLSIZE]; -/** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ +/** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a + * signature group */ /* detection api */ TmEcode Detect(ThreadVars *tv, Packet *p, void *data); @@ -1558,14 +1552,15 @@ void SigRegisterTests(void); void DisableDetectFlowFileFlags(Flow *f); char *DetectLoadCompleteSigPath(const DetectEngineCtx *, const char *sig_file); int SigLoadSignatures(DetectEngineCtx *, char *, bool); -void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Packet *p); +void SigMatchSignatures( + ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p); int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s); const SigGroupHead *SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, const Packet *p); int DetectUnregisterThreadCtxFuncs(DetectEngineCtx *, void *data, const char *name); -int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int); +int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), + void *data, void (*FreeFunc)(void *), int); void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *, int); void RuleMatchCandidateTxArrayInit(DetectEngineThreadCtx *det_ctx, uint32_t size); @@ -1587,6 +1582,4 @@ AppLayerDecoderEvents *DetectEngineGetEvents(DetectEngineThreadCtx *det_ctx); void DumpPatterns(DetectEngineCtx *de_ctx); - #endif /* __DETECT_H__ */ - diff --git a/src/device-storage.c b/src/device-storage.c index d4314c021ea5..8566b2b82435 100644 --- a/src/device-storage.c +++ b/src/device-storage.c @@ -25,8 +25,8 @@ #include "suricata-common.h" #include "device-storage.h" -#include "util-storage.h" -#include "util-unittest.h" +#include "util/storage.h" +#include "util/unittest.h" unsigned int LiveDevStorageSize(void) { @@ -112,5 +112,3 @@ void LiveDevFreeStorage(LiveDevice *d) if (LiveDevStorageSize() > 0) StorageFreeAll(d->storage, STORAGE_DEVICE); } - - diff --git a/src/device-storage.h b/src/device-storage.h index 441b92b82e7d..de73c796a4e9 100644 --- a/src/device-storage.h +++ b/src/device-storage.h @@ -26,7 +26,7 @@ #ifndef __DEVICE_STORAGE_H__ #define __DEVICE_STORAGE_H__ -#include "util-device.h" +#include "util/device.h" typedef struct LiveDevStorageId_ { int id; diff --git a/src/feature.c b/src/feature.c index 0edf9433aca9..ed3f313d21c4 100644 --- a/src/feature.c +++ b/src/feature.c @@ -27,18 +27,17 @@ #include "feature.h" #include "threads.h" -#include "util-debug.h" -#include "util-hashlist.h" +#include "util/debug.h" +#include "util/hashlist.h" typedef struct FeatureEntryType { - const char *feature; + const char *feature; } FeatureEntryType; static SCMutex feature_table_mutex = SCMUTEX_INITIALIZER; static HashListTable *feature_hash_table; -static uint32_t FeatureHashFunc(HashListTable *ht, void *data, - uint16_t datalen) +static uint32_t FeatureHashFunc(HashListTable *ht, void *data, uint16_t datalen) { FeatureEntryType *f = (FeatureEntryType *)data; uint32_t hash = 0; @@ -50,8 +49,7 @@ static uint32_t FeatureHashFunc(HashListTable *ht, void *data, return (hash % ht->array_size); } -static char FeatureHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2) +static char FeatureHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) { FeatureEntryType *f1 = (FeatureEntryType *)data1; FeatureEntryType *f2 = (FeatureEntryType *)data2; @@ -79,10 +77,10 @@ static void FeatureHashFreeFunc(void *data) SCFree(data); } -static void FeatureInit(void) { - feature_hash_table = HashListTableInit(256, FeatureHashFunc, - FeatureHashCompareFunc, - FeatureHashFreeFunc); +static void FeatureInit(void) +{ + feature_hash_table = + HashListTableInit(256, FeatureHashFunc, FeatureHashCompareFunc, FeatureHashFreeFunc); if (!feature_hash_table) { FatalError("Unable to allocate feature hash table."); diff --git a/src/feature.h b/src/feature.h index 6549c5bbeab5..82251cbeb80a 100644 --- a/src/feature.h +++ b/src/feature.h @@ -25,7 +25,7 @@ #define __FEATURE_H__ /* Provided feature names */ -#define FEATURE_OUTPUT_FILESTORE "output::file-store" +#define FEATURE_OUTPUT_FILESTORE "output::file-store" void ProvidesFeature(const char *); bool RequiresFeature(const char *); diff --git a/src/flow-bit.c b/src/flow-bit.c index f59e7eae943e..533f191cfe41 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -38,15 +38,15 @@ #include "flow-util.h" #include "flow-private.h" #include "detect.h" -#include "util-var.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/var.h" +#include "util/debug.h" +#include "util/unittest.h" /* get the flowbit with idx from the flow */ static FlowBit *FlowBitGet(Flow *f, uint32_t idx) { GenericVar *gv = f->flowvar; - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { return (FlowBit *)gv; } @@ -133,10 +133,9 @@ void FlowBitFree(FlowBit *fb) SCFree(fb); } - /* TESTS */ #ifdef UNITTESTS -static int FlowBitTest01 (void) +static int FlowBitTest01(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -150,7 +149,7 @@ static int FlowBitTest01 (void) PASS; } -static int FlowBitTest02 (void) +static int FlowBitTest02(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -162,14 +161,14 @@ static int FlowBitTest02 (void) PASS; } -static int FlowBitTest03 (void) +static int FlowBitTest03(void) { Flow f; memset(&f, 0, sizeof(Flow)); FlowBitAdd(&f, 0); - FlowBit *fb = FlowBitGet(&f,0); + FlowBit *fb = FlowBitGet(&f, 0); FAIL_IF_NULL(fb); FlowBitRemove(&f, 0); @@ -181,7 +180,7 @@ static int FlowBitTest03 (void) PASS; } -static int FlowBitTest04 (void) +static int FlowBitTest04(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -198,7 +197,7 @@ static int FlowBitTest04 (void) PASS; } -static int FlowBitTest05 (void) +static int FlowBitTest05(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -215,7 +214,7 @@ static int FlowBitTest05 (void) PASS; } -static int FlowBitTest06 (void) +static int FlowBitTest06(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -232,7 +231,7 @@ static int FlowBitTest06 (void) PASS; } -static int FlowBitTest07 (void) +static int FlowBitTest07(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -249,7 +248,7 @@ static int FlowBitTest07 (void) PASS; } -static int FlowBitTest08 (void) +static int FlowBitTest08(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -259,10 +258,10 @@ static int FlowBitTest08 (void) FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); - FlowBit *fb = FlowBitGet(&f,0); + FlowBit *fb = FlowBitGet(&f, 0); FAIL_IF_NULL(fb); - FlowBitRemove(&f,0); + FlowBitRemove(&f, 0); fb = FlowBitGet(&f, 0); FAIL_IF_NOT_NULL(fb); @@ -271,7 +270,7 @@ static int FlowBitTest08 (void) PASS; } -static int FlowBitTest09 (void) +static int FlowBitTest09(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -281,10 +280,10 @@ static int FlowBitTest09 (void) FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); - FlowBit *fb = FlowBitGet(&f,1); + FlowBit *fb = FlowBitGet(&f, 1); FAIL_IF_NULL(fb); - FlowBitRemove(&f,1); + FlowBitRemove(&f, 1); fb = FlowBitGet(&f, 1); FAIL_IF_NOT_NULL(fb); @@ -293,7 +292,7 @@ static int FlowBitTest09 (void) PASS; } -static int FlowBitTest10 (void) +static int FlowBitTest10(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -303,10 +302,10 @@ static int FlowBitTest10 (void) FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); - FlowBit *fb = FlowBitGet(&f,2); + FlowBit *fb = FlowBitGet(&f, 2); FAIL_IF_NULL(fb); - FlowBitRemove(&f,2); + FlowBitRemove(&f, 2); fb = FlowBitGet(&f, 2); FAIL_IF_NOT_NULL(fb); @@ -315,7 +314,7 @@ static int FlowBitTest10 (void) PASS; } -static int FlowBitTest11 (void) +static int FlowBitTest11(void) { Flow f; memset(&f, 0, sizeof(Flow)); @@ -325,10 +324,10 @@ static int FlowBitTest11 (void) FlowBitAdd(&f, 2); FlowBitAdd(&f, 3); - FlowBit *fb = FlowBitGet(&f,3); + FlowBit *fb = FlowBitGet(&f, 3); FAIL_IF_NULL(fb); - FlowBitRemove(&f,3); + FlowBitRemove(&f, 3); fb = FlowBitGet(&f, 3); FAIL_IF_NOT_NULL(fb); @@ -355,4 +354,3 @@ void FlowBitRegisterTests(void) UtRegisterTest("FlowBitTest11", FlowBitTest11); #endif /* UNITTESTS */ } - diff --git a/src/flow-bit.h b/src/flow-bit.h index 2362d5180795..01b6fed11f26 100644 --- a/src/flow-bit.h +++ b/src/flow-bit.h @@ -25,12 +25,12 @@ #define __FLOW_BIT_H__ #include "flow.h" -#include "util-var.h" +#include "util/var.h" typedef struct FlowBit_ { uint8_t type; /* type, DETECT_FLOWBITS in this case */ uint8_t pad[3]; - uint32_t idx; /* name idx */ + uint32_t idx; /* name idx */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ @@ -45,4 +45,3 @@ void FlowBitToggle(Flow *, uint32_t); int FlowBitIsset(Flow *, uint32_t); int FlowBitIsnotset(Flow *, uint32_t); #endif /* __FLOW_BIT_H__ */ - diff --git a/src/flow-bypass.c b/src/flow-bypass.c index 8dbb5ab17d74..bd598230cbcc 100644 --- a/src/flow-bypass.c +++ b/src/flow-bypass.c @@ -26,18 +26,19 @@ #include "flow.h" #include "flow-bypass.h" #include "flow-private.h" -#include "util-ebpf.h" +#include "util/ebpf.h" #include "runmodes.h" #ifdef CAPTURE_OFFLOAD_MANAGER -#define FLOW_BYPASS_DELAY 10 +#define FLOW_BYPASS_DELAY 10 #ifndef TIMEVAL_TO_TIMESPEC -#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ - (ts)->tv_sec = (tv)->tv_sec; \ - (ts)->tv_nsec = (tv)->tv_usec * 1000; \ -} +#define TIMEVAL_TO_TIMESPEC(tv, ts) \ + { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ + } #endif typedef struct BypassedFlowManagerThreadData_ { @@ -46,7 +47,7 @@ typedef struct BypassedFlowManagerThreadData_ { uint16_t flow_bypassed_bytes; } BypassedFlowManagerThreadData; -#define BYPASSFUNCMAX 4 +#define BYPASSFUNCMAX 4 typedef struct BypassedCheckFuncItem_ { BypassedCheckFunc Func; @@ -70,7 +71,7 @@ static TmEcode BypassedFlowManager(ThreadVars *th_v, void *thread_data) int tcount = 0; int i; BypassedFlowManagerThreadData *ftd = thread_data; - struct timespec curtime = {0, 0}; + struct timespec curtime = { 0, 0 }; struct timeval tv; gettimeofday(&tv, NULL); @@ -99,10 +100,11 @@ static TmEcode BypassedFlowManager(ThreadVars *th_v, void *thread_data) TIMEVAL_TO_TIMESPEC(&tv, &curtime); for (i = 0; i < g_bypassed_func_max_index; i++) { - struct flows_stats bypassstats = { 0, 0, 0}; + struct flows_stats bypassstats = { 0, 0, 0 }; if (bypassedfunclist[i].Func == NULL) continue; - tcount = bypassedfunclist[i].Func(th_v, &bypassstats, &curtime, bypassedfunclist[i].data); + tcount = bypassedfunclist[i].Func( + th_v, &bypassstats, &curtime, bypassedfunclist[i].data); if (tcount) { StatsAddUI64(th_v, ftd->flow_bypassed_cnt_clo, (uint64_t)bypassstats.count); } @@ -148,9 +150,8 @@ static TmEcode BypassedFlowManagerThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -int BypassedFlowManagerRegisterCheckFunc(BypassedCheckFunc CheckFunc, - BypassedCheckFuncInit CheckFuncInit, - void *data) +int BypassedFlowManagerRegisterCheckFunc( + BypassedCheckFunc CheckFunc, BypassedCheckFuncInit CheckFuncInit, void *data) { if (g_bypassed_func_max_index < BYPASSFUNCMAX) { bypassedfunclist[g_bypassed_func_max_index].Func = CheckFunc; @@ -163,8 +164,7 @@ int BypassedFlowManagerRegisterCheckFunc(BypassedCheckFunc CheckFunc, return 0; } -int BypassedFlowManagerRegisterUpdateFunc(BypassedUpdateFunc UpdateFunc, - void *data) +int BypassedFlowManagerRegisterUpdateFunc(BypassedUpdateFunc UpdateFunc, void *data) { if (!UpdateFunc) { return -1; @@ -186,8 +186,7 @@ void BypassedFlowManagerThreadSpawn(void) #ifdef CAPTURE_OFFLOAD_MANAGER ThreadVars *tv_flowmgr = NULL; - tv_flowmgr = TmThreadCreateMgmtThreadByName(thread_name_flow_bypass, - "BypassedFlowManager", 0); + tv_flowmgr = TmThreadCreateMgmtThreadByName(thread_name_flow_bypass, "BypassedFlowManager", 0); BUG_ON(tv_flowmgr == NULL); if (tv_flowmgr == NULL) { @@ -212,7 +211,7 @@ void BypassedFlowUpdate(Flow *f, Packet *p) #endif } -void TmModuleBypassedFlowManagerRegister (void) +void TmModuleBypassedFlowManagerRegister(void) { #ifdef CAPTURE_OFFLOAD_MANAGER tmm_modules[TMM_BYPASSEDFLOWMANAGER].name = "BypassedFlowManager"; @@ -224,4 +223,3 @@ void TmModuleBypassedFlowManagerRegister (void) SCLogDebug("%s registered", tmm_modules[TMM_BYPASSEDFLOWMANAGER].name); #endif } - diff --git a/src/flow-bypass.h b/src/flow-bypass.h index 58ca76663655..9e4523872b1b 100644 --- a/src/flow-bypass.h +++ b/src/flow-bypass.h @@ -32,22 +32,18 @@ struct flows_stats { uint64_t bytes; }; -typedef int (*BypassedCheckFunc)(ThreadVars *th_v, - struct flows_stats *bypassstats, - struct timespec *curtime, void *data); -typedef int (*BypassedCheckFuncInit)(ThreadVars *th_v, - struct timespec *curtime, void *data); +typedef int (*BypassedCheckFunc)( + ThreadVars *th_v, struct flows_stats *bypassstats, struct timespec *curtime, void *data); +typedef int (*BypassedCheckFuncInit)(ThreadVars *th_v, struct timespec *curtime, void *data); typedef int (*BypassedUpdateFunc)(Flow *f, Packet *p, void *data); void BypassedFlowManagerThreadSpawn(void); void TmModuleBypassedFlowManagerRegister(void); -int BypassedFlowManagerRegisterCheckFunc(BypassedCheckFunc CheckFunc, - BypassedCheckFuncInit CheckFuncInit, void *data); +int BypassedFlowManagerRegisterCheckFunc( + BypassedCheckFunc CheckFunc, BypassedCheckFuncInit CheckFuncInit, void *data); int BypassedFlowManagerRegisterUpdateFunc(BypassedUpdateFunc UpdateFunc, void *data); void BypassedFlowUpdate(Flow *f, Packet *p); #endif - - diff --git a/src/flow-hash.c b/src/flow-hash.c index 3b221e2ffffc..f53c658d5590 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -40,21 +40,20 @@ #include "flow-spare-pool.h" #include "app-layer-parser.h" -#include "util-time.h" -#include "util-debug.h" -#include "util-device.h" +#include "util/time.h" +#include "util/debug.h" +#include "util/device.h" -#include "util-hash-lookup3.h" +#include "util/hash-lookup3.h" #include "conf.h" -#include "output.h" -#include "output-flow.h" +#include "output/output.h" +#include "output/output-flow.h" #include "stream-tcp.h" -#include "util-exception-policy.h" +#include "util/exception-policy.h" extern TcpStreamCnf stream_config; - FlowBucket *flow_hash; SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx); SC_ATOMIC_EXTERN(unsigned int, flow_flags); @@ -196,11 +195,11 @@ static inline uint32_t FlowGetHash(const Packet *p) FlowHashKey4 fhk = { .pad[0] = 0 }; int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); - fhk.addrs[1-ai] = p->src.addr_data32[0]; + fhk.addrs[1 - ai] = p->src.addr_data32[0]; fhk.addrs[ai] = p->dst.addr_data32[0]; const int pi = (p->sp > p->dp); - fhk.ports[1-pi] = p->sp; + fhk.ports[1 - pi] = p->sp; fhk.ports[pi] = p->dp; fhk.proto = p->proto; @@ -223,11 +222,11 @@ static inline uint32_t FlowGetHash(const Packet *p) FlowHashKey4 fhk = { .pad[0] = 0 }; const int ai = (psrc > pdst); - fhk.addrs[1-ai] = psrc; + fhk.addrs[1 - ai] = psrc; fhk.addrs[ai] = pdst; const int pi = (p->icmpv4vars.emb_sport > p->icmpv4vars.emb_dport); - fhk.ports[1-pi] = p->icmpv4vars.emb_sport; + fhk.ports[1 - pi] = p->icmpv4vars.emb_sport; fhk.ports[pi] = p->icmpv4vars.emb_dport; fhk.proto = ICMPV4_GET_EMB_PROTO(p); @@ -243,7 +242,7 @@ static inline uint32_t FlowGetHash(const Packet *p) } else { FlowHashKey4 fhk = { .pad[0] = 0 }; const int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); - fhk.addrs[1-ai] = p->src.addr_data32[0]; + fhk.addrs[1 - ai] = p->src.addr_data32[0]; fhk.addrs[ai] = p->dst.addr_data32[0]; fhk.ports[0] = 0xfeed; fhk.ports[1] = 0xbeef; @@ -280,7 +279,7 @@ static inline uint32_t FlowGetHash(const Packet *p) } const int pi = (p->sp > p->dp); - fhk.ports[1-pi] = p->sp; + fhk.ports[1 - pi] = p->sp; fhk.ports[pi] = p->dp; fhk.proto = p->proto; fhk.recur = p->recursion_level; @@ -313,11 +312,11 @@ uint32_t FlowKeyGetHash(FlowKey *fk) .pad[0] = 0, }; int ai = (fk->src.address.address_un_data32[0] > fk->dst.address.address_un_data32[0]); - fhk.addrs[1-ai] = fk->src.address.address_un_data32[0]; + fhk.addrs[1 - ai] = fk->src.address.address_un_data32[0]; fhk.addrs[ai] = fk->dst.address.address_un_data32[0]; const int pi = (fk->sp > fk->dp); - fhk.ports[1-pi] = fk->sp; + fhk.ports[1 - pi] = fk->sp; fhk.ports[pi] = fk->dp; fhk.proto = fk->proto; @@ -332,8 +331,8 @@ uint32_t FlowKeyGetHash(FlowKey *fk) FlowHashKey6 fhk = { .pad[0] = 0, }; - if (FlowHashRawAddressIPv6GtU32(fk->src.address.address_un_data32, - fk->dst.address.address_un_data32)) { + if (FlowHashRawAddressIPv6GtU32( + fk->src.address.address_un_data32, fk->dst.address.address_un_data32)) { fhk.src[0] = fk->src.address.address_un_data32[0]; fhk.src[1] = fk->src.address.address_un_data32[1]; fhk.src[2] = fk->src.address.address_un_data32[2]; @@ -354,7 +353,7 @@ uint32_t FlowKeyGetHash(FlowKey *fk) } const int pi = (fk->sp > fk->dp); - fhk.ports[1-pi] = fk->sp; + fhk.ports[1 - pi] = fk->sp; fhk.ports[pi] = fk->dp; fhk.proto = fk->proto; fhk.recur = fk->recursion_level; @@ -370,22 +369,21 @@ uint32_t FlowKeyGetHash(FlowKey *fk) static inline bool CmpAddrs(const uint32_t addr1[4], const uint32_t addr2[4]) { - return addr1[0] == addr2[0] && addr1[1] == addr2[1] && - addr1[2] == addr2[2] && addr1[3] == addr2[3]; + return addr1[0] == addr2[0] && addr1[1] == addr2[1] && addr1[2] == addr2[2] && + addr1[3] == addr2[3]; } -static inline bool CmpAddrsAndPorts(const uint32_t src1[4], - const uint32_t dst1[4], Port src_port1, Port dst_port1, - const uint32_t src2[4], const uint32_t dst2[4], Port src_port2, - Port dst_port2) +static inline bool CmpAddrsAndPorts(const uint32_t src1[4], const uint32_t dst1[4], Port src_port1, + Port dst_port1, const uint32_t src2[4], const uint32_t dst2[4], Port src_port2, + Port dst_port2) { /* Compare the source and destination addresses. If they are not equal, * compare the first source address with the second destination address, * and vice versa. Likewise for ports. */ - return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) && - src_port1 == src_port2 && dst_port1 == dst_port2) || - (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) && - src_port1 == dst_port2 && dst_port1 == src_port2); + return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) && src_port1 == src_port2 && + dst_port1 == dst_port2) || + (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) && src_port1 == dst_port2 && + dst_port1 == src_port2); } static inline bool CmpVlanIds( @@ -426,18 +424,17 @@ static inline bool CmpFlowKey(const Flow *f, const FlowKey *k) CmpVlanIds(f->vlan_id, k->vlan_id) && CmpLiveDevIds(f->livedev, k->livedev_id); } -static inline bool CmpAddrsAndICMPTypes(const uint32_t src1[4], - const uint32_t dst1[4], uint8_t icmp_s_type1, uint8_t icmp_d_type1, - const uint32_t src2[4], const uint32_t dst2[4], uint8_t icmp_s_type2, - uint8_t icmp_d_type2) +static inline bool CmpAddrsAndICMPTypes(const uint32_t src1[4], const uint32_t dst1[4], + uint8_t icmp_s_type1, uint8_t icmp_d_type1, const uint32_t src2[4], const uint32_t dst2[4], + uint8_t icmp_s_type2, uint8_t icmp_d_type2) { /* Compare the source and destination addresses. If they are not equal, * compare the first source address with the second destination address, * and vice versa. Likewise for icmp types. */ - return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) && - icmp_s_type1 == icmp_s_type2 && icmp_d_type1 == icmp_d_type2) || - (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) && - icmp_s_type1 == icmp_d_type2 && icmp_d_type1 == icmp_s_type2); + return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) && icmp_s_type1 == icmp_s_type2 && + icmp_d_type1 == icmp_d_type2) || + (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) && icmp_s_type1 == icmp_d_type2 && + icmp_d_type1 == icmp_s_type2); } static inline bool CmpFlowICMPPacket(const Flow *f, const Packet *p) @@ -476,8 +473,8 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) (f->livedev == p->livedev || g_livedev_mask == 0)) { return 1; - /* check the less likely case where the ICMP error was a response to - * a packet from the server. */ + /* check the less likely case where the ICMP error was a response to + * a packet from the server. */ } else if ((f->dst.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p))) && (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p))) && f->dp == p->icmpv4vars.emb_sport && f->sp == p->icmpv4vars.emb_dport && @@ -569,15 +566,14 @@ static inline int FlowCreateCheck(const Packet *p, const bool emerg) return 1; } -static inline void FlowUpdateCounter(ThreadVars *tv, DecodeThreadVars *dtv, - uint8_t proto) +static inline void FlowUpdateCounter(ThreadVars *tv, DecodeThreadVars *dtv, uint8_t proto) { #ifdef UNITTESTS if (tv && dtv) { #endif StatsIncr(tv, dtv->counter_flow_total); StatsIncr(tv, dtv->counter_flow_active); - switch (proto){ + switch (proto) { case IPPROTO_UDP: StatsIncr(tv, dtv->counter_flow_udp); break; @@ -601,8 +597,8 @@ static inline void FlowUpdateCounter(ThreadVars *tv, DecodeThreadVars *dtv, * * If in emergency mode, do this only once a second at max to avoid trying * to synchronise per packet in the worse case. */ -static inline Flow *FlowSpareSync(ThreadVars *tv, FlowLookupStruct *fls, - const Packet *p, const bool emerg) +static inline Flow *FlowSpareSync( + ThreadVars *tv, FlowLookupStruct *fls, const Packet *p, const bool emerg) { Flow *f = NULL; bool spare_sync = false; @@ -626,7 +622,7 @@ static inline Flow *FlowSpareSync(ThreadVars *tv, FlowLookupStruct *fls, #endif if (spare_sync) { if (f != NULL) { - StatsAddUI64(tv, fls->dtv->counter_flow_spare_sync_avg, fls->spare_queue.len+1); + StatsAddUI64(tv, fls->dtv->counter_flow_spare_sync_avg, fls->spare_queue.len + 1); if (fls->spare_queue.len < 99) { StatsIncr(tv, fls->dtv->counter_flow_spare_sync_incomplete); } @@ -780,8 +776,8 @@ static inline bool FlowBelongsToUs(const ThreadVars *tv, const Flow *f) return f->thread_id[0] == tv->id; } -static inline void MoveToWorkQueue(ThreadVars *tv, FlowLookupStruct *fls, - FlowBucket *fb, Flow *f, Flow *prev_f) +static inline void MoveToWorkQueue( + ThreadVars *tv, FlowLookupStruct *fls, FlowBucket *fb, Flow *f, Flow *prev_f) { f->flow_end_flags |= FLOW_END_FLAG_TIMEOUT; @@ -815,8 +811,8 @@ static inline bool FlowIsTimedOut(const Flow *f, const uint32_t sec, const bool } else if (unlikely(emerg)) { extern FlowProtoTimeout flow_timeouts_delta[FLOW_PROTO_MAX]; - int64_t timeout_at = f->timeout_at - - FlowGetFlowTimeoutDirect(flow_timeouts_delta, f->flow_state, f->protomap); + int64_t timeout_at = f->timeout_at - FlowGetFlowTimeoutDirect(flow_timeouts_delta, + f->flow_state, f->protomap); if ((int64_t)sec >= timeout_at) return true; } @@ -897,7 +893,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls, Packet *p, Flow if (prev_f == NULL) /* if we have no prev it means new_f is now our prev */ prev_f = new_f; MoveToWorkQueue(tv, fls, fb, f, prev_f); /* evict old flow */ - FLOWLOCK_UNLOCK(f); /* unlock old replaced flow */ + FLOWLOCK_UNLOCK(f); /* unlock old replaced flow */ if (new_f == NULL) { FBLOCK_UNLOCK(fb); @@ -914,7 +910,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls, Packet *p, Flow prev_f = f; next_f = f->next; -flow_removed: + flow_removed: if (next_f == NULL) { f = FlowGetNew(tv, fls, p); if (f == NULL) { @@ -1096,7 +1092,7 @@ static inline int GetUsedTryLockFlow(Flow *f) } static inline uint32_t GetUsedAtomicUpdate(const uint32_t val) { - uint32_t r = SC_ATOMIC_ADD(flow_prune_idx, val); + uint32_t r = SC_ATOMIC_ADD(flow_prune_idx, val); return r; } @@ -1131,13 +1127,12 @@ static inline bool StillAlive(const Flow *f, const SCTime_t ts) } #ifdef UNITTESTS - #define STATSADDUI64(cnt, value) \ - if (tv && dtv) { \ - StatsAddUI64(tv, dtv->cnt, (value)); \ - } +#define STATSADDUI64(cnt, value) \ + if (tv && dtv) { \ + StatsAddUI64(tv, dtv->cnt, (value)); \ + } #else - #define STATSADDUI64(cnt, value) \ - StatsAddUI64(tv, dtv->cnt, (value)); +#define STATSADDUI64(cnt, value) StatsAddUI64(tv, dtv->cnt, (value)); #endif /** \internal @@ -1208,7 +1203,7 @@ static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv, const SCTime if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) f->flow_end_flags |= FLOW_END_FLAG_EMERGENCY; - /* invoke flow log api */ + /* invoke flow log api */ #ifdef UNITTESTS if (dtv) { #endif diff --git a/src/flow-hash.h b/src/flow-hash.h index 201eb6414543..a8ff79818775 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -27,13 +27,13 @@ #include "flow.h" /** Spinlocks or Mutex for the flow buckets. */ -//#define FBLOCK_SPIN +// #define FBLOCK_SPIN #define FBLOCK_MUTEX #ifdef FBLOCK_SPIN - #ifdef FBLOCK_MUTEX - #error Cannot enable both FBLOCK_SPIN and FBLOCK_MUTEX - #endif +#ifdef FBLOCK_MUTEX +#error Cannot enable both FBLOCK_SPIN and FBLOCK_MUTEX +#endif #endif /* flow hash bucket -- the hash is basically an array of these buckets. @@ -51,7 +51,7 @@ typedef struct FlowBucket_ { #elif defined FBLOCK_SPIN SCSpinlock s; #else - #error Enable FBLOCK_SPIN or FBLOCK_MUTEX +#error Enable FBLOCK_SPIN or FBLOCK_MUTEX #endif /** timestamp in seconds of the earliest possible moment a flow * will time out in this row. Set by the flow manager. Cleared @@ -62,19 +62,19 @@ typedef struct FlowBucket_ { } __attribute__((aligned(CLS))) FlowBucket; #ifdef FBLOCK_SPIN - #define FBLOCK_INIT(fb) SCSpinInit(&(fb)->s, 0) - #define FBLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->s) - #define FBLOCK_LOCK(fb) SCSpinLock(&(fb)->s) - #define FBLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->s) - #define FBLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->s) +#define FBLOCK_INIT(fb) SCSpinInit(&(fb)->s, 0) +#define FBLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->s) +#define FBLOCK_LOCK(fb) SCSpinLock(&(fb)->s) +#define FBLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->s) +#define FBLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->s) #elif defined FBLOCK_MUTEX - #define FBLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL) - #define FBLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m) - #define FBLOCK_LOCK(fb) SCMutexLock(&(fb)->m) - #define FBLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->m) - #define FBLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m) +#define FBLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL) +#define FBLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m) +#define FBLOCK_LOCK(fb) SCMutexLock(&(fb)->m) +#define FBLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->m) +#define FBLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m) #else - #error Enable FBLOCK_SPIN or FBLOCK_MUTEX +#error Enable FBLOCK_SPIN or FBLOCK_MUTEX #endif /* prototypes */ @@ -103,4 +103,3 @@ static inline void RemoveFromHash(Flow *f, Flow *prev_f) } #endif /* __FLOW_HASH_H__ */ - diff --git a/src/flow-manager.c b/src/flow-manager.c index bcc1498c8bd8..9a4bf64207d3 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -28,8 +28,8 @@ #include "tm-threads.h" #include "runmodes.h" -#include "util-random.h" -#include "util-time.h" +#include "util/random.h" +#include "util/time.h" #include "flow.h" #include "flow-queue.h" @@ -44,11 +44,11 @@ #include "stream-tcp-reassemble.h" #include "stream-tcp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-device.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/device.h" -#include "util-debug.h" +#include "util/debug.h" #include "threads.h" #include "detect.h" @@ -60,9 +60,9 @@ #include "host-timeout.h" #include "defrag-timeout.h" #include "ippair-timeout.h" -#include "app-layer-htp-range.h" +#include "app-layer/http/parser-range.h" -#include "output-flow.h" +#include "output/output-flow.h" #include "runmode-unix-socket.h" @@ -114,12 +114,12 @@ void FlowTimeoutsEmergency(void) } /* 1 seconds */ -#define FLOW_NORMAL_MODE_UPDATE_DELAY_SEC 1 +#define FLOW_NORMAL_MODE_UPDATE_DELAY_SEC 1 #define FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC 0 /* 0.3 seconds */ -#define FLOW_EMERG_MODE_UPDATE_DELAY_SEC 0 +#define FLOW_EMERG_MODE_UPDATE_DELAY_SEC 0 #define FLOW_EMERG_MODE_UPDATE_DELAY_NSEC 300000 -#define NEW_FLOW_COUNT_COND 10 +#define NEW_FLOW_COUNT_COND 10 typedef struct FlowTimeoutCounters_ { uint32_t rows_checked; @@ -150,9 +150,7 @@ void FlowDisableFlowManagerThread(void) SCMutexLock(&tv_root_lock); /* flow manager thread(s) is/are a part of mgmt threads */ for (ThreadVars *tv = tv_root[TVT_MGMT]; tv != NULL; tv = tv->next) { - if (strncasecmp(tv->name, thread_name_flow_mgr, - strlen(thread_name_flow_mgr)) == 0) - { + if (strncasecmp(tv->name, thread_name_flow_mgr, strlen(thread_name_flow_mgr)) == 0) { TmThreadsSetFlag(tv, THV_KILL); } } @@ -171,9 +169,7 @@ void FlowDisableFlowManagerThread(void) SCMutexLock(&tv_root_lock); for (ThreadVars *tv = tv_root[TVT_MGMT]; tv != NULL; tv = tv->next) { - if (strncasecmp(tv->name, thread_name_flow_mgr, - strlen(thread_name_flow_mgr)) == 0) - { + if (strncasecmp(tv->name, thread_name_flow_mgr, strlen(thread_name_flow_mgr)) == 0) { if (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { SCMutexUnlock(&tv_root_lock); /* sleep outside lock */ @@ -203,7 +199,8 @@ static int FlowManagerFlowTimeout(Flow *f, SCTime_t ts, uint32_t *next_ts, const uint32_t flow_times_out_at = f->timeout_at; if (emerg) { extern FlowProtoTimeout flow_timeouts_delta[FLOW_PROTO_MAX]; - flow_times_out_at -= FlowGetFlowTimeoutDirect(flow_timeouts_delta, f->flow_state, f->protomap); + flow_times_out_at -= + FlowGetFlowTimeoutDirect(flow_timeouts_delta, f->flow_state, f->protomap); } if (*next_ts == 0 || flow_times_out_at < *next_ts) *next_ts = flow_times_out_at; @@ -242,20 +239,19 @@ static inline int FlowBypassedTimeout(Flow *f, SCTime_t ts, FlowTimeoutCounters uint64_t bytes_todst = fc->todstbytecnt; bool update = fc->BypassUpdate(f, fc->bypass_data, SCTIME_SECS(ts)); if (update) { - SCLogDebug("Updated flow: %"PRId64"", FlowGetId(f)); + SCLogDebug("Updated flow: %" PRId64 "", FlowGetId(f)); pkts_tosrc = fc->tosrcpktcnt - pkts_tosrc; bytes_tosrc = fc->tosrcbytecnt - bytes_tosrc; pkts_todst = fc->todstpktcnt - pkts_todst; bytes_todst = fc->todstbytecnt - bytes_todst; if (f->livedev) { - SC_ATOMIC_ADD(f->livedev->bypassed, - pkts_tosrc + pkts_todst); + SC_ATOMIC_ADD(f->livedev->bypassed, pkts_tosrc + pkts_todst); } counters->bypassed_pkts += pkts_tosrc + pkts_todst; counters->bypassed_bytes += bytes_tosrc + bytes_todst; return 0; } else { - SCLogDebug("No new packet, dead flow %"PRId64"", FlowGetId(f)); + SCLogDebug("No new packet, dead flow %" PRId64 "", FlowGetId(f)); if (f->livedev) { if (FLOW_IS_IPV4(f)) { LiveDevSubBypassStats(f->livedev, 1, AF_INET); @@ -413,7 +409,7 @@ static uint32_t FlowTimeoutHash(FlowManagerTimeoutThread *td, SCTime_t ts, const uint32_t rows_skipped = 0; uint32_t rows_empty = 0; -#if __WORDSIZE==64 +#if __WORDSIZE == 64 #define BITS 64 #define TYPE uint64_t #else @@ -422,11 +418,11 @@ static uint32_t FlowTimeoutHash(FlowManagerTimeoutThread *td, SCTime_t ts, const #endif const uint32_t ts_secs = SCTIME_SECS(ts); - for (uint32_t idx = hash_min; idx < hash_max; idx+=BITS) { + for (uint32_t idx = hash_min; idx < hash_max; idx += BITS) { TYPE check_bits = 0; const uint32_t check = MIN(BITS, (hash_max - idx)); for (uint32_t i = 0; i < check; i++) { - FlowBucket *fb = &flow_hash[idx+i]; + FlowBucket *fb = &flow_hash[idx + i]; check_bits |= (TYPE)(SC_ATOMIC_LOAD_EXPLICIT( fb->next_ts, SC_ATOMIC_MEMORY_ORDER_RELAXED) <= ts_secs) << (TYPE)i; @@ -435,7 +431,7 @@ static uint32_t FlowTimeoutHash(FlowManagerTimeoutThread *td, SCTime_t ts, const continue; for (uint32_t i = 0; i < check; i++) { - FlowBucket *fb = &flow_hash[idx+i]; + FlowBucket *fb = &flow_hash[idx + i]; if ((check_bits & ((TYPE)1 << (TYPE)i)) != 0 && SC_ATOMIC_GET(fb->next_ts) <= ts_secs) { FBLOCK_LOCK(fb); Flow *evicted = NULL; @@ -648,7 +644,8 @@ static void FlowCountersInit(ThreadVars *t, FlowCounters *fc) fc->flow_mgr_flows_notimeout = StatsRegisterCounter("flow.mgr.flows_notimeout", t); fc->flow_mgr_flows_timeout = StatsRegisterCounter("flow.mgr.flows_timeout", t); fc->flow_mgr_flows_aside = StatsRegisterCounter("flow.mgr.flows_evicted", t); - fc->flow_mgr_flows_aside_needs_work = StatsRegisterCounter("flow.mgr.flows_evicted_needs_work", t); + fc->flow_mgr_flows_aside_needs_work = + StatsRegisterCounter("flow.mgr.flows_evicted_needs_work", t); fc->flow_bypassed_cnt_clo = StatsRegisterCounter("flow_bypassed.closed", t); fc->flow_bypassed_pkts = StatsRegisterCounter("flow_bypassed.pkts", t); @@ -795,8 +792,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) TmThreadsSetFlag(th_v, THV_RUNNING); - while (1) - { + while (1) { if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { TmThreadsSetFlag(th_v, THV_PAUSED); TmThreadTestThreadUnPaused(th_v); @@ -827,9 +823,21 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) } /* try to time out flows */ - // clang-format off - FlowTimeoutCounters counters = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; - // clang-format on + FlowTimeoutCounters counters = { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }; if (emerg) { /* in emergency mode, do a full pass of the hash table */ @@ -938,7 +946,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCCtrlMutexUnlock(&flow_manager_ctrl_mutex); } - SCLogDebug("woke up... %s", SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY ? "emergency":""); + SCLogDebug("woke up... %s", SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY ? "emergency" : ""); StatsSyncCountersIfSignalled(th_v); } @@ -961,10 +969,9 @@ void FlowManagerThreadSpawn(void) for (uint32_t u = 0; u < flowmgr_number; u++) { char name[TM_THREAD_NAME_MAX]; - snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_mgr, u+1); + snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_mgr, u + 1); - ThreadVars *tv_flowmgr = TmThreadCreateMgmtThreadByName(name, - "FlowManager", 0); + ThreadVars *tv_flowmgr = TmThreadCreateMgmtThreadByName(name, "FlowManager", 0); BUG_ON(tv_flowmgr == NULL); if (tv_flowmgr == NULL) { @@ -1058,14 +1065,13 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) TmThreadsSetFlag(th_v, THV_RUNNING); - while (1) - { + while (1) { if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { TmThreadsSetFlag(th_v, THV_PAUSED); TmThreadTestThreadUnPaused(th_v); TmThreadsUnsetFlag(th_v, THV_PAUSED); } - SC_ATOMIC_ADD(flowrec_busy,1); + SC_ATOMIC_ADD(flowrec_busy, 1); FlowQueuePrivate list = FlowQueueExtractPrivate(&flow_recycle_q); StatsAddUI64(th_v, ftd->counter_queue_avg, list.len); @@ -1095,7 +1101,7 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) recycled_cnt += cnt; StatsAddUI64(th_v, ftd->counter_flows, cnt); } - SC_ATOMIC_SUB(flowrec_busy,1); + SC_ATOMIC_SUB(flowrec_busy, 1); if (bail) { break; @@ -1131,7 +1137,7 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) StatsSyncCountersIfSignalled(th_v); } StatsSyncCounters(th_v); - SCLogPerf("%"PRIu64" flows processed", recycled_cnt); + SCLogPerf("%" PRIu64 " flows processed", recycled_cnt); return TM_ECODE_OK; } @@ -1163,10 +1169,9 @@ void FlowRecyclerThreadSpawn(void) for (uint32_t u = 0; u < flowrec_number; u++) { char name[TM_THREAD_NAME_MAX]; - snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_rec, u+1); + snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_rec, u + 1); - ThreadVars *tv_flowrec = TmThreadCreateMgmtThreadByName(name, - "FlowRecycler", 0); + ThreadVars *tv_flowrec = TmThreadCreateMgmtThreadByName(name, "FlowRecycler", 0); if (tv_flowrec == NULL) { FatalError("flow recycler thread creation failed"); @@ -1205,9 +1210,7 @@ void FlowDisableFlowRecyclerThread(void) SCMutexLock(&tv_root_lock); /* flow recycler thread(s) is/are a part of mgmt threads */ for (ThreadVars *tv = tv_root[TVT_MGMT]; tv != NULL; tv = tv->next) { - if (strncasecmp(tv->name, thread_name_flow_rec, - strlen(thread_name_flow_rec)) == 0) - { + if (strncasecmp(tv->name, thread_name_flow_rec, strlen(thread_name_flow_rec)) == 0) { TmThreadsSetFlag(tv, THV_KILL); } } @@ -1226,9 +1229,7 @@ void FlowDisableFlowRecyclerThread(void) SCMutexLock(&tv_root_lock); for (ThreadVars *tv = tv_root[TVT_MGMT]; tv != NULL; tv = tv->next) { - if (strncasecmp(tv->name, thread_name_flow_rec, - strlen(thread_name_flow_rec)) == 0) - { + if (strncasecmp(tv->name, thread_name_flow_rec, strlen(thread_name_flow_rec)) == 0) { if (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { SCMutexUnlock(&tv_root_lock); FlowWakeupFlowRecyclerThread(); @@ -1245,7 +1246,7 @@ void FlowDisableFlowRecyclerThread(void) return; } -void TmModuleFlowManagerRegister (void) +void TmModuleFlowManagerRegister(void) { tmm_modules[TMM_FLOWMANAGER].name = "FlowManager"; tmm_modules[TMM_FLOWMANAGER].ThreadInit = FlowManagerThreadInit; @@ -1259,7 +1260,7 @@ void TmModuleFlowManagerRegister (void) SC_ATOMIC_INITPTR(flow_timeouts); } -void TmModuleFlowRecyclerRegister (void) +void TmModuleFlowRecyclerRegister(void) { tmm_modules[TMM_FLOWRECYCLER].name = "FlowRecycler"; tmm_modules[TMM_FLOWRECYCLER].ThreadInit = FlowRecyclerThreadInit; diff --git a/src/flow-manager.h b/src/flow-manager.h index 7cdd017000aa..82c3c47b4cf6 100644 --- a/src/flow-manager.h +++ b/src/flow-manager.h @@ -34,7 +34,7 @@ void FlowManagerThreadSpawn(void); void FlowDisableFlowManagerThread(void); void FlowRecyclerThreadSpawn(void); void FlowDisableFlowRecyclerThread(void); -void TmModuleFlowManagerRegister (void); -void TmModuleFlowRecyclerRegister (void); +void TmModuleFlowManagerRegister(void); +void TmModuleFlowRecyclerRegister(void); #endif /* __FLOW_MANAGER_H__ */ diff --git a/src/flow-private.h b/src/flow-private.h index d3899f6dfbc0..b82000f6d591 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -27,42 +27,42 @@ #include "flow-hash.h" #include "flow-queue.h" -#include "util-atomic.h" +#include "util/atomic.h" /* global flow flags */ /** Flow engine is in emergency mode. This means it doesn't have enough spare * flows for new flows and/or it's memcap limit it reached. In this state the * flow engine with evaluate flows with lower timeout settings. */ -#define FLOW_EMERGENCY 0x01 +#define FLOW_EMERGENCY 0x01 /* Flow Time out values */ -#define FLOW_DEFAULT_NEW_TIMEOUT 30 +#define FLOW_DEFAULT_NEW_TIMEOUT 30 #define FLOW_DEFAULT_EST_TIMEOUT 300 -#define FLOW_DEFAULT_BYPASSED_TIMEOUT 100 -#define FLOW_IPPROTO_TCP_NEW_TIMEOUT 30 -#define FLOW_IPPROTO_TCP_EST_TIMEOUT 300 -#define FLOW_IPPROTO_TCP_CLOSED_TIMEOUT 10 -#define FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT 100 -#define FLOW_IPPROTO_UDP_NEW_TIMEOUT 30 -#define FLOW_IPPROTO_UDP_EST_TIMEOUT 300 -#define FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT 100 -#define FLOW_IPPROTO_ICMP_NEW_TIMEOUT 30 -#define FLOW_IPPROTO_ICMP_EST_TIMEOUT 300 +#define FLOW_DEFAULT_BYPASSED_TIMEOUT 100 +#define FLOW_IPPROTO_TCP_NEW_TIMEOUT 30 +#define FLOW_IPPROTO_TCP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_TCP_CLOSED_TIMEOUT 10 +#define FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT 100 +#define FLOW_IPPROTO_UDP_NEW_TIMEOUT 30 +#define FLOW_IPPROTO_UDP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT 100 +#define FLOW_IPPROTO_ICMP_NEW_TIMEOUT 30 +#define FLOW_IPPROTO_ICMP_EST_TIMEOUT 300 #define FLOW_IPPROTO_ICMP_BYPASSED_TIMEOUT 100 -#define FLOW_DEFAULT_EMERG_NEW_TIMEOUT 10 +#define FLOW_DEFAULT_EMERG_NEW_TIMEOUT 10 #define FLOW_DEFAULT_EMERG_EST_TIMEOUT 100 -#define FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT 50 -#define FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT 10 -#define FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT 100 +#define FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT 50 +#define FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT 10 +#define FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT 100 #define FLOW_IPPROTO_TCP_EMERG_CLOSED_TIMEOUT 5 -#define FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT 10 -#define FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT 100 -#define FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT 10 -#define FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT 100 +#define FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT 10 +#define FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT 100 +#define FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT 10 +#define FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT 100 -#define FLOW_BYPASSED_TIMEOUT 100 +#define FLOW_BYPASSED_TIMEOUT 100 enum { FLOW_PROTO_TCP = 0, @@ -87,7 +87,7 @@ extern FlowProtoTimeout flow_timeouts_emerg[FLOW_PROTO_MAX]; extern FlowProtoFreeFunc flow_freefuncs[FLOW_PROTO_MAX]; /** spare/unused/prealloced flows live here */ -//extern FlowQueue flow_spare_q; +// extern FlowQueue flow_spare_q; /** queue to pass flows to cleanup/log thread(s) */ extern FlowQueue flow_recycle_q; @@ -102,8 +102,7 @@ typedef FlowProtoTimeout *FlowProtoTimeoutPtr; SC_ATOMIC_EXTERN(FlowProtoTimeoutPtr, flow_timeouts); static inline uint32_t FlowGetFlowTimeoutDirect( - const FlowProtoTimeoutPtr flow_timeouts, - const enum FlowState state, const uint8_t protomap) + const FlowProtoTimeoutPtr flow_timeouts, const enum FlowState state, const uint8_t protomap) { uint32_t timeout; switch (state) { diff --git a/src/flow-queue.c b/src/flow-queue.c index 1d4653b3bf30..e32d0319d4fe 100644 --- a/src/flow-queue.c +++ b/src/flow-queue.c @@ -28,9 +28,9 @@ #include "flow-private.h" #include "flow-queue.h" #include "flow-util.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-print.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/print.h" FlowQueue *FlowQueueNew(void) { @@ -43,7 +43,7 @@ FlowQueue *FlowQueueNew(void) return q; } -FlowQueue *FlowQueueInit (FlowQueue *q) +FlowQueue *FlowQueueInit(FlowQueue *q) { if (q != NULL) { memset(q, 0, sizeof(FlowQueue)); @@ -57,7 +57,7 @@ FlowQueue *FlowQueueInit (FlowQueue *q) * * \param q the flow queue to destroy */ -void FlowQueueDestroy (FlowQueue *q) +void FlowQueueDestroy(FlowQueue *q) { FQLOCK_DESTROY(q); } @@ -170,7 +170,7 @@ Flow *FlowQueuePrivateGetFromTop(FlowQueuePrivate *fqc) * \param q queue * \param f flow */ -void FlowEnqueue (FlowQueue *q, Flow *f) +void FlowEnqueue(FlowQueue *q, Flow *f) { #ifdef DEBUG BUG_ON(q == NULL || f == NULL); @@ -188,7 +188,7 @@ void FlowEnqueue (FlowQueue *q, Flow *f) * * \retval f flow or NULL if empty list. */ -Flow *FlowDequeue (FlowQueue *q) +Flow *FlowDequeue(FlowQueue *q) { FQLOCK_LOCK(q); Flow *f = FlowQueuePrivateGetFromTop(&q->priv); diff --git a/src/flow-queue.h b/src/flow-queue.h index 0523546ce8a9..aa6e415897ba 100644 --- a/src/flow-queue.h +++ b/src/flow-queue.h @@ -28,33 +28,31 @@ #include "flow.h" /** Spinlocks or Mutex for the flow queues. */ -//#define FQLOCK_SPIN +// #define FQLOCK_SPIN #define FQLOCK_MUTEX #ifdef FQLOCK_SPIN - #ifdef FQLOCK_MUTEX - #error Cannot enable both FQLOCK_SPIN and FQLOCK_MUTEX - #endif +#ifdef FQLOCK_MUTEX +#error Cannot enable both FQLOCK_SPIN and FQLOCK_MUTEX +#endif #endif -typedef struct FlowQueuePrivate_ -{ +typedef struct FlowQueuePrivate_ { Flow *top; Flow *bot; uint32_t len; } FlowQueuePrivate; /* Define a queue for storing flows */ -typedef struct FlowQueue_ -{ +typedef struct FlowQueue_ { FlowQueuePrivate priv; - SC_ATOMIC_DECLARE(bool,non_empty); + SC_ATOMIC_DECLARE(bool, non_empty); #ifdef FQLOCK_MUTEX SCMutex m; #elif defined FQLOCK_SPIN SCSpinlock s; #else - #error Enable FQLOCK_SPIN or FQLOCK_MUTEX +#error Enable FQLOCK_SPIN or FQLOCK_MUTEX #endif } FlowQueue; #define qtop priv.top @@ -62,28 +60,28 @@ typedef struct FlowQueue_ #define qlen priv.len #ifdef FQLOCK_SPIN - #define FQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) - #define FQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) - #define FQLOCK_LOCK(q) SCSpinLock(&(q)->s) - #define FQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) - #define FQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) +#define FQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) +#define FQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) +#define FQLOCK_LOCK(q) SCSpinLock(&(q)->s) +#define FQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) +#define FQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) #elif defined FQLOCK_MUTEX - #define FQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) - #define FQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) - #define FQLOCK_LOCK(q) SCMutexLock(&(q)->m) - #define FQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) - #define FQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) +#define FQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) +#define FQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) +#define FQLOCK_LOCK(q) SCMutexLock(&(q)->m) +#define FQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) +#define FQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) #else - #error Enable FQLOCK_SPIN or FQLOCK_MUTEX +#error Enable FQLOCK_SPIN or FQLOCK_MUTEX #endif /* prototypes */ FlowQueue *FlowQueueNew(void); FlowQueue *FlowQueueInit(FlowQueue *); -void FlowQueueDestroy (FlowQueue *); +void FlowQueueDestroy(FlowQueue *); -void FlowEnqueue (FlowQueue *, Flow *); -Flow *FlowDequeue (FlowQueue *); +void FlowEnqueue(FlowQueue *, Flow *); +Flow *FlowDequeue(FlowQueue *); void FlowQueueRemove(FlowQueue *fq, Flow *f); void FlowQueuePrivateAppendFlow(FlowQueuePrivate *fqc, Flow *f); @@ -95,4 +93,3 @@ FlowQueuePrivate FlowQueueExtractPrivate(FlowQueue *fq); Flow *FlowQueuePrivateGetFromTop(FlowQueuePrivate *fqp); #endif /* __FLOW_QUEUE_H__ */ - diff --git a/src/flow-spare-pool.c b/src/flow-spare-pool.c index e47b983b8e04..f7a7cfa5f501 100644 --- a/src/flow-spare-pool.c +++ b/src/flow-spare-pool.c @@ -29,10 +29,10 @@ #include "flow-queue.h" #include "flow-util.h" #include "flow-spare-pool.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-validate.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/print.h" +#include "util/validate.h" typedef struct FlowSparePool { FlowQueuePrivate queue; @@ -65,8 +65,7 @@ static bool FlowSparePoolUpdateBlock(FlowSparePool *p) { DEBUG_VALIDATE_BUG_ON(p == NULL); - for (uint32_t i = p->queue.len; i < flow_spare_pool_block_size; i++) - { + for (uint32_t i = p->queue.len; i < flow_spare_pool_block_size; i++) { Flow *f = FlowAlloc(); if (f == NULL) return false; @@ -84,12 +83,11 @@ static void Validate(FlowSparePool *top, const uint32_t target) } assert(top->queue.len >= 1); - //if (top->next != NULL) - // assert(top->next->queue.len == flow_spare_pool_block_size); + // if (top->next != NULL) + // assert(top->next->queue.len == flow_spare_pool_block_size); uint32_t cnt = 0; - for (FlowSparePool *p = top; p != NULL; p = p->next) - { + for (FlowSparePool *p = top; p != NULL; p = p->next) { assert(p->queue.len); cnt += p->queue.len; } @@ -195,7 +193,7 @@ FlowQueuePrivate FlowSpareGetFromPool(void) FlowQueuePrivate ret = p->queue; SCFree(p); return ret; - /* next should always be full if it exists */ + /* next should always be full if it exists */ } else if (flow_spare_pool->next != NULL) { FlowSparePool *p = flow_spare_pool->next; flow_spare_pool->next = p->next; @@ -293,7 +291,7 @@ void FlowSparePoolUpdate(uint32_t size) void FlowSparePoolInit(void) { SCMutexLock(&flow_spare_pool_m); - for (uint32_t cnt = 0; cnt < flow_config.prealloc; ) { + for (uint32_t cnt = 0; cnt < flow_config.prealloc;) { FlowSparePool *p = FlowSpareGetPool(); if (p == NULL) { FatalError("failed to initialize flow pool"); @@ -312,7 +310,7 @@ void FlowSparePoolInit(void) void FlowSparePoolDestroy(void) { SCMutexLock(&flow_spare_pool_m); - for (FlowSparePool *p = flow_spare_pool; p != NULL; ) { + for (FlowSparePool *p = flow_spare_pool; p != NULL;) { uint32_t cnt = 0; Flow *f; while ((f = FlowQueuePrivateGetFromTop(&p->queue))) { diff --git a/src/flow-storage.c b/src/flow-storage.c index 53b67ba63048..f12325e62d52 100644 --- a/src/flow-storage.c +++ b/src/flow-storage.c @@ -29,8 +29,8 @@ #include "flow-storage.h" #include "flow-hash.h" #include "flow-util.h" -#include "util-storage.h" -#include "util-unittest.h" +#include "util/storage.h" +#include "util/unittest.h" unsigned int FlowStorageSize(void) { @@ -200,7 +200,6 @@ static int FlowStorageTest02(void) goto error; } - FlowClearMemory(f, 0); FlowFree(f); FlowShutdown(); diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 90a97fa66688..08fd9cd70e37 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -29,8 +29,8 @@ #include "tm-threads.h" #include "runmodes.h" -#include "util-random.h" -#include "util-time.h" +#include "util/random.h" +#include "util/time.h" #include "flow.h" #include "flow-queue.h" @@ -47,13 +47,13 @@ #include "stream-tcp-reassemble.h" #include "stream-tcp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" -#include "util-debug.h" -#include "util-privs.h" -#include "util-datalink.h" +#include "util/debug.h" +#include "util/privs.h" +#include "util/datalink.h" #include "detect.h" #include "detect-engine-state.h" @@ -62,7 +62,7 @@ #include "app-layer-parser.h" #include "app-layer.h" -#include "util-profiling.h" +#include "util/profiling.h" /** * \internal @@ -126,7 +126,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup( /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr. * Force an allocation if it is not the case. */ - if (GET_PKT_DIRECT_MAX_SIZE(p) < 40) { + if (GET_PKT_DIRECT_MAX_SIZE(p) < 40) { if (PacketCallocExtPkt(p, 40) == -1) { goto error; } @@ -141,7 +141,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup( p->ip4h->ip_off = 0; p->ip4h->ip_ttl = 64; p->ip4h->ip_proto = IPPROTO_TCP; - //p->ip4h->ip_csum = + // p->ip4h->ip_csum = if (direction == 0) { p->ip4h->s_ip_src.s_addr = f->src.addr_data32[0]; p->ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0]; @@ -171,7 +171,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup( /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr. * Force an allocation if it is not the case. */ - if (GET_PKT_DIRECT_MAX_SIZE(p) < 60) { + if (GET_PKT_DIRECT_MAX_SIZE(p) < 60) { if (PacketCallocExtPkt(p, 60) == -1) { goto error; } @@ -233,15 +233,12 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup( } if (FLOW_IS_IPV4(f)) { - p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, 20, 0); + p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, 20, 0); /* calc ipv4 csum as we may log it and barnyard might reject * a wrong checksum */ - p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, - IPV4_GET_RAW_HLEN(p->ip4h), 0); + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h), 0); } else if (FLOW_IS_IPV6(f)) { - p->tcph->th_sum = TCPChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, 20, 0); + p->tcph->th_sum = TCPChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, 20, 0); } p->ts = TimeGet(); @@ -297,8 +294,7 @@ int FlowForceReassemblyNeedReassembly(Flow *f) /* if state is not fully closed we assume that we haven't fully * inspected the app layer state yet */ - if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED) - { + if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED) { client = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION; server = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION; } @@ -307,19 +303,17 @@ int FlowForceReassemblyNeedReassembly(Flow *f) if (f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) { const uint64_t total_txs = AppLayerParserGetTxCnt(f, f->alstate); - if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOCLIENT) < total_txs) - { + if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOCLIENT) < total_txs) { server = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION; } - if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOSERVER) < total_txs) - { + if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOSERVER) < total_txs) { client = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION; } } /* nothing to do */ if (client == STREAM_HAS_UNPROCESSED_SEGMENTS_NONE && - server == STREAM_HAS_UNPROCESSED_SEGMENTS_NONE) { + server == STREAM_HAS_UNPROCESSED_SEGMENTS_NONE) { SCReturnInt(0); } diff --git a/src/flow-util.c b/src/flow-util.c index 672abc23d2ba..ba578598bee2 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -32,9 +32,9 @@ #include "flow-var.h" #include "app-layer.h" -#include "util-var.h" -#include "util-debug.h" -#include "util-macset.h" +#include "util/var.h" +#include "util/debug.h" +#include "util/macset.h" #include "flow-storage.h" #include "detect.h" @@ -42,7 +42,7 @@ #include "decode-icmpv4.h" -#include "util-validate.h" +#include "util/validate.h" /** \brief allocate a flow * @@ -60,7 +60,7 @@ Flow *FlowAlloc(void) return NULL; } - (void) SC_ATOMIC_ADD(flow_memuse, size); + (void)SC_ATOMIC_ADD(flow_memuse, size); f = SCCalloc(1, size); if (unlikely(f == NULL)) { @@ -73,7 +73,6 @@ Flow *FlowAlloc(void) return f; } - /** * \brief cleanup & free the memory of a flow * @@ -85,7 +84,7 @@ void FlowFree(Flow *f) SCFree(f); size_t size = sizeof(Flow) + FlowStorageSize(); - (void) SC_ATOMIC_SUB(flow_memuse, size); + (void)SC_ATOMIC_SUB(flow_memuse, size); } /** @@ -169,11 +168,11 @@ void FlowInit(Flow *f, const Packet *p) } if (p->tcph != NULL) { /* XXX MACRO */ - SET_TCP_SRC_PORT(p,&f->sp); - SET_TCP_DST_PORT(p,&f->dp); + SET_TCP_SRC_PORT(p, &f->sp); + SET_TCP_DST_PORT(p, &f->dp); } else if (p->udph != NULL) { /* XXX MACRO */ - SET_UDP_SRC_PORT(p,&f->sp); - SET_UDP_DST_PORT(p,&f->dp); + SET_UDP_SRC_PORT(p, &f->sp); + SET_UDP_DST_PORT(p, &f->dp); } else if (p->icmpv4h != NULL) { f->icmp_s.type = p->icmp_s.type; f->icmp_s.code = p->icmp_s.code; @@ -183,8 +182,8 @@ void FlowInit(Flow *f, const Packet *p) f->icmp_s.code = p->icmp_s.code; FlowSetICMPv6CounterPart(f); } else if (p->sctph != NULL) { /* XXX MACRO */ - SET_SCTP_SRC_PORT(p,&f->sp); - SET_SCTP_DST_PORT(p,&f->dp); + SET_SCTP_SRC_PORT(p, &f->sp); + SET_SCTP_DST_PORT(p, &f->dp); } else if (p->esph != NULL) { f->esp.spi = ESP_GET_SPI(p); } else { @@ -216,7 +215,7 @@ FlowStorageId GetFlowBypassInfoID(void) static void FlowBypassFree(void *x) { - FlowBypassInfo *fb = (FlowBypassInfo *) x; + FlowBypassInfo *fb = (FlowBypassInfo *)x; if (fb == NULL) return; @@ -229,8 +228,7 @@ static void FlowBypassFree(void *x) void RegisterFlowBypassInfo(void) { - g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *), - NULL, FlowBypassFree); + g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *), NULL, FlowBypassFree); } void FlowEndCountersRegister(ThreadVars *t, FlowEndCounters *fec) diff --git a/src/flow-var.c b/src/flow-var.c index a92358f27144..ebfbd7936f20 100644 --- a/src/flow-var.c +++ b/src/flow-var.c @@ -30,7 +30,7 @@ #include "flow-var.h" #include "flow.h" #include "detect.h" -#include "util-debug.h" +#include "util/debug.h" /* puts a new value into a flowvar */ static void FlowVarUpdateStr(FlowVar *fv, uint8_t *value, uint16_t size) @@ -58,7 +58,7 @@ FlowVar *FlowVarGetByKey(Flow *f, const uint8_t *key, uint16_t keylen) GenericVar *gv = f->flowvar; - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWVAR && gv->idx == 0) { FlowVar *fv = (FlowVar *)gv; @@ -82,7 +82,7 @@ FlowVar *FlowVarGet(Flow *f, uint32_t idx) GenericVar *gv = f->flowvar; - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWVAR && gv->idx == idx) return (FlowVar *)gv; } @@ -143,7 +143,7 @@ void FlowVarAddIntNoLock(Flow *f, uint32_t idx, uint32_t value) fv->type = DETECT_FLOWVAR; fv->datatype = FLOWVAR_TYPE_INT; fv->idx = idx; - fv->data.fv_int.value= value; + fv->data.fv_int.value = value; fv->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fv); @@ -201,4 +201,3 @@ void FlowVarPrint(GenericVar *gv) } FlowVarPrint(gv->next); } - diff --git a/src/flow-var.h b/src/flow-var.h index f0bcf3c0c3f6..f43043ffae47 100644 --- a/src/flow-var.h +++ b/src/flow-var.h @@ -26,7 +26,7 @@ #define __FLOW_VAR_H__ #include "flow.h" -#include "util-var.h" +#include "util/var.h" /** Available data types for Flowvars */ @@ -46,13 +46,13 @@ typedef struct FlowVarTypeInt_ { /** Generic Flowvar Structure */ typedef struct FlowVar_ { - uint8_t type; /* type, DETECT_FLOWVAR in this case */ + uint8_t type; /* type, DETECT_FLOWVAR in this case */ uint8_t datatype; uint16_t keylen; - uint32_t idx; /* name idx */ - GenericVar *next; /* right now just implement this as a list, - * in the long run we have think of something - * faster. */ + uint32_t idx; /* name idx */ + GenericVar *next; /* right now just implement this as a list, + * in the long run we have think of something + * faster. */ union { FlowVarTypeStr fv_str; FlowVarTypeInt fv_int; @@ -73,4 +73,3 @@ void FlowVarFree(FlowVar *); void FlowVarPrint(GenericVar *); #endif /* __FLOW_VAR_H__ */ - diff --git a/src/flow-worker.c b/src/flow-worker.c index 6980570d3ce1..d1fdf7481c0c 100644 --- a/src/flow-worker.c +++ b/src/flow-worker.c @@ -41,13 +41,13 @@ #include "stream-tcp.h" #include "app-layer.h" #include "detect-engine.h" -#include "output.h" +#include "output/output.h" #include "app-layer-parser.h" #include "app-layer-frames.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-time.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/time.h" #include "tmqh-packetpool.h" #include "flow-util.h" @@ -73,7 +73,7 @@ typedef struct FlowWorkerThreadData_ { SC_ATOMIC_DECLARE(DetectEngineThreadCtxPtr, detect_thread); - void *output_thread; /* Output thread data. */ + void *output_thread; /* Output thread data. */ void *output_thread_flow; /* Output thread data. */ uint16_t local_bypass_pkts; @@ -162,7 +162,7 @@ static void CheckWorkQueue(ThreadVars *tv, FlowWorkerThreadData *fw, FlowTimeout Flow *f; while ((f = FlowQueuePrivateGetFromTop(fq)) != NULL) { FLOWLOCK_WRLOCK(f); - f->flow_end_flags |= FLOW_END_FLAG_TIMEOUT; //TODO emerg + f->flow_end_flags |= FLOW_END_FLAG_TIMEOUT; // TODO emerg if (f->proto == IPPROTO_TCP) { if (!(f->flags & (FLOW_TIMEOUT_REASSEMBLY_DONE | FLOW_ACTION_DROP)) && @@ -188,7 +188,7 @@ static void CheckWorkQueue(ThreadVars *tv, FlowWorkerThreadData *fw, FlowTimeout } StatsDecr(tv, fw->dtv->counter_flow_active); - FlowClearMemory (f, f->protomap); + FlowClearMemory(f, f->protomap); FLOWLOCK_UNLOCK(f); if (fw->fls.spare_queue.len >= (flow_spare_pool_block_size * 2)) { @@ -341,18 +341,18 @@ static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data) } TmEcode Detect(ThreadVars *tv, Packet *p, void *data); -TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueueNoLock *pq); +TmEcode StreamTcp(ThreadVars *, Packet *, void *, PacketQueueNoLock *pq); -static inline void UpdateCounters(ThreadVars *tv, - FlowWorkerThreadData *fw, const FlowTimeoutCounters *counters) +static inline void UpdateCounters( + ThreadVars *tv, FlowWorkerThreadData *fw, const FlowTimeoutCounters *counters) { if (counters->flows_aside_needs_work) { - StatsAddUI64(tv, fw->cnt.flows_aside_needs_work, - (uint64_t)counters->flows_aside_needs_work); + StatsAddUI64( + tv, fw->cnt.flows_aside_needs_work, (uint64_t)counters->flows_aside_needs_work); } if (counters->flows_aside_pkt_inject) { - StatsAddUI64(tv, fw->cnt.flows_aside_pkt_inject, - (uint64_t)counters->flows_aside_pkt_inject); + StatsAddUI64( + tv, fw->cnt.flows_aside_pkt_inject, (uint64_t)counters->flows_aside_pkt_inject); } } @@ -378,10 +378,10 @@ static inline void FlowWorkerStreamTCPUpdate(ThreadVars *tv, FlowWorkerThreadDat } /* Packets here can safely access p->flow as it's locked */ - SCLogDebug("packet %"PRIu64": extra packets %u", p->pcap_cnt, fw->pq.len); + SCLogDebug("packet %" PRIu64 ": extra packets %u", p->pcap_cnt, fw->pq.len); Packet *x; while ((x = PacketDequeueNoLock(&fw->pq))) { - SCLogDebug("packet %"PRIu64" extra packet %p", p->pcap_cnt, x); + SCLogDebug("packet %" PRIu64 " extra packet %p", p->pcap_cnt, x); if (detect_thread != NULL) { FLOWWORKER_PROFILING_START(x, PROFILE_FLOWWORKER_DETECT); @@ -412,12 +412,13 @@ static inline void FlowWorkerStreamTCPUpdate(ThreadVars *tv, FlowWorkerThreadDat } } -static void FlowWorkerFlowTimeout(ThreadVars *tv, Packet *p, FlowWorkerThreadData *fw, - void *detect_thread) +static void FlowWorkerFlowTimeout( + ThreadVars *tv, Packet *p, FlowWorkerThreadData *fw, void *detect_thread) { DEBUG_VALIDATE_BUG_ON(p->pkt_src != PKT_SRC_FFR); - SCLogDebug("packet %"PRIu64" is TCP. Direction %s", p->pcap_cnt, PKT_IS_TOSERVER(p) ? "TOSERVER" : "TOCLIENT"); + SCLogDebug("packet %" PRIu64 " is TCP. Direction %s", p->pcap_cnt, + PKT_IS_TOSERVER(p) ? "TOSERVER" : "TOCLIENT"); DEBUG_VALIDATE_BUG_ON(!(p->flow && PKT_IS_TCP(p))); DEBUG_ASSERT_FLOW_LOCKED(p->flow); @@ -427,7 +428,7 @@ static void FlowWorkerFlowTimeout(ThreadVars *tv, Packet *p, FlowWorkerThreadDat PacketUpdateEngineEventCounters(tv, fw->dtv, p); /* handle Detect */ - SCLogDebug("packet %"PRIu64" calling Detect", p->pcap_cnt); + SCLogDebug("packet %" PRIu64 " calling Detect", p->pcap_cnt); if (detect_thread != NULL) { FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_DETECT); Detect(tv, p, detect_thread); @@ -441,8 +442,8 @@ static void FlowWorkerFlowTimeout(ThreadVars *tv, Packet *p, FlowWorkerThreadDat /* Release tcp segments. Done here after alerting can use them. */ FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_TCPPRUNE); - StreamTcpPruneSession(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? - STREAM_TOSERVER : STREAM_TOCLIENT); + StreamTcpPruneSession( + p->flow, p->flowflags & FLOW_PKT_TOSERVER ? STREAM_TOSERVER : STREAM_TOCLIENT); FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_TCPPRUNE); /* run tx cleanup last */ @@ -485,7 +486,10 @@ static inline void FlowWorkerProcessLocalFlows(ThreadVars *tv, FlowWorkerThreadD FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_FLOW_EVICTED); if (fw->fls.work_queue.len) { - FlowTimeoutCounters counters = { 0, 0, }; + FlowTimeoutCounters counters = { + 0, + 0, + }; CheckWorkQueue(tv, fw, &counters, &fw->fls.work_queue, max_work); UpdateCounters(tv, fw, &counters); } @@ -538,7 +542,7 @@ static TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data) DEBUG_VALIDATE_BUG_ON(p == NULL); DEBUG_VALIDATE_BUG_ON(tv->flow_queue == NULL); - SCLogDebug("packet %"PRIu64, p->pcap_cnt); + SCLogDebug("packet %" PRIu64, p->pcap_cnt); /* update time */ if (!(PKT_IS_PSEUDOPKT(p))) { @@ -560,14 +564,14 @@ static TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data) FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_FLOW); - /* if PKT_WANTS_FLOW is not set, but PKT_HAS_FLOW is, then this is a - * pseudo packet created by the flow manager. */ + /* if PKT_WANTS_FLOW is not set, but PKT_HAS_FLOW is, then this is a + * pseudo packet created by the flow manager. */ } else if (p->flags & PKT_HAS_FLOW) { FLOWLOCK_WRLOCK(p->flow); DEBUG_VALIDATE_BUG_ON(p->pkt_src != PKT_SRC_FFR); } - SCLogDebug("packet %"PRIu64" has flow? %s", p->pcap_cnt, p->flow ? "yes" : "no"); + SCLogDebug("packet %" PRIu64 " has flow? %s", p->pcap_cnt, p->flow ? "yes" : "no"); /* handle TCP and app layer */ if (p->flow) { @@ -600,7 +604,7 @@ static TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data) /* handle Detect */ DEBUG_ASSERT_FLOW_LOCKED(p->flow); - SCLogDebug("packet %"PRIu64" calling Detect", p->pcap_cnt); + SCLogDebug("packet %" PRIu64 " calling Detect", p->pcap_cnt); if (detect_thread != NULL) { FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_DETECT); Detect(tv, p, detect_thread); @@ -622,8 +626,8 @@ static TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data) } else if (p->proto == IPPROTO_TCP && p->flow->protoctx) { FramesPrune(p->flow, p); FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_TCPPRUNE); - StreamTcpPruneSession(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? - STREAM_TOSERVER : STREAM_TOCLIENT); + StreamTcpPruneSession( + p->flow, p->flowflags & FLOW_PKT_TOSERVER ? STREAM_TOSERVER : STREAM_TOCLIENT); FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_TCPPRUNE); } else if (p->proto == IPPROTO_UDP) { FramesPrune(p->flow, p); @@ -731,7 +735,7 @@ static bool FlowWorkerIsBusy(ThreadVars *tv, void *flow_worker) return false; } -void TmModuleFlowWorkerRegister (void) +void TmModuleFlowWorkerRegister(void) { tmm_modules[TMM_FLOWWORKER].name = "FlowWorker"; tmm_modules[TMM_FLOWWORKER].ThreadInit = FlowWorkerThreadInit; @@ -740,5 +744,5 @@ void TmModuleFlowWorkerRegister (void) tmm_modules[TMM_FLOWWORKER].ThreadDeinit = FlowWorkerThreadDeinit; tmm_modules[TMM_FLOWWORKER].ThreadExitPrintStats = FlowWorkerExitPrintStats; tmm_modules[TMM_FLOWWORKER].cap_flags = 0; - tmm_modules[TMM_FLOWWORKER].flags = TM_FLAG_STREAM_TM|TM_FLAG_DETECT_TM; + tmm_modules[TMM_FLOWWORKER].flags = TM_FLAG_STREAM_TM | TM_FLAG_DETECT_TM; } diff --git a/src/flow-worker.h b/src/flow-worker.h index 9187602dec2c..c233a8cb6912 100644 --- a/src/flow-worker.h +++ b/src/flow-worker.h @@ -33,6 +33,6 @@ const char *ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi); void FlowWorkerReplaceDetectCtx(void *flow_worker, void *detect_ctx); void *FlowWorkerGetDetectCtxPtr(void *flow_worker); -void TmModuleFlowWorkerRegister (void); +void TmModuleFlowWorkerRegister(void); #endif /* __FLOW_WORKER_H__ */ diff --git a/src/flow.c b/src/flow.c index 9783b7883b0b..41f078cd72f0 100644 --- a/src/flow.c +++ b/src/flow.c @@ -34,8 +34,8 @@ #include "tm-threads.h" #include "runmodes.h" -#include "util-random.h" -#include "util-time.h" +#include "util/random.h" +#include "util/time.h" #include "flow.h" #include "flow-queue.h" @@ -53,15 +53,15 @@ #include "stream-tcp-reassemble.h" #include "stream-tcp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" -#include "util-misc.h" -#include "util-macset.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" +#include "util/misc.h" +#include "util/macset.h" -#include "util-debug.h" -#include "util-privs.h" -#include "util-validate.h" +#include "util/debug.h" +#include "util/privs.h" +#include "util/validate.h" #include "detect.h" #include "detect-engine-state.h" @@ -72,12 +72,12 @@ #define FLOW_DEFAULT_EMERGENCY_RECOVERY 30 -//#define FLOW_DEFAULT_HASHSIZE 262144 -#define FLOW_DEFAULT_HASHSIZE 65536 -//#define FLOW_DEFAULT_MEMCAP 128 * 1024 * 1024 /* 128 MB */ -#define FLOW_DEFAULT_MEMCAP (32 * 1024 * 1024) /* 32 MB */ +// #define FLOW_DEFAULT_HASHSIZE 262144 +#define FLOW_DEFAULT_HASHSIZE 65536 +// #define FLOW_DEFAULT_MEMCAP 128 * 1024 * 1024 /* 128 MB */ +#define FLOW_DEFAULT_MEMCAP (32 * 1024 * 1024) /* 32 MB */ -#define FLOW_DEFAULT_PREALLOC 10000 +#define FLOW_DEFAULT_PREALLOC 10000 SC_ATOMIC_DECLARE(FlowProtoTimeoutPtr, flow_timeouts); @@ -155,14 +155,13 @@ void FlowCleanupAppLayer(Flow *f) } /** \brief Set the IPOnly scanned flag for 'direction'. - * - * \param f Flow to set the flag in - * \param direction direction to set the flag in - */ + * + * \param f Flow to set the flag in + * \param direction direction to set the flag in + */ void FlowSetIPOnlyFlag(Flow *f, int direction) { - direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : - (f->flags |= FLOW_TOCLIENT_IPONLY_SET); + direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : (f->flags |= FLOW_TOCLIENT_IPONLY_SET); return; } @@ -286,7 +285,7 @@ void FlowSwap(Flow *f) f->flags |= FLOW_DIR_REVERSED; SWAP_VARS(uint32_t, f->probing_parser_toserver_alproto_masks, - f->probing_parser_toclient_alproto_masks); + f->probing_parser_toclient_alproto_masks); FlowSwapFlags(f); FlowSwapFileFlags(f); @@ -317,23 +316,23 @@ int FlowGetPacketDirection(const Flow *f, const Packet *p) const int reverse = (f->flags & FLOW_DIR_REVERSED) != 0; if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { - if (!(CMP_PORT(p->sp,p->dp))) { + if (!(CMP_PORT(p->sp, p->dp))) { /* update flags and counters */ - if (CMP_PORT(f->sp,p->sp)) { + if (CMP_PORT(f->sp, p->sp)) { return TOSERVER ^ reverse; } else { return TOCLIENT ^ reverse; } } else { - if (CMP_ADDR(&f->src,&p->src)) { + if (CMP_ADDR(&f->src, &p->src)) { return TOSERVER ^ reverse; } else { return TOCLIENT ^ reverse; } } } else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) { - if (CMP_ADDR(&f->src,&p->src)) { - return TOSERVER ^ reverse; + if (CMP_ADDR(&f->src, &p->src)) { + return TOSERVER ^ reverse; } else { return TOCLIENT ^ reverse; } @@ -382,20 +381,18 @@ static inline void FlowUpdateTtlTC(Flow *f, Packet *p, uint8_t ttl) f->max_ttl_toclient = MAX(f->max_ttl_toclient, ttl); } -static inline void FlowUpdateEthernet(ThreadVars *tv, DecodeThreadVars *dtv, - Flow *f, EthernetHdr *ethh, bool toserver) +static inline void FlowUpdateEthernet( + ThreadVars *tv, DecodeThreadVars *dtv, Flow *f, EthernetHdr *ethh, bool toserver) { if (ethh && MacSetFlowStorageEnabled()) { MacSet *ms = FlowGetStorageById(f, MacSetGetFlowStorageID()); if (ms != NULL) { if (toserver) { MacSetAddWithCtr(ms, ethh->eth_src, ethh->eth_dst, tv, - dtv->counter_max_mac_addrs_src, - dtv->counter_max_mac_addrs_dst); + dtv->counter_max_mac_addrs_src, dtv->counter_max_mac_addrs_dst); } else { MacSetAddWithCtr(ms, ethh->eth_dst, ethh->eth_src, tv, - dtv->counter_max_mac_addrs_dst, - dtv->counter_max_mac_addrs_src); + dtv->counter_max_mac_addrs_dst, dtv->counter_max_mac_addrs_src); } } } @@ -412,7 +409,7 @@ static inline void FlowUpdateEthernet(ThreadVars *tv, DecodeThreadVars *dtv, */ void FlowHandlePacketUpdate(Flow *f, Packet *p, ThreadVars *tv, DecodeThreadVars *dtv) { - SCLogDebug("packet %"PRIu64" -- flow %p", p->pcap_cnt, f); + SCLogDebug("packet %" PRIu64 " -- flow %p", p->pcap_cnt, f); const int pkt_dir = FlowGetPacketDirection(f, p); #ifdef CAPTURE_OFFLOAD @@ -500,8 +497,8 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p, ThreadVars *tv, DecodeThreadVars if (ssn != NULL && ssn->state >= TCP_ESTABLISHED) { p->flowflags |= FLOW_PKT_ESTABLISHED; } - } else if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == - (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) { + } else if ((f->flags & (FLOW_TO_DST_SEEN | FLOW_TO_SRC_SEEN)) == + (FLOW_TO_DST_SEEN | FLOW_TO_SRC_SEEN)) { SCLogDebug("pkt %p FLOW_PKT_ESTABLISHED", p); p->flowflags |= FLOW_PKT_ESTABLISHED; @@ -550,7 +547,7 @@ void FlowInitConfig(bool quiet) { SCLogDebug("initializing flow engine..."); - memset(&flow_config, 0, sizeof(flow_config)); + memset(&flow_config, 0, sizeof(flow_config)); SC_ATOMIC_INIT(flow_flags); SC_ATOMIC_INIT(flow_memuse); SC_ATOMIC_INIT(flow_prune_idx); @@ -558,9 +555,9 @@ void FlowInitConfig(bool quiet) FlowQueueInit(&flow_recycle_q); /* set defaults */ - flow_config.hash_rand = (uint32_t)RandomGet(); - flow_config.hash_size = FLOW_DEFAULT_HASHSIZE; - flow_config.prealloc = FLOW_DEFAULT_PREALLOC; + flow_config.hash_rand = (uint32_t)RandomGet(); + flow_config.hash_size = FLOW_DEFAULT_HASHSIZE; + flow_config.prealloc = FLOW_DEFAULT_PREALLOC; SC_ATOMIC_SET(flow_config.memcap, FLOW_DEFAULT_MEMCAP); /* If we have specific config, overwrite the defaults with them, @@ -585,8 +582,7 @@ void FlowInitConfig(bool quiet) /** set config values for memcap, prealloc and hash_size */ uint64_t flow_memcap_copy = 0; - if ((ConfGet("flow.memcap", &conf_val)) == 1) - { + if ((ConfGet("flow.memcap", &conf_val)) == 1) { if (conf_val == NULL) { FatalError("Invalid value for flow.memcap: NULL"); } @@ -600,8 +596,7 @@ void FlowInitConfig(bool quiet) SC_ATOMIC_SET(flow_config.memcap, flow_memcap_copy); } } - if ((ConfGet("flow.hash-size", &conf_val)) == 1) - { + if ((ConfGet("flow.hash-size", &conf_val)) == 1) { if (conf_val == NULL) { FatalError("Invalid value for flow.hash-size: NULL"); } @@ -613,23 +608,21 @@ void FlowInitConfig(bool quiet) "1-4294967295"); } } - if ((ConfGet("flow.prealloc", &conf_val)) == 1) - { + if ((ConfGet("flow.prealloc", &conf_val)) == 1) { if (conf_val == NULL) { FatalError("Invalid value for flow.prealloc: NULL"); } - if (StringParseUint32(&configval, 10, strlen(conf_val), - conf_val) > 0) { + if (StringParseUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { flow_config.prealloc = configval; } } flow_config.memcap_policy = ExceptionPolicyParse("flow.memcap-policy", false); - SCLogDebug("Flow config from suricata.yaml: memcap: %"PRIu64", hash-size: " - "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(flow_config.memcap), - flow_config.hash_size, flow_config.prealloc); + SCLogDebug("Flow config from suricata.yaml: memcap: %" PRIu64 ", hash-size: " + "%" PRIu32 ", prealloc: %" PRIu32, + SC_ATOMIC_GET(flow_config.memcap), flow_config.hash_size, flow_config.prealloc); /* alloc hash memory */ uint64_t hash_size = flow_config.hash_size * sizeof(FlowBucket); @@ -653,17 +646,16 @@ void FlowInitConfig(bool quiet) FBLOCK_INIT(&flow_hash[i]); SC_ATOMIC_INIT(flow_hash[i].next_ts); } - (void) SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket))); + (void)SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket))); if (!quiet) { - SCLogConfig("allocated %"PRIu64" bytes of memory for the flow hash... " - "%" PRIu32 " buckets of size %" PRIuMAX "", - SC_ATOMIC_GET(flow_memuse), flow_config.hash_size, - (uintmax_t)sizeof(FlowBucket)); + SCLogConfig("allocated %" PRIu64 " bytes of memory for the flow hash... " + "%" PRIu32 " buckets of size %" PRIuMAX "", + SC_ATOMIC_GET(flow_memuse), flow_config.hash_size, (uintmax_t)sizeof(FlowBucket)); } FlowSparePoolInit(); if (!quiet) { - SCLogConfig("flow memory usage: %"PRIu64" bytes, maximum: %"PRIu64, + SCLogConfig("flow memory usage: %" PRIu64 " bytes, maximum: %" PRIu64, SC_ATOMIC_GET(flow_memuse), SC_ATOMIC_GET(flow_config.memcap)); } @@ -727,7 +719,7 @@ void FlowShutdown(void) SCFreeAligned(flow_hash); flow_hash = NULL; } - (void) SC_ATOMIC_SUB(flow_memuse, flow_config.hash_size * sizeof(FlowBucket)); + (void)SC_ATOMIC_SUB(flow_memuse, flow_config.hash_size * sizeof(FlowBucket)); FlowQueueDestroy(&flow_recycle_q); FlowSparePoolDestroy(); return; @@ -742,36 +734,29 @@ void FlowInitFlowProto(void) { FlowTimeoutsInit(); -#define SET_DEFAULTS(p, n, e, c, b, ne, ee, ce, be) \ - flow_timeouts_normal[(p)].new_timeout = (n); \ - flow_timeouts_normal[(p)].est_timeout = (e); \ - flow_timeouts_normal[(p)].closed_timeout = (c); \ - flow_timeouts_normal[(p)].bypassed_timeout = (b); \ - flow_timeouts_emerg[(p)].new_timeout = (ne); \ - flow_timeouts_emerg[(p)].est_timeout = (ee); \ - flow_timeouts_emerg[(p)].closed_timeout = (ce); \ - flow_timeouts_emerg[(p)].bypassed_timeout = (be); \ - - SET_DEFAULTS(FLOW_PROTO_DEFAULT, - FLOW_DEFAULT_NEW_TIMEOUT, FLOW_DEFAULT_EST_TIMEOUT, - 0, FLOW_DEFAULT_BYPASSED_TIMEOUT, - FLOW_DEFAULT_EMERG_NEW_TIMEOUT, FLOW_DEFAULT_EMERG_EST_TIMEOUT, - 0, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); - SET_DEFAULTS(FLOW_PROTO_TCP, - FLOW_IPPROTO_TCP_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EST_TIMEOUT, - FLOW_IPPROTO_TCP_CLOSED_TIMEOUT, FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT, - FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT, - FLOW_IPPROTO_TCP_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); - SET_DEFAULTS(FLOW_PROTO_UDP, - FLOW_IPPROTO_UDP_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EST_TIMEOUT, - 0, FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT, - FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT, - 0, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); - SET_DEFAULTS(FLOW_PROTO_ICMP, - FLOW_IPPROTO_ICMP_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EST_TIMEOUT, - 0, FLOW_IPPROTO_ICMP_BYPASSED_TIMEOUT, - FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT, - 0, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); +#define SET_DEFAULTS(p, n, e, c, b, ne, ee, ce, be) \ + flow_timeouts_normal[(p)].new_timeout = (n); \ + flow_timeouts_normal[(p)].est_timeout = (e); \ + flow_timeouts_normal[(p)].closed_timeout = (c); \ + flow_timeouts_normal[(p)].bypassed_timeout = (b); \ + flow_timeouts_emerg[(p)].new_timeout = (ne); \ + flow_timeouts_emerg[(p)].est_timeout = (ee); \ + flow_timeouts_emerg[(p)].closed_timeout = (ce); \ + flow_timeouts_emerg[(p)].bypassed_timeout = (be); + + SET_DEFAULTS(FLOW_PROTO_DEFAULT, FLOW_DEFAULT_NEW_TIMEOUT, FLOW_DEFAULT_EST_TIMEOUT, 0, + FLOW_DEFAULT_BYPASSED_TIMEOUT, FLOW_DEFAULT_EMERG_NEW_TIMEOUT, + FLOW_DEFAULT_EMERG_EST_TIMEOUT, 0, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_TCP, FLOW_IPPROTO_TCP_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EST_TIMEOUT, + FLOW_IPPROTO_TCP_CLOSED_TIMEOUT, FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT, + FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT, + FLOW_IPPROTO_TCP_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_UDP, FLOW_IPPROTO_UDP_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EST_TIMEOUT, 0, + FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT, FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT, + FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT, 0, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_ICMP, FLOW_IPPROTO_ICMP_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EST_TIMEOUT, 0, + FLOW_IPPROTO_ICMP_BYPASSED_TIMEOUT, FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT, + FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT, 0, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); flow_freefuncs[FLOW_PROTO_DEFAULT].Freefunc = NULL; flow_freefuncs[FLOW_PROTO_TCP].Freefunc = NULL; @@ -801,61 +786,48 @@ void FlowInitFlowProto(void) closed = ConfNodeLookupChildValue(proto, "closed"); bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); - emergency_established = ConfNodeLookupChildValue(proto, - "emergency-established"); - emergency_closed = ConfNodeLookupChildValue(proto, - "emergency-closed"); - emergency_bypassed = ConfNodeLookupChildValue(proto, - "emergency-bypassed"); + emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); + emergency_bypassed = ConfNodeLookupChildValue(proto, "emergency-bypassed"); - if (new != NULL && - StringParseUint32(&configval, 10, strlen(new), new) > 0) { + if (new != NULL && StringParseUint32(&configval, 10, strlen(new), new) > 0) { - flow_timeouts_normal[FLOW_PROTO_DEFAULT].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_DEFAULT].new_timeout = configval; } if (established != NULL && - StringParseUint32(&configval, 10, strlen(established), - established) > 0) { + StringParseUint32(&configval, 10, strlen(established), established) > 0) { flow_timeouts_normal[FLOW_PROTO_DEFAULT].est_timeout = configval; } - if (closed != NULL && - StringParseUint32(&configval, 10, strlen(closed), - closed) > 0) { + if (closed != NULL && StringParseUint32(&configval, 10, strlen(closed), closed) > 0) { flow_timeouts_normal[FLOW_PROTO_DEFAULT].closed_timeout = configval; } if (bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(bypassed), - bypassed) > 0) { + StringParseUint32(&configval, 10, strlen(bypassed), bypassed) > 0) { flow_timeouts_normal[FLOW_PROTO_DEFAULT].bypassed_timeout = configval; } if (emergency_new != NULL && - StringParseUint32(&configval, 10, strlen(emergency_new), - emergency_new) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_timeouts_emerg[FLOW_PROTO_DEFAULT].new_timeout = configval; } if (emergency_established != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_established), - emergency_established) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_established), + emergency_established) > 0) { - flow_timeouts_emerg[FLOW_PROTO_DEFAULT].est_timeout= configval; + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].est_timeout = configval; } if (emergency_closed != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_closed), - emergency_closed) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > + 0) { flow_timeouts_emerg[FLOW_PROTO_DEFAULT].closed_timeout = configval; } if (emergency_bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_bypassed), - emergency_bypassed) > 0) { + StringParseUint32( + &configval, 10, strlen(emergency_bypassed), emergency_bypassed) > 0) { flow_timeouts_emerg[FLOW_PROTO_DEFAULT].bypassed_timeout = configval; } @@ -869,61 +841,48 @@ void FlowInitFlowProto(void) closed = ConfNodeLookupChildValue(proto, "closed"); bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); - emergency_established = ConfNodeLookupChildValue(proto, - "emergency-established"); - emergency_closed = ConfNodeLookupChildValue(proto, - "emergency-closed"); - emergency_bypassed = ConfNodeLookupChildValue(proto, - "emergency-bypassed"); + emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); + emergency_bypassed = ConfNodeLookupChildValue(proto, "emergency-bypassed"); - if (new != NULL && - StringParseUint32(&configval, 10, strlen(new), new) > 0) { + if (new != NULL && StringParseUint32(&configval, 10, strlen(new), new) > 0) { flow_timeouts_normal[FLOW_PROTO_TCP].new_timeout = configval; } if (established != NULL && - StringParseUint32(&configval, 10, strlen(established), - established) > 0) { + StringParseUint32(&configval, 10, strlen(established), established) > 0) { flow_timeouts_normal[FLOW_PROTO_TCP].est_timeout = configval; } - if (closed != NULL && - StringParseUint32(&configval, 10, strlen(closed), - closed) > 0) { + if (closed != NULL && StringParseUint32(&configval, 10, strlen(closed), closed) > 0) { flow_timeouts_normal[FLOW_PROTO_TCP].closed_timeout = configval; } if (bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(bypassed), - bypassed) > 0) { + StringParseUint32(&configval, 10, strlen(bypassed), bypassed) > 0) { flow_timeouts_normal[FLOW_PROTO_TCP].bypassed_timeout = configval; } if (emergency_new != NULL && - StringParseUint32(&configval, 10, strlen(emergency_new), - emergency_new) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_timeouts_emerg[FLOW_PROTO_TCP].new_timeout = configval; } if (emergency_established != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_established), - emergency_established) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_established), + emergency_established) > 0) { flow_timeouts_emerg[FLOW_PROTO_TCP].est_timeout = configval; } if (emergency_closed != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_closed), - emergency_closed) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > + 0) { flow_timeouts_emerg[FLOW_PROTO_TCP].closed_timeout = configval; } if (emergency_bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_bypassed), - emergency_bypassed) > 0) { + StringParseUint32( + &configval, 10, strlen(emergency_bypassed), emergency_bypassed) > 0) { flow_timeouts_emerg[FLOW_PROTO_TCP].bypassed_timeout = configval; } @@ -936,46 +895,37 @@ void FlowInitFlowProto(void) established = ConfNodeLookupChildValue(proto, "established"); bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); - emergency_established = ConfNodeLookupChildValue(proto, - "emergency-established"); - emergency_bypassed = ConfNodeLookupChildValue(proto, - "emergency-bypassed"); + emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_bypassed = ConfNodeLookupChildValue(proto, "emergency-bypassed"); - if (new != NULL && - StringParseUint32(&configval, 10, strlen(new), new) > 0) { + if (new != NULL && StringParseUint32(&configval, 10, strlen(new), new) > 0) { flow_timeouts_normal[FLOW_PROTO_UDP].new_timeout = configval; } if (established != NULL && - StringParseUint32(&configval, 10, strlen(established), - established) > 0) { + StringParseUint32(&configval, 10, strlen(established), established) > 0) { flow_timeouts_normal[FLOW_PROTO_UDP].est_timeout = configval; } if (bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(bypassed), - bypassed) > 0) { + StringParseUint32(&configval, 10, strlen(bypassed), bypassed) > 0) { flow_timeouts_normal[FLOW_PROTO_UDP].bypassed_timeout = configval; } if (emergency_new != NULL && - StringParseUint32(&configval, 10, strlen(emergency_new), - emergency_new) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_timeouts_emerg[FLOW_PROTO_UDP].new_timeout = configval; } if (emergency_established != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_established), - emergency_established) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_established), + emergency_established) > 0) { flow_timeouts_emerg[FLOW_PROTO_UDP].est_timeout = configval; } if (emergency_bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_bypassed), - emergency_bypassed) > 0) { + StringParseUint32( + &configval, 10, strlen(emergency_bypassed), emergency_bypassed) > 0) { flow_timeouts_emerg[FLOW_PROTO_UDP].bypassed_timeout = configval; } @@ -988,46 +938,37 @@ void FlowInitFlowProto(void) established = ConfNodeLookupChildValue(proto, "established"); bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); - emergency_established = ConfNodeLookupChildValue(proto, - "emergency-established"); - emergency_bypassed = ConfNodeLookupChildValue(proto, - "emergency-bypassed"); + emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_bypassed = ConfNodeLookupChildValue(proto, "emergency-bypassed"); - if (new != NULL && - StringParseUint32(&configval, 10, strlen(new), new) > 0) { + if (new != NULL && StringParseUint32(&configval, 10, strlen(new), new) > 0) { flow_timeouts_normal[FLOW_PROTO_ICMP].new_timeout = configval; } if (established != NULL && - StringParseUint32(&configval, 10, strlen(established), - established) > 0) { + StringParseUint32(&configval, 10, strlen(established), established) > 0) { flow_timeouts_normal[FLOW_PROTO_ICMP].est_timeout = configval; } if (bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(bypassed), - bypassed) > 0) { + StringParseUint32(&configval, 10, strlen(bypassed), bypassed) > 0) { flow_timeouts_normal[FLOW_PROTO_ICMP].bypassed_timeout = configval; } if (emergency_new != NULL && - StringParseUint32(&configval, 10, strlen(emergency_new), - emergency_new) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { flow_timeouts_emerg[FLOW_PROTO_ICMP].new_timeout = configval; } if (emergency_established != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_established), - emergency_established) > 0) { + StringParseUint32(&configval, 10, strlen(emergency_established), + emergency_established) > 0) { flow_timeouts_emerg[FLOW_PROTO_ICMP].est_timeout = configval; } if (emergency_bypassed != NULL && - StringParseUint32(&configval, 10, - strlen(emergency_bypassed), - emergency_bypassed) > 0) { + StringParseUint32( + &configval, 10, strlen(emergency_bypassed), emergency_bypassed) > 0) { flow_timeouts_emerg[FLOW_PROTO_ICMP].bypassed_timeout = configval; } @@ -1097,8 +1038,8 @@ void FlowInitFlowProto(void) } d->bypassed_timeout = n->bypassed_timeout - e->bypassed_timeout; - SCLogDebug("deltas: new: -%u est: -%u closed: -%u bypassed: -%u", - d->new_timeout, d->est_timeout, d->closed_timeout, d->bypassed_timeout); + SCLogDebug("deltas: new: -%u est: -%u closed: -%u bypassed: -%u", d->new_timeout, + d->est_timeout, d->closed_timeout, d->bypassed_timeout); } return; @@ -1112,7 +1053,7 @@ void FlowInitFlowProto(void) * \param proto_map mapped value of the protocol to FLOW_PROTO's. */ -int FlowClearMemory(Flow* f, uint8_t proto_map) +int FlowClearMemory(Flow *f, uint8_t proto_map) { SCEnter(); @@ -1140,7 +1081,7 @@ int FlowClearMemory(Flow* f, uint8_t proto_map) * specific memory. */ -int FlowSetProtoFreeFunc (uint8_t proto, void (*Free)(void *)) +int FlowSetProtoFreeFunc(uint8_t proto, void (*Free)(void *)) { uint8_t proto_map; proto_map = FlowGetProtoMapping(proto); @@ -1261,7 +1202,7 @@ uint32_t FlowGetFlags(Flow *flow) * \retval On success it returns 1 and on failure 0. */ -static int FlowTest01 (void) +static int FlowTest01(void) { uint8_t proto_map; @@ -1295,7 +1236,9 @@ static int FlowTest01 (void) /*Test function for the unit test FlowTest02*/ -static void test(void *f) {} +static void test(void *f) +{ +} /** * \test Test the setting of the per protocol free function to free the @@ -1304,7 +1247,7 @@ static void test(void *f) {} * \retval On success it returns 1 and on failure 0. */ -static int FlowTest02 (void) +static int FlowTest02(void) { FlowSetProtoFreeFunc(IPPROTO_DCCP, test); FlowSetProtoFreeFunc(IPPROTO_TCP, test); @@ -1326,7 +1269,7 @@ static int FlowTest02 (void) * \retval On success it returns 1 and on failure 0. */ -static int FlowTest07 (void) +static int FlowTest07(void) { int result = 0; FlowInitConfig(FLOW_QUIET); @@ -1372,7 +1315,7 @@ static int FlowTest07 (void) * \retval On success it returns 1 and on failure 0. */ -static int FlowTest08 (void) +static int FlowTest08(void) { int result = 0; @@ -1419,7 +1362,7 @@ static int FlowTest08 (void) * \retval On success it returns 1 and on failure 0. */ -static int FlowTest09 (void) +static int FlowTest09(void) { int result = 0; @@ -1463,18 +1406,14 @@ static int FlowTest09 (void) /** * \brief Function to register the Flow Unitests. */ -void FlowRegisterTests (void) +void FlowRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("FlowTest01 -- Protocol Specific Timeouts", FlowTest01); - UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", - FlowTest02); - UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", - FlowTest07); - UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", - FlowTest08); - UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", - FlowTest09); + UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", FlowTest02); + UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", FlowTest07); + UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", FlowTest08); + UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", FlowTest09); RegisterFlowStorageTests(); #endif /* UNITTESTS */ diff --git a/src/flow.h b/src/flow.h index c7b5867ea896..3f411d8ae778 100644 --- a/src/flow.h +++ b/src/flow.h @@ -28,10 +28,10 @@ typedef struct FlowStorageId FlowStorageId; #include "decode.h" -#include "util-time.h" -#include "util-exception-policy.h" -#include "util-var.h" -#include "util-optimize.h" +#include "util/time.h" +#include "util/exception-policy.h" +#include "util/var.h" +#include "util/optimize.h" #include "app-layer-protos.h" /* Part of the flow structure, so we declare it here. @@ -46,68 +46,68 @@ typedef struct AppLayerParserState_ AppLayerParserState; /* per flow flags */ /** At least one packet from the source address was seen */ -#define FLOW_TO_SRC_SEEN BIT_U32(0) +#define FLOW_TO_SRC_SEEN BIT_U32(0) /** At least one packet from the destination address was seen */ -#define FLOW_TO_DST_SEEN BIT_U32(1) +#define FLOW_TO_DST_SEEN BIT_U32(1) // vacancy /** Flow was inspected against IP-Only sigs in the toserver direction */ -#define FLOW_TOSERVER_IPONLY_SET BIT_U32(3) +#define FLOW_TOSERVER_IPONLY_SET BIT_U32(3) /** Flow was inspected against IP-Only sigs in the toclient direction */ -#define FLOW_TOCLIENT_IPONLY_SET BIT_U32(4) +#define FLOW_TOCLIENT_IPONLY_SET BIT_U32(4) /** Packet belonging to this flow should not be inspected at all */ -#define FLOW_NOPACKET_INSPECTION BIT_U32(5) +#define FLOW_NOPACKET_INSPECTION BIT_U32(5) /** Packet payloads belonging to this flow should not be inspected */ -#define FLOW_NOPAYLOAD_INSPECTION BIT_U32(6) +#define FLOW_NOPAYLOAD_INSPECTION BIT_U32(6) /** All packets in this flow should be dropped */ -#define FLOW_ACTION_DROP BIT_U32(7) +#define FLOW_ACTION_DROP BIT_U32(7) /** Sgh for toserver direction set (even if it's NULL) */ -#define FLOW_SGH_TOSERVER BIT_U32(8) +#define FLOW_SGH_TOSERVER BIT_U32(8) /** Sgh for toclient direction set (even if it's NULL) */ -#define FLOW_SGH_TOCLIENT BIT_U32(9) +#define FLOW_SGH_TOCLIENT BIT_U32(9) /** packet to server direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10) +#define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10) /** packet to client direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11) +#define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11) /** flow has alerts */ -#define FLOW_HAS_ALERTS BIT_U32(12) +#define FLOW_HAS_ALERTS BIT_U32(12) /** Pattern matcher alproto detection done */ -#define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13) +#define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13) /** Probing parser alproto detection done */ -#define FLOW_TS_PP_ALPROTO_DETECT_DONE BIT_U32(14) +#define FLOW_TS_PP_ALPROTO_DETECT_DONE BIT_U32(14) /** Expectation alproto detection done */ -#define FLOW_TS_PE_ALPROTO_DETECT_DONE BIT_U32(15) +#define FLOW_TS_PE_ALPROTO_DETECT_DONE BIT_U32(15) /** Pattern matcher alproto detection done */ -#define FLOW_TC_PM_ALPROTO_DETECT_DONE BIT_U32(16) +#define FLOW_TC_PM_ALPROTO_DETECT_DONE BIT_U32(16) /** Probing parser alproto detection done */ -#define FLOW_TC_PP_ALPROTO_DETECT_DONE BIT_U32(17) +#define FLOW_TC_PP_ALPROTO_DETECT_DONE BIT_U32(17) /** Expectation alproto detection done */ -#define FLOW_TC_PE_ALPROTO_DETECT_DONE BIT_U32(18) -#define FLOW_TIMEOUT_REASSEMBLY_DONE BIT_U32(19) +#define FLOW_TC_PE_ALPROTO_DETECT_DONE BIT_U32(18) +#define FLOW_TIMEOUT_REASSEMBLY_DONE BIT_U32(19) /** flow is ipv4 */ -#define FLOW_IPV4 BIT_U32(20) +#define FLOW_IPV4 BIT_U32(20) /** flow is ipv6 */ -#define FLOW_IPV6 BIT_U32(21) +#define FLOW_IPV6 BIT_U32(21) -#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(22) -#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(23) +#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(22) +#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(23) /** Indicate that alproto detection for flow should be done again */ -#define FLOW_CHANGE_PROTO BIT_U32(24) +#define FLOW_CHANGE_PROTO BIT_U32(24) -#define FLOW_WRONG_THREAD BIT_U32(25) +#define FLOW_WRONG_THREAD BIT_U32(25) /** Protocol detection told us flow is picked up in wrong direction (midstream) */ -#define FLOW_DIR_REVERSED BIT_U32(26) +#define FLOW_DIR_REVERSED BIT_U32(26) /** Indicate that the flow did trigger an expectation creation */ -#define FLOW_HAS_EXPECTATION BIT_U32(27) +#define FLOW_HAS_EXPECTATION BIT_U32(27) /** All packets in this flow should be passed */ #define FLOW_ACTION_PASS BIT_U32(28) @@ -117,69 +117,61 @@ typedef struct AppLayerParserState_ AppLayerParserState; /* File flags */ -#define FLOWFILE_INIT 0 +#define FLOWFILE_INIT 0 /** no magic on files in this flow */ -#define FLOWFILE_NO_MAGIC_TS BIT_U16(0) -#define FLOWFILE_NO_MAGIC_TC BIT_U16(1) +#define FLOWFILE_NO_MAGIC_TS BIT_U16(0) +#define FLOWFILE_NO_MAGIC_TC BIT_U16(1) /** even if the flow has files, don't store 'm */ -#define FLOWFILE_NO_STORE_TS BIT_U16(2) -#define FLOWFILE_NO_STORE_TC BIT_U16(3) +#define FLOWFILE_NO_STORE_TS BIT_U16(2) +#define FLOWFILE_NO_STORE_TC BIT_U16(3) /** no md5 on files in this flow */ -#define FLOWFILE_NO_MD5_TS BIT_U16(4) -#define FLOWFILE_NO_MD5_TC BIT_U16(5) +#define FLOWFILE_NO_MD5_TS BIT_U16(4) +#define FLOWFILE_NO_MD5_TC BIT_U16(5) /** no sha1 on files in this flow */ -#define FLOWFILE_NO_SHA1_TS BIT_U16(6) -#define FLOWFILE_NO_SHA1_TC BIT_U16(7) +#define FLOWFILE_NO_SHA1_TS BIT_U16(6) +#define FLOWFILE_NO_SHA1_TC BIT_U16(7) /** no sha256 on files in this flow */ -#define FLOWFILE_NO_SHA256_TS BIT_U16(8) -#define FLOWFILE_NO_SHA256_TC BIT_U16(9) +#define FLOWFILE_NO_SHA256_TS BIT_U16(8) +#define FLOWFILE_NO_SHA256_TC BIT_U16(9) /** no size tracking of files in this flow */ -#define FLOWFILE_NO_SIZE_TS BIT_U16(10) -#define FLOWFILE_NO_SIZE_TC BIT_U16(11) +#define FLOWFILE_NO_SIZE_TS BIT_U16(10) +#define FLOWFILE_NO_SIZE_TC BIT_U16(11) /** store all files in the flow */ #define FLOWFILE_STORE BIT_U16(12) -#define FLOWFILE_NONE_TS (FLOWFILE_NO_MAGIC_TS | \ - FLOWFILE_NO_STORE_TS | \ - FLOWFILE_NO_MD5_TS | \ - FLOWFILE_NO_SHA1_TS | \ - FLOWFILE_NO_SHA256_TS| \ - FLOWFILE_NO_SIZE_TS) -#define FLOWFILE_NONE_TC (FLOWFILE_NO_MAGIC_TC | \ - FLOWFILE_NO_STORE_TC | \ - FLOWFILE_NO_MD5_TC | \ - FLOWFILE_NO_SHA1_TC | \ - FLOWFILE_NO_SHA256_TC| \ - FLOWFILE_NO_SIZE_TC) -#define FLOWFILE_NONE (FLOWFILE_NONE_TS|FLOWFILE_NONE_TC) - -#define FLOW_IS_IPV4(f) \ - (((f)->flags & FLOW_IPV4) == FLOW_IPV4) -#define FLOW_IS_IPV6(f) \ - (((f)->flags & FLOW_IPV6) == FLOW_IPV6) - -#define FLOW_GET_SP(f) \ - ((f)->flags & FLOW_DIR_REVERSED) ? (f)->dp : (f)->sp; -#define FLOW_GET_DP(f) \ - ((f)->flags & FLOW_DIR_REVERSED) ? (f)->sp : (f)->dp; - -#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa) do { \ - (pa)->family = AF_INET; \ - (pa)->addr_data32[0] = (fa)->addr_data32[0]; \ +#define FLOWFILE_NONE_TS \ + (FLOWFILE_NO_MAGIC_TS | FLOWFILE_NO_STORE_TS | FLOWFILE_NO_MD5_TS | FLOWFILE_NO_SHA1_TS | \ + FLOWFILE_NO_SHA256_TS | FLOWFILE_NO_SIZE_TS) +#define FLOWFILE_NONE_TC \ + (FLOWFILE_NO_MAGIC_TC | FLOWFILE_NO_STORE_TC | FLOWFILE_NO_MD5_TC | FLOWFILE_NO_SHA1_TC | \ + FLOWFILE_NO_SHA256_TC | FLOWFILE_NO_SIZE_TC) +#define FLOWFILE_NONE (FLOWFILE_NONE_TS | FLOWFILE_NONE_TC) + +#define FLOW_IS_IPV4(f) (((f)->flags & FLOW_IPV4) == FLOW_IPV4) +#define FLOW_IS_IPV6(f) (((f)->flags & FLOW_IPV6) == FLOW_IPV6) + +#define FLOW_GET_SP(f) ((f)->flags & FLOW_DIR_REVERSED) ? (f)->dp : (f)->sp; +#define FLOW_GET_DP(f) ((f)->flags & FLOW_DIR_REVERSED) ? (f)->sp : (f)->dp; + +#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa) \ + do { \ + (pa)->family = AF_INET; \ + (pa)->addr_data32[0] = (fa)->addr_data32[0]; \ } while (0) -#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa) do { \ - (pa)->family = AF_INET6; \ - (pa)->addr_data32[0] = (fa)->addr_data32[0]; \ - (pa)->addr_data32[1] = (fa)->addr_data32[1]; \ - (pa)->addr_data32[2] = (fa)->addr_data32[2]; \ - (pa)->addr_data32[3] = (fa)->addr_data32[3]; \ +#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa) \ + do { \ + (pa)->family = AF_INET6; \ + (pa)->addr_data32[0] = (fa)->addr_data32[0]; \ + (pa)->addr_data32[1] = (fa)->addr_data32[1]; \ + (pa)->addr_data32[2] = (fa)->addr_data32[2]; \ + (pa)->addr_data32[3] = (fa)->addr_data32[3]; \ } while (0) /* Set the IPv4 addressesinto the Addrs of the Packet. @@ -187,47 +179,51 @@ typedef struct AppLayerParserState_ AppLayerParserState; * * We set the rest of the struct to 0 so we can * prevent using memset. */ -#define FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a) do { \ - (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \ - (a)->addr_data32[1] = 0; \ - (a)->addr_data32[2] = 0; \ - (a)->addr_data32[3] = 0; \ +#define FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a) \ + do { \ + (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \ + (a)->addr_data32[1] = 0; \ + (a)->addr_data32[2] = 0; \ + (a)->addr_data32[3] = 0; \ } while (0) -#define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a) do { \ - (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \ - (a)->addr_data32[1] = 0; \ - (a)->addr_data32[2] = 0; \ - (a)->addr_data32[3] = 0; \ +#define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a) \ + do { \ + (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \ + (a)->addr_data32[1] = 0; \ + (a)->addr_data32[2] = 0; \ + (a)->addr_data32[3] = 0; \ } while (0) /* Set the IPv6 addressesinto the Addrs of the Packet. * Make sure p->ip6h is initialized and validated. */ -#define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a) do { \ - (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \ - (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \ - (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \ - (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \ +#define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a) \ + do { \ + (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \ + (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \ + (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \ + (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \ } while (0) -#define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a) do { \ - (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \ - (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \ - (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \ - (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \ +#define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a) \ + do { \ + (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \ + (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \ + (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \ + (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \ } while (0) /* pkt flow flags */ -#define FLOW_PKT_TOSERVER 0x01 -#define FLOW_PKT_TOCLIENT 0x02 -#define FLOW_PKT_ESTABLISHED 0x04 -#define FLOW_PKT_TOSERVER_IPONLY_SET 0x08 -#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10 -#define FLOW_PKT_TOSERVER_FIRST 0x20 -#define FLOW_PKT_TOCLIENT_FIRST 0x40 +#define FLOW_PKT_TOSERVER 0x01 +#define FLOW_PKT_TOCLIENT 0x02 +#define FLOW_PKT_ESTABLISHED 0x04 +#define FLOW_PKT_TOSERVER_IPONLY_SET 0x08 +#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10 +#define FLOW_PKT_TOSERVER_FIRST 0x20 +#define FLOW_PKT_TOCLIENT_FIRST 0x40 /** last pseudo packet in the flow. Can be used to trigger final clean, * logging, etc. */ -#define FLOW_PKT_LAST_PSEUDO 0x80 +#define FLOW_PKT_LAST_PSEUDO 0x80 #define FLOW_END_FLAG_STATE_NEW 0x01 #define FLOW_END_FLAG_STATE_ESTABLISHED 0x02 @@ -239,50 +235,67 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_END_FLAG_STATE_BYPASSED 0x80 /** Mutex or RWLocks for the flow. */ -//#define FLOWLOCK_RWLOCK +// #define FLOWLOCK_RWLOCK #define FLOWLOCK_MUTEX #ifdef FLOWLOCK_RWLOCK - #ifdef FLOWLOCK_MUTEX - #error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX - #endif +#ifdef FLOWLOCK_MUTEX +#error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX +#endif #endif #ifdef FLOWLOCK_RWLOCK - #define FLOWLOCK_INIT(fb) SCRWLockInit(&(fb)->r, NULL) - #define FLOWLOCK_DESTROY(fb) SCRWLockDestroy(&(fb)->r) - #define FLOWLOCK_RDLOCK(fb) SCRWLockRDLock(&(fb)->r) - #define FLOWLOCK_WRLOCK(fb) SCRWLockWRLock(&(fb)->r) - #define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r) - #define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r) - #define FLOWLOCK_UNLOCK(fb) SCRWLockUnlock(&(fb)->r) +#define FLOWLOCK_INIT(fb) SCRWLockInit(&(fb)->r, NULL) +#define FLOWLOCK_DESTROY(fb) SCRWLockDestroy(&(fb)->r) +#define FLOWLOCK_RDLOCK(fb) SCRWLockRDLock(&(fb)->r) +#define FLOWLOCK_WRLOCK(fb) SCRWLockWRLock(&(fb)->r) +#define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r) +#define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r) +#define FLOWLOCK_UNLOCK(fb) SCRWLockUnlock(&(fb)->r) #elif defined FLOWLOCK_MUTEX - #define FLOWLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL) - #define FLOWLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m) - #define FLOWLOCK_RDLOCK(fb) SCMutexLock(&(fb)->m) - #define FLOWLOCK_WRLOCK(fb) SCMutexLock(&(fb)->m) - #define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m) - #define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m) - #define FLOWLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m) +#define FLOWLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL) +#define FLOWLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m) +#define FLOWLOCK_RDLOCK(fb) SCMutexLock(&(fb)->m) +#define FLOWLOCK_WRLOCK(fb) SCMutexLock(&(fb)->m) +#define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m) +#define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m) +#define FLOWLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m) #else - #error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX +#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX #endif -#define FLOW_IS_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE)) -#define FLOW_IS_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PP_ALPROTO_DETECT_DONE)) -#define FLOW_IS_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PE_ALPROTO_DETECT_DONE)) - -#define FLOW_SET_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PM_ALPROTO_DETECT_DONE)) -#define FLOW_SET_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE)) -#define FLOW_SET_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PE_ALPROTO_DETECT_DONE)) - -#define FLOW_RESET_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PM_ALPROTO_DETECT_DONE)) -#define FLOW_RESET_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PP_ALPROTO_DETECT_DONE)) -#define FLOW_RESET_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PE_ALPROTO_DETECT_DONE)) +#define FLOW_IS_PM_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) \ + : ((f)->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE)) +#define FLOW_IS_PP_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PP_ALPROTO_DETECT_DONE) \ + : ((f)->flags & FLOW_TC_PP_ALPROTO_DETECT_DONE)) +#define FLOW_IS_PE_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PE_ALPROTO_DETECT_DONE) \ + : ((f)->flags & FLOW_TC_PE_ALPROTO_DETECT_DONE)) + +#define FLOW_SET_PM_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PM_ALPROTO_DETECT_DONE) \ + : ((f)->flags |= FLOW_TC_PM_ALPROTO_DETECT_DONE)) +#define FLOW_SET_PP_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE) \ + : ((f)->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE)) +#define FLOW_SET_PE_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PE_ALPROTO_DETECT_DONE) \ + : ((f)->flags |= FLOW_TC_PE_ALPROTO_DETECT_DONE)) + +#define FLOW_RESET_PM_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PM_ALPROTO_DETECT_DONE) \ + : ((f)->flags &= ~FLOW_TC_PM_ALPROTO_DETECT_DONE)) +#define FLOW_RESET_PP_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PP_ALPROTO_DETECT_DONE) \ + : ((f)->flags &= ~FLOW_TC_PP_ALPROTO_DETECT_DONE)) +#define FLOW_RESET_PE_DONE(f, dir) \ + (((dir)&STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PE_ALPROTO_DETECT_DONE) \ + : ((f)->flags &= ~FLOW_TC_PE_ALPROTO_DETECT_DONE)) /* global flow config */ -typedef struct FlowCnf_ -{ +typedef struct FlowCnf_ { uint32_t hash_rand; uint32_t hash_size; uint32_t prealloc; @@ -298,8 +311,7 @@ typedef struct FlowCnf_ } FlowConfig; /* Hash key for the flow hash */ -typedef struct FlowKey_ -{ +typedef struct FlowKey_ { Address src, dst; Port sp, dp; uint8_t proto; @@ -310,9 +322,9 @@ typedef struct FlowKey_ typedef struct FlowAddress_ { union { - uint32_t address_un_data32[4]; /* type-specific field */ - uint16_t address_un_data16[8]; /* type-specific field */ - uint8_t address_un_data8[16]; /* type-specific field */ + uint32_t address_un_data32[4]; /* type-specific field */ + uint16_t address_un_data16[8]; /* type-specific field */ + uint8_t address_un_data8[16]; /* type-specific field */ } address; } FlowAddress; @@ -325,7 +337,7 @@ typedef unsigned short FlowStateType; /** Local Thread ID */ typedef uint16_t FlowThreadId; -#include "util-storage.h" +#include "util/storage.h" /** * \brief Flow data structure. @@ -345,16 +357,15 @@ typedef uint16_t FlowThreadId; * of a flow. This is why we can access those without protection of the lock. */ -typedef struct Flow_ -{ +typedef struct Flow_ { /* flow "header", used for hashing and flow lookup. Static after init, * so safe to look at without lock */ FlowAddress src, dst; union { - Port sp; /**< tcp/udp source port */ + Port sp; /**< tcp/udp source port */ struct { - uint8_t type; /**< icmp type */ - uint8_t code; /**< icmp code */ + uint8_t type; /**< icmp type */ + uint8_t code; /**< icmp code */ } icmp_s; struct { @@ -362,10 +373,10 @@ typedef struct Flow_ } esp; }; union { - Port dp; /**< tcp/udp destination port */ + Port dp; /**< tcp/udp destination port */ struct { - uint8_t type; /**< icmp type */ - uint8_t code; /**< icmp code */ + uint8_t type; /**< icmp type */ + uint8_t code; /**< icmp code */ } icmp_d; }; uint8_t proto; @@ -377,8 +388,8 @@ typedef struct Flow_ /* track toserver/toclient flow timeout needs */ union { struct { - uint8_t ffr_ts:4; - uint8_t ffr_tc:4; + uint8_t ffr_ts : 4; + uint8_t ffr_tc : 4; }; uint8_t ffr; }; @@ -416,9 +427,9 @@ typedef struct Flow_ uint32_t probing_parser_toserver_alproto_masks; uint32_t probing_parser_toclient_alproto_masks; - uint32_t flags; /**< generic flags */ + uint32_t flags; /**< generic flags */ - uint16_t file_flags; /**< file tracking/extraction flags */ + uint16_t file_flags; /**< file tracking/extraction flags */ /** destination port to be used in protocol detection. This is meant * for use with STARTTLS and HTTP CONNECT detection */ @@ -432,7 +443,7 @@ typedef struct Flow_ #elif defined FLOWLOCK_MUTEX SCMutex m; #else - #error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX +#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX #endif /** protocol specific data pointer, e.g. for TcpSession */ @@ -470,8 +481,8 @@ typedef struct Flow_ /** application level storage ptrs. * */ - AppLayerParserState *alparser; /**< parser internal state */ - void *alstate; /**< application layer state */ + AppLayerParserState *alparser; /**< parser internal state */ + void *alstate; /**< application layer state */ /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag * has been set. */ @@ -522,8 +533,8 @@ typedef struct FlowProtoFreeFunc_ { } FlowProtoFreeFunc; typedef struct FlowBypassInfo_ { - bool (* BypassUpdate)(Flow *f, void *data, time_t tsec); - void (* BypassFree)(void *data); + bool (*BypassUpdate)(Flow *f, void *data, time_t tsec); + void (*BypassFree)(void *data); void *bypass_data; uint64_t tosrcpktcnt; uint64_t tosrcbytecnt; @@ -547,7 +558,7 @@ typedef struct FlowLookupStruct_ // TODO name * and calc the hash value to be used in the lookup and autofp flow * balancing. */ void FlowSetupPacket(Packet *p); -void FlowHandlePacket (ThreadVars *, FlowLookupStruct *, Packet *); +void FlowHandlePacket(ThreadVars *, FlowLookupStruct *, Packet *); void FlowInitConfig(bool); void FlowReset(void); void FlowShutdown(void); @@ -600,7 +611,7 @@ static inline void *FlowGetAppState(const Flow *f) * * \param f Flow to set the flag in */ -static inline void FlowSetNoPacketInspectionFlag(Flow *f) +static inline void FlowSetNoPacketInspectionFlag(Flow *f) { SCEnter(); @@ -691,7 +702,7 @@ static inline bool FlowIsBypassed(const Flow *f) return false; } -int FlowClearMemory(Flow *,uint8_t ); +int FlowClearMemory(Flow *, uint8_t); AppProto FlowGetAppProtocol(const Flow *f); void *FlowGetAppState(const Flow *f); diff --git a/src/host-bit.c b/src/host-bit.c index 3b03d50efe8e..b9e4ae88733c 100644 --- a/src/host-bit.c +++ b/src/host-bit.c @@ -33,9 +33,9 @@ #include "host-bit.h" #include "host.h" #include "detect.h" -#include "util-var.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/var.h" +#include "util/debug.h" +#include "util/unittest.h" #include "host-storage.h" static HostStorageId host_bit_id = { .id = -1 }; /**< Host storage id for bits */ @@ -63,11 +63,11 @@ int HostHasHostBits(Host *host) } /** \retval 1 host timed out wrt xbits - * \retval 0 host still has active (non-expired) xbits */ + * \retval 0 host still has active (non-expired) xbits */ int HostBitsTimedoutCheck(Host *h, SCTime_t ts) { GenericVar *gv = HostGetStorageById(h, host_bit_id); - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_XBITS) { XBit *xb = (XBit *)gv; if (xb->expire > (uint32_t)SCTIME_SECS(ts)) @@ -81,7 +81,7 @@ int HostBitsTimedoutCheck(Host *h, SCTime_t ts) static XBit *HostBitGet(Host *h, uint32_t idx) { GenericVar *gv = HostGetStorageById(h, host_bit_id); - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_XBITS && gv->idx == idx) { return (XBit *)gv; } @@ -108,7 +108,7 @@ static void HostBitAdd(Host *h, uint32_t idx, uint32_t expire) GenericVarAppend(&gv, (GenericVar *)fb); HostSetStorageById(h, host_bit_id, gv); - // bit already set, lets update it's time + // bit already set, lets update it's time } else { fb->expire = expire; } @@ -159,7 +159,7 @@ int HostBitIsset(Host *h, uint32_t idx, uint32_t ts) XBit *fb = HostBitGet(h, idx); if (fb != NULL) { if (fb->expire < ts) { - HostBitRemove(h,idx); + HostBitRemove(h, idx); return 0; } return 1; @@ -175,7 +175,7 @@ int HostBitIsnotset(Host *h, uint32_t idx, uint32_t ts) } if (fb->expire < ts) { - HostBitRemove(h,idx); + HostBitRemove(h, idx); return 1; } return 0; @@ -190,7 +190,7 @@ int HostBitList(Host *h, XBit **iter) gv = gv->next; } - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_XBITS) { *iter = (XBit *)gv; return 1; @@ -202,7 +202,7 @@ int HostBitList(Host *h, XBit **iter) /* TESTS */ #ifdef UNITTESTS -static int HostBitTest01 (void) +static int HostBitTest01(void) { int ret = 0; @@ -213,7 +213,7 @@ static int HostBitTest01 (void) HostBitAdd(h, 0, 0); - XBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h, 0); if (fb != NULL) ret = 1; @@ -223,7 +223,7 @@ static int HostBitTest01 (void) return ret; } -static int HostBitTest02 (void) +static int HostBitTest02(void) { int ret = 0; @@ -232,7 +232,7 @@ static int HostBitTest02 (void) if (h == NULL) goto end; - XBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h, 0); if (fb == NULL) ret = 1; @@ -242,7 +242,7 @@ static int HostBitTest02 (void) return ret; } -static int HostBitTest03 (void) +static int HostBitTest03(void) { int ret = 0; @@ -253,7 +253,7 @@ static int HostBitTest03 (void) HostBitAdd(h, 0, 30); - XBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h, 0); if (fb == NULL) { printf("fb == NULL although it was just added: "); goto end; @@ -261,7 +261,7 @@ static int HostBitTest03 (void) HostBitRemove(h, 0); - fb = HostBitGet(h,0); + fb = HostBitGet(h, 0); if (fb != NULL) { printf("fb != NULL although it was just removed: "); goto end; @@ -275,7 +275,7 @@ static int HostBitTest03 (void) return ret; } -static int HostBitTest04 (void) +static int HostBitTest04(void) { int ret = 0; @@ -289,7 +289,7 @@ static int HostBitTest04 (void) HostBitAdd(h, 2, 30); HostBitAdd(h, 3, 30); - XBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h, 0); if (fb != NULL) ret = 1; @@ -299,7 +299,7 @@ static int HostBitTest04 (void) return ret; } -static int HostBitTest05 (void) +static int HostBitTest05(void) { int ret = 0; @@ -313,7 +313,7 @@ static int HostBitTest05 (void) HostBitAdd(h, 2, 30); HostBitAdd(h, 3, 30); - XBit *fb = HostBitGet(h,1); + XBit *fb = HostBitGet(h, 1); if (fb != NULL) ret = 1; @@ -323,7 +323,7 @@ static int HostBitTest05 (void) return ret; } -static int HostBitTest06 (void) +static int HostBitTest06(void) { int ret = 0; @@ -337,7 +337,7 @@ static int HostBitTest06 (void) HostBitAdd(h, 2, 90); HostBitAdd(h, 3, 90); - XBit *fb = HostBitGet(h,2); + XBit *fb = HostBitGet(h, 2); if (fb != NULL) ret = 1; @@ -347,7 +347,7 @@ static int HostBitTest06 (void) return ret; } -static int HostBitTest07 (void) +static int HostBitTest07(void) { int ret = 0; @@ -361,7 +361,7 @@ static int HostBitTest07 (void) HostBitAdd(h, 2, 90); HostBitAdd(h, 3, 90); - XBit *fb = HostBitGet(h,3); + XBit *fb = HostBitGet(h, 3); if (fb != NULL) ret = 1; @@ -371,7 +371,7 @@ static int HostBitTest07 (void) return ret; } -static int HostBitTest08 (void) +static int HostBitTest08(void) { int ret = 0; @@ -385,13 +385,13 @@ static int HostBitTest08 (void) HostBitAdd(h, 2, 90); HostBitAdd(h, 3, 90); - XBit *fb = HostBitGet(h,0); + XBit *fb = HostBitGet(h, 0); if (fb == NULL) goto end; - HostBitRemove(h,0); + HostBitRemove(h, 0); - fb = HostBitGet(h,0); + fb = HostBitGet(h, 0); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; @@ -404,7 +404,7 @@ static int HostBitTest08 (void) return ret; } -static int HostBitTest09 (void) +static int HostBitTest09(void) { int ret = 0; @@ -418,13 +418,13 @@ static int HostBitTest09 (void) HostBitAdd(h, 2, 90); HostBitAdd(h, 3, 90); - XBit *fb = HostBitGet(h,1); + XBit *fb = HostBitGet(h, 1); if (fb == NULL) goto end; - HostBitRemove(h,1); + HostBitRemove(h, 1); - fb = HostBitGet(h,1); + fb = HostBitGet(h, 1); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; @@ -437,7 +437,7 @@ static int HostBitTest09 (void) return ret; } -static int HostBitTest10 (void) +static int HostBitTest10(void) { int ret = 0; @@ -451,13 +451,13 @@ static int HostBitTest10 (void) HostBitAdd(h, 2, 90); HostBitAdd(h, 3, 90); - XBit *fb = HostBitGet(h,2); + XBit *fb = HostBitGet(h, 2); if (fb == NULL) goto end; - HostBitRemove(h,2); + HostBitRemove(h, 2); - fb = HostBitGet(h,2); + fb = HostBitGet(h, 2); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; @@ -470,7 +470,7 @@ static int HostBitTest10 (void) return ret; } -static int HostBitTest11 (void) +static int HostBitTest11(void) { int ret = 0; @@ -484,13 +484,13 @@ static int HostBitTest11 (void) HostBitAdd(h, 2, 90); HostBitAdd(h, 3, 90); - XBit *fb = HostBitGet(h,3); + XBit *fb = HostBitGet(h, 3); if (fb == NULL) goto end; - HostBitRemove(h,3); + HostBitRemove(h, 3); - fb = HostBitGet(h,3); + fb = HostBitGet(h, 3); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; diff --git a/src/host-bit.h b/src/host-bit.h index bcd9c2d3dbcd..f05d039b31e5 100644 --- a/src/host-bit.h +++ b/src/host-bit.h @@ -25,7 +25,7 @@ #define __HOST_BIT_H__ #include "host.h" -#include "util-var.h" +#include "util/var.h" void HostBitInitCtx(void); void HostBitRegisterTests(void); diff --git a/src/host-queue.c b/src/host-queue.c index f81cb54c7713..5ca02e57b6ba 100644 --- a/src/host-queue.c +++ b/src/host-queue.c @@ -26,11 +26,11 @@ #include "suricata-common.h" #include "threads.h" #include "host-queue.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-print.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/print.h" -HostQueue *HostQueueInit (HostQueue *q) +HostQueue *HostQueueInit(HostQueue *q) { if (q != NULL) { memset(q, 0, sizeof(HostQueue)); @@ -55,7 +55,7 @@ HostQueue *HostQueueNew(void) * * \param q the host queue to destroy */ -void HostQueueDestroy (HostQueue *q) +void HostQueueDestroy(HostQueue *q) { HQLOCK_DESTROY(q); } @@ -66,7 +66,7 @@ void HostQueueDestroy (HostQueue *q) * \param q queue * \param h host */ -void HostEnqueue (HostQueue *q, Host *h) +void HostEnqueue(HostQueue *q, Host *h) { #ifdef DEBUG BUG_ON(q == NULL || h == NULL); @@ -79,7 +79,7 @@ void HostEnqueue (HostQueue *q, Host *h) h->lnext = q->top; q->top->lprev = h; q->top = h; - /* only host */ + /* only host */ } else { q->top = h; q->bot = h; @@ -99,7 +99,7 @@ void HostEnqueue (HostQueue *q, Host *h) * * \retval h host or NULL if empty list. */ -Host *HostDequeue (HostQueue *q) +Host *HostDequeue(HostQueue *q) { HQLOCK_LOCK(q); @@ -113,7 +113,7 @@ Host *HostDequeue (HostQueue *q) if (q->bot->lprev != NULL) { q->bot = q->bot->lprev; q->bot->lnext = NULL; - /* just the one we remove, so now empty */ + /* just the one we remove, so now empty */ } else { q->top = NULL; q->bot = NULL; @@ -140,4 +140,3 @@ uint32_t HostQueueLen(HostQueue *q) HQLOCK_UNLOCK(q); return len; } - diff --git a/src/host-queue.h b/src/host-queue.h index 2edd169d22f2..bf43d52a4655 100644 --- a/src/host-queue.h +++ b/src/host-queue.h @@ -28,18 +28,17 @@ #include "host.h" /** Spinlocks or Mutex for the host queues. */ -//#define HQLOCK_SPIN +// #define HQLOCK_SPIN #define HQLOCK_MUTEX #ifdef HQLOCK_SPIN - #ifdef HQLOCK_MUTEX - #error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX - #endif +#ifdef HQLOCK_MUTEX +#error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX +#endif #endif /* Define a queue for storing hosts */ -typedef struct HostQueue_ -{ +typedef struct HostQueue_ { Host *top; Host *bot; uint32_t len; @@ -51,34 +50,33 @@ typedef struct HostQueue_ #elif defined HQLOCK_SPIN SCSpinlock s; #else - #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#error Enable HQLOCK_SPIN or HQLOCK_MUTEX #endif } HostQueue; #ifdef HQLOCK_SPIN - #define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) - #define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) - #define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) - #define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) - #define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) +#define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) +#define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) +#define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) +#define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) +#define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) #elif defined HQLOCK_MUTEX - #define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) - #define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) - #define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) - #define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) - #define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) +#define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) +#define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) +#define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) +#define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) +#define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) #else - #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#error Enable HQLOCK_SPIN or HQLOCK_MUTEX #endif /* prototypes */ HostQueue *HostQueueNew(void); HostQueue *HostQueueInit(HostQueue *); -void HostQueueDestroy (HostQueue *); +void HostQueueDestroy(HostQueue *); -void HostEnqueue (HostQueue *, Host *); -Host *HostDequeue (HostQueue *); +void HostEnqueue(HostQueue *, Host *); +Host *HostDequeue(HostQueue *); uint32_t HostQueueLen(HostQueue *); #endif /* __HOST_QUEUE_H__ */ - diff --git a/src/host-storage.c b/src/host-storage.c index 234c67112edf..080503efaffb 100644 --- a/src/host-storage.c +++ b/src/host-storage.c @@ -25,7 +25,7 @@ #include "suricata-common.h" #include "host-storage.h" -#include "util-unittest.h" +#include "util/unittest.h" unsigned int HostStorageSize(void) { @@ -112,7 +112,6 @@ void HostFreeStorage(Host *h) StorageFreeAll(h->storage, STORAGE_HOST); } - #ifdef UNITTESTS static void *StorageTestAlloc(unsigned int size) diff --git a/src/host-timeout.c b/src/host-timeout.c index 8542d5f78abb..37549a85aa2b 100644 --- a/src/host-timeout.c +++ b/src/host-timeout.c @@ -108,7 +108,7 @@ static uint32_t HostHashRowTimeout(HostHashRow *hb, Host *h, SCTime_t ts) h->hnext = NULL; h->hprev = NULL; - HostClearMemory (h); + HostClearMemory(h); /* no one is referring to this host, use_cnt 0, removed from hash * so we can unlock it and move it back to the spare queue. */ @@ -160,4 +160,3 @@ uint32_t HostTimeoutHash(SCTime_t ts) return cnt; } - diff --git a/src/host-timeout.h b/src/host-timeout.h index 044c44d970bb..7b8dc75e0f33 100644 --- a/src/host-timeout.h +++ b/src/host-timeout.h @@ -30,4 +30,3 @@ uint32_t HostGetSpareCount(void); uint32_t HostGetActiveCount(void); #endif - diff --git a/src/host.c b/src/host.c index 37c0f4dad479..50eca0d8ccc9 100644 --- a/src/host.c +++ b/src/host.c @@ -26,15 +26,15 @@ #include "suricata-common.h" #include "conf.h" -#include "util-debug.h" +#include "util/debug.h" #include "host.h" #include "host-storage.h" #include "host-bit.h" -#include "util-random.h" -#include "util-misc.h" -#include "util-byte.h" -#include "util-validate.h" +#include "util/random.h" +#include "util/misc.h" +#include "util/byte.h" +#include "util/validate.h" #include "host-queue.h" @@ -42,7 +42,7 @@ #include "detect-engine-tag.h" #include "detect-engine-threshold.h" -#include "util-hash-lookup3.h" +#include "util/hash-lookup3.h" static Host *HostGetUsedHost(void); @@ -52,9 +52,9 @@ HostHashRow *host_hash; static HostQueue host_spare_q; HostConfig host_config; -SC_ATOMIC_DECLARE(uint64_t,host_memuse); -SC_ATOMIC_DECLARE(uint32_t,host_counter); -SC_ATOMIC_DECLARE(uint32_t,host_prune_idx); +SC_ATOMIC_DECLARE(uint64_t, host_memuse); +SC_ATOMIC_DECLARE(uint32_t, host_counter); +SC_ATOMIC_DECLARE(uint32_t, host_prune_idx); /** size of the host object. Maybe updated in HostInitConfig to include * the storage APIs additions. */ @@ -105,7 +105,7 @@ uint32_t HostSpareQueueGetSize(void) void HostMoveToSpare(Host *h) { HostEnqueue(&host_spare_q, h); - (void) SC_ATOMIC_SUB(host_counter, 1); + (void)SC_ATOMIC_SUB(host_counter, 1); } Host *HostAlloc(void) @@ -113,7 +113,7 @@ Host *HostAlloc(void) if (!(HOST_CHECK_MEMCAP(g_host_size))) { return NULL; } - (void) SC_ATOMIC_ADD(host_memuse, g_host_size); + (void)SC_ATOMIC_ADD(host_memuse, g_host_size); Host *h = SCCalloc(1, g_host_size); if (unlikely(h == NULL)) @@ -133,7 +133,7 @@ void HostFree(Host *h) HostClearMemory(h); SCMutexDestroy(&h->m); SCFree(h); - (void) SC_ATOMIC_SUB(host_memuse, g_host_size); + (void)SC_ATOMIC_SUB(host_memuse, g_host_size); } } @@ -165,7 +165,7 @@ void HostClearMemory(Host *h) } #define HOST_DEFAULT_HASHSIZE 4096 -#define HOST_DEFAULT_MEMCAP 16777216 +#define HOST_DEFAULT_MEMCAP 16777216 #define HOST_DEFAULT_PREALLOC 1000 /** \brief initialize the configuration @@ -178,8 +178,8 @@ void HostInitConfig(bool quiet) g_host_size = (uint16_t)(sizeof(Host) + HostStorageSize()); } - memset(&host_config, 0, sizeof(host_config)); - //SC_ATOMIC_INIT(flow_flags); + memset(&host_config, 0, sizeof(host_config)); + // SC_ATOMIC_INIT(flow_flags); SC_ATOMIC_INIT(host_counter); SC_ATOMIC_INIT(host_memuse); SC_ATOMIC_INIT(host_prune_idx); @@ -187,9 +187,9 @@ void HostInitConfig(bool quiet) HostQueueInit(&host_spare_q); /* set defaults */ - host_config.hash_rand = (uint32_t)RandomGet(); - host_config.hash_size = HOST_DEFAULT_HASHSIZE; - host_config.prealloc = HOST_DEFAULT_PREALLOC; + host_config.hash_rand = (uint32_t)RandomGet(); + host_config.hash_size = HOST_DEFAULT_HASHSIZE; + host_config.prealloc = HOST_DEFAULT_PREALLOC; SC_ATOMIC_SET(host_config.memcap, HOST_DEFAULT_MEMCAP); /* Check if we have memcap and hash_size defined at config */ @@ -209,23 +209,21 @@ void HostInitConfig(bool quiet) } } if ((ConfGet("host.hash-size", &conf_val)) == 1) { - if (StringParseUint32(&configval, 10, strlen(conf_val), - conf_val) > 0) { + if (StringParseUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { host_config.hash_size = configval; } } if ((ConfGet("host.prealloc", &conf_val)) == 1) { - if (StringParseUint32(&configval, 10, strlen(conf_val), - conf_val) > 0) { + if (StringParseUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { host_config.prealloc = configval; } else { - WarnInvalidConfEntry("host.prealloc", "%"PRIu32, host_config.prealloc); + WarnInvalidConfEntry("host.prealloc", "%" PRIu32, host_config.prealloc); } } - SCLogDebug("Host config from suricata.yaml: memcap: %"PRIu64", hash-size: " - "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(host_config.memcap), - host_config.hash_size, host_config.prealloc); + SCLogDebug("Host config from suricata.yaml: memcap: %" PRIu64 ", hash-size: " + "%" PRIu32 ", prealloc: %" PRIu32, + SC_ATOMIC_GET(host_config.memcap), host_config.hash_size, host_config.prealloc); /* alloc hash memory */ uint64_t hash_size = host_config.hash_size * sizeof(HostHashRow); @@ -248,13 +246,12 @@ void HostInitConfig(bool quiet) for (i = 0; i < host_config.hash_size; i++) { HRLOCK_INIT(&host_hash[i]); } - (void) SC_ATOMIC_ADD(host_memuse, (host_config.hash_size * sizeof(HostHashRow))); + (void)SC_ATOMIC_ADD(host_memuse, (host_config.hash_size * sizeof(HostHashRow))); if (!quiet) { - SCLogConfig("allocated %"PRIu64" bytes of memory for the host hash... " - "%" PRIu32 " buckets of size %" PRIuMAX "", - SC_ATOMIC_GET(host_memuse), host_config.hash_size, - (uintmax_t)sizeof(HostHashRow)); + SCLogConfig("allocated %" PRIu64 " bytes of memory for the host hash... " + "%" PRIu32 " buckets of size %" PRIuMAX "", + SC_ATOMIC_GET(host_memuse), host_config.hash_size, (uintmax_t)sizeof(HostHashRow)); } /* pre allocate hosts */ @@ -273,13 +270,13 @@ void HostInitConfig(bool quiet) SCLogError("preallocating host failed: %s", strerror(errno)); exit(EXIT_FAILURE); } - HostEnqueue(&host_spare_q,h); + HostEnqueue(&host_spare_q, h); } if (!quiet) { - SCLogConfig("preallocated %" PRIu32 " hosts of size %" PRIu16 "", - host_spare_q.len, g_host_size); - SCLogConfig("host memory usage: %"PRIu64" bytes, maximum: %"PRIu64, + SCLogConfig("preallocated %" PRIu32 " hosts of size %" PRIu16 "", host_spare_q.len, + g_host_size); + SCLogConfig("host memory usage: %" PRIu64 " bytes, maximum: %" PRIu64, SC_ATOMIC_GET(host_memuse), SC_ATOMIC_GET(host_config.memcap)); } @@ -288,14 +285,14 @@ void HostInitConfig(bool quiet) /** \brief print some host stats * \warning Not thread safe */ -void HostPrintStats (void) +void HostPrintStats(void) { #ifdef HOSTBITS_STATS SCLogPerf("hostbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", - hostbits_added, hostbits_removed, hostbits_memuse_max); + hostbits_added, hostbits_removed, hostbits_memuse_max); #endif /* HOSTBITS_STATS */ - SCLogPerf("host memory usage: %"PRIu64" bytes, maximum: %"PRIu64, - SC_ATOMIC_GET(host_memuse), SC_ATOMIC_GET(host_config.memcap)); + SCLogPerf("host memory usage: %" PRIu64 " bytes, maximum: %" PRIu64, SC_ATOMIC_GET(host_memuse), + SC_ATOMIC_GET(host_config.memcap)); return; } @@ -309,7 +306,7 @@ void HostShutdown(void) HostPrintStats(); /* free spare queue */ - while((h = HostDequeue(&host_spare_q))) { + while ((h = HostDequeue(&host_spare_q))) { HostFree(h); } @@ -328,7 +325,7 @@ void HostShutdown(void) SCFreeAligned(host_hash); host_hash = NULL; } - (void) SC_ATOMIC_SUB(host_memuse, host_config.hash_size * sizeof(HostHashRow)); + (void)SC_ATOMIC_SUB(host_memuse, host_config.hash_size * sizeof(HostHashRow)); HostQueueDestroy(&host_spare_q); return; } @@ -428,12 +425,12 @@ static Host *HostGetNew(Address *a) /* If we reached the max memcap, we get a used host */ if (!(HOST_CHECK_MEMCAP(g_host_size))) { /* declare state of emergency */ - //if (!(SC_ATOMIC_GET(host_flags) & HOST_EMERGENCY)) { - // SC_ATOMIC_OR(host_flags, HOST_EMERGENCY); + // if (!(SC_ATOMIC_GET(host_flags) & HOST_EMERGENCY)) { + // SC_ATOMIC_OR(host_flags, HOST_EMERGENCY); - /* under high load, waking up the flow mgr each time leads - * to high cpu usage. Flows are not timed out much faster if - * we check a 1000 times a second. */ + /* under high load, waking up the flow mgr each time leads + * to high cpu usage. Flows are not timed out much faster if + * we check a 1000 times a second. */ // FlowWakeupFlowManagerThread(); //} @@ -458,7 +455,7 @@ static Host *HostGetNew(Address *a) /* host is initialized (recycled) but *unlocked* */ } - (void) SC_ATOMIC_ADD(host_counter, 1); + (void)SC_ATOMIC_ADD(host_counter, 1); SCMutexLock(&h->m); return h; } @@ -466,12 +463,12 @@ static Host *HostGetNew(Address *a) static void HostInit(Host *h, Address *a) { COPY_ADDRESS(a, &h->a); - (void) HostIncrUsecnt(h); + (void)HostIncrUsecnt(h); } void HostRelease(Host *h) { - (void) HostDecrUsecnt(h); + (void)HostDecrUsecnt(h); SCMutexUnlock(&h->m); } @@ -485,7 +482,6 @@ void HostUnlock(Host *h) SCMutexUnlock(&h->m); } - /* HostGetHostFromHash * * Hash retrieval function for hosts. Looks up the hash bucket containing the @@ -494,7 +490,7 @@ void HostUnlock(Host *h) * * returns a *LOCKED* host or NULL */ -Host *HostGetHostFromHash (Address *a) +Host *HostGetHostFromHash(Address *a) { Host *h = NULL; @@ -517,7 +513,7 @@ Host *HostGetHostFromHash (Address *a) hb->tail = h; /* got one, now lock, initialize and return */ - HostInit(h,a); + HostInit(h, a); HRLOCK_UNLOCK(hb); return h; @@ -547,7 +543,7 @@ Host *HostGetHostFromHash (Address *a) h->hprev = ph; /* initialize and return */ - HostInit(h,a); + HostInit(h, a); HRLOCK_UNLOCK(hb); return h; @@ -573,7 +569,7 @@ Host *HostGetHostFromHash (Address *a) /* found our host, lock & return */ SCMutexLock(&h->m); - (void) HostIncrUsecnt(h); + (void)HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -582,7 +578,7 @@ Host *HostGetHostFromHash (Address *a) /* lock & return */ SCMutexLock(&h->m); - (void) HostIncrUsecnt(h); + (void)HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -593,7 +589,7 @@ Host *HostGetHostFromHash (Address *a) * * \retval h *LOCKED* host or NULL */ -Host *HostLookupHostFromHash (Address *a) +Host *HostLookupHostFromHash(Address *a) { Host *h = NULL; @@ -642,7 +638,7 @@ Host *HostLookupHostFromHash (Address *a) /* found our host, lock & return */ SCMutexLock(&h->m); - (void) HostIncrUsecnt(h); + (void)HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -651,7 +647,7 @@ Host *HostLookupHostFromHash (Address *a) /* lock & return */ SCMutexLock(&h->m); - (void) HostIncrUsecnt(h); + (void)HostIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -714,11 +710,11 @@ static Host *HostGetUsedHost(void) h->hprev = NULL; HRLOCK_UNLOCK(hb); - HostClearMemory (h); + HostClearMemory(h); SCMutexUnlock(&h->m); - (void) SC_ATOMIC_ADD(host_prune_idx, (host_config.hash_size - cnt)); + (void)SC_ATOMIC_ADD(host_prune_idx, (host_config.hash_size - cnt)); return h; } @@ -729,4 +725,3 @@ void HostRegisterUnittests(void) { RegisterHostStorageTests(); } - diff --git a/src/host.h b/src/host.h index f4f248b5eec6..50ef34f92351 100644 --- a/src/host.h +++ b/src/host.h @@ -25,34 +25,34 @@ #define __HOST_H__ #include "decode.h" -#include "util-storage.h" +#include "util/storage.h" /** Spinlocks or Mutex for the flow buckets. */ -//#define HRLOCK_SPIN +// #define HRLOCK_SPIN #define HRLOCK_MUTEX #ifdef HRLOCK_SPIN - #ifdef HRLOCK_MUTEX - #error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX - #endif +#ifdef HRLOCK_MUTEX +#error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX +#endif #endif #ifdef HRLOCK_SPIN - #define HRLOCK_TYPE SCSpinlock - #define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) - #define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) - #define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) - #define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) - #define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) +#define HRLOCK_TYPE SCSpinlock +#define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) +#define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) +#define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) +#define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) +#define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) #elif defined HRLOCK_MUTEX - #define HRLOCK_TYPE SCMutex - #define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) - #define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) - #define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) - #define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) - #define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) +#define HRLOCK_TYPE SCMutex +#define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) +#define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) +#define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) +#define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) +#define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) #else - #error Enable HRLOCK_SPIN or HRLOCK_MUTEX +#error Enable HRLOCK_SPIN or HRLOCK_MUTEX #endif typedef struct Host_ { @@ -89,8 +89,8 @@ typedef struct HostHashRow_ { /** host hash table */ extern HostHashRow *host_hash; -#define HOST_VERBOSE 0 -#define HOST_QUIET 1 +#define HOST_VERBOSE 0 +#define HOST_QUIET 1 typedef struct HostConfig_ { SC_ATOMIC_DECLARE(uint64_t, memcap); @@ -106,45 +106,46 @@ typedef struct HostConfig_ { * \retval 1 it fits * \retval 0 no fit */ -#define HOST_CHECK_MEMCAP(size) \ - ((((uint64_t)SC_ATOMIC_GET(host_memuse) + (uint64_t)(size)) <= SC_ATOMIC_GET(host_config.memcap))) - -#define HostIncrUsecnt(h) \ - (void)SC_ATOMIC_ADD((h)->use_cnt, 1) -#define HostDecrUsecnt(h) \ - (void)SC_ATOMIC_SUB((h)->use_cnt, 1) - -#define HostReference(dst_h_ptr, h) do { \ - if ((h) != NULL) { \ - HostIncrUsecnt((h)); \ - *(dst_h_ptr) = h; \ - } \ +#define HOST_CHECK_MEMCAP(size) \ + ((((uint64_t)SC_ATOMIC_GET(host_memuse) + (uint64_t)(size)) <= \ + SC_ATOMIC_GET(host_config.memcap))) + +#define HostIncrUsecnt(h) (void)SC_ATOMIC_ADD((h)->use_cnt, 1) +#define HostDecrUsecnt(h) (void)SC_ATOMIC_SUB((h)->use_cnt, 1) + +#define HostReference(dst_h_ptr, h) \ + do { \ + if ((h) != NULL) { \ + HostIncrUsecnt((h)); \ + *(dst_h_ptr) = h; \ + } \ } while (0) -#define HostDeReference(src_h_ptr) do { \ - if (*(src_h_ptr) != NULL) { \ - HostDecrUsecnt(*(src_h_ptr)); \ - *(src_h_ptr) = NULL; \ - } \ +#define HostDeReference(src_h_ptr) \ + do { \ + if (*(src_h_ptr) != NULL) { \ + HostDecrUsecnt(*(src_h_ptr)); \ + *(src_h_ptr) = NULL; \ + } \ } while (0) extern HostConfig host_config; -SC_ATOMIC_EXTERN(uint64_t,host_memuse); -SC_ATOMIC_EXTERN(uint32_t,host_counter); -SC_ATOMIC_EXTERN(uint32_t,host_prune_idx); +SC_ATOMIC_EXTERN(uint64_t, host_memuse); +SC_ATOMIC_EXTERN(uint32_t, host_counter); +SC_ATOMIC_EXTERN(uint32_t, host_prune_idx); void HostInitConfig(bool quiet); void HostShutdown(void); void HostCleanup(void); -Host *HostLookupHostFromHash (Address *); -Host *HostGetHostFromHash (Address *); +Host *HostLookupHostFromHash(Address *); +Host *HostGetHostFromHash(Address *); void HostRelease(Host *); void HostLock(Host *); void HostClearMemory(Host *); void HostMoveToSpare(Host *); uint32_t HostSpareQueueGetSize(void); -void HostPrintStats (void); +void HostPrintStats(void); void HostRegisterUnittests(void); @@ -158,4 +159,3 @@ uint64_t HostGetMemcap(void); uint64_t HostGetMemuse(void); #endif /* __HOST_H__ */ - diff --git a/src/ippair-bit.c b/src/ippair-bit.c index 1d3d8fa9bbd2..99c604e3fd2c 100644 --- a/src/ippair-bit.c +++ b/src/ippair-bit.c @@ -33,9 +33,9 @@ #include "ippair-bit.h" #include "ippair.h" #include "detect.h" -#include "util-var.h" -#include "util-debug.h" -#include "util-unittest.h" +#include "util/var.h" +#include "util/debug.h" +#include "util/unittest.h" #include "ippair-storage.h" static IPPairStorageId g_ippair_bit_storage_id = { .id = -1 }; /**< IPPair storage id for bits */ @@ -63,11 +63,11 @@ int IPPairHasBits(IPPair *ippair) } /** \retval 1 ippair timed out wrt xbits - * \retval 0 ippair still has active (non-expired) xbits */ + * \retval 0 ippair still has active (non-expired) xbits */ int IPPairBitsTimedoutCheck(IPPair *h, SCTime_t ts) { GenericVar *gv = IPPairGetStorageById(h, g_ippair_bit_storage_id); - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_XBITS) { XBit *xb = (XBit *)gv; if (xb->expire > (uint32_t)SCTIME_SECS(ts)) @@ -81,7 +81,7 @@ int IPPairBitsTimedoutCheck(IPPair *h, SCTime_t ts) static XBit *IPPairBitGet(IPPair *h, uint32_t idx) { GenericVar *gv = IPPairGetStorageById(h, g_ippair_bit_storage_id); - for ( ; gv != NULL; gv = gv->next) { + for (; gv != NULL; gv = gv->next) { if (gv->type == DETECT_XBITS && gv->idx == idx) { return (XBit *)gv; } @@ -183,10 +183,9 @@ int IPPairBitIsnotset(IPPair *h, uint32_t idx, uint32_t ts) return 0; } - /* TESTS */ #ifdef UNITTESTS -static int IPPairBitTest01 (void) +static int IPPairBitTest01(void) { int ret = 0; @@ -197,7 +196,7 @@ static int IPPairBitTest01 (void) IPPairBitAdd(h, 0, 0); - XBit *fb = IPPairBitGet(h,0); + XBit *fb = IPPairBitGet(h, 0); if (fb != NULL) ret = 1; @@ -207,7 +206,7 @@ static int IPPairBitTest01 (void) return ret; } -static int IPPairBitTest02 (void) +static int IPPairBitTest02(void) { int ret = 0; @@ -216,7 +215,7 @@ static int IPPairBitTest02 (void) if (h == NULL) goto end; - XBit *fb = IPPairBitGet(h,0); + XBit *fb = IPPairBitGet(h, 0); if (fb == NULL) ret = 1; @@ -226,7 +225,7 @@ static int IPPairBitTest02 (void) return ret; } -static int IPPairBitTest03 (void) +static int IPPairBitTest03(void) { int ret = 0; @@ -237,7 +236,7 @@ static int IPPairBitTest03 (void) IPPairBitAdd(h, 0, 30); - XBit *fb = IPPairBitGet(h,0); + XBit *fb = IPPairBitGet(h, 0); if (fb == NULL) { printf("fb == NULL although it was just added: "); goto end; @@ -245,7 +244,7 @@ static int IPPairBitTest03 (void) IPPairBitRemove(h, 0); - fb = IPPairBitGet(h,0); + fb = IPPairBitGet(h, 0); if (fb != NULL) { printf("fb != NULL although it was just removed: "); goto end; @@ -259,7 +258,7 @@ static int IPPairBitTest03 (void) return ret; } -static int IPPairBitTest04 (void) +static int IPPairBitTest04(void) { int ret = 0; @@ -268,12 +267,12 @@ static int IPPairBitTest04 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,30); - IPPairBitAdd(h, 1,30); - IPPairBitAdd(h, 2,30); - IPPairBitAdd(h, 3,30); + IPPairBitAdd(h, 0, 30); + IPPairBitAdd(h, 1, 30); + IPPairBitAdd(h, 2, 30); + IPPairBitAdd(h, 3, 30); - XBit *fb = IPPairBitGet(h,0); + XBit *fb = IPPairBitGet(h, 0); if (fb != NULL) ret = 1; @@ -283,7 +282,7 @@ static int IPPairBitTest04 (void) return ret; } -static int IPPairBitTest05 (void) +static int IPPairBitTest05(void) { int ret = 0; @@ -292,12 +291,12 @@ static int IPPairBitTest05 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,90); - IPPairBitAdd(h, 1,90); - IPPairBitAdd(h, 2,90); - IPPairBitAdd(h, 3,90); + IPPairBitAdd(h, 0, 90); + IPPairBitAdd(h, 1, 90); + IPPairBitAdd(h, 2, 90); + IPPairBitAdd(h, 3, 90); - XBit *fb = IPPairBitGet(h,1); + XBit *fb = IPPairBitGet(h, 1); if (fb != NULL) ret = 1; @@ -307,7 +306,7 @@ static int IPPairBitTest05 (void) return ret; } -static int IPPairBitTest06 (void) +static int IPPairBitTest06(void) { int ret = 0; @@ -316,12 +315,12 @@ static int IPPairBitTest06 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,90); - IPPairBitAdd(h, 1,90); - IPPairBitAdd(h, 2,90); - IPPairBitAdd(h, 3,90); + IPPairBitAdd(h, 0, 90); + IPPairBitAdd(h, 1, 90); + IPPairBitAdd(h, 2, 90); + IPPairBitAdd(h, 3, 90); - XBit *fb = IPPairBitGet(h,2); + XBit *fb = IPPairBitGet(h, 2); if (fb != NULL) ret = 1; @@ -331,7 +330,7 @@ static int IPPairBitTest06 (void) return ret; } -static int IPPairBitTest07 (void) +static int IPPairBitTest07(void) { int ret = 0; @@ -340,12 +339,12 @@ static int IPPairBitTest07 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,90); - IPPairBitAdd(h, 1,90); - IPPairBitAdd(h, 2,90); - IPPairBitAdd(h, 3,90); + IPPairBitAdd(h, 0, 90); + IPPairBitAdd(h, 1, 90); + IPPairBitAdd(h, 2, 90); + IPPairBitAdd(h, 3, 90); - XBit *fb = IPPairBitGet(h,3); + XBit *fb = IPPairBitGet(h, 3); if (fb != NULL) ret = 1; @@ -355,7 +354,7 @@ static int IPPairBitTest07 (void) return ret; } -static int IPPairBitTest08 (void) +static int IPPairBitTest08(void) { int ret = 0; @@ -364,18 +363,18 @@ static int IPPairBitTest08 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,90); - IPPairBitAdd(h, 1,90); - IPPairBitAdd(h, 2,90); - IPPairBitAdd(h, 3,90); + IPPairBitAdd(h, 0, 90); + IPPairBitAdd(h, 1, 90); + IPPairBitAdd(h, 2, 90); + IPPairBitAdd(h, 3, 90); - XBit *fb = IPPairBitGet(h,0); + XBit *fb = IPPairBitGet(h, 0); if (fb == NULL) goto end; - IPPairBitRemove(h,0); + IPPairBitRemove(h, 0); - fb = IPPairBitGet(h,0); + fb = IPPairBitGet(h, 0); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; @@ -388,7 +387,7 @@ static int IPPairBitTest08 (void) return ret; } -static int IPPairBitTest09 (void) +static int IPPairBitTest09(void) { int ret = 0; @@ -397,18 +396,18 @@ static int IPPairBitTest09 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,90); - IPPairBitAdd(h, 1,90); - IPPairBitAdd(h, 2,90); - IPPairBitAdd(h, 3,90); + IPPairBitAdd(h, 0, 90); + IPPairBitAdd(h, 1, 90); + IPPairBitAdd(h, 2, 90); + IPPairBitAdd(h, 3, 90); - XBit *fb = IPPairBitGet(h,1); + XBit *fb = IPPairBitGet(h, 1); if (fb == NULL) goto end; - IPPairBitRemove(h,1); + IPPairBitRemove(h, 1); - fb = IPPairBitGet(h,1); + fb = IPPairBitGet(h, 1); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; @@ -421,7 +420,7 @@ static int IPPairBitTest09 (void) return ret; } -static int IPPairBitTest10 (void) +static int IPPairBitTest10(void) { int ret = 0; @@ -430,18 +429,18 @@ static int IPPairBitTest10 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,90); - IPPairBitAdd(h, 1,90); - IPPairBitAdd(h, 2,90); - IPPairBitAdd(h, 3,90); + IPPairBitAdd(h, 0, 90); + IPPairBitAdd(h, 1, 90); + IPPairBitAdd(h, 2, 90); + IPPairBitAdd(h, 3, 90); - XBit *fb = IPPairBitGet(h,2); + XBit *fb = IPPairBitGet(h, 2); if (fb == NULL) goto end; - IPPairBitRemove(h,2); + IPPairBitRemove(h, 2); - fb = IPPairBitGet(h,2); + fb = IPPairBitGet(h, 2); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; @@ -454,7 +453,7 @@ static int IPPairBitTest10 (void) return ret; } -static int IPPairBitTest11 (void) +static int IPPairBitTest11(void) { int ret = 0; @@ -463,18 +462,18 @@ static int IPPairBitTest11 (void) if (h == NULL) goto end; - IPPairBitAdd(h, 0,90); - IPPairBitAdd(h, 1,90); - IPPairBitAdd(h, 2,90); - IPPairBitAdd(h, 3,90); + IPPairBitAdd(h, 0, 90); + IPPairBitAdd(h, 1, 90); + IPPairBitAdd(h, 2, 90); + IPPairBitAdd(h, 3, 90); - XBit *fb = IPPairBitGet(h,3); + XBit *fb = IPPairBitGet(h, 3); if (fb == NULL) goto end; - IPPairBitRemove(h,3); + IPPairBitRemove(h, 3); - fb = IPPairBitGet(h,3); + fb = IPPairBitGet(h, 3); if (fb != NULL) { printf("fb != NULL even though it was removed: "); goto end; diff --git a/src/ippair-queue.c b/src/ippair-queue.c index dac6b7e9c935..224e39b7f863 100644 --- a/src/ippair-queue.c +++ b/src/ippair-queue.c @@ -26,11 +26,11 @@ #include "suricata-common.h" #include "threads.h" #include "ippair-queue.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-print.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/print.h" -IPPairQueue *IPPairQueueInit (IPPairQueue *q) +IPPairQueue *IPPairQueueInit(IPPairQueue *q) { if (q != NULL) { memset(q, 0, sizeof(IPPairQueue)); @@ -55,7 +55,7 @@ IPPairQueue *IPPairQueueNew(void) * * \param q the ippair queue to destroy */ -void IPPairQueueDestroy (IPPairQueue *q) +void IPPairQueueDestroy(IPPairQueue *q) { HQLOCK_DESTROY(q); } @@ -66,7 +66,7 @@ void IPPairQueueDestroy (IPPairQueue *q) * \param q queue * \param h ippair */ -void IPPairEnqueue (IPPairQueue *q, IPPair *h) +void IPPairEnqueue(IPPairQueue *q, IPPair *h) { #ifdef DEBUG BUG_ON(q == NULL || h == NULL); @@ -79,7 +79,7 @@ void IPPairEnqueue (IPPairQueue *q, IPPair *h) h->lnext = q->top; q->top->lprev = h; q->top = h; - /* only ippair */ + /* only ippair */ } else { q->top = h; q->bot = h; @@ -99,7 +99,7 @@ void IPPairEnqueue (IPPairQueue *q, IPPair *h) * * \retval h ippair or NULL if empty list. */ -IPPair *IPPairDequeue (IPPairQueue *q) +IPPair *IPPairDequeue(IPPairQueue *q) { HQLOCK_LOCK(q); @@ -113,7 +113,7 @@ IPPair *IPPairDequeue (IPPairQueue *q) if (q->bot->lprev != NULL) { q->bot = q->bot->lprev; q->bot->lnext = NULL; - /* just the one we remove, so now empty */ + /* just the one we remove, so now empty */ } else { q->top = NULL; q->bot = NULL; diff --git a/src/ippair-queue.h b/src/ippair-queue.h index cc3814b34f44..d7c2c114e544 100644 --- a/src/ippair-queue.h +++ b/src/ippair-queue.h @@ -28,18 +28,17 @@ #include "ippair.h" /** Spinlocks or Mutex for the ippair queues. */ -//#define HQLOCK_SPIN +// #define HQLOCK_SPIN #define HQLOCK_MUTEX #ifdef HQLOCK_SPIN - #ifdef HQLOCK_MUTEX - #error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX - #endif +#ifdef HQLOCK_MUTEX +#error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX +#endif #endif /* Define a queue for storing ippairs */ -typedef struct IPPairQueue_ -{ +typedef struct IPPairQueue_ { IPPair *top; IPPair *bot; uint32_t len; @@ -51,33 +50,33 @@ typedef struct IPPairQueue_ #elif defined HQLOCK_SPIN SCSpinlock s; #else - #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#error Enable HQLOCK_SPIN or HQLOCK_MUTEX #endif } IPPairQueue; #ifdef HQLOCK_SPIN - #define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) - #define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) - #define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) - #define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) - #define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) +#define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) +#define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) +#define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) +#define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) +#define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) #elif defined HQLOCK_MUTEX - #define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) - #define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) - #define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) - #define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) - #define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) +#define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) +#define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) +#define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) +#define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) +#define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) #else - #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#error Enable HQLOCK_SPIN or HQLOCK_MUTEX #endif /* prototypes */ IPPairQueue *IPPairQueueNew(void); IPPairQueue *IPPairQueueInit(IPPairQueue *); -void IPPairQueueDestroy (IPPairQueue *); +void IPPairQueueDestroy(IPPairQueue *); -void IPPairEnqueue (IPPairQueue *, IPPair *); -IPPair *IPPairDequeue (IPPairQueue *); +void IPPairEnqueue(IPPairQueue *, IPPair *); +IPPair *IPPairDequeue(IPPairQueue *); uint32_t IPPairQueueLen(IPPairQueue *); #endif /* __IPPAIR_QUEUE_H__ */ diff --git a/src/ippair-storage.c b/src/ippair-storage.c index a0e65c75df39..b5af1783419c 100644 --- a/src/ippair-storage.c +++ b/src/ippair-storage.c @@ -25,7 +25,7 @@ #include "suricata-common.h" #include "ippair-storage.h" -#include "util-unittest.h" +#include "util/unittest.h" unsigned int IPPairStorageSize(void) { diff --git a/src/ippair-timeout.c b/src/ippair-timeout.c index 0f510fbd7d5d..ae49e2e71da7 100644 --- a/src/ippair-timeout.c +++ b/src/ippair-timeout.c @@ -112,7 +112,7 @@ static uint32_t IPPairHashRowTimeout(IPPairHashRow *hb, IPPair *h, SCTime_t ts) h->hnext = NULL; h->hprev = NULL; - IPPairClearMemory (h); + IPPairClearMemory(h); /* no one is referring to this ippair, use_cnt 0, removed from hash * so we can unlock it and move it back to the spare queue. */ diff --git a/src/ippair.c b/src/ippair.c index b06f3d164414..ef0146169003 100644 --- a/src/ippair.c +++ b/src/ippair.c @@ -26,14 +26,14 @@ #include "suricata-common.h" #include "conf.h" -#include "util-debug.h" +#include "util/debug.h" #include "ippair.h" #include "ippair-storage.h" -#include "util-random.h" -#include "util-misc.h" -#include "util-byte.h" -#include "util-validate.h" +#include "util/random.h" +#include "util/misc.h" +#include "util/byte.h" +#include "util/validate.h" #include "ippair-queue.h" @@ -41,7 +41,7 @@ #include "detect-engine-tag.h" #include "detect-engine-threshold.h" -#include "util-hash-lookup3.h" +#include "util/hash-lookup3.h" static IPPair *IPPairGetUsedIPPair(void); @@ -50,9 +50,9 @@ IPPairHashRow *ippair_hash; /** queue with spare ippairs */ static IPPairQueue ippair_spare_q; IPPairConfig ippair_config; -SC_ATOMIC_DECLARE(uint64_t,ippair_memuse); -SC_ATOMIC_DECLARE(uint32_t,ippair_counter); -SC_ATOMIC_DECLARE(uint32_t,ippair_prune_idx); +SC_ATOMIC_DECLARE(uint64_t, ippair_memuse); +SC_ATOMIC_DECLARE(uint32_t, ippair_counter); +SC_ATOMIC_DECLARE(uint32_t, ippair_prune_idx); /** size of the ippair object. Maybe updated in IPPairInitConfig to include * the storage APIs additions. */ @@ -103,7 +103,7 @@ uint32_t IPPairSpareQueueGetSize(void) void IPPairMoveToSpare(IPPair *h) { IPPairEnqueue(&ippair_spare_q, h); - (void) SC_ATOMIC_SUB(ippair_counter, 1); + (void)SC_ATOMIC_SUB(ippair_counter, 1); } IPPair *IPPairAlloc(void) @@ -112,7 +112,7 @@ IPPair *IPPairAlloc(void) return NULL; } - (void) SC_ATOMIC_ADD(ippair_memuse, g_ippair_size); + (void)SC_ATOMIC_ADD(ippair_memuse, g_ippair_size); IPPair *h = SCCalloc(1, g_ippair_size); if (unlikely(h == NULL)) @@ -132,7 +132,7 @@ void IPPairFree(IPPair *h) IPPairClearMemory(h); SCMutexDestroy(&h->m); SCFree(h); - (void) SC_ATOMIC_SUB(ippair_memuse, g_ippair_size); + (void)SC_ATOMIC_SUB(ippair_memuse, g_ippair_size); } } @@ -159,7 +159,7 @@ void IPPairClearMemory(IPPair *h) } #define IPPAIR_DEFAULT_HASHSIZE 4096 -#define IPPAIR_DEFAULT_MEMCAP 16777216 +#define IPPAIR_DEFAULT_MEMCAP 16777216 #define IPPAIR_DEFAULT_PREALLOC 1000 /** \brief initialize the configuration @@ -172,8 +172,8 @@ void IPPairInitConfig(bool quiet) g_ippair_size = (uint16_t)(sizeof(IPPair) + IPPairStorageSize()); } - memset(&ippair_config, 0, sizeof(ippair_config)); - //SC_ATOMIC_INIT(flow_flags); + memset(&ippair_config, 0, sizeof(ippair_config)); + // SC_ATOMIC_INIT(flow_flags); SC_ATOMIC_INIT(ippair_counter); SC_ATOMIC_INIT(ippair_memuse); SC_ATOMIC_INIT(ippair_prune_idx); @@ -181,9 +181,9 @@ void IPPairInitConfig(bool quiet) IPPairQueueInit(&ippair_spare_q); /* set defaults */ - ippair_config.hash_rand = (uint32_t)RandomGet(); - ippair_config.hash_size = IPPAIR_DEFAULT_HASHSIZE; - ippair_config.prealloc = IPPAIR_DEFAULT_PREALLOC; + ippair_config.hash_rand = (uint32_t)RandomGet(); + ippair_config.hash_size = IPPAIR_DEFAULT_HASHSIZE; + ippair_config.prealloc = IPPAIR_DEFAULT_PREALLOC; SC_ATOMIC_SET(ippair_config.memcap, IPPAIR_DEFAULT_MEMCAP); /* Check if we have memcap and hash_size defined at config */ @@ -192,8 +192,7 @@ void IPPairInitConfig(bool quiet) /** set config values for memcap, prealloc and hash_size */ uint64_t ippair_memcap; - if ((ConfGet("ippair.memcap", &conf_val)) == 1) - { + if ((ConfGet("ippair.memcap", &conf_val)) == 1) { if (ParseSizeStringU64(conf_val, &ippair_memcap) < 0) { SCLogError("Error parsing ippair.memcap " "from conf file - %s. Killing engine", @@ -203,26 +202,22 @@ void IPPairInitConfig(bool quiet) SC_ATOMIC_SET(ippair_config.memcap, ippair_memcap); } } - if ((ConfGet("ippair.hash-size", &conf_val)) == 1) - { - if (StringParseUint32(&configval, 10, strlen(conf_val), - conf_val) > 0) { + if ((ConfGet("ippair.hash-size", &conf_val)) == 1) { + if (StringParseUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { ippair_config.hash_size = configval; } } - if ((ConfGet("ippair.prealloc", &conf_val)) == 1) - { - if (StringParseUint32(&configval, 10, strlen(conf_val), - conf_val) > 0) { + if ((ConfGet("ippair.prealloc", &conf_val)) == 1) { + if (StringParseUint32(&configval, 10, strlen(conf_val), conf_val) > 0) { ippair_config.prealloc = configval; } else { - WarnInvalidConfEntry("ippair.prealloc", "%"PRIu32, ippair_config.prealloc); + WarnInvalidConfEntry("ippair.prealloc", "%" PRIu32, ippair_config.prealloc); } } - SCLogDebug("IPPair config from suricata.yaml: memcap: %"PRIu64", hash-size: " - "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(ippair_config.memcap), - ippair_config.hash_size, ippair_config.prealloc); + SCLogDebug("IPPair config from suricata.yaml: memcap: %" PRIu64 ", hash-size: " + "%" PRIu32 ", prealloc: %" PRIu32, + SC_ATOMIC_GET(ippair_config.memcap), ippair_config.hash_size, ippair_config.prealloc); /* alloc hash memory */ uint64_t hash_size = ippair_config.hash_size * sizeof(IPPairHashRow); @@ -245,13 +240,13 @@ void IPPairInitConfig(bool quiet) for (i = 0; i < ippair_config.hash_size; i++) { HRLOCK_INIT(&ippair_hash[i]); } - (void) SC_ATOMIC_ADD(ippair_memuse, (ippair_config.hash_size * sizeof(IPPairHashRow))); + (void)SC_ATOMIC_ADD(ippair_memuse, (ippair_config.hash_size * sizeof(IPPairHashRow))); if (!quiet) { - SCLogConfig("allocated %"PRIu64" bytes of memory for the ippair hash... " - "%" PRIu32 " buckets of size %" PRIuMAX "", - SC_ATOMIC_GET(ippair_memuse), ippair_config.hash_size, - (uintmax_t)sizeof(IPPairHashRow)); + SCLogConfig("allocated %" PRIu64 " bytes of memory for the ippair hash... " + "%" PRIu32 " buckets of size %" PRIuMAX "", + SC_ATOMIC_GET(ippair_memuse), ippair_config.hash_size, + (uintmax_t)sizeof(IPPairHashRow)); } /* pre allocate ippairs */ @@ -270,13 +265,13 @@ void IPPairInitConfig(bool quiet) SCLogError("preallocating ippair failed: %s", strerror(errno)); exit(EXIT_FAILURE); } - IPPairEnqueue(&ippair_spare_q,h); + IPPairEnqueue(&ippair_spare_q, h); } if (!quiet) { - SCLogConfig("preallocated %" PRIu32 " ippairs of size %" PRIu16 "", - ippair_spare_q.len, g_ippair_size); - SCLogConfig("ippair memory usage: %"PRIu64" bytes, maximum: %"PRIu64, + SCLogConfig("preallocated %" PRIu32 " ippairs of size %" PRIu16 "", ippair_spare_q.len, + g_ippair_size); + SCLogConfig("ippair memory usage: %" PRIu64 " bytes, maximum: %" PRIu64, SC_ATOMIC_GET(ippair_memuse), SC_ATOMIC_GET(ippair_config.memcap)); } @@ -285,13 +280,13 @@ void IPPairInitConfig(bool quiet) /** \brief print some ippair stats * \warning Not thread safe */ -void IPPairPrintStats (void) +void IPPairPrintStats(void) { #ifdef IPPAIRBITS_STATS SCLogPerf("ippairbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", - ippairbits_added, ippairbits_removed, ippairbits_memuse_max); + ippairbits_added, ippairbits_removed, ippairbits_memuse_max); #endif /* IPPAIRBITS_STATS */ - SCLogPerf("ippair memory usage: %"PRIu64" bytes, maximum: %"PRIu64, + SCLogPerf("ippair memory usage: %" PRIu64 " bytes, maximum: %" PRIu64, SC_ATOMIC_GET(ippair_memuse), SC_ATOMIC_GET(ippair_config.memcap)); return; } @@ -306,7 +301,7 @@ void IPPairShutdown(void) IPPairPrintStats(); /* free spare queue */ - while((h = IPPairDequeue(&ippair_spare_q))) { + while ((h = IPPairDequeue(&ippair_spare_q))) { BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0); IPPairFree(h); } @@ -326,7 +321,7 @@ void IPPairShutdown(void) SCFreeAligned(ippair_hash); ippair_hash = NULL; } - (void) SC_ATOMIC_SUB(ippair_memuse, ippair_config.hash_size * sizeof(IPPairHashRow)); + (void)SC_ATOMIC_SUB(ippair_memuse, ippair_config.hash_size * sizeof(IPPairHashRow)); IPPairQueueDestroy(&ippair_spare_q); return; } @@ -410,12 +405,12 @@ static uint32_t IPPairGetKey(Address *a, Address *b) if (a->family == AF_INET) { uint32_t addrs[2] = { MIN(a->addr_data32[0], b->addr_data32[0]), - MAX(a->addr_data32[0], b->addr_data32[0]) }; + MAX(a->addr_data32[0], b->addr_data32[0]) }; uint32_t hash = hashword(addrs, 2, ippair_config.hash_rand); key = hash % ippair_config.hash_size; } else if (a->family == AF_INET6) { uint32_t addrs[8]; - if (IPPairHashRawAddressIPv6GtU32(&a->addr_data32[0],&b->addr_data32[0])) { + if (IPPairHashRawAddressIPv6GtU32(&a->addr_data32[0], &b->addr_data32[0])) { addrs[0] = b->addr_data32[0]; addrs[1] = b->addr_data32[1]; addrs[2] = b->addr_data32[2]; @@ -448,7 +443,7 @@ static inline int IPPairCompare(IPPair *p, Address *a, Address *b) { /* compare in both directions */ if ((CMP_ADDR(&p->a[0], a) && CMP_ADDR(&p->a[1], b)) || - (CMP_ADDR(&p->a[0], b) && CMP_ADDR(&p->a[1], a))) + (CMP_ADDR(&p->a[0], b) && CMP_ADDR(&p->a[1], a))) return 1; return 0; } @@ -471,12 +466,12 @@ static IPPair *IPPairGetNew(Address *a, Address *b) /* If we reached the max memcap, we get a used ippair */ if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) { /* declare state of emergency */ - //if (!(SC_ATOMIC_GET(ippair_flags) & IPPAIR_EMERGENCY)) { - // SC_ATOMIC_OR(ippair_flags, IPPAIR_EMERGENCY); + // if (!(SC_ATOMIC_GET(ippair_flags) & IPPAIR_EMERGENCY)) { + // SC_ATOMIC_OR(ippair_flags, IPPAIR_EMERGENCY); - /* under high load, waking up the flow mgr each time leads - * to high cpu usage. Flows are not timed out much faster if - * we check a 1000 times a second. */ + /* under high load, waking up the flow mgr each time leads + * to high cpu usage. Flows are not timed out much faster if + * we check a 1000 times a second. */ // FlowWakeupFlowManagerThread(); //} @@ -488,7 +483,7 @@ static IPPair *IPPairGetNew(Address *a, Address *b) /* freed a ippair, but it's unlocked */ } else { /* now see if we can alloc a new ippair */ - h = IPPairNew(a,b); + h = IPPairNew(a, b); if (h == NULL) { return NULL; } @@ -501,7 +496,7 @@ static IPPair *IPPairGetNew(Address *a, Address *b) /* ippair is initialized (recycled) but *unlocked* */ } - (void) SC_ATOMIC_ADD(ippair_counter, 1); + (void)SC_ATOMIC_ADD(ippair_counter, 1); SCMutexLock(&h->m); return h; } @@ -510,12 +505,12 @@ static void IPPairInit(IPPair *h, Address *a, Address *b) { COPY_ADDRESS(a, &h->a[0]); COPY_ADDRESS(b, &h->a[1]); - (void) IPPairIncrUsecnt(h); + (void)IPPairIncrUsecnt(h); } void IPPairRelease(IPPair *h) { - (void) IPPairDecrUsecnt(h); + (void)IPPairDecrUsecnt(h); SCMutexUnlock(&h->m); } @@ -537,7 +532,7 @@ void IPPairUnlock(IPPair *h) * * returns a *LOCKED* ippair or NULL */ -IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) +IPPair *IPPairGetIPPairFromHash(Address *a, Address *b) { IPPair *h = NULL; @@ -549,7 +544,7 @@ IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) /* see if the bucket already has a ippair */ if (hb->head == NULL) { - h = IPPairGetNew(a,b); + h = IPPairGetNew(a, b); if (h == NULL) { HRLOCK_UNLOCK(hb); return NULL; @@ -560,7 +555,7 @@ IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) hb->tail = h; /* got one, now lock, initialize and return */ - IPPairInit(h,a,b); + IPPairInit(h, a, b); HRLOCK_UNLOCK(hb); return h; @@ -578,7 +573,7 @@ IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) h = h->hnext; if (h == NULL) { - h = ph->hnext = IPPairGetNew(a,b); + h = ph->hnext = IPPairGetNew(a, b); if (h == NULL) { HRLOCK_UNLOCK(hb); return NULL; @@ -590,7 +585,7 @@ IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) h->hprev = ph; /* initialize and return */ - IPPairInit(h,a,b); + IPPairInit(h, a, b); HRLOCK_UNLOCK(hb); return h; @@ -616,7 +611,7 @@ IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) /* found our ippair, lock & return */ SCMutexLock(&h->m); - (void) IPPairIncrUsecnt(h); + (void)IPPairIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -625,7 +620,7 @@ IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) /* lock & return */ SCMutexLock(&h->m); - (void) IPPairIncrUsecnt(h); + (void)IPPairIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -636,7 +631,7 @@ IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) * * \retval h *LOCKED* ippair or NULL */ -IPPair *IPPairLookupIPPairFromHash (Address *a, Address *b) +IPPair *IPPairLookupIPPairFromHash(Address *a, Address *b) { IPPair *h = NULL; @@ -685,7 +680,7 @@ IPPair *IPPairLookupIPPairFromHash (Address *a, Address *b) /* found our ippair, lock & return */ SCMutexLock(&h->m); - (void) IPPairIncrUsecnt(h); + (void)IPPairIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -694,7 +689,7 @@ IPPair *IPPairLookupIPPairFromHash (Address *a, Address *b) /* lock & return */ SCMutexLock(&h->m); - (void) IPPairIncrUsecnt(h); + (void)IPPairIncrUsecnt(h); HRLOCK_UNLOCK(hb); return h; } @@ -757,11 +752,11 @@ static IPPair *IPPairGetUsedIPPair(void) h->hprev = NULL; HRLOCK_UNLOCK(hb); - IPPairClearMemory (h); + IPPairClearMemory(h); SCMutexUnlock(&h->m); - (void) SC_ATOMIC_ADD(ippair_prune_idx, (ippair_config.hash_size - cnt)); + (void)SC_ATOMIC_ADD(ippair_prune_idx, (ippair_config.hash_size - cnt)); return h; } diff --git a/src/ippair.h b/src/ippair.h index 3eef45ad8fcc..8639d510c6dd 100644 --- a/src/ippair.h +++ b/src/ippair.h @@ -25,34 +25,34 @@ #define __IPPAIR_H__ #include "decode.h" -#include "util-storage.h" +#include "util/storage.h" /** Spinlocks or Mutex for the flow buckets. */ -//#define HRLOCK_SPIN +// #define HRLOCK_SPIN #define HRLOCK_MUTEX #ifdef HRLOCK_SPIN - #ifdef HRLOCK_MUTEX - #error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX - #endif +#ifdef HRLOCK_MUTEX +#error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX +#endif #endif #ifdef HRLOCK_SPIN - #define HRLOCK_TYPE SCSpinlock - #define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) - #define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) - #define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) - #define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) - #define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) +#define HRLOCK_TYPE SCSpinlock +#define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) +#define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) +#define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) +#define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) +#define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) #elif defined HRLOCK_MUTEX - #define HRLOCK_TYPE SCMutex - #define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) - #define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) - #define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) - #define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) - #define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) +#define HRLOCK_TYPE SCMutex +#define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) +#define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) +#define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) +#define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) +#define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) #else - #error Enable HRLOCK_SPIN or HRLOCK_MUTEX +#error Enable HRLOCK_SPIN or HRLOCK_MUTEX #endif typedef struct IPPair_ { @@ -86,7 +86,7 @@ typedef struct IPPairHashRow_ { /** ippair hash table */ extern IPPairHashRow *ippair_hash; -#define IPPAIR_QUIET 1 +#define IPPAIR_QUIET 1 typedef struct IPPairConfig_ { SC_ATOMIC_DECLARE(uint64_t, memcap); @@ -102,31 +102,30 @@ typedef struct IPPairConfig_ { * \retval 1 it fits * \retval 0 no fit */ -#define IPPAIR_CHECK_MEMCAP(size) \ - ((((uint64_t)SC_ATOMIC_GET(ippair_memuse) + (uint64_t)(size)) <= SC_ATOMIC_GET(ippair_config.memcap))) +#define IPPAIR_CHECK_MEMCAP(size) \ + ((((uint64_t)SC_ATOMIC_GET(ippair_memuse) + (uint64_t)(size)) <= \ + SC_ATOMIC_GET(ippair_config.memcap))) -#define IPPairIncrUsecnt(h) \ - (void)SC_ATOMIC_ADD((h)->use_cnt, 1) -#define IPPairDecrUsecnt(h) \ - (void)SC_ATOMIC_SUB((h)->use_cnt, 1) +#define IPPairIncrUsecnt(h) (void)SC_ATOMIC_ADD((h)->use_cnt, 1) +#define IPPairDecrUsecnt(h) (void)SC_ATOMIC_SUB((h)->use_cnt, 1) extern IPPairConfig ippair_config; -SC_ATOMIC_EXTERN(uint64_t,ippair_memuse); -SC_ATOMIC_EXTERN(uint32_t,ippair_counter); -SC_ATOMIC_EXTERN(uint32_t,ippair_prune_idx); +SC_ATOMIC_EXTERN(uint64_t, ippair_memuse); +SC_ATOMIC_EXTERN(uint32_t, ippair_counter); +SC_ATOMIC_EXTERN(uint32_t, ippair_prune_idx); void IPPairInitConfig(bool quiet); void IPPairShutdown(void); void IPPairCleanup(void); -IPPair *IPPairLookupIPPairFromHash (Address *, Address *); -IPPair *IPPairGetIPPairFromHash (Address *, Address *); +IPPair *IPPairLookupIPPairFromHash(Address *, Address *); +IPPair *IPPairGetIPPairFromHash(Address *, Address *); void IPPairRelease(IPPair *); void IPPairLock(IPPair *); void IPPairClearMemory(IPPair *); void IPPairMoveToSpare(IPPair *); uint32_t IPPairSpareQueueGetSize(void); -void IPPairPrintStats (void); +void IPPairPrintStats(void); void IPPairRegisterUnittests(void); diff --git a/src/log-cf-common.c b/src/log-cf-common.c index 077813501c32..ac5a9831ced3 100644 --- a/src/log-cf-common.c +++ b/src/log-cf-common.c @@ -26,10 +26,10 @@ */ #include "log-cf-common.h" -#include "util-print.h" -#include "util-unittest.h" -#include "util-time.h" -#include "util-debug.h" +#include "util/print.h" +#include "util/unittest.h" +#include "util/time.h" +#include "util/debug.h" /** * \brief Creates a custom format node @@ -38,7 +38,7 @@ */ LogCustomFormatNode *LogCustomFormatNodeAlloc(void) { - LogCustomFormatNode * node = SCCalloc(1, sizeof(LogCustomFormatNode)); + LogCustomFormatNode *node = SCCalloc(1, sizeof(LogCustomFormatNode)); if (unlikely(node == NULL)) { SCLogError("Failed to alloc custom format node"); return NULL; @@ -53,7 +53,7 @@ LogCustomFormatNode *LogCustomFormatNodeAlloc(void) */ LogCustomFormat *LogCustomFormatAlloc(void) { - LogCustomFormat * cf = SCCalloc(1, sizeof(LogCustomFormat)); + LogCustomFormat *cf = SCCalloc(1, sizeof(LogCustomFormat)); if (unlikely(cf == NULL)) { SCLogError("Failed to alloc custom format"); return NULL; @@ -67,7 +67,7 @@ LogCustomFormat *LogCustomFormatAlloc(void) */ void LogCustomFormatNodeFree(LogCustomFormatNode *node) { - if (node==NULL) + if (node == NULL) return; SCFree(node); @@ -79,7 +79,7 @@ void LogCustomFormatNodeFree(LogCustomFormatNode *node) */ void LogCustomFormatFree(LogCustomFormat *cf) { - if (cf==NULL) + if (cf == NULL) return; for (size_t i = 0; i < cf->cf_n; ++i) { @@ -99,15 +99,15 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) uint32_t n; LogCustomFormatNode *node = NULL; - if (cf==NULL) + if (cf == NULL) return 0; - if (format==NULL) + if (format == NULL) return 0; - p=format; + p = format; - for (cf->cf_n = 0; cf->cf_n < LOG_MAXN_NODES-1 && p && *p != '\0';){ + for (cf->cf_n = 0; cf->cf_n < LOG_MAXN_NODES - 1 && p && *p != '\0';) { node = LogCustomFormatNodeAlloc(); if (node == NULL) { @@ -115,17 +115,17 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) } node->maxlen = 0; - if (*p != '%'){ + if (*p != '%') { /* Literal found in format string */ node->type = LOG_CF_LITERAL; np = strchr(p, '%'); - if (np == NULL){ - n = LOG_NODE_STRLEN-2; + if (np == NULL) { + n = LOG_NODE_STRLEN - 2; np = NULL; /* End */ - }else{ - n = np-p; + } else { + n = np - p; } - strlcpy(node->data,p,n+1); + strlcpy(node->data, p, n + 1); p = np; } else { /* Non Literal found in format string */ @@ -134,10 +134,10 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) p++; np = strchr(p, ']'); if (np != NULL) { - if (np-p > 0 && np-p < 10){ - long maxlen = strtol(p,NULL,10); + if (np - p > 0 && np - p < 10) { + long maxlen = strtol(p, NULL, 10); if (maxlen > 0 && maxlen < LOG_NODE_MAXOUTPUTLEN) { - node->maxlen = (uint32_t) maxlen; + node->maxlen = (uint32_t)maxlen; } } else { goto parsererror; @@ -149,10 +149,10 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) } if (*p == '{') { /* Simple format char */ np = strchr(p, '}'); - if (np != NULL && np-p > 1 && np-p < LOG_NODE_STRLEN-2) { + if (np != NULL && np - p > 1 && np - p < LOG_NODE_STRLEN - 2) { p++; - n = np-p; - strlcpy(node->data, p, n+1); + n = np - p; + strlcpy(node->data, p, n + 1); p = np; } else { goto parsererror; @@ -162,7 +162,7 @@ int LogCustomFormatParse(LogCustomFormat *cf, const char *format) node->data[0] = '\0'; } node->type = *p; - if (*p == '%'){ + if (*p == '%') { node->type = LOG_CF_LITERAL; strlcpy(node->data, "%", 2); } @@ -193,8 +193,8 @@ void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node) } #ifdef DEBUG - SCLogDebug("%d-> n.type=[%d] n.maxlen=[%d] n.data=[%s]", - cf->cf_n, node->type, node->maxlen, node->data); + SCLogDebug("%d-> n.type=[%d] n.maxlen=[%d] n.data=[%s]", cf->cf_n, node->type, node->maxlen, + node->data); #endif cf->cf_nodes[cf->cf_n] = node; @@ -214,16 +214,16 @@ void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const SCT time_t time = SCTIME_SECS(ts); struct tm local_tm; struct tm *timestamp = SCLocalTime(time, &local_tm); - char buf[128] = {0}; - const char * fmt_to_use = TIMESTAMP_DEFAULT_FORMAT; + char buf[128] = { 0 }; + const char *fmt_to_use = TIMESTAMP_DEFAULT_FORMAT; if (fmt && *fmt != '\0') { fmt_to_use = fmt; } - CreateFormattedTimeString (timestamp, fmt_to_use, buf, sizeof(buf)); - PrintRawUriBuf((char *)buffer->buffer, &buffer->offset, - buffer->size, (uint8_t *)buf,strlen(buf)); + CreateFormattedTimeString(timestamp, fmt_to_use, buf, sizeof(buf)); + PrintRawUriBuf( + (char *)buffer->buffer, &buffer->offset, buffer->size, (uint8_t *)buf, strlen(buf)); } #ifdef UNITTESTS @@ -254,7 +254,7 @@ static int LogCustomFormatTest01(void) /* * {buffer = "01/13/14-04:30:00", size = 62, offset = 17} */ - FAIL_IF_NOT( buffer->offset == 17); + FAIL_IF_NOT(buffer->offset == 17); FAIL_IF(strcmp((char *)buffer->buffer, "01/13/14-04:30:00") != 0); MemBufferFree(buffer); diff --git a/src/log-cf-common.h b/src/log-cf-common.h index 61d2d55af874..4f1e61530a22 100644 --- a/src/log-cf-common.h +++ b/src/log-cf-common.h @@ -28,38 +28,36 @@ #ifndef __LOG_CF_COMMON_H__ #define __LOG_CF_COMMON_H__ -#define LOG_MAXN_NODES 64 -#define LOG_NODE_STRLEN 256 +#define LOG_MAXN_NODES 64 +#define LOG_NODE_STRLEN 256 #define LOG_NODE_MAXOUTPUTLEN 8192 #define TIMESTAMP_DEFAULT_FORMAT "%D-%H:%M:%S" /* Common format nodes */ -#define LOG_CF_NONE "-" -#define LOG_CF_LITERAL '%' -#define LOG_CF_TIMESTAMP 't' +#define LOG_CF_NONE "-" +#define LOG_CF_LITERAL '%' +#define LOG_CF_TIMESTAMP 't' #define LOG_CF_TIMESTAMP_U 'z' -#define LOG_CF_CLIENT_IP 'a' -#define LOG_CF_SERVER_IP 'A' +#define LOG_CF_CLIENT_IP 'a' +#define LOG_CF_SERVER_IP 'A' #define LOG_CF_CLIENT_PORT 'p' #define LOG_CF_SERVER_PORT 'P' /* Line log common separators **/ -#define LOG_CF_STAR_SEPARATOR "[**]" +#define LOG_CF_STAR_SEPARATOR "[**]" #define LOG_CF_SPACE_SEPARATOR " " -#define LOG_CF_UNKNOWN_VALUE "-" +#define LOG_CF_UNKNOWN_VALUE "-" #define LOG_CF_WRITE_STAR_SEPARATOR(buffer) MemBufferWriteString(buffer, LOG_CF_STAR_SEPARATOR); -#define LOG_CF_WRITE_SPACE_SEPARATOR(buffer) \ - MemBufferWriteString(buffer, LOG_CF_SPACE_SEPARATOR); +#define LOG_CF_WRITE_SPACE_SEPARATOR(buffer) MemBufferWriteString(buffer, LOG_CF_SPACE_SEPARATOR); -#define LOG_CF_WRITE_UNKNOWN_VALUE(buffer) \ - MemBufferWriteString(buffer, LOG_CF_UNKNOWN_VALUE); +#define LOG_CF_WRITE_UNKNOWN_VALUE(buffer) MemBufferWriteString(buffer, LOG_CF_UNKNOWN_VALUE); /* Include */ #include "suricata-common.h" -#include "util-buffer.h" +#include "util/buffer.h" typedef struct LogCustomFormatNode_ { uint32_t type; /**< Node format type. ie: LOG_CF_LITERAL, ... */ @@ -67,14 +65,13 @@ typedef struct LogCustomFormatNode_ { char data[LOG_NODE_STRLEN]; /**< optional data. ie: http header name */ } LogCustomFormatNode; - typedef struct LogCustomFormat_ { - uint32_t cf_n; /**< Total number of custom string format nodes */ - LogCustomFormatNode *cf_nodes[LOG_MAXN_NODES]; /**< Custom format string nodes */ + uint32_t cf_n; /**< Total number of custom string format nodes */ + LogCustomFormatNode *cf_nodes[LOG_MAXN_NODES]; /**< Custom format string nodes */ } LogCustomFormat; -LogCustomFormatNode * LogCustomFormatNodeAlloc(void); -LogCustomFormat * LogCustomFormatAlloc(void); +LogCustomFormatNode *LogCustomFormatNodeAlloc(void); +LogCustomFormat *LogCustomFormatAlloc(void); void LogCustomFormatNodeFree(LogCustomFormatNode *node); void LogCustomFormatFree(LogCustomFormat *cf); diff --git a/src/log-httplog.c b/src/log-httplog.c deleted file mode 100644 index 68fa62e95b7f..000000000000 --- a/src/log-httplog.c +++ /dev/null @@ -1,633 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Ignacio Sanchez - * - * Implements http logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "log-httplog.h" -#include "app-layer-htp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" - -#include "util-logopenfile.h" -#include "util-time.h" -#include "log-cf-common.h" - -#define DEFAULT_LOG_FILENAME "http.log" - -#define MODULE_NAME "LogHttpLog" - -#define OUTPUT_BUFFER_SIZE 65535 - -TmEcode LogHttpLogThreadInit(ThreadVars *, const void *, void **); -TmEcode LogHttpLogThreadDeinit(ThreadVars *, void *); -static void LogHttpLogDeInitCtx(OutputCtx *); - -int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *, Flow *f, void *state, void *tx, uint64_t tx_id); - -void LogHttpLogRegister (void) -{ - OutputRegisterTxModule(LOGGER_HTTP, MODULE_NAME, "http-log", LogHttpLogInitCtx, ALPROTO_HTTP1, - LogHttpLogger, LogHttpLogThreadInit, LogHttpLogThreadDeinit, NULL); -} - -#define LOG_HTTP_CF_REQUEST_HOST 'h' -#define LOG_HTTP_CF_REQUEST_PROTOCOL 'H' -#define LOG_HTTP_CF_REQUEST_METHOD 'm' -#define LOG_HTTP_CF_REQUEST_URI 'u' -#define LOG_HTTP_CF_REQUEST_TIME 't' -#define LOG_HTTP_CF_REQUEST_HEADER 'i' -#define LOG_HTTP_CF_REQUEST_COOKIE 'C' -#define LOG_HTTP_CF_REQUEST_LEN 'b' -#define LOG_HTTP_CF_RESPONSE_STATUS 's' -#define LOG_HTTP_CF_RESPONSE_HEADER 'o' -#define LOG_HTTP_CF_RESPONSE_LEN 'B' - - -typedef struct LogHttpFileCtx_ { - LogFileCtx *file_ctx; - uint32_t flags; /** Store mode */ - LogCustomFormat *cf; -} LogHttpFileCtx; - -#define LOG_HTTP_DEFAULT 0 -#define LOG_HTTP_EXTENDED 1 -#define LOG_HTTP_CUSTOM 2 - -typedef struct LogHttpLogThread_ { - LogHttpFileCtx *httplog_ctx; - /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ - uint32_t uri_cnt; - - MemBuffer *buffer; -} LogHttpLogThread; - -/* Retrieves the selected cookie value */ -static uint32_t GetCookieValue(uint8_t *rawcookies, uint32_t rawcookies_len, char *cookiename, - uint8_t **cookievalue) -{ - uint8_t *p = rawcookies; - uint8_t *cn = p; /* ptr to cookie name start */ - uint8_t *cv = NULL; /* ptr to cookie value start */ - while (p < rawcookies + rawcookies_len) { - if (cv == NULL && *p == '=') { - cv = p + 1; - } else if (cv != NULL && (*p == ';' || p == rawcookies + rawcookies_len - 1) ) { - /* Found end of cookie */ - p++; - if (strlen(cookiename) == (unsigned int) (cv-cn-1) && - strncmp(cookiename, (char *) cn, cv-cn-1) == 0) { - *cookievalue = cv; - return (uint32_t) (p-cv); - } - cv = NULL; - cn = p + 1; - } - p++; - } - return 0; -} - -/* Custom format logging */ -static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const SCTime_t ts, char *srcip, - Port sp, char *dstip, Port dp) -{ - LogHttpFileCtx *httplog_ctx = aft->httplog_ctx; - uint32_t i; - uint32_t datalen; - char buf[128]; - - uint8_t *cvalue = NULL; - uint32_t cvalue_len = 0; - - htp_header_t *h_request_hdr; - htp_header_t *h_response_hdr; - - for (i = 0; i < httplog_ctx->cf->cf_n; i++) { - h_request_hdr = NULL; - h_response_hdr = NULL; - - LogCustomFormatNode * node = httplog_ctx->cf->cf_nodes[i]; - if (! node) /* Should never happen */ - continue; - - switch (node->type){ - case LOG_CF_LITERAL: - /* LITERAL */ - MemBufferWriteString(aft->buffer, "%s", node->data); - break; - case LOG_CF_TIMESTAMP: - /* TIMESTAMP */ - LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); - break; - case LOG_CF_TIMESTAMP_U: - /* TIMESTAMP USECONDS */ - snprintf(buf, sizeof(buf), "%06u", (unsigned int)SCTIME_USECS(ts)); - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)buf, MIN(strlen(buf), 6)); - break; - case LOG_CF_CLIENT_IP: - /* CLIENT IP ADDRESS */ - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)srcip,strlen(srcip)); - break; - case LOG_CF_SERVER_IP: - /* SERVER IP ADDRESS */ - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)dstip,strlen(dstip)); - break; - case LOG_CF_CLIENT_PORT: - /* CLIENT PORT */ - MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); - break; - case LOG_CF_SERVER_PORT: - /* SERVER PORT */ - MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); - break; - case LOG_HTTP_CF_REQUEST_METHOD: - /* METHOD */ - if (tx->request_method != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_method), - bstr_len(tx->request_method)); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_REQUEST_URI: - /* URI */ - if (tx->request_uri != NULL) { - datalen = node->maxlen; - if (datalen == 0 || datalen > bstr_len(tx->request_uri)) { - datalen = bstr_len(tx->request_uri); - } - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_uri), - datalen); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_REQUEST_HOST: - /* HOSTNAME */ - if (tx->request_hostname != NULL) - { - datalen = node->maxlen; - if (datalen == 0 || datalen > bstr_len(tx->request_hostname)) { - datalen = bstr_len(tx->request_hostname); - } - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_hostname), - datalen); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_REQUEST_PROTOCOL: - /* PROTOCOL */ - if (tx->request_protocol != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_protocol), - bstr_len(tx->request_protocol)); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_REQUEST_HEADER: - /* REQUEST HEADER */ - if (tx->request_headers != NULL) { - h_request_hdr = htp_table_get_c(tx->request_headers, node->data); - } - if (h_request_hdr != NULL) { - datalen = node->maxlen; - if (datalen == 0 || datalen > bstr_len(h_request_hdr->value)) { - datalen = bstr_len(h_request_hdr->value); - } - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)bstr_ptr(h_request_hdr->value), - datalen); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_REQUEST_COOKIE: - /* REQUEST COOKIE */ - if (tx->request_headers != NULL) { - h_request_hdr = htp_table_get_c(tx->request_headers, "Cookie"); - if (h_request_hdr != NULL) { - cvalue_len = GetCookieValue((uint8_t *) bstr_ptr(h_request_hdr->value), - bstr_len(h_request_hdr->value), (char *) node->data, - &cvalue); - } - } - if (cvalue_len > 0 && cvalue != NULL) { - datalen = node->maxlen; - if (datalen == 0 || datalen > cvalue_len) { - datalen = cvalue_len; - } - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, cvalue, datalen); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_REQUEST_LEN: - /* REQUEST LEN */ - MemBufferWriteString(aft->buffer, "%"PRIuMAX"", (uintmax_t)tx->request_message_len); - break; - case LOG_HTTP_CF_RESPONSE_STATUS: - /* RESPONSE STATUS */ - if (tx->response_status != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)bstr_ptr(tx->response_status), - bstr_len(tx->response_status)); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_RESPONSE_HEADER: - /* RESPONSE HEADER */ - if (tx->response_headers != NULL) { - h_response_hdr = htp_table_get_c(tx->response_headers, - node->data); - } - if (h_response_hdr != NULL) { - datalen = node->maxlen; - if (datalen == 0 || datalen > bstr_len(h_response_hdr->value)) { - datalen = bstr_len(h_response_hdr->value); - } - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)bstr_ptr(h_response_hdr->value), - datalen); - } else { - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - } - break; - case LOG_HTTP_CF_RESPONSE_LEN: - /* RESPONSE LEN */ - MemBufferWriteString(aft->buffer, "%"PRIuMAX"", (uintmax_t)tx->response_message_len); - break; - default: - /* NO MATCH */ - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - SCLogDebug("No matching parameter %%%c for custom http log.", node->type); - break; - } - } - MemBufferWriteString(aft->buffer, "\n"); -} - -static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) -{ - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - - /* referer */ - htp_header_t *h_referer = NULL; - if (tx->request_headers != NULL) { - h_referer = htp_table_get_c(tx->request_headers, "referer"); - } - if (h_referer != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(h_referer->value), - bstr_len(h_referer->value)); - } else { - MemBufferWriteString(aft->buffer, ""); - } - - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - - /* method */ - if (tx->request_method != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(tx->request_method), - bstr_len(tx->request_method)); - } - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - - /* protocol */ - if (tx->request_protocol != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(tx->request_protocol), - bstr_len(tx->request_protocol)); - } else { - MemBufferWriteString(aft->buffer, ""); - } - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - - /* response status */ - if (tx->response_status != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(tx->response_status), - bstr_len(tx->response_status)); - /* Redirect? */ - if ((tx->response_status_number > 300) && ((tx->response_status_number) < 303)) { - htp_header_t *h_location = htp_table_get_c(tx->response_headers, "location"); - if (h_location != NULL) { - MemBufferWriteString(aft->buffer, " => "); - - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(h_location->value), - bstr_len(h_location->value)); - } - } - } else { - MemBufferWriteString(aft->buffer, ""); - } - - /* length */ - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - MemBufferWriteString(aft->buffer, "%"PRIuMAX" bytes", (uintmax_t)tx->response_message_len); -} - -static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, Flow *f, HtpState *htp_state, htp_tx_t *tx, uint64_t tx_id, int ipproto) -{ - SCEnter(); - - LogHttpLogThread *aft = (LogHttpLogThread *)data; - LogHttpFileCtx *hlog = aft->httplog_ctx; - char timebuf[64]; - - /* check if we have HTTP state or not */ - CreateTimeString(p->ts, timebuf, sizeof(timebuf)); - - char srcip[46], dstip[46]; - Port sp, dp; - if ((PKT_IS_TOSERVER(p))) { - switch (ipproto) { - case AF_INET: - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); - break; - case AF_INET6: - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); - break; - default: - goto end; - } - sp = p->sp; - dp = p->dp; - } else { - switch (ipproto) { - case AF_INET: - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip)); - break; - case AF_INET6: - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip)); - break; - default: - goto end; - } - sp = p->dp; - dp = p->sp; - } - - SCLogDebug("got a HTTP request and now logging !!"); - - /* reset */ - MemBufferReset(aft->buffer); - - if (hlog->flags & LOG_HTTP_CUSTOM) { - LogHttpLogCustom(aft, tx, p->ts, srcip, sp, dstip, dp); - } else { - /* time */ - MemBufferWriteString(aft->buffer, "%s ", timebuf); - - /* hostname */ - if (tx->request_hostname != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(tx->request_hostname), - bstr_len(tx->request_hostname)); - } else { - MemBufferWriteString(aft->buffer, ""); - } - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - - /* uri */ - if (tx->request_uri != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(tx->request_uri), - bstr_len(tx->request_uri)); - } - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - - /* user agent */ - htp_header_t *h_user_agent = NULL; - if (tx->request_headers != NULL) { - h_user_agent = htp_table_get_c(tx->request_headers, "user-agent"); - } - if (h_user_agent != NULL) { - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)bstr_ptr(h_user_agent->value), - bstr_len(h_user_agent->value)); - } else { - MemBufferWriteString(aft->buffer, ""); - } - if (hlog->flags & LOG_HTTP_EXTENDED) { - LogHttpLogExtended(aft, tx); - } - - /* ip/tcp header info */ - LOG_CF_WRITE_STAR_SEPARATOR(aft->buffer); - MemBufferWriteString(aft->buffer, - "%s:%" PRIu16 " -> %s:%" PRIu16 "\n", - srcip, sp, dstip, dp); - } - - aft->uri_cnt ++; - - hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), - MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - -end: - SCReturnInt(0); - -} - -int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - SCEnter(); - - if (!(PKT_IS_TCP(p))) { - SCReturnInt(TM_ECODE_OK); - } - - int r = 0; - if (PKT_IS_IPV4(p)) { - r = LogHttpLogIPWrapper(tv, thread_data, p, f, (HtpState *)state, (htp_tx_t *)tx, tx_id, AF_INET); - } else if (PKT_IS_IPV6(p)) { - r = LogHttpLogIPWrapper(tv, thread_data, p, f, (HtpState *)state, (htp_tx_t *)tx, tx_id, AF_INET6); - } - - SCReturnInt(r); -} - -TmEcode LogHttpLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogHttpLogThread *aft = SCCalloc(1, sizeof(LogHttpLogThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - - if(initdata == NULL) - { - SCLogDebug("Error getting context for LogHTTPLog. \"initdata\" argument NULL"); - SCFree(aft); - return TM_ECODE_FAILED; - } - - aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); - if (aft->buffer == NULL) { - SCFree(aft); - return TM_ECODE_FAILED; - } - - /* Use the Output Context (file pointer and mutex) */ - aft->httplog_ctx= ((OutputCtx *)initdata)->data; - - *data = (void *)aft; - return TM_ECODE_OK; -} - -TmEcode LogHttpLogThreadDeinit(ThreadVars *t, void *data) -{ - LogHttpLogThread *aft = (LogHttpLogThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - - MemBufferFree(aft->buffer); - /* clear memory */ - memset(aft, 0, sizeof(LogHttpLogThread)); - - SCFree(aft); - return TM_ECODE_OK; -} - -/** \brief Create a new http log LogFileCtx. - * \param conf Pointer to ConfNode containing this loggers configuration. - * \return NULL if failure, LogFileCtx* to the file_ctx if succesful - * */ -OutputInitResult LogHttpLogInitCtx(ConfNode *conf) -{ - OutputInitResult result = { NULL, false }; - LogFileCtx* file_ctx = LogFileNewCtx(); - if(file_ctx == NULL) { - SCLogError("couldn't create new file_ctx"); - return result; - } - - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { - LogFileFreeCtx(file_ctx); - return result; - } - - LogHttpFileCtx *httplog_ctx = SCCalloc(1, sizeof(LogHttpFileCtx)); - if (unlikely(httplog_ctx == NULL)) { - LogFileFreeCtx(file_ctx); - return result; - } - - httplog_ctx->file_ctx = file_ctx; - - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - const char *custom = ConfNodeLookupChildValue(conf, "custom"); - const char *customformat = ConfNodeLookupChildValue(conf, "customformat"); - - /* If custom logging format is selected, lets parse it */ - if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { - - httplog_ctx->cf = LogCustomFormatAlloc(); - if (!httplog_ctx->cf) { - goto errorfree; - } - - httplog_ctx->flags |= LOG_HTTP_CUSTOM; - - /* Parsing */ - if ( ! LogCustomFormatParse(httplog_ctx->cf, customformat)) { - goto parsererror; - } - } else { - if (extended == NULL) { - httplog_ctx->flags |= LOG_HTTP_DEFAULT; - } else { - if (ConfValIsTrue(extended)) { - httplog_ctx->flags |= LOG_HTTP_EXTENDED; - } - } - } - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - goto parsererror; - } - - output_ctx->data = httplog_ctx; - output_ctx->DeInit = LogHttpLogDeInitCtx; - - SCLogDebug("HTTP log output initialized"); - - /* enable the logger for the app layer */ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP1); - - result.ctx = output_ctx; - result.ok = true; - return result; - -parsererror: - SCLogError("Syntax error in custom http log format string."); -errorfree: - LogCustomFormatFree(httplog_ctx->cf); - LogFileFreeCtx(file_ctx); - SCFree(httplog_ctx); - return result; - -} - -static void LogHttpLogDeInitCtx(OutputCtx *output_ctx) -{ - LogHttpFileCtx *httplog_ctx = (LogHttpFileCtx *)output_ctx->data; - LogCustomFormatFree(httplog_ctx->cf); - LogFileFreeCtx(httplog_ctx->file_ctx); - SCFree(httplog_ctx); - SCFree(output_ctx); -} diff --git a/src/log-pcap.c b/src/log-pcap.c index 6039e057b8a4..45d5baa94c79 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -27,7 +27,7 @@ #include "suricata-common.h" #ifdef HAVE_LIBLZ4 #include -#include "util-fmemopen.h" +#include "util/fmemopen.h" #endif /* HAVE_LIBLZ4 */ #if defined(HAVE_DIRENT_H) && defined(HAVE_FNMATCH_H) @@ -44,27 +44,27 @@ #include "stream.h" #include "stream-tcp-reassemble.h" -#include "output.h" +#include "output/output.h" -#include "util-buffer.h" -#include "util-byte.h" -#include "util-conf.h" -#include "util-cpu.h" -#include "util-datalink.h" -#include "util-misc.h" -#include "util-path.h" -#include "util-profiling.h" -#include "util-time.h" +#include "util/buffer.h" +#include "util/byte.h" +#include "util/conf.h" +#include "util/cpu.h" +#include "util/datalink.h" +#include "util/misc.h" +#include "util/path.h" +#include "util/profiling.h" +#include "util/time.h" -#define DEFAULT_LOG_FILENAME "pcaplog" -#define MODULE_NAME "PcapLog" -#define MIN_LIMIT 4 * 1024 * 1024 -#define DEFAULT_LIMIT 100 * 1024 * 1024 -#define DEFAULT_FILE_LIMIT 0 +#define DEFAULT_LOG_FILENAME "pcaplog" +#define MODULE_NAME "PcapLog" +#define MIN_LIMIT 4 * 1024 * 1024 +#define DEFAULT_LIMIT 100 * 1024 * 1024 +#define DEFAULT_FILE_LIMIT 0 -#define LOGMODE_NORMAL 0 -#define LOGMODE_SGUIL 1 -#define LOGMODE_MULTI 2 +#define LOGMODE_NORMAL 0 +#define LOGMODE_SGUIL 1 +#define LOGMODE_MULTI 2 typedef enum LogModeConditionalType_ { LOGMODE_COND_ALL, @@ -72,20 +72,20 @@ typedef enum LogModeConditionalType_ { LOGMODE_COND_TAG } LogModeConditionalType; -#define RING_BUFFER_MODE_DISABLED 0 -#define RING_BUFFER_MODE_ENABLED 1 +#define RING_BUFFER_MODE_DISABLED 0 +#define RING_BUFFER_MODE_ENABLED 1 -#define TS_FORMAT_SEC 0 -#define TS_FORMAT_USEC 1 +#define TS_FORMAT_SEC 0 +#define TS_FORMAT_USEC 1 -#define USE_STREAM_DEPTH_DISABLED 0 -#define USE_STREAM_DEPTH_ENABLED 1 +#define USE_STREAM_DEPTH_DISABLED 0 +#define USE_STREAM_DEPTH_ENABLED 1 -#define HONOR_PASS_RULES_DISABLED 0 -#define HONOR_PASS_RULES_ENABLED 1 +#define HONOR_PASS_RULES_DISABLED 0 +#define HONOR_PASS_RULES_ENABLED 1 -#define PCAP_SNAPLEN 262144 -#define PCAP_BUFFER_TIMEOUT 1000000 // microseconds +#define PCAP_SNAPLEN 262144 +#define PCAP_BUFFER_TIMEOUT 1000000 // microseconds SC_ATOMIC_DECLARE(uint32_t, thread_cnt); @@ -110,7 +110,7 @@ typedef struct PcapLogProfileData_ { uint64_t cnt; } PcapLogProfileData; -#define MAX_TOKS 9 +#define MAX_TOKS 9 #define MAX_FILENAMELEN 513 enum PcapLogCompressionFormat { @@ -139,10 +139,10 @@ typedef struct PcapLogCompressionData_ { * Used for storing file options. */ typedef struct PcapLogData_ { - int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */ - int honor_pass_rules; /**< don't log if pass rules have matched */ + int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */ + int honor_pass_rules; /**< don't log if pass rules have matched */ SCMutex plog_lock; - uint64_t pkt_cnt; /**< total number of packets */ + uint64_t pkt_cnt; /**< total number of packets */ struct pcap_pkthdr *h; /**< pcap header struct */ char *filename; /**< current filename */ int mode; /**< normal or sguil */ @@ -168,14 +168,14 @@ typedef struct PcapLogData_ { TAILQ_HEAD(, PcapFileName_) pcap_file_list; - uint32_t thread_number; /**< thread number, first thread is 1, second 2, etc */ - int use_ringbuffer; /**< ring buffer mode enabled or disabled */ - int timestamp_format; /**< timestamp format sec or usec */ - char *prefix; /**< filename prefix */ - const char *suffix; /**< filename suffix */ - char dir[PATH_MAX]; /**< pcap log directory */ + uint32_t thread_number; /**< thread number, first thread is 1, second 2, etc */ + int use_ringbuffer; /**< ring buffer mode enabled or disabled */ + int timestamp_format; /**< timestamp format sec or usec */ + char *prefix; /**< filename prefix */ + const char *suffix; /**< filename suffix */ + char dir[PATH_MAX]; /**< pcap log directory */ int reported; - int threads; /**< number of threads (only set in the global) */ + int threads; /**< number of threads (only set in the global) */ char *filename_parts[MAX_TOKS]; int filename_part_cnt; struct timeval last_pcap_dump; @@ -210,20 +210,18 @@ static bool PcapLogCondition(ThreadVars *, void *, const Packet *); void PcapLogRegister(void) { - OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log", - PcapLogInitCtx, PcapLog, PcapLogCondition, PcapLogDataInit, - PcapLogDataDeinit, NULL); + OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log", PcapLogInitCtx, PcapLog, + PcapLogCondition, PcapLogDataInit, PcapLogDataDeinit, NULL); PcapLogProfileSetup(); SC_ATOMIC_INIT(thread_cnt); SC_ATOMIC_SET(thread_cnt, 1); /* first id is 1 */ return; } -#define PCAPLOG_PROFILE_START \ - uint64_t pcaplog_profile_ticks = UtilCpuGetTicks() +#define PCAPLOG_PROFILE_START uint64_t pcaplog_profile_ticks = UtilCpuGetTicks() -#define PCAPLOG_PROFILE_END(prof) \ - (prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \ +#define PCAPLOG_PROFILE_END(prof) \ + (prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \ (prof).cnt++ static bool PcapLogCondition(ThreadVars *tv, void *thread_data, const Packet *p) @@ -271,8 +269,7 @@ static int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl) /* pcap_dump_close() has closed its output ``file'', * so we need to call fmemopen again. */ - comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, - comp->pcap_buf_size, "w"); + comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, comp->pcap_buf_size, "w"); if (comp->pcap_buf_wrapper == NULL) { SCLogError("SCFmemopen failed: %s", strerror(errno)); return TM_ECODE_FAILED; @@ -293,8 +290,8 @@ static int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl) /* pcap_dump_close did not write any data because we call * pcap_dump_flush() after every write when writing * compressed output. */ - uint64_t bytes_written = LZ4F_compressEnd(comp->lz4f_context, - comp->buffer, comp->buffer_size, NULL); + uint64_t bytes_written = + LZ4F_compressEnd(comp->lz4f_context, comp->buffer, comp->buffer_size, NULL); if (LZ4F_isError(bytes_written)) { SCLogError("LZ4F_compressEnd: %s", LZ4F_getErrorName(bytes_written)); return TM_ECODE_FAILED; @@ -345,7 +342,7 @@ static int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl) PCAPLOG_PROFILE_START; - if (PcapLogCloseFile(t,pl) < 0) { + if (PcapLogCloseFile(t, pl) < 0) { SCLogDebug("PcapLogCloseFile failed"); return -1; } @@ -362,15 +359,15 @@ static int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl) /* Remove directory if Sguil mode and no files left in sguil dir */ if (pl->mode == LOGMODE_SGUIL) { - pfnext = TAILQ_NEXT(pf,next); + pfnext = TAILQ_NEXT(pf, next); if (strcmp(pf->dirname, pfnext->dirname) == 0) { SCLogDebug("Current entry dir %s and next entry %s " - "are equal: not removing dir", + "are equal: not removing dir", pf->dirname, pfnext->dirname); } else { SCLogDebug("current entry %s and %s are " - "not equal: removing dir", + "not equal: removing dir", pf->dirname, pfnext->dirname); if (remove(pf->dirname) != 0) { @@ -414,8 +411,7 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p) if (pl->pcap_dumper == NULL) { if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) { - if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle, - pl->filename)) == NULL) { + if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle, pl->filename)) == NULL) { if (!pl->pcap_open_err) { SCLogError("Error opening dump file %s", pcap_geterr(pl->pcap_dead_handle)); pl->pcap_open_err = true; @@ -453,8 +449,8 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p) pl->pcap_open_err = false; } - uint64_t bytes_written = LZ4F_compressBegin(comp->lz4f_context, - comp->buffer, comp->buffer_size, NULL); + uint64_t bytes_written = + LZ4F_compressBegin(comp->lz4f_context, comp->buffer, comp->buffer_size, NULL); if (LZ4F_isError(bytes_written)) { SCLogError("LZ4F_compressBegin: %s", LZ4F_getErrorName(bytes_written)); return TM_ECODE_FAILED; @@ -589,7 +585,7 @@ static void PcapLogDumpSegments( * \retval TM_ECODE_OK on succes * \retval TM_ECODE_FAILED on serious error */ -static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) +static int PcapLog(ThreadVars *t, void *thread_data, const Packet *p) { size_t len; int rotate = 0; @@ -641,7 +637,7 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) PcapLogCompressionData *comp = &pl->compression; if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_NONE) { if ((pl->size_current + len) > pl->size_limit || rotate) { - if (PcapLogRotateFile(t,pl) < 0) { + if (PcapLogRotateFile(t, pl) < 0) { PcapLogUnlock(pl); SCLogDebug("rotation of pcap failed"); return TM_ECODE_FAILED; @@ -656,9 +652,8 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) * bytes that have been fed into lz4 since the last write, and * act as if they would be written uncompressed. */ - if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit || - rotate) { - if (PcapLogRotateFile(t,pl) < 0) { + if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit || rotate) { + if (PcapLogRotateFile(t, pl) < 0) { PcapLogUnlock(pl); SCLogDebug("rotation of pcap failed"); return TM_ECODE_FAILED; @@ -732,8 +727,8 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) PCAPLOG_PROFILE_END(pl->profile_write); pl->profile_data_size += len; - SCLogDebug("pl->size_current %"PRIu64", pl->size_limit %"PRIu64, - pl->size_current, pl->size_limit); + SCLogDebug("pl->size_current %" PRIu64 ", pl->size_limit %" PRIu64, pl->size_current, + pl->size_limit); PcapLogUnlock(pl); return TM_ECODE_OK; @@ -801,8 +796,8 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) SCFree(copy); return NULL; } - copy_comp->pcap_buf_wrapper = SCFmemopen(copy_comp->pcap_buf, - copy_comp->pcap_buf_size, "w"); + copy_comp->pcap_buf_wrapper = + SCFmemopen(copy_comp->pcap_buf, copy_comp->pcap_buf_size, "w"); if (copy_comp->pcap_buf_wrapper == NULL) { SCLogError("SCFmemopen failed: %s", strerror(errno)); SCFree(copy_comp->buffer); @@ -814,8 +809,7 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) /* Initialize a new compression context. */ - LZ4F_errorCode_t errcode = - LZ4F_createCompressionContext(©_comp->lz4f_context, 1); + LZ4F_errorCode_t errcode = LZ4F_createCompressionContext(©_comp->lz4f_context, 1); if (LZ4F_isError(errcode)) { SCLogError("LZ4F_createCompressionContext failed: %s", LZ4F_getErrorName(errcode)); fclose(copy_comp->pcap_buf_wrapper); @@ -851,8 +845,7 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) } #ifdef INIT_RING_BUFFER -static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs, - uint32_t *usecs) +static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs, uint32_t *usecs) { char buf[PATH_MAX]; size_t copylen; @@ -894,8 +887,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) { char pattern[PATH_MAX]; - SCLogInfo("Initializing PCAP ring buffer for %s/%s.", - pl->dir, pl->prefix); + SCLogInfo("Initializing PCAP ring buffer for %s/%s.", pl->dir, pl->prefix); strlcpy(pattern, pl->dir, PATH_MAX); if (pattern[strlen(pattern) - 1] != '/') { @@ -917,7 +909,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) return TM_ECODE_FAILED; case 'n': { char tmp[PATH_MAX]; - snprintf(tmp, PATH_MAX, "%"PRIu32, pl->thread_number); + snprintf(tmp, PATH_MAX, "%" PRIu32, pl->thread_number); strlcat(pattern, tmp, PATH_MAX); break; } @@ -985,7 +977,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) } else { /* Ordered insert. */ PcapFileName *it = NULL; - TAILQ_FOREACH(it, &pl->pcap_file_list, next) { + TAILQ_FOREACH (it, &pl->pcap_file_list, next) { if (pf->secs < it->secs) { break; } else if (pf->secs == it->secs && pf->usecs < it->usecs) { @@ -1188,8 +1180,7 @@ static void PcapLogDataFree(PcapLogData *pl) SCFree(pl->compression.buffer); fclose(pl->compression.pcap_buf_wrapper); SCFree(pl->compression.pcap_buf); - LZ4F_errorCode_t errcode = - LZ4F_freeCompressionContext(pl->compression.lz4f_context); + LZ4F_errorCode_t errcode = LZ4F_freeCompressionContext(pl->compression.lz4f_context); if (LZ4F_isError(errcode)) { SCLogWarning("Error freeing lz4 context."); } @@ -1212,7 +1203,7 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data) PcapLogData *pl = td->pcap_log; if (pl->pcap_dumper != NULL) { - if (PcapLogCloseFile(t,pl) < 0) { + if (PcapLogCloseFile(t, pl) < 0) { SCLogDebug("PcapLogCloseFile failed"); } } @@ -1242,7 +1233,6 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data) return TM_ECODE_OK; } - static int ParseFilename(PcapLogData *pl, const char *filename) { char *toks[MAX_TOKS] = { NULL }; @@ -1255,7 +1245,7 @@ static int ParseFilename(PcapLogData *pl, const char *filename) if (filename) { filename_len = strlen(filename); - if (filename_len > (MAX_FILENAMELEN-1)) { + if (filename_len > (MAX_FILENAMELEN - 1)) { SCLogError("invalid filename option. Max filename-length: %d", MAX_FILENAMELEN - 1); goto error; } @@ -1269,7 +1259,7 @@ static int ParseFilename(PcapLogData *pl, const char *filename) str[s++] = filename[i]; if (filename[i] == '%') { - str[s-1] = '\0'; + str[s - 1] = '\0'; SCLogDebug("filename with %%-sign: %s", str); p = SCStrdup(str); @@ -1279,19 +1269,20 @@ static int ParseFilename(PcapLogData *pl, const char *filename) s = 0; - if (i+1 < (int)strlen(filename)) { + if (i + 1 < (int)strlen(filename)) { if (tok >= MAX_TOKS) { SCLogError("invalid filename option. Max 2 %%-sign options"); goto error; } - if (filename[i+1] != 'n' && filename[i+1] != 't' && filename[i+1] != 'i') { + if (filename[i + 1] != 'n' && filename[i + 1] != 't' && + filename[i + 1] != 'i') { SCLogError( "invalid filename option. Valid %%-sign options: %%n, %%i and %%t"); goto error; } str[0] = '%'; - str[1] = filename[i+1]; + str[1] = filename[i + 1]; str[2] = '\0'; p = SCStrdup(str); if (p == NULL) @@ -1311,7 +1302,6 @@ static int ParseFilename(PcapLogData *pl, const char *filename) if (tok >= MAX_TOKS) { SCLogError("invalid filename option. Max 3 %%-sign options"); goto error; - } str[s++] = '\0'; p = SCStrdup(str); @@ -1410,8 +1400,9 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) exit(EXIT_FAILURE); } if (pl->size_limit < 4096) { - SCLogInfo("pcap-log \"limit\" value of %"PRIu64" assumed to be pre-1.2 " - "style: setting limit to %"PRIu64"mb", pl->size_limit, pl->size_limit); + SCLogInfo("pcap-log \"limit\" value of %" PRIu64 " assumed to be pre-1.2 " + "style: setting limit to %" PRIu64 "mb", + pl->size_limit, pl->size_limit); uint64_t size = pl->size_limit * 1024 * 1024; pl->size_limit = size; } else if (pl->size_limit < MIN_LIMIT) { @@ -1451,20 +1442,17 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) const char *log_dir = NULL; log_dir = ConfigGetLogDirectory(); - strlcpy(pl->dir, - log_dir, sizeof(pl->dir)); - SCLogInfo("Using log dir %s", pl->dir); + strlcpy(pl->dir, log_dir, sizeof(pl->dir)); + SCLogInfo("Using log dir %s", pl->dir); } } else { if (PathIsAbsolute(s_dir)) { - strlcpy(pl->dir, - s_dir, sizeof(pl->dir)); + strlcpy(pl->dir, s_dir, sizeof(pl->dir)); } else { const char *log_dir = NULL; log_dir = ConfigGetLogDirectory(); - snprintf(pl->dir, sizeof(pl->dir), "%s/%s", - log_dir, s_dir); + snprintf(pl->dir, sizeof(pl->dir), "%s/%s", log_dir, s_dir); } struct stat stat_buf; @@ -1477,8 +1465,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) SCLogInfo("Using log dir %s", pl->dir); } - const char *compression_str = ConfNodeLookupChildValue(conf, - "compression"); + const char *compression_str = ConfNodeLookupChildValue(conf, "compression"); PcapLogCompressionData *comp = &pl->compression; if (compression_str == NULL || strcmp(compression_str, "none") == 0) { @@ -1502,15 +1489,14 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) /* Use SCFmemopen so we can make pcap_dump write to a buffer. */ - comp->pcap_buf_size = sizeof(struct pcap_file_header) + - sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN; + comp->pcap_buf_size = + sizeof(struct pcap_file_header) + sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN; comp->pcap_buf = SCMalloc(comp->pcap_buf_size); if (comp->pcap_buf == NULL) { SCLogError("SCMalloc failed: %s", strerror(errno)); exit(EXIT_FAILURE); } - comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, - comp->pcap_buf_size, "w"); + comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, comp->pcap_buf_size, "w"); if (comp->pcap_buf_wrapper == NULL) { SCLogError("SCFmemopen failed: %s", strerror(errno)); exit(EXIT_FAILURE); @@ -1523,8 +1509,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) comp->lz4f_prefs.frameInfo.blockMode = LZ4F_blockLinked; if (ConfNodeChildValueIsTrue(conf, "lz4-checksum")) { comp->lz4f_prefs.frameInfo.contentChecksumFlag = 1; - } - else { + } else { comp->lz4f_prefs.frameInfo.contentChecksumFlag = 0; } intmax_t lvl = 0; @@ -1542,7 +1527,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) /* Allocate resources for lz4. */ LZ4F_errorCode_t errcode = - LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1); + LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1); if (LZ4F_isError(errcode)) { SCLogError("LZ4F_createCompressionContext failed: %s", LZ4F_getErrorName(errcode)); @@ -1551,8 +1536,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) /* Calculate the size of the lz4 output buffer. */ - comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size, - &comp->lz4f_prefs); + comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size, &comp->lz4f_prefs); comp->buffer = SCMalloc(comp->buffer_size); if (unlikely(comp->buffer == NULL)) { @@ -1572,8 +1556,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) PcapLogDataFree(pl); return result; #endif /* HAVE_LIBLZ4 */ - } - else { + } else { SCLogError("Unsupported pcap-log " "compression format: %s", compression_str); @@ -1606,16 +1589,16 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) if (ParseFilename(pl, filename) != 0) exit(EXIT_FAILURE); - SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL ? - "Sguil compatible" : (pl->mode == LOGMODE_MULTI ? "multi" : "normal")); + SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL + ? "Sguil compatible" + : (pl->mode == LOGMODE_MULTI ? "multi" : "normal")); uint32_t max_file_limit = DEFAULT_FILE_LIMIT; if (conf != NULL) { const char *max_number_of_files_s = NULL; max_number_of_files_s = ConfNodeLookupChildValue(conf, "max-files"); if (max_number_of_files_s != NULL) { - if (StringParseUint32(&max_file_limit, 10, 0, - max_number_of_files_s) == -1) { + if (StringParseUint32(&max_file_limit, 10, 0, max_number_of_files_s) == -1) { SCLogError("Failed to initialize " "pcap-log output, invalid number of files limit: %s", max_number_of_files_s); @@ -1696,7 +1679,7 @@ static void PcapLogFileDeInitCtx(OutputCtx *output_ctx) PcapLogData *pl = output_ctx->data; PcapFileName *pf = NULL; - TAILQ_FOREACH(pf, &pl->pcap_file_list, next) { + TAILQ_FOREACH (pf, &pl->pcap_file_list, next) { SCLogDebug("PCAP files left at exit: %s\n", pf->filename); } PcapLogDataFree(pl); @@ -1747,8 +1730,8 @@ static int PcapLogOpenFileCtx(PcapLogData *pl) char dirname[32], dirfull[PATH_MAX] = ""; - snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d", - tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday); + snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d", tms->tm_year + 1900, tms->tm_mon + 1, + tms->tm_mday); /* create the filename to use */ int ret = snprintf(dirfull, sizeof(dirfull), "%s/%s", pl->dir, dirname); @@ -1801,7 +1784,7 @@ static int PcapLogOpenFileCtx(PcapLogData *pl) int i; for (i = 0; i < pl->filename_part_cnt; i++) { - if (pl->filename_parts[i] == NULL ||strlen(pl->filename_parts[i]) == 0) + if (pl->filename_parts[i] == NULL || strlen(pl->filename_parts[i]) == 0) continue; /* handle variables */ @@ -1810,28 +1793,27 @@ static int PcapLogOpenFileCtx(PcapLogData *pl) if (strlen(pl->filename_parts[i]) < 2) continue; - switch(pl->filename_parts[i][1]) { + switch (pl->filename_parts[i][1]) { case 'n': snprintf(str, sizeof(str), "%u", pl->thread_number); break; - case 'i': - { + case 'i': { long thread_id = SCGetThreadIdLong(); - snprintf(str, sizeof(str), "%"PRIu64, (uint64_t)thread_id); + snprintf(str, sizeof(str), "%" PRIu64, (uint64_t)thread_id); break; } case 't': - /* create the filename to use */ - if (pl->timestamp_format == TS_FORMAT_SEC) { - snprintf(str, sizeof(str), "%" PRIu32, (uint32_t)SCTIME_SECS(ts)); - } else { - snprintf(str, sizeof(str), "%" PRIu32 ".%" PRIu32, - (uint32_t)SCTIME_SECS(ts), (uint32_t)SCTIME_USECS(ts)); - } + /* create the filename to use */ + if (pl->timestamp_format == TS_FORMAT_SEC) { + snprintf(str, sizeof(str), "%" PRIu32, (uint32_t)SCTIME_SECS(ts)); + } else { + snprintf(str, sizeof(str), "%" PRIu32 ".%" PRIu32, + (uint32_t)SCTIME_SECS(ts), (uint32_t)SCTIME_USECS(ts)); + } } strlcat(filename, str, PATH_MAX); - /* copy the rest over */ + /* copy the rest over */ } else { strlcat(filename, pl->filename_parts[i], PATH_MAX); } @@ -1891,13 +1873,13 @@ static const char *profiling_pcaplog_file_mode = "a"; static void FormatNumber(uint64_t num, char *str, size_t size) { if (num < 1000UL) - snprintf(str, size, "%"PRIu64, num); + snprintf(str, size, "%" PRIu64, num); else if (num < 1000000UL) - snprintf(str, size, "%3.1fk", (float)num/1000UL); + snprintf(str, size, "%3.1fk", (float)num / 1000UL); else if (num < 1000000000UL) - snprintf(str, size, "%3.1fm", (float)num/1000000UL); + snprintf(str, size, "%3.1fm", (float)num / 1000000UL); else - snprintf(str, size, "%3.1fb", (float)num/1000000000UL); + snprintf(str, size, "%3.1fb", (float)num / 1000000000UL); } static void ProfileReportPair(FILE *fp, const char *name, PcapLogProfileData *p) @@ -1909,7 +1891,7 @@ static void ProfileReportPair(FILE *fp, const char *name, PcapLogProfileData *p) FormatNumber((uint64_t)p->cnt, cnt_str, sizeof(cnt_str)); FormatNumber((uint64_t)p->total, ticks_str, sizeof(ticks_str)); if (p->cnt && p->total) - FormatNumber((uint64_t)(p->total/p->cnt), avg_str, sizeof(avg_str)); + FormatNumber((uint64_t)(p->total / p->cnt), avg_str, sizeof(avg_str)); fprintf(fp, "%-28s %-10s %-10s %-10s\n", name, cnt_str, avg_str, ticks_str); } @@ -1928,13 +1910,13 @@ static void ProfileReport(FILE *fp, PcapLogData *pl) static void FormatBytes(uint64_t num, char *str, size_t size) { if (num < 1000UL) - snprintf(str, size, "%"PRIu64, num); + snprintf(str, size, "%" PRIu64, num); else if (num < 1048576UL) - snprintf(str, size, "%3.1fKiB", (float)num/1000UL); + snprintf(str, size, "%3.1fKiB", (float)num / 1000UL); else if (num < 1073741824UL) - snprintf(str, size, "%3.1fMiB", (float)num/1000000UL); + snprintf(str, size, "%3.1fMiB", (float)num / 1000000UL); else - snprintf(str, size, "%3.1fGiB", (float)num/1000000000UL); + snprintf(str, size, "%3.1fGiB", (float)num / 1000000000UL); } static void PcapLogProfilingDump(PcapLogData *pl) @@ -1951,25 +1933,24 @@ static void PcapLogProfilingDump(PcapLogData *pl) return; } } else { - fp = stdout; + fp = stdout; } /* counters */ fprintf(fp, "\n\nOperation Cnt Avg ticks Total ticks\n"); - fprintf(fp, "---------------------------- ---------- ---------- -----------\n"); + fprintf(fp, "---------------------------- ---------- ---------- -----------\n"); ProfileReport(fp, pl); uint64_t total = pl->profile_write.total + pl->profile_rotate.total + - pl->profile_handles.total + pl->profile_open.total + - pl->profile_close.total + pl->profile_lock.total + - pl->profile_unlock.total; + pl->profile_handles.total + pl->profile_open.total + pl->profile_close.total + + pl->profile_lock.total + pl->profile_unlock.total; /* overall stats */ - fprintf(fp, "\nOverall: %"PRIu64" bytes written, average %d bytes per write.\n", - pl->profile_data_size, pl->profile_write.cnt ? - (int)(pl->profile_data_size / pl->profile_write.cnt) : 0); - fprintf(fp, " PCAP data structure overhead: %"PRIuMAX" per write.\n", - (uintmax_t)sizeof(struct pcap_pkthdr)); + fprintf(fp, "\nOverall: %" PRIu64 " bytes written, average %d bytes per write.\n", + pl->profile_data_size, + pl->profile_write.cnt ? (int)(pl->profile_data_size / pl->profile_write.cnt) : 0); + fprintf(fp, " PCAP data structure overhead: %" PRIuMAX " per write.\n", + (uintmax_t)sizeof(struct pcap_pkthdr)); /* print total bytes written */ char bytes_str[32]; @@ -1978,17 +1959,17 @@ static void PcapLogProfilingDump(PcapLogData *pl) /* ticks per MiB and GiB */ uint64_t ticks_per_mib = 0, ticks_per_gib = 0; - uint64_t mib = pl->profile_data_size/(1024*1024); + uint64_t mib = pl->profile_data_size / (1024 * 1024); if (mib) - ticks_per_mib = total/mib; + ticks_per_mib = total / mib; char ticks_per_mib_str[32] = "n/a"; if (ticks_per_mib > 0) FormatNumber(ticks_per_mib, ticks_per_mib_str, sizeof(ticks_per_mib_str)); fprintf(fp, " Ticks per MiB: %s\n", ticks_per_mib_str); - uint64_t gib = pl->profile_data_size/(1024*1024*1024); + uint64_t gib = pl->profile_data_size / (1024 * 1024 * 1024); if (gib) - ticks_per_gib = total/gib; + ticks_per_gib = total / gib; char ticks_per_gib_str[32] = "n/a"; if (ticks_per_gib > 0) FormatNumber(ticks_per_gib, ticks_per_gib_str, sizeof(ticks_per_gib_str)); @@ -2025,8 +2006,8 @@ void PcapLogProfileSetup(void) } profiling_pcaplog_output_to_file = 1; - SCLogInfo("pcap-log profiling output goes to %s (mode %s)", - profiling_pcaplog_file_name, profiling_pcaplog_file_mode); + SCLogInfo("pcap-log profiling output goes to %s (mode %s)", profiling_pcaplog_file_name, + profiling_pcaplog_file_mode); } } } diff --git a/src/log-pcap.h b/src/log-pcap.h index 731a365b854c..e5b271d10238 100644 --- a/src/log-pcap.h +++ b/src/log-pcap.h @@ -15,7 +15,6 @@ * 02110-1301, USA. */ - /** * \file * diff --git a/src/log-stats.c b/src/log-stats.c index 69669e9c2257..7fba7baa4f3f 100644 --- a/src/log-stats.c +++ b/src/log-stats.c @@ -31,26 +31,26 @@ #include "threadvars.h" #include "tm-threads.h" -#include "util-print.h" -#include "util-unittest.h" +#include "util/print.h" +#include "util/unittest.h" -#include "util-debug.h" +#include "util/debug.h" -#include "output.h" +#include "output/output.h" #include "log-stats.h" -#include "util-privs.h" -#include "util-buffer.h" +#include "util/privs.h" +#include "util/buffer.h" -#include "util-logopenfile.h" -#include "util-time.h" +#include "util/logopenfile.h" +#include "util/time.h" #define DEFAULT_LOG_FILENAME "stats.log" -#define MODULE_NAME "LogStatsLog" -#define OUTPUT_BUFFER_SIZE 16384 +#define MODULE_NAME "LogStatsLog" +#define OUTPUT_BUFFER_SIZE 16384 -#define LOG_STATS_TOTALS (1<<0) -#define LOG_STATS_THREADS (1<<1) -#define LOG_STATS_NULLS (1<<2) +#define LOG_STATS_TOTALS (1 << 0) +#define LOG_STATS_THREADS (1 << 1) +#define LOG_STATS_NULLS (1 << 2) TmEcode LogStatsLogThreadInit(ThreadVars *, const void *, void **); TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *); @@ -81,25 +81,25 @@ static int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *s /* Calculate the Engine uptime */ double up_time_d = difftime(tval.tv_sec, st->start_time); int up_time = (int)up_time_d; // ignoring risk of overflow here - int sec = up_time % 60; // Seconds in a minute + int sec = up_time % 60; // Seconds in a minute int in_min = up_time / 60; - int min = in_min % 60; // Minutes in a hour + int min = in_min % 60; // Minutes in a hour int in_hours = in_min / 60; - int hours = in_hours % 24; // Hours in a day + int hours = in_hours % 24; // Hours in a day int days = in_hours / 24; MemBufferWriteString(aft->buffer, "----------------------------------------------" - "--------------------------------------\n"); - MemBufferWriteString(aft->buffer, "Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n", - tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, - tms->tm_min, tms->tm_sec, days, hours, min, sec); + "--------------------------------------\n"); + MemBufferWriteString(aft->buffer, + "Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d (uptime: %" PRId32 "d, %02dh %02dm %02ds)\n", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, + tms->tm_sec, days, hours, min, sec); MemBufferWriteString(aft->buffer, "----------------------------------------------" - "--------------------------------------\n"); - MemBufferWriteString(aft->buffer, "%-45s | %-25s | %-s\n", "Counter", "TM Name", - "Value"); + "--------------------------------------\n"); + MemBufferWriteString(aft->buffer, "%-45s | %-25s | %-s\n", "Counter", "TM Name", "Value"); MemBufferWriteString(aft->buffer, "----------------------------------------------" - "--------------------------------------\n"); + "--------------------------------------\n"); /* global stats */ uint32_t u = 0; @@ -156,7 +156,7 @@ static int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *s } aft->statslog_ctx->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), - MEMBUFFER_OFFSET(aft->buffer), aft->statslog_ctx->file_ctx); + MEMBUFFER_OFFSET(aft->buffer), aft->statslog_ctx->file_ctx); MemBufferReset(aft->buffer); @@ -169,8 +169,7 @@ TmEcode LogStatsLogThreadInit(ThreadVars *t, const void *initdata, void **data) if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if(initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context for LogStats. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; @@ -183,7 +182,7 @@ TmEcode LogStatsLogThreadInit(ThreadVars *t, const void *initdata, void **data) } /* Use the Output Context (file pointer and mutex) */ - aft->statslog_ctx= ((OutputCtx *)initdata)->data; + aft->statslog_ctx = ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; @@ -283,9 +282,8 @@ static void LogStatsLogDeInitCtx(OutputCtx *output_ctx) SCFree(output_ctx); } -void LogStatsLogRegister (void) +void LogStatsLogRegister(void) { - OutputRegisterStatsModule(LOGGER_STATS, MODULE_NAME, "stats", - LogStatsLogInitCtx, LogStatsLogger, LogStatsLogThreadInit, - LogStatsLogThreadDeinit, NULL); + OutputRegisterStatsModule(LOGGER_STATS, MODULE_NAME, "stats", LogStatsLogInitCtx, + LogStatsLogger, LogStatsLogThreadInit, LogStatsLogThreadDeinit, NULL); } diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index 9c67497c16c6..67e78d4d9609 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -26,10 +26,10 @@ #include "threadvars.h" -#include "util-conf.h" -#include "util-logopenfile.h" -#include "util-path.h" -#include "util-print.h" +#include "util/conf.h" +#include "util/logopenfile.h" +#include "util/path.h" +#include "util/print.h" #define DEFAULT_LOG_FILENAME "tcp-data.log" @@ -41,15 +41,17 @@ TmEcode LogTcpDataLogThreadInit(ThreadVars *, const void *, void **); TmEcode LogTcpDataLogThreadDeinit(ThreadVars *, void *); static void LogTcpDataLogDeInitCtx(OutputCtx *); -int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); +int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, + uint32_t data_len, uint64_t tx_id, uint8_t flags); -void LogTcpDataLogRegister (void) { - OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "tcp-data", - LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_TCP_DATA, - LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, NULL); +void LogTcpDataLogRegister(void) +{ + OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "tcp-data", LogTcpDataLogInitCtx, + LogTcpDataLogger, STREAMING_TCP_DATA, LogTcpDataLogThreadInit, + LogTcpDataLogThreadDeinit, NULL); OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "http-body-data", - LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_HTTP_BODIES, - LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, NULL); + LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_HTTP_BODIES, LogTcpDataLogThreadInit, + LogTcpDataLogThreadDeinit, NULL); } typedef struct LogTcpDataFileCtx_ { @@ -91,13 +93,11 @@ static int LogTcpDataLoggerDir(ThreadVars *tv, void *thread_data, const Flow *f, char tx[64] = { 0 }; if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) { - snprintf(tx, sizeof(tx), "%"PRIu64, tx_id); + snprintf(tx, sizeof(tx), "%" PRIu64, tx_id); } - snprintf(name, sizeof(name), "%s/%s/%s_%u-%s_%u-%s-%s.data", - td->log_dir, - td->type == STREAMING_HTTP_BODIES ? "http" : "tcp", - srcip, f->sp, dstip, f->dp, tx, + snprintf(name, sizeof(name), "%s/%s/%s_%u-%s_%u-%s-%s.data", td->log_dir, + td->type == STREAMING_HTTP_BODIES ? "http" : "tcp", srcip, f->sp, dstip, f->dp, tx, flags & OUTPUT_STREAMING_FLAG_TOSERVER ? "ts" : "tc"); FILE *fp = fopen(name, mode); @@ -131,16 +131,15 @@ static int LogTcpDataLoggerFile(ThreadVars *tv, void *thread_data, const Flow *f } char name[PATH_MAX]; - snprintf(name, sizeof(name), "%s_%u-%s_%u-%s:", - srcip, f->sp, dstip, f->dp, + snprintf(name, sizeof(name), "%s_%u-%s_%u-%s:", srcip, f->sp, dstip, f->dp, flags & OUTPUT_STREAMING_FLAG_TOSERVER ? "ts" : "tc"); - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)name,strlen(name)); + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)name, strlen(name)); MemBufferWriteString(aft->buffer, "\n"); - PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)data,data_len); + PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, + (uint8_t *)data, data_len); td->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), td->file_ctx); @@ -148,8 +147,8 @@ static int LogTcpDataLoggerFile(ThreadVars *tv, void *thread_data, const Flow *f SCReturnInt(TM_ECODE_OK); } -int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, - const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags) +int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, + uint32_t data_len, uint64_t tx_id, uint8_t flags) { SCEnter(); LogTcpDataLogThread *aft = thread_data; @@ -169,8 +168,7 @@ TmEcode LogTcpDataLogThreadInit(ThreadVars *t, const void *initdata, void **data if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if(initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; @@ -183,7 +181,7 @@ TmEcode LogTcpDataLogThreadInit(ThreadVars *t, const void *initdata, void **data } /* Use the Output Context (file pointer and mutex) */ - aft->tcpdatalog_ctx= ((OutputCtx *)initdata)->data; + aft->tcpdatalog_ctx = ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; @@ -216,7 +214,7 @@ OutputInitResult LogTcpDataLogInitCtx(ConfNode *conf) strlcpy(filename, DEFAULT_LOG_FILENAME, sizeof(filename)); LogFileCtx *file_ctx = LogFileNewCtx(); - if(file_ctx == NULL) { + if (file_ctx == NULL) { SCLogError("couldn't create new file_ctx"); return result; } @@ -299,7 +297,6 @@ OutputInitResult LogTcpDataLogInitCtx(ConfNode *conf) SCFree(tcpdatalog_ctx); SCLogError("Syntax error in custom http log format string."); return result; - } static void LogTcpDataLogDeInitCtx(OutputCtx *output_ctx) diff --git a/src/log-tcp-data.h b/src/log-tcp-data.h index 608dbef3090a..322870ba07fa 100644 --- a/src/log-tcp-data.h +++ b/src/log-tcp-data.h @@ -25,7 +25,7 @@ #define __LOG_TCPDATALOG_H__ #include "conf.h" -#include "output.h" +#include "output/output.h" void LogTcpDataLogRegister(void); OutputInitResult LogTcpDataLogInitCtx(ConfNode *); diff --git a/src/log-tlslog.c b/src/log-tlslog.c deleted file mode 100644 index 6217c5fe9813..000000000000 --- a/src/log-tlslog.c +++ /dev/null @@ -1,531 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Roliers Jean-Paul - * \author Eric Leblond - * \author Victor Julien - * \author Paulo Pacheco - * - * Implements TLS logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "log-tlslog.h" -#include "app-layer-ssl.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" - -#include "util-logopenfile.h" -#include "util-time.h" -#include "log-cf-common.h" - -#define DEFAULT_LOG_FILENAME "tls.log" - -#define MODULE_NAME "LogTlsLog" - -#define PRINT_BUF_LEN 46 - -#define OUTPUT_BUFFER_SIZE 65535 -#define CERT_ENC_BUFFER_SIZE 2048 - -#define LOG_TLS_DEFAULT 0 -#define LOG_TLS_EXTENDED 1 -#define LOG_TLS_CUSTOM 2 - -#define LOG_TLS_SESSION_RESUMPTION 4 - -#define LOG_TLS_CF_VERSION 'v' -#define LOG_TLS_CF_DATE_NOT_BEFORE 'd' -#define LOG_TLS_CF_DATE_NOT_AFTER 'D' -#define LOG_TLS_CF_SHA1 'f' -#define LOG_TLS_CF_SNI 'n' -#define LOG_TLS_CF_SUBJECT 's' -#define LOG_TLS_CF_ISSUER 'i' -#define LOG_TLS_CF_EXTENDED 'E' - -typedef struct LogTlsFileCtx_ { - LogFileCtx *file_ctx; - uint32_t flags; /** Store mode */ - LogCustomFormat *cf; -} LogTlsFileCtx; - -typedef struct LogTlsLogThread_ { - LogTlsFileCtx *tlslog_ctx; - - /* LogTlsFileCtx has the pointer to the file and a mutex to allow - multithreading. */ - uint32_t tls_cnt; - - MemBuffer *buffer; -} LogTlsLogThread; - -int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, - Port* sp, char* dstip, size_t dstip_len, Port* dp, - int ipproto) -{ - if ((PKT_IS_TOSERVER(p))) { - switch (ipproto) { - case AF_INET: - PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), - srcip, srcip_len); - PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), - dstip, dstip_len); - break; - case AF_INET6: - PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), srcip, - srcip_len); - PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), dstip, - dstip_len); - break; - default: - return 0; - } - *sp = p->sp; - *dp = p->dp; - } else { - switch (ipproto) { - case AF_INET: - PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), - srcip, srcip_len); - PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), - dstip, dstip_len); - break; - case AF_INET6: - PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), srcip, - srcip_len); - PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), dstip, - dstip_len); - break; - default: - return 0; - } - *sp = p->dp; - *dp = p->sp; - } - return 1; -} - -static TmEcode LogTlsLogThreadInit(ThreadVars *t, const void *initdata, - void **data) -{ - LogTlsLogThread *aft = SCCalloc(1, sizeof(LogTlsLogThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - - if (initdata == NULL) { - SCLogDebug("Error getting context for TLSLog. \"initdata\" argument NULL"); - SCFree(aft); - return TM_ECODE_FAILED; - } - - aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); - if (aft->buffer == NULL) { - SCFree(aft); - return TM_ECODE_FAILED; - } - - /* Use the Output Context (file pointer and mutex) */ - aft->tlslog_ctx = ((OutputCtx *) initdata)->data; - - *data = (void *)aft; - return TM_ECODE_OK; -} - -static TmEcode LogTlsLogThreadDeinit(ThreadVars *t, void *data) -{ - LogTlsLogThread *aft = (LogTlsLogThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - - MemBufferFree(aft->buffer); - memset(aft, 0, sizeof(LogTlsLogThread)); - - SCFree(aft); - return TM_ECODE_OK; -} - -static void LogTlsLogDeInitCtx(OutputCtx *output_ctx) -{ - LogTlsFileCtx *tlslog_ctx = (LogTlsFileCtx *) output_ctx->data; - LogFileFreeCtx(tlslog_ctx->file_ctx); - LogCustomFormatFree(tlslog_ctx->cf); - SCFree(tlslog_ctx); - SCFree(output_ctx); -} - -static void LogTlsLogExitPrintStats(ThreadVars *tv, void *data) -{ - LogTlsLogThread *aft = (LogTlsLogThread *)data; - if (aft == NULL) { - return; - } - - SCLogInfo("TLS logger logged %" PRIu32 " requests", aft->tls_cnt); -} - -/** \brief Create a new tls log LogFileCtx. - * \param conf Pointer to ConfNode containing this loggers configuration. - * \return NULL if failure, LogFileCtx* to the file_ctx if succesful - * */ -static OutputInitResult LogTlsLogInitCtx(ConfNode *conf) -{ - OutputInitResult result = { NULL, false }; - LogFileCtx* file_ctx = LogFileNewCtx(); - - if (file_ctx == NULL) { - SCLogError("LogTlsLogInitCtx: Couldn't " - "create new file_ctx"); - return result; - } - - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { - goto filectx_error; - } - - LogTlsFileCtx *tlslog_ctx = SCCalloc(1, sizeof(LogTlsFileCtx)); - if (unlikely(tlslog_ctx == NULL)) { - goto filectx_error; - } - tlslog_ctx->file_ctx = file_ctx; - - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - const char *custom = ConfNodeLookupChildValue(conf, "custom"); - const char *customformat = ConfNodeLookupChildValue(conf, "customformat"); - - /* If custom logging format is selected, lets parse it */ - if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { - tlslog_ctx->cf = LogCustomFormatAlloc(); - if (!tlslog_ctx->cf) { - goto tlslog_error; - } - - tlslog_ctx->flags |= LOG_TLS_CUSTOM; - - if (!LogCustomFormatParse(tlslog_ctx->cf, customformat)) { - goto parser_error; - } - } else { - if (extended == NULL) { - tlslog_ctx->flags |= LOG_TLS_DEFAULT; - } else { - if (ConfValIsTrue(extended)) { - tlslog_ctx->flags |= LOG_TLS_EXTENDED; - } - } - } - - const char *resumption = ConfNodeLookupChildValue(conf, - "session-resumption"); - if (resumption == NULL || ConfValIsTrue(resumption)) { - tlslog_ctx->flags |= LOG_TLS_SESSION_RESUMPTION; - } - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - goto tlslog_error; - } - output_ctx->data = tlslog_ctx; - output_ctx->DeInit = LogTlsLogDeInitCtx; - - SCLogDebug("TLS log output initialized"); - - /* Enable the logger for the app layer */ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); - - result.ctx = output_ctx; - result.ok = true; - return result; - -parser_error: - SCLogError("Syntax error in custom tls log " - "format string."); -tlslog_error: - LogCustomFormatFree(tlslog_ctx->cf); - SCFree(tlslog_ctx); -filectx_error: - LogFileFreeCtx(file_ctx); - return result; -} - -static void LogTlsLogVersion(MemBuffer *buffer, uint16_t version) -{ - char ssl_version[SSL_VERSION_MAX_STRLEN]; - SSLVersionToString(version, ssl_version); - MemBufferWriteString(buffer, "VERSION='%s'", ssl_version); -} - -static void LogTlsLogDate(MemBuffer *buffer, const char *title, int64_t *date) -{ - char timebuf[64] = {0}; - if (sc_x509_format_timestamp(*date, timebuf, sizeof(timebuf))) { - MemBufferWriteString(buffer, "%s='%s'", title, timebuf); - } -} - -static void LogTlsLogString(MemBuffer *buffer, const char *title, - const char *value) -{ - MemBufferWriteString(buffer, "%s='%s'", title, value); -} - -static void LogTlsLogBasic(LogTlsLogThread *aft, SSLState *ssl_state, const SCTime_t ts, - char *srcip, Port sp, char *dstip, Port dp) -{ - char timebuf[64]; - CreateTimeString(ts, timebuf, sizeof(timebuf)); - MemBufferWriteString(aft->buffer, - "%s %s:%d -> %s:%d TLS:", - timebuf, srcip, sp, dstip, dp); - - if (ssl_state->server_connp.cert0_subject != NULL) { - MemBufferWriteString(aft->buffer, " Subject='%s'", - ssl_state->server_connp.cert0_subject); - } - - if (ssl_state->server_connp.cert0_issuerdn != NULL) { - MemBufferWriteString(aft->buffer, " Issuerdn='%s'", - ssl_state->server_connp.cert0_issuerdn); - } - - if (ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) { - /* Only log a session as 'resumed' if a certificate has not - been seen. */ - if ((ssl_state->server_connp.cert0_issuerdn == NULL) && - (ssl_state->server_connp.cert0_subject == NULL) && - (ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { - MemBufferWriteString(aft->buffer, " Session='resumed'"); - } - } -} - -static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState *ssl_state, const SCTime_t ts, - char *srcip, Port sp, char *dstip, Port dp) -{ - if (ssl_state->server_connp.cert0_fingerprint != NULL) { - LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); - LogTlsLogString(aft->buffer, "SHA1", - ssl_state->server_connp.cert0_fingerprint); - } - if (ssl_state->client_connp.sni != NULL) { - LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); - LogTlsLogString(aft->buffer, "SNI", ssl_state->client_connp.sni); - } - if (ssl_state->server_connp.cert0_serial != NULL) { - LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); - LogTlsLogString(aft->buffer, "SERIAL", - ssl_state->server_connp.cert0_serial); - } - - LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); - LogTlsLogVersion(aft->buffer, ssl_state->server_connp.version); - - if (ssl_state->server_connp.cert0_not_before != 0) { - LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); - LogTlsLogDate(aft->buffer, "NOTBEFORE", - &ssl_state->server_connp.cert0_not_before); - } - if (ssl_state->server_connp.cert0_not_after != 0) { - LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); - LogTlsLogDate(aft->buffer, "NOTAFTER", - &ssl_state->server_connp.cert0_not_after); - } -} - -/* Custom format logging */ -static void LogTlsLogCustom(LogTlsLogThread *aft, SSLState *ssl_state, const SCTime_t ts, - char *srcip, Port sp, char *dstip, Port dp) -{ - LogTlsFileCtx *tlslog_ctx = aft->tlslog_ctx; - uint32_t i; - char buf[64]; - - for (i = 0; i < tlslog_ctx->cf->cf_n; i++) - { - LogCustomFormatNode *node = tlslog_ctx->cf->cf_nodes[i]; - if (!node) /* Should never happen */ - continue; - - switch (node->type) { - case LOG_CF_LITERAL: - /* LITERAL */ - MemBufferWriteString(aft->buffer, "%s", node->data); - break; - case LOG_CF_TIMESTAMP: - /* TIMESTAMP */ - LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); - break; - case LOG_CF_TIMESTAMP_U: - /* TIMESTAMP USECONDS */ - snprintf(buf, sizeof(buf), "%06u", (unsigned int)SCTIME_USECS(ts)); - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, - (uint8_t *)buf, MIN(strlen(buf), 6)); - break; - case LOG_CF_CLIENT_IP: - /* CLIENT IP ADDRESS */ - PrintRawUriBuf((char *)aft->buffer->buffer, - &aft->buffer->offset, aft->buffer->size, - (uint8_t *)srcip,strlen(srcip)); - break; - case LOG_CF_SERVER_IP: - /* SERVER IP ADDRESS */ - PrintRawUriBuf((char *)aft->buffer->buffer, - &aft->buffer->offset, aft->buffer->size, - (uint8_t *)dstip, strlen(dstip)); - break; - case LOG_CF_CLIENT_PORT: - /* CLIENT PORT */ - MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); - break; - case LOG_CF_SERVER_PORT: - /* SERVER PORT */ - MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); - break; - case LOG_TLS_CF_VERSION: - LogTlsLogVersion(aft->buffer, ssl_state->server_connp.version); - break; - case LOG_TLS_CF_DATE_NOT_BEFORE: - LogTlsLogDate(aft->buffer, "NOTBEFORE", - &ssl_state->server_connp.cert0_not_before); - break; - case LOG_TLS_CF_DATE_NOT_AFTER: - LogTlsLogDate(aft->buffer, "NOTAFTER", - &ssl_state->server_connp.cert0_not_after); - break; - case LOG_TLS_CF_SHA1: - if (ssl_state->server_connp.cert0_fingerprint != NULL) { - MemBufferWriteString(aft->buffer, "%s", - ssl_state->server_connp.cert0_fingerprint); - } else { - LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); - } - break; - case LOG_TLS_CF_SNI: - if (ssl_state->client_connp.sni != NULL) { - MemBufferWriteString(aft->buffer, "%s", - ssl_state->client_connp.sni); - } else { - LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); - } - break; - case LOG_TLS_CF_SUBJECT: - if (ssl_state->server_connp.cert0_subject != NULL) { - MemBufferWriteString(aft->buffer, "%s", - ssl_state->server_connp.cert0_subject); - } else { - LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); - } - break; - case LOG_TLS_CF_ISSUER: - if (ssl_state->server_connp.cert0_issuerdn != NULL) { - MemBufferWriteString(aft->buffer, "%s", - ssl_state->server_connp.cert0_issuerdn); - } else { - LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); - } - break; - case LOG_TLS_CF_EXTENDED: - /* Extended format */ - LogTlsLogExtended(aft, ssl_state, ts, srcip, sp, dstip, dp); - break; - default: - /* NO MATCH */ - MemBufferWriteString(aft->buffer, LOG_CF_NONE); - SCLogDebug("No matching parameter %%%c for custom tls log.", - node->type); - break; - } - } -} - - -static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, - Flow *f, void *state, void *tx, uint64_t tx_id) -{ - LogTlsLogThread *aft = (LogTlsLogThread *)thread_data; - LogTlsFileCtx *hlog = aft->tlslog_ctx; - int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; - - SSLState *ssl_state = (SSLState *)state; - if (unlikely(ssl_state == NULL)) { - return 0; - } - - if (((hlog->flags & LOG_TLS_SESSION_RESUMPTION) == 0 || - (ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) == 0) && - (ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) && - ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { - return 0; - } - - char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; - - Port sp, dp; - if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, - PRINT_BUF_LEN, &dp, ipproto)) { - return 0; - } - - MemBufferReset(aft->buffer); - - if (hlog->flags & LOG_TLS_CUSTOM) { - LogTlsLogCustom(aft, ssl_state, p->ts, srcip, sp, dstip, dp); - } else if (hlog->flags & LOG_TLS_EXTENDED) { - LogTlsLogBasic(aft, ssl_state, p->ts, srcip, sp, dstip, dp); - LogTlsLogExtended(aft, ssl_state, p->ts, srcip, sp, dstip, dp); - } else { - LogTlsLogBasic(aft, ssl_state, p->ts, srcip, sp, dstip, dp); - } - - MemBufferWriteString(aft->buffer, "\n"); - - aft->tls_cnt++; - - hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), - MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - - return 0; -} - -void LogTlsLogRegister(void) -{ - OutputRegisterTxModuleWithProgress(LOGGER_TLS, MODULE_NAME, "tls-log", - LogTlsLogInitCtx, ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, - TLS_HANDSHAKE_DONE, LogTlsLogThreadInit, LogTlsLogThreadDeinit, - LogTlsLogExitPrintStats); -} diff --git a/src/output-json-bittorrent-dht.c b/src/output-json-bittorrent-dht.c deleted file mode 100644 index 066df78f61fb..000000000000 --- a/src/output-json-bittorrent-dht.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * Implement JSON/eve logging app-layer BitTorrent DHT. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "output-json-bittorrent-dht.h" -#include "rust.h" - -typedef struct LogBitTorrentDHTFileCtx_ { - uint32_t flags; - OutputJsonCtx *eve_ctx; -} LogBitTorrentDHTFileCtx; - -typedef struct LogBitTorrentDHTLogThread_ { - LogBitTorrentDHTFileCtx *bittorrent_dht_log_ctx; - OutputJsonThreadCtx *ctx; -} LogBitTorrentDHTLogThread; - -static int JsonBitTorrentDHTLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, - void *state, void *tx, uint64_t tx_id) -{ - LogBitTorrentDHTLogThread *thread = thread_data; - - JsonBuilder *js = CreateEveHeader( - p, LOG_DIR_PACKET, "bittorrent_dht", NULL, thread->bittorrent_dht_log_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_FAILED; - } - - if (!rs_bittorrent_dht_logger_log(tx, js)) { - goto error; - } - - OutputJsonBuilderBuffer(js, thread->ctx); - jb_free(js); - - return TM_ECODE_OK; - -error: - jb_free(js); - return TM_ECODE_FAILED; -} - -static void OutputBitTorrentDHTLogDeInitCtxSub(OutputCtx *output_ctx) -{ - LogBitTorrentDHTFileCtx *bittorrent_dht_log_ctx = (LogBitTorrentDHTFileCtx *)output_ctx->data; - SCFree(bittorrent_dht_log_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputBitTorrentDHTLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ajt = parent_ctx->data; - - LogBitTorrentDHTFileCtx *bittorrent_dht_log_ctx = SCCalloc(1, sizeof(*bittorrent_dht_log_ctx)); - if (unlikely(bittorrent_dht_log_ctx == NULL)) { - return result; - } - bittorrent_dht_log_ctx->eve_ctx = ajt; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(bittorrent_dht_log_ctx); - return result; - } - output_ctx->data = bittorrent_dht_log_ctx; - output_ctx->DeInit = OutputBitTorrentDHTLogDeInitCtxSub; - - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_BITTORRENT_DHT); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonBitTorrentDHTLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogBitTorrentDHTLogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - if (initdata == NULL) { - SCLogDebug("Error getting context for EveLogBitTorrentDHT. \"initdata\" is NULL."); - goto error_exit; - } - - thread->bittorrent_dht_log_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->bittorrent_dht_log_ctx->eve_ctx); - if (!thread->ctx) { - goto error_exit; - } - *data = (void *)thread; - - return TM_ECODE_OK; - -error_exit: - SCFree(thread); - return TM_ECODE_FAILED; -} - -static TmEcode JsonBitTorrentDHTLogThreadDeinit(ThreadVars *t, void *data) -{ - LogBitTorrentDHTLogThread *thread = (LogBitTorrentDHTLogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonBitTorrentDHTLogRegister(void) -{ - if (ConfGetNode("app-layer.protocols.bittorrent-dht") == NULL) { - return; - } - - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonBitTorrentDHTLog", - "eve-log.bittorrent-dht", OutputBitTorrentDHTLogInitSub, ALPROTO_BITTORRENT_DHT, - JsonBitTorrentDHTLogger, JsonBitTorrentDHTLogThreadInit, - JsonBitTorrentDHTLogThreadDeinit, NULL); -} diff --git a/src/output-json-dcerpc.c b/src/output-json-dcerpc.c deleted file mode 100644 index 6ec19a0b849c..000000000000 --- a/src/output-json-dcerpc.c +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (C) 2017-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "util-buffer.h" -#include "output.h" -#include "output-json.h" -#include "app-layer-parser.h" -#include "output-json-dcerpc.h" -#include "rust.h" - - -static int JsonDCERPCLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "dcerpc", NULL, thread->ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_FAILED; - } - - jb_open_object(jb, "dcerpc"); - if (p->proto == IPPROTO_TCP) { - if (!rs_dcerpc_log_json_record_tcp(state, tx, jb)) { - goto error; - } - } else { - if (!rs_dcerpc_log_json_record_udp(state, tx, jb)) { - goto error; - } - } - jb_close(jb); - - MemBufferReset(thread->buffer); - OutputJsonBuilderBuffer(jb, thread); - - jb_free(jb); - return TM_ECODE_OK; - -error: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static OutputInitResult DCERPCLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DCERPC); - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DCERPC); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonDCERPCLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonDCERPCLog", "eve-log.dcerpc", - DCERPCLogInitSub, ALPROTO_DCERPC, JsonDCERPCLogger, JsonLogThreadInit, - JsonLogThreadDeinit, NULL); - - SCLogDebug("DCERPC JSON logger registered."); -} diff --git a/src/output-json-dhcp.c b/src/output-json-dhcp.c deleted file mode 100644 index d6a2111291aa..000000000000 --- a/src/output-json-dhcp.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright (C) 2015-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Jason Ish - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "output-json-dhcp.h" -#include "rust.h" - - -typedef struct LogDHCPFileCtx_ { - void *rs_logger; - OutputJsonCtx *eve_ctx; -} LogDHCPFileCtx; - -typedef struct LogDHCPLogThread_ { - LogDHCPFileCtx *dhcplog_ctx; - OutputJsonThreadCtx *thread; -} LogDHCPLogThread; - -static int JsonDHCPLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - LogDHCPLogThread *thread = thread_data; - LogDHCPFileCtx *ctx = thread->dhcplog_ctx; - - if (!rs_dhcp_logger_do_log(ctx->rs_logger, tx)) { - return TM_ECODE_OK; - } - - JsonBuilder *js = CreateEveHeader((Packet *)p, 0, "dhcp", NULL, ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_FAILED; - } - - rs_dhcp_logger_log(ctx->rs_logger, tx, js); - - OutputJsonBuilderBuffer(js, thread->thread); - jb_free(js); - - return TM_ECODE_OK; -} - -static void OutputDHCPLogDeInitCtxSub(OutputCtx *output_ctx) -{ - LogDHCPFileCtx *dhcplog_ctx = (LogDHCPFileCtx *)output_ctx->data; - rs_dhcp_logger_free(dhcplog_ctx->rs_logger); - SCFree(dhcplog_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputDHCPLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - - LogDHCPFileCtx *dhcplog_ctx = SCCalloc(1, sizeof(*dhcplog_ctx)); - if (unlikely(dhcplog_ctx == NULL)) { - return result; - } - dhcplog_ctx->eve_ctx = parent_ctx->data; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(dhcplog_ctx); - return result; - } - output_ctx->data = dhcplog_ctx; - output_ctx->DeInit = OutputDHCPLogDeInitCtxSub; - - dhcplog_ctx->rs_logger = rs_dhcp_logger_new(conf); - - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DHCP); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonDHCPLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogDHCPLogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - LogDHCPFileCtx *ctx = ((OutputCtx *)initdata)->data; - thread->dhcplog_ctx = ctx; - thread->thread = CreateEveThreadCtx(t, ctx->eve_ctx); - if (thread->thread == NULL) { - SCFree(thread); - return TM_ECODE_FAILED; - } - - *data = (void *)thread; - return TM_ECODE_OK; -} - -static TmEcode JsonDHCPLogThreadDeinit(ThreadVars *t, void *data) -{ - LogDHCPLogThread *thread = (LogDHCPLogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->thread); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonDHCPLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonDHCPLog", "eve-log.dhcp", - OutputDHCPLogInitSub, ALPROTO_DHCP, JsonDHCPLogger, JsonDHCPLogThreadInit, - JsonDHCPLogThreadDeinit, NULL); -} diff --git a/src/output-json-dnp3-objects.c b/src/output-json-dnp3-objects.c deleted file mode 100644 index ce499213cbd2..000000000000 --- a/src/output-json-dnp3-objects.c +++ /dev/null @@ -1,1667 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. - * - * Generated by command: - * ./scripts/dnp3-gen/dnp3-gen.py - */ - -#include "suricata-common.h" - -#include "app-layer-dnp3.h" -#include "app-layer-dnp3-objects.h" -#include "output-json-dnp3-objects.h" -#include "output-json.h" - -// clang-format off -void OutputJsonDNP3SetItem(JsonBuilder *js, DNP3Object *object, - DNP3Point *point) -{ - - switch (DNP3_OBJECT_CODE(object->group, object->variation)) { - case DNP3_OBJECT_CODE(1, 1): { - DNP3ObjectG1V1 *data = point->data; - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(1, 2): { - DNP3ObjectG1V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "chatter_filter", data->chatter_filter); - jb_set_uint(js, "reserved", data->reserved); - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(2, 1): { - DNP3ObjectG2V1 *data = point->data; - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(2, 2): { - DNP3ObjectG2V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "chatter_filter", data->chatter_filter); - jb_set_uint(js, "reserved", data->reserved); - jb_set_uint(js, "state", data->state); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(2, 3): { - DNP3ObjectG2V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "chatter_filter", data->chatter_filter); - jb_set_uint(js, "reserved", data->reserved); - jb_set_uint(js, "state", data->state); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(3, 1): { - DNP3ObjectG3V1 *data = point->data; - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(3, 2): { - DNP3ObjectG3V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "chatter_filter", data->chatter_filter); - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(4, 1): { - DNP3ObjectG4V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "chatter_filter", data->chatter_filter); - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(4, 2): { - DNP3ObjectG4V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "chatter_filter", data->chatter_filter); - jb_set_uint(js, "state", data->state); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(4, 3): { - DNP3ObjectG4V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "chatter_filter", data->chatter_filter); - jb_set_uint(js, "state", data->state); - jb_set_uint(js, "relative_time_ms", data->relative_time_ms); - break; - } - case DNP3_OBJECT_CODE(10, 1): { - DNP3ObjectG10V1 *data = point->data; - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(10, 2): { - DNP3ObjectG10V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(11, 1): { - DNP3ObjectG11V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(11, 2): { - DNP3ObjectG11V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "state", data->state); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(12, 1): { - DNP3ObjectG12V1 *data = point->data; - jb_set_uint(js, "op_type", data->op_type); - jb_set_uint(js, "qu", data->qu); - jb_set_uint(js, "cr", data->cr); - jb_set_uint(js, "tcc", data->tcc); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "ontime", data->ontime); - jb_set_uint(js, "offtime", data->offtime); - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved", data->reserved); - break; - } - case DNP3_OBJECT_CODE(12, 2): { - DNP3ObjectG12V2 *data = point->data; - jb_set_uint(js, "op_type", data->op_type); - jb_set_uint(js, "qu", data->qu); - jb_set_uint(js, "cr", data->cr); - jb_set_uint(js, "tcc", data->tcc); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "ontime", data->ontime); - jb_set_uint(js, "offtime", data->offtime); - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved", data->reserved); - break; - } - case DNP3_OBJECT_CODE(12, 3): { - DNP3ObjectG12V3 *data = point->data; - jb_set_uint(js, "point", data->point); - break; - } - case DNP3_OBJECT_CODE(13, 1): { - DNP3ObjectG13V1 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "commanded_state", data->commanded_state); - break; - } - case DNP3_OBJECT_CODE(13, 2): { - DNP3ObjectG13V2 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "commanded_state", data->commanded_state); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(20, 1): { - DNP3ObjectG20V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(20, 2): { - DNP3ObjectG20V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(20, 3): { - DNP3ObjectG20V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(20, 4): { - DNP3ObjectG20V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(20, 5): { - DNP3ObjectG20V5 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(20, 6): { - DNP3ObjectG20V6 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(20, 7): { - DNP3ObjectG20V7 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(20, 8): { - DNP3ObjectG20V8 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 1): { - DNP3ObjectG21V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 2): { - DNP3ObjectG21V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 3): { - DNP3ObjectG21V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 4): { - DNP3ObjectG21V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 5): { - DNP3ObjectG21V5 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(21, 6): { - DNP3ObjectG21V6 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(21, 7): { - DNP3ObjectG21V7 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(21, 8): { - DNP3ObjectG21V8 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(21, 9): { - DNP3ObjectG21V9 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 10): { - DNP3ObjectG21V10 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 11): { - DNP3ObjectG21V11 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(21, 12): { - DNP3ObjectG21V12 *data = point->data; - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(22, 1): { - DNP3ObjectG22V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(22, 2): { - DNP3ObjectG22V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(22, 3): { - DNP3ObjectG22V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(22, 4): { - DNP3ObjectG22V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(22, 5): { - DNP3ObjectG22V5 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(22, 6): { - DNP3ObjectG22V6 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(22, 7): { - DNP3ObjectG22V7 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(22, 8): { - DNP3ObjectG22V8 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(23, 1): { - DNP3ObjectG23V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(23, 2): { - DNP3ObjectG23V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(23, 3): { - DNP3ObjectG23V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(23, 4): { - DNP3ObjectG23V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - break; - } - case DNP3_OBJECT_CODE(23, 5): { - DNP3ObjectG23V5 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(23, 6): { - DNP3ObjectG23V6 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(23, 7): { - DNP3ObjectG23V7 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(23, 8): { - DNP3ObjectG23V8 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "rollover", data->rollover); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "count", data->count); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(30, 1): { - DNP3ObjectG30V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(30, 2): { - DNP3ObjectG30V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(30, 3): { - DNP3ObjectG30V3 *data = point->data; - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(30, 4): { - DNP3ObjectG30V4 *data = point->data; - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(30, 5): { - DNP3ObjectG30V5 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(30, 6): { - DNP3ObjectG30V6 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(31, 1): { - DNP3ObjectG31V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(31, 2): { - DNP3ObjectG31V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(31, 3): { - DNP3ObjectG31V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(31, 4): { - DNP3ObjectG31V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(31, 5): { - DNP3ObjectG31V5 *data = point->data; - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(31, 6): { - DNP3ObjectG31V6 *data = point->data; - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(31, 7): { - DNP3ObjectG31V7 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(31, 8): { - DNP3ObjectG31V8 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(32, 1): { - DNP3ObjectG32V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(32, 2): { - DNP3ObjectG32V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(32, 3): { - DNP3ObjectG32V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(32, 4): { - DNP3ObjectG32V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(32, 5): { - DNP3ObjectG32V5 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(32, 6): { - DNP3ObjectG32V6 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(32, 7): { - DNP3ObjectG32V7 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(32, 8): { - DNP3ObjectG32V8 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(33, 1): { - DNP3ObjectG33V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(33, 2): { - DNP3ObjectG33V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(33, 3): { - DNP3ObjectG33V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(33, 4): { - DNP3ObjectG33V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(33, 5): { - DNP3ObjectG33V5 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(33, 6): { - DNP3ObjectG33V6 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(33, 7): { - DNP3ObjectG33V7 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(33, 8): { - DNP3ObjectG33V8 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(34, 1): { - DNP3ObjectG34V1 *data = point->data; - jb_set_uint(js, "deadband_value", data->deadband_value); - break; - } - case DNP3_OBJECT_CODE(34, 2): { - DNP3ObjectG34V2 *data = point->data; - jb_set_uint(js, "deadband_value", data->deadband_value); - break; - } - case DNP3_OBJECT_CODE(34, 3): { - DNP3ObjectG34V3 *data = point->data; - jb_set_float(js, "deadband_value", data->deadband_value); - break; - } - case DNP3_OBJECT_CODE(40, 1): { - DNP3ObjectG40V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(40, 2): { - DNP3ObjectG40V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(40, 3): { - DNP3ObjectG40V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(40, 4): { - DNP3ObjectG40V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(41, 1): { - DNP3ObjectG41V1 *data = point->data; - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "control_status", data->control_status); - break; - } - case DNP3_OBJECT_CODE(41, 2): { - DNP3ObjectG41V2 *data = point->data; - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "control_status", data->control_status); - break; - } - case DNP3_OBJECT_CODE(41, 3): { - DNP3ObjectG41V3 *data = point->data; - jb_set_float(js, "value", data->value); - jb_set_uint(js, "control_status", data->control_status); - break; - } - case DNP3_OBJECT_CODE(41, 4): { - DNP3ObjectG41V4 *data = point->data; - jb_set_float(js, "value", data->value); - jb_set_uint(js, "control_status", data->control_status); - break; - } - case DNP3_OBJECT_CODE(42, 1): { - DNP3ObjectG42V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(42, 2): { - DNP3ObjectG42V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(42, 3): { - DNP3ObjectG42V3 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(42, 4): { - DNP3ObjectG42V4 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(42, 5): { - DNP3ObjectG42V5 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(42, 6): { - DNP3ObjectG42V6 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(42, 7): { - DNP3ObjectG42V7 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(42, 8): { - DNP3ObjectG42V8 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "over_range", data->over_range); - jb_set_uint(js, "reference_err", data->reference_err); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "value", data->value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(43, 1): { - DNP3ObjectG43V1 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "commanded_value", data->commanded_value); - break; - } - case DNP3_OBJECT_CODE(43, 2): { - DNP3ObjectG43V2 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "commanded_value", data->commanded_value); - break; - } - case DNP3_OBJECT_CODE(43, 3): { - DNP3ObjectG43V3 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "commanded_value", data->commanded_value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(43, 4): { - DNP3ObjectG43V4 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "commanded_value", data->commanded_value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(43, 5): { - DNP3ObjectG43V5 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "commanded_value", data->commanded_value); - break; - } - case DNP3_OBJECT_CODE(43, 6): { - DNP3ObjectG43V6 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "commanded_value", data->commanded_value); - break; - } - case DNP3_OBJECT_CODE(43, 7): { - DNP3ObjectG43V7 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "commanded_value", data->commanded_value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(43, 8): { - DNP3ObjectG43V8 *data = point->data; - jb_set_uint(js, "status_code", data->status_code); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_float(js, "commanded_value", data->commanded_value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(50, 1): { - DNP3ObjectG50V1 *data = point->data; - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(50, 2): { - DNP3ObjectG50V2 *data = point->data; - jb_set_uint(js, "timestamp", data->timestamp); - jb_set_uint(js, "interval", data->interval); - break; - } - case DNP3_OBJECT_CODE(50, 3): { - DNP3ObjectG50V3 *data = point->data; - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(50, 4): { - DNP3ObjectG50V4 *data = point->data; - jb_set_uint(js, "timestamp", data->timestamp); - jb_set_uint(js, "interval_count", data->interval_count); - jb_set_uint(js, "interval_units", data->interval_units); - break; - } - case DNP3_OBJECT_CODE(51, 1): { - DNP3ObjectG51V1 *data = point->data; - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(51, 2): { - DNP3ObjectG51V2 *data = point->data; - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - case DNP3_OBJECT_CODE(52, 1): { - DNP3ObjectG52V1 *data = point->data; - jb_set_uint(js, "delay_secs", data->delay_secs); - break; - } - case DNP3_OBJECT_CODE(52, 2): { - DNP3ObjectG52V2 *data = point->data; - jb_set_uint(js, "delay_ms", data->delay_ms); - break; - } - case DNP3_OBJECT_CODE(70, 1): { - DNP3ObjectG70V1 *data = point->data; - jb_set_uint(js, "filename_size", data->filename_size); - jb_set_uint(js, "filetype_code", data->filetype_code); - jb_set_uint(js, "attribute_code", data->attribute_code); - jb_set_uint(js, "start_record", data->start_record); - jb_set_uint(js, "end_record", data->end_record); - jb_set_uint(js, "file_size", data->file_size); - jb_set_uint(js, "created_timestamp", data->created_timestamp); - jb_set_uint(js, "permission", data->permission); - jb_set_uint(js, "file_id", data->file_id); - jb_set_uint(js, "owner_id", data->owner_id); - jb_set_uint(js, "group_id", data->group_id); - jb_set_uint(js, "file_function_code", data->file_function_code); - jb_set_uint(js, "status_code", data->status_code); - if (data->filename_size > 0) { - jb_set_string_from_bytes( - js, "filename", (const uint8_t *)data->filename, data->filename_size); - } else { - jb_set_string(js, "filename", ""); - } - jb_set_uint(js, "data_size", data->data_size); - if (data->data_size > 0) { - jb_set_string_from_bytes( - js, "data", (const uint8_t *)data->data, data->data_size); - } else { - jb_set_string(js, "data", ""); - } - break; - } - case DNP3_OBJECT_CODE(70, 2): { - DNP3ObjectG70V2 *data = point->data; - jb_set_uint(js, "username_offset", data->username_offset); - jb_set_uint(js, "username_size", data->username_size); - jb_set_uint(js, "password_offset", data->password_offset); - jb_set_uint(js, "password_size", data->password_size); - jb_set_uint(js, "authentication_key", data->authentication_key); - if (data->username_size > 0) { - jb_set_string_from_bytes( - js, "username", (const uint8_t *)data->username, data->username_size); - } else { - jb_set_string(js, "username", ""); - } - if (data->password_size > 0) { - jb_set_string_from_bytes( - js, "password", (const uint8_t *)data->password, data->password_size); - } else { - jb_set_string(js, "password", ""); - } - break; - } - case DNP3_OBJECT_CODE(70, 3): { - DNP3ObjectG70V3 *data = point->data; - jb_set_uint(js, "filename_offset", data->filename_offset); - jb_set_uint(js, "filename_size", data->filename_size); - jb_set_uint(js, "created", data->created); - jb_set_uint(js, "permissions", data->permissions); - jb_set_uint(js, "authentication_key", data->authentication_key); - jb_set_uint(js, "file_size", data->file_size); - jb_set_uint(js, "operational_mode", data->operational_mode); - jb_set_uint(js, "maximum_block_size", data->maximum_block_size); - jb_set_uint(js, "request_id", data->request_id); - if (data->filename_size > 0) { - jb_set_string_from_bytes( - js, "filename", (const uint8_t *)data->filename, data->filename_size); - } else { - jb_set_string(js, "filename", ""); - } - break; - } - case DNP3_OBJECT_CODE(70, 4): { - DNP3ObjectG70V4 *data = point->data; - jb_set_uint(js, "file_handle", data->file_handle); - jb_set_uint(js, "file_size", data->file_size); - jb_set_uint(js, "maximum_block_size", data->maximum_block_size); - jb_set_uint(js, "request_id", data->request_id); - jb_set_uint(js, "status_code", data->status_code); - if (data->optional_text_len > 0) { - jb_set_string_from_bytes( - js, "optional_text", (const uint8_t *)data->optional_text, data->optional_text_len); - } else { - jb_set_string(js, "optional_text", ""); - } - break; - } - case DNP3_OBJECT_CODE(70, 5): { - DNP3ObjectG70V5 *data = point->data; - jb_set_uint(js, "file_handle", data->file_handle); - jb_set_uint(js, "block_number", data->block_number); - if (data->file_data_len > 0) { - jb_set_string_from_bytes( - js, "file_data", (const uint8_t *)data->file_data, data->file_data_len); - } else { - jb_set_string(js, "file_data", ""); - } - break; - } - case DNP3_OBJECT_CODE(70, 6): { - DNP3ObjectG70V6 *data = point->data; - jb_set_uint(js, "file_handle", data->file_handle); - jb_set_uint(js, "block_number", data->block_number); - jb_set_uint(js, "status_code", data->status_code); - if (data->optional_text_len > 0) { - jb_set_string_from_bytes( - js, "optional_text", (const uint8_t *)data->optional_text, data->optional_text_len); - } else { - jb_set_string(js, "optional_text", ""); - } - break; - } - case DNP3_OBJECT_CODE(70, 7): { - DNP3ObjectG70V7 *data = point->data; - jb_set_uint(js, "filename_offset", data->filename_offset); - jb_set_uint(js, "filename_size", data->filename_size); - jb_set_uint(js, "file_type", data->file_type); - jb_set_uint(js, "file_size", data->file_size); - jb_set_uint(js, "created_timestamp", data->created_timestamp); - jb_set_uint(js, "permissions", data->permissions); - jb_set_uint(js, "request_id", data->request_id); - if (data->filename_size > 0) { - jb_set_string_from_bytes( - js, "filename", (const uint8_t *)data->filename, data->filename_size); - } else { - jb_set_string(js, "filename", ""); - } - break; - } - case DNP3_OBJECT_CODE(70, 8): { - DNP3ObjectG70V8 *data = point->data; - if (data->file_specification_len > 0) { - jb_set_string_from_bytes( - js, "file_specification", (const uint8_t *)data->file_specification, data->file_specification_len); - } else { - jb_set_string(js, "file_specification", ""); - } - break; - } - case DNP3_OBJECT_CODE(80, 1): { - DNP3ObjectG80V1 *data = point->data; - jb_set_uint(js, "state", data->state); - break; - } - case DNP3_OBJECT_CODE(81, 1): { - DNP3ObjectG81V1 *data = point->data; - jb_set_uint(js, "fill_percentage", data->fill_percentage); - jb_set_uint(js, "overflow_state", data->overflow_state); - jb_set_uint(js, "group", data->group); - jb_set_uint(js, "variation", data->variation); - break; - } - case DNP3_OBJECT_CODE(83, 1): { - DNP3ObjectG83V1 *data = point->data; - jb_set_string(js, "data->vendor_code", data->vendor_code); - jb_set_uint(js, "object_id", data->object_id); - jb_set_uint(js, "length", data->length); - jb_set_base64(js, "data->data_objects", data->data_objects, data->length); - break; - } - case DNP3_OBJECT_CODE(86, 2): { - DNP3ObjectG86V2 *data = point->data; - jb_set_uint(js, "rd", data->rd); - jb_set_uint(js, "wr", data->wr); - jb_set_uint(js, "st", data->st); - jb_set_uint(js, "ev", data->ev); - jb_set_uint(js, "df", data->df); - jb_set_uint(js, "padding0", data->padding0); - jb_set_uint(js, "padding1", data->padding1); - jb_set_uint(js, "padding2", data->padding2); - break; - } - case DNP3_OBJECT_CODE(102, 1): { - DNP3ObjectG102V1 *data = point->data; - jb_set_uint(js, "value", data->value); - break; - } - case DNP3_OBJECT_CODE(120, 1): { - DNP3ObjectG120V1 *data = point->data; - jb_set_uint(js, "csq", data->csq); - jb_set_uint(js, "usr", data->usr); - jb_set_uint(js, "mal", data->mal); - jb_set_uint(js, "reason", data->reason); - jb_set_base64(js, "data->challenge_data", data->challenge_data, data->challenge_data_len); - break; - } - case DNP3_OBJECT_CODE(120, 2): { - DNP3ObjectG120V2 *data = point->data; - jb_set_uint(js, "csq", data->csq); - jb_set_uint(js, "usr", data->usr); - jb_set_base64(js, "data->mac_value", data->mac_value, data->mac_value_len); - break; - } - case DNP3_OBJECT_CODE(120, 3): { - DNP3ObjectG120V3 *data = point->data; - jb_set_uint(js, "csq", data->csq); - jb_set_uint(js, "user_number", data->user_number); - break; - } - case DNP3_OBJECT_CODE(120, 4): { - DNP3ObjectG120V4 *data = point->data; - jb_set_uint(js, "user_number", data->user_number); - break; - } - case DNP3_OBJECT_CODE(120, 5): { - DNP3ObjectG120V5 *data = point->data; - jb_set_uint(js, "ksq", data->ksq); - jb_set_uint(js, "user_number", data->user_number); - jb_set_uint(js, "key_wrap_alg", data->key_wrap_alg); - jb_set_uint(js, "key_status", data->key_status); - jb_set_uint(js, "mal", data->mal); - jb_set_uint(js, "challenge_data_len", data->challenge_data_len); - jb_set_base64(js, "data->challenge_data", data->challenge_data, data->challenge_data_len); - jb_set_base64(js, "data->mac_value", data->mac_value, data->mac_value_len); - break; - } - case DNP3_OBJECT_CODE(120, 6): { - DNP3ObjectG120V6 *data = point->data; - jb_set_uint(js, "ksq", data->ksq); - jb_set_uint(js, "usr", data->usr); - jb_set_base64(js, "data->wrapped_key_data", data->wrapped_key_data, data->wrapped_key_data_len); - break; - } - case DNP3_OBJECT_CODE(120, 7): { - DNP3ObjectG120V7 *data = point->data; - jb_set_uint(js, "sequence_number", data->sequence_number); - jb_set_uint(js, "usr", data->usr); - jb_set_uint(js, "association_id", data->association_id); - jb_set_uint(js, "error_code", data->error_code); - jb_set_uint(js, "time_of_error", data->time_of_error); - if (data->error_text_len > 0) { - jb_set_string_from_bytes( - js, "error_text", (const uint8_t *)data->error_text, data->error_text_len); - } else { - jb_set_string(js, "error_text", ""); - } - break; - } - case DNP3_OBJECT_CODE(120, 8): { - DNP3ObjectG120V8 *data = point->data; - jb_set_uint(js, "key_change_method", data->key_change_method); - jb_set_uint(js, "certificate_type", data->certificate_type); - jb_set_base64(js, "data->certificate", data->certificate, data->certificate_len); - break; - } - case DNP3_OBJECT_CODE(120, 9): { - DNP3ObjectG120V9 *data = point->data; - jb_set_base64(js, "data->mac_value", data->mac_value, data->mac_value_len); - break; - } - case DNP3_OBJECT_CODE(120, 10): { - DNP3ObjectG120V10 *data = point->data; - jb_set_uint(js, "key_change_method", data->key_change_method); - jb_set_uint(js, "operation", data->operation); - jb_set_uint(js, "scs", data->scs); - jb_set_uint(js, "user_role", data->user_role); - jb_set_uint(js, "user_role_expiry_interval", data->user_role_expiry_interval); - jb_set_uint(js, "username_len", data->username_len); - jb_set_uint(js, "user_public_key_len", data->user_public_key_len); - jb_set_uint(js, "certification_data_len", data->certification_data_len); - if (data->username_len > 0) { - jb_set_string_from_bytes( - js, "username", (const uint8_t *)data->username, data->username_len); - } else { - jb_set_string(js, "username", ""); - } - jb_set_base64(js, "data->user_public_key", data->user_public_key, data->user_public_key_len); - jb_set_base64(js, "data->certification_data", data->certification_data, data->certification_data_len); - break; - } - case DNP3_OBJECT_CODE(120, 11): { - DNP3ObjectG120V11 *data = point->data; - jb_set_uint(js, "key_change_method", data->key_change_method); - jb_set_uint(js, "username_len", data->username_len); - jb_set_uint(js, "master_challenge_data_len", data->master_challenge_data_len); - if (data->username_len > 0) { - jb_set_string_from_bytes( - js, "username", (const uint8_t *)data->username, data->username_len); - } else { - jb_set_string(js, "username", ""); - } - jb_set_base64(js, "data->master_challenge_data", data->master_challenge_data, data->master_challenge_data_len); - break; - } - case DNP3_OBJECT_CODE(120, 12): { - DNP3ObjectG120V12 *data = point->data; - jb_set_uint(js, "ksq", data->ksq); - jb_set_uint(js, "user_number", data->user_number); - jb_set_uint(js, "challenge_data_len", data->challenge_data_len); - jb_set_base64(js, "data->challenge_data", data->challenge_data, data->challenge_data_len); - break; - } - case DNP3_OBJECT_CODE(120, 13): { - DNP3ObjectG120V13 *data = point->data; - jb_set_uint(js, "ksq", data->ksq); - jb_set_uint(js, "user_number", data->user_number); - jb_set_uint(js, "encrypted_update_key_len", data->encrypted_update_key_len); - jb_set_base64(js, "data->encrypted_update_key_data", data->encrypted_update_key_data, data->encrypted_update_key_len); - break; - } - case DNP3_OBJECT_CODE(120, 14): { - DNP3ObjectG120V14 *data = point->data; - jb_set_base64(js, "data->digital_signature", data->digital_signature, data->digital_signature_len); - break; - } - case DNP3_OBJECT_CODE(120, 15): { - DNP3ObjectG120V15 *data = point->data; - jb_set_base64(js, "data->mac", data->mac, data->mac_len); - break; - } - case DNP3_OBJECT_CODE(121, 1): { - DNP3ObjectG121V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "association_id", data->association_id); - jb_set_uint(js, "count_value", data->count_value); - break; - } - case DNP3_OBJECT_CODE(122, 1): { - DNP3ObjectG122V1 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "association_id", data->association_id); - jb_set_uint(js, "count_value", data->count_value); - break; - } - case DNP3_OBJECT_CODE(122, 2): { - DNP3ObjectG122V2 *data = point->data; - jb_set_uint(js, "online", data->online); - jb_set_uint(js, "restart", data->restart); - jb_set_uint(js, "comm_lost", data->comm_lost); - jb_set_uint(js, "remote_forced", data->remote_forced); - jb_set_uint(js, "local_forced", data->local_forced); - jb_set_uint(js, "reserved0", data->reserved0); - jb_set_uint(js, "discontinuity", data->discontinuity); - jb_set_uint(js, "reserved1", data->reserved1); - jb_set_uint(js, "association_id", data->association_id); - jb_set_uint(js, "count_value", data->count_value); - jb_set_uint(js, "timestamp", data->timestamp); - break; - } - default: - SCLogDebug("Unknown object: %d:%d", object->group, - object->variation); - break; - } - -} -// clang-format on diff --git a/src/output-json-dnp3-objects.h b/src/output-json-dnp3-objects.h deleted file mode 100644 index debe115689ab..000000000000 --- a/src/output-json-dnp3-objects.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __OUTPUT_JSON_DNP3_OBJECTS_H__ -#define __OUTPUT_JSON_DNP3_OBJECTS_H__ - -#include "rust-bindings.h" - -void OutputJsonDNP3SetItem(JsonBuilder *js, DNP3Object *object, - DNP3Point *item); - -#endif /* __OUTPUT_JSON_DNP3_OBJECTS_H__ */ diff --git a/src/output-json-dnp3.c b/src/output-json-dnp3.c deleted file mode 100644 index 4336e04e070c..000000000000 --- a/src/output-json-dnp3.c +++ /dev/null @@ -1,371 +0,0 @@ -/* Copyright (C) 2015-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-dnp3.h" -#include "app-layer-dnp3-objects.h" - -#include "detect-dnp3.h" - -#include "output.h" -#include "output-json.h" -#include "output-json-dnp3.h" -#include "output-json-dnp3-objects.h" - -typedef struct LogDNP3FileCtx_ { - uint32_t flags; - uint8_t include_object_data; - OutputJsonCtx *eve_ctx; -} LogDNP3FileCtx; - -typedef struct LogDNP3LogThread_ { - LogDNP3FileCtx *dnp3log_ctx; - OutputJsonThreadCtx *ctx; -} LogDNP3LogThread; - -static void JsonDNP3LogLinkControl(JsonBuilder *js, uint8_t lc) -{ - jb_set_bool(js, "dir", DNP3_LINK_DIR(lc)); - jb_set_bool(js, "pri", DNP3_LINK_PRI(lc)); - jb_set_bool(js, "fcb", DNP3_LINK_FCB(lc)); - jb_set_bool(js, "fcv", DNP3_LINK_FCV(lc)); - jb_set_uint(js, "function_code", DNP3_LINK_FC(lc)); -} - -static void JsonDNP3LogIin(JsonBuilder *js, uint16_t iin) -{ - if (iin) { - jb_open_array(js, "indicators"); - - int mapping = 0; - do { - if (iin & DNP3IndicatorsMap[mapping].value) { - jb_append_string(js, DNP3IndicatorsMap[mapping].name); - } - mapping++; - } while (DNP3IndicatorsMap[mapping].name != NULL); - jb_close(js); - } -} - -static void JsonDNP3LogApplicationControl(JsonBuilder *js, uint8_t ac) -{ - jb_set_bool(js, "fir", DNP3_APP_FIR(ac)); - jb_set_bool(js, "fin", DNP3_APP_FIN(ac)); - jb_set_bool(js, "con", DNP3_APP_CON(ac)); - jb_set_bool(js, "uns", DNP3_APP_UNS(ac)); - jb_set_uint(js, "sequence", DNP3_APP_SEQ(ac)); -} - -/** - * \brief Log the items (points) for an object. - * - * TODO: Autogenerate this function based on object definitions. - */ -static void JsonDNP3LogObjectItems(JsonBuilder *js, DNP3Object *object) -{ - DNP3Point *item; - - TAILQ_FOREACH(item, object->points, next) { - jb_start_object(js); - - jb_set_uint(js, "prefix", item->prefix); - jb_set_uint(js, "index", item->index); - if (DNP3PrefixIsSize(object->prefix_code)) { - jb_set_uint(js, "size", item->size); - } - - OutputJsonDNP3SetItem(js, object, item); - jb_close(js); - } -} - -/** - * \brief Log the application layer objects. - * - * \param objects A list of DNP3 objects. - * \param jb A JsonBuilder instance with an open array. - */ -static void JsonDNP3LogObjects(JsonBuilder *js, DNP3ObjectList *objects) -{ - DNP3Object *object; - - TAILQ_FOREACH(object, objects, next) { - jb_start_object(js); - jb_set_uint(js, "group", object->group); - jb_set_uint(js, "variation", object->variation); - jb_set_uint(js, "qualifier", object->qualifier); - jb_set_uint(js, "prefix_code", object->prefix_code); - jb_set_uint(js, "range_code", object->range_code); - jb_set_uint(js, "start", object->start); - jb_set_uint(js, "stop", object->stop); - jb_set_uint(js, "count", object->count); - - if (object->points != NULL && !TAILQ_EMPTY(object->points)) { - jb_open_array(js, "points"); - JsonDNP3LogObjectItems(js, object); - jb_close(js); - } - - jb_close(js); - } -} - -void JsonDNP3LogRequest(JsonBuilder *js, DNP3Transaction *dnp3tx) -{ - JB_SET_STRING(js, "type", "request"); - - jb_open_object(js, "control"); - JsonDNP3LogLinkControl(js, dnp3tx->lh.control); - jb_close(js); - - jb_set_uint(js, "src", DNP3_SWAP16(dnp3tx->lh.src)); - jb_set_uint(js, "dst", DNP3_SWAP16(dnp3tx->lh.dst)); - - jb_open_object(js, "application"); - - jb_open_object(js, "control"); - JsonDNP3LogApplicationControl(js, dnp3tx->ah.control); - jb_close(js); - - jb_set_uint(js, "function_code", dnp3tx->ah.function_code); - - if (!TAILQ_EMPTY(&dnp3tx->objects)) { - jb_open_array(js, "objects"); - JsonDNP3LogObjects(js, &dnp3tx->objects); - jb_close(js); - } - - jb_set_bool(js, "complete", dnp3tx->complete); - - /* Close application. */ - jb_close(js); -} - -void JsonDNP3LogResponse(JsonBuilder *js, DNP3Transaction *dnp3tx) -{ - if (dnp3tx->ah.function_code == DNP3_APP_FC_UNSOLICITED_RESP) { - JB_SET_STRING(js, "type", "unsolicited_response"); - } else { - JB_SET_STRING(js, "type", "response"); - } - - jb_open_object(js, "control"); - JsonDNP3LogLinkControl(js, dnp3tx->lh.control); - jb_close(js); - - jb_set_uint(js, "src", DNP3_SWAP16(dnp3tx->lh.src)); - jb_set_uint(js, "dst", DNP3_SWAP16(dnp3tx->lh.dst)); - - jb_open_object(js, "application"); - - jb_open_object(js, "control"); - JsonDNP3LogApplicationControl(js, dnp3tx->ah.control); - jb_close(js); - - jb_set_uint(js, "function_code", dnp3tx->ah.function_code); - - if (!TAILQ_EMPTY(&dnp3tx->objects)) { - jb_open_array(js, "objects"); - JsonDNP3LogObjects(js, &dnp3tx->objects); - jb_close(js); - } - - jb_set_bool(js, "complete", dnp3tx->complete); - - /* Close application. */ - jb_close(js); - - jb_open_object(js, "iin"); - JsonDNP3LogIin(js, (uint16_t)(dnp3tx->iin.iin1 << 8 | dnp3tx->iin.iin2)); - jb_close(js); -} - -bool AlertJsonDnp3(void *vtx, JsonBuilder *js) -{ - DNP3Transaction *tx = (DNP3Transaction *)vtx; - bool logged = false; - jb_open_object(js, "dnp3"); - if (tx->is_request && tx->done) { - jb_open_object(js, "request"); - JsonDNP3LogRequest(js, tx); - jb_close(js); - logged = true; - } - if (!tx->is_request && tx->done) { - jb_open_object(js, "response"); - JsonDNP3LogResponse(js, tx); - jb_close(js); - logged = true; - } - jb_close(js); - return logged; -} - -static int JsonDNP3LoggerToServer(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) -{ - SCEnter(); - LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; - DNP3Transaction *tx = vtx; - - JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "dnp3", NULL, thread->dnp3log_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_OK; - } - - jb_open_object(js, "dnp3"); - JsonDNP3LogRequest(js, tx); - jb_close(js); - OutputJsonBuilderBuffer(js, thread->ctx); - jb_free(js); - - SCReturnInt(TM_ECODE_OK); -} - -static int JsonDNP3LoggerToClient(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) -{ - SCEnter(); - LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; - DNP3Transaction *tx = vtx; - - JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "dnp3", NULL, thread->dnp3log_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_OK; - } - - jb_open_object(js, "dnp3"); - JsonDNP3LogResponse(js, tx); - jb_close(js); - OutputJsonBuilderBuffer(js, thread->ctx); - jb_free(js); - - SCReturnInt(TM_ECODE_OK); -} - -static int JsonDNP3Logger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, - void *vtx, uint64_t tx_id) -{ - SCEnter(); - DNP3Transaction *tx = vtx; - if (tx->is_request && tx->done) { - JsonDNP3LoggerToServer(tv, thread_data, p, f, state, vtx, tx_id); - } else if (!tx->is_request && tx->done) { - JsonDNP3LoggerToClient(tv, thread_data, p, f, state, vtx, tx_id); - } - SCReturnInt(TM_ECODE_OK); -} - -static void OutputDNP3LogDeInitCtxSub(OutputCtx *output_ctx) -{ - SCLogDebug("cleaning up sub output_ctx %p", output_ctx); - LogDNP3FileCtx *dnp3log_ctx = (LogDNP3FileCtx *)output_ctx->data; - SCFree(dnp3log_ctx); - SCFree(output_ctx); -} - -#define DEFAULT_LOG_FILENAME "dnp3.json" - -static OutputInitResult OutputDNP3LogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *json_ctx = parent_ctx->data; - - LogDNP3FileCtx *dnp3log_ctx = SCCalloc(1, sizeof(*dnp3log_ctx)); - if (unlikely(dnp3log_ctx == NULL)) { - return result; - } - dnp3log_ctx->eve_ctx = json_ctx; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(dnp3log_ctx); - return result; - } - output_ctx->data = dnp3log_ctx; - output_ctx->DeInit = OutputDNP3LogDeInitCtxSub; - - SCLogInfo("DNP3 log sub-module initialized."); - - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNP3); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - - -static TmEcode JsonDNP3LogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogDNP3LogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - if (initdata == NULL) { - SCLogDebug("Error getting context for DNP3. \"initdata\" is NULL."); - goto error_exit; - } - - thread->dnp3log_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->dnp3log_ctx->eve_ctx); - if (thread->ctx == NULL) { - goto error_exit; - } - - *data = (void *)thread; - - return TM_ECODE_OK; - -error_exit: - SCFree(thread); - return TM_ECODE_FAILED; -} - -static TmEcode JsonDNP3LogThreadDeinit(ThreadVars *t, void *data) -{ - LogDNP3LogThread *thread = (LogDNP3LogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonDNP3LogRegister(void) -{ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonDNP3Log", "eve-log.dnp3", - OutputDNP3LogInitSub, ALPROTO_DNP3, JsonDNP3Logger, JsonDNP3LogThreadInit, - JsonDNP3LogThreadDeinit, NULL); -} diff --git a/src/output-json-dnp3.h b/src/output-json-dnp3.h deleted file mode 100644 index 6f81026780d9..000000000000 --- a/src/output-json-dnp3.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __OUTPUT_JSON_DNP3_H__ -#define __OUTPUT_JSON_DNP3_H__ - -#include "app-layer-dnp3.h" - -void JsonDNP3LogRequest(JsonBuilder *js, DNP3Transaction *); -void JsonDNP3LogResponse(JsonBuilder *js, DNP3Transaction *); - -void JsonDNP3LogRegister(void); -bool AlertJsonDnp3(void *vtx, JsonBuilder *js); - -#endif /* __OUTPUT_JSON_DNP3_H__ */ diff --git a/src/output-json-dns.c b/src/output-json-dns.c deleted file mode 100644 index 27aa55d8e305..000000000000 --- a/src/output-json-dns.c +++ /dev/null @@ -1,606 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Tom DeCanio - * - * Implements JSON DNS logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" -#include "util-mem.h" -#include "app-layer-parser.h" -#include "output.h" -#include "app-layer.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" - -#include "output-json.h" -#include "output-json-dns.h" -#include "rust.h" - -/* we can do query logging as well, but it's disabled for now as the - * TX id handling doesn't expect it */ -#define QUERY 0 - -#define LOG_QUERIES BIT_U64(0) -#define LOG_ANSWERS BIT_U64(1) - -#define LOG_A BIT_U64(2) -#define LOG_NS BIT_U64(3) -#define LOG_MD BIT_U64(4) -#define LOG_MF BIT_U64(5) -#define LOG_CNAME BIT_U64(6) -#define LOG_SOA BIT_U64(7) -#define LOG_MB BIT_U64(8) -#define LOG_MG BIT_U64(9) -#define LOG_MR BIT_U64(10) -#define LOG_NULL BIT_U64(11) -#define LOG_WKS BIT_U64(12) -#define LOG_PTR BIT_U64(13) -#define LOG_HINFO BIT_U64(14) -#define LOG_MINFO BIT_U64(15) -#define LOG_MX BIT_U64(16) -#define LOG_TXT BIT_U64(17) -#define LOG_RP BIT_U64(18) -#define LOG_AFSDB BIT_U64(19) -#define LOG_X25 BIT_U64(20) -#define LOG_ISDN BIT_U64(21) -#define LOG_RT BIT_U64(22) -#define LOG_NSAP BIT_U64(23) -#define LOG_NSAPPTR BIT_U64(24) -#define LOG_SIG BIT_U64(25) -#define LOG_KEY BIT_U64(26) -#define LOG_PX BIT_U64(27) -#define LOG_GPOS BIT_U64(28) -#define LOG_AAAA BIT_U64(29) -#define LOG_LOC BIT_U64(30) -#define LOG_NXT BIT_U64(31) -#define LOG_SRV BIT_U64(32) -#define LOG_ATMA BIT_U64(33) -#define LOG_NAPTR BIT_U64(34) -#define LOG_KX BIT_U64(35) -#define LOG_CERT BIT_U64(36) -#define LOG_A6 BIT_U64(37) -#define LOG_DNAME BIT_U64(38) -#define LOG_OPT BIT_U64(39) -#define LOG_APL BIT_U64(40) -#define LOG_DS BIT_U64(41) -#define LOG_SSHFP BIT_U64(42) -#define LOG_IPSECKEY BIT_U64(43) -#define LOG_RRSIG BIT_U64(44) -#define LOG_NSEC BIT_U64(45) -#define LOG_DNSKEY BIT_U64(46) -#define LOG_DHCID BIT_U64(47) -#define LOG_NSEC3 BIT_U64(48) -#define LOG_NSEC3PARAM BIT_U64(49) -#define LOG_TLSA BIT_U64(50) -#define LOG_HIP BIT_U64(51) -#define LOG_CDS BIT_U64(52) -#define LOG_CDNSKEY BIT_U64(53) -#define LOG_SPF BIT_U64(54) -#define LOG_TKEY BIT_U64(55) -#define LOG_TSIG BIT_U64(56) -#define LOG_MAILA BIT_U64(57) -#define LOG_ANY BIT_U64(58) -#define LOG_URI BIT_U64(59) - -#define LOG_FORMAT_GROUPED BIT_U64(60) -#define LOG_FORMAT_DETAILED BIT_U64(61) -#define LOG_HTTPS BIT_U64(62) - -#define LOG_FORMAT_ALL (LOG_FORMAT_GROUPED|LOG_FORMAT_DETAILED) -#define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS|LOG_FORMAT_DETAILED|LOG_FORMAT_GROUPED)) - -typedef enum { - DNS_RRTYPE_A = 0, - DNS_RRTYPE_NS, - DNS_RRTYPE_MD, - DNS_RRTYPE_MF, - DNS_RRTYPE_CNAME, - DNS_RRTYPE_SOA, - DNS_RRTYPE_MB, - DNS_RRTYPE_MG, - DNS_RRTYPE_MR, - DNS_RRTYPE_NULL, - DNS_RRTYPE_WKS, - DNS_RRTYPE_PTR, - DNS_RRTYPE_HINFO, - DNS_RRTYPE_MINFO, - DNS_RRTYPE_MX, - DNS_RRTYPE_TXT, - DNS_RRTYPE_RP, - DNS_RRTYPE_AFSDB, - DNS_RRTYPE_X25, - DNS_RRTYPE_ISDN, - DNS_RRTYPE_RT, - DNS_RRTYPE_NSAP, - DNS_RRTYPE_NSAPPTR, - DNS_RRTYPE_SIG, - DNS_RRTYPE_KEY, - DNS_RRTYPE_PX, - DNS_RRTYPE_GPOS, - DNS_RRTYPE_AAAA, - DNS_RRTYPE_LOC, - DNS_RRTYPE_NXT, - DNS_RRTYPE_SRV, - DNS_RRTYPE_ATMA, - DNS_RRTYPE_NAPTR, - DNS_RRTYPE_KX, - DNS_RRTYPE_CERT, - DNS_RRTYPE_A6, - DNS_RRTYPE_DNAME, - DNS_RRTYPE_OPT, - DNS_RRTYPE_APL, - DNS_RRTYPE_DS, - DNS_RRTYPE_SSHFP, - DNS_RRTYPE_IPSECKEY, - DNS_RRTYPE_RRSIG, - DNS_RRTYPE_NSEC, - DNS_RRTYPE_DNSKEY, - DNS_RRTYPE_DHCID, - DNS_RRTYPE_NSEC3, - DNS_RRTYPE_NSEC3PARAM, - DNS_RRTYPE_TLSA, - DNS_RRTYPE_HIP, - DNS_RRTYPE_CDS, - DNS_RRTYPE_CDNSKEY, - DNS_RRTYPE_HTTPS, - DNS_RRTYPE_SPF, - DNS_RRTYPE_TKEY, - DNS_RRTYPE_TSIG, - DNS_RRTYPE_MAILA, - DNS_RRTYPE_ANY, - DNS_RRTYPE_URI, - DNS_RRTYPE_MAX, -} DnsRRTypes; - -static struct { - const char *config_rrtype; - uint64_t flags; -} dns_rrtype_fields[] = { - // clang-format off - { "a", LOG_A }, - { "ns", LOG_NS }, - { "md", LOG_MD }, - { "mf", LOG_MF }, - { "cname", LOG_CNAME }, - { "soa", LOG_SOA }, - { "mb", LOG_MB }, - { "mg", LOG_MG }, - { "mr", LOG_MR }, - { "null", LOG_NULL }, - { "wks", LOG_WKS }, - { "ptr", LOG_PTR }, - { "hinfo", LOG_HINFO }, - { "minfo", LOG_MINFO }, - { "mx", LOG_MX }, - { "txt", LOG_TXT }, - { "rp", LOG_RP }, - { "afsdb", LOG_AFSDB }, - { "x25", LOG_X25 }, - { "isdn", LOG_ISDN }, - { "rt", LOG_RT }, - { "nsap", LOG_NSAP }, - { "nsapptr", LOG_NSAPPTR }, - { "sig", LOG_SIG }, - { "key", LOG_KEY }, - { "px", LOG_PX }, - { "gpos", LOG_GPOS }, - { "aaaa", LOG_AAAA }, - { "loc", LOG_LOC }, - { "nxt", LOG_NXT }, - { "srv", LOG_SRV }, - { "atma", LOG_ATMA }, - { "naptr", LOG_NAPTR }, - { "kx", LOG_KX }, - { "cert", LOG_CERT }, - { "a6", LOG_A6 }, - { "dname", LOG_DNAME }, - { "opt", LOG_OPT }, - { "apl", LOG_APL }, - { "ds", LOG_DS }, - { "sshfp", LOG_SSHFP }, - { "ipseckey", LOG_IPSECKEY }, - { "rrsig", LOG_RRSIG }, - { "nsec", LOG_NSEC }, - { "dnskey", LOG_DNSKEY }, - { "dhcid", LOG_DHCID }, - { "nsec3", LOG_NSEC3 }, - { "nsec3param", LOG_NSEC3PARAM }, - { "tlsa", LOG_TLSA }, - { "hip", LOG_HIP }, - { "cds", LOG_CDS }, - { "cdnskey", LOG_CDNSKEY }, - { "https", LOG_HTTPS }, - { "spf", LOG_SPF }, - { "tkey", LOG_TKEY }, - { "tsig", LOG_TSIG }, - { "maila", LOG_MAILA }, - { "any", LOG_ANY }, - { "uri", LOG_URI } - // clang-format on -}; - -typedef struct LogDnsFileCtx_ { - uint64_t flags; /** Store mode */ - OutputJsonCtx *eve_ctx; -} LogDnsFileCtx; - -typedef struct LogDnsLogThread_ { - LogDnsFileCtx *dnslog_ctx; - OutputJsonThreadCtx *ctx; -} LogDnsLogThread; - -static JsonBuilder *JsonDNSLogQuery(void *txptr) -{ - JsonBuilder *queryjb = jb_new_array(); - if (queryjb == NULL) { - return NULL; - } - bool has_query = false; - - for (uint16_t i = 0; i < UINT16_MAX; i++) { - JsonBuilder *js = jb_new_object(); - if (!rs_dns_log_json_query((void *)txptr, i, LOG_ALL_RRTYPES, js)) { - jb_free(js); - break; - } - jb_close(js); - has_query = true; - jb_append_object(queryjb, js); - jb_free(js); - } - - if (!has_query) { - jb_free(queryjb); - return NULL; - } - - jb_close(queryjb); - return queryjb; -} - -static JsonBuilder *JsonDNSLogAnswer(void *txptr) -{ - if (!rs_dns_do_log_answer(txptr, LOG_ALL_RRTYPES)) { - return NULL; - } else { - JsonBuilder *js = jb_new_object(); - rs_dns_log_json_answer(txptr, LOG_ALL_RRTYPES, js); - jb_close(js); - return js; - } -} - -bool AlertJsonDns(void *txptr, JsonBuilder *js) -{ - jb_open_object(js, "dns"); - JsonBuilder *qjs = JsonDNSLogQuery(txptr); - if (qjs != NULL) { - jb_set_object(js, "query", qjs); - jb_free(qjs); - } - JsonBuilder *ajs = JsonDNSLogAnswer(txptr); - if (ajs != NULL) { - jb_set_object(js, "answer", ajs); - jb_free(ajs); - } - jb_close(js); - return true; -} - -static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) -{ - SCEnter(); - - LogDnsLogThread *td = (LogDnsLogThread *)thread_data; - LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; - - if (unlikely(dnslog_ctx->flags & LOG_QUERIES) == 0) { - return TM_ECODE_OK; - } - - for (uint16_t i = 0; i < 0xffff; i++) { - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "dns", NULL, dnslog_ctx->eve_ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_OK; - } - - jb_open_object(jb, "dns"); - if (!rs_dns_log_json_query(txptr, i, td->dnslog_ctx->flags, jb)) { - jb_free(jb); - break; - } - jb_close(jb); - - OutputJsonBuilderBuffer(jb, td->ctx); - jb_free(jb); - } - - SCReturnInt(TM_ECODE_OK); -} - -static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) -{ - SCEnter(); - - LogDnsLogThread *td = (LogDnsLogThread *)thread_data; - LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; - - if (unlikely(dnslog_ctx->flags & LOG_ANSWERS) == 0) { - return TM_ECODE_OK; - } - - if (rs_dns_do_log_answer(txptr, td->dnslog_ctx->flags)) { - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "dns", NULL, dnslog_ctx->eve_ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_OK; - } - - jb_open_object(jb, "dns"); - rs_dns_log_json_answer(txptr, td->dnslog_ctx->flags, jb); - jb_close(jb); - OutputJsonBuilderBuffer(jb, td->ctx); - jb_free(jb); - } - - SCReturnInt(TM_ECODE_OK); -} - -static int JsonDnsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, - void *txptr, uint64_t tx_id) -{ - if (rs_dns_tx_is_request(txptr)) { - return JsonDnsLoggerToServer(tv, thread_data, p, f, alstate, txptr, tx_id); - } else if (rs_dns_tx_is_response(txptr)) { - return JsonDnsLoggerToClient(tv, thread_data, p, f, alstate, txptr, tx_id); - } - return TM_ECODE_OK; -} - -static TmEcode LogDnsLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogDnsLogThread *aft = SCCalloc(1, sizeof(LogDnsLogThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - - if(initdata == NULL) - { - SCLogDebug("Error getting context for EveLogDNS. \"initdata\" argument NULL"); - goto error_exit; - } - - /* Use the Output Context (file pointer and mutex) */ - aft->dnslog_ctx = ((OutputCtx *)initdata)->data; - aft->ctx = CreateEveThreadCtx(t, aft->dnslog_ctx->eve_ctx); - if (!aft->ctx) { - goto error_exit; - } - - *data = (void *)aft; - return TM_ECODE_OK; - -error_exit: - SCFree(aft); - return TM_ECODE_FAILED; -} - -static TmEcode LogDnsLogThreadDeinit(ThreadVars *t, void *data) -{ - LogDnsLogThread *aft = (LogDnsLogThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(aft->ctx); - - /* clear memory */ - memset(aft, 0, sizeof(LogDnsLogThread)); - - SCFree(aft); - return TM_ECODE_OK; -} - -static void LogDnsLogDeInitCtxSub(OutputCtx *output_ctx) -{ - SCLogDebug("cleaning up sub output_ctx %p", output_ctx); - LogDnsFileCtx *dnslog_ctx = (LogDnsFileCtx *)output_ctx->data; - SCFree(dnslog_ctx); - SCFree(output_ctx); -} - -static void JsonDnsLogParseConfig(LogDnsFileCtx *dnslog_ctx, ConfNode *conf, - const char *query_key, const char *answer_key, - const char *answer_types_key) -{ - const char *query = ConfNodeLookupChildValue(conf, query_key); - if (query != NULL) { - if (ConfValIsTrue(query)) { - dnslog_ctx->flags |= LOG_QUERIES; - } else { - dnslog_ctx->flags &= ~LOG_QUERIES; - } - } else { - dnslog_ctx->flags |= LOG_QUERIES; - } - - const char *response = ConfNodeLookupChildValue(conf, answer_key); - if (response != NULL) { - if (ConfValIsTrue(response)) { - dnslog_ctx->flags |= LOG_ANSWERS; - } else { - dnslog_ctx->flags &= ~LOG_ANSWERS; - } - } else { - dnslog_ctx->flags |= LOG_ANSWERS; - } - - ConfNode *custom; - if ((custom = ConfNodeLookupChild(conf, answer_types_key)) != NULL) { - dnslog_ctx->flags &= ~LOG_ALL_RRTYPES; - ConfNode *field; - TAILQ_FOREACH (field, &custom->head, next) { - DnsRRTypes f; - for (f = DNS_RRTYPE_A; f < DNS_RRTYPE_MAX; f++) { - if (strcasecmp(dns_rrtype_fields[f].config_rrtype, field->val) == 0) { - dnslog_ctx->flags |= dns_rrtype_fields[f].flags; - break; - } - } - } - } else { - dnslog_ctx->flags |= LOG_ALL_RRTYPES; - } -} - -static void JsonDnsCheckVersion(ConfNode *conf) -{ - if (conf == NULL) { - return; - } - - static bool v1_deprecation_warned = false; - const ConfNode *has_version = ConfNodeLookupChild(conf, "version"); - if (has_version != NULL) { - bool invalid = false; - intmax_t config_version; - if (ConfGetChildValueInt(conf, "version", &config_version)) { - switch(config_version) { - case 2: - break; - case 1: - if (!v1_deprecation_warned) { - SCLogWarning("DNS EVE v1 logging has been removed, will use v2"); - v1_deprecation_warned = true; - } - break; - default: - invalid = true; - break; - } - } else { - invalid = true; - } - if (invalid) { - SCLogWarning("Invalid EVE DNS version \"%s\", will use v2", has_version->val); - } - } -} - -static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf) -{ - dnslog_ctx->flags = ~0ULL; - - if (conf) { - JsonDnsLogParseConfig(dnslog_ctx, conf, "requests", "responses", "types"); - if (dnslog_ctx->flags & LOG_ANSWERS) { - ConfNode *format; - if ((format = ConfNodeLookupChild(conf, "formats")) != NULL) { - uint64_t flags = 0; - ConfNode *field; - TAILQ_FOREACH (field, &format->head, next) { - if (strcasecmp(field->val, "detailed") == 0) { - flags |= LOG_FORMAT_DETAILED; - } else if (strcasecmp(field->val, "grouped") == 0) { - flags |= LOG_FORMAT_GROUPED; - } else { - SCLogWarning("Invalid JSON DNS log format: %s", field->val); - } - } - if (flags) { - dnslog_ctx->flags &= ~LOG_FORMAT_ALL; - dnslog_ctx->flags |= flags; - } else { - SCLogWarning("Empty EVE DNS format array, using defaults"); - } - } else { - dnslog_ctx->flags |= LOG_FORMAT_ALL; - } - } - } -} - -static OutputInitResult JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - const char *enabled = ConfNodeLookupChildValue(conf, "enabled"); - if (enabled != NULL && !ConfValIsTrue(enabled)) { - result.ok = true; - return result; - } - - /* As only a single version of logging is supported, this exists to warn about - * unsupported versions. */ - JsonDnsCheckVersion(conf); - - OutputJsonCtx *ojc = parent_ctx->data; - - LogDnsFileCtx *dnslog_ctx = SCCalloc(1, sizeof(LogDnsFileCtx)); - if (unlikely(dnslog_ctx == NULL)) { - return result; - } - - dnslog_ctx->eve_ctx = ojc; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - SCFree(dnslog_ctx); - return result; - } - - output_ctx->data = dnslog_ctx; - output_ctx->DeInit = LogDnsLogDeInitCtxSub; - - JsonDnsLogInitFilters(dnslog_ctx, conf); - - SCLogDebug("DNS log sub-module initialized"); - - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - - -#define MODULE_NAME "JsonDnsLog" -void JsonDnsLogRegister (void) -{ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", MODULE_NAME, "eve-log.dns", - JsonDnsLogInitCtxSub, ALPROTO_DNS, JsonDnsLogger, LogDnsLogThreadInit, - LogDnsLogThreadDeinit, NULL); -} diff --git a/src/output-json-ftp.c b/src/output-json-ftp.c deleted file mode 100644 index 34422f72f4af..000000000000 --- a/src/output-json-ftp.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (C) 2017-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Jeff Lucovsky - * - * Implement JSON/eve logging app-layer FTP. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-mem.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-ftp.h" -#include "output-json-ftp.h" - -bool EveFTPLogCommand(void *vtx, JsonBuilder *jb) -{ - FTPTransaction *tx = vtx; - /* Preallocate array objects to simplify failure case */ - JsonBuilder *js_resplist = NULL; - if (!TAILQ_EMPTY(&tx->response_list)) { - js_resplist = jb_new_array(); - - if (unlikely(js_resplist == NULL)) { - return false; - } - } - jb_open_object(jb, "ftp"); - jb_set_string(jb, "command", tx->command_descriptor->command_name); - uint32_t min_length = tx->command_descriptor->command_length + 1; /* command + space */ - if (tx->request_length > min_length) { - jb_set_string_from_bytes(jb, - "command_data", - (const uint8_t *)tx->request + min_length, - tx->request_length - min_length - 1); - if (tx->request_truncated) { - JB_SET_TRUE(jb, "command_truncated"); - } else { - JB_SET_FALSE(jb, "command_truncated"); - } - } - - bool reply_truncated = false; - - if (!TAILQ_EMPTY(&tx->response_list)) { - int resp_cnt = 0; - FTPString *response; - bool is_cc_array_open = false; - TAILQ_FOREACH(response, &tx->response_list, next) { - /* handle multiple lines within the response, \r\n delimited */ - uint8_t *where = response->str; - uint16_t length = 0; - uint16_t pos; - if (response->len > 0 && response->len <= UINT16_MAX) { - length = (uint16_t)response->len - 1; - } else if (response->len > UINT16_MAX) { - length = UINT16_MAX; - } - if (!reply_truncated && response->truncated) { - reply_truncated = true; - } - while ((pos = JsonGetNextLineFromBuffer((const char *)where, length)) != UINT16_MAX) { - uint16_t offset = 0; - /* Try to find a completion code for this line */ - if (pos >= 3) { - /* Gather the completion code if present */ - if (isdigit(where[0]) && isdigit(where[1]) && isdigit(where[2])) { - if (!is_cc_array_open) { - jb_open_array(jb, "completion_code"); - is_cc_array_open = true; - } - jb_append_string_from_bytes(jb, (const uint8_t *)where, 3); - offset = 4; - } - } - /* move past 3 character completion code */ - if (pos >= offset) { - jb_append_string_from_bytes(js_resplist, (const uint8_t *)where + offset, pos - offset); - resp_cnt++; - } - - where += pos; - length -= pos; - } - } - - if (is_cc_array_open) { - jb_close(jb); - } - if (resp_cnt) { - jb_close(js_resplist); - jb_set_object(jb, "reply", js_resplist); - } - jb_free(js_resplist); - } - - if (tx->dyn_port) { - jb_set_uint(jb, "dynamic_port", tx->dyn_port); - } - - if (tx->command_descriptor->command == FTP_COMMAND_PORT || - tx->command_descriptor->command == FTP_COMMAND_EPRT) { - if (tx->active) { - JB_SET_STRING(jb, "mode", "active"); - } else { - JB_SET_STRING(jb, "mode", "passive"); - } - } - - if (tx->done) { - JB_SET_STRING(jb, "reply_received", "yes"); - } else { - JB_SET_STRING(jb, "reply_received", "no"); - } - - if (reply_truncated) { - JB_SET_TRUE(jb, "reply_truncated"); - } else { - JB_SET_FALSE(jb, "reply_truncated"); - } - jb_close(jb); - return true; -} - - -static int JsonFTPLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) -{ - SCEnter(); - OutputJsonThreadCtx *thread = thread_data; - - const char *event_type; - if (f->alproto == ALPROTO_FTPDATA) { - event_type = "ftp_data"; - } else { - event_type = "ftp"; - } - - JsonBuilder *jb = - CreateEveHeaderWithTxId(p, LOG_DIR_FLOW, event_type, NULL, tx_id, thread->ctx); - if (likely(jb)) { - if (f->alproto == ALPROTO_FTPDATA) { - if (!EveFTPDataAddMetadata(vtx, jb)) { - goto fail; - } - } else { - EveFTPLogCommand(vtx, jb); - } - - OutputJsonBuilderBuffer(jb, thread); - - jb_free(jb); - } - return TM_ECODE_OK; - -fail: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static OutputInitResult OutputFTPLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_FTP); - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_FTPDATA); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonFTPLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonFTPLog", "eve-log.ftp", - OutputFTPLogInitSub, ALPROTO_FTP, JsonFTPLogger, JsonLogThreadInit, JsonLogThreadDeinit, - NULL); - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonFTPLog", "eve-log.ftp", - OutputFTPLogInitSub, ALPROTO_FTPDATA, JsonFTPLogger, JsonLogThreadInit, - JsonLogThreadDeinit, NULL); - - SCLogDebug("FTP JSON logger registered."); -} diff --git a/src/output-json-http.c b/src/output-json-http.c deleted file mode 100644 index 5f44e955573d..000000000000 --- a/src/output-json-http.c +++ /dev/null @@ -1,653 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Tom DeCanio - * - * Implements HTTP JSON logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer-htp.h" -#include "app-layer-htp-file.h" -#include "app-layer-htp-xff.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "output-json.h" -#include "output-json-alert.h" -#include "output-json-http.h" -#include "util-byte.h" - -typedef struct LogHttpFileCtx_ { - uint32_t flags; /** Store mode */ - uint64_t fields;/** Store fields */ - HttpXFFCfg *xff_cfg; - HttpXFFCfg *parent_xff_cfg; - OutputJsonCtx *eve_ctx; -} LogHttpFileCtx; - -typedef struct JsonHttpLogThread_ { - LogHttpFileCtx *httplog_ctx; - uint32_t uri_cnt; - OutputJsonThreadCtx *ctx; -} JsonHttpLogThread; - -#define MAX_SIZE_HEADER_NAME 256 -#define MAX_SIZE_HEADER_VALUE 2048 - -#define LOG_HTTP_DEFAULT 0 -#define LOG_HTTP_EXTENDED 1 -#define LOG_HTTP_REQUEST 2 /* request field */ -#define LOG_HTTP_ARRAY 4 /* require array handling */ -#define LOG_HTTP_REQ_HEADERS 8 -#define LOG_HTTP_RES_HEADERS 16 - -typedef enum { - HTTP_FIELD_ACCEPT = 0, - HTTP_FIELD_ACCEPT_CHARSET, - HTTP_FIELD_ACCEPT_ENCODING, - HTTP_FIELD_ACCEPT_LANGUAGE, - HTTP_FIELD_ACCEPT_DATETIME, - HTTP_FIELD_AUTHORIZATION, - HTTP_FIELD_CACHE_CONTROL, - HTTP_FIELD_COOKIE, - HTTP_FIELD_FROM, - HTTP_FIELD_MAX_FORWARDS, - HTTP_FIELD_ORIGIN, - HTTP_FIELD_PRAGMA, - HTTP_FIELD_PROXY_AUTHORIZATION, - HTTP_FIELD_RANGE, - HTTP_FIELD_TE, - HTTP_FIELD_VIA, - HTTP_FIELD_X_REQUESTED_WITH, - HTTP_FIELD_DNT, - HTTP_FIELD_X_FORWARDED_PROTO, - HTTP_FIELD_X_AUTHENTICATED_USER, - HTTP_FIELD_X_FLASH_VERSION, - HTTP_FIELD_ACCEPT_RANGES, - HTTP_FIELD_AGE, - HTTP_FIELD_ALLOW, - HTTP_FIELD_CONNECTION, - HTTP_FIELD_CONTENT_ENCODING, - HTTP_FIELD_CONTENT_LANGUAGE, - HTTP_FIELD_CONTENT_LENGTH, - HTTP_FIELD_CONTENT_LOCATION, - HTTP_FIELD_CONTENT_MD5, - HTTP_FIELD_CONTENT_RANGE, - HTTP_FIELD_CONTENT_TYPE, - HTTP_FIELD_DATE, - HTTP_FIELD_ETAG, - HTTP_FIELD_EXPIRES, - HTTP_FIELD_LAST_MODIFIED, - HTTP_FIELD_LINK, - HTTP_FIELD_LOCATION, - HTTP_FIELD_PROXY_AUTHENTICATE, - HTTP_FIELD_REFERRER, - HTTP_FIELD_REFRESH, - HTTP_FIELD_RETRY_AFTER, - HTTP_FIELD_SERVER, - HTTP_FIELD_SET_COOKIE, - HTTP_FIELD_TRAILER, - HTTP_FIELD_TRANSFER_ENCODING, - HTTP_FIELD_UPGRADE, - HTTP_FIELD_VARY, - HTTP_FIELD_WARNING, - HTTP_FIELD_WWW_AUTHENTICATE, - HTTP_FIELD_TRUE_CLIENT_IP, - HTTP_FIELD_ORG_SRC_IP, - HTTP_FIELD_X_BLUECOAT_VIA, - HTTP_FIELD_SIZE -} HttpField; - -struct { - const char *config_field; - const char *htp_field; - uint32_t flags; -} http_fields[] = { - { "accept", "accept", LOG_HTTP_REQUEST }, - { "accept_charset", "accept-charset", LOG_HTTP_REQUEST }, - { "accept_encoding", "accept-encoding", LOG_HTTP_REQUEST }, - { "accept_language", "accept-language", LOG_HTTP_REQUEST }, - { "accept_datetime", "accept-datetime", LOG_HTTP_REQUEST }, - { "authorization", "authorization", LOG_HTTP_REQUEST }, - { "cache_control", "cache-control", LOG_HTTP_REQUEST }, - { "cookie", "cookie", LOG_HTTP_REQUEST | LOG_HTTP_ARRAY }, - { "from", "from", LOG_HTTP_REQUEST }, - { "max_forwards", "max-forwards", LOG_HTTP_REQUEST }, - { "origin", "origin", LOG_HTTP_REQUEST }, - { "pragma", "pragma", LOG_HTTP_REQUEST }, - { "proxy_authorization", "proxy-authorization", LOG_HTTP_REQUEST }, - { "range", "range", LOG_HTTP_REQUEST }, - { "te", "te", LOG_HTTP_REQUEST }, - { "via", "via", LOG_HTTP_REQUEST }, - { "x_requested_with", "x-requested-with", LOG_HTTP_REQUEST }, - { "dnt", "dnt", LOG_HTTP_REQUEST }, - { "x_forwarded_proto", "x-forwarded-proto", LOG_HTTP_REQUEST }, - { "x_authenticated_user", "x-authenticated-user", LOG_HTTP_REQUEST }, - { "x_flash_version", "x-flash-version", LOG_HTTP_REQUEST }, - { "accept_range", "accept-range", 0 }, - { "age", "age", 0 }, - { "allow", "allow", 0 }, - { "connection", "connection", 0 }, - { "content_encoding", "content-encoding", 0 }, - { "content_language", "content-language", 0 }, - { "content_length", "content-length", 0 }, - { "content_location", "content-location", 0 }, - { "content_md5", "content-md5", 0 }, - { "content_range", "content-range", 0 }, - { "content_type", "content-type", 0 }, - { "date", "date", 0 }, - { "etag", "etags", 0 }, - { "expires", "expires", 0 }, - { "last_modified", "last-modified", 0 }, - { "link", "link", 0 }, - { "location", "location", 0 }, - { "proxy_authenticate", "proxy-authenticate", 0 }, - { "referer", "referer", LOG_HTTP_EXTENDED }, - { "refresh", "refresh", 0 }, - { "retry_after", "retry-after", 0 }, - { "server", "server", 0 }, - { "set_cookie", "set-cookie", 0 }, - { "trailer", "trailer", 0 }, - { "transfer_encoding", "transfer-encoding", 0 }, - { "upgrade", "upgrade", 0 }, - { "vary", "vary", 0 }, - { "warning", "warning", 0 }, - { "www_authenticate", "www-authenticate", 0 }, - { "true_client_ip", "true-client-ip", LOG_HTTP_REQUEST }, - { "org_src_ip", "org-src-ip", LOG_HTTP_REQUEST }, - { "x_bluecoat_via", "x-bluecoat-via", LOG_HTTP_REQUEST }, -}; - -static void EveHttpLogJSONBasic(JsonBuilder *js, htp_tx_t *tx) -{ - /* hostname */ - if (tx->request_hostname != NULL) { - jb_set_string_from_bytes( - js, "hostname", bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname)); - } - - /* port */ - /* NOTE: this field will be set ONLY if the port is present in the - * hostname. It may be present in the header "Host" or in the URL. - * There is no connection (from the suricata point of view) between this - * port and the TCP destination port of the flow. - */ - if (tx->request_port_number >= 0) { - jb_set_uint(js, "http_port", tx->request_port_number); - } - - /* uri */ - if (tx->request_uri != NULL) { - jb_set_string_from_bytes(js, "url", bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); - } - - if (tx->request_headers != NULL) { - /* user agent */ - htp_header_t *h_user_agent = htp_table_get_c(tx->request_headers, "user-agent"); - if (h_user_agent != NULL) { - jb_set_string_from_bytes(js, "http_user_agent", bstr_ptr(h_user_agent->value), - bstr_len(h_user_agent->value)); - } - - /* x-forwarded-for */ - htp_header_t *h_x_forwarded_for = htp_table_get_c(tx->request_headers, "x-forwarded-for"); - if (h_x_forwarded_for != NULL) { - jb_set_string_from_bytes(js, "xff", bstr_ptr(h_x_forwarded_for->value), - bstr_len(h_x_forwarded_for->value)); - } - } - - /* content-type */ - if (tx->response_headers != NULL) { - htp_header_t *h_content_type = htp_table_get_c(tx->response_headers, "content-type"); - if (h_content_type != NULL) { - const size_t size = bstr_len(h_content_type->value) * 2 + 1; - char string[size]; - BytesToStringBuffer(bstr_ptr(h_content_type->value), bstr_len(h_content_type->value), string, size); - char *p = strchr(string, ';'); - if (p != NULL) - *p = '\0'; - jb_set_string(js, "http_content_type", string); - } - htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range"); - if (h_content_range != NULL) { - jb_open_object(js, "content_range"); - jb_set_string_from_bytes( - js, "raw", bstr_ptr(h_content_range->value), bstr_len(h_content_range->value)); - HTTPContentRange crparsed; - if (HTPParseContentRange(h_content_range->value, &crparsed) == 0) { - if (crparsed.start >= 0) - jb_set_uint(js, "start", crparsed.start); - if (crparsed.end >= 0) - jb_set_uint(js, "end", crparsed.end); - if (crparsed.size >= 0) - jb_set_uint(js, "size", crparsed.size); - } - jb_close(js); - } - } -} - -static void EveHttpLogJSONExtended(JsonBuilder *js, htp_tx_t *tx) -{ - /* referer */ - htp_header_t *h_referer = NULL; - if (tx->request_headers != NULL) { - h_referer = htp_table_get_c(tx->request_headers, "referer"); - } - if (h_referer != NULL) { - jb_set_string_from_bytes( - js, "http_refer", bstr_ptr(h_referer->value), bstr_len(h_referer->value)); - } - - /* method */ - if (tx->request_method != NULL) { - jb_set_string_from_bytes( - js, "http_method", bstr_ptr(tx->request_method), bstr_len(tx->request_method)); - } - - /* protocol */ - if (tx->request_protocol != NULL) { - jb_set_string_from_bytes( - js, "protocol", bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); - } - - /* response status */ - if (tx->response_status != NULL) { - const size_t status_size = bstr_len(tx->response_status) * 2 + 1; - char status_string[status_size]; - BytesToStringBuffer(bstr_ptr(tx->response_status), bstr_len(tx->response_status), - status_string, status_size); - unsigned int val = strtoul(status_string, NULL, 10); - jb_set_uint(js, "status", val); - - htp_header_t *h_location = htp_table_get_c(tx->response_headers, "location"); - if (h_location != NULL) { - jb_set_string_from_bytes( - js, "redirect", bstr_ptr(h_location->value), bstr_len(h_location->value)); - } - } - - /* length */ - jb_set_uint(js, "length", tx->response_message_len); -} - -static void EveHttpLogJSONHeaders( - JsonBuilder *js, uint32_t direction, htp_tx_t *tx, LogHttpFileCtx *http_ctx) -{ - htp_table_t * headers = direction & LOG_HTTP_REQ_HEADERS ? - tx->request_headers : tx->response_headers; - char name[MAX_SIZE_HEADER_NAME] = {0}; - char value[MAX_SIZE_HEADER_VALUE] = {0}; - size_t n = htp_table_size(headers); - JsonBuilderMark mark = { 0, 0, 0 }; - jb_get_mark(js, &mark); - bool array_empty = true; - jb_open_array(js, direction & LOG_HTTP_REQ_HEADERS ? "request_headers" : "response_headers"); - for (size_t i = 0; i < n; i++) { - htp_header_t *h = htp_table_get_index(headers, i, NULL); - if ((http_ctx->flags & direction) == 0 && http_ctx->fields != 0) { - bool tolog = false; - for (HttpField f = HTTP_FIELD_ACCEPT; f < HTTP_FIELD_SIZE; f++) { - if ((http_ctx->fields & (1ULL << f)) != 0) { - /* prevent logging a field twice if extended logging is - enabled */ - if (((http_ctx->flags & LOG_HTTP_EXTENDED) == 0) || - ((http_ctx->flags & LOG_HTTP_EXTENDED) != - (http_fields[f].flags & LOG_HTTP_EXTENDED))) { - if (bstr_cmp_c_nocase(h->name, http_fields[f].htp_field) == 0) { - tolog = true; - break; - } - } - } - } - if (!tolog) { - continue; - } - } - array_empty = false; - jb_start_object(js); - size_t size_name = bstr_len(h->name) < MAX_SIZE_HEADER_NAME - 1 ? - bstr_len(h->name) : MAX_SIZE_HEADER_NAME - 1; - memcpy(name, bstr_ptr(h->name), size_name); - name[size_name] = '\0'; - jb_set_string(js, "name", name); - size_t size_value = bstr_len(h->value) < MAX_SIZE_HEADER_VALUE - 1 ? - bstr_len(h->value) : MAX_SIZE_HEADER_VALUE - 1; - memcpy(value, bstr_ptr(h->value), size_value); - value[size_value] = '\0'; - jb_set_string(js, "value", value); - jb_close(js); - } - if (array_empty) { - jb_restore_mark(js, &mark); - } else { - // Close array. - jb_close(js); - } -} - -static void BodyPrintableBuffer(JsonBuilder *js, HtpBody *body, const char *key) -{ - if (body->sb != NULL && body->sb->region.buf != NULL) { - uint32_t offset = 0; - const uint8_t *body_data; - uint32_t body_data_len; - uint64_t body_offset; - - if (StreamingBufferGetData(body->sb, &body_data, - &body_data_len, &body_offset) == 0) { - return; - } - - uint8_t printable_buf[body_data_len + 1]; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), - body_data, body_data_len); - if (offset > 0) { - jb_set_string(js, key, (char *)printable_buf); - } - } -} - -void EveHttpLogJSONBodyPrintable(JsonBuilder *js, Flow *f, uint64_t tx_id) -{ - HtpState *htp_state = (HtpState *)FlowGetAppState(f); - if (htp_state) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, tx_id); - if (tx) { - HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (htud != NULL) { - BodyPrintableBuffer(js, &htud->request_body, "http_request_body_printable"); - BodyPrintableBuffer(js, &htud->response_body, "http_response_body_printable"); - } - } - } -} - -static void BodyBase64Buffer(JsonBuilder *js, HtpBody *body, const char *key) -{ - if (body->sb != NULL && body->sb->region.buf != NULL) { - const uint8_t *body_data; - uint32_t body_data_len; - uint64_t body_offset; - - if (StreamingBufferGetData(body->sb, &body_data, - &body_data_len, &body_offset) == 0) { - return; - } - - jb_set_base64(js, key, body_data, body_data_len); - } -} - -void EveHttpLogJSONBodyBase64(JsonBuilder *js, Flow *f, uint64_t tx_id) -{ - HtpState *htp_state = (HtpState *)FlowGetAppState(f); - if (htp_state) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, tx_id); - if (tx) { - HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); - if (htud != NULL) { - BodyBase64Buffer(js, &htud->request_body, "http_request_body"); - BodyBase64Buffer(js, &htud->response_body, "http_response_body"); - } - } - } -} - -/* JSON format logging */ -static void EveHttpLogJSON(JsonHttpLogThread *aft, JsonBuilder *js, htp_tx_t *tx, uint64_t tx_id) -{ - LogHttpFileCtx *http_ctx = aft->httplog_ctx; - jb_open_object(js, "http"); - - EveHttpLogJSONBasic(js, tx); - if (http_ctx->flags & LOG_HTTP_EXTENDED) - EveHttpLogJSONExtended(js, tx); - if (http_ctx->flags & LOG_HTTP_REQ_HEADERS || http_ctx->fields != 0) - EveHttpLogJSONHeaders(js, LOG_HTTP_REQ_HEADERS, tx, http_ctx); - if (http_ctx->flags & LOG_HTTP_RES_HEADERS || http_ctx->fields != 0) - EveHttpLogJSONHeaders(js, LOG_HTTP_RES_HEADERS, tx, http_ctx); - - jb_close(js); -} - -static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) -{ - SCEnter(); - - htp_tx_t *tx = txptr; - JsonHttpLogThread *jhl = (JsonHttpLogThread *)thread_data; - - JsonBuilder *js = CreateEveHeaderWithTxId( - p, LOG_DIR_FLOW, "http", NULL, tx_id, jhl->httplog_ctx->eve_ctx); - if (unlikely(js == NULL)) - return TM_ECODE_OK; - - SCLogDebug("got a HTTP request and now logging !!"); - - EveHttpLogJSON(jhl, js, tx, tx_id); - HttpXFFCfg *xff_cfg = jhl->httplog_ctx->xff_cfg != NULL ? - jhl->httplog_ctx->xff_cfg : jhl->httplog_ctx->parent_xff_cfg; - - /* xff header */ - if ((xff_cfg != NULL) && !(xff_cfg->flags & XFF_DISABLED) && p->flow != NULL) { - int have_xff_ip = 0; - char buffer[XFF_MAXLEN]; - - have_xff_ip = HttpXFFGetIPFromTx(p->flow, tx_id, xff_cfg, buffer, XFF_MAXLEN); - - if (have_xff_ip) { - if (xff_cfg->flags & XFF_EXTRADATA) { - jb_set_string(js, "xff", buffer); - } - else if (xff_cfg->flags & XFF_OVERWRITE) { - if (p->flowflags & FLOW_PKT_TOCLIENT) { - jb_set_string(js, "dest_ip", buffer); - } else { - jb_set_string(js, "src_ip", buffer); - } - } - } - } - - OutputJsonBuilderBuffer(js, jhl->ctx); - jb_free(js); - - SCReturnInt(TM_ECODE_OK); -} - -bool EveHttpAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) -{ - HtpState *htp_state = (HtpState *)FlowGetAppState(f); - if (htp_state) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, tx_id); - - if (tx) { - EveHttpLogJSONBasic(js, tx); - EveHttpLogJSONExtended(js, tx); - return true; - } - } - - return false; -} - -static void OutputHttpLogDeinitSub(OutputCtx *output_ctx) -{ - LogHttpFileCtx *http_ctx = output_ctx->data; - if (http_ctx->xff_cfg) { - SCFree(http_ctx->xff_cfg); - } - SCFree(http_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputHttpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ojc = parent_ctx->data; - - LogHttpFileCtx *http_ctx = SCCalloc(1, sizeof(LogHttpFileCtx)); - if (unlikely(http_ctx == NULL)) - return result; - memset(http_ctx, 0x00, sizeof(*http_ctx)); - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - SCFree(http_ctx); - return result; - } - - http_ctx->flags = LOG_HTTP_DEFAULT; - http_ctx->eve_ctx = ojc; - - if (conf) { - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - - if (extended != NULL) { - if (ConfValIsTrue(extended)) { - http_ctx->flags = LOG_HTTP_EXTENDED; - } - } - - const char *all_headers = ConfNodeLookupChildValue(conf, "dump-all-headers"); - if (all_headers != NULL) { - if (strncmp(all_headers, "both", 4) == 0) { - http_ctx->flags |= LOG_HTTP_REQ_HEADERS; - http_ctx->flags |= LOG_HTTP_RES_HEADERS; - } else if (strncmp(all_headers, "request", 7) == 0) { - http_ctx->flags |= LOG_HTTP_REQ_HEADERS; - } else if (strncmp(all_headers, "response", 8) == 0) { - http_ctx->flags |= LOG_HTTP_RES_HEADERS; - } - } - ConfNode *custom; - if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { - if ((http_ctx->flags & (LOG_HTTP_REQ_HEADERS | LOG_HTTP_RES_HEADERS)) == - (LOG_HTTP_REQ_HEADERS | LOG_HTTP_RES_HEADERS)) { - SCLogWarning("No need for custom as dump-all-headers is already present"); - } - ConfNode *field; - TAILQ_FOREACH (field, &custom->head, next) { - HttpField f; - for (f = HTTP_FIELD_ACCEPT; f < HTTP_FIELD_SIZE; f++) { - if ((strcmp(http_fields[f].config_field, field->val) == 0) || - (strcasecmp(http_fields[f].htp_field, field->val) == 0)) { - http_ctx->fields |= (1ULL << f); - break; - } - } - } - } - } - - if (conf != NULL && ConfNodeLookupChild(conf, "xff") != NULL) { - http_ctx->xff_cfg = SCCalloc(1, sizeof(HttpXFFCfg)); - if (http_ctx->xff_cfg != NULL) { - HttpXFFGetCfg(conf, http_ctx->xff_cfg); - } - } else if (ojc->xff_cfg) { - http_ctx->parent_xff_cfg = ojc->xff_cfg; - } - - output_ctx->data = http_ctx; - output_ctx->DeInit = OutputHttpLogDeinitSub; - - /* enable the logger for the app layer */ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP1); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonHttpLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - JsonHttpLogThread *aft = SCCalloc(1, sizeof(JsonHttpLogThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - - if(initdata == NULL) - { - SCLogDebug("Error getting context for EveLogHTTP. \"initdata\" argument NULL"); - goto error_exit; - } - - /* Use the Output Context (file pointer and mutex) */ - aft->httplog_ctx = ((OutputCtx *)initdata)->data; //TODO - - aft->ctx = CreateEveThreadCtx(t, aft->httplog_ctx->eve_ctx); - if (!aft->ctx) { - goto error_exit; - } - - *data = (void *)aft; - return TM_ECODE_OK; - -error_exit: - SCFree(aft); - return TM_ECODE_FAILED; -} - -static TmEcode JsonHttpLogThreadDeinit(ThreadVars *t, void *data) -{ - JsonHttpLogThread *aft = (JsonHttpLogThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - - FreeEveThreadCtx(aft->ctx); - - /* clear memory */ - memset(aft, 0, sizeof(JsonHttpLogThread)); - - SCFree(aft); - return TM_ECODE_OK; -} - -void JsonHttpLogRegister (void) -{ - /* register as child of eve-log */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonHttpLog", "eve-log.http", - OutputHttpLogInitSub, ALPROTO_HTTP1, JsonHttpLogger, JsonHttpLogThreadInit, - JsonHttpLogThreadDeinit, NULL); -} diff --git a/src/output-json-http.h b/src/output-json-http.h deleted file mode 100644 index cb358a4b314f..000000000000 --- a/src/output-json-http.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Tom DeCanio - */ - -#ifndef __OUTPUT_JSON_HTTP_H__ -#define __OUTPUT_JSON_HTTP_H__ - -void JsonHttpLogRegister(void); - -bool EveHttpAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js); -void EveHttpLogJSONBodyPrintable(JsonBuilder *js, Flow *f, uint64_t tx_id); -void EveHttpLogJSONBodyBase64(JsonBuilder *js, Flow *f, uint64_t tx_id); - -#endif /* __OUTPUT_JSON_HTTP_H__ */ - diff --git a/src/output-json-http2.c b/src/output-json-http2.c deleted file mode 100644 index cb096f37a043..000000000000 --- a/src/output-json-http2.c +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright (C) 2020-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Philippe Antoine - * - * Implements HTTP2 JSON logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" -#include "app-layer-parser.h" -#include "output.h" -#include "app-layer-http2.h" -#include "app-layer.h" -#include "util-privs.h" -#include "util-buffer.h" - -#include "util-logopenfile.h" - -#include "output-json.h" -#include "output-json-http2.h" -#include "rust.h" - -#define MODULE_NAME "LogHttp2Log" - -typedef struct OutputHttp2Ctx_ { - OutputJsonCtx *eve_ctx; -} OutputHttp2Ctx; - - -typedef struct JsonHttp2LogThread_ { - OutputHttp2Ctx *http2log_ctx; - OutputJsonThreadCtx *ctx; -} JsonHttp2LogThread; - -static int JsonHttp2Logger(ThreadVars *tv, void *thread_data, const Packet *p, - Flow *f, void *state, void *txptr, uint64_t tx_id) -{ - JsonHttp2LogThread *aft = (JsonHttp2LogThread *)thread_data; - - if (unlikely(state == NULL)) { - return 0; - } - - JsonBuilder *js = CreateEveHeaderWithTxId( - p, LOG_DIR_FLOW, "http", NULL, tx_id, aft->http2log_ctx->eve_ctx); - if (unlikely(js == NULL)) - return 0; - - if (!rs_http2_log_json(txptr, js)) { - goto end; - } - OutputJsonBuilderBuffer(js, aft->ctx); -end: - jb_free(js); - return 0; -} - -static TmEcode JsonHttp2LogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - JsonHttp2LogThread *aft = SCCalloc(1, sizeof(JsonHttp2LogThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - - if(initdata == NULL) - { - SCLogDebug("Error getting context for EveLogHTTP2. \"initdata\" argument NULL"); - goto error_exit; - } - - /* Use the Output Context (file pointer and mutex) */ - aft->http2log_ctx = ((OutputCtx *)initdata)->data; - aft->ctx = CreateEveThreadCtx(t, aft->http2log_ctx->eve_ctx); - if (!aft->ctx) { - goto error_exit; - } - - *data = (void *)aft; - return TM_ECODE_OK; - -error_exit: - SCFree(aft); - return TM_ECODE_FAILED; -} - -static TmEcode JsonHttp2LogThreadDeinit(ThreadVars *t, void *data) -{ - JsonHttp2LogThread *aft = (JsonHttp2LogThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - - FreeEveThreadCtx(aft->ctx); - /* clear memory */ - memset(aft, 0, sizeof(JsonHttp2LogThread)); - - SCFree(aft); - return TM_ECODE_OK; -} - -static void OutputHttp2LogDeinitSub(OutputCtx *output_ctx) -{ - OutputHttp2Ctx *http2_ctx = output_ctx->data; - SCFree(http2_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputHttp2LogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ojc = parent_ctx->data; - - OutputHttp2Ctx *http2_ctx = SCCalloc(1, sizeof(OutputHttp2Ctx)); - if (unlikely(http2_ctx == NULL)) - return result; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - SCFree(http2_ctx); - return result; - } - - http2_ctx->eve_ctx = ojc; - - output_ctx->data = http2_ctx; - output_ctx->DeInit = OutputHttp2LogDeinitSub; - - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP2); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -void JsonHttp2LogRegister (void) -{ - /* also register as child of eve-log */ - OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_TX, "eve-log", MODULE_NAME, "eve-log.http2", - OutputHttp2LogInitSub, ALPROTO_HTTP2, JsonHttp2Logger, HTTP2StateClosed, - HTTP2StateClosed, JsonHttp2LogThreadInit, JsonHttp2LogThreadDeinit, NULL); -} diff --git a/src/output-json-ike.c b/src/output-json-ike.c deleted file mode 100644 index e238a72e4f8f..000000000000 --- a/src/output-json-ike.c +++ /dev/null @@ -1,188 +0,0 @@ -/* Copyright (C) 2018-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * \author Frank Honza - * - * Implement JSON/eve logging app-layer IKE. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-ike.h" -#include "output-json-ike.h" - -#include "rust.h" - -#define LOG_IKE_DEFAULT 0 -#define LOG_IKE_EXTENDED (1 << 0) - -typedef struct LogIKEFileCtx_ { - uint32_t flags; - OutputJsonCtx *eve_ctx; -} LogIKEFileCtx; - -typedef struct LogIKELogThread_ { - LogIKEFileCtx *ikelog_ctx; - OutputJsonThreadCtx *ctx; -} LogIKELogThread; - -bool EveIKEAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) -{ - IKEState *state = FlowGetAppState(f); - if (state) { - IKETransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_IKE, state, tx_id); - if (tx) { - return rs_ike_logger_log(state, tx, LOG_IKE_EXTENDED, js); - } - } - - return false; -} - -static int JsonIKELogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, - void *tx, uint64_t tx_id) -{ - LogIKELogThread *thread = thread_data; - JsonBuilder *jb = - CreateEveHeader((Packet *)p, LOG_DIR_PACKET, "ike", NULL, thread->ikelog_ctx->eve_ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_FAILED; - } - - LogIKEFileCtx *ike_ctx = thread->ikelog_ctx; - if (!rs_ike_logger_log(state, tx, ike_ctx->flags, jb)) { - goto error; - } - - OutputJsonBuilderBuffer(jb, thread->ctx); - - jb_free(jb); - return TM_ECODE_OK; - -error: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static void OutputIKELogDeInitCtxSub(OutputCtx *output_ctx) -{ - LogIKEFileCtx *ikelog_ctx = (LogIKEFileCtx *)output_ctx->data; - SCFree(ikelog_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputIKELogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ajt = parent_ctx->data; - - LogIKEFileCtx *ikelog_ctx = SCCalloc(1, sizeof(*ikelog_ctx)); - if (unlikely(ikelog_ctx == NULL)) { - return result; - } - ikelog_ctx->eve_ctx = ajt; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(ikelog_ctx); - return result; - } - - ikelog_ctx->flags = LOG_IKE_DEFAULT; - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - if (extended) { - if (ConfValIsTrue(extended)) { - ikelog_ctx->flags = LOG_IKE_EXTENDED; - } - } - - output_ctx->data = ikelog_ctx; - output_ctx->DeInit = OutputIKELogDeInitCtxSub; - - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_IKE); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonIKELogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogIKELogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - if (initdata == NULL) { - SCLogDebug("Error getting context for EveLogIKE. \"initdata\" is NULL."); - goto error_exit; - } - - thread->ikelog_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->ikelog_ctx->eve_ctx); - if (!thread->ctx) { - goto error_exit; - } - - *data = (void *)thread; - return TM_ECODE_OK; - -error_exit: - SCFree(thread); - return TM_ECODE_FAILED; -} - -static TmEcode JsonIKELogThreadDeinit(ThreadVars *t, void *data) -{ - LogIKELogThread *thread = (LogIKELogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonIKELogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonIKELog", "eve-log.ike", - OutputIKELogInitSub, ALPROTO_IKE, JsonIKELogger, JsonIKELogThreadInit, - JsonIKELogThreadDeinit, NULL); -} diff --git a/src/output-json-krb5.c b/src/output-json-krb5.c deleted file mode 100644 index 9fc45c5d3c53..000000000000 --- a/src/output-json-krb5.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2018-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * - * Implement JSON/eve logging app-layer KRB5. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-krb5.h" -#include "output-json-krb5.h" - -#include "rust.h" - -static int JsonKRB5Logger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - KRB5Transaction *krb5tx = tx; - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "krb5", NULL, thread->ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_FAILED; - } - - if (!rs_krb5_log_json_response(krb5tx, jb)) { - goto error; - } - - OutputJsonBuilderBuffer(jb, thread); - - jb_free(jb); - return TM_ECODE_OK; - -error: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static OutputInitResult OutputKRB5LogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_KRB5); - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_KRB5); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonKRB5LogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonKRB5Log", "eve-log.krb5", - OutputKRB5LogInitSub, ALPROTO_KRB5, JsonKRB5Logger, JsonLogThreadInit, - JsonLogThreadDeinit, NULL); - - SCLogDebug("KRB5 JSON logger registered."); -} diff --git a/src/output-json-modbus.c b/src/output-json-modbus.c deleted file mode 100644 index 9e508ead9acc..000000000000 --- a/src/output-json-modbus.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (C) 2019-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" -#include "output.h" -#include "output-json.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "output-json-modbus.h" -#include "rust.h" - -typedef struct LogModbusFileCtx_ { - LogFileCtx *file_ctx; - OutputJsonCtx *eve_ctx; -} LogModbusFileCtx; - -typedef struct JsonModbusLogThread_ { - LogModbusFileCtx *modbuslog_ctx; - OutputJsonThreadCtx *ctx; -} JsonModbusLogThread; - -static int JsonModbusLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, - void *state, void *tx, uint64_t tx_id) -{ - JsonModbusLogThread *thread = thread_data; - - JsonBuilder *js = - CreateEveHeader(p, LOG_DIR_FLOW, "modbus", NULL, thread->modbuslog_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_OK; - } - if (!rs_modbus_to_json(tx, js)) { - jb_free(js); - return TM_ECODE_FAILED; - } - OutputJsonBuilderBuffer(js, thread->ctx); - - jb_free(js); - return TM_ECODE_OK; -} - -static void OutputModbusLogDeInitCtxSub(OutputCtx *output_ctx) -{ - LogModbusFileCtx *modbuslog_ctx = (LogModbusFileCtx *)output_ctx->data; - SCFree(modbuslog_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputModbusLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ajt = parent_ctx->data; - - LogModbusFileCtx *modbuslog_ctx = SCCalloc(1, sizeof(*modbuslog_ctx)); - if (unlikely(modbuslog_ctx == NULL)) { - return result; - } - modbuslog_ctx->file_ctx = ajt->file_ctx; - modbuslog_ctx->eve_ctx = ajt; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(modbuslog_ctx); - return result; - } - output_ctx->data = modbuslog_ctx; - output_ctx->DeInit = OutputModbusLogDeInitCtxSub; - - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_MODBUS); - - SCLogDebug("modbus log sub-module initialized."); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonModbusLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - if (initdata == NULL) { - SCLogDebug("Error getting context for EveLogModbus. \"initdata\" is NULL."); - return TM_ECODE_FAILED; - } - - JsonModbusLogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - thread->modbuslog_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->modbuslog_ctx->eve_ctx); - if (thread->ctx == NULL) { - goto error_exit; - } - - *data = (void *)thread; - return TM_ECODE_OK; - -error_exit: - SCFree(thread); - return TM_ECODE_FAILED; -} - -static TmEcode JsonModbusLogThreadDeinit(ThreadVars *t, void *data) -{ - JsonModbusLogThread *thread = (JsonModbusLogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonModbusLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonModbusLog", "eve-log.modbus", - OutputModbusLogInitSub, ALPROTO_MODBUS, JsonModbusLogger, JsonModbusLogThreadInit, - JsonModbusLogThreadDeinit, NULL); - - SCLogDebug("modbus json logger registered."); -} diff --git a/src/output-json-mqtt.c b/src/output-json-mqtt.c deleted file mode 100644 index 2f600343e20d..000000000000 --- a/src/output-json-mqtt.c +++ /dev/null @@ -1,188 +0,0 @@ -/* Copyright (C) 2020-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-mqtt.h" -#include "output-json-mqtt.h" -#include "rust.h" - -#define MQTT_LOG_PASSWORDS BIT_U32(0) -#define MQTT_DEFAULTS (MQTT_LOG_PASSWORDS) - -typedef struct LogMQTTFileCtx_ { - uint32_t flags; - OutputJsonCtx *eve_ctx; -} LogMQTTFileCtx; - -typedef struct LogMQTTLogThread_ { - LogMQTTFileCtx *mqttlog_ctx; - uint32_t count; - OutputJsonThreadCtx *ctx; -} LogMQTTLogThread; - -bool JsonMQTTAddMetadata(void *vtx, JsonBuilder *js) -{ - return rs_mqtt_logger_log(vtx, MQTT_DEFAULTS, js); -} - -static int JsonMQTTLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - LogMQTTLogThread *thread = thread_data; - enum OutputJsonLogDirection dir; - - if (rs_mqtt_tx_is_toclient((MQTTTransaction*) tx)) { - dir = LOG_DIR_FLOW_TOCLIENT; - } else { - dir = LOG_DIR_FLOW_TOSERVER; - } - - JsonBuilder *js = CreateEveHeader(p, dir, "mqtt", NULL, thread->mqttlog_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_FAILED; - } - - if (!rs_mqtt_logger_log(tx, thread->mqttlog_ctx->flags, js)) - goto error; - - OutputJsonBuilderBuffer(js, thread->ctx); - jb_free(js); - - return TM_ECODE_OK; - -error: - jb_free(js); - return TM_ECODE_FAILED; -} - -static void OutputMQTTLogDeInitCtxSub(OutputCtx *output_ctx) -{ - LogMQTTFileCtx *mqttlog_ctx = (LogMQTTFileCtx *)output_ctx->data; - SCFree(mqttlog_ctx); - SCFree(output_ctx); -} - -static void JsonMQTTLogParseConfig(ConfNode *conf, LogMQTTFileCtx *mqttlog_ctx) -{ - const char *query = ConfNodeLookupChildValue(conf, "passwords"); - if (query != NULL) { - if (ConfValIsTrue(query)) { - mqttlog_ctx->flags |= MQTT_LOG_PASSWORDS; - } else { - mqttlog_ctx->flags &= ~MQTT_LOG_PASSWORDS; - } - } else { - mqttlog_ctx->flags |= MQTT_LOG_PASSWORDS; - } -} - -static OutputInitResult OutputMQTTLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ajt = parent_ctx->data; - - LogMQTTFileCtx *mqttlog_ctx = SCCalloc(1, sizeof(*mqttlog_ctx)); - if (unlikely(mqttlog_ctx == NULL)) { - return result; - } - mqttlog_ctx->eve_ctx = ajt; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(mqttlog_ctx); - return result; - } - output_ctx->data = mqttlog_ctx; - output_ctx->DeInit = OutputMQTTLogDeInitCtxSub; - - JsonMQTTLogParseConfig(conf, mqttlog_ctx); - - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_MQTT); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonMQTTLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogMQTTLogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - if (initdata == NULL) { - SCLogDebug("Error getting context for EveLogMQTT. \"initdata\" is NULL."); - SCFree(thread); - return TM_ECODE_FAILED; - } - - thread->mqttlog_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->mqttlog_ctx->eve_ctx); - if (unlikely(thread->ctx == NULL)) { - SCFree(thread); - return TM_ECODE_FAILED; - } - - *data = (void *)thread; - - return TM_ECODE_OK; -} - -static TmEcode JsonMQTTLogThreadDeinit(ThreadVars *t, void *data) -{ - LogMQTTLogThread *thread = (LogMQTTLogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonMQTTLogRegister(void) -{ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonMQTTLog", "eve-log.mqtt", - OutputMQTTLogInitSub, ALPROTO_MQTT, JsonMQTTLogger, JsonMQTTLogThreadInit, - JsonMQTTLogThreadDeinit, NULL); -} diff --git a/src/output-json-nfs.c b/src/output-json-nfs.c deleted file mode 100644 index 946f85cdbbd5..000000000000 --- a/src/output-json-nfs.c +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (C) 2015-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implement JSON/eve logging app-layer NFS. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "output-json-nfs.h" - -#include "rust.h" - -bool EveNFSAddMetadataRPC(const Flow *f, uint64_t tx_id, JsonBuilder *jb) -{ - NFSState *state = FlowGetAppState(f); - if (state) { - NFSTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_NFS, state, tx_id); - if (tx) { - return rs_rpc_log_json_response(tx, jb); - } - } - return false; -} - -bool EveNFSAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb) -{ - NFSState *state = FlowGetAppState(f); - if (state) { - NFSTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_NFS, state, tx_id); - if (tx) { - return rs_nfs_log_json_response(state, tx, jb); - } - } - return false; -} - -static int JsonNFSLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - NFSTransaction *nfstx = tx; - OutputJsonThreadCtx *thread = thread_data; - - if (rs_nfs_tx_logging_is_filtered(state, nfstx)) - return TM_ECODE_OK; - - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "nfs", NULL, thread->ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_OK; - } - - jb_open_object(jb, "rpc"); - rs_rpc_log_json_response(tx, jb); - jb_close(jb); - - jb_open_object(jb, "nfs"); - rs_nfs_log_json_response(state, tx, jb); - jb_close(jb); - - MemBufferReset(thread->buffer); - OutputJsonBuilderBuffer(jb, thread); - jb_free(jb); - return TM_ECODE_OK; -} - -static OutputInitResult NFSLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_NFS); - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_NFS); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonNFSLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonNFSLog", "eve-log.nfs", NFSLogInitSub, - ALPROTO_NFS, JsonNFSLogger, JsonLogThreadInit, JsonLogThreadDeinit, NULL); - - SCLogDebug("NFS JSON logger registered."); -} diff --git a/src/output-json-pgsql.c b/src/output-json-pgsql.c deleted file mode 100644 index 43eb95709844..000000000000 --- a/src/output-json-pgsql.c +++ /dev/null @@ -1,194 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Juliana Fajardini - * - * Implement JSON/eve logging for app-layer Pgsql. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "output-json-pgsql.h" -#include "rust.h" - -#define PGSQL_LOG_PASSWORDS BIT_U32(0) - -typedef struct OutputPgsqlCtx_ { - uint32_t flags; - OutputJsonCtx *eve_ctx; -} OutputPgsqlCtx; - -typedef struct LogPgsqlLogThread_ { - OutputPgsqlCtx *pgsqllog_ctx; - OutputJsonThreadCtx *ctx; -} LogPgsqlLogThread; - -static int JsonPgsqlLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, - void *txptr, uint64_t tx_id) -{ - LogPgsqlLogThread *thread = thread_data; - SCLogDebug("Logging pgsql transaction %" PRIu64 ".", tx_id); - - JsonBuilder *jb = - CreateEveHeader(p, LOG_DIR_FLOW, "pgsql", NULL, thread->pgsqllog_ctx->eve_ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_FAILED; - } - - jb_open_object(jb, "pgsql"); - if (!rs_pgsql_logger(txptr, thread->pgsqllog_ctx->flags, jb)) { - goto error; - } - jb_close(jb); - - OutputJsonBuilderBuffer(jb, thread->ctx); - jb_free(jb); - - return TM_ECODE_OK; - -error: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static void OutputPgsqlLogDeInitCtxSub(OutputCtx *output_ctx) -{ - OutputPgsqlCtx *pgsqllog_ctx = (OutputPgsqlCtx *)output_ctx->data; - SCFree(pgsqllog_ctx); - SCFree(output_ctx); -} - -static void JsonPgsqlLogParseConfig(ConfNode *conf, OutputPgsqlCtx *pgsqllog_ctx) -{ - pgsqllog_ctx->flags = ~0U; - - const char *query = ConfNodeLookupChildValue(conf, "passwords"); - if (query != NULL) { - if (ConfValIsTrue(query)) { - pgsqllog_ctx->flags |= PGSQL_LOG_PASSWORDS; - } else { - pgsqllog_ctx->flags &= ~PGSQL_LOG_PASSWORDS; - } - } else { - pgsqllog_ctx->flags &= ~PGSQL_LOG_PASSWORDS; - } -} - -static OutputInitResult OutputPgsqlLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ojc = parent_ctx->data; - - OutputPgsqlCtx *pgsql_ctx = SCCalloc(1, sizeof(OutputPgsqlCtx)); - if (unlikely(pgsql_ctx == NULL)) - return result; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - SCFree(pgsql_ctx); - return result; - } - - pgsql_ctx->eve_ctx = ojc; - - output_ctx->data = pgsql_ctx; - output_ctx->DeInit = OutputPgsqlLogDeInitCtxSub; - - JsonPgsqlLogParseConfig(conf, pgsql_ctx); - - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_PGSQL); - - SCLogDebug("PostgreSQL log sub-module initialized."); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonPgsqlLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogPgsqlLogThread *thread = SCCalloc(1, sizeof(LogPgsqlLogThread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - if (initdata == NULL) { - SCLogDebug("Error getting context for EveLogPgsql. \"initdata\" is NULL."); - goto error_exit; - } - - thread->pgsqllog_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->pgsqllog_ctx->eve_ctx); - if (!thread->ctx) { - goto error_exit; - } - *data = (void *)thread; - - return TM_ECODE_OK; - -error_exit: - SCFree(thread); - return TM_ECODE_FAILED; -} - -static TmEcode JsonPgsqlLogThreadDeinit(ThreadVars *t, void *data) -{ - LogPgsqlLogThread *thread = (LogPgsqlLogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonPgsqlLogRegister(void) -{ - /* PGSQL_START_REMOVE */ - if (ConfGetNode("app-layer.protocols.pgsql") == NULL) { - SCLogDebug("Disabling Pgsql eve-logger"); - return; - } - /* PGSQL_END_REMOVE */ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonPgsqlLog", "eve-log.pgsql", - OutputPgsqlLogInitSub, ALPROTO_PGSQL, JsonPgsqlLogger, JsonPgsqlLogThreadInit, - JsonPgsqlLogThreadDeinit, NULL); - - SCLogDebug("PostgreSQL JSON logger registered."); -} diff --git a/src/output-json-quic.c b/src/output-json-quic.c deleted file mode 100644 index 830ac78fdfbb..000000000000 --- a/src/output-json-quic.c +++ /dev/null @@ -1,151 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * Implements JSON/eve logging for Quic app-layer. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" -#include "output.h" -#include "output-json.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "output-json-quic.h" -#include "rust.h" - -typedef struct LogQuicFileCtx_ { - LogFileCtx *file_ctx; - OutputJsonCtx *eve_ctx; -} LogQuicFileCtx; - -typedef struct JsonQuicLogThread_ { - LogQuicFileCtx *quiclog_ctx; - OutputJsonThreadCtx *ctx; -} JsonQuicLogThread; - -static int JsonQuicLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, - void *tx, uint64_t tx_id) -{ - JsonQuicLogThread *thread = thread_data; - - JsonBuilder *js = - CreateEveHeader(p, LOG_DIR_PACKET, "quic", NULL, thread->quiclog_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_OK; - } - if (!rs_quic_to_json(tx, js)) { - jb_free(js); - return TM_ECODE_FAILED; - } - OutputJsonBuilderBuffer(js, thread->ctx); - - jb_free(js); - return TM_ECODE_OK; -} - -static void OutputQuicLogDeInitCtxSub(OutputCtx *output_ctx) -{ - LogQuicFileCtx *quiclog_ctx = (LogQuicFileCtx *)output_ctx->data; - SCFree(quiclog_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputQuicLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ajt = parent_ctx->data; - - LogQuicFileCtx *quiclog_ctx = SCCalloc(1, sizeof(*quiclog_ctx)); - if (unlikely(quiclog_ctx == NULL)) { - return result; - } - quiclog_ctx->file_ctx = ajt->file_ctx; - quiclog_ctx->eve_ctx = ajt; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(quiclog_ctx); - return result; - } - output_ctx->data = quiclog_ctx; - output_ctx->DeInit = OutputQuicLogDeInitCtxSub; - - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_QUIC); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonQuicLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - if (initdata == NULL) { - SCLogDebug("Error getting context for EveLogQuic. \"initdata\" is NULL."); - return TM_ECODE_FAILED; - } - - JsonQuicLogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - thread->quiclog_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->quiclog_ctx->eve_ctx); - if (thread->ctx == NULL) { - goto error_exit; - } - - *data = (void *)thread; - return TM_ECODE_OK; - -error_exit: - SCFree(thread); - return TM_ECODE_FAILED; -} - -static TmEcode JsonQuicLogThreadDeinit(ThreadVars *t, void *data) -{ - JsonQuicLogThread *thread = (JsonQuicLogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonQuicLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonQuicLog", "eve-log.quic", - OutputQuicLogInitSub, ALPROTO_QUIC, JsonQuicLogger, JsonQuicLogThreadInit, - JsonQuicLogThreadDeinit, NULL); - - SCLogDebug("quic json logger registered."); -} diff --git a/src/output-json-rdp.c b/src/output-json-rdp.c deleted file mode 100644 index bc5d9ae9df89..000000000000 --- a/src/output-json-rdp.c +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (C) 2019-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Zach Kelly - * - * Application layer logger for RDP - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" -#include "output.h" -#include "output-json.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-rdp.h" -#include "output-json-rdp.h" -#include "rust.h" - -static int JsonRdpLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *js = CreateEveHeader(p, LOG_DIR_PACKET, "rdp", NULL, thread->ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_OK; - } - if (!rs_rdp_to_json(tx, js)) { - jb_free(js); - return TM_ECODE_FAILED; - } - OutputJsonBuilderBuffer(js, thread); - - jb_free(js); - return TM_ECODE_OK; -} - -static OutputInitResult OutputRdpLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_RDP); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonRdpLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonRdpLog", "eve-log.rdp", - OutputRdpLogInitSub, ALPROTO_RDP, JsonRdpLogger, JsonLogThreadInit, JsonLogThreadDeinit, - NULL); - - SCLogDebug("rdp json logger registered."); -} diff --git a/src/output-json-rfb.c b/src/output-json-rfb.c deleted file mode 100644 index e2b832bece13..000000000000 --- a/src/output-json-rfb.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (C) 2020-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Frank Honza - * - * Implement JSON/eve logging app-layer RFB. - */ - -#include "suricata-common.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-rfb.h" -#include "output-json-rfb.h" - -#include "rust-bindings.h" - -static int JsonRFBLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "rfb", NULL, thread->ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_FAILED; - } - - if (!rs_rfb_logger_log(tx, js)) { - goto error; - } - - OutputJsonBuilderBuffer(js, thread); - jb_free(js); - - return TM_ECODE_OK; - -error: - jb_free(js); - return TM_ECODE_FAILED; -} - -static OutputInitResult OutputRFBLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_RFB); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonRFBLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonRFBLog", "eve-log.rfb", - OutputRFBLogInitSub, ALPROTO_RFB, JsonRFBLogger, JsonLogThreadInit, JsonLogThreadDeinit, - NULL); -} diff --git a/src/output-json-sip.c b/src/output-json-sip.c deleted file mode 100644 index 7dd442cf6aba..000000000000 --- a/src/output-json-sip.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (C) 2018-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Giuseppe Longo - * - * Implement JSON/eve logging app-layer SIP. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-sip.h" -#include "output-json-sip.h" - -#include "rust.h" - -static int JsonSIPLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - SIPTransaction *siptx = tx; - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *js = CreateEveHeader((Packet *)p, LOG_DIR_PACKET, "sip", NULL, thread->ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_OK; - } - - if (!rs_sip_log_json(siptx, js)) { - goto error; - } - - OutputJsonBuilderBuffer(js, thread); - jb_free(js); - - return TM_ECODE_OK; - -error: - jb_free(js); - return TM_ECODE_FAILED; -} - -static OutputInitResult OutputSIPLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_SIP); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonSIPLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSIPLog", "eve-log.sip", - OutputSIPLogInitSub, ALPROTO_SIP, JsonSIPLogger, JsonLogThreadInit, JsonLogThreadDeinit, - NULL); - - SCLogDebug("SIP JSON logger registered."); -} diff --git a/src/output-json-smb.c b/src/output-json-smb.c deleted file mode 100644 index 492c50fe27a1..000000000000 --- a/src/output-json-smb.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (C) 2017-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implement JSON/eve logging app-layer SMB. - */ - -#include "suricata-common.h" -#include "util-buffer.h" -#include "output.h" -#include "output-json.h" -#include "app-layer-parser.h" -#include "output-json-smb.h" -#include "rust.h" - -bool EveSMBAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb) -{ - SMBState *state = FlowGetAppState(f); - if (state) { - SMBTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_SMB, state, tx_id); - if (tx) { - return rs_smb_log_json_response(jb, state, tx); - } - } - return false; -} - -static int JsonSMBLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_FLOW, "smb", NULL, thread->ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_FAILED; - } - - jb_open_object(jb, "smb"); - if (!rs_smb_log_json_response(jb, state, tx)) { - goto error; - } - jb_close(jb); - - OutputJsonBuilderBuffer(jb, thread); - - jb_free(jb); - return TM_ECODE_OK; - -error: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static OutputInitResult SMBLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMB); - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_SMB); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonSMBLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSMBLog", "eve-log.smb", SMBLogInitSub, - ALPROTO_SMB, JsonSMBLogger, JsonLogThreadInit, JsonLogThreadDeinit, NULL); - - SCLogDebug("SMB JSON logger registered."); -} diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c deleted file mode 100644 index f7674687c5c4..000000000000 --- a/src/output-json-smtp.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Tom DeCanio - * - * Implements SMTP JSON logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer-smtp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" - -#include "output-json.h" -#include "output-json-smtp.h" -#include "output-json-email-common.h" - -static void EveSmtpDataLogger(void *state, void *vtx, JsonBuilder *js) -{ - SMTPTransaction *tx = vtx; - SMTPString *rcptto_str; - if (((SMTPState *)state)->helo) { - jb_set_string(js, "helo", (const char *)((SMTPState *)state)->helo); - } - if (tx->mail_from) { - jb_set_string(js, "mail_from", (const char *)tx->mail_from); - } - if (!TAILQ_EMPTY(&tx->rcpt_to_list)) { - jb_open_array(js, "rcpt_to"); - TAILQ_FOREACH(rcptto_str, &tx->rcpt_to_list, next) { - jb_append_string(js, (char *)rcptto_str->str); - } - jb_close(js); - } -} - -static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - SCEnter(); - JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; - - JsonBuilder *jb = CreateEveHeaderWithTxId( - p, LOG_DIR_FLOW, "smtp", NULL, tx_id, jhl->emaillog_ctx->eve_ctx); - if (unlikely(jb == NULL)) - return TM_ECODE_OK; - - jb_open_object(jb, "smtp"); - EveSmtpDataLogger(state, tx, jb); - jb_close(jb); - - EveEmailLogJson(jhl, jb, p, f, state, tx, tx_id); - OutputJsonBuilderBuffer(jb, jhl->ctx); - - jb_free(jb); - - SCReturnInt(TM_ECODE_OK); - -} - -bool EveSMTPAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) -{ - SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); - if (smtp_state) { - SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); - if (tx) { - EveSmtpDataLogger(smtp_state, tx, js); - return true; - } - } - - return false; -} - -static void OutputSmtpLogDeInitCtxSub(OutputCtx *output_ctx) -{ - SCLogDebug("cleaning up sub output_ctx %p", output_ctx); - OutputJsonEmailCtx *email_ctx = output_ctx->data; - if (email_ctx != NULL) { - SCFree(email_ctx); - } - SCFree(output_ctx); -} - -static OutputInitResult OutputSmtpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ojc = parent_ctx->data; - - OutputJsonEmailCtx *email_ctx = SCCalloc(1, sizeof(OutputJsonEmailCtx)); - if (unlikely(email_ctx == NULL)) - return result; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - SCFree(email_ctx); - return result; - } - - email_ctx->eve_ctx = ojc; - - OutputEmailInitConf(conf, email_ctx); - - output_ctx->data = email_ctx; - output_ctx->DeInit = OutputSmtpLogDeInitCtxSub; - - /* enable the logger for the app layer */ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonSmtpLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - JsonEmailLogThread *aft = SCCalloc(1, sizeof(JsonEmailLogThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - - if(initdata == NULL) { - SCLogDebug("Error getting context for EveLogSMTP. \"initdata\" argument NULL"); - goto error_exit; - } - - /* Use the Output Context (file pointer and mutex) */ - aft->emaillog_ctx = ((OutputCtx *)initdata)->data; - - aft->ctx = CreateEveThreadCtx(t, aft->emaillog_ctx->eve_ctx); - if (aft->ctx == NULL) { - goto error_exit; - } - - *data = (void *)aft; - return TM_ECODE_OK; - -error_exit: - SCFree(aft); - return TM_ECODE_FAILED; -} - -static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) -{ - JsonEmailLogThread *aft = (JsonEmailLogThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(aft->ctx); - - /* clear memory */ - memset(aft, 0, sizeof(JsonEmailLogThread)); - - SCFree(aft); - return TM_ECODE_OK; -} - -void JsonSmtpLogRegister (void) { - /* register as child of eve-log */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSmtpLog", "eve-log.smtp", - OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, - JsonSmtpLogThreadDeinit, NULL); -} diff --git a/src/output-json-snmp.c b/src/output-json-snmp.c deleted file mode 100644 index cbf0a7c992e4..000000000000 --- a/src/output-json-snmp.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (C) 2018-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pierre Chifflier - * - * Implement JSON/eve logging app-layer SNMP. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-snmp.h" -#include "output-json-snmp.h" - -#include "rust.h" - -static int JsonSNMPLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - SNMPTransaction *snmptx = tx; - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "snmp", NULL, thread->ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_FAILED; - } - - if (!rs_snmp_log_json_response(snmptx, jb)) { - goto error; - } - - OutputJsonBuilderBuffer(jb, thread); - - jb_free(jb); - return TM_ECODE_OK; - -error: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static OutputInitResult OutputSNMPLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_SNMP); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonSNMPLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSNMPLog", "eve-log.snmp", - OutputSNMPLogInitSub, ALPROTO_SNMP, JsonSNMPLogger, JsonLogThreadInit, - JsonLogThreadDeinit, NULL); - - SCLogDebug("SNMP JSON logger registered."); -} diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c deleted file mode 100644 index 45a8d8eab333..000000000000 --- a/src/output-json-ssh.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (C) 2014-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implements SSH JSON logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" -#include "app-layer-parser.h" -#include "output.h" -#include "app-layer-ssh.h" -#include "app-layer.h" -#include "util-privs.h" -#include "util-buffer.h" - -#include "util-logopenfile.h" - -#include "output-json.h" -#include "output-json-ssh.h" -#include "rust.h" - -#define MODULE_NAME "LogSshLog" - -static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p, - Flow *f, void *state, void *txptr, uint64_t tx_id) -{ - OutputJsonThreadCtx *thread = thread_data; - - if (unlikely(state == NULL)) { - return 0; - } - - JsonBuilder *js = CreateEveHeaderWithTxId(p, LOG_DIR_FLOW, "ssh", NULL, tx_id, thread->ctx); - if (unlikely(js == NULL)) - return 0; - - if (!rs_ssh_log_json(txptr, js)) { - goto end; - } - OutputJsonBuilderBuffer(js, thread); - -end: - jb_free(js); - return 0; -} - -static OutputInitResult OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonSshLogRegister (void) -{ - /* register as child of eve-log */ - OutputRegisterTxSubModuleWithCondition(LOGGER_JSON_TX, "eve-log", "JsonSshLog", "eve-log.ssh", - OutputSshLogInitSub, ALPROTO_SSH, JsonSshLogger, SSHTxLogCondition, JsonLogThreadInit, - JsonLogThreadDeinit, NULL); -} diff --git a/src/output-json-template.c b/src/output-json-template.c deleted file mode 100644 index 2ca48b7ae373..000000000000 --- a/src/output-json-template.c +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (C) 2018-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/* - * TODO: Update \author in this file and in output-json-template.h. - * TODO: Remove SCLogNotice statements, or convert to debug. - * TODO: Implement your app-layers logging. - */ - -/** - * \file - * - * \author FirstName LastName - * - * Implement JSON/eve logging app-layer Template. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "output-json-template.h" -#include "rust.h" - -typedef struct LogTemplateFileCtx_ { - uint32_t flags; - OutputJsonCtx *eve_ctx; -} LogTemplateFileCtx; - -typedef struct LogTemplateLogThread_ { - LogTemplateFileCtx *templatelog_ctx; - OutputJsonThreadCtx *ctx; -} LogTemplateLogThread; - -static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, - void *state, void *tx, uint64_t tx_id) -{ - SCLogNotice("JsonTemplateLogger"); - LogTemplateLogThread *thread = thread_data; - - JsonBuilder *js = - CreateEveHeader(p, LOG_DIR_PACKET, "template", NULL, thread->templatelog_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return TM_ECODE_FAILED; - } - - if (!rs_template_logger_log(tx, js)) { - goto error; - } - - OutputJsonBuilderBuffer(js, thread->ctx); - jb_free(js); - - return TM_ECODE_OK; - -error: - jb_free(js); - return TM_ECODE_FAILED; -} - -static void OutputTemplateLogDeInitCtxSub(OutputCtx *output_ctx) -{ - LogTemplateFileCtx *templatelog_ctx = (LogTemplateFileCtx *)output_ctx->data; - SCFree(templatelog_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputTemplateLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ajt = parent_ctx->data; - - LogTemplateFileCtx *templatelog_ctx = SCCalloc(1, sizeof(*templatelog_ctx)); - if (unlikely(templatelog_ctx == NULL)) { - return result; - } - templatelog_ctx->eve_ctx = ajt; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); - if (unlikely(output_ctx == NULL)) { - SCFree(templatelog_ctx); - return result; - } - output_ctx->data = templatelog_ctx; - output_ctx->DeInit = OutputTemplateLogDeInitCtxSub; - - SCLogNotice("Template log sub-module initialized."); - - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TEMPLATE); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -static TmEcode JsonTemplateLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - LogTemplateLogThread *thread = SCCalloc(1, sizeof(*thread)); - if (unlikely(thread == NULL)) { - return TM_ECODE_FAILED; - } - - if (initdata == NULL) { - SCLogDebug("Error getting context for EveLogTemplate. \"initdata\" is NULL."); - goto error_exit; - } - - thread->templatelog_ctx = ((OutputCtx *)initdata)->data; - thread->ctx = CreateEveThreadCtx(t, thread->templatelog_ctx->eve_ctx); - if (!thread->ctx) { - goto error_exit; - } - *data = (void *)thread; - - return TM_ECODE_OK; - -error_exit: - SCFree(thread); - return TM_ECODE_FAILED; -} - -static TmEcode JsonTemplateLogThreadDeinit(ThreadVars *t, void *data) -{ - LogTemplateLogThread *thread = (LogTemplateLogThread *)data; - if (thread == NULL) { - return TM_ECODE_OK; - } - FreeEveThreadCtx(thread->ctx); - SCFree(thread); - return TM_ECODE_OK; -} - -void JsonTemplateLogRegister(void) -{ - /* TEMPLATE_START_REMOVE */ - if (ConfGetNode("app-layer.protocols.template") == NULL) { - return; - } - /* TEMPLATE_END_REMOVE */ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonTemplateLog", "eve-log.template", - OutputTemplateLogInitSub, ALPROTO_TEMPLATE, JsonTemplateLogger, - JsonTemplateLogThreadInit, JsonTemplateLogThreadDeinit, NULL); - - SCLogNotice("Template JSON logger registered."); -} diff --git a/src/output-json-tftp.c b/src/output-json-tftp.c deleted file mode 100644 index a0bc9ee1809e..000000000000 --- a/src/output-json-tftp.c +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (C) 2020-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Clément Galland - * - * Implement JSON/eve logging app-layer TFTP. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-unittest.h" -#include "util-buffer.h" -#include "util-debug.h" -#include "util-byte.h" - -#include "output.h" -#include "output-json.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "app-layer-tftp.h" -#include "output-json-tftp.h" - -#include "rust.h" - -static int JsonTFTPLogger(ThreadVars *tv, void *thread_data, - const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) -{ - OutputJsonThreadCtx *thread = thread_data; - - JsonBuilder *jb = CreateEveHeader(p, LOG_DIR_PACKET, "tftp", NULL, thread->ctx); - if (unlikely(jb == NULL)) { - return TM_ECODE_FAILED; - } - - if (unlikely(!rs_tftp_log_json_request(tx, jb))) { - goto error; - } - - OutputJsonBuilderBuffer(jb, thread); - - jb_free(jb); - return TM_ECODE_OK; - -error: - jb_free(jb); - return TM_ECODE_FAILED; -} - -static OutputInitResult OutputTFTPLogInitSub(ConfNode *conf, - OutputCtx *parent_ctx) -{ - AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_TFTP); - return OutputJsonLogInitSub(conf, parent_ctx); -} - -void JsonTFTPLogRegister(void) -{ - /* Register as an eve sub-module. */ - OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonTFTPLog", "eve-log.tftp", - OutputTFTPLogInitSub, ALPROTO_TFTP, JsonTFTPLogger, JsonLogThreadInit, - JsonLogThreadDeinit, NULL); - - SCLogDebug("TFTP JSON logger registered."); -} diff --git a/src/output-json-tls.c b/src/output-json-tls.c deleted file mode 100644 index 7460a32f2574..000000000000 --- a/src/output-json-tls.c +++ /dev/null @@ -1,665 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Tom DeCanio - * - * Implements TLS JSON logging portion of the engine. - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-time.h" -#include "util-unittest.h" - -#include "util-debug.h" -#include "app-layer-parser.h" -#include "output.h" -#include "app-layer-ssl.h" -#include "app-layer.h" -#include "util-privs.h" -#include "util-buffer.h" - -#include "util-logopenfile.h" -#include "util-ja3.h" - -#include "output-json.h" -#include "output-json-tls.h" - -SC_ATOMIC_EXTERN(unsigned int, cert_id); - -#define MODULE_NAME "LogTlsLog" -#define DEFAULT_LOG_FILENAME "tls.json" - -#define LOG_TLS_DEFAULT 0 -#define LOG_TLS_EXTENDED (1 << 0) -#define LOG_TLS_CUSTOM (1 << 1) -#define LOG_TLS_SESSION_RESUMPTION (1 << 2) - -#define LOG_TLS_FIELD_VERSION (1 << 0) -#define LOG_TLS_FIELD_SUBJECT (1 << 1) -#define LOG_TLS_FIELD_ISSUER (1 << 2) -#define LOG_TLS_FIELD_SERIAL (1 << 3) -#define LOG_TLS_FIELD_FINGERPRINT (1 << 4) -#define LOG_TLS_FIELD_NOTBEFORE (1 << 5) -#define LOG_TLS_FIELD_NOTAFTER (1 << 6) -#define LOG_TLS_FIELD_SNI (1 << 7) -#define LOG_TLS_FIELD_CERTIFICATE (1 << 8) -#define LOG_TLS_FIELD_CHAIN (1 << 9) -#define LOG_TLS_FIELD_SESSION_RESUMED (1 << 10) -#define LOG_TLS_FIELD_JA3 (1 << 11) -#define LOG_TLS_FIELD_JA3S (1 << 12) -#define LOG_TLS_FIELD_CLIENT (1 << 13) /**< client fields (issuer, subject, etc) */ -#define LOG_TLS_FIELD_CLIENT_CERT (1 << 14) -#define LOG_TLS_FIELD_CLIENT_CHAIN (1 << 15) - -typedef struct { - const char *name; - uint64_t flag; -} TlsFields; - -TlsFields tls_fields[] = { { "version", LOG_TLS_FIELD_VERSION }, - { "subject", LOG_TLS_FIELD_SUBJECT }, { "issuer", LOG_TLS_FIELD_ISSUER }, - { "serial", LOG_TLS_FIELD_SERIAL }, { "fingerprint", LOG_TLS_FIELD_FINGERPRINT }, - { "not_before", LOG_TLS_FIELD_NOTBEFORE }, { "not_after", LOG_TLS_FIELD_NOTAFTER }, - { "sni", LOG_TLS_FIELD_SNI }, { "certificate", LOG_TLS_FIELD_CERTIFICATE }, - { "chain", LOG_TLS_FIELD_CHAIN }, { "session_resumed", LOG_TLS_FIELD_SESSION_RESUMED }, - { "ja3", LOG_TLS_FIELD_JA3 }, { "ja3s", LOG_TLS_FIELD_JA3S }, - { "client", LOG_TLS_FIELD_CLIENT }, { "client_certificate", LOG_TLS_FIELD_CLIENT_CERT }, - { "client_chain", LOG_TLS_FIELD_CLIENT_CHAIN }, { NULL, -1 } }; - -typedef struct OutputTlsCtx_ { - uint32_t flags; /** Store mode */ - uint64_t fields; /** Store fields */ - OutputJsonCtx *eve_ctx; -} OutputTlsCtx; - - -typedef struct JsonTlsLogThread_ { - OutputTlsCtx *tlslog_ctx; - OutputJsonThreadCtx *ctx; -} JsonTlsLogThread; - -static void JsonTlsLogSubject(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->server_connp.cert0_subject) { - jb_set_string(js, "subject", - ssl_state->server_connp.cert0_subject); - } -} - -static void JsonTlsLogIssuer(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->server_connp.cert0_issuerdn) { - jb_set_string(js, "issuerdn", - ssl_state->server_connp.cert0_issuerdn); - } -} - -static void JsonTlsLogSessionResumed(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) { - /* Only log a session as 'resumed' if a certificate has not - been seen, and the session is not TLSv1.3 or later. */ - if ((ssl_state->server_connp.cert0_issuerdn == NULL && - ssl_state->server_connp.cert0_subject == NULL) && - (ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { - jb_set_bool(js, "session_resumed", true); - } - } -} - -static void JsonTlsLogFingerprint(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->server_connp.cert0_fingerprint) { - jb_set_string(js, "fingerprint", - ssl_state->server_connp.cert0_fingerprint); - } -} - -static void JsonTlsLogSni(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->client_connp.sni) { - jb_set_string(js, "sni", - ssl_state->client_connp.sni); - } -} - -static void JsonTlsLogSerial(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->server_connp.cert0_serial) { - jb_set_string(js, "serial", - ssl_state->server_connp.cert0_serial); - } -} - -static void JsonTlsLogVersion(JsonBuilder *js, SSLState *ssl_state) -{ - char ssl_version[SSL_VERSION_MAX_STRLEN]; - SSLVersionToString(ssl_state->server_connp.version, ssl_version); - jb_set_string(js, "version", ssl_version); -} - -static void JsonTlsLogNotBefore(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->server_connp.cert0_not_before != 0) { - sc_x509_log_timestamp(js, "notbefore", ssl_state->server_connp.cert0_not_before); - } -} - -static void JsonTlsLogNotAfter(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->server_connp.cert0_not_after != 0) { - sc_x509_log_timestamp(js, "notafter", ssl_state->server_connp.cert0_not_after); - } -} - -static void JsonTlsLogJa3Hash(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->client_connp.ja3_hash != NULL) { - jb_set_string(js, "hash", - ssl_state->client_connp.ja3_hash); - } -} - -static void JsonTlsLogJa3String(JsonBuilder *js, SSLState *ssl_state) -{ - if ((ssl_state->client_connp.ja3_str != NULL) && - ssl_state->client_connp.ja3_str->data != NULL) { - jb_set_string(js, "string", - ssl_state->client_connp.ja3_str->data); - } -} - -static void JsonTlsLogJa3(JsonBuilder *js, SSLState *ssl_state) -{ - if ((ssl_state->client_connp.ja3_hash != NULL) || - ((ssl_state->client_connp.ja3_str != NULL) && - ssl_state->client_connp.ja3_str->data != NULL)) { - jb_open_object(js, "ja3"); - - JsonTlsLogJa3Hash(js, ssl_state); - JsonTlsLogJa3String(js, ssl_state); - - jb_close(js); - } -} - -static void JsonTlsLogJa3SHash(JsonBuilder *js, SSLState *ssl_state) -{ - if (ssl_state->server_connp.ja3_hash != NULL) { - jb_set_string(js, "hash", - ssl_state->server_connp.ja3_hash); - } -} - -static void JsonTlsLogJa3SString(JsonBuilder *js, SSLState *ssl_state) -{ - if ((ssl_state->server_connp.ja3_str != NULL) && - ssl_state->server_connp.ja3_str->data != NULL) { - jb_set_string(js, "string", - ssl_state->server_connp.ja3_str->data); - } -} - -static void JsonTlsLogJa3S(JsonBuilder *js, SSLState *ssl_state) -{ - if ((ssl_state->server_connp.ja3_hash != NULL) || - ((ssl_state->server_connp.ja3_str != NULL) && - ssl_state->server_connp.ja3_str->data != NULL)) { - jb_open_object(js, "ja3s"); - - JsonTlsLogJa3SHash(js, ssl_state); - JsonTlsLogJa3SString(js, ssl_state); - - jb_close(js); - } -} - -static void JsonTlsLogCertificate(JsonBuilder *js, SSLStateConnp *connp) -{ - if (TAILQ_EMPTY(&connp->certs)) { - return; - } - - SSLCertsChain *cert = TAILQ_FIRST(&connp->certs); - if (cert == NULL) { - return; - } - - jb_set_base64(js, "certificate", cert->cert_data, cert->cert_len); -} - -static void JsonTlsLogChain(JsonBuilder *js, SSLStateConnp *connp) -{ - if (TAILQ_EMPTY(&connp->certs)) { - return; - } - - jb_open_array(js, "chain"); - - SSLCertsChain *cert; - TAILQ_FOREACH (cert, &connp->certs, next) { - jb_append_base64(js, cert->cert_data, cert->cert_len); - } - - jb_close(js); -} - -static bool HasClientCert(SSLStateConnp *connp) -{ - if (connp->cert0_subject || connp->cert0_issuerdn) - return true; - return false; -} - -static void JsonTlsLogClientCert( - JsonBuilder *js, SSLStateConnp *connp, const bool log_cert, const bool log_chain) -{ - if (connp->cert0_subject != NULL) { - jb_set_string(js, "subject", connp->cert0_subject); - } - if (connp->cert0_issuerdn != NULL) { - jb_set_string(js, "issuerdn", connp->cert0_issuerdn); - } - if (connp->cert0_fingerprint) { - jb_set_string(js, "fingerprint", connp->cert0_fingerprint); - } - if (connp->cert0_serial) { - jb_set_string(js, "serial", connp->cert0_serial); - } - if (connp->cert0_not_before != 0) { - char timebuf[64]; - SCTime_t ts = SCTIME_FROM_SECS(connp->cert0_not_before); - CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf)); - jb_set_string(js, "notbefore", timebuf); - } - if (connp->cert0_not_after != 0) { - char timebuf[64]; - SCTime_t ts = SCTIME_FROM_SECS(connp->cert0_not_after); - CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf)); - jb_set_string(js, "notafter", timebuf); - } - - if (log_cert) { - JsonTlsLogCertificate(js, connp); - } - if (log_chain) { - JsonTlsLogChain(js, connp); - } -} - -void JsonTlsLogJSONBasic(JsonBuilder *js, SSLState *ssl_state) -{ - /* tls subject */ - JsonTlsLogSubject(js, ssl_state); - - /* tls issuerdn */ - JsonTlsLogIssuer(js, ssl_state); - - /* tls session resumption */ - JsonTlsLogSessionResumed(js, ssl_state); -} - -static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, JsonBuilder *js, - SSLState *ssl_state) -{ - /* tls subject */ - if (tls_ctx->fields & LOG_TLS_FIELD_SUBJECT) - JsonTlsLogSubject(js, ssl_state); - - /* tls issuerdn */ - if (tls_ctx->fields & LOG_TLS_FIELD_ISSUER) - JsonTlsLogIssuer(js, ssl_state); - - /* tls session resumption */ - if (tls_ctx->fields & LOG_TLS_FIELD_SESSION_RESUMED) - JsonTlsLogSessionResumed(js, ssl_state); - - /* tls serial */ - if (tls_ctx->fields & LOG_TLS_FIELD_SERIAL) - JsonTlsLogSerial(js, ssl_state); - - /* tls fingerprint */ - if (tls_ctx->fields & LOG_TLS_FIELD_FINGERPRINT) - JsonTlsLogFingerprint(js, ssl_state); - - /* tls sni */ - if (tls_ctx->fields & LOG_TLS_FIELD_SNI) - JsonTlsLogSni(js, ssl_state); - - /* tls version */ - if (tls_ctx->fields & LOG_TLS_FIELD_VERSION) - JsonTlsLogVersion(js, ssl_state); - - /* tls notbefore */ - if (tls_ctx->fields & LOG_TLS_FIELD_NOTBEFORE) - JsonTlsLogNotBefore(js, ssl_state); - - /* tls notafter */ - if (tls_ctx->fields & LOG_TLS_FIELD_NOTAFTER) - JsonTlsLogNotAfter(js, ssl_state); - - /* tls certificate */ - if (tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) - JsonTlsLogCertificate(js, &ssl_state->server_connp); - - /* tls chain */ - if (tls_ctx->fields & LOG_TLS_FIELD_CHAIN) - JsonTlsLogChain(js, &ssl_state->server_connp); - - /* tls ja3_hash */ - if (tls_ctx->fields & LOG_TLS_FIELD_JA3) - JsonTlsLogJa3(js, ssl_state); - - /* tls ja3s */ - if (tls_ctx->fields & LOG_TLS_FIELD_JA3S) - JsonTlsLogJa3S(js, ssl_state); - - if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT) { - const bool log_cert = (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) != 0; - const bool log_chain = (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN) != 0; - if (HasClientCert(&ssl_state->client_connp)) { - jb_open_object(js, "client"); - JsonTlsLogClientCert(js, &ssl_state->client_connp, log_cert, log_chain); - jb_close(js); - } - } -} - -static bool JsonTlsLogJSONExtendedAux(void *vtx, JsonBuilder *tjs) -{ - SSLState *state = (SSLState *)vtx; - JsonTlsLogJSONBasic(tjs, state); - - /* tls serial */ - JsonTlsLogSerial(tjs, state); - - /* tls fingerprint */ - JsonTlsLogFingerprint(tjs, state); - - /* tls sni */ - JsonTlsLogSni(tjs, state); - - /* tls version */ - JsonTlsLogVersion(tjs, state); - - /* tls notbefore */ - JsonTlsLogNotBefore(tjs, state); - - /* tls notafter */ - JsonTlsLogNotAfter(tjs, state); - - /* tls ja3 */ - JsonTlsLogJa3(tjs, state); - - /* tls ja3s */ - JsonTlsLogJa3S(tjs, state); - - if (HasClientCert(&state->client_connp)) { - jb_open_object(tjs, "client"); - JsonTlsLogClientCert(tjs, &state->client_connp, false, false); - jb_close(tjs); - } - return true; -} - -bool JsonTlsLogJSONExtended(void *vtx, JsonBuilder *tjs) -{ - jb_open_object(tjs, "tls"); - bool r = JsonTlsLogJSONExtendedAux(vtx, tjs); - jb_close(tjs); - return r; -} - -static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, - Flow *f, void *state, void *txptr, uint64_t tx_id) -{ - JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data; - OutputTlsCtx *tls_ctx = aft->tlslog_ctx; - - SSLState *ssl_state = (SSLState *)state; - if (unlikely(ssl_state == NULL)) { - return 0; - } - - if ((ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) && - ((ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) == 0 || - (tls_ctx->flags & LOG_TLS_SESSION_RESUMPTION) == 0) && - ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) { - return 0; - } - - JsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "tls", NULL, aft->tlslog_ctx->eve_ctx); - if (unlikely(js == NULL)) { - return 0; - } - - jb_open_object(js, "tls"); - - /* log custom fields */ - if (tls_ctx->flags & LOG_TLS_CUSTOM) { - JsonTlsLogJSONCustom(tls_ctx, js, ssl_state); - } - /* log extended */ - else if (tls_ctx->flags & LOG_TLS_EXTENDED) { - JsonTlsLogJSONExtendedAux(ssl_state, js); - } - /* log basic */ - else { - JsonTlsLogJSONBasic(js, ssl_state); - } - - /* print original application level protocol when it have been changed - because of STARTTLS, HTTP CONNECT, or similar. */ - if (f->alproto_orig != ALPROTO_UNKNOWN) { - jb_set_string(js, "from_proto", - AppLayerGetProtoName(f->alproto_orig)); - } - - /* Close the tls object. */ - jb_close(js); - - OutputJsonBuilderBuffer(js, aft->ctx); - jb_free(js); - - return 0; -} - -static TmEcode JsonTlsLogThreadInit(ThreadVars *t, const void *initdata, void **data) -{ - JsonTlsLogThread *aft = SCCalloc(1, sizeof(JsonTlsLogThread)); - if (unlikely(aft == NULL)) { - return TM_ECODE_FAILED; - } - - if (initdata == NULL) { - SCLogDebug("Error getting context for eve-log tls 'initdata' argument NULL"); - goto error_exit; - } - - /* use the Output Context (file pointer and mutex) */ - aft->tlslog_ctx = ((OutputCtx *)initdata)->data; - - aft->ctx = CreateEveThreadCtx(t, aft->tlslog_ctx->eve_ctx); - if (!aft->ctx) { - goto error_exit; - } - *data = (void *)aft; - return TM_ECODE_OK; - -error_exit: - SCFree(aft); - return TM_ECODE_FAILED; -} - -static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data) -{ - JsonTlsLogThread *aft = (JsonTlsLogThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; - } - - FreeEveThreadCtx(aft->ctx); - - /* clear memory */ - memset(aft, 0, sizeof(JsonTlsLogThread)); - - SCFree(aft); - return TM_ECODE_OK; -} - -static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf) -{ - OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); - if (unlikely(tls_ctx == NULL)) - return NULL; - - tls_ctx->flags = LOG_TLS_DEFAULT; - tls_ctx->fields = 0; - - if (conf == NULL) - return tls_ctx; - - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - if (extended) { - if (ConfValIsTrue(extended)) { - tls_ctx->flags = LOG_TLS_EXTENDED; - } - } - - ConfNode *custom = ConfNodeLookupChild(conf, "custom"); - if (custom) { - tls_ctx->flags = LOG_TLS_CUSTOM; - ConfNode *field; - TAILQ_FOREACH(field, &custom->head, next) - { - bool valid = false; - TlsFields *valid_fields = tls_fields; - for ( ; valid_fields->name != NULL; valid_fields++) { - if (strcasecmp(field->val, valid_fields->name) == 0) { - tls_ctx->fields |= valid_fields->flag; - SCLogDebug("enabled %s", field->val); - valid = true; - break; - } - } - if (!valid) { - SCLogWarning("eve.tls: unknown 'custom' field '%s'", field->val); - } - } - } - - const char *session_resumption = ConfNodeLookupChildValue(conf, "session-resumption"); - if (session_resumption == NULL || ConfValIsTrue(session_resumption)) { - tls_ctx->flags |= LOG_TLS_SESSION_RESUMPTION; - } - - if ((tls_ctx->fields & LOG_TLS_FIELD_JA3) && - Ja3IsDisabled("fields")) { - /* JA3 is disabled, so don't log any JA3 fields */ - tls_ctx->fields &= ~LOG_TLS_FIELD_JA3; - tls_ctx->fields &= ~LOG_TLS_FIELD_JA3S; - } - - if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && - (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { - SCLogWarning("Both 'certificate' and 'chain' contains the top " - "certificate, so only one of them should be enabled " - "at a time"); - } - if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) && - (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN)) { - SCLogWarning("Both 'client_certificate' and 'client_chain' contains the top " - "certificate, so only one of them should be enabled " - "at a time"); - } - - if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT) == 0) { - if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) { - SCLogConfig("enabling \"client\" as a dependency of \"client_certificate\""); - tls_ctx->fields |= LOG_TLS_FIELD_CLIENT; - } - if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN) { - SCLogConfig("enabling \"client\" as a dependency of \"client_chain\""); - tls_ctx->fields |= LOG_TLS_FIELD_CLIENT; - } - } - - return tls_ctx; -} - -static void OutputTlsLogDeinitSub(OutputCtx *output_ctx) -{ - OutputTlsCtx *tls_ctx = output_ctx->data; - SCFree(tls_ctx); - SCFree(output_ctx); -} - -static OutputInitResult OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) -{ - OutputInitResult result = { NULL, false }; - OutputJsonCtx *ojc = parent_ctx->data; - - OutputTlsCtx *tls_ctx = OutputTlsInitCtx(conf); - if (unlikely(tls_ctx == NULL)) - return result; - - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) { - SCFree(tls_ctx); - return result; - } - - tls_ctx->eve_ctx = ojc; - - if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && - (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { - SCLogWarning("Both 'certificate' and 'chain' contains the top " - "certificate, so only one of them should be enabled " - "at a time"); - } - - output_ctx->data = tls_ctx; - output_ctx->DeInit = OutputTlsLogDeinitSub; - - AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); - - result.ctx = output_ctx; - result.ok = true; - return result; -} - -void JsonTlsLogRegister (void) -{ - /* register as child of eve-log */ - OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_TX, "eve-log", "JsonTlsLog", "eve-log.tls", - OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, - JsonTlsLogThreadInit, JsonTlsLogThreadDeinit, NULL); -} diff --git a/src/output-json-tls.h b/src/output-json-tls.h deleted file mode 100644 index 42f706b91d3f..000000000000 --- a/src/output-json-tls.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Tom DeCanio - */ - -#ifndef __OUTPUT_JSON_TLS_H__ -#define __OUTPUT_JSON_TLS_H__ - -void JsonTlsLogRegister(void); - -#include "app-layer-ssl.h" - -void JsonTlsLogJSONBasic(JsonBuilder *js, SSLState *ssl_state); -bool JsonTlsLogJSONExtended(void *vtx, JsonBuilder *js); - -#endif /* __OUTPUT_JSON_TLS_H__ */ diff --git a/src/output-streaming.h b/src/output-streaming.h deleted file mode 100644 index 07c3722d8e3d..000000000000 --- a/src/output-streaming.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Streaming Logger Output registration functions - */ - -#ifndef __OUTPUT_STREAMING_H__ -#define __OUTPUT_STREAMING_H__ - - -#define OUTPUT_STREAMING_FLAG_OPEN 0x01 -#define OUTPUT_STREAMING_FLAG_CLOSE 0x02 -#define OUTPUT_STREAMING_FLAG_TOSERVER 0x04 -#define OUTPUT_STREAMING_FLAG_TOCLIENT 0x08 -#define OUTPUT_STREAMING_FLAG_TRANSACTION 0x10 - -enum OutputStreamingType { - STREAMING_TCP_DATA, - STREAMING_HTTP_BODIES, -}; - -/** streaming logger function pointer type */ -typedef int (*StreamingLogger)(ThreadVars *, void *thread_data, - const Flow *f, const uint8_t *data, uint32_t data_len, - uint64_t tx_id, uint8_t flags); - -int OutputRegisterStreamingLogger(LoggerId id, const char *name, - StreamingLogger LogFunc, OutputCtx *, enum OutputStreamingType, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputStreamingLoggerRegister (void); - -void OutputStreamingShutdown(void); - -#endif /* __OUTPUT_STREAMING_H__ */ diff --git a/src/output.h b/src/output.h deleted file mode 100644 index 815b2f20ed73..000000000000 --- a/src/output.h +++ /dev/null @@ -1,220 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Endace Technology Limited, Jason Ish - */ - -#ifndef __OUTPUT_H__ -#define __OUTPUT_H__ - -#include "decode.h" -#include "tm-modules.h" - -#define DEFAULT_LOG_MODE_APPEND "yes" -#define DEFAULT_LOG_FILETYPE "regular" - -typedef struct OutputLoggerThreadStore_ { - void *thread_data; - struct OutputLoggerThreadStore_ *next; -} OutputLoggerThreadStore; - -#include "output-packet.h" -#include "output-tx.h" -#include "output-file.h" -#include "output-filedata.h" -#include "output-flow.h" -#include "output-streaming.h" -#include "output-stats.h" - -typedef struct OutputInitResult_ { - OutputCtx *ctx; - bool ok; -} OutputInitResult; - -typedef OutputInitResult (*OutputInitFunc)(ConfNode *); -typedef OutputInitResult (*OutputInitSubFunc)(ConfNode *, OutputCtx *); -typedef TmEcode (*OutputLogFunc)(ThreadVars *, Packet *, void *); -typedef uint32_t (*OutputGetActiveCountFunc)(void); - -typedef struct OutputModule_ { - LoggerId logger_id; - const char *name; - const char *conf_name; - const char *parent_name; - OutputInitFunc InitFunc; - OutputInitSubFunc InitSubFunc; - - ThreadInitFunc ThreadInit; - ThreadDeinitFunc ThreadDeinit; - ThreadExitPrintStatsFunc ThreadExitPrintStats; - - PacketLogger PacketLogFunc; - PacketLogCondition PacketConditionFunc; - TxLogger TxLogFunc; - TxLoggerCondition TxLogCondition; - FileLogger FileLogFunc; - FiledataLogger FiledataLogFunc; - FlowLogger FlowLogFunc; - StreamingLogger StreamingLogFunc; - StatsLogger StatsLogFunc; - AppProto alproto; - enum OutputStreamingType stream_type; - int tc_log_progress; - int ts_log_progress; - - TAILQ_ENTRY(OutputModule_) entries; -} OutputModule; - -typedef TAILQ_HEAD(OutputModuleList_, OutputModule_) OutputModuleList; -extern OutputModuleList output_modules; - -void OutputRegisterModule(const char *, const char *, OutputInitFunc); - -void OutputRegisterPacketModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, PacketLogger LogFunc, - PacketLogCondition ConditionFunc, ThreadInitFunc, ThreadDeinitFunc, - ThreadExitPrintStatsFunc); -void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - PacketLogger LogFunc, PacketLogCondition ConditionFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterTxModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxSubModuleWithCondition(LoggerId id, - const char *parent_name, const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, - int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterFileModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, - FileLogger FileLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, FileLogger FileLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterFiledataModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, - FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterFiledataSubModule(LoggerId, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterStreamingModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, - StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, StreamingLogger StreamingLogFunc, - enum OutputStreamingType stream_type, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -void OutputRegisterStatsModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, - StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); -void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, - StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); - -OutputModule *OutputGetModuleByConfName(const char *name); -void OutputDeregisterAll(void); - -int OutputDropLoggerEnable(void); -void OutputDropLoggerDisable(void); - -void OutputRegisterFileRotationFlag(int *flag); -void OutputUnregisterFileRotationFlag(int *flag); -void OutputNotifyFileRotation(void); - -void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats, - OutputLogFunc LogFunc, OutputGetActiveCountFunc ActiveCntFunc); -void TmModuleLoggerRegister(void); - -TmEcode OutputLoggerLog(ThreadVars *, Packet *, void *); -TmEcode OutputLoggerThreadInit(ThreadVars *, const void *, void **); -TmEcode OutputLoggerThreadDeinit(ThreadVars *, void *); -void OutputLoggerExitPrintStats(ThreadVars *, void *); - -void OutputSetupActiveLoggers(void); -void OutputClearActiveLoggers(void); - -typedef bool (*EveJsonSimpleTxLogFunc)(void *, struct JsonBuilder *); - -typedef struct EveJsonSimpleAppLayerLogger { - AppProto proto; - EveJsonSimpleTxLogFunc LogTx; -} EveJsonSimpleAppLayerLogger; - -EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto); - -#endif /* ! __OUTPUT_H__ */ diff --git a/src/output-eve-null.c b/src/output/eve/output-eve-null.c similarity index 96% rename from src/output-eve-null.c rename to src/output/eve/output-eve-null.c index 1b62b96b36cb..0de3ab21d906 100644 --- a/src/output-eve-null.c +++ b/src/output/eve/output-eve-null.c @@ -25,8 +25,8 @@ #include "suricata-common.h" /* errno.h, string.h, etc. */ -#include "output.h" /* DEFAULT_LOG_* */ -#include "output-eve-null.h" +#include "output/output.h" /* DEFAULT_LOG_* */ +#include "output/eve/output-eve-null.h" #ifdef OS_WIN32 void NullLogInitialize(void) diff --git a/src/output-eve-null.h b/src/output/eve/output-eve-null.h similarity index 100% rename from src/output-eve-null.h rename to src/output/eve/output-eve-null.h diff --git a/src/output-eve-stream.c b/src/output/eve/output-eve-stream.c similarity index 97% rename from src/output-eve-stream.c rename to src/output/eve/output-eve-stream.c index 919505dce70d..4b234c2a39fd 100644 --- a/src/output-eve-stream.c +++ b/src/output/eve/output-eve-stream.c @@ -28,7 +28,7 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" #include "decode-ipv4.h" #include "detect-parse.h" @@ -36,22 +36,22 @@ #include "detect-engine-mpm.h" #include "detect-reference.h" -#include "output.h" -#include "output-json.h" -#include "output-json-flow.h" -#include "output-eve-stream.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-flow.h" +#include "output/eve/output-eve-stream.h" #include "stream-tcp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-classification-config.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "util-buffer.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/classification-config.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "util/buffer.h" #include "action-globals.h" diff --git a/src/output-eve-stream.h b/src/output/eve/output-eve-stream.h similarity index 100% rename from src/output-eve-stream.h rename to src/output/eve/output-eve-stream.h diff --git a/src/output-eve-syslog.c b/src/output/eve/output-eve-syslog.c similarity index 96% rename from src/output-eve-syslog.c rename to src/output/eve/output-eve-syslog.c index 5d71b5d807d1..9ad3ac0f698b 100644 --- a/src/output-eve-syslog.c +++ b/src/output/eve/output-eve-syslog.c @@ -25,9 +25,9 @@ */ #include "suricata-common.h" /* errno.h, string.h, etc. */ -#include "output.h" /* DEFAULT_LOG_* */ -#include "output-eve-syslog.h" -#include "util-syslog.h" +#include "output/output.h" /* DEFAULT_LOG_* */ +#include "output/eve/output-eve-syslog.h" +#include "util/syslog.h" #ifdef OS_WIN32 void SyslogInitialize(void) diff --git a/src/output-eve-syslog.h b/src/output/eve/output-eve-syslog.h similarity index 100% rename from src/output-eve-syslog.h rename to src/output/eve/output-eve-syslog.h diff --git a/src/output-json-alert.c b/src/output/eve/output-json-alert.c similarity index 88% rename from src/output-json-alert.c rename to src/output/eve/output-json-alert.c index c7acfe64d140..80908884d548 100644 --- a/src/output-json-alert.c +++ b/src/output/eve/output-json-alert.c @@ -34,13 +34,13 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" -#include "util-logopenfile.h" -#include "util-misc.h" -#include "util-time.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/logopenfile.h" +#include "util/misc.h" +#include "util/time.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" @@ -48,71 +48,69 @@ #include "detect-reference.h" #include "detect-metadata.h" #include "app-layer-parser.h" -#include "app-layer-dnp3.h" -#include "app-layer-htp.h" -#include "app-layer-htp-xff.h" -#include "app-layer-ftp.h" +#include "app-layer/dnp3/parser.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-xff.h" +#include "app-layer/ftp/parser.h" #include "app-layer-frames.h" -#include "util-classification-config.h" -#include "util-syslog.h" +#include "util/classification-config.h" +#include "util/syslog.h" #include "log-pcap.h" -#include "output.h" -#include "output-json.h" -#include "output-json-alert.h" -#include "output-json-dnp3.h" -#include "output-json-dns.h" -#include "output-json-http.h" -#include "output-json-tls.h" -#include "output-json-ssh.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-alert.h" +#include "app-layer/dnp3/logger.h" +#include "app-layer/dns/logger.h" +#include "app-layer/http/logger.h" +#include "app-layer/tls/logger.h" +#include "app-layer/ssh/logger.h" #include "rust.h" -#include "output-json-smtp.h" -#include "output-json-email-common.h" -#include "output-json-nfs.h" -#include "output-json-smb.h" -#include "output-json-flow.h" -#include "output-json-sip.h" -#include "output-json-rfb.h" -#include "output-json-mqtt.h" -#include "output-json-ike.h" -#include "output-json-modbus.h" -#include "output-json-frame.h" -#include "output-json-quic.h" - -#include "util-byte.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-optimize.h" -#include "util-buffer.h" -#include "util-validate.h" +#include "app-layer/smtp/logger.h" +#include "output/eve/output-json-email-common.h" +#include "app-layer/nfs/logger.h" +#include "app-layer/smb/logger.h" +#include "output/eve/output-json-flow.h" +#include "app-layer/sip/logger.h" +#include "app-layer/rfb/logger.h" +#include "app-layer/mqtt/logger.h" +#include "app-layer/ike/logger.h" +#include "app-layer/modbus/logger.h" +#include "output/eve/output-json-frame.h" +#include "app-layer/quic/logger.h" + +#include "util/byte.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/optimize.h" +#include "util/buffer.h" +#include "util/validate.h" #include "action-globals.h" #define MODULE_NAME "JsonAlertLog" -#define LOG_JSON_PAYLOAD BIT_U16(0) -#define LOG_JSON_PACKET BIT_U16(1) -#define LOG_JSON_PAYLOAD_BASE64 BIT_U16(2) -#define LOG_JSON_TAGGED_PACKETS BIT_U16(3) -#define LOG_JSON_APP_LAYER BIT_U16(4) -#define LOG_JSON_FLOW BIT_U16(5) -#define LOG_JSON_HTTP_BODY BIT_U16(6) -#define LOG_JSON_HTTP_BODY_BASE64 BIT_U16(7) -#define LOG_JSON_RULE_METADATA BIT_U16(8) -#define LOG_JSON_RULE BIT_U16(9) -#define LOG_JSON_VERDICT BIT_U16(10) +#define LOG_JSON_PAYLOAD BIT_U16(0) +#define LOG_JSON_PACKET BIT_U16(1) +#define LOG_JSON_PAYLOAD_BASE64 BIT_U16(2) +#define LOG_JSON_TAGGED_PACKETS BIT_U16(3) +#define LOG_JSON_APP_LAYER BIT_U16(4) +#define LOG_JSON_FLOW BIT_U16(5) +#define LOG_JSON_HTTP_BODY BIT_U16(6) +#define LOG_JSON_HTTP_BODY_BASE64 BIT_U16(7) +#define LOG_JSON_RULE_METADATA BIT_U16(8) +#define LOG_JSON_RULE BIT_U16(9) +#define LOG_JSON_VERDICT BIT_U16(10) -#define METADATA_DEFAULTS ( LOG_JSON_FLOW | \ - LOG_JSON_APP_LAYER | \ - LOG_JSON_RULE_METADATA) +#define METADATA_DEFAULTS (LOG_JSON_FLOW | LOG_JSON_APP_LAYER | LOG_JSON_RULE_METADATA) -#define JSON_BODY_LOGGING (LOG_JSON_HTTP_BODY | LOG_JSON_HTTP_BODY_BASE64) +#define JSON_BODY_LOGGING (LOG_JSON_HTTP_BODY | LOG_JSON_HTTP_BODY_BASE64) #define JSON_STREAM_BUFFER_SIZE 4096 typedef struct AlertJsonOutputCtx_ { - LogFileCtx* file_ctx; + LogFileCtx *file_ctx; uint16_t flags; uint32_t payload_buffer_size; HttpXFFCfg *xff_cfg; @@ -122,7 +120,7 @@ typedef struct AlertJsonOutputCtx_ { typedef struct JsonAlertLogThread_ { MemBuffer *payload_buffer; - AlertJsonOutputCtx* json_output_ctx; + AlertJsonOutputCtx *json_output_ctx; OutputJsonThreadCtx *ctx; } JsonAlertLogThread; @@ -137,8 +135,8 @@ static int AlertJsonDumpStreamSegmentCallback( return 1; } -static void AlertJsonSourceTarget(const Packet *p, const PacketAlert *pa, - JsonBuilder *js, JsonAddrInfo *addr) +static void AlertJsonSourceTarget( + const Packet *p, const PacketAlert *pa, JsonBuilder *js, JsonAddrInfo *addr) { jb_open_object(js, "source"); if (pa->s->flags & SIG_FLAG_DEST_IS_TARGET) { @@ -197,8 +195,8 @@ static void AlertJsonSourceTarget(const Packet *p, const PacketAlert *pa, jb_close(js); } -static void AlertJsonMetadata(AlertJsonOutputCtx *json_output_ctx, - const PacketAlert *pa, JsonBuilder *js) +static void AlertJsonMetadata( + AlertJsonOutputCtx *json_output_ctx, const PacketAlert *pa, JsonBuilder *js) { if (pa->s->metadata && pa->s->metadata->json_str) { jb_set_formatted(js, pa->s->metadata->json_str); @@ -237,8 +235,8 @@ void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, JsonBuil jb_set_uint(js, "rev", pa->s->rev); /* TODO: JsonBuilder should handle unprintable characters like * SCJsonString. */ - jb_set_string(js, "signature", pa->s->msg ? pa->s->msg: ""); - jb_set_string(js, "category", pa->s->class_msg ? pa->s->class_msg: ""); + jb_set_string(js, "signature", pa->s->msg ? pa->s->msg : ""); + jb_set_string(js, "category", pa->s->class_msg ? pa->s->class_msg : ""); jb_set_uint(js, "severity", pa->s->prio); if (p->tenant_id > 0) { @@ -301,16 +299,15 @@ static void AlertAddPayload(AlertJsonOutputCtx *json_output_ctx, JsonBuilder *js if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { uint8_t printable_buf[p->payload_len + 1]; uint32_t offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - p->payload_len + 1, - p->payload, p->payload_len); + PrintStringsToBuffer( + printable_buf, &offset, p->payload_len + 1, p->payload, p->payload_len); printable_buf[p->payload_len] = '\0'; jb_set_string(js, "payload_printable", (char *)printable_buf); } } -static void AlertAddAppLayer(const Packet *p, JsonBuilder *jb, - const uint64_t tx_id, const uint16_t option_flags) +static void AlertAddAppLayer( + const Packet *p, JsonBuilder *jb, const uint64_t tx_id, const uint16_t option_flags) { const AppProto proto = FlowGetAppProtocol(p->flow); EveJsonSimpleAppLayerLogger *al = SCEveJsonSimpleGetLogger(proto); @@ -543,11 +540,10 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if ((xff_cfg != NULL) && !(xff_cfg->flags & XFF_DISABLED) && p->flow != NULL) { if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP1) { if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = HttpXFFGetIPFromTx(p->flow, pa->tx_id, xff_cfg, - xff_buffer, XFF_MAXLEN); + have_xff_ip = + HttpXFFGetIPFromTx(p->flow, pa->tx_id, xff_cfg, xff_buffer, XFF_MAXLEN); } else { - have_xff_ip = HttpXFFGetIP(p->flow, xff_cfg, xff_buffer, - XFF_MAXLEN); + have_xff_ip = HttpXFFGetIP(p->flow, xff_cfg, xff_buffer, XFF_MAXLEN); } } @@ -572,7 +568,6 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (unlikely(jb == NULL)) return TM_ECODE_OK; - /* alert */ AlertJsonHeader(json_output_ctx, p, pa, jb, json_output_ctx->flags, &addr, xff_buffer); @@ -621,9 +616,12 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) /* payload */ if (json_output_ctx->flags & (LOG_JSON_PAYLOAD | LOG_JSON_PAYLOAD_BASE64)) { - int stream = (p->proto == IPPROTO_TCP) ? - (pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_STREAM_MATCH) ? - 1 : 0) : 0; + int stream = (p->proto == IPPROTO_TCP) + ? (pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH | + PACKET_ALERT_FLAG_STREAM_MATCH) + ? 1 + : 0) + : 0; /* Is this a stream? If so, pack part of it into the payload field */ if (stream) { @@ -637,9 +635,8 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) flag = STREAM_DUMP_TOSERVER; } - StreamSegmentForEach((const Packet *)p, flag, - AlertJsonDumpStreamSegmentCallback, - (void *)payload); + StreamSegmentForEach((const Packet *)p, flag, AlertJsonDumpStreamSegmentCallback, + (void *)payload); if (payload->offset) { if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { jb_set_base64(jb, "payload", payload->buffer, payload->offset); @@ -648,8 +645,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { uint8_t printable_buf[payload->offset + 1]; uint32_t offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), + PrintStringsToBuffer(printable_buf, &offset, sizeof(printable_buf), payload->buffer, payload->offset); jb_set_string(jb, "payload_printable", (char *)printable_buf); } @@ -687,8 +683,7 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) jb_free(jb); } - if ((p->flags & PKT_HAS_TAG) && (json_output_ctx->flags & - LOG_JSON_TAGGED_PACKETS)) { + if ((p->flags & PKT_HAS_TAG) && (json_output_ctx->flags & LOG_JSON_TAGGED_PACKETS)) { JsonBuilder *packetjs = CreateEveHeader(p, LOG_DIR_PACKET, "packet", NULL, json_output_ctx->eve_ctx); if (unlikely(packetjs != NULL)) { @@ -757,8 +752,7 @@ static TmEcode JsonAlertLogThreadInit(ThreadVars *t, const void *initdata, void if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if (initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context for EveLogAlert. \"initdata\" argument NULL"); goto error_exit; } @@ -809,7 +803,7 @@ static void JsonAlertLogDeInitCtxSub(OutputCtx *output_ctx) { SCLogDebug("cleaning up sub output_ctx %p", output_ctx); - AlertJsonOutputCtx *json_output_ctx = (AlertJsonOutputCtx *) output_ctx->data; + AlertJsonOutputCtx *json_output_ctx = (AlertJsonOutputCtx *)output_ctx->data; if (json_output_ctx != NULL) { HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; @@ -836,8 +830,7 @@ static void SetFlag(const ConfNode *conf, const char *name, uint16_t flag, uint1 #define DEFAULT_LOG_FILENAME "alert.json" -static void JsonAlertLogSetupMetadata(AlertJsonOutputCtx *json_output_ctx, - ConfNode *conf) +static void JsonAlertLogSetupMetadata(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) { static bool warn_no_meta = false; uint32_t payload_buffer_size = JSON_STREAM_BUFFER_SIZE; @@ -853,8 +846,7 @@ static void JsonAlertLogSetupMetadata(AlertJsonOutputCtx *json_output_ctx, ConfNode *rule_metadata = ConfNodeLookupChild(metadata, "rule"); if (rule_metadata) { SetFlag(rule_metadata, "raw", LOG_JSON_RULE, &flags); - SetFlag(rule_metadata, "metadata", LOG_JSON_RULE_METADATA, - &flags); + SetFlag(rule_metadata, "metadata", LOG_JSON_RULE_METADATA, &flags); } SetFlag(metadata, "flow", LOG_JSON_FLOW, &flags); SetFlag(metadata, "app-layer", LOG_JSON_APP_LAYER, &flags); @@ -973,10 +965,9 @@ static OutputInitResult JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent return result; } -void JsonAlertLogRegister (void) +void JsonAlertLogRegister(void) { - OutputRegisterPacketSubModule(LOGGER_JSON_ALERT, "eve-log", MODULE_NAME, - "eve-log.alert", JsonAlertLogInitCtxSub, JsonAlertLogger, - JsonAlertLogCondition, JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, - NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_ALERT, "eve-log", MODULE_NAME, "eve-log.alert", + JsonAlertLogInitCtxSub, JsonAlertLogger, JsonAlertLogCondition, JsonAlertLogThreadInit, + JsonAlertLogThreadDeinit, NULL); } diff --git a/src/output-json-alert.h b/src/output/eve/output-json-alert.h similarity index 99% rename from src/output-json-alert.h rename to src/output/eve/output-json-alert.h index 6a65cc3d2730..8d7f31e25b4d 100644 --- a/src/output-json-alert.h +++ b/src/output/eve/output-json-alert.h @@ -33,4 +33,3 @@ void AlertJsonHeader(void *ctx, const Packet *p, const PacketAlert *pa, JsonBuil void EveAddVerdict(JsonBuilder *jb, const Packet *p); #endif /* __OUTPUT_JSON_ALERT_H__ */ - diff --git a/src/output-json-anomaly.c b/src/output/eve/output-json-anomaly.c similarity index 81% rename from src/output-json-anomaly.c rename to src/output/eve/output-json-anomaly.c index ffe931a73ed6..72fe0122b91b 100644 --- a/src/output-json-anomaly.c +++ b/src/output/eve/output-json-anomaly.c @@ -35,37 +35,37 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" -#include "util-misc.h" +#include "util/misc.h" #include "detect-parse.h" #include "detect-engine.h" -#include "util-logopenfile.h" +#include "util/logopenfile.h" -#include "output.h" -#include "output-json.h" -#include "output-json-anomaly.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-anomaly.h" -#include "util-byte.h" -#include "util-enum.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-optimize.h" -#include "util-buffer.h" -#include "util-validate.h" +#include "util/byte.h" +#include "util/enum.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/optimize.h" +#include "util/buffer.h" +#include "util/validate.h" #define MODULE_NAME "JsonAnomalyLog" -#define ANOMALY_EVENT_TYPE "anomaly" -#define LOG_JSON_DECODE_TYPE BIT_U16(0) -#define LOG_JSON_STREAM_TYPE BIT_U16(1) -#define LOG_JSON_APPLAYER_TYPE BIT_U16(2) -#define LOG_JSON_PACKETHDR BIT_U16(3) +#define ANOMALY_EVENT_TYPE "anomaly" +#define LOG_JSON_DECODE_TYPE BIT_U16(0) +#define LOG_JSON_STREAM_TYPE BIT_U16(1) +#define LOG_JSON_APPLAYER_TYPE BIT_U16(2) +#define LOG_JSON_PACKETHDR BIT_U16(3) -#define LOG_JSON_PACKET_TYPE (LOG_JSON_DECODE_TYPE | LOG_JSON_STREAM_TYPE) -#define ANOMALY_DEFAULTS LOG_JSON_APPLAYER_TYPE +#define LOG_JSON_PACKET_TYPE (LOG_JSON_DECODE_TYPE | LOG_JSON_STREAM_TYPE) +#define ANOMALY_DEFAULTS LOG_JSON_APPLAYER_TYPE #define TX_ID_UNUSED UINT64_MAX @@ -75,7 +75,7 @@ typedef struct AnomalyJsonOutputCtx_ { } AnomalyJsonOutputCtx; typedef struct JsonAnomalyLogThread_ { - AnomalyJsonOutputCtx* json_output_ctx; + AnomalyJsonOutputCtx *json_output_ctx; OutputJsonThreadCtx *ctx; } JsonAnomalyLogThread; @@ -100,8 +100,7 @@ static void OutputAnomalyLoggerDisable(void) anomaly_loggers--; } -static int AnomalyDecodeEventJson(ThreadVars *tv, JsonAnomalyLogThread *aft, - const Packet *p) +static int AnomalyDecodeEventJson(ThreadVars *tv, JsonAnomalyLogThread *aft, const Packet *p) { const uint16_t log_type = aft->json_output_ctx->flags; const bool log_stream = log_type & LOG_JSON_STREAM_TYPE; @@ -150,16 +149,14 @@ static int AnomalyDecodeEventJson(ThreadVars *tv, JsonAnomalyLogThread *aft, return TM_ECODE_OK; } -static int AnomalyAppLayerDecoderEventJson(JsonAnomalyLogThread *aft, - const Packet *p, AppLayerDecoderEvents *decoder_events, - bool is_pktlayer, const char *layer, uint64_t tx_id) +static int AnomalyAppLayerDecoderEventJson(JsonAnomalyLogThread *aft, const Packet *p, + AppLayerDecoderEvents *decoder_events, bool is_pktlayer, const char *layer, uint64_t tx_id) { const char *alprotoname = AppLayerGetProtoName(p->flow->alproto); - SCLogDebug("decoder_events %p event_count %d (last logged %d) %s", - decoder_events, decoder_events->cnt, - decoder_events->event_last_logged, - tx_id != TX_ID_UNUSED ? "tx" : "no-tx"); + SCLogDebug("decoder_events %p event_count %d (last logged %d) %s", decoder_events, + decoder_events->cnt, decoder_events->event_last_logged, + tx_id != TX_ID_UNUSED ? "tx" : "no-tx"); for (int i = decoder_events->event_last_logged; i < decoder_events->cnt; i++) { JsonBuilder *js; @@ -174,7 +171,6 @@ static int AnomalyAppLayerDecoderEventJson(JsonAnomalyLogThread *aft, return TM_ECODE_OK; } - jb_open_object(js, ANOMALY_EVENT_TYPE); jb_set_string(js, "app_proto", alprotoname); @@ -186,8 +182,8 @@ static int AnomalyAppLayerDecoderEventJson(JsonAnomalyLogThread *aft, if (is_pktlayer) { r = AppLayerGetEventInfoById(event_code, &event_name, &event_type); } else { - r = AppLayerParserGetEventInfoById(p->flow->proto, p->flow->alproto, - event_code, &event_name, &event_type); + r = AppLayerParserGetEventInfoById( + p->flow->proto, p->flow->alproto, event_code, &event_name, &event_type); } if (r == 0) { JB_SET_STRING(js, "type", "applayer"); @@ -211,8 +207,8 @@ static int AnomalyAppLayerDecoderEventJson(JsonAnomalyLogThread *aft, return TM_ECODE_OK; } -static int JsonAnomalyTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, - Flow *f, void *state, void *tx, uint64_t tx_id) +static int JsonAnomalyTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, + void *state, void *tx, uint64_t tx_id) { JsonAnomalyLogThread *aft = thread_data; if (!(aft->json_output_ctx->flags & LOG_JSON_APPLAYER_TYPE)) { @@ -222,17 +218,15 @@ static int JsonAnomalyTxLogger(ThreadVars *tv, void *thread_data, const Packet * AppLayerDecoderEvents *decoder_events; decoder_events = AppLayerParserGetEventsByTx(f->proto, f->alproto, tx); if (decoder_events && decoder_events->event_last_logged < decoder_events->cnt) { - SCLogDebug("state %p, tx: %p, tx_id: %"PRIu64, state, tx, tx_id); - AnomalyAppLayerDecoderEventJson(aft, p, decoder_events, false, - "proto_parser", tx_id); + SCLogDebug("state %p, tx: %p, tx_id: %" PRIu64, state, tx, tx_id); + AnomalyAppLayerDecoderEventJson(aft, p, decoder_events, false, "proto_parser", tx_id); } return TM_ECODE_OK; } static inline bool AnomalyHasParserEvents(const Packet *p) { - return (p->flow && p->flow->alparser && - AppLayerParserHasDecoderEvents(p->flow->alparser)); + return (p->flow && p->flow->alparser && AppLayerParserHasDecoderEvents(p->flow->alparser)); } static inline bool AnomalyHasPacketAppLayerEvents(const Packet *p) @@ -255,17 +249,18 @@ static int AnomalyJson(ThreadVars *tv, JsonAnomalyLogThread *aft, const Packet * if (aft->json_output_ctx->flags & LOG_JSON_APPLAYER_TYPE) { /* app layer proto detect events */ if (rc == TM_ECODE_OK && AnomalyHasPacketAppLayerEvents(p)) { - rc = AnomalyAppLayerDecoderEventJson(aft, p, p->app_layer_events, - true, "proto_detect", TX_ID_UNUSED); + rc = AnomalyAppLayerDecoderEventJson( + aft, p, p->app_layer_events, true, "proto_detect", TX_ID_UNUSED); } /* parser state events */ if (rc == TM_ECODE_OK && AnomalyHasParserEvents(p)) { SCLogDebug("Checking for anomaly events; alproto %d", p->flow->alproto); - AppLayerDecoderEvents *parser_events = AppLayerParserGetDecoderEvents(p->flow->alparser); + AppLayerDecoderEvents *parser_events = + AppLayerParserGetDecoderEvents(p->flow->alparser); if (parser_events && (parser_events->event_last_logged < parser_events->cnt)) { - rc = AnomalyAppLayerDecoderEventJson(aft, p, parser_events, - false, "parser", TX_ID_UNUSED); + rc = AnomalyAppLayerDecoderEventJson( + aft, p, parser_events, false, "parser", TX_ID_UNUSED); } } } @@ -281,8 +276,7 @@ static int JsonAnomalyLogger(ThreadVars *tv, void *thread_data, const Packet *p) static bool JsonAnomalyLogCondition(ThreadVars *tv, void *thread_data, const Packet *p) { - return p->events.cnt > 0 || - (p->app_layer_events && p->app_layer_events->cnt > 0) || + return p->events.cnt > 0 || (p->app_layer_events && p->app_layer_events->cnt > 0) || AnomalyHasParserEvents(p); } @@ -335,7 +329,7 @@ static void JsonAnomalyLogDeInitCtxSubHelper(OutputCtx *output_ctx) { SCLogDebug("cleaning up sub output_ctx %p", output_ctx); - AnomalyJsonOutputCtx *json_output_ctx = (AnomalyJsonOutputCtx *) output_ctx->data; + AnomalyJsonOutputCtx *json_output_ctx = (AnomalyJsonOutputCtx *)output_ctx->data; if (json_output_ctx != NULL) { SCFree(json_output_ctx); @@ -364,8 +358,7 @@ static void SetFlag(const ConfNode *conf, const char *name, uint16_t flag, uint1 } } -static void JsonAnomalyLogConf(AnomalyJsonOutputCtx *json_output_ctx, - ConfNode *conf) +static void JsonAnomalyLogConf(AnomalyJsonOutputCtx *json_output_ctx, ConfNode *conf) { static bool warn_no_flags = false; static bool warn_no_packet = false; @@ -380,7 +373,8 @@ static void JsonAnomalyLogConf(AnomalyJsonOutputCtx *json_output_ctx, } SetFlag(conf, "packethdr", LOG_JSON_PACKETHDR, &flags); } - if (((flags & (LOG_JSON_DECODE_TYPE | LOG_JSON_PACKETHDR)) == LOG_JSON_PACKETHDR) && !warn_no_packet) { + if (((flags & (LOG_JSON_DECODE_TYPE | LOG_JSON_PACKETHDR)) == LOG_JSON_PACKETHDR) && + !warn_no_packet) { SCLogWarning("Anomaly logging configured to include packet headers, however decode " "type logging has not been selected. Packet headers will not be logged."); warn_no_packet = true; @@ -449,15 +443,13 @@ static OutputInitResult JsonAnomalyLogInitCtxSub(ConfNode *conf, OutputCtx *pare return result; } -void JsonAnomalyLogRegister (void) +void JsonAnomalyLogRegister(void) { - OutputRegisterPacketSubModule(LOGGER_JSON_ANOMALY, "eve-log", MODULE_NAME, - "eve-log.anomaly", JsonAnomalyLogInitCtxSub, JsonAnomalyLogger, - JsonAnomalyLogCondition, JsonAnomalyLogThreadInit, JsonAnomalyLogThreadDeinit, - NULL); - - OutputRegisterTxSubModule(LOGGER_JSON_ANOMALY, "eve-log", MODULE_NAME, - "eve-log.anomaly", JsonAnomalyLogInitCtxHelper, ALPROTO_UNKNOWN, - JsonAnomalyTxLogger, JsonAnomalyLogThreadInit, - JsonAnomalyLogThreadDeinit, NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_ANOMALY, "eve-log", MODULE_NAME, "eve-log.anomaly", + JsonAnomalyLogInitCtxSub, JsonAnomalyLogger, JsonAnomalyLogCondition, + JsonAnomalyLogThreadInit, JsonAnomalyLogThreadDeinit, NULL); + + OutputRegisterTxSubModule(LOGGER_JSON_ANOMALY, "eve-log", MODULE_NAME, "eve-log.anomaly", + JsonAnomalyLogInitCtxHelper, ALPROTO_UNKNOWN, JsonAnomalyTxLogger, + JsonAnomalyLogThreadInit, JsonAnomalyLogThreadDeinit, NULL); } diff --git a/src/output-json-anomaly.h b/src/output/eve/output-json-anomaly.h similarity index 99% rename from src/output-json-anomaly.h rename to src/output/eve/output-json-anomaly.h index 4ca32b21ec59..475efbfc0b6c 100644 --- a/src/output-json-anomaly.h +++ b/src/output/eve/output-json-anomaly.h @@ -30,4 +30,3 @@ void JsonAnomalyLogRegister(void); #endif /* __OUTPUT_JSON_ALERT_H__ */ - diff --git a/src/output-json-common.c b/src/output/eve/output-json-common.c similarity index 97% rename from src/output-json-common.c rename to src/output/eve/output-json-common.c index 42595c3dde25..246045cdb780 100644 --- a/src/output-json-common.c +++ b/src/output/eve/output-json-common.c @@ -22,9 +22,9 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-json.h" -#include "util-buffer.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "util/buffer.h" OutputJsonThreadCtx *CreateEveThreadCtx(ThreadVars *t, OutputJsonCtx *ctx) { @@ -86,7 +86,6 @@ OutputInitResult OutputJsonLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return result; } - TmEcode JsonLogThreadInit(ThreadVars *t, const void *initdata, void **data) { if (initdata == NULL) { diff --git a/src/output-json-drop.c b/src/output/eve/output-json-drop.c similarity index 91% rename from src/output-json-drop.c rename to src/output/eve/output-json-drop.c index edce3793d100..803d9f1c3e6c 100644 --- a/src/output-json-drop.c +++ b/src/output/eve/output-json-drop.c @@ -33,7 +33,7 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" #include "decode-ipv4.h" #include "detect-parse.h" @@ -41,20 +41,20 @@ #include "detect-engine-mpm.h" #include "detect-reference.h" -#include "output.h" -#include "output-json.h" -#include "output-json-alert.h" -#include "output-json-drop.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-classification-config.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "util-buffer.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-alert.h" +#include "output/eve/output-json-drop.h" + +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/classification-config.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "util/buffer.h" #include "action-globals.h" @@ -85,7 +85,7 @@ static int g_droplog_flows_start = 1; * * \return return TM_ECODE_OK on success */ -static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) +static int DropLogJSON(JsonDropLogThread *aft, const Packet *p) { JsonDropOutputCtx *drop_ctx = aft->drop_ctx; @@ -132,7 +132,7 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) jb_set_bool(js, "rst", TCP_ISSET_FLAG_RST(p) ? true : false); jb_set_bool(js, "urg", TCP_ISSET_FLAG_URG(p) ? true : false); jb_set_bool(js, "fin", TCP_ISSET_FLAG_FIN(p) ? true : false); - jb_set_uint(js, "tcpres", TCP_GET_RAW_X2(p->tcph)); + jb_set_uint(js, "tcpres", TCP_GET_RAW_X2(p->tcph)); jb_set_uint(js, "tcpurgp", TCP_GET_URG_POINTER(p)); } break; @@ -145,7 +145,7 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) if (PKT_IS_ICMPV4(p)) { jb_set_uint(js, "icmp_id", ICMPV4_GET_ID(p)); jb_set_uint(js, "icmp_seq", ICMPV4_GET_SEQ(p)); - } else if(PKT_IS_ICMPV6(p)) { + } else if (PKT_IS_ICMPV6(p)) { jb_set_uint(js, "icmp_id", ICMPV6_GET_ID(p)); jb_set_uint(js, "icmp_seq", ICMPV6_GET_SEQ(p)); } @@ -171,9 +171,8 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) if (unlikely(pa->s == NULL)) { continue; } - if ((pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) || - ((pa->action & ACTION_DROP) && EngineModeIsIPS())) - { + if ((pa->action & (ACTION_REJECT | ACTION_REJECT_DST | ACTION_REJECT_BOTH)) || + ((pa->action & ACTION_DROP) && EngineModeIsIPS())) { AlertJsonHeader(NULL, p, pa, js, 0, &addr, NULL); logged = 1; break; @@ -199,8 +198,7 @@ static TmEcode JsonDropLogThreadInit(ThreadVars *t, const void *initdata, void * if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if(initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context for EveLogDrop. \"initdata\" argument NULL"); goto error_exit; } @@ -384,10 +382,9 @@ static bool JsonDropLogCondition(ThreadVars *tv, void *data, const Packet *p) return true; } -void JsonDropLogRegister (void) +void JsonDropLogRegister(void) { - OutputRegisterPacketSubModule(LOGGER_JSON_DROP, "eve-log", MODULE_NAME, - "eve-log.drop", JsonDropLogInitCtxSub, JsonDropLogger, - JsonDropLogCondition, JsonDropLogThreadInit, JsonDropLogThreadDeinit, - NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_DROP, "eve-log", MODULE_NAME, "eve-log.drop", + JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition, JsonDropLogThreadInit, + JsonDropLogThreadDeinit, NULL); } diff --git a/src/output-json-drop.h b/src/output/eve/output-json-drop.h similarity index 100% rename from src/output-json-drop.h rename to src/output/eve/output-json-drop.h diff --git a/src/output-json-email-common.c b/src/output/eve/output-json-email-common.c similarity index 83% rename from src/output-json-email-common.c rename to src/output/eve/output-json-email-common.c index 31d855758579..c98bfe0a18d6 100644 --- a/src/output-json-email-common.c +++ b/src/output/eve/output-json-email-common.c @@ -35,52 +35,52 @@ #include "tm-threads.h" #include "tm-threads-common.h" -#include "util-print.h" -#include "util-unittest.h" +#include "util/print.h" +#include "util/unittest.h" -#include "util-debug.h" +#include "util/debug.h" #include "app-layer-parser.h" -#include "output.h" -#include "app-layer-smtp.h" +#include "output/output.h" +#include "app-layer/smtp/parser.h" #include "app-layer.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-byte.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/byte.h" -#include "util-logopenfile.h" +#include "util/logopenfile.h" -#include "output-json.h" -#include "output-json-email-common.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-email-common.h" -#define LOG_EMAIL_DEFAULT 0 -#define LOG_EMAIL_EXTENDED (1<<0) -#define LOG_EMAIL_ARRAY (1<<1) /* require array handling */ -#define LOG_EMAIL_COMMA (1<<2) /* require array handling */ -#define LOG_EMAIL_BODY_MD5 (1<<3) -#define LOG_EMAIL_SUBJECT_MD5 (1<<4) +#define LOG_EMAIL_DEFAULT 0 +#define LOG_EMAIL_EXTENDED (1 << 0) +#define LOG_EMAIL_ARRAY (1 << 1) /* require array handling */ +#define LOG_EMAIL_COMMA (1 << 2) /* require array handling */ +#define LOG_EMAIL_BODY_MD5 (1 << 3) +#define LOG_EMAIL_SUBJECT_MD5 (1 << 4) struct { const char *config_field; const char *email_field; uint32_t flags; -} email_fields[] = { +} email_fields[] = { { "reply_to", "reply-to", LOG_EMAIL_DEFAULT }, - { "bcc", "bcc", LOG_EMAIL_COMMA|LOG_EMAIL_EXTENDED }, + { "bcc", "bcc", LOG_EMAIL_COMMA | LOG_EMAIL_EXTENDED }, { "message_id", "message-id", LOG_EMAIL_EXTENDED }, { "subject", "subject", LOG_EMAIL_EXTENDED }, { "x_mailer", "x-mailer", LOG_EMAIL_EXTENDED }, { "user_agent", "user-agent", LOG_EMAIL_EXTENDED }, { "received", "received", LOG_EMAIL_ARRAY }, { "x_originating_ip", "x-originating-ip", LOG_EMAIL_DEFAULT }, - { "in_reply_to", "in-reply-to", LOG_EMAIL_DEFAULT }, - { "references", "references", LOG_EMAIL_DEFAULT }, - { "importance", "importance", LOG_EMAIL_DEFAULT }, - { "priority", "priority", LOG_EMAIL_DEFAULT }, - { "sensitivity", "sensitivity", LOG_EMAIL_DEFAULT }, - { "organization", "organization", LOG_EMAIL_DEFAULT }, - { "content_md5", "content-md5", LOG_EMAIL_DEFAULT }, + { "in_reply_to", "in-reply-to", LOG_EMAIL_DEFAULT }, + { "references", "references", LOG_EMAIL_DEFAULT }, + { "importance", "importance", LOG_EMAIL_DEFAULT }, + { "priority", "priority", LOG_EMAIL_DEFAULT }, + { "sensitivity", "sensitivity", LOG_EMAIL_DEFAULT }, + { "organization", "organization", LOG_EMAIL_DEFAULT }, + { "content_md5", "content-md5", LOG_EMAIL_DEFAULT }, { "date", "date", LOG_EMAIL_DEFAULT }, - { NULL, NULL, LOG_EMAIL_DEFAULT}, + { NULL, NULL, LOG_EMAIL_DEFAULT }, }; static inline char *SkipWhiteSpaceTill(char *p, char *savep) @@ -155,7 +155,8 @@ static int JsonEmailAddToJsonArray(const uint8_t *val, size_t len, void *data) return 1; } -static void EveEmailLogJSONCustom(OutputJsonEmailCtx *email_ctx, JsonBuilder *js, SMTPTransaction *tx) +static void EveEmailLogJSONCustom( + OutputJsonEmailCtx *email_ctx, JsonBuilder *js, SMTPTransaction *tx) { int f = 0; JsonBuilderMark mark = { 0, 0, 0 }; @@ -165,15 +166,15 @@ static void EveEmailLogJSONCustom(OutputJsonEmailCtx *email_ctx, JsonBuilder *js return; } - while(email_fields[f].config_field) { - if (((email_ctx->fields & (1ULL<flags & LOG_EMAIL_EXTENDED) && (email_fields[f].flags & LOG_EMAIL_EXTENDED)) - ) { + while (email_fields[f].config_field) { + if (((email_ctx->fields & (1ULL << f)) != 0) || + ((email_ctx->flags & LOG_EMAIL_EXTENDED) && + (email_fields[f].flags & LOG_EMAIL_EXTENDED))) { if (email_fields[f].flags & LOG_EMAIL_ARRAY) { jb_get_mark(js, &mark); jb_open_array(js, email_fields[f].config_field); - int found = MimeDecFindFieldsForEach(entity, email_fields[f].email_field, JsonEmailAddToJsonArray, js); + int found = MimeDecFindFieldsForEach( + entity, email_fields[f].email_field, JsonEmailAddToJsonArray, js); if (found > 0) { jb_close(js); } else { @@ -193,22 +194,21 @@ static void EveEmailLogJSONCustom(OutputJsonEmailCtx *email_ctx, JsonBuilder *js } else { field = MimeDecFindField(entity, email_fields[f].email_field); if (field != NULL) { - char *s = BytesToString((uint8_t *)field->value, - (size_t)field->value_len); + char *s = BytesToString((uint8_t *)field->value, (size_t)field->value_len); if (likely(s != NULL)) { jb_set_string(js, email_fields[f].config_field, s); SCFree(s); } } } - } f++; } } /* JSON format logging */ -static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_id, JsonBuilder *sjs) +static bool EveEmailLogJsonData( + const Flow *f, void *state, void *vtx, uint64_t tx_id, JsonBuilder *sjs) { SMTPState *smtp_state; MimeDecParseState *mime_state; @@ -228,7 +228,8 @@ static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t SMTPTransaction *tx = vtx; mime_state = tx->mime_state; entity = tx->msg_tail; - SCLogDebug("lets go mime_state %p, entity %p, state_flag %u", mime_state, entity, mime_state ? mime_state->state_flag : 0); + SCLogDebug("lets go mime_state %p, entity %p, state_flag %u", mime_state, entity, + mime_state ? mime_state->state_flag : 0); break; default: /* don't know how we got here */ @@ -246,11 +247,10 @@ static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t /* From: */ field = MimeDecFindField(entity, "from"); if (field != NULL) { - char *s = BytesToString((uint8_t *)field->value, - (size_t)field->value_len); + char *s = BytesToString((uint8_t *)field->value, (size_t)field->value_len); if (likely(s != NULL)) { - //printf("From: \"%s\"\n", s); - char * sp = SkipWhiteSpaceTill(s, s + strlen(s)); + // printf("From: \"%s\"\n", s); + char *sp = SkipWhiteSpaceTill(s, s + strlen(s)); jb_set_string(sjs, "from", sp); SCFree(s); } @@ -280,7 +280,8 @@ static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t } } - if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) { + if (mime_state->stack == NULL || mime_state->stack->top == NULL || + mime_state->stack->top->data == NULL) { SCReturnBool(false); } @@ -295,8 +296,7 @@ static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t bool has_ipv4_url = false; bool has_exe_url = false; for (url = entity->url_list; url != NULL; url = url->next) { - char *s = BytesToString((uint8_t *)url->url, - (size_t)url->url_len); + char *s = BytesToString((uint8_t *)url->url, (size_t)url->url_len); if (s != NULL) { jb_append_string(js_url, s); if (url->url_flags & URL_IS_EXE) @@ -316,8 +316,7 @@ static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t for (entity = entity->child; entity != NULL; entity = entity->next) { if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { - char *s = BytesToString((uint8_t *)entity->filename, - (size_t)entity->filename_len); + char *s = BytesToString((uint8_t *)entity->filename, (size_t)entity->filename_len); jb_append_string(js_attach, s); SCFree(s); attach_cnt += 1; @@ -325,8 +324,7 @@ static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t if (entity->url_list != NULL) { MimeDecUrl *url; for (url = entity->url_list; url != NULL; url = url->next) { - char *s = BytesToString((uint8_t *)url->url, - (size_t)url->url_len); + char *s = BytesToString((uint8_t *)url->url, (size_t)url->url_len); if (s != NULL) { jb_append_string(js_url, s); SCFree(s); @@ -352,10 +350,11 @@ static bool EveEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t } /* JSON format logging */ -TmEcode EveEmailLogJson(JsonEmailLogThread *aft, JsonBuilder *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +TmEcode EveEmailLogJson(JsonEmailLogThread *aft, JsonBuilder *js, const Packet *p, Flow *f, + void *state, void *vtx, uint64_t tx_id) { OutputJsonEmailCtx *email_ctx = aft->emaillog_ctx; - SMTPTransaction *tx = (SMTPTransaction *) vtx; + SMTPTransaction *tx = (SMTPTransaction *)vtx; JsonBuilderMark mark = { 0, 0, 0 }; jb_get_mark(js, &mark); @@ -400,7 +399,7 @@ void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) } } - email_ctx->fields = 0; + email_ctx->fields = 0; ConfNode *custom; if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { ConfNode *field; @@ -417,7 +416,7 @@ void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) } } - email_ctx->flags = 0; + email_ctx->flags = 0; ConfNode *md5_conf; if ((md5_conf = ConfNodeLookupChild(conf, "md5")) != NULL) { ConfNode *field; diff --git a/src/output-json-email-common.h b/src/output/eve/output-json-email-common.h similarity index 89% rename from src/output-json-email-common.h rename to src/output/eve/output-json-email-common.h index e225f28822f6..c8a645d68a02 100644 --- a/src/output-json-email-common.h +++ b/src/output/eve/output-json-email-common.h @@ -25,8 +25,8 @@ #define __OUTPUT_JSON_EMAIL_COMMON_H__ typedef struct OutputJsonEmailCtx_ { - uint32_t flags; /** Store mode */ - uint64_t fields;/** Store fields */ + uint32_t flags; /** Store mode */ + uint64_t fields; /** Store fields */ OutputJsonCtx *eve_ctx; } OutputJsonEmailCtx; @@ -35,7 +35,8 @@ typedef struct JsonEmailLogThread_ { OutputJsonThreadCtx *ctx; } JsonEmailLogThread; -TmEcode EveEmailLogJson(JsonEmailLogThread *aft, JsonBuilder *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id); +TmEcode EveEmailLogJson(JsonEmailLogThread *aft, JsonBuilder *js, const Packet *p, Flow *f, + void *state, void *vtx, uint64_t tx_id); bool EveEmailAddMetadata(const Flow *f, uint32_t tx_id, JsonBuilder *js); void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx); diff --git a/src/output-json-file.c b/src/output/eve/output-json-file.c similarity index 91% rename from src/output-json-file.c rename to src/output/eve/output-json-file.c index 1018be06ee80..cb1ca1219e2c 100644 --- a/src/output-json-file.c +++ b/src/output/eve/output-json-file.c @@ -40,32 +40,32 @@ #include "stream.h" -#include "util-print.h" -#include "util-unittest.h" -#include "util-privs.h" -#include "util-debug.h" -#include "util-atomic.h" -#include "util-file.h" -#include "util-time.h" -#include "util-buffer.h" -#include "util-byte.h" -#include "util-validate.h" - -#include "util-logopenfile.h" - -#include "output.h" -#include "output-json.h" -#include "output-json-file.h" -#include "output-json-http.h" -#include "output-json-smtp.h" -#include "output-json-email-common.h" -#include "output-json-nfs.h" -#include "output-json-smb.h" -#include "output-json-http2.h" - -#include "app-layer-htp.h" -#include "app-layer-htp-xff.h" -#include "util-memcmp.h" +#include "util/print.h" +#include "util/unittest.h" +#include "util/privs.h" +#include "util/debug.h" +#include "util/atomic.h" +#include "util/file.h" +#include "util/time.h" +#include "util/buffer.h" +#include "util/byte.h" +#include "util/validate.h" + +#include "util/logopenfile.h" + +#include "output/output.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-file.h" +#include "app-layer/http/logger.h" +#include "app-layer/smtp/logger.h" +#include "output/eve/output-json-email-common.h" +#include "app-layer/nfs/logger.h" +#include "app-layer/smb/logger.h" +#include "app-layer/http2/logger.h" + +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-xff.h" +#include "util/memcmp.h" #include "stream-tcp-reassemble.h" typedef struct OutputFileCtx_ { @@ -86,7 +86,7 @@ JsonBuilder *JsonBuildFileInfoRecord(const Packet *p, const File *ff, void *tx, { enum OutputJsonLogDirection fdir = LOG_DIR_FLOW; - switch(dir) { + switch (dir) { case STREAM_TOCLIENT: fdir = LOG_DIR_FLOW_TOCLIENT; break; @@ -242,15 +242,13 @@ static int JsonFileLogger(ThreadVars *tv, void *thread_data, const Packet *p, co return 0; } - static TmEcode JsonFileLogThreadInit(ThreadVars *t, const void *initdata, void **data) { JsonFileLogThread *aft = SCCalloc(1, sizeof(JsonFileLogThread)); if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if(initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context for EveLogFile. \"initdata\" argument NULL"); goto error_exit; } @@ -350,10 +348,10 @@ static OutputInitResult OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_c return result; } -void JsonFileLogRegister (void) +void JsonFileLogRegister(void) { /* register as child of eve-log */ - OutputRegisterFileSubModule(LOGGER_JSON_FILE, "eve-log", "JsonFileLog", - "eve-log.files", OutputFileLogInitSub, JsonFileLogger, - JsonFileLogThreadInit, JsonFileLogThreadDeinit, NULL); + OutputRegisterFileSubModule(LOGGER_JSON_FILE, "eve-log", "JsonFileLog", "eve-log.files", + OutputFileLogInitSub, JsonFileLogger, JsonFileLogThreadInit, JsonFileLogThreadDeinit, + NULL); } diff --git a/src/output-json-file.h b/src/output/eve/output-json-file.h similarity index 96% rename from src/output-json-file.h rename to src/output/eve/output-json-file.h index bdd6a86ba96c..39bd72e96407 100644 --- a/src/output-json-file.h +++ b/src/output/eve/output-json-file.h @@ -24,7 +24,7 @@ #ifndef __OUTPUT_JSON_FILE_H__ #define __OUTPUT_JSON_FILE_H__ -#include "app-layer-htp-xff.h" +#include "app-layer/http/parser-xff.h" typedef struct OutputJsonCtx_ OutputJsonCtx; diff --git a/src/output-json-flow.c b/src/output/eve/output-json-flow.c similarity index 91% rename from src/output-json-flow.c rename to src/output/eve/output-json-flow.c index 07bcd954f2f5..f32a5c59e415 100644 --- a/src/output-json-flow.c +++ b/src/output/eve/output-json-flow.c @@ -32,20 +32,20 @@ #include "threadvars.h" #include "tm-threads.h" -#include "util-print.h" -#include "util-unittest.h" +#include "util/print.h" +#include "util/unittest.h" -#include "util-debug.h" +#include "util/debug.h" -#include "output.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-device.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "output-json.h" -#include "output-json-flow.h" +#include "output/output.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/device.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-flow.h" #include "stream-tcp.h" #include "stream-tcp-private.h" @@ -54,7 +54,7 @@ static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f) { char timebuf[64]; - char srcip[46] = {0}, dstip[46] = {0}; + char srcip[46] = { 0 }, dstip[46] = { 0 }; Port sp, dp; JsonBuilder *jb = jb_new_object(); @@ -121,7 +121,7 @@ static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f) /* tuple */ jb_set_string(jb, "src_ip", srcip); - switch(f->proto) { + switch (f->proto) { case IPPROTO_ICMP: break; case IPPROTO_UDP: @@ -131,7 +131,7 @@ static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f) break; } jb_set_string(jb, "dest_ip", dstip); - switch(f->proto) { + switch (f->proto) { case IPPROTO_ICMP: break; case IPPROTO_UDP: @@ -145,7 +145,7 @@ static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f) jb_set_string(jb, "proto", known_proto[f->proto]); } else { char proto[4]; - snprintf(proto, sizeof(proto), "%"PRIu8"", f->proto); + snprintf(proto, sizeof(proto), "%" PRIu8 "", f->proto); jb_set_string(jb, "proto", proto); } @@ -181,10 +181,8 @@ void EveAddAppProto(Flow *f, JsonBuilder *js) jb_set_string(js, "app_proto_orig", AppProtoToString(f->alproto_orig)); } if (f->alproto_expect != f->alproto && f->alproto_expect != ALPROTO_UNKNOWN) { - jb_set_string(js, "app_proto_expected", - AppProtoToString(f->alproto_expect)); + jb_set_string(js, "app_proto_expected", AppProtoToString(f->alproto_expect)); } - } void EveAddFlow(Flow *f, JsonBuilder *js) @@ -290,16 +288,13 @@ static void EveFlowLogJSON(OutputJsonThreadCtx *aft, JsonBuilder *jb, Flow *f) TcpSession *ssn = f->protoctx; char hexflags[3]; - snprintf(hexflags, sizeof(hexflags), "%02x", - ssn ? ssn->tcp_packet_flags : 0); + snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->tcp_packet_flags : 0); jb_set_string(jb, "tcp_flags", hexflags); - snprintf(hexflags, sizeof(hexflags), "%02x", - ssn ? ssn->client.tcp_flags : 0); + snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->client.tcp_flags : 0); jb_set_string(jb, "tcp_flags_ts", hexflags); - snprintf(hexflags, sizeof(hexflags), "%02x", - ssn ? ssn->server.tcp_flags : 0); + snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->server.tcp_flags : 0); jb_set_string(jb, "tcp_flags_tc", hexflags); EveTcpFlags(ssn ? ssn->tcp_packet_flags : 0, jb); @@ -345,7 +340,7 @@ static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) SCReturnInt(TM_ECODE_OK); } -void JsonFlowLogRegister (void) +void JsonFlowLogRegister(void) { /* register as child of eve-log */ OutputRegisterFlowSubModule(LOGGER_JSON_FLOW, "eve-log", "JsonFlowLog", "eve-log.flow", diff --git a/src/output-json-flow.h b/src/output/eve/output-json-flow.h similarity index 100% rename from src/output-json-flow.h rename to src/output/eve/output-json-flow.h diff --git a/src/output-json-frame.c b/src/output/eve/output-json-frame.c similarity index 96% rename from src/output-json-frame.c rename to src/output/eve/output-json-frame.c index 665010a6e44a..d951b8d30c09 100644 --- a/src/output-json-frame.c +++ b/src/output/eve/output-json-frame.c @@ -32,12 +32,12 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" -#include "util-logopenfile.h" -#include "util-misc.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/logopenfile.h" +#include "util/misc.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" @@ -46,24 +46,24 @@ #include "detect-metadata.h" #include "app-layer-parser.h" #include "app-layer-frames.h" -#include "app-layer-dnp3.h" -#include "app-layer-htp.h" -#include "app-layer-htp-xff.h" -#include "app-layer-ftp.h" -#include "util-classification-config.h" +#include "app-layer/dnp3/parser.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-xff.h" +#include "app-layer/ftp/parser.h" +#include "util/classification-config.h" #include "stream-tcp.h" -#include "output.h" -#include "output-json.h" -#include "output-json-frame.h" - -#include "util-byte.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-optimize.h" -#include "util-buffer.h" -#include "util-validate.h" +#include "output/output.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-frame.h" + +#include "util/byte.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/optimize.h" +#include "util/buffer.h" +#include "util/validate.h" #define MODULE_NAME "JsonFrameLog" diff --git a/src/output-json-frame.h b/src/output/eve/output-json-frame.h similarity index 100% rename from src/output-json-frame.h rename to src/output/eve/output-json-frame.h diff --git a/src/output-json-metadata.c b/src/output/eve/output-json-metadata.c similarity index 80% rename from src/output-json-metadata.c rename to src/output/eve/output-json-metadata.c index 772b2ccb06f2..3bb9f5759a6c 100644 --- a/src/output-json-metadata.c +++ b/src/output/eve/output-json-metadata.c @@ -32,34 +32,34 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" +#include "util/debug.h" -#include "util-misc.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/misc.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-reference.h" #include "app-layer-parser.h" -#include "app-layer-dnp3.h" -#include "app-layer-htp.h" -#include "app-layer-htp-xff.h" -#include "util-classification-config.h" -#include "util-syslog.h" -#include "util-logopenfile.h" - -#include "output.h" -#include "output-json.h" -#include "output-json-metadata.h" - -#include "util-byte.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-optimize.h" -#include "util-buffer.h" +#include "app-layer/dnp3/parser.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-xff.h" +#include "util/classification-config.h" +#include "util/syslog.h" +#include "util/logopenfile.h" + +#include "output/output.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-metadata.h" + +#include "util/byte.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/optimize.h" +#include "util/buffer.h" #define MODULE_NAME "JsonMetadataLog" @@ -92,7 +92,7 @@ static bool JsonMetadataLogCondition(ThreadVars *tv, void *data, const Packet *p return p->pktvar != NULL; } -void JsonMetadataLogRegister (void) +void JsonMetadataLogRegister(void) { OutputRegisterPacketSubModule(LOGGER_JSON_METADATA, "eve-log", MODULE_NAME, "eve-log.metadata", OutputJsonLogInitSub, JsonMetadataLogger, JsonMetadataLogCondition, JsonLogThreadInit, diff --git a/src/output-json-metadata.h b/src/output/eve/output-json-metadata.h similarity index 100% rename from src/output-json-metadata.h rename to src/output/eve/output-json-metadata.h diff --git a/src/output-json-netflow.c b/src/output/eve/output-json-netflow.c similarity index 89% rename from src/output-json-netflow.c rename to src/output/eve/output-json-netflow.c index 2ac6995cfad6..e18a7959a672 100644 --- a/src/output-json-netflow.c +++ b/src/output/eve/output-json-netflow.c @@ -32,27 +32,27 @@ #include "threadvars.h" #include "tm-threads.h" -#include "util-print.h" -#include "util-unittest.h" +#include "util/print.h" +#include "util/unittest.h" -#include "util-debug.h" +#include "util/debug.h" -#include "output.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-device.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "output-json.h" -#include "output-json-netflow.h" +#include "output/output.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/device.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-netflow.h" #include "stream-tcp-private.h" static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) { char timebuf[64]; - char srcip[46] = {0}, dstip[46] = {0}; + char srcip[46] = { 0 }, dstip[46] = { 0 }; Port sp, dp; JsonBuilder *js = jb_new_object(); @@ -125,7 +125,7 @@ static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) /* tuple */ jb_set_string(js, "src_ip", srcip); - switch(f->proto) { + switch (f->proto) { case IPPROTO_ICMP: break; case IPPROTO_UDP: @@ -135,7 +135,7 @@ static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) break; } jb_set_string(js, "dest_ip", dstip); - switch(f->proto) { + switch (f->proto) { case IPPROTO_ICMP: break; case IPPROTO_UDP: @@ -149,7 +149,7 @@ static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) jb_set_string(js, "proto", known_proto[f->proto]); } else { char proto[4]; - snprintf(proto, sizeof(proto), "%"PRIu8"", f->proto); + snprintf(proto, sizeof(proto), "%" PRIu8 "", f->proto); jb_set_string(js, "proto", proto); } @@ -161,7 +161,6 @@ static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) if (dir == 1) { type = f->icmp_d.type; code = f->icmp_d.code; - } jb_set_uint(js, "icmp_type", type); jb_set_uint(js, "icmp_code", code); @@ -177,8 +176,7 @@ static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) /* JSON format logging */ static void NetFlowLogEveToServer(JsonBuilder *js, Flow *f) { - jb_set_string(js, "app_proto", - AppProtoToString(f->alproto_ts ? f->alproto_ts : f->alproto)); + jb_set_string(js, "app_proto", AppProtoToString(f->alproto_ts ? f->alproto_ts : f->alproto)); jb_open_object(js, "netflow"); @@ -209,8 +207,7 @@ static void NetFlowLogEveToServer(JsonBuilder *js, Flow *f) TcpSession *ssn = f->protoctx; char hexflags[3]; - snprintf(hexflags, sizeof(hexflags), "%02x", - ssn ? ssn->client.tcp_flags : 0); + snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->client.tcp_flags : 0); jb_set_string(js, "tcp_flags", hexflags); EveTcpFlags(ssn ? ssn->client.tcp_flags : 0, js); @@ -221,8 +218,7 @@ static void NetFlowLogEveToServer(JsonBuilder *js, Flow *f) static void NetFlowLogEveToClient(JsonBuilder *js, Flow *f) { - jb_set_string(js, "app_proto", - AppProtoToString(f->alproto_tc ? f->alproto_tc : f->alproto)); + jb_set_string(js, "app_proto", AppProtoToString(f->alproto_tc ? f->alproto_tc : f->alproto)); jb_open_object(js, "netflow"); @@ -256,8 +252,7 @@ static void NetFlowLogEveToClient(JsonBuilder *js, Flow *f) TcpSession *ssn = f->protoctx; char hexflags[3]; - snprintf(hexflags, sizeof(hexflags), "%02x", - ssn ? ssn->server.tcp_flags : 0); + snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->server.tcp_flags : 0); jb_set_string(js, "tcp_flags", hexflags); EveTcpFlags(ssn ? ssn->server.tcp_flags : 0, js); diff --git a/src/output-json-netflow.h b/src/output/eve/output-json-netflow.h similarity index 100% rename from src/output-json-netflow.h rename to src/output/eve/output-json-netflow.h diff --git a/src/output-json-stats.c b/src/output/eve/output-json-stats.c similarity index 89% rename from src/output-json-stats.c rename to src/output/eve/output-json-stats.c index 7bfcfc58cad2..ed1b94cfbe15 100644 --- a/src/output-json-stats.c +++ b/src/output/eve/output-json-stats.c @@ -33,19 +33,19 @@ #include "threadvars.h" #include "tm-threads.h" -#include "util-print.h" -#include "util-time.h" -#include "util-unittest.h" +#include "util/print.h" +#include "util/time.h" +#include "util/unittest.h" -#include "util-debug.h" -#include "output.h" -#include "util-privs.h" -#include "util-buffer.h" +#include "util/debug.h" +#include "output/output.h" +#include "util/privs.h" +#include "util/buffer.h" -#include "util-logopenfile.h" +#include "util/logopenfile.h" -#include "output-json.h" -#include "output-json-stats.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-stats.h" #define MODULE_NAME "JsonStatsLog" @@ -73,8 +73,7 @@ typedef struct JsonStatsLogThread_ { MemBuffer *buffer; } JsonStatsLogThread; -static json_t *EngineStats2Json(const DetectEngineCtx *de_ctx, - const OutputEngineInfo output) +static json_t *EngineStats2Json(const DetectEngineCtx *de_ctx, const OutputEngineInfo output) { char timebuf[64]; const SigFileLoaderStat *sig_stat = NULL; @@ -91,13 +90,9 @@ static json_t *EngineStats2Json(const DetectEngineCtx *de_ctx, } sig_stat = &de_ctx->sig_stat; - if ((output == OUTPUT_ENGINE_RULESET || output == OUTPUT_ENGINE_ALL) && - sig_stat != NULL) - { - json_object_set_new(jdata, "rules_loaded", - json_integer(sig_stat->good_sigs_total)); - json_object_set_new(jdata, "rules_failed", - json_integer(sig_stat->bad_sigs_total)); + if ((output == OUTPUT_ENGINE_RULESET || output == OUTPUT_ENGINE_ALL) && sig_stat != NULL) { + json_object_set_new(jdata, "rules_loaded", json_integer(sig_stat->good_sigs_total)); + json_object_set_new(jdata, "rules_failed", json_integer(sig_stat->bad_sigs_total)); } return jdata; @@ -119,7 +114,7 @@ static TmEcode OutputEngineStats2Json(json_t **jdata, const OutputEngineInfo out goto err2; } - while(list) { + while (list) { js_tenant = json_object(); if (js_tenant == NULL) { goto err3; @@ -156,11 +151,13 @@ static TmEcode OutputEngineStats2Json(json_t **jdata, const OutputEngineInfo out return TM_ECODE_FAILED; } -TmEcode OutputEngineStatsReloadTime(json_t **jdata) { +TmEcode OutputEngineStatsReloadTime(json_t **jdata) +{ return OutputEngineStats2Json(jdata, OUTPUT_ENGINE_LAST_RELOAD); } -TmEcode OutputEngineStatsRuleset(json_t **jdata) { +TmEcode OutputEngineStatsRuleset(json_t **jdata) +{ return OutputEngineStats2Json(jdata, OUTPUT_ENGINE_RULESET); } @@ -181,7 +178,7 @@ static json_t *OutputStats2Json(json_t *js, const char *key) strlcpy(s, key, predot_len); iter = json_object_iter_at(js, s); - const char *s2 = strchr(dot+1, '.'); + const char *s2 = strchr(dot + 1, '.'); json_t *value = json_object_iter_value(iter); if (value == NULL) { @@ -198,7 +195,7 @@ static json_t *OutputStats2Json(json_t *js, const char *key) json_object_set_new(js, s, value); } if (s2 != NULL) { - return OutputStats2Json(value, &key[dot-key+1]); + return OutputStats2Json(value, &key[dot - key + 1]); } return value; } @@ -219,8 +216,7 @@ json_t *StatsToJSON(const StatsTable *st, uint8_t flags) /* Uptime, in seconds. */ double up_time_d = difftime(tval.tv_sec, st->start_time); - json_object_set_new(js_stats, "uptime", - json_integer((int)up_time_d)); + json_object_set_new(js_stats, "uptime", json_integer((int)up_time_d)); uint32_t u = 0; if (flags & JSON_STATS_TOTALS) { @@ -246,7 +242,7 @@ json_t *StatsToJSON(const StatsTable *st, uint8_t flags) char deltaname[strlen(stat_name) + strlen(delta_suffix) + 1]; snprintf(deltaname, sizeof(deltaname), "%s%s", stat_name, delta_suffix); json_object_set_new(js_type, deltaname, - json_integer(st->stats[u].value - st->stats[u].pvalue)); + json_integer(st->stats[u].value - st->stats[u].pvalue)); } } } @@ -287,7 +283,7 @@ json_t *StatsToJSON(const StatsTable *st, uint8_t flags) char deltaname[strlen(stat_name) + strlen(delta_suffix) + 1]; snprintf(deltaname, sizeof(deltaname), "%s%s", stat_name, delta_suffix); json_object_set_new(js_type, deltaname, - json_integer(st->tstats[u].value - st->tstats[u].pvalue)); + json_integer(st->tstats[u].value - st->tstats[u].pvalue)); } } } @@ -338,8 +334,7 @@ static TmEcode JsonStatsLogThreadInit(ThreadVars *t, const void *initdata, void if (unlikely(aft == NULL)) return TM_ECODE_FAILED; - if(initdata == NULL) - { + if (initdata == NULL) { SCLogDebug("Error getting context for EveLogStats. \"initdata\" argument NULL"); goto error_exit; } @@ -407,8 +402,7 @@ static OutputInitResult OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ if (unlikely(stats_ctx == NULL)) return result; - if (stats_decoder_events && - strcmp(stats_decoder_events_prefix, "decoder") == 0) { + if (stats_decoder_events && strcmp(stats_decoder_events_prefix, "decoder") == 0) { SCLogWarning("eve.stats will not display " "all decoder events correctly. See ticket #2225. Set a prefix in " "stats.decoder-events-prefix."); @@ -464,9 +458,10 @@ static OutputInitResult OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ return result; } -void JsonStatsLogRegister(void) { +void JsonStatsLogRegister(void) +{ /* register as child of eve-log */ - OutputRegisterStatsSubModule(LOGGER_JSON_STATS, "eve-log", MODULE_NAME, - "eve-log.stats", OutputStatsLogInitSub, JsonStatsLogger, - JsonStatsLogThreadInit, JsonStatsLogThreadDeinit, NULL); + OutputRegisterStatsSubModule(LOGGER_JSON_STATS, "eve-log", MODULE_NAME, "eve-log.stats", + OutputStatsLogInitSub, JsonStatsLogger, JsonStatsLogThreadInit, + JsonStatsLogThreadDeinit, NULL); } diff --git a/src/output-json-stats.h b/src/output/eve/output-json-stats.h similarity index 88% rename from src/output-json-stats.h rename to src/output/eve/output-json-stats.h index 9b96d5001298..dc96060904eb 100644 --- a/src/output-json-stats.h +++ b/src/output/eve/output-json-stats.h @@ -24,11 +24,11 @@ #ifndef __OUTPUT_JSON_COUNTERS_H__ #define __OUTPUT_JSON_COUNTERS_H__ -#include "output-stats.h" +#include "output/output-stats.h" -#define JSON_STATS_TOTALS (1<<0) -#define JSON_STATS_THREADS (1<<1) -#define JSON_STATS_DELTAS (1<<2) +#define JSON_STATS_TOTALS (1 << 0) +#define JSON_STATS_THREADS (1 << 1) +#define JSON_STATS_DELTAS (1 << 2) json_t *StatsToJSON(const StatsTable *st, uint8_t flags); TmEcode OutputEngineStatsReloadTime(json_t **jdata); diff --git a/src/output-json.c b/src/output/eve/output-json.c similarity index 86% rename from src/output-json.c rename to src/output/eve/output-json.c index 1dd2f948aba3..c7846c46d758 100644 --- a/src/output-json.c +++ b/src/output/eve/output-json.c @@ -32,40 +32,40 @@ #include "threads.h" #include "tm-threads.h" #include "threadvars.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-var-name.h" -#include "util-macset.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/var-name.h" +#include "util/macset.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-reference.h" #include "app-layer-parser.h" -#include "util-classification-config.h" -#include "util-syslog.h" +#include "util/classification-config.h" +#include "util/syslog.h" /* Internal output plugins */ -#include "output-eve-syslog.h" -#include "output-eve-null.h" - -#include "output.h" -#include "output-json.h" - -#include "util-byte.h" -#include "util-privs.h" -#include "util-print.h" -#include "util-proto-name.h" -#include "util-optimize.h" -#include "util-buffer.h" -#include "util-logopenfile.h" -#include "util-log-redis.h" -#include "util-device.h" -#include "util-validate.h" -#include "util-plugin.h" +#include "output/eve/output-eve-syslog.h" +#include "output/eve/output-eve-null.h" + +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "util/byte.h" +#include "util/privs.h" +#include "util/print.h" +#include "util/proto-name.h" +#include "util/optimize.h" +#include "util/buffer.h" +#include "util/logopenfile.h" +#include "util/log-redis.h" +#include "util/device.h" +#include "util/validate.h" +#include "util/plugin.h" #include "flow-var.h" #include "flow-bit.h" @@ -76,7 +76,7 @@ #include "suricata-plugin.h" #define DEFAULT_LOG_FILENAME "eve.json" -#define MODULE_NAME "OutputJSON" +#define MODULE_NAME "OutputJSON" #define MAX_JSON_SIZE 2048 @@ -91,7 +91,7 @@ static size_t traffic_label_prefix_len = 0; const JsonAddrInfo json_addr_info_zero; -void OutputJsonRegister (void) +void OutputJsonRegister(void) { OutputRegisterModule(MODULE_NAME, "eve-log", OutputJsonInitCtx); @@ -106,21 +106,19 @@ void OutputJsonRegister (void) json_t *SCJsonString(const char *val) { - if (val == NULL){ + if (val == NULL) { return NULL; } - json_t * retval = json_string(val); - char retbuf[MAX_JSON_SIZE] = {0}; + json_t *retval = json_string(val); + char retbuf[MAX_JSON_SIZE] = { 0 }; if (retval == NULL) { uint32_t u = 0; uint32_t offset = 0; for (u = 0; u < strlen(val); u++) { if (isprint(val[u])) { - PrintBufferData(retbuf, &offset, MAX_JSON_SIZE-1, "%c", - val[u]); + PrintBufferData(retbuf, &offset, MAX_JSON_SIZE - 1, "%c", val[u]); } else { - PrintBufferData(retbuf, &offset, MAX_JSON_SIZE-1, - "\\x%02X", val[u]); + PrintBufferData(retbuf, &offset, MAX_JSON_SIZE - 1, "\\x%02X", val[u]); } } retbuf[offset] = '\0'; @@ -210,24 +208,20 @@ static void EveAddPacketVars(const Packet *p, JsonBuilder *js_vars) if (pv->key != NULL) { uint32_t offset = 0; uint8_t keybuf[pv->key_len + 1]; - PrintStringsToBuffer(keybuf, &offset, - sizeof(keybuf), - pv->key, pv->key_len); + PrintStringsToBuffer(keybuf, &offset, sizeof(keybuf), pv->key, pv->key_len); uint32_t len = pv->value_len; uint8_t printable_buf[len + 1]; offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), - pv->value, pv->value_len); + PrintStringsToBuffer( + printable_buf, &offset, sizeof(printable_buf), pv->value, pv->value_len); jb_set_string(js_vars, (char *)keybuf, (char *)printable_buf); } else { const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); uint32_t len = pv->value_len; uint8_t printable_buf[len + 1]; uint32_t offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), - pv->value, pv->value_len); + PrintStringsToBuffer( + printable_buf, &offset, sizeof(printable_buf), pv->value, pv->value_len); jb_set_string(js_vars, varname, (char *)printable_buf); } jb_close(js_vars); @@ -270,8 +264,7 @@ static void EveAddFlowVars(const Flow *f, JsonBuilder *js_root, JsonBuilder **js if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { FlowVar *fv = (FlowVar *)gv; if (fv->datatype == FLOWVAR_TYPE_STR && fv->key == NULL) { - const char *varname = VarNameStoreLookupById(fv->idx, - VAR_TYPE_FLOW_VAR); + const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_VAR); if (varname) { if (js_flowvars == NULL) { js_flowvars = jb_new_array(); @@ -282,8 +275,7 @@ static void EveAddFlowVars(const Flow *f, JsonBuilder *js_root, JsonBuilder **js uint32_t len = fv->data.fv_str.value_len; uint8_t printable_buf[len + 1]; uint32_t offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), + PrintStringsToBuffer(printable_buf, &offset, sizeof(printable_buf), fv->data.fv_str.value, fv->data.fv_str.value_len); jb_start_object(js_flowvars); @@ -299,23 +291,19 @@ static void EveAddFlowVars(const Flow *f, JsonBuilder *js_root, JsonBuilder **js uint8_t keybuf[fv->keylen + 1]; uint32_t offset = 0; - PrintStringsToBuffer(keybuf, &offset, - sizeof(keybuf), - fv->key, fv->keylen); + PrintStringsToBuffer(keybuf, &offset, sizeof(keybuf), fv->key, fv->keylen); uint32_t len = fv->data.fv_str.value_len; uint8_t printable_buf[len + 1]; offset = 0; - PrintStringsToBuffer(printable_buf, &offset, - sizeof(printable_buf), + PrintStringsToBuffer(printable_buf, &offset, sizeof(printable_buf), fv->data.fv_str.value, fv->data.fv_str.value_len); jb_start_object(js_flowvars); jb_set_string(js_flowvars, (const char *)keybuf, (char *)printable_buf); jb_close(js_flowvars); } else if (fv->datatype == FLOWVAR_TYPE_INT) { - const char *varname = VarNameStoreLookupById(fv->idx, - VAR_TYPE_FLOW_INT); + const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_INT); if (varname) { if (js_flowints == NULL) { js_flowints = jb_new_object(); @@ -324,12 +312,10 @@ static void EveAddFlowVars(const Flow *f, JsonBuilder *js_root, JsonBuilder **js } jb_set_uint(js_flowints, varname, fv->data.fv_int.value); } - } } else if (gv->type == DETECT_FLOWBITS) { FlowBit *fb = (FlowBit *)gv; - const char *varname = VarNameStoreLookupById(fb->idx, - VAR_TYPE_FLOW_BIT); + const char *varname = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); if (varname) { if (SCStringHasPrefix(varname, TRAFFIC_ID_PREFIX)) { if (js_traffic_id == NULL) { @@ -416,8 +402,8 @@ void EveAddMetadata(const Packet *p, const Flow *f, JsonBuilder *js) } } -void EveAddCommonOptions(const OutputJsonCommonSettings *cfg, - const Packet *p, const Flow *f, JsonBuilder *js) +void EveAddCommonOptions( + const OutputJsonCommonSettings *cfg, const Packet *p, const Flow *f, JsonBuilder *js) { if (cfg->include_metadata) { EveAddMetadata(p, f, js); @@ -479,21 +465,17 @@ void EveTcpFlags(const uint8_t flags, JsonBuilder *js) void JsonAddrInfoInit(const Packet *p, enum OutputJsonLogDirection dir, JsonAddrInfo *addr) { - char srcip[46] = {0}, dstip[46] = {0}; + char srcip[46] = { 0 }, dstip[46] = { 0 }; Port sp, dp; switch (dir) { case LOG_DIR_PACKET: if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), - dstip, sizeof(dstip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), - dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); } else { /* Not an IP packet so don't do anything */ return; @@ -505,29 +487,25 @@ void JsonAddrInfoInit(const Packet *p, enum OutputJsonLogDirection dir, JsonAddr case LOG_DIR_FLOW_TOSERVER: if ((PKT_IS_TOSERVER(p))) { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), - dstip, sizeof(dstip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), - dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); } sp = p->sp; dp = p->dp; } else { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), - dstip, sizeof(dstip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), - dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip)); } sp = p->dp; dp = p->sp; @@ -536,29 +514,25 @@ void JsonAddrInfoInit(const Packet *p, enum OutputJsonLogDirection dir, JsonAddr case LOG_DIR_FLOW_TOCLIENT: if ((PKT_IS_TOCLIENT(p))) { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), - dstip, sizeof(dstip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), - dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); } sp = p->sp; dp = p->dp; } else { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), - dstip, sizeof(dstip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet( + AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), - srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), - dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip)); } sp = p->dp; dp = p->sp; @@ -592,8 +566,7 @@ void JsonAddrInfoInit(const Packet *p, enum OutputJsonLogDirection dir, JsonAddr #define COMMUNITY_ID_BUF_SIZE 64 -static bool CalculateCommunityFlowIdv4(const Flow *f, - const uint16_t seed, unsigned char *base64buf) +static bool CalculateCommunityFlowIdv4(const Flow *f, const uint16_t seed, unsigned char *base64buf) { struct { uint16_t seed; @@ -635,15 +608,14 @@ static bool CalculateCommunityFlowIdv4(const Flow *f, if (SCSha1HashBuffer((const uint8_t *)&ipv4, sizeof(ipv4), hash, sizeof(hash)) == 1) { strlcpy((char *)base64buf, "1:", COMMUNITY_ID_BUF_SIZE); unsigned long out_len = COMMUNITY_ID_BUF_SIZE - 2; - if (Base64Encode(hash, sizeof(hash), base64buf+2, &out_len) == SC_BASE64_OK) { + if (Base64Encode(hash, sizeof(hash), base64buf + 2, &out_len) == SC_BASE64_OK) { return true; } } return false; } -static bool CalculateCommunityFlowIdv6(const Flow *f, - const uint16_t seed, unsigned char *base64buf) +static bool CalculateCommunityFlowIdv6(const Flow *f, const uint16_t seed, unsigned char *base64buf) { struct { uint16_t seed; @@ -684,7 +656,7 @@ static bool CalculateCommunityFlowIdv6(const Flow *f, if (SCSha1HashBuffer((const uint8_t *)&ipv6, sizeof(ipv6), hash, sizeof(hash)) == 1) { strlcpy((char *)base64buf, "1:", COMMUNITY_ID_BUF_SIZE); unsigned long out_len = COMMUNITY_ID_BUF_SIZE - 2; - if (Base64Encode(hash, sizeof(hash), base64buf+2, &out_len) == SC_BASE64_OK) { + if (Base64Encode(hash, sizeof(hash), base64buf + 2, &out_len) == SC_BASE64_OK) { return true; } } @@ -717,12 +689,12 @@ void CreateEveFlowId(JsonBuilder *js, const Flow *f) } } -static inline void JSONFormatAndAddMACAddr(JsonBuilder *js, const char *key, - uint8_t *val, bool is_array) +static inline void JSONFormatAndAddMACAddr( + JsonBuilder *js, const char *key, uint8_t *val, bool is_array) { char eth_addr[19]; - (void) snprintf(eth_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", - val[0], val[1], val[2], val[3], val[4], val[5]); + (void)snprintf(eth_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", val[0], val[1], val[2], val[3], + val[4], val[5]); if (is_array) { jb_append_string(js, eth_addr); } else { @@ -737,7 +709,7 @@ typedef struct JSONMACAddrInfo { static int MacSetIterateToJSON(uint8_t *val, MacSetSide side, void *data) { - JSONMACAddrInfo *info = (JSONMACAddrInfo*) data; + JSONMACAddrInfo *info = (JSONMACAddrInfo *)data; if (side == MAC_SET_DST) { JSONFormatAndAddMACAddr(info->dst, NULL, val, true); } else { @@ -902,8 +874,7 @@ int OutputJSONMemBufferCallback(const char *str, size_t size, void *data) int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) { if (file_ctx->sensor_name) { - json_object_set_new(js, "host", - json_string(file_ctx->sensor_name)); + json_object_set_new(js, "host", json_string(file_ctx->sensor_name)); } if (file_ctx->is_pcap_offline) { @@ -914,13 +885,9 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) MemBufferWriteRaw((*buffer), file_ctx->prefix, file_ctx->prefix_len); } - OutputJSONMemBufferWrapper wrapper = { - .buffer = buffer, - .expand_by = JSON_OUTPUT_BUFFER_SIZE - }; + OutputJSONMemBufferWrapper wrapper = { .buffer = buffer, .expand_by = JSON_OUTPUT_BUFFER_SIZE }; - int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, - file_ctx->json_flags); + int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, file_ctx->json_flags); if (r != 0) return TM_ECODE_OK; @@ -1051,8 +1018,7 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf) if (sensor_name != NULL) { SCLogWarning("Found deprecated eve-log setting \"sensor-name\". " "Please set sensor-name globally."); - } - else { + } else { (void)ConfGet("sensor-name", &sensor_name); } @@ -1099,12 +1065,10 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf) } const char *prefix = ConfNodeLookupChildValue(conf, "prefix"); - if (prefix != NULL) - { + if (prefix != NULL) { SCLogInfo("Using prefix '%s' for JSON messages", prefix); json_ctx->file_ctx->prefix = SCStrdup(prefix); - if (json_ctx->file_ctx->prefix == NULL) - { + if (json_ctx->file_ctx->prefix == NULL) { FatalError("Failed to allocate memory for eve-log.prefix setting."); } json_ctx->file_ctx->prefix_len = strlen(prefix); @@ -1159,9 +1123,7 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf) } const char *cid_seed = ConfNodeLookupChildValue(conf, "community-id-seed"); if (cid_seed != NULL) { - if (StringParseUint16(&json_ctx->cfg.community_id_seed, - 10, 0, cid_seed) < 0) - { + if (StringParseUint16(&json_ctx->cfg.community_id_seed, 10, 0, cid_seed) < 0) { FatalError("Failed to initialize JSON output, " "invalid community-id-seed: %s", cid_seed); @@ -1179,9 +1141,8 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf) const char *pcapfile_s = ConfNodeLookupChildValue(conf, "pcap-file"); if (pcapfile_s != NULL && ConfValIsTrue(pcapfile_s)) { - json_ctx->file_ctx->is_pcap_offline = - (RunmodeGetCurrent() == RUNMODE_PCAP_FILE || - RunmodeGetCurrent() == RUNMODE_UNIX_SOCKET); + json_ctx->file_ctx->is_pcap_offline = (RunmodeGetCurrent() == RUNMODE_PCAP_FILE || + RunmodeGetCurrent() == RUNMODE_UNIX_SOCKET); } json_ctx->file_ctx->type = log_filetype; } diff --git a/src/output-json.h b/src/output/eve/output-json.h similarity index 92% rename from src/output-json.h rename to src/output/eve/output-json.h index 6fe6c5898d74..d12402cd5a5f 100644 --- a/src/output-json.h +++ b/src/output/eve/output-json.h @@ -25,12 +25,12 @@ #define __OUTPUT_JSON_H__ #include "suricata-common.h" -#include "util-buffer.h" -#include "util-logopenfile.h" -#include "output.h" +#include "util/buffer.h" +#include "util/logopenfile.h" +#include "output/output.h" #include "rust.h" -#include "app-layer-htp-xff.h" +#include "app-layer/http/parser-xff.h" #include "suricata-plugin.h" void OutputJsonRegister(void); @@ -42,7 +42,7 @@ enum OutputJsonLogDirection { LOG_DIR_FLOW_TOSERVER, }; -#define JSON_ADDR_LEN 46 +#define JSON_ADDR_LEN 46 #define JSON_PROTO_LEN 16 /* A struct to contain address info for rendering to JSON. */ @@ -56,8 +56,7 @@ typedef struct JsonAddrInfo_ { extern const JsonAddrInfo json_addr_info_zero; -void JsonAddrInfoInit(const Packet *p, enum OutputJsonLogDirection dir, - JsonAddrInfo *addr); +void JsonAddrInfoInit(const Packet *p, enum OutputJsonLogDirection dir, JsonAddrInfo *addr); /* Suggested output buffer size */ #define JSON_OUTPUT_BUFFER_SIZE 65535 @@ -110,8 +109,8 @@ OutputInitResult OutputJsonLogInitSub(ConfNode *conf, OutputCtx *parent_ctx); TmEcode JsonLogThreadInit(ThreadVars *t, const void *initdata, void **data); TmEcode JsonLogThreadDeinit(ThreadVars *t, void *data); -void EveAddCommonOptions(const OutputJsonCommonSettings *cfg, - const Packet *p, const Flow *f, JsonBuilder *js); +void EveAddCommonOptions( + const OutputJsonCommonSettings *cfg, const Packet *p, const Flow *f, JsonBuilder *js); void EveAddMetadata(const Packet *p, const Flow *f, JsonBuilder *js); int OutputJSONMemBufferCallback(const char *str, size_t size, void *data); diff --git a/src/output-file.c b/src/output/output-file.c similarity index 96% rename from src/output-file.c rename to src/output/output-file.c index ff8b83739443..88f2325d8a0b 100644 --- a/src/output-file.c +++ b/src/output/output-file.c @@ -24,17 +24,17 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-file.h" +#include "output/output.h" +#include "output/output-file.h" #if 0 #include "app-layer.h" #endif #include "app-layer-parser.h" // FileApplyTxFlags #include "detect-filemagic.h" -#include "util-file.h" -#include "util-magic.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/file.h" +#include "util/magic.h" +#include "util/profiling.h" +#include "util/validate.h" bool g_file_logger_enabled = false; @@ -55,9 +55,8 @@ typedef struct OutputFileLogger_ { static OutputFileLogger *list = NULL; int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, - OutputCtx *output_ctx, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputFileLogger *op = SCCalloc(1, sizeof(*op)); if (op == NULL) diff --git a/src/output-file.h b/src/output/output-file.h similarity index 92% rename from src/output-file.h rename to src/output/output-file.h index 13735b282de0..48323d177928 100644 --- a/src/output-file.h +++ b/src/output/output-file.h @@ -48,9 +48,9 @@ void OutputFileLogFfc(ThreadVars *tv, OutputFileLoggerThreadData *op_thread_data typedef int (*FileLogger)(ThreadVars *, void *thread_data, const Packet *, const File *, void *tx, const uint64_t tx_id, uint8_t direction); -int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, - OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); +int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, OutputCtx *, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputFileLoggerRegister(void); diff --git a/src/output-filedata.c b/src/output/output-filedata.c similarity index 95% rename from src/output-filedata.c rename to src/output/output-filedata.c index daaab1bcc48d..335105f6f32e 100644 --- a/src/output-filedata.c +++ b/src/output/output-filedata.c @@ -24,15 +24,15 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-filedata.h" +#include "output/output.h" +#include "output/output-filedata.h" #include "app-layer-parser.h" #include "detect-filemagic.h" #include "conf.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-magic.h" -#include "util-path.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/magic.h" +#include "util/path.h" bool g_filedata_logger_enabled = false; @@ -52,10 +52,9 @@ typedef struct OutputFiledataLogger_ { static OutputFiledataLogger *list = NULL; -int OutputRegisterFiledataLogger(LoggerId id, const char *name, - FiledataLogger LogFunc, OutputCtx *output_ctx, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +int OutputRegisterFiledataLogger(LoggerId id, const char *name, FiledataLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputFiledataLogger *op = SCCalloc(1, sizeof(*op)); if (op == NULL) diff --git a/src/output-filedata.h b/src/output/output-filedata.h similarity index 90% rename from src/output-filedata.h rename to src/output/output-filedata.h index 58764aa81e03..e2d256551a30 100644 --- a/src/output-filedata.h +++ b/src/output/output-filedata.h @@ -49,10 +49,9 @@ void OutputFiledataLogFfc(ThreadVars *tv, OutputFiledataLoggerThreadData *td, Pa typedef int (*FiledataLogger)(ThreadVars *, void *thread_data, const Packet *, File *, void *tx, const uint64_t tx_id, const uint8_t *, uint32_t, uint8_t, uint8_t dir); -int OutputRegisterFiledataLogger(LoggerId id, const char *name, - FiledataLogger LogFunc, OutputCtx *, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); +int OutputRegisterFiledataLogger(LoggerId id, const char *name, FiledataLogger LogFunc, OutputCtx *, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputFiledataLoggerRegister(void); diff --git a/src/output-filestore.c b/src/output/output-filestore.c similarity index 91% rename from src/output-filestore.c rename to src/output/output-filestore.c index 607fe292ffc1..4e1446de85be 100644 --- a/src/output-filestore.c +++ b/src/output/output-filestore.c @@ -16,26 +16,26 @@ */ #include "suricata-common.h" -#include "output-filestore.h" +#include "output/output-filestore.h" #include "stream-tcp.h" #include "feature.h" -#include "output.h" -#include "output-json-file.h" +#include "output/output.h" +#include "output/eve/output-json-file.h" -#include "util-conf.h" -#include "util-misc.h" -#include "util-path.h" -#include "util-print.h" +#include "util/conf.h" +#include "util/misc.h" +#include "util/path.h" +#include "util/print.h" #define MODULE_NAME "OutputFilestore" /* Create a filestore specific PATH_MAX that is less than the system * PATH_MAX to prevent newer gcc truncation warnings with snprint. */ #define SHA256_STRING_LEN (SC_SHA256_LEN * 2) -#define LEAF_DIR_MAX_LEN 4 +#define LEAF_DIR_MAX_LEN 4 #define FILESTORE_PREFIX_MAX (PATH_MAX - SHA256_STRING_LEN - LEAF_DIR_MAX_LEN) /* The default log directory, relative to the default log @@ -104,8 +104,7 @@ static uint32_t FileGetMaxOpenFiles(void) * \param src_filename Filename to use as timestamp source. * \param filename Filename to apply timestamps to. */ -static void OutputFilestoreUpdateFileTime(const char *src_filename, - const char *filename) +static void OutputFilestoreUpdateFileTime(const char *src_filename, const char *filename) { struct stat sb; if (stat(src_filename, &sb) != 0) { @@ -117,8 +116,7 @@ static void OutputFilestoreUpdateFileTime(const char *src_filename, .modtime = sb.st_mtime, }; if (utime(filename, &utimbuf) != 0) { - SCLogDebug("Failed to update file timestamps: %s: %s", filename, - strerror(errno)); + SCLogDebug("Failed to update file timestamps: %s: %s", filename, strerror(errno)); } } @@ -129,16 +127,14 @@ static void OutputFilestoreFinalizeFiles(ThreadVars *tv, const OutputFilestoreLo /* Stringify the SHA256 which will be used in the final * filename. */ char sha256string[(SC_SHA256_LEN * 2) + 1]; - PrintHexString(sha256string, sizeof(sha256string), ff->sha256, - sizeof(ff->sha256)); + PrintHexString(sha256string, sizeof(sha256string), ff->sha256, sizeof(ff->sha256)); char tmp_filename[PATH_MAX] = ""; - snprintf(tmp_filename, sizeof(tmp_filename), "%s/file.%u", ctx->tmpdir, - ff->file_store_id); + snprintf(tmp_filename, sizeof(tmp_filename), "%s/file.%u", ctx->tmpdir, ff->file_store_id); char final_filename[PATH_MAX] = ""; - snprintf(final_filename, sizeof(final_filename), "%s/%c%c/%s", - ctx->prefix, sha256string[0], sha256string[1], sha256string); + snprintf(final_filename, sizeof(final_filename), "%s/%c%c/%s", ctx->prefix, sha256string[0], + sha256string[1], sha256string); if (SCPathExists(final_filename)) { OutputFilestoreUpdateFileTime(tmp_filename, final_filename); @@ -195,13 +191,11 @@ static int OutputFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet SCLogDebug("ff %p, data %p, data_len %u", ff, data, data_len); char base_filename[PATH_MAX] = ""; - snprintf(base_filename, sizeof(base_filename), "%s/file.%u", - ctx->tmpdir, ff->file_store_id); + snprintf(base_filename, sizeof(base_filename), "%s/file.%u", ctx->tmpdir, ff->file_store_id); snprintf(filename, sizeof(filename), "%s", base_filename); if (flags & OUTPUT_FILEDATA_FLAG_OPEN) { - file_fd = open(filename, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, - 0644); + file_fd = open(filename, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644); if (file_fd == -1) { StatsIncr(tv, aft->fs_error_counter); SCLogWarning("Filestore (v2) failed to create %s: %s", filename, strerror(errno)); @@ -217,7 +211,7 @@ static int OutputFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet } ff->fd = -1; } - /* we can get called with a NULL ffd when we need to close */ + /* we can get called with a NULL ffd when we need to close */ } else if (data != NULL) { if (ff->fd == -1) { file_fd = open(filename, O_APPEND | O_NOFOLLOW | O_WRONLY); @@ -260,8 +254,7 @@ static int OutputFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet return 0; } -static TmEcode OutputFilestoreLogThreadInit(ThreadVars *t, const void *initdata, - void **data) +static TmEcode OutputFilestoreLogThreadInit(ThreadVars *t, const void *initdata, void **data) { OutputFilestoreLogThread *aft = SCCalloc(1, sizeof(OutputFilestoreLogThread)); if (unlikely(aft == NULL)) @@ -276,8 +269,7 @@ static TmEcode OutputFilestoreLogThreadInit(ThreadVars *t, const void *initdata, OutputFilestoreCtx *ctx = ((OutputCtx *)initdata)->data; aft->ctx = ctx; - aft->counter_max_hits = - StatsRegisterCounter("file_store.open_files_max_hit", t); + aft->counter_max_hits = StatsRegisterCounter("file_store.open_files_max_hit", t); /* File system type errors (open, write, rename) will only be * logged once. But this stat will be incremented for every @@ -407,8 +399,7 @@ static OutputInitResult OutputFilestoreLogInitCtx(ConfNode *conf) } strlcpy(ctx->prefix, log_directory, sizeof(ctx->prefix)); - int written = snprintf(ctx->tmpdir, sizeof(ctx->tmpdir) - 1, "%s/tmp", - log_directory); + int written = snprintf(ctx->tmpdir, sizeof(ctx->tmpdir) - 1, "%s/tmp", log_directory); if (written == sizeof(ctx->tmpdir)) { SCLogError("File-store output directory overflow."); SCFree(ctx); @@ -429,15 +420,13 @@ static OutputInitResult OutputFilestoreLogInitCtx(ConfNode *conf) output_ctx->data = ctx; output_ctx->DeInit = OutputFilestoreLogDeInitCtx; - const char *write_fileinfo = ConfNodeLookupChildValue(conf, - "write-fileinfo"); + const char *write_fileinfo = ConfNodeLookupChildValue(conf, "write-fileinfo"); if (write_fileinfo != NULL && ConfValIsTrue(write_fileinfo)) { SCLogConfig("Filestore (v2) will output fileinfo records."); ctx->fileinfo = true; } - const char *force_filestore = ConfNodeLookupChildValue(conf, - "force-filestore"); + const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { FileForceFilestoreEnable(); SCLogInfo("forcing filestore of all files"); @@ -456,12 +445,10 @@ static OutputInitResult OutputFilestoreLogInitCtx(ConfNode *conf) ProvidesFeature(FEATURE_OUTPUT_FILESTORE); - const char *stream_depth_str = ConfNodeLookupChildValue(conf, - "stream-depth"); + const char *stream_depth_str = ConfNodeLookupChildValue(conf, "stream-depth"); if (stream_depth_str != NULL && strcmp(stream_depth_str, "no")) { uint32_t stream_depth = 0; - if (ParseSizeStringU32(stream_depth_str, - &stream_depth) < 0) { + if (ParseSizeStringU32(stream_depth_str, &stream_depth) < 0) { SCLogError("Error parsing " "file-store.stream-depth " "from conf file - %s. Killing engine", @@ -480,12 +467,10 @@ static OutputInitResult OutputFilestoreLogInitCtx(ConfNode *conf) } } - const char *file_count_str = ConfNodeLookupChildValue(conf, - "max-open-files"); + const char *file_count_str = ConfNodeLookupChildValue(conf, "max-open-files"); if (file_count_str != NULL) { uint32_t file_count = 0; - if (ParseSizeStringU32(file_count_str, - &file_count) < 0) { + if (ParseSizeStringU32(file_count_str, &file_count) < 0) { SCLogError("Error parsing " "file-store.max-open-files " "from conf file - %s. Killing engine", @@ -495,7 +480,8 @@ static OutputInitResult OutputFilestoreLogInitCtx(ConfNode *conf) if (file_count != 0) { FileSetMaxOpenFiles(file_count); SCLogConfig("Filestore (v2) will keep a max of %d " - "simultaneously open files", file_count); + "simultaneously open files", + file_count); } } } @@ -508,9 +494,8 @@ static OutputInitResult OutputFilestoreLogInitCtx(ConfNode *conf) void OutputFilestoreRegister(void) { OutputRegisterFiledataModule(LOGGER_FILE_STORE, MODULE_NAME, "file-store", - OutputFilestoreLogInitCtx, OutputFilestoreLogger, - OutputFilestoreLogThreadInit, OutputFilestoreLogThreadDeinit, - NULL); + OutputFilestoreLogInitCtx, OutputFilestoreLogger, OutputFilestoreLogThreadInit, + OutputFilestoreLogThreadDeinit, NULL); SC_ATOMIC_INIT(filestore_open_file_cnt); SC_ATOMIC_SET(filestore_open_file_cnt, 0); diff --git a/src/output-filestore.h b/src/output/output-filestore.h similarity index 100% rename from src/output-filestore.h rename to src/output/output-filestore.h diff --git a/src/output-flow.c b/src/output/output-flow.c similarity index 93% rename from src/output-flow.c rename to src/output/output-flow.c index 5231a3667942..f62a853290b5 100644 --- a/src/output-flow.c +++ b/src/output/output-flow.c @@ -24,10 +24,10 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-flow.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "output/output.h" +#include "output/output-flow.h" +#include "util/profiling.h" +#include "util/validate.h" /** per thread data for this module, contains a list of per thread * data for the packet loggers. */ @@ -50,10 +50,9 @@ typedef struct OutputFlowLogger_ { static OutputFlowLogger *list = NULL; -int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, - OutputCtx *output_ctx, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *output_ctx, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputFlowLogger *op = SCCalloc(1, sizeof(*op)); if (op == NULL) @@ -103,9 +102,9 @@ TmEcode OutputFlowLog(ThreadVars *tv, void *thread_data, Flow *f) DEBUG_VALIDATE_BUG_ON(logger->LogFunc == NULL); SCLogDebug("logger %p", logger); - //PACKET_PROFILING_LOGGER_START(p, logger->module_id); + // PACKET_PROFILING_LOGGER_START(p, logger->module_id); logger->LogFunc(tv, store->thread_data, f); - //PACKET_PROFILING_LOGGER_END(p, logger->module_id); + // PACKET_PROFILING_LOGGER_END(p, logger->module_id); logger = logger->next; store = store->next; diff --git a/src/output-flow.h b/src/output/output-flow.h similarity index 91% rename from src/output-flow.h rename to src/output/output-flow.h index 2fa26660fee7..c53fb8e26f02 100644 --- a/src/output-flow.h +++ b/src/output/output-flow.h @@ -31,9 +31,9 @@ /** flow logger function pointer type */ typedef int (*FlowLogger)(ThreadVars *, void *thread_data, Flow *f); -int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, - OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); +int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputFlowShutdown(void); diff --git a/src/output-lua.c b/src/output/output-lua.c similarity index 93% rename from src/output-lua.c rename to src/output/output-lua.c index 776cf51b9c9b..fa5ccb98fed6 100644 --- a/src/output-lua.c +++ b/src/output/output-lua.c @@ -23,32 +23,32 @@ */ #include "suricata-common.h" -#include "output-lua.h" +#include "output/output-lua.h" #ifdef HAVE_LUA -#include "util-print.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "output.h" -#include "app-layer-htp.h" +#include "util/print.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "output/output.h" +#include "app-layer/http/parser.h" #include "app-layer.h" -#include "app-layer-ssl.h" -#include "app-layer-ssh.h" +#include "app-layer/ssl/parser.h" +#include "app-layer/ssh/parser.h" #include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-http.h" -#include "util-lua-dns.h" -#include "util-lua-ja3.h" -#include "util-lua-tls.h" -#include "util-lua-ssh.h" -#include "util-lua-hassh.h" -#include "util-lua-smtp.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "app-layer/http/lua.h" +#include "app-layer/dns/lua.h" +#include "util/lua/lua-ja3.h" +#include "app-layer/tls/lua.h" +#include "app-layer/ssh/lua.h" +#include "app-layer/ssh/lua-hassh.h" +#include "app-layer/smtp/lua.h" #define MODULE_NAME "LuaLog" @@ -82,7 +82,8 @@ static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data); * * NOTE: The flow (f) also referenced by p->flow is locked. */ -static int LuaTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) +static int LuaTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, + void *txptr, uint64_t tx_id) { SCEnter(); @@ -115,8 +116,8 @@ static int LuaTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow * Hooks into the Streaming Logger API. Gets called for each chunk of new * streaming data. */ -static int LuaStreamingLogger(ThreadVars *tv, void *thread_data, const Flow *f, - const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags) +static int LuaStreamingLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, + uint32_t data_len, uint64_t tx_id, uint8_t flags) { SCEnter(); @@ -203,7 +204,7 @@ static int LuaPacketLoggerAlerts(ThreadVars *tv, void *thread_data, const Packet LuaStateSetPacketAlert(td->lua_ctx->luastate, (PacketAlert *)pa); /* prepare data to pass to script */ - //lua_newtable(td->lua_ctx->luastate); + // lua_newtable(td->lua_ctx->luastate); int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0); if (retval != 0) { @@ -337,8 +338,6 @@ static int LuaFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) return 0; } - - static int LuaStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) { SCEnter(); @@ -388,7 +387,6 @@ static int LuaStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *s } SCMutexUnlock(&td->lua_ctx->m); return 0; - } typedef struct LogLuaScriptOptions_ { @@ -413,7 +411,8 @@ typedef struct LogLuaScriptOptions_ { * \param options struct to pass script requirements/options back to caller * \retval errcode 0 ok, -1 error */ -static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { +static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) +{ lua_State *luastate = LuaGetState(); if (luastate == NULL) goto error; @@ -444,7 +443,7 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { } lua_pushliteral(luastate, "script_api_ver"); - lua_pushnumber (luastate, 1); + lua_pushnumber(luastate, 1); lua_settable(luastate, -3); if (lua_pcall(luastate, 1, 1, 0) != 0) { @@ -476,15 +475,15 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { SCLogDebug("k='%s', v='%s'", k, v); - if (strcmp(k,"protocol") == 0 && strcmp(v, "http") == 0) + if (strcmp(k, "protocol") == 0 && strcmp(v, "http") == 0) options->alproto = ALPROTO_HTTP1; - else if (strcmp(k,"protocol") == 0 && strcmp(v, "dns") == 0) + else if (strcmp(k, "protocol") == 0 && strcmp(v, "dns") == 0) options->alproto = ALPROTO_DNS; - else if (strcmp(k,"protocol") == 0 && strcmp(v, "tls") == 0) + else if (strcmp(k, "protocol") == 0 && strcmp(v, "tls") == 0) options->alproto = ALPROTO_TLS; - else if (strcmp(k,"protocol") == 0 && strcmp(v, "ssh") == 0) + else if (strcmp(k, "protocol") == 0 && strcmp(v, "ssh") == 0) options->alproto = ALPROTO_SSH; - else if (strcmp(k,"protocol") == 0 && strcmp(v, "smtp") == 0) + else if (strcmp(k, "protocol") == 0 && strcmp(v, "smtp") == 0) options->alproto = ALPROTO_SMTP; else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0) options->packet = 1; @@ -590,7 +589,8 @@ static lua_State *LuaScriptSetup(const char *filename) return NULL; } -static void LogLuaSubFree(OutputCtx *oc) { +static void LogLuaSubFree(OutputCtx *oc) +{ if (oc->data) SCFree(oc->data); SCFree(oc); @@ -625,7 +625,7 @@ static OutputInitResult OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ct } char path[PATH_MAX] = ""; - int ret = snprintf(path, sizeof(path),"%s%s%s", dir, strlen(dir) ? "/" : "", conf->val); + int ret = snprintf(path, sizeof(path), "%s%s%s", dir, strlen(dir) ? "/" : "", conf->val); if (ret < 0 || ret == sizeof(path)) { SCLogError("failed to construct lua script path"); goto error; @@ -659,7 +659,7 @@ static void LogLuaMasterFree(OutputCtx *oc) SCFree(oc->data); OutputModule *om, *tom; - TAILQ_FOREACH_SAFE(om, &oc->submodules, entries, tom) { + TAILQ_FOREACH_SAFE (om, &oc->submodules, entries, tom) { SCFree(om); } SCFree(oc); @@ -703,13 +703,13 @@ static OutputInitResult OutputLuaLogInit(ConfNode *conf) /* check the enables scripts and set them up as submodules */ ConfNode *script; - TAILQ_FOREACH(script, &scripts->head, next) { + TAILQ_FOREACH (script, &scripts->head, next) { SCLogInfo("enabling script %s", script->val); LogLuaScriptOptions opts; memset(&opts, 0x00, sizeof(opts)); char path[PATH_MAX] = ""; - snprintf(path, sizeof(path),"%s%s%s", dir, strlen(dir) ? "/" : "", script->val); + snprintf(path, sizeof(path), "%s%s%s", dir, strlen(dir) ? "/" : "", script->val); SCLogDebug("script full path %s", path); int r = LuaScriptInit(path, &opts); @@ -825,7 +825,7 @@ static void OutputLuaLogDoDeinit(LogLuaCtx *lua_ctx) SCLogError("no deinit function in script"); return; } - //LuaPrintStack(luastate); + // LuaPrintStack(luastate); if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError("couldn't run script 'deinit' function: %s", lua_tostring(luastate, -1)); @@ -884,14 +884,16 @@ static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void LuaLogRegister(void) { +void LuaLogRegister(void) +{ /* register as separate module */ OutputRegisterModule(MODULE_NAME, "lua", OutputLuaLogInit); } #else /* HAVE_LUA */ -void LuaLogRegister (void) { +void LuaLogRegister(void) +{ /* no-op */ } diff --git a/src/output-lua.h b/src/output/output-lua.h similarity index 100% rename from src/output-lua.h rename to src/output/output-lua.h diff --git a/src/output-packet.c b/src/output/output-packet.c similarity index 92% rename from src/output-packet.c rename to src/output/output-packet.c index 98ccf7b6b081..7d7cf63cdd97 100644 --- a/src/output-packet.c +++ b/src/output/output-packet.c @@ -24,10 +24,10 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-packet.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "output/output.h" +#include "output/output-packet.h" +#include "util/profiling.h" +#include "util/validate.h" /** per thread data for this module, contains a list of per thread * data for the packet loggers. */ @@ -52,11 +52,9 @@ typedef struct OutputPacketLogger_ { static OutputPacketLogger *list = NULL; -int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, - PacketLogger LogFunc, PacketLogCondition ConditionFunc, - OutputCtx *output_ctx, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, PacketLogger LogFunc, + PacketLogCondition ConditionFunc, OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputPacketLogger *op = SCCalloc(1, sizeof(*op)); if (op == NULL) @@ -212,9 +210,8 @@ static uint32_t OutputPacketLoggerGetActiveCount(void) void OutputPacketLoggerRegister(void) { - OutputRegisterRootLogger(OutputPacketLogThreadInit, - OutputPacketLogThreadDeinit, OutputPacketLogExitPrintStats, - OutputPacketLog, OutputPacketLoggerGetActiveCount); + OutputRegisterRootLogger(OutputPacketLogThreadInit, OutputPacketLogThreadDeinit, + OutputPacketLogExitPrintStats, OutputPacketLog, OutputPacketLoggerGetActiveCount); } void OutputPacketShutdown(void) diff --git a/src/output-packet.h b/src/output/output-packet.h similarity index 90% rename from src/output-packet.h rename to src/output/output-packet.h index 1e468669f137..c10cb82de253 100644 --- a/src/output-packet.h +++ b/src/output/output-packet.h @@ -34,9 +34,9 @@ typedef int (*PacketLogger)(ThreadVars *, void *thread_data, const Packet *); */ typedef bool (*PacketLogCondition)(ThreadVars *, void *thread_data, const Packet *); -int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, - PacketLogger LogFunc, PacketLogCondition ConditionFunc, OutputCtx *, - ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); +int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, PacketLogger LogFunc, + PacketLogCondition ConditionFunc, OutputCtx *, ThreadInitFunc, ThreadDeinitFunc, + ThreadExitPrintStatsFunc); void OutputPacketLoggerRegister(void); diff --git a/src/output-stats.c b/src/output/output-stats.c similarity index 95% rename from src/output-stats.c rename to src/output/output-stats.c index b59432bac4a2..72e8d88b88a3 100644 --- a/src/output-stats.c +++ b/src/output/output-stats.c @@ -24,9 +24,9 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-stats.h" -#include "util-validate.h" +#include "output/output.h" +#include "output/output-stats.h" +#include "util/validate.h" /** per thread data for this module, contains a list of per thread * data for the packet loggers. */ @@ -49,10 +49,9 @@ typedef struct OutputStatsLogger_ { static OutputStatsLogger *list = NULL; -int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, - OutputCtx *output_ctx, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx *output_ctx, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputStatsLogger *op = SCCalloc(1, sizeof(*op)); if (op == NULL) @@ -186,7 +185,7 @@ static void OutputStatsLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleStatsLoggerRegister (void) +void TmModuleStatsLoggerRegister(void) { tmm_modules[TMM_STATSLOGGER].name = "__stats_logger__"; tmm_modules[TMM_STATSLOGGER].ThreadInit = OutputStatsLogThreadInit; diff --git a/src/output-stats.h b/src/output/output-stats.h similarity index 76% rename from src/output-stats.h rename to src/output/output-stats.h index f6fc6a8b2716..1c18e5a66d8e 100644 --- a/src/output-stats.h +++ b/src/output/output-stats.h @@ -37,10 +37,10 @@ typedef struct StatsRecord_ { } StatsRecord; typedef struct StatsTable_ { - StatsRecord *stats; /**< array of global stats, indexed by counters gid */ - StatsRecord *tstats; /**< array of arrays with per thread stats */ - uint32_t nstats; /**< size in records of 'stats' */ - uint32_t ntstats; /**< number of threads for which tstats stores stats */ + StatsRecord *stats; /**< array of global stats, indexed by counters gid */ + StatsRecord *tstats; /**< array of arrays with per thread stats */ + uint32_t nstats; /**< size in records of 'stats' */ + uint32_t ntstats; /**< number of threads for which tstats stores stats */ time_t start_time; struct timeval ts; } StatsTable; @@ -49,11 +49,11 @@ TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st); typedef int (*StatsLogger)(ThreadVars *, void *thread_data, const StatsTable *); -int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, - OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats); +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, OutputCtx *, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); -void TmModuleStatsLoggerRegister (void); +void TmModuleStatsLoggerRegister(void); int OutputStatsLoggersRegistered(void); diff --git a/src/output-streaming.c b/src/output/output-streaming.c similarity index 88% rename from src/output-streaming.c rename to src/output/output-streaming.c index 75ee211022f6..e7fb9a1269de 100644 --- a/src/output-streaming.c +++ b/src/output/output-streaming.c @@ -24,18 +24,18 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-streaming.h" +#include "output/output.h" +#include "output/output-streaming.h" #include "app-layer.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" -#include "util-print.h" +#include "app-layer/http/parser.h" +#include "util/print.h" #include "conf.h" -#include "util-profiling.h" +#include "util/profiling.h" #include "stream-tcp.h" #include "stream-tcp-inline.h" #include "stream-tcp-reassemble.h" -#include "util-validate.h" +#include "util/validate.h" /** per thread data for this module, contains a list of per thread * data for the packet loggers. */ @@ -61,11 +61,9 @@ typedef struct OutputStreamingLogger_ { static OutputStreamingLogger *list = NULL; -int OutputRegisterStreamingLogger(LoggerId id, const char *name, - StreamingLogger LogFunc, OutputCtx *output_ctx, - enum OutputStreamingType type, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +int OutputRegisterStreamingLogger(LoggerId id, const char *name, StreamingLogger LogFunc, + OutputCtx *output_ctx, enum OutputStreamingType type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { OutputStreamingLogger *op = SCCalloc(1, sizeof(*op)); if (op == NULL) @@ -105,7 +103,8 @@ typedef struct StreamerCallbackData_ { enum OutputStreamingType type; } StreamerCallbackData; -static int Streamer(void *cbdata, Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags) +static int Streamer(void *cbdata, Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, + uint8_t flags) { StreamerCallbackData *streamer_cbdata = (StreamerCallbackData *)cbdata; DEBUG_VALIDATE_BUG_ON(streamer_cbdata == NULL); @@ -182,7 +181,7 @@ static int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) } SCLogDebug("tx %p", tx); - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); if (htud != NULL) { SCLogDebug("htud %p", htud); HtpBody *body = NULL; @@ -206,7 +205,7 @@ static int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) // for each chunk HtpBodyChunk *chunk = body->first; - for ( ; chunk != NULL; chunk = chunk->next) { + for (; chunk != NULL; chunk = chunk->next) { if (chunk->logged) { SCLogDebug("logged %d", chunk->logged); continue; @@ -227,7 +226,7 @@ static int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) // invoke Streamer Streamer(cbdata, f, data, data_len, tx_id, flags); - //PrintRawDataFp(stdout, data, data_len); + // PrintRawDataFp(stdout, data, data_len); chunk->logged = 1; tx_logged = 1; } @@ -236,9 +235,9 @@ static int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) /* if we need to close we need to invoke the Streamer for sure. If we * logged no chunks, we call the Streamer with NULL data so it can * close up. */ - if (tx_logged == 0 && (close||tx_done)) { + if (tx_logged == 0 && (close || tx_done)) { Streamer(cbdata, f, NULL, 0, tx_id, - iflags|OUTPUT_STREAMING_FLAG_CLOSE|OUTPUT_STREAMING_FLAG_TRANSACTION); + iflags | OUTPUT_STREAMING_FLAG_CLOSE | OUTPUT_STREAMING_FLAG_TRANSACTION); } } } @@ -264,8 +263,8 @@ static int StreamLogFunc( return 0; } -static int TcpDataLogger (Flow *f, TcpSession *ssn, TcpStream *stream, - bool eof, uint8_t iflags, void *streamer_cbdata) +static int TcpDataLogger(Flow *f, TcpSession *ssn, TcpStream *stream, bool eof, uint8_t iflags, + void *streamer_cbdata) { uint8_t flags = iflags; uint64_t progress = STREAM_LOG_PROGRESS(stream); @@ -274,9 +273,7 @@ static int TcpDataLogger (Flow *f, TcpSession *ssn, TcpStream *stream, flags |= OUTPUT_STREAMING_FLAG_OPEN; struct StreamLogData log_data = { flags, streamer_cbdata, f }; - StreamReassembleLog(ssn, stream, - StreamLogFunc, &log_data, - progress, &progress, eof); + StreamReassembleLog(ssn, stream, StreamLogFunc, &log_data, progress, &progress, eof); if (progress > STREAM_LOG_PROGRESS(stream)) { uint32_t slide = progress - STREAM_LOG_PROGRESS(stream); @@ -284,7 +281,7 @@ static int TcpDataLogger (Flow *f, TcpSession *ssn, TcpStream *stream, } if (eof) { - Streamer(streamer_cbdata, f, NULL, 0, 0, flags|OUTPUT_STREAMING_FLAG_CLOSE); + Streamer(streamer_cbdata, f, NULL, 0, 0, flags | OUTPUT_STREAMING_FLAG_CLOSE); } return 0; } @@ -303,14 +300,14 @@ static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data) OutputStreamingLogger *logger = list; OutputLoggerThreadStore *store = op_thread_data->store; - StreamerCallbackData streamer_cbdata = { logger, store, tv, p , 0}; + StreamerCallbackData streamer_cbdata = { logger, store, tv, p, 0 }; DEBUG_VALIDATE_BUG_ON(logger == NULL && store != NULL); DEBUG_VALIDATE_BUG_ON(logger != NULL && store == NULL); DEBUG_VALIDATE_BUG_ON(logger == NULL && store == NULL); uint8_t flags = 0; - Flow * const f = p->flow; + Flow *const f = p->flow; /* no flow, no streaming */ if (f == NULL) { @@ -331,19 +328,20 @@ static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data) } } - if (op_thread_data->loggers & (1<loggers & (1 << STREAMING_TCP_DATA)) { TcpSession *ssn = f->protoctx; if (ssn) { int close = (ssn->state >= TCP_CLOSED); close |= ((p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0); SCLogDebug("close ? %s", close ? "yes" : "no"); - TcpStream *stream = flags & OUTPUT_STREAMING_FLAG_TOSERVER ? &ssn->client : &ssn->server; + TcpStream *stream = + flags & OUTPUT_STREAMING_FLAG_TOSERVER ? &ssn->client : &ssn->server; streamer_cbdata.type = STREAMING_TCP_DATA; TcpDataLogger(f, ssn, stream, close, flags, (void *)&streamer_cbdata); } } - if (op_thread_data->loggers & (1<loggers & (1 << STREAMING_HTTP_BODIES)) { if (f->alproto == ALPROTO_HTTP1 && f->alstate != NULL) { int close = 0; TcpSession *ssn = f->protoctx; @@ -363,7 +361,8 @@ static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data) /** \brief thread init for the tx logger * This will run the thread init functions for the individual registered * loggers */ -static TmEcode OutputStreamingLogThreadInit(ThreadVars *tv, const void *initdata, void **data) { +static TmEcode OutputStreamingLogThreadInit(ThreadVars *tv, const void *initdata, void **data) +{ OutputStreamingLoggerThreadData *td = SCCalloc(1, sizeof(*td)); if (td == NULL) return TM_ECODE_FAILED; @@ -396,7 +395,7 @@ static TmEcode OutputStreamingLogThreadInit(ThreadVars *tv, const void *initdata } } - td->loggers |= (1<type); + td->loggers |= (1 << logger->type); logger = logger->next; } @@ -404,7 +403,8 @@ static TmEcode OutputStreamingLogThreadInit(ThreadVars *tv, const void *initdata return TM_ECODE_OK; } -static TmEcode OutputStreamingLogThreadDeinit(ThreadVars *tv, void *thread_data) { +static TmEcode OutputStreamingLogThreadDeinit(ThreadVars *tv, void *thread_data) +{ OutputStreamingLoggerThreadData *op_thread_data = (OutputStreamingLoggerThreadData *)thread_data; OutputLoggerThreadStore *store = op_thread_data->store; @@ -425,7 +425,8 @@ static TmEcode OutputStreamingLogThreadDeinit(ThreadVars *tv, void *thread_data) return TM_ECODE_OK; } -static void OutputStreamingLogExitPrintStats(ThreadVars *tv, void *thread_data) { +static void OutputStreamingLogExitPrintStats(ThreadVars *tv, void *thread_data) +{ OutputStreamingLoggerThreadData *op_thread_data = (OutputStreamingLoggerThreadData *)thread_data; OutputLoggerThreadStore *store = op_thread_data->store; @@ -450,10 +451,11 @@ static uint32_t OutputStreamingLoggerGetActiveCount(void) return cnt; } -void OutputStreamingLoggerRegister(void) { - OutputRegisterRootLogger(OutputStreamingLogThreadInit, - OutputStreamingLogThreadDeinit, OutputStreamingLogExitPrintStats, - OutputStreamingLog, OutputStreamingLoggerGetActiveCount); +void OutputStreamingLoggerRegister(void) +{ + OutputRegisterRootLogger(OutputStreamingLogThreadInit, OutputStreamingLogThreadDeinit, + OutputStreamingLogExitPrintStats, OutputStreamingLog, + OutputStreamingLoggerGetActiveCount); } void OutputStreamingShutdown(void) diff --git a/src/output/output-streaming.h b/src/output/output-streaming.h new file mode 100644 index 000000000000..348c9784c5bc --- /dev/null +++ b/src/output/output-streaming.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Streaming Logger Output registration functions + */ + +#ifndef __OUTPUT_STREAMING_H__ +#define __OUTPUT_STREAMING_H__ + +#define OUTPUT_STREAMING_FLAG_OPEN 0x01 +#define OUTPUT_STREAMING_FLAG_CLOSE 0x02 +#define OUTPUT_STREAMING_FLAG_TOSERVER 0x04 +#define OUTPUT_STREAMING_FLAG_TOCLIENT 0x08 +#define OUTPUT_STREAMING_FLAG_TRANSACTION 0x10 + +enum OutputStreamingType { + STREAMING_TCP_DATA, + STREAMING_HTTP_BODIES, +}; + +/** streaming logger function pointer type */ +typedef int (*StreamingLogger)(ThreadVars *, void *thread_data, const Flow *f, const uint8_t *data, + uint32_t data_len, uint64_t tx_id, uint8_t flags); + +int OutputRegisterStreamingLogger(LoggerId id, const char *name, StreamingLogger LogFunc, + OutputCtx *, enum OutputStreamingType, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputStreamingLoggerRegister(void); + +void OutputStreamingShutdown(void); + +#endif /* __OUTPUT_STREAMING_H__ */ diff --git a/src/output-tx.c b/src/output/output-tx.c similarity index 95% rename from src/output-tx.c rename to src/output/output-tx.c index cf9a1bd11dae..ed103ea8db66 100644 --- a/src/output-tx.c +++ b/src/output/output-tx.c @@ -24,13 +24,13 @@ */ #include "suricata-common.h" -#include "output.h" -#include "output-tx.h" +#include "output/output.h" +#include "output/output-tx.h" #include "stream.h" #include "app-layer.h" #include "app-layer-parser.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/profiling.h" +#include "util/validate.h" /** per thread data for this module, contains a list of per thread * data for the packet loggers. */ @@ -64,13 +64,10 @@ typedef struct OutputTxLogger_ { static OutputTxLogger *list[ALPROTO_MAX] = { NULL }; -int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, - TxLogger LogFunc, - OutputCtx *output_ctx, int tc_log_progress, - int ts_log_progress, TxLoggerCondition LogCondition, - ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - void (*ThreadExitPrintStats)(ThreadVars *, void *)) +int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, TxLogger LogFunc, + OutputCtx *output_ctx, int tc_log_progress, int ts_log_progress, + TxLoggerCondition LogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + void (*ThreadExitPrintStats)(ThreadVars *, void *)) { if (alproto != ALPROTO_UNKNOWN && !(AppLayerParserIsEnabled(alproto))) { SCLogDebug( @@ -95,8 +92,7 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, op->tc_log_progress = 0; } else if (tc_log_progress < 0) { op->tc_log_progress = - AppLayerParserGetStateProgressCompletionStatus(alproto, - STREAM_TOCLIENT); + AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); } else { op->tc_log_progress = tc_log_progress; } @@ -105,8 +101,7 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, op->ts_log_progress = 0; } else if (ts_log_progress < 0) { op->ts_log_progress = - AppLayerParserGetStateProgressCompletionStatus(alproto, - STREAM_TOSERVER); + AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); } else { op->ts_log_progress = ts_log_progress; } @@ -253,7 +248,7 @@ static void OutputTxLogList0(ThreadVars *tv, OutputTxLoggerThreadData *op_thread SCLogDebug("logger %p", logger); /* always invoke "wild card" tx loggers */ - SCLogDebug("Logging tx_id %"PRIu64" to logger %d", tx_id, logger->logger_id); + SCLogDebug("Logging tx_id %" PRIu64 " to logger %d", tx_id, logger->logger_id); PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, p, f, f->alstate, tx, tx_id); PACKET_PROFILING_LOGGER_END(p, logger->logger_id); @@ -345,7 +340,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) OutputTxLoggerThreadData *op_thread_data = (OutputTxLoggerThreadData *)thread_data; - Flow * const f = p->flow; + Flow *const f = p->flow; const uint8_t ipproto = f->proto; const AppProto alproto = f->alproto; SCLogDebug("pcap_cnt %u tx logging %u/%s", (uint32_t)p->pcap_cnt, alproto, @@ -409,7 +404,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, tx_id, total_txs, &state); if (ires.tx_ptr == NULL) break; - void * const tx = ires.tx_ptr; + void *const tx = ires.tx_ptr; tx_id = ires.tx_id; SCLogDebug("STARTING tx_id %" PRIu64 ", tx %p", tx_id, tx); @@ -475,7 +470,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) SCLogDebug("tx %p/%" PRIu64 " txd %p: log_flags %x logger_expectation %x", tx, tx_id, txd, txd->config.log_flags, logger_expectation); if (txd->config.log_flags & BIT_U8(CONFIG_TYPE_TX)) { - SCLogDebug("SKIP tx %p/%"PRIu64, tx, tx_id); + SCLogDebug("SKIP tx %p/%" PRIu64, tx, tx_id); // so that AppLayerParserTransactionsCleanup can clean this tx txd->logged.flags |= logger_expectation; goto next_tx; @@ -517,7 +512,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) } else { gap = 1; } -next_tx: + next_tx: if (!ires.has_next) break; tx_id++; @@ -526,7 +521,7 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) /* Update the last ID that has been logged with all * transactions before it. */ if (logged) { - SCLogDebug("updating log tx_id %"PRIu64, max_id); + SCLogDebug("updating log tx_id %" PRIu64, max_id); AppLayerParserSetTransactionLogId(f->alparser, max_id + 1); } @@ -662,11 +657,10 @@ static uint32_t OutputTxLoggerGetActiveCount(void) return cnt; } - -void OutputTxLoggerRegister (void) +void OutputTxLoggerRegister(void) { OutputRegisterRootLogger(OutputTxLogThreadInit, OutputTxLogThreadDeinit, - OutputTxLogExitPrintStats, OutputTxLog, OutputTxLoggerGetActiveCount); + OutputTxLogExitPrintStats, OutputTxLog, OutputTxLoggerGetActiveCount); } void OutputTxShutdown(void) diff --git a/src/output-tx.h b/src/output/output-tx.h similarity index 80% rename from src/output-tx.h rename to src/output/output-tx.h index 88c12ff25f68..239ba484f35a 100644 --- a/src/output-tx.h +++ b/src/output/output-tx.h @@ -30,7 +30,8 @@ #include "flow.h" /** tx logger function pointer type */ -typedef int (*TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f, void *state, void *tx, uint64_t tx_id); +typedef int (*TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f, void *state, + void *tx, uint64_t tx_id); /** tx logger condition function pointer type, * must return true for tx that should be logged @@ -38,14 +39,11 @@ typedef int (*TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f typedef bool (*TxLoggerCondition)( ThreadVars *, const Packet *, void *state, void *tx, uint64_t tx_id); -int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, - TxLogger LogFunc, - OutputCtx *, int tc_log_progress, int ts_log_progress, - TxLoggerCondition LogCondition, - ThreadInitFunc, ThreadDeinitFunc, - void (*ThreadExitPrintStats)(ThreadVars *, void *)); +int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, TxLogger LogFunc, + OutputCtx *, int tc_log_progress, int ts_log_progress, TxLoggerCondition LogCondition, + ThreadInitFunc, ThreadDeinitFunc, void (*ThreadExitPrintStats)(ThreadVars *, void *)); -void OutputTxLoggerRegister (void); +void OutputTxLoggerRegister(void); void OutputTxShutdown(void); diff --git a/src/output.c b/src/output/output.c similarity index 77% rename from src/output.c rename to src/output/output.c index 149dda58c284..272da910cc27 100644 --- a/src/output.c +++ b/src/output/output.c @@ -36,60 +36,60 @@ #include "flow.h" #include "conf.h" #include "tm-threads.h" -#include "util-error.h" -#include "util-debug.h" -#include "output.h" +#include "util/error.h" +#include "util/debug.h" +#include "output/output.h" #include "alert-fastlog.h" #include "alert-debuglog.h" #include "alert-syslog.h" -#include "output-json.h" -#include "output-json-alert.h" -#include "output-json-anomaly.h" -#include "output-json-flow.h" -#include "output-json-netflow.h" +#include "output/eve/output-json.h" +#include "output/eve/output-json-alert.h" +#include "output/eve/output-json-anomaly.h" +#include "output/eve/output-json-flow.h" +#include "output/eve/output-json-netflow.h" #include "log-cf-common.h" -#include "output-json-drop.h" -#include "output-eve-stream.h" -#include "log-httplog.h" -#include "output-json-http.h" -#include "output-json-dns.h" -#include "output-json-modbus.h" -#include "log-tlslog.h" -#include "log-tlsstore.h" -#include "output-json-tls.h" -#include "output-json-ssh.h" +#include "output/eve/output-json-drop.h" +#include "output/eve/output-eve-stream.h" +#include "app-layer/http/log-httplog.h" +#include "app-layer/http/logger.h" +#include "app-layer/dns/logger.h" +#include "app-layer/modbus/logger.h" +#include "app-layer/tls/log-tlslog.h" +#include "app-layer/tls/log-tlsstore.h" +#include "app-layer/tls/logger.h" +#include "app-layer/ssh/logger.h" #include "log-pcap.h" -#include "output-json-file.h" -#include "output-json-smtp.h" -#include "output-json-stats.h" +#include "output/eve/output-json-file.h" +#include "app-layer/smtp/logger.h" +#include "output/eve/output-json-stats.h" #include "log-tcp-data.h" #include "log-stats.h" -#include "output-json-nfs.h" -#include "output-json-ftp.h" +#include "app-layer/nfs/logger.h" +#include "app-layer/ftp/logger.h" // for misplaced EveFTPDataAddMetadata -#include "app-layer-ftp.h" -#include "output-json-tftp.h" -#include "output-json-smb.h" -#include "output-json-ike.h" -#include "output-json-krb5.h" -#include "output-json-quic.h" -#include "output-json-dhcp.h" -#include "output-json-snmp.h" -#include "output-json-sip.h" -#include "output-json-rfb.h" -#include "output-json-mqtt.h" -#include "output-json-pgsql.h" -#include "output-json-template.h" -#include "output-json-rdp.h" -#include "output-json-http2.h" -#include "output-lua.h" -#include "output-json-dnp3.h" -#include "output-json-metadata.h" -#include "output-json-dcerpc.h" -#include "output-json-frame.h" -#include "output-json-bittorrent-dht.h" -#include "output-filestore.h" +#include "app-layer/ftp/parser.h" +#include "app-layer/tftp/logger.h" +#include "app-layer/smb/logger.h" +#include "app-layer/ike/logger.h" +#include "app-layer/krb5/logger.h" +#include "app-layer/quic/logger.h" +#include "app-layer/dhcp/logger.h" +#include "app-layer/snmp/logger.h" +#include "app-layer/sip/logger.h" +#include "app-layer/rfb/logger.h" +#include "app-layer/mqtt/logger.h" +#include "app-layer/pgsql/logger.h" +#include "app-layer/template/logger.h" +#include "app-layer/rdp/logger.h" +#include "app-layer/http2/logger.h" +#include "output/output-lua.h" +#include "app-layer/dnp3/logger.h" +#include "output/eve/output-json-metadata.h" +#include "app-layer/dcerpc/logger.h" +#include "output/eve/output-json-frame.h" +#include "app-layer/bittorrent-dht/logger.h" +#include "output/output-filestore.h" typedef struct RootLogger_ { OutputLogFunc LogFunc; @@ -104,13 +104,11 @@ typedef struct RootLogger_ { /* List of registered root loggers. These are registered at start up and * are independent of configuration. Later we will build a list of active * loggers based on configuration. */ -static TAILQ_HEAD(, RootLogger_) registered_loggers = - TAILQ_HEAD_INITIALIZER(registered_loggers); +static TAILQ_HEAD(, RootLogger_) registered_loggers = TAILQ_HEAD_INITIALIZER(registered_loggers); /* List of active root loggers. This means that at least one logger is enabled * for each root logger type in the config. */ -static TAILQ_HEAD(, RootLogger_) active_loggers = - TAILQ_HEAD_INITIALIZER(active_loggers); +static TAILQ_HEAD(, RootLogger_) active_loggers = TAILQ_HEAD_INITIALIZER(active_loggers); typedef struct LoggerThreadStoreNode_ { void *thread_data; @@ -133,8 +131,8 @@ typedef struct OutputFileRolloverFlag_ { TAILQ_ENTRY(OutputFileRolloverFlag_) entries; } OutputFileRolloverFlag; -TAILQ_HEAD(, OutputFileRolloverFlag_) output_file_rotation_flags = - TAILQ_HEAD_INITIALIZER(output_file_rotation_flags); +TAILQ_HEAD(, OutputFileRolloverFlag_) +output_file_rotation_flags = TAILQ_HEAD_INITIALIZER(output_file_rotation_flags); void OutputRegisterRootLoggers(void); void OutputRegisterLoggers(void); @@ -147,8 +145,7 @@ void OutputRegisterLoggers(void); * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterModule(const char *name, const char *conf_name, - OutputInitFunc InitFunc) +void OutputRegisterModule(const char *name, const char *conf_name, OutputInitFunc InitFunc) { OutputModule *module = SCCalloc(1, sizeof(*module)); if (unlikely(module == NULL)) @@ -175,11 +172,10 @@ void OutputRegisterModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterPacketModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, - PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterPacketModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(PacketLogFunc == NULL || PacketConditionFunc == NULL)) { goto error; @@ -215,11 +211,10 @@ void OutputRegisterPacketModule(LoggerId id, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, PacketLogger PacketLogFunc, + PacketLogCondition PacketConditionFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(PacketLogFunc == NULL || PacketConditionFunc == NULL)) { goto error; @@ -256,12 +251,10 @@ void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -static void OutputRegisterTxModuleWrapper(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, - TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +static void OutputRegisterTxModuleWrapper(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -292,12 +285,11 @@ static void OutputRegisterTxModuleWrapper(LoggerId id, const char *name, FatalError("Fatal error encountered. Exiting..."); } -static void OutputRegisterTxSubModuleWrapper(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, - int ts_log_progress, TxLoggerCondition TxLogCondition, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +static void OutputRegisterTxSubModuleWrapper(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -337,27 +329,22 @@ static void OutputRegisterTxSubModuleWrapper(LoggerId id, const char *parent_nam * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, - TxLogFunc, -1, -1, TxLogCondition, ThreadInit, ThreadDeinit, - ThreadExitPrintStats); + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, TxLogFunc, -1, -1, + TxLogCondition, ThreadInit, ThreadDeinit, ThreadExitPrintStats); } -void OutputRegisterTxSubModuleWithCondition(LoggerId id, - const char *parent_name, const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, - TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterTxSubModuleWithCondition(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, - alproto, TxLogFunc, -1, -1, TxLogCondition, ThreadInit, ThreadDeinit, - ThreadExitPrintStats); + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, alproto, TxLogFunc, + -1, -1, TxLogCondition, ThreadInit, ThreadDeinit, ThreadExitPrintStats); } /** @@ -368,27 +355,22 @@ void OutputRegisterTxSubModuleWithCondition(LoggerId id, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, - TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, - ThreadDeinit, ThreadExitPrintStats); + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, TxLogFunc, + tc_log_progress, ts_log_progress, NULL, ThreadInit, ThreadDeinit, ThreadExitPrintStats); } -void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, - int ts_log_progress, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, - alproto, TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, - ThreadDeinit, ThreadExitPrintStats); + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, alproto, TxLogFunc, + tc_log_progress, ts_log_progress, NULL, ThreadInit, ThreadDeinit, ThreadExitPrintStats); } /** @@ -399,26 +381,21 @@ void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterTxModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, - TxLogger TxLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterTxModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, - TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, - ThreadExitPrintStats); + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, TxLogFunc, -1, -1, NULL, + ThreadInit, ThreadDeinit, ThreadExitPrintStats); } -void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, - OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, - InitFunc, alproto, TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, - ThreadExitPrintStats); + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, alproto, TxLogFunc, + -1, -1, NULL, ThreadInit, ThreadDeinit, ThreadExitPrintStats); } /** @@ -429,10 +406,9 @@ void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterFileModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, FileLogger FileLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterFileModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, FileLogger FileLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FileLogFunc == NULL)) { goto error; @@ -467,11 +443,10 @@ void OutputRegisterFileModule(LoggerId id, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - FileLogger FileLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, FileLogger FileLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FileLogFunc == NULL)) { goto error; @@ -507,11 +482,9 @@ void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterFiledataModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, - FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterFiledataModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FiledataLogFunc == NULL)) { goto error; @@ -546,11 +519,10 @@ void OutputRegisterFiledataModule(LoggerId id, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, FiledataLogger FiledataLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FiledataLogFunc == NULL)) { goto error; @@ -586,11 +558,10 @@ void OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, FlowLogger FlowLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FlowLogFunc == NULL)) { goto error; @@ -626,12 +597,10 @@ void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterStreamingModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, - StreamingLogger StreamingLogFunc, - enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterStreamingModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, StreamingLogger StreamingLogFunc, + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StreamingLogFunc == NULL)) { goto error; @@ -667,11 +636,10 @@ void OutputRegisterStreamingModule(LoggerId id, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, StreamingLogger StreamingLogFunc, + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StreamingLogFunc == NULL)) { goto error; @@ -708,10 +676,9 @@ void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterStatsModule(LoggerId id, const char *name, - const char *conf_name, OutputInitFunc InitFunc, StatsLogger StatsLogFunc, - ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterStatsModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StatsLogFunc == NULL)) { goto error; @@ -746,11 +713,10 @@ void OutputRegisterStatsModule(LoggerId id, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, - const char *name, const char *conf_name, OutputInitSubFunc InitFunc, - StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats) +void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, StatsLogger StatsLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StatsLogFunc == NULL)) { goto error; @@ -788,7 +754,7 @@ OutputModule *OutputGetModuleByConfName(const char *conf_name) { OutputModule *module; - TAILQ_FOREACH(module, &output_modules, entries) { + TAILQ_FOREACH (module, &output_modules, entries) { if (strcmp(module->conf_name, conf_name) == 0) return module; } @@ -855,8 +821,7 @@ void OutputRegisterFileRotationFlag(int *flag) void OutputUnregisterFileRotationFlag(int *flag) { OutputFileRolloverFlag *entry, *next; - for (entry = TAILQ_FIRST(&output_file_rotation_flags); entry != NULL; - entry = next) { + for (entry = TAILQ_FIRST(&output_file_rotation_flags); entry != NULL; entry = next) { next = TAILQ_NEXT(entry, entries); if (entry->flag == flag) { TAILQ_REMOVE(&output_file_rotation_flags, entry, entries); @@ -869,9 +834,10 @@ void OutputUnregisterFileRotationFlag(int *flag) /** * \brief Notifies all registered file rotation notification flags. */ -void OutputNotifyFileRotation(void) { +void OutputNotifyFileRotation(void) +{ OutputFileRolloverFlag *flag; - TAILQ_FOREACH(flag, &output_file_rotation_flags, entries) { + TAILQ_FOREACH (flag, &output_file_rotation_flags, entries) { *(flag->flag) = 1; } } @@ -900,13 +866,12 @@ TmEcode OutputLoggerThreadInit(ThreadVars *tv, const void *initdata, void **data *data = (void *)thread_store; RootLogger *logger; - TAILQ_FOREACH(logger, &active_loggers, entries) { + TAILQ_FOREACH (logger, &active_loggers, entries) { void *child_thread_data = NULL; if (logger->ThreadInit != NULL) { if (logger->ThreadInit(tv, initdata, &child_thread_data) == TM_ECODE_OK) { - LoggerThreadStoreNode *thread_store_node = - SCCalloc(1, sizeof(*thread_store_node)); + LoggerThreadStoreNode *thread_store_node = SCCalloc(1, sizeof(*thread_store_node)); if (thread_store_node == NULL) { /* Undo everything, calling de-init will take care * of that. */ @@ -961,10 +926,9 @@ void OutputLoggerExitPrintStats(ThreadVars *tv, void *thread_data) } } -void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, - ThreadDeinitFunc ThreadDeinit, - ThreadExitPrintStatsFunc ThreadExitPrintStats, - OutputLogFunc LogFunc, OutputGetActiveCountFunc ActiveCntFunc) +void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats, OutputLogFunc LogFunc, + OutputGetActiveCountFunc ActiveCntFunc) { BUG_ON(LogFunc == NULL); diff --git a/src/output/output.h b/src/output/output.h new file mode 100644 index 000000000000..e4f06a20d91c --- /dev/null +++ b/src/output/output.h @@ -0,0 +1,194 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited, Jason Ish + */ + +#ifndef __OUTPUT_H__ +#define __OUTPUT_H__ + +#include "decode.h" +#include "tm-modules.h" + +#define DEFAULT_LOG_MODE_APPEND "yes" +#define DEFAULT_LOG_FILETYPE "regular" + +typedef struct OutputLoggerThreadStore_ { + void *thread_data; + struct OutputLoggerThreadStore_ *next; +} OutputLoggerThreadStore; + +#include "output/output-packet.h" +#include "output/output-tx.h" +#include "output/output-file.h" +#include "output/output-filedata.h" +#include "output/output-flow.h" +#include "output/output-streaming.h" +#include "output/output-stats.h" + +typedef struct OutputInitResult_ { + OutputCtx *ctx; + bool ok; +} OutputInitResult; + +typedef OutputInitResult (*OutputInitFunc)(ConfNode *); +typedef OutputInitResult (*OutputInitSubFunc)(ConfNode *, OutputCtx *); +typedef TmEcode (*OutputLogFunc)(ThreadVars *, Packet *, void *); +typedef uint32_t (*OutputGetActiveCountFunc)(void); + +typedef struct OutputModule_ { + LoggerId logger_id; + const char *name; + const char *conf_name; + const char *parent_name; + OutputInitFunc InitFunc; + OutputInitSubFunc InitSubFunc; + + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; + + PacketLogger PacketLogFunc; + PacketLogCondition PacketConditionFunc; + TxLogger TxLogFunc; + TxLoggerCondition TxLogCondition; + FileLogger FileLogFunc; + FiledataLogger FiledataLogFunc; + FlowLogger FlowLogFunc; + StreamingLogger StreamingLogFunc; + StatsLogger StatsLogFunc; + AppProto alproto; + enum OutputStreamingType stream_type; + int tc_log_progress; + int ts_log_progress; + + TAILQ_ENTRY(OutputModule_) entries; +} OutputModule; + +typedef TAILQ_HEAD(OutputModuleList_, OutputModule_) OutputModuleList; +extern OutputModuleList output_modules; + +void OutputRegisterModule(const char *, const char *, OutputInitFunc); + +void OutputRegisterPacketModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, PacketLogger LogFunc, PacketLogCondition ConditionFunc, + ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); +void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, PacketLogger LogFunc, + PacketLogCondition ConditionFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterTxModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterTxSubModuleWithCondition(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterFileModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, FileLogger FileLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, FileLogger FileLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterFiledataModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterFiledataSubModule(LoggerId, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, FiledataLogger FiledataLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, FlowLogger FlowLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterStreamingModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, StreamingLogger StreamingLogFunc, + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, StreamingLogger StreamingLogFunc, + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterStatsModule(LoggerId id, const char *name, const char *conf_name, + OutputInitFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, const char *name, + const char *conf_name, OutputInitSubFunc InitFunc, StatsLogger StatsLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +OutputModule *OutputGetModuleByConfName(const char *name); +void OutputDeregisterAll(void); + +int OutputDropLoggerEnable(void); +void OutputDropLoggerDisable(void); + +void OutputRegisterFileRotationFlag(int *flag); +void OutputUnregisterFileRotationFlag(int *flag); +void OutputNotifyFileRotation(void); + +void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats, OutputLogFunc LogFunc, + OutputGetActiveCountFunc ActiveCntFunc); +void TmModuleLoggerRegister(void); + +TmEcode OutputLoggerLog(ThreadVars *, Packet *, void *); +TmEcode OutputLoggerThreadInit(ThreadVars *, const void *, void **); +TmEcode OutputLoggerThreadDeinit(ThreadVars *, void *); +void OutputLoggerExitPrintStats(ThreadVars *, void *); + +void OutputSetupActiveLoggers(void); +void OutputClearActiveLoggers(void); + +typedef bool (*EveJsonSimpleTxLogFunc)(void *, struct JsonBuilder *); + +typedef struct EveJsonSimpleAppLayerLogger { + AppProto proto; + EveJsonSimpleTxLogFunc LogTx; +} EveJsonSimpleAppLayerLogger; + +EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto); + +#endif /* ! __OUTPUT_H__ */ diff --git a/src/packet-queue.c b/src/packet-queue.c index 81c7798ef708..e1909a6c4cf4 100644 --- a/src/packet-queue.c +++ b/src/packet-queue.c @@ -28,9 +28,9 @@ #include "packet-queue.h" #include "threads.h" #include "suricata.h" -#include "util-var.h" +#include "util/var.h" #include "pkt-var.h" -#include "util-validate.h" +#include "util/validate.h" #ifdef DEBUG void PacketQueueValidateDebug(PacketQueue *q); @@ -43,7 +43,7 @@ void PacketQueueValidateDebug(PacketQueue *q) if (q->len == 0) { BUG_ON(q->top != NULL); BUG_ON(q->bot != NULL); - } else if(q->len == 1) { + } else if (q->len == 1) { SCLogDebug("q->top->next %p, q->top->prev %p", q->top->next, q->top->prev); SCLogDebug("q->bot->next %p, q->bot->prev %p", q->bot->next, q->bot->prev); @@ -85,22 +85,22 @@ void PacketQueueValidateDebug(PacketQueue *q) SCLogDebug("p %p, pp %p, p->next %p, p->prev %p", p, pp, p->next, p->prev); BUG_ON(pp != p->prev); } - } } -#define BUGGER_ON(cond) { \ - if ((cond)) { \ - PacketQueueValidateDebug(q); \ - } \ -} +#define BUGGER_ON(cond) \ + { \ + if ((cond)) { \ + PacketQueueValidateDebug(q); \ + } \ + } void PacketQueueValidate(PacketQueue *q) { if (q->len == 0) { BUGGER_ON(q->top != NULL); BUGGER_ON(q->bot != NULL); - } else if(q->len == 1) { + } else if (q->len == 1) { BUGGER_ON(q->top != q->bot); BUGGER_ON(q->top->next != NULL); BUGGER_ON(q->bot->next != NULL); @@ -132,14 +132,13 @@ void PacketQueueValidate(PacketQueue *q) for (p = q->top, pp = p->prev; p != NULL; pp = p, p = p->next) { BUGGER_ON(pp != p->prev); } - } } #endif /* DEBUG */ static inline void PacketEnqueueDo(PacketQueue *q, Packet *p) { - //PacketQueueValidateDebug(q); + // PacketQueueValidateDebug(q); if (p == NULL) return; @@ -150,7 +149,7 @@ static inline void PacketEnqueueDo(PacketQueue *q, Packet *p) p->next = q->top; q->top->prev = p; q->top = p; - /* only packet */ + /* only packet */ } else { p->prev = NULL; p->next = NULL; @@ -162,7 +161,7 @@ static inline void PacketEnqueueDo(PacketQueue *q, Packet *p) if (q->len > q->dbg_maxlen) q->dbg_maxlen = q->len; #endif /* DBG_PERF */ - //PacketQueueValidateDebug(q); + // PacketQueueValidateDebug(q); } void PacketEnqueueNoLock(PacketQueueNoLock *qnl, Packet *p) @@ -172,14 +171,14 @@ void PacketEnqueueNoLock(PacketQueueNoLock *qnl, Packet *p) PacketEnqueueDo(q, p); } -void PacketEnqueue (PacketQueue *q, Packet *p) +void PacketEnqueue(PacketQueue *q, Packet *p) { PacketEnqueueDo(q, p); } -static inline Packet *PacketDequeueDo (PacketQueue *q) +static inline Packet *PacketDequeueDo(PacketQueue *q) { - //PacketQueueValidateDebug(q); + // PacketQueueValidateDebug(q); /* if the queue is empty there are no packets left. */ if (q->len == 0) { return NULL; @@ -199,13 +198,13 @@ static inline Packet *PacketDequeueDo (PacketQueue *q) q->bot = NULL; } - //PacketQueueValidateDebug(q); + // PacketQueueValidateDebug(q); p->next = NULL; p->prev = NULL; return p; } -Packet *PacketDequeueNoLock (PacketQueueNoLock *qnl) +Packet *PacketDequeueNoLock(PacketQueueNoLock *qnl) { PacketQueue *q = (PacketQueue *)qnl; Packet *p = PacketDequeueDo(q); @@ -213,7 +212,7 @@ Packet *PacketDequeueNoLock (PacketQueueNoLock *qnl) return p; } -Packet *PacketDequeue (PacketQueue *q) +Packet *PacketDequeue(PacketQueue *q) { return PacketDequeueDo(q); } diff --git a/src/packet-queue.h b/src/packet-queue.h index 408987064380..a11659e792bb 100644 --- a/src/packet-queue.h +++ b/src/packet-queue.h @@ -57,15 +57,13 @@ typedef struct PacketQueue_ { SCCondT cond_q; } PacketQueue; - void PacketEnqueueNoLock(PacketQueueNoLock *qnl, struct Packet_ *p); -void PacketEnqueue (PacketQueue *, struct Packet_ *); +void PacketEnqueue(PacketQueue *, struct Packet_ *); -struct Packet_ *PacketDequeueNoLock (PacketQueueNoLock *qnl); -struct Packet_ *PacketDequeue (PacketQueue *); +struct Packet_ *PacketDequeueNoLock(PacketQueueNoLock *qnl); +struct Packet_ *PacketDequeue(PacketQueue *); PacketQueue *PacketQueueAlloc(void); void PacketQueueFree(PacketQueue *); #endif /* __PACKET_QUEUE_H__ */ - diff --git a/src/packet.c b/src/packet.c index 40f3bdfcf385..7bf05ba320a2 100644 --- a/src/packet.c +++ b/src/packet.c @@ -19,8 +19,8 @@ #include "pkt-var.h" #include "flow.h" #include "host.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/profiling.h" +#include "util/validate.h" #include "action-globals.h" /** \brief issue drop action diff --git a/src/pkt-var.c b/src/pkt-var.c index a81af35e1af2..73b714ef4164 100644 --- a/src/pkt-var.c +++ b/src/pkt-var.c @@ -32,7 +32,7 @@ #include "suricata-common.h" #include "decode.h" #include "pkt-var.h" -#include "util-debug.h" +#include "util/debug.h" /* get the pktvar with name 'name' from the pkt * @@ -41,7 +41,7 @@ PktVar *PktVarGet(Packet *p, uint32_t id) { PktVar *pv = p->pktvar; - for (;pv != NULL; pv = pv->next) { + for (; pv != NULL; pv = pv->next) { if (pv->id == id) return pv; } @@ -68,7 +68,7 @@ int PktVarAddKeyValue(Packet *p, uint8_t *key, uint16_t ksize, uint8_t *value, u if (p->pktvar == NULL) p->pktvar = pv; else { - while(tpv) { + while (tpv) { if (tpv->next == NULL) { tpv->next = pv; return 0; @@ -97,7 +97,7 @@ int PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size) if (p->pktvar == NULL) p->pktvar = pv; else { - while(tpv) { + while (tpv) { if (tpv->next == NULL) { tpv->next = pv; return 0; diff --git a/src/pkt-var.h b/src/pkt-var.h index 0a261c9ffaaf..ea4ec672d51f 100644 --- a/src/pkt-var.h +++ b/src/pkt-var.h @@ -30,4 +30,3 @@ PktVar *PktVarGet(Packet *, uint32_t id); void PktVarFree(PktVar *); #endif /* __PKT_VAR_H__ */ - diff --git a/src/reputation.c b/src/reputation.c index 17f43ca37178..cd24548ae7cb 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -31,14 +31,14 @@ #include "threads.h" #include "conf.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-error.h" -#include "util-ip.h" -#include "util-path.h" -#include "util-print.h" -#include "util-unittest.h" -#include "util-validate.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/error.h" +#include "util/ip.h" +#include "util/path.h" +#include "util/print.h" +#include "util/unittest.h" +#include "util/validate.h" /** effective reputation version, atomic as the host * time out code will use it to check if a host's @@ -173,7 +173,7 @@ uint8_t SRepCIDRGetIPRepDst(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint * a rule/reputation reload is complete. */ void SRepReloadComplete(void) { - (void) SC_ATOMIC_ADD(srep_eversion, 1); + (void)SC_ATOMIC_ADD(srep_eversion, 1); SCLogDebug("effective Reputation version %u", SRepGetEffectiveVersion()); } @@ -189,7 +189,7 @@ void SRepFreeHostData(Host *h) * reputation initialization is complete. */ static void SRepInitComplete(void) { - (void) SC_ATOMIC_SET(srep_eversion, 1); + (void)SC_ATOMIC_SET(srep_eversion, 1); SCLogDebug("effective Reputation version %u", SRepGetEffectiveVersion()); } @@ -214,7 +214,8 @@ int SRepHostTimedOut(Host *h) SReputation *r = h->iprep; if (r->version < eversion) { SCLogDebug("host %p has reputation version %u, " - "effective version is %u", h, r->version, eversion); + "effective version is %u", + h, r->version, eversion); SRepFreeHostData(h); return 1; } @@ -225,7 +226,7 @@ int SRepHostTimedOut(Host *h) static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t shortname_len) { size_t line_len = strlen(line); - char *ptrs[2] = {NULL,NULL}; + char *ptrs[2] = { NULL, NULL }; int i = 0; int idx = 0; char *origline = line; @@ -237,7 +238,7 @@ static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t sh ptrs[idx] = line; idx++; - line += (i+1); + line += (i + 1); i = 0; if (line >= origline + line_len) @@ -264,7 +265,6 @@ static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t sh *cat = (uint8_t)c; strlcpy(shortname, ptrs[1], shortname_len); return 0; - } /** @@ -272,10 +272,11 @@ static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t sh * \retval 1 header * \retval -1 bad line */ -static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, Address *ip, uint8_t *cat, uint8_t *value) +static int SRepSplitLine( + SRepCIDRTree *cidr_ctx, char *line, Address *ip, uint8_t *cat, uint8_t *value) { size_t line_len = strlen(line); - char *ptrs[3] = {NULL,NULL,NULL}; + char *ptrs[3] = { NULL, NULL, NULL }; int i = 0; int idx = 0; char *origline = line; @@ -288,7 +289,7 @@ static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, Address *ip, uint8_ ptrs[idx] = line; idx++; - line += (i+1); + line += (i + 1); i = 0; if (line >= origline + line_len) @@ -306,7 +307,7 @@ static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, Address *ip, uint8_ return -1; } - //SCLogInfo("%s, %s, %s", ptrs[0], ptrs[1], ptrs[2]); + // SCLogInfo("%s, %s, %s", ptrs[0], ptrs[1], ptrs[2]); if (strcmp(ptrs[0], "ip") == 0) return 1; @@ -378,16 +379,18 @@ int SRepLoadCatFileFromFD(FILE *fp) BUG_ON(SRepGetVersion() > 0); - while(fgets(line, (int)sizeof(line), fp) != NULL) { + while (fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) continue; /* ignore comments and empty lines */ - if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') + if (line[0] == '\n' || line[0] == '\r' || line[0] == ' ' || line[0] == '#' || + line[0] == '\t') continue; - while (isspace((unsigned char)line[--len])); + while (isspace((unsigned char)line[--len])) + ; /* Check if we have a trailing newline, and remove it */ len = strlen(line); @@ -432,23 +435,24 @@ static int SRepLoadFile(SRepCIDRTree *cidr_ctx, char *filename) fclose(fp); fp = NULL; return r; - } int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) { char line[8192] = ""; - while(fgets(line, (int)sizeof(line), fp) != NULL) { + while (fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) continue; /* ignore comments and empty lines */ - if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') + if (line[0] == '\n' || line[0] == '\r' || line[0] == ' ' || line[0] == '#' || + line[0] == '\t') continue; - while (isspace((unsigned char)line[--len])); + while (isspace((unsigned char)line[--len])) + ; /* Check if we have a trailing newline, and remove it */ len = strlen(line); @@ -483,7 +487,7 @@ int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) SCLogError("failed to get a host, increase host.memcap"); break; } else { - //SCLogInfo("host %p", h); + // SCLogInfo("host %p", h); if (h->iprep == NULL) { h->iprep = SCCalloc(1, sizeof(SReputation)); @@ -503,8 +507,8 @@ int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) rep->version = SRepGetVersion(); rep->rep[cat] = value; - SCLogDebug("host %p iprep %p setting cat %u to value %u", - h, h->iprep, cat, value); + SCLogDebug( + "host %p iprep %p setting cat %u to value %u", h, h->iprep, cat, value); #ifdef DEBUG if (SCLogDebugEnabled()) { int i; @@ -512,8 +516,8 @@ int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) if (rep->rep[i] == 0) continue; - SCLogDebug("--> host %p iprep %p cat %d to value %u", - h, h->iprep, i, rep->rep[i]); + SCLogDebug("--> host %p iprep %p cat %d to value %u", h, h->iprep, i, + rep->rep[i]); } } #endif @@ -541,8 +545,7 @@ static char *SRepCompleteFilePath(char *file) if (PathIsRelative(file)) { if (ConfGet("default-reputation-path", &defaultpath) == 1) { SCLogDebug("Default path: %s", defaultpath); - size_t path_len = sizeof(char) * (strlen(defaultpath) + - strlen(file) + 2); + size_t path_len = sizeof(char) * (strlen(defaultpath) + strlen(file) + 2); path = SCMalloc(path_len); if (unlikely(path == NULL)) return NULL; @@ -635,13 +638,13 @@ int SRepInit(DetectEngineCtx *de_ctx) /* ok, let's load reputation files from the general config */ if (files != NULL) { - TAILQ_FOREACH(file, &files->head, next) { + TAILQ_FOREACH (file, &files->head, next) { char *sfile = SRepCompleteFilePath(file->val); if (sfile) { SCLogInfo("Loading reputation file: %s", sfile); int r = SRepLoadFile(cidr_ctx, sfile); - if (r < 0){ + if (r < 0) { if (de_ctx->failure_fatal) { exit(EXIT_FAILURE); } @@ -661,7 +664,8 @@ int SRepInit(DetectEngineCtx *de_ctx) return 0; } -void SRepDestroy(DetectEngineCtx *de_ctx) { +void SRepDestroy(DetectEngineCtx *de_ctx) +{ if (de_ctx->srepCIDR_ctx != NULL) { int i; for (i = 0; i < SREP_MAX_CATS; i++) { diff --git a/src/reputation.h b/src/reputation.h index 3ed94d985159..257c1ca96d1b 100644 --- a/src/reputation.h +++ b/src/reputation.h @@ -27,10 +27,10 @@ #define __REPUTATION_H__ #include "host.h" -#include "util-radix-tree.h" +#include "util/radix-tree.h" #define SREP_MAX_CATS 60 -#define SREP_MAX_VAL 127 +#define SREP_MAX_VAL 127 typedef struct SRepCIDRTree_ { SCRadixTree *srepIPV4_tree[SREP_MAX_CATS]; diff --git a/src/respond-reject-libnet11.c b/src/respond-reject-libnet11.c index 634fa3b8b545..90d706a5bec8 100644 --- a/src/respond-reject-libnet11.c +++ b/src/respond-reject-libnet11.c @@ -46,7 +46,7 @@ #include "action-globals.h" #include "respond-reject.h" #include "respond-reject-libnet11.h" -#include "util-device.h" +#include "util/device.h" #ifdef HAVE_LIBNET11 @@ -61,7 +61,7 @@ const char *g_reject_dev = NULL; uint16_t g_reject_dev_mtu = 0; /** set to true in main if we're setting caps. We need it here if we're using - * reject rules as libnet 1.1 is not compatible with caps. */ + * reject rules as libnet 1.1 is not compatible with caps. */ extern bool sc_set_caps; #include @@ -163,26 +163,25 @@ static inline void SetupTCP(Packet *p, Libnet11Packet *lpacket, enum RejectDirec break; } lpacket->window = TCP_GET_WINDOW(p); - //lpacket.seq += lpacket.dsize; + // lpacket.seq += lpacket.dsize; } static inline int BuildTCP(libnet_t *c, Libnet11Packet *lpacket) { /* build the package */ - if ((libnet_build_tcp( - lpacket->sp, /* source port */ - lpacket->dp, /* dst port */ - lpacket->seq, /* seq number */ - lpacket->ack, /* ack number */ - TH_RST|TH_ACK, /* flags */ - lpacket->window, /* window size */ - 0, /* checksum */ - 0, /* urgent flag */ - LIBNET_TCP_H, /* header length */ - NULL, /* payload */ - 0, /* payload length */ - c, /* libnet context */ - 0)) < 0) /* libnet ptag */ + if ((libnet_build_tcp(lpacket->sp, /* source port */ + lpacket->dp, /* dst port */ + lpacket->seq, /* seq number */ + lpacket->ack, /* ack number */ + TH_RST | TH_ACK, /* flags */ + lpacket->window, /* window size */ + 0, /* checksum */ + 0, /* urgent flag */ + LIBNET_TCP_H, /* header length */ + NULL, /* payload */ + 0, /* payload length */ + c, /* libnet context */ + 0)) < 0) /* libnet ptag */ { SCLogError("libnet_build_tcp %s", libnet_geterror(c)); return -1; @@ -192,20 +191,19 @@ static inline int BuildTCP(libnet_t *c, Libnet11Packet *lpacket) static inline int BuildIPv4(libnet_t *c, Libnet11Packet *lpacket, const uint8_t proto) { - if ((libnet_build_ipv4( - lpacket->len, /* entire packet length */ - 0, /* tos */ - lpacket->id, /* ID */ - 0, /* fragmentation flags and offset */ - lpacket->ttl, /* TTL */ - proto, /* protocol */ - 0, /* checksum */ - lpacket->src4, /* source address */ - lpacket->dst4, /* destination address */ - NULL, /* pointer to packet data (or NULL) */ - 0, /* payload length */ - c, /* libnet context pointer */ - 0)) < 0) /* packet id */ + if ((libnet_build_ipv4(lpacket->len, /* entire packet length */ + 0, /* tos */ + lpacket->id, /* ID */ + 0, /* fragmentation flags and offset */ + lpacket->ttl, /* TTL */ + proto, /* protocol */ + 0, /* checksum */ + lpacket->src4, /* source address */ + lpacket->dst4, /* destination address */ + NULL, /* pointer to packet data (or NULL) */ + 0, /* payload length */ + c, /* libnet context pointer */ + 0)) < 0) /* packet id */ { SCLogError("libnet_build_ipv4 %s", libnet_geterror(c)); return -1; @@ -215,18 +213,17 @@ static inline int BuildIPv4(libnet_t *c, Libnet11Packet *lpacket, const uint8_t static inline int BuildIPv6(libnet_t *c, Libnet11Packet *lpacket, const uint8_t proto) { - if ((libnet_build_ipv6( - lpacket->class, /* traffic class */ - lpacket->flow, /* Flow label */ - lpacket->len, /* payload length */ - proto, /* next header */ - lpacket->ttl, /* TTL */ - lpacket->src6, /* source address */ - lpacket->dst6, /* destination address */ - NULL, /* pointer to packet data (or NULL) */ - 0, /* payload length */ - c, /* libnet context pointer */ - 0)) < 0) /* packet id */ + if ((libnet_build_ipv6(lpacket->class, /* traffic class */ + lpacket->flow, /* Flow label */ + lpacket->len, /* payload length */ + proto, /* next header */ + lpacket->ttl, /* TTL */ + lpacket->src6, /* source address */ + lpacket->dst6, /* destination address */ + NULL, /* pointer to packet data (or NULL) */ + 0, /* payload length */ + c, /* libnet context pointer */ + 0)) < 0) /* packet id */ { SCLogError("libnet_build_ipv6 %s", libnet_geterror(c)); return -1; @@ -251,14 +248,15 @@ static inline void SetupEthernet(Packet *p, Libnet11Packet *lpacket, enum Reject static inline int BuildEthernet(libnet_t *c, Libnet11Packet *lpacket, uint16_t proto) { - if ((libnet_build_ethernet(lpacket->dmac,lpacket->smac, proto , NULL, 0, c, 0)) < 0) { + if ((libnet_build_ethernet(lpacket->dmac, lpacket->smac, proto, NULL, 0, c, 0)) < 0) { SCLogError("libnet_build_ethernet %s", libnet_geterror(c)); return -1; } return 0; } -static inline int BuildEthernetVLAN(libnet_t *c, Libnet11Packet *lpacket, uint16_t proto, uint16_t vlan_id) +static inline int BuildEthernetVLAN( + libnet_t *c, Libnet11Packet *lpacket, uint16_t proto, uint16_t vlan_id) { if (libnet_build_802_1q(lpacket->dmac, lpacket->smac, ETHERTYPE_VLAN, 0, 0, vlan_id, proto, NULL, /* payload */ @@ -351,7 +349,7 @@ int RejectSendLibnet11IPv4ICMP(ThreadVars *tv, Packet *p, void *data, enum Rejec if (g_reject_dev_mtu >= ETHERNET_HEADER_LEN + LIBNET_IPV4_H + 8) { lpacket.len = MIN(g_reject_dev_mtu - ETHERNET_HEADER_LEN, (LIBNET_IPV4_H + iplen)); } else { - lpacket.len = LIBNET_IPV4_H + MIN(8,iplen); // 8 bytes is the minimum we have to attach + lpacket.len = LIBNET_IPV4_H + MIN(8, iplen); // 8 bytes is the minimum we have to attach } lpacket.dsize = lpacket.len - (LIBNET_IPV4_H + LIBNET_ICMPV4_H); @@ -375,14 +373,13 @@ int RejectSendLibnet11IPv4ICMP(ThreadVars *tv, Packet *p, void *data, enum Rejec lpacket.ttl = 64; /* build the package */ - if ((libnet_build_icmpv4_unreach( - ICMP_DEST_UNREACH, /* type */ - ICMP_HOST_ANO, /* code */ - 0, /* checksum */ - (uint8_t *)p->ip4h, /* payload */ - lpacket.dsize, /* payload length */ - c, /* libnet context */ - 0)) < 0) /* libnet ptag */ + if ((libnet_build_icmpv4_unreach(ICMP_DEST_UNREACH, /* type */ + ICMP_HOST_ANO, /* code */ + 0, /* checksum */ + (uint8_t *)p->ip4h, /* payload */ + lpacket.dsize, /* payload length */ + c, /* libnet context */ + 0)) < 0) /* libnet ptag */ { SCLogError("libnet_build_icmpv4_unreach %s", libnet_geterror(c)); goto cleanup; @@ -426,7 +423,7 @@ int RejectSendLibnet11IPv6TCP(ThreadVars *tv, Packet *p, void *data, enum Reject lpacket.class = 0; if (p->tcph == NULL) - return 1; + return 1; libnet_t *c = GetCtx(p, LIBNET_RAW6); if (c == NULL) @@ -517,14 +514,13 @@ int RejectSendLibnet11IPv6ICMP(ThreadVars *tv, Packet *p, void *data, enum Rejec lpacket.ttl = 64; /* build the package */ - if ((libnet_build_icmpv6_unreach( - ICMP6_DST_UNREACH, /* type */ - ICMP6_DST_UNREACH_ADMIN, /* code */ - 0, /* checksum */ - (uint8_t *)p->ip6h, /* payload */ - lpacket.dsize, /* payload length */ - c, /* libnet context */ - 0)) < 0) /* libnet ptag */ + if ((libnet_build_icmpv6_unreach(ICMP6_DST_UNREACH, /* type */ + ICMP6_DST_UNREACH_ADMIN, /* code */ + 0, /* checksum */ + (uint8_t *)p->ip6h, /* payload */ + lpacket.dsize, /* payload length */ + c, /* libnet context */ + 0)) < 0) /* libnet ptag */ { SCLogError("libnet_build_icmpv6_unreach %s", libnet_geterror(c)); goto cleanup; @@ -566,7 +562,6 @@ int RejectSendLibnet11IPv6ICMP(ThreadVars *tv, Packet *p, void *data, enum Rejec } #endif /* HAVE_LIBNET_ICMPV6_UNREACH */ - #else int RejectSendLibnet11IPv4TCP(ThreadVars *tv, Packet *p, void *data, enum RejectDirection dir) diff --git a/src/respond-reject.c b/src/respond-reject.c index b53fad9d3f31..5016896b8815 100644 --- a/src/respond-reject.c +++ b/src/respond-reject.c @@ -37,8 +37,8 @@ #include "respond-reject.h" #include "respond-reject-libnet11.h" -#include "util-debug.h" -#include "util-privs.h" +#include "util/debug.h" +#include "util/privs.h" int RejectSendIPv4TCP(ThreadVars *, Packet *, void *); int RejectSendIPv4ICMP(ThreadVars *, Packet *, void *); @@ -47,7 +47,7 @@ int RejectSendIPv6ICMP(ThreadVars *, Packet *, void *); static TmEcode RespondRejectFunc(ThreadVars *tv, Packet *p, void *data); static TmEcode RespondRejectThreadDeinit(ThreadVars *tv, void *data); -void TmModuleRespondRejectRegister (void) +void TmModuleRespondRejectRegister(void) { tmm_modules[TMM_RESPONDREJECT].name = "RespondReject"; tmm_modules[TMM_RESPONDREJECT].ThreadInit = NULL; diff --git a/src/respond-reject.h b/src/respond-reject.h index 0df165591cee..57cdeb8be681 100644 --- a/src/respond-reject.h +++ b/src/respond-reject.h @@ -24,12 +24,11 @@ #ifndef __RESPOND_REJECT_H__ #define __RESPOND_REJECT_H__ - enum RejectDirection { REJECT_DIR_SRC = 0, REJECT_DIR_DST = 1, }; -void TmModuleRespondRejectRegister (void); +void TmModuleRespondRejectRegister(void); #endif /* __RESPOND_REJECT_H__ */ diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index b8ad0bfac0c3..45e88a3828a3 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -36,8 +36,8 @@ #include "conf.h" #include "runmodes.h" #include "runmode-af-packet.h" -#include "output.h" -#include "log-httplog.h" +#include "output/output.h" +#include "app-layer/http/log-httplog.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" @@ -45,19 +45,19 @@ #include "flow-bypass.h" -#include "util-conf.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" -#include "util-device.h" -#include "util-runmodes.h" -#include "util-ioctl.h" -#include "util-ebpf.h" -#include "util-byte.h" +#include "util/conf.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" +#include "util/device.h" +#include "util/runmodes.h" +#include "util/ioctl.h" +#include "util/ebpf.h" +#include "util/byte.h" #include "source-af-packet.h" -#include "util-bpf.h" +#include "util/bpf.h" extern uint16_t max_pending_packets; @@ -169,7 +169,6 @@ void RunModeIdsAFPRegister(void) return; } - #ifdef HAVE_AF_PACKET static void AFPDerefConfig(void *conf) @@ -223,7 +222,7 @@ static void *ParseAFPConfig(const char *iface) strlcpy(aconf->iface, iface, sizeof(aconf->iface)); aconf->threads = 0; SC_ATOMIC_INIT(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, 1); + (void)SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; aconf->cluster_type = cluster_type | PACKET_FANOUT_FLAG_DEFRAG; @@ -449,15 +448,15 @@ static void *ParseAFPConfig(const char *iface) #ifdef HAVE_PACKET_EBPF boolval = false; - if (ConfGetChildValueBoolWithDefault(if_root, if_default, "pinned-maps", (int *)&boolval) == 1) { + if (ConfGetChildValueBoolWithDefault(if_root, if_default, "pinned-maps", (int *)&boolval) == + 1) { if (boolval) { SCLogConfig("%s: using pinned maps", aconf->iface); aconf->ebpf_t_config.flags |= EBPF_PINNED_MAPS; } const char *pinned_maps_name = NULL; - if (ConfGetChildValueWithDefault(if_root, if_default, - "pinned-maps-name", - &pinned_maps_name) != 1) { + if (ConfGetChildValueWithDefault( + if_root, if_default, "pinned-maps-name", &pinned_maps_name) != 1) { aconf->ebpf_t_config.pinned_maps_name = pinned_maps_name; } else { aconf->ebpf_t_config.pinned_maps_name = NULL; @@ -471,8 +470,7 @@ static void *ParseAFPConfig(const char *iface) /* One shot loading of the eBPF file */ if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) { int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_lb_file, "loadbalancer", - &aconf->ebpf_lb_fd, - &aconf->ebpf_t_config); + &aconf->ebpf_lb_fd, &aconf->ebpf_t_config); if (ret != 0) { SCLogWarning("%s: failed to load eBPF lb file", iface); } @@ -508,8 +506,7 @@ static void *ParseAFPConfig(const char *iface) if (aconf->ebpf_filter_file) { #ifdef HAVE_PACKET_EBPF int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_filter_file, "filter", - &aconf->ebpf_filter_fd, - &aconf->ebpf_t_config); + &aconf->ebpf_filter_fd, &aconf->ebpf_t_config); if (ret != 0) { SCLogWarning("%s: failed to load eBPF filter file", iface); } @@ -537,9 +534,8 @@ static void *ParseAFPConfig(const char *iface) SCLogError("%s: flow bypass alloc error", iface); } else { memcpy(ebt, &(aconf->ebpf_t_config), sizeof(struct ebpf_timeout_config)); - BypassedFlowManagerRegisterCheckFunc(NULL, - EBPFCheckBypassedFlowCreate, - (void *)ebt); + BypassedFlowManagerRegisterCheckFunc( + NULL, EBPFCheckBypassedFlowCreate, (void *)ebt); } } BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow, NULL); @@ -565,7 +561,8 @@ static void *ParseAFPConfig(const char *iface) } boolval = true; - if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-percpu-hash", (int *)&boolval) == 1) { + if (ConfGetChildValueBoolWithDefault( + if_root, if_default, "use-percpu-hash", (int *)&boolval) == 1) { if (boolval == false) { SCLogConfig("%s: not using percpu hash", aconf->iface); aconf->ebpf_t_config.cpus_count = 1; @@ -577,9 +574,8 @@ static void *ParseAFPConfig(const char *iface) /* One shot loading of the eBPF file */ if (aconf->xdp_filter_file) { #ifdef HAVE_PACKET_XDP - int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp", - &aconf->xdp_filter_fd, - &aconf->ebpf_t_config); + int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp", &aconf->xdp_filter_fd, + &aconf->ebpf_t_config); switch (ret) { case 1: SCLogInfo("%s: loaded pinned maps from sysfs", iface); @@ -594,10 +590,11 @@ static void *ParseAFPConfig(const char *iface) } else { /* Try to get the xdp-cpu-redirect key */ const char *cpuset; - if (ConfGetChildValueWithDefault(if_root, if_default, - "xdp-cpu-redirect", &cpuset) == 1) { + if (ConfGetChildValueWithDefault( + if_root, if_default, "xdp-cpu-redirect", &cpuset) == 1) { SCLogConfig("%s: Setting up CPU map XDP", iface); - ConfNode *node = ConfGetChildWithDefault(if_root, if_default, "xdp-cpu-redirect"); + ConfNode *node = + ConfGetChildWithDefault(if_root, if_default, "xdp-cpu-redirect"); if (node == NULL) { SCLogError("Previously found node has disappeared"); } else { @@ -703,7 +700,7 @@ static void *ParseAFPConfig(const char *iface) aconf->threads = 1; } SC_ATOMIC_RESET(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); + (void)SC_ATOMIC_ADD(aconf->ref, aconf->threads); if (aconf->ring_size != 0) { if (aconf->ring_size * aconf->threads < max_pending_packets) { @@ -810,11 +807,8 @@ int RunModeIdsAFPSingle(void) FatalError("Unable to init peers list."); } - ret = RunModeSetLiveCaptureSingle(ParseAFPConfig, - AFPConfigGeThreadsCount, - "ReceiveAFP", - "DecodeAFP", thread_name_single, - live_dev); + ret = RunModeSetLiveCaptureSingle(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", + "DecodeAFP", thread_name_single, live_dev); if (ret != 0) { FatalError("Unable to start runmode"); } diff --git a/src/runmode-af-xdp.c b/src/runmode-af-xdp.c index 33a47d167aee..2c5de42413ae 100644 --- a/src/runmode-af-xdp.c +++ b/src/runmode-af-xdp.c @@ -36,8 +36,8 @@ #include "conf.h" #include "runmodes.h" #include "runmode-af-xdp.h" -#include "output.h" -#include "log-httplog.h" +#include "output/output.h" +#include "app-layer/http/log-httplog.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" @@ -45,16 +45,16 @@ #include "flow-bypass.h" -#include "util-conf.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" -#include "util-device.h" -#include "util-runmodes.h" -#include "util-ioctl.h" -#include "util-ebpf.h" -#include "util-byte.h" +#include "util/conf.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" +#include "util/device.h" +#include "util/runmodes.h" +#include "util/ioctl.h" +#include "util/ebpf.h" +#include "util/byte.h" #include "source-af-xdp.h" diff --git a/src/runmode-dpdk.c b/src/runmode-dpdk.c index 2cdf5cb32505..bee207ec659d 100644 --- a/src/runmode-dpdk.c +++ b/src/runmode-dpdk.c @@ -35,28 +35,30 @@ #include "runmode-dpdk.h" #include "decode.h" #include "source-dpdk.h" -#include "util-runmodes.h" -#include "util-byte.h" -#include "util-cpu.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-dpdk.h" -#include "util-dpdk-i40e.h" -#include "util-dpdk-ice.h" -#include "util-dpdk-ixgbe.h" -#include "util-dpdk-bonding.h" -#include "util-time.h" -#include "util-conf.h" +#include "util/runmodes.h" +#include "util/byte.h" +#include "util/cpu.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/dpdk.h" +#include "util/dpdk-i40e.h" +#include "util/dpdk-ice.h" +#include "util/dpdk-ixgbe.h" +#include "util/dpdk-bonding.h" +#include "util/time.h" +#include "util/conf.h" #include "suricata.h" -#include "util-affinity.h" +#include "util/affinity.h" #ifdef HAVE_DPDK #define RSS_HKEY_LEN 40 // General purpose RSS key for symmetric bidirectional flow distribution +// clang-format off uint8_t rss_hkey[] = { 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A }; +// clang-format on // Calculates the closest multiple of y from x #define ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y)) diff --git a/src/runmode-erf-dag.c b/src/runmode-erf-dag.c index 503d1a15562a..c644c5157f5d 100644 --- a/src/runmode-erf-dag.c +++ b/src/runmode-erf-dag.c @@ -20,15 +20,15 @@ #include "conf.h" #include "runmodes.h" #include "runmode-erf-dag.h" -#include "output.h" +#include "output/output.h" #include "detect-engine.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" -#include "util-runmodes.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" +#include "util/runmodes.h" static int DagConfigGetThreadCount(void *conf) { @@ -74,12 +74,8 @@ int RunModeIdsErfDagSingle(void) TimeModeSetLive(); - ret = RunModeSetLiveCaptureSingle(ParseDagConfig, - DagConfigGetThreadCount, - "ReceiveErfDag", - "DecodeErfDag", - thread_name_single, - NULL); + ret = RunModeSetLiveCaptureSingle(ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", + "DecodeErfDag", thread_name_single, NULL); if (ret != 0) { FatalError("DAG single runmode failed to start"); } diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index dc09509d0411..2718f6d88c48 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -20,16 +20,16 @@ #include "conf.h" #include "runmodes.h" #include "runmode-erf-file.h" -#include "output.h" +#include "output/output.h" #include "detect-engine.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" -#include "util-runmodes.h" +#include "util/runmodes.h" const char *RunModeErfFileGetDefaultMode(void) { @@ -63,10 +63,8 @@ int RunModeErfFileSingle(void) /* Basically the same setup as PCAP files. */ - ThreadVars *tv = TmThreadCreatePacketHandler(thread_name_single, - "packetpool", "packetpool", - "packetpool", "packetpool", - "pktacqloop"); + ThreadVars *tv = TmThreadCreatePacketHandler(thread_name_single, "packetpool", "packetpool", + "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); @@ -141,11 +139,8 @@ int RunModeErfFileAutoFp(void) } /* create the threads */ - ThreadVars *tv = - TmThreadCreatePacketHandler(thread_name_autofp, - "packetpool", "packetpool", - queues, "flow", - "pktacqloop"); + ThreadVars *tv = TmThreadCreatePacketHandler( + thread_name_autofp, "packetpool", "packetpool", queues, "flow", "pktacqloop"); SCFree(queues); if (tv == NULL) { @@ -185,11 +180,8 @@ int RunModeErfFileAutoFp(void) SCLogDebug("Assigning %s affinity to cpu %u", tname, cpu); - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(tname, - qname, "flow", - "packetpool", "packetpool", - "varslot"); + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler( + tname, qname, "flow", "packetpool", "packetpool", "varslot"); if (tv_detect_ncpu == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); diff --git a/src/runmode-ipfw.c b/src/runmode-ipfw.c index de72f0623d06..c4b12d9dc2b8 100644 --- a/src/runmode-ipfw.c +++ b/src/runmode-ipfw.c @@ -24,22 +24,20 @@ * Handling of ipfw runmodes. */ - - #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-ipfw.h" -#include "output.h" +#include "output/output.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" -#include "util-runmodes.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" +#include "util/runmodes.h" #include "source-ipfw.h" -#include "util-device.h" +#include "util/device.h" const char *RunModeIpsIPFWGetDefaultMode(void) { @@ -67,10 +65,7 @@ int RunModeIpsIPFWAutoFp(void) LiveDeviceHasNoStats(); - ret = RunModeSetIPSAutoFp(IPFWGetThread, - "ReceiveIPFW", - "VerdictIPFW", - "DecodeIPFW"); + ret = RunModeSetIPSAutoFp(IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); #endif /* IPFW */ return ret; } @@ -85,10 +80,7 @@ int RunModeIpsIPFWWorker(void) LiveDeviceHasNoStats(); - ret = RunModeSetIPSWorker(IPFWGetThread, - "ReceiveIPFW", - "VerdictIPFW", - "DecodeIPFW"); + ret = RunModeSetIPSWorker(IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); #endif /* IPFW */ return ret; } diff --git a/src/runmode-napatech.c b/src/runmode-napatech.c index 3d503b965573..3e8893ece7d4 100644 --- a/src/runmode-napatech.c +++ b/src/runmode-napatech.c @@ -26,15 +26,15 @@ #include "tm-threads.h" #include "conf.h" #include "runmodes.h" -#include "output.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-byte.h" -#include "util-affinity.h" -#include "util-runmodes.h" -#include "util-device.h" -#include "util-napatech.h" +#include "output/output.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/byte.h" +#include "util/affinity.h" +#include "util/runmodes.h" +#include "util/device.h" +#include "util/napatech.h" #include "runmode-napatech.h" #include "source-napatech.h" // need NapatechStreamDevConf structure @@ -95,7 +95,6 @@ void RunModeNapatechRegister(void) #endif } - #ifdef HAVE_NAPATECH static int NapatechRegisterDeviceStreams(void) @@ -154,8 +153,8 @@ static int NapatechRegisterDeviceStreams(void) FatalError("or disable auto-config in the conf file before running."); } } else { - SCLogInfo("Registering Napatech device: %s - active stream%sfound.", - plive_dev_buf, stream_config[inst].is_active ? " " : " NOT "); + SCLogInfo("Registering Napatech device: %s - active stream%sfound.", plive_dev_buf, + stream_config[inst].is_active ? " " : " NOT "); } LiveRegisterDevice(plive_dev_buf); @@ -181,7 +180,7 @@ static void *NapatechConfigParser(const char *device) return NULL; } - struct NapatechStreamDevConf *conf = SCCalloc(1, sizeof (struct NapatechStreamDevConf)); + struct NapatechStreamDevConf *conf = SCCalloc(1, sizeof(struct NapatechStreamDevConf)); if (unlikely(conf == NULL)) { SCLogError("Failed to allocate memory for NAPATECH device name."); return NULL; @@ -194,7 +193,7 @@ static void *NapatechConfigParser(const char *device) return NULL; } - return (void *) conf; + return (void *)conf; } static int NapatechGetThreadsCount(void *conf __attribute__((unused))) @@ -221,8 +220,7 @@ static int NapatechInit(int runmode) FatalError("Unable to find existing Napatech Streams"); } - struct NapatechStreamDevConf *conf = - SCCalloc(1, sizeof (struct NapatechStreamDevConf)); + struct NapatechStreamDevConf *conf = SCCalloc(1, sizeof(struct NapatechStreamDevConf)); if (unlikely(conf == NULL)) { FatalError("Failed to allocate memory for NAPATECH device."); } diff --git a/src/runmode-napatech.h b/src/runmode-napatech.h index d77133addaa2..029611daf54b 100644 --- a/src/runmode-napatech.h +++ b/src/runmode-napatech.h @@ -22,7 +22,6 @@ * \author Matt Keeler */ - #ifndef __RUNMODE_NAPATECH_H__ #define __RUNMODE_NAPATECH_H__ @@ -41,5 +40,4 @@ uint16_t NapatechGetNumLastStream(void); bool NapatechIsAutoConfigEnabled(void); bool NapatechUseHWBypass(void); - #endif /* __RUNMODE_NAPATECH_H__ */ diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c index 927dc718856c..7ab046e492ff 100644 --- a/src/runmode-netmap.c +++ b/src/runmode-netmap.c @@ -16,10 +16,10 @@ */ /** -* \ingroup netmap -* -* @{ -*/ + * \ingroup netmap + * + * @{ + */ /** * \file @@ -35,10 +35,10 @@ #include "decode.h" #include "runmodes.h" #include "runmode-netmap.h" -#include "util-runmodes.h" -#include "util-ioctl.h" -#include "util-byte.h" -#include "util-time.h" +#include "util/runmodes.h" +#include "util/ioctl.h" +#include "util/byte.h" +#include "util/time.h" #ifdef HAVE_NETMAP #define NETMAP_WITH_LIBS @@ -46,9 +46,9 @@ #endif /* HAVE_NETMAP */ #include "source-netmap.h" -#include "util-conf.h" +#include "util/conf.h" #include "suricata.h" -#include "util-bpf.h" +#include "util/bpf.h" extern uint16_t max_pending_packets; @@ -171,8 +171,8 @@ static void NetmapDerefConfig(void *conf) } } -static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, - ConfNode *if_root, ConfNode *if_default) +static int ParseNetmapSettings( + NetmapIfaceSettings *ns, const char *iface, ConfNode *if_root, ConfNode *if_default) { ns->threads = 0; ns->promisc = true; @@ -182,11 +182,11 @@ static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, if (ns->iface[0]) { size_t len = strlen(ns->iface); - if (ns->iface[len-1] == '+') { + if (ns->iface[len - 1] == '+') { SCLogWarning("%s: interface uses obsolete '+' notation. Using '^' instead", ns->iface); - ns->iface[len-1] = '^'; + ns->iface[len - 1] = '^'; ns->sw_ring = true; - } else if (ns->iface[len-1] == '^') { + } else if (ns->iface[len - 1] == '^') { ns->sw_ring = true; } } @@ -201,8 +201,7 @@ static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, /* prefixed with netmap or vale means it's not a real interface * and we don't check offloading. */ - if (strncmp(ns->iface, "netmap:", 7) != 0 && - strncmp(ns->iface, "vale", 4) != 0) { + if (strncmp(ns->iface, "netmap:", 7) != 0 && strncmp(ns->iface, "vale", 4) != 0) { ns->real = true; } @@ -212,7 +211,7 @@ static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, iface, iface); goto finalize; - /* If there is no setting for current interface use default one as main iface */ + /* If there is no setting for current interface use default one as main iface */ } else if (if_root == NULL) { if_root = if_default; if_default = NULL; @@ -245,9 +244,7 @@ static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, } const char *tmpctype; - if (ConfGetChildValueWithDefault(if_root, if_default, - "checksum-checks", &tmpctype) == 1) - { + if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { ns->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (ConfValIsTrue(tmpctype)) { @@ -260,9 +257,7 @@ static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, } const char *copymodestr; - if (ConfGetChildValueWithDefault(if_root, if_default, - "copy-mode", ©modestr) == 1) - { + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { if (strcmp(copymodestr, "ips") == 0) { ns->copy_mode = NETMAP_COPY_MODE_IPS; } else if (strcmp(copymodestr, "tap") == 0) { @@ -320,7 +315,7 @@ static void *ParseNetmapConfig(const char *iface_name) aconf->DerefFunc = NetmapDerefConfig; strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); SC_ATOMIC_INIT(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, 1); + (void)SC_ATOMIC_ADD(aconf->ref, 1); /* Find initial node */ ConfNode *netmap_node = ConfGetNode("netmap"); @@ -336,8 +331,7 @@ static void *ParseNetmapConfig(const char *iface_name) /* if we have a copy iface, parse that as well */ if (netmap_node != NULL && - ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) - { + ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { if_root = ConfFindDeviceConfig(netmap_node, out_iface); ParseNetmapSettings(&aconf->out, out_iface, if_root, if_default); @@ -380,7 +374,7 @@ static void *ParseNetmapConfig(const char *iface_name) } SC_ATOMIC_RESET(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, aconf->in.threads); + (void)SC_ATOMIC_ADD(aconf->ref, aconf->in.threads); SCLogPerf("%s: using %d threads", aconf->iface_name, aconf->in.threads); LiveDeviceHasNoStats(); @@ -438,8 +432,8 @@ int RunModeIdsNetmapAutoFp(void) } /** -* \brief Single thread version of the netmap processing. -*/ + * \brief Single thread version of the netmap processing. + */ int RunModeIdsNetmapSingle(void) { return NetmapRunModeInit(NETMAP_SINGLE); @@ -474,11 +468,11 @@ int RunModeIdsNetmapSingle(void) } /** -* \brief Workers version of the netmap processing. -* -* Start N threads with each thread doing all the work. -* -*/ + * \brief Workers version of the netmap processing. + * + * Start N threads with each thread doing all the work. + * + */ int RunModeIdsNetmapWorkers(void) { SCEnter(); @@ -488,5 +482,5 @@ int RunModeIdsNetmapWorkers(void) #endif // #ifdef HAVE_NETMAP /** -* @} -*/ + * @} + */ diff --git a/src/runmode-netmap.h b/src/runmode-netmap.h index 6ba9445b086d..26194226c00c 100644 --- a/src/runmode-netmap.h +++ b/src/runmode-netmap.h @@ -16,9 +16,9 @@ */ /** \file -* -* \author Aleksey Katargin -*/ + * + * \author Aleksey Katargin + */ #ifndef __RUNMODE_NETMAP_H__ #define __RUNMODE_NETMAP_H__ diff --git a/src/runmode-nflog.c b/src/runmode-nflog.c index 28b9ae5efd64..f29212cf5327 100644 --- a/src/runmode-nflog.c +++ b/src/runmode-nflog.c @@ -26,15 +26,15 @@ #include "runmodes.h" #include "runmode-nflog.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-runmodes.h" -#include "util-misc.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/runmodes.h" +#include "util/misc.h" #include "source-nflog.h" #ifdef HAVE_NFLOG -#include "util-time.h" +#include "util/time.h" static void NflogDerefConfig(void *data) { @@ -77,7 +77,7 @@ static void *ParseNflogConfig(const char *group) if (group_root == NULL && group_default == NULL) { SCLogInfo("Unable to find nflog config for " "group \"%s\" or \"default\", using default value", - group); + group); return nflogconf; } @@ -88,8 +88,7 @@ static void *ParseNflogConfig(const char *group) FatalError("NFLOG's group number invalid."); } - boolval = ConfGetChildValueIntWithDefault(group_root, group_default, - "buffer-size", &bufsize); + boolval = ConfGetChildValueIntWithDefault(group_root, group_default, "buffer-size", &bufsize); if (boolval) nflogconf->nlbufsiz = bufsize; @@ -99,8 +98,7 @@ static void *ParseNflogConfig(const char *group) return NULL; } - boolval = ConfGetChildValueIntWithDefault(group_root, group_default, - "max-size", &bufsize_max); + boolval = ConfGetChildValueIntWithDefault(group_root, group_default, "max-size", &bufsize_max); if (boolval) nflogconf->nlbufsiz_max = bufsize_max; @@ -116,8 +114,7 @@ static void *ParseNflogConfig(const char *group) nflogconf->nlbufsiz = nflogconf->nlbufsiz_max; } - boolval = ConfGetChildValueIntWithDefault(group_root, group_default, - "qthreshold", &qthreshold); + boolval = ConfGetChildValueIntWithDefault(group_root, group_default, "qthreshold", &qthreshold); if (boolval) nflogconf->qthreshold = qthreshold; @@ -127,8 +124,7 @@ static void *ParseNflogConfig(const char *group) return NULL; } - boolval = ConfGetChildValueIntWithDefault(group_root, group_default, - "qtimeout", &qtimeout); + boolval = ConfGetChildValueIntWithDefault(group_root, group_default, "qtimeout", &qtimeout); if (boolval) nflogconf->qtimeout = qtimeout; diff --git a/src/runmode-nfq.c b/src/runmode-nfq.c index d9ea93c746f3..f590b5b8ae26 100644 --- a/src/runmode-nfq.c +++ b/src/runmode-nfq.c @@ -24,20 +24,19 @@ * Handling of NFQ runmodes. */ - #include "suricata-common.h" #include "tm-threads.h" #include "conf.h" #include "runmodes.h" #include "runmode-nfq.h" -#include "output.h" +#include "output/output.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" -#include "util-runmodes.h" -#include "util-device.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" +#include "util/runmodes.h" +#include "util/device.h" const char *RunModeIpsNFQGetDefaultMode(void) { @@ -64,10 +63,7 @@ int RunModeIpsNFQAutoFp(void) LiveDeviceHasNoStats(); - ret = RunModeSetIPSAutoFp(NFQGetThread, - "ReceiveNFQ", - "VerdictNFQ", - "DecodeNFQ"); + ret = RunModeSetIPSAutoFp(NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); #endif /* NFQ */ return ret; } @@ -82,10 +78,7 @@ int RunModeIpsNFQWorker(void) LiveDeviceHasNoStats(); - ret = RunModeSetIPSWorker(NFQGetThread, - "ReceiveNFQ", - "VerdictNFQ", - "DecodeNFQ"); + ret = RunModeSetIPSWorker(NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); #endif /* NFQ */ return ret; } diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index 7c5bfcc4c38a..973ccdef7d55 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -20,17 +20,17 @@ #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" -#include "output.h" +#include "output/output.h" #include "detect-engine.h" #include "source-pcap-file.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" -#include "util-runmodes.h" +#include "util/runmodes.h" const char *RunModeFilePcapGetDefaultMode(void) { @@ -68,10 +68,8 @@ int RunModeFilePcapSingle(void) snprintf(tname, sizeof(tname), "%s#01", thread_name_single); /* create the threads */ - ThreadVars *tv = TmThreadCreatePacketHandler(tname, - "packetpool", "packetpool", - "packetpool", "packetpool", - "pktacqloop"); + ThreadVars *tv = TmThreadCreatePacketHandler( + tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { FatalError("threading setup failed"); } @@ -161,11 +159,8 @@ int RunModeFilePcapAutoFp(void) snprintf(tname, sizeof(tname), "%s#01", thread_name_autofp); /* create the threads */ - ThreadVars *tv_receivepcap = - TmThreadCreatePacketHandler(tname, - "packetpool", "packetpool", - queues, "flow", - "pktacqloop"); + ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler( + tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); SCFree(queues); if (tv_receivepcap == NULL) { @@ -196,11 +191,8 @@ int RunModeFilePcapAutoFp(void) SCLogDebug("tname %s, qname %s", tname, qname); SCLogDebug("Assigning %s affinity to cpu %u", tname, cpu); - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(tname, - qname, "flow", - "packetpool", "packetpool", - "varslot"); + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler( + tname, qname, "flow", "packetpool", "packetpool", "varslot"); if (tv_detect_ncpu == NULL) { FatalError("TmThreadsCreate failed"); } diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index 21c32846b737..b1522fc5776a 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -18,16 +18,16 @@ #include "suricata-common.h" #include "runmode-pcap.h" #include "runmodes.h" -#include "output.h" +#include "output/output.h" -#include "util-conf.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-device.h" -#include "util-runmodes.h" -#include "util-misc.h" -#include "util-byte.h" +#include "util/conf.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/device.h" +#include "util/runmodes.h" +#include "util/misc.h" +#include "util/byte.h" const char *RunModeIdsGetDefaultMode(void) { @@ -124,7 +124,7 @@ static void *ParsePcapConfig(const char *iface) if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find pcap config for " "interface %s, using default value", - iface); + iface); return aconf; } @@ -149,7 +149,7 @@ static void *ParsePcapConfig(const char *iface) if (aconf->threads == 0) { aconf->threads = 1; } - (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); + (void)SC_ATOMIC_ADD(aconf->ref, aconf->threads); if (aconf->buffer_size == 0) { const char *s_limit = NULL; @@ -236,11 +236,8 @@ int RunModeIdsPcapSingle(void) (void)ConfGet("pcap.single-pcap-dev", &live_dev); - ret = RunModeSetLiveCaptureSingle(ParsePcapConfig, - PcapConfigGeThreadsCount, - "ReceivePcap", - "DecodePcap", thread_name_single, - live_dev); + ret = RunModeSetLiveCaptureSingle(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", + "DecodePcap", thread_name_single, live_dev); if (ret != 0) { FatalError("Runmode start failed"); } @@ -273,7 +270,7 @@ int RunModeIdsPcapAutoFp(void) SCEnter(); TimeModeSetLive(); - (void) ConfGet("pcap.single-pcap-dev", &live_dev); + (void)ConfGet("pcap.single-pcap-dev", &live_dev); ret = RunModeSetLiveCaptureAutoFp(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", thread_name_autofp, live_dev); @@ -300,7 +297,7 @@ int RunModeIdsPcapWorkers(void) TimeModeSetLive(); - (void) ConfGet("pcap.single-pcap-dev", &live_dev); + (void)ConfGet("pcap.single-pcap-dev", &live_dev); ret = RunModeSetLiveCaptureWorkers(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", "DecodePcap", thread_name_workers, live_dev); diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index b0af83b4bfc2..d840dc84865d 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -22,15 +22,15 @@ #include "runmodes.h" #include "source-pfring.h" #include "suricata.h" -#include "util-bpf.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-runmodes.h" -#include "util-device.h" -#include "util-ioctl.h" -#include "util-byte.h" -#include "util-conf.h" +#include "util/bpf.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/runmodes.h" +#include "util/device.h" +#include "util/ioctl.h" +#include "util/byte.h" +#include "util/conf.h" #ifdef HAVE_PFRING #include @@ -113,7 +113,7 @@ static void *OldParsePfringConfig(const char *iface) pfconf->DerefFunc = PfringDerefConfig; pfconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; SC_ATOMIC_INIT(pfconf->ref); - (void) SC_ATOMIC_ADD(pfconf->ref, 1); + (void)SC_ATOMIC_ADD(pfconf->ref, 1); /* Find initial node */ if (ConfGet("pfring.threads", &threadsstr) != 1) { @@ -133,12 +133,11 @@ static void *OldParsePfringConfig(const char *iface) } SC_ATOMIC_RESET(pfconf->ref); - (void) SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); + (void)SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); if (strncmp(pfconf->iface, "zc", 2) == 0) { SCLogInfo("%s: ZC interface detected, not setting cluster-id", pfconf->iface); - } - else if ((pfconf->threads == 1) && (strncmp(pfconf->iface, "dna", 3) == 0)) { + } else if ((pfconf->threads == 1) && (strncmp(pfconf->iface, "dna", 3) == 0)) { SCLogInfo("DNA interface detected, not setting cluster-id"); } else if (ConfGet("pfring.cluster-id", &tmpclusterid) != 1) { SCLogError("Could not get cluster-id from config"); @@ -217,7 +216,7 @@ static void *ParsePfringConfig(const char *iface) pfconf->ctype = (cluster_type)default_ctype; pfconf->DerefFunc = PfringDerefConfig; SC_ATOMIC_INIT(pfconf->ref); - (void) SC_ATOMIC_ADD(pfconf->ref, 1); + (void)SC_ATOMIC_ADD(pfconf->ref, 1); /* Find initial node */ pf_ring_node = ConfGetNode("pfring"); @@ -234,7 +233,7 @@ static void *ParsePfringConfig(const char *iface) SCLogInfo("Unable to find pfring config for " "interface %s, using default value or 1.0 " "configuration system. ", - iface); + iface); return pfconf; } @@ -254,7 +253,8 @@ static void *ParsePfringConfig(const char *iface) } else { pfconf->threads = GetIfaceRSSQueuesNum(iface); if (pfconf->threads > 0) { - SCLogPerf("%d RSS queues, so using %u threads", pfconf->threads, pfconf->threads); + SCLogPerf( + "%d RSS queues, so using %u threads", pfconf->threads, pfconf->threads); } } } else { @@ -274,7 +274,7 @@ static void *ParsePfringConfig(const char *iface) } SC_ATOMIC_RESET(pfconf->ref); - (void) SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); + (void)SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); /* command line value has precedence */ if (ConfGet("pfring.cluster-id", &tmpclusterid) == 1) { @@ -285,8 +285,7 @@ static void *ParsePfringConfig(const char *iface) pfconf->cluster_id = 1; } pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; - SCLogDebug("Going to use command-line provided cluster-id %" PRId32, - pfconf->cluster_id); + SCLogDebug("Going to use command-line provided cluster-id %" PRId32, pfconf->cluster_id); } else { if (strncmp(pfconf->iface, "zc", 2) == 0) { @@ -295,7 +294,8 @@ static void *ParsePfringConfig(const char *iface) } else if ((pfconf->threads == 1) && (strncmp(pfconf->iface, "dna", 3) == 0)) { SCLogInfo("%s: DNA interface detected, not setting cluster-id for PF_RING", pfconf->iface); - } else if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { + } else if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != + 1) { SCLogError("Could not get cluster-id from config"); } else { if (StringParseInt32(&pfconf->cluster_id, 10, 0, (const char *)tmpclusterid) < 0) { @@ -325,7 +325,8 @@ static void *ParsePfringConfig(const char *iface) } else if ((pfconf->threads == 1) && (strncmp(pfconf->iface, "dna", 3) == 0)) { SCLogInfo("%s: DNA interface detected, not setting cluster type for PF_RING", pfconf->iface); - } else if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { + } else if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != + 1) { SCLogError("Could not get cluster-type from config"); } else { getctype = 1; @@ -416,7 +417,7 @@ static int PfringConfLevel(void) static int GetDevAndParser(const char **live_dev, ConfigIfaceParserFunc *parser) { - ConfGet("pfring.live-interface", live_dev); + ConfGet("pfring.live-interface", live_dev); /* determine which config type we have */ if (PfringConfLevel() > PFRING_CONF_V1) { @@ -486,11 +487,8 @@ int RunModeIdsPfringSingle(void) FatalError("Unable to get parser and interface params"); } - ret = RunModeSetLiveCaptureSingle(tparser, - PfringConfigGetThreadsCount, - "ReceivePfring", - "DecodePfring", thread_name_single, - live_dev); + ret = RunModeSetLiveCaptureSingle(tparser, PfringConfigGetThreadsCount, "ReceivePfring", + "DecodePfring", thread_name_single, live_dev); if (ret != 0) { FatalError("Runmode start failed"); } diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 1150bad89580..45c7412e7163 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -22,9 +22,9 @@ #include "suricata-common.h" #include "runmode-unittests.h" -#include "util-unittest.h" +#include "util/unittest.h" -#include "util-debug.h" +#include "util/debug.h" #ifdef UNITTESTS #include "detect-parse.h" #include "detect-engine.h" @@ -58,43 +58,43 @@ #include "app-layer-detect-proto.h" #include "app-layer-parser.h" #include "app-layer.h" -#include "app-layer-htp.h" -#include "app-layer-ftp.h" -#include "app-layer-ssl.h" -#include "app-layer-ssh.h" -#include "app-layer-smtp.h" - -#include "util-action.h" -#include "util-radix-tree.h" -#include "util-host-os-info.h" -#include "util-cidr.h" -#include "util-unittest-helper.h" -#include "util-time.h" -#include "util-rule-vars.h" -#include "util-classification-config.h" -#include "util-threshold-config.h" -#include "util-reference-config.h" -#include "util-profiling.h" -#include "util-magic.h" -#include "util-memcmp.h" -#include "util-misc.h" -#include "util-signal.h" +#include "app-layer/http/parser.h" +#include "app-layer/ftp/parser.h" +#include "app-layer/ssl/parser.h" +#include "app-layer/ssh/parser.h" +#include "app-layer/smtp/parser.h" + +#include "util/action.h" +#include "util/radix-tree.h" +#include "util/host-os-info.h" +#include "util/cidr.h" +#include "util/unittest-helper.h" +#include "util/time.h" +#include "util/rule-vars.h" +#include "util/classification-config.h" +#include "util/threshold-config.h" +#include "util/reference-config.h" +#include "util/profiling.h" +#include "util/magic.h" +#include "util/memcmp.h" +#include "util/misc.h" +#include "util/signal.h" #include "reputation.h" -#include "util-atomic.h" -#include "util-spm.h" -#include "util-hash.h" -#include "util-hashlist.h" -#include "util-bloomfilter.h" -#include "util-bloomfilter-counting.h" -#include "util-pool.h" -#include "util-byte.h" -#include "util-proto-name.h" -#include "util-macset.h" -#include "util-memrchr.h" - -#include "util-mpm-ac.h" -#include "util-mpm-hs.h" +#include "util/atomic.h" +#include "util/spm.h" +#include "util/hash.h" +#include "util/hashlist.h" +#include "util/bloomfilter.h" +#include "util/bloomfilter-counting.h" +#include "util/pool.h" +#include "util/byte.h" +#include "util/proto-name.h" +#include "util/macset.h" +#include "util/memrchr.h" + +#include "util/mpm/mpm-ac.h" +#include "util/mpm/mpm-hs.h" #include "conf.h" #include "conf-yaml-loader.h" @@ -102,9 +102,9 @@ #include "defrag.h" #include "detect-engine-siggroup.h" -#include "util-streaming-buffer.h" -#include "util-lua.h" -#include "util-luajit.h" +#include "util/streaming-buffer.h" +#include "util/lua/lua.h" +#include "util/lua/luajit.h" #include "tm-modules.h" #include "tmqh-packetpool.h" #include "decode-chdlc.h" @@ -115,7 +115,7 @@ #include "decode-vxlan.h" #ifdef OS_WIN32 -#include "win32-syscall.h" +#include "windows/win32-syscall.h" #endif #ifdef WINDIVERT @@ -124,7 +124,7 @@ #endif /* UNITTESTS */ -void TmqhSetup (void); +void TmqhSetup(void); #ifdef UNITTESTS static void RegisterUnittests(void) @@ -262,7 +262,7 @@ void RunUnittests(int list_unittests, const char *regex_arg) StorageFinalize(); /* test and initialize the unit testing subsystem */ - if (regex_arg == NULL){ + if (regex_arg == NULL) { regex_arg = ".*"; UtRunSelftest(regex_arg); /* inits and cleans up again */ } diff --git a/src/runmode-unittests.h b/src/runmode-unittests.h index 928e22bd5ed6..2ae310eee66a 100644 --- a/src/runmode-unittests.h +++ b/src/runmode-unittests.h @@ -20,11 +20,9 @@ * \author Eric Leblond */ - #ifndef __UTIL_RUNMODE_UNITTESTS_H__ #define __UTIL_RUNMODE_UNITTESTS_H__ -__attribute__((noreturn)) -void RunUnittests(int list_unittests, const char *regex_arg); +__attribute__((noreturn)) void RunUnittests(int list_unittests, const char *regex_arg); #endif /* __UTIL_RUNMODE_UNITTESTS_H__ */ diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index 099d56cbda2d..d905e6887ec4 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -20,15 +20,15 @@ #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" -#include "output.h" -#include "output-json.h" - -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" -#include "util-var-name.h" -#include "util-path.h" +#include "output/output.h" +#include "output/eve/output-json.h" + +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" +#include "util/var-name.h" +#include "util/path.h" #include "unix-manager.h" #include "detect-engine.h" @@ -44,11 +44,11 @@ #include "defrag-hash.h" #include "ippair.h" #include "app-layer.h" -#include "app-layer-htp-mem.h" +#include "app-layer/http/parser-mem.h" #include "host-bit.h" -#include "util-misc.h" -#include "util-profiling.h" +#include "util/misc.h" +#include "util/profiling.h" #include "conf-yaml-loader.h" @@ -89,47 +89,18 @@ const char *RunModeUnixSocketGetDefaultMode(void) #define MEMCAPS_MAX 7 static MemcapCommand memcaps[MEMCAPS_MAX] = { { - "stream", - StreamTcpSetMemcap, - StreamTcpGetMemcap, - StreamTcpMemuseCounter, - }, - { - "stream-reassembly", - StreamTcpReassembleSetMemcap, - StreamTcpReassembleGetMemcap, - StreamTcpReassembleMemuseGlobalCounter - }, - { - "flow", - FlowSetMemcap, - FlowGetMemcap, - FlowGetMemuse - }, - { - "applayer-proto-http", - HTPSetMemcap, - HTPGetMemcap, - HTPMemuseGlobalCounter - }, - { - "defrag", - DefragTrackerSetMemcap, - DefragTrackerGetMemcap, - DefragTrackerGetMemuse - }, - { - "ippair", - IPPairSetMemcap, - IPPairGetMemcap, - IPPairGetMemuse - }, - { - "host", - HostSetMemcap, - HostGetMemcap, - HostGetMemuse + "stream", + StreamTcpSetMemcap, + StreamTcpGetMemcap, + StreamTcpMemuseCounter, }, + { "stream-reassembly", StreamTcpReassembleSetMemcap, StreamTcpReassembleGetMemcap, + StreamTcpReassembleMemuseGlobalCounter }, + { "flow", FlowSetMemcap, FlowGetMemcap, FlowGetMemuse }, + { "applayer-proto-http", HTPSetMemcap, HTPGetMemcap, HTPMemuseGlobalCounter }, + { "defrag", DefragTrackerSetMemcap, DefragTrackerGetMemcap, DefragTrackerGetMemuse }, + { "ippair", IPPairSetMemcap, IPPairGetMemcap, IPPairGetMemuse }, + { "host", HostSetMemcap, HostGetMemcap, HostGetMemuse }, }; float MemcapsGetPressure(void) @@ -162,9 +133,9 @@ static SCCtrlMutex unix_manager_pcap_last_processed_mutex; * * \retval 0 in case of error, 1 in case of success */ -static TmEcode UnixSocketPcapFilesList(json_t *cmd, json_t* answer, void *data) +static TmEcode UnixSocketPcapFilesList(json_t *cmd, json_t *answer, void *data) { - PcapCommand *this = (PcapCommand *) data; + PcapCommand *this = (PcapCommand *)data; int i = 0; PcapFiles *file; json_t *jdata; @@ -172,18 +143,18 @@ static TmEcode UnixSocketPcapFilesList(json_t *cmd, json_t* answer, void *data) jdata = json_object(); if (jdata == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } jarray = json_array(); if (jarray == NULL) { json_decref(jdata); - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } - TAILQ_FOREACH(file, &this->files, next) { + TAILQ_FOREACH (file, &this->files, next) { json_array_append_new(jarray, SCJsonString(file->filename)); i++; } @@ -193,26 +164,25 @@ static TmEcode UnixSocketPcapFilesList(json_t *cmd, json_t* answer, void *data) return TM_ECODE_OK; } -static TmEcode UnixSocketPcapFilesNumber(json_t *cmd, json_t* answer, void *data) +static TmEcode UnixSocketPcapFilesNumber(json_t *cmd, json_t *answer, void *data) { - PcapCommand *this = (PcapCommand *) data; + PcapCommand *this = (PcapCommand *)data; int i = 0; PcapFiles *file; - TAILQ_FOREACH(file, &this->files, next) { + TAILQ_FOREACH (file, &this->files, next) { i++; } json_object_set_new(answer, "message", json_integer(i)); return TM_ECODE_OK; } -static TmEcode UnixSocketPcapCurrent(json_t *cmd, json_t* answer, void *data) +static TmEcode UnixSocketPcapCurrent(json_t *cmd, json_t *answer, void *data) { - PcapCommand *this = (PcapCommand *) data; + PcapCommand *this = (PcapCommand *)data; if (this->current_file != NULL && this->current_file->filename != NULL) { - json_object_set_new(answer, "message", - json_string(this->current_file->filename)); + json_object_set_new(answer, "message", json_string(this->current_file->filename)); } else { json_object_set_new(answer, "message", json_string("None")); } @@ -226,8 +196,7 @@ static TmEcode UnixSocketPcapLastProcessed(json_t *cmd, json_t *answer, void *da epoch_millis = SCTimespecAsEpochMillis(&unix_manager_pcap_last_processed); SCCtrlMutexUnlock(&unix_manager_pcap_last_processed_mutex); - json_object_set_new(answer, "message", - json_integer(epoch_millis)); + json_object_set_new(answer, "message", json_integer(epoch_millis)); return TM_ECODE_OK; } @@ -313,10 +282,9 @@ static TmEcode UnixListAddFile(PcapCommand *this, const char *filename, const ch * \param data pointer to data defining the context here a PcapCommand:: * \param continuous If this should run in continuous mode */ -static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data, - bool continuous) +static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t *answer, void *data, bool continuous) { - PcapCommand *this = (PcapCommand *) data; + PcapCommand *this = (PcapCommand *)data; const char *filename; const char *output_dir; uint32_t tenant_id = 0; @@ -328,14 +296,12 @@ static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data json_t *jarg = json_object_get(cmd, "filename"); if (!json_is_string(jarg)) { SCLogError("filename is not a string"); - json_object_set_new(answer, "message", - json_string("filename is not a string")); + json_object_set_new(answer, "message", json_string("filename is not a string")); return TM_ECODE_FAILED; } filename = json_string_value(jarg); if (SCStatFn(filename, &st) != 0) { - json_object_set_new(answer, "message", - json_string("filename does not exist")); + json_object_set_new(answer, "message", json_string("filename does not exist")); return TM_ECODE_FAILED; } @@ -344,30 +310,26 @@ static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data if (!json_is_string(oarg)) { SCLogError("output-dir is not a string"); - json_object_set_new(answer, "message", - json_string("output-dir is not a string")); + json_object_set_new(answer, "message", json_string("output-dir is not a string")); return TM_ECODE_FAILED; } output_dir = json_string_value(oarg); } else { SCLogError("can't get output-dir"); - json_object_set_new(answer, "message", - json_string("output-dir param is mandatory")); + json_object_set_new(answer, "message", json_string("output-dir param is mandatory")); return TM_ECODE_FAILED; } if (SCStatFn(output_dir, &st) != 0) { - json_object_set_new(answer, "message", - json_string("output-dir does not exist")); + json_object_set_new(answer, "message", json_string("output-dir does not exist")); return TM_ECODE_FAILED; } json_t *targ = json_object_get(cmd, "tenant"); if (targ != NULL) { if (!json_is_integer(targ)) { - json_object_set_new(answer, "message", - json_string("tenant is not a number")); + json_object_set_new(answer, "message", json_string("tenant is not a number")); return TM_ECODE_FAILED; } tenant_id = json_number_value(targ); @@ -382,8 +344,7 @@ static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data if (delay_arg != NULL) { if (!json_is_integer(delay_arg)) { SCLogError("delay is not a integer"); - json_object_set_new(answer, "message", - json_string("delay is not a integer")); + json_object_set_new(answer, "message", json_string("delay is not a integer")); return TM_ECODE_FAILED; } delay = json_integer_value(delay_arg); @@ -394,24 +355,21 @@ static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data if (!json_is_integer(interval_arg)) { SCLogError("poll-interval is not a integer"); - json_object_set_new(answer, "message", - json_string("poll-interval is not a integer")); + json_object_set_new(answer, "message", json_string("poll-interval is not a integer")); return TM_ECODE_FAILED; } poll_interval = json_integer_value(interval_arg); } - switch (UnixListAddFile(this, filename, output_dir, tenant_id, continuous, - should_delete, delay, poll_interval)) { + switch (UnixListAddFile(this, filename, output_dir, tenant_id, continuous, should_delete, delay, + poll_interval)) { case TM_ECODE_FAILED: case TM_ECODE_DONE: - json_object_set_new(answer, "message", - json_string("Unable to add file to list")); + json_object_set_new(answer, "message", json_string("Unable to add file to list")); return TM_ECODE_FAILED; case TM_ECODE_OK: SCLogInfo("Added file '%s' to list", filename); - json_object_set_new(answer, "message", - json_string("Successfully added file to list")); + json_object_set_new(answer, "message", json_string("Successfully added file to list")); return TM_ECODE_OK; } return TM_ECODE_OK; @@ -424,7 +382,7 @@ static TmEcode UnixSocketAddPcapFileImpl(json_t *cmd, json_t* answer, void *data * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -static TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data) +static TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t *answer, void *data) { bool continuous = false; @@ -443,7 +401,7 @@ static TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data) * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -static TmEcode UnixSocketAddPcapFileContinuous(json_t *cmd, json_t* answer, void *data) +static TmEcode UnixSocketAddPcapFileContinuous(json_t *cmd, json_t *answer, void *data) { return UnixSocketAddPcapFileImpl(cmd, answer, data, true); } @@ -463,7 +421,7 @@ static TmEcode UnixSocketAddPcapFileContinuous(json_t *cmd, json_t* answer, void */ static TmEcode UnixSocketPcapFilesCheck(void *data) { - PcapCommand *this = (PcapCommand *) data; + PcapCommand *this = (PcapCommand *)data; if (unix_manager_pcap_task_running == 1) { return TM_ECODE_OK; } @@ -593,7 +551,7 @@ void RunModeUnixSocketRegister(void) TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed) { #ifdef BUILD_UNIX_SOCKET - if(last_processed) { + if (last_processed) { SCCtrlMutexLock(&unix_manager_pcap_last_processed_mutex); unix_manager_pcap_last_processed.tv_sec = last_processed->tv_sec; unix_manager_pcap_last_processed.tv_nsec = last_processed->tv_nsec; @@ -608,7 +566,7 @@ TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed) SCLogInfo("Marking current task as failed"); unix_manager_pcap_task_running = 0; unix_manager_pcap_task_failed = 1; - //if we return failed, we can't stop the thread and suricata will fail to close + // if we return failed, we can't stop the thread and suricata will fail to close return TM_ECODE_FAILED; case TM_ECODE_OK: if (unix_manager_pcap_task_interrupted == 1) { @@ -631,7 +589,7 @@ TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed) * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -TmEcode UnixSocketDatasetAdd(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketDatasetAdd(json_t *cmd, json_t *answer, void *data) { /* 1 get dataset name */ json_t *narg = json_object_get(cmd, "setname"); @@ -684,7 +642,7 @@ TmEcode UnixSocketDatasetAdd(json_t *cmd, json_t* answer, void *data) } } -TmEcode UnixSocketDatasetRemove(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketDatasetRemove(json_t *cmd, json_t *answer, void *data) { /* 1 get dataset name */ json_t *narg = json_object_get(cmd, "setname"); @@ -838,7 +796,7 @@ TmEcode UnixSocketDatasetLookup(json_t *cmd, json_t *answer, void *data) * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t *answer, void *data) { const char *htype; json_int_t traffic_id = -1; @@ -919,7 +877,7 @@ TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data) * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t *answer, void *data) { const char *htype; json_int_t traffic_id = -1; @@ -975,7 +933,8 @@ TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *dat return TM_ECODE_FAILED; } - SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, tenant_id); + SCLogInfo("VLAN handler: removing mapping of %u to tenant %u", (uint32_t)traffic_id, + tenant_id); r = DetectEngineTenantUnregisterVlanId(tenant_id, (uint16_t)traffic_id); } if (r != 0) { @@ -1001,7 +960,7 @@ TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *dat * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t *answer, void *data) { const char *filename; SCStat st; @@ -1069,7 +1028,7 @@ static int reload_cnt = 1; * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketReloadTenant(json_t *cmd, json_t *answer, void *data) { const char *filename = NULL; SCStat st; @@ -1165,7 +1124,7 @@ TmEcode UnixSocketReloadTenants(json_t *cmd, json_t *answer, void *data) * \param answer the json_t object that has to be used to answer * \param data pointer to data defining the context here a PcapCommand:: */ -TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t *answer, void *data) { if (!(DetectEngineMultiTenantEnabled())) { SCLogInfo("error: multi-tenant support not enabled"); @@ -1218,7 +1177,7 @@ TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) * \param cmd the content of command Arguments as a json_t object * \param answer the json_t object that has to be used to answer */ -TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused) +TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t *answer, void *data_usused) { /* 1 get ip address */ json_t *jarg = json_object_get(cmd, "ipaddress"); @@ -1295,7 +1254,7 @@ TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused) * \param cmd the content of command Arguments as a json_t object * \param answer the json_t object that has to be used to answer */ -TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused) +TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t *answer, void *data_unused) { /* 1 get ip address */ json_t *jarg = json_object_get(cmd, "ipaddress"); @@ -1364,11 +1323,12 @@ TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused) * \param answer the json_t object that has to be used to answer * * Message looks like: - * {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": "OK"} + * {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": + * "OK"} * * \retval r TM_ECODE_OK or TM_ECODE_FAILED */ -TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused) +TmEcode UnixSocketHostbitList(json_t *cmd, json_t *answer, void *data_unused) { /* 1 get ip address */ json_t *jarg = json_object_get(cmd, "ipaddress"); @@ -1434,8 +1394,8 @@ TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused) json_decref(jdata); if (jarray != NULL) json_decref(jarray); - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } @@ -1465,15 +1425,15 @@ TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused) static void MemcapBuildValue(uint64_t val, char *str, uint32_t str_len) { if ((val / (1024 * 1024 * 1024)) != 0) { - snprintf(str, str_len, "%"PRIu64"gb", val / (1024*1024*1024)); + snprintf(str, str_len, "%" PRIu64 "gb", val / (1024 * 1024 * 1024)); } else if ((val / (1024 * 1024)) != 0) { - snprintf(str, str_len, "%"PRIu64"mb", val / (1024*1024)); + snprintf(str, str_len, "%" PRIu64 "mb", val / (1024 * 1024)); } else { - snprintf(str, str_len, "%"PRIu64"kb", val / (1024)); + snprintf(str, str_len, "%" PRIu64 "kb", val / (1024)); } } -TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data) +TmEcode UnixSocketSetMemcap(json_t *cmd, json_t *answer, void *data) { char *memcap = NULL; char *value_str = NULL; @@ -1499,8 +1459,8 @@ TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data) "memcap from unix socket: %s", value_str); json_object_set_new(answer, "message", - json_string("error parsing memcap specified, " - "value not changed")); + json_string("error parsing memcap specified, " + "value not changed")); return TM_ECODE_FAILED; } @@ -1510,27 +1470,26 @@ TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data) char message[150]; if (updated) { - snprintf(message, sizeof(message), - "memcap value for '%s' updated: %"PRIu64" %s", - memcaps[i].name, value, - (value == 0) ? "(unlimited)" : ""); + snprintf(message, sizeof(message), "memcap value for '%s' updated: %" PRIu64 " %s", + memcaps[i].name, value, (value == 0) ? "(unlimited)" : ""); json_object_set_new(answer, "message", json_string(message)); return TM_ECODE_OK; } else { if (value == 0) { - snprintf(message, sizeof(message), - "Unlimited value is not allowed for '%s'", memcaps[i].name); + snprintf(message, sizeof(message), "Unlimited value is not allowed for '%s'", + memcaps[i].name); } else { if (memcaps[i].GetMemuseFunc()) { char memuse[50]; MemcapBuildValue(memcaps[i].GetMemuseFunc(), memuse, sizeof(memuse)); snprintf(message, sizeof(message), - "memcap value specified for '%s' is less than the memory in use: %s", - memcaps[i].name, memuse); + "memcap value specified for '%s' is less than the memory in use: " + "%s", + memcaps[i].name, memuse); } else { snprintf(message, sizeof(message), - "memcap value specified for '%s' is less than the memory in use", - memcaps[i].name); + "memcap value specified for '%s' is less than the memory in use", + memcaps[i].name); } } json_object_set_new(answer, "message", json_string(message)); @@ -1540,7 +1499,7 @@ TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data) } json_object_set_new(answer, "message", - json_string("Memcap value not found. Use 'memcap-list' to show all")); + json_string("Memcap value not found. Use 'memcap-list' to show all")); return TM_ECODE_FAILED; } @@ -1562,8 +1521,8 @@ TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data) uint64_t val = memcaps[i].GetFunc(); json_t *jobj = json_object(); if (jobj == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } @@ -1580,7 +1539,7 @@ TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data) } json_object_set_new(answer, "message", - json_string("Memcap value not found. Use 'memcap-list' to show all")); + json_string("Memcap value not found. Use 'memcap-list' to show all")); return TM_ECODE_FAILED; } @@ -1590,8 +1549,8 @@ TmEcode UnixSocketShowAllMemcap(json_t *cmd, json_t *answer, void *data) int i; if (jmemcaps == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json array creation")); + json_object_set_new( + answer, "message", json_string("internal error at json array creation")); return TM_ECODE_FAILED; } @@ -1599,8 +1558,8 @@ TmEcode UnixSocketShowAllMemcap(json_t *cmd, json_t *answer, void *data) json_t *jobj = json_object(); if (jobj == NULL) { json_decref(jmemcaps); - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } char str[50]; @@ -1681,7 +1640,8 @@ static int RunModeUnixSocketMaster(void) SCCtrlMutexInit(&unix_manager_pcap_last_processed_mutex, NULL); UnixManagerRegisterCommand("pcap-file", UnixSocketAddPcapFile, pcapcmd, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("pcap-file-continuous", UnixSocketAddPcapFileContinuous, pcapcmd, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand( + "pcap-file-continuous", UnixSocketAddPcapFileContinuous, pcapcmd, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("pcap-file-number", UnixSocketPcapFilesNumber, pcapcmd, 0); UnixManagerRegisterCommand("pcap-file-list", UnixSocketPcapFilesList, pcapcmd, 0); UnixManagerRegisterCommand("pcap-last-processed", UnixSocketPcapLastProcessed, pcapcmd, 0); @@ -1701,7 +1661,3 @@ int RunModeUnixSocketIsActive(void) { return unix_socket_mode_is_running; } - - - - diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index af0651f5910b..0366af945649 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -33,21 +33,21 @@ TmEcode UnixSocketPcapFile(TmEcode tm, struct timespec *last_processed); float MemcapsGetPressure(void); #ifdef BUILD_UNIX_SOCKET -TmEcode UnixSocketDatasetAdd(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketDatasetRemove(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketDatasetAdd(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketDatasetRemove(json_t *cmd, json_t *answer, void *data); TmEcode UnixSocketDatasetDump(json_t *cmd, json_t *answer, void *data); TmEcode UnixSocketDatasetClear(json_t *cmd, json_t *answer, void *data); TmEcode UnixSocketDatasetLookup(json_t *cmd, json_t *answer, void *data); -TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketReloadTenant(json_t *cmd, json_t *answer, void *data); TmEcode UnixSocketReloadTenants(json_t *cmd, json_t *answer, void *data); -TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data); -TmEcode UnixSocketSetMemcap(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketHostbitList(json_t *cmd, json_t *answer, void *data); +TmEcode UnixSocketSetMemcap(json_t *cmd, json_t *answer, void *data); TmEcode UnixSocketShowMemcap(json_t *cmd, json_t *answer, void *data); TmEcode UnixSocketShowAllMemcap(json_t *cmd, json_t *answer, void *data); TmEcode UnixSocketGetFlowStatsById(json_t *cmd, json_t *answer, void *data); diff --git a/src/runmode-windivert.c b/src/runmode-windivert.c index a4514270e964..2fc159cbd10b 100644 --- a/src/runmode-windivert.c +++ b/src/runmode-windivert.c @@ -28,14 +28,14 @@ #include "conf.h" #include "runmodes.h" #include "runmode-windivert.h" -#include "output.h" +#include "output/output.h" -#include "util-affinity.h" -#include "util-cpu.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-runmodes.h" -#include "util-time.h" +#include "util/affinity.h" +#include "util/cpu.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/runmodes.h" +#include "util/time.h" const char *RunModeIpsWinDivertGetDefaultMode(void) { @@ -58,8 +58,8 @@ int RunModeIpsWinDivertAutoFp(void) LiveDeviceHasNoStats(); - ret = RunModeSetIPSAutoFp(WinDivertGetThread, "ReceiveWinDivert", - "VerdictWinDivert", "DecodeWinDivert"); + ret = RunModeSetIPSAutoFp( + WinDivertGetThread, "ReceiveWinDivert", "VerdictWinDivert", "DecodeWinDivert"); #endif /* WINDIVERT */ return ret; } diff --git a/src/runmodes.c b/src/runmodes.c index 852155332d75..e42e6a3dcb13 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -28,11 +28,11 @@ #include "detect-engine-mpm.h" #include "app-layer-parser.h" #include "tm-threads.h" -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-byte.h" -#include "util-affinity.h" +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/byte.h" +#include "util/affinity.h" #include "conf.h" #include "queue.h" #include "runmodes.h" @@ -51,16 +51,16 @@ #include "runmode-pfring.h" #include "runmode-unix-socket.h" #include "runmode-windivert.h" -#include "util-unittest.h" -#include "util-misc.h" -#include "util-plugin.h" +#include "util/unittest.h" +#include "util/misc.h" +#include "util/plugin.h" -#include "output.h" +#include "output/output.h" #include "alert-fastlog.h" #include "alert-debuglog.h" -#include "log-httplog.h" +#include "app-layer/http/log-httplog.h" #include "source-pfring.h" @@ -117,8 +117,7 @@ typedef struct OutputFreeList_ { TAILQ_ENTRY(OutputFreeList_) entries; } OutputFreeList; -static TAILQ_HEAD(, OutputFreeList_) output_free_list = - TAILQ_HEAD_INITIALIZER(output_free_list); +static TAILQ_HEAD(, OutputFreeList_) output_free_list = TAILQ_HEAD_INITIALIZER(output_free_list); /** * \internal @@ -206,7 +205,6 @@ static RunMode *RunModeGetCustomMode(enum RunModes runmode, const char *custom_m return NULL; } - /** * Return the running mode * @@ -269,29 +267,23 @@ void RunModeListRunmodes(void) printf("------------------------------------- Runmodes -------------------" "-----------------------\n"); - printf("| %-17s | %-17s | %-10s \n", - "RunMode Type", "Custom Mode ", "Description"); + printf("| %-17s | %-17s | %-10s \n", "RunMode Type", "Custom Mode ", "Description"); printf("|-----------------------------------------------------------------" "-----------------------\n"); int i = RUNMODE_UNKNOWN + 1; int j = 0; - for ( ; i < RUNMODE_USER_MAX; i++) { + for (; i < RUNMODE_USER_MAX; i++) { int mode_displayed = 0; for (j = 0; j < runmodes[i].cnt; j++) { if (mode_displayed == 1) { printf("| ----------------------------------------------" "-----------------------\n"); RunMode *runmode = &runmodes[i].runmodes[j]; - printf("| %-17s | %-17s | %-27s \n", - "", - runmode->name, - runmode->description); + printf("| %-17s | %-17s | %-27s \n", "", runmode->name, runmode->description); } else { RunMode *runmode = &runmodes[i].runmodes[j]; - printf("| %-17s | %-17s | %-27s \n", - RunModeTranslateModeToName(runmode->runmode), - runmode->name, - runmode->description); + printf("| %-17s | %-17s | %-27s \n", RunModeTranslateModeToName(runmode->runmode), + runmode->name, runmode->description); } if (mode_displayed == 0) mode_displayed = 1; @@ -477,8 +469,6 @@ int RunModeNeedsBypassManager(void) return g_runmode_needs_bypass; } - - /** * \brief Registers a new runmode. * @@ -497,8 +487,8 @@ void RunModeRegisterNewRunMode(enum RunModes runmode, const char *name, const ch name); } - void *ptmp = SCRealloc(runmodes[runmode].runmodes, - (runmodes[runmode].cnt + 1) * sizeof(RunMode)); + void *ptmp = + SCRealloc(runmodes[runmode].runmodes, (runmodes[runmode].cnt + 1) * sizeof(RunMode)); if (ptmp == NULL) { SCFree(runmodes[runmode].runmodes); runmodes[runmode].runmodes = NULL; @@ -573,7 +563,7 @@ bool IsRunModeSystem(enum RunModes run_mode_to_check) bool IsRunModeOffline(enum RunModes run_mode_to_check) { - switch(run_mode_to_check) { + switch (run_mode_to_check) { case RUNMODE_CONF_TEST: case RUNMODE_PCAP_FILE: case RUNMODE_ERF_FILE: @@ -626,16 +616,14 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu { /* flow logger doesn't run in the packet path */ if (module->FlowLogFunc) { - OutputRegisterFlowLogger(module->name, module->FlowLogFunc, - output_ctx, module->ThreadInit, module->ThreadDeinit, - module->ThreadExitPrintStats); + OutputRegisterFlowLogger(module->name, module->FlowLogFunc, output_ctx, module->ThreadInit, + module->ThreadDeinit, module->ThreadExitPrintStats); return; } /* stats logger doesn't run in the packet path */ if (module->StatsLogFunc) { - OutputRegisterStatsLogger(module->name, module->StatsLogFunc, - output_ctx,module->ThreadInit, module->ThreadDeinit, - module->ThreadExitPrintStats); + OutputRegisterStatsLogger(module->name, module->StatsLogFunc, output_ctx, + module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); return; } @@ -645,16 +633,14 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu if (module->PacketLogFunc) { SCLogDebug("%s is a packet logger", module->name); - OutputRegisterPacketLogger(module->logger_id, module->name, - module->PacketLogFunc, module->PacketConditionFunc, output_ctx, - module->ThreadInit, module->ThreadDeinit, - module->ThreadExitPrintStats); + OutputRegisterPacketLogger(module->logger_id, module->name, module->PacketLogFunc, + module->PacketConditionFunc, output_ctx, module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); } else if (module->TxLogFunc) { SCLogDebug("%s is a tx logger", module->name); - OutputRegisterTxLogger(module->logger_id, module->name, module->alproto, - module->TxLogFunc, output_ctx, module->tc_log_progress, - module->ts_log_progress, module->TxLogCondition, - module->ThreadInit, module->ThreadDeinit, + OutputRegisterTxLogger(module->logger_id, module->name, module->alproto, module->TxLogFunc, + output_ctx, module->tc_log_progress, module->ts_log_progress, + module->TxLogCondition, module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); /* Not used with wild card loggers */ if (module->alproto != ALPROTO_UNKNOWN) { @@ -662,22 +648,19 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } else if (module->FiledataLogFunc) { SCLogDebug("%s is a filedata logger", module->name); - OutputRegisterFiledataLogger(module->logger_id, module->name, - module->FiledataLogFunc, output_ctx, module->ThreadInit, - module->ThreadDeinit, module->ThreadExitPrintStats); + OutputRegisterFiledataLogger(module->logger_id, module->name, module->FiledataLogFunc, + output_ctx, module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); filedata_logger_count++; } else if (module->FileLogFunc) { SCLogDebug("%s is a file logger", module->name); - OutputRegisterFileLogger(module->logger_id, module->name, - module->FileLogFunc, output_ctx, module->ThreadInit, - module->ThreadDeinit, module->ThreadExitPrintStats); + OutputRegisterFileLogger(module->logger_id, module->name, module->FileLogFunc, output_ctx, + module->ThreadInit, module->ThreadDeinit, module->ThreadExitPrintStats); file_logger_count++; } else if (module->StreamingLogFunc) { SCLogDebug("%s is a streaming logger", module->name); - OutputRegisterStreamingLogger(module->logger_id, module->name, - module->StreamingLogFunc, output_ctx, module->stream_type, - module->ThreadInit, module->ThreadDeinit, - module->ThreadExitPrintStats); + OutputRegisterStreamingLogger(module->logger_id, module->name, module->StreamingLogFunc, + output_ctx, module->stream_type, module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); } else { SCLogError("Unknown logger type: name=%s", module->name); } @@ -692,7 +675,7 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) } ConfNode *type = NULL; - TAILQ_FOREACH(type, &types->head, next) { + TAILQ_FOREACH (type, &types->head, next) { int sub_count = 0; char subname[256]; @@ -707,8 +690,7 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) ConfNode *sub_output_config = ConfNodeLookupChild(type, type->val); if (sub_output_config != NULL) { - const char *enabled = ConfNodeLookupChildValue( - sub_output_config, "enabled"); + const char *enabled = ConfNodeLookupChildValue(sub_output_config, "enabled"); if (enabled != NULL && !ConfValIsTrue(enabled)) { continue; } @@ -716,7 +698,7 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) /* Now setup all registers logger of this name. */ OutputModule *sub_module; - TAILQ_FOREACH(sub_module, &output_modules, entries) { + TAILQ_FOREACH (sub_module, &output_modules, entries) { if (strcmp(subname, sub_module->conf_name) == 0) { sub_count++; @@ -729,15 +711,13 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) } /* pass on parent output_ctx */ - OutputInitResult result = - sub_module->InitSubFunc(sub_output_config, parent_ctx); + OutputInitResult result = sub_module->InitSubFunc(sub_output_config, parent_ctx); if (!result.ok || result.ctx == NULL) { FatalError("unable to initialize sub-module %s", subname); } AddOutputToFreeList(sub_module, result.ctx); - SetupOutput(sub_module->name, sub_module, - result.ctx); + SetupOutput(sub_module->name, sub_module, result.ctx); } } @@ -756,14 +736,14 @@ static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx) BUG_ON(lua_module == NULL); ConfNode *scripts = ConfNodeLookupChild(conf, "scripts"); - BUG_ON(scripts == NULL); //TODO + BUG_ON(scripts == NULL); // TODO OutputModule *m; - TAILQ_FOREACH(m, &parent_ctx->submodules, entries) { + TAILQ_FOREACH (m, &parent_ctx->submodules, entries) { SCLogDebug("m %p %s:%s", m, m->name, m->conf_name); ConfNode *script = NULL; - TAILQ_FOREACH(script, &scripts->head, next) { + TAILQ_FOREACH (script, &scripts->head, next) { SCLogDebug("script %s", script->val); if (strcmp(script->val, m->conf_name) == 0) { break; @@ -803,7 +783,7 @@ void RunModeInitializeOutputs(void) memset(&logger_bits, 0, sizeof(logger_bits)); - TAILQ_FOREACH(output, &outputs->head, next) { + TAILQ_FOREACH (output, &outputs->head, next) { output_config = ConfNodeLookupChild(output, output->val); if (output_config == NULL) { @@ -851,7 +831,7 @@ void RunModeInitializeOutputs(void) OutputModule *module; int count = 0; - TAILQ_FOREACH(module, &output_modules, entries) { + TAILQ_FOREACH (module, &output_modules, entries) { if (strcmp(module->conf_name, output->val) != 0) { continue; } @@ -904,7 +884,7 @@ void RunModeInitializeOutputs(void) * to be started using 'tls-log' config as own config */ SCLogWarning("Please use 'tls-store' in YAML to configure TLS storage"); - TAILQ_FOREACH(output, &outputs->head, next) { + TAILQ_FOREACH (output, &outputs->head, next) { output_config = ConfNodeLookupChild(output, output->val); if (strcmp(output->val, "tls-log") == 0) { @@ -962,15 +942,14 @@ void RunModeInitializeOutputs(void) (g_filedata_logger_enabled); SCLogDebug("tcp %d udp %d", tcp, udp); - SCLogDebug("logger for %s: %s %s", AppProtoToString(a), - tcp ? "true" : "false", udp ? "true" : "false"); + SCLogDebug("logger for %s: %s %s", AppProtoToString(a), tcp ? "true" : "false", + udp ? "true" : "false"); SCLogDebug("logger bits for %s: %08x", AppProtoToString(a), logger_bits[a]); if (tcp) AppLayerParserRegisterLoggerBits(IPPROTO_TCP, a, logger_bits[a]); if (udp) AppLayerParserRegisterLoggerBits(IPPROTO_UDP, a, logger_bits[a]); - } OutputSetupActiveLoggers(); } diff --git a/src/runmodes.h b/src/runmodes.h index 668896dc17c5..2b7cdb401b22 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -81,7 +81,8 @@ const char *RunModeGetMainMode(void); void RunModeListRunmodes(void); void RunModeEngineIsIPS(int capture_mode, const char *runmode, const char *capture_plugin_name); -void RunModeDispatch(int, const char *, const char *capture_plugin_name, const char *capture_plugin_args); +void RunModeDispatch( + int, const char *, const char *capture_plugin_name, const char *capture_plugin_args); void RunModeRegisterRunModes(void); void RunModeRegisterNewRunMode(enum RunModes, const char *, const char *, int (*RunModeFunc)(void), void (*RunModeIsIPSEnabled)(void)); diff --git a/src/rust-context.c b/src/rust-context.c index e63e12ce002d..cc665f0cbc85 100644 --- a/src/rust-context.c +++ b/src/rust-context.c @@ -19,8 +19,8 @@ #include "rust-context.h" #include "app-layer-parser.h" #include "app-layer-register.h" -#include "app-layer-htp-range.h" -#include "app-layer-htp-file.h" +#include "app-layer/http/parser-range.h" +#include "app-layer/http/parser-file.h" const SuricataContext suricata_context = { SCLogMessage, diff --git a/src/rust-context.h b/src/rust-context.h index ba99ac6b7286..707cab28bb7e 100644 --- a/src/rust-context.h +++ b/src/rust-context.h @@ -22,14 +22,14 @@ #include "detect.h" #include "detect-engine-state.h" //DetectEngineState -#include "app-layer-krb5.h" //KRB5State, KRB5Transaction -#include "app-layer-ike.h" //IKEState, IKETransaction -#include "app-layer-ntp.h" //NTPState, NTPTransaction -#include "app-layer-snmp.h" //SNMPState, SNMPTransaction -#include "app-layer-tftp.h" //TFTPState, TFTPTransaction +#include "app-layer/krb5/parser.h" //KRB5State, KRB5Transaction +#include "app-layer/ike/parser.h" //IKEState, IKETransaction +#include "app-layer/ntp/parser.h" //NTPState, NTPTransaction +#include "app-layer/snmp/parser.h" //SNMPState, SNMPTransaction +#include "app-layer/tftp/parser.h" //TFTPState, TFTPTransaction -#include "util-debug.h" -#include "util-file.h" +#include "util/debug.h" +#include "util/file.h" // hack for include orders cf SCSha256 typedef struct HttpRangeContainerBlock HttpRangeContainerBlock; @@ -40,8 +40,7 @@ typedef struct SuricataContext_ { SCError (*SCLogMessage)(const SCLogLevel, const char *, const unsigned int, const char *, const char *, const char *message); void (*DetectEngineStateFree)(DetectEngineState *); - void (*AppLayerDecoderEventsSetEventRaw)(AppLayerDecoderEvents **, - uint8_t); + void (*AppLayerDecoderEventsSetEventRaw)(AppLayerDecoderEvents **, uint8_t); void (*AppLayerDecoderEventsFreeEvents)(AppLayerDecoderEvents **); void (*AppLayerParserTriggerRawStreamReassembly)(Flow *, int direction); @@ -49,9 +48,9 @@ typedef struct SuricataContext_ { bool (*HTPFileCloseHandleRange)(const StreamingBufferConfig *sbcfg, FileContainer *, const uint16_t, HttpRangeContainerBlock *, const uint8_t *, uint32_t); - int (*FileOpenFileWithId)(FileContainer *, const StreamingBufferConfig *, - uint32_t track_id, const uint8_t *name, uint16_t name_len, - const uint8_t *data, uint32_t data_len, uint16_t flags); + int (*FileOpenFileWithId)(FileContainer *, const StreamingBufferConfig *, uint32_t track_id, + const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, + uint16_t flags); int (*FileCloseFileById)(FileContainer *, const StreamingBufferConfig *, uint32_t track_id, const uint8_t *data, uint32_t data_len, uint16_t flags); int (*FileAppendDataById)(FileContainer *, const StreamingBufferConfig *, uint32_t track_id, diff --git a/src/rust.h b/src/rust.h index 12c90e67f30d..a85faf930ad8 100644 --- a/src/rust.h +++ b/src/rust.h @@ -18,7 +18,7 @@ #ifndef __RUST_H__ #define __RUST_H__ -#include "util-file.h" +#include "util/file.h" // hack for include orders cf SCSha256 typedef struct HttpRangeContainerBlock HttpRangeContainerBlock; @@ -26,7 +26,7 @@ typedef struct HttpRangeContainerBlock HttpRangeContainerBlock; #include "rust-bindings.h" #define JB_SET_STRING(jb, key, val) jb_set_formatted((jb), "\"" key "\":\"" val "\"") -#define JB_SET_TRUE(jb, key) jb_set_formatted((jb), "\"" key "\":true") -#define JB_SET_FALSE(jb, key) jb_set_formatted((jb), "\"" key "\":false") +#define JB_SET_TRUE(jb, key) jb_set_formatted((jb), "\"" key "\":true") +#define JB_SET_FALSE(jb, key) jb_set_formatted((jb), "\"" key "\":false") #endif /* !__RUST_H__ */ diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 3c783a149029..3abe0da9721f 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -31,7 +31,7 @@ */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 -#define SC_PCAP_DONT_INCLUDE_PCAP_H 1 +#define SC_PCAP_DONT_INCLUDE_PCAP_H 1 #include "suricata-common.h" #include "suricata.h" #include "packet.h" @@ -44,22 +44,22 @@ #include "tm-threads.h" #include "tm-threads-common.h" #include "conf.h" -#include "util-cpu.h" -#include "util-datalink.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-ebpf.h" -#include "util-error.h" -#include "util-privs.h" -#include "util-optimize.h" -#include "util-checksum.h" -#include "util-ioctl.h" -#include "util-host-info.h" +#include "util/cpu.h" +#include "util/datalink.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/ebpf.h" +#include "util/error.h" +#include "util/privs.h" +#include "util/optimize.h" +#include "util/checksum.h" +#include "util/ioctl.h" +#include "util/host-info.h" #include "tmqh-packetpool.h" #include "source-af-packet.h" #include "runmodes.h" #include "flow-storage.h" -#include "util-validate.h" +#include "util/validate.h" #include "action-globals.h" #ifdef HAVE_AF_PACKET @@ -90,7 +90,7 @@ struct bpf_program { #include #endif -#include "util-bpf.h" +#include "util/bpf.h" #if HAVE_LINUX_IF_ETHER_H #include @@ -124,7 +124,7 @@ extern uint16_t max_pending_packets; TmEcode NoAFPSupportExit(ThreadVars *, const void *, void **); -void TmModuleReceiveAFPRegister (void) +void TmModuleReceiveAFPRegister(void) { tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; tmm_modules[TMM_RECEIVEAFP].ThreadInit = NoAFPSupportExit; @@ -138,7 +138,7 @@ void TmModuleReceiveAFPRegister (void) /** * \brief Registration Function for DecodeAFP. */ -void TmModuleDecodeAFPRegister (void) +void TmModuleDecodeAFPRegister(void) { tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; tmm_modules[TMM_DECODEAFP].ThreadInit = NoAFPSupportExit; @@ -166,9 +166,9 @@ TmEcode NoAFPSupportExit(ThreadVars *tv, const void *initdata, void **data) #define AFP_IFACE_NAME_LENGTH 48 #define AFP_STATE_DOWN 0 -#define AFP_STATE_UP 1 +#define AFP_STATE_UP 1 -#define AFP_RECONNECT_TIMEOUT 500000 +#define AFP_RECONNECT_TIMEOUT 500000 #define AFP_DOWN_COUNTER_INTERVAL 40 #define POLL_TIMEOUT 100 @@ -261,8 +261,7 @@ static int AFPXDPBypassCallback(Packet *p); /** * \brief Structure to hold thread specific variables. */ -typedef struct AFPThreadVars_ -{ +typedef struct AFPThreadVars_ { union AFPRing { union thdr **v2; struct iovec *v3; @@ -373,15 +372,14 @@ static TmEcode DecodeAFP(ThreadVars *, Packet *, void *); static TmEcode AFPSetBPFFilter(AFPThreadVars *ptv); static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose); static int AFPGetDevFlags(int fd, const char *ifname); -static int AFPDerefSocket(AFPPeer* peer); -static int AFPRefSocket(AFPPeer* peer); - +static int AFPDerefSocket(AFPPeer *peer); +static int AFPRefSocket(AFPPeer *peer); /** * \brief Registration Function for RecieveAFP. * \todo Unit tests are needed for this module. */ -void TmModuleReceiveAFPRegister (void) +void TmModuleReceiveAFPRegister(void) { tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit; @@ -392,7 +390,6 @@ void TmModuleReceiveAFPRegister (void) tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = ReceiveAFPThreadDeinit; tmm_modules[TMM_RECEIVEAFP].cap_flags = SC_CAP_NET_RAW; tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM; - } /** @@ -412,7 +409,7 @@ typedef struct AFPPeersList_ { TAILQ_HEAD(, AFPPeer_) peers; /**< Head of list of fragments. */ int cnt; int peered; - int turn; /**< Next value for initialisation order */ + int turn; /**< Next value for initialisation order */ SC_ATOMIC_DECLARE(int, reached); /**< Counter used to synchronize start */ } AFPPeersList; @@ -445,7 +442,6 @@ static void AFPPeerClean(AFPPeer *peer) AFPPeersList peerslist; - /** * \brief Init the global list of ::AFPPeer */ @@ -457,7 +453,7 @@ TmEcode AFPPeersListInit(void) peerslist.cnt = 0; peerslist.turn = 0; SC_ATOMIC_INIT(peerslist.reached); - (void) SC_ATOMIC_SET(peerslist.reached, 0); + (void)SC_ATOMIC_SET(peerslist.reached, 0); SCReturnInt(TM_ECODE_OK); } @@ -469,7 +465,7 @@ TmEcode AFPPeersListInit(void) TmEcode AFPPeersListCheck(void) { #define AFP_PEERS_MAX_TRY 4 -#define AFP_PEERS_WAIT 20000 +#define AFP_PEERS_WAIT 20000 int try = 0; SCEnter(); while (try < AFP_PEERS_MAX_TRY) { @@ -518,7 +514,7 @@ static TmEcode AFPPeersListAdd(AFPThreadVars *ptv) peerslist.cnt++; /* Iter to find a peer */ - TAILQ_FOREACH(pitem, &peerslist.peers, next) { + TAILQ_FOREACH (pitem, &peerslist.peers, next) { if (pitem->peer) continue; if (strcmp(pitem->iface, ptv->out_iface)) @@ -599,7 +595,7 @@ void AFPPeersListClean(void) * \brief Registration Function for DecodeAFP. * \todo Unit tests are needed for this module. */ -void TmModuleDecodeAFPRegister (void) +void TmModuleDecodeAFPRegister(void) { tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; tmm_modules[TMM_DECODEAFP].ThreadInit = DecodeAFPThreadInit; @@ -610,23 +606,20 @@ void TmModuleDecodeAFPRegister (void) tmm_modules[TMM_DECODEAFP].flags = TM_FLAG_DECODE_TM; } - static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose); static inline void AFPDumpCounters(AFPThreadVars *ptv) { #ifdef PACKET_STATISTICS struct tpacket_stats kstats; - socklen_t len = sizeof (struct tpacket_stats); - if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, - &kstats, &len) > -1) { - SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", - ptv->tv->name, + socklen_t len = sizeof(struct tpacket_stats); + if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, &kstats, &len) > -1) { + SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", ptv->tv->name, kstats.tp_packets, kstats.tp_drops); StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, kstats.tp_packets); StatsAddUI64(ptv->tv, ptv->capture_kernel_drops, kstats.tp_drops); - (void) SC_ATOMIC_ADD(ptv->livedev->drop, (uint64_t) kstats.tp_drops); - (void) SC_ATOMIC_ADD(ptv->livedev->pkts, (uint64_t) kstats.tp_packets); + (void)SC_ATOMIC_ADD(ptv->livedev->drop, (uint64_t)kstats.tp_drops); + (void)SC_ATOMIC_ADD(ptv->livedev->pkts, (uint64_t)kstats.tp_packets); const uint64_t value = SC_ATOMIC_GET(ptv->mpeer->send_errors); if (value > ptv->send_errors_logged) { @@ -939,7 +932,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv) if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { return AFPSuriFailure(ptv, h); } -next_frame: + next_frame: if (++ptv->frame_offset >= ptv->req.v2.tp_frame_nr) { ptv->frame_offset = 0; /* Get out of loop to be sure we will reach maintenance tasks */ @@ -959,7 +952,8 @@ static inline void AFPFlushBlock(struct tpacket_block_desc *pbd) pbd->hdr.bh1.block_status = TP_STATUS_KERNEL; } -static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc *pbd, struct tpacket3_hdr *ppd) +static inline int AFPParsePacketV3( + AFPThreadVars *ptv, struct tpacket_block_desc *pbd, struct tpacket3_hdr *ppd) { Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL) { @@ -990,15 +984,13 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc /* Timestamp */ p->ts = (SCTime_t){ .secs = ppd->tp_sec, .usecs = ppd->tp_nsec / 1000 }; - SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", - GET_PKT_LEN(p), p, GET_PKT_DATA(p)); + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", GET_PKT_LEN(p), p, GET_PKT_DATA(p)); /* We only check for checksum disable */ if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { - if (ChecksumAutoModeCheck(ptv->pkts, - SC_ATOMIC_GET(ptv->livedev->pkts), + if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE; p->flags |= PKT_IGNORE_CHECKSUM; @@ -1097,7 +1089,7 @@ static int AFPReadFromRingV3(AFPThreadVars *ptv) * * \retval O in case of failure, 1 in case of success */ -static int AFPRefSocket(AFPPeer* peer) +static int AFPRefSocket(AFPPeer *peer) { if (unlikely(peer == NULL)) return 0; @@ -1106,13 +1098,12 @@ static int AFPRefSocket(AFPPeer* peer) return 1; } - /** * \brief Dereference socket * * \retval 1 if socket is still alive, 0 if not */ -static int AFPDerefSocket(AFPPeer* peer) +static int AFPDerefSocket(AFPPeer *peer) { if (peer == NULL) return 1; @@ -1167,8 +1158,8 @@ static void AFPSwitchState(AFPThreadVars *ptv, uint8_t state) } } -static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv, - uint64_t *discarded_pkts) +static int AFPReadAndDiscardFromRing( + AFPThreadVars *ptv, struct timeval *synctv, uint64_t *discarded_pkts) { if (unlikely(suricata_ctl_flags != 0)) { return 1; @@ -1181,10 +1172,10 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv, (struct tpacket_block_desc *)ptv->ring.v3[ptv->frame_offset].iov_base; *discarded_pkts += pbd->hdr.bh1.num_pkts; struct tpacket3_hdr *ppd = - (struct tpacket3_hdr *)((uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt); + (struct tpacket3_hdr *)((uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt); if (((time_t)ppd->tp_sec > synctv->tv_sec) || ((time_t)ppd->tp_sec == synctv->tv_sec && - (suseconds_t) (ppd->tp_nsec / 1000) > (suseconds_t)synctv->tv_usec)) { + (suseconds_t)(ppd->tp_nsec / 1000) > (suseconds_t)synctv->tv_usec)) { ret = 1; } AFPFlushBlock(pbd); @@ -1205,7 +1196,7 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv, if (((time_t)h.h2->tp_sec > synctv->tv_sec) || ((time_t)h.h2->tp_sec == synctv->tv_sec && - (suseconds_t) (h.h2->tp_nsec / 1000) > synctv->tv_usec)) { + (suseconds_t)(h.h2->tp_nsec / 1000) > synctv->tv_usec)) { return 1; } @@ -1242,13 +1233,12 @@ static int AFPSynchronizeStart(AFPThreadVars *ptv, uint64_t *discarded_pkts) while (1) { int r = poll(&fds, 1, POLL_TIMEOUT); - if (r > 0 && - (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { + if (r > 0 && (fds.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))) { SCLogWarning("%s: poll failed %02x", ptv->iface, fds.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)); return 0; } else if (r > 0) { - if (AFPPeersListStarted() && synctv.tv_sec == (time_t) 0xffffffff) { + if (AFPPeersListStarted() && synctv.tv_sec == (time_t)0xffffffff) { gettimeofday(&synctv, NULL); } r = AFPReadAndDiscardFromRing(ptv, &synctv, discarded_pkts); @@ -1260,7 +1250,7 @@ static int AFPSynchronizeStart(AFPThreadVars *ptv, uint64_t *discarded_pkts) case -1: return r; } - /* no packets */ + /* no packets */ } else if (r == 0 && AFPPeersListStarted()) { SCLogDebug("Starting to read on %s", ptv->tv->name); return 1; @@ -1315,7 +1305,7 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; time_t current_time; - int (*AFPReadFunc) (AFPThreadVars *); + int (*AFPReadFunc)(AFPThreadVars *); uint64_t discarded_pkts = 0; ptv->slot = s->slot_next; @@ -1353,19 +1343,16 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) /* let's reset counter as we will start the capture at the * next function call */ #ifdef PACKET_STATISTICS - struct tpacket_stats kstats; - socklen_t len = sizeof (struct tpacket_stats); - if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, - &kstats, &len) > -1) { - uint64_t pkts = 0; - SCLogDebug("(%s) Kernel socket startup: Packets %" PRIu32 - ", dropped %" PRIu32 "", - ptv->tv->name, - kstats.tp_packets, kstats.tp_drops); - pkts = kstats.tp_packets - discarded_pkts - kstats.tp_drops; - StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, pkts); - (void) SC_ATOMIC_ADD(ptv->livedev->pkts, pkts); - } + struct tpacket_stats kstats; + socklen_t len = sizeof(struct tpacket_stats); + if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, &kstats, &len) > -1) { + uint64_t pkts = 0; + SCLogDebug("(%s) Kernel socket startup: Packets %" PRIu32 ", dropped %" PRIu32 "", + ptv->tv->name, kstats.tp_packets, kstats.tp_drops); + pkts = kstats.tp_packets - discarded_pkts - kstats.tp_drops; + StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, pkts); + (void)SC_ATOMIC_ADD(ptv->livedev->pkts, pkts); + } #endif } @@ -1406,8 +1393,7 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) break; } - if (r > 0 && - (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { + if (r > 0 && (fds.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))) { StatsIncr(ptv->tv, ptv->capture_afp_poll_signal); if (fds.revents & (POLLHUP | POLLRDHUP)) { AFPSwitchState(ptv, AFP_STATE_DOWN); @@ -1489,7 +1475,6 @@ static int AFPGetDevFlags(int fd, const char *ifname) return ifr.ifr_flags; } - static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose) { struct ifreq ifr; @@ -1539,7 +1524,7 @@ int AFPGetLinkType(const char *ifname) return LINKTYPE_RAW; } - ltype = AFPGetDevLinktype(fd, ifname); + ltype = AFPGetDevLinktype(fd, ifname); close(fd); DatalinkSetGlobalType(ltype); @@ -1584,7 +1569,10 @@ sockaddr_ll) + ETH_HLEN) - ETH_HLEN); } } - ptv->req.v2.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); + ptv->req.v2.tp_frame_size = TPACKET_ALIGN( + snaplen + + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - + ETH_HLEN); ptv->req.v2.tp_block_size = getpagesize() << order; int frames_per_block = ptv->req.v2.tp_block_size / ptv->req.v2.tp_frame_size; if (frames_per_block == 0) { @@ -1618,7 +1606,10 @@ static int AFPComputeRingParamsV3(AFPThreadVars *ptv) } } - ptv->req.v3.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); + ptv->req.v3.tp_frame_size = TPACKET_ALIGN( + snaplen + + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - + ETH_HLEN); frames_per_block = ptv->req.v3.tp_block_size / ptv->req.v3.tp_frame_size; if (frames_per_block == 0) { @@ -1672,8 +1663,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) val = TPACKET_V3; } #endif - if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, - sizeof(val)) < 0) { + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) { SCLogError("%s: failed to activate TPACKET_V2/TPACKET_V3 on packet socket: %s", devname, strerror(errno)); return AFP_FATAL_ERROR; @@ -1681,8 +1671,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) #ifdef HAVE_HW_TIMESTAMPING int req = SOF_TIMESTAMPING_RAW_HARDWARE; - if (setsockopt(ptv->socket, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, - sizeof(req)) < 0) { + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_TIMESTAMP, (void *)&req, sizeof(req)) < 0) { SCLogWarning("%s: failed to activate hardware timestamping on packet socket: %s", devname, strerror(errno)); } @@ -1703,8 +1692,8 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) if (AFPComputeRingParamsV3(ptv) != 1) { return AFP_FATAL_ERROR; } - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, - (void *) &ptv->req.v3, sizeof(ptv->req.v3)); + r = setsockopt( + ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *)&ptv->req.v3, sizeof(ptv->req.v3)); if (r < 0) { SCLogError("%s: failed to allocate RX Ring: %s", devname, strerror(errno)); return AFP_FATAL_ERROR; @@ -1717,8 +1706,8 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) return AFP_FATAL_ERROR; } - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, - (void *) &ptv->req, sizeof(ptv->req)); + r = setsockopt( + ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *)&ptv->req, sizeof(ptv->req)); if (r < 0) { if (errno == ENOMEM) { @@ -1752,8 +1741,7 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) mmap_flag = MAP_SHARED; if (ptv->flags & AFP_MMAP_LOCKED) mmap_flag |= MAP_LOCKED; - ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ|PROT_WRITE, - mmap_flag, ptv->socket, 0); + ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ | PROT_WRITE, mmap_flag, ptv->socket, 0); if (ptv->ring_buf == MAP_FAILED) { SCLogError("%s: failed to mmap: %s", devname, strerror(errno)); goto mmap_err; @@ -1782,7 +1770,8 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) for (i = 0; i < ptv->req.v2.tp_block_nr; ++i) { void *base = &(ptv->ring_buf[i * ptv->req.v2.tp_block_size]); unsigned int j; - for (j = 0; j < ptv->req.v2.tp_block_size / ptv->req.v2.tp_frame_size; ++j, ++ptv->frame_offset) { + for (j = 0; j < ptv->req.v2.tp_block_size / ptv->req.v2.tp_frame_size; + ++j, ++ptv->frame_offset) { (((union thdr **)ptv->ring.v2)[ptv->frame_offset]) = base; base += ptv->req.v2.tp_frame_size; } @@ -1817,7 +1806,7 @@ int AFPIsFanoutSupported(uint16_t cluster_id) uint32_t mode = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; uint32_t option = (mode << 16) | cluster_id; - int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); + int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT, (void *)&option, sizeof(option)); close(fd); if (r < 0) { @@ -1925,7 +1914,8 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) memset(&sock_params, 0, sizeof(sock_params)); sock_params.mr_type = PACKET_MR_PROMISC; sock_params.mr_ifindex = bind_address.sll_ifindex; - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP,(void *)&sock_params, sizeof(sock_params)); + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (void *)&sock_params, + sizeof(sock_params)); if (r < 0) { SCLogError("%s: failed to set promisc mode: %s", devname, strerror(errno)); goto socket_err; @@ -1934,8 +1924,8 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) if (ptv->checksum_mode == CHECKSUM_VALIDATION_KERNEL) { int val = 1; - if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val, - sizeof(val)) == -1 && errno != ENOPROTOOPT) { + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1 && + errno != ENOPROTOOPT) { SCLogWarning( "%s: 'kernel' checksum mode not supported, falling back to full mode", devname); ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; @@ -1948,9 +1938,8 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) * Set the socket buffer size to the specified value. */ SCLogPerf("%s: setting socket buffer to %d", devname, ptv->buffer_size); - if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, - &ptv->buffer_size, - sizeof(ptv->buffer_size)) == -1) { + if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, &ptv->buffer_size, + sizeof(ptv->buffer_size)) == -1) { SCLogError("%s: failed to set buffer size to %d: %s", devname, ptv->buffer_size, strerror(errno)); goto socket_err; @@ -1970,14 +1959,13 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) goto socket_err; } - #ifdef HAVE_PACKET_FANOUT /* add bound socket to fanout group */ if (ptv->threads > 1) { uint32_t mode = ptv->cluster_type; uint16_t id = ptv->cluster_id; uint32_t option = (mode << 16) | (id & 0xffff); - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT, (void *)&option, sizeof(option)); if (r < 0) { SCLogError("%s: failed to set fanout mode: %s", devname, strerror(errno)); goto socket_err; @@ -2035,7 +2023,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) { struct bpf_program filter; - struct sock_fprog fcode; + struct sock_fprog fcode; int rc; #ifdef HAVE_PACKET_EBPF @@ -2050,14 +2038,13 @@ TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) SCLogInfo("%s: using BPF '%s'", ptv->iface, ptv->bpf_filter); char errbuf[PCAP_ERRBUF_SIZE]; - if (SCBPFCompile(default_packet_size, /* snaplen_arg */ - ptv->datalink, /* linktype_arg */ - &filter, /* program */ - ptv->bpf_filter, /* const char *buf */ - 1, /* optimize */ - 0, /* mask */ - errbuf, - sizeof(errbuf)) == -1) { + if (SCBPFCompile(default_packet_size, /* snaplen_arg */ + ptv->datalink, /* linktype_arg */ + &filter, /* program */ + ptv->bpf_filter, /* const char *buf */ + 1, /* optimize */ + 0, /* mask */ + errbuf, sizeof(errbuf)) == -1) { SCLogError("%s: failed to compile BPF \"%s\": %s", ptv->iface, ptv->bpf_filter, errbuf); return TM_ECODE_FAILED; } @@ -2066,12 +2053,12 @@ TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) return TM_ECODE_FAILED; } fcode.len = (unsigned short)filter.bf_len; - fcode.filter = (struct sock_filter*)filter.bf_insns; + fcode.filter = (struct sock_filter *)filter.bf_insns; rc = setsockopt(ptv->socket, SOL_SOCKET, SO_ATTACH_FILTER, &fcode, sizeof(fcode)); SCBPFFree(&filter); - if(rc == -1) { + if (rc == -1) { SCLogError("%s: failed to attach filter: %s", ptv->iface, strerror(errno)); return TM_ECODE_FAILED; } @@ -2122,8 +2109,7 @@ static int AFPInsertHalfFlow(int mapd, void *key, unsigned int nr_cpus) return 1; } -static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void* key1, - int family) +static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void *key1, int family) { FlowBypassInfo *fc = FlowGetStorageById(p->flow, GetFlowBypassInfoID()); if (fc) { @@ -2220,13 +2206,12 @@ static int AFPBypassCallback(Packet *p) } else { keys[0]->ip_proto = 0; } - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); return 0; } - keys[1]= SCCalloc(1, sizeof(struct flowv4_keys)); + keys[1] = SCCalloc(1, sizeof(struct flowv4_keys)); if (keys[1] == NULL) { EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET); @@ -2242,8 +2227,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); @@ -2254,8 +2238,7 @@ static int AFPBypassCallback(Packet *p) return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1], AF_INET); } /* For IPv6 case we don't handle extended header in eBPF */ - if (PKT_IS_IPV6(p) && - ((IPV6_GET_NH(p) == IPPROTO_TCP) || (IPV6_GET_NH(p) == IPPROTO_UDP))) { + if (PKT_IS_IPV6(p) && ((IPV6_GET_NH(p) == IPPROTO_TCP) || (IPV6_GET_NH(p) == IPPROTO_UDP))) { int i; if (p->afp_v.v6_map_fd == -1) { return 0; @@ -2282,13 +2265,12 @@ static int AFPBypassCallback(Packet *p) } else { keys[0]->ip_proto = 0; } - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); return 0; } - keys[1]= SCCalloc(1, sizeof(struct flowv6_keys)); + keys[1] = SCCalloc(1, sizeof(struct flowv6_keys)); if (keys[1] == NULL) { EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET6); @@ -2306,8 +2288,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); @@ -2354,7 +2335,7 @@ static int AFPXDPBypassCallback(Packet *p) } if (PKT_IS_IPV4(p)) { struct flowv4_keys *keys[2]; - keys[0]= SCCalloc(1, sizeof(struct flowv4_keys)); + keys[0] = SCCalloc(1, sizeof(struct flowv4_keys)); if (keys[0] == NULL) { LiveDevAddBypassFail(p->livedev, 1, AF_INET); return 0; @@ -2377,13 +2358,12 @@ static int AFPXDPBypassCallback(Packet *p) } else { keys[0]->ip_proto = 0; } - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); return 0; } - keys[1]= SCCalloc(1, sizeof(struct flowv4_keys)); + keys[1] = SCCalloc(1, sizeof(struct flowv4_keys)); if (keys[1] == NULL) { EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET); @@ -2398,8 +2378,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->vlan1 = p->vlan_id[1]; keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); @@ -2409,8 +2388,7 @@ static int AFPXDPBypassCallback(Packet *p) return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1], AF_INET); } /* For IPv6 case we don't handle extended header in eBPF */ - if (PKT_IS_IPV6(p) && - ((IPV6_GET_NH(p) == IPPROTO_TCP) || (IPV6_GET_NH(p) == IPPROTO_UDP))) { + if (PKT_IS_IPV6(p) && ((IPV6_GET_NH(p) == IPPROTO_TCP) || (IPV6_GET_NH(p) == IPPROTO_UDP))) { SCLogDebug("add an IPv6"); if (p->afp_v.v6_map_fd == -1) { return 0; @@ -2436,13 +2414,12 @@ static int AFPXDPBypassCallback(Packet *p) } else { keys[0]->ip_proto = 0; } - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); return 0; } - keys[1]= SCCalloc(1, sizeof(struct flowv6_keys)); + keys[1] = SCCalloc(1, sizeof(struct flowv6_keys)); if (keys[1] == NULL) { EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET6); @@ -2459,8 +2436,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->vlan1 = p->vlan_id[1]; keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], - p->afp_v.nr_cpus) == 0) { + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); @@ -2505,7 +2481,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data) ptv->tv = tv; strlcpy(ptv->iface, afpconfig->iface, AFP_IFACE_NAME_LENGTH); - ptv->iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; + ptv->iface[AFP_IFACE_NAME_LENGTH - 1] = '\0'; ptv->livedev = LiveGetDevice(ptv->iface); if (ptv->livedev == NULL) { @@ -2545,7 +2521,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data) ptv->xdp_mode = afpconfig->xdp_mode; ptv->ebpf_t_config.cpus_count = UtilCpuGetNumProcessorsConfigured(); - if (ptv->flags & (AFP_BYPASS|AFP_XDPBYPASS)) { + if (ptv->flags & (AFP_BYPASS | AFP_XDPBYPASS)) { ptv->v4_map_fd = EBPFGetMapFDByName(ptv->iface, "flow_table_v4"); if (ptv->v4_map_fd == -1) { if (g_flowv4_ok == false) { @@ -2554,7 +2530,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data) } } ptv->v6_map_fd = EBPFGetMapFDByName(ptv->iface, "flow_table_v6"); - if (ptv->v6_map_fd == -1) { + if (ptv->v6_map_fd == -1) { if (g_flowv6_ok) { SCLogError("Can't find eBPF map fd for '%s'", "flow_table_v6"); g_flowv6_ok = false; @@ -2565,12 +2541,9 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data) #endif #ifdef PACKET_STATISTICS - ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", - ptv->tv); - ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", - ptv->tv); - ptv->capture_errors = StatsRegisterCounter("capture.errors", - ptv->tv); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", ptv->tv); + ptv->capture_errors = StatsRegisterCounter("capture.errors", ptv->tv); ptv->afpacket_spin = StatsRegisterAvgCounter("capture.afpacket.busy_loop_avg", ptv->tv); @@ -2585,7 +2558,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data) ptv->copy_mode = afpconfig->copy_mode; if (ptv->copy_mode != AFP_COPY_MODE_NONE) { strlcpy(ptv->out_iface, afpconfig->out_iface, AFP_IFACE_NAME_LENGTH); - ptv->out_iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; + ptv->out_iface[AFP_IFACE_NAME_LENGTH - 1] = '\0'; /* Warn about BPF filter consequence */ if (ptv->bpf_filter) { SCLogWarning("Enabling a BPF filter in IPS mode result" @@ -2593,7 +2566,6 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data) } } - if (AFPPeersListAdd(ptv) == TM_ECODE_FAILED) { SCFree(ptv); afpconfig->DerefFunc(afpconfig); @@ -2645,7 +2617,7 @@ TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data) #ifdef HAVE_PACKET_XDP if ((ptv->ebpf_t_config.flags & EBPF_XDP_CODE) && - (!(ptv->ebpf_t_config.flags & EBPF_PINNED_MAPS))) { + (!(ptv->ebpf_t_config.flags & EBPF_PINNED_MAPS))) { EBPFSetupXDP(ptv->iface, -1, ptv->xdp_mode); } #endif diff --git a/src/source-af-packet.h b/src/source-af-packet.h index d91d0cb25232..8fd959b247bf 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -27,24 +27,24 @@ #ifndef HAVE_PACKET_FANOUT /* not defined if linux/if_packet.h trying to force */ #define HAVE_PACKET_FANOUT 1 -#define PACKET_FANOUT 18 +#define PACKET_FANOUT 18 -#define PACKET_FANOUT_HASH 0 -#define PACKET_FANOUT_LB 1 -#define PACKET_FANOUT_CPU 2 -#define PACKET_FANOUT_ROLLOVER 3 -#define PACKET_FANOUT_RND 4 -#define PACKET_FANOUT_QM 5 +#define PACKET_FANOUT_HASH 0 +#define PACKET_FANOUT_LB 1 +#define PACKET_FANOUT_CPU 2 +#define PACKET_FANOUT_ROLLOVER 3 +#define PACKET_FANOUT_RND 4 +#define PACKET_FANOUT_QM 5 -#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 -#define PACKET_FANOUT_FLAG_DEFRAG 0x8000 +#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 +#define PACKET_FANOUT_FLAG_DEFRAG 0x8000 #else /* HAVE_PACKET_FANOUT */ #include #endif /* HAVE_PACKET_FANOUT */ #include "queue.h" #ifdef HAVE_PACKET_EBPF -#define AFP_MODE_XDP_BYPASS 1 +#define AFP_MODE_XDP_BYPASS 1 #define AFP_MODE_EBPF_BYPASS 2 struct ebpf_timeout_config { const char *pinned_maps_name; @@ -57,17 +57,17 @@ struct ebpf_timeout_config { /* value for flags */ #define AFP_NEED_PEER (1 << 0) // (1<<1) vacant -#define AFP_SOCK_PROTECT (1<<2) -#define AFP_EMERGENCY_MODE (1<<3) -#define AFP_TPACKET_V3 (1<<4) -#define AFP_VLAN_IN_HEADER (1<<5) -#define AFP_MMAP_LOCKED (1<<6) -#define AFP_BYPASS (1<<7) -#define AFP_XDPBYPASS (1<<8) - -#define AFP_COPY_MODE_NONE 0 -#define AFP_COPY_MODE_TAP 1 -#define AFP_COPY_MODE_IPS 2 +#define AFP_SOCK_PROTECT (1 << 2) +#define AFP_EMERGENCY_MODE (1 << 3) +#define AFP_TPACKET_V3 (1 << 4) +#define AFP_VLAN_IN_HEADER (1 << 5) +#define AFP_MMAP_LOCKED (1 << 6) +#define AFP_BYPASS (1 << 7) +#define AFP_XDPBYPASS (1 << 8) + +#define AFP_COPY_MODE_NONE 0 +#define AFP_COPY_MODE_TAP 1 +#define AFP_COPY_MODE_IPS 2 #define AFP_IFACE_NAME_LENGTH 48 @@ -77,8 +77,7 @@ struct ebpf_timeout_config { * to standard frame size */ #define AFP_BLOCK_SIZE_DEFAULT_ORDER 3 -typedef struct AFPIfaceConfig_ -{ +typedef struct AFPIfaceConfig_ { char iface[AFP_IFACE_NAME_LENGTH]; /* number of threads */ int threads; @@ -140,8 +139,7 @@ typedef struct AFPPeer_ { * This structure is used y the release data system and is cleaned * up by the AFPV_CLEANUP macro below. */ -typedef struct AFPPacketVars_ -{ +typedef struct AFPPacketVars_ { void *relptr; AFPPeer *peer; /**< Sending peer for IPS/TAP mode */ /** Pointer to ::AFPPeer used for capture. Field is used to be able @@ -183,8 +181,8 @@ typedef struct AFPPacketVars_ * @} */ -void TmModuleReceiveAFPRegister (void); -void TmModuleDecodeAFPRegister (void); +void TmModuleReceiveAFPRegister(void); +void TmModuleDecodeAFPRegister(void); TmEcode AFPPeersListInit(void); TmEcode AFPPeersListCheck(void); diff --git a/src/source-af-xdp.c b/src/source-af-xdp.c index 17fa0efeec4f..1b0f73a357b1 100644 --- a/src/source-af-xdp.c +++ b/src/source-af-xdp.c @@ -42,23 +42,23 @@ #include "tm-threads.h" #include "tm-threads-common.h" #include "conf.h" -#include "util-cpu.h" -#include "util-datalink.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-ebpf.h" -#include "util-error.h" -#include "util-privs.h" -#include "util-optimize.h" -#include "util-checksum.h" -#include "util-ioctl.h" -#include "util-host-info.h" -#include "util-sysfs.h" +#include "util/cpu.h" +#include "util/datalink.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/ebpf.h" +#include "util/error.h" +#include "util/privs.h" +#include "util/optimize.h" +#include "util/checksum.h" +#include "util/ioctl.h" +#include "util/host-info.h" +#include "util/sysfs.h" #include "tmqh-packetpool.h" #include "source-af-xdp.h" #include "runmodes.h" #include "flow-storage.h" -#include "util-validate.h" +#include "util/validate.h" #ifdef HAVE_AF_XDP #include @@ -969,7 +969,7 @@ static TmEcode DecodeAFXDPThreadDeinit(ThreadVars *tv, void *data) } #endif /* HAVE_AF_XDP */ -/* eof */ -/** - * @} - */ \ No newline at end of file + /* eof */ + /** + * @} + */ \ No newline at end of file diff --git a/src/source-dpdk.c b/src/source-dpdk.c index 54503e212271..6d31c948cd7c 100644 --- a/src/source-dpdk.c +++ b/src/source-dpdk.c @@ -40,7 +40,7 @@ #include "threadvars.h" #include "tm-threads.h" #include "tmqh-packetpool.h" -#include "util-privs.h" +#include "util/privs.h" #include "action-globals.h" #ifndef HAVE_DPDK @@ -85,10 +85,10 @@ TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data) #else /* We have DPDK support */ -#include "util-affinity.h" -#include "util-dpdk.h" -#include "util-dpdk-i40e.h" -#include "util-dpdk-bonding.h" +#include "util/affinity.h" +#include "util/dpdk.h" +#include "util/dpdk-i40e.h" +#include "util/dpdk-bonding.h" #include #define BURST_SIZE 32 diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index e3c820dc4c08..466f097fb5e0 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -30,9 +30,9 @@ #include "suricata.h" #include "tm-threads.h" -#include "util-privs.h" -#include "util-datalink.h" -#include "util-device.h" +#include "util/privs.h" +#include "util/datalink.h" +#include "util/device.h" #include "tmqh-packetpool.h" #include "source-erf-dag.h" @@ -40,8 +40,7 @@ TmEcode NoErfDagSupportExit(ThreadVars *, const void *, void **); -void -TmModuleReceiveErfDagRegister(void) +void TmModuleReceiveErfDagRegister(void) { tmm_modules[TMM_RECEIVEERFDAG].name = "ReceiveErfDag"; tmm_modules[TMM_RECEIVEERFDAG].ThreadInit = NoErfDagSupportExit; @@ -52,8 +51,7 @@ TmModuleReceiveErfDagRegister(void) tmm_modules[TMM_RECEIVEERFDAG].flags = TM_FLAG_RECEIVE_TM; } -void -TmModuleDecodeErfDagRegister(void) +void TmModuleDecodeErfDagRegister(void) { tmm_modules[TMM_DECODEERFDAG].name = "DecodeErfDag"; tmm_modules[TMM_DECODEERFDAG].ThreadInit = NoErfDagSupportExit; @@ -64,8 +62,7 @@ TmModuleDecodeErfDagRegister(void) tmm_modules[TMM_DECODEERFDAG].flags = TM_FLAG_DECODE_TM; } -TmEcode -NoErfDagSupportExit(ThreadVars *tv, const void *initdata, void **data) +TmEcode NoErfDagSupportExit(ThreadVars *tv, const void *initdata, void **data) { SCLogError("Error creating thread %s: you do not have support for DAG cards " "enabled please recompile with --enable-dag", @@ -78,13 +75,13 @@ NoErfDagSupportExit(ThreadVars *tv, const void *initdata, void **data) #include /* Minimum amount of data to read from the DAG at a time. */ -#define MINDATA 32768 +#define MINDATA 32768 /* Maximum time (us) to wait for MINDATA to be read. */ -#define MAXWAIT 20000 +#define MAXWAIT 20000 /* Poll interval in microseconds. */ -#define POLL_INTERVAL 1000; +#define POLL_INTERVAL 1000; /* Number of bytes per loop to process before fetching more data. */ #define BYTES_PER_LOOP (4 * 1024 * 1024) /* 4 MB */ @@ -99,7 +96,7 @@ typedef struct ErfDagThreadVars_ { int dagstream; char dagname[DAGNAME_BUFSIZE]; - struct timeval maxwait, poll; /* Could possibly be made static */ + struct timeval maxwait, poll; /* Could possibly be made static */ LiveDevice *livedev; @@ -114,8 +111,8 @@ typedef struct ErfDagThreadVars_ { } ErfDagThreadVars; -static inline TmEcode ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, - uint32_t *pkts_read); +static inline TmEcode ProcessErfDagRecords( + ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read); static inline TmEcode ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec); TmEcode ReceiveErfDagLoop(ThreadVars *, void *data, void *slot); TmEcode ReceiveErfDagThreadInit(ThreadVars *, void *, void **); @@ -129,16 +126,14 @@ void ReceiveErfDagCloseStream(int dagfd, int stream); /** * \brief Register the ERF file receiver (reader) module. */ -void -TmModuleReceiveErfDagRegister(void) +void TmModuleReceiveErfDagRegister(void) { tmm_modules[TMM_RECEIVEERFDAG].name = "ReceiveErfDag"; tmm_modules[TMM_RECEIVEERFDAG].ThreadInit = ReceiveErfDagThreadInit; tmm_modules[TMM_RECEIVEERFDAG].Func = NULL; tmm_modules[TMM_RECEIVEERFDAG].PktAcqLoop = ReceiveErfDagLoop; tmm_modules[TMM_RECEIVEERFDAG].PktAcqBreakLoop = NULL; - tmm_modules[TMM_RECEIVEERFDAG].ThreadExitPrintStats = - ReceiveErfDagThreadExitStats; + tmm_modules[TMM_RECEIVEERFDAG].ThreadExitPrintStats = ReceiveErfDagThreadExitStats; tmm_modules[TMM_RECEIVEERFDAG].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEERFDAG].cap_flags = 0; tmm_modules[TMM_RECEIVEERFDAG].flags = TM_FLAG_RECEIVE_TM; @@ -147,8 +142,7 @@ TmModuleReceiveErfDagRegister(void) /** * \brief Register the ERF file decoder module. */ -void -TmModuleDecodeErfDagRegister(void) +void TmModuleDecodeErfDagRegister(void) { tmm_modules[TMM_DECODEERFDAG].name = "DecodeErfDag"; tmm_modules[TMM_DECODEERFDAG].ThreadInit = DecodeErfDagThreadInit; @@ -175,8 +169,7 @@ TmModuleDecodeErfDagRegister(void) * \param data data pointer gets populated with * */ -TmEcode -ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) +TmEcode ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); int stream_count = 0; @@ -194,8 +187,7 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) /* dag_parse_name will return a DAG device name and stream number * to open for this thread. */ - if (dag_parse_name(initdata, ewtn->dagname, DAGNAME_BUFSIZE, - &ewtn->dagstream) < 0) { + if (dag_parse_name(initdata, ewtn->dagname, DAGNAME_BUFSIZE, &ewtn->dagstream) < 0) { SCLogError("Failed to parse DAG interface: %s", (char *)initdata); SCFree(ewtn); exit(EXIT_FAILURE); @@ -208,8 +200,7 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); } - SCLogInfo("Opening DAG: %s on stream: %d for processing", - ewtn->dagname, ewtn->dagstream); + SCLogInfo("Opening DAG: %s on stream: %d for processing", ewtn->dagname, ewtn->dagstream); if ((ewtn->dagfd = dag_open(ewtn->dagname)) < 0) { SCLogError("Failed to open DAG: %s", ewtn->dagname); @@ -262,8 +253,7 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); } - SCLogInfo("Attached and started stream: %d on DAG: %s", - ewtn->dagstream, ewtn->dagname); + SCLogInfo("Attached and started stream: %d on DAG: %s", ewtn->dagstream, ewtn->dagname); /* * Initialise DAG Polling parameters. @@ -276,8 +266,8 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) /* 32kB minimum data to return -- we still restrict the number of * pkts that are processed to a maximum of dag_max_read_packets. */ - if (dag_set_stream_poll(ewtn->dagfd, ewtn->dagstream, MINDATA, - &(ewtn->maxwait), &(ewtn->poll)) < 0) { + if (dag_set_stream_poll( + ewtn->dagfd, ewtn->dagstream, MINDATA, &(ewtn->maxwait), &(ewtn->poll)) < 0) { SCLogError("Failed to set poll parameters for stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); SCFree(ewtn); @@ -292,8 +282,8 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) DatalinkSetGlobalType(LINKTYPE_ETHERNET); - SCLogInfo("Starting processing packets from stream: %d on DAG: %s", - ewtn->dagstream, ewtn->dagname); + SCLogInfo("Starting processing packets from stream: %d on DAG: %s", ewtn->dagstream, + ewtn->dagname); SCReturnInt(TM_ECODE_OK); } @@ -308,15 +298,14 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) * \retval TM_ECODE_OK on success * \retval TM_ECODE_FAILED on failure */ -TmEcode -ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) +TmEcode ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); ErfDagThreadVars *dtv = (ErfDagThreadVars *)data; uint32_t diff = 0; - int err; - uint8_t *top = NULL; + int err; + uint8_t *top = NULL; uint32_t pkts_read = 0; TmSlot *s = (TmSlot *)slot; @@ -365,8 +354,8 @@ ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) StatsSyncCountersIfSignalled(tv); - SCLogDebug("Read %d records from stream: %d, DAG: %s", - pkts_read, dtv->dagstream, dtv->dagname); + SCLogDebug("Read %d records from stream: %d, DAG: %s", pkts_read, dtv->dagstream, + dtv->dagname); } SCReturnInt(TM_ECODE_OK); @@ -378,8 +367,8 @@ ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) * This function takes a pointer to buffer read from the DAG interface * and processes it individual records. */ -static inline TmEcode -ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) +static inline TmEcode ProcessErfDagRecords( + ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) { SCEnter(); @@ -393,14 +382,14 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) *pkts_read = 0; while (((top - ewtn->btm) >= dag_record_size) && - ((processed + dag_record_size) < BYTES_PER_LOOP)) { + ((processed + dag_record_size) < BYTES_PER_LOOP)) { /* Make sure we have at least one packet in the packet pool, * to prevent us from alloc'ing packets at line rate. */ PacketPoolWait(); prec = (char *)ewtn->btm; - dr = (dag_record_t*)prec; + dr = (dag_record_t *)prec; rlen = SCNtohs(dr->rlen); hdr_type = dr->type; @@ -415,24 +404,24 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) /* Only support ethernet at this time. */ switch (hdr_type & 0x7f) { - case ERF_TYPE_PAD: - case ERF_TYPE_META: - /* Skip. */ - continue; - case ERF_TYPE_DSM_COLOR_ETH: - case ERF_TYPE_COLOR_ETH: - case ERF_TYPE_COLOR_HASH_ETH: - /* In these types the color value overwrites the lctr - * (drop count). */ - break; - case ERF_TYPE_ETH: - if (dr->lctr) { - StatsAddUI64(ewtn->tv, ewtn->drops, SCNtohs(dr->lctr)); - } - break; - default: - SCLogError("Processing of DAG record type: %d not implemented.", dr->type); - SCReturnInt(TM_ECODE_FAILED); + case ERF_TYPE_PAD: + case ERF_TYPE_META: + /* Skip. */ + continue; + case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_ETH: + case ERF_TYPE_COLOR_HASH_ETH: + /* In these types the color value overwrites the lctr + * (drop count). */ + break; + case ERF_TYPE_ETH: + if (dr->lctr) { + StatsAddUI64(ewtn->tv, ewtn->drops, SCNtohs(dr->lctr)); + } + break; + default: + SCLogError("Processing of DAG record type: %d not implemented.", dr->type); + SCReturnInt(TM_ECODE_FAILED); } err = ProcessErfDagRecord(ewtn, prec); @@ -451,8 +440,7 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) * \param prec pointer to a DAG record. * \param */ -static inline TmEcode -ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) +static inline TmEcode ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) { SCEnter(); @@ -460,7 +448,7 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) int rlen = 0; int hdr_num = 0; char hdr_type = 0; - dag_record_t *dr = (dag_record_t*)prec; + dag_record_t *dr = (dag_record_t *)prec; erf_payload_t *pload; Packet *p; @@ -534,22 +522,16 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) * \param tv Pointer to ThreadVars. * \param data Pointer to data, ErfFileThreadVars. */ -void -ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) +void ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) { ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; - (void)SC_ATOMIC_SET(ewtn->livedev->pkts, - StatsGetLocalCounterValue(tv, ewtn->packets)); - (void)SC_ATOMIC_SET(ewtn->livedev->drop, - StatsGetLocalCounterValue(tv, ewtn->drops)); - - SCLogInfo("Stream: %d; Bytes: %"PRIu64"; Packets: %"PRIu64 - "; Drops: %"PRIu64, - ewtn->dagstream, - ewtn->bytes, - StatsGetLocalCounterValue(tv, ewtn->packets), - StatsGetLocalCounterValue(tv, ewtn->drops)); + (void)SC_ATOMIC_SET(ewtn->livedev->pkts, StatsGetLocalCounterValue(tv, ewtn->packets)); + (void)SC_ATOMIC_SET(ewtn->livedev->drop, StatsGetLocalCounterValue(tv, ewtn->drops)); + + SCLogInfo("Stream: %d; Bytes: %" PRIu64 "; Packets: %" PRIu64 "; Drops: %" PRIu64, + ewtn->dagstream, ewtn->bytes, StatsGetLocalCounterValue(tv, ewtn->packets), + StatsGetLocalCounterValue(tv, ewtn->drops)); } /** @@ -557,8 +539,7 @@ ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) * \param tv pointer to ThreadVars * \param data pointer that gets cast into PcapThreadVars for ptv */ -TmEcode -ReceiveErfDagThreadDeinit(ThreadVars *tv, void *data) +TmEcode ReceiveErfDagThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); @@ -569,8 +550,7 @@ ReceiveErfDagThreadDeinit(ThreadVars *tv, void *data) SCReturnInt(TM_ECODE_OK); } -void -ReceiveErfDagCloseStream(int dagfd, int stream) +void ReceiveErfDagCloseStream(int dagfd, int stream) { dag_stop_stream(dagfd, stream); dag_detach_stream(dagfd, stream); @@ -589,8 +569,7 @@ ReceiveErfDagCloseStream(int dagfd, int stream) * \param p pointer to the current packet * \param data pointer that gets cast into PcapThreadVars for ptv */ -TmEcode -DecodeErfDag(ThreadVars *tv, Packet *p, void *data) +TmEcode DecodeErfDag(ThreadVars *tv, Packet *p, void *data) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; @@ -600,8 +579,8 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data) /* update counters */ DecodeUpdatePacketCounters(tv, dtv, p); - /* call the decoder */ - switch(p->datalink) { + /* call the decoder */ + switch (p->datalink) { case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p)); break; @@ -616,8 +595,7 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data) SCReturnInt(TM_ECODE_OK); } -TmEcode -DecodeErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) +TmEcode DecodeErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; @@ -634,8 +612,7 @@ DecodeErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_OK); } -TmEcode -DecodeErfDagThreadDeinit(ThreadVars *tv, void *data) +TmEcode DecodeErfDagThreadDeinit(ThreadVars *tv, void *data) { if (data != NULL) DecodeThreadVarsFree(tv, data); diff --git a/src/source-erf-dag.h b/src/source-erf-dag.h index e712798b8701..b95410b7310c 100644 --- a/src/source-erf-dag.h +++ b/src/source-erf-dag.h @@ -29,4 +29,3 @@ void TmModuleReceiveErfDagRegister(void); void TmModuleDecodeErfDagRegister(void); #endif /* __SOURCE_ERF_DAG_H__ */ - diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 4803f8b3e28f..9706e8f4931a 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -29,18 +29,18 @@ #include "suricata.h" #include "tm-threads.h" #include "source-erf-file.h" -#include "util-datalink.h" +#include "util/datalink.h" #define DAG_TYPE_ETH 2 typedef struct DagFlags_ { - uint8_t iface:2; - uint8_t vlen:1; - uint8_t trunc:1; - uint8_t rxerror:1; - uint8_t dserror:1; - uint8_t reserved:1; - uint8_t direction:1; + uint8_t iface : 2; + uint8_t vlen : 1; + uint8_t trunc : 1; + uint8_t rxerror : 1; + uint8_t dserror : 1; + uint8_t reserved : 1; + uint8_t direction : 1; } DagFlags; typedef struct DagRecord_ { @@ -76,16 +76,14 @@ static TmEcode DecodeErfFile(ThreadVars *, Packet *, void *); /** * \brief Register the ERF file receiver (reader) module. */ -void -TmModuleReceiveErfFileRegister(void) +void TmModuleReceiveErfFileRegister(void) { tmm_modules[TMM_RECEIVEERFFILE].name = "ReceiveErfFile"; tmm_modules[TMM_RECEIVEERFFILE].ThreadInit = ReceiveErfFileThreadInit; tmm_modules[TMM_RECEIVEERFFILE].Func = NULL; tmm_modules[TMM_RECEIVEERFFILE].PktAcqLoop = ReceiveErfFileLoop; tmm_modules[TMM_RECEIVEERFFILE].PktAcqBreakLoop = NULL; - tmm_modules[TMM_RECEIVEERFFILE].ThreadExitPrintStats = - ReceiveErfFileThreadExitStats; + tmm_modules[TMM_RECEIVEERFFILE].ThreadExitPrintStats = ReceiveErfFileThreadExitStats; tmm_modules[TMM_RECEIVEERFFILE].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEERFFILE].cap_flags = 0; tmm_modules[TMM_RECEIVEERFFILE].flags = TM_FLAG_RECEIVE_TM; @@ -94,8 +92,7 @@ TmModuleReceiveErfFileRegister(void) /** * \brief Register the ERF file decoder module. */ -void -TmModuleDecodeErfFileRegister(void) +void TmModuleDecodeErfFileRegister(void) { tmm_modules[TMM_DECODEERFFILE].name = "DecodeErfFile"; tmm_modules[TMM_DECODEERFFILE].ThreadInit = DecodeErfFileThreadInit; @@ -162,8 +159,7 @@ static inline TmEcode ReadErfRecord(ThreadVars *tv, Packet *p, void *data) if (r < 1) { if (feof(etv->erf)) { SCLogInfo("End of ERF file reached"); - } - else { + } else { SCLogInfo("Error reading ERF record"); } SCReturnInt(TM_ECODE_FAILED); @@ -179,8 +175,7 @@ static inline TmEcode ReadErfRecord(ThreadVars *tv, Packet *p, void *data) if (r < 1) { if (feof(etv->erf)) { SCLogInfo("End of ERF file reached"); - } - else { + } else { SCLogInfo("Error reading ERF record"); } SCReturnInt(TM_ECODE_FAILED); @@ -217,8 +212,7 @@ static inline TmEcode ReadErfRecord(ThreadVars *tv, Packet *p, void *data) /** * \brief Initialize the ERF receiver thread. */ -TmEcode -ReceiveErfFileThreadInit(ThreadVars *tv, const void *initdata, void **data) +TmEcode ReceiveErfFileThreadInit(ThreadVars *tv, const void *initdata, void **data) { SCEnter(); @@ -253,8 +247,7 @@ ReceiveErfFileThreadInit(ThreadVars *tv, const void *initdata, void **data) /** * \brief Initialize the ERF decoder thread. */ -TmEcode -DecodeErfFileThreadInit(ThreadVars *tv, const void *initdata, void **data) +TmEcode DecodeErfFileThreadInit(ThreadVars *tv, const void *initdata, void **data) { SCEnter(); DecodeThreadVars *dtv = NULL; @@ -283,8 +276,7 @@ TmEcode DecodeErfFileThreadDeinit(ThreadVars *tv, void *data) * This function ups the decoder counters and then passes the packet * off to the ethernet decoder. */ -TmEcode -DecodeErfFile(ThreadVars *tv, Packet *p, void *data) +TmEcode DecodeErfFile(ThreadVars *tv, Packet *p, void *data) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; @@ -307,10 +299,9 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data) * \param tv Pointer to ThreadVars. * \param data Pointer to data, ErfFileThreadVars. */ -void -ReceiveErfFileThreadExitStats(ThreadVars *tv, void *data) +void ReceiveErfFileThreadExitStats(ThreadVars *tv, void *data) { ErfFileThreadVars *etv = (ErfFileThreadVars *)data; - SCLogInfo("Packets: %"PRIu32"; Bytes: %"PRIu64, etv->pkts, etv->bytes); + SCLogInfo("Packets: %" PRIu32 "; Bytes: %" PRIu64, etv->pkts, etv->bytes); } diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 6d0f67c11572..426bc850b382 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -34,16 +34,16 @@ #include "tm-queuehandlers.h" #include "tm-threads.h" #include "source-ipfw.h" -#include "util-debug.h" +#include "util/debug.h" #include "conf.h" -#include "util-byte.h" -#include "util-privs.h" -#include "util-datalink.h" -#include "util-device.h" +#include "util/byte.h" +#include "util/privs.h" +#include "util/datalink.h" +#include "util/device.h" #include "runmodes.h" #define IPFW_ACCEPT 0 -#define IPFW_DROP 1 +#define IPFW_DROP 1 #define IPFW_SOCKET_POLL_MSEC 300 @@ -58,7 +58,7 @@ TmEcode NoIPFWSupportExit(ThreadVars *, const void *, void **); -void TmModuleReceiveIPFWRegister (void) +void TmModuleReceiveIPFWRegister(void) { tmm_modules[TMM_RECEIVEIPFW].name = "ReceiveIPFW"; @@ -69,7 +69,7 @@ void TmModuleReceiveIPFWRegister (void) tmm_modules[TMM_RECEIVEIPFW].flags = TM_FLAG_RECEIVE_TM; } -void TmModuleVerdictIPFWRegister (void) +void TmModuleVerdictIPFWRegister(void) { tmm_modules[TMM_VERDICTIPFW].name = "VerdictIPFW"; tmm_modules[TMM_VERDICTIPFW].ThreadInit = NoIPFWSupportExit; @@ -78,7 +78,7 @@ void TmModuleVerdictIPFWRegister (void) tmm_modules[TMM_VERDICTIPFW].ThreadDeinit = NULL; } -void TmModuleDecodeIPFWRegister (void) +void TmModuleDecodeIPFWRegister(void) { tmm_modules[TMM_DECODEIPFW].name = "DecodeIPFW"; tmm_modules[TMM_DECODEIPFW].ThreadInit = NoIPFWSupportExit; @@ -107,8 +107,7 @@ extern uint16_t max_pending_packets; /** * \brief Structure to hold thread specific variables. */ -typedef struct IPFWThreadVars_ -{ +typedef struct IPFWThreadVars_ { /* data link type for the thread, probably not needed */ int datalink; @@ -151,7 +150,7 @@ static TmEcode DecodeIPFW(ThreadVars *, Packet *, void *); * \brief Registration Function for RecieveIPFW. * \todo Unit tests are needed for this module. */ -void TmModuleReceiveIPFWRegister (void) +void TmModuleReceiveIPFWRegister(void) { SCMutexInit(&ipfw_init_lock, NULL); @@ -172,22 +171,22 @@ void TmModuleReceiveIPFWRegister (void) * \brief Registration Function for VerdictIPFW. * \todo Unit tests are needed for this module. */ -void TmModuleVerdictIPFWRegister (void) +void TmModuleVerdictIPFWRegister(void) { tmm_modules[TMM_VERDICTIPFW].name = "VerdictIPFW"; tmm_modules[TMM_VERDICTIPFW].ThreadInit = VerdictIPFWThreadInit; tmm_modules[TMM_VERDICTIPFW].Func = VerdictIPFW; tmm_modules[TMM_VERDICTIPFW].ThreadExitPrintStats = VerdictIPFWThreadExitStats; tmm_modules[TMM_VERDICTIPFW].ThreadDeinit = VerdictIPFWThreadDeinit; - tmm_modules[TMM_VERDICTIPFW].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | - SC_CAP_NET_BIND_SERVICE; /** \todo untested */ + tmm_modules[TMM_VERDICTIPFW].cap_flags = + SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | SC_CAP_NET_BIND_SERVICE; /** \todo untested */ } /** * \brief Registration Function for DecodeIPFW. * \todo Unit tests are needed for this module. */ -void TmModuleDecodeIPFWRegister (void) +void TmModuleDecodeIPFWRegister(void) { tmm_modules[TMM_DECODEIPFW].name = "DecodeIPFW"; tmm_modules[TMM_DECODEIPFW].ThreadInit = DecodeIPFWThreadInit; @@ -230,7 +229,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) IPFWThreadVars *ptv = (IPFWThreadVars *)data; IPFWQueueVars *nq = NULL; uint8_t pkt[IP_MAXPACKET]; - int pktlen=0; + int pktlen = 0; struct pollfd IPFWpoll; struct timeval IPFWts; Packet *p = NULL; @@ -241,8 +240,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_FAILED); } - SCLogInfo("Thread '%s' will run on port %d (item %d)", - tv->name, nq->port_num, ptv->ipfw_index); + SCLogInfo("Thread '%s' will run on port %d (item %d)", tv->name, nq->port_num, ptv->ipfw_index); // Indicate that the thread is actually running its application level code (i.e., it can poll // packets) @@ -256,14 +254,13 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) IPFWpoll.fd = nq->fd; IPFWpoll.events = POLLRDNORM; /* Poll the socket for status */ - if ( (poll(&IPFWpoll, 1, IPFW_SOCKET_POLL_MSEC)) > 0) { + if ((poll(&IPFWpoll, 1, IPFW_SOCKET_POLL_MSEC)) > 0) { if (!(IPFWpoll.revents & (POLLRDNORM | POLLERR))) continue; } - if ((pktlen = recvfrom(nq->fd, pkt, sizeof(pkt), 0, - (struct sockaddr *)&nq->ipfw_sin, - &nq->ipfw_sinlen)) == -1) { + if ((pktlen = recvfrom(nq->fd, pkt, sizeof(pkt), 0, (struct sockaddr *)&nq->ipfw_sin, + &nq->ipfw_sinlen)) == -1) { /* We received an error on socket read */ if (errno == EINTR || errno == EWOULDBLOCK) { /* Nothing for us to process */ @@ -274,7 +271,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) } } /* We have a packet to process */ - memset (&IPFWts, 0, sizeof(struct timeval)); + memset(&IPFWts, 0, sizeof(struct timeval)); gettimeofday(&IPFWts, NULL); /* make sure we have at least one packet in the packet pool, to prevent @@ -299,11 +296,10 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) p->ipfw_v.ipfw_index = ptv->ipfw_index; PacketCopyData(p, pkt, pktlen); - SCLogDebug("Packet info: pkt_len: %" PRIu32 " (pkt %02x, pkt_data %02x)", - GET_PKT_LEN(p), *pkt, *(GET_PKT_DATA(p))); + SCLogDebug("Packet info: pkt_len: %" PRIu32 " (pkt %02x, pkt_data %02x)", GET_PKT_LEN(p), + *pkt, *(GET_PKT_DATA(p))); - if (TmThreadsSlotProcessPkt(tv, ((TmSlot *) slot)->slot_next, p) - != TM_ECODE_OK) { + if (TmThreadsSlotProcessPkt(tv, ((TmSlot *)slot)->slot_next, p) != TM_ECODE_OK) { SCReturnInt(TM_ECODE_FAILED); } @@ -328,7 +324,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) TmEcode ReceiveIPFWThreadInit(ThreadVars *tv, const void *initdata, void **data) { struct timeval timev; - IPFWThreadVars *ntv = (IPFWThreadVars *) initdata; + IPFWThreadVars *ntv = (IPFWThreadVars *)initdata; IPFWQueueVars *nq = IPFWGetQueue(ntv->ipfw_index); sigset_t sigs; @@ -358,7 +354,7 @@ TmEcode ReceiveIPFWThreadInit(ThreadVars *tv, const void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); } - nq->ipfw_sinlen=sizeof(nq->ipfw_sin); + nq->ipfw_sinlen = sizeof(nq->ipfw_sin); memset(&nq->ipfw_sin, 0, nq->ipfw_sinlen); nq->ipfw_sin.sin_family = PF_INET; nq->ipfw_sin.sin_addr.s_addr = INADDR_ANY; @@ -390,11 +386,10 @@ void ReceiveIPFWThreadExitStats(ThreadVars *tv, void *data) SCEnter(); - SCLogNotice("(%s) Treated: Pkts %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "", - tv->name, ptv->pkts, ptv->bytes, ptv->errs); - SCLogNotice("(%s) Verdict: Accepted %"PRIu32", Dropped %"PRIu32 "", - tv->name, ptv->accepted, ptv->dropped); - + SCLogNotice("(%s) Treated: Pkts %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "", tv->name, + ptv->pkts, ptv->bytes, ptv->errs); + SCLogNotice("(%s) Verdict: Accepted %" PRIu32 ", Dropped %" PRIu32 "", tv->name, ptv->accepted, + ptv->dropped); SCReturn; } @@ -453,7 +448,7 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data) SCLogDebug("DecodeIPFW ip4 processing"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p)); - } else if(IPV6_GET_RAW_VER(ip6h) == 6) { + } else if (IPV6_GET_RAW_VER(ip6h) == 6) { if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) { return TM_ECODE_FAILED; } @@ -463,7 +458,7 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data) } else { /* We don't support anything besides IP packets for now, bridged packets? */ SCLogInfo("IPFW unknown protocol support %02x", *GET_PKT_DATA(p)); - SCReturnInt(TM_ECODE_FAILED); + SCReturnInt(TM_ECODE_FAILED); } PacketDecodeFinalize(tv, dtv, p); @@ -547,7 +542,8 @@ TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) /* For divert sockets, accepting means writing the * packet back to the socket for ipfw to pick up */ - SCLogDebug("IPFWSetVerdict writing to socket %d, %p, %u", nq->fd, GET_PKT_DATA(p),GET_PKT_LEN(p)); + SCLogDebug("IPFWSetVerdict writing to socket %d, %p, %u", nq->fd, GET_PKT_DATA(p), + GET_PKT_LEN(p)); #if 0 while ((poll(&IPFWpoll,1,IPFW_SOCKET_POLL_MSEC)) < 1) { @@ -560,7 +556,8 @@ TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) #endif IPFWMutexLock(nq); - if (sendto(nq->fd, GET_PKT_DATA(p), GET_PKT_LEN(p), 0,(struct sockaddr *)&nq->ipfw_sin, nq->ipfw_sinlen) == -1) { + if (sendto(nq->fd, GET_PKT_DATA(p), GET_PKT_LEN(p), 0, (struct sockaddr *)&nq->ipfw_sin, + nq->ipfw_sinlen) == -1) { int r = errno; switch (r) { default: @@ -575,11 +572,10 @@ TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) IPFWMutexUnlock(nq); - SCLogDebug("Sent Packet back into IPFW Len: %d",GET_PKT_LEN(p)); + SCLogDebug("Sent Packet back into IPFW Len: %d", GET_PKT_LEN(p)); } /* end IPFW_ACCEPT */ - if (verdict == IPFW_DROP) { SCLogDebug("IPFW SetVerdict is to DROP"); ptv->dropped++; @@ -592,7 +588,6 @@ TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) SCReturnInt(TM_ECODE_OK); } - /** * \brief This function handles the Verdict processing * \todo Unit tests are needed for this module. @@ -672,7 +667,6 @@ TmEcode VerdictIPFWThreadDeinit(ThreadVars *tv, void *data) /* We don't need to do anything...not sure quite yet */ - SCReturnInt(TM_ECODE_OK); } @@ -686,7 +680,8 @@ TmEcode VerdictIPFWThreadDeinit(ThreadVars *tv, void *data) void VerdictIPFWThreadExitStats(ThreadVars *tv, void *data) { IPFWThreadVars *ptv = (IPFWThreadVars *)data; - SCLogInfo("IPFW Processing: - (%s) Pkts accepted %" PRIu32 ", dropped %" PRIu32 "", tv->name, ptv->accepted, ptv->dropped); + SCLogInfo("IPFW Processing: - (%s) Pkts accepted %" PRIu32 ", dropped %" PRIu32 "", tv->name, + ptv->accepted, ptv->dropped); } /** @@ -703,8 +698,7 @@ int IPFWRegisterQueue(char *queue) IPFWQueueVars *nq = NULL; /* Extract the queue number from the specified command line argument */ uint16_t port_num = 0; - if ((StringParseUint16(&port_num, 10, strlen(queue), queue)) < 0) - { + if ((StringParseUint16(&port_num, 10, strlen(queue), queue)) < 0) { SCLogError("specified queue number %s is not " "valid", queue); @@ -772,4 +766,3 @@ void *IPFWGetThread(int number) #endif /* End ifdef IPFW */ /* eof */ - diff --git a/src/source-ipfw.h b/src/source-ipfw.h index 94c560a4ba7f..94662ce8f5cd 100644 --- a/src/source-ipfw.h +++ b/src/source-ipfw.h @@ -28,13 +28,11 @@ #define IPFW_MAX_QUEUE 16 /* per packet IPFW vars (Not used) */ -typedef struct IPFWPacketVars_ -{ +typedef struct IPFWPacketVars_ { int ipfw_index; } IPFWPacketVars; -typedef struct IPFWQueueVars_ -{ +typedef struct IPFWQueueVars_ { int fd; SCMutex socket_lock; uint8_t use_mutex; @@ -62,9 +60,8 @@ typedef struct IPFWQueueVars_ void *IPFWGetThread(int number); int IPFWRegisterQueue(char *queue); -void TmModuleReceiveIPFWRegister (void); -void TmModuleVerdictIPFWRegister (void); -void TmModuleDecodeIPFWRegister (void); - +void TmModuleReceiveIPFWRegister(void); +void TmModuleVerdictIPFWRegister(void); +void TmModuleDecodeIPFWRegister(void); #endif /* __SOURCE_IPFW_H__ */ diff --git a/src/source-napatech.c b/src/source-napatech.c index 071d9ae68416..078e568c51de 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -31,20 +31,20 @@ #include "packet.h" #include "suricata.h" #include "threadvars.h" -#include "util-datalink.h" -#include "util-optimize.h" +#include "util/datalink.h" +#include "util/optimize.h" #include "tm-queuehandlers.h" #include "tm-threads.h" #include "tm-modules.h" -#include "util-privs.h" +#include "util/privs.h" #include "tmqh-packetpool.h" -#include "util-napatech.h" +#include "util/napatech.h" #include "source-napatech.h" #include "runmode-napatech.h" #ifndef HAVE_NAPATECH -TmEcode NoNapatechSupportExit(ThreadVars*, const void*, void**); +TmEcode NoNapatechSupportExit(ThreadVars *, const void *, void **); void TmModuleNapatechStreamRegister(void) { @@ -77,14 +77,12 @@ TmEcode NoNapatechSupportExit(ThreadVars *tv, const void *initdata, void **data) #else /* Implied we do have NAPATECH support */ - #include #include extern uint16_t max_pending_packets; -typedef struct NapatechThreadVars_ -{ +typedef struct NapatechThreadVars_ { ThreadVars *tv; NtNetStreamRx_t rx_stream; uint16_t stream_id; @@ -204,79 +202,74 @@ void TmModuleNapatechDecodeRegister(void) /** * \brief template of IPv4 header */ -struct ipv4_hdr -{ - uint8_t version_ihl; /**< version and header length */ - uint8_t type_of_service; /**< type of service */ - uint16_t total_length; /**< length of packet */ - uint16_t packet_id; /**< packet ID */ +struct ipv4_hdr { + uint8_t version_ihl; /**< version and header length */ + uint8_t type_of_service; /**< type of service */ + uint16_t total_length; /**< length of packet */ + uint16_t packet_id; /**< packet ID */ uint16_t fragment_offset; /**< fragmentation offset */ - uint8_t time_to_live; /**< time to live */ - uint8_t next_proto_id; /**< protocol ID */ - uint16_t hdr_checksum; /**< header checksum */ - uint32_t src_addr; /**< source address */ - uint32_t dst_addr; /**< destination address */ -} __attribute__ ((__packed__)); + uint8_t time_to_live; /**< time to live */ + uint8_t next_proto_id; /**< protocol ID */ + uint16_t hdr_checksum; /**< header checksum */ + uint32_t src_addr; /**< source address */ + uint32_t dst_addr; /**< destination address */ +} __attribute__((__packed__)); /** * \brief template of IPv6 header */ -struct ipv6_hdr -{ - uint32_t vtc_flow; /**< IP version, traffic class & flow label. */ +struct ipv6_hdr { + uint32_t vtc_flow; /**< IP version, traffic class & flow label. */ uint16_t payload_len; /**< IP packet length - includes sizeof(ip_header). */ - uint8_t proto; /**< Protocol, next header. */ - uint8_t hop_limits; /**< Hop limits. */ + uint8_t proto; /**< Protocol, next header. */ + uint8_t hop_limits; /**< Hop limits. */ uint8_t src_addr[16]; /**< IP address of source host. */ uint8_t dst_addr[16]; /**< IP address of destination host(s). */ -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); /** * \brief template of UDP header */ -struct udp_hdr -{ - uint16_t src_port; /**< UDP source port. */ - uint16_t dst_port; /**< UDP destination port. */ - uint16_t dgram_len; /**< UDP datagram length */ +struct udp_hdr { + uint16_t src_port; /**< UDP source port. */ + uint16_t dst_port; /**< UDP destination port. */ + uint16_t dgram_len; /**< UDP datagram length */ uint16_t dgram_cksum; /**< UDP datagram checksum */ -} __attribute__ ((__packed__)); +} __attribute__((__packed__)); /** * \brief template of TCP header */ -struct tcp_hdr -{ +struct tcp_hdr { uint16_t src_port; /**< TCP source port. */ uint16_t dst_port; /**< TCP destination port. */ uint32_t sent_seq; /**< TX data sequence number. */ uint32_t recv_ack; /**< RX data acknowledgement sequence number. */ - uint8_t data_off; /**< Data offset. */ + uint8_t data_off; /**< Data offset. */ uint8_t tcp_flags; /**< TCP flags */ - uint16_t rx_win; /**< RX flow control window. */ - uint16_t cksum; /**< TCP checksum. */ - uint16_t tcp_urp; /**< TCP urgent pointer, if any. */ -} __attribute__ ((__packed__)); - + uint16_t rx_win; /**< RX flow control window. */ + uint16_t cksum; /**< TCP checksum. */ + uint16_t tcp_urp; /**< TCP urgent pointer, if any. */ +} __attribute__((__packed__)); /* The hardware will assign a "color" value indicating what filters are matched * by a given packet. These constants indicate what bits are set in the color * field for different protocols * */ -#define RTE_PTYPE_L2_ETHER 0x10000000 -#define RTE_PTYPE_L3_IPV4 0x01000000 -#define RTE_PTYPE_L3_IPV6 0x04000000 -#define RTE_PTYPE_L4_TCP 0x00100000 -#define RTE_PTYPE_L4_UDP 0x00200000 +#define RTE_PTYPE_L2_ETHER 0x10000000 +#define RTE_PTYPE_L3_IPV4 0x01000000 +#define RTE_PTYPE_L3_IPV6 0x04000000 +#define RTE_PTYPE_L4_TCP 0x00100000 +#define RTE_PTYPE_L4_UDP 0x00200000 /* These masks are used to extract layer 3 and layer 4 protocol * values from the color field in the packet descriptor. */ -#define RTE_PTYPE_L3_MASK 0x0f000000 -#define RTE_PTYPE_L4_MASK 0x00f00000 +#define RTE_PTYPE_L3_MASK 0x0f000000 +#define RTE_PTYPE_L4_MASK 0x00f00000 -#define COLOR_IS_SPAN 0x00001000 +#define COLOR_IS_SPAN 0x00001000 static int is_inline = 0; static int inline_port_map[MAX_PORTS] = { -1 }; @@ -316,7 +309,7 @@ int NapatechGetAdapter(uint8_t port) { static int port_adapter_map[MAX_PORTS] = { -1 }; int status; - NtInfo_t h_info; /* Info handle */ + NtInfo_t h_info; /* Info handle */ NtInfoStream_t h_info_stream; /* Info stream handle */ if (unlikely(port_adapter_map[port] == -1)) { @@ -326,7 +319,7 @@ int NapatechGetAdapter(uint8_t port) } /* Read the system info */ h_info.cmd = NT_INFO_CMD_READ_PORT_V9; - h_info.u.port_v9.portNo = (uint8_t) port; + h_info.u.port_v9.portNo = (uint8_t)port; if ((status = NT_InfoRead(h_info_stream, &h_info)) != NT_SUCCESS) { /* Get the status code as text */ NAPATECH_ERROR(status); @@ -341,8 +334,7 @@ int NapatechGetAdapter(uint8_t port) /** * \brief IPv4 4-tuple convenience structure */ -struct IPv4Tuple4 -{ +struct IPv4Tuple4 { uint32_t sa; /*!< Source address */ uint32_t da; /*!< Destination address */ uint16_t sp; /*!< Source port */ @@ -352,8 +344,7 @@ struct IPv4Tuple4 /** * \brief IPv6 4-tuple convenience structure */ -struct IPv6Tuple4 -{ +struct IPv6Tuple4 { uint8_t sa[16]; /*!< Source address */ uint8_t da[16]; /*!< Destination address */ uint16_t sp; /*!< Source port */ @@ -371,7 +362,8 @@ struct IPv6Tuple4 * 1 if addr_a > addr_b * 0 if addr_a == addr_b */ -static int CompareIPv6Addr(uint8_t addr_a[16], uint8_t addr_b[16]) { +static int CompareIPv6Addr(uint8_t addr_a[16], uint8_t addr_b[16]) +{ uint16_t pos; for (pos = 0; pos < 16; ++pos) { if (addr_a[pos] < addr_b[pos]) { @@ -405,7 +397,7 @@ static NtFlowStream_t InitFlowStream(int adapter, int stream_id) NT_FlowOpenAttrInit(&attr); NT_FlowOpenAttrSetAdapterNo(&attr, adapter); - snprintf(flow_name, sizeof(flow_name), "Flow_stream_%d", stream_id ); + snprintf(flow_name, sizeof(flow_name), "Flow_stream_%d", stream_id); SCLogDebug("Opening flow programming stream: %s", flow_name); if ((status = NT_FlowOpen_Attr(&hFlowStream, flow_name, &attr)) != NT_SUCCESS) { SCLogWarning("Napatech bypass functionality not supported by the FPGA version on adapter " @@ -442,7 +434,7 @@ static int ProgramFlow(Packet *p, int inline_mode) * the protocols and if the packet is coming in from a SPAN port. */ uint32_t packet_type = ((ntpv->dyn3->color_hi << 14) & 0xFFFFC000) | ntpv->dyn3->color_lo; - uint8_t *packet = (uint8_t *) ntpv->dyn3 + ntpv->dyn3->descrLength; + uint8_t *packet = (uint8_t *)ntpv->dyn3 + ntpv->dyn3->descrLength; uint32_t layer3 = packet_type & RTE_PTYPE_L3_MASK; uint32_t layer4 = packet_type & RTE_PTYPE_L4_MASK; @@ -464,9 +456,12 @@ static int ProgramFlow(Packet *p, int inline_mode) /* Only bypass TCP and UDP */ if (PKT_IS_TCP(p)) { SC_ATOMIC_ADD(flow_callback_tcp_pkts, 1); - } else if PKT_IS_UDP(p) { - SC_ATOMIC_ADD(flow_callback_udp_pkts, 1); - } else { + } else if + PKT_IS_UDP(p) + { + SC_ATOMIC_ADD(flow_callback_udp_pkts, 1); + } + else { SC_ATOMIC_ADD(flow_callback_unhandled_pkts, 1); } @@ -476,9 +471,8 @@ static int ProgramFlow(Packet *p, int inline_mode) struct ipv6_hdr *pIPv6_hdr = NULL; switch (layer3) { - case RTE_PTYPE_L3_IPV4: - { - pIPv4_hdr = (struct ipv4_hdr *) (packet + ntpv->dyn3->offset0); + case RTE_PTYPE_L3_IPV4: { + pIPv4_hdr = (struct ipv4_hdr *)(packet + ntpv->dyn3->offset0); if (!is_span) { v4Tuple.sa = pIPv4_hdr->src_addr; v4Tuple.da = pIPv4_hdr->dst_addr; @@ -495,9 +489,8 @@ static int ProgramFlow(Packet *p, int inline_mode) } break; } - case RTE_PTYPE_L3_IPV6: - { - pIPv6_hdr = (struct ipv6_hdr *) (packet + ntpv->dyn3->offset0); + case RTE_PTYPE_L3_IPV6: { + pIPv6_hdr = (struct ipv6_hdr *)(packet + ntpv->dyn3->offset0); do_swap = (CompareIPv6Addr(pIPv6_hdr->src_addr, pIPv6_hdr->dst_addr) > 0); if (!is_span) { @@ -516,16 +509,14 @@ static int ProgramFlow(Packet *p, int inline_mode) } break; } - default: - { + default: { return 0; } } switch (layer4) { - case RTE_PTYPE_L4_TCP: - { - struct tcp_hdr *tcp_hdr = (struct tcp_hdr *) (packet + ntpv->dyn3->offset1); + case RTE_PTYPE_L4_TCP: { + struct tcp_hdr *tcp_hdr = (struct tcp_hdr *)(packet + ntpv->dyn3->offset1); if (layer3 == RTE_PTYPE_L3_IPV4) { if (!is_span) { v4Tuple.dp = tcp_hdr->dst_port; @@ -562,9 +553,8 @@ static int ProgramFlow(Packet *p, int inline_mode) flow_match.ipProtocolField = 6; break; } - case RTE_PTYPE_L4_UDP: - { - struct udp_hdr *udp_hdr = (struct udp_hdr *) (packet + ntpv->dyn3->offset1); + case RTE_PTYPE_L4_UDP: { + struct udp_hdr *udp_hdr = (struct udp_hdr *)(packet + ntpv->dyn3->offset1); if (layer3 == RTE_PTYPE_L3_IPV4) { if (!is_span) { v4Tuple.dp = udp_hdr->dst_port; @@ -601,8 +591,7 @@ static int ProgramFlow(Packet *p, int inline_mode) flow_match.ipProtocolField = 17; break; } - default: - { + default: { return 0; } } @@ -672,16 +661,16 @@ static int NapatechBypassCallback(Packet *p) TmEcode NapatechStreamThreadInit(ThreadVars *tv, const void *initdata, void **data) { SCEnter(); - struct NapatechStreamDevConf *conf = (struct NapatechStreamDevConf *) initdata; + struct NapatechStreamDevConf *conf = (struct NapatechStreamDevConf *)initdata; uint16_t stream_id = conf->stream_id; *data = NULL; - NapatechThreadVars *ntv = SCCalloc(1, sizeof (NapatechThreadVars)); + NapatechThreadVars *ntv = SCCalloc(1, sizeof(NapatechThreadVars)); if (unlikely(ntv == NULL)) { FatalError("Failed to allocate memory for NAPATECH thread vars."); } - memset(ntv, 0, sizeof (NapatechThreadVars)); + memset(ntv, 0, sizeof(NapatechThreadVars)); ntv->stream_id = stream_id; ntv->tv = tv; @@ -689,7 +678,7 @@ TmEcode NapatechStreamThreadInit(ThreadVars *tv, const void *initdata, void **da SCLogDebug("Started processing packets from NAPATECH Stream: %u", ntv->stream_id); - *data = (void *) ntv; + *data = (void *)ntv; SCReturnInt(TM_ECODE_OK); } @@ -855,8 +844,7 @@ TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot) } #endif /* The last thread to run sets up and deletes the streams */ - status = NapatechSetupTraffic(NapatechGetNumFirstStream(), - NapatechGetNumLastStream()); + status = NapatechSetupTraffic(NapatechGetNumFirstStream(), NapatechGetNumLastStream()); closer = 1; @@ -871,8 +859,7 @@ TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot) } } // is_autoconfig - SCLogInfo( - "Napatech Packet Loop Started - cpu: %3d, cpu_numa: %3d stream: %3u ", + SCLogInfo("Napatech Packet Loop Started - cpu: %3d, cpu_numa: %3d stream: %3u ", sched_getcpu(), numa_node, ntv->stream_id); SCLogDebug("Opening NAPATECH Stream: %u for processing", ntv->stream_id); @@ -884,7 +871,7 @@ TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot) SCFree(ntv); SCReturnInt(TM_ECODE_FAILED); } - TmSlot *s = (TmSlot *) slot; + TmSlot *s = (TmSlot *)slot; ntv->slot = s->slot_next; // Indicate that the thread is actually running its application level code (i.e., it can poll @@ -898,16 +885,14 @@ TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot) /* Napatech returns packets 1 at a time */ status = NT_NetRxGet(ntv->rx_stream, &packet_buffer, 1000); - if (unlikely( - status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) { + if (unlikely(status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) { if (status == NT_STATUS_TIMEOUT) { TmThreadsCaptureHandleTimeout(tv, NULL); } continue; } else if (unlikely(status != NT_SUCCESS)) { NAPATECH_ERROR(status); - SCLogInfo("Failed to read from Napatech Stream %d: %s", - ntv->stream_id, error_buffer); + SCLogInfo("Failed to read from Napatech Stream %d: %s", ntv->stream_id, error_buffer); break; } @@ -967,7 +952,8 @@ TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot) p->ntpv.stream_id = ntv->stream_id; p->datalink = LINKTYPE_ETHERNET; - if (unlikely(PacketSetData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) { + if (unlikely(PacketSetData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), + NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) { TmqhOutputPacketpool(ntv->tv, p); SCReturnInt(TM_ECODE_FAILED); } @@ -999,17 +985,17 @@ TmEcode NapatechPacketLoop(ThreadVars *tv, void *data, void *slot) */ void NapatechStreamThreadExitStats(ThreadVars *tv, void *data) { - NapatechThreadVars *ntv = (NapatechThreadVars *) data; + NapatechThreadVars *ntv = (NapatechThreadVars *)data; NapatechCurrentStats stat = NapatechGetCurrentStats(ntv->stream_id); double percent = 0; if (stat.current_drop_packets > 0) - percent = (((double) stat.current_drop_packets) - / (stat.current_packets + stat.current_drop_packets)) * 100; + percent = (((double)stat.current_drop_packets) / + (stat.current_packets + stat.current_drop_packets)) * + 100; - SCLogInfo("nt%lu - pkts: %lu; drop: %lu (%5.2f%%); bytes: %lu", - (uint64_t) ntv->stream_id, stat.current_packets, - stat.current_drop_packets, percent, stat.current_bytes); + SCLogInfo("nt%lu - pkts: %lu; drop: %lu (%5.2f%%); bytes: %lu", (uint64_t)ntv->stream_id, + stat.current_packets, stat.current_drop_packets, percent, stat.current_bytes); SC_ATOMIC_ADD(total_packets, stat.current_packets); SC_ATOMIC_ADD(total_drops, stat.current_drop_packets); @@ -1017,8 +1003,9 @@ void NapatechStreamThreadExitStats(ThreadVars *tv, void *data) if (SC_ATOMIC_GET(total_tallied) == NapatechGetNumConfiguredStreams()) { if (SC_ATOMIC_GET(total_drops) > 0) - percent = (((double) SC_ATOMIC_GET(total_drops)) / (SC_ATOMIC_GET(total_packets) - + SC_ATOMIC_GET(total_drops))) * 100; + percent = (((double)SC_ATOMIC_GET(total_drops)) / + (SC_ATOMIC_GET(total_packets) + SC_ATOMIC_GET(total_drops))) * + 100; SCLogInfo(" "); SCLogInfo("--- Total Packets: %ld Total Dropped: %ld (%5.2f%%)", @@ -1026,10 +1013,8 @@ void NapatechStreamThreadExitStats(ThreadVars *tv, void *data) #ifdef NAPATECH_ENABLE_BYPASS SCLogInfo("--- BypassCB - Total: %ld, UDP: %ld, TCP: %ld, Unhandled: %ld", - SC_ATOMIC_GET(flow_callback_cnt), - SC_ATOMIC_GET(flow_callback_udp_pkts), - SC_ATOMIC_GET(flow_callback_tcp_pkts), - SC_ATOMIC_GET(flow_callback_unhandled_pkts)); + SC_ATOMIC_GET(flow_callback_cnt), SC_ATOMIC_GET(flow_callback_udp_pkts), + SC_ATOMIC_GET(flow_callback_tcp_pkts), SC_ATOMIC_GET(flow_callback_unhandled_pkts)); #endif } } @@ -1042,7 +1027,7 @@ void NapatechStreamThreadExitStats(ThreadVars *tv, void *data) TmEcode NapatechStreamThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); - NapatechThreadVars *ntv = (NapatechThreadVars *) data; + NapatechThreadVars *ntv = (NapatechThreadVars *)data; SCLogDebug("Closing Napatech Stream: %d", ntv->stream_id); NT_NetRxClose(ntv->rx_stream); @@ -1064,7 +1049,7 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data) { SCEnter(); - DecodeThreadVars *dtv = (DecodeThreadVars *) data; + DecodeThreadVars *dtv = (DecodeThreadVars *)data; BUG_ON(PKT_IS_PSEUDOPKT(p)); @@ -1102,7 +1087,7 @@ TmEcode NapatechDecodeThreadInit(ThreadVars *tv, const void *initdata, void **da } DecodeRegisterPerfCounters(dtv, tv); - *data = (void *) dtv; + *data = (void *)dtv; SCReturnInt(TM_ECODE_OK); } diff --git a/src/source-napatech.h b/src/source-napatech.h index c638f89dae64..cfae5f5b6b6c 100644 --- a/src/source-napatech.h +++ b/src/source-napatech.h @@ -31,8 +31,7 @@ void TmModuleNapatechDecodeRegister(void); #ifdef HAVE_NAPATECH #include -struct NapatechStreamDevConf -{ +struct NapatechStreamDevConf { uint16_t stream_id; }; diff --git a/src/source-netmap.c b/src/source-netmap.c index 0b04b41b52d6..3d8c61dc36bb 100644 --- a/src/source-netmap.c +++ b/src/source-netmap.c @@ -16,10 +16,10 @@ */ /** -* \defgroup netmap Netmap running mode -* -* @{ -*/ + * \defgroup netmap Netmap running mode + * + * @{ + */ /** * \file @@ -38,10 +38,10 @@ #include "suricata-common.h" #include "tm-threads.h" #include "packet.h" -#include "util-bpf.h" -#include "util-privs.h" -#include "util-validate.h" -#include "util-datalink.h" +#include "util/bpf.h" +#include "util/privs.h" +#include "util/validate.h" +#include "util/datalink.h" #include "source-netmap.h" @@ -57,13 +57,13 @@ #endif /* HAVE_NETMAP */ -#include "util-ioctl.h" +#include "util/ioctl.h" #ifndef HAVE_NETMAP /** -* \brief this function prints an error message and exits. -*/ + * \brief this function prints an error message and exits. + */ static TmEcode NoNetmapSupportExit(ThreadVars *tv, const void *initdata, void **data) { FatalError("Error creating thread %s: Netmap is not enabled. " @@ -71,7 +71,7 @@ static TmEcode NoNetmapSupportExit(ThreadVars *tv, const void *initdata, void ** tv->name); } -void TmModuleReceiveNetmapRegister (void) +void TmModuleReceiveNetmapRegister(void) { tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap"; tmm_modules[TMM_RECEIVENETMAP].ThreadInit = NoNetmapSupportExit; @@ -79,9 +79,9 @@ void TmModuleReceiveNetmapRegister (void) } /** -* \brief Registration Function for DecodeNetmap. -*/ -void TmModuleDecodeNetmapRegister (void) + * \brief Registration Function for DecodeNetmap. + */ +void TmModuleDecodeNetmapRegister(void) { tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap"; tmm_modules[TMM_DECODENETMAP].ThreadInit = NoNetmapSupportExit; @@ -95,14 +95,14 @@ void TmModuleDecodeNetmapRegister (void) #define POLL_TIMEOUT 100 #if defined(__linux__) -#define POLL_EVENTS (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL) +#define POLL_EVENTS (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL) #ifndef IFF_PPROMISC #define IFF_PPROMISC IFF_PROMISC #endif #else -#define POLL_EVENTS (POLLHUP|POLLERR|POLLNVAL) +#define POLL_EVENTS (POLLHUP | POLLERR | POLLNVAL) #endif enum { NETMAP_FLAG_ZERO_COPY = 1, NETMAP_FLAG_EXCL_RING_ACCESS = 2 }; @@ -111,8 +111,7 @@ enum { NETMAP_FLAG_ZERO_COPY = 1, NETMAP_FLAG_EXCL_RING_ACCESS = 2 }; * \brief Netmap device instance. Each ring for each device gets its own * device. */ -typedef struct NetmapDevice_ -{ +typedef struct NetmapDevice_ { struct nmport_d *nmd; unsigned int ref; SC_ATOMIC_DECLARE(unsigned int, threads_run); @@ -130,8 +129,7 @@ typedef struct NetmapDevice_ /** * \brief Module thread local variables. */ -typedef struct NetmapThreadVars_ -{ +typedef struct NetmapThreadVars_ { /* receive interface */ NetmapDevice *ifsrc; /* dst interface for IPS mode */ @@ -283,10 +281,8 @@ static int NetmapOpen(NetmapIfaceSettings *ns, NetmapDevice **pdevice, int verbo char base_name[IFNAMSIZ]; strlcpy(base_name, ns->iface, sizeof(base_name)); if (strlen(base_name) > 0 && - (base_name[strlen(base_name)-1] == '^' || - base_name[strlen(base_name)-1] == '*')) - { - base_name[strlen(base_name)-1] = '\0'; + (base_name[strlen(base_name) - 1] == '^' || base_name[strlen(base_name) - 1] == '*')) { + base_name[strlen(base_name) - 1] = '\0'; } if (ns->real) { @@ -305,7 +301,7 @@ static int NetmapOpen(NetmapIfaceSettings *ns, NetmapDevice **pdevice, int verbo goto error; } /* if needed, try to set iface in promisc mode */ - if (ns->promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) { + if (ns->promisc && (if_flags & (IFF_PROMISC | IFF_PPROMISC)) == 0) { if_flags |= IFF_PPROMISC; SetIfaceFlags(base_name, if_flags); // TODO reset at exit // TODO move to parse config? @@ -326,7 +322,7 @@ static int NetmapOpen(NetmapIfaceSettings *ns, NetmapDevice **pdevice, int verbo /* Search for interface in our already opened list. */ /* We will find it when opening multiple rings on */ /* the device when it exposes multiple RSS queues. */ - TAILQ_FOREACH(spdev, &netmap_devlist, next) { + TAILQ_FOREACH (spdev, &netmap_devlist, next) { SCLogDebug("spdev %s", spdev->ifname); if (direction == spdev->direction && strcmp(ns->iface, spdev->ifname) == 0) { ring = spdev->ring + 1; @@ -379,14 +375,15 @@ static int NetmapOpen(NetmapIfaceSettings *ns, NetmapDevice **pdevice, int verbo char devname[128]; if (strncmp(ns->iface, "netmap:", 7) == 0) { - snprintf(devname, sizeof(devname), "%s}%d%s%s", - ns->iface, ring, strlen(optstr) ? "/" : "", optstr); - } else if (strlen(ns->iface) > 5 && strncmp(ns->iface, "vale", 4) == 0 && isdigit(ns->iface[4])) { + snprintf(devname, sizeof(devname), "%s}%d%s%s", ns->iface, ring, strlen(optstr) ? "/" : "", + optstr); + } else if (strlen(ns->iface) > 5 && strncmp(ns->iface, "vale", 4) == 0 && + isdigit(ns->iface[4])) { snprintf(devname, sizeof(devname), "%s", ns->iface); } else if (ring == 0 && ns->threads == 1) { /* just a single thread and ring, so don't use ring param */ - snprintf(devname, sizeof(devname), "netmap:%s%s%s", - ns->iface, strlen(optstr) ? "/" : "", optstr); + snprintf(devname, sizeof(devname), "netmap:%s%s%s", ns->iface, strlen(optstr) ? "/" : "", + optstr); SCLogDebug("device with %s-ring enabled (devname): %s", soft ? "SW" : "HW", devname); } else { /* Going to be using multiple threads and rings */ @@ -486,8 +483,8 @@ static inline void NetmapDumpCounters(NetmapThreadVars *ntv) { StatsAddUI64(ntv->tv, ntv->capture_kernel_packets, ntv->pkts); StatsAddUI64(ntv->tv, ntv->capture_kernel_drops, ntv->drops); - (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops); - (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts); + (void)SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops); + (void)SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts); ntv->drops = 0; ntv->pkts = 0; } @@ -548,23 +545,19 @@ static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, const void *initdata, voi } /* basic counters */ - ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", - ntv->tv); - ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", - ntv->tv); + ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", ntv->tv); + ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", ntv->tv); if (aconf->in.bpf_filter) { SCLogConfig("%s: using BPF '%s'", ntv->ifsrc->ifname, aconf->in.bpf_filter); char errbuf[PCAP_ERRBUF_SIZE]; - if (SCBPFCompile(default_packet_size, /* snaplen_arg */ - LINKTYPE_ETHERNET, /* linktype_arg */ - &ntv->bpf_prog, /* program */ - aconf->in.bpf_filter, /* const char *buf */ - 1, /* optimize */ - PCAP_NETMASK_UNKNOWN, /* mask */ - errbuf, - sizeof(errbuf)) == -1) - { + if (SCBPFCompile(default_packet_size, /* snaplen_arg */ + LINKTYPE_ETHERNET, /* linktype_arg */ + &ntv->bpf_prog, /* program */ + aconf->in.bpf_filter, /* const char *buf */ + 1, /* optimize */ + PCAP_NETMASK_UNKNOWN, /* mask */ + errbuf, sizeof(errbuf)) == -1) { SCLogError("%s: failed to compile BPF \"%s\": %s", ntv->ifsrc->ifname, aconf->in.bpf_filter, errbuf); goto error_dst; @@ -666,7 +659,7 @@ static void NetmapReleasePacket(Packet *p) static void NetmapProcessPacket(NetmapThreadVars *ntv, const struct nm_pkthdr *ph) { if (ntv->bpf_prog.bf_len) { - struct pcap_pkthdr pkthdr = { {0, 0}, ph->len, ph->len }; + struct pcap_pkthdr pkthdr = { { 0, 0 }, ph->len, ph->len }; if (pcap_offline_filter(&ntv->bpf_prog, &pkthdr, ph->buf) == 0) { return; } @@ -699,8 +692,7 @@ static void NetmapProcessPacket(NetmapThreadVars *ntv, const struct nm_pkthdr *p p->ReleasePacket = NetmapReleasePacket; p->netmap_v.ntv = ntv; - SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", - GET_PKT_LEN(p), p, GET_PKT_DATA(p)); + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", GET_PKT_LEN(p), p, GET_PKT_DATA(p)); (void)TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p); } @@ -803,7 +795,7 @@ static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) // packets) TmThreadsSetFlag(tv, THV_RUNNING); - for(;;) { + for (;;) { if (unlikely(suricata_ctl_flags != 0)) { break; } @@ -990,5 +982,5 @@ void TmModuleDecodeNetmapRegister(void) #endif /* HAVE_NETMAP */ /** -* @} -*/ + * @} + */ diff --git a/src/source-netmap.h b/src/source-netmap.h index b60d544d5c28..3be1d31e23c4 100644 --- a/src/source-netmap.h +++ b/src/source-netmap.h @@ -16,11 +16,11 @@ */ /** -* \file -* -* \author Aleksey Katargin -* \author Victor Julien -*/ + * \file + * + * \author Aleksey Katargin + * \author Victor Julien + */ #ifndef __SOURCE_NETMAP_H__ #define __SOURCE_NETMAP_H__ @@ -32,18 +32,17 @@ enum { NETMAP_COPY_MODE_IPS, }; -#define NETMAP_IFACE_NAME_LENGTH 48 +#define NETMAP_IFACE_NAME_LENGTH 48 -typedef struct NetmapIfaceSettings_ -{ +typedef struct NetmapIfaceSettings_ { /* real inner interface name */ char iface[NETMAP_IFACE_NAME_LENGTH]; /* sw ring flag for out_iface */ bool sw_ring; bool promisc; - bool real; /**< real iface or not. Not in case of vale, pipe */ - bool ips; /**< set to true if checksum_mode != NETMAP_COPY_MODE_NONE */ + bool real; /**< real iface or not. Not in case of vale, pipe */ + bool ips; /**< set to true if checksum_mode != NETMAP_COPY_MODE_NONE */ bool threads_auto; uint16_t threads; @@ -52,8 +51,7 @@ typedef struct NetmapIfaceSettings_ const char *bpf_filter; } NetmapIfaceSettings; -typedef struct NetmapIfaceConfig_ -{ +typedef struct NetmapIfaceConfig_ { /* semantic interface name */ char iface_name[NETMAP_IFACE_NAME_LENGTH]; @@ -67,15 +65,14 @@ typedef struct NetmapIfaceConfig_ void (*DerefFunc)(void *); } NetmapIfaceConfig; -typedef struct NetmapPacketVars_ -{ +typedef struct NetmapPacketVars_ { /* NetmapThreadVars */ void *ntv; } NetmapPacketVars; int NetmapGetRSSCount(const char *ifname); -void TmModuleReceiveNetmapRegister (void); -void TmModuleDecodeNetmapRegister (void); +void TmModuleReceiveNetmapRegister(void); +void TmModuleDecodeNetmapRegister(void); #endif /* __SOURCE_NETMAP_H__ */ diff --git a/src/source-nflog.c b/src/source-nflog.c index f7d3616c621d..04900682c9af 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -35,9 +35,9 @@ #include "tmqh-packetpool.h" #include "runmodes.h" -#include "util-error.h" -#include "util-device.h" -#include "util-datalink.h" +#include "util/error.h" +#include "util/device.h" +#include "util/datalink.h" #ifndef HAVE_NFLOG /** Handle the case where no NFLOG support is compiled in. @@ -46,13 +46,13 @@ TmEcode NoNFLOGSupportExit(ThreadVars *, const void *, void **); -void TmModuleReceiveNFLOGRegister (void) +void TmModuleReceiveNFLOGRegister(void) { tmm_modules[TMM_RECEIVENFLOG].name = "ReceiveNFLOG"; tmm_modules[TMM_RECEIVENFLOG].ThreadInit = NoNFLOGSupportExit; } -void TmModuleDecodeNFLOGRegister (void) +void TmModuleDecodeNFLOGRegister(void) { tmm_modules[TMM_DECODENFLOG].name = "DecodeNFLOG"; tmm_modules[TMM_DECODENFLOG].ThreadInit = NoNFLOGSupportExit; @@ -113,7 +113,7 @@ typedef struct NFLOGThreadVars_ { /** * \brief Registration function for ReceiveNFLOG */ -void TmModuleReceiveNFLOGRegister (void) +void TmModuleReceiveNFLOGRegister(void) { tmm_modules[TMM_RECEIVENFLOG].name = "ReceiveNFLOG"; tmm_modules[TMM_RECEIVENFLOG].ThreadInit = ReceiveNFLOGThreadInit; @@ -128,7 +128,7 @@ void TmModuleReceiveNFLOGRegister (void) /** * \brief Registration function for DecodeNFLOG */ -void TmModuleDecodeNFLOGRegister (void) +void TmModuleDecodeNFLOGRegister(void) { tmm_modules[TMM_DECODENFLOG].name = "DecodeNFLOG"; tmm_modules[TMM_DECODENFLOG].ThreadInit = DecodeNFLOGThreadInit; @@ -142,10 +142,10 @@ void TmModuleDecodeNFLOGRegister (void) * \brief NFLOG callback function * This function setup a packet from a nflog message */ -static int NFLOGCallback(struct nflog_g_handle *gh, struct nfgenmsg *msg, - struct nflog_data *nfa, void *data) +static int NFLOGCallback( + struct nflog_g_handle *gh, struct nfgenmsg *msg, struct nflog_data *nfa, void *data) { - NFLOGThreadVars *ntv = (NFLOGThreadVars *) data; + NFLOGThreadVars *ntv = (NFLOGThreadVars *)data; struct nfulnl_msg_packet_hdr *ph; char *payload; int ret; @@ -192,7 +192,7 @@ static int NFLOGCallback(struct nflog_g_handle *gh, struct nfgenmsg *msg, ntv->pkts++; ntv->bytes += GET_PKT_LEN(p); #endif - (void) SC_ATOMIC_ADD(ntv->livedev->pkts, 1); + (void)SC_ATOMIC_ADD(ntv->livedev->pkts, 1); if (TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK) { return -1; @@ -274,18 +274,14 @@ TmEcode ReceiveNFLOGThreadInit(ThreadVars *tv, const void *initdata, void **data } if (nflog_set_qthresh(ntv->gh, ntv->qthreshold) >= 0) - SCLogDebug("NFLOG netlink queue threshold has been set to %d", - ntv->qthreshold); + SCLogDebug("NFLOG netlink queue threshold has been set to %d", ntv->qthreshold); else - SCLogDebug("NFLOG netlink queue threshold can't be set to %d", - ntv->qthreshold); + SCLogDebug("NFLOG netlink queue threshold can't be set to %d", ntv->qthreshold); if (nflog_set_timeout(ntv->gh, ntv->qtimeout) >= 0) - SCLogDebug("NFLOG netlink queue timeout has been set to %d", - ntv->qtimeout); + SCLogDebug("NFLOG netlink queue timeout has been set to %d", ntv->qtimeout); else - SCLogDebug("NFLOG netlink queue timeout can't be set to %d", - ntv->qtimeout); + SCLogDebug("NFLOG netlink queue timeout can't be set to %d", ntv->qtimeout); ntv->livedev = LiveGetDevice(nflconfig->numgroup); if (ntv->livedev == NULL) { @@ -308,10 +304,8 @@ TmEcode ReceiveNFLOGThreadInit(ThreadVars *tv, const void *initdata, void **data } #ifdef PACKET_STATISTICS - ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", - ntv->tv); - ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", - ntv->tv); + ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", ntv->tv); + ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", ntv->tv); #endif char *active_runmode = RunmodeGetActive(); @@ -403,7 +397,6 @@ static int NFLOGSetnlbufsiz(void *data, unsigned int size) "`buffer-size` and `max-size` in nflog configuration", ntv->nlbufsiz); return 0; - } /** @@ -425,7 +418,7 @@ TmEcode ReceiveNFLOGLoop(ThreadVars *tv, void *data, void *slot) int rv, fd; int ret = -1; - ntv->slot = ((TmSlot *) slot)->slot_next; + ntv->slot = ((TmSlot *)slot)->slot_next; fd = nflog_fd(ntv->h); if (fd < 0) { @@ -486,11 +479,9 @@ void ReceiveNFLOGThreadExitStats(ThreadVars *tv, void *data) SCEnter(); NFLOGThreadVars *ntv = (NFLOGThreadVars *)data; - SCLogNotice("(%s) Pkts %" PRIu32 ", Bytes %" PRIu64 "", - tv->name, ntv->pkts, ntv->bytes); + SCLogNotice("(%s) Pkts %" PRIu32 ", Bytes %" PRIu64 "", tv->name, ntv->pkts, ntv->bytes); } - /** * \brief Decode IPv4/v6 packets. * @@ -515,7 +506,7 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data) } SCLogDebug("IPv4 packet"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p)); - } else if(IPV6_GET_RAW_VER(ip6h) == 6) { + } else if (IPV6_GET_RAW_VER(ip6h) == 6) { if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) { return TM_ECODE_FAILED; } diff --git a/src/source-nflog.h b/src/source-nflog.h index 98dd9edf20eb..86bc87dc7513 100644 --- a/src/source-nflog.h +++ b/src/source-nflog.h @@ -30,8 +30,7 @@ #endif /* HAVE_NFLOG */ #define NFLOG_GROUP_NAME_LENGTH 48 -typedef struct NflogGroupConfig_ -{ +typedef struct NflogGroupConfig_ { /* nflog's group */ uint16_t group; /* netlink buffer size */ @@ -51,8 +50,7 @@ typedef struct NflogGroupConfig_ void (*DerefFunc)(void *); } NflogGroupConfig; -typedef struct NFLOGPacketVars_ -{ +typedef struct NFLOGPacketVars_ { uint32_t mark; uint32_t ifi; uint32_t ifo; diff --git a/src/source-nfq-prototypes.h b/src/source-nfq-prototypes.h index eef25884b79d..ee7ce43ef9de 100644 --- a/src/source-nfq-prototypes.h +++ b/src/source-nfq-prototypes.h @@ -24,9 +24,8 @@ #ifndef __SOURCE_NFQ_PROTOTYPES_H__ #define __SOURCE_NFQ_PROTOTYPES_H__ -void TmModuleReceiveNFQRegister (void); -void TmModuleVerdictNFQRegister (void); -void TmModuleDecodeNFQRegister (void); +void TmModuleReceiveNFQRegister(void); +void TmModuleVerdictNFQRegister(void); +void TmModuleDecodeNFQRegister(void); #endif /* __SOURCE_NFQ_PROTOTYPES_H__ */ - diff --git a/src/source-nfq.c b/src/source-nfq.c index 5293f2529a4c..f179cd082bb9 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -42,13 +42,13 @@ #include "source-nfq-prototypes.h" #include "action-globals.h" -#include "util-datalink.h" -#include "util-debug.h" -#include "util-error.h" -#include "util-byte.h" -#include "util-cpu.h" -#include "util-privs.h" -#include "util-device.h" +#include "util/datalink.h" +#include "util/debug.h" +#include "util/error.h" +#include "util/byte.h" +#include "util/cpu.h" +#include "util/privs.h" +#include "util/device.h" #include "runmodes.h" @@ -58,7 +58,7 @@ #ifndef NFQ static TmEcode NoNFQSupportExit(ThreadVars *, const void *, void **); -void TmModuleReceiveNFQRegister (void) +void TmModuleReceiveNFQRegister(void) { tmm_modules[TMM_RECEIVENFQ].name = "ReceiveNFQ"; tmm_modules[TMM_RECEIVENFQ].ThreadInit = NoNFQSupportExit; @@ -68,7 +68,7 @@ void TmModuleReceiveNFQRegister (void) tmm_modules[TMM_RECEIVENFQ].flags = TM_FLAG_RECEIVE_TM; } -void TmModuleVerdictNFQRegister (void) +void TmModuleVerdictNFQRegister(void) { tmm_modules[TMM_VERDICTNFQ].name = "VerdictNFQ"; tmm_modules[TMM_VERDICTNFQ].ThreadInit = NoNFQSupportExit; @@ -77,7 +77,7 @@ void TmModuleVerdictNFQRegister (void) tmm_modules[TMM_VERDICTNFQ].cap_flags = SC_CAP_NET_ADMIN; } -void TmModuleDecodeNFQRegister (void) +void TmModuleDecodeNFQRegister(void) { tmm_modules[TMM_DECODENFQ].name = "DecodeNFQ"; tmm_modules[TMM_DECODENFQ].ThreadInit = NoNFQSupportExit; @@ -99,7 +99,7 @@ static TmEcode NoNFQSupportExit(ThreadVars *tv, const void *initdata, void **dat extern uint16_t max_pending_packets; -#define MAX_ALREADY_TREATED 5 +#define MAX_ALREADY_TREATED 5 #define NFQ_VERDICT_RETRY_COUNT 3 static int already_seen_warning; static int runmode_workers; @@ -110,15 +110,14 @@ static int runmode_workers; #define SOL_NETLINK 270 #endif -typedef struct NFQThreadVars_ -{ +typedef struct NFQThreadVars_ { uint16_t nfq_index; ThreadVars *tv; TmSlot *slot; LiveDevice *livedev; - char *data; /** Per function and thread data */ + char *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ } NFQThreadVars; /* shared vars for all for nfq queues and threads */ @@ -151,7 +150,7 @@ typedef enum NFQMode_ { NFQ_ROUTE_MODE, } NFQMode; -#define NFQ_FLAG_FAIL_OPEN (1 << 0) +#define NFQ_FLAG_FAIL_OPEN (1 << 0) typedef struct NFQCnf_ { NFQMode mode; @@ -166,7 +165,7 @@ typedef struct NFQCnf_ { NFQCnf nfq_config; -void TmModuleReceiveNFQRegister (void) +void TmModuleReceiveNFQRegister(void) { /* XXX create a general NFQ setup function */ memset(&nfq_g, 0, sizeof(nfq_g)); @@ -181,7 +180,7 @@ void TmModuleReceiveNFQRegister (void) tmm_modules[TMM_RECEIVENFQ].flags = TM_FLAG_RECEIVE_TM; } -void TmModuleVerdictNFQRegister (void) +void TmModuleVerdictNFQRegister(void) { tmm_modules[TMM_VERDICTNFQ].name = "VerdictNFQ"; tmm_modules[TMM_VERDICTNFQ].ThreadInit = VerdictNFQThreadInit; @@ -189,7 +188,7 @@ void TmModuleVerdictNFQRegister (void) tmm_modules[TMM_VERDICTNFQ].ThreadDeinit = VerdictNFQThreadDeinit; } -void TmModuleDecodeNFQRegister (void) +void TmModuleDecodeNFQRegister(void) { tmm_modules[TMM_DECODENFQ].name = "DecodeNFQ"; tmm_modules[TMM_DECODENFQ].ThreadInit = DecodeNFQThreadInit; @@ -211,7 +210,7 @@ void NFQInitConfig(bool quiet) SCLogDebug("Initializing NFQ"); - memset(&nfq_config, 0, sizeof(nfq_config)); + memset(&nfq_config, 0, sizeof(nfq_config)); if ((ConfGet("nfq.mode", &nfq_mode)) == 0) { nfq_config.mode = NFQ_ACCEPT_MODE; @@ -220,7 +219,7 @@ void NFQInitConfig(bool quiet) nfq_config.mode = NFQ_ACCEPT_MODE; } else if (!strcmp("repeat", nfq_mode)) { nfq_config.mode = NFQ_REPEAT_MODE; - } else if (!strcmp("route", nfq_mode)) { + } else if (!strcmp("route", nfq_mode)) { nfq_config.mode = NFQ_ROUTE_MODE; } else { FatalError("Unknown nfq.mode"); @@ -264,7 +263,7 @@ void NFQInitConfig(bool quiet) value = 255; } if (value > 1) - nfq_config.batchcount = (uint8_t) (value - 1); + nfq_config.batchcount = (uint8_t)(value - 1); #else SCLogWarning("nfq.%s set but NFQ library has no support for it.", "batchcount"); #endif @@ -276,16 +275,15 @@ void NFQInitConfig(bool quiet) SCLogInfo("NFQ running in standard ACCEPT/DROP mode"); break; case NFQ_REPEAT_MODE: - SCLogInfo("NFQ running in REPEAT mode with mark %"PRIu32"/%"PRIu32, + SCLogInfo("NFQ running in REPEAT mode with mark %" PRIu32 "/%" PRIu32, nfq_config.mark, nfq_config.mask); break; case NFQ_ROUTE_MODE: - SCLogInfo("NFQ running in route mode with next queue %"PRIu32, + SCLogInfo("NFQ running in route mode with next queue %" PRIu32, nfq_config.next_queue >> 16); - break; + break; } } - } static uint8_t NFQVerdictCacheLen(NFQQueueVars *t) @@ -305,14 +303,11 @@ static void NFQVerdictCacheFlush(NFQQueueVars *t) do { if (t->verdict_cache.mark_valid) - ret = nfq_set_verdict_batch2(t->qh, - t->verdict_cache.packet_id, - t->verdict_cache.verdict, - t->verdict_cache.mark); + ret = nfq_set_verdict_batch2(t->qh, t->verdict_cache.packet_id, + t->verdict_cache.verdict, t->verdict_cache.mark); else - ret = nfq_set_verdict_batch(t->qh, - t->verdict_cache.packet_id, - t->verdict_cache.verdict); + ret = nfq_set_verdict_batch( + t->qh, t->verdict_cache.packet_id, t->verdict_cache.verdict); } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_COUNT)); if (ret < 0) { @@ -359,7 +354,7 @@ static int NFQVerdictCacheAdd(NFQQueueVars *t, Packet *p, uint32_t verdict) else t->verdict_cache.len++; return 0; - flush: +flush: /* can't cache. Flush current cache and signal caller it should send single verdict */ if (NFQVerdictCacheLen(t) > 0) NFQVerdictCacheFlush(t); @@ -382,15 +377,17 @@ static inline void NFQMutexInit(NFQQueueVars *nq) } } -#define NFQMutexLock(nq) do { \ - if ((nq)->use_mutex) \ - SCMutexLock(&(nq)->mutex_qh); \ -} while (0) +#define NFQMutexLock(nq) \ + do { \ + if ((nq)->use_mutex) \ + SCMutexLock(&(nq)->mutex_qh); \ + } while (0) -#define NFQMutexUnlock(nq) do { \ - if ((nq)->use_mutex) \ - SCMutexUnlock(&(nq)->mutex_qh); \ -} while (0) +#define NFQMutexUnlock(nq) \ + do { \ + if ((nq)->use_mutex) \ + SCMutexUnlock(&(nq)->mutex_qh); \ + } while (0) /** * \brief Read data from nfq message and setup Packet @@ -399,7 +396,7 @@ static inline void NFQMutexInit(NFQQueueVars *nq) * In case of error, this function verdict the packet * to avoid skb to get stuck in kernel. */ -static int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) +static int NFQSetupPkt(Packet *p, struct nfq_q_handle *qh, void *data) { struct nfq_data *tb = (struct nfq_data *)data; int ret; @@ -418,8 +415,7 @@ static int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) /* coverity[missing_lock] */ p->nfq_v.mark = nfq_get_nfmark(tb); if (nfq_config.mode == NFQ_REPEAT_MODE) { - if ((nfq_config.mark & nfq_config.mask) == - (p->nfq_v.mark & nfq_config.mask)) { + if ((nfq_config.mark & nfq_config.mask) == (p->nfq_v.mark & nfq_config.mask)) { int iter = 0; if (already_seen_warning < MAX_ALREADY_TREATED) SCLogInfo("Packet seems already treated by suricata"); @@ -431,20 +427,20 @@ static int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) SCLogWarning( "nfq_set_verdict of %p failed %" PRId32 ": %s", p, ret, strerror(errno)); } - return -1 ; + return -1; } } // Switch to full featured release function p->ReleasePacket = NFQReleasePacket; - p->nfq_v.ifi = nfq_get_indev(tb); - p->nfq_v.ifo = nfq_get_outdev(tb); + p->nfq_v.ifi = nfq_get_indev(tb); + p->nfq_v.ifo = nfq_get_outdev(tb); p->nfq_v.verdicted = 0; #ifdef NFQ_GET_PAYLOAD_SIGNED ret = nfq_get_payload(tb, &pktdata); #else - ret = nfq_get_payload(tb, (unsigned char **) &pktdata); + ret = nfq_get_payload(tb, (unsigned char **)&pktdata); #endif /* NFQ_GET_PAYLOAD_SIGNED */ if (ret > 0) { /* nfq_get_payload returns a pointer to a part of memory @@ -461,7 +457,7 @@ static int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) } else { PacketCopyData(p, (uint8_t *)pktdata, ret); } - } else if (ret == -1) { + } else if (ret == -1) { /* unable to get pointer to data, ensure packet length is zero. * This will trigger an error in packet decoding */ SET_PKT_LEN(p, 0); @@ -502,8 +498,8 @@ static int NFQBypassCallback(Packet *p) if (p->flags & PKT_REBUILT_FRAGMENT) { Packet *tp = p->root ? p->root : p; SCSpinLock(&tp->persistent.tunnel_lock); - tp->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) - | (tp->nfq_v.mark & ~nfq_config.bypass_mask); + tp->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) | + (tp->nfq_v.mark & ~nfq_config.bypass_mask); tp->flags |= PKT_MARK_MODIFIED; SCSpinUnlock(&tp->persistent.tunnel_lock); return 1; @@ -511,16 +507,16 @@ static int NFQBypassCallback(Packet *p) return 0; } else { /* coverity[missing_lock] */ - p->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) - | (p->nfq_v.mark & ~nfq_config.bypass_mask); + p->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) | + (p->nfq_v.mark & ~nfq_config.bypass_mask); p->flags |= PKT_MARK_MODIFIED; } return 1; } -static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, - struct nfq_data *nfa, void *data) +static int NFQCallBack( + struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; ThreadVars *tv = ntv->tv; @@ -547,7 +543,7 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, q->pkts++; q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ - (void) SC_ATOMIC_ADD(ntv->livedev->pkts, 1); + (void)SC_ATOMIC_ADD(ntv->livedev->pkts, 1); /* NFQSetupPkt is issuing a verdict so we only recycle Packet and leave */ @@ -560,7 +556,7 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, q->pkts++; q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ - (void) SC_ATOMIC_ADD(ntv->livedev->pkts, 1); + (void)SC_ATOMIC_ADD(ntv->livedev->pkts, 1); if (TmThreadsSlotProcessPkt(tv, ntv->slot, p) != TM_ECODE_OK) { return -1; @@ -585,8 +581,7 @@ static TmEcode NFQInitThread(NFQThreadVars *t, uint32_t queue_maxlen) return TM_ECODE_FAILED; } - if (nfq_g.unbind == 0) - { + if (nfq_g.unbind == 0) { /* VJ: on my Ubuntu Hardy system this fails the first time it's * run. Ignoring the error seems to have no bad effects. */ SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)"); @@ -621,7 +616,7 @@ static TmEcode NFQInitThread(NFQThreadVars *t, uint32_t queue_maxlen) SCLogDebug("setting copy_packet mode"); /* 05DC = 1500 */ - //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) { + // if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) { if (nfq_set_mode(q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { SCLogError("can't set packet_copy mode"); return TM_ECODE_FAILED; @@ -648,19 +643,17 @@ static TmEcode NFQInitThread(NFQThreadVars *t, uint32_t queue_maxlen) NFQMutexInit(q); /* Set some netlink specific option on the socket to increase - performance */ + performance */ opt = 1; #ifdef NETLINK_BROADCAST_SEND_ERROR - if (setsockopt(q->fd, SOL_NETLINK, - NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)) == -1) { + if (setsockopt(q->fd, SOL_NETLINK, NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)) == -1) { SCLogWarning("can't set netlink broadcast error: %s", strerror(errno)); } #endif /* Don't send error about no buffer space available but drop the - packets instead */ + packets instead */ #ifdef NETLINK_NO_ENOBUFS - if (setsockopt(q->fd, SOL_NETLINK, - NETLINK_NO_ENOBUFS, &opt, sizeof(int)) == -1) { + if (setsockopt(q->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(int)) == -1) { SCLogWarning("can't set netlink enobufs: %s", strerror(errno)); } #endif @@ -692,12 +685,12 @@ static TmEcode NFQInitThread(NFQThreadVars *t, uint32_t queue_maxlen) tv.tv_sec = 1; tv.tv_usec = 0; - if(setsockopt(q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { + if (setsockopt(q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { SCLogWarning("can't set socket timeout: %s", strerror(errno)); } - SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "", - q->h, q->nh, q->qh, q->fd); + SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "", q->h, q->nh, q->qh, + q->fd); return TM_ECODE_OK; } @@ -710,7 +703,7 @@ TmEcode ReceiveNFQThreadInit(ThreadVars *tv, const void *initdata, void **data) sigfillset(&sigs); pthread_sigmask(SIG_BLOCK, &sigs, NULL); - NFQThreadVars *ntv = (NFQThreadVars *) initdata; + NFQThreadVars *ntv = (NFQThreadVars *)initdata; /* store the ThreadVars pointer in our NFQ thread context * as we will need it in our callback function */ ntv->tv = tv; @@ -858,7 +851,7 @@ int NFQParseAndRegisterQueues(const char *queues) { uint16_t queue_start = 0; uint16_t queue_end = 0; - uint16_t num_queues = 1; // if argument is correct, at least one queue will be created + uint16_t num_queues = 1; // if argument is correct, at least one queue will be created // Either "id" or "start:end" format (e.g., "12" or "0:5") int count = sscanf(queues, "%hu:%hu", &queue_start, &queue_end); @@ -971,7 +964,7 @@ static void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv) NFQMutexUnlock(t); #endif /* COUNTERS */ } - } else if(rv == 0) { + } else if (rv == 0) { SCLogWarning("recv got returncode 0"); } else { #ifdef DBG_PERF @@ -988,7 +981,7 @@ static void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv) } NFQMutexUnlock(t); if (ret != 0) { - SCLogDebug("nfq_handle_packet error %"PRId32, ret); + SCLogDebug("nfq_handle_packet error %" PRId32, ret); } } } @@ -1002,13 +995,13 @@ TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot) NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); - ntv->slot = ((TmSlot *) slot)->slot_next; + ntv->slot = ((TmSlot *)slot)->slot_next; // Indicate that the thread is actually running its application level code (i.e., it can poll // packets) TmThreadsSetFlag(tv, THV_RUNNING); - while(1) { + while (1) { if (unlikely(suricata_ctl_flags != 0)) { NFQDestroyQueue(nq); break; @@ -1028,9 +1021,9 @@ void ReceiveNFQThreadExitStats(ThreadVars *tv, void *data) NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); #ifdef COUNTERS - SCLogNotice("(%s) Treated: Pkts %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "", - tv->name, nq->pkts, nq->bytes, nq->errs); - SCLogNotice("(%s) Verdict: Accepted %"PRIu32", Dropped %"PRIu32", Replaced %"PRIu32, + SCLogNotice("(%s) Treated: Pkts %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "", tv->name, + nq->pkts, nq->bytes, nq->errs); + SCLogNotice("(%s) Verdict: Accepted %" PRIu32 ", Dropped %" PRIu32 ", Replaced %" PRIu32, tv->name, nq->accepted, nq->dropped, nq->replaced); #endif } @@ -1051,7 +1044,7 @@ static inline uint32_t GetVerdict(const Packet *p) verdict = NF_REPEAT; break; case NFQ_ROUTE_MODE: - verdict = ((uint32_t) NF_QUEUE) | nfq_config.next_queue; + verdict = ((uint32_t)NF_QUEUE) | nfq_config.next_queue; break; } } @@ -1089,7 +1082,7 @@ TmEcode NFQSetVerdict(Packet *p) return TM_ECODE_OK; } - //printf("%p verdicting on queue %" PRIu32 "\n", t, t->queue_num); + // printf("%p verdicting on queue %" PRIu32 "\n", t, t->queue_num); NFQMutexLock(t); if (t->qh == NULL) { @@ -1117,54 +1110,52 @@ TmEcode NFQSetVerdict(Packet *p) if (p->flags & PKT_MARK_MODIFIED) { #ifdef HAVE_NFQ_SET_VERDICT2 if (p->flags & PKT_STREAM_MODIFIED) { - ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, - p->nfq_v.mark, + ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, p->nfq_v.mark, GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { - ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, - p->nfq_v.mark, - 0, NULL); + ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, p->nfq_v.mark, 0, NULL); } #else /* fall back to old function */ if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, - htonl(p->nfq_v.mark), - GET_PKT_LEN(p), GET_PKT_DATA(p)); + htonl(p->nfq_v.mark), GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { - ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, - htonl(p->nfq_v.mark), - 0, NULL); + ret = nfq_set_verdict_mark( + t->qh, p->nfq_v.id, verdict, htonl(p->nfq_v.mark), 0, NULL); } #endif /* HAVE_NFQ_SET_VERDICT2 */ } else { if (p->flags & PKT_STREAM_MODIFIED) { - ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, - GET_PKT_LEN(p), GET_PKT_DATA(p)); + ret = nfq_set_verdict( + t->qh, p->nfq_v.id, verdict, GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL); } - } break; case NFQ_REPEAT_MODE: #ifdef HAVE_NFQ_SET_VERDICT2 if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, - (nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask), + (nfq_config.mark & nfq_config.mask) | + (p->nfq_v.mark & ~nfq_config.mask), GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, - (nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask), + (nfq_config.mark & nfq_config.mask) | + (p->nfq_v.mark & ~nfq_config.mask), 0, NULL); } #else /* fall back to old function */ if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, - htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)), + htonl((nfq_config.mark & nfq_config.mask) | + (p->nfq_v.mark & ~nfq_config.mask)), GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, - htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)), + htonl((nfq_config.mark & nfq_config.mask) | + (p->nfq_v.mark & ~nfq_config.mask)), 0, NULL); } #endif /* HAVE_NFQ_SET_VERDICT2 */ diff --git a/src/source-nfq.h b/src/source-nfq.h index b60e6d9cc537..d675ff0e3605 100644 --- a/src/source-nfq.h +++ b/src/source-nfq.h @@ -27,7 +27,7 @@ #ifdef NFQ #include "threads.h" -#include /* for NF_ACCEPT */ +#include /* for NF_ACCEPT */ #include // Netfilter's limit @@ -36,9 +36,8 @@ /* idea: set the recv-thread id in the packet to * select an verdict-queue */ -typedef struct NFQPacketVars_ -{ - int id; /* this nfq packets id */ +typedef struct NFQPacketVars_ { + int id; /* this nfq packets id */ uint16_t nfq_index; /* index in NFQ array */ uint8_t verdicted; @@ -48,8 +47,7 @@ typedef struct NFQPacketVars_ uint16_t hw_protocol; } NFQPacketVars; -typedef struct NFQQueueVars_ -{ +typedef struct NFQQueueVars_ { struct nfq_handle *h; struct nfnl_handle *nh; int fd; @@ -77,15 +75,14 @@ typedef struct NFQQueueVars_ uint32_t packet_id; /* id of last processed packet */ uint32_t verdict; uint32_t mark; - uint8_t mark_valid:1; + uint8_t mark_valid : 1; uint8_t len; uint8_t maxlen; } verdict_cache; } NFQQueueVars; -typedef struct NFQGlobalVars_ -{ +typedef struct NFQGlobalVars_ { char unbind; } NFQGlobalVars; @@ -97,4 +94,3 @@ void *NFQGetThread(int number); void NFQContextsClean(void); #endif /* NFQ */ #endif /* __SOURCE_NFQ_H__ */ - diff --git a/src/source-pcap-file-directory-helper.c b/src/source-pcap-file-directory-helper.c index 59c2116f99df..aae586293af7 100644 --- a/src/source-pcap-file-directory-helper.c +++ b/src/source-pcap-file-directory-helper.c @@ -26,9 +26,9 @@ #include "source-pcap-file-directory-helper.h" #include "suricata.h" #include "runmode-unix-socket.h" -#include "util-mem.h" -#include "util-time.h" -#include "util-path.h" +#include "util/mem.h" +#include "util/time.h" +#include "util/path.h" #include "source-pcap-file.h" static void GetTime(struct timespec *tm); @@ -37,19 +37,17 @@ static int CompareTimes(struct timespec *left, struct timespec *right); static TmEcode PcapRunStatus(PcapFileDirectoryVars *); static TmEcode PcapDirectoryFailure(PcapFileDirectoryVars *ptv); static TmEcode PcapDirectoryDone(PcapFileDirectoryVars *ptv); -static int PcapDirectoryGetModifiedTime(char const * file, struct timespec * out); -static TmEcode PcapDirectoryInsertFile(PcapFileDirectoryVars *pv, - PendingFile *file_to_add); -static TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *ptv, - struct timespec * older_than); -static TmEcode PcapDirectoryDispatchForTimeRange(PcapFileDirectoryVars *pv, - struct timespec *older_than); +static int PcapDirectoryGetModifiedTime(char const *file, struct timespec *out); +static TmEcode PcapDirectoryInsertFile(PcapFileDirectoryVars *pv, PendingFile *file_to_add); +static TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *ptv, struct timespec *older_than); +static TmEcode PcapDirectoryDispatchForTimeRange( + PcapFileDirectoryVars *pv, struct timespec *older_than); void GetTime(struct timespec *tm) { struct timeval now; - if(gettimeofday(&now, NULL) == 0) { - tm->tv_sec = now.tv_sec; + if (gettimeofday(&now, NULL) == 0) { + tm->tv_sec = now.tv_sec; tm->tv_nsec = now.tv_usec * 1000L; } } @@ -84,7 +82,7 @@ TmEcode PcapRunStatus(PcapFileDirectoryVars *ptv) { if (RunModeUnixSocketIsActive()) { TmEcode done = UnixSocketPcapFile(TM_ECODE_OK, &ptv->shared->last_processed); - if ( (suricata_ctl_flags & SURICATA_STOP) || done != TM_ECODE_OK) { + if ((suricata_ctl_flags & SURICATA_STOP) || done != TM_ECODE_OK) { SCReturnInt(TM_ECODE_DONE); } } else { @@ -95,7 +93,8 @@ TmEcode PcapRunStatus(PcapFileDirectoryVars *ptv) SCReturnInt(TM_ECODE_OK); } -void CleanupPendingFile(PendingFile *pending) { +void CleanupPendingFile(PendingFile *pending) +{ if (pending != NULL) { if (pending->filename != NULL) { SCFree(pending->filename); @@ -176,7 +175,7 @@ TmEcode PcapDetermineDirectoryOrFile(char *filename, DIR **directory) temp_dir = opendir(filename); - if (temp_dir == NULL) {//if null, our filename may just be a normal file + if (temp_dir == NULL) { // if null, our filename may just be a normal file switch (errno) { case EACCES: SCLogError("%s: Permission denied", filename); @@ -201,7 +200,7 @@ TmEcode PcapDetermineDirectoryOrFile(char *filename, DIR **directory) SCLogError("%s: Insufficient memory to complete the operation", filename); break; - case ENOTDIR: //no error checking the directory, just is a plain file + case ENOTDIR: // no error checking the directory, just is a plain file SCLogDebug("%s: plain file, not a directory", filename); return_code = TM_ECODE_OK; break; @@ -210,7 +209,7 @@ TmEcode PcapDetermineDirectoryOrFile(char *filename, DIR **directory) SCLogError("%s: %" PRId32, filename, errno); } } else { - //no error, filename references a directory + // no error, filename references a directory *directory = temp_dir; return_code = TM_ECODE_OK; } @@ -242,9 +241,8 @@ int PcapDirectoryGetModifiedTime(char const *file, struct timespec *out) return ret; } -TmEcode PcapDirectoryInsertFile(PcapFileDirectoryVars *pv, - PendingFile *file_to_add -) { +TmEcode PcapDirectoryInsertFile(PcapFileDirectoryVars *pv, PendingFile *file_to_add) +{ PendingFile *file_to_compare = NULL; PendingFile *next_file_to_compare = NULL; @@ -269,15 +267,14 @@ TmEcode PcapDirectoryInsertFile(PcapFileDirectoryVars *pv, TAILQ_INSERT_TAIL(&pv->directory_content, file_to_add, next); } else { file_to_compare = TAILQ_FIRST(&pv->directory_content); - while(file_to_compare != NULL) { + while (file_to_compare != NULL) { if (CompareTimes(&file_to_add->modified_time, &file_to_compare->modified_time) < 0) { TAILQ_INSERT_BEFORE(file_to_compare, file_to_add, next); file_to_compare = NULL; } else { next_file_to_compare = TAILQ_NEXT(file_to_compare, next); if (next_file_to_compare == NULL) { - TAILQ_INSERT_AFTER(&pv->directory_content, file_to_compare, - file_to_add, next); + TAILQ_INSERT_AFTER(&pv->directory_content, file_to_compare, file_to_add, next); } file_to_compare = next_file_to_compare; } @@ -287,9 +284,8 @@ TmEcode PcapDirectoryInsertFile(PcapFileDirectoryVars *pv, SCReturnInt(TM_ECODE_OK); } -TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *pv, - struct timespec *older_than -) { +TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *pv, struct timespec *older_than) +{ if (unlikely(pv == NULL)) { SCLogError("No directory vars passed"); SCReturnInt(TM_ECODE_FAILED); @@ -298,7 +294,7 @@ TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *pv, SCLogError("No directory filename was passed"); SCReturnInt(TM_ECODE_FAILED); } - struct dirent * dir = NULL; + struct dirent *dir = NULL; PendingFile *file_to_add = NULL; while ((dir = readdir(pv->directory)) != NULL) { @@ -307,12 +303,11 @@ TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *pv, continue; } #endif - if (strcmp(dir->d_name, ".") == 0 || - strcmp(dir->d_name, "..") == 0) { + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) { continue; } - char pathbuff[PATH_MAX] = {0}; + char pathbuff[PATH_MAX] = { 0 }; int written = 0; @@ -328,17 +323,15 @@ TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *pv, if (PcapDirectoryGetModifiedTime(pathbuff, &temp_time) == 0) { SCLogDebug("%" PRIuMAX " < %" PRIuMAX "(%s) < %" PRIuMAX ")", - (uintmax_t)SCTimespecAsEpochMillis(&pv->shared->last_processed), - (uintmax_t)SCTimespecAsEpochMillis(&temp_time), - pathbuff, - (uintmax_t)SCTimespecAsEpochMillis(older_than)); + (uintmax_t)SCTimespecAsEpochMillis(&pv->shared->last_processed), + (uintmax_t)SCTimespecAsEpochMillis(&temp_time), pathbuff, + (uintmax_t)SCTimespecAsEpochMillis(older_than)); // Skip files outside of our time range if (CompareTimes(&temp_time, &pv->shared->last_processed) <= 0) { SCLogDebug("Skipping old file %s", pathbuff); continue; - } - else if (CompareTimes(&temp_time, older_than) >= 0) { + } else if (CompareTimes(&temp_time, older_than) >= 0) { SCLogDebug("Skipping new file %s", pathbuff); continue; } @@ -366,7 +359,7 @@ TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *pv, CopyTime(&temp_time, &file_to_add->modified_time); SCLogInfo("Found \"%s\" at %" PRIuMAX, file_to_add->filename, - (uintmax_t)SCTimespecAsEpochMillis(&file_to_add->modified_time)); + (uintmax_t)SCTimespecAsEpochMillis(&file_to_add->modified_time)); if (PcapDirectoryInsertFile(pv, file_to_add) == TM_ECODE_FAILED) { SCLogError("Failed to add file"); @@ -380,9 +373,7 @@ TmEcode PcapDirectoryPopulateBuffer(PcapFileDirectoryVars *pv, SCReturnInt(TM_ECODE_OK); } - -TmEcode PcapDirectoryDispatchForTimeRange(PcapFileDirectoryVars *pv, - struct timespec *older_than) +TmEcode PcapDirectoryDispatchForTimeRange(PcapFileDirectoryVars *pv, struct timespec *older_than) { if (PcapDirectoryPopulateBuffer(pv, older_than) == TM_ECODE_FAILED) { SCLogError("Failed to populate directory buffer"); @@ -446,10 +437,10 @@ TmEcode PcapDirectoryDispatchForTimeRange(PcapFileDirectoryVars *pv, } SCLogInfo("Processed file %s, processed up to %" PRIuMAX, - current_file->filename, - (uintmax_t)SCTimespecAsEpochMillis(¤t_file->modified_time)); + current_file->filename, + (uintmax_t)SCTimespecAsEpochMillis(¤t_file->modified_time)); - if(CompareTimes(¤t_file->modified_time, &last_time_seen) > 0) { + if (CompareTimes(¤t_file->modified_time, &last_time_seen) > 0) { CopyTime(¤t_file->modified_time, &last_time_seen); } @@ -461,9 +452,9 @@ TmEcode PcapDirectoryDispatchForTimeRange(PcapFileDirectoryVars *pv, } } - if(CompareTimes(&last_time_seen, &pv->shared->last_processed) > 0) { + if (CompareTimes(&last_time_seen, &pv->shared->last_processed) > 0) { SCLogInfo("Updating processed to %" PRIuMAX, - (uintmax_t)SCTimespecAsEpochMillis(&last_time_seen)); + (uintmax_t)SCTimespecAsEpochMillis(&last_time_seen)); CopyTime(&last_time_seen, &pv->shared->last_processed); status = PcapRunStatus(pv); } @@ -492,29 +483,29 @@ TmEcode PcapDirectoryDispatch(PcapFileDirectoryVars *ptv) TmEcode status = TM_ECODE_OK; while (status == TM_ECODE_OK) { - //loop while directory is ok - SCLogInfo("Processing pcaps directory %s, files must be newer than %" PRIuMAX " and older than %" PRIuMAX, - ptv->filename, (uintmax_t)SCTimespecAsEpochMillis(&ptv->shared->last_processed), - (uintmax_t)SCTimespecAsEpochMillis(&older_than)); + // loop while directory is ok + SCLogInfo("Processing pcaps directory %s, files must be newer than %" PRIuMAX + " and older than %" PRIuMAX, + ptv->filename, (uintmax_t)SCTimespecAsEpochMillis(&ptv->shared->last_processed), + (uintmax_t)SCTimespecAsEpochMillis(&older_than)); status = PcapDirectoryDispatchForTimeRange(ptv, &older_than); if (ptv->should_loop && status == TM_ECODE_OK) { sleep(poll_seconds); - //update our status based on suricata control flags or unix command socket + // update our status based on suricata control flags or unix command socket status = PcapRunStatus(ptv); if (status == TM_ECODE_OK) { SCLogDebug("Checking if directory %s still exists", ptv->filename); - //check directory - if (PcapDetermineDirectoryOrFile(ptv->filename, - &directory_check) == TM_ECODE_FAILED) { - SCLogInfo("Directory %s no longer exists, stopping", - ptv->filename); + // check directory + if (PcapDetermineDirectoryOrFile(ptv->filename, &directory_check) == + TM_ECODE_FAILED) { + SCLogInfo("Directory %s no longer exists, stopping", ptv->filename); status = TM_ECODE_DONE; - } else if(directory_check != NULL) { + } else if (directory_check != NULL) { closedir(directory_check); directory_check = NULL; } } - } else if (status == TM_ECODE_OK) { //not looping, mark done + } else if (status == TM_ECODE_OK) { // not looping, mark done SCLogDebug("Not looping, stopping directory mode"); status = TM_ECODE_DONE; } diff --git a/src/source-pcap-file-directory-helper.h b/src/source-pcap-file-directory-helper.h index 6e32c044d83b..a3d0e1b5f2b8 100644 --- a/src/source-pcap-file-directory-helper.h +++ b/src/source-pcap-file-directory-helper.h @@ -28,8 +28,7 @@ #ifndef __SOURCE_PCAP_FILE_DIRECTORY_HELPER_H__ #define __SOURCE_PCAP_FILE_DIRECTORY_HELPER_H__ -typedef struct PendingFile_ -{ +typedef struct PendingFile_ { char *filename; struct timespec modified_time; TAILQ_ENTRY(PendingFile_) next; @@ -37,8 +36,7 @@ typedef struct PendingFile_ /** * Data specific to a directory of pcap files */ -typedef struct PcapFileDirectoryVars_ -{ +typedef struct PcapFileDirectoryVars_ { char *filename; DIR *directory; PcapFileFileVars *current_file; diff --git a/src/source-pcap-file-helper.c b/src/source-pcap-file-helper.c index 936b65fb3d9f..ae30839a51c4 100644 --- a/src/source-pcap-file-helper.c +++ b/src/source-pcap-file-helper.c @@ -25,11 +25,11 @@ #include "source-pcap-file-helper.h" #include "suricata.h" -#include "util-datalink.h" -#include "util-checksum.h" -#include "util-profiling.h" +#include "util/datalink.h" +#include "util/checksum.h" +#include "util/profiling.h" #include "source-pcap-file.h" -#include "util-exception-policy.h" +#include "util/exception-policy.h" extern uint16_t max_pending_packets; extern PcapFileGlobalVars pcap_g; @@ -96,8 +96,8 @@ void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) if (pcap_g.checksum_mode == CHECKSUM_VALIDATION_DISABLE) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (pcap_g.checksum_mode == CHECKSUM_VALIDATION_AUTO) { - if (ChecksumAutoModeCheck(ptv->shared->pkts, p->pcap_cnt, - SC_ATOMIC_GET(pcap_g.invalid_checksums))) { + if (ChecksumAutoModeCheck( + ptv->shared->pkts, p->pcap_cnt, SC_ATOMIC_GET(pcap_g.invalid_checksums))) { pcap_g.checksum_mode = CHECKSUM_VALIDATION_DISABLE; p->flags |= PKT_IGNORE_CHECKSUM; } @@ -130,8 +130,7 @@ TmEcode PcapFileDispatch(PcapFileFileVars *ptv) /* initialize all the thread's initial timestamp */ if (likely(ptv->first_pkt_hdr != NULL)) { TmThreadsInitThreadsTimestamp(SCTIME_FROM_TIMEVAL(&ptv->first_pkt_ts)); - PcapFileCallbackLoop((char *)ptv, ptv->first_pkt_hdr, - (u_char *)ptv->first_pkt_data); + PcapFileCallbackLoop((char *)ptv, ptv->first_pkt_hdr, (u_char *)ptv->first_pkt_data); ptv->first_pkt_hdr = NULL; ptv->first_pkt_data = NULL; } @@ -150,8 +149,8 @@ TmEcode PcapFileDispatch(PcapFileFileVars *ptv) PacketPoolWait(); /* Right now we just support reading packets one at a time. */ - int r = pcap_dispatch(ptv->pcap_handle, packet_q_len, - (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv); + int r = pcap_dispatch( + ptv->pcap_handle, packet_q_len, (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv); if (unlikely(r == -1)) { SCLogError("error code %" PRId32 " %s for %s", r, pcap_geterr(ptv->pcap_handle), ptv->filename); @@ -160,8 +159,8 @@ TmEcode PcapFileDispatch(PcapFileFileVars *ptv) } loop_result = TM_ECODE_DONE; } else if (unlikely(r == 0)) { - SCLogInfo("pcap file %s end of file reached (pcap err code %" PRId32 ")", - ptv->filename, r); + SCLogInfo("pcap file %s end of file reached (pcap err code %" PRId32 ")", ptv->filename, + r); ptv->shared->files++; loop_result = TM_ECODE_DONE; } else if (ptv->shared->cb_result == TM_ECODE_FAILED) { @@ -197,7 +196,7 @@ TmEcode InitPcapFile(PcapFileFileVars *pfv) { char errbuf[PCAP_ERRBUF_SIZE] = ""; - if(unlikely(pfv->filename == NULL)) { + if (unlikely(pfv->filename == NULL)) { SCLogError("Filename was null"); SCReturnInt(TM_ECODE_FAILED); } diff --git a/src/source-pcap-file-helper.h b/src/source-pcap-file-helper.h index 7db83b1559bf..10e7dd02da6f 100644 --- a/src/source-pcap-file-helper.h +++ b/src/source-pcap-file-helper.h @@ -37,8 +37,7 @@ typedef struct PcapFileGlobalVars_ { /** * Data that is shared amongst File, Directory, and Thread level vars */ -typedef struct PcapFileSharedVars_ -{ +typedef struct PcapFileSharedVars_ { char *bpf_string; uint32_t tenant_id; @@ -65,8 +64,7 @@ typedef struct PcapFileSharedVars_ /** * Data specific to a single pcap file */ -typedef struct PcapFileFileVars_ -{ +typedef struct PcapFileFileVars_ { char *filename; pcap_t *pcap_handle; diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index c4f97bc0c4c1..5228f9d52a34 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -28,7 +28,7 @@ #include "source-pcap-file-helper.h" #include "source-pcap-file-directory-helper.h" #include "flow-manager.h" -#include "util-checksum.h" +#include "util/checksum.h" #include "runmode-unix-socket.h" #include "suricata.h" @@ -38,8 +38,7 @@ PcapFileGlobalVars pcap_g; /** * Union determining whether the behavior of the thread is file or directory */ -typedef union PcapFileBehaviorVar_ -{ +typedef union PcapFileBehaviorVar_ { PcapFileDirectoryVars *directory; PcapFileFileVars *file; } PcapFileBehaviorVar; @@ -47,8 +46,7 @@ typedef union PcapFileBehaviorVar_ /** * Data specific to the thread */ -typedef struct PcapFileThreadVars_ -{ +typedef struct PcapFileThreadVars_ { PcapFileBehaviorVar behavior; bool is_directory; @@ -64,8 +62,7 @@ static TmEcode DecodePcapFile(ThreadVars *, Packet *, void *); static TmEcode DecodePcapFileThreadInit(ThreadVars *, const void *, void **); static TmEcode DecodePcapFileThreadDeinit(ThreadVars *tv, void *data); -static void CleanupPcapDirectoryFromThreadVars(PcapFileThreadVars *tv, - PcapFileDirectoryVars *ptv); +static void CleanupPcapDirectoryFromThreadVars(PcapFileThreadVars *tv, PcapFileDirectoryVars *ptv); static void CleanupPcapFileFromThreadVars(PcapFileThreadVars *tv, PcapFileFileVars *pfv); static void CleanupPcapFileThreadVars(PcapFileThreadVars *tv); static TmEcode PcapFileExit(TmEcode status, struct timespec *last_processed); @@ -111,7 +108,7 @@ void CleanupPcapFileThreadVars(PcapFileThreadVars *ptv) /** * Pcap File Functionality */ -void TmModuleReceivePcapFileRegister (void) +void TmModuleReceivePcapFileRegister(void) { tmm_modules[TMM_RECEIVEPCAPFILE].name = "ReceivePcapFile"; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit = ReceivePcapFileThreadInit; @@ -124,7 +121,7 @@ void TmModuleReceivePcapFileRegister (void) tmm_modules[TMM_RECEIVEPCAPFILE].flags = TM_FLAG_RECEIVE_TM; } -void TmModuleDecodePcapFileRegister (void) +void TmModuleDecodePcapFileRegister(void) { tmm_modules[TMM_DECODEPCAPFILE].name = "DecodePcapFile"; tmm_modules[TMM_DECODEPCAPFILE].ThreadInit = DecodePcapFileThreadInit; @@ -143,7 +140,7 @@ void PcapFileGlobalInit(void) TmEcode PcapFileExit(TmEcode status, struct timespec *last_processed) { - if(RunModeUnixSocketIsActive()) { + if (RunModeUnixSocketIsActive()) { status = UnixSocketPcapFile(status, last_processed); SCReturnInt(status); } else { @@ -156,7 +153,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); - if(unlikely(data == NULL)) { + if (unlikely(data == NULL)) { SCLogError("pcap file reader thread failed to initialize"); PcapFileExit(TM_ECODE_FAILED, NULL); @@ -165,7 +162,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) } TmEcode status = TM_ECODE_OK; - PcapFileThreadVars *ptv = (PcapFileThreadVars *) data; + PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; TmSlot *s = (TmSlot *)slot; ptv->shared.slot = s->slot_next; @@ -175,7 +172,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) // packets) TmThreadsSetFlag(tv, THV_RUNNING); - if(ptv->is_directory == 0) { + if (ptv->is_directory == 0) { SCLogInfo("Starting file run for %s", ptv->behavior.file->filename); status = PcapFileDispatch(ptv->behavior.file); CleanupPcapFileFromThreadVars(ptv, ptv->behavior.file); @@ -241,13 +238,13 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **d } DIR *directory = NULL; - SCLogDebug("checking file or directory %s", (char*)initdata); - if(PcapDetermineDirectoryOrFile((char *)initdata, &directory) == TM_ECODE_FAILED) { + SCLogDebug("checking file or directory %s", (char *)initdata); + if (PcapDetermineDirectoryOrFile((char *)initdata, &directory) == TM_ECODE_FAILED) { CleanupPcapFileThreadVars(ptv); SCReturnInt(TM_ECODE_OK); } - if(directory == NULL) { + if (directory == NULL) { SCLogDebug("argument %s was a file", (char *)initdata); PcapFileFileVars *pv = SCCalloc(1, sizeof(PcapFileFileVars)); if (unlikely(pv == NULL)) { @@ -266,7 +263,7 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **d pv->shared = &ptv->shared; status = InitPcapFile(pv); - if(status == TM_ECODE_OK) { + if (status == TM_ECODE_OK) { ptv->is_directory = 0; ptv->behavior.file = pv; } else { @@ -285,7 +282,7 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **d SCReturnInt(TM_ECODE_OK); } - pv->filename = SCStrdup((char*)initdata); + pv->filename = SCStrdup((char *)initdata); if (unlikely(pv->filename == NULL)) { SCLogError("Failed to allocate filename"); closedir(directory); @@ -351,7 +348,7 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **d } else { if (strcmp(tmpstring, "auto") == 0) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (ConfValIsTrue(tmpstring)){ + } else if (ConfValIsTrue(tmpstring)) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (ConfValIsFalse(tmpstring)) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_DISABLE; @@ -368,12 +365,11 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, const void *initdata, void **d void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data) { SCEnter(); - if(data != NULL) { + if (data != NULL) { PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; if (pcap_g.conf_checksum_mode == CHECKSUM_VALIDATION_AUTO && - pcap_g.cnt < CHECKSUM_SAMPLE_COUNT && - SC_ATOMIC_GET(pcap_g.invalid_checksums)) { + pcap_g.cnt < CHECKSUM_SAMPLE_COUNT && SC_ATOMIC_GET(pcap_g.invalid_checksums)) { uint64_t chrate = pcap_g.cnt / SC_ATOMIC_GET(pcap_g.invalid_checksums); if (chrate < CHECKSUM_INVALID_RATIO) SCLogWarning("1/%" PRIu64 "th of packets have an invalid checksum," @@ -381,8 +377,7 @@ void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data) " or use '-k none' option on command line.", chrate); else - SCLogInfo("1/%" PRIu64 "th of packets have an invalid checksum", - chrate); + SCLogInfo("1/%" PRIu64 "th of packets have an invalid checksum", chrate); } SCLogNotice("read %" PRIu64 " file%s, %" PRIu64 " packets, %" PRIu64 " bytes", ptv->shared.files, ptv->shared.files == 1 ? "" : "s", ptv->shared.pkts, @@ -393,8 +388,8 @@ void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data) TmEcode ReceivePcapFileThreadDeinit(ThreadVars *tv, void *data) { SCEnter(); - if(data != NULL) { - PcapFileThreadVars *ptv = (PcapFileThreadVars *) data; + if (data != NULL) { + PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; CleanupPcapFileThreadVars(ptv); } SCReturnInt(TM_ECODE_OK); @@ -411,7 +406,7 @@ static TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data) DecodeUpdatePacketCounters(tv, dtv, p); DecoderFunc decoder; - if(ValidateLinkType(p->datalink, &decoder) == TM_ECODE_OK) { + if (ValidateLinkType(p->datalink, &decoder) == TM_ECODE_OK) { /* call the decoder */ decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p)); @@ -453,7 +448,7 @@ TmEcode DecodePcapFileThreadDeinit(ThreadVars *tv, void *data) void PcapIncreaseInvalidChecksum(void) { - (void) SC_ATOMIC_ADD(pcap_g.invalid_checksums, 1); + (void)SC_ATOMIC_ADD(pcap_g.invalid_checksums, 1); } /* eof */ diff --git a/src/source-pcap-file.h b/src/source-pcap-file.h index 30a3c2ec69c0..9e4ecb34f4ab 100644 --- a/src/source-pcap-file.h +++ b/src/source-pcap-file.h @@ -24,12 +24,11 @@ #ifndef __SOURCE_PCAP_FILE_H__ #define __SOURCE_PCAP_FILE_H__ -void TmModuleReceivePcapFileRegister (void); -void TmModuleDecodePcapFileRegister (void); +void TmModuleReceivePcapFileRegister(void); +void TmModuleDecodePcapFileRegister(void); void PcapIncreaseInvalidChecksum(void); void PcapFileGlobalInit(void); #endif /* __SOURCE_PCAP_FILE_H__ */ - diff --git a/src/source-pcap.c b/src/source-pcap.c index f916d69354c7..391d12b78411 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -33,20 +33,20 @@ #include "tm-threads.h" #include "source-pcap.h" #include "conf.h" -#include "util-bpf.h" -#include "util-debug.h" -#include "util-error.h" -#include "util-privs.h" -#include "util-datalink.h" -#include "util-device.h" -#include "util-optimize.h" -#include "util-checksum.h" -#include "util-ioctl.h" -#include "util-time.h" +#include "util/bpf.h" +#include "util/debug.h" +#include "util/error.h" +#include "util/privs.h" +#include "util/datalink.h" +#include "util/device.h" +#include "util/optimize.h" +#include "util/checksum.h" +#include "util/ioctl.h" +#include "util/time.h" #include "tmqh-packetpool.h" #define PCAP_STATE_DOWN 0 -#define PCAP_STATE_UP 1 +#define PCAP_STATE_UP 1 #define PCAP_RECONNECT_TIMEOUT 500000 @@ -69,8 +69,7 @@ typedef struct PcapStats64_ { /** * \brief Structure to hold thread specific variables. */ -typedef struct PcapThreadVars_ -{ +typedef struct PcapThreadVars_ { /* thread specific handle */ pcap_t *pcap_handle; /* handle state */ @@ -132,7 +131,7 @@ static SCMutex pcap_bpf_compile_lock = SCMUTEX_INITIALIZER; /** * \brief Registration Function for ReceivePcap. */ -void TmModuleReceivePcapRegister (void) +void TmModuleReceivePcapRegister(void) { tmm_modules[TMM_RECEIVEPCAP].name = "ReceivePcap"; tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit; @@ -150,7 +149,7 @@ void TmModuleReceivePcapRegister (void) /** * \brief Registration Function for DecodePcap. */ -void TmModuleDecodePcapRegister (void) +void TmModuleDecodePcapRegister(void) { tmm_modules[TMM_DECODEPCAP].name = "DecodePcap"; tmm_modules[TMM_DECODEPCAP].ThreadInit = DecodePcapThreadInit; @@ -184,8 +183,7 @@ static inline void UpdatePcapStatsValue64(uint64_t *last, uint32_t current32) * \brief Update 64 bit |last| stat values with values from |current| * 32 bit pcap_stat. */ -static inline void UpdatePcapStats64( - PcapStats64 *last, const struct pcap_stat *current) +static inline void UpdatePcapStats64(PcapStats64 *last, const struct pcap_stat *current) { UpdatePcapStatsValue64(&last->ps_recv, current->ps_recv); UpdatePcapStatsValue64(&last->ps_drop, current->ps_drop); @@ -198,13 +196,10 @@ static inline void PcapDumpCounters(PcapThreadVars *ptv) if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) { UpdatePcapStats64(&ptv->last_stats64, &pcap_s); - StatsSetUI64(ptv->tv, ptv->capture_kernel_packets, - ptv->last_stats64.ps_recv); - StatsSetUI64( - ptv->tv, ptv->capture_kernel_drops, ptv->last_stats64.ps_drop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_packets, ptv->last_stats64.ps_recv); + StatsSetUI64(ptv->tv, ptv->capture_kernel_drops, ptv->last_stats64.ps_drop); (void)SC_ATOMIC_SET(ptv->livedev->drop, ptv->last_stats64.ps_drop); - StatsSetUI64(ptv->tv, ptv->capture_kernel_ifdrops, - ptv->last_stats64.ps_ifdrop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_ifdrops, ptv->last_stats64.ps_ifdrop); } } @@ -341,7 +336,7 @@ static void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) ptv->pkts++; ptv->bytes += h->caplen; - (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1); + (void)SC_ATOMIC_ADD(ptv->livedev->pkts, 1); p->livedev = ptv->livedev; if (unlikely(PacketCopyData(p, pkt, h->caplen))) { @@ -351,8 +346,7 @@ static void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) switch (ptv->checksum_mode) { case CHECKSUM_VALIDATION_AUTO: - if (ChecksumAutoModeCheck(ptv->pkts, - SC_ATOMIC_GET(ptv->livedev->pkts), + if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE; p->flags |= PKT_IGNORE_CHECKSUM; @@ -411,8 +405,8 @@ static TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot) * us from alloc'ing packets at line rate */ PacketPoolWait(); - int r = pcap_dispatch(ptv->pcap_handle, packet_q_len, - (pcap_handler)PcapCallbackLoop, (u_char *)ptv); + int r = pcap_dispatch( + ptv->pcap_handle, packet_q_len, (pcap_handler)PcapCallbackLoop, (u_char *)ptv); if (unlikely(r == 0 || r == PCAP_ERROR_BREAK || (r > 0 && r < packet_q_len))) { if (r == PCAP_ERROR_BREAK && ptv->cb_result == TM_ECODE_FAILED) { SCReturnInt(TM_ECODE_FAILED); @@ -535,12 +529,9 @@ static TmEcode ReceivePcapThreadInit(ThreadVars *tv, const void *initdata, void pcapconfig->DerefFunc(pcapconfig); - ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", - ptv->tv); - ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", - ptv->tv); - ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops", - ptv->tv); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", ptv->tv); + ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops", ptv->tv); *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); @@ -577,8 +568,7 @@ static void ReceivePcapThreadExitStats(ThreadVars *tv, void *data) UpdatePcapStats64(&ptv->last_stats64, &pcap_s); float drop_percent = likely(ptv->last_stats64.ps_recv > 0) - ? (((float)ptv->last_stats64.ps_drop) / - (float)ptv->last_stats64.ps_recv) * + ? (((float)ptv->last_stats64.ps_drop) / (float)ptv->last_stats64.ps_recv) * 100 : 0; SCLogInfo("%s: pcap total:%" PRIu64 " recv:%" PRIu64 " drop:%" PRIu64 " (%02.1f%%)", @@ -675,25 +665,22 @@ void PcapTranslateIPToDevice(char *pcap_dev, size_t len) return; } - for (pcap_if_t *devsp = alldevsp; devsp ; devsp = devsp->next) { - for (pcap_addr_t *ip = devsp->addresses; ip ; ip = ip->next) { + for (pcap_if_t *devsp = alldevsp; devsp; devsp = devsp->next) { + for (pcap_addr_t *ip = devsp->addresses; ip; ip = ip->next) { if (ai_list->ai_family != ip->addr->sa_family) { continue; } if (ip->addr->sa_family == AF_INET) { - if (memcmp(&((struct sockaddr_in*)ai_list->ai_addr)->sin_addr, - &((struct sockaddr_in*)ip->addr)->sin_addr, - sizeof(struct in_addr))) - { + if (memcmp(&((struct sockaddr_in *)ai_list->ai_addr)->sin_addr, + &((struct sockaddr_in *)ip->addr)->sin_addr, sizeof(struct in_addr))) { continue; } } else if (ip->addr->sa_family == AF_INET6) { - if (memcmp(&((struct sockaddr_in6*)ai_list->ai_addr)->sin6_addr, - &((struct sockaddr_in6*)ip->addr)->sin6_addr, - sizeof(struct in6_addr))) - { + if (memcmp(&((struct sockaddr_in6 *)ai_list->ai_addr)->sin6_addr, + &((struct sockaddr_in6 *)ip->addr)->sin6_addr, + sizeof(struct in6_addr))) { continue; } } else { diff --git a/src/source-pcap.h b/src/source-pcap.h index 5ac36f9bacf5..625bcf31211e 100644 --- a/src/source-pcap.h +++ b/src/source-pcap.h @@ -24,16 +24,15 @@ #ifndef __SOURCE_PCAP_H__ #define __SOURCE_PCAP_H__ -void TmModuleReceivePcapRegister (void); -void TmModuleDecodePcapRegister (void); +void TmModuleReceivePcapRegister(void); +void TmModuleDecodePcapRegister(void); void PcapTranslateIPToDevice(char *pcap_dev, size_t len); -#define LIBPCAP_COPYWAIT 500 -#define LIBPCAP_PROMISC 1 +#define LIBPCAP_COPYWAIT 500 +#define LIBPCAP_PROMISC 1 /* per packet Pcap vars */ -typedef struct PcapPacketVars_ -{ +typedef struct PcapPacketVars_ { uint32_t tenant_id; } PcapPacketVars; @@ -41,8 +40,7 @@ typedef struct PcapPacketVars_ * must be quite long. */ #define PCAP_IFACE_NAME_LENGTH 128 -typedef struct PcapIfaceConfig_ -{ +typedef struct PcapIfaceConfig_ { char iface[PCAP_IFACE_NAME_LENGTH]; /* number of threads */ int threads; diff --git a/src/source-pfring.c b/src/source-pfring.c index 40a42723d6a7..dbf05fb653a4 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -38,14 +38,14 @@ #include "tm-queuehandlers.h" #include "tm-threads.h" #include "source-pfring.h" -#include "util-debug.h" -#include "util-checksum.h" -#include "util-privs.h" -#include "util-datalink.h" -#include "util-device.h" -#include "util-host-info.h" +#include "util/debug.h" +#include "util/checksum.h" +#include "util/privs.h" +#include "util/datalink.h" +#include "util/device.h" +#include "util/host-info.h" #include "runmodes.h" -#include "util-profiling.h" +#include "util/profiling.h" TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot); TmEcode PfringBreakLoop(ThreadVars *tv, void *data); @@ -64,19 +64,19 @@ extern uint16_t max_pending_packets; /*Handle cases where we don't have PF_RING support built-in*/ TmEcode NoPfringSupportExit(ThreadVars *, const void *, void **); -void TmModuleReceivePfringRegister (void) +void TmModuleReceivePfringRegister(void) { tmm_modules[TMM_RECEIVEPFRING].name = "ReceivePfring"; tmm_modules[TMM_RECEIVEPFRING].ThreadInit = NoPfringSupportExit; tmm_modules[TMM_RECEIVEPFRING].Func = NULL; tmm_modules[TMM_RECEIVEPFRING].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVEPFRING].ThreadDeinit = NULL; - tmm_modules[TMM_RECEIVEPFRING].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | - SC_CAP_NET_BIND_SERVICE | SC_CAP_NET_BROADCAST; + tmm_modules[TMM_RECEIVEPFRING].cap_flags = + SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | SC_CAP_NET_BIND_SERVICE | SC_CAP_NET_BROADCAST; tmm_modules[TMM_RECEIVEPFRING].flags = TM_FLAG_RECEIVE_TM; } -void TmModuleDecodePfringRegister (void) +void TmModuleDecodePfringRegister(void) { tmm_modules[TMM_DECODEPFRING].name = "DecodePfring"; tmm_modules[TMM_DECODEPFRING].ThreadInit = NoPfringSupportExit; @@ -109,19 +109,18 @@ TmEcode NoPfringSupportExit(ThreadVars *tv, const void *initdata, void **data) static SCMutex pfring_bpf_set_filter_lock = SCMUTEX_INITIALIZER; /* XXX replace with user configurable options */ -#define LIBPFRING_PROMISC 1 -#define LIBPFRING_REENTRANT 0 +#define LIBPFRING_PROMISC 1 +#define LIBPFRING_REENTRANT 0 #define LIBPFRING_WAIT_FOR_INCOMING 1 /* PfringThreadVars flags */ -#define PFRING_FLAGS_ZERO_COPY (1 << 0) -#define PFRING_FLAGS_BYPASS (1 << 1) +#define PFRING_FLAGS_ZERO_COPY (1 << 0) +#define PFRING_FLAGS_BYPASS (1 << 1) /** * \brief Structure to hold thread specific variables. */ -struct PfringThreadVars_ -{ +struct PfringThreadVars_ { /* thread specific handle */ pfring *pd; @@ -151,7 +150,7 @@ struct PfringThreadVars_ char *bpf_filter; - ChecksumValidationMode checksum_mode; + ChecksumValidationMode checksum_mode; bool vlan_hdr_warned; }; @@ -160,7 +159,7 @@ struct PfringThreadVars_ * \brief Registration Function for ReceivePfring. * \todo Unit tests are needed for this module. */ -void TmModuleReceivePfringRegister (void) +void TmModuleReceivePfringRegister(void) { tmm_modules[TMM_RECEIVEPFRING].name = "ReceivePfring"; tmm_modules[TMM_RECEIVEPFRING].ThreadInit = ReceivePfringThreadInit; @@ -176,7 +175,7 @@ void TmModuleReceivePfringRegister (void) * \brief Registration Function for DecodePfring. * \todo Unit tests are needed for this module. */ -void TmModuleDecodePfringRegister (void) +void TmModuleDecodePfringRegister(void) { tmm_modules[TMM_DECODEPFRING].name = "DecodePfring"; tmm_modules[TMM_DECODEPFRING].ThreadInit = DecodePfringThreadInit; @@ -255,10 +254,8 @@ static inline void PfringProcessPacket(void *user, struct pfring_pkthdr *h, Pack * So if it is not set, use the parsed info from PF_RING's * extended header. */ - if (ptv->vlan_in_ext_header && - h->extended_hdr.parsed_pkt.offset.vlan_offset == 0 && - h->extended_hdr.parsed_pkt.vlan_id) - { + if (ptv->vlan_in_ext_header && h->extended_hdr.parsed_pkt.offset.vlan_offset == 0 && + h->extended_hdr.parsed_pkt.vlan_id) { p->vlan_id[0] = h->extended_hdr.parsed_pkt.vlan_id & 0x0fff; p->vlan_idx = 1; @@ -279,8 +276,7 @@ static inline void PfringProcessPacket(void *user, struct pfring_pkthdr *h, Pack p->flags |= PKT_IGNORE_CHECKSUM; break; case CHECKSUM_VALIDATION_AUTO: - if (ChecksumAutoModeCheck(ptv->pkts, - SC_ATOMIC_GET(ptv->livedev->pkts), + if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE; p->flags |= PKT_IGNORE_CHECKSUM; @@ -367,7 +363,7 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) // packets) TmThreadsSetFlag(tv, THV_RUNNING); - while(1) { + while (1) { if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -394,10 +390,7 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) pkt_buffer = GET_PKT_DIRECT_DATA(p); } - int r = pfring_recv(ptv->pd, &pkt_buffer, - buffer_size, - &hdr, - LIBPFRING_WAIT_FOR_INCOMING); + int r = pfring_recv(ptv->pd, &pkt_buffer, buffer_size, &hdr, LIBPFRING_WAIT_FOR_INCOMING); if (likely(r == 1)) { /* profiling started before blocking pfring_recv call, so * reset it here */ @@ -490,7 +483,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, const void *initdata, void **dat { int rc; u_int32_t version = 0; - PfringIfaceConfig *pfconf = (PfringIfaceConfig *) initdata; + PfringIfaceConfig *pfconf = (PfringIfaceConfig *)initdata; unsigned int opflag; char const *active_runmode = RunmodeGetActive(); @@ -591,11 +584,12 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, const void *initdata, void **dat } if (ptv->threads > 1) { - SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", - tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, - version & 0x000000FF, ptv->interface, ptv->cluster_id); + SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", tv->name, + (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, + ptv->interface, ptv->cluster_id); } else { - SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d, single-pfring-thread", + SCLogPerf( + "(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d, single-pfring-thread", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } @@ -616,26 +610,23 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, const void *initdata, void **dat } } - ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", - ptv->tv); - ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", - ptv->tv); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", ptv->tv); #ifdef HAVE_PF_RING_FLOW_OFFLOAD - ptv->capture_bypassed = StatsRegisterCounter("capture.bypassed", - ptv->tv); + ptv->capture_bypassed = StatsRegisterCounter("capture.bypassed", ptv->tv); #endif /* If kernel is older than 3.0, VLAN is not stripped so we don't * get the info from packet extended header but we will use a standard * parsing */ ptv->vlan_in_ext_header = 1; - if (! SCKernelVersionIsAtLeast(3, 0)) { + if (!SCKernelVersionIsAtLeast(3, 0)) { ptv->vlan_in_ext_header = 0; } /* If VLAN tags are not in the extended header, set cluster type to 5-tuple * or in case of a ZC interface, do nothing */ - if ((! ptv->vlan_in_ext_header) && ptv->ctype == CLUSTER_FLOW && + if ((!ptv->vlan_in_ext_header) && ptv->ctype == CLUSTER_FLOW && strncmp(ptv->interface, "zc", 2) != 0) { SCLogPerf("VLAN not in extended header, setting cluster type to CLUSTER_FLOW_5_TUPLE"); rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, CLUSTER_FLOW_5_TUPLE); @@ -667,15 +658,13 @@ void ReceivePfringThreadExitStats(ThreadVars *tv, void *data) PfringThreadVars *ptv = (PfringThreadVars *)data; PfringDumpCounters(ptv); - SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", - tv->name, + SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); SCLogPerf("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); #ifdef HAVE_PF_RING_FLOW_OFFLOAD if (ptv->flags & PFRING_FLAGS_BYPASS) { - SCLogPerf("(%s) Bypass: Packets %" PRIu64 "", - tv->name, + SCLogPerf("(%s) Bypass: Packets %" PRIu64 "", tv->name, StatsGetLocalCounterValue(tv, ptv->capture_bypassed)); } #endif diff --git a/src/source-pfring.h b/src/source-pfring.h index 6b170ee78d52..b2eb17133028 100644 --- a/src/source-pfring.h +++ b/src/source-pfring.h @@ -32,8 +32,7 @@ typedef struct PfringThreadVars_ PfringThreadVars; #define PFRING_CONF_FLAGS_CLUSTER (1 << 0) #define PFRING_CONF_FLAGS_BYPASS (1 << 1) -typedef struct PfringIfaceConfig_ -{ +typedef struct PfringIfaceConfig_ { uint32_t flags; /* cluster param */ @@ -56,15 +55,13 @@ typedef struct PfringIfaceConfig_ * * This structure is used to pass packet metadata in callbacks. */ -typedef struct PfringPacketVars_ -{ +typedef struct PfringPacketVars_ { PfringThreadVars *ptv; uint32_t flow_id; } PfringPacketVars; - -void TmModuleReceivePfringRegister (void); -void TmModuleDecodePfringRegister (void); +void TmModuleReceivePfringRegister(void); +void TmModuleDecodePfringRegister(void); int PfringConfGetThreads(void); void PfringLoadConfig(void); @@ -74,9 +71,9 @@ void PfringLoadConfig(void); * these values must match with cluster_type in the kernel * include file pf_ring.h */ -#define CLUSTER_FLOW 0 -#define CLUSTER_ROUND_ROBIN 1 -#define CLUSTER_FLOW_5_TUPLE 4 +#define CLUSTER_FLOW 0 +#define CLUSTER_ROUND_ROBIN 1 +#define CLUSTER_FLOW_5_TUPLE 4 #define CLUSTER_INNER_FLOW 6 #define CLUSTER_INNER_FLOW_2_TUPLE 7 #define CLUSTER_INNER_FLOW_4_TUPLE 8 diff --git a/src/source-windivert.c b/src/source-windivert.c index 347d2e7a0f2d..ff1b5dc3d31f 100644 --- a/src/source-windivert.c +++ b/src/source-windivert.c @@ -29,13 +29,13 @@ #include "suricata.h" #include "tm-threads.h" #include "packet.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-error.h" -#include "util-ioctl.h" -#include "util-privs.h" -#include "util-unittest.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/error.h" +#include "util/ioctl.h" +#include "util/privs.h" +#include "util/unittest.h" #include "runmodes.h" @@ -78,8 +78,7 @@ void TmModuleDecodeWinDivertRegister(void) tmm_modules[TMM_DECODEWINDIVERT].flags = TM_FLAG_DECODE_TM; } -TmEcode NoWinDivertSupportExit(ThreadVars *tv, const void *initdata, - void **data) +TmEcode NoWinDivertSupportExit(ThreadVars *tv, const void *initdata, void **data) { SCLogError("Error creating thread %s: you do not have support for WinDivert " "enabled; please recompile with --enable-windivert", @@ -89,7 +88,7 @@ TmEcode NoWinDivertSupportExit(ThreadVars *tv, const void *initdata, #else /* implied we do have WinDivert support */ #include "action-globals.h" -#include "win32-syscall.h" +#include "windows/win32-syscall.h" typedef struct WinDivertThreadVars_ { WinDivertHandle filter_handle; @@ -257,14 +256,12 @@ int WinDivertRegisterQueue(bool forward, char *filter_str) SCEnter(); int ret = 0; - WINDIVERT_LAYER layer = - forward ? WINDIVERT_LAYER_NETWORK_FORWARD : WINDIVERT_LAYER_NETWORK; + WINDIVERT_LAYER layer = forward ? WINDIVERT_LAYER_NETWORK_FORWARD : WINDIVERT_LAYER_NETWORK; /* validate the filter string */ const char *error_str; uint32_t error_pos; - bool valid = WinDivertHelperCheckFilter(filter_str, layer, &error_str, - &error_pos); + bool valid = WinDivertHelperCheckFilter(filter_str, layer, &error_str, &error_pos); if (!valid) { SCLogWarning("Invalid filter \"%s\" supplied to WinDivert: %s at position " "%" PRId32 "", @@ -298,8 +295,7 @@ int WinDivertRegisterQueue(bool forward, char *filter_str) /* copy filter to persistent storage */ size_t filter_len = strlen(filter_str); - size_t copy_len = - strlcpy(wd_qv->filter_str, filter_str, sizeof(wd_qv->filter_str)); + size_t copy_len = strlcpy(wd_qv->filter_str, filter_str, sizeof(wd_qv->filter_str)); if (filter_len > copy_len) { SCLogWarning("Queue length exceeds storage by %" PRId32 " bytes", (int32_t)(filter_len - copy_len)); @@ -308,9 +304,8 @@ int WinDivertRegisterQueue(bool forward, char *filter_str) } wd_qv->layer = layer; - wd_qv->priority = - g_wd_num; /* priority set in the order filters are defined */ - wd_qv->flags = 0; /* normal inline function */ + wd_qv->priority = g_wd_num; /* priority set in the order filters are defined */ + wd_qv->flags = 0; /* normal inline function */ SCMutexInit(&wd_qv->filter_init_mutex, NULL); SCMutexInit(&wd_qv->counters_mutex, NULL); @@ -356,8 +351,7 @@ static TmEcode WinDivertRecvHelper(ThreadVars *tv, WinDivertThreadVars *); static TmEcode WinDivertVerdictHelper(ThreadVars *tv, Packet *p); static TmEcode WinDivertCloseHelper(WinDivertThreadVars *); -static TmEcode WinDivertCollectFilterDevices(WinDivertThreadVars *, - WinDivertQueueVars *); +static TmEcode WinDivertCollectFilterDevices(WinDivertThreadVars *, WinDivertQueueVars *); static bool WinDivertIfaceMatchFilter(const char *filter_string, int if_index); static void WinDivertDisableOffloading(WinDivertThreadVars *); static void WinDivertRestoreOffloading(WinDivertThreadVars *); @@ -440,8 +434,7 @@ static TmEcode WinDivertRecvHelper(ThreadVars *tv, WinDivertThreadVars *wd_tv) /* obtain a packet buffer */ Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { - SCLogDebug( - "PacketGetFromQueueOrAlloc() - failed to obtain Packet buffer"); + SCLogDebug("PacketGetFromQueueOrAlloc() - failed to obtain Packet buffer"); SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); @@ -455,13 +448,11 @@ static TmEcode WinDivertRecvHelper(ThreadVars *tv, WinDivertThreadVars *wd_tv) /* allocate external, if not already */ PacketCallocExtPkt(p, MAX_PAYLOAD_SIZE); - success = - WinDivertRecv(wd_tv->filter_handle, p->ext_pkt, - MAX_PAYLOAD_SIZE, &p->windivert_v.addr, &pktlen); + success = WinDivertRecv( + wd_tv->filter_handle, p->ext_pkt, MAX_PAYLOAD_SIZE, &p->windivert_v.addr, &pktlen); } else { success = WinDivertRecv(wd_tv->filter_handle, GET_PKT_DIRECT_DATA(p), - GET_PKT_DIRECT_MAX_SIZE(p), - &p->windivert_v.addr, &pktlen); + GET_PKT_DIRECT_MAX_SIZE(p), &p->windivert_v.addr, &pktlen); } SET_PKT_LEN(p, pktlen); @@ -476,8 +467,7 @@ static TmEcode WinDivertRecvHelper(ThreadVars *tv, WinDivertThreadVars *wd_tv) */ SET_PKT_LEN(p, 0); - SCLogInfo("WinDivertRecv failed: error %" PRIu32 "", - (uint32_t)(GetLastError())); + SCLogInfo("WinDivertRecv failed: error %" PRIu32 "", (uint32_t)(GetLastError())); SCReturnInt(TM_ECODE_FAILED); } SCLogDebug("Packet received, length %" PRId32 "", GET_PKT_LEN(p)); @@ -512,8 +502,7 @@ static TmEcode WinDivertRecvHelper(ThreadVars *tv, WinDivertThreadVars *wd_tv) * \param initdata pointer to the interface passed from the user * \param data out-pointer to the WinDivert-specific thread vars */ -TmEcode ReceiveWinDivertThreadInit(ThreadVars *tv, const void *initdata, - void **data) +TmEcode ReceiveWinDivertThreadInit(ThreadVars *tv, const void *initdata, void **data) { SCEnter(); TmEcode ret = TM_ECODE_OK; @@ -534,8 +523,7 @@ TmEcode ReceiveWinDivertThreadInit(ThreadVars *tv, const void *initdata, SCMutexLock(&wd_qv->filter_init_mutex); /* does the queue already have an active handle? */ - if (wd_qv->filter_handle != NULL && - wd_qv->filter_handle != INVALID_HANDLE_VALUE) { + if (wd_qv->filter_handle != NULL && wd_qv->filter_handle != INVALID_HANDLE_VALUE) { goto unlock; } @@ -550,8 +538,8 @@ TmEcode ReceiveWinDivertThreadInit(ThreadVars *tv, const void *initdata, /* we open now so that we can immediately start handling packets, * instead of losing however many would occur between registering the * queue and starting a receive thread. */ - wd_qv->filter_handle = WinDivertOpen(wd_qv->filter_str, wd_qv->layer, - wd_qv->priority, wd_qv->flags); + wd_qv->filter_handle = + WinDivertOpen(wd_qv->filter_str, wd_qv->layer, wd_qv->priority, wd_qv->flags); if (wd_qv->filter_handle == INVALID_HANDLE_VALUE) { WinDivertLogError(GetLastError()); ret = TM_ECODE_FAILED; @@ -577,8 +565,7 @@ TmEcode ReceiveWinDivertThreadInit(ThreadVars *tv, const void *initdata, * \param wd_tv pointer to WinDivert thread vars * \param wd_qv pointer to WinDivert queue vars */ -static TmEcode WinDivertCollectFilterDevices(WinDivertThreadVars *wd_tv, - WinDivertQueueVars *wd_qv) +static TmEcode WinDivertCollectFilterDevices(WinDivertThreadVars *wd_tv, WinDivertQueueVars *wd_qv) { SCEnter(); TmEcode ret = TM_ECODE_OK; @@ -590,12 +577,11 @@ static TmEcode WinDivertCollectFilterDevices(WinDivertThreadVars *wd_tv, goto release; } - for (IP_ADAPTER_ADDRESSES *if_info = if_info_list; if_info != NULL; - if_info = if_info->Next) { + for (IP_ADAPTER_ADDRESSES *if_info = if_info_list; if_info != NULL; if_info = if_info->Next) { if (WinDivertIfaceMatchFilter(wd_qv->filter_str, if_info->IfIndex)) { - SCLogConfig("Found adapter %s matching WinDivert filter %s", - if_info->AdapterName, wd_qv->filter_str); + SCLogConfig("Found adapter %s matching WinDivert filter %s", if_info->AdapterName, + wd_qv->filter_str); LiveDevice *new_ldev = SCCalloc(1, sizeof(LiveDevice)); if (new_ldev == NULL) { @@ -609,8 +595,8 @@ static TmEcode WinDivertCollectFilterDevices(WinDivertThreadVars *wd_tv, } TAILQ_INSERT_TAIL(&wd_tv->live_devices, new_ldev, next); } else { - SCLogDebug("Adapter %s does not match WinDivert filter %s", - if_info->AdapterName, wd_qv->filter_str); + SCLogDebug("Adapter %s does not match WinDivert filter %s", if_info->AdapterName, + wd_qv->filter_str); } } @@ -630,10 +616,10 @@ static bool WinDivertIfaceMatchFilter(const char *filter_string, int if_index) WINDIVERT_ADDRESS if_addr = {}; if_addr.IfIdx = if_index; - uint8_t dummy[4] = {4, 4, 4, 4}; + uint8_t dummy[4] = { 4, 4, 4, 4 }; - match = WinDivertHelperEvalFilter(filter_string, WINDIVERT_LAYER_NETWORK, - dummy, sizeof(dummy), &if_addr); + match = WinDivertHelperEvalFilter( + filter_string, WINDIVERT_LAYER_NETWORK, dummy, sizeof(dummy), &if_addr); if (!match) { int err = GetLastError(); if (err != 0) { @@ -652,7 +638,7 @@ static bool WinDivertIfaceMatchFilter(const char *filter_string, int if_index) static void WinDivertDisableOffloading(WinDivertThreadVars *wd_tv) { for (LiveDevice *ldev = TAILQ_FIRST(&wd_tv->live_devices); ldev != NULL; - ldev = TAILQ_NEXT(ldev, next)) { + ldev = TAILQ_NEXT(ldev, next)) { if (LiveGetOffload() == 0) { if (GetIfaceOffloading(ldev->dev, 1, 1) == 1) { @@ -674,7 +660,7 @@ static void WinDivertDisableOffloading(WinDivertThreadVars *wd_tv) static void WinDivertRestoreOffloading(WinDivertThreadVars *wd_tv) { for (LiveDevice *ldev = TAILQ_FIRST(&wd_tv->live_devices); ldev != NULL; - ldev = TAILQ_NEXT(ldev, next)) { + ldev = TAILQ_NEXT(ldev, next)) { RestoreIfaceOffloading(ldev); } @@ -715,11 +701,10 @@ void ReceiveWinDivertThreadExitStats(ThreadVars *tv, void *data) SCMutexLock(&wd_qv->counters_mutex); - SCLogInfo("(%s) Packets %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "", - tv->name, wd_qv->pkts, wd_qv->bytes, wd_qv->errs); - SCLogInfo("(%s) Verdict: Accepted %" PRIu32 ", Dropped %" PRIu32 - ", Replaced %" PRIu32 "", - tv->name, wd_qv->accepted, wd_qv->dropped, wd_qv->replaced); + SCLogInfo("(%s) Packets %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "", tv->name, + wd_qv->pkts, wd_qv->bytes, wd_qv->errs); + SCLogInfo("(%s) Verdict: Accepted %" PRIu32 ", Dropped %" PRIu32 ", Replaced %" PRIu32 "", + tv->name, wd_qv->accepted, wd_qv->dropped, wd_qv->replaced); SCMutexUnlock(&wd_qv->counters_mutex); SCReturn; @@ -762,8 +747,7 @@ static TmEcode WinDivertVerdictHelper(ThreadVars *tv, Packet *p) } /* the handle has been closed and we can no longer use it */ - if (wd_tv->filter_handle == INVALID_HANDLE_VALUE || - wd_tv->filter_handle == NULL) { + if (wd_tv->filter_handle == INVALID_HANDLE_VALUE || wd_tv->filter_handle == NULL) { SCReturnInt(TM_ECODE_OK); } @@ -793,8 +777,8 @@ static TmEcode WinDivertVerdictHelper(ThreadVars *tv, Packet *p) SCReturnInt(TM_ECODE_OK); } - bool success = WinDivertSend(wd_tv->filter_handle, GET_PKT_DATA(p), - GET_PKT_LEN(p), &p->windivert_v.addr, NULL); + bool success = WinDivertSend( + wd_tv->filter_handle, GET_PKT_DATA(p), GET_PKT_LEN(p), &p->windivert_v.addr, NULL); if (unlikely(!success)) { WinDivertLogError(GetLastError()); @@ -814,8 +798,7 @@ static TmEcode WinDivertVerdictHelper(ThreadVars *tv, Packet *p) * \brief init the verdict thread, which is piggybacked off the receive * thread */ -TmEcode VerdictWinDivertThreadInit(ThreadVars *tv, const void *initdata, - void **data) +TmEcode VerdictWinDivertThreadInit(ThreadVars *tv, const void *initdata, void **data) { SCEnter(); @@ -865,8 +848,7 @@ TmEcode DecodeWinDivert(ThreadVars *tv, Packet *p, void *data) SCLogDebug("IPv6 packet"); DecodeIPV6(tv, d_tv, p, GET_PKT_DATA(p), GET_PKT_LEN(p)); } else { - SCLogDebug("packet unsupported by WinDivert, first byte: %02x", - *GET_PKT_DATA(p)); + SCLogDebug("packet unsupported by WinDivert, first byte: %02x", *GET_PKT_DATA(p)); } PacketDecodeFinalize(tv, d_tv, p); @@ -874,8 +856,7 @@ TmEcode DecodeWinDivert(ThreadVars *tv, Packet *p, void *data) SCReturnInt(TM_ECODE_OK); } -TmEcode DecodeWinDivertThreadInit(ThreadVars *tv, const void *initdata, - void **data) +TmEcode DecodeWinDivertThreadInit(ThreadVars *tv, const void *initdata, void **data) { SCEnter(); @@ -912,16 +893,14 @@ static TmEcode WinDivertCloseHelper(WinDivertThreadVars *wd_tv) WinDivertQueueVars *wd_qv = WinDivertGetQueue(wd_tv->thread_num); if (wd_qv == NULL) { - SCLogDebug("No queue could be found for thread num %" PRId32 "", - wd_tv->thread_num); + SCLogDebug("No queue could be found for thread num %" PRId32 "", wd_tv->thread_num); SCReturnInt(TM_ECODE_FAILED); } SCMutexLock(&wd_qv->filter_init_mutex); /* check if there's nothing to close */ - if (wd_qv->filter_handle == INVALID_HANDLE_VALUE || - wd_qv->filter_handle == NULL) { + if (wd_qv->filter_handle == INVALID_HANDLE_VALUE || wd_qv->filter_handle == NULL) { goto unlock; } @@ -955,21 +934,13 @@ static int SourceWinDivertTestIfaceMatchFilter(void) bool expected; }; - struct testdata tests[] = { - {"true", 11, true}, - {"ifIdx=11", 11, true}, - {"ifIdx==11", 11, true}, - {"ifIdx!=11", 1, true}, - {"ifIdx!=11", 11, false}, - {"ifIdx=3", 4, false}, - {"ifIdx=11 || ifIdx=5", 5, true}, - {"ifIdx=11 || ifIdx=4", 5, false}, - {"ifIdx<3 || ifIdx>7", 8, true}, - {"ifIdx<3 || ifIdx>7", 5, false}, - {"ifIdx>3 or ifIdx<7", 5, true}, - {"ifIdx>3 && ifIdx<7", 5, true}, - {"ifIdx>3 && ifIdx<7", 1, false}, - {"(ifIdx > 3 && ifIdx < 7) or ifIdx == 11", 11, true}}; + struct testdata tests[] = { { "true", 11, true }, { "ifIdx=11", 11, true }, + { "ifIdx==11", 11, true }, { "ifIdx!=11", 1, true }, { "ifIdx!=11", 11, false }, + { "ifIdx=3", 4, false }, { "ifIdx=11 || ifIdx=5", 5, true }, + { "ifIdx=11 || ifIdx=4", 5, false }, { "ifIdx<3 || ifIdx>7", 8, true }, + { "ifIdx<3 || ifIdx>7", 5, false }, { "ifIdx>3 or ifIdx<7", 5, true }, + { "ifIdx>3 && ifIdx<7", 5, true }, { "ifIdx>3 && ifIdx<7", 1, false }, + { "(ifIdx > 3 && ifIdx < 7) or ifIdx == 11", 11, true } }; size_t count = (sizeof(tests) / sizeof(tests[0])); @@ -978,8 +949,8 @@ static int SourceWinDivertTestIfaceMatchFilter(void) bool actual = WinDivertIfaceMatchFilter(test.filter, test.if_index); if (actual != test.expected) { - printf("WinDivertIfaceMatchFilter(\"%s\", %d) == %d, expected %d\n", - test.filter, test.if_index, actual, test.expected); + printf("WinDivertIfaceMatchFilter(\"%s\", %d) == %d, expected %d\n", test.filter, + test.if_index, actual, test.expected); FAIL; } } @@ -993,8 +964,7 @@ static int SourceWinDivertTestIfaceMatchFilter(void) void SourceWinDivertRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SourceWinDivertTestIfaceMatchFilter", - SourceWinDivertTestIfaceMatchFilter); + UtRegisterTest("SourceWinDivertTestIfaceMatchFilter", SourceWinDivertTestIfaceMatchFilter); #endif } diff --git a/src/source-windivert.h b/src/source-windivert.h index 71574993ec91..f3f4b31d30eb 100644 --- a/src/source-windivert.h +++ b/src/source-windivert.h @@ -40,8 +40,7 @@ typedef void *WinDivertHandle; * * see https://reqrypt.org/windivert-doc.html#divert_open for more info */ -typedef struct WinDivertQueueVars_ -{ +typedef struct WinDivertQueueVars_ { int queue_num; /* see https://reqrypt.org/windivert-doc.html#filter_language */ @@ -64,8 +63,7 @@ typedef struct WinDivertQueueVars_ SCMutex counters_mutex; } WinDivertQueueVars; -typedef struct WinDivertPacketVars_ -{ +typedef struct WinDivertPacketVars_ { int thread_num; WINDIVERT_ADDRESS addr; diff --git a/src/stream-tcp-cache.c b/src/stream-tcp-cache.c index f6a7c12b33b0..aa5855a124d9 100644 --- a/src/stream-tcp-cache.c +++ b/src/stream-tcp-cache.c @@ -25,7 +25,7 @@ #include "suricata.h" #include "stream-tcp-private.h" #include "stream-tcp-cache.h" -#include "util-debug.h" +#include "util/debug.h" typedef struct TcpPoolCache { bool cache_enabled; /**< cache should only be enabled for worker threads */ diff --git a/src/stream-tcp-inline.c b/src/stream-tcp-inline.c index 80783ef035a6..1c390a10c8b6 100644 --- a/src/stream-tcp-inline.c +++ b/src/stream-tcp-inline.c @@ -28,12 +28,12 @@ #include "stream-tcp-private.h" #include "stream-tcp-inline.h" -#include "util-memcmp.h" -#include "util-print.h" +#include "util/memcmp.h" +#include "util/print.h" -#include "util-validate.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/validate.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" /** * \brief Compare the shared data portion of two segments @@ -46,8 +46,7 @@ * \retval 0 shared data is the same (or no data is shared) * \retval 1 shared data is different */ -int StreamTcpInlineSegmentCompare(const TcpStream *stream, - const Packet *p, const TcpSegment *seg) +int StreamTcpInlineSegmentCompare(const TcpStream *stream, const Packet *p, const TcpSegment *seg) { SCEnter(); @@ -73,8 +72,7 @@ int StreamTcpInlineSegmentCompare(const TcpStream *stream, } else if (SEQ_GT(seg->seq, (pkt_seq + p->payload_len))) { SCReturnInt(0); } else { - SCLogDebug("p %u (%u), seg2 %u (%u)", pkt_seq, - p->payload_len, seg->seq, seg_datalen); + SCLogDebug("p %u (%u), seg2 %u (%u)", pkt_seq, p->payload_len, seg->seq, seg_datalen); uint32_t seg_seq = seg->seq; if (SEQ_LT(seg_seq, stream->base_seq)) { @@ -117,8 +115,7 @@ int StreamTcpInlineSegmentCompare(const TcpStream *stream, * \todo What about reassembled fragments? * \todo What about unwrapped tunnel packets? */ -void StreamTcpInlineSegmentReplacePacket(const TcpStream *stream, - Packet *p, const TcpSegment *seg) +void StreamTcpInlineSegmentReplacePacket(const TcpStream *stream, Packet *p, const TcpSegment *seg) { SCEnter(); @@ -157,7 +154,7 @@ void StreamTcpInlineSegmentReplacePacket(const TcpStream *stream, if (range) { /* update the packets payload. As payload is a ptr to either * p->pkt or p->ext_pkt that is updated as well */ - memcpy(p->payload+poff, seg_data+toff, range); + memcpy(p->payload + poff, seg_data + toff, range); /* flag as modified so we can reinject / replace after * recalculating the checksum */ diff --git a/src/stream-tcp-inline.h b/src/stream-tcp-inline.h index 515c6fd6503b..bb528ef33b73 100644 --- a/src/stream-tcp-inline.h +++ b/src/stream-tcp-inline.h @@ -26,12 +26,9 @@ #include "stream-tcp-private.h" -int StreamTcpInlineSegmentCompare(const TcpStream *, - const Packet *, const TcpSegment *); -void StreamTcpInlineSegmentReplacePacket(const TcpStream *, - Packet *, const TcpSegment *); +int StreamTcpInlineSegmentCompare(const TcpStream *, const Packet *, const TcpSegment *); +void StreamTcpInlineSegmentReplacePacket(const TcpStream *, Packet *, const TcpSegment *); void StreamTcpInlineRegisterTests(void); #endif /* __STREAM_TCP_INLINE_H__ */ - diff --git a/src/stream-tcp-list.c b/src/stream-tcp-list.c index 2b8a4d079cef..2817ca381385 100644 --- a/src/stream-tcp-list.c +++ b/src/stream-tcp-list.c @@ -28,9 +28,9 @@ #include "stream-tcp-reassemble.h" #include "stream-tcp-inline.h" #include "stream-tcp-list.h" -#include "util-streaming-buffer.h" -#include "util-print.h" -#include "util-validate.h" +#include "util/streaming-buffer.h" +#include "util/print.h" +#include "util/validate.h" #include "app-layer-frames.h" static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg); @@ -73,7 +73,8 @@ int TcpSegmentCompare(struct TcpSegment *a, struct TcpSegment *b) * \return SC_OK on success * \return SC_ENOMEM on error (memory allocation error) */ -static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, uint8_t *data, uint16_t data_len) +static inline int InsertSegmentDataCustom( + TcpStream *stream, TcpSegment *seg, uint8_t *data, uint16_t data_len) { uint64_t stream_offset; uint32_t data_offset; @@ -87,10 +88,9 @@ static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, ui stream_offset = STREAM_BASE_OFFSET(stream); } - SCLogDebug("stream %p buffer %p, stream_offset %"PRIu64", " - "data_offset %"PRIu16", SEQ %u BASE %u, data_len %u", - stream, &stream->sb, stream_offset, - data_offset, seg->seq, stream->base_seq, data_len); + SCLogDebug("stream %p buffer %p, stream_offset %" PRIu64 ", " + "data_offset %" PRIu16 ", SEQ %u BASE %u, data_len %u", + stream, &stream->sb, stream_offset, data_offset, seg->seq, stream->base_seq, data_len); DEBUG_VALIDATE_BUG_ON(data_offset > data_len); if (data_len <= data_offset) { SCReturnInt(SC_OK); @@ -108,9 +108,9 @@ static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, ui uint64_t mydata_offset; StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &mydata_offset); - SCLogDebug("stream %p seg %p data in buffer %p of len %u and offset %"PRIu64, - stream, seg, &stream->sb, mydata_len, mydata_offset); - //PrintRawDataFp(stdout, mydata, mydata_len); + SCLogDebug("stream %p seg %p data in buffer %p of len %u and offset %" PRIu64, stream, seg, + &stream->sb, mydata_len, mydata_offset); + // PrintRawDataFp(stdout, mydata, mydata_len); } #endif SCReturnInt(SC_OK); @@ -124,8 +124,8 @@ static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, ui static inline bool CheckOverlap(struct TCPSEG *tree, TcpSegment *seg) { const uint32_t re = SEG_SEQ_RIGHT_EDGE(seg); - SCLogDebug("start. SEQ %u payload_len %u. Right edge: %u. Seg %p", - seg->seq, seg->payload_len, re, seg); + SCLogDebug("start. SEQ %u payload_len %u. Right edge: %u. Seg %p", seg->seq, seg->payload_len, + re, seg); /* check forward */ TcpSegment *next = TCPSEG_RB_NEXT(seg); @@ -162,7 +162,7 @@ static inline bool CheckOverlap(struct TCPSEG *tree, TcpSegment *seg) * \retval 0 inserted, no overlap * \retval -EINVAL seg out of seq range */ -static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, TcpSegment **dup_seg, Packet *p) +static int DoInsertSegment(TcpStream *stream, TcpSegment *seg, TcpSegment **dup_seg, Packet *p) { /* in lossy traffic, we can get here with the wrong sequence numbers */ if (SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(seg), stream->base_seq)) { @@ -172,7 +172,8 @@ static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, TcpSegment **dup /* fast track */ if (RB_EMPTY(&stream->seg_tree)) { SCLogDebug("empty tree, inserting seg %p seq %" PRIu32 ", " - "len %" PRIu32 "", seg, seg->seq, TCP_SEG_LEN(seg)); + "len %" PRIu32 "", + seg, seg->seq, TCP_SEG_LEN(seg)); TCPSEG_RB_INSERT(&stream->seg_tree, seg); stream->segs_right_edge = SEG_SEQ_RIGHT_EDGE(seg); return 0; @@ -181,8 +182,7 @@ static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, TcpSegment **dup /* insert and then check if there was any overlap with other segments */ TcpSegment *res = TCPSEG_RB_INSERT(&stream->seg_tree, seg); if (res) { - SCLogDebug("seg has a duplicate in the tree seq %u/%u", - res->seq, res->payload_len); + SCLogDebug("seg has a duplicate in the tree seq %u/%u", res->seq, res->payload_len); /* exact duplicate SEQ + payload_len */ *dup_seg = res; return 2; // duplicate has overlap by definition. @@ -218,13 +218,13 @@ static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, TcpSegment **dup * \retval 1 if data was different * \retval 0 data was the same or we didn't check for differences */ -static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list, - const TcpSegment *seg, uint8_t *buf, Packet *p) +static int DoHandleDataOverlap( + TcpStream *stream, const TcpSegment *list, const TcpSegment *seg, uint8_t *buf, Packet *p) { SCLogDebug("handle overlap for segment %p seq %u len %u re %u, " - "list segment %p seq %u len %u re %u", seg, seg->seq, - p->payload_len, SEG_SEQ_RIGHT_EDGE(seg), - list, list->seq, TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list)); + "list segment %p seq %u len %u re %u", + seg, seg->seq, p->payload_len, SEG_SEQ_RIGHT_EDGE(seg), list, list->seq, + TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list)); int data_is_different = 0; int use_new_data = 0; @@ -243,7 +243,7 @@ static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list, } } - /* IDS mode */ + /* IDS mode */ } else { if (check_overlap_different_data) { if (StreamTcpInlineSegmentCompare(stream, p, list) != 0) { @@ -333,7 +333,7 @@ static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list, } /* new seg starts after list segment */ - } else { //if (SEQ_GT(seg->seq, list->seq)) { + } else { // if (SEQ_GT(seg->seq, list->seq)) { SCLogDebug("seg starts after list segment"); if (SEQ_EQ(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) { @@ -351,14 +351,12 @@ static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list, } } else { SCLogDebug("seg starts after list and ends before list end"); - } } } - SCLogDebug("data_is_different %s, use_new_data %s", - data_is_different ? "yes" : "no", - use_new_data ? "yes" : "no"); + SCLogDebug("data_is_different %s, use_new_data %s", data_is_different ? "yes" : "no", + use_new_data ? "yes" : "no"); /* if the data is different and we don't want to use the new (seg) * data, we have to update buf with the list data */ @@ -396,13 +394,14 @@ static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list, if (SEQ_LT(seg->seq + seg_offset + seg_len, list_seq + list_offset + list_len)) { list_len -= (list_seq + list_offset + list_len) - (seg->seq + seg_offset + seg_len); } - SCLogDebug("here goes nothing: list %u %u, seg %u %u", list_offset, list_len, seg_offset, seg_len); + SCLogDebug("here goes nothing: list %u %u, seg %u %u", list_offset, list_len, seg_offset, + seg_len); - //PrintRawDataFp(stdout, list_data + list_offset, list_len); - //PrintRawDataFp(stdout, buf + seg_offset, seg_len); + // PrintRawDataFp(stdout, list_data + list_offset, list_len); + // PrintRawDataFp(stdout, buf + seg_offset, seg_len); memcpy(buf + seg_offset, list_data + list_offset, list_len); - //PrintRawDataFp(stdout, buf, p->payload_len); + // PrintRawDataFp(stdout, buf, p->payload_len); } return (check_overlap_different_data && data_is_different); } @@ -413,17 +412,16 @@ static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list, * Walk back from the current segment which is already in the tree. * We walk until we can't possibly overlap anymore. */ -static int DoHandleDataCheckBackwards(TcpStream *stream, - TcpSegment *seg, uint8_t *buf, Packet *p) +static int DoHandleDataCheckBackwards(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p) { int retval = 0; - SCLogDebug("check tree backwards: insert data for segment %p seq %u len %u re %u", - seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg)); + SCLogDebug("check tree backwards: insert data for segment %p seq %u len %u re %u", seg, + seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg)); /* check backwards */ TcpSegment *tree_seg = NULL, *s = seg; - RB_FOREACH_REVERSE_FROM(tree_seg, TCPSEG, s) { + RB_FOREACH_REVERSE_FROM (tree_seg, TCPSEG, s) { if (tree_seg == seg) continue; @@ -438,9 +436,8 @@ static int DoHandleDataCheckBackwards(TcpStream *stream, overlap = 1; } - SCLogDebug("(back) tree seg %u len %u re %u overlap? %s", - tree_seg->seq, TCP_SEG_LEN(tree_seg), - SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no"); + SCLogDebug("(back) tree seg %u len %u re %u overlap? %s", tree_seg->seq, + TCP_SEG_LEN(tree_seg), SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no"); if (overlap) { retval |= DoHandleDataOverlap(stream, tree_seg, seg, buf, p); @@ -458,18 +455,17 @@ static int DoHandleDataCheckBackwards(TcpStream *stream, * \retval 1 data was different * \retval 0 data was the same */ -static int DoHandleDataCheckForward(TcpStream *stream, - TcpSegment *seg, uint8_t *buf, Packet *p) +static int DoHandleDataCheckForward(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p) { int retval = 0; uint32_t seg_re = SEG_SEQ_RIGHT_EDGE(seg); - SCLogDebug("check list forward: insert data for segment %p seq %u len %u re %u", - seg, seg->seq, TCP_SEG_LEN(seg), seg_re); + SCLogDebug("check list forward: insert data for segment %p seq %u len %u re %u", seg, seg->seq, + TCP_SEG_LEN(seg), seg_re); TcpSegment *tree_seg = NULL, *s = seg; - RB_FOREACH_FROM(tree_seg, TCPSEG, s) { + RB_FOREACH_FROM (tree_seg, TCPSEG, s) { if (tree_seg == seg) continue; @@ -478,13 +474,13 @@ static int DoHandleDataCheckForward(TcpStream *stream, overlap = 1; else if (SEQ_LEQ(seg_re, tree_seg->seq)) { SCLogDebug("tree segment %u too far ahead, " - "no more overlaps can happen", tree_seg->seq); + "no more overlaps can happen", + tree_seg->seq); break; } - SCLogDebug("(fwd) in-tree seg %u len %u re %u overlap? %s", - tree_seg->seq, TCP_SEG_LEN(tree_seg), - SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no"); + SCLogDebug("(fwd) in-tree seg %u len %u re %u overlap? %s", tree_seg->seq, + TCP_SEG_LEN(tree_seg), SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no"); if (overlap) { retval |= DoHandleDataOverlap(stream, tree_seg, seg, buf, p); @@ -497,14 +493,14 @@ static int DoHandleDataCheckForward(TcpStream *stream, * \param tree_seg in-tree duplicate of `seg` * \retval res 0 ok, -1 insertion error due to memcap */ -static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpStream *stream, TcpSegment *seg, TcpSegment *tree_seg, Packet *p) +static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, + TcpSegment *seg, TcpSegment *tree_seg, Packet *p) { int result = 0; TcpSegment *handle = seg; - SCLogDebug("insert data for segment %p seq %u len %u re %u", - seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg)); + SCLogDebug("insert data for segment %p seq %u len %u re %u", seg, seg->seq, TCP_SEG_LEN(seg), + SEG_SEQ_RIGHT_EDGE(seg)); /* create temporary buffer to contain the data we will insert. Overlap * handling may update it. By using this we don't have to track whether @@ -525,11 +521,11 @@ static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (is_head && !is_tail) { result = DoHandleDataCheckForward(stream, handle, buf, p); - /* new list tail */ + /* new list tail */ } else if (!is_head && is_tail) { result = DoHandleDataCheckBackwards(stream, handle, buf, p); - /* middle of the list */ + /* middle of the list */ } else if (!is_head && !is_tail) { result = DoHandleDataCheckBackwards(stream, handle, buf, p); result |= DoHandleDataCheckForward(stream, handle, buf, p); @@ -635,15 +631,15 @@ static void StreamTcpSegmentAddPacketData( * In case of error, this function returns the segment to the pool */ int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpStream *stream, TcpSegment *seg, Packet *p, - uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen) + TcpStream *stream, TcpSegment *seg, Packet *p, uint32_t pkt_seq, uint8_t *pkt_data, + uint16_t pkt_datalen) { SCEnter(); TcpSegment *dup_seg = NULL; /* insert segment into list. Note: doesn't handle the data */ - int r = DoInsertSegment (stream, seg, &dup_seg, p); + int r = DoInsertSegment(stream, seg, &dup_seg, p); if (IsTcpSessionDumpingEnabled()) { StreamTcpSegmentAddPacketData(seg, p, tv, ra_ctx); @@ -685,18 +681,16 @@ int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ SCReturnInt(-1); } if (r == 2) { - SCLogDebug("duplicate segment %u/%u, discard it", - seg->seq, seg->payload_len); + SCLogDebug("duplicate segment %u/%u, discard it", seg->seq, seg->payload_len); StreamTcpSegmentReturntoPool(seg); #ifdef DEBUG if (SCLogDebugEnabled()) { TcpSegment *s = NULL, *safe = NULL; - RB_FOREACH_SAFE(s, TCPSEG, &stream->seg_tree, safe) - { - SCLogDebug("tree: seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32"%s%s%s", - s, s->seq, TCP_SEG_LEN(s), - (uint32_t)(s->seq + TCP_SEG_LEN(s)), + RB_FOREACH_SAFE (s, TCPSEG, &stream->seg_tree, safe) { + SCLogDebug("tree: seg %p, SEQ %" PRIu32 ", LEN %" PRIu16 ", SUM %" PRIu32 + "%s%s%s", + s, s->seq, TCP_SEG_LEN(s), (uint32_t)(s->seq + TCP_SEG_LEN(s)), s->seq == seg->seq ? " DUPLICATE" : "", TCPSEG_RB_PREV(s) == NULL ? " HEAD" : "", TCPSEG_RB_NEXT(s) == NULL ? " TAIL" : ""); @@ -712,12 +706,10 @@ int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ SCReturnInt(0); } - /* * Pruning & removal */ - static inline bool SegmentInUse(const TcpStream *stream, const TcpSegment *seg) { /* if proto detect isn't done, we're not returning */ @@ -730,7 +722,6 @@ static inline bool SegmentInUse(const TcpStream *stream, const TcpSegment *seg) SCReturnInt(false); } - /** \internal * \brief check if we can remove a segment from our segment list * @@ -780,9 +771,9 @@ static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream) uint64_t raw_progress = STREAM_RAW_PROGRESS(stream); if (StreamTcpInlineMode()) { - uint32_t chunk_size = (stream == &ssn->client) ? - stream_config.reassembly_toserver_chunk_size : - stream_config.reassembly_toclient_chunk_size; + uint32_t chunk_size = (stream == &ssn->client) + ? stream_config.reassembly_toserver_chunk_size + : stream_config.reassembly_toclient_chunk_size; if (raw_progress < (uint64_t)chunk_size) { raw_progress = 0; } else { @@ -798,7 +789,7 @@ static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream) else raw_progress -= stream->min_inspect_depth; - SCLogDebug("stream->min_inspect_depth %u, raw_progress %"PRIu64, + SCLogDebug("stream->min_inspect_depth %u, raw_progress %" PRIu64, stream->min_inspect_depth, raw_progress); } @@ -809,8 +800,7 @@ static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream) app_le, raw_progress); } else { left_edge = raw_progress; - SCLogDebug("left_edge %"PRIu64", using only raw:%"PRIu64, - left_edge, raw_progress); + SCLogDebug("left_edge %" PRIu64 ", using only raw:%" PRIu64, left_edge, raw_progress); } } else if (use_app) { const uint64_t app_le = GetLeftEdgeForApp(f, ssn, stream); @@ -818,7 +808,7 @@ static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream) SCLogDebug("left_edge %" PRIu64 ", using only app:%" PRIu64, left_edge, app_le); } else { left_edge = StreamingBufferGetConsecutiveDataRightEdge(&stream->sb); - SCLogDebug("no app & raw: left_edge %"PRIu64" (full stream)", left_edge); + SCLogDebug("no app & raw: left_edge %" PRIu64 " (full stream)", left_edge); } if (use_log) { @@ -848,7 +838,7 @@ static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream) else left_edge = 0; - SCLogDebug("stream:%p left_edge %"PRIu64, stream, left_edge); + SCLogDebug("stream:%p left_edge %" PRIu64, stream, left_edge); } if (left_edge > 0) { @@ -856,7 +846,8 @@ static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream) * lets adjust it to make sure in-use segments still have * data */ TcpSegment *seg = NULL; - RB_FOREACH(seg, TCPSEG, &stream->seg_tree) { + RB_FOREACH(seg, TCPSEG, &stream->seg_tree) + { if (TCP_SEG_OFFSET(seg) > left_edge) { SCLogDebug("seg beyond left_edge, we're done"); break; @@ -864,7 +855,8 @@ static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream) if (SegmentInUse(stream, seg)) { left_edge = TCP_SEG_OFFSET(seg); - SCLogDebug("in-use seg before left_edge, adjust to %"PRIu64" and bail", left_edge); + SCLogDebug( + "in-use seg before left_edge, adjust to %" PRIu64 " and bail", left_edge); break; } } @@ -913,7 +905,8 @@ void StreamTcpPruneSession(Flow *f, uint8_t flags) if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY; SCLogDebug("ssn %p / stream %p: reassembly depth reached, " - "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn, stream); + "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", + ssn, stream); StreamTcpReturnStreamSegments(stream); StreamingBufferClear(&stream->sb, &stream_config.sbcnf); return; @@ -921,7 +914,8 @@ void StreamTcpPruneSession(Flow *f, uint8_t flags) } else if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) && (stream->flags & STREAMTCP_STREAM_FLAG_DISABLE_RAW)) { SCLogDebug("ssn %p / stream %p: both app and raw are done, " - "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn, stream); + "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", + ssn, stream); stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY; StreamTcpReturnStreamSegments(stream); StreamingBufferClear(&stream->sb, &stream_config.sbcnf); @@ -932,7 +926,7 @@ void StreamTcpPruneSession(Flow *f, uint8_t flags) SCLogDebug("buffer left_edge %" PRIu64, left_edge); if (left_edge && left_edge > STREAM_BASE_OFFSET(stream)) { uint32_t slide = left_edge - STREAM_BASE_OFFSET(stream); - SCLogDebug("buffer sliding %u to offset %"PRIu64, slide, left_edge); + SCLogDebug("buffer sliding %u to offset %" PRIu64, slide, left_edge); if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { AppLayerFramesSlide(f, slide, flags & (STREAM_TOSERVER | STREAM_TOCLIENT)); @@ -956,17 +950,15 @@ void StreamTcpPruneSession(Flow *f, uint8_t flags) stream->log_progress_rel = 0; } - SCLogDebug("stream base_seq %u at stream offset %"PRIu64, - stream->base_seq, STREAM_BASE_OFFSET(stream)); + SCLogDebug("stream base_seq %u at stream offset %" PRIu64, stream->base_seq, + STREAM_BASE_OFFSET(stream)); } /* loop through the segments and remove all not in use */ TcpSegment *seg = NULL, *safe = NULL; - RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe) - { - SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, - seg, seg->seq, TCP_SEG_LEN(seg), - (uint32_t)(seg->seq + TCP_SEG_LEN(seg))); + RB_FOREACH_SAFE (seg, TCPSEG, &stream->seg_tree, safe) { + SCLogDebug("seg %p, SEQ %" PRIu32 ", LEN %" PRIu16 ", SUM %" PRIu32, seg, seg->seq, + TCP_SEG_LEN(seg), (uint32_t)(seg->seq + TCP_SEG_LEN(seg))); if (StreamTcpReturnSegmentCheck(stream, seg) == 0) { SCLogDebug("not removing segment"); @@ -982,7 +974,6 @@ void StreamTcpPruneSession(Flow *f, uint8_t flags) SCReturn; } - /* * unittests */ diff --git a/src/stream-tcp-list.h b/src/stream-tcp-list.h index 5612354a86a1..8caf493c850d 100644 --- a/src/stream-tcp-list.h +++ b/src/stream-tcp-list.h @@ -24,7 +24,6 @@ #ifndef __STREAM_TCP_LIST_H__ #define __STREAM_TCP_LIST_H__ - #ifdef UNITTESTS void StreamTcpListRegisterTests(void); #endif diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 619398deb7c9..5785f0ef1cf1 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -24,12 +24,12 @@ #ifndef __STREAM_TCP_PRIVATE_H__ #define __STREAM_TCP_PRIVATE_H__ -#include "util-pool-thread.h" -#include "util-streaming-buffer.h" +#include "util/pool-thread.h" +#include "util/streaming-buffer.h" -#define STREAMTCP_QUEUE_FLAG_TS 0x01 -#define STREAMTCP_QUEUE_FLAG_WS 0x02 -#define STREAMTCP_QUEUE_FLAG_SACK 0x04 +#define STREAMTCP_QUEUE_FLAG_TS 0x01 +#define STREAMTCP_QUEUE_FLAG_WS 0x02 +#define STREAMTCP_QUEUE_FLAG_SACK 0x04 /** Tracking SYNs and SYN/ACKs */ typedef struct TcpStateQueue_ { @@ -44,8 +44,8 @@ typedef struct TcpStateQueue_ { } TcpStateQueue; typedef struct StreamTcpSackRecord { - uint32_t le; /**< left edge, host order */ - uint32_t re; /**< right edge, host order */ + uint32_t le; /**< left edge, host order */ + uint32_t re; /**< right edge, host order */ RB_ENTRY(StreamTcpSackRecord) rb; } StreamTcpSackRecord; @@ -71,7 +71,7 @@ typedef struct TcpSegmentPcapHdrStorage_ { typedef struct TcpSegment { PoolThreadId pool_id; - uint16_t payload_len; /**< actual size of the payload */ + uint16_t payload_len; /**< actual size of the payload */ uint32_t seq; RB_ENTRY(TcpSegment) __attribute__((__packed__)) rb; StreamingBufferSegment sbseg; @@ -91,54 +91,57 @@ int TcpSegmentCompare(struct TcpSegment *a, struct TcpSegment *b); RB_HEAD(TCPSEG, TcpSegment); RB_PROTOTYPE(TCPSEG, TcpSegment, rb, TcpSegmentCompare); -#define TCP_SEG_LEN(seg) (seg)->payload_len -#define TCP_SEG_OFFSET(seg) (seg)->sbseg.stream_offset +#define TCP_SEG_LEN(seg) (seg)->payload_len +#define TCP_SEG_OFFSET(seg) (seg)->sbseg.stream_offset #define SEG_SEQ_RIGHT_EDGE(seg) ((seg)->seq + TCP_SEG_LEN((seg))) /* get right edge of sequence space of seen segments. * Only use if STREAM_HAS_SEEN_DATA is true. */ -#define STREAM_SEQ_RIGHT_EDGE(stream) (stream)->segs_right_edge -#define STREAM_RIGHT_EDGE(stream) (STREAM_BASE_OFFSET((stream)) + (STREAM_SEQ_RIGHT_EDGE((stream)) - (stream)->base_seq)) +#define STREAM_SEQ_RIGHT_EDGE(stream) (stream)->segs_right_edge +#define STREAM_RIGHT_EDGE(stream) \ + (STREAM_BASE_OFFSET((stream)) + (STREAM_SEQ_RIGHT_EDGE((stream)) - (stream)->base_seq)) /* return true if we have seen data. */ #define STREAM_HAS_SEEN_DATA(stream) StreamingBufferHasData(&(stream)->sb) typedef struct TcpStream_ { - uint16_t flags:12; /**< Flag specific to the stream e.g. Timestamp */ + uint16_t flags : 12; /**< Flag specific to the stream e.g. Timestamp */ /* coccinelle: TcpStream:flags:STREAMTCP_STREAM_FLAG_ */ - uint16_t wscale:4; /**< wscale setting in this direction, 4 bits as max val is 15 */ - uint8_t os_policy; /**< target based OS policy used for reassembly and handling packets*/ - uint8_t tcp_flags; /**< TCP flags seen */ - - uint32_t isn; /**< initial sequence number */ - uint32_t next_seq; /**< next expected sequence number */ - uint32_t last_ack; /**< last ack'd sequence number in this stream */ - uint32_t next_win; /**< next max seq within window */ - uint32_t window; /**< current window setting, after wscale is applied */ - - uint32_t last_ts; /**< Time stamp (TSVAL) of the last seen packet for this stream*/ - uint32_t last_pkt_ts; /**< Time of last seen packet for this stream (needed for PAWS update) - This will be used to validate the last_ts, when connection has been idle for - longer time.(RFC 1323)*/ + uint16_t wscale : 4; /**< wscale setting in this direction, 4 bits as max val is 15 */ + uint8_t os_policy; /**< target based OS policy used for reassembly and handling packets*/ + uint8_t tcp_flags; /**< TCP flags seen */ + + uint32_t isn; /**< initial sequence number */ + uint32_t next_seq; /**< next expected sequence number */ + uint32_t last_ack; /**< last ack'd sequence number in this stream */ + uint32_t next_win; /**< next max seq within window */ + uint32_t window; /**< current window setting, after wscale is applied */ + + uint32_t last_ts; /**< Time stamp (TSVAL) of the last seen packet for this stream*/ + uint32_t last_pkt_ts; /**< Time of last seen packet for this stream (needed for PAWS update) + This will be used to validate the last_ts, when connection has been + idle for longer time.(RFC 1323)*/ /* reassembly */ uint32_t base_seq; /**< seq where we are left with reassembly. Matches STREAM_BASE_OFFSET below. */ - uint32_t app_progress_rel; /**< app-layer progress relative to STREAM_BASE_OFFSET */ - uint32_t raw_progress_rel; /**< raw reassembly progress relative to STREAM_BASE_OFFSET */ - uint32_t log_progress_rel; /**< streaming logger progress relative to STREAM_BASE_OFFSET */ + uint32_t app_progress_rel; /**< app-layer progress relative to STREAM_BASE_OFFSET */ + uint32_t raw_progress_rel; /**< raw reassembly progress relative to STREAM_BASE_OFFSET */ + uint32_t log_progress_rel; /**< streaming logger progress relative to STREAM_BASE_OFFSET */ - uint32_t min_inspect_depth; /**< min inspect size set by the app layer, to make sure enough data - * remains available for inspection together with app layer buffers */ - uint32_t data_required; /**< data required from STREAM_APP_PROGRESS before calling app-layer again */ + uint32_t min_inspect_depth; /**< min inspect size set by the app layer, to make sure enough data + * remains available for inspection together with app layer + * buffers */ + uint32_t data_required; /**< data required from STREAM_APP_PROGRESS before calling app-layer + again */ StreamingBuffer sb; - struct TCPSEG seg_tree; /**< red black tree of TCP segments. Data is stored in TcpStream::sb */ + struct TCPSEG seg_tree; /**< red black tree of TCP segments. Data is stored in TcpStream::sb */ uint32_t segs_right_edge; - uint32_t sack_size; /**< combined size of the SACK ranges currently in our tree. Updated - * at INSERT/REMOVE time. */ - struct TCPSACK sack_tree; /**< red back tree of TCP SACK records. */ + uint32_t sack_size; /**< combined size of the SACK ranges currently in our tree. Updated + * at INSERT/REMOVE time. */ + struct TCPSACK sack_tree; /**< red back tree of TCP SACK records. */ } TcpStream; #define STREAM_BASE_OFFSET(stream) ((stream)->sb.region.stream_offset) @@ -181,7 +184,8 @@ enum TcpState { /** Flag to indicate that the session is handling asynchronous stream.*/ #define STREAMTCP_FLAG_ASYNC BIT_U32(6) /** Flag to indicate we're dealing with 4WHS: SYN, SYN, SYN/ACK, ACK - * (http://www.breakingpointsystems.com/community/blog/tcp-portals-the-three-way-handshake-is-a-lie) */ + * (http://www.breakingpointsystems.com/community/blog/tcp-portals-the-three-way-handshake-is-a-lie) + */ #define STREAMTCP_FLAG_4WHS BIT_U32(7) /** Flag to indicate that this session is possible trying to evade the detection * (http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html) */ @@ -216,56 +220,57 @@ enum TcpState { /** Flag to indicate that we have seen gap on the stream */ #define STREAMTCP_STREAM_FLAG_HAS_GAP BIT_U16(0) /** Flag to avoid stream reassembly/app layer inspection for the stream */ -#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY BIT_U16(1) +#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY BIT_U16(1) /** we received a keep alive */ -#define STREAMTCP_STREAM_FLAG_KEEPALIVE BIT_U16(2) +#define STREAMTCP_STREAM_FLAG_KEEPALIVE BIT_U16(2) /** Stream has reached it's reassembly depth, all further packets are ignored */ -#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED BIT_U16(3) +#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED BIT_U16(3) /** Trigger reassembly next time we need 'raw' */ -#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW BIT_U16(4) +#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW BIT_U16(4) /** Stream supports TIMESTAMP -- used to set ssn STREAMTCP_FLAG_TIMESTAMP * flag. */ -#define STREAMTCP_STREAM_FLAG_TIMESTAMP BIT_U16(5) +#define STREAMTCP_STREAM_FLAG_TIMESTAMP BIT_U16(5) /** Flag to indicate the zero value of timestamp */ -#define STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP BIT_U16(6) +#define STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP BIT_U16(6) /** App proto detection completed */ -#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED BIT_U16(7) +#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED BIT_U16(7) /** App proto detection skipped */ -#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED BIT_U16(8) +#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED BIT_U16(8) /** Raw reassembly disabled for new segments */ -#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED BIT_U16(9) +#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED BIT_U16(9) /** Raw reassembly disabled completely */ -#define STREAMTCP_STREAM_FLAG_DISABLE_RAW BIT_U16(10) +#define STREAMTCP_STREAM_FLAG_DISABLE_RAW BIT_U16(10) -#define STREAMTCP_STREAM_FLAG_RST_RECV BIT_U16(11) +#define STREAMTCP_STREAM_FLAG_RST_RECV BIT_U16(11) /** NOTE: flags field is 12 bits */ +#define PAWS_24DAYS 2073600 /**< 24 days in seconds */ - - -#define PAWS_24DAYS 2073600 /**< 24 days in seconds */ - -#define PKT_IS_IN_RIGHT_DIR(ssn, p) ((ssn)->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK ? \ - PKT_IS_TOSERVER(p) ? (p)->flowflags &= ~FLOW_PKT_TOSERVER \ - (p)->flowflags |= FLOW_PKT_TOCLIENT : (p)->flowflags &= ~FLOW_PKT_TOCLIENT \ - (p)->flowflags |= FLOW_PKT_TOSERVER : 0) +#define PKT_IS_IN_RIGHT_DIR(ssn, p) \ + ((ssn)->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK \ + ? PKT_IS_TOSERVER(p) ? (p)->flowflags &= ~FLOW_PKT_TOSERVER(p)->flowflags |= \ + FLOW_PKT_TOCLIENT \ + : (p)->flowflags &= ~FLOW_PKT_TOCLIENT(p)->flowflags |= \ + FLOW_PKT_TOSERVER \ + : 0) /* Macro's for comparing Sequence numbers * Page 810 from TCP/IP Illustrated, Volume 2. */ -#define SEQ_EQ(a,b) ((int32_t)((a) - (b)) == 0) -#define SEQ_LT(a,b) ((int32_t)((a) - (b)) < 0) -#define SEQ_LEQ(a,b) ((int32_t)((a) - (b)) <= 0) -#define SEQ_GT(a,b) ((int32_t)((a) - (b)) > 0) -#define SEQ_GEQ(a,b) ((int32_t)((a) - (b)) >= 0) +#define SEQ_EQ(a, b) ((int32_t)((a) - (b)) == 0) +#define SEQ_LT(a, b) ((int32_t)((a) - (b)) < 0) +#define SEQ_LEQ(a, b) ((int32_t)((a) - (b)) <= 0) +#define SEQ_GT(a, b) ((int32_t)((a) - (b)) > 0) +#define SEQ_GEQ(a, b) ((int32_t)((a) - (b)) >= 0) #define SEQ_MIN(a, b) (SEQ_LT((a), (b)) ? (a) : (b)) #define SEQ_MAX(a, b) (SEQ_GT((a), (b)) ? (a) : (b)) -#define STREAMTCP_SET_RA_BASE_SEQ(stream, seq) { \ - do { \ - (stream)->base_seq = (seq) + 1; \ - } while(0); \ -} +#define STREAMTCP_SET_RA_BASE_SEQ(stream, seq) \ + { \ + do { \ + (stream)->base_seq = (seq) + 1; \ + } while (0); \ + } #define StreamTcpSetEvent(p, e) \ { \ @@ -282,9 +287,9 @@ enum TcpState { typedef struct TcpSession_ { PoolThreadId pool_id; - uint8_t state:4; /**< tcp state from state enum */ - uint8_t pstate:4; /**< previous state */ - uint8_t queue_len; /**< length of queue list below */ + uint8_t state : 4; /**< tcp state from state enum */ + uint8_t pstate : 4; /**< previous state */ + uint8_t queue_len; /**< length of queue list below */ int8_t data_first_seen_dir; /** track all the tcp flags we've seen */ uint8_t tcp_packet_flags; @@ -293,18 +298,19 @@ typedef struct TcpSession_ { uint32_t reassembly_depth; /**< reassembly depth for the stream */ TcpStream server; TcpStream client; - TcpStateQueue *queue; /**< list of SYN/ACK candidates */ + TcpStateQueue *queue; /**< list of SYN/ACK candidates */ } TcpSession; -#define StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream) \ +#define StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream) \ ((stream)->flags |= STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) -#define StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) \ +#define StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) \ ((stream)->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) -#define StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream) \ +#define StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream) \ ((stream)->flags &= ~STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED); -#define StreamTcpDisableAppLayerReassembly(ssn) do { \ - SCLogDebug("setting STREAMTCP_FLAG_APP_LAYER_DISABLED on ssn %p", ssn); \ - ((ssn)->flags |= STREAMTCP_FLAG_APP_LAYER_DISABLED); \ +#define StreamTcpDisableAppLayerReassembly(ssn) \ + do { \ + SCLogDebug("setting STREAMTCP_FLAG_APP_LAYER_DISABLED on ssn %p", ssn); \ + ((ssn)->flags |= STREAMTCP_FLAG_APP_LAYER_DISABLED); \ } while (0); #define STREAM_PKT_FLAG_RETRANSMISSION BIT_U16(0) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 9d705f1f5277..7865f07f4b89 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -38,13 +38,13 @@ #include "threadvars.h" #include "tm-threads.h" -#include "util-pool.h" -#include "util-unittest.h" -#include "util-print.h" -#include "util-host-os-info.h" -#include "util-unittest-helper.h" -#include "util-byte.h" -#include "util-device.h" +#include "util/pool.h" +#include "util/unittest.h" +#include "util/print.h" +#include "util/host-os-info.h" +#include "util/unittest-helper.h" +#include "util/byte.h" +#include "util/device.h" #include "stream-tcp.h" #include "stream-tcp-private.h" @@ -56,7 +56,7 @@ #include "stream.h" -#include "util-debug.h" +#include "util/debug.h" #include "app-layer-protos.h" #include "app-layer.h" #include "app-layer-events.h" @@ -65,9 +65,9 @@ #include "detect-engine-state.h" -#include "util-profiling.h" -#include "util-validate.h" -#include "util-exception-policy.h" +#include "util/profiling.h" +#include "util/validate.h" +#include "util/exception-policy.h" #ifdef DEBUG static SCMutex segment_pool_memuse_mutex; @@ -113,8 +113,9 @@ void StreamTcpReassembleInitMemuse(void) */ void StreamTcpReassembleIncrMemuse(uint64_t size) { - (void) SC_ATOMIC_ADD(ra_memuse, size); - SCLogDebug("REASSEMBLY %"PRIu64", incr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size); + (void)SC_ATOMIC_ADD(ra_memuse, size); + SCLogDebug("REASSEMBLY %" PRIu64 ", incr %" PRIu64, StreamTcpReassembleMemuseGlobalCounter(), + size); return; } @@ -133,7 +134,7 @@ void StreamTcpReassembleDecrMemuse(uint64_t size) } #endif - (void) SC_ATOMIC_SUB(ra_memuse, size); + (void)SC_ATOMIC_SUB(ra_memuse, size); #ifdef UNITTESTS if (RunmodeIsUnittests()) { @@ -141,7 +142,8 @@ void StreamTcpReassembleDecrMemuse(uint64_t size) BUG_ON(postsize > presize); } #endif - SCLogDebug("REASSEMBLY %"PRIu64", decr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size); + SCLogDebug("REASSEMBLY %" PRIu64 ", decr %" PRIu64, StreamTcpReassembleMemuseGlobalCounter(), + size); return; } @@ -169,8 +171,7 @@ int StreamTcpReassembleCheckMemcap(uint64_t size) } #endif uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.reassembly_memcap); - if (memcapcopy == 0 || - (uint64_t)((uint64_t)size + SC_ATOMIC_GET(ra_memuse)) <= memcapcopy) + if (memcapcopy == 0 || (uint64_t)((uint64_t)size + SC_ATOMIC_GET(ra_memuse)) <= memcapcopy) return 1; return 0; } @@ -266,7 +267,7 @@ static void *TcpSegmentPoolAlloc(void) TcpSegment *seg = NULL; - seg = SCMalloc(sizeof (TcpSegment)); + seg = SCMalloc(sizeof(TcpSegment)); if (unlikely(seg == NULL)) return NULL; @@ -308,14 +309,14 @@ static void *TcpSegmentPoolAlloc(void) static int TcpSegmentPoolInit(void *data, void *initdata) { - TcpSegment *seg = (TcpSegment *) data; + TcpSegment *seg = (TcpSegment *)data; TcpSegmentPcapHdrStorage *pcap_hdr; pcap_hdr = seg->pcap_hdr_storage; /* do this before the can bail, so TcpSegmentPoolCleanup * won't have uninitialized memory to consider. */ - memset(seg, 0, sizeof (TcpSegment)); + memset(seg, 0, sizeof(TcpSegment)); if (IsTcpSessionDumpingEnabled()) { uint32_t memuse = @@ -335,7 +336,7 @@ static int TcpSegmentPoolInit(void *data, void *initdata) SCMutexLock(&segment_pool_memuse_mutex); segment_pool_memuse += sizeof(TcpSegment); segment_pool_memcnt++; - SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); + SCLogDebug("segment_pool_memcnt %" PRIu64 "", segment_pool_memcnt); SCMutexUnlock(&segment_pool_memuse_mutex); #endif @@ -366,7 +367,7 @@ static void TcpSegmentPoolCleanup(void *ptr) SCMutexLock(&segment_pool_memuse_mutex); segment_pool_memuse -= sizeof(TcpSegment); segment_pool_memcnt--; - SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); + SCLogDebug("segment_pool_memcnt %" PRIu64 "", segment_pool_memcnt); SCMutexUnlock(&segment_pool_memuse_mutex); #endif } @@ -393,11 +394,10 @@ void StreamTcpSegmentReturntoPool(TcpSegment *seg) * * \param stream the stream to cleanup */ -void StreamTcpReturnStreamSegments (TcpStream *stream) +void StreamTcpReturnStreamSegments(TcpStream *stream) { TcpSegment *seg = NULL, *safe = NULL; - RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe) - { + RB_FOREACH_SAFE (seg, TCPSEG, &stream->seg_tree, safe) { RB_REMOVE(TCPSEG, &stream->seg_tree, seg); StreamTcpSegmentReturntoPool(seg); } @@ -458,8 +458,8 @@ void StreamTcpDisableAppLayer(Flow *f) StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); StreamTcpDisableAppLayerReassembly(ssn); if (f->alparser) { - AppLayerParserStateSetFlag(f->alparser, - (APP_LAYER_PARSER_EOF_TS|APP_LAYER_PARSER_EOF_TC)); + AppLayerParserStateSetFlag( + f->alparser, (APP_LAYER_PARSER_EOF_TS | APP_LAYER_PARSER_EOF_TC)); } } @@ -535,8 +535,7 @@ int StreamTcpReassembleInit(bool quiet) #ifdef DEBUG SCMutexInit(&segment_pool_memuse_mutex, NULL); #endif - StatsRegisterGlobalCounter("tcp.reassembly_memuse", - StreamTcpReassembleMemuseGlobalCounter); + StatsRegisterGlobalCounter("tcp.reassembly_memuse", StreamTcpReassembleMemuseGlobalCounter); return 0; } @@ -570,22 +569,17 @@ TcpReassemblyThreadCtx *StreamTcpReassembleInitThreadCtx(ThreadVars *tv) SCMutexLock(&segment_thread_pool_mutex); if (segment_thread_pool == NULL) { segment_thread_pool = PoolThreadInit(1, /* thread */ - 0, /* unlimited */ - stream_config.prealloc_segments, - sizeof(TcpSegment), - TcpSegmentPoolAlloc, - TcpSegmentPoolInit, NULL, - TcpSegmentPoolCleanup, NULL); + 0, /* unlimited */ + stream_config.prealloc_segments, sizeof(TcpSegment), TcpSegmentPoolAlloc, + TcpSegmentPoolInit, NULL, TcpSegmentPoolCleanup, NULL); ra_ctx->segment_thread_pool_id = 0; SCLogDebug("pool size %d, thread segment_thread_pool_id %d", - PoolThreadSize(segment_thread_pool), - ra_ctx->segment_thread_pool_id); + PoolThreadSize(segment_thread_pool), ra_ctx->segment_thread_pool_id); } else { /* grow segment_thread_pool until we have an element for our thread id */ ra_ctx->segment_thread_pool_id = PoolThreadExpand(segment_thread_pool); SCLogDebug("pool size %d, thread segment_thread_pool_id %d", - PoolThreadSize(segment_thread_pool), - ra_ctx->segment_thread_pool_id); + PoolThreadSize(segment_thread_pool), ra_ctx->segment_thread_pool_id); } SCMutexUnlock(&segment_thread_pool_mutex); if (ra_ctx->segment_thread_pool_id < 0 || segment_thread_pool == NULL) { @@ -645,8 +639,8 @@ int StreamTcpReassembleDepthReached(Packet *p) * * \retval size Part of the size that fits in the depth, 0 if none */ -static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream, - uint32_t seq, uint32_t size) +static uint32_t StreamTcpReassembleCheckDepth( + TcpSession *ssn, TcpStream *stream, uint32_t seq, uint32_t size) { SCEnter(); @@ -663,9 +657,9 @@ static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream uint64_t seg_depth; if (SEQ_GT(stream->base_seq, seq)) { - if (SEQ_LEQ(seq+size, stream->base_seq)) { + if (SEQ_LEQ(seq + size, stream->base_seq)) { SCLogDebug("segment entirely before base_seq, weird: base %u, seq %u, re %u", - stream->base_seq, seq, seq+size); + stream->base_seq, seq, seq + size); SCReturnUInt(0); } @@ -678,9 +672,8 @@ static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream * checking and just reject the rest of the packets including * retransmissions. Saves us the hassle of dealing with sequence * wraps as well */ - SCLogDebug("seq + size %u, base %u, seg_depth %"PRIu64" limit %u", (seq + size), - stream->base_seq, seg_depth, - ssn->reassembly_depth); + SCLogDebug("seq + size %u, base %u, seg_depth %" PRIu64 " limit %u", (seq + size), + stream->base_seq, seg_depth, ssn->reassembly_depth); if (seg_depth > (uint64_t)ssn->reassembly_depth) { SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED"); @@ -688,7 +681,7 @@ static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream SCReturnUInt(0); } SCLogDebug("NOT STREAMTCP_STREAM_FLAG_DEPTH_REACHED"); - SCLogDebug("%"PRIu64" <= %u", seg_depth, ssn->reassembly_depth); + SCLogDebug("%" PRIu64 " <= %u", seg_depth, ssn->reassembly_depth); #if 0 SCLogDebug("full depth not yet reached: %"PRIu64" <= %"PRIu32, (stream->base_seq_offset + stream->base_seq + size), @@ -697,7 +690,7 @@ static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) { /* packet (partly?) fits the depth window */ - if (SEQ_LEQ((seq + size),(stream->isn + 1 + ssn->reassembly_depth))) { + if (SEQ_LEQ((seq + size), (stream->isn + 1 + ssn->reassembly_depth))) { /* complete fit */ SCReturnUInt(size); } else { @@ -739,7 +732,7 @@ uint32_t StreamDataAvailableForProtoDetect(TcpStream *stream) * */ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, Packet *p) + TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); @@ -757,7 +750,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre } if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) && - (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) { + (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) { SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn); SCReturnInt(0); } @@ -765,7 +758,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre /* If we have reached the defined depth for either of the stream, then stop reassembling the TCP session */ uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len); - SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size); + SCLogDebug("ssn %p: check depth returned %" PRIu32, ssn, size); if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { StreamTcpSetEvent(p, STREAM_REASSEMBLY_DEPTH_REACHED); @@ -800,10 +793,9 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre /* proto detection skipped, but now we do get data. Set event. */ if (RB_EMPTY(&stream->seg_tree) && - stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) { + stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); } int r = StreamTcpReassembleInsertSegment( @@ -818,8 +810,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre SCReturnInt(0); } -static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream, - Packet *p) +static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream, Packet *p) { uint8_t flag = 0; @@ -856,28 +847,27 @@ static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream, * \retval 0 don't reassemble yet * \retval 1 do reassemble */ -static int StreamTcpReassembleRawCheckLimit(const TcpSession *ssn, - const TcpStream *stream, const Packet *p) +static int StreamTcpReassembleRawCheckLimit( + const TcpSession *ssn, const TcpStream *stream, const Packet *p) { SCEnter(); /* if any of these flags is set we always inspect immediately */ -#define STREAMTCP_STREAM_FLAG_FLUSH_FLAGS \ - ( STREAMTCP_STREAM_FLAG_DEPTH_REACHED \ - | STREAMTCP_STREAM_FLAG_TRIGGER_RAW \ - | STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) +#define STREAMTCP_STREAM_FLAG_FLUSH_FLAGS \ + (STREAMTCP_STREAM_FLAG_DEPTH_REACHED | STREAMTCP_STREAM_FLAG_TRIGGER_RAW | \ + STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) if (stream->flags & STREAMTCP_STREAM_FLAG_FLUSH_FLAGS) { if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_DEPTH_REACHED " - "is set, so not expecting any new data segments"); + "is set, so not expecting any new data segments"); } if (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) { SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_TRIGGER_RAW is set"); } if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) { SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, " - "so no new segments will be considered"); + "so no new segments will be considered"); } SCReturnInt(1); } @@ -982,7 +972,8 @@ static uint64_t GetStreamSize(TcpStream *stream) SCLogDebug("stream_offset %" PRIu64, stream->sb.region.stream_offset); TcpSegment *seg; - RB_FOREACH(seg, TCPSEG, &stream->seg_tree) { + RB_FOREACH(seg, TCPSEG, &stream->seg_tree) + { const uint64_t seg_abs = STREAM_BASE_OFFSET(stream) + (uint64_t)(seg->seq - stream->base_seq); if (last_re != 0 && last_re < seg_abs) { @@ -1015,7 +1006,7 @@ static uint64_t GetStreamSize(TcpStream *stream) size += (uint64_t)TCP_SEG_LEN(seg); } - SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt); + SCLogDebug("size %" PRIu64 ", cnt %" PRIu32, size, cnt); return size; } return (uint64_t)0; @@ -1028,9 +1019,9 @@ static void GetSessionSize(TcpSession *ssn, Packet *p) size = GetStreamSize(&ssn->client); size += GetStreamSize(&ssn->server); - //if (size > 900000) - // SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt); - SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt); + // if (size > 900000) + // SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt); + SCLogDebug("size %" PRIu64 ", packet %" PRIu64, size, p->pcap_cnt); } } #endif @@ -1041,7 +1032,7 @@ static StreamingBufferBlock *GetBlock(const StreamingBuffer *sb, const uint64_t if (blk == NULL) return NULL; - for ( ; blk != NULL; blk = SBB_RB_NEXT(blk)) { + for (; blk != NULL; blk = SBB_RB_NEXT(blk)) { if (blk->offset >= offset) return blk; else if ((blk->offset + blk->len) > offset) { @@ -1103,18 +1094,18 @@ static bool GetAppBuffer(const TcpStream *stream, const uint8_t **data, uint32_t gap_ahead = check_for_gap && GapAhead(stream, blk); - /* block past out offset */ + /* block past out offset */ } else if (blk->offset > offset) { - SCLogDebug("gap, want data at offset %"PRIu64", " - "got data at %"PRIu64". GAP of size %"PRIu64, + SCLogDebug("gap, want data at offset %" PRIu64 ", " + "got data at %" PRIu64 ". GAP of size %" PRIu64, offset, blk->offset, blk->offset - offset); *data = NULL; *data_len = blk->offset - offset; - /* block starts before offset, but ends after */ + /* block starts before offset, but ends after */ } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) { - SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u", - offset, blk->offset, blk->len); + SCLogDebug("get data from offset %" PRIu64 ". SBB %" PRIu64 "/%u", offset, blk->offset, + blk->len); StreamingBufferSBBGetDataAtOffset(&stream->sb, blk, data, data_len, offset); SCLogDebug("data %p, data_len %u", *data, *data_len); @@ -1174,15 +1165,14 @@ static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p) p->pcap_cnt, last_ack_abs, app_progress); return true; } - SCLogDebug("packet %"PRIu64": no GAP. " - "last_ack_abs %"PRIu64" <= app_progress %"PRIu64, + SCLogDebug("packet %" PRIu64 ": no GAP. " + "last_ack_abs %" PRIu64 " <= app_progress %" PRIu64, p->pcap_cnt, last_ack_abs, app_progress); return false; } -static inline uint32_t AdjustToAcked(const Packet *p, - const TcpSession *ssn, const TcpStream *stream, - const uint64_t app_progress, const uint32_t data_len) +static inline uint32_t AdjustToAcked(const Packet *p, const TcpSession *ssn, + const TcpStream *stream, const uint64_t app_progress, const uint32_t data_len) { uint32_t adjusted = data_len; @@ -1204,7 +1194,8 @@ static inline uint32_t AdjustToAcked(const Packet *p, adjusted = last_ack_abs - app_progress; BUG_ON(adjusted > check); SCLogDebug("data len adjusted to %u to make sure only ACK'd " - "data is considered", adjusted); + "data is considered", + adjusted); } } } @@ -1216,14 +1207,12 @@ static inline uint32_t AdjustToAcked(const Packet *p, * \param stream pointer to pointer as app-layer can switch flow dir * \retval 0 success */ -static int ReassembleUpdateAppLayer (ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream **stream, - Packet *p, enum StreamUpdateDir dir) +static int ReassembleUpdateAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, + TcpStream **stream, Packet *p, enum StreamUpdateDir dir) { uint64_t app_progress = STREAM_APP_PROGRESS(*stream); - SCLogDebug("app progress %"PRIu64, app_progress); + SCLogDebug("app progress %" PRIu64, app_progress); #ifdef DEBUG uint64_t last_ack_abs = GetAbsLastAck(*stream); SCLogDebug("last_ack %u (abs %" PRIu64 "), base_seq %u", (*stream)->last_ack, last_ack_abs, @@ -1293,13 +1282,13 @@ static int ReassembleUpdateAppLayer (ThreadVars *tv, mydata = NULL; mydata_len = 0; - SCLogDebug("%"PRIu64" got %p/%u", p->pcap_cnt, mydata, mydata_len); + SCLogDebug("%" PRIu64 " got %p/%u", p->pcap_cnt, mydata, mydata_len); break; } DEBUG_VALIDATE_BUG_ON(mydata == NULL && mydata_len > 0); - SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64, - *stream, &(*stream)->sb, mydata_len, app_progress); + SCLogDebug("stream %p data in buffer %p of len %u and offset %" PRIu64, *stream, + &(*stream)->sb, mydata_len, app_progress); if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED) { SCLogDebug("GAP?2"); @@ -1350,16 +1339,15 @@ static int ReassembleUpdateAppLayer (ThreadVars *tv, * any issues, since processing of each stream is independent of the * other stream. */ -int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p, enum StreamUpdateDir dir) +int StreamTcpReassembleAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, + TcpStream *stream, Packet *p, enum StreamUpdateDir dir) { SCEnter(); /* this function can be directly called by app layer protocol * detection. */ if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || - (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { + (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { SCLogDebug("stream no reassembly flag set or app-layer disabled."); SCReturnInt(0); } @@ -1370,8 +1358,7 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, #endif /* if no segments are in the list or all are already processed, * and state is beyond established, we send an empty msg */ - if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream)) - { + if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream)) { /* send an empty EOF msg if we have no segments but TCP state * is beyond ESTABLISHED */ if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) { @@ -1398,7 +1385,7 @@ static int GetRawBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_ const uint8_t *mydata; uint32_t mydata_len; if (RB_EMPTY(&stream->sb.sbb_tree)) { - SCLogDebug("getting one blob for offset %"PRIu64, offset); + SCLogDebug("getting one blob for offset %" PRIu64, offset); uint64_t roffset = offset; if (offset) @@ -1411,8 +1398,8 @@ static int GetRawBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_ *data_len = mydata_len; *data_offset = roffset; } else { - SCLogDebug("multiblob %s. Want offset %"PRIu64, - *iter == NULL ? "starting" : "continuing", offset); + SCLogDebug("multiblob %s. Want offset %" PRIu64, *iter == NULL ? "starting" : "continuing", + offset); if (*iter == NULL) { StreamingBufferBlock key = { .offset = offset, .len = 0 }; *iter = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key); @@ -1425,7 +1412,8 @@ static int GetRawBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_ *data_offset = 0; return 0; } - SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u", *iter, (*iter)->offset, (*iter)->len); + SCLogDebug("getting multiple blobs. Iter %p, %" PRIu64 "/%u", *iter, (*iter)->offset, + (*iter)->len); StreamingBufferSBBGetData(&stream->sb, (*iter), &mydata, &mydata_len); SCLogDebug("mydata %p", mydata); @@ -1475,8 +1463,7 @@ bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p) return false; } - if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY| - STREAMTCP_STREAM_FLAG_DISABLE_RAW)) + if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY | STREAMTCP_STREAM_FLAG_DISABLE_RAW)) return false; if (!StreamTcpInlineMode()) { @@ -1536,9 +1523,10 @@ void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_ stream->flags &= ~STREAMTCP_STREAM_FLAG_TRIGGER_RAW; } else { - SCLogDebug("p->pcap_cnt %"PRIu64": progress %"PRIu64" app %"PRIu64" raw %"PRIu64" tcp win %"PRIu32, - p->pcap_cnt, progress, STREAM_APP_PROGRESS(stream), - STREAM_RAW_PROGRESS(stream), stream->window); + SCLogDebug("p->pcap_cnt %" PRIu64 ": progress %" PRIu64 " app %" PRIu64 " raw %" PRIu64 + " tcp win %" PRIu32, + p->pcap_cnt, progress, STREAM_APP_PROGRESS(stream), STREAM_RAW_PROGRESS(stream), + stream->window); } /* if we were told to accept no more raw data, we can mark raw as @@ -1546,27 +1534,28 @@ void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_ if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) { stream->flags |= STREAMTCP_STREAM_FLAG_DISABLE_RAW; SCLogDebug("ssn %p: STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED set, " - "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", ssn); + "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", + ssn); } - SCLogDebug("stream raw progress now %"PRIu64, STREAM_RAW_PROGRESS(stream)); + SCLogDebug("stream raw progress now %" PRIu64, STREAM_RAW_PROGRESS(stream)); } /** \internal - * \brief get a buffer around the current packet and run the callback on it - * - * The inline/IPS scanning method takes the current payload and wraps it in - * data from other segments. - * - * How much data is inspected is controlled by the available data, chunk_size - * and the payload size of the packet. - * - * Large packets: if payload size is close to the chunk_size, where close is - * defined as more than 67% of the chunk_size, a larger chunk_size will be - * used: payload_len + 33% of the chunk_size. - * If the payload size if equal to or bigger than the chunk_size, we use - * payload len + 33% of the chunk size. - */ + * \brief get a buffer around the current packet and run the callback on it + * + * The inline/IPS scanning method takes the current payload and wraps it in + * data from other segments. + * + * How much data is inspected is controlled by the available data, chunk_size + * and the payload size of the packet. + * + * Large packets: if payload size is close to the chunk_size, where close is + * defined as more than 67% of the chunk_size, a larger chunk_size will be + * used: payload_len + 33% of the chunk_size. + * If the payload size if equal to or bigger than the chunk_size, we use + * payload len + 33% of the chunk size. + */ static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p, StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out) { @@ -1581,29 +1570,27 @@ static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p, } if (p->payload_len == 0 || (p->flags & PKT_STREAM_ADD) == 0 || - (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) - { + (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { *progress_out = STREAM_RAW_PROGRESS(stream); return 0; } - uint32_t chunk_size = PKT_IS_TOSERVER(p) ? - stream_config.reassembly_toserver_chunk_size : - stream_config.reassembly_toclient_chunk_size; + uint32_t chunk_size = PKT_IS_TOSERVER(p) ? stream_config.reassembly_toserver_chunk_size + : stream_config.reassembly_toclient_chunk_size; if (chunk_size <= p->payload_len) { chunk_size = p->payload_len + (chunk_size / 3); - SCLogDebug("packet payload len %u, so chunk_size adjusted to %u", - p->payload_len, chunk_size); - } else if (((chunk_size / 3 ) * 2) < p->payload_len) { + SCLogDebug( + "packet payload len %u, so chunk_size adjusted to %u", p->payload_len, chunk_size); + } else if (((chunk_size / 3) * 2) < p->payload_len) { chunk_size = p->payload_len + ((chunk_size / 3)); - SCLogDebug("packet payload len %u, so chunk_size adjusted to %u", - p->payload_len, chunk_size); + SCLogDebug( + "packet payload len %u, so chunk_size adjusted to %u", p->payload_len, chunk_size); } uint64_t packet_leftedge_abs = STREAM_BASE_OFFSET(stream) + (TCP_GET_SEQ(p) - stream->base_seq); uint64_t packet_rightedge_abs = packet_leftedge_abs + p->payload_len; - SCLogDebug("packet_leftedge_abs %"PRIu64", rightedge %"PRIu64, - packet_leftedge_abs, packet_rightedge_abs); + SCLogDebug("packet_leftedge_abs %" PRIu64 ", rightedge %" PRIu64, packet_leftedge_abs, + packet_rightedge_abs); const uint8_t *mydata = NULL; uint32_t mydata_len = 0; @@ -1617,12 +1604,12 @@ static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p, return_progress = true; } else { - SCLogDebug("finding our SBB from offset %"PRIu64, packet_leftedge_abs); + SCLogDebug("finding our SBB from offset %" PRIu64, packet_leftedge_abs); /* find our block */ StreamingBufferBlock key = { .offset = packet_leftedge_abs, .len = p->payload_len }; StreamingBufferBlock *sbb = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key); if (sbb) { - SCLogDebug("found %p offset %"PRIu64" len %u", sbb, sbb->offset, sbb->len); + SCLogDebug("found %p offset %" PRIu64 " len %u", sbb, sbb->offset, sbb->len); StreamingBufferSBBGetData(&stream->sb, sbb, &mydata, &mydata_len); mydata_offset = sbb->offset; } @@ -1630,17 +1617,17 @@ static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p, /* this can only happen if the segment insert of our current 'p' failed */ uint64_t mydata_rightedge_abs = mydata_offset + mydata_len; - if ((mydata == NULL || mydata_len == 0) || /* no data */ - (mydata_offset >= packet_rightedge_abs || /* data all to the right */ - packet_leftedge_abs >= mydata_rightedge_abs) || /* data all to the left */ - (packet_leftedge_abs < mydata_offset || /* data missing at the start */ - packet_rightedge_abs > mydata_rightedge_abs)) /* data missing at the end */ + if ((mydata == NULL || mydata_len == 0) || /* no data */ + (mydata_offset >= packet_rightedge_abs || /* data all to the right */ + packet_leftedge_abs >= mydata_rightedge_abs) || /* data all to the left */ + (packet_leftedge_abs < mydata_offset || /* data missing at the start */ + packet_rightedge_abs > mydata_rightedge_abs)) /* data missing at the end */ { /* no data, or data is incomplete or wrong: use packet data */ mydata = p->payload; mydata_len = p->payload_len; mydata_offset = packet_leftedge_abs; - //mydata_rightedge_abs = packet_rightedge_abs; + // mydata_rightedge_abs = packet_rightedge_abs; } else { /* adjust buffer to match chunk_size */ SCLogDebug("chunk_size %u mydata_len %u", chunk_size, mydata_len); @@ -1708,7 +1695,7 @@ static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p, * our block. */ const uint64_t last_ack_abs = GetAbsLastAck(stream); - SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs); + SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs); if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) { if (mydata_offset > last_ack_abs) { @@ -1778,11 +1765,11 @@ static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream, SCLogDebug("no data"); break; } - //PrintRawDataFp(stdout, mydata, mydata_len); + // PrintRawDataFp(stdout, mydata, mydata_len); - SCLogDebug("raw progress %"PRIu64, progress); - SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64, - stream, &stream->sb, mydata_len, progress); + SCLogDebug("raw progress %" PRIu64, progress); + SCLogDebug("stream %p data in buffer %p of len %u and offset %" PRIu64, stream, &stream->sb, + mydata_len, progress); if (eof) { // inspect all remaining data, ack'd or not @@ -1802,7 +1789,8 @@ static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream, mydata_len = re - progress; BUG_ON(check < mydata_len); SCLogDebug("data len adjusted to %u to make sure only ACK'd " - "data is considered", mydata_len); + "data is considered", + mydata_len); } } if (mydata_len == 0) @@ -1815,22 +1803,25 @@ static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream, BUG_ON(r < 0); if (mydata_offset == progress) { - SCLogDebug("progress %"PRIu64" increasing with data len %u to %"PRIu64, - progress, mydata_len, progress_in + mydata_len); + SCLogDebug("progress %" PRIu64 " increasing with data len %u to %" PRIu64, progress, + mydata_len, progress_in + mydata_len); progress += mydata_len; - SCLogDebug("raw progress now %"PRIu64, progress); + SCLogDebug("raw progress now %" PRIu64, progress); - /* data is beyond the progress we'd like, and before last ack. Gap. */ + /* data is beyond the progress we'd like, and before last ack. Gap. */ } else if (mydata_offset > progress && mydata_offset < re) { - SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset); + SCLogDebug("GAP: data is missing from %" PRIu64 + " (%u bytes), setting to first data we have: %" PRIu64, + progress, (uint32_t)(mydata_offset - progress), mydata_offset); SCLogDebug("re %" PRIu64, re); progress = mydata_offset; - SCLogDebug("raw progress now %"PRIu64, progress); + SCLogDebug("raw progress now %" PRIu64, progress); } else { SCLogDebug("not increasing progress, data gap => mydata_offset " - "%"PRIu64" != progress %"PRIu64, mydata_offset, progress); + "%" PRIu64 " != progress %" PRIu64, + mydata_offset, progress); } if (iter == NULL || r == 1) @@ -1853,9 +1844,8 @@ int StreamReassembleForFrame(TcpSession *ssn, TcpStream *stream, StreamReassembl ssn, stream, Callback, cb_data, offset, app_progress, &unused, eof, false); } -int StreamReassembleRaw(TcpSession *ssn, const Packet *p, - StreamReassembleRawFunc Callback, void *cb_data, - uint64_t *progress_out, bool respect_inspect_depth) +int StreamReassembleRaw(TcpSession *ssn, const Packet *p, StreamReassembleRawFunc Callback, + void *cb_data, uint64_t *progress_out, bool respect_inspect_depth) { /* handle inline separately as the logic is very different */ if (StreamTcpInlineMode()) { @@ -1869,9 +1859,9 @@ int StreamReassembleRaw(TcpSession *ssn, const Packet *p, stream = &ssn->server; } - if ((stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|STREAMTCP_STREAM_FLAG_DISABLE_RAW)) || - StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0) - { + if ((stream->flags & + (STREAMTCP_STREAM_FLAG_NOREASSEMBLY | STREAMTCP_STREAM_FLAG_DISABLE_RAW)) || + StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0) { *progress_out = STREAM_RAW_PROGRESS(stream); return 0; } @@ -1918,10 +1908,8 @@ int StreamReassembleRaw(TcpSession *ssn, const Packet *p, progress_out, (p->flags & PKT_PSEUDO_STREAM_END), respect_inspect_depth); } -int StreamReassembleLog(TcpSession *ssn, TcpStream *stream, - StreamReassembleRawFunc Callback, void *cb_data, - uint64_t progress_in, - uint64_t *progress_out, bool eof) +int StreamReassembleLog(TcpSession *ssn, TcpStream *stream, StreamReassembleRawFunc Callback, + void *cb_data, uint64_t progress_in, uint64_t *progress_out, bool eof) { if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) return 0; @@ -1939,8 +1927,8 @@ int StreamReassembleLog(TcpSession *ssn, TcpStream *stream, * * \retval r 0 on success, -1 on error */ -static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p) +static int StreamTcpReassembleHandleSegmentUpdateACK(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); @@ -1957,8 +1945,8 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ DEBUG_VALIDATE_BUG_ON(p->tcph == NULL); - SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"", - ssn, stream, p, p->payload_len); + SCLogDebug( + "ssn %p, stream %p, p %p, p->payload_len %" PRIu16 "", ssn, stream, p, p->payload_len); /* default IDS: update opposing side (triggered by ACK) */ enum StreamUpdateDir dir = UPDATE_DIR_OPPOSING; @@ -2019,7 +2007,7 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ SCReturnInt(-1); } - SCLogDebug("packet %"PRIu64" set PKT_STREAM_ADD", p->pcap_cnt); + SCLogDebug("packet %" PRIu64 " set PKT_STREAM_ADD", p->pcap_cnt); p->flags |= PKT_STREAM_ADD; } else { SCLogDebug("ssn %p / stream %p: not calling StreamTcpReassembleHandleSegmentHandleData:" @@ -2034,13 +2022,12 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ * logic, to inform the applayer no more data in this direction is * to be expected. */ if ((stream->flags & - (STREAMTCP_STREAM_FLAG_DEPTH_REACHED|STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) == - STREAMTCP_STREAM_FLAG_DEPTH_REACHED) - { + (STREAMTCP_STREAM_FLAG_DEPTH_REACHED | STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) == + STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED, truncate applayer"); if (dir != UPDATE_DIR_PACKET) { SCLogDebug("override: direction now UPDATE_DIR_PACKET so we " - "can trigger Truncate"); + "can trigger Truncate"); dir = UPDATE_DIR_PACKET; } } @@ -2049,8 +2036,8 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ * functions to handle EOF */ if (dir == UPDATE_DIR_PACKET || dir == UPDATE_DIR_BOTH) { SCLogDebug("inline (%s) or PKT_PSEUDO_STREAM_END (%s)", - StreamTcpInlineMode()?"true":"false", - (p->flags & PKT_PSEUDO_STREAM_END) ?"true":"false"); + StreamTcpInlineMode() ? "true" : "false", + (p->flags & PKT_PSEUDO_STREAM_END) ? "true" : "false"); if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, dir) < 0) { SCReturnInt(-1); } @@ -2137,8 +2124,8 @@ void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint3 #ifdef UNITTESTS /** unit tests and it's support functions below */ -#define SET_ISN(stream, setseq) \ - (stream)->isn = (setseq); \ +#define SET_ISN(stream, setseq) \ + (stream)->isn = (setseq); \ (stream)->base_seq = (setseq) + 1 /** \brief The Function to create the packet with given payload, which is used @@ -2151,8 +2138,7 @@ void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint3 * \param len Length of the payload array */ -void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value, - uint8_t payload_len, uint8_t len) +void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value, uint8_t payload_len, uint8_t len) { uint8_t i; for (i = 0; i < payload_len; i++) @@ -2170,9 +2156,8 @@ void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value, int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream) { - if (StreamingBufferCompareRawData(&stream->sb, stream_policy,(uint32_t)sp_size) == 0) - { - //PrintRawDataFp(stdout, stream_policy, sp_size); + if (StreamingBufferCompareRawData(&stream->sb, stream_policy, (uint32_t)sp_size) == 0) { + // PrintRawDataFp(stdout, stream_policy, sp_size); return 0; } return 1; @@ -2180,9 +2165,7 @@ int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpSt static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len) { - if (StreamingBufferCompareRawData(&stream->sb, - data, data_len) == 0) - { + if (StreamingBufferCompareRawData(&stream->sb, data, data_len) == 0) { SCReturnInt(0); } SCLogInfo("OK"); @@ -2190,27 +2173,27 @@ static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len) return 1; } -#define MISSED_START(isn) \ - TcpReassemblyThreadCtx *ra_ctx = NULL; \ - TcpSession ssn; \ - ThreadVars tv; \ - memset(&tv, 0, sizeof(tv)); \ - \ - StreamTcpUTInit(&ra_ctx); \ - \ - StreamTcpUTSetupSession(&ssn); \ - StreamTcpUTSetupStream(&ssn.server, (isn)); \ - StreamTcpUTSetupStream(&ssn.client, (isn)); \ - \ +#define MISSED_START(isn) \ + TcpReassemblyThreadCtx *ra_ctx = NULL; \ + TcpSession ssn; \ + ThreadVars tv; \ + memset(&tv, 0, sizeof(tv)); \ + \ + StreamTcpUTInit(&ra_ctx); \ + \ + StreamTcpUTSetupSession(&ssn); \ + StreamTcpUTSetupStream(&ssn.server, (isn)); \ + StreamTcpUTSetupStream(&ssn.client, (isn)); \ + \ TcpStream *stream = &ssn.client; -#define MISSED_END \ - StreamTcpUTClearSession(&ssn); \ - StreamTcpUTDeinit(ra_ctx); \ +#define MISSED_END \ + StreamTcpUTClearSession(&ssn); \ + StreamTcpUTDeinit(ra_ctx); \ PASS -#define MISSED_STEP(seq, seg, seglen, buf, buflen) \ - StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)); \ +#define MISSED_STEP(seq, seg, seglen, buf, buflen) \ + StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)); \ FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen)))); #define MISSED_ADD_PAYLOAD(seq, seg, seglen) \ @@ -2277,7 +2260,7 @@ int UTHCheckDataAtPosition( * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest25 (void) +static int StreamTcpReassembleTest25(void) { MISSED_START(6); MISSED_ADD_PAYLOAD(10, "BB", 2); @@ -2298,7 +2281,7 @@ static int StreamTcpReassembleTest25 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest26 (void) +static int StreamTcpReassembleTest26(void) { MISSED_START(9); MISSED_STEP(10, "AAA", 3, "AAA", 3); @@ -2317,7 +2300,7 @@ static int StreamTcpReassembleTest26 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest27 (void) +static int StreamTcpReassembleTest27(void) { MISSED_START(9); MISSED_STEP(10, "AAA", 3, "AAA", 3); @@ -2334,7 +2317,7 @@ static int StreamTcpReassembleTest27 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest28 (void) +static int StreamTcpReassembleTest28(void) { MISSED_START(6); MISSED_ADD_PAYLOAD(10, "AAA", 3); @@ -2358,7 +2341,7 @@ static int StreamTcpReassembleTest28 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest29 (void) +static int StreamTcpReassembleTest29(void) { MISSED_START(9); MISSED_STEP(10, "AAA", 3, "AAA", 3); @@ -2384,10 +2367,10 @@ static int StreamTcpReassembleTest33(void) StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); - memset(&f, 0, sizeof (Flow)); - memset(&tcph, 0, sizeof (TCPHdr)); + memset(&f, 0, sizeof(Flow)); + memset(&tcph, 0, sizeof(TCPHdr)); ThreadVars tv; - memset(&tv, 0, sizeof (ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; f.proto = IPPROTO_TCP; @@ -2444,10 +2427,10 @@ static int StreamTcpReassembleTest34(void) StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupSession(&ssn); - memset(&f, 0, sizeof (Flow)); - memset(&tcph, 0, sizeof (TCPHdr)); + memset(&f, 0, sizeof(Flow)); + memset(&tcph, 0, sizeof(TCPHdr)); ThreadVars tv; - memset(&tv, 0, sizeof (ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); FLOW_INITIALIZE(&f); f.protoctx = &ssn; f.proto = IPPROTO_TCP; @@ -2500,7 +2483,7 @@ static int StreamTcpReassembleTest34(void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest39 (void) +static int StreamTcpReassembleTest39(void) { Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -2509,11 +2492,11 @@ static int StreamTcpReassembleTest39 (void) StreamTcpThread stt; TCPHdr tcph; PacketQueueNoLock pq; - memset(&pq,0,sizeof(PacketQueueNoLock)); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - memset(&stt, 0, sizeof (stt)); - memset(&tcph, 0, sizeof (TCPHdr)); + memset(&pq, 0, sizeof(PacketQueueNoLock)); + memset(&f, 0, sizeof(Flow)); + memset(&tv, 0, sizeof(ThreadVars)); + memset(&stt, 0, sizeof(stt)); + memset(&tcph, 0, sizeof(TCPHdr)); FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; @@ -2592,7 +2575,10 @@ static int StreamTcpReassembleTest39 (void) FAIL_IF(ssn->data_first_seen_dir != 0); /* partial request */ - uint8_t request1[] = { 0x47, 0x45, }; + uint8_t request1[] = { + 0x47, + 0x45, + }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2639,6 +2625,7 @@ static int StreamTcpReassembleTest39 (void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* complete partial request */ + // clang-format off uint8_t request2[] = { 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, @@ -2651,6 +2638,7 @@ static int StreamTcpReassembleTest39 (void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(3); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2675,6 +2663,7 @@ static int StreamTcpReassembleTest39 (void) FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ + // clang-format off uint8_t response[] = { 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, @@ -2717,6 +2706,7 @@ static int StreamTcpReassembleTest39 (void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + // clang-format on p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; @@ -2984,16 +2974,16 @@ static int StreamTcpReassembleTest39 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest40 (void) +static int StreamTcpReassembleTest40(void) { Packet *p = PacketGetFromAlloc(); FAIL_IF_NULL(p); Flow *f = NULL; TCPHdr tcph; TcpSession ssn; - memset(&tcph, 0, sizeof (TCPHdr)); + memset(&tcph, 0, sizeof(TCPHdr)); ThreadVars tv; - memset(&tv, 0, sizeof (ThreadVars)); + memset(&tv, 0, sizeof(ThreadVars)); StreamTcpInitConfig(true); StreamTcpUTSetupSession(&ssn); @@ -3027,7 +3017,7 @@ static int StreamTcpReassembleTest40 (void) tcph.th_win = htons(5480); tcph.th_seq = htonl(10); tcph.th_ack = htonl(10); - tcph.th_flags = TH_ACK|TH_PUSH; + tcph.th_flags = TH_ACK | TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = httpbuf1; @@ -3127,11 +3117,12 @@ static int StreamTcpReassembleTest44(void) StreamTcpInitConfig(true); uint32_t memuse = SC_ATOMIC_GET(ra_memuse); StreamTcpReassembleIncrMemuse(500); - FAIL_IF(SC_ATOMIC_GET(ra_memuse) != (memuse+500)); + FAIL_IF(SC_ATOMIC_GET(ra_memuse) != (memuse + 500)); StreamTcpReassembleDecrMemuse(500); FAIL_IF(SC_ATOMIC_GET(ra_memuse) != memuse); FAIL_IF(StreamTcpReassembleCheckMemcap(500) != 1); - FAIL_IF(StreamTcpReassembleCheckMemcap((1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) != 0); + FAIL_IF(StreamTcpReassembleCheckMemcap( + (1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) != 0); StreamTcpFreeConfig(true); FAIL_IF(SC_ATOMIC_GET(ra_memuse) != 0); PASS; @@ -3143,13 +3134,13 @@ static int StreamTcpReassembleTest44(void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest45 (void) +static int StreamTcpReassembleTest45(void) { TcpReassemblyThreadCtx *ra_ctx = NULL; TcpSession ssn; ThreadVars tv; memset(&tv, 0, sizeof(tv)); - uint8_t payload[100] = {0}; + uint8_t payload[100] = { 0 }; uint16_t payload_size = 100; StreamTcpUTInit(&ra_ctx); @@ -3181,14 +3172,14 @@ static int StreamTcpReassembleTest45 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest46 (void) +static int StreamTcpReassembleTest46(void) { int result = 0; TcpReassemblyThreadCtx *ra_ctx = NULL; TcpSession ssn; ThreadVars tv; memset(&tv, 0, sizeof(tv)); - uint8_t payload[100] = {0}; + uint8_t payload[100] = { 0 }; uint16_t payload_size = 100; StreamTcpUTInit(&ra_ctx); @@ -3230,7 +3221,7 @@ static int StreamTcpReassembleTest46 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpReassembleTest47 (void) +static int StreamTcpReassembleTest47(void) { Packet *p = PacketGetFromAlloc(); FAIL_IF(unlikely(p == NULL)); @@ -3238,8 +3229,8 @@ static int StreamTcpReassembleTest47 (void) TCPHdr tcph; TcpSession ssn; ThreadVars tv; - memset(&tcph, 0, sizeof (TCPHdr)); - memset(&tv, 0, sizeof (ThreadVars)); + memset(&tcph, 0, sizeof(TCPHdr)); + memset(&tv, 0, sizeof(ThreadVars)); StreamTcpInitConfig(true); StreamTcpUTSetupSession(&ssn); TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(&tv); @@ -3264,10 +3255,10 @@ static int StreamTcpReassembleTest47 (void) TcpStream *s = NULL; uint8_t cnt = 0; - for (cnt=0; cnt < httplen1; cnt++) { + for (cnt = 0; cnt < httplen1; cnt++) { tcph.th_seq = htonl(ssn.client.isn + 1 + cnt); tcph.th_ack = htonl(572799782UL); - tcph.th_flags = TH_ACK|TH_PUSH; + tcph.th_flags = TH_ACK | TH_PUSH; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; p->payload = &httpbuf1[cnt]; @@ -3324,11 +3315,11 @@ static int StreamTcpReassembleInlineTest01(void) p->tcph->th_seq = htonl(12); p->flow = &f; - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3374,11 +3365,11 @@ static int StreamTcpReassembleInlineTest02(void) p->tcph->th_seq = htonl(12); p->flow = &f; - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3433,11 +3424,11 @@ static int StreamTcpReassembleInlineTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3494,11 +3485,11 @@ static int StreamTcpReassembleInlineTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3551,8 +3542,8 @@ static int StreamTcpReassembleInlineTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1); - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1); FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1); ssn.client.next_seq = 17; FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1); @@ -3604,11 +3595,11 @@ static int StreamTcpReassembleInlineTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; } - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3682,7 +3673,7 @@ static int StreamTcpReassembleInlineTest10(void) p->flow = f; p->flowflags = FLOW_PKT_TOSERVER; - if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 2, stream_payload1, 2) == -1) { + if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 2, stream_payload1, 2) == -1) { printf("failed to add segment 1: "); goto end; } @@ -3695,16 +3686,16 @@ static int StreamTcpReassembleInlineTest10(void) } /* ssn.server.ra_app_base_seq should be isn here. */ - if (ssn.client.base_seq != 2 || ssn.client.base_seq != ssn.client.isn+1) { + if (ssn.client.base_seq != 2 || ssn.client.base_seq != ssn.client.isn + 1) { printf("expected ra_app_base_seq 1, got %u: ", ssn.client.base_seq); goto end; } - if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 4, stream_payload2, 3) == -1) { + if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 4, stream_payload2, 3) == -1) { printf("failed to add segment 2: "); goto end; } - if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 7, stream_payload3, 12) == -1) { + if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 7, stream_payload3, 12) == -1) { printf("failed to add segment 3: "); goto end; } @@ -3750,8 +3741,8 @@ static int StreamTcpReassembleInsertTest01(void) p->tcph->th_seq = htonl(12); p->flow = &f; - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1); - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1); FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1); FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1); FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1); @@ -3790,12 +3781,12 @@ static int StreamTcpReassembleInsertTest02(void) if (seq < 2) seq = 2; - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1) { printf("failed to add segment 1: "); goto end; } } - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3822,7 +3813,7 @@ static int StreamTcpReassembleInsertTest03(void) StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3838,7 +3829,7 @@ static int StreamTcpReassembleInsertTest03(void) if (seq < 2) seq = 2; - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1) { + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1) { printf("failed to add segment 2: "); goto end; } @@ -3860,55 +3851,48 @@ static int StreamTcpReassembleInsertTest03(void) void StreamTcpReassembleRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", - StreamTcpReassembleTest25); + UtRegisterTest( + "StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", StreamTcpReassembleTest25); UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test", - StreamTcpReassembleTest26); + StreamTcpReassembleTest26); UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test", - StreamTcpReassembleTest27); + StreamTcpReassembleTest27); UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", - StreamTcpReassembleTest28); + StreamTcpReassembleTest28); UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", - StreamTcpReassembleTest29); - UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", - StreamTcpReassembleTest33); - UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", - StreamTcpReassembleTest34); - UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", - StreamTcpReassembleTest39); - UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", - StreamTcpReassembleTest40); - UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", - StreamTcpReassembleTest44); - UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", - StreamTcpReassembleTest45); - UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", - StreamTcpReassembleTest46); - UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", - StreamTcpReassembleTest47); - - UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra", - StreamTcpReassembleInlineTest01); - UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2", - StreamTcpReassembleInlineTest02); - UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3", - StreamTcpReassembleInlineTest03); - UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4", - StreamTcpReassembleInlineTest04); + StreamTcpReassembleTest29); + UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", StreamTcpReassembleTest33); + UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", StreamTcpReassembleTest34); + UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", StreamTcpReassembleTest39); + UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", StreamTcpReassembleTest40); + UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44); + UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", StreamTcpReassembleTest45); + UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", StreamTcpReassembleTest46); + UtRegisterTest( + "StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", StreamTcpReassembleTest47); + + UtRegisterTest( + "StreamTcpReassembleInlineTest01 -- inline RAW ra", StreamTcpReassembleInlineTest01); + UtRegisterTest( + "StreamTcpReassembleInlineTest02 -- inline RAW ra 2", StreamTcpReassembleInlineTest02); + UtRegisterTest( + "StreamTcpReassembleInlineTest03 -- inline RAW ra 3", StreamTcpReassembleInlineTest03); + UtRegisterTest( + "StreamTcpReassembleInlineTest04 -- inline RAW ra 4", StreamTcpReassembleInlineTest04); UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", - StreamTcpReassembleInlineTest08); + StreamTcpReassembleInlineTest08); UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", - StreamTcpReassembleInlineTest09); + StreamTcpReassembleInlineTest09); - UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", - StreamTcpReassembleInlineTest10); + UtRegisterTest( + "StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10); UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", - StreamTcpReassembleInsertTest01); + StreamTcpReassembleInsertTest01); UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", - StreamTcpReassembleInsertTest02); + StreamTcpReassembleInsertTest02); UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", - StreamTcpReassembleInsertTest03); + StreamTcpReassembleInsertTest03); StreamTcpInlineRegisterTests(); StreamTcpUtilRegisterTests(); diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index 6f761fc0b4e4..32526d0e58dd 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -30,8 +30,7 @@ #include "stream-tcp-private.h" /** Supported OS list and default OS policy is BSD */ -enum -{ +enum { OS_POLICY_NONE = 1, OS_POLICY_BSD, OS_POLICY_BSD_RIGHT, @@ -82,7 +81,7 @@ typedef struct TcpReassemblyThreadCtx_ { uint16_t counter_tcp_reass_data_overlap_fail; } TcpReassemblyThreadCtx; -#define OS_POLICY_DEFAULT OS_POLICY_BSD +#define OS_POLICY_DEFAULT OS_POLICY_BSD void StreamTcpReassembleInitMemuse(void); int StreamTcpReassembleHandleSegment( @@ -93,9 +92,8 @@ void *StreamTcpReassembleRealloc(void *optr, size_t orig_size, size_t size); void StreamTcpReassembleRegisterTests(void); TcpReassemblyThreadCtx *StreamTcpReassembleInitThreadCtx(ThreadVars *tv); void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *); -int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p, enum StreamUpdateDir dir); +int StreamTcpReassembleAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, + TcpStream *stream, Packet *p, enum StreamUpdateDir dir); void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t); @@ -107,7 +105,8 @@ void StreamTcpSetOSPolicy(TcpStream *, Packet *); int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p); -int StreamTcpReassembleInsertSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, Packet *, uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen); +int StreamTcpReassembleInsertSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, + TcpSegment *, Packet *, uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen); TcpSegment *StreamTcpGetSegment(ThreadVars *, TcpReassemblyThreadCtx *); void StreamTcpReturnStreamSegments(TcpStream *); @@ -129,7 +128,7 @@ void StreamTcpDisableAppLayer(Flow *f); int StreamTcpAppLayerIsDisabled(Flow *f); #ifdef UNITTESTS -int StreamTcpCheckStreamContents(uint8_t *, uint16_t , TcpStream *); +int StreamTcpCheckStreamContents(uint8_t *, uint16_t, TcpStream *); #endif bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p); @@ -157,4 +156,3 @@ static inline bool STREAM_LASTACK_GT_BASESEQ(const TcpStream *stream) uint32_t StreamDataAvailableForProtoDetect(TcpStream *stream); #endif /* __STREAM_TCP_REASSEMBLE_H__ */ - diff --git a/src/stream-tcp-sack.c b/src/stream-tcp-sack.c index f97dfc4afdcd..2844e2fdea08 100644 --- a/src/stream-tcp-sack.c +++ b/src/stream-tcp-sack.c @@ -27,7 +27,7 @@ #include "stream-tcp.h" #include "stream-tcp-private.h" #include "stream-tcp-sack.h" -#include "util-unittest.h" +#include "util/unittest.h" RB_GENERATE(TCPSACK, StreamTcpSackRecord, rb, TcpSackCompare); @@ -51,7 +51,8 @@ static void StreamTcpSackPrintList(TcpStream *stream) { SCLogDebug("size %u", stream->sack_size); StreamTcpSackRecord *rec = NULL; - RB_FOREACH(rec, TCPSACK, &stream->sack_tree) { + RB_FOREACH(rec, TCPSACK, &stream->sack_tree) + { SCLogDebug("- record %8u - %8u", rec->le, rec->re); } } @@ -76,10 +77,11 @@ static inline void StreamTcpSackRecordFree(StreamTcpSackRecord *rec) StreamTcpDecrMemuse((uint64_t)sizeof(*rec)); } -static inline void ConsolidateFwd(TcpStream *stream, struct TCPSACK *tree, struct StreamTcpSackRecord *sa) +static inline void ConsolidateFwd( + TcpStream *stream, struct TCPSACK *tree, struct StreamTcpSackRecord *sa) { struct StreamTcpSackRecord *tr, *s = sa; - RB_FOREACH_FROM(tr, TCPSACK, s) { + RB_FOREACH_FROM (tr, TCPSACK, s) { if (sa == tr) continue; SCLogDebug("-> (fwd) tr %p %u/%u", tr, tr->le, tr->re); @@ -96,28 +98,28 @@ static inline void ConsolidateFwd(TcpStream *stream, struct TCPSACK *tree, struc SCLogDebug("-> (fwd) tr %p %u/%u REMOVED ECLIPSED2", tr, tr->le, tr->re); TCPSACK_RB_REMOVE(tree, tr); StreamTcpSackRecordFree(tr); - /* - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ + /* + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ } else if (SEQ_LEQ(sa->le, tr->le) && SEQ_GEQ(sa->re, tr->re)) { SCLogDebug("-> (fwd) tr %p %u/%u REMOVED ECLIPSED", tr, tr->le, tr->re); stream->sack_size -= (tr->re - tr->le); TCPSACK_RB_REMOVE(tree, tr); StreamTcpSackRecordFree(tr); - /* - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - } else if (SEQ_LT(sa->le, tr->le) && // starts before + /* + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + } else if (SEQ_LT(sa->le, tr->le) && // starts before SEQ_GEQ(sa->re, tr->le) && SEQ_LT(sa->re, tr->re) // ends inside - ) { + ) { // merge stream->sack_size -= (tr->re - tr->le); stream->sack_size -= (sa->re - sa->le); @@ -130,11 +132,11 @@ static inline void ConsolidateFwd(TcpStream *stream, struct TCPSACK *tree, struc } } -static inline void ConsolidateBackward(TcpStream *stream, - struct TCPSACK *tree, struct StreamTcpSackRecord *sa) +static inline void ConsolidateBackward( + TcpStream *stream, struct TCPSACK *tree, struct StreamTcpSackRecord *sa) { struct StreamTcpSackRecord *tr, *s = sa; - RB_FOREACH_REVERSE_FROM(tr, TCPSACK, s) { + RB_FOREACH_REVERSE_FROM (tr, TCPSACK, s) { if (sa == tr) continue; SCLogDebug("-> (bwd) tr %p %u/%u", tr, tr->le, tr->re); @@ -150,26 +152,26 @@ static inline void ConsolidateBackward(TcpStream *stream, SCLogDebug("-> (bwd) tr %p %u/%u REMOVED ECLIPSED2", tr, tr->le, tr->re); TCPSACK_RB_REMOVE(tree, tr); StreamTcpSackRecordFree(tr); - /* - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ + /* + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ } else if (SEQ_LEQ(sa->le, tr->le) && SEQ_GEQ(sa->re, tr->re)) { SCLogDebug("-> (bwd) tr %p %u/%u REMOVED ECLIPSED", tr, tr->le, tr->re); stream->sack_size -= (tr->re - tr->le); TCPSACK_RB_REMOVE(tree, tr); StreamTcpSackRecordFree(tr); - /* - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - } else if (SEQ_GT(sa->le, tr->le) && SEQ_GT(sa->re, tr->re) && SEQ_LEQ(sa->le,tr->re)) { + /* + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + } else if (SEQ_GT(sa->le, tr->le) && SEQ_GT(sa->re, tr->re) && SEQ_LEQ(sa->le, tr->re)) { // merge stream->sack_size -= (tr->re - tr->le); stream->sack_size -= (sa->re - sa->le); @@ -295,8 +297,7 @@ int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p) } if (SEQ_GT(re, stream->next_win)) { - SCLogDebug("record %u:%u beyond next_win %u", - le, re, stream->next_win); + SCLogDebug("record %u:%u beyond next_win %u", le, re, stream->next_win); goto next; } @@ -403,7 +404,7 @@ void StreamTcpSackPruneList(TcpStream *stream) SCEnter(); StreamTcpSackRecord *rec = NULL, *safe = NULL; - RB_FOREACH_SAFE(rec, TCPSACK, &stream->sack_tree, safe) { + RB_FOREACH_SAFE (rec, TCPSACK, &stream->sack_tree, safe) { if (SEQ_LT(rec->re, stream->last_ack)) { SCLogDebug("removing le %u re %u", rec->le, rec->re); stream->sack_size -= (rec->re - rec->le); @@ -438,7 +439,7 @@ void StreamTcpSackFreeList(TcpStream *stream) SCEnter(); StreamTcpSackRecord *rec = NULL, *safe = NULL; - RB_FOREACH_SAFE(rec, TCPSACK, &stream->sack_tree, safe) { + RB_FOREACH_SAFE (rec, TCPSACK, &stream->sack_tree, safe) { stream->sack_size -= (rec->re - rec->le); TCPSACK_RB_REMOVE(&stream->sack_tree, rec); StreamTcpSackRecordFree(rec); @@ -447,7 +448,6 @@ void StreamTcpSackFreeList(TcpStream *stream) SCReturn; } - #ifdef UNITTESTS /** @@ -456,7 +456,7 @@ void StreamTcpSackFreeList(TcpStream *stream) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest01 (void) +static int StreamTcpSackTest01(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); @@ -491,7 +491,7 @@ static int StreamTcpSackTest01 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest02 (void) +static int StreamTcpSackTest02(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); @@ -520,14 +520,14 @@ static int StreamTcpSackTest02 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest03 (void) +static int StreamTcpSackTest03(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.window = 100; StreamTcpSackInsertRange(&stream, 10, 20); - StreamTcpSackInsertRange(&stream, 5, 15); + StreamTcpSackInsertRange(&stream, 5, 15); #ifdef DEBUG StreamTcpSackPrintList(&stream); #endif /* DEBUG */ @@ -553,13 +553,13 @@ static int StreamTcpSackTest03 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest04 (void) +static int StreamTcpSackTest04(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.window = 100; - StreamTcpSackInsertRange(&stream, 0, 20); + StreamTcpSackInsertRange(&stream, 0, 20); StreamTcpSackInsertRange(&stream, 30, 50); StreamTcpSackInsertRange(&stream, 10, 25); #ifdef DEBUG @@ -583,13 +583,13 @@ static int StreamTcpSackTest04 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest05 (void) +static int StreamTcpSackTest05(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.window = 100; - StreamTcpSackInsertRange(&stream, 0, 20); + StreamTcpSackInsertRange(&stream, 0, 20); StreamTcpSackInsertRange(&stream, 30, 50); StreamTcpSackInsertRange(&stream, 10, 35); #ifdef DEBUG @@ -613,13 +613,13 @@ static int StreamTcpSackTest05 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest06 (void) +static int StreamTcpSackTest06(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.window = 100; - StreamTcpSackInsertRange(&stream, 0, 9); + StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); @@ -645,13 +645,13 @@ static int StreamTcpSackTest06 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest07 (void) +static int StreamTcpSackTest07(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.window = 100; - StreamTcpSackInsertRange(&stream, 0, 9); + StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); @@ -680,13 +680,13 @@ static int StreamTcpSackTest07 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest08 (void) +static int StreamTcpSackTest08(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.window = 100; - StreamTcpSackInsertRange(&stream, 0, 9); + StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); @@ -715,13 +715,13 @@ static int StreamTcpSackTest08 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest09 (void) +static int StreamTcpSackTest09(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.window = 100; - StreamTcpSackInsertRange(&stream, 0, 9); + StreamTcpSackInsertRange(&stream, 0, 9); StreamTcpSackInsertRange(&stream, 11, 19); StreamTcpSackInsertRange(&stream, 21, 29); StreamTcpSackInsertRange(&stream, 31, 39); @@ -751,7 +751,7 @@ static int StreamTcpSackTest09 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest10 (void) +static int StreamTcpSackTest10(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); @@ -786,7 +786,7 @@ static int StreamTcpSackTest10 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest11 (void) +static int StreamTcpSackTest11(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); @@ -821,7 +821,7 @@ static int StreamTcpSackTest11 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest12 (void) +static int StreamTcpSackTest12(void) { TcpStream stream; memset(&stream, 0, sizeof(stream)); @@ -859,14 +859,15 @@ static int StreamTcpSackTest12 (void) * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest13 (void) { +static int StreamTcpSackTest13(void) +{ TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.last_ack = 10000; stream.window = 2000; for (int i = 0; i < 10; i++) { - StreamTcpSackInsertRange(&stream, 100+(20*i), 110+(20*i)); + StreamTcpSackInsertRange(&stream, 100 + (20 * i), 110 + (20 * i)); } #ifdef DEBUG StreamTcpSackPrintList(&stream); @@ -884,14 +885,15 @@ static int StreamTcpSackTest13 (void) { * \retval On success it returns 1 and on failure 0. */ -static int StreamTcpSackTest14 (void) { +static int StreamTcpSackTest14(void) +{ TcpStream stream; memset(&stream, 0, sizeof(stream)); stream.last_ack = 1000; stream.window = 2000; for (int i = 0; i < 10; i++) { - StreamTcpSackInsertRange(&stream, 4000+(20*i), 4010+(20*i)); + StreamTcpSackInsertRange(&stream, 4000 + (20 * i), 4010 + (20 * i)); } #ifdef DEBUG StreamTcpSackPrintList(&stream); @@ -905,7 +907,7 @@ static int StreamTcpSackTest14 (void) { #endif /* UNITTESTS */ -void StreamTcpSackRegisterTests (void) +void StreamTcpSackRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpSackTest01 -- Insertion", StreamTcpSackTest01); @@ -918,13 +920,9 @@ void StreamTcpSackRegisterTests (void) UtRegisterTest("StreamTcpSackTest08 -- Pruning", StreamTcpSackTest08); UtRegisterTest("StreamTcpSackTest09 -- Pruning", StreamTcpSackTest09); UtRegisterTest("StreamTcpSackTest10 -- Pruning", StreamTcpSackTest10); - UtRegisterTest("StreamTcpSackTest11 -- Insertion && Pruning", - StreamTcpSackTest11); - UtRegisterTest("StreamTcpSackTest12 -- Insertion && Pruning", - StreamTcpSackTest12); - UtRegisterTest("StreamTcpSackTest13 -- Insertion out of window", - StreamTcpSackTest13); - UtRegisterTest("StreamTcpSackTest14 -- Insertion out of window", - StreamTcpSackTest14); + UtRegisterTest("StreamTcpSackTest11 -- Insertion && Pruning", StreamTcpSackTest11); + UtRegisterTest("StreamTcpSackTest12 -- Insertion && Pruning", StreamTcpSackTest12); + UtRegisterTest("StreamTcpSackTest13 -- Insertion out of window", StreamTcpSackTest13); + UtRegisterTest("StreamTcpSackTest14 -- Insertion out of window", StreamTcpSackTest14); #endif } diff --git a/src/stream-tcp-sack.h b/src/stream-tcp-sack.h index 84e7cb1bdfe3..18902a1f2447 100644 --- a/src/stream-tcp-sack.h +++ b/src/stream-tcp-sack.h @@ -42,6 +42,6 @@ int StreamTcpSackUpdatePacket(TcpStream *, Packet *); bool StreamTcpSackPacketIsOutdated(TcpStream *stream, Packet *p); void StreamTcpSackPruneList(TcpStream *); void StreamTcpSackFreeList(TcpStream *); -void StreamTcpSackRegisterTests (void); +void StreamTcpSackRegisterTests(void); #endif /* __STREAM_TCP_SACK_H__*/ diff --git a/src/stream-tcp-util.c b/src/stream-tcp-util.c index 4d8bf8a89313..368a9e7ec6cf 100644 --- a/src/stream-tcp-util.c +++ b/src/stream-tcp-util.c @@ -30,11 +30,11 @@ #include "stream-tcp.h" #include "stream-tcp-util.h" -#include "util-memcmp.h" -#include "util-print.h" +#include "util/memcmp.h" +#include "util/print.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "ippair.h" #ifdef UNITTESTS @@ -55,7 +55,8 @@ void StreamTcpUTDeinit(TcpReassemblyThreadCtx *ra_ctx) stream_config.flags &= ~STREAMTCP_INIT_FLAG_INLINE; } -void StreamTcpUTInitInline(void) { +void StreamTcpUTInitInline(void) +{ stream_config.flags |= STREAMTCP_INIT_FLAG_INLINE; } @@ -82,7 +83,7 @@ void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn) s->isn = isn; STREAMTCP_SET_RA_BASE_SEQ(s, isn); - s->base_seq = isn+1; + s->base_seq = isn + 1; StreamingBuffer x = STREAMING_BUFFER_INITIALIZER; s->sb = x; @@ -94,7 +95,8 @@ void StreamTcpUTClearStream(TcpStream *s) } /** \brief wrapper for StreamTcpReassembleHandleSegmentHandleData */ -int StreamTcpUTAddPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len) +int StreamTcpUTAddPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, + TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len) { Packet *p = UTHBuildPacketReal(payload, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); if (p == NULL) { @@ -110,7 +112,8 @@ int StreamTcpUTAddPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSes return 0; } -int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len) +int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len) { TcpSegment *s = StreamTcpGetSegment(tv, ra_ctx); if (s == NULL) { @@ -126,14 +129,16 @@ int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ } p->tcph->th_seq = htonl(seq); - if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0) + if (StreamTcpReassembleInsertSegment( + tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0) return -1; UTHFreePacket(p); return 0; } -int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t byte, uint16_t len) +int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, + uint32_t seq, uint8_t byte, uint16_t len) { TcpSegment *s = StreamTcpGetSegment(tv, ra_ctx); if (s == NULL) { @@ -151,7 +156,8 @@ int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx } p->tcph->th_seq = htonl(seq); - if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0) + if (StreamTcpReassembleInsertSegment( + tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0) return -1; UTHFreePacket(p); return 0; @@ -177,7 +183,6 @@ static int StreamTcpUtilTest01(void) return ret; } - static int StreamTcpUtilStreamTest01(void) { TcpReassemblyThreadCtx *ra_ctx = NULL; @@ -188,8 +193,8 @@ static int StreamTcpUtilStreamTest01(void) StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupStream(&stream, 1); - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1); - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1); FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1); TcpSegment *seg = RB_MIN(TCPSEG, &stream.seg_tree); @@ -219,9 +224,9 @@ static int StreamTcpUtilStreamTest02(void) StreamTcpUTInit(&ra_ctx); StreamTcpUTSetupStream(&stream, 1); - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1); FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1); - FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1); + FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1); TcpSegment *seg = RB_MIN(TCPSEG, &stream.seg_tree); FAIL_IF_NULL(seg); @@ -250,4 +255,3 @@ void StreamTcpUtilRegisterTests(void) UtRegisterTest("StreamTcpUtilStreamTest02", StreamTcpUtilStreamTest02); #endif /* UNITTESTS */ } - diff --git a/src/stream-tcp-util.h b/src/stream-tcp-util.h index fe05537e33ef..97a3f4d61209 100644 --- a/src/stream-tcp-util.h +++ b/src/stream-tcp-util.h @@ -38,11 +38,13 @@ void StreamTcpUTClearSession(TcpSession *); void StreamTcpUTSetupStream(TcpStream *, uint32_t isn); void StreamTcpUTClearStream(TcpStream *); -int StreamTcpUTAddSegmentWithByte(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, uint32_t, uint8_t, uint16_t); -int StreamTcpUTAddSegmentWithPayload(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, uint32_t, uint8_t *, uint16_t); -int StreamTcpUTAddPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len); +int StreamTcpUTAddSegmentWithByte( + ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, uint32_t, uint8_t, uint16_t); +int StreamTcpUTAddSegmentWithPayload( + ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, uint32_t, uint8_t *, uint16_t); +int StreamTcpUTAddPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, + TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len); void StreamTcpUtilRegisterTests(void); #endif /* __STREAM_TCP_UTIL_H__ */ - diff --git a/src/stream-tcp.c b/src/stream-tcp.c index b77423161800..f52677738217 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -42,13 +42,13 @@ #include "threadvars.h" #include "tm-threads.h" -#include "util-pool.h" -#include "util-pool-thread.h" -#include "util-checksum.h" -#include "util-unittest.h" -#include "util-print.h" -#include "util-debug.h" -#include "util-device.h" +#include "util/pool.h" +#include "util/pool-thread.h" +#include "util/checksum.h" +#include "util/unittest.h" +#include "util/print.h" +#include "util/debug.h" +#include "util/device.h" #include "stream-tcp-private.h" #include "stream-tcp.h" @@ -65,40 +65,40 @@ #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-protos.h" -#include "app-layer-htp-mem.h" - -#include "util-host-os-info.h" -#include "util-privs.h" -#include "util-profiling.h" -#include "util-misc.h" -#include "util-validate.h" -#include "util-runmodes.h" -#include "util-random.h" -#include "util-exception-policy.h" -#include "util-time.h" +#include "app-layer/http/parser-mem.h" + +#include "util/host-os-info.h" +#include "util/privs.h" +#include "util/profiling.h" +#include "util/misc.h" +#include "util/validate.h" +#include "util/runmodes.h" +#include "util/random.h" +#include "util/exception-policy.h" +#include "util/time.h" #include "source-pcap-file.h" #include "action-globals.h" -//#define DEBUG +// #define DEBUG -#define STREAMTCP_DEFAULT_PREALLOC 2048 -#define STREAMTCP_DEFAULT_MEMCAP (64 * 1024 * 1024) /* 64mb */ -#define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (256 * 1024 * 1024) /* 256mb */ -#define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560 -#define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560 -#define STREAMTCP_DEFAULT_MAX_SYN_QUEUED 10 -#define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5 +#define STREAMTCP_DEFAULT_PREALLOC 2048 +#define STREAMTCP_DEFAULT_MEMCAP (64 * 1024 * 1024) /* 64mb */ +#define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (256 * 1024 * 1024) /* 256mb */ +#define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560 +#define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560 +#define STREAMTCP_DEFAULT_MAX_SYN_QUEUED 10 +#define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5 static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *); -void StreamTcpReturnStreamSegments (TcpStream *); +void StreamTcpReturnStreamSegments(TcpStream *); void StreamTcpInitConfig(bool); int StreamTcpGetFlowState(void *); -void StreamTcpSetOSPolicy(TcpStream*, Packet*); +void StreamTcpSetOSPolicy(TcpStream *, Packet *); -static int StreamTcpValidateTimestamp(TcpSession * , Packet *); -static int StreamTcpHandleTimestamp(TcpSession * , Packet *); -static int StreamTcpValidateRst(TcpSession * , Packet *); +static int StreamTcpValidateTimestamp(TcpSession *, Packet *); +static int StreamTcpHandleTimestamp(TcpSession *, Packet *); +static int StreamTcpValidateRst(TcpSession *, Packet *); static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *); static int StreamTcpStateDispatch( ThreadVars *tv, Packet *p, StreamTcpThread *stt, TcpSession *ssn, const uint8_t state); @@ -107,7 +107,8 @@ extern thread_local uint64_t t_pcapcnt; extern int g_detect_disabled; PoolThread *ssn_pool = NULL; -static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */ +static SCMutex ssn_pool_mutex = + SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */ #ifdef DEBUG static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */ #endif @@ -123,8 +124,8 @@ void StreamTcpInitMemuse(void) void StreamTcpIncrMemuse(uint64_t size) { - (void) SC_ATOMIC_ADD(st_memuse, size); - SCLogDebug("STREAM %"PRIu64", incr %"PRIu64, StreamTcpMemuseCounter(), size); + (void)SC_ATOMIC_ADD(st_memuse, size); + SCLogDebug("STREAM %" PRIu64 ", incr %" PRIu64, StreamTcpMemuseCounter(), size); return; } @@ -137,7 +138,7 @@ void StreamTcpDecrMemuse(uint64_t size) } #endif - (void) SC_ATOMIC_SUB(st_memuse, size); + (void)SC_ATOMIC_SUB(st_memuse, size); #if defined(DEBUG_VALIDATION) && defined(UNITTESTS) if (RunmodeIsUnittests()) { @@ -145,7 +146,7 @@ void StreamTcpDecrMemuse(uint64_t size) BUG_ON(postsize > presize); } #endif - SCLogDebug("STREAM %"PRIu64", decr %"PRIu64, StreamTcpMemuseCounter(), size); + SCLogDebug("STREAM %" PRIu64 ", decr %" PRIu64, StreamTcpMemuseCounter(), size); return; } @@ -275,7 +276,7 @@ void StreamTcpSessionClear(void *ssnptr) * * \param p Packet used to identify the stream. */ -void StreamTcpSessionPktFree (Packet *p) +void StreamTcpSessionPktFree(Packet *p) { SCEnter(); @@ -306,7 +307,7 @@ static void *StreamTcpSessionPoolAlloc(void) return ptr; } -static int StreamTcpSessionPoolInit(void *data, void* initdata) +static int StreamTcpSessionPoolInit(void *data, void *initdata) { memset(data, 0, sizeof(TcpSession)); StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession)); @@ -332,8 +333,8 @@ static void StreamTcpSessionPoolCleanup(void *s) */ static inline bool StreamTcpInlineDropInvalid(void) { - return ((stream_config.flags & STREAMTCP_INIT_FLAG_INLINE) - && (stream_config.flags & STREAMTCP_INIT_FLAG_DROP_INVALID)); + return ((stream_config.flags & STREAMTCP_INIT_FLAG_INLINE) && + (stream_config.flags & STREAMTCP_INIT_FLAG_DROP_INVALID)); } /* hack: stream random range code expects random values in range of 0-RAND_MAX, @@ -345,7 +346,7 @@ static int RandomGetWrap(void) do { r = RandomGet(); - } while(r >= ULONG_MAX - (ULONG_MAX % RAND_MAX)); + } while (r >= ULONG_MAX - (ULONG_MAX % RAND_MAX)); return r % RAND_MAX; } @@ -363,7 +364,7 @@ void StreamTcpInitConfig(bool quiet) SCLogDebug("Initializing Stream"); - memset(&stream_config, 0, sizeof(stream_config)); + memset(&stream_config, 0, sizeof(stream_config)); SC_ATOMIC_INIT(stream_config.memcap); SC_ATOMIC_INIT(stream_config.reassembly_memcap); @@ -382,14 +383,13 @@ void StreamTcpInitConfig(bool quiet) } else { stream_config.prealloc_sessions = STREAMTCP_DEFAULT_PREALLOC; if (ConfGetNode("stream.prealloc-sessions") != NULL) { - WarnInvalidConfEntry("stream.prealloc_sessions", - "%"PRIu32, - stream_config.prealloc_sessions); + WarnInvalidConfEntry( + "stream.prealloc_sessions", "%" PRIu32, stream_config.prealloc_sessions); } } } if (!quiet) { - SCLogConfig("stream \"prealloc-sessions\": %"PRIu32" (per thread)", + SCLogConfig("stream \"prealloc-sessions\": %" PRIu32 " (per thread)", stream_config.prealloc_sessions); } @@ -409,7 +409,7 @@ void StreamTcpInitConfig(bool quiet) } if (!quiet) { - SCLogConfig("stream \"memcap\": %"PRIu64, SC_ATOMIC_GET(stream_config.memcap)); + SCLogConfig("stream \"memcap\": %" PRIu64, SC_ATOMIC_GET(stream_config.memcap)); } int imidstream; @@ -417,7 +417,8 @@ void StreamTcpInitConfig(bool quiet) stream_config.midstream = imidstream != 0; if (!quiet) { - SCLogConfig("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled"); + SCLogConfig("stream \"midstream\" session pickups: %s", + stream_config.midstream ? "enabled" : "disabled"); } int async_oneside; @@ -425,7 +426,8 @@ void StreamTcpInitConfig(bool quiet) stream_config.async_oneside = async_oneside != 0; if (!quiet) { - SCLogConfig("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled"); + SCLogConfig("stream \"async-oneside\": %s", + stream_config.async_oneside ? "enabled" : "disabled"); } int csum = 0; @@ -434,15 +436,15 @@ void StreamTcpInitConfig(bool quiet) if (csum == 1) { stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION; } - /* Default is that we validate the checksum of all the packets */ + /* Default is that we validate the checksum of all the packets */ } else { stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION; } if (!quiet) { SCLogConfig("stream \"checksum-validation\": %s", - stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION ? - "enabled" : "disabled"); + stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION ? "enabled" + : "disabled"); } const char *temp_stream_inline_str; @@ -473,8 +475,7 @@ void StreamTcpInitConfig(bool quiet) if (!quiet) { SCLogConfig("stream.\"inline\": %s", - stream_config.flags & STREAMTCP_INIT_FLAG_INLINE - ? "enabled" : "disabled"); + stream_config.flags & STREAMTCP_INIT_FLAG_INLINE ? "enabled" : "disabled"); } int bypass = 0; @@ -486,8 +487,7 @@ void StreamTcpInitConfig(bool quiet) if (!quiet) { SCLogConfig("stream \"bypass\": %s", - (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS) - ? "enabled" : "disabled"); + (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS) ? "enabled" : "disabled"); } int drop_invalid = 0; @@ -522,14 +522,14 @@ void StreamTcpInitConfig(bool quiet) stream_config.max_synack_queued = (uint8_t)STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED; } if (!quiet) { - SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued); + SCLogConfig("stream \"max-synack-queued\": %" PRIu8, stream_config.max_synack_queued); } const char *temp_stream_reassembly_memcap_str; if (ConfGet("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) { uint64_t stream_reassembly_memcap_copy; - if (ParseSizeStringU64(temp_stream_reassembly_memcap_str, - &stream_reassembly_memcap_copy) < 0) { + if (ParseSizeStringU64(temp_stream_reassembly_memcap_str, &stream_reassembly_memcap_copy) < + 0) { SCLogError("Error parsing " "stream.reassembly.memcap " "from conf file - %s. Killing engine", @@ -539,18 +539,18 @@ void StreamTcpInitConfig(bool quiet) SC_ATOMIC_SET(stream_config.reassembly_memcap, stream_reassembly_memcap_copy); } } else { - SC_ATOMIC_SET(stream_config.reassembly_memcap , STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP); + SC_ATOMIC_SET(stream_config.reassembly_memcap, STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP); } if (!quiet) { - SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"", - SC_ATOMIC_GET(stream_config.reassembly_memcap)); + SCLogConfig("stream.reassembly \"memcap\": %" PRIu64 "", + SC_ATOMIC_GET(stream_config.reassembly_memcap)); } const char *temp_stream_reassembly_depth_str; if (ConfGet("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) { - if (ParseSizeStringU32(temp_stream_reassembly_depth_str, - &stream_config.reassembly_depth) < 0) { + if (ParseSizeStringU32(temp_stream_reassembly_depth_str, &stream_config.reassembly_depth) < + 0) { SCLogError("Error parsing " "stream.reassembly.depth " "from conf file - %s. Killing engine", @@ -562,7 +562,7 @@ void StreamTcpInitConfig(bool quiet) } if (!quiet) { - SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth); + SCLogConfig("stream.reassembly \"depth\": %" PRIu32 "", stream_config.reassembly_depth); } int randomize = 0; @@ -593,7 +593,7 @@ void StreamTcpInitConfig(bool quiet) if (ConfGet("stream.reassembly.toserver-chunk-size", &temp_stream_reassembly_toserver_chunk_size_str) == 1) { if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str, - &stream_config.reassembly_toserver_chunk_size) < 0) { + &stream_config.reassembly_toserver_chunk_size) < 0) { SCLogError("Error parsing " "stream.reassembly.toserver-chunk-size " "from conf file - %s. Killing engine", @@ -601,8 +601,7 @@ void StreamTcpInitConfig(bool quiet) exit(EXIT_FAILURE); } } else { - stream_config.reassembly_toserver_chunk_size = - STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE; + stream_config.reassembly_toserver_chunk_size = STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE; } if (randomize) { @@ -615,7 +614,7 @@ void StreamTcpInitConfig(bool quiet) if (ConfGet("stream.reassembly.toclient-chunk-size", &temp_stream_reassembly_toclient_chunk_size_str) == 1) { if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str, - &stream_config.reassembly_toclient_chunk_size) < 0) { + &stream_config.reassembly_toclient_chunk_size) < 0) { SCLogError("Error parsing " "stream.reassembly.toclient-chunk-size " "from conf file - %s. Killing engine", @@ -623,8 +622,7 @@ void StreamTcpInitConfig(bool quiet) exit(EXIT_FAILURE); } } else { - stream_config.reassembly_toclient_chunk_size = - STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE; + stream_config.reassembly_toclient_chunk_size = STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE; } if (randomize) { @@ -634,10 +632,10 @@ void StreamTcpInitConfig(bool quiet) rdrange / 100); } if (!quiet) { - SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16, - stream_config.reassembly_toserver_chunk_size); - SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16, - stream_config.reassembly_toclient_chunk_size); + SCLogConfig("stream.reassembly \"toserver-chunk-size\": %" PRIu16, + stream_config.reassembly_toserver_chunk_size); + SCLogConfig("stream.reassembly \"toclient-chunk-size\": %" PRIu16, + stream_config.reassembly_toclient_chunk_size); } int enable_raw = 1; @@ -675,12 +673,9 @@ void StreamTcpInitConfig(bool quiet) SCMutexLock(&ssn_pool_mutex); if (ssn_pool == NULL) { ssn_pool = PoolThreadInit(1, /* thread */ - 0, /* unlimited */ - stream_config.prealloc_sessions, - sizeof(TcpSession), - StreamTcpSessionPoolAlloc, - StreamTcpSessionPoolInit, NULL, - StreamTcpSessionPoolCleanup, NULL); + 0, /* unlimited */ + stream_config.prealloc_sessions, sizeof(TcpSession), StreamTcpSessionPoolAlloc, + StreamTcpSessionPoolInit, NULL, StreamTcpSessionPoolCleanup, NULL); } SCMutexUnlock(&ssn_pool_mutex); } @@ -699,7 +694,7 @@ void StreamTcpFreeConfig(bool quiet) SCMutexUnlock(&ssn_pool_mutex); SCMutexDestroy(&ssn_pool_mutex); - SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt); + SCLogDebug("ssn_pool_cnt %" PRIu64 "", ssn_pool_cnt); } /** \internal @@ -773,8 +768,7 @@ static TcpSession *StreamTcpNewSession(ThreadVars *tv, StreamTcpThread *stt, Pac return ssn; } -static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, - uint8_t state) +static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, uint8_t state) { if (state == ssn->state || PKT_IS_PSEUDOPKT(p)) return; @@ -784,7 +778,7 @@ static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_STATE_UPDATE); /* update the flow state */ - switch(ssn->state) { + switch (ssn->state) { case TCP_ESTABLISHED: case TCP_FIN_WAIT1: case TCP_FIN_WAIT2: @@ -835,8 +829,7 @@ void StreamTcpSetOSPolicy(TcpStream *stream, Packet *p) else if (stream->os_policy == OS_POLICY_OLD_SOLARIS) stream->os_policy = OS_POLICY_SOLARIS; - SCLogDebug("Policy is %"PRIu8"", stream->os_policy); - + SCLogDebug("Policy is %" PRIu8 "", stream->os_policy); } /** @@ -846,39 +839,45 @@ void StreamTcpSetOSPolicy(TcpStream *stream, Packet *p) * \param stream stream to update * \param ack ACK value to test and set */ -#define StreamTcpUpdateLastAck(ssn, stream, ack) { \ - if (SEQ_GT((ack), (stream)->last_ack)) \ - { \ - SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \ - if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \ - SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \ - } else { \ - SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \ - }\ - (stream)->last_ack = (ack); \ - StreamTcpSackPruneList((stream)); \ - } else { \ - SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \ - (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \ - }\ -} - -#define StreamTcpAsyncLastAckUpdate(ssn, stream) { \ - if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \ - if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \ - uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \ - (stream)->last_ack += ack_diff; \ - SCLogDebug("ssn %p: ASYNC last_ack set to %"PRIu32", moved %u forward", \ - (ssn), (stream)->next_seq, ack_diff); \ - } \ - } \ -} - -#define StreamTcpUpdateNextSeq(ssn, stream, seq) { \ - (stream)->next_seq = seq; \ - SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \ - StreamTcpAsyncLastAckUpdate((ssn), (stream)); \ -} +#define StreamTcpUpdateLastAck(ssn, stream, ack) \ + { \ + if (SEQ_GT((ack), (stream)->last_ack)) { \ + SCLogDebug("ssn %p: last_ack set to %" PRIu32 ", moved %u forward", (ssn), (ack), \ + (ack) - (stream)->last_ack); \ + if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && \ + SEQ_GT((ack), (stream)->next_seq))) { \ + SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), \ + (stream)->last_ack, (stream)->next_seq); \ + } else { \ + SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, \ + (int)(stream)->next_seq - (ack)); \ + } \ + (stream)->last_ack = (ack); \ + StreamTcpSackPruneList((stream)); \ + } else { \ + SCLogDebug("ssn %p: no update: ack %u, last_ack %" PRIu32 ", next_seq %u (state %u)", \ + (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \ + } \ + } + +#define StreamTcpAsyncLastAckUpdate(ssn, stream) \ + { \ + if ((ssn)->flags & STREAMTCP_FLAG_ASYNC) { \ + if (SEQ_GT((stream)->next_seq, (stream)->last_ack)) { \ + uint32_t ack_diff = (stream)->next_seq - (stream)->last_ack; \ + (stream)->last_ack += ack_diff; \ + SCLogDebug("ssn %p: ASYNC last_ack set to %" PRIu32 ", moved %u forward", (ssn), \ + (stream)->next_seq, ack_diff); \ + } \ + } \ + } + +#define StreamTcpUpdateNextSeq(ssn, stream, seq) \ + { \ + (stream)->next_seq = seq; \ + SCLogDebug("ssn %p: next_seq %" PRIu32, (ssn), (stream)->next_seq); \ + StreamTcpAsyncLastAckUpdate((ssn), (stream)); \ + } /** * \brief macro to update next_win only if the new value is higher @@ -887,20 +886,22 @@ void StreamTcpSetOSPolicy(TcpStream *stream, Packet *p) * \param stream stream to update * \param win window value to test and set */ -#define StreamTcpUpdateNextWin(ssn, stream, win) { \ - uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \ - if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \ - (stream)->next_win = ((win) + sacked_size__); \ - SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \ - } \ -} +#define StreamTcpUpdateNextWin(ssn, stream, win) \ + { \ + uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \ + if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \ + (stream)->next_win = ((win) + sacked_size__); \ + SCLogDebug("ssn %p: next_win set to %" PRIu32, (ssn), (stream)->next_win); \ + } \ + } static inline void StreamTcpCloseSsnWithReset(Packet *p, TcpSession *ssn) { ssn->flags |= STREAMTCP_FLAG_CLOSED_BY_RST; StreamTcpPacketSetState(p, ssn, TCP_CLOSED); SCLogDebug("ssn %p: (state: %s) Reset received and state changed to " - "TCP_CLOSED", ssn, StreamTcpStateAsString(ssn->state)); + "TCP_CLOSED", + ssn, StreamTcpStateAsString(ssn->state)); } static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p) @@ -909,8 +910,8 @@ static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p) SCReturnInt(0); /* retransmission of already partially ack'd data */ - if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) - { + if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && + SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) { StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION); SCReturnInt(1); } @@ -1083,7 +1084,8 @@ static int StreamTcpPacketStateNone( /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); SCLogDebug("ssn %p: =~ midstream picked ssn state is now " - "TCP_SYN_RECV", ssn); + "TCP_SYN_RECV", + ssn); ssn->flags |= STREAMTCP_FLAG_MIDSTREAM; /* Flag used to change the direct in the later stage in the session */ ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_SYNACK; @@ -1114,27 +1116,25 @@ static int StreamTcpPacketStateNone( if (TCP_HAS_WSCALE(p)) { ssn->client.wscale = TCP_GET_WSCALE(p); ssn->server.wscale = TCP_WSCALE_MAX; - SCLogDebug("ssn %p: wscale enabled. client %u server %u", - ssn, ssn->client.wscale, ssn->server.wscale); + SCLogDebug("ssn %p: wscale enabled. client %u server %u", ssn, ssn->client.wscale, + ssn->server.wscale); } - SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq" - " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn, - ssn->client.isn, ssn->client.next_seq, - ssn->client.last_ack); - SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq" - " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn, - ssn->server.isn, ssn->server.next_seq, - ssn->server.last_ack); + SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", ssn->client.next_seq" + " %" PRIu32 ", ssn->client.last_ack %" PRIu32 "", + ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack); + SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", ssn->server.next_seq" + " %" PRIu32 ", ssn->server.last_ack %" PRIu32 "", + ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack); /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ if (TCP_HAS_TS(p)) { ssn->server.last_ts = TCP_GET_TSVAL(p); ssn->client.last_ts = TCP_GET_TSECR(p); - SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " - "ssn->client.last_ts %" PRIu32"", ssn, - ssn->server.last_ts, ssn->client.last_ts); + SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " " + "ssn->client.last_ts %" PRIu32 "", + ssn, ssn->server.last_ts, ssn->client.last_ts); ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; @@ -1152,7 +1152,8 @@ static int StreamTcpPacketStateNone( if (TCP_GET_SACKOK(p) == 1) { ssn->flags |= STREAMTCP_FLAG_SACKOK; SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming " - "SACK permitted for both sides", ssn); + "SACK permitted for both sides", + ssn); } return 0; @@ -1211,15 +1212,16 @@ static int StreamTcpPacketStateNone( if (p->payload_len) { StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len)); SCLogDebug("ssn: %p (TFO) [len: %d] isn %u base_seq %u next_seq %u payload len %u", - ssn, p->tcpvars.tfo.len, ssn->client.isn, ssn->client.base_seq, ssn->client.next_seq, p->payload_len); + ssn, p->tcpvars.tfo.len, ssn->client.isn, ssn->client.base_seq, + ssn->client.next_seq, p->payload_len); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); } } SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", " - "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack " - "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq, - ssn->client.last_ack); + "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack " + "%" PRIu32 "", + ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack); } else if (p->tcph->th_flags & TH_ACK) { /* Drop reason will only be used if midstream policy is set to fail closed */ @@ -1249,7 +1251,8 @@ static int StreamTcpPacketStateNone( /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); SCLogDebug("ssn %p: =~ midstream picked ssn state is now " - "TCP_ESTABLISHED", ssn); + "TCP_ESTABLISHED", + ssn); ssn->flags = STREAMTCP_FLAG_MIDSTREAM; ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED; @@ -1270,8 +1273,8 @@ static int StreamTcpPacketStateNone( ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; ssn->client.last_ack = TCP_GET_SEQ(p); ssn->client.next_win = ssn->client.last_ack + ssn->client.window; - SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", - ssn, ssn->client.isn, ssn->client.next_seq); + SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", ssn, ssn->client.isn, + ssn->client.next_seq); ssn->server.isn = TCP_GET_ACK(p) - 1; STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn); @@ -1279,21 +1282,21 @@ static int StreamTcpPacketStateNone( ssn->server.last_ack = TCP_GET_ACK(p); ssn->server.next_win = ssn->server.last_ack; - SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", " - "ssn->server.next_win %"PRIu32"", ssn, - ssn->client.next_win, ssn->server.next_win); - SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", " - "ssn->server.last_ack %"PRIu32"", ssn, - ssn->client.last_ack, ssn->server.last_ack); + SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", " + "ssn->server.next_win %" PRIu32 "", + ssn, ssn->client.next_win, ssn->server.next_win); + SCLogDebug("ssn %p: ssn->client.last_ack %" PRIu32 ", " + "ssn->server.last_ack %" PRIu32 "", + ssn, ssn->client.last_ack, ssn->server.last_ack); /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ if (TCP_HAS_TS(p)) { ssn->client.last_ts = TCP_GET_TSVAL(p); ssn->server.last_ts = TCP_GET_TSECR(p); - SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " - "ssn->client.last_ts %" PRIu32"", ssn, - ssn->server.last_ts, ssn->client.last_ts); + SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " " + "ssn->client.last_ts %" PRIu32 "", + ssn, ssn->server.last_ts, ssn->client.last_ts); ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; @@ -1357,12 +1360,8 @@ static TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p StreamTcp3whsSynAckToStateQueue(p, &search); while (q != NULL) { - if (search.flags == q->flags && - search.wscale == q->wscale && - search.win == q->win && - search.seq == q->seq && - search.ack == q->ack && - search.ts == q->ts) { + if (search.flags == q->flags && search.wscale == q->wscale && search.win == q->win && + search.seq == q->seq && search.ack == q->ack && search.ts == q->ts) { return q; } @@ -1415,8 +1414,7 @@ static TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p) TcpStateQueue *q = ssn->queue; while (q != NULL) { - if (seq == q->seq && - ack == q->ack) { + if (seq == q->seq && ack == q->ack) { return q; } @@ -1464,12 +1462,11 @@ static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue /* Set the timestamp values used to validate the timestamp of * received packets.*/ if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) && - (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) - { + (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) { ssn->server.last_ts = q->ts; - SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " - "ssn->client.last_ts %" PRIu32"", ssn, - ssn->server.last_ts, ssn->client.last_ts); + SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32 " " + "ssn->client.last_ts %" PRIu32 "", + ssn, ssn->server.last_ts, ssn->client.last_ts); ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; ssn->server.last_pkt_ts = q->pkt_ts; if (ssn->server.last_ts == 0) @@ -1485,16 +1482,13 @@ static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue /** check for the presence of the ws ptr to determine if we * support wscale at all */ - if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && - (q->flags & STREAMTCP_QUEUE_FLAG_WS)) - { + if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && (q->flags & STREAMTCP_QUEUE_FLAG_WS)) { ssn->client.wscale = q->wscale; } else { ssn->client.wscale = 0; } - if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) && - (q->flags & STREAMTCP_QUEUE_FLAG_SACK)) { + if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) && (q->flags & STREAMTCP_QUEUE_FLAG_SACK)) { ssn->flags |= STREAMTCP_FLAG_SACKOK; SCLogDebug("ssn %p: SACK permitted for session", ssn); } else { @@ -1503,24 +1497,22 @@ static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue ssn->server.next_win = ssn->server.last_ack + ssn->server.window; ssn->client.next_win = ssn->client.last_ack + ssn->client.window; - SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn, - ssn->server.next_win); - SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn, - ssn->client.next_win); + SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn, ssn->server.next_win); + SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn, ssn->client.next_win); SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", " - "ssn->server.next_seq %" PRIu32 ", " - "ssn->server.last_ack %" PRIu32 " " - "(ssn->client.last_ack %" PRIu32 ")", ssn, - ssn->server.isn, ssn->server.next_seq, - ssn->server.last_ack, ssn->client.last_ack); + "ssn->server.next_seq %" PRIu32 ", " + "ssn->server.last_ack %" PRIu32 " " + "(ssn->client.last_ack %" PRIu32 ")", + ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack, ssn->client.last_ack); /* unset the 4WHS flag as we received this SYN/ACK as part of a * (so far) valid 3WHS */ if (ssn->flags & STREAMTCP_FLAG_4WHS) SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK" - " so considering 3WHS", ssn); + " so considering 3WHS", + ssn); - ssn->flags &=~ STREAMTCP_FLAG_4WHS; + ssn->flags &= ~STREAMTCP_FLAG_4WHS; } /** \internal @@ -1539,17 +1531,13 @@ static inline bool StateSynSentValidateTimestamp(TcpSession *ssn, Packet *p) TcpStream *receiver_stream = &ssn->client; const uint32_t ts_echo = TCP_GET_TSECR(p); if ((receiver_stream->flags & STREAMTCP_STREAM_FLAG_TIMESTAMP) != 0) { - if (receiver_stream->last_ts != 0 && ts_echo != 0 && - ts_echo != receiver_stream->last_ts) - { - SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn, - ts_echo, receiver_stream->last_ts); + if (receiver_stream->last_ts != 0 && ts_echo != 0 && ts_echo != receiver_stream->last_ts) { + SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn, ts_echo, receiver_stream->last_ts); return false; } } else { if (receiver_stream->last_ts == 0 && ts_echo != 0) { - SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn, - ts_echo, receiver_stream->last_ts); + SCLogDebug("ssn %p: BAD TSECR echo %u recv %u", ssn, ts_echo, receiver_stream->last_ts); return false; } } @@ -1750,8 +1738,8 @@ static int StreamTcpPacketStateSynSent( if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) { StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK); SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), - ssn->client.isn + 1); + "%" PRIu32 " from stream", + ssn, TCP_GET_ACK(p), ssn->client.isn + 1); return -1; } } else { @@ -1770,8 +1758,8 @@ static int StreamTcpPacketStateSynSent( } else { StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK); SCLogDebug("ssn %p: (TFO) ACK mismatch, packet ACK %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), - ssn->client.next_seq); + "%" PRIu32 " from stream", + ssn, TCP_GET_ACK(p), ssn->client.next_seq); return -1; } ssn->flags |= STREAMTCP_FLAG_TCP_FAST_OPEN; @@ -1807,7 +1795,7 @@ static int StreamTcpPacketStateSynSent( /* clear ssn->queue on state change: TcpSession can be reused by SYN/ACK */ StreamTcp3wsFreeQueue(ssn); - StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL); + StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */ NULL); return 0; } else if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK) && PKT_IS_TOSERVER(p)) { @@ -1937,7 +1925,8 @@ static int StreamTcpPacketStateSynSent( SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn); if (ssn->flags & STREAMTCP_FLAG_4WHS) { SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of " - "4WHS SYN", ssn); + "4WHS SYN", + ssn); } if (PKT_IS_TOCLIENT(p)) { @@ -1987,15 +1976,13 @@ static int StreamTcpPacketStateSynSent( } SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", " - "ssn->server.next_seq %" PRIu32 ", " - "ssn->server.last_ack %"PRIu32"", ssn, - ssn->server.isn, ssn->server.next_seq, - ssn->server.last_ack); + "ssn->server.next_seq %" PRIu32 ", " + "ssn->server.last_ack %" PRIu32 "", + ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack); SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", " - "ssn->client.next_seq %" PRIu32 ", " - "ssn->client.last_ack %"PRIu32"", ssn, - ssn->client.isn, ssn->client.next_seq, - ssn->client.last_ack); + "ssn->client.next_seq %" PRIu32 ", " + "ssn->client.last_ack %" PRIu32 "", + ssn, ssn->client.isn, ssn->client.next_seq, ssn->client.last_ack); } else if (PKT_IS_TOSERVER(p)) { /* on a SYN resend we queue up the SYN's until a SYN/ACK moves the state * to SYN_RECV. We update the ssn to the most recent, as it is most likely @@ -2029,8 +2016,8 @@ static int StreamTcpPacketStateSynSent( StreamTcpSetEvent(p, STREAM_3WHS_ASYNC_WRONG_SEQ); SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " - "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p), - ssn->client.next_seq); + "%" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } @@ -2051,10 +2038,10 @@ static int StreamTcpPacketStateSynSent( ssn->server.next_win = ssn->server.last_ack; SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ" - " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " - "ssn->client.next_seq %" PRIu32 "" - ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) - + p->payload_len, ssn->client.next_seq); + " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " + "ssn->client.next_seq %" PRIu32 "", + ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, + ssn->client.next_seq); /* if SYN had wscale, assume it to be supported. Otherwise * we know it not to be supported. */ @@ -2064,9 +2051,7 @@ static int StreamTcpPacketStateSynSent( /* Set the timestamp values used to validate the timestamp of * received packets.*/ - if (TCP_HAS_TS(p) && - (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) - { + if (TCP_HAS_TS(p) && (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) { ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_TIMESTAMP; ssn->client.last_pkt_ts = SCTIME_SECS(p->ts); @@ -2121,20 +2106,18 @@ static int StreamTcpPacketStateSynRecv( if (PKT_IS_TOSERVER(p)) { if ((ssn->server.os_policy == OS_POLICY_LINUX) || (ssn->server.os_policy == OS_POLICY_OLD_LINUX) || - (ssn->server.os_policy == OS_POLICY_SOLARIS)) - { + (ssn->server.os_policy == OS_POLICY_SOLARIS)) { reset = false; SCLogDebug("Detection evasion has been attempted, so" - " not resetting the connection !!"); + " not resetting the connection !!"); } } else { if ((ssn->client.os_policy == OS_POLICY_LINUX) || (ssn->client.os_policy == OS_POLICY_OLD_LINUX) || - (ssn->client.os_policy == OS_POLICY_SOLARIS)) - { + (ssn->client.os_policy == OS_POLICY_SOLARIS)) { reset = false; SCLogDebug("Detection evasion has been attempted, so" - " not resetting the connection !!"); + " not resetting the connection !!"); } } } @@ -2157,8 +2140,8 @@ static int StreamTcpPacketStateSynRecv( if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1) return -1; - /* SYN/ACK */ - } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { + /* SYN/ACK */ + } else if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn); if (PKT_IS_TOSERVER(p)) { @@ -2172,8 +2155,8 @@ static int StreamTcpPacketStateSynRecv( * received SYN/ACK packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) { SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), - ssn->client.isn + 1); + "%" PRIu32 " from stream", + ssn, TCP_GET_ACK(p), ssn->client.isn + 1); StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK); return -1; @@ -2183,8 +2166,8 @@ static int StreamTcpPacketStateSynRecv( * received SYN/ACK packet, server resend with different ISN. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) { SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), - ssn->client.isn); + "%" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.isn); if (StreamTcp3whsQueueSynAck(ssn, p) == -1) return -1; @@ -2214,13 +2197,13 @@ static int StreamTcpPacketStateSynRecv( TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p); if (q != NULL) { SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn); - StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q); + StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */ q); } else { - SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn); + SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", + ssn); } } - /* If the timestamp option is enabled for both the streams, then * validate the received packet timestamp value against the * stream->last_ts. If the timestamp is valid then process the @@ -2232,7 +2215,7 @@ static int StreamTcpPacketStateSynRecv( } if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) { - SCLogDebug("ssn %p: ACK received on 4WHS session",ssn); + SCLogDebug("ssn %p: ACK received on 4WHS session", ssn); if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) { SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn); @@ -2248,8 +2231,8 @@ static int StreamTcpPacketStateSynRecv( SCLogDebug("4WHS normal pkt"); SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -2266,8 +2249,8 @@ static int StreamTcpPacketStateSynRecv( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", " - "ssn->client.last_ack %"PRIu32"", ssn, - ssn->client.next_win, ssn->client.last_ack); + "ssn->client.last_ack %" PRIu32 "", + ssn, ssn->client.next_win, ssn->client.last_ack); return 0; } @@ -2282,10 +2265,11 @@ static int StreamTcpPacketStateSynRecv( * direction */ if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) { SCLogDebug("ssn %p: ACK received on midstream SYN/ACK " - "pickup session",ssn); + "pickup session", + ssn); /* fall through */ } else if (ssn->flags & STREAMTCP_FLAG_TCP_FAST_OPEN) { - SCLogDebug("ssn %p: ACK received on TFO session",ssn); + SCLogDebug("ssn %p: ACK received on TFO session", ssn); /* fall through */ } else { @@ -2299,8 +2283,7 @@ static int StreamTcpPacketStateSynRecv( * careful. */ if (StreamTcpInlineMode()) { - if (p->payload_len > 0 && - SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) && + if (p->payload_len > 0 && SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) && SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { /* packet loss is possible but unlikely here */ SCLogDebug("ssn %p: possible data injection", ssn); @@ -2308,8 +2291,7 @@ static int StreamTcpPacketStateSynRecv( return -1; } - SCLogDebug("ssn %p: ACK received in the wrong direction", - ssn); + SCLogDebug("ssn %p: ACK received in the wrong direction", ssn); StreamTcpSetEvent(p, STREAM_3WHS_ACK_IN_WRONG_DIR); return -1; } @@ -2318,8 +2300,8 @@ static int StreamTcpPacketStateSynRecv( } SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 "" - ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), - TCP_GET_ACK(p)); + ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); /* Check both seq and ack number before accepting the packet and changing to ESTABLISHED state */ @@ -2342,8 +2324,7 @@ static int StreamTcpPacketStateSynRecv( if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) { ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; ssn->client.next_win = ssn->client.last_ack + ssn->client.window; - ssn->server.next_win = ssn->server.last_ack + - ssn->server.window; + ssn->server.next_win = ssn->server.last_ack + ssn->server.window; if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) { /* window scaling for midstream pickups, we can't do much * other than assume that it's set to the max value: 14 */ @@ -2385,10 +2366,10 @@ static int StreamTcpPacketStateSynRecv( } SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ" - " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " - "ssn->server.next_seq %" PRIu32 - , ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) - + p->payload_len, ssn->server.next_seq); + " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " + "ssn->server.next_seq %" PRIu32, + ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, + ssn->server.next_seq); StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn); @@ -2400,8 +2381,7 @@ static int StreamTcpPacketStateSynRecv( likely to avoid the detection */ } else if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { ssn->flags |= STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT; - SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!", - ssn); + SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!", ssn); StreamTcpSetEvent(p, STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION); return -1; @@ -2447,14 +2427,14 @@ static int StreamTcpPacketStateSynRecv( ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); - SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq); + SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, + ssn->client.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) { ssn->client.window = TCP_GET_WINDOW(p); - ssn->server.next_win = ssn->server.last_ack + - ssn->server.window; + ssn->server.next_win = ssn->server.last_ack + ssn->server.window; /* window scaling for midstream pickups, we can't do much * other than assume that it's set to the max value: 14 */ ssn->server.wscale = TCP_WSCALE_MAX; @@ -2496,8 +2476,8 @@ static int StreamTcpPacketStateSynRecv( } SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", " - "ssn->server.last_ack %"PRIu32"", ssn, - ssn->server.next_win, ssn->server.last_ack); + "ssn->server.last_ack %" PRIu32 "", + ssn, ssn->server.next_win, ssn->server.last_ack); } else { SCLogDebug("ssn %p: default case", ssn); } @@ -2522,8 +2502,8 @@ static int HandleEstablishedPacketToServer( ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt) { SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 "," - "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); + "ACK %" PRIu32 ", WIN %" PRIu16 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); const bool has_ack = (p->tcph->th_flags & TH_ACK) != 0; if (has_ack) { @@ -2543,8 +2523,8 @@ static int HandleEstablishedPacketToServer( (TCP_GET_SEQ(p) == (ssn->client.next_seq - 1))) { SCLogDebug("ssn %p: pkt is keep alive", ssn); - /* normal pkt */ - } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) { + /* normal pkt */ + } else if (!(SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) { if (ssn->flags & STREAMTCP_FLAG_ASYNC) { SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," @@ -2561,10 +2541,10 @@ static int HandleEstablishedPacketToServer( } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p)) && stream_config.async_oneside && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ." - " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " - "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " - "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), - p->payload_len, TCP_GET_SEQ(p) + p->payload_len, + " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " + "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " + "%" PRIu32 "(%" PRIu32 ")", + ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); @@ -2577,10 +2557,10 @@ static int HandleEstablishedPacketToServer( } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) && stream_config.async_oneside && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ" - " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " - "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " - "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), - p->payload_len, TCP_GET_SEQ(p) + p->payload_len, + " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " + "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " + "%" PRIu32 "(%" PRIu32 ")", + ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); @@ -2590,9 +2570,9 @@ static int HandleEstablishedPacketToServer( StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p)); ssn->flags |= STREAMTCP_FLAG_ASYNC; - /* if last ack is beyond next_seq, we have accepted ack's for missing data. - * In this case we do accept the data before last_ack if it is (partly) - * beyond next seq */ + /* if last ack is beyond next_seq, we have accepted ack's for missing data. + * In this case we do accept the data before last_ack if it is (partly) + * beyond next seq */ } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), ssn->client.next_seq)) { SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16 @@ -2602,10 +2582,10 @@ static int HandleEstablishedPacketToServer( ssn->client.next_seq); } else { SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ" - " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " - "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " - "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), - p->payload_len, TCP_GET_SEQ(p) + p->payload_len, + " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " + "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " + "%" PRIu32 "(%" PRIu32 ")", + ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win); @@ -2632,14 +2612,13 @@ static int HandleEstablishedPacketToServer( if (zerowindowprobe) { SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn); } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) || - (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC))) - { - SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win " - "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win); + (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM | STREAMTCP_FLAG_ASYNC))) { + SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win " + "%" PRIu32 "", + ssn, TCP_GET_SEQ(p), ssn->client.next_win); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; - SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn, - ssn->server.window); + SCLogDebug("ssn %p: ssn->server.window %" PRIu32 "", ssn, ssn->server.window); /* Check if the ACK value is sane and inside the window limit */ if (p->tcph->th_flags & TH_ACK) { @@ -2651,7 +2630,8 @@ static int HandleEstablishedPacketToServer( } } - SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq); + SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, + ssn->server.next_seq); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -2667,10 +2647,10 @@ static int HandleEstablishedPacketToServer( } else { SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ " - "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," - "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " - "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), - p->payload_len, TCP_GET_SEQ(p) + p->payload_len, + "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," + "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win " + "%" PRIu32 "(%" PRIu32 ")", + ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win, (TCP_GET_SEQ(p) + p->payload_len) - ssn->client.next_win); SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window, @@ -2698,8 +2678,8 @@ static int HandleEstablishedPacketToClient( ThreadVars *tv, TcpSession *ssn, Packet *p, StreamTcpThread *stt) { SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 "," - " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); + " ACK %" PRIu32 ", WIN %" PRIu16 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p)); const bool has_ack = (p->tcph->th_flags & TH_ACK) != 0; if (has_ack) { @@ -2717,13 +2697,13 @@ static int HandleEstablishedPacketToClient( /* To get the server window value from the servers packet, when connection is picked up as midstream */ if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) && - (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED)) - { + (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED)) { ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; ssn->flags &= ~STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED; SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to " - "%" PRIu32 "", ssn, ssn->server.next_win); + "%" PRIu32 "", + ssn, ssn->server.next_win); } /* check for Keep Alive */ @@ -2731,8 +2711,8 @@ static int HandleEstablishedPacketToClient( (TCP_GET_SEQ(p) == (ssn->server.next_seq - 1))) { SCLogDebug("ssn %p: pkt is keep alive", ssn); - /* normal pkt */ - } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) { + /* normal pkt */ + } else if (!(SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) { if (ssn->flags & STREAMTCP_FLAG_ASYNC) { SCLogDebug("ssn %p: client => Asynchronous stream, packet SEQ" @@ -2745,21 +2725,21 @@ static int HandleEstablishedPacketToClient( ssn->server.last_ack = TCP_GET_SEQ(p); - /* if last ack is beyond next_seq, we have accepted ack's for missing data. - * In this case we do accept the data before last_ack if it is (partly) - * beyond next seq */ + /* if last ack is beyond next_seq, we have accepted ack's for missing data. + * In this case we do accept the data before last_ack if it is (partly) + * beyond next seq */ } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) && - SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->server.next_seq)) - { + SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), ssn->server.next_seq)) { SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16 " before last_ack %" PRIu32 ", after next_seq %" PRIu32 ":" " acked data that we haven't seen before", ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq); } else { - SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 - " before last_ack %"PRIu32". next_seq %"PRIu32, - ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq); + SCLogDebug("ssn %p: PKT SEQ %" PRIu32 " payload_len %" PRIu16 + " before last_ack %" PRIu32 ". next_seq %" PRIu32, + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, + ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK); return -1; } @@ -2783,13 +2763,12 @@ static int HandleEstablishedPacketToClient( if (zerowindowprobe) { SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn); } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) || - (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC))) - { - SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win " - "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win); + (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM | STREAMTCP_FLAG_ASYNC))) { + SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win " + "%" PRIu32 "", + ssn, TCP_GET_SEQ(p), ssn->server.next_win); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; - SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn, - ssn->client.window); + SCLogDebug("ssn %p: ssn->client.window %" PRIu32 "", ssn, ssn->client.window); if (p->tcph->th_flags & TH_ACK) { StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); @@ -2813,10 +2792,10 @@ static int HandleEstablishedPacketToClient( SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ" "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 ")," " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win " - "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p), - p->payload_len, TCP_GET_SEQ(p) + p->payload_len, - ssn->server.last_ack, ssn->server.next_win, - TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win); + "%" PRIu32 "(%" PRIu32 ")", + ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, + ssn->server.last_ack, ssn->server.next_win, + TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win); StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW); return -1; } @@ -3056,16 +3035,15 @@ static int StreamTcpPacketStateEstablished( ssn->server.next_seq = TCP_GET_ACK(p); ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; - SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, - ssn->server.next_seq); + SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -3073,8 +3051,8 @@ static int StreamTcpPacketStateEstablished( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); /* don't return packets to pools here just yet, the pseudo * packet will take care, otherwise the normal session @@ -3085,16 +3063,15 @@ static int StreamTcpPacketStateEstablished( ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1; ssn->client.next_seq = TCP_GET_ACK(p); - SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, - ssn->server.next_seq); + SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -3102,8 +3079,8 @@ static int StreamTcpPacketStateEstablished( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); /* don't return packets to pools here just yet, the pseudo * packet will take care, otherwise the normal session @@ -3117,18 +3094,17 @@ static int StreamTcpPacketStateEstablished( } SCLogDebug("ssn (%p: FIN received SEQ" - " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32"," - " win %" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack, ssn->server.next_win, + " %" PRIu32 ", last ACK %" PRIu32 ", next win %" PRIu32 "," + " win %" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack, ssn->server.next_win, ssn->server.window); if ((StreamTcpHandleFin(tv, stt, ssn, p)) == -1) return -1; - /* SYN/ACK */ - } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { - SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent", - ssn); + /* SYN/ACK */ + } else if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { + SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent", ssn); if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn); @@ -3141,8 +3117,8 @@ static int StreamTcpPacketStateEstablished( * received SYN/ACK packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) { SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), - ssn->client.isn + 1); + "%" PRIu32 " from stream", + ssn, TCP_GET_ACK(p), ssn->client.isn + 1); StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK); return -1; @@ -3152,8 +3128,8 @@ static int StreamTcpPacketStateEstablished( * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) { SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p), - ssn->client.isn + 1); + "%" PRIu32 " from stream", + ssn, TCP_GET_ACK(p), ssn->client.isn + 1); StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ); return -1; @@ -3166,7 +3142,8 @@ static int StreamTcpPacketStateEstablished( } SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. " - "Likely due server not receiving final ACK in 3whs", ssn); + "Likely due server not receiving final ACK in 3whs", + ssn); return 0; } else if (p->tcph->th_flags & TH_SYN) { @@ -3209,9 +3186,9 @@ static int StreamTcpPacketStateEstablished( HandleEstablishedPacketToServer(tv, ssn, p, stt); SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 "," - " next win %" PRIu32 ", win %" PRIu32 "", ssn, - ssn->client.next_seq, ssn->server.last_ack - ,ssn->client.next_win, ssn->client.window); + " next win %" PRIu32 ", win %" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack, ssn->client.next_win, + ssn->client.window); } else { /* implied to client */ if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) { @@ -3223,9 +3200,9 @@ static int StreamTcpPacketStateEstablished( HandleEstablishedPacketToClient(tv, ssn, p, stt); SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 "," - " next win %" PRIu32 ", win %" PRIu32 "", ssn, - ssn->server.next_seq, ssn->client.last_ack, - ssn->server.next_win, ssn->server.window); + " next win %" PRIu32 ", win %" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack, ssn->server.next_win, + ssn->server.window); } } else { SCLogDebug("ssn %p: default case", ssn); @@ -3250,8 +3227,8 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession * { if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 "," - " ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), - TCP_GET_ACK(p)); + " ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); @@ -3267,8 +3244,8 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession * // within expectations } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != " - "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p), - ssn->client.next_seq); + "%" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW); return -1; @@ -3285,8 +3262,7 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession * /* if we accept the FIN, next_seq needs to reflect the FIN */ ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; - SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, - ssn->client.next_seq); + SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { @@ -3303,12 +3279,12 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession * StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); - SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "", - ssn, ssn->client.next_seq, ssn->server.last_ack); + SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "", ssn, + ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", " - "ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p), - TCP_GET_ACK(p)); + "ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); @@ -3324,8 +3300,9 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession * // within expectations } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != " - "%" PRIu32 " from stream (last_ack %u win %u = %u)", ssn, TCP_GET_SEQ(p), - ssn->server.next_seq, ssn->server.last_ack, ssn->server.window, (ssn->server.last_ack + ssn->server.window)); + "%" PRIu32 " from stream (last_ack %u win %u = %u)", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq, ssn->server.last_ack, + ssn->server.window, (ssn->server.last_ack + ssn->server.window)); StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW); return -1; @@ -3354,8 +3331,8 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, TcpSession * StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); - SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "", - ssn, ssn->server.next_seq, ssn->client.last_ack); + SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "", ssn, + ssn->server.next_seq, ssn->client.last_ack); } return 0; @@ -3387,11 +3364,11 @@ static int StreamTcpPacketStateFinWait1( if (PKT_IS_TOSERVER(p)) { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -3400,11 +3377,11 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); } else { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -3413,7 +3390,7 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); } - } else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) { + } else if ((p->tcph->th_flags & (TH_FIN | TH_ACK)) == (TH_FIN | TH_ACK)) { if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { if (!StreamTcpValidateTimestamp(ssn, p)) return -1; @@ -3421,8 +3398,8 @@ static int StreamTcpPacketStateFinWait1( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { @@ -3433,8 +3410,8 @@ static int StreamTcpPacketStateFinWait1( } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq - 1) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } @@ -3470,12 +3447,12 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { @@ -3492,8 +3469,8 @@ static int StreamTcpPacketStateFinWait1( } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq - 1) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } @@ -3529,8 +3506,8 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_FIN) { @@ -3541,8 +3518,8 @@ static int StreamTcpPacketStateFinWait1( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { @@ -3553,8 +3530,8 @@ static int StreamTcpPacketStateFinWait1( } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq - 1) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } @@ -3591,12 +3568,12 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; @@ -3608,8 +3585,8 @@ static int StreamTcpPacketStateFinWait1( } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq - 1) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ); return -1; } @@ -3646,8 +3623,8 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_SYN) { SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn); @@ -3662,8 +3639,8 @@ static int StreamTcpPacketStateFinWait1( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { @@ -3730,14 +3707,14 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; @@ -3755,10 +3732,10 @@ static int StreamTcpPacketStateFinWait1( if (!retransmission) { if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) || - (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC))) - { - SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win " - "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win); + (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM | STREAMTCP_FLAG_ASYNC))) { + SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win " + "%" PRIu32 "", + ssn, TCP_GET_SEQ(p), ssn->server.next_win); if (TCP_GET_SEQ(p) == ssn->server.next_seq - 1) { StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2); @@ -3766,8 +3743,8 @@ static int StreamTcpPacketStateFinWait1( } } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ); return -1; } @@ -3798,8 +3775,8 @@ static int StreamTcpPacketStateFinWait1( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { SCLogDebug("ssn (%p): default case", ssn); @@ -3831,11 +3808,11 @@ static int StreamTcpPacketStateFinWait2( if (PKT_IS_TOSERVER(p)) { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -3844,11 +3821,11 @@ static int StreamTcpPacketStateFinWait2( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); } else { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -3865,12 +3842,12 @@ static int StreamTcpPacketStateFinWait2( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) && - SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) { + SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) { SCLogDebug("ssn %p: retransmission", ssn); retransmission = 1; STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_RETRANSMISSION); @@ -3880,11 +3857,10 @@ static int StreamTcpPacketStateFinWait2( STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_RETRANSMISSION); } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || - SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) - { + SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ " - "%" PRIu32 " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + "%" PRIu32 " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ); return -1; } @@ -3921,16 +3897,16 @@ static int StreamTcpPacketStateFinWait2( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) && - SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) { + SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) { SCLogDebug("ssn %p: retransmission", ssn); retransmission = 1; STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_RETRANSMISSION); @@ -3940,11 +3916,10 @@ static int StreamTcpPacketStateFinWait2( STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_RETRANSMISSION); } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || - SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) - { + SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ " - "%" PRIu32 " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + "%" PRIu32 " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ); return -1; } @@ -3976,8 +3951,8 @@ static int StreamTcpPacketStateFinWait2( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_SYN) { @@ -3993,8 +3968,8 @@ static int StreamTcpPacketStateFinWait2( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { @@ -4011,15 +3986,15 @@ static int StreamTcpPacketStateFinWait2( if (!retransmission) { if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) || - (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC))) - { - SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win " - "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win); + (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM | STREAMTCP_FLAG_ASYNC))) { + SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->client.next_win " + "%" PRIu32 "", + ssn, TCP_GET_SEQ(p), ssn->client.next_win); } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ); return -1; } @@ -4045,12 +4020,12 @@ static int StreamTcpPacketStateFinWait2( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { @@ -4067,14 +4042,14 @@ static int StreamTcpPacketStateFinWait2( if (!retransmission) { if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) || - (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM|STREAMTCP_FLAG_ASYNC))) - { - SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win " - "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win); + (ssn->flags & (STREAMTCP_FLAG_MIDSTREAM | STREAMTCP_FLAG_ASYNC))) { + SCLogDebug("ssn %p: seq %" PRIu32 " in window, ssn->server.next_win " + "%" PRIu32 "", + ssn, TCP_GET_SEQ(p), ssn->server.next_win); } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ); return -1; } @@ -4100,8 +4075,8 @@ static int StreamTcpPacketStateFinWait2( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { SCLogDebug("ssn %p: default case", ssn); @@ -4133,11 +4108,11 @@ static int StreamTcpPacketStateClosing( if (PKT_IS_TOSERVER(p)) { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4146,11 +4121,11 @@ static int StreamTcpPacketStateClosing( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); } else { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4172,8 +4147,8 @@ static int StreamTcpPacketStateClosing( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); @@ -4183,8 +4158,8 @@ static int StreamTcpPacketStateClosing( if (TCP_GET_SEQ(p) != ssn->client.next_seq) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ); return -1; } @@ -4214,12 +4189,12 @@ static int StreamTcpPacketStateClosing( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); @@ -4229,8 +4204,8 @@ static int StreamTcpPacketStateClosing( if (TCP_GET_SEQ(p) != ssn->server.next_seq) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ); return -1; } @@ -4261,8 +4236,8 @@ static int StreamTcpPacketStateClosing( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ " - "%" PRIu32 ", last ACK %" PRIu32 "", ssn, - ssn->server.next_seq, ssn->client.last_ack); + "%" PRIu32 ", last ACK %" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { SCLogDebug("ssn %p: default case", ssn); @@ -4290,12 +4265,12 @@ static int StreamTcpPacketStateCloseWait( if (PKT_IS_TOCLIENT(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); } if (p->tcph->th_flags & TH_RST) { @@ -4306,11 +4281,11 @@ static int StreamTcpPacketStateCloseWait( if (PKT_IS_TOSERVER(p)) { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4319,11 +4294,11 @@ static int StreamTcpPacketStateCloseWait( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); } else { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4340,8 +4315,8 @@ static int StreamTcpPacketStateCloseWait( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { @@ -4352,11 +4327,10 @@ static int StreamTcpPacketStateCloseWait( if (!retransmission) { if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || - SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) - { + SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW); SCReturnInt(-1); } @@ -4387,12 +4361,12 @@ static int StreamTcpPacketStateCloseWait( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { @@ -4403,11 +4377,10 @@ static int StreamTcpPacketStateCloseWait( if (!retransmission) { if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || - SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) - { + SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW); SCReturnInt(-1); } @@ -4440,8 +4413,8 @@ static int StreamTcpPacketStateCloseWait( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else if (p->tcph->th_flags & TH_SYN) { @@ -4457,8 +4430,8 @@ static int StreamTcpPacketStateCloseWait( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { @@ -4467,16 +4440,16 @@ static int StreamTcpPacketStateCloseWait( STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_RETRANSMISSION); } - if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) { + if (p->payload_len > 0 && + (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) { SCLogDebug("ssn %p: -> retransmission", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK); SCReturnInt(-1); - } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) - { + } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW); SCReturnInt(-1); } @@ -4500,19 +4473,19 @@ static int StreamTcpPacketStateCloseWait( if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) ssn->server.next_seq = TCP_GET_ACK(p); - if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) + if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) StreamTcpUpdateNextSeq(ssn, &ssn->client, (ssn->client.next_seq + p->payload_len)); StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); @@ -4520,16 +4493,16 @@ static int StreamTcpPacketStateCloseWait( STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_RETRANSMISSION); } - if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) { + if (p->payload_len > 0 && + (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) { SCLogDebug("ssn %p: -> retransmission", ssn); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK); SCReturnInt(-1); - } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) - { + } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW); SCReturnInt(-1); } @@ -4553,15 +4526,15 @@ static int StreamTcpPacketStateCloseWait( if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) ssn->client.next_seq = TCP_GET_ACK(p); - if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) + if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) StreamTcpUpdateNextSeq(ssn, &ssn->server, (ssn->server.next_seq + p->payload_len)); StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p)); StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { @@ -4593,11 +4566,11 @@ static int StreamTcpPacketStateLastAck( if (PKT_IS_TOSERVER(p)) { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4606,11 +4579,11 @@ static int StreamTcpPacketStateLastAck( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); } else { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4636,8 +4609,8 @@ static int StreamTcpPacketStateLastAck( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { @@ -4655,16 +4628,16 @@ static int StreamTcpPacketStateLastAck( if (!retransmission) { if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq)) { SCLogDebug("ssn %p: not updating state as packet is before next_seq", ssn); - } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq + 1) { + } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && + TCP_GET_SEQ(p) != ssn->client.next_seq + 1) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_LASTACK_ACK_WRONG_SEQ); return -1; } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn); - } ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; } @@ -4682,8 +4655,8 @@ static int StreamTcpPacketStateLastAck( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } } else { SCLogDebug("ssn %p: default case", ssn); @@ -4715,11 +4688,11 @@ static int StreamTcpPacketStateTimeWait( if (PKT_IS_TOSERVER(p)) { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4728,11 +4701,11 @@ static int StreamTcpPacketStateTimeWait( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); } else { if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); + StreamTcpUpdateLastAck( + ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); @@ -4757,18 +4730,19 @@ static int StreamTcpPacketStateTimeWait( if (PKT_IS_TOSERVER(p)) { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->client, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); retransmission = 1; STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_RETRANSMISSION); - } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq+1) { + } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && + TCP_GET_SEQ(p) != ssn->client.next_seq + 1) { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->client.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->client.next_seq); StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ); return -1; } @@ -4799,12 +4773,12 @@ static int StreamTcpPacketStateTimeWait( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->client.next_seq, - ssn->server.last_ack); + "%" PRIu32 "", + ssn, ssn->client.next_seq, ssn->server.last_ack); } else { SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ " - "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len, - TCP_GET_SEQ(p), TCP_GET_ACK(p)); + "%" PRIu32 ", ACK %" PRIu32 "", + ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); int retransmission = 0; if (StreamTcpPacketIsRetransmission(&ssn->server, p)) { SCLogDebug("ssn %p: packet is retransmission", ssn); @@ -4817,8 +4791,8 @@ static int StreamTcpPacketStateTimeWait( SCReturnInt(0); } else { SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 "" - " != %" PRIu32 " from stream", ssn, - TCP_GET_SEQ(p), ssn->server.next_seq); + " != %" PRIu32 " from stream", + ssn, TCP_GET_SEQ(p), ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ); return -1; } @@ -4850,8 +4824,8 @@ static int StreamTcpPacketStateTimeWait( StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p); SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK " - "%" PRIu32 "", ssn, ssn->server.next_seq, - ssn->client.last_ack); + "%" PRIu32 "", + ssn, ssn->server.next_seq, ssn->client.last_ack); } } else { @@ -4881,8 +4855,8 @@ static int StreamTcpPacketStateClosed( } SCLogDebug("stream %s ostream %s", - stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV?"true":"false", - ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true":"false"); + stream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true" : "false", + ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV ? "true" : "false"); /* if we've seen a RST on our direction, but not on the other * see if we perhaps need to continue processing anyway. */ @@ -4916,8 +4890,9 @@ static void StreamTcpPacketCheckPostRst(TcpSession *ssn, Packet *p) } if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) { - SCLogDebug("regular packet %"PRIu64" from same sender as " - "the previous RST. Looks like it injected!", p->pcap_cnt); + SCLogDebug("regular packet %" PRIu64 " from same sender as " + "the previous RST. Looks like it injected!", + p->pcap_cnt); ostream->flags &= ~STREAMTCP_STREAM_FLAG_RST_RECV; ssn->flags &= ~STREAMTCP_FLAG_CLOSED_BY_RST; StreamTcpSetEvent(p, STREAM_SUSPECTED_RST_INJECT); @@ -4944,7 +4919,7 @@ static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p) if (p->payload_len > 1) return 0; - if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) { + if ((p->tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) { return 0; } @@ -4960,12 +4935,12 @@ static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p) const uint32_t seq = TCP_GET_SEQ(p); const uint32_t ack = TCP_GET_ACK(p); if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) { - SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt); + SCLogDebug("packet is TCP keep-alive: %" PRIu64, p->pcap_cnt); stream->flags |= STREAMTCP_STREAM_FLAG_KEEPALIVE; STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_KEEPALIVE); return 1; } - SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack); + SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack); return 0; } @@ -4986,7 +4961,7 @@ static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p) if (p->payload_len > 0) return 0; - if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) + if ((p->tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) return 0; if (TCP_GET_WINDOW(p) == 0) @@ -5007,13 +4982,15 @@ static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p) if (pkt_win != ostream->window) return 0; - if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) { - SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt); + if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && + seq == stream->next_seq) { + SCLogDebug("packet is TCP keep-aliveACK: %" PRIu64, p->pcap_cnt); ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE; STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_KEEPALIVEACK); return 1; } - SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack, + SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, + ostream->last_ack, ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set"); return 0; } @@ -5057,7 +5034,7 @@ static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p) if (p->payload_len > 0) return 0; - if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) + if ((p->tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) return 0; if (TCP_GET_WINDOW(p) == 0) @@ -5079,7 +5056,7 @@ static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p) return 0; if (ack == ostream->last_ack && seq == stream->next_seq) { - SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt); + SCLogDebug("packet is TCP window update: %" PRIu64, p->pcap_cnt); STREAM_PKT_FLAG_SET(p, STREAM_PKT_FLAG_WINDOWUPDATE); return 1; } @@ -5099,7 +5076,8 @@ static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p) if (p->flags & PKT_PSEUDO_STREAM_END) return 0; - if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK)) + if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || + ssn->state == TCP_LAST_ACK)) return 0; if (p->tcph->th_flags != TH_ACK) return 0; @@ -5117,8 +5095,8 @@ static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p) seq = TCP_GET_SEQ(p); ack = TCP_GET_ACK(p); - SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u", - p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq); + SCLogDebug("%" PRIu64 ", seq %u ack %u stream->next_seq %u ostream->next_seq %u", p->pcap_cnt, + seq, ack, stream->next_seq, ostream->next_seq); if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) { return 1; @@ -5156,7 +5134,7 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED) return 0; - if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) + if ((p->tcph->th_flags & (TH_SYN | TH_FIN | TH_RST)) != 0) return 0; if (PKT_IS_TOSERVER(p)) { @@ -5174,15 +5152,14 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) if (pkt_win < ostream->window) { uint32_t diff = ostream->window - pkt_win; - if (diff > p->payload_len && - SEQ_GT(ack, ostream->next_seq) && - SEQ_GT(seq, stream->next_seq)) - { - SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u", - p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len); - SCLogDebug("%"PRIu64", pkt_win %u, stream win %u", - p->pcap_cnt, pkt_win, ostream->window); - SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)", + if (diff > p->payload_len && SEQ_GT(ack, ostream->next_seq) && + SEQ_GT(seq, stream->next_seq)) { + SCLogDebug("%" PRIu64 ", pkt_win %u, stream win %u, diff %u, dsize %u", p->pcap_cnt, + pkt_win, ostream->window, diff, p->payload_len); + SCLogDebug("%" PRIu64 ", pkt_win %u, stream win %u", p->pcap_cnt, pkt_win, + ostream->window); + SCLogDebug("%" PRIu64 ", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, " + "ostream->next_win %u, diff %u (%u)", p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win, ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack); @@ -5193,16 +5170,15 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) * are rather arbitrary. */ uint32_t adiff = ack - ostream->last_ack; if (((pkt_win > 1024) && (diff > (adiff + 32))) || - ((pkt_win <= 1024) && (diff > adiff))) - { + ((pkt_win <= 1024) && (diff > adiff))) { SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u " - "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win); + "(allowing 32 bytes extra): pkt WIN %u", + ack, adiff, ostream->last_ack, diff, pkt_win); SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state); StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE); return 1; } } - } SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack); return 0; @@ -5309,14 +5285,13 @@ static inline void HandleThreadId(ThreadVars *tv, Packet *p, StreamTcpThread *st } /* flow is and stays locked */ -int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, - PacketQueueNoLock *pq) +int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq) { SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(p->flow); - SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); + SCLogDebug("p->pcap_cnt %" PRIu64, p->pcap_cnt); TcpSession *ssn = (TcpSession *)p->flow->protoctx; @@ -5329,16 +5304,16 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, ssn->server.tcp_flags |= p->tcph->th_flags; /* check if we need to unset the ASYNC flag */ - if (ssn->flags & STREAMTCP_FLAG_ASYNC && - ssn->client.tcp_flags != 0 && - ssn->server.tcp_flags != 0) - { + if (ssn->flags & STREAMTCP_FLAG_ASYNC && ssn->client.tcp_flags != 0 && + ssn->server.tcp_flags != 0) { SCLogDebug("ssn %p: removing ASYNC flag as we have packets on both sides", ssn); ssn->flags &= ~STREAMTCP_FLAG_ASYNC; } } - /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */ + /* broken TCP + * http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set + */ if (!(p->tcph->th_flags & TH_ACK) && TCP_GET_ACK(p) != 0) { StreamTcpSetEvent(p, STREAM_PKT_BROKEN_ACK); } @@ -5362,7 +5337,7 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } if (ssn != NULL) - SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto); + SCLogDebug("ssn->alproto %" PRIu16 "", p->flow->alproto); } else { /* special case for PKT_PSEUDO_STREAM_END packets: * bypass the state handling and various packet checks, @@ -5414,7 +5389,7 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, * a bad window update that we should ignore (and alert on) */ if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0) { if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0) { - if (StreamTcpPacketIsBadWindowUpdate(ssn,p)) + if (StreamTcpPacketIsBadWindowUpdate(ssn, p)) goto skip; if (StreamTcpPacketIsOutdatedAck(ssn, p)) goto skip; @@ -5450,8 +5425,7 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, /* streams that hit depth */ if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) || - (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) - { + (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) { /* we can call bypass callback, if enabled */ if (StreamTcpBypassEnabled()) { PacketBypassCallback(p); @@ -5459,15 +5433,13 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) || - (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) - { + (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) { p->flags |= PKT_STREAM_NOPCAPLOG; } /* encrypted packets */ if ((PKT_IS_TOSERVER(p) && (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) || - (PKT_IS_TOCLIENT(p) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY))) - { + (PKT_IS_TOCLIENT(p) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY))) { p->flags |= PKT_STREAM_NOPCAPLOG; } @@ -5477,12 +5449,10 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketBypassCallback(p); } - /* if stream is dead and we have no detect engine at all, bypass. */ - } else if (g_detect_disabled && - (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && - (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && - StreamTcpBypassEnabled()) - { + /* if stream is dead and we have no detect engine at all, bypass. */ + } else if (g_detect_disabled && (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && + (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && + StreamTcpBypassEnabled()) { SCLogDebug("bypass as stream is dead and we have no rules"); PacketBypassCallback(p); } @@ -5523,24 +5493,18 @@ static inline int StreamTcpValidateChecksum(Packet *p) if (p->level4_comp_csum == -1) { if (PKT_IS_IPV4(p)) { - p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, + (p->payload_len + TCP_GET_HLEN(p)), p->tcph->th_sum); } else if (PKT_IS_IPV6(p)) { - p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p)), - p->tcph->th_sum); + p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, + (p->payload_len + TCP_GET_HLEN(p)), p->tcph->th_sum); } } if (p->level4_comp_csum != 0) { ret = 0; if (p->livedev) { - (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1); + (void)SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1); } else if (p->pcap_cnt) { PcapIncreaseInvalidChecksum(); } @@ -5559,13 +5523,14 @@ static int TcpSessionPacketIsStreamStarter(const Packet *p) } if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) { - SCLogDebug("packet %"PRIu64" is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); + SCLogDebug("packet %" PRIu64 " is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); return 1; } if (stream_config.midstream || stream_config.async_oneside) { if ((p->tcph->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { - SCLogDebug("packet %"PRIu64" is a midstream stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); + SCLogDebug("packet %" PRIu64 " is a midstream stream starter: %02x", p->pcap_cnt, + p->tcph->th_flags); return 1; } } @@ -5591,33 +5556,45 @@ static int TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const Tc return 1; } if (SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p))) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", + p->pcap_cnt, ssn); return 0; } if (ssn->state >= TCP_LAST_ACK) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else if (ssn->state == TCP_NONE) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else { // < TCP_LAST_ACK - SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", + p->pcap_cnt, ssn, ssn->state); return 0; } } else { if (ssn == NULL) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn); + SCLogDebug("steam starter packet %" PRIu64 ", ssn %p null. Reuse.", p->pcap_cnt, ssn); return 1; } if (ssn->state >= TCP_LAST_ACK) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else if (ssn->state == TCP_NONE) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else { // < TCP_LAST_ACK - SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", + p->pcap_cnt, ssn, ssn->state); return 0; } } @@ -5634,37 +5611,50 @@ static int TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const { if (FlowGetPacketDirection(f, p) == TOCLIENT) { if (ssn == NULL) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn); + SCLogDebug( + "steam starter packet %" PRIu64 ", ssn %p null. No reuse.", p->pcap_cnt, ssn); return 0; } if (SEQ_EQ(ssn->server.isn, TCP_GET_SEQ(p))) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", + p->pcap_cnt, ssn); return 0; } if (ssn->state >= TCP_LAST_ACK) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else if (ssn->state == TCP_NONE) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else { // < TCP_LAST_ACK - SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", + p->pcap_cnt, ssn, ssn->state); return 0; } } else { if (ssn == NULL) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn); + SCLogDebug("steam starter packet %" PRIu64 ", ssn %p null. Reuse.", p->pcap_cnt, ssn); return 1; } if (ssn->state >= TCP_LAST_ACK) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else if (ssn->state == TCP_NONE) { - SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 ", ssn %p state == TCP_NONE (%u). Reuse.", + p->pcap_cnt, ssn, ssn->state); return 1; } else { // < TCP_LAST_ACK - SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + SCLogDebug("steam starter packet %" PRIu64 + ", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", + p->pcap_cnt, ssn, ssn->state); return 0; } } @@ -5705,7 +5695,7 @@ int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn return 0; } -TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq) +TmEcode StreamTcp(ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq) { DEBUG_VALIDATE_BUG_ON(p->flow == NULL); if (unlikely(p->flow == NULL)) { @@ -5738,7 +5728,7 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq) p->flags |= PKT_IGNORE_CHECKSUM; } } else { - p->flags |= PKT_IGNORE_CHECKSUM; //TODO check that this is set at creation + p->flags |= PKT_IGNORE_CHECKSUM; // TODO check that this is set at creation } AppLayerProfilingReset(stt->ra_ctx->app_tctx); @@ -5782,29 +5772,30 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv); stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv); stt->ra_ctx->counter_tcp_reass_overlap = StatsRegisterCounter("tcp.overlap", tv); - stt->ra_ctx->counter_tcp_reass_overlap_diff_data = StatsRegisterCounter("tcp.overlap_diff_data", tv); + stt->ra_ctx->counter_tcp_reass_overlap_diff_data = + StatsRegisterCounter("tcp.overlap_diff_data", tv); - stt->ra_ctx->counter_tcp_reass_data_normal_fail = StatsRegisterCounter("tcp.insert_data_normal_fail", tv); - stt->ra_ctx->counter_tcp_reass_data_overlap_fail = StatsRegisterCounter("tcp.insert_data_overlap_fail", tv); + stt->ra_ctx->counter_tcp_reass_data_normal_fail = + StatsRegisterCounter("tcp.insert_data_normal_fail", tv); + stt->ra_ctx->counter_tcp_reass_data_overlap_fail = + StatsRegisterCounter("tcp.insert_data_overlap_fail", tv); - SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p", - stt, stt->ra_ctx); + SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p", stt, stt->ra_ctx); SCMutexLock(&ssn_pool_mutex); if (ssn_pool == NULL) { ssn_pool = PoolThreadInit(1, /* thread */ - 0, /* unlimited */ - stream_config.prealloc_sessions, - sizeof(TcpSession), - StreamTcpSessionPoolAlloc, - StreamTcpSessionPoolInit, NULL, - StreamTcpSessionPoolCleanup, NULL); + 0, /* unlimited */ + stream_config.prealloc_sessions, sizeof(TcpSession), StreamTcpSessionPoolAlloc, + StreamTcpSessionPoolInit, NULL, StreamTcpSessionPoolCleanup, NULL); stt->ssn_pool_id = 0; - SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id); + SCLogDebug( + "pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id); } else { /* grow ssn_pool until we have a element for our thread id */ stt->ssn_pool_id = PoolThreadExpand(ssn_pool); - SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id); + SCLogDebug( + "pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id); } SCMutexUnlock(&ssn_pool_mutex); if (stt->ssn_pool_id < 0 || ssn_pool == NULL) { @@ -5887,8 +5878,8 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) os_policy = ssn->server.os_policy; - if (p->tcph->th_flags & TH_ACK && - TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { + if (p->tcph->th_flags & TH_ACK && TCP_GET_ACK(p) && + StreamTcpValidateAck(ssn, &ssn->server, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK); SCReturnInt(0); @@ -5900,8 +5891,8 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) os_policy = ssn->client.os_policy; - if (p->tcph->th_flags & TH_ACK && - TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { + if (p->tcph->th_flags & TH_ACK && TCP_GET_ACK(p) && + StreamTcpValidateAck(ssn, &ssn->client, p) == -1) { SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn); StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK); SCReturnInt(0); @@ -5941,26 +5932,24 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) switch (os_policy) { case OS_POLICY_HPUX11: - if(PKT_IS_TOSERVER(p)){ - if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { - SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", - TCP_GET_SEQ(p)); + if (PKT_IS_TOSERVER(p)) { + if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { + SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } else { SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " " - "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p), - ssn->client.next_seq); + "and server SEQ: %" PRIu32 "", + TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ - if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { - SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", - TCP_GET_SEQ(p)); + if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { + SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " " - "and client SEQ: %" PRIu32 "", TCP_GET_SEQ(p), - ssn->server.next_seq); + "and client SEQ: %" PRIu32 "", + TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } @@ -5968,38 +5957,30 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) case OS_POLICY_OLD_LINUX: case OS_POLICY_LINUX: case OS_POLICY_SOLARIS: - if(PKT_IS_TOSERVER(p)){ - if(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), - ssn->client.last_ack)) - { /*window base is needed !!*/ - if(SEQ_LT(TCP_GET_SEQ(p), - (ssn->client.next_seq + ssn->client.window))) - { - SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", - TCP_GET_SEQ(p)); + if (PKT_IS_TOSERVER(p)) { + if (SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len), + ssn->client.last_ack)) { /*window base is needed !!*/ + if (SEQ_LT(TCP_GET_SEQ(p), (ssn->client.next_seq + ssn->client.window))) { + SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and" - " server SEQ: %" PRIu32 "", TCP_GET_SEQ(p), - ssn->client.next_seq); + " server SEQ: %" PRIu32 "", + TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ - if(SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len), - ssn->server.last_ack)) - { /*window base is needed !!*/ - if(SEQ_LT(TCP_GET_SEQ(p), - (ssn->server.next_seq + ssn->server.window))) - { - SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", - TCP_GET_SEQ(p)); + if (SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len), + ssn->server.last_ack)) { /*window base is needed !!*/ + if (SEQ_LT(TCP_GET_SEQ(p), (ssn->server.next_seq + ssn->server.window))) { + SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and" - " client SEQ: %" PRIu32 "", TCP_GET_SEQ(p), - ssn->server.next_seq); + " client SEQ: %" PRIu32 "", + TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } @@ -6014,26 +5995,25 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_VISTA: - if(PKT_IS_TOSERVER(p)) { - if(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { - SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", - TCP_GET_SEQ(p)); + if (PKT_IS_TOSERVER(p)) { + if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { + SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "", TCP_GET_SEQ(p)); return 1; } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " " - "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p), - ssn->client.next_seq); + "and server SEQ: %" PRIu32 "", + TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { - SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", - TCP_GET_SEQ(p), ssn->server.next_seq); + SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 " Stream %u", TCP_GET_SEQ(p), + ssn->server.next_seq); return 1; } else { SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and" " client SEQ: %" PRIu32 "", - TCP_GET_SEQ(p), ssn->server.next_seq); + TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } @@ -6056,7 +6036,7 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) * \retval 1 if the timestamp is valid * \retval 0 if the timestamp is invalid */ -static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p) +static int StreamTcpValidateTimestamp(TcpSession *ssn, Packet *p) { SCEnter(); @@ -6132,28 +6112,27 @@ static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p) if (check_ts) { int32_t result = 0; - SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts); + SCLogDebug("ts %" PRIu32 ", last_ts %" PRIu32 "", ts, last_ts); if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) { /* Linux accepts TS which are off by one.*/ - result = (int32_t) ((ts - last_ts) + 1); + result = (int32_t)((ts - last_ts) + 1); } else { - result = (int32_t) (ts - last_ts); + result = (int32_t)(ts - last_ts); } SCLogDebug("result %" PRIi32 ", p->ts(secs) %" PRIuMAX "", result, (uintmax_t)SCTIME_SECS(p->ts)); - if (last_pkt_ts == 0 && - (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) - { + if (last_pkt_ts == 0 && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { last_pkt_ts = SCTIME_SECS(p->ts); } if (result < 0) { SCLogDebug("timestamp is not valid last_ts " "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result " - "%" PRId32 "", last_ts, ts, result); + "%" PRId32 "", + last_ts, ts, result); /* candidate for rejection */ ret = 0; } else if ((sender_stream->last_ts != 0) && @@ -6196,7 +6175,7 @@ static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p) * \retval 1 if the timestamp is valid * \retval 0 if the timestamp is invalid */ -static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p) +static int StreamTcpHandleTimestamp(TcpSession *ssn, Packet *p) { SCEnter(); @@ -6274,28 +6253,27 @@ static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p) if (check_ts) { int32_t result = 0; - SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts); + SCLogDebug("ts %" PRIu32 ", last_ts %" PRIu32 "", ts, sender_stream->last_ts); if (receiver_stream->os_policy == OS_POLICY_LINUX || stream_config.liberal_timestamps) { /* Linux accepts TS which are off by one.*/ - result = (int32_t) ((ts - sender_stream->last_ts) + 1); + result = (int32_t)((ts - sender_stream->last_ts) + 1); } else { - result = (int32_t) (ts - sender_stream->last_ts); + result = (int32_t)(ts - sender_stream->last_ts); } SCLogDebug("result %" PRIi32 ", p->ts(sec) %" PRIuMAX "", result, (uintmax_t)SCTIME_SECS(p->ts)); - if (sender_stream->last_pkt_ts == 0 && - (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) - { + if (sender_stream->last_pkt_ts == 0 && (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) { sender_stream->last_pkt_ts = SCTIME_SECS(p->ts); } if (result < 0) { SCLogDebug("timestamp is not valid sender_stream->last_ts " "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result " - "%" PRId32 "", sender_stream->last_ts, ts, result); + "%" PRId32 "", + sender_stream->last_ts, ts, result); /* candidate for rejection */ ret = 0; } else if ((sender_stream->last_ts != 0) && @@ -6368,8 +6346,7 @@ static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packe const uint32_t ack = TCP_GET_ACK(p); /* fast track */ - if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win)) - { + if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win)) { SCLogDebug("ssn %p: ACK %u in bounds > %u <= %u", ssn, ack, stream->last_ack, stream->next_win); SCReturnInt(0); @@ -6383,15 +6360,16 @@ static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packe /* exception handling */ if (SEQ_LT(ack, stream->last_ack)) { - SCLogDebug("pkt ACK %"PRIu32" < stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack); + SCLogDebug( + "pkt ACK %" PRIu32 " < stream last ACK %" PRIu32, TCP_GET_ACK(p), stream->last_ack); /* This is an attempt to get a 'left edge' value that we can check against. * It doesn't work when the window is 0, need to think of a better way. */ if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) { - SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window " - "%"PRIu32" = %"PRIu32, ack, stream->last_ack, - stream->window, stream->last_ack - stream->window); + SCLogDebug("ACK %" PRIu32 " is before last_ack %" PRIu32 " - window " + "%" PRIu32 " = %" PRIu32, + ack, stream->last_ack, stream->window, stream->last_ack - stream->window); goto invalid; } @@ -6404,18 +6382,18 @@ static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packe } if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) { - SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win); + SCLogDebug("ACK %" PRIu32 " is after next_win %" PRIu32, ack, stream->next_win); goto invalid; /* a toclient RST as a response to SYN, next_win is 0, ack will be isn+1, just like * the syn ack */ - } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && - p->tcph->th_flags & TH_RST && - SEQ_EQ(ack, stream->isn + 1)) { + } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) && p->tcph->th_flags & TH_RST && + SEQ_EQ(ack, stream->isn + 1)) { SCReturnInt(0); } - SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32 - " next_win %"PRIu32, ack, stream->last_ack, stream->next_win); + SCLogDebug("default path leading to invalid: ACK %" PRIu32 ", last_ack %" PRIu32 + " next_win %" PRIu32, + ack, stream->last_ack, stream->next_win); invalid: StreamTcpSetEvent(p, STREAM_PKT_INVALID_ACK); SCReturnInt(-1); @@ -6426,8 +6404,7 @@ static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packe * \param ssn TCP Session * \param direction direction to set the flag in: 0 toserver, 1 toclient */ -void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction, - const uint32_t progress) +void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction, const uint32_t progress) { if (direction) { ssn->server.app_progress_rel += progress; @@ -6464,8 +6441,8 @@ void StreamTcpSetSessionNoReassemblyFlag(TcpSession *ssn, char direction) */ void StreamTcpSetDisableRawReassemblyFlag(TcpSession *ssn, char direction) { - direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) : - (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED); + direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) + : (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED); } /** \brief enable bypass @@ -6485,9 +6462,8 @@ void StreamTcpSetSessionBypassFlag(TcpSession *ssn) * \param pq packet queue to store the new pseudo packet in * \param dir 0 ts 1 tc */ -static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, - StreamTcpThread *stt, Packet *parent, - TcpSession *ssn, PacketQueueNoLock *pq, int dir) +static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, + Packet *parent, TcpSession *ssn, PacketQueueNoLock *pq, int dir) { SCEnter(); Flow *f = parent->flow; @@ -6548,7 +6524,7 @@ static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr. * Force an allocation if it is not the case. */ - if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) { + if (GET_PKT_DIRECT_MAX_SIZE(np) < 40) { if (PacketCallocExtPkt(np, 40) == -1) { goto error; } @@ -6592,7 +6568,7 @@ static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr. * Force an allocation if it is not the case. */ - if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) { + if (GET_PKT_DIRECT_MAX_SIZE(np) < 60) { if (PacketCallocExtPkt(np, 60) == -1) { goto error; } @@ -6644,7 +6620,7 @@ static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, np->tcph->th_seq = htonl(ssn->client.next_seq); np->tcph->th_ack = htonl(ssn->server.last_ack); - /* to client */ + /* to client */ } else { np->tcph->th_sport = htons(f->dp); np->tcph->th_dport = htons(f->sp); @@ -6673,16 +6649,16 @@ static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, * Flag TCP engine that data needs to be inspected regardless * of how far we are wrt inspect limits. */ -void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, - PacketQueueNoLock *pq) +void StreamTcpDetectLogFlush( + ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, PacketQueueNoLock *pq) { TcpSession *ssn = f->protoctx; ssn->client.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW; ssn->server.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW; bool ts = PKT_IS_TOSERVER(p) ? true : false; ts ^= StreamTcpInlineMode(); - StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^0); - StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts^1); + StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts ^ 0); + StreamTcpPseudoPacketCreateDetectLogFlush(tv, stt, p, ssn, pq, ts ^ 1); } /** @@ -6697,7 +6673,8 @@ void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Pack * \return -1 in case of error, the number of segment in case of success * */ -int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) +int StreamTcpSegmentForEach( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) { TcpStream *stream = NULL; int cnt = 0; @@ -6718,7 +6695,8 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback /* for IDS, return ack'd segments. For IPS all. */ TcpSegment *seg; - RB_FOREACH(seg, TCPSEG, &stream->seg_tree) { + RB_FOREACH(seg, TCPSEG, &stream->seg_tree) + { if (!(stream_config.flags & STREAMTCP_INIT_FLAG_INLINE)) { if (PKT_IS_PSEUDOPKT(p)) { /* use un-ACK'd data as well */ @@ -6855,7 +6833,6 @@ bool StreamTcpInlineMode(void) return (stream_config.flags & STREAMTCP_INIT_FLAG_INLINE); } - void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size) { if (size > ssn->reassembly_depth || size == 0) { diff --git a/src/stream-tcp.h b/src/stream-tcp.h index ff8a0998cb4e..2d4713b4fd39 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -34,10 +34,10 @@ #define STREAM_VERBOSE false /* Flag to indicate that the checksum validation for the stream engine has been enabled */ -#define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION BIT_U8(0) -#define STREAMTCP_INIT_FLAG_DROP_INVALID BIT_U8(1) -#define STREAMTCP_INIT_FLAG_BYPASS BIT_U8(2) -#define STREAMTCP_INIT_FLAG_INLINE BIT_U8(3) +#define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION BIT_U8(0) +#define STREAMTCP_INIT_FLAG_DROP_INVALID BIT_U8(1) +#define STREAMTCP_INIT_FLAG_BYPASS BIT_U8(2) +#define STREAMTCP_INIT_FLAG_INLINE BIT_U8(3) /*global flow data*/ typedef struct TcpStreamCnf_ { @@ -61,7 +61,7 @@ typedef struct TcpStreamCnf_ { bool streaming_log_api; uint8_t max_syn_queued; - uint32_t reassembly_depth; /**< Depth until when we reassemble the stream */ + uint32_t reassembly_depth; /**< Depth until when we reassemble the stream */ uint16_t reassembly_toserver_chunk_size; uint16_t reassembly_toclient_chunk_size; @@ -105,9 +105,9 @@ typedef struct StreamTcpThread_ { extern TcpStreamCnf stream_config; void StreamTcpInitConfig(bool); void StreamTcpFreeConfig(bool); -void StreamTcpRegisterTests (void); +void StreamTcpRegisterTests(void); -void StreamTcpSessionPktFree (Packet *); +void StreamTcpSessionPktFree(Packet *); void StreamTcpInitMemuse(void); void StreamTcpIncrMemuse(uint64_t); @@ -118,9 +118,8 @@ int StreamTcpCheckMemcap(uint64_t); uint64_t StreamTcpMemuseCounter(void); uint64_t StreamTcpReassembleMemuseGlobalCounter(void); -int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, - StreamSegmentCallback CallbackFunc, - void *data); +int StreamTcpSegmentForEach( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); int StreamTcpSegmentForSession( const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); void StreamTcpReassembleConfigEnableOverlapCheck(void); @@ -131,16 +130,14 @@ typedef int (*StreamReassembleRawFunc)( int StreamReassembleForFrame(TcpSession *ssn, TcpStream *stream, StreamReassembleRawFunc Callback, void *cb_data, const uint64_t offset, const bool eof); -int StreamReassembleLog(TcpSession *ssn, TcpStream *stream, - StreamReassembleRawFunc Callback, void *cb_data, - uint64_t progress_in, - uint64_t *progress_out, bool eof); -int StreamReassembleRaw(TcpSession *ssn, const Packet *p, - StreamReassembleRawFunc Callback, void *cb_data, - uint64_t *progress_out, bool respect_inspect_depth); +int StreamReassembleLog(TcpSession *ssn, TcpStream *stream, StreamReassembleRawFunc Callback, + void *cb_data, uint64_t progress_in, uint64_t *progress_out, bool eof); +int StreamReassembleRaw(TcpSession *ssn, const Packet *p, StreamReassembleRawFunc Callback, + void *cb_data, uint64_t *progress_out, bool respect_inspect_depth); void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress); -void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, PacketQueueNoLock *pq); +void StreamTcpDetectLogFlush( + ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, PacketQueueNoLock *pq); const char *StreamTcpStateAsString(const enum TcpState); const char *StreamTcpSsnStateAsString(const TcpSession *ssn); @@ -148,14 +145,14 @@ const char *StreamTcpSsnStateAsString(const TcpSession *ssn); /** ------- Inline functions: ------ */ /** - * \brief If we are on IPS mode, and got a drop action triggered from - * the IP only module, or from a reassembled msg and/or from an - * applayer detection, then drop the rest of the packets of the - * same stream and avoid inspecting it any further - * \param p pointer to the Packet to check - * \retval 1 if we must drop this stream - * \retval 0 if the stream still legal - */ + * \brief If we are on IPS mode, and got a drop action triggered from + * the IP only module, or from a reassembled msg and/or from an + * applayer detection, then drop the rest of the packets of the + * same stream and avoid inspecting it any further + * \param p pointer to the Packet to check + * \retval 1 if we must drop this stream + * \retval 0 if the stream still legal + */ static inline int StreamTcpCheckFlowDrops(Packet *p) { /* If we are on IPS mode, and got a drop action triggered from @@ -176,13 +173,12 @@ enum { STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION = 1, }; -TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueueNoLock *); +TmEcode StreamTcp(ThreadVars *, Packet *, void *, PacketQueueNoLock *); uint8_t StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction); TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **); TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data); -int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, - PacketQueueNoLock *pq); +int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq); /* clear ssn and return to pool */ void StreamTcpSessionClear(void *ssnptr); /* cleanup ssn, but don't free ssn */ @@ -195,8 +191,7 @@ bool StreamTcpInlineMode(void); int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn); -void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction, - const uint32_t progress); +void StreamTcpUpdateAppLayerProgress(TcpSession *ssn, char direction, const uint32_t progress); uint64_t StreamTcpGetAcked(const TcpStream *stream); uint64_t StreamTcpGetUsable(const TcpStream *stream, const bool eof); @@ -206,4 +201,3 @@ void StreamTcpThreadCacheEnable(void); void StreamTcpThreadCacheCleanup(void); #endif /* __STREAM_TCP_H__ */ - diff --git a/src/stream.c b/src/stream.c index 7fea5ba55c9e..8cf6f88512bb 100644 --- a/src/stream.c +++ b/src/stream.c @@ -25,8 +25,8 @@ #include "decode.h" #include "threads.h" #include "stream.h" -#include "util-pool.h" -#include "util-debug.h" +#include "util/pool.h" +#include "util/debug.h" #include "stream-tcp.h" #include "flow-util.h" @@ -37,9 +37,10 @@ * * \return -1 in case of error, the number of segment in case of success */ -int StreamSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) +int StreamSegmentForEach( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) { - switch(p->proto) { + switch (p->proto) { case IPPROTO_TCP: return StreamTcpSegmentForEach(p, flag, CallbackFunc, data); break; diff --git a/src/stream.h b/src/stream.h index 4821dc9981f5..53af26c4cf6a 100644 --- a/src/stream.h +++ b/src/stream.h @@ -35,11 +35,9 @@ typedef int (*StreamSegmentCallback)( const Packet *, TcpSegment *, void *, const uint8_t *, uint32_t); -int StreamSegmentForEach(const Packet *p, uint8_t flag, - StreamSegmentCallback CallbackFunc, - void *data); +int StreamSegmentForEach( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); int StreamSegmentForSession( const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); #endif /* __STREAM_H__ */ - diff --git a/src/suricata-common.h b/src/suricata-common.h index 297a6fc4521e..bd1d61addbff 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -133,7 +133,7 @@ #endif #if HAVE_SCHED_H -#include /* for sched_setaffinity(2) */ +#include /* for sched_setaffinity(2) */ #endif #ifdef HAVE_TYPE_U_LONG_NOT_DEFINED @@ -155,13 +155,13 @@ typedef unsigned char u_char; #include #else #ifdef OS_WIN32 -#include "win32-syslog.h" +#include "windows/win32-syslog.h" #endif /* OS_WIN32 */ #endif /* HAVE_SYSLOG_H */ #ifdef OS_WIN32 -#include "win32-misc.h" -#include "win32-service.h" +#include "windows/win32-misc.h" +#include "windows/win32-service.h" #endif /* OS_WIN32 */ #if HAVE_SYS_TIME_H @@ -288,30 +288,33 @@ typedef unsigned char u_char; /* we need this to stringify the defines which are supplied at compiletime see: http://gcc.gnu.org/onlinedocs/gcc-3.4.1/cpp/Stringification.html#Stringification */ #define xstr(s) str(s) -#define str(s) #s +#define str(s) #s -#if CPPCHECK==1 - #define BUG_ON(x) if (((x))) exit(1) +#if CPPCHECK == 1 +#define BUG_ON(x) \ + if (((x))) \ + exit(1) #else - #if defined HAVE_ASSERT_H && !defined NDEBUG - #include - #define BUG_ON(x) assert(!(x)) - #else - #define BUG_ON(x) do { \ - if (((x))) { \ - fprintf(stderr, "BUG at %s:%d(%s)\n", __FILE__, __LINE__, __func__); \ - fprintf(stderr, "Code: '%s'\n", xstr((x))); \ - exit(EXIT_FAILURE); \ - } \ - } while(0) - #endif +#if defined HAVE_ASSERT_H && !defined NDEBUG +#include +#define BUG_ON(x) assert(!(x)) +#else +#define BUG_ON(x) \ + do { \ + if (((x))) { \ + fprintf(stderr, "BUG at %s:%d(%s)\n", __FILE__, __LINE__, __func__); \ + fprintf(stderr, "Code: '%s'\n", xstr((x))); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) +#endif #endif /** type for the internal signature id. Since it's used in the matching engine * extensively keeping this as small as possible reduces the overall memory * footprint of the engine. Set to uint32_t if the engine needs to support * more than 64k sigs. */ -//#define SigIntId uint16_t +// #define SigIntId uint16_t #define SigIntId uint32_t /** same for pattern id's */ @@ -319,85 +322,84 @@ typedef unsigned char u_char; /** FreeBSD does not define __WORDSIZE, but it uses __LONG_BIT */ #ifndef __WORDSIZE - #ifdef __LONG_BIT - #define __WORDSIZE __LONG_BIT - #else - #ifdef LONG_BIT - #define __WORDSIZE LONG_BIT - #endif - #endif +#ifdef __LONG_BIT +#define __WORDSIZE __LONG_BIT +#else +#ifdef LONG_BIT +#define __WORDSIZE LONG_BIT +#endif +#endif #endif /** Windows does not define __WORDSIZE, but it uses __X86__ */ #ifndef __WORDSIZE - #if defined(__X86__) || defined(_X86_) || defined(_M_IX86) - #define __WORDSIZE 32 - #else - #if defined(__X86_64__) || defined(_X86_64_) || \ - defined(__x86_64) || defined(__x86_64__) || \ - defined(__amd64) || defined(__amd64__) - #define __WORDSIZE 64 - #endif - #endif +#if defined(__X86__) || defined(_X86_) || defined(_M_IX86) +#define __WORDSIZE 32 +#else +#if defined(__X86_64__) || defined(_X86_64_) || defined(__x86_64) || defined(__x86_64__) || \ + defined(__amd64) || defined(__amd64__) +#define __WORDSIZE 64 +#endif +#endif #endif /** if not succesful yet try the data models */ #ifndef __WORDSIZE - #if defined(_ILP32) || defined(__ILP32__) - #define __WORDSIZE 32 - #endif - #if defined(_LP64) || defined(__LP64__) - #define __WORDSIZE 64 - #endif +#if defined(_ILP32) || defined(__ILP32__) +#define __WORDSIZE 32 +#endif +#if defined(_LP64) || defined(__LP64__) +#define __WORDSIZE 64 +#endif #endif #ifndef __WORDSIZE - #warning Defaulting to __WORDSIZE 32 - #define __WORDSIZE 32 +#warning Defaulting to __WORDSIZE 32 +#define __WORDSIZE 32 #endif /** darwin doesn't defined __BYTE_ORDER and friends, but BYTE_ORDER */ #ifndef __BYTE_ORDER - #if defined(BYTE_ORDER) - #define __BYTE_ORDER BYTE_ORDER - #elif defined(__BYTE_ORDER__) - #define __BYTE_ORDER __BYTE_ORDER__ - #else - #error "byte order not detected" - #endif +#if defined(BYTE_ORDER) +#define __BYTE_ORDER BYTE_ORDER +#elif defined(__BYTE_ORDER__) +#define __BYTE_ORDER __BYTE_ORDER__ +#else +#error "byte order not detected" +#endif #endif #ifndef __LITTLE_ENDIAN - #if defined(LITTLE_ENDIAN) - #define __LITTLE_ENDIAN LITTLE_ENDIAN - #elif defined(__ORDER_LITTLE_ENDIAN__) - #define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ - #endif +#if defined(LITTLE_ENDIAN) +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#elif defined(__ORDER_LITTLE_ENDIAN__) +#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif #endif #ifndef __BIG_ENDIAN - #if defined(BIG_ENDIAN) - #define __BIG_ENDIAN BIG_ENDIAN - #elif defined(__ORDER_BIG_ENDIAN__) - #define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ - #endif +#if defined(BIG_ENDIAN) +#define __BIG_ENDIAN BIG_ENDIAN +#elif defined(__ORDER_BIG_ENDIAN__) +#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#endif #endif #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) - #error "byte order: can't figure out big or little" +#error "byte order: can't figure out big or little" #endif #ifndef MIN -#define MIN(x, y) (((x)<(y))?(x):(y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif #ifndef MAX -#define MAX(x, y) (((x)<(y))?(y):(x)) +#define MAX(x, y) (((x) < (y)) ? (y) : (x)) #endif #define BIT_U8(n) ((uint8_t)(1 << (n))) #define BIT_U16(n) ((uint16_t)(1 << (n))) -#define BIT_U32(n) (1UL << (n)) +#define BIT_U32(n) (1UL << (n)) #define BIT_U64(n) (1ULL << (n)) #define WARN_UNUSED __attribute__((warn_unused_result)) @@ -410,26 +412,26 @@ typedef unsigned char u_char; #define ATTR_FMT_PRINTF(x, y) #endif -#define SCNtohl(x) (uint32_t)ntohl((x)) -#define SCNtohs(x) (uint16_t)ntohs((x)) +#define SCNtohl(x) (uint32_t) ntohl((x)) +#define SCNtohs(x) (uint16_t) ntohs((x)) /* swap flags if one of them is set, otherwise do nothing. */ -#define SWAP_FLAGS(flags, a, b) \ - do { \ - if (((flags) & ((a)|(b))) == (a)) { \ - (flags) &= ~(a); \ - (flags) |= (b); \ - } else if (((flags) & ((a)|(b))) == (b)) { \ - (flags) &= ~(b); \ - (flags) |= (a); \ - } \ - } while(0) - -#define SWAP_VARS(type, a, b) \ - do { \ - type t = (a); \ - (a) = (b); \ - (b) = t; \ +#define SWAP_FLAGS(flags, a, b) \ + do { \ + if (((flags) & ((a) | (b))) == (a)) { \ + (flags) &= ~(a); \ + (flags) |= (b); \ + } else if (((flags) & ((a) | (b))) == (b)) { \ + (flags) &= ~(b); \ + (flags) |= (a); \ + } \ + } while (0) + +#define SWAP_VARS(type, a, b) \ + do { \ + type t = (a); \ + (a) = (b); \ + (b) = t; \ } while (0) #include @@ -508,12 +510,12 @@ typedef void lua_State; #endif #include "tm-threads-common.h" -#include "util-optimize.h" -#include "util-time.h" -#include "util-mem.h" -#include "util-memcmp.h" -#include "util-atomic.h" -#include "util-unittest.h" +#include "util/optimize.h" +#include "util/time.h" +#include "util/mem.h" +#include "util/memcmp.h" +#include "util/atomic.h" +#include "util/unittest.h" // pseudo system headers #include "queue.h" @@ -526,19 +528,19 @@ size_t strlcat(char *, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_STRPTIME -char *strptime(const char * __restrict, const char * __restrict, struct tm * __restrict); +char *strptime(const char *__restrict, const char *__restrict, struct tm *__restrict); #endif #ifndef HAVE_FWRITE_UNLOCKED -#define SCFwriteUnlocked fwrite -#define SCFflushUnlocked fflush -#define SCClearErrUnlocked clearerr -#define SCFerrorUnlocked ferror +#define SCFwriteUnlocked fwrite +#define SCFflushUnlocked fflush +#define SCClearErrUnlocked clearerr +#define SCFerrorUnlocked ferror #else -#define SCFwriteUnlocked fwrite_unlocked -#define SCFflushUnlocked fflush_unlocked -#define SCClearErrUnlocked clearerr_unlocked -#define SCFerrorUnlocked ferror_unlocked +#define SCFwriteUnlocked fwrite_unlocked +#define SCFflushUnlocked fflush_unlocked +#define SCClearErrUnlocked clearerr_unlocked +#define SCFerrorUnlocked ferror_unlocked #endif extern int coverage_unittests; extern int g_ut_modules; diff --git a/src/suricata.c b/src/suricata.c index ffa970ae7297..525ade49593f 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -77,11 +77,11 @@ #include "app-layer.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" -#include "app-layer-htp-range.h" +#include "app-layer/http/parser.h" +#include "app-layer/http/parser-range.h" -#include "output.h" -#include "output-filestore.h" +#include "output/output.h" +#include "output/output-filestore.h" #include "respond-reject.h" @@ -110,44 +110,44 @@ #include "unix-manager.h" -#include "util-classification-config.h" -#include "util-threshold-config.h" -#include "util-reference-config.h" +#include "util/classification-config.h" +#include "util/threshold-config.h" +#include "util/reference-config.h" #include "tmqh-packetpool.h" #include "tm-queuehandlers.h" -#include "util-byte.h" -#include "util-conf.h" -#include "util-coredump-config.h" -#include "util-cpu.h" -#include "util-daemon.h" -#include "util-device.h" -#include "util-dpdk.h" -#include "util-ebpf.h" -#include "util-exception-policy.h" -#include "util-host-os-info.h" -#include "util-ioctl.h" -#include "util-landlock.h" -#include "util-luajit.h" -#include "util-macset.h" -#include "util-misc.h" -#include "util-mpm-hs.h" -#include "util-path.h" -#include "util-pidfile.h" -#include "util-plugin.h" -#include "util-privs.h" -#include "util-profiling.h" -#include "util-proto-name.h" -#include "util-running-modes.h" -#include "util-signal.h" -#include "util-time.h" -#include "util-validate.h" -#include "util-var-name.h" +#include "util/byte.h" +#include "util/conf.h" +#include "util/coredump-config.h" +#include "util/cpu.h" +#include "util/daemon.h" +#include "util/device.h" +#include "util/dpdk.h" +#include "util/ebpf.h" +#include "util/exception-policy.h" +#include "util/host-os-info.h" +#include "util/ioctl.h" +#include "util/landlock.h" +#include "util/lua/luajit.h" +#include "util/macset.h" +#include "util/misc.h" +#include "util/mpm/mpm-hs.h" +#include "util/path.h" +#include "util/pidfile.h" +#include "util/plugin.h" +#include "util/privs.h" +#include "util/profiling.h" +#include "util/proto-name.h" +#include "util/running-modes.h" +#include "util/signal.h" +#include "util/time.h" +#include "util/validate.h" +#include "util/var-name.h" #ifdef WINDIVERT #include "decode-sll.h" -#include "win32-syscall.h" +#include "windows/win32-syscall.h" #endif /* @@ -175,7 +175,7 @@ volatile uint8_t suricata_ctl_flags = 0; int run_mode = RUNMODE_UNKNOWN; /** Engine mode: inline (ENGINE_MODE_IPS) or just - * detection mode (ENGINE_MODE_IDS by default) */ + * detection mode (ENGINE_MODE_IDS by default) */ static enum EngineMode g_engine_mode = ENGINE_MODE_UNKNOWN; /** Host mode: set if box is sniffing only @@ -201,7 +201,7 @@ int g_disable_randomness = 1; #endif /** determine (without branching) if we include the vlan_ids when hashing or - * comparing flows */ + * comparing flows */ uint16_t g_vlan_mask = 0xffff; /** determine (without branching) if we include the livedev ids when hashing or @@ -463,8 +463,8 @@ static int SetBpfString(int argc, char *argv[]) /* attempt to parse remaining args as bpf filter */ tmpindex = argc; - while(argv[tmpindex] != NULL) { - bpf_len+=strlen(argv[tmpindex]) + 1; + while (argv[tmpindex] != NULL) { + bpf_len += strlen(argv[tmpindex]) + 1; tmpindex++; } @@ -476,15 +476,15 @@ static int SetBpfString(int argc, char *argv[]) return TM_ECODE_FAILED; tmpindex = optind; - while(argv[tmpindex] != NULL) { - strlcat(bpf_filter, argv[tmpindex],bpf_len); - if(argv[tmpindex + 1] != NULL) { - strlcat(bpf_filter," ", bpf_len); + while (argv[tmpindex] != NULL) { + strlcat(bpf_filter, argv[tmpindex], bpf_len); + if (argv[tmpindex + 1] != NULL) { + strlcat(bpf_filter, " ", bpf_len); } tmpindex++; } - if(strlen(bpf_filter) > 0) { + if (strlen(bpf_filter) > 0) { if (ConfSetFinal("bpf-filter", bpf_filter) != 1) { SCLogError("Failed to set bpf filter."); SCFree(bpf_filter); @@ -500,7 +500,7 @@ static void SetBpfStringFromFile(char *filename) { char *bpf_filter = NULL; char *bpf_comment_tmp = NULL; - char *bpf_comment_start = NULL; + char *bpf_comment_start = NULL; uint32_t bpf_len = 0; SCStat st; FILE *fp = NULL; @@ -534,29 +534,26 @@ static void SetBpfStringFromFile(char *filename) fclose(fp); bpf_filter[nm] = '\0'; - if(strlen(bpf_filter) > 0) { + if (strlen(bpf_filter) > 0) { /*replace comments with space*/ bpf_comment_start = bpf_filter; - while((bpf_comment_tmp = strchr(bpf_comment_start, '#')) != NULL) { - while((*bpf_comment_tmp !='\0') && - (*bpf_comment_tmp != '\r') && (*bpf_comment_tmp != '\n')) - { + while ((bpf_comment_tmp = strchr(bpf_comment_start, '#')) != NULL) { + while ((*bpf_comment_tmp != '\0') && (*bpf_comment_tmp != '\r') && + (*bpf_comment_tmp != '\n')) { *bpf_comment_tmp++ = ' '; } bpf_comment_start = bpf_comment_tmp; } /*remove remaining '\r' and '\n' */ - while((bpf_comment_tmp = strchr(bpf_filter, '\r')) != NULL) { + while ((bpf_comment_tmp = strchr(bpf_filter, '\r')) != NULL) { *bpf_comment_tmp = ' '; } - while((bpf_comment_tmp = strchr(bpf_filter, '\n')) != NULL) { + while ((bpf_comment_tmp = strchr(bpf_filter, '\n')) != NULL) { *bpf_comment_tmp = ' '; } /* cut trailing spaces */ - while (strlen(bpf_filter) > 0 && - bpf_filter[strlen(bpf_filter)-1] == ' ') - { - bpf_filter[strlen(bpf_filter)-1] = '\0'; + while (strlen(bpf_filter) > 0 && bpf_filter[strlen(bpf_filter) - 1] == ' ') { + bpf_filter[strlen(bpf_filter) - 1] = '\0'; } if (strlen(bpf_filter) > 0) { if (ConfSetFinal("bpf-filter", bpf_filter) != 1) { @@ -582,13 +579,16 @@ static void PrintUsage(const char *progname) printf("\t-F : bpf filter file\n"); printf("\t-r : run in pcap file/offline mode\n"); #ifdef NFQ - printf("\t-q : run in inline nfqueue mode (use colon to specify a range of queues)\n"); + printf("\t-q : run in inline nfqueue mode (use colon to " + "specify a range of queues)\n"); #endif /* NFQ */ #ifdef IPFW printf("\t-d : run in inline ipfw divert mode\n"); #endif /* IPFW */ - printf("\t-s : path to signature file loaded in addition to suricata.yaml settings (optional)\n"); - printf("\t-S : path to signature file loaded exclusively (optional)\n"); + printf("\t-s : path to signature file loaded in addition to " + "suricata.yaml settings (optional)\n"); + printf("\t-S : path to signature file loaded exclusively " + "(optional)\n"); printf("\t-l : default log directory\n"); #ifndef OS_WIN32 printf("\t-D : run as daemon\n"); @@ -597,9 +597,11 @@ static void PrintUsage(const char *progname) printf("\t--service-remove : remove service\n"); printf("\t--service-change-params : change service startup parameters\n"); #endif /* OS_WIN32 */ - printf("\t-k [all|none] : force checksum check (all) or disabled it (none)\n"); + printf("\t-k [all|none] : force checksum check (all) or disabled it " + "(none)\n"); printf("\t-V : display Suricata version\n"); - printf("\t-v : be more verbose (use multiple times to increase verbosity)\n"); + printf("\t-v : be more verbose (use multiple times to " + "increase verbosity)\n"); #ifdef UNITTESTS printf("\t-u : run the unittests and exit\n"); printf("\t-U, --unittest-filter=REGEX : filter unittests with a regex\n"); @@ -610,44 +612,58 @@ static void PrintUsage(const char *progname) printf("\t--list-app-layer-protos : list supported app layer protocols\n"); printf("\t--list-keywords[=all|csv|] : list keywords implemented by the engine\n"); printf("\t--list-runmodes : list supported runmodes\n"); - printf("\t--runmode : specific runmode modification the engine should run. The argument\n" - "\t supplied should be the id for the runmode obtained by running\n" + printf("\t--runmode : specific runmode modification the engine " + "should run. The argument\n" + "\t supplied should be the id for the runmode " + "obtained by running\n" "\t --list-runmodes\n"); - printf("\t--engine-analysis : print reports on analysis of different sections in the engine and exit.\n" - "\t Please have a look at the conf parameter engine-analysis on what reports\n" + printf("\t--engine-analysis : print reports on analysis of different " + "sections in the engine and exit.\n" + "\t Please have a look at the conf parameter " + "engine-analysis on what reports\n" "\t can be printed\n"); printf("\t--pidfile : write pid to this file\n"); - printf("\t--init-errors-fatal : enable fatal failure on signature init error\n"); + printf("\t--init-errors-fatal : enable fatal failure on signature init " + "error\n"); printf("\t--disable-detection : disable detection engine\n"); printf("\t--dump-config : show the running configuration\n"); printf("\t--dump-features : display provided features\n"); printf("\t--build-info : display build information\n"); - printf("\t--pcap[=] : run in pcap mode, no value select interfaces from suricata.yaml\n"); - printf("\t--pcap-file-continuous : when running in pcap mode with a directory, continue checking directory for pcaps until interrupted\n"); - printf("\t--pcap-file-delete : when running in replay mode (-r with directory or file), will delete pcap files that have been processed when done\n"); - printf("\t--pcap-file-recursive : will descend into subdirectories when running in replay mode (-r)\n"); + printf("\t--pcap[=] : run in pcap mode, no value select interfaces " + "from suricata.yaml\n"); + printf("\t--pcap-file-continuous : when running in pcap mode with a directory, " + "continue checking directory for pcaps until interrupted\n"); + printf("\t--pcap-file-delete : when running in replay mode (-r with " + "directory or file), will delete pcap files that have been processed when done\n"); + printf("\t--pcap-file-recursive : will descend into subdirectories when running " + "in replay mode (-r)\n"); #ifdef HAVE_PCAP_SET_BUFF - printf("\t--pcap-buffer-size : size of the pcap buffer value from 0 - %i\n",INT_MAX); + printf("\t--pcap-buffer-size : size of the pcap buffer value from 0 - %i\n", + INT_MAX); #endif /* HAVE_SET_PCAP_BUFF */ #ifdef HAVE_DPDK printf("\t--dpdk : run in dpdk mode, uses interfaces from " "suricata.yaml\n"); #endif #ifdef HAVE_AF_PACKET - printf("\t--af-packet[=] : run in af-packet mode, no value select interfaces from suricata.yaml\n"); + printf("\t--af-packet[=] : run in af-packet mode, no value select " + "interfaces from suricata.yaml\n"); #endif #ifdef HAVE_AF_XDP printf("\t--af-xdp[=] : run in af-xdp mode, no value select " "interfaces from suricata.yaml\n"); #endif #ifdef HAVE_NETMAP - printf("\t--netmap[=] : run in netmap mode, no value select interfaces from suricata.yaml\n"); + printf("\t--netmap[=] : run in netmap mode, no value select " + "interfaces from suricata.yaml\n"); #endif #ifdef HAVE_PFRING - printf("\t--pfring[=] : run in pfring mode, use interfaces from suricata.yaml\n"); + printf("\t--pfring[=] : run in pfring mode, use interfaces from " + "suricata.yaml\n"); printf("\t--pfring-int : run in pfring mode, use interface \n"); printf("\t--pfring-cluster-id : pfring cluster id \n"); - printf("\t--pfring-cluster-type : pfring cluster type for PF_RING 4.1.2 and later cluster_round_robin|cluster_flow\n"); + printf("\t--pfring-cluster-type : pfring cluster type for PF_RING 4.1.2 and " + "later cluster_round_robin|cluster_flow\n"); #endif /* HAVE_PFRING */ printf("\t--simulate-ips : force engine into IPS mode. Useful for QA\n"); #ifdef HAVE_LIBCAP_NG @@ -656,7 +672,8 @@ static void PrintUsage(const char *progname) #endif /* HAVE_LIBCAP_NG */ printf("\t--erf-in : process an ERF file\n"); #ifdef HAVE_DAG - printf("\t--dag : process ERF records from DAG interface X, stream Y\n"); + printf("\t--dag : process ERF records from DAG interface X, " + "stream Y\n"); #endif #ifdef HAVE_NAPATECH printf("\t--napatech : run Napatech Streams using the API\n"); @@ -675,8 +692,8 @@ static void PrintUsage(const char *progname) printf("\t--set name=value : set a configuration value\n"); printf("\n"); printf("\nTo run the engine with default configuration on " - "interface eth0 with signature file \"signatures.rules\", run the " - "command as:\n\n%s -c suricata.yaml -s signatures.rules -i eth0 \n\n", + "interface eth0 with signature file \"signatures.rules\", run the " + "command as:\n\n%s -c suricata.yaml -s signatures.rules -i eth0 \n\n", progname); } @@ -829,9 +846,9 @@ static void PrintBuildInfo(void) printf("%s, %s architecture\n", bits, endian); #ifdef __GNUC__ - printf("GCC version %s, C version %"PRIiMAX"\n", __VERSION__, (intmax_t)__STDC_VERSION__); + printf("GCC version %s, C version %" PRIiMAX "\n", __VERSION__, (intmax_t)__STDC_VERSION__); #else - printf("C version %"PRIiMAX"\n", (intmax_t)__STDC_VERSION__); + printf("C version %" PRIiMAX "\n", (intmax_t)__STDC_VERSION__); #endif #if __SSP__ == 1 @@ -866,8 +883,7 @@ static void PrintBuildInfo(void) #endif printf("thread local storage method: %s\n", tls); - printf("compiled with %s, linked against %s\n", - HTP_VERSION_STRING_FULL, htp_get_version()); + printf("compiled with %s, linked against %s\n", HTP_VERSION_STRING_FULL, htp_get_version()); printf("\n"); #include "build-info.h" } @@ -1093,7 +1109,7 @@ static void SCInstanceInit(SCInstance *suri, const char *progname) suri->verbose = 0; /* use -1 as unknown */ suri->checksum_validation = -1; -#if HAVE_DETECT_DISABLED==1 +#if HAVE_DETECT_DISABLED == 1 g_detect_disabled = suri->disabled_detect = 1; #else g_detect_disabled = suri->disabled_detect = 0; @@ -1143,8 +1159,7 @@ static TmEcode PrintVersion(void) static TmEcode LogVersion(SCInstance *suri) { const char *mode = suri->system ? "SYSTEM" : "USER"; - SCLogNotice("This is %s version %s running in %s mode", - PROG_NAME, GetProgramVersion(), mode); + SCLogNotice("This is %s version %s running in %s mode", PROG_NAME, GetProgramVersion(), mode); return TM_ECODE_OK; } @@ -1162,8 +1177,8 @@ static void SCPrintElapsedTime(struct timeval *start_time) memset(&end_time, 0, sizeof(end_time)); gettimeofday(&end_time, NULL); uint64_t milliseconds = ((end_time.tv_sec - start_time->tv_sec) * 1000) + - (((1000000 + end_time.tv_usec - start_time->tv_usec) / 1000) - 1000); - SCLogInfo("time elapsed %.3fs", (float)milliseconds/(float)1000); + (((1000000 + end_time.tv_usec - start_time->tv_usec) / 1000) - 1000); + SCLogInfo("time elapsed %.3fs", (float)milliseconds / (float)1000); } static int ParseCommandLineAfpacket(SCInstance *suri, const char *in_arg) @@ -1262,7 +1277,7 @@ static int ParseCommandLinePcapLive(SCInstance *suri, const char *in_arg) /* some windows shells require escaping of the \ in \Device. Otherwise * the backslashes are stripped. We put them back here. */ if (strlen(in_arg) > 9 && strncmp(in_arg, "DeviceNPF", 9) == 0) { - snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", in_arg+9); + snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", in_arg + 9); } else { strlcpy(suri->pcap_dev, in_arg, sizeof(suri->pcap_dev)); PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); @@ -1295,14 +1310,14 @@ static int ParseCommandLinePcapLive(SCInstance *suri, const char *in_arg) /** * Helper function to check if log directory is writable */ -static bool IsLogDirectoryWritable(const char* str) +static bool IsLogDirectoryWritable(const char *str) { if (access(str, W_OK) == 0) return true; return false; } -static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) +static TmEcode ParseCommandLine(int argc, char **argv, SCInstance *suri) { int opt; @@ -1409,624 +1424,615 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) while ((opt = getopt_long(argc, argv, short_opts, long_opts, &option_index)) != -1) { switch (opt) { - case 0: - if (strcmp((long_opts[option_index]).name , "pfring") == 0 || - strcmp((long_opts[option_index]).name , "pfring-int") == 0) { + case 0: + if (strcmp((long_opts[option_index]).name, "pfring") == 0 || + strcmp((long_opts[option_index]).name, "pfring-int") == 0) { #ifdef HAVE_PFRING - suri->run_mode = RUNMODE_PFRING; - if (optarg != NULL) { - memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - strlcpy(suri->pcap_dev, optarg, - ((strlen(optarg) < sizeof(suri->pcap_dev)) ? - (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); - LiveRegisterDeviceName(optarg); - } + suri->run_mode = RUNMODE_PFRING; + if (optarg != NULL) { + memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); + strlcpy(suri->pcap_dev, optarg, + ((strlen(optarg) < sizeof(suri->pcap_dev)) + ? (strlen(optarg) + 1) + : sizeof(suri->pcap_dev))); + LiveRegisterDeviceName(optarg); + } #else - SCLogError("PF_RING not enabled. Make sure " - "to pass --enable-pfring to configure when building."); - return TM_ECODE_FAILED; + SCLogError("PF_RING not enabled. Make sure " + "to pass --enable-pfring to configure when building."); + return TM_ECODE_FAILED; #endif /* HAVE_PFRING */ - } - else if(strcmp((long_opts[option_index]).name , "pfring-cluster-id") == 0){ + } else if (strcmp((long_opts[option_index]).name, "pfring-cluster-id") == 0) { #ifdef HAVE_PFRING - if (ConfSetFinal("pfring.cluster-id", optarg) != 1) { - SCLogError("failed to set pfring.cluster-id"); - return TM_ECODE_FAILED; - } + if (ConfSetFinal("pfring.cluster-id", optarg) != 1) { + SCLogError("failed to set pfring.cluster-id"); + return TM_ECODE_FAILED; + } #else - SCLogError("PF_RING not enabled. Make sure " - "to pass --enable-pfring to configure when building."); - return TM_ECODE_FAILED; + SCLogError("PF_RING not enabled. Make sure " + "to pass --enable-pfring to configure when building."); + return TM_ECODE_FAILED; #endif /* HAVE_PFRING */ - } - else if(strcmp((long_opts[option_index]).name , "pfring-cluster-type") == 0){ + } else if (strcmp((long_opts[option_index]).name, "pfring-cluster-type") == 0) { #ifdef HAVE_PFRING - if (ConfSetFinal("pfring.cluster-type", optarg) != 1) { - SCLogError("failed to set pfring.cluster-type"); - return TM_ECODE_FAILED; - } + if (ConfSetFinal("pfring.cluster-type", optarg) != 1) { + SCLogError("failed to set pfring.cluster-type"); + return TM_ECODE_FAILED; + } #else - SCLogError("PF_RING not enabled. Make sure " - "to pass --enable-pfring to configure when building."); - return TM_ECODE_FAILED; -#endif /* HAVE_PFRING */ - } - else if (strcmp((long_opts[option_index]).name , "capture-plugin") == 0){ - suri->run_mode = RUNMODE_PLUGIN; - suri->capture_plugin_name = optarg; - } - else if (strcmp((long_opts[option_index]).name , "capture-plugin-args") == 0){ - suri->capture_plugin_args = optarg; - } else if (strcmp((long_opts[option_index]).name, "dpdk") == 0) { - if (ParseCommandLineDpdk(suri, optarg) != TM_ECODE_OK) { - return TM_ECODE_FAILED; - } - } else if (strcmp((long_opts[option_index]).name, "af-packet") == 0) { - if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { - return TM_ECODE_FAILED; - } - } else if (strcmp((long_opts[option_index]).name, "af-xdp") == 0) { - if (ParseCommandLineAfxdp(suri, optarg) != TM_ECODE_OK) { + SCLogError("PF_RING not enabled. Make sure " + "to pass --enable-pfring to configure when building."); return TM_ECODE_FAILED; - } - } else if (strcmp((long_opts[option_index]).name, "netmap") == 0) { -#ifdef HAVE_NETMAP - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_NETMAP; - if (optarg) { - LiveRegisterDeviceName(optarg); - memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - strlcpy(suri->pcap_dev, optarg, - ((strlen(optarg) < sizeof(suri->pcap_dev)) ? - (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); +#endif /* HAVE_PFRING */ + } else if (strcmp((long_opts[option_index]).name, "capture-plugin") == 0) { + suri->run_mode = RUNMODE_PLUGIN; + suri->capture_plugin_name = optarg; + } else if (strcmp((long_opts[option_index]).name, "capture-plugin-args") == 0) { + suri->capture_plugin_args = optarg; + } else if (strcmp((long_opts[option_index]).name, "dpdk") == 0) { + if (ParseCommandLineDpdk(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; } - } else if (suri->run_mode == RUNMODE_NETMAP) { - if (optarg) { - LiveRegisterDeviceName(optarg); + } else if (strcmp((long_opts[option_index]).name, "af-packet") == 0) { + if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "af-xdp") == 0) { + if (ParseCommandLineAfxdp(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "netmap") == 0) { +#ifdef HAVE_NETMAP + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_NETMAP; + if (optarg) { + LiveRegisterDeviceName(optarg); + memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); + strlcpy(suri->pcap_dev, optarg, + ((strlen(optarg) < sizeof(suri->pcap_dev)) + ? (strlen(optarg) + 1) + : sizeof(suri->pcap_dev))); + } + } else if (suri->run_mode == RUNMODE_NETMAP) { + if (optarg) { + LiveRegisterDeviceName(optarg); + } else { + SCLogInfo( + "Multiple netmap option without interface on each is useless"); + break; + } } else { - SCLogInfo("Multiple netmap option without interface on each is useless"); - break; + SCLogError("more than one run mode " + "has been specified"); + PrintUsage(argv[0]); + return TM_ECODE_FAILED; } - } else { - SCLogError("more than one run mode " - "has been specified"); - PrintUsage(argv[0]); - return TM_ECODE_FAILED; - } #else - SCLogError("NETMAP not enabled."); - return TM_ECODE_FAILED; + SCLogError("NETMAP not enabled."); + return TM_ECODE_FAILED; #endif - } else if (strcmp((long_opts[option_index]).name, "nflog") == 0) { + } else if (strcmp((long_opts[option_index]).name, "nflog") == 0) { #ifdef HAVE_NFLOG - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_NFLOG; - LiveBuildDeviceListCustom("nflog", "group"); - } + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_NFLOG; + LiveBuildDeviceListCustom("nflog", "group"); + } #else - SCLogError("NFLOG not enabled."); - return TM_ECODE_FAILED; -#endif /* HAVE_NFLOG */ - } else if (strcmp((long_opts[option_index]).name, "pcap") == 0) { - if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { + SCLogError("NFLOG not enabled."); return TM_ECODE_FAILED; - } - } else if (strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { - SCLogInfo("Setting IPS mode"); - EngineModeSetIPS(); - } else if (strcmp((long_opts[option_index]).name, "init-errors-fatal") == 0) { - if (ConfSetFinal("engine.init-failure-fatal", "1") != 1) { - SCLogError("failed to set engine init-failure-fatal"); - return TM_ECODE_FAILED; - } +#endif /* HAVE_NFLOG */ + } else if (strcmp((long_opts[option_index]).name, "pcap") == 0) { + if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { + SCLogInfo("Setting IPS mode"); + EngineModeSetIPS(); + } else if (strcmp((long_opts[option_index]).name, "init-errors-fatal") == 0) { + if (ConfSetFinal("engine.init-failure-fatal", "1") != 1) { + SCLogError("failed to set engine init-failure-fatal"); + return TM_ECODE_FAILED; + } #ifdef BUILD_UNIX_SOCKET - } else if (strcmp((long_opts[option_index]).name , "unix-socket") == 0) { - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_UNIX_SOCKET; - if (optarg) { - if (ConfSetFinal("unix-command.filename", optarg) != 1) { - SCLogError("failed to set unix-command.filename"); - return TM_ECODE_FAILED; + } else if (strcmp((long_opts[option_index]).name, "unix-socket") == 0) { + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_UNIX_SOCKET; + if (optarg) { + if (ConfSetFinal("unix-command.filename", optarg) != 1) { + SCLogError("failed to set unix-command.filename"); + return TM_ECODE_FAILED; + } } - + } else { + SCLogError("more than one run mode " + "has been specified"); + PrintUsage(argv[0]); + return TM_ECODE_FAILED; } - } else { - SCLogError("more than one run mode " - "has been specified"); - PrintUsage(argv[0]); - return TM_ECODE_FAILED; - } #endif - } - else if(strcmp((long_opts[option_index]).name, "list-app-layer-protocols") == 0) { - /* listing all supported app layer protocols */ - } - else if(strcmp((long_opts[option_index]).name, "list-unittests") == 0) { + } else if (strcmp((long_opts[option_index]).name, "list-app-layer-protocols") == + 0) { + /* listing all supported app layer protocols */ + } else if (strcmp((long_opts[option_index]).name, "list-unittests") == 0) { #ifdef UNITTESTS - suri->run_mode = RUNMODE_LIST_UNITTEST; + suri->run_mode = RUNMODE_LIST_UNITTEST; #else - SCLogError("unit tests not enabled. Make sure to pass --enable-unittests to " - "configure when building"); - return TM_ECODE_FAILED; + SCLogError("unit tests not enabled. Make sure to pass --enable-unittests to " + "configure when building"); + return TM_ECODE_FAILED; #endif /* UNITTESTS */ - } else if (strcmp((long_opts[option_index]).name, "list-runmodes") == 0) { - suri->run_mode = RUNMODE_LIST_RUNMODES; - return TM_ECODE_OK; - } else if (strcmp((long_opts[option_index]).name, "list-keywords") == 0) { - if (optarg) { - if (strcmp("short",optarg)) { - suri->keyword_info = optarg; + } else if (strcmp((long_opts[option_index]).name, "list-runmodes") == 0) { + suri->run_mode = RUNMODE_LIST_RUNMODES; + return TM_ECODE_OK; + } else if (strcmp((long_opts[option_index]).name, "list-keywords") == 0) { + if (optarg) { + if (strcmp("short", optarg)) { + suri->keyword_info = optarg; + } } + } else if (strcmp((long_opts[option_index]).name, "runmode") == 0) { + suri->runmode_custom_mode = optarg; + } else if (strcmp((long_opts[option_index]).name, "engine-analysis") == 0) { + // do nothing for now } - } else if (strcmp((long_opts[option_index]).name, "runmode") == 0) { - suri->runmode_custom_mode = optarg; - } else if(strcmp((long_opts[option_index]).name, "engine-analysis") == 0) { - // do nothing for now - } #ifdef OS_WIN32 - else if(strcmp((long_opts[option_index]).name, "service-install") == 0) { - suri->run_mode = RUNMODE_INSTALL_SERVICE; - return TM_ECODE_OK; - } - else if(strcmp((long_opts[option_index]).name, "service-remove") == 0) { - suri->run_mode = RUNMODE_REMOVE_SERVICE; - return TM_ECODE_OK; - } - else if(strcmp((long_opts[option_index]).name, "service-change-params") == 0) { - suri->run_mode = RUNMODE_CHANGE_SERVICE_PARAMS; - return TM_ECODE_OK; - } -#endif /* OS_WIN32 */ - else if(strcmp((long_opts[option_index]).name, "pidfile") == 0) { - suri->pid_filename = SCStrdup(optarg); - if (suri->pid_filename == NULL) { - SCLogError("strdup failed: %s", strerror(errno)); - return TM_ECODE_FAILED; + else if (strcmp((long_opts[option_index]).name, "service-install") == 0) { + suri->run_mode = RUNMODE_INSTALL_SERVICE; + return TM_ECODE_OK; + } else if (strcmp((long_opts[option_index]).name, "service-remove") == 0) { + suri->run_mode = RUNMODE_REMOVE_SERVICE; + return TM_ECODE_OK; + } else if (strcmp((long_opts[option_index]).name, "service-change-params") == 0) { + suri->run_mode = RUNMODE_CHANGE_SERVICE_PARAMS; + return TM_ECODE_OK; } - } - else if(strcmp((long_opts[option_index]).name, "disable-detection") == 0) { - g_detect_disabled = suri->disabled_detect = 1; - } else if (strcmp((long_opts[option_index]).name, "disable-hashing") == 0) { - g_disable_hashing = true; - } else if (strcmp((long_opts[option_index]).name, "fatal-unittests") == 0) { +#endif /* OS_WIN32 */ + else if (strcmp((long_opts[option_index]).name, "pidfile") == 0) { + suri->pid_filename = SCStrdup(optarg); + if (suri->pid_filename == NULL) { + SCLogError("strdup failed: %s", strerror(errno)); + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "disable-detection") == 0) { + g_detect_disabled = suri->disabled_detect = 1; + } else if (strcmp((long_opts[option_index]).name, "disable-hashing") == 0) { + g_disable_hashing = true; + } else if (strcmp((long_opts[option_index]).name, "fatal-unittests") == 0) { #ifdef UNITTESTS - unittests_fatal = 1; + unittests_fatal = 1; #else - SCLogError("unit tests not enabled. Make sure to pass --enable-unittests to " - "configure when building"); - return TM_ECODE_FAILED; + SCLogError("unit tests not enabled. Make sure to pass --enable-unittests to " + "configure when building"); + return TM_ECODE_FAILED; #endif /* UNITTESTS */ - } else if (strcmp((long_opts[option_index]).name, "user") == 0) { + } else if (strcmp((long_opts[option_index]).name, "user") == 0) { #ifndef HAVE_LIBCAP_NG - SCLogError("libcap-ng is required to" - " drop privileges, but it was not compiled into Suricata."); - return TM_ECODE_FAILED; + SCLogError("libcap-ng is required to" + " drop privileges, but it was not compiled into Suricata."); + return TM_ECODE_FAILED; #else - suri->user_name = optarg; - suri->do_setuid = true; + suri->user_name = optarg; + suri->do_setuid = true; #endif /* HAVE_LIBCAP_NG */ - } else if (strcmp((long_opts[option_index]).name, "group") == 0) { + } else if (strcmp((long_opts[option_index]).name, "group") == 0) { #ifndef HAVE_LIBCAP_NG - SCLogError("libcap-ng is required to" - " drop privileges, but it was not compiled into Suricata."); - return TM_ECODE_FAILED; + SCLogError("libcap-ng is required to" + " drop privileges, but it was not compiled into Suricata."); + return TM_ECODE_FAILED; #else - suri->group_name = optarg; - suri->do_setgid = true; + suri->group_name = optarg; + suri->do_setgid = true; #endif /* HAVE_LIBCAP_NG */ - } else if (strcmp((long_opts[option_index]).name, "erf-in") == 0) { - suri->run_mode = RUNMODE_ERF_FILE; - if (ConfSetFinal("erf-file.file", optarg) != 1) { - SCLogError("failed to set erf-file.file"); - return TM_ECODE_FAILED; - } - } else if (strcmp((long_opts[option_index]).name, "dag") == 0) { + } else if (strcmp((long_opts[option_index]).name, "erf-in") == 0) { + suri->run_mode = RUNMODE_ERF_FILE; + if (ConfSetFinal("erf-file.file", optarg) != 1) { + SCLogError("failed to set erf-file.file"); + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "dag") == 0) { #ifdef HAVE_DAG - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_DAG; - } - else if (suri->run_mode != RUNMODE_DAG) { - SCLogError("more than one run mode has been specified"); - PrintUsage(argv[0]); - return TM_ECODE_FAILED; - } - LiveRegisterDeviceName(optarg); + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_DAG; + } else if (suri->run_mode != RUNMODE_DAG) { + SCLogError("more than one run mode has been specified"); + PrintUsage(argv[0]); + return TM_ECODE_FAILED; + } + LiveRegisterDeviceName(optarg); #else - SCLogError("libdag and a DAG card are required" - " to receive packets using --dag."); - return TM_ECODE_FAILED; + SCLogError("libdag and a DAG card are required" + " to receive packets using --dag."); + return TM_ECODE_FAILED; #endif /* HAVE_DAG */ - } else if (strcmp((long_opts[option_index]).name, "napatech") == 0) { + } else if (strcmp((long_opts[option_index]).name, "napatech") == 0) { #ifdef HAVE_NAPATECH - suri->run_mode = RUNMODE_NAPATECH; + suri->run_mode = RUNMODE_NAPATECH; #else - SCLogError("libntapi and a Napatech adapter are required" - " to capture packets using --napatech."); - return TM_ECODE_FAILED; + SCLogError("libntapi and a Napatech adapter are required" + " to capture packets using --napatech."); + return TM_ECODE_FAILED; #endif /* HAVE_NAPATECH */ - } else if (strcmp((long_opts[option_index]).name, "pcap-buffer-size") == 0) { + } else if (strcmp((long_opts[option_index]).name, "pcap-buffer-size") == 0) { #ifdef HAVE_PCAP_SET_BUFF - if (ConfSetFinal("pcap.buffer-size", optarg) != 1) { - SCLogError("failed to set pcap-buffer-size"); - return TM_ECODE_FAILED; - } + if (ConfSetFinal("pcap.buffer-size", optarg) != 1) { + SCLogError("failed to set pcap-buffer-size"); + return TM_ECODE_FAILED; + } #else - SCLogError("The version of libpcap you have" - " doesn't support setting buffer size."); + SCLogError("The version of libpcap you have" + " doesn't support setting buffer size."); #endif /* HAVE_PCAP_SET_BUFF */ - } else if (strcmp((long_opts[option_index]).name, "build-info") == 0) { - suri->run_mode = RUNMODE_PRINT_BUILDINFO; - return TM_ECODE_OK; - } else if (strcmp((long_opts[option_index]).name, "windivert-forward") == 0) { + } else if (strcmp((long_opts[option_index]).name, "build-info") == 0) { + suri->run_mode = RUNMODE_PRINT_BUILDINFO; + return TM_ECODE_OK; + } else if (strcmp((long_opts[option_index]).name, "windivert-forward") == 0) { #ifdef WINDIVERT - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_WINDIVERT; - if (WinDivertRegisterQueue(true, optarg) == -1) { - exit(EXIT_FAILURE); - } - } else if (suri->run_mode == RUNMODE_WINDIVERT) { - if (WinDivertRegisterQueue(true, optarg) == -1) { - exit(EXIT_FAILURE); - } - } else { - SCLogError("more than one run mode " - "has been specified"); - PrintUsage(argv[0]); - exit(EXIT_FAILURE); - } - } - else if(strcmp((long_opts[option_index]).name, "windivert") == 0) { - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_WINDIVERT; - if (WinDivertRegisterQueue(false, optarg) == -1) { + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_WINDIVERT; + if (WinDivertRegisterQueue(true, optarg) == -1) { + exit(EXIT_FAILURE); + } + } else if (suri->run_mode == RUNMODE_WINDIVERT) { + if (WinDivertRegisterQueue(true, optarg) == -1) { + exit(EXIT_FAILURE); + } + } else { + SCLogError("more than one run mode " + "has been specified"); + PrintUsage(argv[0]); exit(EXIT_FAILURE); } - } else if (suri->run_mode == RUNMODE_WINDIVERT) { - if (WinDivertRegisterQueue(false, optarg) == -1) { + } else if (strcmp((long_opts[option_index]).name, "windivert") == 0) { + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_WINDIVERT; + if (WinDivertRegisterQueue(false, optarg) == -1) { + exit(EXIT_FAILURE); + } + } else if (suri->run_mode == RUNMODE_WINDIVERT) { + if (WinDivertRegisterQueue(false, optarg) == -1) { + exit(EXIT_FAILURE); + } + } else { + SCLogError("more than one run mode " + "has been specified"); + PrintUsage(argv[0]); exit(EXIT_FAILURE); } - } else { - SCLogError("more than one run mode " - "has been specified"); - PrintUsage(argv[0]); - exit(EXIT_FAILURE); - } #else - SCLogError("WinDivert not enabled. Make sure to pass --enable-windivert to " - "configure when building."); - return TM_ECODE_FAILED; + SCLogError("WinDivert not enabled. Make sure to pass --enable-windivert to " + "configure when building."); + return TM_ECODE_FAILED; #endif /* WINDIVERT */ - } else if(strcmp((long_opts[option_index]).name, "reject-dev") == 0) { + } else if (strcmp((long_opts[option_index]).name, "reject-dev") == 0) { #ifdef HAVE_LIBNET11 - BUG_ON(optarg == NULL); /* for static analysis */ - extern char *g_reject_dev; - extern uint16_t g_reject_dev_mtu; - g_reject_dev = optarg; - int mtu = GetIfaceMTU(g_reject_dev); - if (mtu > 0) { - g_reject_dev_mtu = (uint16_t)mtu; - } + BUG_ON(optarg == NULL); /* for static analysis */ + extern char *g_reject_dev; + extern uint16_t g_reject_dev_mtu; + g_reject_dev = optarg; + int mtu = GetIfaceMTU(g_reject_dev); + if (mtu > 0) { + g_reject_dev_mtu = (uint16_t)mtu; + } #else - SCLogError("Libnet 1.1 support not enabled. Compile Suricata with libnet support."); - return TM_ECODE_FAILED; + SCLogError("Libnet 1.1 support not enabled. Compile Suricata with libnet " + "support."); + return TM_ECODE_FAILED; #endif - } - else if (strcmp((long_opts[option_index]).name, "set") == 0) { - if (optarg != NULL) { - /* Quick validation. */ - char *val = strchr(optarg, '='); - if (val == NULL) { - FatalError("Invalid argument for --set, must be key=val."); + } else if (strcmp((long_opts[option_index]).name, "set") == 0) { + if (optarg != NULL) { + /* Quick validation. */ + char *val = strchr(optarg, '='); + if (val == NULL) { + FatalError("Invalid argument for --set, must be key=val."); + } + if (!ConfSetFromString(optarg, 1)) { + FatalError("failed to set configuration value %s", optarg); + } } - if (!ConfSetFromString(optarg, 1)) { - FatalError("failed to set configuration value %s", optarg); + } else if (strcmp((long_opts[option_index]).name, "pcap-file-continuous") == 0) { + if (ConfSetFinal("pcap-file.continuous", "true") != 1) { + SCLogError("Failed to set pcap-file.continuous"); + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "pcap-file-delete") == 0) { + if (ConfSetFinal("pcap-file.delete-when-done", "true") != 1) { + SCLogError("Failed to set pcap-file.delete-when-done"); + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "pcap-file-recursive") == 0) { + if (ConfSetFinal("pcap-file.recursive", "true") != 1) { + SCLogError("failed to set pcap-file.recursive"); + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name, "data-dir") == 0) { + if (optarg == NULL) { + SCLogError("no option argument (optarg) for -d"); + return TM_ECODE_FAILED; } - } - } - else if (strcmp((long_opts[option_index]).name, "pcap-file-continuous") == 0) { - if (ConfSetFinal("pcap-file.continuous", "true") != 1) { - SCLogError("Failed to set pcap-file.continuous"); - return TM_ECODE_FAILED; - } - } - else if (strcmp((long_opts[option_index]).name, "pcap-file-delete") == 0) { - if (ConfSetFinal("pcap-file.delete-when-done", "true") != 1) { - SCLogError("Failed to set pcap-file.delete-when-done"); - return TM_ECODE_FAILED; - } - } - else if (strcmp((long_opts[option_index]).name, "pcap-file-recursive") == 0) { - if (ConfSetFinal("pcap-file.recursive", "true") != 1) { - SCLogError("failed to set pcap-file.recursive"); - return TM_ECODE_FAILED; - } - } - else if (strcmp((long_opts[option_index]).name, "data-dir") == 0) { - if (optarg == NULL) { - SCLogError("no option argument (optarg) for -d"); - return TM_ECODE_FAILED; - } - if (ConfigSetDataDirectory(optarg) != TM_ECODE_OK) { - SCLogError("Failed to set data directory."); - return TM_ECODE_FAILED; - } - if (ConfigCheckDataDirectory(optarg) != TM_ECODE_OK) { - SCLogError("The data directory \"%s\"" - " supplied at the command-line (-d %s) doesn't " - "exist. Shutting down the engine.", - optarg, optarg); - return TM_ECODE_FAILED; - } - suri->set_datadir = true; - } else if (strcmp((long_opts[option_index]).name , "strict-rule-keywords") == 0){ - if (optarg == NULL) { - suri->strict_rule_parsing_string = SCStrdup("all"); - } else { - suri->strict_rule_parsing_string = SCStrdup(optarg); - } - if (suri->strict_rule_parsing_string == NULL) { - FatalError("failed to duplicate 'strict' string"); - } - } else if (strcmp((long_opts[option_index]).name, "include") == 0) { - if (suri->additional_configs == NULL) { - suri->additional_configs = SCCalloc(2, sizeof(char *)); - if (suri->additional_configs == NULL) { - FatalError( - "Failed to allocate memory for additional configuration files: %s", - strerror(errno)); + if (ConfigSetDataDirectory(optarg) != TM_ECODE_OK) { + SCLogError("Failed to set data directory."); + return TM_ECODE_FAILED; } - suri->additional_configs[0] = optarg; - } else { - for (int i = 0;; i++) { - if (suri->additional_configs[i] == NULL) { - const char **additional_configs = - SCRealloc(suri->additional_configs, (i + 2) * sizeof(char *)); - if (additional_configs == NULL) { - FatalError("Failed to allocate memory for additional configuration " - "files: %s", - strerror(errno)); - } else { - suri->additional_configs = additional_configs; + if (ConfigCheckDataDirectory(optarg) != TM_ECODE_OK) { + SCLogError("The data directory \"%s\"" + " supplied at the command-line (-d %s) doesn't " + "exist. Shutting down the engine.", + optarg, optarg); + return TM_ECODE_FAILED; + } + suri->set_datadir = true; + } else if (strcmp((long_opts[option_index]).name, "strict-rule-keywords") == 0) { + if (optarg == NULL) { + suri->strict_rule_parsing_string = SCStrdup("all"); + } else { + suri->strict_rule_parsing_string = SCStrdup(optarg); + } + if (suri->strict_rule_parsing_string == NULL) { + FatalError("failed to duplicate 'strict' string"); + } + } else if (strcmp((long_opts[option_index]).name, "include") == 0) { + if (suri->additional_configs == NULL) { + suri->additional_configs = SCCalloc(2, sizeof(char *)); + if (suri->additional_configs == NULL) { + FatalError("Failed to allocate memory for additional configuration " + "files: %s", + strerror(errno)); + } + suri->additional_configs[0] = optarg; + } else { + for (int i = 0;; i++) { + if (suri->additional_configs[i] == NULL) { + const char **additional_configs = SCRealloc( + suri->additional_configs, (i + 2) * sizeof(char *)); + if (additional_configs == NULL) { + FatalError("Failed to allocate memory for additional " + "configuration " + "files: %s", + strerror(errno)); + } else { + suri->additional_configs = additional_configs; + } + suri->additional_configs[i] = optarg; + suri->additional_configs[i + 1] = NULL; + break; } - suri->additional_configs[i] = optarg; - suri->additional_configs[i + 1] = NULL; - break; } } + } else { + int r = ExceptionSimulationCommandLineParser( + (long_opts[option_index]).name, optarg); + if (r < 0) + return TM_ECODE_FAILED; } - } else { - int r = ExceptionSimulationCommandLineParser( - (long_opts[option_index]).name, optarg); - if (r < 0) + break; + case 'c': + suri->conf_filename = optarg; + break; + case 'T': + conf_test = 1; + if (ConfSetFinal("engine.init-failure-fatal", "1") != 1) { + SCLogError("failed to set engine init-failure-fatal"); return TM_ECODE_FAILED; - } - break; - case 'c': - suri->conf_filename = optarg; - break; - case 'T': - conf_test = 1; - if (ConfSetFinal("engine.init-failure-fatal", "1") != 1) { - SCLogError("failed to set engine init-failure-fatal"); - return TM_ECODE_FAILED; - } - break; + } + break; #ifndef OS_WIN32 - case 'D': - suri->daemon = 1; - break; + case 'D': + suri->daemon = 1; + break; #endif /* OS_WIN32 */ - case 'h': - suri->run_mode = RUNMODE_PRINT_USAGE; - return TM_ECODE_OK; - case 'i': - if (optarg == NULL) { - SCLogError("no option argument (optarg) for -i"); - return TM_ECODE_FAILED; - } + case 'h': + suri->run_mode = RUNMODE_PRINT_USAGE; + return TM_ECODE_OK; + case 'i': + if (optarg == NULL) { + SCLogError("no option argument (optarg) for -i"); + return TM_ECODE_FAILED; + } #ifdef HAVE_AF_PACKET - if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { - return TM_ECODE_FAILED; - } + if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } #else /* not afpacket */ - /* warn user if netmap or pf-ring are available */ + /* warn user if netmap or pf-ring are available */ #if defined HAVE_PFRING || HAVE_NETMAP - int i = 0; + int i = 0; #ifdef HAVE_PFRING - i++; + i++; #endif #ifdef HAVE_NETMAP - i++; + i++; #endif - SCLogWarning("faster capture " - "option%s %s available:" + SCLogWarning("faster capture " + "option%s %s available:" #ifdef HAVE_PFRING - " PF_RING (--pfring-int=%s)" + " PF_RING (--pfring-int=%s)" #endif #ifdef HAVE_NETMAP - " NETMAP (--netmap=%s)" + " NETMAP (--netmap=%s)" #endif - ". Use --pcap=%s to suppress this warning", - i == 1 ? "" : "s", i == 1 ? "is" : "are" + ". Use --pcap=%s to suppress this warning", + i == 1 ? "" : "s", i == 1 ? "is" : "are" #ifdef HAVE_PFRING - , - optarg + , + optarg #endif #ifdef HAVE_NETMAP - , - optarg + , + optarg #endif - , - optarg); + , + optarg); #endif /* have faster methods */ - if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { - return TM_ECODE_FAILED; - } + if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } #endif - break; - case 'l': - if (optarg == NULL) { - SCLogError("no option argument (optarg) for -l"); - return TM_ECODE_FAILED; - } + break; + case 'l': + if (optarg == NULL) { + SCLogError("no option argument (optarg) for -l"); + return TM_ECODE_FAILED; + } - if (ConfigSetLogDirectory(optarg) != TM_ECODE_OK) { - SCLogError("Failed to set log directory."); - return TM_ECODE_FAILED; - } - if (ConfigCheckLogDirectoryExists(optarg) != TM_ECODE_OK) { - SCLogError("The logging directory \"%s\"" - " supplied at the command-line (-l %s) doesn't " - "exist. Shutting down the engine.", - optarg, optarg); - return TM_ECODE_FAILED; - } - if (!IsLogDirectoryWritable(optarg)) { - SCLogError("The logging directory \"%s\"" - " supplied at the command-line (-l %s) is not " - "writable. Shutting down the engine.", - optarg, optarg); - return TM_ECODE_FAILED; - } - suri->set_logdir = true; + if (ConfigSetLogDirectory(optarg) != TM_ECODE_OK) { + SCLogError("Failed to set log directory."); + return TM_ECODE_FAILED; + } + if (ConfigCheckLogDirectoryExists(optarg) != TM_ECODE_OK) { + SCLogError("The logging directory \"%s\"" + " supplied at the command-line (-l %s) doesn't " + "exist. Shutting down the engine.", + optarg, optarg); + return TM_ECODE_FAILED; + } + if (!IsLogDirectoryWritable(optarg)) { + SCLogError("The logging directory \"%s\"" + " supplied at the command-line (-l %s) is not " + "writable. Shutting down the engine.", + optarg, optarg); + return TM_ECODE_FAILED; + } + suri->set_logdir = true; - break; - case 'q': + break; + case 'q': #ifdef NFQ - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_NFQ; - EngineModeSetIPS(); - if (NFQParseAndRegisterQueues(optarg) == -1) - return TM_ECODE_FAILED; - } else if (suri->run_mode == RUNMODE_NFQ) { - if (NFQParseAndRegisterQueues(optarg) == -1) + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_NFQ; + EngineModeSetIPS(); + if (NFQParseAndRegisterQueues(optarg) == -1) + return TM_ECODE_FAILED; + } else if (suri->run_mode == RUNMODE_NFQ) { + if (NFQParseAndRegisterQueues(optarg) == -1) + return TM_ECODE_FAILED; + } else { + SCLogError("more than one run mode " + "has been specified"); + PrintUsage(argv[0]); return TM_ECODE_FAILED; - } else { - SCLogError("more than one run mode " - "has been specified"); - PrintUsage(argv[0]); - return TM_ECODE_FAILED; - } + } #else - SCLogError("NFQUEUE not enabled. Make sure to pass --enable-nfqueue to configure when " - "building."); - return TM_ECODE_FAILED; + SCLogError( + "NFQUEUE not enabled. Make sure to pass --enable-nfqueue to configure when " + "building."); + return TM_ECODE_FAILED; #endif /* NFQ */ - break; - case 'd': + break; + case 'd': #ifdef IPFW - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_IPFW; - EngineModeSetIPS(); - if (IPFWRegisterQueue(optarg) == -1) - return TM_ECODE_FAILED; - } else if (suri->run_mode == RUNMODE_IPFW) { - if (IPFWRegisterQueue(optarg) == -1) + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_IPFW; + EngineModeSetIPS(); + if (IPFWRegisterQueue(optarg) == -1) + return TM_ECODE_FAILED; + } else if (suri->run_mode == RUNMODE_IPFW) { + if (IPFWRegisterQueue(optarg) == -1) + return TM_ECODE_FAILED; + } else { + SCLogError("more than one run mode " + "has been specified"); + PrintUsage(argv[0]); return TM_ECODE_FAILED; - } else { - SCLogError("more than one run mode " - "has been specified"); - PrintUsage(argv[0]); - return TM_ECODE_FAILED; - } + } #else - SCLogError("IPFW not enabled. Make sure to pass --enable-ipfw to configure when " - "building."); - return TM_ECODE_FAILED; -#endif /* IPFW */ - break; - case 'r': - BUG_ON(optarg == NULL); /* for static analysis */ - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_PCAP_FILE; - } else { - SCLogError("more than one run mode " - "has been specified"); - PrintUsage(argv[0]); + SCLogError("IPFW not enabled. Make sure to pass --enable-ipfw to configure when " + "building."); return TM_ECODE_FAILED; - } - SCStat buf; - if (SCStatFn(optarg, &buf) != 0) { - SCLogError("pcap file '%s': %s", optarg, strerror(errno)); - return TM_ECODE_FAILED; - } - if (ConfSetFinal("pcap-file.file", optarg) != 1) { - SCLogError("ERROR: Failed to set pcap-file.file\n"); - return TM_ECODE_FAILED; - } +#endif /* IPFW */ + break; + case 'r': + BUG_ON(optarg == NULL); /* for static analysis */ + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_PCAP_FILE; + } else { + SCLogError("more than one run mode " + "has been specified"); + PrintUsage(argv[0]); + return TM_ECODE_FAILED; + } + SCStat buf; + if (SCStatFn(optarg, &buf) != 0) { + SCLogError("pcap file '%s': %s", optarg, strerror(errno)); + return TM_ECODE_FAILED; + } + if (ConfSetFinal("pcap-file.file", optarg) != 1) { + SCLogError("ERROR: Failed to set pcap-file.file\n"); + return TM_ECODE_FAILED; + } - break; - case 's': - if (suri->sig_file != NULL) { - SCLogError("can't have multiple -s options or mix -s and -S."); - return TM_ECODE_FAILED; - } - suri->sig_file = optarg; - break; - case 'S': - if (suri->sig_file != NULL) { - SCLogError("can't have multiple -S options or mix -s and -S."); - return TM_ECODE_FAILED; - } - suri->sig_file = optarg; - suri->sig_file_exclusive = true; - break; - case 'u': + break; + case 's': + if (suri->sig_file != NULL) { + SCLogError("can't have multiple -s options or mix -s and -S."); + return TM_ECODE_FAILED; + } + suri->sig_file = optarg; + break; + case 'S': + if (suri->sig_file != NULL) { + SCLogError("can't have multiple -S options or mix -s and -S."); + return TM_ECODE_FAILED; + } + suri->sig_file = optarg; + suri->sig_file_exclusive = true; + break; + case 'u': #ifdef UNITTESTS - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_UNITTEST; - } else { - SCLogError("more than one run mode has" - " been specified"); - PrintUsage(argv[0]); - return TM_ECODE_FAILED; - } + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_UNITTEST; + } else { + SCLogError("more than one run mode has" + " been specified"); + PrintUsage(argv[0]); + return TM_ECODE_FAILED; + } #else - SCLogError("unit tests not enabled. Make sure to pass --enable-unittests to configure " - "when building."); - return TM_ECODE_FAILED; + SCLogError( + "unit tests not enabled. Make sure to pass --enable-unittests to configure " + "when building."); + return TM_ECODE_FAILED; #endif /* UNITTESTS */ - break; - case 'U': + break; + case 'U': #ifdef UNITTESTS - suri->regex_arg = optarg; + suri->regex_arg = optarg; - if(strlen(suri->regex_arg) == 0) - suri->regex_arg = NULL; + if (strlen(suri->regex_arg) == 0) + suri->regex_arg = NULL; #endif - break; - case 'V': - suri->run_mode = RUNMODE_PRINT_VERSION; - return TM_ECODE_OK; - case 'F': - if (optarg == NULL) { - SCLogError("no option argument (optarg) for -F"); - return TM_ECODE_FAILED; - } + break; + case 'V': + suri->run_mode = RUNMODE_PRINT_VERSION; + return TM_ECODE_OK; + case 'F': + if (optarg == NULL) { + SCLogError("no option argument (optarg) for -F"); + return TM_ECODE_FAILED; + } - SetBpfStringFromFile(optarg); - break; - case 'v': - suri->verbose++; - break; - case 'k': - if (optarg == NULL) { - SCLogError("no option argument (optarg) for -k"); - return TM_ECODE_FAILED; - } - if (!strcmp("all", optarg)) - suri->checksum_validation = 1; - else if (!strcmp("none", optarg)) - suri->checksum_validation = 0; - else { - SCLogError("option '%s' invalid for -k", optarg); + SetBpfStringFromFile(optarg); + break; + case 'v': + suri->verbose++; + break; + case 'k': + if (optarg == NULL) { + SCLogError("no option argument (optarg) for -k"); + return TM_ECODE_FAILED; + } + if (!strcmp("all", optarg)) + suri->checksum_validation = 1; + else if (!strcmp("none", optarg)) + suri->checksum_validation = 0; + else { + SCLogError("option '%s' invalid for -k", optarg); + return TM_ECODE_FAILED; + } + break; + default: + PrintUsage(argv[0]); return TM_ECODE_FAILED; - } - break; - default: - PrintUsage(argv[0]); - return TM_ECODE_FAILED; } } @@ -2298,11 +2304,10 @@ void PostRunDeinit(const int runmode, struct timeval *start_time) #endif } - static int StartInternalRunMode(SCInstance *suri, int argc, char **argv) { /* Treat internal running mode */ - switch(suri->run_mode) { + switch (suri->run_mode) { case RUNMODE_LIST_KEYWORDS: return ListKeywords(suri->keyword_info); case RUNMODE_LIST_APP_LAYERS: @@ -2383,9 +2388,10 @@ static void SetupDelayedDetect(SCInstance *suri) ConfNode *denode = NULL; ConfNode *decnf = ConfGetNode("detect-engine"); if (decnf != NULL) { - TAILQ_FOREACH(denode, &decnf->head, next) { + TAILQ_FOREACH (denode, &decnf->head, next) { if (strcmp(denode->val, "delayed-detect") == 0) { - (void)ConfGetChildValueBool(denode, "delayed-detect", &suri->delayed_detect); + (void)ConfGetChildValueBool( + denode, "delayed-detect", &suri->delayed_detect); } } } @@ -2396,7 +2402,6 @@ static void SetupDelayedDetect(SCInstance *suri) if (suri->delayed_detect) { SCLogInfo("Packets will start being processed before signatures are active."); } - } static int LoadSignatures(DetectEngineCtx *de_ctx, SCInstance *suri) @@ -2467,12 +2472,9 @@ static int ConfigGetCaptureValue(SCInstance *suri) if (strip_trailing_plus) { size_t len = strlen(dev); - if (len && - (dev[len-1] == '+' || - dev[len-1] == '^' || - dev[len-1] == '*')) - { - dev[len-1] = '\0'; + if (len && (dev[len - 1] == '+' || dev[len - 1] == '^' || + dev[len - 1] == '*')) { + dev[len - 1] = '\0'; } } LiveDevice *ld = LiveGetDevice(dev); @@ -2495,7 +2497,7 @@ static int ConfigGetCaptureValue(SCInstance *suri) } } - SCLogDebug("Default packet size set to %"PRIu32, default_packet_size); + SCLogDebug("Default packet size set to %" PRIu32, default_packet_size); return TM_ECODE_OK; } @@ -2693,7 +2695,6 @@ int PostConfLoadedSetup(SCInstance *suri) } } - if (ConfigGetCaptureValue(suri) != TM_ECODE_OK) { SCReturnInt(TM_ECODE_FAILED); } @@ -2796,7 +2797,7 @@ int PostConfLoadedSetup(SCInstance *suri) static void SuricataMainLoop(SCInstance *suri) { - while(1) { + while (1) { if (sigterm_count || sigint_count) { suricata_ctl_flags |= SURICATA_STOP; } @@ -2826,7 +2827,7 @@ static void SuricataMainLoop(SCInstance *suri) DetectEngineReloadSetIdle(); } - usleep(10* 1000); + usleep(10 * 1000); } } @@ -2960,7 +2961,7 @@ int SuricataMain(int argc, char **argv) PostConfLoadedDetectSetup(&suricata); if (suricata.run_mode == RUNMODE_ENGINE_ANALYSIS) { goto out; - } else if (suricata.run_mode == RUNMODE_CONF_TEST){ + } else if (suricata.run_mode == RUNMODE_CONF_TEST) { SCLogNotice("Configuration provided was successfully loaded. Exiting."); goto out; } else if (suricata.run_mode == RUNMODE_DUMP_FEATURES) { @@ -2969,8 +2970,8 @@ int SuricataMain(int argc, char **argv) } SCSetStartTime(&suricata); - RunModeDispatch(suricata.run_mode, suricata.runmode_custom_mode, - suricata.capture_plugin_name, suricata.capture_plugin_args); + RunModeDispatch(suricata.run_mode, suricata.runmode_custom_mode, suricata.capture_plugin_name, + suricata.capture_plugin_args); if (suricata.run_mode != RUNMODE_UNIX_SOCKET) { UnixManagerThreadSpawnNonRunmode(suricata.unix_socket_enabled); } diff --git a/src/suricata.h b/src/suricata.h index 9d275edc5dd0..d1fb37eab9b8 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -68,17 +68,17 @@ /* the name of our binary */ #define PROG_NAME "Suricata" -#define PROG_VER PACKAGE_VERSION +#define PROG_VER PACKAGE_VERSION /* workaround SPlint error (don't know __gnuc_va_list) */ #ifdef S_SPLINT_S -# include -# define CONFIG_DIR "/etc/suricata" +#include +#define CONFIG_DIR "/etc/suricata" #endif #define DEFAULT_CONF_FILE CONFIG_DIR "/suricata.yaml" -#define DEFAULT_PID_DIR LOCAL_STATE_DIR "/run/" +#define DEFAULT_PID_DIR LOCAL_STATE_DIR "/run/" #define DEFAULT_PID_BASENAME "suricata.pid" #define DEFAULT_PID_FILENAME DEFAULT_PID_DIR DEFAULT_PID_BASENAME @@ -86,16 +86,13 @@ const char *GetDocURL(void); /* runtime engine control flags */ -#define SURICATA_STOP (1 << 0) /**< gracefully stop the engine: process all - outstanding packets first */ -#define SURICATA_DONE (1 << 2) /**< packets capture ended */ +#define SURICATA_STOP \ + (1 << 0) /**< gracefully stop the engine: process all \ + outstanding packets first */ +#define SURICATA_DONE (1 << 2) /**< packets capture ended */ /* Engine stage/status*/ -enum { - SURICATA_INIT = 0, - SURICATA_RUNTIME, - SURICATA_DEINIT -}; +enum { SURICATA_INIT = 0, SURICATA_RUNTIME, SURICATA_DEINIT }; /* Engine is acting as */ enum EngineMode { @@ -165,7 +162,6 @@ typedef struct SCInstance_ { const char *capture_plugin_args; } SCInstance; - /* memset to zeros, and mutex init! */ void GlobalsInitPreConfig(void); @@ -204,4 +200,3 @@ void RegisterAllModules(void); const char *GetProgramVersion(void); #endif /* __SURICATA_H__ */ - diff --git a/src/tests/app-layer-htp-file.c b/src/tests/app-layer-htp-file.c index 6f7891c80da9..a5a144c7e6f9 100644 --- a/src/tests/app-layer-htp-file.c +++ b/src/tests/app-layer-htp-file.c @@ -15,18 +15,18 @@ * 02110-1301, USA. */ -#include "../app-layer-htp-file.h" -#include "../util-unittest.h" +#include "../app-layer/http/parser-file.h" +#include "../util/unittest.h" /** * \test AppLayerHtpFileParseContentRangeTest01 is a test * for setting up a valid range value. */ -static int AppLayerHtpFileParseContentRangeTest01 (void) +static int AppLayerHtpFileParseContentRangeTest01(void) { HTTPContentRange range; - bstr * rawvalue = bstr_dup_c("bytes 12-25/100"); + bstr *rawvalue = bstr_dup_c("bytes 12-25/100"); FAIL_IF_NOT(HTPParseContentRange(rawvalue, &range) == 0); FAIL_IF_NOT(range.start == 12); FAIL_IF_NOT(range.end == 25); @@ -40,10 +40,10 @@ static int AppLayerHtpFileParseContentRangeTest01 (void) * for setting up an invalid range value. */ -static int AppLayerHtpFileParseContentRangeTest02 (void) +static int AppLayerHtpFileParseContentRangeTest02(void) { HTTPContentRange range; - bstr * rawvalue = bstr_dup_c("bytes 15335424-27514354/"); + bstr *rawvalue = bstr_dup_c("bytes 15335424-27514354/"); FAIL_IF(HTPParseContentRange(rawvalue, &range) == 0); bstr_free(rawvalue); PASS; @@ -54,25 +54,24 @@ static int AppLayerHtpFileParseContentRangeTest02 (void) * for setting up an invalid range value. */ -static int AppLayerHtpFileParseContentRangeTest03 (void) +static int AppLayerHtpFileParseContentRangeTest03(void) { HTTPContentRange range; - bstr * rawvalue = bstr_dup_c("bytes 15335424-"); + bstr *rawvalue = bstr_dup_c("bytes 15335424-"); FAIL_IF(HTPParseContentRange(rawvalue, &range) == 0); bstr_free(rawvalue); PASS; } - /** * \test AppLayerHtpFileParseContentRangeTest04 is a test * for setting up a valid range value without the size. */ -static int AppLayerHtpFileParseContentRangeTest04 (void) +static int AppLayerHtpFileParseContentRangeTest04(void) { HTTPContentRange range; - bstr * rawvalue = bstr_dup_c("bytes 24-42/*"); + bstr *rawvalue = bstr_dup_c("bytes 24-42/*"); FAIL_IF_NOT(HTPParseContentRange(rawvalue, &range) == 0); FAIL_IF_NOT(range.start == 24); FAIL_IF_NOT(range.end == 42); @@ -85,8 +84,12 @@ static int AppLayerHtpFileParseContentRangeTest04 (void) */ void AppLayerHtpFileRegisterTests(void) { - UtRegisterTest("AppLayerHtpFileParseContentRangeTest01", AppLayerHtpFileParseContentRangeTest01); - UtRegisterTest("AppLayerHtpFileParseContentRangeTest02", AppLayerHtpFileParseContentRangeTest02); - UtRegisterTest("AppLayerHtpFileParseContentRangeTest03", AppLayerHtpFileParseContentRangeTest03); - UtRegisterTest("AppLayerHtpFileParseContentRangeTest04", AppLayerHtpFileParseContentRangeTest04); + UtRegisterTest( + "AppLayerHtpFileParseContentRangeTest01", AppLayerHtpFileParseContentRangeTest01); + UtRegisterTest( + "AppLayerHtpFileParseContentRangeTest02", AppLayerHtpFileParseContentRangeTest02); + UtRegisterTest( + "AppLayerHtpFileParseContentRangeTest03", AppLayerHtpFileParseContentRangeTest03); + UtRegisterTest( + "AppLayerHtpFileParseContentRangeTest04", AppLayerHtpFileParseContentRangeTest04); } diff --git a/src/tests/detect-bsize.c b/src/tests/detect-bsize.c index 2fcd65658990..a70a60b5368d 100644 --- a/src/tests/detect-bsize.c +++ b/src/tests/detect-bsize.c @@ -15,7 +15,7 @@ * 02110-1301, USA. */ -#include "../util-unittest.h" +#include "../util/unittest.h" #define TEST_OK(str, m, lo, hi) \ { \ diff --git a/src/tests/detect-engine-alert.c b/src/tests/detect-engine-alert.c index 86bc8d4a2858..61aa0e1fbf51 100644 --- a/src/tests/detect-engine-alert.c +++ b/src/tests/detect-engine-alert.c @@ -22,8 +22,8 @@ #include "../detect-engine-alert.h" #include "../detect-parse.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" /** * \brief Tests that the reject action is correctly set in Packet->action diff --git a/src/tests/detect-engine-content-inspection.c b/src/tests/detect-engine-content-inspection.c index ee1b605f2c0d..7ba4f3b43fc9 100644 --- a/src/tests/detect-engine-content-inspection.c +++ b/src/tests/detect-engine-content-inspection.c @@ -29,38 +29,37 @@ #include "../detect.h" #include "detect-engine-build.h" -#define TEST_HEADER \ - ThreadVars tv; \ - memset(&tv, 0, sizeof(tv)); \ - Flow f; \ +#define TEST_HEADER \ + ThreadVars tv; \ + memset(&tv, 0, sizeof(tv)); \ + Flow f; \ memset(&f, 0, sizeof(f)); -#define TEST_RUN(buf, buflen, sig, match, steps) \ -{ \ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \ - FAIL_IF_NULL(de_ctx); \ - DetectEngineThreadCtx *det_ctx = NULL; \ - char rule[2048]; \ - snprintf(rule, sizeof(rule), "alert tcp any any -> any any (%s sid:1; rev:1;)", (sig)); \ - Signature *s = DetectEngineAppendSig(de_ctx, rule); \ - FAIL_IF_NULL(s); \ - SigGroupBuild(de_ctx); \ - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); \ - FAIL_IF_NULL(det_ctx); \ - int r = DetectEngineContentInspection(de_ctx, det_ctx, \ - s, s->sm_arrays[DETECT_SM_LIST_PMATCH], NULL, &f, \ - (uint8_t *)(buf), (buflen), 0, DETECT_CI_FLAGS_SINGLE, \ - DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD); \ - FAIL_IF_NOT(r == (match)); \ - FAIL_IF_NOT(det_ctx->inspection_recursion_counter == (steps)); \ - DetectEngineThreadCtxDeinit(&tv, det_ctx); \ - DetectEngineCtxFree(de_ctx); \ -} -#define TEST_FOOTER \ - PASS +#define TEST_RUN(buf, buflen, sig, match, steps) \ + { \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \ + FAIL_IF_NULL(de_ctx); \ + DetectEngineThreadCtx *det_ctx = NULL; \ + char rule[2048]; \ + snprintf(rule, sizeof(rule), "alert tcp any any -> any any (%s sid:1; rev:1;)", (sig)); \ + Signature *s = DetectEngineAppendSig(de_ctx, rule); \ + FAIL_IF_NULL(s); \ + SigGroupBuild(de_ctx); \ + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); \ + FAIL_IF_NULL(det_ctx); \ + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, \ + s->sm_arrays[DETECT_SM_LIST_PMATCH], NULL, &f, (uint8_t *)(buf), (buflen), 0, \ + DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD); \ + FAIL_IF_NOT(r == (match)); \ + FAIL_IF_NOT(det_ctx->inspection_recursion_counter == (steps)); \ + DetectEngineThreadCtxDeinit(&tv, det_ctx); \ + DetectEngineCtxFree(de_ctx); \ + } +#define TEST_FOOTER PASS /** \test simple match with distance */ -static int DetectEngineContentInspectionTest01(void) { +static int DetectEngineContentInspectionTest01(void) +{ TEST_HEADER; TEST_RUN("ab", 2, "content:\"a\"; content:\"b\";", true, 2); TEST_RUN("ab", 2, "content:\"a\"; content:\"b\"; distance:0; ", true, 2); @@ -69,7 +68,8 @@ static int DetectEngineContentInspectionTest01(void) { } /** \test simple match with pcre/R */ -static int DetectEngineContentInspectionTest02(void) { +static int DetectEngineContentInspectionTest02(void) +{ TEST_HEADER; TEST_RUN("ab", 2, "content:\"a\"; pcre:\"/b/\";", true, 2); TEST_RUN("ab", 2, "content:\"a\"; pcre:\"/b/R\";", true, 2); @@ -78,35 +78,56 @@ static int DetectEngineContentInspectionTest02(void) { } /** \test simple recursion logic */ -static int DetectEngineContentInspectionTest03(void) { +static int DetectEngineContentInspectionTest03(void) +{ TEST_HEADER; TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"c\";", true, 3); TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"d\";", false, 3); - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0;", true, 3); - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; content:\"d\"; distance:0;", false, 3); + TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0;", + true, 3); + TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; content:\"d\"; distance:0;", + false, 3); - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"d\"; distance:0; within:1;", false, 5); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"d\"; distance:0; " + "within:1;", + false, 5); // 5 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1;", true, 5); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1;", + true, 5); // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, (6) bab - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; content:\"bab\";", true, 6); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; content:\"bab\";", + true, 6); // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, (6) no not found - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; content:\"no\";", false, 6); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; content:\"no\";", + false, 6); // 5 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; pcre:\"/^c$/R\";", true, 5); + TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; pcre:\"/^c$/R\";", + true, 5); // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, (6) bab - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; pcre:\"/^c$/R\"; content:\"bab\";", true, 6); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; pcre:\"/^c$/R\"; content:\"bab\";", + true, 6); // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, (6) no not found - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; pcre:\"/^c$/R\"; content:\"no\";", false, 6); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; pcre:\"/^c$/R\"; content:\"no\";", + false, 6); TEST_FOOTER; } /** \test pcre recursion logic */ -static int DetectEngineContentInspectionTest04(void) { +static int DetectEngineContentInspectionTest04(void) +{ TEST_HEADER; TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"c\";", true, 3); TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"d\";", false, 3); @@ -121,74 +142,142 @@ static int DetectEngineContentInspectionTest04(void) { } /** \test multiple independent blocks recursion logic */ -static int DetectEngineContentInspectionTest05(void) { +static int DetectEngineContentInspectionTest05(void) +{ TEST_HEADER; TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"c\";", true, 3); TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"d\";", false, 3); // first block 2: (1) a, (2) b // second block 3: (1) b, (2) c not found, (x) b continues within loop, (3) c found - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"b\"; content:\"c\"; distance:0; within:1;", true, 5); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"b\"; content:\"c\"; " + "distance:0; within:1;", + true, 5); TEST_FOOTER; } /** \test isdataat recursion logic */ -static int DetectEngineContentInspectionTest06(void) { +static int DetectEngineContentInspectionTest06(void) +{ TEST_HEADER; TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"c\";", true, 3); TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:\"d\";", false, 3); // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, isdataat - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; isdataat:!1,relative;", true, 5); - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; isdataat:1,relative;", false, 6); - - TEST_RUN("ababcabc", 8, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; isdataat:!1,relative;", true, 7); - TEST_RUN("ababcabc", 8, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; isdataat:1,relative;", true, 6); - - TEST_RUN("abcXYZ", 6, "content:\"abc\"; content:\"XYZ\"; distance:0; within:3; isdataat:!1,relative;", true, 2); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; isdataat:!1,relative;", + true, 5); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; isdataat:1,relative;", + false, 6); + + TEST_RUN("ababcabc", 8, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; isdataat:!1,relative;", + true, 7); + TEST_RUN("ababcabc", 8, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; isdataat:1,relative;", + true, 6); + + TEST_RUN("abcXYZ", 6, + "content:\"abc\"; content:\"XYZ\"; distance:0; within:3; isdataat:!1,relative;", true, + 2); TEST_RUN("abcXYZ", 6, "content:\"XYZ\"; distance:3; within:3; isdataat:!1,relative;", true, 1); TEST_RUN("abcXYZ", 6, "content:\"cXY\"; distance:2; within:3; isdataat:!1,relative;", false, 1); - TEST_RUN("xxxxxxxxxxxxxxxxxyYYYYYYYYYYYYYYYY", 34, "content:\"yYYYYYYYYYYYYYYYY\"; distance:9; within:29; isdataat:!1,relative;", true, 1); + TEST_RUN("xxxxxxxxxxxxxxxxxyYYYYYYYYYYYYYYYY", 34, + "content:\"yYYYYYYYYYYYYYYYY\"; distance:9; within:29; isdataat:!1,relative;", true, 1); TEST_FOOTER; } /** \test extreme recursion */ -static int DetectEngineContentInspectionTest07(void) { +static int DetectEngineContentInspectionTest07(void) +{ TEST_HEADER; - TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; content:\"d\";", true, 4); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; content:\"d\"; within:1; distance:0; ", true, 31); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; content:\"d\"; within:1; distance:0; ", false, 31); - - TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; distance:0; ", false, 4); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; pcre:\"/^d/R\"; ", false, 13); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; isdataat:!1,relative; ", false, 3); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; content:\"d\";", + true, 4); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; content:\"d\"; within:1; distance:0; ", + true, 31); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; content:\"d\"; within:1; distance:0; ", + false, 31); + + TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, + "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; " + "distance:0; ", + false, 4); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, + "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; pcre:\"/^d/R\"; ", + false, 13); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, + "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; " + "isdataat:!1,relative; ", + false, 3); TEST_RUN("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdx", 41, - "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; distance:0; content:\"e\"; distance:0; ", false, 5); + "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; " + "distance:0; content:\"e\"; distance:0; ", + false, 5); TEST_RUN("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdx", 41, - "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; distance:0; pcre:\"/^e/R\"; ", false, 14); // TODO should be 5? + "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; " + "distance:0; pcre:\"/^e/R\"; ", + false, 14); // TODO should be 5? TEST_RUN("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdx", 41, - "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; distance:0; isdataat:!1,relative; ", false, 4); - - TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; pcre:\"/d/\";", true, 4); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; pcre:\"/d/R\";", true, 4); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; pcre:\"/^d/R\";", true, 31); - - TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; pcre:\"/d/\";", false, 4); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; pcre:\"/d/R\";", false, 31); - TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; within:1; pcre:\"/^d/R\";", false, 31); + "content:\"a\"; content:\"b\"; distance:0; content:\"c\"; distance:0; content:\"d\"; " + "distance:0; isdataat:!1,relative; ", + false, 4); + + TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; pcre:\"/d/\";", + true, 4); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; pcre:\"/d/R\";", + true, 4); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcd", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; pcre:\"/^d/R\";", + true, 31); + + TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; pcre:\"/d/\";", + false, 4); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; pcre:\"/d/R\";", + false, 31); + TEST_RUN("abcabcabcabcabcabcabcabcabcabcx", 31, + "content:\"a\"; content:\"b\"; within:1; distance:0; content:\"c\"; distance:0; " + "within:1; pcre:\"/^d/R\";", + false, 31); TEST_FOOTER; } /** \test mix in negation */ -static int DetectEngineContentInspectionTest08(void) { +static int DetectEngineContentInspectionTest08(void) +{ TEST_HEADER; TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:!\"d\";", true, 3); TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:!\"c\";", false, 3); - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:!\"a\"; distance:0; within:1;", true, 5); - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:!\"a\"; distance:0; ", true, 5); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:!\"a\"; distance:0; " + "within:1;", + true, 5); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:!\"a\"; distance:0; ", + true, 5); TEST_RUN("abcdefghy", 9, "content:\"a\"; content:!\"x\"; content:\"c\"; distance:0; within:2; ", true, 3); @@ -201,39 +290,72 @@ static int DetectEngineContentInspectionTest08(void) { } /** \test mix in byte_jump */ -static int DetectEngineContentInspectionTest09(void) { +static int DetectEngineContentInspectionTest09(void) +{ TEST_HEADER; TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:!\"d\";", true, 3); TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; content:!\"c\";", false, 3); - TEST_RUN("abc03abcxyz", 11, "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3;", true, 3); - TEST_RUN("abc03abc03abcxyz", 16, "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3;", true, 5); - TEST_RUN("abc03abc03abcxyz", 16, "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; isdataat:!1,relative;", true, 5); - TEST_RUN("abc03abc03abcxyz", 16, "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; pcre:\"/klm$/R\";", false, 7); - TEST_RUN("abc03abc03abcxyzklm", 19, "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; pcre:\"/klm$/R\";", true, 6); - TEST_RUN("abc03abc03abcxyzklx", 19, "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; pcre:\"/^klm$/R\";", false, 7); - TEST_RUN("abc03abc03abc03abcxyzklm", 24, "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; pcre:\"/^klm$/R\";", true, 8); + TEST_RUN("abc03abcxyz", 11, + "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3;", true, + 3); + TEST_RUN("abc03abc03abcxyz", 16, + "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3;", true, + 5); + TEST_RUN("abc03abc03abcxyz", 16, + "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; " + "isdataat:!1,relative;", + true, 5); + TEST_RUN("abc03abc03abcxyz", 16, + "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; " + "pcre:\"/klm$/R\";", + false, 7); + TEST_RUN("abc03abc03abcxyzklm", 19, + "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; " + "pcre:\"/klm$/R\";", + true, 6); + TEST_RUN("abc03abc03abcxyzklx", 19, + "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; " + "pcre:\"/^klm$/R\";", + false, 7); + TEST_RUN("abc03abc03abc03abcxyzklm", 24, + "content:\"abc\"; byte_jump:2,0,relative,string,dec; content:\"xyz\"; within:3; " + "pcre:\"/^klm$/R\";", + true, 8); TEST_FOOTER; } /** \test mix in byte_extract */ -static int DetectEngineContentInspectionTest10(void) { +static int DetectEngineContentInspectionTest10(void) +{ TEST_HEADER; /* extract first byte as length field and check with isdataat */ TEST_RUN("9abcdefghi", 10, "byte_extract:1,0,data_size,string; isdataat:data_size;", true, 2); TEST_RUN("9abcdefgh", 9, "byte_extract:1,0,data_size,string; isdataat:!data_size;", true, 2); /* anchor len field to pattern 'x' to test recursion */ - TEST_RUN("x9x9abcdefghi", 13, "content:\"x\"; byte_extract:1,0,data_size,string,relative; isdataat:data_size,relative;", true, 3); - TEST_RUN("x9x9abcdefgh", 12, "content:\"x\"; byte_extract:1,0,data_size,string,relative; isdataat:!data_size,relative;", true, 5); - TEST_RUN("x9x9abcdefgh", 12, "content:\"x\"; depth:1; byte_extract:1,0,data_size,string,relative; isdataat:!data_size,relative;", false, 3); + TEST_RUN("x9x9abcdefghi", 13, + "content:\"x\"; byte_extract:1,0,data_size,string,relative; " + "isdataat:data_size,relative;", + true, 3); + TEST_RUN("x9x9abcdefgh", 12, + "content:\"x\"; byte_extract:1,0,data_size,string,relative; " + "isdataat:!data_size,relative;", + true, 5); + TEST_RUN("x9x9abcdefgh", 12, + "content:\"x\"; depth:1; byte_extract:1,0,data_size,string,relative; " + "isdataat:!data_size,relative;", + false, 3); /* check for super high extracted values */ - TEST_RUN("100000000abcdefghi", 18, "byte_extract:0,0,data_size,string; isdataat:data_size;", false, 2); - TEST_RUN("100000000abcdefghi", 18, "byte_extract:0,0,data_size,string; isdataat:!data_size;", true, 2); + TEST_RUN("100000000abcdefghi", 18, "byte_extract:0,0,data_size,string; isdataat:data_size;", + false, 2); + TEST_RUN("100000000abcdefghi", 18, "byte_extract:0,0,data_size,string; isdataat:!data_size;", + true, 2); TEST_FOOTER; } -static int DetectEngineContentInspectionTest11(void) { +static int DetectEngineContentInspectionTest11(void) +{ TEST_HEADER; TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\";", true, 2); TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; within:1; distance:0;", true, 2); @@ -245,27 +367,38 @@ static int DetectEngineContentInspectionTest11(void) { /** \test endswith (isdataat) recursion logic * based on DetectEngineContentInspectionTest06 */ -static int DetectEngineContentInspectionTest12(void) { +static int DetectEngineContentInspectionTest12(void) +{ TEST_HEADER; // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, endswith - TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; endswith;", true, 5); - - TEST_RUN("ababcabc", 8, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; endswith;", true, 7); - - TEST_RUN("abcXYZ", 6, "content:\"abc\"; content:\"XYZ\"; distance:0; within:3; endswith;", true, 2); + TEST_RUN("ababc", 5, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; endswith;", + true, 5); + + TEST_RUN("ababcabc", 8, + "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; " + "within:1; endswith;", + true, 7); + + TEST_RUN("abcXYZ", 6, "content:\"abc\"; content:\"XYZ\"; distance:0; within:3; endswith;", true, + 2); TEST_RUN("abcXYZ", 6, "content:\"XYZ\"; distance:3; within:3; endswith;", true, 1); TEST_RUN("abcXYZ", 6, "content:\"cXY\"; distance:2; within:3; endswith;", false, 1); TEST_RUN("abcXYZ", 6, "content:!\"cXY\"; endswith;", true, 1); TEST_RUN("abcXYZ", 6, "content:!\"XYZ\"; endswith;", false, 1); - TEST_RUN("xxxxxxxxxxxxxxxxxyYYYYYYYYYYYYYYYY", 34, "content:\"yYYYYYYYYYYYYYYYY\"; distance:9; within:29; endswith;", true, 1); + TEST_RUN("xxxxxxxxxxxxxxxxxyYYYYYYYYYYYYYYYY", 34, + "content:\"yYYYYYYYYYYYYYYYY\"; distance:9; within:29; endswith;", true, 1); TEST_FOOTER; } -static int DetectEngineContentInspectionTest13(void) { +static int DetectEngineContentInspectionTest13(void) +{ TEST_HEADER; TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; endswith;", true, 2); - TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; within:1; distance:0; endswith;", true, 2); + TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; within:1; distance:0; endswith;", + true, 2); TEST_RUN("ab", 2, "content:\"ab\"; startswith; endswith;", true, 1); TEST_RUN("ab", 2, "content:\"a\"; startswith; endswith;", false, 1); TEST_RUN("ab", 2, "content:\"b\"; startswith;", false, 1); @@ -275,32 +408,22 @@ static int DetectEngineContentInspectionTest13(void) { void DetectEngineContentInspectionRegisterTests(void) { - UtRegisterTest("DetectEngineContentInspectionTest01", - DetectEngineContentInspectionTest01); - UtRegisterTest("DetectEngineContentInspectionTest02", - DetectEngineContentInspectionTest02); - UtRegisterTest("DetectEngineContentInspectionTest03", - DetectEngineContentInspectionTest03); - UtRegisterTest("DetectEngineContentInspectionTest04", - DetectEngineContentInspectionTest04); - UtRegisterTest("DetectEngineContentInspectionTest05", - DetectEngineContentInspectionTest05); - UtRegisterTest("DetectEngineContentInspectionTest06", - DetectEngineContentInspectionTest06); - UtRegisterTest("DetectEngineContentInspectionTest07", - DetectEngineContentInspectionTest07); - UtRegisterTest("DetectEngineContentInspectionTest08", - DetectEngineContentInspectionTest08); - UtRegisterTest("DetectEngineContentInspectionTest09", - DetectEngineContentInspectionTest09); - UtRegisterTest("DetectEngineContentInspectionTest10", - DetectEngineContentInspectionTest10); - UtRegisterTest("DetectEngineContentInspectionTest11 startswith", - DetectEngineContentInspectionTest11); - UtRegisterTest("DetectEngineContentInspectionTest12 endswith", - DetectEngineContentInspectionTest12); + UtRegisterTest("DetectEngineContentInspectionTest01", DetectEngineContentInspectionTest01); + UtRegisterTest("DetectEngineContentInspectionTest02", DetectEngineContentInspectionTest02); + UtRegisterTest("DetectEngineContentInspectionTest03", DetectEngineContentInspectionTest03); + UtRegisterTest("DetectEngineContentInspectionTest04", DetectEngineContentInspectionTest04); + UtRegisterTest("DetectEngineContentInspectionTest05", DetectEngineContentInspectionTest05); + UtRegisterTest("DetectEngineContentInspectionTest06", DetectEngineContentInspectionTest06); + UtRegisterTest("DetectEngineContentInspectionTest07", DetectEngineContentInspectionTest07); + UtRegisterTest("DetectEngineContentInspectionTest08", DetectEngineContentInspectionTest08); + UtRegisterTest("DetectEngineContentInspectionTest09", DetectEngineContentInspectionTest09); + UtRegisterTest("DetectEngineContentInspectionTest10", DetectEngineContentInspectionTest10); + UtRegisterTest( + "DetectEngineContentInspectionTest11 startswith", DetectEngineContentInspectionTest11); + UtRegisterTest( + "DetectEngineContentInspectionTest12 endswith", DetectEngineContentInspectionTest12); UtRegisterTest("DetectEngineContentInspectionTest13 mix startswith/endswith", - DetectEngineContentInspectionTest13); + DetectEngineContentInspectionTest13); } #undef TEST_HEADER diff --git a/src/tests/detect-http-client-body.c b/src/tests/detect-http-client-body.c index c87d66756b9f..d2183f347ed9 100644 --- a/src/tests/detect-http-client-body.c +++ b/src/tests/detect-http-client-body.c @@ -21,7 +21,6 @@ * @{ */ - /** \file * * \author Anoop Saldanha @@ -48,24 +47,24 @@ #include "detect-engine-build.h" #include "flow-util.h" -#include "util-debug.h" -#include "util-print.h" +#include "util/debug.h" +#include "util/print.h" #include "flow.h" #include "app-layer-parser.h" #include "stream-tcp.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "app-layer-protos.h" #include "conf.h" #include "conf-yaml-loader.h" -#include "util-validate.h" +#include "util/validate.h" #ifdef UNITTESTS @@ -74,15 +73,30 @@ */ static int DetectHttpClientBodyParserTest01(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; http_client_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; nocase; http_client_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; endswith; http_client_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; startswith; http_client_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; startswith; endswith; http_client_body; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; rawbytes; http_client_body; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_server; http_client_body; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; content:\"abc\"; http_client_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "http_client_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "nocase; http_client_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "endswith; http_client_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "startswith; http_client_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "startswith; endswith; http_client_body; sid:1;)", + true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "rawbytes; http_client_body; sid:1;)", + false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tcp any any -> any any (flow:to_server; http_client_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; content:\"abc\"; " + "http_client_body; sid:1;)", + false)); PASS; } @@ -91,27 +105,45 @@ static int DetectHttpClientBodyParserTest01(void) */ static int DetectHttpClientBodyParserTest02(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; nocase; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; startswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; startswith; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; bsize:10; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; content:\"abc\"; rawbytes; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_server; http.request_body; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; http.request_body; content:\"abc\"; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; " + "http.request_body; content:\"abc\"; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; " + "http.request_body; content:\"abc\"; nocase; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; " + "http.request_body; content:\"abc\"; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; " + "http.request_body; content:\"abc\"; startswith; sid:1;)", + true)); + FAIL_IF_NOT( + UTHParseSignature("alert http any any -> any any (flow:to_server; http.request_body; " + "content:\"abc\"; startswith; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (flow:to_server; http.request_body; bsize:10; sid:1;)", + true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; " + "http.request_body; content:\"abc\"; rawbytes; sid:1;)", + false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tcp any any -> any any (flow:to_server; http.request_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; " + "http.request_body; content:\"abc\"; sid:1;)", + false)); PASS; } struct TestSteps { const uint8_t *input; - size_t input_size; /**< if 0 strlen will be used */ - int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ + size_t input_size; /**< if 0 strlen will be used */ + int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ int expect; }; -static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) +static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml) { TcpSession ssn; Flow f; @@ -162,7 +194,7 @@ static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) p->flow = &f; p->flowflags = (b->direction == STREAM_TOSERVER) ? FLOW_PKT_TOSERVER : FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, b->direction, (uint8_t *)b->input, @@ -173,7 +205,7 @@ static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); int match = PacketAlertCheck(p, 1); - FAIL_IF_NOT (b->expect == match); + FAIL_IF_NOT(b->expect == match); UTHFreePackets(&p, 1); b++; @@ -197,522 +229,527 @@ static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) static int DetectEngineHttpClientBodyTest01(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1This\"; http_client_body; sid:1;)"; + const char *sig = + "alert http any any -> any any (content:\"body1This\"; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest02(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:5; sid:1;)"; + const char *sig = + "alert http any any -> any any (content:\"body1\"; http_client_body; offset:5; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest03(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:16; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "offset:16; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest04(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; offset:16; sid:1;)"; + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; " + "offset:16; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest05(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; depth:25; sid:1;)"; + const char *sig = + "alert http any any -> any any (content:\"body1\"; http_client_body; depth:25; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest06(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:25; sid:1;)"; + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; " + "depth:25; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest07(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:15; sid:1;)"; + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; " + "depth:15; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest08(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"This is dummy body1This is dummy message body2\"; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"This is dummy body1This is dummy " + "message body2\"; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest09(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"This\"; http_client_body; within:5; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:\"This\"; http_client_body; within:5; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest10(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"boom\"; http_client_body; within:5; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:!\"boom\"; http_client_body; within:5; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest11(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"boom\"; http_client_body; within:5; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:\"boom\"; http_client_body; within:5; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest12(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"This\"; http_client_body; within:5; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:!\"This\"; http_client_body; within:5; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest13(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:5; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:\"dummy\"; http_client_body; distance:5; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest14(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:10; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:!\"dummy\"; http_client_body; distance:10; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest15(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:10; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:\"dummy\"; http_client_body; distance:10; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest16(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:5; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:!\"dummy\"; http_client_body; distance:5; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest17(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:\"bambu\"; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest18(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; fast_pattern; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; " + "content:\"bambu\"; http_client_body; fast_pattern; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest19(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"bambu\"; http_client_body; content:\"is\"; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"bambu\"; http_client_body; " + "content:\"is\"; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest20(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"is\"; http_client_body; fast_pattern; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"is\"; http_client_body; " + "fast_pattern; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest21(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; http_client_body; within:7; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; " + "http_client_body; within:7; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest22(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; within:7; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; within:7; " + "http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest23(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:3; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; " + "distance:3; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest24(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:13; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; " + "distance:13; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest25(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:15; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:15; " + "http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest26(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:10; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:10; " + "http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest27(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:8; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; " + "distance:8; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } static int DetectEngineHttpClientBodyTest28(void) { struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:14; http_client_body; sid:1;)"; + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; " + "distance:14; http_client_body; sid:1;)"; return RunTest(steps, sig, NULL); } @@ -725,27 +762,26 @@ static int DetectEngineHttpClientBodyTest29(void) if (unlikely(http_buf == NULL)) return 0; for (int i = 0; i < TOTAL_REQUESTS; i++) { - memcpy(http_buf + i * strlen(request_buffer), request_buffer, - strlen(request_buffer)); + memcpy(http_buf + i * strlen(request_buffer), request_buffer, strlen(request_buffer)); } uint32_t http_buf_len = TOTAL_REQUESTS * strlen(request_buffer); #undef TOTAL_REQUESTS struct TestSteps steps[] = { - { (const uint8_t *)http_buf, - (size_t)http_buf_len, STREAM_TOSERVER, 0 }, + { (const uint8_t *)http_buf, (size_t)http_buf_len, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 5\r\n" - "\r\n" - "dummy", - 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "dummy", + 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"dummyone\"; fast_pattern:0,3; http_server_body; sid:1;)"; + const char *sig = "alert http any any -> any any (content:\"dummyone\"; fast_pattern:0,3; " + "http_server_body; sid:1;)"; int result = RunTest(steps, sig, NULL); SCFree(http_buf); return result; @@ -769,19 +805,19 @@ libhtp:\n\ response-body-minimal-inspect-size: 0\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"bags\"; within:4; http_client_body; sid:1;)"; + const char *sig = + "alert http any any -> any any (content:\"bags\"; within:4; http_client_body; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -804,19 +840,19 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"This is dummy message body2", - 0, STREAM_TOSERVER, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (content:\"bags\"; depth:4; http_client_body; sid:1;)"; + const char *sig = + "alert http any any -> any any (content:\"bags\"; depth:4; http_client_body; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -923,14 +959,14 @@ static int DetectHttpClientBodyTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -949,7 +985,7 @@ static int DetectHttpClientBodyTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1019,16 +1055,15 @@ static int DetectHttpClientBodyTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 54\r\n" - "\r\n" - "This is dummy message body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 54\r\n" + "\r\n" + "This is dummy message body1"; + uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1049,11 +1084,11 @@ static int DetectHttpClientBodyTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1137,16 +1172,15 @@ static int DetectHttpClientBodyTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1167,11 +1201,11 @@ static int DetectHttpClientBodyTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1258,16 +1292,15 @@ static int DetectHttpClientBodyTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; + uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1288,11 +1321,11 @@ static int DetectHttpClientBodyTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1379,16 +1412,15 @@ static int DetectHttpClientBodyTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy bodY1"; - uint8_t http2_buf[] = - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy bodY1"; + uint8_t http2_buf[] = "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1409,11 +1441,11 @@ static int DetectHttpClientBodyTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1499,14 +1531,14 @@ static int DetectHttpClientBodyTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1525,7 +1557,7 @@ static int DetectHttpClientBodyTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1594,14 +1626,14 @@ static int DetectHttpClientBodyTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1620,7 +1652,7 @@ static int DetectHttpClientBodyTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1689,14 +1721,14 @@ static int DetectHttpClientBodyTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 55\r\n" - "\r\n" - "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 55\r\n" + "\r\n" + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1715,7 +1747,7 @@ static int DetectHttpClientBodyTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1812,7 +1844,7 @@ static int DetectHttpClientBodyTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1824,12 +1856,18 @@ static int DetectHttpClientBodyTest14(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"POST\"; http_method; " + "content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; " + "content:\"one\"; http_client_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"GET\"; http_method; " + "content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; " + "content:\"two\"; http_client_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; @@ -2009,7 +2047,7 @@ static int DetectHttpClientBodyTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2021,12 +2059,18 @@ static int DetectHttpClientBodyTest15(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"POST\"; http_method; " + "content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; " + "content:\"one\"; http_client_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"GET\"; http_method; " + "content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; " + "content:\"two\"; http_client_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; @@ -2153,7 +2197,7 @@ static int DetectHttpClientBodyTest15(void) htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, htp_state, 1); - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(t1); HtpBodyChunk *cur = htud->request_body.first; if (htud->request_body.first == NULL) { @@ -2161,14 +2205,13 @@ static int DetectHttpClientBodyTest15(void) goto end; } - if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, - (uint8_t *)"Body one!!", 10) != 1) - { + if (StreamingBufferSegmentCompareRawData( + htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } - htud = (HtpTxUserData *) htp_tx_get_user_data(t2); + htud = (HtpTxUserData *)htp_tx_get_user_data(t2); cur = htud->request_body.first; if (htud->request_body.first == NULL) { @@ -2176,9 +2219,8 @@ static int DetectHttpClientBodyTest15(void) goto end; } - if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, - (uint8_t *)"Body two!!", 10) != 1) - { + if (StreamingBufferSegmentCompareRawData( + htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1) { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } @@ -2287,7 +2329,7 @@ static int DetectHttpClientBodyTest24(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2321,24 +2363,22 @@ static int DetectHttpClientBodyTest24(void) ->prev->ctx; DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; - if (pd1->flags != 0 || - cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || - hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || - memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || - hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || - memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || + hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } - if (!DETECT_CONTENT_IS_SINGLE(cd2) || - DETECT_CONTENT_IS_SINGLE(hcbd1) || - DETECT_CONTENT_IS_SINGLE(hcbd2)) { + if (!DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2348,7 +2388,7 @@ static int DetectHttpClientBodyTest25(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2383,25 +2423,23 @@ static int DetectHttpClientBodyTest25(void) ->prev->ctx; DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; - if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || - cd2->flags != DETECT_CONTENT_DISTANCE || - memcmp(cd2->content, "four", cd2->content_len) != 0 || - hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || - memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || - hcbd2->flags != DETECT_CONTENT_DISTANCE || - memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } - if (DETECT_CONTENT_IS_SINGLE(cd2) || - DETECT_CONTENT_IS_SINGLE(hcbd1) || - DETECT_CONTENT_IS_SINGLE(hcbd2)) { + if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2411,7 +2449,7 @@ static int DetectHttpClientBodyTest26(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2446,26 +2484,24 @@ static int DetectHttpClientBodyTest26(void) ->prev->ctx; DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; - if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || - cd2->flags != DETECT_CONTENT_DISTANCE || - memcmp(cd2->content, "four", cd2->content_len) != 0 || - hcbd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || - memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || - hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || - memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { - printf ("failed: http_client_body incorrect flags"); + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || + hcbd1->flags != (DETECT_CONTENT_RELATIVE_NEXT | DETECT_CONTENT_OFFSET) || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + printf("failed: http_client_body incorrect flags"); goto end; } - if (DETECT_CONTENT_IS_SINGLE(cd2) || - DETECT_CONTENT_IS_SINGLE(hcbd1) || - DETECT_CONTENT_IS_SINGLE(hcbd2)) { + if (DETECT_CONTENT_IS_SINGLE(cd2) || DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2475,7 +2511,7 @@ static int DetectHttpClientBodyTest27(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2488,7 +2524,7 @@ static int DetectHttpClientBodyTest27(void) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2498,7 +2534,7 @@ static int DetectHttpClientBodyTest28(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2532,25 +2568,22 @@ static int DetectHttpClientBodyTest28(void) ->prev->ctx; DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; - if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || - cd2->flags != DETECT_CONTENT_DISTANCE || - memcmp(cd2->content, "four", cd2->content_len) != 0 || - hcbd1->flags != 0 || - memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || - hcbd2->flags != DETECT_CONTENT_DEPTH || - memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != 0 || + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_DEPTH || + memcmp(hcbd2->content, "three", hcbd1->content_len) != 0) { goto end; } - if (DETECT_CONTENT_IS_SINGLE(cd2) || - !DETECT_CONTENT_IS_SINGLE(hcbd1) || - DETECT_CONTENT_IS_SINGLE(hcbd2)) { + if (DETECT_CONTENT_IS_SINGLE(cd2) || !DETECT_CONTENT_IS_SINGLE(hcbd1) || + DETECT_CONTENT_IS_SINGLE(hcbd2)) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2560,7 +2593,7 @@ static int DetectHttpClientBodyTest29(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2589,15 +2622,15 @@ static int DetectHttpClientBodyTest29(void) DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || - memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || - hcbd2->flags != DETECT_CONTENT_DISTANCE || - memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2607,7 +2640,7 @@ static int DetectHttpClientBodyTest30(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2636,15 +2669,15 @@ static int DetectHttpClientBodyTest30(void) DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || - memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || - hcbd2->flags != DETECT_CONTENT_WITHIN || - memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { + memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || + hcbd2->flags != DETECT_CONTENT_WITHIN || + memcmp(hcbd2->content, "two", hcbd1->content_len) != 0) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2654,7 +2687,7 @@ static int DetectHttpClientBodyTest31(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2665,7 +2698,7 @@ static int DetectHttpClientBodyTest31(void) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2675,7 +2708,7 @@ static int DetectHttpClientBodyTest32(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2686,7 +2719,7 @@ static int DetectHttpClientBodyTest32(void) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2696,7 +2729,7 @@ static int DetectHttpClientBodyTest33(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2706,7 +2739,7 @@ static int DetectHttpClientBodyTest33(void) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2716,7 +2749,7 @@ static int DetectHttpClientBodyTest34(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2753,15 +2786,14 @@ static int DetectHttpClientBodyTest34(void) ->prev->ctx; DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; - if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || - hcbd2->flags != DETECT_CONTENT_WITHIN || - memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_WITHIN || + memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2771,7 +2803,7 @@ static int DetectHttpClientBodyTest35(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2807,15 +2839,14 @@ static int DetectHttpClientBodyTest35(void) ->prev->ctx; DetectPcreData *pd2 = (DetectPcreData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; - if (pd2->flags != (DETECT_PCRE_RELATIVE) || - hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || - memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { + if (pd2->flags != (DETECT_PCRE_RELATIVE) || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || + memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2825,7 +2856,7 @@ static int DetectHttpClientBodyTest36(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; @@ -2862,15 +2893,14 @@ static int DetectHttpClientBodyTest36(void) ->prev->ctx; DetectContentData *hcbd2 = (DetectContentData *)DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id)->ctx; - if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || - hcbd2->flags != DETECT_CONTENT_DISTANCE || - memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { + if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_DISTANCE || + memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { goto end; } result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; } @@ -2881,10 +2911,9 @@ static int DetectHttpClientBodyIsdataatParseTest(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (" - "content:\"one\"; http_client_body; " - "isdataat:!4,relative; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "content:\"one\"; http_client_body; " + "isdataat:!4,relative; sid:1;)"); FAIL_IF_NULL(s); SigMatch *sm = DetectBufferGetLastSigMatch(s, g_http_client_body_buffer_id); @@ -2935,72 +2964,40 @@ void DetectHttpClientBodyRegisterTests(void) UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35); UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36); - UtRegisterTest("DetectHttpClientBodyIsdataatParseTest", - DetectHttpClientBodyIsdataatParseTest); - - UtRegisterTest("DetectEngineHttpClientBodyTest01", - DetectEngineHttpClientBodyTest01); - UtRegisterTest("DetectEngineHttpClientBodyTest02", - DetectEngineHttpClientBodyTest02); - UtRegisterTest("DetectEngineHttpClientBodyTest03", - DetectEngineHttpClientBodyTest03); - UtRegisterTest("DetectEngineHttpClientBodyTest04", - DetectEngineHttpClientBodyTest04); - UtRegisterTest("DetectEngineHttpClientBodyTest05", - DetectEngineHttpClientBodyTest05); - UtRegisterTest("DetectEngineHttpClientBodyTest06", - DetectEngineHttpClientBodyTest06); - UtRegisterTest("DetectEngineHttpClientBodyTest07", - DetectEngineHttpClientBodyTest07); - UtRegisterTest("DetectEngineHttpClientBodyTest08", - DetectEngineHttpClientBodyTest08); - UtRegisterTest("DetectEngineHttpClientBodyTest09", - DetectEngineHttpClientBodyTest09); - UtRegisterTest("DetectEngineHttpClientBodyTest10", - DetectEngineHttpClientBodyTest10); - UtRegisterTest("DetectEngineHttpClientBodyTest11", - DetectEngineHttpClientBodyTest11); - UtRegisterTest("DetectEngineHttpClientBodyTest12", - DetectEngineHttpClientBodyTest12); - UtRegisterTest("DetectEngineHttpClientBodyTest13", - DetectEngineHttpClientBodyTest13); - UtRegisterTest("DetectEngineHttpClientBodyTest14", - DetectEngineHttpClientBodyTest14); - UtRegisterTest("DetectEngineHttpClientBodyTest15", - DetectEngineHttpClientBodyTest15); - UtRegisterTest("DetectEngineHttpClientBodyTest16", - DetectEngineHttpClientBodyTest16); - UtRegisterTest("DetectEngineHttpClientBodyTest17", - DetectEngineHttpClientBodyTest17); - UtRegisterTest("DetectEngineHttpClientBodyTest18", - DetectEngineHttpClientBodyTest18); - UtRegisterTest("DetectEngineHttpClientBodyTest19", - DetectEngineHttpClientBodyTest19); - UtRegisterTest("DetectEngineHttpClientBodyTest20", - DetectEngineHttpClientBodyTest20); - UtRegisterTest("DetectEngineHttpClientBodyTest21", - DetectEngineHttpClientBodyTest21); - UtRegisterTest("DetectEngineHttpClientBodyTest22", - DetectEngineHttpClientBodyTest22); - UtRegisterTest("DetectEngineHttpClientBodyTest23", - DetectEngineHttpClientBodyTest23); - UtRegisterTest("DetectEngineHttpClientBodyTest24", - DetectEngineHttpClientBodyTest24); - UtRegisterTest("DetectEngineHttpClientBodyTest25", - DetectEngineHttpClientBodyTest25); - UtRegisterTest("DetectEngineHttpClientBodyTest26", - DetectEngineHttpClientBodyTest26); - UtRegisterTest("DetectEngineHttpClientBodyTest27", - DetectEngineHttpClientBodyTest27); - UtRegisterTest("DetectEngineHttpClientBodyTest28", - DetectEngineHttpClientBodyTest28); - UtRegisterTest("DetectEngineHttpClientBodyTest29", - DetectEngineHttpClientBodyTest29); - - UtRegisterTest("DetectEngineHttpClientBodyTest30", - DetectEngineHttpClientBodyTest30); - UtRegisterTest("DetectEngineHttpClientBodyTest31", - DetectEngineHttpClientBodyTest31); + UtRegisterTest("DetectHttpClientBodyIsdataatParseTest", DetectHttpClientBodyIsdataatParseTest); + + UtRegisterTest("DetectEngineHttpClientBodyTest01", DetectEngineHttpClientBodyTest01); + UtRegisterTest("DetectEngineHttpClientBodyTest02", DetectEngineHttpClientBodyTest02); + UtRegisterTest("DetectEngineHttpClientBodyTest03", DetectEngineHttpClientBodyTest03); + UtRegisterTest("DetectEngineHttpClientBodyTest04", DetectEngineHttpClientBodyTest04); + UtRegisterTest("DetectEngineHttpClientBodyTest05", DetectEngineHttpClientBodyTest05); + UtRegisterTest("DetectEngineHttpClientBodyTest06", DetectEngineHttpClientBodyTest06); + UtRegisterTest("DetectEngineHttpClientBodyTest07", DetectEngineHttpClientBodyTest07); + UtRegisterTest("DetectEngineHttpClientBodyTest08", DetectEngineHttpClientBodyTest08); + UtRegisterTest("DetectEngineHttpClientBodyTest09", DetectEngineHttpClientBodyTest09); + UtRegisterTest("DetectEngineHttpClientBodyTest10", DetectEngineHttpClientBodyTest10); + UtRegisterTest("DetectEngineHttpClientBodyTest11", DetectEngineHttpClientBodyTest11); + UtRegisterTest("DetectEngineHttpClientBodyTest12", DetectEngineHttpClientBodyTest12); + UtRegisterTest("DetectEngineHttpClientBodyTest13", DetectEngineHttpClientBodyTest13); + UtRegisterTest("DetectEngineHttpClientBodyTest14", DetectEngineHttpClientBodyTest14); + UtRegisterTest("DetectEngineHttpClientBodyTest15", DetectEngineHttpClientBodyTest15); + UtRegisterTest("DetectEngineHttpClientBodyTest16", DetectEngineHttpClientBodyTest16); + UtRegisterTest("DetectEngineHttpClientBodyTest17", DetectEngineHttpClientBodyTest17); + UtRegisterTest("DetectEngineHttpClientBodyTest18", DetectEngineHttpClientBodyTest18); + UtRegisterTest("DetectEngineHttpClientBodyTest19", DetectEngineHttpClientBodyTest19); + UtRegisterTest("DetectEngineHttpClientBodyTest20", DetectEngineHttpClientBodyTest20); + UtRegisterTest("DetectEngineHttpClientBodyTest21", DetectEngineHttpClientBodyTest21); + UtRegisterTest("DetectEngineHttpClientBodyTest22", DetectEngineHttpClientBodyTest22); + UtRegisterTest("DetectEngineHttpClientBodyTest23", DetectEngineHttpClientBodyTest23); + UtRegisterTest("DetectEngineHttpClientBodyTest24", DetectEngineHttpClientBodyTest24); + UtRegisterTest("DetectEngineHttpClientBodyTest25", DetectEngineHttpClientBodyTest25); + UtRegisterTest("DetectEngineHttpClientBodyTest26", DetectEngineHttpClientBodyTest26); + UtRegisterTest("DetectEngineHttpClientBodyTest27", DetectEngineHttpClientBodyTest27); + UtRegisterTest("DetectEngineHttpClientBodyTest28", DetectEngineHttpClientBodyTest28); + UtRegisterTest("DetectEngineHttpClientBodyTest29", DetectEngineHttpClientBodyTest29); + + UtRegisterTest("DetectEngineHttpClientBodyTest30", DetectEngineHttpClientBodyTest30); + UtRegisterTest("DetectEngineHttpClientBodyTest31", DetectEngineHttpClientBodyTest31); } #endif diff --git a/src/tests/detect-http-cookie.c b/src/tests/detect-http-cookie.c index 466722ee9ee5..82a2881ad900 100644 --- a/src/tests/detect-http-cookie.c +++ b/src/tests/detect-http-cookie.c @@ -21,7 +21,6 @@ * @{ */ - /** \file * * \author Anoop Saldanha @@ -36,10 +35,10 @@ #include "../flow-util.h" #include "../flow.h" #include "../app-layer-parser.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" #include "../app-layer.h" -#include "../app-layer-htp.h" +#include "../app-layer/http/parser.h" #include "../app-layer-protos.h" #include "../detect-isdataat.h" #include "../detect-engine-build.h" @@ -60,10 +59,9 @@ static int DetectEngineHttpCookieTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -81,7 +79,7 @@ static int DetectEngineHttpCookieTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -92,10 +90,10 @@ static int DetectEngineHttpCookieTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CONNECT\"; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CONNECT\"; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -152,10 +150,9 @@ static int DetectEngineHttpCookieTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -173,7 +170,7 @@ static int DetectEngineHttpCookieTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -184,10 +181,10 @@ static int DetectEngineHttpCookieTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; depth:4; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; depth:4; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -244,10 +241,9 @@ static int DetectEngineHttpCookieTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -265,7 +261,7 @@ static int DetectEngineHttpCookieTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -276,10 +272,10 @@ static int DetectEngineHttpCookieTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"ECT\"; depth:4; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"ECT\"; depth:4; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -336,10 +332,9 @@ static int DetectEngineHttpCookieTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -357,7 +352,7 @@ static int DetectEngineHttpCookieTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -368,10 +363,10 @@ static int DetectEngineHttpCookieTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"ECT\"; depth:4; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"ECT\"; depth:4; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -428,10 +423,9 @@ static int DetectEngineHttpCookieTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -449,7 +443,7 @@ static int DetectEngineHttpCookieTest05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -460,10 +454,10 @@ static int DetectEngineHttpCookieTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"CON\"; depth:4; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"CON\"; depth:4; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -520,10 +514,9 @@ static int DetectEngineHttpCookieTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -541,7 +534,7 @@ static int DetectEngineHttpCookieTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -552,10 +545,10 @@ static int DetectEngineHttpCookieTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"ECT\"; offset:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"ECT\"; offset:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -612,10 +605,9 @@ static int DetectEngineHttpCookieTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -633,7 +625,7 @@ static int DetectEngineHttpCookieTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -644,10 +636,10 @@ static int DetectEngineHttpCookieTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"CO\"; offset:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"CO\"; offset:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -704,10 +696,9 @@ static int DetectEngineHttpCookieTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -725,7 +716,7 @@ static int DetectEngineHttpCookieTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -736,10 +727,10 @@ static int DetectEngineHttpCookieTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"ECT\"; offset:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"ECT\"; offset:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -796,10 +787,9 @@ static int DetectEngineHttpCookieTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -817,7 +807,7 @@ static int DetectEngineHttpCookieTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -828,10 +818,10 @@ static int DetectEngineHttpCookieTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CON\"; offset:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CON\"; offset:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -888,10 +878,9 @@ static int DetectEngineHttpCookieTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -909,7 +898,7 @@ static int DetectEngineHttpCookieTest10(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -920,11 +909,11 @@ static int DetectEngineHttpCookieTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:\"EC\"; within:4; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:\"EC\"; within:4; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -981,10 +970,9 @@ static int DetectEngineHttpCookieTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1002,7 +990,7 @@ static int DetectEngineHttpCookieTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1013,11 +1001,11 @@ static int DetectEngineHttpCookieTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:!\"EC\"; within:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:!\"EC\"; within:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1074,10 +1062,9 @@ static int DetectEngineHttpCookieTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1095,7 +1082,7 @@ static int DetectEngineHttpCookieTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1106,11 +1093,11 @@ static int DetectEngineHttpCookieTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:\"EC\"; within:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:\"EC\"; within:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1167,10 +1154,9 @@ static int DetectEngineHttpCookieTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1188,7 +1174,7 @@ static int DetectEngineHttpCookieTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1199,11 +1185,11 @@ static int DetectEngineHttpCookieTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:!\"EC\"; within:4; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:!\"EC\"; within:4; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1260,10 +1246,9 @@ static int DetectEngineHttpCookieTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1281,7 +1266,7 @@ static int DetectEngineHttpCookieTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1292,11 +1277,11 @@ static int DetectEngineHttpCookieTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:\"EC\"; distance:2; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:\"EC\"; distance:2; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1353,10 +1338,9 @@ static int DetectEngineHttpCookieTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1374,7 +1358,7 @@ static int DetectEngineHttpCookieTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1385,11 +1369,11 @@ static int DetectEngineHttpCookieTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:!\"EC\"; distance:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:!\"EC\"; distance:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1446,10 +1430,9 @@ static int DetectEngineHttpCookieTest16(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1467,7 +1450,7 @@ static int DetectEngineHttpCookieTest16(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1478,11 +1461,11 @@ static int DetectEngineHttpCookieTest16(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:\"EC\"; distance:3; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:\"EC\"; distance:3; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1539,10 +1522,9 @@ static int DetectEngineHttpCookieTest17(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Cookie: CONNECT\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Cookie: CONNECT\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1560,7 +1542,7 @@ static int DetectEngineHttpCookieTest17(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1571,11 +1553,11 @@ static int DetectEngineHttpCookieTest17(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_cookie; " - "content:!\"EC\"; distance:2; http_cookie; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_cookie; " + "content:!\"EC\"; distance:2; http_cookie; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1628,12 +1610,12 @@ static int DetectHttpCookieTest01(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_cookie\"; http_cookie;sid:1;)"); + "(msg:\"Testing http_cookie\"; http_cookie;sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; @@ -1652,13 +1634,13 @@ static int DetectHttpCookieTest02(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_cookie\"; content:\"me\"; " - "http_cookie:woo; sid:1;)"); + "(msg:\"Testing http_cookie\"; content:\"me\"; " + "http_cookie:woo; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; @@ -1698,7 +1680,7 @@ static int DetectHttpCookieSigTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1710,20 +1692,19 @@ static int DetectHttpCookieSigTest01(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP cookie\"; content:\"me\"; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP cookie\"; content:\"me\"; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "cookie\"; content:\"go\"; http_cookie; sid:2;)"); + s->next = SigInit(de_ctx, "alert http any any -> any any (msg:\"HTTP " + "cookie\"; content:\"go\"; http_cookie; sid:2;)"); if (s->next == NULL) { goto end; } - SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -1801,7 +1782,7 @@ static int DetectHttpCookieSigTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1813,9 +1794,9 @@ static int DetectHttpCookieSigTest02(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP cookie\"; content:\"me\"; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP cookie\"; content:\"me\"; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } @@ -1867,7 +1848,7 @@ static int DetectHttpCookieSigTest03(void) int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" - "Cookie: dummy\r\n\r\n"; + "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; @@ -1891,7 +1872,7 @@ static int DetectHttpCookieSigTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1903,9 +1884,9 @@ static int DetectHttpCookieSigTest03(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP cookie\"; content:\"boo\"; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP cookie\"; content:\"boo\"; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } @@ -1957,7 +1938,7 @@ static int DetectHttpCookieSigTest04(void) int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" - "Cookie: dummy\r\n\r\n"; + "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; @@ -1982,7 +1963,7 @@ static int DetectHttpCookieSigTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1994,9 +1975,9 @@ static int DetectHttpCookieSigTest04(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP cookie\"; content:!\"boo\"; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP cookie\"; content:!\"boo\"; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } @@ -2048,7 +2029,7 @@ static int DetectHttpCookieSigTest05(void) int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" - "Cookie: DuMmY\r\n\r\n"; + "Cookie: DuMmY\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; @@ -2073,7 +2054,7 @@ static int DetectHttpCookieSigTest05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2085,9 +2066,9 @@ static int DetectHttpCookieSigTest05(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP cookie\"; content:\"dummy\"; nocase; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP cookie\"; content:\"dummy\"; nocase; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } @@ -2139,7 +2120,7 @@ static int DetectHttpCookieSigTest06(void) int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" - "Cookie: DuMmY\r\n\r\n"; + "Cookie: DuMmY\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; @@ -2164,7 +2145,7 @@ static int DetectHttpCookieSigTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2176,9 +2157,9 @@ static int DetectHttpCookieSigTest06(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP cookie\"; content:\"dummy\"; " - "http_cookie; nocase; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP cookie\"; content:\"dummy\"; " + "http_cookie; nocase; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; @@ -2230,7 +2211,7 @@ static int DetectHttpCookieSigTest07(void) int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" - "Cookie: dummy\r\n\r\n"; + "Cookie: dummy\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; Packet *p = NULL; @@ -2254,7 +2235,7 @@ static int DetectHttpCookieSigTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2266,9 +2247,9 @@ static int DetectHttpCookieSigTest07(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP cookie\"; content:!\"dummy\"; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP cookie\"; content:!\"dummy\"; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } @@ -2322,16 +2303,14 @@ static int DetectHttpCookieSigTest08(void) int result = 0; Flow f; - uint8_t httpbuf_request[] = - "GET / HTTP/1.1\r\n" - "User-Agent: Mozilla/1.0\r\n" - "\r\n"; + uint8_t httpbuf_request[] = "GET / HTTP/1.1\r\n" + "User-Agent: Mozilla/1.0\r\n" + "\r\n"; uint32_t httpbuf_request_len = sizeof(httpbuf_request) - 1; /* minus the \0 */ - uint8_t httpbuf_response[] = - "HTTP/1.1 200 OK\r\n" - "Set-Cookie: response_user_agent\r\n" - "\r\n"; + uint8_t httpbuf_response[] = "HTTP/1.1 200 OK\r\n" + "Set-Cookie: response_user_agent\r\n" + "\r\n"; uint32_t httpbuf_response_len = sizeof(httpbuf_response) - 1; /* minus the \0 */ TcpSession ssn; @@ -2373,9 +2352,9 @@ static int DetectHttpCookieSigTest08(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(flow:to_client; content:\"response_user_agent\"; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(flow:to_client; content:\"response_user_agent\"; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } @@ -2445,17 +2424,15 @@ static int DetectHttpCookieSigTest09(void) int result = 0; Flow f; - uint8_t httpbuf_request[] = - "GET / HTTP/1.1\r\n" - "Cookie: request_user_agent\r\n" - "User-Agent: Mozilla/1.0\r\n" - "\r\n"; + uint8_t httpbuf_request[] = "GET / HTTP/1.1\r\n" + "Cookie: request_user_agent\r\n" + "User-Agent: Mozilla/1.0\r\n" + "\r\n"; uint32_t httpbuf_request_len = sizeof(httpbuf_request) - 1; /* minus the \0 */ - uint8_t httpbuf_response[] = - "HTTP/1.1 200 OK\r\n" - "Set-Cookie: response_user_agent\r\n" - "\r\n"; + uint8_t httpbuf_response[] = "HTTP/1.1 200 OK\r\n" + "Set-Cookie: response_user_agent\r\n" + "\r\n"; uint32_t httpbuf_response_len = sizeof(httpbuf_response) - 1; /* minus the \0 */ TcpSession ssn; @@ -2497,15 +2474,16 @@ static int DetectHttpCookieSigTest09(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(flow:to_server; content:\"request_user_agent\"; " - "http_cookie; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(flow:to_server; content:\"request_user_agent\"; " + "http_cookie; sid:1;)"); if (s == NULL) { goto end; } - s = de_ctx->sig_list->next = SigInit(de_ctx,"alert http any any -> any any " - "(flow:to_client; content:\"response_user_agent\"; " - "http_cookie; sid:2;)"); + s = de_ctx->sig_list->next = + SigInit(de_ctx, "alert http any any -> any any " + "(flow:to_client; content:\"response_user_agent\"; " + "http_cookie; sid:2;)"); if (s == NULL) { goto end; } @@ -2570,7 +2548,7 @@ static int DetectHttpCookieSigTest09(void) /** * \brief Register the UNITTESTS for the http_cookie keyword */ -void DetectHttpCookieRegisterTests (void) +void DetectHttpCookieRegisterTests(void) { UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01); UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02); @@ -2583,40 +2561,23 @@ void DetectHttpCookieRegisterTests (void) UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07); UtRegisterTest("DetectHttpCookieSigTest08", DetectHttpCookieSigTest08); UtRegisterTest("DetectHttpCookieSigTest09", DetectHttpCookieSigTest09); - UtRegisterTest("DetectEngineHttpCookieTest01", - DetectEngineHttpCookieTest01); - UtRegisterTest("DetectEngineHttpCookieTest02", - DetectEngineHttpCookieTest02); - UtRegisterTest("DetectEngineHttpCookieTest03", - DetectEngineHttpCookieTest03); - UtRegisterTest("DetectEngineHttpCookieTest04", - DetectEngineHttpCookieTest04); - UtRegisterTest("DetectEngineHttpCookieTest05", - DetectEngineHttpCookieTest05); - UtRegisterTest("DetectEngineHttpCookieTest06", - DetectEngineHttpCookieTest06); - UtRegisterTest("DetectEngineHttpCookieTest07", - DetectEngineHttpCookieTest07); - UtRegisterTest("DetectEngineHttpCookieTest08", - DetectEngineHttpCookieTest08); - UtRegisterTest("DetectEngineHttpCookieTest09", - DetectEngineHttpCookieTest09); - UtRegisterTest("DetectEngineHttpCookieTest10", - DetectEngineHttpCookieTest10); - UtRegisterTest("DetectEngineHttpCookieTest11", - DetectEngineHttpCookieTest11); - UtRegisterTest("DetectEngineHttpCookieTest12", - DetectEngineHttpCookieTest12); - UtRegisterTest("DetectEngineHttpCookieTest13", - DetectEngineHttpCookieTest13); - UtRegisterTest("DetectEngineHttpCookieTest14", - DetectEngineHttpCookieTest14); - UtRegisterTest("DetectEngineHttpCookieTest15", - DetectEngineHttpCookieTest15); - UtRegisterTest("DetectEngineHttpCookieTest16", - DetectEngineHttpCookieTest16); - UtRegisterTest("DetectEngineHttpCookieTest17", - DetectEngineHttpCookieTest17); + UtRegisterTest("DetectEngineHttpCookieTest01", DetectEngineHttpCookieTest01); + UtRegisterTest("DetectEngineHttpCookieTest02", DetectEngineHttpCookieTest02); + UtRegisterTest("DetectEngineHttpCookieTest03", DetectEngineHttpCookieTest03); + UtRegisterTest("DetectEngineHttpCookieTest04", DetectEngineHttpCookieTest04); + UtRegisterTest("DetectEngineHttpCookieTest05", DetectEngineHttpCookieTest05); + UtRegisterTest("DetectEngineHttpCookieTest06", DetectEngineHttpCookieTest06); + UtRegisterTest("DetectEngineHttpCookieTest07", DetectEngineHttpCookieTest07); + UtRegisterTest("DetectEngineHttpCookieTest08", DetectEngineHttpCookieTest08); + UtRegisterTest("DetectEngineHttpCookieTest09", DetectEngineHttpCookieTest09); + UtRegisterTest("DetectEngineHttpCookieTest10", DetectEngineHttpCookieTest10); + UtRegisterTest("DetectEngineHttpCookieTest11", DetectEngineHttpCookieTest11); + UtRegisterTest("DetectEngineHttpCookieTest12", DetectEngineHttpCookieTest12); + UtRegisterTest("DetectEngineHttpCookieTest13", DetectEngineHttpCookieTest13); + UtRegisterTest("DetectEngineHttpCookieTest14", DetectEngineHttpCookieTest14); + UtRegisterTest("DetectEngineHttpCookieTest15", DetectEngineHttpCookieTest15); + UtRegisterTest("DetectEngineHttpCookieTest16", DetectEngineHttpCookieTest16); + UtRegisterTest("DetectEngineHttpCookieTest17", DetectEngineHttpCookieTest17); } /** * @} diff --git a/src/tests/detect-http-header.c b/src/tests/detect-http-header.c index 776d89113861..8a84d51a57a3 100644 --- a/src/tests/detect-http-header.c +++ b/src/tests/detect-http-header.c @@ -21,7 +21,6 @@ * @{ */ - /** * \file * @@ -38,9 +37,9 @@ #include "../app-layer.h" #include "../app-layer-parser.h" -#include "../app-layer-htp.h" -#include "../detect-http-header.h" -#include "../detect-http-header-common.h" +#include "../app-layer/http/parser.h" +#include "../app-layer/http/detect-header.h" +#include "../app-layer/http/detect-header-common.h" #include "../detect-engine-build.h" #include "../detect-engine-alert.h" @@ -48,23 +47,34 @@ #include "../stream-tcp.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" /** * \test Test parser accepting valid rules and rejecting invalid rules */ static int DetectHttpHeaderParserTest01(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (content:\"abc\"; http_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (content:\"abc\"; nocase; http_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (content:\"abc\"; endswith; http_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (content:\"abc\"; startswith; http_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (content:\"abc\"; startswith; endswith; http_header; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (content:\"abc\"; rawbytes; http_header; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (content:\"abc\"; http_header; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (content:\"abc\"; nocase; http_header; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (content:\"abc\"; endswith; http_header; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (content:\"abc\"; startswith; http_header; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (content:\"abc\"; startswith; " + "endswith; http_header; sid:1;)", + true)); + + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (content:\"abc\"; rawbytes; http_header; sid:1;)", + false)); FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (http_header; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (content:\"abc\"; http_header; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tls any any -> any any (content:\"abc\"; http_header; sid:1;)", false)); PASS; } @@ -73,16 +83,28 @@ static int DetectHttpHeaderParserTest01(void) */ static int DetectHttpHeaderParserTest02(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; content:\"abc\"; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; content:\"abc\"; nocase; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; content:\"abc\"; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; content:\"abc\"; startswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; content:\"abc\"; startswith; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; bsize:10; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; content:\"abc\"; rawbytes; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (http.header; content:\"abc\"; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (http.header; content:\"abc\"; nocase; sid:1;)", true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (http.header; content:\"abc\"; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (http.header; content:\"abc\"; startswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (http.header; content:\"abc\"; " + "startswith; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (http.header; bsize:10; sid:1;)", true)); + + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (http.header; content:\"abc\"; rawbytes; sid:1;)", + false)); FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (http.header; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (http.header; content:\"abc\"; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tls any any -> any any (http.header; content:\"abc\"; sid:1;)", false)); PASS; } @@ -99,14 +121,14 @@ static int DetectHttpHeaderTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -124,7 +146,7 @@ static int DetectHttpHeaderTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -135,10 +157,10 @@ static int DetectHttpHeaderTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Type: text/html\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Type: text/html\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -193,15 +215,14 @@ static int DetectHttpHeaderTest07(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozi"; - uint8_t http2_buf[] = - "lla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\nContent-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n" - "This is dummy message body1"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozi"; + uint8_t http2_buf[] = "lla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 " + "Firefox/3.5.7\r\nContent-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n" + "This is dummy message body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; @@ -224,11 +245,11 @@ static int DetectHttpHeaderTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -237,10 +258,10 @@ static int DetectHttpHeaderTest07(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Mozilla\"; http_header; " - "sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Mozilla\"; http_header; " + "sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -256,7 +277,7 @@ static int DetectHttpHeaderTest07(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF( (PacketAlertCheck(p1, 1))); + FAIL_IF((PacketAlertCheck(p1, 1))); r = AppLayerParserParse( NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, http2_buf, http2_len); @@ -291,14 +312,13 @@ static int DetectHttpHeaderTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n"; - uint8_t http2_buf[] = - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n"; + uint8_t http2_buf[] = "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -318,11 +338,11 @@ static int DetectHttpHeaderTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -333,10 +353,10 @@ static int DetectHttpHeaderTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Gecko/20091221 Firefox/3.5.7\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Gecko/20091221 Firefox/3.5.7\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -410,15 +430,14 @@ static int DetectHttpHeaderTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; - uint8_t http2_buf[] = - "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n" - "This is dummy body\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n"; + uint8_t http2_buf[] = "Content-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n" + "This is dummy body\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -438,11 +457,11 @@ static int DetectHttpHeaderTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -454,10 +473,10 @@ static int DetectHttpHeaderTest09(void) de_ctx->flags |= DE_QUIET; de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Firefox/3.5.7|0D 0A|Content\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Firefox/3.5.7|0D 0A|Content\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -531,15 +550,14 @@ static int DetectHttpHeaderTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; - uint8_t http2_buf[] = - "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n" - "This is dummy body"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n"; + uint8_t http2_buf[] = "Content-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n" + "This is dummy body"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -559,11 +577,11 @@ static int DetectHttpHeaderTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -574,10 +592,11 @@ static int DetectHttpHeaderTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"firefox/3.5.7|0D 0A|content\"; nocase; http_header;" - "sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"firefox/3.5.7|0D 0A|content\"; nocase; http_header;" + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -650,14 +669,14 @@ static int DetectHttpHeaderTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -675,7 +694,7 @@ static int DetectHttpHeaderTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -686,10 +705,10 @@ static int DetectHttpHeaderTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"lalalalala\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"lalalalala\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -745,14 +764,14 @@ static int DetectHttpHeaderTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -770,7 +789,7 @@ static int DetectHttpHeaderTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -781,10 +800,10 @@ static int DetectHttpHeaderTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"User-Agent: Mozilla/5.0 \"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"User-Agent: Mozilla/5.0 \"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -840,14 +859,14 @@ static int DetectHttpHeaderTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 100\r\n" - "\r\n" - "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 100\r\n" + "\r\n" + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -866,7 +885,7 @@ static int DetectHttpHeaderTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -877,10 +896,11 @@ static int DetectHttpHeaderTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Host: www.openinfosecfoundation.org\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Host: www.openinfosecfoundation.org\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -933,11 +953,10 @@ static int DetectHttpHeaderTest28(void) DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http_buf[] = - "POST http://xxx.intranet.local:8000/xxx HTTP/1.1\r\n" - "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_29\r\n" - "Host: xxx.intranet.local:8000\r\n" - "\r\n"; + uint8_t http_buf[] = "POST http://xxx.intranet.local:8000/xxx HTTP/1.1\r\n" + "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_29\r\n" + "Host: xxx.intranet.local:8000\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -955,7 +974,7 @@ static int DetectHttpHeaderTest28(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -966,9 +985,9 @@ static int DetectHttpHeaderTest28(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(app-layer-event:http.host_header_ambiguous; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(app-layer-event:http.host_header_ambiguous; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -992,7 +1011,7 @@ static int DetectHttpHeaderTest28(void) } result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -1014,11 +1033,10 @@ static int DetectHttpHeaderTest29(void) DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http_buf[] = - "POST http://xxx.intranet.local:8001/xxx HTTP/1.1\r\n" - "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_29\r\n" - "Host: xxx.intranet.local:8000\r\n" - "\r\n"; + uint8_t http_buf[] = "POST http://xxx.intranet.local:8001/xxx HTTP/1.1\r\n" + "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_29\r\n" + "Host: xxx.intranet.local:8000\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1036,7 +1054,7 @@ static int DetectHttpHeaderTest29(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1047,9 +1065,9 @@ static int DetectHttpHeaderTest29(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(app-layer-event:http.host_header_ambiguous; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(app-layer-event:http.host_header_ambiguous; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1073,7 +1091,7 @@ static int DetectHttpHeaderTest29(void) } result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -1095,11 +1113,10 @@ static int DetectHttpHeaderTest30(void) DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http_buf[] = - "POST http://xxx.intranet.local:8000/xxx HTTP/1.1\r\n" - "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_29\r\n" - "Host: xyz.intranet.local:8000\r\n" - "\r\n"; + uint8_t http_buf[] = "POST http://xxx.intranet.local:8000/xxx HTTP/1.1\r\n" + "User-Agent: Mozilla/4.0 (Windows XP 5.1) Java/1.6.0_29\r\n" + "Host: xyz.intranet.local:8000\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1117,7 +1134,7 @@ static int DetectHttpHeaderTest30(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1128,9 +1145,9 @@ static int DetectHttpHeaderTest30(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(app-layer-event:http.host_header_ambiguous; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(app-layer-event:http.host_header_ambiguous; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1154,7 +1171,7 @@ static int DetectHttpHeaderTest30(void) } result = 1; - end: +end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -1172,11 +1189,10 @@ static int DetectHttpHeaderIsdataatParseTest(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (" - "flow:to_server; " - "content:\"one\"; http_header; " - "isdataat:!4,relative; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "flow:to_server; " + "content:\"one\"; http_header; " + "isdataat:!4,relative; sid:1;)"); FAIL_IF_NULL(s); SigMatch *sm = DetectBufferGetLastSigMatch(s, g_http_header_buffer_id); @@ -1205,9 +1221,8 @@ static int DetectEngineHttpHeaderTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1225,7 +1240,7 @@ static int DetectEngineHttpHeaderTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1236,10 +1251,10 @@ static int DetectEngineHttpHeaderTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1295,9 +1310,8 @@ static int DetectEngineHttpHeaderTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1315,7 +1329,7 @@ static int DetectEngineHttpHeaderTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1326,10 +1340,10 @@ static int DetectEngineHttpHeaderTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; depth:15; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; depth:15; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1385,9 +1399,8 @@ static int DetectEngineHttpHeaderTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1405,7 +1418,7 @@ static int DetectEngineHttpHeaderTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1416,10 +1429,10 @@ static int DetectEngineHttpHeaderTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; depth:5; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; depth:5; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1475,9 +1488,8 @@ static int DetectEngineHttpHeaderTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1495,7 +1507,7 @@ static int DetectEngineHttpHeaderTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1506,10 +1518,10 @@ static int DetectEngineHttpHeaderTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; depth:5; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; depth:5; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1565,9 +1577,8 @@ static int DetectEngineHttpHeaderTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1585,7 +1596,7 @@ static int DetectEngineHttpHeaderTest05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1596,10 +1607,10 @@ static int DetectEngineHttpHeaderTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; depth:15; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; depth:15; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1655,9 +1666,8 @@ static int DetectEngineHttpHeaderTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1675,7 +1685,7 @@ static int DetectEngineHttpHeaderTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1686,10 +1696,10 @@ static int DetectEngineHttpHeaderTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; offset:10; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; offset:10; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1745,9 +1755,8 @@ static int DetectEngineHttpHeaderTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1765,7 +1774,7 @@ static int DetectEngineHttpHeaderTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1776,10 +1785,10 @@ static int DetectEngineHttpHeaderTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; offset:15; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; offset:15; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1835,9 +1844,8 @@ static int DetectEngineHttpHeaderTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1855,7 +1863,7 @@ static int DetectEngineHttpHeaderTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1866,10 +1874,10 @@ static int DetectEngineHttpHeaderTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; offset:15; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; offset:15; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1925,9 +1933,8 @@ static int DetectEngineHttpHeaderTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1945,7 +1952,7 @@ static int DetectEngineHttpHeaderTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1956,10 +1963,10 @@ static int DetectEngineHttpHeaderTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; offset:10; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; offset:10; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2015,9 +2022,8 @@ static int DetectEngineHttpHeaderTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2035,7 +2041,7 @@ static int DetectEngineHttpHeaderTest10(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2046,10 +2052,11 @@ static int DetectEngineHttpHeaderTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"three\"; http_header; within:10; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"three\"; http_header; within:10; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2105,9 +2112,8 @@ static int DetectEngineHttpHeaderTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2125,7 +2131,7 @@ static int DetectEngineHttpHeaderTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2136,10 +2142,11 @@ static int DetectEngineHttpHeaderTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"three\"; http_header; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"three\"; http_header; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2195,9 +2202,8 @@ static int DetectEngineHttpHeaderTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2215,7 +2221,7 @@ static int DetectEngineHttpHeaderTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2226,10 +2232,11 @@ static int DetectEngineHttpHeaderTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"three\"; http_header; within:10; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"three\"; http_header; within:10; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2285,9 +2292,8 @@ static int DetectEngineHttpHeaderTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2305,7 +2311,7 @@ static int DetectEngineHttpHeaderTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2316,10 +2322,11 @@ static int DetectEngineHttpHeaderTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"three\"; http_header; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"three\"; http_header; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2375,9 +2382,8 @@ static int DetectEngineHttpHeaderTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2395,7 +2401,7 @@ static int DetectEngineHttpHeaderTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2406,10 +2412,11 @@ static int DetectEngineHttpHeaderTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; distance:7; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"five\"; http_header; distance:7; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2465,9 +2472,8 @@ static int DetectEngineHttpHeaderTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2485,7 +2491,7 @@ static int DetectEngineHttpHeaderTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2496,10 +2502,11 @@ static int DetectEngineHttpHeaderTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"five\"; http_header; distance:15; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"five\"; http_header; distance:15; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2555,9 +2562,8 @@ static int DetectEngineHttpHeaderTest16(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2575,7 +2581,7 @@ static int DetectEngineHttpHeaderTest16(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2586,10 +2592,11 @@ static int DetectEngineHttpHeaderTest16(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"five\"; http_header; distance:7; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"five\"; http_header; distance:7; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2645,9 +2652,8 @@ static int DetectEngineHttpHeaderTest17(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2665,7 +2671,7 @@ static int DetectEngineHttpHeaderTest17(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2676,10 +2682,11 @@ static int DetectEngineHttpHeaderTest17(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; distance:15; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"five\"; http_header; distance:15; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2732,12 +2739,10 @@ static int DetectEngineHttpHeaderTest20(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2758,11 +2763,11 @@ static int DetectEngineHttpHeaderTest20(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2773,11 +2778,11 @@ static int DetectEngineHttpHeaderTest20(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; http_header; within:7; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; http_header; within:7; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2848,12 +2853,10 @@ static int DetectEngineHttpHeaderTest21(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2874,11 +2877,11 @@ static int DetectEngineHttpHeaderTest21(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2889,11 +2892,11 @@ static int DetectEngineHttpHeaderTest21(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; within:7; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; within:7; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2964,12 +2967,10 @@ static int DetectEngineHttpHeaderTest22(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2990,11 +2991,11 @@ static int DetectEngineHttpHeaderTest22(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3005,11 +3006,11 @@ static int DetectEngineHttpHeaderTest22(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; distance:3; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; distance:3; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3080,12 +3081,10 @@ static int DetectEngineHttpHeaderTest23(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3106,11 +3105,11 @@ static int DetectEngineHttpHeaderTest23(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3121,11 +3120,11 @@ static int DetectEngineHttpHeaderTest23(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; distance:13; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; distance:13; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3196,12 +3195,10 @@ static int DetectEngineHttpHeaderTest24(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3222,11 +3219,11 @@ static int DetectEngineHttpHeaderTest24(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3237,11 +3234,11 @@ static int DetectEngineHttpHeaderTest24(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; within:15; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; within:15; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3312,12 +3309,10 @@ static int DetectEngineHttpHeaderTest25(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3338,11 +3333,11 @@ static int DetectEngineHttpHeaderTest25(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3353,11 +3348,11 @@ static int DetectEngineHttpHeaderTest25(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; within:10; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; within:10; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3428,12 +3423,10 @@ static int DetectEngineHttpHeaderTest26(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3454,11 +3447,11 @@ static int DetectEngineHttpHeaderTest26(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3469,11 +3462,11 @@ static int DetectEngineHttpHeaderTest26(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; distance:8; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; distance:8; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3544,12 +3537,10 @@ static int DetectEngineHttpHeaderTest27(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3570,11 +3561,11 @@ static int DetectEngineHttpHeaderTest27(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3585,11 +3576,11 @@ static int DetectEngineHttpHeaderTest27(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; distance:14; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; distance:14; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3660,18 +3651,17 @@ static int DetectEngineHttpHeaderTest28(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3706,10 +3696,10 @@ static int DetectEngineHttpHeaderTest28(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 6\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 6\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3777,18 +3767,17 @@ static int DetectEngineHttpHeaderTest29(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3823,10 +3812,10 @@ static int DetectEngineHttpHeaderTest29(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 7\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 7\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3927,19 +3916,18 @@ static int DetectEngineHttpHeaderTest30(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Set-Cookie: dummycookieset\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Set-Cookie: dummycookieset\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3974,10 +3962,10 @@ static int DetectEngineHttpHeaderTest30(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"dummycookieset\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"dummycookieset\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4039,8 +4027,8 @@ static int DetectEngineHttpHeaderTest30(void) } /** \test reassembly bug where headers with names of length 6 were - * skipped - */ + * skipped + */ static int DetectEngineHttpHeaderTest31(void) { TcpSession ssn; @@ -4050,12 +4038,11 @@ static int DetectEngineHttpHeaderTest31(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Accept: blah\r\n" - "Cookie: blah\r\n" - "Crazy6: blah\r\n" - "SixZix: blah\r\n\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Accept: blah\r\n" + "Cookie: blah\r\n" + "Crazy6: blah\r\n" + "SixZix: blah\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -4074,7 +4061,7 @@ static int DetectEngineHttpHeaderTest31(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4085,12 +4072,12 @@ static int DetectEngineHttpHeaderTest31(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Accept|3a|\"; http_header; " - "content:!\"Cookie|3a|\"; http_header; " - "content:\"Crazy6|3a|\"; http_header; " - "content:\"SixZix|3a|\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(content:\"Accept|3a|\"; http_header; " + "content:!\"Cookie|3a|\"; http_header; " + "content:\"Crazy6|3a|\"; http_header; " + "content:\"SixZix|3a|\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4146,16 +4133,15 @@ static int DetectEngineHttpHeaderTest32(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n" - "Dummy-Header: kaboom\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n" + "Dummy-Header: kaboom\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -4174,7 +4160,7 @@ static int DetectEngineHttpHeaderTest32(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4185,9 +4171,9 @@ static int DetectEngineHttpHeaderTest32(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(content:\"Dummy\"; http_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4244,17 +4230,15 @@ static int DetectEngineHttpHeaderTest33(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n"; - uint8_t http2_buf[] = - "Dummy-Header: kaboom\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n"; + uint8_t http2_buf[] = "Dummy-Header: kaboom\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; @@ -4276,11 +4260,11 @@ static int DetectEngineHttpHeaderTest33(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4289,9 +4273,9 @@ static int DetectEngineHttpHeaderTest33(void) FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(content:\"Dummy\"; http_header; " + "sid:1;)"); FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); @@ -4339,19 +4323,16 @@ static int DetectEngineHttpHeaderTest34(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Dummy-Header1: blah\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n"; - uint8_t http2_buf[] = - "13\r\n" - "This is dummy body1\r\n" - "0\r\n"; - uint8_t http3_buf[] = - "Dummy-Header2: kaboom\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Dummy-Header1: blah\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n"; + uint8_t http2_buf[] = "13\r\n" + "This is dummy body1\r\n" + "0\r\n"; + uint8_t http3_buf[] = "Dummy-Header2: kaboom\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; uint32_t http3_len = sizeof(http3_buf) - 1; @@ -4375,17 +4356,17 @@ static int DetectEngineHttpHeaderTest34(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p1->pcap_cnt = 1; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->pcap_cnt = 2; p3->flow = &f; p3->flowflags |= FLOW_PKT_TOSERVER; p3->flowflags |= FLOW_PKT_ESTABLISHED; - p3->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p3->pcap_cnt = 3; f.alproto = ALPROTO_HTTP1; @@ -4395,9 +4376,10 @@ static int DetectEngineHttpHeaderTest34(void) FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; content:\"Header2\"; http_header; within:8; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(content:\"Dummy\"; http_header; content:\"Header2\"; http_header; within:8; " + "sid:1;)"); FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); @@ -4452,19 +4434,16 @@ static int DetectEngineHttpHeaderTest35(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Dummy-Header1: blah\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n"; - uint8_t http2_buf[] = - "13\r\n" - "This is dummy body1\r\n" - "0\r\n"; - uint8_t http3_buf[] = - "Dummy-Header2: kaboom\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Dummy-Header1: blah\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n"; + uint8_t http2_buf[] = "13\r\n" + "This is dummy body1\r\n" + "0\r\n"; + uint8_t http3_buf[] = "Dummy-Header2: kaboom\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; uint32_t http3_len = sizeof(http3_buf) - 1; @@ -4488,17 +4467,17 @@ static int DetectEngineHttpHeaderTest35(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p1->pcap_cnt = 1; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->pcap_cnt = 2; p3->flow = &f; p3->flowflags |= FLOW_PKT_TOSERVER; p3->flowflags |= FLOW_PKT_ESTABLISHED; - p3->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p3->pcap_cnt = 3; f.alproto = ALPROTO_HTTP1; @@ -4508,9 +4487,10 @@ static int DetectEngineHttpHeaderTest35(void) FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; fast_pattern; content:\"Header2\"; http_header; within:8; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(content:\"Dummy\"; http_header; fast_pattern; " + "content:\"Header2\"; http_header; within:8; " + "sid:1;)"); FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); @@ -4571,79 +4551,45 @@ void DetectHttpHeaderRegisterTests(void) UtRegisterTest("DetectHttpHeaderTest29", DetectHttpHeaderTest29); UtRegisterTest("DetectHttpHeaderTest30", DetectHttpHeaderTest30); - UtRegisterTest("DetectHttpHeaderIsdataatParseTest", - DetectHttpHeaderIsdataatParseTest); - - UtRegisterTest("DetectEngineHttpHeaderTest01", - DetectEngineHttpHeaderTest01); - UtRegisterTest("DetectEngineHttpHeaderTest02", - DetectEngineHttpHeaderTest02); - UtRegisterTest("DetectEngineHttpHeaderTest03", - DetectEngineHttpHeaderTest03); - UtRegisterTest("DetectEngineHttpHeaderTest04", - DetectEngineHttpHeaderTest04); - UtRegisterTest("DetectEngineHttpHeaderTest05", - DetectEngineHttpHeaderTest05); - UtRegisterTest("DetectEngineHttpHeaderTest06", - DetectEngineHttpHeaderTest06); - UtRegisterTest("DetectEngineHttpHeaderTest07", - DetectEngineHttpHeaderTest07); - UtRegisterTest("DetectEngineHttpHeaderTest08", - DetectEngineHttpHeaderTest08); - UtRegisterTest("DetectEngineHttpHeaderTest09", - DetectEngineHttpHeaderTest09); - UtRegisterTest("DetectEngineHttpHeaderTest10", - DetectEngineHttpHeaderTest10); - UtRegisterTest("DetectEngineHttpHeaderTest11", - DetectEngineHttpHeaderTest11); - UtRegisterTest("DetectEngineHttpHeaderTest12", - DetectEngineHttpHeaderTest12); - UtRegisterTest("DetectEngineHttpHeaderTest13", - DetectEngineHttpHeaderTest13); - UtRegisterTest("DetectEngineHttpHeaderTest14", - DetectEngineHttpHeaderTest14); - UtRegisterTest("DetectEngineHttpHeaderTest15", - DetectEngineHttpHeaderTest15); - UtRegisterTest("DetectEngineHttpHeaderTest16", - DetectEngineHttpHeaderTest16); - UtRegisterTest("DetectEngineHttpHeaderTest17", - DetectEngineHttpHeaderTest17); - UtRegisterTest("DetectEngineHttpHeaderTest20", - DetectEngineHttpHeaderTest20); - UtRegisterTest("DetectEngineHttpHeaderTest21", - DetectEngineHttpHeaderTest21); - UtRegisterTest("DetectEngineHttpHeaderTest22", - DetectEngineHttpHeaderTest22); - UtRegisterTest("DetectEngineHttpHeaderTest23", - DetectEngineHttpHeaderTest23); - UtRegisterTest("DetectEngineHttpHeaderTest24", - DetectEngineHttpHeaderTest24); - UtRegisterTest("DetectEngineHttpHeaderTest25", - DetectEngineHttpHeaderTest25); - UtRegisterTest("DetectEngineHttpHeaderTest26", - DetectEngineHttpHeaderTest26); - UtRegisterTest("DetectEngineHttpHeaderTest27", - DetectEngineHttpHeaderTest27); - UtRegisterTest("DetectEngineHttpHeaderTest28", - DetectEngineHttpHeaderTest28); - UtRegisterTest("DetectEngineHttpHeaderTest29", - DetectEngineHttpHeaderTest29); - UtRegisterTest("DetectEngineHttpHeaderTest30", - DetectEngineHttpHeaderTest30); - UtRegisterTest("DetectEngineHttpHeaderTest31", - DetectEngineHttpHeaderTest31); + UtRegisterTest("DetectHttpHeaderIsdataatParseTest", DetectHttpHeaderIsdataatParseTest); + + UtRegisterTest("DetectEngineHttpHeaderTest01", DetectEngineHttpHeaderTest01); + UtRegisterTest("DetectEngineHttpHeaderTest02", DetectEngineHttpHeaderTest02); + UtRegisterTest("DetectEngineHttpHeaderTest03", DetectEngineHttpHeaderTest03); + UtRegisterTest("DetectEngineHttpHeaderTest04", DetectEngineHttpHeaderTest04); + UtRegisterTest("DetectEngineHttpHeaderTest05", DetectEngineHttpHeaderTest05); + UtRegisterTest("DetectEngineHttpHeaderTest06", DetectEngineHttpHeaderTest06); + UtRegisterTest("DetectEngineHttpHeaderTest07", DetectEngineHttpHeaderTest07); + UtRegisterTest("DetectEngineHttpHeaderTest08", DetectEngineHttpHeaderTest08); + UtRegisterTest("DetectEngineHttpHeaderTest09", DetectEngineHttpHeaderTest09); + UtRegisterTest("DetectEngineHttpHeaderTest10", DetectEngineHttpHeaderTest10); + UtRegisterTest("DetectEngineHttpHeaderTest11", DetectEngineHttpHeaderTest11); + UtRegisterTest("DetectEngineHttpHeaderTest12", DetectEngineHttpHeaderTest12); + UtRegisterTest("DetectEngineHttpHeaderTest13", DetectEngineHttpHeaderTest13); + UtRegisterTest("DetectEngineHttpHeaderTest14", DetectEngineHttpHeaderTest14); + UtRegisterTest("DetectEngineHttpHeaderTest15", DetectEngineHttpHeaderTest15); + UtRegisterTest("DetectEngineHttpHeaderTest16", DetectEngineHttpHeaderTest16); + UtRegisterTest("DetectEngineHttpHeaderTest17", DetectEngineHttpHeaderTest17); + UtRegisterTest("DetectEngineHttpHeaderTest20", DetectEngineHttpHeaderTest20); + UtRegisterTest("DetectEngineHttpHeaderTest21", DetectEngineHttpHeaderTest21); + UtRegisterTest("DetectEngineHttpHeaderTest22", DetectEngineHttpHeaderTest22); + UtRegisterTest("DetectEngineHttpHeaderTest23", DetectEngineHttpHeaderTest23); + UtRegisterTest("DetectEngineHttpHeaderTest24", DetectEngineHttpHeaderTest24); + UtRegisterTest("DetectEngineHttpHeaderTest25", DetectEngineHttpHeaderTest25); + UtRegisterTest("DetectEngineHttpHeaderTest26", DetectEngineHttpHeaderTest26); + UtRegisterTest("DetectEngineHttpHeaderTest27", DetectEngineHttpHeaderTest27); + UtRegisterTest("DetectEngineHttpHeaderTest28", DetectEngineHttpHeaderTest28); + UtRegisterTest("DetectEngineHttpHeaderTest29", DetectEngineHttpHeaderTest29); + UtRegisterTest("DetectEngineHttpHeaderTest30", DetectEngineHttpHeaderTest30); + UtRegisterTest("DetectEngineHttpHeaderTest31", DetectEngineHttpHeaderTest31); #if 0 UtRegisterTest("DetectEngineHttpHeaderTest30", DetectEngineHttpHeaderTest30, 1); #endif - UtRegisterTest("DetectEngineHttpHeaderTest32", - DetectEngineHttpHeaderTest32); - UtRegisterTest("DetectEngineHttpHeaderTest33 -- Trailer", - DetectEngineHttpHeaderTest33); - UtRegisterTest("DetectEngineHttpHeaderTest34 -- Trailer", - DetectEngineHttpHeaderTest34); - UtRegisterTest("DetectEngineHttpHeaderTest35 -- Trailer", - DetectEngineHttpHeaderTest35); + UtRegisterTest("DetectEngineHttpHeaderTest32", DetectEngineHttpHeaderTest32); + UtRegisterTest("DetectEngineHttpHeaderTest33 -- Trailer", DetectEngineHttpHeaderTest33); + UtRegisterTest("DetectEngineHttpHeaderTest34 -- Trailer", DetectEngineHttpHeaderTest34); + UtRegisterTest("DetectEngineHttpHeaderTest35 -- Trailer", DetectEngineHttpHeaderTest35); } /** diff --git a/src/tests/detect-http-host.c b/src/tests/detect-http-host.c index 4fbdff9b69cc..79cd1a81c906 100644 --- a/src/tests/detect-http-host.c +++ b/src/tests/detect-http-host.c @@ -21,7 +21,6 @@ * @{ */ - /** \file * * \author Anoop Saldanha @@ -37,10 +36,10 @@ #include "flow-util.h" #include "flow.h" #include "app-layer-parser.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "app-layer-protos.h" #include "detect-engine-build.h" #include "detect-engine-alert.h" @@ -58,10 +57,9 @@ static int DetectEngineHttpHHTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -79,7 +77,7 @@ static int DetectEngineHttpHHTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -90,10 +88,10 @@ static int DetectEngineHttpHHTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"connect\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"connect\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -154,10 +152,9 @@ static int DetectEngineHttpHHTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -175,7 +172,7 @@ static int DetectEngineHttpHHTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -186,10 +183,10 @@ static int DetectEngineHttpHHTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"co\"; depth:4; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"co\"; depth:4; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -250,10 +247,9 @@ static int DetectEngineHttpHHTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -271,7 +267,7 @@ static int DetectEngineHttpHHTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -282,10 +278,10 @@ static int DetectEngineHttpHHTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:!\"ect\"; depth:4; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:!\"ect\"; depth:4; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -346,10 +342,9 @@ static int DetectEngineHttpHHTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -367,7 +362,7 @@ static int DetectEngineHttpHHTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -378,10 +373,10 @@ static int DetectEngineHttpHHTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"ect\"; depth:4; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"ect\"; depth:4; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -442,10 +437,9 @@ static int DetectEngineHttpHHTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -463,7 +457,7 @@ static int DetectEngineHttpHHTest05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -474,10 +468,10 @@ static int DetectEngineHttpHHTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:!\"con\"; depth:4; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:!\"con\"; depth:4; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -538,10 +532,9 @@ static int DetectEngineHttpHHTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -559,7 +552,7 @@ static int DetectEngineHttpHHTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -570,10 +563,10 @@ static int DetectEngineHttpHHTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"ect\"; offset:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"ect\"; offset:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -634,10 +627,9 @@ static int DetectEngineHttpHHTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -655,7 +647,7 @@ static int DetectEngineHttpHHTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -666,10 +658,10 @@ static int DetectEngineHttpHHTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:!\"co\"; offset:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:!\"co\"; offset:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -730,10 +722,9 @@ static int DetectEngineHttpHHTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -751,7 +742,7 @@ static int DetectEngineHttpHHTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -762,10 +753,10 @@ static int DetectEngineHttpHHTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:!\"ect\"; offset:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:!\"ect\"; offset:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -826,10 +817,9 @@ static int DetectEngineHttpHHTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -847,7 +837,7 @@ static int DetectEngineHttpHHTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -858,10 +848,10 @@ static int DetectEngineHttpHHTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"con\"; offset:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"con\"; offset:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -922,10 +912,9 @@ static int DetectEngineHttpHHTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -943,7 +932,7 @@ static int DetectEngineHttpHHTest10(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -954,11 +943,11 @@ static int DetectEngineHttpHHTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:\"ec\"; within:4; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:\"ec\"; within:4; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1019,10 +1008,9 @@ static int DetectEngineHttpHHTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1040,7 +1028,7 @@ static int DetectEngineHttpHHTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1051,11 +1039,11 @@ static int DetectEngineHttpHHTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:!\"ec\"; within:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:!\"ec\"; within:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1116,10 +1104,9 @@ static int DetectEngineHttpHHTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1137,7 +1124,7 @@ static int DetectEngineHttpHHTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1148,11 +1135,11 @@ static int DetectEngineHttpHHTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:\"ec\"; within:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:\"ec\"; within:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1213,10 +1200,9 @@ static int DetectEngineHttpHHTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1234,7 +1220,7 @@ static int DetectEngineHttpHHTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1245,11 +1231,11 @@ static int DetectEngineHttpHHTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:!\"ec\"; within:4; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:!\"ec\"; within:4; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1310,10 +1296,9 @@ static int DetectEngineHttpHHTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1331,7 +1316,7 @@ static int DetectEngineHttpHHTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1342,11 +1327,11 @@ static int DetectEngineHttpHHTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:\"ec\"; distance:2; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:\"ec\"; distance:2; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1407,10 +1392,9 @@ static int DetectEngineHttpHHTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1428,7 +1412,7 @@ static int DetectEngineHttpHHTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1439,11 +1423,11 @@ static int DetectEngineHttpHHTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:!\"ec\"; distance:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:!\"ec\"; distance:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1504,10 +1488,9 @@ static int DetectEngineHttpHHTest16(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1525,7 +1508,7 @@ static int DetectEngineHttpHHTest16(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1536,11 +1519,11 @@ static int DetectEngineHttpHHTest16(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:\"ec\"; distance:3; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:\"ec\"; distance:3; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1601,10 +1584,9 @@ static int DetectEngineHttpHHTest17(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1622,7 +1604,7 @@ static int DetectEngineHttpHHTest17(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1633,11 +1615,11 @@ static int DetectEngineHttpHHTest17(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"co\"; http_host; " - "content:!\"ec\"; distance:2; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"co\"; http_host; " + "content:!\"ec\"; distance:2; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1694,10 +1676,9 @@ static int DetectEngineHttpHHTest18(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.kaboom.com\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.kaboom.com\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1715,7 +1696,7 @@ static int DetectEngineHttpHHTest18(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1726,10 +1707,10 @@ static int DetectEngineHttpHHTest18(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"kaboom\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"kaboom\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1786,10 +1767,9 @@ static int DetectEngineHttpHHTest19(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.kaboom.com:8080\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.kaboom.com:8080\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1807,7 +1787,7 @@ static int DetectEngineHttpHHTest19(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1818,10 +1798,10 @@ static int DetectEngineHttpHHTest19(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"kaboom\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"kaboom\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1878,10 +1858,9 @@ static int DetectEngineHttpHHTest20(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.kaboom.com:8080\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.kaboom.com:8080\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1899,7 +1878,7 @@ static int DetectEngineHttpHHTest20(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1910,10 +1889,10 @@ static int DetectEngineHttpHHTest20(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"8080\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"8080\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1970,9 +1949,8 @@ static int DetectEngineHttpHHTest21(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com/index.html HTTP/1.0\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com/index.html HTTP/1.0\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1990,7 +1968,7 @@ static int DetectEngineHttpHHTest21(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2001,10 +1979,10 @@ static int DetectEngineHttpHHTest21(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"kaboom\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"kaboom\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2061,9 +2039,8 @@ static int DetectEngineHttpHHTest22(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2081,7 +2058,7 @@ static int DetectEngineHttpHHTest22(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2092,10 +2069,10 @@ static int DetectEngineHttpHHTest22(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"kaboom\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"kaboom\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2152,9 +2129,8 @@ static int DetectEngineHttpHHTest23(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2172,7 +2148,7 @@ static int DetectEngineHttpHHTest23(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2183,10 +2159,10 @@ static int DetectEngineHttpHHTest23(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"8080\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"8080\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2243,10 +2219,9 @@ static int DetectEngineHttpHHTest24(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "Host: www.rabbit.com\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "Host: www.rabbit.com\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2264,7 +2239,7 @@ static int DetectEngineHttpHHTest24(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2275,10 +2250,10 @@ static int DetectEngineHttpHHTest24(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"kaboom\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"kaboom\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2335,10 +2310,9 @@ static int DetectEngineHttpHHTest25(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "Host: www.rabbit.com\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "Host: www.rabbit.com\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2356,7 +2330,7 @@ static int DetectEngineHttpHHTest25(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2367,10 +2341,10 @@ static int DetectEngineHttpHHTest25(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_host header test\"; " - "content:\"rabbit\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_host header test\"; " + "content:\"rabbit\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2433,15 +2407,15 @@ static int DetectHttpHHTest01(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_host\"; " - "content:\"one\"; http_host; sid:1;)"); + "(msg:\"Testing http_host\"; " + "content:\"one\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } else { goto end; } - end: +end: DetectEngineCtxFree(de_ctx); return result; @@ -2462,12 +2436,12 @@ static int DetectHttpHHTest02(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_host\"; " - "content:\"one\"; http_host; sid:1;)"); + "(msg:\"Testing http_host\"; " + "content:\"one\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; @@ -2488,12 +2462,12 @@ static int DetectHttpHHTest03(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_host\"; " - "http_host; sid:1;)"); + "(msg:\"Testing http_host\"; " + "http_host; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; @@ -2514,12 +2488,12 @@ static int DetectHttpHHTest04(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_host\"; " - "content:\"one\"; rawbytes; http_host; sid:1;)"); + "(msg:\"Testing http_host\"; " + "content:\"one\"; rawbytes; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; @@ -2539,12 +2513,12 @@ static int DetectHttpHHTest05(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing http_host\"; " - "content:\"one\"; http_host; sid:1;)"); + "(msg:\"Testing http_host\"; " + "content:\"one\"; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) result = 1; - end: +end: DetectEngineCtxFree(de_ctx); return result; @@ -2557,9 +2531,8 @@ static int DetectHttpHHTest05a(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any " - "(content:\"ABC\"; http_host; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(content:\"ABC\"; http_host; sid:1;)"); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); @@ -2579,12 +2552,11 @@ static int DetectHttpHHTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: This is dummy message body\r\n" - "Content-Type: text/html\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2614,10 +2586,10 @@ static int DetectHttpHHTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:\"message\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:\"message\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2674,12 +2646,10 @@ static int DetectHttpHHTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: This is dummy message"; - uint8_t http2_buf[] = - "body1\r\n\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: This is dummy message"; + uint8_t http2_buf[] = "body1\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2700,11 +2670,11 @@ static int DetectHttpHHTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2715,10 +2685,10 @@ static int DetectHttpHHTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:\"message\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:\"message\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2789,12 +2759,10 @@ static int DetectHttpHHTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "host: This is dummy mess"; - uint8_t http2_buf[] = - "age body\r\n\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "host: This is dummy mess"; + uint8_t http2_buf[] = "age body\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2815,11 +2783,11 @@ static int DetectHttpHHTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2830,10 +2798,10 @@ static int DetectHttpHHTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:\"message\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:\"message\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2907,16 +2875,14 @@ static int DetectHttpHHTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: This is dummy body1"; + uint8_t http2_buf[] = "This is dummy message body2\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2937,11 +2903,11 @@ static int DetectHttpHHTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2952,10 +2918,10 @@ static int DetectHttpHHTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:\"body1this\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:\"body1this\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3029,16 +2995,14 @@ static int DetectHttpHHTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: This is dummy bodY1"; - uint8_t http2_buf[] = - "This is dummy message body2\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy bodY1"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: This is dummy bodY1"; + uint8_t http2_buf[] = "This is dummy message body2\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy bodY1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3059,11 +3023,11 @@ static int DetectHttpHHTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3074,10 +3038,10 @@ static int DetectHttpHHTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:\"body1this\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:\"body1this\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3115,7 +3079,6 @@ static int DetectHttpHHTest10(void) goto end; } - /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3151,12 +3114,11 @@ static int DetectHttpHHTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: This is dummy message body\r\n" - "Content-Type: text/html\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3175,7 +3137,7 @@ static int DetectHttpHHTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3186,10 +3148,10 @@ static int DetectHttpHHTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:!\"message\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:!\"message\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3245,11 +3207,10 @@ static int DetectHttpHHTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: This is dummy body\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: This is dummy body\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3268,7 +3229,7 @@ static int DetectHttpHHTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3279,10 +3240,10 @@ static int DetectHttpHHTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:!\"message\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:!\"message\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3338,12 +3299,11 @@ static int DetectHttpHHTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" - "Content-Type: text/html\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" + "Content-Type: text/html\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3362,7 +3322,7 @@ static int DetectHttpHHTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3373,10 +3333,11 @@ static int DetectHttpHHTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_host; " - "sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:\"abcdefghijklmnopqrstuvwxyz0123456789\"; http_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3459,7 +3420,7 @@ static int DetectHttpHHTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3471,12 +3432,16 @@ static int DetectHttpHHTest14(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; http_cookie; content:\"body one\"; http_host; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; " + "http_cookie; content:\"body one\"; http_host; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; http_cookie; content:\"body two\"; http_host; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; " + "http_cookie; content:\"body two\"; http_host; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; @@ -4642,16 +4607,14 @@ static int DetectHttpHRHTest37(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "User-Agent: www.openinfosecfoundation.org\r\n" - "Host: This is dummy bodY1"; - uint8_t http2_buf[] = - "This is dummy message body2\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy bodY1"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Host: This is dummy bodY1"; + uint8_t http2_buf[] = "This is dummy message body2\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy bodY1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4672,11 +4635,11 @@ static int DetectHttpHRHTest37(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4687,10 +4650,10 @@ static int DetectHttpHRHTest37(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host test\"; " - "content:\"body1this\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host test\"; " + "content:\"body1this\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4763,10 +4726,9 @@ static int DetectEngineHttpHRHTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -4784,7 +4746,7 @@ static int DetectEngineHttpHRHTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4795,10 +4757,10 @@ static int DetectEngineHttpHRHTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"CONNECT\"; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"CONNECT\"; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4855,10 +4817,9 @@ static int DetectEngineHttpHRHTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -4876,7 +4837,7 @@ static int DetectEngineHttpHRHTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4887,10 +4848,10 @@ static int DetectEngineHttpHRHTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"CO\"; depth:4; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"CO\"; depth:4; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4947,10 +4908,9 @@ static int DetectEngineHttpHRHTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -4968,7 +4928,7 @@ static int DetectEngineHttpHRHTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4979,10 +4939,10 @@ static int DetectEngineHttpHRHTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:!\"ECT\"; depth:4; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:!\"ECT\"; depth:4; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5039,10 +4999,9 @@ static int DetectEngineHttpHRHTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5060,7 +5019,7 @@ static int DetectEngineHttpHRHTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5071,10 +5030,10 @@ static int DetectEngineHttpHRHTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"ECT\"; depth:4; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"ECT\"; depth:4; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5131,10 +5090,9 @@ static int DetectEngineHttpHRHTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5152,7 +5110,7 @@ static int DetectEngineHttpHRHTest05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5163,10 +5121,10 @@ static int DetectEngineHttpHRHTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:!\"CON\"; depth:4; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:!\"CON\"; depth:4; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5223,10 +5181,9 @@ static int DetectEngineHttpHRHTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5244,7 +5201,7 @@ static int DetectEngineHttpHRHTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5255,10 +5212,10 @@ static int DetectEngineHttpHRHTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"ECT\"; offset:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"ECT\"; offset:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5315,10 +5272,9 @@ static int DetectEngineHttpHRHTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5336,7 +5292,7 @@ static int DetectEngineHttpHRHTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5347,10 +5303,10 @@ static int DetectEngineHttpHRHTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:!\"CO\"; offset:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:!\"CO\"; offset:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5407,10 +5363,9 @@ static int DetectEngineHttpHRHTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5428,7 +5383,7 @@ static int DetectEngineHttpHRHTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5439,10 +5394,10 @@ static int DetectEngineHttpHRHTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:!\"ECT\"; offset:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:!\"ECT\"; offset:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5499,10 +5454,9 @@ static int DetectEngineHttpHRHTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5520,7 +5474,7 @@ static int DetectEngineHttpHRHTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5531,10 +5485,10 @@ static int DetectEngineHttpHRHTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http host header test\"; " - "content:\"CON\"; offset:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http host header test\"; " + "content:\"CON\"; offset:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5591,10 +5545,9 @@ static int DetectEngineHttpHRHTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5612,7 +5565,7 @@ static int DetectEngineHttpHRHTest10(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5623,11 +5576,11 @@ static int DetectEngineHttpHRHTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:\"EC\"; within:4; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:\"EC\"; within:4; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5684,10 +5637,9 @@ static int DetectEngineHttpHRHTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5705,7 +5657,7 @@ static int DetectEngineHttpHRHTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5716,11 +5668,11 @@ static int DetectEngineHttpHRHTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:!\"EC\"; within:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:!\"EC\"; within:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5777,10 +5729,9 @@ static int DetectEngineHttpHRHTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5798,7 +5749,7 @@ static int DetectEngineHttpHRHTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5809,11 +5760,11 @@ static int DetectEngineHttpHRHTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:\"EC\"; within:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:\"EC\"; within:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5870,10 +5821,9 @@ static int DetectEngineHttpHRHTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5891,7 +5841,7 @@ static int DetectEngineHttpHRHTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5902,11 +5852,11 @@ static int DetectEngineHttpHRHTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:!\"EC\"; within:4; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:!\"EC\"; within:4; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5963,10 +5913,9 @@ static int DetectEngineHttpHRHTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5984,7 +5933,7 @@ static int DetectEngineHttpHRHTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5995,11 +5944,11 @@ static int DetectEngineHttpHRHTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:\"EC\"; distance:2; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:\"EC\"; distance:2; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6056,10 +6005,9 @@ static int DetectEngineHttpHRHTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6077,7 +6025,7 @@ static int DetectEngineHttpHRHTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6088,11 +6036,11 @@ static int DetectEngineHttpHRHTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:!\"EC\"; distance:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:!\"EC\"; distance:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6149,10 +6097,9 @@ static int DetectEngineHttpHRHTest16(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6170,7 +6117,7 @@ static int DetectEngineHttpHRHTest16(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6181,11 +6128,11 @@ static int DetectEngineHttpHRHTest16(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:\"EC\"; distance:3; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:\"EC\"; distance:3; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6242,10 +6189,9 @@ static int DetectEngineHttpHRHTest17(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: CONNECT\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: CONNECT\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6263,7 +6209,7 @@ static int DetectEngineHttpHRHTest17(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6274,11 +6220,11 @@ static int DetectEngineHttpHRHTest17(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"CO\"; http_raw_host; " - "content:!\"EC\"; distance:2; http_raw_host; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"CO\"; http_raw_host; " + "content:!\"EC\"; distance:2; http_raw_host; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6331,10 +6277,9 @@ static int DetectEngineHttpHRHTest18(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.kaboom.com:8080\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.kaboom.com:8080\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6352,7 +6297,7 @@ static int DetectEngineHttpHRHTest18(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6363,10 +6308,10 @@ static int DetectEngineHttpHRHTest18(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"kaboom\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"kaboom\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6419,10 +6364,9 @@ static int DetectEngineHttpHRHTest19(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.kaboom.com:8080\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.kaboom.com:8080\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6440,7 +6384,7 @@ static int DetectEngineHttpHRHTest19(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6451,10 +6395,10 @@ static int DetectEngineHttpHRHTest19(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"kaboom\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"kaboom\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6507,10 +6451,9 @@ static int DetectEngineHttpHRHTest20(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.kaboom.com:8080\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.kaboom.com:8080\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6528,7 +6471,7 @@ static int DetectEngineHttpHRHTest20(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6539,10 +6482,10 @@ static int DetectEngineHttpHRHTest20(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"8080\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"8080\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6595,9 +6538,8 @@ static int DetectEngineHttpHRHTest21(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com/index.html HTTP/1.0\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com/index.html HTTP/1.0\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6615,7 +6557,7 @@ static int DetectEngineHttpHRHTest21(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6626,10 +6568,10 @@ static int DetectEngineHttpHRHTest21(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"kaboom\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"kaboom\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6682,9 +6624,8 @@ static int DetectEngineHttpHRHTest22(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6702,7 +6643,7 @@ static int DetectEngineHttpHRHTest22(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6713,10 +6654,10 @@ static int DetectEngineHttpHRHTest22(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"kaboom\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"kaboom\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6769,9 +6710,8 @@ static int DetectEngineHttpHRHTest23(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6789,7 +6729,7 @@ static int DetectEngineHttpHRHTest23(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6800,10 +6740,10 @@ static int DetectEngineHttpHRHTest23(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"8080\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"8080\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6856,10 +6796,9 @@ static int DetectEngineHttpHRHTest24(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "Host: www.rabbit.com\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "Host: www.rabbit.com\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6877,7 +6816,7 @@ static int DetectEngineHttpHRHTest24(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6888,10 +6827,10 @@ static int DetectEngineHttpHRHTest24(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"kaboom\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"kaboom\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6944,10 +6883,9 @@ static int DetectEngineHttpHRHTest25(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" - "Host: www.rabbit.com\r\n" - "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET http://www.kaboom.com:8080/index.html HTTP/1.0\r\n" + "Host: www.rabbit.com\r\n" + "User-Agent: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6965,7 +6903,7 @@ static int DetectEngineHttpHRHTest25(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6976,10 +6914,10 @@ static int DetectEngineHttpHRHTest25(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http_raw_host header test\"; " - "content:\"rabbit\"; http_raw_host; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http_raw_host header test\"; " + "content:\"rabbit\"; http_raw_host; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; diff --git a/src/tests/detect-http-method.c b/src/tests/detect-http-method.c index 1da5c18917e3..c8ec44ba1ce6 100644 --- a/src/tests/detect-http-method.c +++ b/src/tests/detect-http-method.c @@ -21,7 +21,6 @@ * @{ */ - /** \file * * \author Anoop Saldanha @@ -36,10 +35,10 @@ #include "../flow.h" #include "../app-layer-parser.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" #include "../app-layer.h" -#include "../app-layer-htp.h" +#include "../app-layer/http/parser.h" #include "../app-layer-protos.h" #include "../detect-isdataat.h" #include "../detect-engine-build.h" @@ -58,9 +57,8 @@ static int DetectEngineHttpMethodTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -78,7 +76,7 @@ static int DetectEngineHttpMethodTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -89,10 +87,10 @@ static int DetectEngineHttpMethodTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"GET\"; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"GET\"; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -149,9 +147,8 @@ static int DetectEngineHttpMethodTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -169,7 +166,7 @@ static int DetectEngineHttpMethodTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -180,10 +177,10 @@ static int DetectEngineHttpMethodTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; depth:4; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; depth:4; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -240,9 +237,8 @@ static int DetectEngineHttpMethodTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -260,7 +256,7 @@ static int DetectEngineHttpMethodTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -271,10 +267,10 @@ static int DetectEngineHttpMethodTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"ECT\"; depth:4; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"ECT\"; depth:4; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -331,9 +327,8 @@ static int DetectEngineHttpMethodTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -351,7 +346,7 @@ static int DetectEngineHttpMethodTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -362,10 +357,10 @@ static int DetectEngineHttpMethodTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"ECT\"; depth:4; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"ECT\"; depth:4; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -422,9 +417,8 @@ static int DetectEngineHttpMethodTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -442,7 +436,7 @@ static int DetectEngineHttpMethodTest05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -453,10 +447,10 @@ static int DetectEngineHttpMethodTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"CON\"; depth:4; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"CON\"; depth:4; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -513,9 +507,8 @@ static int DetectEngineHttpMethodTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -533,7 +526,7 @@ static int DetectEngineHttpMethodTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -544,10 +537,10 @@ static int DetectEngineHttpMethodTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"ECT\"; offset:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"ECT\"; offset:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -604,9 +597,8 @@ static int DetectEngineHttpMethodTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -624,7 +616,7 @@ static int DetectEngineHttpMethodTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -635,10 +627,10 @@ static int DetectEngineHttpMethodTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"CO\"; offset:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"CO\"; offset:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -695,9 +687,8 @@ static int DetectEngineHttpMethodTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -715,7 +706,7 @@ static int DetectEngineHttpMethodTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -726,10 +717,10 @@ static int DetectEngineHttpMethodTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"ECT\"; offset:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"ECT\"; offset:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -786,9 +777,8 @@ static int DetectEngineHttpMethodTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -806,7 +796,7 @@ static int DetectEngineHttpMethodTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -817,10 +807,10 @@ static int DetectEngineHttpMethodTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CON\"; offset:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CON\"; offset:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -877,9 +867,8 @@ static int DetectEngineHttpMethodTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -897,7 +886,7 @@ static int DetectEngineHttpMethodTest10(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -908,11 +897,11 @@ static int DetectEngineHttpMethodTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:\"EC\"; within:4; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:\"EC\"; within:4; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -969,9 +958,8 @@ static int DetectEngineHttpMethodTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -989,7 +977,7 @@ static int DetectEngineHttpMethodTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1000,11 +988,11 @@ static int DetectEngineHttpMethodTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:!\"EC\"; within:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:!\"EC\"; within:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1061,9 +1049,8 @@ static int DetectEngineHttpMethodTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1081,7 +1068,7 @@ static int DetectEngineHttpMethodTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1092,11 +1079,11 @@ static int DetectEngineHttpMethodTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:\"EC\"; within:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:\"EC\"; within:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1153,9 +1140,8 @@ static int DetectEngineHttpMethodTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1173,7 +1159,7 @@ static int DetectEngineHttpMethodTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1184,11 +1170,11 @@ static int DetectEngineHttpMethodTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:!\"EC\"; within:4; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:!\"EC\"; within:4; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1245,9 +1231,8 @@ static int DetectEngineHttpMethodTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1265,7 +1250,7 @@ static int DetectEngineHttpMethodTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1276,11 +1261,11 @@ static int DetectEngineHttpMethodTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:\"EC\"; distance:2; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:\"EC\"; distance:2; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1337,9 +1322,8 @@ static int DetectEngineHttpMethodTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1357,7 +1341,7 @@ static int DetectEngineHttpMethodTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1368,11 +1352,11 @@ static int DetectEngineHttpMethodTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:!\"EC\"; distance:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:!\"EC\"; distance:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1429,9 +1413,8 @@ static int DetectEngineHttpMethodTest16(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1449,7 +1432,7 @@ static int DetectEngineHttpMethodTest16(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1460,11 +1443,11 @@ static int DetectEngineHttpMethodTest16(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:\"EC\"; distance:3; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:\"EC\"; distance:3; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1521,9 +1504,8 @@ static int DetectEngineHttpMethodTest17(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "CONNECT /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "CONNECT /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1541,7 +1523,7 @@ static int DetectEngineHttpMethodTest17(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1552,11 +1534,11 @@ static int DetectEngineHttpMethodTest17(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"CO\"; http_method; " - "content:!\"EC\"; distance:2; http_method; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"CO\"; http_method; " + "content:!\"EC\"; distance:2; http_method; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1606,15 +1588,14 @@ static int DetectHttpMethodTest01(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "http_method; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "http_method; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; @@ -1622,7 +1603,7 @@ static int DetectHttpMethodTest01(void) printf("sig parse failed: "); } - end: +end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; @@ -1634,20 +1615,19 @@ static int DetectHttpMethodTest02(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "http_method; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "http_method; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } - end: +end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; @@ -1659,21 +1639,20 @@ static int DetectHttpMethodTest03(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"foobar\"; " - "http_method:\"GET\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"foobar\"; " + "http_method:\"GET\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } - end: +end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; @@ -1685,22 +1664,21 @@ static int DetectHttpMethodTest04(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "fast_pattern; " - "http_method; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "fast_pattern; " + "http_method; sid:1;)"); if (de_ctx->sig_list != NULL) { result = 1; } - end: +end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; @@ -1712,22 +1690,21 @@ static int DetectHttpMethodTest05(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) + if ((de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "rawbytes; " - "http_method; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "rawbytes; " + "http_method; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 1; } - end: +end: if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); return result; @@ -1764,7 +1741,7 @@ static int DetectHttpMethodSigTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1776,20 +1753,18 @@ static int DetectHttpMethodSigTest01(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "http_method; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "http_method; sid:1;)"); if (s == NULL) { goto end; } - s = s->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"POST\"; " - "http_method; sid:2;)"); + s = s->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"POST\"; " + "http_method; sid:2;)"); if (s == NULL) { goto end; } @@ -1864,7 +1839,7 @@ static int DetectHttpMethodSigTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1876,20 +1851,18 @@ static int DetectHttpMethodSigTest02(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"FOO\"; " - "http_method; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"FOO\"; " + "http_method; sid:1;)"); if (s == NULL) { goto end; } - s = s->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"BAR\"; " - "http_method; sid:2;)"); + s = s->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"BAR\"; " + "http_method; sid:2;)"); if (s == NULL) { goto end; } @@ -1925,7 +1898,7 @@ static int DetectHttpMethodSigTest02(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *) det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); @@ -1964,7 +1937,7 @@ static int DetectHttpMethodSigTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1976,11 +1949,10 @@ static int DetectHttpMethodSigTest03(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing http_method\"; " - "content:\"GET\"; " - "http_method; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"Testing http_method\"; " + "content:\"GET\"; " + "http_method; sid:1;)"); if (s == NULL) { SCLogDebug("Bad signature"); goto end; @@ -2053,7 +2025,7 @@ static int DetectHttpMethodSigTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2065,16 +2037,15 @@ static int DetectHttpMethodSigTest04(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"Testing http_method\"; " - "content:\"GET\"; http_method; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Testing http_method\"; " + "content:\"GET\"; http_method; sid:1;)"); if (s == NULL) { goto end; } - s = s->next = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"Testing http_method\"; " - "content:!\"GET\"; http_method; sid:2;)"); + s = s->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Testing http_method\"; " + "content:!\"GET\"; http_method; sid:2;)"); if (s == NULL) { goto end; } @@ -2112,7 +2083,7 @@ static int DetectHttpMethodSigTest04(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *) det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); } if (de_ctx != NULL) { DetectEngineCtxFree(de_ctx); @@ -2130,10 +2101,9 @@ static int DetectHttpMethodIsdataatParseTest(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (" - "content:\"one\"; http_method; " - "isdataat:!4,relative; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "content:\"one\"; http_method; " + "isdataat:!4,relative; sid:1;)"); FAIL_IF_NULL(s); SigMatch *sm = DetectBufferGetLastSigMatch(s, g_http_method_buffer_id); @@ -2164,42 +2134,24 @@ void DetectHttpMethodRegisterTests(void) UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03); UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04); - UtRegisterTest("DetectHttpMethodIsdataatParseTest", - DetectHttpMethodIsdataatParseTest); - UtRegisterTest("DetectEngineHttpMethodTest01", - DetectEngineHttpMethodTest01); - UtRegisterTest("DetectEngineHttpMethodTest02", - DetectEngineHttpMethodTest02); - UtRegisterTest("DetectEngineHttpMethodTest03", - DetectEngineHttpMethodTest03); - UtRegisterTest("DetectEngineHttpMethodTest04", - DetectEngineHttpMethodTest04); - UtRegisterTest("DetectEngineHttpMethodTest05", - DetectEngineHttpMethodTest05); - UtRegisterTest("DetectEngineHttpMethodTest06", - DetectEngineHttpMethodTest06); - UtRegisterTest("DetectEngineHttpMethodTest07", - DetectEngineHttpMethodTest07); - UtRegisterTest("DetectEngineHttpMethodTest08", - DetectEngineHttpMethodTest08); - UtRegisterTest("DetectEngineHttpMethodTest09", - DetectEngineHttpMethodTest09); - UtRegisterTest("DetectEngineHttpMethodTest10", - DetectEngineHttpMethodTest10); - UtRegisterTest("DetectEngineHttpMethodTest11", - DetectEngineHttpMethodTest11); - UtRegisterTest("DetectEngineHttpMethodTest12", - DetectEngineHttpMethodTest12); - UtRegisterTest("DetectEngineHttpMethodTest13", - DetectEngineHttpMethodTest13); - UtRegisterTest("DetectEngineHttpMethodTest14", - DetectEngineHttpMethodTest14); - UtRegisterTest("DetectEngineHttpMethodTest15", - DetectEngineHttpMethodTest15); - UtRegisterTest("DetectEngineHttpMethodTest16", - DetectEngineHttpMethodTest16); - UtRegisterTest("DetectEngineHttpMethodTest17", - DetectEngineHttpMethodTest17); + UtRegisterTest("DetectHttpMethodIsdataatParseTest", DetectHttpMethodIsdataatParseTest); + UtRegisterTest("DetectEngineHttpMethodTest01", DetectEngineHttpMethodTest01); + UtRegisterTest("DetectEngineHttpMethodTest02", DetectEngineHttpMethodTest02); + UtRegisterTest("DetectEngineHttpMethodTest03", DetectEngineHttpMethodTest03); + UtRegisterTest("DetectEngineHttpMethodTest04", DetectEngineHttpMethodTest04); + UtRegisterTest("DetectEngineHttpMethodTest05", DetectEngineHttpMethodTest05); + UtRegisterTest("DetectEngineHttpMethodTest06", DetectEngineHttpMethodTest06); + UtRegisterTest("DetectEngineHttpMethodTest07", DetectEngineHttpMethodTest07); + UtRegisterTest("DetectEngineHttpMethodTest08", DetectEngineHttpMethodTest08); + UtRegisterTest("DetectEngineHttpMethodTest09", DetectEngineHttpMethodTest09); + UtRegisterTest("DetectEngineHttpMethodTest10", DetectEngineHttpMethodTest10); + UtRegisterTest("DetectEngineHttpMethodTest11", DetectEngineHttpMethodTest11); + UtRegisterTest("DetectEngineHttpMethodTest12", DetectEngineHttpMethodTest12); + UtRegisterTest("DetectEngineHttpMethodTest13", DetectEngineHttpMethodTest13); + UtRegisterTest("DetectEngineHttpMethodTest14", DetectEngineHttpMethodTest14); + UtRegisterTest("DetectEngineHttpMethodTest15", DetectEngineHttpMethodTest15); + UtRegisterTest("DetectEngineHttpMethodTest16", DetectEngineHttpMethodTest16); + UtRegisterTest("DetectEngineHttpMethodTest17", DetectEngineHttpMethodTest17); } /** diff --git a/src/tests/detect-http-raw-header.c b/src/tests/detect-http-raw-header.c index de716cb35c5d..123845a239e8 100644 --- a/src/tests/detect-http-raw-header.c +++ b/src/tests/detect-http-raw-header.c @@ -21,7 +21,6 @@ * @{ */ - /** \file * * \author Anoop Saldanha @@ -44,13 +43,13 @@ #include "../stream-tcp.h" #include "../app-layer.h" -#include "../app-layer-htp.h" +#include "../app-layer/http/parser.h" #include "../app-layer-protos.h" #include "../app-layer-parser.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" -#include "../util-validate.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" +#include "../util/validate.h" /***********************************Unittests**********************************/ @@ -61,15 +60,30 @@ */ static int DetectHttpRawHeaderParserTest01(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; http_raw_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; nocase; http_raw_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; endswith; http_raw_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; startswith; http_raw_header; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; startswith; endswith; http_raw_header; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; rawbytes; http_raw_header; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_server; http_raw_header; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; content:\"abc\"; http_raw_header; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "http_raw_header; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "nocase; http_raw_header; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "endswith; http_raw_header; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "startswith; http_raw_header; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "startswith; endswith; http_raw_header; sid:1;)", + true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; content:\"abc\"; " + "rawbytes; http_raw_header; sid:1;)", + false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tcp any any -> any any (flow:to_server; http_raw_header; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; content:\"abc\"; " + "http_raw_header; sid:1;)", + false)); PASS; } @@ -78,16 +92,33 @@ static int DetectHttpRawHeaderParserTest01(void) */ static int DetectHttpRawHeaderParserTest02(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; content:\"abc\"; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; content:\"abc\"; nocase; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; content:\"abc\"; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; content:\"abc\"; startswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; content:\"abc\"; startswith; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; bsize:10; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; content:\"abc\"; rawbytes; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_server; http.header.raw; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; http.header.raw; content:\"abc\"; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; " + "content:\"abc\"; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; " + "content:\"abc\"; nocase; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; " + "content:\"abc\"; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; " + "content:\"abc\"; startswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; " + "content:\"abc\"; startswith; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (flow:to_server; http.header.raw; bsize:10; sid:1;)", + true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_server; http.header.raw; " + "content:\"abc\"; rawbytes; sid:1;)", + false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tcp any any -> any any (flow:to_server; http.header.raw; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_server; http.header.raw; " + "content:\"abc\"; sid:1;)", + false)); PASS; } @@ -104,9 +135,8 @@ static int DetectEngineHttpRawHeaderTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -124,7 +154,7 @@ static int DetectEngineHttpRawHeaderTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -135,10 +165,10 @@ static int DetectEngineHttpRawHeaderTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -194,9 +224,8 @@ static int DetectEngineHttpRawHeaderTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -214,7 +243,7 @@ static int DetectEngineHttpRawHeaderTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -225,10 +254,10 @@ static int DetectEngineHttpRawHeaderTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; depth:15; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; depth:15; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -284,9 +313,8 @@ static int DetectEngineHttpRawHeaderTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -304,7 +332,7 @@ static int DetectEngineHttpRawHeaderTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -315,10 +343,10 @@ static int DetectEngineHttpRawHeaderTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:!\"one\"; depth:5; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:!\"one\"; depth:5; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -374,9 +402,8 @@ static int DetectEngineHttpRawHeaderTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -394,7 +421,7 @@ static int DetectEngineHttpRawHeaderTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -405,10 +432,10 @@ static int DetectEngineHttpRawHeaderTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; depth:5; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; depth:5; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -464,9 +491,8 @@ static int DetectEngineHttpRawHeaderTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -484,7 +510,7 @@ static int DetectEngineHttpRawHeaderTest05(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -495,10 +521,10 @@ static int DetectEngineHttpRawHeaderTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:!\"one\"; depth:15; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:!\"one\"; depth:15; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -554,9 +580,8 @@ static int DetectEngineHttpRawHeaderTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -574,7 +599,7 @@ static int DetectEngineHttpRawHeaderTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -585,10 +610,10 @@ static int DetectEngineHttpRawHeaderTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; offset:10; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; offset:10; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -644,9 +669,8 @@ static int DetectEngineHttpRawHeaderTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -664,7 +688,7 @@ static int DetectEngineHttpRawHeaderTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -675,10 +699,10 @@ static int DetectEngineHttpRawHeaderTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:!\"one\"; offset:15; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:!\"one\"; offset:15; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -734,9 +758,8 @@ static int DetectEngineHttpRawHeaderTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -754,7 +777,7 @@ static int DetectEngineHttpRawHeaderTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -765,10 +788,10 @@ static int DetectEngineHttpRawHeaderTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; offset:15; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; offset:15; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -824,9 +847,8 @@ static int DetectEngineHttpRawHeaderTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -844,7 +866,7 @@ static int DetectEngineHttpRawHeaderTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -855,10 +877,10 @@ static int DetectEngineHttpRawHeaderTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:!\"one\"; offset:10; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:!\"one\"; offset:10; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -914,9 +936,8 @@ static int DetectEngineHttpRawHeaderTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -934,7 +955,7 @@ static int DetectEngineHttpRawHeaderTest10(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -945,10 +966,11 @@ static int DetectEngineHttpRawHeaderTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:\"three\"; http_raw_header; within:10; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:\"three\"; http_raw_header; within:10; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1004,9 +1026,8 @@ static int DetectEngineHttpRawHeaderTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1024,7 +1045,7 @@ static int DetectEngineHttpRawHeaderTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1035,10 +1056,11 @@ static int DetectEngineHttpRawHeaderTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:!\"three\"; http_raw_header; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:!\"three\"; http_raw_header; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1094,9 +1116,8 @@ static int DetectEngineHttpRawHeaderTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1114,7 +1135,7 @@ static int DetectEngineHttpRawHeaderTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1125,10 +1146,11 @@ static int DetectEngineHttpRawHeaderTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:!\"three\"; http_raw_header; within:10; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:!\"three\"; http_raw_header; within:10; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1184,9 +1206,8 @@ static int DetectEngineHttpRawHeaderTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1204,7 +1225,7 @@ static int DetectEngineHttpRawHeaderTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1215,10 +1236,11 @@ static int DetectEngineHttpRawHeaderTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:\"three\"; http_raw_header; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:\"three\"; http_raw_header; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1274,9 +1296,8 @@ static int DetectEngineHttpRawHeaderTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1294,7 +1315,7 @@ static int DetectEngineHttpRawHeaderTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1305,10 +1326,11 @@ static int DetectEngineHttpRawHeaderTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; distance:7; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; distance:7; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1364,9 +1386,8 @@ static int DetectEngineHttpRawHeaderTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1384,7 +1405,7 @@ static int DetectEngineHttpRawHeaderTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1395,10 +1416,11 @@ static int DetectEngineHttpRawHeaderTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:!\"five\"; http_raw_header; distance:15; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:!\"five\"; http_raw_header; distance:15; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1454,9 +1476,8 @@ static int DetectEngineHttpRawHeaderTest16(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1474,7 +1495,7 @@ static int DetectEngineHttpRawHeaderTest16(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1485,10 +1506,11 @@ static int DetectEngineHttpRawHeaderTest16(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:!\"five\"; http_raw_header; distance:7; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:!\"five\"; http_raw_header; distance:7; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1544,9 +1566,8 @@ static int DetectEngineHttpRawHeaderTest17(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1564,7 +1585,7 @@ static int DetectEngineHttpRawHeaderTest17(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1575,10 +1596,11 @@ static int DetectEngineHttpRawHeaderTest17(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; distance:15; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; distance:15; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1627,12 +1649,10 @@ static int DetectEngineHttpRawHeaderTest20(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1655,11 +1675,11 @@ static int DetectEngineHttpRawHeaderTest20(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1669,9 +1689,9 @@ static int DetectEngineHttpRawHeaderTest20(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " - "(flow:to_server; pcre:/body1/D; " - "content:!\"dummy\"; http_raw_header; within:7; " - "sid:1;)"); + "(flow:to_server; pcre:/body1/D; " + "content:!\"dummy\"; http_raw_header; within:7; " + "sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1719,12 +1739,10 @@ static int DetectEngineHttpRawHeaderTest21(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1745,11 +1763,11 @@ static int DetectEngineHttpRawHeaderTest21(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1760,11 +1778,11 @@ static int DetectEngineHttpRawHeaderTest21(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; flow:to_server; " - "pcre:/body1/D; " - "content:!\"dummy\"; within:7; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; flow:to_server; " + "pcre:/body1/D; " + "content:!\"dummy\"; within:7; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1835,12 +1853,10 @@ static int DetectEngineHttpRawHeaderTest22(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1861,11 +1877,11 @@ static int DetectEngineHttpRawHeaderTest22(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1876,11 +1892,11 @@ static int DetectEngineHttpRawHeaderTest22(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; flow:to_server; " - "pcre:/body1/D; " - "content:!\"dummy\"; distance:3; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; flow:to_server; " + "pcre:/body1/D; " + "content:!\"dummy\"; distance:3; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1951,12 +1967,10 @@ static int DetectEngineHttpRawHeaderTest23(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -1977,11 +1991,11 @@ static int DetectEngineHttpRawHeaderTest23(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1992,11 +2006,11 @@ static int DetectEngineHttpRawHeaderTest23(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; flow:to_server; " - "pcre:/body1/D; " - "content:!\"dummy\"; distance:13; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; flow:to_server; " + "pcre:/body1/D; " + "content:!\"dummy\"; distance:13; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2067,12 +2081,10 @@ static int DetectEngineHttpRawHeaderTest24(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2093,11 +2105,11 @@ static int DetectEngineHttpRawHeaderTest24(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2108,11 +2120,11 @@ static int DetectEngineHttpRawHeaderTest24(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; flow:to_server; " - "pcre:/body1/D; " - "content:\"dummy\"; within:15; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; flow:to_server; " + "pcre:/body1/D; " + "content:\"dummy\"; within:15; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2183,12 +2195,10 @@ static int DetectEngineHttpRawHeaderTest25(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2209,11 +2219,11 @@ static int DetectEngineHttpRawHeaderTest25(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2224,11 +2234,11 @@ static int DetectEngineHttpRawHeaderTest25(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; flow:to_server; " - "pcre:/body1/D; " - "content:\"dummy\"; within:10; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; flow:to_server; " + "pcre:/body1/D; " + "content:\"dummy\"; within:10; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2299,12 +2309,10 @@ static int DetectEngineHttpRawHeaderTest26(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2325,11 +2333,11 @@ static int DetectEngineHttpRawHeaderTest26(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2340,11 +2348,11 @@ static int DetectEngineHttpRawHeaderTest26(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; flow:to_server; " - "pcre:/body1/D; " - "content:\"dummy\"; distance:8; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; flow:to_server; " + "pcre:/body1/D; " + "content:\"dummy\"; distance:8; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2413,12 +2421,10 @@ static int DetectEngineHttpRawHeaderTest27(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = "This_is_dummy_message_body2\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2439,11 +2445,11 @@ static int DetectEngineHttpRawHeaderTest27(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2454,11 +2460,11 @@ static int DetectEngineHttpRawHeaderTest27(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; flow:to_server; " - "pcre:/body1/D; " - "content:\"dummy\"; distance:14; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; flow:to_server; " + "pcre:/body1/D; " + "content:\"dummy\"; distance:14; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2529,18 +2535,17 @@ static int DetectEngineHttpRawHeaderTest28(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2575,10 +2580,10 @@ static int DetectEngineHttpRawHeaderTest28(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_client; " - "content:\"Content-Length: 6\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_client; " + "content:\"Content-Length: 6\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2649,18 +2654,17 @@ static int DetectEngineHttpRawHeaderTest29(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2695,10 +2699,10 @@ static int DetectEngineHttpRawHeaderTest29(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_client; " - "content:\"Content-Length: 7\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_client; " + "content:\"Content-Length: 7\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2803,16 +2807,15 @@ static int DetectEngineHttpRawHeaderTest31(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n" - "Dummy-Header: kaboom\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n" + "Dummy-Header: kaboom\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2831,7 +2834,7 @@ static int DetectEngineHttpRawHeaderTest31(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2842,10 +2845,10 @@ static int DetectEngineHttpRawHeaderTest31(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(flow:to_server; " - "content:\"Dummy\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(flow:to_server; " + "content:\"Dummy\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2902,17 +2905,15 @@ static int DetectEngineHttpRawHeaderTest32(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n"; - uint8_t http2_buf[] = - "Dummy-Header: kaboom\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n"; + uint8_t http2_buf[] = "Dummy-Header: kaboom\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -2933,11 +2934,11 @@ static int DetectEngineHttpRawHeaderTest32(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2948,10 +2949,10 @@ static int DetectEngineHttpRawHeaderTest32(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(flow:to_server; " - "content:\"Dummy\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(flow:to_server; " + "content:\"Dummy\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3025,14 +3026,14 @@ static int DetectHttpRawHeaderTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3050,7 +3051,7 @@ static int DetectHttpRawHeaderTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3061,10 +3062,10 @@ static int DetectHttpRawHeaderTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"Content-Type: text/html\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"Content-Type: text/html\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3121,15 +3122,14 @@ static int DetectHttpRawHeaderTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozi"; - uint8_t http2_buf[] = - "lla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\nContent-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n" - "This is dummy message body1"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozi"; + uint8_t http2_buf[] = "lla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 " + "Firefox/3.5.7\r\nContent-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n" + "This is dummy message body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3149,11 +3149,11 @@ static int DetectHttpRawHeaderTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3164,10 +3164,10 @@ static int DetectHttpRawHeaderTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"Mozilla\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"Mozilla\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3192,7 +3192,7 @@ static int DetectHttpRawHeaderTest07(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if ( (PacketAlertCheck(p1, 1))) { + if ((PacketAlertCheck(p1, 1))) { printf("sid 1 matched but shouldn't have: "); goto end; } @@ -3241,14 +3241,13 @@ static int DetectHttpRawHeaderTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n"; - uint8_t http2_buf[] = - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n"; + uint8_t http2_buf[] = "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3268,11 +3267,11 @@ static int DetectHttpRawHeaderTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3283,10 +3282,10 @@ static int DetectHttpRawHeaderTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"Gecko/20091221 Firefox/3.5.7\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"Gecko/20091221 Firefox/3.5.7\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3360,15 +3359,14 @@ static int DetectHttpRawHeaderTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; - uint8_t http2_buf[] = - "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n" - "This is dummy body\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n"; + uint8_t http2_buf[] = "Content-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n" + "This is dummy body\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3388,11 +3386,11 @@ static int DetectHttpRawHeaderTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3403,10 +3401,10 @@ static int DetectHttpRawHeaderTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"Firefox/3.5.7|0D 0A|Content\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"Firefox/3.5.7|0D 0A|Content\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3480,15 +3478,14 @@ static int DetectHttpRawHeaderTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n"; - uint8_t http2_buf[] = - "Content-Type: text/html\r\n" - "Content-Length: 67\r\n" - "\r\n" - "This is dummy body"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n"; + uint8_t http2_buf[] = "Content-Type: text/html\r\n" + "Content-Length: 67\r\n" + "\r\n" + "This is dummy body"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3508,11 +3505,11 @@ static int DetectHttpRawHeaderTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3523,10 +3520,11 @@ static int DetectHttpRawHeaderTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"firefox/3.5.7|0D 0A|content\"; nocase; http_raw_header;" - "sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"firefox/3.5.7|0D 0A|content\"; nocase; http_raw_header;" + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3599,14 +3597,14 @@ static int DetectHttpRawHeaderTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3624,7 +3622,7 @@ static int DetectHttpRawHeaderTest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3635,10 +3633,10 @@ static int DetectHttpRawHeaderTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:!\"lalalalala\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:!\"lalalalala\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3694,14 +3692,14 @@ static int DetectHttpRawHeaderTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 26\r\n" - "\r\n" - "This is dummy message body\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 26\r\n" + "\r\n" + "This is dummy message body\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3719,7 +3717,7 @@ static int DetectHttpRawHeaderTest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3730,10 +3728,10 @@ static int DetectHttpRawHeaderTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:!\"User-Agent: Mozilla/5.0 \"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:!\"User-Agent: Mozilla/5.0 \"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3789,14 +3787,14 @@ static int DetectHttpRawHeaderTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 100\r\n" - "\r\n" - "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 100\r\n" + "\r\n" + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n"; uint32_t http_len = sizeof(http_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3815,7 +3813,7 @@ static int DetectHttpRawHeaderTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3826,10 +3824,11 @@ static int DetectHttpRawHeaderTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"Host: www.openinfosecfoundation.org\"; http_raw_header; " - "sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; flow:to_server; " + "content:\"Host: www.openinfosecfoundation.org\"; http_raw_header; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3875,73 +3874,42 @@ static int DetectHttpRawHeaderTest13(void) void DetectHttpRawHeaderRegisterTests(void) { - UtRegisterTest("DetectHttpRawHeaderParserTest01", - DetectHttpRawHeaderParserTest01); - UtRegisterTest("DetectHttpRawHeaderParserTest02", - DetectHttpRawHeaderParserTest02); - - UtRegisterTest("DetectEngineHttpRawHeaderTest01", - DetectEngineHttpRawHeaderTest01); - UtRegisterTest("DetectEngineHttpRawHeaderTest02", - DetectEngineHttpRawHeaderTest02); - UtRegisterTest("DetectEngineHttpRawHeaderTest03", - DetectEngineHttpRawHeaderTest03); - UtRegisterTest("DetectEngineHttpRawHeaderTest04", - DetectEngineHttpRawHeaderTest04); - UtRegisterTest("DetectEngineHttpRawHeaderTest05", - DetectEngineHttpRawHeaderTest05); - UtRegisterTest("DetectEngineHttpRawHeaderTest06", - DetectEngineHttpRawHeaderTest06); - UtRegisterTest("DetectEngineHttpRawHeaderTest07", - DetectEngineHttpRawHeaderTest07); - UtRegisterTest("DetectEngineHttpRawHeaderTest08", - DetectEngineHttpRawHeaderTest08); - UtRegisterTest("DetectEngineHttpRawHeaderTest09", - DetectEngineHttpRawHeaderTest09); - UtRegisterTest("DetectEngineHttpRawHeaderTest10", - DetectEngineHttpRawHeaderTest10); - UtRegisterTest("DetectEngineHttpRawHeaderTest11", - DetectEngineHttpRawHeaderTest11); - UtRegisterTest("DetectEngineHttpRawHeaderTest12", - DetectEngineHttpRawHeaderTest12); - UtRegisterTest("DetectEngineHttpRawHeaderTest13", - DetectEngineHttpRawHeaderTest13); - UtRegisterTest("DetectEngineHttpRawHeaderTest14", - DetectEngineHttpRawHeaderTest14); - UtRegisterTest("DetectEngineHttpRawHeaderTest15", - DetectEngineHttpRawHeaderTest15); - UtRegisterTest("DetectEngineHttpRawHeaderTest16", - DetectEngineHttpRawHeaderTest16); - UtRegisterTest("DetectEngineHttpRawHeaderTest17", - DetectEngineHttpRawHeaderTest17); - UtRegisterTest("DetectEngineHttpRawHeaderTest20", - DetectEngineHttpRawHeaderTest20); - UtRegisterTest("DetectEngineHttpRawHeaderTest21", - DetectEngineHttpRawHeaderTest21); - UtRegisterTest("DetectEngineHttpRawHeaderTest22", - DetectEngineHttpRawHeaderTest22); - UtRegisterTest("DetectEngineHttpRawHeaderTest23", - DetectEngineHttpRawHeaderTest23); - UtRegisterTest("DetectEngineHttpRawHeaderTest24", - DetectEngineHttpRawHeaderTest24); - UtRegisterTest("DetectEngineHttpRawHeaderTest25", - DetectEngineHttpRawHeaderTest25); - UtRegisterTest("DetectEngineHttpRawHeaderTest26", - DetectEngineHttpRawHeaderTest26); - UtRegisterTest("DetectEngineHttpRawHeaderTest27", - DetectEngineHttpRawHeaderTest27); - UtRegisterTest("DetectEngineHttpRawHeaderTest28", - DetectEngineHttpRawHeaderTest28); - UtRegisterTest("DetectEngineHttpRawHeaderTest29", - DetectEngineHttpRawHeaderTest29); + UtRegisterTest("DetectHttpRawHeaderParserTest01", DetectHttpRawHeaderParserTest01); + UtRegisterTest("DetectHttpRawHeaderParserTest02", DetectHttpRawHeaderParserTest02); + + UtRegisterTest("DetectEngineHttpRawHeaderTest01", DetectEngineHttpRawHeaderTest01); + UtRegisterTest("DetectEngineHttpRawHeaderTest02", DetectEngineHttpRawHeaderTest02); + UtRegisterTest("DetectEngineHttpRawHeaderTest03", DetectEngineHttpRawHeaderTest03); + UtRegisterTest("DetectEngineHttpRawHeaderTest04", DetectEngineHttpRawHeaderTest04); + UtRegisterTest("DetectEngineHttpRawHeaderTest05", DetectEngineHttpRawHeaderTest05); + UtRegisterTest("DetectEngineHttpRawHeaderTest06", DetectEngineHttpRawHeaderTest06); + UtRegisterTest("DetectEngineHttpRawHeaderTest07", DetectEngineHttpRawHeaderTest07); + UtRegisterTest("DetectEngineHttpRawHeaderTest08", DetectEngineHttpRawHeaderTest08); + UtRegisterTest("DetectEngineHttpRawHeaderTest09", DetectEngineHttpRawHeaderTest09); + UtRegisterTest("DetectEngineHttpRawHeaderTest10", DetectEngineHttpRawHeaderTest10); + UtRegisterTest("DetectEngineHttpRawHeaderTest11", DetectEngineHttpRawHeaderTest11); + UtRegisterTest("DetectEngineHttpRawHeaderTest12", DetectEngineHttpRawHeaderTest12); + UtRegisterTest("DetectEngineHttpRawHeaderTest13", DetectEngineHttpRawHeaderTest13); + UtRegisterTest("DetectEngineHttpRawHeaderTest14", DetectEngineHttpRawHeaderTest14); + UtRegisterTest("DetectEngineHttpRawHeaderTest15", DetectEngineHttpRawHeaderTest15); + UtRegisterTest("DetectEngineHttpRawHeaderTest16", DetectEngineHttpRawHeaderTest16); + UtRegisterTest("DetectEngineHttpRawHeaderTest17", DetectEngineHttpRawHeaderTest17); + UtRegisterTest("DetectEngineHttpRawHeaderTest20", DetectEngineHttpRawHeaderTest20); + UtRegisterTest("DetectEngineHttpRawHeaderTest21", DetectEngineHttpRawHeaderTest21); + UtRegisterTest("DetectEngineHttpRawHeaderTest22", DetectEngineHttpRawHeaderTest22); + UtRegisterTest("DetectEngineHttpRawHeaderTest23", DetectEngineHttpRawHeaderTest23); + UtRegisterTest("DetectEngineHttpRawHeaderTest24", DetectEngineHttpRawHeaderTest24); + UtRegisterTest("DetectEngineHttpRawHeaderTest25", DetectEngineHttpRawHeaderTest25); + UtRegisterTest("DetectEngineHttpRawHeaderTest26", DetectEngineHttpRawHeaderTest26); + UtRegisterTest("DetectEngineHttpRawHeaderTest27", DetectEngineHttpRawHeaderTest27); + UtRegisterTest("DetectEngineHttpRawHeaderTest28", DetectEngineHttpRawHeaderTest28); + UtRegisterTest("DetectEngineHttpRawHeaderTest29", DetectEngineHttpRawHeaderTest29); #if 0 UtRegisterTest("DetectEngineHttpRawHeaderTest30", DetectEngineHttpRawHeaderTest30, 1); #endif - UtRegisterTest("DetectEngineHttpRawHeaderTest31", - DetectEngineHttpRawHeaderTest31); - UtRegisterTest("DetectEngineHttpRawHeaderTest32", - DetectEngineHttpRawHeaderTest32); + UtRegisterTest("DetectEngineHttpRawHeaderTest31", DetectEngineHttpRawHeaderTest31); + UtRegisterTest("DetectEngineHttpRawHeaderTest32", DetectEngineHttpRawHeaderTest32); UtRegisterTest("DetectHttpRawHeaderTest06", DetectHttpRawHeaderTest06); UtRegisterTest("DetectHttpRawHeaderTest07", DetectHttpRawHeaderTest07); diff --git a/src/tests/detect-http-server-body.c b/src/tests/detect-http-server-body.c index 89180fe56b98..1cbd7f463e69 100644 --- a/src/tests/detect-http-server-body.c +++ b/src/tests/detect-http-server-body.c @@ -36,15 +36,30 @@ */ static int DetectHttpServerBodyParserTest01(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; http_server_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; nocase; http_server_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; endswith; http_server_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; startswith; http_server_body; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; startswith; endswith; http_server_body; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; rawbytes; http_server_body; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_client; http_server_body; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_client; content:\"abc\"; http_server_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; " + "http_server_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; " + "nocase; http_server_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; " + "endswith; http_server_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; " + "startswith; http_server_body; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; " + "startswith; endswith; http_server_body; sid:1;)", + true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; content:\"abc\"; " + "rawbytes; http_server_body; sid:1;)", + false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tcp any any -> any any (flow:to_client; http_server_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_client; content:\"abc\"; " + "http_server_body; sid:1;)", + false)); PASS; } @@ -53,22 +68,40 @@ static int DetectHttpServerBodyParserTest01(void) */ static int DetectHttpServerBodyParserTest02(void) { - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; content:\"abc\"; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; content:\"abc\"; nocase; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; content:\"abc\"; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; content:\"abc\"; startswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; content:\"abc\"; startswith; endswith; sid:1;)", true)); - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; bsize:10; sid:1;)", true)); - - FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; content:\"abc\"; rawbytes; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tcp any any -> any any (flow:to_client; http.response_body; sid:1;)", false)); - FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_client; http.response_body; content:\"abc\"; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; " + "http.response_body; content:\"abc\"; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; " + "http.response_body; content:\"abc\"; nocase; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; " + "http.response_body; content:\"abc\"; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; " + "http.response_body; content:\"abc\"; startswith; sid:1;)", + true)); + FAIL_IF_NOT( + UTHParseSignature("alert http any any -> any any (flow:to_client; http.response_body; " + "content:\"abc\"; startswith; endswith; sid:1;)", + true)); + FAIL_IF_NOT(UTHParseSignature( + "alert http any any -> any any (flow:to_client; http.response_body; bsize:10; sid:1;)", + true)); + + FAIL_IF_NOT(UTHParseSignature("alert http any any -> any any (flow:to_client; " + "http.response_body; content:\"abc\"; rawbytes; sid:1;)", + false)); + FAIL_IF_NOT(UTHParseSignature( + "alert tcp any any -> any any (flow:to_client; http.response_body; sid:1;)", false)); + FAIL_IF_NOT(UTHParseSignature("alert tls any any -> any any (flow:to_client; " + "http.response_body; content:\"abc\"; sid:1;)", + false)); PASS; } struct TestSteps { const uint8_t *input; - size_t input_size; /**< if 0 strlen will be used */ - int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ + size_t input_size; /**< if 0 strlen will be used */ + int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ int expect; }; @@ -124,7 +157,7 @@ static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml) p->flow = &f; p->flowflags = (b->direction == STREAM_TOSERVER) ? FLOW_PKT_TOSERVER : FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, b->direction, (uint8_t *)b->input, @@ -167,18 +200,17 @@ static int DetectEngineHttpServerBodyTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "message"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -198,11 +230,11 @@ static int DetectEngineHttpServerBodyTest01(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -213,10 +245,10 @@ static int DetectEngineHttpServerBodyTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"message\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"message\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -286,18 +318,17 @@ static int DetectEngineHttpServerBodyTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "xxxxABC"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "xxxxABC"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -316,7 +347,7 @@ static int DetectEngineHttpServerBodyTest02(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -327,10 +358,10 @@ static int DetectEngineHttpServerBodyTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"ABC\"; http_server_body; offset:4; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"ABC\"; http_server_body; offset:4; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -393,21 +424,19 @@ static int DetectEngineHttpServerBodyTest03(void) HtpState *http_state = NULL; Flow f; int result = 0; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 17\r\n" - "\r\n" - "1234567"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "1234567"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "8901234ABC"; + uint8_t http_buf3[] = "8901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -426,11 +455,11 @@ static int DetectEngineHttpServerBodyTest03(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -441,10 +470,10 @@ static int DetectEngineHttpServerBodyTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"ABC\"; http_server_body; offset:14; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"ABC\"; http_server_body; offset:14; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -523,18 +552,17 @@ static int DetectEngineHttpServerBodyTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -554,11 +582,11 @@ static int DetectEngineHttpServerBodyTest04(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -569,10 +597,10 @@ static int DetectEngineHttpServerBodyTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:!\"abc\"; http_server_body; offset:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:!\"abc\"; http_server_body; offset:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -643,18 +671,17 @@ static int DetectEngineHttpServerBodyTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -674,11 +701,11 @@ static int DetectEngineHttpServerBodyTest05(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -689,10 +716,10 @@ static int DetectEngineHttpServerBodyTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"abc\"; http_server_body; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"abc\"; http_server_body; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -763,18 +790,17 @@ static int DetectEngineHttpServerBodyTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -794,11 +820,11 @@ static int DetectEngineHttpServerBodyTest06(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -809,10 +835,10 @@ static int DetectEngineHttpServerBodyTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:!\"def\"; http_server_body; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:!\"def\"; http_server_body; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -883,18 +909,17 @@ static int DetectEngineHttpServerBodyTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -914,11 +939,11 @@ static int DetectEngineHttpServerBodyTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -929,10 +954,10 @@ static int DetectEngineHttpServerBodyTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:!\"def\"; http_server_body; offset:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:!\"def\"; http_server_body; offset:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1003,18 +1028,17 @@ static int DetectEngineHttpServerBodyTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1034,11 +1058,11 @@ static int DetectEngineHttpServerBodyTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1049,10 +1073,10 @@ static int DetectEngineHttpServerBodyTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:!\"abc\"; http_server_body; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:!\"abc\"; http_server_body; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1123,18 +1147,17 @@ static int DetectEngineHttpServerBodyTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1154,11 +1177,11 @@ static int DetectEngineHttpServerBodyTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1169,11 +1192,11 @@ static int DetectEngineHttpServerBodyTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"abc\"; http_server_body; depth:3; " - "content:\"def\"; http_server_body; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"abc\"; http_server_body; depth:3; " + "content:\"def\"; http_server_body; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1244,18 +1267,17 @@ static int DetectEngineHttpServerBodyTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1275,11 +1297,11 @@ static int DetectEngineHttpServerBodyTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1290,11 +1312,11 @@ static int DetectEngineHttpServerBodyTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"abc\"; http_server_body; depth:3; " - "content:!\"xyz\"; http_server_body; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"abc\"; http_server_body; depth:3; " + "content:!\"xyz\"; http_server_body; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1365,18 +1387,17 @@ static int DetectEngineHttpServerBodyTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1396,11 +1417,11 @@ static int DetectEngineHttpServerBodyTest11(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1411,11 +1432,11 @@ static int DetectEngineHttpServerBodyTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"abc\"; http_server_body; depth:3; " - "content:\"xyz\"; http_server_body; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"abc\"; http_server_body; depth:3; " + "content:\"xyz\"; http_server_body; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1486,18 +1507,17 @@ static int DetectEngineHttpServerBodyTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1517,11 +1537,11 @@ static int DetectEngineHttpServerBodyTest12(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1532,11 +1552,11 @@ static int DetectEngineHttpServerBodyTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"ab\"; http_server_body; depth:2; " - "content:\"ef\"; http_server_body; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"ab\"; http_server_body; depth:2; " + "content:\"ef\"; http_server_body; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1607,18 +1627,17 @@ static int DetectEngineHttpServerBodyTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1638,11 +1657,11 @@ static int DetectEngineHttpServerBodyTest13(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1653,11 +1672,11 @@ static int DetectEngineHttpServerBodyTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"ab\"; http_server_body; depth:3; " - "content:!\"yz\"; http_server_body; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"ab\"; http_server_body; depth:3; " + "content:!\"yz\"; http_server_body; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1728,18 +1747,17 @@ static int DetectEngineHttpServerBodyTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1759,11 +1777,11 @@ static int DetectEngineHttpServerBodyTest14(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1774,11 +1792,11 @@ static int DetectEngineHttpServerBodyTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "pcre:/ab/Q; " - "content:\"ef\"; http_server_body; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "pcre:/ab/Q; " + "content:\"ef\"; http_server_body; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1849,18 +1867,17 @@ static int DetectEngineHttpServerBodyTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1880,11 +1897,11 @@ static int DetectEngineHttpServerBodyTest15(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1895,11 +1912,11 @@ static int DetectEngineHttpServerBodyTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "pcre:/abc/Q; " - "content:!\"xyz\"; http_server_body; distance:0; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "pcre:/abc/Q; " + "content:!\"xyz\"; http_server_body; distance:0; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1994,21 +2011,19 @@ libhtp:\n\ HtpState *http_state = NULL; Flow f; int result = 0; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 17\r\n" - "\r\n" - "1234567"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "1234567"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "8901234ABC"; + uint8_t http_buf3[] = "8901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2027,11 +2042,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2042,10 +2057,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"890\"; within:3; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"890\"; within:3; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2159,21 +2174,19 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 17\r\n" - "\r\n" - "1234567"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "1234567"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "8901234ABC"; + uint8_t http_buf3[] = "8901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2192,11 +2205,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2269,12 +2282,13 @@ static int DetectEngineHttpServerBodyTest18(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '5', '1', 0x0d, 0x0a, @@ -2288,6 +2302,7 @@ static int DetectEngineHttpServerBodyTest18(void) 0x8f, 0x0b, 0x00, 0xb2, 0x7d, 0xac, 0x9b, 0x19, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2307,11 +2322,11 @@ static int DetectEngineHttpServerBodyTest18(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2322,10 +2337,10 @@ static int DetectEngineHttpServerBodyTest18(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"file\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"file\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2399,12 +2414,13 @@ static int DetectEngineHttpServerBodyTest19(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '2', '4', 0x0d, 0x0a, @@ -2415,6 +2431,7 @@ static int DetectEngineHttpServerBodyTest19(void) 0x85, 0xcc, 0x3c, 0x20, 0x2b, 0x29, 0xbf, 0x42, 0x8f, 0x0b, 0x00, }; + // clang-format on // 0xb2, 0x7d, 0xac, 0x9b, 0x19, 0x00, 0x00, 0x00, uint32_t http_len2 = sizeof(http_buf2); int result = 0; @@ -2435,11 +2452,11 @@ static int DetectEngineHttpServerBodyTest19(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2450,10 +2467,10 @@ static int DetectEngineHttpServerBodyTest19(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"file\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"file\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2527,12 +2544,13 @@ static int DetectEngineHttpServerBodyTest20(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '2', '4', 0x0d, 0x0a, @@ -2543,6 +2561,7 @@ static int DetectEngineHttpServerBodyTest20(void) 0x85, 0xcc, 0x3c, 0x20, 0x2b, 0x29, 0xbf, 0x42, 0x8f, 0x0b, 0x00, }; + // clang-format on // 0xb2, 0x7d, 0xac, 0x9b, 0x19, 0x00, 0x00, 0x00, uint32_t http_len2 = sizeof(http_buf2); int result = 0; @@ -2563,11 +2582,11 @@ static int DetectEngineHttpServerBodyTest20(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2578,10 +2597,10 @@ static int DetectEngineHttpServerBodyTest20(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"file\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"file\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2654,12 +2673,13 @@ static int DetectEngineHttpServerBodyTest21(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '5', '1', 0x0d, 0x0a, @@ -2673,6 +2693,7 @@ static int DetectEngineHttpServerBodyTest21(void) 0x8f, 0x0b, 0x00, 0xb2, 0x7d, 0xac, 0x9b, 0x19, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2692,11 +2713,11 @@ static int DetectEngineHttpServerBodyTest21(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2707,10 +2728,10 @@ static int DetectEngineHttpServerBodyTest21(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"file\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"file\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2784,12 +2805,13 @@ static int DetectEngineHttpServerBodyTest22(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '5', '1', 0x0d, 0x0a, @@ -2804,6 +2826,7 @@ static int DetectEngineHttpServerBodyTest22(void) 0x8f, 0x0b, 0x00, 0xb2, 0x7d, 0xac, 0x9b, 0x19, 0x00, 0x00, 0x00, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2823,11 +2846,11 @@ static int DetectEngineHttpServerBodyTest22(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2838,10 +2861,10 @@ static int DetectEngineHttpServerBodyTest22(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"file\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"file\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -2911,18 +2934,17 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2942,11 +2964,11 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2957,11 +2979,11 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; pcre:/ab/; " - "content:\"ef\"; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; pcre:/ab/; " + "content:\"ef\"; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3032,18 +3054,17 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3063,11 +3084,11 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3078,11 +3099,11 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; pcre:/abc/; " - "content:!\"xyz\"; distance:0; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; pcre:/abc/; " + "content:!\"xyz\"; distance:0; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3153,18 +3174,17 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 33\r\n" - "\r\n" - "XYZ_klm_1234abcd_XYZ_klm_5678abcd"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 33\r\n" + "\r\n" + "XYZ_klm_1234abcd_XYZ_klm_5678abcd"; uint32_t http_len2 = sizeof(http_buf2) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3183,11 +3203,11 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3259,22 +3279,21 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"cd", - 0, STREAM_TOCLIENT, 1 }, - { (const uint8_t *)"ef", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"ef", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; const char *sig = "alert http any any -> any any (file_data; content:\"abcd\"; sid:1;)"; @@ -3297,22 +3316,21 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"cd", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"ef", - 0, STREAM_TOCLIENT, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ef", 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, }; const char *sig = "alert http any any -> any any (file_data; content:\"abcdef\"; sid:1;)"; @@ -3335,25 +3353,25 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"cd", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"ef", - 0, STREAM_TOCLIENT, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ef", 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"bcdef\"; offset:1; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"bcdef\"; offset:1; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3373,25 +3391,25 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 13\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"cd", - 0, STREAM_TOCLIENT, 1 }, - { (const uint8_t *)"123456789", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"123456789", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"bc\"; offset:1; depth:2; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"bc\"; offset:1; depth:2; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3411,25 +3429,25 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"cd", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"1234567890", - 0, STREAM_TOCLIENT, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"1234567890", 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"d123456789\"; offset:3; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"d123456789\"; offset:3; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3449,25 +3467,25 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 13\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"cd", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"123456789", - 0, STREAM_TOCLIENT, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"123456789", 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"abcd12\"; depth:6; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"abcd12\"; depth:6; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3487,22 +3505,21 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 5\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"c", - 0, STREAM_TOCLIENT, 1 }, - { (const uint8_t *)"de", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"de", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; const char *sig = "alert http any any -> any any (file_data; content:\"abc\"; depth:3; sid:1;)"; @@ -3525,25 +3542,25 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 5\r\n" - "\r\n" - "ab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"c", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"de", - 0, STREAM_TOCLIENT, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"de", 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"bcde\"; offset:1; depth:4; sid:1;)"; + const char *sig = "alert http any any -> any any (file_data; content:\"bcde\"; offset:1; " + "depth:4; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3563,26 +3580,23 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 13\r\n" - "\r\n" - "a", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"b", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"c", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"d", - 0, STREAM_TOCLIENT, 1 }, - { (const uint8_t *)"efghijklm", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "a", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"b", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"d", 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"efghijklm", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; const char *sig = "alert http any any -> any any (file_data; content:\"abcd\"; sid:1;)"; @@ -3605,29 +3619,27 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 13\r\n" - "\r\n" - "a", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"b", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"c", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"d", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"efghijklm", - 0, STREAM_TOCLIENT, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "a", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"b", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"d", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"efghijklm", 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"abcdefghijklm\"; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"abcdefghijklm\"; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3647,20 +3659,20 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 20\r\n" - "\r\n" - "1234567890", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"abcdefghi", - 0, STREAM_TOCLIENT, 1 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "1234567890", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"abcdefghi", 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, }; const char *sig = "alert http any any -> any any (file_data; content:\"890abcdefghi\"; sid:1;)"; @@ -3683,23 +3695,24 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 20\r\n" - "\r\n" - "1234567890", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"abcdefghi", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "1234567890", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"abcdefghi", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"7890ab\"; depth:6; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"7890ab\"; depth:6; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3719,27 +3732,26 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 20\r\n" - "\r\n" - "aaaab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"bbbbc", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"ccccd", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"dddde", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"aabb\"; depth:4; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"aabb\"; depth:4; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3759,27 +3771,26 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 20\r\n" - "\r\n" - "aaaab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"bbbbc", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"ccccd", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"dddde", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"bbbc\"; depth:4; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"bbbc\"; depth:4; sid:1;)"; return RunTest(steps, sig, yaml); } @@ -3799,27 +3810,26 @@ libhtp:\n\ "; struct TestSteps steps[] = { - { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n", - 0, STREAM_TOSERVER, 0 }, - { (const uint8_t *)"HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 20\r\n" - "\r\n" - "aaaab", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"bbbbc", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"ccccd", - 0, STREAM_TOCLIENT, 0 }, - { (const uint8_t *)"dddde", - 0, STREAM_TOCLIENT, 0 }, - { NULL, 0, 0, 0 }, + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, }; - const char *sig = "alert http any any -> any any (file_data; content:\"bccd\"; depth:4; sid:1;)"; + const char *sig = + "alert http any any -> any any (file_data; content:\"bccd\"; depth:4; sid:1;)"; return RunTest(steps, sig, yaml); } static int DetectEngineHttpServerBodyFileDataTest19(void) @@ -3850,12 +3860,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -3868,6 +3879,7 @@ libhtp:\n\ 0x0e, 0xc2, 0x8e, 0x50, 0x76, 0x51, 0xc5, 0x54, 0x15, 0x88, 0x73, 0xc3, 0xd0, 0x88, 0x39, 0x81, 0x98, 0x63, 0x91, 0x93, 0x8a, 0x82, 0x89, 0x60, 0x00, 0xcc, 0xb1, 0x00, 0x01, 0x73, 0xce, 0x39, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -3887,11 +3899,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -3901,10 +3913,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"FWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"FWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -3977,12 +3989,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -3995,6 +4008,7 @@ libhtp:\n\ 0x0e, 0xc2, 0x8e, 0x50, 0x76, 0x51, 0xc5, 0x54, 0x15, 0x88, 0x73, 0xc3, 0xd0, 0x88, 0x39, 0x81, 0x98, 0x63, 0x91, 0x93, 0x8a, 0x82, 0x89, 0x60, 0x00, 0xcc, 0xb1, 0x00, 0x01, 0x73, 0xce, 0x39, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4014,11 +4028,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4028,10 +4042,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"CWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"CWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4104,12 +4118,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -4122,6 +4137,7 @@ libhtp:\n\ 0x0e, 0xc2, 0x8e, 0x50, 0x76, 0x51, 0xc5, 0x54, 0x15, 0x88, 0x73, 0xc3, 0xd0, 0x88, 0x39, 0x81, 0x98, 0x63, 0x91, 0x93, 0x8a, 0x82, 0x89, 0x60, 0x00, 0xcc, 0xb1, 0x00, 0x01, 0x73, 0xce, 0x39, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4141,11 +4157,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4155,10 +4171,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"FWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"FWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4231,12 +4247,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -4249,6 +4266,7 @@ libhtp:\n\ 0x0e, 0xc2, 0x8e, 0x50, 0x76, 0x51, 0xc5, 0x54, 0x15, 0x88, 0x73, 0xc3, 0xd0, 0x88, 0x39, 0x81, 0x98, 0x63, 0x91, 0x93, 0x8a, 0x82, 0x89, 0x60, 0x00, 0xcc, 0xb1, 0x00, 0x01, 0x73, 0xce, 0x39, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4268,11 +4286,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4282,10 +4300,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"CWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"CWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4358,12 +4376,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -4376,6 +4395,7 @@ libhtp:\n\ 0x0e, 0xc2, 0x8e, 0x50, 0x76, 0x51, 0xc5, 0x54, 0x15, 0x88, 0x73, 0xc3, 0xd0, 0x88, 0x39, 0x81, 0x98, 0x63, 0x91, 0x93, 0x8a, 0x82, 0x89, 0x60, 0x00, 0xcc, 0xb1, 0x00, 0x01, 0x73, 0xce, 0x39, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4395,11 +4415,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4409,10 +4429,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"CWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"CWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4485,12 +4505,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '1', '0', '3', 0x0d, 0x0a, @@ -4505,6 +4526,7 @@ libhtp:\n\ 0x0e, 0x76, 0x70, 0xa0, 0xcd, 0x98, 0x2e, 0x76, 0x80, 0xf0, 0xe0, 0x59, 0x56, 0x06, 0x08, 0xe9, 0xca, 0xeb, 0xa2, 0xc6, 0xdb, 0x5a, 0x86 }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4524,11 +4546,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4536,13 +4558,12 @@ libhtp:\n\ de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"FWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"FWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4615,12 +4636,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '1', '0', '3', 0x0d, 0x0a, @@ -4633,6 +4655,7 @@ libhtp:\n\ 0xe1, 0xfc, 0x9e, 0x64, 0xda, 0x6c, 0x11, 0x21, 0x33, 0xed, 0xa0, 0x0e, 0x76, 0x70, 0xa0, 0xcd, 0x98, 0x2e, 0x76, 0x80, 0xf0, 0xe0, 0x59, 0x56, 0x06, 0x08, 0xe9, 0xca, 0xeb, 0xa2, 0xc6, 0xdb, 0x5a, 0x86 }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4652,11 +4675,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4666,10 +4689,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"ZWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"ZWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4742,12 +4765,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '1', '0', '3', 0x0d, 0x0a, @@ -4762,6 +4786,7 @@ libhtp:\n\ 0x0e, 0x76, 0x70, 0xa0, 0xcd, 0x98, 0x2e, 0x76, 0x80, 0xf0, 0xe0, 0x59, 0x56, 0x06, 0x08, 0xe9, 0xca, 0xeb, 0xa2, 0xc6, 0xdb, 0x5a, 0x86 }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4781,11 +4806,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4795,10 +4820,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"FWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"FWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4871,12 +4896,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -4889,6 +4915,7 @@ libhtp:\n\ 0x35, 0x1b, 0x1a, 0x8b, 0x16, 0x4d, 0xdf, 0x05, 0x32, 0xfe, 0xa4, 0x4c, 0x46, 0x49, 0xb7, 0x7b, 0x6b, 0x75, 0xf9, 0x2b, 0x5c, 0x37, 0x29, 0x0b, 0x91, 0x37, 0x01, 0x37, 0x0e, 0xe9, 0xf2, 0xe1, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -4908,11 +4935,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -4922,10 +4949,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"ZWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"ZWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -4998,12 +5025,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -5016,6 +5044,7 @@ libhtp:\n\ 0x35, 0x1b, 0x1a, 0x8b, 0x16, 0x4d, 0xdf, 0x05, 0x32, 0xfe, 0xa4, 0x4c, 0x46, 0x49, 0xb7, 0x7b, 0x6b, 0x75, 0xf9, 0x2b, 0x5c, 0x37, 0x29, 0x0b, 0x91, 0x37, 0x01, 0x37, 0x0e, 0xe9, 0xf2, 0xe1, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -5035,11 +5064,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5049,10 +5078,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"ZWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"ZWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -5124,12 +5153,13 @@ libhtp:\n\ DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /file.swf HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /file.swf HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; + // clang-format off uint8_t http_buf2[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ', '2', '0', '0', 'o', 'k', 0x0d, 0x0a, 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h', ':', ' ', '8', '0', 0x0d, 0x0a, @@ -5142,6 +5172,7 @@ libhtp:\n\ 0x0e, 0xc2, 0x8e, 0x50, 0x76, 0x51, 0xc5, 0x54, 0x15, 0x88, 0x73, 0xc3, 0xd0, 0x88, 0x39, 0x81, 0x98, 0x63, 0x91, 0x93, 0x8a, 0x82, 0x89, 0x60, 0x00, 0xcc, 0xb1, 0x00, 0x01, 0x73, 0xce, 0x39, }; + // clang-format on uint32_t http_len2 = sizeof(http_buf2); AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); FAIL_IF_NULL(alp_tctx); @@ -5161,11 +5192,11 @@ libhtp:\n\ p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5175,10 +5206,10 @@ libhtp:\n\ de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any " - "(flow:established,from_server; " - "file_data; content:\"FWS\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(flow:established,from_server; " + "file_data; content:\"FWS\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -5233,18 +5264,17 @@ static int DetectHttpServerBodyTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "message"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5263,7 +5293,7 @@ static int DetectHttpServerBodyTest06(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5274,10 +5304,10 @@ static int DetectHttpServerBodyTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"message\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"message\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5341,20 +5371,18 @@ static int DetectHttpServerBodyTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "message"; + uint8_t http_buf3[] = "message"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5374,12 +5402,12 @@ static int DetectHttpServerBodyTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5390,10 +5418,10 @@ static int DetectHttpServerBodyTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"message\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"message\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5470,21 +5498,19 @@ static int DetectHttpServerBodyTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n" - "bigmes"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "sage4u!!"; + uint8_t http_buf3[] = "sage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5504,11 +5530,11 @@ static int DetectHttpServerBodyTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5519,10 +5545,10 @@ static int DetectHttpServerBodyTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"message\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"message\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5604,24 +5630,21 @@ static int DetectHttpServerBodyTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n" - "bigmes"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "sag"; + uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = - "e4u!!"; + uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5641,11 +5664,11 @@ static int DetectHttpServerBodyTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5656,10 +5679,10 @@ static int DetectHttpServerBodyTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"message\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"message\"; http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5749,24 +5772,21 @@ static int DetectHttpServerBodyTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n" - "bigmes"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "sag"; + uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = - "e4u!!"; + uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5786,11 +5806,11 @@ static int DetectHttpServerBodyTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5801,10 +5821,10 @@ static int DetectHttpServerBodyTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"MeSSaGE\"; http_server_body; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:\"MeSSaGE\"; http_server_body; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5894,20 +5914,18 @@ static int DetectHttpServerBodyTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "bigmessage4u!!"; + uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5927,11 +5945,11 @@ static int DetectHttpServerBodyTest11(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -5942,10 +5960,10 @@ static int DetectHttpServerBodyTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"MaSSaGE\"; http_server_body; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:!\"MaSSaGE\"; http_server_body; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6027,20 +6045,18 @@ static int DetectHttpServerBodyTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "bigmessage4u!!"; + uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6060,11 +6076,11 @@ static int DetectHttpServerBodyTest12(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6075,10 +6091,10 @@ static int DetectHttpServerBodyTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"MeSSaGE\"; http_server_body; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "content:!\"MeSSaGE\"; http_server_body; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6155,18 +6171,17 @@ static int DetectHttpServerBodyTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 55\r\n" - "\r\n" - "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 55\r\n" + "\r\n" + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6185,7 +6200,7 @@ static int DetectHttpServerBodyTest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6196,10 +6211,12 @@ static int DetectHttpServerBodyTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "content:\"longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\"; http_server_body; " - "sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "content:\"longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\"; " + "http_server_body; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6260,28 +6277,28 @@ static int DetectHttpServerBodyTest14(void) TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy1\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "one"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" - "User-Agent: Firefox/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy2\r\n\r\n"; + "User-Agent: Firefox/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "two"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6299,7 +6316,7 @@ static int DetectHttpServerBodyTest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6311,12 +6328,14 @@ static int DetectHttpServerBodyTest14(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"one\"; http_server_body; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "content:\"one\"; http_server_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"two\"; http_server_body; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "content:\"two\"; http_server_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; @@ -6421,28 +6440,28 @@ static int DetectHttpServerBodyTest15(void) TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy1\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "one"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" - "User-Agent: Firefox/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy2\r\n\r\n"; + "User-Agent: Firefox/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "two"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6460,7 +6479,7 @@ static int DetectHttpServerBodyTest15(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6472,12 +6491,14 @@ static int DetectHttpServerBodyTest15(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"one\"; http_server_body; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "content:\"one\"; http_server_body; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; content:\"two\"; http_server_body; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "content:\"two\"; http_server_body; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; @@ -6577,18 +6598,17 @@ static int DetectHttpServerBodyFileDataTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "message"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6606,7 +6626,7 @@ static int DetectHttpServerBodyFileDataTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6615,10 +6635,10 @@ static int DetectHttpServerBodyFileDataTest01(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"message\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"message\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); @@ -6661,20 +6681,18 @@ static int DetectHttpServerBodyFileDataTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "message"; + uint8_t http_buf3[] = "message"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6694,12 +6712,12 @@ static int DetectHttpServerBodyFileDataTest02(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6710,10 +6728,10 @@ static int DetectHttpServerBodyFileDataTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"message\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"message\"; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6792,21 +6810,19 @@ static int DetectHttpServerBodyFileDataTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n" - "bigmes"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "sage4u!!"; + uint8_t http_buf3[] = "sage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6826,11 +6842,11 @@ static int DetectHttpServerBodyFileDataTest03(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6841,10 +6857,10 @@ static int DetectHttpServerBodyFileDataTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "file_data; content:\"message\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "file_data; content:\"message\"; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6890,7 +6906,6 @@ static int DetectHttpServerBodyFileDataTest03(void) goto end; } - /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -6927,24 +6942,21 @@ static int DetectHttpServerBodyFileDataTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n" - "bigmes"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "sag"; + uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = - "e4u!!"; + uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -6964,11 +6976,11 @@ static int DetectHttpServerBodyFileDataTest04(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -6979,10 +6991,10 @@ static int DetectHttpServerBodyFileDataTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "file_data; content:\"message\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "file_data; content:\"message\"; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7072,24 +7084,21 @@ static int DetectHttpServerBodyFileDataTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n" - "bigmes"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "bigmes"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "sag"; + uint8_t http_buf3[] = "sag"; uint32_t http_len3 = sizeof(http_buf3) - 1; - uint8_t http_buf4[] = - "e4u!!"; + uint8_t http_buf4[] = "e4u!!"; uint32_t http_len4 = sizeof(http_buf4) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -7109,11 +7118,11 @@ static int DetectHttpServerBodyFileDataTest05(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -7124,10 +7133,10 @@ static int DetectHttpServerBodyFileDataTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "file_data; content:\"MeSSaGE\"; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http client body test\"; " + "file_data; content:\"MeSSaGE\"; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7217,20 +7226,18 @@ static int DetectHttpServerBodyFileDataTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "bigmessage4u!!"; + uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -7250,11 +7257,11 @@ static int DetectHttpServerBodyFileDataTest06(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -7265,10 +7272,10 @@ static int DetectHttpServerBodyFileDataTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http file_data test\"; " - "file_data; content:!\"MaSSaGE\"; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http file_data test\"; " + "file_data; content:!\"MaSSaGE\"; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7350,20 +7357,18 @@ static int DetectHttpServerBodyFileDataTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 14\r\n" - "\r\n"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "bigmessage4u!!"; + uint8_t http_buf3[] = "bigmessage4u!!"; uint32_t http_len3 = sizeof(http_buf3) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -7383,11 +7388,11 @@ static int DetectHttpServerBodyFileDataTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -7398,10 +7403,10 @@ static int DetectHttpServerBodyFileDataTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http file_data test\"; " - "file_data; content:!\"MeSSaGE\"; nocase; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http file_data test\"; " + "file_data; content:!\"MeSSaGE\"; nocase; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7478,18 +7483,17 @@ static int DetectHttpServerBodyFileDataTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 55\r\n" - "\r\n" - "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; + uint8_t http_buf2[] = "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 55\r\n" + "\r\n" + "longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -7508,7 +7512,7 @@ static int DetectHttpServerBodyFileDataTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -7519,10 +7523,11 @@ static int DetectHttpServerBodyFileDataTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http server body test\"; " - "file_data; content:\"longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"http server body test\"; " + "file_data; content:\"longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\"; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -7583,28 +7588,28 @@ static int DetectHttpServerBodyFileDataTest09(void) TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy1\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "one"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" - "User-Agent: Firefox/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy2\r\n\r\n"; + "User-Agent: Firefox/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "two"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -7622,7 +7627,7 @@ static int DetectHttpServerBodyFileDataTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -7634,12 +7639,14 @@ static int DetectHttpServerBodyFileDataTest09(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"one\"; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "file_data; content:\"one\"; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"two\"; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "file_data; content:\"two\"; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; @@ -7732,28 +7739,28 @@ static int DetectHttpServerBodyFileDataTest10(void) TcpSession ssn; Packet *p = NULL; uint8_t httpbuf1[] = "GET /index1.html HTTP/1.1\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy1\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy1\r\n\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ uint8_t httpbuf2[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "one"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "one"; uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ uint8_t httpbuf3[] = "GET /index2.html HTTP/1.1\r\n" - "User-Agent: Firefox/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Connection: keep-alive\r\n" - "Cookie: dummy2\r\n\r\n"; + "User-Agent: Firefox/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Connection: keep-alive\r\n" + "Cookie: dummy2\r\n\r\n"; uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ uint8_t httpbuf4[] = "HTTP/1.1 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 3\r\n" - "\r\n" - "two"; + "Content-Type: text/html\r\n" + "Content-Length: 3\r\n" + "\r\n" + "two"; uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -7771,7 +7778,7 @@ static int DetectHttpServerBodyFileDataTest10(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -7783,12 +7790,14 @@ static int DetectHttpServerBodyFileDataTest10(void) de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"one\"; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "file_data; content:\"one\"; sid:1; rev:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; file_data; content:\"two\"; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:established,to_client; " + "file_data; content:\"two\"; sid:2; rev:1;)"); if (s == NULL) { printf("sig2 parse failed: "); goto end; @@ -7887,129 +7896,97 @@ void DetectHttpServerBodyRegisterTests(void) UtRegisterTest("DetectHttpServerBodyTest14", DetectHttpServerBodyTest14); UtRegisterTest("DetectHttpServerBodyTest15", DetectHttpServerBodyTest15); - UtRegisterTest("DetectHttpServerBodyFileDataTest01", - DetectHttpServerBodyFileDataTest01); - UtRegisterTest("DetectHttpServerBodyFileDataTest02", - DetectHttpServerBodyFileDataTest02); - UtRegisterTest("DetectHttpServerBodyFileDataTest03", - DetectHttpServerBodyFileDataTest03); - UtRegisterTest("DetectHttpServerBodyFileDataTest04", - DetectHttpServerBodyFileDataTest04); - UtRegisterTest("DetectHttpServerBodyFileDataTest05", - DetectHttpServerBodyFileDataTest05); - UtRegisterTest("DetectHttpServerBodyFileDataTest06", - DetectHttpServerBodyFileDataTest06); - UtRegisterTest("DetectHttpServerBodyFileDataTest07", - DetectHttpServerBodyFileDataTest07); - UtRegisterTest("DetectHttpServerBodyFileDataTest08", - DetectHttpServerBodyFileDataTest08); - UtRegisterTest("DetectHttpServerBodyFileDataTest09", - DetectHttpServerBodyFileDataTest09); - UtRegisterTest("DetectHttpServerBodyFileDataTest10", - DetectHttpServerBodyFileDataTest10); - - UtRegisterTest("DetectEngineHttpServerBodyTest01", - DetectEngineHttpServerBodyTest01); - UtRegisterTest("DetectEngineHttpServerBodyTest02", - DetectEngineHttpServerBodyTest02); - UtRegisterTest("DetectEngineHttpServerBodyTest03", - DetectEngineHttpServerBodyTest03); - UtRegisterTest("DetectEngineHttpServerBodyTest04", - DetectEngineHttpServerBodyTest04); - UtRegisterTest("DetectEngineHttpServerBodyTest05", - DetectEngineHttpServerBodyTest05); - UtRegisterTest("DetectEngineHttpServerBodyTest06", - DetectEngineHttpServerBodyTest06); - UtRegisterTest("DetectEngineHttpServerBodyTest07", - DetectEngineHttpServerBodyTest07); - UtRegisterTest("DetectEngineHttpServerBodyTest08", - DetectEngineHttpServerBodyTest08); - UtRegisterTest("DetectEngineHttpServerBodyTest09", - DetectEngineHttpServerBodyTest09); - UtRegisterTest("DetectEngineHttpServerBodyTest10", - DetectEngineHttpServerBodyTest10); - UtRegisterTest("DetectEngineHttpServerBodyTest11", - DetectEngineHttpServerBodyTest11); - UtRegisterTest("DetectEngineHttpServerBodyTest12", - DetectEngineHttpServerBodyTest12); - UtRegisterTest("DetectEngineHttpServerBodyTest13", - DetectEngineHttpServerBodyTest13); - UtRegisterTest("DetectEngineHttpServerBodyTest14", - DetectEngineHttpServerBodyTest14); - UtRegisterTest("DetectEngineHttpServerBodyTest15", - DetectEngineHttpServerBodyTest15); - UtRegisterTest("DetectEngineHttpServerBodyTest16", - DetectEngineHttpServerBodyTest16); - UtRegisterTest("DetectEngineHttpServerBodyTest17", - DetectEngineHttpServerBodyTest17); - UtRegisterTest("DetectEngineHttpServerBodyTest18", - DetectEngineHttpServerBodyTest18); - UtRegisterTest("DetectEngineHttpServerBodyTest19", - DetectEngineHttpServerBodyTest19); - UtRegisterTest("DetectEngineHttpServerBodyTest20", - DetectEngineHttpServerBodyTest20); - UtRegisterTest("DetectEngineHttpServerBodyTest21", - DetectEngineHttpServerBodyTest21); - UtRegisterTest("DetectEngineHttpServerBodyTest22", - DetectEngineHttpServerBodyTest22); - - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest01", - DetectEngineHttpServerBodyFileDataTest01); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest02", - DetectEngineHttpServerBodyFileDataTest02); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest03", - DetectEngineHttpServerBodyFileDataTest03); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest04", - DetectEngineHttpServerBodyFileDataTest04); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest05", - DetectEngineHttpServerBodyFileDataTest05); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest06", - DetectEngineHttpServerBodyFileDataTest06); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest07", - DetectEngineHttpServerBodyFileDataTest07); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest08", - DetectEngineHttpServerBodyFileDataTest08); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest09", - DetectEngineHttpServerBodyFileDataTest09); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest10", - DetectEngineHttpServerBodyFileDataTest10); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest11", - DetectEngineHttpServerBodyFileDataTest11); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest12", - DetectEngineHttpServerBodyFileDataTest12); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest13", - DetectEngineHttpServerBodyFileDataTest13); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest14", - DetectEngineHttpServerBodyFileDataTest14); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest15", - DetectEngineHttpServerBodyFileDataTest15); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest16", - DetectEngineHttpServerBodyFileDataTest16); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest17", - DetectEngineHttpServerBodyFileDataTest17); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest18", - DetectEngineHttpServerBodyFileDataTest18); - - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest19", - DetectEngineHttpServerBodyFileDataTest19); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest20", - DetectEngineHttpServerBodyFileDataTest20); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest21", - DetectEngineHttpServerBodyFileDataTest21); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest22", - DetectEngineHttpServerBodyFileDataTest22); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest23", - DetectEngineHttpServerBodyFileDataTest23); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest24", - DetectEngineHttpServerBodyFileDataTest24); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest25", - DetectEngineHttpServerBodyFileDataTest25); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest26", - DetectEngineHttpServerBodyFileDataTest26); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest27", - DetectEngineHttpServerBodyFileDataTest27); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest28", - DetectEngineHttpServerBodyFileDataTest28); - UtRegisterTest("DetectEngineHttpServerBodyFileDataTest29", - DetectEngineHttpServerBodyFileDataTest29); + UtRegisterTest("DetectHttpServerBodyFileDataTest01", DetectHttpServerBodyFileDataTest01); + UtRegisterTest("DetectHttpServerBodyFileDataTest02", DetectHttpServerBodyFileDataTest02); + UtRegisterTest("DetectHttpServerBodyFileDataTest03", DetectHttpServerBodyFileDataTest03); + UtRegisterTest("DetectHttpServerBodyFileDataTest04", DetectHttpServerBodyFileDataTest04); + UtRegisterTest("DetectHttpServerBodyFileDataTest05", DetectHttpServerBodyFileDataTest05); + UtRegisterTest("DetectHttpServerBodyFileDataTest06", DetectHttpServerBodyFileDataTest06); + UtRegisterTest("DetectHttpServerBodyFileDataTest07", DetectHttpServerBodyFileDataTest07); + UtRegisterTest("DetectHttpServerBodyFileDataTest08", DetectHttpServerBodyFileDataTest08); + UtRegisterTest("DetectHttpServerBodyFileDataTest09", DetectHttpServerBodyFileDataTest09); + UtRegisterTest("DetectHttpServerBodyFileDataTest10", DetectHttpServerBodyFileDataTest10); + + UtRegisterTest("DetectEngineHttpServerBodyTest01", DetectEngineHttpServerBodyTest01); + UtRegisterTest("DetectEngineHttpServerBodyTest02", DetectEngineHttpServerBodyTest02); + UtRegisterTest("DetectEngineHttpServerBodyTest03", DetectEngineHttpServerBodyTest03); + UtRegisterTest("DetectEngineHttpServerBodyTest04", DetectEngineHttpServerBodyTest04); + UtRegisterTest("DetectEngineHttpServerBodyTest05", DetectEngineHttpServerBodyTest05); + UtRegisterTest("DetectEngineHttpServerBodyTest06", DetectEngineHttpServerBodyTest06); + UtRegisterTest("DetectEngineHttpServerBodyTest07", DetectEngineHttpServerBodyTest07); + UtRegisterTest("DetectEngineHttpServerBodyTest08", DetectEngineHttpServerBodyTest08); + UtRegisterTest("DetectEngineHttpServerBodyTest09", DetectEngineHttpServerBodyTest09); + UtRegisterTest("DetectEngineHttpServerBodyTest10", DetectEngineHttpServerBodyTest10); + UtRegisterTest("DetectEngineHttpServerBodyTest11", DetectEngineHttpServerBodyTest11); + UtRegisterTest("DetectEngineHttpServerBodyTest12", DetectEngineHttpServerBodyTest12); + UtRegisterTest("DetectEngineHttpServerBodyTest13", DetectEngineHttpServerBodyTest13); + UtRegisterTest("DetectEngineHttpServerBodyTest14", DetectEngineHttpServerBodyTest14); + UtRegisterTest("DetectEngineHttpServerBodyTest15", DetectEngineHttpServerBodyTest15); + UtRegisterTest("DetectEngineHttpServerBodyTest16", DetectEngineHttpServerBodyTest16); + UtRegisterTest("DetectEngineHttpServerBodyTest17", DetectEngineHttpServerBodyTest17); + UtRegisterTest("DetectEngineHttpServerBodyTest18", DetectEngineHttpServerBodyTest18); + UtRegisterTest("DetectEngineHttpServerBodyTest19", DetectEngineHttpServerBodyTest19); + UtRegisterTest("DetectEngineHttpServerBodyTest20", DetectEngineHttpServerBodyTest20); + UtRegisterTest("DetectEngineHttpServerBodyTest21", DetectEngineHttpServerBodyTest21); + UtRegisterTest("DetectEngineHttpServerBodyTest22", DetectEngineHttpServerBodyTest22); + + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest01", DetectEngineHttpServerBodyFileDataTest01); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest02", DetectEngineHttpServerBodyFileDataTest02); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest03", DetectEngineHttpServerBodyFileDataTest03); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest04", DetectEngineHttpServerBodyFileDataTest04); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest05", DetectEngineHttpServerBodyFileDataTest05); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest06", DetectEngineHttpServerBodyFileDataTest06); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest07", DetectEngineHttpServerBodyFileDataTest07); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest08", DetectEngineHttpServerBodyFileDataTest08); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest09", DetectEngineHttpServerBodyFileDataTest09); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest10", DetectEngineHttpServerBodyFileDataTest10); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest11", DetectEngineHttpServerBodyFileDataTest11); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest12", DetectEngineHttpServerBodyFileDataTest12); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest13", DetectEngineHttpServerBodyFileDataTest13); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest14", DetectEngineHttpServerBodyFileDataTest14); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest15", DetectEngineHttpServerBodyFileDataTest15); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest16", DetectEngineHttpServerBodyFileDataTest16); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest17", DetectEngineHttpServerBodyFileDataTest17); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest18", DetectEngineHttpServerBodyFileDataTest18); + + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest19", DetectEngineHttpServerBodyFileDataTest19); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest20", DetectEngineHttpServerBodyFileDataTest20); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest21", DetectEngineHttpServerBodyFileDataTest21); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest22", DetectEngineHttpServerBodyFileDataTest22); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest23", DetectEngineHttpServerBodyFileDataTest23); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest24", DetectEngineHttpServerBodyFileDataTest24); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest25", DetectEngineHttpServerBodyFileDataTest25); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest26", DetectEngineHttpServerBodyFileDataTest26); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest27", DetectEngineHttpServerBodyFileDataTest27); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest28", DetectEngineHttpServerBodyFileDataTest28); + UtRegisterTest( + "DetectEngineHttpServerBodyFileDataTest29", DetectEngineHttpServerBodyFileDataTest29); } diff --git a/src/tests/detect-http-stat-code.c b/src/tests/detect-http-stat-code.c index 25a711545b39..5ed4a8d65106 100644 --- a/src/tests/detect-http-stat-code.c +++ b/src/tests/detect-http-stat-code.c @@ -33,10 +33,10 @@ #include "../flow-util.h" #include "../flow.h" #include "../app-layer-parser.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" #include "../app-layer.h" -#include "../app-layer-htp.h" +#include "../app-layer/http/parser.h" #include "../app-layer-protos.h" #include "../detect-engine-build.h" #include "../detect-engine-alert.h" @@ -51,18 +51,17 @@ static int DetectEngineHttpStatCodeTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 message\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "message"; + uint8_t http_buf2[] = "HTTP/1.0 200 message\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -82,11 +81,11 @@ static int DetectEngineHttpStatCodeTest01(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -97,10 +96,10 @@ static int DetectEngineHttpStatCodeTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"200\"; http_stat_code; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"200\"; http_stat_code; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -170,18 +169,17 @@ static int DetectEngineHttpStatCodeTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 2000123 xxxxABC\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "xxxxABC"; + uint8_t http_buf2[] = "HTTP/1.0 2000123 xxxxABC\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "xxxxABC"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -200,7 +198,7 @@ static int DetectEngineHttpStatCodeTest02(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -211,10 +209,10 @@ static int DetectEngineHttpStatCodeTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"123\"; http_stat_code; offset:4; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"123\"; http_stat_code; offset:4; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -277,21 +275,19 @@ static int DetectEngineHttpStatCodeTest03(void) HtpState *http_state = NULL; Flow f; int result = 0; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 123"; + uint8_t http_buf2[] = "HTTP/1.0 123"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "456789\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 17\r\n" - "\r\n" - "12345678901234ABC"; + uint8_t http_buf3[] = "456789\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "12345678901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -310,11 +306,11 @@ static int DetectEngineHttpStatCodeTest03(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -325,10 +321,10 @@ static int DetectEngineHttpStatCodeTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"789\"; http_stat_code; offset:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"789\"; http_stat_code; offset:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -407,18 +403,17 @@ static int DetectEngineHttpStatCodeTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -438,11 +433,11 @@ static int DetectEngineHttpStatCodeTest04(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -453,10 +448,10 @@ static int DetectEngineHttpStatCodeTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:!\"200\"; http_stat_code; offset:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:!\"200\"; http_stat_code; offset:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -527,18 +522,17 @@ static int DetectEngineHttpStatCodeTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -558,11 +552,11 @@ static int DetectEngineHttpStatCodeTest05(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -573,10 +567,10 @@ static int DetectEngineHttpStatCodeTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"200\"; http_stat_code; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"200\"; http_stat_code; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -647,18 +641,17 @@ static int DetectEngineHttpStatCodeTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -678,11 +671,11 @@ static int DetectEngineHttpStatCodeTest06(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -693,10 +686,10 @@ static int DetectEngineHttpStatCodeTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:!\"123\"; http_stat_code; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:!\"123\"; http_stat_code; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -767,18 +760,17 @@ static int DetectEngineHttpStatCodeTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -798,11 +790,11 @@ static int DetectEngineHttpStatCodeTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -813,10 +805,10 @@ static int DetectEngineHttpStatCodeTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:!\"123\"; http_stat_code; offset:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:!\"123\"; http_stat_code; offset:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -887,18 +879,17 @@ static int DetectEngineHttpStatCodeTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -918,11 +909,11 @@ static int DetectEngineHttpStatCodeTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -933,10 +924,10 @@ static int DetectEngineHttpStatCodeTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:!\"200\"; http_stat_code; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:!\"200\"; http_stat_code; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1007,18 +998,17 @@ static int DetectEngineHttpStatCodeTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1038,11 +1028,11 @@ static int DetectEngineHttpStatCodeTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1053,11 +1043,11 @@ static int DetectEngineHttpStatCodeTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"200\"; http_stat_code; depth:3; " - "content:\"123\"; http_stat_code; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"200\"; http_stat_code; depth:3; " + "content:\"123\"; http_stat_code; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1128,18 +1118,17 @@ static int DetectEngineHttpStatCodeTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1159,11 +1148,11 @@ static int DetectEngineHttpStatCodeTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1174,11 +1163,11 @@ static int DetectEngineHttpStatCodeTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"200\"; http_stat_code; depth:3; " - "content:!\"124\"; http_stat_code; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"200\"; http_stat_code; depth:3; " + "content:!\"124\"; http_stat_code; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1249,18 +1238,17 @@ static int DetectEngineHttpStatCodeTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1280,11 +1268,11 @@ static int DetectEngineHttpStatCodeTest11(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1295,11 +1283,11 @@ static int DetectEngineHttpStatCodeTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"200\"; http_stat_code; depth:3; " - "content:\"124\"; http_stat_code; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"200\"; http_stat_code; depth:3; " + "content:\"124\"; http_stat_code; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1370,18 +1358,17 @@ static int DetectEngineHttpStatCodeTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1401,11 +1388,11 @@ static int DetectEngineHttpStatCodeTest12(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1416,11 +1403,11 @@ static int DetectEngineHttpStatCodeTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"20\"; http_stat_code; depth:2; " - "content:\"23\"; http_stat_code; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"20\"; http_stat_code; depth:2; " + "content:\"23\"; http_stat_code; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1491,18 +1478,17 @@ static int DetectEngineHttpStatCodeTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1522,11 +1508,11 @@ static int DetectEngineHttpStatCodeTest13(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1537,11 +1523,11 @@ static int DetectEngineHttpStatCodeTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "content:\"20\"; http_stat_code; depth:3; " - "content:!\"25\"; http_stat_code; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "content:\"20\"; http_stat_code; depth:3; " + "content:!\"25\"; http_stat_code; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1612,18 +1598,17 @@ static int DetectEngineHttpStatCodeTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1643,11 +1628,11 @@ static int DetectEngineHttpStatCodeTest14(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1658,11 +1643,11 @@ static int DetectEngineHttpStatCodeTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "pcre:/20/S; " - "content:\"23\"; http_stat_code; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "pcre:/20/S; " + "content:\"23\"; http_stat_code; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1733,18 +1718,17 @@ static int DetectEngineHttpStatCodeTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200123 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200123 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1764,11 +1748,11 @@ static int DetectEngineHttpStatCodeTest15(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1779,11 +1763,11 @@ static int DetectEngineHttpStatCodeTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat code test\"; " - "pcre:/200/S; " - "content:!\"124\"; http_stat_code; distance:0; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat code test\"; " + "pcre:/200/S; " + "content:!\"124\"; http_stat_code; distance:0; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1875,7 +1859,7 @@ static int DetectHttpStatCodeSigTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1888,8 +1872,9 @@ static int DetectHttpStatCodeSigTest01(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status code\"; content:\"200\"; http_stat_code; sid:1;)"); + s = de_ctx->sig_list = + SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP status code\"; content:\"200\"; http_stat_code; sid:1;)"); if (s == NULL) { printf("sig parse failed: "); goto end; @@ -1973,7 +1958,7 @@ static int DetectHttpStatCodeSigTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1985,16 +1970,16 @@ static int DetectHttpStatCodeSigTest02(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status code\"; content:\"no\"; " - "http_stat_code; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP status code\"; content:\"no\"; " + "http_stat_code; sid:1;)"); if (s == NULL) { goto end; } - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status code\"; content:\"100\";" - "http_stat_code; sid:2;)"); + s->next = SigInit(de_ctx, "alert http any any -> any any (msg:\"HTTP " + "Status code\"; content:\"100\";" + "http_stat_code; sid:2;)"); if (s->next == NULL) { goto end; } @@ -2085,7 +2070,7 @@ static int DetectHttpStatCodeSigTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2097,16 +2082,16 @@ static int DetectHttpStatCodeSigTest03(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status code\"; content:\"FAIL\"; " - "http_stat_code; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP status code\"; content:\"FAIL\"; " + "http_stat_code; sid:1;)"); if (s == NULL) { goto end; } - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status code nocase\"; content:\"fail\"; nocase; " - "http_stat_code; sid:2;)"); + s->next = SigInit(de_ctx, "alert http any any -> any any (msg:\"HTTP " + "Status code nocase\"; content:\"fail\"; nocase; " + "http_stat_code; sid:2;)"); if (s->next == NULL) { goto end; } @@ -2197,7 +2182,7 @@ static int DetectHttpStatCodeSigTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2209,16 +2194,16 @@ static int DetectHttpStatCodeSigTest04(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status code\"; content:\"200\"; " - "http_stat_code; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP status code\"; content:\"200\"; " + "http_stat_code; sid:1;)"); if (s == NULL) { goto end; } - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status code negation\"; content:!\"100\"; nocase; " - "http_stat_code; sid:2;)"); + s->next = SigInit(de_ctx, "alert http any any -> any any (msg:\"HTTP " + "Status code negation\"; content:!\"100\"; nocase; " + "http_stat_code; sid:2;)"); if (s->next == NULL) { goto end; } @@ -2280,38 +2265,23 @@ static int DetectHttpStatCodeSigTest04(void) /** * \brief Register the UNITTESTS for the http_stat_code keyword */ -void DetectHttpStatCodeRegisterTests (void) +void DetectHttpStatCodeRegisterTests(void) { - UtRegisterTest("DetectEngineHttpStatCodeTest01", - DetectEngineHttpStatCodeTest01); - UtRegisterTest("DetectEngineHttpStatCodeTest02", - DetectEngineHttpStatCodeTest02); - UtRegisterTest("DetectEngineHttpStatCodeTest03", - DetectEngineHttpStatCodeTest03); - UtRegisterTest("DetectEngineHttpStatCodeTest04", - DetectEngineHttpStatCodeTest04); - UtRegisterTest("DetectEngineHttpStatCodeTest05", - DetectEngineHttpStatCodeTest05); - UtRegisterTest("DetectEngineHttpStatCodeTest06", - DetectEngineHttpStatCodeTest06); - UtRegisterTest("DetectEngineHttpStatCodeTest07", - DetectEngineHttpStatCodeTest07); - UtRegisterTest("DetectEngineHttpStatCodeTest08", - DetectEngineHttpStatCodeTest08); - UtRegisterTest("DetectEngineHttpStatCodeTest09", - DetectEngineHttpStatCodeTest09); - UtRegisterTest("DetectEngineHttpStatCodeTest10", - DetectEngineHttpStatCodeTest10); - UtRegisterTest("DetectEngineHttpStatCodeTest11", - DetectEngineHttpStatCodeTest11); - UtRegisterTest("DetectEngineHttpStatCodeTest12", - DetectEngineHttpStatCodeTest12); - UtRegisterTest("DetectEngineHttpStatCodeTest13", - DetectEngineHttpStatCodeTest13); - UtRegisterTest("DetectEngineHttpStatCodeTest14", - DetectEngineHttpStatCodeTest14); - UtRegisterTest("DetectEngineHttpStatCodeTest15", - DetectEngineHttpStatCodeTest15); + UtRegisterTest("DetectEngineHttpStatCodeTest01", DetectEngineHttpStatCodeTest01); + UtRegisterTest("DetectEngineHttpStatCodeTest02", DetectEngineHttpStatCodeTest02); + UtRegisterTest("DetectEngineHttpStatCodeTest03", DetectEngineHttpStatCodeTest03); + UtRegisterTest("DetectEngineHttpStatCodeTest04", DetectEngineHttpStatCodeTest04); + UtRegisterTest("DetectEngineHttpStatCodeTest05", DetectEngineHttpStatCodeTest05); + UtRegisterTest("DetectEngineHttpStatCodeTest06", DetectEngineHttpStatCodeTest06); + UtRegisterTest("DetectEngineHttpStatCodeTest07", DetectEngineHttpStatCodeTest07); + UtRegisterTest("DetectEngineHttpStatCodeTest08", DetectEngineHttpStatCodeTest08); + UtRegisterTest("DetectEngineHttpStatCodeTest09", DetectEngineHttpStatCodeTest09); + UtRegisterTest("DetectEngineHttpStatCodeTest10", DetectEngineHttpStatCodeTest10); + UtRegisterTest("DetectEngineHttpStatCodeTest11", DetectEngineHttpStatCodeTest11); + UtRegisterTest("DetectEngineHttpStatCodeTest12", DetectEngineHttpStatCodeTest12); + UtRegisterTest("DetectEngineHttpStatCodeTest13", DetectEngineHttpStatCodeTest13); + UtRegisterTest("DetectEngineHttpStatCodeTest14", DetectEngineHttpStatCodeTest14); + UtRegisterTest("DetectEngineHttpStatCodeTest15", DetectEngineHttpStatCodeTest15); UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01); UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02); diff --git a/src/tests/detect-http-stat-msg.c b/src/tests/detect-http-stat-msg.c index 60251ec8ede5..1800eb44e851 100644 --- a/src/tests/detect-http-stat-msg.c +++ b/src/tests/detect-http-stat-msg.c @@ -33,16 +33,16 @@ #include "../flow-util.h" #include "../flow.h" #include "../app-layer-parser.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" #include "../app-layer.h" -#include "../app-layer-htp.h" +#include "../app-layer/http/parser.h" #include "../app-layer-protos.h" #include "../detect-engine-build.h" #include "../detect-engine-alert.h" static int DetectEngineHttpStatMsgTest01(void) - { +{ TcpSession ssn; Packet *p1 = NULL; Packet *p2 = NULL; @@ -51,18 +51,17 @@ static int DetectEngineHttpStatMsgTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 message\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "message"; + uint8_t http_buf2[] = "HTTP/1.0 200 message\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -82,11 +81,11 @@ static int DetectEngineHttpStatMsgTest01(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -97,10 +96,10 @@ static int DetectEngineHttpStatMsgTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"message\"; http_stat_msg; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"message\"; http_stat_msg; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -170,18 +169,17 @@ static int DetectEngineHttpStatMsgTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 xxxxABC\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 7\r\n" - "\r\n" - "xxxxABC"; + uint8_t http_buf2[] = "HTTP/1.0 200 xxxxABC\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "xxxxABC"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -200,7 +198,7 @@ static int DetectEngineHttpStatMsgTest02(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOCLIENT; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -211,10 +209,10 @@ static int DetectEngineHttpStatMsgTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"ABC\"; http_stat_msg; offset:4; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"ABC\"; http_stat_msg; offset:4; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -277,21 +275,19 @@ static int DetectEngineHttpStatMsgTest03(void) HtpState *http_state = NULL; Flow f; int result = 0; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 1234567"; + uint8_t http_buf2[] = "HTTP/1.0 200 1234567"; uint32_t http_len2 = sizeof(http_buf2) - 1; - uint8_t http_buf3[] = - "8901234ABC\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 17\r\n" - "\r\n" - "12345678901234ABC"; + uint8_t http_buf3[] = "8901234ABC\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 17\r\n" + "\r\n" + "12345678901234ABC"; uint32_t http_len3 = sizeof(http_buf3) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -310,11 +306,11 @@ static int DetectEngineHttpStatMsgTest03(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -325,10 +321,10 @@ static int DetectEngineHttpStatMsgTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"ABC\"; http_stat_msg; offset:14; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"ABC\"; http_stat_msg; offset:14; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -407,18 +403,17 @@ static int DetectEngineHttpStatMsgTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -438,11 +433,11 @@ static int DetectEngineHttpStatMsgTest04(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -453,10 +448,10 @@ static int DetectEngineHttpStatMsgTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:!\"abc\"; http_stat_msg; offset:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:!\"abc\"; http_stat_msg; offset:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -527,18 +522,17 @@ static int DetectEngineHttpStatMsgTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -558,11 +552,11 @@ static int DetectEngineHttpStatMsgTest05(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -573,10 +567,10 @@ static int DetectEngineHttpStatMsgTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"abc\"; http_stat_msg; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -647,18 +641,17 @@ static int DetectEngineHttpStatMsgTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -678,11 +671,11 @@ static int DetectEngineHttpStatMsgTest06(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -693,10 +686,10 @@ static int DetectEngineHttpStatMsgTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:!\"def\"; http_stat_msg; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:!\"def\"; http_stat_msg; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -767,18 +760,17 @@ static int DetectEngineHttpStatMsgTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -798,11 +790,11 @@ static int DetectEngineHttpStatMsgTest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -813,10 +805,10 @@ static int DetectEngineHttpStatMsgTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:!\"def\"; http_stat_msg; offset:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:!\"def\"; http_stat_msg; offset:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -887,18 +879,17 @@ static int DetectEngineHttpStatMsgTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -918,11 +909,11 @@ static int DetectEngineHttpStatMsgTest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -933,10 +924,10 @@ static int DetectEngineHttpStatMsgTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:!\"abc\"; http_stat_msg; depth:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:!\"abc\"; http_stat_msg; depth:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1007,18 +998,17 @@ static int DetectEngineHttpStatMsgTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1038,11 +1028,11 @@ static int DetectEngineHttpStatMsgTest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1053,11 +1043,11 @@ static int DetectEngineHttpStatMsgTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"abc\"; http_stat_msg; depth:3; " - "content:\"def\"; http_stat_msg; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "content:\"def\"; http_stat_msg; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1128,18 +1118,17 @@ static int DetectEngineHttpStatMsgTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1159,11 +1148,11 @@ static int DetectEngineHttpStatMsgTest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1174,11 +1163,11 @@ static int DetectEngineHttpStatMsgTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"abc\"; http_stat_msg; depth:3; " - "content:!\"xyz\"; http_stat_msg; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "content:!\"xyz\"; http_stat_msg; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1249,18 +1238,17 @@ static int DetectEngineHttpStatMsgTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1280,11 +1268,11 @@ static int DetectEngineHttpStatMsgTest11(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1295,11 +1283,11 @@ static int DetectEngineHttpStatMsgTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"abc\"; http_stat_msg; depth:3; " - "content:\"xyz\"; http_stat_msg; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"abc\"; http_stat_msg; depth:3; " + "content:\"xyz\"; http_stat_msg; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1370,18 +1358,17 @@ static int DetectEngineHttpStatMsgTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1401,11 +1388,11 @@ static int DetectEngineHttpStatMsgTest12(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1416,11 +1403,11 @@ static int DetectEngineHttpStatMsgTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"ab\"; http_stat_msg; depth:2; " - "content:\"ef\"; http_stat_msg; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"ab\"; http_stat_msg; depth:2; " + "content:\"ef\"; http_stat_msg; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1491,18 +1478,17 @@ static int DetectEngineHttpStatMsgTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1522,11 +1508,11 @@ static int DetectEngineHttpStatMsgTest13(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1537,11 +1523,11 @@ static int DetectEngineHttpStatMsgTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "content:\"ab\"; http_stat_msg; depth:3; " - "content:!\"yz\"; http_stat_msg; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "content:\"ab\"; http_stat_msg; depth:3; " + "content:!\"yz\"; http_stat_msg; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1612,18 +1598,17 @@ static int DetectEngineHttpStatMsgTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1643,11 +1628,11 @@ static int DetectEngineHttpStatMsgTest14(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1658,11 +1643,11 @@ static int DetectEngineHttpStatMsgTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "pcre:/ab/Y; " - "content:\"ef\"; http_stat_msg; distance:2; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "pcre:/ab/Y; " + "content:\"ef\"; http_stat_msg; distance:2; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1733,18 +1718,17 @@ static int DetectEngineHttpStatMsgTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; + uint8_t http_buf1[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; uint32_t http_len1 = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 abcdef\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; + uint8_t http_buf2[] = "HTTP/1.0 200 abcdef\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; uint32_t http_len2 = sizeof(http_buf2) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1764,11 +1748,11 @@ static int DetectEngineHttpStatMsgTest15(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOCLIENT; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1779,11 +1763,11 @@ static int DetectEngineHttpStatMsgTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http stat msg test\"; " - "pcre:/abc/Y; " - "content:!\"xyz\"; http_stat_msg; distance:0; within:3; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http stat msg test\"; " + "pcre:/abc/Y; " + "content:!\"xyz\"; http_stat_msg; distance:0; within:3; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -1875,7 +1859,7 @@ static int DetectHttpStatMsgSigTest01(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1887,16 +1871,16 @@ static int DetectHttpStatMsgSigTest01(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status message\"; content:\"OK\"; " - "http_stat_msg; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP status message\"; content:\"OK\"; " + "http_stat_msg; sid:1;)"); if (s == NULL) { goto end; } - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status message nocase\"; content:\"ok\"; nocase; " - "http_stat_msg; sid:2;)"); + s->next = SigInit(de_ctx, "alert http any any -> any any (msg:\"HTTP " + "Status message nocase\"; content:\"ok\"; nocase; " + "http_stat_msg; sid:2;)"); if (s->next == NULL) { goto end; } @@ -1986,7 +1970,7 @@ static int DetectHttpStatMsgSigTest02(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1998,9 +1982,9 @@ static int DetectHttpStatMsgSigTest02(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status message\"; content:\"no\"; " - "http_stat_msg; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP status message\"; content:\"no\"; " + "http_stat_msg; sid:1;)"); if (s == NULL) { goto end; } @@ -2087,7 +2071,7 @@ static int DetectHttpStatMsgSigTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -2099,16 +2083,16 @@ static int DetectHttpStatMsgSigTest03(void) de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\"HTTP status message\"; content:\"ok\"; " - "nocase; http_stat_msg; sid:1;)"); + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any (msg:" + "\"HTTP status message\"; content:\"ok\"; " + "nocase; http_stat_msg; sid:1;)"); if (s == NULL) { goto end; } - s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"HTTP " - "Status message nocase\"; content:!\"Not\"; " - "http_stat_msg; sid:2;)"); + s->next = SigInit(de_ctx, "alert http any any -> any any (msg:\"HTTP " + "Status message nocase\"; content:!\"Not\"; " + "http_stat_msg; sid:2;)"); if (s->next == NULL) { goto end; } @@ -2141,11 +2125,11 @@ static int DetectHttpStatMsgSigTest03(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (! PacketAlertCheck(p, 1)) { + if (!PacketAlertCheck(p, 1)) { printf("sid 1 didn't matched but should have: "); goto end; } - if (! PacketAlertCheck(p, 2)) { + if (!PacketAlertCheck(p, 2)) { printf("sid 2 didn't matched but should have: "); goto end; } @@ -2170,42 +2154,27 @@ static int DetectHttpStatMsgSigTest03(void) /** * \brief Register the UNITTESTS for the http_stat_msg keyword */ -void DetectHttpStatMsgRegisterTests (void) +void DetectHttpStatMsgRegisterTests(void) { UtRegisterTest("DetectHttpStatMsgSigTest01", DetectHttpStatMsgSigTest01); UtRegisterTest("DetectHttpStatMsgSigTest02", DetectHttpStatMsgSigTest02); UtRegisterTest("DetectHttpStatMsgSigTest03", DetectHttpStatMsgSigTest03); - UtRegisterTest("DetectEngineHttpStatMsgTest01", - DetectEngineHttpStatMsgTest01); - UtRegisterTest("DetectEngineHttpStatMsgTest02", - DetectEngineHttpStatMsgTest02); - UtRegisterTest("DetectEngineHttpStatMsgTest03", - DetectEngineHttpStatMsgTest03); - UtRegisterTest("DetectEngineHttpStatMsgTest04", - DetectEngineHttpStatMsgTest04); - UtRegisterTest("DetectEngineHttpStatMsgTest05", - DetectEngineHttpStatMsgTest05); - UtRegisterTest("DetectEngineHttpStatMsgTest06", - DetectEngineHttpStatMsgTest06); - UtRegisterTest("DetectEngineHttpStatMsgTest07", - DetectEngineHttpStatMsgTest07); - UtRegisterTest("DetectEngineHttpStatMsgTest08", - DetectEngineHttpStatMsgTest08); - UtRegisterTest("DetectEngineHttpStatMsgTest09", - DetectEngineHttpStatMsgTest09); - UtRegisterTest("DetectEngineHttpStatMsgTest10", - DetectEngineHttpStatMsgTest10); - UtRegisterTest("DetectEngineHttpStatMsgTest11", - DetectEngineHttpStatMsgTest11); - UtRegisterTest("DetectEngineHttpStatMsgTest12", - DetectEngineHttpStatMsgTest12); - UtRegisterTest("DetectEngineHttpStatMsgTest13", - DetectEngineHttpStatMsgTest13); - UtRegisterTest("DetectEngineHttpStatMsgTest14", - DetectEngineHttpStatMsgTest14); - UtRegisterTest("DetectEngineHttpStatMsgTest15", - DetectEngineHttpStatMsgTest15); + UtRegisterTest("DetectEngineHttpStatMsgTest01", DetectEngineHttpStatMsgTest01); + UtRegisterTest("DetectEngineHttpStatMsgTest02", DetectEngineHttpStatMsgTest02); + UtRegisterTest("DetectEngineHttpStatMsgTest03", DetectEngineHttpStatMsgTest03); + UtRegisterTest("DetectEngineHttpStatMsgTest04", DetectEngineHttpStatMsgTest04); + UtRegisterTest("DetectEngineHttpStatMsgTest05", DetectEngineHttpStatMsgTest05); + UtRegisterTest("DetectEngineHttpStatMsgTest06", DetectEngineHttpStatMsgTest06); + UtRegisterTest("DetectEngineHttpStatMsgTest07", DetectEngineHttpStatMsgTest07); + UtRegisterTest("DetectEngineHttpStatMsgTest08", DetectEngineHttpStatMsgTest08); + UtRegisterTest("DetectEngineHttpStatMsgTest09", DetectEngineHttpStatMsgTest09); + UtRegisterTest("DetectEngineHttpStatMsgTest10", DetectEngineHttpStatMsgTest10); + UtRegisterTest("DetectEngineHttpStatMsgTest11", DetectEngineHttpStatMsgTest11); + UtRegisterTest("DetectEngineHttpStatMsgTest12", DetectEngineHttpStatMsgTest12); + UtRegisterTest("DetectEngineHttpStatMsgTest13", DetectEngineHttpStatMsgTest13); + UtRegisterTest("DetectEngineHttpStatMsgTest14", DetectEngineHttpStatMsgTest14); + UtRegisterTest("DetectEngineHttpStatMsgTest15", DetectEngineHttpStatMsgTest15); } /** diff --git a/src/tests/detect-http-uri.c b/src/tests/detect-http-uri.c index 8c60d430588e..0e3dbd600bb9 100644 --- a/src/tests/detect-http-uri.c +++ b/src/tests/detect-http-uri.c @@ -24,9 +24,9 @@ #include "../suricata-common.h" #include "../app-layer.h" #include "../app-layer-parser.h" -#include "../app-layer-htp.h" -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../app-layer/http/parser.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" #include "../flow.h" #include "../flow-util.h" @@ -42,12 +42,12 @@ static int UriTestSig01(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -68,7 +68,7 @@ static int UriTestSig01(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -82,8 +82,8 @@ static int UriTestSig01(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test uricontent option\"; " - "uricontent:\"one\"; sid:1;)"); + "(msg:\"Test uricontent option\"; " + "uricontent:\"one\"; sid:1;)"); if (s == NULL) { goto end; } @@ -158,12 +158,12 @@ static int UriTestSig02(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /on HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -184,7 +184,7 @@ static int UriTestSig02(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -198,8 +198,8 @@ static int UriTestSig02(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option\"; " - "pcre:/one/U; sid:1;)"); + "(msg:\"Test pcre /U option\"; " + "pcre:/one/U; sid:1;)"); if (s == NULL) { goto end; } @@ -274,12 +274,12 @@ static int UriTestSig03(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -300,7 +300,7 @@ static int UriTestSig03(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -314,8 +314,8 @@ static int UriTestSig03(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option\"; " - "pcre:/blah/U; sid:1;)"); + "(msg:\"Test pcre /U option\"; " + "pcre:/blah/U; sid:1;)"); if (s == NULL) { goto end; } @@ -390,12 +390,12 @@ static int UriTestSig04(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -416,7 +416,7 @@ static int UriTestSig04(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -430,8 +430,8 @@ static int UriTestSig04(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test urilen option\"; " - "urilen:>20; sid:1;)"); + "(msg:\"Test urilen option\"; " + "urilen:>20; sid:1;)"); if (s == NULL) { goto end; } @@ -506,12 +506,12 @@ static int UriTestSig05(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -532,7 +532,7 @@ static int UriTestSig05(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -546,8 +546,8 @@ static int UriTestSig05(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test urilen option\"; " - "urilen:>4; sid:1;)"); + "(msg:\"Test urilen option\"; " + "urilen:>4; sid:1;)"); if (s == NULL) { goto end; } @@ -622,12 +622,12 @@ static int UriTestSig06(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -648,7 +648,7 @@ static int UriTestSig06(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -662,8 +662,8 @@ static int UriTestSig06(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option\"; " - "pcre:/(oneself)+/U; sid:1;)"); + "(msg:\"Test pcre /U option\"; " + "pcre:/(oneself)+/U; sid:1;)"); if (s == NULL) { goto end; } @@ -738,12 +738,12 @@ static int UriTestSig07(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -764,7 +764,7 @@ static int UriTestSig07(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -778,8 +778,8 @@ static int UriTestSig07(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option with urilen \"; " - "pcre:/(one){2,}(self)?/U; urilen:3<>20; sid:1;)"); + "(msg:\"Test pcre /U option with urilen \"; " + "pcre:/(one){2,}(self)?/U; urilen:3<>20; sid:1;)"); if (s == NULL) { goto end; } @@ -854,12 +854,12 @@ static int UriTestSig08(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -880,7 +880,7 @@ static int UriTestSig08(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -894,8 +894,8 @@ static int UriTestSig08(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option with urilen\"; " - "pcre:/(blabla){2,}(self)?/U; urilen:3<>20; sid:1;)"); + "(msg:\"Test pcre /U option with urilen\"; " + "pcre:/(blabla){2,}(self)?/U; urilen:3<>20; sid:1;)"); if (s == NULL) { goto end; } @@ -970,12 +970,12 @@ static int UriTestSig09(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -996,7 +996,7 @@ static int UriTestSig09(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1010,8 +1010,8 @@ static int UriTestSig09(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U option with urilen \"; " - "pcre:/(one){2,}(self)?/U; urilen:<2; sid:1;)"); + "(msg:\"Test pcre /U option with urilen \"; " + "pcre:/(one){2,}(self)?/U; urilen:<2; sid:1;)"); if (s == NULL) { goto end; } @@ -1086,12 +1086,12 @@ static int UriTestSig12(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /oneoneoneone HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneoneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -1112,7 +1112,7 @@ static int UriTestSig12(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1126,9 +1126,9 @@ static int UriTestSig12(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test pcre /U, uricontent and urilen option\"; " - "uricontent:\"one\"; " - "pcre:/(one)+self/U; urilen:>2; sid:1;)"); + "(msg:\"Test pcre /U, uricontent and urilen option\"; " + "uricontent:\"one\"; " + "pcre:/(one)+self/U; urilen:>2; sid:1;)"); if (s == NULL) { goto end; } @@ -1203,12 +1203,12 @@ static int UriTestSig13(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -1229,7 +1229,7 @@ static int UriTestSig13(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1243,8 +1243,8 @@ static int UriTestSig13(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test urilen option\"; " - "urilen:>2; uricontent:\"one\"; sid:1;)"); + "(msg:\"Test urilen option\"; " + "urilen:>2; uricontent:\"one\"; sid:1;)"); if (s == NULL) { goto end; } @@ -1289,7 +1289,6 @@ static int UriTestSig13(void) /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; @@ -1320,12 +1319,12 @@ static int UriTestSig14(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -1346,7 +1345,7 @@ static int UriTestSig14(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1360,8 +1359,8 @@ static int UriTestSig14(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test uricontent option\"; " - "uricontent:\"one\"; pcre:/one(self)?/U;sid:1;)"); + "(msg:\"Test uricontent option\"; " + "uricontent:\"one\"; pcre:/one(self)?/U;sid:1;)"); if (s == NULL) { goto end; } @@ -1406,7 +1405,6 @@ static int UriTestSig14(void) /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; @@ -1437,12 +1435,12 @@ static int UriTestSig15(void) Flow f; HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /oneself HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Packet *p = NULL; @@ -1463,7 +1461,7 @@ static int UriTestSig15(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1477,8 +1475,8 @@ static int UriTestSig15(void) de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Test uricontent option\"; " - "uricontent:\"one\"; pcre:/^\\/one(self)?$/U;sid:1;)"); + "(msg:\"Test uricontent option\"; " + "uricontent:\"one\"; pcre:/^\\/one(self)?$/U;sid:1;)"); if (s == NULL) { goto end; } @@ -1523,7 +1521,6 @@ static int UriTestSig15(void) /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { printf("sig 1 didnt alert with payload2, but it should: "); goto end; @@ -1552,12 +1549,12 @@ static int UriTestSig16(void) { HtpState *http_state = NULL; uint8_t http_buf1[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0/\r\n" - "Host: 1.2.3.4\r\n\r\n"; + "User-Agent: Mozilla/1.0/\r\n" + "Host: 1.2.3.4\r\n\r\n"; uint32_t http_buf1_len = sizeof(http_buf1) - 1; uint8_t http_buf2[] = "POST /search?q=123&aq=7123abcee HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n" - "Cookie: hellocatch\r\n\r\n"; + "User-Agent: Mozilla/1.0\r\n" + "Cookie: hellocatch\r\n\r\n"; uint32_t http_buf2_len = sizeof(http_buf2) - 1; TcpSession ssn; Signature *s = NULL; @@ -1589,7 +1586,11 @@ static int UriTestSig16(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)"); + s = de_ctx->sig_list = SigInit(de_ctx, + "drop tcp any any -> any any (flow:to_server,established; uricontent:\"/search?q=\"; " + "pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; " + "pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; " + "rev:9;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -1642,7 +1643,7 @@ static int UriTestSig17(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_big_big_string_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -1664,7 +1665,7 @@ static int UriTestSig17(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1678,10 +1679,10 @@ static int UriTestSig17(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"this\"; uricontent:\"is\"; within:6; " - "uricontent:\"big\"; within:8; " - "uricontent:\"string\"; within:8; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"this\"; uricontent:\"is\"; within:6; " + "uricontent:\"big\"; within:8; " + "uricontent:\"string\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -1735,7 +1736,7 @@ static int UriTestSig18(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /now_this_is_is_is_big_big_big_string_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -1757,7 +1758,7 @@ static int UriTestSig18(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1771,10 +1772,10 @@ static int UriTestSig18(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"this\"; uricontent:\"is\"; within:9; " - "uricontent:\"big\"; within:12; " - "uricontent:\"string\"; within:8; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"this\"; uricontent:\"is\"; within:9; " + "uricontent:\"big\"; within:12; " + "uricontent:\"string\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -1828,7 +1829,7 @@ static int UriTestSig19(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_this_now_is_is_____big_string_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -1850,7 +1851,7 @@ static int UriTestSig19(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1864,11 +1865,11 @@ static int UriTestSig19(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"now\"; uricontent:\"this\"; " - "uricontent:\"is\"; within:12; " - "uricontent:\"big\"; within:8; " - "uricontent:\"string\"; within:8; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"now\"; uricontent:\"this\"; " + "uricontent:\"is\"; within:12; " + "uricontent:\"big\"; within:8; " + "uricontent:\"string\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -1922,7 +1923,7 @@ static int UriTestSig20(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /_________thus_thus_is_a_big HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -1944,7 +1945,7 @@ static int UriTestSig20(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -1958,10 +1959,10 @@ static int UriTestSig20(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"thus\"; offset:8; " - "uricontent:\"is\"; within:6; " - "uricontent:\"big\"; within:8; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"thus\"; offset:8; " + "uricontent:\"is\"; within:6; " + "uricontent:\"big\"; within:8; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2015,7 +2016,7 @@ static int UriTestSig21(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2037,7 +2038,7 @@ static int UriTestSig21(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2051,9 +2052,9 @@ static int UriTestSig21(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"fix\"; uricontent:\"this\"; within:6; " - "uricontent:!\"and\"; distance:0; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"fix\"; uricontent:\"this\"; within:6; " + "uricontent:!\"and\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2107,8 +2108,8 @@ static int UriTestSig22(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_is_a_super_duper_" - "nova_in_super_nova_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "nova_in_super_nova_now HTTP/1.0\r\n" + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2130,7 +2131,7 @@ static int UriTestSig22(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2144,8 +2145,8 @@ static int UriTestSig22(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "pcre:/super/U; uricontent:\"nova\"; within:7; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "pcre:/super/U; uricontent:\"nova\"; within:7; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2199,7 +2200,7 @@ static int UriTestSig23(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2221,7 +2222,7 @@ static int UriTestSig23(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2235,8 +2236,8 @@ static int UriTestSig23(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:!\"fix_this_now\"; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "uricontent:!\"fix_this_now\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2290,7 +2291,7 @@ static int UriTestSig24(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2312,7 +2313,7 @@ static int UriTestSig24(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2325,9 +2326,10 @@ static int UriTestSig24(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"we_need_to\"; uricontent:!\"fix_this_now\"; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"we_need_to\"; uricontent:!\"fix_this_now\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2381,7 +2383,7 @@ static int UriTestSig25(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2406,7 +2408,7 @@ static int UriTestSig25(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -2416,9 +2418,10 @@ static int UriTestSig25(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "pcre:/normalized/U; uricontent:\"normalized uri\"; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any " + "(msg:\"test multiple relative uricontents\"; " + "pcre:/normalized/U; uricontent:\"normalized uri\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2472,7 +2475,7 @@ static int UriTestSig26(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2494,7 +2497,7 @@ static int UriTestSig26(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2508,8 +2511,8 @@ static int UriTestSig26(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "uricontent:\"fix_this\"; isdataat:4,relative; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "uricontent:\"fix_this\"; isdataat:4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2562,7 +2565,7 @@ static int UriTestSig26(void) static int UriTestSig27(void) { uint8_t *http_buf = (uint8_t *)"POST /we_need_to_fix_this_and_yes_fix_this_now HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2584,7 +2587,7 @@ static int UriTestSig27(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2627,7 +2630,7 @@ static int UriTestSig28(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2649,7 +2652,7 @@ static int UriTestSig28(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2662,11 +2665,10 @@ static int UriTestSig28(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"ring\"; distance:one; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"ring\"; distance:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2717,7 +2719,7 @@ static int UriTestSig29(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2739,7 +2741,7 @@ static int UriTestSig29(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2752,11 +2754,10 @@ static int UriTestSig29(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"ring\"; distance:one; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"ring\"; distance:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2807,7 +2808,7 @@ static int UriTestSig30(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2829,7 +2830,7 @@ static int UriTestSig30(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2842,11 +2843,10 @@ static int UriTestSig30(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"_b5ig\"; offset:one; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"_b5ig\"; offset:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2897,7 +2897,7 @@ static int UriTestSig31(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -2919,7 +2919,7 @@ static int UriTestSig31(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -2932,11 +2932,10 @@ static int UriTestSig31(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"his\"; depth:one; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"his\"; depth:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -2987,7 +2986,7 @@ static int UriTestSig32(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /this_b5ig_string_now_in_http HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -3009,7 +3008,7 @@ static int UriTestSig32(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -3022,11 +3021,10 @@ static int UriTestSig32(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any (msg:\"dummy\"; " - "uricontent:\"this\"; " - "byte_extract:1,2,one,string,dec,relative; " - "uricontent:\"g_st\"; within:one; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"dummy\"; " + "uricontent:\"this\"; " + "byte_extract:1,2,one,string,dec,relative; " + "uricontent:\"g_st\"; within:one; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3077,7 +3075,7 @@ static int UriTestSig33(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -3102,7 +3100,7 @@ static int UriTestSig33(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -3113,8 +3111,8 @@ static int UriTestSig33(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:15; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "urilen:15; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3165,7 +3163,7 @@ static int UriTestSig34(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -3190,7 +3188,7 @@ static int UriTestSig34(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -3201,8 +3199,8 @@ static int UriTestSig34(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:15, norm; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "urilen:15, norm; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3253,7 +3251,7 @@ static int UriTestSig35(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -3278,7 +3276,7 @@ static int UriTestSig35(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -3289,8 +3287,8 @@ static int UriTestSig35(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:16; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "urilen:16; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3322,7 +3320,7 @@ static int UriTestSig35(void) result = 1; end: - if (alp_tctx != NULL) + if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&tv, det_ctx); @@ -3341,7 +3339,7 @@ static int UriTestSig36(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -3366,7 +3364,7 @@ static int UriTestSig36(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -3377,8 +3375,8 @@ static int UriTestSig36(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:16, norm; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "urilen:16, norm; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3429,7 +3427,7 @@ static int UriTestSig37(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -3454,7 +3452,7 @@ static int UriTestSig37(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -3465,8 +3463,8 @@ static int UriTestSig37(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:17, raw; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "urilen:17, raw; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3517,7 +3515,7 @@ static int UriTestSig38(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /normalized%20uri " - "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; + "HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -3542,7 +3540,7 @@ static int UriTestSig38(void) p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; StreamTcpInitConfig(true); @@ -3553,8 +3551,8 @@ static int UriTestSig38(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative uricontents\"; " - "urilen:18, raw; sid:1;)"); + "(msg:\"test multiple relative uricontents\"; " + "urilen:18, raw; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -3635,17 +3633,16 @@ static int DetectEngineHttpRawUriTest01(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/b/../c"; - uint8_t http2_buf[] = - "/./d.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a/b/../c"; + uint8_t http2_buf[] = "/./d.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3681,10 +3678,10 @@ static int DetectEngineHttpRawUriTest01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"../c/./d\"; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"../c/./d\"; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3759,14 +3756,14 @@ static int DetectEngineHttpRawUriTest02(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1"; + uint8_t http1_buf[] = "GET /../a/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -3801,10 +3798,10 @@ static int DetectEngineHttpRawUriTest02(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"/c/./d\"; http_raw_uri; offset:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"/c/./d\"; http_raw_uri; offset:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3863,17 +3860,16 @@ static int DetectEngineHttpRawUriTest03(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/b/../"; - uint8_t http2_buf[] = - "c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a/b/../"; + uint8_t http2_buf[] = "c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -3909,10 +3905,10 @@ static int DetectEngineHttpRawUriTest03(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"/a/b\"; http_raw_uri; offset:10; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"/a/b\"; http_raw_uri; offset:10; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -3987,17 +3983,16 @@ static int DetectEngineHttpRawUriTest04(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/b/../"; - uint8_t http2_buf[] = - "c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a/b/../"; + uint8_t http2_buf[] = "c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) " + "Gecko/20091221 Firefox/3.5.7\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4033,10 +4028,10 @@ static int DetectEngineHttpRawUriTest04(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:!\"/a/b\"; http_raw_uri; offset:10; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:!\"/a/b\"; http_raw_uri; offset:10; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4111,16 +4106,14 @@ static int DetectEngineHttpRawUriTest05(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/b/"; - uint8_t http2_buf[] = - "../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a/b/"; + uint8_t http2_buf[] = "../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4156,10 +4149,10 @@ static int DetectEngineHttpRawUriTest05(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"a/b\"; http_raw_uri; depth:10; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"a/b\"; http_raw_uri; depth:10; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4234,16 +4227,14 @@ static int DetectEngineHttpRawUriTest06(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/b/"; - uint8_t http2_buf[] = - "../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a/b/"; + uint8_t http2_buf[] = "../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4279,10 +4270,10 @@ static int DetectEngineHttpRawUriTest06(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:!\"/a/b\"; http_raw_uri; depth:25; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:!\"/a/b\"; http_raw_uri; depth:25; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4357,16 +4348,14 @@ static int DetectEngineHttpRawUriTest07(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/b/"; - uint8_t http2_buf[] = - "../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a/b/"; + uint8_t http2_buf[] = "../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4402,10 +4391,10 @@ static int DetectEngineHttpRawUriTest07(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:!\"/c/./d\"; http_raw_uri; depth:12; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:!\"/c/./d\"; http_raw_uri; depth:12; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4480,16 +4469,14 @@ static int DetectEngineHttpRawUriTest08(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a/"; - uint8_t http2_buf[] = - "b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a/"; + uint8_t http2_buf[] = "b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4525,10 +4512,10 @@ static int DetectEngineHttpRawUriTest08(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:!\"/c/./d\"; http_raw_uri; depth:18; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:!\"/c/./d\"; http_raw_uri; depth:18; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4603,16 +4590,14 @@ static int DetectEngineHttpRawUriTest09(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4648,11 +4633,11 @@ static int DetectEngineHttpRawUriTest09(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"/a\"; http_raw_uri; " - "content:\"./c/.\"; http_raw_uri; within:9; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"/a\"; http_raw_uri; " + "content:\"./c/.\"; http_raw_uri; within:9; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4727,16 +4712,14 @@ static int DetectEngineHttpRawUriTest10(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4772,11 +4755,11 @@ static int DetectEngineHttpRawUriTest10(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"/a\"; http_raw_uri; " - "content:!\"boom\"; http_raw_uri; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"/a\"; http_raw_uri; " + "content:!\"boom\"; http_raw_uri; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4851,16 +4834,14 @@ static int DetectEngineHttpRawUriTest11(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -4896,11 +4877,11 @@ static int DetectEngineHttpRawUriTest11(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"./a\"; http_raw_uri; " - "content:\"boom\"; http_raw_uri; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"./a\"; http_raw_uri; " + "content:\"boom\"; http_raw_uri; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -4975,16 +4956,14 @@ static int DetectEngineHttpRawUriTest12(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5020,11 +4999,11 @@ static int DetectEngineHttpRawUriTest12(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"./a\"; http_raw_uri; " - "content:!\"/b/..\"; http_raw_uri; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"./a\"; http_raw_uri; " + "content:!\"/b/..\"; http_raw_uri; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5099,16 +5078,14 @@ static int DetectEngineHttpRawUriTest13(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5144,11 +5121,11 @@ static int DetectEngineHttpRawUriTest13(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"./a\"; http_raw_uri; " - "content:\"/c/.\"; http_raw_uri; distance:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"./a\"; http_raw_uri; " + "content:\"/c/.\"; http_raw_uri; distance:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5223,16 +5200,14 @@ static int DetectEngineHttpRawUriTest14(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5268,11 +5243,11 @@ static int DetectEngineHttpRawUriTest14(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"./a\"; http_raw_uri; " - "content:!\"b/..\"; http_raw_uri; distance:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"./a\"; http_raw_uri; " + "content:!\"b/..\"; http_raw_uri; distance:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5347,16 +5322,14 @@ static int DetectEngineHttpRawUriTest15(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5392,11 +5365,11 @@ static int DetectEngineHttpRawUriTest15(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"./a\"; http_raw_uri; " - "content:\"/c/\"; http_raw_uri; distance:7; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"./a\"; http_raw_uri; " + "content:\"/c/\"; http_raw_uri; distance:7; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5471,16 +5444,14 @@ static int DetectEngineHttpRawUriTest16(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5516,11 +5487,11 @@ static int DetectEngineHttpRawUriTest16(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"./a\"; http_raw_uri; " - "content:!\"/c/\"; http_raw_uri; distance:4; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "content:\"./a\"; http_raw_uri; " + "content:!\"/c/\"; http_raw_uri; distance:4; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5595,16 +5566,14 @@ static int DetectEngineHttpRawUriTest21(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5640,11 +5609,11 @@ static int DetectEngineHttpRawUriTest21(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:!\"/c/\"; http_raw_uri; within:5; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:!\"/c/\"; http_raw_uri; within:5; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5719,16 +5688,14 @@ static int DetectEngineHttpRawUriTest22(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5764,11 +5731,11 @@ static int DetectEngineHttpRawUriTest22(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:!\"/c/\"; within:5; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:!\"/c/\"; within:5; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5843,16 +5810,14 @@ static int DetectEngineHttpRawUriTest23(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -5888,11 +5853,11 @@ static int DetectEngineHttpRawUriTest23(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:!\"/c/\"; distance:3; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:!\"/c/\"; distance:3; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -5967,16 +5932,14 @@ static int DetectEngineHttpRawUriTest24(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -6012,11 +5975,11 @@ static int DetectEngineHttpRawUriTest24(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:!\"/c/\"; distance:10; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:!\"/c/\"; distance:10; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6091,16 +6054,14 @@ static int DetectEngineHttpRawUriTest25(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -6136,11 +6097,11 @@ static int DetectEngineHttpRawUriTest25(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:\"/c/\"; within:10; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:\"/c/\"; within:10; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6215,16 +6176,14 @@ static int DetectEngineHttpRawUriTest26(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -6260,11 +6219,11 @@ static int DetectEngineHttpRawUriTest26(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:\"/c/\"; within:5; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:\"/c/\"; within:5; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6339,16 +6298,14 @@ static int DetectEngineHttpRawUriTest27(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -6384,11 +6341,11 @@ static int DetectEngineHttpRawUriTest27(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:\"/c/\"; distance:5; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:\"/c/\"; distance:5; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6463,16 +6420,14 @@ static int DetectEngineHttpRawUriTest28(void) DetectEngineThreadCtx *det_ctx = NULL; HtpState *http_state = NULL; Flow f; - uint8_t http1_buf[] = - "GET /../a"; - uint8_t http2_buf[] = - "/b/../c/./d.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1" - "This is dummy message body2"; + uint8_t http1_buf[] = "GET /../a"; + uint8_t http2_buf[] = "/b/../c/./d.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1" + "This is dummy message body2"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; @@ -6508,11 +6463,11 @@ static int DetectEngineHttpRawUriTest28(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "pcre:/\\.\\/a/I; " - "content:\"/c/\"; distance:10; http_raw_uri; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http raw uri test\"; " + "pcre:/\\.\\/a/I; " + "content:\"/c/\"; distance:10; http_raw_uri; " + "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; @@ -6584,7 +6539,7 @@ static int DetectEngineHttpRawUriTest29(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /../a/b/../c/./d.html HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -6620,9 +6575,9 @@ static int DetectEngineHttpRawUriTest29(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative raw uri contents\"; " - "content:\"/c/\"; http_raw_uri; " - "isdataat:4,relative; sid:1;)"); + "(msg:\"test multiple relative raw uri contents\"; " + "content:\"/c/\"; http_raw_uri; " + "isdataat:4,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -6676,7 +6631,7 @@ static int DetectEngineHttpRawUriTest30(void) { int result = 0; uint8_t *http_buf = (uint8_t *)"POST /../a/b/../c/./d.html HTTP/1.0\r\n" - "User-Agent: Mozilla/1.0\r\n"; + "User-Agent: Mozilla/1.0\r\n"; uint32_t http_buf_len = strlen((char *)http_buf); Flow f; TcpSession ssn; @@ -6698,7 +6653,7 @@ static int DetectEngineHttpRawUriTest30(void) f.flags |= FLOW_IPV4; p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; f.alproto = ALPROTO_HTTP1; @@ -6712,8 +6667,8 @@ static int DetectEngineHttpRawUriTest30(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"test multiple relative raw uri contents\"; " - "uricontent:\"/c/\"; isdataat:!10,relative; sid:1;)"); + "(msg:\"test multiple relative raw uri contents\"; " + "uricontent:\"/c/\"; isdataat:!10,relative; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } @@ -6763,7 +6718,7 @@ static int DetectEngineHttpRawUriTest30(void) /** * \brief Register the UNITTESTS for the http_uri keyword */ -static void DetectHttpUriRegisterTests (void) +static void DetectHttpUriRegisterTests(void) { UtRegisterTest("UriTestSig01", UriTestSig01); UtRegisterTest("UriTestSig02", UriTestSig02); @@ -6803,59 +6758,32 @@ static void DetectHttpUriRegisterTests (void) UtRegisterTest("UriTestSig37", UriTestSig37); UtRegisterTest("UriTestSig38", UriTestSig38); - UtRegisterTest("DetectHttpUriIsdataatParseTest", - DetectHttpUriIsdataatParseTest); - - UtRegisterTest("DetectEngineHttpRawUriTest01", - DetectEngineHttpRawUriTest01); - UtRegisterTest("DetectEngineHttpRawUriTest02", - DetectEngineHttpRawUriTest02); - UtRegisterTest("DetectEngineHttpRawUriTest03", - DetectEngineHttpRawUriTest03); - UtRegisterTest("DetectEngineHttpRawUriTest04", - DetectEngineHttpRawUriTest04); - UtRegisterTest("DetectEngineHttpRawUriTest05", - DetectEngineHttpRawUriTest05); - UtRegisterTest("DetectEngineHttpRawUriTest06", - DetectEngineHttpRawUriTest06); - UtRegisterTest("DetectEngineHttpRawUriTest07", - DetectEngineHttpRawUriTest07); - UtRegisterTest("DetectEngineHttpRawUriTest08", - DetectEngineHttpRawUriTest08); - UtRegisterTest("DetectEngineHttpRawUriTest09", - DetectEngineHttpRawUriTest09); - UtRegisterTest("DetectEngineHttpRawUriTest10", - DetectEngineHttpRawUriTest10); - UtRegisterTest("DetectEngineHttpRawUriTest11", - DetectEngineHttpRawUriTest11); - UtRegisterTest("DetectEngineHttpRawUriTest12", - DetectEngineHttpRawUriTest12); - UtRegisterTest("DetectEngineHttpRawUriTest13", - DetectEngineHttpRawUriTest13); - UtRegisterTest("DetectEngineHttpRawUriTest14", - DetectEngineHttpRawUriTest14); - UtRegisterTest("DetectEngineHttpRawUriTest15", - DetectEngineHttpRawUriTest15); - UtRegisterTest("DetectEngineHttpRawUriTest16", - DetectEngineHttpRawUriTest16); - UtRegisterTest("DetectEngineHttpRawUriTest21", - DetectEngineHttpRawUriTest21); - UtRegisterTest("DetectEngineHttpRawUriTest22", - DetectEngineHttpRawUriTest22); - UtRegisterTest("DetectEngineHttpRawUriTest23", - DetectEngineHttpRawUriTest23); - UtRegisterTest("DetectEngineHttpRawUriTest24", - DetectEngineHttpRawUriTest24); - UtRegisterTest("DetectEngineHttpRawUriTest25", - DetectEngineHttpRawUriTest25); - UtRegisterTest("DetectEngineHttpRawUriTest26", - DetectEngineHttpRawUriTest26); - UtRegisterTest("DetectEngineHttpRawUriTest27", - DetectEngineHttpRawUriTest27); - UtRegisterTest("DetectEngineHttpRawUriTest28", - DetectEngineHttpRawUriTest28); - UtRegisterTest("DetectEngineHttpRawUriTest29", - DetectEngineHttpRawUriTest29); - UtRegisterTest("DetectEngineHttpRawUriTest30", - DetectEngineHttpRawUriTest30); + UtRegisterTest("DetectHttpUriIsdataatParseTest", DetectHttpUriIsdataatParseTest); + + UtRegisterTest("DetectEngineHttpRawUriTest01", DetectEngineHttpRawUriTest01); + UtRegisterTest("DetectEngineHttpRawUriTest02", DetectEngineHttpRawUriTest02); + UtRegisterTest("DetectEngineHttpRawUriTest03", DetectEngineHttpRawUriTest03); + UtRegisterTest("DetectEngineHttpRawUriTest04", DetectEngineHttpRawUriTest04); + UtRegisterTest("DetectEngineHttpRawUriTest05", DetectEngineHttpRawUriTest05); + UtRegisterTest("DetectEngineHttpRawUriTest06", DetectEngineHttpRawUriTest06); + UtRegisterTest("DetectEngineHttpRawUriTest07", DetectEngineHttpRawUriTest07); + UtRegisterTest("DetectEngineHttpRawUriTest08", DetectEngineHttpRawUriTest08); + UtRegisterTest("DetectEngineHttpRawUriTest09", DetectEngineHttpRawUriTest09); + UtRegisterTest("DetectEngineHttpRawUriTest10", DetectEngineHttpRawUriTest10); + UtRegisterTest("DetectEngineHttpRawUriTest11", DetectEngineHttpRawUriTest11); + UtRegisterTest("DetectEngineHttpRawUriTest12", DetectEngineHttpRawUriTest12); + UtRegisterTest("DetectEngineHttpRawUriTest13", DetectEngineHttpRawUriTest13); + UtRegisterTest("DetectEngineHttpRawUriTest14", DetectEngineHttpRawUriTest14); + UtRegisterTest("DetectEngineHttpRawUriTest15", DetectEngineHttpRawUriTest15); + UtRegisterTest("DetectEngineHttpRawUriTest16", DetectEngineHttpRawUriTest16); + UtRegisterTest("DetectEngineHttpRawUriTest21", DetectEngineHttpRawUriTest21); + UtRegisterTest("DetectEngineHttpRawUriTest22", DetectEngineHttpRawUriTest22); + UtRegisterTest("DetectEngineHttpRawUriTest23", DetectEngineHttpRawUriTest23); + UtRegisterTest("DetectEngineHttpRawUriTest24", DetectEngineHttpRawUriTest24); + UtRegisterTest("DetectEngineHttpRawUriTest25", DetectEngineHttpRawUriTest25); + UtRegisterTest("DetectEngineHttpRawUriTest26", DetectEngineHttpRawUriTest26); + UtRegisterTest("DetectEngineHttpRawUriTest27", DetectEngineHttpRawUriTest27); + UtRegisterTest("DetectEngineHttpRawUriTest28", DetectEngineHttpRawUriTest28); + UtRegisterTest("DetectEngineHttpRawUriTest29", DetectEngineHttpRawUriTest29); + UtRegisterTest("DetectEngineHttpRawUriTest30", DetectEngineHttpRawUriTest30); } diff --git a/src/tests/detect-http-user-agent.c b/src/tests/detect-http-user-agent.c index df9c9c169717..9342127b47b9 100644 --- a/src/tests/detect-http-user-agent.c +++ b/src/tests/detect-http-user-agent.c @@ -21,7 +21,6 @@ * @{ */ - /** \file * * \author Anoop Saldanha @@ -36,10 +35,10 @@ #include "flow-util.h" #include "flow.h" #include "app-layer-parser.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "app-layer-protos.h" #include "detect-engine-build.h" #include "detect-engine-alert.h" @@ -69,7 +68,7 @@ static int DetectEngineHttpUATest( p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -432,12 +431,11 @@ static int DetectHttpUATest06(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: This is dummy message body\r\n" - "Content-Type: text/html\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -505,12 +503,10 @@ static int DetectHttpUATest07(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: This is dummy message"; - uint8_t http2_buf[] = - "body1\r\n\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy message"; + uint8_t http2_buf[] = "body1\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -530,11 +526,11 @@ static int DetectHttpUATest07(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -593,12 +589,10 @@ static int DetectHttpUATest08(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: This is dummy mess"; - uint8_t http2_buf[] = - "age body\r\n\r\n"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy mess"; + uint8_t http2_buf[] = "age body\r\n\r\n"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -618,11 +612,11 @@ static int DetectHttpUATest08(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -681,16 +675,14 @@ static int DetectHttpUATest09(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy body1"; + uint8_t http2_buf[] = "This is dummy message body2\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -710,11 +702,11 @@ static int DetectHttpUATest09(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -772,16 +764,14 @@ static int DetectHttpUATest10(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: This is dummy bodY1"; - uint8_t http2_buf[] = - "This is dummy message body2\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy bodY1"; + uint8_t http1_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy bodY1"; + uint8_t http2_buf[] = "This is dummy message body2\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy bodY1"; uint32_t http1_len = sizeof(http1_buf) - 1; uint32_t http2_len = sizeof(http2_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -801,11 +791,11 @@ static int DetectHttpUATest10(void) p1->flow = &f; p1->flowflags |= FLOW_PKT_TOSERVER; p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2->flow = &f; p2->flowflags |= FLOW_PKT_TOSERVER; p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -861,12 +851,11 @@ static int DetectHttpUATest11(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: This is dummy message body\r\n" - "Content-Type: text/html\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -884,7 +873,7 @@ static int DetectHttpUATest11(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -931,11 +920,10 @@ static int DetectHttpUATest12(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: This is dummy body\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy body\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -953,7 +941,7 @@ static int DetectHttpUATest12(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1000,12 +988,11 @@ static int DetectHttpUATest13(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" - "Content-Type: text/html\r\n" - "\r\n"; + uint8_t http_buf[] = "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: longbufferabcdefghijklmnopqrstuvwxyz0123456789bufferend\r\n" + "Content-Type: text/html\r\n" + "\r\n"; uint32_t http_len = sizeof(http_buf) - 1; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1023,7 +1010,7 @@ static int DetectHttpUATest13(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1099,7 +1086,7 @@ static int DetectHttpUATest14(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -1108,9 +1095,13 @@ static int DetectHttpUATest14(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; http_cookie; content:\"Body one\"; http_user_agent; sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy1\"; " + "http_cookie; content:\"Body one\"; http_user_agent; sid:1; rev:1;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; http_cookie; content:\"Body two\"; http_user_agent; sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"dummy2\"; " + "http_cookie; content:\"Body two\"; http_user_agent; sid:2; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); diff --git a/src/tests/detect-http2.c b/src/tests/detect-http2.c index 2ce1bd448162..5e37ecff793b 100644 --- a/src/tests/detect-http2.c +++ b/src/tests/detect-http2.c @@ -19,21 +19,21 @@ #include "../detect-engine.h" -#include "../detect-http2.h" +#include "../app-layer/http2/detect.h" -#include "../util-unittest.h" +#include "../util/unittest.h" /** * \test signature with a valid http2.frametype value. */ -static int DetectHTTP2frameTypeParseTest01 (void) +static int DetectHTTP2frameTypeParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert http2 any any -> any any (http2.frametype:GOAWAY; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert http2 any any -> any any (http2.frametype:GOAWAY; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -52,13 +52,13 @@ void DetectHTTP2frameTypeRegisterTests(void) * \test signature with a valid http2.errorcode value. */ -static int DetectHTTP2errorCodeParseTest01 (void) +static int DetectHTTP2errorCodeParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert http2 any any -> any any (http2.errorcode:NO_ERROR; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert http2 any any -> any any (http2.errorcode:NO_ERROR; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -74,13 +74,13 @@ void DetectHTTP2errorCodeRegisterTests(void) * \test signature with a valid http2.priority value. */ -static int DetectHTTP2priorityParseTest01 (void) +static int DetectHTTP2priorityParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert http2 any any -> any any (http2.priority:>100; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert http2 any any -> any any (http2.priority:>100; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -96,13 +96,13 @@ void DetectHTTP2priorityRegisterTests(void) * \test signature with a valid http2.window value. */ -static int DetectHTTP2windowParseTest01 (void) +static int DetectHTTP2windowParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert http2 any any -> any any (http2.window:<42; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert http2 any any -> any any (http2.window:<42; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -114,18 +114,18 @@ void DetectHTTP2windowRegisterTests(void) UtRegisterTest("DetectHTTP2windowParseTest01", DetectHTTP2windowParseTest01); } - /** * \test signature with a valid http2.settings value. */ -static int DetectHTTP2settingsParseTest01 (void) +static int DetectHTTP2settingsParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); Signature *sig = DetectEngineAppendSig(de_ctx, - "alert http2 any any -> any any (http2.settings:SETTINGS_MAX_HEADER_LIST_SIZE >1024; sid:1; rev:1;)"); + "alert http2 any any -> any any (http2.settings:SETTINGS_MAX_HEADER_LIST_SIZE " + ">1024; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -137,18 +137,17 @@ void DetectHTTP2settingsRegisterTests(void) UtRegisterTest("DetectHTTP2settingsParseTest01", DetectHTTP2settingsParseTest01); } - /** -* \test signature with a valid http2.size_update value. -*/ + * \test signature with a valid http2.size_update value. + */ -static int DetectHTTP2sizeUpdateParseTest01 (void) +static int DetectHTTP2sizeUpdateParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert http2 any any -> any any (http2.size_update:>4096; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert http2 any any -> any any (http2.size_update:>4096; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect-icmpv4hdr.c b/src/tests/detect-icmpv4hdr.c index 7617d805a907..465ac441883e 100644 --- a/src/tests/detect-icmpv4hdr.c +++ b/src/tests/detect-icmpv4hdr.c @@ -22,7 +22,7 @@ #include "../detect-icmpv4hdr.h" -#include "../util-unittest.h" +#include "../util/unittest.h" static int DetectIcmpv4HdrParseTest01(void) { diff --git a/src/tests/detect-icmpv6-mtu.c b/src/tests/detect-icmpv6-mtu.c index 241a221d7231..7c5f36b9bc69 100644 --- a/src/tests/detect-icmpv6-mtu.c +++ b/src/tests/detect-icmpv6-mtu.c @@ -21,24 +21,23 @@ #include "../detect-icmpv6-mtu.h" -#include "../util-unittest.h" +#include "../util/unittest.h" /** * \test signature with a valid icmpv6.mtu value. */ -static int DetectICMPv6mtuParseTest01 (void) +static int DetectICMPv6mtuParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (icmpv6.mtu:<1280; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (icmpv6.mtu:<1280; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); PASS; - } /** diff --git a/src/tests/detect-icmpv6hdr.c b/src/tests/detect-icmpv6hdr.c index 84292a45b59b..d4226c2b9cc6 100644 --- a/src/tests/detect-icmpv6hdr.c +++ b/src/tests/detect-icmpv6hdr.c @@ -23,15 +23,15 @@ #include "../detect-icmpv6hdr.h" -#include "../util-unittest.h" +#include "../util/unittest.h" -static int DetectICMPv6hdrParseTest01 (void) +static int DetectICMPv6hdrParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (icmpv6.hdr; content:\"A\"; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (icmpv6.hdr; content:\"A\"; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect-ipaddr.c b/src/tests/detect-ipaddr.c index 712aac73818e..d3cc5c92138e 100644 --- a/src/tests/detect-ipaddr.c +++ b/src/tests/detect-ipaddr.c @@ -23,7 +23,7 @@ #include "../detect-ipaddr.h" -#include "../util-unittest.h" +#include "../util/unittest.h" static int DetectIPAddrParseTest01(void) { diff --git a/src/tests/detect-ipv4hdr.c b/src/tests/detect-ipv4hdr.c index f86047e2ee45..87a10ed3b941 100644 --- a/src/tests/detect-ipv4hdr.c +++ b/src/tests/detect-ipv4hdr.c @@ -23,15 +23,15 @@ #include "../detect-ipv4hdr.h" -#include "../util-unittest.h" +#include "../util/unittest.h" -static int DetectIpv4hdrParseTest01 (void) +static int DetectIpv4hdrParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (ipv4.hdr; content:\"A\"; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (ipv4.hdr; content:\"A\"; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect-ipv6hdr.c b/src/tests/detect-ipv6hdr.c index 1373ad7b5cfc..d4cac789b544 100644 --- a/src/tests/detect-ipv6hdr.c +++ b/src/tests/detect-ipv6hdr.c @@ -23,15 +23,15 @@ #include "../detect-ipv6hdr.h" -#include "../util-unittest.h" +#include "../util/unittest.h" -static int DetectIpv6hdrParseTest01 (void) +static int DetectIpv6hdrParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert ip any any -> any any (ipv6.hdr; content:\"A\"; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (ipv6.hdr; content:\"A\"; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect-parse.c b/src/tests/detect-parse.c index 694e2ae236d2..4ba975a77332 100644 --- a/src/tests/detect-parse.c +++ b/src/tests/detect-parse.c @@ -18,9 +18,9 @@ #include "../detect.h" #include "../detect-parse.h" #include "../detect-engine-port.h" -#include "../util-unittest.h" -#include "util-debug.h" -#include "util-error.h" +#include "../util/unittest.h" +#include "util/debug.h" +#include "util/error.h" /** * \test DetectParseTest01 is a regression test against a memory leak @@ -28,13 +28,17 @@ * Leak happened in function DetectEngineSignatureIsDuplicate */ -static int DetectParseTest01 (void) +static int DetectParseTest01(void) { - DetectEngineCtx * de_ctx = DetectEngineCtxInit(); - FAIL_IF(DetectEngineAppendSig(de_ctx, "alert http any any -> any any (msg:\"sid 1 version 0\"; content:\"dummy1\"; sid:1;)") == NULL); - DetectEngineAppendSig(de_ctx, "alert http any any -> any any (msg:\"sid 2 version 0\"; content:\"dummy2\"; sid:2;)"); - DetectEngineAppendSig(de_ctx, "alert http any any -> any any (msg:\"sid 1 version 1\"; content:\"dummy1.1\"; sid:1; rev:1;)"); - DetectEngineAppendSig(de_ctx, "alert http any any -> any any (msg:\"sid 2 version 2\"; content:\"dummy2.1\"; sid:2; rev:1;)"); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(DetectEngineAppendSig(de_ctx, "alert http any any -> any any (msg:\"sid 1 version 0\"; " + "content:\"dummy1\"; sid:1;)") == NULL); + DetectEngineAppendSig(de_ctx, + "alert http any any -> any any (msg:\"sid 2 version 0\"; content:\"dummy2\"; sid:2;)"); + DetectEngineAppendSig(de_ctx, "alert http any any -> any any (msg:\"sid 1 version 1\"; " + "content:\"dummy1.1\"; sid:1; rev:1;)"); + DetectEngineAppendSig(de_ctx, "alert http any any -> any any (msg:\"sid 2 version 2\"; " + "content:\"dummy2.1\"; sid:2; rev:1;)"); FAIL_IF(de_ctx->sig_list->next == NULL); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect-snmp-community.c b/src/tests/detect-snmp-community.c index 1eda88385c47..8dca86c0a94e 100644 --- a/src/tests/detect-snmp-community.c +++ b/src/tests/detect-snmp-community.c @@ -15,8 +15,8 @@ * 02110-1301, USA. */ -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" #include "app-layer-parser.h" #include "detect-engine.h" #include "detect-parse.h" @@ -36,6 +36,7 @@ static int DetectSNMPCommunityTest(void) ThreadVars tv; Signature *s; + // clang-format off uint8_t request[] = { 0x30, 0x27, 0x02, 0x01, 0x01, 0x04, 0x0b, 0x5b, 0x52, 0x30, 0x5f, 0x43, 0x40, 0x63, 0x74, 0x69, @@ -44,6 +45,7 @@ static int DetectSNMPCommunityTest(void) 0x30, 0x07, 0x30, 0x05, 0x06, 0x01, 0x01, 0x05, 0x00 }; + // clang-format on /* Setup flow. */ memset(&f, 0, sizeof(Flow)); @@ -65,26 +67,24 @@ static int DetectSNMPCommunityTest(void) FAIL_IF_NULL(de_ctx); /* This rule should match. */ - s = DetectEngineAppendSig(de_ctx, - "alert snmp any any -> any any (" - "msg:\"SNMP Test Rule\"; " - "snmp.community; content:\"[R0_C@cti!]\"; " - "sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert snmp any any -> any any (" + "msg:\"SNMP Test Rule\"; " + "snmp.community; content:\"[R0_C@cti!]\"; " + "sid:1; rev:1;)"); FAIL_IF_NULL(s); /* This rule should not match. */ - s = DetectEngineAppendSig(de_ctx, - "alert snmp any any -> any any (" - "msg:\"SNMP Test Rule\"; " - "snmp.community; content:\"private\"; " - "sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert snmp any any -> any any (" + "msg:\"SNMP Test Rule\"; " + "snmp.community; content:\"private\"; " + "sid:2; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SNMP, - STREAM_TOSERVER, request, sizeof(request)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_SNMP, STREAM_TOSERVER, request, sizeof(request)); FAIL_IF(r != 0); /* Check that we have app-layer state. */ @@ -108,6 +108,5 @@ static int DetectSNMPCommunityTest(void) static void DetectSNMPCommunityRegisterTests(void) { - UtRegisterTest("DetectSNMPCommunityTest", - DetectSNMPCommunityTest); + UtRegisterTest("DetectSNMPCommunityTest", DetectSNMPCommunityTest); } diff --git a/src/tests/detect-snmp-pdu_type.c b/src/tests/detect-snmp-pdu_type.c index 0e7693bcc625..516ab281562b 100644 --- a/src/tests/detect-snmp-pdu_type.c +++ b/src/tests/detect-snmp-pdu_type.c @@ -15,8 +15,8 @@ * 02110-1301, USA. */ -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" /** * \test This is a test for a valid value 2. @@ -24,7 +24,7 @@ * \retval 1 on success. * \retval 0 on failure. */ -static int SNMPValidityTestParse01 (void) +static int SNMPValidityTestParse01(void) { DetectSNMPPduTypeData *dd = NULL; dd = DetectSNMPPduTypeParse("2"); diff --git a/src/tests/detect-snmp-version.c b/src/tests/detect-snmp-version.c index 5da24b1b8700..ee10544a3b69 100644 --- a/src/tests/detect-snmp-version.c +++ b/src/tests/detect-snmp-version.c @@ -15,8 +15,8 @@ * 02110-1301, USA. */ -#include "util-unittest.h" -#include "util-unittest-helper.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" /** * \test This is a test for a valid value 2. @@ -24,7 +24,7 @@ * \retval 1 on success. * \retval 0 on failure. */ -static int SNMPValidityTestParse01 (void) +static int SNMPValidityTestParse01(void) { DetectU32Data *dd = NULL; dd = DetectSNMPVersionParse("2"); @@ -40,7 +40,7 @@ static int SNMPValidityTestParse01 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int SNMPValidityTestParse02 (void) +static int SNMPValidityTestParse02(void) { DetectU32Data *dd = NULL; dd = DetectSNMPVersionParse(">2"); diff --git a/src/tests/detect-ssl-state.c b/src/tests/detect-ssl-state.c index 6be8ea8d89b9..2e9e5bc7ca7d 100644 --- a/src/tests/detect-ssl-state.c +++ b/src/tests/detect-ssl-state.c @@ -37,8 +37,7 @@ static int DetectSslStateTest02(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_hello"); FAIL_IF_NULL(ssd); - FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | - DETECT_SSL_STATE_CLIENT_HELLO)); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_HELLO)); SCFree(ssd); PASS; } @@ -48,9 +47,8 @@ static int DetectSslStateTest03(void) DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello"); FAIL_IF_NULL(ssd); - FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | - DETECT_SSL_STATE_CLIENT_KEYX | - DETECT_SSL_STATE_CLIENT_HELLO)); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | + DETECT_SSL_STATE_CLIENT_HELLO)); SCFree(ssd); PASS; } @@ -61,11 +59,9 @@ static int DetectSslStateTest04(void) "client_hello , server_keyx , " "unknown"); FAIL_IF_NULL(ssd); - FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | - DETECT_SSL_STATE_CLIENT_KEYX | - DETECT_SSL_STATE_CLIENT_HELLO | - DETECT_SSL_STATE_SERVER_KEYX | - DETECT_SSL_STATE_UNKNOWN)); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | + DETECT_SSL_STATE_CLIENT_HELLO | DETECT_SSL_STATE_SERVER_KEYX | + DETECT_SSL_STATE_UNKNOWN)); SCFree(ssd); PASS; } @@ -97,8 +93,7 @@ static int DetectSslStateTest08(void) { DetectSslStateData *ssd = DetectSslStateParse("server_hello|client_hello"); FAIL_IF_NULL(ssd); - FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | - DETECT_SSL_STATE_CLIENT_HELLO)); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_HELLO)); SCFree(ssd); PASS; } @@ -132,6 +127,5 @@ static void DetectSslStateRegisterTests(void) UtRegisterTest("DetectSslStateTest05", DetectSslStateTest05); UtRegisterTest("DetectSslStateTest06", DetectSslStateTest06); UtRegisterTest("DetectSslStateTest08", DetectSslStateTest08); - UtRegisterTest("DetectSslStateTestParseNegate", - DetectSslStateTestParseNegate); + UtRegisterTest("DetectSslStateTestParseNegate", DetectSslStateTestParseNegate); } diff --git a/src/tests/detect-tcphdr.c b/src/tests/detect-tcphdr.c index 6faa0d716f2f..9bcf075e7e9b 100644 --- a/src/tests/detect-tcphdr.c +++ b/src/tests/detect-tcphdr.c @@ -23,15 +23,15 @@ #include "../detect-tcphdr.h" -#include "../util-unittest.h" +#include "../util/unittest.h" -static int DetectTcphdrParseTest01 (void) +static int DetectTcphdrParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (tcp.hdr; content:\"A\"; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (tcp.hdr; content:\"A\"; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect-template-buffer.c b/src/tests/detect-template-buffer.c index 7e04025a96da..4e6ecbf7b183 100644 --- a/src/tests/detect-template-buffer.c +++ b/src/tests/detect-template-buffer.c @@ -15,8 +15,8 @@ * 02110-1301, USA. */ -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" #include "../app-layer-parser.h" #include "../detect-engine.h" #include "../detect-parse.h" @@ -56,19 +56,17 @@ static int DetectTemplateBufferTest(void) FAIL_IF_NULL(de_ctx); /* This rule should match. */ - s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (" - "msg:\"TEMPLATE Test Rule\"; " - "template_buffer; content:\"World!\"; " - "sid:1; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"World!\"; " + "sid:1; rev:1;)"); FAIL_IF_NULL(s); /* This rule should not match. */ - s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (" - "msg:\"TEMPLATE Test Rule\"; " - "template_buffer; content:\"W0rld!\"; " - "sid:2; rev:1;)"); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"W0rld!\"; " + "sid:2; rev:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -77,8 +75,8 @@ static int DetectTemplateBufferTest(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); FAIL_IF_NULL(det_ctx); - AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TEMPLATE, - STREAM_TOSERVER, request, sizeof(request)); + AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, request, sizeof(request)); /* Check that we have app-layer state. */ FAIL_IF_NULL(f.alstate); diff --git a/src/tests/detect-template.c b/src/tests/detect-template.c index c91a463b19c1..d27d2a774e46 100644 --- a/src/tests/detect-template.c +++ b/src/tests/detect-template.c @@ -16,18 +16,18 @@ */ #include "../suricata-common.h" -#include "../util-unittest.h" +#include "../util/unittest.h" #include "../detect-parse.h" #include "../detect-engine.h" -#include "../detect-template.h" +#include "../app-layer/template/detect.h" /** * \test test keyword parsing */ -static int DetectTemplateParseTest01 (void) +static int DetectTemplateParseTest01(void) { DetectTemplateData *templated = DetectTemplateParse("1,10"); FAIL_IF_NULL(templated); @@ -40,12 +40,13 @@ static int DetectTemplateParseTest01 (void) * \test test signature parsing */ -static int DetectTemplateSignatureTest01 (void) +static int DetectTemplateSignatureTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (template:1,10; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (template:1,10; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -58,6 +59,5 @@ static int DetectTemplateSignatureTest01 (void) void DetectTemplateRegisterTests(void) { UtRegisterTest("DetectTemplateParseTest01", DetectTemplateParseTest01); - UtRegisterTest("DetectTemplateSignatureTest01", - DetectTemplateSignatureTest01); + UtRegisterTest("DetectTemplateSignatureTest01", DetectTemplateSignatureTest01); } diff --git a/src/tests/detect-tls-cert-fingerprint.c b/src/tests/detect-tls-cert-fingerprint.c index e2ec3d5f26d9..f5be89483718 100644 --- a/src/tests/detect-tls-cert-fingerprint.c +++ b/src/tests/detect-tls-cert-fingerprint.c @@ -64,6 +64,7 @@ static int DetectTlsFingerprintTest01(void) static int DetectTlsFingerprintTest02(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, @@ -92,8 +93,10 @@ static int DetectTlsFingerprintTest02(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, @@ -106,8 +109,10 @@ static int DetectTlsFingerprintTest02(void) 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, @@ -257,6 +262,7 @@ static int DetectTlsFingerprintTest02(void) 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -272,12 +278,12 @@ static int DetectTlsFingerprintTest02(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -311,19 +317,19 @@ static int DetectTlsFingerprintTest02(void) de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls.cert_fingerprint\"; " - "tls.cert_fingerprint; " - "content:\"4a:a3:66:76:82:cb:6b:23:bb:c3:58:47:23:a4:63:a7:78:a4:a1:18\"; " - "sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tls any any -> any any " + "(msg:\"Test tls.cert_fingerprint\"; " + "tls.cert_fingerprint; " + "content:\"4a:a3:66:76:82:cb:6b:23:bb:c3:58:47:23:a4:63:a7:78:a4:a1:18\"; " + "sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, - STREAM_TOSERVER, client_hello, - sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -334,8 +340,8 @@ static int DetectTlsFingerprintTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -343,8 +349,8 @@ static int DetectTlsFingerprintTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); diff --git a/src/tests/detect-tls-cert-issuer.c b/src/tests/detect-tls-cert-issuer.c index feaa70b3d6d8..ad965ad32586 100644 --- a/src/tests/detect-tls-cert-issuer.c +++ b/src/tests/detect-tls-cert-issuer.c @@ -64,6 +64,7 @@ static int DetectTlsIssuerTest01(void) static int DetectTlsIssuerTest02(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, @@ -92,8 +93,10 @@ static int DetectTlsIssuerTest02(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, @@ -106,8 +109,10 @@ static int DetectTlsIssuerTest02(void) 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, @@ -257,6 +262,7 @@ static int DetectTlsIssuerTest02(void) 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -272,12 +278,12 @@ static int DetectTlsIssuerTest02(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -312,17 +318,16 @@ static int DetectTlsIssuerTest02(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls.cert_issuer\"; " - "tls.cert_issuer; content:\"google\"; nocase; " - "sid:1;)"); + "(msg:\"Test tls.cert_issuer\"; " + "tls.cert_issuer; content:\"google\"; nocase; " + "sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, - STREAM_TOSERVER, client_hello, - sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -333,8 +338,8 @@ static int DetectTlsIssuerTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -342,8 +347,8 @@ static int DetectTlsIssuerTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); diff --git a/src/tests/detect-tls-cert-serial.c b/src/tests/detect-tls-cert-serial.c index 119d94a7eb3f..6126e0ec8365 100644 --- a/src/tests/detect-tls-cert-serial.c +++ b/src/tests/detect-tls-cert-serial.c @@ -61,6 +61,7 @@ static int DetectTlsSerialTest01(void) static int DetectTlsSerialTest02(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, @@ -89,8 +90,10 @@ static int DetectTlsSerialTest02(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, @@ -103,8 +106,10 @@ static int DetectTlsSerialTest02(void) 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, @@ -254,6 +259,7 @@ static int DetectTlsSerialTest02(void) 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -269,12 +275,12 @@ static int DetectTlsSerialTest02(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -309,18 +315,17 @@ static int DetectTlsSerialTest02(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls.cert_serial\"; " - "tls.cert_serial; " - "content:\"5C:19:B7:B1:32:3B:1C:A1\"; " - "sid:1;)"); + "(msg:\"Test tls.cert_serial\"; " + "tls.cert_serial; " + "content:\"5C:19:B7:B1:32:3B:1C:A1\"; " + "sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, - STREAM_TOSERVER, client_hello, - sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -331,8 +336,8 @@ static int DetectTlsSerialTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -340,8 +345,8 @@ static int DetectTlsSerialTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); diff --git a/src/tests/detect-tls-cert-subject.c b/src/tests/detect-tls-cert-subject.c index 2df23eb7f6a5..97f45345bd41 100644 --- a/src/tests/detect-tls-cert-subject.c +++ b/src/tests/detect-tls-cert-subject.c @@ -64,6 +64,7 @@ static int DetectTlsSubjectTest01(void) static int DetectTlsSubjectTest02(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, @@ -92,8 +93,10 @@ static int DetectTlsSubjectTest02(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, @@ -106,8 +109,10 @@ static int DetectTlsSubjectTest02(void) 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, @@ -257,6 +262,7 @@ static int DetectTlsSubjectTest02(void) 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -272,12 +278,12 @@ static int DetectTlsSubjectTest02(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -312,17 +318,16 @@ static int DetectTlsSubjectTest02(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls.cert_subject\"; " - "tls.cert_subject; content:\"google\"; nocase; " - "sid:1;)"); + "(msg:\"Test tls.cert_subject\"; " + "tls.cert_subject; content:\"google\"; nocase; " + "sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, - STREAM_TOSERVER, client_hello, - sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -333,8 +338,8 @@ static int DetectTlsSubjectTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -342,8 +347,8 @@ static int DetectTlsSubjectTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); diff --git a/src/tests/detect-tls-cert-validity.c b/src/tests/detect-tls-cert-validity.c index 6383e2b3e91d..a7b28a191159 100644 --- a/src/tests/detect-tls-cert-validity.c +++ b/src/tests/detect-tls-cert-validity.c @@ -32,7 +32,7 @@ * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse01 (void) +static int ValidityTestParse01(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("1430000000"); @@ -48,7 +48,7 @@ static int ValidityTestParse01 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse02 (void) +static int ValidityTestParse02(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse(">1430000000"); @@ -64,7 +64,7 @@ static int ValidityTestParse02 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse03 (void) +static int ValidityTestParse03(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("<1430000000"); @@ -80,7 +80,7 @@ static int ValidityTestParse03 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse04 (void) +static int ValidityTestParse04(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("1430000000<>1470000000"); @@ -97,7 +97,7 @@ static int ValidityTestParse04 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse05 (void) +static int ValidityTestParse05(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("A"); @@ -111,7 +111,7 @@ static int ValidityTestParse05 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse06 (void) +static int ValidityTestParse06(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse(">1430000000<>1470000000"); @@ -125,7 +125,7 @@ static int ValidityTestParse06 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse07 (void) +static int ValidityTestParse07(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("1430000000<>"); @@ -139,7 +139,7 @@ static int ValidityTestParse07 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse08 (void) +static int ValidityTestParse08(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("<>1430000000"); @@ -153,7 +153,7 @@ static int ValidityTestParse08 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse09 (void) +static int ValidityTestParse09(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse(""); @@ -167,7 +167,7 @@ static int ValidityTestParse09 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse10 (void) +static int ValidityTestParse10(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse(" "); @@ -181,7 +181,7 @@ static int ValidityTestParse10 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse11 (void) +static int ValidityTestParse11(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("1490000000<>1430000000"); @@ -195,7 +195,7 @@ static int ValidityTestParse11 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse12 (void) +static int ValidityTestParse12(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("1430000000 <> 1490000000"); @@ -212,7 +212,7 @@ static int ValidityTestParse12 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse13 (void) +static int ValidityTestParse13(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("> 1430000000 "); @@ -228,7 +228,7 @@ static int ValidityTestParse13 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse14 (void) +static int ValidityTestParse14(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("< 1490000000 "); @@ -244,7 +244,7 @@ static int ValidityTestParse14 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse15 (void) +static int ValidityTestParse15(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse(" 1490000000 "); @@ -260,7 +260,7 @@ static int ValidityTestParse15 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse16 (void) +static int ValidityTestParse16(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("2015-10"); @@ -276,7 +276,7 @@ static int ValidityTestParse16 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse17 (void) +static int ValidityTestParse17(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse(">2015-10-22"); @@ -292,7 +292,7 @@ static int ValidityTestParse17 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse18 (void) +static int ValidityTestParse18(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("<2015-10-22 23"); @@ -308,7 +308,7 @@ static int ValidityTestParse18 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse19 (void) +static int ValidityTestParse19(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("2015-10-22 23:59"); @@ -324,7 +324,7 @@ static int ValidityTestParse19 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse20 (void) +static int ValidityTestParse20(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("2015-10-22 23:59:59"); @@ -340,7 +340,7 @@ static int ValidityTestParse20 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse21 (void) +static int ValidityTestParse21(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("2015-10-22T23"); @@ -356,7 +356,7 @@ static int ValidityTestParse21 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse22 (void) +static int ValidityTestParse22(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("2015-10-22T23:59"); @@ -372,7 +372,7 @@ static int ValidityTestParse22 (void) * \retval 1 on success. * \retval 0 on failure. */ -static int ValidityTestParse23 (void) +static int ValidityTestParse23(void) { DetectTlsValidityData *dd = NULL; dd = DetectTlsValidityParse("2015-10-22T23:59:59"); @@ -428,6 +428,7 @@ static int ValidityTestParse25(void) static int ValidityTestDetect01(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, @@ -456,8 +457,10 @@ static int ValidityTestDetect01(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, @@ -470,8 +473,10 @@ static int ValidityTestDetect01(void) 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, @@ -621,6 +626,7 @@ static int ValidityTestDetect01(void) 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -636,12 +642,12 @@ static int ValidityTestDetect01(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -675,21 +681,20 @@ static int ValidityTestDetect01(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls_cert_notbefore\"; " - "tls_cert_notbefore:<2016-07-20; sid:1;)"); + "(msg:\"Test tls_cert_notbefore\"; " + "tls_cert_notbefore:<2016-07-20; sid:1;)"); FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls_cert_notafter\"; " - "tls_cert_notafter:>2016-09-01; sid:2;)"); + "(msg:\"Test tls_cert_notafter\"; " + "tls_cert_notafter:>2016-09-01; sid:2;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, - STREAM_TOSERVER, client_hello, - sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -701,8 +706,8 @@ static int ValidityTestDetect01(void) FAIL_IF(PacketAlertCheck(p1, 1)); FAIL_IF(PacketAlertCheck(p1, 2)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -711,8 +716,8 @@ static int ValidityTestDetect01(void) FAIL_IF(PacketAlertCheck(p2, 1)); FAIL_IF(PacketAlertCheck(p2, 2)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); @@ -745,6 +750,7 @@ static int ValidityTestDetect01(void) static int ExpiredTestDetect01(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x5a, 0x01, 0x00, 0x00, 0x56, 0x03, 0x03, 0x62, 0x87, 0xa4, 0x11, 0x3e, @@ -759,8 +765,10 @@ static int ExpiredTestDetect01(void) 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x02, 0x01 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x55, 0x02, 0x00, 0x00, 0x51, 0x03, 0x03, 0x22, 0xa1, 0xd8, 0xd0, 0x3c, @@ -775,8 +783,10 @@ static int ExpiredTestDetect01(void) 0x09, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x05, 0x59, 0x0b, 0x00, 0x05, 0x55, 0x00, 0x05, 0x52, 0x00, 0x05, 0x4f, 0x30, @@ -951,6 +961,7 @@ static int ExpiredTestDetect01(void) 0x0c, 0x4f, 0xbb, 0x36, 0x44, 0x68, 0x56, 0x5c, 0x56, 0x59, 0xad, 0xaa, 0x8a, 0xbc, }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -966,12 +977,12 @@ static int ExpiredTestDetect01(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -1007,15 +1018,15 @@ static int ExpiredTestDetect01(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls_cert_expired\"; " - "tls_cert_expired; sid:1;)"); + "(msg:\"Test tls_cert_expired\"; " + "tls_cert_expired; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, - client_hello, sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -1026,8 +1037,8 @@ static int ExpiredTestDetect01(void) FAIL_IF(PacketAlertCheck(p1, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -1035,8 +1046,8 @@ static int ExpiredTestDetect01(void) FAIL_IF(PacketAlertCheck(p2, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); @@ -1066,6 +1077,7 @@ static int ExpiredTestDetect01(void) static int ValidTestDetect01(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, @@ -1094,8 +1106,10 @@ static int ValidTestDetect01(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, @@ -1108,8 +1122,10 @@ static int ValidTestDetect01(void) 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, @@ -1259,6 +1275,7 @@ static int ValidTestDetect01(void) 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -1274,12 +1291,12 @@ static int ValidTestDetect01(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -1315,15 +1332,15 @@ static int ValidTestDetect01(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls_cert_valid\"; " - "tls_cert_valid; sid:1;)"); + "(msg:\"Test tls_cert_valid\"; " + "tls_cert_valid; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, - client_hello, sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -1334,8 +1351,8 @@ static int ValidTestDetect01(void) FAIL_IF(PacketAlertCheck(p1, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -1343,8 +1360,8 @@ static int ValidTestDetect01(void) FAIL_IF(PacketAlertCheck(p2, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); diff --git a/src/tests/detect-tls-certs.c b/src/tests/detect-tls-certs.c index 19b5436dd9f0..ef96216e2fe3 100644 --- a/src/tests/detect-tls-certs.c +++ b/src/tests/detect-tls-certs.c @@ -60,6 +60,7 @@ static int DetectTlsCertsTest01(void) static int DetectTlsCertsTest02(void) { /* client hello */ + // clang-format off uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, @@ -88,8 +89,10 @@ static int DetectTlsCertsTest02(void) 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x04, 0x02, 0x02, 0x02 }; + // clang-format on /* server hello */ + // clang-format off uint8_t server_hello[] = { 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, @@ -102,8 +105,10 @@ static int DetectTlsCertsTest02(void) 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + // clang-format on /* certificate */ + // clang-format off uint8_t certificate[] = { 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, @@ -253,6 +258,7 @@ static int DetectTlsCertsTest02(void) 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d }; + // clang-format on Flow f; SSLState *ssl_state = NULL; @@ -268,12 +274,12 @@ static int DetectTlsCertsTest02(void) memset(&f, 0, sizeof(Flow)); memset(&ssn, 0, sizeof(TcpSession)); - p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 51251, 443); - p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); - p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, - "192.168.1.1", "192.168.1.5", 443, 51251); + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, "192.168.1.5", + "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, "192.168.1.1", + "192.168.1.5", 443, 51251); FLOW_INITIALIZE(&f); f.flags |= FLOW_IPV4; @@ -308,16 +314,15 @@ static int DetectTlsCertsTest02(void) de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " - "(msg:\"Test tls.certs\"; tls.certs; " - "content:\"|06 09 2a 86 48|\"; sid:1;)"); + "(msg:\"Test tls.certs\"; tls.certs; " + "content:\"|06 09 2a 86 48|\"; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, - STREAM_TOSERVER, client_hello, - sizeof(client_hello)); + int r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, sizeof(client_hello)); FAIL_IF(r != 0); @@ -328,8 +333,8 @@ static int DetectTlsCertsTest02(void) FAIL_IF(PacketAlertCheck(p1, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - server_hello, sizeof(server_hello)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello, sizeof(server_hello)); FAIL_IF(r != 0); @@ -337,8 +342,8 @@ static int DetectTlsCertsTest02(void) FAIL_IF(PacketAlertCheck(p2, 1)); - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, - certificate, sizeof(certificate)); + r = AppLayerParserParse( + NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, certificate, sizeof(certificate)); FAIL_IF(r != 0); diff --git a/src/tests/detect-tls-version.c b/src/tests/detect-tls-version.c index 3f55faa89c0d..9e43b7056ada 100644 --- a/src/tests/detect-tls-version.c +++ b/src/tests/detect-tls-version.c @@ -29,7 +29,7 @@ * \test DetectTlsVersionTestParse01 is a test to make sure that we parse the "id" * option correctly when given valid id option */ -static int DetectTlsVersionTestParse01 (void) +static int DetectTlsVersionTestParse01(void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse(NULL, "1.0"); @@ -44,7 +44,7 @@ static int DetectTlsVersionTestParse01 (void) * option correctly when given an invalid id option * it should return id_d = NULL */ -static int DetectTlsVersionTestParse02 (void) +static int DetectTlsVersionTestParse02(void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse(NULL, "2.5"); diff --git a/src/tests/detect-transform-pcrexform.c b/src/tests/detect-transform-pcrexform.c index be236152681e..6644afc9751e 100644 --- a/src/tests/detect-transform-pcrexform.c +++ b/src/tests/detect-transform-pcrexform.c @@ -21,19 +21,18 @@ #include "../detect-transform-pcrexform.h" -#include "../util-unittest.h" +#include "../util/unittest.h" /** * \test signature with an invalid pcrexform value. */ -static int DetectTransformPcrexformParseTest01 (void) +static int DetectTransformPcrexformParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any <> any 1 pcrexform:\"[\";"); + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any 1 pcrexform:\"[\";"); FAIL_IF_NOT_NULL(sig); DetectEngineCtxFree(de_ctx); @@ -44,13 +43,14 @@ static int DetectTransformPcrexformParseTest01 (void) * \test signature with a valid pcrexform value. */ -static int DetectTransformPcrexformParseTest02 (void) +static int DetectTransformPcrexformParseTest02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); Signature *sig = DetectEngineAppendSig(de_ctx, - "alert http any any -> any any (msg:\"HTTP with pcrexform\"; http.request_line; pcrexform:\"[a-zA-Z]+\\s+(.*)\\s+HTTP\"; content:\"/z4d4kWk.jpg\"; sid:1;)"); + "alert http any any -> any any (msg:\"HTTP with pcrexform\"; http.request_line; " + "pcrexform:\"[a-zA-Z]+\\s+(.*)\\s+HTTP\"; content:\"/z4d4kWk.jpg\"; sid:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect-transform-xor.c b/src/tests/detect-transform-xor.c index 3a73665e7628..88a2809df1dc 100644 --- a/src/tests/detect-transform-xor.c +++ b/src/tests/detect-transform-xor.c @@ -21,7 +21,7 @@ #include "../detect-transform-xor.h" -#include "../util-unittest.h" +#include "../util/unittest.h" /** * \test signature with an invalid xor value. diff --git a/src/tests/detect-ttl.c b/src/tests/detect-ttl.c index 74949313c438..b62872d3d6e7 100644 --- a/src/tests/detect-ttl.c +++ b/src/tests/detect-ttl.c @@ -16,8 +16,8 @@ * 02110-1301, USA. */ -#include "../util-unittest.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/unittest-helper.h" #include "detect-engine.h" #include "detect-engine-alert.h" #include "detect-engine-build.h" @@ -26,7 +26,7 @@ * \test DetectTtlParseTest01 is a test for setting up an valid ttl value. */ -static int DetectTtlParseTest01 (void) +static int DetectTtlParseTest01(void) { DetectU8Data *ttld = DetectU8Parse("10"); FAIL_IF_NULL(ttld); @@ -41,7 +41,7 @@ static int DetectTtlParseTest01 (void) * "<" operator. */ -static int DetectTtlParseTest02 (void) +static int DetectTtlParseTest02(void) { DetectU8Data *ttld = DetectU8Parse("<10"); FAIL_IF_NULL(ttld); @@ -56,7 +56,7 @@ static int DetectTtlParseTest02 (void) * "-" operator. */ -static int DetectTtlParseTest03 (void) +static int DetectTtlParseTest03(void) { DetectU8Data *ttld = DetectU8Parse("1-3"); FAIL_IF_NULL(ttld); @@ -72,7 +72,7 @@ static int DetectTtlParseTest03 (void) * ">" operator and include spaces arround the given values. */ -static int DetectTtlParseTest04 (void) +static int DetectTtlParseTest04(void) { DetectU8Data *ttld = DetectU8Parse(" > 10 "); FAIL_IF_NULL(ttld); @@ -87,7 +87,7 @@ static int DetectTtlParseTest04 (void) * "-" operator and include spaces arround the given values. */ -static int DetectTtlParseTest05 (void) +static int DetectTtlParseTest05(void) { DetectU8Data *ttld = DetectU8Parse(" 1 - 3 "); FAIL_IF_NULL(ttld); @@ -103,7 +103,7 @@ static int DetectTtlParseTest05 (void) * invalid "=" operator and include spaces arround the given values. */ -static int DetectTtlParseTest06 (void) +static int DetectTtlParseTest06(void) { DetectU8Data *ttld = DetectU8Parse(" 1 = 2 "); FAIL_IF_NOT_NULL(ttld); @@ -115,7 +115,7 @@ static int DetectTtlParseTest06 (void) * invalid "<>" operator and include spaces arround the given values. */ -static int DetectTtlParseTest07 (void) +static int DetectTtlParseTest07(void) { DetectU8Data *ttld = DetectU8Parse(" 1<>2 "); FAIL_IF_NOT_NULL(ttld); @@ -178,16 +178,20 @@ static int DetectTtlTestSig1(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx,"alert ip any any -> any any (msg:\"with in ttl limit\"; ttl: >16; sid:1;)"); + s = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (msg:\"with in ttl limit\"; ttl: >16; sid:1;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx,"alert ip any any -> any any (msg:\"Less than 17\"; ttl: <17; sid:2;)"); + s = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (msg:\"Less than 17\"; ttl: <17; sid:2;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx,"alert ip any any -> any any (msg:\"Greater than 5\"; ttl:15; sid:3;)"); + s = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (msg:\"Greater than 5\"; ttl:15; sid:3;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx,"alert ip any any -> any any (msg:\"Equals tcp\"; ttl: 1-30; sid:4;)"); + s = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (msg:\"Equals tcp\"; ttl: 1-30; sid:4;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); diff --git a/src/tests/detect-udphdr.c b/src/tests/detect-udphdr.c index 5e661fb57bc5..e9f47318f5b6 100644 --- a/src/tests/detect-udphdr.c +++ b/src/tests/detect-udphdr.c @@ -23,15 +23,15 @@ #include "../detect-tcphdr.h" -#include "../util-unittest.h" +#include "../util/unittest.h" -static int DetectUdphdrParseTest01 (void) +static int DetectUdphdrParseTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert udp any any -> any any (udp.hdr; content:\"A\"; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert udp any any -> any any (udp.hdr; content:\"A\"; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx); diff --git a/src/tests/detect.c b/src/tests/detect.c index 08bf9997536b..744060d78d4a 100644 --- a/src/tests/detect.c +++ b/src/tests/detect.c @@ -17,7 +17,7 @@ #ifdef UNITTESTS -#include "../app-layer-htp.h" +#include "../app-layer/http/parser.h" #include "../conf-yaml-loader.h" #include "../detect-parse.h" #include "../detect-engine-content-inspection.h" @@ -25,90 +25,90 @@ #include "../pkt-var.h" #include "../flow-util.h" #include "../stream-tcp-reassemble.h" -#include "../util-unittest.h" -#include "../util-var-name.h" -#include "../util-unittest-helper.h" +#include "../util/unittest.h" +#include "../util/var-name.h" +#include "../util/unittest-helper.h" static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "default-log-dir: /var/log/suricata\n" - "\n" - "logging:\n" - "\n" - " default-log-level: debug\n" - "\n" - " default-format: \"<%t> - <%l>\"\n" - "\n" - " default-startup-message: Your IDS has started.\n" - "\n" - " default-output-filter:\n" - "\n" - " output:\n" - "\n" - " - interface: console\n" - " log-level: info\n" - "\n" - " - interface: file\n" - " filename: /var/log/suricata.log\n" - "\n" - " - interface: syslog\n" - " facility: local5\n" - " format: \"%l\"\n" - "\n" - "pfring:\n" - "\n" - " interface: eth0\n" - "\n" - " clusterid: 99\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" - "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" - "\n" - " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" - "\n" - " HTTP_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " SMTP_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " SQL_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " DNS_SERVERS: any\n" - "\n" - " TELNET_SERVERS: any\n" - "\n" - " AIM_SERVERS: any\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"80:81,88\"\n" - "\n" - " SHELLCODE_PORTS: 80\n" - "\n" - " ORACLE_PORTS: 1521\n" - "\n" - " SSH_PORTS: 22\n" - "\n"; - -static int SigTest01 (void) + "%YAML 1.1\n" + "---\n" + "\n" + "default-log-dir: /var/log/suricata\n" + "\n" + "logging:\n" + "\n" + " default-log-level: debug\n" + "\n" + " default-format: \"<%t> - <%l>\"\n" + "\n" + " default-startup-message: Your IDS has started.\n" + "\n" + " default-output-filter:\n" + "\n" + " output:\n" + "\n" + " - interface: console\n" + " log-level: info\n" + "\n" + " - interface: file\n" + " filename: /var/log/suricata.log\n" + "\n" + " - interface: syslog\n" + " facility: local5\n" + " format: \"%l\"\n" + "\n" + "pfring:\n" + "\n" + " interface: eth0\n" + "\n" + " clusterid: 99\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" + "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" + "\n" + " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" + "\n" + " HTTP_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " SMTP_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " SQL_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " DNS_SERVERS: any\n" + "\n" + " TELNET_SERVERS: any\n" + "\n" + " AIM_SERVERS: any\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"80:81,88\"\n" + "\n" + " SHELLCODE_PORTS: 80\n" + "\n" + " ORACLE_PORTS: 1521\n" + "\n" + " SSH_PORTS: 22\n" + "\n"; + +static int SigTest01(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); - Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); + Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); int result = 0; - char sig[] = "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"; + char sig[] = "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"; if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; @@ -133,32 +133,31 @@ static int SigTest01 (void) return result; } -static int SigTest02 (void) +static int SigTest02(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); - Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); - char sig[] = "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:41; sid:1;)"; + Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); + char sig[] = "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: " + "one.example.org\"; offset:20; depth:41; sid:1;)"; int ret = UTHPacketMatchSigMpm(p, sig, MPM_AC); UTHFreePacket(p); return ret; } -static int SigTest03 (void) +static int SigTest03(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -176,7 +175,9 @@ static int SigTest03 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:39; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: " + "one.example.org\"; offset:20; depth:39; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -199,15 +200,14 @@ static int SigTest03 (void) return result; } -static int SigTest04 (void) +static int SigTest04(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20*/ - "Host: one.example.org\r\n" /* 23, post "Host:" 18 */ - "\r\n\r\n" /* 4 */ - "GET /two/ HTTP/1.1\r\n" /* 20 */ - "Host: two.example.org\r\n" /* 23 */ - "\r\n\r\n"; /* 4 */ + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" /* 20*/ + "Host: one.example.org\r\n" /* 23, post "Host:" 18 */ + "\r\n\r\n" /* 4 */ + "GET /two/ HTTP/1.1\r\n" /* 20 */ + "Host: two.example.org\r\n" /* 23 */ + "\r\n\r\n"; /* 4 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; @@ -226,7 +226,9 @@ static int SigTest04 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:42; within:47; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; " + "offset:20; depth:25; content:\"Host:\"; distance:42; within:47; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -249,15 +251,14 @@ static int SigTest04 (void) return result; } -static int SigTest05 (void) +static int SigTest05(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -275,7 +276,9 @@ static int SigTest05 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:48; within:52; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; " + "offset:20; depth:25; content:\"Host:\"; distance:48; within:52; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); goto end; @@ -301,15 +304,14 @@ static int SigTest05 (void) return result; } -static int SigTest06 (void) +static int SigTest06(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -333,7 +335,7 @@ static int SigTest06 (void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -342,10 +344,13 @@ static int SigTest06 (void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -368,15 +373,14 @@ static int SigTest06 (void) PASS; } -static int SigTest07 (void) +static int SigTest07(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -399,7 +403,7 @@ static int SigTest07 (void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -411,19 +415,22 @@ static int SigTest07 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"three\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"three\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, buf, buflen); if (r != 0) { @@ -454,15 +461,14 @@ static int SigTest07 (void) return result; } -static int SigTest08 (void) +static int SigTest08(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.0\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -485,7 +491,7 @@ static int SigTest08 (void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -497,19 +503,22 @@ static int SigTest08 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; " + "depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"one\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"one\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, buf, buflen); if (r != 0) { @@ -522,9 +531,8 @@ static int SigTest08 (void) if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; else - printf("sid:1 %s, sid:2 %s: ", - PacketAlertCheck(p, 1) ? "OK" : "FAIL", - PacketAlertCheck(p, 2) ? "OK" : "FAIL"); + printf("sid:1 %s, sid:2 %s: ", PacketAlertCheck(p, 1) ? "OK" : "FAIL", + PacketAlertCheck(p, 2) ? "OK" : "FAIL"); end: FlowCleanupAppLayer(&f); @@ -542,15 +550,14 @@ static int SigTest08 (void) return result; } -static int SigTest09 (void) +static int SigTest09(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.0\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -573,7 +580,7 @@ static int SigTest09 (void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -585,19 +592,22 @@ static int SigTest09 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; " + "depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, buf, buflen); if (r != 0) { @@ -627,10 +637,9 @@ static int SigTest09 (void) return result; } -static int SigTest10 (void) +static int SigTest10(void) { - uint8_t *buf = (uint8_t *) - "ABC"; + uint8_t *buf = (uint8_t *)"ABC"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -653,7 +662,7 @@ static int SigTest10 (void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -665,19 +674,21 @@ static int SigTest10 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (1)\"; content:\"ABCD\"; depth:4; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Long content test " + "(1)\"; content:\"ABCD\"; depth:4; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (2)\"; content:\"VWXYZ\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Long content " + "test (2)\"; content:\"VWXYZ\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, buf, buflen); if (r != 0) { @@ -692,7 +703,7 @@ static int SigTest10 (void) else result = 1; - end: +end: FlowCleanupAppLayer(&f); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -707,10 +718,10 @@ static int SigTest10 (void) return result; } -static int SigTest11 (void) +static int SigTest11(void) { - uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + uint8_t *buf = + (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -731,7 +742,7 @@ static int SigTest11 (void) f.flags |= FLOW_IPV4; p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; f.alproto = ALPROTO_HTTP1; StreamTcpInitConfig(true); @@ -743,23 +754,26 @@ static int SigTest11 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"ABCDEFGHIJ\"; " + "content:\"klmnop\"; content:\"1234\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (content:\"VWXYZabcde\"; content:\"5678\"; content:\"89\"; sid:2;)"); + de_ctx->sig_list->next = + SigInit(de_ctx, "alert tcp any any -> any any (content:\"VWXYZabcde\"; " + "content:\"5678\"; content:\"89\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; - end: +end: FlowCleanupAppLayer(&f); SigGroupCleanup(de_ctx); if (det_ctx) @@ -771,10 +785,10 @@ static int SigTest11 (void) return result; } -static int SigTest12 (void) +static int SigTest12(void) { - uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + uint8_t *buf = + (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -789,7 +803,7 @@ static int SigTest12 (void) p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -798,14 +812,16 @@ static int SigTest12 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Content order test\"; " + "content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) @@ -814,7 +830,7 @@ static int SigTest12 (void) result = 0; if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: UTHFreePackets(&p, 1); if (de_ctx != NULL) { @@ -826,10 +842,10 @@ static int SigTest12 (void) return result; } -static int SigTest13 (void) +static int SigTest13(void) { - uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + uint8_t *buf = + (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -844,7 +860,7 @@ static int SigTest13 (void) p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -853,14 +869,16 @@ static int SigTest13 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Content order test\"; " + "content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) @@ -878,10 +896,10 @@ static int SigTest13 (void) return result; } -static int SigTest14 (void) +static int SigTest14(void) { - uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + uint8_t *buf = + (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -899,14 +917,16 @@ static int SigTest14 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; distance:0; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; " + "content:\"1234\"; content:\"klmnop\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) @@ -923,10 +943,9 @@ static int SigTest14 (void) return result; } -static int SigTest15 (void) +static int SigTest15(void) { - uint8_t *buf = (uint8_t *) - "CONNECT 213.92.8.7:31204 HTTP/1.1"; + uint8_t *buf = (uint8_t *)"CONNECT 213.92.8.7:31204 HTTP/1.1"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -954,14 +973,17 @@ static int SigTest15 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP " + "CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; " + "content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 2008284)) @@ -980,10 +1002,9 @@ static int SigTest15 (void) return result; } -static int SigTest16 (void) +static int SigTest16(void) { - uint8_t *buf = (uint8_t *) - "CONNECT 213.92.8.7:31204 HTTP/1.1"; + uint8_t *buf = (uint8_t *)"CONNECT 213.92.8.7:31204 HTTP/1.1"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -1006,13 +1027,16 @@ static int SigTest16 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP " + "CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; " + "content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); if (de_ctx->sig_list == NULL) { goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 2008284)) @@ -1030,15 +1054,14 @@ static int SigTest16 (void) return result; } -static int SigTest17 (void) +static int SigTest17(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -1056,11 +1079,13 @@ static int SigTest17 (void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; " + "pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); uint32_t capid = VarNameStoreLookupByName("http_host", VAR_TYPE_PKT_VAR); @@ -1078,10 +1103,9 @@ static int SigTest17 (void) PASS; } -static int SigTest18 (void) +static int SigTest18(void) { - uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + uint8_t *buf = (uint8_t *)"220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1106,14 +1130,16 @@ static int SigTest18 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local " + "Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!PacketAlertCheck(p, 2003055)) @@ -1130,10 +1156,9 @@ static int SigTest18 (void) return result; } -static int SigTest19 (void) +static int SigTest19(void) { - uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + uint8_t *buf = (uint8_t *)"220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1165,14 +1190,15 @@ static int SigTest19 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> 1.2.3.4 any (msg:\"IP-ONLY test (1)\"; sid:999; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert ip $HOME_NET any -> 1.2.3.4 any (msg:\"IP-ONLY test (1)\"; sid:999; rev:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 999)) @@ -1190,10 +1216,9 @@ static int SigTest19 (void) return result; } -static int SigTest20 (void) +static int SigTest20(void) { - uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + uint8_t *buf = (uint8_t *)"220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -1225,14 +1250,16 @@ static int SigTest20 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> [99.99.99.99,1.2.3.0/24,1.1.1.1,3.0.0.0/8] any (msg:\"IP-ONLY test (2)\"; sid:999; rev:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert ip $HOME_NET any -> [99.99.99.99,1.2.3.0/24,1.1.1.1,3.0.0.0/8] " + "any (msg:\"IP-ONLY test (2)\"; sid:999; rev:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 999)) @@ -1251,7 +1278,7 @@ static int SigTest20 (void) return result; } -static int SigTest21 (void) +static int SigTest21(void) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); @@ -1264,21 +1291,21 @@ static int SigTest21 (void) /* packet 1 */ uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buf1len = strlen((char *)buf1); Packet *p1 = NULL; /* packet 2 */ uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buf2len = strlen((char *)buf2); Packet *p2 = NULL; p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); p1->flow = &f; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); p2->flow = &f; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1287,12 +1314,15 @@ static int SigTest21 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; " + "flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; " + "content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1329,7 +1359,7 @@ static int SigTest21 (void) return result; } -static int SigTest22 (void) +static int SigTest22(void) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); @@ -1342,23 +1372,23 @@ static int SigTest22 (void) /* packet 1 */ uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buf1len = strlen((char *)buf1); Packet *p1 = NULL; p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); p1->flow = &f; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; /* packet 2 */ uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buf2len = strlen((char *)buf2); Packet *p2 = NULL; p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); p2->flow = &f; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1367,12 +1397,15 @@ static int SigTest22 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; " + "flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.abc; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; " + "content:\"/two/\"; flowbits:isset,TEST.abc; sid:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1404,7 +1437,7 @@ static int SigTest22 (void) return result; } -static int SigTest23 (void) +static int SigTest23(void) { ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); @@ -1417,23 +1450,23 @@ static int SigTest23 (void) /* packet 1 */ uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buf1len = strlen((char *)buf1); Packet *p1 = NULL; p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); p1->flow = &f; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; /* packet 2 */ uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buf2len = strlen((char *)buf2); Packet *p2 = NULL; p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); p2->flow = &f; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -1442,12 +1475,15 @@ static int SigTest23 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:toggle,TEST.one; flowbits:noalert; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; " + "flowbits:toggle,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; " + "content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -1481,15 +1517,19 @@ static int SigTest23 (void) static int SigTest24IPV4Keyword(void) { + // clang-format off uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x06}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -1504,7 +1544,7 @@ static int SigTest24IPV4Keyword(void) int result = 0; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); @@ -1534,27 +1574,25 @@ static int SigTest24IPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:valid; " - "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:valid; " + "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig 1 parse: "); goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:invalid; " - "msg:\"ipv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:invalid; " + "msg:\"ipv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { printf("sig 2 parse: "); goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { @@ -1583,15 +1621,19 @@ static int SigTest24IPV4Keyword(void) static int SigTest25NegativeIPV4Keyword(void) { + // clang-format off uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x06}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -1606,7 +1648,7 @@ static int SigTest25NegativeIPV4Keyword(void) int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); @@ -1636,27 +1678,25 @@ static int SigTest25NegativeIPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:invalid; " - "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:invalid; " + "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:valid; " - "msg:\"ipv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:valid; " + "msg:\"ipv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) @@ -1682,24 +1722,30 @@ static int SigTest25NegativeIPV4Keyword(void) static int SigTest26TCPV4Keyword(void) { + // clang-format off uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t valid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0x4A, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; + // clang-format on + // clang-format off uint8_t invalid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -1745,21 +1791,19 @@ static int SigTest26TCPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " - "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " + "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " - "msg:\"tcpv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " + "msg:\"tcpv4-csum keyword check(1)\"; " + "sid:2;)"); FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); FAIL_IF(!(PacketAlertCheck(p1, 1))); @@ -1779,24 +1823,30 @@ static int SigTest26TCPV4Keyword(void) /* Test SigTest26TCPV4Keyword but also check for invalid IPV4 checksum */ static int SigTest26TCPV4AndNegativeIPV4Keyword(void) { + // clang-format off uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t valid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0x4A, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; + // clang-format on + // clang-format off uint8_t invalid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -1845,27 +1895,26 @@ static int SigTest26TCPV4AndNegativeIPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " - "ipv4-csum:invalid; " - "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " + "ipv4-csum:invalid; " + "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " - "ipv4-csum:invalid; " - "msg:\"tcpv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " + "ipv4-csum:invalid; " + "msg:\"tcpv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { @@ -1896,16 +1945,19 @@ static int SigTest26TCPV4AndIPV4Keyword(void) /* IPV4: src:192.168.176.67 dst: 192.168.176.116 * TTL: 64 Flags: Don't Fragment */ + // clang-format off uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x40, 0x9b, 0xa4, 0x40, 0x00, 0x40, 0x06, 0xbd, 0x0a, 0xc0, 0xa8, 0xb0, 0x43, 0xc0, 0xa8, 0xb0, 0x74}; + // clang-format on /* TCP: sport: 49517 dport: 445 Flags: SYN * Window size: 65535, checksum: 0x2009, * MTU: 1460, Window scale: 4, TSACK permitted, * 24 bytes of options, no payload. */ + // clang-format off uint8_t valid_raw_tcp[] = { 0xc1, 0x6d, 0x01, 0xbd, 0x03, 0x10, 0xd3, 0xc9, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xff, 0xff, @@ -1913,7 +1965,9 @@ static int SigTest26TCPV4AndIPV4Keyword(void) 0x01, 0x03, 0x03, 0x04, 0x01, 0x01, 0x08, 0x0a, 0x19, 0x69, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00}; + // clang-format on + // clang-format off uint8_t invalid_raw_tcp[] = { 0xc1, 0x6d, 0x01, 0xbd, 0x03, 0x10, 0xd3, 0xc9, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xff, 0xff, @@ -1921,6 +1975,7 @@ static int SigTest26TCPV4AndIPV4Keyword(void) 0x01, 0x03, 0x03, 0x04, 0x01, 0x01, 0x08, 0x0a, 0x19, 0x69, 0x81, 0x7e, 0xFF, 0xAA, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -1969,27 +2024,26 @@ static int SigTest26TCPV4AndIPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(tcpv4-csum:valid; " - "ipv4-csum:valid; " - "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert ip any any -> any any " + "(tcpv4-csum:valid; " + "ipv4-csum:valid; " + "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(tcpv4-csum:invalid; " - "ipv4-csum:valid; " - "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert ip any any -> any any " + "(tcpv4-csum:invalid; " + "ipv4-csum:valid; " + "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { @@ -2016,24 +2070,30 @@ static int SigTest26TCPV4AndIPV4Keyword(void) static int SigTest27NegativeTCPV4Keyword(void) { + // clang-format off uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t valid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; + // clang-format on + // clang-format off uint8_t invalid_raw_tcp[] = { 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -2080,25 +2140,23 @@ static int SigTest27NegativeTCPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; dsize:20; " - "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; dsize:20; " + "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " - "msg:\"tcpv4-csum keyword check(2)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " + "msg:\"tcpv4-csum keyword check(2)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!PacketAlertCheck(p1, 1)) { @@ -2125,6 +2183,7 @@ static int SigTest27NegativeTCPV4Keyword(void) static int SigTest28TCPV6Keyword(void) { + // clang-format off static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, @@ -2141,7 +2200,9 @@ static int SigTest28TCPV6Keyword(void) 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x27}; + // clang-format on + // clang-format off static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, @@ -2158,6 +2219,7 @@ static int SigTest28TCPV6Keyword(void) 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x28}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -2175,7 +2237,7 @@ static int SigTest28TCPV6Keyword(void) PACKET_RESET_CHECKSUMS(p1); p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); + p1->tcph = (TCPHdr *)(valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = valid_raw_ipv6 + 54 + 20; @@ -2188,7 +2250,7 @@ static int SigTest28TCPV6Keyword(void) PACKET_RESET_CHECKSUMS(p2); p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); + p2->tcph = (TCPHdr *)(invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = invalid_raw_ipv6 + 54 + 20; @@ -2206,25 +2268,24 @@ static int SigTest28TCPV6Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = + SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (!(PacketAlertCheck(p1, 1))) { @@ -2251,6 +2312,7 @@ static int SigTest28TCPV6Keyword(void) static int SigTest29NegativeTCPV6Keyword(void) { + // clang-format off static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, @@ -2267,7 +2329,9 @@ static int SigTest29NegativeTCPV6Keyword(void) 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x27}; + // clang-format on + // clang-format off static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, @@ -2284,6 +2348,7 @@ static int SigTest29NegativeTCPV6Keyword(void) 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, 0x00, 0x01, 0x69, 0x28}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -2301,7 +2366,7 @@ static int SigTest29NegativeTCPV6Keyword(void) PACKET_RESET_CHECKSUMS(p1); p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); + p1->tcph = (TCPHdr *)(valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = valid_raw_ipv6 + 54 + 20; @@ -2314,7 +2379,7 @@ static int SigTest29NegativeTCPV6Keyword(void) PACKET_RESET_CHECKSUMS(p2); p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); + p2->tcph = (TCPHdr *)(invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = invalid_raw_ipv6 + 54 + 20; @@ -2332,26 +2397,24 @@ static int SigTest29NegativeTCPV6Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) @@ -2375,11 +2438,14 @@ static int SigTest29NegativeTCPV6Keyword(void) static int SigTest30UDPV4Keyword(void) { + // clang-format off uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t valid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, @@ -2392,7 +2458,9 @@ static int SigTest30UDPV4Keyword(void) 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x26}; + // clang-format on + // clang-format off uint8_t invalid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, @@ -2405,6 +2473,7 @@ static int SigTest30UDPV4Keyword(void) 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x27}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); FAIL_IF_NULL(p1); @@ -2415,7 +2484,7 @@ static int SigTest30UDPV4Keyword(void) DetectEngineThreadCtx *det_ctx = NULL; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" - "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; memset(&th_v, 0, sizeof(ThreadVars)); @@ -2442,22 +2511,20 @@ static int SigTest30UDPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:valid; " - "msg:\"udpv4-csum keyword check(1)\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:valid; " + "msg:\"udpv4-csum keyword check(1)\"; " + "sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); - de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:invalid; " - "msg:\"udpv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:invalid; " + "msg:\"udpv4-csum keyword check(1)\"; " + "sid:2;)"); FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); FAIL_IF_NOT(PacketAlertCheck(p1, 1)); @@ -2477,11 +2544,14 @@ static int SigTest30UDPV4Keyword(void) static int SigTest31NegativeUDPV4Keyword(void) { + // clang-format off uint8_t raw_ipv4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, 0xc0, 0xa8, 0x01, 0x03}; + // clang-format on + // clang-format off uint8_t valid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, @@ -2494,7 +2564,9 @@ static int SigTest31NegativeUDPV4Keyword(void) 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x26}; + // clang-format on + // clang-format off uint8_t invalid_raw_udp[] = { 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, @@ -2507,6 +2579,7 @@ static int SigTest31NegativeUDPV4Keyword(void) 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0xc0, 0x27}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -2521,7 +2594,7 @@ static int SigTest31NegativeUDPV4Keyword(void) int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" - "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; memset(&th_v, 0, sizeof(ThreadVars)); @@ -2550,27 +2623,25 @@ static int SigTest31NegativeUDPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:invalid; " - "msg:\"udpv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:invalid; " + "msg:\"udpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:valid; " - "msg:\"udpv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:valid; " + "msg:\"udpv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) @@ -2581,8 +2652,7 @@ static int SigTest31NegativeUDPV4Keyword(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) { result &= 0; - } - else + } else result &= 1; SigGroupCleanup(de_ctx); @@ -2596,9 +2666,9 @@ static int SigTest31NegativeUDPV4Keyword(void) return result; } - static int SigTest32UDPV6Keyword(void) { + // clang-format off static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -2610,7 +2680,9 @@ static int SigTest32UDPV6Keyword(void) 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x00}; + // clang-format on + // clang-format off static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -2622,6 +2694,7 @@ static int SigTest32UDPV6Keyword(void) 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x01}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); FAIL_IF_NULL(p1); @@ -2632,13 +2705,13 @@ static int SigTest32UDPV6Keyword(void) DetectEngineThreadCtx *det_ctx = NULL; uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" - "\r\n\r\n"; + "\r\n\r\n"; memset(&th_v, 0, sizeof(ThreadVars)); PACKET_RESET_CHECKSUMS(p1); p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); + p1->udph = (UDPHdr *)(valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; @@ -2647,7 +2720,7 @@ static int SigTest32UDPV6Keyword(void) PACKET_RESET_CHECKSUMS(p2); p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); + p2->udph = (UDPHdr *)(invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; @@ -2659,21 +2732,19 @@ static int SigTest32UDPV6Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:valid; " - "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:valid; " + "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); FAIL_IF_NULL(de_ctx->sig_list); - de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:invalid; " - "msg:\"udpv6-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:invalid; " + "msg:\"udpv6-csum keyword check(1)\"; " + "sid:2;)"); FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); FAIL_IF_NOT(PacketAlertCheck(p1, 1)); @@ -2694,6 +2765,7 @@ static int SigTest32UDPV6Keyword(void) static int SigTest33NegativeUDPV6Keyword(void) { + // clang-format off static uint8_t valid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -2705,7 +2777,9 @@ static int SigTest33NegativeUDPV6Keyword(void) 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x00}; + // clang-format on + // clang-format off static uint8_t invalid_raw_ipv6[] = { 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, @@ -2717,6 +2791,7 @@ static int SigTest33NegativeUDPV6Keyword(void) 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, 0x09, 0x01}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -2731,13 +2806,13 @@ static int SigTest33NegativeUDPV6Keyword(void) int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" - "\r\n\r\n"; + "\r\n\r\n"; memset(&th_v, 0, sizeof(ThreadVars)); PACKET_RESET_CHECKSUMS(p1); p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); + p1->udph = (UDPHdr *)(valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; @@ -2746,7 +2821,7 @@ static int SigTest33NegativeUDPV6Keyword(void) PACKET_RESET_CHECKSUMS(p2); p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); + p2->udph = (UDPHdr *)(invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; @@ -2760,27 +2835,25 @@ static int SigTest33NegativeUDPV6Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:invalid; " - "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:invalid; " + "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:valid; " - "msg:\"udpv6-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:valid; " + "msg:\"udpv6-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) @@ -2807,6 +2880,7 @@ static int SigTest33NegativeUDPV6Keyword(void) static int SigTest34ICMPV4Keyword(void) { + // clang-format off uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, @@ -2819,7 +2893,9 @@ static int SigTest34ICMPV4Keyword(void) 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; + // clang-format on + // clang-format off uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, @@ -2832,6 +2908,7 @@ static int SigTest34ICMPV4Keyword(void) 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -2846,7 +2923,7 @@ static int SigTest34ICMPV4Keyword(void) int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); @@ -2854,7 +2931,7 @@ static int SigTest34ICMPV4Keyword(void) PACKET_RESET_CHECKSUMS(p1); p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); p1->ip4h->ip_verhl = 69; - p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); + p1->icmpv4h = (ICMPV4Hdr *)(valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; @@ -2864,7 +2941,7 @@ static int SigTest34ICMPV4Keyword(void) PACKET_RESET_CHECKSUMS(p2); p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); p2->ip4h->ip_verhl = 69; - p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); + p2->icmpv4h = (ICMPV4Hdr *)(invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; @@ -2878,27 +2955,25 @@ static int SigTest34ICMPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:valid; " - "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:valid; " + "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:invalid; " - "msg:\"icmpv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:invalid; " + "msg:\"icmpv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) @@ -2925,6 +3000,7 @@ static int SigTest34ICMPV4Keyword(void) static int SigTest35NegativeICMPV4Keyword(void) { + // clang-format off uint8_t valid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, @@ -2937,7 +3013,9 @@ static int SigTest35NegativeICMPV4Keyword(void) 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; + // clang-format on + // clang-format off uint8_t invalid_raw_ipv4[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, @@ -2950,6 +3028,7 @@ static int SigTest35NegativeICMPV4Keyword(void) 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; + // clang-format on Packet *p1 = PacketGetFromAlloc(); if (unlikely(p1 == NULL)) @@ -2964,7 +3043,7 @@ static int SigTest35NegativeICMPV4Keyword(void) int result = 1; uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); @@ -2972,7 +3051,7 @@ static int SigTest35NegativeICMPV4Keyword(void) PACKET_RESET_CHECKSUMS(p1); p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); p1->ip4h->ip_verhl = 69; - p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); + p1->icmpv4h = (ICMPV4Hdr *)(valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; @@ -2982,7 +3061,7 @@ static int SigTest35NegativeICMPV4Keyword(void) PACKET_RESET_CHECKSUMS(p2); p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); p2->ip4h->ip_verhl = 69; - p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); + p2->icmpv4h = (ICMPV4Hdr *)(invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; @@ -2996,27 +3075,25 @@ static int SigTest35NegativeICMPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:invalid; " - "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:invalid; " + "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:valid; " - "msg:\"icmpv4-csum keyword check(1)\"; " - "sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:valid; " + "msg:\"icmpv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) @@ -3050,16 +3127,21 @@ static int SigTest38(void) ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; + // clang-format off uint8_t raw_eth[] = { 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 }; + // clang-format on + // clang-format off uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01 }; + // clang-format on + // clang-format off uint8_t raw_tcp[] = { 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, @@ -3067,6 +3149,8 @@ static int SigTest38(void) 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, 0x00, 0x22, 0xaa, 0x10 }; + // clang-format on + // clang-format off uint8_t buf[] = { 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, @@ -3079,6 +3163,7 @@ static int SigTest38(void) 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on uint16_t ethlen = sizeof(raw_eth); uint16_t ipv4len = sizeof(raw_ipv4); uint16_t tcplen = sizeof(raw_tcp); @@ -3121,20 +3206,18 @@ static int SigTest38(void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"LEN1|20|\"; " - "byte_test:4,=,8,0; " - "msg:\"byte_test keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"LEN1|20|\"; " + "byte_test:4,=,8,0; " + "msg:\"byte_test keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"LEN1|20|\"; " - "byte_test:4,=,8,5,relative,string,dec; " - "msg:\"byte_test keyword check(2)\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"LEN1|20|\"; " + "byte_test:4,=,8,5,relative,string,dec; " + "msg:\"byte_test keyword check(2)\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; goto end; @@ -3176,16 +3259,21 @@ static int SigTest39(void) { ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + // clang-format off uint8_t raw_eth[] = { 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 }; + // clang-format on + // clang-format off uint8_t raw_ipv4[] = { 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01 }; + // clang-format on + // clang-format off uint8_t raw_tcp[] = { 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, @@ -3193,6 +3281,8 @@ static int SigTest39(void) 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, 0x00, 0x22, 0xaa, 0x10 }; + // clang-format on + // clang-format off uint8_t buf[] = { 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, @@ -3205,6 +3295,7 @@ static int SigTest39(void) 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a }; + // clang-format on uint16_t ethlen = sizeof(raw_eth); uint16_t ipv4len = sizeof(raw_ipv4); uint16_t tcplen = sizeof(raw_tcp); @@ -3269,43 +3360,44 @@ static int SigTest39(void) * \brief expecting to match a size */ -static int SigTest36ContentAndIsdataatKeywords01 (void) +static int SigTest36ContentAndIsdataatKeywords01(void) { int result = 0; // Build and decode the packet - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; + uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, + 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, + 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, + 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, + 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, + 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, + 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, + 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, + 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, + 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, + 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, + 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, + 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, + 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, + 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, + 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, + 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, + 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, + 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, + 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, + 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, + 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, + 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -3321,7 +3413,6 @@ static int SigTest36ContentAndIsdataatKeywords01 (void) FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth)); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; @@ -3329,7 +3420,9 @@ static int SigTest36ContentAndIsdataatKeywords01 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest36ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:404, relative; sid:101;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"SigTest36ContentAndIsdataatKeywords01 \"; " + "content:\"HTTP\"; isdataat:404, relative; sid:101;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3343,7 +3436,7 @@ static int SigTest36ContentAndIsdataatKeywords01 (void) result = 0; goto end; } else { - result=1; + result = 1; } SigGroupCleanup(de_ctx); @@ -3358,19 +3451,18 @@ static int SigTest36ContentAndIsdataatKeywords01 (void) return result; end: - if(de_ctx) - { + if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } - if(det_ctx) + if (det_ctx) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); + // PatternMatchDestroy(mpm_ctx); - if(de_ctx) - DetectEngineCtxFree(de_ctx); + if (de_ctx) + DetectEngineCtxFree(de_ctx); if (p != NULL) PacketRecycle(p); @@ -3381,49 +3473,49 @@ static int SigTest36ContentAndIsdataatKeywords01 (void) return result; } - /** * \test SigTest37ContentAndIsdataatKeywords02 is a test to check window with constructed packets, * \brief not expecting to match a size */ -static int SigTest37ContentAndIsdataatKeywords02 (void) +static int SigTest37ContentAndIsdataatKeywords02(void) { int result = 0; // Build and decode the packet - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; + uint8_t raw_eth[] = { 0x00, 0x25, 0x00, 0x9e, 0xfa, 0xfe, 0x00, 0x02, 0xcf, 0x74, 0xfe, 0xe1, + 0x08, 0x00, 0x45, 0x00, 0x01, 0xcc, 0xcb, 0x91, 0x00, 0x00, 0x34, 0x06, 0xdf, 0xa8, 0xd1, + 0x55, 0xe3, 0x67, 0xc0, 0xa8, 0x64, 0x8c, 0x00, 0x50, 0xc0, 0xb7, 0xd1, 0x11, 0xed, 0x63, + 0x81, 0xa9, 0x9a, 0x05, 0x80, 0x18, 0x00, 0x75, 0x0a, 0xdd, 0x00, 0x00, 0x01, 0x01, 0x08, + 0x0a, 0x09, 0x8a, 0x06, 0xd0, 0x12, 0x21, 0x2a, 0x3b, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, + 0x2e, 0x31, 0x20, 0x33, 0x30, 0x32, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, + 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x3a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, + 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x55, + 0x54, 0x46, 0x2d, 0x38, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x6e, + 0x2c, 0x20, 0x31, 0x34, 0x20, 0x53, 0x65, 0x70, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x30, + 0x38, 0x3a, 0x34, 0x38, 0x3a, 0x33, 0x31, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x67, 0x77, 0x73, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x31, 0x38, + 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x3c, 0x48, 0x45, 0x41, 0x44, + 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x65, 0x71, 0x75, + 0x69, 0x76, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x74, 0x65, 0x78, + 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, + 0x75, 0x74, 0x66, 0x2d, 0x38, 0x22, 0x3e, 0x0a, 0x3c, 0x54, 0x49, 0x54, 0x4c, 0x45, 0x3e, + 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, 0x2f, 0x54, 0x49, 0x54, 0x4c, + 0x45, 0x3e, 0x3c, 0x2f, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x42, 0x4f, 0x44, 0x59, 0x3e, + 0x0a, 0x3c, 0x48, 0x31, 0x3e, 0x33, 0x30, 0x32, 0x20, 0x4d, 0x6f, 0x76, 0x65, 0x64, 0x3c, + 0x2f, 0x48, 0x31, 0x3e, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x0a, 0x3c, 0x41, + 0x20, 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x65, 0x73, 0x2f, 0x22, 0x3e, + 0x68, 0x65, 0x72, 0x65, 0x3c, 0x2f, 0x41, 0x3e, 0x2e, 0x0d, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, + 0x44, 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, 0x3e, 0x0d, 0x0a }; Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -3439,7 +3531,6 @@ static int SigTest37ContentAndIsdataatKeywords02 (void) FlowInitConfig(FLOW_QUIET); DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth)); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; @@ -3447,7 +3538,9 @@ static int SigTest37ContentAndIsdataatKeywords02 (void) de_ctx->flags |= DE_QUIET; - Signature *s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest37ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:500, relative; sid:101;)"); + Signature *s = de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"SigTest37ContentAndIsdataatKeywords01 \"; " + "content:\"HTTP\"; isdataat:500, relative; sid:101;)"); if (de_ctx->sig_list == NULL) { printf("sig parse failed: "); result = 0; @@ -3467,7 +3560,7 @@ static int SigTest37ContentAndIsdataatKeywords02 (void) goto end; } else { printf("sig matched, but should not have: "); - result=0; + result = 0; } SigGroupCleanup(de_ctx); @@ -3483,16 +3576,15 @@ static int SigTest37ContentAndIsdataatKeywords02 (void) return result; end: - if(de_ctx) - { + if (de_ctx) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); } - if(det_ctx) + if (det_ctx) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - if(de_ctx) + if (de_ctx) DetectEngineCtxFree(de_ctx); if (p != NULL) @@ -3512,13 +3604,12 @@ static int SigTest37ContentAndIsdataatKeywords02 (void) static int SigTest40NoPacketInspection01(void) { - uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + uint8_t *buf = (uint8_t *)"220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); TCPHdr tcphdr; if (unlikely(p == NULL)) - return 0; + return 0; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; PacketQueue pq; @@ -3553,14 +3644,15 @@ static int SigTest40NoPacketInspection01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 any (msg:\"No Packet Inspection Test\"; flow:to_server; sid:2; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> 1.2.3.4 any (msg:\"No Packet " + "Inspection Test\"; flow:to_server; sid:2; rev:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); det_ctx->de_ctx = de_ctx; Detect(&th_v, p, det_ctx); @@ -3572,7 +3664,7 @@ static int SigTest40NoPacketInspection01(void) SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); + // PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p); @@ -3587,8 +3679,7 @@ static int SigTest40NoPacketInspection01(void) static int SigTest40NoPayloadInspection02(void) { - uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + uint8_t *buf = (uint8_t *)"220 (vsFTPd 2.0.5)\r\n"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); @@ -3608,8 +3699,8 @@ static int SigTest40NoPayloadInspection02(void) FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"No Payload TEST\"; content:\"220 (vsFTPd 2.0.5)\"; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"No Payload " + "TEST\"; content:\"220 (vsFTPd 2.0.5)\"; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); @@ -3625,15 +3716,14 @@ static int SigTest40NoPayloadInspection02(void) PASS; } -static int SigTestMemory01 (void) +static int SigTestMemory01(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) @@ -3656,7 +3746,9 @@ static int SigTestMemory01 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3675,7 +3767,7 @@ static int SigTestMemory01 (void) return result; } -static int SigTestMemory02 (void) +static int SigTestMemory02(void) { ThreadVars th_v; int result = 0; @@ -3688,12 +3780,16 @@ static int SigTestMemory02 (void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; @@ -3709,7 +3805,7 @@ static int SigTestMemory02 (void) return result; } -static int SigTestMemory03 (void) +static int SigTestMemory03(void) { ThreadVars th_v; int result = 0; @@ -3722,17 +3818,23 @@ static int SigTestMemory03 (void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> 1.2.3.4 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> 1.2.3.3-1.2.3.6 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> 1.2.3.3-1.2.3.6 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; " + "depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> !1.2.3.5 1:990 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:3;)"); + de_ctx->sig_list->next->next = SigInit(de_ctx, + "alert tcp any any -> !1.2.3.5 1:990 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; " + "pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:3;)"); if (de_ctx->sig_list->next->next == NULL) { result = 0; goto end; @@ -3748,7 +3850,7 @@ static int SigTestMemory03 (void) return result; } -static int SigTestContent01 (void) +static int SigTestContent01(void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); @@ -3767,7 +3869,8 @@ static int SigTestContent01 (void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test 32\"; " + "content:\"01234567890123456789012345678901\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3792,7 +3895,7 @@ static int SigTestContent01 (void) return result; } -static int SigTestContent02 (void) +static int SigTestContent02(void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); @@ -3810,13 +3913,16 @@ static int SigTestContent02 (void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test 32\"; " + "content:\"01234567890123456789012345678901\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 31\"; content:\"0123456789012345678901234567890\"; sid:2;)"); + de_ctx->sig_list->next = + SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test 31\"; " + "content:\"0123456789012345678901234567890\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; @@ -3831,8 +3937,7 @@ static int SigTestContent02 (void) result = 1; } else printf("sig 2 didn't match: "); - } - else + } else printf("sig 1 didn't match: "); SigGroupCleanup(de_ctx); @@ -3845,9 +3950,10 @@ static int SigTestContent02 (void) return result; } -static int SigTestContent03 (void) +static int SigTestContent03(void) { - uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJ" + "KLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -3864,7 +3970,10 @@ static int SigTestContent03 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; sid:1;)"); + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test 32\"; " + "content:\"01234567890123456789012345678901\"; " + "content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3889,9 +3998,10 @@ static int SigTestContent03 (void) return result; } -static int SigTestContent04 (void) +static int SigTestContent04(void) { - uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJ" + "KLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -3909,7 +4019,10 @@ static int SigTestContent04 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Test 32\"; " + "content:\"01234567890123456789012345678901\"; " + "content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; @@ -3935,9 +4048,10 @@ static int SigTestContent04 (void) } /** \test sigs with patterns at the limit of the pm's size limit */ -static int SigTestContent05 (void) +static int SigTestContent05(void) { - uint8_t *buf = (uint8_t *)"01234567890123456789012345678901PADabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint8_t *buf = (uint8_t *)"01234567890123456789012345678901PADabcdefghijklmnopqrstuvwxyzABCDEFG" + "HIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -3955,12 +4069,18 @@ static int SigTestContent05 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Test 32\"; " + "content:\"01234567890123456789012345678901\"; " + "content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("sig1 parse failed: "); goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:1; within:32; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"Test 32\"; " + "content:\"01234567890123456789012345678901\"; " + "content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:1; within:32; sid:2;)"); if (de_ctx->sig_list->next == NULL) { printf("sig2 parse failed: "); goto end; @@ -3996,9 +4116,10 @@ static int SigTestContent05 (void) return result; } -static int SigTestContent06 (void) +static int SigTestContent06(void) { - uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJ" + "KLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -4015,12 +4136,17 @@ static int SigTestContent06 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Test 32 sig1\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (msg:\"Test 32 sig1\"; " + "content:\"01234567890123456789012345678901\"; " + "content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Test 32 sig2\"; content:\"01234567890123456789012345678901\"; content:\"abcdefg\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert ip any any -> any any (msg:\"Test 32 sig2\"; " + "content:\"01234567890123456789012345678901\"; content:\"abcdefg\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { result = 0; goto end; @@ -4030,16 +4156,16 @@ static int SigTestContent06 (void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)){ - //printf("sig 1 matched :"); - }else{ + if (PacketAlertCheck(p, 1)) { + // printf("sig 1 matched :"); + } else { printf("sig 1 didn't match: "); goto end; } - if (PacketAlertCheck(p, 2)){ + if (PacketAlertCheck(p, 2)) { result = 1; - }else{ + } else { printf("sig 2 didn't match: "); goto end; } @@ -4054,7 +4180,7 @@ static int SigTestContent06 (void) return result; } -static int SigTestWithin01 (void) +static int SigTestWithin01(void) { DecodeThreadVars dtv; ThreadVars th_v; @@ -4064,6 +4190,7 @@ static int SigTestWithin01 (void) Packet *p3 = NULL; Packet *p4 = NULL; + // clang-format off uint8_t rawpkt1[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, @@ -4084,8 +4211,10 @@ static int SigTestWithin01 (void) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00 }; /* end rawpkt1 */ + 0x00,0x00 }; + // clang-format on /* end rawpkt1 */ + // clang-format off uint8_t rawpkt2[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, @@ -4106,8 +4235,10 @@ static int SigTestWithin01 (void) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00 }; /* end rawpkt2 */ + 0x00,0x00 }; + // clang-format on /* end rawpkt2 */ + // clang-format off uint8_t rawpkt3[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, @@ -4128,8 +4259,10 @@ static int SigTestWithin01 (void) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00 }; /* end rawpkt3 */ + 0x00,0x00 }; + // clang-format on /* end rawpkt3 */ + // clang-format off uint8_t rawpkt4[] = { 0x00,0x04,0x76,0xd3,0xd8,0x6a,0x00,0x24, 0xe8,0x29,0xfa,0x4f,0x08,0x00,0x45,0x00, @@ -4150,7 +4283,8 @@ static int SigTestWithin01 (void) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00 }; /* end rawpkt4 */ + 0x00,0x00 }; + // clang-format on /* end rawpkt4 */ memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); diff --git a/src/tests/fuzz/fuzz_applayerparserparse.c b/src/tests/fuzz/fuzz_applayerparserparse.c index 0ee263fc0b0c..1ee02a2fc0a6 100644 --- a/src/tests/fuzz/fuzz_applayerparserparse.c +++ b/src/tests/fuzz/fuzz_applayerparserparse.c @@ -9,10 +9,10 @@ #include "app-layer-detect-proto.h" #include "flow-util.h" #include "app-layer-parser.h" -#include "util-unittest-helper.h" -#include "util-byte.h" +#include "util/unittest-helper.h" +#include "util/byte.h" #include "conf-yaml-loader.h" -#include "util-conf.h" +#include "util/conf.h" #define HEADER_LEN 6 @@ -33,7 +33,7 @@ AppLayerParserThreadCtx *alp_tctx = NULL; * source port (uint16_t) * destination port (uint16_t) */ -const uint8_t separator[] = {0x01, 0xD5, 0xCA, 0x7A}; +const uint8_t separator[] = { 0x01, 0xD5, 0xCA, 0x7A }; SCInstance surifuzz; AppProto forceLayer = 0; SC_ATOMIC_EXTERN(unsigned int, engine_stage); @@ -71,17 +71,17 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - Flow * f; + Flow *f; TcpSession ssn; - const uint8_t * albuffer; - uint8_t * alnext; + const uint8_t *albuffer; + uint8_t *alnext; size_t alsize; // used to find under and overflows // otherwise overflows do not fail as they read the next packet - uint8_t * isolatedBuffer; + uint8_t *isolatedBuffer; if (alp_tctx == NULL) { - //Redirects logs to /dev/null + // Redirects logs to /dev/null setenv("SC_LOG_OP_IFACE", "file", 0); setenv("SC_LOG_FILE", "/dev/null", 0); @@ -89,7 +89,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) run_mode = RUNMODE_PCAP_FILE; GlobalsInitPreConfig(); - //redirect logs to /tmp + // redirect logs to /tmp ConfigSetLogDirectory("/tmp/"); // disables checksums validation for fuzzing if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) { @@ -108,7 +108,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (data[0] >= ALPROTO_MAX) { return 0; } - //no UTHBuildFlow to have storage + // no UTHBuildFlow to have storage f = FlowAlloc(); if (f == NULL) { return 0; @@ -158,7 +158,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) goto bail; } memcpy(isolatedBuffer, albuffer, alnext - albuffer); - (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alnext - albuffer); + (void)AppLayerParserParse( + NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alnext - albuffer); free(isolatedBuffer); if (FlowChangeProto(f)) { // exits if a protocol change is requested @@ -167,11 +168,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) } flags &= ~(STREAM_START); if (f->alparser && - (((flags & STREAM_TOSERVER) != 0 && - AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF_TS)) || - ((flags & STREAM_TOCLIENT) != 0 && - AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF_TC)))) { - //no final chunk + (((flags & STREAM_TOSERVER) != 0 && + AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF_TS)) || + ((flags & STREAM_TOCLIENT) != 0 && + AppLayerParserStateIssetFlag( + f->alparser, APP_LAYER_PARSER_EOF_TC)))) { + // no final chunk alsize = 0; break; } @@ -185,7 +187,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) } alnext = memmem(albuffer, alsize, separator, 4); } - if (alsize > 0 ) { + if (alsize > 0) { if (flip) { flags |= STREAM_TOCLIENT; flags &= ~(STREAM_TOSERVER); @@ -201,7 +203,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) goto bail; } memcpy(isolatedBuffer, albuffer, alsize); - (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alsize); + (void)AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alsize); free(isolatedBuffer); } diff --git a/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c b/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c index 598e7cc03ff6..2eef0b380f8f 100644 --- a/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c +++ b/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c @@ -4,18 +4,17 @@ * fuzz target for AppLayerProtoDetectGetProto */ - #include "suricata-common.h" #include "suricata.h" #include "app-layer-detect-proto.h" #include "flow-util.h" #include "app-layer-parser.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "conf-yaml-loader.h" #define HEADER_LEN 6 -//rule of thumb constant, so as not to timeout target +// rule of thumb constant, so as not to timeout target #define PROTO_DETECT_MAX_LEN 1024 #include "confyaml.c" @@ -34,7 +33,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) AppProto alproto2; if (alpd_tctx == NULL) { - //global init + // global init InitGlobal(); run_mode = RUNMODE_UNITTEST; if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) { @@ -76,7 +75,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) * 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++) { + 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( diff --git a/src/tests/fuzz/fuzz_confyamlloadstring.c b/src/tests/fuzz/fuzz_confyamlloadstring.c index f5f9ed39831e..edc29406c072 100644 --- a/src/tests/fuzz/fuzz_confyamlloadstring.c +++ b/src/tests/fuzz/fuzz_confyamlloadstring.c @@ -4,7 +4,6 @@ * fuzz target for ConfYamlLoadString */ - #include "suricata-common.h" #include "suricata.h" #include "conf-yaml-loader.h" @@ -16,16 +15,16 @@ static int initialized = 0; int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (initialized == 0) { - //Redirects logs to /dev/null + // Redirects logs to /dev/null setenv("SC_LOG_OP_IFACE", "file", 0); setenv("SC_LOG_FILE", "/dev/null", 0); - //global init + // global init InitGlobal(); run_mode = RUNMODE_UNITTEST; initialized = 1; } - ConfYamlLoadString((const char *) data, size); + ConfYamlLoadString((const char *)data, size); return 0; } diff --git a/src/tests/fuzz/fuzz_decodepcapfile.c b/src/tests/fuzz/fuzz_decodepcapfile.c index cf508697f05b..9ec695f0c5f8 100644 --- a/src/tests/fuzz/fuzz_decodepcapfile.c +++ b/src/tests/fuzz/fuzz_decodepcapfile.c @@ -11,10 +11,10 @@ #include "tm-modules.h" #include "tm-threads.h" #include "source-pcap-file.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "conf-yaml-loader.h" -#include "util-time.h" -#include "util-conf.h" +#include "util/time.h" +#include "util/conf.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); @@ -38,16 +38,16 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) void *ptv = NULL; if (initialized == 0) { - //Redirects logs to /dev/null + // Redirects logs to /dev/null setenv("SC_LOG_OP_IFACE", "file", 0); setenv("SC_LOG_FILE", "/dev/null", 0); InitGlobal(); run_mode = RUNMODE_PCAP_FILE; - //redirect logs to /tmp + // redirect logs to /tmp ConfigSetLogDirectory("/tmp/"); - //disables checksums validation for fuzzing + // disables checksums validation for fuzzing if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) { abort(); } @@ -58,10 +58,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) TimeModeSetOffline(); PcapFileGlobalInit(); - tv = TmThreadCreatePacketHandler("fuzz", - "packetpool", "packetpool", - "packetpool", "packetpool", - "pktacqloop"); + tv = TmThreadCreatePacketHandler( + "fuzz", "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); if (tv == NULL) { return 0; } @@ -75,7 +73,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) return 0; } TmSlotSetFuncAppend(tv, tm_module, NULL); - tmm_modules[TMM_DECODEPCAPFILE].ThreadInit(tv, NULL, (void **) &dtv); + tmm_modules[TMM_DECODEPCAPFILE].ThreadInit(tv, NULL, (void **)&dtv); (void)SC_ATOMIC_SET(tv->tm_slots->slot_next->slot_data, dtv); extern uint16_t max_pending_packets; @@ -86,12 +84,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) initialized = 1; } - //rewrite buffer to a file as libpcap does not have buffer inputs + // rewrite buffer to a file as libpcap does not have buffer inputs if (TestHelperBufferToFile("/tmp/fuzz.pcap", data, size) < 0) { return 0; } - if (tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit(tv, "/tmp/fuzz.pcap", &ptv) == TM_ECODE_OK && ptv != NULL) { + if (tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit(tv, "/tmp/fuzz.pcap", &ptv) == TM_ECODE_OK && + ptv != NULL) { suricata_ctl_flags = 0; tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqLoop(tv, ptv, tv->tm_slots); tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit(tv, ptv); diff --git a/src/tests/fuzz/fuzz_mimedecparseline.c b/src/tests/fuzz/fuzz_mimedecparseline.c index 432ce7de9523..236b1bafd137 100644 --- a/src/tests/fuzz/fuzz_mimedecparseline.c +++ b/src/tests/fuzz/fuzz_mimedecparseline.c @@ -4,20 +4,18 @@ * fuzz target for ConfYamlLoadString */ - #include "suricata-common.h" #include "suricata.h" -#include "util-decode-mime.h" +#include "util/decode-mime.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); static int initialized = 0; static int dummy = 0; -static int MimeParserDataFromFileCB(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state) +static int MimeParserDataFromFileCB(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) { - if (len > 0 && chunk[len-1] == 0) { + if (len > 0 && chunk[len - 1] == 0) { // do not get optimized away dummy++; } @@ -27,10 +25,10 @@ static int MimeParserDataFromFileCB(const uint8_t *chunk, uint32_t len, int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (initialized == 0) { - //Redirects logs to /dev/null + // Redirects logs to /dev/null setenv("SC_LOG_OP_IFACE", "file", 0); setenv("SC_LOG_FILE", "/dev/null", 0); - //global init + // global init InitGlobal(); run_mode = RUNMODE_UNITTEST; initialized = 1; @@ -40,15 +38,15 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) MimeDecParseState *state = MimeDecInitParser(&line_count, MimeParserDataFromFileCB); MimeDecEntity *msg_head = state->msg; - const uint8_t * buffer = data; + const uint8_t *buffer = data; while (1) { - uint8_t * next = memchr(buffer, '\n', size); + uint8_t *next = memchr(buffer, '\n', size); if (next == NULL) { if (state->state_flag >= BODY_STARTED) (void)MimeDecParseLine(buffer, size, 0, state); break; } else { - (void) MimeDecParseLine(buffer, next - buffer, 1, state); + (void)MimeDecParseLine(buffer, next - buffer, 1, state); if (buffer + size < next + 1) { break; } diff --git a/src/tests/fuzz/fuzz_predefpcap_aware.c b/src/tests/fuzz/fuzz_predefpcap_aware.c index c20e3d341d52..bc1d1a9cbaf6 100644 --- a/src/tests/fuzz/fuzz_predefpcap_aware.c +++ b/src/tests/fuzz/fuzz_predefpcap_aware.c @@ -7,26 +7,26 @@ #include "suricata-common.h" #include "source-pcap-file.h" #include "detect-engine.h" -#include "util-classification-config.h" -#include "util-reference-config.h" +#include "util/classification-config.h" +#include "util/reference-config.h" #include "app-layer.h" #include "tm-queuehandlers.h" -#include "util-cidr.h" -#include "util-profiling.h" -#include "util-proto-name.h" +#include "util/cidr.h" +#include "util/profiling.h" +#include "util/proto-name.h" #include "detect-engine-tag.h" #include "detect-engine-threshold.h" #include "host-bit.h" #include "ippair-bit.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "detect-fast-pattern.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "conf-yaml-loader.h" #include "pkt-var.h" #include "flow-util.h" #include "tm-modules.h" #include "tmqh-packetpool.h" -#include "util-conf.h" +#include "util/conf.h" #include "packet.h" #include diff --git a/src/tests/fuzz/fuzz_siginit.c b/src/tests/fuzz/fuzz_siginit.c index 80514b2d9a52..a051f02225ef 100644 --- a/src/tests/fuzz/fuzz_siginit.c +++ b/src/tests/fuzz/fuzz_siginit.c @@ -4,10 +4,9 @@ * fuzz target for SigInit */ - #include "suricata-common.h" -#include "util-reference-config.h" -#include "util-classification-config.h" +#include "util/reference-config.h" +#include "util/classification-config.h" #include "detect-engine.h" #include "detect-parse.h" @@ -21,7 +20,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (de_ctx == NULL) { setenv("SC_LOG_OP_IFACE", "file", 0); setenv("SC_LOG_FILE", "/dev/null", 0); - //global init + // global init InitGlobal(); run_mode = RUNMODE_UNITTEST; MpmTableSetup(); @@ -41,10 +40,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) de_ctx->rule_file = (char *)"fuzzer"; } - char * buffer = malloc(size+1); + char *buffer = malloc(size + 1); if (buffer) { memcpy(buffer, data, size); - //null terminate string + // null terminate string buffer[size] = 0; Signature *s = SigInit(de_ctx, buffer); free(buffer); diff --git a/src/tests/fuzz/fuzz_sigpcap.c b/src/tests/fuzz/fuzz_sigpcap.c index e5bd56deb476..7c09ec78cbc9 100644 --- a/src/tests/fuzz/fuzz_sigpcap.c +++ b/src/tests/fuzz/fuzz_sigpcap.c @@ -7,37 +7,36 @@ #include "suricata-common.h" #include "source-pcap-file.h" #include "detect-engine.h" -#include "util-classification-config.h" -#include "util-reference-config.h" +#include "util/classification-config.h" +#include "util/reference-config.h" #include "app-layer.h" #include "tm-queuehandlers.h" -#include "util-cidr.h" -#include "util-profiling.h" -#include "util-proto-name.h" +#include "util/cidr.h" +#include "util/profiling.h" +#include "util/proto-name.h" #include "detect-engine-tag.h" #include "detect-engine-threshold.h" #include "host-bit.h" #include "ippair-bit.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "detect-fast-pattern.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "conf-yaml-loader.h" #include "pkt-var.h" #include "flow-util.h" #include "flow-worker.h" #include "tm-modules.h" #include "tmqh-packetpool.h" -#include "util-file.h" -#include "util-conf.h" +#include "util/file.h" +#include "util/conf.h" #include "packet.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); - static int initialized = 0; ThreadVars tv; DecodeThreadVars *dtv; -//FlowWorkerThreadData +// FlowWorkerThreadData void *fwd; SCInstance surifuzz; SC_ATOMIC_EXTERN(unsigned int, engine_stage); @@ -46,7 +45,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage); int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - pcap_t * pkts; + pcap_t *pkts; char errbuf[PCAP_ERRBUF_SIZE]; const u_char *pkt; struct pcap_pkthdr *header; @@ -56,7 +55,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) size_t pcap_cnt = 0; if (initialized == 0) { - //Redirects logs to /dev/null + // Redirects logs to /dev/null setenv("SC_LOG_OP_IFACE", "file", 0); setenv("SC_LOG_FILE", "/dev/null", 0); @@ -64,9 +63,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) GlobalsInitPreConfig(); run_mode = RUNMODE_PCAP_FILE; - //redirect logs to /tmp + // redirect logs to /tmp ConfigSetLogDirectory("/tmp/"); - //disables checksums validation for fuzzing + // disables checksums validation for fuzzing if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) { abort(); } @@ -74,7 +73,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) remove("/tmp/fuzz.rules"); surifuzz.sig_file = strdup("/tmp/fuzz.rules"); surifuzz.sig_file_exclusive = 1; - //loads rules after init + // loads rules after init surifuzz.delayed_detect = 1; PostConfLoadedSetup(&surifuzz); @@ -113,14 +112,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) data += pos; size -= pos;*/ - for (pos=0; pos < size; pos++) { + for (pos = 0; pos < size; pos++) { if (data[pos] == 0) { break; } } if (pos > 0 && pos < size) { // dump signatures to a file so as to reuse SigLoadSignatures - if (TestHelperBufferToFile(surifuzz.sig_file, data, pos-1) < 0) { + if (TestHelperBufferToFile(surifuzz.sig_file, data, pos - 1) < 0) { return 0; } } else { @@ -142,24 +141,24 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) DetectEngineThreadCtxDeinit(NULL, old_det_ctx); if (pos < size) { - //skip zero + // skip zero pos++; } data += pos; size -= pos; - //rewrite buffer to a file as libpcap does not have buffer inputs + // rewrite buffer to a file as libpcap does not have buffer inputs if (TestHelperBufferToFile("/tmp/fuzz.pcap", data, size) < 0) { return 0; } - //initialize structure + // initialize structure pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf); if (pkts == NULL) { return 0; } - //loop over packets + // loop over packets r = pcap_next_ex(pkts, &header, &pkt); p = PacketGetFromAlloc(); if (r <= 0 || header->ts.tv_sec >= INT_MAX - 3600 || header->ts.tv_usec < 0) { @@ -199,7 +198,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) p->pcap_cnt = pcap_cnt; } bail: - //close structure + // close structure pcap_close(pkts); PacketFree(p); FlowReset(); diff --git a/src/tests/fuzz/fuzz_sigpcap_aware.c b/src/tests/fuzz/fuzz_sigpcap_aware.c index d2454769859b..11c4dd0aebb3 100644 --- a/src/tests/fuzz/fuzz_sigpcap_aware.c +++ b/src/tests/fuzz/fuzz_sigpcap_aware.c @@ -7,27 +7,27 @@ #include "suricata-common.h" #include "source-pcap-file.h" #include "detect-engine.h" -#include "util-classification-config.h" -#include "util-reference-config.h" +#include "util/classification-config.h" +#include "util/reference-config.h" #include "app-layer.h" #include "tm-queuehandlers.h" -#include "util-cidr.h" -#include "util-profiling.h" -#include "util-proto-name.h" +#include "util/cidr.h" +#include "util/profiling.h" +#include "util/proto-name.h" #include "detect-engine-tag.h" #include "detect-engine-threshold.h" #include "host-bit.h" #include "ippair-bit.h" -#include "app-layer-htp.h" +#include "app-layer/http/parser.h" #include "detect-fast-pattern.h" -#include "util-unittest-helper.h" +#include "util/unittest-helper.h" #include "conf-yaml-loader.h" #include "pkt-var.h" #include "flow-util.h" #include "flow-worker.h" #include "tm-modules.h" #include "tmqh-packetpool.h" -#include "util-conf.h" +#include "util/conf.h" #include "packet.h" #include diff --git a/src/tests/fuzz/onefile.c b/src/tests/fuzz/onefile.c index 344ef8ef6aad..a9c7b7448422 100644 --- a/src/tests/fuzz/onefile.c +++ b/src/tests/fuzz/onefile.c @@ -16,7 +16,7 @@ static int runOneFile(const char *fname) return 2; } size = ftell(fp); - if (size == (size_t) -1) { + if (size == (size_t)-1) { fclose(fp); return 2; } diff --git a/src/tests/reputation.c b/src/tests/reputation.c index 8b72a8a6b675..eed6044d8960 100644 --- a/src/tests/reputation.c +++ b/src/tests/reputation.c @@ -26,14 +26,14 @@ #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" -#include "util-unittest-helper.h" - -#define TEST_INIT \ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \ - FAIL_IF(de_ctx == NULL); \ - SRepInit(de_ctx); \ - \ - Address a; \ +#include "util/unittest-helper.h" + +#define TEST_INIT \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \ + FAIL_IF(de_ctx == NULL); \ + SRepInit(de_ctx); \ + \ + Address a; \ uint8_t cat = 0, value = 0; #define TEST_INIT_WITH_PACKET_IPV6(src, dst) \ @@ -43,19 +43,18 @@ FAIL_IF(p == NULL); \ TEST_INIT -#define TEST_INIT_WITH_PACKET(ip) \ - uint8_t *buf = (uint8_t *)"Hi all!"; \ - uint16_t buflen = strlen((char *)buf); \ - Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); \ - FAIL_IF(p == NULL); \ - p->src.addr_data32[0] = UTHSetIPv4Address(ip); \ +#define TEST_INIT_WITH_PACKET(ip) \ + uint8_t *buf = (uint8_t *)"Hi all!"; \ + uint16_t buflen = strlen((char *)buf); \ + Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); \ + FAIL_IF(p == NULL); \ + p->src.addr_data32[0] = UTHSetIPv4Address(ip); \ TEST_INIT -#define TEST_CLEANUP \ - DetectEngineCtxFree(de_ctx); +#define TEST_CLEANUP DetectEngineCtxFree(de_ctx); -#define TEST_CLEANUP_WITH_PACKET \ - UTHFreePacket(p); \ +#define TEST_CLEANUP_WITH_PACKET \ + UTHFreePacket(p); \ TEST_CLEANUP static int SRepTest01(void) @@ -140,7 +139,8 @@ static int SRepTest06(void) PASS; } -static int SRepTest07(void) { +static int SRepTest07(void) +{ TEST_INIT; char str[] = "2000:0000:0000:0000:0000:0000:0000:0001,"; diff --git a/src/tests/source-pcap.c b/src/tests/source-pcap.c index fc1b275e3fb9..3bd03bc5a1cd 100644 --- a/src/tests/source-pcap.c +++ b/src/tests/source-pcap.c @@ -16,7 +16,7 @@ */ #include "../suricata-common.h" -#include "../util-unittest.h" +#include "../util/unittest.h" static uint32_t Upper32(uint64_t value) { @@ -41,9 +41,8 @@ static int UpdatePcapStatsValue64NoChange01(void) * No change in counter values. * Last count is within first 32bit range, i.e. same as pcap_stat range. */ - TestData data[] = {{.last = 0, .current = 0}, - {.last = 12345, .current = 12345}, - {.last = (uint64_t)UINT32_MAX, .current = UINT_MAX}}; + TestData data[] = { { .last = 0, .current = 0 }, { .last = 12345, .current = 12345 }, + { .last = (uint64_t)UINT32_MAX, .current = UINT_MAX } }; for (size_t i = 0; i < ARRAY_SIZE(data); ++i) { FAIL_IF_NOT(data[i].last == data[i].current); @@ -61,10 +60,10 @@ static int UpdatePcapStatsValue64NoChange02(void) * No change in counter values. * Last count is outside 32bits range. */ - TestData data[] = {{.last = (2ull << 32) + 0, .current = 0}, - {.last = (3ull << 32) + 12345, .current = 12345}, - {.last = (3ull << 32) + (uint64_t)UINT32_MAX, .current = UINT_MAX}, - {.last = UINT64_MAX, .current = UINT_MAX}}; + TestData data[] = { { .last = (2ull << 32) + 0, .current = 0 }, + { .last = (3ull << 32) + 12345, .current = 12345 }, + { .last = (3ull << 32) + (uint64_t)UINT32_MAX, .current = UINT_MAX }, + { .last = UINT64_MAX, .current = UINT_MAX } }; for (size_t i = 0; i < ARRAY_SIZE(data); ++i) { uint32_t upper = Upper32(data[i].last); @@ -85,9 +84,8 @@ static int UpdatePcapStatsValue64NoOverflow01(void) * Last count is within first 32bit range, i.e. same as pcap_stat range. * Also test edges and simple +1. */ - TestData data[] = {{.last = 0, .current = 1}, - {.last = 12345, .current = 34567}, - {.last = (uint64_t)UINT32_MAX - 1, .current = UINT_MAX}}; + TestData data[] = { { .last = 0, .current = 1 }, { .last = 12345, .current = 34567 }, + { .last = (uint64_t)UINT32_MAX - 1, .current = UINT_MAX } }; for (size_t i = 0; i < ARRAY_SIZE(data); ++i) { FAIL_IF_NOT(data[i].last < data[i].current); @@ -105,9 +103,9 @@ static int UpdatePcapStatsValue64NoOverflow02(void) * Non-overflowing counter value is simply taken over in lower 32bits. * Last count is outside 32bits range. */ - TestData data[] = {{.last = (2ull << 32) + 0, .current = 1}, - {.last = (3ull << 32) + 12345, .current = 34567}, - {.last = UINT64_MAX - 1, .current = UINT_MAX}}; + TestData data[] = { { .last = (2ull << 32) + 0, .current = 1 }, + { .last = (3ull << 32) + 12345, .current = 34567 }, + { .last = UINT64_MAX - 1, .current = UINT_MAX } }; for (size_t i = 0; i < ARRAY_SIZE(data); ++i) { uint32_t upper = Upper32(data[i].last); @@ -127,9 +125,9 @@ static int UpdatePcapStatsValue64Overflow01(void) * Overflowing counter value is simply taken over in lower 32bits. * Last count is within first 32bit range, i.e. same as pcap_stat range. */ - TestData data[] = {{.last = 1, .current = 0}, - {.last = 12345, .current = 22}, {.last = 12345, .current = 12344}, - {.last = (uint64_t)UINT32_MAX, .current = UINT_MAX - 1}}; + TestData data[] = { { .last = 1, .current = 0 }, { .last = 12345, .current = 22 }, + { .last = 12345, .current = 12344 }, + { .last = (uint64_t)UINT32_MAX, .current = UINT_MAX - 1 } }; for (size_t i = 0; i < ARRAY_SIZE(data); ++i) { FAIL_IF_NOT(data[i].last > data[i].current); @@ -148,10 +146,10 @@ static int UpdatePcapStatsValue64Overflow02(void) * Overflowing counter value is simply taken over in lower 32bits. * Last count is outside 32bits range. */ - TestData data[] = {{.last = (2ull << 32) + 1, .current = 0}, - {.last = (3ull << 32) + 12345, .current = 22}, - {.last = (3ull << 32) + 12345, .current = 12344}, - {.last = UINT64_MAX, .current = UINT_MAX - 1}}; + TestData data[] = { { .last = (2ull << 32) + 1, .current = 0 }, + { .last = (3ull << 32) + 12345, .current = 22 }, + { .last = (3ull << 32) + 12345, .current = 12344 }, + { .last = UINT64_MAX, .current = UINT_MAX - 1 } }; for (size_t i = 0; i < ARRAY_SIZE(data); ++i) { uint32_t upper = Upper32(data[i].last); @@ -171,8 +169,8 @@ static int UpdatePcapStatsValue64Overflow03(void) * Overflowing counter value is simply taken over in lower 32bits. * Edge cases where upper32 bit wrap around to 0. */ - TestData data[] = {{.last = UINT64_MAX, .current = 0}, - {.last = UINT64_MAX, .current = 3333}}; + TestData data[] = { { .last = UINT64_MAX, .current = 0 }, + { .last = UINT64_MAX, .current = 3333 } }; for (size_t i = 0; i < ARRAY_SIZE(data); ++i) { FAIL_IF_NOT(Lower32(data[i].last) > data[i].current); @@ -193,9 +191,8 @@ static int UpdatePcapStats64Assorted01(void) * Full testing of value behaviour is done in UpdatePcapStatsValue64...() * tests. */ - PcapStats64 last = {.ps_recv = 0, .ps_drop = 1234, .ps_ifdrop = 8765}; - struct pcap_stat current = { - .ps_recv = 12, .ps_drop = 2345, .ps_ifdrop = 9876}; + PcapStats64 last = { .ps_recv = 0, .ps_drop = 1234, .ps_ifdrop = 8765 }; + struct pcap_stat current = { .ps_recv = 12, .ps_drop = 2345, .ps_ifdrop = 9876 }; // test setup sanity check FAIL_IF_NOT(last.ps_recv < current.ps_recv); @@ -213,20 +210,13 @@ static int UpdatePcapStats64Assorted01(void) static void SourcePcapRegisterStatsTests(void) { - UtRegisterTest("UpdatePcapStatsValue64NoChange01", - UpdatePcapStatsValue64NoChange01); - UtRegisterTest("UpdatePcapStatsValue64NoChange02", - UpdatePcapStatsValue64NoChange02); - UtRegisterTest("UpdatePcapStatsValue64NoOverflow01", - UpdatePcapStatsValue64NoOverflow01); - UtRegisterTest("UpdatePcapStatsValue64NoOverflow02", - UpdatePcapStatsValue64NoOverflow02); - UtRegisterTest("UpdatePcapStatsValue64Overflow01", - UpdatePcapStatsValue64Overflow01); - UtRegisterTest("UpdatePcapStatsValue64Overflow02", - UpdatePcapStatsValue64Overflow02); - UtRegisterTest("UpdatePcapStatsValue64Overflow03", - UpdatePcapStatsValue64Overflow03); + UtRegisterTest("UpdatePcapStatsValue64NoChange01", UpdatePcapStatsValue64NoChange01); + UtRegisterTest("UpdatePcapStatsValue64NoChange02", UpdatePcapStatsValue64NoChange02); + UtRegisterTest("UpdatePcapStatsValue64NoOverflow01", UpdatePcapStatsValue64NoOverflow01); + UtRegisterTest("UpdatePcapStatsValue64NoOverflow02", UpdatePcapStatsValue64NoOverflow02); + UtRegisterTest("UpdatePcapStatsValue64Overflow01", UpdatePcapStatsValue64Overflow01); + UtRegisterTest("UpdatePcapStatsValue64Overflow02", UpdatePcapStatsValue64Overflow02); + UtRegisterTest("UpdatePcapStatsValue64Overflow03", UpdatePcapStatsValue64Overflow03); UtRegisterTest("UpdatePcapStats64Assorted01", UpdatePcapStats64Assorted01); } diff --git a/src/tests/stream-tcp-inline.c b/src/tests/stream-tcp-inline.c index 410451a833d0..0ec3137350e6 100644 --- a/src/tests/stream-tcp-inline.c +++ b/src/tests/stream-tcp-inline.c @@ -22,15 +22,13 @@ #include "../stream-tcp-inline.h" #include "../stream-tcp-list.h" #include "../stream-tcp-util.h" -#include "../util-streaming-buffer.h" -#include "../util-print.h" -#include "../util-unittest.h" +#include "../util/streaming-buffer.h" +#include "../util/print.h" +#include "../util/unittest.h" static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len) { - if (StreamingBufferCompareRawData(&stream->sb, - data, data_len) == 0) - { + if (StreamingBufferCompareRawData(&stream->sb, data, data_len) == 0) { SCReturnInt(0); } SCLogInfo("OK"); @@ -38,25 +36,25 @@ static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len) return 1; } -#define INLINE_START(isn) \ - Packet *p; \ - TcpReassemblyThreadCtx *ra_ctx = NULL; \ - TcpSession ssn; \ - ThreadVars tv; \ - memset(&tv, 0, sizeof(tv)); \ - \ - StreamTcpUTInit(&ra_ctx); \ - StreamTcpUTInitInline(); \ - \ - StreamTcpUTSetupSession(&ssn); \ - StreamTcpUTSetupStream(&ssn.server, (isn)); \ - StreamTcpUTSetupStream(&ssn.client, (isn)); \ - \ +#define INLINE_START(isn) \ + Packet *p; \ + TcpReassemblyThreadCtx *ra_ctx = NULL; \ + TcpSession ssn; \ + ThreadVars tv; \ + memset(&tv, 0, sizeof(tv)); \ + \ + StreamTcpUTInit(&ra_ctx); \ + StreamTcpUTInitInline(); \ + \ + StreamTcpUTSetupSession(&ssn); \ + StreamTcpUTSetupStream(&ssn.server, (isn)); \ + StreamTcpUTSetupStream(&ssn.client, (isn)); \ + \ TcpStream *stream = &ssn.client; -#define INLINE_END \ - StreamTcpUTClearSession(&ssn); \ - StreamTcpUTDeinit(ra_ctx); \ +#define INLINE_END \ + StreamTcpUTClearSession(&ssn); \ + StreamTcpUTDeinit(ra_ctx); \ PASS #define INLINE_ADD_PAYLOAD(rseq, seg, seglen, packet, packetlen) \ diff --git a/src/tests/stream-tcp-list.c b/src/tests/stream-tcp-list.c index d10c756bd9c6..c754066d7b8b 100644 --- a/src/tests/stream-tcp-list.c +++ b/src/tests/stream-tcp-list.c @@ -22,9 +22,9 @@ #include "../stream-tcp-inline.h" #include "../stream-tcp-list.h" #include "../stream-tcp-util.h" -#include "../util-streaming-buffer.h" -#include "../util-print.h" -#include "../util-unittest.h" +#include "../util/streaming-buffer.h" +#include "../util/print.h" +#include "../util/unittest.h" static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len) { @@ -37,28 +37,29 @@ static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len) return 1; } -#define OVERLAP_START(isn, policy) \ - TcpReassemblyThreadCtx *ra_ctx = NULL; \ - TcpSession ssn; \ - ThreadVars tv; \ - memset(&tv, 0, sizeof(tv)); \ - \ - StreamTcpUTInit(&ra_ctx); \ - \ - StreamTcpUTSetupSession(&ssn); \ - StreamTcpUTSetupStream(&ssn.server, (isn)); \ - StreamTcpUTSetupStream(&ssn.client, (isn)); \ - \ - TcpStream *stream = &ssn.client; \ +#define OVERLAP_START(isn, policy) \ + TcpReassemblyThreadCtx *ra_ctx = NULL; \ + TcpSession ssn; \ + ThreadVars tv; \ + memset(&tv, 0, sizeof(tv)); \ + \ + StreamTcpUTInit(&ra_ctx); \ + \ + StreamTcpUTSetupSession(&ssn); \ + StreamTcpUTSetupStream(&ssn.server, (isn)); \ + StreamTcpUTSetupStream(&ssn.client, (isn)); \ + \ + TcpStream *stream = &ssn.client; \ stream->os_policy = (policy); -#define OVERLAP_END \ - StreamTcpUTClearSession(&ssn); \ - StreamTcpUTDeinit(ra_ctx); \ +#define OVERLAP_END \ + StreamTcpUTClearSession(&ssn); \ + StreamTcpUTDeinit(ra_ctx); \ PASS -#define OVERLAP_STEP(rseq, seg, seglen, buf, buflen) \ - StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, stream->isn + (rseq), (uint8_t *)(seg), (seglen)); \ +#define OVERLAP_STEP(rseq, seg, seglen, buf, buflen) \ + StreamTcpUTAddPayload( \ + &tv, ra_ctx, &ssn, stream, stream->isn + (rseq), (uint8_t *)(seg), (seglen)); \ FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen)))); static int OverlapBSD(uint32_t isn) @@ -105,7 +106,7 @@ static int OverlapBSDBefore(uint32_t isn) OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13); - OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13); + OVERLAP_STEP(11, "MMM", 3, "JJJJ\0\0\0LLLMMM", 13); OVERLAP_END; } @@ -185,7 +186,7 @@ static int OverlapVISTABefore(uint32_t isn) OVERLAP_STEP(2, "AA", 2, "\0AB\0\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(1, "JJJJ", 4, "JABJ\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(8, "LLL", 3, "JABJ\0\0\0LDL\0EE", 13); - OVERLAP_STEP(11,"MMM", 3, "JABJ\0\0\0LDLMEE", 13); + OVERLAP_STEP(11, "MMM", 3, "JABJ\0\0\0LDLMEE", 13); OVERLAP_END; } @@ -263,7 +264,7 @@ static int OverlapLINUXBefore(uint32_t isn) OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13); - OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13); + OVERLAP_STEP(11, "MMM", 3, "JJJJ\0\0\0LLLMMM", 13); OVERLAP_END; } @@ -341,7 +342,7 @@ static int OverlapLINUXOLDBefore(uint32_t isn) OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13); - OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13); + OVERLAP_STEP(11, "MMM", 3, "JJJJ\0\0\0LLLMMM", 13); OVERLAP_END; } @@ -418,7 +419,7 @@ static int OverlapSOLARISBefore(uint32_t isn) OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13); - OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13); + OVERLAP_STEP(11, "MMM", 3, "JJJJ\0\0\0LLLMMM", 13); OVERLAP_END; } @@ -488,7 +489,7 @@ static int OverlapLASTBefore(uint32_t isn) OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13); OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13); - OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13); + OVERLAP_STEP(11, "MMM", 3, "JJJJ\0\0\0LLLMMM", 13); OVERLAP_END; } @@ -548,7 +549,6 @@ static int StreamTcpReassembleTest01(void) return 1; } - /** \test Vista Policy */ static int StreamTcpReassembleTest02(void) @@ -575,7 +575,6 @@ static int StreamTcpReassembleTest02(void) return 1; } - /** \test Linux policy */ static int StreamTcpReassembleTest03(void) @@ -680,7 +679,7 @@ static int StreamTcpReassembleTest06(void) return 1; } -static int StreamTcpReassembleTest30 (void) +static int StreamTcpReassembleTest30(void) { OVERLAP_START(9, OS_POLICY_BSD); OVERLAP_STEP(3, "BBB", 3, "\0\0BBB", 5); @@ -688,7 +687,7 @@ static int StreamTcpReassembleTest30 (void) OVERLAP_END; } -static int StreamTcpReassembleTest31 (void) +static int StreamTcpReassembleTest31(void) { OVERLAP_START(9, OS_POLICY_BSD); OVERLAP_STEP(1, "AA", 2, "AA", 2); @@ -701,32 +700,25 @@ static int StreamTcpReassembleTest32(void) OVERLAP_START(0, OS_POLICY_BSD); OVERLAP_STEP(11, "AAAAAAAAAA", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAA", 20); OVERLAP_STEP(21, "BBBBBBBBBB", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAABBBBBBBBBB", 30); - OVERLAP_STEP(41, "CCCCCCCCCC", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAABBBBBBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50); - OVERLAP_STEP(6, "aaaaaaaaaaaaaaaaaaaa", 20, "\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50); - OVERLAP_STEP(1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50); + OVERLAP_STEP(41, "CCCCCCCCCC", 10, + "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAABBBBBBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50); + OVERLAP_STEP(6, "aaaaaaaaaaaaaaaaaaaa", 20, + "\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50); + OVERLAP_STEP(1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50, + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50); OVERLAP_END; } void StreamTcpListRegisterTests(void) { - UtRegisterTest("StreamTcpReassembleTest01 -- BSD policy", - StreamTcpReassembleTest01); - UtRegisterTest("StreamTcpReassembleTest02 -- VISTA policy", - StreamTcpReassembleTest02); - UtRegisterTest("StreamTcpReassembleTest03 -- LINUX policy", - StreamTcpReassembleTest03); - UtRegisterTest("StreamTcpReassembleTest04 -- LINUX-OLD policy", - StreamTcpReassembleTest04); - UtRegisterTest("StreamTcpReassembleTest05 -- SOLARIS policy", - StreamTcpReassembleTest05); - UtRegisterTest("StreamTcpReassembleTest06 -- LAST policy", - StreamTcpReassembleTest06); - - UtRegisterTest("StreamTcpReassembleTest30", - StreamTcpReassembleTest30); - UtRegisterTest("StreamTcpReassembleTest31", - StreamTcpReassembleTest31); - UtRegisterTest("StreamTcpReassembleTest32", - StreamTcpReassembleTest32); + UtRegisterTest("StreamTcpReassembleTest01 -- BSD policy", StreamTcpReassembleTest01); + UtRegisterTest("StreamTcpReassembleTest02 -- VISTA policy", StreamTcpReassembleTest02); + UtRegisterTest("StreamTcpReassembleTest03 -- LINUX policy", StreamTcpReassembleTest03); + UtRegisterTest("StreamTcpReassembleTest04 -- LINUX-OLD policy", StreamTcpReassembleTest04); + UtRegisterTest("StreamTcpReassembleTest05 -- SOLARIS policy", StreamTcpReassembleTest05); + UtRegisterTest("StreamTcpReassembleTest06 -- LAST policy", StreamTcpReassembleTest06); + UtRegisterTest("StreamTcpReassembleTest30", StreamTcpReassembleTest30); + UtRegisterTest("StreamTcpReassembleTest31", StreamTcpReassembleTest31); + UtRegisterTest("StreamTcpReassembleTest32", StreamTcpReassembleTest32); } diff --git a/src/tests/stream-tcp-reassemble.c b/src/tests/stream-tcp-reassemble.c index 5f07f336c4d8..c19f41997ca5 100644 --- a/src/tests/stream-tcp-reassemble.c +++ b/src/tests/stream-tcp-reassemble.c @@ -22,9 +22,9 @@ #include "../stream-tcp-inline.h" #include "../stream-tcp-list.h" #include "../stream-tcp-util.h" -#include "../util-streaming-buffer.h" -#include "../util-print.h" -#include "../util-unittest.h" +#include "../util/streaming-buffer.h" +#include "../util/print.h" +#include "../util/unittest.h" struct TestReassembleRawCallbackData { const uint8_t *expect_data; @@ -38,8 +38,7 @@ static int TestReassembleRawCallback( SCLogNotice("have %u expect %u", data_len, cb->expect_data_len); - if (data_len == cb->expect_data_len && - memcmp(data, cb->expect_data, data_len) == 0) { + if (data_len == cb->expect_data_len && memcmp(data, cb->expect_data, data_len) == 0) { return 1; } else { SCLogNotice("data mismatch. Expected:"); @@ -50,8 +49,8 @@ static int TestReassembleRawCallback( } } -static int TestReassembleRawValidate(TcpSession *ssn, Packet *p, - const uint8_t *data, const uint32_t data_len) +static int TestReassembleRawValidate( + TcpSession *ssn, Packet *p, const uint8_t *data, const uint32_t data_len) { struct TestReassembleRawCallbackData cb = { data, data_len }; uint64_t progress = 0; @@ -63,56 +62,56 @@ static int TestReassembleRawValidate(TcpSession *ssn, Packet *p, return r; } -#define RAWREASSEMBLY_START(isn) \ - TcpReassemblyThreadCtx *ra_ctx = NULL; \ - TcpSession ssn; \ - ThreadVars tv; \ - memset(&tv, 0, sizeof(tv)); \ - Packet *p = NULL; \ - \ - \ - StreamTcpUTInit(&ra_ctx); \ - StreamTcpUTInitInline(); \ - stream_config.reassembly_toserver_chunk_size = 9; \ - stream_config.reassembly_toclient_chunk_size = 9; \ - StreamTcpUTSetupSession(&ssn); \ - StreamTcpUTSetupStream(&ssn.server, (isn)); \ - StreamTcpUTSetupStream(&ssn.client, (isn)); \ - ssn.server.last_ack = (isn) + 1; \ - ssn.client.last_ack = (isn) + 1; \ - \ +#define RAWREASSEMBLY_START(isn) \ + TcpReassemblyThreadCtx *ra_ctx = NULL; \ + TcpSession ssn; \ + ThreadVars tv; \ + memset(&tv, 0, sizeof(tv)); \ + Packet *p = NULL; \ + \ + StreamTcpUTInit(&ra_ctx); \ + StreamTcpUTInitInline(); \ + stream_config.reassembly_toserver_chunk_size = 9; \ + stream_config.reassembly_toclient_chunk_size = 9; \ + StreamTcpUTSetupSession(&ssn); \ + StreamTcpUTSetupStream(&ssn.server, (isn)); \ + StreamTcpUTSetupStream(&ssn.client, (isn)); \ + ssn.server.last_ack = (isn) + 1; \ + ssn.client.last_ack = (isn) + 1; \ + \ TcpStream *stream = &ssn.client; -#define RAWREASSEMBLY_END \ - StreamTcpUTClearSession(&ssn); \ - StreamTcpUTDeinit(ra_ctx); \ +#define RAWREASSEMBLY_END \ + StreamTcpUTClearSession(&ssn); \ + StreamTcpUTDeinit(ra_ctx); \ PASS -#define RAWREASSEMBLY_STEP(seq, seg, seglen, buf, buflen) \ - p = PacketGetFromAlloc(); \ - FAIL_IF_NULL(p); \ - { \ - SCLogNotice("SEQ %u block of %u", (seq), (seglen)); \ - p->flowflags = FLOW_PKT_TOSERVER; \ - TCPHdr tcphdr; \ - memset(&tcphdr, 0, sizeof(tcphdr)); \ - p->tcph = &tcphdr; \ - p->tcph->th_seq = htonl((seq)); \ - p->tcph->th_ack = htonl(10); \ - p->payload_len = (seglen); \ - \ - FAIL_IF(StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)) != 0); \ - p->flags |= PKT_STREAM_ADD; \ - FAIL_IF(!(TestReassembleRawValidate(&ssn, p, (uint8_t *)(buf), (buflen)))); \ - }\ +#define RAWREASSEMBLY_STEP(seq, seg, seglen, buf, buflen) \ + p = PacketGetFromAlloc(); \ + FAIL_IF_NULL(p); \ + { \ + SCLogNotice("SEQ %u block of %u", (seq), (seglen)); \ + p->flowflags = FLOW_PKT_TOSERVER; \ + TCPHdr tcphdr; \ + memset(&tcphdr, 0, sizeof(tcphdr)); \ + p->tcph = &tcphdr; \ + p->tcph->th_seq = htonl((seq)); \ + p->tcph->th_ack = htonl(10); \ + p->payload_len = (seglen); \ + \ + FAIL_IF(StreamTcpUTAddPayload( \ + &tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)) != 0); \ + p->flags |= PKT_STREAM_ADD; \ + FAIL_IF(!(TestReassembleRawValidate(&ssn, p, (uint8_t *)(buf), (buflen)))); \ + } \ PacketFree(p); -#define RAWREASSEMBLY_STEP_WITH_PROGRESS(seq, seg, seglen, buf, buflen, lastack, progress) \ - stream->last_ack = (lastack); \ - RAWREASSEMBLY_STEP((seq),(seg),(seglen),(buf),(buflen)); \ +#define RAWREASSEMBLY_STEP_WITH_PROGRESS(seq, seg, seglen, buf, buflen, lastack, progress) \ + stream->last_ack = (lastack); \ + RAWREASSEMBLY_STEP((seq), (seg), (seglen), (buf), (buflen)); \ FAIL_IF(STREAM_RAW_PROGRESS(stream) != (progress)); -static int StreamTcpReassembleRawTest01 (void) +static int StreamTcpReassembleRawTest01(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3); @@ -121,64 +120,64 @@ static int StreamTcpReassembleRawTest01 (void) RAWREASSEMBLY_END; } -static int StreamTcpReassembleRawTest02 (void) +static int StreamTcpReassembleRawTest02(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3); RAWREASSEMBLY_STEP(5, "BBB", 3, "AAABBB", 6); - RAWREASSEMBLY_STEP(11,"DDD", 3, "DDD", 3); + RAWREASSEMBLY_STEP(11, "DDD", 3, "DDD", 3); RAWREASSEMBLY_STEP(8, "CCC", 3, "BBBCCCDDD", 9); RAWREASSEMBLY_END; } -static int StreamTcpReassembleRawTest03 (void) +static int StreamTcpReassembleRawTest03(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3); - RAWREASSEMBLY_STEP(11,"DDD", 3, "DDD", 3); + RAWREASSEMBLY_STEP(11, "DDD", 3, "DDD", 3); RAWREASSEMBLY_STEP(8, "CCC", 3, "CCCDDD", 6); RAWREASSEMBLY_END; } -static int StreamTcpReassembleRawTest04 (void) +static int StreamTcpReassembleRawTest04(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5); - RAWREASSEMBLY_STEP(10,"CCCCC", 5, "CCCCC", 5); + RAWREASSEMBLY_STEP(10, "CCCCC", 5, "CCCCC", 5); RAWREASSEMBLY_STEP(7, "BBB", 3, "AAABBBCCC", 9); RAWREASSEMBLY_END; } -static int StreamTcpReassembleRawTest05 (void) +static int StreamTcpReassembleRawTest05(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5); - RAWREASSEMBLY_STEP(10,"CCCCC", 5, "CCCCC", 5); + RAWREASSEMBLY_STEP(10, "CCCCC", 5, "CCCCC", 5); RAWREASSEMBLY_STEP(2, "EEEEEEEEEEEEE", 13, "AAAAAEEECCCCC", 13); RAWREASSEMBLY_END; } -static int StreamTcpReassembleRawTest06 (void) +static int StreamTcpReassembleRawTest06(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5); - RAWREASSEMBLY_STEP(16,"CCCCC", 5, "CCCCC", 5); + RAWREASSEMBLY_STEP(16, "CCCCC", 5, "CCCCC", 5); RAWREASSEMBLY_STEP(7, "BBBBBBBBB", 9, "ABBBBBBBBBC", 11); - RAWREASSEMBLY_STEP(21,"DDDDDDDDDD",10,"CCCDDDDDDDDDD", 13); + RAWREASSEMBLY_STEP(21, "DDDDDDDDDD", 10, "CCCDDDDDDDDDD", 13); RAWREASSEMBLY_END; } -static int StreamTcpReassembleRawTest07 (void) +static int StreamTcpReassembleRawTest07(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP(2, "AAAAAAA", 7, "AAAAAAA", 7); RAWREASSEMBLY_STEP(9, "BBBBBBB", 7, "AAABBBBBBB", 10); - RAWREASSEMBLY_STEP(16,"C", 1, "ABBBBBBBC", 9); - RAWREASSEMBLY_STEP(17,"DDDDDDDD",8,"BBCDDDDDDDD", 11); + RAWREASSEMBLY_STEP(16, "C", 1, "ABBBBBBBC", 9); + RAWREASSEMBLY_STEP(17, "DDDDDDDD", 8, "BBCDDDDDDDD", 11); RAWREASSEMBLY_END; } -static int StreamTcpReassembleRawTest08 (void) +static int StreamTcpReassembleRawTest08(void) { RAWREASSEMBLY_START(1); RAWREASSEMBLY_STEP_WITH_PROGRESS(2, "AAA", 3, "AAA", 3, 3, 3); @@ -190,20 +189,12 @@ static int StreamTcpReassembleRawTest08 (void) static void StreamTcpReassembleRawRegisterTests(void) { - UtRegisterTest("StreamTcpReassembleRawTest01", - StreamTcpReassembleRawTest01); - UtRegisterTest("StreamTcpReassembleRawTest02", - StreamTcpReassembleRawTest02); - UtRegisterTest("StreamTcpReassembleRawTest03", - StreamTcpReassembleRawTest03); - UtRegisterTest("StreamTcpReassembleRawTest04", - StreamTcpReassembleRawTest04); - UtRegisterTest("StreamTcpReassembleRawTest05", - StreamTcpReassembleRawTest05); - UtRegisterTest("StreamTcpReassembleRawTest06", - StreamTcpReassembleRawTest06); - UtRegisterTest("StreamTcpReassembleRawTest07", - StreamTcpReassembleRawTest07); - UtRegisterTest("StreamTcpReassembleRawTest08", - StreamTcpReassembleRawTest08); + UtRegisterTest("StreamTcpReassembleRawTest01", StreamTcpReassembleRawTest01); + UtRegisterTest("StreamTcpReassembleRawTest02", StreamTcpReassembleRawTest02); + UtRegisterTest("StreamTcpReassembleRawTest03", StreamTcpReassembleRawTest03); + UtRegisterTest("StreamTcpReassembleRawTest04", StreamTcpReassembleRawTest04); + UtRegisterTest("StreamTcpReassembleRawTest05", StreamTcpReassembleRawTest05); + UtRegisterTest("StreamTcpReassembleRawTest06", StreamTcpReassembleRawTest06); + UtRegisterTest("StreamTcpReassembleRawTest07", StreamTcpReassembleRawTest07); + UtRegisterTest("StreamTcpReassembleRawTest08", StreamTcpReassembleRawTest08); } diff --git a/src/tests/stream-tcp.c b/src/tests/stream-tcp.c index 32ccb73f92cb..5edda5e7f8e5 100644 --- a/src/tests/stream-tcp.c +++ b/src/tests/stream-tcp.c @@ -22,9 +22,9 @@ #include "../stream-tcp-inline.h" #include "../stream-tcp-list.h" #include "../stream-tcp-util.h" -#include "../util-streaming-buffer.h" -#include "../util-print.h" -#include "../util-unittest.h" +#include "../util/streaming-buffer.h" +#include "../util/print.h" +#include "../util/unittest.h" #define SET_ISN(stream, setseq) \ (stream)->isn = (setseq); \ diff --git a/src/threads-debug.h b/src/threads-debug.h index 2946d9140f26..f3b8e24ec2ef 100644 --- a/src/threads-debug.h +++ b/src/threads-debug.h @@ -34,209 +34,250 @@ * It is for Mac OS X users; * If you see a mutex, spinlock or condition not initialized, report it please! */ -#define SCMutexLock_dbg(mut) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") locking mutex %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut); \ - int retl = pthread_mutex_lock(mut); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); \ - if (retl != 0) { \ - switch (retl) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - retl = pthread_mutex_init(mut, NULL); \ - if (retl != 0) \ - exit(EXIT_FAILURE); \ - retl = pthread_mutex_lock(mut); \ - break; \ - case EDEADLK: \ - printf("A deadlock would occur if the thread blocked waiting for mutex\n"); \ - break; \ - } \ - } \ - retl; \ -}) +#define SCMutexLock_dbg(mut) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") locking mutex %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), mut); \ + int retl = pthread_mutex_lock(mut); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") locked mutex %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); \ + if (retl != 0) { \ + switch (retl) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + retl = pthread_mutex_init(mut, NULL); \ + if (retl != 0) \ + exit(EXIT_FAILURE); \ + retl = pthread_mutex_lock(mut); \ + break; \ + case EDEADLK: \ + printf("A deadlock would occur if the thread blocked waiting for mutex\n"); \ + break; \ + } \ + } \ + retl; \ + }) -#define SCMutexTrylock_dbg(mut) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking mutex %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut); \ - int rett = pthread_mutex_trylock(mut); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, rett); \ - if (rett != 0) { \ - switch (rett) { \ - case EINVAL: \ - printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ - break; \ - case EBUSY: \ - printf("Mutex is already locked\n"); \ - break; \ - } \ - } \ - rett; \ -}) +#define SCMutexTrylock_dbg(mut) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocking mutex %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), mut); \ + int rett = pthread_mutex_trylock(mut); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocked mutex %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, rett); \ + if (rett != 0) { \ + switch (rett) { \ + case EINVAL: \ + printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, \ + __FILE__, __LINE__); \ + break; \ + case EBUSY: \ + printf("Mutex is already locked\n"); \ + break; \ + } \ + } \ + rett; \ + }) -#define SCMutexInit_dbg(mut, mutattr) ({ \ - int ret; \ - ret = pthread_mutex_init(mut, mutattr); \ - if (ret != 0) { \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") mutex %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ - break; \ - case EAGAIN: \ - printf("The system temporarily lacks the resources to create another mutex\n"); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") mutex %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ - break; \ - case ENOMEM: \ - printf("The process cannot allocate enough memory to create another mutex\n"); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") mutex %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ - break; \ - } \ - } \ - ret; \ -}) +#define SCMutexInit_dbg(mut, mutattr) \ + ({ \ + int ret; \ + ret = pthread_mutex_init(mut, mutattr); \ + if (ret != 0) { \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX \ + ") mutex %p initialization returned %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, \ + ret); \ + break; \ + case EAGAIN: \ + printf("The system temporarily lacks the resources to create another " \ + "mutex\n"); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX \ + ") mutex %p initialization returned %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, \ + ret); \ + break; \ + case ENOMEM: \ + printf("The process cannot allocate enough memory to create another mutex\n"); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX \ + ") mutex %p initialization returned %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, \ + ret); \ + break; \ + } \ + } \ + ret; \ + }) -#define SCMutexUnlock_dbg(mut) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocking mutex %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut); \ - int retu = pthread_mutex_unlock(mut); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retu); \ - if (retu != 0) { \ - switch (retu) { \ - case EINVAL: \ - printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ - break; \ - case EPERM: \ - printf("The current thread does not hold a lock on mutex\n"); \ - break; \ - } \ - } \ - retu; \ -}) +#define SCMutexUnlock_dbg(mut) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") unlocking mutex %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), mut); \ + int retu = pthread_mutex_unlock(mut); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") unlocked mutex %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retu); \ + if (retu != 0) { \ + switch (retu) { \ + case EINVAL: \ + printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, \ + __FILE__, __LINE__); \ + break; \ + case EPERM: \ + printf("The current thread does not hold a lock on mutex\n"); \ + break; \ + } \ + } \ + retu; \ + }) -#define SCMutex pthread_mutex_t -#define SCMutexAttr pthread_mutexattr_t +#define SCMutex pthread_mutex_t +#define SCMutexAttr pthread_mutexattr_t #define SCMutexInit(mut, mutattrs) SCMutexInit_dbg(mut, mutattrs) -#define SCMutexLock(mut) SCMutexLock_dbg(mut) -#define SCMutexTrylock(mut) SCMutexTrylock_dbg(mut) -#define SCMutexUnlock(mut) SCMutexUnlock_dbg(mut) -#define SCMutexDestroy pthread_mutex_destroy -#define SCMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define SCMutexLock(mut) SCMutexLock_dbg(mut) +#define SCMutexTrylock(mut) SCMutexTrylock_dbg(mut) +#define SCMutexUnlock(mut) SCMutexUnlock_dbg(mut) +#define SCMutexDestroy pthread_mutex_destroy +#define SCMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER /* conditions */ -#define SCCondWait_dbg(cond, mut) ({ \ - int ret = pthread_cond_wait(cond, mut); \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid (or a SCCondT not initialized!)\n"); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") failed SCCondWait %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ - break; \ - } \ - ret; \ -}) +#define SCCondWait_dbg(cond, mut) \ + ({ \ + int ret = pthread_cond_wait(cond, mut); \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid (or a SCCondT not " \ + "initialized!)\n"); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") failed SCCondWait %p ret %" PRId32 \ + "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, ret); \ + break; \ + } \ + ret; \ + }) /* conditions */ -#define SCCondT pthread_cond_t -#define SCCondInit pthread_cond_init -#define SCCondSignal pthread_cond_signal +#define SCCondT pthread_cond_t +#define SCCondInit pthread_cond_init +#define SCCondSignal pthread_cond_signal #define SCCondDestroy pthread_cond_destroy -#define SCCondWait SCCondWait_dbg +#define SCCondWait SCCondWait_dbg /* spinlocks */ -#define SCSpinLock_dbg(spin) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") locking spin %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ - int ret = pthread_spin_lock(spin); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocked spin %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - break; \ - case EDEADLK: \ - printf("A deadlock would occur if the thread blocked waiting for spin\n"); \ - break; \ - } \ - ret; \ -}) +#define SCSpinLock_dbg(spin) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") locking spin %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), spin); \ + int ret = pthread_spin_lock(spin); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") unlocked spin %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + break; \ + case EDEADLK: \ + printf("A deadlock would occur if the thread blocked waiting for spin\n"); \ + break; \ + } \ + ret; \ + }) -#define SCSpinTrylock_dbg(spin) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking spin %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ - int ret = pthread_spin_trylock(spin); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked spin %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - break; \ - case EDEADLK: \ - printf("A deadlock would occur if the thread blocked waiting for spin\n"); \ - break; \ - case EBUSY: \ - printf("A thread currently holds the lock\n"); \ - break; \ - } \ - ret; \ -}) +#define SCSpinTrylock_dbg(spin) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocking spin %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), spin); \ + int ret = pthread_spin_trylock(spin); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocked spin %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + break; \ + case EDEADLK: \ + printf("A deadlock would occur if the thread blocked waiting for spin\n"); \ + break; \ + case EBUSY: \ + printf("A thread currently holds the lock\n"); \ + break; \ + } \ + ret; \ + }) -#define SCSpinUnlock_dbg(spin) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocking spin %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ - int ret = pthread_spin_unlock(spin); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") unlockedspin %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - break; \ - case EPERM: \ - printf("The calling thread does not hold the lock\n"); \ - break; \ - } \ - ret; \ -}) +#define SCSpinUnlock_dbg(spin) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") unlocking spin %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), spin); \ + int ret = pthread_spin_unlock(spin); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") unlockedspin %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + break; \ + case EPERM: \ + printf("The calling thread does not hold the lock\n"); \ + break; \ + } \ + ret; \ + }) -#define SCSpinInit_dbg(spin, spin_attr) ({ \ - int ret = pthread_spin_init(spin, spin_attr); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") spinlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - break; \ - case EBUSY: \ - printf("A thread currently holds the lock\n"); \ - break; \ - case ENOMEM: \ - printf("The process cannot allocate enough memory to create another spin\n"); \ - break; \ - case EAGAIN: \ - printf("The system temporarily lacks the resources to create another spin\n"); \ - break; \ - } \ - ret; \ -}) +#define SCSpinInit_dbg(spin, spin_attr) \ + ({ \ + int ret = pthread_spin_init(spin, spin_attr); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") spinlock %p initialization returned %" PRId32 \ + "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + break; \ + case EBUSY: \ + printf("A thread currently holds the lock\n"); \ + break; \ + case ENOMEM: \ + printf("The process cannot allocate enough memory to create another spin\n"); \ + break; \ + case EAGAIN: \ + printf("The system temporarily lacks the resources to create another spin\n"); \ + break; \ + } \ + ret; \ + }) -#define SCSpinDestroy_dbg(spin) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") condition %p waiting\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ - int ret = pthread_spin_destroy(spin); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") condition %p passed %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - break; \ - case EBUSY: \ - printf("A thread currently holds the lock\n"); \ - break; \ - case ENOMEM: \ - printf("The process cannot allocate enough memory to create another spin\n"); \ - break; \ - case EAGAIN: \ - printf("The system temporarily lacks the resources to create another spin\n"); \ - break; \ - } \ - ret; \ -}) +#define SCSpinDestroy_dbg(spin) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") condition %p waiting\n", __FUNCTION__, \ + __FILE__, __LINE__, (uintmax_t)pthread_self(), spin); \ + int ret = pthread_spin_destroy(spin); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") condition %p passed %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), spin, ret); \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + break; \ + case EBUSY: \ + printf("A thread currently holds the lock\n"); \ + break; \ + case ENOMEM: \ + printf("The process cannot allocate enough memory to create another spin\n"); \ + break; \ + case EAGAIN: \ + printf("The system temporarily lacks the resources to create another spin\n"); \ + break; \ + } \ + ret; \ + }) -#define SCSpinlock pthread_spinlock_t -#define SCSpinLock SCSpinLock_dbg -#define SCSpinTrylock SCSpinTrylock_dbg -#define SCSpinUnlock SCSpinUnlock_dbg -#define SCSpinInit SCSpinInit_dbg -#define SCSpinDestroy SCSpinDestroy_dbg +#define SCSpinlock pthread_spinlock_t +#define SCSpinLock SCSpinLock_dbg +#define SCSpinTrylock SCSpinTrylock_dbg +#define SCSpinUnlock SCSpinUnlock_dbg +#define SCSpinInit SCSpinInit_dbg +#define SCSpinDestroy SCSpinDestroy_dbg /* rwlocks */ @@ -244,146 +285,175 @@ * initialized, logged, and does a second try; This is to prevent the system to freeze; * If you see a rwlock, spinlock or condition not initialized, report it please! */ -#define SCRWLockRDLock_dbg(rwl) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") locking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ - int retl = pthread_rwlock_rdlock(rwl); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") locked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \ - if (retl != 0) { \ - switch (retl) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - retl = pthread_rwlock_init(rwl, NULL); \ - if (retl != 0) \ - exit(EXIT_FAILURE); \ - retl = pthread_rwlock_rdlock(rwl); \ - break; \ - case EDEADLK: \ - printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \ - break; \ - } \ - } \ - retl; \ -}) +#define SCRWLockRDLock_dbg(rwl) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") locking rwlock %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), rwl); \ + int retl = pthread_rwlock_rdlock(rwl); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") locked rwlock %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \ + if (retl != 0) { \ + switch (retl) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + retl = pthread_rwlock_init(rwl, NULL); \ + if (retl != 0) \ + exit(EXIT_FAILURE); \ + retl = pthread_rwlock_rdlock(rwl); \ + break; \ + case EDEADLK: \ + printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \ + break; \ + } \ + } \ + retl; \ + }) -#define SCRWLockWRLock_dbg(rwl) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") locking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ - int retl = pthread_rwlock_wrlock(rwl); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") locked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \ - if (retl != 0) { \ - switch (retl) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - retl = pthread_rwlock_init(rwl, NULL); \ - if (retl != 0) \ - exit(EXIT_FAILURE); \ - retl = pthread_rwlock_wrlock(rwl); \ - break; \ - case EDEADLK: \ - printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \ - break; \ - } \ - } \ - retl; \ -}) +#define SCRWLockWRLock_dbg(rwl) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") locking rwlock %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), rwl); \ + int retl = pthread_rwlock_wrlock(rwl); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") locked rwlock %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \ + if (retl != 0) { \ + switch (retl) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + retl = pthread_rwlock_init(rwl, NULL); \ + if (retl != 0) \ + exit(EXIT_FAILURE); \ + retl = pthread_rwlock_wrlock(rwl); \ + break; \ + case EDEADLK: \ + printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \ + break; \ + } \ + } \ + retl; \ + }) +#define SCRWLockTryWRLock_dbg(rwl) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocking rwlock %p\n", __FUNCTION__, \ + __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ + int rett = pthread_rwlock_trywrlock(rwl); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocked rwlock %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \ + if (rett != 0) { \ + switch (rett) { \ + case EINVAL: \ + printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, \ + __FILE__, __LINE__); \ + break; \ + case EBUSY: \ + printf("RWLock is already locked\n"); \ + break; \ + } \ + } \ + rett; \ + }) -#define SCRWLockTryWRLock_dbg(rwl) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ - int rett = pthread_rwlock_trywrlock(rwl); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \ - if (rett != 0) { \ - switch (rett) { \ - case EINVAL: \ - printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ - break; \ - case EBUSY: \ - printf("RWLock is already locked\n"); \ - break; \ - } \ - } \ - rett; \ -}) +#define SCRWLockTryRDLock_dbg(rwl) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocking rwlock %p\n", __FUNCTION__, \ + __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ + int rett = pthread_rwlock_tryrdlock(rwl); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") trylocked rwlock %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \ + if (rett != 0) { \ + switch (rett) { \ + case EINVAL: \ + printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, \ + __FILE__, __LINE__); \ + break; \ + case EBUSY: \ + printf("RWLock is already locked\n"); \ + break; \ + } \ + } \ + rett; \ + }) -#define SCRWLockTryRDLock_dbg(rwl) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ - int rett = pthread_rwlock_tryrdlock(rwl); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \ - if (rett != 0) { \ - switch (rett) { \ - case EINVAL: \ - printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ - break; \ - case EBUSY: \ - printf("RWLock is already locked\n"); \ - break; \ - } \ - } \ - rett; \ -}) +#define SCRWLockInit_dbg(rwl, rwlattr) \ + ({ \ + int ret; \ + ret = pthread_rwlock_init(rwl, rwlattr); \ + if (ret != 0) { \ + switch (ret) { \ + case EINVAL: \ + printf("The value specified by attr is invalid\n"); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX \ + ") rwlock %p initialization returned %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, \ + ret); \ + break; \ + case EAGAIN: \ + printf("The system temporarily lacks the resources to create another " \ + "rwlock\n"); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX \ + ") rwlock %p initialization returned %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, \ + ret); \ + break; \ + case ENOMEM: \ + printf("The process cannot allocate enough memory to create another " \ + "rwlock\n"); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX \ + ") rwlock %p initialization returned %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, \ + ret); \ + break; \ + } \ + } \ + ret; \ + }) -#define SCRWLockInit_dbg(rwl, rwlattr) ({ \ - int ret; \ - ret = pthread_rwlock_init(rwl, rwlattr); \ - if (ret != 0) { \ - switch (ret) { \ - case EINVAL: \ - printf("The value specified by attr is invalid\n"); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \ - break; \ - case EAGAIN: \ - printf("The system temporarily lacks the resources to create another rwlock\n"); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \ - break; \ - case ENOMEM: \ - printf("The process cannot allocate enough memory to create another rwlock\n"); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \ - break; \ - } \ - } \ - ret; \ -}) +#define SCRWLockUnlock_dbg(rwl) \ + ({ \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") unlocking rwlock %p\n", __FUNCTION__, __FILE__, \ + __LINE__, (uintmax_t)pthread_self(), rwl); \ + int retu = pthread_rwlock_unlock(rwl); \ + printf("%16s(%s:%d): (thread:%" PRIuMAX ") unlocked rwlock %p ret %" PRId32 "\n", \ + __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retu); \ + if (retu != 0) { \ + switch (retu) { \ + case EINVAL: \ + printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, \ + __FILE__, __LINE__); \ + break; \ + case EPERM: \ + printf("The current thread does not hold a lock on rwlock\n"); \ + break; \ + } \ + } \ + retu; \ + }) -#define SCRWLockUnlock_dbg(rwl) ({ \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \ - int retu = pthread_rwlock_unlock(rwl); \ - printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retu); \ - if (retu != 0) { \ - switch (retu) { \ - case EINVAL: \ - printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \ - break; \ - case EPERM: \ - printf("The current thread does not hold a lock on rwlock\n"); \ - break; \ - } \ - } \ - retu; \ -}) - -#define SCRWLock pthread_rwlock_t +#define SCRWLock pthread_rwlock_t #define SCRWLockInit(rwl, rwlattrs) SCRWLockInit_dbg(rwl, rwlattrs) -#define SCRWLockRDLock(rwl) SCRWLockRDLock_dbg(rwl) -#define SCRWLockWRLock(rwl) SCRWLockWRLock_dbg(rwl) -#define SCRWLockTryWRLock(rwl) SCRWLockTryWRLock_dbg(rwl) -#define SCRWLockTryRDLock(rwl) SCRWLockTryRDLock_dbg(rwl) -#define SCRWLockUnlock(rwl) SCRWLockUnlock_dbg(rwl) -#define SCRWLockDestroy pthread_rwlock_destroy +#define SCRWLockRDLock(rwl) SCRWLockRDLock_dbg(rwl) +#define SCRWLockWRLock(rwl) SCRWLockWRLock_dbg(rwl) +#define SCRWLockTryWRLock(rwl) SCRWLockTryWRLock_dbg(rwl) +#define SCRWLockTryRDLock(rwl) SCRWLockTryRDLock_dbg(rwl) +#define SCRWLockUnlock(rwl) SCRWLockUnlock_dbg(rwl) +#define SCRWLockDestroy pthread_rwlock_destroy /* ctrl mutex */ -#define SCCtrlMutex pthread_mutex_t -#define SCCtrlMutexAttr pthread_mutexattr_t -#define SCCtrlMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) -#define SCCtrlMutexLock(mut) pthread_mutex_lock(mut) -#define SCCtrlMutexTrylock(mut) pthread_mutex_trylock(mut) -#define SCCtrlMutexUnlock(mut) pthread_mutex_unlock(mut) -#define SCCtrlMutexDestroy pthread_mutex_destroy +#define SCCtrlMutex pthread_mutex_t +#define SCCtrlMutexAttr pthread_mutexattr_t +#define SCCtrlMutexInit(mut, mutattr) pthread_mutex_init(mut, mutattr) +#define SCCtrlMutexLock(mut) pthread_mutex_lock(mut) +#define SCCtrlMutexTrylock(mut) pthread_mutex_trylock(mut) +#define SCCtrlMutexUnlock(mut) pthread_mutex_unlock(mut) +#define SCCtrlMutexDestroy pthread_mutex_destroy /* ctrl conditions */ -#define SCCtrlCondT pthread_cond_t -#define SCCtrlCondInit pthread_cond_init -#define SCCtrlCondSignal pthread_cond_signal +#define SCCtrlCondT pthread_cond_t +#define SCCtrlCondInit pthread_cond_init +#define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait -#define SCCtrlCondWait pthread_cond_wait -#define SCCtrlCondDestroy pthread_cond_destroy +#define SCCtrlCondWait pthread_cond_wait +#define SCCtrlCondDestroy pthread_cond_destroy #endif diff --git a/src/threads-profile.h b/src/threads-profile.h index 43606ae98290..7c6d3de2cf4c 100644 --- a/src/threads-profile.h +++ b/src/threads-profile.h @@ -27,7 +27,7 @@ #define __THREADS_PROFILE_H__ // UtilCpuGetTicks -#include "util-cpu.h" +#include "util/cpu.h" #define PROFILING_MAX_LOCKS 64 @@ -59,47 +59,49 @@ extern thread_local uint64_t mutex_lock_cnt; /* mutex */ -//printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); -#define SCMutexLock_profile(mut) ({ \ - mutex_lock_cnt++; \ - int retl = 0; \ - int cont = 0; \ - uint64_t mutex_lock_start = UtilCpuGetTicks(); \ - if (pthread_mutex_trylock((mut)) != 0) { \ - mutex_lock_contention++; \ - cont = 1; \ - retl = pthread_mutex_lock(mut); \ - } \ - uint64_t mutex_lock_end = UtilCpuGetTicks(); \ - mutex_lock_wait_ticks += (uint64_t)(mutex_lock_end - mutex_lock_start); \ - \ - if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ - locks[locks_idx].file = (char *)__FILE__; \ - locks[locks_idx].func = (char *)__func__; \ - locks[locks_idx].line = (int)__LINE__; \ - locks[locks_idx].type = LOCK_MUTEX; \ - locks[locks_idx].cont = cont; \ - locks[locks_idx].ticks = (uint64_t)(mutex_lock_end - mutex_lock_start); \ - locks_idx++; \ - } \ - retl; \ -}) - -#define SCMutex pthread_mutex_t -#define SCMutexAttr pthread_mutexattr_t -#define SCMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) -#define SCMutexLock(mut) SCMutexLock_profile(mut) -#define SCMutexTrylock(mut) pthread_mutex_trylock(mut) -#define SCMutexUnlock(mut) pthread_mutex_unlock(mut) -#define SCMutexDestroy pthread_mutex_destroy -#define SCMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +// printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, +// __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); +#define SCMutexLock_profile(mut) \ + ({ \ + mutex_lock_cnt++; \ + int retl = 0; \ + int cont = 0; \ + uint64_t mutex_lock_start = UtilCpuGetTicks(); \ + if (pthread_mutex_trylock((mut)) != 0) { \ + mutex_lock_contention++; \ + cont = 1; \ + retl = pthread_mutex_lock(mut); \ + } \ + uint64_t mutex_lock_end = UtilCpuGetTicks(); \ + mutex_lock_wait_ticks += (uint64_t)(mutex_lock_end - mutex_lock_start); \ + \ + if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ + locks[locks_idx].file = (char *)__FILE__; \ + locks[locks_idx].func = (char *)__func__; \ + locks[locks_idx].line = (int)__LINE__; \ + locks[locks_idx].type = LOCK_MUTEX; \ + locks[locks_idx].cont = cont; \ + locks[locks_idx].ticks = (uint64_t)(mutex_lock_end - mutex_lock_start); \ + locks_idx++; \ + } \ + retl; \ + }) + +#define SCMutex pthread_mutex_t +#define SCMutexAttr pthread_mutexattr_t +#define SCMutexInit(mut, mutattr) pthread_mutex_init(mut, mutattr) +#define SCMutexLock(mut) SCMutexLock_profile(mut) +#define SCMutexTrylock(mut) pthread_mutex_trylock(mut) +#define SCMutexUnlock(mut) pthread_mutex_unlock(mut) +#define SCMutexDestroy pthread_mutex_destroy +#define SCMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER /* conditions */ -#define SCCondT pthread_cond_t -#define SCCondInit pthread_cond_init -#define SCCondSignal pthread_cond_signal -#define SCCondDestroy pthread_cond_destroy +#define SCCondT pthread_cond_t +#define SCCondInit pthread_cond_init +#define SCCondSignal pthread_cond_signal +#define SCCondDestroy pthread_cond_destroy #define SCCondWait(cond, mut) pthread_cond_wait(cond, mut) /* spinlocks */ @@ -108,38 +110,40 @@ extern thread_local uint64_t spin_lock_contention; extern thread_local uint64_t spin_lock_wait_ticks; extern thread_local uint64_t spin_lock_cnt; -//printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); -#define SCSpinLock_profile(spin) ({ \ - spin_lock_cnt++; \ - int retl = 0; \ - int cont = 0; \ - uint64_t spin_lock_start = UtilCpuGetTicks(); \ - if (pthread_spin_trylock((spin)) != 0) { \ - spin_lock_contention++; \ - cont = 1; \ - retl = pthread_spin_lock((spin)); \ - } \ - uint64_t spin_lock_end = UtilCpuGetTicks(); \ - spin_lock_wait_ticks += (uint64_t)(spin_lock_end - spin_lock_start); \ - \ - if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ - locks[locks_idx].file = (char *)__FILE__; \ - locks[locks_idx].func = (char *)__func__; \ - locks[locks_idx].line = (int)__LINE__; \ - locks[locks_idx].type = LOCK_SPIN; \ - locks[locks_idx].cont = cont; \ - locks[locks_idx].ticks = (uint64_t)(spin_lock_end - spin_lock_start); \ - locks_idx++; \ - } \ - retl; \ -}) - -#define SCSpinlock pthread_spinlock_t -#define SCSpinLock(mut) SCSpinLock_profile(mut) -#define SCSpinTrylock(spin) pthread_spin_trylock(spin) -#define SCSpinUnlock(spin) pthread_spin_unlock(spin) -#define SCSpinInit(spin, spin_attr) pthread_spin_init(spin, spin_attr) -#define SCSpinDestroy(spin) pthread_spin_destroy(spin) +// printf("%16s(%s:%d): (thread:%"PRIuMAX") locked mutex %p ret %" PRId32 "\n", __FUNCTION__, +// __FILE__, __LINE__, (uintmax_t)pthread_self(), mut, retl); +#define SCSpinLock_profile(spin) \ + ({ \ + spin_lock_cnt++; \ + int retl = 0; \ + int cont = 0; \ + uint64_t spin_lock_start = UtilCpuGetTicks(); \ + if (pthread_spin_trylock((spin)) != 0) { \ + spin_lock_contention++; \ + cont = 1; \ + retl = pthread_spin_lock((spin)); \ + } \ + uint64_t spin_lock_end = UtilCpuGetTicks(); \ + spin_lock_wait_ticks += (uint64_t)(spin_lock_end - spin_lock_start); \ + \ + if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ + locks[locks_idx].file = (char *)__FILE__; \ + locks[locks_idx].func = (char *)__func__; \ + locks[locks_idx].line = (int)__LINE__; \ + locks[locks_idx].type = LOCK_SPIN; \ + locks[locks_idx].cont = cont; \ + locks[locks_idx].ticks = (uint64_t)(spin_lock_end - spin_lock_start); \ + locks_idx++; \ + } \ + retl; \ + }) + +#define SCSpinlock pthread_spinlock_t +#define SCSpinLock(mut) SCSpinLock_profile(mut) +#define SCSpinTrylock(spin) pthread_spin_trylock(spin) +#define SCSpinUnlock(spin) pthread_spin_unlock(spin) +#define SCSpinInit(spin, spin_attr) pthread_spin_init(spin, spin_attr) +#define SCSpinDestroy(spin) pthread_spin_destroy(spin) /* rwlocks */ @@ -147,84 +151,86 @@ extern thread_local uint64_t rww_lock_contention; extern thread_local uint64_t rww_lock_wait_ticks; extern thread_local uint64_t rww_lock_cnt; -#define SCRWLockWRLock_profile(mut) ({ \ - rww_lock_cnt++; \ - int retl = 0; \ - int cont = 0; \ - uint64_t rww_lock_start = UtilCpuGetTicks(); \ - if (pthread_rwlock_trywrlock((mut)) != 0) { \ - rww_lock_contention++; \ - cont = 1; \ - retl = pthread_rwlock_wrlock(mut); \ - } \ - uint64_t rww_lock_end = UtilCpuGetTicks(); \ - rww_lock_wait_ticks += (uint64_t)(rww_lock_end - rww_lock_start); \ - \ - if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ - locks[locks_idx].file = (char *)__FILE__; \ - locks[locks_idx].func = (char *)__func__; \ - locks[locks_idx].line = (int)__LINE__; \ - locks[locks_idx].type = LOCK_RWW; \ - locks[locks_idx].cont = cont; \ - locks[locks_idx].ticks = (uint64_t)(rww_lock_end - rww_lock_start); \ - locks_idx++; \ - } \ - retl; \ -}) +#define SCRWLockWRLock_profile(mut) \ + ({ \ + rww_lock_cnt++; \ + int retl = 0; \ + int cont = 0; \ + uint64_t rww_lock_start = UtilCpuGetTicks(); \ + if (pthread_rwlock_trywrlock((mut)) != 0) { \ + rww_lock_contention++; \ + cont = 1; \ + retl = pthread_rwlock_wrlock(mut); \ + } \ + uint64_t rww_lock_end = UtilCpuGetTicks(); \ + rww_lock_wait_ticks += (uint64_t)(rww_lock_end - rww_lock_start); \ + \ + if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ + locks[locks_idx].file = (char *)__FILE__; \ + locks[locks_idx].func = (char *)__func__; \ + locks[locks_idx].line = (int)__LINE__; \ + locks[locks_idx].type = LOCK_RWW; \ + locks[locks_idx].cont = cont; \ + locks[locks_idx].ticks = (uint64_t)(rww_lock_end - rww_lock_start); \ + locks_idx++; \ + } \ + retl; \ + }) extern thread_local uint64_t rwr_lock_contention; extern thread_local uint64_t rwr_lock_wait_ticks; extern thread_local uint64_t rwr_lock_cnt; -#define SCRWLockRDLock_profile(mut) ({ \ - rwr_lock_cnt++; \ - int retl = 0; \ - int cont = 0; \ - uint64_t rwr_lock_start = UtilCpuGetTicks(); \ - if (pthread_rwlock_tryrdlock((mut)) != 0) { \ - rwr_lock_contention++; \ - cont = 1; \ - retl = pthread_rwlock_rdlock(mut); \ - } \ - uint64_t rwr_lock_end = UtilCpuGetTicks(); \ - rwr_lock_wait_ticks += (uint64_t)(rwr_lock_end - rwr_lock_start); \ - \ - if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ - locks[locks_idx].file = (char *)__FILE__; \ - locks[locks_idx].func = (char *)__func__; \ - locks[locks_idx].line = (int)__LINE__; \ - locks[locks_idx].type = LOCK_RWR; \ - locks[locks_idx].cont = cont; \ - locks[locks_idx].ticks = (uint64_t)(rwr_lock_end - rwr_lock_start); \ - locks_idx++; \ - } \ - retl; \ -}) - -#define SCRWLock pthread_rwlock_t -#define SCRWLockInit(rwl, rwlattr ) pthread_rwlock_init(rwl, rwlattr) -#define SCRWLockWRLock(mut) SCRWLockWRLock_profile(mut) -#define SCRWLockRDLock(mut) SCRWLockRDLock_profile(mut) -#define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl) -#define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) -#define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl) -#define SCRWLockDestroy pthread_rwlock_destroy +#define SCRWLockRDLock_profile(mut) \ + ({ \ + rwr_lock_cnt++; \ + int retl = 0; \ + int cont = 0; \ + uint64_t rwr_lock_start = UtilCpuGetTicks(); \ + if (pthread_rwlock_tryrdlock((mut)) != 0) { \ + rwr_lock_contention++; \ + cont = 1; \ + retl = pthread_rwlock_rdlock(mut); \ + } \ + uint64_t rwr_lock_end = UtilCpuGetTicks(); \ + rwr_lock_wait_ticks += (uint64_t)(rwr_lock_end - rwr_lock_start); \ + \ + if (locks_idx < PROFILING_MAX_LOCKS && record_locks) { \ + locks[locks_idx].file = (char *)__FILE__; \ + locks[locks_idx].func = (char *)__func__; \ + locks[locks_idx].line = (int)__LINE__; \ + locks[locks_idx].type = LOCK_RWR; \ + locks[locks_idx].cont = cont; \ + locks[locks_idx].ticks = (uint64_t)(rwr_lock_end - rwr_lock_start); \ + locks_idx++; \ + } \ + retl; \ + }) + +#define SCRWLock pthread_rwlock_t +#define SCRWLockInit(rwl, rwlattr) pthread_rwlock_init(rwl, rwlattr) +#define SCRWLockWRLock(mut) SCRWLockWRLock_profile(mut) +#define SCRWLockRDLock(mut) SCRWLockRDLock_profile(mut) +#define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl) +#define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) +#define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl) +#define SCRWLockDestroy pthread_rwlock_destroy /* ctrl mutex */ -#define SCCtrlMutex pthread_mutex_t -#define SCCtrlMutexAttr pthread_mutexattr_t -#define SCCtrlMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) -#define SCCtrlMutexLock(mut) pthread_mutex_lock(mut) -#define SCCtrlMutexTrylock(mut) pthread_mutex_trylock(mut) -#define SCCtrlMutexUnlock(mut) pthread_mutex_unlock(mut) -#define SCCtrlMutexDestroy pthread_mutex_destroy +#define SCCtrlMutex pthread_mutex_t +#define SCCtrlMutexAttr pthread_mutexattr_t +#define SCCtrlMutexInit(mut, mutattr) pthread_mutex_init(mut, mutattr) +#define SCCtrlMutexLock(mut) pthread_mutex_lock(mut) +#define SCCtrlMutexTrylock(mut) pthread_mutex_trylock(mut) +#define SCCtrlMutexUnlock(mut) pthread_mutex_unlock(mut) +#define SCCtrlMutexDestroy pthread_mutex_destroy /* ctrl conditions */ -#define SCCtrlCondT pthread_cond_t -#define SCCtrlCondInit pthread_cond_init -#define SCCtrlCondSignal pthread_cond_signal +#define SCCtrlCondT pthread_cond_t +#define SCCtrlCondInit pthread_cond_init +#define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait -#define SCCtrlCondWait pthread_cond_wait -#define SCCtrlCondDestroy pthread_cond_destroy +#define SCCtrlCondWait pthread_cond_wait +#define SCCtrlCondDestroy pthread_cond_destroy #endif diff --git a/src/threads.c b/src/threads.c index 1708a8f5cd37..c50e2f1f2705 100644 --- a/src/threads.c +++ b/src/threads.c @@ -25,8 +25,8 @@ */ #include "suricata-common.h" -#include "util-unittest.h" -#include "util-debug.h" +#include "util/unittest.h" +#include "util/debug.h" #include "threads.h" thread_local char t_thread_name[THREAD_NAME_LEN + 1]; @@ -41,11 +41,11 @@ static int ThreadMacrosTest01Mutex(void) int r = 0; r |= SCMutexInit(&mut, NULL); r |= SCMutexLock(&mut); - r |= (SCMutexTrylock(&mut) == EBUSY)? 0 : 1; + r |= (SCMutexTrylock(&mut) == EBUSY) ? 0 : 1; r |= SCMutexUnlock(&mut); r |= SCMutexDestroy(&mut); - return (r == 0)? 1 : 0; + return (r == 0) ? 1 : 0; } /** @@ -70,14 +70,14 @@ static int ThreadMacrosTest02Spinlocks(void) r |= SCSpinInit(&mut, 0); r |= SCSpinLock(&mut); #ifndef __OpenBSD__ - r |= (SCSpinTrylock(&mut) == EBUSY)? 0 : 1; + r |= (SCSpinTrylock(&mut) == EBUSY) ? 0 : 1; #else - r |= (SCSpinTrylock(&mut) == EDEADLK)? 0 : 1; + r |= (SCSpinTrylock(&mut) == EDEADLK) ? 0 : 1; #endif r |= SCSpinUnlock(&mut); r |= SCSpinDestroy(&mut); - return (r == 0)? 1 : 0; + return (r == 0) ? 1 : 0; } /** @@ -91,15 +91,15 @@ static int ThreadMacrosTest03RWLocks(void) r |= SCRWLockWRLock(&rwl_write); /* OS X/macOS 10.10 (Yosemite) and newer return EDEADLK. Older versions * and other tested OS's return EBUSY. */ -#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__>=101000 - r |= (SCRWLockTryWRLock(&rwl_write) == EDEADLK)? 0 : 1; +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000 + r |= (SCRWLockTryWRLock(&rwl_write) == EDEADLK) ? 0 : 1; #else - r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY)? 0 : 1; + r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY) ? 0 : 1; #endif r |= SCRWLockUnlock(&rwl_write); r |= SCRWLockDestroy(&rwl_write); - return (r == 0)? 1 : 0; + return (r == 0) ? 1 : 0; } /** @@ -111,11 +111,11 @@ static int ThreadMacrosTest04RWLocks(void) int r = 0; r |= SCRWLockInit(&rwl_read, NULL); r |= SCRWLockRDLock(&rwl_read); - r |= (SCRWLockTryWRLock(&rwl_read) == EBUSY)? 0 : 1; + r |= (SCRWLockTryWRLock(&rwl_read) == EBUSY) ? 0 : 1; r |= SCRWLockUnlock(&rwl_read); r |= SCRWLockDestroy(&rwl_read); - return (r == 0)? 1 : 0; + return (r == 0) ? 1 : 0; } #if 0 // broken on OSX diff --git a/src/threads.h b/src/threads.h index a9942b9746fb..2d1726b343c2 100644 --- a/src/threads.h +++ b/src/threads.h @@ -48,7 +48,7 @@ #if defined OS_FREEBSD || __OpenBSD__ -#if ! defined __OpenBSD__ +#if !defined __OpenBSD__ #include #endif enum { @@ -101,111 +101,109 @@ enum { * because, some OS doesn't initialize them for you :) */ -//#define DBG_THREADS +// #define DBG_THREADS #if defined DBG_THREADS - #ifdef PROFILE_LOCKING - #error "Cannot mix DBG_THREADS and PROFILE_LOCKING" - #endif - #include "threads-debug.h" +#ifdef PROFILE_LOCKING +#error "Cannot mix DBG_THREADS and PROFILE_LOCKING" +#endif +#include "threads-debug.h" #elif defined PROFILE_LOCKING - #include "threads-profile.h" +#include "threads-profile.h" #else /* normal */ /* mutex */ -#define SCMutex pthread_mutex_t -#define SCMutexAttr pthread_mutexattr_t -#define SCMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) -#define SCMutexLock(mut) pthread_mutex_lock(mut) -#define SCMutexTrylock(mut) pthread_mutex_trylock(mut) -#define SCMutexUnlock(mut) pthread_mutex_unlock(mut) -#define SCMutexDestroy pthread_mutex_destroy -#define SCMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define SCMutex pthread_mutex_t +#define SCMutexAttr pthread_mutexattr_t +#define SCMutexInit(mut, mutattr) pthread_mutex_init(mut, mutattr) +#define SCMutexLock(mut) pthread_mutex_lock(mut) +#define SCMutexTrylock(mut) pthread_mutex_trylock(mut) +#define SCMutexUnlock(mut) pthread_mutex_unlock(mut) +#define SCMutexDestroy pthread_mutex_destroy +#define SCMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER /* rwlocks */ -#define SCRWLock pthread_rwlock_t -#define SCRWLockInit(rwl, rwlattr ) pthread_rwlock_init(rwl, rwlattr) -#define SCRWLockWRLock(rwl) pthread_rwlock_wrlock(rwl) -#define SCRWLockRDLock(rwl) pthread_rwlock_rdlock(rwl) -#define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl) -#define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) -#define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl) -#define SCRWLockDestroy pthread_rwlock_destroy +#define SCRWLock pthread_rwlock_t +#define SCRWLockInit(rwl, rwlattr) pthread_rwlock_init(rwl, rwlattr) +#define SCRWLockWRLock(rwl) pthread_rwlock_wrlock(rwl) +#define SCRWLockRDLock(rwl) pthread_rwlock_rdlock(rwl) +#define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl) +#define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) +#define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl) +#define SCRWLockDestroy pthread_rwlock_destroy /* conditions */ -#define SCCondT pthread_cond_t -#define SCCondInit pthread_cond_init -#define SCCondSignal pthread_cond_signal -#define SCCondDestroy pthread_cond_destroy -#define SCCondWait(cond, mut) pthread_cond_wait(cond, mut) +#define SCCondT pthread_cond_t +#define SCCondInit pthread_cond_init +#define SCCondSignal pthread_cond_signal +#define SCCondDestroy pthread_cond_destroy +#define SCCondWait(cond, mut) pthread_cond_wait(cond, mut) /* ctrl mutex */ -#define SCCtrlMutex pthread_mutex_t -#define SCCtrlMutexAttr pthread_mutexattr_t -#define SCCtrlMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) -#define SCCtrlMutexLock(mut) pthread_mutex_lock(mut) -#define SCCtrlMutexTrylock(mut) pthread_mutex_trylock(mut) -#define SCCtrlMutexUnlock(mut) pthread_mutex_unlock(mut) -#define SCCtrlMutexDestroy pthread_mutex_destroy +#define SCCtrlMutex pthread_mutex_t +#define SCCtrlMutexAttr pthread_mutexattr_t +#define SCCtrlMutexInit(mut, mutattr) pthread_mutex_init(mut, mutattr) +#define SCCtrlMutexLock(mut) pthread_mutex_lock(mut) +#define SCCtrlMutexTrylock(mut) pthread_mutex_trylock(mut) +#define SCCtrlMutexUnlock(mut) pthread_mutex_unlock(mut) +#define SCCtrlMutexDestroy pthread_mutex_destroy /* ctrl conditions */ -#define SCCtrlCondT pthread_cond_t -#define SCCtrlCondInit pthread_cond_init -#define SCCtrlCondSignal pthread_cond_signal -#define SCCtrlCondTimedwait pthread_cond_timedwait -#define SCCtrlCondWait pthread_cond_wait -#define SCCtrlCondDestroy pthread_cond_destroy +#define SCCtrlCondT pthread_cond_t +#define SCCtrlCondInit pthread_cond_init +#define SCCtrlCondSignal pthread_cond_signal +#define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait +#define SCCtrlCondDestroy pthread_cond_destroy /* spinlocks */ #if ((_POSIX_SPIN_LOCKS - 200112L) < 0L) || defined HELGRIND || !defined(HAVE_PTHREAD_SPIN_UNLOCK) -#define SCSpinlock SCMutex -#define SCSpinLock(spin) SCMutexLock((spin)) -#define SCSpinTrylock(spin) SCMutexTrylock((spin)) -#define SCSpinUnlock(spin) SCMutexUnlock((spin)) -#define SCSpinInit(spin, spin_attr) SCMutexInit((spin), NULL) -#define SCSpinDestroy(spin) SCMutexDestroy((spin)) +#define SCSpinlock SCMutex +#define SCSpinLock(spin) SCMutexLock((spin)) +#define SCSpinTrylock(spin) SCMutexTrylock((spin)) +#define SCSpinUnlock(spin) SCMutexUnlock((spin)) +#define SCSpinInit(spin, spin_attr) SCMutexInit((spin), NULL) +#define SCSpinDestroy(spin) SCMutexDestroy((spin)) #else /* no spinlocks */ -#define SCSpinlock pthread_spinlock_t -#define SCSpinLock(spin) pthread_spin_lock(spin) -#define SCSpinTrylock(spin) pthread_spin_trylock(spin) -#define SCSpinUnlock(spin) pthread_spin_unlock(spin) -#define SCSpinInit(spin, spin_attr) pthread_spin_init(spin, spin_attr) -#define SCSpinDestroy(spin) pthread_spin_destroy(spin) +#define SCSpinlock pthread_spinlock_t +#define SCSpinLock(spin) pthread_spin_lock(spin) +#define SCSpinTrylock(spin) pthread_spin_trylock(spin) +#define SCSpinUnlock(spin) pthread_spin_unlock(spin) +#define SCSpinInit(spin, spin_attr) pthread_spin_init(spin, spin_attr) +#define SCSpinDestroy(spin) pthread_spin_destroy(spin) #endif /* no spinlocks */ #endif -#if (!defined SCMutex || !defined SCMutexAttr || !defined SCMutexInit || \ - !defined SCMutexLock || !defined SCMutexTrylock || \ - !defined SCMutexUnlock || !defined SCMutexDestroy || \ - !defined SCMUTEX_INITIALIZER) +#if (!defined SCMutex || !defined SCMutexAttr || !defined SCMutexInit || !defined SCMutexLock || \ + !defined SCMutexTrylock || !defined SCMutexUnlock || !defined SCMutexDestroy || \ + !defined SCMUTEX_INITIALIZER) #error "Mutex types and/or macro's not properly defined" #endif -#if (!defined SCCtrlMutex || !defined SCCtrlMutexAttr || !defined SCCtrlMutexInit || \ - !defined SCCtrlMutexLock || !defined SCCtrlMutexTrylock || \ - !defined SCCtrlMutexUnlock || !defined SCCtrlMutexDestroy) +#if (!defined SCCtrlMutex || !defined SCCtrlMutexAttr || !defined SCCtrlMutexInit || \ + !defined SCCtrlMutexLock || !defined SCCtrlMutexTrylock || !defined SCCtrlMutexUnlock || \ + !defined SCCtrlMutexDestroy) #error "SCCtrlMutex types and/or macro's not properly defined" #endif -#if (!defined SCSpinlock || !defined SCSpinLock || \ - !defined SCSpinTrylock || !defined SCSpinUnlock || \ - !defined SCSpinInit || !defined SCSpinDestroy) +#if (!defined SCSpinlock || !defined SCSpinLock || !defined SCSpinTrylock || \ + !defined SCSpinUnlock || !defined SCSpinInit || !defined SCSpinDestroy) #error "Spinlock types and/or macro's not properly defined" #endif -#if (!defined SCRWLock || !defined SCRWLockInit || !defined SCRWLockWRLock || \ - !defined SCRWLockRDLock || !defined SCRWLockTryWRLock || \ - !defined SCRWLockTryRDLock || !defined SCRWLockUnlock || !defined SCRWLockDestroy) +#if (!defined SCRWLock || !defined SCRWLockInit || !defined SCRWLockWRLock || \ + !defined SCRWLockRDLock || !defined SCRWLockTryWRLock || !defined SCRWLockTryRDLock || \ + !defined SCRWLockUnlock || !defined SCRWLockDestroy) #error "SCRWLock types and/or macro's not properly defined" #endif -#if (!defined SCCondT || !defined SCCondInit || !defined SCCondSignal || \ - !defined SCCondDestroy || !defined SCCondWait) +#if (!defined SCCondT || !defined SCCondInit || !defined SCCondSignal || !defined SCCondDestroy || \ + !defined SCCondWait) #error "SCCond types and/or macro's not properly defined" #endif -#if (!defined SCCtrlCondT || !defined SCCtrlCondInit || !defined SCCtrlCondSignal ||\ - !defined SCCtrlCondDestroy || !defined SCCtrlCondTimedwait) +#if (!defined SCCtrlCondT || !defined SCCtrlCondInit || !defined SCCtrlCondSignal || \ + !defined SCCtrlCondDestroy || !defined SCCtrlCondTimedwait) #error "SCCtrlCond types and/or macro's not properly defined" #endif @@ -213,51 +211,58 @@ enum { #ifdef OS_FREEBSD #include -#define SCGetThreadIdLong(...) ({ \ - long tmpthid; \ - thr_self(&tmpthid); \ - unsigned long _scgetthread_tid = (unsigned long)tmpthid; \ - _scgetthread_tid; \ -}) +#define SCGetThreadIdLong(...) \ + ({ \ + long tmpthid; \ + thr_self(&tmpthid); \ + unsigned long _scgetthread_tid = (unsigned long)tmpthid; \ + _scgetthread_tid; \ + }) #elif __OpenBSD__ -#define SCGetThreadIdLong(...) ({ \ - pid_t tpid; \ - tpid = getpid(); \ - unsigned long _scgetthread_tid = (unsigned long)tpid; \ - _scgetthread_tid; \ -}) +#define SCGetThreadIdLong(...) \ + ({ \ + pid_t tpid; \ + tpid = getpid(); \ + unsigned long _scgetthread_tid = (unsigned long)tpid; \ + _scgetthread_tid; \ + }) #elif __CYGWIN__ -#define SCGetThreadIdLong(...) ({ \ - unsigned long _scgetthread_tid = (unsigned long)GetCurrentThreadId(); \ - _scgetthread_tid; \ -}) +#define SCGetThreadIdLong(...) \ + ({ \ + unsigned long _scgetthread_tid = (unsigned long)GetCurrentThreadId(); \ + _scgetthread_tid; \ + }) #elif OS_WIN32 -#define SCGetThreadIdLong(...) ({ \ - unsigned long _scgetthread_tid = (unsigned long)GetCurrentThreadId(); \ - _scgetthread_tid; \ -}) +#define SCGetThreadIdLong(...) \ + ({ \ + unsigned long _scgetthread_tid = (unsigned long)GetCurrentThreadId(); \ + _scgetthread_tid; \ + }) #elif OS_DARWIN -#define SCGetThreadIdLong(...) ({ \ - thread_port_t tpid; \ - tpid = mach_thread_self(); \ - unsigned long _scgetthread_tid = (unsigned long)tpid; \ - _scgetthread_tid; \ -}) +#define SCGetThreadIdLong(...) \ + ({ \ + thread_port_t tpid; \ + tpid = mach_thread_self(); \ + unsigned long _scgetthread_tid = (unsigned long)tpid; \ + _scgetthread_tid; \ + }) #elif defined(sun) #include -#define SCGetThreadIdLong(...) ({ \ - thread_t tmpthid = thr_self(); \ - unsigned long _scgetthread_tid = (unsigned long)tmpthid; \ - _scgetthread_tid; \ -}) +#define SCGetThreadIdLong(...) \ + ({ \ + thread_t tmpthid = thr_self(); \ + unsigned long _scgetthread_tid = (unsigned long)tmpthid; \ + _scgetthread_tid; \ + }) #else -#define SCGetThreadIdLong(...) ({ \ - pid_t tmpthid; \ - tmpthid = syscall(SYS_gettid); \ - unsigned long _scgetthread_tid = (unsigned long)tmpthid; \ - _scgetthread_tid; \ -}) +#define SCGetThreadIdLong(...) \ + ({ \ + pid_t tmpthid; \ + tmpthid = syscall(SYS_gettid); \ + unsigned long _scgetthread_tid = (unsigned long)tmpthid; \ + _scgetthread_tid; \ + }) #endif /* OS FREEBSD */ extern thread_local char t_thread_name[THREAD_NAME_LEN + 1]; @@ -305,8 +310,6 @@ extern thread_local char t_thread_name[THREAD_NAME_LEN + 1]; } #endif - void ThreadMacrosRegisterTests(void); #endif /* __THREADS_H__ */ - diff --git a/src/threadvars.h b/src/threadvars.h index ea448c094986..0b34846d79b7 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -27,32 +27,33 @@ #include "tm-queues.h" #include "counters.h" #include "packet-queue.h" -#include "util-atomic.h" +#include "util/atomic.h" struct TmSlot_; /** Thread flags set and read by threads to control the threads */ -#define THV_USE BIT_U32(0) /** thread is in use */ -#define THV_INIT_DONE BIT_U32(1) /** thread initialization done */ -#define THV_PAUSE BIT_U32(2) /** signal thread to pause itself */ -#define THV_PAUSED BIT_U32(3) /** the thread is paused atm */ -#define THV_KILL BIT_U32(4) /** thread has been asked to cleanup and exit */ -#define THV_FAILED BIT_U32(5) /** thread has encountered an error and failed */ -#define THV_CLOSED BIT_U32(6) /** thread done, should be joinable */ +#define THV_USE BIT_U32(0) /** thread is in use */ +#define THV_INIT_DONE BIT_U32(1) /** thread initialization done */ +#define THV_PAUSE BIT_U32(2) /** signal thread to pause itself */ +#define THV_PAUSED BIT_U32(3) /** the thread is paused atm */ +#define THV_KILL BIT_U32(4) /** thread has been asked to cleanup and exit */ +#define THV_FAILED BIT_U32(5) /** thread has encountered an error and failed */ +#define THV_CLOSED BIT_U32(6) /** thread done, should be joinable */ /* used to indicate the thread is going through de-init. Introduced as more * of a hack for solving stream-timeout-shutdown. Is set by the main thread. */ -#define THV_DEINIT BIT_U32(7) -#define THV_RUNNING_DONE BIT_U32(8) /** thread has completed running and is entering - * the de-init phase */ -#define THV_KILL_PKTACQ BIT_U32(9) /**< flag thread to stop packet acq */ -#define THV_FLOW_LOOP BIT_U32(10) /**< thread is in flow shutdown loop */ +#define THV_DEINIT BIT_U32(7) +#define THV_RUNNING_DONE \ + BIT_U32(8) /** thread has completed running and is entering \ + * the de-init phase */ +#define THV_KILL_PKTACQ BIT_U32(9) /**< flag thread to stop packet acq */ +#define THV_FLOW_LOOP BIT_U32(10) /**< thread is in flow shutdown loop */ /** signal thread's capture method to create a fake packet to force through * the engine. This is to force timely handling of maintenance tasks like * rule reloads even if no packets are read by the capture method. */ -#define THV_CAPTURE_INJECT_PKT BIT_U32(11) -#define THV_DEAD BIT_U32(12) /**< thread has been joined with pthread_join() */ -#define THV_RUNNING BIT_U32(13) /**< thread is running */ +#define THV_CAPTURE_INJECT_PKT BIT_U32(11) +#define THV_DEAD BIT_U32(12) /**< thread has been joined with pthread_join() */ +#define THV_RUNNING BIT_U32(13) /**< thread is running */ /** \brief Per thread variable structure */ typedef struct ThreadVars_ { @@ -72,8 +73,7 @@ typedef struct ThreadVars_ { uint8_t type; uint16_t cpu_affinity; /** cpu or core number to set affinity to */ - int thread_priority; /** priority (real time) for this thread. Look at threads.h */ - + int thread_priority; /** priority (real time) for this thread. Look at threads.h */ /** TmModule::flags for each module part of this thread */ uint8_t tmm_flags; @@ -88,7 +88,7 @@ typedef struct ThreadVars_ { /** incoming queue and handler */ Tmq *inq; - struct Packet_ * (*tmqh_in)(struct ThreadVars_ *); + struct Packet_ *(*tmqh_in)(struct ThreadVars_ *); SC_ATOMIC_DECLARE(uint32_t, flags); @@ -138,8 +138,8 @@ typedef struct ThreadVars_ { } ThreadVars; /** Thread setup flags: */ -#define THREAD_SET_AFFINITY 0x01 /** CPU/Core affinity */ -#define THREAD_SET_PRIORITY 0x02 /** Real time priority */ -#define THREAD_SET_AFFTYPE 0x04 /** Priority and affinity */ +#define THREAD_SET_AFFINITY 0x01 /** CPU/Core affinity */ +#define THREAD_SET_PRIORITY 0x02 /** Real time priority */ +#define THREAD_SET_AFFTYPE 0x04 /** Priority and affinity */ #endif /* __THREADVARS_H__ */ diff --git a/src/tm-modules.c b/src/tm-modules.c index 8f6082a91a60..cf19211f2e9f 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -26,9 +26,9 @@ #include "suricata-common.h" #include "packet-queue.h" #include "tm-threads.h" -#include "util-debug.h" +#include "util/debug.h" #include "threads.h" -#include "util-logopenfile.h" +#include "util/logopenfile.h" TmModule tmm_modules[TMM_SIZE]; @@ -125,7 +125,6 @@ int TmModuleGetIDForTM(TmModule *tm) return -1; } - void TmModuleRunInit(void) { TmModule *t; @@ -177,7 +176,6 @@ void TmModuleRegisterTests(void) g_ut_modules++; - if (t->RegisterTests == NULL) { if (coverage_unittests) SCLogWarning("threading module %s has no unittest " @@ -192,7 +190,9 @@ void TmModuleRegisterTests(void) } #ifdef PROFILING -#define CASE_CODE(E) case E: return #E +#define CASE_CODE(E) \ + case E: \ + return #E /** * \brief Maps the TmmId, to its string equivalent @@ -201,53 +201,53 @@ void TmModuleRegisterTests(void) * * \retval string equivalent for the tmm id */ -const char * TmModuleTmmIdToString(TmmId id) +const char *TmModuleTmmIdToString(TmmId id) { switch (id) { - CASE_CODE (TMM_FLOWWORKER); - CASE_CODE (TMM_RECEIVENFLOG); - CASE_CODE (TMM_DECODENFLOG); - CASE_CODE (TMM_DECODENFQ); - CASE_CODE (TMM_VERDICTNFQ); - CASE_CODE (TMM_RECEIVENFQ); - CASE_CODE (TMM_RECEIVEPCAP); - CASE_CODE (TMM_RECEIVEPCAPFILE); - CASE_CODE (TMM_DECODEPCAP); - CASE_CODE (TMM_DECODEPCAPFILE); - CASE_CODE (TMM_RECEIVEPFRING); - CASE_CODE (TMM_DECODEPFRING); + CASE_CODE(TMM_FLOWWORKER); + CASE_CODE(TMM_RECEIVENFLOG); + CASE_CODE(TMM_DECODENFLOG); + CASE_CODE(TMM_DECODENFQ); + CASE_CODE(TMM_VERDICTNFQ); + CASE_CODE(TMM_RECEIVENFQ); + CASE_CODE(TMM_RECEIVEPCAP); + CASE_CODE(TMM_RECEIVEPCAPFILE); + CASE_CODE(TMM_DECODEPCAP); + CASE_CODE(TMM_DECODEPCAPFILE); + CASE_CODE(TMM_RECEIVEPFRING); + CASE_CODE(TMM_DECODEPFRING); CASE_CODE(TMM_RECEIVEDPDK); CASE_CODE(TMM_DECODEDPDK); - CASE_CODE (TMM_RECEIVEPLUGIN); - CASE_CODE (TMM_DECODEPLUGIN); - CASE_CODE (TMM_RESPONDREJECT); - CASE_CODE (TMM_DECODEIPFW); - CASE_CODE (TMM_VERDICTIPFW); - CASE_CODE (TMM_RECEIVEIPFW); - CASE_CODE (TMM_RECEIVEERFFILE); - CASE_CODE (TMM_DECODEERFFILE); - CASE_CODE (TMM_RECEIVEERFDAG); - CASE_CODE (TMM_DECODEERFDAG); - CASE_CODE (TMM_RECEIVENAPATECH); - CASE_CODE (TMM_DECODENAPATECH); - CASE_CODE (TMM_RECEIVEAFP); + CASE_CODE(TMM_RECEIVEPLUGIN); + CASE_CODE(TMM_DECODEPLUGIN); + CASE_CODE(TMM_RESPONDREJECT); + CASE_CODE(TMM_DECODEIPFW); + CASE_CODE(TMM_VERDICTIPFW); + CASE_CODE(TMM_RECEIVEIPFW); + CASE_CODE(TMM_RECEIVEERFFILE); + CASE_CODE(TMM_DECODEERFFILE); + CASE_CODE(TMM_RECEIVEERFDAG); + CASE_CODE(TMM_DECODEERFDAG); + CASE_CODE(TMM_RECEIVENAPATECH); + CASE_CODE(TMM_DECODENAPATECH); + CASE_CODE(TMM_RECEIVEAFP); CASE_CODE(TMM_RECEIVEAFXDP); - CASE_CODE (TMM_ALERTPCAPINFO); - CASE_CODE (TMM_DECODEAFP); + CASE_CODE(TMM_ALERTPCAPINFO); + CASE_CODE(TMM_DECODEAFP); CASE_CODE(TMM_DECODEAFXDP); - CASE_CODE (TMM_STATSLOGGER); - CASE_CODE (TMM_FLOWMANAGER); - CASE_CODE (TMM_FLOWRECYCLER); - CASE_CODE (TMM_BYPASSEDFLOWMANAGER); - CASE_CODE (TMM_UNIXMANAGER); - CASE_CODE (TMM_DETECTLOADER); - CASE_CODE (TMM_RECEIVENETMAP); - CASE_CODE (TMM_DECODENETMAP); - CASE_CODE (TMM_RECEIVEWINDIVERT); - CASE_CODE (TMM_VERDICTWINDIVERT); - CASE_CODE (TMM_DECODEWINDIVERT); - - CASE_CODE (TMM_SIZE); + CASE_CODE(TMM_STATSLOGGER); + CASE_CODE(TMM_FLOWMANAGER); + CASE_CODE(TMM_FLOWRECYCLER); + CASE_CODE(TMM_BYPASSEDFLOWMANAGER); + CASE_CODE(TMM_UNIXMANAGER); + CASE_CODE(TMM_DETECTLOADER); + CASE_CODE(TMM_RECEIVENETMAP); + CASE_CODE(TMM_DECODENETMAP); + CASE_CODE(TMM_RECEIVEWINDIVERT); + CASE_CODE(TMM_VERDICTWINDIVERT); + CASE_CODE(TMM_DECODEWINDIVERT); + + CASE_CODE(TMM_SIZE); } return ""; } diff --git a/src/tm-modules.h b/src/tm-modules.h index 4642ff46a6ca..4ec6906724b8 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -28,13 +28,13 @@ #include "threadvars.h" /* thread flags */ -#define TM_FLAG_RECEIVE_TM 0x01 -#define TM_FLAG_DECODE_TM 0x02 -#define TM_FLAG_STREAM_TM 0x04 -#define TM_FLAG_DETECT_TM 0x08 -#define TM_FLAG_LOGAPI_TM 0x10 /**< TM is run by Log API */ -#define TM_FLAG_MANAGEMENT_TM 0x20 -#define TM_FLAG_COMMAND_TM 0x40 +#define TM_FLAG_RECEIVE_TM 0x01 +#define TM_FLAG_DECODE_TM 0x02 +#define TM_FLAG_STREAM_TM 0x04 +#define TM_FLAG_DETECT_TM 0x08 +#define TM_FLAG_LOGAPI_TM 0x10 /**< TM is run by Log API */ +#define TM_FLAG_MANAGEMENT_TM 0x20 +#define TM_FLAG_COMMAND_TM 0x40 typedef TmEcode (*ThreadInitFunc)(ThreadVars *, const void *, void **); typedef TmEcode (*ThreadDeinitFunc)(ThreadVars *, void *); @@ -100,10 +100,9 @@ TmEcode TmModuleRegister(char *name, int (*module_func)(ThreadVars *, Packet *, void TmModuleDebugList(void); void TmModuleRegisterTests(void); #ifdef PROFILING -const char * TmModuleTmmIdToString(TmmId id); +const char *TmModuleTmmIdToString(TmmId id); #endif void TmModuleRunInit(void); void TmModuleRunDeInit(void); #endif /* __TM_MODULES_H__ */ - diff --git a/src/tm-queuehandlers.c b/src/tm-queuehandlers.c index 4850679ceb05..062b0277ebb6 100644 --- a/src/tm-queuehandlers.c +++ b/src/tm-queuehandlers.c @@ -36,7 +36,7 @@ Tmqh tmqh_table[TMQH_SIZE]; -void TmqhSetup (void) +void TmqhSetup(void) { memset(&tmqh_table, 0, sizeof(tmqh_table)); diff --git a/src/tm-queuehandlers.h b/src/tm-queuehandlers.h index eb0081bba66b..06d128427c22 100644 --- a/src/tm-queuehandlers.h +++ b/src/tm-queuehandlers.h @@ -45,11 +45,10 @@ typedef struct Tmqh_ { extern Tmqh tmqh_table[TMQH_SIZE]; -void TmqhSetup (void); +void TmqhSetup(void); void TmqhCleanup(void); int TmqhNameToID(const char *name); Tmqh *TmqhGetQueueHandlerByName(const char *name); Tmqh *TmqhGetQueueHandlerByID(const int id); #endif /* __TM_QUEUEHANDLERS_H__ */ - diff --git a/src/tm-queues.c b/src/tm-queues.c index e184ec9827db..1666248c6984 100644 --- a/src/tm-queues.c +++ b/src/tm-queues.c @@ -26,7 +26,7 @@ #include "suricata.h" #include "threads.h" #include "tm-queues.h" -#include "util-debug.h" +#include "util/debug.h" static TAILQ_HEAD(TmqList_, Tmq_) tmq_list = TAILQ_HEAD_INITIALIZER(tmq_list); @@ -59,7 +59,7 @@ Tmq *TmqCreateQueue(const char *name) Tmq *TmqGetQueueByName(const char *name) { Tmq *tmq = NULL; - TAILQ_FOREACH(tmq, &tmq_list, next) { + TAILQ_FOREACH (tmq, &tmq_list, next) { if (strcmp(tmq->name, name) == 0) return tmq; } @@ -69,10 +69,11 @@ Tmq *TmqGetQueueByName(const char *name) void TmqDebugList(void) { Tmq *tmq = NULL; - TAILQ_FOREACH(tmq, &tmq_list, next) { + TAILQ_FOREACH (tmq, &tmq_list, next) { /* get a lock accessing the len */ SCMutexLock(&tmq->pq->mutex_q); - printf("TmqDebugList: id %" PRIu32 ", name \'%s\', len %" PRIu32 "\n", tmq->id, tmq->name, tmq->pq->len); + printf("TmqDebugList: id %" PRIu32 ", name \'%s\', len %" PRIu32 "\n", tmq->id, tmq->name, + tmq->pq->len); SCMutexUnlock(&tmq->pq->mutex_q); } } @@ -103,7 +104,7 @@ void TmValidateQueueState(void) bool err = false; Tmq *tmq = NULL; - TAILQ_FOREACH(tmq, &tmq_list, next) { + TAILQ_FOREACH (tmq, &tmq_list, next) { SCMutexLock(&tmq->pq->mutex_q); if (tmq->reader_cnt == 0) { SCLogError("queue \"%s\" doesn't have a reader (id %d max %u)", tmq->name, tmq->id, diff --git a/src/tm-queues.h b/src/tm-queues.h index a203b6662327..0713e80c9867 100644 --- a/src/tm-queues.h +++ b/src/tm-queues.h @@ -36,12 +36,11 @@ typedef struct Tmq_ { TAILQ_ENTRY(Tmq_) next; } Tmq; -Tmq* TmqCreateQueue(const char *name); -Tmq* TmqGetQueueByName(const char *name); +Tmq *TmqCreateQueue(const char *name); +Tmq *TmqGetQueueByName(const char *name); void TmqDebugList(void); void TmqResetQueues(void); void TmValidateQueueState(void); #endif /* __TM_QUEUES_H__ */ - diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 47b501c0789e..5297d113d718 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -81,9 +81,9 @@ typedef enum { /*Error codes for the thread modules*/ typedef enum { - TM_ECODE_OK = 0, /**< Thread module exits OK*/ - TM_ECODE_FAILED, /**< Thread module exits due to failure*/ - TM_ECODE_DONE, /**< Thread module task is finished*/ + TM_ECODE_OK = 0, /**< Thread module exits OK*/ + TM_ECODE_FAILED, /**< Thread module exits due to failure*/ + TM_ECODE_DONE, /**< Thread module task is finished*/ } TmEcode; /* ThreadVars type */ @@ -95,4 +95,3 @@ enum { }; #endif /* __TM_THREADS_COMMON_H__ */ - diff --git a/src/tm-threads.c b/src/tm-threads.c index 10ef45da278f..a020191a7b87 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -35,15 +35,15 @@ #include "tm-threads.h" #include "tmqh-packetpool.h" #include "threads.h" -#include "util-affinity.h" -#include "util-debug.h" -#include "util-privs.h" -#include "util-cpu.h" -#include "util-optimize.h" -#include "util-profiling.h" -#include "util-signal.h" +#include "util/affinity.h" +#include "util/debug.h" +#include "util/privs.h" +#include "util/cpu.h" +#include "util/optimize.h" +#include "util/profiling.h" +#include "util/signal.h" #include "queue.h" -#include "util-validate.h" +#include "util/validate.h" #ifdef PROFILE_LOCKING thread_local uint64_t mutex_lock_contention; @@ -254,7 +254,7 @@ static void *TmThreadsSlotPktAcqLoop(void *td) " tmqh_out=%p", s, s ? s->PktAcqLoop : NULL, tv->tmqh_in, tv->tmqh_out); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } @@ -283,10 +283,10 @@ static void *TmThreadsSlotPktAcqLoop(void *td) tv->flow_queue = FlowQueueNew(); if (tv->flow_queue == NULL) { TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } - /* setup a queue */ + /* setup a queue */ } else if (slot->tm_id == TMM_FLOWWORKER) { tv->stream_pq_local = SCCalloc(1, sizeof(PacketQueue)); if (tv->stream_pq_local == NULL) @@ -298,7 +298,7 @@ static void *TmThreadsSlotPktAcqLoop(void *td) tv->flow_queue = FlowQueueNew(); if (tv->flow_queue == NULL) { TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } } @@ -308,7 +308,7 @@ static void *TmThreadsSlotPktAcqLoop(void *td) TmThreadsSetFlag(tv, THV_INIT_DONE); - while(run) { + while (run) { if (TmThreadsCheckFlag(tv, THV_PAUSE)) { TmThreadsSetFlag(tv, THV_PAUSED); TmThreadTestThreadUnPaused(tv); @@ -357,12 +357,12 @@ static void *TmThreadsSlotPktAcqLoop(void *td) tv->stream_pq = NULL; SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); + pthread_exit((void *)0); return NULL; error: tv->stream_pq = NULL; - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } @@ -375,7 +375,7 @@ static void *TmThreadsSlotVar(void *td) TmEcode r = TM_ECODE_OK; CaptureStatsSetup(tv); - PacketPoolInit();//Empty(); + PacketPoolInit(); // Empty(); SCSetThreadName(tv->name); @@ -388,7 +388,7 @@ static void *TmThreadsSlotVar(void *td) /* check if we are setup properly */ if (s == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } @@ -414,10 +414,10 @@ static void *TmThreadsSlotVar(void *td) tv->flow_queue = FlowQueueNew(); if (tv->flow_queue == NULL) { TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } - /* setup a queue */ + /* setup a queue */ } else if (s->tm_id == TMM_FLOWWORKER) { tv->stream_pq_local = SCCalloc(1, sizeof(PacketQueue)); if (tv->stream_pq_local == NULL) @@ -429,7 +429,7 @@ static void *TmThreadsSlotVar(void *td) tv->flow_queue = FlowQueueNew(); if (tv->flow_queue == NULL) { TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } } @@ -495,7 +495,7 @@ static void *TmThreadsSlotVar(void *td) s = (TmSlot *)tv->tm_slots; - for ( ; s != NULL; s = s->slot_next) { + for (; s != NULL; s = s->slot_next) { if (s->SlotThreadExitPrintStats != NULL) { s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); } @@ -512,12 +512,12 @@ static void *TmThreadsSlotVar(void *td) SCLogDebug("%s ending", tv->name); tv->stream_pq = NULL; TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); + pthread_exit((void *)0); return NULL; error: tv->stream_pq = NULL; - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } @@ -544,7 +544,7 @@ static void *TmThreadsManagement(void *td) r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); @@ -575,13 +575,13 @@ static void *TmThreadsManagement(void *td) r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); + pthread_exit((void *)-1); return NULL; } } TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); + pthread_exit((void *)0); return NULL; } @@ -673,8 +673,8 @@ void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, const void *data) TmSlot *a = (TmSlot *)tv->tm_slots, *b = NULL; /* get the last slot */ - for ( ; a != NULL; a = a->slot_next) { - b = a; + for (; a != NULL; a = a->slot_next) { + b = a; } /* append the new slot */ if (b != NULL) { @@ -688,19 +688,18 @@ void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, const void *data) static int SetCPUAffinitySet(cpu_set_t *cs) { #if defined OS_FREEBSD - int r = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, - SCGetThreadIdLong(), sizeof(cpu_set_t),cs); + int r = cpuset_setaffinity( + CPU_LEVEL_WHICH, CPU_WHICH_TID, SCGetThreadIdLong(), sizeof(cpu_set_t), cs); #elif OS_DARWIN - int r = thread_policy_set(mach_thread_self(), THREAD_AFFINITY_POLICY, - (void*)cs, THREAD_AFFINITY_POLICY_COUNT); + int r = thread_policy_set( + mach_thread_self(), THREAD_AFFINITY_POLICY, (void *)cs, THREAD_AFFINITY_POLICY_COUNT); #else pid_t tid = syscall(SYS_gettid); int r = sched_setaffinity(tid, sizeof(cpu_set_t), cs); #endif /* OS_FREEBSD */ if (r != 0) { - printf("Warning: sched_setaffinity failed (%" PRId32 "): %s\n", r, - strerror(errno)); + printf("Warning: sched_setaffinity failed (%" PRId32 "): %s\n", r, strerror(errno)); return -1; } @@ -708,7 +707,6 @@ static int SetCPUAffinitySet(cpu_set_t *cs) } #endif - /** * \brief Set the thread affinity on the calling thread. * @@ -728,12 +726,10 @@ static int SetCPUAffinity(uint16_t cpuid) int r = (0 == SetThreadAffinityMask(GetCurrentThread(), cs)); if (r != 0) { - printf("Warning: sched_setaffinity failed (%" PRId32 "): %s\n", r, - strerror(errno)); + printf("Warning: sched_setaffinity failed (%" PRId32 "): %s\n", r, strerror(errno)); return -1; } - SCLogDebug("CPU Affinity for thread %lu set to CPU %" PRId32, - SCGetThreadIdLong(), cpu); + SCLogDebug("CPU Affinity for thread %lu set to CPU %" PRId32, SCGetThreadIdLong(), cpu); return 0; @@ -748,7 +744,6 @@ static int SetCPUAffinity(uint16_t cpuid) #endif /* not supported */ } - /** * \brief Set the thread options (thread priority). * @@ -772,13 +767,12 @@ void TmThreadSetPrio(ThreadVars *tv) SCEnter(); #ifndef __CYGWIN__ #ifdef OS_WIN32 - if (0 == SetThreadPriority(GetCurrentThread(), tv->thread_priority)) { - SCLogError("Error setting priority for " - "thread %s: %s", - tv->name, strerror(errno)); + if (0 == SetThreadPriority(GetCurrentThread(), tv->thread_priority)) { + SCLogError("Error setting priority for " + "thread %s: %s", + tv->name, strerror(errno)); } else { - SCLogDebug("Priority set to %"PRId32" for thread %s", - tv->thread_priority, tv->name); + SCLogDebug("Priority set to %" PRId32 " for thread %s", tv->thread_priority, tv->name); } #else int ret = nice(tv->thread_priority); @@ -787,15 +781,13 @@ void TmThreadSetPrio(ThreadVars *tv) "for thread %s: %s", tv->thread_priority, tv->name, strerror(errno)); } else { - SCLogDebug("Nice value set to %"PRId32" for thread %s", - tv->thread_priority, tv->name); + SCLogDebug("Nice value set to %" PRId32 " for thread %s", tv->thread_priority, tv->name); } #endif /* OS_WIN32 */ #endif SCReturn; } - /** * \brief Set the thread options (cpu affinity). * @@ -812,7 +804,6 @@ TmEcode TmThreadSetCPUAffinity(ThreadVars *tv, uint16_t cpu) return TM_ECODE_OK; } - TmEcode TmThreadSetCPU(ThreadVars *tv, uint8_t type) { if (!threading_set_cpu_affinity) @@ -849,8 +840,8 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) { if (tv->thread_setup_flags & THREAD_SET_AFFINITY) { SCLogPerf("Setting affinity for thread \"%s\"to cpu/core " - "%"PRIu16", thread id %lu", tv->name, tv->cpu_affinity, - SCGetThreadIdLong()); + "%" PRIu16 ", thread id %lu", + tv->name, tv->cpu_affinity, SCGetThreadIdLong()); SetCPUAffinity(tv->cpu_affinity); } @@ -873,14 +864,14 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) tv->thread_priority = taf->prio; } SCLogPerf("Setting prio %d for thread \"%s\" to cpu/core " - "%d, thread id %lu", tv->thread_priority, - tv->name, cpu, SCGetThreadIdLong()); + "%d, thread id %lu", + tv->thread_priority, tv->name, cpu, SCGetThreadIdLong()); } else { SetCPUAffinitySet(&taf->cpu_set); tv->thread_priority = taf->prio; SCLogPerf("Setting prio %d for thread \"%s\", " - "thread id %lu", tv->thread_priority, - tv->name, SCGetThreadIdLong()); + "thread id %lu", + tv->thread_priority, tv->name, SCGetThreadIdLong()); } TmThreadSetPrio(tv); } @@ -905,8 +896,8 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) * \retval the newly created TV instance, or NULL on error */ ThreadVars *TmThreadCreate(const char *name, const char *inq_name, const char *inqh_name, - const char *outq_name, const char *outqh_name, const char *slots, - void * (*fn_p)(void *), int mucond) + const char *outq_name, const char *outqh_name, const char *slots, void *(*fn_p)(void *), + int mucond) { ThreadVars *tv = NULL; Tmq *tmq = NULL; @@ -1034,13 +1025,11 @@ ThreadVars *TmThreadCreate(const char *name, const char *inq_name, const char *i * \retval the newly created TV instance, or NULL on error */ ThreadVars *TmThreadCreatePacketHandler(const char *name, const char *inq_name, - const char *inqh_name, const char *outq_name, - const char *outqh_name, const char *slots) + const char *inqh_name, const char *outq_name, const char *outqh_name, const char *slots) { ThreadVars *tv = NULL; - tv = TmThreadCreate(name, inq_name, inqh_name, outq_name, outqh_name, - slots, NULL, 0); + tv = TmThreadCreate(name, inq_name, inqh_name, outq_name, outqh_name, slots, NULL, 0); if (tv != NULL) { tv->type = TVT_PPT; @@ -1062,8 +1051,7 @@ ThreadVars *TmThreadCreatePacketHandler(const char *name, const char *inq_name, * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), - int mucond) +ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), int mucond) { ThreadVars *tv = NULL; @@ -1090,8 +1078,7 @@ ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, const char *module, - int mucond) +ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, const char *module, int mucond) { ThreadVars *tv = NULL; @@ -1123,8 +1110,7 @@ ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, const char *module, * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateCmdThreadByName(const char *name, const char *module, - int mucond) +ThreadVars *TmThreadCreateCmdThreadByName(const char *name, const char *module, int mucond) { ThreadVars *tv = NULL; @@ -1244,7 +1230,7 @@ static int TmThreadKillThread(ThreadVars *tv) SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); } - if (tv->ctrl_cond != NULL ) { + if (tv->ctrl_cond != NULL) { pthread_cond_broadcast(tv->ctrl_cond); } return 0; @@ -1707,7 +1693,7 @@ TmEcode TmThreadSpawn(ThreadVars *tv) */ void TmThreadInitMC(ThreadVars *tv) { - if ( (tv->ctrl_mutex = SCMalloc(sizeof(*tv->ctrl_mutex))) == NULL) { + if ((tv->ctrl_mutex = SCMalloc(sizeof(*tv->ctrl_mutex))) == NULL) { FatalError("Fatal error encountered in TmThreadInitMC. " "Exiting..."); } @@ -1717,7 +1703,7 @@ void TmThreadInitMC(ThreadVars *tv) exit(EXIT_FAILURE); } - if ( (tv->ctrl_cond = SCMalloc(sizeof(*tv->ctrl_cond))) == NULL) { + if ((tv->ctrl_cond = SCMalloc(sizeof(*tv->ctrl_cond))) == NULL) { FatalError("Fatal error encountered in TmThreadInitMC. " "Exiting..."); } @@ -1948,7 +1934,7 @@ TmEcode TmThreadWaitOnThreadInit(void) for (int i = 0; i < TVT_MAX; i++) { ThreadVars *tv = tv_root[i]; while (tv != NULL) { - if (TmThreadsCheckFlag(tv, (THV_CLOSED|THV_DEAD))) { + if (TmThreadsCheckFlag(tv, (THV_CLOSED | THV_DEAD))) { SCMutexUnlock(&tv_root_lock); SCLogError("thread \"%s\" failed to " @@ -2022,8 +2008,7 @@ static void TmThreadDoDumpSlots(const ThreadVars *tv) { for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) { TmModule *m = TmModuleGetById(s->tm_id); - SCLogNotice("tv %p: -> slot %p tm_id %d name %s", - tv, s, s->tm_id, m->name); + SCLogNotice("tv %p: -> slot %p tm_id %d name %s", tv, s, s->tm_id, m->name); } } @@ -2034,19 +2019,19 @@ static void TmThreadDumpThreads(void) ThreadVars *tv = tv_root[i]; while (tv != NULL) { const uint32_t flags = SC_ATOMIC_GET(tv->flags); - SCLogNotice("tv %p: type %u name %s tmm_flags %02X flags %X stream_pq %p", - tv, tv->type, tv->name, tv->tmm_flags, flags, tv->stream_pq); + SCLogNotice("tv %p: type %u name %s tmm_flags %02X flags %X stream_pq %p", tv, tv->type, + tv->name, tv->tmm_flags, flags, tv->stream_pq); if (tv->inq && tv->stream_pq == tv->inq->pq) { SCLogNotice("tv %p: stream_pq at tv->inq %u", tv, tv->inq->id); } else if (tv->stream_pq_local != NULL) { for (Packet *xp = tv->stream_pq_local->top; xp != NULL; xp = xp->next) { - SCLogNotice("tv %p: ==> stream_pq_local: pq.len %u packet src %s", - tv, tv->stream_pq_local->len, PktSrcToString(xp->pkt_src)); + SCLogNotice("tv %p: ==> stream_pq_local: pq.len %u packet src %s", tv, + tv->stream_pq_local->len, PktSrcToString(xp->pkt_src)); } } for (Packet *xp = tv->decode_pq.top; xp != NULL; xp = xp->next) { - SCLogNotice("tv %p: ==> decode_pq: decode_pq.len %u packet src %s", - tv, tv->decode_pq.len, PktSrcToString(xp->pkt_src)); + SCLogNotice("tv %p: ==> decode_pq: decode_pq.len %u packet src %s", tv, + tv->decode_pq.len, PktSrcToString(xp->pkt_src)); } TmThreadDoDumpSlots(tv); tv = tv->next; @@ -2058,10 +2043,10 @@ static void TmThreadDumpThreads(void) #endif typedef struct Thread_ { - ThreadVars *tv; /**< threadvars structure */ + ThreadVars *tv; /**< threadvars structure */ const char *name; int type; - int in_use; /**< bool to indicate this is in use */ + int in_use; /**< bool to indicate this is in use */ SCTime_t pktts; /**< current packet time of this thread * (offline mode) */ @@ -2086,13 +2071,13 @@ void TmThreadsListThreads(void) if (t == NULL || t->in_use == 0) continue; - SCLogNotice("Thread %"PRIuMAX", %s type %d, tv %p in_use %d", - (uintmax_t)s+1, t->name, t->type, t->tv, t->in_use); + SCLogNotice("Thread %" PRIuMAX ", %s type %d, tv %p in_use %d", (uintmax_t)s + 1, t->name, + t->type, t->tv, t->in_use); if (t->tv) { ThreadVars *tv = t->tv; const uint32_t flags = SC_ATOMIC_GET(tv->flags); - SCLogNotice("tv %p type %u name %s tmm_flags %02X flags %X", - tv, tv->type, tv->name, tv->tmm_flags, flags); + SCLogNotice("tv %p type %u name %s tmm_flags %02X flags %X", tv, tv->type, tv->name, + tv->tmm_flags, flags); } } SCMutexUnlock(&thread_store_lock); @@ -2121,15 +2106,17 @@ int TmThreadsRegisterThread(ThreadVars *tv, const int type) t->in_use = 1; SCMutexUnlock(&thread_store_lock); - return (int)(s+1); + return (int)(s + 1); } } /* if we get here the array is completely filled */ - void *newmem = SCRealloc(thread_store.threads, ((thread_store.threads_size + STEP) * sizeof(Thread))); + void *newmem = + SCRealloc(thread_store.threads, ((thread_store.threads_size + STEP) * sizeof(Thread))); BUG_ON(newmem == NULL); thread_store.threads = newmem; - memset((uint8_t *)thread_store.threads + (thread_store.threads_size * sizeof(Thread)), 0x00, STEP * sizeof(Thread)); + memset((uint8_t *)thread_store.threads + (thread_store.threads_size * sizeof(Thread)), 0x00, + STEP * sizeof(Thread)); Thread *t = &thread_store.threads[thread_store.threads_size]; t->name = tv->name; @@ -2141,7 +2128,7 @@ int TmThreadsRegisterThread(ThreadVars *tv, const int type) thread_store.threads_size += STEP; SCMutexUnlock(&thread_store_lock); - return (int)(s+1); + return (int)(s + 1); } #undef STEP @@ -2260,7 +2247,7 @@ void TmThreadsGetMinimalTimestamp(struct timeval *ts) } SCMutexUnlock(&thread_store_lock); *ts = local; - SCLogDebug("ts->tv_sec %"PRIuMAX, (uintmax_t)ts->tv_sec); + SCLogDebug("ts->tv_sec %" PRIuMAX, (uintmax_t)ts->tv_sec); } uint16_t TmThreadsGetWorkerThreadMax(void) diff --git a/src/tm-threads.h b/src/tm-threads.h index 4ca55f9bc72c..9e2c2e74fe82 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -45,7 +45,7 @@ static inline void SleepUsec(uint64_t usec) #define SleepMsec(msec) usleep((msec) * 1000) #endif -#define TM_QUEUE_NAME_MAX 16 +#define TM_QUEUE_NAME_MAX 16 #define TM_THREAD_NAME_MAX 16 typedef TmEcode (*TmSlotFunc)(ThreadVars *, Packet *, void *); @@ -84,15 +84,13 @@ extern SCMutex tv_root_lock; void TmSlotSetFuncAppend(ThreadVars *, TmModule *, const void *); -ThreadVars *TmThreadCreate(const char *, const char *, const char *, const char *, const char *, const char *, - void *(fn_p)(void *), int); -ThreadVars *TmThreadCreatePacketHandler(const char *, const char *, const char *, const char *, const char *, - const char *); +ThreadVars *TmThreadCreate(const char *, const char *, const char *, const char *, const char *, + const char *, void *(fn_p)(void *), int); +ThreadVars *TmThreadCreatePacketHandler( + const char *, const char *, const char *, const char *, const char *, const char *); ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), int); -ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, const char *module, - int mucond); -ThreadVars *TmThreadCreateCmdThreadByName(const char *name, const char *module, - int mucond); +ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, const char *module, int mucond); +ThreadVars *TmThreadCreateCmdThreadByName(const char *name, const char *module, int mucond); TmEcode TmThreadSpawn(ThreadVars *); void TmThreadKillThreadsFamily(int family); void TmThreadKillThreads(void); @@ -119,7 +117,7 @@ void TmThreadsSetFlag(ThreadVars *, uint32_t); void TmThreadsUnsetFlag(ThreadVars *, uint32_t); void TmThreadWaitForFlag(ThreadVars *, uint32_t); -TmEcode TmThreadsSlotVarRun (ThreadVars *tv, Packet *p, TmSlot *slot); +TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p, TmSlot *slot); void TmThreadDisablePacketThreads(void); void TmThreadDisableReceiveThreads(void); diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index e11d05d71373..054c81f1c72e 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -38,7 +38,7 @@ #include "tm-queuehandlers.h" #include "conf.h" -#include "util-unittest.h" +#include "util/unittest.h" Packet *TmqhInputFlow(ThreadVars *t); void TmqhOutputFlowHash(ThreadVars *t, Packet *p); @@ -85,9 +85,9 @@ void TmqhFlowRegister(void) void TmqhFlowPrintAutofpHandler(void) { -#define PRINT_IF_FUNC(f, msg) \ - if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \ - SCLogConfig("AutoFP mode using \"%s\" flow load balancer", (msg)) +#define PRINT_IF_FUNC(f, msg) \ + if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \ + SCLogConfig("AutoFP mode using \"%s\" flow load balancer", (msg)) PRINT_IF_FUNC(TmqhOutputFlowHash, "Hash"); PRINT_IF_FUNC(TmqhOutputFlowIPPair, "IPPair"); @@ -183,16 +183,16 @@ void *TmqhOutputFlowSetupCtx(const char *queue_str) /* parse the comma separated string */ do { - char *comma = strchr(tstr,','); + char *comma = strchr(tstr, ','); if (comma != NULL) { *comma = '\0'; char *qname = tstr; - int r = StoreQueueId(ctx,qname); + int r = StoreQueueId(ctx, qname); if (r < 0) goto error; } else { char *qname = tstr; - int r = StoreQueueId(ctx,qname); + int r = StoreQueueId(ctx, qname); if (r < 0) goto error; } @@ -213,8 +213,7 @@ void TmqhOutputFlowFreeCtx(void *ctx) { TmqhFlowCtx *fctx = (TmqhFlowCtx *)ctx; - SCLogPerf("AutoFP - Total flow handler queues - %" PRIu16, - fctx->size); + SCLogPerf("AutoFP - Total flow handler queues - %" PRIu16, fctx->size); SCFree(fctx->queues); SCFree(fctx); @@ -406,12 +405,9 @@ static int TmqhOutputFlowSetupCtxTest03(void) void TmqhFlowRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("TmqhOutputFlowSetupCtxTest01", - TmqhOutputFlowSetupCtxTest01); - UtRegisterTest("TmqhOutputFlowSetupCtxTest02", - TmqhOutputFlowSetupCtxTest02); - UtRegisterTest("TmqhOutputFlowSetupCtxTest03", - TmqhOutputFlowSetupCtxTest03); + UtRegisterTest("TmqhOutputFlowSetupCtxTest01", TmqhOutputFlowSetupCtxTest01); + UtRegisterTest("TmqhOutputFlowSetupCtxTest02", TmqhOutputFlowSetupCtxTest02); + UtRegisterTest("TmqhOutputFlowSetupCtxTest03", TmqhOutputFlowSetupCtxTest03); #endif return; diff --git a/src/tmqh-flow.h b/src/tmqh-flow.h index 3cec7a165f5b..7afcf58e8917 100644 --- a/src/tmqh-flow.h +++ b/src/tmqh-flow.h @@ -38,7 +38,7 @@ typedef struct TmqhFlowCtx_ { TmqhFlowMode *queues; } TmqhFlowCtx; -void TmqhFlowRegister (void); +void TmqhFlowRegister(void); void TmqhFlowRegisterTests(void); void TmqhFlowPrintAutofpHandler(void); diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index f71274b4502c..4e6f890fba70 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -31,8 +31,8 @@ #include "decode.h" #include "tm-modules.h" #include "packet.h" -#include "util-profiling.h" -#include "util-validate.h" +#include "util/profiling.h" +#include "util/validate.h" #include "action-globals.h" extern uint16_t max_pending_packets; @@ -52,7 +52,7 @@ static inline PktPool *GetThreadPacketPool(void) * \brief TmqhPacketpoolRegister * \initonly */ -void TmqhPacketpoolRegister (void) +void TmqhPacketpoolRegister(void) { tmqh_table[TMQH_PACKETPOOL].name = "packetpool"; tmqh_table[TMQH_PACKETPOOL].InHandler = TmqhInputPacketpool; @@ -91,7 +91,7 @@ void PacketPoolWait(void) UpdateReturnThreshold(my_pool); } - while(PacketPoolIsEmpty(my_pool)) + while (PacketPoolIsEmpty(my_pool)) cc_barrier(); } @@ -275,8 +275,7 @@ void PacketPoolInit(void) SC_ATOMIC_SET(my_pool->return_stack.return_threshold, 32); /* pre allocate packets */ - SCLogDebug("preallocating packets... packet size %" PRIuMAX "", - (uintmax_t)SIZE_OF_PACKET); + SCLogDebug("preallocating packets... packet size %" PRIuMAX "", (uintmax_t)SIZE_OF_PACKET); int i = 0; for (i = 0; i < max_pending_packets; i++) { Packet *p = PacketGetFromAlloc(); @@ -286,8 +285,8 @@ void PacketPoolInit(void) PacketPoolStorePacket(p); } - //SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", - // max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); + // SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", + // max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); } void PacketPoolDestroy(void) @@ -338,8 +337,7 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) SCLogDebug("Packet %p, p->root %p, alloced %s", p, p->root, BOOL2STR(p->pool == NULL)); if (IS_TUNNEL_PKT(p)) { - SCLogDebug("Packet %p is a tunnel packet: %s", - p,p->root ? "upper layer" : "tunnel root"); + SCLogDebug("Packet %p is a tunnel packet: %s", p, p->root ? "upper layer" : "tunnel root"); /* get a lock to access root packet fields */ SCSpinlock *lock = p->root ? &p->root->persistent.tunnel_lock : &p->persistent.tunnel_lock; @@ -353,15 +351,16 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) SCLogDebug("root pkt: outstanding %u", outstanding); if (outstanding == 0) { SCLogDebug("no tunnel packets outstanding, no more tunnel " - "packet(s) depending on this root"); + "packet(s) depending on this root"); /* if this packet is the root and there are no * more tunnel packets to consider * * return it to the pool */ } else { SCLogDebug("tunnel root Packet %p: outstanding > 0, so " - "packets are still depending on this root, setting " - "SET_TUNNEL_PKT_VERDICTED", p); + "packets are still depending on this root, setting " + "SET_TUNNEL_PKT_VERDICTED", + p); /* if this is the root and there are more tunnel * packets, return this to the pool. It's still referenced * by the tunnel packets, and we will return it @@ -381,14 +380,13 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) /* all tunnel packets are processed except us. Root already * processed. So return tunnel pkt and root packet to the * pool. */ - if (outstanding == 0 && - p->root && IS_TUNNEL_PKT_VERDICTED(p->root)) - { + if (outstanding == 0 && p->root && IS_TUNNEL_PKT_VERDICTED(p->root)) { SCLogDebug("root verdicted == true && no outstanding"); /* handle freeing the root as well*/ SCLogDebug("setting proot = 1 for root pkt, p->root %p " - "(tunnel packet %p)", p->root, p); + "(tunnel packet %p)", + p->root, p); proot = true; /* fall through */ @@ -398,7 +396,7 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) * so get rid of the tunnel pkt only */ SCLogDebug("NOT IS_TUNNEL_PKT_VERDICTED (%s) || " - "outstanding > 0 (%u)", + "outstanding > 0 (%u)", (p->root && IS_TUNNEL_PKT_VERDICTED(p->root)) ? "true" : "false", outstanding); @@ -500,6 +498,6 @@ void PacketPoolPostRunmodes(void) if (max_pending_return_packets >= RESERVED_PACKETS) max_pending_return_packets -= RESERVED_PACKETS; - SCLogDebug("detect threads %u, max packets %u, max_pending_return_packets %u", - threads, packets, max_pending_return_packets); + SCLogDebug("detect threads %u, max packets %u, max_pending_return_packets %u", threads, packets, + max_pending_return_packets); } diff --git a/src/tmqh-packetpool.h b/src/tmqh-packetpool.h index 74074f953378..67801a73984c 100644 --- a/src/tmqh-packetpool.h +++ b/src/tmqh-packetpool.h @@ -27,8 +27,8 @@ #include "decode.h" #include "threads.h" - /* Return stack, onto which other threads free packets. */ -typedef struct PktPoolLockedStack_{ +/* Return stack, onto which other threads free packets. */ +typedef struct PktPoolLockedStack_ { /* linked list of free packets. */ SCMutex mutex; SCCondT cond; diff --git a/src/tmqh-simple.c b/src/tmqh-simple.c index 47faed5702c5..672f85ff61db 100644 --- a/src/tmqh-simple.c +++ b/src/tmqh-simple.c @@ -36,7 +36,7 @@ Packet *TmqhInputSimple(ThreadVars *t); void TmqhOutputSimple(ThreadVars *t, Packet *p); void TmqhInputSimpleShutdownHandler(ThreadVars *); -void TmqhSimpleRegister (void) +void TmqhSimpleRegister(void) { tmqh_table[TMQH_SIMPLE].name = "simple"; tmqh_table[TMQH_SIMPLE].InHandler = TmqhInputSimple; @@ -91,4 +91,3 @@ void TmqhOutputSimple(ThreadVars *t, Packet *p) SCCondSignal(&q->cond_q); SCMutexUnlock(&q->mutex_q); } - diff --git a/src/tmqh-simple.h b/src/tmqh-simple.h index d80de5085203..a020ce379efe 100644 --- a/src/tmqh-simple.h +++ b/src/tmqh-simple.h @@ -24,6 +24,6 @@ #ifndef __TMQH_SIMPLE_H__ #define __TMQH_SIMPLE_H__ -void TmqhSimpleRegister (void); +void TmqhSimpleRegister(void); #endif /* __TMQH_SIMPLE_H__ */ diff --git a/src/tree.h b/src/tree.h index fd36955039d1..d3dcac26bd0f 100644 --- a/src/tree.h +++ b/src/tree.h @@ -29,8 +29,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _SYS_TREE_H_ -#define _SYS_TREE_H_ +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ #if defined(__clang_analyzer__) #define _T_ASSERT(a) assert((a)) @@ -65,749 +65,723 @@ * The maximum height of a red-black tree is 2lg (n+1). */ -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} +#define SPLAY_HEAD(name, type) \ + struct name { \ + struct type *sph_root; /* root of the tree */ \ + } -#define SPLAY_INITIALIZER(root) \ - { NULL } +#define SPLAY_INITIALIZER(root) \ + { \ + NULL \ + } -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (/*CONSTCOND*/ 0) +#define SPLAY_INIT(root) \ + do { \ + (root)->sph_root = NULL; \ + } while (/*CONSTCOND*/ 0) -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} +#define SPLAY_ENTRY(type) \ + struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ + } -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (/*CONSTCOND*/ 0) +#define SPLAY_ROTATE_RIGHT(head, tmp, field) \ + do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ + } while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) \ + do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ + } while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) \ + do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + } while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) \ + do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) \ + do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ + } while (/*CONSTCOND*/ 0) /* Generates prototypes and inline functions */ -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ + void name##_SPLAY(struct name *, struct type *); \ + void name##_SPLAY_MINMAX(struct name *, int); \ + struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ + struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ + /* Finds the node with the same key as elm */ \ + static __inline struct type *name##_SPLAY_FIND(struct name *head, struct type *elm) \ + { \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ + } \ + \ + static __inline struct type *name##_SPLAY_NEXT(struct name *head, struct type *elm) \ + { \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ + } \ + \ + static __inline struct type *name##_SPLAY_MIN_MAX(struct name *head, int val) \ + { \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ + } /* Main splay operation. * Moves node close to the key of elm to top */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) +#define SPLAY_GENERATE(name, type, field, cmp) \ + struct type *name##_SPLAY_INSERT(struct name *head, struct type *elm) \ + { \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if (__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ + } \ + \ + struct type *name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ + { \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ + } \ + \ + void name##_SPLAY(struct name *head, struct type *elm) \ + { \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0) { \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ + } \ + \ + /* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ + void name##_SPLAY_MINMAX(struct name *head, int __comp) \ + { \ + struct type __node, *__left, *__right, *__tmp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0) { \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ + } + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); (x) != NULL; (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} - -#define RB_INITIALIZER(root) \ - { NULL } - -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (/*CONSTCOND*/ 0) - -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} - -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) - -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (/*CONSTCOND*/ 0) - -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (/*CONSTCOND*/ 0) +#define RB_HEAD(name, type) \ + struct name { \ + struct type *rbh_root; /* root of the tree */ \ + } + +#define RB_INITIALIZER(root) \ + { \ + NULL \ + } + +#define RB_INIT(root) \ + do { \ + (root)->rbh_root = NULL; \ + } while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ + struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ + } + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) \ + do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ + } while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) \ + do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ + } while (/*CONSTCOND*/ 0) #ifndef RB_AUGMENT -#define RB_AUGMENT(x) do {} while (0) +#define RB_AUGMENT(x) \ + do { \ + } while (0) #endif -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (/*CONSTCOND*/ 0) - -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (/*CONSTCOND*/ 0) +#define RB_ROTATE_LEFT(head, elm, tmp, field) \ + do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ + } while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) \ + do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ + } while (/*CONSTCOND*/ 0) /* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) -#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) -#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ - RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ - RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ - RB_PROTOTYPE_INSERT(name, type, attr); \ - RB_PROTOTYPE_REMOVE(name, type, attr); \ - RB_PROTOTYPE_FIND(name, type, attr); \ - RB_PROTOTYPE_NFIND(name, type, attr); \ - RB_PROTOTYPE_NEXT(name, type, attr); \ - RB_PROTOTYPE_PREV(name, type, attr); \ - RB_PROTOTYPE_MINMAX(name, type, attr); -#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ - attr void name##_RB_INSERT_COLOR(struct name *, struct type *) -#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ - attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *) -#define RB_PROTOTYPE_REMOVE(name, type, attr) \ - attr struct type *name##_RB_REMOVE(struct name *, struct type *) -#define RB_PROTOTYPE_INSERT(name, type, attr) \ - attr struct type *name##_RB_INSERT(struct name *, struct type *) -#define RB_PROTOTYPE_FIND(name, type, attr) \ - attr struct type *name##_RB_FIND(struct name *, struct type *) -#define RB_PROTOTYPE_NFIND(name, type, attr) \ - attr struct type *name##_RB_NFIND(struct name *, struct type *) -#define RB_PROTOTYPE_NEXT(name, type, attr) \ - attr struct type *name##_RB_NEXT(struct type *) -#define RB_PROTOTYPE_PREV(name, type, attr) \ - attr struct type *name##_RB_PREV(struct type *) -#define RB_PROTOTYPE_MINMAX(name, type, attr) \ - attr struct type *name##_RB_MINMAX(struct name *, int) +#define RB_PROTOTYPE(name, type, field, cmp) RB_PROTOTYPE_INTERNAL(name, type, field, cmp, ) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ + RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ + RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ + RB_PROTOTYPE_INSERT(name, type, attr); \ + RB_PROTOTYPE_REMOVE(name, type, attr); \ + RB_PROTOTYPE_FIND(name, type, attr); \ + RB_PROTOTYPE_NFIND(name, type, attr); \ + RB_PROTOTYPE_NEXT(name, type, attr); \ + RB_PROTOTYPE_PREV(name, type, attr); \ + RB_PROTOTYPE_MINMAX(name, type, attr); +#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ + attr void name##_RB_INSERT_COLOR(struct name *, struct type *) +#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ + attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *) +#define RB_PROTOTYPE_REMOVE(name, type, attr) \ + attr struct type *name##_RB_REMOVE(struct name *, struct type *) +#define RB_PROTOTYPE_INSERT(name, type, attr) \ + attr struct type *name##_RB_INSERT(struct name *, struct type *) +#define RB_PROTOTYPE_FIND(name, type, attr) \ + attr struct type *name##_RB_FIND(struct name *, struct type *) +#define RB_PROTOTYPE_NFIND(name, type, attr) \ + attr struct type *name##_RB_NFIND(struct name *, struct type *) +#define RB_PROTOTYPE_NEXT(name, type, attr) attr struct type *name##_RB_NEXT(struct type *) +#define RB_PROTOTYPE_PREV(name, type, attr) attr struct type *name##_RB_PREV(struct type *) +#define RB_PROTOTYPE_MINMAX(name, type, attr) attr struct type *name##_RB_MINMAX(struct name *, int) /* Main rb operation. * Moves node close to the key of elm to top */ -#define RB_GENERATE(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp,) -#define RB_GENERATE_STATIC(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) -#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ - RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ - RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ - RB_GENERATE_INSERT(name, type, field, cmp, attr) \ - RB_GENERATE_REMOVE(name, type, field, attr) \ - RB_GENERATE_FIND(name, type, field, cmp, attr) \ - RB_GENERATE_NFIND(name, type, field, cmp, attr) \ - RB_GENERATE_NEXT(name, type, field, attr) \ - RB_GENERATE_PREV(name, type, field, attr) \ - RB_GENERATE_MINMAX(name, type, field, attr) - -#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ -attr void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) != NULL && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - _T_ASSERT(gparent); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} - -#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ -attr void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - _T_ASSERT(tmp); \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)) \ - != NULL) \ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - _T_ASSERT(tmp); \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)) \ - != NULL) \ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} - -#define RB_GENERATE_REMOVE(name, type, field, attr) \ -attr struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field)) != NULL) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - _T_ASSERT((old)); \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - _T_ASSERT(old); \ - _T_ASSERT(RB_LEFT(old, field)); \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field)) != NULL); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ - -#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ -/* Inserts a node into the RB tree */ \ -attr struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} - -#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ -/* Finds the node with the same key as elm */ \ -attr struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} - -#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ -/* Finds the first node greater than or equal to the search key */ \ -attr struct type * \ -name##_RB_NFIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *res = NULL; \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) { \ - res = tmp; \ - tmp = RB_LEFT(tmp, field); \ - } \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (res); \ -} - -#define RB_GENERATE_NEXT(name, type, field, attr) \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} - -#define RB_GENERATE_PREV(name, type, field, attr) \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_PREV(struct type *elm) \ -{ \ - if (RB_LEFT(elm, field)) { \ - elm = RB_LEFT(elm, field); \ - while (RB_RIGHT(elm, field)) \ - elm = RB_RIGHT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} - -#define RB_GENERATE_MINMAX(name, type, field, attr) \ -attr struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} - -#define RB_NEGINF -1 -#define RB_INF 1 - -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_PREV(name, x, y) name##_RB_PREV(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) - -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) - -#define RB_FOREACH_FROM(x, name, y) \ - for ((x) = (y); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ - (x) = (y)) - -#define RB_FOREACH_SAFE(x, name, head, y) \ - for ((x) = RB_MIN(name, head); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ - (x) = (y)) - -#define RB_FOREACH_REVERSE(x, name, head) \ - for ((x) = RB_MAX(name, head); \ - (x) != NULL; \ - (x) = name##_RB_PREV(x)) - -#define RB_FOREACH_REVERSE_FROM(x, name, y) \ - for ((x) = (y); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ - (x) = (y)) - -#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ - for ((x) = RB_MAX(name, head); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ - (x) = (y)) - -#endif /* _SYS_TREE_H_ */ +#define RB_GENERATE(name, type, field, cmp) RB_GENERATE_INTERNAL(name, type, field, cmp, ) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ + RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + RB_GENERATE_REMOVE(name, type, field, attr) \ + RB_GENERATE_FIND(name, type, field, cmp, attr) \ + RB_GENERATE_NFIND(name, type, field, cmp, attr) \ + RB_GENERATE_NEXT(name, type, field, attr) \ + RB_GENERATE_PREV(name, type, field, attr) \ + RB_GENERATE_MINMAX(name, type, field, attr) + +#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + attr void name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ + { \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + _T_ASSERT(gparent); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ + } + +#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + attr void name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ + { \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + _T_ASSERT(tmp); \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + _T_ASSERT(tmp); \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) != NULL) \ + RB_COLOR(oright, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ + } + +#define RB_GENERATE_REMOVE(name, type, field, attr) \ + attr struct type *name##_RB_REMOVE(struct name *head, struct type *elm) \ + { \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + _T_ASSERT((old)); \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old) \ + RB_LEFT(RB_PARENT(old, field), field) = elm; \ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm; \ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + _T_ASSERT(old); \ + _T_ASSERT(RB_LEFT(old, field)); \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ + } + +#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + /* Inserts a node into the RB tree */ \ + attr struct type *name##_RB_INSERT(struct name *head, struct type *elm) \ + { \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ + } + +#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ + /* Finds the node with the same key as elm */ \ + attr struct type *name##_RB_FIND(struct name *head, struct type *elm) \ + { \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ + } + +#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ + /* Finds the first node greater than or equal to the search key */ \ + attr struct type *name##_RB_NFIND(struct name *head, struct type *elm) \ + { \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ + } + +#define RB_GENERATE_NEXT(name, type, field, attr) \ + /* ARGSUSED */ \ + attr struct type *name##_RB_NEXT(struct type *elm) \ + { \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ + } + +#define RB_GENERATE_PREV(name, type, field, attr) \ + /* ARGSUSED */ \ + attr struct type *name##_RB_PREV(struct type *elm) \ + { \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ + } + +#define RB_GENERATE_MINMAX(name, type, field, attr) \ + attr struct type *name##_RB_MINMAX(struct name *head, int val) \ + { \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ + } + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); (x) != NULL; (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); (x) != NULL; (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#endif /* _SYS_TREE_H_ */ diff --git a/src/unix-manager.c b/src/unix-manager.c index 9fb5bd7935bc..daa25f443ded 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -30,41 +30,42 @@ #include "conf.h" #include "runmode-unix-socket.h" -#include "output-json-stats.h" - -#include "util-conf.h" -#include "util-privs.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-ebpf.h" -#include "util-signal.h" -#include "util-buffer.h" -#include "util-path.h" -#include "util-profiling.h" - -#if (defined BUILD_UNIX_SOCKET) && (defined HAVE_SYS_UN_H) && (defined HAVE_SYS_STAT_H) && (defined HAVE_SYS_TYPES_H) +#include "output/eve/output-json-stats.h" + +#include "util/conf.h" +#include "util/privs.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/ebpf.h" +#include "util/signal.h" +#include "util/buffer.h" +#include "util/path.h" +#include "util/profiling.h" + +#if (defined BUILD_UNIX_SOCKET) && (defined HAVE_SYS_UN_H) && (defined HAVE_SYS_STAT_H) && \ + (defined HAVE_SYS_TYPES_H) #include #include #include -#include "output.h" -#include "output-json.h" +#include "output/output.h" +#include "output/eve/output-json.h" // MSG_NOSIGNAL does not exists on OS X #ifdef OS_DARWIN -# ifndef MSG_NOSIGNAL -# define MSG_NOSIGNAL SO_NOSIGPIPE -# endif +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL SO_NOSIGPIPE +#endif #endif -#define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/" +#define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/" #define SOCKET_FILENAME "suricata-command.socket" -#define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME +#define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME SCCtrlCondT unix_manager_ctrl_cond; SCCtrlMutex unix_manager_ctrl_mutex; -#define MAX_FAILED_RULES 20 +#define MAX_FAILED_RULES 20 typedef struct Command_ { char *name; @@ -103,7 +104,7 @@ typedef struct UnixCommand_ { * * \retval 0 in case of error, 1 in case of success */ -static int UnixNew(UnixCommand * this) +static int UnixNew(UnixCommand *this) { struct sockaddr_un addr; int len; @@ -125,8 +126,7 @@ static int UnixNew(UnixCommand * this) if (PathIsAbsolute(socketname)) { strlcpy(sockettarget, socketname, sizeof(sockettarget)); } else { - snprintf(sockettarget, sizeof(sockettarget), "%s/%s", - SOCKET_PATH, socketname); + snprintf(sockettarget, sizeof(sockettarget), "%s/%s", SOCKET_PATH, socketname); check_dir = 1; } } else { @@ -140,7 +140,7 @@ static int UnixNew(UnixCommand * this) /* coverity[toctou] */ if (stat(SOCKET_PATH, &stat_buf) != 0) { /* coverity[toctou] */ - ret = SCMkDir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); + ret = SCMkDir(SOCKET_PATH, S_IRWXU | S_IXGRP | S_IRGRP); if (ret != 0) { int err = errno; if (err != EEXIST) { @@ -155,7 +155,7 @@ static int UnixNew(UnixCommand * this) } /* Remove socket file */ - (void) unlink(sockettarget); + (void)unlink(sockettarget); /* set address */ addr.sun_family = AF_UNIX; @@ -173,14 +173,13 @@ static int UnixNew(UnixCommand * this) this->select_max = this->socket + 1; /* set reuse option */ - ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, - (char *) &on, sizeof(on)); - if ( ret != 0 ) { + ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); + if (ret != 0) { SCLogWarning("Cannot set sockets options: %s.", strerror(errno)); } /* bind socket */ - ret = bind(this->socket, (struct sockaddr *) &addr, len); + ret = bind(this->socket, (struct sockaddr *)&addr, len); if (ret == -1) { SCLogWarning("Unix socket: UNIX socket bind(%s) error: %s", sockettarget, strerror(errno)); return 0; @@ -190,7 +189,7 @@ static int UnixNew(UnixCommand * this) /* Set file mode: will not fully work on most system, the group * permission is not changed on some Linux. *BSD won't do the * chmod: it returns EINVAL when calling chmod on sockets. */ - ret = chmod(sockettarget, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); + ret = chmod(sockettarget, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (ret == -1) { int err = errno; SCLogWarning("Unable to change permission on socket: %s (%d)", strerror(err), err); @@ -215,7 +214,7 @@ static void UnixCommandSetMaxFD(UnixCommand *this) } this->select_max = this->socket + 1; - TAILQ_FOREACH(item, &this->clients, next) { + TAILQ_FOREACH (item, &this->clients, next) { if (item->fd >= this->select_max) { this->select_max = item->fd + 1; } @@ -249,12 +248,12 @@ static void UnixClientFree(UnixClient *c) /** * \brief Close the unix socket */ -static void UnixCommandClose(UnixCommand *this, int fd) +static void UnixCommandClose(UnixCommand *this, int fd) { UnixClient *item; int found = 0; - TAILQ_FOREACH(item, &this->clients, next) { + TAILQ_FOREACH (item, &this->clients, next) { if (item->fd == fd) { found = 1; break; @@ -274,23 +273,20 @@ static void UnixCommandClose(UnixCommand *this, int fd) } #define UNIX_PROTO_VERSION_LENGTH 200 -#define UNIX_PROTO_VERSION_V1 "0.1" -#define UNIX_PROTO_V1 1 -#define UNIX_PROTO_VERSION "0.2" -#define UNIX_PROTO_V2 2 +#define UNIX_PROTO_VERSION_V1 "0.1" +#define UNIX_PROTO_V1 1 +#define UNIX_PROTO_VERSION "0.2" +#define UNIX_PROTO_V2 2 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js) { MemBufferReset(client->mbuf); - OutputJSONMemBufferWrapper wrapper = { - .buffer = &client->mbuf, - .expand_by = CLIENT_BUFFER_SIZE - }; + OutputJSONMemBufferWrapper wrapper = { .buffer = &client->mbuf, + .expand_by = CLIENT_BUFFER_SIZE }; int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, - JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| - JSON_ESCAPE_SLASH); + JSON_PRESERVE_ORDER | JSON_COMPACT | JSON_ENSURE_ASCII | JSON_ESCAPE_SLASH); if (r != 0) { SCLogWarning("unable to serialize JSON object"); return -1; @@ -304,15 +300,14 @@ static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js) } if (send(client->fd, (const char *)MEMBUFFER_BUFFER(client->mbuf), - MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1) - { + MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1) { SCLogWarning("unable to send block of size " "%" PRIuMAX ": %s", (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), strerror(errno)); return -1; } - SCLogDebug("sent message of size %"PRIuMAX" to client socket %d", + SCLogDebug("sent message of size %" PRIuMAX " to client socket %d", (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), client->fd); return 0; } @@ -340,24 +335,22 @@ static int UnixCommandAccept(UnixCommand *this) /* accept client socket */ socklen_t len = sizeof(this->client_addr); - client = accept(this->socket, (struct sockaddr *) &this->client_addr, - &len); + client = accept(this->socket, (struct sockaddr *)&this->client_addr, &len); if (client < 0) { - SCLogInfo("Unix socket: accept() error: %s", - strerror(errno)); + SCLogInfo("Unix socket: accept() error: %s", strerror(errno)); return 0; } SCLogDebug("Unix socket: client connection"); /* read client version */ - buffer[sizeof(buffer)-1] = 0; - ret = recv(client, buffer, sizeof(buffer)-1, 0); + buffer[sizeof(buffer) - 1] = 0; + ret = recv(client, buffer, sizeof(buffer) - 1, 0); if (ret < 0) { SCLogInfo("Command server: client doesn't send version"); close(client); return 0; } - if (ret >= (int)(sizeof(buffer)-1)) { + if (ret >= (int)(sizeof(buffer) - 1)) { SCLogInfo("Command server: client message is too long, " "disconnect him."); close(client); @@ -381,16 +374,14 @@ static int UnixCommandAccept(UnixCommand *this) } /* check client version */ - if ((strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0) - && (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) != 0)) { - SCLogInfo("Unix socket: invalid client version: \"%s\"", - json_string_value(version)); + if ((strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0) && + (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) != 0)) { + SCLogInfo("Unix socket: invalid client version: \"%s\"", json_string_value(version)); json_decref(client_msg); close(client); return 0; } else { - SCLogDebug("Unix socket: client version: \"%s\"", - json_string_value(version)); + SCLogDebug("Unix socket: client version: \"%s\"", json_string_value(version)); if (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) == 0) { client_version = UNIX_PROTO_V1; } else { @@ -434,12 +425,12 @@ static int UnixCommandAccept(UnixCommand *this) return 1; } -static int UnixCommandBackgroundTasks(UnixCommand* this) +static int UnixCommandBackgroundTasks(UnixCommand *this) { int ret = 1; Task *ltask; - TAILQ_FOREACH(ltask, &this->tasks, next) { + TAILQ_FOREACH (ltask, &this->tasks, next) { int fret = ltask->Func(ltask->data); if (fret != TM_ECODE_OK) { ret = 0; @@ -457,14 +448,14 @@ static int UnixCommandBackgroundTasks(UnixCommand* this) * * \retval 0 in case of error, 1 in case of success */ -static int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client) +static int UnixCommandExecute(UnixCommand *this, char *command, UnixClient *client) { int ret = 1; json_error_t error; json_t *jsoncmd = NULL; json_t *cmd = NULL; json_t *server_msg = json_object(); - const char * value; + const char *value; int found = 0; Command *lcmd; @@ -479,19 +470,19 @@ static int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *cli } cmd = json_object_get(jsoncmd, "command"); - if(!json_is_string(cmd)) { + if (!json_is_string(cmd)) { SCLogInfo("error: command is not a string"); goto error_cmd; } value = json_string_value(cmd); - TAILQ_FOREACH(lcmd, &this->commands, next) { + TAILQ_FOREACH (lcmd, &this->commands, next) { if (!strcmp(value, lcmd->name)) { int fret = TM_ECODE_OK; found = 1; if (lcmd->flags & UNIX_CMD_TAKE_ARGS) { cmd = json_object_get(jsoncmd, "arguments"); - if(!json_is_object(cmd)) { + if (!json_is_object(cmd)) { SCLogInfo("error: argument is not an object"); goto error_cmd; } @@ -534,7 +525,7 @@ static int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *cli return 0; } -static void UnixCommandRun(UnixCommand * this, UnixClient *client) +static void UnixCommandRun(UnixCommand *this, UnixClient *client) { char buffer[4096]; int ret; @@ -549,7 +540,7 @@ static void UnixCommandRun(UnixCommand * this, UnixClient *client) UnixCommandClose(this, client->fd); return; } - if (ret >= (int)(sizeof(buffer)-1)) { + if (ret >= (int)(sizeof(buffer) - 1)) { SCLogError("Command server: client command is too long, " "disconnect him."); UnixCommandClose(this, client->fd); @@ -570,13 +561,13 @@ static void UnixCommandRun(UnixCommand * this, UnixClient *client) UnixCommandClose(this, client->fd); return; } - if (ret >= (int)(sizeof(buffer)- offset - 1)) { + if (ret >= (int)(sizeof(buffer) - offset - 1)) { SCLogInfo("Command server: client command is too long, " - "disconnect him."); + "disconnect him."); UnixCommandClose(this, client->fd); } if (buffer[ret - 1] == '\n') { - buffer[ret-1] = 0; + buffer[ret - 1] = 0; cmd_over = 1; } else { struct timeval tv; @@ -600,8 +591,7 @@ static void UnixCommandRun(UnixCommand * this, UnixClient *client) } } while (ret == 0 && try < 3); if (ret > 0) { - ret = recv(client->fd, buffer + offset, - sizeof(buffer) - offset - 1, 0); + ret = recv(client->fd, buffer + offset, sizeof(buffer) - offset - 1, 0); } } } while (try < 3 && cmd_over == 0); @@ -620,7 +610,7 @@ static void UnixCommandRun(UnixCommand * this, UnixClient *client) * * \retval 0 in case of error, 1 in case of success */ -static int UnixMain(UnixCommand * this) +static int UnixMain(UnixCommand *this) { struct timeval tv; int ret; @@ -638,7 +628,7 @@ static int UnixMain(UnixCommand * this) /* Wait activity on the socket */ FD_ZERO(&select_set); FD_SET(this->socket, &select_set); - TAILQ_FOREACH(uclient, &this->clients, next) { + TAILQ_FOREACH (uclient, &this->clients, next) { FD_SET(uclient->fd, &select_set); } @@ -661,7 +651,7 @@ static int UnixMain(UnixCommand * this) return 1; } - TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) { + TAILQ_FOREACH_SAFE (uclient, &this->clients, next, tclient) { if (FD_ISSET(uclient->fd, &select_set)) { UnixCommandRun(this, uclient); } @@ -674,8 +664,7 @@ static int UnixMain(UnixCommand * this) return 1; } -static TmEcode UnixManagerShutdownCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerShutdownCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string("Closing Suricata")); @@ -683,16 +672,14 @@ static TmEcode UnixManagerShutdownCommand(json_t *cmd, SCReturnInt(TM_ECODE_OK); } -static TmEcode UnixManagerVersionCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerVersionCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string(GetProgramVersion())); SCReturnInt(TM_ECODE_OK); } -static TmEcode UnixManagerUptimeCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerUptimeCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); int uptime; @@ -703,30 +690,29 @@ static TmEcode UnixManagerUptimeCommand(json_t *cmd, SCReturnInt(TM_ECODE_OK); } -static TmEcode UnixManagerRunningModeCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerRunningModeCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string(RunmodeGetActive())); SCReturnInt(TM_ECODE_OK); } -static TmEcode UnixManagerCaptureModeCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerCaptureModeCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); json_object_set_new(server_msg, "message", json_string(RunModeGetMainMode())); SCReturnInt(TM_ECODE_OK); } -static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg, void *data, int do_wait) +static TmEcode UnixManagerReloadRulesWrapper( + json_t *cmd, json_t *server_msg, void *data, int do_wait) { SCEnter(); if (SuriHasSigFile()) { json_object_set_new(server_msg, "message", - json_string("Live rule reload not possible if -s " - "or -S option used at runtime.")); + json_string("Live rule reload not possible if -s " + "or -S option used at runtime.")); SCReturnInt(TM_ECODE_FAILED); } @@ -756,8 +742,7 @@ static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0); } -static TmEcode UnixManagerReloadTimeCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerReloadTimeCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); TmEcode retval; @@ -768,8 +753,7 @@ static TmEcode UnixManagerReloadTimeCommand(json_t *cmd, SCReturnInt(retval); } -static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); TmEcode retval; @@ -812,8 +796,7 @@ static TmEcode UnixManagerRulesetProfileStopCommand(json_t *cmd, json_t *server_ } #endif -static TmEcode UnixManagerShowFailedRules(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerShowFailedRules(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); int rules_cnt = 0; @@ -833,7 +816,7 @@ static TmEcode UnixManagerShowFailedRules(json_t *cmd, } while (list) { SigString *sigs_str = NULL; - TAILQ_FOREACH(sigs_str, &list->sig_stat.failed_sigs, next) { + TAILQ_FOREACH (sigs_str, &list->sig_stat.failed_sigs, next) { json_t *jdata = json_object(); if (jdata == NULL) { json_object_set_new(server_msg, "message", json_string("Unable to get the sig")); @@ -869,8 +852,7 @@ static TmEcode UnixManagerShowFailedRules(json_t *cmd, SCReturnInt(TM_ECODE_FAILED); } -static TmEcode UnixManagerConfGetCommand(json_t *cmd, - json_t *server_msg, void *data) +static TmEcode UnixManagerConfGetCommand(json_t *cmd, json_t *server_msg, void *data) { SCEnter(); @@ -878,7 +860,7 @@ static TmEcode UnixManagerConfGetCommand(json_t *cmd, char *variable = NULL; json_t *jarg = json_object_get(cmd, "variable"); - if(!json_is_string(jarg)) { + if (!json_is_string(jarg)) { SCLogInfo("error: variable is not a string"); json_object_set_new(server_msg, "message", json_string("variable is not a string")); SCReturnInt(TM_ECODE_FAILED); @@ -899,30 +881,29 @@ static TmEcode UnixManagerConfGetCommand(json_t *cmd, SCReturnInt(TM_ECODE_FAILED); } -static TmEcode UnixManagerListCommand(json_t *cmd, - json_t *answer, void *data) +static TmEcode UnixManagerListCommand(json_t *cmd, json_t *answer, void *data) { SCEnter(); json_t *jdata; json_t *jarray; Command *lcmd = NULL; - UnixCommand *gcmd = (UnixCommand *) data; + UnixCommand *gcmd = (UnixCommand *)data; int i = 0; jdata = json_object(); if (jdata == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } jarray = json_array(); if (jarray == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); return TM_ECODE_FAILED; } - TAILQ_FOREACH(lcmd, &gcmd->commands, next) { + TAILQ_FOREACH (lcmd, &gcmd->commands, next) { json_array_append_new(jarray, json_string(lcmd->name)); i++; } @@ -967,7 +948,7 @@ static UnixCommand command; * * This function adds a command to the list of commands available * through the unix socket. - * + * * When a command is received from user through the unix socket, the content * of 'Command' field in the JSON message is match against keyword, then the * Func is called. See UnixSocketAddPcapFile() for an example. @@ -978,9 +959,8 @@ static UnixCommand command; * \param flags a flag now used to tune the command type * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure */ -TmEcode UnixManagerRegisterCommand(const char * keyword, - TmEcode (*Func)(json_t *, json_t *, void *), - void *data, int flags) +TmEcode UnixManagerRegisterCommand( + const char *keyword, TmEcode (*Func)(json_t *, json_t *, void *), void *data, int flags) { SCEnter(); Command *cmd = NULL; @@ -996,7 +976,7 @@ TmEcode UnixManagerRegisterCommand(const char * keyword, SCReturnInt(TM_ECODE_FAILED); } - TAILQ_FOREACH(lcmd, &command.commands, next) { + TAILQ_FOREACH (lcmd, &command.commands, next) { if (!strcmp(keyword, lcmd->name)) { SCLogError("%s already registered", keyword); SCReturnInt(TM_ECODE_FAILED); @@ -1028,13 +1008,12 @@ TmEcode UnixManagerRegisterCommand(const char * keyword, * * This function adds a task to run in the background. The task is run * each time the UnixMain() function exits from select. - * + * * \param Func function to run when a command is received * \param data a pointer to data that are passed to Func when it is run * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure */ -TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *), - void *data) +TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *), void *data) { SCEnter(); Task *task = NULL; @@ -1084,7 +1063,8 @@ int UnixManagerInit(void) UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0); UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); UnixManagerRegisterCommand("ruleset-reload-rules", UnixManagerReloadRules, NULL, 0); - UnixManagerRegisterCommand("ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0); + UnixManagerRegisterCommand( + "ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0); UnixManagerRegisterCommand("ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0); UnixManagerRegisterCommand("ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0); UnixManagerRegisterCommand("ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0); @@ -1095,14 +1075,20 @@ int UnixManagerInit(void) UnixManagerRegisterCommand( "ruleset-profile-stop", UnixManagerRulesetProfileStopCommand, NULL, 0); #endif - UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, + UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, + &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand( + "register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand( + "reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("reload-tenants", UnixSocketReloadTenants, &command, 0); - UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand( + "unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("add-hostbit", UnixSocketHostbitAdd, &command, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand( + "remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("reopen-log-files", UnixManagerReopenLogFiles, NULL, 0); UnixManagerRegisterCommand("memcap-set", UnixSocketSetMemcap, &command, UNIX_CMD_TAKE_ARGS); @@ -1110,7 +1096,8 @@ int UnixManagerInit(void) UnixManagerRegisterCommand("memcap-list", UnixSocketShowAllMemcap, NULL, 0); UnixManagerRegisterCommand("dataset-add", UnixSocketDatasetAdd, &command, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("dataset-remove", UnixSocketDatasetRemove, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand( + "dataset-remove", UnixSocketDatasetRemove, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand( "get-flow-stats-by-id", UnixSocketGetFlowStatsById, &command, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("dataset-dump", UnixSocketDatasetDump, NULL, 0); @@ -1166,7 +1153,7 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) if ((ret == 0) || (TmThreadsCheckFlag(th_v, THV_KILL))) { UnixClient *item; UnixClient *titem; - TAILQ_FOREACH_SAFE(item, &(&command)->clients, next, titem) { + TAILQ_FOREACH_SAFE (item, &(&command)->clients, next, titem) { close(item->fd); SCFree(item); } @@ -1179,7 +1166,6 @@ static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) return TM_ECODE_OK; } - /** \brief Spawn the unix socket manager thread * * \param mode if set to 1, init failure cause suricata exit @@ -1191,8 +1177,7 @@ void UnixManagerThreadSpawn(int mode) SCCtrlCondInit(&unix_manager_ctrl_cond, NULL); SCCtrlMutexInit(&unix_manager_ctrl_mutex, NULL); - tv_unixmgr = TmThreadCreateCmdThreadByName(thread_name_unix_socket, - "UnixManager", 0); + tv_unixmgr = TmThreadCreateCmdThreadByName(thread_name_unix_socket, "UnixManager", 0); if (tv_unixmgr == NULL) { FatalError("TmThreadsCreate failed"); @@ -1214,14 +1199,11 @@ void UnixManagerThreadSpawnNonRunmode(const bool unix_socket) /* Spawn the unix socket manager thread */ if (unix_socket) { if (UnixManagerInit() == 0) { - UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, - UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, UNIX_CMD_TAKE_ARGS); UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0); - UnixManagerRegisterCommand("iface-bypassed-stat", - LiveDeviceGetBypassedStats, NULL, 0); + UnixManagerRegisterCommand("iface-bypassed-stat", LiveDeviceGetBypassedStats, NULL, 0); /* For backward compatibility */ - UnixManagerRegisterCommand("ebpf-bypassed-stat", - LiveDeviceGetBypassedStats, NULL, 0); + UnixManagerRegisterCommand("ebpf-bypassed-stat", LiveDeviceGetBypassedStats, NULL, 0); UnixManagerThreadSpawn(0); } } @@ -1291,9 +1273,10 @@ void UnixManagerThreadSpawnNonRunmode(const bool unix_socket_enabled) #endif /* BUILD_UNIX_SOCKET */ -void TmModuleUnixManagerRegister (void) +void TmModuleUnixManagerRegister(void) { -#if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H) +#if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && \ + defined(HAVE_SYS_TYPES_H) tmm_modules[TMM_UNIXMANAGER].name = "UnixManager"; tmm_modules[TMM_UNIXMANAGER].ThreadInit = UnixManagerThreadInit; tmm_modules[TMM_UNIXMANAGER].ThreadDeinit = UnixManagerThreadDeinit; diff --git a/src/unix-manager.h b/src/unix-manager.h index 960879b3cbbf..8a14992efb52 100644 --- a/src/unix-manager.h +++ b/src/unix-manager.h @@ -36,12 +36,9 @@ void UnixManagerThreadSpawn(int mode); void UnixSocketKillSocketThread(void); #ifdef BUILD_UNIX_SOCKET -TmEcode UnixManagerRegisterCommand(const char * keyword, - TmEcode (*Func)(json_t *, json_t *, void *), - void *data, int flags); -TmEcode UnixManagerRegisterBackgroundTask( - TmEcode (*Func)(void *), - void *data); +TmEcode UnixManagerRegisterCommand( + const char *keyword, TmEcode (*Func)(json_t *, json_t *, void *), void *data, int flags); +TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *), void *data); #endif void TmModuleUnixManagerRegister(void); diff --git a/src/util-action.c b/src/util-action.c deleted file mode 100644 index 1b24bc5b0792..000000000000 --- a/src/util-action.c +++ /dev/null @@ -1,440 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon - */ - -#include "suricata-common.h" - -#include "action-globals.h" -#include "conf.h" -#include "conf-yaml-loader.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-sigorder.h" - -#include "util-unittest.h" -#include "util-action.h" -#include "util-unittest-helper.h" -#include "util-debug.h" - -/* Default order: */ -uint8_t action_order_sigs[4] = {ACTION_PASS, ACTION_DROP, ACTION_REJECT, ACTION_ALERT}; -/* This order can be changed from config */ - -/** - * \brief Return the priority associated to an action (to order sigs - * as specified at config) - * action_order_sigs has this priority by index val - * so action_order_sigs[0] has to be inspected first. - * This function is called from detect-engine-sigorder - * \param action can be one of ACTION_PASS, ACTION_DROP, - * ACTION_REJECT or ACTION_ALERT - * \retval uint8_t the priority (order of this actions) - */ -uint8_t ActionOrderVal(uint8_t action) -{ - /* reject_both and reject_dst have the same prio as reject */ - if( (action & ACTION_REJECT) || - (action & ACTION_REJECT_BOTH) || - (action & ACTION_REJECT_DST)) { - action = ACTION_REJECT; - } - uint8_t i = 0; - for (; i < 4; i++) { - if (action_order_sigs[i] == action) - return i; - } - /* Unknown action, set just a low prio (high val) */ - return 10; -} - -/** - * \brief Return the ACTION_* bit from their ascii value - * \param action can be one of "pass", "drop", - * "reject" or "alert" - * \retval uint8_t can be one of ACTION_PASS, ACTION_DROP, - * ACTION_REJECT or ACTION_ALERT - */ -static uint8_t ActionAsciiToFlag(const char *action) -{ - if (strcmp(action,"pass") == 0) - return ACTION_PASS; - if (strcmp(action,"drop") == 0) - return ACTION_DROP; - if (strcmp(action,"reject") == 0) - return ACTION_REJECT; - if (strcmp(action,"alert") == 0) - return ACTION_ALERT; - - return 0; -} - -/** - * \brief Load the action order from config. If none is provided, - * it will be default to ACTION_PASS, ACTION_DROP, - * ACTION_REJECT, ACTION_ALERT (pass has the highest prio) - * - * \retval 0 on success; -1 on fatal error; - */ -int ActionInitConfig(void) -{ - uint8_t actions_used = 0; - uint8_t action_flag = 0; - uint8_t actions_config[4] = {0, 0, 0, 0}; - int order = 0; - - ConfNode *action_order; - ConfNode *action = NULL; - - /* Let's load the order of actions from the general config */ - action_order = ConfGetNode("action-order"); - if (action_order == NULL) { - /* No configuration, use defaults. */ - return 0; - } - else { - TAILQ_FOREACH(action, &action_order->head, next) { - SCLogDebug("Loading action order : %s", action->val); - action_flag = ActionAsciiToFlag(action->val); - if (action_flag == 0) { - SCLogError("action-order, invalid action: \"%s\". Please, use" - " \"pass\",\"drop\",\"alert\",\"reject\". You have" - " to specify all of them, without quotes and without" - " capital letters", - action->val); - goto error; - } - - if (actions_used & action_flag) { - SCLogError("action-order, action already set: \"%s\". Please," - " use \"pass\",\"drop\",\"alert\",\"reject\". You" - " have to specify all of them, without quotes and" - " without capital letters", - action->val); - goto error; - } - - if (order >= 4) { - SCLogError("action-order, you have already specified all the " - "possible actions plus \"%s\". Please, use \"pass\"," - "\"drop\",\"alert\",\"reject\". You have to specify" - " all of them, without quotes and without capital" - " letters", - action->val); - goto error; - } - actions_used |= action_flag; - actions_config[order++] = action_flag; - } - } - if (order < 4) { - SCLogError("action-order, the config didn't specify all of the " - "actions. Please, use \"pass\",\"drop\",\"alert\"," - "\"reject\". You have to specify all of them, without" - " quotes and without capital letters"); - goto error; - } - - /* Now, it's a valid config. Override the default preset */ - for (order = 0; order < 4; order++) { - action_order_sigs[order] = actions_config[order]; - } - - return 0; - - error: - return -1; -} - -#ifdef UNITTESTS - -/** - * \test Check that we invalidate duplicated actions - * (It should default to pass, drop, reject, alert) - */ -static int UtilActionTest01(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -action-order:\n\ - - alert\n\ - - drop\n\ - - reject\n\ - - alert\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ActionInitConfig(); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); - ConfRestoreContextBackup(); - - /* Restore default values */ - action_order_sigs[0] = ACTION_PASS; - action_order_sigs[1] = ACTION_DROP; - action_order_sigs[2] = ACTION_REJECT; - action_order_sigs[3] = ACTION_ALERT; - PASS; -} - -/** - * \test Check that we invalidate with unknown keywords - * (It should default to pass, drop, reject, alert) - */ -static int UtilActionTest02(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -action-order:\n\ - - alert\n\ - - drop\n\ - - reject\n\ - - ftw\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ActionInitConfig(); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); - ConfRestoreContextBackup(); - - /* Restore default values */ - action_order_sigs[0] = ACTION_PASS; - action_order_sigs[1] = ACTION_DROP; - action_order_sigs[2] = ACTION_REJECT; - action_order_sigs[3] = ACTION_ALERT; - PASS; -} - -/** - * \test Check that we invalidate if any action is missing - * (It should default to pass, drop, reject, alert) - */ -static int UtilActionTest03(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -action-order:\n\ - - alert\n\ - - drop\n\ - - reject\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ActionInitConfig(); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); - ConfRestoreContextBackup(); - - /* Restore default values */ - action_order_sigs[0] = ACTION_PASS; - action_order_sigs[1] = ACTION_DROP; - action_order_sigs[2] = ACTION_REJECT; - action_order_sigs[3] = ACTION_ALERT; - PASS; -} - -/** - * \test Check that we invalidate if any action is missing - * (It should default to pass, drop, reject, alert) - */ -static int UtilActionTest04(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -action-order:\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ActionInitConfig(); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); - ConfRestoreContextBackup(); - - /* Restore default values */ - action_order_sigs[0] = ACTION_PASS; - action_order_sigs[1] = ACTION_DROP; - action_order_sigs[2] = ACTION_REJECT; - action_order_sigs[3] = ACTION_ALERT; - PASS; -} - -/** - * \test Check that we invalidate with unknown keywords - * and/or more than the expected - * (It should default to pass, drop, reject, alert) - */ -static int UtilActionTest05(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -action-order:\n\ - - alert\n\ - - drop\n\ - - reject\n\ - - pass\n\ - - whatever\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ActionInitConfig(); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); - ConfRestoreContextBackup(); - - /* Restore default values */ - action_order_sigs[0] = ACTION_PASS; - action_order_sigs[1] = ACTION_DROP; - action_order_sigs[2] = ACTION_REJECT; - action_order_sigs[3] = ACTION_ALERT; - PASS; -} - -/** - * \test Check that we load a valid config - */ -static int UtilActionTest06(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -action-order:\n\ - - alert\n\ - - drop\n\ - - reject\n\ - - pass\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ActionInitConfig(); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_ALERT); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_PASS); - ConfRestoreContextBackup(); - - /* Restore default values */ - action_order_sigs[0] = ACTION_PASS; - action_order_sigs[1] = ACTION_DROP; - action_order_sigs[2] = ACTION_REJECT; - action_order_sigs[3] = ACTION_ALERT; - PASS; -} - -/** - * \test Check that we load a valid config - */ -static int UtilActionTest07(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -action-order:\n\ - - pass\n\ - - alert\n\ - - drop\n\ - - reject\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ActionInitConfig(); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_ALERT); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_REJECT); - ConfRestoreContextBackup(); - - /* Restore default values */ - action_order_sigs[0] = ACTION_PASS; - action_order_sigs[1] = ACTION_DROP; - action_order_sigs[2] = ACTION_REJECT; - action_order_sigs[3] = ACTION_ALERT; - PASS; -} - -/** - * \test Check that the expected defaults are loaded if the - * action-order configuration is not present. - */ -static int UtilActionTest08(void) -{ - char config[] = "%YAML 1.1\n" - "---\n"; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - FAIL_IF_NOT(ActionInitConfig() == 0); - FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); - FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); - FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); - FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); - - ConfRestoreContextBackup(); - PASS; -} - -/* Register unittests */ -void UtilActionRegisterTests(void) -{ - /* Generic tests */ - UtRegisterTest("UtilActionTest01", UtilActionTest01); - UtRegisterTest("UtilActionTest02", UtilActionTest02); - UtRegisterTest("UtilActionTest02", UtilActionTest02); - UtRegisterTest("UtilActionTest03", UtilActionTest03); - UtRegisterTest("UtilActionTest04", UtilActionTest04); - UtRegisterTest("UtilActionTest05", UtilActionTest05); - UtRegisterTest("UtilActionTest06", UtilActionTest06); - UtRegisterTest("UtilActionTest07", UtilActionTest07); - UtRegisterTest("UtilActionTest08", UtilActionTest08); -} -#endif diff --git a/src/util-affinity.c b/src/util-affinity.c deleted file mode 100644 index 06256db5b8cd..000000000000 --- a/src/util-affinity.c +++ /dev/null @@ -1,364 +0,0 @@ -/* Copyright (C) 2010-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Eric Leblond - * - * CPU affinity related code and helper. - */ - -#include "suricata-common.h" -#define _THREAD_AFFINITY -#include "util-affinity.h" -#include "conf.h" -#include "runmodes.h" -#include "util-cpu.h" -#include "util-byte.h" -#include "util-debug.h" - -ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { - { - .name = "receive-cpu-set", - .mode_flag = EXCLUSIVE_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "worker-cpu-set", - .mode_flag = EXCLUSIVE_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "verdict-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "management-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - -}; - -int thread_affinity_init_done = 0; - -/** - * \brief find affinity by its name - * \retval a pointer to the affinity or NULL if not found - */ -ThreadsAffinityType * GetAffinityTypeFromName(const char *name) -{ - int i; - for (i = 0; i < MAX_CPU_SET; i++) { - if (!strcmp(thread_affinity[i].name, name)) { - return &thread_affinity[i]; - } - } - return NULL; -} - -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun -static void AffinitySetupInit(void) -{ - int i, j; - int ncpu = UtilCpuGetNumProcessorsConfigured(); - - SCLogDebug("Initialize affinity setup\n"); - /* be conservative relatively to OS: use all cpus by default */ - for (i = 0; i < MAX_CPU_SET; i++) { - cpu_set_t *cs = &thread_affinity[i].cpu_set; - CPU_ZERO(cs); - for (j = 0; j < ncpu; j++) { - CPU_SET(j, cs); - } - SCMutexInit(&thread_affinity[i].taf_mutex, NULL); - } - return; -} - -void BuildCpusetWithCallback(const char *name, ConfNode *node, - void (*Callback)(int i, void * data), - void *data) -{ - ConfNode *lnode; - TAILQ_FOREACH(lnode, &node->head, next) { - int i; - long int a,b; - int stop = 0; - int max = UtilCpuGetNumProcessorsOnline() - 1; - if (!strcmp(lnode->val, "all")) { - a = 0; - b = max; - stop = 1; - } else if (strchr(lnode->val, '-') != NULL) { - char *sep = strchr(lnode->val, '-'); - char *end; - a = strtoul(lnode->val, &end, 10); - if (end != sep) { - SCLogError("%s: invalid cpu range (start invalid): \"%s\"", name, lnode->val); - exit(EXIT_FAILURE); - } - b = strtol(sep + 1, &end, 10); - if (end != sep + strlen(sep)) { - SCLogError("%s: invalid cpu range (end invalid): \"%s\"", name, lnode->val); - exit(EXIT_FAILURE); - } - if (a > b) { - SCLogError("%s: invalid cpu range (bad order): \"%s\"", name, lnode->val); - exit(EXIT_FAILURE); - } - if (b > max) { - SCLogError("%s: upper bound (%ld) of cpu set is too high, only %d cpu(s)", name, b, - max + 1); - } - } else { - char *end; - a = strtoul(lnode->val, &end, 10); - if (end != lnode->val + strlen(lnode->val)) { - SCLogError("%s: invalid cpu range (not an integer): \"%s\"", name, lnode->val); - exit(EXIT_FAILURE); - } - b = a; - } - for (i = a; i<= b; i++) { - Callback(i, data); - } - if (stop) - break; - } -} - -static void AffinityCallback(int i, void *data) -{ - CPU_SET(i, (cpu_set_t *)data); -} - -static void BuildCpuset(const char *name, ConfNode *node, cpu_set_t *cpu) -{ - BuildCpusetWithCallback(name, node, AffinityCallback, (void *) cpu); -} -#endif /* OS_WIN32 and __OpenBSD__ */ - -/** - * \brief Extract cpu affinity configuration from current config file - */ - -void AffinitySetupLoadFromConfig(void) -{ -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun - ConfNode *root = ConfGetNode("threading.cpu-affinity"); - ConfNode *affinity; - - if (thread_affinity_init_done == 0) { - AffinitySetupInit(); - thread_affinity_init_done = 1; - } - - SCLogDebug("Load affinity from config\n"); - if (root == NULL) { - SCLogInfo("can't get cpu-affinity node"); - return; - } - - TAILQ_FOREACH(affinity, &root->head, next) { - if (strcmp(affinity->val, "decode-cpu-set") == 0 || - strcmp(affinity->val, "stream-cpu-set") == 0 || - strcmp(affinity->val, "reject-cpu-set") == 0 || - strcmp(affinity->val, "output-cpu-set") == 0) { - continue; - } - - const char *setname = affinity->val; - if (strcmp(affinity->val, "detect-cpu-set") == 0) - setname = "worker-cpu-set"; - - ThreadsAffinityType *taf = GetAffinityTypeFromName(setname); - ConfNode *node = NULL; - ConfNode *nprio = NULL; - - if (taf == NULL) { - FatalError("unknown cpu-affinity type"); - } else { - SCLogConfig("Found affinity definition for \"%s\"", setname); - } - - CPU_ZERO(&taf->cpu_set); - node = ConfNodeLookupChild(affinity->head.tqh_first, "cpu"); - if (node == NULL) { - SCLogInfo("unable to find 'cpu'"); - } else { - BuildCpuset(setname, node, &taf->cpu_set); - } - - CPU_ZERO(&taf->lowprio_cpu); - CPU_ZERO(&taf->medprio_cpu); - CPU_ZERO(&taf->hiprio_cpu); - nprio = ConfNodeLookupChild(affinity->head.tqh_first, "prio"); - if (nprio != NULL) { - node = ConfNodeLookupChild(nprio, "low"); - if (node == NULL) { - SCLogDebug("unable to find 'low' prio using default value"); - } else { - BuildCpuset(setname, node, &taf->lowprio_cpu); - } - - node = ConfNodeLookupChild(nprio, "medium"); - if (node == NULL) { - SCLogDebug("unable to find 'medium' prio using default value"); - } else { - BuildCpuset(setname, node, &taf->medprio_cpu); - } - - node = ConfNodeLookupChild(nprio, "high"); - if (node == NULL) { - SCLogDebug("unable to find 'high' prio using default value"); - } else { - BuildCpuset(setname, node, &taf->hiprio_cpu); - } - node = ConfNodeLookupChild(nprio, "default"); - if (node != NULL) { - if (!strcmp(node->val, "low")) { - taf->prio = PRIO_LOW; - } else if (!strcmp(node->val, "medium")) { - taf->prio = PRIO_MEDIUM; - } else if (!strcmp(node->val, "high")) { - taf->prio = PRIO_HIGH; - } else { - FatalError("unknown cpu_affinity prio"); - } - SCLogConfig("Using default prio '%s' for set '%s'", - node->val, setname); - } - } - - node = ConfNodeLookupChild(affinity->head.tqh_first, "mode"); - if (node != NULL) { - if (!strcmp(node->val, "exclusive")) { - taf->mode_flag = EXCLUSIVE_AFFINITY; - } else if (!strcmp(node->val, "balanced")) { - taf->mode_flag = BALANCED_AFFINITY; - } else { - FatalError("unknown cpu_affinity node"); - } - } - - node = ConfNodeLookupChild(affinity->head.tqh_first, "threads"); - if (node != NULL) { - if (StringParseUint32(&taf->nb_threads, 10, 0, (const char *)node->val) < 0) { - FatalError("invalid value for threads " - "count: '%s'", - node->val); - } - if (! taf->nb_threads) { - FatalError("bad value for threads count"); - } - } - } -#endif /* OS_WIN32 and __OpenBSD__ */ -} - -/** - * \brief Return next cpu to use for a given thread family - * \retval the cpu to used given by its id - */ -uint16_t AffinityGetNextCPU(ThreadsAffinityType *taf) -{ - uint16_t ncpu = 0; -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun - int iter = 0; - SCMutexLock(&taf->taf_mutex); - ncpu = taf->lcpu; - while (!CPU_ISSET(ncpu, &taf->cpu_set) && iter < 2) { - ncpu++; - if (ncpu >= UtilCpuGetNumProcessorsOnline()) { - ncpu = 0; - iter++; - } - } - if (iter == 2) { - SCLogError("cpu_set does not contain " - "available cpus, cpu affinity conf is invalid"); - } - taf->lcpu = ncpu + 1; - if (taf->lcpu >= UtilCpuGetNumProcessorsOnline()) - taf->lcpu = 0; - SCMutexUnlock(&taf->taf_mutex); - SCLogDebug("Setting affinity on CPU %d", ncpu); -#endif /* OS_WIN32 and __OpenBSD__ */ - return ncpu; -} - -uint16_t UtilAffinityGetAffinedCPUNum(ThreadsAffinityType *taf) -{ - uint16_t ncpu = 0; -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun - SCMutexLock(&taf->taf_mutex); - for (int i = UtilCpuGetNumProcessorsOnline(); i >= 0; i--) - if (CPU_ISSET(i, &taf->cpu_set)) - ncpu++; - SCMutexUnlock(&taf->taf_mutex); -#endif - return ncpu; -} - -#ifdef HAVE_DPDK -/** - * Find if CPU sets overlap - * \return 1 if CPUs overlap, 0 otherwise - */ -uint16_t UtilAffinityCpusOverlap(ThreadsAffinityType *taf1, ThreadsAffinityType *taf2) -{ - ThreadsAffinityType tmptaf; - CPU_ZERO(&tmptaf); - SCMutexInit(&tmptaf.taf_mutex, NULL); - - cpu_set_t tmpcset; - - SCMutexLock(&taf1->taf_mutex); - SCMutexLock(&taf2->taf_mutex); - CPU_AND(&tmpcset, &taf1->cpu_set, &taf2->cpu_set); - SCMutexUnlock(&taf2->taf_mutex); - SCMutexUnlock(&taf1->taf_mutex); - - for (int i = UtilCpuGetNumProcessorsOnline(); i >= 0; i--) - if (CPU_ISSET(i, &tmpcset)) - return 1; - return 0; -} - -/** - * Function makes sure that CPUs of different types don't overlap by excluding - * one affinity type from the other - * \param mod_taf - CPU set to be modified - * \param static_taf - static CPU set to be used only for evaluation - */ -void UtilAffinityCpusExclude(ThreadsAffinityType *mod_taf, ThreadsAffinityType *static_taf) -{ - cpu_set_t tmpset; - SCMutexLock(&mod_taf->taf_mutex); - SCMutexLock(&static_taf->taf_mutex); - CPU_XOR(&tmpset, &mod_taf->cpu_set, &static_taf->cpu_set); - SCMutexUnlock(&static_taf->taf_mutex); - mod_taf->cpu_set = tmpset; - SCMutexUnlock(&mod_taf->taf_mutex); -} -#endif /* HAVE_DPDK */ diff --git a/src/util-affinity.h b/src/util-affinity.h deleted file mode 100644 index ef3c556498d9..000000000000 --- a/src/util-affinity.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (C) 2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - */ - -#ifndef __UTIL_AFFINITY_H__ -#define __UTIL_AFFINITY_H__ -#include "suricata-common.h" -#include "conf.h" -#include "threads.h" - -#if defined OS_FREEBSD -#include -#include -#include -#include -#include -#define cpu_set_t cpuset_t -#elif defined __OpenBSD__ -#include -#include -#include -#elif defined OS_DARWIN -#include -#include -#include -#define cpu_set_t thread_affinity_policy_data_t -#define CPU_SET(cpu_id, new_mask) (*(new_mask)).affinity_tag = (cpu_id + 1) -#define CPU_ISSET(cpu_id, new_mask) ((*(new_mask)).affinity_tag == (cpu_id + 1)) -#define CPU_ZERO(new_mask) (*(new_mask)).affinity_tag = THREAD_AFFINITY_TAG_NULL -#endif - -enum { - RECEIVE_CPU_SET, - WORKER_CPU_SET, - VERDICT_CPU_SET, - MANAGEMENT_CPU_SET, - MAX_CPU_SET -}; - -enum { - BALANCED_AFFINITY, - EXCLUSIVE_AFFINITY, - MAX_AFFINITY -}; - -typedef struct ThreadsAffinityType_ { - const char *name; - uint8_t mode_flag; - uint16_t lcpu; /* use by exclusive mode */ - int prio; - uint32_t nb_threads; - SCMutex taf_mutex; - -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun - cpu_set_t cpu_set; - cpu_set_t lowprio_cpu; - cpu_set_t medprio_cpu; - cpu_set_t hiprio_cpu; -#endif -} ThreadsAffinityType; - -/** store thread affinity mode for all type of threads */ -#ifndef _THREAD_AFFINITY -extern ThreadsAffinityType thread_affinity[MAX_CPU_SET]; -#endif - -void AffinitySetupLoadFromConfig(void); -ThreadsAffinityType * GetAffinityTypeFromName(const char *name); - -uint16_t AffinityGetNextCPU(ThreadsAffinityType *taf); -uint16_t UtilAffinityGetAffinedCPUNum(ThreadsAffinityType *taf); -#ifdef HAVE_DPDK -uint16_t UtilAffinityCpusOverlap(ThreadsAffinityType *taf1, ThreadsAffinityType *taf2); -void UtilAffinityCpusExclude(ThreadsAffinityType *mod_taf, ThreadsAffinityType *static_taf); -#endif /* HAVE_DPDK */ - -void BuildCpusetWithCallback(const char *name, ConfNode *node, - void (*Callback)(int i, void * data), - void *data); - -#endif /* __UTIL_AFFINITY_H__ */ diff --git a/src/util-atomic.c b/src/util-atomic.c deleted file mode 100644 index 11aa51afd02b..000000000000 --- a/src/util-atomic.c +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-atomic.h" -#include "util-unittest.h" - -#ifdef UNITTESTS - -static int SCAtomicTest01(void) -{ - int result = 0; - int a = 10; - int b = 20; - int *temp_int = NULL; - - SC_ATOMIC_DECLARE(void *, temp); - SC_ATOMIC_INITPTR(temp); - - temp_int = SC_ATOMIC_GET(temp); - if (temp_int != NULL) - goto end; - - (void)SC_ATOMIC_SET(temp, &a); - temp_int = SC_ATOMIC_GET(temp); - if (temp_int == NULL) - goto end; - if (*temp_int != a) - goto end; - - (void)SC_ATOMIC_SET(temp, &b); - temp_int = SC_ATOMIC_GET(temp); - if (temp_int == NULL) - goto end; - if (*temp_int != b) - goto end; - - result = 1; - - end: - return result; -} - -#endif /* UNITTESTS */ - -void SCAtomicRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SCAtomicTest01", SCAtomicTest01); -#endif - - return; -} diff --git a/src/util-atomic.h b/src/util-atomic.h deleted file mode 100644 index 5f2357143010..000000000000 --- a/src/util-atomic.h +++ /dev/null @@ -1,397 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Pablo Rincon - * - * API for atomic operations. Uses C11 atomic instructions - * where available, GCC/clang specific (gnu99) operations otherwise. - * - * To prevent developers from accidentally working with the atomic variables - * directly instead of through the proper macro's, a marco trick is performed - * that exposes different variable names than the developer uses. So if the dev - * uses "somevar", internally "somevar_sc_atomic__" is used. - */ - - -#ifndef __UTIL_ATOMIC_H__ -#define __UTIL_ATOMIC_H__ - -#if HAVE_STDATOMIC_H==1 - -#include - -#define SC_ATOMIC_MEMORY_ORDER_RELAXED memory_order_relaxed -#define SC_ATOMIC_MEMORY_ORDER_CONSUME memory_order_consume -#define SC_ATOMIC_MEMORY_ORDER_ACQUIRE memory_order_acquire -#define SC_ATOMIC_MEMORY_ORDER_RELEASE memory_order_release -#define SC_ATOMIC_MEMORY_ORDER_ACQ_REL memory_order_acq_rel -#define SC_ATOMIC_MEMORY_ORDER_SEQ_CST memory_order_seq_cst - -/** - * \brief wrapper for declaring atomic variables. - * - * \param type Type of the variable (char, short, int, long, long long) - * \param name Name of the variable. - * - * We just declare the variable here as we rely on atomic operations - * to modify it, so no need for locks. - * - * \warning variable is not initialized - */ -#define SC_ATOMIC_DECLARE(type, name) \ - _Atomic(type) name ## _sc_atomic__ - -/** - * \brief wrapper for referencing an atomic variable declared on another file. - * - * \param type Type of the variable (char, short, int, long, long long) - * \param name Name of the variable. - * - * We just declare the variable here as we rely on atomic operations - * to modify it, so no need for locks. - * - */ -#define SC_ATOMIC_EXTERN(type, name) \ - extern _Atomic(type) (name ## _sc_atomic__) - -/** - * \brief wrapper for declaring an atomic variable and initializing it. - **/ -#define SC_ATOMIC_DECL_AND_INIT(type, name) \ - _Atomic(type) (name ## _sc_atomic__) = 0 - -/** - * \brief wrapper for declaring an atomic variable and initializing it - * to a specific value - **/ -#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val) _Atomic(type)(name##_sc_atomic__) = val - -/** - * \brief wrapper for initializing an atomic variable. - **/ -#define SC_ATOMIC_INIT(name) \ - (name ## _sc_atomic__) = 0 -#define SC_ATOMIC_INITPTR(name) \ - (name ## _sc_atomic__) = NULL - -/** - * \brief wrapper for reinitializing an atomic variable. - **/ -#define SC_ATOMIC_RESET(name) \ - SC_ATOMIC_INIT(name) - -/** - * \brief add a value to our atomic variable - * - * \param name the atomic variable - * \param val the value to add to the variable - */ -#define SC_ATOMIC_ADD(name, val) \ - atomic_fetch_add(&(name ## _sc_atomic__), (val)) - -/** - * \brief sub a value from our atomic variable - * - * \param name the atomic variable - * \param val the value to sub from the variable - */ -#define SC_ATOMIC_SUB(name, val) \ - atomic_fetch_sub(&(name ## _sc_atomic__), (val)) - -/** - * \brief Bitwise OR a value to our atomic variable - * - * \param name the atomic variable - * \param val the value to OR to the variable - */ -#define SC_ATOMIC_OR(name, val) \ - atomic_fetch_or(&(name ## _sc_atomic__), (val)) - -/** - * \brief Bitwise AND a value to our atomic variable - * - * \param name the atomic variable - * \param val the value to AND to the variable - */ -#define SC_ATOMIC_AND(name, val) \ - atomic_fetch_and(&(name ## _sc_atomic__), (val)) - -/** - * \brief atomic Compare and Switch - * - * \warning "name" is passed to us as "&var" - */ -#define SC_ATOMIC_CAS(name, cmpval, newval) \ - atomic_compare_exchange_strong((name ## _sc_atomic__), &(cmpval), (newval)) - -/** - * \brief Get the value from the atomic variable. - * - * \retval var value - */ -#define SC_ATOMIC_GET(name) \ - atomic_load(&(name ## _sc_atomic__)) - -#define SC_ATOMIC_LOAD_EXPLICIT(name, order) \ - atomic_load_explicit(&(name ## _sc_atomic__), (order)) - -/** - * \brief Set the value for the atomic variable. - * - * \retval var value - */ -#define SC_ATOMIC_SET(name, val) \ - atomic_store(&(name ## _sc_atomic__), (val)) - -#else - -#define SC_ATOMIC_MEMORY_ORDER_RELAXED -#define SC_ATOMIC_MEMORY_ORDER_CONSUME -#define SC_ATOMIC_MEMORY_ORDER_ACQUIRE -#define SC_ATOMIC_MEMORY_ORDER_RELEASE -#define SC_ATOMIC_MEMORY_ORDER_ACQ_REL -#define SC_ATOMIC_MEMORY_ORDER_SEQ_CST - -/** - * \brief wrapper for OS/compiler specific atomic compare and swap (CAS) - * function. - * - * \param addr Address of the variable to CAS - * \param tv Test value to compare the value at address against - * \param nv New value to set the variable at addr to - * - * \retval 0 CAS failed - * \retval 1 CAS succeeded - */ -#define SCAtomicCompareAndSwap(addr, tv, nv) \ - __sync_bool_compare_and_swap((addr), (tv), (nv)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and add - * function. - * - * \param addr Address of the variable to add to - * \param value Value to add to the variable at addr - */ -#define SCAtomicFetchAndAdd(addr, value) \ - __sync_fetch_and_add((addr), (value)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and sub - * function. - * - * \param addr Address of the variable to add to - * \param value Value to sub from the variable at addr - */ -#define SCAtomicFetchAndSub(addr, value) \ - __sync_fetch_and_sub((addr), (value)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and add - * function. - * - * \param addr Address of the variable to add to - * \param value Value to add to the variable at addr - */ -#define SCAtomicAddAndFetch(addr, value) \ - __sync_add_and_fetch((addr), (value)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and sub - * function. - * - * \param addr Address of the variable to add to - * \param value Value to sub from the variable at addr - */ -#define SCAtomicSubAndFetch(addr, value) \ - __sync_sub_and_fetch((addr), (value)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and "AND" - * function. - * - * \param addr Address of the variable to AND to - * \param value Value to add to the variable at addr - */ -#define SCAtomicFetchAndAnd(addr, value) \ - __sync_fetch_and_and((addr), (value)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and "NAND" - * function. - * - * \param addr Address of the variable to NAND to - * \param value Value to add to the variable at addr - */ -#define SCAtomicFetchAndNand(addr, value) \ - __sync_fetch_and_nand((addr), (value)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and "XOR" - * function. - * - * \param addr Address of the variable to XOR to - * \param value Value to add to the variable at addr - */ -#define SCAtomicFetchAndXor(addr, value) \ - __sync_fetch_and_xor((addr), (value)) - -/** - * \brief wrapper for OS/compiler specific atomic fetch and or - * function. - * - * \param addr Address of the variable to or to - * \param value Value to add to the variable at addr - */ -#define SCAtomicFetchAndOr(addr, value) \ - __sync_fetch_and_or((addr), (value)) - -/** - * \brief wrapper for declaring atomic variables. - * - * \warning Only char, short, int, long, long long and their unsigned - * versions are supported. - * - * \param type Type of the variable (char, short, int, long, long long) - * \param name Name of the variable. - * - * We just declare the variable here as we rely on atomic operations - * to modify it, so no need for locks. - * - * \warning variable is not initialized - */ -#define SC_ATOMIC_DECLARE(type, name) \ - type name ## _sc_atomic__ - -/** - * \brief wrapper for referencing an atomic variable declared on another file. - * - * \warning Only char, short, int, long, long long and their unsigned - * versions are supported. - * - * \param type Type of the variable (char, short, int, long, long long) - * \param name Name of the variable. - * - * We just declare the variable here as we rely on atomic operations - * to modify it, so no need for locks. - * - */ -#define SC_ATOMIC_EXTERN(type, name) \ - extern type name ## _sc_atomic__ - -/** - * \brief wrapper for declaring an atomic variable and initializing it - * to a specific value - **/ -#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val) type name##_sc_atomic__ = val - -/** - * \brief wrapper for declaring an atomic variable and initializing it. - **/ -#define SC_ATOMIC_DECL_AND_INIT(type, name) \ - type name ## _sc_atomic__ = 0 - -/** - * \brief wrapper for initializing an atomic variable. - **/ -#define SC_ATOMIC_INIT(name) \ - (name ## _sc_atomic__) = 0 - -#define SC_ATOMIC_INITPTR(name) \ - (name ## _sc_atomic__) = NULL - -/** - * \brief wrapper for reinitializing an atomic variable. - **/ -#define SC_ATOMIC_RESET(name) \ - (name ## _sc_atomic__) = 0 - -/** - * \brief add a value to our atomic variable - * - * \param name the atomic variable - * \param val the value to add to the variable - */ -#define SC_ATOMIC_ADD(name, val) \ - SCAtomicFetchAndAdd(&(name ## _sc_atomic__), (val)) - -/** - * \brief sub a value from our atomic variable - * - * \param name the atomic variable - * \param val the value to sub from the variable - */ -#define SC_ATOMIC_SUB(name, val) \ - SCAtomicFetchAndSub(&(name ## _sc_atomic__), (val)) - -/** - * \brief Bitwise OR a value to our atomic variable - * - * \param name the atomic variable - * \param val the value to OR to the variable - */ -#define SC_ATOMIC_OR(name, val) \ - SCAtomicFetchAndOr(&(name ## _sc_atomic__), (val)) - -/** - * \brief Bitwise AND a value to our atomic variable - * - * \param name the atomic variable - * \param val the value to AND to the variable - */ -#define SC_ATOMIC_AND(name, val) \ - SCAtomicFetchAndAnd(&(name ## _sc_atomic__), (val)) - -/** - * \brief atomic Compare and Switch - * - * \warning "name" is passed to us as "&var" - */ -#define SC_ATOMIC_CAS(name, cmpval, newval) \ - SCAtomicCompareAndSwap((name ## _sc_atomic__), cmpval, newval) - -/** - * \brief Get the value from the atomic variable. - * - * \retval var value - */ -#define SC_ATOMIC_GET(name) \ - (name ## _sc_atomic__) - -#define SC_ATOMIC_LOAD_EXPLICIT(name, order) \ - (name ## _sc_atomic__) - -/** - * \brief Set the value for the atomic variable. - * - * \retval var value - */ -#define SC_ATOMIC_SET(name, val) ({ \ - while (SC_ATOMIC_CAS(&name, SC_ATOMIC_GET(name), val) == 0) \ - ; \ - }) - -#endif /* no c11 atomics */ - -void SCAtomicRegisterTests(void); - -#endif /* __UTIL_ATOMIC_H__ */ - diff --git a/src/util-base64.c b/src/util-base64.c deleted file mode 100644 index 4a4a5d122c41..000000000000 --- a/src/util-base64.c +++ /dev/null @@ -1,411 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author David Abarbanel - * - */ - -#include "util-base64.h" -#include "util-debug.h" -#include "util-unittest.h" -/* Constants */ -#define BASE64_TABLE_MAX 122 - -/* Base64 character to index conversion table */ -/* Characters are mapped as "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */ -static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51 }; - -/** - * \brief Gets a base64-decoded value from an encoded character - * - * \param c The encoded character - * - * \return The decoded value (0 or above), or -1 if the parameter is invalid - */ -static inline int GetBase64Value(uint8_t c) -{ - int val = -1; - - /* Pull from conversion table */ - if (c <= BASE64_TABLE_MAX) { - val = b64table[(int) c]; - } - - return val; -} - -/** - * \brief Checks if the given char in a byte array is Base64 alphabet - * - * \param Char that needs to be checked - * - * \return True if the char was Base64 alphabet, False otherwise - */ -bool IsBase64Alphabet(uint8_t encoded_byte) -{ - if (GetBase64Value(encoded_byte) < 0 && encoded_byte != '=') { - return false; - } - return true; -} - -/** - * \brief Decodes a 4-byte base64-encoded block into a 3-byte ascii-encoded block - * - * \param ascii the 3-byte ascii output block - * \param b64 the 4-byte base64 input block - * - * \return none - */ -static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) -{ - ascii[0] = (uint8_t) (b64[0] << 2) | (b64[1] >> 4); - ascii[1] = (uint8_t) (b64[1] << 4) | (b64[2] >> 2); - ascii[2] = (uint8_t) (b64[2] << 6) | (b64[3]); -} - -/** - * \brief Decodes a base64-encoded string buffer into an ascii-encoded byte buffer - * - * \param dest The destination byte buffer - * \param dest_size The destination byte buffer size - * \param src The source string - * \param len The length of the source string - * \param consumed_bytes The bytes that were actually processed/consumed - * \param decoded_bytes The bytes that were decoded - * \param mode The mode in which decoding should happen - * - * \return Error code indicating success or failures with parsing - */ -Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len, - uint32_t *consumed_bytes, uint32_t *decoded_bytes, Base64Mode mode) -{ - int val; - uint32_t padding = 0, bbidx = 0, sp = 0, leading_sp = 0; - uint8_t *dptr = dest; - uint8_t b64[B64_BLOCK] = { 0,0,0,0 }; - bool valid = true; - Base64Ecode ecode = BASE64_ECODE_OK; - *decoded_bytes = 0; - - /* Traverse through each alpha-numeric letter in the source array */ - for (uint32_t i = 0; i < len; i++) { - /* Get decimal representation */ - val = GetBase64Value(src[i]); - if (val < 0) { - if (mode == BASE64_MODE_RFC2045 && src[i] != '=') { - if (bbidx == 0) { - /* Special case where last block of data has a leading space or invalid char */ - leading_sp++; - } - sp++; - continue; - } - /* Invalid character found, so decoding fails */ - if (src[i] != '=') { - valid = false; - ecode = BASE64_ECODE_ERR; - if (mode == BASE64_MODE_STRICT) { - *decoded_bytes = 0; - } - break; - } - padding++; - } - - /* For each alpha-numeric letter in the source array, find the numeric - * value */ - b64[bbidx++] = (val > 0 ? (uint8_t)val : 0); - - /* Decode every 4 base64 bytes into 3 ascii bytes */ - if (bbidx == B64_BLOCK) { - - /* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */ - uint32_t numDecoded_blk = ASCII_BLOCK - (padding < B64_BLOCK ? padding : ASCII_BLOCK); - if (dest_size < *decoded_bytes + numDecoded_blk) { - SCLogDebug("Destination buffer full"); - ecode = BASE64_ECODE_BUF; - break; - } - - /* Decode base-64 block into ascii block and move pointer */ - DecodeBase64Block(dptr, b64); - dptr += numDecoded_blk; - *decoded_bytes += numDecoded_blk; - /* Reset base-64 block and index */ - bbidx = 0; - padding = 0; - *consumed_bytes += B64_BLOCK + sp; - sp = 0; - leading_sp = 0; - memset(&b64, 0, sizeof(b64)); - } - } - - if (bbidx > 0 && bbidx < 4 && ((!valid && mode == BASE64_MODE_RFC4648))) { - /* Decoded bytes for 1 or 2 base64 encoded bytes is 1 */ - padding = bbidx > 1 ? B64_BLOCK - bbidx : 2; - uint32_t numDecoded_blk = ASCII_BLOCK - (padding < B64_BLOCK ? padding : ASCII_BLOCK); - if (dest_size < *decoded_bytes + numDecoded_blk) { - SCLogDebug("Destination buffer full"); - ecode = BASE64_ECODE_BUF; - return ecode; - } - /* if the destination size is not at least 3 Bytes long, it'll give a dynamic - * buffer overflow while decoding, so, return and let the caller take care of the - * remaining bytes to be decoded which should always be < 4 at this stage */ - if (dest_size - *decoded_bytes < 3) - return BASE64_ECODE_BUF; - *decoded_bytes += numDecoded_blk; - DecodeBase64Block(dptr, b64); - *consumed_bytes += bbidx; - } - - /* Finish remaining b64 bytes by padding */ - if (valid && bbidx > 0 && (mode != BASE64_MODE_RFC2045)) { - /* Decode remaining */ - *decoded_bytes += ASCII_BLOCK - (B64_BLOCK - bbidx); - DecodeBase64Block(dptr, b64); - } - - if (*decoded_bytes == 0) { - SCLogDebug("base64 decoding failed"); - } - - *consumed_bytes += leading_sp; - return ecode; -} - -#ifdef UNITTESTS - -#define TEST_RFC2045(src, fin_str, dest_size, exp_decoded, exp_consumed, ecode) \ - { \ - uint32_t consumed_bytes = 0, num_decoded = 0; \ - uint8_t dst[dest_size]; \ - Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \ - &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045); \ - FAIL_IF(code != ecode); \ - FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \ - FAIL_IF(num_decoded != exp_decoded); \ - FAIL_IF(consumed_bytes != exp_consumed); \ - } - -#define TEST_RFC4648(src, fin_str, dest_size, exp_decoded, exp_consumed, ecode) \ - { \ - uint32_t consumed_bytes = 0, num_decoded = 0; \ - uint8_t dst[dest_size]; \ - Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \ - &consumed_bytes, &num_decoded, BASE64_MODE_RFC4648); \ - FAIL_IF(code != ecode); \ - FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \ - FAIL_IF(num_decoded != exp_decoded); \ - FAIL_IF(consumed_bytes != exp_consumed); \ - } - -static int B64DecodeCompleteString(void) -{ - /* - * SGVsbG8gV29ybGR6 : Hello Worldz - * */ - const char *src = "SGVsbG8gV29ybGR6"; - const char *fin_str = "Hello Worldz"; - TEST_RFC2045(src, fin_str, strlen(fin_str), strlen(fin_str), strlen(src), BASE64_ECODE_OK); - PASS; -} - -static int B64DecodeInCompleteString(void) -{ - /* - * SGVsbG8gV29ybGR6 : Hello Worldz - * */ - const char *src = "SGVsbG8gV29ybGR"; - const char *fin_str = "Hello Wor"; - TEST_RFC2045(src, fin_str, strlen(fin_str), strlen(fin_str), strlen(src) - 3, BASE64_ECODE_OK); - PASS; -} - -static int B64DecodeCompleteStringWSp(void) -{ - /* - * SGVsbG8gV29ybGQ= : Hello World - * */ - - const char *src = "SGVs bG8 gV29y bGQ="; - const char *fin_str = "Hello World"; - TEST_RFC2045(src, fin_str, strlen(fin_str) + 3, strlen(fin_str), strlen(src), BASE64_ECODE_OK); - PASS; -} - -static int B64DecodeInCompleteStringWSp(void) -{ - /* - * SGVsbG8gV29ybGQ= : Hello World - * Special handling for this case (sp in remainder) done in ProcessBase64Remainder - * */ - - const char *src = "SGVs bG8 gV29y bGQ"; - const char *fin_str = "Hello Wor"; - TEST_RFC2045(src, fin_str, strlen(fin_str) + 1 /* 12 B in dest_size */, strlen(fin_str), - strlen(src) - 3, BASE64_ECODE_OK); - PASS; -} - -static int B64DecodeStringBiggerThanBuffer(void) -{ - /* - * SGVsbG8gV29ybGQ= : Hello World - * */ - - const char *src = "SGVs bG8 gV29y bGQ="; - const char *fin_str = "Hello Wor"; - TEST_RFC2045( - src, fin_str, strlen(fin_str) + 1, strlen(fin_str), strlen(src) - 4, BASE64_ECODE_BUF); - PASS; -} - -static int B64DecodeStringEndingSpaces(void) -{ - const char *src = "0YPhA d H"; - uint32_t consumed_bytes = 0, num_decoded = 0; - uint8_t dst[10]; - Base64Ecode code = DecodeBase64(dst, sizeof(dst), (const uint8_t *)src, strlen(src), - &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045); - FAIL_IF(code != BASE64_ECODE_OK); - FAIL_IF(num_decoded != 3); - FAIL_IF(consumed_bytes != 4); - PASS; -} - -static int B64TestVectorsRFC2045(void) -{ - const char *src1 = ""; - const char *fin_str1 = ""; - - const char *src2 = "Zg=="; - const char *fin_str2 = "f"; - - const char *src3 = "Zm8="; - const char *fin_str3 = "fo"; - - const char *src4 = "Zm9v"; - const char *fin_str4 = "foo"; - - const char *src5 = "Zm9vYg=="; - const char *fin_str5 = "foob"; - - const char *src6 = "Zm9vYmE="; - const char *fin_str6 = "fooba"; - - const char *src7 = "Zm9vYmFy"; - const char *fin_str7 = "foobar"; - - const char *src8 = "Zm 9v Ym Fy"; - const char *fin_str8 = "foobar"; - - const char *src9 = "Zm$9vYm.Fy"; - const char *fin_str9 = "foobar"; - - const char *src10 = "Y21Wd2IzSjBaVzFoYVd4bWNtRjFaRUJoZEc4dVoyOTJMbUYxOmpqcHh4b3Rhb2w%5"; - const char *fin_str10 = "cmVwb3J0ZW1haWxmcmF1ZEBhdG8uZ292LmF1:jjpxxotaol9"; - - TEST_RFC2045(src1, fin_str1, ASCII_BLOCK * 2, strlen(fin_str1), strlen(src1), BASE64_ECODE_OK); - TEST_RFC2045(src2, fin_str2, ASCII_BLOCK * 2, strlen(fin_str2), strlen(src2), BASE64_ECODE_OK); - TEST_RFC2045(src3, fin_str3, ASCII_BLOCK * 2, strlen(fin_str3), strlen(src3), BASE64_ECODE_OK); - TEST_RFC2045(src4, fin_str4, ASCII_BLOCK * 2, strlen(fin_str4), strlen(src4), BASE64_ECODE_OK); - TEST_RFC2045(src5, fin_str5, ASCII_BLOCK * 2, strlen(fin_str5), strlen(src5), BASE64_ECODE_OK); - TEST_RFC2045(src6, fin_str6, ASCII_BLOCK * 2, strlen(fin_str6), strlen(src6), BASE64_ECODE_OK); - TEST_RFC2045(src7, fin_str7, ASCII_BLOCK * 2, strlen(fin_str7), strlen(src7), BASE64_ECODE_OK); - TEST_RFC2045(src8, fin_str8, ASCII_BLOCK * 2, strlen(fin_str8), strlen(src8), BASE64_ECODE_OK); - TEST_RFC2045(src9, fin_str9, ASCII_BLOCK * 2, strlen(fin_str9), strlen(src9), BASE64_ECODE_OK); - TEST_RFC2045(src10, fin_str10, strlen(fin_str10) + 2, strlen(fin_str10), strlen(src10), - BASE64_ECODE_OK); - PASS; -} - -static int B64TestVectorsRFC4648(void) -{ - const char *src1 = ""; - const char *fin_str1 = ""; - - const char *src2 = "Zg=="; - const char *fin_str2 = "f"; - - const char *src3 = "Zm8="; - const char *fin_str3 = "fo"; - - const char *src4 = "Zm9v"; - const char *fin_str4 = "foo"; - - const char *src5 = "Zm9vYg=="; - const char *fin_str5 = "foob"; - - const char *src6 = "Zm9vYmE="; - const char *fin_str6 = "fooba"; - - const char *src7 = "Zm9vYmFy"; - const char *fin_str7 = "foobar"; - - const char *src8 = "Zm 9v Ym Fy"; - const char *fin_str8 = "f"; - - const char *src9 = "Zm$9vYm.Fy"; - const char *fin_str9 = "f"; - - const char *src10 = "Y21Wd2IzSjBaVzFoYVd4bWNtRjFaRUJoZEc4dVoyOTJMbUYxOmpqcHh4b3Rhb2w%3D"; - const char *fin_str10 = "cmVwb3J0ZW1haWxmcmF1ZEBhdG8uZ292LmF1:jjpxxotaol"; - - TEST_RFC4648(src1, fin_str1, ASCII_BLOCK * 2, strlen(fin_str1), strlen(src1), BASE64_ECODE_OK); - TEST_RFC4648(src2, fin_str2, ASCII_BLOCK * 2, strlen(fin_str2), strlen(src2), BASE64_ECODE_OK); - TEST_RFC4648(src3, fin_str3, ASCII_BLOCK * 2, strlen(fin_str3), strlen(src3), BASE64_ECODE_OK); - TEST_RFC4648(src4, fin_str4, ASCII_BLOCK * 2, strlen(fin_str4), strlen(src4), BASE64_ECODE_OK); - TEST_RFC4648(src5, fin_str5, ASCII_BLOCK * 2, strlen(fin_str5), strlen(src5), BASE64_ECODE_OK); - TEST_RFC4648(src6, fin_str6, ASCII_BLOCK * 2, strlen(fin_str6), strlen(src6), BASE64_ECODE_OK); - TEST_RFC4648(src7, fin_str7, ASCII_BLOCK * 2, strlen(fin_str7), strlen(src7), BASE64_ECODE_OK); - TEST_RFC4648(src8, fin_str8, ASCII_BLOCK * 2, 1 /* f */, 2 /* Zm */, BASE64_ECODE_ERR); - TEST_RFC4648(src9, fin_str9, ASCII_BLOCK * 2, 1 /* f */, 2 /* Zm */, BASE64_ECODE_ERR); - TEST_RFC4648(src10, fin_str10, strlen(fin_str10) + 1, strlen(fin_str10), strlen(src10) - 3, - BASE64_ECODE_ERR); - PASS; -} - -void Base64RegisterTests(void) -{ - UtRegisterTest("B64DecodeCompleteStringWSp", B64DecodeCompleteStringWSp); - UtRegisterTest("B64DecodeInCompleteStringWSp", B64DecodeInCompleteStringWSp); - UtRegisterTest("B64DecodeCompleteString", B64DecodeCompleteString); - UtRegisterTest("B64DecodeInCompleteString", B64DecodeInCompleteString); - UtRegisterTest("B64DecodeStringBiggerThanBuffer", B64DecodeStringBiggerThanBuffer); - UtRegisterTest("B64DecodeStringEndingSpaces", B64DecodeStringEndingSpaces); - UtRegisterTest("B64TestVectorsRFC2045", B64TestVectorsRFC2045); - UtRegisterTest("B64TestVectorsRFC4648", B64TestVectorsRFC4648); -} -#endif diff --git a/src/util-base64.h b/src/util-base64.h deleted file mode 100644 index 53cc14c9c4e0..000000000000 --- a/src/util-base64.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author David Abarbanel - * - */ - -#ifndef __UTIL_BASE64_H_ -#define __UTIL_BASE64_H_ - -#include "suricata-common.h" - -/* Constants */ -#define ASCII_BLOCK 3 -#define B64_BLOCK 4 - -typedef enum { - BASE64_MODE_RELAX, - /* If the following strings were to be passed to the decoder with RFC2045 mode, - * the results would be as follows. See the unittest B64TestVectorsRFC2045 in - * src/util-base64.c - * - * BASE64("") = "" - * BASE64("f") = "Zg==" - * BASE64("fo") = "Zm8=" - * BASE64("foo") = "Zm9v" - * BASE64("foob") = "Zm9vYg==" - * BASE64("fooba") = "Zm9vYmE=" - * BASE64("foobar") = "Zm9vYmFy" - * BASE64("foobar") = "Zm 9v Ym Fy" <-- Notice how the spaces are ignored - * BASE64("foobar") = "Zm$9vYm.Fy" # According to RFC 2045, All line breaks or *other - * characters* not found in base64 alphabet must be ignored by decoding software - * */ - BASE64_MODE_RFC2045, /* SPs are allowed during transfer but must be skipped by Decoder */ - BASE64_MODE_STRICT, - /* If the following strings were to be passed to the decoder with RFC4648 mode, - * the results would be as follows. See the unittest B64TestVectorsRFC4648 in - * src/util-base64.c - * - * BASE64("") = "" - * BASE64("f") = "Zg==" - * BASE64("fo") = "Zm8=" - * BASE64("foo") = "Zm9v" - * BASE64("foob") = "Zm9vYg==" - * BASE64("fooba") = "Zm9vYmE=" - * BASE64("foobar") = "Zm9vYmFy" - * BASE64("f") = "Zm 9v Ym Fy" <-- Notice how the processing stops once space is encountered - * BASE64("f") = "Zm$9vYm.Fy" <-- Notice how the processing stops once an invalid char is - * encountered - * */ - BASE64_MODE_RFC4648, /* reject the encoded data if it contains characters outside the base - alphabet */ -} Base64Mode; - -typedef enum { - BASE64_ECODE_ERR = -1, - BASE64_ECODE_OK = 0, - BASE64_ECODE_BUF, -} Base64Ecode; - -/* Function prototypes */ -Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len, - uint32_t *consumed_bytes, uint32_t *decoded_bytes, Base64Mode mode); -bool IsBase64Alphabet(uint8_t encoded_byte); - -#endif - -#ifdef UNITTESTS -void Base64RegisterTests(void); -#endif diff --git a/src/util-bloomfilter-counting.c b/src/util-bloomfilter-counting.c deleted file mode 100644 index 620b507dfa99..000000000000 --- a/src/util-bloomfilter-counting.c +++ /dev/null @@ -1,418 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Counting Bloom Filter implementation. Can be used with 8, 16, 32 bits - * counters. - */ - -#include "suricata-common.h" -#include "util-bloomfilter-counting.h" -#include "util-unittest.h" - -/* type: 1, 2 or 4 for 8, 16, or 32 bit counters - * - */ -BloomFilterCounting *BloomFilterCountingInit(uint32_t size, uint8_t type, uint8_t iter, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)) { - BloomFilterCounting *bf = NULL; - - if (iter == 0) - goto error; - - if (Hash == NULL || size == 0) { - //printf("ERROR: BloomFilterCountingInit no Hash function\n"); - goto error; - } - - if (type != 1 && type != 2 && type != 4) { - //printf("ERROR: BloomFilterCountingInit only 1, 2 and 4 bytes are supported\n"); - goto error; - } - - /* setup the filter */ - bf = SCCalloc(1, sizeof(BloomFilterCounting)); - if (unlikely(bf == NULL)) - goto error; - bf->type = type; /* size of the type: 1, 2, 4 */ - bf->array_size = size; - bf->hash_iterations = iter; - bf->Hash = Hash; - - /* setup the bitarray */ - bf->array = SCCalloc(bf->array_size, bf->type); - if (bf->array == NULL) - goto error; - - return bf; - -error: - if (bf != NULL) { - if (bf->array != NULL) - SCFree(bf->array); - - SCFree(bf); - } - return NULL; -} - -void BloomFilterCountingFree(BloomFilterCounting *bf) -{ - if (bf != NULL) { - if (bf->array != NULL) - SCFree(bf->array); - - SCFree(bf); - } -} - -void BloomFilterCountingPrint(BloomFilterCounting *bf) -{ - printf("\n------ Counting Bloom Filter Stats ------\n"); - printf("Buckets: %" PRIu32 "\n", bf->array_size); - printf("Counter size: %" PRIu32 "\n", bf->type); - printf("Memory size: %" PRIu32 " bytes\n", bf->array_size * bf->type); - printf("Hash function pointer: %p\n", bf->Hash); - printf("Hash functions: %" PRIu32 "\n", bf->hash_iterations); - printf("-----------------------------------------\n"); -} - -int BloomFilterCountingAdd(BloomFilterCounting *bf, const void *data, uint16_t datalen) -{ - uint8_t iter = 0; - uint32_t hash = 0; - - if (bf == NULL || data == NULL || datalen == 0) - return -1; - - for (iter = 0; iter < bf->hash_iterations; iter++) { - hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; - if (bf->type == 1) { - uint8_t *u8 = (uint8_t *)&bf->array[hash]; - if ((*u8) != 255) - (*u8)++; - } else if (bf->type == 2) { - uint16_t *u16 = (uint16_t *)&bf->array[hash]; - if ((*u16) != 65535) - (*u16)++; - } else if (bf->type == 4) { - uint32_t *u32 = (uint32_t *)&bf->array[hash]; - if ((*u32) != 4294967295UL) - (*u32)++; - } - } - - return 0; -} - -int BloomFilterCountingRemove(BloomFilterCounting *bf, const void *data, uint16_t datalen) -{ - uint8_t iter = 0; - uint32_t hash = 0; - - if (bf == NULL || data == NULL || datalen == 0) - return -1; - - /* only remove data that was actually added */ - if (BloomFilterCountingTest(bf, data, datalen) == 0) { - printf("ERROR: BloomFilterCountingRemove tried to remove data " - "that was never added to the set or was already removed.\n"); - return -1; - } - - /* decrease counters for every iteration */ - for (iter = 0; iter < bf->hash_iterations; iter++) { - hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; - if (bf->type == 1) { - uint8_t *u8 = (uint8_t *)&bf->array[hash]; - if ((*u8) > 0) - (*u8)--; - else { - printf("ERROR: BloomFilterCountingRemove tried to decrease a " - "counter below zero.\n"); - return -1; - } - } else if (bf->type == 2) { - uint16_t *u16 = (uint16_t *)&bf->array[hash]; - if ((*u16) > 0) - (*u16)--; - else { - printf("ERROR: BloomFilterCountingRemove tried to decrease a " - "counter below zero.\n"); - return -1; - } - } else if (bf->type == 4) { - uint32_t *u32 = (uint32_t *)&bf->array[hash]; - if ((*u32) > 0) - (*u32)--; - else { - printf("ERROR: BloomFilterCountingRemove tried to decrease a " - "counter below zero.\n"); - return -1; - } - } - } - - return 0; -} - -/* Test if data matches our filter and is likely to be in the set - * - * returns 0: for no match - * 1: match - */ -int BloomFilterCountingTest(BloomFilterCounting *bf, const void *data, uint16_t datalen) -{ - uint8_t iter = 0; - uint32_t hash = 0; - int hit = 1; - - /* check each hash iteration */ - for (iter = 0; iter < bf->hash_iterations; iter++) { - hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; - if (bf->type == 1) { - uint8_t *u8 = (uint8_t *)&bf->array[hash]; - if ((*u8) == 0x00) { - hit = 0; - break; - } - } else if (bf->type == 2) { - uint16_t *u16 = (uint16_t *)&bf->array[hash]; - if ((*u16) == 0x0000) { - hit = 0; - break; - } - } else if (bf->type == 4) { - uint32_t *u32 = (uint32_t *)&bf->array[hash]; - if ((*u32) == 0x00000000) { - hit = 0; - break; - } - } - } - - return hit; -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -static uint32_t BloomHash(const void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint32_t i; - uint32_t hash = 0; - - for (i = 0; i < datalen; i++) { - if (i == 0) hash += (((uint32_t)*d++)); - else if (i == 1) hash += (((uint32_t)*d++) * datalen); - else hash *= (((uint32_t)*d++) * i); - } - - hash *= (iter + datalen); - hash %= hash_size; - return hash; -} - -static int BloomFilterCountingTestInit01 (void) -{ - BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); - if (bf == NULL) - return 0; - - BloomFilterCountingFree(bf); - return 1; -} - -/* no hash function, so it should fail */ -static int BloomFilterCountingTestInit02 (void) -{ - BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, NULL); - if (bf == NULL) - return 1; - - BloomFilterCountingFree(bf); - return 0; -} - -static int BloomFilterCountingTestInit03 (void) -{ - int result = 0; - BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); - if (bf == NULL) - return 0; - - if (bf->Hash == BloomHash) - result = 1; - - BloomFilterCountingFree(bf); - return result; -} - -static int BloomFilterCountingTestInit04 (void) -{ - BloomFilterCounting *bf = BloomFilterCountingInit(1024, 0, 4, BloomHash); - if (bf == NULL) - return 1; - - BloomFilterCountingFree(bf); - return 0; -} - -static int BloomFilterCountingTestInit05 (void) -{ - BloomFilterCounting *bf = BloomFilterCountingInit(0, 4, 4, BloomHash); - if (bf == NULL) - return 1; - - BloomFilterCountingFree(bf); - return 0; -} - -static int BloomFilterCountingTestInit06 (void) -{ - BloomFilterCounting *bf = BloomFilterCountingInit(32, 3, 4, BloomHash); - if (bf == NULL) - return 1; - - BloomFilterCountingFree(bf); - return 0; -} - -static int BloomFilterCountingTestAdd01 (void) -{ - int result = 0; - BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); - if (bf == NULL) - return 0; - - int r = BloomFilterCountingAdd(bf, "test", 0); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (bf != NULL) BloomFilterCountingFree(bf); - return result; -} - -static int BloomFilterCountingTestAdd02 (void) -{ - int result = 0; - BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); - if (bf == NULL) - return 0; - - int r = BloomFilterCountingAdd(bf, NULL, 4); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (bf != NULL) BloomFilterCountingFree(bf); - return result; -} - -static int BloomFilterCountingTestFull01 (void) -{ - int result = 0; - BloomFilterCounting *bf = BloomFilterCountingInit(32, 4, 4, BloomHash); - if (bf == NULL) { - printf("init failed: "); - goto end; - } - - int r = BloomFilterCountingAdd(bf, "test", 4); - if (r != 0) { - printf("first add: "); - goto end; - } - - r = BloomFilterCountingTest(bf, "test", 4); - if (r != 1) { - printf("2nd add: "); - goto end; - } - - r = BloomFilterCountingRemove(bf, "test", 4); - if (r != 0) { - printf("3rd add: "); - goto end; - } - - /* all is good! */ - result = 1; -end: - if (bf != NULL) - BloomFilterCountingFree(bf); - return result; -} - -static int BloomFilterCountingTestFull02 (void) -{ - int result = 0; - BloomFilterCounting *bf = BloomFilterCountingInit(32, 4, 4, BloomHash); - if (bf == NULL) - goto end; - - int r = BloomFilterCountingTest(bf, "test", 4); - if (r != 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (bf != NULL) BloomFilterCountingFree(bf); - return result; -} -#endif - -void BloomFilterCountingRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("BloomFilterCountingTestInit01", - BloomFilterCountingTestInit01); - UtRegisterTest("BloomFilterCountingTestInit02", - BloomFilterCountingTestInit02); - UtRegisterTest("BloomFilterCountingTestInit03", - BloomFilterCountingTestInit03); - UtRegisterTest("BloomFilterCountingTestInit04", - BloomFilterCountingTestInit04); - UtRegisterTest("BloomFilterCountingTestInit05", - BloomFilterCountingTestInit05); - UtRegisterTest("BloomFilterCountingTestInit06", - BloomFilterCountingTestInit06); - - UtRegisterTest("BloomFilterCountingTestAdd01", - BloomFilterCountingTestAdd01); - UtRegisterTest("BloomFilterCountingTestAdd02", - BloomFilterCountingTestAdd02); - - UtRegisterTest("BloomFilterCountingTestFull01", - BloomFilterCountingTestFull01); - UtRegisterTest("BloomFilterCountingTestFull02", - BloomFilterCountingTestFull02); -#endif -} - diff --git a/src/util-bloomfilter-counting.h b/src/util-bloomfilter-counting.h deleted file mode 100644 index bdb0cfa09c95..000000000000 --- a/src/util-bloomfilter-counting.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __BLOOMFILTERCOUNTING_H__ -#define __BLOOMFILTERCOUNTING_H__ - -/* Bloom filter structure */ -typedef struct BloomFilterCounting_ { - uint8_t *array; - uint32_t array_size; /* size in buckets */ - uint8_t type; /* 1, 2 or 4 byte counters */ - uint8_t hash_iterations; - uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t); -} BloomFilterCounting; - -/* prototypes */ -BloomFilterCounting *BloomFilterCountingInit(uint32_t, uint8_t, uint8_t, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)); -void BloomFilterCountingFree(BloomFilterCounting *); -void BloomFilterCountingPrint(BloomFilterCounting *); -int BloomFilterCountingAdd(BloomFilterCounting *, const void *, uint16_t); -int BloomFilterCountingRemove(BloomFilterCounting *, const void *, uint16_t); -int BloomFilterCountingTest(BloomFilterCounting *, const void *, uint16_t); - -void BloomFilterCountingRegisterTests(void); - -#endif /* __BLOOMFILTERCOUNTING_H__ */ - diff --git a/src/util-bloomfilter.c b/src/util-bloomfilter.c deleted file mode 100644 index 5d2549c6a9a4..000000000000 --- a/src/util-bloomfilter.c +++ /dev/null @@ -1,289 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Bitwise bloom filter implementation - */ - -#include "suricata-common.h" -#include "util-bloomfilter.h" -#include "util-unittest.h" - -BloomFilter *BloomFilterInit(uint32_t size, uint8_t iter, - uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)) { - BloomFilter *bf = NULL; - - if (size == 0 || iter == 0) - goto error; - - if (Hash == NULL) { - //printf("ERROR: BloomFilterInit no Hash function\n"); - goto error; - } - - /* setup the filter */ - bf = SCCalloc(1, sizeof(BloomFilter)); - if (unlikely(bf == NULL)) - goto error; - bf->bitarray_size = size; - bf->hash_iterations = iter; - bf->Hash = Hash; - - /* setup the bitarray */ - bf->bitarray = SCCalloc(1, (bf->bitarray_size / 8) + 1); - if (bf->bitarray == NULL) - goto error; - - return bf; - -error: - if (bf != NULL) { - if (bf->bitarray != NULL) - SCFree(bf->bitarray); - - SCFree(bf); - } - return NULL; -} - -void BloomFilterFree(BloomFilter *bf) -{ - if (bf != NULL) { - if (bf->bitarray != NULL) - SCFree(bf->bitarray); - - SCFree(bf); - } -} - -void BloomFilterPrint(BloomFilter *bf) -{ - printf("\n---------- Bloom Filter Stats -----------\n"); - printf("Buckets: %" PRIu32 "\n", bf->bitarray_size); - printf("Memory size: %" PRIu32 " bytes\n", bf->bitarray_size/8 + 1); - printf("Hash function pointer: %p\n", bf->Hash); - printf("Hash functions: %" PRIu32 "\n", bf->hash_iterations); - printf("-----------------------------------------\n"); -} - -int BloomFilterAdd(BloomFilter *bf, const void *data, uint16_t datalen) -{ - uint8_t iter = 0; - uint32_t hash = 0; - - if (bf == NULL || data == NULL || datalen == 0) - return -1; - - for (iter = 0; iter < bf->hash_iterations; iter++) { - hash = bf->Hash(data, datalen, iter, bf->bitarray_size); - bf->bitarray[hash/8] |= (1<bitarray_size/8) + 1); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -static uint32_t BloomFilterTestHash(const void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint32_t i; - uint32_t hash = 0; - - for (i = 0; i < datalen; i++) { - if (i == 0) hash += (((uint32_t)*d++)); - else if (i == 1) hash += (((uint32_t)*d++) * datalen); - else hash *= (((uint32_t)*d++) * i); - } - - hash *= (iter + datalen); - hash %= hash_size; - return hash; -} - -static int BloomFilterTestInit01 (void) -{ - BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); - if (bf == NULL) - return 0; - - BloomFilterFree(bf); - return 1; -} - -/* no hash function, so it should fail */ -static int BloomFilterTestInit02 (void) -{ - BloomFilter *bf = BloomFilterInit(1024, 4, NULL); - if (bf == NULL) - return 1; - - BloomFilterFree(bf); - return 0; -} - -static int BloomFilterTestInit03 (void) -{ - int result = 0; - BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); - if (bf == NULL) - return 0; - - if (bf->Hash == BloomFilterTestHash) - result = 1; - - BloomFilterFree(bf); - return result; -} - -static int BloomFilterTestInit04 (void) -{ - BloomFilter *bf = BloomFilterInit(1024, 0, BloomFilterTestHash); - if (bf == NULL) - return 1; - - BloomFilterFree(bf); - return 0; -} - -static int BloomFilterTestInit05 (void) -{ - BloomFilter *bf = BloomFilterInit(0, 4, BloomFilterTestHash); - if (bf == NULL) - return 1; - - BloomFilterFree(bf); - return 0; -} - -static int BloomFilterTestAdd01 (void) -{ - int result = 0; - BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); - if (bf == NULL) - return 0; - - int r = BloomFilterAdd(bf, "test", 0); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (bf != NULL) BloomFilterFree(bf); - return result; -} - -static int BloomFilterTestAdd02 (void) -{ - int result = 0; - BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); - if (bf == NULL) - return 0; - - int r = BloomFilterAdd(bf, NULL, 4); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (bf != NULL) BloomFilterFree(bf); - return result; -} - -static int BloomFilterTestFull01 (void) -{ - int result = 0; - BloomFilter *bf = BloomFilterInit(32, 4, BloomFilterTestHash); - if (bf == NULL) - goto end; - - int r = BloomFilterAdd(bf, "test", 4); - if (r != 0) - goto end; - - r = BloomFilterTest(bf, "test", 4); - if (r != 1) - goto end; - - /* all is good! */ - result = 1; -end: - if (bf != NULL) BloomFilterFree(bf); - return result; -} - -static int BloomFilterTestFull02 (void) -{ - int result = 0; - BloomFilter *bf = BloomFilterInit(32, 4, BloomFilterTestHash); - if (bf == NULL) - goto end; - - int r = BloomFilterTest(bf, "test", 4); - if (r != 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (bf != NULL) BloomFilterFree(bf); - return result; -} -#endif /* UNITTESTS */ - -void BloomFilterRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("BloomFilterTestInit01", BloomFilterTestInit01); - UtRegisterTest("BloomFilterTestInit02", BloomFilterTestInit02); - UtRegisterTest("BloomFilterTestInit03", BloomFilterTestInit03); - UtRegisterTest("BloomFilterTestInit04", BloomFilterTestInit04); - UtRegisterTest("BloomFilterTestInit05", BloomFilterTestInit05); - - UtRegisterTest("BloomFilterTestAdd01", BloomFilterTestAdd01); - UtRegisterTest("BloomFilterTestAdd02", BloomFilterTestAdd02); - - UtRegisterTest("BloomFilterTestFull01", BloomFilterTestFull01); - UtRegisterTest("BloomFilterTestFull02", BloomFilterTestFull02); -#endif /* UNITTESTS */ -} - diff --git a/src/util-bloomfilter.h b/src/util-bloomfilter.h deleted file mode 100644 index b6dee868a588..000000000000 --- a/src/util-bloomfilter.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __BLOOMFILTER_H__ -#define __BLOOMFILTER_H__ - -/* Bloom Filter structure */ -typedef struct BloomFilter_ { - uint8_t hash_iterations; - uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t); - uint32_t bitarray_size; - uint8_t *bitarray; -} BloomFilter; - -/* prototypes */ -BloomFilter *BloomFilterInit(uint32_t, uint8_t, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)); -void BloomFilterFree(BloomFilter *); -void BloomFilterPrint(BloomFilter *); -int BloomFilterAdd(BloomFilter *, const void *, uint16_t); -uint32_t BloomFilterMemoryCnt(BloomFilter *); -uint32_t BloomFilterMemorySize(BloomFilter *); - -void BloomFilterRegisterTests(void); - -/** ----- Inline functions ---- */ - -static inline int BloomFilterTest(const BloomFilter *, const void *, uint16_t); - -static inline int BloomFilterTest(const BloomFilter *bf, const void *data, uint16_t datalen) -{ - uint8_t iter = 0; - uint32_t hash = 0; - int hit = 1; - - for (iter = 0; iter < bf->hash_iterations; iter++) { - hash = bf->Hash(data, datalen, iter, bf->bitarray_size); - if (!(bf->bitarray[hash/8] & (1< - */ - -#include "suricata-common.h" -#include "util-bpf.h" -#include "threads.h" -#include "conf.h" -#include "util-debug.h" - -void ConfSetBPFFilter( - ConfNode *if_root, ConfNode *if_default, const char *iface, const char **bpf_filter) -{ - if (*bpf_filter != NULL) { - SCLogInfo("BPF filter already configured"); - return; - } - - /* command line value has precedence */ - if (ConfGet("bpf-filter", bpf_filter) == 1) { - if (strlen(*bpf_filter) > 0) { - SCLogConfig("%s: using command-line provided bpf filter '%s'", iface, *bpf_filter); - } - } else if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", bpf_filter) == - 1) { // reading from a file - if (strlen(*bpf_filter) > 0) { - SCLogConfig("%s: using file provided bpf filter %s", iface, *bpf_filter); - } - } else { - SCLogDebug("No BPF filter found, skipping"); - } -} - -/** protect bpf filter build, as it is not thread safe */ -static SCMutex bpf_set_filter_lock = SCMUTEX_INITIALIZER; - -void SCBPFFree(struct bpf_program *program) -{ - if (program) - pcap_freecode(program); -} - -int SCBPFCompile(int snaplen_arg, int linktype_arg, struct bpf_program *program, - const char *buf, - int optimize, uint32_t mask, - char *errbuf, size_t errbuf_len) -{ - pcap_t *p; - int ret; - - p = pcap_open_dead(linktype_arg, snaplen_arg); - if (p == NULL) - return (-1); - - SCMutexLock(&bpf_set_filter_lock); - ret = pcap_compile(p, program, buf, optimize, mask); - if (ret == -1) { - if (errbuf) { - snprintf(errbuf, errbuf_len, "%s", pcap_geterr(p)); - } - pcap_close(p); - SCMutexUnlock(&bpf_set_filter_lock); - return (-1); - } - pcap_close(p); - SCMutexUnlock(&bpf_set_filter_lock); - - if (program->bf_insns == NULL) { - if (errbuf) { - snprintf(errbuf, errbuf_len, "Filter badly setup"); - } - SCBPFFree(program); - return (-1); - } - - return (ret); -} diff --git a/src/util-bpf.h b/src/util-bpf.h deleted file mode 100644 index 8196077f8a07..000000000000 --- a/src/util-bpf.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - */ - -#ifndef __UTIL_BPF_H__ -#define __UTIL_BPF_H__ - -#include "conf.h" - -void ConfSetBPFFilter( - ConfNode *if_root, ConfNode *if_default, const char *iface, const char **bpf_filter); - -int SCBPFCompile(int snaplen_arg, int linktype_arg, struct bpf_program *program, - const char *buf, int optimize, uint32_t mask, - char *errbuf, size_t errbuf_len); - -void SCBPFFree(struct bpf_program *program); - -#endif /* __UTIL_BPF_H__ */ diff --git a/src/util-buffer.c b/src/util-buffer.c deleted file mode 100644 index be7aee4046c8..000000000000 --- a/src/util-buffer.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-debug.h" -#include "util-buffer.h" - -/* 10 mb */ -#define MAX_LIMIT 10485760 - -MemBuffer *MemBufferCreateNew(uint32_t size) -{ - sc_errno = SC_OK; - if (size > MAX_LIMIT) { - SCLogWarning("Mem buffer asked to create " - "buffer with size greater than API limit - %d", - MAX_LIMIT); - sc_errno = SC_EINVAL; - return NULL; - } - - uint32_t total_size = size + sizeof(MemBuffer); - - MemBuffer *buffer = SCCalloc(1, total_size); - if (unlikely(buffer == NULL)) { - sc_errno = SC_ENOMEM; - return NULL; - } - - buffer->size = size; - buffer->buffer = (uint8_t *)buffer + sizeof(MemBuffer); - - return buffer; -} - -/** \brief expand membuffer by size of 'expand_by' - * - * If expansion failed, buffer will still be valid. - * - * \retval result 0 ok, -1 expansion failed - */ -int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by) { - if (((*buffer)->size + expand_by) > MAX_LIMIT) { - SCLogWarning("Mem buffer asked to create " - "buffer with size greater than API limit - %d", - MAX_LIMIT); - return -1; - } - - uint32_t total_size = (*buffer)->size + sizeof(MemBuffer) + expand_by; - - MemBuffer *tbuffer = SCRealloc(*buffer, total_size); - if (unlikely(tbuffer == NULL)) { - return -1; - } - - *buffer = tbuffer; - (*buffer)->size += expand_by; - (*buffer)->buffer = (uint8_t *)tbuffer + sizeof(MemBuffer); - - SCLogDebug("expanded buffer by %u, size is now %u", expand_by, (*buffer)->size); - return 0; -} - -void MemBufferFree(MemBuffer *buffer) -{ - SCFree(buffer); - - return; -} diff --git a/src/util-buffer.h b/src/util-buffer.h deleted file mode 100644 index 3a88c8e96b82..000000000000 --- a/src/util-buffer.h +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_BUFFER_H__ -#define __UTIL_BUFFER_H__ - -typedef struct MemBuffer_ { - uint8_t *buffer; - uint32_t size; - uint32_t offset; -} MemBuffer; - -MemBuffer *MemBufferCreateNew(uint32_t size); -int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by); -void MemBufferFree(MemBuffer *buffer); - -/** - * \brief Reset the mem buffer. - * - * \param mem_buffer Pointer to the mem buffer instance. - */ -#define MemBufferReset(mem_buffer) do { \ - (mem_buffer)->buffer[0] = 0; \ - (mem_buffer)->offset = 0; \ - } while (0) - -/** - * \brief Get the MemBuffers underlying buffer. - */ -#define MEMBUFFER_BUFFER(mem_buffer) (mem_buffer)->buffer - -/** - * \brief Get the MemBuffers current offset. - */ -#define MEMBUFFER_OFFSET(mem_buffer) (mem_buffer)->offset - -/** - * \brief Get the MemBuffers current size. - */ -#define MEMBUFFER_SIZE(mem_buffer) (mem_buffer)->size - -/** - * \brief Write a buffer to the file pointer. - * - * Accepted buffers can contain both printable and non-printable - * characters. Printable characters are written in the printable - * format and the non-printable chars are written in hex codes - * using the |XX| format. - * - * For example this would be the kind of output in the file - - * onetwo|EF|three|ED|five - * - * \param buffer Pointer to the src MemBuffer instance to write. - * \param fp Pointer to the file instance to write to. - */ -#define MemBufferPrintToFP(buffer, fp) do { \ - uint32_t i; \ - \ - for (i = 0; i < (buffer)->offset; i++) { \ - if (isprint(buffer->buffer[i])) \ - fprintf(fp, "%c", (buffer)->buffer[i]); \ - else \ - fprintf(fp, "|%02X|", (buffer)->buffer[i]); \ - } \ - } while (0) - -/** - * \brief Write a buffer to the file pointer as a printable char string. - * - * \param buffer Pointer to the src MemBuffer instance to write. - * \param fp Pointer to the file instance to write to. - */ -#define MemBufferPrintToFPAsString(mem_buffer, fp) ({ \ - fwrite((mem_buffer)->buffer, sizeof(uint8_t), (mem_buffer)->offset, fp); \ -}) - -/** - * \brief Write a buffer in hex format. - * - * \param buffer Pointer to the src MemBuffer instance to write. - * \param fp Pointer to the file instance to write to. - */ -#define MemBufferPrintToFPAsHex(mem_buffer, fp) do { \ - uint32_t i; \ - \ - for (i = 0; i < (mem_buffer)->offset; i++) { \ - if (((mem_buffer)->offset % 8) == 0) \ - fprintf(fp, "\n"); \ - fprintf(fp, " %02X", (mem_buffer)->buffer[i]); \ - } \ - } while (0) - - -/** - * \brief Write a raw buffer to the MemBuffer dst. - * - * When we say raw buffer it indicates a buffer that need not be - * purely a string buffer. It can be a pure string buffer or not or - * a mixture of both. Hence we don't accept any format strings. - * - * If the remaining space on the buffer is lesser than the length of - * the buffer to write, it is truncated to fit into the empty space. - * - * Also after every write a '\0' is appended. This would indicate - * that the total available space to write in the buffer is - * MemBuffer->size - 1 and not Membuffer->size. The reason we - * append the '\0' is for supporting writing pure string buffers - * as well, that can later be used by other string handling funcs. - * - * \param raw_buffer The buffer to write. - * \param raw_buffer_len Length of the above buffer. - */ -#define MemBufferWriteRaw(dst, raw_buffer, raw_buffer_len) do { \ - uint32_t write_len; \ - \ - if (((raw_buffer_len) >= (dst)->size - (dst)->offset)) { \ - SCLogDebug("Truncating data write since it exceeded buffer limit of " \ - "- %"PRIu32, (dst)->size); \ - write_len = ((dst)->size - (dst)->offset) - 1; \ - } else { \ - write_len = (raw_buffer_len); \ - } \ - \ - memcpy((dst)->buffer + (dst)->offset, (raw_buffer), write_len); \ - (dst)->offset += write_len; \ - dst->buffer[dst->offset] = '\0'; \ - } while (0) - -/** - * \brief Write a string buffer to the Membuffer dst. - * - * This function takes a format string and arguments for the format - * string like sprintf. - * - * An example usage of this is - - * MemBufferWriteString(mem_buffer_instance, \"%d - %s\", 10, \"one\"); - * - * \param dst The dst MemBuffer instance. - * \param format The format string. - * \param ... Variable arguments. - */ -#define MemBufferWriteString(dst, ...) do { \ - int cw = snprintf((char *)(dst)->buffer + (dst)->offset, \ - (dst)->size - (dst)->offset, \ - __VA_ARGS__); \ - if (cw >= 0) { \ - if ( ((dst)->offset + cw) >= (dst)->size) { \ - SCLogDebug("Truncating data write since it exceeded buffer " \ - "limit of - %"PRIu32"\n", (dst)->size); \ - (dst)->offset = (dst)->size - 1; \ - } else { \ - (dst->offset) += cw; \ - } \ - } \ - } while (0) - -#endif /* __UTIL_BUFFER_H__ */ diff --git a/src/util-byte.c b/src/util-byte.c deleted file mode 100644 index d2f39fb2d211..000000000000 --- a/src/util-byte.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Brian Rectanus - * - * Byte utility functions - */ - -#include "suricata-common.h" -#include "util-byte.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-validate.h" - -/** \brief Turn byte array into string. - * - * All non-printables are copied over, except for '\0', which is - * turned into literal \0 in the string. - * - * \param bytes byte array - * \param nbytes number of bytes - * \return string nul-terminated string or NULL on error - */ -char *BytesToString(const uint8_t *bytes, size_t nbytes) -{ - size_t n = nbytes + 1; - size_t nulls = 0; - - size_t u; - for (u = 0; u < nbytes; u++) { - if (bytes[u] == '\0') - nulls++; - } - n += nulls; - - char *string = SCCalloc(1, n); - if (string == NULL) - return NULL; - - if (nulls == 0) { - /* no nulls */ - memcpy(string, bytes, nbytes); - } else { - /* nulls present */ - char *dst = string; - for (u = 0; u < nbytes; u++) { - if (bytes[u] == '\0') { - *dst++ = '\\'; - *dst++ = '0'; - } else { - *dst++ = bytes[u]; - } - } - } - return string; -} - -/** \brief Turn byte array into string. - * - * All non-printables are copied over, except for '\0', which is - * turned into literal \0 in the string. - * - * \param bytes byte array - * \param nbytes number of bytes - * \param outstr[out] buffer to fill - * \param outlen size of outstr. Must be at least 2 * nbytes + 1 in size - */ -void BytesToStringBuffer(const uint8_t *bytes, size_t nbytes, char *outstr, size_t outlen) -{ - DEBUG_VALIDATE_BUG_ON(outlen < (nbytes * 2 + 1)); - - size_t n = nbytes + 1; - size_t nulls = 0; - - size_t u; - for (u = 0; u < nbytes; u++) { - if (bytes[u] == '\0') - nulls++; - } - n += nulls; - - char string[n]; - - if (nulls == 0) { - /* no nulls */ - memcpy(string, bytes, nbytes); - string[nbytes] = '\0'; - } else { - /* nulls present */ - char *dst = string; - for (u = 0; u < nbytes; u++) { - if (bytes[u] == '\0') { - *dst++ = '\\'; - *dst++ = '0'; - } else { - *dst++ = bytes[u]; - } - } - *dst = '\0'; - } - - strlcpy(outstr, string, outlen); -} - -int ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes) -{ - uint64_t i64; - int ret; - - /* Uint64 is limited to 8 bytes */ - if (len > 8) { - /** \todo Need standard return values */ - return -1; - } - - ret = ByteExtract(&i64, e, len, bytes); - if (ret <= 0) { - return ret; - } - - *res = (uint64_t)i64; - - return ret; -} - -int ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes) -{ - uint64_t i64; - int ret; - - /* Uint32 is limited to 4 bytes */ - if (len > 4) { - /** \todo Need standard return values */ - return -1; - } - - ret = ByteExtract(&i64, e, len, bytes); - if (ret <= 0) { - return ret; - } - - *res = (uint32_t)i64; - - return ret; -} - -int ByteExtractUint16(uint16_t *res, int e, uint16_t len, const uint8_t *bytes) -{ - uint64_t i64; - int ret; - - /* Uint16 is limited to 2 bytes */ - if (len > 2) { - /** \todo Need standard return values */ - return -1; - } - - ret = ByteExtract(&i64, e, len, bytes); - if (ret <= 0) { - return ret; - } - - *res = (uint16_t)i64; - - return ret; -} - -int ByteExtractString(uint64_t *res, int base, size_t len, const char *str, bool strict) -{ - const char *ptr = str; - char *endptr = NULL; - - /* 23 - This is the largest string (octal, with a zero prefix) that - * will not overflow uint64_t. The only way this length - * could be over 23 and still not overflow is if it were zero - * prefixed and we only support 1 byte of zero prefix for octal. - * - * "01777777777777777777777" = 0xffffffffffffffff - */ - char strbuf[24]; - - if (len > 23) { - SCLogDebug("len too large (23 max)"); - return -1; - } - - if (len) { - /* Extract out the string so it can be null terminated */ - memcpy(strbuf, str, len); - strbuf[len] = '\0'; - ptr = strbuf; - } - - errno = 0; - *res = strtoull(ptr, &endptr, base); - - if (errno == ERANGE) { - SCLogDebug("numeric value out of range"); - return -1; - /* If there is no numeric value in the given string then strtoull(), makes - endptr equals to ptr and return 0 as result */ - } else if (endptr == ptr && *res == 0) { - SCLogDebug("no numeric value"); - return -1; - } else if (endptr == ptr) { - SCLogDebug("invalid numeric value"); - return -1; - } - else if (strict && *endptr != '\0') { - SCLogError("Extra characters following numeric value"); - return -1; - } - - return (endptr - ptr); -} - -int ByteExtractStringUint64(uint64_t *res, int base, size_t len, const char *str) -{ - return ByteExtractString(res, base, len, str, false); -} - -int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str) -{ - uint64_t i64; - - int ret = ByteExtractString(&i64, base, len, str, false); - if (ret <= 0) { - return ret; - } - if (i64 > UINT32_MAX) { - return -1; - } - - *res = (uint32_t)i64; - - if ((uint64_t)(*res) != i64) { - SCLogDebug("Numeric value out of range (%" PRIu64 " > %" PRIuMAX ")", - i64, (uintmax_t)UINT_MAX); - return -1; - } - - return ret; -} - -int ByteExtractStringUint16(uint16_t *res, int base, size_t len, const char *str) -{ - uint64_t i64; - - int ret = ByteExtractString(&i64, base, len, str, false); - if (ret <= 0) { - return ret; - } - if (i64 > UINT16_MAX) { - return -1; - } - - *res = (uint16_t)i64; - - if ((uint64_t)(*res) != i64) { - SCLogDebug("Numeric value out of range (%" PRIu64 " > %" PRIuMAX ")", - i64, (uintmax_t)USHRT_MAX); - return -1; - } - - return ret; -} - -int ByteExtractStringUint8(uint8_t *res, int base, size_t len, const char *str) -{ - uint64_t i64; - - int ret = ByteExtractString(&i64, base, len, str, false); - if (ret <= 0) { - return ret; - } - if (i64 > UINT8_MAX) { - return -1; - } - - *res = (uint8_t)i64; - - if ((uint64_t)(*res) != i64) { - SCLogDebug("Numeric value out of range (%" PRIu64 " > %" PRIuMAX ")", - i64, (uintmax_t)UCHAR_MAX); - return -1; - } - - return ret; -} - -int StringParseUint64(uint64_t *res, int base, size_t len, const char *str) -{ - return ByteExtractString(res, base, len, str, true); -} - -int StringParseUint32(uint32_t *res, int base, size_t len, const char *str) -{ - uint64_t i64; - - int ret = ByteExtractString(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 > UINT32_MAX) { - return -1; - } - - *res = (uint32_t)i64; - - if ((uint64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIu64 " > %" PRIuMAX ")", - i64, (uintmax_t)UINT_MAX); - return -1; - } - - return ret; -} - -int StringParseUint16(uint16_t *res, int base, size_t len, const char *str) -{ - uint64_t i64; - - int ret = ByteExtractString(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 > UINT16_MAX) { - return -1; - } - - *res = (uint16_t)i64; - - if ((uint64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIu64 " > %" PRIuMAX ")", - i64, (uintmax_t)USHRT_MAX); - return -1; - } - - return ret; -} - -int StringParseUint8(uint8_t *res, int base, size_t len, const char *str) -{ - uint64_t i64; - - int ret = ByteExtractString(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 > UINT8_MAX) { - return -1; - } - - *res = (uint8_t)i64; - - if ((uint64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIu64 " > %" PRIuMAX ")", - i64, (uintmax_t)UCHAR_MAX); - return -1; - } - - return ret; -} - -int StringParseU64RangeCheck( - uint64_t *res, int base, size_t len, const char *str, uint64_t min, uint64_t max) -{ - uint64_t u64; - - int ret = ByteExtractString(&u64, base, len, str, true); - if (ret <= 0) { - return ret; - } - - *res = u64; - - if (*res < min || *res > max) { - return -1; - } - - return ret; -} - -int StringParseU32RangeCheck( - uint32_t *res, int base, size_t len, const char *str, uint32_t min, uint32_t max) -{ - uint64_t u64; - - int ret = ByteExtractString(&u64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (u64 > UINT32_MAX) { - return -1; - } - - *res = (uint32_t)u64; - - if (*res < min || *res > max) { - return -1; - } - - if ((uint64_t)(*res) != u64) { - SCLogError("Numeric value out of range " - "(%" PRIu64 " > %" PRIuMAX ")", - u64, (uintmax_t)UINT_MAX); - return -1; - } - - return ret; -} - -int StringParseU16RangeCheck( - uint16_t *res, int base, size_t len, const char *str, uint16_t min, uint16_t max) -{ - uint64_t u64; - - int ret = ByteExtractString(&u64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (u64 > UINT16_MAX) { - return -1; - } - - *res = (uint16_t)u64; - - if (*res < min || *res > max) { - return -1; - } - - if ((uint64_t)(*res) != u64) { - SCLogError("Numeric value out of range " - "(%" PRIu64 " > %" PRIuMAX ")", - u64, (uintmax_t)USHRT_MAX); - return -1; - } - - return ret; -} - -int StringParseU8RangeCheck( - uint8_t *res, int base, size_t len, const char *str, uint8_t min, uint8_t max) -{ - uint64_t u64; - - int ret = ByteExtractString(&u64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (u64 > UINT8_MAX) { - return -1; - } - - *res = (uint8_t)u64; - - if (*res < min || *res > max) { - return -1; - } - - if ((uint64_t)(*res) != u64) { - SCLogError("Numeric value out of range " - "(%" PRIu64 " > %" PRIuMAX ")", - u64, (uintmax_t)UCHAR_MAX); - return -1; - } - - return ret; -} - -int ByteExtractStringSigned(int64_t *res, int base, size_t len, const char *str, bool strict) -{ - const char *ptr = str; - char *endptr; - - /* 23 - This is the largest string (octal, with a zero prefix) that - * will not overflow int64_t. The only way this length - * could be over 23 and still not overflow is if it were zero - * prefixed and we only support 1 byte of zero prefix for octal. - * - * "-0777777777777777777777" = 0xffffffffffffffff - */ - char strbuf[24]; - - if (len > 23) { - SCLogError("len too large (23 max)"); - return -1; - } - - if (len) { - /* Extract out the string so it can be null terminated */ - memcpy(strbuf, str, len); - strbuf[len] = '\0'; - ptr = strbuf; - } - - errno = 0; - *res = strtoll(ptr, &endptr, base); - - if (errno == ERANGE) { - SCLogError("Numeric value out of range"); - return -1; - } else if (endptr == str) { - SCLogError("Invalid numeric value"); - return -1; - } - else if (strict && len && *endptr != '\0') { - SCLogError("Extra characters following numeric value"); - return -1; - } - - //fprintf(stderr, "ByteExtractStringSigned: Extracted base %d: 0x%" PRIx64 "\n", base, *res); - - return (endptr - ptr); -} - -int ByteExtractStringInt64(int64_t *res, int base, size_t len, const char *str) -{ - return ByteExtractStringSigned(res, base, len, str, false); -} - -int ByteExtractStringInt32(int32_t *res, int base, size_t len, const char *str) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, false); - if (ret <= 0) { - return ret; - } - if (i64 < INT32_MIN || i64 > INT32_MAX) { - return -1; - } - - *res = (int32_t)i64; - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)INT_MAX); - return -1; - } - - return ret; -} - -int ByteExtractStringInt16(int16_t *res, int base, size_t len, const char *str) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, false); - if (ret <= 0) { - return ret; - } - if (i64 < INT16_MIN || i64 > INT16_MAX) { - return -1; - } - - *res = (int16_t)i64; - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)SHRT_MAX); - return -1; - } - - return ret; -} - -int ByteExtractStringInt8(int8_t *res, int base, size_t len, const char *str) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, false); - if (ret <= 0) { - return ret; - } - if (i64 < INT8_MIN || i64 > INT8_MAX) { - return -1; - } - - *res = (int8_t)i64; - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)CHAR_MAX); - return -1; - } - - return ret; -} - -int StringParseInt64(int64_t *res, int base, size_t len, const char *str) -{ - return ByteExtractStringSigned(res, base, len, str, true); -} - -int StringParseInt32(int32_t *res, int base, size_t len, const char *str) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 < INT32_MIN || i64 > INT32_MAX) { - return -1; - } - - *res = (int32_t)i64; - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)INT_MAX); - return -1; - } - - return ret; -} - -int StringParseInt16(int16_t *res, int base, size_t len, const char *str) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 < INT16_MIN || i64 > INT16_MAX) { - return -1; - } - - *res = (int16_t)i64; - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)SHRT_MAX); - return -1; - } - - return ret; -} - -int StringParseInt8(int8_t *res, int base, size_t len, const char *str) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 < INT8_MIN || i64 > INT8_MAX) { - return -1; - } - - *res = (int8_t)i64; - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)CHAR_MAX); - return -1; - } - - return ret; -} - -int StringParseI64RangeCheck( - int64_t *res, int base, size_t len, const char *str, int64_t min, int64_t max) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - - *res = i64; - if (*res < min || *res > max) { - return -1; - } - - return ret; -} - -int StringParseI32RangeCheck( - int32_t *res, int base, size_t len, const char *str, int32_t min, int32_t max) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 < INT32_MIN || i64 > INT32_MAX) { - return -1; - } - - *res = (int32_t)i64; - - if (*res < min || *res > max) { - return -1; - } - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)INT_MAX); - return -1; - } - - return ret; -} - -int StringParseI16RangeCheck( - int16_t *res, int base, size_t len, const char *str, int16_t min, int16_t max) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 < INT16_MIN || i64 > INT16_MAX) { - return -1; - } - - *res = (int16_t)i64; - - if (*res < min || *res > max) { - return -1; - } - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)SHRT_MAX); - return -1; - } - - return ret; -} - -int StringParseI8RangeCheck( - int8_t *res, int base, size_t len, const char *str, int8_t min, int8_t max) -{ - int64_t i64; - int ret; - - ret = ByteExtractStringSigned(&i64, base, len, str, true); - if (ret <= 0) { - return ret; - } - if (i64 < INT8_MIN || i64 > INT8_MAX) { - return -1; - } - - *res = (int8_t)i64; - - if (*res < min || *res > max) { - return -1; - } - - if ((int64_t)(*res) != i64) { - SCLogError("Numeric value out of range " - "(%" PRIi64 " > %" PRIiMAX ")\n", - i64, (intmax_t)CHAR_MAX); - return -1; - } - - return ret; -} - -/* UNITTESTS */ -#ifdef UNITTESTS - -static int ByteTest01 (void) -{ - uint16_t val = 0x0102; - uint16_t i16 = 0xbfbf; - uint8_t bytes[2] = { 0x02, 0x01 }; - int ret = ByteExtractUint16(&i16, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); - - if ((ret == 2) && (i16 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest02 (void) -{ - uint16_t val = 0x0102; - uint16_t i16 = 0xbfbf; - uint8_t bytes[2] = { 0x01, 0x02 }; - int ret = ByteExtractUint16(&i16, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); - - if ((ret == 2) && (i16 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest03 (void) -{ - uint32_t val = 0x01020304; - uint32_t i32 = 0xbfbfbfbf; - uint8_t bytes[4] = { 0x04, 0x03, 0x02, 0x01 }; - int ret = ByteExtractUint32(&i32, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); - - if ((ret == 4) && (i32 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest04 (void) -{ - uint32_t val = 0x01020304; - uint32_t i32 = 0xbfbfbfbf; - uint8_t bytes[4] = { 0x01, 0x02, 0x03, 0x04 }; - int ret = ByteExtractUint32(&i32, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); - - if ((ret == 4) && (i32 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest05 (void) -{ - uint64_t val = 0x0102030405060708ULL; - uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; - uint8_t bytes[8] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }; - int ret = ByteExtractUint64(&i64, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); - - if ((ret == 8) && (i64 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest06 (void) -{ - uint64_t val = 0x0102030405060708ULL; - uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; - uint8_t bytes[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; - int ret = ByteExtractUint64(&i64, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); - - if ((ret == 8) && (i64 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest07 (void) -{ - const char str[] = "1234567890"; - uint64_t val = 1234567890; - uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; - int ret = ByteExtractStringUint64(&i64, 10, sizeof(str) - 1, str); - - if ((ret == 10) && (i64 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest08 (void) -{ - const char str[] = "1234567890"; - uint32_t val = 1234567890; - uint32_t i32 = 0xbfbfbfbf; - int ret = ByteExtractStringUint32(&i32, 10, sizeof(str) - 1, str); - - if ((ret == 10) && (i32 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest09 (void) -{ - const char str[] = "12345"; - uint16_t val = 12345; - uint16_t i16 = 0xbfbf; - int ret = ByteExtractStringUint16(&i16, 10, sizeof(str) - 1, str); - - if ((ret == 5) && (i16 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest10 (void) -{ - const char str[] = "123"; - uint8_t val = 123; - uint8_t i8 = 0xbf; - int ret = ByteExtractStringUint8(&i8, 10, sizeof(str) - 1, str); - - if ((ret == 3) && (i8 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest11 (void) -{ - const char str[] = "-1234567890"; - int64_t val = -1234567890; - int64_t i64 = 0xbfbfbfbfbfbfbfbfULL; - int ret = ByteExtractStringInt64(&i64, 10, sizeof(str) - 1, str); - - if ((ret == 11) && (i64 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest12 (void) -{ - const char str[] = "-1234567890"; - int32_t val = -1234567890; - int32_t i32 = 0xbfbfbfbf; - int ret = ByteExtractStringInt32(&i32, 10, sizeof(str) - 1, str); - - if ((ret == 11) && (i32 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest13 (void) -{ - const char str[] = "-12345"; - int16_t val = -12345; - int16_t i16 = 0xbfbf; - int ret = ByteExtractStringInt16(&i16, 10, sizeof(str) - 1, str); - - if ((ret == 6) && (i16 == val)) { - return 1; - } - - return 0; -} - -static int ByteTest14 (void) -{ - const char str[] = "-123"; - int8_t val = -123; - int8_t i8 = 0xbf; - int ret = ByteExtractStringInt8(&i8, 10, sizeof(str) - 1, str); - - if ((ret == 4) && (i8 == val)) { - return 1; - } - - return 0; -} - -/** \test max u32 value */ -static int ByteTest15 (void) -{ - const char str[] = "4294967295"; - uint32_t val = 4294967295UL; - uint32_t u32 = 0xffffffff; - - int ret = ByteExtractStringUint32(&u32, 10, sizeof(str) - 1, str); - if ((ret == 10) && (u32 == val)) { - return 1; - } - - return 0; -} - -/** \test max u32 value + 1 */ -static int ByteTest16 (void) -{ - const char str[] = "4294967296"; - uint32_t u32 = 0; - - int ret = ByteExtractStringUint32(&u32, 10, sizeof(str) - 1, str); - if (ret != 0) { - return 1; - } - - return 0; -} - -void ByteRegisterTests(void) -{ - UtRegisterTest("ByteTest01", ByteTest01); - UtRegisterTest("ByteTest02", ByteTest02); - UtRegisterTest("ByteTest03", ByteTest03); - UtRegisterTest("ByteTest04", ByteTest04); - UtRegisterTest("ByteTest05", ByteTest05); - UtRegisterTest("ByteTest06", ByteTest06); - UtRegisterTest("ByteTest07", ByteTest07); - UtRegisterTest("ByteTest08", ByteTest08); - UtRegisterTest("ByteTest09", ByteTest09); - UtRegisterTest("ByteTest10", ByteTest10); - UtRegisterTest("ByteTest11", ByteTest11); - UtRegisterTest("ByteTest12", ByteTest12); - UtRegisterTest("ByteTest13", ByteTest13); - UtRegisterTest("ByteTest14", ByteTest14); - UtRegisterTest("ByteTest15", ByteTest15); - UtRegisterTest("ByteTest16", ByteTest16); -} -#endif /* UNITTESTS */ - diff --git a/src/util-byte.h b/src/util-byte.h deleted file mode 100644 index ae3e1d2a6902..000000000000 --- a/src/util-byte.h +++ /dev/null @@ -1,506 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Brian Rectanus - */ - -#ifndef __UTIL_BYTE_H__ -#define __UTIL_BYTE_H__ - -#include - -#define BYTE_BIG_ENDIAN 0 -#define BYTE_LITTLE_ENDIAN 1 - -/** Wrappers for OS dependent byte swapping functions */ -#ifdef OS_FREEBSD -#include -#define SCByteSwap16(x) bswap16(x) -#define SCByteSwap32(x) bswap32(x) -#define SCByteSwap64(x) bswap64(x) -#elif defined __OpenBSD__ -#include -#define SCByteSwap16(x) swap16(x) -#define SCByteSwap32(x) swap32(x) -#define SCByteSwap64(x) swap64(x) -#elif OS_DARWIN -#include -#define SCByteSwap16(x) OSSwapInt16(x) -#define SCByteSwap32(x) OSSwapInt32(x) -#define SCByteSwap64(x) OSSwapInt64(x) -#elif defined(__WIN32) || defined(_WIN32) || defined(sun) -/* Quick & dirty solution, nothing seems to exist for this in Win32 API */ -#define SCByteSwap16(x) \ - ((((x) & 0xff00) >> 8) \ - | (((x) & 0x00ff) << 8)) -#define SCByteSwap32(x) \ - ((((x) & 0xff000000) >> 24) \ - | (((x) & 0x00ff0000) >> 8) \ - | (((x) & 0x0000ff00) << 8) \ - | (((x) & 0x000000ff) << 24)) -#define SCByteSwap64(x) \ - ((((x) & 0xff00000000000000ull) >> 56) \ - | (((x) & 0x00ff000000000000ull) >> 40) \ - | (((x) & 0x0000ff0000000000ull) >> 24) \ - | (((x) & 0x000000ff00000000ull) >> 8) \ - | (((x) & 0x00000000ff000000ull) << 8) \ - | (((x) & 0x0000000000ff0000ull) << 24) \ - | (((x) & 0x000000000000ff00ull) << 40) \ - | (((x) & 0x00000000000000ffull) << 56)) -#else -#include -#define SCByteSwap16(x) bswap_16(x) -#define SCByteSwap32(x) bswap_32(x) -#define SCByteSwap64(x) bswap_64(x) -#endif /* OS_FREEBSD */ - -/** \brief Turn byte array into string. - * - * All non-printables are copied over, except for '\0', which is - * turned into literal \0 in the string. - * - * \param bytes byte array - * \param nbytes number of bytes - * \return string nul-terminated string or NULL on error - */ -char *BytesToString(const uint8_t *bytes, size_t nbytes); -void BytesToStringBuffer(const uint8_t *bytes, size_t nbytes, char *outstr, size_t outlen); - -/** - * Extract bytes from a byte string and convert to a unint64_t. - * - * \param res Stores result - * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) - * \param len Number of bytes to extract (8 max) - * \param bytes Data to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes); - -/** - * Extract bytes from a byte string and convert to a uint32_t. - * - * \param res Stores result - * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) - * \param len Number of bytes to extract (8 max) - * \param bytes Data to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes); - -/** - * Extract bytes from a byte string and convert to a unint16_t. - * - * \param res Stores result - * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) - * \param len Number of bytes to extract (8 max) - * \param bytes Data to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractUint16(uint16_t *res, int e, uint16_t len, const uint8_t *bytes); - -/** - * Extract unsigned integer value from a string. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * \param bool Enable strict check for parsers - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractString( - uint64_t *res, int base, size_t len, const char *str, bool strict); - -/** - * Extract unsigned integer value from a string as uint64_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringUint64(uint64_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint32_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint16_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringUint16(uint16_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint8_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringUint8(uint8_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * \param bool Enable strict check for parsers - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringSigned( - int64_t *res, int base, size_t len, const char *str, bool strict); - -/** - * Extract signed integer value from a string as uint64_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringInt64(int64_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string as uint32_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringInt32(int32_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string as uint16_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringInt16(int16_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string as uint8_t. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED ByteExtractStringInt8(int8_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint64_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseUint64(uint64_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint32_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseUint32(uint32_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint16_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseUint16(uint16_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint8_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseUint8(uint8_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string as int64_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseInt64(int64_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string as int32_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseInt32(int32_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string as int16_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseInt16(int16_t *res, int base, size_t len, const char *str); - -/** - * Extract signed integer value from a string as int8_t strictly. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int StringParseInt8(int8_t *res, int base, size_t len, const char *str); - -/** - * Extract unsigned integer value from a string as uint64_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseU64RangeCheck( - uint64_t *res, int base, size_t len, const char *str, uint64_t min, uint64_t max); - -/** - * Extract unsigned integer value from a string as uint32_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseU32RangeCheck( - uint32_t *res, int base, size_t len, const char *str, uint32_t min, uint32_t max); - -/** - * Extract unsigned integer value from a string as uint16_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseU16RangeCheck( - uint16_t *res, int base, size_t len, const char *str, uint16_t min, uint16_t max); - -/** - * Extract unsigned integer value from a string as uint8_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseU8RangeCheck( - uint8_t *res, int base, size_t len, const char *str, uint8_t min, uint8_t max); - -/** - * Extract signed integer value from a string as int64_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseI64RangeCheck( - int64_t *res, int base, size_t len, const char *str, int64_t min, int64_t max); - -/** - * Extract signed integer value from a string as int32_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseI32RangeCheck( - int32_t *res, int base, size_t len, const char *str, int32_t min, int32_t max); - -/** - * Extract signed integer value from a string as int16_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseI16RangeCheck( - int16_t *res, int base, size_t len, const char *str, int16_t min, int16_t max); - -/** - * Extract signed integer value from a string as int8_t strictly within the range. - * - * \param res Stores result - * \param base Base of the number to extract - * \param len Number of bytes to extract (23 max or 0 for unbounded) - * \param str String to extract from - * - * \return n Number of bytes extracted on success - * \return -1 On error - */ -int WARN_UNUSED StringParseI8RangeCheck( - int8_t *res, int base, size_t len, const char *str, int8_t min, int8_t max); - -#ifdef UNITTESTS -void ByteRegisterTests(void); -#endif /* UNITTESTS */ - -/** ------ Inline functions ----- */ -static inline int WARN_UNUSED ByteExtract(uint64_t *res, int e, uint16_t len, const uint8_t *bytes) -{ - if ((e != BYTE_BIG_ENDIAN) && (e != BYTE_LITTLE_ENDIAN)) { - /** \todo Need standard return values */ - return -1; - } - - *res = 0; - - /* Go through each byte and merge it into the result in the correct order */ - /** \todo Probably a more efficient way to do this. */ - for (int i = 0; i < len; i++) { - uint64_t b; - if (e == BYTE_LITTLE_ENDIAN) { - b = bytes[i]; - } - else { - b = bytes[len - i - 1]; - } - - *res |= (b << ((i & 7) << 3)); - } - - return len; -} - -#endif /* __UTIL_BYTE_H__ */ diff --git a/src/util-checksum.c b/src/util-checksum.c deleted file mode 100644 index 53a4c425b693..000000000000 --- a/src/util-checksum.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2011-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * - * Util functions for checksum. - */ - -#include "suricata-common.h" -#include "util-checksum.h" - -int ReCalculateChecksum(Packet *p) -{ - if (PKT_IS_IPV4(p)) { - if (PKT_IS_TCP(p)) { - /* TCP */ - p->tcph->th_sum = 0; - p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); - } else if (PKT_IS_UDP(p)) { - p->udph->uh_sum = 0; - p->udph->uh_sum = UDPV4Checksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); - } - /* IPV4 */ - p->ip4h->ip_csum = 0; - p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, - IPV4_GET_RAW_HLEN(p->ip4h), 0); - } else if (PKT_IS_IPV6(p)) { - /* just TCP for IPV6 */ - if (PKT_IS_TCP(p)) { - p->tcph->th_sum = 0; - p->tcph->th_sum = TCPV6Checksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); - } else if (PKT_IS_UDP(p)) { - p->udph->uh_sum = 0; - p->udph->uh_sum = UDPV6Checksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); - } - } - - return 0; -} - -/** - * \brief Check if the number of invalid checksums indicate checksum - * offloading in place. - * - * \retval 1 yes, offloading in place - * \retval 0 no, no offloading used - */ -int ChecksumAutoModeCheck(uint64_t thread_count, - uint64_t iface_count, uint64_t iface_fail) -{ - if (thread_count == CHECKSUM_SAMPLE_COUNT) { - if (iface_fail != 0) { - if ((iface_count / iface_fail) < CHECKSUM_INVALID_RATIO) { - SCLogInfo("More than 1/%dth of packets have an invalid " - "checksum, assuming checksum offloading is used " - "(%"PRIu64"/%"PRIu64")", - CHECKSUM_INVALID_RATIO, iface_fail, iface_count); - return 1; - } else { - SCLogInfo("Less than 1/%dth of packets have an invalid " - "checksum, assuming checksum offloading is NOT used " - "(%"PRIu64"/%"PRIu64")", CHECKSUM_INVALID_RATIO, - iface_fail, iface_count); - } - } else { - SCLogInfo("No packets with invalid checksum, assuming " - "checksum offloading is NOT used"); - } - } - return 0; -} diff --git a/src/util-checksum.h b/src/util-checksum.h deleted file mode 100644 index c7b056bdd88c..000000000000 --- a/src/util-checksum.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2011-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - */ - -#ifndef __UTIL_CHECKSUM_H__ -#define __UTIL_CHECKSUM_H__ - -#include "decode.h" - -int ReCalculateChecksum(Packet *p); -int ChecksumAutoModeCheck(uint64_t thread_count, - uint64_t iface_count, uint64_t iface_fail); - -/* constant linked with detection of interface with - * invalid checksums */ -#define CHECKSUM_SAMPLE_COUNT 1000ULL -#define CHECKSUM_INVALID_RATIO 10 - -#endif diff --git a/src/util-cidr.c b/src/util-cidr.c deleted file mode 100644 index 4e6e18d67aef..000000000000 --- a/src/util-cidr.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * CIDR utility functions - */ - -#include "suricata-common.h" -#include "util-cidr.h" -#include "util-debug.h" -#include "util-unittest.h" - -/** \brief Turn 32 bit mask into CIDR - * - * \retval cidr The cidr value or -1 if the netmask can't be expressed as cidr - */ -int CIDRFromMask(uint32_t netmask) -{ - netmask = ntohl(netmask); - if (netmask == 0) { - return 0; - } - int p = 0; - bool seen_1 = false; - while (netmask > 0) { - if (netmask & 1) { - seen_1 = true; - p++; - } else { - if (seen_1) { - return -1; - } - } - netmask >>= 1; - } - return p; -} - -uint32_t CIDRGet(int cidr) -{ - if (cidr <= 0 || cidr > 32) - return 0; - uint32_t netmask = htonl(0xFFFFFFFF << (32UL - (uint32_t)cidr)); - SCLogDebug("CIDR %d -> netmask %08X", cidr, netmask); - return netmask; -} - -/** - * \brief Creates a cidr ipv6 netblock, based on the cidr netblock value. - * - * For example if we send a cidr of 7 as argument, an ipv6 address - * mask of the value FE:00:00:00:00:00:00:00 is created and updated - * in the argument struct in6_addr *in6. - * - * \todo I think for the final section: while (cidr > 0), we can simply - * replace it with a - * if (cidr > 0) { - * in6->s6_addr[i] = -1 << (8 - cidr); - * - * \param cidr The value of the cidr. - * \param in6 Pointer to an ipv6 address structure(struct in6_addr) which will - * hold the cidr netblock result. - */ -void CIDRGetIPv6(int cidr, struct in6_addr *in6) -{ - int i = 0; - - memset(in6, 0, sizeof(struct in6_addr)); - - while (cidr > 8) { - in6->s6_addr[i] = 0xff; - cidr -= 8; - i++; - } - - while (cidr > 0) { - in6->s6_addr[i] |= 0x80; - if (--cidr > 0) - in6->s6_addr[i] = in6->s6_addr[i] >> 1; - } -} - -#ifdef UNITTESTS - -static int CIDRFromMaskTest01(void) -{ - struct in_addr in; - int v = inet_pton(AF_INET, "255.255.255.0", &in); - - FAIL_IF(v <= 0); - FAIL_IF_NOT(24 == CIDRFromMask(in.s_addr)); - - PASS; -} - -static int CIDRFromMaskTest02(void) -{ - struct in_addr in; - int v = inet_pton(AF_INET, "255.255.0.42", &in); - - FAIL_IF(v <= 0); - FAIL_IF_NOT(-1 == CIDRFromMask(in.s_addr)); - - PASS; -} - -static int CIDRFromMaskTest03(void) -{ - struct in_addr in; - int v = inet_pton(AF_INET, "0.0.0.0", &in); - - FAIL_IF(v <= 0); - FAIL_IF_NOT(0 == CIDRFromMask(in.s_addr)); - - PASS; -} - -static int CIDRFromMaskTest04(void) -{ - struct in_addr in; - int v = inet_pton(AF_INET, "255.255.255.255", &in); - - FAIL_IF(v <= 0); - FAIL_IF_NOT(32 == CIDRFromMask(in.s_addr)); - - PASS; -} - -#endif /* UNITTESTS */ - -void UtilCIDRTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("CIDRFromMaskTest01", CIDRFromMaskTest01); - UtRegisterTest("CIDRFromMaskTest02", CIDRFromMaskTest02); - UtRegisterTest("CIDRFromMaskTest03", CIDRFromMaskTest03); - UtRegisterTest("CIDRFromMaskTest04", CIDRFromMaskTest04); -#endif /* UNITTESTS */ -} diff --git a/src/util-cidr.h b/src/util-cidr.h deleted file mode 100644 index 745f67823c61..000000000000 --- a/src/util-cidr.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_NETMASK_H__ -#define __UTIL_NETMASK_H__ - -int CIDRFromMask(uint32_t netmask); -uint32_t CIDRGet(int); -void CIDRGetIPv6(int cidr, struct in6_addr *in6); - -void UtilCIDRTests(void); - -#endif /* __UTIL_NETMASK_H__ */ - diff --git a/src/util-classification-config.c b/src/util-classification-config.c deleted file mode 100644 index 5bcc0960c887..000000000000 --- a/src/util-classification-config.c +++ /dev/null @@ -1,798 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Used for parsing a classification.config file - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-engine.h" -#include "util-hash.h" - -#include "conf.h" -#include "util-classification-config.h" -#include "util-unittest.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-fmemopen.h" -#include "util-byte.h" - -/* Regex to parse the classtype argument from a Signature. The first substring - * holds the classtype name, the second substring holds the classtype the - * classtype description, and the third argument holds the priority */ -#define DETECT_CLASSCONFIG_REGEX "^\\s*config\\s*classification\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*,\\s*(.+)\\s*,\\s*(\\d+)\\s*$" - -/* Default path for the classification.config file */ -#if defined OS_WIN32 || defined __CYGWIN__ -#define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\classification.config" -#else -#define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/classification.config" -#endif - -uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen); -char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2); -void SCClassConfClasstypeHashFree(void *ch); -static const char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx); - -static SCClassConfClasstype *SCClassConfAllocClasstype(uint16_t classtype_id, - const char *classtype, const char *classtype_desc, int priority); -static void SCClassConfDeAllocClasstype(SCClassConfClasstype *ct); - -void SCClassConfInit(DetectEngineCtx *de_ctx) -{ - int en; - PCRE2_SIZE eo; - int opts = 0; - - de_ctx->class_conf_regex = pcre2_compile( - (PCRE2_SPTR8)DETECT_CLASSCONFIG_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); - if (de_ctx->class_conf_regex == NULL) { - PCRE2_UCHAR errbuffer[256]; - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - SCLogWarning("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - DETECT_CLASSCONFIG_REGEX, (int)eo, errbuffer); - return; - } - de_ctx->class_conf_regex_match = - pcre2_match_data_create_from_pattern(de_ctx->class_conf_regex, NULL); - return; -} - -void SCClassConfDeinit(DetectEngineCtx *de_ctx) -{ - if (de_ctx->class_conf_regex != NULL) { - pcre2_code_free(de_ctx->class_conf_regex); - de_ctx->class_conf_regex = NULL; - } - if (de_ctx->class_conf_regex_match != NULL) { - pcre2_match_data_free(de_ctx->class_conf_regex_match); - de_ctx->class_conf_regex_match = NULL; - } -} - - -/** - * \brief Inits the context to be used by the Classification Config parsing API. - * - * This function initializes the hash table to be used by the Detection - * Engine Context to hold the data from the classification.config file, - * obtains the file desc to parse the classification.config file, and - * inits the regex used to parse the lines from classification.config - * file. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param fd Pointer to already opened file - * - * \note even if the file open fails we will keep the de_ctx->class_conf_ht - * initialized. - * - * \retval fp NULL on error - */ -static FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) -{ - /* init the hash table to be used by the classification config Classtypes */ - de_ctx->class_conf_ht = HashTableInit(128, SCClassConfClasstypeHashFunc, - SCClassConfClasstypeHashCompareFunc, - SCClassConfClasstypeHashFree); - if (de_ctx->class_conf_ht == NULL) { - SCLogError("Error initializing the hash " - "table"); - return NULL; - } - - /* if it is not NULL, use the file descriptor. The hack so that we can - * avoid using a dummy classification file for testing purposes and - * instead use an input stream against a buffer containing the - * classification strings */ - if (fd == NULL) { - const char *filename = SCClassConfGetConfFilename(de_ctx); - if ( (fd = fopen(filename, "r")) == NULL) { -#ifdef UNITTESTS - if (RunmodeIsUnittests()) - return NULL; // silently fail -#endif - SCLogWarning("could not open: \"%s\": %s", filename, strerror(errno)); - return NULL; - } - } - - return fd; -} - - -/** - * \brief Returns the path for the Classification Config file. We check if we - * can retrieve the path from the yaml conf file. If it is not present, - * return the default path for the classification file which is - * "./classification.config". - * - * \retval log_filename Pointer to a string containing the path for the - * Classification Config file. - */ -static const char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx) -{ - const char *log_filename = NULL; - - if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { - char config_value[256]; - snprintf(config_value, sizeof(config_value), - "%s.classification-file", de_ctx->config_prefix); - - /* try loading prefix setting, fall back to global if that - * fails. */ - if (ConfGet(config_value, &log_filename) != 1) { - if (ConfGet("classification-file", &log_filename) != 1) { - log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; - } - } - } else { - if (ConfGet("classification-file", &log_filename) != 1) { - log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; - } - } - - return log_filename; -} - -/** - * \brief Releases resources used by the Classification Config API. - */ -static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) -{ - if (fd != NULL) { - fclose(fd); - } -} - -/** - * \brief Releases resources used by the Classification Config API. - */ -void SCClassConfDeInitContext(DetectEngineCtx *de_ctx) -{ - if (de_ctx->class_conf_ht != NULL) - HashTableFree(de_ctx->class_conf_ht); - - de_ctx->class_conf_ht = NULL; - - return; -} - -/** - * \brief Converts a string to lowercase. - * - * \param str Pointer to the string to be converted. - */ -static char *SCClassConfStringToLowercase(const char *str) -{ - char *new_str = NULL; - char *temp_str = NULL; - - if ( (new_str = SCStrdup(str)) == NULL) { - SCLogError("Error allocating memory"); - return NULL; - } - - temp_str = new_str; - while (*temp_str != '\0') { - *temp_str = u8_tolower((unsigned char)*temp_str); - temp_str++; - } - - return new_str; -} - -/** - * \brief Parses a line from the classification file and adds it to Classtype - * hash table in DetectEngineCtx, i.e. DetectEngineCtx->class_conf_ht. - * - * \param rawstr Pointer to the string to be parsed. - * \param index Relative index of the string to be parsed. - * \param de_ctx Pointer to the Detection Engine Context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCClassConfAddClasstype(DetectEngineCtx *de_ctx, char *rawstr, uint16_t index) -{ - char ct_name[CLASSTYPE_NAME_MAX_LEN]; - char ct_desc[CLASSTYPE_DESC_MAX_LEN]; - char ct_priority_str[16]; - uint32_t ct_priority = 0; - uint16_t ct_id = index; - - SCClassConfClasstype *ct_new = NULL; - SCClassConfClasstype *ct_lookup = NULL; - - int ret = 0; - - ret = pcre2_match(de_ctx->class_conf_regex, (PCRE2_SPTR8)rawstr, strlen(rawstr), 0, 0, - de_ctx->class_conf_regex_match, NULL); - if (ret < 0) { - SCLogError("Invalid Classtype in " - "classification.config file %s: \"%s\"", - SCClassConfGetConfFilename(de_ctx), rawstr); - goto error; - } - - size_t copylen = sizeof(ct_name); - /* retrieve the classtype name */ - ret = pcre2_substring_copy_bynumber( - de_ctx->class_conf_regex_match, 1, (PCRE2_UCHAR8 *)ct_name, ©len); - if (ret < 0) { - SCLogInfo("pcre2_substring_copy_bynumber() failed"); - goto error; - } - - /* retrieve the classtype description */ - copylen = sizeof(ct_desc); - ret = pcre2_substring_copy_bynumber( - de_ctx->class_conf_regex_match, 2, (PCRE2_UCHAR8 *)ct_desc, ©len); - if (ret < 0) { - SCLogInfo("pcre2_substring_copy_bynumber() failed"); - goto error; - } - - /* retrieve the classtype priority */ - copylen = sizeof(ct_priority_str); - ret = pcre2_substring_copy_bynumber( - de_ctx->class_conf_regex_match, 3, (PCRE2_UCHAR8 *)ct_priority_str, ©len); - if (ret < 0) { - SCLogInfo("pcre2_substring_copy_bynumber() failed"); - goto error; - } - if (StringParseUint32(&ct_priority, 10, 0, (const char *)ct_priority_str) < 0) { - goto error; - } - - /* Create a new instance of the parsed Classtype string */ - ct_new = SCClassConfAllocClasstype(ct_id, ct_name, ct_desc, ct_priority); - if (ct_new == NULL) - goto error; - - /* Check if the Classtype is present in the HashTable. In case it's present - * ignore it, as it is a duplicate. If not present, add it to the table */ - ct_lookup = HashTableLookup(de_ctx->class_conf_ht, ct_new, 0); - if (ct_lookup == NULL) { - if (HashTableAdd(de_ctx->class_conf_ht, ct_new, 0) < 0) - SCLogDebug("HashTable Add failed"); - } else { - SCLogDebug("Duplicate classtype found inside classification.config"); - if (ct_new->classtype_desc) SCFree(ct_new->classtype_desc); - if (ct_new->classtype) SCFree(ct_new->classtype); - SCFree(ct_new); - } - - return 0; - - error: - return -1; -} - -/** - * \brief Checks if a string is a comment or a blank line. - * - * Comments lines are lines of the following format - - * "# This is a comment string" or - * " # This is a comment string". - * - * \param line String that has to be checked - * - * \retval 1 On the argument string being a comment or blank line - * \retval 0 Otherwise - */ -static int SCClassConfIsLineBlankOrComment(char *line) -{ - while (*line != '\0') { - /* we have a comment */ - if (*line == '#') - return 1; - - /* this line is neither a comment line, nor a blank line */ - if (!isspace((unsigned char)*line)) - return 0; - - line++; - } - - /* we have a blank line */ - return 1; -} - -/** - * \brief Parses the Classification Config file and updates the - * DetectionEngineCtx->class_conf_ht with the Classtype information. - * - * \param de_ctx Pointer to the Detection Engine Context. - */ -static bool SCClassConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) -{ - char line[1024]; - uint16_t i = 1; - int errors = 0; - - while (fgets(line, sizeof(line), fd) != NULL) { - if (SCClassConfIsLineBlankOrComment(line)) - continue; - - if (SCClassConfAddClasstype(de_ctx, line, i) == -1) { - errors++; - } else { - i++; - } - } - -#ifdef UNITTESTS - if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) - SCLogInfo("tenant id %d: Added \"%d\" classification types from the classification file", - de_ctx->tenant_id, de_ctx->class_conf_ht->count); - else - SCLogInfo("Added \"%d\" classification types from the classification file", - de_ctx->class_conf_ht->count); -#endif - - return errors == 0; -} - -/** - * \internal - * \brief Returns a new SCClassConfClasstype instance. The classtype string - * is converted into lowercase, before being assigned to the instance. - * - * \param classtype Pointer to the classification type. - * \param classtype_desc Pointer to the classification type description. - * \param priority Holds the priority for the classification type. - * - * \retval ct Pointer to the new instance of SCClassConfClasstype on success; - * NULL on failure. - */ -static SCClassConfClasstype *SCClassConfAllocClasstype(uint16_t classtype_id, - const char *classtype, - const char *classtype_desc, - int priority) -{ - SCClassConfClasstype *ct = NULL; - - if (classtype == NULL) - return NULL; - - if ((ct = SCCalloc(1, sizeof(SCClassConfClasstype))) == NULL) - return NULL; - - if ((ct->classtype = SCClassConfStringToLowercase(classtype)) == NULL) { - SCClassConfDeAllocClasstype(ct); - return NULL; - } - - if (classtype_desc != NULL && - (ct->classtype_desc = SCStrdup(classtype_desc)) == NULL) { - SCLogError("Error allocating memory"); - - SCClassConfDeAllocClasstype(ct); - return NULL; - } - - ct->classtype_id = classtype_id; - ct->priority = priority; - - return ct; -} - -/** - * \internal - * \brief Frees a SCClassConfClasstype instance - * - * \param Pointer to the SCClassConfClasstype instance that has to be freed - */ -static void SCClassConfDeAllocClasstype(SCClassConfClasstype *ct) -{ - if (ct != NULL) { - if (ct->classtype != NULL) - SCFree(ct->classtype); - - if (ct->classtype_desc != NULL) - SCFree(ct->classtype_desc); - - SCFree(ct); - } - - return; -} - -/** - * \brief Hashing function to be used to hash the Classtype name. Would be - * supplied as an argument to the HashTableInit function for - * DetectEngineCtx->class_conf_ht. - * - * \param ht Pointer to the HashTable. - * \param data Pointer to the data to be hashed. In this case, the data - * would be a pointer to a SCClassConfClasstype instance. - * \param datalen Not used by this function. - */ -uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - SCClassConfClasstype *ct = (SCClassConfClasstype *)data; - uint32_t hash = 0; - int i = 0; - - int len = strlen(ct->classtype); - - for (i = 0; i < len; i++) - hash += u8_tolower((unsigned char)(ct->classtype)[i]); - - hash = hash % ht->array_size; - - return hash; -} - -/** - * \brief Used to compare two Classtypes that have been stored in the HashTable. - * This function is supplied as an argument to the HashTableInit function - * for DetectionEngineCtx->class_conf_ct. - * - * \param data1 Pointer to the first SCClassConfClasstype to be compared. - * \param len1 Not used by this function. - * \param data2 Pointer to the second SCClassConfClasstype to be compared. - * \param len2 Not used by this function. - * - * \retval 1 On data1 and data2 being equal. - * \retval 0 On data1 and data2 not being equal. - */ -char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2) -{ - SCClassConfClasstype *ct1 = (SCClassConfClasstype *)data1; - SCClassConfClasstype *ct2 = (SCClassConfClasstype *)data2; - int len1 = 0; - int len2 = 0; - - if (ct1 == NULL || ct2 == NULL) - return 0; - - if (ct1->classtype == NULL || ct2->classtype == NULL) - return 0; - - len1 = strlen(ct1->classtype); - len2 = strlen(ct2->classtype); - - if (len1 == len2 && memcmp(ct1->classtype, ct2->classtype, len1) == 0) { - SCLogDebug("Match found inside Classification-Config hash function"); - return 1; - } - - return 0; -} - -/** - * \brief Used to free the Classification Config Hash Data that was stored in - * DetectEngineCtx->class_conf_ht Hashtable. - * - * \param ch Pointer to the data that has to be freed. - */ -void SCClassConfClasstypeHashFree(void *ch) -{ - SCClassConfDeAllocClasstype(ch); - - return; -} - -/** - * \brief Loads the Classtype info from the classification.config file. - * - * The classification.config file contains the different classtypes, - * that can be used to label Signatures. Each line of the file should - * have the following format - - * classtype_name, classtype_description, priority - * None of the above parameters should hold a quote inside the file. - * - * \param de_ctx Pointer to the Detection Engine Context that should be updated - * with Classtype information. - */ -bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *de_ctx, FILE *fd) -{ - fd = SCClassConfInitContextAndLocalResources(de_ctx, fd); - if (fd == NULL) { -#ifdef UNITTESTS - if (RunmodeIsUnittests()) { - return false; - } -#endif - SCLogError("please check the \"classification-file\" " - "option in your suricata.yaml file"); - return false; - } - - bool ret = true; - if (!SCClassConfParseFile(de_ctx, fd)) { - SCLogWarning("Error loading classification configuration from %s", - SCClassConfGetConfFilename(de_ctx)); - ret = false; - } - - SCClassConfDeInitLocalResources(de_ctx, fd); - - return ret; -} - -/** - * \brief Gets the classtype from the corresponding hash table stored - * in the Detection Engine Context's class conf ht, given the - * classtype name. - * - * \param ct_name Pointer to the classtype name that has to be looked up. - * \param de_ctx Pointer to the Detection Engine Context. - * - * \retval lookup_ct_info Pointer to the SCClassConfClasstype instance from - * the hash table on success; NULL on failure. - */ -SCClassConfClasstype *SCClassConfGetClasstype(const char *ct_name, - DetectEngineCtx *de_ctx) -{ - char name[strlen(ct_name) + 1]; - size_t s; - for (s = 0; s < strlen(ct_name); s++) - name[s] = u8_tolower((unsigned char)ct_name[s]); - name[s] = '\0'; - - SCClassConfClasstype ct_lookup = {0, 0, name, NULL }; - SCClassConfClasstype *lookup_ct_info = HashTableLookup(de_ctx->class_conf_ht, - &ct_lookup, 0); - return lookup_ct_info; -} - -/*----------------------------------Unittests---------------------------------*/ - - -#ifdef UNITTESTS - -/** - * \brief Creates a dummy classification file, with all valid Classtypes, for - * testing purposes. - * - * \file_path Pointer to the file_path for the dummy classification file. - */ -FILE *SCClassConfGenerateValidDummyClassConfigFD01(void) -{ - const char *buffer = - "config classification: nothing-wrong,Nothing Wrong With Us,3\n" - "config classification: unknown,Unknown are we,3\n" - "config classification: bad-unknown,We think it's bad, 2\n"; - - FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Classification Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy classification file, with some valid Classtypes and a - * couple of invalid Classtypes, for testing purposes. - * - * \file_path Pointer to the file_path for the dummy classification file. - */ -FILE *SCClassConfGenerateInvalidDummyClassConfigFD02(void) -{ - const char *buffer = - "config classification: not-suspicious,Not Suspicious Traffic,3\n" - "onfig classification: unknown,Unknown Traffic,3\n" - "config classification: _badunknown,Potentially Bad Traffic, 2\n" - "config classification: bamboola1,Unknown Traffic,3\n" - "config classification: misc-activity,Misc activity,-1\n" - "config classification: policy-violation,Potential Corporate " - "config classification: bamboola,Unknown Traffic,3\n"; - - FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Classification Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy classification file, with all invalid Classtypes, for - * testing purposes. - * - * \file_path Pointer to the file_path for the dummy classification file. - */ -FILE *SCClassConfGenerateInvalidDummyClassConfigFD03(void) -{ - const char *buffer = - "conig classification: not-suspicious,Not Suspicious Traffic,3\n" - "onfig classification: unknown,Unknown Traffic,3\n" - "config classification: _badunknown,Potentially Bad Traffic, 2\n" - "config classification: misc-activity,Misc activity,-1\n"; - - FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Classification Config test code"); - - return fd; -} - -/** - * \test Check that the classification file is loaded and the detection engine - * content class_conf_hash_table loaded with the classtype data. - */ -static int SCClassConfTest01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 0; - - if (de_ctx == NULL) - return result; - - FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassificationConfigFile(de_ctx, fd); - - if (de_ctx->class_conf_ht == NULL) - return result; - - result = (de_ctx->class_conf_ht->count == 3); - if (result == 0) printf("de_ctx->class_conf_ht->count %u: ", de_ctx->class_conf_ht->count); - - DetectEngineCtxFree(de_ctx); - - return result; -} - -/** - * \test Check that invalid classtypes present in the classification config file - * aren't loaded. - */ -static int SCClassConfTest02(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 0; - - if (de_ctx == NULL) - return result; - - FILE *fd = SCClassConfGenerateInvalidDummyClassConfigFD03(); - SCClassConfLoadClassificationConfigFile(de_ctx, fd); - - if (de_ctx->class_conf_ht == NULL) - return result; - - result = (de_ctx->class_conf_ht->count == 0); - - DetectEngineCtxFree(de_ctx); - - return result; -} - -/** - * \test Check that only valid classtypes are loaded into the hash table from - * the classification.config file. - */ -static int SCClassConfTest03(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - - FAIL_IF_NULL(de_ctx); - - FILE *fd = SCClassConfGenerateInvalidDummyClassConfigFD02(); - FAIL_IF(SCClassConfLoadClassificationConfigFile(de_ctx, fd)); - - DetectEngineCtxFree(de_ctx); - - PASS; -} - -/** - * \test Check if the classtype info from the classification.config file have - * been loaded into the hash table. - */ -static int SCClassConfTest04(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 1; - - if (de_ctx == NULL) - return 0; - - FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassificationConfigFile(de_ctx, fd); - - if (de_ctx->class_conf_ht == NULL) - return 0; - - result = (de_ctx->class_conf_ht->count == 3); - - result &= (SCClassConfGetClasstype("unknown", de_ctx) != NULL); - result &= (SCClassConfGetClasstype("unKnoWn", de_ctx) != NULL); - result &= (SCClassConfGetClasstype("bamboo", de_ctx) == NULL); - result &= (SCClassConfGetClasstype("bad-unknown", de_ctx) != NULL); - result &= (SCClassConfGetClasstype("BAD-UNKnOWN", de_ctx) != NULL); - result &= (SCClassConfGetClasstype("bed-unknown", de_ctx) == NULL); - - DetectEngineCtxFree(de_ctx); - - return result; -} - -/** - * \test Check if the classtype info from the invalid classification.config file - * have not been loaded into the hash table, and cross verify to check - * that the hash table contains no classtype data. - */ -static int SCClassConfTest05(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 1; - - if (de_ctx == NULL) - return 0; - - FILE *fd = SCClassConfGenerateInvalidDummyClassConfigFD03(); - SCClassConfLoadClassificationConfigFile(de_ctx, fd); - - if (de_ctx->class_conf_ht == NULL) - return 0; - - result = (de_ctx->class_conf_ht->count == 0); - - result &= (SCClassConfGetClasstype("unknown", de_ctx) == NULL); - result &= (SCClassConfGetClasstype("unKnoWn", de_ctx) == NULL); - result &= (SCClassConfGetClasstype("bamboo", de_ctx) == NULL); - result &= (SCClassConfGetClasstype("bad-unknown", de_ctx) == NULL); - result &= (SCClassConfGetClasstype("BAD-UNKnOWN", de_ctx) == NULL); - result &= (SCClassConfGetClasstype("bed-unknown", de_ctx) == NULL); - - DetectEngineCtxFree(de_ctx); - - return result; -} - -/** - * \brief This function registers unit tests for Classification Config API. - */ -void SCClassConfRegisterTests(void) -{ - UtRegisterTest("SCClassConfTest01", SCClassConfTest01); - UtRegisterTest("SCClassConfTest02", SCClassConfTest02); - UtRegisterTest("SCClassConfTest03", SCClassConfTest03); - UtRegisterTest("SCClassConfTest04", SCClassConfTest04); - UtRegisterTest("SCClassConfTest05", SCClassConfTest05); -} -#endif /* UNITTESTS */ diff --git a/src/util-classification-config.h b/src/util-classification-config.h deleted file mode 100644 index 9ac00c85d09e..000000000000 --- a/src/util-classification-config.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_CLASSIFICATION_CONFIG_H__ -#define __UTIL_CLASSIFICATION_CONFIG_H__ - -#define CLASSTYPE_NAME_MAX_LEN 64 -#define CLASSTYPE_DESC_MAX_LEN 512 - -/** - * \brief Container for a Classtype from the Classification.config file. - */ -typedef struct SCClassConfClasstype_ { - /* The index of the classification within classification.config */ - uint16_t classtype_id; - - /* The priority this classification type carries */ - int priority; - - /* The classtype name. This is the primary key for a Classification. */ - char *classtype; - - /* Description for a classification. Would be used while printing out - * the classification info for a Signature, by the fast-log module. */ - char *classtype_desc; -} SCClassConfClasstype; - -bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *, FILE *fd); -int SCClassConfAddClasstype(DetectEngineCtx *de_ctx, char *rawstr, uint16_t index); -SCClassConfClasstype *SCClassConfGetClasstype(const char *, - DetectEngineCtx *); -void SCClassConfDeInitContext(DetectEngineCtx *); - -void SCClassConfInit(DetectEngineCtx *de_ctx); -void SCClassConfDeinit(DetectEngineCtx *de_ctx); - -/* for unittests */ -#ifdef UNITTESTS -void SCClassConfRegisterTests(void); -FILE *SCClassConfGenerateValidDummyClassConfigFD01(void); -FILE *SCClassConfGenerateInvalidDummyClassConfigFD02(void); -FILE *SCClassConfGenerateInvalidDummyClassConfigFD03(void); -#endif - -#endif /* __UTIL_CLASSIFICATION_CONFIG_H__ */ diff --git a/src/util-clock.h b/src/util-clock.h deleted file mode 100644 index cb6c17623f99..000000000000 --- a/src/util-clock.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_CLOCK_H__ -#define __UTIL_CLOCK_H__ - -#include - -/* Feel free to add more macros */ - -#define CLOCK_INIT clock_t clo1, clo2; clo1 = clo2 = 0; -#define CLOCK_START clo1 = clock() - -#define CLOCK_END clo2 = clock() - -#define CLOCK_PRINT_SEC \ - printf("Seconds spent: %.4fs\n", ((double)(clo2 - clo1) / (double)CLOCKS_PER_SEC)) - -#endif /*__UTIL_CLOCK_H__ */ diff --git a/src/util-conf.c b/src/util-conf.c deleted file mode 100644 index 9bf5586bd970..000000000000 --- a/src/util-conf.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "conf.h" -#include "runmodes.h" -#include "util-conf.h" -#include "util-debug.h" -#include "util-path.h" - -TmEcode ConfigSetLogDirectory(const char *name) -{ - return ConfSetFinal("default-log-dir", name) ? TM_ECODE_OK : TM_ECODE_FAILED; -} - -const char *ConfigGetLogDirectory(void) -{ - const char *log_dir = NULL; - - if (ConfGet("default-log-dir", &log_dir) != 1) { -#ifdef OS_WIN32 - log_dir = _getcwd(NULL, 0); - if (log_dir == NULL) { - log_dir = DEFAULT_LOG_DIR; - } -#else - log_dir = DEFAULT_LOG_DIR; -#endif /* OS_WIN32 */ - } - - return log_dir; -} - -TmEcode ConfigCheckLogDirectoryExists(const char *log_dir) -{ - SCEnter(); - SCStat buf; - if (SCStatFn(log_dir, &buf) != 0) { - SCReturnInt(TM_ECODE_FAILED); - } - SCReturnInt(TM_ECODE_OK); -} - -TmEcode ConfigSetDataDirectory(char *name) -{ - if (strlen(name) == 0) - return TM_ECODE_OK; - - size_t size = strlen(name) + 1; - char tmp[size]; - strlcpy(tmp, name, size); - if (size > 2 && tmp[size - 2] == '/') // > 2 to allow just / - tmp[size - 2] = '\0'; - - return ConfSetFinal("default-data-dir", tmp) ? TM_ECODE_OK : TM_ECODE_FAILED; -} - -const char *ConfigGetDataDirectory(void) -{ - const char *data_dir = NULL; - - if (ConfGet("default-data-dir", &data_dir) != 1) { -#ifdef OS_WIN32 - data_dir = _getcwd(NULL, 0); - if (data_dir == NULL) { - data_dir = DEFAULT_DATA_DIR; - } -#else - data_dir = DEFAULT_DATA_DIR; -#endif /* OS_WIN32 */ - } - - SCLogDebug("returning '%s'", data_dir); - return data_dir; -} - -TmEcode ConfigCheckDataDirectory(const char *data_dir) -{ - SCEnter(); - SCStat buf; - if (SCStatFn(data_dir, &buf) != 0) { - SCReturnInt(TM_ECODE_FAILED); - } - SCReturnInt(TM_ECODE_OK); -} - -/** - * \brief Find the configuration node for a specific device. - - * Basically hunts through the list of maps for the first one with a - * key of "interface", and a value of the provided interface. - * - * \param node The node to start looking for the device - * configuration. Typically this would be something like the af-packet - * or pf-ring node. - * - * \param iface The name of the interface to find the config for. - */ -ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface) -{ - ConfNode *if_node, *item; - TAILQ_FOREACH(if_node, &node->head, next) { - TAILQ_FOREACH(item, &if_node->head, next) { - if (strcmp(item->name, "interface") == 0 && - strcmp(item->val, iface) == 0) { - return if_node; - } - } - } - - return NULL; -} - -int ConfUnixSocketIsEnable(void) -{ - const char *value; - - if (ConfGet("unix-command.enabled", &value) != 1) { - return 0; - } - - if (value == NULL) { - SCLogError("malformed value for unix-command.enabled: NULL"); - return 0; - } - - if (!strcmp(value, "auto")) { -#ifdef OS_WIN32 - return 0; -#else - if (!IsRunModeOffline(RunmodeGetCurrent())) { - SCLogInfo("Running in live mode, activating unix socket"); - return 1; - } else { - return 0; - } -#endif - } - - return ConfValIsTrue(value); -} diff --git a/src/util-conf.h b/src/util-conf.h deleted file mode 100644 index 1006c850cf11..000000000000 --- a/src/util-conf.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * - */ - -#ifndef __UTIL_UTIL_CONF_H__ -#define __UTIL_UTIL_CONF_H__ - -#include "conf.h" - -TmEcode ConfigSetLogDirectory(const char *name); -const char *ConfigGetLogDirectory(void); -TmEcode ConfigCheckLogDirectoryExists(const char *log_dir); - -TmEcode ConfigSetDataDirectory(char *name); -const char *ConfigGetDataDirectory(void); -TmEcode ConfigCheckDataDirectory(const char *log_dir); - -ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface); - -int ConfUnixSocketIsEnable(void); - -#endif /* __UTIL_UTIL_CONF_H__ */ diff --git a/src/util-config.h b/src/util-config.h deleted file mode 100644 index 92017d502162..000000000000 --- a/src/util-config.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_CONFIG_H__ -#define __UTIL_CONFIG_H__ - -enum ConfigAction { - CONFIG_ACTION_SET = 1, -}; - -enum ConfigSubsys { - CONFIG_SUBSYS_LOGGING = 0, -}; - -enum ConfigType { - CONFIG_TYPE_TX = 0, /* transaction logging */ - CONFIG_TYPE_FLOW, /* flow logging */ - CONFIG_TYPE_ALERT, /* alert logging */ - CONFIG_TYPE_ANOMALY, /* anomaly logging */ - CONFIG_TYPE_FILE, /* file logging */ - CONFIG_TYPE_PCAP, /* pcap logging */ - CONFIG_TYPE_DROP, /* drop logging */ -#define CONFIG_TYPE_DEFAULT CONFIG_TYPE_TX -}; - -enum ConfigScope { - CONFIG_SCOPE_TX = 0, /* per transaction */ - CONFIG_SCOPE_FLOW, /* per flow */ -#define CONFIG_SCOPE_DEFAULT CONFIG_SCOPE_TX -}; - -#endif diff --git a/src/util-coredump-config.c b/src/util-coredump-config.c deleted file mode 100644 index 09485cb79571..000000000000 --- a/src/util-coredump-config.c +++ /dev/null @@ -1,242 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eileen Donlon - * - * Coredump configuration - */ - -#include "suricata-common.h" -#define _FILE_OFFSET_BITS 64 -#include "util-coredump-config.h" -#include "conf.h" -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#ifdef HAVE_SYS_PRCTL_H -#include -#endif -#include "util-debug.h" - -#ifdef OS_WIN32 - -void CoredumpEnable(void) { -} - -int32_t CoredumpLoadConfig(void) { - /* todo: use the registry to get/set dump configuration */ - SCLogInfo("Configuring core dump is not yet supported on Windows."); - return 0; -} - -#else - -static bool unlimited = false; -static rlim_t max_dump = 0; - -/** - * \brief Enable coredumps on systems where coredumps can and need to - * be enabled. - */ -void CoredumpEnable(void) -{ - if (!unlimited && !max_dump) { - return; - } -#if HAVE_SYS_PRCTL_H - /* Linux specific core dump configuration; set dumpable flag if needed */ - int dumpable = 0; - dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); - if (dumpable == -1) { - SCLogNotice("Failed to get dumpable state of process, " - "core dumps may not be enabled: %s", - strerror(errno)); - } - else if (unlimited || max_dump > 0) { - /* try to enable core dump for this process */ - if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { - SCLogInfo("Unable to make this process dumpable."); - } else { - SCLogDebug("Process is dumpable."); - } - } - /* don't clear dumpable flag since this will have other effects; - * just set dump size to 0 below */ -#endif /* HAVE_SYS_PRCTL_H */ -} - -/** - * \brief Configures the core dump size. - * - * \retval Returns 1 on success and 0 on failure. - * - */ -int32_t CoredumpLoadConfig (void) -{ -#ifdef HAVE_SYS_RESOURCE_H - /* get core dump configuration settings for suricata */ - const char *dump_size_config = NULL; - size_t rlim_size = sizeof(rlim_t); - - if (ConfGet ("coredump.max-dump", &dump_size_config) == 0) { - SCLogDebug ("core dump size not specified"); - return 1; - } - if (dump_size_config == NULL) { - SCLogError("malformed value for coredump.max-dump: NULL"); - return 0; - } - if (strcasecmp (dump_size_config, "unlimited") == 0) { - unlimited = true; - } - else { - /* disallow negative values */ - if (strchr (dump_size_config, '-') != NULL) { - SCLogInfo ("Negative value for core dump size; ignored."); - return 0; - } - /* the size of rlim_t is platform dependent */ - if (rlim_size > 8) { - SCLogInfo ("Unexpected type for rlim_t"); - return 0; - } - errno = 0; - if (rlim_size == 8) { - max_dump = (rlim_t) strtoull (dump_size_config, NULL, 10); - } - else if (rlim_size == 4) { - max_dump = (rlim_t) strtoul (dump_size_config, NULL, 10); - } - if ((errno == ERANGE) || (errno != 0 && max_dump == 0)) { - SCLogInfo ("Illegal core dump size: %s.", dump_size_config); - return 0; - } - SCLogInfo ("Max dump is %"PRIu64, (uint64_t) max_dump); - } - - CoredumpEnable(); - - struct rlimit lim; /*existing limit*/ - struct rlimit new_lim; /*desired limit*/ - - /* get the current core dump file configuration */ - if (getrlimit (RLIMIT_CORE, &lim) == -1) { - SCLogInfo ("Can't read coredump limit for this process."); - return 0; - } - - if (unlimited) { - /* we want no limit on coredump size */ - if (lim.rlim_max == RLIM_INFINITY && lim.rlim_cur == RLIM_INFINITY) { - SCLogConfig ("Core dump size is unlimited."); - return 1; - } - else { - new_lim.rlim_max = RLIM_INFINITY; - new_lim.rlim_cur = RLIM_INFINITY; - if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { - SCLogConfig ("Core dump size set to unlimited."); - return 1; - } - if (errno == EPERM) { - /* couldn't raise the hard limit to unlimited; - * try increasing the soft limit to the hard limit instead */ - if (lim.rlim_cur < lim.rlim_max) { - new_lim.rlim_cur = lim.rlim_max; - if (setrlimit (RLIMIT_CORE, & new_lim) == 0) { - SCLogInfo ("Could not set core dump size to unlimited; core dump size set to the hard limit."); - return 0; - } - else { - SCLogInfo ("Failed to set core dump size to unlimited or to the hard limit."); - return 0; - } - } - SCLogInfo ("Could not set core dump size to unlimited; it's set to the hard limit."); - return 0; - } - } - } - else { - /* we want a non-infinite soft limit on coredump size */ - new_lim.rlim_cur = max_dump; - - /* check whether the hard limit needs to be adjusted */ - if (lim.rlim_max == RLIM_INFINITY) { - /* keep the current value (unlimited) for the hard limit */ - new_lim.rlim_max = lim.rlim_max; - } -#ifdef RLIM_SAVED_MAX - else if (lim.rlim_max == RLIM_SAVED_MAX) { - /* keep the current value (unknown) for the hard limit */ - new_lim.rlim_max = lim.rlim_max; - } -#endif - else if (lim.rlim_max < max_dump) { - /* need to raise the hard coredump size limit */ - new_lim.rlim_max = max_dump; - } - else { - /* hard limit is ample */ - new_lim.rlim_max = lim.rlim_max; - } - if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { - SCLogInfo ("Core dump setting attempted is %"PRIu64, (uint64_t) new_lim.rlim_cur); - struct rlimit actual_lim; - if (getrlimit (RLIMIT_CORE, &actual_lim) == 0) { - if (actual_lim.rlim_cur == RLIM_INFINITY) { - SCLogConfig ("Core dump size set to unlimited."); - } -#ifdef RLIM_SAVED_CUR - else if (actual_lim.rlim_cur == RLIM_SAVED_CUR) { - SCLogInfo ("Core dump size set to soft limit."); - } -#endif - else { - SCLogInfo ("Core dump size set to %"PRIu64, (uint64_t) actual_lim.rlim_cur); - } - } - return 1; - } - - if (errno == EINVAL || errno == EPERM) { - /* couldn't increase the hard limit, or the soft limit exceeded the hard - * limit; try to raise the soft limit to the hard limit */ - if ((lim.rlim_cur < max_dump && lim.rlim_cur < lim.rlim_max) -#ifdef RLIM_SAVED_CUR - || (lim.rlim_cur == RLIM_SAVED_CUR) -#endif - ){ - new_lim.rlim_max = lim.rlim_max; - new_lim.rlim_cur = lim.rlim_max; - if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { - SCLogInfo("Core dump size set to the hard limit."); - return 0; - } - } - } - } - /* failed to set the coredump limit */ - SCLogInfo("Couldn't set coredump size to %s.", dump_size_config); -#endif /* HAVE_SYS_RESOURCE_H */ - return 0; -} - -#endif /* OS_WIN32 */ diff --git a/src/util-cpu.c b/src/util-cpu.c deleted file mode 100644 index c73d5221e347..000000000000 --- a/src/util-cpu.c +++ /dev/null @@ -1,235 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * - * Retrieve CPU information (configured CPUs, online CPUs) - */ - -#include "suricata-common.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-cpu.h" -#include "util-byte.h" - -/** - * Ok, if they should use sysconf, check that they have the macro's - * (syscalls) defined; - * - * Note: For windows it's different; Check the following: - * SYSTEM_INFO info; - * GetSystemInfo(&info); - * -> info.dwNumberOfProcessors; - */ -#ifdef _SC_NPROCESSORS_CONF -#define SYSCONF_NPROCESSORS_CONF_COMPAT -#endif - -#ifdef _SC_NPROCESSORS_ONLN -#define SYSCONF_NPROCESSORS_ONLN_COMPAT -#endif - -/* This one is available on Solaris 10 */ -#ifdef _SC_NPROCESSORS_MAX -#define SYSCONF_NPROCESSORS_MAX_COMPAT -#endif - -/** - * \brief Get the number of cpus configured in the system - * \retval 0 if the syscall is not available or we have an error; - * otherwise it will return the number of cpus configured - */ -uint16_t UtilCpuGetNumProcessorsConfigured(void) -{ -#ifdef SYSCONF_NPROCESSORS_CONF_COMPAT - long nprocs = -1; - nprocs = sysconf(_SC_NPROCESSORS_CONF); - if (nprocs < 1) { - SCLogError("Couldn't retrieve the number of cpus " - "configured (%s)", - strerror(errno)); - return 0; - } - - if (nprocs > UINT16_MAX) { - SCLogDebug("It seems that there are more than %d CPUs " - "configured on this system. You can modify util-cpu.{c,h} " - "to use uint32_t to support it", UINT16_MAX); - return UINT16_MAX; - } - - return (uint16_t)nprocs; -#elif OS_WIN32 - int64_t nprocs = 0; - const char* envvar = getenv("NUMBER_OF_PROCESSORS"); - if (envvar != NULL) { - if (StringParseInt64(&nprocs, 10, 0, envvar) < 0) { - SCLogWarning("Invalid value for number of " - "processors: %s", - envvar); - return 0; - } - } - if (nprocs < 1) { - SCLogError("Couldn't retrieve the number of cpus " - "configured from the NUMBER_OF_PROCESSORS environment variable"); - return 0; - } - return (uint16_t)nprocs; -#else - SCLogError("Couldn't retrieve the number of cpus " - "configured, sysconf macro unavailable"); - return 0; -#endif -} - -/** - * \brief Get the number of cpus online in the system - * \retval 0 if the syscall is not available or we have an error; - * otherwise it will return the number of cpus online - */ -uint16_t UtilCpuGetNumProcessorsOnline(void) -{ -#ifdef SYSCONF_NPROCESSORS_ONLN_COMPAT - long nprocs = -1; - nprocs = sysconf(_SC_NPROCESSORS_ONLN); - if (nprocs < 1) { - SCLogError("Couldn't retrieve the number of cpus " - "online (%s)", - strerror(errno)); - return 0; - } - - if (nprocs > UINT16_MAX) { - SCLogDebug("It seems that there are more than %d CPUs online. " - "You can modify util-cpu.{c,h} to use uint32_t to " - "support it", UINT16_MAX); - return UINT16_MAX; - } - - return (uint16_t)nprocs; -#elif OS_WIN32 - return UtilCpuGetNumProcessorsConfigured(); -#else - SCLogError("Couldn't retrieve the number of cpus online, " - "synconf macro unavailable"); - return 0; -#endif -} - -/** - * \brief Get the maximum number of cpus allowed in the system - * This syscall is present on Solaris, but it's not on linux - * or macosx. Maybe you should look at UtilCpuGetNumProcessorsConfigured() - * \retval 0 if the syscall is not available or we have an error; - * otherwise it will return the number of cpus allowed - */ -uint16_t UtilCpuGetNumProcessorsMax(void) -{ -#ifdef SYSCONF_NPROCESSORS_MAX_COMPAT - long nprocs = -1; - nprocs = sysconf(_SC_NPROCESSORS_MAX); - if (nprocs < 1) { - SCLogError("Couldn't retrieve the maximum number of cpus " - "allowed by the system (%s)", - strerror(errno)); - return 0; - } - - if (nprocs > UINT16_MAX) { - SCLogDebug("It seems that the system support more that %"PRIu16" CPUs. You " - "can modify util-cpu.{c,h} to use uint32_t to support it", UINT16_MAX); - return UINT16_MAX; - } - - return (uint16_t)nprocs; -#else - SCLogError("Couldn't retrieve the maximum number of cpus allowed by " - "the system, synconf macro unavailable"); - return 0; -#endif -} - -/** - * \brief Print a summary of CPUs detected (configured and online) - */ -void UtilCpuPrintSummary(void) -{ - uint16_t cpus_conf = UtilCpuGetNumProcessorsConfigured(); - uint16_t cpus_online = UtilCpuGetNumProcessorsOnline(); - - SCLogDebug("CPUs Summary: "); - if (cpus_conf > 0) - SCLogDebug("CPUs configured: %"PRIu16, cpus_conf); - if (cpus_online > 0) - SCLogInfo("CPUs/cores online: %"PRIu16, cpus_online); - if (cpus_online == 0 && cpus_conf == 0) - SCLogInfo("Couldn't retrieve any information of CPU's, please, send your operating " - "system info and check util-cpu.{c,h}"); -} - -/** - * Get the current number of ticks from the CPU. - * - * \todo We'll have to deal with removing ticks from the extra cpuids in between - * 2 calls. - */ -uint64_t UtilCpuGetTicks(void) -{ - uint64_t val; -#if defined(__GNUC__) && (defined(__x86_64) || defined(_X86_64_) || defined(ia_64) || defined(__i386__)) -#if defined(__x86_64) || defined(_X86_64_) || defined(ia_64) - __asm__ __volatile__ ( - "xorl %%eax,%%eax\n\t" - "cpuid\n\t" - ::: "%rax", "%rbx", "%rcx", "%rdx"); -#else - __asm__ __volatile__ ( - "xorl %%eax,%%eax\n\t" - "pushl %%ebx\n\t" - "cpuid\n\t" - "popl %%ebx\n\t" - ::: "%eax", "%ecx", "%edx"); -#endif - uint32_t a, d; - __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d)); - val = ((uint64_t)a) | (((uint64_t)d) << 32); -#if defined(__x86_64) || defined(_X86_64_) || defined(ia_64) - __asm__ __volatile__ ( - "xorl %%eax,%%eax\n\t" - "cpuid\n\t" - ::: "%rax", "%rbx", "%rcx", "%rdx"); -#else - __asm__ __volatile__ ( - "xorl %%eax,%%eax\n\t" - "pushl %%ebx\n\t" - "cpuid\n\t" - "popl %%ebx\n\t" - ::: "%eax", "%ecx", "%edx"); -#endif - -#else /* #if defined(__GNU__) */ -//#warning Using inferior version of UtilCpuGetTicks - struct timeval now; - gettimeofday(&now, NULL); - val = (now.tv_sec * 1000000) + now.tv_usec; -#endif - return val; -} diff --git a/src/util-daemon.c b/src/util-daemon.c deleted file mode 100644 index 909218910105..000000000000 --- a/src/util-daemon.c +++ /dev/null @@ -1,193 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gerardo Iglesias Galvan - * - * Daemonization process - */ - -#include "suricata.h" -#include "suricata-common.h" -#include "runmodes.h" -#include "util-daemon.h" -#include "util-debug.h" -#include "conf.h" - -#ifndef OS_WIN32 - -#include -#include -#include - -static volatile sig_atomic_t sigflag = 0; - -/** - * \brief Signal handler used to take the parent process out of stand-by - */ -static void SignalHandlerSigusr1 (int signo) -{ - sigflag = 1; -} - -/** - * \brief Tell the parent process the child is ready - * - * \param pid pid of the parent process to signal - */ -static void TellWaitingParent (pid_t pid) -{ - kill(pid, SIGUSR1); -} - -/** - * \brief Set the parent on stand-by until the child is ready - * - * \param pid pid of the child process to wait - */ -static void WaitForChild (pid_t pid) -{ - int status; - SCLogDebug("Daemon: Parent waiting for child to be ready..."); - /* Wait until child signals is ready */ - while (sigflag == 0) { - if (waitpid(pid, &status, WNOHANG)) { - /* Check if the child is still there, otherwise the parent should exit */ - if (WIFEXITED(status) || WIFSIGNALED(status)) { - FatalError("Child died unexpectedly"); - } - } - /* sigsuspend(); */ - sleep(1); - } -} - -/** - * \brief Close stdin, stdout, stderr.Redirect logging info to syslog - * - */ -static void SetupLogging (void) -{ - /* Redirect stdin, stdout, stderr to /dev/null */ - int fd = open("/dev/null", O_RDWR); - if (fd < 0) - return; - (void)dup2(fd, 0); - (void)dup2(fd, 1); - (void)dup2(fd, 2); - close(fd); -} - -/** - * \brief Daemonize the process - * - */ -void Daemonize (void) -{ - pid_t pid, sid; - - /* Register the signal handler */ - signal(SIGUSR1, SignalHandlerSigusr1); - - /** \todo We should check if we allow more than 1 instance - to run simultaneously. Maybe change the behaviour - through conf file */ - - /* Creates a new process */ -#if defined(OS_DARWIN) && defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - pid = fork(); -#if defined(OS_DARWIN) && defined(__clang__) -#pragma clang diagnostic pop -#endif - - if (pid < 0) { - /* Fork error */ - FatalError("Error forking the process"); - } else if (pid == 0) { - /* Child continues here */ - const char *daemondir; - - sid = setsid(); - if (sid < 0) { - FatalError("Error creating new session"); - } - - if (ConfGet("daemon-directory", &daemondir) == 1) { - if ((chdir(daemondir)) < 0) { - FatalError("Error changing to working directory"); - } - } -#ifndef OS_WIN32 - else { - if (chdir("/") < 0) { - SCLogError("Error changing to working directory '/'"); - } - } -#endif - - SetupLogging(); - - /* Child is ready, tell its parent */ - TellWaitingParent(getppid()); - - /* Daemon is up and running */ - SCLogDebug("Daemon is running"); - return; - } - /* Parent continues here, waiting for child to be ready */ - SCLogDebug("Parent is waiting for child to be ready"); - WaitForChild(pid); - - /* Parent exits */ - SCLogDebug("Child is ready, parent exiting"); - exit(EXIT_SUCCESS); - -} - -#endif /* ifndef OS_WIN32 */ - -/** - * \brief Check for a valid combination daemon/mode - * - * \param daemon daemon on or off - * \param mode selected mode - * - * \retval 1 valid combination - * \retval 0 invalid combination - */ -int CheckValidDaemonModes (int daemon, int mode) -{ - if (daemon) { - switch (mode) { - case RUNMODE_PCAP_FILE: - SCLogError("ERROR: pcap offline mode cannot run as daemon"); - return 0; - case RUNMODE_UNITTEST: - SCLogError("ERROR: unittests cannot run as daemon"); - return 0; - default: - SCLogDebug("Allowed mode"); - break; - } - } - return 1; -} diff --git a/src/util-daemon.h b/src/util-daemon.h deleted file mode 100644 index 424d7093eae8..000000000000 --- a/src/util-daemon.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gerardo Iglesias Galvan - */ - -#ifndef __UTIL_DAEMON_H__ -#define __UTIL_DAEMON_H__ - -#ifdef OS_WIN32 -#define Daemonize() -#else -void Daemonize (void); -#endif - -int CheckValidDaemonModes (int, int); - -#endif /* __UTIL_DAEMON_H__ */ diff --git a/src/util-datalink.c b/src/util-datalink.c deleted file mode 100644 index ad34a2b3a759..000000000000 --- a/src/util-datalink.c +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "util-datalink.h" -#include "decode.h" - -int g_datalink_value = LINKTYPE_NULL; -int g_datalink_is_multiple = 0; - -void DatalinkSetGlobalType(int datalink) -{ - if (g_datalink_value != LINKTYPE_NULL) { - if (datalink != g_datalink_value) { - g_datalink_is_multiple = 1; - } - } else { - g_datalink_value = datalink; - } -} - -inline int DatalinkGetGlobalType(void) -{ - return g_datalink_value; -} - -bool DatalinkHasMultipleValues(void) -{ - return g_datalink_is_multiple == 1; -} diff --git a/src/util-debug-filters.c b/src/util-debug-filters.c deleted file mode 100644 index fd66375cb9fc..000000000000 --- a/src/util-debug-filters.c +++ /dev/null @@ -1,998 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Debug filter utility functions - */ - -#include "suricata-common.h" -#include "util-debug-filters.h" -#include "threads.h" -#include "util-debug.h" - -/* both of these are defined in util-debug.c */ -extern int sc_log_module_initialized; -extern int sc_log_module_cleaned; - -/* used to indicate if any FG filters are registered */ -int sc_log_fg_filters_present = 0; - -/* used to indicate if any FD filters are registered */ -int sc_log_fd_filters_present = 0; - -/** - * \brief Holds the fine-grained filters - */ -SCLogFGFilterFile *sc_log_fg_filters[SC_LOG_FILTER_MAX] = { NULL, NULL }; - -/** - * \brief Mutex for accessing the fine-grained filters sc_log_fg_filters - */ -static SCMutex sc_log_fg_filters_m[SC_LOG_FILTER_MAX] = { SCMUTEX_INITIALIZER, - SCMUTEX_INITIALIZER }; - -/** - * \brief Holds the function-dependent filters - */ -static SCLogFDFilter *sc_log_fd_filters = NULL; - -/** - * \brief Mutex for accessing the function-dependent filters sc_log_fd_filters - */ -static SCMutex sc_log_fd_filters_m = SCMUTEX_INITIALIZER; - -/** - * \brief Holds the thread_list required by function-dependent filters - */ -static SCLogFDFilterThreadList *sc_log_fd_filters_tl = NULL; - -/** - * \brief Mutex for accessing the FD thread_list sc_log_fd_filters_tl - */ -static SCMutex sc_log_fd_filters_tl_m = SCMUTEX_INITIALIZER; - -/** - * \brief Helper function used internally to add a FG filter - * - * \param file File_name of the filter - * \param function Function_name of the filter - * \param line Line number of the filter - * \param listtype The filter listtype. Can be either a blacklist or whitelist - * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) - * - * \retval 0 on successfully adding the filter; - * \retval -1 on failure - */ -static int SCLogAddFGFilter(const char *file, const char *function, - int line, int listtype) -{ - SCLogFGFilterFile *fgf_file = NULL; - SCLogFGFilterFile *prev_fgf_file = NULL; - - SCLogFGFilterFunc *fgf_func = NULL; - SCLogFGFilterFunc *prev_fgf_func = NULL; - - SCLogFGFilterLine *fgf_line = NULL; - SCLogFGFilterLine *prev_fgf_line = NULL; - - int found = 0; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return -1 ; - } - - if (file == NULL && function == NULL && line < 0) { - printf("Error: Invalid arguments supplied to SCLogAddFGFilter\n"); - return -1; - } - - SCMutex *m = &sc_log_fg_filters_m[listtype]; - - SCMutexLock(m); - - fgf_file = sc_log_fg_filters[listtype]; - - prev_fgf_file = fgf_file; - while (fgf_file != NULL) { - prev_fgf_file = fgf_file; - if (file == NULL && fgf_file->file == NULL) - found = 1; - else if (file != NULL && fgf_file->file != NULL) - found = (strcmp(file, fgf_file->file) == 0); - else - found = 0; - - if (found == 1) - break; - - fgf_file = fgf_file->next; - } - - if (found == 0) { - SCLogAddToFGFFileList(prev_fgf_file, file, function, line, listtype); - goto done; - } - - found = 0; - fgf_func = fgf_file->func; - prev_fgf_func = fgf_func; - while (fgf_func != NULL) { - prev_fgf_func = fgf_func; - if (function == NULL && fgf_func->func == NULL) - found = 1; - else if (function != NULL && fgf_func->func != NULL) - found = (strcmp(function, fgf_func->func) == 0); - else - found = 0; - - if (found == 1) - break; - - fgf_func = fgf_func->next; - } - - if (found == 0) { - SCLogAddToFGFFuncList(fgf_file, prev_fgf_func, function, line); - goto done; - } - - found = 0; - fgf_line = fgf_func->line; - prev_fgf_line = fgf_line; - while(fgf_line != NULL) { - prev_fgf_line = fgf_line; - if (line == fgf_line->line) { - found = 1; - break; - } - - fgf_line = fgf_line->next; - } - - if (found == 0) { - SCLogAddToFGFLineList(fgf_func, prev_fgf_line, line); - goto done; - } - - done: - SCMutexUnlock(&sc_log_fg_filters_m[listtype]); - sc_log_fg_filters_present = 1; - - return 0; -} - -/** - * \brief Internal function used to check for matches against registered FG - * filters. Checks if there is a match for the incoming log_message with - * any of the FG filters. Based on whether the filter type is whitelist - * or blacklist, the function allows the message to be logged or not. - * - * \param file File_name from where the log_message originated - * \param function Function_name from where the log_message originated - * \param line Line number from where the log_message originated - * \param listtype The filter listtype. Can be either a blacklist or whitelist - * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) - * - * \retval 1 if there is a match - * \retval 0 on no match - * \retval -1 on failure - */ -static int SCLogMatchFGFilter(const char *file, const char *function, int line, - int listtype) -{ - SCLogFGFilterFile *fgf_file = NULL; - SCLogFGFilterFunc *fgf_func = NULL; - SCLogFGFilterLine *fgf_line = NULL; - int match = 1; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return -1; - } - - SCMutexLock(&sc_log_fg_filters_m[listtype]); - - fgf_file = sc_log_fg_filters[listtype]; - - if (fgf_file == NULL) { - SCMutexUnlock(&sc_log_fg_filters_m[listtype]); - return 1; - } - - while(fgf_file != NULL) { - match = 1; - - match &= (fgf_file->file != NULL)? !strcmp(file, fgf_file->file): 1; - - if (match == 0) { - fgf_file = fgf_file->next; - continue; - } - - fgf_func = fgf_file->func; - while (fgf_func != NULL) { - match = 1; - - match &= (fgf_func->func != NULL)? !strcmp(function, fgf_func->func): 1; - - if (match == 0) { - fgf_func = fgf_func->next; - continue; - } - - fgf_line = fgf_func->line; - while (fgf_line != NULL) { - match = 1; - - match &= (fgf_line->line != -1)? (line == fgf_line->line): 1; - - if (match == 1) - break; - - fgf_line = fgf_line->next; - } - - if (match == 1) - break; - - fgf_func = fgf_func->next; - } - - if (match == 1) { - SCMutexUnlock(&sc_log_fg_filters_m[listtype]); - if (listtype == SC_LOG_FILTER_WL) - return 1; - else - return 0; - } - - fgf_file = fgf_file->next; - } - - SCMutexUnlock(&sc_log_fg_filters_m[listtype]); - - if (listtype == SC_LOG_FILTER_WL) - return 0; - else - return 1; -} - -/** - * \brief Checks if there is a match for the incoming log_message with any - * of the FG filters. If there is a match, it allows the message - * to be logged, else it rejects that message. - * - * \param file File_name from where the log_message originated - * \param function Function_name from where the log_message originated - * \param line Line number from where the log_message originated - * - * \retval 1 if there is a match - * \retval 0 on no match - * \retval -1 on failure - */ -int SCLogMatchFGFilterWL(const char *file, const char *function, int line) -{ - return SCLogMatchFGFilter(file, function, line, SC_LOG_FILTER_WL); -} - -/** - * \brief Checks if there is a match for the incoming log_message with any - * of the FG filters. If there is a match it rejects the logging - * for that messages, else it allows that message to be logged - * - * \param file File_name from where the log_message originated - * \param function Function_name from where the log_message originated - * \param line Line number from where the log_message originated - * - * \retval 1 if there is a match - * \retval 0 on no match - * \retval -1 on failure - */ -int SCLogMatchFGFilterBL(const char *file, const char *function, int line) -{ - return SCLogMatchFGFilter(file, function, line, SC_LOG_FILTER_BL); -} - -/** - * \brief Adds a Whitelist(WL) fine-grained(FG) filter. A FG filter WL filter - * allows messages that match this filter, to be logged, while the filter - * is defined using a file_name, function_name and line_number. - * - * If a particular parameter in the fg-filter(file, function and line), - * shouldn't be considered while logging the message, one can supply - * NULL for the file_name or function_name and a negative line_no. - * - * \param file File_name of the filter - * \param function Function_name of the filter - * \param line Line number of the filter - * - * \retval 0 on successfully adding the filter; - * \retval -1 on failure - */ -int SCLogAddFGFilterWL(const char *file, const char *function, int line) -{ - return SCLogAddFGFilter(file, function, line, SC_LOG_FILTER_WL); -} - -/** - * \brief Adds a Blacklist(BL) fine-grained(FG) filter. A FG filter BL filter - * allows messages that don't match this filter, to be logged, while the - * filter is defined using a file_name, function_name and line_number - * - * If a particular parameter in the fg-filter(file, function and line), - * shouldn't be considered while logging the message, one can supply - * NULL for the file_name or function_name and a negative line_no. - * - * \param file File_name of the filter - * \param function Function_name of the filter - * \param line Line number of the filter - * - * \retval 0 on successfully adding the filter - * \retval -1 on failure - */ -int SCLogAddFGFilterBL(const char *file, const char *function, int line) -{ - return SCLogAddFGFilter(file, function, line, SC_LOG_FILTER_BL); -} - -void SCLogReleaseFGFilters(void) -{ - SCLogFGFilterFile *fgf_file = NULL; - SCLogFGFilterFunc *fgf_func = NULL; - SCLogFGFilterLine *fgf_line = NULL; - - void *temp = NULL; - - int i = 0; - - for (i = 0; i < SC_LOG_FILTER_MAX; i++) { - SCMutexLock(&sc_log_fg_filters_m[i]); - - fgf_file = sc_log_fg_filters[i]; - while (fgf_file != NULL) { - - fgf_func = fgf_file->func; - while (fgf_func != NULL) { - - fgf_line = fgf_func->line; - while(fgf_line != NULL) { - temp = fgf_line; - fgf_line = fgf_line->next; - SCFree(temp); - } - - if (fgf_func->func != NULL) - SCFree(fgf_func->func); - temp = fgf_func; - fgf_func = fgf_func->next; - SCFree(temp); - } - - if (fgf_file->file != NULL) - SCFree(fgf_file->file); - temp = fgf_file; - fgf_file = fgf_file->next; - SCFree(temp); - } - - SCMutexUnlock(&sc_log_fg_filters_m[i]); - sc_log_fg_filters[i] = NULL; - } - - return; -} - -/** - * \brief Prints the FG filters(both WL and BL). Used for debugging purposes. - * - * \retval count The no of FG filters - */ -int SCLogPrintFGFilters(void) -{ - SCLogFGFilterFile *fgf_file = NULL; - SCLogFGFilterFunc *fgf_func = NULL; - SCLogFGFilterLine *fgf_line = NULL; - - int count = 0; - int i = 0; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return 0; - } - -#ifdef DEBUG - printf("Fine grained filters:\n"); -#endif - - for (i = 0; i < SC_LOG_FILTER_MAX; i++) { - SCMutexLock(&sc_log_fg_filters_m[i]); - - fgf_file = sc_log_fg_filters[i]; - while (fgf_file != NULL) { - - fgf_func = fgf_file->func; - while (fgf_func != NULL) { - - fgf_line = fgf_func->line; - while(fgf_line != NULL) { -#ifdef DEBUG - printf("%s - ", fgf_file->file); - printf("%s - ", fgf_func->func); - printf("%d\n", fgf_line->line); -#endif - - count++; - - fgf_line = fgf_line->next; - } - - fgf_func = fgf_func->next; - } - - fgf_file = fgf_file->next; - } - SCMutexUnlock(&sc_log_fg_filters_m[i]); - } - - return count; -} - - - -/* --------------------------------------------------|-------------------------- - * -------------------------- Code for the FD Filter |-------------------------- - * --------------------------------------------------V-------------------------- - */ - -/** - * \brief Checks if there is a match for the incoming log_message with any - * of the FD filters - * - * \param function Function_name from where the log_message originated - * - * \retval 1 if there is a match - * \retval 0 on no match; - */ -int SCLogMatchFDFilter(const char *function) -{ -#ifndef DEBUG - return 1; -#else - SCLogFDFilterThreadList *thread_list = NULL; - - pthread_t self = pthread_self(); - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return 0; - } - - SCMutexLock(&sc_log_fd_filters_tl_m); - - if (sc_log_fd_filters_tl == NULL) { - SCMutexUnlock(&sc_log_fd_filters_tl_m); - if (sc_log_fd_filters != NULL) - return 0; - return 1; - } - - thread_list = sc_log_fd_filters_tl; - while (thread_list != NULL) { - if (pthread_equal(self, thread_list->t)) { - if (thread_list->entered > 0) { - SCMutexUnlock(&sc_log_fd_filters_tl_m); - return 1; - } - SCMutexUnlock(&sc_log_fd_filters_tl_m); - return 0; - } - - thread_list = thread_list->next; - } - - SCMutexUnlock(&sc_log_fd_filters_tl_m); - - return 0; -#endif -} - -/** - * \brief Updates a FD filter, based on whether the function that calls this - * function, is registered as a FD filter or not. This is called by - * a function only on its entry - * - * \param function Function_name from where the log_message originated - * - * \retval 1 Since it is a hack to get things working inside the macros - */ -int SCLogCheckFDFilterEntry(const char *function) -{ - SCLogFDFilter *curr = NULL; - - SCLogFDFilterThreadList *thread_list = NULL; - SCLogFDFilterThreadList *thread_list_temp = NULL; - - //pid_t self = syscall(SYS_gettid); - pthread_t self = pthread_self(); - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return 0; - } - - SCMutexLock(&sc_log_fd_filters_m); - - curr = sc_log_fd_filters; - - while (curr != NULL) { - if (strcmp(function, curr->func) == 0) - break; - - curr = curr->next; - } - - if (curr == NULL) { - SCMutexUnlock(&sc_log_fd_filters_m); - return 1; - } - - SCMutexUnlock(&sc_log_fd_filters_m); - - SCMutexLock(&sc_log_fd_filters_tl_m); - - thread_list = sc_log_fd_filters_tl; - while (thread_list != NULL) { - if (pthread_equal(self, thread_list->t)) - break; - - thread_list = thread_list->next; - } - - if (thread_list != NULL) { - thread_list->entered++; - SCMutexUnlock(&sc_log_fd_filters_tl_m); - return 1; - } - - if ((thread_list_temp = SCCalloc(1, sizeof(SCLogFDFilterThreadList))) == NULL) { - SCMutexUnlock(&sc_log_fd_filters_tl_m); - return 0; - } - - thread_list_temp->t = self; - thread_list_temp->entered++; - - sc_log_fd_filters_tl = thread_list_temp; - - SCMutexUnlock(&sc_log_fd_filters_tl_m); - - return 1; -} - -/** - * \brief Updates a FD filter, based on whether the function that calls this - * function, is registered as a FD filter or not. This is called by - * a function only before its exit. - * - * \param function Function_name from where the log_message originated - * - */ -void SCLogCheckFDFilterExit(const char *function) -{ - SCLogFDFilter *curr = NULL; - - SCLogFDFilterThreadList *thread_list = NULL; - - //pid_t self = syscall(SYS_gettid); - pthread_t self = pthread_self(); - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return; - } - - SCMutexLock(&sc_log_fd_filters_m); - - curr = sc_log_fd_filters; - - while (curr != NULL) { - if (strcmp(function, curr->func) == 0) - break; - - curr = curr->next; - } - - if (curr == NULL) { - SCMutexUnlock(&sc_log_fd_filters_m); - return; - } - - SCMutexUnlock(&sc_log_fd_filters_m); - - SCMutexLock(&sc_log_fd_filters_tl_m); - - thread_list = sc_log_fd_filters_tl; - while (thread_list != NULL) { - if (pthread_equal(self, thread_list->t)) - break; - - thread_list = thread_list->next; - } - - SCMutexUnlock(&sc_log_fd_filters_tl_m); - - if (thread_list != NULL) - thread_list->entered--; - - return; -} - -/** - * \brief Adds a Function-Dependent(FD) filter - * - * \param Name of the function for which a FD filter has to be registered - * - * \retval 0 on success - * \retval -1 on failure - */ -int SCLogAddFDFilter(const char *function) -{ - SCLogFDFilter *curr = NULL; - SCLogFDFilter *prev = NULL; - SCLogFDFilter *temp = NULL; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return -1; - } - - if (function == NULL) { - printf("Invalid argument supplied to SCLogAddFDFilter\n"); - return -1; - } - - SCMutexLock(&sc_log_fd_filters_m); - - curr = sc_log_fd_filters; - while (curr != NULL) { - prev = curr; - - if (strcmp(function, curr->func) == 0) { - - SCMutexUnlock(&sc_log_fd_filters_m); - return 0; - } - - curr = curr->next; - } - - if ((temp = SCCalloc(1, sizeof(SCLogFDFilter))) == NULL) { - printf("Error Allocating memory (SCCalloc)\n"); - exit(EXIT_FAILURE); - } - - if ( (temp->func = SCStrdup(function)) == NULL) { - printf("Error Allocating memory (SCStrdup)\n"); - exit(EXIT_FAILURE); - } - - if (sc_log_fd_filters == NULL) - sc_log_fd_filters = temp; - /* clang thinks prev can be NULL, but it can't be unless - * sc_log_fd_filters is also NULL which is handled here. - * Doing this "fix" to shut clang up. */ - else if (prev != NULL) - prev->next = temp; - - SCMutexUnlock(&sc_log_fd_filters_m); - sc_log_fd_filters_present = 1; - - return 0; -} - -/** - * \brief Releases all the FD filters added to the logging module - */ -void SCLogReleaseFDFilters(void) -{ - SCLogFDFilter *fdf = NULL; - SCLogFDFilter *temp = NULL; - - SCMutexLock(&sc_log_fd_filters_m); - - fdf = sc_log_fd_filters; - while (fdf != NULL) { - temp = fdf; - fdf = fdf->next; - SCLogReleaseFDFilter(temp); - } - - sc_log_fd_filters = NULL; - - SCMutexUnlock( &sc_log_fd_filters_m ); - - return; -} - -/** - * \brief Removes a Function-Dependent(FD) filter - * - * \param Name of the function for which a FD filter has to be unregistered - * - * \retval 0 on success(the filter was removed or the filter was not present) - * \retval -1 on failure/error - */ -int SCLogRemoveFDFilter(const char *function) -{ - SCLogFDFilter *curr = NULL; - SCLogFDFilter *prev = NULL; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return -1 ; - } - - if (function == NULL) { - printf("Invalid argument(s) supplied to SCLogRemoveFDFilter\n"); - return -1; - } - - SCMutexLock(&sc_log_fd_filters_m); - - if (sc_log_fd_filters == NULL) { - SCMutexUnlock(&sc_log_fd_filters_m); - return 0; - } - - curr = sc_log_fd_filters; - prev = curr; - while (curr != NULL) { - if (strcmp(function, curr->func) == 0) - break; - - prev = curr; - curr = curr->next; - } - - if (curr == NULL) { - - SCMutexUnlock(&sc_log_fd_filters_m); - - return 0; - } - - if (sc_log_fd_filters == curr) - sc_log_fd_filters = curr->next; - else - prev->next = curr->next; - - SCLogReleaseFDFilter(curr); - - SCMutexUnlock(&sc_log_fd_filters_m); - - if (sc_log_fd_filters == NULL) - sc_log_fd_filters_present = 0; - - return 0; -} - -/** - * \brief Prints the FG filters(both WL and BL). Used for debugging purposes. - * - * \retval count The no of FG filters - */ -int SCLogPrintFDFilters(void) -{ - SCLogFDFilter *fdf = NULL; - int count = 0; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return 0; - } - -#ifdef DEBUG - printf("FD filters:\n"); -#endif - - SCMutexLock(&sc_log_fd_filters_m); - - fdf = sc_log_fd_filters; - while (fdf != NULL) { -#ifdef DEBUG - printf("%s \n", fdf->func); -#endif - fdf = fdf->next; - count++; - } - - SCMutexUnlock(&sc_log_fd_filters_m); - - return count; -} - -/** - * \brief Helper function used internally to add a FG filter. This function is - * called when the file component of the incoming filter has no entry - * in the filter list. - * - * \param fgf_file The file component(basically the position in the list) from - * the filter list, after which the new filter has to be added - * \param file File_name of the filter - * \param function Function_name of the filter - * \param line Line number of the filter - * \param listtype The filter listtype. Can be either a blacklist or whitelist - * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) - */ -void SCLogAddToFGFFileList(SCLogFGFilterFile *fgf_file, - const char *file, - const char *function, int line, - int listtype) -{ - SCLogFGFilterFile *fgf_file_temp = NULL; - SCLogFGFilterFunc *fgf_func_temp = NULL; - SCLogFGFilterLine *fgf_line_temp = NULL; - - if ((fgf_file_temp = SCCalloc(1, sizeof(SCLogFGFilterFile))) == NULL) { - FatalError("Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); - } - - if ( file != NULL && (fgf_file_temp->file = SCStrdup(file)) == NULL) { - printf("Error Allocating memory\n"); - exit(EXIT_FAILURE); - } - - if ((fgf_func_temp = SCCalloc(1, sizeof(SCLogFGFilterFunc))) == NULL) { - FatalError("Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); - } - - if ( function != NULL && (fgf_func_temp->func = SCStrdup(function)) == NULL) { - printf("Error Allocating memory\n"); - exit(EXIT_FAILURE); - } - - if ((fgf_line_temp = SCCalloc(1, sizeof(SCLogFGFilterLine))) == NULL) { - FatalError("Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); - } - - fgf_line_temp->line = line; - - /* add to the lists */ - fgf_func_temp->line = fgf_line_temp; - - fgf_file_temp->func = fgf_func_temp; - - if (fgf_file == NULL) - sc_log_fg_filters[listtype] = fgf_file_temp; - else - fgf_file->next = fgf_file_temp; - - return; -} - -/** - * \brief Helper function used internally to add a FG filter. This function is - * called when the file component of the incoming filter has an entry - * in the filter list, but the function component doesn't have an entry - * for the corresponding file component - * - * \param fgf_file The file component from the filter list to which the new - * filter has to be added - * \param fgf_func The function component(basically the position in the list), - * from the filter list, after which the new filter has to be - * added - * \param function Function_name of the filter - * \param line Line number of the filter - */ -void SCLogAddToFGFFuncList(SCLogFGFilterFile *fgf_file, - SCLogFGFilterFunc *fgf_func, - const char *function, int line) -{ - SCLogFGFilterFunc *fgf_func_temp = NULL; - SCLogFGFilterLine *fgf_line_temp = NULL; - - if ((fgf_func_temp = SCCalloc(1, sizeof(SCLogFGFilterFunc))) == NULL) { - FatalError("Fatal error encountered in SCLogAddToFGFFuncList. Exiting..."); - } - - if ( function != NULL && (fgf_func_temp->func = SCStrdup(function)) == NULL) { - printf("Error Allocating memory\n"); - exit(EXIT_FAILURE); - } - - if ((fgf_line_temp = SCCalloc(1, sizeof(SCLogFGFilterLine))) == NULL) { - FatalError("Fatal error encountered in SCLogAddToFGFFuncList. Exiting..."); - } - - fgf_line_temp->line = line; - - /* add to the lists */ - fgf_func_temp->line = fgf_line_temp; - - if (fgf_func == NULL) - fgf_file->func = fgf_func_temp; - else - fgf_func->next = fgf_func_temp; - - return; -} - -/** - * \brief Helper function used internally to add a FG filter. This function is - * called when the file and function components of the incoming filter - * have an entry in the filter list, but the line component doesn't have - * an entry for the corresponding function component - * - * \param fgf_func The function component from the filter list to which the new - * filter has to be added - * \param fgf_line The function component(basically the position in the list), - * from the filter list, after which the new filter has to be - * added - * \param line Line number of the filter - */ -void SCLogAddToFGFLineList(SCLogFGFilterFunc *fgf_func, - SCLogFGFilterLine *fgf_line, - int line) -{ - SCLogFGFilterLine *fgf_line_temp = NULL; - - if ((fgf_line_temp = SCCalloc(1, sizeof(SCLogFGFilterLine))) == NULL) { - FatalError("Fatal error encountered in SCLogAddToFGFLineList. Exiting..."); - } - - fgf_line_temp->line = line; - - /* add to the lists */ - if (fgf_line == NULL) - fgf_func->line = fgf_line_temp; - else - fgf_line->next = fgf_line_temp; - - return; -} - -/** - * \brief Releases the memory alloted to a FD filter - * - * \param Pointer to the FD filter that has to be freed - */ -void SCLogReleaseFDFilter(SCLogFDFilter *fdf) -{ - if (fdf != NULL) { - if (fdf->func != NULL) - SCFree(fdf->func); - SCFree(fdf); - } - - return; -} - diff --git a/src/util-debug-filters.h b/src/util-debug-filters.h deleted file mode 100644 index 26c9ec9c88a4..000000000000 --- a/src/util-debug-filters.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __DEBUG_FILTERS_H__ -#define __DEBUG_FILTERS_H__ - -// pthread_t -#include "threads.h" - -/** - * \brief Enum that holds the different kinds of filters available - */ -enum { - SC_LOG_FILTER_BL = 0, - SC_LOG_FILTER_WL = 1, - SC_LOG_FILTER_MAX = 2, -}; - -/** - * \brief Structure used to hold the line_no details of a FG filter - */ -typedef struct SCLogFGFilterLine_ { - int line; - - struct SCLogFGFilterLine_ *next; -} SCLogFGFilterLine; - -/** - * \brief structure used to hold the function details of a FG filter - */ -typedef struct SCLogFGFilterFunc_ { - char *func; - SCLogFGFilterLine *line; - - struct SCLogFGFilterFunc_ *next; -} SCLogFGFilterFunc; - -/** - * \brief Structure used to hold FG filters. Encapsulates filename details, - * func details, which inturn encapsulates the line_no details - */ -typedef struct SCLogFGFilterFile_ { - char *file; - SCLogFGFilterFunc *func; - - struct SCLogFGFilterFile_ *next; -} SCLogFGFilterFile; - -/** - * \brief Structure used to hold the thread_list used by FD filters - */ -typedef struct SCLogFDFilterThreadList_ { - int entered; - pthread_t t; -// pid_t t; - - struct SCLogFDFilterThreadList_ *next; -} SCLogFDFilterThreadList; - -/** - * \brief Structure that holds the FD filters - */ -typedef struct SCLogFDFilter_ { - char *func; - - struct SCLogFDFilter_ *next; -} SCLogFDFilter; - - -extern int sc_log_fg_filters_present; - -extern int sc_log_fd_filters_present; - - -int SCLogAddFGFilterWL(const char *, const char *, int); - -int SCLogAddFGFilterBL(const char *, const char *, int); - -int SCLogMatchFGFilterBL(const char *, const char *, int); - -int SCLogMatchFGFilterWL(const char *, const char *, int); - -void SCLogReleaseFGFilters(void); - -int SCLogAddFDFilter(const char *); - -int SCLogPrintFDFilters(void); - -void SCLogReleaseFDFilters(void); - -int SCLogRemoveFDFilter(const char *); - -int SCLogCheckFDFilterEntry(const char *); - -void SCLogCheckFDFilterExit(const char *); - -int SCLogMatchFDFilter(const char *); - -int SCLogPrintFGFilters(void); - -void SCLogAddToFGFFileList(SCLogFGFilterFile *, - const char *, - const char *, int, - int); - -void SCLogAddToFGFFuncList(SCLogFGFilterFile *, - SCLogFGFilterFunc *, - const char *, int); - -void SCLogAddToFGFLineList(SCLogFGFilterFunc *, - SCLogFGFilterLine *, - int); - -void SCLogReleaseFDFilter(SCLogFDFilter *); -#endif /* __DEBUG_FILTERS_H__ */ diff --git a/src/util-debug.c b/src/util-debug.c deleted file mode 100644 index c62a0104dda3..000000000000 --- a/src/util-debug.c +++ /dev/null @@ -1,1835 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Debug utility functions - */ - -#include "suricata-common.h" -#include "util-debug.h" - -#include "output.h" - -#include "suricata.h" - -#include "util-conf.h" -#include "util-enum.h" -#include "util-path.h" -#include "util-syslog.h" -#include "util-time.h" - -// clang-format off -/* holds the string-enum mapping for the enums held in the table SCLogLevel */ -SCEnumCharMap sc_log_level_map[] = { - { "Not set", SC_LOG_NOTSET }, - { "None", SC_LOG_NONE }, - { "Error", SC_LOG_ERROR }, - { "Warning", SC_LOG_WARNING }, - { "Notice", SC_LOG_NOTICE }, - { "Info", SC_LOG_INFO }, - { "Perf", SC_LOG_PERF }, - { "Config", SC_LOG_CONFIG }, - { "Debug", SC_LOG_DEBUG }, - { NULL, -1 } -}; - -SCEnumCharMap sc_log_slevel_map[] = { - { "Not set", SC_LOG_NOTSET }, - { "None", SC_LOG_NONE }, - { "E", SC_LOG_ERROR }, - { "W", SC_LOG_WARNING }, - { "i", SC_LOG_NOTICE }, - { "i", SC_LOG_INFO }, - { "i", SC_LOG_PERF }, - { "i", SC_LOG_CONFIG }, - { "d", SC_LOG_DEBUG }, - { NULL, -1 } -}; - -/* holds the string-enum mapping for the enums held in the table SCLogOPIface */ -SCEnumCharMap sc_log_op_iface_map[ ] = { - { "Console", SC_LOG_OP_IFACE_CONSOLE }, - { "File", SC_LOG_OP_IFACE_FILE }, - { "Syslog", SC_LOG_OP_IFACE_SYSLOG }, - { NULL, -1 } -}; -// clang-format on - -#if defined (OS_WIN32) -/** - * \brief Used for synchronous output on WIN32 - */ -static SCMutex sc_log_stream_lock; -#endif /* OS_WIN32 */ - -/** - * \brief Transform the module name into display module name for logging - */ -static const char *SCTransformModule(const char *module_name, int *dn_len); - -/** - * \brief Holds the config state for the logging module - */ -static SCLogConfig *sc_log_config = NULL; - -/** - * \brief Returns the full path given a file and configured log dir - */ -static char *SCLogGetLogFilename(const char *); - -/** - * \brief Holds the global log level. Is the same as sc_log_config->log_level - */ -SCLogLevel sc_log_global_log_level; - -/** - * \brief Used to indicate whether the logging module has been init or not - */ -int sc_log_module_initialized = 0; - -/** - * \brief Used to indicate whether the logging module has been cleaned or not - */ -int sc_log_module_cleaned = 0; - -/** - * \brief Maps the SC logging level to the syslog logging level - * - * \param The SC logging level that has to be mapped to the syslog_log_level - * - * \retval syslog_log_level The mapped syslog_api_log_level, for the logging - * module api's internal log_level - */ -static inline int SCLogMapLogLevelToSyslogLevel(int log_level) -{ - int syslog_log_level = 0; - - switch (log_level) { - case SC_LOG_ERROR: - syslog_log_level = LOG_ERR; - break; - case SC_LOG_WARNING: - syslog_log_level = LOG_WARNING; - break; - case SC_LOG_NOTICE: - syslog_log_level = LOG_NOTICE; - break; - case SC_LOG_INFO: - syslog_log_level = LOG_INFO; - break; - case SC_LOG_CONFIG: - case SC_LOG_DEBUG: - case SC_LOG_PERF: - syslog_log_level = LOG_DEBUG; - break; - default: - syslog_log_level = LOG_EMERG; - break; - } - - return syslog_log_level; -} - -/** - * \brief Output function that logs a character string out to a file descriptor - * - * \param fd Pointer to the file descriptor - * \param msg Pointer to the character string that should be logged - */ -static inline void SCLogPrintToStream(FILE *fd, char *msg) -{ - /* Would only happen if the log file failed to re-open during rotation. */ - if (fd == NULL) { - return; - } - -#if defined (OS_WIN32) - SCMutexLock(&sc_log_stream_lock); -#endif /* OS_WIN32 */ - - if (fprintf(fd, "%s\n", msg) < 0) - printf("Error writing to stream using fprintf\n"); - - fflush(fd); - -#if defined (OS_WIN32) - SCMutexUnlock(&sc_log_stream_lock); -#endif /* OS_WIN32 */ - - return; -} - -/** - * \brief Output function that logs a character string through the syslog iface - * - * \param syslog_log_level Holds the syslog_log_level that the message should be - * logged as - * \param msg Pointer to the char string, that should be logged - * - * \todo syslog is thread-safe according to POSIX manual and glibc code, but we - * we will have to look into non POSIX compliant boxes like freeBSD - */ -static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) -{ - //static struct syslog_data data = SYSLOG_DATA_INIT; - //syslog_r(syslog_log_level, NULL, "%s", msg); - - syslog(syslog_log_level, "%s", msg); - - return; -} - -/** - */ -static int SCLogMessageJSON(SCTime_t tval, char *buffer, size_t buffer_size, SCLogLevel log_level, - const char *file, unsigned line, const char *function, const char *module, - const char *message) -{ - JsonBuilder *js = jb_new_object(); - if (unlikely(js == NULL)) - goto error; - - char timebuf[64]; - CreateIsoTimeString(tval, timebuf, sizeof(timebuf)); - jb_set_string(js, "timestamp", timebuf); - - const char *s = SCMapEnumValueToName(log_level, sc_log_level_map); - if (s != NULL) { - jb_set_string(js, "log_level", s); - } else { - JB_SET_STRING(js, "log_level", "INVALID"); - } - - JB_SET_STRING(js, "event_type", "engine"); - jb_open_object(js, "engine"); - - if (message) - jb_set_string(js, "message", message); - - if (t_thread_name[0] != '\0') { - jb_set_string(js, "thread_name", t_thread_name); - } - - if (module) { - /* Determine how much of module name to display */ - int dn_len = 0; - const char *dn_name; - dn_name = SCTransformModule(module, &dn_len); - jb_set_string(js, "module", dn_name); - } - - if (log_level >= SC_LOG_DEBUG) { - if (function) - jb_set_string(js, "function", function); - - if (file) - jb_set_string(js, "file", file); - - if (line > 0) - jb_set_uint(js, "line", line); - } - jb_close(js); // engine - - jb_close(js); - memcpy(buffer, jb_ptr(js), MIN(buffer_size, jb_len(js))); - - jb_free(js); - - return 0; - -error: - return -1; -} - -static const int transform_max_segs = 2; /* The maximum segment count to display */ -/* - * \brief Return a display name for the given module name for logging. - * - * The transformation is dependent upon the source code module names - * that use the dash character to separate incremental refinements of - * the subsystem. - * - * The transformation uses the local constant "transform_max_segs" to determine - * how many segments to display; the transformed name will never consist - * of more than this many segments. - * - * E.g., "detect-http-content-len" ==> "detect-http" when the max is 2 - * - * \param module_name The source code module name to be transformed. - * \param dn_len The number of characters in the display name to print. - * - * \retval Pointer to the display name - */ -static const char *SCTransformModule(const char *module_name, int *dn_len) -{ - /* - * special case for source code module names beginning with: - * Prefixes skipped - * tm-* - * util-* - * source-* - * No transformation - * app-layer-* - */ - if (strncmp("tm-", module_name, 3) == 0) { - *dn_len = strlen(module_name) - 3; - return module_name + 3; - } else if (strncmp("util-", module_name, 5) == 0) { - *dn_len = strlen(module_name) - 5; - return module_name + 5; - } else if (strncmp("source-pcap-file", module_name, 16) == 0) { - *dn_len = strlen("pcap"); - return "pcap"; - } else if (strncmp("source-", module_name, 7) == 0) { - *dn_len = strlen(module_name) - 7; - return module_name + 7; - } else if (strncmp("runmode-", module_name, 8) == 0) { - *dn_len = strlen(module_name) - 8; - return module_name + 8; - } else if (strncmp("app-layer-", module_name, 10) == 0) { - *dn_len = strlen(module_name); - return module_name; - } else if (strncmp("detect-engine", module_name, 13) == 0) { - *dn_len = strlen("detect"); - return "detect"; - } - - int seg_cnt = 0; - - char *last; - char *w = (char *)module_name; - while (w && (w = strchr(w, '-')) != NULL && seg_cnt < transform_max_segs) { - seg_cnt++; - last = w; - w++; /* skip past '-' */ - } - - if (seg_cnt < transform_max_segs) - *dn_len = strlen(module_name); - else - *dn_len = last - module_name; - - return module_name; -} - -/** - * \brief Adds the global log_format to the outgoing buffer - * - * \param log_level log_level of the message that has to be logged - * \param msg Buffer containing the outgoing message - * \param file File_name from where the message originated - * \param function Function_name from where the message originated - * \param line Line_no from where the messaged originated - * - * \retval 0 on success; else a negative value on error - */ -static SCError SCLogMessageGetBuffer(SCTime_t tval, bool color, SCLogOPType type, char *buffer, - size_t buffer_size, const char *log_format, const SCLogLevel log_level, const char *file, - const unsigned int line, const char *function, const char *module, const char *message) -{ - if (type == SC_LOG_OP_TYPE_JSON) - return SCLogMessageJSON( - tval, buffer, buffer_size, log_level, file, line, function, module, message); - - char *temp = buffer; - const char *s = NULL; - struct tm *tms = NULL; - - const char *redb = ""; - const char *red = ""; - const char *yellowb = ""; - const char *yellow = ""; - const char *green = ""; - const char *blue = ""; - const char *reset = ""; - if (color) { - redb = "\x1b[1;31m"; - red = "\x1b[31m"; - yellowb = "\x1b[1;33m"; - yellow = "\x1b[33m"; - green = "\x1b[32m"; - blue = "\x1b[34m"; - reset = "\x1b[0m"; - } - /* no of characters_written(cw) by snprintf */ - int cw = 0; - - BUG_ON(sc_log_module_initialized != 1); - - /* make a copy of the format string as it will be modified below */ - const int add_M = strstr(log_format, "%M") == NULL; - char local_format[strlen(log_format) + add_M * 2 + 1]; - strlcpy(local_format, log_format, sizeof(local_format)); - if (add_M) - strlcat(local_format, "%M", sizeof(local_format)); - char *temp_fmt = local_format; - char *substr = temp_fmt; - struct tm local_tm; - - while ((temp_fmt = strchr(temp_fmt, SC_LOG_FMT_PREFIX))) { - if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - return 0; - } - switch(temp_fmt[1]) { - case SC_LOG_FMT_TIME: - temp_fmt[0] = '\0'; - - tms = SCLocalTime(SCTIME_SECS(tval), &local_tm); - - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%04d-%02d-%02d %02d:%02d:%02d%s", substr, green, tms->tm_year + 1900, - tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec, - reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_TIME_LEGACY: - temp_fmt[0] = '\0'; - - tms = SCLocalTime(SCTIME_SECS(tval), &local_tm); - - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%d/%d/%04d -- %02d:%02d:%02d%s", - substr, green, tms->tm_mday, tms->tm_mon + 1, - tms->tm_year + 1900, tms->tm_hour, tms->tm_min, - tms->tm_sec, reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_PID: - temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%u%s", substr, yellow, getpid(), reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_TID: - temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_THREAD_NAME: - case SC_LOG_FMT_TM: - temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, - yellow, t_thread_name, reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_LOG_LEVEL: - temp_fmt[0] = '\0'; - s = SCMapEnumValueToName(log_level, sc_log_level_map); - if (s != NULL) { - if (log_level <= SC_LOG_ERROR) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%s%s", substr, redb, s, reset); - else if (log_level == SC_LOG_WARNING) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%s%s", substr, red, s, reset); - else if (log_level == SC_LOG_NOTICE) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%s%s", substr, yellowb, s, reset); - else - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", - substr, yellow, s, reset); - } else { - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, - "INVALID"); - } - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_LOG_SLEVEL: - temp_fmt[0] = '\0'; - s = SCMapEnumValueToName(log_level, sc_log_slevel_map); - if (s != NULL) { - if (log_level <= SC_LOG_ERROR) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", - substr, redb, s, reset); - else if (log_level == SC_LOG_WARNING) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", - substr, red, s, reset); - else if (log_level == SC_LOG_NOTICE) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", - substr, yellowb, s, reset); - else - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%s%s", substr, yellow, s, reset); - } else { - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s", substr, "INVALID"); - } - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_FILE_NAME: - temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%s%s", substr, blue, file, reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_LINE: - temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%u%s", substr, green, line, reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_SUBSYSTEM: - temp_fmt[0] = '\0'; - - /* Determine how much of module name to display */ - int dn_len = 0; - const char *dn_name = "unknown"; - if (module) { - dn_name = SCTransformModule(module, &dn_len); - } - - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, - green, dn_name, reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_FUNCTION: - temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), - "%s%s%s%s", substr, green, function, reset); - if (cw < 0) - return -1; - temp += cw; - temp_fmt++; - substr = temp_fmt; - substr++; - break; - - case SC_LOG_FMT_MESSAGE: { - temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr); - if (cw < 0) { - return -1; - } - temp += cw; - if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - return 0; - } - const char *hi = ""; - if (log_level <= SC_LOG_ERROR) - hi = red; - else if (log_level <= SC_LOG_NOTICE) - hi = yellow; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message, - reset); - if (cw < 0) { - return -1; - } - temp += cw; - if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - return 0; - } - temp_fmt++; - substr = temp_fmt; - substr++; - break; - } - } - temp_fmt++; - } - if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { - return 0; - } - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr); - if (cw < 0) { - return -1; - } - if (sc_log_config->op_filter_regex != NULL) { - if (pcre2_match(sc_log_config->op_filter_regex, (PCRE2_SPTR8)buffer, strlen(buffer), 0, 0, - sc_log_config->op_filter_regex_match, NULL) < 0) { - return -1; // bit hacky, but just return !0 - } - } - - return 0; -} - -/** \internal - * \brief try to reopen file - * \note no error reporting here, as we're called by SCLogMessage - * \retval status 0 ok, -1 error */ -static int SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx) -{ - if (op_iface_ctx->file == NULL) { - return 0; - } - - if (op_iface_ctx->file_d != NULL) { - fclose(op_iface_ctx->file_d); - } - op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a"); - if (op_iface_ctx->file_d == NULL) { - return -1; - } - return 0; -} - -/** - * \brief Adds the global log_format to the outgoing buffer - * - * \param log_level log_level of the message that has to be logged - * \param msg Buffer containing the outgoing message - * \param file File_name from where the message originated - * \param function Function_name from where the message originated - * \param line Line_no from where the messaged originated - * - * \retval SC_OK on success; else an error code - */ -SCError SCLogMessage(const SCLogLevel log_level, const char *file, const unsigned int line, - const char *function, const char *module, const char *message) -{ - char buffer[SC_LOG_MAX_LOG_MSG_LEN] = ""; - SCLogOPIfaceCtx *op_iface_ctx = NULL; - - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return SC_OK; - } - - /* get ts here so we log the same ts to each output */ - struct timeval tval; - gettimeofday(&tval, NULL); - SCTime_t ts = SCTIME_FROM_TIMEVAL(&tval); - - op_iface_ctx = sc_log_config->op_ifaces; - while (op_iface_ctx != NULL) { - if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) { - op_iface_ctx = op_iface_ctx->next; - continue; - } - - switch (op_iface_ctx->iface) { - case SC_LOG_OP_IFACE_CONSOLE: - if (SCLogMessageGetBuffer(ts, op_iface_ctx->use_color, op_iface_ctx->type, buffer, - sizeof(buffer), - op_iface_ctx->log_format ? op_iface_ctx->log_format - : sc_log_config->log_format, - log_level, file, line, function, module, message) == 0) { - SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, buffer); - } - break; - case SC_LOG_OP_IFACE_FILE: - if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer), - op_iface_ctx->log_format ? op_iface_ctx->log_format - : sc_log_config->log_format, - log_level, file, line, function, module, message) == 0) { - int r = 0; - SCMutexLock(&op_iface_ctx->fp_mutex); - if (op_iface_ctx->rotation_flag) { - r = SCLogReopen(op_iface_ctx); - op_iface_ctx->rotation_flag = 0; - } - SCLogPrintToStream(op_iface_ctx->file_d, buffer); - SCMutexUnlock(&op_iface_ctx->fp_mutex); - - /* report error outside of lock to avoid recursion */ - if (r == -1) { - SCLogError("re-opening file \"%s\" failed: %s", op_iface_ctx->file, - strerror(errno)); - } - } - break; - case SC_LOG_OP_IFACE_SYSLOG: - if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer), - op_iface_ctx->log_format ? op_iface_ctx->log_format - : sc_log_config->log_format, - log_level, file, line, function, module, message) == 0) { - SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer); - } - break; - default: - break; - } - op_iface_ctx = op_iface_ctx->next; - } - return SC_OK; -} - -void SCLog(int x, const char *file, const char *func, const int line, const char *module, - const char *fmt, ...) -{ - if (sc_log_global_log_level >= x && - (sc_log_fg_filters_present == 0 || - SCLogMatchFGFilterWL(file, func, line) == 1 || - SCLogMatchFGFilterBL(file, func, line) == 1) && - (sc_log_fd_filters_present == 0 || - SCLogMatchFDFilter(func) == 1)) - { - char msg[SC_LOG_MAX_LOG_MSG_LEN]; - va_list ap; - va_start(ap, fmt); - vsnprintf(msg, sizeof(msg), fmt, ap); - va_end(ap); - SCLogMessage(x, file, line, func, module, msg); - } -} - -void SCLogErr(int x, const char *file, const char *func, const int line, const char *module, - const char *fmt, ...) -{ - if (sc_log_global_log_level >= x && - (sc_log_fg_filters_present == 0 || - SCLogMatchFGFilterWL(file, func, line) == 1 || - SCLogMatchFGFilterBL(file, func, line) == 1) && - (sc_log_fd_filters_present == 0 || - SCLogMatchFDFilter(func) == 1)) - { - char msg[SC_LOG_MAX_LOG_MSG_LEN]; - va_list ap; - va_start(ap, fmt); - vsnprintf(msg, sizeof(msg), fmt, ap); - va_end(ap); - SCLogMessage(x, file, line, func, module, msg); - } -} - -/** - * \brief Returns whether debug messages are enabled to be logged or not - * - * \retval 1 if debug messages are enabled to be logged - * \retval 0 if debug messages are not enabled to be logged - */ -int SCLogDebugEnabled(void) -{ -#ifdef DEBUG - if (sc_log_global_log_level == SC_LOG_DEBUG) - return 1; - else - return 0; -#else - return 0; -#endif -} - -/** - * \brief Allocates an output buffer for an output interface. Used when we - * want the op_interface log_format to override the global_log_format. - * Currently not used. - * - * \retval buffer Pointer to the newly created output_buffer - */ -SCLogOPBuffer *SCLogAllocLogOPBuffer(void) -{ - SCLogOPBuffer *buffer = NULL; - - if ( (buffer = SCMalloc(sc_log_config->op_ifaces_cnt * - sizeof(SCLogOPBuffer))) == NULL) { - FatalError("Fatal error encountered in SCLogAllocLogOPBuffer. Exiting..."); - } - - SCLogOPIfaceCtx *op_iface_ctx = sc_log_config->op_ifaces; - for (int i = 0; i < sc_log_config->op_ifaces_cnt; i++, op_iface_ctx = op_iface_ctx->next) { - buffer[i].log_format = op_iface_ctx->log_format; - buffer[i].temp = buffer[i].msg; - } - - return buffer; -} - -/*----------------------The logging module initialization code--------------- */ - -/** - * \brief Returns a new output_interface_context - * - * \retval iface_ctx Pointer to a newly allocated output_interface_context - * \initonly - */ -static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx(void) -{ - SCLogOPIfaceCtx *iface_ctx = NULL; - - if ((iface_ctx = SCCalloc(1, sizeof(SCLogOPIfaceCtx))) == NULL) { - FatalError("Fatal error encountered in SCLogallocLogOPIfaceCtx. Exiting..."); - } - - return iface_ctx; -} - -/** - * \brief Initializes the file output interface - * - * \param file Path to the file used for logging purposes - * \param log_format Pointer to the log_format for this op interface, that - * overrides the global_log_format - * \param log_level Override of the global_log_level by this interface - * - * \retval iface_ctx Pointer to the file output interface context created - * \initonly - */ -static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, uint32_t userid, - uint32_t groupid, const char *log_format, int log_level, SCLogOPType type) -{ - SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); - if (iface_ctx == NULL) { - FatalError("Fatal error encountered in SCLogInitFileOPIface. Exiting..."); - } - - if (file == NULL) { - goto error; - } - - iface_ctx->iface = SC_LOG_OP_IFACE_FILE; - iface_ctx->type = type; - - if ( (iface_ctx->file_d = fopen(file, "a")) == NULL) { - SCLogWarning("error opening file %s: %s", file, strerror(errno)); - goto error; - } - -#ifndef OS_WIN32 - if (userid != 0 || groupid != 0) { - if (fchown(fileno(iface_ctx->file_d), userid, groupid) == -1) { - SCLogWarning("Failed to change ownership of file %s: %s", file, strerror(errno)); - } - } -#endif - - if ((iface_ctx->file = SCStrdup(file)) == NULL) { - goto error; - } - - if (log_format != NULL && (iface_ctx->log_format = SCStrdup(log_format)) == NULL) { - goto error; - } - - SCMutexInit(&iface_ctx->fp_mutex, NULL); - OutputRegisterFileRotationFlag(&iface_ctx->rotation_flag); - - iface_ctx->log_level = log_level; - - return iface_ctx; - -error: - if (iface_ctx->file != NULL) { - SCFree((char *)iface_ctx->file); - iface_ctx->file = NULL; - } - if (iface_ctx->log_format != NULL) { - SCFree((char *)iface_ctx->log_format); - iface_ctx->log_format = NULL; - } - if (iface_ctx->file_d != NULL) { - fclose(iface_ctx->file_d); - iface_ctx->file_d = NULL; - } - SCFree(iface_ctx); - return NULL; -} - -/** - * \brief Initializes the console output interface and deals with possible - * env var overrides. - * - * \param log_format Pointer to the log_format for this op interface, that - * overrides the global_log_format - * \param log_level Override of the global_log_level by this interface - * - * \retval iface_ctx Pointer to the console output interface context created - * \initonly - */ -static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, - SCLogLevel log_level, SCLogOPType type) -{ - SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); - - if (iface_ctx == NULL) { - FatalError("Fatal error encountered in SCLogInitConsoleOPIface. Exiting..."); - } - - iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE; - iface_ctx->type = type; - - /* console log format is overridden by envvars */ - const char *tmp_log_format = log_format; - const char *s = getenv(SC_LOG_ENV_LOG_FORMAT); - if (s != NULL) { -#if 0 - printf("Overriding setting for \"console.format\" because of env " - "var SC_LOG_FORMAT=\"%s\".\n", s); -#endif - tmp_log_format = s; - } - - if (tmp_log_format != NULL && - (iface_ctx->log_format = SCStrdup(tmp_log_format)) == NULL) { - printf("Error allocating memory\n"); - exit(EXIT_FAILURE); - } - - /* console log level is overridden by envvars */ - SCLogLevel tmp_log_level = log_level; - s = getenv(SC_LOG_ENV_LOG_LEVEL); - if (s != NULL) { - SCLogLevel l = SCMapEnumNameToValue(s, sc_log_level_map); - if (l > SC_LOG_NOTSET && l < SC_LOG_LEVEL_MAX) { -#if 0 - printf("Overriding setting for \"console.level\" because of env " - "var SC_LOG_LEVEL=\"%s\".\n", s); -#endif - tmp_log_level = l; - } - } - iface_ctx->log_level = tmp_log_level; - -#ifndef OS_WIN32 - if (isatty(fileno(stdout)) && isatty(fileno(stderr))) { - iface_ctx->use_color = true; - } -#endif - - return iface_ctx; -} - -/** - * \brief Initializes the syslog output interface - * - * \param facility The facility code for syslog - * \param log_format Pointer to the log_format for this op interface, that - * overrides the global_log_format - * \param log_level Override of the global_log_level by this interface - * - * \retval iface_ctx Pointer to the syslog output interface context created - */ -static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility, - const char *log_format, - SCLogLevel log_level, - SCLogOPType type) -{ - SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); - - if ( iface_ctx == NULL) { - FatalError("Fatal error encountered in SCLogInitSyslogOPIface. Exiting..."); - } - - iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG; - iface_ctx->type = type; - - if (facility == -1) - facility = SC_LOG_DEF_SYSLOG_FACILITY; - iface_ctx->facility = facility; - - if (log_format != NULL && - (iface_ctx->log_format = SCStrdup(log_format)) == NULL) { - printf("Error allocating memory\n"); - exit(EXIT_FAILURE); - } - - iface_ctx->log_level = log_level; - - openlog(NULL, LOG_NDELAY, iface_ctx->facility); - - return iface_ctx; -} - -/** - * \brief Frees the output_interface context supplied as an argument - * - * \param iface_ctx Pointer to the op_interface_context to be freed - */ -static inline void SCLogFreeLogOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx) -{ - SCLogOPIfaceCtx *temp = NULL; - - while (iface_ctx != NULL) { - temp = iface_ctx; - - if (iface_ctx->file_d != NULL) { - fclose(iface_ctx->file_d); - SCMutexDestroy(&iface_ctx->fp_mutex); - } - - if (iface_ctx->file != NULL) - SCFree((void *)iface_ctx->file); - - if (iface_ctx->log_format != NULL) - SCFree((void *)iface_ctx->log_format); - - if (iface_ctx->iface == SC_LOG_OP_IFACE_SYSLOG) { - closelog(); - } - - iface_ctx = iface_ctx->next; - - SCFree(temp); - } - - return; -} - -/** - * \brief Internal function used to set the logging module global_log_level - * during the initialization phase - * - * \param sc_lid The initialization data supplied. - * \param sc_lc The logging module context which has to be updated. - */ -static inline void SCLogSetLogLevel(SCLogInitData *sc_lid, SCLogConfig *sc_lc) -{ - SCLogLevel log_level = SC_LOG_NOTSET; - const char *s = NULL; - - /* envvar overrides config */ - s = getenv(SC_LOG_ENV_LOG_LEVEL); - if (s != NULL) { - log_level = SCMapEnumNameToValue(s, sc_log_level_map); - } else if (sc_lid != NULL) { - log_level = sc_lid->global_log_level; - } - - /* deal with the global_log_level to be used */ - if (log_level > SC_LOG_NOTSET && log_level < SC_LOG_LEVEL_MAX) - sc_lc->log_level = log_level; - else { - sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL; -#ifndef UNITTESTS - if (sc_lid != NULL) { - printf("Warning: Invalid/No global_log_level assigned by user. Falling " - "back on the default_log_level \"%s\"\n", - SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map)); - } -#endif - } - - /* we also set it to a global var, as it is easier to access it */ - sc_log_global_log_level = sc_lc->log_level; - - return; -} - -SCLogLevel SCLogGetLogLevel(void) -{ - return sc_log_global_log_level; -} - -static inline const char *SCLogGetDefaultLogFormat(const SCLogLevel lvl) -{ - const char *prog_ver = GetProgramVersion(); - if (strstr(prog_ver, "RELEASE") != NULL) { - if (lvl <= SC_LOG_NOTICE) - return SC_LOG_DEF_LOG_FORMAT_REL_NOTICE; - else if (lvl <= SC_LOG_INFO) - return SC_LOG_DEF_LOG_FORMAT_REL_INFO; - else if (lvl <= SC_LOG_CONFIG) - return SC_LOG_DEF_LOG_FORMAT_REL_CONFIG; - } - return SC_LOG_DEF_LOG_FORMAT_DEBUG; -} - -/** - * \brief Internal function used to set the logging module global_log_format - * during the initialization phase - * - * \param sc_lid The initialization data supplied. - * \param sc_lc The logging module context which has to be updated. - */ -static inline void SCLogSetLogFormat(SCLogInitData *sc_lid, SCLogConfig *sc_lc) -{ - const char *format = NULL; - - /* envvar overrides config */ - format = getenv(SC_LOG_ENV_LOG_FORMAT); - if (format == NULL) { - if (sc_lid != NULL) { - format = sc_lid->global_log_format; - } - } - - /* deal with the global log format to be used */ - if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) { - format = SCLogGetDefaultLogFormat(sc_lc->log_level); -#ifndef UNITTESTS - if (sc_lid != NULL) { - printf("Warning: Invalid/No global_log_format supplied by user or format " - "length exceeded limit of \"%d\" characters. Falling back on " - "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN, - format); - } -#endif - } - - if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) { - printf("Error allocating memory\n"); - exit(EXIT_FAILURE); - } - - return; -} - -/** - * \brief Internal function used to set the logging module global_op_ifaces - * during the initialization phase - * - * \param sc_lid The initialization data supplied. - * \param sc_lc The logging module context which has to be updated. - */ -static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc) -{ - SCLogOPIfaceCtx *op_ifaces_ctx = NULL; - int op_iface = 0; - const char *s = NULL; - - if (sc_lid != NULL && sc_lid->op_ifaces != NULL) { - sc_lc->op_ifaces = sc_lid->op_ifaces; - sc_lid->op_ifaces = NULL; - sc_lc->op_ifaces_cnt = sc_lid->op_ifaces_cnt; - } else { - s = getenv(SC_LOG_ENV_LOG_OP_IFACE); - if (s != NULL) { - op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map); - - if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) { - op_iface = SC_LOG_DEF_LOG_OP_IFACE; -#ifndef UNITTESTS - printf("Warning: Invalid output interface supplied by user. " - "Falling back on default_output_interface \"%s\"\n", - SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); -#endif - } - } - else { - op_iface = SC_LOG_DEF_LOG_OP_IFACE; -#ifndef UNITTESTS - if (sc_lid != NULL) { - printf("Warning: Output_interface not supplied by user. Falling " - "back on default_output_interface \"%s\"\n", - SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); - } -#endif - } - - switch (op_iface) { - case SC_LOG_OP_IFACE_CONSOLE: - op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0); - break; - case SC_LOG_OP_IFACE_FILE: - s = getenv(SC_LOG_ENV_LOG_FILE); - if (s == NULL) { - char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); - if (str != NULL) { - op_ifaces_ctx = SCLogInitFileOPIface(str, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0); - SCFree(str); - } - } else { - op_ifaces_ctx = SCLogInitFileOPIface(s, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0); - } - break; - case SC_LOG_OP_IFACE_SYSLOG: - s = getenv(SC_LOG_ENV_LOG_FACILITY); - if (s == NULL) - s = SC_LOG_DEF_SYSLOG_FACILITY_STR; - - op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0); - break; - } - sc_lc->op_ifaces = op_ifaces_ctx; - sc_lc->op_ifaces_cnt++; - } - return; -} - -/** - * \brief Internal function used to set the logging module op_filter - * during the initialization phase - * - * \param sc_lid The initialization data supplied. - * \param sc_lc The logging module context which has to be updated. - */ -static inline void SCLogSetOPFilter(SCLogInitData *sc_lid, SCLogConfig *sc_lc) -{ - const char *filter = NULL; - - int opts = 0; - int en; - PCRE2_SIZE eo = 0; - - /* envvar overrides */ - filter = getenv(SC_LOG_ENV_LOG_OP_FILTER); - if (filter == NULL) { - if (sc_lid != NULL) { - filter = sc_lid->op_filter; - } - } - - if (filter != NULL && strcmp(filter, "") != 0) { - sc_lc->op_filter = SCStrdup(filter); - if (sc_lc->op_filter == NULL) { - printf("pcre filter alloc failed\n"); - return; - } - sc_lc->op_filter_regex = - pcre2_compile((PCRE2_SPTR8)filter, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); - if (sc_lc->op_filter_regex == NULL) { - SCFree(sc_lc->op_filter); - PCRE2_UCHAR errbuffer[256]; - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - printf("pcre2 compile of \"%s\" failed at offset %d : %s\n", filter, (int)eo, - errbuffer); - return; - } - sc_lc->op_filter_regex_match = - pcre2_match_data_create_from_pattern(sc_lc->op_filter_regex, NULL); - } - - return; -} - -/** - * \brief Returns a pointer to a new SCLogInitData. This is a public interface - * intended to be used after the logging parameters are read from the - * conf file - * - * \retval sc_lid Pointer to the newly created SCLogInitData - * \initonly - */ -SCLogInitData *SCLogAllocLogInitData(void) -{ - SCLogInitData *sc_lid = NULL; - - if ((sc_lid = SCCalloc(1, sizeof(SCLogInitData))) == NULL) - return NULL; - - return sc_lid; -} - -#ifdef UNITTESTS -#ifndef OS_WIN32 -/** - * \brief Frees a SCLogInitData - * - * \param sc_lid Pointer to the SCLogInitData to be freed - */ -static void SCLogFreeLogInitData(SCLogInitData *sc_lid) -{ - if (sc_lid != NULL) { - SCLogFreeLogOPIfaceCtx(sc_lid->op_ifaces); - SCFree(sc_lid); - } - - return; -} -#endif -#endif - -/** - * \brief Frees the logging module context - */ -static inline void SCLogFreeLogConfig(SCLogConfig *sc_lc) -{ - if (sc_lc != NULL) { - if (sc_lc->startup_message != NULL) - SCFree(sc_lc->startup_message); - if (sc_lc->log_format != NULL) - SCFree(sc_lc->log_format); - if (sc_lc->op_filter != NULL) - SCFree(sc_lc->op_filter); - - if (sc_lc->op_filter_regex != NULL) - pcre2_code_free(sc_lc->op_filter_regex); - if (sc_lc->op_filter_regex_match) - pcre2_match_data_free(sc_lc->op_filter_regex_match); - - SCLogFreeLogOPIfaceCtx(sc_lc->op_ifaces); - SCFree(sc_lc); - } - - return; -} - -/** - * \brief Appends an output_interface to the output_interface list sent in head - * - * \param iface_ctx Pointer to the output_interface that has to be added to head - * \param head Pointer to the output_interface list - */ -void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx, SCLogInitData *sc_lid) -{ - SCLogOPIfaceCtx *temp = NULL, *prev = NULL; - SCLogOPIfaceCtx **head = &sc_lid->op_ifaces; - - if (iface_ctx == NULL) { -#ifdef DEBUG - printf("Argument(s) to SCLogAppendOPIfaceCtx() NULL\n"); -#endif - return; - } - - temp = *head; - while (temp != NULL) { - prev = temp; - temp = temp->next; - } - - if (prev == NULL) - *head = iface_ctx; - else - prev->next = iface_ctx; - - sc_lid->op_ifaces_cnt++; - - return; -} - -#ifdef UNITTESTS -#ifndef OS_WIN32 -/** - * \internal - * \brief Creates a new output interface based on the arguments sent. The kind - * of output interface to be created is decided by the iface_name arg. - * If iface_name is "file", the arg argument will hold the filename to be - * used for logging purposes. If iface_name is "syslog", the arg - * argument holds the facility code. If iface_name is "console", arg is - * NULL. - * - * \param iface_name Interface name. Can be "console", "file" or "syslog" - * \param log_format Override for the global_log_format - * \param log_level Override for the global_log_level - * \param log_level Parameter required by a particular interface. Explained in - * the function description - * - * \retval iface_ctx Pointer to the newly created output interface - */ -static SCLogOPIfaceCtx *SCLogInitOPIfaceCtx( - const char *iface_name, const char *log_format, int log_level, const char *arg) -{ - int iface = SCMapEnumNameToValue(iface_name, sc_log_op_iface_map); - - if (log_level < SC_LOG_NONE || log_level > SC_LOG_DEBUG) { - printf("Warning: Supplied log_level_override for op_interface \"%s\" " - "is invalid. Defaulting to not specifying an override\n", - iface_name); - log_level = SC_LOG_NOTSET; - } - - switch (iface) { - case SC_LOG_OP_IFACE_CONSOLE: - return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR); - case SC_LOG_OP_IFACE_FILE: - return SCLogInitFileOPIface(arg, 0, 0, log_format, log_level, SC_LOG_OP_TYPE_REGULAR); - case SC_LOG_OP_IFACE_SYSLOG: - return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), - log_format, log_level, SC_LOG_OP_TYPE_REGULAR); - default: -#ifdef DEBUG - printf("Output Interface \"%s\" not supported by the logging module", - iface_name); -#endif - return NULL; - } -} -#endif -#endif - -/** - * \brief Initializes the logging module. - * - * \param sc_lid The initialization data for the logging module. If sc_lid is - * NULL, we would stick to the default configuration for the - * logging subsystem. - * \initonly - */ -void SCLogInitLogModule(SCLogInitData *sc_lid) -{ - /* De-initialize the logging context, if it has already init by the - * environment variables at the start of the engine */ - SCLogDeInitLogModule(); - -#if defined (OS_WIN32) - if (SCMutexInit(&sc_log_stream_lock, NULL) != 0) { - FatalError("Failed to initialize log mutex."); - } -#endif /* OS_WIN32 */ - - /* sc_log_config is a global variable */ - if ((sc_log_config = SCCalloc(1, sizeof(SCLogConfig))) == NULL) { - FatalError("Fatal error encountered in SCLogInitLogModule. Exiting..."); - } - - SCLogSetLogLevel(sc_lid, sc_log_config); - SCLogSetLogFormat(sc_lid, sc_log_config); - SCLogSetOPIface(sc_lid, sc_log_config); - SCLogSetOPFilter(sc_lid, sc_log_config); - - sc_log_module_initialized = 1; - sc_log_module_cleaned = 0; - - //SCOutputPrint(sc_did->startup_message); - - rs_log_set_level(sc_log_global_log_level); - return; -} - -void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid) -{ - ConfNode *outputs; - SCLogInitData *sc_lid; - int have_logging = 0; - int max_level = 0; - SCLogLevel min_level = 0; - - /* If verbose logging was requested, set the minimum as - * SC_LOG_NOTICE plus the extra verbosity. */ - if (verbose) { - min_level = SC_LOG_NOTICE + verbose; - } - - outputs = ConfGetNode("logging.outputs"); - if (outputs == NULL) { - SCLogDebug("No logging.output configuration section found."); - return; - } - - sc_lid = SCLogAllocLogInitData(); - if (sc_lid == NULL) { - SCLogDebug("Could not allocate memory for log init data"); - return; - } - - /* Get default log level and format. */ - const char *default_log_level_s = NULL; - if (ConfGet("logging.default-log-level", &default_log_level_s) == 1) { - SCLogLevel default_log_level = - SCMapEnumNameToValue(default_log_level_s, sc_log_level_map); - if (default_log_level == -1) { - SCLogError("Invalid default log level: %s", default_log_level_s); - exit(EXIT_FAILURE); - } - sc_lid->global_log_level = MAX(min_level, default_log_level); - } - else { - sc_lid->global_log_level = MAX(min_level, SC_LOG_NOTICE); - } - - if (ConfGet("logging.default-log-format", &sc_lid->global_log_format) != 1) - sc_lid->global_log_format = SCLogGetDefaultLogFormat(sc_lid->global_log_level); - - (void)ConfGet("logging.default-output-filter", &sc_lid->op_filter); - - ConfNode *seq_node, *output; - TAILQ_FOREACH(seq_node, &outputs->head, next) { - SCLogLevel level = sc_lid->global_log_level; - SCLogOPIfaceCtx *op_iface_ctx = NULL; - const char *format; - const char *level_s; - - output = ConfNodeLookupChild(seq_node, seq_node->val); - if (output == NULL) - continue; - - /* By default an output is enabled. */ - const char *enabled = ConfNodeLookupChildValue(output, "enabled"); - if (enabled != NULL && ConfValIsFalse(enabled)) - continue; - - SCLogOPType type = SC_LOG_OP_TYPE_REGULAR; - const char *type_s = ConfNodeLookupChildValue(output, "type"); - if (type_s != NULL) { - if (strcmp(type_s, "regular") == 0) - type = SC_LOG_OP_TYPE_REGULAR; - else if (strcmp(type_s, "json") == 0) { - type = SC_LOG_OP_TYPE_JSON; - } - } - - format = ConfNodeLookupChildValue(output, "format"); - - level_s = ConfNodeLookupChildValue(output, "level"); - if (level_s != NULL) { - level = SCMapEnumNameToValue(level_s, sc_log_level_map); - if (level == -1) { - SCLogError("Invalid log level: %s", level_s); - exit(EXIT_FAILURE); - } - max_level = MAX(max_level, level); - } - - /* Increase the level of extra verbosity was requested. */ - level = MAX(min_level, level); - - if (strcmp(output->name, "console") == 0) { - op_iface_ctx = SCLogInitConsoleOPIface(format, level, type); - } - else if (strcmp(output->name, "file") == 0) { - if (format == NULL) { - format = SC_LOG_DEF_FILE_FORMAT; - } - - const char *filename = ConfNodeLookupChildValue(output, "filename"); - if (filename == NULL) { - FatalError("Logging to file requires a filename"); - } - char *path = NULL; - if (!(PathIsAbsolute(filename))) { - path = SCLogGetLogFilename(filename); - } else { - path = SCStrdup(filename); - } - if (path == NULL) - FatalError("failed to setup output to file"); - have_logging = 1; - op_iface_ctx = SCLogInitFileOPIface(path, userid, groupid, format, level, type); - SCFree(path); - } - else if (strcmp(output->name, "syslog") == 0) { - int facility = SC_LOG_DEF_SYSLOG_FACILITY; - const char *facility_s = ConfNodeLookupChildValue(output, - "facility"); - if (facility_s != NULL) { - facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap()); - if (facility == -1) { - SCLogWarning("Invalid syslog " - "facility: \"%s\", now using \"%s\" as syslog " - "facility", - facility_s, SC_LOG_DEF_SYSLOG_FACILITY_STR); - facility = SC_LOG_DEF_SYSLOG_FACILITY; - } - } - SCLogDebug("Initializing syslog logging with format \"%s\"", format); - have_logging = 1; - op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type); - } - else { - SCLogWarning("invalid logging method: %s, ignoring", output->name); - } - if (op_iface_ctx != NULL) { - SCLogAppendOPIfaceCtx(op_iface_ctx, sc_lid); - } - } - - if (daemon && (have_logging == 0)) { - SCLogWarning("no logging compatible with daemon mode selected," - " suricata won't be able to log. Please update " - " 'logging.outputs' in the YAML."); - } - - /* Set the global log level to that of the max level used. */ - sc_lid->global_log_level = MAX(sc_lid->global_log_level, max_level); - SCLogInitLogModule(sc_lid); - - SCLogDebug("sc_log_global_log_level: %d", sc_log_global_log_level); - SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format); - SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter); - - if (sc_lid != NULL) - SCFree(sc_lid); -} - -/** - * \brief Returns a full file path given a filename uses log dir specified in - * conf or DEFAULT_LOG_DIR - * - * \param filearg The relative filename for which we want a full path include - * log directory - * - * \retval log_filename The fullpath of the logfile to open - */ -static char *SCLogGetLogFilename(const char *filearg) -{ - const char *log_dir = ConfigGetLogDirectory(); - char *log_filename = SCMalloc(PATH_MAX); - if (unlikely(log_filename == NULL)) - return NULL; - snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filearg); - return log_filename; -} - -/** - * \brief De-Initializes the logging module - */ -void SCLogDeInitLogModule(void) -{ - SCLogFreeLogConfig(sc_log_config); - - /* reset the global logging_module variables */ - sc_log_global_log_level = 0; - sc_log_module_initialized = 0; - sc_log_module_cleaned = 1; - sc_log_config = NULL; - - /* de-init the FD filters */ - SCLogReleaseFDFilters(); - /* de-init the FG filters */ - SCLogReleaseFGFilters(); - -#if defined (OS_WIN32) - SCMutexDestroy(&sc_log_stream_lock); -#endif /* OS_WIN32 */ - - return; -} - -//------------------------------------Unit_Tests-------------------------------- - -/* The logging engine should be tested to the maximum extent possible, since - * logging code would be used throughout the codebase, and hence we can't afford - * to have a single bug here(not that you can afford to have a bug - * elsewhere ;) ). Please report a bug, if you get a slightest hint of a bug - * from the logging module. - */ - -#ifdef UNITTESTS - -static int SCLogTestInit01(void) -{ -#ifndef OS_WIN32 - /* unset any environment variables set for the logging module */ - unsetenv(SC_LOG_ENV_LOG_LEVEL); - unsetenv(SC_LOG_ENV_LOG_OP_IFACE); - unsetenv(SC_LOG_ENV_LOG_FORMAT); - - SCLogInitLogModule(NULL); - - FAIL_IF_NULL(sc_log_config); - - FAIL_IF_NOT(SC_LOG_DEF_LOG_LEVEL == sc_log_config->log_level); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - SC_LOG_DEF_LOG_OP_IFACE == sc_log_config->op_ifaces->iface); - FAIL_IF_NOT(sc_log_config->log_format != NULL && - strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level), - sc_log_config->log_format) == 0); - - SCLogDeInitLogModule(); - - setenv(SC_LOG_ENV_LOG_LEVEL, "Debug", 1); - setenv(SC_LOG_ENV_LOG_OP_IFACE, "Console", 1); - setenv(SC_LOG_ENV_LOG_FORMAT, "%n- %l", 1); - - SCLogInitLogModule(NULL); - - FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface); - FAIL_IF_NOT(sc_log_config->log_format != NULL && - !strcmp("%n- %l", sc_log_config->log_format)); - - unsetenv(SC_LOG_ENV_LOG_LEVEL); - unsetenv(SC_LOG_ENV_LOG_OP_IFACE); - unsetenv(SC_LOG_ENV_LOG_FORMAT); - - SCLogDeInitLogModule(); -#endif - PASS; -} - -static int SCLogTestInit02(void) -{ -#ifndef OS_WIN32 - SCLogInitData *sc_lid = NULL; - SCLogOPIfaceCtx *sc_iface_ctx = NULL; - char *logfile = SCLogGetLogFilename("boo.txt"); - sc_lid = SCLogAllocLogInitData(); - FAIL_IF_NULL(sc_lid); - sc_lid->startup_message = "Test02"; - sc_lid->global_log_level = SC_LOG_DEBUG; - sc_lid->op_filter = "boo"; - sc_iface_ctx = SCLogInitOPIfaceCtx("file", "%m - %d", SC_LOG_WARNING, logfile); - SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid); - sc_iface_ctx = SCLogInitOPIfaceCtx("console", NULL, SC_LOG_ERROR, - NULL); - SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid); - - SCLogInitLogModule(sc_lid); - - FAIL_IF_NULL(sc_log_config); - - FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - SC_LOG_OP_IFACE_FILE == sc_log_config->op_ifaces->iface); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - sc_log_config->op_ifaces->next != NULL && - SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->next->iface); - FAIL_IF_NOT(sc_log_config->log_format != NULL && - strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level), - sc_log_config->log_format) == 0); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - sc_log_config->op_ifaces->log_format != NULL && - strcmp("%m - %d", sc_log_config->op_ifaces->log_format) == 0); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - sc_log_config->op_ifaces->next != NULL && - sc_log_config->op_ifaces->next->log_format == NULL); - - SCLogFreeLogInitData(sc_lid); - SCLogDeInitLogModule(); - - sc_lid = SCLogAllocLogInitData(); - FAIL_IF_NULL(sc_lid); - sc_lid->startup_message = "Test02"; - sc_lid->global_log_level = SC_LOG_DEBUG; - sc_lid->op_filter = "boo"; - sc_lid->global_log_format = "kaboo"; - - SCLogInitLogModule(sc_lid); - - FAIL_IF_NULL(sc_log_config); - - FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - sc_log_config->op_ifaces->next == NULL); - FAIL_IF_NOT(sc_log_config->log_format != NULL && - strcmp("kaboo", sc_log_config->log_format) == 0); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - sc_log_config->op_ifaces->log_format == NULL); - FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && - sc_log_config->op_ifaces->next == NULL); - - SCLogFreeLogInitData(sc_lid); - SCLogDeInitLogModule(); - SCFree(logfile); -#endif - PASS; -} - -static int SCLogTestInit03(void) -{ - SCLogInitLogModule(NULL); - - SCLogAddFGFilterBL(NULL, "bamboo", -1); - SCLogAddFGFilterBL(NULL, "soo", -1); - SCLogAddFGFilterBL(NULL, "dummy", -1); - - FAIL_IF_NOT(SCLogPrintFGFilters() == 3); - - SCLogAddFGFilterBL(NULL, "dummy1", -1); - SCLogAddFGFilterBL(NULL, "dummy2", -1); - - FAIL_IF_NOT(SCLogPrintFGFilters() == 5); - - SCLogDeInitLogModule(); - - PASS; -} - -static int SCLogTestInit04(void) -{ - SCLogInitLogModule(NULL); - - SCLogAddFDFilter("bamboo"); - SCLogAddFDFilter("soo"); - SCLogAddFDFilter("foo"); - SCLogAddFDFilter("roo"); - - FAIL_IF_NOT(SCLogPrintFDFilters() == 4); - - SCLogAddFDFilter("loo"); - SCLogAddFDFilter("soo"); - - FAIL_IF_NOT(SCLogPrintFDFilters() == 5); - - SCLogRemoveFDFilter("bamboo"); - SCLogRemoveFDFilter("soo"); - SCLogRemoveFDFilter("foo"); - SCLogRemoveFDFilter("noo"); - - FAIL_IF_NOT(SCLogPrintFDFilters() == 2); - - SCLogDeInitLogModule(); - - PASS; -} - -static int SCLogTestInit05(void) -{ - char str[4096]; - memset(str, 'A', sizeof(str)); - SCLogInfo("%s", str); - - PASS; -} - -#endif /* UNITTESTS */ - -void SCLogRegisterTests(void) -{ - -#ifdef UNITTESTS - - UtRegisterTest("SCLogTestInit01", SCLogTestInit01); - UtRegisterTest("SCLogTestInit02", SCLogTestInit02); - UtRegisterTest("SCLogTestInit03", SCLogTestInit03); - UtRegisterTest("SCLogTestInit04", SCLogTestInit04); - UtRegisterTest("SCLogTestInit05", SCLogTestInit05); - -#endif /* UNITTESTS */ - - return; -} diff --git a/src/util-debug.h b/src/util-debug.h deleted file mode 100644 index 296cf896519c..000000000000 --- a/src/util-debug.h +++ /dev/null @@ -1,550 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_DEBUG_H__ -#define __UTIL_DEBUG_H__ - -#include "suricata-common.h" - -#include "threads.h" -#include "util-error.h" -#include "util-debug-filters.h" - -/** - * \brief ENV vars that can be used to set the properties for the logging module - */ -#define SC_LOG_ENV_LOG_LEVEL "SC_LOG_LEVEL" -#define SC_LOG_ENV_LOG_OP_IFACE "SC_LOG_OP_IFACE" -#define SC_LOG_ENV_LOG_FILE "SC_LOG_FILE" -#define SC_LOG_ENV_LOG_FACILITY "SC_LOG_FACILITY" -#define SC_LOG_ENV_LOG_FORMAT "SC_LOG_FORMAT" -#define SC_LOG_ENV_LOG_OP_FILTER "SC_LOG_OP_FILTER" - -/** - * \brief The various log levels - * NOTE: when adding new level, don't forget to update SCLogMapLogLevelToSyslogLevel() - * or it may result in logging to syslog with LOG_EMERG priority. - */ -typedef enum { - SC_LOG_NOTSET = -1, - SC_LOG_NONE = 0, - SC_LOG_ERROR, - SC_LOG_WARNING, - SC_LOG_NOTICE, - SC_LOG_INFO, - SC_LOG_PERF, - SC_LOG_CONFIG, - SC_LOG_DEBUG, - SC_LOG_LEVEL_MAX, -} SCLogLevel; - -/** - * \brief The various output interfaces supported - */ -typedef enum { - SC_LOG_OP_IFACE_CONSOLE, - SC_LOG_OP_IFACE_FILE, - SC_LOG_OP_IFACE_SYSLOG, - SC_LOG_OP_IFACE_MAX, -} SCLogOPIface; - -typedef enum { - SC_LOG_OP_TYPE_REGULAR = 0, - SC_LOG_OP_TYPE_JSON, -} SCLogOPType; - -/* The default log_format, if it is not supplied by the user */ -#define SC_LOG_DEF_FILE_FORMAT "[%i - %m] %z %d: %S: %M" -#define SC_LOG_DEF_LOG_FORMAT_REL_NOTICE "%D: %S: %M" -#define SC_LOG_DEF_LOG_FORMAT_REL_INFO "%d: %S: %M" -#define SC_LOG_DEF_LOG_FORMAT_REL_CONFIG "[%i] %d: %S: %M" -#define SC_LOG_DEF_LOG_FORMAT_DEBUG "%d: %S: %M [%n:%f:%l]" - -/* The maximum length of the log message */ -#define SC_LOG_MAX_LOG_MSG_LEN 2048 - -/* The maximum length of the log format */ -#define SC_LOG_MAX_LOG_FORMAT_LEN 128 - -/* The default log level, if it is not supplied by the user */ -#define SC_LOG_DEF_LOG_LEVEL SC_LOG_INFO - -/* The default output interface to be used */ -#define SC_LOG_DEF_LOG_OP_IFACE SC_LOG_OP_IFACE_CONSOLE - -/* The default log file to be used */ -#define SC_LOG_DEF_LOG_FILE "suricata.log" - -/* The default syslog facility to be used */ -#define SC_LOG_DEF_SYSLOG_FACILITY_STR "local0" -#define SC_LOG_DEF_SYSLOG_FACILITY LOG_LOCAL0 - -/** - * \brief Structure to be used when log_level override support would be provided - * by the logging module - */ -typedef struct SCLogOPBuffer_ { - char msg[SC_LOG_MAX_LOG_MSG_LEN]; - char *temp; - const char *log_format; -} SCLogOPBuffer; - -/** - * \brief The output interface context for the logging module - */ -typedef struct SCLogOPIfaceCtx_ { - SCLogOPIface iface; - - bool use_color; - SCLogOPType type; - - /* the output file to be used if the interface is SC_LOG_IFACE_FILE */ - const char *file; - /* the output file descriptor for the above file */ - FILE * file_d; - - /* registered to be set on a file rotation signal */ - int rotation_flag; - - /* the facility code if the interface is SC_LOG_IFACE_SYSLOG */ - int facility; - - /* override for the global_log_level */ - SCLogLevel log_level; - - /* override for the global_log_format(currently not used) */ - const char *log_format; - - /* Mutex used for locking around rotate/write to a file. */ - SCMutex fp_mutex; - - struct SCLogOPIfaceCtx_ *next; -} SCLogOPIfaceCtx; - -/** - * \brief Structure containing init data, that would be passed to - * SCInitDebugModule() - */ -typedef struct SCLogInitData_ { - /* startup message */ - const char *startup_message; - - /* the log level */ - SCLogLevel global_log_level; - - /* the log format */ - const char *global_log_format; - - /* output filter */ - const char *op_filter; - - /* list of output interfaces to be used */ - SCLogOPIfaceCtx *op_ifaces; - /* no of op ifaces */ - uint8_t op_ifaces_cnt; -} SCLogInitData; - -/** - * \brief Holds the config state used by the logging api - */ -typedef struct SCLogConfig_ { - char *startup_message; - SCLogLevel log_level; - char *log_format; - - char *op_filter; - /* compiled pcre filter expression */ - pcre2_code *op_filter_regex; - pcre2_match_data *op_filter_regex_match; - - /* op ifaces used */ - SCLogOPIfaceCtx *op_ifaces; - /* no of op ifaces */ - uint8_t op_ifaces_cnt; -} SCLogConfig; - -/* The different log format specifiers supported by the API */ -#define SC_LOG_FMT_TIME 'z' /* Timestamp in RFC3339 like format */ -#define SC_LOG_FMT_TIME_LEGACY 't' /* Timestamp in legacy format */ -#define SC_LOG_FMT_PID 'p' /* PID */ -#define SC_LOG_FMT_TID 'i' /* Thread ID */ -#define SC_LOG_FMT_TM 'm' /* Thread module name */ -#define SC_LOG_FMT_LOG_LEVEL 'd' /* Log level */ -#define SC_LOG_FMT_LOG_SLEVEL 'D' /* Log level */ -#define SC_LOG_FMT_FILE_NAME 'f' /* File name */ -#define SC_LOG_FMT_LINE 'l' /* Line number */ -#define SC_LOG_FMT_FUNCTION 'n' /* Function */ -#define SC_LOG_FMT_SUBSYSTEM 'S' /* Subsystem name */ -#define SC_LOG_FMT_THREAD_NAME 'T' /* thread name */ -#define SC_LOG_FMT_MESSAGE 'M' /* log message body */ - -/* The log format prefix for the format specifiers */ -#define SC_LOG_FMT_PREFIX '%' - -/* Module and thread tagging */ -/* The module name, usually the containing source-module name */ -static const char *_sc_module __attribute__((unused)) = __SCFILENAME__; - -extern SCLogLevel sc_log_global_log_level; - -extern int sc_log_module_initialized; - -extern int sc_log_module_cleaned; - -void SCLog(int x, const char *file, const char *func, const int line, const char *module, - const char *fmt, ...) ATTR_FMT_PRINTF(6, 7); -void SCLogErr(int x, const char *file, const char *func, const int line, const char *module, - const char *fmt, ...) ATTR_FMT_PRINTF(6, 7); - -/** - * \brief Macro used to log INFORMATIONAL messages. - * - * \retval ... Takes as argument(s), a printf style format message - */ -#define SCLogInfo(...) SCLog(SC_LOG_INFO, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) -#define SCLogInfoRaw(file, func, line, ...) \ - SCLog(SC_LOG_INFO, (file), (func), (line), _sc_module, __VA_ARGS__) - -#define SCLogConfig(...) \ - SCLog(SC_LOG_CONFIG, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) -#define SCLogPerf(...) SCLog(SC_LOG_PERF, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) - -/** - * \brief Macro used to log NOTICE messages. - * - * \retval ... Takes as argument(s), a printf style format message - */ -#define SCLogNotice(...) \ - SCLog(SC_LOG_NOTICE, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) -#define SCLogNoticeRaw(file, func, line, ...) \ - SCLog(SC_LOG_NOTICE, (file), (func), (line), _sc_module, __VA_ARGS__) - -/** - * \brief Macro used to log WARNING messages. - * - * \retval err_code Error code that has to be logged along with the - * warning message - * \retval ... Takes as argument(s), a printf style format message - */ -#define SCLogWarning(...) \ - SCLogErr(SC_LOG_WARNING, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) -#define SCLogWarningRaw(file, func, line, ...) \ - SCLogErr(SC_LOG_WARNING, (file), (func), (line), _sc_module, __VA_ARGS__) - -/** - * \brief Macro used to log ERROR messages. - * - * \retval err_code Error code that has to be logged along with the - * error message - * \retval ... Takes as argument(s), a printf style format message - */ -#define SCLogError(...) \ - SCLogErr(SC_LOG_ERROR, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) -#define SCLogErrorRaw(file, func, line, ...) \ - SCLogErr(SC_LOG_ERROR, (file), (func), (line), _sc_module, __VA_ARGS__) - -/* Avoid the overhead of using the debugging subsystem, in production mode */ -#ifndef DEBUG - -#define SCLogDebug(...) do { } while (0) - -#define SCEnter(...) - -#define SCReturn return - -#define SCReturnInt(x) return x - -#define SCReturnUInt(x) return x - -#define SCReturnDbl(x) return x - -#define SCReturnChar(x) return x - -#define SCReturnCharPtr(x) return x - -#define SCReturnCT(x, type) return x - -#define SCReturnPtr(x, type) return x - -#define SCReturnBool(x) return x - -#define SCReturnStruct(x) return x - -/* Please use it only for debugging purposes */ -#else - - -/** - * \brief Macro used to log DEBUG messages. Comes under the debugging subsystem, - * and hence will be enabled only in the presence of the DEBUG macro. - * - * \retval ... Takes as argument(s), a printf style format message - */ -#define SCLogDebug(...) \ - SCLog(SC_LOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) - -/** - * \brief Macro used to log debug messages on function entry. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_entry logs, it also - * processes the FD filters, if any FD filters are registered. - * - * \retval f An argument can be supplied, although it is not used - */ -#define SCEnter(f) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG &&\ - SCLogCheckFDFilterEntry(__FUNCTION__)) \ - { \ - SCLogDebug("Entering ... >>"); \ - } \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that don't return - * a value. - */ -#define SCReturn do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning ... <<" ); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns an - * integer value. - * - * \retval x Variable of type 'integer' that has to be returned - */ -#define SCReturnInt(x) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning: %"PRIdMAX" ... <<", (intmax_t)x); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns an - * unsigned integer value. - * - * \retval x Variable of type 'unsigned integer' that has to be returned - */ -#define SCReturnUInt(x) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning: %"PRIuMAX" ... <<", (uintmax_t)x); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns a - * float/double value. - * - * \retval x Variable of type 'float/double' that has to be returned - */ -#define SCReturnDbl(x) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning: %f ... <<", x); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns a var - * of character type. - * - * \retval x Variable of type 'char' that has to be returned - */ -#define SCReturnChar(x) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning: %c ... <<", x); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns a - * character string. - * - * \retval x Pointer to the char string that has to be returned - */ -#define SCReturnCharPtr(x) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - if ((x) != NULL) { \ - SCLogDebug("Returning: %s ... <<", x); \ - } else { \ - SCLogDebug("Returning: NULL ... <<"); \ - } SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns a var - * of custom type - * - * \retval x Variable instance of a custom type that has to be returned - * \retval type Pointer to a character string holding the name of the custom - * type(the argument x) that has to be returned - */ -#define SCReturnCT(x, type) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning var of " \ - "type %s ... <<", type); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns a - * pointer to a custom type - * - * \retval x Pointer to a variable instance of a custom type that has to be - * returned - * \retval type Pointer to a character string holding the name of the custom - * type(the argument x) that has to be returned - */ -#define SCReturnPtr(x, type) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning pointer %p of " \ - "type %s ... <<", x, type); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -/** - * \brief Macro used to log debug messages on function exit. Comes under the - * debugging subsystem, and hence will be enabled only in the presence - * of the DEBUG macro. Apart from logging function_exit logs, it also - * processes the FD filters, if any FD filters are registered. This - * function_exit macro should be used for functions that returns a - * boolean value. - * - * \retval x Variable of type 'bool' that has to be returned - */ -#define SCReturnBool(x) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning: %s ... <<", x ? "true" : "false"); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -#define SCReturnStruct(x) do { \ - if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ - SCLogDebug("Returning: ... <<"); \ - SCLogCheckFDFilterExit(__FUNCTION__); \ - } \ - return x; \ - } while(0) - -#endif /* DEBUG */ - -#define FatalError(...) \ - do { \ - SCLogError(__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) - -/** \brief Fatal error IF we're starting up, and configured to consider - * errors to be fatal errors */ -#if !defined(__clang_analyzer__) -#define FatalErrorOnInit(...) \ - do { \ - SC_ATOMIC_EXTERN(unsigned int, engine_stage); \ - int init_errors_fatal = 0; \ - (void)ConfGetBool("engine.init-failure-fatal", &init_errors_fatal); \ - if (init_errors_fatal && (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT)) { \ - SCLogError(__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } \ - SCLogWarning(__VA_ARGS__); \ - } while (0) -/* make it simpler for scan-build */ -#else -#define FatalErrorOnInit(...) FatalError(__VA_ARGS__) -#endif - -#define BOOL2STR(b) (b) ? "true" : "false" - -SCLogInitData *SCLogAllocLogInitData(void); - -void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *, SCLogInitData *); - -void SCLogInitLogModule(SCLogInitData *); - -void SCLogDeInitLogModule(void); - -SCError SCLogMessage(const SCLogLevel, const char *, const unsigned int, const char *, const char *, - const char *message); - -SCLogOPBuffer *SCLogAllocLogOPBuffer(void); - -int SCLogDebugEnabled(void); - -void SCLogRegisterTests(void); - -void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid); - -SCLogLevel SCLogGetLogLevel(void); - -#endif /* __UTIL_DEBUG_H__ */ diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c deleted file mode 100644 index d9941cd986b9..000000000000 --- a/src/util-decode-mime.c +++ /dev/null @@ -1,3584 +0,0 @@ -/* Copyright (C) 2012 BAE Systems - * Copyright (C) 2020-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author David Abarbanel - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "app-layer-smtp.h" -#include "util-decode-mime.h" -#include "util-ip.h" -#include "util-spm-bs.h" -#include "util-unittest.h" -#include "util-memcmp.h" -#include "util-print.h" -#include "util-validate.h" -#include "rust.h" - -/* Character constants */ -#ifndef CR -#define CR 13 -#define LF 10 -#endif - -#define CRLF "\r\n" -#define COLON 58 -#define DASH 45 -#define PRINTABLE_START 33 -#define PRINTABLE_END 126 -#define UC_START 65 -#define UC_END 90 -#define LC_START 97 -#define LC_END 122 -#define UC_LC_DIFF 32 -#define EOL_LEN 2 - -/* Base-64 constants */ -#define BASE64_STR "Base64" - -/* Mime Constants */ -#define MAX_LINE_LEN 998 /* Def in RFC 2045, excluding CRLF sequence */ -#define MAX_ENC_LINE_LEN 76 /* Def in RFC 2045, excluding CRLF sequence */ -#define MAX_HEADER_NAME 75 /* 75 + ":" = 76 */ -#define MAX_HEADER_VALUE 2000 /* Default - arbitrary limit */ -#define BOUNDARY_BUF 256 -#define CTNT_TYPE_STR "content-type" -#define CTNT_DISP_STR "content-disposition" -#define CTNT_TRAN_STR "content-transfer-encoding" -#define MSG_ID_STR "message-id" -#define MSG_STR "message/" -#define MULTIPART_STR "multipart/" -#define QP_STR "quoted-printable" -#define TXT_STR "text/plain" -#define HTML_STR "text/html" - -/* Memory Usage Constants */ -#define STACK_FREE_NODES 10 - -/* Other Constants */ -#define MAX_IP4_CHARS 15 -#define MAX_IP6_CHARS 39 - -/* Globally hold configuration data */ -static MimeDecConfig mime_dec_config = { true, true, true, NULL, false, false, MAX_HEADER_VALUE }; - -/* Mime Parser String translation */ -static const char *StateFlags[] = { "NONE", - "HEADER_READY", - "HEADER_STARTED", - "HEADER_DONE", - "BODY_STARTED", - "BODY_DONE", - "BODY_END_BOUND", - "PARSE_DONE", - "PARSE_ERROR", - NULL }; - -/* URL executable file extensions */ -static const char *UrlExeExts[] = { ".exe", ".vbs", ".bin", ".cmd", ".bat", ".jar", ".js", ".ps", - ".ps1", ".sh", ".run", ".hta", ".bin", ".elf", NULL }; - -/** - * \brief Function used to print character strings that are not null-terminated - * - * \param log_level The logging level in which to print - * \param label A label for the string to print - * \param src The source string - * \param len The length of the string - * - * \return none - */ -static void PrintChars(int log_level, const char *label, const uint8_t *src, uint32_t len) -{ -#ifdef DEBUG - if (log_level <= sc_log_global_log_level) { - printf("[%s]\n", label); - PrintRawDataFp(stdout, (uint8_t *)src, len); - } -#endif -} - -/** - * \brief Set global config policy - * - * \param config Config policy to set - * \return none - */ -void MimeDecSetConfig(MimeDecConfig *config) -{ - if (config != NULL) { - mime_dec_config = *config; - - /* Set to default */ - if (mime_dec_config.header_value_depth == 0) { - mime_dec_config.header_value_depth = MAX_HEADER_VALUE; - } - } else { - SCLogWarning("Invalid null configuration parameters"); - } -} - -/** - * \brief Get global config policy - * - * \return config data structure - */ -MimeDecConfig * MimeDecGetConfig(void) -{ - return &mime_dec_config; -} - -/** - * \brief Follow the 'next' pointers to the leaf - * - * \param node The root entity - * - * \return Pointer to leaf on 'next' side - * - */ -static MimeDecEntity *findLastSibling(MimeDecEntity *node) -{ - if (node == NULL) - return NULL; - while(node->next != NULL) - node = node->next; - return node; -} - -/** - * \brief Frees a mime entity tree - * - * \param entity The root entity - * - * \return none - * - */ -void MimeDecFreeEntity (MimeDecEntity *entity) -{ - if (entity == NULL) - return; - MimeDecEntity *lastSibling = findLastSibling(entity); - while (entity != NULL) - { - /* move child to next to transform the tree into a list */ - if (entity->child != NULL) { - lastSibling->next = entity->child; - entity->child = NULL; - lastSibling = findLastSibling(lastSibling); - } - - MimeDecEntity *next = entity->next; - DEBUG_VALIDATE_BUG_ON( - (next != NULL && entity == lastSibling) || (next == NULL && entity != lastSibling)); - MimeDecFreeField(entity->field_list); - MimeDecFreeUrl(entity->url_list); - SCFree(entity->filename); - SCFree(entity); - entity = next; - } -} - -/** - * \brief Iteratively frees a header field entry list - * - * \param field The header field - * - * \return none - * - */ -void MimeDecFreeField(MimeDecField *field) -{ - MimeDecField *temp, *curr; - - if (field != NULL) { - - curr = field; - while (curr != NULL) { - temp = curr; - curr = curr->next; - - /* Free contents of node */ - SCFree(temp->name); - SCFree(temp->value); - - /* Now free node data */ - SCFree(temp); - } - } -} - -/** - * \brief Iteratively frees a URL entry list - * - * \param url The url entry - * - * \return none - * - */ -void MimeDecFreeUrl(MimeDecUrl *url) -{ - MimeDecUrl *temp, *curr; - - if (url != NULL) { - - curr = url; - while (curr != NULL) { - temp = curr; - curr = curr->next; - - /* Now free node data */ - SCFree(temp->url); - SCFree(temp); - } - } -} - -/** - * \brief Creates and adds a header field entry to an entity - * - * The entity is optional. If NULL is specified, than a new stand-alone field - * is created. - * - * \param entity The parent entity - * - * \return The field object, or NULL if the operation fails - * - */ -MimeDecField * MimeDecAddField(MimeDecEntity *entity) -{ - MimeDecField *node = SCCalloc(1, sizeof(MimeDecField)); - if (unlikely(node == NULL)) { - return NULL; - } - - /* If list is empty, then set as head of list */ - if (entity->field_list == NULL) { - entity->field_list = node; - } else { - /* Otherwise add to beginning of list since these are out-of-order in - * the message */ - node->next = entity->field_list; - entity->field_list = node; - } - - return node; -} - - -/** - * \brief Searches for header fields with the specified name - * - * \param entity The entity to search - * \param name The header name (lowercase) - * - * \return number of items found - * - */ -int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data) -{ - MimeDecField *curr = entity->field_list; - int found = 0; - - while (curr != NULL) { - /* name is stored lowercase */ - if (strlen(name) == curr->name_len) { - if (SCMemcmp(curr->name, name, curr->name_len) == 0) { - if (DataCallback(curr->value, curr->value_len, data)) - found++; - } - } - curr = curr->next; - } - - return found; -} - -/** - * \brief Searches for a header field with the specified name - * - * \param entity The entity to search - * \param name The header name (lowercase) - * - * \return The field object, or NULL if not found - * - */ -MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name) { - MimeDecField *curr = entity->field_list; - - while (curr != NULL) { - /* name is stored lowercase */ - if (strlen(name) == curr->name_len) { - if (SCMemcmp(curr->name, name, curr->name_len) == 0) { - break; - } - } - curr = curr->next; - } - - return curr; -} - -/** - * \brief Creates and adds a URL entry to the specified entity - * - * The entity is optional and if NULL is specified, then a new list will be created. - * - * \param entity The entity - * - * \return URL entry or NULL if the operation fails - * - */ -static MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity, uint8_t *url, uint32_t url_len, uint8_t flags) -{ - MimeDecUrl *node = SCCalloc(1, sizeof(MimeDecUrl)); - if (unlikely(node == NULL)) { - return NULL; - } - - node->url = url; - node->url_len = url_len; - node->url_flags = flags; - - /* If list is empty, then set as head of list */ - if (entity->url_list == NULL) { - entity->url_list = node; - } else { - /* Otherwise add to beginning of list since these are out-of-order in - * the message */ - node->next = entity->url_list; - entity->url_list = node; - } - - return node; -} - -/** - * \brief Creates and adds a child entity to the specified parent entity - * - * \param parent The parent entity - * - * \return The child entity, or NULL if the operation fails - * - */ -MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) -{ - MimeDecEntity *node = SCCalloc(1, sizeof(MimeDecEntity)); - if (unlikely(node == NULL)) { - return NULL; - } - - /* If parent is NULL then just return the new pointer */ - if (parent != NULL) { - if (parent->child == NULL) { - parent->child = node; - parent->last_child = node; - } else { - parent->last_child->next = node; - parent->last_child = node; - } - } - - return node; -} - -/** - * \brief Creates a mime header field and fills in its values and adds it to the - * specified entity - * - * \param entity Entity in which to add the field - * \param name String containing the name - * \param nlen Length of the name - * \param value String containing the value - * \param vlen Length of the value - * - * \return The field or NULL if the operation fails - * - * name and val are passed as ptr to ptr and each will be set to NULL - * only if the pointer is consumed. This gives the caller an easy way - * to free the memory if not consumed. - */ -static MimeDecField *MimeDecFillField( - MimeDecEntity *entity, uint8_t **name, uint32_t nlen, uint8_t **value, uint32_t vlen) -{ - if (nlen == 0 && vlen == 0) - return NULL; - - MimeDecField *field = MimeDecAddField(entity); - if (unlikely(field == NULL)) { - return NULL; - } - - if (nlen > 0) { - uint8_t *n = *name; - - /* convert to lowercase and store */ - for (uint32_t u = 0; u < nlen; u++) - n[u] = u8_tolower(n[u]); - - field->name = (uint8_t *)n; - field->name_len = nlen; - *name = NULL; - } - - if (vlen > 0) { - field->value = (uint8_t *)*value; - field->value_len = vlen; - *value = NULL; - } - - return field; -} - -/** - * \brief Pushes a node onto a stack and returns the new node. - * - * \param stack The top of the stack - * - * \return pointer to a new node, otherwise NULL if it fails - */ -static MimeDecStackNode * PushStack(MimeDecStack *stack) -{ - /* Attempt to pull from free nodes list */ - MimeDecStackNode *node = stack->free_nodes; - if (node == NULL) { - node = SCCalloc(1, sizeof(MimeDecStackNode)); - if (unlikely(node == NULL)) { - return NULL; - } - } else { - /* Move free nodes pointer over */ - stack->free_nodes = stack->free_nodes->next; - stack->free_nodes_cnt--; - memset(node, 0x00, sizeof(MimeDecStackNode)); - } - - /* Push to top of stack */ - node->next = stack->top; - stack->top = node; - - /* Return a pointer to the top of the stack */ - return node; -} - -/** - * \brief Pops the top node from the stack and returns the next node. - * - * \param stack The top of the stack - * - * \return pointer to the next node, otherwise NULL if no nodes remain - */ -static MimeDecStackNode * PopStack(MimeDecStack *stack) -{ - /* Move stack pointer to next item */ - MimeDecStackNode *curr = stack->top; - if (curr != NULL) { - curr = curr->next; - } - - /* Always free alloc'd memory */ - SCFree(stack->top->bdef); - - /* Now move head to free nodes list */ - if (stack->free_nodes_cnt < STACK_FREE_NODES) { - stack->top->next = stack->free_nodes; - stack->free_nodes = stack->top; - stack->free_nodes_cnt++; - } else { - SCFree(stack->top); - } - stack->top = curr; - - /* Return a pointer to the top of the stack */ - return curr; -} - -/** - * \brief Frees the stack along with the free-nodes list - * - * \param stack The stack pointer - * - * \return none - */ -static void FreeMimeDecStack(MimeDecStack *stack) -{ - MimeDecStackNode *temp, *curr; - - if (stack != NULL) { - /* Top of stack */ - curr = stack->top; - while (curr != NULL) { - temp = curr; - curr = curr->next; - - /* Now free node */ - SCFree(temp->bdef); - SCFree(temp); - } - - /* Free nodes */ - curr = stack->free_nodes; - while (curr != NULL) { - temp = curr; - curr = curr->next; - - /* Now free node */ - SCFree(temp); - } - - SCFree(stack); - } -} - -/** - * \brief Adds a data value to the data values linked list - * - * \param dv The head of the linked list (NULL if new list) - * - * \return pointer to a new node, otherwise NULL if it fails - */ -static DataValue * AddDataValue(DataValue *dv) -{ - DataValue *curr, *node = SCCalloc(1, sizeof(DataValue)); - if (unlikely(node == NULL)) { - return NULL; - } - - if (dv != NULL) { - curr = dv; - while (curr->next != NULL) { - curr = curr->next; - } - - curr->next = node; - } - - return node; -} - -/** - * \brief Frees a linked list of data values starting at the head - * - * \param dv The head of the linked list - * - * \return none - */ -static void FreeDataValue(DataValue *dv) -{ - DataValue *temp, *curr; - - if (dv != NULL) { - curr = dv; - while (curr != NULL) { - temp = curr; - curr = curr->next; - - /* Now free node */ - SCFree(temp->value); - SCFree(temp); - } - } -} - -/** - * \brief Converts a list of data values into a single value (returns dynamically - * allocated memory) - * - * \param dv The head of the linked list (NULL if new list) - * \param olen The output length of the single value - * - * \return pointer to a single value, otherwise NULL if it fails or is zero-length - */ -static uint8_t *GetFullValue(const DataValue *dv, uint32_t *olen) -{ - uint32_t offset = 0; - uint8_t *val = NULL; - uint32_t len = 0; - *olen = 0; - - /* First calculate total length */ - for (const DataValue *curr = dv; curr != NULL; curr = curr->next) { - len += curr->value_len; - } - /* Must have at least one character in the value */ - if (len > 0) { - val = SCCalloc(1, len); - if (unlikely(val == NULL)) { - return NULL; - } - for (const DataValue *curr = dv; curr != NULL; curr = curr->next) { - memcpy(val + offset, curr->value, curr->value_len); - offset += curr->value_len; - } - } - *olen = len; - return val; -} - -/** - * \brief Find a string while searching up to N characters within a source - * buffer - * - * \param src The source string (not null-terminated) - * \param len The length of the source string - * \param find The string to find (null-terminated) - * \param find_len length of the 'find' string - * - * \return Pointer to the position it was found, otherwise NULL if not found - */ -static inline uint8_t *FindBuffer( - const uint8_t *src, uint32_t len, const uint8_t *find, uint16_t find_len) -{ - /* Use utility search function */ - return BasicSearchNocase(src, len, find, find_len); -} - -/** - * \brief Get a line (CRLF or just CR or LF) from a buffer (similar to GetToken) - * - * \param buf The input buffer (not null-terminated) - * \param blen The length of the input buffer - * \param remainPtr Pointer to remaining after tokenizing iteration - * \param tokLen Output token length (if non-null line) - * - * \return Pointer to line - */ -static uint8_t * GetLine(uint8_t *buf, uint32_t blen, uint8_t **remainPtr, - uint32_t *tokLen) -{ - uint32_t i; - uint8_t *tok; - - /* So that it can be used just like strtok_r */ - if (buf == NULL) { - buf = *remainPtr; - } else { - *remainPtr = buf; - } - if (buf == NULL) - return NULL; - - tok = buf; - - /* length must be specified */ - for (i = 0; i < blen && buf[i] != 0; i++) { - - /* Found delimiter */ - if (buf[i] == CR || buf[i] == LF) { - - /* Add another if we find either CRLF or LFCR */ - *remainPtr += (i + 1); - if ((i + 1 < blen) && buf[i] != buf[i + 1] && - (buf[i + 1] == CR || buf[i + 1] == LF)) { - (*remainPtr)++; - } - break; - } - } - - /* If no delimiter found, then point to end of buffer */ - if (buf == *remainPtr) { - (*remainPtr) += i; - } - - /* Calculate token length */ - *tokLen = (buf + i) - tok; - - return tok; -} - -/** - * \brief Get token from buffer and return pointer to it - * - * \param buf The input buffer (not null-terminated) - * \param blen The length of the input buffer - * \param delims Character delimiters (null-terminated) - * \param remainPtr Pointer to remaining after tokenizing iteration - * \param tokLen Output token length (if non-null line) - * - * \return Pointer to token, or NULL if not found - */ -static uint8_t * GetToken(uint8_t *buf, uint32_t blen, const char *delims, - uint8_t **remainPtr, uint32_t *tokenLen) -{ - uint32_t i, j, delimFound = 0; - uint8_t *tok = NULL; - - /* So that it can be used just like strtok_r */ - if (buf == NULL) { - buf = *remainPtr; - } else { - *remainPtr = buf; - } - if (buf == NULL) - return NULL; - - /* Must specify length */ - for (i = 0; i < blen && buf[i] != 0; i++) { - - /* Look for delimiters */ - for (j = 0; delims[j] != 0; j++) { - if (buf[i] == delims[j]) { - /* Data must be found before delimiter matters */ - if (tok != NULL) { - (*remainPtr) += (i + 1); - } - delimFound = 1; - break; - } - } - - /* If at least one non-delimiter found, then a token is found */ - if (tok == NULL && !delimFound) { - tok = buf + i; - } else { - /* Reset delimiter */ - delimFound = 0; - } - - /* If delimiter found, then break out of loop */ - if (buf != *remainPtr) { - break; - } - } - - /* Make sure remaining points to end of buffer if delimiters not found */ - if (tok != NULL) { - if (buf == *remainPtr) { - (*remainPtr) += i; - } - - /* Calculate token length */ - *tokenLen = (buf + i) - tok; - } - - return tok; -} - -/** - * \brief Stores the final MIME header value into the current entity on the - * stack. - * - * \param state The parser state - * - * \return MIME_DEC_OK if stored, otherwise a negative number indicating error - */ -static int StoreMimeHeader(MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - - /* Lets save the most recent header */ - if (state->hname != NULL || state->hvalue != NULL) { - SCLogDebug("Storing last header"); - uint32_t vlen; - uint8_t *val = GetFullValue(state->hvalue, &vlen); - if (val != NULL) { - if (state->hname == NULL) { - SCLogDebug("Error: Invalid parser state - header value without" - " name"); - ret = MIME_DEC_ERR_PARSE; - - } else if (state->stack->top != NULL) { - /* Store each header name and value */ - if (MimeDecFillField(state->stack->top->data, &state->hname, state->hlen, &val, - vlen) == NULL) { - ret = MIME_DEC_ERR_MEM; - } - } else { - SCLogDebug("Error: Stack pointer missing"); - ret = MIME_DEC_ERR_DATA; - } - } else { - if (state->hvalue != NULL) { - /* Memory allocation must have failed since val is NULL */ - ret = MIME_DEC_ERR_MEM; - } - } - - SCFree(val); - SCFree(state->hname); - state->hname = NULL; - FreeDataValue(state->hvalue); - state->hvalue = NULL; - state->hvlen = 0; - } - - return ret; -} - -/** - * \brief Function determines whether a url string points to an executable - * based on file extension only. - * - * \param url The url string - * \param len The url string length - * - * \retval 1 The url points to an EXE - * \retval 0 The url does NOT point to an EXE - */ -static int IsExeUrl(const uint8_t *url, uint32_t len) -{ - int isExeUrl = 0; - uint32_t i, extLen; - uint8_t *ext; - - /* Now check for executable extensions and if not found, cut off at first '/' */ - for (i = 0; UrlExeExts[i] != NULL; i++) { - extLen = strlen(UrlExeExts[i]); - ext = FindBuffer(url, len, (uint8_t *)UrlExeExts[i], (uint16_t)strlen(UrlExeExts[i])); - if (ext != NULL && (ext + extLen - url == (int)len || ext[extLen] == '?')) { - isExeUrl = 1; - break; - } - } - - return isExeUrl; -} - -/** - * \brief Function determines whether a host string is a numeric IP v4 address - * - * \param urlhost The host string - * \param len The host string length - * - * \retval 1 The host is a numeric IP - * \retval 0 The host is NOT a numeric IP - */ -static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) -{ - struct sockaddr_in sa; - char tempIp[MAX_IP4_CHARS + 1]; - - /* Cut off at '/' */ - uint32_t i = 0; - for ( ; i < len && urlhost[i] != 0; i++) { - - if (urlhost[i] == '/') { - break; - } - } - - /* Too many chars */ - if (i > MAX_IP4_CHARS) { - return 0; - } - - /* Create null-terminated string */ - memcpy(tempIp, urlhost, i); - tempIp[i] = '\0'; - - if (!IPv4AddressStringIsValid(tempIp)) - return 0; - - return inet_pton(AF_INET, tempIp, &(sa.sin_addr)); -} - -/** - * \brief Function determines whether a host string is a numeric IP v6 address - * - * \param urlhost The host string - * \param len The host string length - * - * \retval 1 The host is a numeric IP - * \retval 0 The host is NOT a numeric IP - */ -static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) -{ - struct in6_addr in6; - char tempIp[MAX_IP6_CHARS + 1]; - - /* Cut off at '/' */ - uint32_t i = 0; - for (i = 0; i < len && urlhost[i] != 0; i++) { - if (urlhost[i] == '/') { - break; - } - } - - /* Too many chars */ - if (i > MAX_IP6_CHARS) { - return 0; - } - - /* Create null-terminated string */ - memcpy(tempIp, urlhost, i); - tempIp[i] = '\0'; - - if (!IPv6AddressStringIsValid(tempIp)) - return 0; - - return inet_pton(AF_INET6, tempIp, &in6); -} - -/** - * \brief Traverses through the list of URLs for an exact match of the specified - * string - * - * \param entity The MIME entity - * \param url The matching URL string (lowercase) - * \param url_len The matching URL string length - * - * \return URL object or NULL if not found - */ -static MimeDecUrl *FindExistingUrl(MimeDecEntity *entity, uint8_t *url, uint32_t url_len) -{ - MimeDecUrl *curr = entity->url_list; - - while (curr != NULL) { - if (url_len == curr->url_len) { - /* search url and stored url are both in - * lowercase, so we can do an exact match */ - if (SCMemcmp(curr->url, url, url_len) == 0) { - break; - } - } - curr = curr->next; - } - - return curr; -} - -/** - * \brief This function searches a text or html line for a URL string - * - * The URL strings are searched for using the URL schemes defined in the global - * MIME config e.g. "http", "https". - * - * The found URL strings are stored in lowercase and with their schemes - * stripped unless the MIME config flag for log_url_scheme is set. - * - * Numeric IPs, malformed numeric IPs, and URLs pointing to executables are - * also flagged as URLs of interest. - * - * \param line the line - * \param len the line length - * \param state The current parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int FindUrlStrings(const uint8_t *line, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - MimeDecConfig *mdcfg = MimeDecGetConfig(); - uint8_t *fptr, *remptr, *tok = NULL, *tempUrl, *urlHost; - uint32_t tokLen = 0, i, tempUrlLen, urlHostLen; - uint16_t schemeStrLen = 0; - uint8_t flags = 0; - ConfNode *scheme = NULL; - char *schemeStr = NULL; - - if (mdcfg != NULL && mdcfg->extract_urls_schemes == NULL) { - SCLogDebug("Error: MIME config extract_urls_schemes was NULL."); - return MIME_DEC_ERR_DATA; - } - - TAILQ_FOREACH (scheme, &mdcfg->extract_urls_schemes->head, next) { - schemeStr = scheme->val; - // checked against UINT16_MAX when setting in SMTPConfigure - schemeStrLen = (uint16_t)strlen(schemeStr); - - remptr = (uint8_t *)line; - do { - SCLogDebug("Looking for URL String starting with: %s", schemeStr); - - /* Check for token definition */ - fptr = FindBuffer(remptr, len - (remptr - line), (uint8_t *)schemeStr, schemeStrLen); - if (fptr != NULL) { - if (!mdcfg->log_url_scheme) { - fptr += schemeStrLen; /* Strip scheme from stored URL */ - } - tok = GetToken(fptr, len - (fptr - line), " \"\'<>]\t", &remptr, &tokLen); - if (tok == fptr) { - SCLogDebug("Found url string"); - - /* First copy to temp URL string */ - tempUrl = SCMalloc(tokLen); - if (unlikely(tempUrl == NULL)) { - return MIME_DEC_ERR_MEM; - } - - PrintChars(SC_LOG_DEBUG, "RAW URL", tok, tokLen); - - /* Copy over to temp URL while decoding */ - tempUrlLen = 0; - for (i = 0; i < tokLen && tok[i] != 0; i++) { - /* url is all lowercase */ - tempUrl[tempUrlLen] = u8_tolower(tok[i]); - tempUrlLen++; - } - - urlHost = tempUrl; - urlHostLen = tempUrlLen; - if (mdcfg->log_url_scheme) { - /* tempUrl contains the scheme in the string but - * IsIpv4Host & IsPv6Host methods below require - * an input URL string with scheme stripped. Get a - * reference sub-string urlHost which starts with - * the host instead of the scheme. */ - urlHost += schemeStrLen; - urlHostLen -= schemeStrLen; - } - - /* Determine if URL points to an EXE */ - if (IsExeUrl(tempUrl, tempUrlLen)) { - flags |= URL_IS_EXE; - - PrintChars(SC_LOG_DEBUG, "EXE URL", tempUrl, tempUrlLen); - } - - /* Make sure remaining URL exists */ - if (tempUrlLen > 0) { - if (!(FindExistingUrl(entity, tempUrl, tempUrlLen))) { - /* Now look for numeric IP */ - if (IsIpv4Host(urlHost, urlHostLen)) { - flags |= URL_IS_IP4; - - PrintChars(SC_LOG_DEBUG, "IP URL4", tempUrl, tempUrlLen); - } else if (IsIpv6Host(urlHost, urlHostLen)) { - flags |= URL_IS_IP6; - - PrintChars(SC_LOG_DEBUG, "IP URL6", tempUrl, tempUrlLen); - } - - /* Add URL list item */ - MimeDecAddUrl(entity, tempUrl, tempUrlLen, flags); - } else { - SCFree(tempUrl); - } - } else { - SCFree(tempUrl); - } - - /* Reset flags for next URL */ - flags = 0; - } - } - } while (fptr != NULL); - } - - return ret; -} - -/** - * \brief This function is a pre-processor for handling decoded data chunks that - * then invokes the caller's callback function for further processing - * - * \param chunk The decoded chunk - * \param len The decoded chunk length (varies) - * \param state The current parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - uint8_t *remainPtr, *tok; - uint32_t tokLen; - - if ((state->stack != NULL) && (state->stack->top != NULL) && - (state->stack->top->data != NULL)) { - MimeDecConfig *mdcfg = MimeDecGetConfig(); - if (mdcfg != NULL && mdcfg->extract_urls) { - MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - /* If plain text or html, then look for URLs */ - if (((entity->ctnt_flags & CTNT_IS_TEXT) || - (entity->ctnt_flags & CTNT_IS_MSG) || - (entity->ctnt_flags & CTNT_IS_HTML)) && - ((entity->ctnt_flags & CTNT_IS_ATTACHMENT) == 0)) { - - /* Parse each line one by one */ - remainPtr = (uint8_t *)chunk; - do { - tok = GetLine( - remainPtr, len - (remainPtr - (uint8_t *)chunk), &remainPtr, &tokLen); - if (tok != remainPtr) { - /* Search line for URL */ - ret = FindUrlStrings(tok, tokLen, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: FindUrlStrings() function" - " failed: %d", - ret); - break; - } - } - } while (tok != remainPtr && remainPtr - (uint8_t *)chunk < (int)len); - } - } - - /* Now invoke callback */ - if (state->DataChunkProcessorFunc != NULL) { - ret = state->DataChunkProcessorFunc(chunk, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: state->dataChunkProcessor() callback function" - " failed"); - } - } - } else { - SCLogDebug("Error: Stack pointer missing"); - ret = MIME_DEC_ERR_DATA; - } - - /* Reset data chunk buffer */ - state->data_chunk_len = 0; - - /* Mark body / file as no longer at beginning */ - state->body_begin = 0; - - return ret; -} - -/** - * \brief Processes a remainder (line % 4 = remainder) from the previous line - * such that all base64 decoding attempts are divisible by 4 - * - * \param buf The current line - * \param len The length of the line - * \param state The current parser state - * \param force Flag indicating whether decoding should always occur - * - * \return Number of bytes consumed from `buf` - */ -static uint32_t ProcessBase64Remainder( - const uint8_t *buf, const uint32_t len, MimeDecParseState *state, int force) -{ - uint32_t buf_consumed = 0; /* consumed bytes from 'buf' */ - uint8_t cnt = 0; - uint8_t block[B64_BLOCK]; - - SCLogDebug("len %u force %d", len, force); - - /* should be impossible, but lets be defensive */ - DEBUG_VALIDATE_BUG_ON(state->bvr_len > B64_BLOCK); - if (state->bvr_len > B64_BLOCK) { - state->bvr_len = 0; - return 0; - } - - /* Strip spaces in remainder */ - for (uint8_t i = 0; i < state->bvr_len; i++) { - if (IsBase64Alphabet(state->bvremain[i])) { - block[cnt++] = state->bvremain[i]; - } - } - - /* if we don't have 4 bytes see if we can fill it from `buf` */ - if (buf && len > 0 && cnt != B64_BLOCK) { - for (uint32_t i = 0; i < len && cnt < B64_BLOCK; i++) { - if (IsBase64Alphabet(buf[i])) { - block[cnt++] = buf[i]; - } - buf_consumed++; - } - DEBUG_VALIDATE_BUG_ON(cnt > B64_BLOCK); - for (uint32_t i = 0; i < cnt; i++) { - state->bvremain[i] = block[i]; - } - state->bvr_len = cnt; - } else if (!force && cnt != B64_BLOCK) { - SCLogDebug("incomplete data and no buffer to backfill"); - return 0; - } - - /* in force mode pad the block */ - if (force && cnt != B64_BLOCK) { - SCLogDebug("force and cnt %u != %u", cnt, B64_BLOCK); - for (uint8_t i = state->bvr_len; i < B64_BLOCK; i++) { - state->bvremain[state->bvr_len++] = '='; - } - } - - /* If data chunk buffer will be full, then clear it now */ - if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { - - /* Invoke pre-processor and callback */ - uint32_t ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); - } - } - - if (state->bvr_len == B64_BLOCK || force) { - uint32_t consumed_bytes = 0; - uint32_t remdec = 0; - const uint32_t avail_space = DATA_CHUNK_SIZE - state->data_chunk_len; - PrintChars(SC_LOG_DEBUG, "BASE64 INPUT (bvremain)", state->bvremain, state->bvr_len); - Base64Ecode code = DecodeBase64(state->data_chunk + state->data_chunk_len, avail_space, - state->bvremain, state->bvr_len, &consumed_bytes, &remdec, BASE64_MODE_RFC2045); - SCLogDebug("DecodeBase64 result %u", code); - if (remdec > 0 && (code == BASE64_ECODE_OK || code == BASE64_ECODE_BUF)) { - PrintChars(SC_LOG_DEBUG, "BASE64 DECODED (bvremain)", - state->data_chunk + state->data_chunk_len, remdec); - - state->data_chunk_len += remdec; - - /* If data chunk buffer is now full, then clear */ - if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { - - /* Invoke pre-processor and callback */ - uint32_t ret = - ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessDecodedDataChunk() function " - "failed"); - } - } - } else if (code == BASE64_ECODE_ERR) { - /* Track failed base64 */ - state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; - state->msg->anomaly_flags |= ANOM_INVALID_BASE64; - SCLogDebug("Error: DecodeBase64() function failed"); - PrintChars(SC_LOG_DEBUG, "Base64 failed string", state->bvremain, state->bvr_len); - } - - /* Reset remaining */ - state->bvr_len = 0; - } - - DEBUG_VALIDATE_BUG_ON(buf_consumed > len); - return buf_consumed; -} - -static inline MimeDecRetCode ProcessBase64BodyLineCopyRemainder( - const uint8_t *buf, const uint32_t buf_len, const uint32_t offset, MimeDecParseState *state) -{ - DEBUG_VALIDATE_BUG_ON(offset > buf_len); - if (offset > buf_len) - return MIME_DEC_ERR_DATA; - - for (uint32_t i = offset; i < buf_len; i++) { - // Skip any characters outside of the base64 alphabet as per RFC 2045 - if (IsBase64Alphabet(buf[i])) { - DEBUG_VALIDATE_BUG_ON(state->bvr_len >= B64_BLOCK); - if (state->bvr_len >= B64_BLOCK) - return MIME_DEC_ERR_DATA; - state->bvremain[state->bvr_len++] = buf[i]; - } - } - return MIME_DEC_OK; -} - -/** - * \brief Processes a body line by base64-decoding and passing to the data chunk - * processing callback function when the buffer is read - * - * \param buf The current line - * \param len The length of the line - * \param state The current parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - uint32_t numDecoded, remaining = len, offset = 0; - - /* Track long line TODO should we count space padding too? */ - if (len > MAX_ENC_LINE_LEN) { - state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; - state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; - SCLogDebug("max encoded input line length exceeded %u > %u", len, MAX_ENC_LINE_LEN); - } - - if (state->bvr_len + len < B64_BLOCK) { - return ProcessBase64BodyLineCopyRemainder(buf, len, 0, state); - } - - /* First process remaining from previous line. We will consume - * state->bvremain, filling it from 'buf' until we have a properly - * sized block. Spaces are skipped (rfc2045). If state->bvr_len - * is not 0 after processing we have no data left at 'buf'. */ - if (state->bvr_len > 0) { - uint32_t consumed = ProcessBase64Remainder(buf, len, state, 0); - DEBUG_VALIDATE_BUG_ON(consumed > len); - if (consumed > len) - return MIME_DEC_ERR_PARSE; - - uint32_t left = len - consumed; - if (left < B64_BLOCK) { - DEBUG_VALIDATE_BUG_ON(left + state->bvr_len > B64_BLOCK); - return ProcessBase64BodyLineCopyRemainder(buf, len, consumed, state); - } - - remaining -= consumed; - offset = consumed; - } - - while (remaining > 0 && remaining >= B64_BLOCK) { - uint32_t consumed_bytes = 0; - uint32_t avail_space = DATA_CHUNK_SIZE - state->data_chunk_len; - PrintChars(SC_LOG_DEBUG, "BASE64 INPUT (line)", buf + offset, remaining); - Base64Ecode code = DecodeBase64(state->data_chunk + state->data_chunk_len, avail_space, - buf + offset, remaining, &consumed_bytes, &numDecoded, BASE64_MODE_RFC2045); - SCLogDebug("DecodeBase64 result %u", code); - DEBUG_VALIDATE_BUG_ON(consumed_bytes > remaining); - if (consumed_bytes > remaining) - return MIME_DEC_ERR_PARSE; - - uint32_t leftover_bytes = remaining - consumed_bytes; - if (numDecoded > 0 && (code == BASE64_ECODE_OK || code == BASE64_ECODE_BUF)) { - PrintChars(SC_LOG_DEBUG, "BASE64 DECODED (line)", - state->data_chunk + state->data_chunk_len, numDecoded); - - state->data_chunk_len += numDecoded; - - if ((int)(DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { - SCLogDebug("Error: Invalid Chunk length: %u", state->data_chunk_len); - return MIME_DEC_ERR_PARSE; - } - /* If buffer full, then invoke callback */ - if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { - /* Invoke pre-processor and callback */ - ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); - break; - } - } - } else if (code == BASE64_ECODE_ERR) { - /* Track failed base64 */ - state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; - state->msg->anomaly_flags |= ANOM_INVALID_BASE64; - SCLogDebug("Error: DecodeBase64() function failed"); - return MIME_DEC_ERR_DATA; - } - - /* corner case: multiples spaces in the last data, leading it to exceed the block - * size. We strip of spaces this while storing it in bvremain */ - if (consumed_bytes == 0 && leftover_bytes > B64_BLOCK) { - DEBUG_VALIDATE_BUG_ON(state->bvr_len != 0); - ret = ProcessBase64BodyLineCopyRemainder(buf, len, offset, state); - break; - } else if (leftover_bytes > 0 && leftover_bytes <= B64_BLOCK) { - /* If remaining is 4 by this time, we encountered spaces during processing */ - DEBUG_VALIDATE_BUG_ON(state->bvr_len != 0); - ret = ProcessBase64BodyLineCopyRemainder(buf, len, offset + consumed_bytes, state); - break; - } - - /* Update counts */ - remaining = leftover_bytes; - offset += consumed_bytes; - } - if (ret == MIME_DEC_OK && state->data_chunk_len > 0) { - ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); - } - return ret; -} - -/** - * \brief Decoded a hex character into its equivalent byte value for - * quoted-printable decoding - * - * \param h The hex char - * - * \return byte value on success, -1 if failed - **/ -static int8_t DecodeQPChar(char h) -{ - int8_t res = 0; - - /* 0-9 */ - if (h >= 48 && h <= 57) { - res = h - 48; - } else if (h >= 65 && h <= 70) { - /* A-F */ - res = h - 55; - } else { - /* Invalid */ - res = -1; - } - - return res; - -} - -/** - * \brief Processes a quoted-printable encoded body line by decoding and passing - * to the data chunk processing callback function when the buffer is read - * - * \param buf The current line - * \param len The length of the line - * \param state The current parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessQuotedPrintableBodyLine(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - uint32_t remaining, offset; - MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - uint8_t c, h1, h2, val; - int16_t res; - - /* Track long line */ - if (len > MAX_ENC_LINE_LEN) { - state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; - state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; - SCLogDebug("Error: Max encoded input line length exceeded %u > %u", - len, MAX_ENC_LINE_LEN); - } - if (len == 0) { - memcpy(state->data_chunk + state->data_chunk_len, buf + len, - state->current_line_delimiter_len); - state->data_chunk_len += state->current_line_delimiter_len; - return ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); - } - - remaining = len; - offset = 0; - while (remaining > 0) { - - c = *(buf + offset); - - /* Copy over normal character */ - if (c != '=') { - state->data_chunk[state->data_chunk_len] = c; - state->data_chunk_len++; - - /* Add CRLF sequence if end of line, unless its a partial line */ - if (remaining == 1 && state->current_line_delimiter_len > 0) { - memcpy(state->data_chunk + state->data_chunk_len, CRLF, EOL_LEN); - state->data_chunk_len += EOL_LEN; - } - } else if (remaining > 1) { - /* If last character handle as soft line break by ignoring, - otherwise process as escaped '=' character */ - - /* Not enough characters */ - if (remaining < 3) { - entity->anomaly_flags |= ANOM_INVALID_QP; - state->msg->anomaly_flags |= ANOM_INVALID_QP; - SCLogDebug("Error: Quoted-printable decoding failed"); - } else { - h1 = *(buf + offset + 1); - res = DecodeQPChar(h1); - if (res < 0) { - entity->anomaly_flags |= ANOM_INVALID_QP; - state->msg->anomaly_flags |= ANOM_INVALID_QP; - SCLogDebug("Error: Quoted-printable decoding failed"); - } else { - val = (uint8_t)(res << 4); /* Shift result left */ - h2 = *(buf + offset + 2); - res = DecodeQPChar(h2); - if (res < 0) { - entity->anomaly_flags |= ANOM_INVALID_QP; - state->msg->anomaly_flags |= ANOM_INVALID_QP; - SCLogDebug("Error: Quoted-printable decoding failed"); - } else { - /* Decoding sequence succeeded */ - val += res; - - state->data_chunk[state->data_chunk_len] = val; - state->data_chunk_len++; - - /* Add CRLF sequence if end of line, unless for partial lines */ - if (remaining == 3 && state->current_line_delimiter_len > 0) { - memcpy(state->data_chunk + state->data_chunk_len, - CRLF, EOL_LEN); - state->data_chunk_len += EOL_LEN; - } - - /* Account for extra 2 characters in 3-character QP - * sequence */ - remaining -= 2; - offset += 2; - } - } - } - } - - /* Change by 1 */ - remaining--; - offset++; - - /* If buffer full, then invoke callback */ - if (DATA_CHUNK_SIZE - state->data_chunk_len < EOL_LEN + 1) { - - /* Invoke pre-processor and callback */ - ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, - state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessDecodedDataChunk() function " - "failed"); - } - } - } - - return ret; -} - -/** - * \brief Processes a body line by base64-decoding (if applicable) and passing to - * the data chunk processing callback function - * - * \param buf The current line - * \param len The length of the line - * \param state The current parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessBodyLine(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - uint32_t remaining, offset, avail, tobuf; - MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - - SCLogDebug("Processing body line"); - - /* Process base-64 content if enabled */ - MimeDecConfig *mdcfg = MimeDecGetConfig(); - if (mdcfg != NULL && mdcfg->decode_base64 && - (entity->ctnt_flags & CTNT_IS_BASE64)) { - - ret = ProcessBase64BodyLine(buf, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessBase64BodyLine() function failed"); - } - } else if (mdcfg != NULL && mdcfg->decode_quoted_printable && - (entity->ctnt_flags & CTNT_IS_QP)) { - /* Process quoted-printable content if enabled */ - ret = ProcessQuotedPrintableBodyLine(buf, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessQuotedPrintableBodyLine() function " - "failed"); - } - } else { - /* Process non-decoded content */ - remaining = len; - offset = 0; - while (remaining > 0) { - /* Plan to add CRLF to the end of each line */ - avail = DATA_CHUNK_SIZE - state->data_chunk_len; - tobuf = avail > remaining ? remaining : avail; - - /* Copy over to buffer */ - memcpy(state->data_chunk + state->data_chunk_len, buf + offset, tobuf); - state->data_chunk_len += tobuf; - - if ((int) (DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { - SCLogDebug("Error: Invalid Chunk length: %u", - state->data_chunk_len); - ret = MIME_DEC_ERR_PARSE; - break; - } - - /* If buffer full, then invoke callback */ - if (DATA_CHUNK_SIZE - state->data_chunk_len == 0) { - /* Invoke pre-processor and callback */ - ret = ProcessDecodedDataChunk(state->data_chunk, - state->data_chunk_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessDecodedDataChunk() function " - "failed"); - } - } - - remaining -= tobuf; - offset += tobuf; - } - if (ret == MIME_DEC_OK) { - ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessDecodedDataChunk() function " - "failed"); - } - } - // keep end of line for next call (and skip it on completion) - memcpy(state->data_chunk, buf + offset, state->current_line_delimiter_len); - state->data_chunk_len = state->current_line_delimiter_len; - } - - return ret; -} - -/** - * \brief Find the start of a header name on the current line - * - * \param buf The input line (not null-terminated) - * \param blen The length of the input line - * \param glen The output length of the header name - * - * \return Pointer to header name, or NULL if not found - */ -static uint8_t * FindMimeHeaderStart(const uint8_t *buf, uint32_t blen, uint32_t *hlen) -{ - uint32_t i, valid = 0; - uint8_t *hname = NULL; - - /* Init */ - *hlen = 0; - - /* Look for sequence of printable characters followed by ':', or - CRLF then printable characters followed by ':' */ - for (i = 0; i < blen && buf[i] != 0; i++) { - - /* If ready for printable characters and found one, then increment */ - if (buf[i] != COLON && buf[i] >= PRINTABLE_START && - buf[i] <= PRINTABLE_END) { - valid++; - } else if (valid > 0 && buf[i] == COLON) { - /* If ready for printable characters, found some, and found colon - * delimiter, then a match is found */ - hname = (uint8_t *) buf + i - valid; - *hlen = valid; - break; - } else { - /* Otherwise reset and quit */ - break; - } - } - - return hname; -} - -/** - * \brief Find full header name and value on the current line based on the - * current state - * - * \param buf The current line (no CRLF) - * \param blen The length of the current line - * \param state The current state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int FindMimeHeader(const uint8_t *buf, uint32_t blen, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - uint8_t *hname, *hval = NULL; - DataValue *dv; - uint32_t hlen, vlen; - int finish_header = 0, new_header = 0; - MimeDecConfig *mdcfg = MimeDecGetConfig(); - - DEBUG_VALIDATE_BUG_ON(state->current_line_delimiter_len == 0 && blen < SMTP_LINE_BUFFER_LIMIT); - - /* Find first header */ - hname = FindMimeHeaderStart(buf, blen, &hlen); - if (hname != NULL) { - - /* Warn and track but don't do anything yet */ - if (hlen > MAX_HEADER_NAME) { - state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_NAME; - state->msg->anomaly_flags |= ANOM_LONG_HEADER_NAME; - SCLogDebug("Error: Header name exceeds limit (%u > %u)", - hlen, MAX_HEADER_NAME); - } - - /* Value starts after 'header:' (normalize spaces) */ - hval = hname + hlen + 1; - if (hval - buf >= (int)blen) { - SCLogDebug("No Header value found"); - hval = NULL; - } else { - while (hval[0] == ' ') { - - /* If last character before end of bounds, set to NULL */ - if (hval - buf >= (int)blen - 1) { - SCLogDebug("No Header value found"); - hval = NULL; - break; - } - - hval++; - } - } - - /* If new header found, then previous header is finished */ - if (state->state_flag == HEADER_STARTED) { - finish_header = 1; - } - - /* Now process new header */ - new_header = 1; - - /* Must wait for next line to determine if finished */ - state->state_flag = HEADER_STARTED; - } else if (blen == 0) { - /* Found body */ - /* No more headers */ - state->state_flag = HEADER_DONE; - - finish_header = 1; - - SCLogDebug("All Header processing finished"); - } else if (state->state_flag == HEADER_STARTED) { - /* Found multi-line value (ie. Received header) */ - /* If max header value exceeded, flag it */ - vlen = blen; - if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { - SCLogDebug("Error: Header value of length (%u) is too long", - state->hvlen + vlen); - vlen = mdcfg->header_value_depth - state->hvlen; - state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; - state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; - } - if (vlen > 0) { - dv = AddDataValue(state->hvalue); - if (dv == NULL) { - return MIME_DEC_ERR_MEM; - } - if (state->hvalue == NULL) { - state->hvalue = dv; - } - - dv->value = SCMalloc(vlen); - if (unlikely(dv->value == NULL)) { - return MIME_DEC_ERR_MEM; - } - memcpy(dv->value, buf, vlen); - dv->value_len = vlen; - state->hvlen += vlen; - } - } else { - /* Likely a body without headers */ - SCLogDebug("No headers found"); - - state->state_flag = BODY_STARTED; - - /* Flag beginning of body */ - state->body_begin = 1; - state->body_end = 0; - - // Begin the body md5 computation if config asks so - if (MimeDecGetConfig()->body_md5 && state->md5_ctx == NULL) { - state->md5_ctx = SCMd5New(); - SCMd5Update(state->md5_ctx, buf, blen + state->current_line_delimiter_len); - } - - ret = ProcessBodyLine(buf, blen, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessBodyLine() function failed"); - return ret; - } - } - - /* If we need to finish a header, then do so below and then cleanup */ - if (finish_header) { - /* Store the header value */ - ret = StoreMimeHeader(state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: StoreMimeHeader() function failed"); - return ret; - } - } - - /* When next header is found, we always create a new one */ - if (new_header) { - /* Copy name and value to state */ - state->hname = SCMalloc(hlen); - if (unlikely(state->hname == NULL)) { - return MIME_DEC_ERR_MEM; - } - memcpy(state->hname, hname, hlen); - state->hlen = hlen; - - if (state->hvalue != NULL) { - SCLogDebug("Error: Parser failed due to unexpected header " - "value"); - return MIME_DEC_ERR_DATA; - } - - if (hval != NULL) { - /* If max header value exceeded, flag it */ - vlen = blen - (hval - buf); - if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { - SCLogDebug("Error: Header value of length (%u) is too long", - state->hvlen + vlen); - vlen = mdcfg->header_value_depth - state->hvlen; - state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; - state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; - } - - if (vlen > 0) { - state->hvalue = AddDataValue(NULL); - if (state->hvalue == NULL) { - return MIME_DEC_ERR_MEM; - } - state->hvalue->value = SCMalloc(vlen); - if (unlikely(state->hvalue->value == NULL)) { - return MIME_DEC_ERR_MEM; - } - memcpy(state->hvalue->value, hval, vlen); - state->hvalue->value_len = vlen; - state->hvlen += vlen; - } - } - } - - return ret; -} - -/** - * \brief Processes the current line for mime headers and also does post-processing - * when all headers found - * - * \param buf The current line - * \param len The length of the line - * \param state The current parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - MimeDecField *field; - uint8_t *rptr = NULL; - uint32_t blen = 0; - MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; - uint8_t bptr[RS_MIME_MAX_TOKEN_LEN]; - - /* Look for mime header in current line */ - ret = FindMimeHeader(buf, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: FindMimeHeader() function failed: %d", ret); - return ret; - } - - /* Post-processing after all headers done */ - if (state->state_flag == HEADER_DONE) { - /* First determine encoding by looking at Content-Transfer-Encoding */ - field = MimeDecFindField(entity, CTNT_TRAN_STR); - if (field != NULL) { - /* Look for base64 */ - if (FindBuffer(field->value, field->value_len, (const uint8_t *)BASE64_STR, - (uint16_t)strlen(BASE64_STR))) { - SCLogDebug("Base64 encoding found"); - entity->ctnt_flags |= CTNT_IS_BASE64; - } else if (FindBuffer(field->value, field->value_len, (const uint8_t *)QP_STR, - (uint16_t)strlen(QP_STR))) { - /* Look for quoted-printable */ - SCLogDebug("quoted-printable encoding found"); - entity->ctnt_flags |= CTNT_IS_QP; - } - } - - /* Check for file attachment in content disposition */ - field = MimeDecFindField(entity, CTNT_DISP_STR); - if (field != NULL) { - bool truncated_name = false; - if (rs_mime_find_header_token(field->value, field->value_len, - (const uint8_t *)"filename", strlen("filename"), &bptr, &blen)) { - SCLogDebug("File attachment found in disposition"); - entity->ctnt_flags |= CTNT_IS_ATTACHMENT; - - if (blen > RS_MIME_MAX_TOKEN_LEN) { - blen = RS_MIME_MAX_TOKEN_LEN; - truncated_name = true; - } - - /* Copy over using dynamic memory */ - entity->filename = SCMalloc(blen); - if (unlikely(entity->filename == NULL)) { - return MIME_DEC_ERR_MEM; - } - memcpy(entity->filename, bptr, blen); - entity->filename_len = blen; - - if (truncated_name) { - state->stack->top->data->anomaly_flags |= ANOM_LONG_FILENAME; - state->msg->anomaly_flags |= ANOM_LONG_FILENAME; - } - } - } - - /* Check for boundary, encapsulated message, and file name in Content-Type */ - field = MimeDecFindField(entity, CTNT_TYPE_STR); - if (field != NULL) { - /* Check if child entity boundary definition found */ - // RS_MIME_MAX_TOKEN_LEN is RS_MIME_MAX_TOKEN_LEN on the rust side - if (rs_mime_find_header_token(field->value, field->value_len, - (const uint8_t *)"boundary", strlen("boundary"), &bptr, &blen)) { - state->found_child = 1; - entity->ctnt_flags |= CTNT_IS_MULTIPART; - - if (blen > (BOUNDARY_BUF - 2)) { - state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; - return MIME_DEC_ERR_PARSE; - } - - /* Store boundary in parent node */ - state->stack->top->bdef = SCMalloc(blen); - if (unlikely(state->stack->top->bdef == NULL)) { - return MIME_DEC_ERR_MEM; - } - memcpy(state->stack->top->bdef, bptr, blen); - state->stack->top->bdef_len = (uint16_t)blen; - } - - /* Look for file name (if not already found) */ - if (!(entity->ctnt_flags & CTNT_IS_ATTACHMENT)) { - bool truncated_name = false; - if (rs_mime_find_header_token(field->value, field->value_len, - (const uint8_t *)"name", strlen("name"), &bptr, &blen)) { - SCLogDebug("File attachment found"); - entity->ctnt_flags |= CTNT_IS_ATTACHMENT; - - if (blen > RS_MIME_MAX_TOKEN_LEN) { - blen = RS_MIME_MAX_TOKEN_LEN; - truncated_name = true; - } - - /* Copy over using dynamic memory */ - entity->filename = SCMalloc(blen); - if (unlikely(entity->filename == NULL)) { - return MIME_DEC_ERR_MEM; - } - memcpy(entity->filename, bptr, blen); - entity->filename_len = blen; - - if (truncated_name) { - state->stack->top->data->anomaly_flags |= ANOM_LONG_FILENAME; - state->msg->anomaly_flags |= ANOM_LONG_FILENAME; - } - } - } - - /* Pull out short-hand content type */ - entity->ctnt_type = GetToken(field->value, field->value_len, " \r\n;", - &rptr, &entity->ctnt_type_len); - if (entity->ctnt_type != NULL) { - /* Check for encapsulated message */ - if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, (const uint8_t *)MSG_STR, - (uint16_t)strlen(MSG_STR))) { - SCLogDebug("Found encapsulated message entity"); - - entity->ctnt_flags |= CTNT_IS_ENV; - - /* Create and push child to stack */ - MimeDecEntity *child = MimeDecAddEntity(entity); - if (child == NULL) - return MIME_DEC_ERR_MEM; - child->ctnt_flags |= (CTNT_IS_ENCAP | CTNT_IS_MSG); - PushStack(state->stack); - state->stack->top->data = child; - - /* Mark as encapsulated child */ - state->stack->top->is_encap = 1; - - /* Ready to parse headers */ - state->state_flag = HEADER_READY; - } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, - (const uint8_t *)MULTIPART_STR, - (uint16_t)strlen(MULTIPART_STR))) { - /* Check for multipart */ - SCLogDebug("Found multipart entity"); - entity->ctnt_flags |= CTNT_IS_MULTIPART; - } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, - (const uint8_t *)TXT_STR, (uint16_t)strlen(TXT_STR))) { - /* Check for plain text */ - SCLogDebug("Found plain text entity"); - entity->ctnt_flags |= CTNT_IS_TEXT; - } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, - (const uint8_t *)HTML_STR, (uint16_t)strlen(HTML_STR))) { - /* Check for html */ - SCLogDebug("Found html entity"); - entity->ctnt_flags |= CTNT_IS_HTML; - } - } - } - - /* Store pointer to Message-ID */ - field = MimeDecFindField(entity, MSG_ID_STR); - if (field != NULL) { - entity->msg_id = field->value; - entity->msg_id_len = field->value_len; - } - - /* Flag beginning of body */ - state->body_begin = 1; - state->body_end = 0; - } - - return ret; -} - -/** - * \brief Indicates to the parser that the body of an entity has completed - * processing on the previous line - * - * \param state The current parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ - -static int ProcessBodyComplete(MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - - SCLogDebug("Process body complete called"); - - /* Mark the file as hitting the end */ - state->body_end = 1; - - if (state->bvr_len > 0) { - SCLogDebug("Found (%u) remaining base64 bytes not processed", - state->bvr_len); - - /* Process the remainder */ - ret = ProcessBase64Remainder(NULL, 0, state, 1); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessBase64BodyLine() function failed"); - } - } - - MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; - if ((entity->ctnt_flags & (CTNT_IS_BASE64 | CTNT_IS_QP)) == 0) { - // last eol of plaintext is the beginning of the boundary - state->data_chunk_len = 0; - } - /* Invoke pre-processor and callback with remaining data */ - ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); - } - - /* Now reset */ - state->body_begin = 0; - state->body_end = 0; - - return ret; -} - -/** - * \brief When a mime boundary is found, look for end boundary and also do stack - * management - * - * \param buf The current line - * \param len The length of the line - * \param bdef_len The length of the current boundary - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessMimeBoundary( - const uint8_t *buf, uint32_t len, uint16_t bdef_len, MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - uint8_t *rptr; - MimeDecEntity *child; - - SCLogDebug("PROCESSING BOUNDARY - START: %d", - state->state_flag); - - /* If previous line was not an end boundary, then we process the body as - * completed */ - if (state->state_flag != BODY_END_BOUND) { - - /* First lets complete the body */ - ret = ProcessBodyComplete(state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessBodyComplete() function failed"); - return ret; - } - } else { - /* If last line was an end boundary, then now we are ready to parse - * headers again */ - state->state_flag = HEADER_READY; - } - - /* Update remaining buffer */ - rptr = (uint8_t *) buf + bdef_len + 2; - - /* If entity is encapsulated and current and parent didn't define the boundary, - * then pop out */ - if (state->stack->top->is_encap && state->stack->top->bdef_len == 0) { - - if (state->stack->top->next == NULL) { - SCLogDebug("Error: Missing parent entity from stack"); - return MIME_DEC_ERR_DATA; - } - - if (state->stack->top->next->bdef_len == 0) { - - SCLogDebug("POPPED ENCAPSULATED CHILD FROM STACK: %p=%p", - state->stack->top, state->stack->top->data); - - /* If end of boundary found, pop the child off the stack */ - PopStack(state->stack); - if (state->stack->top == NULL) { - SCLogDebug("Error: Message is malformed"); - return MIME_DEC_ERR_DATA; - } - } - } - - /* Now check for end of nested boundary */ - if (len - (rptr - buf) > 1 && rptr[0] == DASH && rptr[1] == DASH) { - SCLogDebug("FOUND END BOUNDARY, POPPING: %p=%p", - state->stack->top, state->stack->top->data); - - /* If end of boundary found, pop the child off the stack */ - PopStack(state->stack); - if (state->stack->top == NULL) { - SCLogDebug("Error: Message is malformed"); - return MIME_DEC_ERR_DATA; - } - - /* If current is an encapsulated message with a boundary definition, - * then pop him as well */ - if (state->stack->top->is_encap && state->stack->top->bdef_len != 0) { - SCLogDebug("FOUND END BOUNDARY AND ENCAP, POPPING: %p=%p", - state->stack->top, state->stack->top->data); - - PopStack(state->stack); - if (state->stack->top == NULL) { - SCLogDebug("Error: Message is malformed"); - return MIME_DEC_ERR_DATA; - } - } - - state->state_flag = BODY_END_BOUND; - } else if (state->found_child) { - /* Otherwise process new child */ - SCLogDebug("Child entity created"); - - /* Create and push child to stack */ - child = MimeDecAddEntity(state->stack->top->data); - if (child == NULL) - return MIME_DEC_ERR_MEM; - child->ctnt_flags |= CTNT_IS_BODYPART; - PushStack(state->stack); - state->stack->top->data = child; - - /* Reset flag */ - state->found_child = 0; - } else { - /* Otherwise process sibling */ - if (state->stack->top->next == NULL) { - SCLogDebug("Error: Missing parent entity from stack"); - return MIME_DEC_ERR_DATA; - } - - SCLogDebug("SIBLING CREATED, POPPING PARENT: %p=%p", - state->stack->top, state->stack->top->data); - - /* First pop current to get access to parent */ - PopStack(state->stack); - if (state->stack->top == NULL) { - SCLogDebug("Error: Message is malformed"); - return MIME_DEC_ERR_DATA; - } - - /* Create and push child to stack */ - child = MimeDecAddEntity(state->stack->top->data); - if (child == NULL) - return MIME_DEC_ERR_MEM; - child->ctnt_flags |= CTNT_IS_BODYPART; - PushStack(state->stack); - state->stack->top->data = child; - } - - /* After boundary look for headers */ - if (state->state_flag != BODY_END_BOUND) { - state->state_flag = HEADER_READY; - } - - SCLogDebug("PROCESSING BOUNDARY - END: %d", state->state_flag); - return ret; -} - -/** - * \brief Processes the MIME Entity body based on the input line and current - * state of the parser - * - * \param buf The current line - * \param len The length of the line - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessMimeBody(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - uint8_t temp[BOUNDARY_BUF]; - uint8_t *bstart; - int body_found = 0; - uint16_t tlen; - - /* pass empty lines on if we're parsing the body, otherwise we have no use - * for them, and in fact they would disrupt the state tracking */ - if (len == 0) { - /* don't start a new body after an end bound based on an empty line */ - if (state->state_flag == BODY_END_BOUND) { - SCLogDebug("skip empty line"); - return MIME_DEC_OK; - } else if (state->state_flag == HEADER_DONE) { - SCLogDebug("empty line, lets see if we skip it. We're in state %s", - MimeDecParseStateGetStatus(state)); - MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; - MimeDecConfig *mdcfg = MimeDecGetConfig(); - if (entity != NULL && mdcfg != NULL) { - if (mdcfg->decode_base64 && (entity->ctnt_flags & CTNT_IS_BASE64)) { - SCLogDebug("skip empty line"); - return MIME_DEC_OK; - } - SCLogDebug("not skipping empty line"); - } - } else { - SCLogDebug("not skipping line at state %s", MimeDecParseStateGetStatus(state)); - } - } - - /* First look for boundary */ - MimeDecStackNode *node = state->stack->top; - if (node == NULL) { - SCLogDebug("Error: Invalid stack state"); - return MIME_DEC_ERR_PARSE; - } - - /* Traverse through stack to find a boundary definition */ - if (state->state_flag == BODY_END_BOUND || node->bdef == NULL) { - - /* If not found, then use parent's boundary */ - node = node->next; - while (node != NULL && node->bdef == NULL) { - SCLogDebug("Traversing through stack for node with boundary"); - node = node->next; - } - } - - /* This means no boundary / parent w/boundary was found so we are in the body */ - if (node == NULL) { - body_found = 1; - } else { - - /* Now look for start of boundary */ - if (len > 1 && buf[0] == '-' && buf[1] == '-') { - - tlen = node->bdef_len + 2; - if (tlen > BOUNDARY_BUF) { - if (state->stack->top->data) - state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; - SCLogDebug("Error: Long boundary: tlen %u > %d. Set ANOM_LONG_BOUNDARY", tlen, - BOUNDARY_BUF); - return MIME_DEC_ERR_PARSE; - } - - memcpy(temp, "--", 2); - memcpy(temp + 2, node->bdef, node->bdef_len); - - /* Find either next boundary or end boundary */ - bstart = FindBuffer(buf, len, temp, tlen); - if (bstart != NULL) { - ret = ProcessMimeBoundary(buf, len, node->bdef_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessMimeBoundary() function " - "failed"); - return ret; - } - } else { - /* Otherwise add value to body */ - body_found = 1; - } - } else { - /* Otherwise add value to body */ - body_found = 1; - } - } - - /* Process body line */ - if (body_found) { - state->state_flag = BODY_STARTED; - - ret = ProcessBodyLine(buf, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessBodyLine() function failed"); - return ret; - } - } - - return ret; -} - -const char *MimeDecParseStateGetStatus(MimeDecParseState *state) -{ - return StateFlags[state->state_flag]; -} - -/** - * \brief Processes the MIME Entity based on the input line and current state of - * the parser - * - * \param buf The current line - * \param len The length of the line - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -static int ProcessMimeEntity(const uint8_t *buf, uint32_t len, - MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - - SCLogDebug("START FLAG: %s", StateFlags[state->state_flag]); - - if (state->state_flag == PARSE_ERROR) { - SCLogDebug("START FLAG: PARSE_ERROR, bail"); - return MIME_DEC_ERR_STATE; - } - - /* Track long line */ - if (len > MAX_LINE_LEN) { - state->stack->top->data->anomaly_flags |= ANOM_LONG_LINE; - state->msg->anomaly_flags |= ANOM_LONG_LINE; - SCLogDebug("Error: Max input line length exceeded %u > %u", len, - MAX_LINE_LEN); - } - - if (!g_disable_hashing) { - if ((state->state_flag != HEADER_READY && state->state_flag != HEADER_STARTED) || - (state->stack->top->data->ctnt_flags & CTNT_IS_BODYPART)) { - if (MimeDecGetConfig()->body_md5) { - if (state->body_begin == 1 && state->md5_ctx == NULL) { - state->md5_ctx = SCMd5New(); - } - SCMd5Update(state->md5_ctx, buf, len + state->current_line_delimiter_len); - } - } - } - - /* Looking for headers */ - if (state->state_flag == HEADER_READY || - state->state_flag == HEADER_STARTED) { - - SCLogDebug("Processing Headers"); - - /* Process message headers */ - ret = ProcessMimeHeaders(buf, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessMimeHeaders() function failed: %d", - ret); - return ret; - } - } else { - /* Processing body */ - SCLogDebug("Processing Body of: %p", state->stack->top); - - ret = ProcessMimeBody(buf, len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessMimeBody() function failed: %d", - ret); - return ret; - } - } - - SCLogDebug("END FLAG: %s", StateFlags[state->state_flag]); - - return ret; -} - -/** - * \brief Init the parser by allocating memory for the state and top-level entity - * - * \param data A caller-specified pointer to data for access within the data chunk - * processor callback function - * \param dcpfunc The data chunk processor callback function - * - * \return A pointer to the state object, or NULL if the operation fails - */ -MimeDecParseState * MimeDecInitParser(void *data, - int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state)) -{ - MimeDecParseState *state; - MimeDecEntity *mimeMsg; - - state = SCCalloc(1, sizeof(MimeDecParseState)); - if (unlikely(state == NULL)) { - return NULL; - } - - state->stack = SCCalloc(1, sizeof(MimeDecStack)); - if (unlikely(state->stack == NULL)) { - SCFree(state); - return NULL; - } - - mimeMsg = SCCalloc(1, sizeof(MimeDecEntity)); - if (unlikely(mimeMsg == NULL)) { - SCFree(state->stack); - SCFree(state); - return NULL; - } - mimeMsg->ctnt_flags |= CTNT_IS_MSG; - - /* Init state */ - state->msg = mimeMsg; - PushStack(state->stack); - if (state->stack->top == NULL) { - SCFree(state->stack); - SCFree(state); - return NULL; - } - state->stack->top->data = mimeMsg; - state->state_flag = HEADER_READY; - state->data = data; - state->DataChunkProcessorFunc = DataChunkProcessorFunc; - - return state; -} - -/** - * \brief De-Init parser by freeing up any residual memory - * - * \param state The parser state - * - * \return none - */ -void MimeDecDeInitParser(MimeDecParseState *state) -{ - uint32_t cnt = 0; - - while (state->stack->top != NULL) { - SCLogDebug("Remaining on stack: [%p]=>[%p]", - state->stack->top, state->stack->top->data); - - PopStack(state->stack); - cnt++; - } - - if (cnt > 1) { - state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; - SCLogDebug("Warning: Stack is not empty upon completion of " - "processing (%u items remaining)", cnt); - } - - SCFree(state->hname); - FreeDataValue(state->hvalue); - FreeMimeDecStack(state->stack); - if (state->md5_ctx) - SCMd5Free(state->md5_ctx); - SCFree(state); -} - -/** - * \brief Called to indicate that the last message line has been processed and - * the parsing operation is complete - * - * This function should be called directly by the caller. - * - * \param state The parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -int MimeDecParseComplete(MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - - SCLogDebug("Parsing flagged as completed"); - - if (state->state_flag == PARSE_ERROR) { - SCLogDebug("parser in error state: PARSE_ERROR"); - return MIME_DEC_ERR_STATE; - } - - /* Store the header value */ - ret = StoreMimeHeader(state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: StoreMimeHeader() function failed"); - return ret; - } - - /* Lets complete the body */ - ret = ProcessBodyComplete(state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: ProcessBodyComplete() function failed"); - return ret; - } - - if (state->md5_ctx) { - SCMd5Finalize(state->md5_ctx, state->md5, sizeof(state->md5)); - state->md5_ctx = NULL; - state->has_md5 = true; - } - - if (state->stack->top == NULL) { - state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; - SCLogDebug("Error: Message is malformed"); - return MIME_DEC_ERR_DATA; - } - - /* If encapsulated, pop off the stack */ - if (state->stack->top->is_encap) { - PopStack(state->stack); - if (state->stack->top == NULL) { - state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; - SCLogDebug("Error: Message is malformed"); - return MIME_DEC_ERR_DATA; - } - } - - /* Look extra stack items remaining */ - if (state->stack->top->next != NULL) { - state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; - SCLogDebug("Warning: Message has unclosed message part boundary"); - } - - state->state_flag = PARSE_DONE; - - return ret; -} - -/** - * \brief Parse a line of a MIME message and update the parser state - * - * \param line A string representing the line (w/out CRLF) - * \param len The length of the line - * \param delim_len The length of the line end delimiter - * \param state The parser state - * - * \return MIME_DEC_OK on success, otherwise < 0 on failure - */ -int MimeDecParseLine(const uint8_t *line, const uint32_t len, - const uint8_t delim_len, MimeDecParseState *state) -{ - int ret = MIME_DEC_OK; - - /* For debugging purposes */ - if (len > 0) { - PrintChars(SC_LOG_DEBUG, "SMTP LINE", line, len); - } else { - SCLogDebug("SMTP LINE - EMPTY"); - } - - state->current_line_delimiter_len = delim_len; - /* Process the entity */ - ret = ProcessMimeEntity(line, len, state); - if (ret != MIME_DEC_OK) { - state->state_flag = PARSE_ERROR; - SCLogDebug("Error: ProcessMimeEntity() function failed: %d", ret); - } - - return ret; -} - -/** - * \brief Parses an entire message when available in its entirety (wraps the - * line-based parsing functions) - * - * \param buf Buffer pointing to the full message - * \param blen Length of the buffer - * \param data Caller data to be available in callback - * \param dcpfunc Callback for processing each decoded body data chunk - * - * \return A pointer to the decoded MIME message, or NULL if the operation fails - */ -MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, - int (*dcpfunc)(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state)) -{ - int ret = MIME_DEC_OK; - uint8_t *remainPtr, *tok; - uint32_t tokLen; - - MimeDecParseState *state = MimeDecInitParser(data, dcpfunc); - if (state == NULL) { - SCLogDebug("Error: MimeDecInitParser() function failed to create " - "state"); - return NULL; - } - - MimeDecEntity *msg = state->msg; - - /* Parse each line one by one */ - remainPtr = (uint8_t *) buf; - uint8_t *line = NULL; - do { - tok = GetLine(remainPtr, blen - (remainPtr - buf), &remainPtr, &tokLen); - if (tok != remainPtr) { - - line = tok; - - if ((remainPtr - tok) - tokLen > UINT8_MAX) { - SCLogDebug("Error: MimeDecParseLine() overflow: %ld", (remainPtr - tok) - tokLen); - ret = MIME_DEC_ERR_OVERFLOW; - break; - } - state->current_line_delimiter_len = (uint8_t)((remainPtr - tok) - tokLen); - /* Parse the line */ - ret = MimeDecParseLine(line, tokLen, state->current_line_delimiter_len, state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: MimeDecParseLine() function failed: %d", - ret); - break; - } - } - - } while (tok != remainPtr && remainPtr - buf < (int)blen); - - if (ret == MIME_DEC_OK) { - SCLogDebug("Message parser was successful"); - - /* Now complete message */ - ret = MimeDecParseComplete(state); - if (ret != MIME_DEC_OK) { - SCLogDebug("Error: MimeDecParseComplete() function failed"); - } - } - - /* De-allocate memory for parser */ - MimeDecDeInitParser(state); - - if (ret != MIME_DEC_OK) { - MimeDecFreeEntity(msg); - msg = NULL; - } - - return msg; -} - -#ifdef UNITTESTS - -/* Helper body chunk callback function */ -static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, - MimeDecParseState *state) -{ - uint32_t *line_count = (uint32_t *) state->data; - - if (state->body_begin) { - SCLogDebug("Body begin (len=%u)", len); - } - - /* Add up the line counts */ - if (len > 0) { - if ((*line_count) == 0) { - (*line_count)++; - } - PrintChars(SC_LOG_DEBUG, "CHUNK", chunk, len); - for (uint32_t i = 0; i < len; i++) { - if (chunk[i] == CR || chunk[i] == LF) { - if (i + 1 < len && chunk[i] != chunk[i + 1] && - (chunk[i + 1] == CR || chunk[i + 1] == LF)) { - i++; - } - (*line_count)++; - } - } - - SCLogDebug("line count (len=%u): %u", len, *line_count); - } - - if (state->body_end) { - SCLogDebug("Body end (len=%u)", len); - } - - return MIME_DEC_OK; -} - -/* Test simple case of line counts */ -static int MimeDecParseLineTest01(void) -{ - uint32_t line_count = 0; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, - TestDataChunkCallback); - - const char *str = "From: Sender1\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); - - str = "To: Recipient1\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); - - str = "Content-Type: text/plain\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); - - str = "\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); - - str = "A simple message line 1\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); - - str = "A simple message line 2\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); - - str = "A simple message line 3\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); - - /* Completed */ - FAIL_IF_NOT(MimeDecParseComplete(state) == MIME_DEC_OK); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NOT_NULL(msg->next); - FAIL_IF_NOT_NULL(msg->child); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - FAIL_IF_NOT(line_count == 3); - PASS; -} - -/* Test simple case of EXE URL extraction */ -static int MimeDecParseLineTest02(void) -{ - uint32_t line_count = 0; - - ConfNode *url_schemes = ConfNodeNew(); - ConfNode *scheme = ConfNodeNew(); - FAIL_IF_NULL(url_schemes); - FAIL_IF_NULL(scheme); - - url_schemes->is_seq = 1; - scheme->val = SCStrdup("http://"); - FAIL_IF_NULL(scheme->val); - TAILQ_INSERT_TAIL(&url_schemes->head, scheme, next); - - MimeDecGetConfig()->decode_base64 = true; - MimeDecGetConfig()->decode_quoted_printable = true; - MimeDecGetConfig()->extract_urls = true; - MimeDecGetConfig()->extract_urls_schemes = url_schemes; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, - TestDataChunkCallback); - - const char *str = "From: Sender1\r\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); - - str = "To: Recipient1\r\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); - - str = "Content-Type: text/plain\r\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); - - str = "\r\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); - - str = "A simple message line 1\r\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); - - str = "A simple message line 2 click on http://www.test.com/malware.exe?" - "hahah hopefully you click this link\r\n"; - FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); - - /* Completed */ - FAIL_IF_NOT(MimeDecParseComplete(state) == MIME_DEC_OK); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NULL(msg); - FAIL_IF_NULL(msg->url_list); - FAIL_IF_NOT((msg->url_list->url_flags & URL_IS_EXE)); - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - ConfNodeFree(url_schemes); - MimeDecGetConfig()->extract_urls_schemes = NULL; - - FAIL_IF_NOT(line_count == 2); - PASS; -} - -/* Test error case where no url schemes set in config */ -static int MimeFindUrlStringsTest01(void) -{ - int ret = MIME_DEC_OK; - uint32_t line_count = 0; - - MimeDecGetConfig()->extract_urls = true; - MimeDecGetConfig()->extract_urls_schemes = NULL; - MimeDecGetConfig()->log_url_scheme = false; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - - const char *str = "test"; - ret = FindUrlStrings((uint8_t *)str, strlen(str), state); - /* Expected error since extract_url_schemes is NULL */ - FAIL_IF_NOT(ret == MIME_DEC_ERR_DATA); - - /* Completed */ - ret = MimeDecParseComplete(state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - MimeDecEntity *msg = state->msg; - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - PASS; -} - -/* Test simple case of URL extraction */ -static int MimeFindUrlStringsTest02(void) -{ - int ret = MIME_DEC_OK; - uint32_t line_count = 0; - ConfNode *url_schemes = ConfNodeNew(); - ConfNode *scheme = ConfNodeNew(); - FAIL_IF_NULL(url_schemes); - FAIL_IF_NULL(scheme); - - url_schemes->is_seq = 1; - scheme->val = SCStrdup("http://"); - FAIL_IF_NULL(scheme->val); - TAILQ_INSERT_TAIL(&url_schemes->head, scheme, next); - - MimeDecGetConfig()->extract_urls = true; - MimeDecGetConfig()->extract_urls_schemes = url_schemes; - MimeDecGetConfig()->log_url_scheme = false; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - - const char *str = "A simple message click on " - "http://www.test.com/malware.exe? " - "hahah hopefully you click this link"; - ret = FindUrlStrings((uint8_t *)str, strlen(str), state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - /* Completed */ - ret = MimeDecParseComplete(state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - MimeDecEntity *msg = state->msg; - - FAIL_IF(msg->url_list == NULL); - - FAIL_IF_NOT(msg->url_list->url_flags & URL_IS_EXE); - FAIL_IF_NOT( - memcmp("www.test.com/malware.exe?", msg->url_list->url, msg->url_list->url_len) == 0); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - ConfNodeFree(url_schemes); - MimeDecGetConfig()->extract_urls_schemes = NULL; - - PASS; -} - -/* Test URL extraction with multiple schemes and URLs */ -static int MimeFindUrlStringsTest03(void) -{ - int ret = MIME_DEC_OK; - uint32_t line_count = 0; - ConfNode *url_schemes = ConfNodeNew(); - ConfNode *scheme1 = ConfNodeNew(); - ConfNode *scheme2 = ConfNodeNew(); - FAIL_IF_NULL(url_schemes); - FAIL_IF_NULL(scheme1); - FAIL_IF_NULL(scheme2); - - url_schemes->is_seq = 1; - scheme1->val = SCStrdup("http://"); - FAIL_IF_NULL(scheme1->val); - TAILQ_INSERT_TAIL(&url_schemes->head, scheme1, next); - scheme2->val = SCStrdup("https://"); - FAIL_IF_NULL(scheme2->val); - TAILQ_INSERT_TAIL(&url_schemes->head, scheme2, next); - - MimeDecGetConfig()->extract_urls = true; - MimeDecGetConfig()->extract_urls_schemes = url_schemes; - MimeDecGetConfig()->log_url_scheme = false; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - - const char *str = "A simple message click on " - "http://www.test.com/malware.exe? " - "hahah hopefully you click this link, or " - "you can go to http://www.test.com/test/01.html and " - "https://www.test.com/test/02.php"; - ret = FindUrlStrings((uint8_t *)str, strlen(str), state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - /* Completed */ - ret = MimeDecParseComplete(state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - MimeDecEntity *msg = state->msg; - - FAIL_IF(msg->url_list == NULL); - - MimeDecUrl *url = msg->url_list; - FAIL_IF_NOT(memcmp("www.test.com/test/02.php", url->url, url->url_len) == 0); - - url = url->next; - FAIL_IF_NOT(memcmp("www.test.com/test/01.html", url->url, url->url_len) == 0); - - url = url->next; - FAIL_IF_NOT(memcmp("www.test.com/malware.exe?", url->url, url->url_len) == 0); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - ConfNodeFree(url_schemes); - MimeDecGetConfig()->extract_urls_schemes = NULL; - - PASS; -} - -/* Test URL extraction with multiple schemes and URLs with - * log_url_scheme enabled in the MIME config */ -static int MimeFindUrlStringsTest04(void) -{ - int ret = MIME_DEC_OK; - uint32_t line_count = 0; - ConfNode *url_schemes = ConfNodeNew(); - ConfNode *scheme1 = ConfNodeNew(); - ConfNode *scheme2 = ConfNodeNew(); - FAIL_IF_NULL(url_schemes); - FAIL_IF_NULL(scheme1); - FAIL_IF_NULL(scheme2); - - url_schemes->is_seq = 1; - scheme1->val = SCStrdup("http://"); - FAIL_IF_NULL(scheme1->val); - TAILQ_INSERT_TAIL(&url_schemes->head, scheme1, next); - scheme2->val = SCStrdup("https://"); - FAIL_IF_NULL(scheme2->val); - TAILQ_INSERT_TAIL(&url_schemes->head, scheme2, next); - - MimeDecGetConfig()->extract_urls = true; - MimeDecGetConfig()->extract_urls_schemes = url_schemes; - MimeDecGetConfig()->log_url_scheme = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - - const char *str = "A simple message click on " - "http://www.test.com/malware.exe? " - "hahah hopefully you click this link, or " - "you can go to http://www.test.com/test/01.html and " - "https://www.test.com/test/02.php"; - ret = FindUrlStrings((uint8_t *)str, strlen(str), state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - /* Completed */ - ret = MimeDecParseComplete(state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - MimeDecEntity *msg = state->msg; - - FAIL_IF(msg->url_list == NULL); - - MimeDecUrl *url = msg->url_list; - FAIL_IF_NOT(memcmp("https://www.test.com/test/02.php", url->url, url->url_len) == 0); - - url = url->next; - FAIL_IF_NOT(memcmp("http://www.test.com/test/01.html", url->url, url->url_len) == 0); - - url = url->next; - FAIL_IF_NOT(memcmp("http://www.test.com/malware.exe?", url->url, url->url_len) == 0); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - ConfNodeFree(url_schemes); - MimeDecGetConfig()->extract_urls_schemes = NULL; - - PASS; -} - -/* Test URL extraction of IPV4 and IPV6 URLs with log_url_scheme - * enabled in the MIME config */ -static int MimeFindUrlStringsTest05(void) -{ - int ret = MIME_DEC_OK; - uint32_t line_count = 0; - ConfNode *url_schemes = ConfNodeNew(); - ConfNode *scheme = ConfNodeNew(); - FAIL_IF_NULL(url_schemes); - FAIL_IF_NULL(scheme); - - url_schemes->is_seq = 1; - scheme->val = SCStrdup("http://"); - FAIL_IF_NULL(scheme->val); - TAILQ_INSERT_TAIL(&url_schemes->head, scheme, next); - - MimeDecGetConfig()->extract_urls = true; - MimeDecGetConfig()->extract_urls_schemes = url_schemes; - MimeDecGetConfig()->log_url_scheme = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - - const char *str = "A simple message click on " - "http://192.168.1.1/test/01.html " - "hahah hopefully you click this link or this one " - "http://0:0:0:0:0:0:0:0/test/02.php"; - ret = FindUrlStrings((uint8_t *)str, strlen(str), state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - /* Completed */ - ret = MimeDecParseComplete(state); - FAIL_IF_NOT(ret == MIME_DEC_OK); - - MimeDecEntity *msg = state->msg; - - FAIL_IF(msg->url_list == NULL); - - MimeDecUrl *url = msg->url_list; - FAIL_IF_NOT(url->url_flags & URL_IS_IP6); - FAIL_IF_NOT(memcmp("http://0:0:0:0:0:0:0:0/test/02.php", url->url, url->url_len) == 0); - - url = url->next; - FAIL_IF_NOT(url->url_flags & URL_IS_IP4); - FAIL_IF_NOT(memcmp("http://192.168.1.1/test/01.html", url->url, url->url_len) == 0); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - ConfNodeFree(url_schemes); - MimeDecGetConfig()->extract_urls_schemes = NULL; - - PASS; -} - -/* Test full message with linebreaks */ -static int MimeDecParseFullMsgTest01(void) -{ - uint32_t expected_count = 3; - uint32_t line_count = 0; - - char msg[] = "From: Sender1\r\n" - "To: Recipient1\r\n" - "Content-Type: text/plain\r\n" - "\r\n" - "Line 1\r\n" - "Line 2\r\n" - "Line 3\r\n"; - - MimeDecEntity *entity = MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, - TestDataChunkCallback); - if (entity == NULL) { - SCLogInfo("Warning: Message failed to parse"); - return 0; - } - - MimeDecFreeEntity(entity); - - if (expected_count != line_count) { - SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", - expected_count, line_count); - return 0; - } - - return 1; -} - -/* Test full message with linebreaks */ -static int MimeDecParseFullMsgTest02(void) -{ - uint32_t expected_count = 3; - uint32_t line_count = 0; - - char msg[] = "From: Sender2\r\n" - "To: Recipient2\r\n" - "Subject: subject2\r\n" - "Content-Type: text/plain\r\n" - "\r\n" - "Line 1\r\n" - "Line 2\r\n" - "Line 3\r\n"; - - MimeDecEntity *entity = MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, - TestDataChunkCallback); - - if (entity == NULL) { - SCLogInfo("Warning: Message failed to parse"); - return 0; - } - - MimeDecField *field = MimeDecFindField(entity, "subject"); - if (field == NULL) { - SCLogInfo("Warning: Message failed to parse"); - return 0; - } - - if (field->value_len != sizeof("subject2") - 1) { - SCLogInfo("Warning: failed to get subject"); - return 0; - } - - if (memcmp(field->value, "subject2", field->value_len) != 0) { - SCLogInfo("Warning: failed to get subject"); - return 0; - } - - - MimeDecFreeEntity(entity); - - if (expected_count != line_count) { - SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count, - line_count); - return 0; - } - - return 1; -} - -static int MimeBase64DecodeTest01(void) -{ - int ret = 0; - uint32_t consumed_bytes = 0, num_decoded = 0; - - const char *msg = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@" - "#$%^&*()-=_+,./;'[]<>?:"; - const char *base64msg = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QU" - "VJTVFVWV1hZWjEyMzQ1Njc4OTBAIyQlXiYqKCktPV8rLC4vOydbXTw+Pzo="; - - uint8_t *dst = SCMalloc(strlen(msg) + 1); - if (dst == NULL) - return 0; - - ret = DecodeBase64(dst, strlen(msg) + 1, (const uint8_t *)base64msg, strlen(base64msg), - &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045); - - if (memcmp(dst, msg, strlen(msg)) == 0) { - ret = 1; - } - - SCFree(dst); - - return ret; -} - -static int MimeIsExeURLTest01(void) -{ - int ret = 0; - const char *url1 = "http://www.google.com/"; - const char *url2 = "http://www.google.com/test.exe"; - - if(IsExeUrl((const uint8_t *)url1, strlen(url1)) != 0){ - SCLogDebug("Debug: URL1 error"); - goto end; - } - if(IsExeUrl((const uint8_t *)url2, strlen(url2)) != 1){ - SCLogDebug("Debug: URL2 error"); - goto end; - } - ret = 1; - - end: - - return ret; -} - -#define TEST(str, len, expect) { \ - SCLogDebug("str %s", (str)); \ - int r = IsIpv4Host((const uint8_t *)(str),(len)); \ - FAIL_IF_NOT(r == (expect)); \ -} -static int MimeIsIpv4HostTest01(void) -{ - TEST("192.168.1.1", 11, 1); - TEST("192.168.1.1.4", 13, 0); - TEST("999.168.1.1", 11, 0); - TEST("1111.168.1.1", 12, 0); - TEST("999.oogle.com", 14, 0); - TEST("0:0:0:0:0:0:0:0", 15, 0); - TEST("192.168.255.255", 15, 1); - TEST("192.168.255.255/testurl.html", 28, 1); - TEST("www.google.com", 14, 0); - PASS; -} -#undef TEST - -#define TEST(str, len, expect) { \ - SCLogDebug("str %s", (str)); \ - int r = IsIpv6Host((const uint8_t *)(str),(len)); \ - FAIL_IF_NOT(r == (expect)); \ -} -static int MimeIsIpv6HostTest01(void) -{ - TEST("0:0:0:0:0:0:0:0", 19, 1); - TEST("0000:0000:0000:0000:0000:0000:0000:0000", 39, 1); - TEST("XXXX:0000:0000:0000:0000:0000:0000:0000", 39, 0); - TEST("00001:0000:0000:0000:0000:0000:0000:0000", 40, 0); - TEST("0:0:0:0:0:0:0:0", 19, 1); - TEST("0:0:0:0:0:0:0:0:0", 20, 0); - TEST("192:168:1:1:0:0:0:0", 19, 1); - TEST("999.oogle.com", 14, 0); - TEST("192.168.255.255", 15, 0); - TEST("192.168.255.255/testurl.html", 28, 0); - TEST("www.google.com", 14, 0); - PASS; -} -#undef TEST - -static int MimeDecParseLongFilename01(void) -{ - /* contains 276 character filename -- length restricted to 255 chars */ - char mimemsg[] = "Content-Disposition: attachment; filename=\"" - "12characters12characters12characters12characters" - "12characters12characters12characters12characters" - "12characters12characters12characters12characters" - "12characters12characters12characters12characters" - "12characters12characters12characters12characters" - "12characters12characters12characters.exe\""; - - uint32_t line_count = 0; - - MimeDecGetConfig()->decode_base64 = true; - MimeDecGetConfig()->decode_quoted_printable = true; - MimeDecGetConfig()->extract_urls = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, - TestDataChunkCallback); - - const char *str = "From: Sender1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "To: Recipient1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Type: text/plain"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - /* Contains 276 character filename */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); - - str = ""; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "A simple message line 1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - /* Completed */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NOT(msg); - - FAIL_IF_NOT(msg->anomaly_flags & ANOM_LONG_FILENAME); - FAIL_IF_NOT(msg->filename_len == RS_MIME_MAX_TOKEN_LEN); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - PASS; -} - -static int MimeDecParseSmallRemInp(void) -{ - // Remainder dA - // New input: AAAA - char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vdA"; - - uint32_t line_count = 0; - - MimeDecGetConfig()->decode_base64 = true; - MimeDecGetConfig()->decode_quoted_printable = true; - MimeDecGetConfig()->extract_urls = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; - - const char *str = "From: Sender1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "To: Recipient1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Type: text/plain"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Transfer-Encoding: base64"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = ""; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); - - str = "AAAA"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - /* Completed */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NOT(msg); - - /* filename is not too long */ - FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - PASS; -} - -static int MimeDecParseRemSp(void) -{ - // Should have remainder vd A - char mimemsg[] = "TWltZSBkZWNvZGluZyBpc yBzbyBOT1QgZnVuISBJIGNhbm5vd A"; - - uint32_t line_count = 0; - - MimeDecGetConfig()->decode_base64 = true; - MimeDecGetConfig()->decode_quoted_printable = true; - MimeDecGetConfig()->extract_urls = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; - - const char *str = "From: Sender1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "To: Recipient1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Type: text/plain"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Transfer-Encoding: base64"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = ""; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); - /* Completed */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NOT(msg); - - /* filename is not too long */ - FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - PASS; -} - -static int MimeDecVerySmallInp(void) -{ - // Remainder: A - // New input: aA - char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vA"; - - uint32_t line_count = 0; - - MimeDecGetConfig()->decode_base64 = true; - MimeDecGetConfig()->decode_quoted_printable = true; - MimeDecGetConfig()->extract_urls = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; - - const char *str = "From: Sender1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "To: Recipient1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Type: text/plain"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Transfer-Encoding: base64"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = ""; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); - - str = "aA"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - /* Completed */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NOT(msg); - - /* filename is not too long */ - FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - PASS; -} - -static int MimeDecParseOddLen(void) -{ - char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vdA"; - - uint32_t line_count = 0; - - MimeDecGetConfig()->decode_base64 = true; - MimeDecGetConfig()->decode_quoted_printable = true; - MimeDecGetConfig()->extract_urls = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); - state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; - - const char *str = "From: Sender1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "To: Recipient1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Type: text/plain"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Transfer-Encoding: base64"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = ""; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); - /* Completed */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NOT(msg); - - /* filename is not too long */ - FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - PASS; -} - -static int MimeDecParseLongFilename02(void) -{ - /* contains 40 character filename and 500+ characters following filename */ - char mimemsg[] = "Content-Disposition: attachment; filename=\"" - "12characters12characters12characters.exe\"; " - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd" - "somejunkasfdasfsafasafdsasdasassdssdsd"; - - uint32_t line_count = 0; - - MimeDecGetConfig()->decode_base64 = true; - MimeDecGetConfig()->decode_quoted_printable = true; - MimeDecGetConfig()->extract_urls = true; - - /* Init parser */ - MimeDecParseState *state = MimeDecInitParser(&line_count, - TestDataChunkCallback); - - const char *str = "From: Sender1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "To: Recipient1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "Content-Type: text/plain"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - /* Contains 40 character filename */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); - - str = ""; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - str = "A simple message line 1"; - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); - - /* Completed */ - FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); - - MimeDecEntity *msg = state->msg; - FAIL_IF_NOT(msg); - - /* filename is not too long */ - FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); - - MimeDecFreeEntity(msg); - - /* De Init parser */ - MimeDecDeInitParser(state); - - PASS; -} - -#endif /* UNITTESTS */ - -void MimeDecRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01); - UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02); - UtRegisterTest("MimeFindUrlStringsTest01", MimeFindUrlStringsTest01); - UtRegisterTest("MimeFindUrlStringsTest02", MimeFindUrlStringsTest02); - UtRegisterTest("MimeFindUrlStringsTest03", MimeFindUrlStringsTest03); - UtRegisterTest("MimeFindUrlStringsTest04", MimeFindUrlStringsTest04); - UtRegisterTest("MimeFindUrlStringsTest05", MimeFindUrlStringsTest05); - UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01); - UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02); - UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01); - UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01); - UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01); - UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01); - UtRegisterTest("MimeDecParseLongFilename01", MimeDecParseLongFilename01); - UtRegisterTest("MimeDecParseLongFilename02", MimeDecParseLongFilename02); - UtRegisterTest("MimeDecParseSmallRemInp", MimeDecParseSmallRemInp); - UtRegisterTest("MimeDecParseRemSp", MimeDecParseRemSp); - UtRegisterTest("MimeDecVerySmallInp", MimeDecVerySmallInp); - UtRegisterTest("MimeDecParseOddLen", MimeDecParseOddLen); -#endif /* UNITTESTS */ -} diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h deleted file mode 100644 index cc79d98a6eb0..000000000000 --- a/src/util-decode-mime.h +++ /dev/null @@ -1,243 +0,0 @@ -/* Copyright (C) 2012 BAE Systems - * Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author David Abarbanel - * - */ - -#ifndef MIME_DECODE_H_ -#define MIME_DECODE_H_ - -#include "conf.h" -#include "util-base64.h" -#include "util-file.h" - -/* Content Flags */ -#define CTNT_IS_MSG 1 -#define CTNT_IS_ENV 2 -#define CTNT_IS_ENCAP 4 -#define CTNT_IS_BODYPART 8 -#define CTNT_IS_MULTIPART 16 -#define CTNT_IS_ATTACHMENT 32 -#define CTNT_IS_BASE64 64 -#define CTNT_IS_QP 128 -#define CTNT_IS_TEXT 256 -#define CTNT_IS_HTML 512 - -/* URL Flags */ -#define URL_IS_IP4 1 -#define URL_IS_IP6 2 -#define URL_IS_EXE 4 - -/* Anomaly Flags */ -#define ANOM_INVALID_BASE64 1 /* invalid base64 chars */ -#define ANOM_INVALID_QP 2 /* invalid quoted-printable chars */ -#define ANOM_LONG_HEADER_NAME 4 /* header is abnormally long */ -#define ANOM_LONG_HEADER_VALUE 8 /* header value is abnormally long - * (includes multi-line) */ -#define ANOM_LONG_LINE 16 /* Lines that exceed 998 octets */ -#define ANOM_LONG_ENC_LINE 32 /* Lines that exceed 76 octets */ -#define ANOM_MALFORMED_MSG 64 /* Misc msg format errors found */ -#define ANOM_LONG_BOUNDARY 128 /* Boundary too long */ -#define ANOM_LONG_FILENAME 256 /* filename truncated */ - -/* Publicly exposed size constants */ -#define DATA_CHUNK_SIZE 3072 /* Should be divisible by 3 */ - -/* Mime Parser Constants */ -#define HEADER_READY 0x01 -#define HEADER_STARTED 0x02 -#define HEADER_DONE 0x03 -#define BODY_STARTED 0x04 -#define BODY_DONE 0x05 -#define BODY_END_BOUND 0x06 -#define PARSE_DONE 0x07 -#define PARSE_ERROR 0x08 - -/** - * \brief Mime Decoder Error Codes - */ -typedef enum MimeDecRetCode { - MIME_DEC_OK = 0, - MIME_DEC_MORE = 1, - MIME_DEC_ERR_DATA = -1, - MIME_DEC_ERR_MEM = -2, - MIME_DEC_ERR_PARSE = -3, - MIME_DEC_ERR_STATE = -4, /**< parser in error state */ - MIME_DEC_ERR_OVERFLOW = -5, -} MimeDecRetCode; - -/** - * \brief Structure for containing configuration options - * - */ -typedef struct MimeDecConfig { - bool decode_base64; /**< Decode base64 bodies */ - bool decode_quoted_printable; /**< Decode quoted-printable bodies */ - bool extract_urls; /**< Extract and store URLs in data structure */ - ConfNode *extract_urls_schemes; /**< List of schemes of which to - extract urls */ - bool log_url_scheme; /**< Log the scheme of extracted URLs */ - bool body_md5; /**< Compute md5 sum of body */ - uint32_t header_value_depth; /**< Depth of which to store header values - (Default is 2000) */ -} MimeDecConfig; - -/** - * \brief This represents a header field name and associated value - */ -typedef struct MimeDecField { - uint8_t *name; /**< Name of the header field */ - uint32_t name_len; /**< Length of the name */ - uint32_t value_len; /**< Length of the value */ - uint8_t *value; /**< Value of the header field */ - struct MimeDecField *next; /**< Pointer to next field */ -} MimeDecField; - -/** - * \brief This represents a URL value node in a linked list - * - * Since HTML can sometimes contain a high number of URLs, this - * structure only features the URL host name/IP or those that are - * pointing to an executable file (see url_flags to determine which). - */ -typedef struct MimeDecUrl { - uint8_t *url; /**< String representation of full or partial URL (lowercase) */ - uint32_t url_len; /**< Length of the URL string */ - uint32_t url_flags; /**< Flags indicating type of URL */ - struct MimeDecUrl *next; /**< Pointer to next URL */ -} MimeDecUrl; - -/** - * \brief This represents the MIME Entity (or also top level message) in a - * child-sibling tree - */ -typedef struct MimeDecEntity { - MimeDecField *field_list; /**< Pointer to list of header fields */ - MimeDecUrl *url_list; /**< Pointer to list of URLs */ - uint32_t header_flags; /**< Flags indicating header characteristics */ - uint32_t ctnt_flags; /**< Flags indicating type of content */ - uint32_t anomaly_flags; /**< Flags indicating an anomaly in the message */ - uint32_t filename_len; /**< Length of file attachment name */ - uint8_t *filename; /**< Name of file attachment */ - uint8_t *ctnt_type; /**< Quick access pointer to short-hand content type field */ - uint32_t ctnt_type_len; /**< Length of content type field value */ - uint32_t msg_id_len; /**< Quick access pointer to message Id */ - uint8_t *msg_id; /**< Quick access pointer to message Id */ - struct MimeDecEntity *next; /**< Pointer to list of sibling entities */ - struct MimeDecEntity *child; /**< Pointer to list of child entities */ - struct MimeDecEntity *last_child; /**< Pointer to tail of the list of child entities */ -} MimeDecEntity; - -/** - * \brief Structure contains boundary and entity for the current node (entity) - * in the stack - * - */ -typedef struct MimeDecStackNode { - MimeDecEntity *data; /**< Pointer to the entity data structure */ - uint8_t *bdef; /**< Copy of boundary definition for child entity */ - uint16_t bdef_len; /**< Boundary length for child entity */ - bool is_encap; /**< Flag indicating entity is encapsulated in message */ - struct MimeDecStackNode *next; /**< Pointer to next item on the stack */ -} MimeDecStackNode; - -/** - * \brief Structure holds the top of the stack along with some free reusable nodes - * - */ -typedef struct MimeDecStack { - MimeDecStackNode *top; /**< Pointer to the top of the stack */ - MimeDecStackNode *free_nodes; /**< Pointer to the list of free nodes */ - uint32_t free_nodes_cnt; /**< Count of free nodes in the list */ -} MimeDecStack; - -/** - * \brief Structure contains a list of value and lengths for robust data processing - * - */ -typedef struct DataValue { - uint8_t *value; /**< Copy of data value */ - uint32_t value_len; /**< Length of data value */ - struct DataValue *next; /**< Pointer to next value in the list */ -} DataValue; - -/** - * \brief Structure contains the current state of the MIME parser - * - */ -typedef struct MimeDecParseState { - MimeDecEntity *msg; /**< Pointer to the top-level message entity */ - MimeDecStack *stack; /**< Pointer to the top of the entity stack */ - uint8_t *hname; /**< Copy of the last known header name */ - uint32_t hlen; /**< Length of the last known header name */ - uint32_t hvlen; /**< Total length of value list */ - DataValue *hvalue; /**< Pointer to the incomplete header value list */ - uint8_t bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ - uint8_t bvr_len; /**< Length of remainder from base64-decoded line */ - uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */ - SCMd5 *md5_ctx; - uint8_t md5[SC_MD5_LEN]; - bool has_md5; - uint8_t state_flag; /**< Flag representing current state of parser */ - uint32_t data_chunk_len; /**< Length of data chunk */ - int found_child; /**< Flag indicating a child entity was found */ - int body_begin; /**< Currently at beginning of body */ - int body_end; /**< Currently at end of body */ - uint8_t current_line_delimiter_len; /**< Length of line delimiter */ - void *data; /**< Pointer to data specific to the caller */ - int (*DataChunkProcessorFunc) (const uint8_t *chunk, uint32_t len, - struct MimeDecParseState *state); /**< Data chunk processing function callback */ -} MimeDecParseState; - -/* Config functions */ -void MimeDecSetConfig(MimeDecConfig *config); -MimeDecConfig * MimeDecGetConfig(void); - -/* Memory functions */ -void MimeDecFreeEntity(MimeDecEntity *entity); -void MimeDecFreeField(MimeDecField *field); -void MimeDecFreeUrl(MimeDecUrl *url); - -/* List functions */ -MimeDecField * MimeDecAddField(MimeDecEntity *entity); -MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name); -int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data); -MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent); - -/* Helper functions */ -//MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, -// uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value); - -/* Parser functions */ -MimeDecParseState * MimeDecInitParser(void *data, int (*dcpfunc)(const uint8_t *chunk, - uint32_t len, MimeDecParseState *state)); -void MimeDecDeInitParser(MimeDecParseState *state); -int MimeDecParseComplete(MimeDecParseState *state); -int MimeDecParseLine(const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state); -MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, - int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); -const char *MimeDecParseStateGetStatus(MimeDecParseState *state); - -/* Test functions */ -void MimeDecRegisterTests(void); - -#endif diff --git a/src/util-detect.c b/src/util-detect.c deleted file mode 100644 index 1b68e520548b..000000000000 --- a/src/util-detect.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Giuseppe Longo - * - * Detection engine helper functions - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" -#include "util-detect.h" - -/** - * \brief Allocate SigString list member - * - * \retval Pointer to SigString - */ -SigString *SigStringAlloc(void) -{ - SigString *sigstr = SCCalloc(1, sizeof(SigString)); - if (unlikely(sigstr == NULL)) - return NULL; - - sigstr->line = 0; - - return sigstr; -} - -/** - * \brief Assigns the filename, signature, lineno to SigString list member - * - * \param sig pointer to SigString - * \param sig_file filename that contains the signature - * \param sig_str signature in string format - * \param sig_error signature parsing error - * \param line line line number - * - * \retval 1 on success 0 on failure - */ -static int SigStringAddSig(SigString *sig, const char *sig_file, - const char *sig_str, const char *sig_error, - int line) -{ - if (sig_file == NULL || sig_str == NULL) { - return 0; - } - - sig->filename = SCStrdup(sig_file); - if (sig->filename == NULL) { - SCLogError("Error allocating memory"); - return 0; - } - - sig->sig_str = SCStrdup(sig_str); - if (sig->sig_str == NULL) { - SCLogError("Error allocating memory"); - SCFree(sig->filename); - return 0; - } - - if (sig_error) { - sig->sig_error = SCStrdup(sig_error); - if (sig->sig_error == NULL) { - SCLogError("Error allocating memory"); - SCFree(sig->filename); - SCFree(sig->sig_str); - return 0; - } - } - - sig->line = line; - - return 1; -} - -/** - * \brief Append a new list member to SigString list - * - * \param list pointer to the start of the SigString list - * \param sig_file filename that contains the signature - * \param sig_str signature in string format - * \param line line line number - * - * \retval 1 on success 0 on failure - */ -int SigStringAppend(SigFileLoaderStat *sig_stats, const char *sig_file, - const char *sig_str, const char *sig_error, int line) -{ - SigString *item = SigStringAlloc(); - if (item == NULL) { - return 0; - } - - if (!SigStringAddSig(item, sig_file, sig_str, sig_error, line)) { - SCFree(item); - return 0; - } - - TAILQ_INSERT_TAIL(&sig_stats->failed_sigs, item, next); - - return 1; -} diff --git a/src/util-detect.h b/src/util-detect.h deleted file mode 100644 index b483d507fbbf..000000000000 --- a/src/util-detect.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Giuseppe Longo - * - * Detection engine helper functions - */ - -SigString *SigStringAlloc(void); -int SigStringAppend(SigFileLoaderStat *sigs_stats, const char *sig_file, const char *sig_str, - const char *sig_error, int line); diff --git a/src/util-device.c b/src/util-device.c deleted file mode 100644 index b624cf07342b..000000000000 --- a/src/util-device.c +++ /dev/null @@ -1,626 +0,0 @@ -/* Copyright (C) 2011-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "conf.h" -#include "util-device.h" -#include "util-ioctl.h" -#include "util-misc.h" -#include "util-dpdk.h" - -#include "device-storage.h" -#include "util-debug.h" - -#define MAX_DEVNAME 10 - -static LiveDevStorageId g_bypass_storage_id = { .id = -1 }; - -/** - * \file - * - * \author Eric Leblond - * - * \brief Utility functions to handle device list - */ - -/** private device list */ -static TAILQ_HEAD(, LiveDevice_) live_devices = - TAILQ_HEAD_INITIALIZER(live_devices); - -/** List of the name of devices - * - * As we don't know the size of the Storage on devices - * before the parsing we need to wait and use this list - * to create later the LiveDevice via LiveDeviceFinalize() - */ -static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices = - TAILQ_HEAD_INITIALIZER(pre_live_devices); - -typedef struct BypassInfo_ { - SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count); - SC_ATOMIC_DECLARE(uint64_t, ipv4_fail); - SC_ATOMIC_DECLARE(uint64_t, ipv4_success); - SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count); - SC_ATOMIC_DECLARE(uint64_t, ipv6_fail); - SC_ATOMIC_DECLARE(uint64_t, ipv6_success); -} BypassInfo; - -/** if set to 0 when we don't have real devices */ -static int live_devices_stats = 1; - - -static int LiveSafeDeviceName(const char *devname, - char *newdevname, size_t destlen); - -static int g_live_devices_disable_offloading = 1; - -void LiveSetOffloadDisable(void) -{ - g_live_devices_disable_offloading = 1; -} - -void LiveSetOffloadWarn(void) -{ - g_live_devices_disable_offloading = 0; -} - -int LiveGetOffload(void) -{ - return g_live_devices_disable_offloading; -} - -/** - * \brief Add a device for monitoring - * - * To be used during option parsing. When a device has - * to be created during runmode init, use LiveRegisterDevice() - * - * \param dev string with the device name - * - * \retval 0 on success. - * \retval -1 on failure. - */ -int LiveRegisterDeviceName(const char *dev) -{ - LiveDeviceName *pd = NULL; - - pd = SCCalloc(1, sizeof(LiveDeviceName)); - if (unlikely(pd == NULL)) { - return -1; - } - - pd->dev = SCStrdup(dev); - if (unlikely(pd->dev == NULL)) { - SCFree(pd); - return -1; - } - - TAILQ_INSERT_TAIL(&pre_live_devices, pd, next); - - SCLogDebug("Device \"%s\" registered.", dev); - return 0; -} - -/** - * \brief Add a pcap device for monitoring and create structure - * - * \param dev string with the device name - * - * \retval 0 on success. - * \retval -1 on failure. - */ -int LiveRegisterDevice(const char *dev) -{ - LiveDevice *pd = NULL; - - pd = SCCalloc(1, sizeof(LiveDevice) + LiveDevStorageSize()); - if (unlikely(pd == NULL)) { - return -1; - } - - int id = LiveGetDeviceCount(); - if (id > UINT16_MAX) { - SCFree(pd); - return -1; - } - - pd->dev = SCStrdup(dev); - if (unlikely(pd->dev == NULL)) { - SCFree(pd); - return -1; - } - /* create a short version to be used in thread names */ - LiveSafeDeviceName(pd->dev, pd->dev_short, sizeof(pd->dev_short)); - - SC_ATOMIC_INIT(pd->pkts); - SC_ATOMIC_INIT(pd->drop); - SC_ATOMIC_INIT(pd->invalid_checksums); - pd->id = (uint16_t)id; - TAILQ_INSERT_TAIL(&live_devices, pd, next); - - SCLogDebug("Device \"%s\" registered and created.", dev); - return 0; -} - -/** - * \brief Get the number of registered devices - * - * \retval cnt the number of registered devices - */ -int LiveGetDeviceCount(void) -{ - int i = 0; - LiveDevice *pd; - - TAILQ_FOREACH(pd, &live_devices, next) { - i++; - } - - return i; -} - -/** - * \brief Get a pointer to the device name at idx - * - * \param number idx of the device in our list - * - * \retval ptr pointer to the string containing the device - * \retval NULL on error - */ -const char *LiveGetDeviceName(int number) -{ - int i = 0; - LiveDevice *pd; - - TAILQ_FOREACH(pd, &live_devices, next) { - if (i == number) { - return pd->dev; - } - - i++; - } - - return NULL; -} - -/** \internal - * \brief Shorten a device name that is to long - * - * \param device name from config and destination for modified - * - * \retval None, is added to destination char *newdevname - */ -static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) -{ - const size_t devnamelen = strlen(devname); - - /* If we have to shorten the interface name */ - if (devnamelen > MAX_DEVNAME) { - /* special mode for DPDK pci addresses */ - if (devnamelen >= 5 && strncmp(devname, "0000:", 5) == 0) { - strlcpy(newdevname, devname + 5, destlen); - return 0; - } - - /* IF the dest length is over 10 chars long it will not do any - * good for the shortening. The shortening is done due to the - * max length of pthread names (15 chars) and we use 3 chars - * for the threadname indicator eg. "W#-" and one-two chars for - * the thread number. And if the destination buffer is under - * 6 chars there is no point in shortening it since we must at - * least enter two periods (.) into the string. - */ - if ((destlen-1) > 10 || (destlen-1) < 6) { - return 1; - } - - ShortenString(devname, newdevname, destlen, '.'); - - SCLogInfo("%s: shortening device name to %s", devname, newdevname); - } else { - strlcpy(newdevname, devname, destlen); - } - return 0; -} - -/** - * \brief Get a pointer to the device at idx - * - * \param number idx of the device in our list - * - * \retval ptr pointer to the string containing the device - * \retval NULL on error - */ -LiveDevice *LiveGetDevice(const char *name) -{ - LiveDevice *pd; - - if (name == NULL) { - SCLogWarning("Name of device should not be null"); - return NULL; - } - - TAILQ_FOREACH(pd, &live_devices, next) { - if (!strcmp(name, pd->dev)) { - return pd; - } - } - - return NULL; -} - -const char *LiveGetShortName(const char *dev) -{ - LiveDevice *live_dev = LiveGetDevice(dev); - if (live_dev == NULL) - return NULL; - return live_dev->dev_short; -} - -int LiveBuildDeviceList(const char *runmode) -{ - return LiveBuildDeviceListCustom(runmode, "interface"); -} - -int LiveBuildDeviceListCustom(const char *runmode, const char *itemname) -{ - ConfNode *base = ConfGetNode(runmode); - ConfNode *child; - int i = 0; - - if (base == NULL) - return 0; - - TAILQ_FOREACH(child, &base->head, next) { - ConfNode *subchild; - TAILQ_FOREACH(subchild, &child->head, next) { - if ((!strcmp(subchild->name, itemname))) { - if (!strcmp(subchild->val, "default")) - break; - SCLogConfig("Adding %s %s from config file", - itemname, subchild->val); - LiveRegisterDeviceName(subchild->val); - i++; - } - } - } - - return i; -} - -/** Call this function to disable stat on live devices - * - * This can be useful in the case, this is not a real interface. - */ -void LiveDeviceHasNoStats(void) -{ - live_devices_stats = 0; -} - -int LiveDeviceListClean(void) -{ - SCEnter(); - LiveDevice *pd, *tpd; - - /* dpdk: need to close all devices before freeing them. */ - TAILQ_FOREACH (pd, &live_devices, next) { - DPDKCloseDevice(pd); - } - TAILQ_FOREACH_SAFE(pd, &live_devices, next, tpd) { - if (live_devices_stats) { - SCLogNotice("%s: packets: %" PRIu64 ", drops: %" PRIu64 - " (%.2f%%), invalid chksum: %" PRIu64, - pd->dev, SC_ATOMIC_GET(pd->pkts), SC_ATOMIC_GET(pd->drop), - SC_ATOMIC_GET(pd->pkts) > 0 ? 100 * ((double)SC_ATOMIC_GET(pd->drop)) / - (double)SC_ATOMIC_GET(pd->pkts) - : 0, - SC_ATOMIC_GET(pd->invalid_checksums)); - } - - RestoreIfaceOffloading(pd); - DPDKFreeDevice(pd); - - if (pd->dev) - SCFree(pd->dev); - LiveDevFreeStorage(pd); - SCFree(pd); - } - - SCReturnInt(TM_ECODE_OK); -} - -#ifdef BUILD_UNIX_SOCKET -TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *answer, void *data) -{ - SCEnter(); - LiveDevice *pd; - const char * name = NULL; - json_t *jarg = json_object_get(cmd, "iface"); - if(!json_is_string(jarg)) { - json_object_set_new(answer, "message", json_string("Iface is not a string")); - SCReturnInt(TM_ECODE_FAILED); - } - name = json_string_value(jarg); - if (name == NULL) { - json_object_set_new(answer, "message", json_string("Iface name is NULL")); - SCReturnInt(TM_ECODE_FAILED); - } - - TAILQ_FOREACH(pd, &live_devices, next) { - if (!strcmp(name, pd->dev)) { - json_t *jdata = json_object(); - if (jdata == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - SCReturnInt(TM_ECODE_FAILED); - } - json_object_set_new(jdata, "pkts", - json_integer(SC_ATOMIC_GET(pd->pkts))); - json_object_set_new(jdata, "invalid-checksums", - json_integer(SC_ATOMIC_GET(pd->invalid_checksums))); - json_object_set_new(jdata, "drop", - json_integer(SC_ATOMIC_GET(pd->drop))); - json_object_set_new(jdata, "bypassed", - json_integer(SC_ATOMIC_GET(pd->bypassed))); - json_object_set_new(answer, "message", jdata); - SCReturnInt(TM_ECODE_OK); - } - } - json_object_set_new(answer, "message", json_string("Iface does not exist")); - SCReturnInt(TM_ECODE_FAILED); -} - -TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *answer, void *data) -{ - SCEnter(); - json_t *jdata; - json_t *jarray; - LiveDevice *pd; - int i = 0; - - jdata = json_object(); - if (jdata == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - return TM_ECODE_FAILED; - } - jarray = json_array(); - if (jarray == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - return TM_ECODE_FAILED; - } - TAILQ_FOREACH(pd, &live_devices, next) { - json_array_append_new(jarray, json_string(pd->dev)); - i++; - } - - json_object_set_new(jdata, "count", json_integer(i)); - json_object_set_new(jdata, "ifaces", jarray); - json_object_set_new(answer, "message", jdata); - SCReturnInt(TM_ECODE_OK); -} - -#endif /* BUILD_UNIX_SOCKET */ - -LiveDevice *LiveDeviceForEach(LiveDevice **ldev, LiveDevice **ndev) -{ - if (*ldev == NULL) { - *ldev = TAILQ_FIRST(&live_devices); - *ndev = TAILQ_NEXT(*ldev, next); - return *ldev; - } else { - *ldev = *ndev; - if (*ldev) { - *ndev = TAILQ_NEXT(*ldev, next); - } - return *ldev; - } - return NULL; -} - -/** - * Create registered devices - * - * This function creates all needed LiveDevice from - * the LiveDeviceName list created via LiveRegisterDevice() - */ -void LiveDeviceFinalize(void) -{ - LiveDeviceName *ld, *pld; - SCLogDebug("Finalize live device"); - /* Iter on devices and register them */ - TAILQ_FOREACH_SAFE(ld, &pre_live_devices, next, pld) { - if (ld->dev) { - LiveRegisterDevice(ld->dev); - SCFree(ld->dev); - } - SCFree(ld); - } -} - -static void LiveDevExtensionFree(void *x) -{ - if (x) - SCFree(x); -} - -/** - * Register bypass stats storage - */ -void LiveDevRegisterExtension(void) -{ - g_bypass_storage_id = LiveDevStorageRegister("bypass_stats", sizeof(void *), - NULL, LiveDevExtensionFree); -} - -/** - * Prepare a LiveDevice so we can set bypass stats - */ -int LiveDevUseBypass(LiveDevice *dev) -{ - BypassInfo *bpinfo = SCCalloc(1, sizeof(*bpinfo)); - if (bpinfo == NULL) { - SCLogError("Can't allocate bypass info structure"); - return -1; - } - - SC_ATOMIC_INIT(bpinfo->ipv4_hash_count); - SC_ATOMIC_INIT(bpinfo->ipv4_hash_count); - - LiveDevSetStorageById(dev, g_bypass_storage_id, bpinfo); - return 0; -} - -/** - * Set number of currently bypassed flows for a protocol family - * - * \param dev pointer to LiveDevice to set stats for - * \param cnt number of currently bypassed flows - * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count - */ -void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family) -{ - BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); - if (bpfdata) { - if (family == AF_INET) { - SC_ATOMIC_SET(bpfdata->ipv4_hash_count, cnt); - } else if (family == AF_INET6) { - SC_ATOMIC_SET(bpfdata->ipv6_hash_count, cnt); - } - } -} - -/** - * Increase number of currently bypassed flows for a protocol family - * - * \param dev pointer to LiveDevice to set stats for - * \param cnt number of flows to add - * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count - */ -void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family) -{ - BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); - if (bpfdata) { - if (family == AF_INET) { - SC_ATOMIC_ADD(bpfdata->ipv4_hash_count, cnt); - } else if (family == AF_INET6) { - SC_ATOMIC_ADD(bpfdata->ipv6_hash_count, cnt); - } - } -} - -/** - * Decrease number of currently bypassed flows for a protocol family - * - * \param dev pointer to LiveDevice to set stats for - * \param cnt number of flows to remove - * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count - */ -void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family) -{ - BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); - if (bpfdata) { - if (family == AF_INET) { - SC_ATOMIC_SUB(bpfdata->ipv4_hash_count, cnt); - } else if (family == AF_INET6) { - SC_ATOMIC_SUB(bpfdata->ipv6_hash_count, cnt); - } - } -} - -/** - * Increase number of failed captured flows for a protocol family - * - * \param dev pointer to LiveDevice to set stats for - * \param cnt number of flows to add - * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count - */ -void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family) -{ - BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); - if (bpfdata) { - if (family == AF_INET) { - SC_ATOMIC_ADD(bpfdata->ipv4_fail, cnt); - } else if (family == AF_INET6) { - SC_ATOMIC_ADD(bpfdata->ipv6_fail, cnt); - } - } -} - -/** - * Increase number of currently successfully bypassed flows for a protocol family - * - * \param dev pointer to LiveDevice to set stats for - * \param cnt number of flows to add - * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count - */ -void LiveDevAddBypassSuccess(LiveDevice *dev, uint64_t cnt, int family) -{ - BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); - if (bpfdata) { - if (family == AF_INET) { - SC_ATOMIC_ADD(bpfdata->ipv4_success, cnt); - } else if (family == AF_INET6) { - SC_ATOMIC_ADD(bpfdata->ipv6_success, cnt); - } - } -} - -#ifdef BUILD_UNIX_SOCKET -TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data) -{ - LiveDevice *ldev = NULL, *ndev = NULL; - - json_t *ifaces = NULL; - while(LiveDeviceForEach(&ldev, &ndev)) { - BypassInfo *bpinfo = LiveDevGetStorageById(ldev, g_bypass_storage_id); - if (bpinfo) { - uint64_t ipv4_hash_count = SC_ATOMIC_GET(bpinfo->ipv4_hash_count); - uint64_t ipv6_hash_count = SC_ATOMIC_GET(bpinfo->ipv6_hash_count); - uint64_t ipv4_success = SC_ATOMIC_GET(bpinfo->ipv4_success); - uint64_t ipv4_fail = SC_ATOMIC_GET(bpinfo->ipv4_fail); - uint64_t ipv6_success = SC_ATOMIC_GET(bpinfo->ipv6_success); - uint64_t ipv6_fail = SC_ATOMIC_GET(bpinfo->ipv6_fail); - json_t *iface = json_object(); - if (ifaces == NULL) { - ifaces = json_object(); - if (ifaces == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - return TM_ECODE_FAILED; - } - } - json_object_set_new(iface, "ipv4_maps_count", json_integer(ipv4_hash_count)); - json_object_set_new(iface, "ipv4_success", json_integer(ipv4_success)); - json_object_set_new(iface, "ipv4_fail", json_integer(ipv4_fail)); - json_object_set_new(iface, "ipv6_maps_count", json_integer(ipv6_hash_count)); - json_object_set_new(iface, "ipv6_success", json_integer(ipv6_success)); - json_object_set_new(iface, "ipv6_fail", json_integer(ipv6_fail)); - json_object_set_new(ifaces, ldev->dev, iface); - } - } - if (ifaces) { - json_object_set_new(answer, "message", ifaces); - SCReturnInt(TM_ECODE_OK); - } - - json_object_set_new(answer, "message", - json_string("No interface using bypass")); - SCReturnInt(TM_ECODE_FAILED); -} -#endif diff --git a/src/util-device.h b/src/util-device.h deleted file mode 100644 index d5a2d46caf08..000000000000 --- a/src/util-device.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2011-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __UTIL_DEVICE_H__ -#define __UTIL_DEVICE_H__ - -#ifdef HAVE_DPDK -#include -#endif /* HAVE_DPDK */ - -#include "queue.h" -#include "util-storage.h" - -#define OFFLOAD_FLAG_SG (1<<0) -#define OFFLOAD_FLAG_TSO (1<<1) -#define OFFLOAD_FLAG_GSO (1<<2) -#define OFFLOAD_FLAG_GRO (1<<3) -#define OFFLOAD_FLAG_LRO (1<<4) -#define OFFLOAD_FLAG_RXCSUM (1<<5) -#define OFFLOAD_FLAG_TXCSUM (1<<6) -#define OFFLOAD_FLAG_TOE (1<<7) - -void LiveSetOffloadDisable(void); -void LiveSetOffloadWarn(void); -int LiveGetOffload(void); - -#define MAX_DEVNAME 10 - -#ifdef HAVE_DPDK -typedef struct { - struct rte_mempool *pkt_mp; -} DPDKDeviceResources; -#endif /* HAVE_DPDK */ - -/** storage for live device names */ -typedef struct LiveDevice_ { - char *dev; /**< the device (e.g. "eth0") */ - char dev_short[MAX_DEVNAME + 1]; - int mtu; /* MTU of the device */ - bool tenant_id_set; - - uint16_t id; - - SC_ATOMIC_DECLARE(uint64_t, pkts); - SC_ATOMIC_DECLARE(uint64_t, drop); - SC_ATOMIC_DECLARE(uint64_t, bypassed); - SC_ATOMIC_DECLARE(uint64_t, invalid_checksums); - TAILQ_ENTRY(LiveDevice_) next; - - uint32_t tenant_id; /**< tenant id in multi-tenancy */ - uint32_t offload_orig; /**< original offload settings to restore @exit */ -#ifdef HAVE_DPDK - // DPDK resources that needs to be cleaned after workers are stopped and devices closed - DPDKDeviceResources dpdk_vars; -#endif - /** storage handle as a flex array member */ - Storage storage[]; -} LiveDevice; - -typedef struct LiveDeviceName_ { - char *dev; /**< the device (e.g. "eth0") */ - TAILQ_ENTRY(LiveDeviceName_) next; -} LiveDeviceName; - -void LiveDevRegisterExtension(void); - -int LiveRegisterDeviceName(const char *dev); -int LiveRegisterDevice(const char *dev); -int LiveDevUseBypass(LiveDevice *dev); -void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family); -void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family); -void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family); -void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family); -void LiveDevAddBypassSuccess(LiveDevice *dev, uint64_t cnt, int family); -int LiveGetDeviceCount(void); -const char *LiveGetDeviceName(int number); -LiveDevice *LiveGetDevice(const char *dev); -const char *LiveGetShortName(const char *dev); -int LiveBuildDeviceList(const char *base); -void LiveDeviceHasNoStats(void); -int LiveDeviceListClean(void); -int LiveBuildDeviceListCustom(const char *base, const char *itemname); - -LiveDevice *LiveDeviceForEach(LiveDevice **ldev, LiveDevice **ndev); - -void LiveDeviceFinalize(void); - -#ifdef BUILD_UNIX_SOCKET -TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *server_msg, void *data); -TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *server_msg, void *data); -TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data); -#endif - -#endif /* __UTIL_DEVICE_H__ */ diff --git a/src/util-dpdk-bonding.c b/src/util-dpdk-bonding.c deleted file mode 100644 index 59b92ba8294a..000000000000 --- a/src/util-dpdk-bonding.c +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright (C) 2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Lukas Sismis - */ - -#ifndef UTIL_DPDK_BONDING_C -#define UTIL_DPDK_BONDING_C - -#include "suricata-common.h" -#include "util-dpdk-bonding.h" - -#ifdef HAVE_DPDK - -#include "util-dpdk.h" -#include "util-debug.h" - -/** - * Determines if the port is Bond or not by evaluating device driver name - * @param pid port ID - * @return 0 - the device si Bond PMD, 1 - regular device, <0 error - */ -int32_t BondingIsBond(uint16_t pid) -{ - struct rte_eth_dev_info di; - int32_t ret = rte_eth_dev_info_get(pid, &di); - if (ret < 0) { - SCLogError("%s: unable to get device info (err: %s)", DPDKGetPortNameByPortID(pid), - rte_strerror(-ret)); - return ret; - } - - return strcmp(di.driver_name, "net_bonding") == 0 ? 0 : 1; -} - -uint16_t BondingMemberDevicesGet( - uint16_t bond_pid, uint16_t bonded_devs[], uint16_t bonded_devs_length) -{ -#ifdef HAVE_DPDK_BOND -#if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0) - int32_t len = rte_eth_bond_members_get(bond_pid, bonded_devs, bonded_devs_length); -#else - int32_t len = rte_eth_bond_slaves_get(bond_pid, bonded_devs, bonded_devs_length); -#endif /* RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0) */ - - if (len == 0) - FatalError("%s: no bonded devices found", DPDKGetPortNameByPortID(bond_pid)); - else if (len < 0) - FatalError("%s: unable to get bonded devices (err: %s)", DPDKGetPortNameByPortID(bond_pid), - rte_strerror(-len)); - - return len; -#else - FatalError( - "%s: bond port not supported in DPDK installation", DPDKGetPortNameByPortID(bond_pid)); -#endif -} - -int32_t BondingAllDevicesSameDriver(uint16_t bond_pid) -{ - uint16_t bonded_devs[RTE_MAX_ETHPORTS] = { 0 }; - uint16_t len = BondingMemberDevicesGet(bond_pid, bonded_devs, RTE_MAX_ETHPORTS); - - const char *driver_name = NULL, *first_driver_name = NULL; - struct rte_eth_dev_info di = { 0 }; - - for (uint16_t i = 0; i < len; i++) { - int32_t ret = rte_eth_dev_info_get(bonded_devs[i], &di); - if (ret < 0) - FatalError("%s: unable to get device info (err: %s)", - DPDKGetPortNameByPortID(bonded_devs[i]), rte_strerror(-ret)); - - if (i == 0) { - first_driver_name = di.driver_name; - } else { - driver_name = di.driver_name; - if (strncmp(first_driver_name, driver_name, - MIN(strlen(first_driver_name), strlen(driver_name))) != 0) { - return -EINVAL; // inconsistent drivers - } - } - } - - return 0; -} - -/** - * Translates to the driver that is actually used by the bonded ports - * \param bond_pid - * \return driver name, FatalError otherwise - */ -const char *BondingDeviceDriverGet(uint16_t bond_pid) -{ - uint16_t bonded_devs[RTE_MAX_ETHPORTS] = { 0 }; - BondingMemberDevicesGet(bond_pid, bonded_devs, RTE_MAX_ETHPORTS); - - struct rte_eth_dev_info di = { 0 }; - int32_t ret = rte_eth_dev_info_get(bonded_devs[0], &di); - if (ret < 0) - FatalError("%s: unable to get device info (err: %s)", - DPDKGetPortNameByPortID(bonded_devs[0]), rte_strerror(-ret)); - - return di.driver_name; -} - -#endif /* HAVE_DPDK */ - -#endif /* UTIL_DPDK_BONDING_C */ diff --git a/src/util-dpdk-i40e.c b/src/util-dpdk-i40e.c deleted file mode 100644 index 2484b45c793b..000000000000 --- a/src/util-dpdk-i40e.c +++ /dev/null @@ -1,416 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \defgroup dpdk DPDK Intel I40E driver helpers functions - * - * @{ - */ - -/** - * \file - * - * \author Lukas Sismis - * - * DPDK driver's helper functions - * - */ - -#include "util-dpdk-i40e.h" -#include "util-dpdk.h" -#include "util-debug.h" -#include "util-dpdk-bonding.h" - -#ifdef HAVE_DPDK - -#define I40E_RSS_HKEY_LEN 52 - -#if RTE_VERSION < RTE_VERSION_NUM(20, 0, 0, 0) -static int i40eDeviceEnableSymHash( - int port_id, const char *port_name, uint32_t ftype, enum rte_eth_hash_function function) -{ - struct rte_eth_hash_filter_info info; - int retval; - uint32_t idx, offset; - - memset(&info, 0, sizeof(info)); - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - retval = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_HASH); -#pragma GCC diagnostic pop - if (retval < 0) { - SCLogError("RTE_ETH_FILTER_HASH not supported on port: %s", port_name); - return retval; - } - - info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG; - info.info.global_conf.hash_func = function; - - idx = ftype / UINT64_BIT; - offset = ftype % UINT64_BIT; - info.info.global_conf.valid_bit_mask[idx] |= (1ULL << offset); - info.info.global_conf.sym_hash_enable_mask[idx] |= (1ULL << offset); - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - retval = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH, RTE_ETH_FILTER_SET, &info); -#pragma GCC diagnostic pop - - if (retval < 0) { - SCLogError("Cannot set global hash configurations on port %s", port_name); - return retval; - } - - return 0; -} - -static int i40eDeviceSetSymHash(int port_id, const char *port_name, int enable) -{ - int ret; - struct rte_eth_hash_filter_info info; - - memset(&info, 0, sizeof(info)); - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_HASH); -#pragma GCC diagnostic pop - - if (ret < 0) { - SCLogError("RTE_ETH_FILTER_HASH not supported on port: %s", port_name); - return ret; - } - - info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT; - info.info.enable = enable; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH, RTE_ETH_FILTER_SET, &info); -#pragma GCC diagnostic pop - - if (ret < 0) { - SCLogError("Cannot set symmetric hash enable per port on port %s", port_name); - return ret; - } - - return 0; -} - -static int i40eDeviceApplyRSSFilter(int port_id, const char *port_name) -{ - int retval = 0; - - // Behavior of RTE_FLOW in DPDK version 19.xx and less is different than on versions - // above. For that reason RSS on i40e driver is set differently. - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_FRAG_IPV4, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_FRAG_IPV6, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_TCP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_SCTP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - retval |= i40eDeviceEnableSymHash( - port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, RTE_ETH_HASH_FUNCTION_TOEPLITZ); - - retval |= i40eDeviceSetSymHash(port_id, port_name, 1); - return retval; -} - -static int32_t i40eDeviceSetRSSWithFilter(int port_id, const char *port_name) -{ - int32_t ret = BondingIsBond(port_id); - if (ret < 0) - return -ret; - - if (ret == 1) { // regular device - i40eDeviceApplyRSSFilter(port_id, port_name); - } else if (ret == 0) { // the device is Bond PMD - uint16_t bonded_devs[RTE_MAX_ETHPORTS]; - ret = BondingMemberDevicesGet(port_id, bonded_devs, RTE_MAX_ETHPORTS); - for (int i = 0; i < ret; i++) { - i40eDeviceApplyRSSFilter(bonded_devs[i], port_name); - } - } else { - FatalError("Unknown return value from BondingIsBond()"); - } - - return 0; -} - -#else - -static int i40eDeviceSetRSSFlowQueues( - int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf, int nb_rx_queues) -{ - struct rte_flow_action_rss rss_action_conf = { 0 }; - struct rte_flow_attr attr = { 0 }; - struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } }; - struct rte_flow_action action[] = { { 0 }, { 0 } }; - struct rte_flow *flow; - struct rte_flow_error flow_error = { 0 }; - uint16_t queues[RTE_MAX_QUEUES_PER_PORT]; - - for (int i = 0; i < nb_rx_queues; ++i) - queues[i] = i; - - rss_action_conf.func = RTE_ETH_HASH_FUNCTION_DEFAULT; - rss_action_conf.level = 0; - rss_action_conf.types = 0; // queues region can not be configured with types - rss_action_conf.key_len = 0; - rss_action_conf.key = NULL; - - if (nb_rx_queues < 1) { - FatalError("The number of queues for RSS configuration must be " - "configured with a positive number"); - } - - rss_action_conf.queue_num = nb_rx_queues; - rss_action_conf.queue = queues; - - attr.ingress = 1; - pattern[0].type = RTE_FLOW_ITEM_TYPE_END; - action[0].type = RTE_FLOW_ACTION_TYPE_RSS; - action[0].conf = &rss_action_conf; - action[1].type = RTE_FLOW_ACTION_TYPE_END; - - flow = rte_flow_create(port_id, &attr, pattern, action, &flow_error); - if (flow == NULL) { - SCLogError("Error when creating rte_flow rule on %s: %s", port_name, flow_error.message); - int ret = rte_flow_validate(port_id, &attr, pattern, action, &flow_error); - SCLogError("Error on rte_flow validation for port %s: %s errmsg: %s", port_name, - rte_strerror(-ret), flow_error.message); - return ret; - } else { - SCLogInfo("RTE_FLOW queue region created for port %s", port_name); - } - return 0; -} - -static int i40eDeviceCreateRSSFlow(int port_id, const char *port_name, - struct rte_eth_rss_conf rss_conf, uint64_t rss_type, struct rte_flow_item *pattern) -{ - struct rte_flow_action_rss rss_action_conf = { 0 }; - struct rte_flow_attr attr = { 0 }; - struct rte_flow_action action[] = { { 0 }, { 0 } }; - struct rte_flow *flow; - struct rte_flow_error flow_error = { 0 }; - - rss_action_conf.func = RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ; - rss_action_conf.level = 0; - rss_action_conf.types = rss_type; - rss_action_conf.key_len = rss_conf.rss_key_len; - rss_action_conf.key = rss_conf.rss_key; - rss_action_conf.queue_num = 0; - rss_action_conf.queue = NULL; - - attr.ingress = 1; - action[0].type = RTE_FLOW_ACTION_TYPE_RSS; - action[0].conf = &rss_action_conf; - action[1].type = RTE_FLOW_ACTION_TYPE_END; - - flow = rte_flow_create(port_id, &attr, pattern, action, &flow_error); - if (flow == NULL) { - SCLogError("Error when creating rte_flow rule on %s: %s", port_name, flow_error.message); - int ret = rte_flow_validate(port_id, &attr, pattern, action, &flow_error); - SCLogError("Error on rte_flow validation for port %s: %s errmsg: %s", port_name, - rte_strerror(-ret), flow_error.message); - return ret; - } else { - SCLogInfo("RTE_FLOW flow rule created for port %s", port_name); - } - - return 0; -} - -static int i40eDeviceSetRSSFlowIPv4( - int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf) -{ - int ret = 0; - struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } }; - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; - pattern[2].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_OTHER, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; - pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP; - pattern[3].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_UDP, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; - pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP; - pattern[3].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_TCP, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; - pattern[2].type = RTE_FLOW_ITEM_TYPE_SCTP; - pattern[3].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_SCTP, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; - pattern[2].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, RTE_ETH_RSS_FRAG_IPV4, pattern); - - return ret; -} - -static int i40eDeviceSetRSSFlowIPv6( - int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf) -{ - int ret = 0; - struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } }; - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; - pattern[2].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_OTHER, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; - pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP; - pattern[3].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_UDP, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; - pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP; - pattern[3].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_TCP, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; - pattern[2].type = RTE_FLOW_ITEM_TYPE_SCTP; - pattern[3].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow( - port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_SCTP, pattern); - memset(pattern, 0, sizeof(pattern)); - - pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; - pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; - pattern[2].type = RTE_FLOW_ITEM_TYPE_END; - ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, RTE_ETH_RSS_FRAG_IPV6, pattern); - - return ret; -} - -static int i40eDeviceSetRSSWithFlows(int port_id, const char *port_name, int nb_rx_queues) -{ - int retval; - uint8_t rss_key[I40E_RSS_HKEY_LEN]; - struct rte_flow_error flush_error = { 0 }; - struct rte_eth_rss_conf rss_conf = { - .rss_key = rss_key, - .rss_key_len = I40E_RSS_HKEY_LEN, - }; - - retval = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf); - if (retval != 0) { - SCLogError("Unable to get RSS hash configuration of port %s", port_name); - return retval; - } - - retval = 0; - retval |= i40eDeviceSetRSSFlowQueues(port_id, port_name, rss_conf, nb_rx_queues); - retval |= i40eDeviceSetRSSFlowIPv4(port_id, port_name, rss_conf); - retval |= i40eDeviceSetRSSFlowIPv6(port_id, port_name, rss_conf); - if (retval != 0) { - retval = rte_flow_flush(port_id, &flush_error); - if (retval != 0) { - SCLogError("Unable to flush rte_flow rules of %s: %s Flush error msg: %s", port_name, - rte_strerror(-retval), flush_error.message); - } - return retval; - } - - return 0; -} - -#endif /* RTE_VERSION < RTE_VERSION_NUM(20,0,0,0) */ - -int i40eDeviceSetRSS(int port_id, int nb_rx_queues) -{ - int retval; - (void)nb_rx_queues; // avoid unused variable warnings - char port_name[RTE_ETH_NAME_MAX_LEN]; - - retval = rte_eth_dev_get_name_by_port(port_id, port_name); - if (unlikely(retval != 0)) { - SCLogError("Failed to convert port id %d to the interface name: %s", port_id, - strerror(-retval)); - return retval; - } - -#if RTE_VERSION >= RTE_VERSION_NUM(20, 0, 0, 0) - i40eDeviceSetRSSWithFlows(port_id, port_name, nb_rx_queues); -#else - i40eDeviceSetRSSWithFilter(port_id, port_name); -#endif - return 0; -} - -void i40eDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf) -{ -#if RTE_VERSION >= RTE_VERSION_NUM(20, 0, 0, 0) - rss_conf->rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | - RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_OTHER; - rss_conf->rss_key = NULL; - rss_conf->rss_key_len = 0; -#else - rss_conf->rss_hf = - RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV4_UDP | - RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 | - RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_NONFRAG_IPV6_UDP | - RTE_ETH_RSS_NONFRAG_IPV6_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_OTHER | RTE_ETH_RSS_SCTP; -#endif -} - -#endif /* HAVE_DPDK */ -/** - * @} - */ diff --git a/src/util-dpdk-i40e.h b/src/util-dpdk-i40e.h deleted file mode 100644 index 6133aed5d771..000000000000 --- a/src/util-dpdk-i40e.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Lukas Sismis - */ - -#ifndef UTIL_DPDK_I40E_H -#define UTIL_DPDK_I40E_H - -#include "suricata-common.h" - -#ifdef HAVE_DPDK - -#include "util-dpdk.h" - -int i40eDeviceSetRSS(int port_id, int nb_rx_queues); -void i40eDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf); - -#endif /* HAVE_DPDK */ - -#endif /* UTIL_DPDK_I40E_H */ diff --git a/src/util-dpdk-ice.c b/src/util-dpdk-ice.c deleted file mode 100644 index 36f4481dea2f..000000000000 --- a/src/util-dpdk-ice.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \defgroup dpdk DPDK Intel ICE driver helpers functions - * - * @{ - */ - -/** - * \file - * - * \author Lukas Sismis - * - * DPDK driver's helper functions - * - */ - -#include "util-dpdk-ice.h" -#include "util-dpdk.h" - -#ifdef HAVE_DPDK - -void iceDeviceSetRSSHashFunction(uint64_t *rss_hf) -{ -#if RTE_VERSION < RTE_VERSION_NUM(20, 0, 0, 0) - *rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 | - RTE_ETH_RSS_NONFRAG_IPV6_OTHER; -#else - *rss_hf = RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | - RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_OTHER; -#endif -} - -#endif /* HAVE_DPDK */ -/** - * @} - */ diff --git a/src/util-dpdk-ixgbe.c b/src/util-dpdk-ixgbe.c deleted file mode 100644 index 5627c45270d1..000000000000 --- a/src/util-dpdk-ixgbe.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \defgroup dpdk DPDK Intel IXGBE driver helpers functions - * - * @{ - */ - -/** - * \file - * - * \author Lukas Sismis - * - * DPDK driver's helper functions - * - */ - -#include "util-dpdk-ixgbe.h" -#include "util-dpdk.h" - -#ifdef HAVE_DPDK - -void ixgbeDeviceSetRSSHashFunction(uint64_t *rss_hf) -{ - *rss_hf = RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_IPV6_EX; -} - -#endif /* HAVE_DPDK */ -/** - * @} - */ diff --git a/src/util-dpdk.c b/src/util-dpdk.c deleted file mode 100644 index 089aa45674ae..000000000000 --- a/src/util-dpdk.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Lukas Sismis - */ - -#include "suricata.h" -#include "util-dpdk.h" -#include "util-debug.h" -#include "util-byte.h" - -void DPDKCleanupEAL(void) -{ -#ifdef HAVE_DPDK - if (run_mode == RUNMODE_DPDK) { - int retval = rte_eal_cleanup(); - if (retval != 0) - SCLogError("EAL cleanup failed: %s", strerror(-retval)); - } -#endif -} - -void DPDKCloseDevice(LiveDevice *ldev) -{ - (void)ldev; // avoid warnings of unused variable -#ifdef HAVE_DPDK - if (run_mode == RUNMODE_DPDK) { - uint16_t port_id; - int retval = rte_eth_dev_get_port_by_name(ldev->dev, &port_id); - if (retval < 0) { - SCLogError("%s: failed get port id, error: %s", ldev->dev, rte_strerror(-retval)); - return; - } - - SCLogPerf("%s: closing device", ldev->dev); - rte_eth_dev_close(port_id); - } -#endif -} - -void DPDKFreeDevice(LiveDevice *ldev) -{ - (void)ldev; // avoid warnings of unused variable -#ifdef HAVE_DPDK - if (run_mode == RUNMODE_DPDK) { - SCLogDebug("%s: releasing packet mempool", ldev->dev); - rte_mempool_free(ldev->dpdk_vars.pkt_mp); - } -#endif -} - -static FILE *HugepagesMeminfoOpen(void) -{ - FILE *fp = fopen("/proc/meminfo", "r"); - if (fp == NULL) { - SCLogInfo("Can't analyze hugepage usage: failed to open /proc/meminfo"); - } - return fp; -} - -static void HugepagesMeminfoClose(FILE *fp) -{ - if (fp) { - fclose(fp); - } -} - -/** - * Parsing values of meminfo - * - * \param fp Opened file pointer for reading of file /proc/meminfo at beginning - * \param keyword Entry to look for e.g. "HugePages_Free:" - * \return n Value of the entry - * \return -1 On error - * - */ -static int32_t MemInfoParseValue(FILE *fp, const char *keyword) -{ - char path[256], value_str[64]; - int32_t value = -1; - - while (fscanf(fp, "%255s", path) != EOF) { - if (strcmp(path, keyword) == 0) { - if (fscanf(fp, "%63s", value_str) == EOF) { - SCLogDebug("%s: not followed by any number", keyword); - break; - } - - if (StringParseInt32(&value, 10, 23, value_str) < 0) { - SCLogDebug("Failed to convert %s from /proc/meminfo", keyword); - value = -1; - } - break; - } - } - return value; -} - -static void MemInfoEvaluateHugepages(FILE *fp) -{ - int32_t free_hugepages = MemInfoParseValue(fp, "HugePages_Free:"); - if (free_hugepages < 0) { - SCLogInfo("HugePages_Free information not found in /proc/meminfo"); - return; - } - - rewind(fp); - - int32_t total_hugepages = MemInfoParseValue(fp, "HugePages_Total:"); - if (total_hugepages < 0) { - SCLogInfo("HugePages_Total information not found in /proc/meminfo"); - return; - } else if (total_hugepages == 0) { - SCLogInfo("HugePages_Total equals to zero"); - return; - } - - float free_hugepages_ratio = (float)free_hugepages / (float)total_hugepages; - if (free_hugepages_ratio > 0.5) { - SCLogInfo("%" PRIu32 " of %" PRIu32 - " of hugepages are free - number of hugepages can be lowered to e.g. %.0lf", - free_hugepages, total_hugepages, ceil((total_hugepages - free_hugepages) * 1.15)); - } -} - -static void MemInfoWith(void (*callback)(FILE *)) -{ - FILE *fp = HugepagesMeminfoOpen(); - if (fp) { - callback(fp); - HugepagesMeminfoClose(fp); - } -} - -void DPDKEvaluateHugepages(void) -{ - if (run_mode != RUNMODE_DPDK) - return; - -#ifdef HAVE_DPDK - if (rte_eal_has_hugepages() == 0) { // hugepages disabled - SCLogPerf("Hugepages not enabled - enabling hugepages can improve performance"); - return; - } -#endif - - MemInfoWith(MemInfoEvaluateHugepages); -} - -#ifdef HAVE_DPDK - -/** - * Retrieves name of the port from port id - * Not thread-safe - * @param pid - * @return static dev_name on success - */ -const char *DPDKGetPortNameByPortID(uint16_t pid) -{ - static char dev_name[RTE_ETH_NAME_MAX_LEN]; - int32_t ret = rte_eth_dev_get_name_by_port(pid, dev_name); - if (ret < 0) { - FatalError("Port %d: Failed to obtain port name (err: %s)", pid, rte_strerror(-ret)); - } - return dev_name; -} - -#endif /* HAVE_DPDK */ diff --git a/src/util-dpdk.h b/src/util-dpdk.h deleted file mode 100644 index a94f46225217..000000000000 --- a/src/util-dpdk.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright (C) 2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Lukas Sismis - */ - -#ifndef UTIL_DPDK_H -#define UTIL_DPDK_H - -#ifdef HAVE_DPDK - -#include -#include -#ifdef HAVE_DPDK_BOND -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#if RTE_VERSION < RTE_VERSION_NUM(22, 0, 0, 0) -#define RTE_ETH_MQ_RX_RSS ETH_MQ_RX_RSS -#endif - -#if RTE_VERSION < RTE_VERSION_NUM(21, 11, 0, 0) -#define RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE DEV_TX_OFFLOAD_MBUF_FAST_FREE - -#define RTE_ETH_RX_OFFLOAD_CHECKSUM DEV_RX_OFFLOAD_CHECKSUM - -#define RTE_ETH_RX_OFFLOAD_VLAN_STRIP DEV_RX_OFFLOAD_VLAN_STRIP -#define RTE_ETH_RX_OFFLOAD_IPV4_CKSUM DEV_RX_OFFLOAD_IPV4_CKSUM -#define RTE_ETH_RX_OFFLOAD_UDP_CKSUM DEV_RX_OFFLOAD_UDP_CKSUM -#define RTE_ETH_RX_OFFLOAD_TCP_CKSUM DEV_RX_OFFLOAD_TCP_CKSUM -#define RTE_ETH_RX_OFFLOAD_TCP_LRO DEV_RX_OFFLOAD_TCP_LRO -#define RTE_ETH_RX_OFFLOAD_QINQ_STRIP DEV_RX_OFFLOAD_QINQ_STRIP -#define RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM -#define RTE_ETH_RX_OFFLOAD_MACSEC_STRIP DEV_RX_OFFLOAD_MACSEC_STRIP -#define RTE_ETH_RX_OFFLOAD_HEADER_SPLIT DEV_RX_OFFLOAD_HEADER_SPLIT -#define RTE_ETH_RX_OFFLOAD_VLAN_FILTER DEV_RX_OFFLOAD_VLAN_FILTER -#define RTE_ETH_RX_OFFLOAD_VLAN_EXTEND DEV_RX_OFFLOAD_VLAN_EXTEND -#define RTE_ETH_RX_OFFLOAD_SCATTER DEV_RX_OFFLOAD_SCATTER -#define RTE_ETH_RX_OFFLOAD_TIMESTAMP DEV_RX_OFFLOAD_TIMESTAMP -#define RTE_ETH_RX_OFFLOAD_SECURITY DEV_RX_OFFLOAD_SECURITY -#define RTE_ETH_RX_OFFLOAD_KEEP_CRC DEV_RX_OFFLOAD_KEEP_CRC -#define RTE_ETH_RX_OFFLOAD_SCTP_CKSUM DEV_RX_OFFLOAD_SCTP_CKSUM -#define RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM DEV_RX_OFFLOAD_OUTER_UDP_CKSUM -#define RTE_ETH_RX_OFFLOAD_RSS_HASH DEV_RX_OFFLOAD_RSS_HASH - -#define RTE_ETH_MQ_TX_NONE ETH_MQ_TX_NONE - -#define RTE_ETH_MQ_RX_NONE ETH_MQ_RX_NONE - -#define RTE_ETH_RSS_IP ETH_RSS_IP -#define RTE_ETH_RSS_UDP ETH_RSS_UDP -#define RTE_ETH_RSS_TCP ETH_RSS_TCP -#define RTE_ETH_RSS_SCTP ETH_RSS_SCTP -#define RTE_ETH_RSS_TUNNEL ETH_RSS_TUNNEL - -#define RTE_ETH_RSS_L3_SRC_ONLY ETH_RSS_L3_SRC_ONLY -#define RTE_ETH_RSS_L3_DST_ONLY ETH_RSS_L3_DST_ONLY -#define RTE_ETH_RSS_L4_SRC_ONLY ETH_RSS_L4_SRC_ONLY -#define RTE_ETH_RSS_L4_DST_ONLY ETH_RSS_L4_DST_ONLY - -#define RTE_ETH_RSS_IPV4 ETH_RSS_IPV4 -#define RTE_ETH_RSS_FRAG_IPV4 ETH_RSS_FRAG_IPV4 -#define RTE_ETH_RSS_NONFRAG_IPV4_TCP ETH_RSS_NONFRAG_IPV4_TCP -#define RTE_ETH_RSS_NONFRAG_IPV4_UDP ETH_RSS_NONFRAG_IPV4_UDP -#define RTE_ETH_RSS_NONFRAG_IPV4_SCTP ETH_RSS_NONFRAG_IPV4_SCTP -#define RTE_ETH_RSS_NONFRAG_IPV4_OTHER ETH_RSS_NONFRAG_IPV4_OTHER -#define RTE_ETH_RSS_IPV6 ETH_RSS_IPV6 -#define RTE_ETH_RSS_FRAG_IPV6 ETH_RSS_FRAG_IPV6 -#define RTE_ETH_RSS_NONFRAG_IPV6_TCP ETH_RSS_NONFRAG_IPV6_TCP -#define RTE_ETH_RSS_NONFRAG_IPV6_UDP ETH_RSS_NONFRAG_IPV6_UDP -#define RTE_ETH_RSS_NONFRAG_IPV6_SCTP ETH_RSS_NONFRAG_IPV6_SCTP -#define RTE_ETH_RSS_NONFRAG_IPV6_OTHER ETH_RSS_NONFRAG_IPV6_OTHER -#define RTE_ETH_RSS_L2_PAYLOAD ETH_RSS_L2_PAYLOAD -#define RTE_ETH_RSS_IPV6_EX ETH_RSS_IPV6_EX -#define RTE_ETH_RSS_IPV6_TCP_EX ETH_RSS_IPV6_TCP_EX -#define RTE_ETH_RSS_IPV6_UDP_EX ETH_RSS_IPV6_UDP_EX -#define RTE_ETH_RSS_PORT ETH_RSS_PORT -#define RTE_ETH_RSS_VXLAN ETH_RSS_VXLAN -#define RTE_ETH_RSS_NVGRE ETH_RSS_NVGRE -#define RTE_ETH_RSS_GTPU ETH_RSS_GTPU - -#define RTE_MBUF_F_RX_IP_CKSUM_MASK PKT_RX_IP_CKSUM_MASK -#define RTE_MBUF_F_RX_IP_CKSUM_NONE PKT_RX_IP_CKSUM_NONE -#define RTE_MBUF_F_RX_IP_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD -#define RTE_MBUF_F_RX_IP_CKSUM_BAD PKT_RX_IP_CKSUM_BAD - -#define RTE_MBUF_F_RX_L4_CKSUM_MASK PKT_RX_L4_CKSUM_MASK -#define RTE_MBUF_F_RX_L4_CKSUM_GOOD PKT_RX_L4_CKSUM_GOOD -#define RTE_MBUF_F_RX_L4_CKSUM_BAD PKT_RX_L4_CKSUM_BAD -#endif - -#endif /* HAVE_DPDK */ - -#include "util-device.h" - -void DPDKCleanupEAL(void); - -void DPDKCloseDevice(LiveDevice *ldev); -void DPDKFreeDevice(LiveDevice *ldev); -void DPDKEvaluateHugepages(void); - -#ifdef HAVE_DPDK -const char *DPDKGetPortNameByPortID(uint16_t pid); -#endif /* HAVE_DPDK */ - -#endif /* UTIL_DPDK_H */ diff --git a/src/util-ebpf.c b/src/util-ebpf.c deleted file mode 100644 index 13eaea828d9b..000000000000 --- a/src/util-ebpf.c +++ /dev/null @@ -1,1077 +0,0 @@ -/* Copyright (C) 2018-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup afppacket - * - * @{ - */ - -/** - * \file - * - * \author Eric Leblond - * - * eBPF utility - * - */ - -#define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 -#define SC_PCAP_DONT_INCLUDE_PCAP_H 1 - -#include "suricata-common.h" -#include "flow-bypass.h" - -#ifdef HAVE_PACKET_EBPF - -#include -#include - -#include "util-ebpf.h" -#include "util-affinity.h" -#include "util-cpu.h" -#include "util-device.h" - -#include "device-storage.h" -#include "flow-storage.h" -#include "flow.h" -#include "flow-hash.h" -#include "tm-threads.h" - -#include -#include -#include -#include "autoconf.h" - -#define BPF_MAP_MAX_COUNT 16 - -#define BYPASSED_FLOW_TIMEOUT 60 - -static LiveDevStorageId g_livedev_storage_id = { .id = -1 }; -static FlowStorageId g_flow_storage_id = { .id = -1 }; - -struct bpf_map_item { - char iface[IFNAMSIZ]; - char * name; - int fd; - uint8_t to_unlink; -}; - -struct bpf_maps_info { - struct bpf_map_item array[BPF_MAP_MAX_COUNT]; - int last; -}; - -typedef struct BypassedIfaceList_ { - LiveDevice *dev; - struct BypassedIfaceList_ *next; -} BypassedIfaceList; - -static void BpfMapsInfoFree(void *bpf) -{ - struct bpf_maps_info *bpfinfo = (struct bpf_maps_info *)bpf; - int i; - for (i = 0; i < bpfinfo->last; i ++) { - if (bpfinfo->array[i].name) { - if (bpfinfo->array[i].to_unlink) { - char pinnedpath[PATH_MAX]; - int ret = snprintf(pinnedpath, sizeof(pinnedpath), - "/sys/fs/bpf/suricata-%s-%s", - bpfinfo->array[i].iface, - bpfinfo->array[i].name); - if (ret > 0) { - /* Unlink the pinned entry */ - ret = unlink(pinnedpath); - if (ret == -1) { - int error = errno; - SCLogWarning( - "Unable to remove %s: %s (%d)", pinnedpath, strerror(error), error); - } - } else { - SCLogWarning("Unable to remove map %s", bpfinfo->array[i].name); - } - } - SCFree(bpfinfo->array[i].name); - } - } - SCFree(bpfinfo); -} - -static void BypassedListFree(void *ifl) -{ - BypassedIfaceList *mifl = (BypassedIfaceList *)ifl; - BypassedIfaceList *nifl; - while (mifl) { - nifl = mifl->next; - SCFree(mifl); - mifl = nifl; - } -} - -void EBPFDeleteKey(int fd, void *key) -{ - int ret = bpf_map_delete_elem(fd, key); - if (ret < 0) { - SCLogWarning("Unable to delete entry: %s (%d)", strerror(errno), errno); - } -} - -static struct bpf_maps_info *EBPFGetBpfMap(const char *iface) -{ - LiveDevice *livedev = LiveGetDevice(iface); - if (livedev == NULL) - return NULL; - void *data = LiveDevGetStorageById(livedev, g_livedev_storage_id); - - return (struct bpf_maps_info *)data; -} - -/** - * Get file descriptor of a map in the scope of a interface - * - * \param iface the interface where the map need to be looked for - * \param name the name of the map - * \return the file descriptor or -1 in case of error - */ -int EBPFGetMapFDByName(const char *iface, const char *name) -{ - int i; - - if (iface == NULL || name == NULL) - return -1; - struct bpf_maps_info *bpf_maps = EBPFGetBpfMap(iface); - if (bpf_maps == NULL) - return -1; - - for (i = 0; i < BPF_MAP_MAX_COUNT; i++) { - if (!bpf_maps->array[i].name) - continue; - if (!strcmp(bpf_maps->array[i].name, name)) { - SCLogDebug("Got fd %d for eBPF map '%s'", bpf_maps->array[i].fd, name); - return bpf_maps->array[i].fd; - } - } - - return -1; -} - -static int EBPFLoadPinnedMapsFile(LiveDevice *livedev, const char *file) -{ - char pinnedpath[1024]; - snprintf(pinnedpath, sizeof(pinnedpath), - "/sys/fs/bpf/suricata-%s-%s", - livedev->dev, - file); - - return bpf_obj_get(pinnedpath); -} - -static int EBPFLoadPinnedMaps(LiveDevice *livedev, struct ebpf_timeout_config *config) -{ - int fd_v4 = -1, fd_v6 = -1; - - /* First try to load the eBPF check map and return if found */ - if (config->pinned_maps_name) { - int ret = EBPFLoadPinnedMapsFile(livedev, config->pinned_maps_name); - if (ret == 0) { - /* pinned maps found, let's just exit as XDP filter is in place */ - return ret; - } - } - - if (config->mode == AFP_MODE_XDP_BYPASS) { - /* Get flow v4 table */ - fd_v4 = EBPFLoadPinnedMapsFile(livedev, "flow_table_v4"); - if (fd_v4 < 0) { - return fd_v4; - } - - /* Get flow v6 table */ - fd_v6 = EBPFLoadPinnedMapsFile(livedev, "flow_table_v6"); - if (fd_v6 < 0) { - SCLogWarning("Found a flow_table_v4 map but no flow_table_v6 map"); - return fd_v6; - } - } - - struct bpf_maps_info *bpf_map_data = SCCalloc(1, sizeof(*bpf_map_data)); - if (bpf_map_data == NULL) { - SCLogError("Can't allocate bpf map array"); - return -1; - } - - if (config->mode == AFP_MODE_XDP_BYPASS) { - bpf_map_data->array[0].fd = fd_v4; - bpf_map_data->array[0].name = SCStrdup("flow_table_v4"); - if (bpf_map_data->array[0].name == NULL) { - goto alloc_error; - } - bpf_map_data->array[1].fd = fd_v6; - bpf_map_data->array[1].name = SCStrdup("flow_table_v6"); - if (bpf_map_data->array[1].name == NULL) { - goto alloc_error; - } - bpf_map_data->last = 2; - } else { - bpf_map_data->last = 0; - } - - /* Load other known maps: cpu_map, cpus_available, tx_peer, tx_peer_int */ - int fd = EBPFLoadPinnedMapsFile(livedev, "cpu_map"); - if (fd >= 0) { - bpf_map_data->array[bpf_map_data->last].fd = fd; - bpf_map_data->array[bpf_map_data->last].name = SCStrdup("cpu_map"); - if (bpf_map_data->array[bpf_map_data->last].name == NULL) { - goto alloc_error; - } - bpf_map_data->last++; - } - fd = EBPFLoadPinnedMapsFile(livedev, "cpus_available"); - if (fd >= 0) { - bpf_map_data->array[bpf_map_data->last].fd = fd; - bpf_map_data->array[bpf_map_data->last].name = SCStrdup("cpus_available"); - if (bpf_map_data->array[bpf_map_data->last].name == NULL) { - goto alloc_error; - } - bpf_map_data->last++; - } - fd = EBPFLoadPinnedMapsFile(livedev, "tx_peer"); - if (fd >= 0) { - bpf_map_data->array[bpf_map_data->last].fd = fd; - bpf_map_data->array[bpf_map_data->last].name = SCStrdup("tx_peer"); - if (bpf_map_data->array[bpf_map_data->last].name == NULL) { - goto alloc_error; - } - bpf_map_data->last++; - } - fd = EBPFLoadPinnedMapsFile(livedev, "tx_peer_int"); - if (fd >= 0) { - bpf_map_data->array[bpf_map_data->last].fd = fd; - bpf_map_data->array[bpf_map_data->last].name = SCStrdup("tx_peer_int"); - if (bpf_map_data->array[bpf_map_data->last].name == NULL) { - goto alloc_error; - } - bpf_map_data->last++; - } - - /* Attach the bpf_maps_info to the LiveDevice via the device storage */ - LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data); - /* Declare that device will use bypass stats */ - LiveDevUseBypass(livedev); - - return 0; - -alloc_error: - for (int i = 0; i < bpf_map_data->last; i++) { - SCFree(bpf_map_data->array[i].name); - } - bpf_map_data->last = 0; - SCLogError("Can't allocate bpf map name"); - return -1; -} - -/** - * Load a section of an eBPF file - * - * This function loads a section inside an eBPF and return - * via the parameter val the file descriptor that will be used to - * inject the eBPF code into the kernel via a syscall. - * - * \param path the path of the eBPF file to load - * \param section the section in the eBPF file to load - * \param val a pointer to an integer that will be the file desc - * \return -1 in case of error, 0 in case of success, 1 if pinned maps is loaded - */ -int EBPFLoadFile(const char *iface, const char *path, const char * section, - int *val, struct ebpf_timeout_config *config) -{ - int err, pfd; - bool found = false; - struct bpf_object *bpfobj = NULL; - struct bpf_program *bpfprog = NULL; - struct bpf_map *map = NULL; - - if (iface == NULL) - return -1; - LiveDevice *livedev = LiveGetDevice(iface); - if (livedev == NULL) - return -1; - - if (config->flags & EBPF_XDP_CODE && config->flags & EBPF_PINNED_MAPS) { - /* We try to get our flow table maps and if we have them we can simply return */ - if (EBPFLoadPinnedMaps(livedev, config) == 0) { - SCLogInfo("Loaded pinned maps, will use already loaded eBPF filter"); - return 1; - } - } - - if (! path) { - SCLogError("No file defined to load eBPF from"); - return -1; - } - - /* Sending the eBPF code to the kernel requires a large amount of - * locked memory so we set it to unlimited to avoid a ENOPERM error */ - struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; - if (setrlimit(RLIMIT_MEMLOCK, &r) != 0) { - SCLogError("Unable to lock memory: %s (%d)", strerror(errno), errno); - return -1; - } - - /* Open the eBPF file and parse it */ - bpfobj = bpf_object__open(path); - long error = libbpf_get_error(bpfobj); - if (error) { - char err_buf[128]; - libbpf_strerror(error, err_buf, - sizeof(err_buf)); - SCLogError("Unable to load eBPF objects in '%s': %s", path, err_buf); - return -1; - } - - if (config->flags & EBPF_XDP_HW_MODE) { - unsigned int ifindex = if_nametoindex(iface); - bpf_object__for_each_program(bpfprog, bpfobj) { - bpf_program__set_ifindex(bpfprog, ifindex); - } - bpf_map__for_each(map, bpfobj) { - bpf_map__set_ifindex(map, ifindex); - } - } - - /* Let's check that our section is here */ - bpf_object__for_each_program(bpfprog, bpfobj) { -#ifdef HAVE_BPF_PROGRAM__SECTION_NAME - const char *title = bpf_program__section_name(bpfprog); -#else - const char *title = bpf_program__title(bpfprog, 0); -#endif - if (!strcmp(title, section)) { - if (config->flags & EBPF_SOCKET_FILTER) { -#ifdef HAVE_BPF_PROGRAM__SET_TYPE - bpf_program__set_type(bpfprog, BPF_PROG_TYPE_SOCKET_FILTER); -#else - /* Fall back to legacy API */ - bpf_program__set_socket_filter(bpfprog); -#endif - } else { -#ifdef HAVE_BPF_PROGRAM__SET_TYPE - bpf_program__set_type(bpfprog, BPF_PROG_TYPE_XDP); -#else - /* Fall back to legacy API */ - bpf_program__set_xdp(bpfprog); -#endif - } - found = true; - break; - } - } - - if (found == false) { - SCLogError("No section '%s' in '%s' file. Will not be able to use the file", section, path); - return -1; - } - - err = bpf_object__load(bpfobj); - if (err < 0) { - if (err == -EPERM) { - SCLogError("Permission issue when loading eBPF object" - " (check libbpf error on stdout)"); - } else { - char buf[129]; - libbpf_strerror(err, buf, sizeof(buf)); - SCLogError("Unable to load eBPF object: %s (%d)", buf, err); - } - return -1; - } - - /* Kernel and userspace are sharing data via map. Userspace access to the - * map via a file descriptor. So we need to store the map to fd info. For - * that we use bpf_maps_info:: */ - struct bpf_maps_info *bpf_map_data = SCCalloc(1, sizeof(*bpf_map_data)); - if (bpf_map_data == NULL) { - SCLogError("Can't allocate bpf map array"); - return -1; - } - - /* Store the maps in bpf_maps_info:: */ - bpf_map__for_each(map, bpfobj) { - if (bpf_map_data->last == BPF_MAP_MAX_COUNT) { - SCLogError("Too many BPF maps in eBPF files"); - break; - } - SCLogDebug("Got a map '%s' with fd '%d'", bpf_map__name(map), bpf_map__fd(map)); - bpf_map_data->array[bpf_map_data->last].fd = bpf_map__fd(map); - bpf_map_data->array[bpf_map_data->last].name = SCStrdup(bpf_map__name(map)); - snprintf(bpf_map_data->array[bpf_map_data->last].iface, IFNAMSIZ, - "%s", iface); - if (!bpf_map_data->array[bpf_map_data->last].name) { - SCLogError("Unable to duplicate map name"); - BpfMapsInfoFree(bpf_map_data); - return -1; - } - bpf_map_data->array[bpf_map_data->last].to_unlink = 0; - if (config->flags & EBPF_PINNED_MAPS) { - SCLogConfig("Pinning: %d to %s", bpf_map_data->array[bpf_map_data->last].fd, - bpf_map_data->array[bpf_map_data->last].name); - char buf[1024]; - snprintf(buf, sizeof(buf), "/sys/fs/bpf/suricata-%s-%s", iface, - bpf_map_data->array[bpf_map_data->last].name); - int ret = bpf_obj_pin(bpf_map_data->array[bpf_map_data->last].fd, buf); - if (ret != 0) { - SCLogWarning("Can not pin: %s", strerror(errno)); - } - /* Don't unlink pinned maps in XDP mode to avoid a state reset */ - if (config->flags & EBPF_XDP_CODE) { - bpf_map_data->array[bpf_map_data->last].to_unlink = 0; - } else { - bpf_map_data->array[bpf_map_data->last].to_unlink = 1; - } - } - bpf_map_data->last++; - } - - /* Attach the bpf_maps_info to the LiveDevice via the device storage */ - LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data); - LiveDevUseBypass(livedev); - - /* Finally we get the file descriptor for our eBPF program. We will use - * the fd to attach the program to the socket (eBPF case) or to the device - * (XDP case). */ - pfd = bpf_program__fd(bpfprog); - if (pfd == -1) { - SCLogError("Unable to find %s section", section); - return -1; - } - - SCLogInfo("Successfully loaded eBPF file '%s' on '%s'", path, iface); - *val = pfd; - return 0; -} - -/** - * Attach a XDP program identified by its file descriptor to a device - * - * \param iface the name of interface - * \param fd the eBPF/XDP program file descriptor - * \param a flag to pass to attach function mostly used to set XDP mode - * \return -1 in case of error, 0 if success - */ -int EBPFSetupXDP(const char *iface, int fd, uint8_t flags) -{ -#ifdef HAVE_PACKET_XDP - unsigned int ifindex = if_nametoindex(iface); - if (ifindex == 0) { - SCLogError("Unknown interface '%s'", iface); - return -1; - } -#ifdef HAVE_BPF_XDP_ATTACH - int err = bpf_xdp_attach(ifindex, fd, flags, NULL); -#else - /* Fall back to legacy API */ - int err = bpf_set_link_xdp_fd(ifindex, fd, flags); -#endif - if (err != 0) { - char buf[129]; - libbpf_strerror(err, buf, sizeof(buf)); - SCLogError("Unable to set XDP on '%s': %s (%d)", iface, buf, err); - return -1; - } -#endif - return 0; -} - -/** - * Create a Flow in the table for a Flowkey - * - * \return false (this create function never returns true) - */ -static bool EBPFCreateFlowForKey(struct flows_stats *flowstats, LiveDevice *dev, void *key, - size_t skey, FlowKey *flow_key, struct timespec *ctime, - uint64_t pkts_cnt, uint64_t bytes_cnt, - int mapfd, int cpus_count) -{ - Flow *f = NULL; - uint32_t hash = FlowKeyGetHash(flow_key); - - f = FlowGetFromFlowKey(flow_key, ctime, hash); - if (f == NULL) - return false; - - /* set accounting, we can't know the direction, so let's just start to - * serve them if we already have something from server to client. We need - * these numbers as we will use it to see if we have new traffic coming - * on the flow */ - FlowBypassInfo *fc = FlowGetStorageById(f, GetFlowBypassInfoID()); - if (fc == NULL) { - fc = SCCalloc(sizeof(FlowBypassInfo), 1); - if (fc) { - FlowUpdateState(f, FLOW_STATE_CAPTURE_BYPASSED); - FlowSetStorageById(f, GetFlowBypassInfoID(), fc); - fc->BypassUpdate = EBPFBypassUpdate; - fc->BypassFree = EBPFBypassFree; - fc->todstpktcnt = pkts_cnt; - fc->todstbytecnt = bytes_cnt; - f->livedev = dev; - EBPFBypassData *eb = SCCalloc(1, sizeof(EBPFBypassData)); - if (eb == NULL) { - SCFree(fc); - FLOWLOCK_UNLOCK(f); - return false; - } - void *mkey = SCCalloc(1, skey); - if (mkey == NULL) { - SCFree(fc); - SCFree(eb); - FLOWLOCK_UNLOCK(f); - return false; - } - memcpy(mkey, key, skey); - eb->key[0] = mkey; - eb->mapfd = mapfd; - eb->cpus_count = cpus_count; - fc->bypass_data = eb; - flowstats->count++; - } else { - FLOWLOCK_UNLOCK(f); - return false; - } - } else { - EBPFBypassData *eb = (EBPFBypassData *) fc->bypass_data; - if (eb == NULL) { - FLOWLOCK_UNLOCK(f); - return false; - } - /* if both keys are here, then it is a flow bypassed by this - * instance so we ignore it */ - if (eb->key[0] && eb->key[1]) { - FLOWLOCK_UNLOCK(f); - return false; - } - fc->tosrcpktcnt = pkts_cnt; - fc->tosrcbytecnt = bytes_cnt; - void *mkey = SCCalloc(1, skey); - if (mkey == NULL) { - FLOWLOCK_UNLOCK(f); - return false; - } - memcpy(mkey, key, skey); - eb->key[1] = mkey; - } - f->livedev = dev; - FLOWLOCK_UNLOCK(f); - return false; -} - -void EBPFBypassFree(void *data) -{ - EBPFBypassData *eb = (EBPFBypassData *)data; - if (eb == NULL) - return; - SCFree(eb->key[0]); - if (eb->key[1]) { - SCFree(eb->key[1]); - } - SCFree(eb); - return; -} - -/** - * - * Compare eBPF half flow to Flow - * - * \return true if entries have activity, false if not - */ - -static bool EBPFBypassCheckHalfFlow(Flow *f, FlowBypassInfo *fc, - EBPFBypassData *eb, void *key, - int index) -{ - int i; - uint64_t pkts_cnt = 0; - uint64_t bytes_cnt = 0; - /* We use a per CPU structure so we will get a array of values. But if nr_cpus - * is 1 then we have a global hash. */ - BPF_DECLARE_PERCPU(struct pair, values_array, eb->cpus_count); - memset(values_array, 0, sizeof(values_array)); - int res = bpf_map_lookup_elem(eb->mapfd, key, values_array); - if (res < 0) { - SCLogDebug("errno: (%d) %s", errno, strerror(errno)); - return false; - } - for (i = 0; i < eb->cpus_count; i++) { - /* let's start accumulating value so we can compute the counters */ - SCLogDebug("%d: Adding pkts %lu bytes %lu", i, - BPF_PERCPU(values_array, i).packets, - BPF_PERCPU(values_array, i).bytes); - pkts_cnt += BPF_PERCPU(values_array, i).packets; - bytes_cnt += BPF_PERCPU(values_array, i).bytes; - } - if (index == 0) { - if (pkts_cnt != fc->todstpktcnt) { - fc->todstpktcnt = pkts_cnt; - fc->todstbytecnt = bytes_cnt; - return true; - } - } else { - if (pkts_cnt != fc->tosrcpktcnt) { - fc->tosrcpktcnt = pkts_cnt; - fc->tosrcbytecnt = bytes_cnt; - return true; - } - } - - return false; -} - -/** Check both half flows for update - * - * Update lastts in the flow and do accounting - * - * */ -bool EBPFBypassUpdate(Flow *f, void *data, time_t tsec) -{ - EBPFBypassData *eb = (EBPFBypassData *)data; - if (eb == NULL) { - return false; - } - FlowBypassInfo *fc = FlowGetStorageById(f, GetFlowBypassInfoID()); - if (fc == NULL) { - return false; - } - bool activity = EBPFBypassCheckHalfFlow(f, fc, eb, eb->key[0], 0); - activity |= EBPFBypassCheckHalfFlow(f, fc, eb, eb->key[1], 1); - if (!activity) { - SCLogDebug("Delete entry: %u (%ld)", FLOW_IS_IPV6(f), FlowGetId(f)); - /* delete the entries if no time update */ - EBPFDeleteKey(eb->mapfd, eb->key[0]); - EBPFDeleteKey(eb->mapfd, eb->key[1]); - SCLogDebug("Done delete entry: %u", FLOW_IS_IPV6(f)); - } else { - f->lastts = SCTIME_FROM_SECS(tsec); - return true; - } - return false; -} - -typedef bool (*OpFlowForKey)(struct flows_stats * flowstats, LiveDevice*dev, void *key, - size_t skey, FlowKey *flow_key, struct timespec *ctime, - uint64_t pkts_cnt, uint64_t bytes_cnt, - int mapfd, int cpus_count); - -/** - * Bypassed flows iterator for IPv4 - * - * This function iterates on all the flows of the IPv4 table - * running a callback function on each flow. - */ -static int EBPFForEachFlowV4Table(ThreadVars *th_v, LiveDevice *dev, const char *name, - struct timespec *ctime, - struct ebpf_timeout_config *tcfg, - OpFlowForKey EBPFOpFlowForKey - ) -{ - struct flows_stats flowstats = { 0, 0, 0}; - int mapfd = EBPFGetMapFDByName(dev->dev, name); - if (mapfd == -1) - return -1; - - struct flowv4_keys key = {}, next_key; - int found = 0; - unsigned int i; - uint64_t hash_cnt = 0; - - if (tcfg->cpus_count == 0) { - return 0; - } - - bool dead_flow = false; - while (bpf_map_get_next_key(mapfd, &key, &next_key) == 0) { - uint64_t bytes_cnt = 0; - uint64_t pkts_cnt = 0; - hash_cnt++; - if (dead_flow) { - EBPFDeleteKey(mapfd, &key); - dead_flow = false; - } - /* We use a per CPU structure so we will get a array of values. But if nr_cpus - * is 1 then we have a global hash. */ - BPF_DECLARE_PERCPU(struct pair, values_array, tcfg->cpus_count); - memset(values_array, 0, sizeof(values_array)); - int res = bpf_map_lookup_elem(mapfd, &next_key, values_array); - if (res < 0) { - SCLogDebug("no entry in v4 table for %d -> %d", key.port16[0], key.port16[1]); - SCLogDebug("errno: (%d) %s", errno, strerror(errno)); - key = next_key; - continue; - } - for (i = 0; i < tcfg->cpus_count; i++) { - /* let's start accumulating value so we can compute the counters */ - SCLogDebug("%d: Adding pkts %lu bytes %lu", i, - BPF_PERCPU(values_array, i).packets, - BPF_PERCPU(values_array, i).bytes); - pkts_cnt += BPF_PERCPU(values_array, i).packets; - bytes_cnt += BPF_PERCPU(values_array, i).bytes; - } - /* Get the corresponding Flow in the Flow table to compare and update - * its counters and lastseen if needed */ - FlowKey flow_key; - if (tcfg->mode == AFP_MODE_XDP_BYPASS) { - flow_key.sp = ntohs(next_key.port16[0]); - flow_key.dp = ntohs(next_key.port16[1]); - flow_key.src.addr_data32[0] = next_key.src; - flow_key.dst.addr_data32[0] = next_key.dst; - } else { - flow_key.sp = next_key.port16[0]; - flow_key.dp = next_key.port16[1]; - flow_key.src.addr_data32[0] = ntohl(next_key.src); - flow_key.dst.addr_data32[0] = ntohl(next_key.dst); - } - flow_key.src.family = AF_INET; - flow_key.src.addr_data32[1] = 0; - flow_key.src.addr_data32[2] = 0; - flow_key.src.addr_data32[3] = 0; - flow_key.dst.family = AF_INET; - flow_key.dst.addr_data32[1] = 0; - flow_key.dst.addr_data32[2] = 0; - flow_key.dst.addr_data32[3] = 0; - flow_key.vlan_id[0] = next_key.vlan0; - flow_key.vlan_id[1] = next_key.vlan1; - flow_key.vlan_id[2] = next_key.vlan2; - if (next_key.ip_proto == 1) { - flow_key.proto = IPPROTO_TCP; - } else { - flow_key.proto = IPPROTO_UDP; - } - flow_key.recursion_level = 0; - flow_key.livedev_id = dev->id; - dead_flow = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key, - ctime, pkts_cnt, bytes_cnt, - mapfd, tcfg->cpus_count); - if (dead_flow) { - found = 1; - } - - if (TmThreadsCheckFlag(th_v, THV_KILL)) { - return 0; - } - - key = next_key; - } - if (dead_flow) { - EBPFDeleteKey(mapfd, &key); - found = 1; - } - SC_ATOMIC_ADD(dev->bypassed, flowstats.packets); - - LiveDevAddBypassStats(dev, flowstats.count, AF_INET); - SCLogInfo("IPv4 bypassed flow table size: %" PRIu64, hash_cnt); - - return found; -} - -/** - * Bypassed flows iterator for IPv6 - * - * This function iterates on all the flows of the IPv4 table - * running a callback function on each flow. - */ -static int EBPFForEachFlowV6Table(ThreadVars *th_v, - LiveDevice *dev, const char *name, - struct timespec *ctime, - struct ebpf_timeout_config *tcfg, - OpFlowForKey EBPFOpFlowForKey - ) -{ - struct flows_stats flowstats = { 0, 0, 0}; - int mapfd = EBPFGetMapFDByName(dev->dev, name); - if (mapfd == -1) - return -1; - - struct flowv6_keys key = {}, next_key; - int found = 0; - unsigned int i; - uint64_t hash_cnt = 0; - - if (tcfg->cpus_count == 0) { - SCLogWarning("CPU count should not be 0"); - return 0; - } - - uint64_t pkts_cnt = 0; - while (bpf_map_get_next_key(mapfd, &key, &next_key) == 0) { - uint64_t bytes_cnt = 0; - hash_cnt++; - if (pkts_cnt > 0) { - EBPFDeleteKey(mapfd, &key); - } - pkts_cnt = 0; - /* We use a per CPU structure so we will get a array of values. But if nr_cpus - * is 1 then we have a global hash. */ - BPF_DECLARE_PERCPU(struct pair, values_array, tcfg->cpus_count); - memset(values_array, 0, sizeof(values_array)); - int res = bpf_map_lookup_elem(mapfd, &next_key, values_array); - if (res < 0) { - SCLogDebug("no entry in v4 table for %d -> %d", key.port16[0], key.port16[1]); - key = next_key; - continue; - } - for (i = 0; i < tcfg->cpus_count; i++) { - /* let's start accumulating value so we can compute the counters */ - SCLogDebug("%d: Adding pkts %lu bytes %lu", i, - BPF_PERCPU(values_array, i).packets, - BPF_PERCPU(values_array, i).bytes); - pkts_cnt += BPF_PERCPU(values_array, i).packets; - bytes_cnt += BPF_PERCPU(values_array, i).bytes; - } - /* Get the corresponding Flow in the Flow table to compare and update - * its counters and lastseen if needed */ - FlowKey flow_key; - if (tcfg->mode == AFP_MODE_XDP_BYPASS) { - flow_key.sp = ntohs(next_key.port16[0]); - flow_key.dp = ntohs(next_key.port16[1]); - flow_key.src.family = AF_INET6; - flow_key.src.addr_data32[0] = next_key.src[0]; - flow_key.src.addr_data32[1] = next_key.src[1]; - flow_key.src.addr_data32[2] = next_key.src[2]; - flow_key.src.addr_data32[3] = next_key.src[3]; - flow_key.dst.family = AF_INET6; - flow_key.dst.addr_data32[0] = next_key.dst[0]; - flow_key.dst.addr_data32[1] = next_key.dst[1]; - flow_key.dst.addr_data32[2] = next_key.dst[2]; - flow_key.dst.addr_data32[3] = next_key.dst[3]; - } else { - flow_key.sp = next_key.port16[0]; - flow_key.dp = next_key.port16[1]; - flow_key.src.family = AF_INET6; - flow_key.src.addr_data32[0] = ntohl(next_key.src[0]); - flow_key.src.addr_data32[1] = ntohl(next_key.src[1]); - flow_key.src.addr_data32[2] = ntohl(next_key.src[2]); - flow_key.src.addr_data32[3] = ntohl(next_key.src[3]); - flow_key.dst.family = AF_INET6; - flow_key.dst.addr_data32[0] = ntohl(next_key.dst[0]); - flow_key.dst.addr_data32[1] = ntohl(next_key.dst[1]); - flow_key.dst.addr_data32[2] = ntohl(next_key.dst[2]); - flow_key.dst.addr_data32[3] = ntohl(next_key.dst[3]); - } - flow_key.vlan_id[0] = next_key.vlan0; - flow_key.vlan_id[1] = next_key.vlan1; - flow_key.vlan_id[2] = next_key.vlan2; - if (next_key.ip_proto == 1) { - flow_key.proto = IPPROTO_TCP; - } else { - flow_key.proto = IPPROTO_UDP; - } - flow_key.recursion_level = 0; - flow_key.livedev_id = dev->id; - pkts_cnt = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key, - ctime, pkts_cnt, bytes_cnt, - mapfd, tcfg->cpus_count); - if (pkts_cnt > 0) { - found = 1; - } - - if (TmThreadsCheckFlag(th_v, THV_KILL)) { - return 0; - } - - key = next_key; - } - if (pkts_cnt > 0) { - EBPFDeleteKey(mapfd, &key); - found = 1; - } - SC_ATOMIC_ADD(dev->bypassed, flowstats.packets); - - LiveDevAddBypassStats(dev, flowstats.count, AF_INET6); - SCLogInfo("IPv6 bypassed flow table size: %" PRIu64, hash_cnt); - return found; -} - - -int EBPFCheckBypassedFlowCreate(ThreadVars *th_v, struct timespec *curtime, void *data) -{ - LiveDevice *ldev = NULL, *ndev; - struct ebpf_timeout_config *cfg = (struct ebpf_timeout_config *)data; - while(LiveDeviceForEach(&ldev, &ndev)) { - EBPFForEachFlowV4Table(th_v, ldev, "flow_table_v4", - curtime, - cfg, EBPFCreateFlowForKey); - EBPFForEachFlowV6Table(th_v, ldev, "flow_table_v6", - curtime, - cfg, EBPFCreateFlowForKey); - } - - return 0; -} - -void EBPFRegisterExtension(void) -{ - g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree); - g_flow_storage_id = FlowStorageRegister("bypassedlist", sizeof(void *), NULL, BypassedListFree); -} - - -#ifdef HAVE_PACKET_XDP - -static uint32_t g_redirect_iface_cpu_counter = 0; - -static int EBPFAddCPUToMap(const char *iface, uint32_t i) -{ - int cpumap = EBPFGetMapFDByName(iface, "cpu_map"); - uint32_t queue_size = 4096; - int ret; - - if (cpumap < 0) { - SCLogError("Can't find cpu_map"); - return -1; - } - ret = bpf_map_update_elem(cpumap, &i, &queue_size, 0); - if (ret) { - SCLogError("Create CPU entry failed (err:%d)", ret); - return -1; - } - int cpus_available = EBPFGetMapFDByName(iface, "cpus_available"); - if (cpus_available < 0) { - SCLogError("Can't find cpus_available map"); - return -1; - } - - ret = bpf_map_update_elem(cpus_available, &g_redirect_iface_cpu_counter, &i, 0); - if (ret) { - SCLogError("Create CPU entry failed (err:%d)", ret); - return -1; - } - return 0; -} - -static void EBPFRedirectMapAddCPU(int i, void *data) -{ - if (EBPFAddCPUToMap(data, i) < 0) { - SCLogError("Unable to add CPU %d to set", i); - } else { - g_redirect_iface_cpu_counter++; - } -} - -void EBPFBuildCPUSet(ConfNode *node, char *iface) -{ - uint32_t key0 = 0; - int mapfd = EBPFGetMapFDByName(iface, "cpus_count"); - if (mapfd < 0) { - SCLogError("Unable to find 'cpus_count' map"); - return; - } - g_redirect_iface_cpu_counter = 0; - if (node == NULL) { - bpf_map_update_elem(mapfd, &key0, &g_redirect_iface_cpu_counter, - BPF_ANY); - return; - } - BuildCpusetWithCallback("xdp-cpu-redirect", node, - EBPFRedirectMapAddCPU, - iface); - bpf_map_update_elem(mapfd, &key0, &g_redirect_iface_cpu_counter, - BPF_ANY); -} - -/** - * Setup peer interface in XDP system - * - * Ths function set up the peer interface in the XDP maps used by the - * bypass filter. The first map tx_peer has type device map and is - * used to store the peer. The second map tx_peer_int is used by the - * code to check if we have a peer defined for this interface. - * - * As the map are per device we just need maps with one single element. - * In both case, we use the key 0 to enter element so XDP kernel code - * is using the same key. - */ -int EBPFSetPeerIface(const char *iface, const char *out_iface) -{ - int mapfd = EBPFGetMapFDByName(iface, "tx_peer"); - if (mapfd < 0) { - SCLogError("Unable to find 'tx_peer' map"); - return -1; - } - int intmapfd = EBPFGetMapFDByName(iface, "tx_peer_int"); - if (intmapfd < 0) { - SCLogError("Unable to find 'tx_peer_int' map"); - return -1; - } - - int key0 = 0; - unsigned int peer_index = if_nametoindex(out_iface); - if (peer_index == 0) { - SCLogError("No iface '%s'", out_iface); - return -1; - } - int ret = bpf_map_update_elem(mapfd, &key0, &peer_index, BPF_ANY); - if (ret) { - SCLogError("Create peer entry failed (err:%d)", ret); - return -1; - } - ret = bpf_map_update_elem(intmapfd, &key0, &peer_index, BPF_ANY); - if (ret) { - SCLogError("Create peer entry failed (err:%d)", ret); - return -1; - } - return 0; -} - -/** - * Bypass the flow on all ifaces it is seen on. This is used - * in IPS mode. - */ - -int EBPFUpdateFlow(Flow *f, Packet *p, void *data) -{ - BypassedIfaceList *ifl = (BypassedIfaceList *)FlowGetStorageById(f, g_flow_storage_id); - if (ifl == NULL) { - ifl = SCCalloc(1, sizeof(*ifl)); - if (ifl == NULL) { - return 0; - } - ifl->dev = p->livedev; - FlowSetStorageById(f, g_flow_storage_id, ifl); - return 1; - } - /* Look for packet iface in the list */ - BypassedIfaceList *ldev = ifl; - while (ldev) { - if (p->livedev == ldev->dev) { - return 1; - } - ldev = ldev->next; - } - /* Call bypass function if ever not in the list */ - p->BypassPacketsFlow(p); - - /* Add iface to the list */ - BypassedIfaceList *nifl = SCCalloc(1, sizeof(*nifl)); - if (nifl == NULL) { - return 0; - } - nifl->dev = p->livedev; - nifl->next = ifl; - FlowSetStorageById(f, g_flow_storage_id, nifl); - return 1; -} - -#endif /* HAVE_PACKET_XDP */ - -#endif diff --git a/src/util-ebpf.h b/src/util-ebpf.h deleted file mode 100644 index bf1768a69da7..000000000000 --- a/src/util-ebpf.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2018 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - */ - -#ifndef __UTIL_EBPF_H__ -#define __UTIL_EBPF_H__ - -#include "flow-bypass.h" - -#ifdef HAVE_PACKET_EBPF - -#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0) -#define XDP_FLAGS_SKB_MODE (1U << 1) -#define XDP_FLAGS_DRV_MODE (1U << 2) -#define XDP_FLAGS_HW_MODE (1U << 3) - - -struct flowv4_keys { - __be32 src; - __be32 dst; - union { - __be32 ports; - __be16 port16[2]; - }; - __u8 ip_proto:1; - __u16 vlan0:15; - __u16 vlan1; - __u16 vlan2; -}; - -struct flowv6_keys { - __be32 src[4]; - __be32 dst[4]; - union { - __be32 ports; - __be16 port16[2]; - }; - __u8 ip_proto:1; - __u16 vlan0:15; - __u16 vlan1; - __u16 vlan2; -}; - -struct pair { - uint64_t packets; - uint64_t bytes; -}; - -typedef struct EBPFBypassData_ { - void *key[2]; - int mapfd; - int cpus_count; -} EBPFBypassData; - -#define EBPF_SOCKET_FILTER (1<<0) -#define EBPF_XDP_CODE (1<<1) -#define EBPF_PINNED_MAPS (1<<2) -#define EBPF_XDP_HW_MODE (1<<3) - -int EBPFGetMapFDByName(const char *iface, const char *name); -int EBPFLoadFile(const char *iface, const char *path, const char * section, - int *val, struct ebpf_timeout_config *config); -int EBPFSetupXDP(const char *iface, int fd, uint8_t flags); - -int EBPFCheckBypassedFlowCreate(ThreadVars *th_v, struct timespec *curtime, void *data); - -void EBPFRegisterExtension(void); - -void EBPFBuildCPUSet(ConfNode *node, char *iface); - -int EBPFSetPeerIface(const char *iface, const char *out_iface); - -int EBPFUpdateFlow(Flow *f, Packet *p, void *data); -bool EBPFBypassUpdate(Flow *f, void *data, time_t tsec); -void EBPFBypassFree(void *data); - -void EBPFDeleteKey(int fd, void *key); - -#define __bpf_percpu_val_align __attribute__((__aligned__(8))) - -#define BPF_DECLARE_PERCPU(type, name, nr_cpus) \ - struct { type v; /* padding */ } __bpf_percpu_val_align \ - name[nr_cpus] -#define BPF_PERCPU(name, cpu) name[(cpu)].v - - -#endif - -#endif diff --git a/src/util-enum.c b/src/util-enum.c deleted file mode 100644 index f63140afa006..000000000000 --- a/src/util-enum.c +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" - -#include "util-enum.h" -#include "util-debug.h" - -/** - * \brief Maps a string name to an enum value from the supplied table. Please - * specify the last element of any map table with a {NULL, -1}. If - * missing, you will be welcomed with a segfault :) - * - * \param enum_name Character string that has to be mapped to an enum value - * from the table - * \param table Enum-Char table, from which the mapping is retrieved - * - * \retval result The enum_value for the enum_name string or -1 on failure - */ -int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table) -{ - int result = -1; - - if (enum_name == NULL || table == NULL) { - SCLogDebug("Invalid argument(s) passed into SCMapEnumNameToValue"); - return -1; - } - - for (; table->enum_name != NULL; table++) { - if (strcasecmp(table->enum_name, enum_name) == 0) { - result = table->enum_value; - break; - } - } - - return result; -} - -/** - * \brief Maps an enum value to a string name, from the supplied table - * - * \param enum_value Enum_value that has to be mapped to a string_value - * from the table - * \param table Enum-Char table, from which the mapping is retrieved - * - * \retval result The enum_name for the enum_value supplied or NULL on failure - */ -const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table) -{ - if (table == NULL) { - SCLogDebug("Invalid argument(s) passed into SCMapEnumValueToName"); - return NULL; - } - - for (; table->enum_name != NULL; table++) { - if (table->enum_value == enum_value) { - return table->enum_name; - } - } - - SCLogDebug("A enum by the value %d doesn't exist in this table", enum_value); - - return NULL; -} diff --git a/src/util-enum.h b/src/util-enum.h deleted file mode 100644 index ea88fc4b4460..000000000000 --- a/src/util-enum.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_ENUM_H__ -#define __UTIL_ENUM_H__ - -typedef struct SCEnumCharMap_ { - const char *enum_name; - int enum_value; -} SCEnumCharMap; - -int SCMapEnumNameToValue(const char *, SCEnumCharMap *); - -const char * SCMapEnumValueToName(int, SCEnumCharMap *); - -#endif /* __UTIL_ENUM_H__ */ diff --git a/src/util-error.c b/src/util-error.c deleted file mode 100644 index 01c2f9a01b73..000000000000 --- a/src/util-error.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Error utility functions - * - * \todo Needs refining of the error codes. Renaming with a prefix of SC_ERR, - * removal of duplicates and entries have to be made in util-error.c - */ - -#include "util-error.h" - -thread_local SCError sc_errno = SC_OK; -#define CASE_CODE(E) case E: return #E - -/** - * \brief Maps the error code, to its string equivalent - * - * \param The error code - * - * \retval The string equivalent for the error code - */ -const char * SCErrorToString(SCError err) -{ - switch (err) { - CASE_CODE (SC_OK); - - CASE_CODE(SC_ENOMEM); - CASE_CODE(SC_EINVAL); - CASE_CODE(SC_ELIMIT); - CASE_CODE(SC_EEXIST); - - CASE_CODE (SC_ERR_MAX); - } - - return "UNKNOWN_ERROR"; -} diff --git a/src/util-exception-policy.c b/src/util-exception-policy.c deleted file mode 100644 index 6c8ba0fba975..000000000000 --- a/src/util-exception-policy.c +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright (C) 2022-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "packet.h" -#include "util-exception-policy.h" -#include "util-misc.h" -#include "stream-tcp-reassemble.h" -#include "action-globals.h" - -enum ExceptionPolicy g_eps_master_switch = EXCEPTION_POLICY_NOT_SET; -/** true if exception policy was defined in config */ -static bool g_eps_have_exception_policy = false; - -static const char *ExceptionPolicyEnumToString(enum ExceptionPolicy policy) -{ - switch (policy) { - case EXCEPTION_POLICY_NOT_SET: - return "ignore"; - case EXCEPTION_POLICY_AUTO: - return "auto"; - case EXCEPTION_POLICY_REJECT: - return "reject"; - case EXCEPTION_POLICY_BYPASS_FLOW: - return "bypass"; - case EXCEPTION_POLICY_DROP_FLOW: - return "drop-flow"; - case EXCEPTION_POLICY_DROP_PACKET: - return "drop-packet"; - case EXCEPTION_POLICY_PASS_PACKET: - return "pass-packet"; - case EXCEPTION_POLICY_PASS_FLOW: - return "pass-flow"; - } - // TODO we shouldn't reach this, but if we do, better not to leave this as simply null... - return "not set"; -} - -void SetMasterExceptionPolicy(void) -{ - g_eps_master_switch = ExceptionPolicyParse("exception-policy", true); -} - -static enum ExceptionPolicy GetMasterExceptionPolicy(const char *option) -{ - return g_eps_master_switch; -} - -void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason) -{ - SCLogDebug("start: pcap_cnt %" PRIu64 ", policy %u", p->pcap_cnt, policy); - switch (policy) { - case EXCEPTION_POLICY_AUTO: - break; - case EXCEPTION_POLICY_NOT_SET: - break; - case EXCEPTION_POLICY_REJECT: - SCLogDebug("EXCEPTION_POLICY_REJECT"); - PacketDrop(p, ACTION_REJECT, drop_reason); - if (!EngineModeIsIPS()) { - break; - } - /* fall through */ - case EXCEPTION_POLICY_DROP_FLOW: - SCLogDebug("EXCEPTION_POLICY_DROP_FLOW"); - if (p->flow) { - p->flow->flags |= FLOW_ACTION_DROP; - FlowSetNoPayloadInspectionFlag(p->flow); - FlowSetNoPacketInspectionFlag(p->flow); - StreamTcpDisableAppLayer(p->flow); - } - /* fall through */ - case EXCEPTION_POLICY_DROP_PACKET: - SCLogDebug("EXCEPTION_POLICY_DROP_PACKET"); - DecodeSetNoPayloadInspectionFlag(p); - DecodeSetNoPacketInspectionFlag(p); - PacketDrop(p, ACTION_DROP, drop_reason); - break; - case EXCEPTION_POLICY_BYPASS_FLOW: - PacketBypassCallback(p); - /* fall through */ - case EXCEPTION_POLICY_PASS_FLOW: - SCLogDebug("EXCEPTION_POLICY_PASS_FLOW"); - if (p->flow) { - p->flow->flags |= FLOW_ACTION_PASS; - FlowSetNoPacketInspectionFlag(p->flow); // TODO util func - } - /* fall through */ - case EXCEPTION_POLICY_PASS_PACKET: - SCLogDebug("EXCEPTION_POLICY_PASS_PACKET"); - DecodeSetNoPayloadInspectionFlag(p); - DecodeSetNoPacketInspectionFlag(p); - break; - } - SCLogDebug("end"); -} - -static enum ExceptionPolicy PickPacketAction(const char *option, enum ExceptionPolicy p) -{ - switch (p) { - case EXCEPTION_POLICY_DROP_FLOW: - SCLogWarning( - "flow actions not supported for %s, defaulting to \"drop-packet\"", option); - return EXCEPTION_POLICY_DROP_PACKET; - case EXCEPTION_POLICY_PASS_FLOW: - SCLogWarning( - "flow actions not supported for %s, defaulting to \"pass-packet\"", option); - return EXCEPTION_POLICY_PASS_PACKET; - case EXCEPTION_POLICY_BYPASS_FLOW: - SCLogWarning("flow actions not supported for %s, defaulting to \"ignore\"", option); - return EXCEPTION_POLICY_NOT_SET; - /* add all cases, to make sure new cases not handle will raise - * errors */ - case EXCEPTION_POLICY_DROP_PACKET: - break; - case EXCEPTION_POLICY_PASS_PACKET: - break; - case EXCEPTION_POLICY_REJECT: - break; - case EXCEPTION_POLICY_NOT_SET: - break; - case EXCEPTION_POLICY_AUTO: - break; - } - return p; -} - -static enum ExceptionPolicy ExceptionPolicyConfigValueParse( - const char *option, const char *value_str) -{ - enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; - if (strcmp(value_str, "drop-flow") == 0) { - policy = EXCEPTION_POLICY_DROP_FLOW; - } else if (strcmp(value_str, "pass-flow") == 0) { - policy = EXCEPTION_POLICY_PASS_FLOW; - } else if (strcmp(value_str, "bypass") == 0) { - policy = EXCEPTION_POLICY_BYPASS_FLOW; - } else if (strcmp(value_str, "drop-packet") == 0) { - policy = EXCEPTION_POLICY_DROP_PACKET; - } else if (strcmp(value_str, "pass-packet") == 0) { - policy = EXCEPTION_POLICY_PASS_PACKET; - } else if (strcmp(value_str, "reject") == 0) { - policy = EXCEPTION_POLICY_REJECT; - } else if (strcmp(value_str, "ignore") == 0) { // TODO name? - policy = EXCEPTION_POLICY_NOT_SET; - } else if (strcmp(value_str, "auto") == 0) { - policy = EXCEPTION_POLICY_AUTO; - } else { - FatalErrorOnInit( - "\"%s\" is not a valid exception policy value. Valid options are drop-flow, " - "pass-flow, bypass, reject, drop-packet, pass-packet, ignore or auto.", - value_str); - } - - return policy; -} - -/* Select an exception policy in case the configuration value was set to 'auto' */ -static enum ExceptionPolicy ExceptionPolicyPickAuto(bool midstream_enabled, bool support_flow) -{ - enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; - if (!midstream_enabled && EngineModeIsIPS()) { - if (support_flow) { - policy = EXCEPTION_POLICY_DROP_FLOW; - } else { - policy = EXCEPTION_POLICY_DROP_PACKET; - } - } - return policy; -} - -static enum ExceptionPolicy ExceptionPolicyMasterParse(const char *value) -{ - enum ExceptionPolicy policy = ExceptionPolicyConfigValueParse("exception-policy", value); - if (!EngineModeIsIPS() && - (policy == EXCEPTION_POLICY_DROP_PACKET || policy == EXCEPTION_POLICY_DROP_FLOW)) { - policy = EXCEPTION_POLICY_NOT_SET; - } - g_eps_have_exception_policy = true; - - SCLogInfo("master exception-policy set to: %s", ExceptionPolicyEnumToString(policy)); - - return policy; -} - -static enum ExceptionPolicy ExceptionPolicyGetDefault( - const char *option, bool support_flow, bool midstream) -{ - enum ExceptionPolicy p = EXCEPTION_POLICY_NOT_SET; - if (g_eps_have_exception_policy) { - p = GetMasterExceptionPolicy(option); - - if (p == EXCEPTION_POLICY_AUTO) { - p = ExceptionPolicyPickAuto(midstream, support_flow); - } - - if (!support_flow) { - p = PickPacketAction(option, p); - } - SCLogConfig("%s: %s (defined via 'exception-policy' master switch)", option, - ExceptionPolicyEnumToString(p)); - return p; - } else if (EngineModeIsIPS() && !midstream) { - p = EXCEPTION_POLICY_DROP_FLOW; - } - SCLogConfig("%s: %s (defined via 'built-in default' for %s-mode)", option, - ExceptionPolicyEnumToString(p), EngineModeIsIPS() ? "IPS" : "IDS"); - - return p; -} - -enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow) -{ - enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; - const char *value_str = NULL; - - if ((ConfGet(option, &value_str) == 1) && value_str != NULL) { - if (strcmp(option, "exception-policy") == 0) { - policy = ExceptionPolicyMasterParse(value_str); - } else { - policy = ExceptionPolicyConfigValueParse(option, value_str); - if (policy == EXCEPTION_POLICY_AUTO) { - policy = ExceptionPolicyPickAuto(false, support_flow); - } - if (!support_flow) { - policy = PickPacketAction(option, policy); - } - SCLogConfig("%s: %s", option, ExceptionPolicyEnumToString(policy)); - } - } else { - policy = ExceptionPolicyGetDefault(option, support_flow, false); - } - - return policy; -} - -enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled) -{ - enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; - const char *value_str = NULL; - /* policy was set directly */ - if ((ConfGet("stream.midstream-policy", &value_str)) == 1 && value_str != NULL) { - policy = ExceptionPolicyConfigValueParse("midstream-policy", value_str); - if (policy == EXCEPTION_POLICY_AUTO) { - policy = ExceptionPolicyPickAuto(midstream_enabled, true); - } else if (midstream_enabled) { - if (policy != EXCEPTION_POLICY_NOT_SET && policy != EXCEPTION_POLICY_PASS_FLOW) { - FatalErrorOnInit( - "Error parsing stream.midstream-policy from config file. \"%s\" is " - "not a valid exception policy when midstream is enabled. Valid options " - "are pass-flow and ignore.", - value_str); - } - } - if (!EngineModeIsIPS()) { - if (policy == EXCEPTION_POLICY_DROP_FLOW) { - FatalErrorOnInit( - "Error parsing stream.midstream-policy from config file. \"%s\" is " - "not a valid exception policy in IDS mode. See our documentation for a " - "list of all possible values.", - value_str); - } - } - } else { - policy = ExceptionPolicyGetDefault("stream.midstream-policy", true, midstream_enabled); - } - - if (policy == EXCEPTION_POLICY_PASS_PACKET || policy == EXCEPTION_POLICY_DROP_PACKET) { - FatalErrorOnInit("Error parsing stream.midstream-policy from config file. \"%s\" is " - "not valid for this exception policy. See our documentation for a list of " - "all possible values.", - value_str); - } - - return policy; -} - -#ifndef DEBUG - -int ExceptionSimulationCommandLineParser(const char *name, const char *arg) -{ - return 0; -} - -#else - -/* exception policy simulation (eps) handling */ - -uint64_t g_eps_applayer_error_offset_ts = UINT64_MAX; -uint64_t g_eps_applayer_error_offset_tc = UINT64_MAX; -uint64_t g_eps_pcap_packet_loss = UINT64_MAX; -uint64_t g_eps_stream_ssn_memcap = UINT64_MAX; -uint64_t g_eps_stream_reassembly_memcap = UINT64_MAX; -uint64_t g_eps_flow_memcap = UINT64_MAX; -uint64_t g_eps_defrag_memcap = UINT64_MAX; -bool g_eps_is_alert_queue_fail_mode = false; - -/* 1: parsed, 0: not for us, -1: error */ -int ExceptionSimulationCommandLineParser(const char *name, const char *arg) -{ - if (strcmp(name, "simulate-applayer-error-at-offset-ts") == 0) { - BUG_ON(arg == NULL); - uint64_t offset = 0; - if (ParseSizeStringU64(arg, &offset) < 0) { - return -1; - } - g_eps_applayer_error_offset_ts = offset; - } else if (strcmp(name, "simulate-applayer-error-at-offset-tc") == 0) { - BUG_ON(arg == NULL); - uint64_t offset = 0; - if (ParseSizeStringU64(arg, &offset) < 0) { - return TM_ECODE_FAILED; - } - g_eps_applayer_error_offset_tc = offset; - } else if (strcmp(name, "simulate-packet-loss") == 0) { - BUG_ON(arg == NULL); - uint64_t pkt_num = 0; - if (ParseSizeStringU64(arg, &pkt_num) < 0) { - return TM_ECODE_FAILED; - } - g_eps_pcap_packet_loss = pkt_num; - } else if (strcmp(name, "simulate-packet-tcp-reassembly-memcap") == 0) { - BUG_ON(arg == NULL); - uint64_t pkt_num = 0; - if (ParseSizeStringU64(arg, &pkt_num) < 0) { - return TM_ECODE_FAILED; - } - g_eps_stream_reassembly_memcap = pkt_num; - } else if (strcmp(name, "simulate-packet-tcp-ssn-memcap") == 0) { - BUG_ON(arg == NULL); - uint64_t pkt_num = 0; - if (ParseSizeStringU64(arg, &pkt_num) < 0) { - return TM_ECODE_FAILED; - } - g_eps_stream_ssn_memcap = pkt_num; - } else if (strcmp(name, "simulate-packet-flow-memcap") == 0) { - BUG_ON(arg == NULL); - uint64_t pkt_num = 0; - if (ParseSizeStringU64(arg, &pkt_num) < 0) { - return TM_ECODE_FAILED; - } - g_eps_flow_memcap = pkt_num; - } else if (strcmp(name, "simulate-packet-defrag-memcap") == 0) { - BUG_ON(arg == NULL); - uint64_t pkt_num = 0; - if (ParseSizeStringU64(arg, &pkt_num) < 0) { - return TM_ECODE_FAILED; - } - g_eps_defrag_memcap = pkt_num; - } else if (strcmp(name, "simulate-alert-queue-realloc-failure") == 0) { - g_eps_is_alert_queue_fail_mode = true; - } else { - // not for us - return 0; - } - return 1; -} -#endif diff --git a/src/util-file-decompression.c b/src/util-file-decompression.c deleted file mode 100644 index dfafdc87f050..000000000000 --- a/src/util-file-decompression.c +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Giuseppe Longo - * - * \brief Decompress files transferred via HTTP corresponding to file_data - * keyword. - * - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "detect-engine.h" -#include "app-layer-htp.h" - -#include "util-file-decompression.h" -#include "util-file-swf-decompression.h" -#include "util-misc.h" -#include "util-print.h" - -#define SWF_ZLIB_MIN_VERSION 0x06 -#define SWF_LZMA_MIN_VERSION 0x0D - -int FileIsSwfFile(const uint8_t *buffer, uint32_t buffer_len) -{ - if (buffer_len >= 3 && buffer[1] == 'W' && buffer[2] == 'S') { - if (buffer[0] == 'F') - return FILE_SWF_NO_COMPRESSION; - else if (buffer[0] == 'C') - return FILE_SWF_ZLIB_COMPRESSION; - else if (buffer[0] == 'Z') - return FILE_SWF_LZMA_COMPRESSION; - else - return FILE_IS_NOT_SWF; - } - - return FILE_IS_NOT_SWF; -} - -/** - * \brief This function decompresses a buffer with zlib/lzma algorithm - * - * \param buffer compressed buffer - * \param buffer_len compressed buffer length - * \param decompressed_buffer buffer that store decompressed data - * \param decompressed_buffer_len decompressed data length - * \param swf_type decompression algorithm to use - * \param decompress_depth how much decompressed data we want to store - * \param compress_depth how much compressed data we want to decompress - * - * \retval 1 if decompression works - * \retval 0 an error occurred, and event set - */ -int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len, - DetectEngineThreadCtx *det_ctx, - InspectionBuffer *out_buffer, - int swf_type, - uint32_t decompress_depth, - uint32_t compress_depth) -{ - int r = 0; - - int compression_type = FileIsSwfFile(buffer, buffer_len); - if (compression_type == FILE_SWF_NO_COMPRESSION) { - return 0; - } - - uint32_t offset = 0; - if (compression_type == FILE_SWF_ZLIB_COMPRESSION) { - /* compressed data start from the 4th bytes */ - offset = 8; - } else if (compression_type == FILE_SWF_LZMA_COMPRESSION) { - /* compressed data start from the 17th bytes */ - offset = 17; - } - - if (buffer_len <= offset) { - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_LENGTH); - return 0; - } - - uint32_t compressed_data_len = 0; - if (compress_depth > 0 && compress_depth <= buffer_len - offset) { - compressed_data_len = compress_depth; - } else { - compressed_data_len = buffer_len - offset; - } - - /* get swf version */ - uint8_t swf_version = FileGetSwfVersion(buffer, buffer_len); - if (compression_type == FILE_SWF_ZLIB_COMPRESSION && - swf_version < SWF_ZLIB_MIN_VERSION) - { - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_VERSION); - return 0; - } - if (compression_type == FILE_SWF_LZMA_COMPRESSION && - swf_version < SWF_LZMA_MIN_VERSION) - { - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_VERSION); - return 0; - } - - /* get flash decompressed file length */ - uint32_t decompressed_swf_len = FileGetSwfDecompressedLen(buffer, buffer_len); - if (decompressed_swf_len == 0) { - decompressed_swf_len = MIN_SWF_LEN; - } - - /* if decompress_depth is 0, keep the flash file length */ - uint32_t decompressed_data_len = (decompress_depth == 0) ? decompressed_swf_len : decompress_depth; - decompressed_data_len += 8; - - /* make sure the inspection buffer has enough space */ - InspectionBufferCheckAndExpand(out_buffer, decompressed_data_len); - if (out_buffer->size < decompressed_data_len) { - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_NO_MEM); - return 0; - } - out_buffer->len = decompressed_data_len; - - /* - * FWS format - * | 4 bytes | 4 bytes | n bytes | - * | 'FWS' + version | script len | data | - */ - out_buffer->buf[0] = 'F'; - out_buffer->buf[1] = 'W'; - out_buffer->buf[2] = 'S'; - out_buffer->buf[3] = swf_version; - memcpy(out_buffer->buf + 4, &decompressed_swf_len, 4); - memset(out_buffer->buf + 8, 0, decompressed_data_len - 8); - - if ((swf_type == HTTP_SWF_COMPRESSION_ZLIB || swf_type == HTTP_SWF_COMPRESSION_BOTH) && - compression_type == FILE_SWF_ZLIB_COMPRESSION) - { - /* the first 8 bytes represents the fws header, see 'FWS format' above. - * data will start from 8th bytes - */ - r = FileSwfZlibDecompression(det_ctx, - (uint8_t *)buffer + offset, compressed_data_len, - out_buffer->buf + 8, out_buffer->len - 8); - if (r == 0) - goto error; - - } else if ((swf_type == HTTP_SWF_COMPRESSION_LZMA || swf_type == HTTP_SWF_COMPRESSION_BOTH) && - compression_type == FILE_SWF_LZMA_COMPRESSION) - { - /* we need to setup the lzma header */ - /* - * | 5 bytes | 8 bytes | n bytes | - * | LZMA properties | Uncompressed length | Compressed data | - */ - compressed_data_len += 13; - uint8_t compressed_data[compressed_data_len]; - /* put lzma properties */ - memcpy(compressed_data, buffer + 12, 5); - /* put lzma end marker */ - memset(compressed_data + 5, 0xFF, 8); - /* put compressed data */ - memcpy(compressed_data + 13, buffer + offset, compressed_data_len - 13); - - /* the first 8 bytes represents the fws header, see 'FWS format' above. - * data will start from 8th bytes - */ - r = FileSwfLzmaDecompression(det_ctx, - compressed_data, compressed_data_len, - out_buffer->buf + 8, out_buffer->len - 8); - if (r == 0) - goto error; - } else { - goto error; - } - - /* all went well so switch the buffer's inspect pointer/size - * to use the new data. */ - out_buffer->inspect = out_buffer->buf; - out_buffer->inspect_len = out_buffer->len; - - return 1; - -error: - return 0; -} diff --git a/src/util-file-decompression.h b/src/util-file-decompression.h deleted file mode 100644 index 043d68319115..000000000000 --- a/src/util-file-decompression.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Giuseppe Longo - * - * - */ - -#ifndef __UTIL_FILE_DECOMPRESSION_H__ -#define __UTIL_FILE_DECOMPRESSION_H__ - -#include "detect.h" - -enum { - FILE_IS_NOT_SWF = 0, - FILE_SWF_NO_COMPRESSION, - FILE_SWF_ZLIB_COMPRESSION, - FILE_SWF_LZMA_COMPRESSION, -}; - -int FileIsSwfFile(const uint8_t *buffer, uint32_t buffer_len); -int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len, - DetectEngineThreadCtx *det_ctx, - InspectionBuffer *out_buffer, - int swf_type, - uint32_t decompress_depth, uint32_t compress_depth); - -#endif /* __UTIL_FILE_DECOMPRESSION_H__ */ diff --git a/src/util-file-swf-decompression.c b/src/util-file-swf-decompression.c deleted file mode 100644 index 378b4f96e942..000000000000 --- a/src/util-file-swf-decompression.c +++ /dev/null @@ -1,183 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Giuseppe Longo - * - */ - - -#include "suricata.h" -#include "suricata-common.h" - -#include "app-layer-htp.h" - -#include "util-file-decompression.h" -#include "util-file-swf-decompression.h" -#include "util-misc.h" -#include "util-print.h" -#include "util-validate.h" - -#include "rust.h" - -#include - -#define MAX_SWF_DECOMPRESSED_LEN 50000000 -/* - * Return uncompressed file length - * in little-endian order - */ -uint32_t FileGetSwfDecompressedLen(const uint8_t *buffer, - const uint32_t buffer_len) -{ - if (buffer_len < 8) { - return 0; - } - - uint32_t a = buffer[4]; - uint32_t b = buffer[5]; - uint32_t c = buffer[6]; - uint32_t d = buffer[7]; - - uint32_t value = (((a & 0xff) << 24UL) | - ((b & 0xff) << 16UL) | - ((c & 0xff) << 8UL) | - (d & 0xff)); - - uint32_t len = (((value >> 24) & 0x000000FFUL) | - ((value >> 8) & 0x0000FF00UL) | - ((value << 8) & 0x00FF0000UL) | - ((value << 24) & 0xFF000000UL)); - - return MIN(MAX_SWF_DECOMPRESSED_LEN, len); -} - -uint8_t FileGetSwfVersion(const uint8_t *buffer, const uint32_t buffer_len) -{ - if (buffer_len > 3) - return buffer[3]; - - return 0; -} - -/* CWS format */ -/* - * | 4 bytes | 4 bytes | n bytes | - * | 'CWS' + version | script len | compressed data | - */ -int FileSwfZlibDecompression(DetectEngineThreadCtx *det_ctx, - uint8_t *compressed_data, uint32_t compressed_data_len, - uint8_t *decompressed_data, uint32_t decompressed_data_len) -{ - int ret = 1; - z_stream infstream; - memset(&infstream, 0, sizeof(infstream)); - infstream.zalloc = Z_NULL; - infstream.zfree = Z_NULL; - infstream.opaque = Z_NULL; - - infstream.avail_in = (uInt)compressed_data_len; - infstream.next_in = (Bytef *)compressed_data; - infstream.avail_out = (uInt)decompressed_data_len; - infstream.next_out = (Bytef *)decompressed_data; - - int result = inflateInit(&infstream); - if (result != Z_OK) { - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_UNKNOWN_ERROR); - return 0; - } - - result = inflate(&infstream, Z_NO_FLUSH); - switch(result) { - case Z_STREAM_END: - break; - case Z_OK: - break; - case Z_DATA_ERROR: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_DATA_ERROR); - ret = 0; - break; - case Z_STREAM_ERROR: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_STREAM_ERROR); - ret = 0; - break; - case Z_BUF_ERROR: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_BUF_ERROR); - ret = 0; - break; - default: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_UNKNOWN_ERROR); - ret = 0; - break; - } - inflateEnd(&infstream); - - return ret; -} - -/* ZWS format */ -/* - * | 4 bytes | 4 bytes | 4 bytes | 5 bytes | n bytes | 6 bytes | - * | 'ZWS' + version | script len | compressed len | LZMA props | LZMA data | LZMA end marker | - */ -int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, - uint8_t *compressed_data, uint32_t compressed_data_len, - uint8_t *decompressed_data, uint32_t decompressed_data_len) -{ - int ret = 0; - - size_t inprocessed = compressed_data_len; - size_t outprocessed = decompressed_data_len; - - ret = lzma_decompress(compressed_data, &inprocessed, decompressed_data, &outprocessed, - MAX_SWF_DECOMPRESSED_LEN); - - switch(ret) { - case LzmaOk: - ret = 1; - break; - case LzmaIoError: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_IO_ERROR); - ret = 0; - break; - case LzmaHeaderTooShortError: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR); - ret = 0; - break; - case LzmaError: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_DECODER_ERROR); - ret = 0; - break; - case LzmaMemoryError: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR); - ret = 0; - break; - case LzmaXzError: - /* We should not see XZ compressed SWF files */ - DEBUG_VALIDATE_BUG_ON(ret == LzmaXzError); - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_XZ_ERROR); - ret = 0; - break; - default: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR); - ret = 0; - break; - } - - return ret; -} diff --git a/src/util-file-swf-decompression.h b/src/util-file-swf-decompression.h deleted file mode 100644 index 65ac74add178..000000000000 --- a/src/util-file-swf-decompression.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Giuseppe Longo - * - * - */ - -#ifndef __UTIL_FILE_SWF_DECOMPRESSION_H__ -#define __UTIL_FILE_SWF_DECOMPRESSION_H__ - -/* If we don't have the decompressed data len, - * we use a default value. - */ -#define MIN_SWF_LEN 2920 - -uint8_t FileGetSwfVersion(const uint8_t *buffer, const uint32_t buffer_len); -uint32_t FileGetSwfDecompressedLen(const uint8_t *buffer, uint32_t buffer_len); -int FileSwfZlibDecompression(DetectEngineThreadCtx *det_ctx, - uint8_t *compressed_data, uint32_t compressed_data_len, - uint8_t *decompressed_data, uint32_t decompressed_data_len); -int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, - uint8_t *compressed_data, uint32_t compressed_data_len, - uint8_t *decompressed_data, uint32_t decompressed_data_len); - -#endif /* __UTIL_FILE_SWF_DECOMPRESSION_H__ */ diff --git a/src/util-file.c b/src/util-file.c deleted file mode 100644 index 3221d116870d..000000000000 --- a/src/util-file.c +++ /dev/null @@ -1,1220 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Pablo Rincon - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "flow.h" -#include "stream.h" -#include "stream-tcp.h" -#include "runmodes.h" -#include "util-hash.h" -#include "util-debug.h" -#include "util-memcmp.h" -#include "util-print.h" -#include "app-layer-parser.h" -#include "util-validate.h" -#include "rust.h" - -extern int g_detect_disabled; - -/** \brief mask of file flags we'll not set - * This mask is set based on global file settings and - * cannot be overridden by detection. - */ -static uint16_t g_file_flow_mask = 0; - -/** \brief switch to force filestore on all files - * regardless of the rules. - */ -static int g_file_force_filestore = 0; - -/** \brief switch to force magic checks on all files - * regardless of the rules. - */ -static int g_file_force_magic = 0; - -/** \brief switch to force md5 calculation on all files - * regardless of the rules. - */ -static int g_file_force_md5 = 0; - -/** \brief switch to force sha1 calculation on all files - * regardless of the rules. - */ -static int g_file_force_sha1 = 0; - -/** \brief switch to force sha256 calculation on all files - * regardless of the rules. - */ -static int g_file_force_sha256 = 0; - -/** \brief switch to force tracking off all files - * regardless of the rules. - */ -static int g_file_force_tracking = 0; - -/** \brief switch to use g_file_store_reassembly_depth - * to reassembly files - */ -static int g_file_store_enable = 0; - -/** \brief stream_config.reassembly_depth equivalent - * for files - */ -static uint32_t g_file_store_reassembly_depth = 0; - -/* prototypes */ -static void FileFree(File *, const StreamingBufferConfig *cfg); -static void FileEndSha256(File *ff); - -void FileForceFilestoreEnable(void) -{ - g_file_force_filestore = 1; - g_file_flow_mask |= (FLOWFILE_NO_STORE_TS|FLOWFILE_NO_STORE_TC); -} - -void FileForceMagicEnable(void) -{ - g_file_force_magic = 1; - g_file_flow_mask |= (FLOWFILE_NO_MAGIC_TS|FLOWFILE_NO_MAGIC_TC); -} - -void FileForceMd5Enable(void) -{ - g_file_force_md5 = 1; - g_file_flow_mask |= (FLOWFILE_NO_MD5_TS|FLOWFILE_NO_MD5_TC); -} - -void FileForceSha1Enable(void) -{ - g_file_force_sha1 = 1; - g_file_flow_mask |= (FLOWFILE_NO_SHA1_TS|FLOWFILE_NO_SHA1_TC); -} - -void FileForceSha256Enable(void) -{ - g_file_force_sha256 = 1; - g_file_flow_mask |= (FLOWFILE_NO_SHA256_TS|FLOWFILE_NO_SHA256_TC); -} - -int FileForceFilestore(void) -{ - return g_file_force_filestore; -} - -void FileReassemblyDepthEnable(uint32_t size) -{ - g_file_store_enable = 1; - g_file_store_reassembly_depth = size; -} - -uint32_t FileReassemblyDepth(void) -{ - if (g_file_store_enable == 1) - return g_file_store_reassembly_depth; - else - return stream_config.reassembly_depth; -} - -int FileForceMagic(void) -{ - return g_file_force_magic; -} - -int FileForceMd5(void) -{ - return g_file_force_md5; -} - -int FileForceSha1(void) -{ - return g_file_force_sha1; -} - -int FileForceSha256(void) -{ - return g_file_force_sha256; -} - -void FileForceTrackingEnable(void) -{ - g_file_force_tracking = 1; - g_file_flow_mask |= (FLOWFILE_NO_SIZE_TS|FLOWFILE_NO_SIZE_TC); -} - -/** - * \brief Function to parse forced file hashing configuration. - */ -void FileForceHashParseCfg(ConfNode *conf) -{ - BUG_ON(conf == NULL); - - ConfNode *forcehash_node = NULL; - - /* legacy option */ - const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); - if (force_md5 != NULL) { - SCLogWarning("deprecated 'force-md5' option " - "found. Please use 'force-hash: [md5]' instead"); - - if (ConfValIsTrue(force_md5)) { - if (g_disable_hashing) { - SCLogInfo( - "not forcing md5 calculation for logged files: hashing globally disabled"); - } else { - FileForceMd5Enable(); - SCLogInfo("forcing md5 calculation for logged files"); - } - } - } - - if (conf != NULL) - forcehash_node = ConfNodeLookupChild(conf, "force-hash"); - - if (forcehash_node != NULL) { - ConfNode *field = NULL; - - TAILQ_FOREACH(field, &forcehash_node->head, next) { - if (strcasecmp("md5", field->val) == 0) { - if (g_disable_hashing) { - SCLogInfo("not forcing md5 calculation for logged files: hashing globally " - "disabled"); - } else { - FileForceMd5Enable(); - SCLogConfig("forcing md5 calculation for logged or stored files"); - } - } - - if (strcasecmp("sha1", field->val) == 0) { - if (g_disable_hashing) { - SCLogInfo("not forcing sha1 calculation for logged files: hashing globally " - "disabled"); - } else { - FileForceSha1Enable(); - SCLogConfig("forcing sha1 calculation for logged or stored files"); - } - } - - if (strcasecmp("sha256", field->val) == 0) { - if (g_disable_hashing) { - SCLogInfo("not forcing sha256 calculation for logged files: hashing globally " - "disabled"); - } else { - FileForceSha256Enable(); - SCLogConfig("forcing sha256 calculation for logged or stored files"); - } - } - } - } -} - -uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction) -{ - uint16_t flags = 0; - - if (direction == STREAM_TOSERVER) { - if ((flow_file_flags & (FLOWFILE_NO_STORE_TS | FLOWFILE_STORE)) == FLOWFILE_NO_STORE_TS) { - flags |= FILE_NOSTORE; - } - - if (flow_file_flags & FLOWFILE_NO_MAGIC_TS) { - flags |= FILE_NOMAGIC; - } - - if (flow_file_flags & FLOWFILE_NO_MD5_TS) { - flags |= FILE_NOMD5; - } - - if (flow_file_flags & FLOWFILE_NO_SHA1_TS) { - flags |= FILE_NOSHA1; - } - - if (flow_file_flags & FLOWFILE_NO_SHA256_TS) { - flags |= FILE_NOSHA256; - } - } else { - if ((flow_file_flags & (FLOWFILE_NO_STORE_TC | FLOWFILE_STORE)) == FLOWFILE_NO_STORE_TC) { - flags |= FILE_NOSTORE; - } - - if (flow_file_flags & FLOWFILE_NO_MAGIC_TC) { - flags |= FILE_NOMAGIC; - } - - if (flow_file_flags & FLOWFILE_NO_MD5_TC) { - flags |= FILE_NOMD5; - } - - if (flow_file_flags & FLOWFILE_NO_SHA1_TC) { - flags |= FILE_NOSHA1; - } - - if (flow_file_flags & FLOWFILE_NO_SHA256_TC) { - flags |= FILE_NOSHA256; - } - } - if (flow_file_flags & FLOWFILE_STORE) { - flags |= FILE_STORE; - } - DEBUG_VALIDATE_BUG_ON((flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); - - SCLogDebug("direction %02x flags %02x", direction, flags); - return flags; -} - -uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction) -{ - return FileFlowFlagsToFlags(flow->file_flags, direction); -} - -void FileApplyTxFlags(const AppLayerTxData *txd, const uint8_t direction, File *file) -{ - SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags, - (file->flags & FILE_STORE) ? "true" : "false", - (file->flags & FILE_NOSTORE) ? "true" : "false"); - uint16_t update_flags = FileFlowFlagsToFlags(txd->file_flags, direction); - DEBUG_VALIDATE_BUG_ON( - (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); - if (file->flags & FILE_STORE) - update_flags &= ~FILE_NOSTORE; - - file->flags |= update_flags; - SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags, - (file->flags & FILE_STORE) ? "true" : "false", - (file->flags & FILE_NOSTORE) ? "true" : "false"); - DEBUG_VALIDATE_BUG_ON( - (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); -} - -static int FileMagicSize(void) -{ - /** \todo make this size configurable */ - return 512; -} - -/** - * \brief get the size of the file data - * - * This doesn't reflect how much of the file we have in memory, just the - * total size of filedata so far. - */ -uint64_t FileDataSize(const File *file) -{ - if (file != NULL && file->sb != NULL) { - const uint64_t size = StreamingBufferGetConsecutiveDataRightEdge(file->sb); - SCLogDebug("returning %" PRIu64, size); - return size; - } - SCLogDebug("returning 0 (default)"); - return 0; -} - -/** - * \brief get the size of the file - * - * This doesn't reflect how much of the file we have in memory, just the - * total size of file so far. - */ -uint64_t FileTrackedSize(const File *file) -{ - if (file != NULL) { - return file->size; - } - return 0; -} - -/** \brief test if file is ready to be pruned - * - * If a file is in the 'CLOSED' state, it means it has been processed - * completely by the pipeline in the correct direction. So we can - * prune it then. - * - * For other states, as well as for files we may not need to track - * until the close state, more specific checks are done. - * - * Also does house keeping within the file: move streaming buffer - * forward if possible. - * - * \retval 1 prune (free) this file - * \retval 0 file not ready to be freed - */ -static int FilePruneFile(File *file, const StreamingBufferConfig *cfg) -{ - SCEnter(); - - /* file is done when state is closed+, logging/storing is done (if any) */ - SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s", - file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no"); - if (file->state >= FILE_STATE_CLOSED) { - SCReturnInt(1); - } - -#ifdef HAVE_MAGIC - if (!(file->flags & FILE_NOMAGIC)) { - /* need magic but haven't set it yet, bail out */ - if (file->magic == NULL) - SCReturnInt(0); - else - SCLogDebug("file->magic %s", file->magic); - } else { - SCLogDebug("file->flags & FILE_NOMAGIC == true"); - } -#endif - uint64_t left_edge = FileDataSize(file); - if (file->flags & FILE_STORE) { - left_edge = MIN(left_edge,file->content_stored); - } - - if (!g_detect_disabled) { - left_edge = MIN(left_edge, file->content_inspected); - /* if file has inspect window and min size set, we - * do some house keeping here */ - if (file->inspect_window != 0 && file->inspect_min_size != 0) { - const uint64_t file_offset = StreamingBufferGetOffset(file->sb); - uint32_t window = file->inspect_window; - if (file_offset == 0) - window = MAX(window, file->inspect_min_size); - - uint64_t file_size = FileDataSize(file); - uint64_t data_size = file_size - file_offset; - - SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, - window, file_size, data_size); - - if (data_size > (window * 3)) { - file->content_inspected = MAX(file->content_inspected, file->size - window); - SCLogDebug("file->content_inspected now %" PRIu64, file->content_inspected); - } - - if (left_edge > window) - left_edge -= window; - else - left_edge = 0; - } - } - - if (left_edge) { - SCLogDebug("sliding to %" PRIu64, left_edge); - StreamingBufferSlideToOffset(file->sb, cfg, left_edge); - } - - SCReturnInt(0); -} - -#ifdef DEBUG -#define P(file, flag) ((file)->flags & (flag)) ? "true" : "false" -void FilePrintFlags(const File *file) -{ - SCLogDebug("file %p flags %04x " - "FILE_TRUNCATED %s " - "FILE_NOMAGIC %s " - "FILE_NOMD5 %s " - "FILE_MD5 %s " - "FILE_NOSHA1 %s " - "FILE_SHA1 %s " - "FILE_NOSHA256 %s " - "FILE_SHA256 %s " - "FILE_LOGGED %s " - "FILE_NOSTORE %s " - "FILE_STORE %s " - "FILE_STORED %s " - "FILE_NOTRACK %s " - "FILE_HAS_GAPS %s", - file, file->flags, P(file, FILE_TRUNCATED), P(file, FILE_NOMAGIC), P(file, FILE_NOMD5), - P(file, FILE_MD5), P(file, FILE_NOSHA1), P(file, FILE_SHA1), P(file, FILE_NOSHA256), - P(file, FILE_SHA256), P(file, FILE_LOGGED), P(file, FILE_NOSTORE), P(file, FILE_STORE), - P(file, FILE_STORED), P(file, FILE_NOTRACK), P(file, FILE_HAS_GAPS)); -} -#undef P -#endif - -static void FilePrune(FileContainer *ffc, const StreamingBufferConfig *cfg) -{ - SCEnter(); - SCLogDebug("ffc %p head %p", ffc, ffc->head); - File *file = ffc->head; - File *prev = NULL; - - while (file) { -#ifdef DEBUG - FilePrintFlags(file); -#endif - if (FilePruneFile(file, cfg) == 0) { - prev = file; - file = file->next; - continue; - } - - SCLogDebug("removing file %p", file); - - File *file_next = file->next; - - if (prev) - prev->next = file_next; - /* update head and tail */ - if (file == ffc->head) - ffc->head = file_next; - if (file == ffc->tail) - ffc->tail = prev; - - FileFree(file, cfg); - file = file_next; - } - SCReturn; -} - -/** - * \brief allocate a FileContainer - * - * \retval new newly allocated FileContainer - * \retval NULL error - */ -FileContainer *FileContainerAlloc(void) -{ - FileContainer *new = SCCalloc(1, sizeof(FileContainer)); - if (unlikely(new == NULL)) { - SCLogError("Error allocating mem"); - return NULL; - } - new->head = new->tail = NULL; - return new; -} - -/** - * \brief Recycle a FileContainer - * - * \param ffc FileContainer - */ -void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg) -{ - SCLogDebug("ffc %p", ffc); - if (ffc == NULL) - return; - - File *cur = ffc->head; - File *next = NULL; - for (;cur != NULL; cur = next) { - next = cur->next; - FileFree(cur, cfg); - } - ffc->head = ffc->tail = NULL; -} - -/** - * \brief Free a FileContainer - * - * \param ffc FileContainer - */ -void FileContainerFree(FileContainer *ffc, const StreamingBufferConfig *cfg) -{ - SCLogDebug("ffc %p", ffc); - if (ffc == NULL) - return; - - File *ptr = ffc->head; - File *next = NULL; - for (;ptr != NULL; ptr = next) { - next = ptr->next; - FileFree(ptr, cfg); - } - ffc->head = ffc->tail = NULL; - SCFree(ffc); -} - -/** - * \brief Alloc a new File - * - * \param name character array containing the name (not a string) - * \param name_len length in bytes of the name - * - * \retval new File object or NULL on error - */ -static File *FileAlloc(const uint8_t *name, uint16_t name_len) -{ - File *new = SCCalloc(1, sizeof(File)); - if (unlikely(new == NULL)) { - SCLogError("Error allocating mem"); - return NULL; - } - - new->name = SCMalloc(name_len); - if (new->name == NULL) { - SCFree(new); - return NULL; - } - - new->name_len = name_len; - memcpy(new->name, name, name_len); - - new->sid_cnt = 0; - new->sid_max = 8; - /* SCMalloc() is allowed to fail here because sid well be checked later on */ - new->sid = SCMalloc(sizeof(uint32_t) * new->sid_max); - if (new->sid == NULL) - new->sid_max = 0; - - return new; -} - -static void FileFree(File *ff, const StreamingBufferConfig *sbcfg) -{ - SCLogDebug("ff %p", ff); - if (ff == NULL) - return; - - if (ff->name != NULL) - SCFree(ff->name); - if (ff->sid != NULL) - SCFree(ff->sid); -#ifdef HAVE_MAGIC - /* magic returned by libmagic is strdup'd by MagicLookup. */ - if (ff->magic != NULL) - SCFree(ff->magic); -#endif - if (ff->sb != NULL) { - StreamingBufferFree(ff->sb, sbcfg); - } - - if (ff->md5_ctx) - SCMd5Free(ff->md5_ctx); - if (ff->sha1_ctx) - SCSha1Free(ff->sha1_ctx); - if (ff->sha256_ctx) - SCSha256Free(ff->sha256_ctx); - SCFree(ff); -} - -void FileContainerAdd(FileContainer *ffc, File *ff) -{ - SCLogDebug("ffc %p ff %p", ffc, ff); - if (ffc->head == NULL || ffc->tail == NULL) { - ffc->head = ffc->tail = ff; - } else { - ffc->tail->next = ff; - ffc->tail = ff; - } -} - -/** - * \brief Tag a file for storing - * - * \param ff The file to store - */ -int FileStore(File *ff) -{ - SCLogDebug("ff %p", ff); - ff->flags |= FILE_STORE; - SCReturnInt(0); -} - -/** - * \brief check if we have stored enough - * - * \param ff file - * - * \retval 0 limit not reached yet - * \retval 1 limit reached - */ -static int FileStoreNoStoreCheck(File *ff) -{ - SCEnter(); - - if (ff == NULL) { - SCReturnInt(0); - } - - if (ff->flags & FILE_NOSTORE) { - if (ff->state == FILE_STATE_OPENED && - FileDataSize(ff) >= (uint64_t)FileMagicSize()) - { - SCReturnInt(1); - } - } - - SCReturnInt(0); -} - -static int AppendData( - const StreamingBufferConfig *sbcfg, File *file, const uint8_t *data, uint32_t data_len) -{ - SCLogDebug("file %p data_len %u", file, data_len); - if (StreamingBufferAppendNoTrack(file->sb, sbcfg, data, data_len) != 0) { - SCLogDebug("file %p StreamingBufferAppendNoTrack failed", file); - SCReturnInt(-1); - } - - if (file->md5_ctx) { - SCMd5Update(file->md5_ctx, data, data_len); - } - if (file->sha1_ctx) { - SCSha1Update(file->sha1_ctx, data, data_len); - } - if (file->sha256_ctx) { - SCLogDebug("SHA256 file %p data %p data_len %u", file, data, data_len); - SCSha256Update(file->sha256_ctx, data, data_len); - } else { - SCLogDebug("NO SHA256 file %p data %p data_len %u", file, data, data_len); - } - SCReturnInt(0); -} - -/** \internal - * \brief Flags a file as having gaps - * - * \param ff the file - */ -static void FileFlagGap(File *ff) { - ff->flags |= FILE_HAS_GAPS; - ff->flags |= (FILE_NOMD5|FILE_NOSHA1|FILE_NOSHA256); - ff->flags &= ~(FILE_MD5|FILE_SHA1|FILE_SHA256); -} - -/** \internal - * \brief Store/handle a chunk of file data in the File structure - * - * \param ff the file - * \param data data chunk - * \param data_len data chunk len - * - * \retval 0 ok - * \retval -1 error - * \retval -2 no store for this file - */ -static int FileAppendDataDo( - const StreamingBufferConfig *sbcfg, File *ff, const uint8_t *data, uint32_t data_len) -{ - SCEnter(); -#ifdef DEBUG_VALIDATION - BUG_ON(ff == NULL); -#endif - - ff->size += data_len; - if (data == NULL) { - FileFlagGap(ff); - SCReturnInt(0); - } - - if (ff->state != FILE_STATE_OPENED) { - if (ff->flags & FILE_NOSTORE) { - SCReturnInt(-2); - } - SCReturnInt(-1); - } - - if (g_detect_disabled && FileStoreNoStoreCheck(ff) == 1) { - int hash_done = 0; - /* no storage but forced hashing */ - if (ff->md5_ctx) { - SCMd5Update(ff->md5_ctx, data, data_len); - hash_done = 1; - } - if (ff->sha1_ctx) { - SCSha1Update(ff->sha1_ctx, data, data_len); - hash_done = 1; - } - if (ff->sha256_ctx) { - SCLogDebug("file %p data %p data_len %u", ff, data, data_len); - SCSha256Update(ff->sha256_ctx, data, data_len); - hash_done = 1; - } - - if (hash_done) - SCReturnInt(0); - - if (g_file_force_tracking || (!(ff->flags & FILE_NOTRACK))) - SCReturnInt(0); - - ff->state = FILE_STATE_TRUNCATED; - SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); - SCReturnInt(-2); - } - - SCLogDebug("appending %"PRIu32" bytes", data_len); - - int r = AppendData(sbcfg, ff, data, data_len); - if (r != 0) { - ff->state = FILE_STATE_ERROR; - SCReturnInt(r); - } - - SCReturnInt(0); -} - -/** - * \brief Store/handle a chunk of file data in the File structure - * The last file in the FileContainer will be used. - * - * \param ffc FileContainer used to append to - * \param data data chunk - * \param data_len data chunk len - * - * \retval 0 ok - * \retval -1 error - * \retval -2 no store for this file - */ -int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, - uint32_t data_len) -{ - SCEnter(); - - if (ffc == NULL || ffc->tail == NULL || data_len == 0 || sbcfg == NULL) { - SCReturnInt(-1); - } - int r = FileAppendDataDo(sbcfg, ffc->tail, data, data_len); - SCReturnInt(r); -} - -/** - * \brief Store/handle a chunk of file data in the File structure - * The file with 'track_id' in the FileContainer will be used. - * - * \param ffc FileContainer used to append to - * \param track_id id to lookup the file - * \param data data chunk - * \param data_len data chunk len - * - * \retval 0 ok - * \retval -1 error - * \retval -2 no store for this file - */ -int FileAppendDataById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, - const uint8_t *data, uint32_t data_len) -{ - SCEnter(); - - if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) { - SCReturnInt(-1); - } - File *ff = ffc->head; - for ( ; ff != NULL; ff = ff->next) { - if (track_id == ff->file_track_id) { - int r = FileAppendDataDo(sbcfg, ff, data, data_len); - SCReturnInt(r); - } - } - SCReturnInt(-1); -} - -/** - * \brief Store/handle a chunk of file data in the File structure - * The file with 'track_id' in the FileContainer will be used. - * - * \param ffc FileContainer used to append to - * \param track_id id to lookup the file - * \param data data chunk - * \param data_len data chunk len - * - * \retval 0 ok - * \retval -1 error - * \retval -2 no store for this file - */ -int FileAppendGAPById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, - const uint8_t *data, uint32_t data_len) -{ - SCEnter(); - - if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) { - SCReturnInt(-1); - } - File *ff = ffc->head; - for ( ; ff != NULL; ff = ff->next) { - if (track_id == ff->file_track_id) { - FileFlagGap(ff); - SCLogDebug("FILE_HAS_GAPS set"); - - int r = FileAppendDataDo(sbcfg, ff, data, data_len); - SCReturnInt(r); - } - } - SCReturnInt(-1); -} - -void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min) -{ - file->inspect_window = win; - file->inspect_min_size = min; -} - -/** - * \brief Sets the offset range for a file. - * - * \param ffc the container - * \param start start offset - * \param end end offset - * - * \retval 0 ok - * \retval -1 error - */ -int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end) -{ - SCEnter(); - - if (ffc == NULL || ffc->tail == NULL) { - SCReturnInt(-1); - } - ffc->tail->start = start; - ffc->tail->end = end; - SCReturnInt(0); -} - -/** - * \brief Open a new File - * - * \param ffc flow container - * \param sbcfg buffer config - * \param name filename character array - * \param name_len filename len - * \param data initial data - * \param data_len initial data len - * \param flags open flags - * - * \retval ff flowfile object - * - * \note filename is not a string, so it's not nul terminated. - */ -static File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, - const uint8_t *name, uint16_t name_len, - const uint8_t *data, uint32_t data_len, uint16_t flags) -{ - SCEnter(); - - //PrintRawDataFp(stdout, name, name_len); - - File *ff = FileAlloc(name, name_len); - if (ff == NULL) { - SCReturnPtr(NULL, "File"); - } - - ff->sb = StreamingBufferInit(sbcfg); - if (ff->sb == NULL) { - FileFree(ff, sbcfg); - SCReturnPtr(NULL, "File"); - } - SCLogDebug("ff->sb %p", ff->sb); - - if (flags & FILE_STORE || g_file_force_filestore) { - FileStore(ff); - } else if (flags & FILE_NOSTORE) { - SCLogDebug("not storing this file"); - ff->flags |= FILE_NOSTORE; - } - if (flags & FILE_NOMAGIC) { - SCLogDebug("not doing magic for this file"); - ff->flags |= FILE_NOMAGIC; - } - if (flags & FILE_NOMD5) { - SCLogDebug("not doing md5 for this file"); - ff->flags |= FILE_NOMD5; - } - if (flags & FILE_NOSHA1) { - SCLogDebug("not doing sha1 for this file"); - ff->flags |= FILE_NOSHA1; - } - if (flags & FILE_NOSHA256) { - SCLogDebug("not doing sha256 for this file"); - ff->flags |= FILE_NOSHA256; - } - - if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) { - ff->md5_ctx = SCMd5New(); - } - if (!(ff->flags & FILE_NOSHA1) || g_file_force_sha1) { - ff->sha1_ctx = SCSha1New(); - } - if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) { - ff->sha256_ctx = SCSha256New(); - SCLogDebug("ff %p ff->sha256_ctx %p", ff, ff->sha256_ctx); - } - - ff->state = FILE_STATE_OPENED; - SCLogDebug("flowfile state transitioned to FILE_STATE_OPENED"); - - ff->fd = -1; - - FileContainerAdd(ffc, ff); - - /* set default window and min inspection size */ - FileSetInspectSizes(ff, FILEDATA_CONTENT_INSPECT_WINDOW, FILEDATA_CONTENT_INSPECT_MIN_SIZE); - - ff->size += data_len; - if (data != NULL) { - if (AppendData(sbcfg, ff, data, data_len) != 0) { - ff->state = FILE_STATE_ERROR; - SCReturnPtr(NULL, "File"); - } - SCLogDebug("file size is now %"PRIu64, FileTrackedSize(ff)); - } else if (data_len > 0) { - FileFlagGap(ff); - } - - SCReturnPtr(ff, "File"); -} - -/** - * \retval 0 ok - * \retval -1 failed */ -int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, - uint32_t track_id, const uint8_t *name, uint16_t name_len, - const uint8_t *data, uint32_t data_len, uint16_t flags) -{ - SCLogDebug("ffc %p track_id %u", ffc, track_id); - File *ff = FileOpenFile(ffc, sbcfg, name, name_len, data, data_len, flags); - if (ff == NULL) - return -1; - - ff->file_track_id = track_id; - return 0; -} - -int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data, - uint32_t data_len, uint16_t flags) -{ - SCEnter(); - - if (ff == NULL) { - SCReturnInt(-1); - } - - if (ff->state != FILE_STATE_OPENED) { - SCReturnInt(-1); - } - - ff->size += data_len; - if (data != NULL) { - if (ff->flags & FILE_NOSTORE) { - /* no storage but hashing */ - if (ff->md5_ctx) - SCMd5Update(ff->md5_ctx, data, data_len); - if (ff->sha1_ctx) - SCSha1Update(ff->sha1_ctx, data, data_len); - if (ff->sha256_ctx) { - SCLogDebug("file %p data %p data_len %u", ff, data, data_len); - SCSha256Update(ff->sha256_ctx, data, data_len); - } - } else { - if (AppendData(sbcfg, ff, data, data_len) != 0) { - ff->state = FILE_STATE_ERROR; - SCReturnInt(-1); - } - } - } - - if ((flags & FILE_TRUNCATED) || (ff->flags & FILE_HAS_GAPS)) { - SCLogDebug("flags FILE_TRUNCATED %s", (flags & FILE_TRUNCATED) ? "true" : "false"); - SCLogDebug("ff->flags FILE_HAS_GAPS %s", (ff->flags & FILE_HAS_GAPS) ? "true" : "false"); - - ff->state = FILE_STATE_TRUNCATED; - SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); - - if (flags & FILE_NOSTORE) { - SCLogDebug("not storing this file"); - ff->flags |= FILE_NOSTORE; - } else { - if (g_file_force_sha256 && ff->sha256_ctx) { - SCLogDebug("file %p data %p data_len %u", ff, data, data_len); - FileEndSha256(ff); - } - } - } else { - ff->state = FILE_STATE_CLOSED; - SCLogDebug("flowfile state transitioned to FILE_STATE_CLOSED"); - - if (ff->md5_ctx) { - SCMd5Finalize(ff->md5_ctx, ff->md5, sizeof(ff->md5)); - ff->md5_ctx = NULL; - ff->flags |= FILE_MD5; - } - if (ff->sha1_ctx) { - SCSha1Finalize(ff->sha1_ctx, ff->sha1, sizeof(ff->sha1)); - ff->sha1_ctx = NULL; - ff->flags |= FILE_SHA1; - } - if (ff->sha256_ctx) { - SCLogDebug("file %p data %p data_len %u", ff, data, data_len); - FileEndSha256(ff); - } - } - - SCReturnInt(0); -} - -/** - * \brief Close a File - * - * \param ffc the container - * \param data final data if any - * \param data_len data len if any - * \param flags flags - * - * \retval 0 ok - * \retval -1 error - */ -int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, - uint32_t data_len, uint16_t flags) -{ - SCEnter(); - - if (ffc == NULL || ffc->tail == NULL) { - SCReturnInt(-1); - } - - if (FileCloseFilePtr(ffc->tail, sbcfg, data, data_len, flags) == -1) { - SCReturnInt(-1); - } - - SCReturnInt(0); -} - -int FileCloseFileById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, - const uint8_t *data, uint32_t data_len, uint16_t flags) -{ - SCEnter(); - - if (ffc == NULL || ffc->tail == NULL) { - SCReturnInt(-1); - } - - File *ff = ffc->head; - for ( ; ff != NULL; ff = ff->next) { - if (track_id == ff->file_track_id) { - int r = FileCloseFilePtr(ff, sbcfg, data, data_len, flags); - SCReturnInt(r); - } - } - SCReturnInt(-1); -} - -/** \brief set a flow's file flags - * \param set_file_flags flags in both directions that are requested to set - * - * This function will ignore the flags for the irrelevant direction and - * also mask the flags with the global settings. - */ -void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction) -{ - SCEnter(); - DEBUG_ASSERT_FLOW_LOCKED(f); - - /* remove flags not in our direction and - don't disable what is globally enabled */ - if (direction == STREAM_TOSERVER) { - set_file_flags &= ~(FLOWFILE_NONE_TC|g_file_flow_mask); - } else { - set_file_flags &= ~(FLOWFILE_NONE_TS|g_file_flow_mask); - } - f->file_flags |= set_file_flags; - - SCLogDebug("f->file_flags %04x set_file_flags %04x g_file_flow_mask %04x", - f->file_flags, set_file_flags, g_file_flow_mask); - - if (set_file_flags != 0 && f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) { - AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate); - if (sd != NULL) { - if ((sd->file_flags & f->file_flags) != f->file_flags) { - SCLogDebug("state data: updating file_flags %04x with flow file_flags %04x", - sd->file_flags, f->file_flags); - sd->file_flags |= f->file_flags; - } - } - } -} - -/** - * \brief disable file storing for files in a transaction - * - * \param f *LOCKED* flow - * \param direction flow direction - * \param tx_id transaction id - */ -void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id) -{ - if (g_file_force_filestore == 0) { - AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, tx); - if (txd != NULL) { - if (direction & STREAM_TOSERVER) { - txd->file_flags |= FLOWFILE_NO_STORE_TS; - } else { - txd->file_flags |= FLOWFILE_NO_STORE_TC; - } - } - } -} - -/** - * \brief flag a file with id "file_id" to be stored. - * - * \param fc file store - * \param file_id the file's id - */ -void FileStoreFileById(FileContainer *fc, uint32_t file_id) -{ - File *ptr = NULL; - - SCEnter(); - - if (fc != NULL) { - for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { - if (ptr->file_track_id == file_id) { - FileStore(ptr); - } - } - } -} - -static void FileTruncateAllOpenFiles(FileContainer *fc, const StreamingBufferConfig *sbcfg) -{ - File *ptr = NULL; - - SCEnter(); - - if (fc != NULL) { - for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { - if (ptr->state == FILE_STATE_OPENED) { - FileCloseFilePtr(ptr, sbcfg, NULL, 0, FILE_TRUNCATED); - } - } - } -} - -void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc) -{ - if (trunc) { - FileTruncateAllOpenFiles(fc, sbcfg); - } - FilePrune(fc, sbcfg); -} - -/** - * \brief Finish the SHA256 calculation. - */ -static void FileEndSha256(File *ff) -{ - SCLogDebug("ff %p ff->size %" PRIu64, ff, ff->size); - if (!(ff->flags & FILE_SHA256) && ff->sha256_ctx) { - SCSha256Finalize(ff->sha256_ctx, ff->sha256, sizeof(ff->sha256)); - ff->sha256_ctx = NULL; - ff->flags |= FILE_SHA256; - } -} diff --git a/src/util-file.h b/src/util-file.h deleted file mode 100644 index 55d91192fe12..000000000000 --- a/src/util-file.h +++ /dev/null @@ -1,255 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#ifndef __UTIL_FILE_H__ -#define __UTIL_FILE_H__ - -#include "conf.h" -#include "util-streaming-buffer.h" -#include "flow.h" - -/* Hack: Pulling rust.h to get the SCSha256 causes all sorts of problems with - * header include orders, which is something we'll have to resolve as we provide - * more functionality via Rust. But this lets me continue with replacing nss - * without fighting the headers at this time. */ -typedef struct SCSha256 SCSha256; -#define SC_SHA256_LEN 32 - -typedef struct SCSha1 SCSha1; -#define SC_SHA1_LEN 20 - -typedef struct SCMd5 SCMd5; -#define SC_MD5_LEN 16 - -#define FILE_TRUNCATED BIT_U16(0) -#define FILE_NOMAGIC BIT_U16(1) -#define FILE_NOMD5 BIT_U16(2) -#define FILE_MD5 BIT_U16(3) -#define FILE_NOSHA1 BIT_U16(4) -#define FILE_SHA1 BIT_U16(5) -#define FILE_NOSHA256 BIT_U16(6) -#define FILE_SHA256 BIT_U16(7) -#define FILE_LOGGED BIT_U16(8) -#define FILE_NOSTORE BIT_U16(9) -#define FILE_STORE BIT_U16(10) -#define FILE_STORED BIT_U16(11) -#define FILE_NOTRACK BIT_U16(12) /**< track size of file */ -#define FILE_USE_DETECT BIT_U16(13) /**< use content_inspected tracker */ -#define FILE_HAS_GAPS BIT_U16(15) - -// to be used instead of PATH_MAX which depends on the OS -#define SC_FILENAME_MAX 4096 - -#define FILEDATA_CONTENT_LIMIT 100000 -#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768 -#define FILEDATA_CONTENT_INSPECT_WINDOW 4096 - -typedef enum FileState_ { - FILE_STATE_NONE = 0, /**< no state */ - FILE_STATE_OPENED, /**< flow file is opened */ - FILE_STATE_CLOSED, /**< flow file is completed, - there will be no more data. */ - FILE_STATE_TRUNCATED, /**< flow file is not complete, but - there will be no more data. */ - FILE_STATE_ERROR, /**< file is in an error state */ - FILE_STATE_MAX -} FileState; - -typedef struct File_ { - uint16_t flags; - uint16_t name_len; - FileState state; - StreamingBuffer *sb; - uint32_t file_track_id; /**< id used by protocol parser */ - uint32_t file_store_id; /**< id used in store file name file. */ - int fd; /**< file descriptor for filestore, not - open if equal to -1 */ - uint8_t *name; -#ifdef HAVE_MAGIC - char *magic; -#endif - struct File_ *next; - SCMd5 *md5_ctx; - uint8_t md5[SC_MD5_LEN]; - SCSha1 *sha1_ctx; - uint8_t sha1[SC_SHA1_LEN]; - SCSha256 *sha256_ctx; - uint8_t sha256[SC_SHA256_LEN]; - uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT - * flag is set */ - uint64_t content_stored; - uint64_t size; - uint32_t inspect_window; - uint32_t inspect_min_size; - uint64_t start; - uint64_t end; - - uint32_t *sid; /* signature id of a rule that triggered the filestore event */ - uint32_t sid_cnt; - uint32_t sid_max; -} File; - -typedef struct FileContainer_ { - File *head; - File *tail; -} FileContainer; - -FileContainer *FileContainerAlloc(void); -void FileContainerFree(FileContainer *, const StreamingBufferConfig *cfg); - -void FileContainerRecycle(FileContainer *, const StreamingBufferConfig *cfg); - -void FileContainerAdd(FileContainer *, File *); - -/** - * \brief Open a new File - * - * \param ffc flow container - * \param sbcfg buffer config - * \param name filename character array - * \param name_len filename len - * \param data initial data - * \param data_len initial data len - * \param flags open flags - * - * \retval ff flowfile object - * - * \note filename is not a string, so it's not nul terminated. - * - * If flags contains the FILE_USE_DETECT bit, the pruning code will - * consider not just the content_stored tracker, but also content_inspected. - * It's the responsibility of the API user to make sure this tracker is - * properly updated. - */ -int FileOpenFileWithId(FileContainer *, const StreamingBufferConfig *, - uint32_t track_id, const uint8_t *name, uint16_t name_len, - const uint8_t *data, uint32_t data_len, uint16_t flags); - -/** - * \brief Close a File - * - * \param ffc the container - * \param data final data if any - * \param data_len data len if any - * \param flags flags - * - * \retval 0 ok - * \retval -1 error - */ -int FileCloseFile(FileContainer *, const StreamingBufferConfig *sbcfg, const uint8_t *data, - uint32_t data_len, uint16_t flags); -int FileCloseFileById(FileContainer *, const StreamingBufferConfig *sbcfg, uint32_t track_id, - const uint8_t *data, uint32_t data_len, uint16_t flags); -int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data, - uint32_t data_len, uint16_t flags); - -/** - * \brief Store a chunk of file data in the flow. The open "flowfile" - * will be used. - * - * \param ffc the container - * \param data data chunk - * \param data_len data chunk len - * - * \retval 0 ok - * \retval -1 error - */ -int FileAppendData(FileContainer *, const StreamingBufferConfig *sbcfg, const uint8_t *data, - uint32_t data_len); -int FileAppendDataById(FileContainer *, const StreamingBufferConfig *sbcfg, uint32_t track_id, - const uint8_t *data, uint32_t data_len); -int FileAppendGAPById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, - const uint8_t *data, uint32_t data_len); - -void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min); - -/** - * \brief Sets the offset range for a file. - * - * \param ffc the container - * \param start start offset - * \param end end offset - * - * \retval 0 ok - * \retval -1 error - */ -int FileSetRange(FileContainer *, uint64_t start, uint64_t end); - -/** - * \brief Tag a file for storing - * - * \param ff The file to store - */ -int FileStore(File *); - -/** - * \brief disable file storing for a transaction - * - * \param f flow - * \param direction STREAM_TOSERVER or STREAM_TOCLIENT - * \param tx transaction pointer - * \param tx_id transaction id - */ -void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id); - -void FileForceFilestoreEnable(void); -int FileForceFilestore(void); -void FileReassemblyDepthEnable(uint32_t size); -uint32_t FileReassemblyDepth(void); - -void FileForceMagicEnable(void); -int FileForceMagic(void); - -void FileForceMd5Enable(void); -int FileForceMd5(void); - -void FileForceSha1Enable(void); -int FileForceSha1(void); - -void FileForceSha256Enable(void); -int FileForceSha256(void); - -void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction); - -void FileForceHashParseCfg(ConfNode *); - -void FileForceTrackingEnable(void); - -void FileStoreFileById(FileContainer *fc, uint32_t); - -uint64_t FileDataSize(const File *file); -uint64_t FileTrackedSize(const File *file); - -uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction); -uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction); - -#ifdef DEBUG -void FilePrintFlags(const File *file); -#else -#define FilePrintFlags(file) -#endif - -void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc); - -#endif /* __UTIL_FILE_H__ */ diff --git a/src/util-fix_checksum.c b/src/util-fix_checksum.c deleted file mode 100644 index 4fc60004ac2a..000000000000 --- a/src/util-fix_checksum.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Reference: OpenBSD's pf.c. - * - * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002 - 2008 Henning Brauer - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Effort sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F30602-01-2-0537. - */ - -#include - -#include "util-fix_checksum.h" - -/** - * \brief Fix-up an IP checksum. - * - * \param sum The current checksum. - * \param old Value of old header parameter. - * \param new Value of new header parameter. - * - * \retval New checksum. - */ -uint16_t -FixChecksum(uint16_t sum, uint16_t old, uint16_t new) -{ - uint32_t l; - - l = sum + old - new; - l = (l >> 16) + (l & 65535); - - return (uint16_t)(l & 65535); -} diff --git a/src/util-fmemopen.c b/src/util-fmemopen.c deleted file mode 100644 index 412b9783ef3a..000000000000 --- a/src/util-fmemopen.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * Based on FMem.c of Alexandre Flori (2008/10/17 AF) - */ - -#include "suricata-common.h" -#include "util-fmemopen.h" - -#ifdef OS_DARWIN -#define USE_FMEM_WRAPPER 1 -#endif - -#ifdef OS_FREEBSD -#define USE_FMEM_WRAPPER 1 -#endif - -#ifdef __OpenBSD__ -#define USE_FMEM_WRAPPER 1 -#endif - -#ifdef USE_FMEM_WRAPPER - -#ifdef OS_WIN32 - -/** - * \brief portable version of SCFmemopen for Windows works on top of real temp files - * \param buffer that holds the file content - * \param size of the file buffer - * \param mode mode of the file to open - * \retval pointer to the file; NULL if something is wrong - */ -FILE *SCFmemopen(void *buf, size_t size, const char *mode) -{ - char temppath[MAX_PATH - 13]; - if (0 == GetTempPath(sizeof(temppath), temppath)) - return NULL; - - char filename[MAX_PATH + 1]; - if (0 == GetTempFileName(temppath, "SC", 0, filename)) - return NULL; - - FILE *f = fopen(filename, "wb"); - if (NULL == f) - return NULL; - - fwrite(buf, size, 1, f); - fclose(f); - - return fopen(filename, mode); -} - -#else - -typedef struct SCFmem_ { - size_t pos; - size_t size; - char *buffer; -} SCFmem; - -/** - * \brief Seek the mem file from offset and whence - * \param handler pointer to the memfile - * \param offset number of bytes to move from whence - * \param whence SEEK_SET, SEEK_CUR, SEEK_END - * \retval pos the position by the last operation, -1 if sizes are out of bounds - */ -static fpos_t SeekFn(void *handler, fpos_t offset, int whence) -{ - size_t pos = 0; - SCFmem *mem = handler; - - switch (whence) { - case SEEK_SET: - if (offset >= 0 && (size_t)offset <= mem->size) { - return mem->pos = offset; - } - break; - case SEEK_CUR: - if (mem->pos + offset <= mem->size) - return mem->pos += offset; - break; - case SEEK_END: - /* must be negative */ - if (mem->size + offset <= mem->size) - return pos = mem->size + offset; - break; - } - - return -1; -} - -/** - * \brief Read from the buffer looking for the available memory limits - * \param handler pointer to the memfile - * \param buf buffer to read from the handler - * \param number of bytes to read - * \retval count , the number of bytes read - */ -static int ReadFn(void *handler, char *buf, int size) -{ - size_t count = 0; - SCFmem *mem = handler; - size_t available = mem->size - mem->pos; - int is_eof = 0; - - if (size < 0) return - 1; - - if ((size_t)size > available) { - size = available; - } else { - is_eof = 1; - } - - while (count < (size_t)size) - buf[count++] = mem->buffer[mem->pos++]; - - if (is_eof == 1) - return 0; - - return count; -} - -/** - * \brief Write into the buffer looking for the available memory limits - * \param handler pointer to the memfile - * \param buf buffer to write in the handler - * \param number of bytes to write - * \retval count , the number of bytes written - */ -static int WriteFn(void *handler, const char *buf, int size) -{ - size_t count = 0; - SCFmem *mem = handler; - size_t available = mem->size - mem->pos; - - if (size < 0) return - 1; - - if ((size_t)size > available) - size = available; - - while (count < (size_t)size) - mem->buffer[mem->pos++] = buf[count++]; - - return count; -} - -/** - * \brief close the mem file handler - * \param handler pointer to the memfile - * \retval 0 on succesful - */ -static int CloseFn(void *handler) -{ - SCFree(handler); - return 0; -} - -/** - * \brief portable version of SCFmemopen for OS X / BSD built on top of funopen() - * \param buffer that holds the file content - * \param size of the file buffer - * \param mode mode of the file to open - * \retval pointer to the file; NULL if something is wrong - */ -FILE *SCFmemopen(void *buf, size_t size, const char *mode) -{ - SCFmem *mem = (SCFmem *)SCCalloc(1, sizeof(SCFmem)); - if (mem == NULL) - return NULL; - - mem->size = size, mem->buffer = buf; - - return funopen(mem, ReadFn, WriteFn, SeekFn, CloseFn); -} - -#endif /* OS_WIN32 */ - -#endif /* USE_FMEM_WRAPPER */ diff --git a/src/util-hash-lookup3.c b/src/util-hash-lookup3.c deleted file mode 100644 index 5d1146152bf2..000000000000 --- a/src/util-hash-lookup3.c +++ /dev/null @@ -1,1175 +0,0 @@ -/* -------------------------------------------------------------------------------- -lookup3.c, by Bob Jenkins, May 2006, Public Domain. - -These are functions for producing 32-bit hashes for hash table lookup. -hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() -are externally useful functions. Routines to test the hash are included -if SELF_TEST is defined. You can use this free for any purpose. It's in -the public domain. It has no warranty. - -You probably want to use hashlittle(). hashlittle() and hashbig() -hash byte arrays. hashlittle() is is faster than hashbig() on -little-endian machines. Intel and AMD are little-endian machines. -On second thought, you probably want hashlittle2(), which is identical to -hashlittle() except it returns two 32-bit hashes for the price of one. -You could implement hashbig2() if you wanted but I haven't bothered here. - -If you want to find a hash of, say, exactly 7 integers, do - a = i1; b = i2; c = i3; - mix(a,b,c); - a += i4; b += i5; c += i6; - mix(a,b,c); - a += i7; - final(a,b,c); -then use c as the hash value. If you have a variable length array of -4-byte integers to hash, use hashword(). If you have a byte array (like -a character string), use hashlittle(). If you have several byte arrays, or -a mix of things, see the comments above hashlittle(). - -Why is this so big? I read 12 bytes at a time into 3 4-byte integers, -then mix those integers. This is fast (you can do a lot more thorough -mixing with 12*3 instructions on 3 integers than you can with 3 instructions -on 1 byte), but shoehorning those bytes into integers efficiently is messy. -------------------------------------------------------------------------------- -*/ -//#define SELF_TEST 1 - -#include /* defines printf for tests */ -#include /* defines time_t for timings in the test */ -#include /* defines uint32_t etc */ -#include /* attempt to define endianness */ -#ifdef linux -# include /* attempt to define endianness */ -#endif -#include "util-hash-lookup3.h" - -/* - * My best guess at if you are big-endian or little-endian. This may - * need adjustment. - */ -#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ - __BYTE_ORDER == __LITTLE_ENDIAN) || \ - (defined(i386) || defined(__i386__) || defined(__i486__) || \ - defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) -# define HASH_LITTLE_ENDIAN 1 -# define HASH_BIG_ENDIAN 0 -#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN) || \ - (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) -# define HASH_LITTLE_ENDIAN 0 -# define HASH_BIG_ENDIAN 1 -#else -# define HASH_LITTLE_ENDIAN 0 -# define HASH_BIG_ENDIAN 0 -#endif - -#define hashsize(n) ((uint32_t)1<<(n)) -#define hashmask(n) (hashsize(n)-1) -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) - -/* -------------------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. - -This is reversible, so any information in (a,b,c) before mix() is -still in (a,b,c) after mix(). - -If four pairs of (a,b,c) inputs are run through mix(), or through -mix() in reverse, there are at least 32 bits of the output that -are sometimes the same for one pair and different for another pair. -This was tested for: -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that -satisfy this are - 4 6 8 16 19 4 - 9 15 3 18 27 15 - 14 9 3 7 17 3 -Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing -for "differ" defined as + with a one-bit base and a two-bit delta. I -used http://burtleburtle.net/bob/hash/avalanche.html to choose -the operations, constants, and arrangements of the variables. - -This does not achieve avalanche. There are input bits of (a,b,c) -that fail to affect some output bits of (a,b,c), especially of a. The -most thoroughly mixed value is c, but it doesn't really even achieve -avalanche in c. - -This allows some parallelism. Read-after-writes are good at doubling -the number of bits affected, so the goal of mixing pulls in the opposite -direction as the goal of parallelism. I did what I could. Rotates -seem to cost as much as shifts on every machine I could lay my hands -on, and rotates are much kinder to the top and bottom bits, so I used -rotates. -------------------------------------------------------------------------------- -*/ -#define mix(a,b,c) \ -{ \ - a -= c; a ^= rot(c, 4); c += b; \ - b -= a; b ^= rot(a, 6); a += c; \ - c -= b; c ^= rot(b, 8); b += a; \ - a -= c; a ^= rot(c,16); c += b; \ - b -= a; b ^= rot(a,19); a += c; \ - c -= b; c ^= rot(b, 4); b += a; \ -} - -/* -------------------------------------------------------------------------------- -final -- final mixing of 3 32-bit values (a,b,c) into c - -Pairs of (a,b,c) values differing in only a few bits will usually -produce values of c that look totally different. This was tested for -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -These constants passed: - 14 11 25 16 4 14 24 - 12 14 25 16 4 14 24 -and these came close: - 4 8 15 26 3 22 24 - 10 8 15 26 3 22 24 - 11 8 15 26 3 22 24 -------------------------------------------------------------------------------- -*/ -#define final(a,b,c) \ -{ \ - c ^= b; c -= rot(b,14); \ - a ^= c; a -= rot(c,11); \ - b ^= a; b -= rot(a,25); \ - c ^= b; c -= rot(b,16); \ - a ^= c; a -= rot(c,4); \ - b ^= a; b -= rot(a,14); \ - c ^= b; c -= rot(b,24); \ -} - -/* --------------------------------------------------------------------- - This works on all machines. To be useful, it requires - -- that the key be an array of uint32_t's, and - -- that the length be the number of uint32_t's in the key - - The function hashword() is identical to hashlittle() on little-endian - machines, and identical to hashbig() on big-endian machines, - except that the length has to be measured in uint32_ts rather than in - bytes. hashlittle() is more complicated than hashword() only because - hashlittle() has to dance around fitting the key bytes into registers. --------------------------------------------------------------------- -*/ -uint32_t hashword( -const uint32_t *k, /* the key, an array of uint32_t values */ -size_t length, /* the length of the key, in uint32_ts */ -uint32_t initval) /* the previous hash, or an arbitrary value */ -{ - uint32_t a,b,c; - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; - - /*------------------------------------------------- handle most of the key */ - while (length > 3) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 3; - k += 3; - } - - /*------------------------------------------- handle the last 3 uint32_t's */ - switch(length) /* all the case statements fall through */ - { - case 3 : c+=k[2]; /* fall through */ - case 2 : b+=k[1]; /* fall through */ - case 1 : a+=k[0]; - final(a,b,c); /* fall through */ - case 0: /* case 0: nothing left to add */ - break; - } - /*------------------------------------------------------ report the result */ - return c; -} - - -/* --------------------------------------------------------------------- -hashword2() -- same as hashword(), but take two seeds and return two -32-bit values. pc and pb must both be nonnull, and *pc and *pb must -both be initialized with seeds. If you pass in (*pb)==0, the output -(*pc) will be the same as the return value from hashword(). --------------------------------------------------------------------- -*/ -void hashword2 ( -const uint32_t *k, /* the key, an array of uint32_t values */ -size_t length, /* the length of the key, in uint32_ts */ -uint32_t *pc, /* IN: seed OUT: primary hash value */ -uint32_t *pb) /* IN: more seed OUT: secondary hash value */ -{ - uint32_t a,b,c; - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc; - c += *pb; - - /*------------------------------------------------- handle most of the key */ - while (length > 3) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 3; - k += 3; - } - - /*------------------------------------------- handle the last 3 uint32_t's */ - switch(length) /* all the case statements fall through */ - { - case 3 : c+=k[2]; /* fall through */ - case 2 : b+=k[1]; /* fall through */ - case 1 : a+=k[0]; - final(a,b,c); /* fall through */ - case 0: /* case 0: nothing left to add */ - break; - } - /*------------------------------------------------------ report the result */ - *pc=c; *pb=b; -} - - -/* -------------------------------------------------------------------------------- -hashlittle() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - length : the length of the key, counting by bytes - initval : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Two keys differing by one or two bits will have -totally different hash values. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (uint8_t **)k, do it like this: - for (i=0, h=0; i 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * "k[2]&0xffffff" actually reads beyond the end of the string, but - * then masks off the part it's not allowed to read. Because the - * string is aligned, the masked-off tail is in the same word as the - * rest of the string. Every machine with memory protection I've seen - * does it on word boundaries, so is OK with this. But VALGRIND will - * still catch it and complain. The masking trick does make the hash - * noticeably faster for short strings (like English words). - */ -#ifndef VALGRIND - - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; - case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; - case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=k[1]&0xffffff; a+=k[0]; break; - case 6 : b+=k[1]&0xffff; a+=k[0]; break; - case 5 : b+=k[1]&0xff; a+=k[0]; break; - case 4 : a+=k[0]; break; - case 3 : a+=k[0]&0xffffff; break; - case 2 : a+=k[0]&0xffff; break; - case 1 : a+=k[0]&0xff; break; - case 0 : return c; /* zero length strings require no mixing */ - } - -#else /* make valgrind happy */ - - const uint8_t *k8 = (const uint8_t *)k; - - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]; break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ - case 1 : a+=k8[0]; break; - case 0 : return c; - } - -#endif /* !valgrind */ - - } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) - { - a += k[0] + (((uint32_t)k[1])<<16); - b += k[2] + (((uint32_t)k[3])<<16); - c += k[4] + (((uint32_t)k[5])<<16); - mix(a,b,c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[4]+(((uint32_t)k[5])<<16); - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=k[4]; - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=k[2]; - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=k[0]; - break; - case 1 : a+=k8[0]; - break; - case 0 : return c; /* zero length requires no mixing */ - } - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; - b += k[4]; - b += ((uint32_t)k[5])<<8; - b += ((uint32_t)k[6])<<16; - b += ((uint32_t)k[7])<<24; - c += k[8]; - c += ((uint32_t)k[9])<<8; - c += ((uint32_t)k[10])<<16; - c += ((uint32_t)k[11])<<24; - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=((uint32_t)k[11])<<24; /* fall through */ - case 11: c+=((uint32_t)k[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k[9])<<8; /* fall through */ - case 9 : c+=k[8]; /* fall through */ - case 8 : b+=((uint32_t)k[7])<<24; /* fall through */ - case 7 : b+=((uint32_t)k[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k[5])<<8; /* fall through */ - case 5 : b+=k[4]; /* fall through */ - case 4 : a+=((uint32_t)k[3])<<24; /* fall through */ - case 3 : a+=((uint32_t)k[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k[1])<<8; /* fall through */ - case 1 : a+=k[0]; - break; - case 0 : return c; - } - } - - final(a,b,c); - return c; -} - - -/* -------------------------------------------------------------------------------- -hashlittle_safe() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - length : the length of the key, counting by bytes - initval : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Two keys differing by one or two bits will have -totally different hash values. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (uint8_t **)k, do it like this: - for (i=0, h=0; i 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * Note that unlike hashlittle() above, we use the "safe" version of this - * block that is #ifdef VALGRIND above, in order to avoid warnings from - * Valgrind or Address Sanitizer. - */ - - const uint8_t *k8 = (const uint8_t *)k; - - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]; break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ - case 1 : a+=k8[0]; break; - case 0 : return c; - } - } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) - { - a += k[0] + (((uint32_t)k[1])<<16); - b += k[2] + (((uint32_t)k[3])<<16); - c += k[4] + (((uint32_t)k[5])<<16); - mix(a,b,c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[4]+(((uint32_t)k[5])<<16); - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=k[4]; - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=k[2]; - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=k[0]; - break; - case 1 : a+=k8[0]; - break; - case 0 : return c; /* zero length requires no mixing */ - } - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; - b += k[4]; - b += ((uint32_t)k[5])<<8; - b += ((uint32_t)k[6])<<16; - b += ((uint32_t)k[7])<<24; - c += k[8]; - c += ((uint32_t)k[9])<<8; - c += ((uint32_t)k[10])<<16; - c += ((uint32_t)k[11])<<24; - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=((uint32_t)k[11])<<24; /* fall through */ - case 11: c+=((uint32_t)k[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k[9])<<8; /* fall through */ - case 9 : c+=k[8]; /* fall through */ - case 8 : b+=((uint32_t)k[7])<<24; /* fall through */ - case 7 : b+=((uint32_t)k[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k[5])<<8; /* fall through */ - case 5 : b+=k[4]; /* fall through */ - case 4 : a+=((uint32_t)k[3])<<24; /* fall through */ - case 3 : a+=((uint32_t)k[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k[1])<<8; /* fall through */ - case 1 : a+=k[0]; - break; - case 0 : return c; - } - } - - final(a,b,c); - return c; -} - - -/* - * hashlittle2: return 2 32-bit hash values - * - * This is identical to hashlittle(), except it returns two 32-bit hash - * values instead of just one. This is good enough for hash table - * lookup with 2^^64 buckets, or if you want a second hash if you're not - * happy with the first, or if you want a probably-unique 64-bit ID for - * the key. *pc is better mixed than *pb, so use *pc first. If you want - * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". - */ -void hashlittle2( - const void *key, /* the key to hash */ - size_t length, /* length of the key */ - uint32_t *pc, /* IN: primary initval, OUT: primary hash */ - uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ -{ - uint32_t a,b,c; /* internal state */ - union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc; - c += *pb; - - u.ptr = key; - if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { - const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ - - /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * "k[2]&0xffffff" actually reads beyond the end of the string, but - * then masks off the part it's not allowed to read. Because the - * string is aligned, the masked-off tail is in the same word as the - * rest of the string. Every machine with memory protection I've seen - * does it on word boundaries, so is OK with this. But VALGRIND will - * still catch it and complain. The masking trick does make the hash - * noticeably faster for short strings (like English words). - */ -#ifndef VALGRIND - - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; - case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; - case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=k[1]&0xffffff; a+=k[0]; break; - case 6 : b+=k[1]&0xffff; a+=k[0]; break; - case 5 : b+=k[1]&0xff; a+=k[0]; break; - case 4 : a+=k[0]; break; - case 3 : a+=k[0]&0xffffff; break; - case 2 : a+=k[0]&0xffff; break; - case 1 : a+=k[0]&0xff; break; - case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ - } - -#else /* make valgrind happy */ - - const uint8_t *k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]; break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ - case 1 : a+=k8[0]; break; - case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ - } - -#endif /* !valgrind */ - - } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) - { - a += k[0] + (((uint32_t)k[1])<<16); - b += k[2] + (((uint32_t)k[3])<<16); - c += k[4] + (((uint32_t)k[5])<<16); - mix(a,b,c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[4]+(((uint32_t)k[5])<<16); - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=k[4]; - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=k[2]; - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=k[0]; - break; - case 1 : a+=k8[0]; - break; - case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ - } - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; - b += k[4]; - b += ((uint32_t)k[5])<<8; - b += ((uint32_t)k[6])<<16; - b += ((uint32_t)k[7])<<24; - c += k[8]; - c += ((uint32_t)k[9])<<8; - c += ((uint32_t)k[10])<<16; - c += ((uint32_t)k[11])<<24; - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=((uint32_t)k[11])<<24; /* fall through */ - case 11: c+=((uint32_t)k[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k[9])<<8; /* fall through */ - case 9 : c+=k[8]; /* fall through */ - case 8 : b+=((uint32_t)k[7])<<24; /* fall through */ - case 7 : b+=((uint32_t)k[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k[5])<<8; /* fall through */ - case 5 : b+=k[4]; /* fall through */ - case 4 : a+=((uint32_t)k[3])<<24; /* fall through */ - case 3 : a+=((uint32_t)k[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k[1])<<8; /* fall through */ - case 1 : a+=k[0]; - break; - case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ - } - } - - final(a,b,c); - *pc=c; *pb=b; -} - - - -/* - * hashbig(): - * This is the same as hashword() on big-endian machines. It is different - * from hashlittle() on all machines. hashbig() takes advantage of - * big-endian byte ordering. - */ -uint32_t hashbig( const void *key, size_t length, uint32_t initval) -{ - uint32_t a,b,c; - union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; - - u.ptr = key; - if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { - const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ - - /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * "k[2]<<8" actually reads beyond the end of the string, but - * then shifts out the part it's not allowed to read. Because the - * string is aligned, the illegal read is in the same word as the - * rest of the string. Every machine with memory protection I've seen - * does it on word boundaries, so is OK with this. But VALGRIND will - * still catch it and complain. The masking trick does make the hash - * noticeably faster for short strings (like English words). - */ -#ifndef VALGRIND - - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; - case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; - case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; - case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; - case 5 : b+=k[1]&0xff000000; a+=k[0]; break; - case 4 : a+=k[0]; break; - case 3 : a+=k[0]&0xffffff00; break; - case 2 : a+=k[0]&0xffff0000; break; - case 1 : a+=k[0]&0xff000000; break; - case 0 : return c; /* zero length strings require no mixing */ - } - -#else /* make valgrind happy */ - - const uint8_t *k8 = (const uint8_t *)k; - switch(length) /* all the case statements fall through */ - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ - case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ - case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ - case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ - case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ - case 4 : a+=k[0]; break; - case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ - case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ - case 1 : a+=((uint32_t)k8[0])<<24; break; - case 0 : return c; - } - -#endif /* !VALGRIND */ - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += ((uint32_t)k[0])<<24; - a += ((uint32_t)k[1])<<16; - a += ((uint32_t)k[2])<<8; - a += ((uint32_t)k[3]); - b += ((uint32_t)k[4])<<24; - b += ((uint32_t)k[5])<<16; - b += ((uint32_t)k[6])<<8; - b += ((uint32_t)k[7]); - c += ((uint32_t)k[8])<<24; - c += ((uint32_t)k[9])<<16; - c += ((uint32_t)k[10])<<8; - c += ((uint32_t)k[11]); - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=k[11]; /* fall through */ - case 11: c+=((uint32_t)k[10])<<8; /* fall through */ - case 10: c+=((uint32_t)k[9])<<16; /* fall through */ - case 9 : c+=((uint32_t)k[8])<<24; /* fall through */ - case 8 : b+=k[7]; /* fall through */ - case 7 : b+=((uint32_t)k[6])<<8; /* fall through */ - case 6 : b+=((uint32_t)k[5])<<16; /* fall through */ - case 5 : b+=((uint32_t)k[4])<<24; /* fall through */ - case 4 : a+=k[3]; /* fall through */ - case 3 : a+=((uint32_t)k[2])<<8; /* fall through */ - case 2 : a+=((uint32_t)k[1])<<16; /* fall through */ - case 1 : a+=((uint32_t)k[0])<<24; - break; - case 0 : return c; - } - } - - final(a,b,c); - return c; -} - - -#ifdef SELF_TEST - -/* used for timings */ -void driver1(void) -{ - uint8_t buf[256]; - uint32_t i; - uint32_t h=0; - time_t a,z; - - time(&a); - for (i=0; i<256; ++i) buf[i] = 'x'; - for (i=0; i<1; ++i) - { - h = hashlittle(&buf[0],1,h); - } - time(&z); - if (z-a > 0) printf("time %d %.8x\n", z-a, h); -} - -/* check that every input bit changes every output bit half the time */ -#define HASHSTATE 1 -#define HASHLEN 1 -#define MAXPAIR 60 -#define MAXLEN 70 -void driver2(void) -{ - uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; - uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; - uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; - uint32_t x[HASHSTATE],y[HASHSTATE]; - uint32_t hlen; - - printf("No more than %d trials should ever be needed \n",MAXPAIR/2); - for (hlen=0; hlen < MAXLEN; ++hlen) - { - z=0; - for (i=0; i> (8 - j)); - c[0] = hashlittle(a, hlen, m); - b[i] ^= ((k + 1) << j); - b[i] ^= ((k + 1) >> (8 - j)); - d[0] = hashlittle(b, hlen, m); - /* check every bit is 1, 0, set, and not set at least once */ - for (l = 0; l < HASHSTATE; ++l) { - e[l] &= (c[l] ^ d[l]); - f[l] &= ~(c[l] ^ d[l]); - g[l] &= c[l]; - h[l] &= ~c[l]; - x[l] &= d[l]; - y[l] &= ~d[l]; - if (e[l] | f[l] | g[l] | h[l] | x[l] | y[l]) - finished = 0; - } - if (finished) - break; - } - if (k > z) - z = k; - if (k == MAXPAIR) { - printf("Some bit didn't change: "); - printf("%.8x %.8x %.8x %.8x %.8x %.8x ", e[0], f[0], g[0], h[0], x[0], y[0]); - printf("i %d j %d m %d len %d\n", i, j, m, hlen); - } - if (z == MAXPAIR) - goto done; - } - } - } - done: - if (z < MAXPAIR) - { - printf("Mix success %2d bytes %2d initvals ",i,m); - printf("required %d trials\n", z/2); - } - } - printf("\n"); -} - -/* Check for reading beyond the end of the buffer and alignment problems */ -void driver3(void) -{ - uint8_t buf[MAXLEN+20], *b; - uint32_t len; - uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; - uint32_t h; - uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; - uint32_t i; - uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; - uint32_t j; - uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; - uint32_t ref,x,y; - uint8_t *p; - - printf("Endianness. These lines should all be the same (for values filled in):\n"); - printf("%.8x %.8x %.8x\n", - hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13), - hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13), - hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13)); - p = q; - printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", - hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), - hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), - hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), - hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), - hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), - hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); - p = &qq[1]; - printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", - hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), - hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), - hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), - hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), - hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), - hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); - p = &qqq[2]; - printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", - hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), - hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), - hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), - hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), - hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), - hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); - p = &qqqq[3]; - printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", - hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), - hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), - hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), - hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), - hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), - hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); - printf("\n"); - - /* check that hashlittle2 and hashlittle produce the same results */ - i=47; j=0; - hashlittle2(q, sizeof(q), &i, &j); - if (hashlittle(q, sizeof(q), 47) != i) - printf("hashlittle2 and hashlittle mismatch\n"); - - /* check that hashword2 and hashword produce the same results */ - len = 0xdeadbeef; - i=47, j=0; - hashword2(&len, 1, &i, &j); - if (hashword(&len, 1, 47) != i) - printf("hashword2 and hashword mismatch %x %x\n", - i, hashword(&len, 1, 47)); - - /* check hashlittle doesn't read before or after the ends of the string */ - for (h=0, b=buf+1; h<8; ++h, ++b) - { - for (i=0; iarray_size; -} - -char StringHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2) -{ - int len1 = strlen((char *)data1); - int len2 = strlen((char *)data2); - - if (len1 == len2 && memcmp(data1, data2, len1) == 0) { - return 1; - } - - return 0; -} - -void StringHashFreeFunc(void *data) -{ - SCFree(data); -} diff --git a/src/util-hash-string.h b/src/util-hash-string.h deleted file mode 100644 index 7153af800d3b..000000000000 --- a/src/util-hash-string.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __UTIL_HASH_STRING_H__ -#define __UTIL_HASH_STRING_H__ - -#include "util-hash.h" - -uint32_t StringHashDjb2(const uint8_t *data, uint32_t datalen); -uint32_t StringHashFunc(HashTable *ht, void *data, uint16_t datalen); -char StringHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2); -void StringHashFreeFunc(void *data); - -#endif /* __UTIL_HASH_STRING_H__ */ diff --git a/src/util-hash.c b/src/util-hash.c deleted file mode 100644 index 412a46fa7eb9..000000000000 --- a/src/util-hash.c +++ /dev/null @@ -1,442 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Chained hash table implementation - * - * The 'Free' pointer can be used to have the API free your - * hashed data. If it's NULL it's the callers responsibility - */ - -#include "suricata-common.h" -#include "util-hash.h" -#include "util-unittest.h" -#include "util-memcmp.h" -#include "util-debug.h" - -HashTable* HashTableInit(uint32_t size, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)) { - - HashTable *ht = NULL; - - if (size == 0) { - goto error; - } - - if (Hash == NULL) { - //printf("ERROR: HashTableInit no Hash function\n"); - goto error; - } - - /* setup the filter */ - ht = SCCalloc(1, sizeof(HashTable)); - if (unlikely(ht == NULL)) - goto error; - ht->array_size = size; - ht->Hash = Hash; - ht->Free = Free; - - if (Compare != NULL) - ht->Compare = Compare; - else - ht->Compare = HashTableDefaultCompare; - - /* setup the bitarray */ - ht->array = SCCalloc(ht->array_size, sizeof(HashTableBucket *)); - if (ht->array == NULL) - goto error; - - return ht; - -error: - if (ht != NULL) { - if (ht->array != NULL) - SCFree(ht->array); - - SCFree(ht); - } - return NULL; -} - -void HashTableFree(HashTable *ht) -{ - uint32_t i = 0; - - if (ht == NULL) - return; - - /* free the buckets */ - for (i = 0; i < ht->array_size; i++) { - HashTableBucket *hashbucket = ht->array[i]; - while (hashbucket != NULL) { - HashTableBucket *next_hashbucket = hashbucket->next; - if (ht->Free != NULL) - ht->Free(hashbucket->data); - SCFree(hashbucket); - hashbucket = next_hashbucket; - } - } - - /* free the array */ - if (ht->array != NULL) - SCFree(ht->array); - - SCFree(ht); -} - -void HashTablePrint(HashTable *ht) -{ - printf("\n----------- Hash Table Stats ------------\n"); - printf("Buckets: %" PRIu32 "\n", ht->array_size); - printf("Hash function pointer: %p\n", ht->Hash); - printf("-----------------------------------------\n"); -} - -int HashTableAdd(HashTable *ht, void *data, uint16_t datalen) -{ - if (ht == NULL || data == NULL) - return -1; - - uint32_t hash = ht->Hash(ht, data, datalen); - - HashTableBucket *hb = SCCalloc(1, sizeof(HashTableBucket)); - if (unlikely(hb == NULL)) - goto error; - hb->data = data; - hb->size = datalen; - hb->next = NULL; - - if (hash >= ht->array_size) { - SCLogWarning("attempt to insert element out of hash array\n"); - goto error; - } - - if (ht->array[hash] == NULL) { - ht->array[hash] = hb; - } else { - hb->next = ht->array[hash]; - ht->array[hash] = hb; - } - -#ifdef UNITTESTS - ht->count++; -#endif - - return 0; - -error: - if (hb != NULL) - SCFree(hb); - return -1; -} - -int HashTableRemove(HashTable *ht, void *data, uint16_t datalen) -{ - uint32_t hash = ht->Hash(ht, data, datalen); - - if (ht->array[hash] == NULL) { - return -1; - } - - if (ht->array[hash]->next == NULL) { - if (ht->Free != NULL) - ht->Free(ht->array[hash]->data); - SCFree(ht->array[hash]); - ht->array[hash] = NULL; - return 0; - } - - HashTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL; - do { - if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) { - if (prev_hashbucket == NULL) { - /* root bucket */ - ht->array[hash] = hashbucket->next; - } else { - /* child bucket */ - prev_hashbucket->next = hashbucket->next; - } - - /* remove this */ - if (ht->Free != NULL) - ht->Free(hashbucket->data); - SCFree(hashbucket); - return 0; - } - - prev_hashbucket = hashbucket; - hashbucket = hashbucket->next; - } while (hashbucket != NULL); - - return -1; -} - -void *HashTableLookup(HashTable *ht, void *data, uint16_t datalen) -{ - uint32_t hash = 0; - - if (ht == NULL) - return NULL; - - hash = ht->Hash(ht, data, datalen); - - if (hash >= ht->array_size) { - SCLogWarning("attempt to access element out of hash array\n"); - return NULL; - } - - if (ht->array[hash] == NULL) - return NULL; - - HashTableBucket *hashbucket = ht->array[hash]; - do { - if (ht->Compare(hashbucket->data, hashbucket->size, data, datalen) == 1) - return hashbucket->data; - - hashbucket = hashbucket->next; - } while (hashbucket != NULL); - - return NULL; -} - -uint32_t HashTableGenericHash(HashTable *ht, void *data, uint16_t datalen) -{ - uint8_t *d = (uint8_t *)data; - uint32_t i; - uint32_t hash = 0; - - for (i = 0; i < datalen; i++) { - if (i == 0) hash += (((uint32_t)*d++)); - else if (i == 1) hash += (((uint32_t)*d++) * datalen); - else hash *= (((uint32_t)*d++) * i) + datalen + i; - } - - hash *= datalen; - hash %= ht->array_size; - return hash; -} - -char HashTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2) -{ - if (len1 != len2) - return 0; - - if (SCMemcmp(data1,data2,len1) != 0) - return 0; - - return 1; -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -static int HashTableTestInit01 (void) -{ - HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - return 0; - - HashTableFree(ht); - return 1; -} - -/* no hash function, so it should fail */ -static int HashTableTestInit02 (void) -{ - HashTable *ht = HashTableInit(1024, NULL, NULL, NULL); - if (ht == NULL) - return 1; - - HashTableFree(ht); - return 0; -} - -static int HashTableTestInit03 (void) -{ - int result = 0; - HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - return 0; - - if (ht->Hash == HashTableGenericHash) - result = 1; - - HashTableFree(ht); - return result; -} - -static int HashTableTestInit04 (void) -{ - HashTable *ht = HashTableInit(0, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - return 1; - - HashTableFree(ht); - return 0; -} - -static int HashTableTestInit05 (void) -{ - int result = 0; - HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - return 0; - - if (ht->Compare == HashTableDefaultCompare) - result = 1; - - HashTableFree(ht); - return result; -} - -static char HashTableDefaultCompareTest(void *data1, uint16_t len1, void *data2, uint16_t len2) -{ - if (len1 != len2) - return 0; - - if (SCMemcmp(data1,data2,len1) != 0) - return 0; - - return 1; -} - -static int HashTableTestInit06 (void) -{ - int result = 0; - HashTable *ht = HashTableInit(1024, HashTableGenericHash, HashTableDefaultCompareTest, NULL); - if (ht == NULL) - return 0; - - if (ht->Compare == HashTableDefaultCompareTest) - result = 1; - - HashTableFree(ht); - return result; -} - -static int HashTableTestAdd01 (void) -{ - int result = 0; - HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashTableAdd(ht, (char *)"test", 0); - if (r != 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashTableFree(ht); - return result; -} - -static int HashTableTestAdd02 (void) -{ - int result = 0; - HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashTableAdd(ht, NULL, 4); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashTableFree(ht); - return result; -} - -static int HashTableTestFull01 (void) -{ - int result = 0; - HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashTableAdd(ht, (char *)"test", 4); - if (r != 0) - goto end; - - char *rp = HashTableLookup(ht, (char *)"test", 4); - if (rp == NULL) - goto end; - - r = HashTableRemove(ht, (char *)"test", 4); - if (r != 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashTableFree(ht); - return result; -} - -static int HashTableTestFull02 (void) -{ - int result = 0; - HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashTableAdd(ht, (char *)"test", 4); - if (r != 0) - goto end; - - char *rp = HashTableLookup(ht, (char *)"test", 4); - if (rp == NULL) - goto end; - - r = HashTableRemove(ht, (char *)"test2", 5); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashTableFree(ht); - return result; -} -#endif - -void HashTableRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("HashTableTestInit01", HashTableTestInit01); - UtRegisterTest("HashTableTestInit02", HashTableTestInit02); - UtRegisterTest("HashTableTestInit03", HashTableTestInit03); - UtRegisterTest("HashTableTestInit04", HashTableTestInit04); - UtRegisterTest("HashTableTestInit05", HashTableTestInit05); - UtRegisterTest("HashTableTestInit06", HashTableTestInit06); - - UtRegisterTest("HashTableTestAdd01", HashTableTestAdd01); - UtRegisterTest("HashTableTestAdd02", HashTableTestAdd02); - - UtRegisterTest("HashTableTestFull01", HashTableTestFull01); - UtRegisterTest("HashTableTestFull02", HashTableTestFull02); -#endif -} - diff --git a/src/util-hash.h b/src/util-hash.h deleted file mode 100644 index f16111887431..000000000000 --- a/src/util-hash.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __HASH_H__ -#define __HASH_H__ - -/* hash bucket structure */ -typedef struct HashTableBucket_ { - void *data; - uint16_t size; - struct HashTableBucket_ *next; -} HashTableBucket; - -/* hash table structure */ -typedef struct HashTable_ { - HashTableBucket **array; - uint32_t array_size; -#ifdef UNITTESTS - uint32_t count; -#endif - uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t); - char (*Compare)(void *, uint16_t, void *, uint16_t); - void (*Free)(void *); -} HashTable; - -#define HASH_NO_SIZE 0 - -/* prototypes */ -HashTable* HashTableInit(uint32_t, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)); -void HashTableFree(HashTable *); -void HashTablePrint(HashTable *); -int HashTableAdd(HashTable *, void *, uint16_t); -int HashTableRemove(HashTable *, void *, uint16_t); -void *HashTableLookup(HashTable *, void *, uint16_t); -uint32_t HashTableGenericHash(HashTable *, void *, uint16_t); -char HashTableDefaultCompare(void *, uint16_t, void *, uint16_t); - -void HashTableRegisterTests(void); - -#endif /* __HASH_H__ */ - diff --git a/src/util-hashlist.c b/src/util-hashlist.c deleted file mode 100644 index e4b62a613d6e..000000000000 --- a/src/util-hashlist.c +++ /dev/null @@ -1,523 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Chained hash table implementation - * - * The 'Free' pointer can be used to have the API free your - * hashed data. If it's NULL it's the callers responsibility - */ - -#include "suricata-common.h" -#include "util-hashlist.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-memcmp.h" - -HashListTable *HashListTableInit(uint32_t size, - uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t), - char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)) -{ - sc_errno = SC_OK; - HashListTable *ht = NULL; - - if (size == 0) { - sc_errno = SC_EINVAL; - goto error; - } - - if (Hash == NULL) { - sc_errno = SC_EINVAL; - goto error; - } - - /* setup the filter */ - ht = SCCalloc(1, sizeof(HashListTable)); - if (unlikely(ht == NULL)) { - sc_errno = SC_ENOMEM; - goto error; - } - ht->array_size = size; - ht->Hash = Hash; - ht->Free = Free; - - if (Compare != NULL) - ht->Compare = Compare; - else - ht->Compare = HashListTableDefaultCompare; - - /* setup the bitarray */ - ht->array = SCCalloc(ht->array_size, sizeof(HashListTableBucket *)); - if (ht->array == NULL) { - sc_errno = SC_ENOMEM; - goto error; - } - - ht->listhead = NULL; - ht->listtail = NULL; - return ht; - -error: - if (ht != NULL) { - if (ht->array != NULL) - SCFree(ht->array); - - SCFree(ht); - } - return NULL; -} - -void HashListTableFree(HashListTable *ht) -{ - uint32_t i = 0; - - if (ht == NULL) - return; - - /* free the buckets */ - for (i = 0; i < ht->array_size; i++) { - HashListTableBucket *hashbucket = ht->array[i]; - while (hashbucket != NULL) { - HashListTableBucket *next_hashbucket = hashbucket->bucknext; - if (ht->Free != NULL) - ht->Free(hashbucket->data); - SCFree(hashbucket); - hashbucket = next_hashbucket; - } - } - - /* free the array */ - if (ht->array != NULL) - SCFree(ht->array); - - SCFree(ht); -} - -void HashListTablePrint(HashListTable *ht) -{ - printf("\n----------- Hash Table Stats ------------\n"); - printf("Buckets: %" PRIu32 "\n", ht->array_size); - printf("Hash function pointer: %p\n", ht->Hash); - printf("-----------------------------------------\n"); -} - -int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen) -{ - if (ht == NULL || data == NULL) - return -1; - - uint32_t hash = ht->Hash(ht, data, datalen); - - SCLogDebug("ht %p hash %"PRIu32"", ht, hash); - - HashListTableBucket *hb = SCCalloc(1, sizeof(HashListTableBucket)); - if (unlikely(hb == NULL)) - goto error; - hb->data = data; - hb->size = datalen; - hb->bucknext = NULL; - hb->listnext = NULL; - hb->listprev = NULL; - - if (ht->array[hash] == NULL) { - ht->array[hash] = hb; - } else { - hb->bucknext = ht->array[hash]; - ht->array[hash] = hb; - } - - if (ht->listtail == NULL) { - ht->listhead = hb; - ht->listtail = hb; - } else { - hb->listprev = ht->listtail; - ht->listtail->listnext = hb; - ht->listtail = hb; - } - - return 0; - -error: - return -1; -} - -int HashListTableRemove(HashListTable *ht, void *data, uint16_t datalen) -{ - uint32_t hash = ht->Hash(ht, data, datalen); - - SCLogDebug("ht %p hash %"PRIu32"", ht, hash); - - if (ht->array[hash] == NULL) { - SCLogDebug("ht->array[hash] NULL"); - return -1; - } - - /* fast track for just one data part */ - if (ht->array[hash]->bucknext == NULL) { - HashListTableBucket *hb = ht->array[hash]; - - if (ht->Compare(hb->data,hb->size,data,datalen) == 1) { - /* remove from the list */ - if (hb->listprev == NULL) { - ht->listhead = hb->listnext; - } else { - hb->listprev->listnext = hb->listnext; - } - if (hb->listnext == NULL) { - ht->listtail = hb->listprev; - } else { - hb->listnext->listprev = hb->listprev; - } - - if (ht->Free != NULL) - ht->Free(hb->data); - - SCFree(ht->array[hash]); - ht->array[hash] = NULL; - return 0; - } - - SCLogDebug("fast track default case"); - return -1; - } - - /* more data in this bucket */ - HashListTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL; - do { - if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) { - - /* remove from the list */ - if (hashbucket->listprev == NULL) { - ht->listhead = hashbucket->listnext; - } else { - hashbucket->listprev->listnext = hashbucket->listnext; - } - if (hashbucket->listnext == NULL) { - ht->listtail = hashbucket->listprev; - } else { - hashbucket->listnext->listprev = hashbucket->listprev; - } - - if (prev_hashbucket == NULL) { - /* root bucket */ - ht->array[hash] = hashbucket->bucknext; - } else { - /* child bucket */ - prev_hashbucket->bucknext = hashbucket->bucknext; - } - - /* remove this */ - if (ht->Free != NULL) - ht->Free(hashbucket->data); - SCFree(hashbucket); - return 0; - } - - prev_hashbucket = hashbucket; - hashbucket = hashbucket->bucknext; - } while (hashbucket != NULL); - - SCLogDebug("slow track default case"); - return -1; -} - -char HashListTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2) -{ - if (len1 != len2) - return 0; - - if (SCMemcmp(data1,data2,len1) != 0) - return 0; - - return 1; -} - -void *HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen) -{ - - if (ht == NULL) { - SCLogDebug("Hash List table is NULL"); - return NULL; - } - - uint32_t hash = ht->Hash(ht, data, datalen); - - if (ht->array[hash] == NULL) { - return NULL; - } - - HashListTableBucket *hashbucket = ht->array[hash]; - do { - if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) - return hashbucket->data; - - hashbucket = hashbucket->bucknext; - } while (hashbucket != NULL); - - return NULL; -} - -uint32_t HashListTableGenericHash(HashListTable *ht, void *data, uint16_t datalen) -{ - uint8_t *d = (uint8_t *)data; - uint32_t i; - uint32_t hash = 0; - - for (i = 0; i < datalen; i++) { - if (i == 0) hash += (((uint32_t)*d++)); - else if (i == 1) hash += (((uint32_t)*d++) * datalen); - else hash *= (((uint32_t)*d++) * i) + datalen + i; - } - - hash *= datalen; - hash %= ht->array_size; - return hash; -} - -HashListTableBucket *HashListTableGetListHead(HashListTable *ht) -{ - return ht->listhead; -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -static int HashListTableTestInit01 (void) -{ - HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - return 0; - - HashListTableFree(ht); - return 1; -} - -/* no hash function, so it should fail */ -static int HashListTableTestInit02 (void) -{ - HashListTable *ht = HashListTableInit(1024, NULL, NULL, NULL); - if (ht == NULL) - return 1; - - HashListTableFree(ht); - return 0; -} - -static int HashListTableTestInit03 (void) -{ - int result = 0; - HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - return 0; - - if (ht->Hash == HashListTableGenericHash) - result = 1; - - HashListTableFree(ht); - return result; -} - -static int HashListTableTestInit04 (void) -{ - HashListTable *ht = HashListTableInit(0, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - return 1; - - HashListTableFree(ht); - return 0; -} - -static int HashListTableTestAdd01 (void) -{ - int result = 0; - HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashListTableAdd(ht, (char *)"test", 0); - if (r != 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashListTableFree(ht); - return result; -} - -static int HashListTableTestAdd02 (void) -{ - int result = 0; - HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashListTableAdd(ht, NULL, 4); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashListTableFree(ht); - return result; -} - -static int HashListTableTestAdd03 (void) -{ - int result = 0; - HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashListTableAdd(ht, (char *)"test", 0); - if (r != 0) - goto end; - - if (ht->listhead == NULL) { - printf("ht->listhead == NULL: "); - goto end; - } - - if (ht->listtail == NULL) { - printf("ht->listtail == NULL: "); - goto end; - } - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashListTableFree(ht); - return result; -} - -static int HashListTableTestAdd04 (void) -{ - int result = 0; - HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashListTableAdd(ht, (char *)"test", 4); - if (r != 0) - goto end; - - char *rp = HashListTableLookup(ht, (char *)"test", 4); - if (rp == NULL) - goto end; - - HashListTableBucket *htb = HashListTableGetListHead(ht); - if (htb == NULL) { - printf("htb == NULL: "); - goto end; - } - - char *rp2 = HashListTableGetListData(htb); - if (rp2 == NULL) { - printf("rp2 == NULL: "); - goto end; - } - - if (rp != rp2) { - printf("rp != rp2: "); - goto end; - } - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashListTableFree(ht); - return result; -} - -static int HashListTableTestFull01 (void) -{ - int result = 0; - HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashListTableAdd(ht, (char *)"test", 4); - if (r != 0) - goto end; - - char *rp = HashListTableLookup(ht, (char *)"test", 4); - if (rp == NULL) - goto end; - - r = HashListTableRemove(ht, (char *)"test", 4); - if (r != 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashListTableFree(ht); - return result; -} - -static int HashListTableTestFull02 (void) -{ - int result = 0; - HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); - if (ht == NULL) - goto end; - - int r = HashListTableAdd(ht, (char *)"test", 4); - if (r != 0) - goto end; - - char *rp = HashListTableLookup(ht, (char *)"test", 4); - if (rp == NULL) - goto end; - - r = HashListTableRemove(ht, (char *)"test2", 5); - if (r == 0) - goto end; - - /* all is good! */ - result = 1; -end: - if (ht != NULL) HashListTableFree(ht); - return result; -} -#endif /* UNITTESTS */ - -void HashListTableRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01); - UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02); - UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03); - UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04); - - UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01); - UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02); - UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03); - UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04); - - UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01); - UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02); -#endif /* UNITTESTS */ -} - diff --git a/src/util-hashlist.h b/src/util-hashlist.h deleted file mode 100644 index bca74c98719b..000000000000 --- a/src/util-hashlist.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __HASHLIST_H__ -#define __HASHLIST_H__ - -/* hash bucket structure */ -typedef struct HashListTableBucket_ { - void *data; - uint16_t size; - struct HashListTableBucket_ *bucknext; - struct HashListTableBucket_ *listnext; - struct HashListTableBucket_ *listprev; -} HashListTableBucket; - -/* hash table structure */ -typedef struct HashListTable_ { - HashListTableBucket **array; - HashListTableBucket *listhead; - HashListTableBucket *listtail; - uint32_t array_size; - uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t); - char (*Compare)(void *, uint16_t, void *, uint16_t); - void (*Free)(void *); -} HashListTable; - -/* prototypes */ -HashListTable* HashListTableInit(uint32_t, uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)); -void HashListTableFree(HashListTable *); -void HashListTablePrint(HashListTable *); -int HashListTableAdd(HashListTable *, void *, uint16_t); -int HashListTableRemove(HashListTable *, void *, uint16_t); -void *HashListTableLookup(HashListTable *, void *, uint16_t); -uint32_t HashListTableGenericHash(HashListTable *, void *, uint16_t); -HashListTableBucket *HashListTableGetListHead(HashListTable *); -#define HashListTableGetListNext(hb) (hb)->listnext -#define HashListTableGetListData(hb) (hb)->data -char HashListTableDefaultCompare(void *, uint16_t, void *, uint16_t); - -void HashListTableRegisterTests(void); - -#endif /* __HASHLIST_H__ */ - diff --git a/src/util-host-info.c b/src/util-host-info.c deleted file mode 100644 index c0dd93b80cfc..000000000000 --- a/src/util-host-info.c +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * - * Get information on running host - * - */ - -#include "suricata-common.h" -#include "util-host-info.h" -#include "util-byte.h" -#include "util-debug.h" - -#ifndef OS_WIN32 -#include - -#define VERSION_REGEX "^([0-9]+)\\.([0-9]+)" - -int SCKernelVersionIsAtLeast(int major, int minor) -{ - struct utsname kuname; - pcre2_code *version_regex; - pcre2_match_data *version_regex_match; - int en; - int opts = 0; - PCRE2_SIZE eo; - int ret; - int kmajor, kminor; - PCRE2_UCHAR **list; - - /* get local version */ - if (uname(&kuname) != 0) { - SCLogError("Invalid uname return: %s", strerror(errno)); - return 0; - } - - SCLogDebug("Kernel release is '%s'", kuname.release); - - version_regex = - pcre2_compile((PCRE2_SPTR8)VERSION_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); - if (version_regex == NULL) { - PCRE2_UCHAR errbuffer[256]; - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - SCLogError("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - VERSION_REGEX, (int)eo, errbuffer); - goto error; - } - version_regex_match = pcre2_match_data_create_from_pattern(version_regex, NULL); - - ret = pcre2_match(version_regex, (PCRE2_SPTR8)kuname.release, strlen(kuname.release), 0, 0, - version_regex_match, NULL); - - if (ret < 0) { - SCLogError("Version did not cut"); - goto error; - } - - if (ret < 3) { - SCLogError("Version major and minor not found (ret %d)", ret); - goto error; - } - - pcre2_substring_list_get(version_regex_match, &list, NULL); - - bool err = false; - if (StringParseInt32(&kmajor, 10, 0, (const char *)list[1]) < 0) { - SCLogError("Invalid value for kmajor: '%s'", list[1]); - err = true; - } - if (StringParseInt32(&kminor, 10, 0, (const char *)list[2]) < 0) { - SCLogError("Invalid value for kminor: '%s'", list[2]); - err = true; - } - - pcre2_substring_list_free((PCRE2_SPTR *)list); - pcre2_match_data_free(version_regex_match); - pcre2_code_free(version_regex); - - if (err) - goto error; - - if (kmajor > major) - return 1; - if (kmajor == major && kminor >= minor) - return 1; -error: - return 0; -} - -#else /* OS_WIN32 */ - -int SCKernelVersionIsAtLeast(int major, int minor) -{ - SCLogError("OS compare is not supported on Windows"); - return 0; -} - -#endif /* OS_WIN32 */ diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c deleted file mode 100644 index 02b3ee72a263..000000000000 --- a/src/util-host-os-info.c +++ /dev/null @@ -1,1641 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Host info utility functions - */ - -#include "suricata-common.h" -#include "util-host-os-info.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-ip.h" -#include "util-radix-tree.h" -#include "util-byte.h" -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" - -#include "conf.h" -#include "conf-yaml-loader.h" - -#include "util-enum.h" -#include "util-unittest.h" - -/** Enum map for the various OS flavours */ -SCEnumCharMap sc_hinfo_os_policy_map[ ] = { - { "none", OS_POLICY_NONE }, - { "bsd", OS_POLICY_BSD }, - { "bsd-right", OS_POLICY_BSD_RIGHT }, - { "old-linux", OS_POLICY_OLD_LINUX }, - { "linux", OS_POLICY_LINUX }, - { "old-solaris", OS_POLICY_OLD_SOLARIS }, - { "solaris", OS_POLICY_SOLARIS }, - { "hpux10", OS_POLICY_HPUX10 }, - { "hpux11", OS_POLICY_HPUX11 }, - { "irix", OS_POLICY_IRIX }, - { "macos", OS_POLICY_MACOS }, - { "windows", OS_POLICY_WINDOWS }, - { "vista", OS_POLICY_VISTA }, - { "windows2k3", OS_POLICY_WINDOWS2K3 }, - { NULL, -1 }, -}; - -/** Radix tree that holds the host OS information */ -static SCRadixTree *sc_hinfo_tree = NULL; - - -/** - * \brief Allocates the host_os flavour wrapped in user_data variable to be sent - * along with the key to the radix tree - * - * \param host_os Pointer to a character string containing the host_os flavour - * - * \retval user_data On success, pointer to the user_data that has to be sent - * along with the key, to be added to the Radix tree; NULL on - * failure - * \initonly - */ -static void *SCHInfoAllocUserDataOSPolicy(const char *host_os) -{ - int *user_data = NULL; - - if ( (user_data = SCMalloc(sizeof(int))) == NULL) { - FatalError("Error allocating memory. Exiting"); - } - - /* the host os flavour that has to be sent as user data */ - if ( (*user_data = SCMapEnumNameToValue(host_os, sc_hinfo_os_policy_map)) == -1) { - SCLogError("Invalid enum map inside " - "SCHInfoAddHostOSInfo()"); - SCFree(user_data); - return NULL; - } - - return (void *)user_data; -} - -/** - * \brief Used to free the user data that is allocated by host_os_info API - * - * \param Pointer to the data that has to be freed - */ -static void SCHInfoFreeUserDataOSPolicy(void *data) -{ - if (data != NULL) - SCFree(data); - - return; -} - -/** - * \brief Used to add the host-os-info data obtained from the conf - * - * \param host_os The host_os name/flavour from the conf file - * \param host_os_ip_range Pointer to a char string holding the ip/ip_netblock - * for the host_os specified in the first argument - * \param is_ipv4 Indicates if the ip address to be considered for the - * default configuration is IPV4; if not it is IPV6. - * Specified using SC_HINFO_IS_IPV6 or SC_HINFO_IS_IPV4 - * - * \retval 0 On successfully adding the host os info to the Radix tree - * \retval -1 On failure - * \initonly (only specified from config, at the startup) - */ -int SCHInfoAddHostOSInfo(const char *host_os, const char *host_os_ip_range, int is_ipv4) -{ - char *ip_str = NULL; - char *ip_str_rem = NULL; - struct in_addr *ipv4_addr = NULL; - struct in6_addr *ipv6_addr = NULL; - char *netmask_str = NULL; - uint8_t netmask_value = 0; - int *user_data = NULL; - bool recursive = false; - - if (host_os == NULL || host_os_ip_range == NULL || - strlen(host_os_ip_range) == 0) { - SCLogError("Invalid arguments"); - return -1; - } - - /* create the radix tree that would hold all the host os info */ - if (sc_hinfo_tree == NULL) - sc_hinfo_tree = SCRadixCreateRadixTree(SCHInfoFreeUserDataOSPolicy, NULL); - - /* the host os flavour that has to be sent as user data */ - if ( (user_data = SCHInfoAllocUserDataOSPolicy(host_os)) == NULL) { - SCLogError("Invalid enum map inside"); - return -1; - } - - /* if we have a default configuration set the appropriate values for the - * netblocks */ - if ( (strcasecmp(host_os_ip_range, "default")) == 0) { - if (is_ipv4) - host_os_ip_range = "0.0.0.0/0"; - else - host_os_ip_range = "::/0"; - } - - if ( (ip_str = SCStrdup(host_os_ip_range)) == NULL) { - FatalError("Error allocating memory"); - } - - /* check if we have more addresses in the host_os_ip_range */ - if ((ip_str_rem = strchr(ip_str, ',')) != NULL) { - ip_str_rem[0] = '\0'; - ip_str_rem++; - recursive = true; - } - - /* check if we have received a netblock */ - if ( (netmask_str = strchr(ip_str, '/')) != NULL) { - netmask_str[0] = '\0'; - netmask_str++; - } - - if (strchr(ip_str, ':') == NULL) { - /* if we are here, we have an IPV4 address */ - if ( (ipv4_addr = ValidateIPV4Address(ip_str)) == NULL) { - SCLogError("Invalid IPV4 address"); - SCHInfoFreeUserDataOSPolicy(user_data); - SCFree(ip_str); - return -1; - } - - if (netmask_str == NULL) { - SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, sc_hinfo_tree, - (void *)user_data); - } else { - if (StringParseU8RangeCheck(&netmask_value, 10, 0, (const char *)netmask_str, 0, 32) < - 0) { - SCLogError("Invalid IPV4 Netblock"); - SCHInfoFreeUserDataOSPolicy(user_data); - SCFree(ipv4_addr); - SCFree(ip_str); - return -1; - } - - MaskIPNetblock((uint8_t *)ipv4_addr, netmask_value, 32); - SCRadixAddKeyIPV4Netblock((uint8_t *)ipv4_addr, sc_hinfo_tree, - (void *)user_data, netmask_value); - } - } else { - /* if we are here, we have an IPV6 address */ - if ( (ipv6_addr = ValidateIPV6Address(ip_str)) == NULL) { - SCLogError("Invalid IPV6 address inside"); - SCHInfoFreeUserDataOSPolicy(user_data); - SCFree(ip_str); - return -1; - } - - if (netmask_str == NULL) { - SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, sc_hinfo_tree, - (void *)user_data); - } else { - if (StringParseU8RangeCheck(&netmask_value, 10, 0, (const char *)netmask_str, 0, 128) < - 0) { - SCLogError("Invalid IPV6 Netblock"); - SCHInfoFreeUserDataOSPolicy(user_data); - SCFree(ipv6_addr); - SCFree(ip_str); - return -1; - } - - MaskIPNetblock((uint8_t *)ipv6_addr, netmask_value, 128); - SCRadixAddKeyIPV6Netblock((uint8_t *)ipv6_addr, sc_hinfo_tree, - (void *)user_data, netmask_value); - } - } - - if (recursive) { - SCHInfoAddHostOSInfo(host_os, ip_str_rem, is_ipv4); - } - - SCFree(ip_str); - if (ipv4_addr != NULL) - SCFree(ipv4_addr); - if (ipv6_addr != NULL) - SCFree(ipv6_addr); - return *user_data; -} - -/** - * \brief Retrieves the host os flavour, given an ipv4/ipv6 address as a string. - * - * \param Pointer to a string containing an IP address - * - * \retval The OS flavour on success; -1 on failure, or on not finding the key - */ -int SCHInfoGetHostOSFlavour(const char *ip_addr_str) -{ - struct in_addr *ipv4_addr = NULL; - struct in6_addr *ipv6_addr = NULL; - void *user_data = NULL; - - if (ip_addr_str == NULL || strchr(ip_addr_str, '/') != NULL) - return -1; - - if (strchr(ip_addr_str, ':') != NULL) { - if ( (ipv6_addr = ValidateIPV6Address(ip_addr_str)) == NULL) { - SCLogError("Invalid IPV4 address"); - return -1; - } - - (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)ipv6_addr, sc_hinfo_tree, &user_data); - SCFree(ipv6_addr); - if (user_data == NULL) - return -1; - else - return *((int *)user_data); - } else { - if ( (ipv4_addr = ValidateIPV4Address(ip_addr_str)) == NULL) { - SCLogError("Invalid IPV4 address"); - return -1; - } - - (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)ipv4_addr, sc_hinfo_tree, &user_data); - SCFree(ipv4_addr); - if (user_data == NULL) - return -1; - else - return *((int *)user_data); - } -} - -/** - * \brief Retrieves the host os flavour, given an ipv4 address in the raw - * address format. - * - * \param Pointer to a raw ipv4 address. - * - * \retval The OS flavour on success; -1 on failure, or on not finding the key - */ -int SCHInfoGetIPv4HostOSFlavour(uint8_t *ipv4_addr) -{ - void *user_data = NULL; - (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, sc_hinfo_tree, &user_data); - if (user_data == NULL) - return -1; - else - return *((int *)user_data); -} - -/** - * \brief Retrieves the host os flavour, given an ipv6 address in the raw - * address format. - * - * \param Pointer to a raw ipv6 address. - * - * \retval The OS flavour on success; -1 on failure, or on not finding the key - */ -int SCHInfoGetIPv6HostOSFlavour(uint8_t *ipv6_addr) -{ - void *user_data = NULL; - (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, sc_hinfo_tree, &user_data); - if (user_data == NULL) - return -1; - else - return *((int *)user_data); -} - -void SCHInfoCleanResources(void) -{ - if (sc_hinfo_tree != NULL) { - SCRadixReleaseRadixTree(sc_hinfo_tree); - sc_hinfo_tree = NULL; - } - - return; -} - -/** - * \brief Load the host os policy information from the configuration. - * - * \initonly (A mem alloc error should cause an exit failure) - */ -void SCHInfoLoadFromConfig(void) -{ - ConfNode *root = ConfGetNode("host-os-policy"); - if (root == NULL) - return; - - ConfNode *policy; - TAILQ_FOREACH(policy, &root->head, next) { - ConfNode *host; - TAILQ_FOREACH(host, &policy->head, next) { - int is_ipv4 = 1; - if (host->val != NULL && strchr(host->val, ':') != NULL) - is_ipv4 = 0; - if (SCHInfoAddHostOSInfo(policy->name, host->val, is_ipv4) == -1) { - SCLogError("Failed to add host \"%s\" with policy \"%s\" to host " - "info database", - host->val, policy->name); - exit(EXIT_FAILURE); - } - } - } -} - -/*------------------------------------Unit_Tests------------------------------*/ - -#ifdef UNITTESTS -static SCRadixTree *sc_hinfo_tree_backup = NULL; - -static void SCHInfoCreateContextBackup(void) -{ - sc_hinfo_tree_backup = sc_hinfo_tree; - sc_hinfo_tree = NULL; - - return; -} - -static void SCHInfoRestoreContextBackup(void) -{ - sc_hinfo_tree = sc_hinfo_tree_backup; - sc_hinfo_tree_backup = NULL; - - return; -} - -/** - * \test Check if we the IPs with the right OS flavours are added to the host OS - * radix tree, and the IPS with invalid flavours returns an error(-1) - */ -static int SCHInfoTestInvalidOSFlavour01(void) -{ - SCHInfoCreateContextBackup(); - - int result = 0; - - if (SCHInfoAddHostOSInfo("bamboo", "192.168.1.1", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux10", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux11", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("irix", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("bsd", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("bsd", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("old_linux", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("old_linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("macos", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows2k3", "192.168.1.1", SC_HINFO_IS_IPV4) != - SCMapEnumNameToValue("windows2k3", sc_hinfo_os_policy_map)) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that invalid ipv4 addresses and ipv4 netblocks are rejected by - * the host os info API - */ -static int SCHInfoTestInvalidIPV4Address02(void) -{ - SCHInfoCreateContextBackup(); - - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", "192.168.1.566", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.168", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.168.1.1/33", SC_HINFO_IS_IPV4) != -1) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that invalid ipv4 addresses and ipv4 netblocks are rejected by - * the host os info API - */ -static int SCHInfoTestInvalidIPV6Address03(void) -{ - SCHInfoCreateContextBackup(); - - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", "2362:7322", SC_HINFO_IS_IPV6) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "19YW:", SC_HINFO_IS_IPV6) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "1235", SC_HINFO_IS_IPV6) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "1922:236115:", SC_HINFO_IS_IPV6) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV6) != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", - "1921.6311:6241:6422:7352:ABBB:DDDD:EEEE/129", - SC_HINFO_IS_IPV6) != -1) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that valid ipv4 addresses are inserted into the host os radix - * tree, and the host os api retrieves the right value for the host os - * flavour, on supplying as arg an ipv4 addresses that has been added to - * the host os radix tree. - */ -static int SCHInfoTestValidIPV4Address04(void) -{ - SCHInfoCreateContextBackup(); - - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "11.1.120.210", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "19.18.110.210", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "19.18.120.110", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux11", "191.168.11.128", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "191.168.11.192", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - - if (SCHInfoGetHostOSFlavour("192.168.1.1") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.2") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.192.2.4") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.2.4") != - SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.192.1.5") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.10.20") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.163.151.62") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("11.1.120.210") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("19.18.110.210") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("19.18.120.110") != - SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("191.168.11.128") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("191.168.11.192") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("191.168.11.224") != -1) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that valid ipv4 addresses/netblocks are inserted into the host os - * radix tree, and the host os api retrieves the right value for the host - * os flavour, on supplying as arg an ipv4 addresses that has been added - * to the host os radix tree. - */ -static int SCHInfoTestValidIPV4Address05(void) -{ - SCHInfoCreateContextBackup(); - - struct in_addr in; - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux11", "111.162.208.124/20", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "111.162.240.1", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "111.162.214.100", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "111.162.208.100", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", "111.162.194.112", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - - if (SCHInfoGetHostOSFlavour("192.168.1.1") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.2") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.192.2.4") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.2.4") != - SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.192.1.5") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.10.20") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.163.151.62") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.208.0") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.210.1") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.214.1") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.0.0") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.240.112") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.240.1") != - SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.214.100") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (inet_pton(AF_INET, "111.162.208.100", &in) < 0) { - goto end; - } - if (SCHInfoGetIPv4HostOSFlavour((uint8_t *)&in) != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.194.112") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.208.200") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (inet_pton(AF_INET, "111.162.208.200", &in) < 0) { - goto end; - } - if (SCHInfoGetIPv4HostOSFlavour((uint8_t *)&in) != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("111.162.200.201") != -1) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that valid ipv6 addresses are inserted into the host os radix - * tree, and the host os api retrieves the right value for the host os - * flavour, on supplying as arg an ipv6 address that has been added to - * the host os radix tree. - */ -static int SCHInfoTestValidIPV6Address06(void) -{ - SCHInfoCreateContextBackup(); - - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", - "2351:2512:6211:6246:235A:6242:2352:62AD", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", - "6961:6121:2132:6241:423A:2135:2461:621D", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "DD13:613D:F312:62DD:6213:421A:6212:2652", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux10", - "9891:2131:2151:6426:1342:674D:622F:2342", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", - "3525:2351:4223:6211:2311:2667:6242:2154", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", - "1511:6211:6726:7777:1212:2333:6222:7722", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "2666:6222:7222:2335:6223:7722:3425:2362", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "8762:2352:6241:7245:EE23:21AD:2312:622C", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", - "6422:EE1A:2621:34AD:2462:432D:642E:E13A", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", - "3521:7622:6241:6242:7277:1234:2352:6234", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux11", - "2141:6232:6252:2223:7734:2345:6245:6222", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", - "5222:6432:6432:2322:6662:3423:4322:3245", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - - if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != - SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("6422:EE1A:2621:34AD:2462:432D:642E:E13A") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("3521:7622:6241:6242:7277:1234:2352:6234") != - SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("2141:6232:6252:2223:7734:2345:6245:6222") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:3245") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != -1) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that valid ipv6 addresses/netblocks are inserted into the host os - * radix tree, and the host os api retrieves the right value for the host - * os flavour, on supplying as arg an ipv6 address that has been added to - * the host os radix tree. - */ -static int SCHInfoTestValidIPV6Address07(void) -{ - SCHInfoCreateContextBackup(); - - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", - "2351:2512:6211:6246:235A:6242:2352:62AD", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", - "6961:6121:2132:6241:423A:2135:2461:621D", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "DD13:613D:F312:62DD:6213:421A:6212:2652", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux10", - "9891:2131:2151:6426:1342:674D:622F:2342", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", - "3525:2351:4223:6211:2311:2667:6242:2154", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", - "1511:6211:6726:7777:1212:2333:6222:7722", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "2666:6222:7222:2335:6223:7722:3425:2362", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "8762:2352:6241:7245:EE23:21AD:2312:622C/68", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", - "8762:2352:6241:7245:EE23:21AD:2412:622C", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", - "8762:2352:6241:7245:EE23:21AD:FFFF:622C", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux11", - "8762:2352:6241:7245:EE23:21AD:2312:62FF", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", - "8762:2352:6241:7245:EE23:21AD:2121:1212", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - - if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != - SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") != - SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:E000:0000:0000:0000") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that valid ipv6 addresses/netblocks are inserted into the host os - * radix tree, and the host os api retrieves the right value for the host - * os flavour, on supplying as arg an ipv6 address that has been added to - * the host os radix tree. - */ -static int SCHInfoTestValidIPV6Address08(void) -{ - SCHInfoCreateContextBackup(); - - struct in6_addr in6; - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", - "2351:2512:6211:6246:235A:6242:2352:62AD", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", - "6961:6121:2132:6241:423A:2135:2461:621D", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "DD13:613D:F312:62DD:6213:421A:6212:2652", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux10", - "9891:2131:2151:6426:1342:674D:622F:2342", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", - "3525:2351:4223:6211:2311:2667:6242:2154", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", - "1511:6211:6726:7777:1212:2333:6222:7722", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "2666:6222:7222:2335:6223:7722:3425:2362", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", - "8762:2352:6241:7245:EE23:21AD:2312:622C/68", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("linux", - "8762:2352:6241:7245:EE23:21AD:2412:622C", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", - "8762:2352:6241:7245:EE23:21AD:FFFF:622C", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("hpux11", - "8762:2352:6241:7245:EE23:21AD:2312:62FF", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", - "8762:2352:6241:7245:EE23:21AD:2121:1212", - SC_HINFO_IS_IPV6) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "8.8.8.0/24", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("irix", "default", SC_HINFO_IS_IPV6) == -1) { - goto end; - } - - if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFF") != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != - SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") != - SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") != - SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (inet_pton(AF_INET6, "8762:2352:6241:7245:E000:0000:0000:0000", &in6) < 0) { - goto end; - } - if (SCHInfoGetIPv6HostOSFlavour((uint8_t *)&in6) != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - if (inet_pton(AF_INET6, "AD23:2DDA:6D1D:A223:E235:0232:1241:1666", &in6) < 0) { - goto end; - } - if (SCHInfoGetIPv6HostOSFlavour((uint8_t *)&in6) != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoGetHostOSFlavour("8.8.8.8") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check that valid ipv4 addresses are inserted into the host os radix - * tree, and the host os api retrieves the right value for the host os - * flavour, on supplying as arg an ipv4 addresses that has been added to - * the host os radix tree. - */ -static int SCHInfoTestValidIPV4Address09(void) -{ - SCHInfoCreateContextBackup(); - - int result = 0; - - if (SCHInfoAddHostOSInfo("linux", "192.168.1.0", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.0") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.1.0") != - SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("vista", "192.168.50.128/25", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.50.128") != - SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { - goto end; - } - if (SCHInfoAddHostOSInfo("irix", "192.168.50.128", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoGetHostOSFlavour("192.168.50.128") != - SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { - goto end; - } - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { - goto end; - } - - /* 192.168.1.100 should match "macos" as its more specific than - * "solaris". */ - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { - goto end; - } - - /* Remove the 192.168.1.0/20 -> macos entry. */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != - SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { - goto end; - } - - /* Remove the 192.168.1.0/16 -> solaris entry. */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { - goto end; - } - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); - - if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { - goto end; - } - - result = 1; - - end: - SCHInfoCleanResources(); - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check the loading of host info from a configuration file. - */ -static int SCHInfoTestLoadFromConfig01(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -host-os-policy:\n\ - bsd: [0.0.0.0/0]\n\ - windows: [10.0.0.0/8, 192.168.1.0/24]\n\ - linux: [10.0.0.5/32]\n\ -\n"; - - int result = 0; - - SCHInfoCreateContextBackup(); - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - SCHInfoLoadFromConfig(); - if (SCHInfoGetHostOSFlavour("10.0.0.4") != OS_POLICY_WINDOWS) - goto end; - if (SCHInfoGetHostOSFlavour("10.0.0.5") != OS_POLICY_LINUX) - goto end; - if (SCHInfoGetHostOSFlavour("192.168.1.1") != OS_POLICY_WINDOWS) - goto end; - if (SCHInfoGetHostOSFlavour("172.168.1.1") != OS_POLICY_BSD) - goto end; - - result = 1; - - end: - ConfDeInit(); - ConfRestoreContextBackup(); - - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check the loading of host info from a configuration file. - */ -static int SCHInfoTestLoadFromConfig02(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -host-os-policy:\n\ - one-two: [0.0.0.0/0]\n\ - one-two-three:\n\ - four_five:\n\ - six-seven_eight: [10.0.0.0/8, 192.168.1.0/24]\n\ - nine_ten_eleven: [10.0.0.5/32]\n\ -\n"; - - int result = 0; - - SCHInfoCreateContextBackup(); - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ConfNode *root = ConfGetNode("host-os-policy"); - if (root == NULL) - goto end; - - int count = 0; - - ConfNode *policy; - TAILQ_FOREACH(policy, &root->head, next) { - switch (count) { - case 0: - if (strcmp("one-two", policy->name) != 0) - goto end; - break; - case 1: - if (strcmp("one-two-three", policy->name) != 0) - goto end; - break; - case 2: - if (strcmp("four-five", policy->name) != 0) - goto end; - break; - case 3: - if (strcmp("six-seven-eight", policy->name) != 0) - goto end; - break; - case 4: - if (strcmp("nine-ten-eleven", policy->name) != 0) - goto end; - break; - } - count++; - } - - result = 1; - - end: - ConfDeInit(); - ConfRestoreContextBackup(); - - SCHInfoRestoreContextBackup(); - - return result; -} - -/** - * \test Check the loading of host info from a configuration file. - */ -static int SCHInfoTestLoadFromConfig03(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -host-os-policy:\n\ - bsd-right: [0.0.0.1]\n\ - old-linux: [0.0.0.2]\n\ - old-solaris: [0.0.0.3]\n\ - windows: [0.0.0.4]\n\ - vista: [0.0.0.5]\n\ -\n"; - - int result = 0; - - SCHInfoCreateContextBackup(); - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ConfNode *root = ConfGetNode("host-os-policy"); - if (root == NULL) - goto end; - - ConfNode *policy; - TAILQ_FOREACH(policy, &root->head, next) { - if (SCMapEnumNameToValue(policy->name, sc_hinfo_os_policy_map) == -1) { - printf("Invalid enum map inside\n"); - goto end; - } - } - - result = 1; - - end: - ConfDeInit(); - ConfRestoreContextBackup(); - - SCHInfoRestoreContextBackup(); - return result; -} - -/** - * \test Check the loading of host info from a configuration file. - */ -static int SCHInfoTestLoadFromConfig04(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -host-os-policy:\n\ - bsd_right: [0.0.0.1]\n\ - old_linux: [0.0.0.2]\n\ - old_solaris: [0.0.0.3]\n\ - windows: [0.0.0.4]\n\ - vista: [0.0.0.5]\n\ -\n"; - - int result = 0; - - SCHInfoCreateContextBackup(); - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - - ConfNode *root = ConfGetNode("host-os-policy"); - if (root == NULL) - goto end; - - ConfNode *policy; - TAILQ_FOREACH(policy, &root->head, next) { - if (SCMapEnumNameToValue(policy->name, sc_hinfo_os_policy_map) == -1) { - printf("Invalid enum map inside\n"); - goto end; - } - } - - result = 1; - - end: - ConfDeInit(); - ConfRestoreContextBackup(); - - SCHInfoRestoreContextBackup(); - return result; -} - -/** - * \test Check the loading of host info from a configuration file. - */ -static int SCHInfoTestLoadFromConfig05(void) -{ - char config[] = "\ -%YAML 1.1\n\ ----\n\ -host-os-policy:\n\ - bsd_right: [0.0.0.1]\n\ - old_linux: [0.0.0.2]\n\ - old-solaris: [0.0.0.3]\n\ - windows: [0.0.0.4]\n\ - linux: [0.0.0.5]\n\ -\n"; - - SCHInfoCreateContextBackup(); - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(config, strlen(config)); - SCHInfoLoadFromConfig(); - - FAIL_IF (SCHInfoGetHostOSFlavour("0.0.0.1") != OS_POLICY_BSD_RIGHT); - FAIL_IF (SCHInfoGetHostOSFlavour("0.0.0.2") != OS_POLICY_OLD_LINUX); - FAIL_IF (SCHInfoGetHostOSFlavour("0.0.0.3") != OS_POLICY_OLD_SOLARIS); - FAIL_IF (SCHInfoGetHostOSFlavour("0.0.0.4") != OS_POLICY_WINDOWS); - FAIL_IF (SCHInfoGetHostOSFlavour("0.0.0.5") != OS_POLICY_LINUX); - FAIL_IF (SCHInfoGetHostOSFlavour("0.0.0.0") != -1); - FAIL_IF (SCHInfoGetHostOSFlavour("0.0.0.6") != -1); - - ConfDeInit(); - ConfRestoreContextBackup(); - SCHInfoRestoreContextBackup(); - PASS; -} - -#endif /* UNITTESTS */ - -void SCHInfoRegisterTests(void) -{ - -#ifdef UNITTESTS - - UtRegisterTest("SCHInfoTesInvalidOSFlavour01", - SCHInfoTestInvalidOSFlavour01); - UtRegisterTest("SCHInfoTestInvalidIPV4Address02", - SCHInfoTestInvalidIPV4Address02); - UtRegisterTest("SCHInfoTestInvalidIPV6Address03", - SCHInfoTestInvalidIPV6Address03); - UtRegisterTest("SCHInfoTestValidIPV4Address04", - SCHInfoTestValidIPV4Address04); - UtRegisterTest("SCHInfoTestValidIPV4Address05", - SCHInfoTestValidIPV4Address05); - UtRegisterTest("SCHInfoTestValidIPV6Address06", - SCHInfoTestValidIPV6Address06); - UtRegisterTest("SCHInfoTestValidIPV6Address07", - SCHInfoTestValidIPV6Address07); - UtRegisterTest("SCHInfoTestValidIPV6Address08", - SCHInfoTestValidIPV6Address08); - UtRegisterTest("SCHInfoTestValidIPV4Address09", - SCHInfoTestValidIPV4Address09); - - UtRegisterTest("SCHInfoTestLoadFromConfig01", SCHInfoTestLoadFromConfig01); - UtRegisterTest("SCHInfoTestLoadFromConfig02", SCHInfoTestLoadFromConfig02); - UtRegisterTest("SCHInfoTestLoadFromConfig03", SCHInfoTestLoadFromConfig03); - UtRegisterTest("SCHInfoTestLoadFromConfig04", SCHInfoTestLoadFromConfig04); - UtRegisterTest("SCHInfoTestLoadFromConfig05", SCHInfoTestLoadFromConfig05); -#endif /* UNITTESTS */ - -} diff --git a/src/util-hyperscan.c b/src/util-hyperscan.c deleted file mode 100644 index c49012b6b202..000000000000 --- a/src/util-hyperscan.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Justin Viiret - * - * Support functions for Hyperscan library integration. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#ifdef BUILD_HYPERSCAN -#include "util-hyperscan.h" - -/** - * \internal - * \brief Convert a pattern into a regex string accepted by the Hyperscan - * compiler. - * - * For simplicity, we just take each byte of the original pattern and render it - * with a hex escape (i.e. ' ' -> "\x20")/ - */ -char *HSRenderPattern(const uint8_t *pat, uint16_t pat_len) -{ - if (pat == NULL) { - return NULL; - } - const size_t hex_len = (pat_len * 4) + 1; - char *str = SCCalloc(1, hex_len); - if (str == NULL) { - return NULL; - } - char *sp = str; - for (uint16_t i = 0; i < pat_len; i++) { - snprintf(sp, 5, "\\x%02x", pat[i]); - sp += 4; - } - *sp = '\0'; - return str; -} - -#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-ioctl.c b/src/util-ioctl.c deleted file mode 100644 index f39662bd4d47..000000000000 --- a/src/util-ioctl.c +++ /dev/null @@ -1,739 +0,0 @@ -/* Copyright (C) 2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * \author Victor Julien - */ - -#include "suricata-common.h" -#include "util-ioctl.h" -#include "conf.h" -#include "decode.h" -#include "decode-sll.h" - -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_LINUX_ETHTOOL_H -#include -#include -#ifdef HAVE_LINUX_SOCKIOS_H -#include -#else -#error "ethtool.h present but sockios.h is missing" -#endif /* HAVE_LINUX_SOCKIOS_H */ -#endif /* HAVE_LINUX_ETHTOOL_H */ - -#ifdef HAVE_NET_IF_H -#include -#endif - -#ifdef OS_WIN32 -#include "win32-syscall.h" -#endif - -/** - * \brief output a majorant of hardware header length - * - * \param Name of a network interface - */ -static int GetIfaceMaxHWHeaderLength(const char *dev) -{ - if ((!strcmp("eth", dev)) || (!strcmp("br", dev)) || (!strcmp("bond", dev)) || - (!strcmp("wlan", dev)) || (!strcmp("tun", dev)) || (!strcmp("tap", dev)) || - (!strcmp("lo", dev))) { - /* Add possible VLAN tag or Qing headers */ - return 8 + ETHERNET_HEADER_LEN; - } - - if (!strcmp("ppp", dev)) - return SLL_HEADER_LEN; - /* SLL_HEADER_LEN is the biggest one and - add possible VLAN tag and Qing headers */ - return 8 + SLL_HEADER_LEN; -} - - -/** - * \brief output the link MTU - * - * \param Name of link - * \retval -1 in case of error, 0 if MTU can not be found - */ -int GetIfaceMTU(const char *dev) -{ -#if defined SIOCGIFMTU - struct ifreq ifr; - int fd; - - (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd == -1) { - return -1; - } - - if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { - SCLogWarning("Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev, - strerror(errno), errno); - close(fd); - return -1; - } - close(fd); - SCLogInfo("%s: MTU %d", dev, ifr.ifr_mtu); - return ifr.ifr_mtu; -#elif defined OS_WIN32 - return GetIfaceMTUWin32(dev); -#else - /* ioctl is not defined, let's pretend returning 0 is ok */ - return 0; -#endif -} - -/** - * \brief output max packet size for a link - * - * This does a best effort to find the maximum packet size - * for the link. In case of uncertainty, it will output a - * majorant to be sure avoid the cost of dynamic allocation. - * - * \param LiveDevice object - * \retval 0 in case of error - */ -int GetIfaceMaxPacketSize(LiveDevice *ld) -{ - if (ld == NULL) - return 0; - - const char *dev = ld->dev; - if ((dev == NULL) || strlen(dev) == 0) - return 0; - - int mtu = GetIfaceMTU(dev); - switch (mtu) { - case 0: - case -1: - return 0; - } - ld->mtu = mtu; - int ll_header = GetIfaceMaxHWHeaderLength(dev); - return ll_header + mtu; -} - -#ifdef SIOCGIFFLAGS -/** - * \brief Get interface flags. - * \param ifname Interface name. - * \return Interface flags or -1 on error - */ -int GetIfaceFlags(const char *ifname) -{ - struct ifreq ifr; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { - SCLogError("%s: failed to get device flags: %s", ifname, strerror(errno)); - close(fd); - return -1; - } - - close(fd); -#ifdef OS_FREEBSD - int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); - return flags; -#else - return ifr.ifr_flags; -#endif -} -#endif - -#ifdef SIOCSIFFLAGS -/** - * \brief Set interface flags. - * \param ifname Interface name. - * \param flags Flags to set. - * \return Zero on success. - */ -int SetIfaceFlags(const char *ifname, int flags) -{ - struct ifreq ifr; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); -#ifdef OS_FREEBSD - ifr.ifr_flags = flags & 0xffff; - ifr.ifr_flagshigh = flags >> 16; -#else - ifr.ifr_flags = (uint16_t)flags; -#endif - - if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { - SCLogError("%s: unable to set device flags: %s", ifname, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} -#endif /* SIOCGIFFLAGS */ - -#ifdef SIOCGIFCAP -int GetIfaceCaps(const char *ifname) -{ - struct ifreq ifr; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { - SCLogError("%s: unable to get device caps: %s", ifname, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return ifr.ifr_curcap; -} -#endif -#ifdef SIOCSIFCAP -int SetIfaceCaps(const char *ifname, int caps) -{ - struct ifreq ifr; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - ifr.ifr_reqcap = caps; - - if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) { - SCLogError("%s: unable to set caps: %s", ifname, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} -#endif - - -#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL -static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) -{ - struct ifreq ifr; - int fd; - struct ethtool_value ethv; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd == -1) { - return -1; - } - (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - - ethv.cmd = cmd; - ifr.ifr_data = (void *) ðv; - if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { - SCLogWarning("%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno)); - close(fd); - return -1; - } - - *value = ethv.data; - close(fd); - return 0; -} - -static int SetEthtoolValue(const char *dev, int cmd, uint32_t value) -{ - struct ifreq ifr; - int fd; - struct ethtool_value ethv; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd == -1) { - return -1; - } - (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - - ethv.cmd = cmd; - ethv.data = value; - ifr.ifr_data = (void *) ðv; - if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { - SCLogWarning("%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - return 0; -} - -static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) -{ - int ret = 0; - uint32_t value = 0; - - if (csum) { - const char *rx = "unset", *tx = "unset"; - int csum_ret = 0; -#ifdef ETHTOOL_GRXCSUM - if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { - rx = "SET"; - csum_ret = 1; - } -#endif -#ifdef ETHTOOL_GTXCSUM - if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { - tx = "SET"; - csum_ret = 1; - } -#endif - if (csum_ret == 0) - SCLogPerf("%s: NIC offloading: RX %s TX %s", dev, rx, tx); - else { - SCLogWarning("%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev, - rx, tx, dev); - ret = 1; - } - } - - if (other) { - const char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; - const char *sg = "unset"; - int other_ret = 0; -#ifdef ETHTOOL_GGRO - if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { - gro = "SET"; - other_ret = 1; - } -#endif -#ifdef ETHTOOL_GTSO - if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { - tso = "SET"; - other_ret = 1; - } -#endif -#ifdef ETHTOOL_GGSO - if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { - gso = "SET"; - other_ret = 1; - } -#endif -#ifdef ETHTOOL_GSG - if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { - sg = "SET"; - other_ret = 1; - } -#endif -#ifdef ETHTOOL_GFLAGS - if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { - if (value & ETH_FLAG_LRO) { - lro = "SET"; - other_ret = 1; - } - } -#endif - if (other_ret == 0) { - SCLogPerf("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg, - gro, lro, tso, gso); - } else { - SCLogWarning("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: " - "ethtool -K %s sg off gro off lro off tso off gso off", - dev, sg, gro, lro, tso, gso, dev); - ret = 1; - } - } - return ret; -} - -static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) -{ - int ret = 0; - uint32_t value = 0; - - if (ldev == NULL) - return -1; - - const char *dev = ldev->dev; - - if (csum) { -#ifdef ETHTOOL_GRXCSUM - if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { - SCLogPerf("%s: disabling rxcsum offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); - ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; - } -#endif -#ifdef ETHTOOL_GTXCSUM - if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { - SCLogPerf("%s: disabling txcsum offloading", dev); - SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); - ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM; - } -#endif - } - if (other) { -#ifdef ETHTOOL_GGRO - if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { - SCLogPerf("%s: disabling gro offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SGRO, 0); - ldev->offload_orig |= OFFLOAD_FLAG_GRO; - } -#endif -#ifdef ETHTOOL_GTSO - if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { - SCLogPerf("%s: disabling tso offloading", dev); - SetEthtoolValue(dev, ETHTOOL_STSO, 0); - ldev->offload_orig |= OFFLOAD_FLAG_TSO; - } -#endif -#ifdef ETHTOOL_GGSO - if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { - SCLogPerf("%s: disabling gso offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SGSO, 0); - ldev->offload_orig |= OFFLOAD_FLAG_GSO; - } -#endif -#ifdef ETHTOOL_GSG - if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { - SCLogPerf("%s: disabling sg offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SSG, 0); - ldev->offload_orig |= OFFLOAD_FLAG_SG; - } -#endif -#ifdef ETHTOOL_GFLAGS - if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { - if (value & ETH_FLAG_LRO) { - SCLogPerf("%s: disabling lro offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); - ldev->offload_orig |= OFFLOAD_FLAG_LRO; - } - } -#endif - } - return ret; -} - -static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) -{ - if (ldev == NULL) - return -1; - - const char *dev = ldev->dev; - -#ifdef ETHTOOL_GRXCSUM - if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { - SCLogPerf("%s: restoring rxcsum offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1); - } -#endif -#ifdef ETHTOOL_GTXCSUM - if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) { - SCLogPerf("%s: restoring txcsum offloading", dev); - SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1); - } -#endif -#ifdef ETHTOOL_GGRO - if (ldev->offload_orig & OFFLOAD_FLAG_GRO) { - SCLogPerf("%s: restoring gro offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SGRO, 1); - } -#endif -#ifdef ETHTOOL_GTSO - if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { - SCLogPerf("%s: restoring tso offloading", dev); - SetEthtoolValue(dev, ETHTOOL_STSO, 1); - } -#endif -#ifdef ETHTOOL_GGSO - if (ldev->offload_orig & OFFLOAD_FLAG_GSO) { - SCLogPerf("%s: restoring gso offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SGSO, 1); - } -#endif -#ifdef ETHTOOL_GSG - if (ldev->offload_orig & OFFLOAD_FLAG_SG) { - SCLogPerf("%s: restoring sg offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SSG, 1); - } -#endif -#ifdef ETHTOOL_GFLAGS - if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { - uint32_t value = 0; - if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { - SCLogPerf("%s: restoring lro offloading", dev); - SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO); - } - } -#endif - return 0; -} - -#endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ - -#ifdef SIOCGIFCAP -static int GetIfaceOffloadingBSD(const char *ifname) -{ - int ret = 0; - int if_caps = GetIfaceCaps(ifname); - if (if_caps == -1) { - return -1; - } - SCLogDebug("if_caps %X", if_caps); - - if (if_caps & IFCAP_RXCSUM) { - SCLogWarning("%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum", - ifname, ifname); - ret = 1; - } -#ifdef IFCAP_TOE - if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { - SCLogWarning("%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s " - "-tso -toe -lro", - ifname, ifname); - ret = 1; - } -#else - if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { - SCLogWarning( - "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro", - ifname, ifname); - ret = 1; - } -#endif - return ret; -} -#endif - -#ifdef SIOCSIFCAP -static int DisableIfaceOffloadingBSD(LiveDevice *ldev) -{ - int ret = 0; - - if (ldev == NULL) - return -1; - - const char *ifname = ldev->dev; - int if_caps = GetIfaceCaps(ifname); - int set_caps = if_caps; - if (if_caps == -1) { - return -1; - } - SCLogDebug("if_caps %X", if_caps); - - if (if_caps & IFCAP_RXCSUM) { - SCLogPerf("%s: disabling rxcsum offloading", ifname); - set_caps &= ~IFCAP_RXCSUM; - } - if (if_caps & IFCAP_TXCSUM) { - SCLogPerf("%s: disabling txcsum offloading", ifname); - set_caps &= ~IFCAP_TXCSUM; - } -#ifdef IFCAP_RXCSUM_IPV6 - if (if_caps & IFCAP_RXCSUM_IPV6) { - SCLogPerf("%s: disabling rxcsum6 offloading", ifname); - set_caps &= ~IFCAP_RXCSUM_IPV6; - } -#endif -#ifdef IFCAP_TXCSUM_IPV6 - if (if_caps & IFCAP_TXCSUM_IPV6) { - SCLogPerf("%s: disabling txcsum6 offloading", ifname); - set_caps &= ~IFCAP_TXCSUM_IPV6; - } -#endif -#ifdef IFCAP_TOE - if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { - SCLogPerf("%s: disabling tso|toe|lro offloading", ifname); - set_caps &= ~(IFCAP_TSO|IFCAP_LRO); - } -#else - if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { - SCLogPerf("%s: disabling tso|lro offloading", ifname); - set_caps &= ~(IFCAP_TSO|IFCAP_LRO); - } -#endif - if (set_caps != if_caps) { - if (if_caps & IFCAP_RXCSUM) - ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; - if (if_caps & IFCAP_TSO) - ldev->offload_orig |= OFFLOAD_FLAG_TSO; -#ifdef IFCAP_TOE - if (if_caps & IFCAP_TOE) - ldev->offload_orig |= OFFLOAD_FLAG_TOE; -#endif - if (if_caps & IFCAP_LRO) - ldev->offload_orig |= OFFLOAD_FLAG_LRO; - - SetIfaceCaps(ifname, set_caps); - } - return ret; -} - -static int RestoreIfaceOffloadingBSD(LiveDevice *ldev) -{ - int ret = 0; - - if (ldev == NULL) - return -1; - - const char *ifname = ldev->dev; - int if_caps = GetIfaceCaps(ifname); - int set_caps = if_caps; - if (if_caps == -1) { - return -1; - } - SCLogDebug("if_caps %X", if_caps); - - if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { - SCLogPerf("%s: restoring rxcsum offloading", ifname); - set_caps |= IFCAP_RXCSUM; - } - if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { - SCLogPerf("%s: restoring tso offloading", ifname); - set_caps |= IFCAP_TSO; - } -#ifdef IFCAP_TOE - if (ldev->offload_orig & OFFLOAD_FLAG_TOE) { - SCLogPerf("%s: restoring toe offloading", ifname); - set_caps |= IFCAP_TOE; - } -#endif - if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { - SCLogPerf("%s: restoring lro offloading", ifname); - set_caps |= IFCAP_LRO; - } - - if (set_caps != if_caps) { - SetIfaceCaps(ifname, set_caps); - } - return ret; -} -#endif - -/** - * \brief output offloading status of the link - * - * Test interface for offloading features. If one of them is - * activated then suricata mays received packets merge at reception. - * The result is oversized packets and this may cause some serious - * problem in some capture mode where the size of the packet is - * limited (AF_PACKET in V2 more for example). - * - * \param Name of link - * \param csum check if checksums are offloaded - * \param other check if other things are offloaded: TSO, GRO, etc. - * \retval -1 in case of error, 0 if none, 1 if some - */ -int GetIfaceOffloading(const char *dev, int csum, int other) -{ -#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL - return GetIfaceOffloadingLinux(dev, csum, other); -#elif defined SIOCGIFCAP - return GetIfaceOffloadingBSD(dev); -#elif defined OS_WIN32 - return GetIfaceOffloadingWin32(dev, csum, other); -#else - return 0; -#endif -} - -int DisableIfaceOffloading(LiveDevice *dev, int csum, int other) -{ - /* already set */ - if (dev->offload_orig != 0) - return 0; -#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL - return DisableIfaceOffloadingLinux(dev, csum, other); -#elif defined SIOCSIFCAP - return DisableIfaceOffloadingBSD(dev); -#elif defined OS_WIN32 - return DisableIfaceOffloadingWin32(dev, csum, other); -#else - return 0; -#endif - -} - -void RestoreIfaceOffloading(LiveDevice *dev) -{ - if (dev->offload_orig != 0) { -#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL - RestoreIfaceOffloadingLinux(dev); -#elif defined SIOCSIFCAP - RestoreIfaceOffloadingBSD(dev); -#elif defined OS_WIN32 - RestoreIfaceOffloadingWin32(dev); -#endif - } -} - -int GetIfaceRSSQueuesNum(const char *dev) -{ -#if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS - struct ifreq ifr; - struct ethtool_rxnfc nfccmd; - int fd; - - (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd == -1) { - SCLogWarning("%s: failed to open socket for ioctl: %s", dev, strerror(errno)); - return -1; - } - - nfccmd.cmd = ETHTOOL_GRXRINGS; - ifr.ifr_data = (void*) &nfccmd; - - if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { - if (errno != ENOTSUP) { - SCLogWarning("%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno)); - } - close(fd); - return 0; - } - close(fd); - SCLogInfo("%s: RX RSS queues: %d", dev, (int)nfccmd.data); - return (int)nfccmd.data; -#else - return 0; -#endif -} diff --git a/src/util-ioctl.h b/src/util-ioctl.h deleted file mode 100644 index 24f897487511..000000000000 --- a/src/util-ioctl.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - */ - -#include "suricata-common.h" -#include "util-device.h" - -int GetIfaceMTU(const char *pcap_dev); -int GetIfaceMaxPacketSize(LiveDevice *ld); -int GetIfaceOffloading(const char *dev, int csum, int other); -int GetIfaceRSSQueuesNum(const char *pcap_dev); -#ifdef SIOCGIFFLAGS -int GetIfaceFlags(const char *ifname); -#endif -#ifdef SIOCSIFFLAGS -int SetIfaceFlags(const char *ifname, int flags); -#endif -#ifdef SIOCGIFCAP -int GetIfaceCaps(const char *ifname); -#endif -#ifdef SIOCSIFCAP -int SetIfaceCaps(const char *ifname, int caps); -#endif -int DisableIfaceOffloading(LiveDevice *dev, int csum, int other); -void RestoreIfaceOffloading(LiveDevice *dev); diff --git a/src/util-ip.c b/src/util-ip.c deleted file mode 100644 index 8d482d90ed5f..000000000000 --- a/src/util-ip.c +++ /dev/null @@ -1,205 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * \author Duarte Silva - * - * IP addresses related utility functions - */ - -#include "suricata-common.h" -#include "util-ip.h" -#include "util-byte.h" -#include "util-debug.h" - -/** \brief determine if a string is a valid ipv4 address - * \retval bool is addr valid? - */ -bool IPv4AddressStringIsValid(const char *str) -{ - int alen = 0; - char addr[4][4]; - int dots = 0; - - memset(&addr, 0, sizeof(addr)); - - uint32_t len = strlen(str); - uint32_t i = 0; - for (i = 0; i < len; i++) { - if (!(str[i] == '.' || isdigit(str[i]))) { - return false; - } - if (str[i] == '.') { - if (dots == 3) { - SCLogDebug("too many dots"); - return false; - } - addr[dots][alen] = '\0'; - dots++; - alen = 0; - } else { - if (alen >= 3) { - SCLogDebug("too long"); - return false; - } - addr[dots][alen++] = str[i]; - } - } - if (dots != 3) - return false; - - addr[dots][alen] = '\0'; - for (int x = 0; x < 4; x++) { - uint8_t a; - if (StringParseUint8(&a, 10, 0, (const char *)addr[x]) < 0) { - SCLogDebug("invalid value for address byte: %s", addr[x]); - return false; - } - } - return true; -} - -/** \brief determine if a string is a valid ipv6 address - * \retval bool is addr valid? - */ -bool IPv6AddressStringIsValid(const char *str) -{ - int block_size = 0; - int sep = 0; - bool colon_seen = false; - - uint32_t len = strlen(str); - uint32_t i = 0; - for (i = 0; i < len && str[i] != 0; i++) { - if (!(str[i] == '.' || str[i] == ':' || - isxdigit(str[i]))) - return false; - - if (str[i] == ':') { - block_size = 0; - colon_seen = true; - sep++; - } else if (str[i] == '.') { - block_size = false; - sep++; - } else { - if (block_size == 4) - return false; - block_size++; - } - } - - if (!colon_seen) - return false; - if (sep > 7) { - SCLogDebug("too many seps %d", sep); - return false; - } - return true; -} - -/** - * \brief Validates an IPV4 address and returns the network endian arranged - * version of the IPV4 address - * - * \param addr Pointer to a character string containing an IPV4 address. A - * valid IPV4 address is a character string containing a dotted - * format of "ddd.ddd.ddd.ddd" - * - * \retval Pointer to an in_addr instance containing the network endian format - * of the IPV4 address - * \retval NULL if the IPV4 address is invalid - */ -struct in_addr *ValidateIPV4Address(const char *addr_str) -{ - struct in_addr *addr = NULL; - - if (!IPv4AddressStringIsValid(addr_str)) - return NULL; - - if ( (addr = SCMalloc(sizeof(struct in_addr))) == NULL) { - FatalError("Fatal error encountered in ValidateIPV4Address. Exiting..."); - } - - if (inet_pton(AF_INET, addr_str, addr) <= 0) { - SCFree(addr); - return NULL; - } - - return addr; -} - -/** - * \brief Validates an IPV6 address and returns the network endian arranged - * version of the IPV6 address - * - * \param addr Pointer to a character string containing an IPV6 address - * - * \retval Pointer to a in6_addr instance containing the network endian format - * of the IPV6 address - * \retval NULL if the IPV6 address is invalid - */ -struct in6_addr *ValidateIPV6Address(const char *addr_str) -{ - struct in6_addr *addr = NULL; - - if (!IPv6AddressStringIsValid(addr_str)) - return NULL; - - if ( (addr = SCMalloc(sizeof(struct in6_addr))) == NULL) { - FatalError("Fatal error encountered in ValidateIPV6Address. Exiting..."); - } - - if (inet_pton(AF_INET6, addr_str, addr) <= 0) { - SCFree(addr); - return NULL; - } - - return addr; -} - -/** - * \brief Culls the non-netmask portion of the IP address. For example an IP - * address 192.168.240.1 would be chopped to 192.168.224.0 against a - * netmask value of 19. - * - * \param stream Pointer the IP address that has to be masked - * \param netmask The netmask value (cidr) to which the IP address has to be culled - * \param key_bitlen The bitlen of the stream - */ -void MaskIPNetblock(uint8_t *stream, int netmask, int key_bitlen) -{ - uint32_t mask = 0; - int i = 0; - int bytes = key_bitlen / 8; - - for (i = 0; i < bytes; i++) { - mask = UINT_MAX; - if ( ((i + 1) * 8) > netmask) { - if ( ((i + 1) * 8 - netmask) < 8) - mask = UINT_MAX << ((i + 1) * 8 - netmask); - else - mask = 0; - } - stream[i] &= mask; - } - - return; -} diff --git a/src/util-ja3.c b/src/util-ja3.c deleted file mode 100644 index b361b3e74e39..000000000000 --- a/src/util-ja3.c +++ /dev/null @@ -1,302 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - * - * Functions used to generate JA3 fingerprint. - */ - -#include "suricata-common.h" -#include "app-layer-ssl.h" -#include "util-validate.h" -#include "util-ja3.h" - -#include "detect-engine.h" - -/** - * \brief Allocate new buffer. - * - * \return pointer to buffer on success. - * \return NULL on failure. - */ -JA3Buffer *Ja3BufferInit(void) -{ - JA3Buffer *buffer = SCCalloc(1, sizeof(JA3Buffer)); - if (buffer == NULL) { - return NULL; - } - - return buffer; -} - -/** - * \brief Free allocated buffer. - * - * \param buffer The buffer to free. - */ -void Ja3BufferFree(JA3Buffer **buffer) -{ - DEBUG_VALIDATE_BUG_ON(*buffer == NULL); - - if ((*buffer)->data != NULL) { - SCFree((*buffer)->data); - (*buffer)->data = NULL; - } - - SCFree(*buffer); - *buffer = NULL; -} - -/** - * \internal - * \brief Resize buffer if it is full. - * - * \param buffer The buffer. - * \param len The length of the data that should fit into the buffer. - * - * \retval 0 on success. - * \retval -1 on failure. - */ -static int Ja3BufferResizeIfFull(JA3Buffer *buffer, uint32_t len) -{ - DEBUG_VALIDATE_BUG_ON(buffer == NULL); - - while (buffer->used + len + 2 > buffer->size) - { - buffer->size *= 2; - char *tmp = SCRealloc(buffer->data, buffer->size); - if (tmp == NULL) { - SCLogError("Error resizing JA3 buffer"); - return -1; - } - buffer->data = tmp; - } - - return 0; -} - -/** - * \brief Append buffer to buffer. - * - * Append the second buffer to the first and then free it. - * - * \param buffer1 The first buffer. - * \param buffer2 The second buffer. - * - * \retval 0 on success. - * \retval -1 on failure. - */ -int Ja3BufferAppendBuffer(JA3Buffer **buffer1, JA3Buffer **buffer2) -{ - if (*buffer1 == NULL || *buffer2 == NULL) { - SCLogError("Buffers should not be NULL"); - return -1; - } - - /* If buffer1 contains no data, then we just copy the second buffer - instead of appending its data. */ - if ((*buffer1)->data == NULL) { - (*buffer1)->data = (*buffer2)->data; - (*buffer1)->used = (*buffer2)->used; - (*buffer1)->size = (*buffer2)->size; - SCFree(*buffer2); - return 0; - } - - int rc = Ja3BufferResizeIfFull(*buffer1, (*buffer2)->used); - if (rc != 0) { - Ja3BufferFree(buffer1); - Ja3BufferFree(buffer2); - return -1; - } - - if ((*buffer2)->used == 0) { - (*buffer1)->used += snprintf((*buffer1)->data + (*buffer1)->used, - (*buffer1)->size - (*buffer1)->used, ","); - } else { - (*buffer1)->used += snprintf((*buffer1)->data + (*buffer1)->used, - (*buffer1)->size - (*buffer1)->used, ",%s", - (*buffer2)->data); - } - - Ja3BufferFree(buffer2); - - return 0; -} - -/** - * \internal - * \brief Return number of digits in number. - * - * \param num The number. - * - * \return digits Number of digits. - */ -static uint32_t NumberOfDigits(uint32_t num) -{ - if (num < 10) { - return 1; - } - - return 1 + NumberOfDigits(num / 10); -} - -/** - * \brief Add value to buffer. - * - * \param buffer The buffer. - * \param value The value. - * - * \retval 0 on success. - * \retval -1 on failure. - */ -int Ja3BufferAddValue(JA3Buffer **buffer, uint32_t value) -{ - if (*buffer == NULL) { - SCLogError("Buffer should not be NULL"); - return -1; - } - - if ((*buffer)->data == NULL) { - (*buffer)->data = SCMalloc(JA3_BUFFER_INITIAL_SIZE); - if ((*buffer)->data == NULL) { - SCLogError("Error allocating memory for JA3 data"); - Ja3BufferFree(buffer); - return -1; - } - (*buffer)->size = JA3_BUFFER_INITIAL_SIZE; - } - - uint32_t value_len = NumberOfDigits(value); - - int rc = Ja3BufferResizeIfFull(*buffer, value_len); - if (rc != 0) { - Ja3BufferFree(buffer); - return -1; - } - - if ((*buffer)->used == 0) { - (*buffer)->used += snprintf((*buffer)->data, (*buffer)->size, "%u", value); - } - else { - (*buffer)->used += snprintf( - (*buffer)->data + (*buffer)->used, (*buffer)->size - (*buffer)->used, "-%u", value); - } - - return 0; -} - -/** - * \brief Generate Ja3 hash string. - * - * \param buffer The Ja3 buffer. - * - * \retval pointer to hash string on success. - * \retval NULL on failure. - */ -char *Ja3GenerateHash(JA3Buffer *buffer) -{ - if (buffer == NULL) { - SCLogError("Buffer should not be NULL"); - return NULL; - } - - if (buffer->data == NULL) { - SCLogError("Buffer data should not be NULL"); - return NULL; - } - - char *ja3_hash = SCMalloc(SC_MD5_HEX_LEN + 1); - if (ja3_hash == NULL) { - SCLogError("Error allocating memory for JA3 hash"); - return NULL; - } - - SCMd5HashBufferToHex((unsigned char *)buffer->data, buffer->used, ja3_hash, SC_MD5_HEX_LEN + 1); - return ja3_hash; -} - -/** - * \brief Check if JA3 is disabled. - * - * Issue warning if JA3 is disabled or if we are lacking support for JA3. - * - * \param type Type to add to warning. - * - * \retval 1 if disabled. - * \retval 0 otherwise. - */ -int Ja3IsDisabled(const char *type) -{ - bool is_enabled = SSLJA3IsEnabled(); - if (is_enabled == 0) { - if (strcmp(type, "rule") != 0) { - SCLogWarning("JA3 is disabled, skipping %s", type); - } - return 1; - } - - return 0; -} - -InspectionBuffer *Ja3DetectGetHash(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_quic_tx_get_ja3(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - uint8_t ja3_hash[SC_MD5_HEX_LEN + 1]; - // this adds a final zero - SCMd5HashBufferToHex(b, b_len, (char *)ja3_hash, SC_MD5_HEX_LEN + 1); - - InspectionBufferSetup(det_ctx, list_id, buffer, NULL, 0); - InspectionBufferCopy(buffer, ja3_hash, SC_MD5_HEX_LEN); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} - -InspectionBuffer *Ja3DetectGetString(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - uint32_t b_len = 0; - const uint8_t *b = NULL; - - if (rs_quic_tx_get_ja3(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); - InspectionBufferApplyTransforms(buffer, transforms); - } - return buffer; -} diff --git a/src/util-ja3.h b/src/util-ja3.h deleted file mode 100644 index 5a0f8c508e6d..000000000000 --- a/src/util-ja3.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mats Klepsland - */ - -#ifndef __UTIL_JA3_H__ -#define __UTIL_JA3_H__ - -#define JA3_BUFFER_INITIAL_SIZE 128 - -#include "detect.h" - -typedef struct JA3Buffer_ { - char *data; - size_t size; - size_t used; -} JA3Buffer; - -JA3Buffer *Ja3BufferInit(void); -void Ja3BufferFree(JA3Buffer **); -int Ja3BufferAppendBuffer(JA3Buffer **, JA3Buffer **); -int Ja3BufferAddValue(JA3Buffer **, uint32_t); -char *Ja3GenerateHash(JA3Buffer *); -int Ja3IsDisabled(const char *); - -InspectionBuffer *Ja3DetectGetHash(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); - -InspectionBuffer *Ja3DetectGetString(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id); - -#endif /* __UTIL_JA3_H__ */ - diff --git a/src/util-landlock.c b/src/util-landlock.c deleted file mode 100644 index 258993c30d5c..000000000000 --- a/src/util-landlock.c +++ /dev/null @@ -1,282 +0,0 @@ -/* Copyright (C) 2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - */ - -#include "suricata.h" -#include "feature.h" -#include "util-conf.h" -#include "util-file.h" -#include "util-landlock.h" -#include "util-mem.h" -#include "util-path.h" - -#ifndef HAVE_LINUX_LANDLOCK_H - -void LandlockSandboxing(SCInstance *suri) -{ - return; -} - -#else /* HAVE_LINUX_LANDLOCK_H */ - -#include - -#ifndef landlock_create_ruleset -static inline int landlock_create_ruleset( - const struct landlock_ruleset_attr *const attr, const size_t size, const __u32 flags) -{ - return syscall(__NR_landlock_create_ruleset, attr, size, flags); -} -#endif - -#ifndef landlock_add_rule -static inline int landlock_add_rule(const int ruleset_fd, const enum landlock_rule_type rule_type, - const void *const rule_attr, const __u32 flags) -{ - return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags); -} -#endif - -#ifndef landlock_restrict_self -static inline int landlock_restrict_self(const int ruleset_fd, const __u32 flags) -{ - return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); -} -#endif - -#ifndef LANDLOCK_ACCESS_FS_REFER -#define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) -#endif - -#define _LANDLOCK_ACCESS_FS_WRITE \ - (LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | \ - LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_CHAR | \ - LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | \ - LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | \ - LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM | \ - LANDLOCK_ACCESS_FS_REFER) - -#define _LANDLOCK_ACCESS_FS_READ (LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR) - -#define _LANDLOCK_SURI_ACCESS_FS_WRITE \ - (LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | \ - LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) - -struct landlock_ruleset { - int fd; - struct landlock_ruleset_attr attr; -}; - -static inline struct landlock_ruleset *LandlockCreateRuleset(void) -{ - struct landlock_ruleset *ruleset = SCCalloc(1, sizeof(struct landlock_ruleset)); - if (ruleset == NULL) { - SCLogError("Can't alloc landlock ruleset"); - return NULL; - } - - ruleset->attr.handled_access_fs = - _LANDLOCK_ACCESS_FS_READ | _LANDLOCK_ACCESS_FS_WRITE | LANDLOCK_ACCESS_FS_EXECUTE; - - int abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); - if (abi < 0) { - SCFree(ruleset); - return NULL; - } - if (abi < 2) { - if (RequiresFeature(FEATURE_OUTPUT_FILESTORE)) { - SCLogError("Landlock disabled: need Linux 5.19+ for file store support"); - SCFree(ruleset); - return NULL; - } else { - ruleset->attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; - } - } - - ruleset->fd = landlock_create_ruleset(&ruleset->attr, sizeof(ruleset->attr), 0); - if (ruleset->fd < 0) { - SCFree(ruleset); - SCLogError("Can't create landlock ruleset"); - return NULL; - } - return ruleset; -} - -static inline void LandlockEnforceRuleset(struct landlock_ruleset *ruleset) -{ - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) { - SCLogError("Can't self restrict (prctl phase): %s", strerror(errno)); - return; - } - if (landlock_restrict_self(ruleset->fd, 0)) { - SCLogError("Can't self restrict (landlock phase): %s", strerror(errno)); - } -} - -static int LandlockSandboxingAddRule( - struct landlock_ruleset *ruleset, const char *directory, uint64_t permission) -{ - struct landlock_path_beneath_attr path_beneath = { - .allowed_access = permission & ruleset->attr.handled_access_fs, - }; - - int dir_fd = open(directory, O_PATH | O_CLOEXEC | O_DIRECTORY); - if (dir_fd == -1) { - SCLogError("Can't open %s", directory); - return -1; - } - path_beneath.parent_fd = dir_fd; - - if (landlock_add_rule(ruleset->fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0)) { - SCLogError("Can't add write rule: %s", strerror(errno)); - close(dir_fd); - return -1; - } - - close(dir_fd); - return 0; -} - -static inline void LandlockSandboxingWritePath( - struct landlock_ruleset *ruleset, const char *directory) -{ - if (LandlockSandboxingAddRule(ruleset, directory, _LANDLOCK_SURI_ACCESS_FS_WRITE) == 0) { - SCLogConfig("Added write permission to '%s'", directory); - } -} - -static inline void LandlockSandboxingReadPath( - struct landlock_ruleset *ruleset, const char *directory) -{ - if (LandlockSandboxingAddRule(ruleset, directory, _LANDLOCK_ACCESS_FS_READ) == 0) { - SCLogConfig("Added read permission to '%s'", directory); - } -} - -void LandlockSandboxing(SCInstance *suri) -{ - /* Read configuration variable and exit if no enforcement */ - int conf_status; - if (ConfGetBool("security.landlock.enabled", &conf_status) == 0) { - conf_status = 0; - } - if (!conf_status) { - SCLogConfig("Landlock is not enabled in configuration"); - return; - } - struct landlock_ruleset *ruleset = LandlockCreateRuleset(); - if (ruleset == NULL) { - SCLogError("Kernel does not support Landlock"); - return; - } - - LandlockSandboxingWritePath(ruleset, ConfigGetLogDirectory()); - struct stat sb; - if (stat(ConfigGetDataDirectory(), &sb) == 0) { - LandlockSandboxingAddRule(ruleset, ConfigGetDataDirectory(), - _LANDLOCK_SURI_ACCESS_FS_WRITE | _LANDLOCK_ACCESS_FS_READ); - } - if (suri->run_mode == RUNMODE_PCAP_FILE) { - const char *pcap_file; - if (ConfGet("pcap-file.file", &pcap_file) == 1) { - char *file_name = SCStrdup(pcap_file); - if (file_name != NULL) { - struct stat statbuf; - if (stat(file_name, &statbuf) != -1) { - if (S_ISDIR(statbuf.st_mode)) { - LandlockSandboxingReadPath(ruleset, file_name); - } else { - LandlockSandboxingReadPath(ruleset, dirname(file_name)); - } - } else { - SCLogError("Can't open pcap file"); - } - SCFree(file_name); - } - } - } - if (suri->sig_file) { - char *file_name = SCStrdup(suri->sig_file); - if (file_name != NULL) { - LandlockSandboxingReadPath(ruleset, dirname(file_name)); - SCFree(file_name); - } - } - if (suri->pid_filename) { - char *file_name = SCStrdup(suri->pid_filename); - if (file_name != NULL) { - LandlockSandboxingWritePath(ruleset, dirname(file_name)); - SCFree(file_name); - } - } - if (ConfUnixSocketIsEnable()) { - const char *socketname; - if (ConfGet("unix-command.filename", &socketname) == 1) { - if (PathIsAbsolute(socketname)) { - char *file_name = SCStrdup(socketname); - if (file_name != NULL) { - LandlockSandboxingWritePath(ruleset, dirname(file_name)); - SCFree(file_name); - } - } else { - LandlockSandboxingWritePath(ruleset, LOCAL_STATE_DIR "/run/suricata/"); - } - } else { - LandlockSandboxingWritePath(ruleset, LOCAL_STATE_DIR "/run/suricata/"); - } - } - if (!suri->sig_file_exclusive) { - const char *rule_path; - if (ConfGet("default-rule-path", &rule_path) == 1 && rule_path) { - LandlockSandboxingReadPath(ruleset, rule_path); - } - } - - ConfNode *read_dirs = ConfGetNode("security.landlock.directories.read"); - if (read_dirs) { - if (!ConfNodeIsSequence(read_dirs)) { - SCLogWarning("Invalid security.landlock.directories.read configuration section: " - "expected a list of directory names."); - } else { - ConfNode *directory; - TAILQ_FOREACH (directory, &read_dirs->head, next) { - LandlockSandboxingReadPath(ruleset, directory->val); - } - } - } - ConfNode *write_dirs = ConfGetNode("security.landlock.directories.write"); - if (write_dirs) { - if (!ConfNodeIsSequence(write_dirs)) { - SCLogWarning("Invalid security.landlock.directories.write configuration section: " - "expected a list of directory names."); - } else { - ConfNode *directory; - TAILQ_FOREACH (directory, &write_dirs->head, next) { - LandlockSandboxingWritePath(ruleset, directory->val); - } - } - } - LandlockEnforceRuleset(ruleset); - SCFree(ruleset); -} - -#endif /* HAVE_LINUX_LANDLOCK_H */ diff --git a/src/util-log-redis.c b/src/util-log-redis.c deleted file mode 100644 index 5f590d2c6933..000000000000 --- a/src/util-log-redis.c +++ /dev/null @@ -1,600 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Paulo Pacheco - * - * File-like output for logging: redis - */ -#include "suricata-common.h" /* errno.h, string.h, etc. */ -#include "util-log-redis.h" -#include "util-logopenfile.h" -#include "util-byte.h" -#include "util-debug.h" - -#ifdef HAVE_LIBHIREDIS - -#ifdef HAVE_LIBEVENT_PTHREADS -#include -#endif /* HAVE_LIBEVENT_PTHREADS */ - -static const char * redis_lpush_cmd = "LPUSH"; -static const char * redis_rpush_cmd = "RPUSH"; -static const char * redis_publish_cmd = "PUBLISH"; -static const char * redis_default_key = "suricata"; -static const char * redis_default_server = "127.0.0.1"; - -static int SCConfLogReopenSyncRedis(LogFileCtx *log_ctx); -static void SCLogFileCloseRedis(LogFileCtx *log_ctx); - -/** - * \brief SCLogRedisInit() - Initializes global stuff before threads - */ -void SCLogRedisInit(void) -{ -#ifdef HAVE_LIBEVENT_PTHREADS - evthread_use_pthreads(); -#endif /* HAVE_LIBEVENT_PTHREADS */ -} - -/** \brief SCLogRedisContextAlloc() - Allocates and initializes redis context - */ -static SCLogRedisContext *SCLogRedisContextAlloc(void) -{ - SCLogRedisContext* ctx = (SCLogRedisContext*) SCCalloc(1, sizeof(SCLogRedisContext)); - if (ctx == NULL) { - FatalError("Unable to allocate redis context"); - } - ctx->sync = NULL; -#if HAVE_LIBEVENT - ctx->ev_base = NULL; - ctx->async = NULL; -#endif - ctx->batch_count = 0; - ctx->last_push = 0; - ctx->tried = 0; - - return ctx; -} - -#ifdef HAVE_LIBEVENT - -static int SCConfLogReopenAsyncRedis(LogFileCtx *log_ctx); -#include - -/** \brief SCLogRedisAsyncContextAlloc() - Allocates and initializes redis context with async - */ -static SCLogRedisContext *SCLogRedisContextAsyncAlloc(void) -{ - SCLogRedisContext* ctx = (SCLogRedisContext*) SCCalloc(1, sizeof(SCLogRedisContext)); - if (unlikely(ctx == NULL)) { - FatalError("Unable to allocate redis context"); - } - - ctx->sync = NULL; - ctx->async = NULL; - ctx->ev_base = NULL; - ctx->connected = 0; - ctx->batch_count = 0; - ctx->last_push = 0; - ctx->tried = 0; - - return ctx; -} - -/** \brief SCRedisAsyncCommandCallback() Callback when reply from redis happens. - * \param ac redis async context - * \param r redis reply - * \param privdata opaque data with pointer to LogFileCtx - */ -static void SCRedisAsyncCommandCallback(redisAsyncContext *ac, void *r, void *privdata) -{ - redisReply *reply = r; - LogFileCtx *log_ctx = privdata; - SCLogRedisContext *ctx = log_ctx->redis; - - if (reply == NULL) { - if (ctx->connected > 0) - SCLogInfo("Missing reply from redis, disconnected."); - ctx->connected = 0; - } else { - ctx->connected = 1; - event_base_loopbreak(ctx->ev_base); - } -} - -/** \brief SCRedisAsyncEchoCommandCallback() Callback for an ECHO command reply - * This is used to check if redis is connected. - * \param ac redis async context - * \param r redis reply - * \param privdata opaque data with pointer to LogFileCtx - */ -static void SCRedisAsyncEchoCommandCallback(redisAsyncContext *ac, void *r, void *privdata) -{ - redisReply *reply = r; - SCLogRedisContext * ctx = privdata; - - if (reply) { - if (ctx->connected == 0) { - SCLogNotice("Connected to Redis."); - ctx->connected = 1; - ctx->tried = 0; - } - } else { - ctx->connected = 0; - if (ctx->tried == 0) { - SCLogWarning("Failed to connect to Redis... (will keep trying)"); - } - ctx->tried = time(NULL); - } - event_base_loopbreak(ctx->ev_base); -} - -/** \brief SCRedisAsyncEchoCommandCallback() Callback for an QUIT command reply - * Emits and awaits response for an async ECHO command. - * It's used for check if redis is alive. - * \param ctx redis context - */ -static void SCLogAsyncRedisSendEcho(SCLogRedisContext * ctx) -{ - redisAsyncCommand(ctx->async, SCRedisAsyncEchoCommandCallback, ctx, "ECHO suricata"); - event_base_dispatch(ctx->ev_base); -} - -/** \brief SCRedisAsyncEchoCommandCallback() Callback for an QUIT command reply - * This is used to terminate connection with redis. - * \param ac redis async context - * \param r redis reply - * \param privdata opaque data with pointer to LogFileCtx - */ -static void SCRedisAsyncQuitCommandCallback(redisAsyncContext *ac, void *r, void *privdata) -{ - SCLogInfo("Disconnecting from redis!"); -} - -/** \brief QUIT command - * Emits and awaits response for an async QUIT command. - * It's used to disconnect with redis - * \param ctx redis context - */ -static void SCLogAsyncRedisSendQuit(SCLogRedisContext * ctx) -{ - if (ctx->connected) { - redisAsyncCommand(ctx->async, SCRedisAsyncQuitCommandCallback, ctx, "QUIT"); - SCLogInfo("QUIT Command sent to redis. Connection will terminate!"); - } - - redisAsyncFree(ctx->async); - event_base_dispatch(ctx->ev_base); - ctx->async = NULL; - event_base_free(ctx->ev_base); - ctx->ev_base = NULL; - ctx->connected = 0; -} - -/** \brief SCConfLogReopenAsyncRedis() Open or re-opens connection to redis for logging. - * \param log_ctx Log file context allocated by caller - */ -static int SCConfLogReopenAsyncRedis(LogFileCtx *log_ctx) -{ - SCLogRedisContext * ctx = log_ctx->redis; - const char *redis_server = log_ctx->redis_setup.server; - int redis_port = log_ctx->redis_setup.port; - - /* only try to reconnect once per second */ - if (ctx->tried >= time(NULL)) { - return -1; - } - - if (strchr(redis_server, '/') == NULL) { - ctx->async = redisAsyncConnect(redis_server, redis_port); - } else { - ctx->async = redisAsyncConnectUnix(redis_server); - } - - if (ctx->ev_base != NULL) { - event_base_free(ctx->ev_base); - ctx->ev_base = NULL; - } - - if (ctx->async == NULL) { - SCLogError("Error allocate redis async."); - ctx->tried = time(NULL); - return -1; - } - - if (ctx->async != NULL && ctx->async->err) { - SCLogError("Error setting to redis async: [%s].", ctx->async->errstr); - ctx->tried = time(NULL); - return -1; - } - - ctx->ev_base = event_base_new(); - - if (ctx->ev_base == NULL) { - ctx->tried = time(NULL); - redisAsyncFree(ctx->async); - ctx->async = NULL; - return -1; - } - - redisLibeventAttach(ctx->async, ctx->ev_base); - - log_ctx->redis = ctx; - log_ctx->Close = SCLogFileCloseRedis; - return 0; -} - - -/** \brief SCLogRedisWriteAsync() writes string to redis output in async mode - * \param file_ctx Log file context allocated by caller - * \param string Buffer to output - */ -static int SCLogRedisWriteAsync(LogFileCtx *file_ctx, const char *string, size_t string_len) -{ - SCLogRedisContext *ctx = file_ctx->redis; - - if (! ctx->connected) { - if (SCConfLogReopenAsyncRedis(file_ctx) == -1) { - return -1; - } - if (ctx->tried == 0) { - SCLogNotice("Trying to connect to Redis"); - } - SCLogAsyncRedisSendEcho(ctx); - } - - if (!ctx->connected) { - return -1; - } - - if (ctx->async == NULL) { - return -1; - } - - redisAsyncCommand(ctx->async, - SCRedisAsyncCommandCallback, - file_ctx, - "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - string); - - event_base_loop(ctx->ev_base, EVLOOP_NONBLOCK); - - return 0; -} - -#endif// HAVE_LIBEVENT - -/** \brief SCConfLogReopenSyncRedis() Open or re-opens connection to redis for logging. - * \param log_ctx Log file context allocated by caller - */ -static int SCConfLogReopenSyncRedis(LogFileCtx *log_ctx) -{ - SCLogRedisContext * ctx = log_ctx->redis; - - /* only try to reconnect once per second */ - if (ctx->tried >= time(NULL)) { - return -1; - } - - const char *redis_server = log_ctx->redis_setup.server; - int redis_port = log_ctx->redis_setup.port; - - if (ctx->sync != NULL) { - redisFree(ctx->sync); - } - - if (strchr(redis_server, '/') == NULL) { - ctx->sync = redisConnect(redis_server, redis_port); - } else { - ctx->sync = redisConnectUnix(redis_server); - } - if (ctx->sync == NULL) { - SCLogError("Error connecting to redis server."); - ctx->tried = time(NULL); - return -1; - } - if (ctx->sync->err) { - SCLogError("Error connecting to redis server: [%s].", ctx->sync->errstr); - redisFree(ctx->sync); - ctx->sync = NULL; - ctx->tried = time(NULL); - return -1; - } - SCLogInfo("Connected to redis server [%s].", log_ctx->redis_setup.server); - - log_ctx->redis = ctx; - log_ctx->Close = SCLogFileCloseRedis; - return 0; -} -/** \brief SCLogRedisWriteSync() writes string to redis output in sync mode - * \param file_ctx Log file context allocated by caller - * \param string Buffer to output - */ -static int SCLogRedisWriteSync(LogFileCtx *file_ctx, const char *string) -{ - SCLogRedisContext * ctx = file_ctx->redis; - int ret = -1; - redisContext *redis = ctx->sync; - if (redis == NULL) { - SCConfLogReopenSyncRedis(file_ctx); - redis = ctx->sync; - if (redis == NULL) { - SCLogDebug("Redis after re-open is not available."); - return -1; - } - } - - /* synchronous mode */ - if (file_ctx->redis_setup.batch_size) { - redisAppendCommand(redis, "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - string); - time_t now = time(NULL); - if ((ctx->batch_count == file_ctx->redis_setup.batch_size) || (ctx->last_push < now)) { - redisReply *reply; - int i; - int batch_size = ctx->batch_count; - ctx->batch_count = 0; - ctx->last_push = now; - for (i = 0; i <= batch_size; i++) { - if (redisGetReply(redis, (void **)&reply) == REDIS_OK) { - freeReplyObject(reply); - ret = 0; - } else { - if (redis->err) { - SCLogInfo("Error when fetching reply: %s (%d)", - redis->errstr, - redis->err); - } - switch (redis->err) { - case REDIS_ERR_EOF: - case REDIS_ERR_IO: - SCLogInfo("Reopening connection to redis server"); - SCConfLogReopenSyncRedis(file_ctx); - redis = ctx->sync; - if (redis) { - SCLogInfo("Reconnected to redis server"); - redisAppendCommand(redis, "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - string); - ctx->batch_count++; - return 0; - } else { - SCLogInfo("Unable to reconnect to redis server"); - return -1; - } - break; - default: - SCLogWarning("Unsupported error code %d", redis->err); - return -1; - } - } - } - } else { - ctx->batch_count++; - } - } else { - redisReply *reply = redisCommand(redis, "%s %s %s", - file_ctx->redis_setup.command, - file_ctx->redis_setup.key, - string); - /* We may lose the reply if disconnection happens*/ - if (reply) { - switch (reply->type) { - case REDIS_REPLY_ERROR: - SCLogWarning("Redis error: %s", reply->str); - SCConfLogReopenSyncRedis(file_ctx); - break; - case REDIS_REPLY_INTEGER: - SCLogDebug("Redis integer %lld", reply->integer); - ret = 0; - break; - default: - SCLogError("Redis default triggered with %d", reply->type); - SCConfLogReopenSyncRedis(file_ctx); - break; - } - freeReplyObject(reply); - } else { - SCConfLogReopenSyncRedis(file_ctx); - } - } - return ret; -} - -/** - * \brief LogFileWriteRedis() writes log data to redis output. - * \param log_ctx Log file context allocated by caller - * \param string buffer with data to write - * \param string_len data length - * \retval 0 on success; - * \retval -1 on failure; - */ -int LogFileWriteRedis(void *lf_ctx, const char *string, size_t string_len) -{ - LogFileCtx *file_ctx = lf_ctx; - if (file_ctx == NULL) { - return -1; - } - -#if HAVE_LIBEVENT - /* async mode on */ - if (file_ctx->redis_setup.is_async) { - return SCLogRedisWriteAsync(file_ctx, string, string_len); - } -#endif - /* sync mode */ - if (! file_ctx->redis_setup.is_async) { - return SCLogRedisWriteSync(file_ctx, string); - } - return -1; -} - -/** \brief configure and initializes redis output logging - * \param conf ConfNode structure for the output section in question - * \param log_ctx Log file context allocated by caller - * \retval 0 on success - */ -int SCConfLogOpenRedis(ConfNode *redis_node, void *lf_ctx) -{ - LogFileCtx *log_ctx = lf_ctx; - - if (log_ctx->threaded) { - FatalError("redis does not support threaded output"); - } - - const char *redis_port = NULL; - const char *redis_mode = NULL; - - int is_async = 0; - - if (redis_node) { - log_ctx->redis_setup.server = ConfNodeLookupChildValue(redis_node, "server"); - log_ctx->redis_setup.key = ConfNodeLookupChildValue(redis_node, "key"); - - redis_port = ConfNodeLookupChildValue(redis_node, "port"); - redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); - - (void)ConfGetChildValueBool(redis_node, "async", &is_async); - } - if (!log_ctx->redis_setup.server) { - log_ctx->redis_setup.server = redis_default_server; - SCLogInfo("Using default redis server (127.0.0.1)"); - } - if (!redis_port) - redis_port = "6379"; - if (!redis_mode) - redis_mode = "list"; - if (!log_ctx->redis_setup.key) { - log_ctx->redis_setup.key = redis_default_key; - } - -#ifndef HAVE_LIBEVENT - if (is_async) { - SCLogWarning("async option not available."); - } - is_async = 0; -#endif //ifndef HAVE_LIBEVENT - - log_ctx->redis_setup.is_async = is_async; - log_ctx->redis_setup.batch_size = 0; - if (redis_node) { - ConfNode *pipelining = ConfNodeLookupChild(redis_node, "pipelining"); - if (pipelining) { - int enabled = 0; - int ret; - intmax_t val; - ret = ConfGetChildValueBool(pipelining, "enabled", &enabled); - if (ret && enabled) { - ret = ConfGetChildValueInt(pipelining, "batch-size", &val); - if (ret) { - log_ctx->redis_setup.batch_size = val; - } else { - log_ctx->redis_setup.batch_size = 10; - } - } - } - } else { - log_ctx->redis_setup.batch_size = 0; - } - - if (!strcmp(redis_mode, "list") || !strcmp(redis_mode,"lpush")) { - log_ctx->redis_setup.command = redis_lpush_cmd; - } else if(!strcmp(redis_mode, "rpush")){ - log_ctx->redis_setup.command = redis_rpush_cmd; - } else if(!strcmp(redis_mode,"channel") || !strcmp(redis_mode,"publish")) { - log_ctx->redis_setup.command = redis_publish_cmd; - } else { - FatalError("Invalid redis mode"); - } - - /* store server params for reconnection */ - if (!log_ctx->redis_setup.server) { - FatalError("Error allocating redis server string"); - } - if (StringParseUint16(&log_ctx->redis_setup.port, 10, 0, (const char *)redis_port) < 0) { - FatalError("Invalid value for redis port: %s", redis_port); - } - log_ctx->Close = SCLogFileCloseRedis; - -#ifdef HAVE_LIBEVENT - if (is_async) { - log_ctx->redis = SCLogRedisContextAsyncAlloc(); - } -#endif /*HAVE_LIBEVENT*/ - if (! is_async) { - log_ctx->redis = SCLogRedisContextAlloc(); - SCConfLogReopenSyncRedis(log_ctx); - } - return 0; -} - -/** \brief SCLogFileCloseRedis() Closes redis log more - * \param log_ctx Log file context allocated by caller - */ -void SCLogFileCloseRedis(LogFileCtx *log_ctx) -{ - SCLogRedisContext * ctx = log_ctx->redis; - if (ctx == NULL) { - return; - } - /* asynchronous */ - if (log_ctx->redis_setup.is_async) { -#if HAVE_LIBEVENT == 1 - if (ctx->async) { - if (ctx->connected > 0) { - SCLogAsyncRedisSendQuit(ctx); - } - if (ctx->ev_base != NULL) { - event_base_free(ctx->ev_base); - ctx->ev_base = NULL; - } - } -#endif - } - - /* synchronous */ - if (!log_ctx->redis_setup.is_async) { - if (ctx->sync) { - redisReply *reply; - int i; - for (i = 0; i < ctx->batch_count; i++) { - redisGetReply(ctx->sync, (void **)&reply); - if (reply) { - freeReplyObject(reply); - } - } - redisFree(ctx->sync); - ctx->sync = NULL; - } - ctx->tried = 0; - ctx->batch_count = 0; - } - - if (ctx != NULL) { - SCFree(ctx); - } -} - -#endif //#ifdef HAVE_LIBHIREDIS diff --git a/src/util-log-redis.h b/src/util-log-redis.h deleted file mode 100644 index 12e87dee4a30..000000000000 --- a/src/util-log-redis.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Paulo Pacheco - */ - -#ifndef __UTIL_LOG_REDIS_H__ -#define __UTIL_LOG_REDIS_H__ - -#ifdef HAVE_LIBHIREDIS -#include - - -#ifdef HAVE_LIBEVENT -#include -#endif /* HAVE_LIBEVENT */ - -#include "conf.h" /* ConfNode */ - -enum RedisMode { REDIS_LIST, REDIS_CHANNEL }; - -typedef struct RedisSetup_ { - enum RedisMode mode; - const char *command; - const char *key; - const char *server; - uint16_t port; - int is_async; - int batch_size; -} RedisSetup; - -typedef struct SCLogRedisContext_ { - redisContext *sync; -#if HAVE_LIBEVENT - redisAsyncContext *async; - struct event_base *ev_base; - int connected; -#endif /* HAVE_LIBEVENT */ - time_t tried; - int batch_count; - time_t last_push; -} SCLogRedisContext; - -void SCLogRedisInit(void); -int SCConfLogOpenRedis(ConfNode *, void *); -int LogFileWriteRedis(void *, const char *, size_t); - -#endif /* HAVE_LIBHIREDIS */ -#endif /* __UTIL_LOG_REDIS_H__ */ diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c deleted file mode 100644 index 1b1986490658..000000000000 --- a/src/util-logopenfile.c +++ /dev/null @@ -1,939 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mike Pomraning - * - * File-like output for logging: regular files and sockets. - */ - -#include "suricata-common.h" /* errno.h, string.h, etc. */ -#include "util-logopenfile.h" -#include "suricata.h" -#include "conf.h" /* ConfNode, etc. */ -#include "output.h" /* DEFAULT_LOG_* */ -#include "util-byte.h" -#include "util-conf.h" -#include "util-path.h" -#include "util-time.h" - -#if defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SYS_TYPES_H) -#define BUILD_WITH_UNIXSOCKET -#include -#include -#include -#endif - -#ifdef HAVE_LIBHIREDIS -#include "util-log-redis.h" -#endif /* HAVE_LIBHIREDIS */ - -#define LOGFILE_NAME_MAX 255 - -static bool LogFileNewThreadedCtx(LogFileCtx *parent_ctx, const char *log_path, const char *append, - ThreadLogFileHashEntry *entry); - -// Threaded eve.json identifier -static SC_ATOMIC_DECL_AND_INIT_WITH_VAL(uint32_t, eve_file_id, 1); - -#ifdef BUILD_WITH_UNIXSOCKET -/** \brief connect to the indicated local stream socket, logging any errors - * \param path filesystem path to connect to - * \param log_err, non-zero if connect failure should be logged. - * \retval FILE* on success (fdopen'd wrapper of underlying socket) - * \retval NULL on error - */ -static FILE * -SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err) -{ - struct sockaddr_un saun; - int s = -1; - FILE * ret = NULL; - - memset(&saun, 0x00, sizeof(saun)); - - s = socket(PF_UNIX, sock_type, 0); - if (s < 0) goto err; - - saun.sun_family = AF_UNIX; - strlcpy(saun.sun_path, path, sizeof(saun.sun_path)); - - if (connect(s, (const struct sockaddr *)&saun, sizeof(saun)) < 0) - goto err; - - ret = fdopen(s, "w"); - if (ret == NULL) - goto err; - - return ret; - -err: - if (log_err) - SCLogWarning( - "Error connecting to socket \"%s\": %s (will keep trying)", path, strerror(errno)); - - if (s >= 0) - close(s); - - return NULL; -} - -/** - * \brief Attempt to reconnect a disconnected (or never-connected) Unix domain socket. - * \retval 1 if it is now connected; otherwise 0 - */ -static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx) -{ - int disconnected = 0; - if (log_ctx->fp) { - SCLogWarning("Write error on Unix socket \"%s\": %s; reconnecting...", log_ctx->filename, - strerror(errno)); - fclose(log_ctx->fp); - log_ctx->fp = NULL; - log_ctx->reconn_timer = 0; - disconnected = 1; - } - - struct timeval tv; - uint64_t now; - gettimeofday(&tv, NULL); - now = (uint64_t)tv.tv_sec * 1000; - now += tv.tv_usec / 1000; /* msec resolution */ - if (log_ctx->reconn_timer != 0 && - (now - log_ctx->reconn_timer) < LOGFILE_RECONN_MIN_TIME) { - /* Don't bother to try reconnecting too often. */ - return 0; - } - log_ctx->reconn_timer = now; - - log_ctx->fp = SCLogOpenUnixSocketFp(log_ctx->filename, log_ctx->sock_type, 0); - if (log_ctx->fp) { - /* Connected at last (or reconnected) */ - SCLogNotice("Reconnected socket \"%s\"", log_ctx->filename); - } else if (disconnected) { - SCLogWarning("Reconnect failed: %s (will keep trying)", strerror(errno)); - } - - return log_ctx->fp ? 1 : 0; -} - -static int SCLogFileWriteSocket(const char *buffer, int buffer_len, - LogFileCtx *ctx) -{ - int tries = 0; - int ret = 0; - bool reopen = false; - if (ctx->fp == NULL && ctx->is_sock) { - SCLogUnixSocketReconnect(ctx); - } -tryagain: - ret = -1; - reopen = 0; - errno = 0; - if (ctx->fp != NULL) { - int fd = fileno(ctx->fp); - ssize_t size = send(fd, buffer, buffer_len, ctx->send_flags); - if (size > -1) { - ret = 0; - } else { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - SCLogDebug("Socket would block, dropping event."); - } else if (errno == EINTR) { - if (tries++ == 0) { - SCLogDebug("Interrupted system call, trying again."); - goto tryagain; - } - SCLogDebug("Too many interrupted system calls, " - "dropping event."); - } else { - /* Some other error. Assume badness and reopen. */ - SCLogDebug("Send failed: %s", strerror(errno)); - reopen = true; - } - } - } - - if (reopen && tries++ == 0) { - if (SCLogUnixSocketReconnect(ctx)) { - goto tryagain; - } - } - - if (ret == -1) { - ctx->dropped++; - } - - return ret; -} -#endif /* BUILD_WITH_UNIXSOCKET */ -static inline void OutputWriteLock(pthread_mutex_t *m) -{ - SCMutexLock(m); - -} - -/** - * \brief Write buffer to log file. - * \retval 0 on failure; otherwise, the return value of fwrite_unlocked (number of - * characters successfully written). - */ -static int SCLogFileWriteNoLock(const char *buffer, int buffer_len, LogFileCtx *log_ctx) -{ - int ret = 0; - - BUG_ON(log_ctx->is_sock); - - /* Check for rotation. */ - if (log_ctx->rotation_flag) { - log_ctx->rotation_flag = 0; - SCConfLogReopen(log_ctx); - } - - if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { - time_t now = time(NULL); - if (now >= log_ctx->rotate_time) { - SCConfLogReopen(log_ctx); - log_ctx->rotate_time = now + log_ctx->rotate_interval; - } - } - - if (log_ctx->fp) { - SCClearErrUnlocked(log_ctx->fp); - if (1 != SCFwriteUnlocked(buffer, buffer_len, 1, log_ctx->fp)) { - /* Only the first error is logged */ - if (!log_ctx->output_errors) { - SCLogError("%s error while writing to %s", - SCFerrorUnlocked(log_ctx->fp) ? strerror(errno) : "unknown error", - log_ctx->filename); - } - log_ctx->output_errors++; - } else { - SCFflushUnlocked(log_ctx->fp); - } - } - - return ret; -} - -/** - * \brief Write buffer to log file. - * \retval 0 on failure; otherwise, the return value of fwrite (number of - * characters successfully written). - */ -static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) -{ - OutputWriteLock(&log_ctx->fp_mutex); - int ret = 0; - -#ifdef BUILD_WITH_UNIXSOCKET - if (log_ctx->is_sock) { - ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx); - } else -#endif - { - - /* Check for rotation. */ - if (log_ctx->rotation_flag) { - log_ctx->rotation_flag = 0; - SCConfLogReopen(log_ctx); - } - - if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { - time_t now = time(NULL); - if (now >= log_ctx->rotate_time) { - SCConfLogReopen(log_ctx); - log_ctx->rotate_time = now + log_ctx->rotate_interval; - } - } - - if (log_ctx->fp) { - clearerr(log_ctx->fp); - if (1 != fwrite(buffer, buffer_len, 1, log_ctx->fp)) { - /* Only the first error is logged */ - if (!log_ctx->output_errors) { - SCLogError("%s error while writing to %s", - ferror(log_ctx->fp) ? strerror(errno) : "unknown error", - log_ctx->filename); - } - log_ctx->output_errors++; - } else { - fflush(log_ctx->fp); - } - } - } - - SCMutexUnlock(&log_ctx->fp_mutex); - - return ret; -} - -/** \brief generate filename based on pattern - * \param pattern pattern to use - * \retval char* on success - * \retval NULL on error - */ -static char *SCLogFilenameFromPattern(const char *pattern) -{ - char *filename = SCMalloc(PATH_MAX); - if (filename == NULL) { - return NULL; - } - - int rc = SCTimeToStringPattern(time(NULL), pattern, filename, PATH_MAX); - if (rc != 0) { - SCFree(filename); - return NULL; - } - - return filename; -} - -static void SCLogFileCloseNoLock(LogFileCtx *log_ctx) -{ - SCLogDebug("Closing %s", log_ctx->filename); - if (log_ctx->fp) - fclose(log_ctx->fp); - - if (log_ctx->output_errors) { - SCLogError("There were %" PRIu64 " output errors to %s", log_ctx->output_errors, - log_ctx->filename); - } -} - -static void SCLogFileClose(LogFileCtx *log_ctx) -{ - SCMutexLock(&log_ctx->fp_mutex); - SCLogFileCloseNoLock(log_ctx); - SCMutexUnlock(&log_ctx->fp_mutex); -} - -static char ThreadLogFileHashCompareFunc( - void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) -{ - ThreadLogFileHashEntry *p1 = (ThreadLogFileHashEntry *)data1; - ThreadLogFileHashEntry *p2 = (ThreadLogFileHashEntry *)data2; - - if (p1 == NULL || p2 == NULL) - return 0; - - return p1->thread_id == p2->thread_id; -} -static uint32_t ThreadLogFileHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - const ThreadLogFileHashEntry *ent = (ThreadLogFileHashEntry *)data; - - return ent->thread_id % ht->array_size; -} - -static void ThreadLogFileHashFreeFunc(void *data) -{ - BUG_ON(data == NULL); - ThreadLogFileHashEntry *thread_ent = (ThreadLogFileHashEntry *)data; - - if (thread_ent) { - LogFileCtx *lf_ctx = thread_ent->ctx; - /* Free the leaf log file entries */ - if (!lf_ctx->threaded) { - LogFileFreeCtx(lf_ctx); - } - SCFree(thread_ent); - } -} - -bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx) -{ - parent_ctx->threads = SCCalloc(1, sizeof(LogThreadedFileCtx)); - if (!parent_ctx->threads) { - SCLogError("Unable to allocate threads container"); - return false; - } - - parent_ctx->threads->ht = HashTableInit(255, ThreadLogFileHashFunc, - ThreadLogFileHashCompareFunc, ThreadLogFileHashFreeFunc); - if (!parent_ctx->threads->ht) { - FatalError("Unable to initialize thread/entry hash table"); - } - - parent_ctx->threads->append = SCStrdup(append == NULL ? DEFAULT_LOG_MODE_APPEND : append); - if (!parent_ctx->threads->append) { - SCLogError("Unable to allocate threads append setting"); - goto error_exit; - } - - SCMutexInit(&parent_ctx->threads->mutex, NULL); - return true; - -error_exit: - - if (parent_ctx->threads->append) { - SCFree(parent_ctx->threads->append); - } - if (parent_ctx->threads->ht) { - HashTableFree(parent_ctx->threads->ht); - } - SCFree(parent_ctx->threads); - parent_ctx->threads = NULL; - return false; -} - -/** \brief open the indicated file, logging any errors - * \param path filesystem path to open - * \param append_setting open file with O_APPEND: "yes" or "no" - * \param mode permissions to set on file - * \retval FILE* on success - * \retval NULL on error - */ -static FILE * -SCLogOpenFileFp(const char *path, const char *append_setting, uint32_t mode) -{ - FILE *ret = NULL; - - char *filename = SCLogFilenameFromPattern(path); - if (filename == NULL) { - return NULL; - } - - int rc = SCCreateDirectoryTree(filename, false); - if (rc < 0) { - SCFree(filename); - return NULL; - } - - if (ConfValIsTrue(append_setting)) { - ret = fopen(filename, "a"); - } else { - ret = fopen(filename, "w"); - } - - if (ret == NULL) { - SCLogError("Error opening file: \"%s\": %s", filename, strerror(errno)); - } else { - if (mode != 0) { -#ifdef OS_WIN32 - int r = _chmod(filename, (mode_t)mode); -#else - int r = fchmod(fileno(ret), (mode_t)mode); -#endif - if (r < 0) { - SCLogWarning("Could not chmod %s to %o: %s", filename, mode, strerror(errno)); - } - } - } - - SCFree(filename); - return ret; -} - -/** \brief open a generic output "log file", which may be a regular file or a socket - * \param conf ConfNode structure for the output section in question - * \param log_ctx Log file context allocated by caller - * \param default_filename Default name of file to open, if not specified in ConfNode - * \param rotate Register the file for rotation in HUP. - * \retval 0 on success - * \retval -1 on error - */ -int -SCConfLogOpenGeneric(ConfNode *conf, - LogFileCtx *log_ctx, - const char *default_filename, - int rotate) -{ - char log_path[PATH_MAX]; - const char *log_dir; - const char *filename, *filetype; - - // Arg check - if (conf == NULL || log_ctx == NULL || default_filename == NULL) { - SCLogError("SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " - "missing an argument", - conf, log_ctx, default_filename); - return -1; - } - if (log_ctx->fp != NULL) { - SCLogError("SCConfLogOpenGeneric: previously initialized Log CTX " - "encountered"); - return -1; - } - - // Resolve the given config - filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename == NULL) - filename = default_filename; - - log_dir = ConfigGetLogDirectory(); - - if (PathIsAbsolute(filename)) { - snprintf(log_path, PATH_MAX, "%s", filename); - } else { - snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); - } - - /* Rotate log file based on time */ - const char *rotate_int = ConfNodeLookupChildValue(conf, "rotate-interval"); - if (rotate_int != NULL) { - time_t now = time(NULL); - log_ctx->flags |= LOGFILE_ROTATE_INTERVAL; - - /* Use a specific time */ - if (strcmp(rotate_int, "minute") == 0) { - log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); - log_ctx->rotate_interval = 60; - } else if (strcmp(rotate_int, "hour") == 0) { - log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); - log_ctx->rotate_interval = 3600; - } else if (strcmp(rotate_int, "day") == 0) { - log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); - log_ctx->rotate_interval = 86400; - } - - /* Use a timer */ - else { - log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int); - if (log_ctx->rotate_interval == 0) { - FatalError("invalid rotate-interval value"); - } - log_ctx->rotate_time = now + log_ctx->rotate_interval; - } - } - - filetype = ConfNodeLookupChildValue(conf, "filetype"); - if (filetype == NULL) - filetype = DEFAULT_LOG_FILETYPE; - - const char *filemode = ConfNodeLookupChildValue(conf, "filemode"); - uint32_t mode = 0; - if (filemode != NULL && StringParseUint32(&mode, 8, (uint16_t)strlen(filemode), filemode) > 0) { - log_ctx->filemode = mode; - } - - const char *append = ConfNodeLookupChildValue(conf, "append"); - if (append == NULL) - append = DEFAULT_LOG_MODE_APPEND; - - /* JSON flags */ - log_ctx->json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT| - JSON_ENSURE_ASCII|JSON_ESCAPE_SLASH; - - ConfNode *json_flags = ConfNodeLookupChild(conf, "json"); - - if (json_flags != 0) { - const char *preserve_order = ConfNodeLookupChildValue(json_flags, - "preserve-order"); - if (preserve_order != NULL && ConfValIsFalse(preserve_order)) - log_ctx->json_flags &= ~(JSON_PRESERVE_ORDER); - - const char *compact = ConfNodeLookupChildValue(json_flags, "compact"); - if (compact != NULL && ConfValIsFalse(compact)) - log_ctx->json_flags &= ~(JSON_COMPACT); - - const char *ensure_ascii = ConfNodeLookupChildValue(json_flags, - "ensure-ascii"); - if (ensure_ascii != NULL && ConfValIsFalse(ensure_ascii)) - log_ctx->json_flags &= ~(JSON_ENSURE_ASCII); - - const char *escape_slash = ConfNodeLookupChildValue(json_flags, - "escape-slash"); - if (escape_slash != NULL && ConfValIsFalse(escape_slash)) - log_ctx->json_flags &= ~(JSON_ESCAPE_SLASH); - } - -#ifdef BUILD_WITH_UNIXSOCKET - if (log_ctx->threaded) { - if (strcasecmp(filetype, "unix_stream") == 0 || strcasecmp(filetype, "unix_dgram") == 0) { - FatalError("Socket file types do not support threaded output"); - } - } -#endif - // Now, what have we been asked to open? - if (strcasecmp(filetype, "unix_stream") == 0) { -#ifdef BUILD_WITH_UNIXSOCKET - /* Don't bail. May be able to connect later. */ - log_ctx->is_sock = 1; - log_ctx->sock_type = SOCK_STREAM; - log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1); -#else - return -1; -#endif - } else if (strcasecmp(filetype, "unix_dgram") == 0) { -#ifdef BUILD_WITH_UNIXSOCKET - /* Don't bail. May be able to connect later. */ - log_ctx->is_sock = 1; - log_ctx->sock_type = SOCK_DGRAM; - log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); -#else - return -1; -#endif - } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || - strcasecmp(filetype, "file") == 0) { - log_ctx->is_regular = 1; - if (!log_ctx->threaded) { - log_ctx->fp = SCLogOpenFileFp(log_path, append, log_ctx->filemode); - if (log_ctx->fp == NULL) - return -1; // Error already logged by Open...Fp routine - } else { - if (!SCLogOpenThreadedFile(log_path, append, log_ctx)) { - return -1; - } - } - if (rotate) { - OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); - } - } else { - SCLogError("Invalid entry for " - "%s.filetype. Expected \"regular\" (default), \"unix_stream\", " - "or \"unix_dgram\"", - conf->name); - } - log_ctx->filename = SCStrdup(log_path); - if (unlikely(log_ctx->filename == NULL)) { - SCLogError("Failed to allocate memory for filename"); - return -1; - } - -#ifdef BUILD_WITH_UNIXSOCKET - /* If a socket and running live, do non-blocking writes. */ - if (log_ctx->is_sock && !IsRunModeOffline(RunmodeGetCurrent())) { - SCLogInfo("Setting logging socket of non-blocking in live mode."); - log_ctx->send_flags |= MSG_DONTWAIT; - } -#endif - SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, - filename); - - return 0; -} - -/** - * \brief Reopen a regular log file with the side-affect of truncating it. - * - * This is useful to clear the log file and start a new one, or to - * re-open the file after its been moved by something external - * (eg. logrotate). - */ -int SCConfLogReopen(LogFileCtx *log_ctx) -{ - if (!log_ctx->is_regular) { - /* Not supported and not needed on non-regular files. */ - return 0; - } - - if (log_ctx->filename == NULL) { - SCLogWarning("Can't re-open LogFileCtx without a filename."); - return -1; - } - - if (log_ctx->fp != NULL) { - fclose(log_ctx->fp); - } - - /* Reopen the file. Append is forced in case the file was not - * moved as part of a rotation process. */ - SCLogDebug("Reopening log file %s.", log_ctx->filename); - log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "yes", log_ctx->filemode); - if (log_ctx->fp == NULL) { - return -1; // Already logged by Open..Fp routine. - } - - return 0; -} - -/** \brief LogFileNewCtx() Get a new LogFileCtx - * \retval LogFileCtx * pointer if successful, NULL if error - * */ -LogFileCtx *LogFileNewCtx(void) -{ - LogFileCtx* lf_ctx; - lf_ctx = (LogFileCtx*)SCCalloc(1, sizeof(LogFileCtx)); - - if (lf_ctx == NULL) - return NULL; - - lf_ctx->Write = SCLogFileWrite; - lf_ctx->Close = SCLogFileClose; - - return lf_ctx; -} - -/** \brief LogFileThread2Slot() Return a file entry - * \retval ThreadLogFileHashEntry * file entry for caller - * - * This function returns the file entry for the calling thread. - * Each thread -- identified by its operating system thread-id -- has its - * own file entry that includes a file pointer. - */ -static ThreadLogFileHashEntry *LogFileThread2Slot(LogThreadedFileCtx *parent) -{ - ThreadLogFileHashEntry thread_hash_entry; - - /* Check hash table for thread id*/ - thread_hash_entry.thread_id = SCGetThreadIdLong(); - ThreadLogFileHashEntry *ent = - HashTableLookup(parent->ht, &thread_hash_entry, sizeof(thread_hash_entry)); - - if (!ent) { - ent = SCCalloc(1, sizeof(*ent)); - if (!ent) { - FatalError("Unable to allocate thread/entry entry"); - } - ent->thread_id = thread_hash_entry.thread_id; - SCLogDebug("Trying to add thread %ld to entry %d", ent->thread_id, ent->slot_number); - if (0 != HashTableAdd(parent->ht, ent, 0)) { - FatalError("Unable to add thread/entry mapping"); - } - } - return ent; -} - -/** \brief LogFileEnsureExists() Ensure a log file context for the thread exists - * \param parent_ctx - * \retval LogFileCtx * pointer if successful; NULL otherwise - */ -LogFileCtx *LogFileEnsureExists(LogFileCtx *parent_ctx) -{ - /* threaded output disabled */ - if (!parent_ctx->threaded) - return parent_ctx; - - SCMutexLock(&parent_ctx->threads->mutex); - /* Find this thread's entry */ - ThreadLogFileHashEntry *entry = LogFileThread2Slot(parent_ctx->threads); - SCLogDebug("Adding reference for thread %ld [slot %d] to file %s [ctx %p]", SCGetThreadIdLong(), - entry->slot_number, parent_ctx->filename, parent_ctx); - - bool new = entry->isopen; - /* has it been opened yet? */ - if (!entry->isopen) { - SCLogDebug("Opening new file for thread/slot %d to file %s [ctx %p]", entry->slot_number, - parent_ctx->filename, parent_ctx); - if (LogFileNewThreadedCtx( - parent_ctx, parent_ctx->filename, parent_ctx->threads->append, entry)) { - entry->isopen = true; - } else { - SCLogError( - "Unable to open slot %d for file %s", entry->slot_number, parent_ctx->filename); - (void)HashTableRemove(parent_ctx->threads->ht, entry, 0); - } - } - SCMutexUnlock(&parent_ctx->threads->mutex); - - if (sc_log_global_log_level >= SC_LOG_DEBUG) { - if (new) { - SCLogDebug("Existing file for thread/entry %p reference to file %s [ctx %p]", entry, - parent_ctx->filename, parent_ctx); - } - } - - return entry->ctx; -} - -/** \brief LogFileThreadedName() Create file name for threaded EVE storage - * - */ -static bool LogFileThreadedName( - const char *original_name, char *threaded_name, size_t len, uint32_t unique_id) -{ - sc_errno = SC_OK; - - if (strcmp("/dev/null", original_name) == 0) { - strlcpy(threaded_name, original_name, len); - return true; - } - - const char *base = SCBasename(original_name); - if (!base) { - FatalError("Invalid filename for threaded mode \"%s\"; " - "no basename found.", - original_name); - } - - /* Check if basename has an extension */ - char *dot = strrchr(base, '.'); - if (dot) { - char *tname = SCStrdup(original_name); - if (!tname) { - sc_errno = SC_ENOMEM; - return false; - } - - /* Fetch extension location from original, not base - * for update - */ - dot = strrchr(original_name, '.'); - int dotpos = dot - original_name; - tname[dotpos] = '\0'; - char *ext = tname + dotpos + 1; - if (strlen(tname) && strlen(ext)) { - snprintf(threaded_name, len, "%s.%u.%s", tname, unique_id, ext); - } else { - FatalError("Invalid filename for threaded mode \"%s\"; " - "filenames must include an extension, e.g: \"name.ext\"", - original_name); - } - SCFree(tname); - } else { - snprintf(threaded_name, len, "%s.%u", original_name, unique_id); - } - return true; -} - -/** \brief LogFileNewThreadedCtx() Create file context for threaded output - * \param parent_ctx - * \param log_path - * \param append - * \param entry - */ -static bool LogFileNewThreadedCtx(LogFileCtx *parent_ctx, const char *log_path, const char *append, - ThreadLogFileHashEntry *entry) -{ - LogFileCtx *thread = SCCalloc(1, sizeof(LogFileCtx)); - if (!thread) { - SCLogError("Unable to allocate thread file context entry %p", entry); - return false; - } - - *thread = *parent_ctx; - if (parent_ctx->type == LOGFILE_TYPE_FILE) { - char fname[LOGFILE_NAME_MAX]; - if (!LogFileThreadedName(log_path, fname, sizeof(fname), SC_ATOMIC_ADD(eve_file_id, 1))) { - SCLogError("Unable to create threaded filename for log"); - goto error; - } - SCLogDebug("Thread open -- using name %s [replaces %s]", fname, log_path); - thread->fp = SCLogOpenFileFp(fname, append, thread->filemode); - if (thread->fp == NULL) { - goto error; - } - thread->filename = SCStrdup(fname); - if (!thread->filename) { - SCLogError("Unable to duplicate filename for context entry %p", entry); - goto error; - } - thread->is_regular = true; - thread->Write = SCLogFileWriteNoLock; - thread->Close = SCLogFileCloseNoLock; - OutputRegisterFileRotationFlag(&thread->rotation_flag); - } else if (parent_ctx->type == LOGFILE_TYPE_PLUGIN) { - entry->slot_number = SC_ATOMIC_ADD(eve_file_id, 1); - thread->plugin.plugin->ThreadInit( - thread->plugin.init_data, entry->slot_number, &thread->plugin.thread_data); - } - thread->threaded = false; - thread->parent = parent_ctx; - thread->entry = entry; - entry->ctx = thread; - - return true; - -error: - if (parent_ctx->type == LOGFILE_TYPE_FILE) { - SC_ATOMIC_SUB(eve_file_id, 1); - if (thread->fp) { - thread->Close(thread); - } - } - - if (thread) { - SCFree(thread); - } - return false; -} - -/** \brief LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory) - * \param lf_ctx pointer to the OutputCtx - * \retval int 1 if successful, 0 if error - * */ -int LogFileFreeCtx(LogFileCtx *lf_ctx) -{ - if (lf_ctx == NULL) { - SCReturnInt(0); - } - - if (lf_ctx->type == LOGFILE_TYPE_PLUGIN && lf_ctx->parent != NULL) { - lf_ctx->plugin.plugin->ThreadDeinit(lf_ctx->plugin.init_data, lf_ctx->plugin.thread_data); - } - - if (lf_ctx->threaded) { - BUG_ON(lf_ctx->threads == NULL); - SCMutexDestroy(&lf_ctx->threads->mutex); - if (lf_ctx->threads->append) - SCFree(lf_ctx->threads->append); - if (lf_ctx->threads->ht) { - HashTableFree(lf_ctx->threads->ht); - } - SCFree(lf_ctx->threads); - } else { - if (lf_ctx->type != LOGFILE_TYPE_PLUGIN) { - if (lf_ctx->fp != NULL) { - lf_ctx->Close(lf_ctx); - } - } - SCMutexDestroy(&lf_ctx->fp_mutex); - } - - if (lf_ctx->prefix != NULL) { - SCFree(lf_ctx->prefix); - lf_ctx->prefix_len = 0; - } - - if(lf_ctx->filename != NULL) - SCFree(lf_ctx->filename); - - if (lf_ctx->sensor_name) - SCFree(lf_ctx->sensor_name); - - if (!lf_ctx->threaded) { - OutputUnregisterFileRotationFlag(&lf_ctx->rotation_flag); - } - - /* Deinitialize output plugins. We only want to call this for the - * parent of threaded output, or always for non-threaded - * output. */ - if (lf_ctx->type == LOGFILE_TYPE_PLUGIN && lf_ctx->parent == NULL) { - lf_ctx->plugin.plugin->Deinit(lf_ctx->plugin.init_data); - } - - memset(lf_ctx, 0, sizeof(*lf_ctx)); - SCFree(lf_ctx); - - SCReturnInt(1); -} - -int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer) -{ - if (file_ctx->type == LOGFILE_TYPE_FILE || file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || - file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) { - /* append \n for files only */ - MemBufferWriteString(buffer, "\n"); - file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), - MEMBUFFER_OFFSET(buffer), file_ctx); - } else if (file_ctx->type == LOGFILE_TYPE_PLUGIN) { - file_ctx->plugin.plugin->Write((const char *)MEMBUFFER_BUFFER(buffer), - MEMBUFFER_OFFSET(buffer), file_ctx->plugin.init_data, file_ctx->plugin.thread_data); - } -#ifdef HAVE_LIBHIREDIS - else if (file_ctx->type == LOGFILE_TYPE_REDIS) { - SCMutexLock(&file_ctx->fp_mutex); - LogFileWriteRedis(file_ctx, (const char *)MEMBUFFER_BUFFER(buffer), - MEMBUFFER_OFFSET(buffer)); - SCMutexUnlock(&file_ctx->fp_mutex); - } -#endif - - return 0; -} diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h deleted file mode 100644 index bbb5211cda77..000000000000 --- a/src/util-logopenfile.h +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Mike Pomraning - */ - -#ifndef __UTIL_LOGOPENFILE_H__ -#define __UTIL_LOGOPENFILE_H__ - -#include "threads.h" -#include "conf.h" /* ConfNode */ -#include "util-buffer.h" -#include "util-hash.h" - -#ifdef HAVE_LIBHIREDIS -#include "util-log-redis.h" -#endif /* HAVE_LIBHIREDIS */ - -#include "suricata-plugin.h" - -enum LogFileType { - LOGFILE_TYPE_FILE, - LOGFILE_TYPE_UNIX_DGRAM, - LOGFILE_TYPE_UNIX_STREAM, - LOGFILE_TYPE_REDIS, - LOGFILE_TYPE_PLUGIN, - LOGFILE_TYPE_NOTSET -}; - -typedef struct SyslogSetup_ { - int alert_syslog_level; -} SyslogSetup; - -typedef struct ThreadLogFileHashEntry { - uint64_t thread_id; - int slot_number; /* slot identifier -- for plugins */ - bool isopen; - struct LogFileCtx_ *ctx; -} ThreadLogFileHashEntry; - -struct LogFileCtx_; -typedef struct LogThreadedFileCtx_ { - SCMutex mutex; - HashTable *ht; - char *append; -} LogThreadedFileCtx; - -typedef struct LogFilePluginCtx_ { - SCEveFileType *plugin; - void *init_data; - void *thread_data; -} LogFilePluginCtx; - -/** Global structure for Output Context */ -typedef struct LogFileCtx_ { - union { - FILE *fp; -#ifdef HAVE_LIBHIREDIS - void *redis; -#endif - }; - LogThreadedFileCtx *threads; - - union { -#ifdef HAVE_LIBHIREDIS - RedisSetup redis_setup; -#endif - }; - - int (*Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp); - void (*Close)(struct LogFileCtx_ *fp); - - LogFilePluginCtx plugin; - - /** It will be locked if the log/alert - * record cannot be written to the file in one call */ - SCMutex fp_mutex; - - /** When threaded, track of the parent and thread id */ - bool threaded; - struct LogFileCtx_ *parent; - ThreadLogFileHashEntry *entry; - - /** the type of file */ - enum LogFileType type; - - /** The name of the file */ - char *filename; - - /** File permissions */ - uint32_t filemode; - - /** Suricata sensor name */ - char *sensor_name; - - /** Handle auto-connecting / reconnecting sockets */ - int is_sock; - int sock_type; - uint64_t reconn_timer; - - /** The next time to rotate log file, if rotate interval is - specified. */ - time_t rotate_time; - - /** The interval to rotate the log file */ - uint64_t rotate_interval; - - /**< Used by some alert loggers like the unified ones that append - * the date onto the end of files. */ - char *prefix; - size_t prefix_len; - - /** Generic size_limit and size_current - * They must be common to the threads accessing the same file */ - uint64_t size_limit; /**< file size limit */ - uint64_t size_current; /**< file current size */ - - /* flag to avoid multiple threads printing the same stats */ - uint8_t flags; - - /* flags to set when sending over a socket */ - uint8_t send_flags; - - /* Flag if file is a regular file or not. Only regular files - * allow for rotation. */ - uint8_t is_regular; - - /* JSON flags */ - size_t json_flags; /* passed to json_dump_callback() */ - - /* Flag set when file rotation notification is received. */ - int rotation_flag; - - /* if set to true EVE will add a pcap file record */ - bool is_pcap_offline; - - /* Socket types may need to drop events to keep from blocking - * Suricata. */ - uint64_t dropped; - - uint64_t output_errors; -} LogFileCtx; - -/* Min time (msecs) before trying to reconnect a Unix domain socket */ -#define LOGFILE_RECONN_MIN_TIME 500 - -/* flags for LogFileCtx */ -#define LOGFILE_ROTATE_INTERVAL 0x04 - -LogFileCtx *LogFileNewCtx(void); -int LogFileFreeCtx(LogFileCtx *); -int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer); - -LogFileCtx *LogFileEnsureExists(LogFileCtx *lf_ctx); -int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *, int); -int SCConfLogReopen(LogFileCtx *); -bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx); - -#endif /* __UTIL_LOGOPENFILE_H__ */ diff --git a/src/util-lua-common.c b/src/util-lua-common.c deleted file mode 100644 index bb0f7899eb84..000000000000 --- a/src/util-lua-common.c +++ /dev/null @@ -1,1010 +0,0 @@ -/* Copyright (C) 2014-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Common function for Lua Output - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer-htp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "util-conf.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "action-globals.h" - -int LuaCallbackError(lua_State *luastate, const char *msg) -{ - lua_pushnil(luastate); - lua_pushstring(luastate, msg); - return 2; -} - -const char *LuaGetStringArgument(lua_State *luastate, int argc) -{ - /* get argument */ - if (!lua_isstring(luastate, argc)) - return NULL; - const char *str = lua_tostring(luastate, argc); - if (str == NULL) - return NULL; - if (strlen(str) == 0) - return NULL; - return str; -} - -void LuaPushTableKeyValueInt(lua_State *luastate, const char *key, int value) -{ - lua_pushstring(luastate, key); - lua_pushnumber(luastate, value); - lua_settable(luastate, -3); -} - -/** \brief Push a key plus string value to the stack - * - * If value is NULL, string "(null")" will be put on the stack. - */ -void LuaPushTableKeyValueString(lua_State *luastate, const char *key, const char *value) -{ - lua_pushstring(luastate, key); - lua_pushstring(luastate, value ? value : "(null)"); - lua_settable(luastate, -3); -} - -void LuaPushTableKeyValueArray(lua_State *luastate, const char *key, const uint8_t *value, size_t len) -{ - lua_pushstring(luastate, key); - LuaPushStringBuffer(luastate, value, len); - lua_settable(luastate, -3); -} - -/** \internal - * \brief fill lua stack with payload - * \param luastate the lua state - * \param p packet - * \retval cnt number of data items placed on the stack - * - * Places: payload (string), open (bool), close (bool), toserver (bool), toclient (bool) - */ -static int LuaCallbackStreamingBufferPushToStack(lua_State *luastate, const LuaStreamingBuffer *b) -{ - //PrintRawDataFp(stdout, (uint8_t *)b->data, b->data_len); - lua_pushlstring (luastate, (const char *)b->data, b->data_len); - lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_OPEN)); - lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_CLOSE)); - lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_TOSERVER)); - lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_TOCLIENT)); - return 5; -} - -/** \internal - * \brief Wrapper for getting payload into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackStreamingBuffer(lua_State *luastate) -{ - const LuaStreamingBuffer *b = LuaStateGetStreamingBuffer(luastate); - if (b == NULL) - return LuaCallbackError(luastate, "internal error: no buffer"); - - return LuaCallbackStreamingBufferPushToStack(luastate, b); -} - -/** \internal - * \brief fill lua stack with payload - * \param luastate the lua state - * \param p packet - * \retval cnt number of data items placed on the stack - * - * Places: payload (string) - */ -static int LuaCallbackPacketPayloadPushToStackFromPacket(lua_State *luastate, const Packet *p) -{ - lua_pushlstring (luastate, (const char *)p->payload, p->payload_len); - return 1; -} - -/** \internal - * \brief Wrapper for getting payload into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackPacketPayload(lua_State *luastate) -{ - const Packet *p = LuaStateGetPacket(luastate); - if (p == NULL) - return LuaCallbackError(luastate, "internal error: no packet"); - - return LuaCallbackPacketPayloadPushToStackFromPacket(luastate, p); -} - -/** \internal - * \brief fill lua stack with packet timestamp - * \param luastate the lua state - * \param p packet - * \retval cnt number of data items placed on the stack - * - * Places: seconds (number), microseconds (number) - */ -static int LuaCallbackTimestampPushToStack(lua_State *luastate, const SCTime_t ts) -{ - lua_pushnumber(luastate, (double)SCTIME_SECS(ts)); - lua_pushnumber(luastate, (double)SCTIME_USECS(ts)); - return 2; -} - -/** \internal - * \brief fill lua stack with header info - * \param luastate the lua state - * \param p packet - * \retval cnt number of data items placed on the stack - * - * Places: ts (string) - */ -static int LuaCallbackTimeStringPushToStackFromPacket(lua_State *luastate, const Packet *p) -{ - char timebuf[64]; - CreateTimeString(p->ts, timebuf, sizeof(timebuf)); - lua_pushstring (luastate, timebuf); - return 1; -} - -/** \internal - * \brief Wrapper for getting packet timestamp (as numbers) into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackPacketTimestamp(lua_State *luastate) -{ - const Packet *p = LuaStateGetPacket(luastate); - if (p == NULL) - return LuaCallbackError(luastate, "internal error: no packet"); - - return LuaCallbackTimestampPushToStack(luastate, p->ts); -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackPacketTimeString(lua_State *luastate) -{ - const Packet *p = LuaStateGetPacket(luastate); - if (p == NULL) - return LuaCallbackError(luastate, "internal error: no packet"); - - return LuaCallbackTimeStringPushToStackFromPacket(luastate, p); -} - -/** \internal - * \brief fill lua stack with flow timestamps - * \param luastate the lua state - * \param startts timestamp of first packet in the flow - * \param lastts timestamp of last packet in the flow - * \retval cnt number of data items placed on the stack - * - * Places: seconds (number), seconds (number), microseconds (number), - * microseconds (number) - */ -static int LuaCallbackFlowTimestampsPushToStack( - lua_State *luastate, const SCTime_t startts, const SCTime_t lastts) -{ - lua_pushnumber(luastate, (double)SCTIME_SECS(startts)); - lua_pushnumber(luastate, (double)SCTIME_SECS(lastts)); - lua_pushnumber(luastate, (double)SCTIME_USECS(startts)); - lua_pushnumber(luastate, (double)SCTIME_USECS(lastts)); - return 4; -} - -/** \internal - * \brief Wrapper for getting flow timestamp (as numbers) into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackFlowTimestamps(lua_State *luastate) -{ - Flow *flow = LuaStateGetFlow(luastate); - if (flow == NULL) { - return LuaCallbackError(luastate, "internal error: no flow"); - } - - return LuaCallbackFlowTimestampsPushToStack(luastate, flow->startts, flow->lastts); -} - -/** \internal - * \brief fill lua stack with time string - * \param luastate the lua state - * \param flow flow - * \retval cnt number of data items placed on the stack - * - * Places: ts (string) - */ -static int LuaCallbackTimeStringPushToStackFromFlow(lua_State *luastate, const Flow *flow) -{ - char timebuf[64]; - CreateTimeString(flow->startts, timebuf, sizeof(timebuf)); - lua_pushstring (luastate, timebuf); - return 1; -} - -/** \internal - * \brief Wrapper for getting ts info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackFlowTimeString(lua_State *luastate) -{ - int r = 0; - Flow *flow = LuaStateGetFlow(luastate); - if (flow == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); - - return r; -} - -/** \internal - * \brief fill lua stack with flow has alerts - * \param luastate the lua state - * \param flow flow - * \retval cnt number of data items placed on the stack - * - * Places alerts (bool) - */ -static int LuaCallbackHasAlertsPushToStackFromFlow(lua_State *luastate, const Flow *flow) -{ - lua_pushboolean(luastate, FlowHasAlerts(flow)); - - return 1; -} - -/** \internal - * \brief Wrapper for getting flow has alerts info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackFlowHasAlerts(lua_State *luastate) -{ - int r = 0; - Flow *flow = LuaStateGetFlow(luastate); - if (flow == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = LuaCallbackHasAlertsPushToStackFromFlow(luastate, flow); - - return r; -} - -/** \internal - * \brief fill lua stack with header info - * \param luastate the lua state - * \param p packet - * \retval cnt number of data items placed on the stack - * - * Places: ipver (number), src ip (string), dst ip (string), protocol (number), - * sp or icmp type (number), dp or icmp code (number). - */ -static int LuaCallbackTuplePushToStackFromPacket(lua_State *luastate, const Packet *p) -{ - int ipver = 0; - if (PKT_IS_IPV4(p)) { - ipver = 4; - } else if (PKT_IS_IPV6(p)) { - ipver = 6; - } - lua_pushinteger(luastate, ipver); - if (ipver == 0) - return 1; - - char srcip[46] = "", dstip[46] = ""; - if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); - } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); - } - - lua_pushstring (luastate, srcip); - lua_pushstring (luastate, dstip); - - /* proto and ports (or type/code) */ - lua_pushinteger(luastate, p->proto); - if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP) { - lua_pushinteger(luastate, p->sp); - lua_pushinteger(luastate, p->dp); - - } else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) { - lua_pushinteger(luastate, p->icmp_s.type); - lua_pushinteger(luastate, p->icmp_s.code); - } else { - lua_pushinteger(luastate, 0); - lua_pushinteger(luastate, 0); - } - - return 6; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackTuple(lua_State *luastate) -{ - const Packet *p = LuaStateGetPacket(luastate); - if (p == NULL) - return LuaCallbackError(luastate, "internal error: no packet"); - - return LuaCallbackTuplePushToStackFromPacket(luastate, p); -} - -/** \internal - * \brief fill lua stack with header info - * \param luastate the lua state - * \param f flow, locked - * \retval cnt number of data items placed on the stack - * - * Places: ipver (number), src ip (string), dst ip (string), protocol (number), - * sp or icmp type (number), dp or icmp code (number). - */ -static int LuaCallbackTuplePushToStackFromFlow(lua_State *luastate, const Flow *f) -{ - int ipver = 0; - if (FLOW_IS_IPV4(f)) { - ipver = 4; - } else if (FLOW_IS_IPV6(f)) { - ipver = 6; - } - lua_pushinteger(luastate, ipver); - if (ipver == 0) - return 1; - - char srcip[46] = "", dstip[46] = ""; - if (FLOW_IS_IPV4(f)) { - PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), dstip, sizeof(dstip)); - } else if (FLOW_IS_IPV6(f)) { - PrintInet(AF_INET6, (const void *)&(f->src.address), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)&(f->dst.address), dstip, sizeof(dstip)); - } - - lua_pushstring (luastate, srcip); - lua_pushstring (luastate, dstip); - - /* proto and ports (or type/code) */ - lua_pushinteger(luastate, f->proto); - if (f->proto == IPPROTO_TCP || f->proto == IPPROTO_UDP) { - lua_pushinteger(luastate, f->sp); - lua_pushinteger(luastate, f->dp); - - } else if (f->proto == IPPROTO_ICMP || f->proto == IPPROTO_ICMPV6) { - lua_pushinteger(luastate, f->icmp_s.type); - lua_pushinteger(luastate, f->icmp_s.code); - } else { - lua_pushinteger(luastate, 0); - lua_pushinteger(luastate, 0); - } - - return 6; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackTupleFlow(lua_State *luastate) -{ - int r = 0; - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = LuaCallbackTuplePushToStackFromFlow(luastate, f); - - return r; -} - -/** \internal - * \brief fill lua stack with AppLayerProto - * \param luastate the lua state - * \param alproto AppProto to push to stack as string - * \retval cnt number of data items placed on the stack - * - * Places: alproto as string (string) - */ -static int LuaCallbackAppLayerProtoPushToStackFromFlow(lua_State *luastate, const AppProto alproto) -{ - const char *string = AppProtoToString(alproto); - if (string == NULL) - string = "unknown"; - lua_pushstring(luastate, string); - return 1; -} - -/** \internal - * \brief Wrapper for getting AppLayerProto info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackAppLayerProtoFlow(lua_State *luastate) -{ - int r = 0; - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto); - r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_ts); - r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_tc); - r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_orig); - r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_expect); - - return r; -} - -/** \internal - * \brief fill lua stack with flow stats - * \param luastate the lua state - * \param f flow, locked - * \retval cnt number of data items placed on the stack - * - * Places: ts pkts (number), ts bytes (number), tc pkts (number), tc bytes (number) - */ -static int LuaCallbackStatsPushToStackFromFlow(lua_State *luastate, const Flow *f) -{ - lua_pushinteger(luastate, f->todstpktcnt); - lua_pushinteger(luastate, f->todstbytecnt); - lua_pushinteger(luastate, f->tosrcpktcnt); - lua_pushinteger(luastate, f->tosrcbytecnt); - return 4; -} - -/** \internal - * \brief Wrapper for getting AppLayerProto info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackStatsFlow(lua_State *luastate) -{ - int r = 0; - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = LuaCallbackStatsPushToStackFromFlow(luastate, f); - - return r; -} - -/** \internal - * \brief fill lua stack with flow id - * \param luastate the lua state - * \param f flow, locked - * \retval cnt number of data items placed on the stack - * - * Places: flow id (number) - */ -static int LuaCallbackPushFlowIdToStackFromFlow(lua_State *luastate, const Flow *f) -{ - int64_t id = FlowGetId(f); - lua_pushinteger(luastate, id); - return 1; -} - -/** \internal - * \brief Wrapper for getting FlowId into lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackFlowId(lua_State *luastate) -{ - int r = 0; - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = LuaCallbackPushFlowIdToStackFromFlow(luastate, f); - - return r; -} - -/** \internal - * \brief fill lua stack with signature info - * \param luastate the lua state - * \param s pointer to signature struct - * \retval cnt number of data items placed on the stack - * - * Places: sid (number), rev (number), gid (number) - */ -static int LuaCallbackRuleIdsPushToStackFromSignature(lua_State *luastate, const Signature *s) -{ - lua_pushinteger(luastate, s->id); - lua_pushinteger(luastate, s->rev); - lua_pushinteger(luastate, s->gid); - return 3; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - * - * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) - * otherwise pulled from Signature in lua registry (for match scripts) - */ -static int LuaCallbackRuleIds(lua_State *luastate) -{ - const Signature *s = NULL; - const PacketAlert *pa = LuaStateGetPacketAlert(luastate); - if (pa != NULL) { - s = pa->s; - } else { - s = LuaStateGetSignature(luastate); - if (s == NULL) - return LuaCallbackError(luastate, "internal error: no packet alert or signature"); - } - return LuaCallbackRuleIdsPushToStackFromSignature(luastate, s); -} - -/** \internal - * \brief fill lua stack with signature info - * \param luastate the lua state - * \param s pointer to signature struct - * \retval cnt number of data items placed on the stack - * - * Places: action (string) - */ -static int LuaCallbackRuleActionPushToStackFromSignature(lua_State *luastate, const Signature *s) -{ - const char *action = ""; - if (s->action & ACTION_PASS) { - action = "pass"; - } else if ((s->action & ACTION_REJECT) || (s->action & ACTION_REJECT_BOTH) || - (s->action & ACTION_REJECT_DST)) { - action = "reject"; - } else if (s->action & ACTION_DROP) { - action = "drop"; - } else if (s->action & ACTION_ALERT) { - action = "alert"; - } - lua_pushstring(luastate, action); - return 1; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - * - * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) - * otherwise pulled from Signature in lua registry (for match scripts) - */ -static int LuaCallbackRuleAction(lua_State *luastate) -{ - const Signature *s = NULL; - const PacketAlert *pa = LuaStateGetPacketAlert(luastate); - if (pa != NULL) { - s = pa->s; - } else { - s = LuaStateGetSignature(luastate); - if (s == NULL) - return LuaCallbackError(luastate, "internal error: no packet alert or signature"); - } - return LuaCallbackRuleActionPushToStackFromSignature(luastate, s); -} - -/** \internal - * \brief fill lua stack with signature info - * \param luastate the lua state - * \param s pointer to signature struct - * \retval cnt number of data items placed on the stack - * - * Places: msg (string) - */ -static int LuaCallbackRuleMsgPushToStackFromSignature(lua_State *luastate, const Signature *s) -{ - lua_pushstring(luastate, s->msg); - return 1; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - * - * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) - * otherwise pulled from Signature in lua registry (for match scripts) - */ -static int LuaCallbackRuleMsg(lua_State *luastate) -{ - const Signature *s = NULL; - const PacketAlert *pa = LuaStateGetPacketAlert(luastate); - if (pa != NULL) { - s = pa->s; - } else { - s = LuaStateGetSignature(luastate); - if (s == NULL) - return LuaCallbackError(luastate, "internal error: no packet alert or signature"); - } - return LuaCallbackRuleMsgPushToStackFromSignature(luastate, s); -} - -/** \internal - * \brief fill lua stack with signature info - * \param luastate the lua state - * \param s pointer to signature struct - * \retval cnt number of data items placed on the stack - * - * Places: class (string), prio (number) - */ -static int LuaCallbackRuleClassPushToStackFromSignature(lua_State *luastate, const Signature *s) -{ - lua_pushstring(luastate, s->class_msg); - lua_pushinteger(luastate, s->prio); - return 2; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - * - * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) - * otherwise pulled from Signature in lua registry (for match scripts) - */ -static int LuaCallbackRuleClass(lua_State *luastate) -{ - const Signature *s = NULL; - const PacketAlert *pa = LuaStateGetPacketAlert(luastate); - if (pa != NULL) { - s = pa->s; - } else { - s = LuaStateGetSignature(luastate); - if (s == NULL) - return LuaCallbackError(luastate, "internal error: no packet alert or signature"); - } - return LuaCallbackRuleClassPushToStackFromSignature(luastate, s); -} - -static int LuaCallbackLogPath(lua_State *luastate) -{ - const char *ld = ConfigGetLogDirectory(); - if (ld == NULL) - return LuaCallbackError(luastate, "internal error: no log dir"); - - return LuaPushStringBuffer(luastate, (const uint8_t *)ld, strlen(ld)); -} - -static int LuaCallbackLogDebug(lua_State *luastate) -{ - const char *msg = LuaGetStringArgument(luastate, 1); - if (msg == NULL) - return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogDebug("%s", msg); - return 0; -} - -static int LuaCallbackLogInfo(lua_State *luastate) -{ - const char *msg = LuaGetStringArgument(luastate, 1); - if (msg == NULL) - return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - - lua_Debug ar; - lua_getstack(luastate, 1, &ar); - lua_getinfo(luastate, "nSl", &ar); - const char *funcname = ar.name ? ar.name : ar.what; - SCLogInfoRaw(ar.short_src, funcname, ar.currentline, "%s", msg); - return 0; -} - -static int LuaCallbackLogNotice(lua_State *luastate) -{ - const char *msg = LuaGetStringArgument(luastate, 1); - if (msg == NULL) - return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - - lua_Debug ar; - lua_getstack(luastate, 1, &ar); - lua_getinfo(luastate, "nSl", &ar); - const char *funcname = ar.name ? ar.name : ar.what; - SCLogNoticeRaw(ar.short_src, funcname, ar.currentline, "%s", msg); - return 0; -} - -static int LuaCallbackLogWarning(lua_State *luastate) -{ - const char *msg = LuaGetStringArgument(luastate, 1); - if (msg == NULL) - return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - - lua_Debug ar; - lua_getstack(luastate, 1, &ar); - lua_getinfo(luastate, "nSl", &ar); - const char *funcname = ar.name ? ar.name : ar.what; - SCLogWarningRaw(ar.short_src, funcname, ar.currentline, "%s", msg); - return 0; -} - -static int LuaCallbackLogError(lua_State *luastate) -{ - const char *msg = LuaGetStringArgument(luastate, 1); - if (msg == NULL) - return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - lua_Debug ar; - lua_getstack(luastate, 1, &ar); - lua_getinfo(luastate, "nSl", &ar); - const char *funcname = ar.name ? ar.name : ar.what; - SCLogErrorRaw(ar.short_src, funcname, ar.currentline, "%s", msg); - return 0; -} - -/** \internal - * \brief fill lua stack with file info - * \param luastate the lua state - * \param pa pointer to packet alert struct - * \retval cnt number of data items placed on the stack - * - * Places: fileid (number), txid (number), name (string), - * size (number), magic (string), md5 in hex (string), - * sha1 (string), sha256 (string) - */ -static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const File *file) -{ - char *md5ptr = NULL; - char *sha1ptr = NULL; - char *sha256ptr = NULL; - - char md5[33] = ""; - md5ptr = md5; - if (file->flags & FILE_MD5) { - size_t x; - for (x = 0; x < sizeof(file->md5); x++) { - char one[3] = ""; - snprintf(one, sizeof(one), "%02x", file->md5[x]); - strlcat(md5, one, sizeof(md5)); - } - } - char sha1[41] = ""; - sha1ptr = sha1; - if (file->flags & FILE_SHA1) { - size_t x; - for (x = 0; x < sizeof(file->sha1); x++) { - char one[3] = ""; - snprintf(one, sizeof(one), "%02x", file->sha1[x]); - strlcat(sha1, one, sizeof(sha1)); - } - } - char sha256[65] = ""; - sha256ptr = sha256; - if (file->flags & FILE_SHA256) { - size_t x; - for (x = 0; x < sizeof(file->sha256); x++) { - char one[3] = ""; - snprintf(one, sizeof(one), "%02x", file->sha256[x]); - strlcat(sha256, one, sizeof(sha256)); - } - } - - lua_Integer tx_id = LuaStateGetTxId(luastate); - lua_pushinteger(luastate, file->file_store_id); - lua_pushinteger(luastate, tx_id); - lua_pushlstring(luastate, (char *)file->name, file->name_len); - lua_pushinteger(luastate, FileTrackedSize(file)); - lua_pushstring (luastate, -#ifdef HAVE_MAGIC - file->magic -#else - "nomagic" -#endif - ); - lua_pushstring(luastate, md5ptr); - lua_pushstring(luastate, sha1ptr); - lua_pushstring(luastate, sha256ptr); - return 8; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackFileInfo(lua_State *luastate) -{ - const File *file = LuaStateGetFile(luastate); - if (file == NULL) - return LuaCallbackError(luastate, "internal error: no file"); - - return LuaCallbackFileInfoPushToStackFromFile(luastate, file); -} - -/** \internal - * \brief fill lua stack with file info - * \param luastate the lua state - * \param pa pointer to packet alert struct - * \retval cnt number of data items placed on the stack - * - * Places: state (string), stored (bool) - */ -static int LuaCallbackFileStatePushToStackFromFile(lua_State *luastate, const File *file) -{ - const char *state = "UNKNOWN"; - switch (file->state) { - case FILE_STATE_CLOSED: - state = "CLOSED"; - break; - case FILE_STATE_TRUNCATED: - state = "TRUNCATED"; - break; - case FILE_STATE_ERROR: - state = "ERROR"; - break; - case FILE_STATE_OPENED: - state = "OPENED"; - break; - case FILE_STATE_NONE: - state = "NONE"; - break; - case FILE_STATE_MAX: - break; - } - - lua_pushstring (luastate, state); - lua_pushboolean (luastate, file->flags & FILE_STORED); - return 2; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackFileState(lua_State *luastate) -{ - const File *file = LuaStateGetFile(luastate); - if (file == NULL) - return LuaCallbackError(luastate, "internal error: no file"); - - return LuaCallbackFileStatePushToStackFromFile(luastate, file); -} - -/** \internal - * \brief fill lua stack with thread info - * \param luastate the lua state - * \param pa pointer to packet alert struct - * \retval cnt number of data items placed on the stack - * - * Places: thread id (number), thread name (string, thread group name (string) - */ -static int LuaCallbackThreadInfoPushToStackFromThreadVars(lua_State *luastate, const ThreadVars *tv) -{ - unsigned long tid = SCGetThreadIdLong(); - lua_pushinteger (luastate, (lua_Integer)tid); - lua_pushstring (luastate, tv->name); - lua_pushstring (luastate, tv->thread_group_name); - return 3; -} - -/** \internal - * \brief Wrapper for getting tuple info into a lua script - * \retval cnt number of items placed on the stack - */ -static int LuaCallbackThreadInfo(lua_State *luastate) -{ - const ThreadVars *tv = LuaStateGetThreadVars(luastate); - if (tv == NULL) - return LuaCallbackError(luastate, "internal error: no tv"); - - return LuaCallbackThreadInfoPushToStackFromThreadVars(luastate, tv); -} - -int LuaRegisterFunctions(lua_State *luastate) -{ - /* registration of the callbacks */ - lua_pushcfunction(luastate, LuaCallbackPacketPayload); - lua_setglobal(luastate, "SCPacketPayload"); - lua_pushcfunction(luastate, LuaCallbackPacketTimestamp); - lua_setglobal(luastate, "SCPacketTimestamp"); - lua_pushcfunction(luastate, LuaCallbackPacketTimeString); - lua_setglobal(luastate, "SCPacketTimeString"); - lua_pushcfunction(luastate, LuaCallbackTuple); - lua_setglobal(luastate, "SCPacketTuple"); - - lua_pushcfunction(luastate, LuaCallbackFlowTimestamps); - lua_setglobal(luastate, "SCFlowTimestamps"); - lua_pushcfunction(luastate, LuaCallbackFlowTimeString); - lua_setglobal(luastate, "SCFlowTimeString"); - lua_pushcfunction(luastate, LuaCallbackTupleFlow); - lua_setglobal(luastate, "SCFlowTuple"); - lua_pushcfunction(luastate, LuaCallbackAppLayerProtoFlow); - lua_setglobal(luastate, "SCFlowAppLayerProto"); - lua_pushcfunction(luastate, LuaCallbackStatsFlow); - lua_setglobal(luastate, "SCFlowStats"); - lua_pushcfunction(luastate, LuaCallbackFlowHasAlerts); - lua_setglobal(luastate, "SCFlowHasAlerts"); - lua_pushcfunction(luastate, LuaCallbackFlowId); - lua_setglobal(luastate, "SCFlowId"); - - lua_pushcfunction(luastate, LuaCallbackStreamingBuffer); - lua_setglobal(luastate, "SCStreamingBuffer"); - - lua_pushcfunction(luastate, LuaCallbackLogPath); - lua_setglobal(luastate, "SCLogPath"); - - lua_pushcfunction(luastate, LuaCallbackLogDebug); - lua_setglobal(luastate, "SCLogDebug"); - lua_pushcfunction(luastate, LuaCallbackLogInfo); - lua_setglobal(luastate, "SCLogInfo"); - lua_pushcfunction(luastate, LuaCallbackLogNotice); - lua_setglobal(luastate, "SCLogNotice"); - lua_pushcfunction(luastate, LuaCallbackLogWarning); - lua_setglobal(luastate, "SCLogWarning"); - lua_pushcfunction(luastate, LuaCallbackLogError); - lua_setglobal(luastate, "SCLogError"); - - - lua_pushcfunction(luastate, LuaCallbackRuleIds); - lua_setglobal(luastate, "SCRuleIds"); - lua_pushcfunction(luastate, LuaCallbackRuleAction); - lua_setglobal(luastate, "SCRuleAction"); - lua_pushcfunction(luastate, LuaCallbackRuleMsg); - lua_setglobal(luastate, "SCRuleMsg"); - lua_pushcfunction(luastate, LuaCallbackRuleClass); - lua_setglobal(luastate, "SCRuleClass"); - - lua_pushcfunction(luastate, LuaCallbackFileInfo); - lua_setglobal(luastate, "SCFileInfo"); - lua_pushcfunction(luastate, LuaCallbackFileState); - lua_setglobal(luastate, "SCFileState"); - - lua_pushcfunction(luastate, LuaCallbackThreadInfo); - lua_setglobal(luastate, "SCThreadInfo"); - return 0; -} - -int LuaStateNeedProto(lua_State *luastate, AppProto alproto) -{ - AppProto flow_alproto = 0; - Flow *flow = LuaStateGetFlow(luastate); - if (flow == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - flow_alproto = flow->alproto; - - return (alproto == flow_alproto); - -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-common.h b/src/util-lua-common.h deleted file mode 100644 index 2e0df28751a1..000000000000 --- a/src/util-lua-common.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_LUA_COMMON_H__ -#define __UTIL_LUA_COMMON_H__ - -#ifdef HAVE_LUA - -int LuaCallbackError(lua_State *luastate, const char *msg); -const char *LuaGetStringArgument(lua_State *luastate, int argc); - -void LuaPushTableKeyValueInt(lua_State *luastate, const char *key, int value); -void LuaPushTableKeyValueString(lua_State *luastate, const char *key, const char *value); -void LuaPushTableKeyValueArray(lua_State *luastate, const char *key, const uint8_t *value, size_t len); - -int LuaRegisterFunctions(lua_State *luastate); - -int LuaStateNeedProto(lua_State *luastate, AppProto alproto); - -#endif /* HAVE_LUA */ - -#endif /* __UTIL_LUA_COMMON_H__ */ diff --git a/src/util-lua-dnp3-objects.c b/src/util-lua-dnp3-objects.c deleted file mode 100644 index 27bbc5351901..000000000000 --- a/src/util-lua-dnp3-objects.c +++ /dev/null @@ -1,3543 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. - * - * Generated by command: - * ./scripts/dnp3-gen/dnp3-gen.py - */ - -#include "suricata-common.h" - -#include "app-layer-dnp3.h" -#include "app-layer-dnp3-objects.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-dnp3-objects.h" - -/** - * \brief Push an object point item onto the stack. - */ -void DNP3PushPoint(lua_State *luastate, DNP3Object *object, - DNP3Point *point) -{ - switch (DNP3_OBJECT_CODE(object->group, object->variation)) { - case DNP3_OBJECT_CODE(1, 1): { - DNP3ObjectG1V1 *data = point->data; - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(1, 2): { - DNP3ObjectG1V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "chatter_filter"); - lua_pushinteger(luastate, data->chatter_filter); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved"); - lua_pushinteger(luastate, data->reserved); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(2, 1): { - DNP3ObjectG2V1 *data = point->data; - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(2, 2): { - DNP3ObjectG2V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "chatter_filter"); - lua_pushinteger(luastate, data->chatter_filter); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved"); - lua_pushinteger(luastate, data->reserved); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(2, 3): { - DNP3ObjectG2V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "chatter_filter"); - lua_pushinteger(luastate, data->chatter_filter); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved"); - lua_pushinteger(luastate, data->reserved); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(3, 1): { - DNP3ObjectG3V1 *data = point->data; - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(3, 2): { - DNP3ObjectG3V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "chatter_filter"); - lua_pushinteger(luastate, data->chatter_filter); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(4, 1): { - DNP3ObjectG4V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "chatter_filter"); - lua_pushinteger(luastate, data->chatter_filter); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(4, 2): { - DNP3ObjectG4V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "chatter_filter"); - lua_pushinteger(luastate, data->chatter_filter); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(4, 3): { - DNP3ObjectG4V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "chatter_filter"); - lua_pushinteger(luastate, data->chatter_filter); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "relative_time_ms"); - lua_pushinteger(luastate, data->relative_time_ms); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(10, 1): { - DNP3ObjectG10V1 *data = point->data; - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(10, 2): { - DNP3ObjectG10V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(11, 1): { - DNP3ObjectG11V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(11, 2): { - DNP3ObjectG11V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(12, 1): { - DNP3ObjectG12V1 *data = point->data; - lua_pushliteral(luastate, "op_type"); - lua_pushinteger(luastate, data->op_type); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "qu"); - lua_pushinteger(luastate, data->qu); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "cr"); - lua_pushinteger(luastate, data->cr); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "tcc"); - lua_pushinteger(luastate, data->tcc); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "ontime"); - lua_pushinteger(luastate, data->ontime); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "offtime"); - lua_pushinteger(luastate, data->offtime); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved"); - lua_pushinteger(luastate, data->reserved); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(12, 2): { - DNP3ObjectG12V2 *data = point->data; - lua_pushliteral(luastate, "op_type"); - lua_pushinteger(luastate, data->op_type); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "qu"); - lua_pushinteger(luastate, data->qu); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "cr"); - lua_pushinteger(luastate, data->cr); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "tcc"); - lua_pushinteger(luastate, data->tcc); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "ontime"); - lua_pushinteger(luastate, data->ontime); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "offtime"); - lua_pushinteger(luastate, data->offtime); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved"); - lua_pushinteger(luastate, data->reserved); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(12, 3): { - DNP3ObjectG12V3 *data = point->data; - lua_pushliteral(luastate, "point"); - lua_pushinteger(luastate, data->point); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(13, 1): { - DNP3ObjectG13V1 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_state"); - lua_pushinteger(luastate, data->commanded_state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(13, 2): { - DNP3ObjectG13V2 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_state"); - lua_pushinteger(luastate, data->commanded_state); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 1): { - DNP3ObjectG20V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 2): { - DNP3ObjectG20V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 3): { - DNP3ObjectG20V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 4): { - DNP3ObjectG20V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 5): { - DNP3ObjectG20V5 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 6): { - DNP3ObjectG20V6 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 7): { - DNP3ObjectG20V7 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(20, 8): { - DNP3ObjectG20V8 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 1): { - DNP3ObjectG21V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 2): { - DNP3ObjectG21V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 3): { - DNP3ObjectG21V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 4): { - DNP3ObjectG21V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 5): { - DNP3ObjectG21V5 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 6): { - DNP3ObjectG21V6 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 7): { - DNP3ObjectG21V7 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 8): { - DNP3ObjectG21V8 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 9): { - DNP3ObjectG21V9 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 10): { - DNP3ObjectG21V10 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 11): { - DNP3ObjectG21V11 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(21, 12): { - DNP3ObjectG21V12 *data = point->data; - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 1): { - DNP3ObjectG22V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 2): { - DNP3ObjectG22V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 3): { - DNP3ObjectG22V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 4): { - DNP3ObjectG22V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 5): { - DNP3ObjectG22V5 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 6): { - DNP3ObjectG22V6 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 7): { - DNP3ObjectG22V7 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(22, 8): { - DNP3ObjectG22V8 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 1): { - DNP3ObjectG23V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 2): { - DNP3ObjectG23V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 3): { - DNP3ObjectG23V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 4): { - DNP3ObjectG23V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 5): { - DNP3ObjectG23V5 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 6): { - DNP3ObjectG23V6 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 7): { - DNP3ObjectG23V7 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(23, 8): { - DNP3ObjectG23V8 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "rollover"); - lua_pushinteger(luastate, data->rollover); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count"); - lua_pushinteger(luastate, data->count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(30, 1): { - DNP3ObjectG30V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(30, 2): { - DNP3ObjectG30V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(30, 3): { - DNP3ObjectG30V3 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(30, 4): { - DNP3ObjectG30V4 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(30, 5): { - DNP3ObjectG30V5 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(30, 6): { - DNP3ObjectG30V6 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 1): { - DNP3ObjectG31V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 2): { - DNP3ObjectG31V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 3): { - DNP3ObjectG31V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 4): { - DNP3ObjectG31V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 5): { - DNP3ObjectG31V5 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 6): { - DNP3ObjectG31V6 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 7): { - DNP3ObjectG31V7 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(31, 8): { - DNP3ObjectG31V8 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 1): { - DNP3ObjectG32V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 2): { - DNP3ObjectG32V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 3): { - DNP3ObjectG32V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 4): { - DNP3ObjectG32V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 5): { - DNP3ObjectG32V5 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 6): { - DNP3ObjectG32V6 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 7): { - DNP3ObjectG32V7 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(32, 8): { - DNP3ObjectG32V8 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 1): { - DNP3ObjectG33V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 2): { - DNP3ObjectG33V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 3): { - DNP3ObjectG33V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 4): { - DNP3ObjectG33V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 5): { - DNP3ObjectG33V5 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 6): { - DNP3ObjectG33V6 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 7): { - DNP3ObjectG33V7 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(33, 8): { - DNP3ObjectG33V8 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(34, 1): { - DNP3ObjectG34V1 *data = point->data; - lua_pushliteral(luastate, "deadband_value"); - lua_pushinteger(luastate, data->deadband_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(34, 2): { - DNP3ObjectG34V2 *data = point->data; - lua_pushliteral(luastate, "deadband_value"); - lua_pushinteger(luastate, data->deadband_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(34, 3): { - DNP3ObjectG34V3 *data = point->data; - lua_pushliteral(luastate, "deadband_value"); - lua_pushnumber(luastate, data->deadband_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(40, 1): { - DNP3ObjectG40V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(40, 2): { - DNP3ObjectG40V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(40, 3): { - DNP3ObjectG40V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(40, 4): { - DNP3ObjectG40V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(41, 1): { - DNP3ObjectG41V1 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "control_status"); - lua_pushinteger(luastate, data->control_status); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(41, 2): { - DNP3ObjectG41V2 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "control_status"); - lua_pushinteger(luastate, data->control_status); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(41, 3): { - DNP3ObjectG41V3 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "control_status"); - lua_pushinteger(luastate, data->control_status); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(41, 4): { - DNP3ObjectG41V4 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "control_status"); - lua_pushinteger(luastate, data->control_status); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 1): { - DNP3ObjectG42V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 2): { - DNP3ObjectG42V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 3): { - DNP3ObjectG42V3 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 4): { - DNP3ObjectG42V4 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 5): { - DNP3ObjectG42V5 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 6): { - DNP3ObjectG42V6 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 7): { - DNP3ObjectG42V7 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(42, 8): { - DNP3ObjectG42V8 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "over_range"); - lua_pushinteger(luastate, data->over_range); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reference_err"); - lua_pushinteger(luastate, data->reference_err); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "value"); - lua_pushnumber(luastate, data->value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 1): { - DNP3ObjectG43V1 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushinteger(luastate, data->commanded_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 2): { - DNP3ObjectG43V2 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushinteger(luastate, data->commanded_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 3): { - DNP3ObjectG43V3 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushinteger(luastate, data->commanded_value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 4): { - DNP3ObjectG43V4 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushinteger(luastate, data->commanded_value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 5): { - DNP3ObjectG43V5 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushnumber(luastate, data->commanded_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 6): { - DNP3ObjectG43V6 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushnumber(luastate, data->commanded_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 7): { - DNP3ObjectG43V7 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushnumber(luastate, data->commanded_value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(43, 8): { - DNP3ObjectG43V8 *data = point->data; - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "commanded_value"); - lua_pushnumber(luastate, data->commanded_value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(50, 1): { - DNP3ObjectG50V1 *data = point->data; - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(50, 2): { - DNP3ObjectG50V2 *data = point->data; - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "interval"); - lua_pushinteger(luastate, data->interval); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(50, 3): { - DNP3ObjectG50V3 *data = point->data; - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(50, 4): { - DNP3ObjectG50V4 *data = point->data; - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "interval_count"); - lua_pushinteger(luastate, data->interval_count); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "interval_units"); - lua_pushinteger(luastate, data->interval_units); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(51, 1): { - DNP3ObjectG51V1 *data = point->data; - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(51, 2): { - DNP3ObjectG51V2 *data = point->data; - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(52, 1): { - DNP3ObjectG52V1 *data = point->data; - lua_pushliteral(luastate, "delay_secs"); - lua_pushinteger(luastate, data->delay_secs); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(52, 2): { - DNP3ObjectG52V2 *data = point->data; - lua_pushliteral(luastate, "delay_ms"); - lua_pushinteger(luastate, data->delay_ms); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 1): { - DNP3ObjectG70V1 *data = point->data; - lua_pushliteral(luastate, "filename_size"); - lua_pushinteger(luastate, data->filename_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "filetype_code"); - lua_pushinteger(luastate, data->filetype_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "attribute_code"); - lua_pushinteger(luastate, data->attribute_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "start_record"); - lua_pushinteger(luastate, data->start_record); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "end_record"); - lua_pushinteger(luastate, data->end_record); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_size"); - lua_pushinteger(luastate, data->file_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "created_timestamp"); - lua_pushinteger(luastate, data->created_timestamp); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "permission"); - lua_pushinteger(luastate, data->permission); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_id"); - lua_pushinteger(luastate, data->file_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "owner_id"); - lua_pushinteger(luastate, data->owner_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "group_id"); - lua_pushinteger(luastate, data->group_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_function_code"); - lua_pushinteger(luastate, data->file_function_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "filename"); - LuaPushStringBuffer(luastate, (uint8_t *)data->filename, - strlen(data->filename)); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "data_size"); - lua_pushinteger(luastate, data->data_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "data"); - LuaPushStringBuffer(luastate, (uint8_t *)data->data, - strlen(data->data)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 2): { - DNP3ObjectG70V2 *data = point->data; - lua_pushliteral(luastate, "username_offset"); - lua_pushinteger(luastate, data->username_offset); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "username_size"); - lua_pushinteger(luastate, data->username_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "password_offset"); - lua_pushinteger(luastate, data->password_offset); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "password_size"); - lua_pushinteger(luastate, data->password_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "authentication_key"); - lua_pushinteger(luastate, data->authentication_key); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "username"); - LuaPushStringBuffer(luastate, (uint8_t *)data->username, - strlen(data->username)); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "password"); - LuaPushStringBuffer(luastate, (uint8_t *)data->password, - strlen(data->password)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 3): { - DNP3ObjectG70V3 *data = point->data; - lua_pushliteral(luastate, "filename_offset"); - lua_pushinteger(luastate, data->filename_offset); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "filename_size"); - lua_pushinteger(luastate, data->filename_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "created"); - lua_pushinteger(luastate, data->created); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "permissions"); - lua_pushinteger(luastate, data->permissions); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "authentication_key"); - lua_pushinteger(luastate, data->authentication_key); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_size"); - lua_pushinteger(luastate, data->file_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "operational_mode"); - lua_pushinteger(luastate, data->operational_mode); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "maximum_block_size"); - lua_pushinteger(luastate, data->maximum_block_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "request_id"); - lua_pushinteger(luastate, data->request_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "filename"); - LuaPushStringBuffer(luastate, (uint8_t *)data->filename, - strlen(data->filename)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 4): { - DNP3ObjectG70V4 *data = point->data; - lua_pushliteral(luastate, "file_handle"); - lua_pushinteger(luastate, data->file_handle); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_size"); - lua_pushinteger(luastate, data->file_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "maximum_block_size"); - lua_pushinteger(luastate, data->maximum_block_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "request_id"); - lua_pushinteger(luastate, data->request_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "optional_text"); - LuaPushStringBuffer(luastate, (uint8_t *)data->optional_text, - strlen(data->optional_text)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 5): { - DNP3ObjectG70V5 *data = point->data; - lua_pushliteral(luastate, "file_handle"); - lua_pushinteger(luastate, data->file_handle); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "block_number"); - lua_pushinteger(luastate, data->block_number); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_data"); - LuaPushStringBuffer(luastate, (uint8_t *)data->file_data, - strlen(data->file_data)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 6): { - DNP3ObjectG70V6 *data = point->data; - lua_pushliteral(luastate, "file_handle"); - lua_pushinteger(luastate, data->file_handle); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "block_number"); - lua_pushinteger(luastate, data->block_number); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "status_code"); - lua_pushinteger(luastate, data->status_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "optional_text"); - LuaPushStringBuffer(luastate, (uint8_t *)data->optional_text, - strlen(data->optional_text)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 7): { - DNP3ObjectG70V7 *data = point->data; - lua_pushliteral(luastate, "filename_offset"); - lua_pushinteger(luastate, data->filename_offset); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "filename_size"); - lua_pushinteger(luastate, data->filename_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_type"); - lua_pushinteger(luastate, data->file_type); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "file_size"); - lua_pushinteger(luastate, data->file_size); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "created_timestamp"); - lua_pushinteger(luastate, data->created_timestamp); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "permissions"); - lua_pushinteger(luastate, data->permissions); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "request_id"); - lua_pushinteger(luastate, data->request_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "filename"); - LuaPushStringBuffer(luastate, (uint8_t *)data->filename, - strlen(data->filename)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(70, 8): { - DNP3ObjectG70V8 *data = point->data; - lua_pushliteral(luastate, "file_specification"); - LuaPushStringBuffer(luastate, (uint8_t *)data->file_specification, - strlen(data->file_specification)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(80, 1): { - DNP3ObjectG80V1 *data = point->data; - lua_pushliteral(luastate, "state"); - lua_pushinteger(luastate, data->state); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(81, 1): { - DNP3ObjectG81V1 *data = point->data; - lua_pushliteral(luastate, "fill_percentage"); - lua_pushinteger(luastate, data->fill_percentage); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "overflow_state"); - lua_pushinteger(luastate, data->overflow_state); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "group"); - lua_pushinteger(luastate, data->group); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "variation"); - lua_pushinteger(luastate, data->variation); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(83, 1): { - DNP3ObjectG83V1 *data = point->data; - lua_pushliteral(luastate, "vendor_code"); - LuaPushStringBuffer(luastate, (uint8_t *)data->vendor_code, - strlen(data->vendor_code)); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "object_id"); - lua_pushinteger(luastate, data->object_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "length"); - lua_pushinteger(luastate, data->length); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "data_objects"); - lua_pushlstring(luastate, (const char *)data->data_objects, - data->length); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(86, 2): { - DNP3ObjectG86V2 *data = point->data; - lua_pushliteral(luastate, "rd"); - lua_pushinteger(luastate, data->rd); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "wr"); - lua_pushinteger(luastate, data->wr); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "st"); - lua_pushinteger(luastate, data->st); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "ev"); - lua_pushinteger(luastate, data->ev); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "df"); - lua_pushinteger(luastate, data->df); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "padding0"); - lua_pushinteger(luastate, data->padding0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "padding1"); - lua_pushinteger(luastate, data->padding1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "padding2"); - lua_pushinteger(luastate, data->padding2); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(102, 1): { - DNP3ObjectG102V1 *data = point->data; - lua_pushliteral(luastate, "value"); - lua_pushinteger(luastate, data->value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 1): { - DNP3ObjectG120V1 *data = point->data; - lua_pushliteral(luastate, "csq"); - lua_pushinteger(luastate, data->csq); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "usr"); - lua_pushinteger(luastate, data->usr); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "mal"); - lua_pushinteger(luastate, data->mal); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reason"); - lua_pushinteger(luastate, data->reason); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "challenge_data"); - lua_pushlstring(luastate, (const char *)data->challenge_data, - data->challenge_data_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 2): { - DNP3ObjectG120V2 *data = point->data; - lua_pushliteral(luastate, "csq"); - lua_pushinteger(luastate, data->csq); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "usr"); - lua_pushinteger(luastate, data->usr); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "mac_value"); - lua_pushlstring(luastate, (const char *)data->mac_value, - data->mac_value_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 3): { - DNP3ObjectG120V3 *data = point->data; - lua_pushliteral(luastate, "csq"); - lua_pushinteger(luastate, data->csq); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_number"); - lua_pushinteger(luastate, data->user_number); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 4): { - DNP3ObjectG120V4 *data = point->data; - lua_pushliteral(luastate, "user_number"); - lua_pushinteger(luastate, data->user_number); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 5): { - DNP3ObjectG120V5 *data = point->data; - lua_pushliteral(luastate, "ksq"); - lua_pushinteger(luastate, data->ksq); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_number"); - lua_pushinteger(luastate, data->user_number); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "key_wrap_alg"); - lua_pushinteger(luastate, data->key_wrap_alg); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "key_status"); - lua_pushinteger(luastate, data->key_status); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "mal"); - lua_pushinteger(luastate, data->mal); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "challenge_data_len"); - lua_pushinteger(luastate, data->challenge_data_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "challenge_data"); - lua_pushlstring(luastate, (const char *)data->challenge_data, - data->challenge_data_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "mac_value"); - lua_pushlstring(luastate, (const char *)data->mac_value, - data->mac_value_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 6): { - DNP3ObjectG120V6 *data = point->data; - lua_pushliteral(luastate, "ksq"); - lua_pushinteger(luastate, data->ksq); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "usr"); - lua_pushinteger(luastate, data->usr); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "wrapped_key_data"); - lua_pushlstring(luastate, (const char *)data->wrapped_key_data, - data->wrapped_key_data_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 7): { - DNP3ObjectG120V7 *data = point->data; - lua_pushliteral(luastate, "sequence_number"); - lua_pushinteger(luastate, data->sequence_number); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "usr"); - lua_pushinteger(luastate, data->usr); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "association_id"); - lua_pushinteger(luastate, data->association_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "error_code"); - lua_pushinteger(luastate, data->error_code); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "time_of_error"); - lua_pushinteger(luastate, data->time_of_error); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "error_text"); - LuaPushStringBuffer(luastate, (uint8_t *)data->error_text, - strlen(data->error_text)); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 8): { - DNP3ObjectG120V8 *data = point->data; - lua_pushliteral(luastate, "key_change_method"); - lua_pushinteger(luastate, data->key_change_method); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "certificate_type"); - lua_pushinteger(luastate, data->certificate_type); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "certificate"); - lua_pushlstring(luastate, (const char *)data->certificate, - data->certificate_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 9): { - DNP3ObjectG120V9 *data = point->data; - lua_pushliteral(luastate, "mac_value"); - lua_pushlstring(luastate, (const char *)data->mac_value, - data->mac_value_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 10): { - DNP3ObjectG120V10 *data = point->data; - lua_pushliteral(luastate, "key_change_method"); - lua_pushinteger(luastate, data->key_change_method); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "operation"); - lua_pushinteger(luastate, data->operation); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "scs"); - lua_pushinteger(luastate, data->scs); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_role"); - lua_pushinteger(luastate, data->user_role); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_role_expiry_interval"); - lua_pushinteger(luastate, data->user_role_expiry_interval); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "username_len"); - lua_pushinteger(luastate, data->username_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_public_key_len"); - lua_pushinteger(luastate, data->user_public_key_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "certification_data_len"); - lua_pushinteger(luastate, data->certification_data_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "username"); - LuaPushStringBuffer(luastate, (uint8_t *)data->username, - strlen(data->username)); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_public_key"); - lua_pushlstring(luastate, (const char *)data->user_public_key, - data->user_public_key_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "certification_data"); - lua_pushlstring(luastate, (const char *)data->certification_data, - data->certification_data_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 11): { - DNP3ObjectG120V11 *data = point->data; - lua_pushliteral(luastate, "key_change_method"); - lua_pushinteger(luastate, data->key_change_method); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "username_len"); - lua_pushinteger(luastate, data->username_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "master_challenge_data_len"); - lua_pushinteger(luastate, data->master_challenge_data_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "username"); - LuaPushStringBuffer(luastate, (uint8_t *)data->username, - strlen(data->username)); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "master_challenge_data"); - lua_pushlstring(luastate, (const char *)data->master_challenge_data, - data->master_challenge_data_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 12): { - DNP3ObjectG120V12 *data = point->data; - lua_pushliteral(luastate, "ksq"); - lua_pushinteger(luastate, data->ksq); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_number"); - lua_pushinteger(luastate, data->user_number); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "challenge_data_len"); - lua_pushinteger(luastate, data->challenge_data_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "challenge_data"); - lua_pushlstring(luastate, (const char *)data->challenge_data, - data->challenge_data_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 13): { - DNP3ObjectG120V13 *data = point->data; - lua_pushliteral(luastate, "ksq"); - lua_pushinteger(luastate, data->ksq); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "user_number"); - lua_pushinteger(luastate, data->user_number); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "encrypted_update_key_len"); - lua_pushinteger(luastate, data->encrypted_update_key_len); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "encrypted_update_key_data"); - lua_pushlstring(luastate, (const char *)data->encrypted_update_key_data, - data->encrypted_update_key_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 14): { - DNP3ObjectG120V14 *data = point->data; - lua_pushliteral(luastate, "digital_signature"); - lua_pushlstring(luastate, (const char *)data->digital_signature, - data->digital_signature_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(120, 15): { - DNP3ObjectG120V15 *data = point->data; - lua_pushliteral(luastate, "mac"); - lua_pushlstring(luastate, (const char *)data->mac, - data->mac_len); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(121, 1): { - DNP3ObjectG121V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "association_id"); - lua_pushinteger(luastate, data->association_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count_value"); - lua_pushinteger(luastate, data->count_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(122, 1): { - DNP3ObjectG122V1 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "association_id"); - lua_pushinteger(luastate, data->association_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count_value"); - lua_pushinteger(luastate, data->count_value); - lua_settable(luastate, -3); - break; - } - case DNP3_OBJECT_CODE(122, 2): { - DNP3ObjectG122V2 *data = point->data; - lua_pushliteral(luastate, "online"); - lua_pushinteger(luastate, data->online); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "restart"); - lua_pushinteger(luastate, data->restart); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "comm_lost"); - lua_pushinteger(luastate, data->comm_lost); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "remote_forced"); - lua_pushinteger(luastate, data->remote_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "local_forced"); - lua_pushinteger(luastate, data->local_forced); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved0"); - lua_pushinteger(luastate, data->reserved0); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "discontinuity"); - lua_pushinteger(luastate, data->discontinuity); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "reserved1"); - lua_pushinteger(luastate, data->reserved1); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "association_id"); - lua_pushinteger(luastate, data->association_id); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "count_value"); - lua_pushinteger(luastate, data->count_value); - lua_settable(luastate, -3); - lua_pushliteral(luastate, "timestamp"); - lua_pushinteger(luastate, data->timestamp); - lua_settable(luastate, -3); - break; - } - default: - break; - } -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-dnp3-objects.h b/src/util-lua-dnp3-objects.h deleted file mode 100644 index 6575695a2650..000000000000 --- a/src/util-lua-dnp3-objects.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __UTIL_LUA_DNP3_OBJECTS_H__ -#define __UTIL_LUA_DNP3_OBJECTS_H__ - -void DNP3PushPoint(lua_State *luastate, DNP3Object *object, - DNP3Point *item); - -#endif /* ! __UTIL_LUA_DNP3_OBJECTS_H__ */ diff --git a/src/util-lua-dnp3.c b/src/util-lua-dnp3.c deleted file mode 100644 index 09f8694d6c15..000000000000 --- a/src/util-lua-dnp3.c +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright (C) 2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" - -#include "app-layer-dnp3.h" -#include "app-layer-dnp3-objects.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-dnp3.h" -#include "util-lua-dnp3-objects.h" - -/** - * \brief Helper macro to push key and integer value onto a table. - */ -#define LUA_PUSHT_INT(l, k, v) do { \ - lua_pushliteral(luastate, k); \ - lua_pushinteger(luastate, v); \ - lua_settable(luastate, -3); \ - } while (0); - -static void DNP3PushPoints(lua_State *luastate, DNP3Object *object) -{ - DNP3Point *point; - int i = 1; - - TAILQ_FOREACH(point, object->points, next) { - lua_pushinteger(luastate, i++); - lua_newtable(luastate); - - lua_pushliteral(luastate, "index"); - lua_pushinteger(luastate, point->index); - lua_settable(luastate, -3); - - DNP3PushPoint(luastate, object, point); - - lua_settable(luastate, -3); - } -} - -static void DNP3PushObjects(lua_State *luastate, DNP3ObjectList *objects) -{ - DNP3Object *object = NULL; - int i = 1; - - TAILQ_FOREACH(object, objects, next) { - lua_pushinteger(luastate, i++); - lua_newtable(luastate); - - lua_pushliteral(luastate, "group"); - lua_pushinteger(luastate, object->group); - lua_settable(luastate, -3); - - lua_pushliteral(luastate, "variation"); - lua_pushinteger(luastate, object->variation); - lua_settable(luastate, -3); - - lua_pushliteral(luastate, "points"); - lua_newtable(luastate); - DNP3PushPoints(luastate, object); - lua_settable(luastate, -3); - - lua_settable(luastate, -3); - } -} - -static void DNP3PushLinkHeader(lua_State *luastate, DNP3LinkHeader *header) -{ - LUA_PUSHT_INT(luastate, "len", header->len); - LUA_PUSHT_INT(luastate, "control", header->control); - LUA_PUSHT_INT(luastate, "dst", header->dst); - LUA_PUSHT_INT(luastate, "src", header->src); - LUA_PUSHT_INT(luastate, "crc", header->crc); -} - -static void DNP3PushApplicationHeader(lua_State *luastate, - DNP3ApplicationHeader *header) -{ - LUA_PUSHT_INT(luastate, "control", header->control); - LUA_PUSHT_INT(luastate, "function_code", header->function_code); -} - -static void DNP3PushRequest(lua_State *luastate, DNP3Transaction *tx) -{ - /* Link header. */ - lua_pushliteral(luastate, "link_header"); - lua_newtable(luastate); - DNP3PushLinkHeader(luastate, &tx->lh); - lua_settable(luastate, -3); - - /* Transport header. */ - LUA_PUSHT_INT(luastate, "transport_header", tx->th); - - /* Application header. */ - lua_pushliteral(luastate, "application_header"); - lua_newtable(luastate); - DNP3PushApplicationHeader(luastate, &tx->ah); - lua_settable(luastate, -3); - - lua_pushliteral(luastate, "objects"); - lua_newtable(luastate); - DNP3PushObjects(luastate, &tx->objects); - lua_settable(luastate, -3); -} - -static void DNP3PushResponse(lua_State *luastate, DNP3Transaction *tx) -{ - /* Link header. */ - lua_pushliteral(luastate, "link_header"); - lua_newtable(luastate); - DNP3PushLinkHeader(luastate, &tx->lh); - lua_settable(luastate, -3); - - /* Transport header. */ - LUA_PUSHT_INT(luastate, "transport_header", tx->th); - - /* Application header. */ - lua_pushliteral(luastate, "application_header"); - lua_newtable(luastate); - DNP3PushApplicationHeader(luastate, &tx->ah); - lua_settable(luastate, -3); - - /* Internal indicators. */ - LUA_PUSHT_INT(luastate, "indicators", tx->iin.iin1 << 8 | tx->iin.iin2); - - lua_pushliteral(luastate, "objects"); - lua_newtable(luastate); - DNP3PushObjects(luastate, &tx->objects); - lua_settable(luastate, -3); -} - -static int DNP3GetTx(lua_State *luastate) -{ - if (!LuaStateNeedProto(luastate, ALPROTO_DNP3)) { - return LuaCallbackError(luastate, "error: protocol not dnp3"); - } - - DNP3Transaction *tx = LuaStateGetTX(luastate); - if (tx == NULL) { - return LuaCallbackError(luastate, "error: no tx"); - } - - lua_newtable(luastate); - - lua_pushliteral(luastate, "tx_num"); - lua_pushinteger(luastate, tx->tx_num); - lua_settable(luastate, -3); - - LUA_PUSHT_INT(luastate, "has_request", tx->is_request ? 1 : 0); - if (tx->is_request) { - lua_pushliteral(luastate, "request"); - lua_newtable(luastate); - LUA_PUSHT_INT(luastate, "done", tx->done); - LUA_PUSHT_INT(luastate, "complete", tx->complete); - DNP3PushRequest(luastate, tx); - lua_settable(luastate, -3); - } - - LUA_PUSHT_INT(luastate, "has_response", tx->is_request ? 0 : 1); - if (!tx->is_request) { - lua_pushliteral(luastate, "response"); - lua_newtable(luastate); - LUA_PUSHT_INT(luastate, "done", tx->done); - LUA_PUSHT_INT(luastate, "complete", tx->complete); - DNP3PushResponse(luastate, tx); - lua_settable(luastate, -3); - } - - return 1; -} - -int LuaRegisterDNP3Functions(lua_State *luastate) -{ - lua_pushcfunction(luastate, DNP3GetTx); - lua_setglobal(luastate, "DNP3GetTx"); - - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-dns.c b/src/util-lua-dns.c deleted file mode 100644 index 3fbd84a75ae2..000000000000 --- a/src/util-lua-dns.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -/** - * \file - * - * \author Eric Leblond - * - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "rust.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-dns.h" - -static int DnsGetDnsRrname(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) - return LuaCallbackError(luastate, "error: protocol not dns"); - RSDNSTransaction *tx = LuaStateGetTX(luastate); - if (tx == NULL) { - return LuaCallbackError(luastate, "internal error: no tx"); - } - return rs_dns_lua_get_rrname(luastate, tx); -} - -static int DnsGetTxid(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) - return LuaCallbackError(luastate, "error: protocol not dns"); - RSDNSTransaction *tx = LuaStateGetTX(luastate); - if (tx == NULL) { - return LuaCallbackError(luastate, "internal error: no tx"); - } - rs_dns_lua_get_tx_id(luastate, tx); - return 1; -} - -static int DnsGetRcode(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) - return LuaCallbackError(luastate, "error: protocol not dns"); - RSDNSTransaction *tx = LuaStateGetTX(luastate); - if (tx == NULL) { - return LuaCallbackError(luastate, "internal error: no tx"); - } - return rs_dns_lua_get_rcode(luastate, tx); -} - -static int DnsGetRecursionDesired(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) - return LuaCallbackError(luastate, "error: protocol not dns"); - RSDNSTransaction *tx = LuaStateGetTX(luastate); - if (tx == NULL) { - return LuaCallbackError(luastate, "internal error: no tx"); - } - uint16_t flags = rs_dns_tx_get_response_flags(tx); - int recursion_desired = flags & 0x0080 ? 1 : 0; - lua_pushboolean(luastate, recursion_desired); - return 1; -} - -static int DnsGetQueryTable(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) - return LuaCallbackError(luastate, "error: protocol not dns"); - RSDNSTransaction *tx = LuaStateGetTX(luastate); - if (tx == NULL) { - return LuaCallbackError(luastate, "internal error: no tx"); - } - return rs_dns_lua_get_query_table(luastate, tx); -} - -static int DnsGetAnswerTable(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) - return LuaCallbackError(luastate, "error: protocol not dns"); - RSDNSTransaction *tx = LuaStateGetTX(luastate); - return rs_dns_lua_get_answer_table(luastate, tx); -} - -static int DnsGetAuthorityTable(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) - return LuaCallbackError(luastate, "error: protocol not dns"); - RSDNSTransaction *tx = LuaStateGetTX(luastate); - return rs_dns_lua_get_authority_table(luastate, tx); -} - -/** \brief register http lua extensions in a luastate */ -int LuaRegisterDnsFunctions(lua_State *luastate) -{ - /* registration of the callbacks */ - lua_pushcfunction(luastate, DnsGetDnsRrname); - lua_setglobal(luastate, "DnsGetDnsRrname"); - - lua_pushcfunction(luastate, DnsGetQueryTable); - lua_setglobal(luastate, "DnsGetQueries"); - - lua_pushcfunction(luastate, DnsGetAnswerTable); - lua_setglobal(luastate, "DnsGetAnswers"); - - lua_pushcfunction(luastate, DnsGetAuthorityTable); - lua_setglobal(luastate, "DnsGetAuthorities"); - - lua_pushcfunction(luastate, DnsGetTxid); - lua_setglobal(luastate, "DnsGetTxid"); - - lua_pushcfunction(luastate, DnsGetRcode); - lua_setglobal(luastate, "DnsGetRcode"); - - lua_pushcfunction(luastate, DnsGetRecursionDesired); - lua_setglobal(luastate, "DnsGetRecursionDesired"); - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-hassh.c b/src/util-lua-hassh.c deleted file mode 100644 index 631268d1b458..000000000000 --- a/src/util-lua-hassh.c +++ /dev/null @@ -1,219 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -/** - * \file - * - * \author Vadym Malakhatko - * - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssl.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-hassh.h" - -static int GetHasshServerString(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *hassh_server_string = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_hassh_string(tx, &hassh_server_string, &b_len, STREAM_TOCLIENT) != 1) - return LuaCallbackError(luastate, "error: no server hassh string"); - if (hassh_server_string == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no server hassh string"); - } - - return LuaPushStringBuffer(luastate, hassh_server_string, b_len); -} - -static int HasshServerGetString(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol is not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no ssh flow"); - - r = GetHasshServerString(luastate, f); - - return r; -} - -static int GetHasshServer(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no ssh app layer state"); - - const uint8_t *hassh_server = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_hassh(tx, &hassh_server, &b_len, STREAM_TOCLIENT) != 1) - return LuaCallbackError(luastate, "error: no server hassh"); - if (hassh_server == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no server hassh"); - } - - return LuaPushStringBuffer(luastate, hassh_server, b_len); -} - -static int HasshServerGet(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol is not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no ssh flow"); - - r = GetHasshServer(luastate, f); - - return r; -} - -static int GetHasshString(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *hassh_string = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_hassh_string(tx, &hassh_string, &b_len, STREAM_TOSERVER) != 1) - return LuaCallbackError(luastate, "error: no client hassh_string"); - if (hassh_string == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no client hassh_string"); - } - - return LuaPushStringBuffer(luastate, hassh_string, b_len); -} - -static int HasshGetString(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol is not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no ssh flow"); - - r = GetHasshString(luastate, f); - - return r; -} - -static int GetHassh(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *hassh = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_hassh(tx, &hassh, &b_len, STREAM_TOSERVER) != 1) - return LuaCallbackError(luastate, "error: no client hassh"); - if (hassh == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no client hassh"); - } - - return LuaPushStringBuffer(luastate, hassh, b_len); -} - -static int HasshGet(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol is not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no sshflow"); - - r = GetHassh(luastate, f); - - return r; -} - -/** *\brief Register Hassh Lua extensions */ -int LuaRegisterHasshFunctions(lua_State *luastate) -{ - - lua_pushcfunction(luastate, HasshGet); - lua_setglobal(luastate, "HasshGet"); - - lua_pushcfunction(luastate, HasshGetString); - lua_setglobal(luastate, "HasshGetString"); - - lua_pushcfunction(luastate, HasshServerGet); - lua_setglobal(luastate, "HasshServerGet"); - - lua_pushcfunction(luastate, HasshServerGetString); - lua_setglobal(luastate, "HasshServerGetString"); - - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-http.c b/src/util-lua-http.c deleted file mode 100644 index e04c168fa6ea..000000000000 --- a/src/util-lua-http.c +++ /dev/null @@ -1,353 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer-htp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-http.h" - -static int HttpGetRequestHost(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - if (tx->request_hostname == NULL) - return LuaCallbackError(luastate, "no request hostname"); - - return LuaPushStringBuffer(luastate, - bstr_ptr(tx->request_hostname), bstr_len(tx->request_hostname)); -} - -static int HttpGetRequestUriRaw(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - if (tx->request_uri == NULL) - return LuaCallbackError(luastate, "no request uri"); - - return LuaPushStringBuffer(luastate, - bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); -} - -static int HttpGetRequestUriNormalized(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud == NULL) - return LuaCallbackError(luastate, "no htud in tx"); - - if (htud->request_uri_normalized == NULL || - bstr_ptr(htud->request_uri_normalized) == NULL || - bstr_len(htud->request_uri_normalized) == 0) - return LuaCallbackError(luastate, "no normalized uri"); - - return LuaPushStringBuffer(luastate, - bstr_ptr(htud->request_uri_normalized), - bstr_len(htud->request_uri_normalized)); -} - -static int HttpGetRequestLine(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - if (tx->request_line == NULL) - return LuaCallbackError(luastate, "no request_line"); - - return LuaPushStringBuffer(luastate, - bstr_ptr(tx->request_line), bstr_len(tx->request_line)); -} - -static int HttpGetResponseLine(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - if (tx->response_line == NULL) - return LuaCallbackError(luastate, "no response_line"); - - return LuaPushStringBuffer(luastate, - bstr_ptr(tx->response_line), bstr_len(tx->response_line)); -} - -static int HttpGetHeader(lua_State *luastate, int dir) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - const char *name = LuaGetStringArgument(luastate, 1); - if (name == NULL) - return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - - htp_table_t *headers = tx->request_headers; - if (dir == 1) - headers = tx->response_headers; - if (headers == NULL) - return LuaCallbackError(luastate, "tx has no headers"); - - htp_header_t *h = (htp_header_t *)htp_table_get_c(headers, name); - if (h == NULL || bstr_len(h->value) == 0) - return LuaCallbackError(luastate, "header not found"); - - return LuaPushStringBuffer(luastate, - bstr_ptr(h->value), bstr_len(h->value)); -} - -static int HttpGetRequestHeader(lua_State *luastate) -{ - return HttpGetHeader(luastate, 0 /* request */); -} - -static int HttpGetResponseHeader(lua_State *luastate) -{ - return HttpGetHeader(luastate, 1 /* response */); -} - -static int HttpGetRawHeaders(lua_State *luastate, int dir) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud == NULL) - return LuaCallbackError(luastate, "no htud in tx"); - - uint8_t *raw = htud->request_headers_raw; - uint32_t raw_len = htud->request_headers_raw_len; - if (dir == 1) { - raw = htud->response_headers_raw; - raw_len = htud->response_headers_raw_len; - } - - if (raw == NULL || raw_len == 0) - return LuaCallbackError(luastate, "no raw headers"); - - return LuaPushStringBuffer(luastate, raw, raw_len); -} - -static int HttpGetRawRequestHeaders(lua_State *luastate) -{ - return HttpGetRawHeaders(luastate, 0); -} - -static int HttpGetRawResponseHeaders(lua_State *luastate) -{ - return HttpGetRawHeaders(luastate, 1); -} - - -static int HttpGetHeaders(lua_State *luastate, int dir) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - htp_table_t *table = tx->request_headers; - if (dir == 1) - table = tx->response_headers; - if (tx->request_headers == NULL) - return LuaCallbackError(luastate, "no headers"); - - lua_newtable(luastate); - htp_header_t *h = NULL; - size_t i = 0; - size_t no_of_headers = htp_table_size(table); - for (; i < no_of_headers; i++) { - h = htp_table_get_index(table, i, NULL); - LuaPushStringBuffer(luastate, bstr_ptr(h->name), bstr_len(h->name)); - LuaPushStringBuffer(luastate, bstr_ptr(h->value), bstr_len(h->value)); - lua_settable(luastate, -3); - } - return 1; -} - -/** \brief return request headers as lua table */ -static int HttpGetRequestHeaders(lua_State *luastate) -{ - return HttpGetHeaders(luastate, 0); -} - -/** \brief return response headers as lua table */ -static int HttpGetResponseHeaders(lua_State *luastate) -{ - return HttpGetHeaders(luastate, 1); -} - -static int HttpGetBody(lua_State *luastate, int dir) -{ - HtpBody *body = NULL; - - if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP1))) - return LuaCallbackError(luastate, "error: protocol not http"); - - htp_tx_t *tx = LuaStateGetTX(luastate); - if (tx == NULL) - return LuaCallbackError(luastate, "internal error: no tx"); - - HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud == NULL) - return LuaCallbackError(luastate, "no htud in tx"); - - if (dir == 0) - body = &htud->request_body; - else - body = &htud->response_body; - - if (body->first == NULL) - return LuaCallbackError(luastate, "no body"); - - int index = 1; - HtpBodyChunk *chunk = body->first; - lua_newtable(luastate); - while (chunk != NULL) { - lua_pushinteger(luastate, index); - - const uint8_t *data = NULL; - uint32_t data_len = 0; - StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len); - LuaPushStringBuffer(luastate, data, data_len); - - lua_settable(luastate, -3); - - chunk = chunk->next; - index++; - } - - if (body->first && body->last) { - lua_pushinteger(luastate, body->first->sbseg.stream_offset); - lua_pushinteger(luastate, body->last->sbseg.stream_offset + body->last->sbseg.segment_len); - return 3; - } else { - return 1; - } -} - -static int HttpGetRequestBody(lua_State *luastate) -{ - return HttpGetBody(luastate, 0); -} - -static int HttpGetResponseBody(lua_State *luastate) -{ - return HttpGetBody(luastate, 1); -} - -/** \brief register http lua extensions in a luastate */ -int LuaRegisterHttpFunctions(lua_State *luastate) -{ - /* registration of the callbacks */ - lua_pushcfunction(luastate, HttpGetRequestHeader); - lua_setglobal(luastate, "HttpGetRequestHeader"); - lua_pushcfunction(luastate, HttpGetResponseHeader); - lua_setglobal(luastate, "HttpGetResponseHeader"); - lua_pushcfunction(luastate, HttpGetRequestLine); - lua_setglobal(luastate, "HttpGetRequestLine"); - lua_pushcfunction(luastate, HttpGetResponseLine); - lua_setglobal(luastate, "HttpGetResponseLine"); - lua_pushcfunction(luastate, HttpGetRawRequestHeaders); - lua_setglobal(luastate, "HttpGetRawRequestHeaders"); - lua_pushcfunction(luastate, HttpGetRawResponseHeaders); - lua_setglobal(luastate, "HttpGetRawResponseHeaders"); - lua_pushcfunction(luastate, HttpGetRequestUriRaw); - lua_setglobal(luastate, "HttpGetRequestUriRaw"); - lua_pushcfunction(luastate, HttpGetRequestUriNormalized); - lua_setglobal(luastate, "HttpGetRequestUriNormalized"); - lua_pushcfunction(luastate, HttpGetRequestHeaders); - lua_setglobal(luastate, "HttpGetRequestHeaders"); - lua_pushcfunction(luastate, HttpGetResponseHeaders); - lua_setglobal(luastate, "HttpGetResponseHeaders"); - lua_pushcfunction(luastate, HttpGetRequestHost); - lua_setglobal(luastate, "HttpGetRequestHost"); - - lua_pushcfunction(luastate, HttpGetRequestBody); - lua_setglobal(luastate, "HttpGetRequestBody"); - lua_pushcfunction(luastate, HttpGetResponseBody); - lua_setglobal(luastate, "HttpGetResponseBody"); - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-ja3.c b/src/util-lua-ja3.c deleted file mode 100644 index 1faed68f56a0..000000000000 --- a/src/util-lua-ja3.c +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -/** - * \file - * - * \author Mats Klepsland - * - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssl.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-ja3.h" - -static int Ja3GetHash(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol is not tls"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - - if (ssl_state->client_connp.ja3_hash == NULL) - return LuaCallbackError(luastate, "error: no JA3 hash"); - - return LuaPushStringBuffer(luastate, - (uint8_t *)ssl_state->client_connp.ja3_hash, - strlen(ssl_state->client_connp.ja3_hash)); -} - -static int Ja3GetString(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol is not tls"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - - if (ssl_state->client_connp.ja3_str == NULL || - ssl_state->client_connp.ja3_str->data == NULL) - return LuaCallbackError(luastate, "error: no JA3 str"); - - return LuaPushStringBuffer(luastate, - (uint8_t *)ssl_state->client_connp.ja3_str->data, - ssl_state->client_connp.ja3_str->used); -} - -static int Ja3SGetHash(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol is not tls"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - - if (ssl_state->server_connp.ja3_hash == NULL) - return LuaCallbackError(luastate, "error: no JA3S hash"); - - return LuaPushStringBuffer(luastate, - (uint8_t *)ssl_state->server_connp.ja3_hash, - strlen(ssl_state->server_connp.ja3_hash)); -} - -static int Ja3SGetString(lua_State *luastate) -{ - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol is not tls"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - - if (ssl_state->server_connp.ja3_str == NULL || - ssl_state->server_connp.ja3_str->data == NULL) - return LuaCallbackError(luastate, "error: no JA3S str"); - - return LuaPushStringBuffer(luastate, - (uint8_t *)ssl_state->server_connp.ja3_str->data, - ssl_state->server_connp.ja3_str->used); -} - -/** *\brief Register JA3 Lua extensions */ -int LuaRegisterJa3Functions(lua_State *luastate) -{ - lua_pushcfunction(luastate, Ja3GetHash); - lua_setglobal(luastate, "Ja3GetHash"); - - lua_pushcfunction(luastate, Ja3GetString); - lua_setglobal(luastate, "Ja3GetString"); - - lua_pushcfunction(luastate, Ja3SGetHash); - lua_setglobal(luastate, "Ja3SGetHash"); - - lua_pushcfunction(luastate, Ja3SGetString); - lua_setglobal(luastate, "Ja3SGetString"); - - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-smtp.c b/src/util-lua-smtp.c deleted file mode 100644 index a0ecf815d98b..000000000000 --- a/src/util-lua-smtp.c +++ /dev/null @@ -1,342 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author casec Bachelors group - * \author Lauritz Prag Sømme - * \author Levi Tobiassen - * \author Stian Hoel Bergseth - * \author Vinjar Hillestad - */ - -#include "suricata-common.h" - -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" -#include "output.h" - -#include "app-layer-smtp.h" - -#ifdef HAVE_LUA - -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-smtp.h" -#include "util-file.h" - -/* - * \brief internal function used by SMTPGetMimeField - * - * \param luastate luastate stack to use and push attributes to - * \param flow network flow of SMTP packets - * \param name name of the attribute to extract from MimeDecField - * - * \retval 1 if success mimefield found and pushed to stack. Returns error - * int and msg pushed to luastate stack if error occurs. - */ - -static int GetMimeDecField(lua_State *luastate, Flow *flow, const char *name) -{ - /* extract state from flow */ - SMTPState *state = (SMTPState *) FlowGetAppState(flow); - /* check that state exists */ - if(state == NULL) { - return LuaCallbackError(luastate, "Internal error: no state in flow"); - } - /* pointer to current transaction in state */ - SMTPTransaction *smtp_tx = state->curr_tx; - if(smtp_tx == NULL) { - return LuaCallbackError(luastate, "Transaction ending or not found"); - } - /* pointer to tail of msg list of MimeDecEntities in current transaction. */ - MimeDecEntity *mime = smtp_tx->msg_tail; - /* check if msg_tail was hit */ - if(mime == NULL){ - return LuaCallbackError(luastate, "Internal error: no fields in transaction"); - } - /* extract MIME field based on specific field name. */ - MimeDecField *field = MimeDecFindField(mime, name); - /* check MIME field */ - if(field == NULL) { - return LuaCallbackError(luastate, "Error: mimefield not found"); - } - /* return extracted field. */ - if(field->value == NULL || field->value_len == 0){ - return LuaCallbackError(luastate, "Error, pointer error"); - } - - return LuaPushStringBuffer(luastate, field->value, field->value_len); -} - -/** - * \brief Function extracts specific MIME field based on argument from luastate - * stack then pushing the attribute onto the luastate stack. - * - * \param luastate luastate stack to pop and push attributes for I/O to lua - * - * \retval 1 if success mimefield found and pushed to stack. Returns error - * int and msg pushed to luastate stack if error occurs. - */ - -static int SMTPGetMimeField(lua_State *luastate) -{ - if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { - return LuaCallbackError(luastate, "error: protocol not SMTP"); - } - Flow *flow = LuaStateGetFlow(luastate); - /* check that flow exist */ - if(flow == NULL) { - return LuaCallbackError(luastate, "Error: no flow found"); - } - const char *name = LuaGetStringArgument(luastate, 1); - if (name == NULL) - return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - - GetMimeDecField(luastate, flow, name); - - return 1; -} - -/** - * \brief Internal function used by SMTPGetMimeList - * - * \param luastate luastate stack to pop and push attributes for I/O to lua - * \param flow network flow of SMTP packets - * - * \retval 1 if the mimelist table is pushed to luastate stack. - * Returns error int and msg pushed to luastate stack if error occurs. -*/ - -static int GetMimeList(lua_State *luastate, Flow *flow) -{ - - SMTPState *state = (SMTPState *) FlowGetAppState(flow); - if(state == NULL) { - return LuaCallbackError(luastate, "Error: no SMTP state"); - } - /* Create a pointer to the current SMTPtransaction */ - SMTPTransaction *smtp_tx = state->curr_tx; - if(smtp_tx == NULL) { - return LuaCallbackError(luastate, "Error: no SMTP transaction found"); - } - /* Create a pointer to the tail of MimeDecEntity list */ - MimeDecEntity *mime = smtp_tx->msg_tail; - if(mime == NULL) { - return LuaCallbackError(luastate, "Error: no mime entity found"); - } - MimeDecField *field = mime->field_list; - if(field == NULL) { - return LuaCallbackError(luastate, "Error: no field_list found"); - } - if(field->name == NULL || field->name_len == 0) { - return LuaCallbackError(luastate, "Error: field has no name"); - } - /* Counter of MIME fields found */ - int num = 1; - /* loop trough the list of mimeFields, printing each name found */ - lua_newtable(luastate); - while (field != NULL) { - if(field->name != NULL && field->name_len != 0) { - lua_pushinteger(luastate,num++); - LuaPushStringBuffer(luastate, field->name, field->name_len); - lua_settable(luastate,-3); - } - field = field->next; - } - return 1; -} - -/** - * \brief Lists name and value to all MIME fields which - * is included in a SMTP transaction. - * - * \param luastate luastate stack to pop and push attributes for I/O to lua. - * - * \retval 1 if the table is pushed to lua. - * Returns error int and msg pushed to luastate stack if error occurs - * - */ - -static int SMTPGetMimeList(lua_State *luastate) -{ - /* Check if right protocol */ - if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { - return LuaCallbackError(luastate, "Error: protocol not SMTP"); - } - /* Extract network flow */ - Flow *flow = LuaStateGetFlow(luastate); - if(flow == NULL) { - return LuaCallbackError(luastate, "Error: no flow found"); - } - - GetMimeList(luastate, flow); - - return 1; -} - -/** - * \brief internal function used by SMTPGetMailFrom - * - * \param luastate luastate stack to pop and push attributes for I/O to lua. - * \param flow flow to get state for SMTP - * - * \retval 1 if mailfrom field found. - * Returns error int and msg pushed to luastate stack if error occurs - */ - -static int GetMailFrom(lua_State *luastate, Flow *flow) -{ - /* Extract SMTPstate from current flow */ - SMTPState *state = (SMTPState *) FlowGetAppState(flow); - - if(state == NULL) { - return LuaCallbackError(luastate, "Internal Error: no state"); - } - SMTPTransaction *smtp_tx = state->curr_tx; - if(smtp_tx == NULL) { - return LuaCallbackError(luastate, "Internal Error: no SMTP transaction"); - } - if(smtp_tx->mail_from == NULL || smtp_tx->mail_from_len == 0) { - return LuaCallbackError(luastate, "MailFrom not found"); - } - return LuaPushStringBuffer(luastate, smtp_tx->mail_from, smtp_tx->mail_from_len); - /* Returns 1 because we never push more then 1 item to the lua stack */ -} - -/** - * \brief Extracts mail_from parameter from SMTPState. - * Attribute may also be available from mimefields, although there is no - * guarantee of it existing as mime. - * - * \param luastate luastate stack to pop and push attributes for I/O to lua. - * - * \retval 1 if mailfrom field found. - * Returns error int and msg pushed to luastate stack if error occurs - */ - -static int SMTPGetMailFrom(lua_State *luastate) -{ - /* check protocol */ - if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { - return LuaCallbackError(luastate, "Error: protocol not SMTP"); - } - /* Extract flow, with lockhint to check mutexlocking */ - Flow *flow = LuaStateGetFlow(luastate); - if(flow == NULL) { - return LuaCallbackError(luastate, "Internal Error: no flow"); - } - - GetMailFrom(luastate, flow); - - return 1; -} - -/** - * \brief intern function used by SMTPGetRcpList - * - * \param luastate luastate stack for internal communication with Lua. - * Used to hand over data to the receiving luascript. - * - * \retval 1 if the table is pushed to lua. - * Returns error int and msg pushed to luastate stack if error occurs - */ - -static int GetRcptList(lua_State *luastate, Flow *flow) -{ - - SMTPState *state = (SMTPState *) FlowGetAppState(flow); - if(state == NULL) { - return LuaCallbackError(luastate, "Internal error, no state"); - } - - SMTPTransaction *smtp_tx = state->curr_tx; - if(smtp_tx == NULL) { - return LuaCallbackError(luastate, "No more tx, or tx not found"); - } - - /* Create a new table in luastate for rcpt list */ - lua_newtable(luastate); - /* rcpt var for iterator */ - int u = 1; - SMTPString *rcpt; - - TAILQ_FOREACH(rcpt, &smtp_tx->rcpt_to_list, next) { - lua_pushinteger(luastate, u++); - LuaPushStringBuffer(luastate, rcpt->str, rcpt->len); - lua_settable(luastate, -3); - } - /* return 1 since we always push one table to luastate */ - return 1; -} - -/** - * \brief function loops through rcpt-list located in - * flow->SMTPState->SMTPTransaction, adding all items to a table. - * Then pushing it to the luastate stack. - * - * \param luastate luastate stack for internal communication with Lua. - * Used to hand over data to the receiving luascript. - * - * \retval 1 if the table is pushed to lua. - * Returns error int and msg pushed to luastate stack if error occurs - */ - -static int SMTPGetRcptList(lua_State *luastate) -{ - /* check protocol */ - if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { - return LuaCallbackError(luastate, "Error: protocol not SMTP"); - } - /* Extract flow, with lockhint to check mutexlocking */ - Flow *flow = LuaStateGetFlow(luastate); - if(flow == NULL) { - return LuaCallbackError(luastate, "Internal error: no flow"); - } - - GetRcptList(luastate, flow); - - /* return 1 since we always push one table to luastate */ - return 1; -} - -int LuaRegisterSmtpFunctions(lua_State *luastate) -{ - - lua_pushcfunction(luastate, SMTPGetMimeField); - lua_setglobal(luastate, "SMTPGetMimeField"); - - lua_pushcfunction(luastate, SMTPGetMimeList); - lua_setglobal(luastate, "SMTPGetMimeList"); - - lua_pushcfunction(luastate, SMTPGetMailFrom); - lua_setglobal(luastate, "SMTPGetMailFrom"); - - lua_pushcfunction(luastate, SMTPGetRcptList); - lua_setglobal(luastate, "SMTPGetRcptList"); - - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-ssh.c b/src/util-lua-ssh.c deleted file mode 100644 index 266d3df860b5..000000000000 --- a/src/util-lua-ssh.c +++ /dev/null @@ -1,219 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -/** - * \file - * - * \author Mats Klepsland - * - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssh.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" -#include "rust.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-ssh.h" - -static int GetServerProtoVersion(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - const uint8_t *protocol = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_protocol(tx, &protocol, &b_len, STREAM_TOCLIENT) != 1) - return LuaCallbackError(luastate, "error: no server proto version"); - if (protocol == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no server proto version"); - } - - return LuaPushStringBuffer(luastate, protocol, b_len); -} - -static int SshGetServerProtoVersion(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetServerProtoVersion(luastate, f); - - return r; -} - -static int GetServerSoftwareVersion(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *software = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_software(tx, &software, &b_len, STREAM_TOCLIENT) != 1) - return LuaCallbackError(luastate, "error: no server software version"); - if (software == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no server software version"); - } - - return LuaPushStringBuffer(luastate, software, b_len); -} - -static int SshGetServerSoftwareVersion(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetServerSoftwareVersion(luastate, f); - - return r; -} - -static int GetClientProtoVersion(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *protocol = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_protocol(tx, &protocol, &b_len, STREAM_TOSERVER) != 1) - return LuaCallbackError(luastate, "error: no client proto version"); - if (protocol == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no client proto version"); - } - - return LuaPushStringBuffer(luastate, protocol, b_len); -} - -static int SshGetClientProtoVersion(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetClientProtoVersion(luastate, f); - - return r; -} - -static int GetClientSoftwareVersion(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - const uint8_t *software = NULL; - uint32_t b_len = 0; - - void *tx = rs_ssh_state_get_tx(state, 0); - if (rs_ssh_tx_get_software(tx, &software, &b_len, STREAM_TOSERVER) != 1) - return LuaCallbackError(luastate, "error: no client software version"); - if (software == NULL || b_len == 0) { - return LuaCallbackError(luastate, "error: no client software version"); - } - - return LuaPushStringBuffer(luastate, software, b_len); -} - -static int SshGetClientSoftwareVersion(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) - return LuaCallbackError(luastate, "error: protocol not ssh"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetClientSoftwareVersion(luastate, f); - - return r; -} - -/** \brief register ssh lua extensions in a luastate */ -int LuaRegisterSshFunctions(lua_State *luastate) -{ - /* registration of the callbacks */ - lua_pushcfunction(luastate, SshGetServerProtoVersion); - lua_setglobal(luastate, "SshGetServerProtoVersion"); - - lua_pushcfunction(luastate, SshGetServerSoftwareVersion); - lua_setglobal(luastate, "SshGetServerSoftwareVersion"); - - lua_pushcfunction(luastate, SshGetClientProtoVersion); - lua_setglobal(luastate, "SshGetClientProtoVersion"); - - lua_pushcfunction(luastate, SshGetClientSoftwareVersion); - lua_setglobal(luastate, "SshGetClientSoftwareVersion"); - - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c deleted file mode 100644 index 9413f42965ca..000000000000 --- a/src/util-lua-tls.c +++ /dev/null @@ -1,367 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -/** - * \file - * - * \author Eric Leblond - * - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "app-layer-ssl.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" -#include "util-lua-common.h" -#include "util-lua-tls.h" - -static int GetCertNotBefore(lua_State *luastate, const Flow *f, int direction) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - SSLStateConnp *connp = NULL; - - if (direction) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_not_before == 0) - return LuaCallbackError(luastate, "error: no certificate NotBefore"); - - int r = LuaPushInteger(luastate, connp->cert0_not_before); - - return r; -} - -static int TlsGetCertNotBefore(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol not tls"); - - int direction = LuaStateGetDirection(luastate); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetCertNotBefore(luastate, f, direction); - - return r; -} - -static int GetCertNotAfter(lua_State *luastate, const Flow *f, int direction) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - SSLStateConnp *connp = NULL; - - if (direction) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_not_after == 0) - return LuaCallbackError(luastate, "error: no certificate NotAfter"); - - int r = LuaPushInteger(luastate, connp->cert0_not_after); - - return r; -} - -static int TlsGetCertNotAfter(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol not tls"); - - int direction = LuaStateGetDirection(luastate); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetCertNotAfter(luastate, f, direction); - - return r; -} - -static int GetCertInfo(lua_State *luastate, const Flow *f, int direction) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - SSLStateConnp *connp = NULL; - - if (direction) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - if (connp->cert0_subject == NULL) - return LuaCallbackError(luastate, "error: no cert"); - - /* tls.version */ - char ssl_version[SSL_VERSION_MAX_STRLEN]; - SSLVersionToString(ssl_state->server_connp.version, ssl_version); - - int r = LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, strlen(ssl_version)); - r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_subject, strlen(connp->cert0_subject)); - r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_issuerdn, strlen(connp->cert0_issuerdn)); - r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_fingerprint, strlen(connp->cert0_fingerprint)); - return r; -} - -static int TlsGetCertInfo(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol not tls"); - - int direction = LuaStateGetDirection(luastate); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetCertInfo(luastate, f, direction); - - return r; -} - -static int GetAgreedVersion(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - - char ssl_version[SSL_VERSION_MAX_STRLEN]; - SSLVersionToString(ssl_state->server_connp.version, ssl_version); - - return LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, - strlen(ssl_version)); -} - -static int TlsGetVersion(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol not tls"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetAgreedVersion(luastate, f); - - return r; -} - -static int GetSNI(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - - if (ssl_state->client_connp.sni == NULL) - return LuaCallbackError(luastate, "error: no server name indication"); - - return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->client_connp.sni, - strlen(ssl_state->client_connp.sni)); -} - -static int TlsGetSNI(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol not tls"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetSNI(luastate, f); - - return r; -} - -static int GetCertSerial(lua_State *luastate, const Flow *f) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - - if (ssl_state->server_connp.cert0_serial == NULL) - return LuaCallbackError(luastate, "error: no certificate serial"); - - return LuaPushStringBuffer(luastate, - (uint8_t *)ssl_state->server_connp.cert0_serial, - strlen(ssl_state->server_connp.cert0_serial)); -} - -static int TlsGetCertSerial(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol not tls"); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetCertSerial(luastate, f); - - return r; -} - -static int GetCertChain(lua_State *luastate, const Flow *f, int direction) -{ - void *state = FlowGetAppState(f); - if (state == NULL) - return LuaCallbackError(luastate, "error: no app layer state"); - - SSLState *ssl_state = (SSLState *)state; - SSLStateConnp *connp = NULL; - - if (direction) { - connp = &ssl_state->client_connp; - } else { - connp = &ssl_state->server_connp; - } - - uint32_t u = 0; - lua_newtable(luastate); - SSLCertsChain *cert = NULL; - TAILQ_FOREACH(cert, &connp->certs, next) - { - lua_pushinteger(luastate, u++); - - lua_newtable(luastate); - - lua_pushstring(luastate, "length"); - lua_pushinteger(luastate, cert->cert_len); - lua_settable(luastate, -3); - - lua_pushstring(luastate, "data"); - LuaPushStringBuffer(luastate, cert->cert_data, cert->cert_len); - - lua_settable(luastate, -3); - lua_settable(luastate, -3); - } - - return 1; -} - -static int TlsGetCertChain(lua_State *luastate) -{ - int r; - - if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) - return LuaCallbackError(luastate, "error: protocol not tls"); - - int direction = LuaStateGetDirection(luastate); - - Flow *f = LuaStateGetFlow(luastate); - if (f == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - r = GetCertChain(luastate, f, direction); - - return r; -} - -/** \brief register tls lua extensions in a luastate */ -int LuaRegisterTlsFunctions(lua_State *luastate) -{ - /* registration of the callbacks */ - lua_pushcfunction(luastate, TlsGetCertNotBefore); - lua_setglobal(luastate, "TlsGetCertNotBefore"); - - lua_pushcfunction(luastate, TlsGetCertNotAfter); - lua_setglobal(luastate, "TlsGetCertNotAfter"); - - lua_pushcfunction(luastate, TlsGetVersion); - lua_setglobal(luastate, "TlsGetVersion"); - - lua_pushcfunction(luastate, TlsGetCertInfo); - lua_setglobal(luastate, "TlsGetCertInfo"); - - lua_pushcfunction(luastate, TlsGetSNI); - lua_setglobal(luastate, "TlsGetSNI"); - - lua_pushcfunction(luastate, TlsGetCertSerial); - lua_setglobal(luastate, "TlsGetCertSerial"); - - lua_pushcfunction(luastate, TlsGetCertChain); - lua_setglobal(luastate, "TlsGetCertChain"); - - return 0; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua.c b/src/util-lua.c deleted file mode 100644 index 9e65c3017fcb..000000000000 --- a/src/util-lua.c +++ /dev/null @@ -1,356 +0,0 @@ -/* Copyright (C) 2014-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Common function for Lua - */ - -#include "suricata-common.h" -#include "detect.h" -#include "pkt-var.h" -#include "conf.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-print.h" -#include "util-unittest.h" -#include "util-luajit.h" - -#include "util-debug.h" - -#include "output.h" -#include "app-layer-htp.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-privs.h" -#include "util-buffer.h" -#include "util-proto-name.h" -#include "util-logopenfile.h" -#include "util-time.h" - -#ifdef HAVE_LUA - -#include -#include -#include - -#include "util-lua.h" - -lua_State *LuaGetState(void) -{ - lua_State *s = NULL; -#ifdef HAVE_LUAJIT - s = LuajitGetState(); -#else - s = luaL_newstate(); -#endif - return s; -} - -void LuaReturnState(lua_State *s) -{ - if (s != NULL) { - /* clear the stack */ - while (lua_gettop(s) > 0) { - lua_pop(s, 1); - } -#ifdef HAVE_LUAJIT - LuajitReturnState(s); -#else - lua_close(s); -#endif - } -} - -/* key for tv (threadvars) pointer */ -const char lua_ext_key_tv[] = "suricata:lua:tv:ptr"; -/* key for tx pointer */ -const char lua_ext_key_tx[] = "suricata:lua:tx:ptr"; -/* key for tx id */ -const char lua_ext_key_tx_id[] = "suricata:lua:tx_id"; -/* key for p (packet) pointer */ -const char lua_ext_key_p[] = "suricata:lua:pkt:ptr"; -/* key for f (flow) pointer */ -const char lua_ext_key_flow[] = "suricata:lua:flow:ptr"; -/* key for flow lock hint bool */ -const char lua_ext_key_flow_lock_hint[] = "suricata:lua:flow:lock_hint"; -/* key for direction */ -const char lua_ext_key_direction[] = "suricata:lua:direction"; - -/* key for pa (packet alert) pointer */ -const char lua_ext_key_pa[] = "suricata:lua:pkt:alert:ptr"; -/* key for s (signature) pointer */ -const char lua_ext_key_s[] = "suricata:lua:signature:ptr"; -/* key for file pointer */ -const char lua_ext_key_file[] = "suricata:lua:file:ptr"; -/* key for DetectEngineThreadCtx pointer */ -const char lua_ext_key_det_ctx[] = "suricata:lua:det_ctx:ptr"; -/* key for streaming buffer pointer */ -const char lua_ext_key_streaming_buffer[] = "suricata:lua:streaming_buffer:ptr"; - -/** \brief get tv pointer from the lua state */ -ThreadVars *LuaStateGetThreadVars(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tv); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *tv = lua_touserdata(luastate, -1); - return (ThreadVars *)tv; -} - -void LuaStateSetThreadVars(lua_State *luastate, ThreadVars *tv) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tv); - lua_pushlightuserdata(luastate, (void *)tv); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief get packet pointer from the lua state */ -Packet *LuaStateGetPacket(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_p); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *p = lua_touserdata(luastate, -1); - return (Packet *)p; -} - -void LuaStateSetPacket(lua_State *luastate, Packet *p) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_p); - lua_pushlightuserdata(luastate, (void *)p); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief get tx pointer from the lua state */ -void *LuaStateGetTX(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *tx = lua_touserdata(luastate, -1); - return tx; -} - -/** \brief get tx id from the lua state */ -uint64_t LuaStateGetTxId(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx_id); - lua_gettable(luastate, LUA_REGISTRYINDEX); - uint64_t tx_id = lua_tointeger(luastate, -1); - return tx_id; -} -void LuaStateSetTX(lua_State *luastate, void *txptr, const uint64_t tx_id) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx); - lua_pushlightuserdata(luastate, (void *)txptr); - lua_settable(luastate, LUA_REGISTRYINDEX); - - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx_id); - lua_pushinteger(luastate, tx_id); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -Flow *LuaStateGetFlow(lua_State *luastate) -{ - Flow *f = NULL; - - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); - lua_gettable(luastate, LUA_REGISTRYINDEX); - f = lua_touserdata(luastate, -1); - - /* need flow lock hint */ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); - lua_gettable(luastate, LUA_REGISTRYINDEX); - - return f; -} - -void LuaStateSetFlow(lua_State *luastate, Flow *f) -{ - /* flow */ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); - lua_pushlightuserdata(luastate, (void *)f); - lua_settable(luastate, LUA_REGISTRYINDEX); - - /* flow lock status hint */ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); - /* locking is not required, set to 0 for backwards compatibility */ - lua_pushboolean(luastate, 0); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief get packet alert pointer from the lua state */ -PacketAlert *LuaStateGetPacketAlert(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_pa); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *pa = lua_touserdata(luastate, -1); - return (PacketAlert *)pa; -} - -void LuaStateSetPacketAlert(lua_State *luastate, PacketAlert *pa) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_pa); - lua_pushlightuserdata(luastate, (void *)pa); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief get signature pointer from the lua state */ -Signature *LuaStateGetSignature(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_s); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *s = lua_touserdata(luastate, -1); - return (Signature *)s; -} - -void LuaStateSetSignature(lua_State *luastate, const Signature *s) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_s); - lua_pushlightuserdata(luastate, (void *)s); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief get file pointer from the lua state */ -File *LuaStateGetFile(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_file); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *file = lua_touserdata(luastate, -1); - return (File *)file; -} - -void LuaStateSetFile(lua_State *luastate, File *file) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_file); - lua_pushlightuserdata(luastate, (void *)file); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief get DetectEngineThreadCtx pointer from the lua state */ -DetectEngineThreadCtx *LuaStateGetDetCtx(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_det_ctx); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *det_ctx = lua_touserdata(luastate, -1); - return (DetectEngineThreadCtx *)det_ctx; -} - -void LuaStateSetDetCtx(lua_State *luastate, DetectEngineThreadCtx *det_ctx) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_det_ctx); - lua_pushlightuserdata(luastate, (void *)det_ctx); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -LuaStreamingBuffer *LuaStateGetStreamingBuffer(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_streaming_buffer); - lua_gettable(luastate, LUA_REGISTRYINDEX); - void *b = lua_touserdata(luastate, -1); - return (LuaStreamingBuffer *)b; -} - -void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_streaming_buffer); - lua_pushlightuserdata(luastate, (void *)b); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief get packet pointer from the lua state */ -int LuaStateGetDirection(lua_State *luastate) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); - lua_gettable(luastate, LUA_REGISTRYINDEX); - int dir = lua_toboolean(luastate, -1); - return dir; -} - -void LuaStateSetDirection(lua_State *luastate, int direction) -{ - lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); - lua_pushboolean(luastate, direction); - lua_settable(luastate, LUA_REGISTRYINDEX); -} - -/** \brief dump stack from lua state to screen */ -void LuaPrintStack(lua_State *state) { - int size = lua_gettop(state); - int i; - - for (i = 1; i <= size; i++) { - int type = lua_type(state, i); - printf("Stack size=%d, level=%d, type=%d, ", size, i, type); - - switch (type) { - case LUA_TFUNCTION: - printf("function %s", lua_tostring(state, i) ? "true" : "false"); - break; - case LUA_TBOOLEAN: - printf("bool %s", lua_toboolean(state, i) ? "true" : "false"); - break; - case LUA_TNUMBER: - printf("number %g", lua_tonumber(state, i)); - break; - case LUA_TSTRING: - printf("string `%s'", lua_tostring(state, i)); - break; - case LUA_TTABLE: - printf("table `%s'", lua_tostring(state, i)); - break; - default: - printf("other %s", lua_typename(state, type)); - break; - - } - printf("\n"); - } -} - -int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len) -{ - if (input_len % 4 != 0) { - /* we're using a buffer sized at a multiple of 4 as lua_pushlstring generates - * invalid read errors in valgrind otherwise. Adding in a nul to be sure. - * - * Buffer size = len + 1 (for nul) + whatever makes it a multiple of 4 */ - size_t buflen = input_len + 1 + ((input_len + 1) % 4); - uint8_t buf[buflen]; - memset(buf, 0x00, buflen); - memcpy(buf, input, input_len); - buf[input_len] = '\0'; - - /* return value through luastate, as a luastring */ - lua_pushlstring(luastate, (char *)buf, input_len); - } else { - lua_pushlstring(luastate, (char *)input, input_len); - } - return 1; -} - -int LuaPushInteger(lua_State *luastate, lua_Integer n) -{ - lua_pushinteger(luastate, n); - return 1; -} - -#endif /* HAVE_LUA */ diff --git a/src/util-lua.h b/src/util-lua.h deleted file mode 100644 index 471692526c55..000000000000 --- a/src/util-lua.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2014-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_LUA_H__ -#define __UTIL_LUA_H__ - -#ifndef HAVE_LUA - -/* If we don't have Lua, create a typedef for lua_State so the - * exported Lua functions don't fail the build. */ -typedef void lua_State; - -#else -#include "threadvars.h" -#include "detect.h" - -typedef struct LuaStreamingBuffer_ { - const uint8_t *data; - uint32_t data_len; - uint8_t flags; -} LuaStreamingBuffer; - -lua_State *LuaGetState(void); -void LuaReturnState(lua_State *s); - -/* gets */ - -/** \brief get tv pointer from the lua state */ -ThreadVars *LuaStateGetThreadVars(lua_State *luastate); - -Packet *LuaStateGetPacket(lua_State *luastate); -void *LuaStateGetTX(lua_State *luastate); -uint64_t LuaStateGetTxId(lua_State *luastate); - -/** \brief get flow pointer from lua state - * - * \retval f flow pointer or NULL if it was not set - */ -Flow *LuaStateGetFlow(lua_State *luastate); - -PacketAlert *LuaStateGetPacketAlert(lua_State *luastate); - -Signature *LuaStateGetSignature(lua_State *luastate); - -/** \brief get file pointer from the lua state */ -File *LuaStateGetFile(lua_State *luastate); - -/** \brief get detect engine thread context pointer from the lua state */ -DetectEngineThreadCtx *LuaStateGetDetCtx(lua_State *luastate); - -LuaStreamingBuffer *LuaStateGetStreamingBuffer(lua_State *luastate); - -int LuaStateGetDirection(lua_State *luastate); - -/* sets */ - -void LuaStateSetPacket(lua_State *luastate, Packet *p); -void LuaStateSetTX(lua_State *luastate, void *tx, const uint64_t tx_id); - -/** \brief set a flow pointer in the lua state - * - * \param f flow pointer - */ -void LuaStateSetFlow(lua_State *luastate, Flow *f); - -void LuaStateSetPacketAlert(lua_State *luastate, PacketAlert *pa); - -void LuaStateSetSignature(lua_State *luastate, const Signature *s); - -void LuaStateSetFile(lua_State *luastate, File *file); - -void LuaStateSetDetCtx(lua_State *luastate, DetectEngineThreadCtx *det_ctx); - -void LuaStateSetThreadVars(lua_State *luastate, ThreadVars *tv); - -void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b); - -void LuaStateSetDirection(lua_State *luastate, int direction); - -void LuaPrintStack(lua_State *state); - -int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len); - -int LuaPushInteger(lua_State *luastate, lua_Integer n); - -#endif /* HAVE_LUA */ - -#endif /* __UTIL_LUA_H__ */ diff --git a/src/util-luajit.c b/src/util-luajit.c deleted file mode 100644 index a089e139cfcf..000000000000 --- a/src/util-luajit.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#include "suricata-common.h" - -#ifdef HAVE_LUAJIT -#include "conf.h" -#include "util-pool.h" -#include "util-lua.h" -#include "util-luajit.h" - -/** \brief lua_State pool - * - * Lua requires states to be alloc'd in memory <2GB. For this reason we - * prealloc the states early during engine startup so we have a better chance - * of getting the states. We protect the pool with a lock as the detect - * threads access it during their init and cleanup. - * - * Pool size is automagically determined based on number of keyword occurrences, - * cpus/cores and rule reloads being enabled or not. - * - * Alternatively, the "detect-engine.luajit-states" var can be set. - */ -static Pool *luajit_states = NULL; -static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; -static int luajit_states_cnt = 0; -static int luajit_states_cnt_max = 0; -static int luajit_states_size = 0; -#define LUAJIT_DEFAULT_STATES 128 - -static void *LuaStatePoolAlloc(void) -{ - return luaL_newstate(); -} - -static void LuaStatePoolFree(void *d) -{ - lua_State *s = (lua_State *)d; - if (s != NULL) - lua_close(s); -} - -/** \brief Populate lua states pool - * - * \param num keyword instances - * \param reloads bool indicating we have rule reloads enabled - */ -int LuajitSetupStatesPool(void) -{ - int retval = 0; - pthread_mutex_lock(&luajit_states_lock); - - if (luajit_states == NULL) { - intmax_t cnt = 0; - if (ConfGetInt("luajit.states", &cnt) != 1) { - ConfNode *denode = NULL; - ConfNode *decnf = ConfGetNode("detect-engine"); - if (decnf != NULL) { - TAILQ_FOREACH(denode, &decnf->head, next) { - if (denode->val && strcmp(denode->val, "luajit-states") == 0) { - ConfGetChildValueInt(denode, "luajit-states", &cnt); - } - } - } - } - if (cnt == 0) { - cnt = LUAJIT_DEFAULT_STATES; - } - luajit_states_size = cnt; - - luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); - if (luajit_states == NULL) { - SCLogError("luastate pool init failed, lua/luajit keywords won't work"); - retval = -1; - } - - if (retval == 0) { - SCLogConfig("luajit states preallocated: %d", luajit_states_size); - } - } - - pthread_mutex_unlock(&luajit_states_lock); - return retval; -} - -void LuajitFreeStatesPool(void) -{ - pthread_mutex_lock(&luajit_states_lock); - if (luajit_states_cnt_max > luajit_states_size) { - SCLogNotice("luajit states used %d is bigger than pool size %d. Set " - "luajit.states to %d to avoid memory issues. " - "See tickets #1577 and #1955.", - luajit_states_cnt_max, luajit_states_size, luajit_states_cnt_max); - } - PoolFree(luajit_states); - luajit_states = NULL; - luajit_states_size = 0; - luajit_states_cnt = 0; - pthread_mutex_unlock(&luajit_states_lock); -} - -lua_State *LuajitGetState(void) -{ - lua_State *s = NULL; - pthread_mutex_lock(&luajit_states_lock); - if (luajit_states != NULL) { - s = (lua_State *)PoolGet(luajit_states); - if (s != NULL) { - if (luajit_states_cnt == luajit_states_size) { - SCLogWarning("luajit states pool size %d " - "reached. Increase luajit.states config option. " - "See tickets #1577 and #1955", - luajit_states_size); - } - - luajit_states_cnt++; - if (luajit_states_cnt > luajit_states_cnt_max) - luajit_states_cnt_max = luajit_states_cnt; - } - } - pthread_mutex_unlock(&luajit_states_lock); - return s; -} - -void LuajitReturnState(lua_State *s) -{ - if (s != NULL) { - pthread_mutex_lock(&luajit_states_lock); - PoolReturn(luajit_states, (void *)s); - BUG_ON(luajit_states_cnt <= 0); - luajit_states_cnt--; - pthread_mutex_unlock(&luajit_states_lock); - } -} - -#endif /* HAVE_LUAJIT */ diff --git a/src/util-luajit.h b/src/util-luajit.h deleted file mode 100644 index b90cef431b47..000000000000 --- a/src/util-luajit.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_LUAJIT_H__ -#define __UTIL_LUAJIT_H__ - -#ifdef HAVE_LUAJIT - -#include "util-lua.h" - -int LuajitSetupStatesPool(void); -void LuajitFreeStatesPool(void); -lua_State *LuajitGetState(void); -void LuajitReturnState(lua_State *s); - -#endif /* HAVE_LUAJIT */ - -#endif /* __UTIL_LUAJIT_H__ */ diff --git a/src/util-macset.c b/src/util-macset.c deleted file mode 100644 index 9853a3241680..000000000000 --- a/src/util-macset.c +++ /dev/null @@ -1,431 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - * - * Set-like data store for MAC addresses. Implemented as array for memory - * locality reasons as the expected number of items is typically low. - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "flow-util.h" -#include "flow-private.h" -#include "flow-storage.h" -#include "util-macset.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -typedef uint8_t MacAddr[6]; -typedef enum { - EMPTY_SET, /* no address inserted yet */ - SINGLE_MAC, /* we have a single pair of addresses (likely) */ - MULTI_MAC /* we have multiple addresses per flow */ -} MacSetState; - -struct MacSet_ { - /* static store for a single MAC address per side */ - MacAddr singles[2]; - /* state determines how addresses are stored per side: - - SINGLE_MAC uses static locations allocated with the MacSet - itself to store a single address (most likely case) - - MULTI_MAC is used when more than one distinct address - is detected (causes another allocation and linear-time add) */ - MacSetState state[2]; - /* buffer for multiple MACs per flow and direction */ - MacAddr *buf[2]; - int size, - last[2]; -}; - -FlowStorageId g_macset_storage_id = { .id = -1 }; - -void MacSetRegisterFlowStorage(void) -{ - ConfNode *root = ConfGetNode("outputs"); - ConfNode *node = NULL; - /* we only need to register if at least one enabled 'eve-log' output - has the ethernet setting enabled */ - if (root != NULL) { - TAILQ_FOREACH(node, &root->head, next) { - if (node->val && strcmp(node->val, "eve-log") == 0) { - const char *enabled = ConfNodeLookupChildValue(node->head.tqh_first, "enabled"); - if (enabled != NULL && ConfValIsTrue(enabled)) { - const char *ethernet = ConfNodeLookupChildValue(node->head.tqh_first, "ethernet"); - if (ethernet != NULL && ConfValIsTrue(ethernet)) { - g_macset_storage_id = FlowStorageRegister("macset", sizeof(void *), - NULL, (void(*)(void *)) MacSetFree); - return; - } - } - } - } - } -} - -bool MacSetFlowStorageEnabled(void) -{ - return (g_macset_storage_id.id != -1); -} - - -MacSet *MacSetInit(int size) -{ - MacSet *ms = NULL; - if (!FLOW_CHECK_MEMCAP(sizeof(*ms))) { - return NULL; - } - ms = SCCalloc(1, sizeof(*ms)); - if (unlikely(ms == NULL)) { - SCLogError("Unable to allocate MacSet memory"); - return NULL; - } - (void) SC_ATOMIC_ADD(flow_memuse, (sizeof(*ms))); - ms->state[MAC_SET_SRC] = ms->state[MAC_SET_DST] = EMPTY_SET; - if (size < 3) { - /* we want to make sure we have at space for at least 3 items to - fit MACs during the initial extension to MULTI_MAC storage */ - size = 3; - } - ms->size = size; - ms->last[MAC_SET_SRC] = ms->last[MAC_SET_DST] = 0; - return ms; -} - -FlowStorageId MacSetGetFlowStorageID(void) -{ - return g_macset_storage_id; -} - -static inline void MacUpdateEntry(MacSet *ms, uint8_t *addr, int side, ThreadVars *tv, uint16_t ctr) -{ - switch (ms->state[side]) { - case EMPTY_SET: - memcpy(ms->singles[side], addr, sizeof(MacAddr)); - ms->state[side] = SINGLE_MAC; - if (tv != NULL) - StatsSetUI64(tv, ctr, 1); - break; - case SINGLE_MAC: - if (unlikely(memcmp(addr, ms->singles[side], sizeof(MacAddr)) != 0)) { - if (ms->buf[side] == NULL) { - if (!FLOW_CHECK_MEMCAP(ms->size * sizeof(MacAddr))) { - /* in this case there is not much we can do */ - return; - } - ms->buf[side] = SCCalloc(ms->size, sizeof(MacAddr)); - if (unlikely(ms->buf[side] == NULL)) { - SCLogError("Unable to allocate " - "MacSet memory"); - return; - } - (void) SC_ATOMIC_ADD(flow_memuse, (ms->size * sizeof(MacAddr))); - } - memcpy(ms->buf[side], ms->singles[side], sizeof(MacAddr)); - memcpy(ms->buf[side] + 1, addr, sizeof(MacAddr)); - ms->last[side] = 2; - if (tv != NULL) - StatsSetUI64(tv, ctr, 2); - ms->state[side] = MULTI_MAC; - } - break; - case MULTI_MAC: - if (unlikely(ms->last[side] == ms->size)) { - /* MacSet full, ignore item. We intentionally do not output - any warning in order not to stall packet processing */ - return; - } - /* If the set is non-empty... */ - if (ms->last[side] > 0) { - /* ...we search for duplicates in the set to decide whether - we need to insert the current item. We do this backwards, - since we expect the latest item to match more likely than - the first */ - for (int i = ms->last[side] - 1; i >= 0; i--) { - uint8_t *addr2 = (uint8_t*) ((ms->buf[side]) + i); - /* If we find a match, we return early with no action */ - if (likely(memcmp(addr2, addr, sizeof(MacAddr)) == 0)) { - return; - } - } - } - /* Otherwise, we insert the new address at the end */ - memcpy(ms->buf[side] + ms->last[side], addr, sizeof(MacAddr)); - ms->last[side]++; - if (tv != NULL) - StatsSetUI64(tv, ctr, ms->last[side]); - break; - } -} - -void MacSetAddWithCtr(MacSet *ms, uint8_t *src_addr, uint8_t *dst_addr, ThreadVars *tv, - uint16_t ctr_src, uint16_t ctr_dst) -{ - if (ms == NULL) - return; - MacUpdateEntry(ms, src_addr, MAC_SET_SRC, tv, ctr_src); - MacUpdateEntry(ms, dst_addr, MAC_SET_DST, tv, ctr_dst); -} - -void MacSetAdd(MacSet *ms, uint8_t *src_addr, uint8_t *dst_addr) -{ - MacSetAddWithCtr(ms, src_addr, dst_addr, NULL, 0, 0); -} - -static inline int MacSetIterateSide(const MacSet *ms, MacSetIteratorFunc IterFunc, - MacSetSide side, void *data) -{ - int ret = 0; - switch (ms->state[side]) { - case EMPTY_SET: - return 0; - case SINGLE_MAC: - ret = IterFunc((uint8_t*) ms->singles[side], side, data); - if (unlikely(ret != 0)) { - return ret; - } - break; - case MULTI_MAC: - for (int i = 0; i < ms->last[side]; i++) { - ret = IterFunc((uint8_t*) ms->buf[side][i], side, data); - if (unlikely(ret != 0)) { - return ret; - } - } - break; - } - return 0; -} - -int MacSetForEach(const MacSet *ms, MacSetIteratorFunc IterFunc, void *data) -{ - int ret = 0; - if (ms == NULL) - return 0; - - ret = MacSetIterateSide(ms, IterFunc, MAC_SET_SRC, data); - if (ret != 0) { - return ret; - } - return MacSetIterateSide(ms, IterFunc, MAC_SET_DST, data); -} - -int MacSetSize(const MacSet *ms) -{ - int size = 0; - if (ms == NULL) - return 0; - - switch(ms->state[MAC_SET_SRC]) { - case EMPTY_SET: - /* pass */ - break; - case SINGLE_MAC: - size += 1; - break; - case MULTI_MAC: - size += ms->last[MAC_SET_SRC]; - break; - } - switch(ms->state[MAC_SET_DST]) { - case EMPTY_SET: - /* pass */ - break; - case SINGLE_MAC: - size += 1; - break; - case MULTI_MAC: - size += ms->last[MAC_SET_DST]; - break; - } - return size; -} - -void MacSetFree(MacSet *ms) -{ - size_t total_free = 0; - if (ms == NULL) - return; - if (ms->buf[MAC_SET_SRC] != NULL) { - SCFree(ms->buf[MAC_SET_SRC]); - total_free += ms->size * sizeof(MacAddr); - } - if (ms->buf[MAC_SET_DST] != NULL) { - SCFree(ms->buf[MAC_SET_DST]); - total_free += ms->size * sizeof(MacAddr); - } - SCFree(ms); - total_free += sizeof(*ms); - (void) SC_ATOMIC_SUB(flow_memuse, total_free); -} - -#ifdef UNITTESTS - -static int CheckTest1Membership(uint8_t *addr, MacSetSide side, void *data) -{ - int *i = (int*) data; - switch (*i) { - case 0: - if (addr[5] != 1) return 1; - break; - case 1: - if (addr[5] != 2) return 1; - break; - case 2: - if (addr[5] != 3) return 1; - break; - } - (*i)++; - return 0; -} - -static int MacSetTest01(void) -{ - MacSet *ms = NULL; - int ret = 0, i = 0; - MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, - addr2 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, - addr3 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3}; - SC_ATOMIC_SET(flow_config.memcap, 10000); - - ms = MacSetInit(10); - FAIL_IF_NULL(ms); - FAIL_IF_NOT(MacSetSize(ms) == 0); - - ret = MacSetForEach(ms, CheckTest1Membership, &i); - FAIL_IF_NOT(ret == 0); - - MacSetAdd(ms, addr1, addr2); - FAIL_IF_NOT(MacSetSize(ms) == 2); - - ret = MacSetForEach(ms, CheckTest1Membership, &i); - FAIL_IF_NOT(ret == 0); - - MacSetAdd(ms, addr1, addr3); - FAIL_IF_NOT(MacSetSize(ms) == 3); - - i = 0; - ret = MacSetForEach(ms, CheckTest1Membership, &i); - FAIL_IF_NOT(ret == 0); - - MacSetFree(ms); - PASS; -} - -static int MacSetTest02(void) -{ - MacSet *ms = NULL; - int ret = 0, i = 0; - SC_ATOMIC_SET(flow_config.memcap, 10000); - - ms = MacSetInit(10); - FAIL_IF_NULL(ms); - FAIL_IF_NOT(MacSetSize(ms) == 0); - - for (i = 1; i < 100; i++) { - MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, - addr2 = {0x1, 0x0, 0x0, 0x0, 0x0, 0x2}; - MacSetAdd(ms, addr1, addr2); - } - FAIL_IF_NOT(MacSetSize(ms) == 2); - - ret = MacSetForEach(ms, CheckTest1Membership, &i); - FAIL_IF_NOT(ret == 0); - - MacSetFree(ms); - PASS; -} - -static int MacSetTest03(void) -{ - MacSet *ms = NULL; - SC_ATOMIC_SET(flow_config.memcap, 10000); - - ms = MacSetInit(10); - FAIL_IF_NULL(ms); - FAIL_IF_NOT(MacSetSize(ms) == 0); - - for (uint8_t i = 1; i < 100; i++) { - MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, - addr2 = {0x1, 0x0, 0x0, 0x0, 0x0, 0x1}; - addr1[5] = i; - addr2[5] = i; - MacSetAdd(ms, addr1, addr2); - } - FAIL_IF_NOT(MacSetSize(ms) == 20); - - MacSetFree(ms); - PASS; -} - -static int MacSetTest04(void) -{ - MacSet *ms = NULL; - SC_ATOMIC_SET(flow_config.memcap, 2); - - ms = MacSetInit(10); - FAIL_IF_NOT_NULL(ms); - - PASS; -} - -static int MacSetTest05(void) -{ - MacSet *ms = NULL; - int ret = 0; - SC_ATOMIC_SET(flow_config.memcap, 64); - - ms = MacSetInit(10); - FAIL_IF_NULL(ms); - FAIL_IF_NOT(MacSetSize(ms) == 0); - - for (uint8_t i = 1; i < 100; i++) { - MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, - addr2 = {0x1, 0x0, 0x0, 0x0, 0x0, 0x1}; - addr1[5] = i; - addr2[5] = i; - MacSetAdd(ms, addr1, addr2); - } - FAIL_IF_NOT(MacSetSize(ms) == 2); - - int i2 = 100; - ret = MacSetForEach(ms, CheckTest1Membership, &i2); - FAIL_IF_NOT(ret == 0); - - MacSetFree(ms); - PASS; -} - -#endif /* UNITTESTS */ - -void MacSetRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("MacSetTest01", MacSetTest01); - UtRegisterTest("MacSetTest02", MacSetTest02); - UtRegisterTest("MacSetTest03", MacSetTest03); - UtRegisterTest("MacSetTest04", MacSetTest04); - UtRegisterTest("MacSetTest05", MacSetTest05); -#endif - - return; -} diff --git a/src/util-macset.h b/src/util-macset.h deleted file mode 100644 index 1b17255593c5..000000000000 --- a/src/util-macset.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Sascha Steinbiss - */ - -#ifndef __UTIL_MACSET_H__ -#define __UTIL_MACSET_H__ - -typedef struct MacSet_ MacSet; -typedef enum { - MAC_SET_SRC = 0, - MAC_SET_DST -} MacSetSide; - -typedef int (*MacSetIteratorFunc)(uint8_t *addr, MacSetSide side, void*); - -MacSet *MacSetInit(int size); -void MacSetAdd(MacSet*, uint8_t *src_addr, uint8_t *dst_addr); -void MacSetAddWithCtr(MacSet*, uint8_t *src_addr, uint8_t *dst_addr, ThreadVars *tv, - uint16_t ctr_src, uint16_t ctr_dst); -int MacSetForEach(const MacSet*, MacSetIteratorFunc, void*); -int MacSetSize(const MacSet*); -void MacSetReset(MacSet*); -void MacSetFree(MacSet*); -void MacSetRegisterFlowStorage(void); -FlowStorageId MacSetGetFlowStorageID(void); -bool MacSetFlowStorageEnabled(void); -void MacSetRegisterTests(void); - -#endif /* __UTIL_MACSET_H__ */ diff --git a/src/util-magic.c b/src/util-magic.c deleted file mode 100644 index 63c991cc92d8..000000000000 --- a/src/util-magic.c +++ /dev/null @@ -1,602 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Wrappers and tests for libmagic usage. - * - * Libmagic's API is not thread safe. The data the pointer returned by - * magic_buffer is overwritten by the next magic_buffer call. This is - * why we need to lock calls and copy the returned string. - */ - -#include "suricata-common.h" -#include "conf.h" -#include "util-unittest.h" -#include "util-magic.h" -#include "util-debug.h" - -#ifdef HAVE_MAGIC - -/** - * \brief Initialize a "magic" context. - */ -magic_t MagicInitContext(void) -{ - magic_t ctx; - const char *filename = NULL; - FILE *fd = NULL; - - ctx = magic_open(0); - if (ctx == NULL) { - SCLogError("magic_open failed: %s", magic_error(ctx)); - goto error; - } - - (void)ConfGet("magic-file", &filename); - - - if (filename != NULL) { - if (strlen(filename) == 0) { - /* set filename to NULL on *nix systems so magic_load uses system - * default path (see man libmagic) */ - SCLogConfig("using system default magic-file"); - filename = NULL; - } - else { - SCLogConfig("using magic-file %s", filename); - - if ( (fd = fopen(filename, "r")) == NULL) { - SCLogWarning("Error opening file: \"%s\": %s", filename, strerror(errno)); - goto error; - } - fclose(fd); - } - } - - if (magic_load(ctx, filename) != 0) { - SCLogError("magic_load failed: %s", magic_error(ctx)); - goto error; - } - return ctx; - -error: - if (ctx != NULL) { - magic_close(ctx); - ctx = NULL; - } - return NULL; -} - - -void MagicDeinitContext(magic_t ctx) -{ - if (ctx != NULL) - magic_close(ctx); -} - -/** - * \brief Find the magic value for a buffer. - * - * \param buf the buffer - * \param buflen length of the buffer - * - * \retval result pointer to null terminated string - */ -char *MagicThreadLookup(magic_t *ctx, const uint8_t *buf, uint32_t buflen) -{ - const char *result = NULL; - char *magic = NULL; - - if (buf != NULL && buflen > 0) { - result = magic_buffer(*ctx, (void *)buf, (size_t)buflen); - if (result != NULL) { - magic = SCStrdup(result); - if (unlikely(magic == NULL)) { - SCLogError("Unable to dup magic"); - } - } - } - - SCReturnPtr(magic, "const char"); -} - -#ifdef UNITTESTS - -#if defined OS_FREEBSD || defined OS_DARWIN -#define MICROSOFT_OFFICE_DOC "OLE 2 Compound Document" -#else -#define MICROSOFT_OFFICE_DOC "Microsoft Office Document" -#endif - -/** \test magic lib calls -- init */ -static int MagicInitTest01(void) -{ - int result = 0; - magic_t magic_ctx; - - magic_ctx = magic_open(0); - if (magic_ctx == NULL) { - printf("failure retrieving magic_ctx\n"); - return 0; - } - - if (magic_load(magic_ctx, NULL) == -1) { - printf("failure magic_load\n"); - goto end; - } - - result = 1; - end: - magic_close(magic_ctx); - return result; -} - -/** \test magic lib calls -- lookup */ -static int MagicDetectTest01(void) -{ - magic_t magic_ctx; - char *result = NULL; - char buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a}; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - magic_ctx = magic_open(0); - if (magic_ctx == NULL) { - printf("failure retrieving magic_ctx\n"); - return 0; - } - - if (magic_load(magic_ctx, NULL) == -1) { - printf("magic_load failure\n"); - goto end; - } - - result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - if (result == NULL || strncmp(result, "PDF document", 12) != 0) { - printf("result %p:%s, not \"PDF document\": ", result,result?result:"(null)"); - goto end; - } - - retval = 1; -end: - magic_close(magic_ctx); - return retval; -} -#if 0 -/** \test magic lib calls -- lookup */ -static int MagicDetectTest02(void) -{ - magic_t magic_ctx; - char *result = NULL; - - char buffer[] = { - 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0xfe, 0xff, 0x09, 0x00, - - 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, - - 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - magic_ctx = magic_open(0); - if (magic_ctx == NULL) { - printf("failure retrieving magic_ctx\n"); - return 0; - } - - if (magic_load(magic_ctx, NULL) == -1) { - printf("magic_load failure\n"); - goto end; - } - - result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - if (result == NULL || strcmp(result, MICROSOFT_OFFICE_DOC) != 0) { - printf("result %p:%s, not \"Microsoft Office Document\": ", result,result?result:"(null)"); - goto end; - } - - retval = 1; -end: - magic_close(magic_ctx); - return retval; -} -#endif -/** \test magic lib calls -- lookup */ -static int MagicDetectTest03(void) -{ - char buffer[] = { - 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6, - 0x32, 0x0c, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, - - 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, - 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - - 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x4b, 0x03, - 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, - 0x55, 0x2a, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, - 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, - - 0x73, 0x62, 0x61, 0x72, 0x2f, 0x50, 0x4b, 0x03, - 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, - }; - size_t buffer_len = sizeof(buffer); - - magic_t magic_ctx = magic_open(0); - FAIL_IF_NULL(magic_ctx); - - FAIL_IF(magic_load(magic_ctx, NULL) == -1); - - char *result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - FAIL_IF_NULL(result); - - char *str = strstr(result, "OpenDocument Text"); - FAIL_IF_NULL(str); - - magic_close(magic_ctx); - PASS; -} - -/** \test magic lib calls -- lookup */ -static int MagicDetectTest04(void) -{ - magic_t magic_ctx; - char *result = NULL; - - char buffer[] = { - 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x8b, 0x70, - 0x96, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, - - 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, - 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x62, 0x61, - - 0x73, 0x65, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - - 0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46, - 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, - 0x08, 0x08, 0x00, 0xa8, 0x42, 0x1d, 0x37, 0x5d, - 0xa7, 0xb2, 0xc1, 0xde, 0x01, 0x00, 0x00, 0x7e, - - 0x04, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x78, - 0x6d, 0x6c, 0x95, 0x54, 0x4d, 0x6f, 0xdb, 0x30, - 0x0c, 0xbd, 0xe7, 0x57, 0x18, 0x02, 0x06, 0x6c, - - 0x07, 0xc5, 0xe9, 0xb6, 0xc3, 0x22, 0xc4, 0x29, - 0x86, 0x7d, 0x00, 0x05, 0x8a, 0x9d, 0xb2, 0x43, - 0x8f, 0xb2, 0x24, 0xa7, 0xc2, 0x64, 0xc9, 0x15, - }; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - magic_ctx = magic_open(0); - if (magic_ctx == NULL) { - printf("failure retrieving magic_ctx\n"); - return 0; - } - - if (magic_load(magic_ctx, NULL) == -1) { - printf("magic_load failure\n"); - goto end; - } - - result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { - printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result,result?result:"(null)"); - goto end; - } - - retval = 1; -end: - magic_close(magic_ctx); - return retval; -} - - -/** \test magic api calls -- lookup */ -static int MagicDetectTest05(void) -{ - const char *result = NULL; - magic_t ctx = NULL; - uint8_t buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a}; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - - ctx = MagicInitContext(); - FAIL_IF(ctx == NULL); - - result = MagicThreadLookup(&ctx, buffer, buffer_len); - if (result == NULL || strncmp(result, "PDF document", 12) != 0) { - printf("result %p:%s, not \"PDF document\": ", result,result?result:"(null)"); - goto end; - } - - retval = 1; -end: - MagicDeinitContext(ctx); - return retval; -} - -#if 0 -/** \test magic api calls -- lookup */ -static int MagicDetectTest06(void) -{ - const char *result = NULL; - uint8_t buffer[] = { - 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0xfe, 0xff, 0x09, 0x00, - - 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, - - 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - if (MagicInit() < 0) { - printf("MagicInit() failure\n"); - return 0; - } - - result = MagicGlobalLookup(buffer, buffer_len); - if (result == NULL || strcmp(result, MICROSOFT_OFFICE_DOC) != 0) { - printf("result %p:%s, not \"Microsoft Office Document\": ", result,result?result:"(null)"); - goto end; - } - - retval = 1; - -end: - MagicDeinit(); - return retval; -} -#endif -/** \test magic api calls -- lookup */ -static int MagicDetectTest07(void) -{ - const char *result = NULL; - magic_t ctx = NULL; - uint8_t buffer[] = { - 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6, - 0x32, 0x0c, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, - - 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, - 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - - 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x4b, 0x03, - 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, - 0x55, 0x2a, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, - 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, - - 0x73, 0x62, 0x61, 0x72, 0x2f, 0x50, 0x4b, 0x03, - 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, - }; - size_t buffer_len = sizeof(buffer); - - ctx = MagicInitContext(); - FAIL_IF(ctx == NULL); - - result = MagicThreadLookup(&ctx, buffer, buffer_len); - FAIL_IF_NULL(result); - - char *str = strstr(result, "OpenDocument Text"); - FAIL_IF_NULL(str); - - MagicDeinitContext(ctx); - PASS; -} - -/** \test magic api calls -- lookup */ -static int MagicDetectTest08(void) -{ - const char *result = NULL; - magic_t ctx = NULL; - uint8_t buffer[] = { - 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x8b, 0x70, - 0x96, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, - - 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, - 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x62, 0x61, - - 0x73, 0x65, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - - 0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46, - 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, - 0x08, 0x08, 0x00, 0xa8, 0x42, 0x1d, 0x37, 0x5d, - 0xa7, 0xb2, 0xc1, 0xde, 0x01, 0x00, 0x00, 0x7e, - - 0x04, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x78, - 0x6d, 0x6c, 0x95, 0x54, 0x4d, 0x6f, 0xdb, 0x30, - - 0x0c, 0xbd, 0xe7, 0x57, 0x18, 0x02, 0x06, 0x6c, - 0x07, 0xc5, 0xe9, 0xb6, 0xc3, 0x22, 0xc4, 0x29, - 0x86, 0x7d, 0x00, 0x05, 0x8a, 0x9d, 0xb2, 0x43, - 0x8f, 0xb2, 0x24, 0xa7, 0xc2, 0x64, 0xc9, 0x15, - }; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - ctx = MagicInitContext(); - FAIL_IF(ctx == NULL); - - result = MagicThreadLookup(&ctx, buffer, buffer_len); - if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { - printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result,result?result:"(null)"); - goto end; - } - - retval = 1; -end: - MagicDeinitContext(ctx); - return retval; -} -#if 0 -/** \test magic api calls -- make sure memory is shared */ -static int MagicDetectTest09(void) -{ - const char *result1 = NULL; - const char *result2 = NULL; - uint8_t buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a}; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - if (MagicInit() < 0) { - printf("MagicInit() failure\n"); - return 0; - } - - result1 = MagicGlobalLookup(buffer, buffer_len); - if (result1 == NULL || strncmp(result1, "PDF document", 12) != 0) { - printf("result %p:%s, not \"PDF document\": ", result1,result1?result1:"(null)"); - goto end; - } - - result2 = MagicGlobalLookup(buffer, buffer_len); - if (result2 == NULL || strncmp(result2, "PDF document", 12) != 0) { - printf("result %p:%s, not \"PDF document\": ", result2,result2?result2:"(null)"); - goto end; - } - - if (result1 != result2) { - printf("pointers not equal, weird... %p != %p: ", result1, result2); - goto end; - } - - retval = 1; -end: - MagicDeinit(); - return retval; -} -#endif -/** \test results in valgrind warning about invalid read, tested with - * file 5.09 and 5.11 */ -static int MagicDetectTest10ValgrindError(void) -{ - const char *result = NULL; - magic_t ctx = NULL; - uint8_t buffer[] = { - 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2C, - 0x01,0x2C,0x00,0x00,0xFF,0xFE,0x00,0x4C,0x53,0x69,0x67,0x6E,0x61,0x74,0x75,0x72, - 0x65,0x3A,0x34,0x31,0x31,0x65,0x33,0x38,0x61,0x61,0x61,0x31,0x37,0x65,0x33,0x30, - 0x66,0x30,0x32,0x38,0x62,0x61,0x30,0x31,0x36,0x32,0x36,0x37,0x66,0x66,0x30,0x31, - 0x36,0x36,0x61,0x65,0x35,0x39,0x65,0x38,0x31,0x39,0x62,0x61,0x32,0x34,0x63,0x39, - 0x62,0x31,0x33,0x37,0x33,0x62,0x31,0x61,0x35,0x61,0x38,0x65,0x64,0x63,0x36,0x30, - 0x65,0x37,0xFF,0xE2,0x02,0x2C,0x49,0x43,0x43,0x5F,0x50,0x52,0x4F,0x46,0x49,0x4C, - 0x45,0x00,0x01,0x01,0x00,0x00,0x02,0x1C,0x41,0x44,0x42,0x45,0x02,0x10,0x00,0x00, - 0x6D,0x6E,0x74,0x72,0x52,0x47,0x42,0x20,0x58,0x59,0x5A,0x20,0x07,0xCF,0x00,0x05, - 0x00,0x09,0x00,0x15,0x00,0x0B,0x00,0x21,0x61,0x63,0x73,0x70,0x41,0x50,0x50,0x4C, - 0x00,0x00,0x00,0x00,0x6E,0x6F,0x6E,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - }; - size_t buffer_len = sizeof(buffer); - int retval = 0; - - - ctx = MagicInitContext(); - FAIL_IF(ctx == NULL); - - result = MagicThreadLookup(&ctx, buffer, buffer_len); - if (result == NULL || strncmp(result, "JPEG", 4) != 0) { - printf("result %p:%s, not \"JPEG\": ", result,result?result:"(null)"); - goto end; - } - - retval = 1; -end: - MagicDeinitContext(ctx); - return retval; -} - -#endif /* UNITTESTS */ -#endif - -void MagicRegisterTests(void) -{ -#ifdef HAVE_MAGIC -#ifdef UNITTESTS - UtRegisterTest("MagicInitTest01", MagicInitTest01); - UtRegisterTest("MagicDetectTest01", MagicDetectTest01); - //UtRegisterTest("MagicDetectTest02", MagicDetectTest02, 1); - UtRegisterTest("MagicDetectTest03", MagicDetectTest03); - UtRegisterTest("MagicDetectTest04", MagicDetectTest04); - UtRegisterTest("MagicDetectTest05", MagicDetectTest05); - //UtRegisterTest("MagicDetectTest06", MagicDetectTest06, 1); - UtRegisterTest("MagicDetectTest07", MagicDetectTest07); - UtRegisterTest("MagicDetectTest08", MagicDetectTest08); - /* fails in valgrind, somehow it returns different pointers then. - UtRegisterTest("MagicDetectTest09", MagicDetectTest09, 1); */ - - UtRegisterTest("MagicDetectTest10ValgrindError", - MagicDetectTest10ValgrindError); -#endif /* UNITTESTS */ -#endif /* HAVE_MAGIC */ -} - diff --git a/src/util-mem.c b/src/util-mem.c deleted file mode 100644 index babdfa3f5671..000000000000 --- a/src/util-mem.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-atomic.h" -#include "util-debug.h" - -#if defined(_WIN32) || defined(__WIN32) -#include -#endif - -SC_ATOMIC_EXTERN(unsigned int, engine_stage); - -void *SCMallocFunc(const size_t sz) -{ - void *ptrmem = malloc(sz); - if (unlikely(ptrmem == NULL)) { - if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { - uintmax_t scmalloc_size_ = (uintmax_t)sz; - SCLogError("SCMalloc failed: %s, while trying " - "to allocate %" PRIuMAX " bytes", - strerror(errno), scmalloc_size_); - FatalError("Out of memory. The engine cannot be initialized. Exiting..."); - } - } - return ptrmem; -} - -void *SCReallocFunc(void *ptr, const size_t size) -{ - void *ptrmem = realloc(ptr, size); - if (unlikely(ptrmem == NULL)) { - if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { - SCLogError("SCRealloc failed: %s, while trying " - "to allocate %" PRIuMAX " bytes", - strerror(errno), (uintmax_t)size); - FatalError("Out of memory. The engine cannot be initialized. Exiting..."); - } - } - return ptrmem; -} - -void *SCCallocFunc(const size_t nm, const size_t sz) -{ - void *ptrmem = calloc(nm, sz); - if (unlikely(ptrmem == NULL)) { - if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { - SCLogError("SCCalloc failed: %s, while trying " - "to allocate %" PRIuMAX " bytes", - strerror(errno), (uintmax_t)nm * sz); - FatalError("Out of memory. The engine cannot be initialized. Exiting..."); - } - } - return ptrmem; -} - -char *SCStrdupFunc(const char *s) -{ - char *ptrmem = strdup(s); - if (unlikely(ptrmem == NULL)) { - if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { - size_t _scstrdup_len = strlen(s); - SCLogError("SCStrdup failed: %s, while trying " - "to allocate %" PRIuMAX " bytes", - strerror(errno), (uintmax_t)_scstrdup_len); - FatalError("Out of memory. The engine cannot be initialized. Exiting..."); - } - } - return ptrmem; -} - -char *SCStrndupFunc(const char *s, size_t n) -{ -#ifdef HAVE_STRNDUP - char *ptrmem = strndup(s, n); -#else - const size_t sz = n + 1; - char *ptrmem = (char *)malloc(sz); - if (likely(ptrmem != NULL)) { - strlcpy(ptrmem, s, sz); - } -#endif - if (unlikely(ptrmem == NULL)) { - if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { - SCLogError("SCStrndup failed: %s, while trying " - "to allocate %" PRIuMAX " bytes", - strerror(errno), (uintmax_t)(n + 1)); - FatalError("Out of memory. The engine cannot be initialized. Exiting..."); - } - } - return ptrmem; -} - -void *SCMallocAlignedFunc(const size_t size, const size_t align) -{ -#if defined(__WIN32) || defined(_WIN32) - void *ptrmem = _mm_malloc(size, align); - if (unlikely(ptrmem == NULL)) { - if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { - SCLogError("SCMallocAligned(posix_memalign) failed: %s, while trying " - "to allocate %" PRIuMAX " bytes, alignment %" PRIuMAX, - strerror(errno), (uintmax_t)size, (uintmax_t)align); - FatalError("Out of memory. The engine cannot be initialized. Exiting..."); - } - } -#else - void *ptrmem = NULL; - int r = posix_memalign(&ptrmem, align, size); - if (unlikely(r != 0 || ptrmem == NULL)) { - if (ptrmem != NULL) { - free(ptrmem); - ptrmem = NULL; - } - if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { - SCLogError("SCMallocAligned(posix_memalign) failed: %s, while trying " - "to allocate %" PRIuMAX " bytes, alignment %" PRIuMAX, - strerror(errno), (uintmax_t)size, (uintmax_t)align); - FatalError("Out of memory. The engine cannot be initialized. Exiting..."); - } - } -#endif - return ptrmem; -} - -void SCFreeAlignedFunc(void *ptr) -{ -#if defined(__WIN32) || defined(_WIN32) - _mm_free(ptr); -#else - free(ptr); -#endif -} diff --git a/src/util-mem.h b/src/util-mem.h deleted file mode 100644 index 56a7b22c78f0..000000000000 --- a/src/util-mem.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * \author Bill Meeks - * - * Utility Macros for memory management - * - * \todo Add wrappers for functions that allocate/free memory here. - * Currently we have malloc, calloc, realloc, strdup, strndup and - * free, but there are more. - */ - -#ifndef __UTIL_MEM_H__ -#define __UTIL_MEM_H__ - -#if CPPCHECK==1 || defined(__clang_analyzer__) -#define SCMalloc malloc -#define SCCalloc calloc -#define SCRealloc realloc -#define SCFree free -#define SCStrdup strdup -#define SCStrndup strndup -#define SCMallocAligned _mm_malloc -#define SCFreeAligned _mm_free -#else /* CPPCHECK */ - - -void *SCMallocFunc(const size_t sz); -#define SCMalloc(sz) SCMallocFunc((sz)) - -void *SCReallocFunc(void *ptr, const size_t size); -#define SCRealloc(ptr, sz) SCReallocFunc((ptr), (sz)) - -void *SCCallocFunc(const size_t nm, const size_t sz); -#define SCCalloc(nm, sz) SCCallocFunc((nm), (sz)) - -char *SCStrdupFunc(const char *s); -#define SCStrdup(s) SCStrdupFunc((s)) - -char *SCStrndupFunc(const char *s, size_t n); -#define SCStrndup(s, n) SCStrndupFunc((s), (n)) - -#define SCFree(p) free((p)) - -/** \brief wrapper for allocing aligned mem - * \param a size - * \param b alignment - */ -void *SCMallocAlignedFunc(const size_t size, const size_t align); -#define SCMallocAligned(size, align) SCMallocAlignedFunc((size), (align)) - -/** \brief Free aligned memory - * - * Not needed for mem alloc'd by posix_memalign, - * but for possible future use of _mm_malloc needing - * _mm_free. - */ -void SCFreeAlignedFunc(void *ptr); -#define SCFreeAligned(p) SCFreeAlignedFunc((p)) - -#endif /* CPPCHECK */ - -#endif /* __UTIL_MEM_H__ */ - diff --git a/src/util-memcmp.c b/src/util-memcmp.c deleted file mode 100644 index 7113b82dd60c..000000000000 --- a/src/util-memcmp.c +++ /dev/null @@ -1,374 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Memcmp implementations. - */ - -#include "suricata-common.h" -#include "util-memcmp.h" -#include "util-unittest.h" - -/* code is implemented in util-memcmp.h as it's all inlined */ - -/* UNITTESTS */ -#ifdef UNITTESTS -#include "util-debug.h" - -static int MemcmpTest01 (void) -{ - uint8_t a[] = "abcd"; - uint8_t b[] = "abcd"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); - PASS; -} - -static int MemcmpTest02 (void) -{ - uint8_t a[] = "abcdabcdabcdabcd"; - uint8_t b[] = "abcdabcdabcdabcd"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); - PASS; -} - -static int MemcmpTest03 (void) -{ - uint8_t a[] = "abcdabcd"; - uint8_t b[] = "abcdabcd"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); - PASS; -} - -static int MemcmpTest04 (void) -{ - uint8_t a[] = "abcd"; - uint8_t b[] = "abcD"; - - int r = SCMemcmp(a, b, sizeof(a)-1); - FAIL_IF(r != 1); - - PASS; -} - -static int MemcmpTest05 (void) -{ - uint8_t a[] = "abcdabcdabcdabcd"; - uint8_t b[] = "abcDabcdabcdabcd"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); - PASS; -} - -static int MemcmpTest06 (void) -{ - uint8_t a[] = "abcdabcd"; - uint8_t b[] = "abcDabcd"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); - PASS; -} - -static int MemcmpTest07 (void) -{ - uint8_t a[] = "abcd"; - uint8_t b[] = "abcde"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); - PASS; -} - -static int MemcmpTest08 (void) -{ - uint8_t a[] = "abcdabcdabcdabcd"; - uint8_t b[] = "abcdabcdabcdabcde"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); - PASS; -} - -static int MemcmpTest09 (void) -{ - uint8_t a[] = "abcdabcd"; - uint8_t b[] = "abcdabcde"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); - PASS; -} - -static int MemcmpTest10 (void) -{ - uint8_t a[] = "abcd"; - uint8_t b[] = "Zbcde"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); - PASS; -} - -static int MemcmpTest11 (void) -{ - uint8_t a[] = "abcdabcdabcdabcd"; - uint8_t b[] = "Zbcdabcdabcdabcde"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); - PASS; -} - -static int MemcmpTest12 (void) -{ - uint8_t a[] = "abcdabcd"; - uint8_t b[] = "Zbcdabcde"; - - FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); - PASS; -} - -static int MemcmpTest13 (void) -{ - uint8_t a[] = "abcdefgh"; - uint8_t b[] = "AbCdEfGhIjK"; - - FAIL_IF(SCMemcmpLowercase(a, b, sizeof(a) - 1) != 0); - PASS; -} - -#include "util-cpu.h" - -#define TEST_RUNS 1000000 - -static int MemcmpTest14 (void) -{ -#ifdef PROFILING - uint64_t ticks_start = 0; - uint64_t ticks_end = 0; - const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - - int t = 0; - int i, j; - int r1 = 0; - - printf("\n"); - - ticks_start = UtilCpuGetTicks(); - for (t = 0; t < TEST_RUNS; t++) { - for (i = 0; a[i] != NULL; i++) { - // printf("a[%d] = %s\n", i, a[i]); - size_t alen = strlen(a[i]) - 1; - - for (j = 0; b[j] != NULL; j++) { - // printf("b[%d] = %s\n", j, b[j]); - size_t blen = strlen(b[j]) - 1; - - r1 += (memcmp((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen) ? 1 : 0); - } - } - } - ticks_end = UtilCpuGetTicks(); - printf("memcmp(%d) \t\t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); - SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); - - printf("r1 %d\n", r1); - FAIL_IF(r1 != (51 * TEST_RUNS)); -#endif - PASS; -} - -static int MemcmpTest15 (void) -{ -#ifdef PROFILING - uint64_t ticks_start = 0; - uint64_t ticks_end = 0; - const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - - int t = 0; - int i, j; - int r2 = 0; - - printf("\n"); - - ticks_start = UtilCpuGetTicks(); - for (t = 0; t < TEST_RUNS; t++) { - for (i = 0; a[i] != NULL; i++) { - // printf("a[%d] = %s\n", i, a[i]); - size_t alen = strlen(a[i]) - 1; - - for (j = 0; b[j] != NULL; j++) { - // printf("b[%d] = %s\n", j, b[j]); - size_t blen = strlen(b[j]) - 1; - - r2 += MemcmpLowercase((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); - } - } - } - ticks_end = UtilCpuGetTicks(); - printf("MemcmpLowercase(%d) \t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); - SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); - - printf("r2 %d\n", r2); - FAIL_IF(r2 != (51 * TEST_RUNS)); -#endif - PASS; -} - -static int MemcmpTest16 (void) -{ -#ifdef PROFILING - uint64_t ticks_start = 0; - uint64_t ticks_end = 0; - const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - - int t = 0; - int i, j; - int r3 = 0; - - printf("\n"); - - ticks_start = UtilCpuGetTicks(); - for (t = 0; t < TEST_RUNS; t++) { - for (i = 0; a[i] != NULL; i++) { - // printf("a[%d] = %s\n", i, a[i]); - size_t alen = strlen(a[i]) - 1; - - for (j = 0; b[j] != NULL; j++) { - // printf("b[%d] = %s\n", j, b[j]); - size_t blen = strlen(b[j]) - 1; - - r3 += SCMemcmp((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); - } - } - } - ticks_end = UtilCpuGetTicks(); - printf("SCMemcmp(%d) \t\t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); - SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); - - printf("r3 %d\n", r3); - FAIL_IF(r3 != (51 * TEST_RUNS)); -#endif - PASS; -} - -static int MemcmpTest17 (void) -{ -#ifdef PROFILING - uint64_t ticks_start = 0; - uint64_t ticks_end = 0; - const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", "abcdefghijklmnopqrstuvwxyz", NULL }; - - int t = 0; - int i, j; - int r4 = 0; - - printf("\n"); - - ticks_start = UtilCpuGetTicks(); - for (t = 0; t < TEST_RUNS; t++) { - for (i = 0; a[i] != NULL; i++) { - // printf("a[%d] = %s\n", i, a[i]); - size_t alen = strlen(a[i]) - 1; - - for (j = 0; b[j] != NULL; j++) { - // printf("b[%d] = %s\n", j, b[j]); - size_t blen = strlen(b[j]) - 1; - - r4 += SCMemcmpLowercase((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); - } - } - } - ticks_end = UtilCpuGetTicks(); - printf("SCMemcmpLowercase(%d) \t\t%"PRIu64"\n", TEST_RUNS, ((uint64_t)(ticks_end - ticks_start))/TEST_RUNS); - SCLogInfo("ticks passed %"PRIu64, ticks_end - ticks_start); - - printf("r4 %d\n", r4); - FAIL_IF(r4 != (51 * TEST_RUNS)); -#endif - PASS; -} - -struct MemcmpTest18Tests { - const char *a; - const char *b; - int result; -} memcmp_tests18_tests[] = { - { "abcdefgh", "!bcdefgh", 1, }, - { "?bcdefgh", "!bcdefgh", 1, }, - { "!bcdefgh", "abcdefgh", 1, }, - { "!bcdefgh", "?bcdefgh", 1, }, - { "zbcdefgh", "bbcdefgh", 1, }, - - { "abcdefgh12345678", "!bcdefgh12345678", 1, }, - { "?bcdefgh12345678", "!bcdefgh12345678", 1, }, - { "!bcdefgh12345678", "abcdefgh12345678", 1, }, - { "!bcdefgh12345678", "?bcdefgh12345678", 1, }, - { "bbcdefgh12345678", "zbcdefgh12345678", 1, }, - - { "abcdefgh", "abcdefgh", 0, }, - { "abcdefgh", "Abcdefgh", 0, }, - { "abcdefgh12345678", "Abcdefgh12345678", 0, }, - - { NULL, NULL, 0 }, - - }; - -static int MemcmpTest18 (void) -{ - struct MemcmpTest18Tests *t = memcmp_tests18_tests; - - while (t && t->a != NULL) { - - FAIL_IF(SCMemcmpLowercase(t->a, t->b, strlen(t->a) - 1) != t->result); - t++; - } - - PASS; -} - -#endif /* UNITTESTS */ - -void MemcmpRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MemcmpTest01", MemcmpTest01); - UtRegisterTest("MemcmpTest02", MemcmpTest02); - UtRegisterTest("MemcmpTest03", MemcmpTest03); - UtRegisterTest("MemcmpTest04", MemcmpTest04); - UtRegisterTest("MemcmpTest05", MemcmpTest05); - UtRegisterTest("MemcmpTest06", MemcmpTest06); - UtRegisterTest("MemcmpTest07", MemcmpTest07); - UtRegisterTest("MemcmpTest08", MemcmpTest08); - UtRegisterTest("MemcmpTest09", MemcmpTest09); - UtRegisterTest("MemcmpTest10", MemcmpTest10); - UtRegisterTest("MemcmpTest11", MemcmpTest11); - UtRegisterTest("MemcmpTest12", MemcmpTest12); - UtRegisterTest("MemcmpTest13", MemcmpTest13); - UtRegisterTest("MemcmpTest14", MemcmpTest14); - UtRegisterTest("MemcmpTest15", MemcmpTest15); - UtRegisterTest("MemcmpTest16", MemcmpTest16); - UtRegisterTest("MemcmpTest17", MemcmpTest17); - UtRegisterTest("MemcmpTest18", MemcmpTest18); -#endif /* UNITTESTS */ -} - diff --git a/src/util-memcmp.h b/src/util-memcmp.h deleted file mode 100644 index 47bfc98c9a16..000000000000 --- a/src/util-memcmp.h +++ /dev/null @@ -1,312 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Memcmp implementations for SSE3, SSE4.1, SSE4.2. - * - * Both SCMemcmp and SCMemcmpLowercase return 0 on a exact match, - * 1 on a failed match. - */ - -#ifndef __UTIL_MEMCMP_H__ -#define __UTIL_MEMCMP_H__ - -#include "suricata-common.h" -#include "util-optimize.h" - -/** \brief compare two patterns, converting the 2nd to lowercase - * \warning *ONLY* the 2nd pattern is converted to lowercase - */ -static inline int SCMemcmpLowercase(const void *, const void *, size_t); - -void MemcmpRegisterTests(void); - -static inline int -MemcmpLowercase(const void *s1, const void *s2, size_t n) -{ - for (size_t i = 0; i < n; i++) { - if (((uint8_t *)s1)[i] != u8_tolower(((uint8_t *)s2)[i])) - return 1; - } - - return 0; -} - -#if defined(__SSE4_2__) -#include -#define SCMEMCMP_BYTES 16 - -static inline int SCMemcmp(const void *s1, const void *s2, size_t n) -{ - int r = 0; - /* counter for how far we already matched in the buffer */ - size_t m = 0; - do { - if (likely(n - m < SCMEMCMP_BYTES)) { - return memcmp(s1, s2, n - m) ? 1 : 0; - } - - /* load the buffers into the 128bit vars */ - __m128i b1 = _mm_loadu_si128((const __m128i *)s1); - __m128i b2 = _mm_loadu_si128((const __m128i *)s2); - - /* do the actual compare: _mm_cmpestri() returns the number of matching bytes */ - r = _mm_cmpestri(b1, SCMEMCMP_BYTES, b2, SCMEMCMP_BYTES, - _SIDD_CMP_EQUAL_EACH | _SIDD_MASKED_NEGATIVE_POLARITY); - m += r; - s1 += SCMEMCMP_BYTES; - s2 += SCMEMCMP_BYTES; - } while (r == SCMEMCMP_BYTES); - - return ((m == n) ? 0 : 1); -} - -/* Range of values of uppercase characters. We only use the first 2 bytes. */ -static char scmemcmp_uppercase[16] __attribute__((aligned(16))) = { - 'A', 'Z', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; - -/** \brief compare two buffers in a case insensitive way - * \param s1 buffer already in lowercase - * \param s2 buffer with mixed upper and lowercase - */ -static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t n) -{ - /* counter for how far we already matched in the buffer */ - size_t m = 0; - int r = 0; - __m128i ucase = _mm_load_si128((const __m128i *) scmemcmp_uppercase); - __m128i uplow = _mm_set1_epi8(0x20); - - do { - const size_t len = n - m; - if (likely(len < SCMEMCMP_BYTES)) { - return MemcmpLowercase(s1, s2, len); - } - - __m128i b1 = _mm_loadu_si128((const __m128i *)s1); - __m128i b2 = _mm_loadu_si128((const __m128i *)s2); - /* The first step is creating a mask that is FF for all uppercase - * characters, 00 for all others */ - __m128i mask = _mm_cmpestrm(ucase, 2, b2, len, _SIDD_CMP_RANGES | _SIDD_UNIT_MASK); - /* Next we use that mask to create a new: this one has 0x20 for - * the uppercase chars, 00 for all other. */ - mask = _mm_and_si128(uplow, mask); - /* finally, merge the mask and the buffer converting the - * uppercase to lowercase */ - b2 = _mm_add_epi8(b2, mask); - - /* search using our converted buffer, return number of matching bytes */ - r = _mm_cmpestri(b1, SCMEMCMP_BYTES, b2, SCMEMCMP_BYTES, - _SIDD_CMP_EQUAL_EACH | _SIDD_MASKED_NEGATIVE_POLARITY); - m += r; - s1 += SCMEMCMP_BYTES; - s2 += SCMEMCMP_BYTES; - } while (r == SCMEMCMP_BYTES); - - return ((m == n) ? 0 : 1); -} - -#elif defined(__SSE4_1__) -#include -#define SCMEMCMP_BYTES 16 - -static inline int SCMemcmp(const void *s1, const void *s2, size_t len) -{ - size_t offset = 0; - do { - if (likely(len - offset < SCMEMCMP_BYTES)) { - return memcmp(s1, s2, len - offset) ? 1 : 0; - } - - /* unaligned loads */ - __m128i b1 = _mm_loadu_si128((const __m128i *)s1); - __m128i b2 = _mm_loadu_si128((const __m128i *)s2); - __m128i c = _mm_cmpeq_epi8(b1, b2); - - if (_mm_movemask_epi8(c) != 0x0000FFFF) { - return 1; - } - - offset += SCMEMCMP_BYTES; - s1 += SCMEMCMP_BYTES; - s2 += SCMEMCMP_BYTES; - } while (len > offset); - - return 0; -} - -#define UPPER_LOW 0x40 /* "A" - 1 */ -#define UPPER_HIGH 0x5B /* "Z" + 1 */ - -static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) -{ - size_t offset = 0; - __m128i b1, b2, mask1, mask2, upper1, upper2, uplow; - - /* setup registers for upper to lower conversion */ - upper1 = _mm_set1_epi8(UPPER_LOW); - upper2 = _mm_set1_epi8(UPPER_HIGH); - uplow = _mm_set1_epi8(0x20); - - do { - if (likely(len - offset < SCMEMCMP_BYTES)) { - return MemcmpLowercase(s1, s2, len - offset); - } - - /* unaligned loading of the bytes to compare */ - b1 = _mm_loadu_si128((const __m128i *) s1); - b2 = _mm_loadu_si128((const __m128i *) s2); - - /* mark all chars bigger than upper1 */ - mask1 = _mm_cmpgt_epi8(b2, upper1); - /* mark all chars lower than upper2 */ - mask2 = _mm_cmplt_epi8(b2, upper2); - /* merge the two, leaving only those that are true in both */ - mask1 = _mm_cmpeq_epi8(mask1, mask2); - /* Next we use that mask to create a new: this one has 0x20 for - * the uppercase chars, 00 for all other. */ - mask1 = _mm_and_si128(uplow, mask1); - /* add to b2, converting uppercase to lowercase */ - b2 = _mm_add_epi8(b2, mask1); - /* now all is lowercase, let's do the actual compare (reuse mask1 reg) */ - mask1 = _mm_cmpeq_epi8(b1, b2); - - if (_mm_movemask_epi8(mask1) != 0x0000FFFF) { - return 1; - } - - offset += SCMEMCMP_BYTES; - s1 += SCMEMCMP_BYTES; - s2 += SCMEMCMP_BYTES; - } while (len > offset); - - return 0; -} - -#elif defined(__SSE3__) -#include /* for SSE3 */ -#define SCMEMCMP_BYTES 16 - -static inline int SCMemcmp(const void *s1, const void *s2, size_t len) -{ - size_t offset = 0; - __m128i b1, b2, c; - - do { - if (likely(len - offset < SCMEMCMP_BYTES)) { - return memcmp(s1, s2, len - offset) ? 1 : 0; - } - - /* unaligned loads */ - b1 = _mm_loadu_si128((const __m128i *) s1); - b2 = _mm_loadu_si128((const __m128i *) s2); - c = _mm_cmpeq_epi8(b1, b2); - - if (_mm_movemask_epi8(c) != 0x0000FFFF) { - return 1; - } - - offset += SCMEMCMP_BYTES; - s1 += SCMEMCMP_BYTES; - s2 += SCMEMCMP_BYTES; - } while (len > offset); - - return 0; -} - -#define UPPER_LOW 0x40 /* "A" - 1 */ -#define UPPER_HIGH 0x5B /* "Z" + 1 */ -#define UPPER_DELTA 0xDF /* 0xFF - 0x20 */ - -static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) -{ - size_t offset = 0; - __m128i b1, b2, mask1, mask2, upper1, upper2, delta; - - /* setup registers for upper to lower conversion */ - upper1 = _mm_set1_epi8(UPPER_LOW); - upper2 = _mm_set1_epi8(UPPER_HIGH); - delta = _mm_set1_epi8(UPPER_DELTA); - - do { - if (likely(len - offset < SCMEMCMP_BYTES)) { - return MemcmpLowercase(s1, s2, len - offset); - } - - /* unaligned loading of the bytes to compare */ - b1 = _mm_loadu_si128((const __m128i *) s1); - b2 = _mm_loadu_si128((const __m128i *) s2); - - /* mark all chars bigger than upper1 */ - mask1 = _mm_cmpgt_epi8(b2, upper1); - /* mark all chars lower than upper2 */ - mask2 = _mm_cmplt_epi8(b2, upper2); - /* merge the two, leaving only those that are true in both */ - mask1 = _mm_cmpeq_epi8(mask1, mask2); - /* sub delta leaves 0x20 only for uppercase positions, the - rest is 0x00 due to the saturation (reuse mask1 reg)*/ - mask1 = _mm_subs_epu8(mask1, delta); - /* add to b2, converting uppercase to lowercase */ - b2 = _mm_add_epi8(b2, mask1); - - /* now all is lowercase, let's do the actual compare (reuse mask1 reg) */ - mask1 = _mm_cmpeq_epi8(b1, b2); - - if (_mm_movemask_epi8(mask1) != 0x0000FFFF) { - return 1; - } - - offset += SCMEMCMP_BYTES; - s1 += SCMEMCMP_BYTES; - s2 += SCMEMCMP_BYTES; - } while (len > offset); - - return 0; -} - -#else - -/* No SIMD support, fall back to plain memcmp and a home grown lowercase one */ - -/* wrapper around memcmp to match the retvals of the SIMD implementations */ -#define SCMemcmp(a,b,c) ({ \ - memcmp((a), (b), (c)) ? 1 : 0; \ -}) - -static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) -{ - return MemcmpLowercase(s1, s2, len); -} - -#endif /* SIMD */ - -static inline int SCBufferCmp(const void *s1, size_t len1, const void *s2, size_t len2) -{ - if (len1 == len2) { - return SCMemcmp(s1, s2, len1); - } else if (len1 < len2) { - return -1; - } - return 1; -} - -#endif /* __UTIL_MEMCMP_H__ */ - diff --git a/src/util-memrchr.c b/src/util-memrchr.c deleted file mode 100644 index e531f845c7fd..000000000000 --- a/src/util-memrchr.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#include "suricata-common.h" -#include "util-unittest.h" -#include "util-memrchr.h" - -#ifndef HAVE_MEMRCHR -void *memrchr (const void *s, int c, size_t n) -{ - const char *end = s + n; - - while (end > (const char *)s) { - if (*end == (char)c) - return (void *)end; - end--; - } - return NULL; -} -#endif /* HAVE_MEMRCHR */ - -#ifdef UNITTESTS -static int MemrchrTest01 (void) -{ - const char *haystack = "abcabc"; - char needle = 'b'; - - char *ptr = memrchr(haystack, needle, strlen(haystack)); - if (ptr == NULL) - return 0; - - if (strlen(ptr) != 2) - return 0; - - if (strcmp(ptr, "bc") != 0) - return 0; - - return 1; -} -#endif - -void MemrchrRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("MemrchrTest01", MemrchrTest01); -#endif -} diff --git a/src/util-misc.c b/src/util-misc.c deleted file mode 100644 index 4380e694a8a0..000000000000 --- a/src/util-misc.c +++ /dev/null @@ -1,778 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-byte.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-misc.h" - -#define PARSE_REGEX "^\\s*(\\d+(?:.\\d+)?)\\s*([a-zA-Z]{2})?\\s*$" -static pcre2_code *parse_regex = NULL; -static pcre2_match_data *parse_regex_match = NULL; - -void ParseSizeInit(void) -{ - int en; - PCRE2_SIZE eo; - int opts = 0; - - parse_regex = - pcre2_compile((PCRE2_SPTR8)PARSE_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); - if (parse_regex == NULL) { - PCRE2_UCHAR errbuffer[256]; - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - SCLogError("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - PARSE_REGEX, (int)eo, errbuffer); - exit(EXIT_FAILURE); - } - parse_regex_match = pcre2_match_data_create_from_pattern(parse_regex, NULL); -} - -void ParseSizeDeinit(void) -{ - pcre2_code_free(parse_regex); - pcre2_match_data_free(parse_regex_match); -} - -/* size string parsing API */ - -static int ParseSizeString(const char *size, double *res) -{ - int pcre2_match_ret; - int r; - int retval = 0; - char str[128]; - char str2[128]; - - *res = 0; - - if (size == NULL) { - SCLogError("invalid size argument - NULL. Valid size " - "argument should be in the format - \n" - "xxx <- indicates it is just bytes\n" - "xxxkb or xxxKb or xxxKB or xxxkB <- indicates kilobytes\n" - "xxxmb or xxxMb or xxxMB or xxxmB <- indicates megabytes\n" - "xxxgb or xxxGb or xxxGB or xxxgB <- indicates gigabytes.\n"); - retval = -2; - goto end; - } - - pcre2_match_ret = pcre2_match( - parse_regex, (PCRE2_SPTR8)size, strlen(size), 0, 0, parse_regex_match, NULL); - - if (!(pcre2_match_ret == 2 || pcre2_match_ret == 3)) { - SCLogError("invalid size argument - %s. Valid size " - "argument should be in the format - \n" - "xxx <- indicates it is just bytes\n" - "xxxkb or xxxKb or xxxKB or xxxkB <- indicates kilobytes\n" - "xxxmb or xxxMb or xxxMB or xxxmB <- indicates megabytes\n" - "xxxgb or xxxGb or xxxGB or xxxgB <- indicates gigabytes.\n", - size); - retval = -2; - goto end; - } - - size_t copylen = sizeof(str); - r = pcre2_substring_copy_bynumber(parse_regex_match, 1, (PCRE2_UCHAR8 *)str, ©len); - if (r < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - retval = -2; - goto end; - } - - char *endptr, *str_ptr = str; - errno = 0; - *res = strtod(str_ptr, &endptr); - if (errno == ERANGE) { - SCLogError("Numeric value out of range"); - retval = -1; - goto end; - } else if (endptr == str_ptr) { - SCLogError("Invalid numeric value"); - retval = -1; - goto end; - } - - if (pcre2_match_ret == 3) { - copylen = sizeof(str2); - r = pcre2_substring_copy_bynumber(parse_regex_match, 2, (PCRE2_UCHAR8 *)str2, ©len); - - if (r < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - retval = -2; - goto end; - } - - if (strcasecmp(str2, "kb") == 0) { - *res *= 1024; - } else if (strcasecmp(str2, "mb") == 0) { - *res *= 1024 * 1024; - } else if (strcasecmp(str2, "gb") == 0) { - *res *= 1024 * 1024 * 1024; - } else { - /* Bad unit. */ - retval = -1; - goto end; - } - } - - retval = 0; -end: - return retval; -} - -int ParseSizeStringU8(const char *size, uint8_t *res) -{ - double temp_res = 0; - - *res = 0; - int r = ParseSizeString(size, &temp_res); - if (r < 0) - return r; - - if (temp_res > UINT8_MAX) - return -1; - - *res = temp_res; - - return 0; -} - -int ParseSizeStringU16(const char *size, uint16_t *res) -{ - double temp_res = 0; - - *res = 0; - int r = ParseSizeString(size, &temp_res); - if (r < 0) - return r; - - if (temp_res > UINT16_MAX) - return -1; - - *res = temp_res; - - return 0; -} - -int ParseSizeStringU32(const char *size, uint32_t *res) -{ - double temp_res = 0; - - *res = 0; - int r = ParseSizeString(size, &temp_res); - if (r < 0) - return r; - - if (temp_res > UINT32_MAX) - return -1; - - *res = temp_res; - - return 0; -} - -int ParseSizeStringU64(const char *size, uint64_t *res) -{ - double temp_res = 0; - - *res = 0; - int r = ParseSizeString(size, &temp_res); - if (r < 0) - return r; - - if (temp_res > (double) UINT64_MAX) - return -1; - - *res = temp_res; - - return 0; -} - -void ShortenString(const char *input, - char *output, size_t output_size, char c) -{ - const size_t str_len = strlen(input); - size_t half = (output_size - 1) / 2; - - /* If the output size is an even number */ - if (half * 2 == (output_size - 1)) { - half = half - 1; - } - - size_t spaces = (output_size - 1) - (half * 2); - - /* Add the first half to the new string */ - snprintf(output, half+1, "%s", input); - - /* Add the amount of spaces wanted */ - size_t length = half; - for (size_t i = half; i < half + spaces; i++) { - char s[2] = ""; - snprintf(s, sizeof(s), "%c", c); - length = strlcat(output, s, output_size); - } - - snprintf(output + length, half + 1, "%s", input + (str_len - half)); -} - -/*********************************Unittests********************************/ - -#ifdef UNITTESTS - -static int UtilMiscParseSizeStringTest01(void) -{ - const char *str; - double result; - - /* no space */ - - str = "10"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = "10kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = "10gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240UL); - - /* space start */ - - str = " 10"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = " 10kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = " 10gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240); - - /* space end */ - - str = "10 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = "10kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = "10gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240); - - /* space start - space end */ - - str = " 10 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = " 10kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = " 10gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240); - - /* space between number and scale */ - - /* no space */ - - str = "10"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = "10 kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10 Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10 KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10 mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = "10 gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240); - - /* space start */ - - str = " 10"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = " 10 kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10 Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10 KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10 mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = " 10 gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240); - - /* space end */ - - str = "10 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = "10 kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10 Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10 KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = "10 mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = "10 gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240); - - /* space start - space end */ - - str = " 10 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10); - - str = " 10 kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10 Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10 KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024); - - str = " 10 mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10 * 1024 * 1024); - - str = " 10 gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10737418240); - - /* no space */ - - str = "10.5"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = "10.5kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = "10.5gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* space start */ - - str = " 10.5"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = " 10.5kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = " 10.5gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* space end */ - - str = "10.5 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = "10.5kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = "10.5gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* space start - space end */ - - str = " 10.5 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = " 10.5kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = " 10.5gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* space between number and scale */ - - /* no space */ - - str = "10.5"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = "10.5 kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5 Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5 KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5 mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = "10.5 gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* space start */ - - str = " 10.5"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = " 10.5 kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5 Kb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5 KB"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5 mb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = " 10.5 gb"; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* space end */ - - str = "10.5 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = "10.5 kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5 Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5 KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = "10.5 mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = "10.5 gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* space start - space end */ - - str = " 10.5 "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5); - - str = " 10.5 kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5 Kb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5 KB "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024); - - str = " 10.5 mb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024); - - str = " 10.5 gb "; - result = 0; - FAIL_IF(ParseSizeString(str, &result) > 0); - FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); - - /* Should fail on unknown units. */ - FAIL_IF(ParseSizeString("32eb", &result) > 0); - - PASS; -} - -void UtilMiscRegisterTests(void) -{ - UtRegisterTest("UtilMiscParseSizeStringTest01", - UtilMiscParseSizeStringTest01); -} -#endif /* UNITTESTS */ diff --git a/src/util-misc.h b/src/util-misc.h deleted file mode 100644 index a3d398d92f0a..000000000000 --- a/src/util-misc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_MISC_H__ -#define __UTIL_MISC_H__ - - -/** - * \brief Generic API that can be used by all to log an - * invalid conf entry. - * \param param_name A string specifying the param name. - * \param format Format for the below value. For example "%s", "%"PRIu32, - etc. - * \param value Default value to be printed. - */ -#define WarnInvalidConfEntry(param_name, format, value) \ - do { \ - SCLogWarning("Invalid conf entry found for " \ - "\"%s\". Using default value of \"" format "\".", \ - param_name, value); \ - } while (0) - -/* size string parsing API */ - -int ParseSizeStringU8(const char *, uint8_t *); -int ParseSizeStringU16(const char *, uint16_t *); -int ParseSizeStringU32(const char *, uint32_t *); -int ParseSizeStringU64(const char *, uint64_t *); - -#ifdef UNITTESTS -void UtilMiscRegisterTests(void); -#endif /* UNITTESTS */ - -void ParseSizeInit(void); -void ParseSizeDeinit(void); - -void ShortenString(const char *input, - char *output, size_t output_size, char c); - -#endif /* __UTIL_MISC_H__ */ diff --git a/src/util-mpm-ac-ks-small.c b/src/util-mpm-ac-ks-small.c deleted file mode 100644 index 44f51d02b9fb..000000000000 --- a/src/util-mpm-ac-ks-small.c +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright (C) 2013-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Ken Steele - - * Included by util-mpm-ac-ks.c with different SLOAD, SINDEX and - * FUNC_NAME - * - */ - -/* Only included into util-mpm-ac-ks.c, which defines FUNC_NAME - * - */ -#ifdef FUNC_NAME - -/* This function handles (ctx->state_count < 32767) */ -uint32_t FUNC_NAME(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen) -{ - uint32_t i = 0; - int matches = 0; - - uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; - memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); - - const uint8_t* restrict xlate = ctx->translate_table; - STYPE *state_table = (STYPE*)ctx->state_table; - STYPE state = 0; - int c = xlate[buf[0]]; - /* If buflen at least 4 bytes and buf 4-byte aligned. */ - if (buflen >= (4 + EXTRA) && ((uintptr_t)buf & 0x3) == 0) { - BUF_TYPE data = *(BUF_TYPE* restrict)(&buf[0]); - uint64_t index = 0; - /* Process 4*floor(buflen/4) bytes. */ - i = 0; - while ((i + EXTRA) < (buflen & ~0x3)) { - BUF_TYPE data1 = *(BUF_TYPE* restrict)(&buf[i + 4]); - index = SINDEX(index, state); - state = SLOAD(state_table + index + c); - c = xlate[BYTE1(data)]; - if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); - } - i++; - index = SINDEX(index, state); - state = SLOAD(state_table + index + c); - c = xlate[BYTE2(data)]; - if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); - } - i++; - index = SINDEX(index, state); - state = SLOAD(state_table + index + c); - c = xlate[BYTE3(data)]; - if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); - } - data = data1; - i++; - index = SINDEX(index, state); - state = SLOAD(state_table + index + c); - c = xlate[BYTE0(data)]; - if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); - } - i++; - } - } - /* Process buflen % 4 bytes. */ - for (; i < buflen; i++) { - size_t index = 0 ; - index = SINDEX(index, state); - state = SLOAD(state_table + index + c); - if (likely(i+1 < buflen)) - c = xlate[buf[i+1]]; - if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); - } - } /* for (i = 0; i < buflen; i++) */ - - return matches; -} - -#endif /* FUNC_NAME */ diff --git a/src/util-mpm-ac-ks.c b/src/util-mpm-ac-ks.c deleted file mode 100644 index 465b66918b62..000000000000 --- a/src/util-mpm-ac-ks.c +++ /dev/null @@ -1,2432 +0,0 @@ -/* Copyright (C) 2013-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Ken Steele - * \author Anoop Saldanha - * - * Aho-corasick MPM optimized for the Tilera Tile-Gx architecture. - * - * Efficient String Matching: An Aid to Bibliographic Search - * Alfred V. Aho and Margaret J. Corasick - * - * - Started with util-mpm-ac.c: - * - Uses the delta table for calculating transitions, - * instead of having separate goto and failure - * transitions. - * - If we cross 2 ** 16 states, we use 4 bytes in the - * transition table to hold each state, otherwise we use - * 2 bytes. - * - This version of the MPM is heavy on memory, but it - * performs well. If you can fit the ruleset with this - * mpm on your box without hitting swap, this is the MPM - * to go for. - * - * - Added these optimizations: - * - Compress the input alphabet from 256 characters down - * to the actual characters used in the patterns, plus - * one character for all the unused characters. - * - Reduce the size of the delta table so that each state - * is the smallest power of two that is larger than the - * size of the compressed alphabet. - * - Specialized the search function based on state count - * (small for 8-bit large for 16-bit) and the size of - * the alphabet, so that it is constant inside the - * function for better optimization. - * - * \todo - Do a proper analysis of our existing MPMs and suggest a good - * one based on the pattern distribution and the expected - * traffic(say http). - - * - Irrespective of whether we cross 2 ** 16 states or - * not,shift to using uint32_t for state type, so that we can - * integrate it's status as a final state or not in the - * topmost byte. We are already doing it if state_count is > - * 2 ** 16. - * - Test case-sensitive patterns if they have any ascii chars. - * If they don't treat them as nocase. - * - Reorder the compressed alphabet to put the most common characters - * first. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-build.h" - -#include "conf.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-memcmp.h" -#include "util-memcpy.h" -#include "util-validate.h" -#include "util-mpm-ac-ks.h" - -#if __BYTE_ORDER == __LITTLE_ENDIAN - -void SCACTileInitCtx(MpmCtx *); -void SCACTileDestroyCtx(MpmCtx *); -int SCACTileAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCACTileAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCACTilePreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, const uint8_t *buf, - uint32_t buflen); -void SCACTilePrintInfo(MpmCtx *mpm_ctx); -void SCACTileRegisterTests(void); - -uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchSmall256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchSmall128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchSmall64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchSmall32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchSmall16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchSmall8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); - -uint32_t SCACTileSearchTiny256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchTiny128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchTiny64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchTiny32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchTiny16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); -uint32_t SCACTileSearchTiny8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen); - - -static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx); - - -/* a placeholder to denote a failure transition in the goto table */ -#define SC_AC_TILE_FAIL (-1) - -#define STATE_QUEUE_CONTAINER_SIZE 65536 - -/** - * \brief Helper structure used by AC during state table creation - */ -typedef struct StateQueue_ { - int32_t store[STATE_QUEUE_CONTAINER_SIZE]; - int top; - int bot; -} StateQueue; - -/** - * \internal - * \brief Initialize the AC context with user specified conf parameters. We - * aren't retrieving anything for AC conf now, but we will certainly - * need it, when we customize AC. - */ -static void SCACTileGetConfig(void) -{ -} - -/** - * \internal - * \brief Count the occurrences of each character in the pattern and - * accumulate into a histogram. Really only used to detect unused - * characters, so could just set to 1 instead of counting. - */ -static inline void SCACTileHistogramAlphabet(SCACTileCtx *ctx, - MpmPattern *p) -{ - for (int i = 0; i < p->len; i++) { - ctx->alpha_hist[p->ci[i]]++; - } -} - -/* Use Alphabet Histogram to create compressed alphabet. - */ -static void SCACTileInitTranslateTable(SCACTileCtx *ctx) -{ - /* Count the number of ASCII values actually appearing in any - * pattern. Create compressed mapping table with unused - * characters mapping to zero. - */ - for (int i = 0; i < 256; i++) { - /* Move all upper case counts to lower case */ - if (i >= 'A' && i <= 'Z') { - ctx->alpha_hist[i - 'A' + 'a'] += ctx->alpha_hist[i]; - ctx->alpha_hist[i] = 0; - } - if (ctx->alpha_hist[i]) { - ctx->alphabet_size++; - DEBUG_VALIDATE_BUG_ON(ctx->alphabet_size > UINT8_MAX); - ctx->translate_table[i] = (uint8_t)ctx->alphabet_size; - } else - ctx->translate_table[i] = 0; - } - /* Fix up translation table for uppercase */ - for (int i = 'A'; i <= 'Z'; i++) - ctx->translate_table[i] = ctx->translate_table[i - 'A' + 'a']; - - SCLogDebug(" Alphabet size %d", ctx->alphabet_size); - - /* Round alphabet size up to next power-of-two Leave one extra - * space For the unused-characters = 0 mapping. - */ - ctx->alphabet_size += 1; /* Extra space for unused-character */ - if (ctx->alphabet_size <= 8) { - ctx->alphabet_storage = 8; - } else if (ctx->alphabet_size <= 16) { - ctx->alphabet_storage = 16; - } else if (ctx->alphabet_size <= 32) { - ctx->alphabet_storage = 32; - } else if (ctx->alphabet_size <= 64) { - ctx->alphabet_storage = 64; - } else if (ctx->alphabet_size <= 128) { - ctx->alphabet_storage = 128; - } else - ctx->alphabet_storage = 256; -} - -static void SCACTileReallocOutputTable(SCACTileCtx *ctx, int new_state_count) -{ - - /* reallocate space in the output table for the new state */ - size_t size = ctx->allocated_state_count * sizeof(SCACTileOutputTable); - void *ptmp = SCRealloc(ctx->output_table, size); - if (ptmp == NULL) { - SCFree(ctx->output_table); - ctx->output_table = NULL; - FatalError("Error allocating memory"); - } - ctx->output_table = ptmp; -} - -static void SCACTileReallocState(SCACTileCtx *ctx, int new_state_count) -{ - /* reallocate space in the goto table to include a new state */ - size_t size = ctx->allocated_state_count * sizeof(int32_t) * 256; - void *ptmp = SCRealloc(ctx->goto_table, size); - if (ptmp == NULL) { - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - FatalError("Error allocating memory"); - } - ctx->goto_table = ptmp; - - SCACTileReallocOutputTable(ctx, new_state_count); -} - -/** - * \internal - * \brief Initialize a new state in the goto and output tables. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval The state id, of the newly created state. - */ -static inline int SCACTileInitNewState(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - int aa = 0; - - /* Exponentially increase the allocated space when needed. */ - if (ctx->allocated_state_count < ctx->state_count + 1) { - if (ctx->allocated_state_count == 0) - ctx->allocated_state_count = 256; - else - ctx->allocated_state_count *= 2; - - SCACTileReallocState(ctx, ctx->allocated_state_count); - } - - /* set all transitions for the newly assigned state as FAIL transitions */ - for (aa = 0; aa < ctx->alphabet_size; aa++) { - ctx->goto_table[ctx->state_count][aa] = SC_AC_TILE_FAIL; - } - - memset(ctx->output_table + ctx->state_count, 0, - sizeof(SCACTileOutputTable)); - - return ctx->state_count++; -} - -/** - * \internal - * \brief Adds a pid to the output table for a state. - * - * \param state The state to whose output table we should add the pid. - * \param pid The pattern id to add. - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACTileSetOutputState(int32_t state, MpmPatternIndex pindex, MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - SCACTileOutputTable *output_state = &ctx->output_table[state]; - uint32_t i = 0; - - /* Don't add the pattern more than once to the same state. */ - for (i = 0; i < output_state->no_of_entries; i++) { - if (output_state->patterns[i] == pindex) - return; - } - - /* Increase the size of the array of pids for this state and add - * the new pid. */ - output_state->no_of_entries++; - ptmp = SCRealloc(output_state->patterns, - output_state->no_of_entries * sizeof(MpmPatternIndex)); - if (ptmp == NULL) { - SCFree(output_state->patterns); - output_state->patterns = NULL; - FatalError("Error allocating memory"); - } - output_state->patterns = ptmp; - - output_state->patterns[output_state->no_of_entries - 1] = pindex; -} - -/** - * \brief Helper function used by SCACTileCreateGotoTable. Adds a - * pattern to the goto table. - * - * \param pattern Pointer to the pattern. - * \param pattern_len Pattern length. - * \param pid The pattern id, that corresponds to this pattern. We - * need it to updated the output table for this pattern. - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACTileEnter(uint8_t *pattern, uint16_t pattern_len, - MpmPatternIndex pindex, MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - int32_t state = 0; - int32_t newstate = 0; - int i = 0; - int p = 0; - int tc; - - /* Walk down the trie till we have a match for the pattern prefix */ - state = 0; - for (i = 0; i < pattern_len; i++) { - tc = ctx->translate_table[pattern[i]]; - if (ctx->goto_table[state][tc] == SC_AC_TILE_FAIL) - break; - state = ctx->goto_table[state][tc]; - } - - /* Add the non-matching pattern suffix to the trie, from the last state - * we left off */ - for (p = i; p < pattern_len; p++) { - newstate = SCACTileInitNewState(mpm_ctx); - tc = ctx->translate_table[pattern[p]]; - ctx->goto_table[state][tc] = newstate; - state = newstate; - } - - /* Add this pattern id, to the output table of the last state, where the - * pattern ends in the trie */ - SCACTileSetOutputState(state, pindex, mpm_ctx); -} - -/** - * \internal - * \brief Create the goto table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACTileCreateGotoTable(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - uint32_t i = 0; - - /* add each pattern to create the goto table */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - SCACTileEnter(ctx->parray[i]->ci, ctx->parray[i]->len, - i, mpm_ctx); - } - - int aa = 0; - for (aa = 0; aa < ctx->alphabet_size; aa++) { - if (ctx->goto_table[0][aa] == SC_AC_TILE_FAIL) { - ctx->goto_table[0][aa] = 0; - } - } -} - -static inline int SCACTileStateQueueIsEmpty(StateQueue *q) -{ - if (q->top == q->bot) - return 1; - else - return 0; -} - -static inline void SCACTileEnqueue(StateQueue *q, int32_t state) -{ - int i = 0; - - /*if we already have this */ - for (i = q->bot; i < q->top; i++) { - if (q->store[i] == state) - return; - } - - q->store[q->top++] = state; - - if (q->top == STATE_QUEUE_CONTAINER_SIZE) - q->top = 0; - - if (q->top == q->bot) { - FatalError("Just ran out of space in the queue. " - "Fatal Error. Exiting. Please file a bug report on this"); - } -} - -static inline int32_t SCACTileDequeue(StateQueue *q) -{ - if (q->bot == STATE_QUEUE_CONTAINER_SIZE) - q->bot = 0; - - if (q->bot == q->top) { - FatalError("StateQueue behaving weirdly. " - "Fatal Error. Exiting. Please file a bug report on this"); - } - - return q->store[q->bot++]; -} - -/** - * \internal - * \brief Club the output data from 2 states and store it in the 1st state. - * dst_state_data = {dst_state_data} UNION {src_state_data} - * - * \param dst_state First state(also the destination) for the union operation. - * \param src_state Second state for the union operation. - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACTileClubOutputStates(int32_t dst_state, - int32_t src_state, - MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - uint32_t i = 0; - uint32_t j = 0; - - SCACTileOutputTable *output_dst_state = &ctx->output_table[dst_state]; - SCACTileOutputTable *output_src_state = &ctx->output_table[src_state]; - - for (i = 0; i < output_src_state->no_of_entries; i++) { - for (j = 0; j < output_dst_state->no_of_entries; j++) { - if (output_src_state->patterns[i] == output_dst_state->patterns[j]) { - break; - } - } - if (j == output_dst_state->no_of_entries) { - output_dst_state->no_of_entries++; - - ptmp = SCRealloc(output_dst_state->patterns, - (output_dst_state->no_of_entries * sizeof(uint32_t))); - if (ptmp == NULL) { - SCFree(output_dst_state->patterns); - output_dst_state->patterns = NULL; - FatalError("Error allocating memory"); - } - output_dst_state->patterns = ptmp; - - output_dst_state->patterns[output_dst_state->no_of_entries - 1] = - output_src_state->patterns[i]; - } - } -} - -/** - * \internal - * \brief Create the failure table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACTileCreateFailureTable(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - int aa = 0; - int32_t state = 0; - int32_t r_state = 0; - - StateQueue q; - memset(&q, 0, sizeof(StateQueue)); - - /* Allocate space for the failure table. A failure entry in the table for - * every state(SCACTileCtx->state_count) */ - ctx->failure_table = SCCalloc(ctx->state_count, sizeof(int32_t)); - if (ctx->failure_table == NULL) { - FatalError("Error allocating memory"); - } - - /* Add the failure transitions for the 0th state, and add every non-fail - * transition from the 0th state to the queue for further processing - * of failure states */ - for (aa = 0; aa < ctx->alphabet_size; aa++) { - int32_t temp_state = ctx->goto_table[0][aa]; - if (temp_state != 0) { - SCACTileEnqueue(&q, temp_state); - ctx->failure_table[temp_state] = 0; - } - } - - while (!SCACTileStateQueueIsEmpty(&q)) { - /* pick up every state from the queue and add failure transitions */ - r_state = SCACTileDequeue(&q); - for (aa = 0; aa < ctx->alphabet_size; aa++) { - int32_t temp_state = ctx->goto_table[r_state][aa]; - if (temp_state == SC_AC_TILE_FAIL) - continue; - SCACTileEnqueue(&q, temp_state); - state = ctx->failure_table[r_state]; - - while(ctx->goto_table[state][aa] == SC_AC_TILE_FAIL) - state = ctx->failure_table[state]; - ctx->failure_table[temp_state] = ctx->goto_table[state][aa]; - SCACTileClubOutputStates(temp_state, ctx->failure_table[temp_state], - mpm_ctx); - } - } -} - -/* - * Set the next state for 1 byte next-state. - */ -static void SCACTileSetState1Byte(SCACTileCtx *ctx, int state, int aa, - int next_state, int outputs) -{ - uint8_t *state_table = (uint8_t*)ctx->state_table; - DEBUG_VALIDATE_BUG_ON(next_state < 0 || next_state > UINT8_MAX); - uint8_t encoded_next_state = (uint8_t)next_state; - - if (next_state == SC_AC_TILE_FAIL) { - FatalError("Error FAIL state in output"); - } - - if (outputs == 0) - encoded_next_state |= (1 << 7); - - state_table[state * ctx->alphabet_storage + aa] = encoded_next_state; -} - -/* - * Set the next state for 2 byte next-state. - */ -static void SCACTileSetState2Bytes(SCACTileCtx *ctx, int state, int aa, - int next_state, int outputs) -{ - uint16_t *state_table = (uint16_t*)ctx->state_table; - DEBUG_VALIDATE_BUG_ON(next_state < 0 || next_state > UINT16_MAX); - uint16_t encoded_next_state = (uint16_t)next_state; - - if (next_state == SC_AC_TILE_FAIL) { - FatalError("Error FAIL state in output"); - } - - if (outputs == 0) - encoded_next_state |= (1 << 15); - - state_table[state * ctx->alphabet_storage + aa] = encoded_next_state; -} - -/* - * Set the next state for 4 byte next-state. - */ -static void SCACTileSetState4Bytes(SCACTileCtx *ctx, int state, int aa, - int next_state, int outputs) -{ - uint32_t *state_table = (uint32_t*)ctx->state_table; - uint32_t encoded_next_state = next_state; - - if (next_state == SC_AC_TILE_FAIL) { - FatalError("Error FAIL state in output"); - } - - if (outputs == 0) - encoded_next_state |= (1UL << 31); - - state_table[state * ctx->alphabet_storage + aa] = encoded_next_state; -} - -/** - * \internal - * \brief Create the delta table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACTileCreateDeltaTable(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - int aa = 0; - int32_t r_state = 0; - - if (ctx->state_count < 32767) { - if (ctx->state_count < 128) { - ctx->bytes_per_state = 1; - ctx->SetNextState = SCACTileSetState1Byte; - - switch(ctx->alphabet_storage) { - case 8: - ctx->Search = SCACTileSearchTiny8; - break; - case 16: - ctx->Search = SCACTileSearchTiny16; - break; - case 32: - ctx->Search = SCACTileSearchTiny32; - break; - case 64: - ctx->Search = SCACTileSearchTiny64; - break; - case 128: - ctx->Search = SCACTileSearchTiny128; - break; - default: - ctx->Search = SCACTileSearchTiny256; - } - } else { - /* 16-bit state needed */ - ctx->bytes_per_state = 2; - ctx->SetNextState = SCACTileSetState2Bytes; - - switch(ctx->alphabet_storage) { - case 8: - ctx->Search = SCACTileSearchSmall8; - break; - case 16: - ctx->Search = SCACTileSearchSmall16; - break; - case 32: - ctx->Search = SCACTileSearchSmall32; - break; - case 64: - ctx->Search = SCACTileSearchSmall64; - break; - case 128: - ctx->Search = SCACTileSearchSmall128; - break; - default: - ctx->Search = SCACTileSearchSmall256; - } - } - } else { - /* 32-bit next state */ - ctx->Search = SCACTileSearchLarge; - ctx->bytes_per_state = 4; - ctx->SetNextState = SCACTileSetState4Bytes; - - ctx->alphabet_storage = 256; /* Change? */ - } - - StateQueue q; - memset(&q, 0, sizeof(StateQueue)); - - for (aa = 0; aa < ctx->alphabet_size; aa++) { - int temp_state = ctx->goto_table[0][aa]; - if (temp_state != 0) - SCACTileEnqueue(&q, temp_state); - } - - while (!SCACTileStateQueueIsEmpty(&q)) { - r_state = SCACTileDequeue(&q); - - for (aa = 0; aa < ctx->alphabet_size; aa++) { - int temp_state = ctx->goto_table[r_state][aa]; - if (temp_state != SC_AC_TILE_FAIL) { - SCACTileEnqueue(&q, temp_state); - } else { - int f_state = ctx->failure_table[r_state]; - ctx->goto_table[r_state][aa] = ctx->goto_table[f_state][aa]; - } - } - } -} - -static void SCACTileClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - int aa = 0; - uint32_t state = 0; - - /* Allocate next-state table. */ - int size = ctx->state_count * ctx->bytes_per_state * ctx->alphabet_storage; - void *state_table = SCCalloc(1, size); - if (unlikely(state_table == NULL)) { - FatalError("Error allocating memory"); - } - ctx->state_table = state_table; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += size; - - SCLogDebug("Delta Table size %d, alphabet: %d, %d-byte states: %d", - size, ctx->alphabet_size, ctx->bytes_per_state, ctx->state_count); - - /* Copy next state from Goto table, which is 32 bits and encode it into the next - * state table, which can be 1, 2 or 4 bytes each and include if there is an - * output. - */ - for (state = 0; state < ctx->state_count; state++) { - for (aa = 0; aa < ctx->alphabet_size; aa++) { - int next_state = ctx->goto_table[state][aa]; - int next_state_outputs = ctx->output_table[next_state].no_of_entries; - ctx->SetNextState(ctx, state, aa, next_state, next_state_outputs); - } - } -} - -static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - uint32_t state = 0; - uint32_t k = 0; - - for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].no_of_entries == 0) - continue; - - for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { - if (ctx->pattern_list[ctx->output_table[state].patterns[k]].cs != NULL) { - /* TODO - Find better way to store this. */ - ctx->output_table[state].patterns[k] &= 0x0FFFFFFF; - ctx->output_table[state].patterns[k] |= (uint32_t)1 << 31; - } - } - } -} - -#if 0 -static void SCACTilePrintDeltaTable(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - int i = 0, j = 0; - - printf("##############Delta Table##############\n"); - for (i = 0; i < ctx->state_count; i++) { - printf("%d: \n", i); - for (j = 0; j < ctx->alphabet_size; j++) { - if (SCACTileGetDelta(i, j, mpm_ctx) != 0) { - printf(" %c -> %d\n", j, SCACTileGetDelta(i, j, mpm_ctx)); - } - } - } -} -#endif - -/** - * \brief Process the patterns and prepare the state table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACTilePrepareStateTable(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - /* Create Alphabet compression and Lower Case translation table. */ - SCACTileInitTranslateTable(ctx); - - /* create the 0th state in the goto table and output_table */ - SCACTileInitNewState(mpm_ctx); - - /* create the goto table */ - SCACTileCreateGotoTable(mpm_ctx); - /* create the failure table */ - SCACTileCreateFailureTable(mpm_ctx); - /* create the final state(delta) table */ - SCACTileCreateDeltaTable(mpm_ctx); - /* club the output state presence with delta transition entries */ - SCACTileClubOutputStatePresenceWithDeltaTable(mpm_ctx); - - /* club nocase entries */ - SCACTileInsertCaseSensitiveEntriesForPatterns(mpm_ctx); - -#if 0 - SCACTilePrintDeltaTable(mpm_ctx); -#endif - - /* we don't need these anymore */ - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - SCFree(ctx->failure_table); - ctx->failure_table = NULL; -} - - -/** - * \brief Process Internal AC MPM tables to create the Search Context - * - * The search context is only the data needed to search the MPM. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACTilePrepareSearch(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - /* Resize the output table to be only as big as its final size. */ - SCACTileReallocOutputTable(ctx, ctx->state_count); - - search_ctx->Search = ctx->Search; - memcpy(search_ctx->translate_table, ctx->translate_table, sizeof(ctx->translate_table)); - - /* Move the state table from the Init context */ - search_ctx->state_table = ctx->state_table; - ctx->state_table = NULL; /* So that it won't get freed twice. */ - - /* Move the output_table from the Init context to the Search Context */ - /* TODO: Could be made more compact */ - search_ctx->output_table = ctx->output_table; - ctx->output_table = NULL; - search_ctx->state_count = ctx->state_count; - - search_ctx->pattern_list = ctx->pattern_list; - ctx->pattern_list = NULL; - search_ctx->pattern_cnt = mpm_ctx->pattern_cnt; - - /* One bit per pattern, rounded up to the next byte size. */ - search_ctx->mpm_bitarray_size = (mpm_ctx->pattern_cnt + 7) / 8; - - /* Can now free the Initialization data */ - SCACTileDestroyInitCtx(mpm_ctx); -} - -/** - * \brief Process the patterns added to the mpm, and create the internal tables. - * - * \param mpm_ctx Pointer to the mpm context. - */ -int SCACTilePreparePatterns(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - - if (mpm_ctx->pattern_cnt == 0 || search_ctx->init_ctx == NULL) { - SCLogDebug("no patterns supplied to this mpm_ctx"); - return 0; - } - SCACTileCtx *ctx = search_ctx->init_ctx; - if (mpm_ctx->init_hash == NULL) { - SCLogDebug("no patterns supplied to this mpm_ctx"); - return 0; - } - - /* alloc the pattern array */ - ctx->parray = (MpmPattern **)SCCalloc(mpm_ctx->pattern_cnt, sizeof(MpmPattern *)); - if (ctx->parray == NULL) - goto error; - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { - MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; - while(node != NULL) { - nnode = node->next; - node->next = NULL; - ctx->parray[p++] = node; - SCACTileHistogramAlphabet(ctx, node); - node = nnode; - } - } - - /* we no longer need the hash, so free it's memory */ - SCFree(mpm_ctx->init_hash); - mpm_ctx->init_hash = NULL; - - /* Handle case patterns by storing a copy of the pattern to compare - * to each possible match (no-case). - * - * Allocate the memory for the array and each of the strings as one block. - */ - size_t string_space_needed = 0; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { - /* Round up to next 8 byte aligned length */ - uint32_t space = ((ctx->parray[i]->len + 7) / 8) * 8; - string_space_needed += space; - } - } - - size_t pattern_list_size = mpm_ctx->pattern_cnt * sizeof(SCACTilePatternList); - size_t mem_size = string_space_needed + pattern_list_size; - void *mem_block = SCCalloc(1, mem_size); - if (mem_block == NULL) { - FatalError("Error allocating memory"); - } - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += mem_size; - /* Split the allocated block into pattern list array and string space. */ - ctx->pattern_list = mem_block; - uint8_t *string_space = mem_block + pattern_list_size; - - /* Now make the copies of the no-case strings. */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { - uint16_t len = ctx->parray[i]->len; - uint32_t space = ((len + 7) / 8) * 8; - memcpy(string_space, ctx->parray[i]->original_pat, len); - ctx->pattern_list[i].cs = string_space; - ctx->pattern_list[i].patlen = len; - string_space += space; - } - ctx->pattern_list[i].offset = ctx->parray[i]->offset; - ctx->pattern_list[i].depth = ctx->parray[i]->depth; - ctx->pattern_list[i].pid = ctx->parray[i]->id; - - /* ACPatternList now owns this memory */ - ctx->pattern_list[i].sids_size = ctx->parray[i]->sids_size; - ctx->pattern_list[i].sids = ctx->parray[i]->sids; - ctx->parray[i]->sids = NULL; - ctx->parray[i]->sids_size = 0; - } - - /* prepare the state table required by AC */ - SCACTilePrepareStateTable(mpm_ctx); - - /* Convert to the Search Context structure */ - SCACTilePrepareSearch(mpm_ctx); - - return 0; - -error: - return -1; -} - -/** - * \brief Initialize the AC context. - * - * \param mpm_ctx Mpm context. - */ -void SCACTileInitCtx(MpmCtx *mpm_ctx) -{ - if (mpm_ctx->ctx != NULL) - return; - - /* Search Context */ - mpm_ctx->ctx = SCCalloc(1, sizeof(SCACTileSearchCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACTileSearchCtx); - - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - - /* MPM Creation context */ - search_ctx->init_ctx = SCCalloc(1, sizeof(SCACTileCtx)); - if (search_ctx->init_ctx == NULL) { - exit(EXIT_FAILURE); - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACTileCtx); - - /* initialize the hash we use to speed up pattern insertions */ - mpm_ctx->init_hash = SCCalloc(MPM_INIT_HASH_SIZE, sizeof(MpmPattern *)); - if (mpm_ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - - /* get conf values for AC from our yaml file. We have no conf values for - * now. We will certainly need this, as we develop the algo */ - SCACTileGetConfig(); -} - -static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - if (ctx == NULL) - return; - - if (mpm_ctx->init_hash != NULL) { - SCFree(mpm_ctx->init_hash); - mpm_ctx->init_hash = NULL; - } - - if (ctx->parray != NULL) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - MpmFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - ctx->parray = NULL; - } - - if (ctx->state_table != NULL) { - SCFree(ctx->state_table); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (ctx->state_count * - ctx->bytes_per_state * ctx->alphabet_storage); - } - - if (ctx->output_table != NULL) { - uint32_t state; - for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].patterns != NULL) { - SCFree(ctx->output_table[state].patterns); - } - } - SCFree(ctx->output_table); - } - - if (ctx->pattern_list != NULL) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->pattern_list[i].cs != NULL) - SCFree(ctx->pattern_list[i].cs); - if (ctx->pattern_list[i].sids != NULL) - SCFree(ctx->pattern_list[i].sids); - } - SCFree(ctx->pattern_list); - } - - SCFree(ctx); - search_ctx->init_ctx = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACTileCtx); -} - -/** - * \brief Destroy the mpm context. - * - * \param mpm_ctx Pointer to the mpm context. - */ -void SCACTileDestroyCtx(MpmCtx *mpm_ctx) -{ - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - if (search_ctx == NULL) - return; - - /* Destroy Initialization data */ - SCACTileDestroyInitCtx(mpm_ctx); - - /* Free Search tables */ - SCFree(search_ctx->state_table); - - if (search_ctx->pattern_list != NULL) { - uint32_t i; - for (i = 0; i < search_ctx->pattern_cnt; i++) { - if (search_ctx->pattern_list[i].sids != NULL) - SCFree(search_ctx->pattern_list[i].sids); - } - SCFree(search_ctx->pattern_list); - } - - if (search_ctx->output_table != NULL) { - uint32_t state; - for (state = 0; state < search_ctx->state_count; state++) { - if (search_ctx->output_table[state].patterns != NULL) { - SCFree(search_ctx->output_table[state].patterns); - } - } - SCFree(search_ctx->output_table); - } - - SCFree(search_ctx); - mpm_ctx->ctx = NULL; - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACTileSearchCtx); -} - -/* - * Heavily optimized pattern matching routine for TILE-Gx. - */ - -#define SCHECK(x) ((x) > 0) -#define BUF_TYPE int32_t -// Extract byte N=0,1,2,3 from x -#define BYTE0(x) (((x) & 0x000000ff) >> 0) -#define BYTE1(x) (((x) & 0x0000ff00) >> 8) -#define BYTE2(x) (((x) & 0x00ff0000) >> 16) -#define BYTE3(x) (((x) & 0xff000000) >> 24) -#define EXTRA 4 // need 4 extra bytes to avoid OOB reads - -static int CheckMatch(const SCACTileSearchCtx *ctx, PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen, - uint16_t state, int i, int matches, - uint8_t *mpm_bitarray) -{ - const SCACTilePatternList *pattern_list = ctx->pattern_list; - const uint8_t *buf_offset = buf + i + 1; // Lift out of loop - uint32_t no_of_entries = ctx->output_table[state].no_of_entries; - MpmPatternIndex *patterns = ctx->output_table[state].patterns; - uint32_t k; - - for (k = 0; k < no_of_entries; k++) { - MpmPatternIndex pindex = patterns[k] & 0x0FFFFFFF; - if (mpm_bitarray[pindex / 8] & (1 << (pindex % 8))) { - /* Pattern already seen by this MPM. */ - continue; - } - const SCACTilePatternList *pat = &pattern_list[pindex]; - const int offset = i - pat->patlen + 1; - if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) - continue; - - /* Double check case-sensitive match now. */ - if (patterns[k] >> 31) { - const uint16_t patlen = pat->patlen; - if (SCMemcmp(pat->cs, buf_offset - patlen, patlen) != 0) { - /* Case-sensitive match failed. */ - continue; - } - } - /* New match found */ - mpm_bitarray[pindex / 8] |= (1 << (pindex % 8)); - - /* Always add the Signature IDs, since they could be different in the current MPM - * than in a previous MPM on the same PMQ when finding the same pattern. - */ - PrefilterAddSids(pmq, pattern_list[pindex].sids, - pattern_list[pindex].sids_size); - matches++; - } - - return matches; -} - -/** - * \brief The aho corasick search function. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param pmq Pointer to the Pattern Matcher Queue to hold - * search matches. - * \param buf Buffer to be searched. - * \param buflen Buffer length. - * - * \retval matches Match count. - */ -uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen) -{ - const SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - - if (buflen == 0) - return 0; - - /* Context specific matching function. */ - return search_ctx->Search(search_ctx, mpm_thread_ctx, pmq, buf, buflen); -} - -/* This function handles (ctx->state_count >= 32767) */ -uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, - const uint8_t *buf, uint32_t buflen) -{ - uint32_t i = 0; - int matches = 0; - - uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; - memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); - - const uint8_t* restrict xlate = ctx->translate_table; - register int state = 0; - int32_t (*state_table_u32)[256] = ctx->state_table; - for (i = 0; i < buflen; i++) { - state = state_table_u32[state & 0x00FFFFFF][xlate[buf[i]]]; - if (SCHECK(state)) { - DEBUG_VALIDATE_BUG_ON(state < 0 || state > UINT16_MAX); - matches = CheckMatch(ctx, pmq, buf, buflen, (uint16_t)state, i, matches, mpm_bitarray); - } - } /* for (i = 0; i < buflen; i++) */ - - return matches; -} - -/* - * Search with Alphabet size of 256 and 16-bit next-state entries. - * Next state entry has MSB as "match" and 15 LSB bits as next-state index. - */ -// y = 1<ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - printf("MPM AC Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeof:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" SCACTileCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACTileCtx)); - printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); - printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Total states in the state table: %u\n", ctx->state_count); - printf("\n"); -} - -/************************** Mpm Registration ***************************/ - -/** - * \brief Register the aho-corasick mpm 'ks' originally developed by - * Ken Steele for Tilera Tile-Gx processor. - */ -void MpmACTileRegister(void) -{ - mpm_table[MPM_AC_KS].name = "ac-ks"; - mpm_table[MPM_AC_KS].InitCtx = SCACTileInitCtx; - mpm_table[MPM_AC_KS].DestroyCtx = SCACTileDestroyCtx; - mpm_table[MPM_AC_KS].AddPattern = SCACTileAddPatternCS; - mpm_table[MPM_AC_KS].AddPatternNocase = SCACTileAddPatternCI; - mpm_table[MPM_AC_KS].Prepare = SCACTilePreparePatterns; - mpm_table[MPM_AC_KS].Search = SCACTileSearch; - mpm_table[MPM_AC_KS].PrintCtx = SCACTilePrintInfo; - mpm_table[MPM_AC_KS].RegisterUnittests = SCACTileRegisterTests; -} - - -/*************************************Unittests********************************/ - -#ifdef UNITTESTS -#include "detect-engine-alert.h" - -static int SCACTileTest01(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest02(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest03(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest04(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest05(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest06(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcd"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest07(void) -{ - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); - /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); - /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); - /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq); - /* total matches: 135: 6 unique */ - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - FAIL_IF_NOT(cnt == 6); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - PASS; -} - -static int SCACTileTest08(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest09(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest10(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest11(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) - goto end; - PmqSetup(&pmq); - - if (SCACTilePreparePatterns(&mpm_ctx) == -1) - goto end; - - result = 1; - - const char *buf = "he"; - result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "she"; - result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - buf = "his"; - result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "hers"; - result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - - end: - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest12(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest13(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest14(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest15(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest16(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABC"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABC"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest17(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzAB"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzAB"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest18(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - const char pat[] = "abcde" - "fghij" - "klmno" - "pqrst" - "uvwxy" - "z"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest19(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 */ - const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest20(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 */ - const char pat[] = "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest21(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest22(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest23(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 0) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest24(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 1 */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest25(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest26(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "works"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest27(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "tone"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest28(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_KS); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACTilePreparePatterns(&mpm_ctx); - - const char *buf = "tONE"; - uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACTileDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTileTest29(void) -{ - uint8_t buf[] = "onetwothreefourfivesixseveneightnine"; - uint16_t buflen = sizeof(buf) - 1; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); - if (de_ctx->sig_list->next == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) != 1) { - printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); - goto end; - } - if (PacketAlertCheck(p, 2) != 1) { - printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); - goto end; - } - - result = 1; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - UTHFreePackets(&p, 1); - return result; -} - -#endif /* UNITTESTS */ - -void SCACTileRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("SCACTileTest01", SCACTileTest01); - UtRegisterTest("SCACTileTest02", SCACTileTest02); - UtRegisterTest("SCACTileTest03", SCACTileTest03); - UtRegisterTest("SCACTileTest04", SCACTileTest04); - UtRegisterTest("SCACTileTest05", SCACTileTest05); - UtRegisterTest("SCACTileTest06", SCACTileTest06); - UtRegisterTest("SCACTileTest07", SCACTileTest07); - UtRegisterTest("SCACTileTest08", SCACTileTest08); - UtRegisterTest("SCACTileTest09", SCACTileTest09); - UtRegisterTest("SCACTileTest10", SCACTileTest10); - UtRegisterTest("SCACTileTest11", SCACTileTest11); - UtRegisterTest("SCACTileTest12", SCACTileTest12); - UtRegisterTest("SCACTileTest13", SCACTileTest13); - UtRegisterTest("SCACTileTest14", SCACTileTest14); - UtRegisterTest("SCACTileTest15", SCACTileTest15); - UtRegisterTest("SCACTileTest16", SCACTileTest16); - UtRegisterTest("SCACTileTest17", SCACTileTest17); - UtRegisterTest("SCACTileTest18", SCACTileTest18); - UtRegisterTest("SCACTileTest19", SCACTileTest19); - UtRegisterTest("SCACTileTest20", SCACTileTest20); - UtRegisterTest("SCACTileTest21", SCACTileTest21); - UtRegisterTest("SCACTileTest22", SCACTileTest22); - UtRegisterTest("SCACTileTest23", SCACTileTest23); - UtRegisterTest("SCACTileTest24", SCACTileTest24); - UtRegisterTest("SCACTileTest25", SCACTileTest25); - UtRegisterTest("SCACTileTest26", SCACTileTest26); - UtRegisterTest("SCACTileTest27", SCACTileTest27); - UtRegisterTest("SCACTileTest28", SCACTileTest28); - UtRegisterTest("SCACTileTest29", SCACTileTest29); -#endif -} - -#else /* we're big endian */ - -void MpmACTileRegister(void) -{ - /* no-op on big endian */ -} - -#endif /* little endian check */ diff --git a/src/util-mpm-ac-ks.h b/src/util-mpm-ac-ks.h deleted file mode 100644 index 4979f84241a4..000000000000 --- a/src/util-mpm-ac-ks.h +++ /dev/null @@ -1,150 +0,0 @@ -/* Copyright (C) 2013-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * \author Ken Steele - * - */ - -#ifndef __UTIL_MPM_AC_KS__H__ -#define __UTIL_MPM_AC_KS__H__ - -typedef struct SCACTilePatternList_ { - uint8_t *cs; - uint16_t patlen; - - uint16_t offset; - uint16_t depth; - - /* Pattern Id */ - uint32_t pid; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; -} SCACTilePatternList; - -typedef struct SCACTileOutputTable_ { - /* list of pattern indexes */ - MpmPatternIndex *patterns; - /* number of entries in pattern list */ - uint32_t no_of_entries; -} SCACTileOutputTable; - -struct SCACTileSearchCtx_; - -/* Reordered for Tilera cache */ -typedef struct SCACTileCtx_ { - - /* Convert input character to matching alphabet */ - uint8_t translate_table[256]; - - /* The all important memory hungry state_table. - * The size of each next-state is determined by bytes_per_state. - */ - void *state_table; - - /* Specialized search function based on size of data in delta - * tables. The alphabet size determines address shifting and the - * number of states could make the next state could be 16 bits or - * 32 bits. - */ - uint32_t (*Search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PrefilterRuleStore *, const uint8_t *, uint32_t); - - /* Function to set the next state based on size of next state - * (bytes_per_state). - */ - void (*SetNextState)(struct SCACTileCtx_ *ctx, int state, int aa, - int new_state, int outputs); - - /* List of patterns that match for this state. Indexed by State Number */ - SCACTileOutputTable *output_table; - /* Indexed by MpmPatternIndex */ - SCACTilePatternList *pattern_list; - - /* pattern arrays. We need this only during the goto table - creation phase */ - MpmPattern **parray; - - /* goto_table, failure table and output table. Needed to create - * state_table. Will be freed, once we have created the - * state_table */ - int32_t (*goto_table)[256]; - int32_t *failure_table; - - /* Number of states used */ - uint32_t state_count; - /* Number of states allocated. */ - uint32_t allocated_state_count; - - uint32_t alpha_hist[256]; - /* Number of characters in the compressed alphabet. */ - uint16_t alphabet_size; - /* Space used to store compressed alphabet is the next - * larger or equal power-of-2. - */ - uint16_t alphabet_storage; - - /* How many bytes are used to store the next state. */ - uint8_t bytes_per_state; - -} SCACTileCtx; - - -/* Only the stuff used at search time. This - * structure is created after all the patterns are added. - */ -typedef struct SCACTileSearchCtx_ { - - /* Specialized search function based on size of data in delta - * tables. The alphabet size determines address shifting and the - * number of states could make the next state could be 16 bits or - * 32 bits. - */ - uint32_t (*Search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PrefilterRuleStore *, const uint8_t *, uint32_t); - - /* Convert input character to matching alphabet */ - uint8_t translate_table[256]; - - /* the all important memory hungry state_table */ - void *state_table; - - /* List of patterns that match for this state. Indexed by State Number */ - SCACTileOutputTable *output_table; - SCACTilePatternList *pattern_list; - - /* Number of bytes in the array of bits. One bit per pattern in this MPM. */ - uint32_t mpm_bitarray_size; - - /* Number of states used */ - uint32_t state_count; - - uint32_t pattern_cnt; - - /* MPM Creation data, only used at initialization. */ - SCACTileCtx *init_ctx; - -} SCACTileSearchCtx; - -void MpmACTileRegister(void); - -#endif /* __UTIL_MPM_AC_KS__H__ */ diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c deleted file mode 100644 index 6d0fc050b99a..000000000000 --- a/src/util-mpm-ac.c +++ /dev/null @@ -1,2162 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * First iteration of aho-corasick MPM from - - * - * Efficient String Matching: An Aid to Bibliographic Search - * Alfred V. Aho and Margaret J. Corasick - * - * - Uses the delta table for calculating transitions, instead of having - * separate goto and failure transitions. - * - If we cross 2 ** 16 states, we use 4 bytes in the transition table - * to hold each state, otherwise we use 2 bytes. - * - This version of the MPM is heavy on memory, but it performs well. - * If you can fit the ruleset with this mpm on your box without hitting - * swap, this is the MPM to go for. - * - * \todo - Do a proper analysis of our existing MPMs and suggest a good one based - * on the pattern distribution and the expected traffic(say http). - * - Tried out loop unrolling without any perf increase. Need to dig deeper. - * - Irrespective of whether we cross 2 ** 16 states or not,shift to using - * uint32_t for state type, so that we can integrate it's status as a - * final state or not in the topmost byte. We are already doing it if - * state_count is > 2 ** 16. - * - Test case-sensitive patterns if they have any ascii chars. If they - * don't treat them as nocase. - * - Carry out other optimizations we are working on. hashes, compression. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-build.h" - -#include "conf.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-memcmp.h" -#include "util-mpm-ac.h" -#include "util-memcpy.h" -#include "util-validate.h" - -void SCACInitCtx(MpmCtx *); -void SCACDestroyCtx(MpmCtx *); -int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCACPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); -void SCACPrintInfo(MpmCtx *mpm_ctx); -void SCACRegisterTests(void); - -/* a placeholder to denote a failure transition in the goto table */ -#define SC_AC_FAIL (-1) - -#define STATE_QUEUE_CONTAINER_SIZE 65536 - -#define AC_CASE_MASK 0x80000000 -#define AC_PID_MASK 0x7FFFFFFF -#define AC_CASE_BIT 31 - -static int construct_both_16_and_32_state_tables = 0; - -/** - * \brief Helper structure used by AC during state table creation - */ -typedef struct StateQueue_ { - int32_t store[STATE_QUEUE_CONTAINER_SIZE]; - int top; - int bot; -} StateQueue; - -/** - * \internal - * \brief Initialize the AC context with user specified conf parameters. We - * aren't retrieving anything for AC conf now, but we will certainly - * need it, when we customize AC. - */ -static void SCACGetConfig(void) -{ - //ConfNode *ac_conf; - //const char *hash_val = NULL; - - //ConfNode *pm = ConfGetNode("pattern-matcher"); - - return; -} - -/** - * \internal - * \brief Check if size_t multiplication would overflow and perform operation - * if safe. In case of an overflow we exit(). - * - * \param a First size_t value to multiplicate. - * \param b Second size_t value to multiplicate. - * - * \retval The product of a and b, guaranteed to not overflow. - */ -static inline size_t SCACCheckSafeSizetMult(size_t a, size_t b) -{ - /* check for safety of multiplication operation */ - if (b > 0 && a > SIZE_MAX / b) { - SCLogError("%" PRIuMAX " * %" PRIuMAX " > %" PRIuMAX - " would overflow size_t calculating buffer size", - (uintmax_t)a, (uintmax_t)b, (uintmax_t)SIZE_MAX); - exit(EXIT_FAILURE); - } - return a * b; -} - -/** - * \internal - * \brief Initialize a new state in the goto and output tables. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval The state id, of the newly created state. - */ -static inline int SCACReallocState(SCACCtx *ctx, uint32_t cnt) -{ - void *ptmp = NULL; - size_t size = 0; - - /* reallocate space in the goto table to include a new state */ - size = SCACCheckSafeSizetMult((size_t) cnt, (size_t) ctx->single_state_size); - if (size > 0) - ptmp = SCRealloc(ctx->goto_table, size); - if (ptmp == NULL) { - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - FatalError("Error allocating memory"); - } - ctx->goto_table = ptmp; - - /* reallocate space in the output table for the new state */ - size_t oldsize = SCACCheckSafeSizetMult((size_t) ctx->state_count, - sizeof(SCACOutputTable)); - size = SCACCheckSafeSizetMult((size_t) cnt, sizeof(SCACOutputTable)); - SCLogDebug("oldsize %"PRIuMAX" size %"PRIuMAX" cnt %d ctx->state_count %u", - (uintmax_t) oldsize, (uintmax_t) size, cnt, ctx->state_count); - - ptmp = NULL; - if (size > 0) - ptmp = SCRealloc(ctx->output_table, size); - if (ptmp == NULL) { - SCFree(ctx->output_table); - ctx->output_table = NULL; - FatalError("Error allocating memory"); - } - ctx->output_table = ptmp; - - memset(((uint8_t *)ctx->output_table + oldsize), 0, (size - oldsize)); - - /* \todo using it temporarily now during dev, since I have restricted - * state var in SCACCtx->state_table to uint16_t. */ - //if (ctx->state_count > 65536) { - // printf("state count exceeded\n"); - // exit(EXIT_FAILURE); - //} - - return 0;//ctx->state_count++; -} - -/** \internal - * \brief Shrink state after setup is done - * - * Shrinks only the output table, goto table is freed after calling this - */ -static void SCACShrinkState(SCACCtx *ctx) -{ - /* reallocate space in the output table for the new state */ -#ifdef DEBUG - int oldsize = ctx->allocated_state_count * sizeof(SCACOutputTable); -#endif - int newsize = ctx->state_count * sizeof(SCACOutputTable); - - SCLogDebug("oldsize %d newsize %d ctx->allocated_state_count %u " - "ctx->state_count %u: shrink by %d bytes", oldsize, - newsize, ctx->allocated_state_count, ctx->state_count, - oldsize - newsize); - - void *ptmp = SCRealloc(ctx->output_table, newsize); - if (ptmp == NULL) { - SCFree(ctx->output_table); - ctx->output_table = NULL; - FatalError("Error allocating memory"); - } - ctx->output_table = ptmp; -} - -static inline int SCACInitNewState(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - - /* Exponentially increase the allocated space when needed. */ - if (ctx->allocated_state_count < ctx->state_count + 1) { - if (ctx->allocated_state_count == 0) - ctx->allocated_state_count = 256; - else - ctx->allocated_state_count *= 2; - - SCACReallocState(ctx, ctx->allocated_state_count); - - } -#if 0 - if (ctx->allocated_state_count > 260) { - SCACOutputTable *output_state = &ctx->output_table[260]; - SCLogInfo("output_state %p %p %u", output_state, output_state->pids, output_state->no_of_entries); - } -#endif - int ascii_code = 0; - /* set all transitions for the newly assigned state as FAIL transitions */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_FAIL; - } - - return ctx->state_count++; -} - -/** - * \internal - * \brief Adds a pid to the output table for a state. - * - * \param state The state to whose output table we should add the pid. - * \param pid The pattern id to add. - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - SCACOutputTable *output_state = &ctx->output_table[state]; - uint32_t i = 0; - - for (i = 0; i < output_state->no_of_entries; i++) { - if (output_state->pids[i] == pid) - return; - } - - output_state->no_of_entries++; - ptmp = SCRealloc(output_state->pids, - output_state->no_of_entries * sizeof(uint32_t)); - if (ptmp == NULL) { - SCFree(output_state->pids); - output_state->pids = NULL; - FatalError("Error allocating memory"); - } - output_state->pids = ptmp; - - output_state->pids[output_state->no_of_entries - 1] = pid; - - return; -} - -/** - * \brief Helper function used by SCACCreateGotoTable. Adds a pattern to the - * goto table. - * - * \param pattern Pointer to the pattern. - * \param pattern_len Pattern length. - * \param pid The pattern id, that corresponds to this pattern. We - * need it to updated the output table for this pattern. - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, - MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - int32_t state = 0; - int32_t newstate = 0; - int i = 0; - int p = 0; - - /* walk down the trie till we have a match for the pattern prefix */ - state = 0; - for (i = 0; i < pattern_len; i++) { - if (ctx->goto_table[state][pattern[i]] != SC_AC_FAIL) { - state = ctx->goto_table[state][pattern[i]]; - } else { - break; - } - } - - /* add the non-matching pattern suffix to the trie, from the last state - * we left off */ - for (p = i; p < pattern_len; p++) { - newstate = SCACInitNewState(mpm_ctx); - ctx->goto_table[state][pattern[p]] = newstate; - state = newstate; - } - - /* add this pattern id, to the output table of the last state, where the - * pattern ends in the trie */ - SCACSetOutputState(state, pid, mpm_ctx); - - return; -} - -/** - * \internal - * \brief Create the goto table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACCreateGotoTable(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - uint32_t i = 0; - - /* add each pattern to create the goto table */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - SCACEnter(ctx->parray[i]->ci, ctx->parray[i]->len, - ctx->parray[i]->id, mpm_ctx); - } - - int ascii_code = 0; - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[0][ascii_code] == SC_AC_FAIL) { - ctx->goto_table[0][ascii_code] = 0; - } - } - - return; -} - -static inline void SCACDetermineLevel1Gap(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - uint32_t u = 0; - - uint8_t map[256]; - memset(map, 0, sizeof(map)); - - for (u = 0; u < mpm_ctx->pattern_cnt; u++) - map[ctx->parray[u]->ci[0]] = 1; - - for (u = 0; u < 256; u++) { - if (map[u] == 0) - continue; - int32_t newstate = SCACInitNewState(mpm_ctx); - ctx->goto_table[0][u] = newstate; - } - - return; -} - -static inline int SCACStateQueueIsEmpty(StateQueue *q) -{ - if (q->top == q->bot) - return 1; - else - return 0; -} - -static inline void SCACEnqueue(StateQueue *q, int32_t state) -{ - int i = 0; - - /*if we already have this */ - for (i = q->bot; i < q->top; i++) { - if (q->store[i] == state) - return; - } - - q->store[q->top++] = state; - - if (q->top == STATE_QUEUE_CONTAINER_SIZE) - q->top = 0; - - if (q->top == q->bot) { - FatalError("Just ran out of space in the queue. Please file a bug report on this"); - } - - return; -} - -static inline int32_t SCACDequeue(StateQueue *q) -{ - if (q->bot == STATE_QUEUE_CONTAINER_SIZE) - q->bot = 0; - - if (q->bot == q->top) { - FatalError("StateQueue behaving weirdly. Please file a bug report on this"); - } - - return q->store[q->bot++]; -} - -/** - * \internal - * \brief Club the output data from 2 states and store it in the 1st state. - * dst_state_data = {dst_state_data} UNION {src_state_data} - * - * \param dst_state First state(also the destination) for the union operation. - * \param src_state Second state for the union operation. - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACClubOutputStates(int32_t dst_state, int32_t src_state, - MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - uint32_t i = 0; - uint32_t j = 0; - - SCACOutputTable *output_dst_state = &ctx->output_table[dst_state]; - SCACOutputTable *output_src_state = &ctx->output_table[src_state]; - - for (i = 0; i < output_src_state->no_of_entries; i++) { - for (j = 0; j < output_dst_state->no_of_entries; j++) { - if (output_src_state->pids[i] == output_dst_state->pids[j]) { - break; - } - } - if (j == output_dst_state->no_of_entries) { - output_dst_state->no_of_entries++; - - ptmp = SCRealloc(output_dst_state->pids, - (output_dst_state->no_of_entries * sizeof(uint32_t))); - if (ptmp == NULL) { - SCFree(output_dst_state->pids); - output_dst_state->pids = NULL; - FatalError("Error allocating memory"); - } - output_dst_state->pids = ptmp; - - output_dst_state->pids[output_dst_state->no_of_entries - 1] = - output_src_state->pids[i]; - } - } - - return; -} - -/** - * \internal - * \brief Create the failure table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACCreateFailureTable(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - int ascii_code = 0; - int32_t state = 0; - int32_t r_state = 0; - - StateQueue *q = SCCalloc(1, sizeof(StateQueue)); - if (q == NULL) { - FatalError("Error allocating memory"); - } - - /* allot space for the failure table. A failure entry in the table for - * every state(SCACCtx->state_count) */ - ctx->failure_table = SCCalloc(ctx->state_count, sizeof(int32_t)); - if (ctx->failure_table == NULL) { - FatalError("Error allocating memory"); - } - - /* add the failure transitions for the 0th state, and add every non-fail - * transition from the 0th state to the queue for further processing - * of failure states */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[0][ascii_code]; - if (temp_state != 0) { - SCACEnqueue(q, temp_state); - ctx->failure_table[temp_state] = 0; - } - } - - while (!SCACStateQueueIsEmpty(q)) { - /* pick up every state from the queue and add failure transitions */ - r_state = SCACDequeue(q); - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[r_state][ascii_code]; - if (temp_state == SC_AC_FAIL) - continue; - SCACEnqueue(q, temp_state); - state = ctx->failure_table[r_state]; - - while(ctx->goto_table[state][ascii_code] == SC_AC_FAIL) - state = ctx->failure_table[state]; - ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code]; - SCACClubOutputStates(temp_state, ctx->failure_table[temp_state], - mpm_ctx); - } - } - SCFree(q); - - return; -} - -/** - * \internal - * \brief Create the delta table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACCreateDeltaTable(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - int ascii_code = 0; - int32_t r_state = 0; - - if ((ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { - ctx->state_table_u16 = SCCalloc(ctx->state_count, sizeof(*ctx->state_table_u16)); - if (ctx->state_table_u16 == NULL) { - FatalError("Error allocating memory"); - } - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (ctx->state_count * sizeof(*ctx->state_table_u16)); - - StateQueue *q = SCCalloc(1, sizeof(StateQueue)); - if (q == NULL) { - FatalError("Error allocating memory"); - } - - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - DEBUG_VALIDATE_BUG_ON(ctx->goto_table[0][ascii_code] > UINT16_MAX); - SC_AC_STATE_TYPE_U16 temp_state = (uint16_t)ctx->goto_table[0][ascii_code]; - ctx->state_table_u16[0][ascii_code] = temp_state; - if (temp_state != 0) - SCACEnqueue(q, temp_state); - } - - while (!SCACStateQueueIsEmpty(q)) { - r_state = SCACDequeue(q); - - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[r_state][ascii_code]; - if (temp_state != SC_AC_FAIL) { - SCACEnqueue(q, temp_state); - DEBUG_VALIDATE_BUG_ON(temp_state > UINT16_MAX); - ctx->state_table_u16[r_state][ascii_code] = (uint16_t)temp_state; - } else { - ctx->state_table_u16[r_state][ascii_code] = - ctx->state_table_u16[ctx->failure_table[r_state]][ascii_code]; - } - } - } - SCFree(q); - } - - if (!(ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { - /* create space for the state table. We could have used the existing goto - * table, but since we have it set to hold 32 bit state values, we will create - * a new state table here of type SC_AC_STATE_TYPE(current set to uint16_t) */ - ctx->state_table_u32 = SCCalloc(ctx->state_count, sizeof(*ctx->state_table_u32)); - if (ctx->state_table_u32 == NULL) { - FatalError("Error allocating memory"); - } - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (ctx->state_count * sizeof(*ctx->state_table_u32)); - - StateQueue *q = SCCalloc(1, sizeof(StateQueue)); - if (q == NULL) { - FatalError("Error allocating memory"); - } - - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - SC_AC_STATE_TYPE_U32 temp_state = ctx->goto_table[0][ascii_code]; - ctx->state_table_u32[0][ascii_code] = temp_state; - if (temp_state != 0) - SCACEnqueue(q, temp_state); - } - - while (!SCACStateQueueIsEmpty(q)) { - r_state = SCACDequeue(q); - - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[r_state][ascii_code]; - if (temp_state != SC_AC_FAIL) { - SCACEnqueue(q, temp_state); - ctx->state_table_u32[r_state][ascii_code] = temp_state; - } else { - ctx->state_table_u32[r_state][ascii_code] = - ctx->state_table_u32[ctx->failure_table[r_state]][ascii_code]; - } - } - } - SCFree(q); - } - - return; -} - -static inline void SCACClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - int ascii_code = 0; - uint32_t state = 0; - uint32_t temp_state = 0; - - if ((ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { - for (state = 0; state < ctx->state_count; state++) { - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - temp_state = ctx->state_table_u16[state & 0x7FFF][ascii_code]; - if (ctx->output_table[temp_state & 0x7FFF].no_of_entries != 0) - ctx->state_table_u16[state & 0x7FFF][ascii_code] |= (1 << 15); - } - } - } - - if (!(ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { - for (state = 0; state < ctx->state_count; state++) { - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - temp_state = ctx->state_table_u32[state & 0x00FFFFFF][ascii_code]; - if (ctx->output_table[temp_state & 0x00FFFFFF].no_of_entries != 0) - ctx->state_table_u32[state & 0x00FFFFFF][ascii_code] |= (1 << 24); - } - } - } - - return; -} - -static inline void SCACInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - uint32_t state = 0; - uint32_t k = 0; - - for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].no_of_entries == 0) - continue; - - for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { - if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { - ctx->output_table[state].pids[k] &= AC_PID_MASK; - ctx->output_table[state].pids[k] |= ((uint32_t)1 << AC_CASE_BIT); - } - } - } - - return; -} - -#if 0 -static void SCACPrintDeltaTable(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - int i = 0, j = 0; - - printf("##############Delta Table##############\n"); - for (i = 0; i < ctx->state_count; i++) { - printf("%d: \n", i); - for (j = 0; j < 256; j++) { - if (SCACGetDelta(i, j, mpm_ctx) != 0) { - printf(" %c -> %d\n", j, SCACGetDelta(i, j, mpm_ctx)); - } - } - } - - return; -} -#endif - -/** - * \brief Process the patterns and prepare the state table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACPrepareStateTable(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - - /* create the 0th state in the goto table and output_table */ - SCACInitNewState(mpm_ctx); - - SCACDetermineLevel1Gap(mpm_ctx); - - /* create the goto table */ - SCACCreateGotoTable(mpm_ctx); - /* create the failure table */ - SCACCreateFailureTable(mpm_ctx); - /* create the final state(delta) table */ - SCACCreateDeltaTable(mpm_ctx); - /* club the output state presence with delta transition entries */ - SCACClubOutputStatePresenceWithDeltaTable(mpm_ctx); - - /* club nocase entries */ - SCACInsertCaseSensitiveEntriesForPatterns(mpm_ctx); - - /* shrink the memory */ - SCACShrinkState(ctx); - -#if 0 - SCACPrintDeltaTable(mpm_ctx); -#endif - - /* we don't need these anymore */ - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - SCFree(ctx->failure_table); - ctx->failure_table = NULL; - - return; -} - -/** - * \brief Process the patterns added to the mpm, and create the internal tables. - * - * \param mpm_ctx Pointer to the mpm context. - */ -int SCACPreparePatterns(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - - if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) { - SCLogDebug("no patterns supplied to this mpm_ctx"); - return 0; - } - - /* alloc the pattern array */ - ctx->parray = (MpmPattern **)SCCalloc(mpm_ctx->pattern_cnt, sizeof(MpmPattern *)); - if (ctx->parray == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { - MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; - while(node != NULL) { - nnode = node->next; - node->next = NULL; - ctx->parray[p++] = node; - node = nnode; - } - } - - /* we no longer need the hash, so free it's memory */ - SCFree(mpm_ctx->init_hash); - mpm_ctx->init_hash = NULL; - - /* the memory consumed by a single state in our goto table */ - ctx->single_state_size = sizeof(int32_t) * 256; - - /* handle no case patterns */ - ctx->pid_pat_list = SCCalloc((mpm_ctx->max_pat_id + 1), sizeof(SCACPatternList)); - if (ctx->pid_pat_list == NULL) { - FatalError("Error allocating memory"); - } - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { - ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); - if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { - FatalError("Error allocating memory"); - } - memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, - ctx->parray[i]->original_pat, ctx->parray[i]->len); - ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; - } - ctx->pid_pat_list[ctx->parray[i]->id].offset = ctx->parray[i]->offset; - ctx->pid_pat_list[ctx->parray[i]->id].depth = ctx->parray[i]->depth; - - /* ACPatternList now owns this memory */ - //SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size); - ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; - ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; - - ctx->parray[i]->sids_size = 0; - ctx->parray[i]->sids = NULL; - } - - /* prepare the state table required by AC */ - SCACPrepareStateTable(mpm_ctx); - - /* free all the stored patterns. Should save us a good 100-200 mbs */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - MpmFreePattern(mpm_ctx, ctx->parray[i]); - } - } - SCFree(ctx->parray); - ctx->parray = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); - - ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1; - SCLogDebug("ctx->pattern_id_bitarray_size %u", ctx->pattern_id_bitarray_size); - - return 0; - -error: - return -1; -} - -/** - * \brief Initialize the AC context. - * - * \param mpm_ctx Mpm context. - */ -void SCACInitCtx(MpmCtx *mpm_ctx) -{ - if (mpm_ctx->ctx != NULL) - return; - - mpm_ctx->ctx = SCCalloc(1, sizeof(SCACCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACCtx); - - /* initialize the hash we use to speed up pattern insertions */ - mpm_ctx->init_hash = SCCalloc(MPM_INIT_HASH_SIZE, sizeof(MpmPattern *)); - if (mpm_ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - - /* get conf values for AC from our yaml file. We have no conf values for - * now. We will certainly need this, as we develop the algo */ - SCACGetConfig(); - - SCReturn; -} - -/** - * \brief Destroy the mpm context. - * - * \param mpm_ctx Pointer to the mpm context. - */ -void SCACDestroyCtx(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (mpm_ctx->init_hash != NULL) { - SCFree(mpm_ctx->init_hash); - mpm_ctx->init_hash = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *)); - } - - if (ctx->parray != NULL) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - MpmFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - ctx->parray = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); - } - - if (ctx->state_table_u16 != NULL) { - SCFree(ctx->state_table_u16); - ctx->state_table_u16 = NULL; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size -= (ctx->state_count * - sizeof(SC_AC_STATE_TYPE_U16) * 256); - } - if (ctx->state_table_u32 != NULL) { - SCFree(ctx->state_table_u32); - ctx->state_table_u32 = NULL; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size -= (ctx->state_count * - sizeof(SC_AC_STATE_TYPE_U32) * 256); - } - - if (ctx->output_table != NULL) { - uint32_t state_count; - for (state_count = 0; state_count < ctx->state_count; state_count++) { - if (ctx->output_table[state_count].pids != NULL) { - SCFree(ctx->output_table[state_count].pids); - } - } - SCFree(ctx->output_table); - } - - if (ctx->pid_pat_list != NULL) { - uint32_t i; - for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) { - if (ctx->pid_pat_list[i].cs != NULL) - SCFree(ctx->pid_pat_list[i].cs); - if (ctx->pid_pat_list[i].sids != NULL) - SCFree(ctx->pid_pat_list[i].sids); - } - SCFree(ctx->pid_pat_list); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACCtx); - - return; -} - -/** - * \brief The aho corasick search function. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param pmq Pointer to the Pattern Matcher Queue to hold - * search matches. - * \param buf Buffer to be searched. - * \param buflen Buffer length. - * - * \retval matches Match count: counts unique matches per pattern. - */ -uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen) -{ - const SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - uint32_t i = 0; - int matches = 0; - - /* \todo tried loop unrolling with register var, with no perf increase. Need - * to dig deeper */ - /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ - const SCACPatternList *pid_pat_list = ctx->pid_pat_list; - - uint8_t bitarray[ctx->pattern_id_bitarray_size]; - memset(bitarray, 0, ctx->pattern_id_bitarray_size); - - if (ctx->state_count < 32767) { - register SC_AC_STATE_TYPE_U16 state = 0; - SC_AC_STATE_TYPE_U16 (*state_table_u16)[256] = ctx->state_table_u16; - for (i = 0; i < buflen; i++) { - state = state_table_u16[state & 0x7FFF][u8_tolower(buf[i])]; - if (state & 0x8000) { - uint32_t no_of_entries = ctx->output_table[state & 0x7FFF].no_of_entries; - uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; - uint32_t k; - for (k = 0; k < no_of_entries; k++) { - if (pids[k] & AC_CASE_MASK) { - uint32_t lower_pid = pids[k] & AC_PID_MASK; - const SCACPatternList *pat = &pid_pat_list[lower_pid]; - const int offset = i - pat->patlen + 1; - - if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) - continue; - - if (SCMemcmp(pat->cs, buf + offset, pat->patlen) != 0) - { - /* inside loop */ - continue; - } - if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { - ; - } else { - bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - PrefilterAddSids(pmq, pat->sids, pat->sids_size); - matches++; - } - } else { - const SCACPatternList *pat = &pid_pat_list[pids[k]]; - const int offset = i - pat->patlen + 1; - - if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) - continue; - - if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - PrefilterAddSids(pmq, pat->sids, pat->sids_size); - matches++; - } - } - //loop1: - //; - } - } - } /* for (i = 0; i < buflen; i++) */ - - } else { - register SC_AC_STATE_TYPE_U32 state = 0; - SC_AC_STATE_TYPE_U32 (*state_table_u32)[256] = ctx->state_table_u32; - for (i = 0; i < buflen; i++) { - state = state_table_u32[state & 0x00FFFFFF][u8_tolower(buf[i])]; - if (state & 0xFF000000) { - uint32_t no_of_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; - uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; - uint32_t k; - for (k = 0; k < no_of_entries; k++) { - if (pids[k] & AC_CASE_MASK) { - uint32_t lower_pid = pids[k] & 0x0000FFFF; - const SCACPatternList *pat = &pid_pat_list[lower_pid]; - const int offset = i - pat->patlen + 1; - - if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) - continue; - - if (SCMemcmp(pat->cs, buf + offset, - pat->patlen) != 0) { - /* inside loop */ - continue; - } - if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { - ; - } else { - bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - PrefilterAddSids(pmq, pat->sids, pat->sids_size); - matches++; - } - } else { - const SCACPatternList *pat = &pid_pat_list[pids[k]]; - const int offset = i - pat->patlen + 1; - - if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) - continue; - - if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - PrefilterAddSids(pmq, pat->sids, pat->sids_size); - matches++; - } - } - //loop1: - //; - } - } - } /* for (i = 0; i < buflen; i++) */ - } - - return matches; -} - -/** - * \brief Add a case insensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patnen The pattern length. - * \param offset Ignored. - * \param depth Ignored. - * \param pid The pattern id. - * \param sid Ignored. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -/** - * \brief Add a case sensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patnen The pattern length. - * \param offset Ignored. - * \param depth Ignored. - * \param pid The pattern id. - * \param sid Ignored. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCACAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -void SCACPrintInfo(MpmCtx *mpm_ctx) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - - printf("MPM AC Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeof:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" SCACCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACCtx)); - printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); - printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count); - printf("\n"); - - return; -} - - -/************************** Mpm Registration ***************************/ - -/** - * \brief Register the aho-corasick mpm. - */ -void MpmACRegister(void) -{ - mpm_table[MPM_AC].name = "ac"; - mpm_table[MPM_AC].InitCtx = SCACInitCtx; - mpm_table[MPM_AC].DestroyCtx = SCACDestroyCtx; - mpm_table[MPM_AC].AddPattern = SCACAddPatternCS; - mpm_table[MPM_AC].AddPatternNocase = SCACAddPatternCI; - mpm_table[MPM_AC].Prepare = SCACPreparePatterns; - mpm_table[MPM_AC].Search = SCACSearch; - mpm_table[MPM_AC].PrintCtx = SCACPrintInfo; - mpm_table[MPM_AC].RegisterUnittests = SCACRegisterTests; - - return; -} - -/*************************************Unittests********************************/ - -#ifdef UNITTESTS -#include "detect-engine-alert.h" - -static int SCACTest01(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest02(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest03(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest04(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest05(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest06(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcd"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest07(void) -{ - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); - /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); - /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); - /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq); - /* total matches: 135: unique matches: 6 */ - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - FAIL_IF_NOT(cnt == 6); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - PASS; -} - -static int SCACTest08(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest09(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest10(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest11(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) - goto end; - PmqSetup(&pmq); - - if (SCACPreparePatterns(&mpm_ctx) == -1) - goto end; - - result = 1; - - const char *buf = "he"; - result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "she"; - result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - buf = "his"; - result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "hers"; - result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - - end: - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest12(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest13(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest14(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest15(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest16(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABC"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABC"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest17(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzAB"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzAB"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest18(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - const char pat[] = "abcde" - "fghij" - "klmno" - "pqrst" - "uvwxy" - "z"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest19(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 */ - const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest20(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 */ - const char pat[] = "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest21(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest22(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest23(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 0) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest24(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 1 */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest25(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest26(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "works"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest27(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "tone"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest28(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCACPreparePatterns(&mpm_ctx); - - const char *buf = "tONE"; - uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACDestroyCtx(&mpm_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACTest29(void) -{ - uint8_t buf[] = "onetwothreefourfivesixseveneightnine"; - uint16_t buflen = sizeof(buf) - 1; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); - if (de_ctx->sig_list->next == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) != 1) { - printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); - goto end; - } - if (PacketAlertCheck(p, 2) != 1) { - printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); - goto end; - } - - result = 1; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - UTHFreePackets(&p, 1); - return result; -} - -#endif /* UNITTESTS */ - -void SCACRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("SCACTest01", SCACTest01); - UtRegisterTest("SCACTest02", SCACTest02); - UtRegisterTest("SCACTest03", SCACTest03); - UtRegisterTest("SCACTest04", SCACTest04); - UtRegisterTest("SCACTest05", SCACTest05); - UtRegisterTest("SCACTest06", SCACTest06); - UtRegisterTest("SCACTest07", SCACTest07); - UtRegisterTest("SCACTest08", SCACTest08); - UtRegisterTest("SCACTest09", SCACTest09); - UtRegisterTest("SCACTest10", SCACTest10); - UtRegisterTest("SCACTest11", SCACTest11); - UtRegisterTest("SCACTest12", SCACTest12); - UtRegisterTest("SCACTest13", SCACTest13); - UtRegisterTest("SCACTest14", SCACTest14); - UtRegisterTest("SCACTest15", SCACTest15); - UtRegisterTest("SCACTest16", SCACTest16); - UtRegisterTest("SCACTest17", SCACTest17); - UtRegisterTest("SCACTest18", SCACTest18); - UtRegisterTest("SCACTest19", SCACTest19); - UtRegisterTest("SCACTest20", SCACTest20); - UtRegisterTest("SCACTest21", SCACTest21); - UtRegisterTest("SCACTest22", SCACTest22); - UtRegisterTest("SCACTest23", SCACTest23); - UtRegisterTest("SCACTest24", SCACTest24); - UtRegisterTest("SCACTest25", SCACTest25); - UtRegisterTest("SCACTest26", SCACTest26); - UtRegisterTest("SCACTest27", SCACTest27); - UtRegisterTest("SCACTest28", SCACTest28); - UtRegisterTest("SCACTest29", SCACTest29); -#endif - - return; -} diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h deleted file mode 100644 index 3e8ec9db5bb2..000000000000 --- a/src/util-mpm-ac.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - */ - -#ifndef __UTIL_MPM_AC__H__ -#define __UTIL_MPM_AC__H__ - -#include "util-mpm.h" - -#define SC_AC_STATE_TYPE_U16 uint16_t -#define SC_AC_STATE_TYPE_U32 uint32_t - -typedef struct SCACPatternList_ { - uint8_t *cs; - uint16_t patlen; - - uint16_t offset; - uint16_t depth; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; -} SCACPatternList; - -typedef struct SCACOutputTable_ { - /* list of pattern sids */ - uint32_t *pids; - /* no of entries we have in pids */ - uint32_t no_of_entries; -} SCACOutputTable; - -typedef struct SCACCtx_ { - /* pattern arrays. We need this only during the goto table creation phase */ - MpmPattern **parray; - - /* no of states used by ac */ - uint32_t state_count; - - uint32_t pattern_id_bitarray_size; - - /* the all important memory hungry state_table */ - SC_AC_STATE_TYPE_U16 (*state_table_u16)[256]; - /* the all important memory hungry state_table */ - SC_AC_STATE_TYPE_U32 (*state_table_u32)[256]; - - /* goto_table, failure table and output table. Needed to create state_table. - * Will be freed, once we have created the state_table */ - int32_t (*goto_table)[256]; - int32_t *failure_table; - SCACOutputTable *output_table; - SCACPatternList *pid_pat_list; - - /* the size of each state */ - uint32_t single_state_size; - - uint32_t allocated_state_count; - -} SCACCtx; - -void MpmACRegister(void); - -#endif /* __UTIL_MPM_AC__H__ */ diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c deleted file mode 100644 index a3b896abde93..000000000000 --- a/src/util-mpm-hs.c +++ /dev/null @@ -1,2174 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Jim Xu - * \author Justin Viiret - * - * MPM pattern matcher that calls the Hyperscan regex matcher. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-build.h" - -#include "conf.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-memcmp.h" -#include "util-mpm-hs.h" -#include "util-memcpy.h" -#include "util-hash.h" -#include "util-hash-lookup3.h" -#include "util-hyperscan.h" - -#ifdef BUILD_HYPERSCAN - -#include - -void SCHSInitCtx(MpmCtx *); -void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *); -void SCHSDestroyCtx(MpmCtx *); -void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); -int SCHSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, SigIntId, uint8_t); -int SCHSPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, const uint8_t *buf, const uint32_t buflen); -void SCHSPrintInfo(MpmCtx *mpm_ctx); -void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void SCHSRegisterTests(void); - -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 - -/* Initial size of the global database hash (used for de-duplication). */ -#define INIT_DB_HASH_SIZE 1000 - -/* Global prototype scratch, built incrementally as Hyperscan databases are - * built and then cloned for each thread context. Access is serialised via - * g_scratch_proto_mutex. */ -static hs_scratch_t *g_scratch_proto = NULL; -static SCMutex g_scratch_proto_mutex = SCMUTEX_INITIALIZER; - -/* Global hash table of Hyperscan databases, used for de-duplication. Access is - * serialised via g_db_table_mutex. */ -static HashTable *g_db_table = NULL; -static SCMutex g_db_table_mutex = SCMUTEX_INITIALIZER; - -/** - * \internal - * \brief Wraps SCMalloc (which is a macro) so that it can be passed to - * hs_set_allocator() for Hyperscan's use. - */ -static void *SCHSMalloc(size_t size) -{ - return SCMalloc(size); -} - -/** - * \internal - * \brief Wraps SCFree (which is a macro) so that it can be passed to - * hs_set_allocator() for Hyperscan's use. - */ -static void SCHSFree(void *ptr) -{ - SCFree(ptr); -} - -/** \brief Register Suricata malloc/free with Hyperscan. - * - * Requests that Hyperscan use Suricata's allocator for allocation of - * databases, scratch space, etc. - */ -static void SCHSSetAllocators(void) -{ - hs_error_t err = hs_set_allocator(SCHSMalloc, SCHSFree); - if (err != HS_SUCCESS) { - FatalError("Failed to set Hyperscan allocator."); - } -} - -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCHSInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the HS ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCHSPattern *SCHSInitHashLookup(SCHSCtx *ctx, uint8_t *pat, - uint16_t patlen, uint16_t offset, - uint16_t depth, char flags, - uint32_t pid) -{ - uint32_t hash = SCHSInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - SCHSPattern *t = ctx->init_hash[hash]; - for (; t != NULL; t = t->next) { - /* Since Hyperscan uses offset/depth, we must distinguish between - * patterns with the same ID but different offset/depth here. */ - if (t->id == pid && t->offset == offset && t->depth == depth) { - BUG_ON(t->len != patlen); - BUG_ON(SCMemcmp(t->original_pat, pat, patlen) != 0); - return t; - } - } - - return NULL; -} - -/** - * \internal - * \brief Allocates a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCHSPattern *SCHSAllocPattern(MpmCtx *mpm_ctx) -{ - SCHSPattern *p = SCCalloc(1, sizeof(SCHSPattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCHSPattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCHSPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCHSPattern instance to be freed. - * \param free Free the above pointer or not. - */ -static inline void SCHSFreePattern(MpmCtx *mpm_ctx, SCHSPattern *p) -{ - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->sids != NULL) { - SCFree(p->sids); - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCHSPattern); - } -} - -static inline uint32_t SCHSInitHash(SCHSPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCHSInitHashAdd(SCHSCtx *ctx, SCHSPattern *p) -{ - uint32_t hash = SCHSInitHash(p); - - if (ctx->init_hash == NULL) { - return -1; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCHSPattern *tt = NULL; - SCHSPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-hs context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCHSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; - - if (offset != 0) { - flags |= MPM_PATTERN_FLAG_OFFSET; - } - if (depth != 0) { - flags |= MPM_PATTERN_FLAG_DEPTH; - } - - if (patlen == 0) { - SCLogWarning("pattern length 0"); - return 0; - } - - /* check if we have already inserted this pattern */ - SCHSPattern *p = - SCHSInitHashLookup(ctx, pat, patlen, offset, depth, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCHSAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->offset = offset; - p->depth = depth; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - /* put in the pattern hash */ - if (SCHSInitHashAdd(ctx, p) != 0) - goto error; - - mpm_ctx->pattern_cnt++; - - if (!(mpm_ctx->flags & MPMCTX_FLAGS_NODEPTH)) { - if (depth) { - mpm_ctx->maxdepth = MAX(mpm_ctx->maxdepth, depth); - SCLogDebug("%p: depth %u max %u", mpm_ctx, depth, mpm_ctx->maxdepth); - } else { - mpm_ctx->flags |= MPMCTX_FLAGS_NODEPTH; - mpm_ctx->maxdepth = 0; - SCLogDebug("%p: alas, no depth for us", mpm_ctx); - } - } - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - } else { - /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ - - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - } - } - - return 0; - -error: - SCHSFreePattern(mpm_ctx, p); - return -1; -} - -/** - * \brief Pattern database information used only as input to the Hyperscan - * compiler. - */ -typedef struct SCHSCompileData_ { - unsigned int *ids; - unsigned int *flags; - char **expressions; - hs_expr_ext_t **ext; - unsigned int pattern_cnt; -} SCHSCompileData; - -static SCHSCompileData *SCHSAllocCompileData(unsigned int pattern_cnt) -{ - SCHSCompileData *cd = SCCalloc(pattern_cnt, sizeof(SCHSCompileData)); - if (cd == NULL) { - goto error; - } - - cd->pattern_cnt = pattern_cnt; - - cd->ids = SCCalloc(pattern_cnt, sizeof(unsigned int)); - if (cd->ids == NULL) { - goto error; - } - - cd->flags = SCCalloc(pattern_cnt, sizeof(unsigned int)); - if (cd->flags == NULL) { - goto error; - } - - cd->expressions = SCCalloc(pattern_cnt, sizeof(char *)); - if (cd->expressions == NULL) { - goto error; - } - - cd->ext = SCCalloc(pattern_cnt, sizeof(hs_expr_ext_t *)); - if (cd->ext == NULL) { - goto error; - } - - return cd; - -error: - SCLogDebug("SCHSCompileData alloc failed"); - if (cd) { - SCFree(cd->ids); - SCFree(cd->flags); - SCFree(cd->expressions); - SCFree(cd->ext); - SCFree(cd); - } - return NULL; -} - -static void SCHSFreeCompileData(SCHSCompileData *cd) -{ - if (cd == NULL) { - return; - } - - SCFree(cd->ids); - SCFree(cd->flags); - if (cd->expressions) { - for (unsigned int i = 0; i < cd->pattern_cnt; i++) { - SCFree(cd->expressions[i]); - } - SCFree(cd->expressions); - } - if (cd->ext) { - for (unsigned int i = 0; i < cd->pattern_cnt; i++) { - SCFree(cd->ext[i]); - } - SCFree(cd->ext); - } - SCFree(cd); -} - -typedef struct PatternDatabase_ { - SCHSPattern **parray; - hs_database_t *hs_db; - uint32_t pattern_cnt; - - /* Reference count: number of MPM contexts using this pattern database. */ - uint32_t ref_cnt; -} PatternDatabase; - -static uint32_t SCHSPatternHash(const SCHSPattern *p, uint32_t hash) -{ - BUG_ON(p->original_pat == NULL); - BUG_ON(p->sids == NULL); - - hash = hashlittle_safe(&p->len, sizeof(p->len), hash); - hash = hashlittle_safe(&p->flags, sizeof(p->flags), hash); - hash = hashlittle_safe(p->original_pat, p->len, hash); - hash = hashlittle_safe(&p->id, sizeof(p->id), hash); - hash = hashlittle_safe(&p->offset, sizeof(p->offset), hash); - hash = hashlittle_safe(&p->depth, sizeof(p->depth), hash); - hash = hashlittle_safe(&p->sids_size, sizeof(p->sids_size), hash); - hash = hashlittle_safe(p->sids, p->sids_size * sizeof(SigIntId), hash); - return hash; -} - -static char SCHSPatternCompare(const SCHSPattern *p1, const SCHSPattern *p2) -{ - if ((p1->len != p2->len) || (p1->flags != p2->flags) || - (p1->id != p2->id) || (p1->offset != p2->offset) || - (p1->depth != p2->depth) || (p1->sids_size != p2->sids_size)) { - return 0; - } - - if (SCMemcmp(p1->original_pat, p2->original_pat, p1->len) != 0) { - return 0; - } - - if (SCMemcmp(p1->sids, p2->sids, p1->sids_size * sizeof(p1->sids[0])) != - 0) { - return 0; - } - - return 1; -} - -static uint32_t PatternDatabaseHash(HashTable *ht, void *data, uint16_t len) -{ - const PatternDatabase *pd = data; - uint32_t hash = 0; - hash = hashword(&pd->pattern_cnt, 1, hash); - - for (uint32_t i = 0; i < pd->pattern_cnt; i++) { - hash = SCHSPatternHash(pd->parray[i], hash); - } - - hash %= ht->array_size; - return hash; -} - -static char PatternDatabaseCompare(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - const PatternDatabase *pd1 = data1; - const PatternDatabase *pd2 = data2; - - if (pd1->pattern_cnt != pd2->pattern_cnt) { - return 0; - } - - for (uint32_t i = 0; i < pd1->pattern_cnt; i++) { - if (SCHSPatternCompare(pd1->parray[i], pd2->parray[i]) == 0) { - return 0; - } - } - - return 1; -} - -static void PatternDatabaseFree(PatternDatabase *pd) -{ - BUG_ON(pd->ref_cnt != 0); - - if (pd->parray != NULL) { - for (uint32_t i = 0; i < pd->pattern_cnt; i++) { - SCHSPattern *p = pd->parray[i]; - if (p != NULL) { - SCFree(p->original_pat); - SCFree(p->sids); - SCFree(p); - } - } - SCFree(pd->parray); - } - - hs_free_database(pd->hs_db); - - SCFree(pd); -} - -static void PatternDatabaseTableFree(void *data) -{ - /* Stub function handed to hash table; actual freeing of PatternDatabase - * structures is done in MPM destruction when the ref_cnt drops to zero. */ -} - -static PatternDatabase *PatternDatabaseAlloc(uint32_t pattern_cnt) -{ - PatternDatabase *pd = SCCalloc(1, sizeof(PatternDatabase)); - if (pd == NULL) { - return NULL; - } - pd->pattern_cnt = pattern_cnt; - pd->ref_cnt = 0; - pd->hs_db = NULL; - - /* alloc the pattern array */ - pd->parray = (SCHSPattern **)SCCalloc(pd->pattern_cnt, sizeof(SCHSPattern *)); - if (pd->parray == NULL) { - SCFree(pd); - return NULL; - } - - return pd; -} - -/** - * \brief Process the patterns added to the mpm, and create the internal tables. - * - * \param mpm_ctx Pointer to the mpm context. - */ -int SCHSPreparePatterns(MpmCtx *mpm_ctx) -{ - SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; - - if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { - SCLogDebug("no patterns supplied to this mpm_ctx"); - return 0; - } - - hs_error_t err; - hs_compile_error_t *compile_err = NULL; - SCHSCompileData *cd = NULL; - PatternDatabase *pd = NULL; - - cd = SCHSAllocCompileData(mpm_ctx->pattern_cnt); - if (cd == NULL) { - goto error; - } - - pd = PatternDatabaseAlloc(mpm_ctx->pattern_cnt); - if (pd == NULL) { - goto error; - } - - /* populate the pattern array with the patterns in the hash */ - for (uint32_t i = 0, p = 0; i < INIT_HASH_SIZE; i++) { - SCHSPattern *node = ctx->init_hash[i], *nnode = NULL; - while (node != NULL) { - nnode = node->next; - node->next = NULL; - pd->parray[p++] = node; - node = nnode; - } - } - - /* we no longer need the hash, so free its memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* Serialise whole database compilation as a relatively easy way to ensure - * dedupe is safe. */ - SCMutexLock(&g_db_table_mutex); - - /* Init global pattern database hash if necessary. */ - if (g_db_table == NULL) { - g_db_table = HashTableInit(INIT_DB_HASH_SIZE, PatternDatabaseHash, - PatternDatabaseCompare, - PatternDatabaseTableFree); - if (g_db_table == NULL) { - SCMutexUnlock(&g_db_table_mutex); - goto error; - } - } - - /* Check global hash table to see if we've seen this pattern database - * before, and reuse the Hyperscan database if so. */ - PatternDatabase *pd_cached = HashTableLookup(g_db_table, pd, 1); - - if (pd_cached != NULL) { - SCLogDebug("Reusing cached database %p with %" PRIu32 - " patterns (ref_cnt=%" PRIu32 ")", - pd_cached->hs_db, pd_cached->pattern_cnt, - pd_cached->ref_cnt); - pd_cached->ref_cnt++; - ctx->pattern_db = pd_cached; - SCMutexUnlock(&g_db_table_mutex); - PatternDatabaseFree(pd); - SCHSFreeCompileData(cd); - return 0; - } - - BUG_ON(ctx->pattern_db != NULL); /* already built? */ - - for (uint32_t i = 0; i < pd->pattern_cnt; i++) { - const SCHSPattern *p = pd->parray[i]; - - cd->ids[i] = i; - cd->flags[i] = HS_FLAG_SINGLEMATCH; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - cd->flags[i] |= HS_FLAG_CASELESS; - } - - cd->expressions[i] = HSRenderPattern(p->original_pat, p->len); - - if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) { - cd->ext[i] = SCCalloc(1, sizeof(hs_expr_ext_t)); - if (cd->ext[i] == NULL) { - SCMutexUnlock(&g_db_table_mutex); - goto error; - } - - if (p->flags & MPM_PATTERN_FLAG_OFFSET) { - cd->ext[i]->flags |= HS_EXT_FLAG_MIN_OFFSET; - cd->ext[i]->min_offset = p->offset + p->len; - } - if (p->flags & MPM_PATTERN_FLAG_DEPTH) { - cd->ext[i]->flags |= HS_EXT_FLAG_MAX_OFFSET; - cd->ext[i]->max_offset = p->offset + p->depth; - } - } - } - - BUG_ON(mpm_ctx->pattern_cnt == 0); - - err = hs_compile_ext_multi((const char *const *)cd->expressions, cd->flags, - cd->ids, (const hs_expr_ext_t *const *)cd->ext, - cd->pattern_cnt, HS_MODE_BLOCK, NULL, &pd->hs_db, - &compile_err); - - if (err != HS_SUCCESS) { - SCLogError("failed to compile hyperscan database"); - if (compile_err) { - SCLogError("compile error: %s", compile_err->message); - } - hs_free_compile_error(compile_err); - SCMutexUnlock(&g_db_table_mutex); - goto error; - } - - ctx->pattern_db = pd; - - SCMutexLock(&g_scratch_proto_mutex); - err = hs_alloc_scratch(pd->hs_db, &g_scratch_proto); - SCMutexUnlock(&g_scratch_proto_mutex); - if (err != HS_SUCCESS) { - SCLogError("failed to allocate scratch"); - SCMutexUnlock(&g_db_table_mutex); - goto error; - } - - err = hs_database_size(pd->hs_db, &ctx->hs_db_size); - if (err != HS_SUCCESS) { - SCLogError("failed to query database size"); - SCMutexUnlock(&g_db_table_mutex); - goto error; - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += ctx->hs_db_size; - - SCLogDebug("Built %" PRIu32 " patterns into a database of size %" PRIuMAX - " bytes", mpm_ctx->pattern_cnt, (uintmax_t)ctx->hs_db_size); - - /* Cache this database globally for later. */ - pd->ref_cnt = 1; - int r = HashTableAdd(g_db_table, pd, 1); - SCMutexUnlock(&g_db_table_mutex); - if (r < 0) - goto error; - - SCHSFreeCompileData(cd); - return 0; - -error: - if (pd) { - PatternDatabaseFree(pd); - } - if (cd) { - SCHSFreeCompileData(cd); - } - return -1; -} - -/** - * \brief Init the mpm thread context. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - */ -void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - SCHSThreadCtx *ctx = SCCalloc(1, sizeof(SCHSThreadCtx)); - if (ctx == NULL) { - exit(EXIT_FAILURE); - } - mpm_thread_ctx->ctx = ctx; - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(SCHSThreadCtx); - - ctx->scratch = NULL; - ctx->scratch_size = 0; - - SCMutexLock(&g_scratch_proto_mutex); - - if (g_scratch_proto == NULL) { - /* There is no scratch prototype: this means that we have not compiled - * any Hyperscan databases. */ - SCMutexUnlock(&g_scratch_proto_mutex); - SCLogDebug("No scratch space prototype"); - return; - } - - hs_error_t err = hs_clone_scratch(g_scratch_proto, - (hs_scratch_t **)&ctx->scratch); - - SCMutexUnlock(&g_scratch_proto_mutex); - - if (err != HS_SUCCESS) { - FatalError("Unable to clone scratch prototype"); - } - - err = hs_scratch_size(ctx->scratch, &ctx->scratch_size); - if (err != HS_SUCCESS) { - FatalError("Unable to query scratch size"); - } - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += ctx->scratch_size; -} - -/** - * \brief Initialize the HS context. - * - * \param mpm_ctx Mpm context. - */ -void SCHSInitCtx(MpmCtx *mpm_ctx) -{ - if (mpm_ctx->ctx != NULL) - return; - - mpm_ctx->ctx = SCCalloc(1, sizeof(SCHSCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCHSCtx); - - /* initialize the hash we use to speed up pattern insertions */ - SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; - ctx->init_hash = SCCalloc(INIT_HASH_SIZE, sizeof(SCHSPattern *)); - if (ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } -} - -/** - * \brief Destroy the mpm thread context. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - */ -void SCHSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - SCHSPrintSearchStats(mpm_thread_ctx); - - if (mpm_thread_ctx->ctx != NULL) { - SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx; - - if (thr_ctx->scratch != NULL) { - hs_free_scratch(thr_ctx->scratch); - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= thr_ctx->scratch_size; - } - - SCFree(mpm_thread_ctx->ctx); - mpm_thread_ctx->ctx = NULL; - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(SCHSThreadCtx); - } -} - -/** - * \brief Destroy the mpm context. - * - * \param mpm_ctx Pointer to the mpm context. - */ -void SCHSDestroyCtx(MpmCtx *mpm_ctx) -{ - SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCHSPattern *)); - } - - /* Decrement pattern database ref count, and delete it entirely if the - * count has dropped to zero. */ - SCMutexLock(&g_db_table_mutex); - PatternDatabase *pd = ctx->pattern_db; - if (pd) { - BUG_ON(pd->ref_cnt == 0); - pd->ref_cnt--; - if (pd->ref_cnt == 0) { - HashTableRemove(g_db_table, pd, 1); - PatternDatabaseFree(pd); - } - } - SCMutexUnlock(&g_db_table_mutex); - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCHSCtx); -} - -typedef struct SCHSCallbackCtx_ { - SCHSCtx *ctx; - void *pmq; - uint32_t match_count; -} SCHSCallbackCtx; - -/* Hyperscan MPM match event handler */ -static int SCHSMatchEvent(unsigned int id, unsigned long long from, - unsigned long long to, unsigned int flags, - void *ctx) -{ - SCHSCallbackCtx *cctx = ctx; - PrefilterRuleStore *pmq = cctx->pmq; - const PatternDatabase *pd = cctx->ctx->pattern_db; - const SCHSPattern *pat = pd->parray[id]; - - SCLogDebug("Hyperscan Match %" PRIu32 ": id=%" PRIu32 " @ %" PRIuMAX - " (pat id=%" PRIu32 ")", - cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id); - - PrefilterAddSids(pmq, pat->sids, pat->sids_size); - - cctx->match_count++; - return 0; -} - -/** - * \brief The Hyperscan search function. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param pmq Pointer to the Pattern Matcher Queue to hold - * search matches. - * \param buf Buffer to be searched. - * \param buflen Buffer length. - * - * \retval matches Match count. - */ -uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PrefilterRuleStore *pmq, const uint8_t *buf, const uint32_t buflen) -{ - uint32_t ret = 0; - SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; - SCHSThreadCtx *hs_thread_ctx = (SCHSThreadCtx *)(mpm_thread_ctx->ctx); - const PatternDatabase *pd = ctx->pattern_db; - - if (unlikely(buflen == 0)) { - return 0; - } - - SCHSCallbackCtx cctx = {.ctx = ctx, .pmq = pmq, .match_count = 0}; - - /* scratch should have been cloned from g_scratch_proto at thread init. */ - hs_scratch_t *scratch = hs_thread_ctx->scratch; - BUG_ON(pd->hs_db == NULL); - BUG_ON(scratch == NULL); - - hs_error_t err = hs_scan(pd->hs_db, (const char *)buf, buflen, 0, scratch, - SCHSMatchEvent, &cctx); - if (err != HS_SUCCESS) { - /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() - * indicates that it was passed an invalid database or scratch region, - * which is not something we can recover from at scan time. */ - SCLogError("Hyperscan returned error %d", err); - exit(EXIT_FAILURE); - } else { - ret = cctx.match_count; - } - - return ret; -} - -/** - * \brief Add a case insensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patlen The pattern length. - * \param offset The pattern offset. - * \param depth The pattern depth. - * \param pid The pattern id. - * \param sid The pattern signature id. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCHSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -/** - * \brief Add a case sensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patlen The pattern length. - * \param offset The pattern offset. - * \param depth The pattern depth. - * \param pid The pattern id. - * \param sid The pattern signature id. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCHSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ - return; -} - -void SCHSPrintInfo(MpmCtx *mpm_ctx) -{ - SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; - - printf("MPM HS Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeof:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" SCHSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSCtx)); - printf(" SCHSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("\n"); - - if (ctx) { - PatternDatabase *pd = ctx->pattern_db; - char *db_info = NULL; - if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) { - printf("HS Database Info: %s\n", db_info); - SCFree(db_info); - } - printf("HS Database Size: %" PRIuMAX " bytes\n", - (uintmax_t)ctx->hs_db_size); - } - - printf("\n"); -} - -/************************** Mpm Registration ***************************/ - -/** - * \brief Register the Hyperscan MPM. - */ -void MpmHSRegister(void) -{ - mpm_table[MPM_HS].name = "hs"; - mpm_table[MPM_HS].InitCtx = SCHSInitCtx; - mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx; - mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx; - mpm_table[MPM_HS].DestroyThreadCtx = SCHSDestroyThreadCtx; - mpm_table[MPM_HS].AddPattern = SCHSAddPatternCS; - mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI; - mpm_table[MPM_HS].Prepare = SCHSPreparePatterns; - mpm_table[MPM_HS].Search = SCHSSearch; - mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo; - mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats; - mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests; - - /* Set Hyperscan memory allocators */ - SCHSSetAllocators(); -} - -/** - * \brief Clean up global memory used by all Hyperscan MPM instances. - * - * Currently, this is just the global scratch prototype. - */ -void MpmHSGlobalCleanup(void) -{ - SCMutexLock(&g_scratch_proto_mutex); - if (g_scratch_proto) { - SCLogDebug("Cleaning up Hyperscan global scratch"); - hs_free_scratch(g_scratch_proto); - g_scratch_proto = NULL; - } - SCMutexUnlock(&g_scratch_proto_mutex); - - SCMutexLock(&g_db_table_mutex); - if (g_db_table != NULL) { - SCLogDebug("Clearing Hyperscan database cache"); - HashTableFree(g_db_table); - g_db_table = NULL; - } - SCMutexUnlock(&g_db_table_mutex); -} - -/*************************************Unittests********************************/ - -#ifdef UNITTESTS -#include "detect-engine-alert.h" - -static int SCHSTest01(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest02(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest03(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest04(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest05(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest06(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcd"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest07(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); - /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); - /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); - /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, - 0, 0, 5, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 6) - result = 1; - else - printf("6 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest08(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - uint32_t cnt = - SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest09(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - uint32_t cnt = - SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest10(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest11(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) - goto end; - PmqSetup(&pmq); - - if (SCHSPreparePatterns(&mpm_ctx) == -1) - goto end; - - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - result = 1; - - const char *buf = "he"; - result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "she"; - result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - buf = "his"; - result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "hers"; - result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - -end: - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest12(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest13(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest14(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest15(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest16(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzABC"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzABC"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest17(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - const char pat[] = "abcdefghijklmnopqrstuvwxyzAB"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyzAB"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest18(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - const char pat[] = "abcde" - "fghij" - "klmno" - "pqrst" - "uvwxy" - "z"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcde" - "fghij" - "klmno" - "pqrst" - "uvwxy" - "z"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest19(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 */ - const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest20(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 */ - const char pat[] = "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AAAAA" - "AA"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest21(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - uint32_t cnt = - SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest22(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest23(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - uint32_t cnt = - SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); - - if (cnt == 0) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest24(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 1 */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - uint32_t cnt = - SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest25(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest26(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "works"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("3 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest27(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "tone"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest28(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PrefilterRuleStore pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_HS); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq); - - SCHSPreparePatterns(&mpm_ctx); - SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); - - const char *buf = "tONE"; - uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ", cnt); - - SCHSDestroyCtx(&mpm_ctx); - SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCHSTest29(void) -{ - uint8_t buf[] = "onetwothreefourfivesixseveneightnine"; - uint16_t buflen = sizeof(buf) - 1; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->mpm_matcher = MPM_HS; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit( - de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - de_ctx->sig_list->next = - SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; " - "fast_pattern:3,3; sid:2;)"); - if (de_ctx->sig_list->next == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) != 1) { - printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); - goto end; - } - if (PacketAlertCheck(p, 2) != 1) { - printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); - goto end; - } - - result = 1; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - UTHFreePackets(&p, 1); - return result; -} - -#endif /* UNITTESTS */ - -void SCHSRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SCHSTest01", SCHSTest01); - UtRegisterTest("SCHSTest02", SCHSTest02); - UtRegisterTest("SCHSTest03", SCHSTest03); - UtRegisterTest("SCHSTest04", SCHSTest04); - UtRegisterTest("SCHSTest05", SCHSTest05); - UtRegisterTest("SCHSTest06", SCHSTest06); - UtRegisterTest("SCHSTest07", SCHSTest07); - UtRegisterTest("SCHSTest08", SCHSTest08); - UtRegisterTest("SCHSTest09", SCHSTest09); - UtRegisterTest("SCHSTest10", SCHSTest10); - UtRegisterTest("SCHSTest11", SCHSTest11); - UtRegisterTest("SCHSTest12", SCHSTest12); - UtRegisterTest("SCHSTest13", SCHSTest13); - UtRegisterTest("SCHSTest14", SCHSTest14); - UtRegisterTest("SCHSTest15", SCHSTest15); - UtRegisterTest("SCHSTest16", SCHSTest16); - UtRegisterTest("SCHSTest17", SCHSTest17); - UtRegisterTest("SCHSTest18", SCHSTest18); - UtRegisterTest("SCHSTest19", SCHSTest19); - UtRegisterTest("SCHSTest20", SCHSTest20); - UtRegisterTest("SCHSTest21", SCHSTest21); - UtRegisterTest("SCHSTest22", SCHSTest22); - UtRegisterTest("SCHSTest23", SCHSTest23); - UtRegisterTest("SCHSTest24", SCHSTest24); - UtRegisterTest("SCHSTest25", SCHSTest25); - UtRegisterTest("SCHSTest26", SCHSTest26); - UtRegisterTest("SCHSTest27", SCHSTest27); - UtRegisterTest("SCHSTest28", SCHSTest28); - UtRegisterTest("SCHSTest29", SCHSTest29); -#endif - - return; -} - -#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-mpm.c b/src/util-mpm.c deleted file mode 100644 index 23ff23082885..000000000000 --- a/src/util-mpm.c +++ /dev/null @@ -1,598 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Pattern matcher utility Functions - */ - -#include "suricata-common.h" -#include "util-mpm.h" -#include "util-debug.h" - -/* include pattern matchers */ -#include "util-mpm-ac.h" -#include "util-mpm-ac-ks.h" -#include "util-mpm-hs.h" -#include "util-hashlist.h" - -#include "detect-engine.h" -#include "util-misc.h" -#include "conf.h" -#include "conf-yaml-loader.h" -#include "queue.h" -#include "util-unittest.h" -#include "util-memcpy.h" -#ifdef BUILD_HYPERSCAN -#include "hs.h" -#endif - -MpmTableElmt mpm_table[MPM_TABLE_SIZE]; -uint8_t mpm_default_matcher; - -/** - * \brief Register a new Mpm Context. - * - * \param name A new profile to be registered to store this MpmCtx. - * \param sm_list sm_list for this name (might be variable with xforms) - * \param alproto app proto or ALPROTO_UNKNOWN if not for app-layer - * - * \retval id Return the id created for the new MpmCtx profile. - */ -int32_t MpmFactoryRegisterMpmCtxProfile( - DetectEngineCtx *de_ctx, const char *name, const int sm_list, const AppProto alproto) -{ - /* the very first entry */ - if (de_ctx->mpm_ctx_factory_container == NULL) { - de_ctx->mpm_ctx_factory_container = SCCalloc(1, sizeof(MpmCtxFactoryContainer)); - if (de_ctx->mpm_ctx_factory_container == NULL) { - FatalError("Error allocating memory"); - } - de_ctx->mpm_ctx_factory_container->max_id = ENGINE_SGH_MPM_FACTORY_CONTEXT_START_ID_RANGE; - } - - MpmCtxFactoryItem *item = de_ctx->mpm_ctx_factory_container->items; - MpmCtxFactoryItem *pitem = NULL; - while (item) { - if (item->sm_list == sm_list && item->alproto == alproto && item->name != NULL && - strcmp(item->name, name) == 0) { - return item->id; - } - pitem = item; - item = item->next; - } - - MpmCtxFactoryItem *nitem = SCCalloc(1, sizeof(MpmCtxFactoryItem)); - if (unlikely(nitem == NULL)) { - FatalError("Error allocating memory"); - } - nitem->name = name; - nitem->sm_list = sm_list; - nitem->id = de_ctx->mpm_ctx_factory_container->max_id++; - nitem->alproto = alproto; - - /* toserver */ - nitem->mpm_ctx_ts = SCCalloc(1, sizeof(MpmCtx)); - if (nitem->mpm_ctx_ts == NULL) { - FatalError("Error allocating memory"); - } - nitem->mpm_ctx_ts->flags |= MPMCTX_FLAGS_GLOBAL; - - /* toclient */ - nitem->mpm_ctx_tc = SCCalloc(1, sizeof(MpmCtx)); - if (nitem->mpm_ctx_tc == NULL) { - FatalError("Error allocating memory"); - } - nitem->mpm_ctx_tc->flags |= MPMCTX_FLAGS_GLOBAL; - - /* store the newly created item */ - if (pitem == NULL) - de_ctx->mpm_ctx_factory_container->items = nitem; - else - pitem->next = nitem; - - de_ctx->mpm_ctx_factory_container->no_of_items++; - return nitem->id; -} - -int32_t MpmFactoryIsMpmCtxAvailable(const DetectEngineCtx *de_ctx, const MpmCtx *mpm_ctx) -{ - if (mpm_ctx == NULL) - return 0; - - if (de_ctx->mpm_ctx_factory_container == NULL) { - return 0; - } - - for (MpmCtxFactoryItem *i = de_ctx->mpm_ctx_factory_container->items; i != NULL; i = i->next) { - if (mpm_ctx == i->mpm_ctx_ts || mpm_ctx == i->mpm_ctx_tc) { - return 1; - } - } - return 0; -} - -MpmCtx *MpmFactoryGetMpmCtxForProfile(const DetectEngineCtx *de_ctx, int32_t id, int direction) -{ - if (id == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { - MpmCtx *mpm_ctx = SCCalloc(1, sizeof(MpmCtx)); - if (unlikely(mpm_ctx == NULL)) { - FatalError("Error allocating memory"); - } - return mpm_ctx; - } else if (id < -1) { - SCLogError("Invalid argument - %d\n", id); - return NULL; - } else if (id >= de_ctx->mpm_ctx_factory_container->max_id) { - /* this id does not exist */ - return NULL; - } else { - for (MpmCtxFactoryItem *i = de_ctx->mpm_ctx_factory_container->items; i != NULL; - i = i->next) { - if (id == i->id) { - return (direction == 0) ? i->mpm_ctx_ts : i->mpm_ctx_tc; - } - } - return NULL; - } -} - -void MpmFactoryReClaimMpmCtx(const DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) -{ - if (mpm_ctx == NULL) - return; - - if (!MpmFactoryIsMpmCtxAvailable(de_ctx, mpm_ctx)) { - if (mpm_ctx->mpm_type != MPM_NOTSET) - mpm_table[mpm_ctx->mpm_type].DestroyCtx(mpm_ctx); - SCFree(mpm_ctx); - } -} - -void MpmFactoryDeRegisterAllMpmCtxProfiles(DetectEngineCtx *de_ctx) -{ - if (de_ctx->mpm_ctx_factory_container == NULL) - return; - - MpmCtxFactoryItem *item = de_ctx->mpm_ctx_factory_container->items; - while (item) { - if (item->mpm_ctx_ts != NULL) { - if (item->mpm_ctx_ts->mpm_type != MPM_NOTSET) - mpm_table[item->mpm_ctx_ts->mpm_type].DestroyCtx(item->mpm_ctx_ts); - SCFree(item->mpm_ctx_ts); - } - if (item->mpm_ctx_tc != NULL) { - if (item->mpm_ctx_tc->mpm_type != MPM_NOTSET) - mpm_table[item->mpm_ctx_tc->mpm_type].DestroyCtx(item->mpm_ctx_tc); - SCFree(item->mpm_ctx_tc); - } - - MpmCtxFactoryItem *next = item->next; - SCFree(item); - item = next; - } - - SCFree(de_ctx->mpm_ctx_factory_container); - de_ctx->mpm_ctx_factory_container = NULL; -} - -void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher) -{ - if (mpm_table[matcher].InitThreadCtx != NULL) { - mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx); - } -} - -void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher) -{ - if (mpm_table[matcher].DestroyThreadCtx != NULL) { - mpm_table[matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); - } -} - -void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher) -{ - mpm_ctx->mpm_type = matcher; - mpm_table[matcher].InitCtx(mpm_ctx); -} - -/* MPM matcher to use by default, i.e. when "mpm-algo" is set to "auto". - * If Hyperscan is available, use it. Otherwise, use AC. */ -#ifdef BUILD_HYPERSCAN -# define DEFAULT_MPM MPM_HS -# define DEFAULT_MPM_AC MPM_AC -#else -# define DEFAULT_MPM MPM_AC -#endif - -void MpmTableSetup(void) -{ - memset(mpm_table, 0, sizeof(mpm_table)); - mpm_default_matcher = DEFAULT_MPM; - - MpmACRegister(); - MpmACTileRegister(); -#ifdef BUILD_HYPERSCAN - #ifdef HAVE_HS_VALID_PLATFORM - /* Enable runtime check for SSSE3. Do not use Hyperscan MPM matcher if - * check is not successful. */ - if (hs_valid_platform() != HS_SUCCESS) { - SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " - "MPM"); - /* Fall back to best Aho-Corasick variant. */ - mpm_default_matcher = DEFAULT_MPM_AC; - } else { - MpmHSRegister(); - } - #else - MpmHSRegister(); - #endif /* HAVE_HS_VALID_PLATFORM */ -#endif /* BUILD_HYPERSCAN */ -} - -int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, - uint32_t pid, SigIntId sid, uint8_t flags) -{ - return mpm_table[mpm_ctx->mpm_type].AddPattern(mpm_ctx, pat, patlen, - offset, depth, - pid, sid, flags); -} - -int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, - uint32_t pid, SigIntId sid, uint8_t flags) -{ - return mpm_table[mpm_ctx->mpm_type].AddPatternNocase(mpm_ctx, pat, patlen, - offset, depth, - pid, sid, flags); -} - - -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t MpmInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % MPM_INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline MpmPattern *MpmInitHashLookup(MpmCtx *ctx, - uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, - uint8_t flags, uint32_t pid) -{ - uint32_t hash = MpmInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - MpmPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (!(flags & MPM_PATTERN_CTX_OWNS_ID)) { - if (t->id == pid) - return t; - } else { - if (t->len == patlen && t->offset == offset && t->depth == depth && - memcmp(pat, t->original_pat, patlen) == 0 && - t->flags == flags) - { - return t; - } - } - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline MpmPattern *MpmAllocPattern(MpmCtx *mpm_ctx) -{ - MpmPattern *p = SCCalloc(1, sizeof(MpmPattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(MpmPattern); - - return p; -} - -/** - * \internal - * \brief Used to free MpmPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the MpmPattern instance to be freed. - */ -void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p) -{ - if (p == NULL) - return; - - if (p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p->sids != NULL) { - SCFree(p->sids); - } - - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(MpmPattern); -} - -static inline uint32_t MpmInitHash(MpmPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % MPM_INIT_HASH_SIZE); -} - -static inline int MpmInitHashAdd(MpmCtx *ctx, MpmPattern *p) -{ - uint32_t hash = MpmInitHash(p); - - if (ctx->init_hash == NULL) { - return -1; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - MpmPattern *tt = NULL; - MpmPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags) -{ - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - mpm_ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning("pattern length 0"); - return 0; - } - - if (flags & MPM_PATTERN_CTX_OWNS_ID) - pid = UINT_MAX; - - /* check if we have already inserted this pattern */ - MpmPattern *p = MpmInitHashLookup(mpm_ctx, pat, patlen, - offset, depth, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = MpmAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->offset = offset; - p->depth = depth; - if (flags & MPM_PATTERN_CTX_OWNS_ID) - p->id = mpm_ctx->max_pat_id++; - else - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - if (MpmInitHashAdd(mpm_ctx, p) != 0) - goto error; - - mpm_ctx->pattern_cnt++; - - if (!(mpm_ctx->flags & MPMCTX_FLAGS_NODEPTH)) { - if (depth) { - mpm_ctx->maxdepth = MAX(mpm_ctx->maxdepth, depth); - SCLogDebug("%p: depth %u max %u", mpm_ctx, depth, mpm_ctx->maxdepth); - } else { - mpm_ctx->flags |= MPMCTX_FLAGS_NODEPTH; - mpm_ctx->maxdepth = 0; - SCLogDebug("%p: alas, no depth for us", mpm_ctx); - } - } - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (p->id > mpm_ctx->max_pat_id) - mpm_ctx->max_pat_id = p->id; - - p->sids_size = 1; - p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); - BUG_ON(p->sids == NULL); - p->sids[0] = sid; - } else { - /* we can be called multiple times for the same sid in the case - * of the 'single' modus. Here multiple rule groups share the - * same mpm ctx and might be adding the same pattern to the - * mpm_ctx */ - int found = 0; - uint32_t x = 0; - for (x = 0; x < p->sids_size; x++) { - if (p->sids[x] == sid) { - found = 1; - break; - } - } - - if (!found) { - SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); - BUG_ON(sids == NULL); - p->sids = sids; - p->sids[p->sids_size] = sid; - p->sids_size++; - } - } - - return 0; - -error: - MpmFreePattern(mpm_ctx, p); - return -1; -} - - -/************************************Unittests*********************************/ - -#ifdef UNITTESTS -#endif /* UNITTESTS */ - -void MpmRegisterTests(void) -{ -#ifdef UNITTESTS - uint16_t i; - - for (i = 0; i < MPM_TABLE_SIZE; i++) { - if (i == MPM_NOTSET) - continue; - - g_ut_modules++; - - if (mpm_table[i].RegisterUnittests != NULL) { - g_ut_covered++; - mpm_table[i].RegisterUnittests(); - } else { - if (coverage_unittests) - SCLogWarning("mpm module %s has no " - "unittest registration function.", - mpm_table[i].name); - } - } - -#endif -} diff --git a/src/util-mpm.h b/src/util-mpm.h deleted file mode 100644 index d3ac12bdec89..000000000000 --- a/src/util-mpm.h +++ /dev/null @@ -1,202 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_MPM_H__ -#define __UTIL_MPM_H__ - -#include "app-layer-protos.h" -#include "util-prefilter.h" - -#define MPM_INIT_HASH_SIZE 65536 - -enum { - MPM_NOTSET = 0, - - /* aho-corasick */ - MPM_AC, - MPM_AC_KS, - MPM_HS, - /* table size */ - MPM_TABLE_SIZE, -}; - -/* Internal Pattern Index: 0 to pattern_cnt-1 */ -typedef uint32_t MpmPatternIndex; - -typedef struct MpmThreadCtx_ { - void *ctx; - - uint32_t memory_cnt; - uint32_t memory_size; - -} MpmThreadCtx; - -typedef struct MpmPattern_ { - /* length of the pattern */ - uint16_t len; - /* flags describing the pattern */ - uint8_t flags; - - /* offset into the buffer where match may start */ - uint16_t offset; - - /* offset into the buffer before which match much complete */ - uint16_t depth; - - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case insensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - /* sid(s) for this pattern */ - uint32_t sids_size; - SigIntId *sids; - - struct MpmPattern_ *next; -} MpmPattern; - -/* Indicates if this a global mpm_ctx. Global mpm_ctx is the one that - * is instantiated when we use "single". Non-global is "full", i.e. - * one per sgh. */ -#define MPMCTX_FLAGS_GLOBAL BIT_U8(0) -#define MPMCTX_FLAGS_NODEPTH BIT_U8(1) - -typedef struct MpmCtx_ { - void *ctx; - uint8_t mpm_type; - - uint8_t flags; - - uint16_t maxdepth; - - /* unique patterns */ - uint32_t pattern_cnt; - - uint16_t minlen; - uint16_t maxlen; - - uint32_t memory_cnt; - uint32_t memory_size; - - uint32_t max_pat_id; - - /* hash used during ctx initialization */ - MpmPattern **init_hash; -} MpmCtx; - -/* if we want to retrieve an unique mpm context from the mpm context factory - * we should supply this as the key */ -#define MPM_CTX_FACTORY_UNIQUE_CONTEXT -1 - -typedef struct MpmCtxFactoryItem { - const char *name; - MpmCtx *mpm_ctx_ts; - MpmCtx *mpm_ctx_tc; - int32_t id; - int32_t sm_list; - AppProto alproto; /**< ALPROTO_UNKNOWN is not an app item */ - struct MpmCtxFactoryItem *next; -} MpmCtxFactoryItem; - -typedef struct MpmCtxFactoryContainer_ { - MpmCtxFactoryItem *items; - int32_t no_of_items; - int32_t max_id; -} MpmCtxFactoryContainer; - -/** pattern is case insensitive */ -#define MPM_PATTERN_FLAG_NOCASE 0x01 -/** pattern has a depth setting */ -#define MPM_PATTERN_FLAG_DEPTH 0x04 -/** pattern has an offset setting */ -#define MPM_PATTERN_FLAG_OFFSET 0x08 -/** the ctx uses it's own internal id instead of - * what is passed through the API */ -#define MPM_PATTERN_CTX_OWNS_ID 0x20 - -typedef struct MpmTableElmt_ { - const char *name; - void (*InitCtx)(struct MpmCtx_ *); - void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); - void (*DestroyCtx)(struct MpmCtx_ *); - void (*DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); - - /** function pointers for adding patterns to the mpm ctx. - * - * \param mpm_ctx Mpm context to add the pattern to - * \param pattern pointer to the pattern - * \param pattern_len length of the pattern in bytes - * \param offset pattern offset setting - * \param depth pattern depth setting - * \param pid pattern id - * \param sid signature _internal_ id - * \param flags pattern flags - */ - int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); - int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); - int (*Prepare)(struct MpmCtx_ *); - /** \retval cnt number of patterns that matches: once per pattern max. */ - uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t); - void (*PrintCtx)(struct MpmCtx_ *); - void (*PrintThreadCtx)(struct MpmThreadCtx_ *); - void (*RegisterUnittests)(void); - uint8_t flags; -} MpmTableElmt; - -extern MpmTableElmt mpm_table[MPM_TABLE_SIZE]; -extern uint8_t mpm_default_matcher; - -struct DetectEngineCtx_; - -int32_t MpmFactoryRegisterMpmCtxProfile( - struct DetectEngineCtx_ *, const char *, const int, const AppProto); -void MpmFactoryReClaimMpmCtx(const struct DetectEngineCtx_ *, MpmCtx *); -MpmCtx *MpmFactoryGetMpmCtxForProfile(const struct DetectEngineCtx_ *, int32_t, int); -void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); -int32_t MpmFactoryIsMpmCtxAvailable(const struct DetectEngineCtx_ *, const MpmCtx *); - -void MpmTableSetup(void); -void MpmRegisterTests(void); - -void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher); -void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t); -void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher); - -int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, - uint32_t pid, SigIntId sid, uint8_t flags); -int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, - uint32_t pid, SigIntId sid, uint8_t flags); - -void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p); - -int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - SigIntId sid, uint8_t flags); - -#endif /* __UTIL_MPM_H__ */ diff --git a/src/util-napatech.c b/src/util-napatech.c deleted file mode 100644 index affcd49cbb87..000000000000 --- a/src/util-napatech.c +++ /dev/null @@ -1,1863 +0,0 @@ -/* Copyright (C) 2017-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -/** - * \file - * - * \author Napatech Inc. - * \author Phil Young - * - * - */ -#include "suricata-common.h" - -#ifdef HAVE_NAPATECH -#include "suricata.h" -#include "util-device.h" -#include "util-cpu.h" -#include "util-byte.h" -#include "threadvars.h" -#include "tm-threads.h" -#include "util-napatech.h" -#include "source-napatech.h" -#include "runmode-napatech.h" - -#ifdef NAPATECH_ENABLE_BYPASS - -/* - * counters to track the number of flows programmed on - * the adapter. - */ -typedef struct FlowStatsCounters_ -{ - uint16_t active_bypass_flows; - uint16_t total_bypass_flows; -} FlowStatsCounters; - - -static int bypass_supported; -int NapatechIsBypassSupported(void) -{ - return bypass_supported; -} - -/** - * \brief Returns the number of Napatech Adapters in the system. - * - * \return count of the Napatech adapters present in the system. - */ -int NapatechGetNumAdapters(void) -{ - NtInfoStream_t hInfo; - NtInfo_t hInfoSys; - int status; - static int num_adapters = -1; - - if (num_adapters == -1) { - if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - hInfoSys.cmd = NT_INFO_CMD_READ_SYSTEM; - if ((status = NT_InfoRead(hInfo, &hInfoSys)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - num_adapters = hInfoSys.u.system.data.numAdapters; - - NT_InfoClose(hInfo); - } - - return num_adapters; -} - -/** - * \brief Verifies that the Napatech adapters support bypass. - * - * Attempts to opens a FlowStream on each adapter present in the system. - * If successful then bypass is supported - * - * \return 1 if Bypass functionality is supported; zero otherwise. - */ -int NapatechVerifyBypassSupport(void) -{ - int status; - int adapter = 0; - int num_adapters = NapatechGetNumAdapters(); - SCLogInfo("Found %d Napatech adapters.", num_adapters); - NtFlowStream_t hFlowStream; - - if (!NapatechUseHWBypass()) { - /* HW Bypass is disabled in the conf file */ - return 0; - } - - for (adapter = 0; adapter < num_adapters; ++adapter) { - NtFlowAttr_t attr; - char flow_name[80]; - - NT_FlowOpenAttrInit(&attr); - NT_FlowOpenAttrSetAdapterNo(&attr, adapter); - - snprintf(flow_name, sizeof(flow_name), "Flow stream %d", adapter ); - SCLogInfo("Opening flow programming stream: %s\n", flow_name); - if ((status = NT_FlowOpen_Attr(&hFlowStream, flow_name, &attr)) != NT_SUCCESS) { - SCLogWarning("Napatech bypass functionality not supported by the FPGA version on " - "adapter %d - disabling support.", - adapter); - bypass_supported = 0; - return 0; - } - NT_FlowClose(hFlowStream); - } - - bypass_supported = 1; - return bypass_supported; -} - - -/** - * \brief Updates statistic counters for Napatech FlowStats - * - * \param tv Thread variable to ThreadVars - * \param hInfo Handle to the Napatech InfoStream. - * \param hstat_stream Handle to the Napatech Statistics Stream. - * \param flow_counters The flow counters statistics to update. - * \param clear_stats Indicates if statistics on the card should be reset to zero. - * - */ -static void UpdateFlowStats( - ThreadVars *tv, - NtInfoStream_t hInfo, - NtStatStream_t hstat_stream, - FlowStatsCounters flow_counters, - int clear_stats - ) -{ - NtStatistics_t hStat; - int status; - - uint64_t programed = 0; - uint64_t removed = 0; - int adapter = 0; - - for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) { - hStat.cmd = NT_STATISTICS_READ_CMD_FLOW_V0; - hStat.u.flowData_v0.clear = clear_stats; - hStat.u.flowData_v0.adapterNo = adapter; - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(1); - } - programed = hStat.u.flowData_v0.learnDone; - removed = hStat.u.flowData_v0.unlearnDone - + hStat.u.flowData_v0.automaticUnlearnDone - + hStat.u.flowData_v0.timeoutUnlearnDone; - } - - StatsSetUI64(tv, flow_counters.active_bypass_flows, programed - removed); - StatsSetUI64(tv, flow_counters.total_bypass_flows, programed); -} - -#endif /* NAPATECH_ENABLE_BYPASS */ - - -/*----------------------------------------------------------------------------- - *----------------------------------------------------------------------------- - * Statistics code - *----------------------------------------------------------------------------- - */ -typedef struct PacketCounters_ -{ - uint16_t pkts; - uint16_t byte; - uint16_t drop_pkts; - uint16_t drop_byte; -} PacketCounters; - -NapatechCurrentStats total_stats; -NapatechCurrentStats current_stats[MAX_STREAMS]; - -NapatechCurrentStats NapatechGetCurrentStats(uint16_t id) -{ - - return current_stats[id]; -} - -enum CONFIG_SPECIFIER { - CONFIG_SPECIFIER_UNDEFINED = 0, - CONFIG_SPECIFIER_RANGE, - CONFIG_SPECIFIER_INDIVIDUAL -}; - -#define MAX_HOSTBUFFERS 8 - -/** - * \brief Test to see if any of the configured streams are active - * - * \param hInfo Handle to Napatech Info Stream. - * \param hStatsStream Handle to Napatech Statistics stream - * \param stream_config array of stream configuration structures - * \param num_inst - * - */ -static uint16_t TestStreamConfig( - NtInfoStream_t hInfo, - NtStatStream_t hstat_stream, - NapatechStreamConfig stream_config[], - uint16_t num_inst) -{ - uint16_t num_active = 0; - - for (uint16_t inst = 0; inst < num_inst; ++inst) { - int status; - NtStatistics_t stat; // Stat handle. - - /* Check to see if it is an active stream */ - memset(&stat, 0, sizeof (NtStatistics_t)); - - /* Read usage data for the chosen stream ID */ - stat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; - stat.u.usageData_v0.streamid = (uint8_t) stream_config[inst].stream_id; - - if ((status = NT_StatRead(hstat_stream, &stat)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return 0; - } - - if (stat.u.usageData_v0.data.numHostBufferUsed > 0) { - stream_config[inst].is_active = true; - num_active++; - } else { - stream_config[inst].is_active = false; - } - } - - return num_active; -} - -/** - * \brief Updates Napatech packet counters - * - * \param tv Pointer to ThreadVars structure - * \param hInfo Handle to Napatech Info Stream. - * \param hstat_stream Handle to Napatech Statistics stream - * \param num_streams the number of streams that are currently active - * \param stream_config array of stream configuration structures - * \param total_counters - cumulative count of all packets received. - * \param dispatch_host, - Count of packets that were delivered to the host buffer - * \param dispatch_drop - count of packets that were dropped as a result of a rule - * \param dispatch_fwd - count of packets forwarded out the egress port as the result of a rule - * \param is_inline - are we running in inline mode? - * \param enable_stream_stats - are per thread/stream statistics enabled. - * \param stream_counters - counters for each thread/stream configured. - * - * \return The number of active streams that were updated. - * - */ -static uint32_t UpdateStreamStats(ThreadVars *tv, - NtInfoStream_t hInfo, - NtStatStream_t hstat_stream, - uint16_t num_streams, - NapatechStreamConfig stream_config[], - PacketCounters total_counters, - PacketCounters dispatch_host, - PacketCounters dispatch_drop, - PacketCounters dispatch_fwd, - int is_inline, - int enable_stream_stats, - PacketCounters stream_counters[] - ) { - static uint64_t rxPktsStart[MAX_STREAMS] = {0}; - static uint64_t rxByteStart[MAX_STREAMS] = {0}; - static uint64_t dropPktStart[MAX_STREAMS] = {0}; - static uint64_t dropByteStart[MAX_STREAMS] = {0}; - - int status; - NtInfo_t hStreamInfo; - NtStatistics_t hStat; // Stat handle. - - /* Query the system to get the number of streams currently instantiated */ - hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM; - if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - uint16_t num_active; - if ((num_active = TestStreamConfig(hInfo, hstat_stream, stream_config, num_streams)) == 0) { - /* None of the configured streams are active */ - return 0; - } - - /* At least one stream is active so proceed with the stats. */ - uint16_t inst_id = 0; - uint32_t stream_cnt = 0; - for (stream_cnt = 0; stream_cnt < num_streams; ++stream_cnt) { - while (inst_id < num_streams) { - if (stream_config[inst_id].is_active) { - break; - } else { - ++inst_id; - } - } - if (inst_id == num_streams) - break; - - /* Read usage data for the chosen stream ID */ - memset(&hStat, 0, sizeof (NtStatistics_t)); - hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; - hStat.u.usageData_v0.streamid = (uint8_t) stream_config[inst_id].stream_id; - - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return 0; - } - - uint16_t stream_id = stream_config[inst_id].stream_id; - if (stream_config[inst_id].is_active) { - uint64_t rx_pkts_total = 0; - uint64_t rx_byte_total = 0; - uint64_t drop_pkts_total = 0; - uint64_t drop_byte_total = 0; - - for (uint32_t hbCount = 0; hbCount < hStat.u.usageData_v0.data.numHostBufferUsed; hbCount++) { - if (unlikely(stream_config[inst_id].initialized == false)) { - rxPktsStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.frames; - rxByteStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.bytes; - dropPktStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames; - dropByteStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.bytes; - stream_config[inst_id].initialized = true; - } else { - rx_pkts_total += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.frames; - rx_byte_total += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.bytes; - drop_pkts_total += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames; - drop_byte_total += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.bytes; - } - } - - current_stats[stream_id].current_packets = rx_pkts_total - rxPktsStart[stream_id]; - current_stats[stream_id].current_bytes = rx_byte_total - rxByteStart[stream_id]; - current_stats[stream_id].current_drop_packets = drop_pkts_total - dropPktStart[stream_id]; - current_stats[stream_id].current_drop_bytes = drop_byte_total - dropByteStart[stream_id]; - } - - if (enable_stream_stats) { - StatsSetUI64(tv, stream_counters[inst_id].pkts, current_stats[stream_id].current_packets); - StatsSetUI64(tv, stream_counters[inst_id].byte, current_stats[stream_id].current_bytes); - StatsSetUI64(tv, stream_counters[inst_id].drop_pkts, current_stats[stream_id].current_drop_packets); - StatsSetUI64(tv, stream_counters[inst_id].drop_byte, current_stats[stream_id].current_drop_bytes); - } - - ++inst_id; - } - - uint32_t stream_id; - for (stream_id = 0; stream_id < num_streams; ++stream_id) { - -#ifndef NAPATECH_ENABLE_BYPASS - total_stats.current_packets += current_stats[stream_id].current_packets; - total_stats.current_bytes += current_stats[stream_id].current_bytes; -#endif /* NAPATECH_ENABLE_BYPASS */ - total_stats.current_drop_packets += current_stats[stream_id].current_drop_packets; - total_stats.current_drop_bytes += current_stats[stream_id].current_drop_bytes; - } - - -#ifndef NAPATECH_ENABLE_BYPASS - StatsSetUI64(tv, total_counters.pkts, total_stats.current_packets); - StatsSetUI64(tv, total_counters.byte, total_stats.current_bytes); -#endif /* NAPATECH_ENABLE_BYPASS */ - - StatsSetUI64(tv, total_counters.drop_pkts, total_stats.current_drop_packets); - StatsSetUI64(tv, total_counters.drop_byte, total_stats.current_drop_bytes); - - total_stats.current_packets = 0; - total_stats.current_bytes = 0; - total_stats.current_drop_packets = 0; - total_stats.current_drop_bytes = 0; - - /* Read usage data for the chosen stream ID */ - memset(&hStat, 0, sizeof (NtStatistics_t)); - -#ifdef NAPATECH_ENABLE_BYPASS - hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V3; - hStat.u.query_v3.clear = 0; -#else /* NAPATECH_ENABLE_BYPASS */ - /* Older versions of the API have a different structure. */ - hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V2; - hStat.u.query_v2.clear = 0; -#endif /* !NAPATECH_ENABLE_BYPASS */ - - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - if (status == NT_STATUS_TIMEOUT) { - SCLogInfo("Statistics timed out - will retry next time."); - return 0; - } else { - NAPATECH_ERROR(status); - return 0; - } - } - -#ifdef NAPATECH_ENABLE_BYPASS - - int adapter = 0; - uint64_t total_dispatch_host_pkts = 0; - uint64_t total_dispatch_host_byte = 0; - uint64_t total_dispatch_drop_pkts = 0; - uint64_t total_dispatch_drop_byte = 0; - uint64_t total_dispatch_fwd_pkts = 0; - uint64_t total_dispatch_fwd_byte = 0; - - for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) { - total_dispatch_host_pkts += hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].pkts; - total_dispatch_host_byte += hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].octets; - - total_dispatch_drop_pkts += hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].pkts - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].pkts; - total_dispatch_drop_byte += hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].octets - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].octets; - - total_dispatch_fwd_pkts += hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].pkts - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[4].pkts; - total_dispatch_fwd_byte += hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].octets - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[4].octets; - - total_stats.current_packets += hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].pkts - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].pkts - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].pkts - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].pkts; - - total_stats.current_bytes = hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].octets - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].octets - + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].octets; - } - - StatsSetUI64(tv, dispatch_host.pkts, total_dispatch_host_pkts); - StatsSetUI64(tv, dispatch_host.byte, total_dispatch_host_byte); - - StatsSetUI64(tv, dispatch_drop.pkts, total_dispatch_drop_pkts); - StatsSetUI64(tv, dispatch_drop.byte, total_dispatch_drop_byte); - - if (is_inline) { - StatsSetUI64(tv, dispatch_fwd.pkts, total_dispatch_fwd_pkts); - StatsSetUI64(tv, dispatch_fwd.byte, total_dispatch_fwd_byte); - } - - StatsSetUI64(tv, total_counters.pkts, total_stats.current_packets); - StatsSetUI64(tv, total_counters.byte, total_stats.current_bytes); - -#endif /* NAPATECH_ENABLE_BYPASS */ - - return num_active; -} - -/** - * \brief Statistics processing loop - * - * Instantiated on the stats thread. Periodically retrieves - * statistics from the Napatech card and updates the packet counters - * - * \param arg Pointer that is cast into a ThreadVars structure - */ -static void *NapatechStatsLoop(void *arg) -{ - ThreadVars *tv = (ThreadVars *) arg; - - int status; - NtInfoStream_t hInfo; - NtStatStream_t hstat_stream; - int is_inline = 0; - int enable_stream_stats = 0; - PacketCounters stream_counters[MAX_STREAMS]; - - if (ConfGetBool("napatech.inline", &is_inline) == 0) { - is_inline = 0; - } - - if (ConfGetBool("napatech.enable-stream-stats", &enable_stream_stats) == 0) { - /* default is "no" */ - enable_stream_stats = 0; - } - - NapatechStreamConfig stream_config[MAX_STREAMS]; - uint16_t stream_cnt = NapatechGetStreamConfig(stream_config); - - /* Open the info and Statistics */ - if ((status = NT_InfoOpen(&hInfo, "StatsLoopInfoStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return NULL; - } - - if ((status = NT_StatOpen(&hstat_stream, "StatsLoopStatsStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return NULL; - } - - NtStatistics_t hStat; - memset(&hStat, 0, sizeof (NtStatistics_t)); - -#ifdef NAPATECH_ENABLE_BYPASS - hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V3; - hStat.u.query_v3.clear = 1; -#else /* NAPATECH_ENABLE_BYPASS */ - hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V2; - hStat.u.query_v2.clear = 1; -#endif /* !NAPATECH_ENABLE_BYPASS */ - - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return 0; - } - - PacketCounters total_counters; - memset(&total_counters, 0, sizeof(total_counters)); - - PacketCounters dispatch_host; - memset(&dispatch_host, 0, sizeof(dispatch_host)); - - PacketCounters dispatch_drop; - memset(&dispatch_drop, 0, sizeof(dispatch_drop)); - - PacketCounters dispatch_fwd; - memset(&dispatch_fwd, 0, sizeof(dispatch_fwd)); - - total_counters.pkts = StatsRegisterCounter("napa_total.pkts", tv); - dispatch_host.pkts = StatsRegisterCounter("napa_dispatch_host.pkts", tv); - dispatch_drop.pkts = StatsRegisterCounter("napa_dispatch_drop.pkts", tv); - if (is_inline) { - dispatch_fwd.pkts = StatsRegisterCounter("napa_dispatch_fwd.pkts", tv); - } - - total_counters.byte = StatsRegisterCounter("napa_total.byte", tv); - dispatch_host.byte = StatsRegisterCounter("napa_dispatch_host.byte", tv); - dispatch_drop.byte = StatsRegisterCounter("napa_dispatch_drop.byte", tv); - if (is_inline) { - dispatch_fwd.byte = StatsRegisterCounter("napa_dispatch_fwd.byte", tv); - } - - total_counters.drop_pkts = StatsRegisterCounter("napa_total.overflow_drop_pkts", tv); - total_counters.drop_byte = StatsRegisterCounter("napa_total.overflow_drop_byte", tv); - - if (enable_stream_stats) { - for (int i = 0; i < stream_cnt; ++i) { - char *pkts_buf = SCCalloc(1, 32); - if (unlikely(pkts_buf == NULL)) { - FatalError("Failed to allocate memory for NAPATECH stream counter."); - } - - snprintf(pkts_buf, 32, "napa%d.pkts", stream_config[i].stream_id); - stream_counters[i].pkts = StatsRegisterCounter(pkts_buf, tv); - - char *byte_buf = SCCalloc(1, 32); - if (unlikely(byte_buf == NULL)) { - FatalError("Failed to allocate memory for NAPATECH stream counter."); - } - snprintf(byte_buf, 32, "napa%d.bytes", stream_config[i].stream_id); - stream_counters[i].byte = StatsRegisterCounter(byte_buf, tv); - - char *drop_pkts_buf = SCCalloc(1, 32); - if (unlikely(drop_pkts_buf == NULL)) { - FatalError("Failed to allocate memory for NAPATECH stream counter."); - } - snprintf(drop_pkts_buf, 32, "napa%d.drop_pkts", stream_config[i].stream_id); - stream_counters[i].drop_pkts = StatsRegisterCounter(drop_pkts_buf, tv); - - char *drop_byte_buf = SCCalloc(1, 32); - if (unlikely(drop_byte_buf == NULL)) { - FatalError("Failed to allocate memory for NAPATECH stream counter."); - } - snprintf(drop_byte_buf, 32, "napa%d.drop_byte", stream_config[i].stream_id); - stream_counters[i].drop_byte = StatsRegisterCounter(drop_byte_buf, tv); - } - } - -#ifdef NAPATECH_ENABLE_BYPASS - FlowStatsCounters flow_counters; - if (bypass_supported) { - flow_counters.active_bypass_flows = StatsRegisterCounter("napa_bypass.active_flows", tv); - flow_counters.total_bypass_flows = StatsRegisterCounter("napa_bypass.total_flows", tv); - } -#endif /* NAPATECH_ENABLE_BYPASS */ - - StatsSetupPrivate(tv); - - StatsSetUI64(tv, total_counters.pkts, 0); - StatsSetUI64(tv, total_counters.byte, 0); - StatsSetUI64(tv, total_counters.drop_pkts, 0); - StatsSetUI64(tv, total_counters.drop_byte, 0); - -#ifdef NAPATECH_ENABLE_BYPASS - if (bypass_supported) { - StatsSetUI64(tv, dispatch_host.pkts, 0); - StatsSetUI64(tv, dispatch_drop.pkts, 0); - - if (is_inline) { - StatsSetUI64(tv, dispatch_fwd.pkts, 0); - } - - StatsSetUI64(tv, dispatch_host.byte, 0); - StatsSetUI64(tv, dispatch_drop.byte, 0); - if (is_inline) { - StatsSetUI64(tv, dispatch_fwd.byte, 0); - } - - if (enable_stream_stats) { - for (int i = 0; i < stream_cnt; ++i) { - StatsSetUI64(tv, stream_counters[i].pkts, 0); - StatsSetUI64(tv, stream_counters[i].byte, 0); - StatsSetUI64(tv, stream_counters[i].drop_pkts, 0); - StatsSetUI64(tv, stream_counters[i].drop_byte, 0); - } - } - - StatsSetUI64(tv, flow_counters.active_bypass_flows, 0); - StatsSetUI64(tv, flow_counters.total_bypass_flows, 0); - UpdateFlowStats(tv, hInfo, hstat_stream, flow_counters, 1); - } -#endif /* NAPATECH_ENABLE_BYPASS */ - - uint32_t num_active = UpdateStreamStats(tv, hInfo, hstat_stream, - stream_cnt, stream_config, total_counters, - dispatch_host, dispatch_drop, dispatch_fwd, - is_inline, enable_stream_stats, stream_counters); - - if (!NapatechIsAutoConfigEnabled() && (num_active < stream_cnt)) { - SCLogInfo("num_active: %d, stream_cnt: %d", num_active, stream_cnt); - SCLogWarning("Some or all of the configured streams are not created. Proceeding with " - "active streams."); - } - - TmThreadsSetFlag(tv, THV_INIT_DONE | THV_RUNNING); - while (1) { - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCLogDebug("NapatechStatsLoop THV_KILL detected"); - break; - } - - UpdateStreamStats(tv, hInfo, hstat_stream, - stream_cnt, stream_config, total_counters, - dispatch_host, dispatch_drop, dispatch_fwd, - is_inline, enable_stream_stats, - stream_counters); - -#ifdef NAPATECH_ENABLE_BYPASS - if (bypass_supported) { - UpdateFlowStats(tv, hInfo, hstat_stream, flow_counters, 0); - } -#endif /* NAPATECH_ENABLE_BYPASS */ - - StatsSyncCountersIfSignalled(tv); - usleep(1000000); - } - - /* CLEAN UP NT Resources and Close the info stream */ - if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return NULL; - } - - /* Close the statistics stream */ - if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return NULL; - } - - SCLogDebug("Exiting NapatechStatsLoop"); - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - TmThreadsSetFlag(tv, THV_CLOSED); - - return NULL; -} - -#define MAX_HOSTBUFFER 4 -#define MAX_STREAMS 256 -#define HB_HIGHWATER 2048 //1982 - -/** - * \brief Tests whether a particular stream_id is actively registered - * - * \param stream_id - ID of the stream to look up - * \param num_registered - The total number of registered streams - * \param registered_streams - An array containing actively registered streams. - * - * \return Bool indicating is the specified stream is registered. - * - */ -static bool RegisteredStream(uint16_t stream_id, uint16_t num_registered, - NapatechStreamConfig registered_streams[]) -{ - for (uint16_t reg_id = 0; reg_id < num_registered; ++reg_id) { - if (stream_id == registered_streams[reg_id].stream_id) { - return true; - } - } - return false; -} - -/** - * \brief Count the number of worker threads defined in the conf file. - * - * \return - The number of worker threads defined by the configuration - */ -static uint32_t CountWorkerThreads(void) -{ - int worker_count = 0; - - ConfNode *affinity; - ConfNode *root = ConfGetNode("threading.cpu-affinity"); - - if (root != NULL) { - - TAILQ_FOREACH(affinity, &root->head, next) - { - if (strcmp(affinity->val, "decode-cpu-set") == 0 || - strcmp(affinity->val, "stream-cpu-set") == 0 || - strcmp(affinity->val, "reject-cpu-set") == 0 || - strcmp(affinity->val, "output-cpu-set") == 0) { - continue; - } - - if (strcmp(affinity->val, "worker-cpu-set") == 0) { - ConfNode *node = ConfNodeLookupChild(affinity->head.tqh_first, "cpu"); - ConfNode *lnode; - - enum CONFIG_SPECIFIER cpu_spec = CONFIG_SPECIFIER_UNDEFINED; - - TAILQ_FOREACH(lnode, &node->head, next) - { - uint8_t start, end; - char *end_str; - if (strncmp(lnode->val, "all", 4) == 0) { - /* check that the sting in the config file is correctly specified */ - if (cpu_spec != CONFIG_SPECIFIER_UNDEFINED) { - FatalError("Only one Napatech port specifier type allowed."); - } - cpu_spec = CONFIG_SPECIFIER_RANGE; - worker_count = UtilCpuGetNumProcessorsConfigured(); - } else if ((end_str = strchr(lnode->val, '-'))) { - /* check that the sting in the config file is correctly specified */ - if (cpu_spec != CONFIG_SPECIFIER_UNDEFINED) { - FatalError("Only one Napatech port specifier type allowed."); - } - cpu_spec = CONFIG_SPECIFIER_RANGE; - - - if (StringParseUint8(&start, 10, end_str - lnode->val, (const char *)lnode->val) < 0) { - FatalError("Napatech invalid" - " worker range start: '%s'", - lnode->val); - } - if (StringParseUint8(&end, 10, 0, (const char *) (end_str + 1)) < 0) { - FatalError("Napatech invalid" - " worker range end: '%s'", - (end_str != NULL) ? (const char *)(end_str + 1) : "Null"); - } - if (end < start) { - FatalError("Napatech invalid" - " worker range start: '%d' is greater than end: '%d'", - start, end); - } - worker_count = end - start + 1; - - } else { - /* check that the sting in the config file is correctly specified */ - if (cpu_spec == CONFIG_SPECIFIER_RANGE) { - FatalError("Napatech port range specifiers cannot be combined with " - "individual stream specifiers."); - } - cpu_spec = CONFIG_SPECIFIER_INDIVIDUAL; - ++worker_count; - } - } - break; - } - } - } - return worker_count; -} - -/** - * \brief Reads and parses the stream configuration defined in the config file. - * - * \param stream_config - array to be filled in with active stream info. - * - * \return the number of streams configured or -1 if an error occurred - * - */ -int NapatechGetStreamConfig(NapatechStreamConfig stream_config[]) -{ - int status; - char error_buffer[80]; // Error buffer - NtStatStream_t hstat_stream; - NtStatistics_t hStat; // Stat handle. - NtInfoStream_t info_stream; - NtInfo_t info; - uint16_t instance_cnt = 0; - int use_all_streams = 0; - int set_cpu_affinity = 0; - ConfNode *ntstreams; - uint16_t stream_id = 0; - uint8_t start = 0; - uint8_t end = 0; - - for (uint16_t i = 0; i < MAX_STREAMS; ++i) { - stream_config[i].stream_id = 0; - stream_config[i].is_active = false; - stream_config[i].initialized = false; - } - - if (ConfGetBool("napatech.use-all-streams", &use_all_streams) == 0) { - /* default is "no" */ - use_all_streams = 0; - } - - if ((status = NT_InfoOpen(&info_stream, "SuricataStreamInfo")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return -1; - } - - if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return -1; - } - - if (use_all_streams) { - info.cmd = NT_INFO_CMD_READ_STREAM; - if ((status = NT_InfoRead(info_stream, &info)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return -1; - } - - while (instance_cnt < info.u.stream.data.count) { - - /* - * For each stream ID query the number of host-buffers used by - * the stream. If zero, then that streamID is not used; skip - * over it and continue until we get a streamID with a non-zero - * count of the host-buffers. - */ - memset(&hStat, 0, sizeof (NtStatistics_t)); - - /* Read usage data for the chosen stream ID */ - hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; - hStat.u.usageData_v0.streamid = (uint8_t) stream_id; - - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - /* Get the status code as text */ - NT_ExplainError(status, error_buffer, sizeof (error_buffer)); - SCLogError("NT_StatRead() failed: %s\n", error_buffer); - return -1; - } - - if (hStat.u.usageData_v0.data.numHostBufferUsed == 0) { - ++stream_id; - continue; - } - - /* if we get here it is an active stream */ - stream_config[instance_cnt].stream_id = stream_id++; - stream_config[instance_cnt].is_active = true; - instance_cnt++; - } - - } else { - (void)ConfGetBool("threading.set-cpu-affinity", &set_cpu_affinity); - if (NapatechIsAutoConfigEnabled() && (set_cpu_affinity == 1)) { - start = 0; - end = CountWorkerThreads() - 1; - } else { - /* When not using the default streams we need to - * parse the array of streams from the conf */ - if ((ntstreams = ConfGetNode("napatech.streams")) == NULL) { - SCLogError("Failed retrieving napatech.streams from Config"); - if (NapatechIsAutoConfigEnabled() && (set_cpu_affinity == 0)) { - SCLogError("if set-cpu-affinity: no in conf then napatech.streams must be " - "defined"); - } - exit(EXIT_FAILURE); - } - - /* Loop through all stream numbers in the array and register the devices */ - ConfNode *stream; - enum CONFIG_SPECIFIER stream_spec = CONFIG_SPECIFIER_UNDEFINED; - instance_cnt = 0; - - TAILQ_FOREACH(stream, &ntstreams->head, next) - { - - if (stream == NULL) { - SCLogError("Couldn't Parse Stream Configuration"); - return -1; - } - - char *end_str = strchr(stream->val, '-'); - if (end_str) { - if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) { - SCLogError("Only one Napatech stream range specifier allowed."); - return -1; - } - stream_spec = CONFIG_SPECIFIER_RANGE; - - if (StringParseUint8(&start, 10, end_str - stream->val, - (const char *)stream->val) < 0) { - FatalError("Napatech invalid " - "stream id start: '%s'", - stream->val); - } - if (StringParseUint8(&end, 10, 0, (const char *) (end_str + 1)) < 0) { - FatalError("Napatech invalid " - "stream id end: '%s'", - (end_str != NULL) ? (const char *)(end_str + 1) : "Null"); - } - } else { - if (stream_spec == CONFIG_SPECIFIER_RANGE) { - FatalError("Napatech range and individual specifiers cannot be combined."); - } - stream_spec = CONFIG_SPECIFIER_INDIVIDUAL; - if (StringParseUint8(&stream_config[instance_cnt].stream_id, - 10, 0, (const char *)stream->val) < 0) { - FatalError("Napatech invalid " - "stream id: '%s'", - stream->val); - } - start = stream_config[instance_cnt].stream_id; - end = stream_config[instance_cnt].stream_id; - } - } - } - - for (stream_id = start; stream_id <= end; ++stream_id) { - /* if we get here it is configured in the .yaml file */ - stream_config[instance_cnt].stream_id = stream_id; - - /* Check to see if it is an active stream */ - memset(&hStat, 0, sizeof (NtStatistics_t)); - - /* Read usage data for the chosen stream ID */ - hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; - hStat.u.usageData_v0.streamid = - (uint8_t) stream_config[instance_cnt].stream_id; - - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return -1; - } - - if (hStat.u.usageData_v0.data.numHostBufferUsed > 0) { - stream_config[instance_cnt].is_active = true; - } - instance_cnt++; - } - } - - /* Close the statistics stream */ - if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return -1; - } - - if ((status = NT_InfoClose(info_stream)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return -1; - } - - return instance_cnt; -} - -static void *NapatechBufMonitorLoop(void *arg) -{ - ThreadVars *tv = (ThreadVars *) arg; - - NtInfo_t hStreamInfo; - NtStatistics_t hStat; // Stat handle. - NtInfoStream_t hInfo; - NtStatStream_t hstat_stream; - int status; // Status variable - - const uint32_t alertInterval = 25; - -#ifndef NAPATECH_ENABLE_BYPASS - uint32_t OB_fill_level[MAX_STREAMS] = {0}; - uint32_t OB_alert_level[MAX_STREAMS] = {0}; - uint32_t ave_OB_fill_level[MAX_STREAMS] = {0}; -#endif /* NAPATECH_ENABLE_BYPASS */ - - uint32_t HB_fill_level[MAX_STREAMS] = {0}; - uint32_t HB_alert_level[MAX_STREAMS] = {0}; - uint32_t ave_HB_fill_level[MAX_STREAMS] = {0}; - - /* Open the info and Statistics */ - if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - /* Read the info on all streams instantiated in the system */ - hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM; - if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - NapatechStreamConfig registered_streams[MAX_STREAMS]; - int num_registered = NapatechGetStreamConfig(registered_streams); - if (num_registered == -1) { - exit(EXIT_FAILURE); - } - - TmThreadsSetFlag(tv, THV_INIT_DONE | THV_RUNNING); - while (1) { - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCLogDebug("NapatechBufMonitorLoop THV_KILL detected"); - break; - } - - usleep(200000); - - /* Read the info on all streams instantiated in the system */ - hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM; - if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - char pktCntStr[4096]; - memset(pktCntStr, 0, sizeof (pktCntStr)); - - uint32_t stream_id = 0; - uint32_t stream_cnt = 0; - uint32_t num_streams = hStreamInfo.u.stream.data.count; - - for (stream_cnt = 0; stream_cnt < num_streams; ++stream_cnt) { - - do { - - /* Read usage data for the chosen stream ID */ - hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; - hStat.u.usageData_v0.streamid = (uint8_t) stream_id; - - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - if (hStat.u.usageData_v0.data.numHostBufferUsed == 0) { - ++stream_id; - continue; - } - } while (hStat.u.usageData_v0.data.numHostBufferUsed == 0); - - if (RegisteredStream(stream_id, num_registered, registered_streams)) { - -#ifndef NAPATECH_ENABLE_BYPASS - ave_OB_fill_level[stream_id] = 0; -#endif /* NAPATECH_ENABLE_BYPASS */ - - ave_HB_fill_level[stream_id] = 0; - - for (uint32_t hb_count = 0; hb_count < hStat.u.usageData_v0.data.numHostBufferUsed; hb_count++) { - -#ifndef NAPATECH_ENABLE_BYPASS - OB_fill_level[hb_count] = - ((100 * hStat.u.usageData_v0.data.hb[hb_count].onboardBuffering.used) / - hStat.u.usageData_v0.data.hb[hb_count].onboardBuffering.size); - - if (OB_fill_level[hb_count] > 100) { - OB_fill_level[hb_count] = 100; - } -#endif /* NAPATECH_ENABLE_BYPASS */ - uint32_t bufSize = hStat.u.usageData_v0.data.hb[hb_count].enQueuedAdapter / 1024 - + hStat.u.usageData_v0.data.hb[hb_count].deQueued / 1024 - + hStat.u.usageData_v0.data.hb[hb_count].enQueued / 1024 - - HB_HIGHWATER; - - HB_fill_level[hb_count] = (uint32_t) - ((100 * hStat.u.usageData_v0.data.hb[hb_count].deQueued / 1024) / - bufSize); - -#ifndef NAPATECH_ENABLE_BYPASS - ave_OB_fill_level[stream_id] += OB_fill_level[hb_count]; -#endif /* NAPATECH_ENABLE_BYPASS */ - - ave_HB_fill_level[stream_id] += HB_fill_level[hb_count]; - } - -#ifndef NAPATECH_ENABLE_BYPASS - ave_OB_fill_level[stream_id] /= hStat.u.usageData_v0.data.numHostBufferUsed; -#endif /* NAPATECH_ENABLE_BYPASS */ - - ave_HB_fill_level[stream_id] /= hStat.u.usageData_v0.data.numHostBufferUsed; - - /* Host Buffer Fill Level warnings... */ - if (ave_HB_fill_level[stream_id] >= (HB_alert_level[stream_id] + alertInterval)) { - - while (ave_HB_fill_level[stream_id] >= HB_alert_level[stream_id] + alertInterval) { - HB_alert_level[stream_id] += alertInterval; - } - SCLogPerf("nt%d - Increasing Host Buffer Fill Level : %4d%%", - stream_id, ave_HB_fill_level[stream_id] - 1); - } - - if (HB_alert_level[stream_id] > 0) { - if ((ave_HB_fill_level[stream_id] <= (HB_alert_level[stream_id] - alertInterval))) { - SCLogPerf("nt%d - Decreasing Host Buffer Fill Level: %4d%%", - stream_id, ave_HB_fill_level[stream_id]); - - while (ave_HB_fill_level[stream_id] <= (HB_alert_level[stream_id] - alertInterval)) { - if ((HB_alert_level[stream_id]) > 0) { - HB_alert_level[stream_id] -= alertInterval; - } else break; - } - } - } - -#ifndef NAPATECH_ENABLE_BYPASS - /* On Board SDRAM Fill Level warnings... */ - if (ave_OB_fill_level[stream_id] >= (OB_alert_level[stream_id] + alertInterval)) { - while (ave_OB_fill_level[stream_id] >= OB_alert_level[stream_id] + alertInterval) { - OB_alert_level[stream_id] += alertInterval; - - } - SCLogPerf("nt%d - Increasing Adapter SDRAM Fill Level: %4d%%", - stream_id, ave_OB_fill_level[stream_id]); - } - - if (OB_alert_level[stream_id] > 0) { - if ((ave_OB_fill_level[stream_id] <= (OB_alert_level[stream_id] - alertInterval))) { - SCLogPerf("nt%d - Decreasing Adapter SDRAM Fill Level : %4d%%", - stream_id, ave_OB_fill_level[stream_id]); - - while (ave_OB_fill_level[stream_id] <= (OB_alert_level[stream_id] - alertInterval)) { - if ((OB_alert_level[stream_id]) > 0) { - OB_alert_level[stream_id] -= alertInterval; - } else break; - } - } - } -#endif /* NAPATECH_ENABLE_BYPASS */ - } - ++stream_id; - } - } - - if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - /* Close the statistics stream */ - if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - SCLogDebug("Exiting NapatechStatsLoop"); - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - TmThreadsSetFlag(tv, THV_CLOSED); - - return NULL; -} - - -void NapatechStartStats(void) -{ - /* Creates the Statistic threads */ - ThreadVars *stats_tv = TmThreadCreate("NapatechStats", - NULL, NULL, - NULL, NULL, - "custom", NapatechStatsLoop, 0); - - if (stats_tv == NULL) { - FatalError("Error creating a thread for NapatechStats - Killing engine."); - } - - if (TmThreadSpawn(stats_tv) != 0) { - FatalError("Failed to spawn thread for NapatechStats - Killing engine."); - } - -#ifdef NAPATECH_ENABLE_BYPASS - if (bypass_supported) { - SCLogInfo("Napatech bypass functionality enabled."); - } -#endif /* NAPATECH_ENABLE_BYPASS */ - - ThreadVars *buf_monitor_tv = TmThreadCreate("NapatechBufMonitor", - NULL, NULL, - NULL, NULL, - "custom", NapatechBufMonitorLoop, 0); - - if (buf_monitor_tv == NULL) { - FatalError("Error creating a thread for NapatechBufMonitor - Killing engine."); - } - - if (TmThreadSpawn(buf_monitor_tv) != 0) { - FatalError("Failed to spawn thread for NapatechBufMonitor - Killing engine."); - } - - return; -} - -bool NapatechSetupNuma(uint32_t stream, uint32_t numa) -{ - uint32_t status = 0; - static NtConfigStream_t hconfig; - - char ntpl_cmd[64]; - snprintf(ntpl_cmd, 64, "setup[numanode=%d] = streamid == %d", numa, stream); - - NtNtplInfo_t ntpl_info; - - if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return false; - } - - if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) == NT_SUCCESS) { - status = ntpl_info.ntplId; - - } else { - NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); - return false; - } - - return status; -} - -static uint32_t NapatechSetHashmode(void) -{ - uint32_t status = 0; - const char *hash_mode; - static NtConfigStream_t hconfig; - char ntpl_cmd[64]; - NtNtplInfo_t ntpl_info; - - uint32_t filter_id = 0; - - /* Get the hashmode from the conf file. */ - ConfGet("napatech.hashmode", &hash_mode); - - snprintf(ntpl_cmd, 64, "hashmode = %s", hash_mode); - - /* Issue the NTPL command */ - if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - return false; - } - - if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, - NT_NTPL_PARSER_VALIDATE_NORMAL)) == NT_SUCCESS) { - filter_id = ntpl_info.ntplId; - SCLogConfig("Napatech hashmode: %s ID: %d", hash_mode, status); - } else { - NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); - status = 0; - } - - return filter_id; -} - -static uint32_t GetStreamNUMAs(uint32_t stream_id, int stream_numas[]) -{ - NtStatistics_t hStat; // Stat handle. - NtStatStream_t hstat_stream; - int status; // Status variable - - for (int i = 0; i < MAX_HOSTBUFFERS; ++i) - stream_numas[i] = -1; - - if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - char pktCntStr[4096]; - memset(pktCntStr, 0, sizeof (pktCntStr)); - - - /* Read usage data for the chosen stream ID */ - hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; - hStat.u.usageData_v0.streamid = (uint8_t) stream_id; - - if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - for (uint32_t hb_id = 0; hb_id < hStat.u.usageData_v0.data.numHostBufferUsed; ++hb_id) { - stream_numas[hb_id] = hStat.u.usageData_v0.data.hb[hb_id].numaNode; - } - - return hStat.u.usageData_v0.data.numHostBufferUsed; -} - -static int NapatechSetFilter(NtConfigStream_t hconfig, char *ntpl_cmd) -{ - int status = 0; - int local_filter_id = 0; - - NtNtplInfo_t ntpl_info; - if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, - NT_NTPL_PARSER_VALIDATE_NORMAL)) == NT_SUCCESS) { - SCLogConfig("NTPL filter assignment \"%s\" returned filter id %4d", - ntpl_cmd, local_filter_id); - } else { - NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); - exit(EXIT_FAILURE); - } - - return local_filter_id; -} - -uint32_t NapatechDeleteFilters(void) -{ - uint32_t status = 0; - static NtConfigStream_t hconfig; - char ntpl_cmd[64]; - NtNtplInfo_t ntpl_info; - - if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - snprintf(ntpl_cmd, 64, "delete = all"); - if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, - NT_NTPL_PARSER_VALIDATE_NORMAL)) == NT_SUCCESS) { - status = ntpl_info.ntplId; - } else { - NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); - status = 0; - } - - NT_ConfigClose(hconfig); - - return status; -} - - -uint32_t NapatechSetupTraffic(uint32_t first_stream, uint32_t last_stream) -{ -#define PORTS_SPEC_SIZE 64 - - struct ports_spec_s { - uint8_t first[MAX_PORTS]; - uint8_t second[MAX_PORTS]; - bool all; - char str[PORTS_SPEC_SIZE]; - } ports_spec; - - ports_spec.all = false; - - ConfNode *ntports; - int iteration = 0; - int status = 0; - NtConfigStream_t hconfig; - char ntpl_cmd[512]; - int is_inline = 0; -#ifdef NAPATECH_ENABLE_BYPASS - int is_span_port[MAX_PORTS] = { 0 }; -#endif - - char span_ports[128]; - memset(span_ports, 0, sizeof(span_ports)); - - if (ConfGetBool("napatech.inline", &is_inline) == 0) { - is_inline = 0; - } - - NapatechSetHashmode(); - - if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { - NAPATECH_ERROR(status); - exit(EXIT_FAILURE); - } - - if (first_stream == last_stream) { - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "Setup[state=inactive] = StreamId == %d", - first_stream); - } else { - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "Setup[state=inactive] = StreamId == (%d..%d)", - first_stream, last_stream); - } - NapatechSetFilter(hconfig, ntpl_cmd); - -#ifdef NAPATECH_ENABLE_BYPASS - if (NapatechUseHWBypass()) { - SCLogInfo("Napatech Hardware Bypass enabled."); - } -#else - if (NapatechUseHWBypass()) { - SCLogInfo("Napatech Hardware Bypass requested in conf but is not available."); - exit(EXIT_FAILURE); - } else { - SCLogInfo("Napatech Hardware Bypass disabled."); - } -#endif - - if (is_inline) { - SCLogInfo("Napatech configured for inline mode."); - } else { - - SCLogInfo("Napatech configured for passive (non-inline) mode."); - } - - /* When not using the default streams we need to parse - * the array of streams from the conf - */ - if ((ntports = ConfGetNode("napatech.ports")) == NULL) { - FatalError("Failed retrieving napatech.ports from Conf"); - } - - /* Loop through all ports in the array */ - ConfNode *port; - enum CONFIG_SPECIFIER stream_spec = CONFIG_SPECIFIER_UNDEFINED; - - if (NapatechUseHWBypass()) { - SCLogInfo("Listening on the following Napatech ports:"); - } - /* Build the NTPL command using values in the config file. */ - TAILQ_FOREACH(port, &ntports->head, next) - { - if (port == NULL) { - FatalError("Couldn't Parse Port Configuration"); - } - - if (NapatechUseHWBypass()) { -#ifdef NAPATECH_ENABLE_BYPASS - if (strchr(port->val, '-')) { - stream_spec = CONFIG_SPECIFIER_RANGE; - - if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) { - FatalError("Invalid value '%s' in napatech.ports specification in conf file.", - port->val); - } - - if (ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0, - strchr(port->val, '-') + 1) == -1) { - FatalError("Invalid value '%s' in napatech.ports specification in conf file.", - port->val); - } - - if (ports_spec.first[iteration] == ports_spec.second[iteration]) { - if (is_inline) { - FatalError( - "Error with napatech.ports in conf file. When running in inline " - "mode the two ports specifying a segment must be different."); - } else { - /* SPAN port configuration */ - is_span_port[ports_spec.first[iteration]] = 1; - - if (strlen(span_ports) == 0) { - snprintf(span_ports, sizeof (span_ports), "%d", ports_spec.first[iteration]); - } else { - char temp[16]; - snprintf(temp, sizeof(temp), ",%d", ports_spec.first[iteration]); - strlcat(span_ports, temp, sizeof(span_ports)); - } - - } - } - - if (NapatechGetAdapter(ports_spec.first[iteration]) != NapatechGetAdapter(ports_spec.first[iteration])) { - SCLogError("Invalid napatech.ports specification in conf file."); - SCLogError("Two ports on a segment must reside on the same adapter. port %d " - "is on adapter %d, port %d is on adapter %d.", - ports_spec.first[iteration], - NapatechGetAdapter(ports_spec.first[iteration]), - ports_spec.second[iteration], - NapatechGetAdapter(ports_spec.second[iteration])); - exit(EXIT_FAILURE); - } - - NapatechSetPortmap(ports_spec.first[iteration], ports_spec.second[iteration]); - if (ports_spec.first[iteration] == ports_spec.second[iteration]) { - SCLogInfo(" span_port: %d", ports_spec.first[iteration]); - } else { - SCLogInfo(" %s: %d - %d", is_inline ? "inline_ports" : "tap_ports", ports_spec.first[iteration], ports_spec.second[iteration]); - } - - if (iteration == 0) { - if (ports_spec.first[iteration] == ports_spec.second[iteration]) { - snprintf(ports_spec.str, sizeof (ports_spec.str), "%d", ports_spec.first[iteration]); - } else { - snprintf(ports_spec.str, sizeof (ports_spec.str), "%d,%d", ports_spec.first[iteration], ports_spec.second[iteration]); - } - } else { - char temp[16]; - if (ports_spec.first[iteration] == ports_spec.second[iteration]) { - snprintf(temp, sizeof(temp), ",%d", ports_spec.first[iteration]); - } else { - snprintf(temp, sizeof(temp), ",%d,%d", ports_spec.first[iteration], ports_spec.second[iteration]); - } - strlcat(ports_spec.str, temp, sizeof(ports_spec.str)); - } - } else { - FatalError("When using hardware flow bypass ports must be specified as segments. " - "E.g. ports: [0-1, 0-2]"); - } -#endif - } else { // !NapatechUseHWBypass() - if (strncmp(port->val, "all", 3) == 0) { - /* check that the sting in the config file is correctly specified */ - if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) { - FatalError("Only one Napatech port specifier type is allowed."); - } - stream_spec = CONFIG_SPECIFIER_RANGE; - - ports_spec.all = true; - snprintf(ports_spec.str, sizeof (ports_spec.str), "all"); - } else if (strchr(port->val, '-')) { - /* check that the sting in the config file is correctly specified */ - if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) { - FatalError("Only one Napatech port specifier is allowed when hardware bypass " - "is disabled. (E.g. ports: [0-4], NOT ports: [0-1,2-3])"); - } - stream_spec = CONFIG_SPECIFIER_RANGE; - - if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) { - FatalError("Invalid value '%s' in napatech.ports specification in conf file.", - port->val); - } - - if (ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0, - strchr(port->val, '-') + 1) == -1) { - FatalError("Invalid value '%s' in napatech.ports specification in conf file.", - port->val); - } - - snprintf(ports_spec.str, sizeof (ports_spec.str), "(%d..%d)", ports_spec.first[iteration], ports_spec.second[iteration]); - } else { - /* check that the sting in the config file is correctly specified */ - if (stream_spec == CONFIG_SPECIFIER_RANGE) { - FatalError("Napatech port range specifiers cannot be combined with individual " - "stream specifiers."); - } - stream_spec = CONFIG_SPECIFIER_INDIVIDUAL; - - if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) { - FatalError("Invalid value '%s' in napatech.ports specification in conf file.", - port->val); - } - - /* Determine the ports to use on the NTPL assign statement*/ - if (iteration == 0) { - snprintf(ports_spec.str, sizeof (ports_spec.str), "%s", port->val); - } else { - strlcat(ports_spec.str, ",", sizeof(ports_spec.str)); - strlcat(ports_spec.str, port->val, sizeof(ports_spec.str)); - } - } - } // if !NapatechUseHWBypass() - ++iteration; - } /* TAILQ_FOREACH */ - -#ifdef NAPATECH_ENABLE_BYPASS - if (bypass_supported) { - if (is_inline) { - char inline_setup_cmd[512]; - if (first_stream == last_stream) { - snprintf(inline_setup_cmd, sizeof (ntpl_cmd), - "Setup[TxDescriptor=Dyn;TxPorts=%s;RxCRC=False;TxPortPos=112;UseWL=True] = StreamId == %d", - ports_spec.str, first_stream); - } else { - snprintf(inline_setup_cmd, sizeof (ntpl_cmd), - "Setup[TxDescriptor=Dyn;TxPorts=%s;RxCRC=False;TxPortPos=112;UseWL=True] = StreamId == (%d..%d)", - ports_spec.str, first_stream, last_stream); - } - NapatechSetFilter(hconfig, inline_setup_cmd); - } - /* Build the NTPL command */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=3;streamid=(%d..%d);colormask=0x10000000;" - "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=Layer4Header[0]]= %s%s", - first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); - NapatechSetFilter(hconfig, ntpl_cmd); - - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=2;streamid=(%d..%d);colormask=0x11000000;" - "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=Layer4Header[0]" - "]= %s%s and (Layer3Protocol==IPV4)", - first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); - NapatechSetFilter(hconfig, ntpl_cmd); - - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=2;streamid=(%d..%d);colormask=0x14000000;" - "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=Layer4Header[0]]= %s%s and (Layer3Protocol==IPV6)", - first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=2;streamid=(%d..%d);colormask=0x10100000;" - "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=Layer4Header[0]]= %s%s and (Layer4Protocol==TCP)", - first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=2;streamid=(%d..%d);colormask=0x10200000;" - "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=Layer4Header[0]" - "]= %s%s and (Layer4Protocol==UDP)", - first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); - NapatechSetFilter(hconfig, ntpl_cmd); - - if (strlen(span_ports) > 0) { - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=2;streamid=(%d..%d);colormask=0x00001000;" - "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=Layer4Header[0]" - "]= port==%s", - first_stream, last_stream, span_ports); - NapatechSetFilter(hconfig, ntpl_cmd); - } - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyType[name=KT%u]={sw_32_32,sw_16_16}", - NAPATECH_KEYTYPE_IPV4); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER]=(Layer3Header[12]/32/32,Layer4Header[0]/16/16)", - NAPATECH_KEYTYPE_IPV4, NAPATECH_KEYTYPE_IPV4); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyType[name=KT%u]={32,32,16,16}", - NAPATECH_KEYTYPE_IPV4_SPAN); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER;keysort=sorted]=(Layer3Header[12]/32,Layer3Header[16]/32,Layer4Header[0]/16,Layer4Header[2]/16)", - NAPATECH_KEYTYPE_IPV4_SPAN, NAPATECH_KEYTYPE_IPV4_SPAN); - NapatechSetFilter(hconfig, ntpl_cmd); - - /* IPv6 5tuple for inline and tap ports */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyType[name=KT%u]={sw_128_128,sw_16_16}", - NAPATECH_KEYTYPE_IPV6); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER]=(Layer3Header[8]/128/128,Layer4Header[0]/16/16)", - NAPATECH_KEYTYPE_IPV6, NAPATECH_KEYTYPE_IPV6); - NapatechSetFilter(hconfig, ntpl_cmd); - - /* IPv6 5tuple for SPAN Ports */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyType[name=KT%u]={128,128,16,16}", - NAPATECH_KEYTYPE_IPV6_SPAN); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER;keysort=sorted]=(Layer3Header[8]/128,Layer3Header[24]/128,Layer4Header[0]/16,Layer4Header[2]/16)", - NAPATECH_KEYTYPE_IPV6_SPAN, NAPATECH_KEYTYPE_IPV6_SPAN); - NapatechSetFilter(hconfig, ntpl_cmd); - - - int pair; - char ports_ntpl_a[64]; - char ports_ntpl_b[64]; - memset(ports_ntpl_a, 0, sizeof(ports_ntpl_a)); - memset(ports_ntpl_b, 0, sizeof(ports_ntpl_b)); - - for (pair = 0; pair < iteration; ++pair) { - char port_str[8]; - - if (!is_span_port[ports_spec.first[pair]]) { - snprintf(port_str, sizeof(port_str), "%s%u ", strlen(ports_ntpl_a) == 0 ? "" : ",", ports_spec.first[pair]); - strlcat(ports_ntpl_a, port_str, sizeof(ports_ntpl_a)); - - snprintf(port_str, sizeof(port_str), "%s%u ", strlen(ports_ntpl_b) == 0 ? "" : ",", ports_spec.second[pair]); - strlcat(ports_ntpl_b, port_str, sizeof(ports_ntpl_b)); - } - } - - if (strlen(ports_ntpl_a) > 0) { - /* This is the assign for dropping upstream traffic */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port == %s)and(Key(KDEF%u,KeyID=%u)==%u)", - ports_ntpl_a, - NAPATECH_KEYTYPE_IPV4, - NAPATECH_KEYTYPE_IPV4, - NAPATECH_FLOWTYPE_DROP); - NapatechSetFilter(hconfig, ntpl_cmd); - } - - if (strlen(ports_ntpl_b) > 0) { - /* This is the assign for dropping downstream traffic */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port == %s)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)", - ports_ntpl_b, //ports_spec.str, - NAPATECH_KEYTYPE_IPV4, - NAPATECH_KEYTYPE_IPV4, - NAPATECH_FLOWTYPE_DROP); - NapatechSetFilter(hconfig, ntpl_cmd); - } - - if (strlen(span_ports) > 0) { - /* This is the assign for dropping SPAN Port traffic */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port == %s)and(Key(KDEF%u,KeyID=%u)==%u)", - span_ports, - NAPATECH_KEYTYPE_IPV4_SPAN, - NAPATECH_KEYTYPE_IPV4_SPAN, - NAPATECH_FLOWTYPE_DROP); - NapatechSetFilter(hconfig, ntpl_cmd); - } - - if (is_inline) { - for (pair = 0; pair < iteration; ++pair) { - /* This is the assignment for forwarding traffic */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x2]=(Layer3Protocol==IPV4)and(port == %d)and(Key(KDEF%u,KeyID=%u)==%u)", - ports_spec.second[pair], - ports_spec.first[pair], - NAPATECH_KEYTYPE_IPV4, - NAPATECH_KEYTYPE_IPV4, - NAPATECH_FLOWTYPE_PASS); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x2]=(Layer3Protocol==IPV4)and(port == %d)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)", - ports_spec.first[pair], - ports_spec.second[pair], - NAPATECH_KEYTYPE_IPV4, - NAPATECH_KEYTYPE_IPV4, - NAPATECH_FLOWTYPE_PASS); - NapatechSetFilter(hconfig, ntpl_cmd); - } - } - - if (strlen(ports_ntpl_a) > 0) { - /* This is the assign for dropping upstream traffic */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port == %s)and(Key(KDEF%u,KeyID=%u)==%u)", - ports_ntpl_a, - NAPATECH_KEYTYPE_IPV6, - NAPATECH_KEYTYPE_IPV6, - NAPATECH_FLOWTYPE_DROP); - NapatechSetFilter(hconfig, ntpl_cmd); - } - - if (strlen(ports_ntpl_b) > 0) { - /* This is the assign for dropping downstream traffic */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port == %s)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)", - ports_ntpl_b, //ports_spec.str, - NAPATECH_KEYTYPE_IPV6, - NAPATECH_KEYTYPE_IPV6, - NAPATECH_FLOWTYPE_DROP); - NapatechSetFilter(hconfig, ntpl_cmd); - } - - if (strlen(span_ports) > 0) { - /* This is the assign for dropping SPAN Port traffic */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port == %s)and(Key(KDEF%u,KeyID=%u)==%u)", - span_ports, - NAPATECH_KEYTYPE_IPV6_SPAN, - NAPATECH_KEYTYPE_IPV6_SPAN, - NAPATECH_FLOWTYPE_DROP); - NapatechSetFilter(hconfig, ntpl_cmd); - } - - if (is_inline) { - for (pair = 0; pair < iteration; ++pair) { - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x4]=(Layer3Protocol==IPV6)and(port==%d)and(Key(KDEF%u,KeyID=%u)==%u)", - ports_spec.second[pair], - ports_spec.first[pair], - NAPATECH_KEYTYPE_IPV6, - NAPATECH_KEYTYPE_IPV6, - NAPATECH_FLOWTYPE_PASS); - NapatechSetFilter(hconfig, ntpl_cmd); - - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x4]=(Layer3Protocol==IPV6)and(port==%d)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)", - ports_spec.first[pair], - ports_spec.second[pair], - NAPATECH_KEYTYPE_IPV6, - NAPATECH_KEYTYPE_IPV6, - NAPATECH_FLOWTYPE_PASS); - NapatechSetFilter(hconfig, ntpl_cmd); - } - } - } else { - if (is_inline) { - FatalError("Napatech Inline operation not supported by this FPGA version."); - } - - if (NapatechIsAutoConfigEnabled()){ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), "assign[streamid=(%d..%d);colormask=0x0] = %s%s", - first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); - NapatechSetFilter(hconfig, ntpl_cmd); - } - } - -#else /* NAPATECH_ENABLE_BYPASS */ - snprintf(ntpl_cmd, sizeof (ntpl_cmd), "assign[streamid=(%d..%d)] = %s%s", - first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); - NapatechSetFilter(hconfig, ntpl_cmd); - -#endif /* !NAPATECH_ENABLE_BYPASS */ - - SCLogConfig("Host-buffer NUMA assignments: "); - int numa_nodes[MAX_HOSTBUFFERS]; - uint32_t stream_id; - for (stream_id = first_stream; stream_id < last_stream; ++stream_id) { - char temp1[256]; - char temp2[256]; - - uint32_t num_host_buffers = GetStreamNUMAs(stream_id, numa_nodes); - - snprintf(temp1, 256, " stream %d: ", stream_id); - - for (uint32_t hb_id = 0; hb_id < num_host_buffers; ++hb_id) { - snprintf(temp2, 256, "%d ", numa_nodes[hb_id]); - strlcat(temp1, temp2, sizeof(temp1)); - } - - SCLogConfig("%s", temp1); - } - - if (first_stream == last_stream) { - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "Setup[state=active] = StreamId == %d", - first_stream); - } else { - snprintf(ntpl_cmd, sizeof (ntpl_cmd), - "Setup[state=active] = StreamId == (%d..%d)", - first_stream, last_stream); - } - NapatechSetFilter(hconfig, ntpl_cmd); - - NT_ConfigClose(hconfig); - - return status; -} - -#endif // HAVE_NAPATECH diff --git a/src/util-napatech.h b/src/util-napatech.h deleted file mode 100644 index 45d4ddf6789d..000000000000 --- a/src/util-napatech.h +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright (C) 2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -/** - * \file - * - * \author Phil Young - * - */ -#ifndef __UTIL_NAPATECH_H__ -#define __UTIL_NAPATECH_H__ - -#ifdef HAVE_NAPATECH -#include - -typedef struct NapatechPacketVars_ -{ - uint64_t stream_id; - NtNetBuf_t nt_packet_buf; - NtNetStreamRx_t rx_stream; - NtFlowStream_t flow_stream; - ThreadVars *tv; -#ifdef NAPATECH_ENABLE_BYPASS - NtDyn3Descr_t *dyn3; - int bypass; -#endif -} NapatechPacketVars; - -typedef struct NapatechStreamConfig_ -{ - uint8_t stream_id; - bool is_active; - bool initialized; -} NapatechStreamConfig; - -typedef struct NapatechCurrentStats_ -{ - uint64_t current_packets; - uint64_t current_bytes; - uint64_t current_drop_packets; - uint64_t current_drop_bytes; -} NapatechCurrentStats; - -#define MAX_HOSTBUFFER 4 -#define MAX_STREAMS 256 -#define MAX_PORTS 80 -#define MAX_ADAPTERS 8 -#define HB_HIGHWATER 2048 //1982 - -extern void NapatechStartStats(void); - -#define NAPATECH_ERROR(status) \ - { \ - char errorBuffer[1024]; \ - NT_ExplainError((status), errorBuffer, sizeof(errorBuffer) - 1); \ - SCLogError("Napatech Error: %s", errorBuffer); \ - } - -#define NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status) \ - { \ - char errorBuffer[1024]; \ - NT_ExplainError(status, errorBuffer, sizeof(errorBuffer) - 1); \ - SCLogError(" NTPL failed: %s", errorBuffer); \ - SCLogError(" cmd: %s", ntpl_cmd); \ - if (strncmp(ntpl_info.u.errorData.errBuffer[0], "", 256) != 0) \ - SCLogError(" %s", ntpl_info.u.errorData.errBuffer[0]); \ - if (strncmp(ntpl_info.u.errorData.errBuffer[1], "", 256) != 0) \ - SCLogError(" %s", ntpl_info.u.errorData.errBuffer[1]); \ - if (strncmp(ntpl_info.u.errorData.errBuffer[2], "", 256) != 0) \ - SCLogError(" %s", ntpl_info.u.errorData.errBuffer[2]); \ - } - -// #define ENABLE_NT_DEBUG -#ifdef ENABLE_NT_DEBUG - void NapatechPrintIP(uint32_t address); - - #define NAPATECH_DEBUG(...) printf(__VA_ARGS__) - #define NAPATECH_PRINTIP(a) NapatechPrintIP(uint32_t address) -#else - #define NAPATECH_DEBUG(...) - #define NAPATECH_PRINTIP(a) -#endif - -NapatechCurrentStats NapatechGetCurrentStats(uint16_t id); -int NapatechGetStreamConfig(NapatechStreamConfig stream_config[]); -bool NapatechSetupNuma(uint32_t stream, uint32_t numa); -uint32_t NapatechSetupTraffic(uint32_t first_stream, uint32_t last_stream); -uint32_t NapatechDeleteFilters(void); - -#ifdef NAPATECH_ENABLE_BYPASS - -/* */ -#define NAPATECH_KEYTYPE_IPV4 3 -#define NAPATECH_KEYTYPE_IPV4_SPAN 4 -#define NAPATECH_KEYTYPE_IPV6 5 -#define NAPATECH_KEYTYPE_IPV6_SPAN 6 -#define NAPATECH_FLOWTYPE_DROP 7 -#define NAPATECH_FLOWTYPE_PASS 8 - -int NapatechVerifyBypassSupport(void); -int NapatechGetNumAdapters(void); - - -int NapatechIsBypassSupported(void); - -#endif /* NAPATECH_ENABLE_BYPASS */ -#endif /* HAVE_NAPATECH */ -#endif /* __UTIL_NAPATECH_H__ */ diff --git a/src/util-optimize.h b/src/util-optimize.h deleted file mode 100644 index bde35ddd810e..000000000000 --- a/src/util-optimize.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef __UTIL_OPTIMIZE_H__ -#define __UTIL_OPTIMIZE_H__ - -/** - * \file - * - * \author Victor Julien - */ - -#if CPPCHECK==1 -#define likely -#define unlikely -#else -#ifndef likely -#define likely(expr) __builtin_expect(!!(expr), 1) -#endif -#ifndef unlikely -#define unlikely(expr) __builtin_expect(!!(expr), 0) -#endif -#endif - -/** from http://en.wikipedia.org/wiki/Memory_ordering - * - * C Compiler memory barrier - */ -#define cc_barrier() __asm__ __volatile__("": : :"memory") - -/** from http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html - * - * Hardware memory barrier - */ -#define hw_barrier() __sync_synchronize() - -#endif /* __UTIL_OPTIMIZE_H__ */ - diff --git a/src/util-pages.c b/src/util-pages.c deleted file mode 100644 index 170170b1933d..000000000000 --- a/src/util-pages.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Page util functions - */ - -#include "suricata-common.h" -#include "util-pages.h" -#include "util-debug.h" - -#ifndef HAVE_PAGESUPPORTSRWX_AS_MACRO - -/** \brief check if OS allows for RWX pages - * - * Some OS' disallow RWX pages for security reasons. This function mmaps - * some memory RW and then tries to turn it into RWX. If this fails we - * assume that the OS doesn't allow for this. - * - * Thanks to Shawn Webb from HardenedBSD for the suggestion. - * - * \retval 1 RWX supported - * \retval 0 not supported - */ -int PageSupportsRWX(void) -{ - int retval = 1; - void *ptr; - ptr = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); - if (ptr != MAP_FAILED) { - if (mprotect(ptr, getpagesize(), PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { - SCLogConfig("RWX pages denied by OS"); - retval = 0; - } - munmap(ptr, getpagesize()); - } - return retval; -} -#endif /* HAVE_PAGESUPPORTSRWX_AS_MACRO */ - diff --git a/src/util-pages.h b/src/util-pages.h deleted file mode 100644 index 037639147737..000000000000 --- a/src/util-pages.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#ifndef __UTIL_PAGES_H__ -#define __UTIL_PAGES_H__ - -#include "suricata-common.h" - -#ifdef __OpenBSD__ - /* OpenBSD won't allow for this test: - * "suricata(...): mprotect W^X violation" */ - #define PageSupportsRWX() 0 - #define HAVE_PAGESUPPORTSRWX_AS_MACRO 1 -#else - #ifndef HAVE_SYS_MMAN_H - #define PageSupportsRWX() 1 - #define HAVE_PAGESUPPORTSRWX_AS_MACRO 1 - #else - int PageSupportsRWX(void); - #endif /* HAVE_SYS_MMAN_H */ -#endif - -#endif /* __UTIL_PAGES_H__ */ diff --git a/src/util-path.c b/src/util-path.c deleted file mode 100644 index 34c4cc75ca79..000000000000 --- a/src/util-path.c +++ /dev/null @@ -1,315 +0,0 @@ -/* Copyright (C) 2007-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-debug.h" -#include "util-path.h" - -#ifdef OS_WIN32 -#define DIRECTORY_SEPARATOR '\\' -#else -#define DIRECTORY_SEPARATOR '/' -#endif - -/** - * \brief Check if a path is absolute - * - * \param path string with the path - * - * \retval 1 absolute - * \retval 0 not absolute - */ -int PathIsAbsolute(const char *path) -{ - if (strlen(path) > 1 && path[0] == '/') { - return 1; - } - -#if (defined OS_WIN32 || defined __CYGWIN__) - if (strlen(path) > 2) { - if (isalpha((unsigned char)path[0]) && path[1] == ':') { - return 1; - } - } -#endif - - return 0; -} - -/** - * \brief Check if a path is relative - * - * \param path string with the path - * - * \retval 1 relative - * \retval 0 not relative - */ -int PathIsRelative(const char *path) -{ - return PathIsAbsolute(path) ? 0 : 1; -} - -int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname) -{ - char path[PATH_MAX]; - if (dir == NULL || strlen(dir) == 0) - return -1; - - size_t r = strlcpy(path, dir, sizeof(path)); - if (r >= sizeof(path)) { - return -1; - } - -#if defined OS_WIN32 || defined __CYGWIN__ - if (path[strlen(path) - 1] != '\\') - r = strlcat(path, "\\\\", sizeof(path)); -#else - if (path[strlen(path) - 1] != '/') - r = strlcat(path, "/", sizeof(path)); -#endif - if (r >= sizeof(path)) { - return -1; - } - r = strlcat(path, fname, sizeof(path)); - if (r >= sizeof(path)) { - return -1; - } - r = strlcpy(out_buf, path, buf_size); - if (r >= buf_size) { - return -1; - } - - return 0; -} - -char *PathMergeAlloc(const char *const dir, const char *const fname) -{ - char path[PATH_MAX]; - if (PathMerge(path, sizeof(path), dir, fname) != 0) - return NULL; - - char *ret = SCStrdup(path); - if (ret == NULL) - return NULL; - - return ret; -} - -/** - * \brief Wrapper to join a directory and filename and resolve using realpath - * _fullpath is used for WIN32 - * - * \param out_buf output buffer. Up to PATH_MAX will be written. Unchanged on exit failure. - * \param buf_size length of output buffer, must be PATH_MAX - * \param dir the directory - * \param fname the filename - * - * \retval 0 on success - * \retval -1 on failure - */ -int PathJoin(char *out_buf, size_t buf_size, const char *const dir, const char *const fname) -{ - SCEnter(); - if (buf_size != PATH_MAX) { - return -1; - } - if (PathMerge(out_buf, buf_size, dir, fname) != 0) { - SCLogError("Could not join filename to path"); - return -1; - } - char *tmp_buf = SCRealPath(out_buf, NULL); - if (tmp_buf == NULL) { - SCLogError("Error resolving path: %s", strerror(errno)); - return -1; - } - memset(out_buf, 0, buf_size); - size_t ret = strlcpy(out_buf, tmp_buf, buf_size); - free(tmp_buf); - if (ret >= buf_size) { - return -1; - } - return 0; -} - -/** - * \brief Wrapper around SCMkDir with default mode arguments. - */ -int SCDefaultMkDir(const char *path) -{ - return SCMkDir(path, S_IRWXU | S_IRGRP | S_IXGRP); -} - -/** - * \brief Recursively create a directory. - * - * \param path Path to create - * \param final true will create the final path component, false will not - * - * \retval 0 on success - * \retval -1 on error - */ -int SCCreateDirectoryTree(const char *path, const bool final) -{ - char pathbuf[PATH_MAX]; - char *p; - size_t len = strlen(path); - - if (len > PATH_MAX - 1) { - return -1; - } - - strlcpy(pathbuf, path, sizeof(pathbuf)); - - for (p = pathbuf + 1; *p; p++) { - if (*p == '/') { - /* Truncate, while creating directory */ - *p = '\0'; - - if (SCDefaultMkDir(pathbuf) != 0) { - if (errno != EEXIST) { - return -1; - } - } - - *p = '/'; - } - } - - if (final) { - if (SCDefaultMkDir(pathbuf) != 0) { - if (errno != EEXIST) { - return -1; - } - } - } - - return 0; -} - -/** - * \brief Check if a path exists. - * - * \param Path to check for existence - * - * \retval true if path exists - * \retval false if path does not exist - */ -bool SCPathExists(const char *path) -{ - struct stat sb; - if (stat(path, &sb) == 0) { - return true; - } - return false; -} - -/** - * \brief OS independent wrapper for directory check - * - * \param dir_entry object to check - * - * \retval True if the object is a regular directory, otherwise false. This directory - * and parent directory will return false. - */ -bool SCIsRegularDirectory(const struct dirent *const dir_entry) -{ -#ifndef OS_WIN32 - if ((dir_entry->d_type == DT_DIR) && - (strcmp(dir_entry->d_name, ".") != 0) && - (strcmp(dir_entry->d_name, "..") != 0)) { - return true; - } -#endif - return false; -} -/** - * \brief OS independent to check for regular file - * - * \param dir_entry object to check - * - * \retval True if the object is a regular file. Otherwise false. - */ -bool SCIsRegularFile(const struct dirent *const dir_entry) -{ -#ifndef OS_WIN32 - return dir_entry->d_type == DT_REG; -#endif - return false; -} - -/** - * \brief OS independent wrapper for realpath - * - * \param path the path to resolve - * \param resolved_path the resolved path; if null, a buffer will be allocated - * - * \retval the resolved_path; or a pointer to a new resolved_path buffer - */ -char *SCRealPath(const char *path, char *resolved_path) -{ -#ifdef OS_WIN32 - return _fullpath(resolved_path, path, PATH_MAX); -#else - return realpath(path, resolved_path); -#endif -} - -/* - * \brief Return the basename of the provided path. - * \param path The path on which to compute the basename - * - * \retval the basename of the path or NULL if the path lacks a non-leaf - */ -const char *SCBasename(const char *path) -{ - if (!path || strlen(path) == 0) - return NULL; - - char *final = strrchr(path, DIRECTORY_SEPARATOR); - if (!final) - return path; - - if (*(final + 1) == '\0') - return NULL; - - return final + 1; -} - -/** - * \brief Check for directory traversal - * - * \param path The path string to check for traversal - * - * \retval true if directory traversal is found, otherwise false - */ -bool SCPathContainsTraversal(const char *path) -{ -#ifdef OS_WIN32 - const char *pattern = "..\\"; -#else - const char *pattern = "../"; -#endif - return strstr(path, pattern) != NULL; -} diff --git a/src/util-path.h b/src/util-path.h deleted file mode 100644 index 141b6fc2472e..000000000000 --- a/src/util-path.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#ifndef __UTIL_PATH_H__ -#define __UTIL_PATH_H__ - -#ifdef OS_WIN32 -typedef struct _stat SCStat; -#define SCFstatFn(fd, statbuf) _fstat((fd), (statbuf)) -#define SCStatFn(pathname, statbuf) _stat((pathname), (statbuf)) -#else -typedef struct stat SCStat; -#define SCFstatFn(fd, statbuf) fstat((fd), (statbuf)) -#define SCStatFn(pathname, statbuf) stat((pathname), (statbuf)) -#endif - -#if defined OS_WIN32 || defined __CYGWIN__ -#define PATH_SEPARATOR_SIZE 2 -#else -#define PATH_SEPARATOR_SIZE 1 -#endif - -#ifndef HAVE_NON_POSIX_MKDIR - #define SCMkDir(a, b) mkdir(a, b) -#else - #define SCMkDir(a, b) mkdir(a) -#endif - -int PathIsAbsolute(const char *); -int PathIsRelative(const char *); -int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname); -char *PathMergeAlloc(const char *const dir, const char *const fname); -int PathJoin(char *out_buf, size_t buf_len, const char *const dir, const char *const fname); -int SCDefaultMkDir(const char *path); -int SCCreateDirectoryTree(const char *path, const bool final); -bool SCPathExists(const char *path); -bool SCIsRegularDirectory(const struct dirent *const dir_entry); -bool SCIsRegularFile(const struct dirent *const dir_entry); -char *SCRealPath(const char *path, char *resolved_path); -const char *SCBasename(const char *path); -bool SCPathContainsTraversal(const char *path); - -#endif /* __UTIL_PATH_H__ */ diff --git a/src/util-pidfile.c b/src/util-pidfile.c deleted file mode 100644 index 1cbae0eb7a5d..000000000000 --- a/src/util-pidfile.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * \author Victor Julien - * - * Utility code for dealing with a pidfile. - * Adaptation of Steve Grubbs patch to our coding guidelines - * (thanks for the patch Steve ;) - */ - -#include "suricata-common.h" -#include "util-pidfile.h" -#include "util-debug.h" - -/** - * \brief Write a pid file (used at the startup) - * This commonly needed by the init scripts - * - * \param pointer to the name of the pid file to write (optarg) - * - * \retval 0 if succes - * \retval -1 on failure - */ -int SCPidfileCreate(const char *pidfile) -{ - SCEnter(); - - int pidfd = 0; - char val[16]; - - size_t len = snprintf(val, sizeof(val), "%"PRIuMAX"\n", (uintmax_t)getpid()); - if (len <= 0) { - SCLogError("Pid error (%s)", strerror(errno)); - SCReturnInt(-1); - } - - pidfd = open(pidfile, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644); - if (pidfd < 0) { - SCLogError("unable to set pidfile '%s': %s", pidfile, strerror(errno)); - SCReturnInt(-1); - } - - ssize_t r = write(pidfd, val, (unsigned int)len); - if (r == -1) { - SCLogError("unable to write pidfile: %s", strerror(errno)); - close(pidfd); - SCReturnInt(-1); - } else if ((size_t)r != len) { - SCLogError("unable to write pidfile: wrote" - " %" PRIdMAX " of %" PRIuMAX " bytes.", - (intmax_t)r, (uintmax_t)len); - close(pidfd); - SCReturnInt(-1); - } - - close(pidfd); - SCReturnInt(0); -} - -/** - * \brief Remove the pid file (used at the startup) - * - * \param pointer to the name of the pid file to write (optarg) - */ -void SCPidfileRemove(const char *pid_filename) -{ - if (pid_filename != NULL) { - /* we ignore the result, the user may have removed the file already. */ - (void)unlink(pid_filename); - } -} - -/** - * \brief Check the Suricata pid file (used at the startup) - * - * This commonly needed by the init scripts. - * - * This function will fail if the PID file exists, but tries to log a - * meaningful message if appears Suricata is running, or if the PID - * file appears to be stale. - * - * \param pointer to the name of the pid file to write (optarg) - * - * \retval 0 if succes - * \retval -1 on failure - */ -int SCPidfileTestRunning(const char *pid_filename) -{ - /* Check if the existing process is still alive. */ - FILE *pf; - - pf = fopen(pid_filename, "r"); - if (pf == NULL) { - if (access(pid_filename, F_OK) == 0) { - SCLogError("pid file '%s' exists and can not be read. Aborting!", pid_filename); - return -1; - } else { - return 0; - } - } - -#ifndef OS_WIN32 - pid_t pidv; - if (fscanf(pf, "%d", &pidv) == 1 && kill(pidv, 0) == 0) { - SCLogError("pid file '%s' exists and Suricata appears to be running. " - "Aborting!", - pid_filename); - } else -#endif - { - SCLogError("pid file '%s' exists but appears stale. " - "Make sure Suricata is not running and then remove %s. " - "Aborting!", - pid_filename, pid_filename); - } - - fclose(pf); - return -1; -} diff --git a/src/util-pidfile.h b/src/util-pidfile.h deleted file mode 100644 index ef071f4e8424..000000000000 --- a/src/util-pidfile.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * \author Victor Julien - */ - -#ifndef __UTIL_PID_H__ -#define __UTIL_PID_H__ - -int SCPidfileCreate(const char *); -void SCPidfileRemove(const char *); -int SCPidfileTestRunning(const char *pid_filename); - -#endif /* __UTIL_PID_H__ */ - diff --git a/src/util-plugin.c b/src/util-plugin.c deleted file mode 100644 index 3a08aa8876ad..000000000000 --- a/src/util-plugin.c +++ /dev/null @@ -1,214 +0,0 @@ -/* Copyright (C) 2020-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "suricata-plugin.h" -#include "suricata.h" -#include "runmodes.h" -#include "output-eve-syslog.h" -#include "util-plugin.h" -#include "util-debug.h" - -#ifdef HAVE_PLUGINS - -#include - -typedef struct PluginListNode_ { - SCPlugin *plugin; - void *lib; - TAILQ_ENTRY(PluginListNode_) entries; -} PluginListNode; - -/** - * The list of loaded plugins. - * - * Currently only used as a place to stash the pointer returned from - * dlopen, but could have other uses, such as a plugin unload destructor. - */ -static TAILQ_HEAD(, PluginListNode_) plugins = TAILQ_HEAD_INITIALIZER(plugins); - -static TAILQ_HEAD(, SCEveFileType_) output_types = TAILQ_HEAD_INITIALIZER(output_types); - -static TAILQ_HEAD(, SCCapturePlugin_) capture_plugins = TAILQ_HEAD_INITIALIZER(capture_plugins); - -bool RegisterPlugin(SCPlugin *plugin, void *lib) -{ - BUG_ON(plugin->name == NULL); - BUG_ON(plugin->author == NULL); - BUG_ON(plugin->license == NULL); - BUG_ON(plugin->Init == NULL); - - PluginListNode *node = SCCalloc(1, sizeof(*node)); - if (node == NULL) { - SCLogError("Failed to allocate memory for plugin"); - return false; - } - node->plugin = plugin; - node->lib = lib; - TAILQ_INSERT_TAIL(&plugins, node, entries); - SCLogNotice("Initializing plugin %s; author=%s; license=%s", plugin->name, plugin->author, - plugin->license); - (*plugin->Init)(); - return true; -} - -static void InitPlugin(char *path) -{ - void *lib = dlopen(path, RTLD_NOW); - if (lib == NULL) { - SCLogNotice("Failed to open %s as a plugin: %s", path, dlerror()); - } else { - SCLogNotice("Loading plugin %s", path); - - SCPluginRegisterFunc plugin_register = dlsym(lib, "SCPluginRegister"); - if (plugin_register == NULL) { - SCLogError("Plugin does not export SCPluginRegister function: %s", path); - dlclose(lib); - return; - } - - if (!RegisterPlugin(plugin_register(), lib)) { - SCLogError("Plugin registration failed: %s", path); - dlclose(lib); - return; - } - } -} - -void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args) -{ - ConfNode *conf = ConfGetNode("plugins"); - if (conf == NULL) { - return; - } - ConfNode *plugin = NULL; - TAILQ_FOREACH(plugin, &conf->head, next) { - struct stat statbuf; - if (stat(plugin->val, &statbuf) == -1) { - SCLogError("Bad plugin path: %s: %s", plugin->val, strerror(errno)); - continue; - } - if (S_ISDIR(statbuf.st_mode)) { - // coverity[toctou : FALSE] - DIR *dir = opendir(plugin->val); - if (dir == NULL) { - SCLogError("Failed to open plugin directory %s: %s", plugin->val, strerror(errno)); - continue; - } - struct dirent *entry = NULL; - char path[PATH_MAX]; - while ((entry = readdir(dir)) != NULL) { - if (strstr(entry->d_name, ".so") != NULL) { - snprintf(path, sizeof(path), "%s/%s", plugin->val, entry->d_name); - InitPlugin(path); - } - } - closedir(dir); - } else { - InitPlugin(plugin->val); - } - } - - if (run_mode == RUNMODE_PLUGIN) { - SCCapturePlugin *capture = SCPluginFindCaptureByName(capture_plugin_name); - if (capture == NULL) { - FatalError("No capture plugin found with name %s", capture_plugin_name); - } - capture->Init(capture_plugin_args, RUNMODE_PLUGIN, TMM_RECEIVEPLUGIN, - TMM_DECODEPLUGIN); - } -} - -static bool IsBuiltinTypeName(const char *name) -{ - const char *builtin[] = { - "regular", - "unix_dgram", - "unix_stream", - "redis", - NULL, - }; - for (int i = 0;; i++) { - if (builtin[i] == NULL) { - break; - } - if (strcmp(builtin[i], name) == 0) { - return true; - } - } - return false; -} - -/** - * \brief Register an Eve file type. - * - * \retval true if registered successfully, false if the file type name - * conflicts with a built-in or previously registered - * file type. - */ -bool SCRegisterEveFileType(SCEveFileType *plugin) -{ - /* First check that the name doesn't conflict with a built-in filetype. */ - if (IsBuiltinTypeName(plugin->name)) { - SCLogError("Eve file type name conflicts with built-in type: %s", plugin->name); - return false; - } - - /* Now check against previously registered file types. */ - SCEveFileType *existing = NULL; - TAILQ_FOREACH (existing, &output_types, entries) { - if (strcmp(existing->name, plugin->name) == 0) { - SCLogError("Eve file type name conflicts with previously registered type: %s", - plugin->name); - return false; - } - } - - SCLogDebug("Registering EVE file type plugin %s", plugin->name); - TAILQ_INSERT_TAIL(&output_types, plugin, entries); - return true; -} - -SCEveFileType *SCPluginFindFileType(const char *name) -{ - SCEveFileType *plugin = NULL; - TAILQ_FOREACH(plugin, &output_types, entries) { - if (strcmp(name, plugin->name) == 0) { - return plugin; - } - } - return NULL; -} - -int SCPluginRegisterCapture(SCCapturePlugin *plugin) -{ - TAILQ_INSERT_TAIL(&capture_plugins, plugin, entries); - SCLogNotice("Capture plugin registered: %s", plugin->name); - return 0; -} - -SCCapturePlugin *SCPluginFindCaptureByName(const char *name) -{ - SCCapturePlugin *plugin = NULL; - TAILQ_FOREACH(plugin, &capture_plugins, entries) { - if (strcmp(name, plugin->name) == 0) { - return plugin; - } - } - return plugin; -} -#endif diff --git a/src/util-pool-thread.c b/src/util-pool-thread.c deleted file mode 100644 index 162b523fce9e..000000000000 --- a/src/util-pool-thread.c +++ /dev/null @@ -1,420 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \defgroup utilpool Pool - * - * @{ - */ - -/** - * \file - * - * \author Victor Julien - * - * Pool utility functions - */ - -#include "suricata-common.h" -#include "util-pool.h" -#include "util-pool-thread.h" -#include "util-unittest.h" -#include "util-debug.h" - -/** - * \brief per thread Pool, initialization function - * \param thread number of threads this is for. Can start with 1 and be expanded. - * Other params are as for PoolInit() - */ -PoolThread *PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, - uint32_t elt_size, void *(*Alloc)(void), int (*Init)(void *, void *), - void *InitData, void (*Cleanup)(void *), void (*Free)(void *)) -{ - sc_errno = SC_OK; - - if (threads <= 0) { - SCLogDebug("error"); - sc_errno = SC_EINVAL; - return NULL; - } - - PoolThread *pt = SCCalloc(1, sizeof(*pt)); - if (unlikely(pt == NULL)) { - SCLogDebug("memory alloc error"); - sc_errno = SC_ENOMEM; - goto error; - } - - SCLogDebug("size %d", threads); - pt->array = SCMalloc(threads * sizeof(PoolThreadElement)); - if (pt->array == NULL) { - SCLogDebug("memory alloc error"); - sc_errno = SC_ENOMEM; - goto error; - } - pt->size = threads; - - for (int i = 0; i < threads; i++) { - PoolThreadElement *e = &pt->array[i]; - - SCMutexInit(&e->lock, NULL); - SCMutexLock(&e->lock); -// SCLogDebug("size %u prealloc_size %u elt_size %u Alloc %p Init %p InitData %p Cleanup %p Free %p", -// size, prealloc_size, elt_size, -// Alloc, Init, InitData, Cleanup, Free); - e->pool = PoolInit(size, prealloc_size, elt_size, Alloc, Init, InitData, Cleanup, Free); - SCMutexUnlock(&e->lock); - if (e->pool == NULL) { - SCLogDebug("error"); - goto error; - } - } - - return pt; -error: - if (pt != NULL) - PoolThreadFree(pt); - return NULL; -} - -/** \brief expand pool by one for a new thread - * \retval -1 or pool thread id - */ -int PoolThreadExpand(PoolThread *pt) -{ - if (pt == NULL || pt->array == NULL || pt->size == 0) { - SCLogError("pool grow failed"); - return -1; - } - - size_t newsize = pt->size + 1; - SCLogDebug("newsize %"PRIuMAX, (uintmax_t)newsize); - - void *ptmp = SCRealloc(pt->array, (newsize * sizeof(PoolThreadElement))); - if (ptmp == NULL) { - SCFree(pt->array); - pt->array = NULL; - SCLogError("pool grow failed"); - return -1; - } - pt->array = ptmp; - pt->size = newsize; - - /* copy settings from first thread that registered the pool */ - Pool settings; - memset(&settings, 0x0, sizeof(settings)); - PoolThreadElement *e = &pt->array[0]; - SCMutexLock(&e->lock); - settings.max_buckets = e->pool->max_buckets; - settings.preallocated = e->pool->preallocated; - settings.elt_size = e->pool->elt_size; - settings.Alloc = e->pool->Alloc; - settings.Init = e->pool->Init; - settings.InitData = e->pool->InitData; - settings.Cleanup = e->pool->Cleanup; - settings.Free = e->pool->Free; - SCMutexUnlock(&e->lock); - - e = &pt->array[newsize - 1]; - memset(e, 0x00, sizeof(*e)); - SCMutexInit(&e->lock, NULL); - SCMutexLock(&e->lock); - e->pool = PoolInit(settings.max_buckets, settings.preallocated, - settings.elt_size, settings.Alloc, settings.Init, settings.InitData, - settings.Cleanup, settings.Free); - SCMutexUnlock(&e->lock); - if (e->pool == NULL) { - SCLogError("pool grow failed"); - return -1; - } - - return (int)(newsize - 1); -} - -int PoolThreadSize(PoolThread *pt) -{ - if (pt == NULL) - return -1; - return (int)pt->size; -} - -void PoolThreadFree(PoolThread *pt) -{ - if (pt == NULL) - return; - - if (pt->array != NULL) { - for (int i = 0; i < (int)pt->size; i++) { - PoolThreadElement *e = &pt->array[i]; - SCMutexLock(&e->lock); - PoolFree(e->pool); - SCMutexUnlock(&e->lock); - SCMutexDestroy(&e->lock); - } - SCFree(pt->array); - } - SCFree(pt); -} - -void *PoolThreadGetById(PoolThread *pt, uint16_t id) -{ - void *data = NULL; - - if (pt == NULL || id >= pt->size) - return NULL; - - PoolThreadElement *e = &pt->array[id]; - SCMutexLock(&e->lock); - data = PoolGet(e->pool); - SCMutexUnlock(&e->lock); - if (data) { - PoolThreadId *did = data; - *did = id; - } - - return data; -} - -void PoolThreadReturn(PoolThread *pt, void *data) -{ - PoolThreadId *id = data; - - if (pt == NULL || *id >= pt->size) - return; - - SCLogDebug("returning to id %u", *id); - - PoolThreadElement *e = &pt->array[*id]; - SCMutexLock(&e->lock); - PoolReturn(e->pool, data); - SCMutexUnlock(&e->lock); -} - -void PoolThreadLock(PoolThread *pt, PoolThreadId id) -{ - BUG_ON(pt == NULL || id >= pt->size); - PoolThreadElement *e = &pt->array[id]; - SCMutexLock(&e->lock); -} - -void PoolThreadReturnRaw(PoolThread *pt, PoolThreadId id, void *data) -{ - BUG_ON(pt == NULL || id >= pt->size); - PoolThreadElement *e = &pt->array[id]; - PoolReturn(e->pool, data); -} - -void PoolThreadUnlock(PoolThread *pt, PoolThreadId id) -{ - BUG_ON(pt == NULL || id >= pt->size); - PoolThreadElement *e = &pt->array[id]; - SCMutexUnlock(&e->lock); -} - -#ifdef UNITTESTS -struct PoolThreadTestData { - PoolThreadId res; - int abc; -}; - -static void *PoolThreadTestAlloc(void) -{ - void *data = SCMalloc(sizeof(struct PoolThreadTestData)); - return data; -} - -static -int PoolThreadTestInit(void *data, void *allocdata) -{ - if (!data) - return 0; - - memset(data,0x00,sizeof(allocdata)); - struct PoolThreadTestData *pdata = data; - pdata->abc = *(int *)allocdata; - return 1; -} - -static -void PoolThreadTestFree(void *data) -{ -} - -static int PoolThreadTestInit01(void) -{ - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, PoolThreadTestAlloc, - NULL, NULL, NULL, NULL); - FAIL_IF(pt == NULL); - PoolThreadFree(pt); - PASS; -} - -static int PoolThreadTestInit02(void) -{ - int i = 123; - - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, - PoolThreadTestAlloc, PoolThreadTestInit, - &i, PoolThreadTestFree, NULL); - FAIL_IF(pt == NULL); - PoolThreadFree(pt); - PASS; -} - -static int PoolThreadTestGet01(void) -{ - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, PoolThreadTestAlloc, - NULL, NULL, NULL, NULL); - FAIL_IF(pt == NULL); - - void *data = PoolThreadGetById(pt, 3); - FAIL_IF_NULL(data); - - struct PoolThreadTestData *pdata = data; - FAIL_IF(pdata->res != 3); - - PoolThreadFree(pt); - PASS; -} - -static int PoolThreadTestGet02(void) -{ - int i = 123; - - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, PoolThreadTestAlloc, - PoolThreadTestInit, &i, PoolThreadTestFree, NULL); - FAIL_IF_NULL(pt); - - void *data = PoolThreadGetById(pt, 3); - FAIL_IF_NULL(data); - - struct PoolThreadTestData *pdata = data; - FAIL_IF_NOT (pdata->res == 3); - - FAIL_IF_NOT (pdata->abc == 123); - - PoolThreadFree(pt); - PASS; -} - -static int PoolThreadTestReturn01(void) -{ - int i = 123; - - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, PoolThreadTestAlloc, - PoolThreadTestInit, &i, PoolThreadTestFree, NULL); - FAIL_IF_NULL(pt); - - void *data = PoolThreadGetById(pt, 3); - FAIL_IF_NULL(data); - - struct PoolThreadTestData *pdata = data; - FAIL_IF_NOT (pdata->res == 3); - - FAIL_IF_NOT (pdata->abc == 123); - - FAIL_IF_NOT (pt->array[3].pool->outstanding == 1); - - PoolThreadReturn(pt, data); - - FAIL_IF_NOT (pt->array[3].pool->outstanding == 0); - - PoolThreadFree(pt); - PASS; -} - -static int PoolThreadTestGrow01(void) -{ - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, PoolThreadTestAlloc, - NULL, NULL, NULL, NULL); - FAIL_IF_NULL(pt); - FAIL_IF(PoolThreadExpand(pt) < 0); - - PoolThreadFree(pt); - PASS; -} - -static int PoolThreadTestGrow02(void) -{ - int i = 123; - - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, PoolThreadTestAlloc, - PoolThreadTestInit, &i, PoolThreadTestFree, NULL); - FAIL_IF_NULL(pt); - FAIL_IF(PoolThreadExpand(pt) < 0); - - PoolThreadFree(pt); - PASS; -} - -static int PoolThreadTestGrow03(void) -{ - int i = 123; - - PoolThread *pt = PoolThreadInit(4, /* threads */ - 10, 5, 10, PoolThreadTestAlloc, - PoolThreadTestInit, &i, PoolThreadTestFree, NULL); - FAIL_IF_NULL(pt); - FAIL_IF(PoolThreadExpand(pt) < 0); - - void *data = PoolThreadGetById(pt, 4); - FAIL_IF_NULL(data); - - struct PoolThreadTestData *pdata = data; - FAIL_IF_NOT(pdata->res == 4); - - FAIL_IF_NOT(pdata->abc == 123); - - FAIL_IF_NOT(pt->array[4].pool->outstanding == 1); - - PoolThreadReturn(pt, data); - - FAIL_IF_NOT(pt->array[4].pool->outstanding == 0); - - PoolThreadFree(pt); - PASS; -} - -#endif - -void PoolThreadRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01); - UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02); - - UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01); - UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02); - - UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01); - - UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01); - UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02); - UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03); -#endif -} - -/** - * @} - */ diff --git a/src/util-pool-thread.h b/src/util-pool-thread.h deleted file mode 100644 index 44b76e75e292..000000000000 --- a/src/util-pool-thread.h +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup utilpool - * - * @{ - */ - -/** - * \file - * - * \author Victor Julien - */ - -/** - * Consumers of this API MUST add PoolThreadReserved as the first - * member in the data structure. They also MUST ignore that data - * completely. It's managed by this API. - * - * It's purpose is to make sure thread X can return data to a pool - * from thread Y. - */ - -#ifndef __UTIL_POOL_THREAD_H__ -#define __UTIL_POOL_THREAD_H__ - -#include "threads.h" -#include "util-pool.h" - -struct PoolThreadElement_ { - SCMutex lock; /**< lock, should have low contention */ - Pool *pool; /**< actual pool */ -}; -// __attribute__((aligned(CLS))); <- VJ: breaks on clang 32bit, segv in PoolThreadTestGrow01 - -typedef struct PoolThreadElement_ PoolThreadElement; - -typedef struct PoolThread_ { - size_t size; /**< size of the array */ - PoolThreadElement *array; /**< array of elements */ -} PoolThread; - -/** per data item reserved data containing the - * thread pool id */ -typedef uint16_t PoolThreadId; - -void PoolThreadRegisterTests(void); - -/** \brief initialize a thread pool - * \note same as PoolInit() except for "threads" - * \param threads number of threads to use this - * \retval pt thread pool or NULL on error */ -PoolThread *PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int (*Init)(void *, void *), void *InitData, void (*Cleanup)(void *), void (*Free)(void *)); - -/** \brief grow a thread pool by one - * \note copies settings from initial PoolThreadInit() call - * \param pt thread pool to grow - * \retval r id of new entry on succes, -1 on error */ -int PoolThreadExpand(PoolThread *pt); - -/** \brief destroy the thread pool - * \note wrapper around PoolFree() - * \param pt thread pool */ -void PoolThreadFree(PoolThread *pt); - -/** \brief get data from thread pool by thread id - * \note wrapper around PoolGet() - * \param pt thread pool - * \param id thread id - * \retval ptr data or NULL */ -void *PoolThreadGetById(PoolThread *pt, uint16_t id); - -/** \brief return data to thread pool - * \note wrapper around PoolReturn() - * \param pt thread pool - * \param data memory block to return, with PoolThreadReserved as it's first member */ -void PoolThreadReturn(PoolThread *pt, void *data); - -void PoolThreadLock(PoolThread *pt, PoolThreadId id); -void PoolThreadReturnRaw(PoolThread *pt, PoolThreadId id, void *data); -void PoolThreadUnlock(PoolThread *pt, PoolThreadId id); - -/** \brief get size of PoolThread (number of 'threads', so array elements) - * \param pt thread pool - * \retval size or -1 on error */ -int PoolThreadSize(PoolThread *pt); - -#endif /* __UTIL_POOL_THREAD_H__ */ - -/** - * @} - */ diff --git a/src/util-pool.c b/src/util-pool.c deleted file mode 100644 index bb9ff520c965..000000000000 --- a/src/util-pool.c +++ /dev/null @@ -1,743 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \defgroup utilpool Pool - * - * ::Pool are an effective way to maintain a set of ready to use - * structures. - * - * To create a ::Pool, you need to use PoolInit(). You can - * get an item from the ::Pool by using PoolGet(). When you're - * done with it call PoolReturn(). - * To destroy the ::Pool, call PoolFree(), it will free all used - * memory. - * - * @{ - */ - -/** - * \file - * - * \author Victor Julien - * - * Pool utility functions - */ - -#include "suricata-common.h" -#include "util-pool.h" -#include "util-pool-thread.h" -#include "util-unittest.h" -#include "util-debug.h" - -static int PoolMemset(void *pitem, void *initdata) -{ - Pool *p = (Pool *) initdata; - - memset(pitem, 0, p->elt_size); - return 1; -} - -/** - * \brief Check if data is preallocated - * \retval false if not inside the prealloc'd block, true if inside */ -static bool PoolDataPreAllocated(Pool *p, void *data) -{ - ptrdiff_t delta = data - p->data_buffer; - if ((delta < 0) || (delta > p->data_buffer_size)) { - return false; - } - return true; -} - -/** \brief Init a Pool - * - * PoolInit() creates a ::Pool. The Alloc function must only do - * allocation stuff. The Cleanup function must not try to free - * the PoolBucket::data. This is done by the ::Pool management - * system. - * - * \param size - * \param prealloc_size - * \param elt_size Memory size of an element - * \param Alloc An allocation function or NULL to use a standard SCMalloc - * \param Init An init function or NULL to use a standard memset to 0 - * \param InitData Init data - * \param Cleanup a free function or NULL if no special treatment is needed - * \param Free free func - * \retval the allocated Pool - */ -Pool *PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size, - void *(*Alloc)(void), int (*Init)(void *, void *), void *InitData, - void (*Cleanup)(void *), void (*Free)(void *)) -{ - sc_errno = SC_OK; - - Pool *p = NULL; - - if (size != 0 && prealloc_size > size) { - sc_errno = SC_EINVAL; - goto error; - } - if (size != 0 && elt_size == 0) { - sc_errno = SC_EINVAL; - goto error; - } - if (elt_size && Free) { - sc_errno = SC_EINVAL; - goto error; - } - if (elt_size == 0 && Alloc == NULL) { - sc_errno = SC_EINVAL; - goto error; - } - - /* setup the filter */ - p = SCCalloc(1, sizeof(Pool)); - if (unlikely(p == NULL)) { - sc_errno = SC_ENOMEM; - goto error; - } - - p->max_buckets = size; - p->preallocated = prealloc_size; - p->elt_size = elt_size; - p->data_buffer_size = prealloc_size * elt_size; - p->Alloc = Alloc; - p->Init = Init; - p->InitData = InitData; - p->Cleanup = Cleanup; - p->Free = Free; - if (p->Init == NULL) { - p->Init = PoolMemset; - p->InitData = p; - } - - /* alloc the buckets and place them in the empty list */ - uint32_t u32 = 0; - if (size > 0) { - PoolBucket *pb = SCCalloc(size, sizeof(PoolBucket)); - if (unlikely(pb == NULL)) { - sc_errno = SC_ENOMEM; - goto error; - } - memset(pb, 0, size * sizeof(PoolBucket)); - p->pb_buffer = pb; - for (u32 = 0; u32 < size; u32++) { - /* populate pool */ - pb->next = p->empty_stack; - pb->flags |= POOL_BUCKET_PREALLOCATED; - p->empty_stack = pb; - p->empty_stack_size++; - pb++; - } - - p->data_buffer = SCCalloc(prealloc_size, elt_size); - /* FIXME better goto */ - if (p->data_buffer == NULL) { - sc_errno = SC_ENOMEM; - goto error; - } - } - /* prealloc the buckets and requeue them to the alloc list */ - for (u32 = 0; u32 < prealloc_size; u32++) { - if (size == 0) { /* unlimited */ - PoolBucket *pb = SCCalloc(1, sizeof(PoolBucket)); - if (unlikely(pb == NULL)) { - sc_errno = SC_ENOMEM; - goto error; - } - - if (p->Alloc) { - pb->data = p->Alloc(); - } else { - pb->data = SCMalloc(p->elt_size); - } - if (pb->data == NULL) { - SCFree(pb); - sc_errno = SC_ENOMEM; - goto error; - } - if (p->Init(pb->data, p->InitData) != 1) { - if (p->Free) - p->Free(pb->data); - else - SCFree(pb->data); - SCFree(pb); - sc_errno = SC_EINVAL; - goto error; - } - p->allocated++; - - pb->next = p->alloc_stack; - p->alloc_stack = pb; - p->alloc_stack_size++; - } else { - PoolBucket *pb = p->empty_stack; - if (pb == NULL) { - sc_errno = SC_ENOMEM; - goto error; - } - - pb->data = (char *)p->data_buffer + u32 * elt_size; - if (p->Init(pb->data, p->InitData) != 1) { - pb->data = NULL; - sc_errno = SC_EINVAL; - goto error; - } - - p->empty_stack = pb->next; - p->empty_stack_size--; - - p->allocated++; - - pb->next = p->alloc_stack; - p->alloc_stack = pb; - p->alloc_stack_size++; - } - } - - return p; - -error: - if (p != NULL) { - PoolFree(p); - } - return NULL; -} - -void PoolFree(Pool *p) -{ - if (p == NULL) - return; - - while (p->alloc_stack != NULL) { - PoolBucket *pb = p->alloc_stack; - p->alloc_stack = pb->next; - if (p->Cleanup) - p->Cleanup(pb->data); - if (!PoolDataPreAllocated(p, pb->data)) { - if (p->Free) - p->Free(pb->data); - else - SCFree(pb->data); - } - pb->data = NULL; - if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { - SCFree(pb); - } - } - - while (p->empty_stack != NULL) { - PoolBucket *pb = p->empty_stack; - p->empty_stack = pb->next; - if (pb->data!= NULL) { - if (p->Cleanup) - p->Cleanup(pb->data); - if (!PoolDataPreAllocated(p, pb->data)) { - if (p->Free) - p->Free(pb->data); - else - SCFree(pb->data); - } - pb->data = NULL; - } - if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { - SCFree(pb); - } - } - - if (p->pb_buffer) - SCFree(p->pb_buffer); - if (p->data_buffer) - SCFree(p->data_buffer); - SCFree(p); -} - -void PoolPrint(Pool *p) -{ - printf("\n----------- Hash Table Stats ------------\n"); - printf("Buckets: %" PRIu32 "\n", p->empty_stack_size + p->alloc_stack_size); - printf("-----------------------------------------\n"); -} - -void *PoolGet(Pool *p) -{ - SCEnter(); - - PoolBucket *pb = p->alloc_stack; - if (pb != NULL) { - /* pull from the alloc list */ - p->alloc_stack = pb->next; - p->alloc_stack_size--; - - /* put in the empty list */ - pb->next = p->empty_stack; - p->empty_stack = pb; - p->empty_stack_size++; - } else { - if (p->max_buckets == 0 || p->allocated < p->max_buckets) { - void *pitem; - SCLogDebug("max_buckets %"PRIu32"", p->max_buckets); - - if (p->Alloc != NULL) { - pitem = p->Alloc(); - } else { - pitem = SCMalloc(p->elt_size); - } - - if (pitem != NULL) { - if (p->Init(pitem, p->InitData) != 1) { - if (p->Free != NULL) - p->Free(pitem); - else - SCFree(pitem); - SCReturnPtr(NULL, "void"); - } - - p->allocated++; - p->outstanding++; -#ifdef DEBUG - if (p->outstanding > p->max_outstanding) - p->max_outstanding = p->outstanding; -#endif - } - - SCReturnPtr(pitem, "void"); - } else { - SCReturnPtr(NULL, "void"); - } - } - - void *ptr = pb->data; - pb->data = NULL; - p->outstanding++; -#ifdef DEBUG - if (p->outstanding > p->max_outstanding) - p->max_outstanding = p->outstanding; -#endif - SCReturnPtr(ptr,"void"); -} - -void PoolReturn(Pool *p, void *data) -{ - SCEnter(); - - PoolBucket *pb = p->empty_stack; - - SCLogDebug("pb %p", pb); - - if (pb == NULL) { - p->allocated--; - p->outstanding--; - if (p->Cleanup != NULL) { - p->Cleanup(data); - } - if (!PoolDataPreAllocated(p, data)) { - if (p->Free) - p->Free(data); - else - SCFree(data); - } - - SCLogDebug("tried to return data %p to the pool %p, but no more " - "buckets available. Just freeing the data.", data, p); - SCReturn; - } - - /* pull from the alloc list */ - p->empty_stack = pb->next; - p->empty_stack_size--; - - /* put in the alloc list */ - pb->next = p->alloc_stack; - p->alloc_stack = pb; - p->alloc_stack_size++; - - pb->data = data; - p->outstanding--; - SCReturn; -} - -void PoolPrintSaturation(Pool *p) -{ - if (p->max_buckets > 0) { - SCLogDebug("pool %p is using %" PRIu32 " out of %" PRIu32 " items (%02.1f%%), max %" PRIu32 - " (%02.1f%%): pool struct memory %" PRIu64 ".", - p, p->outstanding, p->max_buckets, - (float)(p->outstanding) / (float)(p->max_buckets) * 100, p->max_outstanding, - (float)(p->max_outstanding) / (float)(p->max_buckets) * 100, - (uint64_t)(p->max_buckets * sizeof(PoolBucket))); - } -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -static void *PoolTestAlloc(void) -{ - void *ptr = SCMalloc(10); - if (unlikely(ptr == NULL)) - return NULL; - return ptr; -} -static int PoolTestInitArg(void *data, void *allocdata) -{ - size_t len = strlen((char *)allocdata) + 1; - char *str = data; - if (str != NULL) - strlcpy(str,(char *)allocdata,len); - return 1; -} - -static void PoolTestFree(void *ptr) -{ - return; -} - -static int PoolTestInit01 (void) -{ - Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); - if (p == NULL) - return 0; - - PoolFree(p); - return 1; -} - -static int PoolTestInit02 (void) -{ - int retval = 0; - - Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); - if (p == NULL) - goto end; - - if (p->alloc_stack == NULL || p->empty_stack == NULL) { - printf("list(s) not properly initialized (a:%p e:%p): ", - p->alloc_stack, p->empty_stack); - retval = 0; - goto end; - } - - if (p->Alloc != PoolTestAlloc) { - printf("Alloc func ptr %p != %p: ", - p->Alloc, PoolTestAlloc); - retval = 0; - goto end; - } - - if (p->Cleanup != PoolTestFree) { - printf("Free func ptr %p != %p: ", - p->Cleanup, PoolTestFree); - retval = 0; - goto end; - } - - retval = 1; -end: - if (p != NULL) - PoolFree(p); - return retval; -} - -static int PoolTestInit03 (void) -{ - int retval = 0; - void *data = NULL; - - Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); - if (p == NULL) - goto end; - - data = PoolGet(p); - if (data == NULL) { - printf("PoolGet returned NULL: "); - retval = 0; - goto end; - } - - if (p->alloc_stack_size != 4) { - printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size); - retval = 0; - goto end; - } - - if (p->empty_stack_size != 6) { - printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size); - retval = 0; - goto end; - } - - retval = 1; -end: - if (p != NULL) - PoolFree(p); - return retval; -} - -static int PoolTestInit04 (void) -{ - int retval = 0; - char *str = NULL; - - Pool *p = PoolInit(10,5,strlen("test") + 1,NULL, PoolTestInitArg,(void *)"test",PoolTestFree, NULL); - if (p == NULL) - goto end; - - str = PoolGet(p); - if (str == NULL) { - printf("PoolGet returned NULL: "); - retval = 0; - goto end; - } - - if (strcmp(str, "test") != 0) { - printf("Memory not properly initialized: "); - retval = 0; - goto end; - } - - if (p->alloc_stack_size != 4) { - printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size); - retval = 0; - goto end; - } - - if (p->empty_stack_size != 6) { - printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size); - retval = 0; - goto end; - } - - retval = 1; -end: - if (p != NULL) - PoolFree(p); - return retval; -} - -static int PoolTestInit05 (void) -{ - int retval = 0; - void *data = NULL; - - Pool *p = PoolInit(10,5,10,PoolTestAlloc,NULL, NULL,PoolTestFree, NULL); - if (p == NULL) - goto end; - - data = PoolGet(p); - if (data == NULL) { - printf("PoolGet returned NULL: "); - retval = 0; - goto end; - } - - if (p->alloc_stack_size != 4) { - printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size); - retval = 0; - goto end; - } - - if (p->empty_stack_size != 6) { - printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size); - retval = 0; - goto end; - } - - PoolReturn(p, data); - data = NULL; - - if (p->alloc_stack_size != 5) { - printf("p->alloc_stack_size 5 != %" PRIu32 ": ", p->alloc_stack_size); - retval = 0; - goto end; - } - - if (p->empty_stack_size != 5) { - printf("p->empty_stack_size 5 != %" PRIu32 ": ", p->empty_stack_size); - retval = 0; - goto end; - } - - retval = 1; -end: - if (p != NULL) - PoolFree(p); - return retval; -} - -static int PoolTestInit06 (void) -{ - int retval = 0; - void *data = NULL; - void *data2 = NULL; - - Pool *p = PoolInit(1,0,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); - if (p == NULL) - goto end; - - if (p->allocated != 0) { - printf("p->allocated 0 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - data = PoolGet(p); - if (data == NULL) { - printf("PoolGet returned NULL: "); - retval = 0; - goto end; - } - - if (p->allocated != 1) { - printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - data2 = PoolGet(p); - if (data2 != NULL) { - printf("PoolGet returned %p, expected NULL: ", data2); - retval = 0; - goto end; - } - - PoolReturn(p,data); - data = NULL; - - if (p->allocated != 1) { - printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - if (p->alloc_stack_size != 1) { - printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size); - retval = 0; - goto end; - } - - retval = 1; -end: - if (p != NULL) - PoolFree(p); - return retval; -} - -/** \test pool with unlimited size */ -static int PoolTestInit07 (void) -{ - int retval = 0; - void *data = NULL; - void *data2 = NULL; - - Pool *p = PoolInit(0,1,10,PoolTestAlloc,NULL,NULL,PoolTestFree, NULL); - if (p == NULL) - goto end; - - if (p->max_buckets != 0) { - printf("p->max_buckets 0 != %" PRIu32 ": ", p->max_buckets); - retval = 0; - goto end; - } - - if (p->allocated != 1) { - printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - data = PoolGet(p); - if (data == NULL) { - printf("PoolGet returned NULL: "); - retval = 0; - goto end; - } - - if (p->allocated != 1) { - printf("(2) p->allocated 1 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - data2 = PoolGet(p); - if (data2 == NULL) { - printf("PoolGet returned NULL: "); - retval = 0; - goto end; - } - - if (p->allocated != 2) { - printf("(3) p->allocated 2 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - PoolReturn(p,data); - data = NULL; - - if (p->allocated != 2) { - printf("(4) p->allocated 2 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - if (p->alloc_stack_size != 1) { - printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size); - retval = 0; - goto end; - } - - PoolReturn(p,data2); - data2 = NULL; - - if (p->allocated != 1) { - printf("(5) p->allocated 1 != %" PRIu32 ": ", p->allocated); - retval = 0; - goto end; - } - - retval = 1; -end: - if (p != NULL) - PoolFree(p); - return retval; -} -#endif /* UNITTESTS */ - -void PoolRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("PoolTestInit01", PoolTestInit01); - UtRegisterTest("PoolTestInit02", PoolTestInit02); - UtRegisterTest("PoolTestInit03", PoolTestInit03); - UtRegisterTest("PoolTestInit04", PoolTestInit04); - UtRegisterTest("PoolTestInit05", PoolTestInit05); - UtRegisterTest("PoolTestInit06", PoolTestInit06); - UtRegisterTest("PoolTestInit07", PoolTestInit07); - - PoolThreadRegisterTests(); -#endif /* UNITTESTS */ -} - - -/** - * @} - */ diff --git a/src/util-pool.h b/src/util-pool.h deleted file mode 100644 index cb82ff6da076..000000000000 --- a/src/util-pool.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup utilpool - * - * @{ - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_POOL_H__ -#define __UTIL_POOL_H__ - -#define POOL_BUCKET_PREALLOCATED (1 << 0) - -/* pool bucket structure */ -typedef struct PoolBucket_ { - void *data; - uint8_t flags; - struct PoolBucket_ *next; -} PoolBucket; - -/* pool structure */ -typedef struct Pool_ { - uint32_t max_buckets; - uint32_t preallocated; - uint32_t allocated; /**< counter of data elements, both currently in - * the pool and outside of it (outstanding) */ - - uint32_t alloc_stack_size; - - PoolBucket *alloc_stack; - - PoolBucket *empty_stack; - uint32_t empty_stack_size; - - int data_buffer_size; - void *data_buffer; - PoolBucket *pb_buffer; - - void *(*Alloc)(void); - int (*Init)(void *, void *); - void *InitData; - void (*Cleanup)(void *); - void (*Free)(void *); - - uint32_t elt_size; - uint32_t outstanding; /**< counter of data items 'in use'. Pretty much - * the diff between PoolGet and PoolReturn */ -#ifdef DEBUG - uint32_t max_outstanding; /**< max value of outstanding we saw */ -#endif -} Pool; - -/* prototypes */ -Pool* PoolInit(uint32_t, uint32_t, uint32_t, void *(*Alloc)(void), int (*Init)(void *, void *), void *, void (*Cleanup)(void *), void (*Free)(void *)); -void PoolFree(Pool *); -void PoolPrint(Pool *); -void PoolPrintSaturation(Pool *p); - -void *PoolGet(Pool *); -void PoolReturn(Pool *, void *); - -void PoolRegisterTests(void); - -#endif /* __UTIL_POOL_H__ */ - -/** - * @} - */ diff --git a/src/util-prefilter.c b/src/util-prefilter.c deleted file mode 100644 index c00aa6528c64..000000000000 --- a/src/util-prefilter.c +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Pattern matcher utility Functions - */ - -#include "suricata-common.h" -#include "util-prefilter.h" - -/** - * \brief Setup a pmq - * - * \param pmq Pattern matcher queue to be initialized - * - * \retval -1 error - * \retval 0 ok - */ -int PmqSetup(PrefilterRuleStore *pmq) -{ - SCEnter(); - - if (pmq == NULL) { - SCReturnInt(-1); - } - - memset(pmq, 0, sizeof(PrefilterRuleStore)); - - pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ - pmq->rule_id_array_cnt = 0; - - size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); - pmq->rule_id_array = (SigIntId*)SCMalloc(bytes); - if (pmq->rule_id_array == NULL) { - pmq->rule_id_array_size = 0; - SCReturnInt(-1); - } - // Don't need to zero memory since it is always written first. - - SCReturnInt(0); -} - -/** \brief Add array of Signature IDs to rule ID array. - * - * Checks size of the array first - * - * \param pmq storage for match results - * \param new_size number of Signature IDs needing to be stored. - * - */ -int -PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size) -{ - /* Need to make the array bigger. Double the size needed to - * also handle the case that sids_size might still be - * larger than the old size. - */ - new_size = new_size * 2; - SigIntId *new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, - new_size * sizeof(SigIntId)); - if (unlikely(new_array == NULL)) { - /* Try again just big enough. */ - new_size = new_size / 2; - new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, - new_size * sizeof(SigIntId)); - if (unlikely(new_array == NULL)) { - - SCLogError("Failed to realloc PatternMatchQueue" - " rule ID array. Some signature ID matches lost"); - return 0; - } - } - pmq->rule_id_array = new_array; - pmq->rule_id_array_size = new_size; - - return new_size; -} - -/** \brief Reset a Pmq for reusage. Meant to be called after a single search. - * \param pmq Pattern matcher to be reset. - * \todo memset is expensive, but we need it as we merge pmq's. We might use - * a flag so we can clear pmq's the old way if we can. - */ -void PmqReset(PrefilterRuleStore *pmq) -{ - if (pmq == NULL) - return; - - PMQ_RESET(pmq); -} - -/** \brief Cleanup a Pmq - * \param pmq Pattern matcher queue to be cleaned up. - */ -void PmqCleanup(PrefilterRuleStore *pmq) -{ - if (pmq == NULL) - return; - if (pmq->rule_id_array != NULL) { - SCFree(pmq->rule_id_array); - pmq->rule_id_array = NULL; - } -} - -/** \brief Cleanup and free a Pmq - * \param pmq Pattern matcher queue to be free'd. - */ -void PmqFree(PrefilterRuleStore *pmq) -{ - if (pmq == NULL) - return; - - PmqCleanup(pmq); -} diff --git a/src/util-prefilter.h b/src/util-prefilter.h deleted file mode 100644 index 67c24d6c9de7..000000000000 --- a/src/util-prefilter.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (C) 2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_PREFILTER_H__ -#define __UTIL_PREFILTER_H__ - -#include "util-debug.h" - -/** \brief structure for storing potential rule matches - * - * Helper structure for the prefilter engine. The Pattern Matchers - * and other prefilter engines will add rule id's for potential - * rule matches */ -typedef struct PrefilterRuleStore_ { - /* used for storing rule id's */ - - /* Array of rule IDs found. */ - SigIntId *rule_id_array; - /* Number of rule IDs in the array. */ - uint32_t rule_id_array_cnt; - /* The number of slots allocated for storing rule IDs */ - uint32_t rule_id_array_size; - -} PrefilterRuleStore; - -#define PMQ_RESET(pmq) (pmq)->rule_id_array_cnt = 0 - -/* Resize Signature ID array. Only called from MpmAddSids(). */ -int PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size); - -/** \brief Add array of Signature IDs to rule ID array. - * - * Checks size of the array first. Calls PrefilterAddSidsResize to increase - * The size of the array, since that is the slow path. - * - * \param pmq storage for match results - * \param sids pointer to array of Signature IDs - * \param sids_size number of Signature IDs in sids array. - * - */ -static inline void PrefilterAddSids( - PrefilterRuleStore *pmq, const SigIntId *sids, uint32_t sids_size) -{ - if (sids_size == 0) - return; - - uint32_t new_size = pmq->rule_id_array_cnt + sids_size; - if (new_size > pmq->rule_id_array_size) { - if (PrefilterAddSidsResize(pmq, new_size) == 0) { - // Failed to allocate larger memory for all the SIDS, but - // keep as many as we can. - sids_size = pmq->rule_id_array_size - pmq->rule_id_array_cnt; - } - } - SCLogDebug("Adding %u sids", sids_size); - // Add SIDs for this pattern to the end of the array - SigIntId *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; - SigIntId *end = ptr + sids_size; - do { - *ptr++ = *sids++; - } while (ptr != end); - pmq->rule_id_array_cnt += sids_size; -} - -int PmqSetup(PrefilterRuleStore *); -void PmqReset(PrefilterRuleStore *); -void PmqCleanup(PrefilterRuleStore *); -void PmqFree(PrefilterRuleStore *); - -#endif /* __UTIL_PREFILTER_H__ */ diff --git a/src/util-print.c b/src/util-print.c deleted file mode 100644 index be87af1ccfda..000000000000 --- a/src/util-print.c +++ /dev/null @@ -1,290 +0,0 @@ -/* Copyright (C) 2007-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Print utility functions - */ - -#include "suricata-common.h" -#include "util-print.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-validate.h" -#include "rust.h" - -/** - * \brief print a buffer as hex on a single line - * - * Prints in the format "00 AA BB" - * - * \param nbuf buffer into which the output is written - * \param offset of where to start writing into the buffer - * \param max_size the size of the output buffer - * \param buf buffer to print from - * \param buflen length of the input buffer - */ -void PrintBufferRawLineHex(char *nbuf, int *offset, int max_size, const uint8_t *buf, uint32_t buflen) -{ - for (uint32_t u = 0; u < buflen; u++) { - PrintBufferData(nbuf, offset, max_size, "%02X ", buf[u]); - } -} - -/** - * \brief print a buffer as hex on a single line into retbuf buffer - * - * Prints in the format "00 AA BB" - * - * \param retbuf pointer to the buffer which will have the result - * \param rebuflen length of the buffer - * \param buf buffer to print from - * \param buflen length of the input buffer - */ -void PrintRawLineHexBuf(char *retbuf, uint32_t retbuflen, const uint8_t *buf, uint32_t buflen) -{ - uint32_t offset = 0; - for (uint32_t u = 0; u < buflen; u++) { - PrintBufferData(retbuf, &offset, retbuflen, "%02X ", buf[u]); - } -} - -void PrintRawJsonFp(FILE *fp, uint8_t *buf, uint32_t buflen) -{ -#define BUFFER_LENGTH 2048 - char nbuf[BUFFER_LENGTH] = ""; - uint32_t offset = 0; - - for (uint32_t u = 0; u < buflen; u++) { - if (buf[u] == '\\' || buf[u] == '/' || buf[u] == '\"') { - PrintBufferData(nbuf, &offset, BUFFER_LENGTH, - "\\%c", buf[u]); - } else if (isprint(buf[u])) { - PrintBufferData(nbuf, &offset, BUFFER_LENGTH, - "%c", buf[u]); - } else { - PrintBufferData(nbuf, &offset, BUFFER_LENGTH, - "\\\\x%02X", buf[u]); - } - } - fprintf(fp, "%s", nbuf); -} - -void PrintRawUriFp(FILE *fp, uint8_t *buf, uint32_t buflen) -{ -#define BUFFER_LENGTH 2048 - char nbuf[BUFFER_LENGTH] = ""; - uint32_t offset = 0; - - for (uint32_t u = 0; u < buflen; u++) { - if (isprint(buf[u]) && buf[u] != '\"') { - if (buf[u] == '\\') { - PrintBufferData(nbuf, &offset, BUFFER_LENGTH, - "\\\\"); - } else { - PrintBufferData(nbuf, &offset, BUFFER_LENGTH, - "%c", buf[u]); - } - } else { - PrintBufferData(nbuf, &offset, BUFFER_LENGTH, - "\\x%02X", buf[u]); - } - } - - fprintf(fp, "%s", nbuf); -} - -void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, - uint8_t *buf, uint32_t buflen) -{ - for (uint32_t u = 0; u < buflen; u++) { - if (isprint(buf[u]) && buf[u] != '\"') { - if (buf[u] == '\\') { - PrintBufferData(retbuf, offset, retbuflen, - "\\\\"); - } else { - PrintBufferData(retbuf, offset, retbuflen, - "%c", buf[u]); - } - } else { - PrintBufferData(retbuf, offset, retbuflen, - "\\x%02X", buf[u]); - } - } - - return; -} - -void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen) -{ - int ch = 0; - - if (buf == NULL) { - fprintf(fp, " (null)\n"); - return; - } - for (uint32_t u = 0; u < buflen; u += 16) { - fprintf(fp ," %04X ", u); - for (ch = 0; (u+ch) < buflen && ch < 16; ch++) { - fprintf(fp, "%02X ", (uint8_t)buf[u+ch]); - - if (ch == 7) fprintf(fp, " "); - } - if (ch == 16) fprintf(fp, " "); - else if (ch < 8) { - int spaces = (16 - ch) * 3 + 2 + 1; - int s = 0; - for ( ; s < spaces; s++) fprintf(fp, " "); - } else if(ch < 16) { - int spaces = (16 - ch) * 3 + 2; - int s = 0; - for ( ; s < spaces; s++) fprintf(fp, " "); - } - - for (ch = 0; (u+ch) < buflen && ch < 16; ch++) { - fprintf(fp, "%c", isprint((uint8_t)buf[u+ch]) ? (uint8_t)buf[u+ch] : '.'); - - if (ch == 7) fprintf(fp, " "); - if (ch == 15) fprintf(fp, "\n"); - } - } - if (ch != 16) - fprintf(fp, "\n"); -} - -void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - const uint8_t *src_buf, uint32_t src_buf_len) -{ - int ch = 0; - - for (uint32_t u = 0; u < src_buf_len; u += 16) { - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, - " %04X ", u); - for (ch = 0; (u + ch) < src_buf_len && ch < 16; ch++) { - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, - "%02X ", (uint8_t)src_buf[u + ch]); - - if (ch == 7) { - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, - " "); - } - } - if (ch == 16) { - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); - } else if (ch < 8) { - int spaces = (16 - ch) * 3 + 2 + 1; - int s = 0; - for ( ; s < spaces; s++) - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); - } else if(ch < 16) { - int spaces = (16 - ch) * 3 + 2; - int s = 0; - for ( ; s < spaces; s++) - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); - } - - for (ch = 0; (u+ch) < src_buf_len && ch < 16; ch++) { - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, - "%c", - isprint((uint8_t)src_buf[u + ch]) ? (uint8_t)src_buf[u + ch] : '.'); - - if (ch == 7) - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); - if (ch == 15) - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "\n"); - } - } - if (ch != 16) - PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "\n"); - - return; -} - -void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - const uint8_t *src_buf, const uint32_t src_buf_len) -{ - for (uint32_t ch = 0; ch < src_buf_len && *dst_buf_offset_ptr < dst_buf_size; - ch++, (*dst_buf_offset_ptr)++) { - if (isprint((uint8_t)src_buf[ch]) || src_buf[ch] == '\n' || src_buf[ch] == '\r') { - dst_buf[*dst_buf_offset_ptr] = src_buf[ch]; - } else { - dst_buf[*dst_buf_offset_ptr] = '.'; - } - } - dst_buf[dst_buf_size - 1] = 0; - - return; -} - -#ifndef s6_addr16 -# define s6_addr16 __u6_addr.__u6_addr16 -#endif - -static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size) -{ - char s_part[6]; - uint16_t x[8]; - memcpy(&x, src, 16); - - /* current IPv6 format is fixed size */ - if (size < 8 * 5) { - SCLogWarning("Too small buffer to write IPv6 address"); - return NULL; - } - memset(dst, 0, size); - for (int i = 0; i < 8; i++) { - snprintf(s_part, sizeof(s_part), "%04x:", htons(x[i])); - strlcat(dst, s_part, size); - } - /* suppress last ':' */ - dst[strlen(dst) - 1] = 0; - - return dst; -} - -const char *PrintInet(int af, const void *src, char *dst, socklen_t size) -{ - switch (af) { - case AF_INET: -#if defined(OS_WIN32) && NTDDI_VERSION >= NTDDI_VISTA -{ - // because Windows has to provide a non-conformant inet_ntop, of - // course! - struct in_addr _src; - memcpy(&_src, src, sizeof(struct in_addr)); - return inet_ntop(af, &_src, dst, size); -} -#else - return inet_ntop(af, src, dst, size); -#endif - case AF_INET6: - /* Format IPv6 without deleting zeroes */ - return PrintInetIPv6(src, dst, size); - default: - SCLogError("Unsupported protocol: %d", af); - } - return NULL; -} - -void PrintHexString(char *str, size_t size, uint8_t *buf, size_t buf_len) -{ - DEBUG_VALIDATE_BUG_ON(size < 2 * buf_len); - rs_to_hex((uint8_t *)str, size, buf, buf_len); -} diff --git a/src/util-print.h b/src/util-print.h deleted file mode 100644 index 249ec20f7353..000000000000 --- a/src/util-print.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - - - -#ifndef __UTIL_PRINT_H__ -#define __UTIL_PRINT_H__ - -#define PrintBufferData(buf, buf_offset_ptr, buf_size, ...) do { \ - int cw = snprintf((buf) + *(buf_offset_ptr), \ - (buf_size) - *(buf_offset_ptr), \ - __VA_ARGS__); \ - if (cw >= 0) { \ - if ( (*(buf_offset_ptr) + cw) >= buf_size) { \ - SCLogDebug("Truncating data write since it exceeded buffer " \ - "limit of - %"PRIu32"\n", buf_size); \ - *(buf_offset_ptr) = buf_size - 1; \ - } else { \ - *(buf_offset_ptr) += cw; \ - } \ - } \ - } while (0) - -void PrintBufferRawLineHex(char *, int *,int, const uint8_t *, uint32_t); -void PrintRawUriFp(FILE *, uint8_t *, uint32_t); -void PrintRawUriBuf(char *, uint32_t *, uint32_t, - uint8_t *, uint32_t); -void PrintRawJsonFp(FILE *, uint8_t *, uint32_t); -void PrintRawDataFp(FILE *, const uint8_t *, uint32_t); -void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - const uint8_t *src_buf, uint32_t src_buf_len); -void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - const uint8_t *src_buf, const uint32_t src_buf_len); -void PrintRawLineHexBuf(char *, uint32_t, const uint8_t *, uint32_t ); -const char *PrintInet(int , const void *, char *, socklen_t); -void PrintHexString(char *str, size_t size, uint8_t *buf, size_t buf_len); - -#endif /* __UTIL_PRINT_H__ */ - diff --git a/src/util-privs.c b/src/util-privs.c deleted file mode 100644 index 3a1ea485159a..000000000000 --- a/src/util-privs.c +++ /dev/null @@ -1,262 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - * - * File to drop the engine capabilities using libcap-ng by - * Steve Grubb - */ - -#ifndef OS_WIN32 - -#include "suricata-common.h" -#include "util-debug.h" -#include "suricata.h" - -#include "util-privs.h" -#include "util-byte.h" - -#ifdef HAVE_LIBCAP_NG - -#include -#ifdef HAVE_SYS_PRCTL_H -#include -#endif -#include "threadvars.h" -#include "util-cpu.h" -#include "runmodes.h" - -/** flag indicating if we'll be using caps */ -extern bool sc_set_caps; - -/** our current runmode */ -extern int run_mode; - -/** - * \brief Drop the privileges of the main thread - */ -void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) -{ - if (!sc_set_caps) - return; - - capng_clear(CAPNG_SELECT_BOTH); - - switch (run_mode) { - case RUNMODE_PCAP_DEV: - case RUNMODE_AFP_DEV: - case RUNMODE_AFXDP_DEV: - capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, - CAP_NET_RAW, /* needed for pcap live mode */ - CAP_SYS_NICE, - CAP_NET_ADMIN, - -1); - break; - case RUNMODE_PFRING: - capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, - CAP_NET_ADMIN, CAP_NET_RAW, CAP_SYS_NICE, - -1); - break; - case RUNMODE_NFLOG: - case RUNMODE_NFQ: - capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, - CAP_NET_ADMIN, /* needed for nflog and nfqueue inline mode */ - CAP_SYS_NICE, - -1); - break; - } - - if (capng_change_id(userid, groupid, CAPNG_DROP_SUPP_GRP | - CAPNG_CLEAR_BOUNDING) < 0) - { - FatalError("capng_change_id for main thread" - " failed"); - } - - SCLogInfo("dropped the caps for main thread"); -} - -void SCDropCaps(ThreadVars *tv) -{ -#if 0 - capng_clear(CAPNG_SELECT_BOTH); - capng_apply(CAPNG_SELECT_BOTH); - if (tv->cap_flags & SC_CAP_IPC_LOCK) { - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); - capng_apply(CAPNG_SELECT_CAPS); - SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); - } - if (tv->cap_flags & SC_CAP_NET_ADMIN) { - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); - capng_apply(CAPNG_SELECT_CAPS); - SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); - } - if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); - capng_apply(CAPNG_SELECT_CAPS); - SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); - } - if (tv->cap_flags & SC_CAP_NET_BROADCAST) { - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); - capng_apply(CAPNG_SELECT_CAPS); - SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); - } - if (tv->cap_flags & SC_CAP_NET_RAW) { - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); - capng_apply(CAPNG_SELECT_CAPS); - SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); - } - if (tv->cap_flags & SC_CAP_SYS_ADMIN) { - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); - capng_apply(CAPNG_SELECT_CAPS); - SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); - } - if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); - capng_apply(CAPNG_SELECT_CAPS); - SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); - } -#endif -} - -#endif /* HAVE_LIBCAP_NG */ - -/** - * \brief Function to get the user and group ID from the specified user name - * - * \param user_name pointer to the given user name - * \param uid pointer to the user id in which result will be stored - * \param gid pointer to the group id in which result will be stored - * - * \retval FatalError on a failure - */ -void SCGetUserID(const char *user_name, const char *group_name, uint32_t *uid, uint32_t *gid) -{ - uint32_t userid = 0; - uint32_t groupid = 0; - struct passwd *pw; - - if (user_name == NULL || strlen(user_name) == 0) { - FatalError("no user name was provided - ensure it is specified either in the configuration " - "file (run-as.user) or in command-line arguments (--user)"); - } - - /* Get the user ID */ - if (isdigit((unsigned char)user_name[0]) != 0) { - if (ByteExtractStringUint32(&userid, 10, 0, (const char *)user_name) < 0) { - FatalError("invalid user id value: '%s'", user_name); - } - pw = getpwuid(userid); - if (pw == NULL) { - FatalError("unable to get the user ID, " - "check if user exist!!"); - } - } else { - pw = getpwnam(user_name); - if (pw == NULL) { - FatalError("unable to get the user ID, " - "check if user exist!!"); - } - userid = pw->pw_uid; - } - - /* Get the group ID */ - if (group_name != NULL) { - struct group *gp; - - if (isdigit((unsigned char)group_name[0]) != 0) { - if (ByteExtractStringUint32(&groupid, 10, 0, (const char *)group_name) < 0) { - FatalError("invalid group id: '%s'", group_name); - } - } else { - gp = getgrnam(group_name); - if (gp == NULL) { - FatalError("unable to get the group" - " ID, check if group exist!!"); - } - groupid = gp->gr_gid; - } - } else { - groupid = pw->pw_gid; - } - - /* close the group database */ - endgrent(); - /* close the user database */ - endpwent(); - - *uid = userid; - *gid = groupid; -} - -/** - * \brief Function to get the group ID from the specified group name - * - * \param group_name pointer to the given group name - * \param gid pointer to the group id in which result will be stored - * - * \retval FatalError on a failure - */ -void SCGetGroupID(const char *group_name, uint32_t *gid) -{ - uint32_t grpid = 0; - struct group *gp; - - if (group_name == NULL || strlen(group_name) == 0) { - FatalError("no group name was provided - ensure it is specified either in the " - "configuration file (run-as.group) or in command-line arguments (--group)"); - } - - /* Get the group ID */ - if (isdigit((unsigned char)group_name[0]) != 0) { - if (ByteExtractStringUint32(&grpid, 10, 0, (const char *)group_name) < 0) { - FatalError("invalid group id: '%s'", group_name); - } - } else { - gp = getgrnam(group_name); - if (gp == NULL) { - FatalError("unable to get the group ID," - " check if group exist!!"); - } - grpid = gp->gr_gid; - } - - /* close the group database */ - endgrent(); - - *gid = grpid; -} - -#ifdef __OpenBSD__ -int SCPledge(void) -{ - int ret = pledge("stdio rpath wpath cpath fattr unix dns bpf", NULL); - - if (ret != 0) { - SCLogError("unable to pledge," - " check permissions!! ret=%i errno=%i", - ret, errno); - exit(EXIT_FAILURE); - } - - return 0; -} -#endif /* __OpenBSD__ */ -#endif /* OS_WIN32 */ diff --git a/src/util-privs.h b/src/util-privs.h deleted file mode 100644 index 454533963d34..000000000000 --- a/src/util-privs.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - */ - -#ifndef _UTIL_PRIVS_H -#define _UTIL_PRIVS_H - -#define SC_CAP_NONE 0x01 -#define SC_CAP_SYS_ADMIN 0x02 -#define SC_CAP_SYS_RAW_IO 0x04 -#define SC_CAP_IPC_LOCK 0x08 -#define SC_CAP_NET_ADMIN 0x10 -#define SC_CAP_NET_RAW 0x20 -#define SC_CAP_NET_BIND_SERVICE 0x40 -#define SC_CAP_NET_BROADCAST 0x80 - -#ifdef HAVE_LIBCAP_NG -#include -#include "threadvars.h" - -/**Drop the privileges of the given thread tv, based on the thread cap_flags - * which implies the capability requirement of the given thread. Initially all - * caps are dropped and later, the required caps are set for the given thread - */ -void SCDropCaps(ThreadVars *tv); -/* -#define SCDropCaps(tv) ({ \ - capng_clear(CAPNG_SELECT_BOTH); \ - capng_apply(CAPNG_SELECT_BOTH); \ - if (tv->cap_flags & SC_CAP_IPC_LOCK) { \ - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); \ - capng_apply(CAPNG_SELECT_CAPS); \ - SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); \ - } \ - if (tv->cap_flags & SC_CAP_NET_ADMIN) { \ - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); \ - capng_apply(CAPNG_SELECT_CAPS); \ - SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); \ - } \ - if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { \ - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); \ - capng_apply(CAPNG_SELECT_CAPS); \ - SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); \ - } \ - if (tv->cap_flags & SC_CAP_NET_BROADCAST) { \ - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); \ - capng_apply(CAPNG_SELECT_CAPS); \ - SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); \ - } \ - if (tv->cap_flags & SC_CAP_NET_RAW) { \ - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); \ - capng_apply(CAPNG_SELECT_CAPS); \ - SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); \ - } \ - if (tv->cap_flags & SC_CAP_SYS_ADMIN) { \ - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); \ - capng_apply(CAPNG_SELECT_CAPS); \ - SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); \ - } \ - if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { \ - capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); \ - capng_apply(CAPNG_SELECT_CAPS); \ - SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); \ - } \ -}) -*/ -void SCDropMainThreadCaps(uint32_t , uint32_t ); - -#else -#define SCDropCaps(...) -#define SCDropMainThreadCaps(...) -#endif /* HAVE_LIBCAP_NG */ - -void SCGetUserID(const char *, const char *, uint32_t *, uint32_t *); -void SCGetGroupID(const char *, uint32_t *); - -#ifdef __OpenBSD__ -int SCPledge(void); -#else /* __OpenBSD__ */ -#define SCPledge(...) -#endif /* __OpenBSD__ */ - -#endif /* _UTIL_PRIVS_H */ - diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c deleted file mode 100644 index c0620a751bcd..000000000000 --- a/src/util-profiling-keywords.c +++ /dev/null @@ -1,390 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Endace Technology Limited. - * \author Victor Julien - * - * An API for rule profiling operations. - */ - -#include "suricata-common.h" -#include "util-profiling.h" -#include "util-profiling-locks.h" - -#ifdef PROFILING -#include "detect-engine.h" -#include "tm-threads.h" -#include "util-conf.h" -#include "util-time.h" - -/** - * Extra data for rule profiling. - */ -typedef struct SCProfileKeywordData_ { - uint64_t checks; - uint64_t matches; - uint64_t max; - uint64_t ticks_match; - uint64_t ticks_no_match; -} SCProfileKeywordData; - -typedef struct SCProfileKeywordDetectCtx_ { - uint32_t id; - SCProfileKeywordData *data; - pthread_mutex_t data_m; -} SCProfileKeywordDetectCtx; - -static int profiling_keywords_output_to_file = 0; -int profiling_keyword_enabled = 0; -thread_local int profiling_keyword_entered = 0; -static char profiling_file_name[PATH_MAX]; -static const char *profiling_file_mode = "a"; - -void SCProfilingKeywordsGlobalInit(void) -{ - ConfNode *conf; - - conf = ConfGetNode("profiling.keywords"); - if (conf != NULL) { - if (ConfNodeChildValueIsTrue(conf, "enabled")) { - profiling_keyword_enabled = 1; - const char *filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename != NULL) { - const char *log_dir; - log_dir = ConfigGetLogDirectory(); - - snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", - log_dir, filename); - - const char *v = ConfNodeLookupChildValue(conf, "append"); - if (v == NULL || ConfValIsTrue(v)) { - profiling_file_mode = "a"; - } else { - profiling_file_mode = "w"; - } - - profiling_keywords_output_to_file = 1; - } - } - } -} - -static void DoDump(SCProfileKeywordDetectCtx *rules_ctx, FILE *fp, const char *name) -{ - int i; - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Stats for: %s\n", name); - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " %-16s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Keyword", "Ticks", "Checks", "Matches", "Max Ticks", "Avg", "Avg Match", "Avg No Match"); - fprintf(fp, " ---------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "\n"); - for (i = 0; i < DETECT_TBLSIZE; i++) { - SCProfileKeywordData *d = &rules_ctx->data[i]; - if (d == NULL || d->checks == 0) - continue; - - uint64_t ticks = d->ticks_match + d->ticks_no_match; - double avgticks = 0; - double avgticks_match = 0; - double avgticks_no_match = 0; - if (ticks && d->checks) { - avgticks = (double)(ticks / d->checks); - - if (d->ticks_match && d->matches) - avgticks_match = (double)(d->ticks_match / d->matches); - if (d->ticks_no_match && (d->checks - d->matches) != 0) - avgticks_no_match = (double)(d->ticks_no_match / (d->checks - d->matches)); - } - - fprintf(fp, - " %-16s %-15"PRIu64" %-15"PRIu64" %-15"PRIu64" %-15"PRIu64" %-15.2f %-15.2f %-15.2f\n", - sigmatch_table[i].name, - ticks, - d->checks, - d->matches, - d->max, - avgticks, - avgticks_match, - avgticks_no_match); - } -} - -static void -SCProfilingKeywordDump(DetectEngineCtx *de_ctx) -{ - int i; - FILE *fp; - struct timeval tval; - struct tm *tms; - struct tm local_tm; - - if (profiling_keyword_enabled == 0) - return; - - const int nlists = de_ctx->buffer_type_id; - gettimeofday(&tval, NULL); - tms = SCLocalTime(tval.tv_sec, &local_tm); - - if (profiling_keywords_output_to_file == 1) { - SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); - - fp = fopen(profiling_file_name, profiling_file_mode); - - if (fp == NULL) { - SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); - return; - } - } else { - fp = stdout; - } - - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, - tms->tm_hour,tms->tm_min, tms->tm_sec); - - /* global stats first */ - DoDump(de_ctx->profile_keyword_ctx, fp, "total"); - /* per buffer stats next, but only if there are stats to print */ - for (i = 0; i < nlists; i++) { - int j; - uint64_t checks = 0; - for (j = 0; j < DETECT_TBLSIZE; j++) { - checks += de_ctx->profile_keyword_ctx_per_list[i]->data[j].checks; - } - - if (checks) { - const char *name = NULL; - if (i < DETECT_SM_LIST_DYNAMIC_START) { - name = DetectSigmatchListEnumToString(i); - } else { - name = DetectEngineBufferTypeGetNameById(de_ctx, i); - } - - DoDump(de_ctx->profile_keyword_ctx_per_list[i], fp, name); - } - } - - fprintf(fp,"\n"); - if (fp != stdout) - fclose(fp); - - SCLogPerf("Done dumping keyword profiling data."); -} - -/** - * \brief Update a rule counter. - * - * \param id The ID of this counter. - * \param ticks Number of CPU ticks for this rule. - * \param match Did the rule match? - */ -void -SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, int match) -{ - if (det_ctx != NULL && det_ctx->keyword_perf_data != NULL && id < DETECT_TBLSIZE) { - SCProfileKeywordData *p = &det_ctx->keyword_perf_data[id]; - - p->checks++; - p->matches += match; - if (ticks > p->max) - p->max = ticks; - if (match == 1) - p->ticks_match += ticks; - else - p->ticks_no_match += ticks; - - /* store per list (buffer type) as well */ - if (det_ctx->keyword_perf_list >= 0) {// && det_ctx->keyword_perf_list < DETECT_SM_LIST_MAX) { - p = &det_ctx->keyword_perf_data_per_list[det_ctx->keyword_perf_list][id]; - p->checks++; - p->matches += match; - if (ticks > p->max) - p->max = ticks; - if (match == 1) - p->ticks_match += ticks; - else - p->ticks_no_match += ticks; - } - } -} - -static SCProfileKeywordDetectCtx *SCProfilingKeywordInitCtx(void) -{ - SCProfileKeywordDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileKeywordDetectCtx)); - if (ctx != NULL) { - - if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { - FatalError("Failed to initialize hash table mutex."); - } - } - - return ctx; -} - -static void DetroyCtx(SCProfileKeywordDetectCtx *ctx) -{ - if (ctx) { - if (ctx->data != NULL) - SCFree(ctx->data); - pthread_mutex_destroy(&ctx->data_m); - SCFree(ctx); - } -} - -void SCProfilingKeywordDestroyCtx(DetectEngineCtx *de_ctx) -{ - if (de_ctx != NULL) { - SCProfilingKeywordDump(de_ctx); - - DetroyCtx(de_ctx->profile_keyword_ctx); - - const int nlists = de_ctx->buffer_type_id; - int i; - for (i = 0; i < nlists; i++) { - DetroyCtx(de_ctx->profile_keyword_ctx_per_list[i]); - } - SCFree(de_ctx->profile_keyword_ctx_per_list); - } -} - -void SCProfilingKeywordThreadSetup(SCProfileKeywordDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) -{ - if (ctx == NULL) - return; - - SCProfileKeywordData *a = SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); - if (a != NULL) { - det_ctx->keyword_perf_data = a; - } - - const int nlists = det_ctx->de_ctx->buffer_type_id; - det_ctx->keyword_perf_data_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordData *)); - BUG_ON(det_ctx->keyword_perf_data_per_list == NULL); - - int i; - for (i = 0; i < nlists; i++) { - SCProfileKeywordData *b = SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); - if (b != NULL) { - det_ctx->keyword_perf_data_per_list[i] = b; - } - } -} - -static void SCProfilingKeywordThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) -{ - if (de_ctx == NULL || de_ctx->profile_keyword_ctx == NULL || - de_ctx->profile_keyword_ctx->data == NULL || det_ctx == NULL || - det_ctx->keyword_perf_data == NULL) - return; - - int i; - for (i = 0; i < DETECT_TBLSIZE; i++) { - de_ctx->profile_keyword_ctx->data[i].checks += det_ctx->keyword_perf_data[i].checks; - de_ctx->profile_keyword_ctx->data[i].matches += det_ctx->keyword_perf_data[i].matches; - de_ctx->profile_keyword_ctx->data[i].ticks_match += det_ctx->keyword_perf_data[i].ticks_match; - de_ctx->profile_keyword_ctx->data[i].ticks_no_match += det_ctx->keyword_perf_data[i].ticks_no_match; - if (det_ctx->keyword_perf_data[i].max > de_ctx->profile_keyword_ctx->data[i].max) - de_ctx->profile_keyword_ctx->data[i].max = det_ctx->keyword_perf_data[i].max; - } - - const int nlists = det_ctx->de_ctx->buffer_type_id; - int j; - for (j = 0; j < nlists; j++) { - for (i = 0; i < DETECT_TBLSIZE; i++) { - de_ctx->profile_keyword_ctx_per_list[j]->data[i].checks += det_ctx->keyword_perf_data_per_list[j][i].checks; - de_ctx->profile_keyword_ctx_per_list[j]->data[i].matches += det_ctx->keyword_perf_data_per_list[j][i].matches; - de_ctx->profile_keyword_ctx_per_list[j]->data[i].ticks_match += det_ctx->keyword_perf_data_per_list[j][i].ticks_match; - de_ctx->profile_keyword_ctx_per_list[j]->data[i].ticks_no_match += det_ctx->keyword_perf_data_per_list[j][i].ticks_no_match; - if (det_ctx->keyword_perf_data_per_list[j][i].max > de_ctx->profile_keyword_ctx_per_list[j]->data[i].max) - de_ctx->profile_keyword_ctx_per_list[j]->data[i].max = det_ctx->keyword_perf_data_per_list[j][i].max; - } - } -} - -void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *det_ctx) -{ - if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->keyword_perf_data == NULL) - return; - - pthread_mutex_lock(&det_ctx->de_ctx->profile_keyword_ctx->data_m); - SCProfilingKeywordThreadMerge(det_ctx->de_ctx, det_ctx); - pthread_mutex_unlock(&det_ctx->de_ctx->profile_keyword_ctx->data_m); - - SCFree(det_ctx->keyword_perf_data); - det_ctx->keyword_perf_data = NULL; - - const int nlists = det_ctx->de_ctx->buffer_type_id; - int i; - for (i = 0; i < nlists; i++) { - SCFree(det_ctx->keyword_perf_data_per_list[i]); - det_ctx->keyword_perf_data_per_list[i] = NULL; - } - SCFree(det_ctx->keyword_perf_data_per_list); -} - -/** - * \brief Register the keyword profiling counters. - * - * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. - */ -void -SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) -{ - if (profiling_keyword_enabled == 0) - return; - - const int nlists = de_ctx->buffer_type_id; - - de_ctx->profile_keyword_ctx = SCProfilingKeywordInitCtx(); - BUG_ON(de_ctx->profile_keyword_ctx == NULL); - - de_ctx->profile_keyword_ctx->data = SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); - BUG_ON(de_ctx->profile_keyword_ctx->data == NULL); - - de_ctx->profile_keyword_ctx_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordDetectCtx *)); - BUG_ON(de_ctx->profile_keyword_ctx_per_list == NULL); - - int i; - for (i = 0; i < nlists; i++) { - de_ctx->profile_keyword_ctx_per_list[i] = SCProfilingKeywordInitCtx(); - BUG_ON(de_ctx->profile_keyword_ctx_per_list[i] == NULL); - de_ctx->profile_keyword_ctx_per_list[i]->data = - SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); - BUG_ON(de_ctx->profile_keyword_ctx_per_list[i]->data == NULL); - } - - SCLogPerf("Registered %"PRIu32" keyword profiling counters.", DETECT_TBLSIZE); -} - -#endif /* PROFILING */ diff --git a/src/util-profiling-locks.c b/src/util-profiling-locks.c deleted file mode 100644 index 00f9ef652a30..000000000000 --- a/src/util-profiling-locks.c +++ /dev/null @@ -1,242 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * An API for profiling locks. - * - */ - -#include "suricata-common.h" -#include "util-profiling-locks.h" - -#ifdef PROFILING -#ifdef PROFILE_LOCKING -#include "threads.h" -#include "util-hashlist.h" -#include "util-debug.h" - -thread_local ProfilingLock locks[PROFILING_MAX_LOCKS]; -thread_local int locks_idx = 0; -thread_local int record_locks = 0; - -int profiling_locks_enabled = 0; -int profiling_locks_output_to_file = 0; -char *profiling_locks_file_name = NULL; -const char *profiling_locks_file_mode = "a"; - -typedef struct LockRecord_ { - char *file; // hash - - char *func; // info - int type; // info - - int line; // hash - - uint32_t cont; - uint32_t ticks_cnt; - uint64_t ticks_total; - uint64_t ticks_max; -} LockRecord; - -HashListTable *lock_records; -pthread_mutex_t lock_records_mutex; - -static uint32_t LockRecordHash(HashListTable *ht, void *buf, uint16_t buflen) -{ - LockRecord *fn = (LockRecord *)buf; - uint32_t hash = strlen(fn->file) + fn->line; - uint16_t u; - - for (u = 0; u < strlen(fn->file); u++) { - hash += fn->file[u]; - } - - return hash % ht->array_size; -} - -static char LockRecordCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) -{ - LockRecord *fn1 = (LockRecord *)buf1; - LockRecord *fn2 = (LockRecord *)buf2; - - if (fn1->line != fn2->line) - return 0; - - if (fn1->file == fn2->file) - return 1; - - return 0; -} - -static void LockRecordFree(void *data) -{ - LockRecord *fn = (LockRecord *)data; - - if (fn == NULL) - return; - SCFree(fn); -} - -int LockRecordInitHash(void) -{ - pthread_mutex_init(&lock_records_mutex, NULL); - pthread_mutex_lock(&lock_records_mutex); - - lock_records = HashListTableInit(512, LockRecordHash, LockRecordCompare, LockRecordFree); - BUG_ON(lock_records == NULL); - - pthread_mutex_unlock(&lock_records_mutex); - - return 0; -} - -static void LockRecordAdd(ProfilingLock *l) -{ - LockRecord fn = { NULL, NULL, 0,0,0,0,0,0}, *ptr = &fn; - fn.file = l->file; - fn.line = l->line; - - LockRecord *lookup_fn = (LockRecord *)HashListTableLookup(lock_records, (void *)ptr, 0); - if (lookup_fn == NULL) { - LockRecord *new = SCMalloc(sizeof(LockRecord)); - BUG_ON(new == NULL); - - new->file = l->file; - new->line = l->line; - new->type = l->type; - new->cont = l->cont; - new->func = l->func; - new->ticks_max = l->ticks; - new->ticks_total = l->ticks; - new->ticks_cnt = 1; - - HashListTableAdd(lock_records, (void *)new, 0); - } else { - lookup_fn->ticks_total += l->ticks; - if (l->ticks > lookup_fn->ticks_max) - lookup_fn->ticks_max = l->ticks; - lookup_fn->ticks_cnt++; - lookup_fn->cont += l->cont; - } - - return; -} - -/** \param p void ptr to Packet struct */ -void SCProfilingAddPacketLocks(void *p) -{ - int i; - - if (profiling_locks_enabled == 0) - return; - - for (i = 0; i < locks_idx; i++) { - pthread_mutex_lock(&lock_records_mutex); - LockRecordAdd(&locks[i]); - pthread_mutex_unlock(&lock_records_mutex); - } -} - -static void SCProfilingListLocks(void) -{ - FILE *fp = NULL; - - if (profiling_locks_output_to_file == 1) { - fp = fopen(profiling_locks_file_name, profiling_locks_file_mode); - - if (fp == NULL) { - SCLogError("failed to open %s: %s", profiling_locks_file_name, strerror(errno)); - return; - } - } else { - fp = stdout; - } - - fprintf(fp, "\n\nLock Cnt Avg ticks Max ticks Total ticks Cont Func\n"); - fprintf(fp, "------------------ ---------- --------- ------------ ------------ ------- ---------\n"); - - uint64_t total = 0; - uint32_t cont = 0; - uint64_t cnt = 0; - - HashListTableBucket *b = HashListTableGetListHead(lock_records); - while (b) { - LockRecord *r = HashListTableGetListData(b); - - const char *lock; - switch (r->type) { - case LOCK_MUTEX: - lock = "mtx"; - break; - case LOCK_SPIN: - lock = "spn"; - break; - case LOCK_RWW: - lock = "rww"; - break; - case LOCK_RWR: - lock = "rwr"; - break; - default: - lock = "bug"; - break; - } - - char str[128] = ""; - snprintf(str, sizeof(str), "(%s) %s:%d", lock,r->file, r->line); - - fprintf(fp, "%-50s %-10u %-9"PRIu64" %-12"PRIu64" %-12"PRIu64" %-7u %-s\n", - str, r->ticks_cnt, (uint64_t)((uint64_t)r->ticks_total/(uint64_t)r->ticks_cnt), r->ticks_max, r->ticks_total, r->cont, r->func); - - total += r->ticks_total; - cnt += r->ticks_cnt; - cont += r->cont; - - b = HashListTableGetListNext(b); - } - - fprintf(fp, "\nOverall: locks %"PRIu64", average cost %"PRIu64", contentions %"PRIu32", total ticks %"PRIu64"\n", - cnt, (uint64_t)((uint64_t)total/(uint64_t)cnt), cont, total); - - fclose(fp); -} - -void LockRecordFreeHash(void) -{ - if (profiling_locks_enabled == 0) - return; - - pthread_mutex_lock(&lock_records_mutex); - - SCProfilingListLocks(); - - if (lock_records != NULL) { - HashListTableFree(lock_records); - lock_records = NULL; - } - pthread_mutex_unlock(&lock_records_mutex); - - pthread_mutex_destroy(&lock_records_mutex); -} - -#endif -#endif - diff --git a/src/util-profiling-locks.h b/src/util-profiling-locks.h deleted file mode 100644 index 08d745a72182..000000000000 --- a/src/util-profiling-locks.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_PROFILE_LOCKS_H__ -#define __UTIL_PROFILE_LOCKS_H__ - -#ifdef PROFILING - -void SCProfilingAddPacketLocks(void *); - -int LockRecordInitHash(void); -void LockRecordFreeHash(void); - -#endif /* PROFILING */ -#endif /* __UTIL_PROFILE_LOCKS_H__ */ - diff --git a/src/util-profiling-prefilter.c b/src/util-profiling-prefilter.c deleted file mode 100644 index 958846ae68c6..000000000000 --- a/src/util-profiling-prefilter.c +++ /dev/null @@ -1,324 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Endace Technology Limited. - * \author Victor Julien - * - * An API for rule profiling operations. - */ - -#include "suricata-common.h" -#include "util-profiling.h" - -#ifdef PROFILING -#include "detect-engine-prefilter.h" -#include "util-conf.h" -#include "util-time.h" - -typedef struct SCProfilePrefilterData_ { - uint64_t called; - uint64_t total; - uint64_t max; - uint64_t total_bytes; - uint64_t max_bytes; - uint64_t bytes_called; /**< number of times total_bytes was updated. Differs from `called` as a - prefilter engine may skip mpm if the smallest pattern is bigger than - the buffer to inspect. */ - const char *name; -} SCProfilePrefilterData; - -typedef struct SCProfilePrefilterDetectCtx_ { - uint32_t id; - uint32_t size; /**< size in elements */ - SCProfilePrefilterData *data; - pthread_mutex_t data_m; -} SCProfilePrefilterDetectCtx; - -static int profiling_prefilter_output_to_file = 0; -int profiling_prefilter_enabled = 0; -thread_local int profiling_prefilter_entered = 0; -static char profiling_file_name[PATH_MAX]; -static const char *profiling_file_mode = "a"; - -void SCProfilingPrefilterGlobalInit(void) -{ - ConfNode *conf; - - conf = ConfGetNode("profiling.prefilter"); - if (conf != NULL) { - if (ConfNodeChildValueIsTrue(conf, "enabled")) { - profiling_prefilter_enabled = 1; - const char *filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename != NULL) { - const char *log_dir; - log_dir = ConfigGetLogDirectory(); - - snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", - log_dir, filename); - - const char *v = ConfNodeLookupChildValue(conf, "append"); - if (v == NULL || ConfValIsTrue(v)) { - profiling_file_mode = "a"; - } else { - profiling_file_mode = "w"; - } - - profiling_prefilter_output_to_file = 1; - } - } - } -} - -static void DoDump(SCProfilePrefilterDetectCtx *rules_ctx, FILE *fp, const char *name) -{ - int i; - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Stats for: %s\n", name); - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " %-32s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Prefilter", - "Ticks", "Called", "Max Ticks", "Avg", "Bytes", "Called", "Max Bytes", "Avg Bytes", - "Ticks/Byte"); - fprintf(fp, " -------------------------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "\n"); - for (i = 0; i < (int)rules_ctx->size; i++) { - SCProfilePrefilterData *d = &rules_ctx->data[i]; - if (d == NULL || d->called== 0) - continue; - - uint64_t ticks = d->total; - double avgticks = 0; - if (ticks && d->called) { - avgticks = (double)(ticks / d->called); - } - double avgbytes = 0; - if (d->total_bytes && d->bytes_called) { - avgbytes = (double)(d->total_bytes / d->bytes_called); - } - double ticks_per_byte = 0; - if (ticks && d->total_bytes) { - ticks_per_byte = (double)(ticks / d->total_bytes); - } - - fprintf(fp, - " %-32s %-15" PRIu64 " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15" PRIu64 - " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15.2f\n", - d->name, ticks, d->called, d->max, avgticks, d->total_bytes, d->bytes_called, - d->max_bytes, avgbytes, ticks_per_byte); - } -} - -static void -SCProfilingPrefilterDump(DetectEngineCtx *de_ctx) -{ - FILE *fp; - struct timeval tval; - struct tm *tms; - struct tm local_tm; - - if (profiling_prefilter_enabled == 0 || de_ctx->profile_prefilter_ctx == NULL) - return; - - gettimeofday(&tval, NULL); - tms = SCLocalTime(tval.tv_sec, &local_tm); - - if (profiling_prefilter_output_to_file == 1) { - SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); - - fp = fopen(profiling_file_name, profiling_file_mode); - - if (fp == NULL) { - SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); - return; - } - } else { - fp = stdout; - } - - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, - tms->tm_hour,tms->tm_min, tms->tm_sec); - - /* global stats first */ - DoDump(de_ctx->profile_prefilter_ctx, fp, "total"); - - fprintf(fp,"\n"); - if (fp != stdout) - fclose(fp); - - SCLogPerf("Done dumping prefilter profiling data."); -} - -/** - * \brief Update a rule counter. - * - * \param id The ID of this counter. - * \param ticks Number of CPU ticks for this rule. - * \param match Did the rule match? - */ -void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, - uint64_t bytes, uint64_t bytes_called) -{ - if (det_ctx != NULL && det_ctx->prefilter_perf_data != NULL && - id < (int)det_ctx->de_ctx->prefilter_id) - { - SCProfilePrefilterData *p = &det_ctx->prefilter_perf_data[id]; - - p->called++; - if (ticks > p->max) - p->max = ticks; - p->total += ticks; - - p->bytes_called += bytes_called; - if (bytes > p->max_bytes) - p->max_bytes = bytes; - p->total_bytes += bytes; - } -} - -static SCProfilePrefilterDetectCtx *SCProfilingPrefilterInitCtx(void) -{ - SCProfilePrefilterDetectCtx *ctx = SCCalloc(1, sizeof(SCProfilePrefilterDetectCtx)); - if (ctx != NULL) { - if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { - FatalError("Failed to initialize hash table mutex."); - } - } - - return ctx; -} - -static void DetroyCtx(SCProfilePrefilterDetectCtx *ctx) -{ - if (ctx) { - if (ctx->data != NULL) - SCFree(ctx->data); - pthread_mutex_destroy(&ctx->data_m); - SCFree(ctx); - } -} - -void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *de_ctx) -{ - if (de_ctx != NULL) { - SCProfilingPrefilterDump(de_ctx); - - DetroyCtx(de_ctx->profile_prefilter_ctx); - } -} - -void SCProfilingPrefilterThreadSetup(SCProfilePrefilterDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) -{ - if (ctx == NULL) - return; - - const uint32_t size = det_ctx->de_ctx->prefilter_id; - - SCProfilePrefilterData *a = SCCalloc(1, sizeof(SCProfilePrefilterData) * size); - if (a != NULL) { - det_ctx->prefilter_perf_data = a; - } -} - -static void SCProfilingPrefilterThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) -{ - if (de_ctx == NULL || de_ctx->profile_prefilter_ctx == NULL || - de_ctx->profile_prefilter_ctx->data == NULL || det_ctx == NULL || - det_ctx->prefilter_perf_data == NULL) - return; - - for (uint32_t i = 0; i < de_ctx->prefilter_id; i++) { - de_ctx->profile_prefilter_ctx->data[i].called += det_ctx->prefilter_perf_data[i].called; - de_ctx->profile_prefilter_ctx->data[i].total += det_ctx->prefilter_perf_data[i].total; - if (det_ctx->prefilter_perf_data[i].max > de_ctx->profile_prefilter_ctx->data[i].max) - de_ctx->profile_prefilter_ctx->data[i].max = det_ctx->prefilter_perf_data[i].max; - de_ctx->profile_prefilter_ctx->data[i].total_bytes += - det_ctx->prefilter_perf_data[i].total_bytes; - if (det_ctx->prefilter_perf_data[i].max_bytes > - de_ctx->profile_prefilter_ctx->data[i].max_bytes) - de_ctx->profile_prefilter_ctx->data[i].max_bytes = - det_ctx->prefilter_perf_data[i].max_bytes; - de_ctx->profile_prefilter_ctx->data[i].bytes_called += - det_ctx->prefilter_perf_data[i].bytes_called; - } -} - -void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *det_ctx) -{ - if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->prefilter_perf_data == NULL) - return; - - pthread_mutex_lock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m); - SCProfilingPrefilterThreadMerge(det_ctx->de_ctx, det_ctx); - pthread_mutex_unlock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m); - - SCFree(det_ctx->prefilter_perf_data); - det_ctx->prefilter_perf_data = NULL; -} - -/** - * \brief Register the prefilter profiling counters. - * - * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. - */ -void -SCProfilingPrefilterInitCounters(DetectEngineCtx *de_ctx) -{ - if (profiling_prefilter_enabled == 0) - return; - - const uint32_t size = de_ctx->prefilter_id; - if (size == 0) - return; - - de_ctx->profile_prefilter_ctx = SCProfilingPrefilterInitCtx(); - BUG_ON(de_ctx->profile_prefilter_ctx == NULL); - de_ctx->profile_prefilter_ctx->size = size; - - de_ctx->profile_prefilter_ctx->data = SCCalloc(1, sizeof(SCProfilePrefilterData) * size); - BUG_ON(de_ctx->profile_prefilter_ctx->data == NULL); - - HashListTableBucket *hb = HashListTableGetListHead(de_ctx->prefilter_hash_table); - for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { - PrefilterStore *ctx = HashListTableGetListData(hb); - de_ctx->profile_prefilter_ctx->data[ctx->id].name = ctx->name; - SCLogDebug("prefilter %s set up", de_ctx->profile_prefilter_ctx->data[ctx->id].name); - } - SCLogDebug("size alloc'd %u", (uint32_t)size * (uint32_t)sizeof(SCProfilePrefilterData)); - - SCLogPerf("Registered %"PRIu32" prefilter profiling counters.", size); -} - -#endif /* PROFILING */ diff --git a/src/util-profiling-rulegroups.c b/src/util-profiling-rulegroups.c deleted file mode 100644 index a6f0a68826a6..000000000000 --- a/src/util-profiling-rulegroups.c +++ /dev/null @@ -1,382 +0,0 @@ -/* Copyright (C) 2007-2015 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Endace Technology Limited. - * \author Victor Julien - * - * An API for rule profiling operations. - */ - -#include "suricata-common.h" -#include "util-profiling.h" - -#ifdef PROFILING -#include "util-conf.h" -#include "util-time.h" - -/** - * Extra data for rule profiling. - */ -typedef struct SCProfileSghData_ { - uint64_t checks; - - uint64_t non_mpm_generic; - uint64_t non_mpm_syn; - - uint64_t post_prefilter_sigs_total; - uint64_t post_prefilter_sigs_max; - - uint64_t mpm_match_cnt_total; - uint64_t mpm_match_cnt_max; - -} SCProfileSghData; - -typedef struct SCProfileSghDetectCtx_ { - uint32_t cnt; - SCProfileSghData *data; - pthread_mutex_t data_m; -} SCProfileSghDetectCtx; - -static int profiling_sghs_output_to_file = 0; -int profiling_sghs_enabled = 0; -static char profiling_file_name[PATH_MAX]; -static const char *profiling_file_mode = "a"; -static int profiling_rulegroup_json = 0; - -void SCProfilingSghsGlobalInit(void) -{ - ConfNode *conf; - - conf = ConfGetNode("profiling.rulegroups"); - if (conf != NULL) { - if (ConfNodeChildValueIsTrue(conf, "enabled")) { - profiling_sghs_enabled = 1; - const char *filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename != NULL) { - const char *log_dir; - log_dir = ConfigGetLogDirectory(); - - snprintf(profiling_file_name, sizeof(profiling_file_name), - "%s/%s", log_dir, filename); - - const char *v = ConfNodeLookupChildValue(conf, "append"); - if (v == NULL || ConfValIsTrue(v)) { - profiling_file_mode = "a"; - } else { - profiling_file_mode = "w"; - } - - profiling_sghs_output_to_file = 1; - } - if (ConfNodeChildValueIsTrue(conf, "json")) { - profiling_rulegroup_json = 1; - } - } - } -} - -static void DoDumpJSON(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) -{ - char timebuf[64]; - uint32_t i; - struct timeval tval; - - json_t *js = json_object(); - if (js == NULL) - return; - json_t *jsa = json_array(); - if (jsa == NULL) { - json_decref(js); - return; - } - - gettimeofday(&tval, NULL); - CreateIsoTimeString(SCTIME_FROM_TIMEVAL(&tval), timebuf, sizeof(timebuf)); - json_object_set_new(js, "timestamp", json_string(timebuf)); - - for (i = 0; i < rules_ctx->cnt; i++) { - SCProfileSghData *d = &rules_ctx->data[i]; - if (d == NULL || d->checks == 0) - continue; - - double avgsigs = 0; - double avgmpms = 0; - - if (d->post_prefilter_sigs_total && d->checks) { - avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); - } - if (d->mpm_match_cnt_total && d->checks) { - avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); - } - - json_t *jsm = json_object(); - if (jsm) { - json_object_set_new(jsm, "id", json_integer(i)); - json_object_set_new(jsm, "checks", json_integer(d->checks)); - json_object_set_new(jsm, "non_mpm_generic", json_integer(d->non_mpm_generic)); - json_object_set_new(jsm, "non_mpm_syn", json_integer(d->non_mpm_syn)); - json_object_set_new(jsm, "avgmpms", json_real(avgmpms)); - json_object_set_new(jsm, "mpm_match_cnt_max", json_integer(d->mpm_match_cnt_max)); - json_object_set_new(jsm, "avgsigs", json_real(avgsigs)); - json_object_set_new(jsm, "post_prefilter_sigs_max", json_integer(d->post_prefilter_sigs_max)); - json_array_append_new(jsa, jsm); - } - } - json_object_set_new(js, "rule_groups", jsa); - - char *js_s = json_dumps(js, - JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| - JSON_ESCAPE_SLASH); - if (likely(js_s != NULL)) { - fprintf(fp, "%s", js_s); - free(js_s); - } - json_decref(js); -} - -static void DoDump(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) -{ - uint32_t i; - struct timeval tval; - struct tm *tms; - struct tm local_tm; - - gettimeofday(&tval, NULL); - tms = SCLocalTime(tval.tv_sec, &local_tm); - - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, - tms->tm_hour,tms->tm_min, tms->tm_sec); - - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Stats for: %s %u\n", name, rules_ctx->cnt); - fprintf(fp, " ----------------------------------------------" - "------------------------------------------------------" - "----------------------------\n"); - fprintf(fp, " %-16s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Sgh", "Checks", "Non-MPM(gen)", "Non-Mpm(syn)", "MPM Matches", "MPM Match Max", "Post-Filter", "Post-Filter Max"); - fprintf(fp, " ---------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "--------------- " - "\n"); - for (i = 0; i < rules_ctx->cnt; i++) { - SCProfileSghData *d = &rules_ctx->data[i]; - if (d == NULL || d->checks == 0) - continue; - - double avgsigs = 0; - double avgmpms = 0; - - if (d->post_prefilter_sigs_total && d->checks) { - avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); - } - if (d->mpm_match_cnt_total && d->checks) { - avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); - } - - fprintf(fp, - " %-16u %-15"PRIu64" %-15"PRIu64" %-15"PRIu64" %-15.2f %-15"PRIu64" %-15.2f %-15"PRIu64"\n", - i, - d->checks, - d->non_mpm_generic, - d->non_mpm_syn, - avgmpms, - d->mpm_match_cnt_max, - avgsigs, - d->post_prefilter_sigs_max); - } - fprintf(fp,"\n"); -} - -static void -SCProfilingSghDump(DetectEngineCtx *de_ctx) -{ - FILE *fp; - - if (profiling_sghs_enabled == 0) - return; - - if (profiling_sghs_output_to_file == 1) { - SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); - - fp = fopen(profiling_file_name, profiling_file_mode); - - if (fp == NULL) { - SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); - return; - } - } else { - fp = stdout; - } - - if (profiling_rulegroup_json) { - DoDumpJSON(de_ctx->profile_sgh_ctx, fp, "rule groups"); - } else { - DoDump(de_ctx->profile_sgh_ctx, fp, "rule groups"); - } - - if (fp != stdout) - fclose(fp); - - SCLogPerf("Done dumping rulegroup profiling data."); -} - -/** - * \brief Update a rule counter. - * - * \param id The ID of this counter. - * \param ticks Number of CPU ticks for this rule. - * \param match Did the rule match? - */ -void -SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh) -{ - if (det_ctx != NULL && det_ctx->sgh_perf_data != NULL && sgh->id < det_ctx->de_ctx->sgh_array_cnt) { - SCProfileSghData *p = &det_ctx->sgh_perf_data[sgh->id]; - p->checks++; - - if (det_ctx->non_pf_store_cnt > 0) { - if (det_ctx->non_pf_store_ptr == sgh->non_pf_syn_store_array) - p->non_mpm_syn++; - else - p->non_mpm_generic++; - } - p->post_prefilter_sigs_total += det_ctx->match_array_cnt; - if (det_ctx->match_array_cnt > p->post_prefilter_sigs_max) - p->post_prefilter_sigs_max = det_ctx->match_array_cnt; - p->mpm_match_cnt_total += det_ctx->pmq.rule_id_array_cnt; - if (det_ctx->pmq.rule_id_array_cnt > p->mpm_match_cnt_max) - p->mpm_match_cnt_max = det_ctx->pmq.rule_id_array_cnt; - } -} - -static SCProfileSghDetectCtx *SCProfilingSghInitCtx(void) -{ - SCProfileSghDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileSghDetectCtx)); - if (ctx != NULL) { - if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { - FatalError("Failed to initialize mutex."); - } - } - - return ctx; -} - -static void DetroyCtx(SCProfileSghDetectCtx *ctx) -{ - if (ctx) { - if (ctx->data != NULL) - SCFree(ctx->data); - pthread_mutex_destroy(&ctx->data_m); - SCFree(ctx); - } -} - -void SCProfilingSghDestroyCtx(DetectEngineCtx *de_ctx) -{ - if (de_ctx != NULL) { - SCProfilingSghDump(de_ctx); - - DetroyCtx(de_ctx->profile_sgh_ctx); - } -} - -void SCProfilingSghThreadSetup(SCProfileSghDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) -{ - if (ctx == NULL) - return; - - uint32_t array_size = det_ctx->de_ctx->sgh_array_cnt; - - SCProfileSghData *a = SCCalloc(array_size, sizeof(SCProfileSghData)); - if (a != NULL) { - det_ctx->sgh_perf_data = a; - } -} - -static void SCProfilingSghThreadMerge(DetectEngineCtx *de_ctx, const DetectEngineThreadCtx *det_ctx) -{ - if (de_ctx == NULL || de_ctx->profile_sgh_ctx == NULL || - de_ctx->profile_sgh_ctx->data == NULL || det_ctx == NULL || - det_ctx->sgh_perf_data == NULL) - return; - -#define ADD(name) de_ctx->profile_sgh_ctx->data[i].name += det_ctx->sgh_perf_data[i].name - uint32_t i; - for (i = 0; i < de_ctx->sgh_array_cnt; i++) { - ADD(checks); - ADD(non_mpm_generic); - ADD(non_mpm_syn); - ADD(post_prefilter_sigs_total); - ADD(mpm_match_cnt_total); - - if (det_ctx->sgh_perf_data[i].mpm_match_cnt_max > de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max) - de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max = det_ctx->sgh_perf_data[i].mpm_match_cnt_max; - if (det_ctx->sgh_perf_data[i].post_prefilter_sigs_max > de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max) - de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max = det_ctx->sgh_perf_data[i].post_prefilter_sigs_max; - } -#undef ADD -} - -void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *det_ctx) -{ - if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->sgh_perf_data == NULL) - return; - - pthread_mutex_lock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); - SCProfilingSghThreadMerge(det_ctx->de_ctx, det_ctx); - pthread_mutex_unlock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); - - SCFree(det_ctx->sgh_perf_data); - det_ctx->sgh_perf_data = NULL; -} - -/** - * \brief Register the keyword profiling counters. - * - * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. - */ -void -SCProfilingSghInitCounters(DetectEngineCtx *de_ctx) -{ - if (profiling_sghs_enabled == 0) - return; - - de_ctx->profile_sgh_ctx = SCProfilingSghInitCtx(); - BUG_ON(de_ctx->profile_sgh_ctx == NULL); - - de_ctx->profile_sgh_ctx->data = SCCalloc(de_ctx->sgh_array_cnt, sizeof(SCProfileSghData)); - BUG_ON(de_ctx->profile_sgh_ctx->data == NULL); - - de_ctx->profile_sgh_ctx->cnt = de_ctx->sgh_array_cnt; - - SCLogPerf("Registered %"PRIu32" rulegroup profiling counters.", de_ctx->sgh_array_cnt); -} - -#endif /* PROFILING */ diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c deleted file mode 100644 index 8262f71f4c8a..000000000000 --- a/src/util-profiling-rules.c +++ /dev/null @@ -1,689 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Endace Technology Limited. - * \author Victor Julien - * - * An API for rule profiling operations. - */ - -#include "suricata-common.h" -#include "util-profiling.h" - -#include "util-byte.h" -#include "util-conf.h" -#include "util-time.h" - -#ifdef PROFILE_RULES - -/** - * Used for generating the summary data to print. - */ -typedef struct SCProfileSummary_ { - uint32_t sid; - uint32_t gid; - uint32_t rev; - uint64_t ticks; - double avgticks; - double avgticks_match; - double avgticks_no_match; - uint64_t checks; - uint64_t matches; - uint64_t max; - uint64_t ticks_match; - uint64_t ticks_no_match; -} SCProfileSummary; - -extern int profiling_output_to_file; -int profiling_rules_enabled = 0; -static char profiling_file_name[PATH_MAX] = ""; -static const char *profiling_file_mode = "a"; -static int profiling_rule_json = 0; - -/** - * Sort orders for dumping profiled rules. - */ -enum { - SC_PROFILING_RULES_SORT_BY_TICKS = 0, - SC_PROFILING_RULES_SORT_BY_AVG_TICKS, - SC_PROFILING_RULES_SORT_BY_CHECKS, - SC_PROFILING_RULES_SORT_BY_MATCHES, - SC_PROFILING_RULES_SORT_BY_MAX_TICKS, - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, -}; - -static int profiling_rules_sort_orders[8] = { - SC_PROFILING_RULES_SORT_BY_TICKS, - SC_PROFILING_RULES_SORT_BY_AVG_TICKS, - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, - SC_PROFILING_RULES_SORT_BY_CHECKS, - SC_PROFILING_RULES_SORT_BY_MATCHES, - SC_PROFILING_RULES_SORT_BY_MAX_TICKS, - -1 }; - -/** - * Maximum number of rules to dump. - */ -static uint32_t profiling_rules_limit = UINT32_MAX; - -void SCProfilingRulesGlobalInit(void) -{ -#define SET_ONE(x) { \ - profiling_rules_sort_orders[0] = (x); \ - profiling_rules_sort_orders[1] = -1; \ - } - - ConfNode *conf; - const char *val; - - conf = ConfGetNode("profiling.rules"); - if (conf != NULL) { - if (ConfNodeChildValueIsTrue(conf, "enabled")) { - profiling_rules_enabled = 1; - - val = ConfNodeLookupChildValue(conf, "sort"); - if (val != NULL) { - if (strcmp(val, "ticks") == 0) { - SET_ONE(SC_PROFILING_RULES_SORT_BY_TICKS); - } - else if (strcmp(val, "avgticks") == 0) { - SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS); - } - else if (strcmp(val, "avgticks_match") == 0) { - SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH); - } - else if (strcmp(val, "avgticks_no_match") == 0) { - SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH); - } - else if (strcmp(val, "checks") == 0) { - SET_ONE(SC_PROFILING_RULES_SORT_BY_CHECKS); - } - else if (strcmp(val, "matches") == 0) { - SET_ONE(SC_PROFILING_RULES_SORT_BY_MATCHES); - } - else if (strcmp(val, "maxticks") == 0) { - SET_ONE(SC_PROFILING_RULES_SORT_BY_MAX_TICKS); - } - else { - SCLogError("Invalid profiling sort order: %s", val); - exit(EXIT_FAILURE); - } - } - - val = ConfNodeLookupChildValue(conf, "limit"); - if (val != NULL) { - if (StringParseUint32(&profiling_rules_limit, 10, - (uint16_t)strlen(val), val) <= 0) { - SCLogError("Invalid limit: %s", val); - exit(EXIT_FAILURE); - } - } - const char *filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename != NULL) { - - const char *log_dir; - log_dir = ConfigGetLogDirectory(); - - snprintf(profiling_file_name, sizeof(profiling_file_name), - "%s/%s", log_dir, filename); - - const char *v = ConfNodeLookupChildValue(conf, "append"); - if (v == NULL || ConfValIsTrue(v)) { - profiling_file_mode = "a"; - } else { - profiling_file_mode = "w"; - } - - profiling_output_to_file = 1; - } - if (ConfNodeChildValueIsTrue(conf, "json")) { - profiling_rule_json = 1; - } - } - } -#undef SET_ONE -} - -/** - * \brief Qsort comparison function to sort by ticks. - */ -static int -SCProfileSummarySortByTicks(const void *a, const void *b) -{ - const SCProfileSummary *s0 = a; - const SCProfileSummary *s1 = b; - if (s1->ticks == s0->ticks) - return 0; - else - return s0->ticks > s1->ticks ? -1 : 1; -} - -/** - * \brief Qsort comparison function to sort by average ticks per match. - */ -static int -SCProfileSummarySortByAvgTicksMatch(const void *a, const void *b) -{ - const SCProfileSummary *s0 = a; - const SCProfileSummary *s1 = b; - if (s1->avgticks_match == s0->avgticks_match) - return 0; - else - return s0->avgticks_match > s1->avgticks_match ? -1 : 1; -} - -/** - * \brief Qsort comparison function to sort by average ticks per non match. - */ -static int -SCProfileSummarySortByAvgTicksNoMatch(const void *a, const void *b) -{ - const SCProfileSummary *s0 = a; - const SCProfileSummary *s1 = b; - if (s1->avgticks_no_match == s0->avgticks_no_match) - return 0; - else - return s0->avgticks_no_match > s1->avgticks_no_match ? -1 : 1; -} - -/** - * \brief Qsort comparison function to sort by average ticks. - */ -static int -SCProfileSummarySortByAvgTicks(const void *a, const void *b) -{ - const SCProfileSummary *s0 = a; - const SCProfileSummary *s1 = b; - if (s1->avgticks == s0->avgticks) - return 0; - else - return s0->avgticks > s1->avgticks ? -1 : 1; -} - -/** - * \brief Qsort comparison function to sort by checks. - */ -static int -SCProfileSummarySortByChecks(const void *a, const void *b) -{ - const SCProfileSummary *s0 = a; - const SCProfileSummary *s1 = b; - if (s1->checks == s0->checks) - return 0; - else - return s0->checks > s1->checks ? -1 : 1; -} - -/** - * \brief Qsort comparison function to sort by matches. - */ -static int -SCProfileSummarySortByMatches(const void *a, const void *b) -{ - const SCProfileSummary *s0 = a; - const SCProfileSummary *s1 = b; - if (s1->matches == s0->matches) - return 0; - else - return s0->matches > s1->matches ? -1 : 1; -} - -/** - * \brief Qsort comparison function to sort by max ticks. - */ -static int -SCProfileSummarySortByMaxTicks(const void *a, const void *b) -{ - const SCProfileSummary *s0 = a; - const SCProfileSummary *s1 = b; - if (s1->max == s0->max) - return 0; - else - return s0->max > s1->max ? -1 : 1; -} - -static json_t *BuildJson( - SCProfileSummary *summary, uint32_t count, uint64_t total_ticks, const char *sort_desc) -{ - - char timebuf[64]; - uint32_t i; - struct timeval tval; - - json_t *js = json_object(); - if (js == NULL) - return js; - json_t *jsa = json_array(); - if (jsa == NULL) { - json_decref(js); - return js; - } - - gettimeofday(&tval, NULL); - CreateIsoTimeString(SCTIME_FROM_TIMEVAL(&tval), timebuf, sizeof(timebuf)); - json_object_set_new(js, "timestamp", json_string(timebuf)); - json_object_set_new(js, "sort", json_string(sort_desc)); - - for (i = 0; i < MIN(count, profiling_rules_limit); i++) { - /* Stop dumping when we hit our first rule with 0 checks. Due - * to sorting this will be the beginning of all the rules with - * 0 checks. */ - if (summary[i].checks == 0) - break; - - json_t *jsm = json_object(); - if (jsm) { - json_object_set_new(jsm, "signature_id", json_integer(summary[i].sid)); - json_object_set_new(jsm, "gid", json_integer(summary[i].gid)); - json_object_set_new(jsm, "rev", json_integer(summary[i].rev)); - - json_object_set_new(jsm, "checks", json_integer(summary[i].checks)); - json_object_set_new(jsm, "matches", json_integer(summary[i].matches)); - - json_object_set_new(jsm, "ticks_total", json_integer(summary[i].ticks)); - json_object_set_new(jsm, "ticks_max", json_integer(summary[i].max)); - json_object_set_new(jsm, "ticks_avg", json_integer(summary[i].avgticks)); - json_object_set_new(jsm, "ticks_avg_match", json_integer(summary[i].avgticks_match)); - json_object_set_new(jsm, "ticks_avg_nomatch", json_integer(summary[i].avgticks_no_match)); - - double percent = (long double)summary[i].ticks / - (long double)total_ticks * 100; - json_object_set_new(jsm, "percent", json_integer(percent)); - json_array_append_new(jsa, jsm); - } - } - json_object_set_new(js, "rules", jsa); - return js; -} - -static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks, - const char *sort_desc) -{ - json_t *js = BuildJson(summary, count, total_ticks, sort_desc); - if (unlikely(js == NULL)) - return; - char *js_s = json_dumps(js, - JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| - JSON_ESCAPE_SLASH); - - if (unlikely(js_s == NULL)) - return; - fprintf(fp, "%s\n", js_s); - free(js_s); - json_decref(js); -} - -static void DumpText(FILE *fp, SCProfileSummary *summary, - uint32_t count, uint64_t total_ticks, - const char *sort_desc) -{ - uint32_t i; - struct timeval tval; - struct tm *tms; - gettimeofday(&tval, NULL); - struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); - - fprintf(fp, " ----------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d.", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, - tms->tm_hour,tms->tm_min, tms->tm_sec); - fprintf(fp, " Sorted by: %s.\n", sort_desc); - fprintf(fp, " ----------------------------------------------" - "----------------------------\n"); - fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match"); - fprintf(fp, " -------- " - "------------ " - "-------- " - "-------- " - "------------ " - "------ " - "-------- " - "-------- " - "----------- " - "----------- " - "----------- " - "-------------- " - "\n"); - for (i = 0; i < MIN(count, profiling_rules_limit); i++) { - - /* Stop dumping when we hit our first rule with 0 checks. Due - * to sorting this will be the beginning of all the rules with - * 0 checks. */ - if (summary[i].checks == 0) - break; - - double percent = (long double)summary[i].ticks / - (long double)total_ticks * 100; - fprintf(fp, - " %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n", - i + 1, - summary[i].sid, - summary[i].gid, - summary[i].rev, - summary[i].ticks, - percent, - summary[i].checks, - summary[i].matches, - summary[i].max, - summary[i].avgticks, - summary[i].avgticks_match, - summary[i].avgticks_no_match); - } - - fprintf(fp,"\n"); -} - -/** - * \brief Dump rule profiling information to file - * - * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. - */ -static void *SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx, int file_output) -{ - uint32_t i; - FILE *fp = NULL; - - if (rules_ctx == NULL) - return NULL; - - if (file_output != 0) { - if (profiling_output_to_file == 1) { - fp = fopen(profiling_file_name, profiling_file_mode); - - if (fp == NULL) { - SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); - return NULL; - } - } else { - fp = stdout; - } - } - - int summary_size = sizeof(SCProfileSummary) * rules_ctx->size; - SCProfileSummary *summary = SCMalloc(summary_size); - if (unlikely(summary == NULL)) { - SCLogError("Error allocating memory for profiling summary"); - return NULL; - } - - uint32_t count = rules_ctx->size; - uint64_t total_ticks = 0; - - SCLogPerf("Dumping profiling data for %u rules.", count); - - memset(summary, 0, summary_size); - for (i = 0; i < count; i++) { - summary[i].sid = rules_ctx->data[i].sid; - summary[i].rev = rules_ctx->data[i].rev; - summary[i].gid = rules_ctx->data[i].gid; - - summary[i].ticks = rules_ctx->data[i].ticks_match + rules_ctx->data[i].ticks_no_match; - summary[i].checks = rules_ctx->data[i].checks; - - if (summary[i].checks > 0) { - summary[i].avgticks = (long double)summary[i].ticks / (long double)summary[i].checks; - } - - summary[i].matches = rules_ctx->data[i].matches; - summary[i].max = rules_ctx->data[i].max; - summary[i].ticks_match = rules_ctx->data[i].ticks_match; - summary[i].ticks_no_match = rules_ctx->data[i].ticks_no_match; - if (summary[i].ticks_match > 0) { - summary[i].avgticks_match = (long double)summary[i].ticks_match / - (long double)summary[i].matches; - } - - if (summary[i].ticks_no_match > 0) { - summary[i].avgticks_no_match = (long double)summary[i].ticks_no_match / - ((long double)summary[i].checks - (long double)summary[i].matches); - } - total_ticks += summary[i].ticks; - } - - int *order = profiling_rules_sort_orders; - while (*order != -1) { - const char *sort_desc = NULL; - switch (*order) { - case SC_PROFILING_RULES_SORT_BY_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByTicks); - sort_desc = "ticks"; - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicks); - sort_desc = "average ticks"; - break; - case SC_PROFILING_RULES_SORT_BY_CHECKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByChecks); - sort_desc = "number of checks"; - break; - case SC_PROFILING_RULES_SORT_BY_MATCHES: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByMatches); - sort_desc = "number of matches"; - break; - case SC_PROFILING_RULES_SORT_BY_MAX_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByMaxTicks); - sort_desc = "max ticks"; - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicksMatch); - sort_desc = "average ticks (match)"; - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicksNoMatch); - sort_desc = "average ticks (no match)"; - break; - } - if (profiling_rule_json) { - if (file_output != 1) { - json_t *js = BuildJson(summary, count, total_ticks, sort_desc); - SCFree(summary); - return js; - } else { - DumpJson(fp, summary, count, total_ticks, sort_desc); - } - } else { - DumpText(fp, summary, count, total_ticks, sort_desc); - } - order++; - } - - if (file_output != 0) { - if (fp != stdout) - fclose(fp); - } - SCFree(summary); - SCLogPerf("Done dumping profiling data."); - return NULL; -} - -/** - * \brief Register a rule profiling counter. - * - * \retval Returns the ID of the counter on success, 0 on failure. - */ -static uint16_t -SCProfilingRegisterRuleCounter(SCProfileDetectCtx *ctx) -{ - ctx->size++; - return ctx->id++; -} - -/** - * \brief Update a rule counter. - * - * \param id The ID of this counter. - * \param ticks Number of CPU ticks for this rule. - * \param match Did the rule match? - */ -void -SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *det_ctx, uint16_t id, uint64_t ticks, int match) -{ - if (det_ctx != NULL && det_ctx->rule_perf_data != NULL && det_ctx->rule_perf_data_size > id) { - SCProfileData *p = &det_ctx->rule_perf_data[id]; - - p->checks++; - p->matches += match; - if (ticks > p->max) - p->max = ticks; - if (match == 1) - p->ticks_match += ticks; - else - p->ticks_no_match += ticks; - } -} - -static SCProfileDetectCtx *SCProfilingRuleInitCtx(void) -{ - SCProfileDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileDetectCtx)); - if (ctx != NULL) { - if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { - FatalError("Failed to initialize hash table mutex."); - } - } - - return ctx; -} - -void SCProfilingRuleDestroyCtx(SCProfileDetectCtx *ctx) -{ - if (ctx != NULL) { - SCProfilingRuleDump(ctx, 1); - if (ctx->data != NULL) - SCFree(ctx->data); - pthread_mutex_destroy(&ctx->data_m); - SCFree(ctx); - } -} - -void SCProfilingRuleThreadSetup(SCProfileDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) -{ - if (ctx == NULL|| ctx->size == 0) - return; - - SCProfileData *a = SCCalloc(ctx->size, sizeof(SCProfileData)); - if (a != NULL) { - det_ctx->rule_perf_data = a; - det_ctx->rule_perf_data_size = ctx->size; - } -} - -static void SCProfilingRuleThreadMerge( - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, bool reset) -{ - if (de_ctx == NULL || de_ctx->profile_ctx == NULL || de_ctx->profile_ctx->data == NULL || - det_ctx == NULL || det_ctx->rule_perf_data == NULL) - return; - - for (int i = 0; i < det_ctx->rule_perf_data_size; i++) { - de_ctx->profile_ctx->data[i].checks += det_ctx->rule_perf_data[i].checks; - de_ctx->profile_ctx->data[i].matches += det_ctx->rule_perf_data[i].matches; - de_ctx->profile_ctx->data[i].ticks_match += det_ctx->rule_perf_data[i].ticks_match; - de_ctx->profile_ctx->data[i].ticks_no_match += det_ctx->rule_perf_data[i].ticks_no_match; - if (reset) { - det_ctx->rule_perf_data[i].checks = 0; - det_ctx->rule_perf_data[i].matches = 0; - det_ctx->rule_perf_data[i].ticks_match = 0; - det_ctx->rule_perf_data[i].ticks_no_match = 0; - } - if (det_ctx->rule_perf_data[i].max > de_ctx->profile_ctx->data[i].max) - de_ctx->profile_ctx->data[i].max = det_ctx->rule_perf_data[i].max; - } -} - -void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *det_ctx) -{ - if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->rule_perf_data == NULL) - return; - - pthread_mutex_lock(&det_ctx->de_ctx->profile_ctx->data_m); - SCProfilingRuleThreadMerge(det_ctx->de_ctx, det_ctx, false); - pthread_mutex_unlock(&det_ctx->de_ctx->profile_ctx->data_m); - - SCFree(det_ctx->rule_perf_data); - det_ctx->rule_perf_data = NULL; - det_ctx->rule_perf_data_size = 0; -} - -void SCProfilingRuleThreatAggregate(DetectEngineThreadCtx *det_ctx) -{ - - if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->de_ctx->profile_ctx == NULL) - return; - pthread_mutex_lock(&det_ctx->de_ctx->profile_ctx->data_m); - SCProfilingRuleThreadMerge(det_ctx->de_ctx, det_ctx, true); - pthread_mutex_unlock(&det_ctx->de_ctx->profile_ctx->data_m); -} - -/** - * \brief Register the rule profiling counters. - * - * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. - */ -void -SCProfilingRuleInitCounters(DetectEngineCtx *de_ctx) -{ - if (profiling_rules_enabled == 0) - return; - - de_ctx->profile_ctx = SCProfilingRuleInitCtx(); - BUG_ON(de_ctx->profile_ctx == NULL); - - Signature *sig = de_ctx->sig_list; - uint32_t count = 0; - while (sig != NULL) { - sig->profiling_id = SCProfilingRegisterRuleCounter(de_ctx->profile_ctx); - sig = sig->next; - count++; - } - - if (count > 0) { - de_ctx->profile_ctx->data = SCCalloc(de_ctx->profile_ctx->size, sizeof(SCProfileData)); - BUG_ON(de_ctx->profile_ctx->data == NULL); - - sig = de_ctx->sig_list; - while (sig != NULL) { - de_ctx->profile_ctx->data[sig->profiling_id].sid = sig->id; - de_ctx->profile_ctx->data[sig->profiling_id].gid = sig->gid; - de_ctx->profile_ctx->data[sig->profiling_id].rev = sig->rev; - sig = sig->next; - } - } - - SCLogPerf("Registered %"PRIu32" rule profiling counters.", count); -} - -json_t *SCProfileRuleTriggerDump(DetectEngineCtx *de_ctx) -{ - return SCProfilingRuleDump(de_ctx->profile_ctx, 0); -} - -#endif /* PROFILING */ - diff --git a/src/util-profiling.c b/src/util-profiling.c deleted file mode 100644 index 5d4bcc8905ce..000000000000 --- a/src/util-profiling.c +++ /dev/null @@ -1,1477 +0,0 @@ -/* Copyright (C) 2007-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Endace Technology Limited. - * \author Victor Julien - * - * An API for profiling operations. - * - * Really just a wrapper around the existing perf counters. - */ - -#include "suricata-common.h" -#include "util-profiling.h" - -#ifdef PROFILING -#include "tm-threads.h" -#include "conf.h" -#include "util-unittest.h" -#include "util-byte.h" -#include "util-profiling-locks.h" -#include "util-conf.h" - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#define DEFAULT_LOG_FILENAME "profile.log" -#define DEFAULT_LOG_MODE_APPEND "yes" - -static pthread_mutex_t packet_profile_lock; -static FILE *packet_profile_csv_fp = NULL; - -extern int profiling_locks_enabled; -extern int profiling_locks_output_to_file; -extern char *profiling_locks_file_name; -extern const char *profiling_locks_file_mode; - -typedef struct SCProfilePacketData_ { - uint64_t min; - uint64_t max; - uint64_t tot; - uint64_t cnt; -#ifdef PROFILE_LOCKING - uint64_t lock; - uint64_t ticks; - uint64_t contention; - - uint64_t slock; - uint64_t sticks; - uint64_t scontention; -#endif -} SCProfilePacketData; -SCProfilePacketData packet_profile_data4[257]; /**< all proto's + tunnel */ -SCProfilePacketData packet_profile_data6[257]; /**< all proto's + tunnel */ - -/* each module, each proto */ -SCProfilePacketData packet_profile_tmm_data4[TMM_SIZE][257]; -SCProfilePacketData packet_profile_tmm_data6[TMM_SIZE][257]; - -SCProfilePacketData packet_profile_app_data4[TMM_SIZE][257]; -SCProfilePacketData packet_profile_app_data6[TMM_SIZE][257]; - -SCProfilePacketData packet_profile_app_pd_data4[257]; -SCProfilePacketData packet_profile_app_pd_data6[257]; - -SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]; -SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]; - -SCProfilePacketData packet_profile_log_data4[LOGGER_SIZE][256]; -SCProfilePacketData packet_profile_log_data6[LOGGER_SIZE][256]; - -struct ProfileProtoRecords { - SCProfilePacketData records4[257]; - SCProfilePacketData records6[257]; -}; - -struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]; - -int profiling_packets_enabled = 0; -int profiling_output_to_file = 0; - -static int profiling_packets_csv_enabled = 0; -static int profiling_packets_output_to_file = 0; -static char *profiling_file_name; -static char profiling_packets_file_name[PATH_MAX]; -static char *profiling_csv_file_name; -static const char *profiling_packets_file_mode = "a"; - -static int rate = 1; -static SC_ATOMIC_DECLARE(uint64_t, samples); - -/** - * Used as a check so we don't double enter a profiling run. - */ -thread_local int profiling_rules_entered = 0; - -void SCProfilingDumpPacketStats(void); -const char * PacketProfileDetectIdToString(PacketProfileDetectId id); -const char *PacketProfileLoggerIdToString(LoggerId id); -static void PrintCSVHeader(void); - -static void FormatNumber(uint64_t num, char *str, size_t size) -{ - if (num < 1000UL) - snprintf(str, size, "%"PRIu64, num); - else if (num < 1000000UL) - snprintf(str, size, "%3.1fk", (float)num/1000UL); - else if (num < 1000000000UL) - snprintf(str, size, "%3.1fm", (float)num/1000000UL); - else - snprintf(str, size, "%3.1fb", (float)num/1000000000UL); -} - -/** - * \brief Initialize profiling. - */ -void -SCProfilingInit(void) -{ - ConfNode *conf; - - SC_ATOMIC_INIT(samples); - - intmax_t rate_v = 0; - (void)ConfGetInt("profiling.sample-rate", &rate_v); - if (rate_v > 0 && rate_v < INT_MAX) { - rate = (int)rate_v; - if (rate != 1) - SCLogInfo("profiling runs for every %dth packet", rate); - else - SCLogInfo("profiling runs for every packet"); - } - - conf = ConfGetNode("profiling.packets"); - if (conf != NULL) { - if (ConfNodeChildValueIsTrue(conf, "enabled")) { - profiling_packets_enabled = 1; - - if (pthread_mutex_init(&packet_profile_lock, NULL) != 0) { - FatalError("Failed to initialize packet profiling mutex."); - } - memset(&packet_profile_data4, 0, sizeof(packet_profile_data4)); - 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)); - 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)); - memset(&packet_profile_detect_data6, 0, sizeof(packet_profile_detect_data6)); - memset(&packet_profile_log_data4, 0, sizeof(packet_profile_log_data4)); - memset(&packet_profile_log_data6, 0, sizeof(packet_profile_log_data6)); - memset(&packet_profile_flowworker_data, 0, sizeof(packet_profile_flowworker_data)); - - const char *filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename != NULL) { - const char *log_dir; - log_dir = ConfigGetLogDirectory(); - - snprintf(profiling_packets_file_name, sizeof(profiling_packets_file_name), - "%s/%s", log_dir, filename); - - const char *v = ConfNodeLookupChildValue(conf, "append"); - if (v == NULL || ConfValIsTrue(v)) { - profiling_packets_file_mode = "a"; - } else { - profiling_packets_file_mode = "w"; - } - - profiling_packets_output_to_file = 1; - } - } - - conf = ConfGetNode("profiling.packets.csv"); - if (conf != NULL) { - if (ConfNodeChildValueIsTrue(conf, "enabled")) { - const char *filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename == NULL) { - filename = "packet_profile.csv"; - } - - const char *log_dir = ConfigGetLogDirectory(); - - profiling_csv_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_csv_file_name == NULL)) { - FatalError("out of memory"); - } - snprintf(profiling_csv_file_name, PATH_MAX, "%s/%s", log_dir, filename); - - packet_profile_csv_fp = fopen(profiling_csv_file_name, "w"); - if (packet_profile_csv_fp == NULL) { - SCFree(profiling_csv_file_name); - profiling_csv_file_name = NULL; - return; - } - - PrintCSVHeader(); - - profiling_packets_csv_enabled = 1; - } - } - } - - conf = ConfGetNode("profiling.locks"); - if (conf != NULL) { - if (ConfNodeChildValueIsTrue(conf, "enabled")) { -#ifndef PROFILE_LOCKING - SCLogWarning( - "lock profiling not compiled in. Add --enable-profiling-locks to configure."); -#else - profiling_locks_enabled = 1; - - LockRecordInitHash(); - - const char *filename = ConfNodeLookupChildValue(conf, "filename"); - if (filename != NULL) { - const char *log_dir = ConfigGetLogDirectory(); - - profiling_locks_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_locks_file_name == NULL)) { - FatalError("can't duplicate file name"); - } - - snprintf(profiling_locks_file_name, PATH_MAX, "%s/%s", log_dir, filename); - - const char *v = ConfNodeLookupChildValue(conf, "append"); - if (v == NULL || ConfValIsTrue(v)) { - profiling_locks_file_mode = "a"; - } else { - profiling_locks_file_mode = "w"; - } - - profiling_locks_output_to_file = 1; - } -#endif - } - } - -} - -/** - * \brief Free resources used by profiling. - */ -void -SCProfilingDestroy(void) -{ - if (profiling_packets_enabled) { - pthread_mutex_destroy(&packet_profile_lock); - } - - if (profiling_packets_csv_enabled) { - if (packet_profile_csv_fp != NULL) - fclose(packet_profile_csv_fp); - packet_profile_csv_fp = NULL; - } - - if (profiling_csv_file_name != NULL) - SCFree(profiling_csv_file_name); - profiling_csv_file_name = NULL; - - if (profiling_file_name != NULL) - SCFree(profiling_file_name); - profiling_file_name = NULL; - -#ifdef PROFILE_LOCKING - LockRecordFreeHash(); -#endif -} - -void -SCProfilingDump(void) -{ - SCProfilingDumpPacketStats(); - SCLogPerf("Done dumping profiling data."); -} - -static void DumpFlowWorkerIP(FILE *fp, int ipv, uint64_t total) -{ - char totalstr[256]; - - enum ProfileFlowWorkerId fwi; - for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { - struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = ipv == 4 ? &r->records4[p] : &r->records6[p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, "%-20s IPv%d %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", - ProfileFlowWorkerIdToString(fwi), ipv, p, pd->cnt, - pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } -} - -static void DumpFlowWorker(FILE *fp) -{ - uint64_t total = 0; - - enum ProfileFlowWorkerId fwi; - for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { - struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &r->records4[p]; - total += pd->tot; - pd = &r->records6[p]; - total += pd->tot; - } - } - - fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", - "Flow Worker", "IP ver", "Proto", "cnt", "min", "max", "avg"); - fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", - "--------------------", "------", "-----", "----------", "------------", "------------", "-----------"); - DumpFlowWorkerIP(fp, 4, total); - DumpFlowWorkerIP(fp, 6, total); - fprintf(fp, "Note: %s includes app-layer for TCP\n", - ProfileFlowWorkerIdToString(PROFILE_FLOWWORKER_STREAM)); -} - -void SCProfilingDumpPacketStats(void) -{ - FILE *fp; - char totalstr[256]; - uint64_t total; - - if (profiling_packets_enabled == 0) - return; - - if (profiling_packets_output_to_file == 1) { - fp = fopen(profiling_packets_file_name, profiling_packets_file_mode); - - if (fp == NULL) { - SCLogError("failed to open %s: %s", profiling_packets_file_name, strerror(errno)); - return; - } - } else { - fp = stdout; - } - - fprintf(fp, "\n\nPacket profile dump:\n"); - - fprintf(fp, "\n%-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s\n", - "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%"); - fprintf(fp, "%-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s\n", - "------", "-----", "----------", "------------", "------------", "-----------", "-----------", "---"); - total = 0; - for (int i = 0; i < 257; i++) { - SCProfilePacketData *pd = &packet_profile_data4[i]; - total += pd->tot; - pd = &packet_profile_data6[i]; - total += pd->tot; - } - - for (int i = 0; i < 257; i++) { - SCProfilePacketData *pd = &packet_profile_data4[i]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, " IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n", i, pd->cnt, - pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - - for (int i = 0; i < 257; i++) { - SCProfilePacketData *pd = &packet_profile_data6[i]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, " IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n", i, pd->cnt, - pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - fprintf(fp, "Note: Protocol 256 tracks pseudo/tunnel packets.\n"); - - fprintf(fp, "\nPer Thread module stats:\n"); - - fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", - "Thread Module", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%"); -#ifdef PROFILE_LOCKING - fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", - "locks", "ticks", "cont.", "cont.avg", "slocks", "sticks", "scont.", "scont.avg"); -#else - fprintf(fp, "\n"); -#endif - fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", - "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------", "---"); -#ifdef PROFILE_LOCKING - fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", - "--------", "--------", "----------", "-----------", "--------", "--------", "------------", "-----------"); -#else - fprintf(fp, "\n"); -#endif - total = 0; - for (int m = 0; m < TMM_SIZE; m++) { - if (tmm_modules[m].flags & TM_FLAG_LOGAPI_TM) - continue; - - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; - total += pd->tot; - - pd = &packet_profile_tmm_data6[m][p]; - total += pd->tot; - } - } - - for (int m = 0; m < TMM_SIZE; m++) { - if (tmm_modules[m].flags & TM_FLAG_LOGAPI_TM) - continue; - - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f", - TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); -#ifdef PROFILE_LOCKING - fprintf(fp, " %10.2f %12"PRIu64" %12"PRIu64" %10.2f %10.2f %12"PRIu64" %12"PRIu64" %10.2f\n", - (float)pd->lock/pd->cnt, (uint64_t)pd->ticks/pd->cnt, pd->contention, (float)pd->contention/pd->cnt, (float)pd->slock/pd->cnt, (uint64_t)pd->sticks/pd->cnt, pd->scontention, (float)pd->scontention/pd->cnt); -#else - fprintf(fp, "\n"); -#endif - } - } - - for (int m = 0; m < TMM_SIZE; m++) { - if (tmm_modules[m].flags & TM_FLAG_LOGAPI_TM) - continue; - - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_tmm_data6[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n", - TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - - DumpFlowWorker(fp); - - fprintf(fp, "\nPer App layer parser stats:\n"); - - fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", - "App Layer", "IP ver", "Proto", "cnt", "min", "max", "avg"); - fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", - "--------------------", "------", "-----", "----------", "------------", "------------", "-----------"); - - total = 0; - for (AppProto a = 0; a < ALPROTO_MAX; a++) { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_data4[a][p]; - total += pd->tot; - - pd = &packet_profile_app_data6[a][p]; - total += pd->tot; - } - } - for (AppProto a = 0; a < ALPROTO_MAX; a++) { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_data4[a][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, - "%-20s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 - " %12" PRIu64 " %12s %-6.2f\n", - AppProtoToString(a), p, pd->cnt, pd->min, pd->max, - (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - - for (AppProto a = 0; a < ALPROTO_MAX; a++) { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_data6[a][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, - "%-20s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 - " %12" PRIu64 " %12s %-6.2f\n", - AppProtoToString(a), p, pd->cnt, pd->min, pd->max, - (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - - /* proto detect output */ - { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_pd_data4[p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - fprintf(fp, "%-20s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s\n", - "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr); - } - - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_pd_data6[p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - fprintf(fp, "%-20s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s\n", - "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr); - } - } - - total = 0; - for (int m = 0; m < PROF_DETECT_SIZE; m++) { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_detect_data4[m][p]; - total += pd->tot; - - pd = &packet_profile_detect_data6[m][p]; - total += pd->tot; - } - } - - fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", - "Log Thread Module", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%"); -#ifdef PROFILE_LOCKING - fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", - "locks", "ticks", "cont.", "cont.avg", "slocks", "sticks", "scont.", "scont.avg"); -#else - fprintf(fp, "\n"); -#endif - fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", - "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------", "---"); -#ifdef PROFILE_LOCKING - fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", - "--------", "--------", "----------", "-----------", "--------", "--------", "------------", "-----------"); -#else - fprintf(fp, "\n"); -#endif - total = 0; - for (int m = 0; m < TMM_SIZE; m++) { - if (!(tmm_modules[m].flags & TM_FLAG_LOGAPI_TM)) - continue; - - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; - total += pd->tot; - - pd = &packet_profile_tmm_data6[m][p]; - total += pd->tot; - } - } - - for (int m = 0; m < TMM_SIZE; m++) { - if (!(tmm_modules[m].flags & TM_FLAG_LOGAPI_TM)) - continue; - - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f", - TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); -#ifdef PROFILE_LOCKING - fprintf(fp, " %10.2f %12"PRIu64" %12"PRIu64" %10.2f %10.2f %12"PRIu64" %12"PRIu64" %10.2f\n", - (float)pd->lock/pd->cnt, (uint64_t)pd->ticks/pd->cnt, pd->contention, (float)pd->contention/pd->cnt, (float)pd->slock/pd->cnt, (uint64_t)pd->sticks/pd->cnt, pd->scontention, (float)pd->scontention/pd->cnt); -#else - fprintf(fp, "\n"); -#endif - } - } - - for (int m = 0; m < TMM_SIZE; m++) { - if (!(tmm_modules[m].flags & TM_FLAG_LOGAPI_TM)) - continue; - - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_tmm_data6[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n", - TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - - fprintf(fp, "\nLogger/output stats:\n"); - - total = 0; - for (int m = 0; m < LOGGER_SIZE; m++) { - for (int p = 0; p < 256; p++) { - SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; - total += pd->tot; - pd = &packet_profile_log_data6[m][p]; - total += pd->tot; - } - } - - fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", - "Logger", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot"); - fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", - "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------"); - for (int m = 0; m < LOGGER_SIZE; m++) { - for (int p = 0; p < 256; p++) { - SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, - "%-24s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 - " %12" PRIu64 " %12s %-6.2f\n", - PacketProfileLoggerIdToString(m), p, pd->cnt, pd->min, pd->max, - (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - for (int m = 0; m < LOGGER_SIZE; m++) { - for (int p = 0; p < 256; p++) { - SCProfilePacketData *pd = &packet_profile_log_data6[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, - "%-24s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 - " %12" PRIu64 " %12s %-6.2f\n", - PacketProfileLoggerIdToString(m), p, pd->cnt, pd->min, pd->max, - (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - - fprintf(fp, "\nGeneral detection engine stats:\n"); - - total = 0; - for (int m = 0; m < PROF_DETECT_SIZE; m++) { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_detect_data4[m][p]; - total += pd->tot; - pd = &packet_profile_detect_data6[m][p]; - total += pd->tot; - } - } - - fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", - "Detection phase", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot"); - fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", - "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------"); - for (int m = 0; m < PROF_DETECT_SIZE; m++) { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_detect_data4[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", - PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - for (int m = 0; m < PROF_DETECT_SIZE; m++) { - for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_detect_data6[m][p]; - if (pd->cnt == 0) { - continue; - } - - FormatNumber(pd->tot, totalstr, sizeof(totalstr)); - double percent = (long double)pd->tot / - (long double)total * 100; - - fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", - PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); - } - } - fclose(fp); -} - -static void PrintCSVHeader(void) -{ - fprintf(packet_profile_csv_fp, "pcap_cnt,total,receive,decode,flowworker,"); - fprintf(packet_profile_csv_fp, "threading,"); - fprintf(packet_profile_csv_fp, "proto detect,"); - - for (enum ProfileFlowWorkerId fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { - fprintf(packet_profile_csv_fp, "%s,", ProfileFlowWorkerIdToString(fwi)); - } - fprintf(packet_profile_csv_fp, "loggers,"); - - /* detect stages */ - for (int i = 0; i < PROF_DETECT_SIZE; i++) { - fprintf(packet_profile_csv_fp, "%s,", PacketProfileDetectIdToString(i)); - } - - /* individual loggers */ - for (LoggerId i = 0; i < LOGGER_SIZE; i++) { - fprintf(packet_profile_csv_fp, "%s,", PacketProfileLoggerIdToString(i)); - } - - fprintf(packet_profile_csv_fp, "\n"); -} - -void SCProfilingPrintPacketProfile(Packet *p) -{ - if (profiling_packets_csv_enabled == 0 || p == NULL || - packet_profile_csv_fp == NULL || p->profile == NULL) { - return; - } - - uint64_t tmm_total = 0; - uint64_t receive = 0; - uint64_t decode = 0; - - /* total cost from acquisition to return to packetpool */ - uint64_t delta = p->profile->ticks_end - p->profile->ticks_start; - fprintf(packet_profile_csv_fp, "%"PRIu64",%"PRIu64",", - p->pcap_cnt, delta); - - for (int i = 0; i < TMM_SIZE; i++) { - const PktProfilingTmmData *pdt = &p->profile->tmm[i]; - uint64_t tmm_delta = pdt->ticks_end - pdt->ticks_start; - - if (tmm_modules[i].flags & TM_FLAG_RECEIVE_TM) { - if (tmm_delta) { - receive = tmm_delta; - } - continue; - - } else if (tmm_modules[i].flags & TM_FLAG_DECODE_TM) { - if (tmm_delta) { - decode = tmm_delta; - } - continue; - } - - tmm_total += tmm_delta; - } - fprintf(packet_profile_csv_fp, "%"PRIu64",", receive); - fprintf(packet_profile_csv_fp, "%"PRIu64",", decode); - PktProfilingTmmData *fw_pdt = &p->profile->tmm[TMM_FLOWWORKER]; - fprintf(packet_profile_csv_fp, "%"PRIu64",", fw_pdt->ticks_end - fw_pdt->ticks_start); - fprintf(packet_profile_csv_fp, "%"PRIu64",", delta - tmm_total); - - /* count ticks for app layer */ - uint64_t app_total = 0; - for (AppProto i = 1; i < ALPROTO_FAILED; i++) { - const PktProfilingAppData *pdt = &p->profile->app[i]; - - if (p->proto == IPPROTO_TCP) { - app_total += pdt->ticks_spent; - } - } - - fprintf(packet_profile_csv_fp, "%"PRIu64",", p->profile->proto_detect); - - /* print flowworker steps */ - for (enum ProfileFlowWorkerId fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { - const PktProfilingData *pd = &p->profile->flowworker[fwi]; - uint64_t ticks_spent = pd->ticks_end - pd->ticks_start; - if (fwi == PROFILE_FLOWWORKER_STREAM) { - ticks_spent -= app_total; - } else if (fwi == PROFILE_FLOWWORKER_APPLAYERUDP && app_total) { - ticks_spent = app_total; - } - - fprintf(packet_profile_csv_fp, "%"PRIu64",", ticks_spent); - } - - /* count loggers cost and print as a single cost */ - uint64_t loggers = 0; - for (LoggerId i = 0; i < LOGGER_SIZE; i++) { - const PktProfilingLoggerData *pd = &p->profile->logger[i]; - loggers += pd->ticks_spent; - } - fprintf(packet_profile_csv_fp, "%"PRIu64",", loggers); - - /* detect steps */ - for (int i = 0; i < PROF_DETECT_SIZE; i++) { - const PktProfilingDetectData *pdt = &p->profile->detect[i]; - - fprintf(packet_profile_csv_fp,"%"PRIu64",", pdt->ticks_spent); - } - - /* print individual loggers */ - for (LoggerId i = 0; i < LOGGER_SIZE; i++) { - const PktProfilingLoggerData *pd = &p->profile->logger[i]; - fprintf(packet_profile_csv_fp, "%"PRIu64",", pd->ticks_spent); - } - - fprintf(packet_profile_csv_fp,"\n"); -} - -static void SCProfilingUpdatePacketDetectRecord(PacketProfileDetectId id, uint8_t ipproto, PktProfilingDetectData *pdt, int ipver) -{ - if (pdt == NULL) { - return; - } - - SCProfilePacketData *pd; - if (ipver == 4) - pd = &packet_profile_detect_data4[id][ipproto]; - else - pd = &packet_profile_detect_data6[id][ipproto]; - - if (pd->min == 0 || pdt->ticks_spent < pd->min) { - pd->min = pdt->ticks_spent; - } - if (pd->max < pdt->ticks_spent) { - pd->max = pdt->ticks_spent; - } - - pd->tot += pdt->ticks_spent; - pd->cnt ++; -} - -static void SCProfilingUpdatePacketDetectRecords(Packet *p) -{ - PacketProfileDetectId i; - for (i = 0; i < PROF_DETECT_SIZE; i++) { - PktProfilingDetectData *pdt = &p->profile->detect[i]; - - if (pdt->ticks_spent > 0) { - if (PKT_IS_IPV4(p)) { - SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 4); - } else { - SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 6); - } - } - } -} - -static void SCProfilingUpdatePacketAppPdRecord(uint8_t ipproto, uint32_t ticks_spent, int ipver) -{ - SCProfilePacketData *pd; - if (ipver == 4) - pd = &packet_profile_app_pd_data4[ipproto]; - else - pd = &packet_profile_app_pd_data6[ipproto]; - - if (pd->min == 0 || ticks_spent < pd->min) { - pd->min = ticks_spent; - } - if (pd->max < ticks_spent) { - pd->max = ticks_spent; - } - - pd->tot += ticks_spent; - pd->cnt ++; -} - -static void SCProfilingUpdatePacketAppRecord(int alproto, uint8_t ipproto, PktProfilingAppData *pdt, int ipver) -{ - if (pdt == NULL) { - return; - } - - SCProfilePacketData *pd; - if (ipver == 4) - pd = &packet_profile_app_data4[alproto][ipproto]; - else - pd = &packet_profile_app_data6[alproto][ipproto]; - - if (pd->min == 0 || pdt->ticks_spent < pd->min) { - pd->min = pdt->ticks_spent; - } - if (pd->max < pdt->ticks_spent) { - pd->max = pdt->ticks_spent; - } - - pd->tot += pdt->ticks_spent; - pd->cnt ++; -} - -static void SCProfilingUpdatePacketAppRecords(Packet *p) -{ - int i; - for (i = 0; i < ALPROTO_MAX; i++) { - PktProfilingAppData *pdt = &p->profile->app[i]; - - if (pdt->ticks_spent > 0) { - if (PKT_IS_IPV4(p)) { - SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 4); - } else { - SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 6); - } - } - } - - if (p->profile->proto_detect > 0) { - if (PKT_IS_IPV4(p)) { - SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 4); - } else { - SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 6); - } - } -} - -static void SCProfilingUpdatePacketTmmRecord(int module, uint8_t proto, PktProfilingTmmData *pdt, int ipver) -{ - if (pdt == NULL) { - return; - } - - SCProfilePacketData *pd; - if (ipver == 4) - pd = &packet_profile_tmm_data4[module][proto]; - else - pd = &packet_profile_tmm_data6[module][proto]; - - uint32_t delta = (uint32_t)pdt->ticks_end - pdt->ticks_start; - if (pd->min == 0 || delta < pd->min) { - pd->min = delta; - } - if (pd->max < delta) { - pd->max = delta; - } - - pd->tot += (uint64_t)delta; - pd->cnt ++; - -#ifdef PROFILE_LOCKING - pd->lock += pdt->mutex_lock_cnt; - pd->ticks += pdt->mutex_lock_wait_ticks; - pd->contention += pdt->mutex_lock_contention; - pd->slock += pdt->spin_lock_cnt; - pd->sticks += pdt->spin_lock_wait_ticks; - pd->scontention += pdt->spin_lock_contention; -#endif -} - -static void SCProfilingUpdatePacketTmmRecords(Packet *p) -{ - int i; - for (i = 0; i < TMM_SIZE; i++) { - PktProfilingTmmData *pdt = &p->profile->tmm[i]; - - if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) { - continue; - } - - if (PKT_IS_IPV4(p)) { - SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 4); - } else { - SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 6); - } - } -} - -static inline void SCProfilingUpdatePacketGenericRecord(PktProfilingData *pdt, - SCProfilePacketData *pd) -{ - if (pdt == NULL || pd == NULL) { - return; - } - - uint64_t delta = pdt->ticks_end - pdt->ticks_start; - if (pd->min == 0 || delta < pd->min) { - pd->min = delta; - } - if (pd->max < delta) { - pd->max = delta; - } - - pd->tot += delta; - pd->cnt ++; -} - -static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *pd, - struct ProfileProtoRecords *records, int size) -{ - int i; - for (i = 0; i < size; i++) { - PktProfilingData *pdt = &pd[i]; - - if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) { - continue; - } - - struct ProfileProtoRecords *r = &records[i]; - SCProfilePacketData *store = NULL; - - if (PKT_IS_IPV4(p)) { - store = &(r->records4[p->proto]); - } else { - store = &(r->records6[p->proto]); - } - - SCProfilingUpdatePacketGenericRecord(pdt, store); - } -} - -static void SCProfilingUpdatePacketLogRecord(LoggerId id, - uint8_t ipproto, PktProfilingLoggerData *pdt, int ipver) -{ - if (pdt == NULL) { - return; - } - - SCProfilePacketData *pd; - if (ipver == 4) - pd = &packet_profile_log_data4[id][ipproto]; - else - pd = &packet_profile_log_data6[id][ipproto]; - - if (pd->min == 0 || pdt->ticks_spent < pd->min) { - pd->min = pdt->ticks_spent; - } - if (pd->max < pdt->ticks_spent) { - pd->max = pdt->ticks_spent; - } - - pd->tot += pdt->ticks_spent; - pd->cnt++; -} - -static void SCProfilingUpdatePacketLogRecords(Packet *p) -{ - for (LoggerId i = 0; i < LOGGER_SIZE; i++) { - PktProfilingLoggerData *pdt = &p->profile->logger[i]; - - if (pdt->ticks_spent > 0) { - if (PKT_IS_IPV4(p)) { - SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 4); - } else { - SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 6); - } - } - } -} - -void SCProfilingAddPacket(Packet *p) -{ - if (p == NULL || p->profile == NULL || - p->profile->ticks_start == 0 || p->profile->ticks_end == 0 || - p->profile->ticks_start > p->profile->ticks_end) - return; - - pthread_mutex_lock(&packet_profile_lock); - { - - if (PKT_IS_IPV4(p)) { - SCProfilePacketData *pd = &packet_profile_data4[p->proto]; - - uint64_t delta = p->profile->ticks_end - p->profile->ticks_start; - if (pd->min == 0 || delta < pd->min) { - pd->min = delta; - } - if (pd->max < delta) { - pd->max = delta; - } - - pd->tot += delta; - pd->cnt ++; - - if (IS_TUNNEL_PKT(p)) { - pd = &packet_profile_data4[256]; - - if (pd->min == 0 || delta < pd->min) { - pd->min = delta; - } - if (pd->max < delta) { - pd->max = delta; - } - - pd->tot += delta; - pd->cnt ++; - } - - SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, - packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); - - SCProfilingUpdatePacketTmmRecords(p); - SCProfilingUpdatePacketAppRecords(p); - SCProfilingUpdatePacketDetectRecords(p); - SCProfilingUpdatePacketLogRecords(p); - - } else if (PKT_IS_IPV6(p)) { - SCProfilePacketData *pd = &packet_profile_data6[p->proto]; - - uint64_t delta = p->profile->ticks_end - p->profile->ticks_start; - if (pd->min == 0 || delta < pd->min) { - pd->min = delta; - } - if (pd->max < delta) { - pd->max = delta; - } - - pd->tot += delta; - pd->cnt ++; - - if (IS_TUNNEL_PKT(p)) { - pd = &packet_profile_data6[256]; - - if (pd->min == 0 || delta < pd->min) { - pd->min = delta; - } - if (pd->max < delta) { - pd->max = delta; - } - - pd->tot += delta; - pd->cnt ++; - } - - SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, - packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); - - SCProfilingUpdatePacketTmmRecords(p); - SCProfilingUpdatePacketAppRecords(p); - SCProfilingUpdatePacketDetectRecords(p); - SCProfilingUpdatePacketLogRecords(p); - } - - if (profiling_packets_csv_enabled) - SCProfilingPrintPacketProfile(p); - - } - pthread_mutex_unlock(&packet_profile_lock); -} - -PktProfiling *SCProfilePacketStart(void) -{ - uint64_t sample = SC_ATOMIC_ADD(samples, 1); - if (sample % rate == 0) - return SCCalloc(1, sizeof(PktProfiling)); - else - return NULL; -} - -/* see if we want to profile rules for this packet */ -int SCProfileRuleStart(Packet *p) -{ -#ifdef PROFILE_LOCKING - if (p->profile != NULL) { - p->flags |= PKT_PROFILE; - return 1; - } -#else - uint64_t sample = SC_ATOMIC_ADD(samples, 1); - if (sample % rate == 0) { - p->flags |= PKT_PROFILE; - return 1; - } -#endif - if (p->flags & PKT_PROFILE) - return 1; - return 0; -} - -#define CASE_CODE(E) case E: return #E - -/** - * \brief Maps the PacketProfileDetectId, to its string equivalent - * - * \param id PacketProfileDetectId id - * - * \retval string equivalent for the PacketProfileDetectId id - */ -const char * PacketProfileDetectIdToString(PacketProfileDetectId id) -{ - switch (id) { - CASE_CODE(PROF_DETECT_SETUP); - CASE_CODE(PROF_DETECT_GETSGH); - CASE_CODE(PROF_DETECT_IPONLY); - CASE_CODE(PROF_DETECT_RULES); - CASE_CODE(PROF_DETECT_PF_PKT); - CASE_CODE(PROF_DETECT_PF_PAYLOAD); - CASE_CODE(PROF_DETECT_PF_TX); - CASE_CODE(PROF_DETECT_PF_RECORD); - CASE_CODE(PROF_DETECT_PF_SORT1); - CASE_CODE(PROF_DETECT_PF_SORT2); - CASE_CODE(PROF_DETECT_NONMPMLIST); - CASE_CODE(PROF_DETECT_TX); - CASE_CODE(PROF_DETECT_ALERT); - CASE_CODE(PROF_DETECT_TX_UPDATE); - CASE_CODE(PROF_DETECT_CLEANUP); - default: - return "UNKNOWN"; - } -} - -/** - * \brief Maps the LoggerId's to its string equivalent for profiling output. - * - * \param id LoggerId id - * - * \retval string equivalent for the LoggerId id - */ -const char *PacketProfileLoggerIdToString(LoggerId id) -{ - switch (id) { - CASE_CODE(LOGGER_UNDEFINED); - CASE_CODE(LOGGER_HTTP); - CASE_CODE(LOGGER_TLS_STORE); - CASE_CODE(LOGGER_TLS); - CASE_CODE(LOGGER_JSON_TX); - CASE_CODE(LOGGER_FILE); - CASE_CODE(LOGGER_FILEDATA); - CASE_CODE(LOGGER_ALERT_DEBUG); - CASE_CODE(LOGGER_ALERT_FAST); - CASE_CODE(LOGGER_ALERT_SYSLOG); - CASE_CODE(LOGGER_JSON_ALERT); - CASE_CODE(LOGGER_JSON_ANOMALY); - CASE_CODE(LOGGER_JSON_DROP); - CASE_CODE(LOGGER_FILE_STORE); - CASE_CODE(LOGGER_JSON_FILE); - CASE_CODE(LOGGER_TCP_DATA); - CASE_CODE(LOGGER_JSON_FLOW); - CASE_CODE(LOGGER_JSON_NETFLOW); - CASE_CODE(LOGGER_STATS); - CASE_CODE(LOGGER_JSON_STATS); - CASE_CODE(LOGGER_PCAP); - CASE_CODE(LOGGER_JSON_METADATA); - CASE_CODE(LOGGER_JSON_FRAME); - CASE_CODE(LOGGER_JSON_STREAM); - - case LOGGER_SIZE: - return "UNKNOWN"; - } - return "UNKNOWN"; -} - -#ifdef UNITTESTS - -static int -ProfilingGenericTicksTest01(void) -{ -#define TEST_RUNS 1024 - uint64_t ticks_start = 0; - uint64_t ticks_end = 0; - void *ptr[TEST_RUNS]; - unsigned int i; - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - ptr[i] = SCMalloc(1024); - } - ticks_end = UtilCpuGetTicks(); - printf("malloc(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCFree(ptr[i]); - } - ticks_end = UtilCpuGetTicks(); - printf("SCFree(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - SCMutex m[TEST_RUNS]; - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCMutexInit(&m[i], NULL); - } - ticks_end = UtilCpuGetTicks(); - printf("SCMutexInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCMutexLock(&m[i]); - } - ticks_end = UtilCpuGetTicks(); - printf("SCMutexLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCMutexUnlock(&m[i]); - } - ticks_end = UtilCpuGetTicks(); - printf("SCMutexUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCMutexDestroy(&m[i]); - } - ticks_end = UtilCpuGetTicks(); - printf("SCMutexDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - SCSpinlock s[TEST_RUNS]; - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCSpinInit(&s[i], 0); - } - ticks_end = UtilCpuGetTicks(); - printf("SCSpinInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCSpinLock(&s[i]); - } - ticks_end = UtilCpuGetTicks(); - printf("SCSpinLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCSpinUnlock(&s[i]); - } - ticks_end = UtilCpuGetTicks(); - printf("SCSpinUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SCSpinDestroy(&s[i]); - } - ticks_end = UtilCpuGetTicks(); - printf("SCSpinDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - SC_ATOMIC_DECL_AND_INIT(unsigned int, test); - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - (void) SC_ATOMIC_ADD(test,1); - } - ticks_end = UtilCpuGetTicks(); - printf("SC_ATOMIC_ADD %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - - ticks_start = UtilCpuGetTicks(); - for (i = 0; i < TEST_RUNS; i++) { - SC_ATOMIC_CAS(&test,i,i+1); - } - ticks_end = UtilCpuGetTicks(); - printf("SC_ATOMIC_CAS %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS); - return 1; -} - -#endif /* UNITTESTS */ - -void -SCProfilingRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01); -#endif /* UNITTESTS */ -} - -void SCProfileRuleStartCollection(void) -{ -} - -void SCProfileRuleStopCollection(void) -{ -} - -#elif PROFILE_RULES - -thread_local int profiling_rules_entered = 0; -int profiling_output_to_file = 0; -static SC_ATOMIC_DECLARE(uint64_t, samples); -static uint64_t rate = 0; -static SC_ATOMIC_DECLARE(bool, profiling_rules_active); - -/** - * \brief Initialize profiling. - */ -void SCProfilingInit(void) -{ - SC_ATOMIC_INIT(profiling_rules_active); - SC_ATOMIC_INIT(samples); - intmax_t rate_v = 0; - - (void)ConfGetInt("profiling.sample-rate", &rate_v); - if (rate_v > 0 && rate_v < INT_MAX) { - int literal_rate = (int)rate_v; - for (int i = literal_rate; i >= 1; i--) { - /* If i is a power of 2 */ - if ((i & (i - 1)) == 0) { - rate = i - 1; - break; - } - } - if (rate != 0) - SCLogInfo("profiling runs for every %luth packet", rate + 1); - else - SCLogInfo("profiling runs for every packet"); - } -} - -/* see if we want to profile rules for this packet */ -int SCProfileRuleStart(Packet *p) -{ - if (!SC_ATOMIC_GET(profiling_rules_active)) { - return 0; - } - uint64_t sample = SC_ATOMIC_ADD(samples, 1); - if ((sample & rate) == 0) { - p->flags |= PKT_PROFILE; - return 1; - } - - if (p->flags & PKT_PROFILE) - return 1; - return 0; -} - -void SCProfileRuleStartCollection(void) -{ - SC_ATOMIC_SET(profiling_rules_active, true); -} - -void SCProfileRuleStopCollection(void) -{ - SC_ATOMIC_SET(profiling_rules_active, false); -} - -#endif /* PROFILING */ diff --git a/src/util-profiling.h b/src/util-profiling.h deleted file mode 100644 index 6450bc8cefe3..000000000000 --- a/src/util-profiling.h +++ /dev/null @@ -1,435 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Endace Technology Limited. - * \author Victor Julien - */ - -#ifndef __UTIL_PROFILE_H__ -#define __UTIL_PROFILE_H__ - -#include "util-cpu.h" - -#include "detect.h" - -#ifdef PROFILING - -#include "util-cpu.h" -#include "util-profiling-locks.h" - -extern int profiling_rules_enabled; -extern int profiling_packets_enabled; -extern int profiling_sghs_enabled; - -void SCProfilingPrintPacketProfile(Packet *); -void SCProfilingAddPacket(Packet *); -extern int profiling_keyword_enabled; -extern thread_local int profiling_keyword_entered; - -#define KEYWORD_PROFILING_SET_LIST(ctx, list) { \ - (ctx)->keyword_perf_list = (list); \ -} - -#define KEYWORD_PROFILING_START \ - uint64_t profile_keyword_start_ = 0; \ - uint64_t profile_keyword_end_ = 0; \ - if (profiling_keyword_enabled) { \ - if (profiling_keyword_entered > 0) { \ - SCLogError("Re-entered profiling, exiting."); \ - abort(); \ - } \ - profiling_keyword_entered++; \ - profile_keyword_start_ = UtilCpuGetTicks(); \ - } - -/* we allow this macro to be called if profiling_keyword_entered == 0, - * so that we don't have to refactor some of the detection code. */ -#define KEYWORD_PROFILING_END(ctx, type, m) \ - if (profiling_keyword_enabled && profiling_keyword_entered) { \ - profile_keyword_end_ = UtilCpuGetTicks(); \ - SCProfilingKeywordUpdateCounter((ctx),(type),(profile_keyword_end_ - profile_keyword_start_),(m)); \ - profiling_keyword_entered--; \ - } - -PktProfiling *SCProfilePacketStart(void); - -#define PACKET_PROFILING_START(p) \ - if (profiling_packets_enabled) { \ - (p)->profile = SCProfilePacketStart(); \ - if ((p)->profile != NULL) \ - (p)->profile->ticks_start = UtilCpuGetTicks(); \ - } - -#define PACKET_PROFILING_RESTART(p) \ - if (profiling_packets_enabled) { \ - if ((p)->profile != NULL) \ - (p)->profile->ticks_start = UtilCpuGetTicks(); \ - } - -#define PACKET_PROFILING_END(p) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - (p)->profile->ticks_end = UtilCpuGetTicks(); \ - SCProfilingAddPacket((p)); \ - } - -#ifdef PROFILE_LOCKING -#define PACKET_PROFILING_RESET_LOCKS do { \ - mutex_lock_cnt = 0; \ - mutex_lock_wait_ticks = 0; \ - mutex_lock_contention = 0; \ - spin_lock_cnt = 0; \ - spin_lock_wait_ticks = 0; \ - spin_lock_contention = 0; \ - rww_lock_cnt = 0; \ - rww_lock_wait_ticks = 0; \ - rww_lock_contention = 0; \ - rwr_lock_cnt = 0; \ - rwr_lock_wait_ticks = 0; \ - rwr_lock_contention = 0; \ - locks_idx = 0; \ - record_locks = 1;\ - } while (0) - -#define PACKET_PROFILING_COPY_LOCKS(p, id) do { \ - (p)->profile->tmm[(id)].mutex_lock_cnt = mutex_lock_cnt; \ - (p)->profile->tmm[(id)].mutex_lock_wait_ticks = mutex_lock_wait_ticks; \ - (p)->profile->tmm[(id)].mutex_lock_contention = mutex_lock_contention; \ - (p)->profile->tmm[(id)].spin_lock_cnt = spin_lock_cnt; \ - (p)->profile->tmm[(id)].spin_lock_wait_ticks = spin_lock_wait_ticks; \ - (p)->profile->tmm[(id)].spin_lock_contention = spin_lock_contention; \ - (p)->profile->tmm[(id)].rww_lock_cnt = rww_lock_cnt; \ - (p)->profile->tmm[(id)].rww_lock_wait_ticks = rww_lock_wait_ticks; \ - (p)->profile->tmm[(id)].rww_lock_contention = rww_lock_contention; \ - (p)->profile->tmm[(id)].rwr_lock_cnt = rwr_lock_cnt; \ - (p)->profile->tmm[(id)].rwr_lock_wait_ticks = rwr_lock_wait_ticks; \ - (p)->profile->tmm[(id)].rwr_lock_contention = rwr_lock_contention; \ - record_locks = 0; \ - SCProfilingAddPacketLocks((p)); \ - } while(0) -#else -#define PACKET_PROFILING_RESET_LOCKS -#define PACKET_PROFILING_COPY_LOCKS(p, id) -#endif - -#define PACKET_PROFILING_TMM_START(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < TMM_SIZE) { \ - (p)->profile->tmm[(id)].ticks_start = UtilCpuGetTicks();\ - PACKET_PROFILING_RESET_LOCKS; \ - } \ - } - -#define PACKET_PROFILING_TMM_END(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < TMM_SIZE) { \ - PACKET_PROFILING_COPY_LOCKS((p), (id)); \ - (p)->profile->tmm[(id)].ticks_end = UtilCpuGetTicks(); \ - } \ - } - -#define FLOWWORKER_PROFILING_START(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < PROFILE_FLOWWORKER_SIZE) { \ - (p)->profile->flowworker[(id)].ticks_start = UtilCpuGetTicks();\ - } \ - } - -#define FLOWWORKER_PROFILING_END(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < PROFILE_FLOWWORKER_SIZE) { \ - (p)->profile->flowworker[(id)].ticks_end = UtilCpuGetTicks(); \ - } \ - } - -#define PACKET_PROFILING_RESET(p) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - SCFree((p)->profile); \ - (p)->profile = NULL; \ - } - -#define PACKET_PROFILING_APP_START(dp, id) \ - if (profiling_packets_enabled) { \ - (dp)->ticks_start = UtilCpuGetTicks(); \ - (dp)->alproto = (id); \ - } - -#define PACKET_PROFILING_APP_END(dp, id) \ - if (profiling_packets_enabled) { \ - BUG_ON((id) != (dp)->alproto); \ - (dp)->ticks_end = UtilCpuGetTicks(); \ - if ((dp)->ticks_start != 0 && (dp)->ticks_start < ((dp)->ticks_end)) { \ - (dp)->ticks_spent = ((dp)->ticks_end - (dp)->ticks_start); \ - } \ - } - -#define PACKET_PROFILING_APP_PD_START(dp) \ - if (profiling_packets_enabled) { \ - (dp)->proto_detect_ticks_start = UtilCpuGetTicks(); \ - } - -#define PACKET_PROFILING_APP_PD_END(dp) \ - if (profiling_packets_enabled) { \ - (dp)->proto_detect_ticks_end = UtilCpuGetTicks(); \ - if ((dp)->proto_detect_ticks_start != 0 && (dp)->proto_detect_ticks_start < ((dp)->proto_detect_ticks_end)) { \ - (dp)->proto_detect_ticks_spent = \ - ((dp)->proto_detect_ticks_end - (dp)->proto_detect_ticks_start); \ - } \ - } - -#define PACKET_PROFILING_APP_RESET(dp) \ - if (profiling_packets_enabled) { \ - (dp)->ticks_start = 0; \ - (dp)->ticks_end = 0; \ - (dp)->ticks_spent = 0; \ - (dp)->alproto = 0; \ - (dp)->proto_detect_ticks_start = 0; \ - (dp)->proto_detect_ticks_end = 0; \ - (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_DETECT_START(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < PROF_DETECT_SIZE) { \ - (p)->profile->detect[(id)].ticks_start = UtilCpuGetTicks(); \ - } \ - } - -#define PACKET_PROFILING_DETECT_END(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < PROF_DETECT_SIZE) { \ - (p)->profile->detect[(id)].ticks_end = UtilCpuGetTicks();\ - if ((p)->profile->detect[(id)].ticks_start != 0 && \ - (p)->profile->detect[(id)].ticks_start < (p)->profile->detect[(id)].ticks_end) { \ - (p)->profile->detect[(id)].ticks_spent += \ - ((p)->profile->detect[(id)].ticks_end - (p)->profile->detect[(id)].ticks_start); \ - } \ - } \ - } - -#define PACKET_PROFILING_LOGGER_START(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < LOGGER_SIZE) { \ - (p)->profile->logger[(id)].ticks_start = UtilCpuGetTicks(); \ - } \ - } - -#define PACKET_PROFILING_LOGGER_END(p, id) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((id) < LOGGER_SIZE) { \ - (p)->profile->logger[(id)].ticks_end = UtilCpuGetTicks();\ - if ((p)->profile->logger[(id)].ticks_start != 0 && \ - (p)->profile->logger[(id)].ticks_start < (p)->profile->logger[(id)].ticks_end) { \ - (p)->profile->logger[(id)].ticks_spent += \ - ((p)->profile->logger[(id)].ticks_end - (p)->profile->logger[(id)].ticks_start); \ - } \ - } \ - } - -#define SGH_PROFILING_RECORD(det_ctx, sgh) \ - if (profiling_sghs_enabled) { \ - SCProfilingSghUpdateCounter((det_ctx), (sgh)); \ - } - -extern int profiling_prefilter_enabled; -extern thread_local int profiling_prefilter_entered; - -#define PREFILTER_PROFILING_START(det_ctx) \ - (det_ctx)->prefilter_bytes = 0; \ - (det_ctx)->prefilter_bytes_called = 0; \ - uint64_t profile_prefilter_start_ = 0; \ - uint64_t profile_prefilter_end_ = 0; \ - if (profiling_prefilter_enabled) { \ - if (profiling_prefilter_entered > 0) { \ - SCLogError("Re-entered profiling, exiting."); \ - abort(); \ - } \ - profiling_prefilter_entered++; \ - profile_prefilter_start_ = UtilCpuGetTicks(); \ - } - -/* we allow this macro to be called if profiling_prefilter_entered == 0, - * so that we don't have to refactor some of the detection code. */ -#define PREFILTER_PROFILING_END(ctx, profile_id) \ - if (profiling_prefilter_enabled && profiling_prefilter_entered) { \ - profile_prefilter_end_ = UtilCpuGetTicks(); \ - if (profile_prefilter_end_ > profile_prefilter_start_) \ - SCProfilingPrefilterUpdateCounter((ctx), (profile_id), \ - (profile_prefilter_end_ - profile_prefilter_start_), (ctx)->prefilter_bytes, \ - (ctx)->prefilter_bytes_called); \ - profiling_prefilter_entered--; \ - } - -#define PREFILTER_PROFILING_ADD_BYTES(det_ctx, bytes) \ - (det_ctx)->prefilter_bytes += (bytes); \ - (det_ctx)->prefilter_bytes_called++ - -struct SCProfileDetectCtx_; -void SCProfilingRulesGlobalInit(void); -void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); -void SCProfilingRuleInitCounters(DetectEngineCtx *); -void SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *, uint16_t, uint64_t, int); -void SCProfilingRuleThreadSetup(struct SCProfileDetectCtx_ *, DetectEngineThreadCtx *); -void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *); - -void SCProfilingKeywordsGlobalInit(void); -void SCProfilingKeywordDestroyCtx(DetectEngineCtx *);//struct SCProfileKeywordDetectCtx_ *); -void SCProfilingKeywordInitCounters(DetectEngineCtx *); -void SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, int match); -void SCProfilingKeywordThreadSetup(struct SCProfileKeywordDetectCtx_ *, DetectEngineThreadCtx *); -void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *); - -struct SCProfilePrefilterDetectCtx_; -void SCProfilingPrefilterGlobalInit(void); -void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *); -void SCProfilingPrefilterInitCounters(DetectEngineCtx *); -void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, - uint64_t bytes, uint64_t bytes_called); -void SCProfilingPrefilterThreadSetup(struct SCProfilePrefilterDetectCtx_ *, DetectEngineThreadCtx *); -void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *); - -void SCProfilingSghsGlobalInit(void); -void SCProfilingSghDestroyCtx(DetectEngineCtx *); -void SCProfilingSghInitCounters(DetectEngineCtx *); -void SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh); -void SCProfilingSghThreadSetup(struct SCProfileSghDetectCtx_ *, DetectEngineThreadCtx *); -void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *); - -void SCProfilingInit(void); -void SCProfilingDestroy(void); -void SCProfilingRegisterTests(void); -void SCProfilingDump(void); - -#else - -#define KEYWORD_PROFILING_SET_LIST(a,b) -#define KEYWORD_PROFILING_START -#define KEYWORD_PROFILING_END(a,b,c) - -#define PACKET_PROFILING_START(p) -#define PACKET_PROFILING_RESTART(p) -#define PACKET_PROFILING_END(p) - -#define PACKET_PROFILING_TMM_START(p, id) -#define PACKET_PROFILING_TMM_END(p, id) - -#define PACKET_PROFILING_RESET(p) - -#define PACKET_PROFILING_APP_START(dp, id) -#define PACKET_PROFILING_APP_END(dp, id) -#define PACKET_PROFILING_APP_RESET(dp) -#define PACKET_PROFILING_APP_STORE(dp, p) - -#define PACKET_PROFILING_APP_PD_START(dp) -#define PACKET_PROFILING_APP_PD_END(dp) - -#define PACKET_PROFILING_DETECT_START(p, id) -#define PACKET_PROFILING_DETECT_END(p, id) - -#define PACKET_PROFILING_LOGGER_START(p, id) -#define PACKET_PROFILING_LOGGER_END(p, id) - -#define SGH_PROFILING_RECORD(det_ctx, sgh) - -#define FLOWWORKER_PROFILING_START(p, id) -#define FLOWWORKER_PROFILING_END(p, id) - -#define PREFILTER_PROFILING_START(ctx) -#define PREFILTER_PROFILING_END(ctx, profile_id) -#define PREFILTER_PROFILING_ADD_BYTES(det_ctx, bytes) - -#endif /* PROFILING */ - -#ifdef PROFILE_RULES - -extern int profiling_rules_enabled; -extern thread_local int profiling_rules_entered; - -#ifndef PROFILING -void SCProfilingInit(void); -#endif -/** - * Extra data for rule profiling. - */ -typedef struct SCProfileData_ { - uint32_t sid; - uint32_t gid; - uint32_t rev; - uint64_t checks; - uint64_t matches; - uint64_t max; - uint64_t ticks_match; - uint64_t ticks_no_match; -} SCProfileData; - -typedef struct SCProfileDetectCtx_ { - uint32_t size; - uint32_t id; - SCProfileData *data; - pthread_mutex_t data_m; -} SCProfileDetectCtx; - -void SCProfilingRulesGlobalInit(void); -void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); -void SCProfilingRuleInitCounters(DetectEngineCtx *); -void SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *, uint16_t, uint64_t, int); -void SCProfilingRuleThreadSetup(struct SCProfileDetectCtx_ *, DetectEngineThreadCtx *); -void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *); -int SCProfileRuleStart(Packet *p); -json_t *SCProfileRuleTriggerDump(DetectEngineCtx *de_ctx); -void SCProfileRuleStartCollection(void); -void SCProfileRuleStopCollection(void); -void SCProfilingRuleThreatAggregate(DetectEngineThreadCtx *det_ctx); - -#define RULE_PROFILING_START(p) \ - uint64_t profile_rule_start_ = 0; \ - uint64_t profile_rule_end_ = 0; \ - if (profiling_rules_enabled && SCProfileRuleStart((p))) { \ - if (profiling_rules_entered > 0) { \ - FatalError("Re-entered profiling, exiting."); \ - } \ - profiling_rules_entered++; \ - profile_rule_start_ = UtilCpuGetTicks(); \ - } - -#define RULE_PROFILING_END(ctx, r, m, p) \ - if (profiling_rules_enabled && ((p)->flags & PKT_PROFILE)) { \ - profile_rule_end_ = UtilCpuGetTicks(); \ - SCProfilingRuleUpdateCounter( \ - ctx, r->profiling_id, profile_rule_end_ - profile_rule_start_, m); \ - profiling_rules_entered--; \ - BUG_ON(profiling_rules_entered < 0); \ - } - -#else /* PROFILE_RULES */ - -#define RULE_PROFILING_START(p) -#define RULE_PROFILING_END(a, b, c, p) - -#endif /* PROFILE_RULES */ - -#endif /* ! __UTIL_PROFILE_H__ */ diff --git a/src/util-proto-name.c b/src/util-proto-name.c deleted file mode 100644 index 41423c9477d6..000000000000 --- a/src/util-proto-name.c +++ /dev/null @@ -1,507 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - * - * File to provide the protocol names based on protocol numbers defined by the - * IANA - */ - -#include "suricata-common.h" -#include "util-hash-string.h" -#include "util-proto-name.h" -#include "util-debug.h" - -#ifdef UNITTESTS -#include "util-unittest.h" -#endif - -/** Lookup array to hold the information related to known protocol - * values - */ - -const char *known_proto[256] = { - "HOPOPT", /* 0x00: 0 - IPv6 Hop-by-Hop Option RFC 8200 */ - "ICMP", /* 0x01: 1 - Internet Control Message Protocol RFC 792 */ - "IGMP", /* 0x02: 2 - Internet Group Management Protocol RFC 1112 */ - "GGP", /* 0x03: 3 - Gateway-to-Gateway Protocol RFC 823 */ - "IP-in-IP", /* 0x04: 4 - IP in IP (encapsulation) RFC 2003 */ - "ST", /* 0x05: 5 - Internet Stream Protocol RFC 1190, RFC 1819 */ - "TCP", /* 0x06: 6 - Transmission Control Protocol RFC 793 */ - "CBT", /* 0x07: 7 - Core-based trees RFC 2189 */ - "EGP", /* 0x08: 8 - Exterior Gateway Protocol RFC 888 */ - "IGP", /* 0x09: 9 - Interior Gateway Protocol (any private interior gateway, for example Cisco's - IGRP) */ - "BBN-RCC-MON", /* 0x0A: 10 - BBN RCC Monitoring */ - "NVP-II", /* 0x0B: 11 - Network Voice Protocol RFC 741 */ - "PUP", /* 0x0C: 12 - Xerox PUP */ - "ARGUS", /* 0x0D: 13 - ARGUS */ - "EMCON", /* 0x0E: 14 - EMCON */ - "XNET", /* 0x0F: 15 - Cross Net Debugger IEN 158[2] */ - "CHAOS", /* 0x10: 16 - Chaos */ - "UDP", /* 0x11: 17 - User Datagram Protocol RFC 768 */ - "MUX", /* 0x12: 18 - Multiplexing IEN 90[3] */ - "DCN-MEAS", /* 0x13: 19 - DCN Measurement Subsystems */ - "HMP", /* 0x14: 20 - Host Monitoring Protocol RFC 869 */ - "PRM", /* 0x15: 21 - Packet Radio Measurement */ - "XNS-IDP", /* 0x16: 22 - XEROX NS IDP */ - "TRUNK-1", /* 0x17: 23 - Trunk-1 */ - "TRUNK-2", /* 0x18: 24 - Trunk-2 */ - "LEAF-1", /* 0x19: 25 - Leaf-1 */ - "LEAF-2", /* 0x1A: 26 - Leaf-2 */ - "RDP", /* 0x1B: 27 - Reliable Data Protocol RFC 908 */ - "IRTP", /* 0x1C: 28 - Internet Reliable Transaction Protocol RFC 938 */ - "ISO-TP4", /* 0x1D: 29 - ISO Transport Protocol Class 4 RFC 905 */ - "NETBLT", /* 0x1E: 30 - Bulk Data Transfer Protocol RFC 998 */ - "MFE-NSP", /* 0x1F: 31 - MFE Network Services Protocol */ - "MERIT-INP", /* 0x20: 32 - MERIT Internodal Protocol */ - "DCCP", /* 0x21: 33 - Datagram Congestion Control Protocol RFC 4340 */ - "3PC", /* 0x22: 34 - Third Party Connect Protocol */ - "IDPR", /* 0x23: 35 - Inter-Domain Policy Routing Protocol RFC 1479 */ - "XTP", /* 0x24: 36 - Xpress Transport Protocol */ - "DDP", /* 0x25: 37 - Datagram Delivery Protocol */ - "IDPR-CMTP", /* 0x26: 38 - IDPR Control Message Transport Protocol */ - "TP++", /* 0x27: 39 - TP++ Transport Protocol */ - "IL", /* 0x28: 40 - IL Transport Protocol */ - "IPv6", /* 0x29: 41 - IPv6 Encapsulation RFC 2473 */ - "SDRP", /* 0x2A: 42 - Source Demand Routing Protocol RFC 1940 */ - "IPv6-Route", /* 0x2B: 43 - Routing Header for IPv6 RFC 8200 */ - "IPv6-Frag", /* 0x2C: 44 - Fragment Header for IPv6 RFC 8200 */ - "IDRP", /* 0x2D: 45 - Inter-Domain Routing Protocol */ - "RSVP", /* 0x2E: 46 - Resource Reservation Protocol RFC 2205 */ - "GRE", /* 0x2F: 47 - Generic Routing Encapsulation RFC 2784, RFC 2890 */ - "DSR", /* 0x30: 48 - Dynamic Source Routing Protocol RFC 4728 */ - "BNA", /* 0x31: 49 - Burroughs Network Architecture */ - "ESP", /* 0x32: 50 - Encapsulating Security Payload RFC 4303 */ - "AH", /* 0x33: 51 - Authentication Header RFC 4302 */ - "I-NLSP", /* 0x34: 52 - Integrated Net Layer Security Protocol TUBA */ - "SwIPe", /* 0x35: 53 - SwIPe RFC 5237 */ - "NARP", /* 0x36: 54 - NBMA Address Resolution Protocol RFC 1735 */ - "MOBILE", /* 0x37: 55 - IP Mobility (Min Encap) RFC 2004 */ - "TLSP", /* 0x38: 56 - Transport Layer Security Protocol (using Kryptonet key management) */ - "SKIP", /* 0x39: 57 - Simple Key-Management for Internet Protocol RFC 2356 */ - "IPv6-ICMP", /* 0x3A: 58 - ICMP for IPv6 RFC 4443, RFC 4884 */ - "IPv6-NoNxt", /* 0x3B: 59 - No Next Header for IPv6 RFC 8200 */ - "IPv6-Opts", /* 0x3C: 60 - Destination Options for IPv6 RFC 8200 */ - "Any", /* 0x3D: 61 - host internal protocol */ - "CFTP", /* 0x3E: 62 - CFTP */ - "Any", /* 0x3F: 63 - local network */ - "SAT-EXPAK", /* 0x40: 64 - SATNET and Backroom EXPAK */ - "KRYPTOLAN", /* 0x41: 65 - Kryptolan */ - "RVD", /* 0x42: 66 - MIT Remote Virtual Disk Protocol */ - "IPPC", /* 0x43: 67 - Internet Pluribus Packet Core */ - "Any", /* 0x44: 68 - distributed file system */ - "SAT-MON", /* 0x45: 69 - SATNET Monitoring */ - "VISA", /* 0x46: 70 - VISA Protocol */ - "IPCU", /* 0x47: 71 - Internet Packet Core Utility */ - "CPNX", /* 0x48: 72 - Computer Protocol Network Executive */ - "CPHB", /* 0x49: 73 - Computer Protocol Heart Beat */ - "WSN", /* 0x4A: 74 - Wang Span Network */ - "PVP", /* 0x4B: 75 - Packet Video Protocol */ - "BR-SAT-MON", /* 0x4C: 76 - Backroom SATNET Monitoring */ - "SUN-ND", /* 0x4D: 77 - SUN ND PROTOCOL-Temporary */ - "WB-MON", /* 0x4E: 78 - WIDEBAND Monitoring */ - "WB-EXPAK", /* 0x4F: 79 - WIDEBAND EXPAK */ - "ISO-IP", /* 0x50: 80 - International Organization for Standardization Internet Protocol */ - "VMTP", /* 0x51: 81 - Versatile Message Transaction Protocol RFC 1045 */ - "SECURE-VMTP", /* 0x52: 82 - Secure Versatile Message Transaction Protocol RFC 1045 */ - "VINES", /* 0x53: 83 - VINES */ - "TTP", /* 0x54: 84 - TTP */ - "NSFNET-IGP", /* 0x55: 85 - NSFNET-IGP */ - "DGP", /* 0x56: 86 - Dissimilar Gateway Protocol */ - "TCF", /* 0x57: 87 - TCF */ - "EIGRP", /* 0x58: 88 - EIGRP Informational RFC 7868 */ - "OSPF", /* 0x59: 89 - Open Shortest Path First RFC 2328 */ - "Sprite-RPC", /* 0x5A: 90 - Sprite RPC Protocol */ - "LARP", /* 0x5B: 91 - Locus Address Resolution Protocol */ - "MTP", /* 0x5C: 92 - Multicast Transport Protocol */ - "AX.25", /* 0x5D: 93 - AX.25 */ - "OS", /* 0x5E: 94 - KA9Q NOS compatible IP over IP tunneling */ - "MICP", /* 0x5F: 95 - Mobile Internetworking Control Protocol */ - "SCC-SP", /* 0x60: 96 - Semaphore Communications Sec. Pro */ - "ETHERIP", /* 0x61: 97 - Ethernet-within-IP Encapsulation RFC 3378 */ - "ENCAP", /* 0x62: 98 - Encapsulation Header RFC 1241 */ - "Any", /* 0x63: 99 - private encryption scheme */ - "GMTP", /* 0x64: 100 - GMTP */ - "IFMP", /* 0x65: 101 - Ipsilon Flow Management Protocol */ - "PNNI", /* 0x66: 102 - PNNI over IP */ - "PIM", /* 0x67: 103 - Protocol Independent Multicast */ - "ARIS", /* 0x68: 104 - IBM's ARIS (Aggregate Route IP Switching) Protocol */ - "SCPS", /* 0x69: 105 - SCPS (Space Communications Protocol Standards) SCPS-TP[4] */ - "QNX", /* 0x6A: 106 - QNX */ - "A/N", /* 0x6B: 107 - Active Networks */ - "IPComp", /* 0x6C: 108 - IP Payload Compression Protocol RFC 3173 */ - "SNP", /* 0x6D: 109 - Sitara Networks Protocol */ - "Compaq-Peer", /* 0x6E: 110 - Compaq Peer Protocol */ - "IPX-in-IP", /* 0x6F: 111 - IPX in IP */ - "VRRP", /* 0x70: 112 - Virtual Router Redundancy Protocol, Common Address Redundancy Protocol - (not IANA assigned) VRRP:RFC 3768 */ - "PGM", /* 0x71: 113 - PGM Reliable Transport Protocol RFC 3208 */ - "Any", /* 0x72: 114 - 0-hop protocol */ - "L2TP", /* 0x73: 115 - Layer Two Tunneling Protocol Version 3 RFC 3931 */ - "DDX", /* 0x74: 116 - D-II Data Exchange (DDX) */ - "IATP", /* 0x75: 117 - Interactive Agent Transfer Protocol */ - "STP", /* 0x76: 118 - Schedule Transfer Protocol */ - "SRP", /* 0x77: 119 - SpectraLink Radio Protocol */ - "UTI", /* 0x78: 120 - Universal Transport Interface Protocol */ - "SMP", /* 0x79: 121 - Simple Message Protocol */ - "SM", /* 0x7A: 122 - Simple Multicast Protocol draft-perlman-simple-multicast-03 */ - "PTP", /* 0x7B: 123 - Performance Transparency Protocol */ - "IS-IS", /* 0x7C: 124 - over IPv4 Intermediate System to Intermediate System (IS-IS) Protocol - over IPv4 RFC 1142 and RFC 1195 */ - "FIRE", /* 0x7D: 125 - Flexible Intra-AS Routing Environment */ - "CRTP", /* 0x7E: 126 - Combat Radio Transport Protocol */ - "CRUDP", /* 0x7F: 127 - Combat Radio User Datagram */ - "SSCOPMCE", /* 0x80: 128 - Service-Specific Connection-Oriented Protocol in a Multilink and - Connectionless Environment ITU-T Q.2111 (1999) */ - "IPLT", /* 0x81: 129 - */ - "SPS", /* 0x82: 130 - Secure Packet Shield */ - "PIPE", /* 0x83: 131 - Private IP Encapsulation within IP Expired I-D - draft-petri-mobileip-pipe-00.txt */ - "SCTP", /* 0x84: 132 - Stream Control Transmission Protocol RFC 4960 */ - "FC", /* 0x85: 133 - Fibre Channel */ - "RSVP-E2E-IGNORE", /* 0x86: 134 - Reservation Protocol (RSVP) End-to-End Ignore RFC 3175 */ - "Mobility", /* 0x87: 135 - Header Mobility Extension Header for IPv6 RFC 6275 */ - "UDPLite", /* 0x88: 136 - Lightweight User Datagram Protocol RFC 3828 */ - "MPLS-in-IP", /* 0x89: 137 - Multiprotocol Label Switching Encapsulated in IP RFC 4023, - RFC 5332 */ - "manet", /* 0x8A: 138 - MANET Protocols RFC 5498 */ - "HIP", /* 0x8B: 139 - Host Identity Protocol RFC 5201 */ - "Shim6", /* 0x8C: 140 - Site Multihoming by IPv6 Intermediation RFC 5533 */ - "WESP", /* 0x8D: 141 - Wrapped Encapsulating Security Payload RFC 5840 */ - "ROHC", /* 0x8E: 142 - Robust Header Compression RFC 5856 */ - "Ethernet" /* 0x8F: 143 - IPv6 Segment Routing (TEMPORARY - registered 2020-01-31, expires - 2021-01-31) */ -}; - -/* - * Protocol name aliases - */ -const char *proto_aliases[256] = { - "ip", /* 0x00: 0 - IPv6 Hop-by-Hop Option RFC 8200 */ - "icmp", /* 0x01: 1 - Internet Control Message Protocol RFC 792 */ - "igmp", /* 0x02: 2 - Internet Group Management Protocol RFC 1112 */ - "ggp", /* 0x03: 3 - Gateway-to-Gateway Protocol RFC 823 */ - "ipencap", /* 0x04: 4 - IP in IP (encapsulation) RFC 2003 */ - "st", /* 0x05: 5 - Internet Stream Protocol RFC 1190, RFC 1819 */ - "tcp", /* 0x06: 6 - Transmission Control Protocol RFC 793 */ - NULL, /* 0x07: 7 - Core-based trees RFC 2189 */ - "egp", /* 0x08: 8 - Exterior Gateway Protocol RFC 888 */ - "igp", /* 0x09: 9 - Interior Gateway Protocol (any private interior gateway, for example Cisco's - IGRP) */ - NULL, /* 0x0A: 10 - BBN RCC Monitoring */ - NULL, /* 0x0B: 11 - Network Voice Protocol RFC 741 */ - "pup", /* 0x0C: 12 - Xerox PUP */ - NULL, /* 0x0D: 13 - ARGUS */ - NULL, /* 0x0E: 14 - EMCON */ - NULL, /* 0x0F: 15 - Cross Net Debugger IEN 158[2] */ - NULL, /* 0x10: 16 - Chaos */ - "udp", /* 0x11: 17 - User Datagram Protocol RFC 768 */ - NULL, /* 0x12: 18 - Multiplexing IEN 90[3] */ - NULL, /* 0x13: 19 - DCN Measurement Subsystems */ - "hmp", /* 0x14: 20 - Host Monitoring Protocol RFC 869 */ - NULL, /* 0x15: 21 - Packet Radio Measurement */ - "xns-idp", /* 0x16: 22 - XEROX NS IDP */ - NULL, /* 0x17: 23 - Trunk-1 */ - NULL, /* 0x18: 24 - Trunk-2 */ - NULL, /* 0x19: 25 - Leaf-1 */ - NULL, /* 0x1A: 26 - Leaf-2 */ - "rdp", /* 0x1B: 27 - Reliable Data Protocol RFC 908 */ - NULL, /* 0x1C: 28 - Internet Reliable Transaction Protocol RFC 938 */ - "iso-tp4", /* 0x1D: 29 - ISO Transport Protocol Class 4 RFC 905 */ - NULL, /* 0x1E: 30 - Bulk Data Transfer Protocol RFC 998 */ - NULL, /* 0x1F: 31 - MFE Network Services Protocol */ - NULL, /* 0x20: 32 - MERIT Internodal Protocol */ - "dccp", /* 0x21: 33 - Datagram Congestion Control Protocol RFC 4340 */ - NULL, /* 0x22: 34 - Third Party Connect Protocol */ - NULL, /* 0x23: 35 - Inter-Domain Policy Routing Protocol RFC 1479 */ - "xtp", /* 0x24: 36 - Xpress Transport Protocol */ - "ddp", /* 0x25: 37 - Datagram Delivery Protocol */ - "idpr-cmtp", /* 0x26: 38 - IDPR Control Message Transport Protocol */ - NULL, /* 0x27: 39 - TP++ Transport Protocol */ - NULL, /* 0x28: 40 - IL Transport Protocol */ - "ipV6", /* 0x29: 41 - IPv6 Encapsulation RFC 2473 */ - NULL, /* 0x2A: 42 - Source Demand Routing Protocol RFC 1940 */ - "ipv6-route", /* 0x2B: 43 - Routing Header for IPv6 RFC 8200 */ - "ipv6-frag", /* 0x2C: 44 - Fragment Header for IPv6 RFC 8200 */ - "idrp", /* 0x2D: 45 - Inter-Domain Routing Protocol */ - "rsvp", /* 0x2E: 46 - Resource Reservation Protocol RFC 2205 */ - "gre", /* 0x2F: 47 - Generic Routing Encapsulation RFC 2784, RFC 2890 */ - NULL, /* 0x30: 48 - Dynamic Source Routing Protocol RFC 4728 */ - NULL, /* 0x31: 49 - Burroughs Network Architecture */ - "esp", /* 0x32: 50 - Encapsulating Security Payload RFC 4303 */ - "ah", /* 0x33: 51 - Authentication Header RFC 4302 */ - NULL, /* 0x34: 52 - Integrated Net Layer Security Protocol TUBA */ - NULL, /* 0x35: 53 - SwIPe RFC 5237 */ - NULL, /* 0x36: 54 - NBMA Address Resolution Protocol RFC 1735 */ - NULL, /* 0x37: 55 - IP Mobility (Min Encap) RFC 2004 */ - NULL, /* 0x38: 56 - Transport Layer Security Protocol (using Kryptonet key management) */ - "skip", /* 0x39: 57 - Simple Key-Management for Internet Protocol RFC 2356 */ - "ipv6-icmp", /* 0x3A: 58 - ICMP for IPv6 RFC 4443, RFC 4884 */ - "ipv6-nonxt", /* 0x3B: 59 - No Next Header for IPv6 RFC 8200 */ - "ipv6-opts", /* 0x3C: 60 - Destination Options for IPv6 RFC 8200 */ - NULL, /* 0x3D: 61 - host internal protocol */ - NULL, /* 0x3E: 62 - CFTP */ - NULL, /* 0x3F: 63 - local network */ - NULL, /* 0x40: 64 - SATNET and Backroom EXPAK */ - NULL, /* 0x41: 65 - Kryptolan */ - NULL, /* 0x42: 66 - MIT Remote Virtual Disk Protocol */ - NULL, /* 0x43: 67 - Internet Pluribus Packet Core */ - NULL, /* 0x44: 68 - distributed file system */ - NULL, /* 0x45: 69 - SATNET Monitoring */ - NULL, /* 0x46: 70 - VISA Protocol */ - NULL, /* 0x47: 71 - Internet Packet Core Utility */ - NULL, /* 0x48: 72 - Computer Protocol Network Executive */ - "cphb", /* 0x49: 73 - Computer Protocol Heart Beat */ - NULL, /* 0x4A: 74 - Wang Span Network */ - NULL, /* 0x4B: 75 - Packet Video Protocol */ - NULL, /* 0x4C: 76 - Backroom SATNET Monitoring */ - NULL, /* 0x4D: 77 - SUN ND PROTOCOL-Temporary */ - NULL, /* 0x4E: 78 - WIDEBAND Monitoring */ - NULL, /* 0x4F: 79 - WIDEBAND EXPAK */ - NULL, /* 0x50: 80 - International Organization for Standardization Internet Protocol */ - "vmtp", /* 0x51: 81 - Versatile Message Transaction Protocol RFC 1045 */ - NULL, /* 0x52: 82 - Secure Versatile Message Transaction Protocol RFC 1045 */ - NULL, /* 0x53: 83 - VINES */ - NULL, /* 0x54: 84 - TTP */ - NULL, /* 0x55: 85 - NSFNET-IGP */ - NULL, /* 0x56: 86 - Dissimilar Gateway Protocol */ - NULL, /* 0x57: 87 - TCF */ - "eigrp", /* 0x58: 88 - EIGRP Informational RFC 7868 */ - "ospf", /* 0x59: 89 - Open Shortest Path First RFC 2328 */ - NULL, /* 0x5A: 90 - Sprite RPC Protocol */ - NULL, /* 0x5B: 91 - Locus Address Resolution Protocol */ - NULL, /* 0x5C: 92 - Multicast Transport Protocol */ - "ax.25", /* 0x5D: 93 - AX.25 */ - "ipip", /* 0x5E: 94 - KA9Q NOS compatible IP over IP tunneling */ - NULL, /* 0x5F: 95 - Mobile Internetworking Control Protocol */ - NULL, /* 0x60: 96 - Semaphore Communications Sec. Pro */ - "etherip", /* 0x61: 97 - Ethernet-within-IP Encapsulation RFC 3378 */ - "encap", /* 0x62: 98 - Encapsulation Header RFC 1241 */ - NULL, /* 0x63: 99 - private encryption scheme */ - "GMTP", /* 0x64: 100 - GMTP */ - NULL, /* 0x65: 101 - Ipsilon Flow Management Protocol */ - NULL, /* 0x66: 102 - PNNI over IP */ - "pim", /* 0x67: 103 - Protocol Independent Multicast */ - NULL, /* 0x68: 104 - IBM's ARIS (Aggregate Route IP Switching) Protocol */ - NULL, /* 0x69: 105 - SCPS (Space Communications Protocol Standards) SCPS-TP[4] */ - NULL, /* 0x6A: 106 - QNX */ - NULL, /* 0x6B: 107 - Active Networks */ - "ipcomp", /* 0x6C: 108 - IP Payload Compression Protocol RFC 3173 */ - NULL, /* 0x6D: 109 - Sitara Networks Protocol */ - NULL, /* 0x6E: 110 - Compaq Peer Protocol */ - NULL, /* 0x6F: 111 - IPX in IP */ - "vrrp", /* 0x70: 112 - Virtual Router Redundancy Protocol, Common Address Redundancy Protocol - (not IANA assigned) VRRP:RFC 3768 */ - NULL, /* 0x71: 113 - PGM Reliable Transport Protocol RFC 3208 */ - NULL, /* 0x72: 114 - 0-hop protocol */ - "l2tp", /* 0x73: 115 - Layer Two Tunneling Protocol Version 3 RFC 3931 */ - NULL, /* 0x74: 116 - D-II Data Exchange (DDX) */ - NULL, /* 0x75: 117 - Interactive Agent Transfer Protocol */ - NULL, /* 0x76: 118 - Schedule Transfer Protocol */ - NULL, /* 0x77: 119 - SpectraLink Radio Protocol */ - NULL, /* 0x78: 120 - Universal Transport Interface Protocol */ - NULL, /* 0x79: 121 - Simple Message Protocol */ - NULL, /* 0x7A: 122 - Simple Multicast Protocol draft-perlman-simple-multicast-03 */ - NULL, /* 0x7B: 123 - Performance Transparency Protocol */ - "isis", /* 0x7C: 124 - over IPv4 Intermediate System to Intermediate System (IS-IS) Protocol - over IPv4 RFC 1142 and RFC 1195 */ - NULL, /* 0x7D: 125 - Flexible Intra-AS Routing Environment */ - NULL, /* 0x7E: 126 - Combat Radio Transport Protocol */ - NULL, /* 0x7F: 127 - Combat Radio User Datagram */ - NULL, /* 0x80: 128 - Service-Specific Connection-Oriented Protocol in a Multilink and - Connectionless Environment ITU-T Q.2111 (1999) */ - NULL, /* 0x81: 129 - */ - NULL, /* 0x82: 130 - Secure Packet Shield */ - NULL, /* 0x83: 131 - Private IP Encapsulation within IP Expired I-D - draft-petri-mobileip-pipe-00.txt */ - "sctp", /* 0x84: 132 - Stream Control Transmission Protocol RFC 4960 */ - "fc", /* 0x85: 133 - Fibre Channel */ - NULL, /* 0x86: 134 - Reservation Protocol (RSVP) End-to-End Ignore RFC 3175 */ - "mobility-header", /* 0x87: 135 - Header Mobility Extension Header for IPv6 RFC 6275 */ - "udplite", /* 0x88: 136 - Lightweight User Datagram Protocol RFC 3828 */ - "mpls-in-ip", /* 0x89: 137 - Multiprotocol Label Switching Encapsulated in IP RFC 4023, - RFC 5332 */ - NULL, /* 0x8A: 138 - MANET Protocols RFC 5498 */ - "hip", /* 0x8B: 139 - Host Identity Protocol RFC 5201 */ - "shim6", /* 0x8C: 140 - Site Multihoming by IPv6 Intermediation RFC 5533 */ - "wesp", /* 0x8D: 141 - Wrapped Encapsulating Security Payload RFC 5840 */ - "rohc", /* 0x8E: 142 - Robust Header Compression RFC 5856 */ - /* no aliases for 142-255 */ -}; - -typedef struct ProtoNameHashEntry_ { - const char *name; - uint8_t number; -} ProtoNameHashEntry; - -static HashTable *proto_ht = NULL; - -static uint32_t ProtoNameHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - /* - * datalen covers the entire struct -- only the proto name is hashed - * as the proto number is not used for lookups - */ - ProtoNameHashEntry *p = (ProtoNameHashEntry *)data; - return StringHashDjb2((uint8_t *)p->name, strlen(p->name)) % ht->array_size; -} - -static char ProtoNameHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) -{ - ProtoNameHashEntry *p1 = (ProtoNameHashEntry *)data1; - ProtoNameHashEntry *p2 = (ProtoNameHashEntry *)data2; - - if (p1 == NULL || p2 == NULL) - return 0; - - if (p1->name == NULL || p2->name == NULL) - return 0; - - int len1 = strlen(p1->name); - int len2 = strlen(p2->name); - - return len1 == len2 && memcmp(p1->name, p2->name, len1) == 0; -} - -static void ProtoNameAddEntry(const char *proto_name, const uint8_t proto_number) -{ - ProtoNameHashEntry *proto_ent = SCCalloc(1, sizeof(ProtoNameHashEntry)); - if (!proto_ent) { - FatalError("Unable to allocate protocol hash entry"); - } - - proto_ent->name = SCStrdup(proto_name); - if (!proto_ent->name) - FatalError("Unable to allocate memory for protocol name entries"); - - proto_ent->number = proto_number; - - SCLogDebug("new protocol entry: name: \"%s\"; protocol number: %d", proto_ent->name, - proto_ent->number); - if (0 != HashTableAdd(proto_ht, proto_ent, 0)) { - FatalError("Unable to add entry to proto hash table for " - "name: \"%s\"; number: %d", - proto_ent->name, proto_ent->number); - } - return; -} - -static void ProtoNameHashFreeFunc(void *data) -{ - ProtoNameHashEntry *proto_ent = (ProtoNameHashEntry *)data; - - if (proto_ent) { - if (proto_ent->name) - SCFree((void *)proto_ent->name); - SCFree(proto_ent); - } -} - -void SCProtoNameInit(void) -{ - proto_ht = - HashTableInit(256, ProtoNameHashFunc, ProtoNameHashCompareFunc, ProtoNameHashFreeFunc); - if (proto_ht == NULL) { - FatalError("Unable to initialize protocol name/number table"); - } - - for (uint16_t i = 0; i < ARRAY_SIZE(known_proto); i++) { - if (known_proto[i]) { - ProtoNameAddEntry(known_proto[i], (uint8_t)i); - } - } - - for (uint16_t i = 0; i < ARRAY_SIZE(proto_aliases); i++) { - if (proto_aliases[i]) { - ProtoNameAddEntry(proto_aliases[i], (uint8_t)i); - } - } -} - -void SCProtoNameRelease(void) -{ - if (proto_ht != NULL) { - HashTableFree(proto_ht); - proto_ht = NULL; - } -} - -/** - * \brief Function to check if the received protocol number is valid and do - * we have corresponding name entry for this number or not. - * - * \param proto Protocol number to be validated - * \retval ret On success returns true otherwise false - */ -bool SCProtoNameValid(uint16_t proto) -{ - return (proto <= 255 && known_proto[proto] != NULL); -} - -/** - * \brief Function to return the protocol number for a named protocol. Note - * that protocol name aliases are honored. - * - * \param protoname Protocol name (or alias for a protocol name). - * \param proto_number Where to return protocol number - * \retval ret On success returns the protocol number; else -1 - */ -bool SCGetProtoByName(const char *protoname, uint8_t *proto_number) -{ - if (!protoname || !proto_number) { - return false; - } - - ProtoNameHashEntry proto; - proto.name = protoname; - - ProtoNameHashEntry *proto_ent = HashTableLookup(proto_ht, &proto, sizeof(proto)); - if (proto_ent) { - *proto_number = proto_ent->number; - return true; - } - return false; -} - -#ifdef UNITTESTS -static int ProtoNameTest01(void) -{ - uint8_t proto; - FAIL_IF(!SCGetProtoByName("tcp", &proto)); - FAIL_IF(SCGetProtoByName("TcP", &proto)); - FAIL_IF(!SCGetProtoByName("TCP", &proto)); - FAIL_IF(SCGetProtoByName("Invalid", &proto)); - FAIL_IF(!SCGetProtoByName("Ethernet", &proto)); - - /* 'ip' is an alias for 'HOPOPT' */ - FAIL_IF(!SCGetProtoByName("ip", &proto)); - FAIL_IF(!SCGetProtoByName("HOPOPT", &proto)); - - FAIL_IF(SCGetProtoByName("IP", &proto)); - - PASS; -} - -void SCProtoNameRegisterTests(void) -{ - UtRegisterTest("ProtoNameTest01", ProtoNameTest01); -} -#endif diff --git a/src/util-proto-name.h b/src/util-proto-name.h deleted file mode 100644 index bc5037395a0d..000000000000 --- a/src/util-proto-name.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - */ - -#ifndef __UTIL_PROTO_NAME_H__ -#define __UTIL_PROTO_NAME_H__ - -/** Lookup array to hold the information related to known protocol - * values - */ -extern const char *known_proto[256]; - -bool SCProtoNameValid(uint16_t); -bool SCGetProtoByName(const char *protoname, uint8_t *proto_number); -void SCProtoNameInit(void); -void SCProtoNameRelease(void); - -#ifdef UNITTESTS -void SCProtoNameRegisterTests(void); -#endif - -#endif /* __UTIL_PROTO_NAME_H__ */ - diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c deleted file mode 100644 index 861d1256f409..000000000000 --- a/src/util-radix-tree.c +++ /dev/null @@ -1,3852 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Implementation of radix trees - */ - -#include "suricata-common.h" -#include "util-radix-tree.h" -#include "util-debug.h" -#include "util-error.h" -#include "util-ip.h" -#include "util-unittest.h" -#include "util-memcmp.h" -#include "util-byte.h" -#include "util-cidr.h" -#include "util-print.h" -#include "util-validate.h" - -/** - * \brief Allocates and returns a new instance of SCRadixUserData. - * - * \param netmask The netmask entry (cidr) that has to be made in the new - * SCRadixUserData instance - * \param user The user data that has to be set for the above - * netmask in the newly created SCRadixUserData instance. - * - * \retval user_data Pointer to a new instance of SCRadixUserData. - */ -static SCRadixUserData *SCRadixAllocSCRadixUserData(uint8_t netmask, void *user) -{ - SCRadixUserData *user_data = SCCalloc(1, sizeof(SCRadixUserData)); - if (unlikely(user_data == NULL)) { - SCLogError("Error allocating memory"); - return NULL; - } - - user_data->netmask = netmask; - user_data->user = user; - - return user_data; -} - -/** - * \brief Deallocates an instance of SCRadixUserData. - * - * \param user_data Pointer to the instance of SCRadixUserData that has to be - * freed. - */ -static void SCRadixDeAllocSCRadixUserData(SCRadixUserData *user_data) -{ - SCFree(user_data); - - return; -} - -/** - * \brief Appends a user_data instance(SCRadixUserData) to a - * user_data(SCRadixUserData) list. We add the new entry in descending - * order with respect to the netmask contained in the SCRadixUserData. - * - * \param new Pointer to the SCRadixUserData to be added to the list. - * \param list Pointer to the SCRadixUserData list head, to which "new" has to - * be appended. - */ -static void SCRadixAppendToSCRadixUserDataList(SCRadixUserData *new, - SCRadixUserData **list) -{ - SCRadixUserData *temp = NULL; - SCRadixUserData *prev = NULL; - - if (new == NULL || list == NULL) { - FatalError("new or list supplied as NULL"); - } - - /* add to the list in descending order. The reason we do this is for - * optimizing key retrieval for a ip key under a netblock */ - prev = temp = *list; - while (temp != NULL) { - if (new->netmask > temp->netmask) - break; - prev = temp; - temp = temp->next; - } - - if (temp == *list) { - new->next = *list; - *list = new; - } else { - new->next = prev->next; - prev->next = new; - } - - return; -} - -/** - * \brief Creates a new Prefix for a key. Used internally by the API. - * - * \param key_stream Data that has to be wrapped in a SCRadixPrefix instance to - * be processed for insertion/lookup/removal of a node by the - * radix tree - * \param key_bitlen The bitlen of the above stream. For example if the - * stream holds the ipv4 address(4 bytes), bitlen would be 32 - * \param user Pointer to the user data that has to be associated with - * this key - * - * \retval prefix The newly created prefix instance on success; NULL on failure - */ -static SCRadixPrefix *SCRadixCreatePrefix(uint8_t *key_stream, - uint16_t key_bitlen, void *user, - uint8_t netmask) -{ - SCRadixPrefix *prefix = NULL; - - if (key_bitlen == 0 || (key_bitlen % 8 != 0)) { - SCLogError("Invalid argument bitlen - %d", key_bitlen); - return NULL; - } - - if (key_stream == NULL) { - SCLogError("Argument \"stream\" NULL"); - return NULL; - } - - if ((prefix = SCCalloc(1, sizeof(SCRadixPrefix))) == NULL) - goto error; - - if ((prefix->stream = SCCalloc(1, key_bitlen / 8)) == NULL) - goto error; - - memcpy(prefix->stream, key_stream, key_bitlen / 8); - prefix->bitlen = key_bitlen; - - prefix->user_data = SCRadixAllocSCRadixUserData(netmask, user); - if (prefix->user_data == NULL) { - goto error; - } - - return prefix; - -error: - if (prefix != NULL) { - if (prefix->stream != NULL) { - SCFree(prefix->stream); - } - SCFree(prefix); - } - - return NULL; -} - -/** - * \brief Adds a netmask and its user_data for a particular prefix stream. - * - * \param prefix The prefix stream to which the netmask and its corresponding - * user data has to be added. - * \param netmask The netmask value (cidr) that has to be added to the prefix. - * \param user The pointer to the user data corresponding to the above - * netmask. - */ -static void SCRadixAddNetmaskUserDataToPrefix(SCRadixPrefix *prefix, - uint8_t netmask, - void *user) -{ - if (prefix == NULL || user == NULL) { - FatalError("prefix or user NULL"); - } - - SCRadixAppendToSCRadixUserDataList(SCRadixAllocSCRadixUserData(netmask, user), - &prefix->user_data); - - return; -} - -/** - * \brief Removes a particular user_data corresponding to a particular netmask - * entry, from a prefix. - * - * \param prefix Pointer to the prefix from which the user_data/netmask entry - * has to be removed. - * \param netmask The netmask value (cidr) whose user_data has to be deleted. - */ -static void SCRadixRemoveNetmaskUserDataFromPrefix(SCRadixPrefix *prefix, - uint8_t netmask) -{ - SCRadixUserData *temp = NULL, *prev = NULL; - - if (prefix == NULL) { - FatalError("prefix NULL"); - } - - prev = temp = prefix->user_data; - while (temp != NULL) { - if (temp->netmask == netmask) { - if (temp == prefix->user_data) - prefix->user_data = temp->next; - else - prev->next = temp->next; - - SCRadixDeAllocSCRadixUserData(temp); - break; - } - prev = temp; - temp = temp->next; - } - - return; -} - -/** - * \brief Indicates if prefix contains an entry for an ip with a specific netmask. - * - * \param prefix Pointer to the ip prefix that is being checked. - * \param netmask The netmask value (cidr) that has to be checked for - * presence in the prefix. - * - * \retval 1 On match. - * \retval 0 On no match. - */ -static int SCRadixPrefixContainNetmask(SCRadixPrefix *prefix, uint8_t netmask) -{ - SCRadixUserData *user_data = NULL; - - if (prefix == NULL) { - SCLogError("prefix is NULL"); - goto no_match; - } - - user_data = prefix->user_data; - while (user_data != NULL) { - if (user_data->netmask == netmask) - return 1; - user_data = user_data->next; - } - - no_match: - return 0; -} - -/** - * \brief Returns the total netmask count for this prefix. - * - * \param prefix Pointer to the prefix - * - * \retval count The total netmask count for this prefix. - */ -static int SCRadixPrefixNetmaskCount(SCRadixPrefix *prefix) -{ - SCRadixUserData *user_data = NULL; - uint32_t count = 0; - - if (prefix == NULL) { - SCLogError("prefix is NULL"); - return 0; - } - - user_data = prefix->user_data; - while (user_data != NULL) { - count++; - user_data = user_data->next; - } - - return count; -} - -/** - * \brief Indicates if prefix contains an entry for an ip with a specific netmask - * and if it does, it sets the user data field - * SCRadixPrefix->user_data_result to the netmask user_data entry. - * - * \param prefix Pointer to the ip prefix that is being checked. - * \param netmask The netmask value for which we will have to return the user_data - * \param exact_match flag which indicates if we should check if the prefix - * holds proper netblock(< 32 for ipv4 and < 128 for ipv6) or not. - * - * \retval 1 On match. - * \retval 0 On no match. - */ -static int SCRadixPrefixContainNetmaskAndSetUserData( - SCRadixPrefix *prefix, uint16_t netmask, bool exact_match, void **user_data_result) -{ - SCRadixUserData *user_data = NULL; - - if (prefix == NULL) { - SCLogError("prefix is NULL"); - goto no_match; - } - - user_data = prefix->user_data; - /* Check if we have a match for an exact ip. An exact ip as in not a proper - * netblock, i.e. an ip with a netmask of 32(ipv4) or 128(ipv6) */ - if (exact_match) { - if (user_data->netmask == netmask) { - if (user_data_result) - *user_data_result = user_data->user; - return 1; - } else { - goto no_match; - } - } - - /* Check for the user_data entry for this netmask_value */ - while (user_data != NULL) { - if (user_data->netmask == netmask) { - if (user_data_result) - *user_data_result = user_data->user; - return 1; - } - user_data = user_data->next; - } - -no_match: - if (user_data_result != NULL) - *user_data_result = NULL; - return 0; -} - -/** - * \brief Frees a SCRadixPrefix instance - * - * \param prefix Pointer to a prefix instance - * \param tree Pointer to the Radix tree to which this prefix belongs - */ -static void SCRadixReleasePrefix(SCRadixPrefix *prefix, SCRadixTree *tree) -{ - SCRadixUserData *user_data_temp1 = NULL; - SCRadixUserData *user_data_temp2 = NULL; - - if (prefix != NULL) { - if (prefix->stream != NULL) - SCFree(prefix->stream); - - user_data_temp1 = prefix->user_data; - if (tree->Free != NULL) { - while (user_data_temp1 != NULL) { - user_data_temp2 = user_data_temp1; - user_data_temp1 = user_data_temp1->next; - tree->Free(user_data_temp2->user); - SCRadixDeAllocSCRadixUserData(user_data_temp2); - } - } else if (user_data_temp1 != NULL) { - SCFree(user_data_temp1); - } - - SCFree(prefix); - } - - return; -} - -/** - * \brief Creates a new node for the Radix tree - * - * \retval node The newly created node for the radix tree - */ -static inline SCRadixNode *SCRadixCreateNode(void) -{ - SCRadixNode *node = NULL; - - if ((node = SCCalloc(1, sizeof(SCRadixNode))) == NULL) { - SCLogError("Fatal error encountered in SCRadixCreateNode. Mem not allocated..."); - return NULL; - } - - return node; -} - -/** - * \brief Frees a Radix tree node - * - * \param node Pointer to a Radix tree node - * \param tree Pointer to the Radix tree to which this node belongs - */ -static void SCRadixReleaseNode(SCRadixNode *node, SCRadixTree *tree) -{ - if (node != NULL) { - SCRadixReleasePrefix(node->prefix, tree); - - if (node->netmasks != NULL) - SCFree(node->netmasks); - - SCFree(node); - } - - return; -} - -/** - * \brief Creates a new Radix tree - * - * \param Free Function pointer supplied by the user to be used by the Radix - * cleanup API to free the user supplied data - * - * \retval tree The newly created radix tree on success - * - * \initonly (all radix trees should be created at init) - */ -SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*), void (*PrintData)(void*)) -{ - SCRadixTree *tree = NULL; - - if ((tree = SCCalloc(1, sizeof(SCRadixTree))) == NULL) { - FatalError("Fatal error encountered in SCRadixCreateRadixTree. Exiting..."); - } - - tree->Free = Free; - tree->PrintData = PrintData; - - return tree; -} - -/** - * \brief Internal helper function used by SCRadixReleaseRadixTree to free a - * subtree - * - * \param node Pointer to the root of the subtree that has to be freed - * \param tree Pointer to the Radix tree to which this subtree belongs - */ -static void SCRadixReleaseRadixSubtree(SCRadixNode *node, SCRadixTree *tree) -{ - if (node != NULL) { - SCRadixReleaseRadixSubtree(node->left, tree); - SCRadixReleaseRadixSubtree(node->right, tree); - SCRadixReleaseNode(node, tree); - } - - return; -} - -/** - * \brief Frees a Radix tree and all its nodes - * - * \param tree Pointer to the Radix tree that has to be freed - */ -void SCRadixReleaseRadixTree(SCRadixTree *tree) -{ - if (tree == NULL) - return; - - SCRadixReleaseRadixSubtree(tree->head, tree); - tree->head = NULL; - SCFree(tree); - return; -} - -/** - * \brief Adds a key to the Radix tree. Used internally by the API. - * - * \param key_stream Data that has to added to the Radix tree - * \param key_bitlen The bitlen of the above stream. For example if the - * stream is the string "abcd", the bitlen would be 32. If - * the stream is an IPV6 address bitlen would be 128 - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with - * this key - * \param netmask The netmask (cidr) if we are adding an IP netblock; 255 - * if we are not adding an IP netblock - * \param exclusive True if the node should be added iff it doesn't exist. - * - * \retval node Pointer to the newly created node - */ -static SCRadixNode *SCRadixAddKeyInternal(uint8_t *key_stream, uint8_t key_bitlen, - SCRadixTree *tree, void *user, uint8_t netmask, bool exclusive) -{ - SCRadixNode *node = NULL; - SCRadixNode *new_node = NULL; - SCRadixNode *parent = NULL; - SCRadixNode *inter_node = NULL; - SCRadixNode *bottom_node = NULL; - void *ptmp; - - uint8_t *stream = NULL; - uint8_t bitlen = 0; - - uint16_t check_bit = 0; - uint16_t differ_bit = 0; - - uint16_t i = 0; - uint16_t j = 0; - - if (tree == NULL) { - SCLogError("Argument \"tree\" NULL"); - sc_errno = SC_EINVAL; - return NULL; - } - - /* chop the ip address against a netmask */ - MaskIPNetblock(key_stream, netmask, key_bitlen); - - /* the very first element in the radix tree */ - if (tree->head == NULL) { - SCRadixPrefix *prefix = NULL; - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, - netmask)) == NULL) { - SCLogError("Error creating prefix"); - sc_errno = SC_EINVAL; - return NULL; - } - node = SCRadixCreateNode(); - if (node == NULL) { - SCRadixReleasePrefix(prefix, tree); - sc_errno = SC_ENOMEM; - return NULL; - } - node->prefix = prefix; - node->bit = prefix->bitlen; - tree->head = node; - if (netmask == 255 || (netmask == 32 && key_bitlen == 32) || - (netmask == 128 && key_bitlen == 128)) { - sc_errno = SC_EINVAL; - return node; - } - - /* if we have reached here, we are actually having a proper netblock in - * our hand(i.e. < 32 for ipv4 and < 128 for ipv6). Add the netmask for - * this node. The reason we add netmasks other than 32 and 128, is - * because we need those netmasks in case of searches for ips contained - * in netblocks. If the netmask is 32 or 128, either ways we will be - * having an exact match for that ip value. If it is not, we start - * chopping the incoming search ip key using the netmask values added - * into the tree and then verify for a match */ - node->netmask_cnt++; - if ( (ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * - sizeof(uint8_t)))) == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated"); - sc_errno = SC_ENOMEM; - return NULL; - } - node->netmasks = ptmp; - node->netmasks[0] = netmask; - return node; - } - - node = tree->head; - stream = key_stream; - bitlen = key_bitlen; - - /* we walk down the tree only when we satisfy 2 conditions. The first one - * being the incoming prefix is shorter than the differ bit of the current - * node. In case we fail in this aspect, we walk down to the tree, till we - * arrive at a node that ends in a prefix */ - while (node->bit < bitlen || node->prefix == NULL) { - /* if the bitlen isn't long enough to handle the bit test, we just walk - * down along one of the paths, since either paths should end up with a - * node that has a common prefix whose differ bit is greater than the - * bitlen of the incoming prefix */ - if (bitlen <= node->bit) { - if (node->right == NULL) - break; - node = node->right; - } else { - if (SC_RADIX_BITTEST(stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - if (node->right == NULL) - break; - node = node->right; - } else { - if (node->left == NULL) - break; - node = node->left; - } - } - } - - /* we need to keep a reference to the bottom-most node, that actually holds - * the prefix */ - bottom_node = node; - - DEBUG_VALIDATE_BUG_ON(bottom_node == NULL); - DEBUG_VALIDATE_BUG_ON(bottom_node->prefix == NULL); - - /* get the first bit position where the ips differ */ - check_bit = (node->bit < bitlen)? node->bit: bitlen; - for (i = 0; (i * 8) < check_bit; i++) { - int temp; - if ((temp = (stream[i] ^ bottom_node->prefix->stream[i])) == 0) { - differ_bit = (i + 1) * 8; - continue; - } - - /* find out the position where the first bit differs. This method is - * faster, but at the cost of being larger. But with larger caches - * these days we don't have to worry about cache misses */ - temp = temp * 2; - if (temp >= 256) - j = 0; - else if (temp >= 128) - j = 1; - else if (temp >= 64) - j = 2; - else if (temp >= 32) - j = 3; - else if (temp >= 16) - j = 4; - else if (temp >= 8) - j = 5; - else if (temp >= 4) - j = 6; - else if (temp >= 2) - j = 7; - - differ_bit = i * 8 + j; - break; - } - if (check_bit < differ_bit) - differ_bit = check_bit; - - /* walk up the tree till we find the position, to fit our new node in */ - parent = node->parent; - while (parent && differ_bit <= parent->bit) { - node = parent; - parent = node->parent; - } - - /* We already have the node in the tree with the same differing bit pstn */ - if (differ_bit == bitlen && node->bit == bitlen) { - if (node->prefix != NULL) { - /* Check if we already have this netmask entry covered by this prefix */ - if (SCRadixPrefixContainNetmask(node->prefix, netmask)) { - /* Basically we already have this stream prefix, as well as the - * netblock entry for this. A perfect duplicate. */ - if (exclusive) { - SCLogDebug("not inserting since it already exists"); - sc_errno = SC_EEXIST; - return NULL; - } - SCLogDebug("Duplicate entry for this ip address/netblock"); - } else { - /* Basically we already have this stream prefix, but we don't - * have an entry for this particular netmask value for this - * prefix. For example, we have an entry for 192.168.0.0 and - * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ - SCRadixAddNetmaskUserDataToPrefix(node->prefix, netmask, user); - - /* if we are adding a netmask of 32(for ipv4) or 128(for ipv6) - * it indicates we are adding an exact host ip into the radix - * tree, in which case we don't need to add the netmask value - * into the tree */ - if (netmask == 255 || (netmask == 32 && bitlen == 32) || (netmask == 128 && bitlen == 128)) - return node; - - /* looks like we have a netmask which is != 32 or 128, in which - * case we walk up the tree to insert this netmask value in the - * correct node */ - parent = node->parent; - while (parent != NULL && netmask < (parent->bit + 1)) { - node = parent; - parent = parent->parent; - } - - node->netmask_cnt++; - new_node = node; - - if ( (ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * - sizeof(uint8_t)))) == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated..."); - sc_errno = SC_ENOMEM; - return NULL; - } - node->netmasks = ptmp; - - if (node->netmask_cnt == 1) { - node->netmasks[0] = netmask; - return new_node; - } - - node->netmasks[node->netmask_cnt - 1] = netmask; - - for (i = node->netmask_cnt - 1; i > 0; i--) { - if (netmask < node->netmasks[i - 1]) { - node->netmasks[i] = netmask; - break; - } - - node->netmasks[i] = node->netmasks[i - 1]; - node->netmasks[i - 1] = netmask; - } - } - } else { - node->prefix = SCRadixCreatePrefix(key_stream, key_bitlen, - user, 255); - } - return node; - } - - /* create the leaf node for the new key */ - SCRadixPrefix *prefix = NULL; - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, - netmask)) == NULL) { - SCLogError("Error creating prefix"); - sc_errno = SC_EINVAL; - return NULL; - } - new_node = SCRadixCreateNode(); - new_node->prefix = prefix; - new_node->bit = prefix->bitlen; - - /* indicates that we have got a key that has length that is already covered - * by a prefix of some other key in the tree. We create a new intermediate - * node with a single child and stick it in. We need the if only in the - * case of variable length keys */ - if (differ_bit == bitlen) { - if (SC_RADIX_BITTEST(bottom_node->prefix->stream[differ_bit >> 3], - (0x80 >> (differ_bit % 8))) ) { - new_node->right = node; - } else { - new_node->left = node; - } - new_node->parent = node->parent; - - if (node->parent == NULL) - tree->head = new_node; - else if (node->parent->right == node) - node->parent->right = new_node; - else - node->parent->left = new_node; - - node->parent = new_node; - /* stick our new_node into the tree. Create a node that holds the - * differing bit position and break the branch. Also handle the - * transfer of netmasks between node and inter_node(explained in more - * detail below) */ - } else { - inter_node = SCRadixCreateNode(); - inter_node->prefix = NULL; - inter_node->bit = differ_bit; - inter_node->parent = node->parent; - - if (node->netmasks != NULL) { - for (i = 0; i < node->netmask_cnt; i++) { - if (node->netmasks[i] < differ_bit + 1) - break; - } - - if (i < node->netmask_cnt) { - if ( (inter_node->netmasks = SCMalloc((node->netmask_cnt - i) * - sizeof(uint8_t))) == NULL) { - SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated..."); - SCRadixReleaseNode(inter_node, tree); - SCRadixReleaseNode(new_node, tree); - sc_errno = SC_ENOMEM; - return NULL; - } - - for (j = 0; j < (node->netmask_cnt - i); j++) - inter_node->netmasks[j] = node->netmasks[i + j]; - - inter_node->netmask_cnt = (node->netmask_cnt - i); - node->netmask_cnt = i; - } - } - - if (SC_RADIX_BITTEST(stream[differ_bit >> 3], - (0x80 >> (differ_bit % 8))) ) { - inter_node->left = node; - inter_node->right = new_node; - } else { - inter_node->left = new_node; - inter_node->right = node; - } - new_node->parent = inter_node; - - if (node->parent == NULL) - tree->head = inter_node; - else if (node->parent->right == node) - node->parent->right = inter_node; - else - node->parent->left = inter_node; - - node->parent = inter_node; - } - - /* insert the netmask into the tree */ - if (netmask != 255 && (netmask != 32 || (netmask == 32 && bitlen != 32)) && netmask != 128) { - node = new_node; - parent = new_node->parent; - while (parent != NULL && netmask < (parent->bit + 1)) { - node = parent; - parent = parent->parent; - } - - node->netmask_cnt++; - if ( (ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * - sizeof(uint8_t)))) == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - FatalError("Fatal error encountered in SCRadixAddKey. Exiting..."); - } - node->netmasks = ptmp; - - if (node->netmask_cnt == 1) { - node->netmasks[0] = netmask; - return new_node; - } - - node->netmasks[node->netmask_cnt - 1] = netmask; - - for (i = node->netmask_cnt - 1; i > 0; i--) { - if (netmask < node->netmasks[i - 1]) { - node->netmasks[i] = netmask; - break; - } - - node->netmasks[i] = node->netmasks[i - 1]; - node->netmasks[i - 1] = netmask; - } - } - - return new_node; -} - -static SCRadixNode *SCRadixAddKeyExclusive( - uint8_t *key_stream, uint8_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask) -{ - return SCRadixAddKeyInternal(key_stream, key_bitlen, tree, user, netmask, true); -} - -static SCRadixNode *SCRadixAddKey( - uint8_t *key_stream, uint8_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask) -{ - return SCRadixAddKeyInternal(key_stream, key_bitlen, tree, user, netmask, false); -} - -/** - * \brief Adds a new IPV4 address to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * a pointer to an IPV4 address - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV4(uint8_t *key_stream, SCRadixTree *tree, - void *user) -{ - SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, 32); - - return node; -} - -/** - * \brief Adds a new IPV6 address to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * the pointer to an IPV6 address - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV6(uint8_t *key_stream, SCRadixTree *tree, - void *user) -{ - SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, 128); - - return node; -} - -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) -static void SCRadixValidateIPv4Key(uint8_t *key, const uint8_t netmask) -{ - uint32_t address; - memcpy(&address, key, sizeof(address)); - uint32_t mask = CIDRGet(netmask); - if (address != (address & mask)) { - uint32_t masked = address & mask; - char ostr[16], nstr[16]; - PrintInet(AF_INET, (void *)&address, ostr, sizeof(ostr)); - PrintInet(AF_INET, (void *)&masked, nstr, sizeof(nstr)); - SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask); - abort(); - } -} - -static void SCRadixValidateIPv6Key(uint8_t *key, const uint8_t netmask) -{ - uint32_t address[4]; - memcpy(&address, key, sizeof(address)); - - uint32_t mask[4]; - memset(&mask, 0, sizeof(mask)); - struct in6_addr mask6; - CIDRGetIPv6(netmask, &mask6); - memcpy(&mask, &mask6.s6_addr, sizeof(mask)); - - uint32_t masked[4]; - masked[0] = address[0] & mask[0]; - masked[1] = address[1] & mask[1]; - masked[2] = address[2] & mask[2]; - masked[3] = address[3] & mask[3]; - - if (memcmp(masked, address, sizeof(masked)) != 0) { - char ostr[64], nstr[64]; - PrintInet(AF_INET6, (void *)&address, ostr, sizeof(ostr)); - PrintInet(AF_INET6, (void *)&masked, nstr, sizeof(nstr)); - SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask); - abort(); - } -} -#endif - -/** - * \brief Adds a new IPV4 netblock to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * a pointer to an IPV4 netblock - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * \param netmask The netmask (cidr) if we are adding a netblock - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, - void *user, uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, netmask); - - return node; -} - -/** - * \brief Adds a new IPV6 netblock to the Radix tree - * - * \param key_stream Data that has to be added to the Radix tree. In this case - * a pointer to an IPV6 netblock - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with the - * key - * \param netmask The netmask (cidr) if we are adding a netblock - * - * \retval node Pointer to the newly created node - */ -SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, - void *user, uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, netmask); - - return node; -} - -/** - * \brief Adds a new IPV4/netblock to the Radix tree from a string - * - * \param str IPV4 string with optional /cidr netmask - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with - * the key - * - * \retval bool true (false) if the node was (wasn't) added. - * - * sc_errno is set: - * - SC_OK: Node added - * - SC_EEXIST: Node already exists - * - SC_EINVAL: Parameter value error - */ -bool SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *user) -{ - uint32_t ip; - uint8_t netmask = 32; - char ip_str[32]; /* Max length for full ipv4/mask string with NUL */ - char *mask_str = NULL; - struct in_addr addr; - - /* Make a copy of the string so it can be modified */ - strlcpy(ip_str, str, sizeof(ip_str) - 2); - *(ip_str + (sizeof(ip_str) - 1)) = '\0'; - - /* Does it have a mask? */ - if (NULL != (mask_str = strchr(ip_str, '/'))) { - uint8_t cidr; - *(mask_str++) = '\0'; - - /* Dotted type netmask not supported (yet) */ - if (strchr(mask_str, '.') != NULL) { - sc_errno = SC_EINVAL; - return false; - } - - /* Get binary values for cidr mask */ - if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 32) < 0) { - sc_errno = SC_EINVAL; - return false; - } - - netmask = (uint8_t)cidr; - } - - /* Validate the IP */ - if (inet_pton(AF_INET, ip_str, &addr) <= 0) { - sc_errno = SC_EINVAL; - return false; - } - ip = addr.s_addr; - if (netmask != 32) { - uint32_t mask = CIDRGet(netmask); - uint32_t masked = ip & mask; - if (masked != ip) { - char nstr[16]; - PrintInet(AF_INET, (void *)&masked, nstr, sizeof(nstr)); - SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask); - ip = masked; - } -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key((uint8_t *)&ip, netmask); -#endif - } - - SCLogDebug("trying to add %s, but only if it doesn't exist", ip_str); - /* Add, but only if not there */ - if (SCRadixAddKeyExclusive((uint8_t *)&ip, 32, tree, user, netmask) == NULL) { - return false; - } - - return true; -} - -/** - * \brief Adds a new IPV6/netblock to the Radix tree from a string - * - * \param str IPV6 string with optional /cidr netmask - * \param tree Pointer to the Radix tree - * \param user Pointer to the user data that has to be associated with - * the key - * - * \retval bool true (false) if the node was (wasn't) added. - * sc_errno is set: - * - SC_OK: Node added - * - SC_EEXIST: Node already exists - * - SC_EINVAL: Parameter value error - */ -bool SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *user) -{ - uint8_t netmask = 128; - char ip_str[80]; /* Max length for full ipv6/mask string with NUL */ - char *mask_str = NULL; - struct in6_addr addr; - - /* Make a copy of the string so it can be modified */ - strlcpy(ip_str, str, sizeof(ip_str) - 2); - *(ip_str + sizeof(ip_str) - 1) = '\0'; - - /* Does it have a mask? */ - if (NULL != (mask_str = strchr(ip_str, '/'))) { - uint8_t cidr; - *(mask_str++) = '\0'; - - /* Dotted type netmask not supported (yet) */ - if (strchr(mask_str, '.') != NULL) { - sc_errno = SC_EINVAL; - return false; - } - - /* Get binary values for cidr mask */ - if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 128) < 0) { - sc_errno = SC_EINVAL; - return false; - } - - netmask = (uint8_t)cidr; - } - - /* Validate the IP */ - if (inet_pton(AF_INET6, ip_str, &addr) <= 0) { - sc_errno = SC_EINVAL; - return false; - } - - if (netmask != 128) { - struct in6_addr mask6, check; - CIDRGetIPv6(netmask, &mask6); - memcpy(&check, &addr, sizeof(check)); - bool diff = false; - for (int i = 0; i < 16; i++) { - addr.s6_addr[i] &= mask6.s6_addr[i]; - diff |= (addr.s6_addr[i] != check.s6_addr[i]); - } - if (diff) { - char nstr[64]; - PrintInet(AF_INET6, (void *)&addr.s6_addr, nstr, sizeof(nstr)); - SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask); - } -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key((uint8_t *)&addr.s6_addr, netmask); -#endif - } - - SCLogDebug("trying to add %s, but only if it doesn't exist", str); - /* Add, but only if not there */ - if (SCRadixAddKeyExclusive(addr.s6_addr, 128, tree, user, netmask) == NULL) { - return false; - } - - sc_errno = SC_OK; - return true; -} - -static void SCRadixTransferNetmasksBWNodes(SCRadixNode *dest, SCRadixNode *src) -{ - int i = 0, j = 0; - void *ptmp = NULL; - - if (src == NULL || dest == NULL) { - SCLogError("src or dest NULL"); - return; - } - - /* no netmasks in the source node, to transfer to the destination node */ - if (src->netmasks == NULL) - return; - - if ( (ptmp = SCRealloc(dest->netmasks, - (src->netmask_cnt + dest->netmask_cnt) * - sizeof(uint8_t))) == NULL) { - SCFree(dest->netmasks); - dest->netmasks = NULL; - return; - } - dest->netmasks = ptmp; - - for (i = dest->netmask_cnt, j = 0; j < src->netmask_cnt; i++, j++) - dest->netmasks[i] = src->netmasks[j]; - - return; -} - -/** - * \brief Removes a netblock entry from an ip node. The function first - * deletes the netblock/user_data entry for the prefix and then - * removes the netmask entry that has been made in the tree, by - * walking up the tree and deleting the entry from the specific node. - * - * \param node The node from which the netblock entry has to be removed. - * \param netmask The netmask entry (cidr) that has to be removed. - */ -static void SCRadixRemoveNetblockEntry(SCRadixNode *node, uint8_t netmask) -{ - void *ptmp; - SCRadixNode *parent = NULL; - int i = 0; - - if (node == NULL) { - SCLogError("Invalid argument. Node is NULL"); - return; - } - - SCRadixRemoveNetmaskUserDataFromPrefix(node->prefix, netmask); - - if (netmask == 32 || netmask == 128) - return; - - parent = node->parent; - while (parent != NULL && netmask < (parent->bit + 1)) { - parent = parent->parent; - } - - for (i = 0; i < node->netmask_cnt; i++) { - if (node->netmasks[i] == netmask) - break; - } - - if (i == node->netmask_cnt) { - SCLogDebug("Something's wrong with the tree. We are unable to find the " - "netmask entry"); - return; - } - - for ( ; i < node->netmask_cnt - 1; i++) - node->netmasks[i] = node->netmasks[i + 1]; - - node->netmask_cnt--; - if (node->netmask_cnt == 0) { - SCFree(node->netmasks); - node->netmasks = NULL; - return; - } - - ptmp = SCRealloc(node->netmasks, node->netmask_cnt * sizeof(uint8_t)); - if (ptmp == NULL) { - SCFree(node->netmasks); - node->netmasks = NULL; - return; - } - node->netmasks = ptmp; - - return; -} - -/** - * \brief Removes a key from the Radix tree - * - * \param key_stream Data that has to be removed from the Radix tree - * \param key_bitlen The bitlen of the above stream. For example if the - * stream holds an IPV4 address(4 bytes), bitlen would be 32 - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, - SCRadixTree *tree, uint8_t netmask) -{ - SCRadixNode *node = tree->head; - SCRadixNode *parent = NULL; - SCRadixNode *temp_dest = NULL; - - SCRadixPrefix *prefix = NULL; - - uint32_t mask = 0; - int i = 0; - - if (node == NULL) - return; - - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL, 255)) == NULL) - return; - - while (node->bit < prefix->bitlen) { - if (SC_RADIX_BITTEST(prefix->stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - node = node->right; - } else { - node = node->left; - } - - if (node == NULL) { - SCRadixReleasePrefix(prefix, tree); - return; - } - } - - if (node->bit != prefix->bitlen || node->prefix == NULL) { - SCRadixReleasePrefix(prefix, tree); - return; - } - - i = prefix->bitlen / 8; - if (SCMemcmp(node->prefix->stream, prefix->stream, i) == 0) { - mask = UINT_MAX << (8 - prefix->bitlen % 8); - - if (prefix->bitlen % 8 == 0 || - (node->prefix->stream[i] & mask) == (prefix->stream[i] & mask)) { - if (!SCRadixPrefixContainNetmask(node->prefix, netmask)) { - SCLogDebug("The ip key exists in the Radix Tree, but this(%d) " - "netblock entry doesn't exist", netmask); - SCRadixReleasePrefix(prefix, tree); - return; - } - } else { - SCLogDebug("You are trying to remove a key that doesn't exist in " - "the Radix Tree"); - SCRadixReleasePrefix(prefix, tree); - return; - } - } else { - SCLogDebug("You are trying to remove a key that doesn't exist in the " - "Radix Tree"); - SCRadixReleasePrefix(prefix, tree); - return; - } - - /* The ip node does exist, and the netblock entry does exist in this node, if - * we have reached this point. If we have more than one netblock entry, it - * indicates we have multiple entries for this key. So we delete that - * particular netblock entry, and make our way out of this function */ - if (SCRadixPrefixNetmaskCount(node->prefix) > 1) { - SCRadixRemoveNetblockEntry(node, netmask); - SCRadixReleasePrefix(prefix, tree); - return; - } - - /* we are deleting the root of the tree. This would be the only node left - * in the tree */ - if (tree->head == node) { - SCRadixReleaseNode(node, tree); - tree->head = NULL; - SCRadixReleasePrefix(prefix, tree); - return; - } - - parent = node->parent; - /* parent->parent is not the root of the tree */ - if (parent->parent != NULL) { - if (parent->parent->left == parent) { - if (node->parent->left == node) { - temp_dest = parent->right; - parent->parent->left = parent->right; - parent->right->parent = parent->parent; - } else { - temp_dest = parent->left; - parent->parent->left = parent->left; - parent->left->parent = parent->parent; - } - } else { - if (node->parent->left == node) { - temp_dest = parent->right; - parent->parent->right = parent->right; - parent->right->parent = parent->parent; - } else { - temp_dest = parent->left; - parent->parent->right = parent->left; - parent->left->parent = parent->parent; - } - } - /* parent is the root of the tree */ - } else { - if (parent->left == node) { - temp_dest = tree->head->right; - tree->head->right->parent = NULL; - tree->head = tree->head->right; - } else { - temp_dest = tree->head->left; - tree->head->left->parent = NULL; - tree->head = tree->head->left; - } - } - /* We need to shift the netmask entries from the node that would be - * deleted to its immediate descendant */ - SCRadixTransferNetmasksBWNodes(temp_dest, parent); - /* release the nodes */ - SCRadixReleaseNode(parent, tree); - SCRadixReleaseNode(node, tree); - SCRadixReleasePrefix(prefix, tree); - - return; -} - -/** - * \brief Removes a key from the Radix tree - * - * \param key_stream Data that has to be removed from the Radix tree - * \param key_bitlen The bitlen of the above stream. - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, - SCRadixTree *tree) -{ - SCRadixRemoveKey(key_stream, key_bitlen, tree, 255); - return; -} - -/** - * \brief Removes an IPV4 address netblock key from the Radix tree. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV4 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key(key_stream, netmask); -#endif - SCRadixRemoveKey(key_stream, 32, tree, netmask); - return; -} - -/** - * \brief Removes an IPV4 address key(not a netblock) from the Radix tree. - * Instead of using this function, we can also used - * SCRadixRemoveKeyIPV4Netblock(), by supplying a netmask value of 32. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV4 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV4(uint8_t *key_stream, SCRadixTree *tree) -{ - SCRadixRemoveKey(key_stream, 32, tree, 32); - return; -} - -/** - * \brief Removes an IPV6 netblock address key from the Radix tree. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV6 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key(key_stream, netmask); -#endif - SCRadixRemoveKey(key_stream, 128, tree, netmask); - return; -} - -/** - * \brief Removes an IPV6 address key(not a netblock) from the Radix tree. - * Instead of using this function, we can also used - * SCRadixRemoveKeyIPV6Netblock(), by supplying a netmask value of 128. - * - * \param key_stream Data that has to be removed from the Radix tree. In this - * case an IPV6 address - * \param tree Pointer to the Radix tree from which the key has to be - * removed - */ -void SCRadixRemoveKeyIPV6(uint8_t *key_stream, SCRadixTree *tree) -{ - SCRadixRemoveKey(key_stream, 128, tree, 128); - return; -} - -/** - * \brief Checks if an IP prefix falls under a netblock, in the path to the root - * of the tree, from the node. Used internally by SCRadixFindKey() - * - * \param prefix Pointer to the prefix that contains the ip address - * \param node Pointer to the node from where we have to climb the tree - */ -static inline SCRadixNode *SCRadixFindKeyIPNetblock( - uint8_t *key_stream, uint8_t key_bitlen, SCRadixNode *node, void **user_data_result) -{ - SCRadixNode *netmask_node = NULL; - uint32_t mask = 0; - int bytes = 0; - int i = 0; - int j = 0; - - while (node != NULL && node->netmasks == NULL) - node = node->parent; - - if (node == NULL) - return NULL; - /* hold the node found containing a netmask. We will need it when we call - * this function recursively */ - netmask_node = node; - - for (j = 0; j < netmask_node->netmask_cnt; j++) { - bytes = key_bitlen / 8; - for (i = 0; i < bytes; i++) { - mask = UINT_MAX; - if ( ((i + 1) * 8) > netmask_node->netmasks[j]) { - if ( ((i + 1) * 8 - netmask_node->netmasks[j]) < 8) - mask = UINT_MAX << ((i + 1) * 8 - netmask_node->netmasks[j]); - else - mask = 0; - } - key_stream[i] &= mask; - } - - while (node->bit < key_bitlen) { - if (SC_RADIX_BITTEST(key_stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - node = node->right; - } else { - node = node->left; - } - - if (node == NULL) - return NULL; - } - - if (node->bit != key_bitlen || node->prefix == NULL) - return NULL; - - if (SCMemcmp(node->prefix->stream, key_stream, bytes) == 0) { - mask = UINT_MAX << (8 - key_bitlen % 8); - - if (key_bitlen % 8 == 0 || - (node->prefix->stream[bytes] & mask) == (key_stream[bytes] & mask)) { - if (SCRadixPrefixContainNetmaskAndSetUserData( - node->prefix, netmask_node->netmasks[j], false, user_data_result)) - return node; - } - } - } - - return SCRadixFindKeyIPNetblock(key_stream, key_bitlen, netmask_node->parent, user_data_result); -} - -/** - * \brief Checks if an IP address key is present in the tree. The function - * apart from handling any normal data, also handles ipv4/ipv6 netblocks - * - * \param key_stream Data that has to be found in the Radix tree - * \param key_bitlen The bitlen of the above stream. - * \param tree Pointer to the Radix tree - * \param exact_match The key to be searched is an ip address - * \param netmask Netmask used during exact match - */ -static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint8_t key_bitlen, uint8_t netmask, - SCRadixTree *tree, bool exact_match, void **user_data_result) -{ - if (tree == NULL || tree->head == NULL) - return NULL; - - SCRadixNode *node = tree->head; - uint32_t mask = 0; - int bytes = 0; - uint8_t tmp_stream[255]; - - memset(tmp_stream, 0, 255); - memcpy(tmp_stream, key_stream, key_bitlen / 8); - - while (node->bit < key_bitlen) { - if (SC_RADIX_BITTEST(tmp_stream[node->bit >> 3], - (0x80 >> (node->bit % 8))) ) { - node = node->right; - } else { - node = node->left; - } - - if (node == NULL) { - return NULL; - } - } - - if (node->bit != key_bitlen || node->prefix == NULL) { - return NULL; - } - - bytes = key_bitlen / 8; - if (SCMemcmp(node->prefix->stream, tmp_stream, bytes) == 0) { - mask = UINT_MAX << (8 - key_bitlen % 8); - - if (key_bitlen % 8 == 0 || - (node->prefix->stream[bytes] & mask) == (tmp_stream[bytes] & mask)) { - if (SCRadixPrefixContainNetmaskAndSetUserData( - node->prefix, netmask, true, user_data_result)) { - return node; - } - } - } - - /* if you are not an ip key, get out of here */ - if (exact_match) { - return NULL; - } - - SCRadixNode *ret = SCRadixFindKeyIPNetblock(tmp_stream, key_bitlen, node, user_data_result); - return ret; -} - -/** - * \brief Checks if an IPV4 address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV4 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV4ExactMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 32, 32, tree, true, user_data_result); -} - -/** - * \brief Checks if an IPV4 address is present in the tree under a netblock - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV4 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 32, 32, tree, false, user_data_result); -} - -/** - * \brief Checks if an IPV4 Netblock address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV4 netblock address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask, void **user_data_result) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv4Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixFindKey(key_stream, 32, netmask, tree, true, user_data_result); - return node; -} - -/** - * \brief Checks if an IPV6 Netblock address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV6 netblock address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, - uint8_t netmask, void **user_data_result) -{ -#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) - SCRadixValidateIPv6Key(key_stream, netmask); -#endif - SCRadixNode *node = SCRadixFindKey(key_stream, 128, netmask, tree, true, user_data_result); - return node; -} - -/** - * \brief Checks if an IPV6 address is present in the tree - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV6 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV6ExactMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 128, 128, tree, true, user_data_result); -} - -/** - * \brief Checks if an IPV6 address is present in the tree under a netblock - * - * \param key_stream Data that has to be found in the Radix tree. In this case - * an IPV6 address - * \param tree Pointer to the Radix tree instance - */ -SCRadixNode *SCRadixFindKeyIPV6BestMatch(uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) -{ - return SCRadixFindKey(key_stream, 128, 128, tree, false, user_data_result); -} - -/** - * \brief Prints the node information from a Radix tree - * - * \param node Pointer to the Radix node whose information has to be printed - * \param level Used for indentation purposes - */ -void SCRadixPrintNodeInfo(SCRadixNode *node, int level, void (*PrintData)(void*)) -{ - int i = 0; - - if (node == NULL) - return; - - for (i = 0; i < level; i++) - printf(" "); - - printf("%d [", node->bit); - - if (node->netmasks == NULL) { - printf("%d, ", -1); - } else { - for (i = 0; i < node->netmask_cnt; i++) - printf("%s%d", (0 == i ? "" : ", "), node->netmasks[i]); - } - - printf("] ("); - if (node->prefix != NULL) { - for (i = 0; i * 8 < node->prefix->bitlen; i++) - printf("%s%d", (0 == i ? "" : "."), node->prefix->stream[i]); - printf(") user_data %p\n", node->prefix->user_data); - - SCRadixUserData *ud = node->prefix->user_data; - do { - for (int x = 0; x <= level; x++) - printf(" "); - printf("[%d] (%p): ", ud->netmask, ud->user); - if (PrintData != NULL) { - PrintData(ud->user); - } else { - printf("NULL"); - } - printf("\n"); - ud = ud->next; - } while (ud != NULL); - } else { - printf("inter_node)\n"); - } - - return; -} - -/** - * \brief Helper function used by SCRadixPrintTree. Prints the subtree with - * node as the root of the subtree - * - * \param node Pointer to the node that is the root of the subtree to be printed - * \param level Used for indentation purposes - */ -static void SCRadixPrintRadixSubtree(SCRadixNode *node, int level, void (*PrintData)(void*)) -{ - if (node != NULL) { - SCRadixPrintNodeInfo(node, level, PrintData); - SCRadixPrintRadixSubtree(node->left, level + 1, PrintData); - SCRadixPrintRadixSubtree(node->right, level + 1, PrintData); - } - - return; -} - -/** - * \brief Prints the Radix Tree. While printing the radix tree we use the - * following format - * - * Parent_0 - * Left_Child_1 - * Left_Child_2 - * Right_Child_2 - * Right_Child_1 - * Left_Child_2 - * Right_Child_2 and so on - * - * Each node printed out holds details on the next bit that differs - * amongst its children, and if the node holds a prefix, the perfix is - * printed as well. - * - * \param tree Pointer to the Radix tree that has to be printed - */ -void SCRadixPrintTree(SCRadixTree *tree) -{ - printf("Printing the Radix Tree: \n"); - - SCRadixPrintRadixSubtree(tree->head, 0, tree->PrintData); - - return; -} - -/*------------------------------------Unit_Tests------------------------------*/ - -#ifdef UNITTESTS - -static int SCRadixTestIPV4Insertion03(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* add a key that already exists in the tree */ - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - /* continue adding keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.3", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "127.234.2.62", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV4Removal04(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - /* remove the keys from the tree */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); - - result &= (tree->head == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6Insertion07(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* Try to add the prefix that already exists in the tree */ - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6Removal08(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* Try to add the prefix that already exists in the tree */ - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "8888:0BF1:5346:BDEA:6422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2006:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test for existence */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:DDDD:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - /* remove keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - /* test for existence */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - /* remove keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); - - /* test for existence */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -/** Bug #5066 - * - * insert: - * - 100.117.241.0/25: 100.117.241.0 - 100.117.241.127 - * - 100.117.241.0/26: 100.117.241.0 - 100.117.241.63 - * - * check: - * - 100.117.241.64/26: 100.117.241.64 - 100.117.241.127 - */ - -static int SCRadixTestIPV4Bug5066(void) -{ - struct sockaddr_in servaddr; - SCRadixNode *node = NULL; - - SCLogDebug("setup tree"); - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "100.117.241.0", &servaddr.sin_addr) <= 0); - SCLogDebug("add 100.117.241.0/25"); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1"), 25); - SCRadixPrintTree(tree); - SCLogDebug("find 100.117.241.0/25"); - char *r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 25, (void **)&r); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 100.117.241.0/26"); - FAIL_IF(inet_pton(AF_INET, "100.117.241.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("2"), 26); - SCRadixPrintTree(tree); - SCLogDebug("find 100.117.241.0/26"); - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("find 100.117.241.64/26 (should fail)"); - FAIL_IF(inet_pton(AF_INET, "100.117.241.64", &servaddr.sin_addr) <= 0); - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); - FAIL_IF_NOT_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 100.117.241.64/26"); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("3"), 26); - SCLogDebug("find 100.117.241.64/26 (should succeed)"); - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCRadixPrintTree(tree); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -static void SCRadixTestIPV4Bug5066v2PrintData(void *d) -{ - const char *s = d; - printf("%s", s); -} - -static int SCRadixTestIPV4Bug5066v2(void) -{ - struct sockaddr_in servaddr; - SCRadixNode *node = NULL; - - SCLogDebug("setup tree"); - SCRadixTree *tree = SCRadixCreateRadixTree(free, SCRadixTestIPV4Bug5066v2PrintData); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/24"), 24); - SCRadixPrintTree(tree); - char *r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 24, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.0/24") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/25"), 25); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 25, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.0/25") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/26"), 26); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.0/26") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.64", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.64/26"), 26); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.64/26") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.64", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.64/27"), 27); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 27, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.64/27") == 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "1.2.3.96", &servaddr.sin_addr) <= 0); - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.96/27"), 27); - SCRadixPrintTree(tree); - r = NULL; - node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 27, (void **)&r); - SCRadixPrintTree(tree); - FAIL_IF_NULL(node); - SCLogNotice("node:"); - SCRadixPrintNodeInfo(node, 0, NULL); - FAIL_IF_NOT(strcmp(r, "1.2.3.96/27") == 0); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** Bug #5066 - */ -static int SCRadixTestIPV6Bug5066(void) -{ - struct sockaddr_in6 servaddr; - SCRadixNode *node = NULL; - - SCLogDebug("setup tree"); - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "2000::1:0", &servaddr.sin6_addr) <= 0); - SCLogDebug("add 2000::1:0/121"); - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("1"), 121); - SCRadixPrintTree(tree); - SCLogDebug("find 2000::1:0/121"); - char *r = NULL; - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 121, (void **)&r); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 2000::1:0/122"); - FAIL_IF(inet_pton(AF_INET6, "2000::1:0", &servaddr.sin6_addr) <= 0); - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("2"), 122); - SCRadixPrintTree(tree); - SCLogDebug("find 2000::1:0/122"); - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("find 2000::1:40/122 (should fail)"); - FAIL_IF(inet_pton(AF_INET6, "2000::1:40", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); - FAIL_IF_NOT_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCLogDebug("add 2000::1:40/122"); - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("3"), 122); - SCLogDebug("find 2000::1:40/122 (should succeed)"); - node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); - FAIL_IF_NULL(node); - SCRadixPrintNodeInfo(node, 0, NULL); - - SCRadixPrintTree(tree); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -static int SCRadixTestIPV4NetblockInsertion09(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.192.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.170.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.145", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.64.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.191.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.224.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.174.224.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.175.224.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV4NetblockInsertion10(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node[2]; - struct sockaddr_in servaddr; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - SCRadixPrintTree(tree); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - SCRadixNode *found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[0]); - - SCLogDebug("search \"exact\" match for 192.171.128.45"); - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[1]); - - SCLogDebug("search \"best\" match for 192.171.128.45"); - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT(found == node[0]); - - /* let us remove a netblock */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT_NULL(found); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); - FAIL_IF_NOT_NULL(found); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -static int SCRadixTestIPV4NetblockInsertion11(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 0); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "245.63.62.121", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); - - /* remove node 0.0.0.0 */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 0); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV4NetblockInsertion12(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node[2]; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) - return 0; - node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); - - if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 32); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[0]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[0]); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.224", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.229", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "225.175.21.230", &servaddr.sin_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6NetblockInsertion13(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1146:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1356:1241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DAAA:1245:2342:1146:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - - SCRadixReleaseRadixTree(tree); - - return result; -} - -static int SCRadixTestIPV6NetblockInsertion14(void) -{ - SCRadixTree *tree = NULL; - SCRadixNode *node = NULL; - struct sockaddr_in6 servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - /* add the keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "::", &servaddr.sin6_addr) <= 0) - return 0; - node = SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, - 0); - - /* test the existence of keys */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0BF1:5346:B116:2362:8713:9124:2315", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "2004:0B23:3252:BDEA:7422:8713:9124:2341", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != node); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", - &servaddr.sin6_addr) <= 0) - return 0; - result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL && - SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != node); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch15(void) -{ - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "192.168.0.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "192.168.0.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch16(void) -{ - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "192.168.1.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch17(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "10.0.0.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "10.0.0.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch18(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "172.26.0.1", &servaddr.sin_addr) <= 0); - - for (uint32_t i = 0; i <= 32; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[32]; - snprintf(str, sizeof(str), "172.26.0.1/%u", i); - SCRadixAddKeyIPV4String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check special combinations of netblocks and addresses - * on best search checking the returned userdata - */ -static int SCRadixTestIPV4NetBlocksAndBestSearch19(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); - - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 100; - - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 0); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "192.168.1.15", &servaddr.sin_addr) <= 0); - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.0.0.0", &servaddr.sin_addr) <= 0); - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 200; - - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 8); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "178.168.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.160.0.0", &servaddr.sin_addr) <= 0); - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 300; - - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 12); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.167.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "177.178.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "197.178.1.15", &servaddr.sin_addr) <= 0); - - node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch20(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABAB:CDCD:ABAB:CDCD:1234:4321:1234:4321", &servaddr.sin6_addr) <= - 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "ABAB:CDCD:ABAB:CDCD:1234:4321:1234:4321/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch21(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ff00::1", &servaddr.sin6_addr) <= 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "ff00::1/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch22(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ff00::192:168:1:1", &servaddr.sin6_addr) <= 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "ff00::192:168:1:1/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check that the best match search works for all the - * possible netblocks of a fixed address - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch23(void) -{ - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - struct sockaddr_in6 servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "FF00:ABCD:BCDA::ABCD", &servaddr.sin6_addr) <= 0); - - for (uint32_t i = 0; i <= 128; i++) { - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = i; - - char str[64]; - snprintf(str, sizeof(str), "FF00:ABCD:BCDA::ABCD/%u", i); - SCRadixAddKeyIPV6String(str, tree, user); - - void *user_data = NULL; - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != i); - } - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test Check special combinations of netblocks and addresses - * on best search checking the returned userdata - */ -static int SCRadixTestIPV6NetBlocksAndBestSearch24(void) -{ - struct sockaddr_in6 servaddr; - void *user_data = NULL; - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - uint32_t *user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 100; - SCRadixAddKeyIPV6String("::/0", tree, user); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0); - SCRadixNode *node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 200; - SCRadixAddKeyIPV6String("ABCD::0/8", tree, user); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "DCBA::1", &servaddr.sin6_addr) <= 0); - - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - user_data = NULL; - user = SCMalloc(sizeof(uint32_t)); - FAIL_IF_NULL(user); - *user = 300; - SCRadixAddKeyIPV6String("ABCD:ABCD::0/12", tree, user); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD:ABCD::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABCD:AAAA::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 300); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "ABAB::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 200); - - user_data = NULL; - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET6, "CABD::1", &servaddr.sin6_addr) <= 0); - node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); - FAIL_IF_NULL(node); - FAIL_IF_NULL(user_data); - FAIL_IF(*((uint32_t *)user_data) != 100); - - SCRadixReleaseRadixTree(tree); - PASS; -} - -/** - * \test SCRadixTestIPV4NetblockInsertion15 insert a node searching on it. - * Should always return true but the purpose of the test is to monitor - * the memory usage to detect memleaks (there was one on searching) - */ -static int SCRadixTestIPV4NetblockInsertion25(void) -{ - SCRadixTree *tree = NULL; - struct sockaddr_in servaddr; - int result = 1; - - tree = SCRadixCreateRadixTree(free, NULL); - - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) - return 0; - SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); - - /* test for the existence of a key */ - memset(&servaddr, 0, sizeof(servaddr)); - if (inet_pton(AF_INET, "192.168.128.53", &servaddr.sin_addr) <= 0) - return 0; - - result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); - - SCRadixReleaseRadixTree(tree); - - return result; -} - -/** - * \test SCRadixTestIPV4NetblockInsertion26 insert a node searching on it. - * Should always return true but the purpose of the test is to monitor - * the memory usage to detect memleaks (there was one on searching) - */ -static int SCRadixTestIPV4NetblockInsertion26(void) -{ - struct sockaddr_in servaddr; - - SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); - FAIL_IF_NULL(tree); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); - - char *str = SCStrdup("Hello1"); - FAIL_IF_NULL(str); - SCRadixNode *node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 0); - FAIL_IF_NULL(node); - - str = SCStrdup("Hello1"); - FAIL_IF_NULL(str); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "176.0.0.0", &servaddr.sin_addr) <= 0); - - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 5); - FAIL_IF_NULL(node); - - str = SCStrdup("Hello1"); - FAIL_IF_NULL(str); - - memset(&servaddr, 0, sizeof(servaddr)); - FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); - - node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 7); - FAIL_IF_NULL(node); - - /* test for the existence of a key */ - // result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); - - SCRadixReleaseRadixTree(tree); - - PASS; -} - -#endif - -void SCRadixRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03); - UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04); - UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07); - UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion09", - SCRadixTestIPV4NetblockInsertion09); - UtRegisterTest("SCRadixTestIPV4Bug5066", SCRadixTestIPV4Bug5066); - UtRegisterTest("SCRadixTestIPV4Bug5066v2", SCRadixTestIPV4Bug5066v2); - UtRegisterTest("SCRadixTestIPV6Bug5066", SCRadixTestIPV6Bug5066); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion10", - SCRadixTestIPV4NetblockInsertion10); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion11", - SCRadixTestIPV4NetblockInsertion11); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion12", - SCRadixTestIPV4NetblockInsertion12); - UtRegisterTest("SCRadixTestIPV6NetblockInsertion13", - SCRadixTestIPV6NetblockInsertion13); - UtRegisterTest("SCRadixTestIPV6NetblockInsertion14", - SCRadixTestIPV6NetblockInsertion14); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch15", - SCRadixTestIPV4NetBlocksAndBestSearch15); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch16", - SCRadixTestIPV4NetBlocksAndBestSearch16); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch17", - SCRadixTestIPV4NetBlocksAndBestSearch17); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch18", - SCRadixTestIPV4NetBlocksAndBestSearch18); - UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch19", - SCRadixTestIPV4NetBlocksAndBestSearch19); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch20", - SCRadixTestIPV6NetBlocksAndBestSearch20); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch21", - SCRadixTestIPV6NetBlocksAndBestSearch21); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch22", - SCRadixTestIPV6NetBlocksAndBestSearch22); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch23", - SCRadixTestIPV6NetBlocksAndBestSearch23); - UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch24", - SCRadixTestIPV6NetBlocksAndBestSearch24); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion25", - SCRadixTestIPV4NetblockInsertion25); - UtRegisterTest("SCRadixTestIPV4NetblockInsertion26", - SCRadixTestIPV4NetblockInsertion26); -#endif - - return; -} diff --git a/src/util-radix-tree.h b/src/util-radix-tree.h deleted file mode 100644 index c43e14eb0126..000000000000 --- a/src/util-radix-tree.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_RADIX_TREE_H__ -#define __UTIL_RADIX_TREE_H__ - -#define SC_RADIX_BITTEST(x, y) ((x) & (y)) - -/** - * \brief Structure that hold the user data and the netmask associated with it. - */ -typedef struct SCRadixUserData_ { - /* holds a pointer to the user data associated with the particular netmask */ - void *user; - /* pointer to the next user data in the list */ - struct SCRadixUserData_ *next; - /* holds the netmask value that corresponds to this user data pointer */ - uint8_t netmask; -} SCRadixUserData; - -/** - * \brief Structure for the prefix/key in the radix tree - */ -typedef struct SCRadixPrefix_ { - /* length of the stream */ - uint16_t bitlen; - - /* the key that has been stored in the tree */ - uint8_t *stream; - - /* any user data that has to be associated with this key. We need a user - * data field for each netblock value possible since one ip can be associated - * with any of the 32 or 128 netblocks. Also for non-ips, we store the - * netmask as 255 in SCRadixUserData->netmask */ - SCRadixUserData *user_data; -} SCRadixPrefix; - -/** - * \brief Structure for the node in the radix tree - */ -typedef struct SCRadixNode_ { - /* the bit position where the bits differ in the nodes children. Used - * to determine the path to be taken during a lookup*/ - uint16_t bit; - - uint16_t pad0; - - /* total no of netmasks that are registered under this node */ - uint16_t netmask_cnt; - /* holds a list of netmasks that come under this node in the tree */ - uint8_t *netmasks; - - /* holds the prefix that the path to this node holds */ - SCRadixPrefix *prefix; - - /* the left and the right children of a node */ - struct SCRadixNode_ *left, *right; - - /* the parent node for this tree */ - struct SCRadixNode_ *parent; -} SCRadixNode; - -/** - * \brief Structure for the radix tree - */ -typedef struct SCRadixTree_ { - /* the root node in the radix tree */ - SCRadixNode *head; - - /* function pointer that is supplied by the user to free the user data - * held by the user field of SCRadixNode */ - void (*PrintData)(void *); - void (*Free)(void *); -} SCRadixTree; - -SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*), void (*PrintData)(void*)); -void SCRadixReleaseRadixTree(SCRadixTree *); - -SCRadixNode *SCRadixAddKeyIPV4(uint8_t *, SCRadixTree *, void *); -SCRadixNode *SCRadixAddKeyIPV6(uint8_t *, SCRadixTree *, void *); -SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *, SCRadixTree *, void *, - uint8_t); -SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *, SCRadixTree *, void *, - uint8_t); -bool SCRadixAddKeyIPV4String(const char *, SCRadixTree *, void *); -bool SCRadixAddKeyIPV6String(const char *, SCRadixTree *, void *); - -void SCRadixRemoveKeyGeneric(uint8_t *, uint16_t, SCRadixTree *); -void SCRadixRemoveKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t); -void SCRadixRemoveKeyIPV4(uint8_t *, SCRadixTree *); -void SCRadixRemoveKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t); -void SCRadixRemoveKeyIPV6(uint8_t *, SCRadixTree *); - -SCRadixNode *SCRadixFindKeyIPV4ExactMatch(uint8_t *, SCRadixTree *, void **); -SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t, void **); -SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *, SCRadixTree *, void **); - -SCRadixNode *SCRadixFindKeyIPV6ExactMatch(uint8_t *, SCRadixTree *, void **); -SCRadixNode *SCRadixFindKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t, void **); -SCRadixNode *SCRadixFindKeyIPV6BestMatch(uint8_t *, SCRadixTree *, void **); - -void SCRadixPrintTree(SCRadixTree *); -void SCRadixPrintNodeInfo(SCRadixNode *, int, void (*PrintData)(void*)); - -void SCRadixRegisterTests(void); - -#endif /* __UTIL_RADIX_TREE_H__ */ diff --git a/src/util-random.c b/src/util-random.c deleted file mode 100644 index 0beee3287880..000000000000 --- a/src/util-random.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Functions for getting a random value based on - * SEI CERT C Coding Standard MSC30-C - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-random.h" -#include "util-debug.h" - -#if !(defined(HAVE_WINCRYPT_H) && defined(OS_WIN32)) -#if defined(HAVE_CLOCK_GETTIME) - -static long int RandomGetClock(void) -{ - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - - // coverity[dont_call : FALSE] - srandom(ts.tv_nsec ^ ts.tv_sec); - long int value = random(); - return value; -} - -#else - -static long int RandomGetPosix(void) -{ - struct timeval tv; - memset(&tv, 0, sizeof(tv)); - gettimeofday(&tv, NULL); - - // coverity[dont_call : FALSE] - srandom(tv.tv_usec ^ tv.tv_sec); - long int value = random(); - return value; -} - -#endif -#endif /* !(defined(HAVE_WINCRYPT_H) && defined(OS_WIN32)) */ - -#if defined(HAVE_WINCRYPT_H) && defined(OS_WIN32) -#include - -long int RandomGet(void) -{ - if (g_disable_randomness) - return 0; - - HCRYPTPROV p; - if (!CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, 0)) { - DWORD err = GetLastError(); - SCLogDebug("CryptAcquireContext error: %" PRIu32, (uint32_t)err); - if (err == (DWORD)NTE_BAD_KEYSET) { - /* The key doesn't exist yet, create it */ - if (!CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, - CRYPT_NEWKEYSET)) { - - SCLogDebug("CryptAcquireContext error: %" PRIu32, - (uint32_t)err); - return -1; - } - } else { - return -1; - } - } - - long int value = 0; - if (!CryptGenRandom(p, sizeof(value), (BYTE *)&value)) { - (void)CryptReleaseContext(p, 0); - return -1; - } - - (void)CryptReleaseContext(p, 0); - - return value; -} -#elif defined(HAVE_GETRANDOM) -long int RandomGet(void) -{ - if (g_disable_randomness) - return 0; - - long int value = 0; - int ret = getrandom(&value, sizeof(value), 0); - /* ret should be sizeof(value), but if it is > 0 and < sizeof(value) - * it's still better than nothing so we return what we have */ - if (ret <= 0) { - if (ret == -1 && errno == ENOSYS) { -#if defined(HAVE_CLOCK_GETTIME) - return RandomGetClock(); -#else - return RandomGetPosix(); -#endif - } - return -1; - } - return value; -} -#elif defined(HAVE_CLOCK_GETTIME) -long int RandomGet(void) -{ - if (g_disable_randomness) - return 0; - - return RandomGetClock(); -} -#else -long int RandomGet(void) -{ - if (g_disable_randomness) - return 0; - - return RandomGetPosix(); -} -#endif diff --git a/src/util-random.h b/src/util-random.h deleted file mode 100644 index 6376c05a3aaa..000000000000 --- a/src/util-random.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_RANDOM_H__ -#define __UTIL_RANDOM_H__ - -long int RandomGet(void); - -#endif /* __UTIL_RANDOM_H__ */ - diff --git a/src/util-reference-config.c b/src/util-reference-config.c deleted file mode 100644 index 89cc1d23881c..000000000000 --- a/src/util-reference-config.c +++ /dev/null @@ -1,798 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" -#include "detect.h" -#include "detect-engine.h" -#include "util-hash.h" - -#include "util-reference-config.h" -#include "conf.h" -#include "util-unittest.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-fmemopen.h" - -/* Regex to parse each line from reference.config file. The first substring - * is for the system name and the second for the url */ -/*-----------------------------------------------------------system-------------------url----*/ -#define SC_RCONF_REGEX "^\\s*config\\s+reference\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s+(.+)\\s*$" - -/* Default path for the reference.conf file */ -#define SC_RCONF_DEFAULT_FILE_PATH CONFIG_DIR "/reference.config" - -/* the hash functions */ -uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen); -char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2); -void SCRConfReferenceHashFree(void *ch); - -/* used to get the reference.config file path */ -static const char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx); - -void SCReferenceConfInit(DetectEngineCtx *de_ctx) -{ - int en; - PCRE2_SIZE eo; - int opts = 0; - - de_ctx->reference_conf_regex = - pcre2_compile((PCRE2_SPTR8)SC_RCONF_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); - if (de_ctx->reference_conf_regex == NULL) { - PCRE2_UCHAR errbuffer[256]; - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - SCLogWarning("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - SC_RCONF_REGEX, (int)eo, errbuffer); - return; - } - de_ctx->reference_conf_regex_match = - pcre2_match_data_create_from_pattern(de_ctx->reference_conf_regex, NULL); - return; -} - -void SCReferenceConfDeinit(DetectEngineCtx *de_ctx) -{ - if (de_ctx->reference_conf_regex != NULL) { - pcre2_code_free(de_ctx->reference_conf_regex); - de_ctx->reference_conf_regex = NULL; - } - if (de_ctx->reference_conf_regex_match != NULL) { - pcre2_match_data_free(de_ctx->reference_conf_regex_match); - de_ctx->reference_conf_regex_match = NULL; - } -} - - -/** - * \brief Inits the context to be used by the Reference Config parsing API. - * - * This function initializes the hash table to be used by the Detection - * Engine Context to hold the data from reference.config file, - * obtains the file descriptor to parse the reference.config file, and - * inits the regex used to parse the lines from reference.config file. - * - * \param de_ctx Pointer to the Detection Engine Context. - * - * \note if file open fails, we leave de_ctx->reference_conf_ht initialized - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) -{ - /* init the hash table to be used by the reference config references */ - de_ctx->reference_conf_ht = HashTableInit(128, SCRConfReferenceHashFunc, - SCRConfReferenceHashCompareFunc, - SCRConfReferenceHashFree); - if (de_ctx->reference_conf_ht == NULL) { - SCLogError("Error initializing the hash " - "table"); - return NULL; - } - - /* if it is not NULL, use the file descriptor. The hack so that we can - * avoid using a dummy reference file for testing purposes and - * instead use an input stream against a buffer containing the - * reference strings */ - if (fd == NULL) { - const char *filename = SCRConfGetConfFilename(de_ctx); - if ((fd = fopen(filename, "r")) == NULL) { -#ifdef UNITTESTS - if (RunmodeIsUnittests()) { - return NULL; // silently fail - } -#endif - SCLogError("Error opening file: \"%s\": %s", filename, strerror(errno)); - return NULL; - } - } - - return fd; -} - - -/** - * \brief Returns the path for the Reference Config file. We check if we - * can retrieve the path from the yaml conf file. If it is not present, - * return the default path for the reference.config file which is - * "./reference.config". - * - * \retval log_filename Pointer to a string containing the path for the - * reference.config file. - */ -static const char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx) -{ - const char *path = NULL; - - if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { - char config_value[256]; - snprintf(config_value, sizeof(config_value), - "%s.reference-config-file", de_ctx->config_prefix); - - /* try loading prefix setting, fall back to global if that - * fails. */ - if (ConfGet(config_value, &path) != 1) { - if (ConfGet("reference-config-file", &path) != 1) { - return (char *)SC_RCONF_DEFAULT_FILE_PATH; - } - } - } else { - if (ConfGet("reference-config-file", &path) != 1) { - return (char *)SC_RCONF_DEFAULT_FILE_PATH; - } - } - return path; -} - -/** - * \brief Releases local resources used by the Reference Config API. - */ -static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) -{ - if (fd != NULL) { - fclose(fd); - } - - return; -} - -/** - * \brief Releases de_ctx resources related to Reference Config API. - */ -void SCRConfDeInitContext(DetectEngineCtx *de_ctx) -{ - if (de_ctx->reference_conf_ht != NULL) - HashTableFree(de_ctx->reference_conf_ht); - - de_ctx->reference_conf_ht = NULL; - - return; -} - -/** - * \brief Converts a string to lowercase. - * - * \param str Pointer to the string to be converted. - */ -static char *SCRConfStringToLowercase(const char *str) -{ - char *new_str = NULL; - char *temp_str = NULL; - - if ((new_str = SCStrdup(str)) == NULL) { - return NULL; - } - - temp_str = new_str; - while (*temp_str != '\0') { - *temp_str = u8_tolower((unsigned char)*temp_str); - temp_str++; - } - - return new_str; -} - -/** - * \brief Parses a line from the reference config file and adds it to Reference - * Config hash table DetectEngineCtx->reference_conf_ht. - * - * \param rawstr Pointer to the string to be parsed. - * \param de_ctx Pointer to the Detection Engine Context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCRConfAddReference(DetectEngineCtx *de_ctx, const char *line) -{ - char system[REFERENCE_SYSTEM_NAME_MAX]; - char url[REFERENCE_CONTENT_NAME_MAX]; - - SCRConfReference *ref_new = NULL; - SCRConfReference *ref_lookup = NULL; - - int ret = 0; - - ret = pcre2_match(de_ctx->reference_conf_regex, (PCRE2_SPTR8)line, strlen(line), 0, 0, - de_ctx->reference_conf_regex_match, NULL); - if (ret < 0) { - SCLogError("Invalid Reference Config in " - "reference.config file"); - goto error; - } - - /* retrieve the reference system */ - size_t copylen = sizeof(system); - ret = pcre2_substring_copy_bynumber( - de_ctx->reference_conf_regex_match, 1, (PCRE2_UCHAR8 *)system, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber() failed"); - goto error; - } - - /* retrieve the reference url */ - copylen = sizeof(url); - ret = pcre2_substring_copy_bynumber( - de_ctx->reference_conf_regex_match, 2, (PCRE2_UCHAR8 *)url, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber() failed"); - goto error; - } - - /* Create a new instance of the parsed Reference string */ - ref_new = SCRConfAllocSCRConfReference(system, url); - if (ref_new == NULL) - goto error; - - /* Check if the Reference is present in the HashTable. In case it's present - * ignore it, as it's a duplicate. If not present, add it to the table */ - ref_lookup = HashTableLookup(de_ctx->reference_conf_ht, ref_new, 0); - if (ref_lookup == NULL) { - if (HashTableAdd(de_ctx->reference_conf_ht, ref_new, 0) < 0) { - SCLogDebug("HashTable Add failed"); - } - } else { - SCLogDebug("Duplicate reference found inside reference.config"); - SCRConfDeAllocSCRConfReference(ref_new); - } - - return 0; - - error: - return -1; -} - -/** - * \brief Checks if a string is a comment or a blank line. - * - * Comments lines are lines of the following format - - * "# This is a comment string" or - * " # This is a comment string". - * - * \param line String that has to be checked. - * - * \retval 1 On the argument string being a comment or blank line. - * \retval 0 Otherwise. - */ -static int SCRConfIsLineBlankOrComment(char *line) -{ - while (*line != '\0') { - /* we have a comment */ - if (*line == '#') - return 1; - - /* this line is neither a comment line, nor a blank line */ - if (!isspace((unsigned char)*line)) - return 0; - - line++; - } - - /* we have a blank line */ - return 1; -} - -/** - * \brief Parses the Reference Config file and updates the - * DetectionEngineCtx->reference_conf_ht with the Reference information. - * - * \param de_ctx Pointer to the Detection Engine Context. - */ -static bool SCRConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) -{ - char line[1024]; - int runmode = RunmodeGetCurrent(); - bool is_conf_test_mode = runmode == RUNMODE_CONF_TEST; - while (fgets(line, sizeof(line), fd) != NULL) { - if (SCRConfIsLineBlankOrComment(line)) - continue; - - if (SCRConfAddReference(de_ctx, line) != 0) { - if (is_conf_test_mode) { - return false; - } - } - } - -#ifdef UNITTESTS - if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) - SCLogInfo("tenant id %d: Added \"%d\" reference types from the reference.config file", - de_ctx->tenant_id, de_ctx->reference_conf_ht->count); - else - SCLogInfo("Added \"%d\" reference types from the reference.config file", - de_ctx->reference_conf_ht->count); -#endif /* UNITTESTS */ - return true; -} - -/** - * \brief Returns a new SCRConfReference instance. The reference string - * is converted into lowercase, before being assigned to the instance. - * - * \param system Pointer to the system. - * \param url Pointer to the reference url. - * - * \retval ref Pointer to the new instance of SCRConfReference. - */ -SCRConfReference *SCRConfAllocSCRConfReference(const char *system, - const char *url) -{ - SCRConfReference *ref = NULL; - - if (system == NULL) { - SCLogError("Invalid arguments. system NULL"); - return NULL; - } - - if ((ref = SCCalloc(1, sizeof(SCRConfReference))) == NULL) { - return NULL; - } - - if ((ref->system = SCRConfStringToLowercase(system)) == NULL) { - SCFree(ref); - return NULL; - } - - if (url != NULL && (ref->url = SCStrdup(url)) == NULL) { - SCFree(ref->system); - SCFree(ref); - return NULL; - } - - return ref; -} - -/** - * \brief Frees a SCRConfReference instance. - * - * \param Pointer to the SCRConfReference instance that has to be freed. - */ -void SCRConfDeAllocSCRConfReference(SCRConfReference *ref) -{ - if (ref != NULL) { - if (ref->system != NULL) - SCFree(ref->system); - - if (ref->url != NULL) - SCFree(ref->url); - - SCFree(ref); - } - - return; -} - -/** - * \brief Hashing function to be used to hash the Reference name. Would be - * supplied as an argument to the HashTableInit function for - * DetectEngineCtx->reference_conf_ht. - * - * \param ht Pointer to the HashTable. - * \param data Pointer to the data to be hashed. In this case, the data - * would be a pointer to a SCRConfReference instance. - * \param datalen Not used by this function. - */ -uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - SCRConfReference *ref = (SCRConfReference *)data; - uint32_t hash = 0; - int i = 0; - - int len = strlen(ref->system); - - for (i = 0; i < len; i++) - hash += u8_tolower((unsigned char)ref->system[i]); - - hash = hash % ht->array_size; - - return hash; -} - -/** - * \brief Used to compare two References that have been stored in the HashTable. - * This function is supplied as an argument to the HashTableInit function - * for DetectionEngineCtx->reference_conf_ct. - * - * \param data1 Pointer to the first SCRConfReference to be compared. - * \param len1 Not used by this function. - * \param data2 Pointer to the second SCRConfReference to be compared. - * \param len2 Not used by this function. - * - * \retval 1 On data1 and data2 being equal. - * \retval 0 On data1 and data2 not being equal. - */ -char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, - void *data2, uint16_t datalen2) -{ - SCRConfReference *ref1 = (SCRConfReference *)data1; - SCRConfReference *ref2 = (SCRConfReference *)data2; - int len1 = 0; - int len2 = 0; - - if (ref1 == NULL || ref2 == NULL) - return 0; - - if (ref1->system == NULL || ref2->system == NULL) - return 0; - - len1 = strlen(ref1->system); - len2 = strlen(ref2->system); - - if (len1 == len2 && memcmp(ref1->system, ref2->system, len1) == 0) { - SCLogDebug("Match found inside Reference-Config hash function"); - return 1; - } - - return 0; -} - -/** - * \brief Used to free the Reference Config Hash Data that was stored in - * DetectEngineCtx->reference_conf_ht Hashtable. - * - * \param data Pointer to the data that has to be freed. - */ -void SCRConfReferenceHashFree(void *data) -{ - SCRConfDeAllocSCRConfReference(data); - - return; -} - -/** - * \brief Loads the Reference info from the reference.config file. - * - * The reference.config file contains references that can be used in - * Signatures. Each line of the file should have the following format - - * config reference: system_name, reference_url. - * - * \param de_ctx Pointer to the Detection Engine Context that should be updated - * with reference information. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx, FILE *fd) -{ - fd = SCRConfInitContextAndLocalResources(de_ctx, fd); - if (fd == NULL) { -#ifdef UNITTESTS - if (RunmodeIsUnittests()) { - return -1; - } -#endif - SCLogError("please check the \"reference-config-file\" " - "option in your suricata.yaml file"); - return -1; - } - - bool rc = SCRConfParseFile(de_ctx, fd); - SCRConfDeInitLocalResources(de_ctx, fd); - - return rc ? 0 : -1; -} - -/** - * \brief Gets the reference config from the corresponding hash table stored - * in the Detection Engine Context's reference conf ht, given the - * reference name. - * - * \param ct_name Pointer to the reference name that has to be looked up. - * \param de_ctx Pointer to the Detection Engine Context. - * - * \retval lookup_rconf_info Pointer to the SCRConfReference instance from - * the hash table on success; NULL on failure. - */ -SCRConfReference *SCRConfGetReference(const char *rconf_name, - DetectEngineCtx *de_ctx) -{ - SCRConfReference *ref_conf = SCRConfAllocSCRConfReference(rconf_name, NULL); - if (ref_conf == NULL) - return NULL; - SCRConfReference *lookup_ref_conf = HashTableLookup(de_ctx->reference_conf_ht, - ref_conf, 0); - - SCRConfDeAllocSCRConfReference(ref_conf); - return lookup_ref_conf; -} - -/*----------------------------------Unittests---------------------------------*/ - - -#ifdef UNITTESTS - -/** - * \brief Creates a dummy reference config, with all valid references, for - * testing purposes. - */ -FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void) -{ - const char *buffer = - "config reference: one http://www.one.com\n" - "config reference: two http://www.two.com\n" - "config reference: three http://www.three.com\n" - "config reference: one http://www.one.com\n" - "config reference: three http://www.three.com\n"; - - FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy reference config, with some valid references and a - * couple of invalid references, for testing purposes. - */ -FILE *SCRConfGenerateInvalidDummyReferenceConfigFD02(void) -{ - const char *buffer = - "config reference: one http://www.one.com\n" - "config_ reference: two http://www.two.com\n" - "config reference_: three http://www.three.com\n" - "config reference: four\n" - "config reference five http://www.five.com\n"; - - FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy reference config, with all invalid references, for - * testing purposes. - */ -FILE *SCRConfGenerateInvalidDummyReferenceConfigFD03(void) -{ - const char *buffer = - "config reference one http://www.one.com\n" - "config_ reference: two http://www.two.com\n" - "config reference_: three http://www.three.com\n" - "config reference: four\n"; - - FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - - return fd; -} - -/** - * \test Check that the reference file is loaded and the detection engine - * content reference_conf_ht loaded with the reference data. - */ -static int SCRConfTest01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 0; - - if (de_ctx == NULL) - return result; - - FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx, fd); - - if (de_ctx->reference_conf_ht == NULL) - goto end; - - result = (de_ctx->reference_conf_ht->count == 3); - if (result == 0) - printf("FAILED: de_ctx->reference_conf_ht->count %u: ", de_ctx->reference_conf_ht->count); - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Check that invalid references present in the reference.config file - * aren't loaded. - */ -static int SCRConfTest02(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 0; - - if (de_ctx == NULL) - return result; - - FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD03(); - SCRConfLoadReferenceConfigFile(de_ctx, fd); - - if (de_ctx->reference_conf_ht == NULL) - goto end; - - result = (de_ctx->reference_conf_ht->count == 0); - - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Check that only valid references are loaded into the hash table from - * the reference.config file. - */ -static int SCRConfTest03(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 0; - - if (de_ctx == NULL) - return result; - - FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD02(); - SCRConfLoadReferenceConfigFile(de_ctx, fd); - - if (de_ctx->reference_conf_ht == NULL) - goto end; - - result = (de_ctx->reference_conf_ht->count == 1); - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Check if the reference info from the reference.config file have - * been loaded into the hash table. - */ -static int SCRConfTest04(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 1; - - if (de_ctx == NULL) - return 0; - - FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx, fd); - - if (de_ctx->reference_conf_ht == NULL) - goto end; - - result = (de_ctx->reference_conf_ht->count == 3); - - result &= (SCRConfGetReference("one", de_ctx) != NULL); - result &= (SCRConfGetReference("two", de_ctx) != NULL); - result &= (SCRConfGetReference("three", de_ctx) != NULL); - result &= (SCRConfGetReference("four", de_ctx) == NULL); - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Check if the reference info from the invalid reference.config file - * have not been loaded into the hash table, and cross verify to check - * that the hash table contains no reference data. - */ -static int SCRConfTest05(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 1; - - if (de_ctx == NULL) - return 0; - - FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD03(); - SCRConfLoadReferenceConfigFile(de_ctx, fd); - - if (de_ctx->reference_conf_ht == NULL) - goto end; - - result = (de_ctx->reference_conf_ht->count == 0); - - result &= (SCRConfGetReference("one", de_ctx) == NULL); - result &= (SCRConfGetReference("two", de_ctx) == NULL); - result &= (SCRConfGetReference("three", de_ctx) == NULL); - result &= (SCRConfGetReference("four", de_ctx) == NULL); - result &= (SCRConfGetReference("five", de_ctx) == NULL); - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Check if the reference info from the reference.config file have - * been loaded into the hash table. - */ -static int SCRConfTest06(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - int result = 1; - - if (de_ctx == NULL) - return 0; - - FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD02(); - SCRConfLoadReferenceConfigFile(de_ctx, fd); - - if (de_ctx->reference_conf_ht == NULL) - goto end; - - result = (de_ctx->reference_conf_ht->count == 1); - - result &= (SCRConfGetReference("one", de_ctx) != NULL); - result &= (SCRConfGetReference("two", de_ctx) == NULL); - result &= (SCRConfGetReference("three", de_ctx) == NULL); - result &= (SCRConfGetReference("four", de_ctx) == NULL); - result &= (SCRConfGetReference("five", de_ctx) == NULL); - - end: - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -#endif /* UNITTESTS */ - -/** - * \brief This function registers unit tests for Reference Config API. - */ -void SCRConfRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("SCRConfTest01", SCRConfTest01); - UtRegisterTest("SCRConfTest02", SCRConfTest02); - UtRegisterTest("SCRConfTest03", SCRConfTest03); - UtRegisterTest("SCRConfTest04", SCRConfTest04); - UtRegisterTest("SCRConfTest05", SCRConfTest05); - UtRegisterTest("SCRConfTest06", SCRConfTest06); -#endif /* UNITTESTS */ - - return; -} diff --git a/src/util-reference-config.h b/src/util-reference-config.h deleted file mode 100644 index 5334fd7c42c1..000000000000 --- a/src/util-reference-config.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_REFERENCE_CONFIG_H__ -#define __UTIL_REFERENCE_CONFIG_H__ - -#include "detect.h" - -#define REFERENCE_SYSTEM_NAME_MAX 64 -#define REFERENCE_CONTENT_NAME_MAX 1024 - -/** - * \brief Holds a reference from the file - reference.config. - */ -typedef struct SCRConfReference_ { - /* The system name. This is the primary key for a reference. */ - char *system; - /* The url for the above reference */ - char *url; -} SCRConfReference; - -SCRConfReference *SCRConfAllocSCRConfReference(const char *, const char *); -void SCRConfDeAllocSCRConfReference(SCRConfReference *); -int SCRConfLoadReferenceConfigFile(DetectEngineCtx *, FILE *); -void SCRConfDeInitContext(DetectEngineCtx *); -SCRConfReference *SCRConfGetReference(const char *, - DetectEngineCtx *); -int SCRConfAddReference(DetectEngineCtx *de_ctx, const char *line); -void SCRConfRegisterTests(void); - -/* these below functions are only used by unittests */ -FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void); -FILE *SCRConfGenerateInvalidDummyReferenceConfigFD02(void); -FILE *SCRConfGenerateInvalidDummyReferenceConfigFD03(void); - -void SCReferenceConfInit(DetectEngineCtx *de_ctx); -void SCReferenceConfDeinit(DetectEngineCtx *de_ctx); - -#endif /* __UTIL_REFERENCE_CONFIG_H__ */ diff --git a/src/util-rohash.c b/src/util-rohash.c deleted file mode 100644 index 53437430291b..000000000000 --- a/src/util-rohash.c +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Chained read only hash table implementation, meaning that - * after the initial fill no changes are allowed. - * - * Loading takes 2 stages. - * - stage1 maps data - * - stage2 fills blob - * - * \todo a bloomfilter in the ROHashTableOffsets could possibly prevent - * a lot of cache misses when validating a potential match - * - * \todo maybe add a user ctx to be returned instead, something like a - * 4/8 byte ptr or simply a flag - */ - -#include "suricata-common.h" -#include "util-hash.h" -#include "util-unittest.h" -#include "util-memcmp.h" -#include "util-hash-lookup3.h" -#include "util-rohash.h" -#include "util-debug.h" - -/** item_size data beyond this header */ -typedef struct ROHashTableItem_ { - uint32_t pos; /**< position relative to other values with same hash */ - TAILQ_ENTRY(ROHashTableItem_) next; -} ROHashTableItem; - -/** offset table */ -typedef struct ROHashTableOffsets_ { - uint32_t cnt; /**< number of items for this hash */ - uint32_t offset; /**< position in the blob of the first item */ -} ROHashTableOffsets; - -/** \brief initialize a new rohash - * - * \param hash_bits hash size as 2^hash_bits, so power of 2, max 31 - * \param item_size size of the data to store - * - * \retval table ptr or NULL on error - */ -ROHashTable *ROHashInit(uint8_t hash_bits, uint16_t item_size) -{ - if (item_size % 4 != 0 || item_size == 0) { - SCLogError("data size must be multiple of 4"); - return NULL; - } - if (hash_bits < 4 || hash_bits > 31) { - SCLogError("invalid hash_bits setting, valid range is 4-31"); - return NULL; - } - - uint32_t size = hashsize(hash_bits) * sizeof(ROHashTableOffsets); - - ROHashTable *table = SCCalloc(1, sizeof(ROHashTable) + size); - if (unlikely(table == NULL)) { - SCLogError("failed to alloc memory"); - return NULL; - } - - table->items = 0; - table->item_size = item_size; - table->hash_bits = hash_bits; - TAILQ_INIT(&table->head); - - return table; -} - -void ROHashFree(ROHashTable *table) -{ - if (table != NULL) { - if (table->data != NULL) { - SCFree(table->data); - } - - SCFree(table); - } -} - -uint32_t ROHashMemorySize(ROHashTable *table) -{ - uint32_t r1 = hashsize(table->hash_bits) * sizeof(ROHashTableOffsets); - uint32_t r2 = table->items * table->item_size; - return (uint32_t)(r1 + r2 + sizeof(ROHashTable)); -} - -/** - * \retval NULL not found - * \retval ptr found - */ -void *ROHashLookup(ROHashTable *table, void *data, uint16_t size) -{ - if (data == NULL || size != table->item_size) { - SCReturnPtr(NULL, "void"); - } - - uint32_t hash = hashword(data, table->item_size/4, 0) & hashmask(table->hash_bits); - - /* get offsets start */ - ROHashTableOffsets *os = (void *)table + sizeof(ROHashTable); - ROHashTableOffsets *o = &os[hash]; - - /* no matches */ - if (o->cnt == 0) { - SCReturnPtr(NULL, "void"); - } - - uint32_t u; - for (u = 0; u < o->cnt; u++) { - uint32_t offset = (o->offset + u) * table->item_size; - - if (SCMemcmp(table->data + offset, data, table->item_size) == 0) { - SCReturnPtr(table->data + offset, "void"); - } - } - SCReturnPtr(NULL, "void"); -} - -/** \brief Add a new value to the hash - * - * \note can only be done when table isn't in a locked state yet - * - * \param table the hash table - * \param value value to add - * \param size value size. *MUST* match table item_size - * - * \retval 0 error - * \retval 1 ok - */ -int ROHashInitQueueValue(ROHashTable *table, void *value, uint16_t size) -{ - if (table->locked) { - SCLogError("can't add value to locked table"); - return 0; - } - if (table->item_size != size) { - SCLogError("wrong size for data %u != %u", size, table->item_size); - return 0; - } - - ROHashTableItem *item = SCCalloc(1, sizeof(ROHashTableItem) + table->item_size); - if (item != NULL) { - memcpy((void *)item + sizeof(ROHashTableItem), value, table->item_size); - TAILQ_INSERT_TAIL(&table->head, item, next); - return 1; - } - - return 0; -} - -/** \brief create final hash data structure - * - * \param table the hash table - * - * \retval 0 error - * \retval 1 ok - * - * \note after this call the nothing can be added to the hash anymore. - */ -int ROHashInitFinalize(ROHashTable *table) -{ - if (table->locked) { - SCLogError("table already locked"); - return 0; - } - - ROHashTableItem *item = NULL; - ROHashTableOffsets *os = (void *)table + sizeof(ROHashTable); - - /* count items per hash value */ - TAILQ_FOREACH(item, &table->head, next) { - uint32_t hash = hashword((void *)item + sizeof(*item), table->item_size/4, 0) & hashmask(table->hash_bits); - ROHashTableOffsets *o = &os[hash]; - - item->pos = o->cnt; - o->cnt++; - table->items++; - } - - if (table->items == 0) { - SCLogError("no items"); - return 0; - } - - /* get the data block */ - uint32_t newsize = table->items * table->item_size; - table->data = SCCalloc(1, newsize); - if (table->data == NULL) { - SCLogError("failed to alloc memory"); - return 0; - } - - /* calc offsets into the block per hash value */ - uint32_t total = 0; - uint32_t x; - for (x = 0; x < hashsize(table->hash_bits); x++) { - ROHashTableOffsets *o = &os[x]; - - if (o->cnt == 0) - continue; - - o->offset = total; - total += o->cnt; - } - - /* copy each value into the data block */ - TAILQ_FOREACH(item, &table->head, next) { - uint32_t hash = hashword((void *)item + sizeof(*item), table->item_size/4, 0) & hashmask(table->hash_bits); - - ROHashTableOffsets *o = &os[hash]; - uint32_t offset = (o->offset + item->pos) * table->item_size; - - memcpy(table->data + offset, (void *)item + sizeof(*item), table->item_size); - - } - - /* clean up temp items */ - while ((item = TAILQ_FIRST(&table->head))) { - TAILQ_REMOVE(&table->head, item, next); - SCFree(item); - } - - table->locked = 1; - return 1; -} diff --git a/src/util-rohash.h b/src/util-rohash.h deleted file mode 100644 index 3b044274a54b..000000000000 --- a/src/util-rohash.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_ROHASH_H__ -#define __UTIL_ROHASH_H__ - - -typedef struct ROHashTable_ { - uint8_t locked; - uint8_t hash_bits; - uint16_t item_size; - uint32_t items; - void *data; - TAILQ_HEAD(, ROHashTableItem_) head; -} ROHashTable; - -/* init time */ -ROHashTable *ROHashInit(uint8_t hash_bits, uint16_t item_size); -int ROHashInitFinalize(ROHashTable *table); -void ROHashFree(ROHashTable *table); -int ROHashInitQueueValue(ROHashTable *table, void *value, uint16_t size); -uint32_t ROHashMemorySize(ROHashTable *table); - -/* run time */ -void *ROHashLookup(ROHashTable *table, void *data, uint16_t size); - -#endif /* __UTIL_ROHASH_H__ */ diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c deleted file mode 100644 index e526035d030a..000000000000 --- a/src/util-rule-vars.c +++ /dev/null @@ -1,412 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Rule variable utility functions - */ - -#include "suricata-common.h" -#include "conf.h" -#include "conf-yaml-loader.h" - -#include "detect.h" -#include "detect-content.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" - -#include "util-rule-vars.h" -#include "util-enum.h" -#include "util-debug.h" -#include "util-unittest.h" - -/** An enum-string map, that maps the different vars type in the yaml conf - * type with the mapping path in the yaml conf file */ -SCEnumCharMap sc_rule_vars_type_map[ ] = { - { "vars.address-groups", SC_RULE_VARS_ADDRESS_GROUPS }, - { "vars.port-groups", SC_RULE_VARS_PORT_GROUPS } -}; - -/** - * \internal - * \brief Retrieves a value for a yaml mapping. The sequence from the yaml - * conf file, from which the conf value has to be retrieved can be - * specified by supplying a SCRuleVarsType enum. The string mapping - * for each of the SCRuleVarsType is present in sc_rule_vars_type_map. - * - * \param conf_var_name Pointer to a character string containing the conf var - * name, whose value has to be retrieved from the yaml - * conf file. - * \param conf_vars_type Holds an enum value that indicates the kind of yaml - * mapping that has to be retrieved. Can be one of the - * values in SCRuleVarsType. - * - * \retval conf_var_name_value Pointer to the string containing the conf value - * on success; NULL on failure. - */ -const char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, - const char *conf_var_name, - SCRuleVarsType conf_vars_type) -{ - SCEnter(); - - const char *conf_var_type_name = NULL; - char conf_var_full_name[2048]; - const char *conf_var_full_name_value = NULL; - - if (conf_var_name == NULL) - goto end; - - while (conf_var_name[0] != '\0' && isspace((unsigned char)conf_var_name[0])) { - conf_var_name++; - } - - (conf_var_name[0] == '$') ? conf_var_name++ : conf_var_name; - conf_var_type_name = SCMapEnumValueToName(conf_vars_type, - sc_rule_vars_type_map); - if (conf_var_type_name == NULL) - goto end; - - if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { - if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s.%s", - de_ctx->config_prefix, conf_var_type_name, conf_var_name) < 0) { - goto end; - } - } else { - if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s", - conf_var_type_name, conf_var_name) < 0) { - goto end; - } - } - - if (ConfGet(conf_var_full_name, &conf_var_full_name_value) != 1) { - SCLogError("Variable \"%s\" is not defined in " - "configuration file", - conf_var_name); - goto end; - } - - SCLogDebug("Value obtained from the yaml conf file, for the var " - "\"%s\" is \"%s\"", conf_var_name, conf_var_full_name_value); - - end: - SCReturnCharPtr(conf_var_full_name_value); -} - - -/**********************************Unittests***********************************/ -#ifdef UNITTESTS - -static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "default-log-dir: /var/log/suricata\n" - "\n" - "logging:\n" - "\n" - " default-log-level: debug\n" - "\n" - " default-format: \"<%t> - <%l>\"\n" - "\n" - " default-startup-message: Your IDS has started.\n" - "\n" - " default-output-filter:\n" - "\n" - " output:\n" - "\n" - " - interface: console\n" - " log-level: info\n" - "\n" - " - interface: file\n" - " filename: /var/log/suricata.log\n" - "\n" - " - interface: syslog\n" - " facility: local5\n" - " format: \"%l\"\n" - "\n" - "pfring:\n" - "\n" - " interface: eth0\n" - "\n" - " clusterid: 99\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" - "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" - "\n" - " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" - "\n" - " HTTP_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " SMTP_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " SQL_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " DNS_SERVERS: any\n" - "\n" - " TELNET_SERVERS: any\n" - "\n" - " AIM_SERVERS: any\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"80:81,88\"\n" - "\n" - " SHELLCODE_PORTS: 80\n" - "\n" - " ORACLE_PORTS: 1521\n" - "\n" - " SSH_PORTS: 22\n" - "\n"; - -/** - * \test Check that valid address and port group vars are correctly retrieved - * from the configuration. - */ -static int SCRuleVarsPositiveTest01(void) -{ - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); - - /* check for address-groups */ - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), - "[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:13c5:" - "5AFE::/64,2001:888:13c5:CAFE::/64]") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS), - "[!192.168.0.0/16,2000::/3]") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), - "!192.168.0.0/16") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), - "!192.168.0.0/16") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), - "!192.168.0.0/16") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), - "any") == 0); - FAIL_IF_NOT( - SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), - "any") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), - "any") == 0); - - /* Test that a leading space is stripped. */ - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), - "any") == 0); - - /* check for port-groups */ - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), - "80:81,88") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS), - "80") == 0); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS), - "1521") == 0); - FAIL_IF_NOT( - SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), "22") == 0); - - ConfDeInit(); - ConfRestoreContextBackup(); - PASS; -} - -/** - * \test Check that invalid address and port groups are properly handled by the - * API. - */ -static int SCRuleVarsNegativeTest02(void) -{ - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); - - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL); - FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL); - - ConfDeInit(); - ConfRestoreContextBackup(); - PASS; -} - -/** - * \test Check that Signatures with valid address and port groups are parsed - * without any errors by the Signature parsing API. - */ -static int SCRuleVarsPositiveTest03(void) -{ - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp [$HTTP_SERVERS,$HOME_NET,192.168.2.5] $HTTP_PORTS -> $EXTERNAL_NET " - "[80,[!$HTTP_PORTS,$ORACLE_PORTS]] (msg:\"Rule Vars Test\"; sid:1;)"); - FAIL_IF_NULL(s); - - ConfDeInit(); - ConfRestoreContextBackup(); - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check that Signatures with invalid address and port groups, are - * are invalidated by the Signature parsing API. - */ -static int SCRuleVarsNegativeTest04(void) -{ - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *s = DetectEngineAppendSig( - de_ctx, "alert tcp $HTTP_SERVER any -> any any (msg:\"Rule Vars Test\"; sid:1;)"); - FAIL_IF_NOT_NULL(s); - s = DetectEngineAppendSig( - de_ctx, "alert tcp $http_servers any -> any any (msg:\"Rule Vars Test\"; sid:1;)"); - FAIL_IF_NOT_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert tcp $http_servers any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); - FAIL_IF_NOT_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert tcp !$TELNET_SERVERS !80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); - FAIL_IF_NOT_NULL(s); - - DetectEngineCtxFree(de_ctx); - ConfDeInit(); - ConfRestoreContextBackup(); - PASS; -} - -static const char *dummy_mt_conf_string = - "%YAML 1.1\n" - "---\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"[1.2.3.4]\"\n" - " port-groups:\n" - " HTTP_PORTS: \"12345\"\n" - "multi-detect:\n" - " 0:\n" - " vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"[8.8.8.8]\"\n" - " port-groups:\n" - " HTTP_PORTS: \"54321\"\n" - "\n"; - -/** - * \test Check that valid address and port group vars are correctly retrieved - * from the configuration. - */ -static int SCRuleVarsMTest01(void) -{ - int result = 0; - DetectEngineCtx *de_ctx = NULL; - - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_mt_conf_string, strlen(dummy_mt_conf_string)); - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - return 0; - de_ctx->flags |= DE_QUIET; - snprintf(de_ctx->config_prefix, sizeof(de_ctx->config_prefix), - "multi-detect.0"); - - /* check for address-groups */ - result = (SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), - "[8.8.8.8]") == 0); - if (result == 0) - goto end; - - result = (SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), - "[1.2.3.4]") == 0); - if (result == 0) - goto end; - - /* check for port-groups */ - result = (SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), - "54321") == 0); - if (result == 0) - goto end; - - result = (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), - "12345") == 0); - if (result == 0) - goto end; - -end: - ConfDeInit(); - ConfRestoreContextBackup(); - - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -#endif /* UNITTESTS */ - -void SCRuleVarsRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01); - UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02); - UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03); - UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04); - - UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01); -#endif - - return; -} diff --git a/src/util-rule-vars.h b/src/util-rule-vars.h deleted file mode 100644 index a5be2fa3a3db..000000000000 --- a/src/util-rule-vars.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#ifndef __UTIL_RULE_VARS_H__ -#define __UTIL_RULE_VARS_H__ - -#include "detect.h" - -/** Enum indicating the various vars type in the yaml conf file */ -typedef enum { - SC_RULE_VARS_ADDRESS_GROUPS, - SC_RULE_VARS_PORT_GROUPS, -} SCRuleVarsType; - -const char *SCRuleVarsGetConfVar(const DetectEngineCtx *, const char *, SCRuleVarsType); -void SCRuleVarsRegisterTests(void); - -#endif /* __UTIL_RULE_VARS_H__ */ diff --git a/src/util-runmodes.c b/src/util-runmodes.c deleted file mode 100644 index f78e857abfc6..000000000000 --- a/src/util-runmodes.c +++ /dev/null @@ -1,573 +0,0 @@ -/* Copyright (C) 2011-2019 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Eric Leblond - * - * Helper function for runmode. - * - */ - -#include "suricata-common.h" -#include "tm-threads.h" -#include "conf.h" -#include "runmodes.h" -#include "runmode-af-packet.h" -#include "output.h" -#include "log-httplog.h" - -#include "detect-engine.h" -#include "detect-engine-mpm.h" - -#include "alert-fastlog.h" -#include "alert-debuglog.h" - -#include "util-debug.h" -#include "util-time.h" -#include "util-cpu.h" -#include "util-affinity.h" -#include "util-device.h" - -#include "util-runmodes.h" - -#include "flow-hash.h" - -/** \brief create a queue string for autofp to pass to - * the flow queue handler. - * - * The string will be "pickup1,pickup2,pickup3\0" - */ -char *RunmodeAutoFpCreatePickupQueuesString(int n) -{ - if (n > 1024) - return NULL; - - /* 13 because pickup12345, = 12 + \0 */ - size_t queues_size = n * 13; - char qname[TM_QUEUE_NAME_MAX]; - - char *queues = SCCalloc(1, queues_size); - if (unlikely(queues == NULL)) { - SCLogError("failed to alloc queues buffer: %s", strerror(errno)); - return NULL; - } - - for (int thread = 0; thread < n; thread++) { - if (strlen(queues) > 0) - strlcat(queues, ",", queues_size); - - snprintf(qname, sizeof(qname), "pickup%d", (int16_t)thread+1); - strlcat(queues, qname, queues_size); - } - - SCLogDebug("%d %"PRIuMAX", queues %s", n, (uintmax_t)queues_size, queues); - return queues; -} - -/** - */ -int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, - ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, const char *live_dev) -{ - char tname[TM_THREAD_NAME_MAX]; - char qname[TM_QUEUE_NAME_MAX]; - - /* Available cpus */ - int nlive = LiveGetDeviceCount(); - uint16_t thread_max = TmThreadsGetWorkerThreadMax(); - - char *queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); - if (queues == NULL) { - FatalError("RunmodeAutoFpCreatePickupQueuesString failed"); - } - - if ((nlive <= 1) && (live_dev != NULL)) { - SCLogDebug("live_dev %s", live_dev); - - void *aconf = ConfigParser(live_dev); - if (aconf == NULL) { - FatalError("Failed to allocate config for %s", live_dev); - } - - int threads_count = ModThreadsCount(aconf); - SCLogInfo("Going to use %" PRId32 " %s receive thread(s)", - threads_count, recv_mod_name); - - /* create the threads */ - for (int thread = 0; thread < threads_count; thread++) { - snprintf(tname, sizeof(tname), "%s#%02d", thread_name, thread+1); - ThreadVars *tv_receive = - TmThreadCreatePacketHandler(tname, - "packetpool", "packetpool", - queues, "flow", "pktacqloop"); - if (tv_receive == NULL) { - FatalError("TmThreadsCreate failed"); - } - TmModule *tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName failed for %s", recv_mod_name); - } - TmSlotSetFuncAppend(tv_receive, tm_module, aconf); - - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName %s failed", decode_mod_name); - } - TmSlotSetFuncAppend(tv_receive, tm_module, NULL); - - TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - } - } else { /* Multiple input device */ - SCLogInfo("Using %d live device(s).", nlive); - - for (int lthread = 0; lthread < nlive; lthread++) { - const char *dev = LiveGetDeviceName(lthread); - const char *visual_devname = LiveGetShortName(dev); - - if (dev == NULL) { - FatalError("Failed to lookup live dev %d", lthread); - } - SCLogDebug("dev %s", dev); - - void *aconf = ConfigParser(dev); - if (aconf == NULL) { - FatalError("Multidev: Failed to allocate config for %s (%d)", dev, lthread); - } - - int threads_count = ModThreadsCount(aconf); - for (int thread = 0; thread < threads_count; thread++) { - char *printable_threadname = SCMalloc(sizeof(char) * (strlen(thread_name)+5+strlen(dev))); - if (unlikely(printable_threadname == NULL)) { - FatalError("failed to alloc printable thread name: %s", strerror(errno)); - } - snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, - thread+1, visual_devname); - snprintf(printable_threadname, strlen(thread_name)+5+strlen(dev), - "%s#%02d-%s", thread_name, thread+1, - dev); - - ThreadVars *tv_receive = - TmThreadCreatePacketHandler(tname, - "packetpool", "packetpool", - queues, "flow", "pktacqloop"); - if (tv_receive == NULL) { - FatalError("TmThreadsCreate failed"); - } - tv_receive->printable_name = printable_threadname; - TmModule *tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName failed for %s", recv_mod_name); - } - TmSlotSetFuncAppend(tv_receive, tm_module, aconf); - - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName %s failed", decode_mod_name); - } - TmSlotSetFuncAppend(tv_receive, tm_module, NULL); - - TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - } - } - } - - for (uint16_t thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "%s#%02u", thread_name_workers, (uint16_t)(thread + 1)); - snprintf(qname, sizeof(qname), "pickup%u", (uint16_t)(thread + 1)); - - SCLogDebug("tname %s, qname %s", tname, qname); - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(tname, - qname, "flow", - "packetpool", "packetpool", - "varslot"); - if (tv_detect_ncpu == NULL) { - FatalError("TmThreadsCreate failed"); - } - TmModule *tm_module = TmModuleGetByName("FlowWorker"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName for FlowWorker failed"); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - - TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); - - TmThreadSetGroupName(tv_detect_ncpu, "Detect"); - - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName RespondReject failed"); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - } - - SCFree(queues); - return 0; -} - -/** - */ -static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc ModThreadsCount, - const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, - const char *live_dev, void *aconf, - unsigned char single_mode) -{ - int threads_count; - uint16_t thread_max = TmThreadsGetWorkerThreadMax(); - - if (single_mode) { - threads_count = 1; - } else { - threads_count = MIN(ModThreadsCount(aconf), thread_max); - SCLogInfo("%s: creating %" PRId32 " thread%s", live_dev, threads_count, - threads_count > 1 ? "s" : ""); - } - - /* create the threads */ - for (int thread = 0; thread < threads_count; thread++) { - char tname[TM_THREAD_NAME_MAX]; - TmModule *tm_module = NULL; - const char *visual_devname = LiveGetShortName(live_dev); - char *printable_threadname = SCMalloc(sizeof(char) * (strlen(thread_name)+5+strlen(live_dev))); - if (unlikely(printable_threadname == NULL)) { - FatalError("failed to alloc printable thread name: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - if (single_mode) { - snprintf(tname, sizeof(tname), "%s#01-%s", thread_name, visual_devname); - snprintf(printable_threadname, strlen(thread_name)+5+strlen(live_dev), "%s#01-%s", - thread_name, live_dev); - } else { - snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, - thread+1, visual_devname); - snprintf(printable_threadname, strlen(thread_name)+5+strlen(live_dev), "%s#%02d-%s", - thread_name, thread+1, live_dev); - } - ThreadVars *tv = TmThreadCreatePacketHandler(tname, - "packetpool", "packetpool", - "packetpool", "packetpool", - "pktacqloop"); - if (tv == NULL) { - FatalError("TmThreadsCreate failed"); - } - tv->printable_name = printable_threadname; - - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName failed for %s", recv_mod_name); - } - TmSlotSetFuncAppend(tv, tm_module, aconf); - - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName %s failed", decode_mod_name); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - - tm_module = TmModuleGetByName("FlowWorker"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName for FlowWorker failed"); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName RespondReject failed"); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - - TmThreadSetCPU(tv, WORKER_CPU_SET); - - if (TmThreadSpawn(tv) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - } - - return 0; -} - -int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, - ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, const char *live_dev) -{ - int nlive = LiveGetDeviceCount(); - void *aconf; - int ldev; - - for (ldev = 0; ldev < nlive; ldev++) { - const char *live_dev_c = NULL; - if ((nlive <= 1) && (live_dev != NULL)) { - aconf = ConfigParser(live_dev); - live_dev_c = live_dev; - } else { - live_dev_c = LiveGetDeviceName(ldev); - aconf = ConfigParser(live_dev_c); - } - RunModeSetLiveCaptureWorkersForDevice(ModThreadsCount, - recv_mod_name, - decode_mod_name, - thread_name, - live_dev_c, - aconf, - 0); - } - - return 0; -} - -int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, - ConfigIfaceThreadsCountFunc ModThreadsCount, - const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, - const char *live_dev) -{ - int nlive = LiveGetDeviceCount(); - const char *live_dev_c = NULL; - void *aconf; - - if (nlive > 1) { - FatalError("Can't use the 'single' runmode with multiple devices"); - } - - if (live_dev != NULL) { - aconf = ConfigParser(live_dev); - live_dev_c = live_dev; - } else { - live_dev_c = LiveGetDeviceName(0); - aconf = ConfigParser(live_dev_c); - } - - return RunModeSetLiveCaptureWorkersForDevice( - ModThreadsCount, - recv_mod_name, - decode_mod_name, - thread_name, - live_dev_c, - aconf, - 1); -} - - -/** - */ -int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, - const char *recv_mod_name, - const char *verdict_mod_name, - const char *decode_mod_name) -{ - SCEnter(); - char tname[TM_THREAD_NAME_MAX]; - TmModule *tm_module ; - - /* Available cpus */ - const int nqueue = LiveGetDeviceCount(); - - uint16_t thread_max = TmThreadsGetWorkerThreadMax(); - - char *queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); - if (queues == NULL) { - FatalError("RunmodeAutoFpCreatePickupQueuesString failed"); - } - - /* create the threads */ - for (int i = 0; i < nqueue; i++) { - const char *cur_queue = LiveGetDeviceName(i); - if (cur_queue == NULL) { - FatalError("invalid queue number"); - } - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "%s-%s", thread_name_autofp, cur_queue); - - ThreadVars *tv_receive = - TmThreadCreatePacketHandler(tname, - "packetpool", "packetpool", - queues, "flow", "pktacqloop"); - if (tv_receive == NULL) { - FatalError("TmThreadsCreate failed"); - } - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName failed for %s", recv_mod_name); - } - TmSlotSetFuncAppend(tv_receive, tm_module, (void *) ConfigParser(i)); - - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName %s failed", decode_mod_name); - } - TmSlotSetFuncAppend(tv_receive, tm_module, NULL); - - TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - - } - for (int thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "%s#%02u", thread_name_workers, (uint16_t)(thread + 1)); - char qname[TM_QUEUE_NAME_MAX]; - snprintf(qname, sizeof(qname), "pickup%u", (uint16_t)(thread + 1)); - - SCLogDebug("tname %s, qname %s", tname, qname); - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(tname, - qname, "flow", - "verdict-queue", "simple", - "varslot"); - if (tv_detect_ncpu == NULL) { - FatalError("TmThreadsCreate failed"); - } - - tm_module = TmModuleGetByName("FlowWorker"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName for FlowWorker failed"); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - - TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); - - TmThreadSetGroupName(tv_detect_ncpu, "Detect"); - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - } - - /* create the threads */ - for (int i = 0; i < nqueue; i++) { - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "%s#%02d", thread_name_verdict, i); - - ThreadVars *tv_verdict = - TmThreadCreatePacketHandler(tname, - "verdict-queue", "simple", - "packetpool", "packetpool", - "varslot"); - if (tv_verdict == NULL) { - FatalError("TmThreadsCreate failed"); - } - tm_module = TmModuleGetByName(verdict_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName %s failed", verdict_mod_name); - } - TmSlotSetFuncAppend(tv_verdict, tm_module, (void *)ConfigParser(i)); - - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName for RespondReject failed"); - } - TmSlotSetFuncAppend(tv_verdict, tm_module, NULL); - - TmThreadSetCPU(tv_verdict, VERDICT_CPU_SET); - - if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - } - - SCFree(queues); - return 0; -} - -/** - */ -int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, - const char *recv_mod_name, - const char *verdict_mod_name, - const char *decode_mod_name) -{ - TmModule *tm_module = NULL; - const int nqueue = LiveGetDeviceCount(); - - for (int i = 0; i < nqueue; i++) { - /* create the threads */ - const char *cur_queue = LiveGetDeviceName(i); - if (cur_queue == NULL) { - FatalError("invalid queue number"); - } - - char tname[TM_THREAD_NAME_MAX]; - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "%s-%s", thread_name_workers, cur_queue); - - ThreadVars *tv = TmThreadCreatePacketHandler(tname, - "packetpool", "packetpool", - "packetpool", "packetpool", - "pktacqloop"); - if (tv == NULL) { - FatalError("TmThreadsCreate failed"); - } - - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName failed for %s", recv_mod_name); - } - TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i)); - - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName %s failed", decode_mod_name); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - - tm_module = TmModuleGetByName("FlowWorker"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName for FlowWorker failed"); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - - tm_module = TmModuleGetByName(verdict_mod_name); - if (tm_module == NULL) { - FatalError("TmModuleGetByName %s failed", verdict_mod_name); - } - TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i)); - - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - FatalError("TmModuleGetByName for RespondReject failed"); - } - TmSlotSetFuncAppend(tv, tm_module, NULL); - - TmThreadSetCPU(tv, WORKER_CPU_SET); - - if (TmThreadSpawn(tv) != TM_ECODE_OK) { - FatalError("TmThreadSpawn failed"); - } - } - - return 0; -} diff --git a/src/util-runmodes.h b/src/util-runmodes.h deleted file mode 100644 index 419f9f95112d..000000000000 --- a/src/util-runmodes.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (C) 2011 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Eric Leblond - */ - -#ifndef __UTIL_RUNMODES_H__ -#define __UTIL_RUNMODES_H__ - -typedef void *(*ConfigIfaceParserFunc) (const char *); -typedef void *(*ConfigIPSParserFunc) (int); -typedef int (*ConfigIfaceThreadsCountFunc) (void *); - -int RunModeSetLiveCaptureAuto(ConfigIfaceParserFunc configparser, - ConfigIfaceThreadsCountFunc ModThreadsCount, - const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, - const char *live_dev); - -int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc configparser, - ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, const char *live_dev); - -int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc configparser, - ConfigIfaceThreadsCountFunc ModThreadsCount, - const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, - const char *live_dev); - -int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc configparser, - ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, - const char *decode_mod_name, const char *thread_name, const char *live_dev); - -int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, - const char *recv_mod_name, - const char *verdict_mod_name, - const char *decode_mod_name); - -int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, - const char *recv_mod_name, - const char *verdict_mod_name, - const char *decode_mod_name); - -char *RunmodeAutoFpCreatePickupQueuesString(int n); - -#endif /* __UTIL_RUNMODES_H__ */ diff --git a/src/util-running-modes.c b/src/util-running-modes.c deleted file mode 100644 index dd50c85ab420..000000000000 --- a/src/util-running-modes.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Eric Leblond - */ - -#include "suricata-common.h" -#include "app-layer-detect-proto.h" -#include "app-layer.h" -#include "app-layer-parser.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "conf-yaml-loader.h" -#include "util-running-modes.h" - -int ListKeywords(const char *keyword_info) -{ - EngineModeSetIDS(); - SCLogLoadConfig(0, 0, 0, 0); - MpmTableSetup(); - SpmTableSetup(); - AppLayerSetup(); - SigTableSetup(); /* load the rule keywords */ - return SigTableList(keyword_info); -} - -int ListAppLayerProtocols(const char *conf_filename) -{ - EngineModeSetIDS(); - if (ConfYamlLoadFile(conf_filename) != -1) - SCLogLoadConfig(0, 0, 0, 0); - MpmTableSetup(); - SpmTableSetup(); - AppLayerSetup(); - AppLayerListSupportedProtocols(); - - return TM_ECODE_DONE; -} - diff --git a/src/util-signal.c b/src/util-signal.c deleted file mode 100644 index 9e3ec0cdf812..000000000000 --- a/src/util-signal.c +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-debug.h" -#include "util-signal.h" - -int UtilSignalBlock(int signum) -{ -#ifndef OS_WIN32 - sigset_t x; - if (sigemptyset(&x) < 0) - return -1; - if (sigaddset(&x, signum) < 0) - return -1; - /* don't use sigprocmask(), as it's undefined for - * multithreaded programs. Use phtread_sigmask(). - */ - if (pthread_sigmask(SIG_BLOCK, &x, NULL) != 0) - return -1; -#endif - return 0; -} - -int UtilSignalUnblock(int signum) -{ -#ifndef OS_WIN32 - sigset_t x; - if (sigemptyset(&x) < 0) - return -1; - if (sigaddset(&x, signum) < 0) - return -1; - if (pthread_sigmask(SIG_UNBLOCK, &x, NULL) != 0) - return -1; -#endif - return 0; -} - -void UtilSignalHandlerSetup(int sig, void (*handler)(int)) -{ -#ifdef OS_WIN32 - signal(sig, handler); -#else - struct sigaction action; - memset(&action, 0x00, sizeof(struct sigaction)); - - action.sa_handler = handler; - sigemptyset(&(action.sa_mask)); - sigaddset(&(action.sa_mask),sig); - action.sa_flags = 0; - sigaction(sig, &action, 0); -#endif /* OS_WIN32 */ - - return; -} - -#if 0 -int UtilSignalIsHandler(int sig, void (*handler)(int)) -{ - struct sigaction action; - memset(&action, 0x00, sizeof(struct sigaction)); - - sigaction(sig, NULL, &action); - - return (action.sa_handler == handler); -} -#endif diff --git a/src/util-spm-bm.c b/src/util-spm-bm.c deleted file mode 100644 index 449c6b62962e..000000000000 --- a/src/util-spm-bm.c +++ /dev/null @@ -1,509 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * - * Boyer Moore simple pattern matcher implementation - * - * Boyer Moore algorithm has a really good performance. It need two arrays - * of context for each pattern that hold applicable shifts on the text - * to search in, based on characters not available in the pattern - * and combinations of characters that start a suffix of the pattern. - * If possible, we should store the context of patterns that we are going - * to search for multiple times, so we don't spend time on rebuilding them. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "util-spm-bm.h" -#include "util-spm.h" -#include "util-debug.h" -#include "util-error.h" -#include "util-memcpy.h" -#include "util-validate.h" - -static int PreBmGs(const uint8_t *x, uint16_t m, uint16_t *bmGs); -static void PreBmBc(const uint8_t *x, uint16_t m, uint16_t *bmBc); -static void PreBmBcNocase(const uint8_t *x, uint16_t m, uint16_t *bmBc); -static void BoyerMooreSuffixesNocase(const uint8_t *x, uint16_t m, - uint16_t *suff); -static void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs); - -/** - * \brief Given a BmCtx structure, recreate the pre/suffixes for - * nocase - * - * \retval BmCtx pointer to the already created BmCtx (with BoyerMooreCtxInit()) - * \param str pointer to the pattern string - * \param size length of the string - */ -void BoyerMooreCtxToNocase(BmCtx *bm_ctx, uint8_t *needle, uint16_t needle_len) -{ - /* Store the content as lower case to make searching faster */ - memcpy_tolower(needle, needle, needle_len); - - /* Prepare bad chars with nocase chars */ - PreBmBcNocase(needle, needle_len, bm_ctx->bmBc); - - /* Prepare good Suffixes with nocase chars */ - PreBmGsNocase(needle, needle_len, bm_ctx->bmGs); -} - -/** - * \brief Setup a Boyer Moore context. - * - * \param str pointer to the pattern string - * \param size length of the string - * \retval BmCtx pointer to the newly created Context for the pattern - * \initonly BoyerMoore contexts should be created at init - */ -BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len) -{ - BmCtx *new = SCMalloc(sizeof(BmCtx) + sizeof(uint16_t) * (needle_len + 1)); - if (unlikely(new == NULL)) { - FatalError("Fatal error encountered in BoyerMooreCtxInit. Exiting..."); - } - - /* Prepare bad chars */ - PreBmBc(needle, needle_len, new->bmBc); - - /* Prepare good Suffixes */ - if (PreBmGs(needle, needle_len, new->bmGs) == -1) { - FatalError("Fatal error encountered in BoyerMoreCtxInit. Exiting..."); - } - - - return new; -} - -/** - * \brief Setup a Boyer Moore context for nocase search - * - * \param str pointer to the pattern string - * \param size length of the string - * \retval BmCtx pointer to the newly created Context for the pattern - * \initonly BoyerMoore contexts should be created at init - */ -BmCtx *BoyerMooreNocaseCtxInit(uint8_t *needle, uint16_t needle_len) -{ - BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needle_len); - - BoyerMooreCtxToNocase(bm_ctx, needle, needle_len); - - return bm_ctx; -} - -/** - * \brief Free the memory allocated to Boyer Moore context. - * - * \param bmCtx pointer to the Context for the pattern - */ -void BoyerMooreCtxDeInit(BmCtx *bmctx) -{ - SCEnter(); - if (bmctx == NULL) - SCReturn; - - SCFree(bmctx); - - SCReturn; -} -/** - * \brief Array setup function for bad characters that split the pattern - * Remember that the result array should be the length of ALPHABET_SIZE - * - * \param str pointer to the pattern string - * \param size length of the string - * \param result pointer to an empty array that will hold the badchars - */ -static void PreBmBc(const uint8_t *x, uint16_t m, uint16_t *bmBc) -{ - uint16_t i; - - for (i = 0; i < 256; ++i) { - bmBc[i] = m; - } - for (i = 0; i < m - 1; ++i) { - bmBc[(unsigned char)x[i]] = m - i - 1; - } -} - -/** - * \brief Array setup function for building prefixes (shift for valid prefixes) for boyermoore context - * - * \param x pointer to the pattern string - * \param m length of the string - * \param suff pointer to an empty array that will hold the prefixes (shifts) - */ -static void BoyerMooreSuffixes(const uint8_t *x, uint16_t m, uint16_t *suff) -{ - int32_t f = 0, g, i; - suff[m - 1] = m; - g = m - 1; - for (i = m - 2; i >= 0; --i) { - if (i > g && suff[i + m - 1 - f] < i - g) - suff[i] = suff[i + m - 1 - f]; - else { - if (i < g) - g = i; - f = i; - while (g >= 0 && x[g] == x[g + m - 1 - f]) - --g; - DEBUG_VALIDATE_BUG_ON(f - g < 0 || f - g > UINT16_MAX); - suff[i] = (uint16_t)(f - g); - } - } -} - -/** - * \brief Array setup function for building prefixes (shift for valid prefixes) for boyermoore context - * - * \param x pointer to the pattern string - * \param m length of the string - * \param bmGs pointer to an empty array that will hold the prefixes (shifts) - * \retval 0 ok, -1 failed - */ -static int PreBmGs(const uint8_t *x, uint16_t m, uint16_t *bmGs) -{ - int32_t i, j; - uint16_t suff[m + 1]; - - BoyerMooreSuffixes(x, m, suff); - - for (i = 0; i < m; ++i) - bmGs[i] = m; - - j = 0; - - for (i = m - 1; i >= -1; --i) - if (i == -1 || suff[i] == i + 1) - for (; j < m - 1 - i; ++j) - if (bmGs[j] == m) - bmGs[j] = (uint16_t)(m - 1 - i); - - for (i = 0; i <= m - 2; ++i) - bmGs[m - 1 - suff[i]] = (uint16_t)(m - 1 - i); - return 0; -} - -/** - * \brief Array setup function for bad characters that split the pattern - * Remember that the result array should be the length of ALPHABET_SIZE - * - * \param str pointer to the pattern string - * \param size length of the string - * \param result pointer to an empty array that will hold the badchars - */ -static void PreBmBcNocase(const uint8_t *x, uint16_t m, uint16_t *bmBc) -{ - uint16_t i; - - for (i = 0; i < 256; ++i) { - bmBc[i] = m; - } - for (i = 0; i < m - 1; ++i) { - bmBc[u8_tolower(x[i])] = m - 1 - i; - bmBc[u8_toupper(x[i])] = m - 1 - i; - } -} - -static void BoyerMooreSuffixesNocase(const uint8_t *x, uint16_t m, - uint16_t *suff) -{ - int32_t f = 0, g, i; - - suff[m - 1] = m; - g = m - 1; - for (i = m - 2; i >= 0; --i) { - if (i > g && suff[i + m - 1 - f] < i - g) { - suff[i] = suff[i + m - 1 - f]; - } else { - if (i < g) { - g = i; - } - f = i; - while (g >= 0 && u8_tolower(x[g]) == u8_tolower(x[g + m - 1 - f])) { - --g; - } - DEBUG_VALIDATE_BUG_ON(f - g < 0 || f - g > UINT16_MAX); - suff[i] = (uint16_t)(f - g); - } - } -} - -/** - * \brief Array setup function for building prefixes (shift for valid prefixes) - * for boyermoore context case less - * - * \param x pointer to the pattern string - * \param m length of the string - * \param bmGs pointer to an empty array that will hold the prefixes (shifts) - */ -static void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs) -{ - uint16_t i, j; - uint16_t suff[m + 1]; - - BoyerMooreSuffixesNocase(x, m, suff); - - for (i = 0; i < m; ++i) { - bmGs[i] = m; - } - j = 0; - for (i = m; i > 0; --i) { - if (suff[i - 1] == i) { - for (; j < m - i; ++j) { - if (bmGs[j] == m) { - bmGs[j] = m - i; - } - } - } - } - for (i = 0; i <= m - 2; ++i) { - bmGs[m - 1 - suff[i]] = m - 1 - i; - } -} - -/** - * \brief Boyer Moore search algorithm - * Is better as the pattern length increases and for big buffers to search in. - * The algorithm needs a context of two arrays already prepared - * by prep_bad_chars() and prep_good_suffix() - * - * \param y pointer to the buffer to search in - * \param n length limit of the buffer - * \param x pointer to the pattern we ar searching for - * \param m length limit of the needle - * \param bmBc pointer to an array of BoyerMooreSuffixes prepared by prep_good_suffix() - * \param bmGs pointer to an array of bachars prepared by prep_bad_chars() - * - * \retval ptr to start of the match; NULL if no match - */ -uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx) -{ - uint16_t *bmGs = bm_ctx->bmGs; - uint16_t *bmBc = bm_ctx->bmBc; - - int i, j, m1, m2; - int32_t int_n; -#if 0 - printf("\nBad:\n"); - for (i=0;i INT32_MAX) ? INT32_MAX : n; - j = 0; - while (j <= int_n - m ) { - for (i = m - 1; i >= 0 && x[i] == y[i + j]; --i); - - if (i < 0) { - return (uint8_t *)(y + j); - //j += bmGs[0]; - } else { -// printf("%c", y[i+j]); - j += (m1 = bmGs[i]) > (m2 = bmBc[y[i + j]] - m + 1 + i)? m1: m2; -// printf("%d, %d\n", m1, m2); - } - } - return NULL; -} - - -/** - * \brief Boyer Moore search algorithm - * Is better as the pattern length increases and for big buffers to search in. - * The algorithm needs a context of two arrays already prepared - * by prep_bad_chars() and prep_good_suffix() - * - * \param y pointer to the buffer to search in - * \param n length limit of the buffer - * \param x pointer to the pattern we ar searching for - * \param m length limit of the needle - * \param bmBc pointer to an array of BoyerMooreSuffixes prepared by prep_good_suffix() - * \param bmGs pointer to an array of bachars prepared by prep_bad_chars() - * - * \retval ptr to start of the match; NULL if no match - */ -uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx) -{ - uint16_t *bmGs = bm_ctx->bmGs; - uint16_t *bmBc = bm_ctx->bmBc; - int i, j, m1, m2; - int32_t int_n; -#if 0 - printf("\nBad:\n"); - for (i=0;i INT32_MAX) ? INT32_MAX : n; - j = 0; - while (j <= int_n - m ) { - /* x is stored in lowercase. */ - for (i = m - 1; i >= 0 && x[i] == u8_tolower(y[i + j]); --i); - - if (i < 0) { - return (uint8_t *)(y + j); - } else { - j += (m1 = bmGs[i]) > (m2 = bmBc[y[i + j]] - m + 1 + i)? - m1: m2; - } - } - return NULL; -} - -typedef struct SpmBmCtx_ { - BmCtx *bm_ctx; - uint8_t *needle; - uint16_t needle_len; - int nocase; -} SpmBmCtx; - -static SpmCtx *BMInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, - SpmGlobalThreadCtx *global_thread_ctx) -{ - SpmCtx *ctx = SCCalloc(1, sizeof(SpmCtx)); - if (ctx == NULL) { - SCLogDebug("Unable to alloc SpmCtx."); - return NULL; - } - ctx->matcher = SPM_BM; - - SpmBmCtx *sctx = SCCalloc(1, sizeof(SpmBmCtx)); - if (sctx == NULL) { - SCLogDebug("Unable to alloc SpmBmCtx."); - SCFree(ctx); - return NULL; - } - - sctx->needle = SCMalloc(needle_len); - if (sctx->needle == NULL) { - SCLogDebug("Unable to alloc string."); - SCFree(sctx); - SCFree(ctx); - return NULL; - } - memcpy(sctx->needle, needle, needle_len); - sctx->needle_len = needle_len; - - if (nocase) { - sctx->bm_ctx = BoyerMooreNocaseCtxInit(sctx->needle, sctx->needle_len); - sctx->nocase = 1; - } else { - sctx->bm_ctx = BoyerMooreCtxInit(sctx->needle, sctx->needle_len); - sctx->nocase = 0; - } - - ctx->ctx = sctx; - return ctx; -} - -static void BMDestroyCtx(SpmCtx *ctx) -{ - if (ctx == NULL) { - return; - } - - SpmBmCtx *sctx = ctx->ctx; - if (sctx != NULL) { - BoyerMooreCtxDeInit(sctx->bm_ctx); - if (sctx->needle != NULL) { - SCFree(sctx->needle); - } - SCFree(sctx); - } - - SCFree(ctx); -} - -static uint8_t *BMScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, - const uint8_t *haystack, uint32_t haystack_len) -{ - const SpmBmCtx *sctx = ctx->ctx; - - if (sctx->nocase) { - return BoyerMooreNocase(sctx->needle, sctx->needle_len, haystack, - haystack_len, sctx->bm_ctx); - } else { - return BoyerMoore(sctx->needle, sctx->needle_len, haystack, - haystack_len, sctx->bm_ctx); - } -} - -static SpmGlobalThreadCtx *BMInitGlobalThreadCtx(void) -{ - SpmGlobalThreadCtx *global_thread_ctx = SCCalloc(1, sizeof(SpmGlobalThreadCtx)); - if (global_thread_ctx == NULL) { - SCLogDebug("Unable to alloc SpmThreadCtx."); - return NULL; - } - global_thread_ctx->matcher = SPM_BM; - return global_thread_ctx; -} - -static void BMDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) -{ - if (global_thread_ctx == NULL) { - return; - } - SCFree(global_thread_ctx); -} - -static void BMDestroyThreadCtx(SpmThreadCtx *thread_ctx) -{ - if (thread_ctx == NULL) { - return; - } - SCFree(thread_ctx); -} - -static SpmThreadCtx *BMMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) { - SpmThreadCtx *thread_ctx = SCCalloc(1, sizeof(SpmThreadCtx)); - if (thread_ctx == NULL) { - SCLogDebug("Unable to alloc SpmThreadCtx."); - return NULL; - } - thread_ctx->matcher = SPM_BM; - return thread_ctx; -} - -void SpmBMRegister(void) -{ - spm_table[SPM_BM].name = "bm"; - spm_table[SPM_BM].InitGlobalThreadCtx = BMInitGlobalThreadCtx; - spm_table[SPM_BM].DestroyGlobalThreadCtx = BMDestroyGlobalThreadCtx; - spm_table[SPM_BM].MakeThreadCtx = BMMakeThreadCtx; - spm_table[SPM_BM].DestroyThreadCtx = BMDestroyThreadCtx; - spm_table[SPM_BM].InitCtx = BMInitCtx; - spm_table[SPM_BM].DestroyCtx = BMDestroyCtx; - spm_table[SPM_BM].Scan = BMScan; -} diff --git a/src/util-spm-bm.h b/src/util-spm-bm.h deleted file mode 100644 index 3c5e59ce03fb..000000000000 --- a/src/util-spm-bm.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * - */ - -#ifndef __UTIL_SPM_BM__ -#define __UTIL_SPM_BM__ - -#include "suricata-common.h" - -#define ALPHABET_SIZE 256 - -/* Context for boyer moore */ -typedef struct BmCtx_ { - uint16_t bmBc[ALPHABET_SIZE]; - //C99 "flexible array member" - uint16_t bmGs[]; // = SCMalloc(sizeof(int16_t)*(needlelen + 1)); -} BmCtx; - -/** Prepare and return a Boyer Moore context */ -BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len); -BmCtx *BoyerMooreNocaseCtxInit(uint8_t *needle, uint16_t needle_len); - -void BoyerMooreCtxToNocase(BmCtx *, uint8_t *, uint16_t); -uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx); -uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx); -void BoyerMooreCtxDeInit(BmCtx *); - -void SpmBMRegister(void); - -#endif /* __UTIL_SPM_BM__ */ - diff --git a/src/util-spm-bs.c b/src/util-spm-bs.c deleted file mode 100644 index 823e2a646b68..000000000000 --- a/src/util-spm-bs.c +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Pablo Rincon Crespo - * - * bs is a bruteforce search. It will try to search the pattern - * from all characters until the available text len is less - * than the length of the pattern. It needs no context but it - * time cost is not good. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "util-debug.h" -#include "util-spm-bs.h" - -/** - * \brief Basic search improved. Limits are better handled, so - * it doesn't start searches that wont fit in the remaining buffer - * - * \param haystack pointer to the buffer to search in - * \param haystack_len length limit of the buffer - * \param needle pointer to the pattern we ar searching for - * \param needle_len length limit of the needle - * - * \retval ptr to start of the match; NULL if no match - */ -uint8_t *BasicSearch(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len) -{ - SCEnter(); - - const uint8_t *h, *n; - const uint8_t *hmax = haystack + haystack_len; - const uint8_t *nmax = needle + needle_len; - - if (needle_len == 0 || needle_len > haystack_len) { - SCReturnPtr(NULL, "uint8_t"); - } - - //PrintRawDataFp(stdout,needle,needle_len); - - //PrintRawDataFp(stdout,haystack,haystack_len); - - for (n = needle; nmax - n <= hmax - haystack; haystack++) { - if (*haystack != *n) { - continue; - } - - SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); - - /* one byte needles */ - if (needle_len == 1) { - SCReturnPtr((uint8_t *)haystack, "uint8_t"); - } - - for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) { - if (*h != *n) { - break; - } - SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); - /* if we run out of needle we fully matched */ - if (n == nmax - 1) { - SCReturnPtr((uint8_t *)haystack, "uint8_t"); - } - } - n = needle; - } - - SCReturnPtr(NULL, "uint8_t"); -} - -/** - * \brief Basic search case less - * - * \param haystack pointer to the buffer to search in - * \param haystack_len length limit of the buffer - * \param needle pointer to the pattern we ar searching for - * \param needle_len length limit of the needle - * - * \retval ptr to start of the match; NULL if no match - */ -uint8_t *BasicSearchNocase(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len) -{ - const uint8_t *h, *n; - const uint8_t *hmax = haystack + haystack_len; - const uint8_t *nmax = needle + needle_len; - - if (needle_len == 0 || needle_len > haystack_len) - return NULL; - - for (n = needle; nmax - n <= hmax - haystack; haystack++) { - if (u8_tolower(*haystack) != u8_tolower(*n)) { - continue; - } - /* one byte needles */ - if (needle_len == 1) { - return (uint8_t *)haystack; - } - - for (h = haystack+1, n++; nmax - n <= hmax - h ; h++, n++) { - if (u8_tolower(*h) != u8_tolower(*n)) { - break; - } - /* if we run out of needle we fully matched */ - if (n == nmax - 1) { - return (uint8_t *)haystack; - } - } - n = needle; - } - - return NULL; -} - -void BasicSearchInit (void) -{ - /* nothing no more */ -} - diff --git a/src/util-spm-bs.h b/src/util-spm-bs.h deleted file mode 100644 index ddd930239052..000000000000 --- a/src/util-spm-bs.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Pablo Rincon Crespo - */ - -#ifndef __UTIL_SPM_BS__ -#define __UTIL_SPM_BS__ - -#include "suricata-common.h" - -uint8_t *BasicSearch(const uint8_t *, uint32_t, const uint8_t *, uint16_t); -uint8_t *BasicSearchNocase(const uint8_t *, uint32_t, const uint8_t *, uint16_t); -void BasicSearchInit (void); - -#endif /* __UTIL_SPM_BS__ */ - diff --git a/src/util-spm-bs2bm.c b/src/util-spm-bs2bm.c deleted file mode 100644 index 589e6e9d92db..000000000000 --- a/src/util-spm-bs2bm.c +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * - * Bs2Bm use a simple context array to determine the characters - * that are not present on the pattern. This way on partial matches - * broken by a char not present, we can skip to the next character - * making less checks - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "util-spm-bs2bm.h" - -/** - * \brief Array setup function for Bs2Bm of bad characters index (not found at the needle) - * - * \param needle pointer to the pattern we ar searching for - * \param needle_len length limit of the needle - * \param badchars pointer to an empty array of bachars. The array prepared contains - * characters that can't be inside the needle_len. So the skips can be - * faster - */ -void Bs2BmBadchars(const uint8_t *needle, uint16_t needle_len, uint8_t *badchars) -{ - uint32_t i; - for (i = 0; i < ALPHABET_SIZE; i++) - badchars[i] = 1; - - /* set to 0 the values where index as ascii is present - * because they are not badchars - */ - for (i = 0; i < needle_len; i++) - badchars[needle[i]] = 0; -} - -/** - * \brief Array setup function for Bs2BmNocase of bad characters index (not found at the needle) - * - * \param needle pointer to the pattern we ar searching for - * \param needle_len length limit of the needle - * \param badchars pointer to an empty array of bachars. The array prepared contains - * characters that can't be inside the needle_len. So the skips can be - * faster - */ -void Bs2BmBadcharsNocase(const uint8_t *needle, uint16_t needle_len, uint8_t *badchars) -{ - uint32_t i; - for (i = 0; i < ALPHABET_SIZE; i++) - badchars[i] = 1; - - /* set to 0 the values where index as ascii is present - * because they are not badchars - */ - for (i = 0; i < needle_len; i++) { - badchars[u8_tolower(needle[i])] = 0; - } -} - -/** - * \brief Basic search with a bad characters array. The array badchars contains - * flags at character's ascii index that can't be inside the needle. So the skips can be - * faster - * - * \param haystack pointer to the buffer to search in - * \param haystack_len length limit of the buffer - * \param needle pointer to the pattern we ar searching for - * \param needle_len length limit of the needle - * \param badchars pointer to an array of bachars prepared by Bs2BmBadchars() - * - * \retval ptr to start of the match; NULL if no match - */ -uint8_t *Bs2Bm(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, - uint16_t needle_len, const uint8_t badchars[]) -{ - const uint8_t *h, *n; - const uint8_t *hmax = haystack + haystack_len; - const uint8_t *nmax = needle + needle_len; - - if (needle_len == 0 || needle_len > haystack_len) - return NULL; - - for (n = needle; nmax - n <= hmax - haystack; haystack++) { - if (*haystack != *n) { - continue; - } - /* one byte needles */ - if (needle_len == 1) - return (uint8_t *)haystack; - - for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) { - if (*h != *n) { - if (badchars[*h] == 1) { - /* skip it! */ - haystack = h; - } - break; - } - /* if we run out of needle we fully matched */ - if (n == nmax - 1 ) { - return (uint8_t *)haystack; - } - } - n = needle; - } - - return NULL; -} - -/** - * \brief Basic search case less with a bad characters array. The array badchars contains - * flags at character's ascii index that can't be inside the needle. So the skips can be - * faster - * - * \param haystack pointer to the buffer to search in - * \param haystack_len length limit of the buffer - * \param needle pointer to the pattern we ar searching for - * \param needle_len length limit of the needle - * \param badchars pointer to an array of bachars prepared by Bs2BmBadchars() - * - * \retval ptr to start of the match; NULL if no match - */ -uint8_t *Bs2BmNocase(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, - uint16_t needle_len, const uint8_t badchars[]) -{ - const uint8_t *h, *n; - const uint8_t *hmax = haystack + haystack_len; - const uint8_t *nmax = needle + needle_len; - - if (needle_len == 0 || needle_len > haystack_len) - return NULL; - - for (n = needle; nmax - n <= hmax - haystack; haystack++) { - if (u8_tolower(*haystack) != u8_tolower(*n)) { - continue; - } - /* one byte needles */ - if (needle_len == 1) - return (uint8_t *)haystack; - - for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) { - if (u8_tolower(*h) != u8_tolower(*n)) { - if (badchars[u8_tolower(*h)] == 1) { - /* skip it! */ - haystack = h; - } - break; - } - /* if we run out of needle we fully matched */ - if (n == nmax - 1) { - return (uint8_t *)haystack; - } - } - n = needle; - } - - return NULL; -} diff --git a/src/util-spm-bs2bm.h b/src/util-spm-bs2bm.h deleted file mode 100644 index 74df96aae1e2..000000000000 --- a/src/util-spm-bs2bm.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - */ - -#ifndef __UTIL_SPM_BS2BM__ -#define __UTIL_SPM_BS2BM__ - -#include "suricata-common.h" - -#define ALPHABET_SIZE 256 - -void Bs2BmBadchars(const uint8_t *, uint16_t, uint8_t *); -void Bs2BmBadcharsNocase(const uint8_t *, uint16_t, uint8_t *); -uint8_t *Bs2Bm(const uint8_t *, uint32_t, const uint8_t *, uint16_t, const uint8_t[]); -uint8_t *Bs2BmNocase(const uint8_t *, uint32_t, const uint8_t *, uint16_t, const uint8_t[]); - -#endif /* __UTIL_SPM_BS2BM__ */ - diff --git a/src/util-spm-hs.c b/src/util-spm-hs.c deleted file mode 100644 index d58de651d943..000000000000 --- a/src/util-spm-hs.c +++ /dev/null @@ -1,235 +0,0 @@ -/* Copyright (C) 2016-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Justin Viiret - * - * Single pattern matcher that uses the Hyperscan regex matcher. - */ - -#include "suricata-common.h" -#include "util-hyperscan.h" -#include "util-spm.h" -#include "util-spm-hs.h" -#include "util-debug.h" - -#ifdef BUILD_HYPERSCAN - -#include - -/** - * \internal - * \brief Hyperscan match callback, called by hs_scan. - */ -static int MatchEvent(unsigned int id, unsigned long long from, - unsigned long long to, unsigned int flags, void *context) -{ - uint64_t *match_offset = context; - BUG_ON(*match_offset != UINT64_MAX); - *match_offset = to; - return 1; /* Terminate matching. */ -} - -typedef struct SpmHsCtx_ { - hs_database_t *db; - uint16_t needle_len; -} SpmHsCtx; - -static void HSDestroyCtx(SpmCtx *ctx) -{ - if (ctx == NULL) { - return; - } - SpmHsCtx *sctx = ctx->ctx; - if (sctx) { - hs_free_database(sctx->db); - SCFree(sctx); - } - SCFree(ctx); -} - -static int HSBuildDatabase(const uint8_t *needle, uint16_t needle_len, - int nocase, SpmHsCtx *sctx, - SpmGlobalThreadCtx *global_thread_ctx) -{ - char *expr = HSRenderPattern(needle, needle_len); - if (expr == NULL) { - SCLogDebug("HSRenderPattern returned NULL"); - return -1; - } - - unsigned flags = nocase ? HS_FLAG_CASELESS : 0; - - hs_database_t *db = NULL; - hs_compile_error_t *compile_err = NULL; - hs_error_t err = hs_compile(expr, flags, HS_MODE_BLOCK, NULL, &db, - &compile_err); - if (err != HS_SUCCESS) { - SCLogError("Unable to compile '%s' with Hyperscan, " - "returned %d.", - expr, err); - return -1; - } - - SCFree(expr); - - /* Update scratch for this database. */ - hs_scratch_t *scratch = global_thread_ctx->ctx; - err = hs_alloc_scratch(db, &scratch); - if (err != HS_SUCCESS) { - /* If scratch allocation failed, this is not recoverable: other SPM - * contexts may need this scratch space. */ - SCLogError("Unable to alloc scratch for Hyperscan, returned %d.", err); - return -1; - } - global_thread_ctx->ctx = scratch; - sctx->db = db; - sctx->needle_len = needle_len; - - return 0; -} - -static SpmCtx *HSInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, - SpmGlobalThreadCtx *global_thread_ctx) -{ - SpmCtx *ctx = SCCalloc(1, sizeof(SpmCtx)); - if (ctx == NULL) { - SCLogDebug("Unable to alloc SpmCtx."); - return NULL; - } - ctx->matcher = SPM_HS; - - SpmHsCtx *sctx = SCCalloc(1, sizeof(SpmHsCtx)); - if (sctx == NULL) { - SCLogDebug("Unable to alloc SpmHsCtx."); - SCFree(ctx); - return NULL; - } - ctx->ctx = sctx; - - if (HSBuildDatabase(needle, needle_len, nocase, sctx, - global_thread_ctx) != 0) { - SCLogDebug("HSBuildDatabase failed."); - HSDestroyCtx(ctx); - return NULL; - } - - return ctx; -} - -static uint8_t *HSScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, - const uint8_t *haystack, uint32_t haystack_len) -{ - const SpmHsCtx *sctx = ctx->ctx; - hs_scratch_t *scratch = thread_ctx->ctx; - - if (unlikely(haystack_len == 0)) { - return NULL; - } - - uint64_t match_offset = UINT64_MAX; - hs_error_t err = hs_scan(sctx->db, (const char *)haystack, haystack_len, 0, - scratch, MatchEvent, &match_offset); - if (err != HS_SUCCESS && err != HS_SCAN_TERMINATED) { - /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() - * indicates that it was passed an invalid database or scratch region, - * which is not something we can recover from at scan time. */ - SCLogError("Hyperscan returned fatal error %d.", err); - exit(EXIT_FAILURE); - } - - if (match_offset == UINT64_MAX) { - return NULL; - } - - BUG_ON(match_offset < sctx->needle_len); - - /* Note: existing API returns non-const ptr */ - return (uint8_t *)haystack + (match_offset - sctx->needle_len); -} - -static SpmGlobalThreadCtx *HSInitGlobalThreadCtx(void) -{ - SpmGlobalThreadCtx *global_thread_ctx = SCCalloc(1, sizeof(SpmGlobalThreadCtx)); - if (global_thread_ctx == NULL) { - SCLogDebug("Unable to alloc SpmGlobalThreadCtx."); - return NULL; - } - global_thread_ctx->matcher = SPM_HS; - - /* We store scratch in the HS-specific ctx. This will be initialized as - * patterns are compiled by SpmInitCtx. */ - global_thread_ctx->ctx = NULL; - - return global_thread_ctx; -} - -static void HSDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) -{ - if (global_thread_ctx == NULL) { - return; - } - hs_free_scratch(global_thread_ctx->ctx); - SCFree(global_thread_ctx); -} - -static void HSDestroyThreadCtx(SpmThreadCtx *thread_ctx) -{ - if (thread_ctx == NULL) { - return; - } - hs_free_scratch(thread_ctx->ctx); - SCFree(thread_ctx); -} - -static SpmThreadCtx *HSMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) -{ - SpmThreadCtx *thread_ctx = SCCalloc(1, sizeof(SpmThreadCtx)); - if (thread_ctx == NULL) { - SCLogDebug("Unable to alloc SpmThreadCtx."); - return NULL; - } - thread_ctx->matcher = SPM_HS; - - if (global_thread_ctx->ctx != NULL) { - hs_scratch_t *scratch = NULL; - hs_error_t err = hs_clone_scratch(global_thread_ctx->ctx, &scratch); - if (err != HS_SUCCESS) { - SCLogError("Unable to clone scratch (error %d).", err); - exit(EXIT_FAILURE); - } - thread_ctx->ctx = scratch; - } - - return thread_ctx; -} - -void SpmHSRegister(void) -{ - spm_table[SPM_HS].name = "hs"; - spm_table[SPM_HS].InitGlobalThreadCtx = HSInitGlobalThreadCtx; - spm_table[SPM_HS].DestroyGlobalThreadCtx = HSDestroyGlobalThreadCtx; - spm_table[SPM_HS].MakeThreadCtx = HSMakeThreadCtx; - spm_table[SPM_HS].DestroyThreadCtx = HSDestroyThreadCtx; - spm_table[SPM_HS].InitCtx = HSInitCtx; - spm_table[SPM_HS].DestroyCtx = HSDestroyCtx; - spm_table[SPM_HS].Scan = HSScan; -} - -#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-spm.c b/src/util-spm.c deleted file mode 100644 index 15b33398a62a..000000000000 --- a/src/util-spm.c +++ /dev/null @@ -1,2744 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * - * PR (17/01/2010): Single pattern search algorithms: - * Currently there are 3 algorithms to choose: BasicSearch, Bs2Bm and - * BoyerMoore (Boyer Moores algorithm). The first one doesn't need a context. - * But for Bs2Bm and BoyerMoore, you'll need to build some arrays. - * - * !! If you are going to use the same pattern multiple times, - * please, try to store the context some where. For Bs2Bm, the - * context is an array of "badchars". For BoyerMoore you need to store - * two arrays of shifts. Have a look at the wrappers and unittests - * for examples of this. If you cant store the context, use the - * wrappers: Bs2bmSearch, BoyerMooreSearch, and the ones caseless, or BasicSearch - * That is the most basic. - * - * Use the stats and util-clock.h to determine which one fit better for you - * Boyer Moore should be used for patterns greater than 1 of length - * In the range of 2 - 6, if the text length is greater than 1000 you could - * use boyer moore, otherwise, basic search. If the pattern is greater - * than 6 and the textlen is greater than 500, use boyer moore. - * This is an aproximation, but use the stats and util-clock to determine which one - * fit better for your case. - * - */ - -#include "suricata-common.h" -#include "util-unittest.h" - -#include "conf.h" - -#include "util-spm.h" -#include "util-spm-bs.h" -#include "util-spm-bs2bm.h" -#include "util-spm-bm.h" -#include "util-spm-hs.h" -#include "util-clock.h" -#ifdef BUILD_HYPERSCAN -#include "hs.h" -#endif -#include "util-debug.h" - -SpmTableElmt spm_table[SPM_TABLE_SIZE]; - -/** - * \brief Returns the single pattern matcher algorithm to be used, based on the - * spm-algo setting in yaml. - */ -uint8_t SinglePatternMatchDefaultMatcher(void) -{ - const char *spm_algo; - if ((ConfGet("spm-algo", &spm_algo)) == 1) { - if (spm_algo != NULL) { - if (strcmp("auto", spm_algo) == 0) { - goto default_matcher; - } - for (uint8_t i = 0; i < SPM_TABLE_SIZE; i++) { - if (spm_table[i].name == NULL) { - continue; - } - if (strcmp(spm_table[i].name, spm_algo) == 0) { - return i; - } - } - } - -#ifndef BUILD_HYPERSCAN - if ((spm_algo != NULL) && (strcmp(spm_algo, "hs") == 0)) { - FatalError("Hyperscan (hs) support for spm-algo is " - "not compiled into Suricata."); - } -#endif - SCLogError("Invalid spm algo supplied " - "in the yaml conf file: \"%s\"", - spm_algo); - exit(EXIT_FAILURE); - } - -default_matcher: - /* When Suricata is built with Hyperscan support, default to using it for - * SPM. */ -#ifdef BUILD_HYPERSCAN - #ifdef HAVE_HS_VALID_PLATFORM - /* Enable runtime check for SSSE3. Do not use Hyperscan SPM matcher if - * check is not successful. */ - if (hs_valid_platform() != HS_SUCCESS) { - SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " - "SPM"); - /* Use Boyer-Moore as fallback. */ - return SPM_BM; - } else { - return SPM_HS; - } - #else - return SPM_HS; - #endif -#else - /* Otherwise, default to Boyer-Moore */ - return SPM_BM; -#endif -} - -void SpmTableSetup(void) -{ - memset(spm_table, 0, sizeof(spm_table)); - - SpmBMRegister(); -#ifdef BUILD_HYPERSCAN - #ifdef HAVE_HS_VALID_PLATFORM - if (hs_valid_platform() == HS_SUCCESS) { - SpmHSRegister(); - } - #else - SpmHSRegister(); - #endif -#endif -} - -SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint8_t matcher) -{ - BUG_ON(spm_table[matcher].InitGlobalThreadCtx == NULL); - return spm_table[matcher].InitGlobalThreadCtx(); -} - -void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) -{ - if (global_thread_ctx == NULL) { - return; - } - uint8_t matcher = global_thread_ctx->matcher; - spm_table[matcher].DestroyGlobalThreadCtx(global_thread_ctx); -} - -SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) -{ - if (global_thread_ctx == NULL) { - return NULL; - } - uint8_t matcher = global_thread_ctx->matcher; - BUG_ON(spm_table[matcher].MakeThreadCtx == NULL); - return spm_table[matcher].MakeThreadCtx(global_thread_ctx); -} - -void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx) -{ - if (thread_ctx == NULL) { - return; - } - uint8_t matcher = thread_ctx->matcher; - BUG_ON(spm_table[matcher].DestroyThreadCtx == NULL); - spm_table[matcher].DestroyThreadCtx(thread_ctx); -} - -SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, - SpmGlobalThreadCtx *global_thread_ctx) -{ - BUG_ON(global_thread_ctx == NULL); - uint8_t matcher = global_thread_ctx->matcher; - BUG_ON(spm_table[matcher].InitCtx == NULL); - return spm_table[matcher].InitCtx(needle, needle_len, nocase, - global_thread_ctx); -} - -void SpmDestroyCtx(SpmCtx *ctx) -{ - if (ctx == NULL) { - return; - } - uint8_t matcher = ctx->matcher; - BUG_ON(spm_table[matcher].DestroyCtx == NULL); - spm_table[matcher].DestroyCtx(ctx); -} - -uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, - const uint8_t *haystack, uint32_t haystack_len) -{ - uint8_t matcher = ctx->matcher; - return spm_table[matcher].Scan(ctx, thread_ctx, haystack, haystack_len); -} - -/** - * Wrappers for building context and searching (Bs2Bm and boyermoore) - * Use them if you cant store the context - * - */ - -/** - * \brief Search a pattern in the text using the Bs2Bm algorithm (build a bad characters array) - * - * \param text Text to search in - * \param textlen length of the text - * \param needle pattern to search for - * \param needlelen length of the pattern - */ -uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, - const uint8_t *needle, uint16_t needlelen) -{ - uint8_t badchars[ALPHABET_SIZE]; - Bs2BmBadchars(needle, needlelen, badchars); - - return Bs2Bm(text, textlen, needle, needlelen, badchars); -} - -/** - * \brief Search a pattern in the text using the Bs2Bm nocase algorithm (build a bad characters array) - * - * \param text Text to search in - * \param textlen length of the text - * \param needle pattern to search for - * \param needlelen length of the pattern - */ -uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, - const uint8_t *needle, uint16_t needlelen) -{ - uint8_t badchars[ALPHABET_SIZE]; - Bs2BmBadchars(needle, needlelen, badchars); - - return Bs2BmNocase(text, textlen, needle, needlelen, badchars); -} - -/** - * \brief Search a pattern in the text using Boyer Moore algorithm - * (build a bad character shifts array and good prefixes shift array) - * - * \param text Text to search in - * \param textlen length of the text - * \param needle pattern to search for - * \param needlelen length of the pattern - */ -uint8_t *BoyerMooreSearch(const uint8_t *text, uint32_t textlen, - const uint8_t *needle, uint16_t needlelen) -{ - BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); - - uint8_t *ret = BoyerMoore(needle, needlelen, text, textlen, bm_ctx); - BoyerMooreCtxDeInit(bm_ctx); - - return ret; -} - -/** - * \brief Search a pattern in the text using Boyer Moore nocase algorithm - * (build a bad character shifts array and good prefixes shift array) - * - * \param text Text to search in - * \param textlen length of the text - * \param needle pattern to search for - * \param needlelen length of the pattern - */ -uint8_t *BoyerMooreNocaseSearch(const uint8_t *text, uint32_t textlen, - uint8_t *needle, uint16_t needlelen) -{ - BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); - - uint8_t *ret = BoyerMooreNocase(needle, needlelen, text, textlen, bm_ctx); - BoyerMooreCtxDeInit(bm_ctx); - - return ret; -} - - -#ifdef UNITTESTS - -/** Comment out this if you want stats - * #define ENABLE_SEARCH_STATS 1 - */ - -/* Number of times to repeat the search (for stats) */ -#define STATS_TIMES 1000000 - -/** - * \brief Unittest helper function wrappers for the search algorithms - * \param text pointer to the buffer to search in - * \param needle pointer to the pattern to search for - * \param times If you are testing performance, se the numebr of times - * that you want to repeat the search - */ -static uint8_t *BasicSearchWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = (uint16_t)strlen((char *)needle); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) - CLOCK_START; - - for (i = 0; i < times; i++) { - ret = BasicSearch(text, textlen, needle, needlelen); - } - - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *BasicSearchNocaseWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = (uint16_t)strlen((char *)needle); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - ret = BasicSearchNocase(text, textlen, needle, needlelen); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *Bs2bmWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = (uint16_t)strlen((char *)needle); - - uint8_t badchars[ALPHABET_SIZE]; - Bs2BmBadchars(needle, needlelen, badchars); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - ret = Bs2Bm(text, textlen, needle, needlelen, badchars); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *Bs2bmNocaseWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = (uint16_t)strlen((char *)needle); - - uint8_t badchars[ALPHABET_SIZE]; - Bs2BmBadchars(needle, needlelen, badchars); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - ret = Bs2BmNocase(text, textlen, needle, needlelen, badchars); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *BoyerMooreWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = (uint16_t)strlen((char *)needle); - - BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - ret = BoyerMoore(needle, needlelen, text, textlen, bm_ctx); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - BoyerMooreCtxDeInit(bm_ctx); - return ret; -} - -static uint8_t *BoyerMooreNocaseWrapper(uint8_t *text, uint8_t *in_needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = (uint16_t)strlen((char *)in_needle); - - /* Make a copy of in_needle to be able to convert it to lowercase. */ - uint8_t *needle = SCMalloc(needlelen); - if (needle == NULL) - return NULL; - memcpy(needle, in_needle, needlelen); - - BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - ret = BoyerMooreNocase(needle, needlelen, text, textlen, bm_ctx); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - BoyerMooreCtxDeInit(bm_ctx); - free(needle); - return ret; - -} - -#ifdef ENABLE_SEARCH_STATS -/** - * \brief Unittest helper function wrappers for the search algorithms - * \param text pointer to the buffer to search in - * \param needle pointer to the pattern to search for - * \param times If you are testing performance, se the numebr of times - * that you want to repeat the search - */ -static uint8_t *BasicSearchCtxWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = strlen((char *)needle); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - /* This wrapper is a fake, no context needed! */ - ret = BasicSearch(text, textlen, needle, needlelen); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *BasicSearchNocaseCtxWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = strlen((char *)needle); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - /* This wrapper is a fake, no context needed! */ - ret = BasicSearchNocase(text, textlen, needle, needlelen); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *Bs2bmCtxWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = strlen((char *)needle); - - uint8_t badchars[ALPHABET_SIZE]; - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - /* Stats including context building */ - Bs2BmBadchars(needle, needlelen, badchars); - ret = Bs2Bm(text, textlen, needle, needlelen, badchars); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *Bs2bmNocaseCtxWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = strlen((char *)needle); - - uint8_t badchars[ALPHABET_SIZE]; - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - /* Stats including context building */ - Bs2BmBadchars(needle, needlelen, badchars); - ret = Bs2BmNocase(text, textlen, needle, needlelen, badchars); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *BoyerMooreCtxWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = strlen((char *)needle); - - BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - /* Stats including context building */ - ret = BoyerMoore(needle, needlelen, text, textlen, bm_ctx); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - BoyerMooreCtxDeInit(bm_ctx); - - return ret; -} - -static uint8_t *RawCtxWrapper(uint8_t *text, uint8_t *needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = strlen((char *)needle); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - ret = SpmSearch(text, textlen, needle, needlelen); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - return ret; -} - -static uint8_t *BoyerMooreNocaseCtxWrapper(uint8_t *text, uint8_t *in_needle, int times) -{ - uint32_t textlen = strlen((char *)text); - uint16_t needlelen = strlen((char *)in_needle); - - /* Make a copy of in_needle to be able to convert it to lowercase. */ - uint8_t *needle = SCMalloc(needlelen); - if (needle == NULL) - return NULL; - memcpy(needle, in_needle, needlelen); - - BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); - - uint8_t *ret = NULL; - int i = 0; - - CLOCK_INIT; - if (times > 1) CLOCK_START; - for (i = 0; i < times; i++) { - ret = BoyerMooreNocase(needle, needlelen, text, textlen, bm_ctx); - } - if (times > 1) { CLOCK_END; CLOCK_PRINT_SEC; }; - BoyerMooreCtxDeInit(bm_ctx); - free(needle); - return ret; - -} -#endif - -/** - * \test Generic test for BasicSearch matching - */ -static int UtilSpmBasicSearchTest01(void) -{ - uint8_t *needle = (uint8_t *)"oPqRsT"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BasicSearchWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 1; - else - return 0; -} - -/** - * \test Generic test for BasicSearch nocase matching - */ -static int UtilSpmBasicSearchNocaseTest01(void) -{ - uint8_t *needle = (uint8_t *)"OpQrSt"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BasicSearchNocaseWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 1; - else - return 0; -} - -/** - * \test Generic test for Bs2Bm matching - */ -static int UtilSpmBs2bmSearchTest01(void) -{ - uint8_t *needle = (uint8_t *)"oPqRsT"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = Bs2bmWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 1; - else - return 0; -} - -/** - * \test Generic test for Bs2Bm no case matching - */ -static int UtilSpmBs2bmSearchNocaseTest01(void) -{ - uint8_t *needle = (uint8_t *)"OpQrSt"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = Bs2bmNocaseWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 1; - else - return 0; -} - -/** - * \test Generic test for boyer moore matching - */ -static int UtilSpmBoyerMooreSearchTest01(void) -{ - uint8_t *needle = (uint8_t *)"oPqRsT"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BoyerMooreWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 1; - else - return 0; -} - -/** - * \test Generic test for boyer moore nocase matching - */ -static int UtilSpmBoyerMooreSearchNocaseTest01(void) -{ - uint8_t *needle = (uint8_t *)"OpQrSt"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 1; - else - return 0; -} - -/** - * \test issue 130 (@redmine) check to ensure that the - * problem is not the algorithm implementation - */ -static int UtilSpmBoyerMooreSearchNocaseTestIssue130(void) -{ - uint8_t *needle = (uint8_t *)"WWW-Authenticate: "; - uint8_t *text = (uint8_t *)"Date: Mon, 23 Feb 2009 13:31:49 GMT" - "Server: Apache\r\n" - "Www-authenticate: Basic realm=\"Authentification user password\"\r\n" - "Vary: accept-language,accept-charset\r\n" - "Accept-ranges: bytes\r\n" - "Connection: close\r\n" - "Content-type: text/html; charset=iso-8859-1\r\n" - "Content-language: fr\r\n" - "Expires: Mon, 23 Feb 2009 13:31:49 GMT\r\n\r\n"; - uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 1; - else - return 0; -} - -/* Generic tests that should not match */ -static int UtilSpmBasicSearchTest02(void) -{ - uint8_t *needle = (uint8_t *)"oPQRsT"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BasicSearchWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 0; - else - return 1; -} - -static int UtilSpmBasicSearchNocaseTest02(void) -{ - uint8_t *needle = (uint8_t *)"OpZrSt"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BasicSearchNocaseWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 0; - else - return 1; -} - -static int UtilSpmBs2bmSearchTest02(void) -{ - uint8_t *needle = (uint8_t *)"oPQRsT"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = Bs2bmWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 0; - else - return 1; -} - -static int UtilSpmBs2bmSearchNocaseTest02(void) -{ - uint8_t *needle = (uint8_t *)"OpZrSt"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = Bs2bmNocaseWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 0; - else - return 1; -} - -static int UtilSpmBoyerMooreSearchTest02(void) -{ - uint8_t *needle = (uint8_t *)"oPQRsT"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BoyerMooreWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 0; - else - return 1; -} - -static int UtilSpmBoyerMooreSearchNocaseTest02(void) -{ - uint8_t *needle = (uint8_t *)"OpZrSt"; - uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); - //printf("found: %s\n", found); - if (found != NULL) - return 0; - else - return 1; -} - -/** - * \test Check that all the algorithms work at any offset and any pattern length - */ -static int UtilSpmSearchOffsetsTest01(void) -{ - const char *text[26][27]; - text[0][0]="azzzzzzzzzzzzzzzzzzzzzzzzzz"; - text[0][1]="zazzzzzzzzzzzzzzzzzzzzzzzzz"; - text[0][2]="zzazzzzzzzzzzzzzzzzzzzzzzzz"; - text[0][3]="zzzazzzzzzzzzzzzzzzzzzzzzzz"; - text[0][4]="zzzzazzzzzzzzzzzzzzzzzzzzzz"; - text[0][5]="zzzzzazzzzzzzzzzzzzzzzzzzzz"; - text[0][6]="zzzzzzazzzzzzzzzzzzzzzzzzzz"; - text[0][7]="zzzzzzzazzzzzzzzzzzzzzzzzzz"; - text[0][8]="zzzzzzzzazzzzzzzzzzzzzzzzzz"; - text[0][9]="zzzzzzzzzazzzzzzzzzzzzzzzzz"; - text[0][10]="zzzzzzzzzzazzzzzzzzzzzzzzzz"; - text[0][11]="zzzzzzzzzzzazzzzzzzzzzzzzzz"; - text[0][12]="zzzzzzzzzzzzazzzzzzzzzzzzzz"; - text[0][13]="zzzzzzzzzzzzzazzzzzzzzzzzzz"; - text[0][14]="zzzzzzzzzzzzzzazzzzzzzzzzzz"; - text[0][15]="zzzzzzzzzzzzzzzazzzzzzzzzzz"; - text[0][16]="zzzzzzzzzzzzzzzzazzzzzzzzzz"; - text[0][17]="zzzzzzzzzzzzzzzzzazzzzzzzzz"; - text[0][18]="zzzzzzzzzzzzzzzzzzazzzzzzzz"; - text[0][19]="zzzzzzzzzzzzzzzzzzzazzzzzzz"; - text[0][20]="zzzzzzzzzzzzzzzzzzzzazzzzzz"; - text[0][21]="zzzzzzzzzzzzzzzzzzzzzazzzzz"; - text[0][22]="zzzzzzzzzzzzzzzzzzzzzzazzzz"; - text[0][23]="zzzzzzzzzzzzzzzzzzzzzzzazzz"; - text[0][24]="zzzzzzzzzzzzzzzzzzzzzzzzazz"; - text[0][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaz"; - text[0][26]="zzzzzzzzzzzzzzzzzzzzzzzzzza"; - text[1][0]="aBzzzzzzzzzzzzzzzzzzzzzzzzz"; - text[1][1]="zaBzzzzzzzzzzzzzzzzzzzzzzzz"; - text[1][2]="zzaBzzzzzzzzzzzzzzzzzzzzzzz"; - text[1][3]="zzzaBzzzzzzzzzzzzzzzzzzzzzz"; - text[1][4]="zzzzaBzzzzzzzzzzzzzzzzzzzzz"; - text[1][5]="zzzzzaBzzzzzzzzzzzzzzzzzzzz"; - text[1][6]="zzzzzzaBzzzzzzzzzzzzzzzzzzz"; - text[1][7]="zzzzzzzaBzzzzzzzzzzzzzzzzzz"; - text[1][8]="zzzzzzzzaBzzzzzzzzzzzzzzzzz"; - text[1][9]="zzzzzzzzzaBzzzzzzzzzzzzzzzz"; - text[1][10]="zzzzzzzzzzaBzzzzzzzzzzzzzzz"; - text[1][11]="zzzzzzzzzzzaBzzzzzzzzzzzzzz"; - text[1][12]="zzzzzzzzzzzzaBzzzzzzzzzzzzz"; - text[1][13]="zzzzzzzzzzzzzaBzzzzzzzzzzzz"; - text[1][14]="zzzzzzzzzzzzzzaBzzzzzzzzzzz"; - text[1][15]="zzzzzzzzzzzzzzzaBzzzzzzzzzz"; - text[1][16]="zzzzzzzzzzzzzzzzaBzzzzzzzzz"; - text[1][17]="zzzzzzzzzzzzzzzzzaBzzzzzzzz"; - text[1][18]="zzzzzzzzzzzzzzzzzzaBzzzzzzz"; - text[1][19]="zzzzzzzzzzzzzzzzzzzaBzzzzzz"; - text[1][20]="zzzzzzzzzzzzzzzzzzzzaBzzzzz"; - text[1][21]="zzzzzzzzzzzzzzzzzzzzzaBzzzz"; - text[1][22]="zzzzzzzzzzzzzzzzzzzzzzaBzzz"; - text[1][23]="zzzzzzzzzzzzzzzzzzzzzzzaBzz"; - text[1][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBz"; - text[1][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaB"; - text[2][0]="aBczzzzzzzzzzzzzzzzzzzzzzzz"; - text[2][1]="zaBczzzzzzzzzzzzzzzzzzzzzzz"; - text[2][2]="zzaBczzzzzzzzzzzzzzzzzzzzzz"; - text[2][3]="zzzaBczzzzzzzzzzzzzzzzzzzzz"; - text[2][4]="zzzzaBczzzzzzzzzzzzzzzzzzzz"; - text[2][5]="zzzzzaBczzzzzzzzzzzzzzzzzzz"; - text[2][6]="zzzzzzaBczzzzzzzzzzzzzzzzzz"; - text[2][7]="zzzzzzzaBczzzzzzzzzzzzzzzzz"; - text[2][8]="zzzzzzzzaBczzzzzzzzzzzzzzzz"; - text[2][9]="zzzzzzzzzaBczzzzzzzzzzzzzzz"; - text[2][10]="zzzzzzzzzzaBczzzzzzzzzzzzzz"; - text[2][11]="zzzzzzzzzzzaBczzzzzzzzzzzzz"; - text[2][12]="zzzzzzzzzzzzaBczzzzzzzzzzzz"; - text[2][13]="zzzzzzzzzzzzzaBczzzzzzzzzzz"; - text[2][14]="zzzzzzzzzzzzzzaBczzzzzzzzzz"; - text[2][15]="zzzzzzzzzzzzzzzaBczzzzzzzzz"; - text[2][16]="zzzzzzzzzzzzzzzzaBczzzzzzzz"; - text[2][17]="zzzzzzzzzzzzzzzzzaBczzzzzzz"; - text[2][18]="zzzzzzzzzzzzzzzzzzaBczzzzzz"; - text[2][19]="zzzzzzzzzzzzzzzzzzzaBczzzzz"; - text[2][20]="zzzzzzzzzzzzzzzzzzzzaBczzzz"; - text[2][21]="zzzzzzzzzzzzzzzzzzzzzaBczzz"; - text[2][22]="zzzzzzzzzzzzzzzzzzzzzzaBczz"; - text[2][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcz"; - text[2][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBc"; - text[3][0]="aBcDzzzzzzzzzzzzzzzzzzzzzzz"; - text[3][1]="zaBcDzzzzzzzzzzzzzzzzzzzzzz"; - text[3][2]="zzaBcDzzzzzzzzzzzzzzzzzzzzz"; - text[3][3]="zzzaBcDzzzzzzzzzzzzzzzzzzzz"; - text[3][4]="zzzzaBcDzzzzzzzzzzzzzzzzzzz"; - text[3][5]="zzzzzaBcDzzzzzzzzzzzzzzzzzz"; - text[3][6]="zzzzzzaBcDzzzzzzzzzzzzzzzzz"; - text[3][7]="zzzzzzzaBcDzzzzzzzzzzzzzzzz"; - text[3][8]="zzzzzzzzaBcDzzzzzzzzzzzzzzz"; - text[3][9]="zzzzzzzzzaBcDzzzzzzzzzzzzzz"; - text[3][10]="zzzzzzzzzzaBcDzzzzzzzzzzzzz"; - text[3][11]="zzzzzzzzzzzaBcDzzzzzzzzzzzz"; - text[3][12]="zzzzzzzzzzzzaBcDzzzzzzzzzzz"; - text[3][13]="zzzzzzzzzzzzzaBcDzzzzzzzzzz"; - text[3][14]="zzzzzzzzzzzzzzaBcDzzzzzzzzz"; - text[3][15]="zzzzzzzzzzzzzzzaBcDzzzzzzzz"; - text[3][16]="zzzzzzzzzzzzzzzzaBcDzzzzzzz"; - text[3][17]="zzzzzzzzzzzzzzzzzaBcDzzzzzz"; - text[3][18]="zzzzzzzzzzzzzzzzzzaBcDzzzzz"; - text[3][19]="zzzzzzzzzzzzzzzzzzzaBcDzzzz"; - text[3][20]="zzzzzzzzzzzzzzzzzzzzaBcDzzz"; - text[3][21]="zzzzzzzzzzzzzzzzzzzzzaBcDzz"; - text[3][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDz"; - text[3][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcD"; - text[4][0]="aBcDezzzzzzzzzzzzzzzzzzzzzz"; - text[4][1]="zaBcDezzzzzzzzzzzzzzzzzzzzz"; - text[4][2]="zzaBcDezzzzzzzzzzzzzzzzzzzz"; - text[4][3]="zzzaBcDezzzzzzzzzzzzzzzzzzz"; - text[4][4]="zzzzaBcDezzzzzzzzzzzzzzzzzz"; - text[4][5]="zzzzzaBcDezzzzzzzzzzzzzzzzz"; - text[4][6]="zzzzzzaBcDezzzzzzzzzzzzzzzz"; - text[4][7]="zzzzzzzaBcDezzzzzzzzzzzzzzz"; - text[4][8]="zzzzzzzzaBcDezzzzzzzzzzzzzz"; - text[4][9]="zzzzzzzzzaBcDezzzzzzzzzzzzz"; - text[4][10]="zzzzzzzzzzaBcDezzzzzzzzzzzz"; - text[4][11]="zzzzzzzzzzzaBcDezzzzzzzzzzz"; - text[4][12]="zzzzzzzzzzzzaBcDezzzzzzzzzz"; - text[4][13]="zzzzzzzzzzzzzaBcDezzzzzzzzz"; - text[4][14]="zzzzzzzzzzzzzzaBcDezzzzzzzz"; - text[4][15]="zzzzzzzzzzzzzzzaBcDezzzzzzz"; - text[4][16]="zzzzzzzzzzzzzzzzaBcDezzzzzz"; - text[4][17]="zzzzzzzzzzzzzzzzzaBcDezzzzz"; - text[4][18]="zzzzzzzzzzzzzzzzzzaBcDezzzz"; - text[4][19]="zzzzzzzzzzzzzzzzzzzaBcDezzz"; - text[4][20]="zzzzzzzzzzzzzzzzzzzzaBcDezz"; - text[4][21]="zzzzzzzzzzzzzzzzzzzzzaBcDez"; - text[4][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDe"; - text[5][0]="aBcDeFzzzzzzzzzzzzzzzzzzzzz"; - text[5][1]="zaBcDeFzzzzzzzzzzzzzzzzzzzz"; - text[5][2]="zzaBcDeFzzzzzzzzzzzzzzzzzzz"; - text[5][3]="zzzaBcDeFzzzzzzzzzzzzzzzzzz"; - text[5][4]="zzzzaBcDeFzzzzzzzzzzzzzzzzz"; - text[5][5]="zzzzzaBcDeFzzzzzzzzzzzzzzzz"; - text[5][6]="zzzzzzaBcDeFzzzzzzzzzzzzzzz"; - text[5][7]="zzzzzzzaBcDeFzzzzzzzzzzzzzz"; - text[5][8]="zzzzzzzzaBcDeFzzzzzzzzzzzzz"; - text[5][9]="zzzzzzzzzaBcDeFzzzzzzzzzzzz"; - text[5][10]="zzzzzzzzzzaBcDeFzzzzzzzzzzz"; - text[5][11]="zzzzzzzzzzzaBcDeFzzzzzzzzzz"; - text[5][12]="zzzzzzzzzzzzaBcDeFzzzzzzzzz"; - text[5][13]="zzzzzzzzzzzzzaBcDeFzzzzzzzz"; - text[5][14]="zzzzzzzzzzzzzzaBcDeFzzzzzzz"; - text[5][15]="zzzzzzzzzzzzzzzaBcDeFzzzzzz"; - text[5][16]="zzzzzzzzzzzzzzzzaBcDeFzzzzz"; - text[5][17]="zzzzzzzzzzzzzzzzzaBcDeFzzzz"; - text[5][18]="zzzzzzzzzzzzzzzzzzaBcDeFzzz"; - text[5][19]="zzzzzzzzzzzzzzzzzzzaBcDeFzz"; - text[5][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFz"; - text[5][21]="zzzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6][0]="aBcDeFgzzzzzzzzzzzzzzzzzzzz"; - text[6][1]="zaBcDeFgzzzzzzzzzzzzzzzzzzz"; - text[6][2]="zzaBcDeFgzzzzzzzzzzzzzzzzzz"; - text[6][3]="zzzaBcDeFgzzzzzzzzzzzzzzzzz"; - text[6][4]="zzzzaBcDeFgzzzzzzzzzzzzzzzz"; - text[6][5]="zzzzzaBcDeFgzzzzzzzzzzzzzzz"; - text[6][6]="zzzzzzaBcDeFgzzzzzzzzzzzzzz"; - text[6][7]="zzzzzzzaBcDeFgzzzzzzzzzzzzz"; - text[6][8]="zzzzzzzzaBcDeFgzzzzzzzzzzzz"; - text[6][9]="zzzzzzzzzaBcDeFgzzzzzzzzzzz"; - text[6][10]="zzzzzzzzzzaBcDeFgzzzzzzzzzz"; - text[6][11]="zzzzzzzzzzzaBcDeFgzzzzzzzzz"; - text[6][12]="zzzzzzzzzzzzaBcDeFgzzzzzzzz"; - text[6][13]="zzzzzzzzzzzzzaBcDeFgzzzzzzz"; - text[6][14]="zzzzzzzzzzzzzzaBcDeFgzzzzzz"; - text[6][15]="zzzzzzzzzzzzzzzaBcDeFgzzzzz"; - text[6][16]="zzzzzzzzzzzzzzzzaBcDeFgzzzz"; - text[6][17]="zzzzzzzzzzzzzzzzzaBcDeFgzzz"; - text[6][18]="zzzzzzzzzzzzzzzzzzaBcDeFgzz"; - text[6][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgz"; - text[6][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7][0]="aBcDeFgHzzzzzzzzzzzzzzzzzzz"; - text[7][1]="zaBcDeFgHzzzzzzzzzzzzzzzzzz"; - text[7][2]="zzaBcDeFgHzzzzzzzzzzzzzzzzz"; - text[7][3]="zzzaBcDeFgHzzzzzzzzzzzzzzzz"; - text[7][4]="zzzzaBcDeFgHzzzzzzzzzzzzzzz"; - text[7][5]="zzzzzaBcDeFgHzzzzzzzzzzzzzz"; - text[7][6]="zzzzzzaBcDeFgHzzzzzzzzzzzzz"; - text[7][7]="zzzzzzzaBcDeFgHzzzzzzzzzzzz"; - text[7][8]="zzzzzzzzaBcDeFgHzzzzzzzzzzz"; - text[7][9]="zzzzzzzzzaBcDeFgHzzzzzzzzzz"; - text[7][10]="zzzzzzzzzzaBcDeFgHzzzzzzzzz"; - text[7][11]="zzzzzzzzzzzaBcDeFgHzzzzzzzz"; - text[7][12]="zzzzzzzzzzzzaBcDeFgHzzzzzzz"; - text[7][13]="zzzzzzzzzzzzzaBcDeFgHzzzzzz"; - text[7][14]="zzzzzzzzzzzzzzaBcDeFgHzzzzz"; - text[7][15]="zzzzzzzzzzzzzzzaBcDeFgHzzzz"; - text[7][16]="zzzzzzzzzzzzzzzzaBcDeFgHzzz"; - text[7][17]="zzzzzzzzzzzzzzzzzaBcDeFgHzz"; - text[7][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHz"; - text[7][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8][0]="aBcDeFgHizzzzzzzzzzzzzzzzzz"; - text[8][1]="zaBcDeFgHizzzzzzzzzzzzzzzzz"; - text[8][2]="zzaBcDeFgHizzzzzzzzzzzzzzzz"; - text[8][3]="zzzaBcDeFgHizzzzzzzzzzzzzzz"; - text[8][4]="zzzzaBcDeFgHizzzzzzzzzzzzzz"; - text[8][5]="zzzzzaBcDeFgHizzzzzzzzzzzzz"; - text[8][6]="zzzzzzaBcDeFgHizzzzzzzzzzzz"; - text[8][7]="zzzzzzzaBcDeFgHizzzzzzzzzzz"; - text[8][8]="zzzzzzzzaBcDeFgHizzzzzzzzzz"; - text[8][9]="zzzzzzzzzaBcDeFgHizzzzzzzzz"; - text[8][10]="zzzzzzzzzzaBcDeFgHizzzzzzzz"; - text[8][11]="zzzzzzzzzzzaBcDeFgHizzzzzzz"; - text[8][12]="zzzzzzzzzzzzaBcDeFgHizzzzzz"; - text[8][13]="zzzzzzzzzzzzzaBcDeFgHizzzzz"; - text[8][14]="zzzzzzzzzzzzzzaBcDeFgHizzzz"; - text[8][15]="zzzzzzzzzzzzzzzaBcDeFgHizzz"; - text[8][16]="zzzzzzzzzzzzzzzzaBcDeFgHizz"; - text[8][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiz"; - text[8][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9][0]="aBcDeFgHiJzzzzzzzzzzzzzzzzz"; - text[9][1]="zaBcDeFgHiJzzzzzzzzzzzzzzzz"; - text[9][2]="zzaBcDeFgHiJzzzzzzzzzzzzzzz"; - text[9][3]="zzzaBcDeFgHiJzzzzzzzzzzzzzz"; - text[9][4]="zzzzaBcDeFgHiJzzzzzzzzzzzzz"; - text[9][5]="zzzzzaBcDeFgHiJzzzzzzzzzzzz"; - text[9][6]="zzzzzzaBcDeFgHiJzzzzzzzzzzz"; - text[9][7]="zzzzzzzaBcDeFgHiJzzzzzzzzzz"; - text[9][8]="zzzzzzzzaBcDeFgHiJzzzzzzzzz"; - text[9][9]="zzzzzzzzzaBcDeFgHiJzzzzzzzz"; - text[9][10]="zzzzzzzzzzaBcDeFgHiJzzzzzzz"; - text[9][11]="zzzzzzzzzzzaBcDeFgHiJzzzzzz"; - text[9][12]="zzzzzzzzzzzzaBcDeFgHiJzzzzz"; - text[9][13]="zzzzzzzzzzzzzaBcDeFgHiJzzzz"; - text[9][14]="zzzzzzzzzzzzzzaBcDeFgHiJzzz"; - text[9][15]="zzzzzzzzzzzzzzzaBcDeFgHiJzz"; - text[9][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJz"; - text[9][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10][0]="aBcDeFgHiJkzzzzzzzzzzzzzzzz"; - text[10][1]="zaBcDeFgHiJkzzzzzzzzzzzzzzz"; - text[10][2]="zzaBcDeFgHiJkzzzzzzzzzzzzzz"; - text[10][3]="zzzaBcDeFgHiJkzzzzzzzzzzzzz"; - text[10][4]="zzzzaBcDeFgHiJkzzzzzzzzzzzz"; - text[10][5]="zzzzzaBcDeFgHiJkzzzzzzzzzzz"; - text[10][6]="zzzzzzaBcDeFgHiJkzzzzzzzzzz"; - text[10][7]="zzzzzzzaBcDeFgHiJkzzzzzzzzz"; - text[10][8]="zzzzzzzzaBcDeFgHiJkzzzzzzzz"; - text[10][9]="zzzzzzzzzaBcDeFgHiJkzzzzzzz"; - text[10][10]="zzzzzzzzzzaBcDeFgHiJkzzzzzz"; - text[10][11]="zzzzzzzzzzzaBcDeFgHiJkzzzzz"; - text[10][12]="zzzzzzzzzzzzaBcDeFgHiJkzzzz"; - text[10][13]="zzzzzzzzzzzzzaBcDeFgHiJkzzz"; - text[10][14]="zzzzzzzzzzzzzzaBcDeFgHiJkzz"; - text[10][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkz"; - text[10][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11][0]="aBcDeFgHiJkLzzzzzzzzzzzzzzz"; - text[11][1]="zaBcDeFgHiJkLzzzzzzzzzzzzzz"; - text[11][2]="zzaBcDeFgHiJkLzzzzzzzzzzzzz"; - text[11][3]="zzzaBcDeFgHiJkLzzzzzzzzzzzz"; - text[11][4]="zzzzaBcDeFgHiJkLzzzzzzzzzzz"; - text[11][5]="zzzzzaBcDeFgHiJkLzzzzzzzzzz"; - text[11][6]="zzzzzzaBcDeFgHiJkLzzzzzzzzz"; - text[11][7]="zzzzzzzaBcDeFgHiJkLzzzzzzzz"; - text[11][8]="zzzzzzzzaBcDeFgHiJkLzzzzzzz"; - text[11][9]="zzzzzzzzzaBcDeFgHiJkLzzzzzz"; - text[11][10]="zzzzzzzzzzaBcDeFgHiJkLzzzzz"; - text[11][11]="zzzzzzzzzzzaBcDeFgHiJkLzzzz"; - text[11][12]="zzzzzzzzzzzzaBcDeFgHiJkLzzz"; - text[11][13]="zzzzzzzzzzzzzaBcDeFgHiJkLzz"; - text[11][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLz"; - text[11][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12][0]="aBcDeFgHiJkLmzzzzzzzzzzzzzz"; - text[12][1]="zaBcDeFgHiJkLmzzzzzzzzzzzzz"; - text[12][2]="zzaBcDeFgHiJkLmzzzzzzzzzzzz"; - text[12][3]="zzzaBcDeFgHiJkLmzzzzzzzzzzz"; - text[12][4]="zzzzaBcDeFgHiJkLmzzzzzzzzzz"; - text[12][5]="zzzzzaBcDeFgHiJkLmzzzzzzzzz"; - text[12][6]="zzzzzzaBcDeFgHiJkLmzzzzzzzz"; - text[12][7]="zzzzzzzaBcDeFgHiJkLmzzzzzzz"; - text[12][8]="zzzzzzzzaBcDeFgHiJkLmzzzzzz"; - text[12][9]="zzzzzzzzzaBcDeFgHiJkLmzzzzz"; - text[12][10]="zzzzzzzzzzaBcDeFgHiJkLmzzzz"; - text[12][11]="zzzzzzzzzzzaBcDeFgHiJkLmzzz"; - text[12][12]="zzzzzzzzzzzzaBcDeFgHiJkLmzz"; - text[12][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmz"; - text[12][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13][0]="aBcDeFgHiJkLmNzzzzzzzzzzzzz"; - text[13][1]="zaBcDeFgHiJkLmNzzzzzzzzzzzz"; - text[13][2]="zzaBcDeFgHiJkLmNzzzzzzzzzzz"; - text[13][3]="zzzaBcDeFgHiJkLmNzzzzzzzzzz"; - text[13][4]="zzzzaBcDeFgHiJkLmNzzzzzzzzz"; - text[13][5]="zzzzzaBcDeFgHiJkLmNzzzzzzzz"; - text[13][6]="zzzzzzaBcDeFgHiJkLmNzzzzzzz"; - text[13][7]="zzzzzzzaBcDeFgHiJkLmNzzzzzz"; - text[13][8]="zzzzzzzzaBcDeFgHiJkLmNzzzzz"; - text[13][9]="zzzzzzzzzaBcDeFgHiJkLmNzzzz"; - text[13][10]="zzzzzzzzzzaBcDeFgHiJkLmNzzz"; - text[13][11]="zzzzzzzzzzzaBcDeFgHiJkLmNzz"; - text[13][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNz"; - text[13][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14][0]="aBcDeFgHiJkLmNozzzzzzzzzzzz"; - text[14][1]="zaBcDeFgHiJkLmNozzzzzzzzzzz"; - text[14][2]="zzaBcDeFgHiJkLmNozzzzzzzzzz"; - text[14][3]="zzzaBcDeFgHiJkLmNozzzzzzzzz"; - text[14][4]="zzzzaBcDeFgHiJkLmNozzzzzzzz"; - text[14][5]="zzzzzaBcDeFgHiJkLmNozzzzzzz"; - text[14][6]="zzzzzzaBcDeFgHiJkLmNozzzzzz"; - text[14][7]="zzzzzzzaBcDeFgHiJkLmNozzzzz"; - text[14][8]="zzzzzzzzaBcDeFgHiJkLmNozzzz"; - text[14][9]="zzzzzzzzzaBcDeFgHiJkLmNozzz"; - text[14][10]="zzzzzzzzzzaBcDeFgHiJkLmNozz"; - text[14][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoz"; - text[14][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15][0]="aBcDeFgHiJkLmNoPzzzzzzzzzzz"; - text[15][1]="zaBcDeFgHiJkLmNoPzzzzzzzzzz"; - text[15][2]="zzaBcDeFgHiJkLmNoPzzzzzzzzz"; - text[15][3]="zzzaBcDeFgHiJkLmNoPzzzzzzzz"; - text[15][4]="zzzzaBcDeFgHiJkLmNoPzzzzzzz"; - text[15][5]="zzzzzaBcDeFgHiJkLmNoPzzzzzz"; - text[15][6]="zzzzzzaBcDeFgHiJkLmNoPzzzzz"; - text[15][7]="zzzzzzzaBcDeFgHiJkLmNoPzzzz"; - text[15][8]="zzzzzzzzaBcDeFgHiJkLmNoPzzz"; - text[15][9]="zzzzzzzzzaBcDeFgHiJkLmNoPzz"; - text[15][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPz"; - text[15][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoP"; - text[16][0]="aBcDeFgHiJkLmNoPqzzzzzzzzzz"; - text[16][1]="zaBcDeFgHiJkLmNoPqzzzzzzzzz"; - text[16][2]="zzaBcDeFgHiJkLmNoPqzzzzzzzz"; - text[16][3]="zzzaBcDeFgHiJkLmNoPqzzzzzzz"; - text[16][4]="zzzzaBcDeFgHiJkLmNoPqzzzzzz"; - text[16][5]="zzzzzaBcDeFgHiJkLmNoPqzzzzz"; - text[16][6]="zzzzzzaBcDeFgHiJkLmNoPqzzzz"; - text[16][7]="zzzzzzzaBcDeFgHiJkLmNoPqzzz"; - text[16][8]="zzzzzzzzaBcDeFgHiJkLmNoPqzz"; - text[16][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqz"; - text[16][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPq"; - text[17][0]="aBcDeFgHiJkLmNoPqRzzzzzzzzz"; - text[17][1]="zaBcDeFgHiJkLmNoPqRzzzzzzzz"; - text[17][2]="zzaBcDeFgHiJkLmNoPqRzzzzzzz"; - text[17][3]="zzzaBcDeFgHiJkLmNoPqRzzzzzz"; - text[17][4]="zzzzaBcDeFgHiJkLmNoPqRzzzzz"; - text[17][5]="zzzzzaBcDeFgHiJkLmNoPqRzzzz"; - text[17][6]="zzzzzzaBcDeFgHiJkLmNoPqRzzz"; - text[17][7]="zzzzzzzaBcDeFgHiJkLmNoPqRzz"; - text[17][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRz"; - text[17][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqR"; - text[18][0]="aBcDeFgHiJkLmNoPqRszzzzzzzz"; - text[18][1]="zaBcDeFgHiJkLmNoPqRszzzzzzz"; - text[18][2]="zzaBcDeFgHiJkLmNoPqRszzzzzz"; - text[18][3]="zzzaBcDeFgHiJkLmNoPqRszzzzz"; - text[18][4]="zzzzaBcDeFgHiJkLmNoPqRszzzz"; - text[18][5]="zzzzzaBcDeFgHiJkLmNoPqRszzz"; - text[18][6]="zzzzzzaBcDeFgHiJkLmNoPqRszz"; - text[18][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsz"; - text[18][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRs"; - text[19][0]="aBcDeFgHiJkLmNoPqRsTzzzzzzz"; - text[19][1]="zaBcDeFgHiJkLmNoPqRsTzzzzzz"; - text[19][2]="zzaBcDeFgHiJkLmNoPqRsTzzzzz"; - text[19][3]="zzzaBcDeFgHiJkLmNoPqRsTzzzz"; - text[19][4]="zzzzaBcDeFgHiJkLmNoPqRsTzzz"; - text[19][5]="zzzzzaBcDeFgHiJkLmNoPqRsTzz"; - text[19][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTz"; - text[19][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsT"; - text[20][0]="aBcDeFgHiJkLmNoPqRsTuzzzzzz"; - text[20][1]="zaBcDeFgHiJkLmNoPqRsTuzzzzz"; - text[20][2]="zzaBcDeFgHiJkLmNoPqRsTuzzzz"; - text[20][3]="zzzaBcDeFgHiJkLmNoPqRsTuzzz"; - text[20][4]="zzzzaBcDeFgHiJkLmNoPqRsTuzz"; - text[20][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuz"; - text[20][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTu"; - text[21][0]="aBcDeFgHiJkLmNoPqRsTuVzzzzz"; - text[21][1]="zaBcDeFgHiJkLmNoPqRsTuVzzzz"; - text[21][2]="zzaBcDeFgHiJkLmNoPqRsTuVzzz"; - text[21][3]="zzzaBcDeFgHiJkLmNoPqRsTuVzz"; - text[21][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVz"; - text[21][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuV"; - text[22][0]="aBcDeFgHiJkLmNoPqRsTuVwzzzz"; - text[22][1]="zaBcDeFgHiJkLmNoPqRsTuVwzzz"; - text[22][2]="zzaBcDeFgHiJkLmNoPqRsTuVwzz"; - text[22][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwz"; - text[22][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVw"; - text[23][0]="aBcDeFgHiJkLmNoPqRsTuVwXzzz"; - text[23][1]="zaBcDeFgHiJkLmNoPqRsTuVwXzz"; - text[23][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXz"; - text[23][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwX"; - text[24][0]="aBcDeFgHiJkLmNoPqRsTuVwXyzz"; - text[24][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyz"; - text[24][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXy"; - text[25][0]="aBcDeFgHiJkLmNoPqRsTuVwXyZz"; - text[25][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyZ"; - - const char *needle[26]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - needle[16]="aBcDeFgHiJkLmNoPq"; - needle[17]="aBcDeFgHiJkLmNoPqR"; - needle[18]="aBcDeFgHiJkLmNoPqRs"; - needle[19]="aBcDeFgHiJkLmNoPqRsT"; - needle[20]="aBcDeFgHiJkLmNoPqRsTu"; - needle[21]="aBcDeFgHiJkLmNoPqRsTuV"; - needle[22]="aBcDeFgHiJkLmNoPqRsTuVw"; - needle[23]="aBcDeFgHiJkLmNoPqRsTuVwX"; - needle[24]="aBcDeFgHiJkLmNoPqRsTuVwXy"; - needle[25]="aBcDeFgHiJkLmNoPqRsTuVwXyZ"; - - int i, j; - uint8_t *found = NULL; - for (i = 0; i < 26; i++) { - for (j = 0; j <= (26 - i); j++) { - found = BasicSearchWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i][j]); - return 0; - } - found = Bs2bmWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i][j]); - return 0; - } - found = BoyerMooreWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i][j]); - return 0; - } - } - } - return 1; -} - -/** - * \test Check that all the algorithms (no case) work at any offset and any pattern length - */ -static int UtilSpmSearchOffsetsNocaseTest01(void) -{ - const char *text[26][27]; - text[0][0]="azzzzzzzzzzzzzzzzzzzzzzzzzz"; - text[0][1]="zazzzzzzzzzzzzzzzzzzzzzzzzz"; - text[0][2]="zzazzzzzzzzzzzzzzzzzzzzzzzz"; - text[0][3]="zzzazzzzzzzzzzzzzzzzzzzzzzz"; - text[0][4]="zzzzazzzzzzzzzzzzzzzzzzzzzz"; - text[0][5]="zzzzzazzzzzzzzzzzzzzzzzzzzz"; - text[0][6]="zzzzzzazzzzzzzzzzzzzzzzzzzz"; - text[0][7]="zzzzzzzazzzzzzzzzzzzzzzzzzz"; - text[0][8]="zzzzzzzzazzzzzzzzzzzzzzzzzz"; - text[0][9]="zzzzzzzzzazzzzzzzzzzzzzzzzz"; - text[0][10]="zzzzzzzzzzazzzzzzzzzzzzzzzz"; - text[0][11]="zzzzzzzzzzzazzzzzzzzzzzzzzz"; - text[0][12]="zzzzzzzzzzzzazzzzzzzzzzzzzz"; - text[0][13]="zzzzzzzzzzzzzazzzzzzzzzzzzz"; - text[0][14]="zzzzzzzzzzzzzzazzzzzzzzzzzz"; - text[0][15]="zzzzzzzzzzzzzzzazzzzzzzzzzz"; - text[0][16]="zzzzzzzzzzzzzzzzazzzzzzzzzz"; - text[0][17]="zzzzzzzzzzzzzzzzzazzzzzzzzz"; - text[0][18]="zzzzzzzzzzzzzzzzzzazzzzzzzz"; - text[0][19]="zzzzzzzzzzzzzzzzzzzazzzzzzz"; - text[0][20]="zzzzzzzzzzzzzzzzzzzzazzzzzz"; - text[0][21]="zzzzzzzzzzzzzzzzzzzzzazzzzz"; - text[0][22]="zzzzzzzzzzzzzzzzzzzzzzazzzz"; - text[0][23]="zzzzzzzzzzzzzzzzzzzzzzzazzz"; - text[0][24]="zzzzzzzzzzzzzzzzzzzzzzzzazz"; - text[0][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaz"; - text[0][26]="zzzzzzzzzzzzzzzzzzzzzzzzzza"; - text[1][0]="aBzzzzzzzzzzzzzzzzzzzzzzzzz"; - text[1][1]="zaBzzzzzzzzzzzzzzzzzzzzzzzz"; - text[1][2]="zzaBzzzzzzzzzzzzzzzzzzzzzzz"; - text[1][3]="zzzaBzzzzzzzzzzzzzzzzzzzzzz"; - text[1][4]="zzzzaBzzzzzzzzzzzzzzzzzzzzz"; - text[1][5]="zzzzzaBzzzzzzzzzzzzzzzzzzzz"; - text[1][6]="zzzzzzaBzzzzzzzzzzzzzzzzzzz"; - text[1][7]="zzzzzzzaBzzzzzzzzzzzzzzzzzz"; - text[1][8]="zzzzzzzzaBzzzzzzzzzzzzzzzzz"; - text[1][9]="zzzzzzzzzaBzzzzzzzzzzzzzzzz"; - text[1][10]="zzzzzzzzzzaBzzzzzzzzzzzzzzz"; - text[1][11]="zzzzzzzzzzzaBzzzzzzzzzzzzzz"; - text[1][12]="zzzzzzzzzzzzaBzzzzzzzzzzzzz"; - text[1][13]="zzzzzzzzzzzzzaBzzzzzzzzzzzz"; - text[1][14]="zzzzzzzzzzzzzzaBzzzzzzzzzzz"; - text[1][15]="zzzzzzzzzzzzzzzaBzzzzzzzzzz"; - text[1][16]="zzzzzzzzzzzzzzzzaBzzzzzzzzz"; - text[1][17]="zzzzzzzzzzzzzzzzzaBzzzzzzzz"; - text[1][18]="zzzzzzzzzzzzzzzzzzaBzzzzzzz"; - text[1][19]="zzzzzzzzzzzzzzzzzzzaBzzzzzz"; - text[1][20]="zzzzzzzzzzzzzzzzzzzzaBzzzzz"; - text[1][21]="zzzzzzzzzzzzzzzzzzzzzaBzzzz"; - text[1][22]="zzzzzzzzzzzzzzzzzzzzzzaBzzz"; - text[1][23]="zzzzzzzzzzzzzzzzzzzzzzzaBzz"; - text[1][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBz"; - text[1][25]="zzzzzzzzzzzzzzzzzzzzzzzzzaB"; - text[2][0]="aBczzzzzzzzzzzzzzzzzzzzzzzz"; - text[2][1]="zaBczzzzzzzzzzzzzzzzzzzzzzz"; - text[2][2]="zzaBczzzzzzzzzzzzzzzzzzzzzz"; - text[2][3]="zzzaBczzzzzzzzzzzzzzzzzzzzz"; - text[2][4]="zzzzaBczzzzzzzzzzzzzzzzzzzz"; - text[2][5]="zzzzzaBczzzzzzzzzzzzzzzzzzz"; - text[2][6]="zzzzzzaBczzzzzzzzzzzzzzzzzz"; - text[2][7]="zzzzzzzaBczzzzzzzzzzzzzzzzz"; - text[2][8]="zzzzzzzzaBczzzzzzzzzzzzzzzz"; - text[2][9]="zzzzzzzzzaBczzzzzzzzzzzzzzz"; - text[2][10]="zzzzzzzzzzaBczzzzzzzzzzzzzz"; - text[2][11]="zzzzzzzzzzzaBczzzzzzzzzzzzz"; - text[2][12]="zzzzzzzzzzzzaBczzzzzzzzzzzz"; - text[2][13]="zzzzzzzzzzzzzaBczzzzzzzzzzz"; - text[2][14]="zzzzzzzzzzzzzzaBczzzzzzzzzz"; - text[2][15]="zzzzzzzzzzzzzzzaBczzzzzzzzz"; - text[2][16]="zzzzzzzzzzzzzzzzaBczzzzzzzz"; - text[2][17]="zzzzzzzzzzzzzzzzzaBczzzzzzz"; - text[2][18]="zzzzzzzzzzzzzzzzzzaBczzzzzz"; - text[2][19]="zzzzzzzzzzzzzzzzzzzaBczzzzz"; - text[2][20]="zzzzzzzzzzzzzzzzzzzzaBczzzz"; - text[2][21]="zzzzzzzzzzzzzzzzzzzzzaBczzz"; - text[2][22]="zzzzzzzzzzzzzzzzzzzzzzaBczz"; - text[2][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcz"; - text[2][24]="zzzzzzzzzzzzzzzzzzzzzzzzaBc"; - text[3][0]="aBcDzzzzzzzzzzzzzzzzzzzzzzz"; - text[3][1]="zaBcDzzzzzzzzzzzzzzzzzzzzzz"; - text[3][2]="zzaBcDzzzzzzzzzzzzzzzzzzzzz"; - text[3][3]="zzzaBcDzzzzzzzzzzzzzzzzzzzz"; - text[3][4]="zzzzaBcDzzzzzzzzzzzzzzzzzzz"; - text[3][5]="zzzzzaBcDzzzzzzzzzzzzzzzzzz"; - text[3][6]="zzzzzzaBcDzzzzzzzzzzzzzzzzz"; - text[3][7]="zzzzzzzaBcDzzzzzzzzzzzzzzzz"; - text[3][8]="zzzzzzzzaBcDzzzzzzzzzzzzzzz"; - text[3][9]="zzzzzzzzzaBcDzzzzzzzzzzzzzz"; - text[3][10]="zzzzzzzzzzaBcDzzzzzzzzzzzzz"; - text[3][11]="zzzzzzzzzzzaBcDzzzzzzzzzzzz"; - text[3][12]="zzzzzzzzzzzzaBcDzzzzzzzzzzz"; - text[3][13]="zzzzzzzzzzzzzaBcDzzzzzzzzzz"; - text[3][14]="zzzzzzzzzzzzzzaBcDzzzzzzzzz"; - text[3][15]="zzzzzzzzzzzzzzzaBcDzzzzzzzz"; - text[3][16]="zzzzzzzzzzzzzzzzaBcDzzzzzzz"; - text[3][17]="zzzzzzzzzzzzzzzzzaBcDzzzzzz"; - text[3][18]="zzzzzzzzzzzzzzzzzzaBcDzzzzz"; - text[3][19]="zzzzzzzzzzzzzzzzzzzaBcDzzzz"; - text[3][20]="zzzzzzzzzzzzzzzzzzzzaBcDzzz"; - text[3][21]="zzzzzzzzzzzzzzzzzzzzzaBcDzz"; - text[3][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDz"; - text[3][23]="zzzzzzzzzzzzzzzzzzzzzzzaBcD"; - text[4][0]="aBcDezzzzzzzzzzzzzzzzzzzzzz"; - text[4][1]="zaBcDezzzzzzzzzzzzzzzzzzzzz"; - text[4][2]="zzaBcDezzzzzzzzzzzzzzzzzzzz"; - text[4][3]="zzzaBcDezzzzzzzzzzzzzzzzzzz"; - text[4][4]="zzzzaBcDezzzzzzzzzzzzzzzzzz"; - text[4][5]="zzzzzaBcDezzzzzzzzzzzzzzzzz"; - text[4][6]="zzzzzzaBcDezzzzzzzzzzzzzzzz"; - text[4][7]="zzzzzzzaBcDezzzzzzzzzzzzzzz"; - text[4][8]="zzzzzzzzaBcDezzzzzzzzzzzzzz"; - text[4][9]="zzzzzzzzzaBcDezzzzzzzzzzzzz"; - text[4][10]="zzzzzzzzzzaBcDezzzzzzzzzzzz"; - text[4][11]="zzzzzzzzzzzaBcDezzzzzzzzzzz"; - text[4][12]="zzzzzzzzzzzzaBcDezzzzzzzzzz"; - text[4][13]="zzzzzzzzzzzzzaBcDezzzzzzzzz"; - text[4][14]="zzzzzzzzzzzzzzaBcDezzzzzzzz"; - text[4][15]="zzzzzzzzzzzzzzzaBcDezzzzzzz"; - text[4][16]="zzzzzzzzzzzzzzzzaBcDezzzzzz"; - text[4][17]="zzzzzzzzzzzzzzzzzaBcDezzzzz"; - text[4][18]="zzzzzzzzzzzzzzzzzzaBcDezzzz"; - text[4][19]="zzzzzzzzzzzzzzzzzzzaBcDezzz"; - text[4][20]="zzzzzzzzzzzzzzzzzzzzaBcDezz"; - text[4][21]="zzzzzzzzzzzzzzzzzzzzzaBcDez"; - text[4][22]="zzzzzzzzzzzzzzzzzzzzzzaBcDe"; - text[5][0]="aBcDeFzzzzzzzzzzzzzzzzzzzzz"; - text[5][1]="zaBcDeFzzzzzzzzzzzzzzzzzzzz"; - text[5][2]="zzaBcDeFzzzzzzzzzzzzzzzzzzz"; - text[5][3]="zzzaBcDeFzzzzzzzzzzzzzzzzzz"; - text[5][4]="zzzzaBcDeFzzzzzzzzzzzzzzzzz"; - text[5][5]="zzzzzaBcDeFzzzzzzzzzzzzzzzz"; - text[5][6]="zzzzzzaBcDeFzzzzzzzzzzzzzzz"; - text[5][7]="zzzzzzzaBcDeFzzzzzzzzzzzzzz"; - text[5][8]="zzzzzzzzaBcDeFzzzzzzzzzzzzz"; - text[5][9]="zzzzzzzzzaBcDeFzzzzzzzzzzzz"; - text[5][10]="zzzzzzzzzzaBcDeFzzzzzzzzzzz"; - text[5][11]="zzzzzzzzzzzaBcDeFzzzzzzzzzz"; - text[5][12]="zzzzzzzzzzzzaBcDeFzzzzzzzzz"; - text[5][13]="zzzzzzzzzzzzzaBcDeFzzzzzzzz"; - text[5][14]="zzzzzzzzzzzzzzaBcDeFzzzzzzz"; - text[5][15]="zzzzzzzzzzzzzzzaBcDeFzzzzzz"; - text[5][16]="zzzzzzzzzzzzzzzzaBcDeFzzzzz"; - text[5][17]="zzzzzzzzzzzzzzzzzaBcDeFzzzz"; - text[5][18]="zzzzzzzzzzzzzzzzzzaBcDeFzzz"; - text[5][19]="zzzzzzzzzzzzzzzzzzzaBcDeFzz"; - text[5][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFz"; - text[5][21]="zzzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6][0]="aBcDeFgzzzzzzzzzzzzzzzzzzzz"; - text[6][1]="zaBcDeFgzzzzzzzzzzzzzzzzzzz"; - text[6][2]="zzaBcDeFgzzzzzzzzzzzzzzzzzz"; - text[6][3]="zzzaBcDeFgzzzzzzzzzzzzzzzzz"; - text[6][4]="zzzzaBcDeFgzzzzzzzzzzzzzzzz"; - text[6][5]="zzzzzaBcDeFgzzzzzzzzzzzzzzz"; - text[6][6]="zzzzzzaBcDeFgzzzzzzzzzzzzzz"; - text[6][7]="zzzzzzzaBcDeFgzzzzzzzzzzzzz"; - text[6][8]="zzzzzzzzaBcDeFgzzzzzzzzzzzz"; - text[6][9]="zzzzzzzzzaBcDeFgzzzzzzzzzzz"; - text[6][10]="zzzzzzzzzzaBcDeFgzzzzzzzzzz"; - text[6][11]="zzzzzzzzzzzaBcDeFgzzzzzzzzz"; - text[6][12]="zzzzzzzzzzzzaBcDeFgzzzzzzzz"; - text[6][13]="zzzzzzzzzzzzzaBcDeFgzzzzzzz"; - text[6][14]="zzzzzzzzzzzzzzaBcDeFgzzzzzz"; - text[6][15]="zzzzzzzzzzzzzzzaBcDeFgzzzzz"; - text[6][16]="zzzzzzzzzzzzzzzzaBcDeFgzzzz"; - text[6][17]="zzzzzzzzzzzzzzzzzaBcDeFgzzz"; - text[6][18]="zzzzzzzzzzzzzzzzzzaBcDeFgzz"; - text[6][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgz"; - text[6][20]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7][0]="aBcDeFgHzzzzzzzzzzzzzzzzzzz"; - text[7][1]="zaBcDeFgHzzzzzzzzzzzzzzzzzz"; - text[7][2]="zzaBcDeFgHzzzzzzzzzzzzzzzzz"; - text[7][3]="zzzaBcDeFgHzzzzzzzzzzzzzzzz"; - text[7][4]="zzzzaBcDeFgHzzzzzzzzzzzzzzz"; - text[7][5]="zzzzzaBcDeFgHzzzzzzzzzzzzzz"; - text[7][6]="zzzzzzaBcDeFgHzzzzzzzzzzzzz"; - text[7][7]="zzzzzzzaBcDeFgHzzzzzzzzzzzz"; - text[7][8]="zzzzzzzzaBcDeFgHzzzzzzzzzzz"; - text[7][9]="zzzzzzzzzaBcDeFgHzzzzzzzzzz"; - text[7][10]="zzzzzzzzzzaBcDeFgHzzzzzzzzz"; - text[7][11]="zzzzzzzzzzzaBcDeFgHzzzzzzzz"; - text[7][12]="zzzzzzzzzzzzaBcDeFgHzzzzzzz"; - text[7][13]="zzzzzzzzzzzzzaBcDeFgHzzzzzz"; - text[7][14]="zzzzzzzzzzzzzzaBcDeFgHzzzzz"; - text[7][15]="zzzzzzzzzzzzzzzaBcDeFgHzzzz"; - text[7][16]="zzzzzzzzzzzzzzzzaBcDeFgHzzz"; - text[7][17]="zzzzzzzzzzzzzzzzzaBcDeFgHzz"; - text[7][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHz"; - text[7][19]="zzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8][0]="aBcDeFgHizzzzzzzzzzzzzzzzzz"; - text[8][1]="zaBcDeFgHizzzzzzzzzzzzzzzzz"; - text[8][2]="zzaBcDeFgHizzzzzzzzzzzzzzzz"; - text[8][3]="zzzaBcDeFgHizzzzzzzzzzzzzzz"; - text[8][4]="zzzzaBcDeFgHizzzzzzzzzzzzzz"; - text[8][5]="zzzzzaBcDeFgHizzzzzzzzzzzzz"; - text[8][6]="zzzzzzaBcDeFgHizzzzzzzzzzzz"; - text[8][7]="zzzzzzzaBcDeFgHizzzzzzzzzzz"; - text[8][8]="zzzzzzzzaBcDeFgHizzzzzzzzzz"; - text[8][9]="zzzzzzzzzaBcDeFgHizzzzzzzzz"; - text[8][10]="zzzzzzzzzzaBcDeFgHizzzzzzzz"; - text[8][11]="zzzzzzzzzzzaBcDeFgHizzzzzzz"; - text[8][12]="zzzzzzzzzzzzaBcDeFgHizzzzzz"; - text[8][13]="zzzzzzzzzzzzzaBcDeFgHizzzzz"; - text[8][14]="zzzzzzzzzzzzzzaBcDeFgHizzzz"; - text[8][15]="zzzzzzzzzzzzzzzaBcDeFgHizzz"; - text[8][16]="zzzzzzzzzzzzzzzzaBcDeFgHizz"; - text[8][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiz"; - text[8][18]="zzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9][0]="aBcDeFgHiJzzzzzzzzzzzzzzzzz"; - text[9][1]="zaBcDeFgHiJzzzzzzzzzzzzzzzz"; - text[9][2]="zzaBcDeFgHiJzzzzzzzzzzzzzzz"; - text[9][3]="zzzaBcDeFgHiJzzzzzzzzzzzzzz"; - text[9][4]="zzzzaBcDeFgHiJzzzzzzzzzzzzz"; - text[9][5]="zzzzzaBcDeFgHiJzzzzzzzzzzzz"; - text[9][6]="zzzzzzaBcDeFgHiJzzzzzzzzzzz"; - text[9][7]="zzzzzzzaBcDeFgHiJzzzzzzzzzz"; - text[9][8]="zzzzzzzzaBcDeFgHiJzzzzzzzzz"; - text[9][9]="zzzzzzzzzaBcDeFgHiJzzzzzzzz"; - text[9][10]="zzzzzzzzzzaBcDeFgHiJzzzzzzz"; - text[9][11]="zzzzzzzzzzzaBcDeFgHiJzzzzzz"; - text[9][12]="zzzzzzzzzzzzaBcDeFgHiJzzzzz"; - text[9][13]="zzzzzzzzzzzzzaBcDeFgHiJzzzz"; - text[9][14]="zzzzzzzzzzzzzzaBcDeFgHiJzzz"; - text[9][15]="zzzzzzzzzzzzzzzaBcDeFgHiJzz"; - text[9][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJz"; - text[9][17]="zzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10][0]="aBcDeFgHiJkzzzzzzzzzzzzzzzz"; - text[10][1]="zaBcDeFgHiJkzzzzzzzzzzzzzzz"; - text[10][2]="zzaBcDeFgHiJkzzzzzzzzzzzzzz"; - text[10][3]="zzzaBcDeFgHiJkzzzzzzzzzzzzz"; - text[10][4]="zzzzaBcDeFgHiJkzzzzzzzzzzzz"; - text[10][5]="zzzzzaBcDeFgHiJkzzzzzzzzzzz"; - text[10][6]="zzzzzzaBcDeFgHiJkzzzzzzzzzz"; - text[10][7]="zzzzzzzaBcDeFgHiJkzzzzzzzzz"; - text[10][8]="zzzzzzzzaBcDeFgHiJkzzzzzzzz"; - text[10][9]="zzzzzzzzzaBcDeFgHiJkzzzzzzz"; - text[10][10]="zzzzzzzzzzaBcDeFgHiJkzzzzzz"; - text[10][11]="zzzzzzzzzzzaBcDeFgHiJkzzzzz"; - text[10][12]="zzzzzzzzzzzzaBcDeFgHiJkzzzz"; - text[10][13]="zzzzzzzzzzzzzaBcDeFgHiJkzzz"; - text[10][14]="zzzzzzzzzzzzzzaBcDeFgHiJkzz"; - text[10][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkz"; - text[10][16]="zzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11][0]="aBcDeFgHiJkLzzzzzzzzzzzzzzz"; - text[11][1]="zaBcDeFgHiJkLzzzzzzzzzzzzzz"; - text[11][2]="zzaBcDeFgHiJkLzzzzzzzzzzzzz"; - text[11][3]="zzzaBcDeFgHiJkLzzzzzzzzzzzz"; - text[11][4]="zzzzaBcDeFgHiJkLzzzzzzzzzzz"; - text[11][5]="zzzzzaBcDeFgHiJkLzzzzzzzzzz"; - text[11][6]="zzzzzzaBcDeFgHiJkLzzzzzzzzz"; - text[11][7]="zzzzzzzaBcDeFgHiJkLzzzzzzzz"; - text[11][8]="zzzzzzzzaBcDeFgHiJkLzzzzzzz"; - text[11][9]="zzzzzzzzzaBcDeFgHiJkLzzzzzz"; - text[11][10]="zzzzzzzzzzaBcDeFgHiJkLzzzzz"; - text[11][11]="zzzzzzzzzzzaBcDeFgHiJkLzzzz"; - text[11][12]="zzzzzzzzzzzzaBcDeFgHiJkLzzz"; - text[11][13]="zzzzzzzzzzzzzaBcDeFgHiJkLzz"; - text[11][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLz"; - text[11][15]="zzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12][0]="aBcDeFgHiJkLmzzzzzzzzzzzzzz"; - text[12][1]="zaBcDeFgHiJkLmzzzzzzzzzzzzz"; - text[12][2]="zzaBcDeFgHiJkLmzzzzzzzzzzzz"; - text[12][3]="zzzaBcDeFgHiJkLmzzzzzzzzzzz"; - text[12][4]="zzzzaBcDeFgHiJkLmzzzzzzzzzz"; - text[12][5]="zzzzzaBcDeFgHiJkLmzzzzzzzzz"; - text[12][6]="zzzzzzaBcDeFgHiJkLmzzzzzzzz"; - text[12][7]="zzzzzzzaBcDeFgHiJkLmzzzzzzz"; - text[12][8]="zzzzzzzzaBcDeFgHiJkLmzzzzzz"; - text[12][9]="zzzzzzzzzaBcDeFgHiJkLmzzzzz"; - text[12][10]="zzzzzzzzzzaBcDeFgHiJkLmzzzz"; - text[12][11]="zzzzzzzzzzzaBcDeFgHiJkLmzzz"; - text[12][12]="zzzzzzzzzzzzaBcDeFgHiJkLmzz"; - text[12][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmz"; - text[12][14]="zzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13][0]="aBcDeFgHiJkLmNzzzzzzzzzzzzz"; - text[13][1]="zaBcDeFgHiJkLmNzzzzzzzzzzzz"; - text[13][2]="zzaBcDeFgHiJkLmNzzzzzzzzzzz"; - text[13][3]="zzzaBcDeFgHiJkLmNzzzzzzzzzz"; - text[13][4]="zzzzaBcDeFgHiJkLmNzzzzzzzzz"; - text[13][5]="zzzzzaBcDeFgHiJkLmNzzzzzzzz"; - text[13][6]="zzzzzzaBcDeFgHiJkLmNzzzzzzz"; - text[13][7]="zzzzzzzaBcDeFgHiJkLmNzzzzzz"; - text[13][8]="zzzzzzzzaBcDeFgHiJkLmNzzzzz"; - text[13][9]="zzzzzzzzzaBcDeFgHiJkLmNzzzz"; - text[13][10]="zzzzzzzzzzaBcDeFgHiJkLmNzzz"; - text[13][11]="zzzzzzzzzzzaBcDeFgHiJkLmNzz"; - text[13][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNz"; - text[13][13]="zzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14][0]="aBcDeFgHiJkLmNozzzzzzzzzzzz"; - text[14][1]="zaBcDeFgHiJkLmNozzzzzzzzzzz"; - text[14][2]="zzaBcDeFgHiJkLmNozzzzzzzzzz"; - text[14][3]="zzzaBcDeFgHiJkLmNozzzzzzzzz"; - text[14][4]="zzzzaBcDeFgHiJkLmNozzzzzzzz"; - text[14][5]="zzzzzaBcDeFgHiJkLmNozzzzzzz"; - text[14][6]="zzzzzzaBcDeFgHiJkLmNozzzzzz"; - text[14][7]="zzzzzzzaBcDeFgHiJkLmNozzzzz"; - text[14][8]="zzzzzzzzaBcDeFgHiJkLmNozzzz"; - text[14][9]="zzzzzzzzzaBcDeFgHiJkLmNozzz"; - text[14][10]="zzzzzzzzzzaBcDeFgHiJkLmNozz"; - text[14][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoz"; - text[14][12]="zzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15][0]="aBcDeFgHiJkLmNoPzzzzzzzzzzz"; - text[15][1]="zaBcDeFgHiJkLmNoPzzzzzzzzzz"; - text[15][2]="zzaBcDeFgHiJkLmNoPzzzzzzzzz"; - text[15][3]="zzzaBcDeFgHiJkLmNoPzzzzzzzz"; - text[15][4]="zzzzaBcDeFgHiJkLmNoPzzzzzzz"; - text[15][5]="zzzzzaBcDeFgHiJkLmNoPzzzzzz"; - text[15][6]="zzzzzzaBcDeFgHiJkLmNoPzzzzz"; - text[15][7]="zzzzzzzaBcDeFgHiJkLmNoPzzzz"; - text[15][8]="zzzzzzzzaBcDeFgHiJkLmNoPzzz"; - text[15][9]="zzzzzzzzzaBcDeFgHiJkLmNoPzz"; - text[15][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPz"; - text[15][11]="zzzzzzzzzzzaBcDeFgHiJkLmNoP"; - text[16][0]="aBcDeFgHiJkLmNoPqzzzzzzzzzz"; - text[16][1]="zaBcDeFgHiJkLmNoPqzzzzzzzzz"; - text[16][2]="zzaBcDeFgHiJkLmNoPqzzzzzzzz"; - text[16][3]="zzzaBcDeFgHiJkLmNoPqzzzzzzz"; - text[16][4]="zzzzaBcDeFgHiJkLmNoPqzzzzzz"; - text[16][5]="zzzzzaBcDeFgHiJkLmNoPqzzzzz"; - text[16][6]="zzzzzzaBcDeFgHiJkLmNoPqzzzz"; - text[16][7]="zzzzzzzaBcDeFgHiJkLmNoPqzzz"; - text[16][8]="zzzzzzzzaBcDeFgHiJkLmNoPqzz"; - text[16][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqz"; - text[16][10]="zzzzzzzzzzaBcDeFgHiJkLmNoPq"; - text[17][0]="aBcDeFgHiJkLmNoPqRzzzzzzzzz"; - text[17][1]="zaBcDeFgHiJkLmNoPqRzzzzzzzz"; - text[17][2]="zzaBcDeFgHiJkLmNoPqRzzzzzzz"; - text[17][3]="zzzaBcDeFgHiJkLmNoPqRzzzzzz"; - text[17][4]="zzzzaBcDeFgHiJkLmNoPqRzzzzz"; - text[17][5]="zzzzzaBcDeFgHiJkLmNoPqRzzzz"; - text[17][6]="zzzzzzaBcDeFgHiJkLmNoPqRzzz"; - text[17][7]="zzzzzzzaBcDeFgHiJkLmNoPqRzz"; - text[17][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRz"; - text[17][9]="zzzzzzzzzaBcDeFgHiJkLmNoPqR"; - text[18][0]="aBcDeFgHiJkLmNoPqRszzzzzzzz"; - text[18][1]="zaBcDeFgHiJkLmNoPqRszzzzzzz"; - text[18][2]="zzaBcDeFgHiJkLmNoPqRszzzzzz"; - text[18][3]="zzzaBcDeFgHiJkLmNoPqRszzzzz"; - text[18][4]="zzzzaBcDeFgHiJkLmNoPqRszzzz"; - text[18][5]="zzzzzaBcDeFgHiJkLmNoPqRszzz"; - text[18][6]="zzzzzzaBcDeFgHiJkLmNoPqRszz"; - text[18][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsz"; - text[18][8]="zzzzzzzzaBcDeFgHiJkLmNoPqRs"; - text[19][0]="aBcDeFgHiJkLmNoPqRsTzzzzzzz"; - text[19][1]="zaBcDeFgHiJkLmNoPqRsTzzzzzz"; - text[19][2]="zzaBcDeFgHiJkLmNoPqRsTzzzzz"; - text[19][3]="zzzaBcDeFgHiJkLmNoPqRsTzzzz"; - text[19][4]="zzzzaBcDeFgHiJkLmNoPqRsTzzz"; - text[19][5]="zzzzzaBcDeFgHiJkLmNoPqRsTzz"; - text[19][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTz"; - text[19][7]="zzzzzzzaBcDeFgHiJkLmNoPqRsT"; - text[20][0]="aBcDeFgHiJkLmNoPqRsTuzzzzzz"; - text[20][1]="zaBcDeFgHiJkLmNoPqRsTuzzzzz"; - text[20][2]="zzaBcDeFgHiJkLmNoPqRsTuzzzz"; - text[20][3]="zzzaBcDeFgHiJkLmNoPqRsTuzzz"; - text[20][4]="zzzzaBcDeFgHiJkLmNoPqRsTuzz"; - text[20][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuz"; - text[20][6]="zzzzzzaBcDeFgHiJkLmNoPqRsTu"; - text[21][0]="aBcDeFgHiJkLmNoPqRsTuVzzzzz"; - text[21][1]="zaBcDeFgHiJkLmNoPqRsTuVzzzz"; - text[21][2]="zzaBcDeFgHiJkLmNoPqRsTuVzzz"; - text[21][3]="zzzaBcDeFgHiJkLmNoPqRsTuVzz"; - text[21][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVz"; - text[21][5]="zzzzzaBcDeFgHiJkLmNoPqRsTuV"; - text[22][0]="aBcDeFgHiJkLmNoPqRsTuVwzzzz"; - text[22][1]="zaBcDeFgHiJkLmNoPqRsTuVwzzz"; - text[22][2]="zzaBcDeFgHiJkLmNoPqRsTuVwzz"; - text[22][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwz"; - text[22][4]="zzzzaBcDeFgHiJkLmNoPqRsTuVw"; - text[23][0]="aBcDeFgHiJkLmNoPqRsTuVwXzzz"; - text[23][1]="zaBcDeFgHiJkLmNoPqRsTuVwXzz"; - text[23][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXz"; - text[23][3]="zzzaBcDeFgHiJkLmNoPqRsTuVwX"; - text[24][0]="aBcDeFgHiJkLmNoPqRsTuVwXyzz"; - text[24][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyz"; - text[24][2]="zzaBcDeFgHiJkLmNoPqRsTuVwXy"; - text[25][0]="aBcDeFgHiJkLmNoPqRsTuVwXyZz"; - text[25][1]="zaBcDeFgHiJkLmNoPqRsTuVwXyZ"; - - const char *needle[26]; - needle[0]="A"; - needle[1]="Ab"; - needle[2]="AbC"; - needle[3]="AbCd"; - needle[4]="AbCdE"; - needle[5]="AbCdEf"; - needle[6]="AbCdEfG"; - needle[7]="AbCdEfGh"; - needle[8]="AbCdEfGhI"; - needle[9]="AbCdEfGhIJ"; - needle[10]="AbCdEfGhIjK"; - needle[11]="AbCdEfGhIjKl"; - needle[12]="AbCdEfGhIjKlM"; - needle[13]="AbCdEfGhIjKlMn"; - needle[14]="AbCdEfGhIjKlMnO"; - needle[15]="AbCdEfGhIjKlMnOp"; - needle[16]="AbCdEfGhIjKlMnOpQ"; - needle[17]="AbCdEfGhIjKlMnOpQr"; - needle[18]="AbCdEfGhIjKlMnOpQrS"; - needle[19]="AbCdEfGhIjKlMnOpQrSt"; - needle[20]="AbCdEfGhIjKlMnOpQrStU"; - needle[21]="AbCdEfGhIjKlMnOpQrStUv"; - needle[22]="AbCdEfGhIjKlMnOpQrStUvW"; - needle[23]="AbCdEfGhIjKlMnOpQrStUvWx"; - needle[24]="AbCdEfGhIjKlMnOpQrStUvWxY"; - needle[25]="AbCdEfGhIjKlMnOpQrStUvWxYZ"; - - int i, j; - uint8_t *found = NULL; - for (i = 0; i < 26; i++) { - for (j = 0; j <= (26-i); j++) { - found = BasicSearchNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i][j]); - return 0; - } - found = Bs2bmNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i][j]); - return 0; - } - found = BoyerMooreNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i][j]); - return 0; - } - } - } - return 1; -} - -#ifdef ENABLE_SEARCH_STATS -/** - * \test Give some stats - */ -static int UtilSpmSearchStatsTest01(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; - text[1]="aaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaraaaaazaaaaaaazaaaaaaaaaaaaaazaaaaaaaazaaaaaaaaazaaaaaaaaaaaaB"; - text[2]="aBaBaBaBaBaBaBaBazaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBzBaBaBaBaBaBaBzBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBazaBaBaBaBaBc"; - text[3]="aBcaBcaBcaBcaBczBcaBcaBzaBcaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBzaBcaBcaBcazcaBcaBcaBcaBcaBcD"; - text[4]="aBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDzBcDaBcDaBczaBcDaBcDaBczaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBzDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDazcDaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDaBcDaBcDe"; - text[5]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDzaBcDeaBcDezBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDezBcDeaBcDezBcDeaBczeaBcDeaBcDeaBzDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeF"; - text[6]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBczzaBcDeaBcDeaBcDzazcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBczeaBcDezzzaBcDeFg"; - text[7]="aBcDeaBczeaBcDzaBcDezBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBzDzaBcDeaBcDeazcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDzaBcDeaBcDeaBcDezBcDzaBcDeaBzDeaBcDeaBcDezBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBrDeaBcDeaBcDezzzaBcDeFgH"; - text[8]="aBcDeaBcDeaBczzaBcDeazcDeaBcDezBcDeaBcDzaBcDeaBcDeaBcDeaBczzaBcDeaBcDeaBczeaBcDeaBcDzzBcDeaBcDeaBcDzaBczeaBcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBczeaBcDeaBzDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHi"; - text[9]="aBcDeaBcDzaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeazcDeaBcDeaBcDzzBcDeaBcDeaBczeaBcDzaBcDezBcDeaBczeaBcDzaBcDezBcDeaBcDzaBczeaBcDeaBcDzaBcDeazcDeaBcDeaBcDzaBczeaBcDeaBcDzaBzDeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJ"; - text[10]="aBcDeaBcDeaBczeaBcDzaBczeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDeaBzDzaBcDeazcDeaBcDeazcDeaBcDzaBcDeazcDeaBcDeaBczzaBcDeaBcDeaBzDeaBcDeaBcDzaBczeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDeaBzDeaBcDeaBcDezzzaBcDeFgHiJk"; - text[11]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDeazcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzzBcDeaBcDeaBcDeaBcDzaBcDzaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBzDeaBcDeaBczeaBcDeazcDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkL"; - text[12]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDeazcDeaBcDeaBczeaBcDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLm"; - text[13]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmN"; - text[14]="aBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDezzzaBcDeFgHiJkLmNo"; - text[15]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of greater length (text with a lot of partial matches, worst case for a basic search):\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch:", i+1); - found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch:", i+1); - found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch:", i+1); - found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -/** - * \test Give some stats for - */ -static int UtilSpmSearchStatsTest02(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzza"; - text[1]="zzzzzzzzzzzzzzzzzzaB"; - text[2]="zzzzzzzzzzzzzzzzzzaBc"; - text[3]="zzzzzzzzzzzzzzzzzzaBcD"; - text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; - text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length:\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch:", i+1); - found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch:", i+1); - found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch:", i+1); - found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - - -static int UtilSpmSearchStatsTest03(void) -{ - char *text[16]; - text[0]="zzzzzza"; - text[1]="zzzzzzaB"; - text[2]="zzzzzzaBc"; - text[3]="zzzzzzaBcD"; - text[4]="zzzzzzaBcDe"; - text[5]="zzzzzzzzaBcDeF"; - text[6]="zzzzzzzzaBcDeFg"; - text[7]="zzzzzzzzaBcDeFgH"; - text[8]="zzzzzzzzaBcDeFgHi"; - text[9]="zzzzzzzzaBcDeFgHiJ"; - text[10]="zzzzzzzzaBcDeFgHiJk"; - text[11]="zzzzzzzzaBcDeFgHiJkL"; - text[12]="zzzzzzzzaBcDeFgHiJkLm"; - text[13]="zzzzzzzzaBcDeFgHiJkLmN"; - text[14]="zzzzzzzzaBcDeFgHiJkLmNo"; - text[15]="zzzzzzzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length (badcase for):\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch:", i+1); - found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch:", i+1); - found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch:", i+1); - found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -/** - * \test Give some stats - */ -static int UtilSpmSearchStatsTest04(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; - text[1]="aaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaraaaaazaaaaaaazaaaaaaaaaaaaaazaaaaaaaazaaaaaaaaazaaaaaaaaaaaaB"; - text[2]="aBaBaBaBaBaBaBaBazaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBzBaBaBaBaBaBaBzBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBazaBaBaBaBaBc"; - text[3]="aBcaBcaBcaBcaBczBcaBcaBzaBcaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBzaBcaBcaBcazcaBcaBcaBcaBcaBcD"; - text[4]="aBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDzBcDaBcDaBczaBcDaBcDaBczaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBzDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDazcDaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDaBcDaBcDe"; - text[5]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDzaBcDeaBcDezBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDezBcDeaBcDezBcDeaBczeaBcDeaBcDeaBzDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeF"; - text[6]="aBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBczzaBcDeaBcDeaBcDzazcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBczeaBcDezzzaBcDeFg"; - text[7]="aBcDeaBczeaBcDzaBcDezBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBzDzaBcDeaBcDeazcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDzaBcDeaBcDeaBcDezBcDzaBcDeaBzDeaBcDeaBcDezBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBrDeaBcDeaBcDezzzaBcDeFgH"; - text[8]="aBcDeaBcDeaBczzaBcDeazcDeaBcDezBcDeaBcDzaBcDeaBcDeaBcDeaBczzaBcDeaBcDeaBczeaBcDeaBcDzzBcDeaBcDeaBcDzaBczeaBcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBczeaBcDeaBzDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHi"; - text[9]="aBcDeaBcDzaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeazcDeaBcDeaBcDzzBcDeaBcDeaBczeaBcDzaBcDezBcDeaBczeaBcDzaBcDezBcDeaBcDzaBczeaBcDeaBcDzaBcDeazcDeaBcDeaBcDzaBczeaBcDeaBcDzaBzDeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJ"; - text[10]="aBcDeaBcDeaBczeaBcDzaBczeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDeaBzDzaBcDeazcDeaBcDeazcDeaBcDzaBcDeazcDeaBcDeaBczzaBcDeaBcDeaBzDeaBcDeaBcDzaBczeaBcDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDeaBzDeaBcDeaBcDezzzaBcDeFgHiJk"; - text[11]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDeazcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzzBcDeaBcDeaBcDeaBcDzaBcDzaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBzDeaBcDeaBczeaBcDeazcDeaBcDezBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkL"; - text[12]="aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDeazcDeaBcDeaBczeaBcDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLm"; - text[13]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmN"; - text[14]="aBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDezzzaBcDeFgHiJkLmNo"; - text[15]="aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmNoP"; - - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of greater length:\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i + 1); - found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); - found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); - found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with SpmSearch (Building Context):", i + 1); - found = RawCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -/** - * \test Give some stats for - */ -static int UtilSpmSearchStatsTest05(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzza"; - text[1]="zzzzzzzzzzzzzzzzzzaB"; - text[2]="zzzzzzzzzzzzzzzzzzaBc"; - text[3]="zzzzzzzzzzzzzzzzzzaBcD"; - text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; - text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length:\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i+1); - found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); - found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); - found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - - -static int UtilSpmSearchStatsTest06(void) -{ - char *text[16]; - text[0]="zzzzkzzzzzzzkzzzzzza"; - text[1]="BBBBkBBBBBBBkBBBBBaB"; - text[2]="BcBckcBcBcBckcBcBcaBc"; - text[3]="BcDBkDBcDBcDkcDBcDaBcD"; - text[4]="BcDekcDeBcDekcDezzaBcDe"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length (badcase for):\n"); - for (i = 0; i < 5; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i+1); - found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); - found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); - found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -static int UtilSpmSearchStatsTest07(void) -{ - char *text[16]; - text[0]="zzzza"; - text[1]="BBBaB"; - text[2]="bbaBc"; - text[3]="aaBcD"; - text[4]="aBcDe"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of real lower length (badcase for):\n"); - for (i = 0; i < 5; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i+1); - found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); - found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); - found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -/** - * \test Give some stats for no case algorithms - */ -static int UtilSpmNocaseSearchStatsTest01(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; - text[1]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaB"; - text[2]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBc"; - text[3]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcD"; - text[4]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDe"; - text[5]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of greater length:\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch:", i+1); - found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch:", i+1); - found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch:", i+1); - found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -static int UtilSpmNocaseSearchStatsTest02(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzza"; - text[1]="zzzzzzzzzzzzzzzzzzaB"; - text[2]="zzzzzzzzzzzzzzzzzzaBc"; - text[3]="zzzzzzzzzzzzzzzzzzaBcD"; - text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; - text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length:\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch:", i+1); - found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch:", i+1); - found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch:", i+1); - found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - - -static int UtilSpmNocaseSearchStatsTest03(void) -{ - char *text[16]; - text[0]="zzzzkzzzzzzzkzzzzzza"; - text[1]="BBBBkBBBBBBBkBBBBBaB"; - text[2]="BcBckcBcBcBckcBcBcaBc"; - text[3]="BcDBkDBcDBcDkcDBcDaBcD"; - text[4]="BcDekcDeBcDekcDezzaBcDe"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length (badcase for):\n"); - for (i = 0; i < 5; i++) { - printf("Pattern length %d with BasicSearch:", i+1); - found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch:", i+1); - found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch:", i+1); - found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -/** - * \test Give some stats for no case algorithms - */ -static int UtilSpmNocaseSearchStatsTest04(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; - text[1]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaB"; - text[2]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBc"; - text[3]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcD"; - text[4]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDe"; - text[5]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15]="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of greater length:\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i+1); - found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); - found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); - found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -static int UtilSpmNocaseSearchStatsTest05(void) -{ - char *text[16]; - text[0]="zzzzzzzzzzzzzzzzzza"; - text[1]="zzzzzzzzzzzzzzzzzzaB"; - text[2]="zzzzzzzzzzzzzzzzzzaBc"; - text[3]="zzzzzzzzzzzzzzzzzzaBcD"; - text[4]="zzzzzzzzzzzzzzzzzzaBcDe"; - text[5]="zzzzzzzzzzzzzzzzzzzzaBcDeF"; - text[6]="zzzzzzzzzzzzzzzzzzzzaBcDeFg"; - text[7]="zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; - text[8]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; - text[9]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; - text[10]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; - text[11]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; - text[12]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; - text[13]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; - text[14]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; - text[15]="zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - needle[5]="aBcDeF"; - needle[6]="aBcDeFg"; - needle[7]="aBcDeFgH"; - needle[8]="aBcDeFgHi"; - needle[9]="aBcDeFgHiJ"; - needle[10]="aBcDeFgHiJk"; - needle[11]="aBcDeFgHiJkL"; - needle[12]="aBcDeFgHiJkLm"; - needle[13]="aBcDeFgHiJkLmN"; - needle[14]="aBcDeFgHiJkLmNo"; - needle[15]="aBcDeFgHiJkLmNoP"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length:\n"); - for (i = 0; i < 16; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i+1); - found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); - found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); - found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - - -static int UtilSpmNocaseSearchStatsTest06(void) -{ - char *text[16]; - text[0]="zzzzkzzzzzzzkzzzzzza"; - text[1]="BBBBkBBBBBBBkBBBBBaB"; - text[2]="BcBckcBcBcBckcBcBcaBc"; - text[3]="BcDBkDBcDBcDkcDBcDaBcD"; - text[4]="BcDekcDeBcDekcDezzaBcDe"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of lower length (badcase for):\n"); - for (i = 0; i < 5; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i+1); - found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); - found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); - found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} - -static int UtilSpmNocaseSearchStatsTest07(void) -{ - char *text[16]; - text[0]="zzzza"; - text[1]="bbbAb"; - text[2]="bbAbC"; - text[3]="bAbCd"; - text[4]="AbCdE"; - - char *needle[16]; - needle[0]="a"; - needle[1]="aB"; - needle[2]="aBc"; - needle[3]="aBcD"; - needle[4]="aBcDe"; - - int i; - uint8_t *found = NULL; - printf("\nStats for text of real lower length (badcase for):\n"); - for (i = 0; i < 5; i++) { - printf("Pattern length %d with BasicSearch (Building Context):", i+1); - found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error1 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with Bs2BmSearch (Building Context):", i+1); - found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error2 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("Pattern length %d with BoyerMooreSearch (Building Context):", i+1); - found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); - if (found == 0) { - printf("Error3 searching for %s in text %s\n", needle[i], text[i]); - return 0; - } - printf("\n"); - } - return 1; -} -#endif - -/* Unit tests for new SPM API. */ - -#define SPM_NO_MATCH UINT32_MAX - -/* Helper structure describing a particular search. */ -typedef struct SpmTestData_ { - const char *needle; - uint16_t needle_len; - const char *haystack; - uint16_t haystack_len; - int nocase; - uint32_t match_offset; /* offset in haystack, or SPM_NO_MATCH. */ -} SpmTestData; - -/* Helper function to conduct a search with a particular SPM matcher. */ -static int SpmTestSearch(const SpmTestData *d, uint8_t matcher) -{ - int ret = 1; - SpmGlobalThreadCtx *global_thread_ctx = NULL; - SpmThreadCtx *thread_ctx = NULL; - SpmCtx *ctx = NULL; - uint8_t *found = NULL; - - global_thread_ctx = SpmInitGlobalThreadCtx(matcher); - if (global_thread_ctx == NULL) { - ret = 0; - goto exit; - } - - ctx = SpmInitCtx((const uint8_t *)d->needle, d->needle_len, d->nocase, - global_thread_ctx); - if (ctx == NULL) { - ret = 0; - goto exit; - } - - thread_ctx = SpmMakeThreadCtx(global_thread_ctx); - if (thread_ctx == NULL) { - ret = 0; - goto exit; - } - - found = SpmScan(ctx, thread_ctx, (const uint8_t *)d->haystack, - d->haystack_len); - if (found == NULL) { - if (d->match_offset != SPM_NO_MATCH) { - printf(" should have matched at %" PRIu32 " but didn't\n", - d->match_offset); - ret = 0; - } - } else { - uint32_t offset = (uint32_t)(found - (const uint8_t *)d->haystack); - if (offset != d->match_offset) { - printf(" should have matched at %" PRIu32 - " but matched at %" PRIu32 "\n", - d->match_offset, offset); - ret = 0; - } - } - -exit: - SpmDestroyCtx(ctx); - SpmDestroyThreadCtx(thread_ctx); - SpmDestroyGlobalThreadCtx(global_thread_ctx); - return ret; -} - -static int SpmSearchTest01(void) { - SpmTableSetup(); - printf("\n"); - - /* Each of the following tests will be run against every registered SPM - * algorithm. */ - - static const SpmTestData data[] = { - /* Some trivial single-character case/nocase tests */ - {"a", 1, "a", 1, 0, 0}, - {"a", 1, "A", 1, 1, 0}, - {"A", 1, "A", 1, 0, 0}, - {"A", 1, "a", 1, 1, 0}, - {"a", 1, "A", 1, 0, SPM_NO_MATCH}, - {"A", 1, "a", 1, 0, SPM_NO_MATCH}, - /* Nulls and odd characters */ - {"\x00", 1, "test\x00test", 9, 0, 4}, - {"\x00", 1, "testtest", 8, 0, SPM_NO_MATCH}, - {"\n", 1, "new line\n", 9, 0, 8}, - {"\n", 1, "new line\x00\n", 10, 0, 9}, - {"\xff", 1, "abcdef\xff", 7, 0, 6}, - {"\xff", 1, "abcdef\xff", 7, 1, 6}, - {"$", 1, "dollar$", 7, 0, 6}, - {"^", 1, "caret^", 6, 0, 5}, - /* Longer literals */ - {"Suricata", 8, "This is a Suricata test", 23, 0, 10}, - {"Suricata", 8, "This is a suricata test", 23, 1, 10}, - {"Suricata", 8, "This is a suriCATA test", 23, 1, 10}, - {"suricata", 8, "This is a Suricata test", 23, 0, SPM_NO_MATCH}, - {"Suricata", 8, "This is a Suricat_ test", 23, 0, SPM_NO_MATCH}, - {"Suricata", 8, "This is a _uricata test", 23, 0, SPM_NO_MATCH}, - /* First occurrence with the correct case should match */ - {"foo", 3, "foofoofoo", 9, 0, 0}, - {"foo", 3, "_foofoofoo", 9, 0, 1}, - {"FOO", 3, "foofoofoo", 9, 1, 0}, - {"FOO", 3, "_foofoofoo", 9, 1, 1}, - {"FOO", 3, "foo Foo FOo fOo foO FOO", 23, 0, 20}, - {"foo", 3, "Foo FOo fOo foO FOO foo", 23, 0, 20}, - }; - - int ret = 1; - - uint8_t matcher; - for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { - const SpmTableElmt *m = &spm_table[matcher]; - if (m->name == NULL) { - continue; - } - printf("matcher: %s\n", m->name); - - uint32_t i; - for (i = 0; i < sizeof(data)/sizeof(data[0]); i++) { - const SpmTestData *d = &data[i]; - if (SpmTestSearch(d, matcher) == 0) { - printf(" test %" PRIu32 ": fail\n", i); - ret = 0; - } - } - printf(" %" PRIu32 " tests passed\n", i); - } - - return ret; -} - -static int SpmSearchTest02(void) { - SpmTableSetup(); - printf("\n"); - - /* Test that we can find needles of various lengths at various alignments - * in the haystack. Note that these are passed to strlen. */ - - static const char* needles[] = { - /* Single bytes */ - "a", "b", "c", ":", "/", "\x7f", "\xff", - /* Repeats */ - "aa", "aaa", "aaaaaaaaaaaaaaaaaaaaaaa", - /* Longer literals */ - "suricata", "meerkat", "aardvark", "raptor", "marmot", "lemming", - /* Mixed case */ - "Suricata", "CAPS LOCK", "mIxEd cAsE", - }; - - int ret = 1; - - uint8_t matcher; - for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { - const SpmTableElmt *m = &spm_table[matcher]; - if (m->name == NULL) { - continue; - } - printf("matcher: %s\n", m->name); - - SpmTestData d; - - uint32_t i; - for (i = 0; i < sizeof(needles) / sizeof(needles[0]); i++) { - const char *needle = needles[i]; - uint16_t prefix; - for (prefix = 0; prefix < 32; prefix++) { - d.needle = needle; - d.needle_len = (uint16_t)strlen(needle); - uint16_t haystack_len = prefix + d.needle_len; - char *haystack = SCMalloc(haystack_len); - if (haystack == NULL) { - printf("alloc failure\n"); - return 0; - } - memset(haystack, ' ', haystack_len); - memcpy(haystack + prefix, d.needle, d.needle_len); - d.haystack = haystack; - d.haystack_len = haystack_len; - d.nocase = 0; - d.match_offset = prefix; - - /* Case-sensitive scan */ - if (SpmTestSearch(&d, matcher) == 0) { - printf(" test %" PRIu32 ": fail (case-sensitive)\n", i); - ret = 0; - } - - /* Case-insensitive scan */ - d.nocase = 1; - uint16_t j; - for (j = 0; j < haystack_len; j++) { - haystack[j] = u8_toupper(haystack[j]); - } - if (SpmTestSearch(&d, matcher) == 0) { - printf(" test %" PRIu32 ": fail (case-insensitive)\n", i); - ret = 0; - } - - SCFree(haystack); - } - } - printf(" %" PRIu32 " tests passed\n", i); - } - - return ret; -} - -/* Register unittests */ -void UtilSpmSearchRegistertests(void) -{ - /* Generic tests */ - UtRegisterTest("UtilSpmBasicSearchTest01", UtilSpmBasicSearchTest01); - UtRegisterTest("UtilSpmBasicSearchNocaseTest01", - UtilSpmBasicSearchNocaseTest01); - - UtRegisterTest("UtilSpmBs2bmSearchTest01", UtilSpmBs2bmSearchTest01); - UtRegisterTest("UtilSpmBs2bmSearchNocaseTest01", - UtilSpmBs2bmSearchNocaseTest01); - - UtRegisterTest("UtilSpmBoyerMooreSearchTest01", - UtilSpmBoyerMooreSearchTest01); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest01", - UtilSpmBoyerMooreSearchNocaseTest01); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTestIssue130", - UtilSpmBoyerMooreSearchNocaseTestIssue130); - - UtRegisterTest("UtilSpmBs2bmSearchTest02", UtilSpmBs2bmSearchTest02); - UtRegisterTest("UtilSpmBs2bmSearchNocaseTest02", - UtilSpmBs2bmSearchNocaseTest02); - - UtRegisterTest("UtilSpmBasicSearchTest02", UtilSpmBasicSearchTest02); - UtRegisterTest("UtilSpmBasicSearchNocaseTest02", - UtilSpmBasicSearchNocaseTest02); - - UtRegisterTest("UtilSpmBoyerMooreSearchTest02", - UtilSpmBoyerMooreSearchTest02); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest02", - UtilSpmBoyerMooreSearchNocaseTest02); - - /* test matches at any offset */ - UtRegisterTest("UtilSpmSearchOffsetsTest01", UtilSpmSearchOffsetsTest01); - UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", - UtilSpmSearchOffsetsNocaseTest01); - - /* new SPM API */ - UtRegisterTest("SpmSearchTest01", SpmSearchTest01); - UtRegisterTest("SpmSearchTest02", SpmSearchTest02); - -#ifdef ENABLE_SEARCH_STATS - /* Give some stats searching given a prepared context (look at the wrappers) */ - UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01); - UtRegisterTest("UtilSpmSearchStatsTest02", UtilSpmSearchStatsTest02); - UtRegisterTest("UtilSpmSearchStatsTest03", UtilSpmSearchStatsTest03); - - UtRegisterTest("UtilSpmNocaseSearchStatsTest01", - UtilSpmNocaseSearchStatsTest01); - UtRegisterTest("UtilSpmNocaseSearchStatsTest02", - UtilSpmNocaseSearchStatsTest02); - UtRegisterTest("UtilSpmNocaseSearchStatsTest03", - UtilSpmNocaseSearchStatsTest03); - - /* Stats building context and searching */ - UtRegisterTest("UtilSpmSearchStatsTest04", UtilSpmSearchStatsTest04); - UtRegisterTest("UtilSpmSearchStatsTest05", UtilSpmSearchStatsTest05); - UtRegisterTest("UtilSpmSearchStatsTest06", UtilSpmSearchStatsTest06); - UtRegisterTest("UtilSpmSearchStatsTest07", UtilSpmSearchStatsTest07); - - UtRegisterTest("UtilSpmNocaseSearchStatsTest04", - UtilSpmNocaseSearchStatsTest04); - UtRegisterTest("UtilSpmNocaseSearchStatsTest05", - UtilSpmNocaseSearchStatsTest05); - UtRegisterTest("UtilSpmNocaseSearchStatsTest06", - UtilSpmNocaseSearchStatsTest06); - UtRegisterTest("UtilSpmNocaseSearchStatsTest07", - UtilSpmNocaseSearchStatsTest07); - -#endif -} -#endif diff --git a/src/util-spm.h b/src/util-spm.h deleted file mode 100644 index 9893dcd4222e..000000000000 --- a/src/util-spm.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - */ - -#ifndef __UTIL_SPM_H__ -#define __UTIL_SPM_H__ - -#include "util-spm-bs.h" - -enum { - SPM_BM, /* Boyer-Moore */ - SPM_HS, /* Hyperscan */ - /* Other SPM matchers will go here. */ - SPM_TABLE_SIZE -}; - -uint8_t SinglePatternMatchDefaultMatcher(void); - -/** Structure holding an immutable "built" SPM matcher (such as the Boyer-Moore - * tables, Hyperscan database etc) that is passed to the Scan call. */ -typedef struct SpmCtx_ { - uint8_t matcher; - void *ctx; -} SpmCtx; - -/** Structure holding a global prototype for per-thread scratch space, passed - * to each InitCtx call. */ -typedef struct SpmGlobalThreadCtx_ { - uint8_t matcher; - void *ctx; -} SpmGlobalThreadCtx; - -/** Structure holding some mutable per-thread space for use by a matcher at - * scan time. Constructed from SpmGlobalThreadCtx by the MakeThreadCtx call. */ -typedef struct SpmThreadCtx_ { - uint8_t matcher; - void *ctx; -} SpmThreadCtx; - -typedef struct SpmTableElmt_ { - const char *name; - SpmGlobalThreadCtx *(*InitGlobalThreadCtx)(void); - void (*DestroyGlobalThreadCtx)(SpmGlobalThreadCtx *g_thread_ctx); - SpmThreadCtx *(*MakeThreadCtx)(const SpmGlobalThreadCtx *g_thread_ctx); - void (*DestroyThreadCtx)(SpmThreadCtx *thread_ctx); - SpmCtx *(*InitCtx)(const uint8_t *needle, uint16_t needle_len, int nocase, - SpmGlobalThreadCtx *g_thread_ctx); - void (*DestroyCtx)(SpmCtx *); - uint8_t *(*Scan)(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, - const uint8_t *haystack, uint32_t haystack_len); -} SpmTableElmt; - -extern SpmTableElmt spm_table[SPM_TABLE_SIZE]; - -void SpmTableSetup(void); - -SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint8_t matcher); - -void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *g_thread_ctx); - -SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *g_thread_ctx); - -void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx); - -SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, - SpmGlobalThreadCtx *g_thread_ctx); - -void SpmDestroyCtx(SpmCtx *ctx); - -uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, - const uint8_t *haystack, uint32_t haystack_len); - -/** Default algorithm to use: Boyer Moore */ -uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); -uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); -uint8_t *BoyerMooreSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); -uint8_t *BoyerMooreNocaseSearch(const uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); - -/* Macros for automatic algorithm selection (use them only when you can't store the context) */ -#define SpmSearch(text, textlen, needle, needlelen) ({\ - uint8_t *mfound; \ - if (needlelen < 4 && textlen < 512) \ - mfound = BasicSearch(text, textlen, needle, needlelen); \ - else if (needlelen < 4) \ - mfound = BasicSearch(text, textlen, needle, needlelen); \ - else \ - mfound = BoyerMooreSearch(text, textlen, needle, needlelen); \ - mfound; \ - }) - -#define SpmNocaseSearch(text, textlen, needle, needlelen) ({\ - uint8_t *mfound; \ - if (needlelen < 4 && textlen < 512) \ - mfound = BasicSearchNocase(text, textlen, needle, needlelen); \ - else if (needlelen < 4) \ - mfound = BasicSearchNocase(text, textlen, needle, needlelen); \ - else \ - mfound = BoyerMooreNocaseSearch(text, textlen, needle, needlelen); \ - mfound; \ - }) - -#ifdef UNITTESTS -void UtilSpmSearchRegistertests(void); -#endif -#endif /* __UTIL_SPM_H__ */ diff --git a/src/util-storage.c b/src/util-storage.c deleted file mode 100644 index 493b139ee85f..000000000000 --- a/src/util-storage.c +++ /dev/null @@ -1,409 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Storage API - */ - -#include "suricata-common.h" -#include "util-unittest.h" -#include "util-storage.h" -#include "util-debug.h" - -typedef struct StorageMapping_ { - const char *name; - StorageEnum type; // host, flow, tx, stream, ssn, etc - unsigned int size; - void *(*Alloc)(unsigned int); - void (*Free)(void *); -} StorageMapping; - -/** \brief list of StorageMapping used at registration time */ -typedef struct StorageList_ { - StorageMapping map; - int id; - struct StorageList_ *next; -} StorageList; - -static StorageList *storage_list = NULL; -static int storage_max_id[STORAGE_MAX]; -static int storage_registration_closed = 0; -static StorageMapping **storage_map = NULL; - -static const char *StoragePrintType(StorageEnum type) -{ - switch(type) { - case STORAGE_HOST: - return "host"; - case STORAGE_FLOW: - return "flow"; - case STORAGE_IPPAIR: - return "ippair"; - case STORAGE_DEVICE: - return "livedevice"; - case STORAGE_MAX: - return "max"; - } - return "invalid"; -} - -void StorageInit(void) -{ - memset(&storage_max_id, 0x00, sizeof(storage_max_id)); - storage_list = NULL; - storage_map = NULL; - storage_registration_closed = 0; -} - -void StorageCleanup(void) -{ - if (storage_map) { - int i; - for (i = 0; i < STORAGE_MAX; i++) { - if (storage_map[i] != NULL) { - SCFree(storage_map[i]); - storage_map[i] = NULL; - } - } - SCFree(storage_map); - storage_map = NULL; - } - - StorageList *entry = storage_list; - while (entry) { - StorageList *next = entry->next; - SCFree(entry); - entry = next; - } - - storage_list = NULL; -} - -int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)) -{ - if (storage_registration_closed) - return -1; - - if (type >= STORAGE_MAX || name == NULL || strlen(name) == 0 || - size == 0 || (size != sizeof(void *) && Alloc == NULL) || Free == NULL) - return -1; - - StorageList *list = storage_list; - while (list) { - if (strcmp(name, list->map.name) == 0 && type == list->map.type) { - SCLogError("storage for type \"%s\" with " - "name \"%s\" already registered", - StoragePrintType(type), name); - return -1; - } - - list = list->next; - } - - StorageList *entry = SCCalloc(1, sizeof(StorageList)); - if (unlikely(entry == NULL)) - return -1; - - entry->map.type = type; - entry->map.name = name; - entry->map.size = size; - entry->map.Alloc = Alloc; - entry->map.Free = Free; - - entry->id = storage_max_id[type]++; - entry->next = storage_list; - storage_list = entry; - - return entry->id; -} - -int StorageFinalize(void) -{ - int count = 0; - int i; - - storage_registration_closed = 1; - - for (i = 0; i < STORAGE_MAX; i++) { - if (storage_max_id[i] > 0) - count++; - } - if (count == 0) - return 0; - - storage_map = SCCalloc(STORAGE_MAX, sizeof(StorageMapping *)); - if (unlikely(storage_map == NULL)) { - return -1; - } - - for (i = 0; i < STORAGE_MAX; i++) { - if (storage_max_id[i] > 0) { - storage_map[i] = SCCalloc(storage_max_id[i], sizeof(StorageMapping)); - if (storage_map[i] == NULL) - return -1; - } - } - - StorageList *entry = storage_list; - while (entry) { - if (storage_map[entry->map.type] != NULL) { - storage_map[entry->map.type][entry->id].name = entry->map.name; - storage_map[entry->map.type][entry->id].type = entry->map.type; - storage_map[entry->map.type][entry->id].size = entry->map.size; - storage_map[entry->map.type][entry->id].Alloc = entry->map.Alloc; - storage_map[entry->map.type][entry->id].Free = entry->map.Free; - } - - StorageList *next = entry->next; - SCFree(entry); - entry = next; - }; - storage_list = NULL; - -#ifdef DEBUG - for (i = 0; i < STORAGE_MAX; i++) { - if (storage_map[i] == NULL) - continue; - - int j; - for (j = 0; j < storage_max_id[i]; j++) { - StorageMapping *m = &storage_map[i][j]; - SCLogDebug("type \"%s\" name \"%s\" size \"%"PRIuMAX"\"", - StoragePrintType(m->type), m->name, (uintmax_t)m->size); - } - } -#endif - return 0; -} - -unsigned int StorageGetCnt(StorageEnum type) -{ - return storage_max_id[type]; -} - -/** \brief get the size of the void array used to store - * the pointers - * \retval size size in bytes, can return 0 if not storage is needed - * - * \todo we could return -1 when registration isn't closed yet, however - * this will break lots of tests currently, so not doing it now */ -unsigned int StorageGetSize(StorageEnum type) -{ - return storage_max_id[type] * sizeof(void *); -} - -void *StorageGetById(const Storage *storage, const StorageEnum type, const int id) -{ -#ifdef DEBUG - BUG_ON(!storage_registration_closed); -#endif - SCLogDebug("storage %p id %d", storage, id); - if (storage == NULL) - return NULL; - return storage[id].ptr; -} - -int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr) -{ -#ifdef DEBUG - BUG_ON(!storage_registration_closed); -#endif - SCLogDebug("storage %p id %d", storage, id); - if (storage == NULL) - return -1; - storage[id].ptr = ptr; - return 0; -} - -void *StorageAllocByIdPrealloc(Storage *storage, StorageEnum type, int id) -{ -#ifdef DEBUG - BUG_ON(!storage_registration_closed); -#endif - SCLogDebug("storage %p id %d", storage, id); - - StorageMapping *map = &storage_map[type][id]; - if (storage[id].ptr == NULL && map->Alloc != NULL) { - storage[id].ptr = map->Alloc(map->size); - if (storage[id].ptr == NULL) { - return NULL; - } - } - - return storage[id].ptr; -} - -void StorageFreeById(Storage *storage, StorageEnum type, int id) -{ -#ifdef DEBUG - BUG_ON(!storage_registration_closed); -#endif -#ifdef UNITTESTS - if (storage_map == NULL) - return; -#endif - SCLogDebug("storage %p id %d", storage, id); - - Storage *store = storage; - if (store != NULL) { - SCLogDebug("store %p", store); - if (store[id].ptr != NULL) { - StorageMapping *map = &storage_map[type][id]; - map->Free(store[id].ptr); - store[id].ptr = NULL; - } - } -} - -void StorageFreeAll(Storage *storage, StorageEnum type) -{ - if (storage == NULL) - return; -#ifdef DEBUG - BUG_ON(!storage_registration_closed); -#endif -#ifdef UNITTESTS - if (storage_map == NULL) - return; -#endif - - Storage *store = storage; - int i; - for (i = 0; i < storage_max_id[type]; i++) { - if (store[i].ptr != NULL) { - StorageMapping *map = &storage_map[type][i]; - map->Free(store[i].ptr); - store[i].ptr = NULL; - } - } -} - -#ifdef UNITTESTS - -static void *StorageTestAlloc(unsigned int size) -{ - void *x = SCMalloc(size); - return x; -} -static void StorageTestFree(void *x) -{ - if (x) - SCFree(x); -} - -static int StorageTest01(void) -{ - StorageInit(); - - int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree); - if (id < 0) - goto error; - id = StorageRegister(STORAGE_HOST, "variable", 24, StorageTestAlloc, StorageTestFree); - if (id < 0) - goto error; - id = StorageRegister(STORAGE_FLOW, "store", sizeof(void *), StorageTestAlloc, StorageTestFree); - if (id < 0) - goto error; - - if (StorageFinalize() < 0) - goto error; - - StorageCleanup(); - return 1; -error: - StorageCleanup(); - return 0; -} - -static int StorageTest03(void) -{ - StorageInit(); - - int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree); - if (id < 0) - goto error; - id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed: "); - goto error; - } - - id = StorageRegister(STORAGE_HOST, "test1", 6, NULL, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed (2): "); - goto error; - } - - id = StorageRegister(STORAGE_HOST, "test2", 8, StorageTestAlloc, NULL); - if (id != -1) { - printf("duplicate registration should have failed (3): "); - goto error; - } - - id = StorageRegister(STORAGE_HOST, "test3", 0, StorageTestAlloc, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed (4): "); - goto error; - } - - id = StorageRegister(STORAGE_HOST, "", 8, StorageTestAlloc, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed (5): "); - goto error; - } - - id = StorageRegister(STORAGE_HOST, NULL, 8, StorageTestAlloc, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed (6): "); - goto error; - } - - id = StorageRegister(STORAGE_MAX, "test4", 8, StorageTestAlloc, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed (7): "); - goto error; - } - - id = StorageRegister(38, "test5", 8, StorageTestAlloc, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed (8): "); - goto error; - } - - id = StorageRegister(-1, "test6", 8, StorageTestAlloc, StorageTestFree); - if (id != -1) { - printf("duplicate registration should have failed (9): "); - goto error; - } - - StorageCleanup(); - return 1; -error: - StorageCleanup(); - return 0; -} - -void StorageRegisterTests(void) -{ - UtRegisterTest("StorageTest01", StorageTest01); - UtRegisterTest("StorageTest03", StorageTest03); -} -#endif diff --git a/src/util-storage.h b/src/util-storage.h deleted file mode 100644 index 6866874f7deb..000000000000 --- a/src/util-storage.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Storage API - */ - -#ifndef __UTIL_STORAGE_H__ -#define __UTIL_STORAGE_H__ - -typedef enum StorageEnum_ { - STORAGE_HOST, - STORAGE_FLOW, - STORAGE_IPPAIR, - STORAGE_DEVICE, - - STORAGE_MAX, -} StorageEnum; - -/** void ptr array for now */ -typedef struct Storage { - void *ptr; -} Storage; - -void StorageInit(void); -void StorageCleanup(void); - -/** \brief Register new storage - * - * \param type type from StorageEnum - * \param name name - * \param size size of the per instance storage - * \param Alloc alloc function for per instance storage - * \param Free free function for per instance storage - * - * \note if size == ptr size (so sizeof(void *)) and Alloc == NULL the API just - * gives the caller a ptr to store something it alloc'ed itself. - */ -int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)); -int StorageFinalize(void); - -unsigned int StorageGetCnt(const StorageEnum type); -unsigned int StorageGetSize(const StorageEnum type); - -/** \brief get storage for id */ -void *StorageGetById(const Storage *storage, const StorageEnum type, const int id); -/** \brief set storage for id */ -int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr); - -/** \brief AllocById func for prealloc'd base storage (storage ptrs are part - * of another memory block) */ -void *StorageAllocByIdPrealloc(Storage *storage, StorageEnum type, int id); -void StorageFreeById(Storage *storage, const StorageEnum type, const int id); -void StorageFreeAll(Storage *storage, const StorageEnum type); - -void StorageRegisterTests(void); -#endif diff --git a/src/util-streaming-buffer.c b/src/util-streaming-buffer.c deleted file mode 100644 index 7608b5082109..000000000000 --- a/src/util-streaming-buffer.c +++ /dev/null @@ -1,2334 +0,0 @@ -/* Copyright (C) 2015-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "suricata-common.h" -#include "util-streaming-buffer.h" -#include "util-unittest.h" -#include "util-print.h" -#include "util-validate.h" -#include "util-debug.h" -#include "util-error.h" - -static void ListRegions(StreamingBuffer *sb); - -#define DUMP_REGIONS 0 // set to 1 to dump a visual representation of the regions list and sbb tree. - -/** - * \file - * - * \author Victor Julien - * - * \brief Streaming Buffer API - */ - -static void *ReallocFunc(void *ptr, const size_t size) -{ - void *ptrmem = SCRealloc(ptr, size); - if (unlikely(ptrmem == NULL)) { - sc_errno = SC_ENOMEM; - } - return ptrmem; -} - -static void *CallocFunc(const size_t nm, const size_t sz) -{ - void *ptrmem = SCCalloc(nm, sz); - if (unlikely(ptrmem == NULL)) { - sc_errno = SC_ENOMEM; - } - return ptrmem; -} - -/* memory handling wrappers. If config doesn't define it's own set of - * functions, use the defaults */ -// TODO the default allocators don't set `sc_errno` yet. -#define CALLOC(cfg, n, s) (cfg)->Calloc ? (cfg)->Calloc((n), (s)) : CallocFunc((n), (s)) -#define REALLOC(cfg, ptr, orig_s, s) \ - (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : ReallocFunc((ptr), (s)) -#define FREE(cfg, ptr, s) \ - (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr)) - -static void SBBFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg); - -RB_GENERATE(SBB, StreamingBufferBlock, rb, SBBCompare); - -int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b) -{ - SCLogDebug("a %" PRIu64 " len %u, b %" PRIu64 " len %u", a->offset, a->len, b->offset, b->len); - - if (a->offset > b->offset) - SCReturnInt(1); - else if (a->offset < b->offset) - SCReturnInt(-1); - else { - if (a->len == 0 || b->len == 0 || a->len == b->len) - SCReturnInt(0); - else if (a->len > b->len) - SCReturnInt(1); - else - SCReturnInt(-1); - } -} - -/* inclusive compare function that also considers the right edge, - * not just the offset. */ -static inline int InclusiveCompare(StreamingBufferBlock *lookup, StreamingBufferBlock *intree) { - const uint64_t lre = lookup->offset + lookup->len; - const uint64_t tre = intree->offset + intree->len; - if (lre <= intree->offset) // entirely before - return -1; - else if (lookup->offset < tre && lre <= tre) // (some) overlap - return 0; - else - return 1; // entirely after -} - -StreamingBufferBlock *SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm) -{ - SCLogDebug("looking up %" PRIu64, elm->offset); - - struct StreamingBufferBlock *tmp = RB_ROOT(head); - struct StreamingBufferBlock *res = NULL; - while (tmp) { - SCLogDebug("compare with %" PRIu64 "/%u", tmp->offset, tmp->len); - const int comp = InclusiveCompare(elm, tmp); - SCLogDebug("compare result: %d", comp); - if (comp < 0) { - res = tmp; - tmp = RB_LEFT(tmp, rb); - } else if (comp > 0) { - tmp = RB_RIGHT(tmp, rb); - } else { - return tmp; - } - } - return res; -} - -/** \interal - * \brief does data region intersect with list region 'r' - * Takes the max gap into account. - */ -static inline bool RegionsIntersect(const StreamingBuffer *sb, const StreamingBufferConfig *cfg, - const StreamingBufferRegion *r, const uint64_t offset, const uint64_t re) -{ - /* create the data range for the region, adding the max gap */ - const uint64_t reg_o = - r->stream_offset > cfg->region_gap ? (r->stream_offset - cfg->region_gap) : 0; - const uint64_t reg_re = r->stream_offset + r->buf_size + cfg->region_gap; - SCLogDebug("r %p: %" PRIu64 "/%" PRIu64 " - adjusted %" PRIu64 "/%" PRIu64, r, r->stream_offset, - r->stream_offset + r->buf_size, reg_o, reg_re); - /* check if data range intersects with region range */ - if (offset >= reg_o && offset <= reg_re) { - SCLogDebug("r %p is in-scope", r); - return true; - } - if (re >= reg_o && re <= reg_re) { - SCLogDebug("r %p is in-scope: %" PRIu64 " >= %" PRIu64 " && %" PRIu64 " <= %" PRIu64, r, re, - reg_o, re, reg_re); - return true; - } - SCLogDebug("r %p is out of scope: %" PRIu64 "/%" PRIu64, r, offset, re); - return false; -} - -/** \internal - * \brief find the first region for merging. - */ -static StreamingBufferRegion *FindFirstRegionForOffset(const StreamingBuffer *sb, - const StreamingBufferConfig *cfg, StreamingBufferRegion *r, const uint64_t offset, - const uint32_t len, StreamingBufferRegion **prev) -{ - const uint64_t data_re = offset + len; - SCLogDebug("looking for first region matching %" PRIu64 "/%" PRIu64, offset, data_re); - - StreamingBufferRegion *p = NULL; - for (; r != NULL; r = r->next) { - if (RegionsIntersect(sb, cfg, r, offset, data_re) == true) { - *prev = p; - return r; - } - p = r; - } - *prev = NULL; - return NULL; -} - -static StreamingBufferRegion *FindLargestRegionForOffset(const StreamingBuffer *sb, - const StreamingBufferConfig *cfg, StreamingBufferRegion *r, const uint64_t offset, - const uint32_t len) -{ - const uint64_t data_re = offset + len; - SCLogDebug("starting at %p/%" PRIu64 ", offset %" PRIu64 ", data_re %" PRIu64, r, - r->stream_offset, offset, data_re); - StreamingBufferRegion *candidate = r; - for (; r != NULL; r = r->next) { -#ifdef DEBUG - const uint64_t reg_re = r->stream_offset + r->buf_size; - SCLogDebug("checking: %p/%" PRIu64 "/%" PRIu64 ", offset %" PRIu64 "/%" PRIu64, r, - r->stream_offset, reg_re, offset, data_re); -#endif - if (!RegionsIntersect(sb, cfg, r, offset, data_re)) - return candidate; - - if (r->buf_size > candidate->buf_size) { - SCLogDebug("candidate %p as size %u > %u", candidate, r->buf_size, candidate->buf_size); - candidate = r; - } - } - return candidate; -} - -static StreamingBufferRegion *FindRightEdge(const StreamingBuffer *sb, - const StreamingBufferConfig *cfg, StreamingBufferRegion *r, const uint64_t offset, - const uint32_t len) -{ - const uint64_t data_re = offset + len; - StreamingBufferRegion *candidate = r; - for (; r != NULL; r = r->next) { - if (!RegionsIntersect(sb, cfg, r, offset, data_re)) { - SCLogDebug( - "r %p is out of scope: %" PRIu64 "/%u/%" PRIu64, r, offset, len, offset + len); - return candidate; - } - candidate = r; - } - return candidate; -} - -/** \note uses sc_errno to give error details */ -static inline StreamingBufferRegion *InitBufferRegion( - StreamingBuffer *sb, const StreamingBufferConfig *cfg, const uint32_t min_size) -{ - if (sb->regions == USHRT_MAX || (cfg->max_regions != 0 && sb->regions >= cfg->max_regions)) { - SCLogDebug("max regions reached"); - sc_errno = SC_ELIMIT; - return NULL; - } - - StreamingBufferRegion *aux_r = CALLOC(cfg, 1, sizeof(*aux_r)); - if (aux_r == NULL) { - return NULL; - } - - aux_r->buf = CALLOC(cfg, 1, MAX(cfg->buf_size, min_size)); - if (aux_r->buf == NULL) { - FREE(cfg, aux_r, sizeof(*aux_r)); - return NULL; - } - aux_r->buf_size = MAX(cfg->buf_size, min_size); - sb->regions++; - sb->max_regions = MAX(sb->regions, sb->max_regions); - return aux_r; -} - -static inline int InitBuffer(StreamingBuffer *sb, const StreamingBufferConfig *cfg) -{ - sb->region.buf = CALLOC(cfg, 1, cfg->buf_size); - if (sb->region.buf == NULL) { - return sc_errno; - } - sb->region.buf_size = cfg->buf_size; - return SC_OK; -} - -StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg) -{ - StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer)); - if (sb == NULL) { - return NULL; - } - - sb->region.buf_size = cfg->buf_size; - sb->regions = sb->max_regions = 1; - - if (cfg->buf_size == 0) { - return sb; - } - - int r = InitBuffer(sb, cfg); - if (r != SC_OK) { - FREE(cfg, sb, sizeof(StreamingBuffer)); - sc_errno = r; - return NULL; - } - return sb; -} - -void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg) -{ - if (sb != NULL) { - SCLogDebug("sb->region.buf_size %u max %u", sb->region.buf_size, sb->buf_size_max); - - SBBFree(sb, cfg); - ListRegions(sb); - if (sb->region.buf != NULL) { - FREE(cfg, sb->region.buf, sb->region.buf_size); - sb->region.buf = NULL; - } - - for (StreamingBufferRegion *r = sb->region.next; r != NULL;) { - StreamingBufferRegion *next = r->next; - FREE(cfg, r->buf, r->buf_size); - FREE(cfg, r, sizeof(*r)); - r = next; - } - sb->region.next = NULL; - sb->regions = sb->max_regions = 1; - } -} - -void StreamingBufferFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg) -{ - if (sb != NULL) { - StreamingBufferClear(sb, cfg); - FREE(cfg, sb, sizeof(StreamingBuffer)); - } -} - -#ifdef DEBUG -static void SBBPrintList(StreamingBuffer *sb) -{ - StreamingBufferBlock *sbb = NULL; - RB_FOREACH(sbb, SBB, &sb->sbb_tree) { - SCLogDebug("sbb: offset %" PRIu64 ", len %u", sbb->offset, sbb->len); - StreamingBufferBlock *next = SBB_RB_NEXT(sbb); - if (next) { - if ((sbb->offset + sbb->len) != next->offset) { - SCLogDebug("gap: offset %" PRIu64 ", len %" PRIu64, (sbb->offset + sbb->len), - next->offset - (sbb->offset + sbb->len)); - } - } - } -} -#endif - -/* setup with gap between 2 blocks - * - * [block][gap][block] - **/ -static int WARN_UNUSED SBBInit(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferRegion *region, uint32_t rel_offset, uint32_t data_len) -{ - DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree)); - DEBUG_VALIDATE_BUG_ON(region->buf_offset > region->stream_offset + rel_offset); - - /* need to set up 2: existing data block and new data block */ - StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb)); - if (sbb == NULL) { - return sc_errno; - } - sbb->offset = sb->region.stream_offset; - sbb->len = sb->region.buf_offset; - (void)SBB_RB_INSERT(&sb->sbb_tree, sbb); - sb->head = sbb; - sb->sbb_size = sbb->len; - - StreamingBufferBlock *sbb2 = CALLOC(cfg, 1, sizeof(*sbb2)); - if (sbb2 == NULL) { - return sc_errno; - } - sbb2->offset = region->stream_offset + rel_offset; - sbb2->len = data_len; - DEBUG_VALIDATE_BUG_ON(sbb2->offset < sbb->len); - SCLogDebug("sbb1 %" PRIu64 ", len %u, sbb2 %" PRIu64 ", len %u", sbb->offset, sbb->len, - sbb2->offset, sbb2->len); - - sb->sbb_size += sbb2->len; - if (SBB_RB_INSERT(&sb->sbb_tree, sbb2) != NULL) { - FREE(cfg, sbb2, sizeof(*sbb2)); - return SC_EINVAL; - } - -#ifdef DEBUG - SBBPrintList(sb); -#endif - return SC_OK; -} - -/* setup with leading gap - * - * [gap][block] - **/ -static int WARN_UNUSED SBBInitLeadingGap(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferRegion *region, uint64_t offset, uint32_t data_len) -{ - DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree)); - - StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb)); - if (sbb == NULL) { - return sc_errno; - } - sbb->offset = offset; - sbb->len = data_len; - - sb->head = sbb; - sb->sbb_size = sbb->len; - (void)SBB_RB_INSERT(&sb->sbb_tree, sbb); - - SCLogDebug("sbb %" PRIu64 ", len %u", sbb->offset, sbb->len); -#ifdef DEBUG - SBBPrintList(sb); -#endif - return SC_OK; -} - -static inline void ConsolidateFwd(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferRegion *region, struct SBB *tree, StreamingBufferBlock *sa) -{ - uint64_t sa_re = sa->offset + sa->len; - StreamingBufferBlock *tr, *s = sa; - RB_FOREACH_FROM(tr, SBB, s) { - if (sa == tr) - continue; - - const uint64_t tr_re = tr->offset + tr->len; - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u re %" PRIu64, tr, tr->offset, tr->len, tr_re); - - if (sa_re < tr->offset) { - SCLogDebug("entirely before: %" PRIu64 " < %" PRIu64, sa_re, tr->offset); - break; // entirely before - } - - /* new block (sa) entirely eclipsed by in tree block (tr) - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - if (sa->offset >= tr->offset && sa_re <= tr_re) { - sb->sbb_size -= sa->len; - sa->len = tr->len; - sa->offset = tr->offset; - sa_re = sa->offset + sa->len; - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr, - tr->offset, tr->len); - SBB_RB_REMOVE(tree, tr); - FREE(cfg, tr, sizeof(StreamingBufferBlock)); - /* new block (sa) entire eclipses in tree block (tr) - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - } else if (sa->offset <= tr->offset && sa_re >= tr_re) { - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr, - tr->offset, tr->len); - SBB_RB_REMOVE(tree, tr); - sb->sbb_size -= tr->len; - FREE(cfg, tr, sizeof(StreamingBufferBlock)); - - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, - sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - if (sa->offset == region->stream_offset && - sa_re > (region->stream_offset + region->buf_offset)) { - DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); - region->buf_offset = sa_re - region->stream_offset; - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 - " bo %u sz %u BUF_OFFSET UPDATED", - sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - } - /* new block (sa) extended by in tree block (tr) - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - } else if (sa->offset < tr->offset && // starts before - sa_re >= tr->offset && sa_re < tr_re) // ends inside - { - // merge. sb->sbb_size includes both so we need to adjust that too. - uint32_t combined_len = sa->len + tr->len; - sa->len = tr_re - sa->offset; - sa_re = sa->offset + sa->len; - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len); - SBB_RB_REMOVE(tree, tr); - sb->sbb_size -= (combined_len - sa->len); // remove what we added twice - FREE(cfg, tr, sizeof(StreamingBufferBlock)); - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u RESULT", sa, sa->offset, sa->len); - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, - sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - if (sa->offset == region->stream_offset && - sa_re > (region->stream_offset + region->buf_offset)) { - DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); - region->buf_offset = sa_re - region->stream_offset; - SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 - " bo %u sz %u BUF_OFFSET UPDATED", - sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - } - } - } -} - -static inline void ConsolidateBackward(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferRegion *region, struct SBB *tree, StreamingBufferBlock *sa) -{ - uint64_t sa_re = sa->offset + sa->len; - StreamingBufferBlock *tr, *s = sa; - RB_FOREACH_REVERSE_FROM(tr, SBB, s) { - if (sa == tr) - continue; - const uint64_t tr_re = tr->offset + tr->len; - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u", tr, tr->offset, tr->len); - - if (sa->offset > tr_re) - break; // entirely after - - /* new block (sa) entirely eclipsed by in tree block (tr) - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - if (sa->offset >= tr->offset && sa_re <= tr_re) { - sb->sbb_size -= sa->len; // sa entirely eclipsed so remove double accounting - sa->len = tr->len; - sa->offset = tr->offset; - sa_re = sa->offset + sa->len; - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr, - tr->offset, tr->len); - if (sb->head == tr) - sb->head = sa; - SBB_RB_REMOVE(tree, tr); - FREE(cfg, tr, sizeof(StreamingBufferBlock)); - /* new block (sa) entire eclipses in tree block (tr) - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - } else if (sa->offset <= tr->offset && sa_re >= tr_re) { - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr, - tr->offset, tr->len); - if (sb->head == tr) - sb->head = sa; - SBB_RB_REMOVE(tree, tr); - sb->sbb_size -= tr->len; // tr entirely eclipsed so remove double accounting - FREE(cfg, tr, sizeof(StreamingBufferBlock)); - - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, - sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - - if (sa->offset == region->stream_offset && - sa_re > (region->stream_offset + region->buf_offset)) { - DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); - region->buf_offset = sa_re - region->stream_offset; - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 - " bo %u sz %u BUF_OFFSET UPDATED", - sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - } - - /* new block (sa) extends in tree block (tr) - sa: [ ] - tr: [ ] - sa: [ ] - tr: [ ] - */ - } else if (sa->offset > tr->offset && sa_re > tr_re && sa->offset <= tr_re) { - // merge. sb->sbb_size includes both so we need to adjust that too. - uint32_t combined_len = sa->len + tr->len; - sa->len = sa_re - tr->offset; - sa->offset = tr->offset; - sa_re = sa->offset + sa->len; - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len); - if (sb->head == tr) - sb->head = sa; - SBB_RB_REMOVE(tree, tr); - sb->sbb_size -= (combined_len - sa->len); // remove what we added twice - FREE(cfg, tr, sizeof(StreamingBufferBlock)); - - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, - sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - if (sa->offset == region->stream_offset && - sa_re > (region->stream_offset + region->buf_offset)) { - DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); - region->buf_offset = sa_re - region->stream_offset; - SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 - " bo %u sz %u BUF_OFFSET UPDATED", - sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, - region->buf_size); - } - } - } -} - -/** \internal - * \param region the region that holds the new data - */ -static int SBBUpdate(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferRegion *region, uint32_t rel_offset, uint32_t len) -{ - struct SBB *tree = &sb->sbb_tree; - SCLogDebug("* inserting: %u/%u", rel_offset, len); - - StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb)); - if (sbb == NULL) { - return sc_errno; - } - sbb->offset = region->stream_offset + rel_offset; - sbb->len = len; - - StreamingBufferBlock *res = SBB_RB_INSERT(tree, sbb); - if (res) { - // exact overlap - SCLogDebug("* insert failed: exact match in tree with %p %" PRIu64 "/%u", res, res->offset, - res->len); - FREE(cfg, sbb, sizeof(StreamingBufferBlock)); - return SC_OK; - } - sb->sbb_size += len; // may adjust based on consolidation below - - /* handle backwards and forwards overlaps */ - if (SBB_RB_PREV(sbb) == NULL) { - sb->head = sbb; - } else { - ConsolidateBackward(sb, cfg, region, tree, sbb); - } - ConsolidateFwd(sb, cfg, region, tree, sbb); -#ifdef DEBUG - SBBPrintList(sb); -#endif - if (sbb->offset == region->stream_offset) { - SCLogDebug("insert at region head"); - region->buf_offset = sbb->len; - } - return SC_OK; -} - -static void SBBFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg) -{ - StreamingBufferBlock *sbb = NULL, *safe = NULL; - RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) { - SBB_RB_REMOVE(&sb->sbb_tree, sbb); - sb->sbb_size -= sbb->len; - FREE(cfg, sbb, sizeof(StreamingBufferBlock)); - } - sb->head = NULL; -} - -static void SBBPrune(StreamingBuffer *sb, const StreamingBufferConfig *cfg) -{ - SCLogDebug("pruning %p to %" PRIu64, sb, sb->region.stream_offset); - StreamingBufferBlock *sbb = NULL, *safe = NULL; - RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) { - /* completely beyond window, we're done */ - if (sbb->offset >= sb->region.stream_offset) { - sb->head = sbb; - if (sbb->offset == sb->region.stream_offset) { - SCLogDebug("set buf_offset?"); - if (sbb->offset == sb->region.stream_offset) { - SCLogDebug("set buf_offset to first sbb len %u", sbb->len); - DEBUG_VALIDATE_BUG_ON(sbb->len > sb->region.buf_size); - sb->region.buf_offset = sbb->len; - } - } - break; - } - - /* partly before, partly beyond. Adjust */ - if (sbb->offset < sb->region.stream_offset && - sbb->offset + sbb->len > sb->region.stream_offset) { - uint32_t shrink_by = sb->region.stream_offset - sbb->offset; - DEBUG_VALIDATE_BUG_ON(shrink_by > sbb->len); - if (sbb->len >= shrink_by) { - sbb->len -= shrink_by; - sbb->offset += shrink_by; - sb->sbb_size -= shrink_by; - SCLogDebug("shrunk by %u", shrink_by); - DEBUG_VALIDATE_BUG_ON(sbb->offset != sb->region.stream_offset); - } - sb->head = sbb; - if (sbb->offset == sb->region.stream_offset) { - SCLogDebug("set buf_offset to first sbb len %u", sbb->len); - DEBUG_VALIDATE_BUG_ON(sbb->len > sb->region.buf_size); - sb->region.buf_offset = sbb->len; - } - break; - } - - SBB_RB_REMOVE(&sb->sbb_tree, sbb); - /* either we set it again for the next sbb, or there isn't any */ - sb->head = NULL; - sb->sbb_size -= sbb->len; - SCLogDebug("sb %p removed %p %" PRIu64 ", %u", sb, sbb, sbb->offset, sbb->len); - FREE(cfg, sbb, sizeof(StreamingBufferBlock)); - } -#ifdef DEBUG - SBBPrintList(sb); -#endif -} - -static inline uint32_t ToNextMultipleOf(const uint32_t in, const uint32_t m) -{ - uint32_t r = in; - if (m > 0) { - const uint32_t x = in % m; - if (x != 0) { - r = (in - x) + m; - } - } - return r; -} - -static thread_local bool g2s_warn_once = false; - -static inline int WARN_UNUSED GrowRegionToSize(StreamingBuffer *sb, - const StreamingBufferConfig *cfg, StreamingBufferRegion *region, const uint32_t size) -{ - DEBUG_VALIDATE_BUG_ON(region->buf_size > BIT_U32(30)); - if (size > BIT_U32(30)) { // 1GiB - if (!g2s_warn_once) { - SCLogWarning("StreamingBuffer::GrowRegionToSize() tried to alloc %u bytes, exceeds " - "limit of %lu", - size, BIT_U32(30)); - g2s_warn_once = true; - } - return SC_ELIMIT; - } - - /* try to grow in multiples of cfg->buf_size */ - const uint32_t grow = ToNextMultipleOf(size, cfg->buf_size); - SCLogDebug("grow %u", grow); - - void *ptr = REALLOC(cfg, region->buf, region->buf_size, grow); - if (ptr == NULL) { - return sc_errno; - } - /* for safe printing and general caution, lets memset the - * new data to 0 */ - size_t diff = grow - region->buf_size; - void *new_mem = ((char *)ptr) + region->buf_size; - memset(new_mem, 0, diff); - - region->buf = ptr; - region->buf_size = grow; - SCLogDebug("grown buffer to %u", grow); -#ifdef DEBUG - if (region->buf_size > sb->buf_size_max) { - sb->buf_size_max = region->buf_size; - } -#endif - return SC_OK; -} - -static int WARN_UNUSED GrowToSize( - StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint32_t size) -{ - return GrowRegionToSize(sb, cfg, &sb->region, size); -} - -static inline bool RegionBeforeOffset(const StreamingBufferRegion *r, const uint64_t o) -{ - return (r->stream_offset + r->buf_size <= o); -} - -static inline bool RegionContainsOffset(const StreamingBufferRegion *r, const uint64_t o) -{ - return (o >= r->stream_offset && (r->stream_offset + r->buf_size) >= o); -} - -/** \internal - * \brief slide to offset for regions - * - * - * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] - * ^ - * - main reset to 0 - * - * - * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] - * ^ - * - main shift - * - * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] - * ^ - * - main reset - * - move aux into main - * - free aux - * - shift - * - * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] - * ^ - * - main reset - * - move aux into main - * - free aux - * - no shift - */ -static inline void StreamingBufferSlideToOffsetWithRegions( - StreamingBuffer *sb, const StreamingBufferConfig *cfg, const uint64_t slide_offset) -{ - ListRegions(sb); - DEBUG_VALIDATE_BUG_ON(slide_offset == sb->region.stream_offset); - - SCLogDebug("slide_offset %" PRIu64, slide_offset); - SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", sb->region.stream_offset, - sb->region.buf, sb->region.buf_size, sb->region.buf_offset); - - StreamingBufferRegion *to_shift = NULL; - const bool main_is_oow = RegionBeforeOffset(&sb->region, slide_offset); - if (main_is_oow) { - SCLogDebug("main_is_oow"); - if (sb->region.buf != NULL) { - SCLogDebug("clearing main"); - FREE(cfg, sb->region.buf, sb->region.buf_size); - sb->region.buf = NULL; - sb->region.buf_size = 0; - sb->region.buf_offset = 0; - sb->region.stream_offset = slide_offset; - } else { - sb->region.stream_offset = slide_offset; - } - - /* remove regions that are out of window & select the region to - * become the new main */ - StreamingBufferRegion *prev = &sb->region; - for (StreamingBufferRegion *r = sb->region.next; r != NULL;) { - SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64, r, r->stream_offset, - r->stream_offset + r->buf_offset); - StreamingBufferRegion *next = r->next; - if (RegionBeforeOffset(r, slide_offset)) { - SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> before", r, r->stream_offset, - r->stream_offset + r->buf_offset); - DEBUG_VALIDATE_BUG_ON(r == &sb->region); - prev->next = next; - - FREE(cfg, r->buf, r->buf_size); - FREE(cfg, r, sizeof(*r)); - sb->regions--; - DEBUG_VALIDATE_BUG_ON(sb->regions == 0); - } else if (RegionContainsOffset(r, slide_offset)) { - SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> within", r, r->stream_offset, - r->stream_offset + r->buf_offset); - /* remove from list, we will xfer contents to main below */ - prev->next = next; - to_shift = r; - break; - } else { - SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> post", r, r->stream_offset, - r->stream_offset + r->buf_offset); - /* implied beyond slide offset */ - DEBUG_VALIDATE_BUG_ON(r->stream_offset < slide_offset); - break; - } - r = next; - } - SCLogDebug("to_shift %p", to_shift); - } else { - to_shift = &sb->region; - SCLogDebug("shift start region %p", to_shift); - } - - // this region is main, or will xfer its buffer to main - if (to_shift) { - SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", to_shift->stream_offset, - to_shift->buf, to_shift->buf_size, to_shift->buf_offset); - if (to_shift != &sb->region) { - DEBUG_VALIDATE_BUG_ON(sb->region.buf != NULL); - - sb->region.buf = to_shift->buf; - sb->region.stream_offset = to_shift->stream_offset; - sb->region.buf_offset = to_shift->buf_offset; - sb->region.buf_size = to_shift->buf_size; - sb->region.next = to_shift->next; - - FREE(cfg, to_shift, sizeof(*to_shift)); - to_shift = &sb->region; - sb->regions--; - DEBUG_VALIDATE_BUG_ON(sb->regions == 0); - } - - // Do the shift. If new region is exactly at the slide offset we can skip this. - DEBUG_VALIDATE_BUG_ON(to_shift->stream_offset > slide_offset); - const uint32_t s = slide_offset - to_shift->stream_offset; - if (s > 0) { - const uint32_t new_data_size = to_shift->buf_size - s; - uint32_t new_mem_size = ToNextMultipleOf(new_data_size, cfg->buf_size); - - /* see if after the slide we'd overlap with the next region. If so, we need - * to consolidate them into one. Error handling is a bit peculiar. We need - * to grow a region, move data from another region into it, then free the - * other region. This could fail if we're close to the memcap. In this case - * we relax our rounding up logic so we only shrink and don't merge the 2 - * regions after all. */ - if (to_shift->next && slide_offset + new_mem_size >= to_shift->next->stream_offset) { - StreamingBufferRegion *start = to_shift; - StreamingBufferRegion *next = start->next; - const uint64_t next_re = next->stream_offset + next->buf_size; - const uint32_t mem_size = ToNextMultipleOf(next_re - slide_offset, cfg->buf_size); - - /* using next as the new main */ - if (start->buf_size < next->buf_size) { - SCLogDebug("replace main with the next bigger region"); - - const uint32_t next_data_offset = next->stream_offset - slide_offset; - const uint32_t prev_buf_size = next->buf_size; - const uint32_t start_data_offset = slide_offset - start->stream_offset; - DEBUG_VALIDATE_BUG_ON(start_data_offset > start->buf_size); - if (start_data_offset > start->buf_size) { - new_mem_size = new_data_size; - goto just_main; - } - /* expand "next" to include relevant part of "start" */ - if (GrowRegionToSize(sb, cfg, next, mem_size) != 0) { - new_mem_size = new_data_size; - goto just_main; - } - SCLogDebug("region now sized %u", mem_size); - - // slide "next": - // pre-grow: [nextnextnext] - // post-grow [nextnextnextXXX] - // post-move [XXXnextnextnext] - memmove(next->buf + next_data_offset, next->buf, prev_buf_size); - - // move portion of "start" into "next" - // - // start: [ooooookkkkk] (o: old, k: keep) - // pre-next [xxxxxnextnextnext] - // post-next [kkkkknextnextnext] - const uint32_t start_data_size = start->buf_size - start_data_offset; - memcpy(next->buf, start->buf + start_data_offset, start_data_size); - - // free "start"s buffer, we will use the one from "next" - FREE(cfg, start->buf, start->buf_size); - - // update "main" to use "next" - start->stream_offset = slide_offset; - start->buf = next->buf; - start->buf_size = next->buf_size; - start->next = next->next; - - // free "next" - FREE(cfg, next, sizeof(*next)); - sb->regions--; - DEBUG_VALIDATE_BUG_ON(sb->regions == 0); - goto done; - } else { - /* using "main", expand to include "next" */ - if (GrowRegionToSize(sb, cfg, start, mem_size) != 0) { - new_mem_size = new_data_size; - goto just_main; - } - SCLogDebug("start->buf now size %u", mem_size); - - // slide "start" - // pre: [xxxxxxxAAA] - // post: [AAAxxxxxxx] - SCLogDebug("s %u new_data_size %u", s, new_data_size); - memmove(start->buf, start->buf + s, new_data_size); - - // copy in "next" - // pre: [AAAxxxxxxx] - // [BBBBBBB] - // post: [AAABBBBBBB] - SCLogDebug("copy next->buf %p/%u to start->buf offset %u", next->buf, - next->buf_size, new_data_size); - memcpy(start->buf + new_data_size, next->buf, next->buf_size); - - start->stream_offset = slide_offset; - start->next = next->next; - - // free "next" - FREE(cfg, next->buf, next->buf_size); - FREE(cfg, next, sizeof(*next)); - sb->regions--; - DEBUG_VALIDATE_BUG_ON(sb->regions == 0); - goto done; - } - } - - just_main: - SCLogDebug("s %u new_data_size %u", s, new_data_size); - memmove(to_shift->buf, to_shift->buf + s, new_data_size); - /* shrink memory region. If this fails we keep the old */ - void *ptr = REALLOC(cfg, to_shift->buf, to_shift->buf_size, new_mem_size); - if (ptr != NULL) { - to_shift->buf = ptr; - to_shift->buf_size = new_mem_size; - SCLogDebug("new buf_size %u", to_shift->buf_size); - } - if (s < to_shift->buf_offset) - to_shift->buf_offset -= s; - else - to_shift->buf_offset = 0; - to_shift->stream_offset = slide_offset; - } - } - -done: - SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", sb->region.stream_offset, - sb->region.buf, sb->region.buf_size, sb->region.buf_offset); - SCLogDebug("end of slide"); -} - -/** - * \brief slide to absolute offset - * \todo if sliding beyond window, we could perhaps reset? - */ -void StreamingBufferSlideToOffset( - StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint64_t offset) -{ - SCLogDebug("sliding to offset %" PRIu64, offset); - ListRegions(sb); -#ifdef DEBUG - SBBPrintList(sb); -#endif - - if (sb->region.next) { - StreamingBufferSlideToOffsetWithRegions(sb, cfg, offset); - SBBPrune(sb, cfg); - SCLogDebug("post SBBPrune"); - ListRegions(sb); -#ifdef DEBUG - SBBPrintList(sb); -#endif - DEBUG_VALIDATE_BUG_ON(sb->region.buf != NULL && sb->region.buf_size == 0); - DEBUG_VALIDATE_BUG_ON(sb->region.buf_offset > sb->region.buf_size); - DEBUG_VALIDATE_BUG_ON(offset > sb->region.stream_offset); - DEBUG_VALIDATE_BUG_ON(sb->head && sb->head->offset == sb->region.stream_offset && - sb->head->len > sb->region.buf_offset); - DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset); - return; - } - - if (offset > sb->region.stream_offset) { - const uint32_t slide = offset - sb->region.stream_offset; - if (sb->head != NULL) { - /* have sbb's, so can't rely on buf_offset for the slide */ - if (slide < sb->region.buf_size) { - const uint32_t size = sb->region.buf_size - slide; - SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, - size); - memmove(sb->region.buf, sb->region.buf + slide, size); - if (sb->region.buf_offset > slide) { - sb->region.buf_offset -= slide; - } else { - sb->region.buf_offset = 0; - } - } else { - sb->region.buf_offset = 0; - } - sb->region.stream_offset = offset; - } else { - /* no sbb's, so we can use buf_offset */ - if (offset <= sb->region.stream_offset + sb->region.buf_offset) { - const uint32_t size = sb->region.buf_offset - slide; - SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, - size); - memmove(sb->region.buf, sb->region.buf + slide, size); - sb->region.stream_offset = offset; - sb->region.buf_offset = size; - } else { - /* moved past all data */ - sb->region.stream_offset = offset; - sb->region.buf_offset = 0; - } - } - SBBPrune(sb, cfg); - } -#ifdef DEBUG - SBBPrintList(sb); -#endif - DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset); -} - -#define DATA_FITS(sb, len) ((sb)->region.buf_offset + (len) <= (sb)->region.buf_size) - -int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len) -{ - DEBUG_VALIDATE_BUG_ON(seg == NULL); - - if (sb->region.buf == NULL) { - if (InitBuffer(sb, cfg) == -1) - return -1; - } - - if (!DATA_FITS(sb, data_len)) { - if (sb->region.buf_size == 0) { - if (GrowToSize(sb, cfg, data_len) != SC_OK) - return -1; - } else { - if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK) - return -1; - } - } - DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len)); - - memcpy(sb->region.buf + sb->region.buf_offset, data, data_len); - seg->stream_offset = sb->region.stream_offset + sb->region.buf_offset; - seg->segment_len = data_len; - uint32_t rel_offset = sb->region.buf_offset; - sb->region.buf_offset += data_len; - - if (!RB_EMPTY(&sb->sbb_tree)) { - return SBBUpdate(sb, cfg, &sb->region, rel_offset, data_len); - } else { - return 0; - } -} - -/** - * \brief add data w/o tracking a segment - */ -int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - const uint8_t *data, uint32_t data_len) -{ - if (sb->region.buf == NULL) { - if (InitBuffer(sb, cfg) == -1) - return -1; - } - - if (!DATA_FITS(sb, data_len)) { - if (sb->region.buf_size == 0) { - if (GrowToSize(sb, cfg, data_len) != SC_OK) - return -1; - } else { - if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK) - return -1; - } - } - DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len)); - - memcpy(sb->region.buf + sb->region.buf_offset, data, data_len); - uint32_t rel_offset = sb->region.buf_offset; - sb->region.buf_offset += data_len; - - if (!RB_EMPTY(&sb->sbb_tree)) { - return SBBUpdate(sb, cfg, &sb->region, rel_offset, data_len); - } else { - return 0; - } -} - -#define DATA_FITS_AT_OFFSET(region, len, offset) ((offset) + (len) <= (region)->buf_size) - -#if defined(DEBUG) || defined(DEBUG_VALIDATION) -static void Validate(const StreamingBuffer *sb) -{ - bool bail = false; - uint32_t cnt = 0; - for (const StreamingBufferRegion *r = &sb->region; r != NULL; r = r->next) { - cnt++; - if (r->next) { - bail |= ((r->stream_offset + r->buf_size) > r->next->stream_offset); - } - - bail |= (r->buf != NULL && r->buf_size == 0); - bail |= (r->buf_offset > r->buf_size); - } - // leading gap, so buf_offset should be 0? - if (sb->head && sb->head->offset > sb->region.stream_offset) { - SCLogDebug("leading gap of size %" PRIu64, sb->head->offset - sb->region.stream_offset); - BUG_ON(sb->region.buf_offset != 0); - } - - if (sb->head && sb->head->offset == sb->region.stream_offset) { - BUG_ON(sb->head->len > sb->region.buf_offset); - BUG_ON(sb->head->len < sb->region.buf_offset); - } - BUG_ON(sb->regions != cnt); - BUG_ON(bail); -} -#endif - -static void ListRegions(StreamingBuffer *sb) -{ - if (sb->region.buf == NULL && sb->region.buf_offset == 0 && sb->region.next == NULL) - return; -#if defined(DEBUG) && DUMP_REGIONS == 1 - uint32_t cnt = 0; - for (StreamingBufferRegion *r = &sb->region; r != NULL; r = r->next) { - cnt++; - char gap[64] = ""; - if (r->next) { - snprintf(gap, sizeof(gap), "[ gap:%" PRIu64 " ]", - r->next->stream_offset - (r->stream_offset + r->buf_size)); - } - - printf("[ %s offset:%" PRIu64 " size:%u offset:%u ]%s", r == &sb->region ? "main" : "aux", - r->stream_offset, r->buf_size, r->buf_offset, gap); - } - printf("(max %u, cnt %u, sb->regions %u)\n", sb->max_regions, cnt, sb->regions); - bool at_least_one = false; - uint64_t last_re = sb->region.stream_offset; - StreamingBufferBlock *sbb = NULL; - RB_FOREACH(sbb, SBB, &sb->sbb_tree) - { - if (last_re != sbb->offset) { - printf("[ gap:%" PRIu64 " ]", sbb->offset - last_re); - } - printf("[ sbb offset:%" PRIu64 " len:%u ]", sbb->offset, sbb->len); - at_least_one = true; - last_re = sbb->offset + sbb->len; - } - if (at_least_one) - printf("\n"); -#endif -#if defined(DEBUG) || defined(DEBUG_VALIDATION) - StreamingBufferBlock *sbb2 = NULL; - RB_FOREACH(sbb2, SBB, &sb->sbb_tree) - { - const uint8_t *_data = NULL; - uint32_t _data_len = 0; - (void)StreamingBufferSBBGetData(sb, sbb2, &_data, &_data_len); - } - Validate(sb); -#endif -} - -/** \internal - * \brief process insert by consolidating the affected regions into one - * \note sets sc_errno - */ -static StreamingBufferRegion *BufferInsertAtRegionConsolidate(StreamingBuffer *sb, - const StreamingBufferConfig *cfg, StreamingBufferRegion *dst, - StreamingBufferRegion *src_start, StreamingBufferRegion *src_end, - const uint64_t data_offset, const uint32_t data_len, StreamingBufferRegion *prev, - uint32_t dst_buf_size) -{ - int retval; -#ifdef DEBUG - const uint64_t data_re = data_offset + data_len; - SCLogDebug("sb %p dst %p src_start %p src_end %p data_offset %" PRIu64 - "/data_len %u/data_re %" PRIu64, - sb, dst, src_start, src_end, data_offset, data_len, data_re); -#endif - - // 1. determine size and offset for dst. - const uint64_t dst_offset = MIN(src_start->stream_offset, data_offset); - DEBUG_VALIDATE_BUG_ON(dst_offset < sb->region.stream_offset); - const uint32_t dst_size = dst_buf_size; - SCLogDebug("dst_size %u", dst_size); - - // 2. resize dst - const uint32_t old_size = dst->buf_size; - const uint32_t dst_copy_offset = dst->stream_offset - dst_offset; -#ifdef DEBUG - const uint32_t old_offset = dst->buf_offset; - SCLogDebug("old_size %u, old_offset %u, dst_copy_offset %u", old_size, old_offset, - dst_copy_offset); -#endif - if ((retval = GrowRegionToSize(sb, cfg, dst, dst_size)) != SC_OK) { - sc_errno = retval; - return NULL; - } - SCLogDebug("resized to %u -> %u", dst_size, dst->buf_size); - /* validate that the size is exactly what we asked for */ - DEBUG_VALIDATE_BUG_ON(dst_size != dst->buf_size); - if (dst_copy_offset != 0) - memmove(dst->buf + dst_copy_offset, dst->buf, old_size); - if (dst_offset != dst->stream_offset) { - dst->stream_offset = dst_offset; - // buf_offset no longer valid, reset. - dst->buf_offset = 0; - } - - uint32_t new_offset = src_start->buf_offset; - if (data_offset == src_start->stream_offset + src_start->buf_offset) { - new_offset += data_len; - } - - bool start_is_main = false; - if (src_start == &sb->region) { - DEBUG_VALIDATE_BUG_ON(src_start->stream_offset != dst_offset); - - start_is_main = true; - SCLogDebug("src_start is main region"); - if (src_start != dst) - memcpy(dst->buf, src_start->buf, src_start->buf_offset); - if (src_start == src_end) { - SCLogDebug("src_start == src_end == main, we're done"); - DEBUG_VALIDATE_BUG_ON(src_start != dst); - return src_start; - } - prev = src_start; - src_start = src_start->next; // skip in the loop below - } - - // 3. copy all regions from src_start to dst_start into the new region - for (StreamingBufferRegion *r = src_start; r != NULL;) { - SCLogDebug("r %p %" PRIu64 ", offset %u, len %u, %s, last %s", r, r->stream_offset, - r->buf_offset, r->buf_size, r == &sb->region ? "main" : "aux", - BOOL2STR(r == src_end)); - // skip dst - if (r == dst) { - SCLogDebug("skipping r %p as it is 'dst'", r); - if (r == src_end) - break; - prev = r; - r = r->next; - continue; - } - const uint32_t target_offset = r->stream_offset - dst_offset; - SCLogDebug("r %p: target_offset %u", r, target_offset); - DEBUG_VALIDATE_BUG_ON(target_offset > dst->buf_size); - DEBUG_VALIDATE_BUG_ON(target_offset + r->buf_size > dst->buf_size); - memcpy(dst->buf + target_offset, r->buf, r->buf_size); - - StreamingBufferRegion *next = r->next; - FREE(cfg, r->buf, r->buf_size); - FREE(cfg, r, sizeof(*r)); - sb->regions--; - DEBUG_VALIDATE_BUG_ON(sb->regions == 0); - - DEBUG_VALIDATE_BUG_ON(prev == NULL && src_start != &sb->region); - if (prev != NULL) { - SCLogDebug("setting prev %p next to %p (was %p)", prev, next, prev->next); - prev->next = next; - } else { - SCLogDebug("no prev yet"); - } - - if (r == src_end) - break; - r = next; - } - - /* special handling of main region being the start, but not the - * region we expand. In this case we'll have main and dst. We will - * move the buffer from dst into main and free dst. */ - if (start_is_main && dst != &sb->region) { - DEBUG_VALIDATE_BUG_ON(sb->region.next != dst); - SCLogDebug("start_is_main && dst != main region"); - FREE(cfg, sb->region.buf, sb->region.buf_size); - sb->region.buf = dst->buf; - sb->region.buf_size = dst->buf_size; - sb->region.buf_offset = new_offset; - SCLogDebug("sb->region.buf_offset set to %u", sb->region.buf_offset); - sb->region.next = dst->next; - FREE(cfg, dst, sizeof(*dst)); - dst = &sb->region; - sb->regions--; - DEBUG_VALIDATE_BUG_ON(sb->regions == 0); - } else { - SCLogDebug("dst: %p next %p", dst, dst->next); - } - - SCLogDebug("returning dst %p stream_offset %" PRIu64 " buf_offset %u buf_size %u", dst, - dst->stream_offset, dst->buf_offset, dst->buf_size); - return dst; -} - -/** \note sets sc_errno */ -static StreamingBufferRegion *BufferInsertAtRegionDo(StreamingBuffer *sb, - const StreamingBufferConfig *cfg, const uint64_t offset, const uint32_t len) -{ - SCLogDebug("offset %" PRIu64 ", len %u", offset, len); - StreamingBufferRegion *start_prev = NULL; - StreamingBufferRegion *start = - FindFirstRegionForOffset(sb, cfg, &sb->region, offset, len, &start_prev); - if (start) { - const uint64_t insert_re = offset + len; - const uint64_t insert_start_offset = MIN(start->stream_offset, offset); - uint64_t insert_adjusted_re = insert_re; - - SCLogDebug("start region %p/%" PRIu64 "/%u", start, start->stream_offset, start->buf_size); - StreamingBufferRegion *big = FindLargestRegionForOffset(sb, cfg, start, offset, len); - DEBUG_VALIDATE_BUG_ON(big == NULL); - if (big == NULL) { - sc_errno = SC_EINVAL; - return NULL; - } - SCLogDebug("big region %p/%" PRIu64 "/%u", big, big->stream_offset, big->buf_size); - StreamingBufferRegion *end = FindRightEdge(sb, cfg, big, offset, len); - DEBUG_VALIDATE_BUG_ON(end == NULL); - if (end == NULL) { - sc_errno = SC_EINVAL; - return NULL; - } - insert_adjusted_re = MAX(insert_adjusted_re, (end->stream_offset + end->buf_size)); - - uint32_t new_buf_size = - ToNextMultipleOf(insert_adjusted_re - insert_start_offset, cfg->buf_size); - SCLogDebug("new_buf_size %u", new_buf_size); - - /* see if our new buf size + cfg->buf_size margin leads to an overlap with the next region. - * If so, include that in the consolidation. */ - if (end->next != NULL && new_buf_size + insert_start_offset > end->next->stream_offset) { - SCLogDebug("adjusted end from %p to %p", end, end->next); - end = end->next; - insert_adjusted_re = MAX(insert_adjusted_re, (end->stream_offset + end->buf_size)); - new_buf_size = - ToNextMultipleOf(insert_adjusted_re - insert_start_offset, cfg->buf_size); - SCLogDebug("new_buf_size %u", new_buf_size); - } - - SCLogDebug("end region %p/%" PRIu64 "/%u", end, end->stream_offset, end->buf_size); - /* sets sc_errno */ - StreamingBufferRegion *ret = BufferInsertAtRegionConsolidate( - sb, cfg, big, start, end, offset, len, start_prev, new_buf_size); - return ret; - } else { - /* if there was no region we can use we add a new region and insert it */ - StreamingBufferRegion *append = &sb->region; - for (StreamingBufferRegion *r = append; r != NULL; r = r->next) { - if (r->stream_offset > offset) { - break; - } else { - append = r; - } - } - - SCLogDebug("no matching region found, append to %p (%s)", append, - append == &sb->region ? "main" : "aux"); - /* sets sc_errno */ - StreamingBufferRegion *add = InitBufferRegion(sb, cfg, len); - if (add == NULL) - return NULL; - add->stream_offset = offset; - add->next = append->next; - append->next = add; - SCLogDebug("new region %p offset %" PRIu64, add, add->stream_offset); - return add; - } -} - -/** \internal - * \brief return the region to put the new data in - * - * Will find an existing region, expand it if needed. If no existing region exists or is - * a good fit, it will try to set up a new region. If the region then overlaps or gets - * too close to the next, merge them. - * - * \note sets sc_errno - */ -static StreamingBufferRegion *BufferInsertAtRegion(StreamingBuffer *sb, - const StreamingBufferConfig *cfg, const uint8_t *data, const uint32_t data_len, - const uint64_t data_offset) -{ - SCLogDebug("data_offset %" PRIu64 ", data_len %u, re %" PRIu64, data_offset, data_len, - data_offset + data_len); - ListRegions(sb); - - if (RegionsIntersect(sb, cfg, &sb->region, data_offset, data_offset + data_len)) { - SCLogDebug("data_offset %" PRIu64 ", data_len %u intersects with main region (next %p)", - data_offset, data_len, sb->region.next); - if (sb->region.next == NULL || - !RegionsIntersect(sb, cfg, sb->region.next, data_offset, data_offset + data_len)) { - SCLogDebug( - "data_offset %" PRIu64 - ", data_len %u intersects with main region, no next or way before next region", - data_offset, data_len); - if (sb->region.buf == NULL) { - int r; - if ((r = InitBuffer(sb, cfg)) != SC_OK) { // TODO init with size - sc_errno = r; - return NULL; - } - } - return &sb->region; - } - } else if (sb->region.next == NULL) { - /* InitBufferRegion sets sc_errno */ - StreamingBufferRegion *aux_r = sb->region.next = InitBufferRegion(sb, cfg, data_len); - if (aux_r == NULL) - return NULL; - aux_r->stream_offset = data_offset; - DEBUG_VALIDATE_BUG_ON(data_len > aux_r->buf_size); - SCLogDebug("created new region %p with offset %" PRIu64 ", size %u", aux_r, - aux_r->stream_offset, aux_r->buf_size); - return aux_r; - } - /* BufferInsertAtRegionDo sets sc_errno */ - StreamingBufferRegion *blob = BufferInsertAtRegionDo(sb, cfg, data_offset, data_len); - SCLogDebug("blob %p (%s)", blob, blob == &sb->region ? "main" : "aux"); - return blob; -} - -/** - * \param offset offset relative to StreamingBuffer::stream_offset - * - * \return SC_OK in case of success - * \return SC_E* errors otherwise - */ -int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, uint64_t offset) -{ - int r; - - DEBUG_VALIDATE_BUG_ON(seg == NULL); - DEBUG_VALIDATE_BUG_ON(offset < sb->region.stream_offset); - if (offset < sb->region.stream_offset) { - return SC_EINVAL; - } - - StreamingBufferRegion *region = BufferInsertAtRegion(sb, cfg, data, data_len, offset); - if (region == NULL) { - return sc_errno; - } - - const bool region_is_main = region == &sb->region; - - SCLogDebug("inserting %" PRIu64 "/%u using %s region %p", offset, data_len, - region == &sb->region ? "main" : "aux", region); - - uint32_t rel_offset = offset - region->stream_offset; - if (!DATA_FITS_AT_OFFSET(region, data_len, rel_offset)) { - if ((r = GrowToSize(sb, cfg, (rel_offset + data_len))) != SC_OK) - return r; - } - DEBUG_VALIDATE_BUG_ON(!DATA_FITS_AT_OFFSET(region, data_len, rel_offset)); - - SCLogDebug("offset %" PRIu64 " data_len %u, rel_offset %u into region offset %" PRIu64 - ", buf_offset %u, buf_size %u", - offset, data_len, rel_offset, region->stream_offset, region->buf_offset, - region->buf_size); - memcpy(region->buf + rel_offset, data, data_len); - seg->stream_offset = offset; - seg->segment_len = data_len; - - SCLogDebug("rel_offset %u region->stream_offset %" PRIu64 ", buf_offset %u", rel_offset, - region->stream_offset, region->buf_offset); - - if (RB_EMPTY(&sb->sbb_tree)) { - SCLogDebug("empty sbb list"); - - if (region_is_main) { - if (sb->region.stream_offset == offset) { - SCLogDebug("empty sbb list: block exactly what was expected, fall through"); - /* empty list, data is exactly what is expected (append), - * so do nothing. - * Update buf_offset if needed, but in case of overlaps it might be beyond us. */ - sb->region.buf_offset = MAX(sb->region.buf_offset, rel_offset + data_len); - } else if ((rel_offset + data_len) <= sb->region.buf_offset) { - SCLogDebug("empty sbb list: block is within existing main data region"); - } else { - if (sb->region.buf_offset && rel_offset == sb->region.buf_offset) { - SCLogDebug("exactly at expected offset"); - // nothing to do - sb->region.buf_offset = rel_offset + data_len; - - } else if (rel_offset < sb->region.buf_offset) { - // nothing to do - - SCLogDebug("before expected offset: %u < sb->region.buf_offset %u", rel_offset, - sb->region.buf_offset); - if (rel_offset + data_len > sb->region.buf_offset) { - SCLogDebug("before expected offset, ends after: %u < sb->region.buf_offset " - "%u, %u > %u", - rel_offset, sb->region.buf_offset, rel_offset + data_len, - sb->region.buf_offset); - sb->region.buf_offset = rel_offset + data_len; - } - - } else if (sb->region.buf_offset) { - SCLogDebug("beyond expected offset: SBBInit"); - /* existing data, but there is a gap between us */ - if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK) - return r; - } else { - /* gap before data in empty list */ - SCLogDebug("empty sbb list: invoking SBBInitLeadingGap"); - if ((r = SBBInitLeadingGap(sb, cfg, region, offset, data_len)) != SC_OK) - return r; - } - } - } else { - if (sb->region.buf_offset) { - /* existing data, but there is a gap between us */ - SCLogDebug("empty sbb list, no data in main: use SBBInit"); - if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK) - return r; - } else { - /* gap before data in empty list */ - SCLogDebug("empty sbb list: invoking SBBInitLeadingGap"); - if ((r = SBBInitLeadingGap(sb, cfg, region, offset, data_len)) != SC_OK) - return r; - } - if (rel_offset == region->buf_offset) { - SCLogDebug("pre region->buf_offset %u", region->buf_offset); - region->buf_offset = rel_offset + data_len; - SCLogDebug("post region->buf_offset %u", region->buf_offset); - } - } - } else { - SCLogDebug("updating sbb tree"); - /* already have blocks, so append new block based on new data */ - if ((r = SBBUpdate(sb, cfg, region, rel_offset, data_len)) != SC_OK) - return r; - } - DEBUG_VALIDATE_BUG_ON(!region_is_main && sb->head == NULL); - - ListRegions(sb); - if (RB_EMPTY(&sb->sbb_tree)) { - DEBUG_VALIDATE_BUG_ON(offset + data_len > sb->region.stream_offset + sb->region.buf_offset); - } - - return SC_OK; -} - -int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, - const StreamingBufferSegment *seg) -{ - if (seg->stream_offset < sb->region.stream_offset) { - if (seg->stream_offset + seg->segment_len <= sb->region.stream_offset) { - return 1; - } - } - return 0; -} - -static inline const StreamingBufferRegion *GetRegionForOffset( - const StreamingBuffer *sb, const uint64_t offset) -{ - if (sb == NULL) - return NULL; - if (sb->region.next == NULL) { - return &sb->region; - } - if (offset >= sb->region.stream_offset && - offset < (sb->region.stream_offset + sb->region.buf_size)) { - return &sb->region; - } - for (const StreamingBufferRegion *r = sb->region.next; r != NULL; r = r->next) { - if (offset >= r->stream_offset && offset < (r->stream_offset + r->buf_size)) { - return r; - } - } - return NULL; -} - -/** \brief get the data for one SBB */ -void StreamingBufferSBBGetData(const StreamingBuffer *sb, - const StreamingBufferBlock *sbb, - const uint8_t **data, uint32_t *data_len) -{ - const StreamingBufferRegion *region = GetRegionForOffset(sb, sbb->offset); - SCLogDebug("first find our region (offset %" PRIu64 ") -> %p", sbb->offset, region); - if (region) { - SCLogDebug("region %p found %" PRIu64 "/%u/%u", region, region->stream_offset, - region->buf_size, region->buf_offset); - DEBUG_VALIDATE_BUG_ON( - region->stream_offset == sbb->offset && region->buf_offset > sbb->len); - // buf_offset should match first sbb len if it has the same offset - - if (sbb->offset >= region->stream_offset) { - SCLogDebug("1"); - uint64_t offset = sbb->offset - region->stream_offset; - *data = region->buf + offset; - DEBUG_VALIDATE_BUG_ON(offset + sbb->len > region->buf_size); - *data_len = sbb->len; - return; - } else { - SCLogDebug("2"); - uint64_t offset = region->stream_offset - sbb->offset; - if (offset < sbb->len) { - *data = region->buf; - *data_len = sbb->len - offset; - return; - } - SCLogDebug("3"); - } - } - *data = NULL; - *data_len = 0; - return; -} - -/** \brief get the data for one SBB */ -void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb, - const StreamingBufferBlock *sbb, - const uint8_t **data, uint32_t *data_len, - uint64_t offset) -{ - /* validate that we are looking for a offset within the sbb */ - DEBUG_VALIDATE_BUG_ON(!(offset >= sbb->offset && offset < (sbb->offset + sbb->len))); - if (!(offset >= sbb->offset && offset < (sbb->offset + sbb->len))) { - *data = NULL; - *data_len = 0; - return; - } - - const StreamingBufferRegion *region = GetRegionForOffset(sb, offset); - if (region) { - uint32_t sbblen = sbb->len - (offset - sbb->offset); - - if (offset >= region->stream_offset) { - uint64_t data_offset = offset - region->stream_offset; - *data = region->buf + data_offset; - if (data_offset + sbblen > region->buf_size) - *data_len = region->buf_size - data_offset; - else - *data_len = sbblen; - DEBUG_VALIDATE_BUG_ON(*data_len > sbblen); - return; - } else { - uint64_t data_offset = region->stream_offset - sbb->offset; - if (data_offset < sbblen) { - *data = region->buf; - *data_len = sbblen - data_offset; - DEBUG_VALIDATE_BUG_ON(*data_len > sbblen); - return; - } - } - } - - *data = NULL; - *data_len = 0; - return; -} - -void StreamingBufferSegmentGetData(const StreamingBuffer *sb, - const StreamingBufferSegment *seg, - const uint8_t **data, uint32_t *data_len) -{ - const StreamingBufferRegion *region = GetRegionForOffset(sb, seg->stream_offset); - if (region) { - if (seg->stream_offset >= region->stream_offset) { - uint64_t offset = seg->stream_offset - region->stream_offset; - *data = region->buf + offset; - if (offset + seg->segment_len > region->buf_size) - *data_len = region->buf_size - offset; - else - *data_len = seg->segment_len; - SCLogDebug("*data_len %u", *data_len); - return; - } else { - uint64_t offset = region->stream_offset - seg->stream_offset; - if (offset < seg->segment_len) { - *data = region->buf; - *data_len = seg->segment_len - offset; - SCLogDebug("*data_len %u", *data_len); - return; - } - } - } - *data = NULL; - *data_len = 0; - return; -} - -/** - * \retval 1 data is the same - * \retval 0 data is different - */ -int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, - const StreamingBufferSegment *seg, - const uint8_t *rawdata, uint32_t rawdata_len) -{ - const uint8_t *segdata = NULL; - uint32_t segdata_len = 0; - StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len); - if (segdata && segdata_len && - segdata_len == rawdata_len && - memcmp(segdata, rawdata, segdata_len) == 0) - { - return 1; - } - return 0; -} - -int StreamingBufferGetData(const StreamingBuffer *sb, - const uint8_t **data, uint32_t *data_len, - uint64_t *stream_offset) -{ - if (sb != NULL && sb->region.buf != NULL) { - *data = sb->region.buf; - *data_len = sb->region.buf_offset; - *stream_offset = sb->region.stream_offset; - return 1; - } else { - *data = NULL; - *data_len = 0; - *stream_offset = 0; - return 0; - } -} - -int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb, - const uint8_t **data, uint32_t *data_len, - uint64_t offset) -{ - const StreamingBufferRegion *region = GetRegionForOffset(sb, offset); - if (region != NULL && region->buf != NULL && offset >= region->stream_offset && - offset < (region->stream_offset + region->buf_offset)) { - uint32_t skip = offset - region->stream_offset; - *data = region->buf + skip; - *data_len = region->buf_offset - skip; - return 1; - } else { - *data = NULL; - *data_len = 0; - return 0; - } -} - -/** - * \retval 1 data is the same - * \retval 0 data is different - */ -int StreamingBufferCompareRawData(const StreamingBuffer *sb, - const uint8_t *rawdata, uint32_t rawdata_len) -{ - const uint8_t *sbdata = NULL; - uint32_t sbdata_len = 0; - uint64_t offset = 0; - StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset); - if (offset == 0 && - sbdata && sbdata_len && - sbdata_len == rawdata_len && - memcmp(sbdata, rawdata, sbdata_len) == 0) - { - return 1; - } - SCLogDebug("sbdata_len %u, offset %" PRIu64, sbdata_len, offset); - printf("got:\n"); - PrintRawDataFp(stdout, sbdata,sbdata_len); - printf("wanted:\n"); - PrintRawDataFp(stdout, rawdata,rawdata_len); - return 0; -} - -#ifdef UNITTESTS -static void Dump(StreamingBuffer *sb) -{ - PrintRawDataFp(stdout, sb->region.buf, sb->region.buf_offset); -} - -static void DumpSegment(StreamingBuffer *sb, StreamingBufferSegment *seg) -{ - const uint8_t *data = NULL; - uint32_t data_len = 0; - StreamingBufferSegmentGetData(sb, seg, &data, &data_len); - if (data && data_len) { - PrintRawDataFp(stdout, data, data_len); - } -} - -static int StreamingBufferTest02(void) -{ - StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8) != 0); - FAIL_IF(sb->region.stream_offset != 0); - FAIL_IF(sb->region.buf_offset != 16); - FAIL_IF(seg1.stream_offset != 0); - FAIL_IF(seg2.stream_offset != 8); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - FAIL_IF_NOT_NULL(sb->head); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSlideToOffset(sb, &cfg, 6); - FAIL_IF_NOT_NULL(sb->head); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6) != 0); - FAIL_IF(sb->region.stream_offset != 6); - FAIL_IF(sb->region.buf_offset != 16); - FAIL_IF(seg3.stream_offset != 16); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - DumpSegment(sb, &seg3); - FAIL_IF_NOT_NULL(sb->head); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSlideToOffset(sb, &cfg, 12); - FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - DumpSegment(sb, &seg3); - FAIL_IF_NOT_NULL(sb->head); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -static int StreamingBufferTest03(void) -{ - StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); - FAIL_IF(sb->region.stream_offset != 0); - FAIL_IF(sb->region.buf_offset != 8); - FAIL_IF(seg1.stream_offset != 0); - FAIL_IF(seg2.stream_offset != 14); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 16); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); - FAIL_IF(sb->region.stream_offset != 0); - FAIL_IF(sb->region.buf_offset != 22); - FAIL_IF(seg3.stream_offset != 8); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - DumpSegment(sb, &seg3); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 22); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSlideToOffset(sb, &cfg, 10); - FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - DumpSegment(sb, &seg3); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 12); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -static int StreamingBufferTest04(void) -{ - StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); - FAIL_IF(!RB_EMPTY(&sb->sbb_tree)); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); - FAIL_IF(sb->region.stream_offset != 0); - FAIL_IF(sb->region.buf_offset != 8); - FAIL_IF(seg1.stream_offset != 0); - FAIL_IF(seg2.stream_offset != 14); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - FAIL_IF(RB_EMPTY(&sb->sbb_tree)); - StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF(sbb1 != sb->head); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 8); - StreamingBufferBlock *sbb2 = SBB_RB_NEXT(sbb1); - FAIL_IF_NULL(sbb2); - FAIL_IF(sbb2 == sb->head); - FAIL_IF(sbb2->offset != 14); - FAIL_IF(sbb2->len != 8); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); - FAIL_IF(sb->region.stream_offset != 0); - FAIL_IF(sb->region.buf_offset != 22); - FAIL_IF(seg3.stream_offset != 8); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); - sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1 != sb->head); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 22); - FAIL_IF(SBB_RB_NEXT(sbb1)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - DumpSegment(sb, &seg3); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 22); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - /* far ahead of curve: */ - StreamingBufferSegment seg4; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"XYZ", 3, 124) != 0); - FAIL_IF(sb->region.stream_offset != 0); - FAIL_IF(sb->region.buf_offset != 22); - FAIL_IF(sb->region.buf_size != 128); - FAIL_IF(seg4.stream_offset != 124); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); - FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg4)); - sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1 != sb->head); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 22); - FAIL_IF(!SBB_RB_NEXT(sbb1)); - Dump(sb); - DumpSegment(sb, &seg1); - DumpSegment(sb, &seg2); - DumpSegment(sb, &seg3); - DumpSegment(sb, &seg4); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 25); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg1,(const uint8_t *)"ABCDEFGH", 8)); - FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg2,(const uint8_t *)"01234567", 8)); - FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg3,(const uint8_t *)"QWERTY", 6)); - FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg4,(const uint8_t *)"XYZ", 3)); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -/** \test lots of gaps in block list */ -static int StreamingBufferTest06(void) -{ - StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"A", 1) != 0); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"C", 1, 2) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 2); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 3); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg4; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 4); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg5; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); - Dump(sb); - StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg6; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0); - Dump(sb); - sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -/** \test lots of gaps in block list */ -static int StreamingBufferTest07(void) -{ - StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 2); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 3); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg4; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 4); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg5; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); - Dump(sb); - StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg6; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0); - Dump(sb); - sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -/** \test lots of gaps in block list */ -static int StreamingBufferTest08(void) -{ - StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 2); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 3); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg4; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 4); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg5; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); - Dump(sb); - StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg6; - FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10) != 0); - Dump(sb); - sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 20); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 20); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -/** \test lots of gaps in block list */ -static int StreamingBufferTest09(void) -{ - StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 2); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"H", 1, 7) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 3); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg4; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"F", 1, 5) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 4); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg5; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); - Dump(sb); - StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferSegment seg6; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0); - Dump(sb); - sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -/** \test lots of gaps in block list */ -static int StreamingBufferTest10(void) -{ - StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; - StreamingBuffer *sb = StreamingBufferInit(&cfg); - FAIL_IF(sb == NULL); - - StreamingBufferSegment seg1; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"A", 1, 0) != 0); - Dump(sb); - StreamingBufferSegment seg2; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); - Dump(sb); - StreamingBufferSegment seg3; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"H", 1, 7) != 0); - Dump(sb); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 3); - - StreamingBufferSegment seg4; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"B", 1, 1) != 0); - Dump(sb); - StreamingBufferSegment seg5; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"C", 1, 2) != 0); - Dump(sb); - StreamingBufferSegment seg6; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"G", 1, 6) != 0); - Dump(sb); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 6); - - StreamingBufferSegment seg7; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg7, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); - Dump(sb); - StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - - StreamingBufferSegment seg8; - FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg8, (const uint8_t *)"abcdefghij", 10, 0) != 0); - Dump(sb); - sbb1 = RB_MIN(SBB, &sb->sbb_tree); - FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); - FAIL_IF_NULL(sbb1); - FAIL_IF(sbb1->offset != 0); - FAIL_IF(sbb1->len != 10); - FAIL_IF(SBB_RB_NEXT(sbb1)); - FAIL_IF_NULL(sb->head); - FAIL_IF_NOT(sb->sbb_size == 10); - - StreamingBufferFree(sb, &cfg); - PASS; -} - -#endif - -void StreamingBufferRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02); - UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03); - UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04); - UtRegisterTest("StreamingBufferTest06", StreamingBufferTest06); - UtRegisterTest("StreamingBufferTest07", StreamingBufferTest07); - UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08); - UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09); - UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10); -#endif -} diff --git a/src/util-streaming-buffer.h b/src/util-streaming-buffer.h deleted file mode 100644 index 98ee6f67ca26..000000000000 --- a/src/util-streaming-buffer.h +++ /dev/null @@ -1,203 +0,0 @@ -/* Copyright (C) 2015-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/* - * This API is meant to be used with streaming data. A single memory - * block is used to store the data. StreamingBufferSegment points to - * chunk of data in the single StreamingBuffer. It points by offset - * and length, so no pointers. The buffer is resized on demand and - * slides forward, either automatically or manually. - * - * When a segment needs it's data it uses StreamingBufferSegmentGetData - * which takes care of checking if the segment still has a valid offset - * and length. - * - * The StreamingBuffer::stream_offset is an absolute offset since the - * start of the data streaming. - * - * Similarly, StreamingBufferSegment::stream_offset is also an absolute - * offset. - * - * Using the segments is optional. - * - * - * stream_offset buf_offset stream_offset + buf_size - * ^ ^ ^ - * | | | - * | | | - * +--------------------------------------------+ - * | data | empty | - * | xxxxxxxxxx | | - * +------^--------^--------+-------------------+ - * | | - * | | - * | | - * | | - * | | - * +------+--------+-------+ - * | StreamingBufferSegment| - * +-----------+-----------+ - * | offset | len | - * +-----------+-----------+ - */ - - -#ifndef __UTIL_STREAMING_BUFFER_H__ -#define __UTIL_STREAMING_BUFFER_H__ - -#include "tree.h" - -#define STREAMING_BUFFER_REGION_GAP_DEFAULT 262144 - -typedef struct StreamingBufferConfig_ { - uint32_t buf_size; - uint16_t max_regions; /**< max concurrent memory regions. 0 means no limit. */ - uint32_t region_gap; /**< max gap size before a new region will be created. */ - void *(*Calloc)(size_t n, size_t size); - void *(*Realloc)(void *ptr, size_t orig_size, size_t size); - void (*Free)(void *ptr, size_t size); -} StreamingBufferConfig; - -#define STREAMING_BUFFER_CONFIG_INITIALIZER \ - { \ - 2048, 8, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL, \ - } - -#define STREAMING_BUFFER_REGION_INIT \ - { \ - NULL, 0, 0, 0ULL, NULL, \ - } - -typedef struct StreamingBufferRegion_ { - uint8_t *buf; /**< memory block for reassembly */ - uint32_t buf_size; /**< size of memory block */ - uint32_t buf_offset; /**< how far we are in buf_size */ - uint64_t stream_offset; /**< stream offset of this region */ - struct StreamingBufferRegion_ *next; -} StreamingBufferRegion; - -/** - * \brief block of continues data - */ -typedef struct StreamingBufferBlock { - uint64_t offset; - RB_ENTRY(StreamingBufferBlock) rb; - uint32_t len; -} __attribute__((__packed__)) StreamingBufferBlock; - -int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b); - -/* red-black tree prototype for SACK records */ -RB_HEAD(SBB, StreamingBufferBlock); -RB_PROTOTYPE(SBB, StreamingBufferBlock, rb, SBBCompare); -StreamingBufferBlock *SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm); - -typedef struct StreamingBuffer_ { - StreamingBufferRegion region; - struct SBB sbb_tree; /**< red black tree of Stream Buffer Blocks */ - StreamingBufferBlock *head; /**< head, should always be the same as RB_MIN */ - uint32_t sbb_size; /**< data size covered by sbbs */ - uint16_t regions; - uint16_t max_regions; -#ifdef DEBUG - uint32_t buf_size_max; -#endif -} StreamingBuffer; - -static inline bool StreamingBufferHasData(const StreamingBuffer *sb) -{ - return (sb->region.stream_offset || sb->region.buf_offset || sb->region.next != NULL || - !RB_EMPTY(&sb->sbb_tree)); -} - -static inline uint64_t StreamingBufferGetConsecutiveDataRightEdge(const StreamingBuffer *sb) -{ - return sb->region.stream_offset + sb->region.buf_offset; -} - -static inline uint64_t StreamingBufferGetOffset(const StreamingBuffer *sb) -{ - return sb->region.stream_offset; -} - -#ifndef DEBUG -#define STREAMING_BUFFER_INITIALIZER \ - { \ - STREAMING_BUFFER_REGION_INIT, \ - { NULL }, \ - NULL, \ - 0, \ - 1, \ - 1, \ - }; -#else -#define STREAMING_BUFFER_INITIALIZER { STREAMING_BUFFER_REGION_INIT, { NULL }, NULL, 0, 1, 1, 0 }; -#endif - -typedef struct StreamingBufferSegment_ { - uint32_t segment_len; - uint64_t stream_offset; -} __attribute__((__packed__)) StreamingBufferSegment; - -StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg); -void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg); -void StreamingBufferFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg); - -void StreamingBufferSlideToOffset( - StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint64_t offset); - -int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len) WARN_UNUSED; -int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - const uint8_t *data, uint32_t data_len) WARN_UNUSED; -int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg, - StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, - uint64_t offset) WARN_UNUSED; - -void StreamingBufferSegmentGetData(const StreamingBuffer *sb, - const StreamingBufferSegment *seg, - const uint8_t **data, uint32_t *data_len); - -void StreamingBufferSBBGetData(const StreamingBuffer *sb, - const StreamingBufferBlock *sbb, - const uint8_t **data, uint32_t *data_len); - -void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb, - const StreamingBufferBlock *sbb, - const uint8_t **data, uint32_t *data_len, - uint64_t offset); - -int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, - const StreamingBufferSegment *seg, - const uint8_t *rawdata, uint32_t rawdata_len); -int StreamingBufferCompareRawData(const StreamingBuffer *sb, - const uint8_t *rawdata, uint32_t rawdata_len); - -int StreamingBufferGetData(const StreamingBuffer *sb, - const uint8_t **data, uint32_t *data_len, - uint64_t *stream_offset); - -int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb, - const uint8_t **data, uint32_t *data_len, - uint64_t offset); - -int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, - const StreamingBufferSegment *seg); - -void StreamingBufferRegisterTests(void); - -#endif /* __UTIL_STREAMING_BUFFER_H__ */ diff --git a/src/util-strlcatu.c b/src/util-strlcatu.c deleted file mode 100644 index b2b188f9430a..000000000000 --- a/src/util-strlcatu.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 1998 Todd C. Miller - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* $Id: strlcatu.c,v 1.4 2003/10/20 15:03:27 chrisgreen Exp $ */ - -#include "suricata-common.h" - -#ifndef HAVE_STRLCAT - -#if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: strlcat.c,v 1.5 2001/01/13 16:17:24 millert Exp $"; -#endif /* LIBC_SCCS and not lint */ - -/* - * Appends src to string dst of size siz (unlike strncat, siz is the - * full size of dst, not space left). At most siz-1 characters - * will be copied. Always NUL terminates (unless siz <= strlen(dst)). - * Returns strlen(initial dst) + strlen(src); if retval >= siz, - * truncation occurred. - */ -size_t strlcat(char *dst, const char *src, size_t siz) -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} -#endif diff --git a/src/util-strlcpyu.c b/src/util-strlcpyu.c deleted file mode 100644 index 7b746bd9c740..000000000000 --- a/src/util-strlcpyu.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1998 Todd C. Miller - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* $Id: strlcpyu.c,v 1.4 2003/10/20 15:03:27 chrisgreen Exp $ */ - -#include "suricata-common.h" - -#ifndef HAVE_STRLCPY - -#if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $"; -#endif /* LIBC_SCCS and not lint */ - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t strlcpy(char *dst, const char *src, size_t siz) -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} -#endif diff --git a/src/util-strptime.c b/src/util-strptime.c deleted file mode 100644 index e0475ec611f0..000000000000 --- a/src/util-strptime.c +++ /dev/null @@ -1,599 +0,0 @@ -/* $NetBSD: strptime.c,v 1.36 2012/03/13 21:13:48 christos Exp $ */ - -/*- - * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code was contributed to The NetBSD Foundation by Klaus Klein. - * Heavily optimised by David Laight - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/* -#include -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: strptime.c,v 1.36 2012/03/13 21:13:48 christos Exp $"); -#endif - -#include "namespace.h" -#include -*/ -#include "suricata-common.h" -#ifndef HAVE_STRPTIME -#include -#include -#include -#include -#include -/* -#include -#include "private.h" - -#ifdef __weak_alias -__weak_alias(strptime,_strptime) -#endif -*/ - -#define _ctloc(x) (_CurrentTimeLocale->x) - -/* - * We do not implement alternate representations. However, we always - * check whether a given modifier is allowed for a certain conversion. - */ -#define ALT_E 0x01 -#define ALT_O 0x02 -#define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } - -static int TM_YEAR_BASE = 1900; -static char gmt[] = { "GMT" }; -static char utc[] = { "UTC" }; -/* RFC-822/RFC-2822 */ -static const char * const nast[5] = { - "EST", "CST", "MST", "PST", "\0\0\0" -}; -static const char * const nadt[5] = { - "EDT", "CDT", "MDT", "PDT", "\0\0\0" -}; -static const char * const am_pm[2] = { - "am", "pm" -}; -static const char * const day[7] = { - "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" -}; -static const char * const abday[7] = { - "sun", "mon", "tue", "wed", "thu", "fri", "sat" -}; -static const char * const mon[12] = { - "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" -}; -static const char * const abmon[12] = { - "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" -}; - -static const u_char *conv_num(const unsigned char *, int *, unsigned int, unsigned int); -static const u_char *find_string(const u_char *, int *, const char * const *, - const char * const *, int); - -char * -strptime(const char *buf, const char *fmt, struct tm *tm) -{ - unsigned char c; - const unsigned char *bp, *ep; - int alt_format, i, split_year = 0, neg = 0, offs; - const char *new_fmt; - - bp = (const u_char *)buf; - - while (bp != NULL && (c = *fmt++) != '\0') { - /* Clear `alternate' modifier prior to new conversion. */ - alt_format = 0; - i = 0; - - /* Eat up white-space. */ - if (isspace(c)) { - while (isspace(*bp)) - bp++; - continue; - } - - if (c != '%') - goto literal; - - -again: switch (c = *fmt++) { - case '%': /* "%%" is converted to "%". */ -literal: - if (c != *bp++) - return NULL; - LEGAL_ALT(0); - continue; - - /* - * "Alternative" modifiers. Just set the appropriate flag - * and start over again. - */ - case 'E': /* "%E?" alternative conversion modifier. */ - LEGAL_ALT(0); - alt_format |= ALT_E; - goto again; - - case 'O': /* "%O?" alternative conversion modifier. */ - LEGAL_ALT(0); - alt_format |= ALT_O; - goto again; - - /* - * "Complex" conversion rules, implemented through recursion. - */ - /* we do not need 'c' - case 'c': Date and time, using the locale's format. - new_fmt = _ctloc(d_t_fmt); - goto recurse; - */ - - case 'D': /* The date as "%m/%d/%y". */ - new_fmt = "%m/%d/%y"; - LEGAL_ALT(0); - goto recurse; - - case 'F': /* The date as "%Y-%m-%d". */ - new_fmt = "%Y-%m-%d"; - LEGAL_ALT(0); - goto recurse; - - case 'R': /* The time as "%H:%M". */ - new_fmt = "%H:%M"; - LEGAL_ALT(0); - goto recurse; - - case 'r': /* The time in 12-hour clock representation. */ - new_fmt = "%I:%M:S %p";//_ctloc(t_fmt_ampm); - LEGAL_ALT(0); - goto recurse; - - case 'T': /* The time as "%H:%M:%S". */ - new_fmt = "%H:%M:%S"; - LEGAL_ALT(0); - goto recurse; - - /* we don't use 'X' - case 'X': The time, using the locale's format. - new_fmt =_ctloc(t_fmt); - goto recurse; - */ - - /* we do not need 'x' - case 'x': The date, using the locale's format. - new_fmt =_ctloc(d_fmt);*/ -recurse: - bp = (const u_char *)strptime((const char *)bp, - new_fmt, tm); - LEGAL_ALT(ALT_E); - continue; - - /* - * "Elementary" conversion rules. - */ - case 'A': /* The day of week, using the locale's form. */ - case 'a': - bp = find_string(bp, &tm->tm_wday, day, abday, 7); - LEGAL_ALT(0); - continue; - - case 'B': /* The month, using the locale's form. */ - case 'b': - case 'h': - bp = find_string(bp, &tm->tm_mon, mon, abmon, 12); - LEGAL_ALT(0); - continue; - - case 'C': /* The century number. */ - i = 20; - bp = conv_num(bp, &i, 0, 99); - - i = i * 100 - TM_YEAR_BASE; - if (split_year) - i += tm->tm_year % 100; - split_year = 1; - tm->tm_year = i; - LEGAL_ALT(ALT_E); - continue; - - case 'd': /* The day of month. */ - case 'e': - bp = conv_num(bp, &tm->tm_mday, 1, 31); - LEGAL_ALT(ALT_O); - continue; - - case 'k': /* The hour (24-hour clock representation). */ - LEGAL_ALT(0); - /* FALLTHROUGH */ - case 'H': - bp = conv_num(bp, &tm->tm_hour, 0, 23); - LEGAL_ALT(ALT_O); - continue; - - case 'l': /* The hour (12-hour clock representation). */ - LEGAL_ALT(0); - /* FALLTHROUGH */ - case 'I': - bp = conv_num(bp, &tm->tm_hour, 1, 12); - if (tm->tm_hour == 12) - tm->tm_hour = 0; - LEGAL_ALT(ALT_O); - continue; - - case 'j': /* The day of year. */ - i = 1; - bp = conv_num(bp, &i, 1, 366); - tm->tm_yday = i - 1; - LEGAL_ALT(0); - continue; - - case 'M': /* The minute. */ - bp = conv_num(bp, &tm->tm_min, 0, 59); - LEGAL_ALT(ALT_O); - continue; - - case 'm': /* The month. */ - i = 1; - bp = conv_num(bp, &i, 1, 12); - tm->tm_mon = i - 1; - LEGAL_ALT(ALT_O); - continue; - - case 'p': /* The locale's equivalent of AM/PM. */ - bp = find_string(bp, &i, am_pm, NULL, 2); - if (tm->tm_hour > 11) - return NULL; - tm->tm_hour += i * 12; - LEGAL_ALT(0); - continue; - - case 'S': /* The seconds. */ - bp = conv_num(bp, &tm->tm_sec, 0, 61); - LEGAL_ALT(ALT_O); - continue; - -#ifndef TIME_MAX -#define TIME_MAX INT64_MAX -#endif - case 's': /* seconds since the epoch */ - { - time_t sse = 0; - uint64_t rulim = TIME_MAX; - - if (*bp < '0' || *bp > '9') { - bp = NULL; - continue; - } - - do { - sse *= 10; - sse += *bp++ - '0'; - rulim /= 10; - } while (((uint64_t)sse * 10 <= TIME_MAX) && - rulim && *bp >= '0' && *bp <= '9'); - - if (sse < 0 || (uint64_t)sse > TIME_MAX) { - bp = NULL; - continue; - } - - tm = localtime(&sse); - if (tm == NULL) - bp = NULL; - } - continue; - - case 'U': /* The week of year, beginning on sunday. */ - case 'W': /* The week of year, beginning on monday. */ - /* - * XXX This is bogus, as we can not assume any valid - * information present in the tm structure at this - * point to calculate a real value, so just check the - * range for now. - */ - bp = conv_num(bp, &i, 0, 53); - LEGAL_ALT(ALT_O); - continue; - - case 'w': /* The day of week, beginning on sunday. */ - bp = conv_num(bp, &tm->tm_wday, 0, 6); - LEGAL_ALT(ALT_O); - continue; - - case 'u': /* The day of week, monday = 1. */ - bp = conv_num(bp, &i, 1, 7); - tm->tm_wday = i % 7; - LEGAL_ALT(ALT_O); - continue; - - case 'g': /* The year corresponding to the ISO week - * number but without the century. - */ - bp = conv_num(bp, &i, 0, 99); - continue; - - case 'G': /* The year corresponding to the ISO week - * number with century. - */ - do - bp++; - while (isdigit(*bp)); - continue; - - case 'V': /* The ISO 8601:1988 week number as decimal */ - bp = conv_num(bp, &i, 0, 53); - continue; - - case 'Y': /* The year. */ - i = TM_YEAR_BASE; /* just for data sanity... */ - bp = conv_num(bp, &i, 0, 9999); - tm->tm_year = i - TM_YEAR_BASE; - LEGAL_ALT(ALT_E); - continue; - - case 'y': /* The year within 100 years of the epoch. */ - /* LEGAL_ALT(ALT_E | ALT_O); */ - bp = conv_num(bp, &i, 0, 99); - - if (split_year) - /* preserve century */ - i += (tm->tm_year / 100) * 100; - else { - split_year = 1; - if (i <= 68) - i = i + 2000 - TM_YEAR_BASE; - else - i = i + 1900 - TM_YEAR_BASE; - } - tm->tm_year = i; - continue; - - case 'Z': - tzset(); - if (strncasecmp((const char *)bp, gmt, 3) == 0 - || strncasecmp((const char *)bp, utc, 3) == 0) { - tm->tm_isdst = 0; -#ifdef TM_GMTOFF - tm->TM_GMTOFF = 0; -#endif -#ifdef TM_ZONE - tm->TM_ZONE = gmt; -#endif - bp += 3; - } else { - ep = find_string(bp, &i, - (const char * const *)tzname, - NULL, 2); - if (ep != NULL) { - tm->tm_isdst = i; -#ifdef TM_GMTOFF - tm->TM_GMTOFF = -(timezone); -#endif -#ifdef TM_ZONE - tm->TM_ZONE = tzname[i]; -#endif - } - bp = ep; - } - continue; - - case 'z': - /* - * We recognize all ISO 8601 formats: - * Z = Zulu time/UTC - * [+-]hhmm - * [+-]hh:mm - * [+-]hh - * We recognize all RFC-822/RFC-2822 formats: - * UT|GMT - * North American : UTC offsets - * E[DS]T = Eastern : -4 | -5 - * C[DS]T = Central : -5 | -6 - * M[DS]T = Mountain: -6 | -7 - * P[DS]T = Pacific : -7 | -8 - * Military - * [A-IL-M] = -1 ... -9 (J not used) - * [N-Y] = +1 ... +12 - */ - while (isspace(*bp)) - bp++; - - switch (*bp++) { - case 'G': - if (*bp++ != 'M') - return NULL; - /*FALLTHROUGH*/ - case 'U': - if (*bp++ != 'T') - return NULL; - /*FALLTHROUGH*/ - case 'Z': - tm->tm_isdst = 0; -#ifdef TM_GMTOFF - tm->TM_GMTOFF = 0; -#endif -#ifdef TM_ZONE - tm->TM_ZONE = utc; -#endif - continue; - case '+': - neg = 0; - break; - case '-': - neg = 1; - break; - default: - --bp; - ep = find_string(bp, &i, nast, NULL, 4); - if (ep != NULL) { -#ifdef TM_GMTOFF - tm->TM_GMTOFF = -5 - i; -#endif -#ifdef TM_ZONE - tm->TM_ZONE = __UNCONST(nast[i]); -#endif - bp = ep; - continue; - } - ep = find_string(bp, &i, nadt, NULL, 4); - if (ep != NULL) { - tm->tm_isdst = 1; -#ifdef TM_GMTOFF - tm->TM_GMTOFF = -4 - i; -#endif -#ifdef TM_ZONE - tm->TM_ZONE = __UNCONST(nadt[i]); -#endif - bp = ep; - continue; - } - - if ((*bp >= 'A' && *bp <= 'I') || - (*bp >= 'L' && *bp <= 'Y')) { -#ifdef TM_GMTOFF - /* Argh! No 'J'! */ - if (*bp >= 'A' && *bp <= 'I') - tm->TM_GMTOFF = - ('A' - 1) - (int)*bp; - else if (*bp >= 'L' && *bp <= 'M') - tm->TM_GMTOFF = 'A' - (int)*bp; - else if (*bp >= 'N' && *bp <= 'Y') - tm->TM_GMTOFF = (int)*bp - 'M'; -#endif -#ifdef TM_ZONE - tm->TM_ZONE = NULL; /* XXX */ -#endif - bp++; - continue; - } - return NULL; - } - offs = 0; - for (i = 0; i < 4; ) { - if (isdigit(*bp)) { - offs = offs * 10 + (*bp++ - '0'); - i++; - continue; - } - if (i == 2 && *bp == ':') { - bp++; - continue; - } - break; - } - switch (i) { - case 2: - offs *= 100; - break; - case 4: - i = offs % 100; - if (i >= 60) - return NULL; - /* Convert minutes into decimal */ - offs = (offs / 100) * 100 + (i * 50) / 30; - break; - default: - return NULL; - } - if (neg) - offs = -offs; - tm->tm_isdst = 0; /* XXX */ -#ifdef TM_GMTOFF - tm->TM_GMTOFF = offs; -#endif -#ifdef TM_ZONE - tm->TM_ZONE = NULL; /* XXX */ -#endif - continue; - - /* - * Miscellaneous conversions. - */ - case 'n': /* Any kind of white-space. */ - case 't': - while (isspace(*bp)) - bp++; - LEGAL_ALT(0); - continue; - - - default: /* Unknown/unsupported conversion. */ - return NULL; - } - } - - return (char *)(bp); -} - - -static const u_char * -conv_num(const unsigned char *buf, int *dest, unsigned int llim, unsigned int ulim) -{ - unsigned int result = 0; - unsigned char ch; - - /* The limit also determines the number of valid digits. */ - unsigned int rulim = ulim; - - ch = *buf; - if (ch < '0' || ch > '9') - return NULL; - - do { - result *= 10; - result += ch - '0'; - rulim /= 10; - ch = *++buf; - } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9'); - - if (result < llim || result > ulim) - return NULL; - - *dest = result; - return buf; -} - -static const u_char * -find_string(const u_char *bp, int *tgt, const char * const *n1, - const char * const *n2, int c) -{ - int i; - size_t len; - - /* check full name - then abbreviated ones */ - for (; n1 != NULL; n1 = n2, n2 = NULL) { - for (i = 0; i < c; i++, n1++) { - len = strlen(*n1); - if (strncasecmp(*n1, (const char *)bp, len) == 0) { - *tgt = i; - return bp + len; - } - } - } - - /* Nothing matched */ - return NULL; -} -#endif /* HAVE_STRPTIME */ diff --git a/src/util-sysfs.c b/src/util-sysfs.c deleted file mode 100644 index 11f1854a8c45..000000000000 --- a/src/util-sysfs.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (C) 2011-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Richard McConnell - * - * Sysfs utility file - */ - -#include "util-sysfs.h" - -#define SYSFS_MAX_FILENAME_LEN (SYSFS_MAX_FILENAME_SIZE + 5) - -TmEcode SysFsWriteValue(const char *path, int64_t value) -{ -#if defined(__linux__) - char fname[SYSFS_MAX_FILENAME_LEN] = "/sys/"; - char sentence[64]; - - if (!path || strlen(path) > SYSFS_MAX_FILENAME_SIZE) { - SCLogWarning("File path too long, max allowed: %d", SYSFS_MAX_FILENAME_SIZE); - SCReturnInt(TM_ECODE_FAILED); - } - - strlcat(fname, path, sizeof(fname)); - - /* File must be present and process have correct capabilities to open */ - int fd = open(fname, O_WRONLY); - if (fd < 0) { - SCLogError("Could not open file: %s", fname); - SCReturnInt(TM_ECODE_FAILED); - } - - snprintf(sentence, sizeof(sentence), "%" PRIu64, value); - ssize_t len = strlen(sentence); - - if (write(fd, sentence, len) != len) { - SCLogError("Could not write to file: %s", fname); - close(fd); - SCReturnInt(TM_ECODE_FAILED); - } - close(fd); -#endif /* __LINUX__ */ - - SCReturnInt(TM_ECODE_OK); -} diff --git a/src/util-sysfs.h b/src/util-sysfs.h deleted file mode 100644 index 6318accb2b32..000000000000 --- a/src/util-sysfs.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (C) 2011-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Richard McConnell - * - */ - -#ifndef UTIL_SYSFS_H -#define UTIL_SYSFS_H - -#include "util-error.h" -#include "util-debug.h" - -/* /sys/ prepended as mount point 251 + 5 = 256 */ -#define SYSFS_MAX_FILENAME_SIZE 251 - -TmEcode SysFsWriteValue(const char *path, int64_t value); - -#endif /* UTIL_SYSFS_H */ diff --git a/src/util-syslog.c b/src/util-syslog.c deleted file mode 100644 index 482f206789aa..000000000000 --- a/src/util-syslog.c +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - * - * Syslog utility file - * - */ - -#include "suricata-common.h" -#include "util-syslog.h" - -/* holds the string-enum mapping for the syslog facility in SCLogOPIfaceCtx */ -SCEnumCharMap sc_syslog_facility_map[] = { - { "auth", LOG_AUTH }, - { "authpriv", LOG_AUTHPRIV }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "security", LOG_AUTH }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, -1 } -}; - -/** \brief returns the syslog facility enum map */ -SCEnumCharMap *SCSyslogGetFacilityMap(void) -{ - return sc_syslog_facility_map; -} - -SCEnumCharMap sc_syslog_level_map[ ] = { - { "Emergency", LOG_EMERG }, - { "Alert", LOG_ALERT }, - { "Critical", LOG_CRIT }, - { "Error", LOG_ERR }, - { "Warning", LOG_WARNING }, - { "Notice", LOG_NOTICE }, - { "Info", LOG_INFO }, - { "Debug", LOG_DEBUG }, - { NULL, -1 } -}; - -/** \brief returns the syslog facility enum map */ -SCEnumCharMap *SCSyslogGetLogLevelMap(void) -{ - return sc_syslog_level_map; -} - diff --git a/src/util-syslog.h b/src/util-syslog.h deleted file mode 100644 index 473057a102a0..000000000000 --- a/src/util-syslog.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh - * - */ - -#ifndef UTIL_SYSLOG_H -#define UTIL_SYSLOG_H - -#include "util-enum.h" - -SCEnumCharMap *SCSyslogGetFacilityMap(void); -SCEnumCharMap *SCSyslogGetLogLevelMap(void); - -#ifndef OS_WIN32 -#define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" -#define DEFAULT_ALERT_SYSLOG_FACILITY LOG_LOCAL0 -#define DEFAULT_ALERT_SYSLOG_LEVEL LOG_ERR -#endif - -#endif /* UTIL_SYSLOG_H */ diff --git a/src/util-thash.c b/src/util-thash.c deleted file mode 100644 index 6443990bc219..000000000000 --- a/src/util-thash.c +++ /dev/null @@ -1,820 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - */ - -#include "suricata-common.h" -#include "conf.h" - -#include "util-debug.h" -#include "util-thash.h" - -#include "util-random.h" -#include "util-misc.h" -#include "util-byte.h" - -#include "util-hash-lookup3.h" -#include "util-validate.h" - -static THashData *THashGetUsed(THashTableContext *ctx); -static void THashDataEnqueue (THashDataQueue *q, THashData *h); - -void THashDataMoveToSpare(THashTableContext *ctx, THashData *h) -{ - THashDataEnqueue(&ctx->spare_q, h); - (void) SC_ATOMIC_SUB(ctx->counter, 1); -} - -static THashDataQueue *THashDataQueueInit (THashDataQueue *q) -{ - if (q != NULL) { - memset(q, 0, sizeof(THashDataQueue)); - HQLOCK_INIT(q); - } - return q; -} - -THashDataQueue *THashDataQueueNew(void) -{ - THashDataQueue *q = (THashDataQueue *)SCMalloc(sizeof(THashDataQueue)); - if (q == NULL) { - SCLogError("Fatal error encountered in THashDataQueueNew. Exiting..."); - exit(EXIT_SUCCESS); - } - q = THashDataQueueInit(q); - return q; -} - -/** - * \brief Destroy a queue - * - * \param q the queue to destroy - */ -static void THashDataQueueDestroy (THashDataQueue *q) -{ - HQLOCK_DESTROY(q); -} - -/** - * \brief add to queue - * - * \param q queue - * \param h data - */ -static void THashDataEnqueue (THashDataQueue *q, THashData *h) -{ -#ifdef DEBUG - BUG_ON(q == NULL || h == NULL); -#endif - - HQLOCK_LOCK(q); - - /* more data in queue */ - if (q->top != NULL) { - h->next = q->top; - q->top->prev = h; - q->top = h; - /* only data */ - } else { - q->top = h; - q->bot = h; - } - q->len++; -#ifdef DBG_PERF - if (q->len > q->dbg_maxlen) - q->dbg_maxlen = q->len; -#endif /* DBG_PERF */ - HQLOCK_UNLOCK(q); -} - -/** - * \brief remove data from the queue - * - * \param q queue - * - * \retval h data or NULL if empty list. - */ -static THashData *THashDataDequeue (THashDataQueue *q) -{ - HQLOCK_LOCK(q); - - THashData *h = q->bot; - if (h == NULL) { - HQLOCK_UNLOCK(q); - return NULL; - } - - /* more packets in queue */ - if (q->bot->prev != NULL) { - q->bot = q->bot->prev; - q->bot->next = NULL; - /* just the one we remove, so now empty */ - } else { - q->top = NULL; - q->bot = NULL; - } - -#ifdef DEBUG - BUG_ON(q->len == 0); -#endif - if (q->len > 0) - q->len--; - - h->next = NULL; - h->prev = NULL; - - HQLOCK_UNLOCK(q); - return h; -} - -#if 0 -static uint32_t THashDataQueueLen(THashDataQueue *q) -{ - uint32_t len; - HQLOCK_LOCK(q); - len = q->len; - HQLOCK_UNLOCK(q); - return len; -} -#endif - -static THashData *THashDataAlloc(THashTableContext *ctx) -{ - const size_t data_size = THASH_DATA_SIZE(ctx); - - if (!(THASH_CHECK_MEMCAP(ctx, data_size))) { - return NULL; - } - - (void) SC_ATOMIC_ADD(ctx->memuse, data_size); - - THashData *h = SCCalloc(1, data_size); - if (unlikely(h == NULL)) - goto error; - - /* points to data right after THashData block */ - h->data = (uint8_t *)h + sizeof(THashData); - -// memset(h, 0x00, data_size); - - SCMutexInit(&h->m, NULL); - SC_ATOMIC_INIT(h->use_cnt); - return h; - -error: - return NULL; -} - -static void THashDataFree(THashTableContext *ctx, THashData *h) -{ - if (h != NULL) { - DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(h->use_cnt) != 0); - - if (h->data != NULL) { - ctx->config.DataFree(h->data); - } - SCMutexDestroy(&h->m); - SCFree(h); - (void) SC_ATOMIC_SUB(ctx->memuse, THASH_DATA_SIZE(ctx)); - } -} - -#define THASH_DEFAULT_HASHSIZE 4096 -#define THASH_DEFAULT_MEMCAP 16777216 -#define THASH_DEFAULT_PREALLOC 1000 - -#define GET_VAR(prefix,name) \ - snprintf(varname, sizeof(varname), "%s.%s", (prefix), (name)) - -/** \brief initialize the configuration - * \warning Not thread safe */ -static int THashInitConfig(THashTableContext *ctx, const char *cnf_prefix) -{ - char varname[256]; - - SCLogDebug("initializing thash engine..."); - - /* Check if we have memcap and hash_size defined at config */ - const char *conf_val; - uint32_t configval = 0; - - /** set config values for memcap, prealloc and hash_size */ - GET_VAR(cnf_prefix, "memcap"); - if ((ConfGet(varname, &conf_val)) == 1) - { - if (ParseSizeStringU64(conf_val, &ctx->config.memcap) < 0) { - SCLogError("Error parsing %s " - "from conf file - %s. Killing engine", - varname, conf_val); - return -1; - } - } - GET_VAR(cnf_prefix, "hash-size"); - if ((ConfGet(varname, &conf_val)) == 1) - { - if (StringParseUint32(&configval, 10, (uint16_t)strlen(conf_val), conf_val) > 0) { - ctx->config.hash_size = configval; - } - } - - GET_VAR(cnf_prefix, "prealloc"); - if ((ConfGet(varname, &conf_val)) == 1) - { - if (StringParseUint32(&configval, 10, (uint16_t)strlen(conf_val), conf_val) > 0) { - ctx->config.prealloc = configval; - } else { - WarnInvalidConfEntry(varname, "%"PRIu32, ctx->config.prealloc); - } - } - - /* alloc hash memory */ - uint64_t hash_size = ctx->config.hash_size * sizeof(THashHashRow); - if (!(THASH_CHECK_MEMCAP(ctx, hash_size))) { - SCLogError("allocating hash failed: " - "max hash memcap is smaller than projected hash size. " - "Memcap: %" PRIu64 ", Hash table size %" PRIu64 ". Calculate " - "total hash size by multiplying \"hash-size\" with %" PRIuMAX ", " - "which is the hash bucket size.", - ctx->config.memcap, hash_size, (uintmax_t)sizeof(THashHashRow)); - return -1; - } - ctx->array = SCMallocAligned(ctx->config.hash_size * sizeof(THashHashRow), CLS); - if (unlikely(ctx->array == NULL)) { - SCLogError("Fatal error encountered in THashInitConfig. Exiting..."); - return -1; - } - memset(ctx->array, 0, ctx->config.hash_size * sizeof(THashHashRow)); - - uint32_t i = 0; - for (i = 0; i < ctx->config.hash_size; i++) { - HRLOCK_INIT(&ctx->array[i]); - } - (void) SC_ATOMIC_ADD(ctx->memuse, (ctx->config.hash_size * sizeof(THashHashRow))); - - /* pre allocate prealloc */ - for (i = 0; i < ctx->config.prealloc; i++) { - if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) { - SCLogError("preallocating data failed: " - "max thash memcap reached. Memcap %" PRIu64 ", " - "Memuse %" PRIu64 ".", - ctx->config.memcap, - ((uint64_t)SC_ATOMIC_GET(ctx->memuse) + THASH_DATA_SIZE(ctx))); - return -1; - } - - THashData *h = THashDataAlloc(ctx); - if (h == NULL) { - SCLogError("preallocating data failed: %s", strerror(errno)); - return -1; - } - THashDataEnqueue(&ctx->spare_q,h); - } - - return 0; -} - -THashTableContext *THashInit(const char *cnf_prefix, size_t data_size, - int (*DataSet)(void *, void *), void (*DataFree)(void *), uint32_t (*DataHash)(void *), - bool (*DataCompare)(void *, void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize) -{ - THashTableContext *ctx = SCCalloc(1, sizeof(*ctx)); - BUG_ON(!ctx); - - ctx->config.data_size = data_size; - ctx->config.DataSet = DataSet; - ctx->config.DataFree = DataFree; - ctx->config.DataHash = DataHash; - ctx->config.DataCompare = DataCompare; - - /* set defaults */ - ctx->config.hash_rand = (uint32_t)RandomGet(); - ctx->config.hash_size = hashsize > 0 ? hashsize : THASH_DEFAULT_HASHSIZE; - /* Reset memcap in case of loading from file to the highest possible value - unless defined by the rule keyword */ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - // limit memcap size to default when fuzzing - ctx->config.memcap = THASH_DEFAULT_MEMCAP; -#else - if (memcap > 0) { - ctx->config.memcap = memcap; - } else { - ctx->config.memcap = reset_memcap ? UINT64_MAX : THASH_DEFAULT_MEMCAP; - } -#endif - ctx->config.prealloc = THASH_DEFAULT_PREALLOC; - - SC_ATOMIC_INIT(ctx->counter); - SC_ATOMIC_INIT(ctx->memuse); - SC_ATOMIC_INIT(ctx->prune_idx); - THashDataQueueInit(&ctx->spare_q); - - if (THashInitConfig(ctx, cnf_prefix) < 0) { - THashShutdown(ctx); - ctx = NULL; - } - return ctx; -} - -/* \brief Set memcap to current memuse - * */ -void THashConsolidateMemcap(THashTableContext *ctx) -{ - ctx->config.memcap = MAX(SC_ATOMIC_GET(ctx->memuse), ctx->config.memcap); - SCLogDebug("memcap after load set to: %" PRIu64, ctx->config.memcap); -} - -/** \brief shutdown the flow engine - * \warning Not thread safe */ -void THashShutdown(THashTableContext *ctx) -{ - THashData *h; - - /* free spare queue */ - while ((h = THashDataDequeue(&ctx->spare_q))) { - BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0); - THashDataFree(ctx, h); - } - - /* clear and free the hash */ - if (ctx->array != NULL) { - for (uint32_t u = 0; u < ctx->config.hash_size; u++) { - h = ctx->array[u].head; - while (h) { - THashData *n = h->next; - THashDataFree(ctx, h); - h = n; - } - - HRLOCK_DESTROY(&ctx->array[u]); - } - SCFreeAligned(ctx->array); - ctx->array = NULL; - } - (void) SC_ATOMIC_SUB(ctx->memuse, ctx->config.hash_size * sizeof(THashHashRow)); - THashDataQueueDestroy(&ctx->spare_q); - SCFree(ctx); - return; -} - -/** \brief Walk the hash - * - */ -int THashWalk(THashTableContext *ctx, THashFormatFunc FormatterFunc, THashOutputFunc OutputterFunc, void *output_ctx) -{ - uint32_t u; - - if (ctx->array == NULL) - return -1; - - bool err = false; - for (u = 0; u < ctx->config.hash_size; u++) { - THashHashRow *hb = &ctx->array[u]; - HRLOCK_LOCK(hb); - THashData *h = hb->head; - while (h) { - char output_string[1024] = ""; - int size = FormatterFunc(h->data, output_string, sizeof(output_string)); - if (size > 0) { - if (OutputterFunc(output_ctx, (const uint8_t *)output_string, size) < 0) { - err = true; - break; - } - } - h = h->next; - } - HRLOCK_UNLOCK(hb); - if (err == true) - return -1; - } - return 0; -} - -/** \brief Cleanup the thash engine - * - * Cleanup the thash engine from tag and threshold. - * - */ -void THashCleanup(THashTableContext *ctx) -{ - uint32_t u; - - if (ctx->array == NULL) - return; - - for (u = 0; u < ctx->config.hash_size; u++) { - THashHashRow *hb = &ctx->array[u]; - HRLOCK_LOCK(hb); - THashData *h = hb->head; - while (h) { - if ((SC_ATOMIC_GET(h->use_cnt) > 0)) { - h = h->next; - } else { - THashData *n = h->next; - /* remove from the hash */ - if (h->prev != NULL) - h->prev->next = h->next; - if (h->next != NULL) - h->next->prev = h->prev; - if (hb->head == h) - hb->head = h->next; - if (hb->tail == h) - hb->tail = h->prev; - h->next = NULL; - h->prev = NULL; - THashDataMoveToSpare(ctx, h); - h = n; - } - } - HRLOCK_UNLOCK(hb); - } - return; -} - -/* calculate the hash key for this packet - * - * we're using: - * hash_rand -- set at init time - * source address - */ -static uint32_t THashGetKey(const THashConfig *cnf, void *data) -{ - uint32_t key; - - key = cnf->DataHash(data); - key %= cnf->hash_size; - - return key; -} - -static inline int THashCompare(const THashConfig *cnf, void *a, void *b) -{ - if (cnf->DataCompare(a, b)) - return 1; - return 0; -} - -/** - * \brief Get new data - * - * Get new data. We're checking memcap first and will try to make room - * if the memcap is reached. - * - * \retval h *LOCKED* data on succes, NULL on error. - */ -static THashData *THashDataGetNew(THashTableContext *ctx, void *data) -{ - THashData *h = NULL; - - /* get data from the spare queue */ - h = THashDataDequeue(&ctx->spare_q); - if (h == NULL) { - /* If we reached the max memcap, we get used data */ - if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) { - h = THashGetUsed(ctx); - if (h == NULL) { - return NULL; - } - - if (!SC_ATOMIC_GET(ctx->memcap_reached)) { - SC_ATOMIC_SET(ctx->memcap_reached, true); - } - - /* freed data, but it's unlocked */ - } else { - /* now see if we can alloc a new data */ - h = THashDataAlloc(ctx); - if (h == NULL) { - return NULL; - } - - /* data is initialized but *unlocked* */ - } - } else { - /* data has been recycled before it went into the spare queue */ - - /* data is initialized (recycled) but *unlocked* */ - } - - // setup the data - BUG_ON(ctx->config.DataSet(h->data, data) != 0); - - (void) SC_ATOMIC_ADD(ctx->counter, 1); - SCMutexLock(&h->m); - return h; -} - -/* - * returns a *LOCKED* data or NULL - */ - -struct THashDataGetResult -THashGetFromHash (THashTableContext *ctx, void *data) -{ - struct THashDataGetResult res = { .data = NULL, .is_new = false, }; - THashData *h = NULL; - - /* get the key to our bucket */ - uint32_t key = THashGetKey(&ctx->config, data); - /* get our hash bucket and lock it */ - THashHashRow *hb = &ctx->array[key]; - HRLOCK_LOCK(hb); - - /* see if the bucket already has data */ - if (hb->head == NULL) { - h = THashDataGetNew(ctx, data); - if (h == NULL) { - HRLOCK_UNLOCK(hb); - return res; - } - - /* data is locked */ - hb->head = h; - hb->tail = h; - - /* initialize and return */ - (void) THashIncrUsecnt(h); - - HRLOCK_UNLOCK(hb); - res.data = h; - res.is_new = true; - return res; - } - - /* ok, we have data in the bucket. Let's find out if it is our data */ - h = hb->head; - - /* see if this is the data we are looking for */ - if (THashCompare(&ctx->config, h->data, data) == 0) { - THashData *ph = NULL; /* previous data */ - - while (h) { - ph = h; - h = h->next; - - if (h == NULL) { - h = ph->next = THashDataGetNew(ctx, data); - if (h == NULL) { - HRLOCK_UNLOCK(hb); - return res; - } - hb->tail = h; - - /* data is locked */ - - h->prev = ph; - - /* initialize and return */ - (void) THashIncrUsecnt(h); - - HRLOCK_UNLOCK(hb); - res.data = h; - res.is_new = true; - return res; - } - - if (THashCompare(&ctx->config, h->data, data) != 0) { - /* we found our data, lets put it on top of the - * hash list -- this rewards active data */ - if (h->next) { - h->next->prev = h->prev; - } - if (h->prev) { - h->prev->next = h->next; - } - if (h == hb->tail) { - hb->tail = h->prev; - } - - h->next = hb->head; - h->prev = NULL; - hb->head->prev = h; - hb->head = h; - - /* found our data, lock & return */ - SCMutexLock(&h->m); - (void) THashIncrUsecnt(h); - HRLOCK_UNLOCK(hb); - res.data = h; - res.is_new = false; - /* coverity[missing_unlock : FALSE] */ - return res; - } - } - } - - /* lock & return */ - SCMutexLock(&h->m); - (void) THashIncrUsecnt(h); - HRLOCK_UNLOCK(hb); - res.data = h; - res.is_new = false; - /* coverity[missing_unlock : FALSE] */ - return res; -} - -/** \brief look up data in the hash - * - * \param data data to look up - * - * \retval h *LOCKED* data or NULL - */ -THashData *THashLookupFromHash (THashTableContext *ctx, void *data) -{ - THashData *h = NULL; - - /* get the key to our bucket */ - uint32_t key = THashGetKey(&ctx->config, data); - /* get our hash bucket and lock it */ - THashHashRow *hb = &ctx->array[key]; - HRLOCK_LOCK(hb); - - if (hb->head == NULL) { - HRLOCK_UNLOCK(hb); - return h; - } - - /* ok, we have data in the bucket. Let's find out if it is our data */ - h = hb->head; - - /* see if this is the data we are looking for */ - if (THashCompare(&ctx->config, h->data, data) == 0) { - while (h) { - h = h->next; - if (h == NULL) { - HRLOCK_UNLOCK(hb); - return h; - } - - if (THashCompare(&ctx->config, h->data, data) != 0) { - /* we found our data, lets put it on top of the - * hash list -- this rewards active data */ - if (h->next) { - h->next->prev = h->prev; - } - if (h->prev) { - h->prev->next = h->next; - } - if (h == hb->tail) { - hb->tail = h->prev; - } - - h->next = hb->head; - h->prev = NULL; - hb->head->prev = h; - hb->head = h; - - /* found our data, lock & return */ - SCMutexLock(&h->m); - (void) THashIncrUsecnt(h); - HRLOCK_UNLOCK(hb); - return h; - } - } - } - - /* lock & return */ - SCMutexLock(&h->m); - (void) THashIncrUsecnt(h); - HRLOCK_UNLOCK(hb); - return h; -} - -/** \internal - * \brief Get data from the hash directly. - * - * Called in conditions where the spare queue is empty and memcap is - * reached. - * - * Walks the hash until data can be freed. "prune_idx" atomic int makes - * sure we don't start at the top each time since that would clear the top - * of the hash leading to longer and longer search times under high - * pressure (observed). - * - * \retval h data or NULL - */ -static THashData *THashGetUsed(THashTableContext *ctx) -{ - uint32_t idx = SC_ATOMIC_GET(ctx->prune_idx) % ctx->config.hash_size; - uint32_t cnt = ctx->config.hash_size; - - while (cnt--) { - if (++idx >= ctx->config.hash_size) - idx = 0; - - THashHashRow *hb = &ctx->array[idx]; - - if (HRLOCK_TRYLOCK(hb) != 0) - continue; - - THashData *h = hb->tail; - if (h == NULL) { - HRLOCK_UNLOCK(hb); - continue; - } - - if (SCMutexTrylock(&h->m) != 0) { - HRLOCK_UNLOCK(hb); - continue; - } - - if (SC_ATOMIC_GET(h->use_cnt) > 0) { - HRLOCK_UNLOCK(hb); - SCMutexUnlock(&h->m); - continue; - } - - /* remove from the hash */ - if (h->prev != NULL) - h->prev->next = h->next; - if (h->next != NULL) - h->next->prev = h->prev; - if (hb->head == h) - hb->head = h->next; - if (hb->tail == h) - hb->tail = h->prev; - - h->next = NULL; - h->prev = NULL; - HRLOCK_UNLOCK(hb); - - if (h->data != NULL) { - ctx->config.DataFree(h->data); - } - SCMutexUnlock(&h->m); - - (void) SC_ATOMIC_ADD(ctx->prune_idx, (ctx->config.hash_size - cnt)); - return h; - } - - return NULL; -} - -/** - * \retval int -1 not found - * \retval int 0 found, but it was busy (ref cnt) - * \retval int 1 found and removed */ -int THashRemoveFromHash (THashTableContext *ctx, void *data) -{ - /* get the key to our bucket */ - uint32_t key = THashGetKey(&ctx->config, data); - /* get our hash bucket and lock it */ - THashHashRow *hb = &ctx->array[key]; - - HRLOCK_LOCK(hb); - THashData *h = hb->head; - while (h != NULL) { - /* see if this is the data we are looking for */ - if (THashCompare(&ctx->config, h->data, data) == 0) { - h = h->next; - continue; - } - - SCMutexLock(&h->m); - if (SC_ATOMIC_GET(h->use_cnt) > 0) { - SCMutexUnlock(&h->m); - HRLOCK_UNLOCK(hb); - return 0; - } - - /* remove from the hash */ - if (h->prev != NULL) - h->prev->next = h->next; - if (h->next != NULL) - h->next->prev = h->prev; - if (hb->head == h) - hb->head = h->next; - if (hb->tail == h) - hb->tail = h->prev; - - h->next = NULL; - h->prev = NULL; - SCMutexUnlock(&h->m); - HRLOCK_UNLOCK(hb); - THashDataFree(ctx, h); - SCLogDebug("found and removed"); - return 1; - } - - HRLOCK_UNLOCK(hb); - SCLogDebug("data not found"); - return -1; -} diff --git a/src/util-thash.h b/src/util-thash.h deleted file mode 100644 index 9618d5c06442..000000000000 --- a/src/util-thash.h +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * thash -> thread hash. Hash table with locking handling. - */ - -#ifndef __THASH_H__ -#define __THASH_H__ - -#include "threads.h" - -/** Spinlocks or Mutex for the buckets. */ -//#define HRLOCK_SPIN -#define HRLOCK_MUTEX - -#ifdef HRLOCK_SPIN - #ifdef HRLOCK_MUTEX - #error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX - #endif -#endif - -#ifdef HRLOCK_SPIN - #define HRLOCK_TYPE SCSpinlock - #define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) - #define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) - #define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) - #define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) - #define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) -#elif defined HRLOCK_MUTEX - #define HRLOCK_TYPE SCMutex - #define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) - #define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) - #define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) - #define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) - #define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) -#else - #error Enable HRLOCK_SPIN or HRLOCK_MUTEX -#endif - -/** Spinlocks or Mutex for the queues. */ -//#define HQLOCK_SPIN -#define HQLOCK_MUTEX - -#ifdef HQLOCK_SPIN - #ifdef HQLOCK_MUTEX - #error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX - #endif -#endif - -#ifdef HQLOCK_SPIN - #define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) - #define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) - #define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) - #define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) - #define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) -#elif defined HQLOCK_MUTEX - #define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) - #define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) - #define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) - #define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) - #define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) -#else - #error Enable HQLOCK_SPIN or HQLOCK_MUTEX -#endif - -typedef struct THashData_ { - /** ippair mutex */ - SCMutex m; - - /** use cnt, reference counter */ - SC_ATOMIC_DECLARE(unsigned int, use_cnt); - - void *data; - - struct THashData_ *next; - struct THashData_ *prev; -} THashData; - -typedef struct THashHashRow_ { - HRLOCK_TYPE lock; - THashData *head; - THashData *tail; -} __attribute__((aligned(CLS))) THashHashRow; - -typedef struct THashDataQueue_ -{ - THashData *top; - THashData *bot; - uint32_t len; -#ifdef DBG_PERF - uint32_t dbg_maxlen; -#endif /* DBG_PERF */ -#ifdef HQLOCK_MUTEX - SCMutex m; -#elif defined HQLOCK_SPIN - SCSpinlock s; -#else - #error Enable HQLOCK_SPIN or HQLOCK_MUTEX -#endif -} THashDataQueue; - -typedef int (*THashOutputFunc)(void *output_ctx, const uint8_t *data, const uint32_t data_len); -typedef int (*THashFormatFunc)(const void *in_data, char *output, size_t output_size); - -typedef struct THashDataConfig_ { - uint64_t memcap; - uint32_t hash_rand; - uint32_t hash_size; - uint32_t prealloc; - - uint32_t data_size; - int (*DataSet)(void *dst, void *src); - void (*DataFree)(void *); - uint32_t (*DataHash)(void *); - bool (*DataCompare)(void *, void *); -} THashConfig; - -#define THASH_DATA_SIZE(ctx) (sizeof(THashData) + (ctx)->config.data_size) - -typedef struct THashTableContext_ { - /* array of rows indexed by the hash value % hash size */ - THashHashRow *array; - - SC_ATOMIC_DECLARE(uint64_t, memuse); - SC_ATOMIC_DECLARE(uint32_t, counter); - SC_ATOMIC_DECLARE(uint32_t, prune_idx); - - THashDataQueue spare_q; - - THashConfig config; - - /* flag set if memcap was reached at least once. */ - SC_ATOMIC_DECLARE(bool, memcap_reached); -} THashTableContext; - -/** \brief check if a memory alloc would fit in the memcap - * - * \param size memory allocation size to check - * - * \retval 1 it fits - * \retval 0 no fit - */ -#define THASH_CHECK_MEMCAP(ctx, size) \ - ((((uint64_t)SC_ATOMIC_GET((ctx)->memuse) + (uint64_t)(size)) <= (ctx)->config.memcap)) - -#define THashIncrUsecnt(h) \ - (void)SC_ATOMIC_ADD((h)->use_cnt, 1) -#define THashDecrUsecnt(h) \ - (void)SC_ATOMIC_SUB((h)->use_cnt, 1) - -THashTableContext *THashInit(const char *cnf_prefix, size_t data_size, - int (*DataSet)(void *dst, void *src), void (*DataFree)(void *), - uint32_t (*DataHash)(void *), bool (*DataCompare)(void *, void *), bool reset_memcap, - uint64_t memcap, uint32_t hashsize); - -void THashShutdown(THashTableContext *ctx); - -static inline void THashDataLock(THashData *d) -{ - SCMutexLock(&d->m); -} - -static inline void THashDataUnlock(THashData *d) -{ - SCMutexUnlock(&d->m); -} - -struct THashDataGetResult { - THashData *data; - bool is_new; -}; - -struct THashDataGetResult THashGetFromHash (THashTableContext *ctx, void *data); -THashData *THashLookupFromHash (THashTableContext *ctx, void *data); -THashDataQueue *THashDataQueueNew(void); -void THashCleanup(THashTableContext *ctx); -int THashWalk(THashTableContext *, THashFormatFunc, THashOutputFunc, void *); -int THashRemoveFromHash (THashTableContext *ctx, void *data); -void THashConsolidateMemcap(THashTableContext *ctx); -void THashDataMoveToSpare(THashTableContext *ctx, THashData *h); - -#endif /* __THASH_H__ */ diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c deleted file mode 100644 index 70cc41a73e91..000000000000 --- a/src/util-threshold-config.c +++ /dev/null @@ -1,2623 +0,0 @@ -/* Copyright (C) 2007-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup threshold - * @{ - */ - -/** - * \file - * - * \author Breno Silva Pinto - * - * Implements Threshold support - */ - -#include "suricata-common.h" - -#include "host.h" -#include "ippair.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-address.h" -#include "detect-engine-threshold.h" -#include "detect-threshold.h" -#include "detect-parse.h" -#include "detect-engine-build.h" - -#include "conf.h" -#include "util-threshold-config.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-byte.h" -#include "util-time.h" -#include "util-error.h" -#include "util-debug.h" -#include "util-fmemopen.h" - -typedef enum ThresholdRuleType { - THRESHOLD_TYPE_EVENT_FILTER, - THRESHOLD_TYPE_THRESHOLD, - THRESHOLD_TYPE_RATE, - THRESHOLD_TYPE_SUPPRESS, -} ThresholdRuleType; - -#ifdef UNITTESTS -/* File descriptor for unittests */ -static FILE *g_ut_threshold_fp = NULL; -#endif - -/* common base for all options */ -#define DETECT_BASE_REGEX "^\\s*(event_filter|threshold|rate_filter|suppress)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*(.*)\\s*$" - -#define DETECT_THRESHOLD_REGEX \ - "^,\\s*type\\s*(limit|both|threshold)\\s*,\\s*track\\s*(by_dst|by_src|by_both|by_rule)\\s*," \ - "\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*$" - -/* TODO: "apply_to" */ -#define DETECT_RATE_REGEX "^,\\s*track\\s*(by_dst|by_src|by_both|by_rule)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*,\\s*new_action\\s*(alert|drop|pass|log|sdrop|reject)\\s*,\\s*timeout\\s*(\\d+)\\s*$" - -/* - * suppress has two form: - * suppress gen_id 0, sig_id 0, track by_dst, ip 10.88.0.14 - * suppress gen_id 1, sig_id 2000328 - * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10 -*/ -#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\s\\da-zA-Z.:/_]+)*\\s*$" - -/* Default path for the threshold.config file */ -#if defined OS_WIN32 || defined __CYGWIN__ -#define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\threshold.config" -#else -#define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/threshold.config" -#endif - -static DetectParseRegex *regex_base = NULL; -static DetectParseRegex *regex_threshold = NULL; -static DetectParseRegex *regex_rate = NULL; -static DetectParseRegex *regex_suppress = NULL; - -static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd); - -void SCThresholdConfGlobalInit(void) -{ - regex_base = DetectSetupPCRE2(DETECT_BASE_REGEX, 0); - if (regex_base == NULL) { - FatalError("classification base regex setup failed"); - } - regex_threshold = DetectSetupPCRE2(DETECT_THRESHOLD_REGEX, 0); - if (regex_threshold == NULL) { - FatalError("classification threshold regex setup failed"); - } - regex_rate = DetectSetupPCRE2(DETECT_RATE_REGEX, 0); - if (regex_rate == NULL) { - FatalError("classification rate_filter regex setup failed"); - } - regex_suppress = DetectSetupPCRE2(DETECT_SUPPRESS_REGEX, 0); - if (regex_suppress == NULL) { - FatalError("classification suppress regex setup failed"); - } -} - -/** - * \brief Returns the path for the Threshold Config file. We check if we - * can retrieve the path from the yaml conf file. If it is not present, - * return the default path for the threshold file which is - * "./threshold.config". - * - * \retval log_filename Pointer to a string containing the path for the - * Threshold Config file. - */ -static const char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx) -{ - const char *log_filename = NULL; - - if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { - char config_value[256]; - snprintf(config_value, sizeof(config_value), - "%s.threshold-file", de_ctx->config_prefix); - - /* try loading prefix setting, fall back to global if that - * fails. */ - if (ConfGet(config_value, &log_filename) != 1) { - if (ConfGet("threshold-file", &log_filename) != 1) { - log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; - } - } - } else { - if (ConfGet("threshold-file", &log_filename) != 1) { - log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; - } - } - return log_filename; -} - -/** - * \brief Inits the context to be used by the Threshold Config parsing API. - * - * This function initializes the hash table to be used by the Detection - * Engine Context to hold the data from the threshold.config file, - * obtains the file desc to parse the threshold.config file, and - * inits the regex used to parse the lines from threshold.config - * file. - * - * \param de_ctx Pointer to the Detection Engine Context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCThresholdConfInitContext(DetectEngineCtx *de_ctx) -{ - const char *filename = NULL; - int ret = 0; -#ifndef UNITTESTS - FILE *fd = NULL; -#else - FILE *fd = g_ut_threshold_fp; - if (fd == NULL) { -#endif - filename = SCThresholdConfGetConfFilename(de_ctx); - if ( (fd = fopen(filename, "r")) == NULL) { - SCLogWarning("Error opening file: \"%s\": %s", filename, strerror(errno)); - SCThresholdConfDeInitContext(de_ctx, fd); - return 0; - } -#ifdef UNITTESTS - } -#endif - - if (SCThresholdConfParseFile(de_ctx, fd) < 0) { - SCLogWarning("Error loading threshold configuration from %s", filename); - SCThresholdConfDeInitContext(de_ctx, fd); - /* maintain legacy behavior so no errors unless config testing */ - if (RunmodeGetCurrent() == RUNMODE_CONF_TEST) { - ret = -1; - } - return ret; - } - SCThresholdConfDeInitContext(de_ctx, fd); - -#ifdef UNITTESTS - g_ut_threshold_fp = NULL; -#endif - SCLogDebug("Global thresholding options defined"); - return 0; -} - -/** - * \brief Releases resources used by the Threshold Config API. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param fd Pointer to file descriptor. - */ -static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) -{ - if (fd != NULL) - fclose(fd); - return; -} - -/** \internal - * \brief setup suppress rules - * \retval 0 ok - * \retval -1 error - */ -static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, - uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, - uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action, - const char *th_ip) -{ - Signature *s = NULL; - DetectThresholdData *de = NULL; - - BUG_ON(parsed_type != TYPE_SUPPRESS); - - DetectThresholdData *orig_de = NULL; - if (parsed_track != TRACK_RULE) { - orig_de = SCCalloc(1, sizeof(DetectThresholdData)); - if (unlikely(orig_de == NULL)) - goto error; - - orig_de->type = TYPE_SUPPRESS; - orig_de->track = parsed_track; - orig_de->count = parsed_count; - orig_de->seconds = parsed_seconds; - orig_de->new_action = parsed_new_action; - orig_de->timeout = parsed_timeout; - if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &orig_de->addrs, (char *)th_ip) < - 0) { - SCLogError("failed to parse %s", th_ip); - goto error; - } - } - - /* Install it */ - if (id == 0 && gid == 0) { - if (parsed_track == TRACK_RULE) { - SCLogWarning("suppressing all rules"); - } - - /* update each sig with our suppress info */ - for (s = de_ctx->sig_list; s != NULL; s = s->next) { - /* tag the rule as noalert */ - if (parsed_track == TRACK_RULE) { - s->flags |= SIG_FLAG_NOALERT; - continue; - } - - de = DetectThresholdDataCopy(orig_de); - if (unlikely(de == NULL)) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_THRESHOLD, (SigMatchCtx *)de, - DETECT_SM_LIST_SUPPRESS) == NULL) { - goto error; - } - } - } else if (id == 0 && gid > 0) { - if (parsed_track == TRACK_RULE) { - SCLogWarning("suppressing all rules with gid %" PRIu32, gid); - } - /* set up suppression for each signature with a matching gid */ - for (s = de_ctx->sig_list; s != NULL; s = s->next) { - if (s->gid != gid) - continue; - - /* tag the rule as noalert */ - if (parsed_track == TRACK_RULE) { - s->flags |= SIG_FLAG_NOALERT; - continue; - } - - de = DetectThresholdDataCopy(orig_de); - if (unlikely(de == NULL)) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_THRESHOLD, (SigMatchCtx *)de, - DETECT_SM_LIST_SUPPRESS) == NULL) { - goto error; - } - } - } else if (id > 0 && gid == 0) { - SCLogError("Can't use a event config that has " - "sid > 0 and gid == 0. Please fix this " - "in your threshold.config file"); - goto error; - } else { - s = SigFindSignatureBySidGid(de_ctx, id, gid); - if (s == NULL) { - SCLogWarning("can't suppress sid " - "%" PRIu32 ", gid %" PRIu32 ": unknown rule", - id, gid); - } else { - if (parsed_track == TRACK_RULE) { - s->flags |= SIG_FLAG_NOALERT; - goto end; - } - - de = DetectThresholdDataCopy(orig_de); - if (unlikely(de == NULL)) - goto error; - - if (SigMatchAppendSMToList(de_ctx, s, DETECT_THRESHOLD, (SigMatchCtx *)de, - DETECT_SM_LIST_SUPPRESS) == NULL) { - goto error; - } - } - } - -end: - if (orig_de != NULL) { - DetectAddressHeadCleanup(&orig_de->addrs); - SCFree(orig_de); - } - return 0; -error: - if (orig_de != NULL) { - DetectAddressHeadCleanup(&orig_de->addrs); - SCFree(orig_de); - } - if (de != NULL) { - DetectAddressHeadCleanup(&de->addrs); - SCFree(de); - } - return -1; -} - -/** \internal - * \brief setup suppress rules - * \retval 0 ok - * \retval -1 error - */ -static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, - uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, - uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action, - const char *th_ip) -{ - Signature *s = NULL; - SigMatch *sm = NULL; - DetectThresholdData *de = NULL; - - BUG_ON(parsed_type == TYPE_SUPPRESS); - - /* Install it */ - if (id == 0 && gid == 0) { - for (s = de_ctx->sig_list; s != NULL; s = s->next) { - sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); - if (sm != NULL) { - SCLogWarning("signature sid:%" PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", - s->id); - continue; - } - - sm = DetectGetLastSMByListId(s, - DETECT_SM_LIST_THRESHOLD, DETECT_DETECTION_FILTER, -1); - if (sm != NULL) { - SCLogWarning("signature sid:%" PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", - s->id); - continue; - } - - de = SCCalloc(1, sizeof(DetectThresholdData)); - if (unlikely(de == NULL)) - goto error; - - de->type = parsed_type; - de->track = parsed_track; - de->count = parsed_count; - de->seconds = parsed_seconds; - de->new_action = parsed_new_action; - de->timeout = parsed_timeout; - - uint16_t smtype = DETECT_THRESHOLD; - if (parsed_type == TYPE_RATE) - smtype = DETECT_DETECTION_FILTER; - - if (SigMatchAppendSMToList( - de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) { - goto error; - } - } - - } else if (id == 0 && gid > 0) { - for (s = de_ctx->sig_list; s != NULL; s = s->next) { - if (s->gid == gid) { - sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); - if (sm != NULL) { - SCLogWarning("signature sid:%" PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", - id); - continue; - } - - de = SCCalloc(1, sizeof(DetectThresholdData)); - if (unlikely(de == NULL)) - goto error; - - de->type = parsed_type; - de->track = parsed_track; - de->count = parsed_count; - de->seconds = parsed_seconds; - de->new_action = parsed_new_action; - de->timeout = parsed_timeout; - - uint16_t smtype = DETECT_THRESHOLD; - if (parsed_type == TYPE_RATE) - smtype = DETECT_DETECTION_FILTER; - - if (SigMatchAppendSMToList(de_ctx, s, smtype, (SigMatchCtx *)de, - DETECT_SM_LIST_THRESHOLD) == NULL) { - goto error; - } - } - } - } else if (id > 0 && gid == 0) { - SCLogError("Can't use a event config that has " - "sid > 0 and gid == 0. Please fix this " - "in your threshold.conf file"); - } else { - s = SigFindSignatureBySidGid(de_ctx, id, gid); - if (s == NULL) { - SCLogWarning("can't suppress sid " - "%" PRIu32 ", gid %" PRIu32 ": unknown rule", - id, gid); - } else { - if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD && - parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) - { - sm = DetectGetLastSMByListId(s, - DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); - if (sm != NULL) { - SCLogWarning("signature sid:%" PRIu32 " has " - "a threshold set. The signature event var is " - "given precedence over the threshold.conf one. " - "Bug #425.", - s->id); - goto end; - } - - sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, - DETECT_DETECTION_FILTER, -1); - if (sm != NULL) { - SCLogWarning("signature sid:%" PRIu32 " has " - "a detection_filter set. The signature event var is " - "given precedence over the threshold.conf one. " - "Bug #425.", - s->id); - goto end; - } - - /* replace threshold on sig if we have a global override for it */ - } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) { - sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); - if (sm != NULL) { - SigMatchRemoveSMFromList(s, sm, DETECT_SM_LIST_THRESHOLD); - SigMatchFree(de_ctx, sm); - } - } - - de = SCCalloc(1, sizeof(DetectThresholdData)); - if (unlikely(de == NULL)) - goto error; - - de->type = parsed_type; - de->track = parsed_track; - de->count = parsed_count; - de->seconds = parsed_seconds; - de->new_action = parsed_new_action; - de->timeout = parsed_timeout; - - uint16_t smtype = DETECT_THRESHOLD; - if (parsed_type == TYPE_RATE) - smtype = DETECT_DETECTION_FILTER; - - if (SigMatchAppendSMToList( - de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) { - goto error; - } - } - } -end: - return 0; -error: - if (de != NULL) { - DetectAddressHeadCleanup(&de->addrs); - SCFree(de); - } - return -1; -} - -static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint32_t *ret_id, - uint32_t *ret_gid, uint8_t *ret_parsed_type, uint8_t *ret_parsed_track, - uint32_t *ret_parsed_count, uint32_t *ret_parsed_seconds, uint32_t *ret_parsed_timeout, - uint8_t *ret_parsed_new_action, char **ret_th_ip) -{ - char th_rule_type[32]; - char th_gid[16]; - char th_sid[16]; - const char *rule_extend = NULL; - char th_type[16] = ""; - char th_track[16] = ""; - char th_count[16] = ""; - char th_seconds[16] = ""; - char th_new_action[16] = ""; - char th_timeout[16] = ""; - const char *th_ip = NULL; - - uint8_t parsed_type = 0; - uint8_t parsed_track = 0; - uint8_t parsed_new_action = 0; - uint32_t parsed_count = 0; - uint32_t parsed_seconds = 0; - uint32_t parsed_timeout = 0; - - int ret = 0; - uint32_t id = 0, gid = 0; - ThresholdRuleType rule_type; - - if (de_ctx == NULL) - return -1; - - pcre2_match_data *regex_base_match = NULL; - ret = DetectParsePcreExec(regex_base, ®ex_base_match, rawstr, 0, 0); - if (ret < 4) { - SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rawstr); - pcre2_match_data_free(regex_base_match); - goto error; - } - - /* retrieve the classtype name */ - size_t copylen = sizeof(th_rule_type); - ret = pcre2_substring_copy_bynumber( - regex_base_match, 1, (PCRE2_UCHAR8 *)th_rule_type, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(regex_base_match); - goto error; - } - - /* retrieve the classtype name */ - copylen = sizeof(th_gid); - ret = pcre2_substring_copy_bynumber(regex_base_match, 2, (PCRE2_UCHAR8 *)th_gid, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(regex_base_match); - goto error; - } - - copylen = sizeof(th_sid); - ret = pcre2_substring_copy_bynumber(regex_base_match, 3, (PCRE2_UCHAR8 *)th_sid, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(regex_base_match); - goto error; - } - - /* Use "get" for heap allocation */ - ret = pcre2_substring_get_bynumber( - regex_base_match, 4, (PCRE2_UCHAR8 **)&rule_extend, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_get_bynumber failed"); - pcre2_match_data_free(regex_base_match); - goto error; - } - pcre2_match_data_free(regex_base_match); - regex_base_match = NULL; - - /* get type of rule */ - if (strcasecmp(th_rule_type,"event_filter") == 0) { - rule_type = THRESHOLD_TYPE_EVENT_FILTER; - } else if (strcasecmp(th_rule_type,"threshold") == 0) { - rule_type = THRESHOLD_TYPE_THRESHOLD; - } else if (strcasecmp(th_rule_type,"rate_filter") == 0) { - rule_type = THRESHOLD_TYPE_RATE; - } else if (strcasecmp(th_rule_type,"suppress") == 0) { - rule_type = THRESHOLD_TYPE_SUPPRESS; - } else { - SCLogError("rule type %s is unknown", th_rule_type); - goto error; - } - - /* get end of rule */ - switch(rule_type) { - case THRESHOLD_TYPE_EVENT_FILTER: - case THRESHOLD_TYPE_THRESHOLD: - if (strlen(rule_extend) > 0) { - pcre2_match_data *match = NULL; - - ret = DetectParsePcreExec(regex_threshold, &match, rule_extend, 0, 0); - if (ret < 4) { - SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, - rule_extend); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_type); - ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_type, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_track); - ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_track, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_count); - ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_count, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_seconds); - ret = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)th_seconds, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - pcre2_match_data_free(match); - - if (strcasecmp(th_type,"limit") == 0) - parsed_type = TYPE_LIMIT; - else if (strcasecmp(th_type,"both") == 0) - parsed_type = TYPE_BOTH; - else if (strcasecmp(th_type,"threshold") == 0) - parsed_type = TYPE_THRESHOLD; - else { - SCLogError("limit type not supported: %s", th_type); - goto error; - } - } else { - SCLogError("rule invalid: %s", rawstr); - goto error; - } - break; - case THRESHOLD_TYPE_SUPPRESS: - if (strlen(rule_extend) > 0) { - pcre2_match_data *match = NULL; - ret = DetectParsePcreExec(regex_suppress, &match, rule_extend, 0, 0); - if (ret < 2) { - SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, - rule_extend); - pcre2_match_data_free(match); - goto error; - } - /* retrieve the track mode */ - copylen = sizeof(th_seconds); - ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - /* retrieve the IP; use "get" for heap allocation */ - ret = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&th_ip, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_get_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - pcre2_match_data_free(match); - } else { - parsed_track = TRACK_RULE; - } - parsed_type = TYPE_SUPPRESS; - break; - case THRESHOLD_TYPE_RATE: - if (strlen(rule_extend) > 0) { - pcre2_match_data *match = NULL; - ret = DetectParsePcreExec(regex_rate, &match, rule_extend, 0, 0); - if (ret < 5) { - SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, - rule_extend); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_track); - ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_count); - ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_count, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_seconds); - ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_seconds, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_new_action); - ret = pcre2_substring_copy_bynumber( - match, 4, (PCRE2_UCHAR8 *)th_new_action, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - - copylen = sizeof(th_timeout); - ret = pcre2_substring_copy_bynumber(match, 5, (PCRE2_UCHAR8 *)th_timeout, ©len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - pcre2_match_data_free(match); - goto error; - } - pcre2_match_data_free(match); - - /* TODO: implement option "apply_to" */ - - if (StringParseUint32(&parsed_timeout, 10, sizeof(th_timeout), th_timeout) <= 0) { - goto error; - } - - /* Get the new action to take */ - if (strcasecmp(th_new_action, "alert") == 0) - parsed_new_action = TH_ACTION_ALERT; - if (strcasecmp(th_new_action, "drop") == 0) - parsed_new_action = TH_ACTION_DROP; - if (strcasecmp(th_new_action, "pass") == 0) - parsed_new_action = TH_ACTION_PASS; - if (strcasecmp(th_new_action, "reject") == 0) - parsed_new_action = TH_ACTION_REJECT; - if (strcasecmp(th_new_action, "log") == 0) { - SCLogInfo("log action for rate_filter not supported yet"); - parsed_new_action = TH_ACTION_LOG; - } - if (strcasecmp(th_new_action, "sdrop") == 0) { - SCLogInfo("sdrop action for rate_filter not supported yet"); - parsed_new_action = TH_ACTION_SDROP; - } - parsed_type = TYPE_RATE; - } else { - SCLogError("rule invalid: %s", rawstr); - goto error; - } - break; - } - - switch (rule_type) { - /* This part is common to threshold/event_filter/rate_filter */ - case THRESHOLD_TYPE_EVENT_FILTER: - case THRESHOLD_TYPE_THRESHOLD: - case THRESHOLD_TYPE_RATE: - if (strcasecmp(th_track,"by_dst") == 0) - parsed_track = TRACK_DST; - else if (strcasecmp(th_track,"by_src") == 0) - parsed_track = TRACK_SRC; - else if (strcasecmp(th_track, "by_both") == 0) { - parsed_track = TRACK_BOTH; - } - else if (strcasecmp(th_track,"by_rule") == 0) - parsed_track = TRACK_RULE; - else { - SCLogError("Invalid track parameter %s in %s", th_track, rawstr); - goto error; - } - - if (StringParseUint32(&parsed_count, 10, sizeof(th_count), th_count) <= 0) { - goto error; - } - if (parsed_count == 0) { - SCLogError("rate filter count should be > 0"); - goto error; - } - - if (StringParseUint32(&parsed_seconds, 10, sizeof(th_seconds), th_seconds) <= 0) { - goto error; - } - - break; - case THRESHOLD_TYPE_SUPPRESS: - /* need to get IP if extension is provided */ - if (strcmp("", th_track) != 0) { - if (strcasecmp(th_track,"by_dst") == 0) - parsed_track = TRACK_DST; - else if (strcasecmp(th_track,"by_src") == 0) - parsed_track = TRACK_SRC; - else if (strcasecmp(th_track,"by_either") == 0) { - parsed_track = TRACK_EITHER; - } - else { - SCLogError("Invalid track parameter %s in %s", th_track, rule_extend); - goto error; - } - } - break; - } - - if (StringParseUint32(&id, 10, sizeof(th_sid), th_sid) <= 0) { - goto error; - } - - if (StringParseUint32(&gid, 10, sizeof(th_gid), th_gid) <= 0) { - goto error; - } - - *ret_id = id; - *ret_gid = gid; - *ret_parsed_type = parsed_type; - *ret_parsed_track = parsed_track; - *ret_parsed_new_action = parsed_new_action; - *ret_parsed_count = parsed_count; - *ret_parsed_seconds = parsed_seconds; - *ret_parsed_timeout = parsed_timeout; - *ret_th_ip = NULL; - if (th_ip != NULL) { - *ret_th_ip = (char *)th_ip; - } - pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend); - return 0; - -error: - if (rule_extend != NULL) { - pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend); - } - if (th_ip != NULL) { - pcre2_substring_free((PCRE2_UCHAR8 *)th_ip); - } - return -1; -} - -/** - * \brief Parses a line from the threshold file and applies it to the - * detection engine - * - * \param rawstr Pointer to the string to be parsed. - * \param de_ctx Pointer to the Detection Engine Context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) -{ - uint8_t parsed_type = 0; - uint8_t parsed_track = 0; - uint8_t parsed_new_action = 0; - uint32_t parsed_count = 0; - uint32_t parsed_seconds = 0; - uint32_t parsed_timeout = 0; - char *th_ip = NULL; - uint32_t id = 0, gid = 0; - - int r = ParseThresholdRule(de_ctx, rawstr, &id, &gid, &parsed_type, &parsed_track, - &parsed_count, &parsed_seconds, &parsed_timeout, &parsed_new_action, &th_ip); - if (r < 0) - goto error; - - if (parsed_type == TYPE_SUPPRESS) { - r = SetupSuppressRule(de_ctx, id, gid, parsed_type, parsed_track, - parsed_count, parsed_seconds, parsed_timeout, parsed_new_action, - th_ip); - } else { - r = SetupThresholdRule(de_ctx, id, gid, parsed_type, parsed_track, - parsed_count, parsed_seconds, parsed_timeout, parsed_new_action, - th_ip); - } - if (r < 0) { - goto error; - } - - pcre2_substring_free((PCRE2_UCHAR8 *)th_ip); - return 0; -error: - if (th_ip != NULL) - pcre2_substring_free((PCRE2_UCHAR8 *)th_ip); - return -1; -} - -/** - * \brief Checks if a string is a comment or a blank line. - * - * Comments lines are lines of the following format - - * "# This is a comment string" or - * " # This is a comment string". - * - * \param line String that has to be checked - * - * \retval 1 On the argument string being a comment or blank line - * \retval 0 Otherwise - */ -static int SCThresholdConfIsLineBlankOrComment(char *line) -{ - while (*line != '\0') { - /* we have a comment */ - if (*line == '#') - return 1; - - /* this line is neither a comment line, nor a blank line */ - if (!isspace((unsigned char)*line)) - return 0; - - line++; - } - - /* we have a blank line */ - return 1; -} - -/** - * \brief Checks if the rule is multiline, by searching an ending slash - * - * \param line String that has to be checked - * - * \retval the position of the slash making it multiline - * \retval 0 Otherwise - */ -static int SCThresholdConfLineIsMultiline(char *line) -{ - int flag = 0; - char *rline = line; - int len = strlen(line); - - while (line < rline + len && *line != '\n') { - /* we have a comment */ - if (*line == '\\') - flag = line - rline; - else - if (!isspace((unsigned char)*line)) - flag = 0; - - line++; - } - - /* we have a blank line */ - return flag; -} - -/** - * \brief Parses the Threshold Config file - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param fd Pointer to file descriptor. - */ -int SCThresholdConfParseFile(DetectEngineCtx *de_ctx, FILE *fp) -{ - char line[8192] = ""; - int rule_num = 0; - - /* position of "\", on multiline rules */ - int esc_pos = 0; - - if (fp == NULL) - return -1; - - while (fgets(line + esc_pos, (int)sizeof(line) - esc_pos, fp) != NULL) { - if (SCThresholdConfIsLineBlankOrComment(line)) { - continue; - } - - esc_pos = SCThresholdConfLineIsMultiline(line); - if (esc_pos == 0) { - if (SCThresholdConfAddThresholdtype(line, de_ctx) < 0) { - if (RunmodeGetCurrent() == RUNMODE_CONF_TEST) - return -1; - } else { - SCLogDebug("Adding threshold.config rule num %" PRIu32 "( %s )", rule_num, line); - rule_num++; - } - } - } - - if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) - SCLogInfo("tenant id %d: Threshold config parsed: %d rule(s) found", de_ctx->tenant_id, - rule_num); - else - SCLogInfo("Threshold config parsed: %d rule(s) found", rule_num); - return 0; -} - -#ifdef UNITTESTS -#include "detect-engine-alert.h" -#include "packet.h" -#include "action-globals.h" - -/** - * \brief Creates a dummy threshold file, with all valid options, for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD01(void) -{ - FILE *fd = NULL; - const char *buffer = - "event_filter gen_id 1, sig_id 10, type limit, track by_src, count 1, seconds 60\n" - "threshold gen_id 1, sig_id 100, type both, track by_dst, count 10, seconds 60\n" - "event_filter gen_id 1, sig_id 1000, type threshold, track by_src, count 100, seconds 60\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with some valid options and a couple of invalid options. - * For testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateInvalidDummyFD02(void) -{ - FILE *fd; - const char *buffer = - "event_filter gen_id 1, sig_id 1000, type invalid, track by_src, count 100, seconds 60\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD03(void) -{ - FILE *fd; - const char *buffer = - "event_filter gen_id 0, sig_id 0, type threshold, track by_src, count 100, seconds 60\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, but - * with split rules (multiline), for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD04(void) -{ - FILE *fd = NULL; - const char *buffer = - "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 1, seconds 60\n" - "threshold gen_id 1, \\\nsig_id 100, type both\\\n, track by_dst, count 10, \\\n seconds 60\n" - "event_filter gen_id 1, sig_id 1000, \\\ntype threshold, track \\\nby_src, count 100, seconds 60\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD05(void) -{ - FILE *fd = NULL; - const char *buffer = - "rate_filter gen_id 1, sig_id 10, track by_src, count 1, seconds 60, new_action drop, timeout 10\n" - "rate_filter gen_id 1, sig_id 100, track by_dst, count 10, seconds 60, new_action pass, timeout 5\n" - "rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, new_action alert, timeout 30\n" - "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, seconds 60, new_action reject, timeout 21\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, but - * with split rules (multiline), for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD06(void) -{ - FILE *fd = NULL; - const char *buffer = - "rate_filter \\\ngen_id 1, sig_id 10, track by_src, count 1, seconds 60\\\n, new_action drop, timeout 10\n" - "rate_filter gen_id 1, \\\nsig_id 100, track by_dst, \\\ncount 10, seconds 60, new_action pass, timeout 5\n" - "rate_filter gen_id 1, sig_id 1000, \\\ntrack by_rule, count 100, seconds 60, new_action alert, timeout 30\n" - "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, \\\nseconds 60, new_action reject, timeout 21\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, but - * with split rules (multiline), for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD07(void) -{ - FILE *fd = NULL; - const char *buffer = - "rate_filter gen_id 1, sig_id 10, track by_src, count 3, seconds 3, new_action drop, timeout 10\n" - "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, for testing rate_filter, track by_rule - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD08(void) -{ - FILE *fd = NULL; - const char *buffer = - "rate_filter gen_id 1, sig_id 10, track by_rule, count 3, seconds 3, new_action drop, timeout 10\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, but - * with split rules (multiline), for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD09(void) -{ - FILE *fd = NULL; - const char *buffer = - "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 2, seconds 60\n" - "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 3, \\\n seconds 60\n" - "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 2, seconds 60\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, but - * with split rules (multiline), for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD10(void) -{ - FILE *fd = NULL; - const char *buffer = - "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 5, seconds 2\n" - "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 5, \\\n seconds 2\n" - "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 5, seconds 2\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD11(void) -{ - FILE *fd = NULL; - const char *buffer = - "suppress gen_id 1, sig_id 10000\n" - "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest01(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NULL(de); - - FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest02(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NULL(de); - - FAIL_IF_NOT(de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60); - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest03(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NULL(de); - - FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest04(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD02(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NOT_NULL(m); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest05(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)"); - FAIL_IF_NULL(sig); - sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - - sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD03(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - Signature *s = de_ctx->sig_list; - SigMatch *m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - FAIL_IF_NULL(m->ctx); - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); - - s = de_ctx->sig_list->next; - m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - FAIL_IF_NULL(m->ctx); - de = (DetectThresholdData *)m->ctx; - FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); - - s = de_ctx->sig_list->next->next; - m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - FAIL_IF_NULL(m->ctx); - de = (DetectThresholdData *)m->ctx; - FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); - - PASS; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest06(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, - DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the rate_filter rules are loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest07(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, - DETECT_DETECTION_FILTER, -1); - FAIL_IF_NULL(m); - - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the rate_filter rules are loaded and well parsed - * with multilines - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest08(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, - DETECT_DETECTION_FILTER, -1); - FAIL_IF_NULL(m); - - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the rate_filter rules work - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest09(void) -{ - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - FAIL_IF_NULL(p); - - DetectEngineThreadCtx *det_ctx = NULL; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); - FAIL_IF_NULL(s); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - p->ts = TimeGet(); - p->alerts.cnt = 0; - p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); - p->alerts.cnt = 0; - p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); - p->alerts.cnt = 0; - p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); - - TimeSetIncrementTime(2); - p->ts = TimeGet(); - - p->alerts.cnt = 0; - p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP))); - - TimeSetIncrementTime(3); - p->ts = TimeGet(); - - p->alerts.cnt = 0; - p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP))); - - TimeSetIncrementTime(10); - p->ts = TimeGet(); - - p->alerts.cnt = 0; - p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); - - p->alerts.cnt = 0; - p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); - - UTHFreePacket(p); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \test Check if the rate_filter rules work with track by_rule - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest10(void) -{ - HostInitConfig(HOST_QUIET); - - /* Create two different packets falling to the same rule, and - * because count:3, we should drop on match #4. - */ - Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, - "172.26.0.2", "172.26.0.11"); - FAIL_IF_NULL(p1); - Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, - "172.26.0.1", "172.26.0.10"); - FAIL_IF_NULL(p2); - - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - DetectEngineThreadCtx *det_ctx = NULL; - - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); - FAIL_IF_NULL(s); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - p1->ts = TimeGet(); - p2->ts = p1->ts; - - /* All should be alerted, none dropped */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - p1->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - FAIL_IF(PacketTestAction(p2, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p2, 10) != 1); - p2->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - p1->action = 0; - - /* Match #4 should be dropped*/ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p2, 10) != 1); - p2->action = 0; - - TimeSetIncrementTime(2); - p1->ts = TimeGet(); - - /* Still dropped because timeout not expired */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - p1->action = 0; - - TimeSetIncrementTime(10); - p1->ts = TimeGet(); - - /* Not dropped because timeout expired */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - - /* Ensure that a Threshold entry was installed at the sig */ - FAIL_IF_NULL(de_ctx->ths_ctx.th_entry[s->num]); - - UTHFreePacket(p1); - UTHFreePacket(p2); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \test Check if the rate_filter rules work - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest11(void) -{ - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - FAIL_IF_NULL(p); - - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - DetectEngineThreadCtx *det_ctx = NULL; - - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); - FAIL_IF_NULL(s); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - p->ts = TimeGet(); - - int alerts10 = 0; - int alerts11 = 0; - int alerts12 = 0; - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - - TimeSetIncrementTime(100); - p->ts = TimeGet(); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - - TimeSetIncrementTime(10); - p->ts = TimeGet(); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - - FAIL_IF_NOT(alerts10 == 4); - /* One on the first interval, another on the second */ - FAIL_IF_NOT(alerts11 == 2); - FAIL_IF_NOT(alerts12 == 2); - - UTHFreePacket(p); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \test Check if the rate_filter rules work - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest12(void) -{ - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - FAIL_IF_NULL(p); - - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - DetectEngineThreadCtx *det_ctx = NULL; - - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); - FAIL_IF_NULL(s); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - p->ts = TimeGet(); - - int alerts10 = 0; - int alerts11 = 0; - int alerts12 = 0; - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - - TimeSetIncrementTime(100); - p->ts = TimeGet(); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - - TimeSetIncrementTime(10); - p->ts = TimeGet(); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts10 += PacketAlertCheck(p, 10); - alerts11 += PacketAlertCheck(p, 11); - alerts12 += PacketAlertCheck(p, 12); - - FAIL_IF_NOT(alerts10 == 10); - /* One on the first interval, another on the second */ - FAIL_IF_NOT(alerts11 == 1); - FAIL_IF_NOT(alerts12 == 1); - - UTHFreePacket(p); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest13(void) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigMatch *m = DetectGetLastSMByListId(sig, - DETECT_SM_LIST_SUPPRESS, DETECT_THRESHOLD, -1); - FAIL_IF_NULL(m); - - DetectThresholdData *de = (DetectThresholdData *)m->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/** - * \test Check if the suppress rules work - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest14(void) -{ - HostInitConfig(HOST_QUIET); - - Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", - "192.168.0.100", 1234, 24); - FAIL_IF_NULL(p1); - Packet *p2 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", - "192.168.0.100", 1234, 24); - FAIL_IF_NULL(p2); - - DetectEngineThreadCtx *det_ctx = NULL; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)"); - FAIL_IF_NULL(sig); - sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)"); - FAIL_IF_NULL(sig); - - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0); - FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1); - FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1); - FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0); - - UTHFreePacket(p1); - UTHFreePacket(p2); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - - HostShutdown(); - PASS; -} - -/** - * \test Check if the suppress rules work - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest15(void) -{ - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", - "192.168.0.100", 1234, 24); - FAIL_IF_NULL(p); - - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineThreadCtx *det_ctx = NULL; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - /* 10000 shouldn't match */ - FAIL_IF(PacketAlertCheck(p, 10000) != 0); - /* however, it should have set the drop flag */ - FAIL_IF(!(PacketTestAction(p, ACTION_DROP))); - - UTHFreePacket(p); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \test Check if the suppress rules work - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest16(void) -{ - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", - "192.168.0.100", 1234, 24); - FAIL_IF_NULL(p); - - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineThreadCtx *det_ctx = NULL; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - FAIL_IF(PacketAlertCheck(p, 1000) != 0); - /* however, it should have set the drop flag */ - FAIL_IF(!(PacketTestAction(p, ACTION_DROP))); - - UTHFreePacket(p); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \test Check if the suppress rules work - ip only rule - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest17(void) -{ - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", - "192.168.0.100", 1234, 24); - FAIL_IF_NULL(p); - - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineThreadCtx *det_ctx = NULL; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - /* 10000 shouldn't match */ - FAIL_IF(PacketAlertCheck(p, 10000) != 0); - /* however, it should have set the drop flag */ - FAIL_IF(!(PacketTestAction(p, ACTION_DROP))); - - UTHFreePacket(p); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateInvalidDummyFD12(void) -{ - FILE *fd = NULL; - const char *buffer = - "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n" - "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \test Check if the suppress rule parsing handles errors correctly - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest18(void) -{ - HostInitConfig(HOST_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); - FAIL_IF_NULL(s); - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - SigGroupBuild(de_ctx); - - FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); - SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; - DetectThresholdData *de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); - - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateInvalidDummyFD13(void) -{ - FILE *fd = NULL; - const char *buffer = - "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n" - "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \test Check if the suppress rule parsing handles errors correctly - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest19(void) -{ - HostInitConfig(HOST_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); - FAIL_IF_NULL(s); - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - SigGroupBuild(de_ctx); - FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); - SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; - DetectThresholdData *de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \brief Creates a dummy threshold file, with all valid options, for testing purposes. - * - * \retval fd Pointer to file descriptor. - */ -static FILE *SCThresholdConfGenerateValidDummyFD20(void) -{ - FILE *fd = NULL; - const char *buffer = - "suppress gen_id 1, sig_id 1000, track by_src, ip 2.2.3.4\n" - "suppress gen_id 1, sig_id 1000, track by_src, ip 1.2.3.4\n" - "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \test Check if the threshold file is loaded and well parsed - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest20(void) -{ - HostInitConfig(HOST_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)"); - FAIL_IF_NULL(s); - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - SigGroupBuild(de_ctx); - FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); - - SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; - DetectThresholdData *de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - FAIL_IF(smd->is_last); - - smd++; - de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - FAIL_IF(smd->is_last); - - smd++; - de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - FAIL_IF_NOT(smd->is_last); - - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** - * \test Check if the threshold file is loaded and well parsed, and applied - * correctly to a rule with thresholding - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest21(void) -{ - HostInitConfig(HOST_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - Signature *s = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); - FAIL_IF_NULL(s); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - SigGroupBuild(de_ctx); - FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); - - SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; - DetectThresholdData *de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - FAIL_IF(smd->is_last); - - smd++; - de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - FAIL_IF(smd->is_last); - - smd++; - de = (DetectThresholdData *)smd->ctx; - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - FAIL_IF_NOT(smd->is_last); - - DetectEngineCtxFree(de_ctx); - HostShutdown(); - PASS; -} - -/** -* \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination -* -* \retval fd Pointer to file descriptor. -*/ -static FILE *SCThresholdConfGenerateValidDummyFD22(void) -{ - FILE *fd = NULL; - const char *buffer = - "rate_filter gen_id 1, sig_id 10, track by_both, count 2, seconds 5, new_action drop, timeout 6\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \test Check if the rate_filter rules work with track by_both - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest22(void) -{ - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - IPPairInitConfig(IPPAIR_QUIET); - - /* This packet will cause rate_filter */ - Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); - FAIL_IF_NULL(p1); - - /* Should not be filtered for different destination */ - Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.2"); - FAIL_IF_NULL(p2); - - /* Should not be filtered when both src and dst the same */ - Packet *p3 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.1"); - FAIL_IF_NULL(p3); - - DetectEngineThreadCtx *det_ctx = NULL; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD22(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - p1->ts = TimeGet(); - p2->ts = p3->ts = p1->ts; - - /* All should be alerted, none dropped */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - FAIL_IF(PacketTestAction(p2, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p2, 10) != 1); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); - FAIL_IF(PacketTestAction(p3, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p3, 10) != 1); - - p1->action = p2->action = p3->action = 0; - - TimeSetIncrementTime(2); - p1->ts = TimeGet(); - p2->ts = p3->ts = p1->ts; - - /* p1 still shouldn't be dropped after 2nd alert */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - - p1->action = 0; - - TimeSetIncrementTime(2); - p1->ts = TimeGet(); - p2->ts = p3->ts = p1->ts; - - /* All should be alerted, only p1 must be dropped due to rate_filter*/ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - FAIL_IF(PacketTestAction(p2, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p2, 10) != 1); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); - FAIL_IF(PacketTestAction(p3, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p3, 10) != 1); - - p1->action = p2->action = p3->action = 0; - - TimeSetIncrementTime(7); - p1->ts = TimeGet(); - p2->ts = p3->ts = p1->ts; - - /* All should be alerted, none dropped (because timeout expired) */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - FAIL_IF(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - FAIL_IF(PacketTestAction(p2, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p2, 10) != 1); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); - FAIL_IF(PacketTestAction(p3, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p3, 10) != 1); - - UTHFreePacket(p3); - UTHFreePacket(p2); - UTHFreePacket(p1); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - IPPairShutdown(); - PASS; -} - -/** -* \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and destination -* -* \retval fd Pointer to file descriptor. -*/ -static FILE *SCThresholdConfGenerateValidDummyFD23(void) -{ - FILE *fd = NULL; - const char *buffer = - "rate_filter gen_id 1, sig_id 10, track by_both, count 1, seconds 5, new_action drop, timeout 6\n"; - - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); - if (fd == NULL) - SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); - - return fd; -} - -/** - * \test Check if the rate_filter by_both work when similar packets - * going in opposite direction - * - * \retval 1 on success - * \retval 0 on failure - */ -static int SCThresholdConfTest23(void) -{ - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - - IPPairInitConfig(IPPAIR_QUIET); - - /* Create two packets between same addresses in opposite direction */ - Packet *p1 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); - FAIL_IF_NULL(p1); - - Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.10", "172.26.0.1"); - FAIL_IF_NULL(p2); - - DetectEngineThreadCtx *det_ctx = NULL; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *sig = DetectEngineAppendSig(de_ctx, - "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)"); - FAIL_IF_NULL(sig); - - FAIL_IF_NOT_NULL(g_ut_threshold_fp); - g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD23(); - FAIL_IF_NULL(g_ut_threshold_fp); - FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - p1->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - /* First packet should be alerted, not dropped */ - FAIL_IF(PacketTestAction(p1, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p1, 10) != 1); - - TimeSetIncrementTime(2); - p2->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - /* Second packet should be dropped because it considered as "the same pair" - and rate_filter count reached*/ - FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP)); - FAIL_IF(PacketAlertCheck(p2, 10) != 1); - - UTHFreePacket(p2); - UTHFreePacket(p1); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - IPPairShutdown(); - PASS; -} -#endif /* UNITTESTS */ - -/** - * \brief This function registers unit tests for Classification Config API. - */ -void SCThresholdConfRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01); - UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02); - UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03); - UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04); - UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05); - UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06); - UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07); - UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08); - UtRegisterTest("SCThresholdConfTest09 - rate_filter", - SCThresholdConfTest09); - UtRegisterTest("SCThresholdConfTest10 - rate_filter", - SCThresholdConfTest10); - UtRegisterTest("SCThresholdConfTest11 - event_filter", - SCThresholdConfTest11); - UtRegisterTest("SCThresholdConfTest12 - event_filter", - SCThresholdConfTest12); - UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13); - UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14); - UtRegisterTest("SCThresholdConfTest15 - suppress drop", - SCThresholdConfTest15); - UtRegisterTest("SCThresholdConfTest16 - suppress drop", - SCThresholdConfTest16); - UtRegisterTest("SCThresholdConfTest17 - suppress drop", - SCThresholdConfTest17); - - UtRegisterTest("SCThresholdConfTest18 - suppress parsing", - SCThresholdConfTest18); - UtRegisterTest("SCThresholdConfTest19 - suppress parsing", - SCThresholdConfTest19); - UtRegisterTest("SCThresholdConfTest20 - suppress parsing", - SCThresholdConfTest20); - UtRegisterTest("SCThresholdConfTest21 - suppress parsing", - SCThresholdConfTest21); - UtRegisterTest("SCThresholdConfTest22 - rate_filter by_both", - SCThresholdConfTest22); - UtRegisterTest("SCThresholdConfTest23 - rate_filter by_both opposite", - SCThresholdConfTest23); - -#endif /* UNITTESTS */ -} - -/** - * @} - */ diff --git a/src/util-time.c b/src/util-time.c deleted file mode 100644 index 9900f1b94bd3..000000000000 --- a/src/util-time.c +++ /dev/null @@ -1,647 +0,0 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Ken Steele - * - * Time keeping for offline (non-live) packet handling (pcap files). - * And time string generation for alerts. - */ - -/* Real time vs offline time - * - * When we run on live traffic, time handling is simple. Packets have a - * timestamp set by the capture method. Management threads can simply - * use 'gettimeofday' to know the current time. There should never be - * any serious gap between the two. - * - * In offline mode, things are dramatically different. Here we try to keep - * the time from the pcap, which means that if the packets are in 2011 the - * log output should also reflect this. Multiple issues: - * 1. merged pcaps might have huge time jumps or time going backward - * 2. slowly recorded pcaps may be processed much faster than their 'realtime' - * 3. management threads need a concept of what the 'current' time is for - * enforcing timeouts - * 4. due to (1) individual threads may have very different views on what - * the current time is. E.g. T1 processed packet 1 with TS X, while T2 - * at the very same time processes packet 2 with TS X+100000s. - * - * In offline mode we keep the timestamp per thread. If a management thread - * needs current time, it will get the minimum of the threads' values. This - * is to avoid the problem that T2s time value might already trigger a flow - * timeout as the flow lastts + 100000s is almost certainly meaning the flow - * would be considered timed out. - */ - -#ifdef OS_WIN32 -/* for MinGW we need to set _POSIX_C_SOURCE before including - * sys/time.h. */ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif -#endif - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" -#include "threads.h" -#include "tm-threads.h" -#include "util-debug.h" -#include "util-time.h" - -#ifdef UNITTESTS -static struct timeval current_time = { 0, 0 }; -#endif -//static SCMutex current_time_mutex = SCMUTEX_INITIALIZER; -static SCSpinlock current_time_spinlock; -static bool live_time_tracking = true; - -struct tm *SCLocalTime(time_t timep, struct tm *result); -struct tm *SCUtcTime(time_t timep, struct tm *result); - -void TimeInit(void) -{ - SCSpinInit(¤t_time_spinlock, 0); - - /* Initialize Time Zone settings. */ - tzset(); -} - -void TimeDeinit(void) -{ - SCSpinDestroy(¤t_time_spinlock); -} - -bool TimeModeIsReady(void) -{ - if (live_time_tracking) - return true; - return TmThreadsTimeSubsysIsReady(); -} - -void TimeModeSetLive(void) -{ - live_time_tracking = true; - SCLogDebug("live time mode enabled"); -} - -void TimeModeSetOffline (void) -{ - live_time_tracking = false; - SCLogDebug("offline time mode enabled"); -} - -bool TimeModeIsLive(void) -{ - return live_time_tracking; -} - -void TimeSetByThread(const int thread_id, SCTime_t tv) -{ - if (live_time_tracking) - return; - - TmThreadsSetThreadTimestamp(thread_id, tv); -} - -#ifdef UNITTESTS -void TimeSet(SCTime_t ts) -{ - if (live_time_tracking) - return; - - SCSpinLock(¤t_time_spinlock); - SCTIME_TO_TIMEVAL(¤t_time, ts); - - SCLogDebug("time set to %" PRIuMAX " sec, %" PRIuMAX " usec", - (uintmax_t)current_time.tv_sec, (uintmax_t)current_time.tv_usec); - - SCSpinUnlock(¤t_time_spinlock); -} - -/** \brief set the time to "gettimeofday" meant for testing */ -void TimeSetToCurrentTime(void) -{ - struct timeval tv; - memset(&tv, 0x00, sizeof(tv)); - - gettimeofday(&tv, NULL); - - SCTime_t ts = SCTIME_FROM_TIMEVAL(&tv); - TimeSet(ts); -} -#endif - -SCTime_t TimeGet(void) -{ - struct timeval tv = { 0 }; - if (live_time_tracking) { - gettimeofday(&tv, NULL); - } else { -#ifdef UNITTESTS - if (unlikely(RunmodeIsUnittests())) { - SCSpinLock(¤t_time_spinlock); - tv.tv_sec = current_time.tv_sec; - tv.tv_usec = current_time.tv_usec; - SCSpinUnlock(¤t_time_spinlock); - } else { -#endif - TmThreadsGetMinimalTimestamp(&tv); -#ifdef UNITTESTS - } -#endif - } - - SCLogDebug("time we got is %" PRIuMAX " sec, %" PRIuMAX " usec", (uintmax_t)tv.tv_sec, - (uintmax_t)tv.tv_usec); - return SCTIME_FROM_TIMEVAL(&tv); -} - -#ifdef UNITTESTS -/** \brief increment the time in the engine - * \param tv_sec seconds to increment the time with */ -void TimeSetIncrementTime(uint32_t tv_sec) -{ - SCTime_t ts = TimeGet(); - - ts = SCTIME_ADD_SECS(ts, tv_sec); - - TimeSet(ts); -} -#endif - -#ifdef OS_WIN32 -/** \internal - * \brief wrapper around strftime on Windows to provide output - * compatible with posix %z - */ -static inline void WinStrftime(const SCTime_t ts, const struct tm *t, char *str, size_t size) -{ - char time_fmt[64] = { 0 }; - char tz[6] = { 0 }; - const long int tzdiff = -_timezone; - const int h = abs(_timezone) / 3600 + _daylight; - const int m = (abs(_timezone) % 3600) / 60; - snprintf(tz, sizeof(tz), "%c%02d%02d", tzdiff < 0 ? '-' : '+', h, m); - strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S.%%06u", t); - snprintf(str, size, time_fmt, SCTIME_USECS(ts)); - strlcat(str, tz, size); // append our timezone -} -#endif - -void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size) -{ - time_t time = SCTIME_SECS(ts); - struct tm local_tm; - memset(&local_tm, 0, sizeof(local_tm)); - struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); - - if (likely(t != NULL)) { -#ifdef OS_WIN32 - WinStrftime(ts, t, str, size); -#else - char time_fmt[64] = { 0 }; - int64_t usec = SCTIME_USECS(ts); - strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S.%%06" PRIi64 "%z", t); - snprintf(str, size, time_fmt, usec); -#endif - } else { - snprintf(str, size, "ts-error"); - } -} - -void CreateUtcIsoTimeString(const SCTime_t ts, char *str, size_t size) -{ - time_t time = SCTIME_SECS(ts); - struct tm local_tm; - memset(&local_tm, 0, sizeof(local_tm)); - struct tm *t = (struct tm*)SCUtcTime(time, &local_tm); - - if (likely(t != NULL)) { - char time_fmt[64] = { 0 }; - strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S", t); - snprintf(str, size, time_fmt, SCTIME_USECS(ts)); - } else { - snprintf(str, size, "ts-error"); - } -} - -void CreateFormattedTimeString (const struct tm *t, const char *fmt, char *str, size_t size) -{ - if (likely(t != NULL)) { - strftime(str, size, fmt, t); - } else { - snprintf(str, size, "ts-error"); - } -} - -struct tm *SCUtcTime(time_t timep, struct tm *result) -{ - return gmtime_r(&timep, result); -} - -/* - * Time Caching code - */ - -#ifndef TLS -/* OpenBSD does not support thread_local, so don't use time caching on BSD - */ -struct tm *SCLocalTime(time_t timep, struct tm *result) -{ - return localtime_r(&timep, result); -} - -void CreateTimeString(const SCTime_t ts, char *str, size_t size) -{ - time_t time = SCTIME_SECS(ts); - struct tm local_tm; - struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); - - if (likely(t != NULL)) { - snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, - t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t)SCTIME_USECS(ts)); - } else { - snprintf(str, size, "ts-error"); - } -} - -#else - -/* On systems supporting thread_local, use Per-thread values for caching - * in CreateTimeString */ - -/* The maximum possible length of the time string. - * "%02d/%02d/%02d-%02d:%02d:%02d.%06u" - * Or "01/01/2013-15:42:21.123456", which is 26, so round up to 32. */ -#define MAX_LOCAL_TIME_STRING 32 - -static thread_local int mru_time_slot; /* Most recently used cached value */ -static thread_local time_t last_local_time[2]; -static thread_local short int cached_local_time_len[2]; -static thread_local char cached_local_time[2][MAX_LOCAL_TIME_STRING]; - -/* Per-thread values for caching SCLocalTime() These cached values are - * independent from the CreateTimeString cached values. */ -static thread_local int mru_tm_slot; /* Most recently used local tm */ -static thread_local time_t cached_minute_start[2]; -static thread_local struct tm cached_local_tm[2]; - -/** \brief Convert time_t into Year, month, day, hour and minutes. - * \param timep Time in seconds since defined date. - * \param result The structure into which the broken down time it put. - * - * To convert a time in seconds into year, month, day, hours, minutes - * and seconds, call localtime_r(), which uses the current time zone - * to compute these values. Note, glibc's localtime_r() acquires a lock - * each time it is called, which limits parallelism. To call - * localtime_r() less often, the values returned are cached for the - * current and previous minute and then seconds are adjusted to - * compute the returned result. This is valid as long as the - * difference between the start of the current minute and the current - * time is less than 60 seconds. Once the minute value changes, all - * the other values could change. - * - * Two values are cached to prevent thrashing when changing from one - * minute to the next. The two cached minutes are independent and are - * not required to be M and M+1. If more than two minutes are - * requested, the least-recently-used cached value is updated more - * often, the results are still correct, but performance will be closer - * to previous performance. - */ -struct tm *SCLocalTime(time_t timep, struct tm *result) -{ - /* Only get a new local time when the time crosses into a new - * minute. */ - int mru = mru_tm_slot; - int lru = 1 - mru; - int mru_seconds = timep - cached_minute_start[mru]; - int lru_seconds = timep - cached_minute_start[lru]; - int new_seconds; - if (cached_minute_start[mru]==0 && cached_minute_start[lru]==0) { - localtime_r(&timep, &cached_local_tm[lru]); - /* Subtract seconds to get back to the start of the minute. */ - new_seconds = cached_local_tm[lru].tm_sec; - cached_minute_start[lru] = timep - new_seconds; - mru = lru; - mru_tm_slot = mru; - } else if (lru_seconds > 0 && (mru_seconds >= 0 && mru_seconds <= 59)) { - /* Use most-recently cached time, adjusting the seconds. */ - new_seconds = mru_seconds; - } else if (mru_seconds > 0 && (lru_seconds >= 0 && lru_seconds <= 59)) { - /* Use least-recently cached time, update to most recently used. */ - new_seconds = lru_seconds; - mru = lru; - mru_tm_slot = mru; - } else { - /* Update least-recent cached time. */ - if (localtime_r(&timep, &cached_local_tm[lru]) == NULL) - return NULL; - /* Subtract seconds to get back to the start of the minute. */ - new_seconds = cached_local_tm[lru].tm_sec; - cached_minute_start[lru] = timep - new_seconds; - mru = lru; - mru_tm_slot = mru; - } - memcpy(result, &cached_local_tm[mru], sizeof(struct tm)); - result->tm_sec = new_seconds; - - return result; -} - -/* Update the cached time string in cache index N, for the current minute. */ -static int UpdateCachedTime(int n, time_t time) -{ - struct tm local_tm; - struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); - int cached_len = snprintf(cached_local_time[n], MAX_LOCAL_TIME_STRING, - "%02d/%02d/%02d-%02d:%02d:", - t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, - t->tm_hour, t->tm_min); - cached_local_time_len[n] = cached_len; - /* Store the time of the beginning of the minute. */ - last_local_time[n] = time - t->tm_sec; - mru_time_slot = n; - - return t->tm_sec; -} - -/** \brief Return a formatted string for the provided time. - * - * Cache the Month/Day/Year - Hours:Min part of the time string for - * the current minute. Copy that result into the return string and - * then only print the seconds for each call. - */ -void CreateTimeString(const SCTime_t ts, char *str, size_t size) -{ - time_t time = SCTIME_SECS(ts); - int seconds; - - /* Only get a new local time when the time crosses into a new - * minute */ - int mru = mru_time_slot; - int lru = 1 - mru; - int mru_seconds = time - last_local_time[mru]; - int lru_seconds = time - last_local_time[lru]; - if (last_local_time[mru]==0 && last_local_time[lru]==0) { - /* First time here, update both caches */ - UpdateCachedTime(mru, time); - seconds = UpdateCachedTime(lru, time); - } else if (mru_seconds >= 0 && mru_seconds <= 59) { - /* Use most-recently cached time. */ - seconds = mru_seconds; - } else if (lru_seconds >= 0 && lru_seconds <= 59) { - /* Use least-recently cached time. Change this slot to Most-recent */ - seconds = lru_seconds; - mru_time_slot = lru; - } else { - /* Update least-recent cached time. Lock accessing local time - * function because it keeps any internal non-spin lock. */ - seconds = UpdateCachedTime(lru, time); - } - - /* Copy the string up to the current minute then print the seconds - into the return string buffer. */ - char *cached_str = cached_local_time[mru_time_slot]; - int cached_len = cached_local_time_len[mru_time_slot]; - if (cached_len >= (int)size) - cached_len = size; - memcpy(str, cached_str, cached_len); - snprintf(str + cached_len, size - cached_len, "%02d.%06u", seconds, (uint32_t)SCTIME_USECS(ts)); -} - -#endif /* defined(__OpenBSD__) */ - -/** - * \brief Convert broken-down time to seconds since Unix epoch. - * - * This function is based on: http://www.catb.org/esr/time-programming - * (released to the public domain). - * - * \param tp Pointer to broken-down time. - * - * \retval Seconds since Unix epoch. - */ -time_t SCMkTimeUtc (struct tm *tp) -{ - time_t result; - long year; -#define MONTHSPERYEAR 12 - static const int mdays[MONTHSPERYEAR] = - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - year = 1900 + tp->tm_year + tp->tm_mon / MONTHSPERYEAR; - result = (year - 1970) * 365 + mdays[tp->tm_mon % MONTHSPERYEAR]; - result += (year - 1968) / 4; - result -= (year - 1900) / 100; - result += (year - 1600) / 400; - if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) && - (tp->tm_mon % MONTHSPERYEAR) < 2) - result--; - result += tp->tm_mday - 1; - result *= 24; - result += tp->tm_hour; - result *= 60; - result += tp->tm_min; - result *= 60; - result += tp->tm_sec; -#ifndef OS_WIN32 - if (tp->tm_gmtoff) - result -= tp->tm_gmtoff; -#endif - return result; -} - -/** - * \brief Parse a date string based on specified patterns. - * - * This function is based on GNU C library getdate. - * - * \param string Date string to parse. - * \param patterns String array containing patterns. - * \param num_patterns Number of patterns to check. - * \param tp Pointer to broken-down time. - * - * \retval 0 on success. - * \retval 1 on failure. - */ -int SCStringPatternToTime (char *string, const char **patterns, int num_patterns, - struct tm *tp) -{ - char *result = NULL; - int i = 0; - - /* Do the pattern matching */ - for (i = 0; i < num_patterns; i++) - { - if (patterns[i] == NULL) - continue; - - tp->tm_hour = tp->tm_min = tp->tm_sec = 0; - tp->tm_year = tp->tm_mon = tp->tm_mday = tp->tm_wday = INT_MIN; - tp->tm_isdst = -1; -#ifndef OS_WIN32 - tp->tm_gmtoff = 0; - tp->tm_zone = NULL; -#endif - result = strptime(string, patterns[i], tp); - - if (result && *result == '\0') - break; - } - - /* Return if no patterns matched */ - if (result == NULL || *result != '\0') - return 1; - - /* Return if no date is given */ - if (tp->tm_year == INT_MIN && tp->tm_mon == INT_MIN && - tp->tm_mday == INT_MIN) - return 1; - - /* The first of the month is assumed, if only year and - month is given */ - if (tp->tm_year != INT_MIN && tp->tm_mon != INT_MIN && - tp->tm_mday <= 0) - tp->tm_mday = 1; - - return 0; -} - -/** - * \brief Convert epoch time to string pattern. - * - * This function converts epoch time to a string based on a pattern. - * - * \param epoch Epoch time. - * \param pattern String pattern. - * \param str Formated string. - * \param size Size of allocated string. - * - * \retval 0 on success. - * \retval 1 on failure. - */ -int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, size_t size) -{ - struct tm tm; - memset(&tm, 0, sizeof(tm)); - struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); - char buffer[PATH_MAX] = { 0 }; - - if (unlikely(tp == NULL)) { - return 1; - } - - int r = strftime(buffer, sizeof(buffer), pattern, tp); - if (r == 0) { - return 1; - } - - strlcpy(str, buffer, size); - - return 0; -} - -/** - * \brief Parse string containing time size (1m, 1h, etc). - * - * \param str String to parse. - * - * \retval size on success. - * \retval 0 on failure. - */ -uint64_t SCParseTimeSizeString (const char *str) -{ - uint64_t size = 0; - uint64_t modifier = 1; - char last = str[strlen(str)-1]; - - switch (last) - { - case '0' ... '9': - break; - /* seconds */ - case 's': - break; - /* minutes */ - case 'm': - modifier = 60; - break; - /* hours */ - case 'h': - modifier = 60 * 60; - break; - /* days */ - case 'd': - modifier = 60 * 60 * 24; - break; - /* weeks */ - case 'w': - modifier = 60 * 60 * 24 * 7; - break; - /* invalid */ - default: - return 0; - } - - errno = 0; - size = strtoumax(str, NULL, 10); - if (errno) { - return 0; - } - - return (size * modifier); -} - -/** - * \brief Get seconds until a time unit changes. - * - * \param str String containing time type (minute, hour, etc). - * \param epoch Epoch time. - * - * \retval seconds. - */ -uint64_t SCGetSecondsUntil (const char *str, time_t epoch) -{ - uint64_t seconds = 0; - struct tm tm; - memset(&tm, 0, sizeof(tm)); - struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); - - if (strcmp(str, "minute") == 0) - seconds = 60 - tp->tm_sec; - else if (strcmp(str, "hour") == 0) - seconds = (60 * (60 - tp->tm_min)) + (60 - tp->tm_sec); - else if (strcmp(str, "day") == 0) - seconds = (3600 * (24 - tp->tm_hour)) + (60 * (60 - tp->tm_min)) + - (60 - tp->tm_sec); - - return seconds; -} - -uint64_t SCTimespecAsEpochMillis(const struct timespec* ts) -{ - return ts->tv_sec * 1000L + ts->tv_nsec / 1000000L; -} - -uint64_t TimeDifferenceMicros(struct timeval t0, struct timeval t1) -{ - return (uint64_t)(t1.tv_sec - t0.tv_sec) * 1000000L + (t1.tv_usec - t1.tv_usec); -} diff --git a/src/util-time.h b/src/util-time.h deleted file mode 100644 index 9bbd8798dd17..000000000000 --- a/src/util-time.h +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_TIME_H__ -#define __UTIL_TIME_H__ - -/* - * The SCTime_t member is broken up as - * seconds: 44 - * useconds: 20 - * - * Over 500000 years can be represented in 44 bits of seconds: - * 2^44/(365*24*60*60) - * 557855.560 - * 1048576 microseconds can be represented in 20 bits: - * 2^20 - * 1048576 - */ - -typedef struct { - uint64_t secs : 44; - uint64_t usecs : 20; -} SCTime_t; - -#define SCTIME_INIT(t) \ - { \ - (t).secs = 0; \ - (t).usecs = 0; \ - } - -#define SCTIME_INITIALIZER \ - (SCTime_t) \ - { \ - .secs = 0, .usecs = 0 \ - } -#define SCTIME_USECS(t) ((uint64_t)(t).usecs) -#define SCTIME_SECS(t) ((uint64_t)(t).secs) -#define SCTIME_MSECS(t) (SCTIME_SECS(t) * 1000 + SCTIME_USECS(t) / 1000) -#define SCTIME_ADD_SECS(ts, s) SCTIME_FROM_SECS((ts).secs + (s)) -#define SCTIME_ADD_USECS(ts, us) SCTIME_FROM_USECS((ts).usecs + (us)) -#define SCTIME_FROM_SECS(s) \ - (SCTime_t) \ - { \ - .secs = (s), .usecs = 0 \ - } -#define SCTIME_FROM_USECS(us) \ - (SCTime_t) \ - { \ - .secs = 0, .usecs = (us) \ - } -#define SCTIME_FROM_TIMEVAL(tv) \ - (SCTime_t) \ - { \ - .secs = (tv)->tv_sec, .usecs = (tv)->tv_usec \ - } -/** \brief variant to deal with potentially bad timestamps, like from pcap files */ -#define SCTIME_FROM_TIMEVAL_UNTRUSTED(tv) \ - (SCTime_t) \ - { \ - .secs = ((tv)->tv_sec > 0) ? (tv)->tv_sec : 0, \ - .usecs = ((tv)->tv_usec > 0) ? (tv)->tv_usec : 0 \ - } -#define SCTIME_FROM_TIMESPEC(ts) \ - (SCTime_t) \ - { \ - .secs = (ts)->tv_sec, .usecs = (ts)->tv_nsec * 1000 \ - } - -#define SCTIME_TO_TIMEVAL(tv, t) \ - (tv)->tv_sec = SCTIME_SECS((t)); \ - (tv)->tv_usec = SCTIME_USECS((t)); -#define SCTIME_CMP(a, b, CMP) \ - ((SCTIME_SECS(a) == SCTIME_SECS(b)) ? (SCTIME_USECS(a) CMP SCTIME_USECS(b)) \ - : (SCTIME_SECS(a) CMP SCTIME_SECS(b))) -#define SCTIME_CMP_GTE(a, b) SCTIME_CMP((a), (b), >=) -#define SCTIME_CMP_GT(a, b) SCTIME_CMP((a), (b), >) -#define SCTIME_CMP_LT(a, b) SCTIME_CMP((a), (b), <) -#define SCTIME_CMP_LTE(a, b) SCTIME_CMP((a), (b), <=) -#define SCTIME_CMP_NEQ(a, b) SCTIME_CMP((a), (b), !=) - -void TimeInit(void); -void TimeDeinit(void); - -void TimeSetByThread(const int thread_id, SCTime_t tv); -SCTime_t TimeGet(void); - -/** \brief initialize a 'struct timespec' from a 'struct timeval'. */ -#define FROM_TIMEVAL(timev) { .tv_sec = (timev).tv_sec, .tv_nsec = (timev).tv_usec * 1000 } - -/** \brief compare two 'struct timeval' and return if the first is earlier than the second */ -static inline bool TimevalEarlier(struct timeval *first, struct timeval *second) -{ - /* from man timercmp on Linux: "Some systems (but not Linux/glibc), have a broken timercmp() - * implementation, in which CMP of >=, <=, and == do not work; portable applications can instead - * use ... !timercmp(..., >) */ - return !timercmp(first, second, >); -} - -#ifndef timeradd -#define timeradd(a, b, r) \ - do { \ - (r)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ - (r)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ - if ((r)->tv_usec >= 1000000) { \ - (r)->tv_sec++; \ - (r)->tv_usec -= 1000000; \ - } \ - } while (0) -#endif - -#ifdef UNITTESTS -void TimeSet(SCTime_t); -void TimeSetToCurrentTime(void); -void TimeSetIncrementTime(uint32_t); -#endif - -bool TimeModeIsReady(void); -void TimeModeSetLive(void); -void TimeModeSetOffline (void); -bool TimeModeIsLive(void); - -struct tm *SCLocalTime(time_t timep, struct tm *result); -void CreateTimeString(const SCTime_t ts, char *str, size_t size); -void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size); -void CreateUtcIsoTimeString(const SCTime_t ts, char *str, size_t size); -void CreateFormattedTimeString(const struct tm *t, const char * fmt, char *str, size_t size); -time_t SCMkTimeUtc(struct tm *tp); -int SCStringPatternToTime(char *string, const char **patterns, - int num_patterns, struct tm *time); -int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, - size_t size); -uint64_t SCParseTimeSizeString (const char *str); -uint64_t SCGetSecondsUntil (const char *str, time_t epoch); -uint64_t SCTimespecAsEpochMillis(const struct timespec *ts); -uint64_t TimeDifferenceMicros(struct timeval t0, struct timeval t1); - -#endif /* __UTIL_TIME_H__ */ - diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c deleted file mode 100644 index 48d2a045c19b..000000000000 --- a/src/util-unittest-helper.c +++ /dev/null @@ -1,1154 +0,0 @@ -/* Copyright (C) 2007-2017 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - * - * This file provide a set of helper functions for reducing the complexity - * when constructing unittests - */ - -#include "suricata-common.h" - -#include "decode.h" - -#include "flow-private.h" -#include "flow-util.h" -#include "flow-spare-pool.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-alert.h" -#include "detect-engine-sigorder.h" -#include "detect-engine-build.h" - -#include "stream-tcp.h" -#include "stream-tcp-private.h" - -#include "util-debug.h" -#include "util-time.h" -#include "util-error.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -#if defined(UNITTESTS) || defined(FUZZ) -Flow *TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp) -{ - struct in_addr in; - - Flow *f = SCMalloc(sizeof(Flow)); - if (unlikely(f == NULL)) { - printf("FlowAlloc failed\n"); - ; - return NULL; - } - memset(f, 0x00, sizeof(Flow)); - - FLOW_INITIALIZE(f); - - if (family == AF_INET) { - f->flags |= FLOW_IPV4; - } else if (family == AF_INET6) { - f->flags |= FLOW_IPV6; - } - - if (src != NULL) { - if (family == AF_INET) { - if (inet_pton(AF_INET, src, &in) != 1) { - printf("invalid address %s\n", src); - SCFree(f); - return NULL; - } - f->src.addr_data32[0] = in.s_addr; - } else { - BUG_ON(1); - } - } - if (dst != NULL) { - if (family == AF_INET) { - if (inet_pton(AF_INET, dst, &in) != 1) { - printf("invalid address %s\n", dst); - SCFree(f); - return NULL; - } - f->dst.addr_data32[0] = in.s_addr; - } else { - BUG_ON(1); - } - } - - f->sp = sp; - f->dp = dp; - - return f; -} -/** \brief writes the contents of a buffer into a file */ -int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size) -{ - if (remove(name) != 0) { - if (errno != ENOENT) { - printf("failed remove, errno=%d\n", errno); - return -1; - } - } - FILE *fd = fopen(name, "wb"); - if (fd == NULL) { - printf("failed open, errno=%d\n", errno); - return -2; - } - if (fwrite (data, 1, size, fd) != size) { - fclose(fd); - return -3; - } - fclose(fd); - return 0; -} - -#endif -#ifdef UNITTESTS - -/** - * \brief return the uint32_t for a ipv4 address string - * - * \param str Valid ipaddress in string form (e.g. 1.2.3.4) - * - * \retval uint the uin32_t representation - */ -uint32_t UTHSetIPv4Address(const char *str) -{ - struct in_addr in; - if (inet_pton(AF_INET, str, &in) != 1) { - printf("invalid IPv6 address %s\n", str); - exit(EXIT_FAILURE); - } - return (uint32_t)in.s_addr; -} - -/** - * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests - * specifying ip and port sources and destinations (IPV6) - * - * \param payload pointer to the payload buffer - * \param payload_len pointer to the length of the payload - * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP - * \param src pointer to a string containing the ip source - * \param dst pointer to a string containing the ip destination - * \param sport pointer to a string containing the port source - * \param dport pointer to a string containing the port destination - * - * \retval Packet pointer to the built in packet - */ -Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len, - uint8_t ipproto, const char *src, const char *dst, - uint16_t sport, uint16_t dport) -{ - uint32_t in[4]; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return NULL; - - p->ts = TimeGet(); - - p->src.family = AF_INET6; - p->dst.family = AF_INET6; - p->payload = payload; - p->payload_len = payload_len; - p->proto = ipproto; - - p->ip6h = SCMalloc(sizeof(IPV6Hdr)); - if (p->ip6h == NULL) - goto error; - memset(p->ip6h, 0, sizeof(IPV6Hdr)); - p->ip6h->s_ip6_nxt = ipproto; - p->ip6h->s_ip6_plen = htons(payload_len + sizeof(TCPHdr)); - - if (inet_pton(AF_INET6, src, &in) != 1) - goto error; - p->src.addr_data32[0] = in[0]; - p->src.addr_data32[1] = in[1]; - p->src.addr_data32[2] = in[2]; - p->src.addr_data32[3] = in[3]; - p->sp = sport; - p->ip6h->s_ip6_src[0] = in[0]; - p->ip6h->s_ip6_src[1] = in[1]; - p->ip6h->s_ip6_src[2] = in[2]; - p->ip6h->s_ip6_src[3] = in[3]; - - if (inet_pton(AF_INET6, dst, &in) != 1) - goto error; - p->dst.addr_data32[0] = in[0]; - p->dst.addr_data32[1] = in[1]; - p->dst.addr_data32[2] = in[2]; - p->dst.addr_data32[3] = in[3]; - p->dp = dport; - p->ip6h->s_ip6_dst[0] = in[0]; - p->ip6h->s_ip6_dst[1] = in[1]; - p->ip6h->s_ip6_dst[2] = in[2]; - p->ip6h->s_ip6_dst[3] = in[3]; - - p->tcph = SCMalloc(sizeof(TCPHdr)); - if (p->tcph == NULL) - goto error; - memset(p->tcph, 0, sizeof(TCPHdr)); - p->tcph->th_sport = htons(sport); - p->tcph->th_dport = htons(dport); - - SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len); - return p; - -error: - if (p != NULL) { - if (p->ip6h != NULL) { - SCFree(p->ip6h); - } - if (p->tcph != NULL) { - SCFree(p->tcph); - } - SCFree(p); - } - return NULL; -} - -/** - * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests - * specifying ip and port sources and destinations - * - * \param payload pointer to the payload buffer - * \param payload_len pointer to the length of the payload - * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP - * \param src pointer to a string containing the ip source - * \param dst pointer to a string containing the ip destination - * \param sport pointer to a string containing the port source - * \param dport pointer to a string containing the port destination - * - * \retval Packet pointer to the built in packet - */ -Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, - uint8_t ipproto, const char *src, const char *dst, - uint16_t sport, uint16_t dport) -{ - struct in_addr in; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return NULL; - - p->ts = TimeGet(); - - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = payload; - p->payload_len = payload_len; - p->proto = ipproto; - - if (inet_pton(AF_INET, src, &in) != 1) - goto error; - p->src.addr_data32[0] = in.s_addr; - p->sp = sport; - - if (inet_pton(AF_INET, dst, &in) != 1) - goto error; - p->dst.addr_data32[0] = in.s_addr; - p->dp = dport; - - p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); - if (p->ip4h == NULL) - goto error; - - p->ip4h->s_ip_src.s_addr = p->src.addr_data32[0]; - p->ip4h->s_ip_dst.s_addr = p->dst.addr_data32[0]; - p->ip4h->ip_proto = ipproto; - p->ip4h->ip_verhl = sizeof(IPV4Hdr); - p->proto = ipproto; - - int hdr_offset = sizeof(IPV4Hdr); - switch (ipproto) { - case IPPROTO_UDP: - p->udph = (UDPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); - if (p->udph == NULL) - goto error; - - p->udph->uh_sport = sport; - p->udph->uh_dport = dport; - hdr_offset += sizeof(UDPHdr); - break; - case IPPROTO_TCP: - p->tcph = (TCPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); - if (p->tcph == NULL) - goto error; - - p->tcph->th_sport = htons(sport); - p->tcph->th_dport = htons(dport); - hdr_offset += sizeof(TCPHdr); - break; - case IPPROTO_ICMP: - p->icmpv4h = (ICMPV4Hdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); - if (p->icmpv4h == NULL) - goto error; - - hdr_offset += sizeof(ICMPV4Hdr); - break; - default: - break; - /* TODO: Add more protocols */ - } - - if (payload && payload_len) { - PacketCopyDataOffset(p, hdr_offset, payload, payload_len); - } - SET_PKT_LEN(p, hdr_offset + payload_len); - p->payload = GET_PKT_DATA(p)+hdr_offset; - - return p; - -error: - SCFree(p); - return NULL; -} - -/** - * \brief UTHBuildPacket is a wrapper that build packets with default ip - * and port fields - * - * \param payload pointer to the payload buffer - * \param payload_len pointer to the length of the payload - * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP - * - * \retval Packet pointer to the built in packet - */ -Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len, - uint8_t ipproto) -{ - return UTHBuildPacketReal(payload, payload_len, ipproto, - "192.168.1.5", "192.168.1.1", - 41424, 80); -} - -/** - * \brief UTHBuildPacketArrayFromEth is a wrapper that build a packets from an array of - * packets in ethernet rawbytes. Hint: It also share the flows. - * - * \param raw_eth pointer to the array of ethernet packets in rawbytes - * \param pktsize pointer to the array of sizes corresponding to each buffer pointed - * from pktsize. - * \param numpkts number of packets in the array - * - * \retval Packet pointer to the array of built in packets; NULL if something fail - */ -Packet **UTHBuildPacketArrayFromEth(uint8_t *raw_eth[], int *pktsize, int numpkts) -{ - DecodeThreadVars dtv; - ThreadVars th_v; - if (raw_eth == NULL || pktsize == NULL || numpkts <= 0) { - SCLogError("The arrays cant be null, and the number" - " of packets should be grater thatn zero"); - return NULL; - } - Packet **p = NULL; - p = SCMalloc(sizeof(Packet *) * numpkts); - if (unlikely(p == NULL)) - return NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - - int i = 0; - for (; i < numpkts; i++) { - p[i] = PacketGetFromAlloc(); - if (p[i] == NULL) { - SCFree(p); - return NULL; - } - DecodeEthernet(&th_v, &dtv, p[i], raw_eth[i], pktsize[i]); - } - return p; -} - -/** - * \brief UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes - * - * \param raw_eth pointer to the rawbytes containing an ethernet packet - * (and any other headers inside) - * \param pktsize pointer to the length of the payload - * - * \retval Packet pointer to the built in packet; NULL if something fail - */ -Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize) -{ - DecodeThreadVars dtv; - ThreadVars th_v; - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return NULL; - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - - DecodeEthernet(&th_v, &dtv, p, raw_eth, pktsize); - return p; -} - -/** - * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs - * and defaulting ports - * - * \param payload pointer to the payload buffer - * \param payload_len pointer to the length of the payload - * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP - * - * \retval Packet pointer to the built in packet - */ -Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, - uint8_t ipproto, const char *src, const char *dst) -{ - return UTHBuildPacketReal(payload, payload_len, ipproto, - src, dst, - 41424, 80); -} - -/** - * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs - * and defaulting ports (IPV6) - * - * \param payload pointer to the payload buffer - * \param payload_len pointer to the length of the payload - * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP - * - * \retval Packet pointer to the built in packet - */ -Packet *UTHBuildPacketIPV6SrcDst(uint8_t *payload, uint16_t payload_len, - uint8_t ipproto, const char *src, const char *dst) -{ - return UTHBuildPacketIPV6Real(payload, payload_len, ipproto, - src, dst, - 41424, 80); -} - -/** - * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying - * src and dst ports and defaulting IPs - * - * \param payload pointer to the payload buffer - * \param payload_len pointer to the length of the payload - * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP - * - * \retval Packet pointer to the built in packet - */ -Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len, - uint8_t ipproto, uint16_t sport, uint16_t dport) -{ - return UTHBuildPacketReal(payload, payload_len, ipproto, - "192.168.1.5", "192.168.1.1", - sport, dport); -} - -/** - * \brief UTHFreePackets: function to release the allocated data - * from UTHBuildPacket and the packet itself - * - * \param p pointer to the Packet - */ -void UTHFreePackets(Packet **p, int numpkts) -{ - if (p == NULL) - return; - - int i = 0; - for (; i < numpkts; i++) { - UTHFreePacket(p[i]); - } -} - -/** - * \brief UTHFreePacket: function to release the allocated data - * from UTHBuildPacket and the packet itself - * - * \param p pointer to the Packet - */ -void UTHFreePacket(Packet *p) -{ - if (p == NULL) - return; - PacketFree(p); -} - -void UTHAssignFlow(Packet *p, Flow *f) -{ - if (p && f) { - p->flow = f; - p->flags |= PKT_HAS_FLOW; - } -} - -Flow *UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp) -{ - return TestHelperBuildFlow(family, src, dst, sp, dp); -} - -void UTHFreeFlow(Flow *flow) -{ - if (flow != NULL) { - SCFree(flow);//FlowFree(flow); - } -} - -int UTHAddStreamToFlow(Flow *f, int direction, - uint8_t *data, uint32_t data_len) -{ - FAIL_IF_NULL(f); - FAIL_IF_NOT(f->proto == IPPROTO_TCP); - FAIL_IF_NULL(f->protoctx); - TcpSession *ssn = f->protoctx; - - StreamingBufferSegment seg; - TcpStream *stream = direction == 0 ? &ssn->client : &ssn->server; - int r = StreamingBufferAppend(&stream->sb, &stream_config.sbcnf, &seg, data, data_len); - FAIL_IF_NOT(r == 0); - stream->last_ack += data_len; - return 1; -} - -int UTHAddSessionToFlow(Flow *f, - uint32_t ts_isn, - uint32_t tc_isn) -{ - FAIL_IF_NULL(f); - - TcpSession *ssn = SCCalloc(1, sizeof(*ssn)); - FAIL_IF_NULL(ssn); - - StreamingBuffer x = STREAMING_BUFFER_INITIALIZER; - ssn->client.sb = x; - ssn->server.sb = x; - - ssn->client.isn = ts_isn; - ssn->server.isn = tc_isn; - - f->protoctx = ssn; - return 1; -} - -int UTHRemoveSessionFromFlow(Flow *f) -{ - FAIL_IF_NULL(f); - FAIL_IF_NOT(f->proto == IPPROTO_TCP); - TcpSession *ssn = f->protoctx; - FAIL_IF_NULL(ssn); - StreamTcpSessionCleanup(ssn); - SCFree(ssn); - f->protoctx = NULL; - return 1; -} - -/** - * \brief UTHGenericTest: function that perform a generic check taking care of - * as maximum common unittest elements as possible. - * It will create a detection engine, append an array - * of signatures an check the expected results for each - * of them, it check matches for an array of packets - * - * \param pkt pointer to the array of packets - * \param numpkts number of packets to match - * \param sigs array of char* pointing to signatures to load - * \param numsigs number of signatures to load and check - * \param results pointer to arrays of numbers, each of them foreach packet - * to check if sids matches that packet as expected with - * that number of times or not. The size of results should be - * numpkts * numsigs * sizeof(uint16_t *) - * - * Example: - * result[1][3] would mean the number of times the pkt[1] - * match the sid[3] - * - * \retval int 1 if the match of all the sids is the specified has the - * specified results; 0 if not - */ -int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs) -{ - - int result = 0; - if (pkt == NULL || sigs == NULL || numpkts == 0 - || sids == NULL || results == NULL || numsigs == 0) { - SCLogError("Arguments invalid, that the pointer/arrays are not NULL, and the number of " - "signatures and packets is > 0"); - goto end; - } - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0) - goto cleanup; - - result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs); - -cleanup: - DetectEngineCtxFree(de_ctx); -end: - return result; -} - -/** - * \brief UTHCheckPacketMatches: function to check if a packet match some sids - * - * - * \param p pointer to the Packet - * \param sigs array of char* pointing to signatures to load - * \param numsigs number of signatures to load from the array - * \param results pointer to an array of numbers to check if sids matches - * that number of times or not. - * - * \retval int 1 if the match of all the sids is the specified has the - * specified results; 0 if not - */ -int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs) -{ - if (p == NULL || sids == NULL) { - SCLogError("Arguments invalid, check if the " - "packet is NULL, and if the array contain sids is set"); - return 0; - } - - int i = 0; - int res = 1; - for (; i < numsigs; i++) { - uint32_t r = PacketAlertCheck(p, sids[i]); - if (r != results[i]) { - SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, and not %" PRIu32 " as expected", - sids[i], r, results[i]); - res = 0; - } else { - SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, as expected", sids[i], r); - } - } - return res; -} - -/** - * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors - * - * \param de_ctx pointer to the DetectEngineCtx used - * \param sigs array of char* pointing to signatures to load - * \param numsigs number of signatures to load from the array - * (size of the array) - * - * \retval int 0 if we have errors; 1 if all the signatures loaded successfully - */ -int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs) -{ - BUG_ON(de_ctx == NULL); - BUG_ON(numsigs <= 0); - BUG_ON(sigs == NULL); - - for (int i = 0; i < numsigs; i++) { - if (sigs[i] == NULL) { - SCLogError("Check the signature" - " at position %d", - i); - return 0; - } - Signature *s = DetectEngineAppendSig(de_ctx, sigs[i]); - if (s == NULL) { - SCLogError("Check the signature at" - " position %d (%s)", - i, sigs[i]); - return 0; - } - } - return 1; -} - -/** - * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs - * of a de_ctx, checking that each signature matches X times for certain packets - * - * \param de_ctx pointer with the signatures loaded - * \param p pointer to the array of packets - * \param num_packets number of packets in the array - * - * \retval return 1 if all goes well - * \retval return 0 if something fail - */ -int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs) -{ - BUG_ON(de_ctx == NULL); - BUG_ON(p == NULL); - - int result = 0; - DecodeThreadVars dtv; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - for (int i = 0; i < num_packets; i++) { - SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); - if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0) - goto cleanup; - } - - result = 1; -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - return result; -} - -/** - * \test UTHMatchPackets Match a packet or a array of packets against sigs - * of a de_ctx, but note that the return value doesn't mean that we have a - * match, we have to check it later with PacketAlertCheck() - * - * \param de_ctx pointer with the signatures loaded - * \param p pointer to the array of packets - * \param num_packets number of packets in the array - * - * \retval return 1 if all goes well - * \retval return 0 if something fail - */ -int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets) -{ - BUG_ON(de_ctx == NULL); - BUG_ON(p == NULL); - int result = 1; - DecodeThreadVars dtv; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - SCSigRegisterSignatureOrderingFuncs(de_ctx); - SCSigOrderSignatures(de_ctx); - SCSigSignatureOrderingModuleCleanup(de_ctx); - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - for (int i = 0; i < num_packets; i++) - SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); - - /* Here we don't check if the packet matched or not, because - * the de_ctx can have multiple signatures, and some of them may match - * and others may not. That check will be outside - */ - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - if (de_ctx != NULL) SigGroupCleanup(de_ctx); - return result; -} - -/** - * \test Test if a packet match a signature given as string and a mpm_type - * Hint: Useful for unittests with only one packet and one signature - * - * \param sig pointer to the string signature to test - * \param sid sid number of the signature - * - * \retval return 1 if match - * \retval return 0 if not - */ -int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type) -{ - SCEnter(); - - int result = 0; - - DecodeThreadVars dtv; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx == NULL: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - de_ctx->mpm_matcher = mpm_type; - - de_ctx->sig_list = SigInit(de_ctx, sig); - if (de_ctx->sig_list == NULL) { - printf("signature == NULL: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) { - printf("signature didn't alert: "); - goto end; - } - - result = 1; -end: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - SCReturnInt(result); -} - -/** - * \test Test if a packet match a signature given as string - * Hint: Useful for unittests with only one packet and one signature - * - * \param sig pointer to the string signature to test - * \param sid sid number of the signature - * - * \retval return 1 if match - * \retval return 0 if not - */ -int UTHPacketMatchSig(Packet *p, const char *sig) -{ - int result = 1; - - DecodeThreadVars dtv; - - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result=0; - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) { - result = 0; - goto end; - } - -end: - if (de_ctx) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - return result; -} - -uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir) -{ - FlowLookupStruct fls; - memset(&fls, 0, sizeof(fls)); - - uint32_t i = start; - uint8_t payload[] = "Payload"; - for (; i < end; i++) { - Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); - if (dir == 0) { - p->src.addr_data32[0] = i; - p->dst.addr_data32[0] = i + 1; - } else { - p->src.addr_data32[0] = i + 1; - p->dst.addr_data32[0] = i; - } - FlowHandlePacket(NULL, &fls, p); - if (p->flow != NULL) { - FLOWLOCK_UNLOCK(p->flow); - } - - /* Now the queues should be updated */ - UTHFreePacket(p); - } - - Flow *f; - while ((f = FlowQueuePrivateGetFromTop(&fls.spare_queue))) { - FlowFree(f); - } - while ((f = FlowQueuePrivateGetFromTop(&fls.work_queue))) { - FlowFree(f); - } - - return i; -} - -/** \brief parser a sig and see if the expected result is correct */ -int UTHParseSignature(const char *str, bool expect) -{ - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - - Signature *s = DetectEngineAppendSig(de_ctx, str); - if (expect) - FAIL_IF_NULL(s); - else - FAIL_IF_NOT_NULL(s); - - DetectEngineCtxFree(de_ctx); - PASS; -} - -/* - * unittests for the unittest helpers - */ - -/** - * \brief CheckUTHTestPacket wrapper to check packets for unittests - */ -static int CheckUTHTestPacket(Packet *p, uint8_t ipproto) -{ - uint16_t sport = 41424; - uint16_t dport = 80; - uint8_t payload[] = "Payload"; - - uint8_t len = sizeof(payload); - - if (p == NULL) - return 0; - - if (p->payload_len != len) - return 0; - - if (strncmp((char *)payload, (char *)p->payload, len) != 0) - return 0; - - if (p->src.family != AF_INET) - return 0; - if (p->dst.family != AF_INET) - return 0; - if (p->proto != ipproto) - return 0; - - switch(ipproto) { - case IPPROTO_UDP: - if (p->udph == NULL) - return 0; - if (p->udph->uh_sport != sport) - return 0; - if (p->udph->uh_dport != dport) - return 0; - break; - case IPPROTO_TCP: - if (p->tcph == NULL) - return 0; - if (SCNtohs(p->tcph->th_sport) != sport) - return 0; - if (SCNtohs(p->tcph->th_dport) != dport) - return 0; - break; - } - return 1; -} - -#ifdef HAVE_MEMMEM -#include -void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) { - return memmem(big, big_len, little, little_len); -} -#else -#include "util-spm-bs.h" -void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) { - return BasicSearch(big, big_len, little, little_len); -} -#endif //HAVE_MEMMEM - -/** - * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests - */ -static int UTHBuildPacketRealTest01(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", 41424, 80); - - int ret = CheckUTHTestPacket(p, IPPROTO_TCP); - UTHFreePacket(p); - - return ret; -} - -/** - * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests - */ -static int UTHBuildPacketRealTest02(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", 41424, 80); - - int ret = CheckUTHTestPacket(p, IPPROTO_UDP); - UTHFreePacket(p); - return ret; -} - -/** - * \brief UTHBuildPacketTest01 wrapper to check packets for unittests - */ -static int UTHBuildPacketTest01(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); - - int ret = CheckUTHTestPacket(p, IPPROTO_TCP); - UTHFreePacket(p); - - return ret; -} - -/** - * \brief UTHBuildPacketTest02 wrapper to check packets for unittests - */ -static int UTHBuildPacketTest02(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP); - - int ret = CheckUTHTestPacket(p, IPPROTO_UDP); - UTHFreePacket(p); - - return ret; -} - -/** - * \brief UTHBuildPacketOfFlowsTest01 wrapper to check packets for unittests - */ -static int UTHBuildPacketOfFlowsTest01(void) -{ - int result = 0; - - FlowInitConfig(FLOW_QUIET); - uint32_t flow_spare_q_len = FlowSpareGetPoolSize(); - - UTHBuildPacketOfFlows(0, 100, 0); - - if (FlowSpareGetPoolSize() != flow_spare_q_len - 100) - result = 0; - else - result = 1; - FlowShutdown(); - - return result; -} - - -/** - * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests - */ -static int UTHBuildPacketSrcDstTest01(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1"); - - int ret = CheckUTHTestPacket(p, IPPROTO_TCP); - UTHFreePacket(p); - - return ret; -} - -/** - * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests - */ -static int UTHBuildPacketSrcDstTest02(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1"); - - int ret = CheckUTHTestPacket(p, IPPROTO_UDP); - UTHFreePacket(p); - - return ret; -} - -/** - * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests - */ -static int UTHBuildPacketSrcDstPortsTest01(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP, - 41424, 80); - - int ret = CheckUTHTestPacket(p, IPPROTO_TCP); - UTHFreePacket(p); - - return ret; -} - -/** - * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests - */ -static int UTHBuildPacketSrcDstPortsTest02(void) -{ - uint8_t payload[] = "Payload"; - - Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP, - 41424, 80); - - int ret = CheckUTHTestPacket(p, IPPROTO_UDP); - UTHFreePacket(p); - - return ret; -} - -#endif /* UNITTESTS */ - -void UTHRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01); - UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02); - UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01); - UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02); - UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01); - UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02); - UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", - UTHBuildPacketSrcDstPortsTest01); - UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", - UTHBuildPacketSrcDstPortsTest02); - UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01); - -#endif /* UNITTESTS */ -} - diff --git a/src/util-unittest-helper.h b/src/util-unittest-helper.h deleted file mode 100644 index b3b6d18aa4b0..000000000000 --- a/src/util-unittest-helper.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Pablo Rincon Crespo - */ - -#ifndef __UTIL_UNITTEST_HELPER__ -#define __UTIL_UNITTEST_HELPER__ - -#if defined(UNITTESTS) -#include "flow.h" -#include "detect.h" -#elif defined(FUZZ) -#include "flow.h" -#endif - -#if defined(UNITTESTS) || defined(FUZZ) -Flow *TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp); -int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size); -#endif -#ifdef UNITTESTS -uint32_t UTHSetIPv4Address(const char *); - -Packet *UTHBuildPacketReal(uint8_t *, uint16_t, uint8_t ipproto, const char *, const char *, uint16_t, uint16_t); -Packet *UTHBuildPacket(uint8_t *, uint16_t, uint8_t ipproto); -Packet *UTHBuildPacketSrcDst(uint8_t *, uint16_t, uint8_t ipproto, const char *, const char *); -Packet *UTHBuildPacketSrcDstPorts(uint8_t *, uint16_t, uint8_t ipproto, uint16_t, uint16_t); - -Packet *UTHBuildPacketIPV6SrcDst(uint8_t *, uint16_t, uint8_t ipproto, const char *, const char *); - -int UTHPacketMatchSigMpm(Packet *, char *, uint16_t); -Packet **UTHBuildPacketArrayFromEth(uint8_t **, int *, int); -Packet *UTHBuildPacketFromEth(uint8_t *, uint16_t); - -void UTHFreePacket(Packet *); -void UTHFreePackets(Packet **, int); - -void UTHAssignFlow(Packet *p, Flow *f); -Flow *UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp); -void UTHFreeFlow(Flow *flow); -int UTHAddStreamToFlow(Flow *f, int direction, uint8_t *data, uint32_t data_len); -int UTHAddSessionToFlow(Flow *f, uint32_t ts_isn, uint32_t tc_isn); -int UTHRemoveSessionFromFlow(Flow *f); - -int UTHAppendSigs(DetectEngineCtx *, const char **, int); -int UTHMatchPackets(DetectEngineCtx *, Packet **, int); -int UTHPacketMatchSig(Packet *p, const char *); -int UTHCheckPacketMatch(Packet *, uint32_t *, uint32_t *, int); - -int UTHCheckPacketMatchResults(Packet *, uint32_t *, uint32_t *, int); -int UTHMatchPacketsWithResults(DetectEngineCtx *, Packet **, int, uint32_t *, uint32_t *, int); -int UTHGenericTest(Packet **, int, const char **, uint32_t *, uint32_t *, int); - -uint32_t UTHBuildPacketOfFlows(uint32_t, uint32_t, uint8_t); -Packet *UTHBuildPacketIPV6Real(uint8_t *, uint16_t , uint8_t ipproto, const char *, const char *, - uint16_t , uint16_t ); - -void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len); -int UTHParseSignature(const char *str, bool expect); -#endif - -void UTHRegisterTests(void); - -#endif /* __UTIL_UNITTEST_HELPER__ */ diff --git a/src/util-unittest.c b/src/util-unittest.c deleted file mode 100644 index d4ef5dc99c76..000000000000 --- a/src/util-unittest.c +++ /dev/null @@ -1,345 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Breno Silva - * - * Unit test framework - */ - -/** - * \defgroup Testing Testing - * - * \brief Unit testing support functions. - * - * @{ - */ - -#include "suricata-common.h" -#include "runmodes.h" -#include "util-unittest.h" -#include "util-debug.h" -#include "util-time.h" -#include "conf.h" - -#include "stream-tcp.h" -#include "stream-tcp-reassemble.h" - -#ifdef UNITTESTS - -static pcre2_code *parse_regex; -static pcre2_match_data *parse_regex_match; - -static UtTest *ut_list; - -int unittests_fatal = 0; - -/** - * \brief Allocate UtTest list member - * - * \retval ut Pointer to UtTest - */ - -static UtTest *UtAllocTest(void) -{ - UtTest *ut = SCMalloc(sizeof(UtTest)); - if (unlikely(ut == NULL)) - return NULL; - - memset(ut, 0, sizeof(UtTest)); - - return ut; -} - -/** - * \brief Append test in UtTest list - * - * \param list Pointer to the start of the IP packet - * \param test Pointer to unit test - * - * \retval 0 Function always returns zero - */ - -static int UtAppendTest(UtTest **list, UtTest *test) -{ - if (*list == NULL) { - *list = test; - } else { - UtTest *tmp = *list; - - while (tmp->next != NULL) { - tmp = tmp->next; - } - tmp->next = test; - } - - return 0; -} - -/** - * \brief Register unit test - * - * \param name Unit test name - * \param TestFn Unit test function - */ - -void UtRegisterTest(const char *name, int(*TestFn)(void)) -{ - UtTest *ut = UtAllocTest(); - if (ut == NULL) - return; - - ut->name = name; - ut->TestFn = TestFn; - ut->next = NULL; - - /* append */ - UtAppendTest(&ut_list, ut); -} - -/** - * \brief Compile a regex to run a specific unit test - * - * \param regex_arg The regular expression - * - * \retval 1 Regex compiled - * \retval -1 Regex error - */ -static int UtRegex (const char *regex_arg) -{ - int en; - PCRE2_SIZE eo; - int opts = PCRE2_CASELESS; - - if(regex_arg == NULL) - return -1; - - parse_regex = - pcre2_compile((PCRE2_SPTR8)regex_arg, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); - if(parse_regex == NULL) - { - PCRE2_UCHAR errbuffer[256]; - pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); - SCLogError("pcre2 compile of \"%s\" failed at " - "offset %d: %s", - regex_arg, (int)eo, errbuffer); - goto error; - } - parse_regex_match = pcre2_match_data_create_from_pattern(parse_regex, NULL); - - return 1; - -error: - return -1; -} - -/** \brief List all registered unit tests. - * - * \param regex_arg Regular expression to limit listed tests. - */ -void UtListTests(const char *regex_arg) -{ - UtTest *ut; - int ret = 0, rcomp = 0; - - rcomp = UtRegex(regex_arg); - - for (ut = ut_list; ut != NULL; ut = ut->next) { - if (rcomp == 1) { - ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0, - parse_regex_match, NULL); - if (ret >= 1) { - printf("%s\n", ut->name); - } - } - else { - printf("%s\n", ut->name); - } - } - pcre2_code_free(parse_regex); - pcre2_match_data_free(parse_regex_match); -} - -/** \brief Run all registered unittests. - * - * \param regex_arg The regular expression - * - * \retval 0 all successful - * \retval result number of tests that failed - */ - -uint32_t UtRunTests(const char *regex_arg) -{ - UtTest *ut; - uint32_t good = 0, bad = 0, matchcnt = 0; - int ret = 0, rcomp = 0; - - StreamTcpInitMemuse(); - StreamTcpReassembleInitMemuse(); - - rcomp = UtRegex(regex_arg); - - if(rcomp == 1){ - for (ut = ut_list; ut != NULL; ut = ut->next) { - ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0, - parse_regex_match, NULL); - if( ret >= 1 ) { - printf("Test %-60.60s : ", ut->name); - matchcnt++; - fflush(stdout); /* flush so in case of a segv we see the testname */ - - /* reset the time */ - TimeModeSetOffline(); - TimeSetToCurrentTime(); - - ret = ut->TestFn(); - - if (StreamTcpMemuseCounter() != 0) { - printf("STREAM MEMORY IN USE %"PRIu64"\n", StreamTcpMemuseCounter()); - ret = 0; - } - if (FlowGetMemuse() != 0) { - printf("FLOW MEMORY IN USE %"PRIu64"\n", FlowGetMemuse()); - ret = 0; - } - - if (StreamTcpReassembleMemuseGlobalCounter() != 0) { - printf("STREAM REASSEMBLY MEMORY IN USE %"PRIu64"\n", StreamTcpReassembleMemuseGlobalCounter()); - ret = 0; - } - - printf("%s\n", ret ? "pass" : "FAILED"); - - if (!ret) { - if (unittests_fatal == 1) { - fprintf(stderr, "ERROR: unittest failed.\n"); - exit(EXIT_FAILURE); - } - bad++; - } else { - good++; - } - } - } - if(matchcnt > 0){ - printf("==== TEST RESULTS ====\n"); - printf("PASSED: %" PRIu32 "\n", good); - printf("FAILED: %" PRIu32 "\n", bad); - printf("======================\n"); - } else { - SCLogInfo("UtRunTests: regex provided regex_arg: %s did not match any tests",regex_arg); - } - } else { - SCLogInfo("UtRunTests: pcre compilation failed"); - } - pcre2_code_free(parse_regex); - pcre2_match_data_free(parse_regex_match); - return bad; -} -/** - * \brief Initialize unit test list - */ - -void UtInitialize(void) -{ - ut_list = NULL; -} - -/** - * \brief Cleanup unit test list - */ - -void UtCleanup(void) -{ - - UtTest *tmp = ut_list, *otmp; - - while (tmp != NULL) { - otmp = tmp->next; - SCFree(tmp); - tmp = otmp; - } - - ut_list = NULL; -} - -void UtRunModeRegister(void) -{ - RunModeRegisterNewRunMode(RUNMODE_UNITTEST, "unittest", "Unittest mode", NULL, NULL); - - return; -} - -/* - * unittests for the unittests code - */ - -/** \brief True test - * - * \retval 1 True - * \retval 0 False - */ -static int UtSelftestTrue(void) -{ - if (1)return 1; - else return 0; -} - -/** \brief False test - * - * \retval 1 False - * \retval 0 True - */ -static int UtSelftestFalse(void) -{ - if (0)return 0; - else return 1; -} - -/** \brief Run self tests - * - * \param regex_arg The regular expression - * - * \retval 0 all successful - */ - -int UtRunSelftest (const char *regex_arg) -{ - printf("* Running Unittesting subsystem selftests...\n"); - - UtInitialize(); - - UtRegisterTest("true", UtSelftestTrue); - UtRegisterTest("false", UtSelftestFalse); - - int ret = UtRunTests(regex_arg); - if (ret == 0) - printf("* Done running Unittesting subsystem selftests...\n"); - else - printf("* ERROR running Unittesting subsystem selftests failed...\n"); - - UtCleanup(); - return 0; -} -#endif /* UNITTESTS */ - -/** - * @} - */ diff --git a/src/util-unittest.h b/src/util-unittest.h deleted file mode 100644 index 80d666304da3..000000000000 --- a/src/util-unittest.h +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * \author Breno Silva - * - * Unit test framework - */ - -/** - * \addtogroup Testing - * - * @{ - */ - -#ifndef __UTIL_UNITTEST_H__ -#define __UTIL_UNITTEST_H__ - -#ifdef UNITTESTS - -typedef struct UtTest_ -{ - const char *name; - int(*TestFn)(void); - - struct UtTest_ *next; - -} UtTest; - -void UtRegisterTest(const char *name, int(*TestFn)(void)); -uint32_t UtRunTests(const char *regex_arg); -void UtInitialize(void); -void UtCleanup(void); -int UtRunSelftest (const char *regex_arg); -void UtListTests(const char *regex_arg); -void UtRunModeRegister(void); - -extern int unittests_fatal; - -/** - * \brief Fail a test. - */ -#define FAIL do { \ - if (unittests_fatal) { \ - BUG_ON(1); \ - } else { \ - return 0; \ - } \ - } while (0) - -/** - * \brief Fail a test if expression evaluates to true. - */ -#define FAIL_IF(expr) do { \ - if (unittests_fatal) { \ - BUG_ON(expr); \ - } else if (expr) { \ - return 0; \ - } \ - } while (0) - -/** - * \brief Fail a test if expression evaluates to false. - */ -#define FAIL_IF_NOT(expr) do { \ - FAIL_IF(!(expr)); \ - } while (0) - -/** - * \brief Fail a test if expression evaluates to NULL. - */ -#define FAIL_IF_NULL(expr) do { \ - FAIL_IF(NULL == expr); \ - } while (0) - -/** - * \brief Fail a test if expression evaluates to non-NULL. - */ -#define FAIL_IF_NOT_NULL(expr) do { \ - FAIL_IF(NULL != expr); \ - } while (0) - -/** - * \brief Pass the test. - * - * Only to be used at the end of a function instead of "return 1." - */ -#define PASS do { \ - return 1; \ - } while (0) - -#endif - -#endif /* __UTIL_UNITTEST_H__ */ - -/** - * @} - */ diff --git a/src/util-validate.h b/src/util-validate.h deleted file mode 100644 index c0dac20b78be..000000000000 --- a/src/util-validate.h +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Functions & Macro's for validation of data structures. This is used for - * code correctness. - * - * These will abort() the program if they fail, so they should _only_ be - * used for testing. - */ - - -#ifndef __UTIL_VALIDATE_H__ -#define __UTIL_VALIDATE_H__ - -#ifdef DEBUG_VALIDATION - -/** \brief test if a flow is locked. - * - * If trylock returns 0 it got a lock. Which means - * the flow was previously unlocked. - */ -#define DEBUG_ASSERT_FLOW_LOCKED(f) do { \ - if ((f) != NULL) { \ - int r = SCMutexTrylock(&(f)->m); \ - if (r == 0) { \ - BUG_ON(1); \ - } \ - } \ -} while(0) - -/** \brief validate the integrity of the flow - * - * BUG_ON's on problems - */ -#define DEBUG_VALIDATE_FLOW(f) do { \ - if ((f) != NULL) { \ - BUG_ON((f)->flags & FLOW_IPV4 && \ - (f)->flags & FLOW_IPV6); \ - if ((f)->proto == IPPROTO_TCP) { \ - BUG_ON((f)->alstate != NULL && \ - (f)->alparser == NULL); \ - } \ - } \ -} while(0) - -/** \brief validate the integrity of the packet - * - * BUG_ON's on problems - */ -#define DEBUG_VALIDATE_PACKET(p) do { \ - if ((p) != NULL) { \ - if ((p)->flow != NULL) { \ - DEBUG_VALIDATE_FLOW((p)->flow); \ - } \ - if (!((p)->flags & (PKT_IS_FRAGMENT|PKT_IS_INVALID))) { \ - if ((p)->proto == IPPROTO_TCP) { \ - BUG_ON((p)->tcph == NULL); \ - } else if ((p)->proto == IPPROTO_UDP) { \ - BUG_ON((p)->udph == NULL); \ - } else if ((p)->proto == IPPROTO_ICMP) { \ - BUG_ON((p)->icmpv4h == NULL); \ - } else if ((p)->proto == IPPROTO_SCTP) { \ - BUG_ON((p)->sctph == NULL); \ - } else if ((p)->proto == IPPROTO_ICMPV6) { \ - BUG_ON((p)->icmpv6h == NULL); \ - } \ - } \ - if ((p)->payload_len > 0) { \ - BUG_ON((p)->payload == NULL); \ - } \ - BUG_ON((p)->ip4h != NULL && (p)->ip6h != NULL); \ - BUG_ON((p)->flowflags != 0 && (p)->flow == NULL); \ - BUG_ON((p)->flowflags & FLOW_PKT_TOSERVER &&\ - (p)->flowflags & FLOW_PKT_TOCLIENT); \ - } \ -} while(0) - -#define DEBUG_VALIDATE_BUG_ON(exp) BUG_ON((exp)) - -#else /* DEBUG_VALIDATE */ - -#define DEBUG_ASSERT_FLOW_LOCKED(f) -#define DEBUG_VALIDATE_FLOW(f) -#define DEBUG_VALIDATE_PACKET(p) -#define DEBUG_VALIDATE_BUG_ON(exp) - -#endif /* DEBUG_VALIDATE */ - -#endif /* __UTIL_VALIDATE_H__ */ - diff --git a/src/util-var-name.c b/src/util-var-name.c deleted file mode 100644 index b0a88bface59..000000000000 --- a/src/util-var-name.c +++ /dev/null @@ -1,375 +0,0 @@ -/* Copyright (C) 2007-2023 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Generic variable name utility functions - */ - -#include "suricata-common.h" -#include "detect.h" -#include "util-hash-string.h" -#include "util-hashlist.h" -#include "util-var-name.h" -#include "util-validate.h" - -/* Overall Design: - * - * Base Store: "base" - * - * Used during keyword registration. Operates under lock. Base is shared - * between all detect engines, detect engine versions and tenants. - * Each variable name is ref counted. - * - * During the freeing of a detect engine / tenant, unregistration decreases - * the ref cnt. - * - * Base has both a string to id and a id to string hash table. String to - * id is used during parsing/registration. id to string during unregistration. - * - * - * Active Store Pointer (atomic) - * - * The "active" store atomic pointer points to the active store. The call - * to `VarNameStoreActivate` will build a new lookup store and hot swap - * the pointer. - * - * Ensuring memory safety. During the hot swap, the pointer is replaced, so - * any new call to the lookup functions will automatically use the new store. - * This leaves the case of any lookup happening concurrently with the pointer - * swap. For this case we add the old store to a free list. It gets a timestamp - * before which it cannot be freed. - * - * - * Free List - * - * The free list contains old stores that are waiting to get removed. They - * contain a timestamp that is checked before they are freed. - * - */ -typedef struct VarNameStore_ { - HashListTable *names; - HashListTable *ids; - uint32_t max_id; - struct timeval free_after; - TAILQ_ENTRY(VarNameStore_) next; -} VarNameStore; -typedef VarNameStore *VarNameStorePtr; - -/** \brief Name2idx mapping structure for flowbits, flowvars and pktvars. */ -typedef struct VariableName_ { - char *name; - enum VarTypes type; /* flowbit, pktvar, etc */ - uint32_t id; - uint32_t ref_cnt; -} VariableName; - -#define VARNAME_HASHSIZE 0x1000 -#define VARID_HASHSIZE 0x1000 - -static SCMutex base_lock = SCMUTEX_INITIALIZER; -static VarNameStore base = { .names = NULL, .ids = NULL, .max_id = 0 }; -static TAILQ_HEAD(, VarNameStore_) free_list = TAILQ_HEAD_INITIALIZER(free_list); -static SC_ATOMIC_DECLARE(VarNameStorePtr, active); - -static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen); -static char VariableNameCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2); -static uint32_t VariableIdHash(HashListTable *ht, void *ptr, uint16_t _unused); -static char VariableIdCompare(void *ptr1, uint16_t _unused1, void *ptr2, uint16_t _unused2); -static void VariableNameFree(void *data); - -void VarNameStoreInit(void) -{ - SCMutexLock(&base_lock); - base.names = HashListTableInit( - VARNAME_HASHSIZE, VariableNameHash, VariableNameCompare, VariableNameFree); - if (base.names == NULL) { - FatalError("failed to initialize variable name hash (names)"); - } - - /* base.names owns the allocation, so use a NULL Free pointer here */ - base.ids = HashListTableInit(VARID_HASHSIZE, VariableIdHash, VariableIdCompare, NULL); - if (base.ids == NULL) { - FatalError("failed to initialize variable name hash (names)"); - } - SC_ATOMIC_INITPTR(active); - SCMutexUnlock(&base_lock); -} - -void VarNameStoreDestroy(void) -{ - SCMutexLock(&base_lock); - VarNameStore *s = SC_ATOMIC_GET(active); - if (s) { - HashListTableFree(s->names); - HashListTableFree(s->ids); - SCFree(s); - s = NULL; - } - SC_ATOMIC_SET(active, NULL); - - while ((s = TAILQ_FIRST(&free_list))) { - TAILQ_REMOVE(&free_list, s, next); - HashListTableFree(s->names); - HashListTableFree(s->ids); - SCFree(s); - } - - for (HashListTableBucket *b = HashListTableGetListHead(base.names); b != NULL; - b = HashListTableGetListNext(b)) { - VariableName *vn = HashListTableGetListData(b); - DEBUG_VALIDATE_BUG_ON(vn->ref_cnt > 0); - if (vn->ref_cnt > 0) { - SCLogWarning("%s (type %u, id %u) still has ref_cnt %u", vn->name, vn->type, vn->id, - vn->ref_cnt); - } - } - HashListTableFree(base.ids); - base.ids = NULL; - HashListTableFree(base.names); - base.names = NULL; - base.max_id = 0; - SCMutexUnlock(&base_lock); -} - -/** - * \retval id or 0 on error - */ -uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type) -{ - SCMutexLock(&base_lock); - uint32_t id = 0; - - SCLogDebug("registering: name %s type %u", name, type); - VariableName lookup = { .type = type, .name = (char *)name }; - VariableName *found = (VariableName *)HashListTableLookup(base.names, (void *)&lookup, 0); - if (found == NULL) { - VariableName *vn = SCCalloc(1, sizeof(VariableName)); - if (likely(vn != NULL)) { - vn->type = type; - vn->name = SCStrdup(name); - if (vn->name != NULL) { - vn->ref_cnt = 1; - id = vn->id = ++base.max_id; - HashListTableAdd(base.names, (void *)vn, 0); - HashListTableAdd(base.ids, (void *)vn, 0); - SCLogDebug( - "new registration %s id %u type %u -> %u", vn->name, vn->id, vn->type, id); - } else { - SCFree(vn); - } - } - } else { - id = found->id; - found->ref_cnt++; - SCLogDebug("existing registration %s ref_cnt %u -> %u", name, found->ref_cnt, id); - } - SCMutexUnlock(&base_lock); - return id; -} - -const char *VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type) -{ - const char *name = NULL; - SCMutexLock(&base_lock); - VariableName lookup = { .type = type, .id = id }; - VariableName *found = (VariableName *)HashListTableLookup(base.ids, (void *)&lookup, 0); - if (found) { - name = found->name; - } - SCMutexUnlock(&base_lock); - return name; -} - -void VarNameStoreUnregister(const uint32_t id, const enum VarTypes type) -{ - SCMutexLock(&base_lock); - VariableName lookup = { .type = type, .id = id }; - VariableName *found = (VariableName *)HashListTableLookup(base.ids, (void *)&lookup, 0); - if (found) { - SCLogDebug("found %s ref_cnt %u", found->name, found->ref_cnt); - DEBUG_VALIDATE_BUG_ON(found->ref_cnt == 0); - found->ref_cnt--; - } - SCMutexUnlock(&base_lock); -} - -int VarNameStoreActivate(void) -{ - int result = 0; - SCMutexLock(&base_lock); - SCLogDebug("activating new lookup store"); - - VarNameStore *new_active = NULL; - - // create lookup hash for id to string, strings should point to base - for (HashListTableBucket *b = HashListTableGetListHead(base.names); b != NULL; - b = HashListTableGetListNext(b)) { - VariableName *vn = HashListTableGetListData(b); - BUG_ON(vn == NULL); - SCLogDebug("base: %s/%u/%u", vn->name, vn->id, vn->ref_cnt); - if (vn->ref_cnt == 0) - continue; - - if (new_active == NULL) { - new_active = SCCalloc(1, sizeof(*new_active)); - if (new_active == NULL) { - result = -1; - goto out; - } - - new_active->names = HashListTableInit( - VARNAME_HASHSIZE, VariableNameHash, VariableNameCompare, NULL); - if (new_active->names == NULL) { - SCFree(new_active); - result = -1; - goto out; - } - new_active->ids = - HashListTableInit(VARID_HASHSIZE, VariableIdHash, VariableIdCompare, NULL); - if (new_active->ids == NULL) { - HashListTableFree(new_active->names); - SCFree(new_active); - result = -1; - goto out; - } - } - - /* memory is still owned by "base" */ - HashListTableAdd(new_active->names, (void *)vn, 0); - HashListTableAdd(new_active->ids, (void *)vn, 0); - } - - if (new_active) { - VarNameStore *old_active = SC_ATOMIC_GET(active); - if (old_active) { - struct timeval ts, add; - memset(&ts, 0, sizeof(ts)); - memset(&add, 0, sizeof(add)); - gettimeofday(&ts, NULL); - add.tv_sec = 60; - timeradd(&ts, &add, &ts); - old_active->free_after = ts; - - TAILQ_INSERT_TAIL(&free_list, old_active, next); - SCLogDebug("old active is stored in free list"); - } - - SC_ATOMIC_SET(active, new_active); - SCLogDebug("new store active"); - - struct timeval now; - memset(&now, 0, sizeof(now)); - gettimeofday(&now, NULL); - - VarNameStore *s = NULL; - while ((s = TAILQ_FIRST(&free_list))) { - char timebuf[64]; - CreateIsoTimeString(SCTIME_FROM_TIMEVAL(&s->free_after), timebuf, sizeof(timebuf)); - - if (!timercmp(&now, &s->free_after, >)) { - SCLogDebug("not yet freeing store %p before %s", s, timebuf); - break; - } - SCLogDebug("freeing store %p with time %s", s, timebuf); - TAILQ_REMOVE(&free_list, s, next); - HashListTableFree(s->names); - HashListTableFree(s->ids); - SCFree(s); - } - } -out: - SCLogDebug("activating new lookup store: complete %d", result); - SCMutexUnlock(&base_lock); - return result; -} - -/** \brief find name for id+type at packet time. */ -const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type) -{ - const char *name = NULL; - - const VarNameStore *current = SC_ATOMIC_GET(active); - if (current) { - VariableName lookup = { .type = type, .id = id }; - const VariableName *found = HashListTableLookup(current->ids, (void *)&lookup, 0); - if (found) { - return found->name; - } - } - - return name; -} - -/** \brief find name for id+type at packet time. */ -uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type) -{ - const VarNameStore *current = SC_ATOMIC_GET(active); - if (current) { - VariableName lookup = { .name = (char *)name, .type = type }; - const VariableName *found = HashListTableLookup(current->names, (void *)&lookup, 0); - if (found) { - return found->id; - } - } - - return 0; -} - -static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen) -{ - VariableName *vn = (VariableName *)buf; - uint32_t hash = StringHashDjb2((const uint8_t *)vn->name, strlen(vn->name)) + vn->type; - return (hash % VARNAME_HASHSIZE); -} - -static char VariableNameCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) -{ - VariableName *vn1 = (VariableName *)buf1; - VariableName *vn2 = (VariableName *)buf2; - return (vn1->type == vn2->type && strcmp(vn1->name, vn2->name) == 0); -} - -static uint32_t VariableIdHash(HashListTable *ht, void *ptr, uint16_t _unused) -{ - VariableName *vn = (VariableName *)ptr; - uint32_t hash = vn->id << vn->type; - return (hash % VARID_HASHSIZE); -} - -static char VariableIdCompare(void *ptr1, uint16_t _unused1, void *ptr2, uint16_t _unused2) -{ - VariableName *vn1 = (VariableName *)ptr1; - VariableName *vn2 = (VariableName *)ptr2; - - return (vn1->id == vn2->id && vn1->type == vn2->type); -} - -static void VariableNameFree(void *data) -{ - VariableName *vn = (VariableName *)data; - if (vn == NULL) - return; - if (vn->name != NULL) { - SCFree(vn->name); - vn->name = NULL; - } - SCFree(vn); -} diff --git a/src/util-var-name.h b/src/util-var-name.h deleted file mode 100644 index 5f21ea3fa4ca..000000000000 --- a/src/util-var-name.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_VAR_NAME_H__ -#define __UTIL_VAR_NAME_H__ - -void VarNameStoreInit(void); -void VarNameStoreDestroy(void); - -uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type); -const char *VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type); -void VarNameStoreUnregister(const uint32_t id, const enum VarTypes type); -int VarNameStoreActivate(void); - -const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type); -uint32_t VarNameStoreLookupByName(const char *, const enum VarTypes type); - -#endif - diff --git a/src/util-var.c b/src/util-var.c deleted file mode 100644 index 8a2df63f1fa7..000000000000 --- a/src/util-var.c +++ /dev/null @@ -1,174 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Generic variable utility functions - */ - -#include "suricata-common.h" -#include "detect.h" - -#include "util-var.h" - -#include "flow-var.h" -#include "flow-bit.h" -#include "pkt-var.h" -#include "host-bit.h" -#include "ippair-bit.h" - -#include "util-debug.h" - -void XBitFree(XBit *fb) -{ - if (fb == NULL) - return; - - SCFree(fb); -} - -void GenericVarFree(GenericVar *gv) -{ - if (gv == NULL) - return; - - SCLogDebug("gv %p, gv->type %" PRIu32 "", gv, gv->type); - GenericVar *next_gv = gv->next; - - switch (gv->type) { - case DETECT_FLOWBITS: - { - FlowBit *fb = (FlowBit *)gv; - //printf("GenericVarFree: fb %p, removing\n", fb); - FlowBitFree(fb); - break; - } - case DETECT_XBITS: - { - XBit *fb = (XBit *)gv; - //printf("GenericVarFree: fb %p, removing\n", fb); - XBitFree(fb); - break; - } - case DETECT_FLOWVAR: - { - FlowVar *fv = (FlowVar *)gv; - FlowVarFree(fv); - break; - } - case DETECT_PKTVAR: - { - PktVar *pv = (PktVar *)gv; - PktVarFree(pv); - break; - } - default: - { - printf("ERROR: GenericVarFree unknown type %" PRIu32 "\n", gv->type); - break; - } - } - - GenericVarFree(next_gv); -} - -void GenericVarAppend(GenericVar **list, GenericVar *gv) -{ - gv->next = NULL; - - if (*list == NULL) { - *list = gv; - } else { - GenericVar *tgv = *list; - while(tgv) { - if (tgv->next == NULL) { - tgv->next = gv; - return; - } - - tgv = tgv->next; - } - } -} - -void GenericVarRemove(GenericVar **list, GenericVar *gv) -{ - if (*list == NULL) - return; - - GenericVar *listgv = *list, *prevgv = NULL; - while (listgv != NULL) { - if (listgv == gv) { - if (prevgv == NULL) - *list = gv->next; - else - prevgv->next = gv->next; - - return; - } - - prevgv = listgv; - listgv = listgv->next; - } -} - -// Checks if a variable is already in a resolve list and if it's not, adds it. -int AddVariableToResolveList(ResolvedVariablesList *list, const char *var) -{ - ResolvedVariable *p_item; - - if (list == NULL || var == NULL) - return 0; - - if (var[0] != '$') { - return 0; - } - - TAILQ_FOREACH(p_item, list, next) { - if (!strcmp(p_item->var_name, var)) { - return -1; - } - } - - p_item = SCMalloc(sizeof(ResolvedVariable)); - - if (unlikely(p_item == NULL)) { - return -1; - } - - strlcpy(p_item->var_name, var, sizeof(p_item->var_name) - 1); - TAILQ_INSERT_TAIL(list, p_item, next); - - return 0; -} - -void CleanVariableResolveList(ResolvedVariablesList *var_list) -{ - if (var_list == NULL) { - return; - } - - ResolvedVariable *p_item; - - while ((p_item = TAILQ_FIRST(var_list))) { - TAILQ_REMOVE(var_list, p_item, next); - SCFree(p_item); - } -} diff --git a/src/util-var.h b/src/util-var.h deleted file mode 100644 index ce491ecdcd82..000000000000 --- a/src/util-var.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_VAR_H__ -#define __UTIL_VAR_H__ - -enum VarTypes { - VAR_TYPE_NOT_SET, - - VAR_TYPE_PKT_BIT, - VAR_TYPE_PKT_INT, - VAR_TYPE_PKT_VAR, - VAR_TYPE_PKT_VAR_KV, // key-value - - VAR_TYPE_FLOW_BIT, - VAR_TYPE_FLOW_INT, - VAR_TYPE_FLOW_VAR, - - VAR_TYPE_HOST_BIT, - VAR_TYPE_HOST_INT, - VAR_TYPE_HOST_VAR, - - VAR_TYPE_IPPAIR_BIT, - VAR_TYPE_IPPAIR_INT, - VAR_TYPE_IPPAIR_VAR, -}; - -typedef struct GenericVar_ { - uint8_t type; - uint8_t pad[3]; - uint32_t idx; - struct GenericVar_ *next; -} GenericVar; - -typedef struct XBit_ { - uint8_t type; /* type, DETECT_XBITS in this case */ - uint8_t pad[3]; - uint32_t idx; /* name idx */ - GenericVar *next; - uint32_t expire; -} XBit; - -void XBitFree(XBit *); - -// A list of variables we try to resolve while parsing configuration file. -// Helps to detect recursive declarations. -typedef struct ResolvedVariable_ { - char var_name[256]; - TAILQ_ENTRY(ResolvedVariable_) next; -} ResolvedVariable; - -typedef TAILQ_HEAD(, ResolvedVariable_) ResolvedVariablesList; - -void GenericVarFree(GenericVar *); -void GenericVarAppend(GenericVar **, GenericVar *); -void GenericVarRemove(GenericVar **, GenericVar *); - -int AddVariableToResolveList(ResolvedVariablesList *list, const char *var); -void CleanVariableResolveList(ResolvedVariablesList *var_list); - -#endif /* __UTIL_VAR_H__ */ - diff --git a/src/util/action.c b/src/util/action.c new file mode 100644 index 000000000000..3bf6d2aae220 --- /dev/null +++ b/src/util/action.c @@ -0,0 +1,437 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon + */ + +#include "suricata-common.h" + +#include "action-globals.h" +#include "../conf.h" +#include "conf-yaml-loader.h" + +#include "../detect.h" +#include "detect-engine.h" +#include "detect-engine-sigorder.h" + +#include "util/unittest.h" +#include "util/action.h" +#include "util/unittest-helper.h" +#include "util/debug.h" + +/* Default order: */ +uint8_t action_order_sigs[4] = { ACTION_PASS, ACTION_DROP, ACTION_REJECT, ACTION_ALERT }; +/* This order can be changed from config */ + +/** + * \brief Return the priority associated to an action (to order sigs + * as specified at config) + * action_order_sigs has this priority by index val + * so action_order_sigs[0] has to be inspected first. + * This function is called from detect-engine-sigorder + * \param action can be one of ACTION_PASS, ACTION_DROP, + * ACTION_REJECT or ACTION_ALERT + * \retval uint8_t the priority (order of this actions) + */ +uint8_t ActionOrderVal(uint8_t action) +{ + /* reject_both and reject_dst have the same prio as reject */ + if ((action & ACTION_REJECT) || (action & ACTION_REJECT_BOTH) || (action & ACTION_REJECT_DST)) { + action = ACTION_REJECT; + } + uint8_t i = 0; + for (; i < 4; i++) { + if (action_order_sigs[i] == action) + return i; + } + /* Unknown action, set just a low prio (high val) */ + return 10; +} + +/** + * \brief Return the ACTION_* bit from their ascii value + * \param action can be one of "pass", "drop", + * "reject" or "alert" + * \retval uint8_t can be one of ACTION_PASS, ACTION_DROP, + * ACTION_REJECT or ACTION_ALERT + */ +static uint8_t ActionAsciiToFlag(const char *action) +{ + if (strcmp(action, "pass") == 0) + return ACTION_PASS; + if (strcmp(action, "drop") == 0) + return ACTION_DROP; + if (strcmp(action, "reject") == 0) + return ACTION_REJECT; + if (strcmp(action, "alert") == 0) + return ACTION_ALERT; + + return 0; +} + +/** + * \brief Load the action order from config. If none is provided, + * it will be default to ACTION_PASS, ACTION_DROP, + * ACTION_REJECT, ACTION_ALERT (pass has the highest prio) + * + * \retval 0 on success; -1 on fatal error; + */ +int ActionInitConfig(void) +{ + uint8_t actions_used = 0; + uint8_t action_flag = 0; + uint8_t actions_config[4] = { 0, 0, 0, 0 }; + int order = 0; + + ConfNode *action_order; + ConfNode *action = NULL; + + /* Let's load the order of actions from the general config */ + action_order = ConfGetNode("action-order"); + if (action_order == NULL) { + /* No configuration, use defaults. */ + return 0; + } else { + TAILQ_FOREACH (action, &action_order->head, next) { + SCLogDebug("Loading action order : %s", action->val); + action_flag = ActionAsciiToFlag(action->val); + if (action_flag == 0) { + SCLogError("action-order, invalid action: \"%s\". Please, use" + " \"pass\",\"drop\",\"alert\",\"reject\". You have" + " to specify all of them, without quotes and without" + " capital letters", + action->val); + goto error; + } + + if (actions_used & action_flag) { + SCLogError("action-order, action already set: \"%s\". Please," + " use \"pass\",\"drop\",\"alert\",\"reject\". You" + " have to specify all of them, without quotes and" + " without capital letters", + action->val); + goto error; + } + + if (order >= 4) { + SCLogError("action-order, you have already specified all the " + "possible actions plus \"%s\". Please, use \"pass\"," + "\"drop\",\"alert\",\"reject\". You have to specify" + " all of them, without quotes and without capital" + " letters", + action->val); + goto error; + } + actions_used |= action_flag; + actions_config[order++] = action_flag; + } + } + if (order < 4) { + SCLogError("action-order, the config didn't specify all of the " + "actions. Please, use \"pass\",\"drop\",\"alert\"," + "\"reject\". You have to specify all of them, without" + " quotes and without capital letters"); + goto error; + } + + /* Now, it's a valid config. Override the default preset */ + for (order = 0; order < 4; order++) { + action_order_sigs[order] = actions_config[order]; + } + + return 0; + +error: + return -1; +} + +#ifdef UNITTESTS + +/** + * \test Check that we invalidate duplicated actions + * (It should default to pass, drop, reject, alert) + */ +static int UtilActionTest01(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +action-order:\n\ + - alert\n\ + - drop\n\ + - reject\n\ + - alert\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ActionInitConfig(); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); + ConfRestoreContextBackup(); + + /* Restore default values */ + action_order_sigs[0] = ACTION_PASS; + action_order_sigs[1] = ACTION_DROP; + action_order_sigs[2] = ACTION_REJECT; + action_order_sigs[3] = ACTION_ALERT; + PASS; +} + +/** + * \test Check that we invalidate with unknown keywords + * (It should default to pass, drop, reject, alert) + */ +static int UtilActionTest02(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +action-order:\n\ + - alert\n\ + - drop\n\ + - reject\n\ + - ftw\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ActionInitConfig(); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); + ConfRestoreContextBackup(); + + /* Restore default values */ + action_order_sigs[0] = ACTION_PASS; + action_order_sigs[1] = ACTION_DROP; + action_order_sigs[2] = ACTION_REJECT; + action_order_sigs[3] = ACTION_ALERT; + PASS; +} + +/** + * \test Check that we invalidate if any action is missing + * (It should default to pass, drop, reject, alert) + */ +static int UtilActionTest03(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +action-order:\n\ + - alert\n\ + - drop\n\ + - reject\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ActionInitConfig(); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); + ConfRestoreContextBackup(); + + /* Restore default values */ + action_order_sigs[0] = ACTION_PASS; + action_order_sigs[1] = ACTION_DROP; + action_order_sigs[2] = ACTION_REJECT; + action_order_sigs[3] = ACTION_ALERT; + PASS; +} + +/** + * \test Check that we invalidate if any action is missing + * (It should default to pass, drop, reject, alert) + */ +static int UtilActionTest04(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +action-order:\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ActionInitConfig(); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); + ConfRestoreContextBackup(); + + /* Restore default values */ + action_order_sigs[0] = ACTION_PASS; + action_order_sigs[1] = ACTION_DROP; + action_order_sigs[2] = ACTION_REJECT; + action_order_sigs[3] = ACTION_ALERT; + PASS; +} + +/** + * \test Check that we invalidate with unknown keywords + * and/or more than the expected + * (It should default to pass, drop, reject, alert) + */ +static int UtilActionTest05(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +action-order:\n\ + - alert\n\ + - drop\n\ + - reject\n\ + - pass\n\ + - whatever\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ActionInitConfig(); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); + ConfRestoreContextBackup(); + + /* Restore default values */ + action_order_sigs[0] = ACTION_PASS; + action_order_sigs[1] = ACTION_DROP; + action_order_sigs[2] = ACTION_REJECT; + action_order_sigs[3] = ACTION_ALERT; + PASS; +} + +/** + * \test Check that we load a valid config + */ +static int UtilActionTest06(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +action-order:\n\ + - alert\n\ + - drop\n\ + - reject\n\ + - pass\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ActionInitConfig(); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_ALERT); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_PASS); + ConfRestoreContextBackup(); + + /* Restore default values */ + action_order_sigs[0] = ACTION_PASS; + action_order_sigs[1] = ACTION_DROP; + action_order_sigs[2] = ACTION_REJECT; + action_order_sigs[3] = ACTION_ALERT; + PASS; +} + +/** + * \test Check that we load a valid config + */ +static int UtilActionTest07(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +action-order:\n\ + - pass\n\ + - alert\n\ + - drop\n\ + - reject\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ActionInitConfig(); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_ALERT); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_REJECT); + ConfRestoreContextBackup(); + + /* Restore default values */ + action_order_sigs[0] = ACTION_PASS; + action_order_sigs[1] = ACTION_DROP; + action_order_sigs[2] = ACTION_REJECT; + action_order_sigs[3] = ACTION_ALERT; + PASS; +} + +/** + * \test Check that the expected defaults are loaded if the + * action-order configuration is not present. + */ +static int UtilActionTest08(void) +{ + char config[] = "%YAML 1.1\n" + "---\n"; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + FAIL_IF_NOT(ActionInitConfig() == 0); + FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS); + FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP); + FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT); + FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT); + + ConfRestoreContextBackup(); + PASS; +} + +/* Register unittests */ +void UtilActionRegisterTests(void) +{ + /* Generic tests */ + UtRegisterTest("UtilActionTest01", UtilActionTest01); + UtRegisterTest("UtilActionTest02", UtilActionTest02); + UtRegisterTest("UtilActionTest02", UtilActionTest02); + UtRegisterTest("UtilActionTest03", UtilActionTest03); + UtRegisterTest("UtilActionTest04", UtilActionTest04); + UtRegisterTest("UtilActionTest05", UtilActionTest05); + UtRegisterTest("UtilActionTest06", UtilActionTest06); + UtRegisterTest("UtilActionTest07", UtilActionTest07); + UtRegisterTest("UtilActionTest08", UtilActionTest08); +} +#endif diff --git a/src/util-action.h b/src/util/action.h similarity index 100% rename from src/util-action.h rename to src/util/action.h diff --git a/src/util/affinity.c b/src/util/affinity.c new file mode 100644 index 000000000000..a0f2d427e897 --- /dev/null +++ b/src/util/affinity.c @@ -0,0 +1,362 @@ +/* Copyright (C) 2010-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Eric Leblond + * + * CPU affinity related code and helper. + */ + +#include "suricata-common.h" +#define _THREAD_AFFINITY +#include "util/affinity.h" +#include "../conf.h" +#include "runmodes.h" +#include "util/cpu.h" +#include "util/byte.h" +#include "util/debug.h" + +ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { + { + .name = "receive-cpu-set", + .mode_flag = EXCLUSIVE_AFFINITY, + .prio = PRIO_MEDIUM, + .lcpu = 0, + }, + { + .name = "worker-cpu-set", + .mode_flag = EXCLUSIVE_AFFINITY, + .prio = PRIO_MEDIUM, + .lcpu = 0, + }, + { + .name = "verdict-cpu-set", + .mode_flag = BALANCED_AFFINITY, + .prio = PRIO_MEDIUM, + .lcpu = 0, + }, + { + .name = "management-cpu-set", + .mode_flag = BALANCED_AFFINITY, + .prio = PRIO_MEDIUM, + .lcpu = 0, + }, + +}; + +int thread_affinity_init_done = 0; + +/** + * \brief find affinity by its name + * \retval a pointer to the affinity or NULL if not found + */ +ThreadsAffinityType *GetAffinityTypeFromName(const char *name) +{ + int i; + for (i = 0; i < MAX_CPU_SET; i++) { + if (!strcmp(thread_affinity[i].name, name)) { + return &thread_affinity[i]; + } + } + return NULL; +} + +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun +static void AffinitySetupInit(void) +{ + int i, j; + int ncpu = UtilCpuGetNumProcessorsConfigured(); + + SCLogDebug("Initialize affinity setup\n"); + /* be conservative relatively to OS: use all cpus by default */ + for (i = 0; i < MAX_CPU_SET; i++) { + cpu_set_t *cs = &thread_affinity[i].cpu_set; + CPU_ZERO(cs); + for (j = 0; j < ncpu; j++) { + CPU_SET(j, cs); + } + SCMutexInit(&thread_affinity[i].taf_mutex, NULL); + } + return; +} + +void BuildCpusetWithCallback( + const char *name, ConfNode *node, void (*Callback)(int i, void *data), void *data) +{ + ConfNode *lnode; + TAILQ_FOREACH (lnode, &node->head, next) { + int i; + long int a, b; + int stop = 0; + int max = UtilCpuGetNumProcessorsOnline() - 1; + if (!strcmp(lnode->val, "all")) { + a = 0; + b = max; + stop = 1; + } else if (strchr(lnode->val, '-') != NULL) { + char *sep = strchr(lnode->val, '-'); + char *end; + a = strtoul(lnode->val, &end, 10); + if (end != sep) { + SCLogError("%s: invalid cpu range (start invalid): \"%s\"", name, lnode->val); + exit(EXIT_FAILURE); + } + b = strtol(sep + 1, &end, 10); + if (end != sep + strlen(sep)) { + SCLogError("%s: invalid cpu range (end invalid): \"%s\"", name, lnode->val); + exit(EXIT_FAILURE); + } + if (a > b) { + SCLogError("%s: invalid cpu range (bad order): \"%s\"", name, lnode->val); + exit(EXIT_FAILURE); + } + if (b > max) { + SCLogError("%s: upper bound (%ld) of cpu set is too high, only %d cpu(s)", name, b, + max + 1); + } + } else { + char *end; + a = strtoul(lnode->val, &end, 10); + if (end != lnode->val + strlen(lnode->val)) { + SCLogError("%s: invalid cpu range (not an integer): \"%s\"", name, lnode->val); + exit(EXIT_FAILURE); + } + b = a; + } + for (i = a; i <= b; i++) { + Callback(i, data); + } + if (stop) + break; + } +} + +static void AffinityCallback(int i, void *data) +{ + CPU_SET(i, (cpu_set_t *)data); +} + +static void BuildCpuset(const char *name, ConfNode *node, cpu_set_t *cpu) +{ + BuildCpusetWithCallback(name, node, AffinityCallback, (void *)cpu); +} +#endif /* OS_WIN32 and __OpenBSD__ */ + +/** + * \brief Extract cpu affinity configuration from current config file + */ + +void AffinitySetupLoadFromConfig(void) +{ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun + ConfNode *root = ConfGetNode("threading.cpu-affinity"); + ConfNode *affinity; + + if (thread_affinity_init_done == 0) { + AffinitySetupInit(); + thread_affinity_init_done = 1; + } + + SCLogDebug("Load affinity from config\n"); + if (root == NULL) { + SCLogInfo("can't get cpu-affinity node"); + return; + } + + TAILQ_FOREACH (affinity, &root->head, next) { + if (strcmp(affinity->val, "decode-cpu-set") == 0 || + strcmp(affinity->val, "stream-cpu-set") == 0 || + strcmp(affinity->val, "reject-cpu-set") == 0 || + strcmp(affinity->val, "output-cpu-set") == 0) { + continue; + } + + const char *setname = affinity->val; + if (strcmp(affinity->val, "detect-cpu-set") == 0) + setname = "worker-cpu-set"; + + ThreadsAffinityType *taf = GetAffinityTypeFromName(setname); + ConfNode *node = NULL; + ConfNode *nprio = NULL; + + if (taf == NULL) { + FatalError("unknown cpu-affinity type"); + } else { + SCLogConfig("Found affinity definition for \"%s\"", setname); + } + + CPU_ZERO(&taf->cpu_set); + node = ConfNodeLookupChild(affinity->head.tqh_first, "cpu"); + if (node == NULL) { + SCLogInfo("unable to find 'cpu'"); + } else { + BuildCpuset(setname, node, &taf->cpu_set); + } + + CPU_ZERO(&taf->lowprio_cpu); + CPU_ZERO(&taf->medprio_cpu); + CPU_ZERO(&taf->hiprio_cpu); + nprio = ConfNodeLookupChild(affinity->head.tqh_first, "prio"); + if (nprio != NULL) { + node = ConfNodeLookupChild(nprio, "low"); + if (node == NULL) { + SCLogDebug("unable to find 'low' prio using default value"); + } else { + BuildCpuset(setname, node, &taf->lowprio_cpu); + } + + node = ConfNodeLookupChild(nprio, "medium"); + if (node == NULL) { + SCLogDebug("unable to find 'medium' prio using default value"); + } else { + BuildCpuset(setname, node, &taf->medprio_cpu); + } + + node = ConfNodeLookupChild(nprio, "high"); + if (node == NULL) { + SCLogDebug("unable to find 'high' prio using default value"); + } else { + BuildCpuset(setname, node, &taf->hiprio_cpu); + } + node = ConfNodeLookupChild(nprio, "default"); + if (node != NULL) { + if (!strcmp(node->val, "low")) { + taf->prio = PRIO_LOW; + } else if (!strcmp(node->val, "medium")) { + taf->prio = PRIO_MEDIUM; + } else if (!strcmp(node->val, "high")) { + taf->prio = PRIO_HIGH; + } else { + FatalError("unknown cpu_affinity prio"); + } + SCLogConfig("Using default prio '%s' for set '%s'", node->val, setname); + } + } + + node = ConfNodeLookupChild(affinity->head.tqh_first, "mode"); + if (node != NULL) { + if (!strcmp(node->val, "exclusive")) { + taf->mode_flag = EXCLUSIVE_AFFINITY; + } else if (!strcmp(node->val, "balanced")) { + taf->mode_flag = BALANCED_AFFINITY; + } else { + FatalError("unknown cpu_affinity node"); + } + } + + node = ConfNodeLookupChild(affinity->head.tqh_first, "threads"); + if (node != NULL) { + if (StringParseUint32(&taf->nb_threads, 10, 0, (const char *)node->val) < 0) { + FatalError("invalid value for threads " + "count: '%s'", + node->val); + } + if (!taf->nb_threads) { + FatalError("bad value for threads count"); + } + } + } +#endif /* OS_WIN32 and __OpenBSD__ */ +} + +/** + * \brief Return next cpu to use for a given thread family + * \retval the cpu to used given by its id + */ +uint16_t AffinityGetNextCPU(ThreadsAffinityType *taf) +{ + uint16_t ncpu = 0; +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun + int iter = 0; + SCMutexLock(&taf->taf_mutex); + ncpu = taf->lcpu; + while (!CPU_ISSET(ncpu, &taf->cpu_set) && iter < 2) { + ncpu++; + if (ncpu >= UtilCpuGetNumProcessorsOnline()) { + ncpu = 0; + iter++; + } + } + if (iter == 2) { + SCLogError("cpu_set does not contain " + "available cpus, cpu affinity conf is invalid"); + } + taf->lcpu = ncpu + 1; + if (taf->lcpu >= UtilCpuGetNumProcessorsOnline()) + taf->lcpu = 0; + SCMutexUnlock(&taf->taf_mutex); + SCLogDebug("Setting affinity on CPU %d", ncpu); +#endif /* OS_WIN32 and __OpenBSD__ */ + return ncpu; +} + +uint16_t UtilAffinityGetAffinedCPUNum(ThreadsAffinityType *taf) +{ + uint16_t ncpu = 0; +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun + SCMutexLock(&taf->taf_mutex); + for (int i = UtilCpuGetNumProcessorsOnline(); i >= 0; i--) + if (CPU_ISSET(i, &taf->cpu_set)) + ncpu++; + SCMutexUnlock(&taf->taf_mutex); +#endif + return ncpu; +} + +#ifdef HAVE_DPDK +/** + * Find if CPU sets overlap + * \return 1 if CPUs overlap, 0 otherwise + */ +uint16_t UtilAffinityCpusOverlap(ThreadsAffinityType *taf1, ThreadsAffinityType *taf2) +{ + ThreadsAffinityType tmptaf; + CPU_ZERO(&tmptaf); + SCMutexInit(&tmptaf.taf_mutex, NULL); + + cpu_set_t tmpcset; + + SCMutexLock(&taf1->taf_mutex); + SCMutexLock(&taf2->taf_mutex); + CPU_AND(&tmpcset, &taf1->cpu_set, &taf2->cpu_set); + SCMutexUnlock(&taf2->taf_mutex); + SCMutexUnlock(&taf1->taf_mutex); + + for (int i = UtilCpuGetNumProcessorsOnline(); i >= 0; i--) + if (CPU_ISSET(i, &tmpcset)) + return 1; + return 0; +} + +/** + * Function makes sure that CPUs of different types don't overlap by excluding + * one affinity type from the other + * \param mod_taf - CPU set to be modified + * \param static_taf - static CPU set to be used only for evaluation + */ +void UtilAffinityCpusExclude(ThreadsAffinityType *mod_taf, ThreadsAffinityType *static_taf) +{ + cpu_set_t tmpset; + SCMutexLock(&mod_taf->taf_mutex); + SCMutexLock(&static_taf->taf_mutex); + CPU_XOR(&tmpset, &mod_taf->cpu_set, &static_taf->cpu_set); + SCMutexUnlock(&static_taf->taf_mutex); + mod_taf->cpu_set = tmpset; + SCMutexUnlock(&mod_taf->taf_mutex); +} +#endif /* HAVE_DPDK */ diff --git a/src/util/affinity.h b/src/util/affinity.h new file mode 100644 index 000000000000..223f0a41a973 --- /dev/null +++ b/src/util/affinity.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#ifndef __UTIL_AFFINITY_H__ +#define __UTIL_AFFINITY_H__ +#include "suricata-common.h" +#include "../conf.h" +#include "threads.h" + +#if defined OS_FREEBSD +#include +#include +#include +#include +#include +#define cpu_set_t cpuset_t +#elif defined __OpenBSD__ +#include +#include +#include +#elif defined OS_DARWIN +#include +#include +#include +#define cpu_set_t thread_affinity_policy_data_t +#define CPU_SET(cpu_id, new_mask) (*(new_mask)).affinity_tag = (cpu_id + 1) +#define CPU_ISSET(cpu_id, new_mask) ((*(new_mask)).affinity_tag == (cpu_id + 1)) +#define CPU_ZERO(new_mask) (*(new_mask)).affinity_tag = THREAD_AFFINITY_TAG_NULL +#endif + +enum { RECEIVE_CPU_SET, WORKER_CPU_SET, VERDICT_CPU_SET, MANAGEMENT_CPU_SET, MAX_CPU_SET }; + +enum { BALANCED_AFFINITY, EXCLUSIVE_AFFINITY, MAX_AFFINITY }; + +typedef struct ThreadsAffinityType_ { + const char *name; + uint8_t mode_flag; + uint16_t lcpu; /* use by exclusive mode */ + int prio; + uint32_t nb_threads; + SCMutex taf_mutex; + +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun + cpu_set_t cpu_set; + cpu_set_t lowprio_cpu; + cpu_set_t medprio_cpu; + cpu_set_t hiprio_cpu; +#endif +} ThreadsAffinityType; + +/** store thread affinity mode for all type of threads */ +#ifndef _THREAD_AFFINITY +extern ThreadsAffinityType thread_affinity[MAX_CPU_SET]; +#endif + +void AffinitySetupLoadFromConfig(void); +ThreadsAffinityType *GetAffinityTypeFromName(const char *name); + +uint16_t AffinityGetNextCPU(ThreadsAffinityType *taf); +uint16_t UtilAffinityGetAffinedCPUNum(ThreadsAffinityType *taf); +#ifdef HAVE_DPDK +uint16_t UtilAffinityCpusOverlap(ThreadsAffinityType *taf1, ThreadsAffinityType *taf2); +void UtilAffinityCpusExclude(ThreadsAffinityType *mod_taf, ThreadsAffinityType *static_taf); +#endif /* HAVE_DPDK */ + +void BuildCpusetWithCallback( + const char *name, ConfNode *node, void (*Callback)(int i, void *data), void *data); + +#endif /* __UTIL_AFFINITY_H__ */ diff --git a/src/util/atomic.c b/src/util/atomic.c new file mode 100644 index 000000000000..67b48e0108e7 --- /dev/null +++ b/src/util/atomic.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util/atomic.h" +#include "util/unittest.h" + +#ifdef UNITTESTS + +static int SCAtomicTest01(void) +{ + int result = 0; + int a = 10; + int b = 20; + int *temp_int = NULL; + + SC_ATOMIC_DECLARE(void *, temp); + SC_ATOMIC_INITPTR(temp); + + temp_int = SC_ATOMIC_GET(temp); + if (temp_int != NULL) + goto end; + + (void)SC_ATOMIC_SET(temp, &a); + temp_int = SC_ATOMIC_GET(temp); + if (temp_int == NULL) + goto end; + if (*temp_int != a) + goto end; + + (void)SC_ATOMIC_SET(temp, &b); + temp_int = SC_ATOMIC_GET(temp); + if (temp_int == NULL) + goto end; + if (*temp_int != b) + goto end; + + result = 1; + +end: + return result; +} + +#endif /* UNITTESTS */ + +void SCAtomicRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCAtomicTest01", SCAtomicTest01); +#endif + + return; +} diff --git a/src/util/atomic.h b/src/util/atomic.h new file mode 100644 index 000000000000..0cdc09ea44ec --- /dev/null +++ b/src/util/atomic.h @@ -0,0 +1,362 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Pablo Rincon + * + * API for atomic operations. Uses C11 atomic instructions + * where available, GCC/clang specific (gnu99) operations otherwise. + * + * To prevent developers from accidentally working with the atomic variables + * directly instead of through the proper macro's, a marco trick is performed + * that exposes different variable names than the developer uses. So if the dev + * uses "somevar", internally "somevar_sc_atomic__" is used. + */ + +#ifndef __UTIL_ATOMIC_H__ +#define __UTIL_ATOMIC_H__ + +#if HAVE_STDATOMIC_H == 1 + +#include + +#define SC_ATOMIC_MEMORY_ORDER_RELAXED memory_order_relaxed +#define SC_ATOMIC_MEMORY_ORDER_CONSUME memory_order_consume +#define SC_ATOMIC_MEMORY_ORDER_ACQUIRE memory_order_acquire +#define SC_ATOMIC_MEMORY_ORDER_RELEASE memory_order_release +#define SC_ATOMIC_MEMORY_ORDER_ACQ_REL memory_order_acq_rel +#define SC_ATOMIC_MEMORY_ORDER_SEQ_CST memory_order_seq_cst + +/** + * \brief wrapper for declaring atomic variables. + * + * \param type Type of the variable (char, short, int, long, long long) + * \param name Name of the variable. + * + * We just declare the variable here as we rely on atomic operations + * to modify it, so no need for locks. + * + * \warning variable is not initialized + */ +#define SC_ATOMIC_DECLARE(type, name) _Atomic(type) name##_sc_atomic__ + +/** + * \brief wrapper for referencing an atomic variable declared on another file. + * + * \param type Type of the variable (char, short, int, long, long long) + * \param name Name of the variable. + * + * We just declare the variable here as we rely on atomic operations + * to modify it, so no need for locks. + * + */ +#define SC_ATOMIC_EXTERN(type, name) extern _Atomic(type)(name##_sc_atomic__) + +/** + * \brief wrapper for declaring an atomic variable and initializing it. + **/ +#define SC_ATOMIC_DECL_AND_INIT(type, name) _Atomic(type)(name##_sc_atomic__) = 0 + +/** + * \brief wrapper for declaring an atomic variable and initializing it + * to a specific value + **/ +#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val) _Atomic(type)(name##_sc_atomic__) = val + +/** + * \brief wrapper for initializing an atomic variable. + **/ +#define SC_ATOMIC_INIT(name) (name##_sc_atomic__) = 0 +#define SC_ATOMIC_INITPTR(name) (name##_sc_atomic__) = NULL + +/** + * \brief wrapper for reinitializing an atomic variable. + **/ +#define SC_ATOMIC_RESET(name) SC_ATOMIC_INIT(name) + +/** + * \brief add a value to our atomic variable + * + * \param name the atomic variable + * \param val the value to add to the variable + */ +#define SC_ATOMIC_ADD(name, val) atomic_fetch_add(&(name##_sc_atomic__), (val)) + +/** + * \brief sub a value from our atomic variable + * + * \param name the atomic variable + * \param val the value to sub from the variable + */ +#define SC_ATOMIC_SUB(name, val) atomic_fetch_sub(&(name##_sc_atomic__), (val)) + +/** + * \brief Bitwise OR a value to our atomic variable + * + * \param name the atomic variable + * \param val the value to OR to the variable + */ +#define SC_ATOMIC_OR(name, val) atomic_fetch_or(&(name##_sc_atomic__), (val)) + +/** + * \brief Bitwise AND a value to our atomic variable + * + * \param name the atomic variable + * \param val the value to AND to the variable + */ +#define SC_ATOMIC_AND(name, val) atomic_fetch_and(&(name##_sc_atomic__), (val)) + +/** + * \brief atomic Compare and Switch + * + * \warning "name" is passed to us as "&var" + */ +#define SC_ATOMIC_CAS(name, cmpval, newval) \ + atomic_compare_exchange_strong((name##_sc_atomic__), &(cmpval), (newval)) + +/** + * \brief Get the value from the atomic variable. + * + * \retval var value + */ +#define SC_ATOMIC_GET(name) atomic_load(&(name##_sc_atomic__)) + +#define SC_ATOMIC_LOAD_EXPLICIT(name, order) atomic_load_explicit(&(name##_sc_atomic__), (order)) + +/** + * \brief Set the value for the atomic variable. + * + * \retval var value + */ +#define SC_ATOMIC_SET(name, val) atomic_store(&(name##_sc_atomic__), (val)) + +#else + +#define SC_ATOMIC_MEMORY_ORDER_RELAXED +#define SC_ATOMIC_MEMORY_ORDER_CONSUME +#define SC_ATOMIC_MEMORY_ORDER_ACQUIRE +#define SC_ATOMIC_MEMORY_ORDER_RELEASE +#define SC_ATOMIC_MEMORY_ORDER_ACQ_REL +#define SC_ATOMIC_MEMORY_ORDER_SEQ_CST + +/** + * \brief wrapper for OS/compiler specific atomic compare and swap (CAS) + * function. + * + * \param addr Address of the variable to CAS + * \param tv Test value to compare the value at address against + * \param nv New value to set the variable at addr to + * + * \retval 0 CAS failed + * \retval 1 CAS succeeded + */ +#define SCAtomicCompareAndSwap(addr, tv, nv) __sync_bool_compare_and_swap((addr), (tv), (nv)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and add + * function. + * + * \param addr Address of the variable to add to + * \param value Value to add to the variable at addr + */ +#define SCAtomicFetchAndAdd(addr, value) __sync_fetch_and_add((addr), (value)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and sub + * function. + * + * \param addr Address of the variable to add to + * \param value Value to sub from the variable at addr + */ +#define SCAtomicFetchAndSub(addr, value) __sync_fetch_and_sub((addr), (value)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and add + * function. + * + * \param addr Address of the variable to add to + * \param value Value to add to the variable at addr + */ +#define SCAtomicAddAndFetch(addr, value) __sync_add_and_fetch((addr), (value)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and sub + * function. + * + * \param addr Address of the variable to add to + * \param value Value to sub from the variable at addr + */ +#define SCAtomicSubAndFetch(addr, value) __sync_sub_and_fetch((addr), (value)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and "AND" + * function. + * + * \param addr Address of the variable to AND to + * \param value Value to add to the variable at addr + */ +#define SCAtomicFetchAndAnd(addr, value) __sync_fetch_and_and((addr), (value)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and "NAND" + * function. + * + * \param addr Address of the variable to NAND to + * \param value Value to add to the variable at addr + */ +#define SCAtomicFetchAndNand(addr, value) __sync_fetch_and_nand((addr), (value)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and "XOR" + * function. + * + * \param addr Address of the variable to XOR to + * \param value Value to add to the variable at addr + */ +#define SCAtomicFetchAndXor(addr, value) __sync_fetch_and_xor((addr), (value)) + +/** + * \brief wrapper for OS/compiler specific atomic fetch and or + * function. + * + * \param addr Address of the variable to or to + * \param value Value to add to the variable at addr + */ +#define SCAtomicFetchAndOr(addr, value) __sync_fetch_and_or((addr), (value)) + +/** + * \brief wrapper for declaring atomic variables. + * + * \warning Only char, short, int, long, long long and their unsigned + * versions are supported. + * + * \param type Type of the variable (char, short, int, long, long long) + * \param name Name of the variable. + * + * We just declare the variable here as we rely on atomic operations + * to modify it, so no need for locks. + * + * \warning variable is not initialized + */ +#define SC_ATOMIC_DECLARE(type, name) type name##_sc_atomic__ + +/** + * \brief wrapper for referencing an atomic variable declared on another file. + * + * \warning Only char, short, int, long, long long and their unsigned + * versions are supported. + * + * \param type Type of the variable (char, short, int, long, long long) + * \param name Name of the variable. + * + * We just declare the variable here as we rely on atomic operations + * to modify it, so no need for locks. + * + */ +#define SC_ATOMIC_EXTERN(type, name) extern type name##_sc_atomic__ + +/** + * \brief wrapper for declaring an atomic variable and initializing it + * to a specific value + **/ +#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val) type name##_sc_atomic__ = val + +/** + * \brief wrapper for declaring an atomic variable and initializing it. + **/ +#define SC_ATOMIC_DECL_AND_INIT(type, name) type name##_sc_atomic__ = 0 + +/** + * \brief wrapper for initializing an atomic variable. + **/ +#define SC_ATOMIC_INIT(name) (name##_sc_atomic__) = 0 + +#define SC_ATOMIC_INITPTR(name) (name##_sc_atomic__) = NULL + +/** + * \brief wrapper for reinitializing an atomic variable. + **/ +#define SC_ATOMIC_RESET(name) (name##_sc_atomic__) = 0 + +/** + * \brief add a value to our atomic variable + * + * \param name the atomic variable + * \param val the value to add to the variable + */ +#define SC_ATOMIC_ADD(name, val) SCAtomicFetchAndAdd(&(name##_sc_atomic__), (val)) + +/** + * \brief sub a value from our atomic variable + * + * \param name the atomic variable + * \param val the value to sub from the variable + */ +#define SC_ATOMIC_SUB(name, val) SCAtomicFetchAndSub(&(name##_sc_atomic__), (val)) + +/** + * \brief Bitwise OR a value to our atomic variable + * + * \param name the atomic variable + * \param val the value to OR to the variable + */ +#define SC_ATOMIC_OR(name, val) SCAtomicFetchAndOr(&(name##_sc_atomic__), (val)) + +/** + * \brief Bitwise AND a value to our atomic variable + * + * \param name the atomic variable + * \param val the value to AND to the variable + */ +#define SC_ATOMIC_AND(name, val) SCAtomicFetchAndAnd(&(name##_sc_atomic__), (val)) + +/** + * \brief atomic Compare and Switch + * + * \warning "name" is passed to us as "&var" + */ +#define SC_ATOMIC_CAS(name, cmpval, newval) \ + SCAtomicCompareAndSwap((name##_sc_atomic__), cmpval, newval) + +/** + * \brief Get the value from the atomic variable. + * + * \retval var value + */ +#define SC_ATOMIC_GET(name) (name##_sc_atomic__) + +#define SC_ATOMIC_LOAD_EXPLICIT(name, order) (name##_sc_atomic__) + +/** + * \brief Set the value for the atomic variable. + * + * \retval var value + */ +#define SC_ATOMIC_SET(name, val) \ + ({ \ + while (SC_ATOMIC_CAS(&name, SC_ATOMIC_GET(name), val) == 0) \ + ; \ + }) + +#endif /* no c11 atomics */ + +void SCAtomicRegisterTests(void); + +#endif /* __UTIL_ATOMIC_H__ */ diff --git a/src/util/base64.c b/src/util/base64.c new file mode 100644 index 000000000000..9845004d94b6 --- /dev/null +++ b/src/util/base64.c @@ -0,0 +1,404 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#include "util/base64.h" +#include "util/debug.h" +#include "util/unittest.h" +/* Constants */ +#define BASE64_TABLE_MAX 122 + +/* Base64 character to index conversion table */ +/* Characters are mapped as "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */ +static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51 }; + +/** + * \brief Gets a base64-decoded value from an encoded character + * + * \param c The encoded character + * + * \return The decoded value (0 or above), or -1 if the parameter is invalid + */ +static inline int GetBase64Value(uint8_t c) +{ + int val = -1; + + /* Pull from conversion table */ + if (c <= BASE64_TABLE_MAX) { + val = b64table[(int)c]; + } + + return val; +} + +/** + * \brief Checks if the given char in a byte array is Base64 alphabet + * + * \param Char that needs to be checked + * + * \return True if the char was Base64 alphabet, False otherwise + */ +bool IsBase64Alphabet(uint8_t encoded_byte) +{ + if (GetBase64Value(encoded_byte) < 0 && encoded_byte != '=') { + return false; + } + return true; +} + +/** + * \brief Decodes a 4-byte base64-encoded block into a 3-byte ascii-encoded block + * + * \param ascii the 3-byte ascii output block + * \param b64 the 4-byte base64 input block + * + * \return none + */ +static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) +{ + ascii[0] = (uint8_t)(b64[0] << 2) | (b64[1] >> 4); + ascii[1] = (uint8_t)(b64[1] << 4) | (b64[2] >> 2); + ascii[2] = (uint8_t)(b64[2] << 6) | (b64[3]); +} + +/** + * \brief Decodes a base64-encoded string buffer into an ascii-encoded byte buffer + * + * \param dest The destination byte buffer + * \param dest_size The destination byte buffer size + * \param src The source string + * \param len The length of the source string + * \param consumed_bytes The bytes that were actually processed/consumed + * \param decoded_bytes The bytes that were decoded + * \param mode The mode in which decoding should happen + * + * \return Error code indicating success or failures with parsing + */ +Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len, + uint32_t *consumed_bytes, uint32_t *decoded_bytes, Base64Mode mode) +{ + int val; + uint32_t padding = 0, bbidx = 0, sp = 0, leading_sp = 0; + uint8_t *dptr = dest; + uint8_t b64[B64_BLOCK] = { 0, 0, 0, 0 }; + bool valid = true; + Base64Ecode ecode = BASE64_ECODE_OK; + *decoded_bytes = 0; + + /* Traverse through each alpha-numeric letter in the source array */ + for (uint32_t i = 0; i < len; i++) { + /* Get decimal representation */ + val = GetBase64Value(src[i]); + if (val < 0) { + if (mode == BASE64_MODE_RFC2045 && src[i] != '=') { + if (bbidx == 0) { + /* Special case where last block of data has a leading space or invalid char */ + leading_sp++; + } + sp++; + continue; + } + /* Invalid character found, so decoding fails */ + if (src[i] != '=') { + valid = false; + ecode = BASE64_ECODE_ERR; + if (mode == BASE64_MODE_STRICT) { + *decoded_bytes = 0; + } + break; + } + padding++; + } + + /* For each alpha-numeric letter in the source array, find the numeric + * value */ + b64[bbidx++] = (val > 0 ? (uint8_t)val : 0); + + /* Decode every 4 base64 bytes into 3 ascii bytes */ + if (bbidx == B64_BLOCK) { + + /* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */ + uint32_t numDecoded_blk = ASCII_BLOCK - (padding < B64_BLOCK ? padding : ASCII_BLOCK); + if (dest_size < *decoded_bytes + numDecoded_blk) { + SCLogDebug("Destination buffer full"); + ecode = BASE64_ECODE_BUF; + break; + } + + /* Decode base-64 block into ascii block and move pointer */ + DecodeBase64Block(dptr, b64); + dptr += numDecoded_blk; + *decoded_bytes += numDecoded_blk; + /* Reset base-64 block and index */ + bbidx = 0; + padding = 0; + *consumed_bytes += B64_BLOCK + sp; + sp = 0; + leading_sp = 0; + memset(&b64, 0, sizeof(b64)); + } + } + + if (bbidx > 0 && bbidx < 4 && ((!valid && mode == BASE64_MODE_RFC4648))) { + /* Decoded bytes for 1 or 2 base64 encoded bytes is 1 */ + padding = bbidx > 1 ? B64_BLOCK - bbidx : 2; + uint32_t numDecoded_blk = ASCII_BLOCK - (padding < B64_BLOCK ? padding : ASCII_BLOCK); + if (dest_size < *decoded_bytes + numDecoded_blk) { + SCLogDebug("Destination buffer full"); + ecode = BASE64_ECODE_BUF; + return ecode; + } + /* if the destination size is not at least 3 Bytes long, it'll give a dynamic + * buffer overflow while decoding, so, return and let the caller take care of the + * remaining bytes to be decoded which should always be < 4 at this stage */ + if (dest_size - *decoded_bytes < 3) + return BASE64_ECODE_BUF; + *decoded_bytes += numDecoded_blk; + DecodeBase64Block(dptr, b64); + *consumed_bytes += bbidx; + } + + /* Finish remaining b64 bytes by padding */ + if (valid && bbidx > 0 && (mode != BASE64_MODE_RFC2045)) { + /* Decode remaining */ + *decoded_bytes += ASCII_BLOCK - (B64_BLOCK - bbidx); + DecodeBase64Block(dptr, b64); + } + + if (*decoded_bytes == 0) { + SCLogDebug("base64 decoding failed"); + } + + *consumed_bytes += leading_sp; + return ecode; +} + +#ifdef UNITTESTS + +#define TEST_RFC2045(src, fin_str, dest_size, exp_decoded, exp_consumed, ecode) \ + { \ + uint32_t consumed_bytes = 0, num_decoded = 0; \ + uint8_t dst[dest_size]; \ + Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \ + &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045); \ + FAIL_IF(code != ecode); \ + FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \ + FAIL_IF(num_decoded != exp_decoded); \ + FAIL_IF(consumed_bytes != exp_consumed); \ + } + +#define TEST_RFC4648(src, fin_str, dest_size, exp_decoded, exp_consumed, ecode) \ + { \ + uint32_t consumed_bytes = 0, num_decoded = 0; \ + uint8_t dst[dest_size]; \ + Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \ + &consumed_bytes, &num_decoded, BASE64_MODE_RFC4648); \ + FAIL_IF(code != ecode); \ + FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \ + FAIL_IF(num_decoded != exp_decoded); \ + FAIL_IF(consumed_bytes != exp_consumed); \ + } + +static int B64DecodeCompleteString(void) +{ + /* + * SGVsbG8gV29ybGR6 : Hello Worldz + * */ + const char *src = "SGVsbG8gV29ybGR6"; + const char *fin_str = "Hello Worldz"; + TEST_RFC2045(src, fin_str, strlen(fin_str), strlen(fin_str), strlen(src), BASE64_ECODE_OK); + PASS; +} + +static int B64DecodeInCompleteString(void) +{ + /* + * SGVsbG8gV29ybGR6 : Hello Worldz + * */ + const char *src = "SGVsbG8gV29ybGR"; + const char *fin_str = "Hello Wor"; + TEST_RFC2045(src, fin_str, strlen(fin_str), strlen(fin_str), strlen(src) - 3, BASE64_ECODE_OK); + PASS; +} + +static int B64DecodeCompleteStringWSp(void) +{ + /* + * SGVsbG8gV29ybGQ= : Hello World + * */ + + const char *src = "SGVs bG8 gV29y bGQ="; + const char *fin_str = "Hello World"; + TEST_RFC2045(src, fin_str, strlen(fin_str) + 3, strlen(fin_str), strlen(src), BASE64_ECODE_OK); + PASS; +} + +static int B64DecodeInCompleteStringWSp(void) +{ + /* + * SGVsbG8gV29ybGQ= : Hello World + * Special handling for this case (sp in remainder) done in ProcessBase64Remainder + * */ + + const char *src = "SGVs bG8 gV29y bGQ"; + const char *fin_str = "Hello Wor"; + TEST_RFC2045(src, fin_str, strlen(fin_str) + 1 /* 12 B in dest_size */, strlen(fin_str), + strlen(src) - 3, BASE64_ECODE_OK); + PASS; +} + +static int B64DecodeStringBiggerThanBuffer(void) +{ + /* + * SGVsbG8gV29ybGQ= : Hello World + * */ + + const char *src = "SGVs bG8 gV29y bGQ="; + const char *fin_str = "Hello Wor"; + TEST_RFC2045( + src, fin_str, strlen(fin_str) + 1, strlen(fin_str), strlen(src) - 4, BASE64_ECODE_BUF); + PASS; +} + +static int B64DecodeStringEndingSpaces(void) +{ + const char *src = "0YPhA d H"; + uint32_t consumed_bytes = 0, num_decoded = 0; + uint8_t dst[10]; + Base64Ecode code = DecodeBase64(dst, sizeof(dst), (const uint8_t *)src, strlen(src), + &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045); + FAIL_IF(code != BASE64_ECODE_OK); + FAIL_IF(num_decoded != 3); + FAIL_IF(consumed_bytes != 4); + PASS; +} + +static int B64TestVectorsRFC2045(void) +{ + const char *src1 = ""; + const char *fin_str1 = ""; + + const char *src2 = "Zg=="; + const char *fin_str2 = "f"; + + const char *src3 = "Zm8="; + const char *fin_str3 = "fo"; + + const char *src4 = "Zm9v"; + const char *fin_str4 = "foo"; + + const char *src5 = "Zm9vYg=="; + const char *fin_str5 = "foob"; + + const char *src6 = "Zm9vYmE="; + const char *fin_str6 = "fooba"; + + const char *src7 = "Zm9vYmFy"; + const char *fin_str7 = "foobar"; + + const char *src8 = "Zm 9v Ym Fy"; + const char *fin_str8 = "foobar"; + + const char *src9 = "Zm$9vYm.Fy"; + const char *fin_str9 = "foobar"; + + const char *src10 = "Y21Wd2IzSjBaVzFoYVd4bWNtRjFaRUJoZEc4dVoyOTJMbUYxOmpqcHh4b3Rhb2w%5"; + const char *fin_str10 = "cmVwb3J0ZW1haWxmcmF1ZEBhdG8uZ292LmF1:jjpxxotaol9"; + + TEST_RFC2045(src1, fin_str1, ASCII_BLOCK * 2, strlen(fin_str1), strlen(src1), BASE64_ECODE_OK); + TEST_RFC2045(src2, fin_str2, ASCII_BLOCK * 2, strlen(fin_str2), strlen(src2), BASE64_ECODE_OK); + TEST_RFC2045(src3, fin_str3, ASCII_BLOCK * 2, strlen(fin_str3), strlen(src3), BASE64_ECODE_OK); + TEST_RFC2045(src4, fin_str4, ASCII_BLOCK * 2, strlen(fin_str4), strlen(src4), BASE64_ECODE_OK); + TEST_RFC2045(src5, fin_str5, ASCII_BLOCK * 2, strlen(fin_str5), strlen(src5), BASE64_ECODE_OK); + TEST_RFC2045(src6, fin_str6, ASCII_BLOCK * 2, strlen(fin_str6), strlen(src6), BASE64_ECODE_OK); + TEST_RFC2045(src7, fin_str7, ASCII_BLOCK * 2, strlen(fin_str7), strlen(src7), BASE64_ECODE_OK); + TEST_RFC2045(src8, fin_str8, ASCII_BLOCK * 2, strlen(fin_str8), strlen(src8), BASE64_ECODE_OK); + TEST_RFC2045(src9, fin_str9, ASCII_BLOCK * 2, strlen(fin_str9), strlen(src9), BASE64_ECODE_OK); + TEST_RFC2045(src10, fin_str10, strlen(fin_str10) + 2, strlen(fin_str10), strlen(src10), + BASE64_ECODE_OK); + PASS; +} + +static int B64TestVectorsRFC4648(void) +{ + const char *src1 = ""; + const char *fin_str1 = ""; + + const char *src2 = "Zg=="; + const char *fin_str2 = "f"; + + const char *src3 = "Zm8="; + const char *fin_str3 = "fo"; + + const char *src4 = "Zm9v"; + const char *fin_str4 = "foo"; + + const char *src5 = "Zm9vYg=="; + const char *fin_str5 = "foob"; + + const char *src6 = "Zm9vYmE="; + const char *fin_str6 = "fooba"; + + const char *src7 = "Zm9vYmFy"; + const char *fin_str7 = "foobar"; + + const char *src8 = "Zm 9v Ym Fy"; + const char *fin_str8 = "f"; + + const char *src9 = "Zm$9vYm.Fy"; + const char *fin_str9 = "f"; + + const char *src10 = "Y21Wd2IzSjBaVzFoYVd4bWNtRjFaRUJoZEc4dVoyOTJMbUYxOmpqcHh4b3Rhb2w%3D"; + const char *fin_str10 = "cmVwb3J0ZW1haWxmcmF1ZEBhdG8uZ292LmF1:jjpxxotaol"; + + TEST_RFC4648(src1, fin_str1, ASCII_BLOCK * 2, strlen(fin_str1), strlen(src1), BASE64_ECODE_OK); + TEST_RFC4648(src2, fin_str2, ASCII_BLOCK * 2, strlen(fin_str2), strlen(src2), BASE64_ECODE_OK); + TEST_RFC4648(src3, fin_str3, ASCII_BLOCK * 2, strlen(fin_str3), strlen(src3), BASE64_ECODE_OK); + TEST_RFC4648(src4, fin_str4, ASCII_BLOCK * 2, strlen(fin_str4), strlen(src4), BASE64_ECODE_OK); + TEST_RFC4648(src5, fin_str5, ASCII_BLOCK * 2, strlen(fin_str5), strlen(src5), BASE64_ECODE_OK); + TEST_RFC4648(src6, fin_str6, ASCII_BLOCK * 2, strlen(fin_str6), strlen(src6), BASE64_ECODE_OK); + TEST_RFC4648(src7, fin_str7, ASCII_BLOCK * 2, strlen(fin_str7), strlen(src7), BASE64_ECODE_OK); + TEST_RFC4648(src8, fin_str8, ASCII_BLOCK * 2, 1 /* f */, 2 /* Zm */, BASE64_ECODE_ERR); + TEST_RFC4648(src9, fin_str9, ASCII_BLOCK * 2, 1 /* f */, 2 /* Zm */, BASE64_ECODE_ERR); + TEST_RFC4648(src10, fin_str10, strlen(fin_str10) + 1, strlen(fin_str10), strlen(src10) - 3, + BASE64_ECODE_ERR); + PASS; +} + +void Base64RegisterTests(void) +{ + UtRegisterTest("B64DecodeCompleteStringWSp", B64DecodeCompleteStringWSp); + UtRegisterTest("B64DecodeInCompleteStringWSp", B64DecodeInCompleteStringWSp); + UtRegisterTest("B64DecodeCompleteString", B64DecodeCompleteString); + UtRegisterTest("B64DecodeInCompleteString", B64DecodeInCompleteString); + UtRegisterTest("B64DecodeStringBiggerThanBuffer", B64DecodeStringBiggerThanBuffer); + UtRegisterTest("B64DecodeStringEndingSpaces", B64DecodeStringEndingSpaces); + UtRegisterTest("B64TestVectorsRFC2045", B64TestVectorsRFC2045); + UtRegisterTest("B64TestVectorsRFC4648", B64TestVectorsRFC4648); +} +#endif diff --git a/src/util/base64.h b/src/util/base64.h new file mode 100644 index 000000000000..5d05a1a62561 --- /dev/null +++ b/src/util/base64.h @@ -0,0 +1,87 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#ifndef __UTIL_BASE64_H_ +#define __UTIL_BASE64_H_ + +#include "suricata-common.h" + +/* Constants */ +#define ASCII_BLOCK 3 +#define B64_BLOCK 4 + +typedef enum { + BASE64_MODE_RELAX, + /* If the following strings were to be passed to the decoder with RFC2045 mode, + * the results would be as follows. See the unittest B64TestVectorsRFC2045 in + * src/util-base64.c + * + * BASE64("") = "" + * BASE64("f") = "Zg==" + * BASE64("fo") = "Zm8=" + * BASE64("foo") = "Zm9v" + * BASE64("foob") = "Zm9vYg==" + * BASE64("fooba") = "Zm9vYmE=" + * BASE64("foobar") = "Zm9vYmFy" + * BASE64("foobar") = "Zm 9v Ym Fy" <-- Notice how the spaces are ignored + * BASE64("foobar") = "Zm$9vYm.Fy" # According to RFC 2045, All line breaks or *other + * characters* not found in base64 alphabet must be ignored by decoding software + * */ + BASE64_MODE_RFC2045, /* SPs are allowed during transfer but must be skipped by Decoder */ + BASE64_MODE_STRICT, + /* If the following strings were to be passed to the decoder with RFC4648 mode, + * the results would be as follows. See the unittest B64TestVectorsRFC4648 in + * src/util-base64.c + * + * BASE64("") = "" + * BASE64("f") = "Zg==" + * BASE64("fo") = "Zm8=" + * BASE64("foo") = "Zm9v" + * BASE64("foob") = "Zm9vYg==" + * BASE64("fooba") = "Zm9vYmE=" + * BASE64("foobar") = "Zm9vYmFy" + * BASE64("f") = "Zm 9v Ym Fy" <-- Notice how the processing stops once space is encountered + * BASE64("f") = "Zm$9vYm.Fy" <-- Notice how the processing stops once an invalid char is + * encountered + * */ + BASE64_MODE_RFC4648, /* reject the encoded data if it contains characters outside the base + alphabet */ +} Base64Mode; + +typedef enum { + BASE64_ECODE_ERR = -1, + BASE64_ECODE_OK = 0, + BASE64_ECODE_BUF, +} Base64Ecode; + +/* Function prototypes */ +Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len, + uint32_t *consumed_bytes, uint32_t *decoded_bytes, Base64Mode mode); +bool IsBase64Alphabet(uint8_t encoded_byte); + +#endif + +#ifdef UNITTESTS +void Base64RegisterTests(void); +#endif diff --git a/src/util/bloomfilter-counting.c b/src/util/bloomfilter-counting.c new file mode 100644 index 000000000000..842cd40c8072 --- /dev/null +++ b/src/util/bloomfilter-counting.c @@ -0,0 +1,415 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Counting Bloom Filter implementation. Can be used with 8, 16, 32 bits + * counters. + */ + +#include "suricata-common.h" +#include "util/bloomfilter-counting.h" +#include "util/unittest.h" + +/* type: 1, 2 or 4 for 8, 16, or 32 bit counters + * + */ +BloomFilterCounting *BloomFilterCountingInit(uint32_t size, uint8_t type, uint8_t iter, + uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)) +{ + BloomFilterCounting *bf = NULL; + + if (iter == 0) + goto error; + + if (Hash == NULL || size == 0) { + // printf("ERROR: BloomFilterCountingInit no Hash function\n"); + goto error; + } + + if (type != 1 && type != 2 && type != 4) { + // printf("ERROR: BloomFilterCountingInit only 1, 2 and 4 bytes are supported\n"); + goto error; + } + + /* setup the filter */ + bf = SCCalloc(1, sizeof(BloomFilterCounting)); + if (unlikely(bf == NULL)) + goto error; + bf->type = type; /* size of the type: 1, 2, 4 */ + bf->array_size = size; + bf->hash_iterations = iter; + bf->Hash = Hash; + + /* setup the bitarray */ + bf->array = SCCalloc(bf->array_size, bf->type); + if (bf->array == NULL) + goto error; + + return bf; + +error: + if (bf != NULL) { + if (bf->array != NULL) + SCFree(bf->array); + + SCFree(bf); + } + return NULL; +} + +void BloomFilterCountingFree(BloomFilterCounting *bf) +{ + if (bf != NULL) { + if (bf->array != NULL) + SCFree(bf->array); + + SCFree(bf); + } +} + +void BloomFilterCountingPrint(BloomFilterCounting *bf) +{ + printf("\n------ Counting Bloom Filter Stats ------\n"); + printf("Buckets: %" PRIu32 "\n", bf->array_size); + printf("Counter size: %" PRIu32 "\n", bf->type); + printf("Memory size: %" PRIu32 " bytes\n", bf->array_size * bf->type); + printf("Hash function pointer: %p\n", bf->Hash); + printf("Hash functions: %" PRIu32 "\n", bf->hash_iterations); + printf("-----------------------------------------\n"); +} + +int BloomFilterCountingAdd(BloomFilterCounting *bf, const void *data, uint16_t datalen) +{ + uint8_t iter = 0; + uint32_t hash = 0; + + if (bf == NULL || data == NULL || datalen == 0) + return -1; + + for (iter = 0; iter < bf->hash_iterations; iter++) { + hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; + if (bf->type == 1) { + uint8_t *u8 = (uint8_t *)&bf->array[hash]; + if ((*u8) != 255) + (*u8)++; + } else if (bf->type == 2) { + uint16_t *u16 = (uint16_t *)&bf->array[hash]; + if ((*u16) != 65535) + (*u16)++; + } else if (bf->type == 4) { + uint32_t *u32 = (uint32_t *)&bf->array[hash]; + if ((*u32) != 4294967295UL) + (*u32)++; + } + } + + return 0; +} + +int BloomFilterCountingRemove(BloomFilterCounting *bf, const void *data, uint16_t datalen) +{ + uint8_t iter = 0; + uint32_t hash = 0; + + if (bf == NULL || data == NULL || datalen == 0) + return -1; + + /* only remove data that was actually added */ + if (BloomFilterCountingTest(bf, data, datalen) == 0) { + printf("ERROR: BloomFilterCountingRemove tried to remove data " + "that was never added to the set or was already removed.\n"); + return -1; + } + + /* decrease counters for every iteration */ + for (iter = 0; iter < bf->hash_iterations; iter++) { + hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; + if (bf->type == 1) { + uint8_t *u8 = (uint8_t *)&bf->array[hash]; + if ((*u8) > 0) + (*u8)--; + else { + printf("ERROR: BloomFilterCountingRemove tried to decrease a " + "counter below zero.\n"); + return -1; + } + } else if (bf->type == 2) { + uint16_t *u16 = (uint16_t *)&bf->array[hash]; + if ((*u16) > 0) + (*u16)--; + else { + printf("ERROR: BloomFilterCountingRemove tried to decrease a " + "counter below zero.\n"); + return -1; + } + } else if (bf->type == 4) { + uint32_t *u32 = (uint32_t *)&bf->array[hash]; + if ((*u32) > 0) + (*u32)--; + else { + printf("ERROR: BloomFilterCountingRemove tried to decrease a " + "counter below zero.\n"); + return -1; + } + } + } + + return 0; +} + +/* Test if data matches our filter and is likely to be in the set + * + * returns 0: for no match + * 1: match + */ +int BloomFilterCountingTest(BloomFilterCounting *bf, const void *data, uint16_t datalen) +{ + uint8_t iter = 0; + uint32_t hash = 0; + int hit = 1; + + /* check each hash iteration */ + for (iter = 0; iter < bf->hash_iterations; iter++) { + hash = bf->Hash(data, datalen, iter, bf->array_size) * bf->type; + if (bf->type == 1) { + uint8_t *u8 = (uint8_t *)&bf->array[hash]; + if ((*u8) == 0x00) { + hit = 0; + break; + } + } else if (bf->type == 2) { + uint16_t *u16 = (uint16_t *)&bf->array[hash]; + if ((*u16) == 0x0000) { + hit = 0; + break; + } + } else if (bf->type == 4) { + uint32_t *u32 = (uint32_t *)&bf->array[hash]; + if ((*u32) == 0x00000000) { + hit = 0; + break; + } + } + } + + return hit; +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +static uint32_t BloomHash(const void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) +{ + uint8_t *d = (uint8_t *)data; + uint32_t i; + uint32_t hash = 0; + + for (i = 0; i < datalen; i++) { + if (i == 0) + hash += (((uint32_t)*d++)); + else if (i == 1) + hash += (((uint32_t)*d++) * datalen); + else + hash *= (((uint32_t)*d++) * i); + } + + hash *= (iter + datalen); + hash %= hash_size; + return hash; +} + +static int BloomFilterCountingTestInit01(void) +{ + BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); + if (bf == NULL) + return 0; + + BloomFilterCountingFree(bf); + return 1; +} + +/* no hash function, so it should fail */ +static int BloomFilterCountingTestInit02(void) +{ + BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, NULL); + if (bf == NULL) + return 1; + + BloomFilterCountingFree(bf); + return 0; +} + +static int BloomFilterCountingTestInit03(void) +{ + int result = 0; + BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); + if (bf == NULL) + return 0; + + if (bf->Hash == BloomHash) + result = 1; + + BloomFilterCountingFree(bf); + return result; +} + +static int BloomFilterCountingTestInit04(void) +{ + BloomFilterCounting *bf = BloomFilterCountingInit(1024, 0, 4, BloomHash); + if (bf == NULL) + return 1; + + BloomFilterCountingFree(bf); + return 0; +} + +static int BloomFilterCountingTestInit05(void) +{ + BloomFilterCounting *bf = BloomFilterCountingInit(0, 4, 4, BloomHash); + if (bf == NULL) + return 1; + + BloomFilterCountingFree(bf); + return 0; +} + +static int BloomFilterCountingTestInit06(void) +{ + BloomFilterCounting *bf = BloomFilterCountingInit(32, 3, 4, BloomHash); + if (bf == NULL) + return 1; + + BloomFilterCountingFree(bf); + return 0; +} + +static int BloomFilterCountingTestAdd01(void) +{ + int result = 0; + BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); + if (bf == NULL) + return 0; + + int r = BloomFilterCountingAdd(bf, "test", 0); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterCountingFree(bf); + return result; +} + +static int BloomFilterCountingTestAdd02(void) +{ + int result = 0; + BloomFilterCounting *bf = BloomFilterCountingInit(1024, 4, 4, BloomHash); + if (bf == NULL) + return 0; + + int r = BloomFilterCountingAdd(bf, NULL, 4); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterCountingFree(bf); + return result; +} + +static int BloomFilterCountingTestFull01(void) +{ + int result = 0; + BloomFilterCounting *bf = BloomFilterCountingInit(32, 4, 4, BloomHash); + if (bf == NULL) { + printf("init failed: "); + goto end; + } + + int r = BloomFilterCountingAdd(bf, "test", 4); + if (r != 0) { + printf("first add: "); + goto end; + } + + r = BloomFilterCountingTest(bf, "test", 4); + if (r != 1) { + printf("2nd add: "); + goto end; + } + + r = BloomFilterCountingRemove(bf, "test", 4); + if (r != 0) { + printf("3rd add: "); + goto end; + } + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterCountingFree(bf); + return result; +} + +static int BloomFilterCountingTestFull02(void) +{ + int result = 0; + BloomFilterCounting *bf = BloomFilterCountingInit(32, 4, 4, BloomHash); + if (bf == NULL) + goto end; + + int r = BloomFilterCountingTest(bf, "test", 4); + if (r != 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterCountingFree(bf); + return result; +} +#endif + +void BloomFilterCountingRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("BloomFilterCountingTestInit01", BloomFilterCountingTestInit01); + UtRegisterTest("BloomFilterCountingTestInit02", BloomFilterCountingTestInit02); + UtRegisterTest("BloomFilterCountingTestInit03", BloomFilterCountingTestInit03); + UtRegisterTest("BloomFilterCountingTestInit04", BloomFilterCountingTestInit04); + UtRegisterTest("BloomFilterCountingTestInit05", BloomFilterCountingTestInit05); + UtRegisterTest("BloomFilterCountingTestInit06", BloomFilterCountingTestInit06); + + UtRegisterTest("BloomFilterCountingTestAdd01", BloomFilterCountingTestAdd01); + UtRegisterTest("BloomFilterCountingTestAdd02", BloomFilterCountingTestAdd02); + + UtRegisterTest("BloomFilterCountingTestFull01", BloomFilterCountingTestFull01); + UtRegisterTest("BloomFilterCountingTestFull02", BloomFilterCountingTestFull02); +#endif +} diff --git a/src/util/bloomfilter-counting.h b/src/util/bloomfilter-counting.h new file mode 100644 index 000000000000..a3ca769bfb50 --- /dev/null +++ b/src/util/bloomfilter-counting.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __BLOOMFILTERCOUNTING_H__ +#define __BLOOMFILTERCOUNTING_H__ + +/* Bloom filter structure */ +typedef struct BloomFilterCounting_ { + uint8_t *array; + uint32_t array_size; /* size in buckets */ + uint8_t type; /* 1, 2 or 4 byte counters */ + uint8_t hash_iterations; + uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t); +} BloomFilterCounting; + +/* prototypes */ +BloomFilterCounting *BloomFilterCountingInit( + uint32_t, uint8_t, uint8_t, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)); +void BloomFilterCountingFree(BloomFilterCounting *); +void BloomFilterCountingPrint(BloomFilterCounting *); +int BloomFilterCountingAdd(BloomFilterCounting *, const void *, uint16_t); +int BloomFilterCountingRemove(BloomFilterCounting *, const void *, uint16_t); +int BloomFilterCountingTest(BloomFilterCounting *, const void *, uint16_t); + +void BloomFilterCountingRegisterTests(void); + +#endif /* __BLOOMFILTERCOUNTING_H__ */ diff --git a/src/util/bloomfilter.c b/src/util/bloomfilter.c new file mode 100644 index 000000000000..16e0f4f18e35 --- /dev/null +++ b/src/util/bloomfilter.c @@ -0,0 +1,297 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Bitwise bloom filter implementation + */ + +#include "suricata-common.h" +#include "util/bloomfilter.h" +#include "util/unittest.h" + +BloomFilter *BloomFilterInit( + uint32_t size, uint8_t iter, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)) +{ + BloomFilter *bf = NULL; + + if (size == 0 || iter == 0) + goto error; + + if (Hash == NULL) { + // printf("ERROR: BloomFilterInit no Hash function\n"); + goto error; + } + + /* setup the filter */ + bf = SCCalloc(1, sizeof(BloomFilter)); + if (unlikely(bf == NULL)) + goto error; + bf->bitarray_size = size; + bf->hash_iterations = iter; + bf->Hash = Hash; + + /* setup the bitarray */ + bf->bitarray = SCCalloc(1, (bf->bitarray_size / 8) + 1); + if (bf->bitarray == NULL) + goto error; + + return bf; + +error: + if (bf != NULL) { + if (bf->bitarray != NULL) + SCFree(bf->bitarray); + + SCFree(bf); + } + return NULL; +} + +void BloomFilterFree(BloomFilter *bf) +{ + if (bf != NULL) { + if (bf->bitarray != NULL) + SCFree(bf->bitarray); + + SCFree(bf); + } +} + +void BloomFilterPrint(BloomFilter *bf) +{ + printf("\n---------- Bloom Filter Stats -----------\n"); + printf("Buckets: %" PRIu32 "\n", bf->bitarray_size); + printf("Memory size: %" PRIu32 " bytes\n", bf->bitarray_size / 8 + 1); + printf("Hash function pointer: %p\n", bf->Hash); + printf("Hash functions: %" PRIu32 "\n", bf->hash_iterations); + printf("-----------------------------------------\n"); +} + +int BloomFilterAdd(BloomFilter *bf, const void *data, uint16_t datalen) +{ + uint8_t iter = 0; + uint32_t hash = 0; + + if (bf == NULL || data == NULL || datalen == 0) + return -1; + + for (iter = 0; iter < bf->hash_iterations; iter++) { + hash = bf->Hash(data, datalen, iter, bf->bitarray_size); + bf->bitarray[hash / 8] |= (1 << hash % 8); + } + + return 0; +} + +uint32_t BloomFilterMemoryCnt(BloomFilter *bf) +{ + if (bf == NULL) + return 0; + + return 2; +} + +uint32_t BloomFilterMemorySize(BloomFilter *bf) +{ + if (bf == NULL) + return 0; + + return (sizeof(BloomFilter) + (bf->bitarray_size / 8) + 1); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +static uint32_t BloomFilterTestHash( + const void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) +{ + uint8_t *d = (uint8_t *)data; + uint32_t i; + uint32_t hash = 0; + + for (i = 0; i < datalen; i++) { + if (i == 0) + hash += (((uint32_t)*d++)); + else if (i == 1) + hash += (((uint32_t)*d++) * datalen); + else + hash *= (((uint32_t)*d++) * i); + } + + hash *= (iter + datalen); + hash %= hash_size; + return hash; +} + +static int BloomFilterTestInit01(void) +{ + BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); + if (bf == NULL) + return 0; + + BloomFilterFree(bf); + return 1; +} + +/* no hash function, so it should fail */ +static int BloomFilterTestInit02(void) +{ + BloomFilter *bf = BloomFilterInit(1024, 4, NULL); + if (bf == NULL) + return 1; + + BloomFilterFree(bf); + return 0; +} + +static int BloomFilterTestInit03(void) +{ + int result = 0; + BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); + if (bf == NULL) + return 0; + + if (bf->Hash == BloomFilterTestHash) + result = 1; + + BloomFilterFree(bf); + return result; +} + +static int BloomFilterTestInit04(void) +{ + BloomFilter *bf = BloomFilterInit(1024, 0, BloomFilterTestHash); + if (bf == NULL) + return 1; + + BloomFilterFree(bf); + return 0; +} + +static int BloomFilterTestInit05(void) +{ + BloomFilter *bf = BloomFilterInit(0, 4, BloomFilterTestHash); + if (bf == NULL) + return 1; + + BloomFilterFree(bf); + return 0; +} + +static int BloomFilterTestAdd01(void) +{ + int result = 0; + BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); + if (bf == NULL) + return 0; + + int r = BloomFilterAdd(bf, "test", 0); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterFree(bf); + return result; +} + +static int BloomFilterTestAdd02(void) +{ + int result = 0; + BloomFilter *bf = BloomFilterInit(1024, 4, BloomFilterTestHash); + if (bf == NULL) + return 0; + + int r = BloomFilterAdd(bf, NULL, 4); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterFree(bf); + return result; +} + +static int BloomFilterTestFull01(void) +{ + int result = 0; + BloomFilter *bf = BloomFilterInit(32, 4, BloomFilterTestHash); + if (bf == NULL) + goto end; + + int r = BloomFilterAdd(bf, "test", 4); + if (r != 0) + goto end; + + r = BloomFilterTest(bf, "test", 4); + if (r != 1) + goto end; + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterFree(bf); + return result; +} + +static int BloomFilterTestFull02(void) +{ + int result = 0; + BloomFilter *bf = BloomFilterInit(32, 4, BloomFilterTestHash); + if (bf == NULL) + goto end; + + int r = BloomFilterTest(bf, "test", 4); + if (r != 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (bf != NULL) + BloomFilterFree(bf); + return result; +} +#endif /* UNITTESTS */ + +void BloomFilterRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("BloomFilterTestInit01", BloomFilterTestInit01); + UtRegisterTest("BloomFilterTestInit02", BloomFilterTestInit02); + UtRegisterTest("BloomFilterTestInit03", BloomFilterTestInit03); + UtRegisterTest("BloomFilterTestInit04", BloomFilterTestInit04); + UtRegisterTest("BloomFilterTestInit05", BloomFilterTestInit05); + + UtRegisterTest("BloomFilterTestAdd01", BloomFilterTestAdd01); + UtRegisterTest("BloomFilterTestAdd02", BloomFilterTestAdd02); + + UtRegisterTest("BloomFilterTestFull01", BloomFilterTestFull01); + UtRegisterTest("BloomFilterTestFull02", BloomFilterTestFull02); +#endif /* UNITTESTS */ +} diff --git a/src/util/bloomfilter.h b/src/util/bloomfilter.h new file mode 100644 index 000000000000..013982b0f232 --- /dev/null +++ b/src/util/bloomfilter.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __BLOOMFILTER_H__ +#define __BLOOMFILTER_H__ + +/* Bloom Filter structure */ +typedef struct BloomFilter_ { + uint8_t hash_iterations; + uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t); + uint32_t bitarray_size; + uint8_t *bitarray; +} BloomFilter; + +/* prototypes */ +BloomFilter *BloomFilterInit( + uint32_t, uint8_t, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)); +void BloomFilterFree(BloomFilter *); +void BloomFilterPrint(BloomFilter *); +int BloomFilterAdd(BloomFilter *, const void *, uint16_t); +uint32_t BloomFilterMemoryCnt(BloomFilter *); +uint32_t BloomFilterMemorySize(BloomFilter *); + +void BloomFilterRegisterTests(void); + +/** ----- Inline functions ---- */ + +static inline int BloomFilterTest(const BloomFilter *, const void *, uint16_t); + +static inline int BloomFilterTest(const BloomFilter *bf, const void *data, uint16_t datalen) +{ + uint8_t iter = 0; + uint32_t hash = 0; + int hit = 1; + + for (iter = 0; iter < bf->hash_iterations; iter++) { + hash = bf->Hash(data, datalen, iter, bf->bitarray_size); + if (!(bf->bitarray[hash / 8] & (1 << hash % 8))) { + hit = 0; + break; + } + } + + return hit; +} + +#endif /* __BLOOMFILTER_H__ */ diff --git a/src/util/bpf.c b/src/util/bpf.c new file mode 100644 index 000000000000..fa59ff7fc0d6 --- /dev/null +++ b/src/util/bpf.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#include "suricata-common.h" +#include "util/bpf.h" +#include "threads.h" +#include "../conf.h" +#include "util/debug.h" + +void ConfSetBPFFilter( + ConfNode *if_root, ConfNode *if_default, const char *iface, const char **bpf_filter) +{ + if (*bpf_filter != NULL) { + SCLogInfo("BPF filter already configured"); + return; + } + + /* command line value has precedence */ + if (ConfGet("bpf-filter", bpf_filter) == 1) { + if (strlen(*bpf_filter) > 0) { + SCLogConfig("%s: using command-line provided bpf filter '%s'", iface, *bpf_filter); + } + } else if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", bpf_filter) == + 1) { // reading from a file + if (strlen(*bpf_filter) > 0) { + SCLogConfig("%s: using file provided bpf filter %s", iface, *bpf_filter); + } + } else { + SCLogDebug("No BPF filter found, skipping"); + } +} + +/** protect bpf filter build, as it is not thread safe */ +static SCMutex bpf_set_filter_lock = SCMUTEX_INITIALIZER; + +void SCBPFFree(struct bpf_program *program) +{ + if (program) + pcap_freecode(program); +} + +int SCBPFCompile(int snaplen_arg, int linktype_arg, struct bpf_program *program, const char *buf, + int optimize, uint32_t mask, char *errbuf, size_t errbuf_len) +{ + pcap_t *p; + int ret; + + p = pcap_open_dead(linktype_arg, snaplen_arg); + if (p == NULL) + return (-1); + + SCMutexLock(&bpf_set_filter_lock); + ret = pcap_compile(p, program, buf, optimize, mask); + if (ret == -1) { + if (errbuf) { + snprintf(errbuf, errbuf_len, "%s", pcap_geterr(p)); + } + pcap_close(p); + SCMutexUnlock(&bpf_set_filter_lock); + return (-1); + } + pcap_close(p); + SCMutexUnlock(&bpf_set_filter_lock); + + if (program->bf_insns == NULL) { + if (errbuf) { + snprintf(errbuf, errbuf_len, "Filter badly setup"); + } + SCBPFFree(program); + return (-1); + } + + return (ret); +} diff --git a/src/util/bpf.h b/src/util/bpf.h new file mode 100644 index 000000000000..c0e296469d73 --- /dev/null +++ b/src/util/bpf.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#ifndef __UTIL_BPF_H__ +#define __UTIL_BPF_H__ + +#include "../conf.h" + +void ConfSetBPFFilter( + ConfNode *if_root, ConfNode *if_default, const char *iface, const char **bpf_filter); + +int SCBPFCompile(int snaplen_arg, int linktype_arg, struct bpf_program *program, const char *buf, + int optimize, uint32_t mask, char *errbuf, size_t errbuf_len); + +void SCBPFFree(struct bpf_program *program); + +#endif /* __UTIL_BPF_H__ */ diff --git a/src/util/buffer.c b/src/util/buffer.c new file mode 100644 index 000000000000..999c15ff8dde --- /dev/null +++ b/src/util/buffer.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util/debug.h" +#include "util/buffer.h" + +/* 10 mb */ +#define MAX_LIMIT 10485760 + +MemBuffer *MemBufferCreateNew(uint32_t size) +{ + sc_errno = SC_OK; + if (size > MAX_LIMIT) { + SCLogWarning("Mem buffer asked to create " + "buffer with size greater than API limit - %d", + MAX_LIMIT); + sc_errno = SC_EINVAL; + return NULL; + } + + uint32_t total_size = size + sizeof(MemBuffer); + + MemBuffer *buffer = SCCalloc(1, total_size); + if (unlikely(buffer == NULL)) { + sc_errno = SC_ENOMEM; + return NULL; + } + + buffer->size = size; + buffer->buffer = (uint8_t *)buffer + sizeof(MemBuffer); + + return buffer; +} + +/** \brief expand membuffer by size of 'expand_by' + * + * If expansion failed, buffer will still be valid. + * + * \retval result 0 ok, -1 expansion failed + */ +int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by) +{ + if (((*buffer)->size + expand_by) > MAX_LIMIT) { + SCLogWarning("Mem buffer asked to create " + "buffer with size greater than API limit - %d", + MAX_LIMIT); + return -1; + } + + uint32_t total_size = (*buffer)->size + sizeof(MemBuffer) + expand_by; + + MemBuffer *tbuffer = SCRealloc(*buffer, total_size); + if (unlikely(tbuffer == NULL)) { + return -1; + } + + *buffer = tbuffer; + (*buffer)->size += expand_by; + (*buffer)->buffer = (uint8_t *)tbuffer + sizeof(MemBuffer); + + SCLogDebug("expanded buffer by %u, size is now %u", expand_by, (*buffer)->size); + return 0; +} + +void MemBufferFree(MemBuffer *buffer) +{ + SCFree(buffer); + + return; +} diff --git a/src/util/buffer.h b/src/util/buffer.h new file mode 100644 index 000000000000..889c209357ce --- /dev/null +++ b/src/util/buffer.h @@ -0,0 +1,181 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_BUFFER_H__ +#define __UTIL_BUFFER_H__ + +typedef struct MemBuffer_ { + uint8_t *buffer; + uint32_t size; + uint32_t offset; +} MemBuffer; + +MemBuffer *MemBufferCreateNew(uint32_t size); +int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by); +void MemBufferFree(MemBuffer *buffer); + +/** + * \brief Reset the mem buffer. + * + * \param mem_buffer Pointer to the mem buffer instance. + */ +#define MemBufferReset(mem_buffer) \ + do { \ + (mem_buffer)->buffer[0] = 0; \ + (mem_buffer)->offset = 0; \ + } while (0) + +/** + * \brief Get the MemBuffers underlying buffer. + */ +#define MEMBUFFER_BUFFER(mem_buffer) (mem_buffer)->buffer + +/** + * \brief Get the MemBuffers current offset. + */ +#define MEMBUFFER_OFFSET(mem_buffer) (mem_buffer)->offset + +/** + * \brief Get the MemBuffers current size. + */ +#define MEMBUFFER_SIZE(mem_buffer) (mem_buffer)->size + +/** + * \brief Write a buffer to the file pointer. + * + * Accepted buffers can contain both printable and non-printable + * characters. Printable characters are written in the printable + * format and the non-printable chars are written in hex codes + * using the |XX| format. + * + * For example this would be the kind of output in the file - + * onetwo|EF|three|ED|five + * + * \param buffer Pointer to the src MemBuffer instance to write. + * \param fp Pointer to the file instance to write to. + */ +#define MemBufferPrintToFP(buffer, fp) \ + do { \ + uint32_t i; \ + \ + for (i = 0; i < (buffer)->offset; i++) { \ + if (isprint(buffer->buffer[i])) \ + fprintf(fp, "%c", (buffer)->buffer[i]); \ + else \ + fprintf(fp, "|%02X|", (buffer)->buffer[i]); \ + } \ + } while (0) + +/** + * \brief Write a buffer to the file pointer as a printable char string. + * + * \param buffer Pointer to the src MemBuffer instance to write. + * \param fp Pointer to the file instance to write to. + */ +#define MemBufferPrintToFPAsString(mem_buffer, fp) \ + ({ fwrite((mem_buffer)->buffer, sizeof(uint8_t), (mem_buffer)->offset, fp); }) + +/** + * \brief Write a buffer in hex format. + * + * \param buffer Pointer to the src MemBuffer instance to write. + * \param fp Pointer to the file instance to write to. + */ +#define MemBufferPrintToFPAsHex(mem_buffer, fp) \ + do { \ + uint32_t i; \ + \ + for (i = 0; i < (mem_buffer)->offset; i++) { \ + if (((mem_buffer)->offset % 8) == 0) \ + fprintf(fp, "\n"); \ + fprintf(fp, " %02X", (mem_buffer)->buffer[i]); \ + } \ + } while (0) + +/** + * \brief Write a raw buffer to the MemBuffer dst. + * + * When we say raw buffer it indicates a buffer that need not be + * purely a string buffer. It can be a pure string buffer or not or + * a mixture of both. Hence we don't accept any format strings. + * + * If the remaining space on the buffer is lesser than the length of + * the buffer to write, it is truncated to fit into the empty space. + * + * Also after every write a '\0' is appended. This would indicate + * that the total available space to write in the buffer is + * MemBuffer->size - 1 and not Membuffer->size. The reason we + * append the '\0' is for supporting writing pure string buffers + * as well, that can later be used by other string handling funcs. + * + * \param raw_buffer The buffer to write. + * \param raw_buffer_len Length of the above buffer. + */ +#define MemBufferWriteRaw(dst, raw_buffer, raw_buffer_len) \ + do { \ + uint32_t write_len; \ + \ + if (((raw_buffer_len) >= (dst)->size - (dst)->offset)) { \ + SCLogDebug("Truncating data write since it exceeded buffer limit of " \ + "- %" PRIu32, \ + (dst)->size); \ + write_len = ((dst)->size - (dst)->offset) - 1; \ + } else { \ + write_len = (raw_buffer_len); \ + } \ + \ + memcpy((dst)->buffer + (dst)->offset, (raw_buffer), write_len); \ + (dst)->offset += write_len; \ + dst->buffer[dst->offset] = '\0'; \ + } while (0) + +/** + * \brief Write a string buffer to the Membuffer dst. + * + * This function takes a format string and arguments for the format + * string like sprintf. + * + * An example usage of this is - + * MemBufferWriteString(mem_buffer_instance, \"%d - %s\", 10, \"one\"); + * + * \param dst The dst MemBuffer instance. + * \param format The format string. + * \param ... Variable arguments. + */ +#define MemBufferWriteString(dst, ...) \ + do { \ + int cw = snprintf( \ + (char *)(dst)->buffer + (dst)->offset, (dst)->size - (dst)->offset, __VA_ARGS__); \ + if (cw >= 0) { \ + if (((dst)->offset + cw) >= (dst)->size) { \ + SCLogDebug("Truncating data write since it exceeded buffer " \ + "limit of - %" PRIu32 "\n", \ + (dst)->size); \ + (dst)->offset = (dst)->size - 1; \ + } else { \ + (dst->offset) += cw; \ + } \ + } \ + } while (0) + +#endif /* __UTIL_BUFFER_H__ */ diff --git a/src/util/byte.c b/src/util/byte.c new file mode 100644 index 000000000000..08bebf8d5eb1 --- /dev/null +++ b/src/util/byte.c @@ -0,0 +1,1051 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Brian Rectanus + * + * Byte utility functions + */ + +#include "suricata-common.h" +#include "util/byte.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/validate.h" + +/** \brief Turn byte array into string. + * + * All non-printables are copied over, except for '\0', which is + * turned into literal \0 in the string. + * + * \param bytes byte array + * \param nbytes number of bytes + * \return string nul-terminated string or NULL on error + */ +char *BytesToString(const uint8_t *bytes, size_t nbytes) +{ + size_t n = nbytes + 1; + size_t nulls = 0; + + size_t u; + for (u = 0; u < nbytes; u++) { + if (bytes[u] == '\0') + nulls++; + } + n += nulls; + + char *string = SCCalloc(1, n); + if (string == NULL) + return NULL; + + if (nulls == 0) { + /* no nulls */ + memcpy(string, bytes, nbytes); + } else { + /* nulls present */ + char *dst = string; + for (u = 0; u < nbytes; u++) { + if (bytes[u] == '\0') { + *dst++ = '\\'; + *dst++ = '0'; + } else { + *dst++ = bytes[u]; + } + } + } + return string; +} + +/** \brief Turn byte array into string. + * + * All non-printables are copied over, except for '\0', which is + * turned into literal \0 in the string. + * + * \param bytes byte array + * \param nbytes number of bytes + * \param outstr[out] buffer to fill + * \param outlen size of outstr. Must be at least 2 * nbytes + 1 in size + */ +void BytesToStringBuffer(const uint8_t *bytes, size_t nbytes, char *outstr, size_t outlen) +{ + DEBUG_VALIDATE_BUG_ON(outlen < (nbytes * 2 + 1)); + + size_t n = nbytes + 1; + size_t nulls = 0; + + size_t u; + for (u = 0; u < nbytes; u++) { + if (bytes[u] == '\0') + nulls++; + } + n += nulls; + + char string[n]; + + if (nulls == 0) { + /* no nulls */ + memcpy(string, bytes, nbytes); + string[nbytes] = '\0'; + } else { + /* nulls present */ + char *dst = string; + for (u = 0; u < nbytes; u++) { + if (bytes[u] == '\0') { + *dst++ = '\\'; + *dst++ = '0'; + } else { + *dst++ = bytes[u]; + } + } + *dst = '\0'; + } + + strlcpy(outstr, string, outlen); +} + +int ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes) +{ + uint64_t i64; + int ret; + + /* Uint64 is limited to 8 bytes */ + if (len > 8) { + /** \todo Need standard return values */ + return -1; + } + + ret = ByteExtract(&i64, e, len, bytes); + if (ret <= 0) { + return ret; + } + + *res = (uint64_t)i64; + + return ret; +} + +int ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes) +{ + uint64_t i64; + int ret; + + /* Uint32 is limited to 4 bytes */ + if (len > 4) { + /** \todo Need standard return values */ + return -1; + } + + ret = ByteExtract(&i64, e, len, bytes); + if (ret <= 0) { + return ret; + } + + *res = (uint32_t)i64; + + return ret; +} + +int ByteExtractUint16(uint16_t *res, int e, uint16_t len, const uint8_t *bytes) +{ + uint64_t i64; + int ret; + + /* Uint16 is limited to 2 bytes */ + if (len > 2) { + /** \todo Need standard return values */ + return -1; + } + + ret = ByteExtract(&i64, e, len, bytes); + if (ret <= 0) { + return ret; + } + + *res = (uint16_t)i64; + + return ret; +} + +int ByteExtractString(uint64_t *res, int base, size_t len, const char *str, bool strict) +{ + const char *ptr = str; + char *endptr = NULL; + + /* 23 - This is the largest string (octal, with a zero prefix) that + * will not overflow uint64_t. The only way this length + * could be over 23 and still not overflow is if it were zero + * prefixed and we only support 1 byte of zero prefix for octal. + * + * "01777777777777777777777" = 0xffffffffffffffff + */ + char strbuf[24]; + + if (len > 23) { + SCLogDebug("len too large (23 max)"); + return -1; + } + + if (len) { + /* Extract out the string so it can be null terminated */ + memcpy(strbuf, str, len); + strbuf[len] = '\0'; + ptr = strbuf; + } + + errno = 0; + *res = strtoull(ptr, &endptr, base); + + if (errno == ERANGE) { + SCLogDebug("numeric value out of range"); + return -1; + /* If there is no numeric value in the given string then strtoull(), makes + endptr equals to ptr and return 0 as result */ + } else if (endptr == ptr && *res == 0) { + SCLogDebug("no numeric value"); + return -1; + } else if (endptr == ptr) { + SCLogDebug("invalid numeric value"); + return -1; + } else if (strict && *endptr != '\0') { + SCLogError("Extra characters following numeric value"); + return -1; + } + + return (endptr - ptr); +} + +int ByteExtractStringUint64(uint64_t *res, int base, size_t len, const char *str) +{ + return ByteExtractString(res, base, len, str, false); +} + +int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str) +{ + uint64_t i64; + + int ret = ByteExtractString(&i64, base, len, str, false); + if (ret <= 0) { + return ret; + } + if (i64 > UINT32_MAX) { + return -1; + } + + *res = (uint32_t)i64; + + if ((uint64_t)(*res) != i64) { + SCLogDebug("Numeric value out of range (%" PRIu64 " > %" PRIuMAX ")", i64, + (uintmax_t)UINT_MAX); + return -1; + } + + return ret; +} + +int ByteExtractStringUint16(uint16_t *res, int base, size_t len, const char *str) +{ + uint64_t i64; + + int ret = ByteExtractString(&i64, base, len, str, false); + if (ret <= 0) { + return ret; + } + if (i64 > UINT16_MAX) { + return -1; + } + + *res = (uint16_t)i64; + + if ((uint64_t)(*res) != i64) { + SCLogDebug("Numeric value out of range (%" PRIu64 " > %" PRIuMAX ")", i64, + (uintmax_t)USHRT_MAX); + return -1; + } + + return ret; +} + +int ByteExtractStringUint8(uint8_t *res, int base, size_t len, const char *str) +{ + uint64_t i64; + + int ret = ByteExtractString(&i64, base, len, str, false); + if (ret <= 0) { + return ret; + } + if (i64 > UINT8_MAX) { + return -1; + } + + *res = (uint8_t)i64; + + if ((uint64_t)(*res) != i64) { + SCLogDebug("Numeric value out of range (%" PRIu64 " > %" PRIuMAX ")", i64, + (uintmax_t)UCHAR_MAX); + return -1; + } + + return ret; +} + +int StringParseUint64(uint64_t *res, int base, size_t len, const char *str) +{ + return ByteExtractString(res, base, len, str, true); +} + +int StringParseUint32(uint32_t *res, int base, size_t len, const char *str) +{ + uint64_t i64; + + int ret = ByteExtractString(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 > UINT32_MAX) { + return -1; + } + + *res = (uint32_t)i64; + + if ((uint64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIu64 " > %" PRIuMAX ")", + i64, (uintmax_t)UINT_MAX); + return -1; + } + + return ret; +} + +int StringParseUint16(uint16_t *res, int base, size_t len, const char *str) +{ + uint64_t i64; + + int ret = ByteExtractString(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 > UINT16_MAX) { + return -1; + } + + *res = (uint16_t)i64; + + if ((uint64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIu64 " > %" PRIuMAX ")", + i64, (uintmax_t)USHRT_MAX); + return -1; + } + + return ret; +} + +int StringParseUint8(uint8_t *res, int base, size_t len, const char *str) +{ + uint64_t i64; + + int ret = ByteExtractString(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 > UINT8_MAX) { + return -1; + } + + *res = (uint8_t)i64; + + if ((uint64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIu64 " > %" PRIuMAX ")", + i64, (uintmax_t)UCHAR_MAX); + return -1; + } + + return ret; +} + +int StringParseU64RangeCheck( + uint64_t *res, int base, size_t len, const char *str, uint64_t min, uint64_t max) +{ + uint64_t u64; + + int ret = ByteExtractString(&u64, base, len, str, true); + if (ret <= 0) { + return ret; + } + + *res = u64; + + if (*res < min || *res > max) { + return -1; + } + + return ret; +} + +int StringParseU32RangeCheck( + uint32_t *res, int base, size_t len, const char *str, uint32_t min, uint32_t max) +{ + uint64_t u64; + + int ret = ByteExtractString(&u64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (u64 > UINT32_MAX) { + return -1; + } + + *res = (uint32_t)u64; + + if (*res < min || *res > max) { + return -1; + } + + if ((uint64_t)(*res) != u64) { + SCLogError("Numeric value out of range " + "(%" PRIu64 " > %" PRIuMAX ")", + u64, (uintmax_t)UINT_MAX); + return -1; + } + + return ret; +} + +int StringParseU16RangeCheck( + uint16_t *res, int base, size_t len, const char *str, uint16_t min, uint16_t max) +{ + uint64_t u64; + + int ret = ByteExtractString(&u64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (u64 > UINT16_MAX) { + return -1; + } + + *res = (uint16_t)u64; + + if (*res < min || *res > max) { + return -1; + } + + if ((uint64_t)(*res) != u64) { + SCLogError("Numeric value out of range " + "(%" PRIu64 " > %" PRIuMAX ")", + u64, (uintmax_t)USHRT_MAX); + return -1; + } + + return ret; +} + +int StringParseU8RangeCheck( + uint8_t *res, int base, size_t len, const char *str, uint8_t min, uint8_t max) +{ + uint64_t u64; + + int ret = ByteExtractString(&u64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (u64 > UINT8_MAX) { + return -1; + } + + *res = (uint8_t)u64; + + if (*res < min || *res > max) { + return -1; + } + + if ((uint64_t)(*res) != u64) { + SCLogError("Numeric value out of range " + "(%" PRIu64 " > %" PRIuMAX ")", + u64, (uintmax_t)UCHAR_MAX); + return -1; + } + + return ret; +} + +int ByteExtractStringSigned(int64_t *res, int base, size_t len, const char *str, bool strict) +{ + const char *ptr = str; + char *endptr; + + /* 23 - This is the largest string (octal, with a zero prefix) that + * will not overflow int64_t. The only way this length + * could be over 23 and still not overflow is if it were zero + * prefixed and we only support 1 byte of zero prefix for octal. + * + * "-0777777777777777777777" = 0xffffffffffffffff + */ + char strbuf[24]; + + if (len > 23) { + SCLogError("len too large (23 max)"); + return -1; + } + + if (len) { + /* Extract out the string so it can be null terminated */ + memcpy(strbuf, str, len); + strbuf[len] = '\0'; + ptr = strbuf; + } + + errno = 0; + *res = strtoll(ptr, &endptr, base); + + if (errno == ERANGE) { + SCLogError("Numeric value out of range"); + return -1; + } else if (endptr == str) { + SCLogError("Invalid numeric value"); + return -1; + } else if (strict && len && *endptr != '\0') { + SCLogError("Extra characters following numeric value"); + return -1; + } + + // fprintf(stderr, "ByteExtractStringSigned: Extracted base %d: 0x%" PRIx64 "\n", base, *res); + + return (endptr - ptr); +} + +int ByteExtractStringInt64(int64_t *res, int base, size_t len, const char *str) +{ + return ByteExtractStringSigned(res, base, len, str, false); +} + +int ByteExtractStringInt32(int32_t *res, int base, size_t len, const char *str) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, false); + if (ret <= 0) { + return ret; + } + if (i64 < INT32_MIN || i64 > INT32_MAX) { + return -1; + } + + *res = (int32_t)i64; + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)INT_MAX); + return -1; + } + + return ret; +} + +int ByteExtractStringInt16(int16_t *res, int base, size_t len, const char *str) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, false); + if (ret <= 0) { + return ret; + } + if (i64 < INT16_MIN || i64 > INT16_MAX) { + return -1; + } + + *res = (int16_t)i64; + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)SHRT_MAX); + return -1; + } + + return ret; +} + +int ByteExtractStringInt8(int8_t *res, int base, size_t len, const char *str) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, false); + if (ret <= 0) { + return ret; + } + if (i64 < INT8_MIN || i64 > INT8_MAX) { + return -1; + } + + *res = (int8_t)i64; + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)CHAR_MAX); + return -1; + } + + return ret; +} + +int StringParseInt64(int64_t *res, int base, size_t len, const char *str) +{ + return ByteExtractStringSigned(res, base, len, str, true); +} + +int StringParseInt32(int32_t *res, int base, size_t len, const char *str) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 < INT32_MIN || i64 > INT32_MAX) { + return -1; + } + + *res = (int32_t)i64; + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)INT_MAX); + return -1; + } + + return ret; +} + +int StringParseInt16(int16_t *res, int base, size_t len, const char *str) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 < INT16_MIN || i64 > INT16_MAX) { + return -1; + } + + *res = (int16_t)i64; + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)SHRT_MAX); + return -1; + } + + return ret; +} + +int StringParseInt8(int8_t *res, int base, size_t len, const char *str) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 < INT8_MIN || i64 > INT8_MAX) { + return -1; + } + + *res = (int8_t)i64; + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)CHAR_MAX); + return -1; + } + + return ret; +} + +int StringParseI64RangeCheck( + int64_t *res, int base, size_t len, const char *str, int64_t min, int64_t max) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + + *res = i64; + if (*res < min || *res > max) { + return -1; + } + + return ret; +} + +int StringParseI32RangeCheck( + int32_t *res, int base, size_t len, const char *str, int32_t min, int32_t max) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 < INT32_MIN || i64 > INT32_MAX) { + return -1; + } + + *res = (int32_t)i64; + + if (*res < min || *res > max) { + return -1; + } + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)INT_MAX); + return -1; + } + + return ret; +} + +int StringParseI16RangeCheck( + int16_t *res, int base, size_t len, const char *str, int16_t min, int16_t max) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 < INT16_MIN || i64 > INT16_MAX) { + return -1; + } + + *res = (int16_t)i64; + + if (*res < min || *res > max) { + return -1; + } + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)SHRT_MAX); + return -1; + } + + return ret; +} + +int StringParseI8RangeCheck( + int8_t *res, int base, size_t len, const char *str, int8_t min, int8_t max) +{ + int64_t i64; + int ret; + + ret = ByteExtractStringSigned(&i64, base, len, str, true); + if (ret <= 0) { + return ret; + } + if (i64 < INT8_MIN || i64 > INT8_MAX) { + return -1; + } + + *res = (int8_t)i64; + + if (*res < min || *res > max) { + return -1; + } + + if ((int64_t)(*res) != i64) { + SCLogError("Numeric value out of range " + "(%" PRIi64 " > %" PRIiMAX ")\n", + i64, (intmax_t)CHAR_MAX); + return -1; + } + + return ret; +} + +/* UNITTESTS */ +#ifdef UNITTESTS + +static int ByteTest01(void) +{ + uint16_t val = 0x0102; + uint16_t i16 = 0xbfbf; + uint8_t bytes[2] = { 0x02, 0x01 }; + int ret = ByteExtractUint16(&i16, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); + + if ((ret == 2) && (i16 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest02(void) +{ + uint16_t val = 0x0102; + uint16_t i16 = 0xbfbf; + uint8_t bytes[2] = { 0x01, 0x02 }; + int ret = ByteExtractUint16(&i16, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); + + if ((ret == 2) && (i16 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest03(void) +{ + uint32_t val = 0x01020304; + uint32_t i32 = 0xbfbfbfbf; + uint8_t bytes[4] = { 0x04, 0x03, 0x02, 0x01 }; + int ret = ByteExtractUint32(&i32, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); + + if ((ret == 4) && (i32 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest04(void) +{ + uint32_t val = 0x01020304; + uint32_t i32 = 0xbfbfbfbf; + uint8_t bytes[4] = { 0x01, 0x02, 0x03, 0x04 }; + int ret = ByteExtractUint32(&i32, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); + + if ((ret == 4) && (i32 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest05(void) +{ + uint64_t val = 0x0102030405060708ULL; + uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; + uint8_t bytes[8] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }; + int ret = ByteExtractUint64(&i64, BYTE_LITTLE_ENDIAN, sizeof(bytes), bytes); + + if ((ret == 8) && (i64 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest06(void) +{ + uint64_t val = 0x0102030405060708ULL; + uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; + uint8_t bytes[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + int ret = ByteExtractUint64(&i64, BYTE_BIG_ENDIAN, sizeof(bytes), bytes); + + if ((ret == 8) && (i64 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest07(void) +{ + const char str[] = "1234567890"; + uint64_t val = 1234567890; + uint64_t i64 = 0xbfbfbfbfbfbfbfbfULL; + int ret = ByteExtractStringUint64(&i64, 10, sizeof(str) - 1, str); + + if ((ret == 10) && (i64 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest08(void) +{ + const char str[] = "1234567890"; + uint32_t val = 1234567890; + uint32_t i32 = 0xbfbfbfbf; + int ret = ByteExtractStringUint32(&i32, 10, sizeof(str) - 1, str); + + if ((ret == 10) && (i32 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest09(void) +{ + const char str[] = "12345"; + uint16_t val = 12345; + uint16_t i16 = 0xbfbf; + int ret = ByteExtractStringUint16(&i16, 10, sizeof(str) - 1, str); + + if ((ret == 5) && (i16 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest10(void) +{ + const char str[] = "123"; + uint8_t val = 123; + uint8_t i8 = 0xbf; + int ret = ByteExtractStringUint8(&i8, 10, sizeof(str) - 1, str); + + if ((ret == 3) && (i8 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest11(void) +{ + const char str[] = "-1234567890"; + int64_t val = -1234567890; + int64_t i64 = 0xbfbfbfbfbfbfbfbfULL; + int ret = ByteExtractStringInt64(&i64, 10, sizeof(str) - 1, str); + + if ((ret == 11) && (i64 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest12(void) +{ + const char str[] = "-1234567890"; + int32_t val = -1234567890; + int32_t i32 = 0xbfbfbfbf; + int ret = ByteExtractStringInt32(&i32, 10, sizeof(str) - 1, str); + + if ((ret == 11) && (i32 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest13(void) +{ + const char str[] = "-12345"; + int16_t val = -12345; + int16_t i16 = 0xbfbf; + int ret = ByteExtractStringInt16(&i16, 10, sizeof(str) - 1, str); + + if ((ret == 6) && (i16 == val)) { + return 1; + } + + return 0; +} + +static int ByteTest14(void) +{ + const char str[] = "-123"; + int8_t val = -123; + int8_t i8 = 0xbf; + int ret = ByteExtractStringInt8(&i8, 10, sizeof(str) - 1, str); + + if ((ret == 4) && (i8 == val)) { + return 1; + } + + return 0; +} + +/** \test max u32 value */ +static int ByteTest15(void) +{ + const char str[] = "4294967295"; + uint32_t val = 4294967295UL; + uint32_t u32 = 0xffffffff; + + int ret = ByteExtractStringUint32(&u32, 10, sizeof(str) - 1, str); + if ((ret == 10) && (u32 == val)) { + return 1; + } + + return 0; +} + +/** \test max u32 value + 1 */ +static int ByteTest16(void) +{ + const char str[] = "4294967296"; + uint32_t u32 = 0; + + int ret = ByteExtractStringUint32(&u32, 10, sizeof(str) - 1, str); + if (ret != 0) { + return 1; + } + + return 0; +} + +void ByteRegisterTests(void) +{ + UtRegisterTest("ByteTest01", ByteTest01); + UtRegisterTest("ByteTest02", ByteTest02); + UtRegisterTest("ByteTest03", ByteTest03); + UtRegisterTest("ByteTest04", ByteTest04); + UtRegisterTest("ByteTest05", ByteTest05); + UtRegisterTest("ByteTest06", ByteTest06); + UtRegisterTest("ByteTest07", ByteTest07); + UtRegisterTest("ByteTest08", ByteTest08); + UtRegisterTest("ByteTest09", ByteTest09); + UtRegisterTest("ByteTest10", ByteTest10); + UtRegisterTest("ByteTest11", ByteTest11); + UtRegisterTest("ByteTest12", ByteTest12); + UtRegisterTest("ByteTest13", ByteTest13); + UtRegisterTest("ByteTest14", ByteTest14); + UtRegisterTest("ByteTest15", ByteTest15); + UtRegisterTest("ByteTest16", ByteTest16); +} +#endif /* UNITTESTS */ diff --git a/src/util/byte.h b/src/util/byte.h new file mode 100644 index 000000000000..af00d35aabad --- /dev/null +++ b/src/util/byte.h @@ -0,0 +1,497 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Brian Rectanus + */ + +#ifndef __UTIL_BYTE_H__ +#define __UTIL_BYTE_H__ + +#include + +#define BYTE_BIG_ENDIAN 0 +#define BYTE_LITTLE_ENDIAN 1 + +/** Wrappers for OS dependent byte swapping functions */ +#ifdef OS_FREEBSD +#include +#define SCByteSwap16(x) bswap16(x) +#define SCByteSwap32(x) bswap32(x) +#define SCByteSwap64(x) bswap64(x) +#elif defined __OpenBSD__ +#include +#define SCByteSwap16(x) swap16(x) +#define SCByteSwap32(x) swap32(x) +#define SCByteSwap64(x) swap64(x) +#elif OS_DARWIN +#include +#define SCByteSwap16(x) OSSwapInt16(x) +#define SCByteSwap32(x) OSSwapInt32(x) +#define SCByteSwap64(x) OSSwapInt64(x) +#elif defined(__WIN32) || defined(_WIN32) || defined(sun) +/* Quick & dirty solution, nothing seems to exist for this in Win32 API */ +#define SCByteSwap16(x) ((((x)&0xff00) >> 8) | (((x)&0x00ff) << 8)) +#define SCByteSwap32(x) \ + ((((x)&0xff000000) >> 24) | (((x)&0x00ff0000) >> 8) | (((x)&0x0000ff00) << 8) | \ + (((x)&0x000000ff) << 24)) +#define SCByteSwap64(x) \ + ((((x)&0xff00000000000000ull) >> 56) | (((x)&0x00ff000000000000ull) >> 40) | \ + (((x)&0x0000ff0000000000ull) >> 24) | (((x)&0x000000ff00000000ull) >> 8) | \ + (((x)&0x00000000ff000000ull) << 8) | (((x)&0x0000000000ff0000ull) << 24) | \ + (((x)&0x000000000000ff00ull) << 40) | (((x)&0x00000000000000ffull) << 56)) +#else +#include +#define SCByteSwap16(x) bswap_16(x) +#define SCByteSwap32(x) bswap_32(x) +#define SCByteSwap64(x) bswap_64(x) +#endif /* OS_FREEBSD */ + +/** \brief Turn byte array into string. + * + * All non-printables are copied over, except for '\0', which is + * turned into literal \0 in the string. + * + * \param bytes byte array + * \param nbytes number of bytes + * \return string nul-terminated string or NULL on error + */ +char *BytesToString(const uint8_t *bytes, size_t nbytes); +void BytesToStringBuffer(const uint8_t *bytes, size_t nbytes, char *outstr, size_t outlen); + +/** + * Extract bytes from a byte string and convert to a unint64_t. + * + * \param res Stores result + * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) + * \param len Number of bytes to extract (8 max) + * \param bytes Data to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes); + +/** + * Extract bytes from a byte string and convert to a uint32_t. + * + * \param res Stores result + * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) + * \param len Number of bytes to extract (8 max) + * \param bytes Data to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes); + +/** + * Extract bytes from a byte string and convert to a unint16_t. + * + * \param res Stores result + * \param e Endianness (BYTE_BIG_ENDIAN or BYTE_LITTLE_ENDIAN) + * \param len Number of bytes to extract (8 max) + * \param bytes Data to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractUint16(uint16_t *res, int e, uint16_t len, const uint8_t *bytes); + +/** + * Extract unsigned integer value from a string. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * \param bool Enable strict check for parsers + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractString( + uint64_t *res, int base, size_t len, const char *str, bool strict); + +/** + * Extract unsigned integer value from a string as uint64_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringUint64(uint64_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint32_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint16_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringUint16(uint16_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint8_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringUint8(uint8_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * \param bool Enable strict check for parsers + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringSigned( + int64_t *res, int base, size_t len, const char *str, bool strict); + +/** + * Extract signed integer value from a string as uint64_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringInt64(int64_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string as uint32_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringInt32(int32_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string as uint16_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringInt16(int16_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string as uint8_t. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED ByteExtractStringInt8(int8_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint64_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseUint64(uint64_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint32_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseUint32(uint32_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint16_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseUint16(uint16_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint8_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseUint8(uint8_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string as int64_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseInt64(int64_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string as int32_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseInt32(int32_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string as int16_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseInt16(int16_t *res, int base, size_t len, const char *str); + +/** + * Extract signed integer value from a string as int8_t strictly. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int StringParseInt8(int8_t *res, int base, size_t len, const char *str); + +/** + * Extract unsigned integer value from a string as uint64_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseU64RangeCheck( + uint64_t *res, int base, size_t len, const char *str, uint64_t min, uint64_t max); + +/** + * Extract unsigned integer value from a string as uint32_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseU32RangeCheck( + uint32_t *res, int base, size_t len, const char *str, uint32_t min, uint32_t max); + +/** + * Extract unsigned integer value from a string as uint16_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseU16RangeCheck( + uint16_t *res, int base, size_t len, const char *str, uint16_t min, uint16_t max); + +/** + * Extract unsigned integer value from a string as uint8_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseU8RangeCheck( + uint8_t *res, int base, size_t len, const char *str, uint8_t min, uint8_t max); + +/** + * Extract signed integer value from a string as int64_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseI64RangeCheck( + int64_t *res, int base, size_t len, const char *str, int64_t min, int64_t max); + +/** + * Extract signed integer value from a string as int32_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseI32RangeCheck( + int32_t *res, int base, size_t len, const char *str, int32_t min, int32_t max); + +/** + * Extract signed integer value from a string as int16_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseI16RangeCheck( + int16_t *res, int base, size_t len, const char *str, int16_t min, int16_t max); + +/** + * Extract signed integer value from a string as int8_t strictly within the range. + * + * \param res Stores result + * \param base Base of the number to extract + * \param len Number of bytes to extract (23 max or 0 for unbounded) + * \param str String to extract from + * + * \return n Number of bytes extracted on success + * \return -1 On error + */ +int WARN_UNUSED StringParseI8RangeCheck( + int8_t *res, int base, size_t len, const char *str, int8_t min, int8_t max); + +#ifdef UNITTESTS +void ByteRegisterTests(void); +#endif /* UNITTESTS */ + +/** ------ Inline functions ----- */ +static inline int WARN_UNUSED ByteExtract(uint64_t *res, int e, uint16_t len, const uint8_t *bytes) +{ + if ((e != BYTE_BIG_ENDIAN) && (e != BYTE_LITTLE_ENDIAN)) { + /** \todo Need standard return values */ + return -1; + } + + *res = 0; + + /* Go through each byte and merge it into the result in the correct order */ + /** \todo Probably a more efficient way to do this. */ + for (int i = 0; i < len; i++) { + uint64_t b; + if (e == BYTE_LITTLE_ENDIAN) { + b = bytes[i]; + } else { + b = bytes[len - i - 1]; + } + + *res |= (b << ((i & 7) << 3)); + } + + return len; +} + +#endif /* __UTIL_BYTE_H__ */ diff --git a/src/util/checksum.c b/src/util/checksum.c new file mode 100644 index 000000000000..d12081a8569c --- /dev/null +++ b/src/util/checksum.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2011-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + * Util functions for checksum. + */ + +#include "suricata-common.h" +#include "util/checksum.h" + +int ReCalculateChecksum(Packet *p) +{ + if (PKT_IS_IPV4(p)) { + if (PKT_IS_TCP(p)) { + /* TCP */ + p->tcph->th_sum = 0; + p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, + (p->payload_len + TCP_GET_HLEN(p)), 0); + } else if (PKT_IS_UDP(p)) { + p->udph->uh_sum = 0; + p->udph->uh_sum = UDPV4Checksum( + p->ip4h->s_ip_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); + } + /* IPV4 */ + p->ip4h->ip_csum = 0; + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h), 0); + } else if (PKT_IS_IPV6(p)) { + /* just TCP for IPV6 */ + if (PKT_IS_TCP(p)) { + p->tcph->th_sum = 0; + p->tcph->th_sum = TCPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, + (p->payload_len + TCP_GET_HLEN(p)), 0); + } else if (PKT_IS_UDP(p)) { + p->udph->uh_sum = 0; + p->udph->uh_sum = UDPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->udph, + (p->payload_len + UDP_HEADER_LEN), 0); + } + } + + return 0; +} + +/** + * \brief Check if the number of invalid checksums indicate checksum + * offloading in place. + * + * \retval 1 yes, offloading in place + * \retval 0 no, no offloading used + */ +int ChecksumAutoModeCheck(uint64_t thread_count, uint64_t iface_count, uint64_t iface_fail) +{ + if (thread_count == CHECKSUM_SAMPLE_COUNT) { + if (iface_fail != 0) { + if ((iface_count / iface_fail) < CHECKSUM_INVALID_RATIO) { + SCLogInfo("More than 1/%dth of packets have an invalid " + "checksum, assuming checksum offloading is used " + "(%" PRIu64 "/%" PRIu64 ")", + CHECKSUM_INVALID_RATIO, iface_fail, iface_count); + return 1; + } else { + SCLogInfo("Less than 1/%dth of packets have an invalid " + "checksum, assuming checksum offloading is NOT used " + "(%" PRIu64 "/%" PRIu64 ")", + CHECKSUM_INVALID_RATIO, iface_fail, iface_count); + } + } else { + SCLogInfo("No packets with invalid checksum, assuming " + "checksum offloading is NOT used"); + } + } + return 0; +} diff --git a/src/util/checksum.h b/src/util/checksum.h new file mode 100644 index 000000000000..33f14bdd6c7e --- /dev/null +++ b/src/util/checksum.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2011-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#ifndef __UTIL_CHECKSUM_H__ +#define __UTIL_CHECKSUM_H__ + +#include "decode.h" + +int ReCalculateChecksum(Packet *p); +int ChecksumAutoModeCheck(uint64_t thread_count, uint64_t iface_count, uint64_t iface_fail); + +/* constant linked with detection of interface with + * invalid checksums */ +#define CHECKSUM_SAMPLE_COUNT 1000ULL +#define CHECKSUM_INVALID_RATIO 10 + +#endif diff --git a/src/util/cidr.c b/src/util/cidr.c new file mode 100644 index 000000000000..050a79eb8b7c --- /dev/null +++ b/src/util/cidr.c @@ -0,0 +1,157 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * CIDR utility functions + */ + +#include "suricata-common.h" +#include "util/cidr.h" +#include "util/debug.h" +#include "util/unittest.h" + +/** \brief Turn 32 bit mask into CIDR + * + * \retval cidr The cidr value or -1 if the netmask can't be expressed as cidr + */ +int CIDRFromMask(uint32_t netmask) +{ + netmask = ntohl(netmask); + if (netmask == 0) { + return 0; + } + int p = 0; + bool seen_1 = false; + while (netmask > 0) { + if (netmask & 1) { + seen_1 = true; + p++; + } else { + if (seen_1) { + return -1; + } + } + netmask >>= 1; + } + return p; +} + +uint32_t CIDRGet(int cidr) +{ + if (cidr <= 0 || cidr > 32) + return 0; + uint32_t netmask = htonl(0xFFFFFFFF << (32UL - (uint32_t)cidr)); + SCLogDebug("CIDR %d -> netmask %08X", cidr, netmask); + return netmask; +} + +/** + * \brief Creates a cidr ipv6 netblock, based on the cidr netblock value. + * + * For example if we send a cidr of 7 as argument, an ipv6 address + * mask of the value FE:00:00:00:00:00:00:00 is created and updated + * in the argument struct in6_addr *in6. + * + * \todo I think for the final section: while (cidr > 0), we can simply + * replace it with a + * if (cidr > 0) { + * in6->s6_addr[i] = -1 << (8 - cidr); + * + * \param cidr The value of the cidr. + * \param in6 Pointer to an ipv6 address structure(struct in6_addr) which will + * hold the cidr netblock result. + */ +void CIDRGetIPv6(int cidr, struct in6_addr *in6) +{ + int i = 0; + + memset(in6, 0, sizeof(struct in6_addr)); + + while (cidr > 8) { + in6->s6_addr[i] = 0xff; + cidr -= 8; + i++; + } + + while (cidr > 0) { + in6->s6_addr[i] |= 0x80; + if (--cidr > 0) + in6->s6_addr[i] = in6->s6_addr[i] >> 1; + } +} + +#ifdef UNITTESTS + +static int CIDRFromMaskTest01(void) +{ + struct in_addr in; + int v = inet_pton(AF_INET, "255.255.255.0", &in); + + FAIL_IF(v <= 0); + FAIL_IF_NOT(24 == CIDRFromMask(in.s_addr)); + + PASS; +} + +static int CIDRFromMaskTest02(void) +{ + struct in_addr in; + int v = inet_pton(AF_INET, "255.255.0.42", &in); + + FAIL_IF(v <= 0); + FAIL_IF_NOT(-1 == CIDRFromMask(in.s_addr)); + + PASS; +} + +static int CIDRFromMaskTest03(void) +{ + struct in_addr in; + int v = inet_pton(AF_INET, "0.0.0.0", &in); + + FAIL_IF(v <= 0); + FAIL_IF_NOT(0 == CIDRFromMask(in.s_addr)); + + PASS; +} + +static int CIDRFromMaskTest04(void) +{ + struct in_addr in; + int v = inet_pton(AF_INET, "255.255.255.255", &in); + + FAIL_IF(v <= 0); + FAIL_IF_NOT(32 == CIDRFromMask(in.s_addr)); + + PASS; +} + +#endif /* UNITTESTS */ + +void UtilCIDRTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("CIDRFromMaskTest01", CIDRFromMaskTest01); + UtRegisterTest("CIDRFromMaskTest02", CIDRFromMaskTest02); + UtRegisterTest("CIDRFromMaskTest03", CIDRFromMaskTest03); + UtRegisterTest("CIDRFromMaskTest04", CIDRFromMaskTest04); +#endif /* UNITTESTS */ +} diff --git a/src/util/cidr.h b/src/util/cidr.h new file mode 100644 index 000000000000..caa0c7a2bd4f --- /dev/null +++ b/src/util/cidr.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_NETMASK_H__ +#define __UTIL_NETMASK_H__ + +int CIDRFromMask(uint32_t netmask); +uint32_t CIDRGet(int); +void CIDRGetIPv6(int cidr, struct in6_addr *in6); + +void UtilCIDRTests(void); + +#endif /* __UTIL_NETMASK_H__ */ diff --git a/src/util/classification-config.c b/src/util/classification-config.c new file mode 100644 index 000000000000..9340973f44a5 --- /dev/null +++ b/src/util/classification-config.c @@ -0,0 +1,791 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Used for parsing a classification.config file + */ + +#include "suricata-common.h" +#include "../detect.h" +#include "detect-engine.h" +#include "util/hash.h" + +#include "../conf.h" +#include "util/classification-config.h" +#include "util/unittest.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/fmemopen.h" +#include "util/byte.h" + +/* Regex to parse the classtype argument from a Signature. The first substring + * holds the classtype name, the second substring holds the classtype the + * classtype description, and the third argument holds the priority */ +#define DETECT_CLASSCONFIG_REGEX \ + "^\\s*config\\s*classification\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*,\\s*(.+)\\s*,\\s*(\\d+)" \ + "\\s*$" + +/* Default path for the classification.config file */ +#if defined OS_WIN32 || defined __CYGWIN__ +#define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\classification.config" +#else +#define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/classification.config" +#endif + +uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen); +char SCClassConfClasstypeHashCompareFunc( + void *data1, uint16_t datalen1, void *data2, uint16_t datalen2); +void SCClassConfClasstypeHashFree(void *ch); +static const char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx); + +static SCClassConfClasstype *SCClassConfAllocClasstype( + uint16_t classtype_id, const char *classtype, const char *classtype_desc, int priority); +static void SCClassConfDeAllocClasstype(SCClassConfClasstype *ct); + +void SCClassConfInit(DetectEngineCtx *de_ctx) +{ + int en; + PCRE2_SIZE eo; + int opts = 0; + + de_ctx->class_conf_regex = pcre2_compile( + (PCRE2_SPTR8)DETECT_CLASSCONFIG_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + if (de_ctx->class_conf_regex == NULL) { + PCRE2_UCHAR errbuffer[256]; + pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); + SCLogWarning("pcre2 compile of \"%s\" failed at " + "offset %d: %s", + DETECT_CLASSCONFIG_REGEX, (int)eo, errbuffer); + return; + } + de_ctx->class_conf_regex_match = + pcre2_match_data_create_from_pattern(de_ctx->class_conf_regex, NULL); + return; +} + +void SCClassConfDeinit(DetectEngineCtx *de_ctx) +{ + if (de_ctx->class_conf_regex != NULL) { + pcre2_code_free(de_ctx->class_conf_regex); + de_ctx->class_conf_regex = NULL; + } + if (de_ctx->class_conf_regex_match != NULL) { + pcre2_match_data_free(de_ctx->class_conf_regex_match); + de_ctx->class_conf_regex_match = NULL; + } +} + +/** + * \brief Inits the context to be used by the Classification Config parsing API. + * + * This function initializes the hash table to be used by the Detection + * Engine Context to hold the data from the classification.config file, + * obtains the file desc to parse the classification.config file, and + * inits the regex used to parse the lines from classification.config + * file. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param fd Pointer to already opened file + * + * \note even if the file open fails we will keep the de_ctx->class_conf_ht + * initialized. + * + * \retval fp NULL on error + */ +static FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) +{ + /* init the hash table to be used by the classification config Classtypes */ + de_ctx->class_conf_ht = HashTableInit(128, SCClassConfClasstypeHashFunc, + SCClassConfClasstypeHashCompareFunc, SCClassConfClasstypeHashFree); + if (de_ctx->class_conf_ht == NULL) { + SCLogError("Error initializing the hash " + "table"); + return NULL; + } + + /* if it is not NULL, use the file descriptor. The hack so that we can + * avoid using a dummy classification file for testing purposes and + * instead use an input stream against a buffer containing the + * classification strings */ + if (fd == NULL) { + const char *filename = SCClassConfGetConfFilename(de_ctx); + if ((fd = fopen(filename, "r")) == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) + return NULL; // silently fail +#endif + SCLogWarning("could not open: \"%s\": %s", filename, strerror(errno)); + return NULL; + } + } + + return fd; +} + +/** + * \brief Returns the path for the Classification Config file. We check if we + * can retrieve the path from the yaml conf file. If it is not present, + * return the default path for the classification file which is + * "./classification.config". + * + * \retval log_filename Pointer to a string containing the path for the + * Classification Config file. + */ +static const char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx) +{ + const char *log_filename = NULL; + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; + snprintf(config_value, sizeof(config_value), "%s.classification-file", + de_ctx->config_prefix); + + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &log_filename) != 1) { + if (ConfGet("classification-file", &log_filename) != 1) { + log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; + } + } + } else { + if (ConfGet("classification-file", &log_filename) != 1) { + log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; + } + } + + return log_filename; +} + +/** + * \brief Releases resources used by the Classification Config API. + */ +static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) +{ + if (fd != NULL) { + fclose(fd); + } +} + +/** + * \brief Releases resources used by the Classification Config API. + */ +void SCClassConfDeInitContext(DetectEngineCtx *de_ctx) +{ + if (de_ctx->class_conf_ht != NULL) + HashTableFree(de_ctx->class_conf_ht); + + de_ctx->class_conf_ht = NULL; + + return; +} + +/** + * \brief Converts a string to lowercase. + * + * \param str Pointer to the string to be converted. + */ +static char *SCClassConfStringToLowercase(const char *str) +{ + char *new_str = NULL; + char *temp_str = NULL; + + if ((new_str = SCStrdup(str)) == NULL) { + SCLogError("Error allocating memory"); + return NULL; + } + + temp_str = new_str; + while (*temp_str != '\0') { + *temp_str = u8_tolower((unsigned char)*temp_str); + temp_str++; + } + + return new_str; +} + +/** + * \brief Parses a line from the classification file and adds it to Classtype + * hash table in DetectEngineCtx, i.e. DetectEngineCtx->class_conf_ht. + * + * \param rawstr Pointer to the string to be parsed. + * \param index Relative index of the string to be parsed. + * \param de_ctx Pointer to the Detection Engine Context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCClassConfAddClasstype(DetectEngineCtx *de_ctx, char *rawstr, uint16_t index) +{ + char ct_name[CLASSTYPE_NAME_MAX_LEN]; + char ct_desc[CLASSTYPE_DESC_MAX_LEN]; + char ct_priority_str[16]; + uint32_t ct_priority = 0; + uint16_t ct_id = index; + + SCClassConfClasstype *ct_new = NULL; + SCClassConfClasstype *ct_lookup = NULL; + + int ret = 0; + + ret = pcre2_match(de_ctx->class_conf_regex, (PCRE2_SPTR8)rawstr, strlen(rawstr), 0, 0, + de_ctx->class_conf_regex_match, NULL); + if (ret < 0) { + SCLogError("Invalid Classtype in " + "classification.config file %s: \"%s\"", + SCClassConfGetConfFilename(de_ctx), rawstr); + goto error; + } + + size_t copylen = sizeof(ct_name); + /* retrieve the classtype name */ + ret = pcre2_substring_copy_bynumber( + de_ctx->class_conf_regex_match, 1, (PCRE2_UCHAR8 *)ct_name, ©len); + if (ret < 0) { + SCLogInfo("pcre2_substring_copy_bynumber() failed"); + goto error; + } + + /* retrieve the classtype description */ + copylen = sizeof(ct_desc); + ret = pcre2_substring_copy_bynumber( + de_ctx->class_conf_regex_match, 2, (PCRE2_UCHAR8 *)ct_desc, ©len); + if (ret < 0) { + SCLogInfo("pcre2_substring_copy_bynumber() failed"); + goto error; + } + + /* retrieve the classtype priority */ + copylen = sizeof(ct_priority_str); + ret = pcre2_substring_copy_bynumber( + de_ctx->class_conf_regex_match, 3, (PCRE2_UCHAR8 *)ct_priority_str, ©len); + if (ret < 0) { + SCLogInfo("pcre2_substring_copy_bynumber() failed"); + goto error; + } + if (StringParseUint32(&ct_priority, 10, 0, (const char *)ct_priority_str) < 0) { + goto error; + } + + /* Create a new instance of the parsed Classtype string */ + ct_new = SCClassConfAllocClasstype(ct_id, ct_name, ct_desc, ct_priority); + if (ct_new == NULL) + goto error; + + /* Check if the Classtype is present in the HashTable. In case it's present + * ignore it, as it is a duplicate. If not present, add it to the table */ + ct_lookup = HashTableLookup(de_ctx->class_conf_ht, ct_new, 0); + if (ct_lookup == NULL) { + if (HashTableAdd(de_ctx->class_conf_ht, ct_new, 0) < 0) + SCLogDebug("HashTable Add failed"); + } else { + SCLogDebug("Duplicate classtype found inside classification.config"); + if (ct_new->classtype_desc) + SCFree(ct_new->classtype_desc); + if (ct_new->classtype) + SCFree(ct_new->classtype); + SCFree(ct_new); + } + + return 0; + +error: + return -1; +} + +/** + * \brief Checks if a string is a comment or a blank line. + * + * Comments lines are lines of the following format - + * "# This is a comment string" or + * " # This is a comment string". + * + * \param line String that has to be checked + * + * \retval 1 On the argument string being a comment or blank line + * \retval 0 Otherwise + */ +static int SCClassConfIsLineBlankOrComment(char *line) +{ + while (*line != '\0') { + /* we have a comment */ + if (*line == '#') + return 1; + + /* this line is neither a comment line, nor a blank line */ + if (!isspace((unsigned char)*line)) + return 0; + + line++; + } + + /* we have a blank line */ + return 1; +} + +/** + * \brief Parses the Classification Config file and updates the + * DetectionEngineCtx->class_conf_ht with the Classtype information. + * + * \param de_ctx Pointer to the Detection Engine Context. + */ +static bool SCClassConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) +{ + char line[1024]; + uint16_t i = 1; + int errors = 0; + + while (fgets(line, sizeof(line), fd) != NULL) { + if (SCClassConfIsLineBlankOrComment(line)) + continue; + + if (SCClassConfAddClasstype(de_ctx, line, i) == -1) { + errors++; + } else { + i++; + } + } + +#ifdef UNITTESTS + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) + SCLogInfo("tenant id %d: Added \"%d\" classification types from the classification file", + de_ctx->tenant_id, de_ctx->class_conf_ht->count); + else + SCLogInfo("Added \"%d\" classification types from the classification file", + de_ctx->class_conf_ht->count); +#endif + + return errors == 0; +} + +/** + * \internal + * \brief Returns a new SCClassConfClasstype instance. The classtype string + * is converted into lowercase, before being assigned to the instance. + * + * \param classtype Pointer to the classification type. + * \param classtype_desc Pointer to the classification type description. + * \param priority Holds the priority for the classification type. + * + * \retval ct Pointer to the new instance of SCClassConfClasstype on success; + * NULL on failure. + */ +static SCClassConfClasstype *SCClassConfAllocClasstype( + uint16_t classtype_id, const char *classtype, const char *classtype_desc, int priority) +{ + SCClassConfClasstype *ct = NULL; + + if (classtype == NULL) + return NULL; + + if ((ct = SCCalloc(1, sizeof(SCClassConfClasstype))) == NULL) + return NULL; + + if ((ct->classtype = SCClassConfStringToLowercase(classtype)) == NULL) { + SCClassConfDeAllocClasstype(ct); + return NULL; + } + + if (classtype_desc != NULL && (ct->classtype_desc = SCStrdup(classtype_desc)) == NULL) { + SCLogError("Error allocating memory"); + + SCClassConfDeAllocClasstype(ct); + return NULL; + } + + ct->classtype_id = classtype_id; + ct->priority = priority; + + return ct; +} + +/** + * \internal + * \brief Frees a SCClassConfClasstype instance + * + * \param Pointer to the SCClassConfClasstype instance that has to be freed + */ +static void SCClassConfDeAllocClasstype(SCClassConfClasstype *ct) +{ + if (ct != NULL) { + if (ct->classtype != NULL) + SCFree(ct->classtype); + + if (ct->classtype_desc != NULL) + SCFree(ct->classtype_desc); + + SCFree(ct); + } + + return; +} + +/** + * \brief Hashing function to be used to hash the Classtype name. Would be + * supplied as an argument to the HashTableInit function for + * DetectEngineCtx->class_conf_ht. + * + * \param ht Pointer to the HashTable. + * \param data Pointer to the data to be hashed. In this case, the data + * would be a pointer to a SCClassConfClasstype instance. + * \param datalen Not used by this function. + */ +uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen) +{ + SCClassConfClasstype *ct = (SCClassConfClasstype *)data; + uint32_t hash = 0; + int i = 0; + + int len = strlen(ct->classtype); + + for (i = 0; i < len; i++) + hash += u8_tolower((unsigned char)(ct->classtype)[i]); + + hash = hash % ht->array_size; + + return hash; +} + +/** + * \brief Used to compare two Classtypes that have been stored in the HashTable. + * This function is supplied as an argument to the HashTableInit function + * for DetectionEngineCtx->class_conf_ct. + * + * \param data1 Pointer to the first SCClassConfClasstype to be compared. + * \param len1 Not used by this function. + * \param data2 Pointer to the second SCClassConfClasstype to be compared. + * \param len2 Not used by this function. + * + * \retval 1 On data1 and data2 being equal. + * \retval 0 On data1 and data2 not being equal. + */ +char SCClassConfClasstypeHashCompareFunc( + void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) +{ + SCClassConfClasstype *ct1 = (SCClassConfClasstype *)data1; + SCClassConfClasstype *ct2 = (SCClassConfClasstype *)data2; + int len1 = 0; + int len2 = 0; + + if (ct1 == NULL || ct2 == NULL) + return 0; + + if (ct1->classtype == NULL || ct2->classtype == NULL) + return 0; + + len1 = strlen(ct1->classtype); + len2 = strlen(ct2->classtype); + + if (len1 == len2 && memcmp(ct1->classtype, ct2->classtype, len1) == 0) { + SCLogDebug("Match found inside Classification-Config hash function"); + return 1; + } + + return 0; +} + +/** + * \brief Used to free the Classification Config Hash Data that was stored in + * DetectEngineCtx->class_conf_ht Hashtable. + * + * \param ch Pointer to the data that has to be freed. + */ +void SCClassConfClasstypeHashFree(void *ch) +{ + SCClassConfDeAllocClasstype(ch); + + return; +} + +/** + * \brief Loads the Classtype info from the classification.config file. + * + * The classification.config file contains the different classtypes, + * that can be used to label Signatures. Each line of the file should + * have the following format - + * classtype_name, classtype_description, priority + * None of the above parameters should hold a quote inside the file. + * + * \param de_ctx Pointer to the Detection Engine Context that should be updated + * with Classtype information. + */ +bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *de_ctx, FILE *fd) +{ + fd = SCClassConfInitContextAndLocalResources(de_ctx, fd); + if (fd == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) { + return false; + } +#endif + SCLogError("please check the \"classification-file\" " + "option in your suricata.yaml file"); + return false; + } + + bool ret = true; + if (!SCClassConfParseFile(de_ctx, fd)) { + SCLogWarning("Error loading classification configuration from %s", + SCClassConfGetConfFilename(de_ctx)); + ret = false; + } + + SCClassConfDeInitLocalResources(de_ctx, fd); + + return ret; +} + +/** + * \brief Gets the classtype from the corresponding hash table stored + * in the Detection Engine Context's class conf ht, given the + * classtype name. + * + * \param ct_name Pointer to the classtype name that has to be looked up. + * \param de_ctx Pointer to the Detection Engine Context. + * + * \retval lookup_ct_info Pointer to the SCClassConfClasstype instance from + * the hash table on success; NULL on failure. + */ +SCClassConfClasstype *SCClassConfGetClasstype(const char *ct_name, DetectEngineCtx *de_ctx) +{ + char name[strlen(ct_name) + 1]; + size_t s; + for (s = 0; s < strlen(ct_name); s++) + name[s] = u8_tolower((unsigned char)ct_name[s]); + name[s] = '\0'; + + SCClassConfClasstype ct_lookup = { 0, 0, name, NULL }; + SCClassConfClasstype *lookup_ct_info = HashTableLookup(de_ctx->class_conf_ht, &ct_lookup, 0); + return lookup_ct_info; +} + +/*----------------------------------Unittests---------------------------------*/ + +#ifdef UNITTESTS + +/** + * \brief Creates a dummy classification file, with all valid Classtypes, for + * testing purposes. + * + * \file_path Pointer to the file_path for the dummy classification file. + */ +FILE *SCClassConfGenerateValidDummyClassConfigFD01(void) +{ + const char *buffer = "config classification: nothing-wrong,Nothing Wrong With Us,3\n" + "config classification: unknown,Unknown are we,3\n" + "config classification: bad-unknown,We think it's bad, 2\n"; + + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Classification Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy classification file, with some valid Classtypes and a + * couple of invalid Classtypes, for testing purposes. + * + * \file_path Pointer to the file_path for the dummy classification file. + */ +FILE *SCClassConfGenerateInvalidDummyClassConfigFD02(void) +{ + const char *buffer = "config classification: not-suspicious,Not Suspicious Traffic,3\n" + "onfig classification: unknown,Unknown Traffic,3\n" + "config classification: _badunknown,Potentially Bad Traffic, 2\n" + "config classification: bamboola1,Unknown Traffic,3\n" + "config classification: misc-activity,Misc activity,-1\n" + "config classification: policy-violation,Potential Corporate " + "config classification: bamboola,Unknown Traffic,3\n"; + + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Classification Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy classification file, with all invalid Classtypes, for + * testing purposes. + * + * \file_path Pointer to the file_path for the dummy classification file. + */ +FILE *SCClassConfGenerateInvalidDummyClassConfigFD03(void) +{ + const char *buffer = "conig classification: not-suspicious,Not Suspicious Traffic,3\n" + "onfig classification: unknown,Unknown Traffic,3\n" + "config classification: _badunknown,Potentially Bad Traffic, 2\n" + "config classification: misc-activity,Misc activity,-1\n"; + + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Classification Config test code"); + + return fd; +} + +/** + * \test Check that the classification file is loaded and the detection engine + * content class_conf_hash_table loaded with the classtype data. + */ +static int SCClassConfTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 0; + + if (de_ctx == NULL) + return result; + + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassificationConfigFile(de_ctx, fd); + + if (de_ctx->class_conf_ht == NULL) + return result; + + result = (de_ctx->class_conf_ht->count == 3); + if (result == 0) + printf("de_ctx->class_conf_ht->count %u: ", de_ctx->class_conf_ht->count); + + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Check that invalid classtypes present in the classification config file + * aren't loaded. + */ +static int SCClassConfTest02(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 0; + + if (de_ctx == NULL) + return result; + + FILE *fd = SCClassConfGenerateInvalidDummyClassConfigFD03(); + SCClassConfLoadClassificationConfigFile(de_ctx, fd); + + if (de_ctx->class_conf_ht == NULL) + return result; + + result = (de_ctx->class_conf_ht->count == 0); + + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Check that only valid classtypes are loaded into the hash table from + * the classification.config file. + */ +static int SCClassConfTest03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + FAIL_IF_NULL(de_ctx); + + FILE *fd = SCClassConfGenerateInvalidDummyClassConfigFD02(); + FAIL_IF(SCClassConfLoadClassificationConfigFile(de_ctx, fd)); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test Check if the classtype info from the classification.config file have + * been loaded into the hash table. + */ +static int SCClassConfTest04(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 1; + + if (de_ctx == NULL) + return 0; + + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassificationConfigFile(de_ctx, fd); + + if (de_ctx->class_conf_ht == NULL) + return 0; + + result = (de_ctx->class_conf_ht->count == 3); + + result &= (SCClassConfGetClasstype("unknown", de_ctx) != NULL); + result &= (SCClassConfGetClasstype("unKnoWn", de_ctx) != NULL); + result &= (SCClassConfGetClasstype("bamboo", de_ctx) == NULL); + result &= (SCClassConfGetClasstype("bad-unknown", de_ctx) != NULL); + result &= (SCClassConfGetClasstype("BAD-UNKnOWN", de_ctx) != NULL); + result &= (SCClassConfGetClasstype("bed-unknown", de_ctx) == NULL); + + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Check if the classtype info from the invalid classification.config file + * have not been loaded into the hash table, and cross verify to check + * that the hash table contains no classtype data. + */ +static int SCClassConfTest05(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 1; + + if (de_ctx == NULL) + return 0; + + FILE *fd = SCClassConfGenerateInvalidDummyClassConfigFD03(); + SCClassConfLoadClassificationConfigFile(de_ctx, fd); + + if (de_ctx->class_conf_ht == NULL) + return 0; + + result = (de_ctx->class_conf_ht->count == 0); + + result &= (SCClassConfGetClasstype("unknown", de_ctx) == NULL); + result &= (SCClassConfGetClasstype("unKnoWn", de_ctx) == NULL); + result &= (SCClassConfGetClasstype("bamboo", de_ctx) == NULL); + result &= (SCClassConfGetClasstype("bad-unknown", de_ctx) == NULL); + result &= (SCClassConfGetClasstype("BAD-UNKnOWN", de_ctx) == NULL); + result &= (SCClassConfGetClasstype("bed-unknown", de_ctx) == NULL); + + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \brief This function registers unit tests for Classification Config API. + */ +void SCClassConfRegisterTests(void) +{ + UtRegisterTest("SCClassConfTest01", SCClassConfTest01); + UtRegisterTest("SCClassConfTest02", SCClassConfTest02); + UtRegisterTest("SCClassConfTest03", SCClassConfTest03); + UtRegisterTest("SCClassConfTest04", SCClassConfTest04); + UtRegisterTest("SCClassConfTest05", SCClassConfTest05); +} +#endif /* UNITTESTS */ diff --git a/src/util/classification-config.h b/src/util/classification-config.h new file mode 100644 index 000000000000..40538876b989 --- /dev/null +++ b/src/util/classification-config.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_CLASSIFICATION_CONFIG_H__ +#define __UTIL_CLASSIFICATION_CONFIG_H__ + +#define CLASSTYPE_NAME_MAX_LEN 64 +#define CLASSTYPE_DESC_MAX_LEN 512 + +/** + * \brief Container for a Classtype from the Classification.config file. + */ +typedef struct SCClassConfClasstype_ { + /* The index of the classification within classification.config */ + uint16_t classtype_id; + + /* The priority this classification type carries */ + int priority; + + /* The classtype name. This is the primary key for a Classification. */ + char *classtype; + + /* Description for a classification. Would be used while printing out + * the classification info for a Signature, by the fast-log module. */ + char *classtype_desc; +} SCClassConfClasstype; + +bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *, FILE *fd); +int SCClassConfAddClasstype(DetectEngineCtx *de_ctx, char *rawstr, uint16_t index); +SCClassConfClasstype *SCClassConfGetClasstype(const char *, DetectEngineCtx *); +void SCClassConfDeInitContext(DetectEngineCtx *); + +void SCClassConfInit(DetectEngineCtx *de_ctx); +void SCClassConfDeinit(DetectEngineCtx *de_ctx); + +/* for unittests */ +#ifdef UNITTESTS +void SCClassConfRegisterTests(void); +FILE *SCClassConfGenerateValidDummyClassConfigFD01(void); +FILE *SCClassConfGenerateInvalidDummyClassConfigFD02(void); +FILE *SCClassConfGenerateInvalidDummyClassConfigFD03(void); +#endif + +#endif /* __UTIL_CLASSIFICATION_CONFIG_H__ */ diff --git a/src/util/clock.h b/src/util/clock.h new file mode 100644 index 000000000000..81256a7a03e6 --- /dev/null +++ b/src/util/clock.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_CLOCK_H__ +#define __UTIL_CLOCK_H__ + +#include + +/* Feel free to add more macros */ + +#define CLOCK_INIT \ + clock_t clo1, clo2; \ + clo1 = clo2 = 0; +#define CLOCK_START clo1 = clock() + +#define CLOCK_END clo2 = clock() + +#define CLOCK_PRINT_SEC \ + printf("Seconds spent: %.4fs\n", ((double)(clo2 - clo1) / (double)CLOCKS_PER_SEC)) + +#endif /*__UTIL_CLOCK_H__ */ diff --git a/src/util/conf.c b/src/util/conf.c new file mode 100644 index 000000000000..e7af7a8eb942 --- /dev/null +++ b/src/util/conf.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "../conf.h" +#include "runmodes.h" +#include "util/conf.h" +#include "util/debug.h" +#include "util/path.h" + +TmEcode ConfigSetLogDirectory(const char *name) +{ + return ConfSetFinal("default-log-dir", name) ? TM_ECODE_OK : TM_ECODE_FAILED; +} + +const char *ConfigGetLogDirectory(void) +{ + const char *log_dir = NULL; + + if (ConfGet("default-log-dir", &log_dir) != 1) { +#ifdef OS_WIN32 + log_dir = _getcwd(NULL, 0); + if (log_dir == NULL) { + log_dir = DEFAULT_LOG_DIR; + } +#else + log_dir = DEFAULT_LOG_DIR; +#endif /* OS_WIN32 */ + } + + return log_dir; +} + +TmEcode ConfigCheckLogDirectoryExists(const char *log_dir) +{ + SCEnter(); + SCStat buf; + if (SCStatFn(log_dir, &buf) != 0) { + SCReturnInt(TM_ECODE_FAILED); + } + SCReturnInt(TM_ECODE_OK); +} + +TmEcode ConfigSetDataDirectory(char *name) +{ + if (strlen(name) == 0) + return TM_ECODE_OK; + + size_t size = strlen(name) + 1; + char tmp[size]; + strlcpy(tmp, name, size); + if (size > 2 && tmp[size - 2] == '/') // > 2 to allow just / + tmp[size - 2] = '\0'; + + return ConfSetFinal("default-data-dir", tmp) ? TM_ECODE_OK : TM_ECODE_FAILED; +} + +const char *ConfigGetDataDirectory(void) +{ + const char *data_dir = NULL; + + if (ConfGet("default-data-dir", &data_dir) != 1) { +#ifdef OS_WIN32 + data_dir = _getcwd(NULL, 0); + if (data_dir == NULL) { + data_dir = DEFAULT_DATA_DIR; + } +#else + data_dir = DEFAULT_DATA_DIR; +#endif /* OS_WIN32 */ + } + + SCLogDebug("returning '%s'", data_dir); + return data_dir; +} + +TmEcode ConfigCheckDataDirectory(const char *data_dir) +{ + SCEnter(); + SCStat buf; + if (SCStatFn(data_dir, &buf) != 0) { + SCReturnInt(TM_ECODE_FAILED); + } + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief Find the configuration node for a specific device. + + * Basically hunts through the list of maps for the first one with a + * key of "interface", and a value of the provided interface. + * + * \param node The node to start looking for the device + * configuration. Typically this would be something like the af-packet + * or pf-ring node. + * + * \param iface The name of the interface to find the config for. + */ +ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface) +{ + ConfNode *if_node, *item; + TAILQ_FOREACH (if_node, &node->head, next) { + TAILQ_FOREACH (item, &if_node->head, next) { + if (strcmp(item->name, "interface") == 0 && strcmp(item->val, iface) == 0) { + return if_node; + } + } + } + + return NULL; +} + +int ConfUnixSocketIsEnable(void) +{ + const char *value; + + if (ConfGet("unix-command.enabled", &value) != 1) { + return 0; + } + + if (value == NULL) { + SCLogError("malformed value for unix-command.enabled: NULL"); + return 0; + } + + if (!strcmp(value, "auto")) { +#ifdef OS_WIN32 + return 0; +#else + if (!IsRunModeOffline(RunmodeGetCurrent())) { + SCLogInfo("Running in live mode, activating unix socket"); + return 1; + } else { + return 0; + } +#endif + } + + return ConfValIsTrue(value); +} diff --git a/src/util/conf.h b/src/util/conf.h new file mode 100644 index 000000000000..bcf12e944778 --- /dev/null +++ b/src/util/conf.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + */ + +#ifndef __UTIL_UTIL_CONF_H__ +#define __UTIL_UTIL_CONF_H__ + +#include "../conf.h" + +TmEcode ConfigSetLogDirectory(const char *name); +const char *ConfigGetLogDirectory(void); +TmEcode ConfigCheckLogDirectoryExists(const char *log_dir); + +TmEcode ConfigSetDataDirectory(char *name); +const char *ConfigGetDataDirectory(void); +TmEcode ConfigCheckDataDirectory(const char *log_dir); + +ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface); + +int ConfUnixSocketIsEnable(void); + +#endif /* __UTIL_UTIL_CONF_H__ */ diff --git a/src/util/config.h b/src/util/config.h new file mode 100644 index 000000000000..ae97d96edf77 --- /dev/null +++ b/src/util/config.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_CONFIG_H__ +#define __UTIL_CONFIG_H__ + +enum ConfigAction { + CONFIG_ACTION_SET = 1, +}; + +enum ConfigSubsys { + CONFIG_SUBSYS_LOGGING = 0, +}; + +enum ConfigType { + CONFIG_TYPE_TX = 0, /* transaction logging */ + CONFIG_TYPE_FLOW, /* flow logging */ + CONFIG_TYPE_ALERT, /* alert logging */ + CONFIG_TYPE_ANOMALY, /* anomaly logging */ + CONFIG_TYPE_FILE, /* file logging */ + CONFIG_TYPE_PCAP, /* pcap logging */ + CONFIG_TYPE_DROP, /* drop logging */ +#define CONFIG_TYPE_DEFAULT CONFIG_TYPE_TX +}; + +enum ConfigScope { + CONFIG_SCOPE_TX = 0, /* per transaction */ + CONFIG_SCOPE_FLOW, /* per flow */ +#define CONFIG_SCOPE_DEFAULT CONFIG_SCOPE_TX +}; + +#endif diff --git a/src/util/coredump-config.c b/src/util/coredump-config.c new file mode 100644 index 000000000000..283f4ac728d8 --- /dev/null +++ b/src/util/coredump-config.c @@ -0,0 +1,239 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eileen Donlon + * + * Coredump configuration + */ + +#include "suricata-common.h" +#define _FILE_OFFSET_BITS 64 +#include "util/coredump-config.h" +#include "../conf.h" +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +#ifdef HAVE_SYS_PRCTL_H +#include +#endif +#include "util/debug.h" + +#ifdef OS_WIN32 + +void CoredumpEnable(void) +{ +} + +int32_t CoredumpLoadConfig(void) +{ + /* todo: use the registry to get/set dump configuration */ + SCLogInfo("Configuring core dump is not yet supported on Windows."); + return 0; +} + +#else + +static bool unlimited = false; +static rlim_t max_dump = 0; + +/** + * \brief Enable coredumps on systems where coredumps can and need to + * be enabled. + */ +void CoredumpEnable(void) +{ + if (!unlimited && !max_dump) { + return; + } +#if HAVE_SYS_PRCTL_H + /* Linux specific core dump configuration; set dumpable flag if needed */ + int dumpable = 0; + dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); + if (dumpable == -1) { + SCLogNotice("Failed to get dumpable state of process, " + "core dumps may not be enabled: %s", + strerror(errno)); + } else if (unlimited || max_dump > 0) { + /* try to enable core dump for this process */ + if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { + SCLogInfo("Unable to make this process dumpable."); + } else { + SCLogDebug("Process is dumpable."); + } + } + /* don't clear dumpable flag since this will have other effects; + * just set dump size to 0 below */ +#endif /* HAVE_SYS_PRCTL_H */ +} + +/** + * \brief Configures the core dump size. + * + * \retval Returns 1 on success and 0 on failure. + * + */ +int32_t CoredumpLoadConfig(void) +{ +#ifdef HAVE_SYS_RESOURCE_H + /* get core dump configuration settings for suricata */ + const char *dump_size_config = NULL; + size_t rlim_size = sizeof(rlim_t); + + if (ConfGet("coredump.max-dump", &dump_size_config) == 0) { + SCLogDebug("core dump size not specified"); + return 1; + } + if (dump_size_config == NULL) { + SCLogError("malformed value for coredump.max-dump: NULL"); + return 0; + } + if (strcasecmp(dump_size_config, "unlimited") == 0) { + unlimited = true; + } else { + /* disallow negative values */ + if (strchr(dump_size_config, '-') != NULL) { + SCLogInfo("Negative value for core dump size; ignored."); + return 0; + } + /* the size of rlim_t is platform dependent */ + if (rlim_size > 8) { + SCLogInfo("Unexpected type for rlim_t"); + return 0; + } + errno = 0; + if (rlim_size == 8) { + max_dump = (rlim_t)strtoull(dump_size_config, NULL, 10); + } else if (rlim_size == 4) { + max_dump = (rlim_t)strtoul(dump_size_config, NULL, 10); + } + if ((errno == ERANGE) || (errno != 0 && max_dump == 0)) { + SCLogInfo("Illegal core dump size: %s.", dump_size_config); + return 0; + } + SCLogInfo("Max dump is %" PRIu64, (uint64_t)max_dump); + } + + CoredumpEnable(); + + struct rlimit lim; /*existing limit*/ + struct rlimit new_lim; /*desired limit*/ + + /* get the current core dump file configuration */ + if (getrlimit(RLIMIT_CORE, &lim) == -1) { + SCLogInfo("Can't read coredump limit for this process."); + return 0; + } + + if (unlimited) { + /* we want no limit on coredump size */ + if (lim.rlim_max == RLIM_INFINITY && lim.rlim_cur == RLIM_INFINITY) { + SCLogConfig("Core dump size is unlimited."); + return 1; + } else { + new_lim.rlim_max = RLIM_INFINITY; + new_lim.rlim_cur = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &new_lim) == 0) { + SCLogConfig("Core dump size set to unlimited."); + return 1; + } + if (errno == EPERM) { + /* couldn't raise the hard limit to unlimited; + * try increasing the soft limit to the hard limit instead */ + if (lim.rlim_cur < lim.rlim_max) { + new_lim.rlim_cur = lim.rlim_max; + if (setrlimit(RLIMIT_CORE, &new_lim) == 0) { + SCLogInfo("Could not set core dump size to unlimited; core dump size set " + "to the hard limit."); + return 0; + } else { + SCLogInfo( + "Failed to set core dump size to unlimited or to the hard limit."); + return 0; + } + } + SCLogInfo("Could not set core dump size to unlimited; it's set to the hard limit."); + return 0; + } + } + } else { + /* we want a non-infinite soft limit on coredump size */ + new_lim.rlim_cur = max_dump; + + /* check whether the hard limit needs to be adjusted */ + if (lim.rlim_max == RLIM_INFINITY) { + /* keep the current value (unlimited) for the hard limit */ + new_lim.rlim_max = lim.rlim_max; + } +#ifdef RLIM_SAVED_MAX + else if (lim.rlim_max == RLIM_SAVED_MAX) { + /* keep the current value (unknown) for the hard limit */ + new_lim.rlim_max = lim.rlim_max; + } +#endif + else if (lim.rlim_max < max_dump) { + /* need to raise the hard coredump size limit */ + new_lim.rlim_max = max_dump; + } else { + /* hard limit is ample */ + new_lim.rlim_max = lim.rlim_max; + } + if (setrlimit(RLIMIT_CORE, &new_lim) == 0) { + SCLogInfo("Core dump setting attempted is %" PRIu64, (uint64_t)new_lim.rlim_cur); + struct rlimit actual_lim; + if (getrlimit(RLIMIT_CORE, &actual_lim) == 0) { + if (actual_lim.rlim_cur == RLIM_INFINITY) { + SCLogConfig("Core dump size set to unlimited."); + } +#ifdef RLIM_SAVED_CUR + else if (actual_lim.rlim_cur == RLIM_SAVED_CUR) { + SCLogInfo("Core dump size set to soft limit."); + } +#endif + else { + SCLogInfo("Core dump size set to %" PRIu64, (uint64_t)actual_lim.rlim_cur); + } + } + return 1; + } + + if (errno == EINVAL || errno == EPERM) { + /* couldn't increase the hard limit, or the soft limit exceeded the hard + * limit; try to raise the soft limit to the hard limit */ + if ((lim.rlim_cur < max_dump && lim.rlim_cur < lim.rlim_max) +#ifdef RLIM_SAVED_CUR + || (lim.rlim_cur == RLIM_SAVED_CUR) +#endif + ) { + new_lim.rlim_max = lim.rlim_max; + new_lim.rlim_cur = lim.rlim_max; + if (setrlimit(RLIMIT_CORE, &new_lim) == 0) { + SCLogInfo("Core dump size set to the hard limit."); + return 0; + } + } + } + } + /* failed to set the coredump limit */ + SCLogInfo("Couldn't set coredump size to %s.", dump_size_config); +#endif /* HAVE_SYS_RESOURCE_H */ + return 0; +} + +#endif /* OS_WIN32 */ diff --git a/src/util-coredump-config.h b/src/util/coredump-config.h similarity index 100% rename from src/util-coredump-config.h rename to src/util/coredump-config.h diff --git a/src/util/cpu.c b/src/util/cpu.c new file mode 100644 index 000000000000..277f4ac74500 --- /dev/null +++ b/src/util/cpu.c @@ -0,0 +1,235 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * + * Retrieve CPU information (configured CPUs, online CPUs) + */ + +#include "suricata-common.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/cpu.h" +#include "util/byte.h" + +/** + * Ok, if they should use sysconf, check that they have the macro's + * (syscalls) defined; + * + * Note: For windows it's different; Check the following: + * SYSTEM_INFO info; + * GetSystemInfo(&info); + * -> info.dwNumberOfProcessors; + */ +#ifdef _SC_NPROCESSORS_CONF +#define SYSCONF_NPROCESSORS_CONF_COMPAT +#endif + +#ifdef _SC_NPROCESSORS_ONLN +#define SYSCONF_NPROCESSORS_ONLN_COMPAT +#endif + +/* This one is available on Solaris 10 */ +#ifdef _SC_NPROCESSORS_MAX +#define SYSCONF_NPROCESSORS_MAX_COMPAT +#endif + +/** + * \brief Get the number of cpus configured in the system + * \retval 0 if the syscall is not available or we have an error; + * otherwise it will return the number of cpus configured + */ +uint16_t UtilCpuGetNumProcessorsConfigured(void) +{ +#ifdef SYSCONF_NPROCESSORS_CONF_COMPAT + long nprocs = -1; + nprocs = sysconf(_SC_NPROCESSORS_CONF); + if (nprocs < 1) { + SCLogError("Couldn't retrieve the number of cpus " + "configured (%s)", + strerror(errno)); + return 0; + } + + if (nprocs > UINT16_MAX) { + SCLogDebug("It seems that there are more than %d CPUs " + "configured on this system. You can modify util-cpu.{c,h} " + "to use uint32_t to support it", + UINT16_MAX); + return UINT16_MAX; + } + + return (uint16_t)nprocs; +#elif OS_WIN32 + int64_t nprocs = 0; + const char *envvar = getenv("NUMBER_OF_PROCESSORS"); + if (envvar != NULL) { + if (StringParseInt64(&nprocs, 10, 0, envvar) < 0) { + SCLogWarning("Invalid value for number of " + "processors: %s", + envvar); + return 0; + } + } + if (nprocs < 1) { + SCLogError("Couldn't retrieve the number of cpus " + "configured from the NUMBER_OF_PROCESSORS environment variable"); + return 0; + } + return (uint16_t)nprocs; +#else + SCLogError("Couldn't retrieve the number of cpus " + "configured, sysconf macro unavailable"); + return 0; +#endif +} + +/** + * \brief Get the number of cpus online in the system + * \retval 0 if the syscall is not available or we have an error; + * otherwise it will return the number of cpus online + */ +uint16_t UtilCpuGetNumProcessorsOnline(void) +{ +#ifdef SYSCONF_NPROCESSORS_ONLN_COMPAT + long nprocs = -1; + nprocs = sysconf(_SC_NPROCESSORS_ONLN); + if (nprocs < 1) { + SCLogError("Couldn't retrieve the number of cpus " + "online (%s)", + strerror(errno)); + return 0; + } + + if (nprocs > UINT16_MAX) { + SCLogDebug("It seems that there are more than %d CPUs online. " + "You can modify util-cpu.{c,h} to use uint32_t to " + "support it", + UINT16_MAX); + return UINT16_MAX; + } + + return (uint16_t)nprocs; +#elif OS_WIN32 + return UtilCpuGetNumProcessorsConfigured(); +#else + SCLogError("Couldn't retrieve the number of cpus online, " + "synconf macro unavailable"); + return 0; +#endif +} + +/** + * \brief Get the maximum number of cpus allowed in the system + * This syscall is present on Solaris, but it's not on linux + * or macosx. Maybe you should look at UtilCpuGetNumProcessorsConfigured() + * \retval 0 if the syscall is not available or we have an error; + * otherwise it will return the number of cpus allowed + */ +uint16_t UtilCpuGetNumProcessorsMax(void) +{ +#ifdef SYSCONF_NPROCESSORS_MAX_COMPAT + long nprocs = -1; + nprocs = sysconf(_SC_NPROCESSORS_MAX); + if (nprocs < 1) { + SCLogError("Couldn't retrieve the maximum number of cpus " + "allowed by the system (%s)", + strerror(errno)); + return 0; + } + + if (nprocs > UINT16_MAX) { + SCLogDebug("It seems that the system support more that %" PRIu16 " CPUs. You " + "can modify util-cpu.{c,h} to use uint32_t to support it", + UINT16_MAX); + return UINT16_MAX; + } + + return (uint16_t)nprocs; +#else + SCLogError("Couldn't retrieve the maximum number of cpus allowed by " + "the system, synconf macro unavailable"); + return 0; +#endif +} + +/** + * \brief Print a summary of CPUs detected (configured and online) + */ +void UtilCpuPrintSummary(void) +{ + uint16_t cpus_conf = UtilCpuGetNumProcessorsConfigured(); + uint16_t cpus_online = UtilCpuGetNumProcessorsOnline(); + + SCLogDebug("CPUs Summary: "); + if (cpus_conf > 0) + SCLogDebug("CPUs configured: %" PRIu16, cpus_conf); + if (cpus_online > 0) + SCLogInfo("CPUs/cores online: %" PRIu16, cpus_online); + if (cpus_online == 0 && cpus_conf == 0) + SCLogInfo("Couldn't retrieve any information of CPU's, please, send your operating " + "system info and check util-cpu.{c,h}"); +} + +/** + * Get the current number of ticks from the CPU. + * + * \todo We'll have to deal with removing ticks from the extra cpuids in between + * 2 calls. + */ +uint64_t UtilCpuGetTicks(void) +{ + uint64_t val; +#if defined(__GNUC__) && \ + (defined(__x86_64) || defined(_X86_64_) || defined(ia_64) || defined(__i386__)) +#if defined(__x86_64) || defined(_X86_64_) || defined(ia_64) + __asm__ __volatile__("xorl %%eax,%%eax\n\t" + "cpuid\n\t" :: + : "%rax", "%rbx", "%rcx", "%rdx"); +#else + __asm__ __volatile__("xorl %%eax,%%eax\n\t" + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" :: + : "%eax", "%ecx", "%edx"); +#endif + uint32_t a, d; + __asm__ __volatile__("rdtsc" : "=a"(a), "=d"(d)); + val = ((uint64_t)a) | (((uint64_t)d) << 32); +#if defined(__x86_64) || defined(_X86_64_) || defined(ia_64) + __asm__ __volatile__("xorl %%eax,%%eax\n\t" + "cpuid\n\t" :: + : "%rax", "%rbx", "%rcx", "%rdx"); +#else + __asm__ __volatile__("xorl %%eax,%%eax\n\t" + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" :: + : "%eax", "%ecx", "%edx"); +#endif + +#else /* #if defined(__GNU__) */ + // #warning Using inferior version of UtilCpuGetTicks + struct timeval now; + gettimeofday(&now, NULL); + val = (now.tv_sec * 1000000) + now.tv_usec; +#endif + return val; +} diff --git a/src/util-cpu.h b/src/util/cpu.h similarity index 100% rename from src/util-cpu.h rename to src/util/cpu.h diff --git a/src/util/daemon.c b/src/util/daemon.c new file mode 100644 index 000000000000..b44eb6cc6ad1 --- /dev/null +++ b/src/util/daemon.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gerardo Iglesias Galvan + * + * Daemonization process + */ + +#include "suricata.h" +#include "suricata-common.h" +#include "runmodes.h" +#include "util/daemon.h" +#include "util/debug.h" +#include "../conf.h" + +#ifndef OS_WIN32 + +#include +#include +#include + +static volatile sig_atomic_t sigflag = 0; + +/** + * \brief Signal handler used to take the parent process out of stand-by + */ +static void SignalHandlerSigusr1(int signo) +{ + sigflag = 1; +} + +/** + * \brief Tell the parent process the child is ready + * + * \param pid pid of the parent process to signal + */ +static void TellWaitingParent(pid_t pid) +{ + kill(pid, SIGUSR1); +} + +/** + * \brief Set the parent on stand-by until the child is ready + * + * \param pid pid of the child process to wait + */ +static void WaitForChild(pid_t pid) +{ + int status; + SCLogDebug("Daemon: Parent waiting for child to be ready..."); + /* Wait until child signals is ready */ + while (sigflag == 0) { + if (waitpid(pid, &status, WNOHANG)) { + /* Check if the child is still there, otherwise the parent should exit */ + if (WIFEXITED(status) || WIFSIGNALED(status)) { + FatalError("Child died unexpectedly"); + } + } + /* sigsuspend(); */ + sleep(1); + } +} + +/** + * \brief Close stdin, stdout, stderr.Redirect logging info to syslog + * + */ +static void SetupLogging(void) +{ + /* Redirect stdin, stdout, stderr to /dev/null */ + int fd = open("/dev/null", O_RDWR); + if (fd < 0) + return; + (void)dup2(fd, 0); + (void)dup2(fd, 1); + (void)dup2(fd, 2); + close(fd); +} + +/** + * \brief Daemonize the process + * + */ +void Daemonize(void) +{ + pid_t pid, sid; + + /* Register the signal handler */ + signal(SIGUSR1, SignalHandlerSigusr1); + + /** \todo We should check if we allow more than 1 instance + to run simultaneously. Maybe change the behaviour + through conf file */ + + /* Creates a new process */ +#if defined(OS_DARWIN) && defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + pid = fork(); +#if defined(OS_DARWIN) && defined(__clang__) +#pragma clang diagnostic pop +#endif + + if (pid < 0) { + /* Fork error */ + FatalError("Error forking the process"); + } else if (pid == 0) { + /* Child continues here */ + const char *daemondir; + + sid = setsid(); + if (sid < 0) { + FatalError("Error creating new session"); + } + + if (ConfGet("daemon-directory", &daemondir) == 1) { + if ((chdir(daemondir)) < 0) { + FatalError("Error changing to working directory"); + } + } +#ifndef OS_WIN32 + else { + if (chdir("/") < 0) { + SCLogError("Error changing to working directory '/'"); + } + } +#endif + + SetupLogging(); + + /* Child is ready, tell its parent */ + TellWaitingParent(getppid()); + + /* Daemon is up and running */ + SCLogDebug("Daemon is running"); + return; + } + /* Parent continues here, waiting for child to be ready */ + SCLogDebug("Parent is waiting for child to be ready"); + WaitForChild(pid); + + /* Parent exits */ + SCLogDebug("Child is ready, parent exiting"); + exit(EXIT_SUCCESS); +} + +#endif /* ifndef OS_WIN32 */ + +/** + * \brief Check for a valid combination daemon/mode + * + * \param daemon daemon on or off + * \param mode selected mode + * + * \retval 1 valid combination + * \retval 0 invalid combination + */ +int CheckValidDaemonModes(int daemon, int mode) +{ + if (daemon) { + switch (mode) { + case RUNMODE_PCAP_FILE: + SCLogError("ERROR: pcap offline mode cannot run as daemon"); + return 0; + case RUNMODE_UNITTEST: + SCLogError("ERROR: unittests cannot run as daemon"); + return 0; + default: + SCLogDebug("Allowed mode"); + break; + } + } + return 1; +} diff --git a/src/util/daemon.h b/src/util/daemon.h new file mode 100644 index 000000000000..a67113883340 --- /dev/null +++ b/src/util/daemon.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gerardo Iglesias Galvan + */ + +#ifndef __UTIL_DAEMON_H__ +#define __UTIL_DAEMON_H__ + +#ifdef OS_WIN32 +#define Daemonize() +#else +void Daemonize(void); +#endif + +int CheckValidDaemonModes(int, int); + +#endif /* __UTIL_DAEMON_H__ */ diff --git a/src/util/datalink.c b/src/util/datalink.c new file mode 100644 index 000000000000..8362a187ea84 --- /dev/null +++ b/src/util/datalink.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "util/datalink.h" +#include "decode.h" + +int g_datalink_value = LINKTYPE_NULL; +int g_datalink_is_multiple = 0; + +void DatalinkSetGlobalType(int datalink) +{ + if (g_datalink_value != LINKTYPE_NULL) { + if (datalink != g_datalink_value) { + g_datalink_is_multiple = 1; + } + } else { + g_datalink_value = datalink; + } +} + +inline int DatalinkGetGlobalType(void) +{ + return g_datalink_value; +} + +bool DatalinkHasMultipleValues(void) +{ + return g_datalink_is_multiple == 1; +} diff --git a/src/util-datalink.h b/src/util/datalink.h similarity index 100% rename from src/util-datalink.h rename to src/util/datalink.h diff --git a/src/util/debug-filters.c b/src/util/debug-filters.c new file mode 100644 index 000000000000..0fe88f6b558c --- /dev/null +++ b/src/util/debug-filters.c @@ -0,0 +1,988 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Debug filter utility functions + */ + +#include "suricata-common.h" +#include "util/debug-filters.h" +#include "threads.h" +#include "util/debug.h" + +/* both of these are defined in util-debug.c */ +extern int sc_log_module_initialized; +extern int sc_log_module_cleaned; + +/* used to indicate if any FG filters are registered */ +int sc_log_fg_filters_present = 0; + +/* used to indicate if any FD filters are registered */ +int sc_log_fd_filters_present = 0; + +/** + * \brief Holds the fine-grained filters + */ +SCLogFGFilterFile *sc_log_fg_filters[SC_LOG_FILTER_MAX] = { NULL, NULL }; + +/** + * \brief Mutex for accessing the fine-grained filters sc_log_fg_filters + */ +static SCMutex sc_log_fg_filters_m[SC_LOG_FILTER_MAX] = { SCMUTEX_INITIALIZER, + SCMUTEX_INITIALIZER }; + +/** + * \brief Holds the function-dependent filters + */ +static SCLogFDFilter *sc_log_fd_filters = NULL; + +/** + * \brief Mutex for accessing the function-dependent filters sc_log_fd_filters + */ +static SCMutex sc_log_fd_filters_m = SCMUTEX_INITIALIZER; + +/** + * \brief Holds the thread_list required by function-dependent filters + */ +static SCLogFDFilterThreadList *sc_log_fd_filters_tl = NULL; + +/** + * \brief Mutex for accessing the FD thread_list sc_log_fd_filters_tl + */ +static SCMutex sc_log_fd_filters_tl_m = SCMUTEX_INITIALIZER; + +/** + * \brief Helper function used internally to add a FG filter + * + * \param file File_name of the filter + * \param function Function_name of the filter + * \param line Line number of the filter + * \param listtype The filter listtype. Can be either a blacklist or whitelist + * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) + * + * \retval 0 on successfully adding the filter; + * \retval -1 on failure + */ +static int SCLogAddFGFilter(const char *file, const char *function, int line, int listtype) +{ + SCLogFGFilterFile *fgf_file = NULL; + SCLogFGFilterFile *prev_fgf_file = NULL; + + SCLogFGFilterFunc *fgf_func = NULL; + SCLogFGFilterFunc *prev_fgf_func = NULL; + + SCLogFGFilterLine *fgf_line = NULL; + SCLogFGFilterLine *prev_fgf_line = NULL; + + int found = 0; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return -1; + } + + if (file == NULL && function == NULL && line < 0) { + printf("Error: Invalid arguments supplied to SCLogAddFGFilter\n"); + return -1; + } + + SCMutex *m = &sc_log_fg_filters_m[listtype]; + + SCMutexLock(m); + + fgf_file = sc_log_fg_filters[listtype]; + + prev_fgf_file = fgf_file; + while (fgf_file != NULL) { + prev_fgf_file = fgf_file; + if (file == NULL && fgf_file->file == NULL) + found = 1; + else if (file != NULL && fgf_file->file != NULL) + found = (strcmp(file, fgf_file->file) == 0); + else + found = 0; + + if (found == 1) + break; + + fgf_file = fgf_file->next; + } + + if (found == 0) { + SCLogAddToFGFFileList(prev_fgf_file, file, function, line, listtype); + goto done; + } + + found = 0; + fgf_func = fgf_file->func; + prev_fgf_func = fgf_func; + while (fgf_func != NULL) { + prev_fgf_func = fgf_func; + if (function == NULL && fgf_func->func == NULL) + found = 1; + else if (function != NULL && fgf_func->func != NULL) + found = (strcmp(function, fgf_func->func) == 0); + else + found = 0; + + if (found == 1) + break; + + fgf_func = fgf_func->next; + } + + if (found == 0) { + SCLogAddToFGFFuncList(fgf_file, prev_fgf_func, function, line); + goto done; + } + + found = 0; + fgf_line = fgf_func->line; + prev_fgf_line = fgf_line; + while (fgf_line != NULL) { + prev_fgf_line = fgf_line; + if (line == fgf_line->line) { + found = 1; + break; + } + + fgf_line = fgf_line->next; + } + + if (found == 0) { + SCLogAddToFGFLineList(fgf_func, prev_fgf_line, line); + goto done; + } + +done: + SCMutexUnlock(&sc_log_fg_filters_m[listtype]); + sc_log_fg_filters_present = 1; + + return 0; +} + +/** + * \brief Internal function used to check for matches against registered FG + * filters. Checks if there is a match for the incoming log_message with + * any of the FG filters. Based on whether the filter type is whitelist + * or blacklist, the function allows the message to be logged or not. + * + * \param file File_name from where the log_message originated + * \param function Function_name from where the log_message originated + * \param line Line number from where the log_message originated + * \param listtype The filter listtype. Can be either a blacklist or whitelist + * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) + * + * \retval 1 if there is a match + * \retval 0 on no match + * \retval -1 on failure + */ +static int SCLogMatchFGFilter(const char *file, const char *function, int line, int listtype) +{ + SCLogFGFilterFile *fgf_file = NULL; + SCLogFGFilterFunc *fgf_func = NULL; + SCLogFGFilterLine *fgf_line = NULL; + int match = 1; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return -1; + } + + SCMutexLock(&sc_log_fg_filters_m[listtype]); + + fgf_file = sc_log_fg_filters[listtype]; + + if (fgf_file == NULL) { + SCMutexUnlock(&sc_log_fg_filters_m[listtype]); + return 1; + } + + while (fgf_file != NULL) { + match = 1; + + match &= (fgf_file->file != NULL) ? !strcmp(file, fgf_file->file) : 1; + + if (match == 0) { + fgf_file = fgf_file->next; + continue; + } + + fgf_func = fgf_file->func; + while (fgf_func != NULL) { + match = 1; + + match &= (fgf_func->func != NULL) ? !strcmp(function, fgf_func->func) : 1; + + if (match == 0) { + fgf_func = fgf_func->next; + continue; + } + + fgf_line = fgf_func->line; + while (fgf_line != NULL) { + match = 1; + + match &= (fgf_line->line != -1) ? (line == fgf_line->line) : 1; + + if (match == 1) + break; + + fgf_line = fgf_line->next; + } + + if (match == 1) + break; + + fgf_func = fgf_func->next; + } + + if (match == 1) { + SCMutexUnlock(&sc_log_fg_filters_m[listtype]); + if (listtype == SC_LOG_FILTER_WL) + return 1; + else + return 0; + } + + fgf_file = fgf_file->next; + } + + SCMutexUnlock(&sc_log_fg_filters_m[listtype]); + + if (listtype == SC_LOG_FILTER_WL) + return 0; + else + return 1; +} + +/** + * \brief Checks if there is a match for the incoming log_message with any + * of the FG filters. If there is a match, it allows the message + * to be logged, else it rejects that message. + * + * \param file File_name from where the log_message originated + * \param function Function_name from where the log_message originated + * \param line Line number from where the log_message originated + * + * \retval 1 if there is a match + * \retval 0 on no match + * \retval -1 on failure + */ +int SCLogMatchFGFilterWL(const char *file, const char *function, int line) +{ + return SCLogMatchFGFilter(file, function, line, SC_LOG_FILTER_WL); +} + +/** + * \brief Checks if there is a match for the incoming log_message with any + * of the FG filters. If there is a match it rejects the logging + * for that messages, else it allows that message to be logged + * + * \param file File_name from where the log_message originated + * \param function Function_name from where the log_message originated + * \param line Line number from where the log_message originated + * + * \retval 1 if there is a match + * \retval 0 on no match + * \retval -1 on failure + */ +int SCLogMatchFGFilterBL(const char *file, const char *function, int line) +{ + return SCLogMatchFGFilter(file, function, line, SC_LOG_FILTER_BL); +} + +/** + * \brief Adds a Whitelist(WL) fine-grained(FG) filter. A FG filter WL filter + * allows messages that match this filter, to be logged, while the filter + * is defined using a file_name, function_name and line_number. + * + * If a particular parameter in the fg-filter(file, function and line), + * shouldn't be considered while logging the message, one can supply + * NULL for the file_name or function_name and a negative line_no. + * + * \param file File_name of the filter + * \param function Function_name of the filter + * \param line Line number of the filter + * + * \retval 0 on successfully adding the filter; + * \retval -1 on failure + */ +int SCLogAddFGFilterWL(const char *file, const char *function, int line) +{ + return SCLogAddFGFilter(file, function, line, SC_LOG_FILTER_WL); +} + +/** + * \brief Adds a Blacklist(BL) fine-grained(FG) filter. A FG filter BL filter + * allows messages that don't match this filter, to be logged, while the + * filter is defined using a file_name, function_name and line_number + * + * If a particular parameter in the fg-filter(file, function and line), + * shouldn't be considered while logging the message, one can supply + * NULL for the file_name or function_name and a negative line_no. + * + * \param file File_name of the filter + * \param function Function_name of the filter + * \param line Line number of the filter + * + * \retval 0 on successfully adding the filter + * \retval -1 on failure + */ +int SCLogAddFGFilterBL(const char *file, const char *function, int line) +{ + return SCLogAddFGFilter(file, function, line, SC_LOG_FILTER_BL); +} + +void SCLogReleaseFGFilters(void) +{ + SCLogFGFilterFile *fgf_file = NULL; + SCLogFGFilterFunc *fgf_func = NULL; + SCLogFGFilterLine *fgf_line = NULL; + + void *temp = NULL; + + int i = 0; + + for (i = 0; i < SC_LOG_FILTER_MAX; i++) { + SCMutexLock(&sc_log_fg_filters_m[i]); + + fgf_file = sc_log_fg_filters[i]; + while (fgf_file != NULL) { + + fgf_func = fgf_file->func; + while (fgf_func != NULL) { + + fgf_line = fgf_func->line; + while (fgf_line != NULL) { + temp = fgf_line; + fgf_line = fgf_line->next; + SCFree(temp); + } + + if (fgf_func->func != NULL) + SCFree(fgf_func->func); + temp = fgf_func; + fgf_func = fgf_func->next; + SCFree(temp); + } + + if (fgf_file->file != NULL) + SCFree(fgf_file->file); + temp = fgf_file; + fgf_file = fgf_file->next; + SCFree(temp); + } + + SCMutexUnlock(&sc_log_fg_filters_m[i]); + sc_log_fg_filters[i] = NULL; + } + + return; +} + +/** + * \brief Prints the FG filters(both WL and BL). Used for debugging purposes. + * + * \retval count The no of FG filters + */ +int SCLogPrintFGFilters(void) +{ + SCLogFGFilterFile *fgf_file = NULL; + SCLogFGFilterFunc *fgf_func = NULL; + SCLogFGFilterLine *fgf_line = NULL; + + int count = 0; + int i = 0; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return 0; + } + +#ifdef DEBUG + printf("Fine grained filters:\n"); +#endif + + for (i = 0; i < SC_LOG_FILTER_MAX; i++) { + SCMutexLock(&sc_log_fg_filters_m[i]); + + fgf_file = sc_log_fg_filters[i]; + while (fgf_file != NULL) { + + fgf_func = fgf_file->func; + while (fgf_func != NULL) { + + fgf_line = fgf_func->line; + while (fgf_line != NULL) { +#ifdef DEBUG + printf("%s - ", fgf_file->file); + printf("%s - ", fgf_func->func); + printf("%d\n", fgf_line->line); +#endif + + count++; + + fgf_line = fgf_line->next; + } + + fgf_func = fgf_func->next; + } + + fgf_file = fgf_file->next; + } + SCMutexUnlock(&sc_log_fg_filters_m[i]); + } + + return count; +} + +/* --------------------------------------------------|-------------------------- + * -------------------------- Code for the FD Filter |-------------------------- + * --------------------------------------------------V-------------------------- + */ + +/** + * \brief Checks if there is a match for the incoming log_message with any + * of the FD filters + * + * \param function Function_name from where the log_message originated + * + * \retval 1 if there is a match + * \retval 0 on no match; + */ +int SCLogMatchFDFilter(const char *function) +{ +#ifndef DEBUG + return 1; +#else + SCLogFDFilterThreadList *thread_list = NULL; + + pthread_t self = pthread_self(); + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return 0; + } + + SCMutexLock(&sc_log_fd_filters_tl_m); + + if (sc_log_fd_filters_tl == NULL) { + SCMutexUnlock(&sc_log_fd_filters_tl_m); + if (sc_log_fd_filters != NULL) + return 0; + return 1; + } + + thread_list = sc_log_fd_filters_tl; + while (thread_list != NULL) { + if (pthread_equal(self, thread_list->t)) { + if (thread_list->entered > 0) { + SCMutexUnlock(&sc_log_fd_filters_tl_m); + return 1; + } + SCMutexUnlock(&sc_log_fd_filters_tl_m); + return 0; + } + + thread_list = thread_list->next; + } + + SCMutexUnlock(&sc_log_fd_filters_tl_m); + + return 0; +#endif +} + +/** + * \brief Updates a FD filter, based on whether the function that calls this + * function, is registered as a FD filter or not. This is called by + * a function only on its entry + * + * \param function Function_name from where the log_message originated + * + * \retval 1 Since it is a hack to get things working inside the macros + */ +int SCLogCheckFDFilterEntry(const char *function) +{ + SCLogFDFilter *curr = NULL; + + SCLogFDFilterThreadList *thread_list = NULL; + SCLogFDFilterThreadList *thread_list_temp = NULL; + + // pid_t self = syscall(SYS_gettid); + pthread_t self = pthread_self(); + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return 0; + } + + SCMutexLock(&sc_log_fd_filters_m); + + curr = sc_log_fd_filters; + + while (curr != NULL) { + if (strcmp(function, curr->func) == 0) + break; + + curr = curr->next; + } + + if (curr == NULL) { + SCMutexUnlock(&sc_log_fd_filters_m); + return 1; + } + + SCMutexUnlock(&sc_log_fd_filters_m); + + SCMutexLock(&sc_log_fd_filters_tl_m); + + thread_list = sc_log_fd_filters_tl; + while (thread_list != NULL) { + if (pthread_equal(self, thread_list->t)) + break; + + thread_list = thread_list->next; + } + + if (thread_list != NULL) { + thread_list->entered++; + SCMutexUnlock(&sc_log_fd_filters_tl_m); + return 1; + } + + if ((thread_list_temp = SCCalloc(1, sizeof(SCLogFDFilterThreadList))) == NULL) { + SCMutexUnlock(&sc_log_fd_filters_tl_m); + return 0; + } + + thread_list_temp->t = self; + thread_list_temp->entered++; + + sc_log_fd_filters_tl = thread_list_temp; + + SCMutexUnlock(&sc_log_fd_filters_tl_m); + + return 1; +} + +/** + * \brief Updates a FD filter, based on whether the function that calls this + * function, is registered as a FD filter or not. This is called by + * a function only before its exit. + * + * \param function Function_name from where the log_message originated + * + */ +void SCLogCheckFDFilterExit(const char *function) +{ + SCLogFDFilter *curr = NULL; + + SCLogFDFilterThreadList *thread_list = NULL; + + // pid_t self = syscall(SYS_gettid); + pthread_t self = pthread_self(); + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return; + } + + SCMutexLock(&sc_log_fd_filters_m); + + curr = sc_log_fd_filters; + + while (curr != NULL) { + if (strcmp(function, curr->func) == 0) + break; + + curr = curr->next; + } + + if (curr == NULL) { + SCMutexUnlock(&sc_log_fd_filters_m); + return; + } + + SCMutexUnlock(&sc_log_fd_filters_m); + + SCMutexLock(&sc_log_fd_filters_tl_m); + + thread_list = sc_log_fd_filters_tl; + while (thread_list != NULL) { + if (pthread_equal(self, thread_list->t)) + break; + + thread_list = thread_list->next; + } + + SCMutexUnlock(&sc_log_fd_filters_tl_m); + + if (thread_list != NULL) + thread_list->entered--; + + return; +} + +/** + * \brief Adds a Function-Dependent(FD) filter + * + * \param Name of the function for which a FD filter has to be registered + * + * \retval 0 on success + * \retval -1 on failure + */ +int SCLogAddFDFilter(const char *function) +{ + SCLogFDFilter *curr = NULL; + SCLogFDFilter *prev = NULL; + SCLogFDFilter *temp = NULL; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return -1; + } + + if (function == NULL) { + printf("Invalid argument supplied to SCLogAddFDFilter\n"); + return -1; + } + + SCMutexLock(&sc_log_fd_filters_m); + + curr = sc_log_fd_filters; + while (curr != NULL) { + prev = curr; + + if (strcmp(function, curr->func) == 0) { + + SCMutexUnlock(&sc_log_fd_filters_m); + return 0; + } + + curr = curr->next; + } + + if ((temp = SCCalloc(1, sizeof(SCLogFDFilter))) == NULL) { + printf("Error Allocating memory (SCCalloc)\n"); + exit(EXIT_FAILURE); + } + + if ((temp->func = SCStrdup(function)) == NULL) { + printf("Error Allocating memory (SCStrdup)\n"); + exit(EXIT_FAILURE); + } + + if (sc_log_fd_filters == NULL) + sc_log_fd_filters = temp; + /* clang thinks prev can be NULL, but it can't be unless + * sc_log_fd_filters is also NULL which is handled here. + * Doing this "fix" to shut clang up. */ + else if (prev != NULL) + prev->next = temp; + + SCMutexUnlock(&sc_log_fd_filters_m); + sc_log_fd_filters_present = 1; + + return 0; +} + +/** + * \brief Releases all the FD filters added to the logging module + */ +void SCLogReleaseFDFilters(void) +{ + SCLogFDFilter *fdf = NULL; + SCLogFDFilter *temp = NULL; + + SCMutexLock(&sc_log_fd_filters_m); + + fdf = sc_log_fd_filters; + while (fdf != NULL) { + temp = fdf; + fdf = fdf->next; + SCLogReleaseFDFilter(temp); + } + + sc_log_fd_filters = NULL; + + SCMutexUnlock(&sc_log_fd_filters_m); + + return; +} + +/** + * \brief Removes a Function-Dependent(FD) filter + * + * \param Name of the function for which a FD filter has to be unregistered + * + * \retval 0 on success(the filter was removed or the filter was not present) + * \retval -1 on failure/error + */ +int SCLogRemoveFDFilter(const char *function) +{ + SCLogFDFilter *curr = NULL; + SCLogFDFilter *prev = NULL; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return -1; + } + + if (function == NULL) { + printf("Invalid argument(s) supplied to SCLogRemoveFDFilter\n"); + return -1; + } + + SCMutexLock(&sc_log_fd_filters_m); + + if (sc_log_fd_filters == NULL) { + SCMutexUnlock(&sc_log_fd_filters_m); + return 0; + } + + curr = sc_log_fd_filters; + prev = curr; + while (curr != NULL) { + if (strcmp(function, curr->func) == 0) + break; + + prev = curr; + curr = curr->next; + } + + if (curr == NULL) { + + SCMutexUnlock(&sc_log_fd_filters_m); + + return 0; + } + + if (sc_log_fd_filters == curr) + sc_log_fd_filters = curr->next; + else + prev->next = curr->next; + + SCLogReleaseFDFilter(curr); + + SCMutexUnlock(&sc_log_fd_filters_m); + + if (sc_log_fd_filters == NULL) + sc_log_fd_filters_present = 0; + + return 0; +} + +/** + * \brief Prints the FG filters(both WL and BL). Used for debugging purposes. + * + * \retval count The no of FG filters + */ +int SCLogPrintFDFilters(void) +{ + SCLogFDFilter *fdf = NULL; + int count = 0; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return 0; + } + +#ifdef DEBUG + printf("FD filters:\n"); +#endif + + SCMutexLock(&sc_log_fd_filters_m); + + fdf = sc_log_fd_filters; + while (fdf != NULL) { +#ifdef DEBUG + printf("%s \n", fdf->func); +#endif + fdf = fdf->next; + count++; + } + + SCMutexUnlock(&sc_log_fd_filters_m); + + return count; +} + +/** + * \brief Helper function used internally to add a FG filter. This function is + * called when the file component of the incoming filter has no entry + * in the filter list. + * + * \param fgf_file The file component(basically the position in the list) from + * the filter list, after which the new filter has to be added + * \param file File_name of the filter + * \param function Function_name of the filter + * \param line Line number of the filter + * \param listtype The filter listtype. Can be either a blacklist or whitelist + * filter listtype(SC_LOG_FILTER_BL or SC_LOG_FILTER_WL) + */ +void SCLogAddToFGFFileList( + SCLogFGFilterFile *fgf_file, const char *file, const char *function, int line, int listtype) +{ + SCLogFGFilterFile *fgf_file_temp = NULL; + SCLogFGFilterFunc *fgf_func_temp = NULL; + SCLogFGFilterLine *fgf_line_temp = NULL; + + if ((fgf_file_temp = SCCalloc(1, sizeof(SCLogFGFilterFile))) == NULL) { + FatalError("Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); + } + + if (file != NULL && (fgf_file_temp->file = SCStrdup(file)) == NULL) { + printf("Error Allocating memory\n"); + exit(EXIT_FAILURE); + } + + if ((fgf_func_temp = SCCalloc(1, sizeof(SCLogFGFilterFunc))) == NULL) { + FatalError("Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); + } + + if (function != NULL && (fgf_func_temp->func = SCStrdup(function)) == NULL) { + printf("Error Allocating memory\n"); + exit(EXIT_FAILURE); + } + + if ((fgf_line_temp = SCCalloc(1, sizeof(SCLogFGFilterLine))) == NULL) { + FatalError("Fatal error encountered in SCLogAddToFGFFileList. Exiting..."); + } + + fgf_line_temp->line = line; + + /* add to the lists */ + fgf_func_temp->line = fgf_line_temp; + + fgf_file_temp->func = fgf_func_temp; + + if (fgf_file == NULL) + sc_log_fg_filters[listtype] = fgf_file_temp; + else + fgf_file->next = fgf_file_temp; + + return; +} + +/** + * \brief Helper function used internally to add a FG filter. This function is + * called when the file component of the incoming filter has an entry + * in the filter list, but the function component doesn't have an entry + * for the corresponding file component + * + * \param fgf_file The file component from the filter list to which the new + * filter has to be added + * \param fgf_func The function component(basically the position in the list), + * from the filter list, after which the new filter has to be + * added + * \param function Function_name of the filter + * \param line Line number of the filter + */ +void SCLogAddToFGFFuncList( + SCLogFGFilterFile *fgf_file, SCLogFGFilterFunc *fgf_func, const char *function, int line) +{ + SCLogFGFilterFunc *fgf_func_temp = NULL; + SCLogFGFilterLine *fgf_line_temp = NULL; + + if ((fgf_func_temp = SCCalloc(1, sizeof(SCLogFGFilterFunc))) == NULL) { + FatalError("Fatal error encountered in SCLogAddToFGFFuncList. Exiting..."); + } + + if (function != NULL && (fgf_func_temp->func = SCStrdup(function)) == NULL) { + printf("Error Allocating memory\n"); + exit(EXIT_FAILURE); + } + + if ((fgf_line_temp = SCCalloc(1, sizeof(SCLogFGFilterLine))) == NULL) { + FatalError("Fatal error encountered in SCLogAddToFGFFuncList. Exiting..."); + } + + fgf_line_temp->line = line; + + /* add to the lists */ + fgf_func_temp->line = fgf_line_temp; + + if (fgf_func == NULL) + fgf_file->func = fgf_func_temp; + else + fgf_func->next = fgf_func_temp; + + return; +} + +/** + * \brief Helper function used internally to add a FG filter. This function is + * called when the file and function components of the incoming filter + * have an entry in the filter list, but the line component doesn't have + * an entry for the corresponding function component + * + * \param fgf_func The function component from the filter list to which the new + * filter has to be added + * \param fgf_line The function component(basically the position in the list), + * from the filter list, after which the new filter has to be + * added + * \param line Line number of the filter + */ +void SCLogAddToFGFLineList(SCLogFGFilterFunc *fgf_func, SCLogFGFilterLine *fgf_line, int line) +{ + SCLogFGFilterLine *fgf_line_temp = NULL; + + if ((fgf_line_temp = SCCalloc(1, sizeof(SCLogFGFilterLine))) == NULL) { + FatalError("Fatal error encountered in SCLogAddToFGFLineList. Exiting..."); + } + + fgf_line_temp->line = line; + + /* add to the lists */ + if (fgf_line == NULL) + fgf_func->line = fgf_line_temp; + else + fgf_line->next = fgf_line_temp; + + return; +} + +/** + * \brief Releases the memory alloted to a FD filter + * + * \param Pointer to the FD filter that has to be freed + */ +void SCLogReleaseFDFilter(SCLogFDFilter *fdf) +{ + if (fdf != NULL) { + if (fdf->func != NULL) + SCFree(fdf->func); + SCFree(fdf); + } + + return; +} diff --git a/src/util/debug-filters.h b/src/util/debug-filters.h new file mode 100644 index 000000000000..47ef7d979351 --- /dev/null +++ b/src/util/debug-filters.h @@ -0,0 +1,126 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __DEBUG_FILTERS_H__ +#define __DEBUG_FILTERS_H__ + +// pthread_t +#include "threads.h" + +/** + * \brief Enum that holds the different kinds of filters available + */ +enum { + SC_LOG_FILTER_BL = 0, + SC_LOG_FILTER_WL = 1, + SC_LOG_FILTER_MAX = 2, +}; + +/** + * \brief Structure used to hold the line_no details of a FG filter + */ +typedef struct SCLogFGFilterLine_ { + int line; + + struct SCLogFGFilterLine_ *next; +} SCLogFGFilterLine; + +/** + * \brief structure used to hold the function details of a FG filter + */ +typedef struct SCLogFGFilterFunc_ { + char *func; + SCLogFGFilterLine *line; + + struct SCLogFGFilterFunc_ *next; +} SCLogFGFilterFunc; + +/** + * \brief Structure used to hold FG filters. Encapsulates filename details, + * func details, which inturn encapsulates the line_no details + */ +typedef struct SCLogFGFilterFile_ { + char *file; + SCLogFGFilterFunc *func; + + struct SCLogFGFilterFile_ *next; +} SCLogFGFilterFile; + +/** + * \brief Structure used to hold the thread_list used by FD filters + */ +typedef struct SCLogFDFilterThreadList_ { + int entered; + pthread_t t; + // pid_t t; + + struct SCLogFDFilterThreadList_ *next; +} SCLogFDFilterThreadList; + +/** + * \brief Structure that holds the FD filters + */ +typedef struct SCLogFDFilter_ { + char *func; + + struct SCLogFDFilter_ *next; +} SCLogFDFilter; + +extern int sc_log_fg_filters_present; + +extern int sc_log_fd_filters_present; + +int SCLogAddFGFilterWL(const char *, const char *, int); + +int SCLogAddFGFilterBL(const char *, const char *, int); + +int SCLogMatchFGFilterBL(const char *, const char *, int); + +int SCLogMatchFGFilterWL(const char *, const char *, int); + +void SCLogReleaseFGFilters(void); + +int SCLogAddFDFilter(const char *); + +int SCLogPrintFDFilters(void); + +void SCLogReleaseFDFilters(void); + +int SCLogRemoveFDFilter(const char *); + +int SCLogCheckFDFilterEntry(const char *); + +void SCLogCheckFDFilterExit(const char *); + +int SCLogMatchFDFilter(const char *); + +int SCLogPrintFGFilters(void); + +void SCLogAddToFGFFileList(SCLogFGFilterFile *, const char *, const char *, int, int); + +void SCLogAddToFGFFuncList(SCLogFGFilterFile *, SCLogFGFilterFunc *, const char *, int); + +void SCLogAddToFGFLineList(SCLogFGFilterFunc *, SCLogFGFilterLine *, int); + +void SCLogReleaseFDFilter(SCLogFDFilter *); +#endif /* __DEBUG_FILTERS_H__ */ diff --git a/src/util/debug.c b/src/util/debug.c new file mode 100644 index 000000000000..523fbbb9a4f6 --- /dev/null +++ b/src/util/debug.c @@ -0,0 +1,1808 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Debug utility functions + */ + +#include "suricata-common.h" +#include "util/debug.h" + +#include "output/output.h" + +#include "suricata.h" + +#include "util/conf.h" +#include "util/enum.h" +#include "util/path.h" +#include "util/syslog.h" +#include "util/time.h" + +// clang-format off +/* holds the string-enum mapping for the enums held in the table SCLogLevel */ +SCEnumCharMap sc_log_level_map[] = { + { "Not set", SC_LOG_NOTSET }, + { "None", SC_LOG_NONE }, + { "Error", SC_LOG_ERROR }, + { "Warning", SC_LOG_WARNING }, + { "Notice", SC_LOG_NOTICE }, + { "Info", SC_LOG_INFO }, + { "Perf", SC_LOG_PERF }, + { "Config", SC_LOG_CONFIG }, + { "Debug", SC_LOG_DEBUG }, + { NULL, -1 } +}; + +SCEnumCharMap sc_log_slevel_map[] = { + { "Not set", SC_LOG_NOTSET }, + { "None", SC_LOG_NONE }, + { "E", SC_LOG_ERROR }, + { "W", SC_LOG_WARNING }, + { "i", SC_LOG_NOTICE }, + { "i", SC_LOG_INFO }, + { "i", SC_LOG_PERF }, + { "i", SC_LOG_CONFIG }, + { "d", SC_LOG_DEBUG }, + { NULL, -1 } +}; + +/* holds the string-enum mapping for the enums held in the table SCLogOPIface */ +SCEnumCharMap sc_log_op_iface_map[ ] = { + { "Console", SC_LOG_OP_IFACE_CONSOLE }, + { "File", SC_LOG_OP_IFACE_FILE }, + { "Syslog", SC_LOG_OP_IFACE_SYSLOG }, + { NULL, -1 } +}; +// clang-format on + +#if defined(OS_WIN32) +/** + * \brief Used for synchronous output on WIN32 + */ +static SCMutex sc_log_stream_lock; +#endif /* OS_WIN32 */ + +/** + * \brief Transform the module name into display module name for logging + */ +static const char *SCTransformModule(const char *module_name, int *dn_len); + +/** + * \brief Holds the config state for the logging module + */ +static SCLogConfig *sc_log_config = NULL; + +/** + * \brief Returns the full path given a file and configured log dir + */ +static char *SCLogGetLogFilename(const char *); + +/** + * \brief Holds the global log level. Is the same as sc_log_config->log_level + */ +SCLogLevel sc_log_global_log_level; + +/** + * \brief Used to indicate whether the logging module has been init or not + */ +int sc_log_module_initialized = 0; + +/** + * \brief Used to indicate whether the logging module has been cleaned or not + */ +int sc_log_module_cleaned = 0; + +/** + * \brief Maps the SC logging level to the syslog logging level + * + * \param The SC logging level that has to be mapped to the syslog_log_level + * + * \retval syslog_log_level The mapped syslog_api_log_level, for the logging + * module api's internal log_level + */ +static inline int SCLogMapLogLevelToSyslogLevel(int log_level) +{ + int syslog_log_level = 0; + + switch (log_level) { + case SC_LOG_ERROR: + syslog_log_level = LOG_ERR; + break; + case SC_LOG_WARNING: + syslog_log_level = LOG_WARNING; + break; + case SC_LOG_NOTICE: + syslog_log_level = LOG_NOTICE; + break; + case SC_LOG_INFO: + syslog_log_level = LOG_INFO; + break; + case SC_LOG_CONFIG: + case SC_LOG_DEBUG: + case SC_LOG_PERF: + syslog_log_level = LOG_DEBUG; + break; + default: + syslog_log_level = LOG_EMERG; + break; + } + + return syslog_log_level; +} + +/** + * \brief Output function that logs a character string out to a file descriptor + * + * \param fd Pointer to the file descriptor + * \param msg Pointer to the character string that should be logged + */ +static inline void SCLogPrintToStream(FILE *fd, char *msg) +{ + /* Would only happen if the log file failed to re-open during rotation. */ + if (fd == NULL) { + return; + } + +#if defined(OS_WIN32) + SCMutexLock(&sc_log_stream_lock); +#endif /* OS_WIN32 */ + + if (fprintf(fd, "%s\n", msg) < 0) + printf("Error writing to stream using fprintf\n"); + + fflush(fd); + +#if defined(OS_WIN32) + SCMutexUnlock(&sc_log_stream_lock); +#endif /* OS_WIN32 */ + + return; +} + +/** + * \brief Output function that logs a character string through the syslog iface + * + * \param syslog_log_level Holds the syslog_log_level that the message should be + * logged as + * \param msg Pointer to the char string, that should be logged + * + * \todo syslog is thread-safe according to POSIX manual and glibc code, but we + * we will have to look into non POSIX compliant boxes like freeBSD + */ +static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) +{ + // static struct syslog_data data = SYSLOG_DATA_INIT; + // syslog_r(syslog_log_level, NULL, "%s", msg); + + syslog(syslog_log_level, "%s", msg); + + return; +} + +/** + */ +static int SCLogMessageJSON(SCTime_t tval, char *buffer, size_t buffer_size, SCLogLevel log_level, + const char *file, unsigned line, const char *function, const char *module, + const char *message) +{ + JsonBuilder *js = jb_new_object(); + if (unlikely(js == NULL)) + goto error; + + char timebuf[64]; + CreateIsoTimeString(tval, timebuf, sizeof(timebuf)); + jb_set_string(js, "timestamp", timebuf); + + const char *s = SCMapEnumValueToName(log_level, sc_log_level_map); + if (s != NULL) { + jb_set_string(js, "log_level", s); + } else { + JB_SET_STRING(js, "log_level", "INVALID"); + } + + JB_SET_STRING(js, "event_type", "engine"); + jb_open_object(js, "engine"); + + if (message) + jb_set_string(js, "message", message); + + if (t_thread_name[0] != '\0') { + jb_set_string(js, "thread_name", t_thread_name); + } + + if (module) { + /* Determine how much of module name to display */ + int dn_len = 0; + const char *dn_name; + dn_name = SCTransformModule(module, &dn_len); + jb_set_string(js, "module", dn_name); + } + + if (log_level >= SC_LOG_DEBUG) { + if (function) + jb_set_string(js, "function", function); + + if (file) + jb_set_string(js, "file", file); + + if (line > 0) + jb_set_uint(js, "line", line); + } + jb_close(js); // engine + + jb_close(js); + memcpy(buffer, jb_ptr(js), MIN(buffer_size, jb_len(js))); + + jb_free(js); + + return 0; + +error: + return -1; +} + +static const int transform_max_segs = 2; /* The maximum segment count to display */ +/* + * \brief Return a display name for the given module name for logging. + * + * The transformation is dependent upon the source code module names + * that use the dash character to separate incremental refinements of + * the subsystem. + * + * The transformation uses the local constant "transform_max_segs" to determine + * how many segments to display; the transformed name will never consist + * of more than this many segments. + * + * E.g., "detect-http-content-len" ==> "detect-http" when the max is 2 + * + * \param module_name The source code module name to be transformed. + * \param dn_len The number of characters in the display name to print. + * + * \retval Pointer to the display name + */ +static const char *SCTransformModule(const char *module_name, int *dn_len) +{ + /* + * special case for source code module names beginning with: + * Prefixes skipped + * tm-* + * util-* + * source-* + * No transformation + * app-layer-* + */ + if (strncmp("tm-", module_name, 3) == 0) { + *dn_len = strlen(module_name) - 3; + return module_name + 3; + } else if (strncmp("util-", module_name, 5) == 0) { + *dn_len = strlen(module_name) - 5; + return module_name + 5; + } else if (strncmp("source-pcap-file", module_name, 16) == 0) { + *dn_len = strlen("pcap"); + return "pcap"; + } else if (strncmp("source-", module_name, 7) == 0) { + *dn_len = strlen(module_name) - 7; + return module_name + 7; + } else if (strncmp("runmode-", module_name, 8) == 0) { + *dn_len = strlen(module_name) - 8; + return module_name + 8; + } else if (strncmp("app-layer-", module_name, 10) == 0) { + *dn_len = strlen(module_name); + return module_name; + } else if (strncmp("detect-engine", module_name, 13) == 0) { + *dn_len = strlen("detect"); + return "detect"; + } + + int seg_cnt = 0; + + char *last; + char *w = (char *)module_name; + while (w && (w = strchr(w, '-')) != NULL && seg_cnt < transform_max_segs) { + seg_cnt++; + last = w; + w++; /* skip past '-' */ + } + + if (seg_cnt < transform_max_segs) + *dn_len = strlen(module_name); + else + *dn_len = last - module_name; + + return module_name; +} + +/** + * \brief Adds the global log_format to the outgoing buffer + * + * \param log_level log_level of the message that has to be logged + * \param msg Buffer containing the outgoing message + * \param file File_name from where the message originated + * \param function Function_name from where the message originated + * \param line Line_no from where the messaged originated + * + * \retval 0 on success; else a negative value on error + */ +static SCError SCLogMessageGetBuffer(SCTime_t tval, bool color, SCLogOPType type, char *buffer, + size_t buffer_size, const char *log_format, const SCLogLevel log_level, const char *file, + const unsigned int line, const char *function, const char *module, const char *message) +{ + if (type == SC_LOG_OP_TYPE_JSON) + return SCLogMessageJSON( + tval, buffer, buffer_size, log_level, file, line, function, module, message); + + char *temp = buffer; + const char *s = NULL; + struct tm *tms = NULL; + + const char *redb = ""; + const char *red = ""; + const char *yellowb = ""; + const char *yellow = ""; + const char *green = ""; + const char *blue = ""; + const char *reset = ""; + if (color) { + redb = "\x1b[1;31m"; + red = "\x1b[31m"; + yellowb = "\x1b[1;33m"; + yellow = "\x1b[33m"; + green = "\x1b[32m"; + blue = "\x1b[34m"; + reset = "\x1b[0m"; + } + /* no of characters_written(cw) by snprintf */ + int cw = 0; + + BUG_ON(sc_log_module_initialized != 1); + + /* make a copy of the format string as it will be modified below */ + const int add_M = strstr(log_format, "%M") == NULL; + char local_format[strlen(log_format) + add_M * 2 + 1]; + strlcpy(local_format, log_format, sizeof(local_format)); + if (add_M) + strlcat(local_format, "%M", sizeof(local_format)); + char *temp_fmt = local_format; + char *substr = temp_fmt; + struct tm local_tm; + + while ((temp_fmt = strchr(temp_fmt, SC_LOG_FMT_PREFIX))) { + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + return 0; + } + switch (temp_fmt[1]) { + case SC_LOG_FMT_TIME: + temp_fmt[0] = '\0'; + + tms = SCLocalTime(SCTIME_SECS(tval), &local_tm); + + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%04d-%02d-%02d %02d:%02d:%02d%s", substr, green, tms->tm_year + 1900, + tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec, + reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_TIME_LEGACY: + temp_fmt[0] = '\0'; + + tms = SCLocalTime(SCTIME_SECS(tval), &local_tm); + + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%d/%d/%04d -- %02d:%02d:%02d%s", substr, green, tms->tm_mday, + tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, + tms->tm_sec, reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_PID: + temp_fmt[0] = '\0'; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%u%s", substr, + yellow, getpid(), reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_TID: + temp_fmt[0] = '\0'; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%lu%s", substr, + yellow, SCGetThreadIdLong(), reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_THREAD_NAME: + case SC_LOG_FMT_TM: + temp_fmt[0] = '\0'; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, + yellow, t_thread_name, reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_LOG_LEVEL: + temp_fmt[0] = '\0'; + s = SCMapEnumValueToName(log_level, sc_log_level_map); + if (s != NULL) { + if (log_level <= SC_LOG_ERROR) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, redb, s, reset); + else if (log_level == SC_LOG_WARNING) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, red, s, reset); + else if (log_level == SC_LOG_NOTICE) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, yellowb, s, reset); + else + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, yellow, s, reset); + } else { + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, + "INVALID"); + } + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_LOG_SLEVEL: + temp_fmt[0] = '\0'; + s = SCMapEnumValueToName(log_level, sc_log_slevel_map); + if (s != NULL) { + if (log_level <= SC_LOG_ERROR) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, redb, s, reset); + else if (log_level == SC_LOG_WARNING) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, red, s, reset); + else if (log_level == SC_LOG_NOTICE) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, yellowb, s, reset); + else + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", + substr, yellow, s, reset); + } else { + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, + "INVALID"); + } + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_FILE_NAME: + temp_fmt[0] = '\0'; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, + blue, file, reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_LINE: + temp_fmt[0] = '\0'; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%u%s", substr, + green, line, reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_SUBSYSTEM: + temp_fmt[0] = '\0'; + + /* Determine how much of module name to display */ + int dn_len = 0; + const char *dn_name = "unknown"; + if (module) { + dn_name = SCTransformModule(module, &dn_len); + } + + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, + green, dn_name, reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_FUNCTION: + temp_fmt[0] = '\0'; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr, + green, function, reset); + if (cw < 0) + return -1; + temp += cw; + temp_fmt++; + substr = temp_fmt; + substr++; + break; + + case SC_LOG_FMT_MESSAGE: { + temp_fmt[0] = '\0'; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr); + if (cw < 0) { + return -1; + } + temp += cw; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + return 0; + } + const char *hi = ""; + if (log_level <= SC_LOG_ERROR) + hi = red; + else if (log_level <= SC_LOG_NOTICE) + hi = yellow; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message, + reset); + if (cw < 0) { + return -1; + } + temp += cw; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + return 0; + } + temp_fmt++; + substr = temp_fmt; + substr++; + break; + } + } + temp_fmt++; + } + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + return 0; + } + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr); + if (cw < 0) { + return -1; + } + if (sc_log_config->op_filter_regex != NULL) { + if (pcre2_match(sc_log_config->op_filter_regex, (PCRE2_SPTR8)buffer, strlen(buffer), 0, 0, + sc_log_config->op_filter_regex_match, NULL) < 0) { + return -1; // bit hacky, but just return !0 + } + } + + return 0; +} + +/** \internal + * \brief try to reopen file + * \note no error reporting here, as we're called by SCLogMessage + * \retval status 0 ok, -1 error */ +static int SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx) +{ + if (op_iface_ctx->file == NULL) { + return 0; + } + + if (op_iface_ctx->file_d != NULL) { + fclose(op_iface_ctx->file_d); + } + op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a"); + if (op_iface_ctx->file_d == NULL) { + return -1; + } + return 0; +} + +/** + * \brief Adds the global log_format to the outgoing buffer + * + * \param log_level log_level of the message that has to be logged + * \param msg Buffer containing the outgoing message + * \param file File_name from where the message originated + * \param function Function_name from where the message originated + * \param line Line_no from where the messaged originated + * + * \retval SC_OK on success; else an error code + */ +SCError SCLogMessage(const SCLogLevel log_level, const char *file, const unsigned int line, + const char *function, const char *module, const char *message) +{ + char buffer[SC_LOG_MAX_LOG_MSG_LEN] = ""; + SCLogOPIfaceCtx *op_iface_ctx = NULL; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return SC_OK; + } + + /* get ts here so we log the same ts to each output */ + struct timeval tval; + gettimeofday(&tval, NULL); + SCTime_t ts = SCTIME_FROM_TIMEVAL(&tval); + + op_iface_ctx = sc_log_config->op_ifaces; + while (op_iface_ctx != NULL) { + if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) { + op_iface_ctx = op_iface_ctx->next; + continue; + } + + switch (op_iface_ctx->iface) { + case SC_LOG_OP_IFACE_CONSOLE: + if (SCLogMessageGetBuffer(ts, op_iface_ctx->use_color, op_iface_ctx->type, buffer, + sizeof(buffer), + op_iface_ctx->log_format ? op_iface_ctx->log_format + : sc_log_config->log_format, + log_level, file, line, function, module, message) == 0) { + SCLogPrintToStream((log_level == SC_LOG_ERROR) ? stderr : stdout, buffer); + } + break; + case SC_LOG_OP_IFACE_FILE: + if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer), + op_iface_ctx->log_format ? op_iface_ctx->log_format + : sc_log_config->log_format, + log_level, file, line, function, module, message) == 0) { + int r = 0; + SCMutexLock(&op_iface_ctx->fp_mutex); + if (op_iface_ctx->rotation_flag) { + r = SCLogReopen(op_iface_ctx); + op_iface_ctx->rotation_flag = 0; + } + SCLogPrintToStream(op_iface_ctx->file_d, buffer); + SCMutexUnlock(&op_iface_ctx->fp_mutex); + + /* report error outside of lock to avoid recursion */ + if (r == -1) { + SCLogError("re-opening file \"%s\" failed: %s", op_iface_ctx->file, + strerror(errno)); + } + } + break; + case SC_LOG_OP_IFACE_SYSLOG: + if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer), + op_iface_ctx->log_format ? op_iface_ctx->log_format + : sc_log_config->log_format, + log_level, file, line, function, module, message) == 0) { + SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer); + } + break; + default: + break; + } + op_iface_ctx = op_iface_ctx->next; + } + return SC_OK; +} + +void SCLog(int x, const char *file, const char *func, const int line, const char *module, + const char *fmt, ...) +{ + if (sc_log_global_log_level >= x && + (sc_log_fg_filters_present == 0 || SCLogMatchFGFilterWL(file, func, line) == 1 || + SCLogMatchFGFilterBL(file, func, line) == 1) && + (sc_log_fd_filters_present == 0 || SCLogMatchFDFilter(func) == 1)) { + char msg[SC_LOG_MAX_LOG_MSG_LEN]; + va_list ap; + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + SCLogMessage(x, file, line, func, module, msg); + } +} + +void SCLogErr(int x, const char *file, const char *func, const int line, const char *module, + const char *fmt, ...) +{ + if (sc_log_global_log_level >= x && + (sc_log_fg_filters_present == 0 || SCLogMatchFGFilterWL(file, func, line) == 1 || + SCLogMatchFGFilterBL(file, func, line) == 1) && + (sc_log_fd_filters_present == 0 || SCLogMatchFDFilter(func) == 1)) { + char msg[SC_LOG_MAX_LOG_MSG_LEN]; + va_list ap; + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + SCLogMessage(x, file, line, func, module, msg); + } +} + +/** + * \brief Returns whether debug messages are enabled to be logged or not + * + * \retval 1 if debug messages are enabled to be logged + * \retval 0 if debug messages are not enabled to be logged + */ +int SCLogDebugEnabled(void) +{ +#ifdef DEBUG + if (sc_log_global_log_level == SC_LOG_DEBUG) + return 1; + else + return 0; +#else + return 0; +#endif +} + +/** + * \brief Allocates an output buffer for an output interface. Used when we + * want the op_interface log_format to override the global_log_format. + * Currently not used. + * + * \retval buffer Pointer to the newly created output_buffer + */ +SCLogOPBuffer *SCLogAllocLogOPBuffer(void) +{ + SCLogOPBuffer *buffer = NULL; + + if ((buffer = SCMalloc(sc_log_config->op_ifaces_cnt * sizeof(SCLogOPBuffer))) == NULL) { + FatalError("Fatal error encountered in SCLogAllocLogOPBuffer. Exiting..."); + } + + SCLogOPIfaceCtx *op_iface_ctx = sc_log_config->op_ifaces; + for (int i = 0; i < sc_log_config->op_ifaces_cnt; i++, op_iface_ctx = op_iface_ctx->next) { + buffer[i].log_format = op_iface_ctx->log_format; + buffer[i].temp = buffer[i].msg; + } + + return buffer; +} + +/*----------------------The logging module initialization code--------------- */ + +/** + * \brief Returns a new output_interface_context + * + * \retval iface_ctx Pointer to a newly allocated output_interface_context + * \initonly + */ +static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx(void) +{ + SCLogOPIfaceCtx *iface_ctx = NULL; + + if ((iface_ctx = SCCalloc(1, sizeof(SCLogOPIfaceCtx))) == NULL) { + FatalError("Fatal error encountered in SCLogallocLogOPIfaceCtx. Exiting..."); + } + + return iface_ctx; +} + +/** + * \brief Initializes the file output interface + * + * \param file Path to the file used for logging purposes + * \param log_format Pointer to the log_format for this op interface, that + * overrides the global_log_format + * \param log_level Override of the global_log_level by this interface + * + * \retval iface_ctx Pointer to the file output interface context created + * \initonly + */ +static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, uint32_t userid, + uint32_t groupid, const char *log_format, int log_level, SCLogOPType type) +{ + SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); + if (iface_ctx == NULL) { + FatalError("Fatal error encountered in SCLogInitFileOPIface. Exiting..."); + } + + if (file == NULL) { + goto error; + } + + iface_ctx->iface = SC_LOG_OP_IFACE_FILE; + iface_ctx->type = type; + + if ((iface_ctx->file_d = fopen(file, "a")) == NULL) { + SCLogWarning("error opening file %s: %s", file, strerror(errno)); + goto error; + } + +#ifndef OS_WIN32 + if (userid != 0 || groupid != 0) { + if (fchown(fileno(iface_ctx->file_d), userid, groupid) == -1) { + SCLogWarning("Failed to change ownership of file %s: %s", file, strerror(errno)); + } + } +#endif + + if ((iface_ctx->file = SCStrdup(file)) == NULL) { + goto error; + } + + if (log_format != NULL && (iface_ctx->log_format = SCStrdup(log_format)) == NULL) { + goto error; + } + + SCMutexInit(&iface_ctx->fp_mutex, NULL); + OutputRegisterFileRotationFlag(&iface_ctx->rotation_flag); + + iface_ctx->log_level = log_level; + + return iface_ctx; + +error: + if (iface_ctx->file != NULL) { + SCFree((char *)iface_ctx->file); + iface_ctx->file = NULL; + } + if (iface_ctx->log_format != NULL) { + SCFree((char *)iface_ctx->log_format); + iface_ctx->log_format = NULL; + } + if (iface_ctx->file_d != NULL) { + fclose(iface_ctx->file_d); + iface_ctx->file_d = NULL; + } + SCFree(iface_ctx); + return NULL; +} + +/** + * \brief Initializes the console output interface and deals with possible + * env var overrides. + * + * \param log_format Pointer to the log_format for this op interface, that + * overrides the global_log_format + * \param log_level Override of the global_log_level by this interface + * + * \retval iface_ctx Pointer to the console output interface context created + * \initonly + */ +static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface( + const char *log_format, SCLogLevel log_level, SCLogOPType type) +{ + SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); + + if (iface_ctx == NULL) { + FatalError("Fatal error encountered in SCLogInitConsoleOPIface. Exiting..."); + } + + iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE; + iface_ctx->type = type; + + /* console log format is overridden by envvars */ + const char *tmp_log_format = log_format; + const char *s = getenv(SC_LOG_ENV_LOG_FORMAT); + if (s != NULL) { +#if 0 + printf("Overriding setting for \"console.format\" because of env " + "var SC_LOG_FORMAT=\"%s\".\n", s); +#endif + tmp_log_format = s; + } + + if (tmp_log_format != NULL && (iface_ctx->log_format = SCStrdup(tmp_log_format)) == NULL) { + printf("Error allocating memory\n"); + exit(EXIT_FAILURE); + } + + /* console log level is overridden by envvars */ + SCLogLevel tmp_log_level = log_level; + s = getenv(SC_LOG_ENV_LOG_LEVEL); + if (s != NULL) { + SCLogLevel l = SCMapEnumNameToValue(s, sc_log_level_map); + if (l > SC_LOG_NOTSET && l < SC_LOG_LEVEL_MAX) { +#if 0 + printf("Overriding setting for \"console.level\" because of env " + "var SC_LOG_LEVEL=\"%s\".\n", s); +#endif + tmp_log_level = l; + } + } + iface_ctx->log_level = tmp_log_level; + +#ifndef OS_WIN32 + if (isatty(fileno(stdout)) && isatty(fileno(stderr))) { + iface_ctx->use_color = true; + } +#endif + + return iface_ctx; +} + +/** + * \brief Initializes the syslog output interface + * + * \param facility The facility code for syslog + * \param log_format Pointer to the log_format for this op interface, that + * overrides the global_log_format + * \param log_level Override of the global_log_level by this interface + * + * \retval iface_ctx Pointer to the syslog output interface context created + */ +static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface( + int facility, const char *log_format, SCLogLevel log_level, SCLogOPType type) +{ + SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); + + if (iface_ctx == NULL) { + FatalError("Fatal error encountered in SCLogInitSyslogOPIface. Exiting..."); + } + + iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG; + iface_ctx->type = type; + + if (facility == -1) + facility = SC_LOG_DEF_SYSLOG_FACILITY; + iface_ctx->facility = facility; + + if (log_format != NULL && (iface_ctx->log_format = SCStrdup(log_format)) == NULL) { + printf("Error allocating memory\n"); + exit(EXIT_FAILURE); + } + + iface_ctx->log_level = log_level; + + openlog(NULL, LOG_NDELAY, iface_ctx->facility); + + return iface_ctx; +} + +/** + * \brief Frees the output_interface context supplied as an argument + * + * \param iface_ctx Pointer to the op_interface_context to be freed + */ +static inline void SCLogFreeLogOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx) +{ + SCLogOPIfaceCtx *temp = NULL; + + while (iface_ctx != NULL) { + temp = iface_ctx; + + if (iface_ctx->file_d != NULL) { + fclose(iface_ctx->file_d); + SCMutexDestroy(&iface_ctx->fp_mutex); + } + + if (iface_ctx->file != NULL) + SCFree((void *)iface_ctx->file); + + if (iface_ctx->log_format != NULL) + SCFree((void *)iface_ctx->log_format); + + if (iface_ctx->iface == SC_LOG_OP_IFACE_SYSLOG) { + closelog(); + } + + iface_ctx = iface_ctx->next; + + SCFree(temp); + } + + return; +} + +/** + * \brief Internal function used to set the logging module global_log_level + * during the initialization phase + * + * \param sc_lid The initialization data supplied. + * \param sc_lc The logging module context which has to be updated. + */ +static inline void SCLogSetLogLevel(SCLogInitData *sc_lid, SCLogConfig *sc_lc) +{ + SCLogLevel log_level = SC_LOG_NOTSET; + const char *s = NULL; + + /* envvar overrides config */ + s = getenv(SC_LOG_ENV_LOG_LEVEL); + if (s != NULL) { + log_level = SCMapEnumNameToValue(s, sc_log_level_map); + } else if (sc_lid != NULL) { + log_level = sc_lid->global_log_level; + } + + /* deal with the global_log_level to be used */ + if (log_level > SC_LOG_NOTSET && log_level < SC_LOG_LEVEL_MAX) + sc_lc->log_level = log_level; + else { + sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL; +#ifndef UNITTESTS + if (sc_lid != NULL) { + printf("Warning: Invalid/No global_log_level assigned by user. Falling " + "back on the default_log_level \"%s\"\n", + SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map)); + } +#endif + } + + /* we also set it to a global var, as it is easier to access it */ + sc_log_global_log_level = sc_lc->log_level; + + return; +} + +SCLogLevel SCLogGetLogLevel(void) +{ + return sc_log_global_log_level; +} + +static inline const char *SCLogGetDefaultLogFormat(const SCLogLevel lvl) +{ + const char *prog_ver = GetProgramVersion(); + if (strstr(prog_ver, "RELEASE") != NULL) { + if (lvl <= SC_LOG_NOTICE) + return SC_LOG_DEF_LOG_FORMAT_REL_NOTICE; + else if (lvl <= SC_LOG_INFO) + return SC_LOG_DEF_LOG_FORMAT_REL_INFO; + else if (lvl <= SC_LOG_CONFIG) + return SC_LOG_DEF_LOG_FORMAT_REL_CONFIG; + } + return SC_LOG_DEF_LOG_FORMAT_DEBUG; +} + +/** + * \brief Internal function used to set the logging module global_log_format + * during the initialization phase + * + * \param sc_lid The initialization data supplied. + * \param sc_lc The logging module context which has to be updated. + */ +static inline void SCLogSetLogFormat(SCLogInitData *sc_lid, SCLogConfig *sc_lc) +{ + const char *format = NULL; + + /* envvar overrides config */ + format = getenv(SC_LOG_ENV_LOG_FORMAT); + if (format == NULL) { + if (sc_lid != NULL) { + format = sc_lid->global_log_format; + } + } + + /* deal with the global log format to be used */ + if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) { + format = SCLogGetDefaultLogFormat(sc_lc->log_level); +#ifndef UNITTESTS + if (sc_lid != NULL) { + printf("Warning: Invalid/No global_log_format supplied by user or format " + "length exceeded limit of \"%d\" characters. Falling back on " + "default log_format \"%s\"\n", + SC_LOG_MAX_LOG_FORMAT_LEN, format); + } +#endif + } + + if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) { + printf("Error allocating memory\n"); + exit(EXIT_FAILURE); + } + + return; +} + +/** + * \brief Internal function used to set the logging module global_op_ifaces + * during the initialization phase + * + * \param sc_lid The initialization data supplied. + * \param sc_lc The logging module context which has to be updated. + */ +static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc) +{ + SCLogOPIfaceCtx *op_ifaces_ctx = NULL; + int op_iface = 0; + const char *s = NULL; + + if (sc_lid != NULL && sc_lid->op_ifaces != NULL) { + sc_lc->op_ifaces = sc_lid->op_ifaces; + sc_lid->op_ifaces = NULL; + sc_lc->op_ifaces_cnt = sc_lid->op_ifaces_cnt; + } else { + s = getenv(SC_LOG_ENV_LOG_OP_IFACE); + if (s != NULL) { + op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map); + + if (op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) { + op_iface = SC_LOG_DEF_LOG_OP_IFACE; +#ifndef UNITTESTS + printf("Warning: Invalid output interface supplied by user. " + "Falling back on default_output_interface \"%s\"\n", + SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); +#endif + } + } else { + op_iface = SC_LOG_DEF_LOG_OP_IFACE; +#ifndef UNITTESTS + if (sc_lid != NULL) { + printf("Warning: Output_interface not supplied by user. Falling " + "back on default_output_interface \"%s\"\n", + SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); + } +#endif + } + + switch (op_iface) { + case SC_LOG_OP_IFACE_CONSOLE: + op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX, 0); + break; + case SC_LOG_OP_IFACE_FILE: + s = getenv(SC_LOG_ENV_LOG_FILE); + if (s == NULL) { + char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); + if (str != NULL) { + op_ifaces_ctx = SCLogInitFileOPIface(str, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0); + SCFree(str); + } + } else { + op_ifaces_ctx = SCLogInitFileOPIface(s, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0); + } + break; + case SC_LOG_OP_IFACE_SYSLOG: + s = getenv(SC_LOG_ENV_LOG_FACILITY); + if (s == NULL) + s = SC_LOG_DEF_SYSLOG_FACILITY_STR; + + op_ifaces_ctx = SCLogInitSyslogOPIface( + SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1, 0); + break; + } + sc_lc->op_ifaces = op_ifaces_ctx; + sc_lc->op_ifaces_cnt++; + } + return; +} + +/** + * \brief Internal function used to set the logging module op_filter + * during the initialization phase + * + * \param sc_lid The initialization data supplied. + * \param sc_lc The logging module context which has to be updated. + */ +static inline void SCLogSetOPFilter(SCLogInitData *sc_lid, SCLogConfig *sc_lc) +{ + const char *filter = NULL; + + int opts = 0; + int en; + PCRE2_SIZE eo = 0; + + /* envvar overrides */ + filter = getenv(SC_LOG_ENV_LOG_OP_FILTER); + if (filter == NULL) { + if (sc_lid != NULL) { + filter = sc_lid->op_filter; + } + } + + if (filter != NULL && strcmp(filter, "") != 0) { + sc_lc->op_filter = SCStrdup(filter); + if (sc_lc->op_filter == NULL) { + printf("pcre filter alloc failed\n"); + return; + } + sc_lc->op_filter_regex = + pcre2_compile((PCRE2_SPTR8)filter, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + if (sc_lc->op_filter_regex == NULL) { + SCFree(sc_lc->op_filter); + PCRE2_UCHAR errbuffer[256]; + pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); + printf("pcre2 compile of \"%s\" failed at offset %d : %s\n", filter, (int)eo, + errbuffer); + return; + } + sc_lc->op_filter_regex_match = + pcre2_match_data_create_from_pattern(sc_lc->op_filter_regex, NULL); + } + + return; +} + +/** + * \brief Returns a pointer to a new SCLogInitData. This is a public interface + * intended to be used after the logging parameters are read from the + * conf file + * + * \retval sc_lid Pointer to the newly created SCLogInitData + * \initonly + */ +SCLogInitData *SCLogAllocLogInitData(void) +{ + SCLogInitData *sc_lid = NULL; + + if ((sc_lid = SCCalloc(1, sizeof(SCLogInitData))) == NULL) + return NULL; + + return sc_lid; +} + +#ifdef UNITTESTS +#ifndef OS_WIN32 +/** + * \brief Frees a SCLogInitData + * + * \param sc_lid Pointer to the SCLogInitData to be freed + */ +static void SCLogFreeLogInitData(SCLogInitData *sc_lid) +{ + if (sc_lid != NULL) { + SCLogFreeLogOPIfaceCtx(sc_lid->op_ifaces); + SCFree(sc_lid); + } + + return; +} +#endif +#endif + +/** + * \brief Frees the logging module context + */ +static inline void SCLogFreeLogConfig(SCLogConfig *sc_lc) +{ + if (sc_lc != NULL) { + if (sc_lc->startup_message != NULL) + SCFree(sc_lc->startup_message); + if (sc_lc->log_format != NULL) + SCFree(sc_lc->log_format); + if (sc_lc->op_filter != NULL) + SCFree(sc_lc->op_filter); + + if (sc_lc->op_filter_regex != NULL) + pcre2_code_free(sc_lc->op_filter_regex); + if (sc_lc->op_filter_regex_match) + pcre2_match_data_free(sc_lc->op_filter_regex_match); + + SCLogFreeLogOPIfaceCtx(sc_lc->op_ifaces); + SCFree(sc_lc); + } + + return; +} + +/** + * \brief Appends an output_interface to the output_interface list sent in head + * + * \param iface_ctx Pointer to the output_interface that has to be added to head + * \param head Pointer to the output_interface list + */ +void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx, SCLogInitData *sc_lid) +{ + SCLogOPIfaceCtx *temp = NULL, *prev = NULL; + SCLogOPIfaceCtx **head = &sc_lid->op_ifaces; + + if (iface_ctx == NULL) { +#ifdef DEBUG + printf("Argument(s) to SCLogAppendOPIfaceCtx() NULL\n"); +#endif + return; + } + + temp = *head; + while (temp != NULL) { + prev = temp; + temp = temp->next; + } + + if (prev == NULL) + *head = iface_ctx; + else + prev->next = iface_ctx; + + sc_lid->op_ifaces_cnt++; + + return; +} + +#ifdef UNITTESTS +#ifndef OS_WIN32 +/** + * \internal + * \brief Creates a new output interface based on the arguments sent. The kind + * of output interface to be created is decided by the iface_name arg. + * If iface_name is "file", the arg argument will hold the filename to be + * used for logging purposes. If iface_name is "syslog", the arg + * argument holds the facility code. If iface_name is "console", arg is + * NULL. + * + * \param iface_name Interface name. Can be "console", "file" or "syslog" + * \param log_format Override for the global_log_format + * \param log_level Override for the global_log_level + * \param log_level Parameter required by a particular interface. Explained in + * the function description + * + * \retval iface_ctx Pointer to the newly created output interface + */ +static SCLogOPIfaceCtx *SCLogInitOPIfaceCtx( + const char *iface_name, const char *log_format, int log_level, const char *arg) +{ + int iface = SCMapEnumNameToValue(iface_name, sc_log_op_iface_map); + + if (log_level < SC_LOG_NONE || log_level > SC_LOG_DEBUG) { + printf("Warning: Supplied log_level_override for op_interface \"%s\" " + "is invalid. Defaulting to not specifying an override\n", + iface_name); + log_level = SC_LOG_NOTSET; + } + + switch (iface) { + case SC_LOG_OP_IFACE_CONSOLE: + return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR); + case SC_LOG_OP_IFACE_FILE: + return SCLogInitFileOPIface(arg, 0, 0, log_format, log_level, SC_LOG_OP_TYPE_REGULAR); + case SC_LOG_OP_IFACE_SYSLOG: + return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), + log_format, log_level, SC_LOG_OP_TYPE_REGULAR); + default: +#ifdef DEBUG + printf("Output Interface \"%s\" not supported by the logging module", iface_name); +#endif + return NULL; + } +} +#endif +#endif + +/** + * \brief Initializes the logging module. + * + * \param sc_lid The initialization data for the logging module. If sc_lid is + * NULL, we would stick to the default configuration for the + * logging subsystem. + * \initonly + */ +void SCLogInitLogModule(SCLogInitData *sc_lid) +{ + /* De-initialize the logging context, if it has already init by the + * environment variables at the start of the engine */ + SCLogDeInitLogModule(); + +#if defined(OS_WIN32) + if (SCMutexInit(&sc_log_stream_lock, NULL) != 0) { + FatalError("Failed to initialize log mutex."); + } +#endif /* OS_WIN32 */ + + /* sc_log_config is a global variable */ + if ((sc_log_config = SCCalloc(1, sizeof(SCLogConfig))) == NULL) { + FatalError("Fatal error encountered in SCLogInitLogModule. Exiting..."); + } + + SCLogSetLogLevel(sc_lid, sc_log_config); + SCLogSetLogFormat(sc_lid, sc_log_config); + SCLogSetOPIface(sc_lid, sc_log_config); + SCLogSetOPFilter(sc_lid, sc_log_config); + + sc_log_module_initialized = 1; + sc_log_module_cleaned = 0; + + // SCOutputPrint(sc_did->startup_message); + + rs_log_set_level(sc_log_global_log_level); + return; +} + +void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid) +{ + ConfNode *outputs; + SCLogInitData *sc_lid; + int have_logging = 0; + int max_level = 0; + SCLogLevel min_level = 0; + + /* If verbose logging was requested, set the minimum as + * SC_LOG_NOTICE plus the extra verbosity. */ + if (verbose) { + min_level = SC_LOG_NOTICE + verbose; + } + + outputs = ConfGetNode("logging.outputs"); + if (outputs == NULL) { + SCLogDebug("No logging.output configuration section found."); + return; + } + + sc_lid = SCLogAllocLogInitData(); + if (sc_lid == NULL) { + SCLogDebug("Could not allocate memory for log init data"); + return; + } + + /* Get default log level and format. */ + const char *default_log_level_s = NULL; + if (ConfGet("logging.default-log-level", &default_log_level_s) == 1) { + SCLogLevel default_log_level = SCMapEnumNameToValue(default_log_level_s, sc_log_level_map); + if (default_log_level == -1) { + SCLogError("Invalid default log level: %s", default_log_level_s); + exit(EXIT_FAILURE); + } + sc_lid->global_log_level = MAX(min_level, default_log_level); + } else { + sc_lid->global_log_level = MAX(min_level, SC_LOG_NOTICE); + } + + if (ConfGet("logging.default-log-format", &sc_lid->global_log_format) != 1) + sc_lid->global_log_format = SCLogGetDefaultLogFormat(sc_lid->global_log_level); + + (void)ConfGet("logging.default-output-filter", &sc_lid->op_filter); + + ConfNode *seq_node, *output; + TAILQ_FOREACH (seq_node, &outputs->head, next) { + SCLogLevel level = sc_lid->global_log_level; + SCLogOPIfaceCtx *op_iface_ctx = NULL; + const char *format; + const char *level_s; + + output = ConfNodeLookupChild(seq_node, seq_node->val); + if (output == NULL) + continue; + + /* By default an output is enabled. */ + const char *enabled = ConfNodeLookupChildValue(output, "enabled"); + if (enabled != NULL && ConfValIsFalse(enabled)) + continue; + + SCLogOPType type = SC_LOG_OP_TYPE_REGULAR; + const char *type_s = ConfNodeLookupChildValue(output, "type"); + if (type_s != NULL) { + if (strcmp(type_s, "regular") == 0) + type = SC_LOG_OP_TYPE_REGULAR; + else if (strcmp(type_s, "json") == 0) { + type = SC_LOG_OP_TYPE_JSON; + } + } + + format = ConfNodeLookupChildValue(output, "format"); + + level_s = ConfNodeLookupChildValue(output, "level"); + if (level_s != NULL) { + level = SCMapEnumNameToValue(level_s, sc_log_level_map); + if (level == -1) { + SCLogError("Invalid log level: %s", level_s); + exit(EXIT_FAILURE); + } + max_level = MAX(max_level, level); + } + + /* Increase the level of extra verbosity was requested. */ + level = MAX(min_level, level); + + if (strcmp(output->name, "console") == 0) { + op_iface_ctx = SCLogInitConsoleOPIface(format, level, type); + } else if (strcmp(output->name, "file") == 0) { + if (format == NULL) { + format = SC_LOG_DEF_FILE_FORMAT; + } + + const char *filename = ConfNodeLookupChildValue(output, "filename"); + if (filename == NULL) { + FatalError("Logging to file requires a filename"); + } + char *path = NULL; + if (!(PathIsAbsolute(filename))) { + path = SCLogGetLogFilename(filename); + } else { + path = SCStrdup(filename); + } + if (path == NULL) + FatalError("failed to setup output to file"); + have_logging = 1; + op_iface_ctx = SCLogInitFileOPIface(path, userid, groupid, format, level, type); + SCFree(path); + } else if (strcmp(output->name, "syslog") == 0) { + int facility = SC_LOG_DEF_SYSLOG_FACILITY; + const char *facility_s = ConfNodeLookupChildValue(output, "facility"); + if (facility_s != NULL) { + facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap()); + if (facility == -1) { + SCLogWarning("Invalid syslog " + "facility: \"%s\", now using \"%s\" as syslog " + "facility", + facility_s, SC_LOG_DEF_SYSLOG_FACILITY_STR); + facility = SC_LOG_DEF_SYSLOG_FACILITY; + } + } + SCLogDebug("Initializing syslog logging with format \"%s\"", format); + have_logging = 1; + op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type); + } else { + SCLogWarning("invalid logging method: %s, ignoring", output->name); + } + if (op_iface_ctx != NULL) { + SCLogAppendOPIfaceCtx(op_iface_ctx, sc_lid); + } + } + + if (daemon && (have_logging == 0)) { + SCLogWarning("no logging compatible with daemon mode selected," + " suricata won't be able to log. Please update " + " 'logging.outputs' in the YAML."); + } + + /* Set the global log level to that of the max level used. */ + sc_lid->global_log_level = MAX(sc_lid->global_log_level, max_level); + SCLogInitLogModule(sc_lid); + + SCLogDebug("sc_log_global_log_level: %d", sc_log_global_log_level); + SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format); + SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter); + + if (sc_lid != NULL) + SCFree(sc_lid); +} + +/** + * \brief Returns a full file path given a filename uses log dir specified in + * conf or DEFAULT_LOG_DIR + * + * \param filearg The relative filename for which we want a full path include + * log directory + * + * \retval log_filename The fullpath of the logfile to open + */ +static char *SCLogGetLogFilename(const char *filearg) +{ + const char *log_dir = ConfigGetLogDirectory(); + char *log_filename = SCMalloc(PATH_MAX); + if (unlikely(log_filename == NULL)) + return NULL; + snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filearg); + return log_filename; +} + +/** + * \brief De-Initializes the logging module + */ +void SCLogDeInitLogModule(void) +{ + SCLogFreeLogConfig(sc_log_config); + + /* reset the global logging_module variables */ + sc_log_global_log_level = 0; + sc_log_module_initialized = 0; + sc_log_module_cleaned = 1; + sc_log_config = NULL; + + /* de-init the FD filters */ + SCLogReleaseFDFilters(); + /* de-init the FG filters */ + SCLogReleaseFGFilters(); + +#if defined(OS_WIN32) + SCMutexDestroy(&sc_log_stream_lock); +#endif /* OS_WIN32 */ + + return; +} + +//------------------------------------Unit_Tests-------------------------------- + +/* The logging engine should be tested to the maximum extent possible, since + * logging code would be used throughout the codebase, and hence we can't afford + * to have a single bug here(not that you can afford to have a bug + * elsewhere ;) ). Please report a bug, if you get a slightest hint of a bug + * from the logging module. + */ + +#ifdef UNITTESTS + +static int SCLogTestInit01(void) +{ +#ifndef OS_WIN32 + /* unset any environment variables set for the logging module */ + unsetenv(SC_LOG_ENV_LOG_LEVEL); + unsetenv(SC_LOG_ENV_LOG_OP_IFACE); + unsetenv(SC_LOG_ENV_LOG_FORMAT); + + SCLogInitLogModule(NULL); + + FAIL_IF_NULL(sc_log_config); + + FAIL_IF_NOT(SC_LOG_DEF_LOG_LEVEL == sc_log_config->log_level); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && + SC_LOG_DEF_LOG_OP_IFACE == sc_log_config->op_ifaces->iface); + FAIL_IF_NOT(sc_log_config->log_format != NULL && + strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level), + sc_log_config->log_format) == 0); + + SCLogDeInitLogModule(); + + setenv(SC_LOG_ENV_LOG_LEVEL, "Debug", 1); + setenv(SC_LOG_ENV_LOG_OP_IFACE, "Console", 1); + setenv(SC_LOG_ENV_LOG_FORMAT, "%n- %l", 1); + + SCLogInitLogModule(NULL); + + FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && + SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface); + FAIL_IF_NOT(sc_log_config->log_format != NULL && !strcmp("%n- %l", sc_log_config->log_format)); + + unsetenv(SC_LOG_ENV_LOG_LEVEL); + unsetenv(SC_LOG_ENV_LOG_OP_IFACE); + unsetenv(SC_LOG_ENV_LOG_FORMAT); + + SCLogDeInitLogModule(); +#endif + PASS; +} + +static int SCLogTestInit02(void) +{ +#ifndef OS_WIN32 + SCLogInitData *sc_lid = NULL; + SCLogOPIfaceCtx *sc_iface_ctx = NULL; + char *logfile = SCLogGetLogFilename("boo.txt"); + sc_lid = SCLogAllocLogInitData(); + FAIL_IF_NULL(sc_lid); + sc_lid->startup_message = "Test02"; + sc_lid->global_log_level = SC_LOG_DEBUG; + sc_lid->op_filter = "boo"; + sc_iface_ctx = SCLogInitOPIfaceCtx("file", "%m - %d", SC_LOG_WARNING, logfile); + SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid); + sc_iface_ctx = SCLogInitOPIfaceCtx("console", NULL, SC_LOG_ERROR, NULL); + SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid); + + SCLogInitLogModule(sc_lid); + + FAIL_IF_NULL(sc_log_config); + + FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && + SC_LOG_OP_IFACE_FILE == sc_log_config->op_ifaces->iface); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next != NULL && + SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->next->iface); + FAIL_IF_NOT(sc_log_config->log_format != NULL && + strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level), + sc_log_config->log_format) == 0); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->log_format != NULL && + strcmp("%m - %d", sc_log_config->op_ifaces->log_format) == 0); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next != NULL && + sc_log_config->op_ifaces->next->log_format == NULL); + + SCLogFreeLogInitData(sc_lid); + SCLogDeInitLogModule(); + + sc_lid = SCLogAllocLogInitData(); + FAIL_IF_NULL(sc_lid); + sc_lid->startup_message = "Test02"; + sc_lid->global_log_level = SC_LOG_DEBUG; + sc_lid->op_filter = "boo"; + sc_lid->global_log_format = "kaboo"; + + SCLogInitLogModule(sc_lid); + + FAIL_IF_NULL(sc_log_config); + + FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && + SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next == NULL); + FAIL_IF_NOT( + sc_log_config->log_format != NULL && strcmp("kaboo", sc_log_config->log_format) == 0); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->log_format == NULL); + FAIL_IF_NOT(sc_log_config->op_ifaces != NULL && sc_log_config->op_ifaces->next == NULL); + + SCLogFreeLogInitData(sc_lid); + SCLogDeInitLogModule(); + SCFree(logfile); +#endif + PASS; +} + +static int SCLogTestInit03(void) +{ + SCLogInitLogModule(NULL); + + SCLogAddFGFilterBL(NULL, "bamboo", -1); + SCLogAddFGFilterBL(NULL, "soo", -1); + SCLogAddFGFilterBL(NULL, "dummy", -1); + + FAIL_IF_NOT(SCLogPrintFGFilters() == 3); + + SCLogAddFGFilterBL(NULL, "dummy1", -1); + SCLogAddFGFilterBL(NULL, "dummy2", -1); + + FAIL_IF_NOT(SCLogPrintFGFilters() == 5); + + SCLogDeInitLogModule(); + + PASS; +} + +static int SCLogTestInit04(void) +{ + SCLogInitLogModule(NULL); + + SCLogAddFDFilter("bamboo"); + SCLogAddFDFilter("soo"); + SCLogAddFDFilter("foo"); + SCLogAddFDFilter("roo"); + + FAIL_IF_NOT(SCLogPrintFDFilters() == 4); + + SCLogAddFDFilter("loo"); + SCLogAddFDFilter("soo"); + + FAIL_IF_NOT(SCLogPrintFDFilters() == 5); + + SCLogRemoveFDFilter("bamboo"); + SCLogRemoveFDFilter("soo"); + SCLogRemoveFDFilter("foo"); + SCLogRemoveFDFilter("noo"); + + FAIL_IF_NOT(SCLogPrintFDFilters() == 2); + + SCLogDeInitLogModule(); + + PASS; +} + +static int SCLogTestInit05(void) +{ + char str[4096]; + memset(str, 'A', sizeof(str)); + SCLogInfo("%s", str); + + PASS; +} + +#endif /* UNITTESTS */ + +void SCLogRegisterTests(void) +{ + +#ifdef UNITTESTS + + UtRegisterTest("SCLogTestInit01", SCLogTestInit01); + UtRegisterTest("SCLogTestInit02", SCLogTestInit02); + UtRegisterTest("SCLogTestInit03", SCLogTestInit03); + UtRegisterTest("SCLogTestInit04", SCLogTestInit04); + UtRegisterTest("SCLogTestInit05", SCLogTestInit05); + +#endif /* UNITTESTS */ + + return; +} diff --git a/src/util/debug.h b/src/util/debug.h new file mode 100644 index 000000000000..1a9bad4b8634 --- /dev/null +++ b/src/util/debug.h @@ -0,0 +1,563 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_DEBUG_H__ +#define __UTIL_DEBUG_H__ + +#include "suricata-common.h" + +#include "threads.h" +#include "util/error.h" +#include "util/debug-filters.h" + +/** + * \brief ENV vars that can be used to set the properties for the logging module + */ +#define SC_LOG_ENV_LOG_LEVEL "SC_LOG_LEVEL" +#define SC_LOG_ENV_LOG_OP_IFACE "SC_LOG_OP_IFACE" +#define SC_LOG_ENV_LOG_FILE "SC_LOG_FILE" +#define SC_LOG_ENV_LOG_FACILITY "SC_LOG_FACILITY" +#define SC_LOG_ENV_LOG_FORMAT "SC_LOG_FORMAT" +#define SC_LOG_ENV_LOG_OP_FILTER "SC_LOG_OP_FILTER" + +/** + * \brief The various log levels + * NOTE: when adding new level, don't forget to update SCLogMapLogLevelToSyslogLevel() + * or it may result in logging to syslog with LOG_EMERG priority. + */ +typedef enum { + SC_LOG_NOTSET = -1, + SC_LOG_NONE = 0, + SC_LOG_ERROR, + SC_LOG_WARNING, + SC_LOG_NOTICE, + SC_LOG_INFO, + SC_LOG_PERF, + SC_LOG_CONFIG, + SC_LOG_DEBUG, + SC_LOG_LEVEL_MAX, +} SCLogLevel; + +/** + * \brief The various output interfaces supported + */ +typedef enum { + SC_LOG_OP_IFACE_CONSOLE, + SC_LOG_OP_IFACE_FILE, + SC_LOG_OP_IFACE_SYSLOG, + SC_LOG_OP_IFACE_MAX, +} SCLogOPIface; + +typedef enum { + SC_LOG_OP_TYPE_REGULAR = 0, + SC_LOG_OP_TYPE_JSON, +} SCLogOPType; + +/* The default log_format, if it is not supplied by the user */ +#define SC_LOG_DEF_FILE_FORMAT "[%i - %m] %z %d: %S: %M" +#define SC_LOG_DEF_LOG_FORMAT_REL_NOTICE "%D: %S: %M" +#define SC_LOG_DEF_LOG_FORMAT_REL_INFO "%d: %S: %M" +#define SC_LOG_DEF_LOG_FORMAT_REL_CONFIG "[%i] %d: %S: %M" +#define SC_LOG_DEF_LOG_FORMAT_DEBUG "%d: %S: %M [%n:%f:%l]" + +/* The maximum length of the log message */ +#define SC_LOG_MAX_LOG_MSG_LEN 2048 + +/* The maximum length of the log format */ +#define SC_LOG_MAX_LOG_FORMAT_LEN 128 + +/* The default log level, if it is not supplied by the user */ +#define SC_LOG_DEF_LOG_LEVEL SC_LOG_INFO + +/* The default output interface to be used */ +#define SC_LOG_DEF_LOG_OP_IFACE SC_LOG_OP_IFACE_CONSOLE + +/* The default log file to be used */ +#define SC_LOG_DEF_LOG_FILE "suricata.log" + +/* The default syslog facility to be used */ +#define SC_LOG_DEF_SYSLOG_FACILITY_STR "local0" +#define SC_LOG_DEF_SYSLOG_FACILITY LOG_LOCAL0 + +/** + * \brief Structure to be used when log_level override support would be provided + * by the logging module + */ +typedef struct SCLogOPBuffer_ { + char msg[SC_LOG_MAX_LOG_MSG_LEN]; + char *temp; + const char *log_format; +} SCLogOPBuffer; + +/** + * \brief The output interface context for the logging module + */ +typedef struct SCLogOPIfaceCtx_ { + SCLogOPIface iface; + + bool use_color; + SCLogOPType type; + + /* the output file to be used if the interface is SC_LOG_IFACE_FILE */ + const char *file; + /* the output file descriptor for the above file */ + FILE *file_d; + + /* registered to be set on a file rotation signal */ + int rotation_flag; + + /* the facility code if the interface is SC_LOG_IFACE_SYSLOG */ + int facility; + + /* override for the global_log_level */ + SCLogLevel log_level; + + /* override for the global_log_format(currently not used) */ + const char *log_format; + + /* Mutex used for locking around rotate/write to a file. */ + SCMutex fp_mutex; + + struct SCLogOPIfaceCtx_ *next; +} SCLogOPIfaceCtx; + +/** + * \brief Structure containing init data, that would be passed to + * SCInitDebugModule() + */ +typedef struct SCLogInitData_ { + /* startup message */ + const char *startup_message; + + /* the log level */ + SCLogLevel global_log_level; + + /* the log format */ + const char *global_log_format; + + /* output filter */ + const char *op_filter; + + /* list of output interfaces to be used */ + SCLogOPIfaceCtx *op_ifaces; + /* no of op ifaces */ + uint8_t op_ifaces_cnt; +} SCLogInitData; + +/** + * \brief Holds the config state used by the logging api + */ +typedef struct SCLogConfig_ { + char *startup_message; + SCLogLevel log_level; + char *log_format; + + char *op_filter; + /* compiled pcre filter expression */ + pcre2_code *op_filter_regex; + pcre2_match_data *op_filter_regex_match; + + /* op ifaces used */ + SCLogOPIfaceCtx *op_ifaces; + /* no of op ifaces */ + uint8_t op_ifaces_cnt; +} SCLogConfig; + +/* The different log format specifiers supported by the API */ +#define SC_LOG_FMT_TIME 'z' /* Timestamp in RFC3339 like format */ +#define SC_LOG_FMT_TIME_LEGACY 't' /* Timestamp in legacy format */ +#define SC_LOG_FMT_PID 'p' /* PID */ +#define SC_LOG_FMT_TID 'i' /* Thread ID */ +#define SC_LOG_FMT_TM 'm' /* Thread module name */ +#define SC_LOG_FMT_LOG_LEVEL 'd' /* Log level */ +#define SC_LOG_FMT_LOG_SLEVEL 'D' /* Log level */ +#define SC_LOG_FMT_FILE_NAME 'f' /* File name */ +#define SC_LOG_FMT_LINE 'l' /* Line number */ +#define SC_LOG_FMT_FUNCTION 'n' /* Function */ +#define SC_LOG_FMT_SUBSYSTEM 'S' /* Subsystem name */ +#define SC_LOG_FMT_THREAD_NAME 'T' /* thread name */ +#define SC_LOG_FMT_MESSAGE 'M' /* log message body */ + +/* The log format prefix for the format specifiers */ +#define SC_LOG_FMT_PREFIX '%' + +/* Module and thread tagging */ +/* The module name, usually the containing source-module name */ +static const char *_sc_module __attribute__((unused)) = __SCFILENAME__; + +extern SCLogLevel sc_log_global_log_level; + +extern int sc_log_module_initialized; + +extern int sc_log_module_cleaned; + +void SCLog(int x, const char *file, const char *func, const int line, const char *module, + const char *fmt, ...) ATTR_FMT_PRINTF(6, 7); +void SCLogErr(int x, const char *file, const char *func, const int line, const char *module, + const char *fmt, ...) ATTR_FMT_PRINTF(6, 7); + +/** + * \brief Macro used to log INFORMATIONAL messages. + * + * \retval ... Takes as argument(s), a printf style format message + */ +#define SCLogInfo(...) SCLog(SC_LOG_INFO, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) +#define SCLogInfoRaw(file, func, line, ...) \ + SCLog(SC_LOG_INFO, (file), (func), (line), _sc_module, __VA_ARGS__) + +#define SCLogConfig(...) \ + SCLog(SC_LOG_CONFIG, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) +#define SCLogPerf(...) SCLog(SC_LOG_PERF, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) + +/** + * \brief Macro used to log NOTICE messages. + * + * \retval ... Takes as argument(s), a printf style format message + */ +#define SCLogNotice(...) \ + SCLog(SC_LOG_NOTICE, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) +#define SCLogNoticeRaw(file, func, line, ...) \ + SCLog(SC_LOG_NOTICE, (file), (func), (line), _sc_module, __VA_ARGS__) + +/** + * \brief Macro used to log WARNING messages. + * + * \retval err_code Error code that has to be logged along with the + * warning message + * \retval ... Takes as argument(s), a printf style format message + */ +#define SCLogWarning(...) \ + SCLogErr(SC_LOG_WARNING, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) +#define SCLogWarningRaw(file, func, line, ...) \ + SCLogErr(SC_LOG_WARNING, (file), (func), (line), _sc_module, __VA_ARGS__) + +/** + * \brief Macro used to log ERROR messages. + * + * \retval err_code Error code that has to be logged along with the + * error message + * \retval ... Takes as argument(s), a printf style format message + */ +#define SCLogError(...) \ + SCLogErr(SC_LOG_ERROR, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) +#define SCLogErrorRaw(file, func, line, ...) \ + SCLogErr(SC_LOG_ERROR, (file), (func), (line), _sc_module, __VA_ARGS__) + +/* Avoid the overhead of using the debugging subsystem, in production mode */ +#ifndef DEBUG + +#define SCLogDebug(...) \ + do { \ + } while (0) + +#define SCEnter(...) + +#define SCReturn return + +#define SCReturnInt(x) return x + +#define SCReturnUInt(x) return x + +#define SCReturnDbl(x) return x + +#define SCReturnChar(x) return x + +#define SCReturnCharPtr(x) return x + +#define SCReturnCT(x, type) return x + +#define SCReturnPtr(x, type) return x + +#define SCReturnBool(x) return x + +#define SCReturnStruct(x) return x + +/* Please use it only for debugging purposes */ +#else + +/** + * \brief Macro used to log DEBUG messages. Comes under the debugging subsystem, + * and hence will be enabled only in the presence of the DEBUG macro. + * + * \retval ... Takes as argument(s), a printf style format message + */ +#define SCLogDebug(...) \ + SCLog(SC_LOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) + +/** + * \brief Macro used to log debug messages on function entry. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_entry logs, it also + * processes the FD filters, if any FD filters are registered. + * + * \retval f An argument can be supplied, although it is not used + */ +#define SCEnter(f) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG && SCLogCheckFDFilterEntry(__FUNCTION__)) { \ + SCLogDebug("Entering ... >>"); \ + } \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that don't return + * a value. + */ +#define SCReturn \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning ... <<"); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns an + * integer value. + * + * \retval x Variable of type 'integer' that has to be returned + */ +#define SCReturnInt(x) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning: %" PRIdMAX " ... <<", (intmax_t)x); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns an + * unsigned integer value. + * + * \retval x Variable of type 'unsigned integer' that has to be returned + */ +#define SCReturnUInt(x) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning: %" PRIuMAX " ... <<", (uintmax_t)x); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns a + * float/double value. + * + * \retval x Variable of type 'float/double' that has to be returned + */ +#define SCReturnDbl(x) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning: %f ... <<", x); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns a var + * of character type. + * + * \retval x Variable of type 'char' that has to be returned + */ +#define SCReturnChar(x) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning: %c ... <<", x); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns a + * character string. + * + * \retval x Pointer to the char string that has to be returned + */ +#define SCReturnCharPtr(x) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + if ((x) != NULL) { \ + SCLogDebug("Returning: %s ... <<", x); \ + } else { \ + SCLogDebug("Returning: NULL ... <<"); \ + } \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns a var + * of custom type + * + * \retval x Variable instance of a custom type that has to be returned + * \retval type Pointer to a character string holding the name of the custom + * type(the argument x) that has to be returned + */ +#define SCReturnCT(x, type) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning var of " \ + "type %s ... <<", \ + type); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns a + * pointer to a custom type + * + * \retval x Pointer to a variable instance of a custom type that has to be + * returned + * \retval type Pointer to a character string holding the name of the custom + * type(the argument x) that has to be returned + */ +#define SCReturnPtr(x, type) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning pointer %p of " \ + "type %s ... <<", \ + x, type); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +/** + * \brief Macro used to log debug messages on function exit. Comes under the + * debugging subsystem, and hence will be enabled only in the presence + * of the DEBUG macro. Apart from logging function_exit logs, it also + * processes the FD filters, if any FD filters are registered. This + * function_exit macro should be used for functions that returns a + * boolean value. + * + * \retval x Variable of type 'bool' that has to be returned + */ +#define SCReturnBool(x) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning: %s ... <<", x ? "true" : "false"); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +#define SCReturnStruct(x) \ + do { \ + if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ + SCLogDebug("Returning: ... <<"); \ + SCLogCheckFDFilterExit(__FUNCTION__); \ + } \ + return x; \ + } while (0) + +#endif /* DEBUG */ + +#define FatalError(...) \ + do { \ + SCLogError(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +/** \brief Fatal error IF we're starting up, and configured to consider + * errors to be fatal errors */ +#if !defined(__clang_analyzer__) +#define FatalErrorOnInit(...) \ + do { \ + SC_ATOMIC_EXTERN(unsigned int, engine_stage); \ + int init_errors_fatal = 0; \ + (void)ConfGetBool("engine.init-failure-fatal", &init_errors_fatal); \ + if (init_errors_fatal && (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT)) { \ + SCLogError(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } \ + SCLogWarning(__VA_ARGS__); \ + } while (0) +/* make it simpler for scan-build */ +#else +#define FatalErrorOnInit(...) FatalError(__VA_ARGS__) +#endif + +#define BOOL2STR(b) (b) ? "true" : "false" + +SCLogInitData *SCLogAllocLogInitData(void); + +void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *, SCLogInitData *); + +void SCLogInitLogModule(SCLogInitData *); + +void SCLogDeInitLogModule(void); + +SCError SCLogMessage(const SCLogLevel, const char *, const unsigned int, const char *, const char *, + const char *message); + +SCLogOPBuffer *SCLogAllocLogOPBuffer(void); + +int SCLogDebugEnabled(void); + +void SCLogRegisterTests(void); + +void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid); + +SCLogLevel SCLogGetLogLevel(void); + +#endif /* __UTIL_DEBUG_H__ */ diff --git a/src/util/decode-mime.c b/src/util/decode-mime.c new file mode 100644 index 000000000000..14b99244403a --- /dev/null +++ b/src/util/decode-mime.c @@ -0,0 +1,3542 @@ +/* Copyright (C) 2012 BAE Systems + * Copyright (C) 2020-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "app-layer/smtp/parser.h" +#include "util/decode-mime.h" +#include "util/ip.h" +#include "util/spm-bs.h" +#include "util/unittest.h" +#include "util/memcmp.h" +#include "util/print.h" +#include "util/validate.h" +#include "rust.h" + +/* Character constants */ +#ifndef CR +#define CR 13 +#define LF 10 +#endif + +#define CRLF "\r\n" +#define COLON 58 +#define DASH 45 +#define PRINTABLE_START 33 +#define PRINTABLE_END 126 +#define UC_START 65 +#define UC_END 90 +#define LC_START 97 +#define LC_END 122 +#define UC_LC_DIFF 32 +#define EOL_LEN 2 + +/* Base-64 constants */ +#define BASE64_STR "Base64" + +/* Mime Constants */ +#define MAX_LINE_LEN 998 /* Def in RFC 2045, excluding CRLF sequence */ +#define MAX_ENC_LINE_LEN 76 /* Def in RFC 2045, excluding CRLF sequence */ +#define MAX_HEADER_NAME 75 /* 75 + ":" = 76 */ +#define MAX_HEADER_VALUE 2000 /* Default - arbitrary limit */ +#define BOUNDARY_BUF 256 +#define CTNT_TYPE_STR "content-type" +#define CTNT_DISP_STR "content-disposition" +#define CTNT_TRAN_STR "content-transfer-encoding" +#define MSG_ID_STR "message-id" +#define MSG_STR "message/" +#define MULTIPART_STR "multipart/" +#define QP_STR "quoted-printable" +#define TXT_STR "text/plain" +#define HTML_STR "text/html" + +/* Memory Usage Constants */ +#define STACK_FREE_NODES 10 + +/* Other Constants */ +#define MAX_IP4_CHARS 15 +#define MAX_IP6_CHARS 39 + +/* Globally hold configuration data */ +static MimeDecConfig mime_dec_config = { true, true, true, NULL, false, false, MAX_HEADER_VALUE }; + +/* Mime Parser String translation */ +static const char *StateFlags[] = { "NONE", "HEADER_READY", "HEADER_STARTED", "HEADER_DONE", + "BODY_STARTED", "BODY_DONE", "BODY_END_BOUND", "PARSE_DONE", "PARSE_ERROR", NULL }; + +/* URL executable file extensions */ +static const char *UrlExeExts[] = { ".exe", ".vbs", ".bin", ".cmd", ".bat", ".jar", ".js", ".ps", + ".ps1", ".sh", ".run", ".hta", ".bin", ".elf", NULL }; + +/** + * \brief Function used to print character strings that are not null-terminated + * + * \param log_level The logging level in which to print + * \param label A label for the string to print + * \param src The source string + * \param len The length of the string + * + * \return none + */ +static void PrintChars(int log_level, const char *label, const uint8_t *src, uint32_t len) +{ +#ifdef DEBUG + if (log_level <= sc_log_global_log_level) { + printf("[%s]\n", label); + PrintRawDataFp(stdout, (uint8_t *)src, len); + } +#endif +} + +/** + * \brief Set global config policy + * + * \param config Config policy to set + * \return none + */ +void MimeDecSetConfig(MimeDecConfig *config) +{ + if (config != NULL) { + mime_dec_config = *config; + + /* Set to default */ + if (mime_dec_config.header_value_depth == 0) { + mime_dec_config.header_value_depth = MAX_HEADER_VALUE; + } + } else { + SCLogWarning("Invalid null configuration parameters"); + } +} + +/** + * \brief Get global config policy + * + * \return config data structure + */ +MimeDecConfig *MimeDecGetConfig(void) +{ + return &mime_dec_config; +} + +/** + * \brief Follow the 'next' pointers to the leaf + * + * \param node The root entity + * + * \return Pointer to leaf on 'next' side + * + */ +static MimeDecEntity *findLastSibling(MimeDecEntity *node) +{ + if (node == NULL) + return NULL; + while (node->next != NULL) + node = node->next; + return node; +} + +/** + * \brief Frees a mime entity tree + * + * \param entity The root entity + * + * \return none + * + */ +void MimeDecFreeEntity(MimeDecEntity *entity) +{ + if (entity == NULL) + return; + MimeDecEntity *lastSibling = findLastSibling(entity); + while (entity != NULL) { + /* move child to next to transform the tree into a list */ + if (entity->child != NULL) { + lastSibling->next = entity->child; + entity->child = NULL; + lastSibling = findLastSibling(lastSibling); + } + + MimeDecEntity *next = entity->next; + DEBUG_VALIDATE_BUG_ON( + (next != NULL && entity == lastSibling) || (next == NULL && entity != lastSibling)); + MimeDecFreeField(entity->field_list); + MimeDecFreeUrl(entity->url_list); + SCFree(entity->filename); + SCFree(entity); + entity = next; + } +} + +/** + * \brief Iteratively frees a header field entry list + * + * \param field The header field + * + * \return none + * + */ +void MimeDecFreeField(MimeDecField *field) +{ + MimeDecField *temp, *curr; + + if (field != NULL) { + + curr = field; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Free contents of node */ + SCFree(temp->name); + SCFree(temp->value); + + /* Now free node data */ + SCFree(temp); + } + } +} + +/** + * \brief Iteratively frees a URL entry list + * + * \param url The url entry + * + * \return none + * + */ +void MimeDecFreeUrl(MimeDecUrl *url) +{ + MimeDecUrl *temp, *curr; + + if (url != NULL) { + + curr = url; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node data */ + SCFree(temp->url); + SCFree(temp); + } + } +} + +/** + * \brief Creates and adds a header field entry to an entity + * + * The entity is optional. If NULL is specified, than a new stand-alone field + * is created. + * + * \param entity The parent entity + * + * \return The field object, or NULL if the operation fails + * + */ +MimeDecField *MimeDecAddField(MimeDecEntity *entity) +{ + MimeDecField *node = SCCalloc(1, sizeof(MimeDecField)); + if (unlikely(node == NULL)) { + return NULL; + } + + /* If list is empty, then set as head of list */ + if (entity->field_list == NULL) { + entity->field_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->field_list; + entity->field_list = node; + } + + return node; +} + +/** + * \brief Searches for header fields with the specified name + * + * \param entity The entity to search + * \param name The header name (lowercase) + * + * \return number of items found + * + */ +int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, + int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data) +{ + MimeDecField *curr = entity->field_list; + int found = 0; + + while (curr != NULL) { + /* name is stored lowercase */ + if (strlen(name) == curr->name_len) { + if (SCMemcmp(curr->name, name, curr->name_len) == 0) { + if (DataCallback(curr->value, curr->value_len, data)) + found++; + } + } + curr = curr->next; + } + + return found; +} + +/** + * \brief Searches for a header field with the specified name + * + * \param entity The entity to search + * \param name The header name (lowercase) + * + * \return The field object, or NULL if not found + * + */ +MimeDecField *MimeDecFindField(const MimeDecEntity *entity, const char *name) +{ + MimeDecField *curr = entity->field_list; + + while (curr != NULL) { + /* name is stored lowercase */ + if (strlen(name) == curr->name_len) { + if (SCMemcmp(curr->name, name, curr->name_len) == 0) { + break; + } + } + curr = curr->next; + } + + return curr; +} + +/** + * \brief Creates and adds a URL entry to the specified entity + * + * The entity is optional and if NULL is specified, then a new list will be created. + * + * \param entity The entity + * + * \return URL entry or NULL if the operation fails + * + */ +static MimeDecUrl *MimeDecAddUrl( + MimeDecEntity *entity, uint8_t *url, uint32_t url_len, uint8_t flags) +{ + MimeDecUrl *node = SCCalloc(1, sizeof(MimeDecUrl)); + if (unlikely(node == NULL)) { + return NULL; + } + + node->url = url; + node->url_len = url_len; + node->url_flags = flags; + + /* If list is empty, then set as head of list */ + if (entity->url_list == NULL) { + entity->url_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->url_list; + entity->url_list = node; + } + + return node; +} + +/** + * \brief Creates and adds a child entity to the specified parent entity + * + * \param parent The parent entity + * + * \return The child entity, or NULL if the operation fails + * + */ +MimeDecEntity *MimeDecAddEntity(MimeDecEntity *parent) +{ + MimeDecEntity *node = SCCalloc(1, sizeof(MimeDecEntity)); + if (unlikely(node == NULL)) { + return NULL; + } + + /* If parent is NULL then just return the new pointer */ + if (parent != NULL) { + if (parent->child == NULL) { + parent->child = node; + parent->last_child = node; + } else { + parent->last_child->next = node; + parent->last_child = node; + } + } + + return node; +} + +/** + * \brief Creates a mime header field and fills in its values and adds it to the + * specified entity + * + * \param entity Entity in which to add the field + * \param name String containing the name + * \param nlen Length of the name + * \param value String containing the value + * \param vlen Length of the value + * + * \return The field or NULL if the operation fails + * + * name and val are passed as ptr to ptr and each will be set to NULL + * only if the pointer is consumed. This gives the caller an easy way + * to free the memory if not consumed. + */ +static MimeDecField *MimeDecFillField( + MimeDecEntity *entity, uint8_t **name, uint32_t nlen, uint8_t **value, uint32_t vlen) +{ + if (nlen == 0 && vlen == 0) + return NULL; + + MimeDecField *field = MimeDecAddField(entity); + if (unlikely(field == NULL)) { + return NULL; + } + + if (nlen > 0) { + uint8_t *n = *name; + + /* convert to lowercase and store */ + for (uint32_t u = 0; u < nlen; u++) + n[u] = u8_tolower(n[u]); + + field->name = (uint8_t *)n; + field->name_len = nlen; + *name = NULL; + } + + if (vlen > 0) { + field->value = (uint8_t *)*value; + field->value_len = vlen; + *value = NULL; + } + + return field; +} + +/** + * \brief Pushes a node onto a stack and returns the new node. + * + * \param stack The top of the stack + * + * \return pointer to a new node, otherwise NULL if it fails + */ +static MimeDecStackNode *PushStack(MimeDecStack *stack) +{ + /* Attempt to pull from free nodes list */ + MimeDecStackNode *node = stack->free_nodes; + if (node == NULL) { + node = SCCalloc(1, sizeof(MimeDecStackNode)); + if (unlikely(node == NULL)) { + return NULL; + } + } else { + /* Move free nodes pointer over */ + stack->free_nodes = stack->free_nodes->next; + stack->free_nodes_cnt--; + memset(node, 0x00, sizeof(MimeDecStackNode)); + } + + /* Push to top of stack */ + node->next = stack->top; + stack->top = node; + + /* Return a pointer to the top of the stack */ + return node; +} + +/** + * \brief Pops the top node from the stack and returns the next node. + * + * \param stack The top of the stack + * + * \return pointer to the next node, otherwise NULL if no nodes remain + */ +static MimeDecStackNode *PopStack(MimeDecStack *stack) +{ + /* Move stack pointer to next item */ + MimeDecStackNode *curr = stack->top; + if (curr != NULL) { + curr = curr->next; + } + + /* Always free alloc'd memory */ + SCFree(stack->top->bdef); + + /* Now move head to free nodes list */ + if (stack->free_nodes_cnt < STACK_FREE_NODES) { + stack->top->next = stack->free_nodes; + stack->free_nodes = stack->top; + stack->free_nodes_cnt++; + } else { + SCFree(stack->top); + } + stack->top = curr; + + /* Return a pointer to the top of the stack */ + return curr; +} + +/** + * \brief Frees the stack along with the free-nodes list + * + * \param stack The stack pointer + * + * \return none + */ +static void FreeMimeDecStack(MimeDecStack *stack) +{ + MimeDecStackNode *temp, *curr; + + if (stack != NULL) { + /* Top of stack */ + curr = stack->top; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp->bdef); + SCFree(temp); + } + + /* Free nodes */ + curr = stack->free_nodes; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp); + } + + SCFree(stack); + } +} + +/** + * \brief Adds a data value to the data values linked list + * + * \param dv The head of the linked list (NULL if new list) + * + * \return pointer to a new node, otherwise NULL if it fails + */ +static DataValue *AddDataValue(DataValue *dv) +{ + DataValue *curr, *node = SCCalloc(1, sizeof(DataValue)); + if (unlikely(node == NULL)) { + return NULL; + } + + if (dv != NULL) { + curr = dv; + while (curr->next != NULL) { + curr = curr->next; + } + + curr->next = node; + } + + return node; +} + +/** + * \brief Frees a linked list of data values starting at the head + * + * \param dv The head of the linked list + * + * \return none + */ +static void FreeDataValue(DataValue *dv) +{ + DataValue *temp, *curr; + + if (dv != NULL) { + curr = dv; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp->value); + SCFree(temp); + } + } +} + +/** + * \brief Converts a list of data values into a single value (returns dynamically + * allocated memory) + * + * \param dv The head of the linked list (NULL if new list) + * \param olen The output length of the single value + * + * \return pointer to a single value, otherwise NULL if it fails or is zero-length + */ +static uint8_t *GetFullValue(const DataValue *dv, uint32_t *olen) +{ + uint32_t offset = 0; + uint8_t *val = NULL; + uint32_t len = 0; + *olen = 0; + + /* First calculate total length */ + for (const DataValue *curr = dv; curr != NULL; curr = curr->next) { + len += curr->value_len; + } + /* Must have at least one character in the value */ + if (len > 0) { + val = SCCalloc(1, len); + if (unlikely(val == NULL)) { + return NULL; + } + for (const DataValue *curr = dv; curr != NULL; curr = curr->next) { + memcpy(val + offset, curr->value, curr->value_len); + offset += curr->value_len; + } + } + *olen = len; + return val; +} + +/** + * \brief Find a string while searching up to N characters within a source + * buffer + * + * \param src The source string (not null-terminated) + * \param len The length of the source string + * \param find The string to find (null-terminated) + * \param find_len length of the 'find' string + * + * \return Pointer to the position it was found, otherwise NULL if not found + */ +static inline uint8_t *FindBuffer( + const uint8_t *src, uint32_t len, const uint8_t *find, uint16_t find_len) +{ + /* Use utility search function */ + return BasicSearchNocase(src, len, find, find_len); +} + +/** + * \brief Get a line (CRLF or just CR or LF) from a buffer (similar to GetToken) + * + * \param buf The input buffer (not null-terminated) + * \param blen The length of the input buffer + * \param remainPtr Pointer to remaining after tokenizing iteration + * \param tokLen Output token length (if non-null line) + * + * \return Pointer to line + */ +static uint8_t *GetLine(uint8_t *buf, uint32_t blen, uint8_t **remainPtr, uint32_t *tokLen) +{ + uint32_t i; + uint8_t *tok; + + /* So that it can be used just like strtok_r */ + if (buf == NULL) { + buf = *remainPtr; + } else { + *remainPtr = buf; + } + if (buf == NULL) + return NULL; + + tok = buf; + + /* length must be specified */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* Found delimiter */ + if (buf[i] == CR || buf[i] == LF) { + + /* Add another if we find either CRLF or LFCR */ + *remainPtr += (i + 1); + if ((i + 1 < blen) && buf[i] != buf[i + 1] && (buf[i + 1] == CR || buf[i + 1] == LF)) { + (*remainPtr)++; + } + break; + } + } + + /* If no delimiter found, then point to end of buffer */ + if (buf == *remainPtr) { + (*remainPtr) += i; + } + + /* Calculate token length */ + *tokLen = (buf + i) - tok; + + return tok; +} + +/** + * \brief Get token from buffer and return pointer to it + * + * \param buf The input buffer (not null-terminated) + * \param blen The length of the input buffer + * \param delims Character delimiters (null-terminated) + * \param remainPtr Pointer to remaining after tokenizing iteration + * \param tokLen Output token length (if non-null line) + * + * \return Pointer to token, or NULL if not found + */ +static uint8_t *GetToken( + uint8_t *buf, uint32_t blen, const char *delims, uint8_t **remainPtr, uint32_t *tokenLen) +{ + uint32_t i, j, delimFound = 0; + uint8_t *tok = NULL; + + /* So that it can be used just like strtok_r */ + if (buf == NULL) { + buf = *remainPtr; + } else { + *remainPtr = buf; + } + if (buf == NULL) + return NULL; + + /* Must specify length */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* Look for delimiters */ + for (j = 0; delims[j] != 0; j++) { + if (buf[i] == delims[j]) { + /* Data must be found before delimiter matters */ + if (tok != NULL) { + (*remainPtr) += (i + 1); + } + delimFound = 1; + break; + } + } + + /* If at least one non-delimiter found, then a token is found */ + if (tok == NULL && !delimFound) { + tok = buf + i; + } else { + /* Reset delimiter */ + delimFound = 0; + } + + /* If delimiter found, then break out of loop */ + if (buf != *remainPtr) { + break; + } + } + + /* Make sure remaining points to end of buffer if delimiters not found */ + if (tok != NULL) { + if (buf == *remainPtr) { + (*remainPtr) += i; + } + + /* Calculate token length */ + *tokenLen = (buf + i) - tok; + } + + return tok; +} + +/** + * \brief Stores the final MIME header value into the current entity on the + * stack. + * + * \param state The parser state + * + * \return MIME_DEC_OK if stored, otherwise a negative number indicating error + */ +static int StoreMimeHeader(MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + /* Lets save the most recent header */ + if (state->hname != NULL || state->hvalue != NULL) { + SCLogDebug("Storing last header"); + uint32_t vlen; + uint8_t *val = GetFullValue(state->hvalue, &vlen); + if (val != NULL) { + if (state->hname == NULL) { + SCLogDebug("Error: Invalid parser state - header value without" + " name"); + ret = MIME_DEC_ERR_PARSE; + + } else if (state->stack->top != NULL) { + /* Store each header name and value */ + if (MimeDecFillField(state->stack->top->data, &state->hname, state->hlen, &val, + vlen) == NULL) { + ret = MIME_DEC_ERR_MEM; + } + } else { + SCLogDebug("Error: Stack pointer missing"); + ret = MIME_DEC_ERR_DATA; + } + } else { + if (state->hvalue != NULL) { + /* Memory allocation must have failed since val is NULL */ + ret = MIME_DEC_ERR_MEM; + } + } + + SCFree(val); + SCFree(state->hname); + state->hname = NULL; + FreeDataValue(state->hvalue); + state->hvalue = NULL; + state->hvlen = 0; + } + + return ret; +} + +/** + * \brief Function determines whether a url string points to an executable + * based on file extension only. + * + * \param url The url string + * \param len The url string length + * + * \retval 1 The url points to an EXE + * \retval 0 The url does NOT point to an EXE + */ +static int IsExeUrl(const uint8_t *url, uint32_t len) +{ + int isExeUrl = 0; + uint32_t i, extLen; + uint8_t *ext; + + /* Now check for executable extensions and if not found, cut off at first '/' */ + for (i = 0; UrlExeExts[i] != NULL; i++) { + extLen = strlen(UrlExeExts[i]); + ext = FindBuffer(url, len, (uint8_t *)UrlExeExts[i], (uint16_t)strlen(UrlExeExts[i])); + if (ext != NULL && (ext + extLen - url == (int)len || ext[extLen] == '?')) { + isExeUrl = 1; + break; + } + } + + return isExeUrl; +} + +/** + * \brief Function determines whether a host string is a numeric IP v4 address + * + * \param urlhost The host string + * \param len The host string length + * + * \retval 1 The host is a numeric IP + * \retval 0 The host is NOT a numeric IP + */ +static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) +{ + struct sockaddr_in sa; + char tempIp[MAX_IP4_CHARS + 1]; + + /* Cut off at '/' */ + uint32_t i = 0; + for (; i < len && urlhost[i] != 0; i++) { + + if (urlhost[i] == '/') { + break; + } + } + + /* Too many chars */ + if (i > MAX_IP4_CHARS) { + return 0; + } + + /* Create null-terminated string */ + memcpy(tempIp, urlhost, i); + tempIp[i] = '\0'; + + if (!IPv4AddressStringIsValid(tempIp)) + return 0; + + return inet_pton(AF_INET, tempIp, &(sa.sin_addr)); +} + +/** + * \brief Function determines whether a host string is a numeric IP v6 address + * + * \param urlhost The host string + * \param len The host string length + * + * \retval 1 The host is a numeric IP + * \retval 0 The host is NOT a numeric IP + */ +static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) +{ + struct in6_addr in6; + char tempIp[MAX_IP6_CHARS + 1]; + + /* Cut off at '/' */ + uint32_t i = 0; + for (i = 0; i < len && urlhost[i] != 0; i++) { + if (urlhost[i] == '/') { + break; + } + } + + /* Too many chars */ + if (i > MAX_IP6_CHARS) { + return 0; + } + + /* Create null-terminated string */ + memcpy(tempIp, urlhost, i); + tempIp[i] = '\0'; + + if (!IPv6AddressStringIsValid(tempIp)) + return 0; + + return inet_pton(AF_INET6, tempIp, &in6); +} + +/** + * \brief Traverses through the list of URLs for an exact match of the specified + * string + * + * \param entity The MIME entity + * \param url The matching URL string (lowercase) + * \param url_len The matching URL string length + * + * \return URL object or NULL if not found + */ +static MimeDecUrl *FindExistingUrl(MimeDecEntity *entity, uint8_t *url, uint32_t url_len) +{ + MimeDecUrl *curr = entity->url_list; + + while (curr != NULL) { + if (url_len == curr->url_len) { + /* search url and stored url are both in + * lowercase, so we can do an exact match */ + if (SCMemcmp(curr->url, url, url_len) == 0) { + break; + } + } + curr = curr->next; + } + + return curr; +} + +/** + * \brief This function searches a text or html line for a URL string + * + * The URL strings are searched for using the URL schemes defined in the global + * MIME config e.g. "http", "https". + * + * The found URL strings are stored in lowercase and with their schemes + * stripped unless the MIME config flag for log_url_scheme is set. + * + * Numeric IPs, malformed numeric IPs, and URLs pointing to executables are + * also flagged as URLs of interest. + * + * \param line the line + * \param len the line length + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int FindUrlStrings(const uint8_t *line, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + MimeDecConfig *mdcfg = MimeDecGetConfig(); + uint8_t *fptr, *remptr, *tok = NULL, *tempUrl, *urlHost; + uint32_t tokLen = 0, i, tempUrlLen, urlHostLen; + uint16_t schemeStrLen = 0; + uint8_t flags = 0; + ConfNode *scheme = NULL; + char *schemeStr = NULL; + + if (mdcfg != NULL && mdcfg->extract_urls_schemes == NULL) { + SCLogDebug("Error: MIME config extract_urls_schemes was NULL."); + return MIME_DEC_ERR_DATA; + } + + TAILQ_FOREACH (scheme, &mdcfg->extract_urls_schemes->head, next) { + schemeStr = scheme->val; + // checked against UINT16_MAX when setting in SMTPConfigure + schemeStrLen = (uint16_t)strlen(schemeStr); + + remptr = (uint8_t *)line; + do { + SCLogDebug("Looking for URL String starting with: %s", schemeStr); + + /* Check for token definition */ + fptr = FindBuffer(remptr, len - (remptr - line), (uint8_t *)schemeStr, schemeStrLen); + if (fptr != NULL) { + if (!mdcfg->log_url_scheme) { + fptr += schemeStrLen; /* Strip scheme from stored URL */ + } + tok = GetToken(fptr, len - (fptr - line), " \"\'<>]\t", &remptr, &tokLen); + if (tok == fptr) { + SCLogDebug("Found url string"); + + /* First copy to temp URL string */ + tempUrl = SCMalloc(tokLen); + if (unlikely(tempUrl == NULL)) { + return MIME_DEC_ERR_MEM; + } + + PrintChars(SC_LOG_DEBUG, "RAW URL", tok, tokLen); + + /* Copy over to temp URL while decoding */ + tempUrlLen = 0; + for (i = 0; i < tokLen && tok[i] != 0; i++) { + /* url is all lowercase */ + tempUrl[tempUrlLen] = u8_tolower(tok[i]); + tempUrlLen++; + } + + urlHost = tempUrl; + urlHostLen = tempUrlLen; + if (mdcfg->log_url_scheme) { + /* tempUrl contains the scheme in the string but + * IsIpv4Host & IsPv6Host methods below require + * an input URL string with scheme stripped. Get a + * reference sub-string urlHost which starts with + * the host instead of the scheme. */ + urlHost += schemeStrLen; + urlHostLen -= schemeStrLen; + } + + /* Determine if URL points to an EXE */ + if (IsExeUrl(tempUrl, tempUrlLen)) { + flags |= URL_IS_EXE; + + PrintChars(SC_LOG_DEBUG, "EXE URL", tempUrl, tempUrlLen); + } + + /* Make sure remaining URL exists */ + if (tempUrlLen > 0) { + if (!(FindExistingUrl(entity, tempUrl, tempUrlLen))) { + /* Now look for numeric IP */ + if (IsIpv4Host(urlHost, urlHostLen)) { + flags |= URL_IS_IP4; + + PrintChars(SC_LOG_DEBUG, "IP URL4", tempUrl, tempUrlLen); + } else if (IsIpv6Host(urlHost, urlHostLen)) { + flags |= URL_IS_IP6; + + PrintChars(SC_LOG_DEBUG, "IP URL6", tempUrl, tempUrlLen); + } + + /* Add URL list item */ + MimeDecAddUrl(entity, tempUrl, tempUrlLen, flags); + } else { + SCFree(tempUrl); + } + } else { + SCFree(tempUrl); + } + + /* Reset flags for next URL */ + flags = 0; + } + } + } while (fptr != NULL); + } + + return ret; +} + +/** + * \brief This function is a pre-processor for handling decoded data chunks that + * then invokes the caller's callback function for further processing + * + * \param chunk The decoded chunk + * \param len The decoded chunk length (varies) + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t *remainPtr, *tok; + uint32_t tokLen; + + if ((state->stack != NULL) && (state->stack->top != NULL) && + (state->stack->top->data != NULL)) { + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (mdcfg != NULL && mdcfg->extract_urls) { + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + /* If plain text or html, then look for URLs */ + if (((entity->ctnt_flags & CTNT_IS_TEXT) || (entity->ctnt_flags & CTNT_IS_MSG) || + (entity->ctnt_flags & CTNT_IS_HTML)) && + ((entity->ctnt_flags & CTNT_IS_ATTACHMENT) == 0)) { + + /* Parse each line one by one */ + remainPtr = (uint8_t *)chunk; + do { + tok = GetLine( + remainPtr, len - (remainPtr - (uint8_t *)chunk), &remainPtr, &tokLen); + if (tok != remainPtr) { + /* Search line for URL */ + ret = FindUrlStrings(tok, tokLen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: FindUrlStrings() function" + " failed: %d", + ret); + break; + } + } + } while (tok != remainPtr && remainPtr - (uint8_t *)chunk < (int)len); + } + } + + /* Now invoke callback */ + if (state->DataChunkProcessorFunc != NULL) { + ret = state->DataChunkProcessorFunc(chunk, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: state->dataChunkProcessor() callback function" + " failed"); + } + } + } else { + SCLogDebug("Error: Stack pointer missing"); + ret = MIME_DEC_ERR_DATA; + } + + /* Reset data chunk buffer */ + state->data_chunk_len = 0; + + /* Mark body / file as no longer at beginning */ + state->body_begin = 0; + + return ret; +} + +/** + * \brief Processes a remainder (line % 4 = remainder) from the previous line + * such that all base64 decoding attempts are divisible by 4 + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * \param force Flag indicating whether decoding should always occur + * + * \return Number of bytes consumed from `buf` + */ +static uint32_t ProcessBase64Remainder( + const uint8_t *buf, const uint32_t len, MimeDecParseState *state, int force) +{ + uint32_t buf_consumed = 0; /* consumed bytes from 'buf' */ + uint8_t cnt = 0; + uint8_t block[B64_BLOCK]; + + SCLogDebug("len %u force %d", len, force); + + /* should be impossible, but lets be defensive */ + DEBUG_VALIDATE_BUG_ON(state->bvr_len > B64_BLOCK); + if (state->bvr_len > B64_BLOCK) { + state->bvr_len = 0; + return 0; + } + + /* Strip spaces in remainder */ + for (uint8_t i = 0; i < state->bvr_len; i++) { + if (IsBase64Alphabet(state->bvremain[i])) { + block[cnt++] = state->bvremain[i]; + } + } + + /* if we don't have 4 bytes see if we can fill it from `buf` */ + if (buf && len > 0 && cnt != B64_BLOCK) { + for (uint32_t i = 0; i < len && cnt < B64_BLOCK; i++) { + if (IsBase64Alphabet(buf[i])) { + block[cnt++] = buf[i]; + } + buf_consumed++; + } + DEBUG_VALIDATE_BUG_ON(cnt > B64_BLOCK); + for (uint32_t i = 0; i < cnt; i++) { + state->bvremain[i] = block[i]; + } + state->bvr_len = cnt; + } else if (!force && cnt != B64_BLOCK) { + SCLogDebug("incomplete data and no buffer to backfill"); + return 0; + } + + /* in force mode pad the block */ + if (force && cnt != B64_BLOCK) { + SCLogDebug("force and cnt %u != %u", cnt, B64_BLOCK); + for (uint8_t i = state->bvr_len; i < B64_BLOCK; i++) { + state->bvremain[state->bvr_len++] = '='; + } + } + + /* If data chunk buffer will be full, then clear it now */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + uint32_t ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); + } + } + + if (state->bvr_len == B64_BLOCK || force) { + uint32_t consumed_bytes = 0; + uint32_t remdec = 0; + const uint32_t avail_space = DATA_CHUNK_SIZE - state->data_chunk_len; + PrintChars(SC_LOG_DEBUG, "BASE64 INPUT (bvremain)", state->bvremain, state->bvr_len); + Base64Ecode code = DecodeBase64(state->data_chunk + state->data_chunk_len, avail_space, + state->bvremain, state->bvr_len, &consumed_bytes, &remdec, BASE64_MODE_RFC2045); + SCLogDebug("DecodeBase64 result %u", code); + if (remdec > 0 && (code == BASE64_ECODE_OK || code == BASE64_ECODE_BUF)) { + PrintChars(SC_LOG_DEBUG, "BASE64 DECODED (bvremain)", + state->data_chunk + state->data_chunk_len, remdec); + + state->data_chunk_len += remdec; + + /* If data chunk buffer is now full, then clear */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + uint32_t ret = + ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + } else if (code == BASE64_ECODE_ERR) { + /* Track failed base64 */ + state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; + state->msg->anomaly_flags |= ANOM_INVALID_BASE64; + SCLogDebug("Error: DecodeBase64() function failed"); + PrintChars(SC_LOG_DEBUG, "Base64 failed string", state->bvremain, state->bvr_len); + } + + /* Reset remaining */ + state->bvr_len = 0; + } + + DEBUG_VALIDATE_BUG_ON(buf_consumed > len); + return buf_consumed; +} + +static inline MimeDecRetCode ProcessBase64BodyLineCopyRemainder( + const uint8_t *buf, const uint32_t buf_len, const uint32_t offset, MimeDecParseState *state) +{ + DEBUG_VALIDATE_BUG_ON(offset > buf_len); + if (offset > buf_len) + return MIME_DEC_ERR_DATA; + + for (uint32_t i = offset; i < buf_len; i++) { + // Skip any characters outside of the base64 alphabet as per RFC 2045 + if (IsBase64Alphabet(buf[i])) { + DEBUG_VALIDATE_BUG_ON(state->bvr_len >= B64_BLOCK); + if (state->bvr_len >= B64_BLOCK) + return MIME_DEC_ERR_DATA; + state->bvremain[state->bvr_len++] = buf[i]; + } + } + return MIME_DEC_OK; +} + +/** + * \brief Processes a body line by base64-decoding and passing to the data chunk + * processing callback function when the buffer is read + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint32_t numDecoded, remaining = len, offset = 0; + + /* Track long line TODO should we count space padding too? */ + if (len > MAX_ENC_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; + state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; + SCLogDebug("max encoded input line length exceeded %u > %u", len, MAX_ENC_LINE_LEN); + } + + if (state->bvr_len + len < B64_BLOCK) { + return ProcessBase64BodyLineCopyRemainder(buf, len, 0, state); + } + + /* First process remaining from previous line. We will consume + * state->bvremain, filling it from 'buf' until we have a properly + * sized block. Spaces are skipped (rfc2045). If state->bvr_len + * is not 0 after processing we have no data left at 'buf'. */ + if (state->bvr_len > 0) { + uint32_t consumed = ProcessBase64Remainder(buf, len, state, 0); + DEBUG_VALIDATE_BUG_ON(consumed > len); + if (consumed > len) + return MIME_DEC_ERR_PARSE; + + uint32_t left = len - consumed; + if (left < B64_BLOCK) { + DEBUG_VALIDATE_BUG_ON(left + state->bvr_len > B64_BLOCK); + return ProcessBase64BodyLineCopyRemainder(buf, len, consumed, state); + } + + remaining -= consumed; + offset = consumed; + } + + while (remaining > 0 && remaining >= B64_BLOCK) { + uint32_t consumed_bytes = 0; + uint32_t avail_space = DATA_CHUNK_SIZE - state->data_chunk_len; + PrintChars(SC_LOG_DEBUG, "BASE64 INPUT (line)", buf + offset, remaining); + Base64Ecode code = DecodeBase64(state->data_chunk + state->data_chunk_len, avail_space, + buf + offset, remaining, &consumed_bytes, &numDecoded, BASE64_MODE_RFC2045); + SCLogDebug("DecodeBase64 result %u", code); + DEBUG_VALIDATE_BUG_ON(consumed_bytes > remaining); + if (consumed_bytes > remaining) + return MIME_DEC_ERR_PARSE; + + uint32_t leftover_bytes = remaining - consumed_bytes; + if (numDecoded > 0 && (code == BASE64_ECODE_OK || code == BASE64_ECODE_BUF)) { + PrintChars(SC_LOG_DEBUG, "BASE64 DECODED (line)", + state->data_chunk + state->data_chunk_len, numDecoded); + + state->data_chunk_len += numDecoded; + + if ((int)(DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { + SCLogDebug("Error: Invalid Chunk length: %u", state->data_chunk_len); + return MIME_DEC_ERR_PARSE; + } + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); + break; + } + } + } else if (code == BASE64_ECODE_ERR) { + /* Track failed base64 */ + state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; + state->msg->anomaly_flags |= ANOM_INVALID_BASE64; + SCLogDebug("Error: DecodeBase64() function failed"); + return MIME_DEC_ERR_DATA; + } + + /* corner case: multiples spaces in the last data, leading it to exceed the block + * size. We strip of spaces this while storing it in bvremain */ + if (consumed_bytes == 0 && leftover_bytes > B64_BLOCK) { + DEBUG_VALIDATE_BUG_ON(state->bvr_len != 0); + ret = ProcessBase64BodyLineCopyRemainder(buf, len, offset, state); + break; + } else if (leftover_bytes > 0 && leftover_bytes <= B64_BLOCK) { + /* If remaining is 4 by this time, we encountered spaces during processing */ + DEBUG_VALIDATE_BUG_ON(state->bvr_len != 0); + ret = ProcessBase64BodyLineCopyRemainder(buf, len, offset + consumed_bytes, state); + break; + } + + /* Update counts */ + remaining = leftover_bytes; + offset += consumed_bytes; + } + if (ret == MIME_DEC_OK && state->data_chunk_len > 0) { + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + } + return ret; +} + +/** + * \brief Decoded a hex character into its equivalent byte value for + * quoted-printable decoding + * + * \param h The hex char + * + * \return byte value on success, -1 if failed + **/ +static int8_t DecodeQPChar(char h) +{ + int8_t res = 0; + + /* 0-9 */ + if (h >= 48 && h <= 57) { + res = h - 48; + } else if (h >= 65 && h <= 70) { + /* A-F */ + res = h - 55; + } else { + /* Invalid */ + res = -1; + } + + return res; +} + +/** + * \brief Processes a quoted-printable encoded body line by decoding and passing + * to the data chunk processing callback function when the buffer is read + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessQuotedPrintableBodyLine( + const uint8_t *buf, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint32_t remaining, offset; + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + uint8_t c, h1, h2, val; + int16_t res; + + /* Track long line */ + if (len > MAX_ENC_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; + state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; + SCLogDebug("Error: Max encoded input line length exceeded %u > %u", len, MAX_ENC_LINE_LEN); + } + if (len == 0) { + memcpy(state->data_chunk + state->data_chunk_len, buf + len, + state->current_line_delimiter_len); + state->data_chunk_len += state->current_line_delimiter_len; + return ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + } + + remaining = len; + offset = 0; + while (remaining > 0) { + + c = *(buf + offset); + + /* Copy over normal character */ + if (c != '=') { + state->data_chunk[state->data_chunk_len] = c; + state->data_chunk_len++; + + /* Add CRLF sequence if end of line, unless its a partial line */ + if (remaining == 1 && state->current_line_delimiter_len > 0) { + memcpy(state->data_chunk + state->data_chunk_len, CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + } + } else if (remaining > 1) { + /* If last character handle as soft line break by ignoring, + otherwise process as escaped '=' character */ + + /* Not enough characters */ + if (remaining < 3) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + h1 = *(buf + offset + 1); + res = DecodeQPChar(h1); + if (res < 0) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + val = (uint8_t)(res << 4); /* Shift result left */ + h2 = *(buf + offset + 2); + res = DecodeQPChar(h2); + if (res < 0) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + /* Decoding sequence succeeded */ + val += res; + + state->data_chunk[state->data_chunk_len] = val; + state->data_chunk_len++; + + /* Add CRLF sequence if end of line, unless for partial lines */ + if (remaining == 3 && state->current_line_delimiter_len > 0) { + memcpy(state->data_chunk + state->data_chunk_len, CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + } + + /* Account for extra 2 characters in 3-character QP + * sequence */ + remaining -= 2; + offset += 2; + } + } + } + } + + /* Change by 1 */ + remaining--; + offset++; + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < EOL_LEN + 1) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + } + + return ret; +} + +/** + * \brief Processes a body line by base64-decoding (if applicable) and passing to + * the data chunk processing callback function + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessBodyLine(const uint8_t *buf, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint32_t remaining, offset, avail, tobuf; + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + + SCLogDebug("Processing body line"); + + /* Process base-64 content if enabled */ + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (mdcfg != NULL && mdcfg->decode_base64 && (entity->ctnt_flags & CTNT_IS_BASE64)) { + + ret = ProcessBase64BodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBase64BodyLine() function failed"); + } + } else if (mdcfg != NULL && mdcfg->decode_quoted_printable && + (entity->ctnt_flags & CTNT_IS_QP)) { + /* Process quoted-printable content if enabled */ + ret = ProcessQuotedPrintableBodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessQuotedPrintableBodyLine() function " + "failed"); + } + } else { + /* Process non-decoded content */ + remaining = len; + offset = 0; + while (remaining > 0) { + /* Plan to add CRLF to the end of each line */ + avail = DATA_CHUNK_SIZE - state->data_chunk_len; + tobuf = avail > remaining ? remaining : avail; + + /* Copy over to buffer */ + memcpy(state->data_chunk + state->data_chunk_len, buf + offset, tobuf); + state->data_chunk_len += tobuf; + + if ((int)(DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { + SCLogDebug("Error: Invalid Chunk length: %u", state->data_chunk_len); + ret = MIME_DEC_ERR_PARSE; + break; + } + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len == 0) { + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + + remaining -= tobuf; + offset += tobuf; + } + if (ret == MIME_DEC_OK) { + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + // keep end of line for next call (and skip it on completion) + memcpy(state->data_chunk, buf + offset, state->current_line_delimiter_len); + state->data_chunk_len = state->current_line_delimiter_len; + } + + return ret; +} + +/** + * \brief Find the start of a header name on the current line + * + * \param buf The input line (not null-terminated) + * \param blen The length of the input line + * \param glen The output length of the header name + * + * \return Pointer to header name, or NULL if not found + */ +static uint8_t *FindMimeHeaderStart(const uint8_t *buf, uint32_t blen, uint32_t *hlen) +{ + uint32_t i, valid = 0; + uint8_t *hname = NULL; + + /* Init */ + *hlen = 0; + + /* Look for sequence of printable characters followed by ':', or + CRLF then printable characters followed by ':' */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* If ready for printable characters and found one, then increment */ + if (buf[i] != COLON && buf[i] >= PRINTABLE_START && buf[i] <= PRINTABLE_END) { + valid++; + } else if (valid > 0 && buf[i] == COLON) { + /* If ready for printable characters, found some, and found colon + * delimiter, then a match is found */ + hname = (uint8_t *)buf + i - valid; + *hlen = valid; + break; + } else { + /* Otherwise reset and quit */ + break; + } + } + + return hname; +} + +/** + * \brief Find full header name and value on the current line based on the + * current state + * + * \param buf The current line (no CRLF) + * \param blen The length of the current line + * \param state The current state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int FindMimeHeader(const uint8_t *buf, uint32_t blen, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t *hname, *hval = NULL; + DataValue *dv; + uint32_t hlen, vlen; + int finish_header = 0, new_header = 0; + MimeDecConfig *mdcfg = MimeDecGetConfig(); + + DEBUG_VALIDATE_BUG_ON(state->current_line_delimiter_len == 0 && blen < SMTP_LINE_BUFFER_LIMIT); + + /* Find first header */ + hname = FindMimeHeaderStart(buf, blen, &hlen); + if (hname != NULL) { + + /* Warn and track but don't do anything yet */ + if (hlen > MAX_HEADER_NAME) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_NAME; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_NAME; + SCLogDebug("Error: Header name exceeds limit (%u > %u)", hlen, MAX_HEADER_NAME); + } + + /* Value starts after 'header:' (normalize spaces) */ + hval = hname + hlen + 1; + if (hval - buf >= (int)blen) { + SCLogDebug("No Header value found"); + hval = NULL; + } else { + while (hval[0] == ' ') { + + /* If last character before end of bounds, set to NULL */ + if (hval - buf >= (int)blen - 1) { + SCLogDebug("No Header value found"); + hval = NULL; + break; + } + + hval++; + } + } + + /* If new header found, then previous header is finished */ + if (state->state_flag == HEADER_STARTED) { + finish_header = 1; + } + + /* Now process new header */ + new_header = 1; + + /* Must wait for next line to determine if finished */ + state->state_flag = HEADER_STARTED; + } else if (blen == 0) { + /* Found body */ + /* No more headers */ + state->state_flag = HEADER_DONE; + + finish_header = 1; + + SCLogDebug("All Header processing finished"); + } else if (state->state_flag == HEADER_STARTED) { + /* Found multi-line value (ie. Received header) */ + /* If max header value exceeded, flag it */ + vlen = blen; + if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { + SCLogDebug("Error: Header value of length (%u) is too long", state->hvlen + vlen); + vlen = mdcfg->header_value_depth - state->hvlen; + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + } + if (vlen > 0) { + dv = AddDataValue(state->hvalue); + if (dv == NULL) { + return MIME_DEC_ERR_MEM; + } + if (state->hvalue == NULL) { + state->hvalue = dv; + } + + dv->value = SCMalloc(vlen); + if (unlikely(dv->value == NULL)) { + return MIME_DEC_ERR_MEM; + } + memcpy(dv->value, buf, vlen); + dv->value_len = vlen; + state->hvlen += vlen; + } + } else { + /* Likely a body without headers */ + SCLogDebug("No headers found"); + + state->state_flag = BODY_STARTED; + + /* Flag beginning of body */ + state->body_begin = 1; + state->body_end = 0; + + // Begin the body md5 computation if config asks so + if (MimeDecGetConfig()->body_md5 && state->md5_ctx == NULL) { + state->md5_ctx = SCMd5New(); + SCMd5Update(state->md5_ctx, buf, blen + state->current_line_delimiter_len); + } + + ret = ProcessBodyLine(buf, blen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyLine() function failed"); + return ret; + } + } + + /* If we need to finish a header, then do so below and then cleanup */ + if (finish_header) { + /* Store the header value */ + ret = StoreMimeHeader(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: StoreMimeHeader() function failed"); + return ret; + } + } + + /* When next header is found, we always create a new one */ + if (new_header) { + /* Copy name and value to state */ + state->hname = SCMalloc(hlen); + if (unlikely(state->hname == NULL)) { + return MIME_DEC_ERR_MEM; + } + memcpy(state->hname, hname, hlen); + state->hlen = hlen; + + if (state->hvalue != NULL) { + SCLogDebug("Error: Parser failed due to unexpected header " + "value"); + return MIME_DEC_ERR_DATA; + } + + if (hval != NULL) { + /* If max header value exceeded, flag it */ + vlen = blen - (hval - buf); + if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { + SCLogDebug("Error: Header value of length (%u) is too long", state->hvlen + vlen); + vlen = mdcfg->header_value_depth - state->hvlen; + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + } + + if (vlen > 0) { + state->hvalue = AddDataValue(NULL); + if (state->hvalue == NULL) { + return MIME_DEC_ERR_MEM; + } + state->hvalue->value = SCMalloc(vlen); + if (unlikely(state->hvalue->value == NULL)) { + return MIME_DEC_ERR_MEM; + } + memcpy(state->hvalue->value, hval, vlen); + state->hvalue->value_len = vlen; + state->hvlen += vlen; + } + } + } + + return ret; +} + +/** + * \brief Processes the current line for mime headers and also does post-processing + * when all headers found + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + MimeDecField *field; + uint8_t *rptr = NULL; + uint32_t blen = 0; + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + uint8_t bptr[RS_MIME_MAX_TOKEN_LEN]; + + /* Look for mime header in current line */ + ret = FindMimeHeader(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: FindMimeHeader() function failed: %d", ret); + return ret; + } + + /* Post-processing after all headers done */ + if (state->state_flag == HEADER_DONE) { + /* First determine encoding by looking at Content-Transfer-Encoding */ + field = MimeDecFindField(entity, CTNT_TRAN_STR); + if (field != NULL) { + /* Look for base64 */ + if (FindBuffer(field->value, field->value_len, (const uint8_t *)BASE64_STR, + (uint16_t)strlen(BASE64_STR))) { + SCLogDebug("Base64 encoding found"); + entity->ctnt_flags |= CTNT_IS_BASE64; + } else if (FindBuffer(field->value, field->value_len, (const uint8_t *)QP_STR, + (uint16_t)strlen(QP_STR))) { + /* Look for quoted-printable */ + SCLogDebug("quoted-printable encoding found"); + entity->ctnt_flags |= CTNT_IS_QP; + } + } + + /* Check for file attachment in content disposition */ + field = MimeDecFindField(entity, CTNT_DISP_STR); + if (field != NULL) { + bool truncated_name = false; + if (rs_mime_find_header_token(field->value, field->value_len, + (const uint8_t *)"filename", strlen("filename"), &bptr, &blen)) { + SCLogDebug("File attachment found in disposition"); + entity->ctnt_flags |= CTNT_IS_ATTACHMENT; + + if (blen > RS_MIME_MAX_TOKEN_LEN) { + blen = RS_MIME_MAX_TOKEN_LEN; + truncated_name = true; + } + + /* Copy over using dynamic memory */ + entity->filename = SCMalloc(blen); + if (unlikely(entity->filename == NULL)) { + return MIME_DEC_ERR_MEM; + } + memcpy(entity->filename, bptr, blen); + entity->filename_len = blen; + + if (truncated_name) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_FILENAME; + state->msg->anomaly_flags |= ANOM_LONG_FILENAME; + } + } + } + + /* Check for boundary, encapsulated message, and file name in Content-Type */ + field = MimeDecFindField(entity, CTNT_TYPE_STR); + if (field != NULL) { + /* Check if child entity boundary definition found */ + // RS_MIME_MAX_TOKEN_LEN is RS_MIME_MAX_TOKEN_LEN on the rust side + if (rs_mime_find_header_token(field->value, field->value_len, + (const uint8_t *)"boundary", strlen("boundary"), &bptr, &blen)) { + state->found_child = 1; + entity->ctnt_flags |= CTNT_IS_MULTIPART; + + if (blen > (BOUNDARY_BUF - 2)) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; + return MIME_DEC_ERR_PARSE; + } + + /* Store boundary in parent node */ + state->stack->top->bdef = SCMalloc(blen); + if (unlikely(state->stack->top->bdef == NULL)) { + return MIME_DEC_ERR_MEM; + } + memcpy(state->stack->top->bdef, bptr, blen); + state->stack->top->bdef_len = (uint16_t)blen; + } + + /* Look for file name (if not already found) */ + if (!(entity->ctnt_flags & CTNT_IS_ATTACHMENT)) { + bool truncated_name = false; + if (rs_mime_find_header_token(field->value, field->value_len, + (const uint8_t *)"name", strlen("name"), &bptr, &blen)) { + SCLogDebug("File attachment found"); + entity->ctnt_flags |= CTNT_IS_ATTACHMENT; + + if (blen > RS_MIME_MAX_TOKEN_LEN) { + blen = RS_MIME_MAX_TOKEN_LEN; + truncated_name = true; + } + + /* Copy over using dynamic memory */ + entity->filename = SCMalloc(blen); + if (unlikely(entity->filename == NULL)) { + return MIME_DEC_ERR_MEM; + } + memcpy(entity->filename, bptr, blen); + entity->filename_len = blen; + + if (truncated_name) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_FILENAME; + state->msg->anomaly_flags |= ANOM_LONG_FILENAME; + } + } + } + + /* Pull out short-hand content type */ + entity->ctnt_type = GetToken( + field->value, field->value_len, " \r\n;", &rptr, &entity->ctnt_type_len); + if (entity->ctnt_type != NULL) { + /* Check for encapsulated message */ + if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, (const uint8_t *)MSG_STR, + (uint16_t)strlen(MSG_STR))) { + SCLogDebug("Found encapsulated message entity"); + + entity->ctnt_flags |= CTNT_IS_ENV; + + /* Create and push child to stack */ + MimeDecEntity *child = MimeDecAddEntity(entity); + if (child == NULL) + return MIME_DEC_ERR_MEM; + child->ctnt_flags |= (CTNT_IS_ENCAP | CTNT_IS_MSG); + PushStack(state->stack); + state->stack->top->data = child; + + /* Mark as encapsulated child */ + state->stack->top->is_encap = 1; + + /* Ready to parse headers */ + state->state_flag = HEADER_READY; + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)MULTIPART_STR, + (uint16_t)strlen(MULTIPART_STR))) { + /* Check for multipart */ + SCLogDebug("Found multipart entity"); + entity->ctnt_flags |= CTNT_IS_MULTIPART; + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)TXT_STR, (uint16_t)strlen(TXT_STR))) { + /* Check for plain text */ + SCLogDebug("Found plain text entity"); + entity->ctnt_flags |= CTNT_IS_TEXT; + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)HTML_STR, (uint16_t)strlen(HTML_STR))) { + /* Check for html */ + SCLogDebug("Found html entity"); + entity->ctnt_flags |= CTNT_IS_HTML; + } + } + } + + /* Store pointer to Message-ID */ + field = MimeDecFindField(entity, MSG_ID_STR); + if (field != NULL) { + entity->msg_id = field->value; + entity->msg_id_len = field->value_len; + } + + /* Flag beginning of body */ + state->body_begin = 1; + state->body_end = 0; + } + + return ret; +} + +/** + * \brief Indicates to the parser that the body of an entity has completed + * processing on the previous line + * + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ + +static int ProcessBodyComplete(MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + SCLogDebug("Process body complete called"); + + /* Mark the file as hitting the end */ + state->body_end = 1; + + if (state->bvr_len > 0) { + SCLogDebug("Found (%u) remaining base64 bytes not processed", state->bvr_len); + + /* Process the remainder */ + ret = ProcessBase64Remainder(NULL, 0, state, 1); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBase64BodyLine() function failed"); + } + } + + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + if ((entity->ctnt_flags & (CTNT_IS_BASE64 | CTNT_IS_QP)) == 0) { + // last eol of plaintext is the beginning of the boundary + state->data_chunk_len = 0; + } + /* Invoke pre-processor and callback with remaining data */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); + } + + /* Now reset */ + state->body_begin = 0; + state->body_end = 0; + + return ret; +} + +/** + * \brief When a mime boundary is found, look for end boundary and also do stack + * management + * + * \param buf The current line + * \param len The length of the line + * \param bdef_len The length of the current boundary + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeBoundary( + const uint8_t *buf, uint32_t len, uint16_t bdef_len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t *rptr; + MimeDecEntity *child; + + SCLogDebug("PROCESSING BOUNDARY - START: %d", state->state_flag); + + /* If previous line was not an end boundary, then we process the body as + * completed */ + if (state->state_flag != BODY_END_BOUND) { + + /* First lets complete the body */ + ret = ProcessBodyComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyComplete() function failed"); + return ret; + } + } else { + /* If last line was an end boundary, then now we are ready to parse + * headers again */ + state->state_flag = HEADER_READY; + } + + /* Update remaining buffer */ + rptr = (uint8_t *)buf + bdef_len + 2; + + /* If entity is encapsulated and current and parent didn't define the boundary, + * then pop out */ + if (state->stack->top->is_encap && state->stack->top->bdef_len == 0) { + + if (state->stack->top->next == NULL) { + SCLogDebug("Error: Missing parent entity from stack"); + return MIME_DEC_ERR_DATA; + } + + if (state->stack->top->next->bdef_len == 0) { + + SCLogDebug("POPPED ENCAPSULATED CHILD FROM STACK: %p=%p", state->stack->top, + state->stack->top->data); + + /* If end of boundary found, pop the child off the stack */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + } + + /* Now check for end of nested boundary */ + if (len - (rptr - buf) > 1 && rptr[0] == DASH && rptr[1] == DASH) { + SCLogDebug( + "FOUND END BOUNDARY, POPPING: %p=%p", state->stack->top, state->stack->top->data); + + /* If end of boundary found, pop the child off the stack */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* If current is an encapsulated message with a boundary definition, + * then pop him as well */ + if (state->stack->top->is_encap && state->stack->top->bdef_len != 0) { + SCLogDebug("FOUND END BOUNDARY AND ENCAP, POPPING: %p=%p", state->stack->top, + state->stack->top->data); + + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + + state->state_flag = BODY_END_BOUND; + } else if (state->found_child) { + /* Otherwise process new child */ + SCLogDebug("Child entity created"); + + /* Create and push child to stack */ + child = MimeDecAddEntity(state->stack->top->data); + if (child == NULL) + return MIME_DEC_ERR_MEM; + child->ctnt_flags |= CTNT_IS_BODYPART; + PushStack(state->stack); + state->stack->top->data = child; + + /* Reset flag */ + state->found_child = 0; + } else { + /* Otherwise process sibling */ + if (state->stack->top->next == NULL) { + SCLogDebug("Error: Missing parent entity from stack"); + return MIME_DEC_ERR_DATA; + } + + SCLogDebug("SIBLING CREATED, POPPING PARENT: %p=%p", state->stack->top, + state->stack->top->data); + + /* First pop current to get access to parent */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* Create and push child to stack */ + child = MimeDecAddEntity(state->stack->top->data); + if (child == NULL) + return MIME_DEC_ERR_MEM; + child->ctnt_flags |= CTNT_IS_BODYPART; + PushStack(state->stack); + state->stack->top->data = child; + } + + /* After boundary look for headers */ + if (state->state_flag != BODY_END_BOUND) { + state->state_flag = HEADER_READY; + } + + SCLogDebug("PROCESSING BOUNDARY - END: %d", state->state_flag); + return ret; +} + +/** + * \brief Processes the MIME Entity body based on the input line and current + * state of the parser + * + * \param buf The current line + * \param len The length of the line + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeBody(const uint8_t *buf, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t temp[BOUNDARY_BUF]; + uint8_t *bstart; + int body_found = 0; + uint16_t tlen; + + /* pass empty lines on if we're parsing the body, otherwise we have no use + * for them, and in fact they would disrupt the state tracking */ + if (len == 0) { + /* don't start a new body after an end bound based on an empty line */ + if (state->state_flag == BODY_END_BOUND) { + SCLogDebug("skip empty line"); + return MIME_DEC_OK; + } else if (state->state_flag == HEADER_DONE) { + SCLogDebug("empty line, lets see if we skip it. We're in state %s", + MimeDecParseStateGetStatus(state)); + MimeDecEntity *entity = (MimeDecEntity *)state->stack->top->data; + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (entity != NULL && mdcfg != NULL) { + if (mdcfg->decode_base64 && (entity->ctnt_flags & CTNT_IS_BASE64)) { + SCLogDebug("skip empty line"); + return MIME_DEC_OK; + } + SCLogDebug("not skipping empty line"); + } + } else { + SCLogDebug("not skipping line at state %s", MimeDecParseStateGetStatus(state)); + } + } + + /* First look for boundary */ + MimeDecStackNode *node = state->stack->top; + if (node == NULL) { + SCLogDebug("Error: Invalid stack state"); + return MIME_DEC_ERR_PARSE; + } + + /* Traverse through stack to find a boundary definition */ + if (state->state_flag == BODY_END_BOUND || node->bdef == NULL) { + + /* If not found, then use parent's boundary */ + node = node->next; + while (node != NULL && node->bdef == NULL) { + SCLogDebug("Traversing through stack for node with boundary"); + node = node->next; + } + } + + /* This means no boundary / parent w/boundary was found so we are in the body */ + if (node == NULL) { + body_found = 1; + } else { + + /* Now look for start of boundary */ + if (len > 1 && buf[0] == '-' && buf[1] == '-') { + + tlen = node->bdef_len + 2; + if (tlen > BOUNDARY_BUF) { + if (state->stack->top->data) + state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; + SCLogDebug("Error: Long boundary: tlen %u > %d. Set ANOM_LONG_BOUNDARY", tlen, + BOUNDARY_BUF); + return MIME_DEC_ERR_PARSE; + } + + memcpy(temp, "--", 2); + memcpy(temp + 2, node->bdef, node->bdef_len); + + /* Find either next boundary or end boundary */ + bstart = FindBuffer(buf, len, temp, tlen); + if (bstart != NULL) { + ret = ProcessMimeBoundary(buf, len, node->bdef_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeBoundary() function " + "failed"); + return ret; + } + } else { + /* Otherwise add value to body */ + body_found = 1; + } + } else { + /* Otherwise add value to body */ + body_found = 1; + } + } + + /* Process body line */ + if (body_found) { + state->state_flag = BODY_STARTED; + + ret = ProcessBodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyLine() function failed"); + return ret; + } + } + + return ret; +} + +const char *MimeDecParseStateGetStatus(MimeDecParseState *state) +{ + return StateFlags[state->state_flag]; +} + +/** + * \brief Processes the MIME Entity based on the input line and current state of + * the parser + * + * \param buf The current line + * \param len The length of the line + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeEntity(const uint8_t *buf, uint32_t len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + SCLogDebug("START FLAG: %s", StateFlags[state->state_flag]); + + if (state->state_flag == PARSE_ERROR) { + SCLogDebug("START FLAG: PARSE_ERROR, bail"); + return MIME_DEC_ERR_STATE; + } + + /* Track long line */ + if (len > MAX_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_LINE; + state->msg->anomaly_flags |= ANOM_LONG_LINE; + SCLogDebug("Error: Max input line length exceeded %u > %u", len, MAX_LINE_LEN); + } + + if (!g_disable_hashing) { + if ((state->state_flag != HEADER_READY && state->state_flag != HEADER_STARTED) || + (state->stack->top->data->ctnt_flags & CTNT_IS_BODYPART)) { + if (MimeDecGetConfig()->body_md5) { + if (state->body_begin == 1 && state->md5_ctx == NULL) { + state->md5_ctx = SCMd5New(); + } + SCMd5Update(state->md5_ctx, buf, len + state->current_line_delimiter_len); + } + } + } + + /* Looking for headers */ + if (state->state_flag == HEADER_READY || state->state_flag == HEADER_STARTED) { + + SCLogDebug("Processing Headers"); + + /* Process message headers */ + ret = ProcessMimeHeaders(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeHeaders() function failed: %d", ret); + return ret; + } + } else { + /* Processing body */ + SCLogDebug("Processing Body of: %p", state->stack->top); + + ret = ProcessMimeBody(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeBody() function failed: %d", ret); + return ret; + } + } + + SCLogDebug("END FLAG: %s", StateFlags[state->state_flag]); + + return ret; +} + +/** + * \brief Init the parser by allocating memory for the state and top-level entity + * + * \param data A caller-specified pointer to data for access within the data chunk + * processor callback function + * \param dcpfunc The data chunk processor callback function + * + * \return A pointer to the state object, or NULL if the operation fails + */ +MimeDecParseState *MimeDecInitParser(void *data, + int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)) +{ + MimeDecParseState *state; + MimeDecEntity *mimeMsg; + + state = SCCalloc(1, sizeof(MimeDecParseState)); + if (unlikely(state == NULL)) { + return NULL; + } + + state->stack = SCCalloc(1, sizeof(MimeDecStack)); + if (unlikely(state->stack == NULL)) { + SCFree(state); + return NULL; + } + + mimeMsg = SCCalloc(1, sizeof(MimeDecEntity)); + if (unlikely(mimeMsg == NULL)) { + SCFree(state->stack); + SCFree(state); + return NULL; + } + mimeMsg->ctnt_flags |= CTNT_IS_MSG; + + /* Init state */ + state->msg = mimeMsg; + PushStack(state->stack); + if (state->stack->top == NULL) { + SCFree(state->stack); + SCFree(state); + return NULL; + } + state->stack->top->data = mimeMsg; + state->state_flag = HEADER_READY; + state->data = data; + state->DataChunkProcessorFunc = DataChunkProcessorFunc; + + return state; +} + +/** + * \brief De-Init parser by freeing up any residual memory + * + * \param state The parser state + * + * \return none + */ +void MimeDecDeInitParser(MimeDecParseState *state) +{ + uint32_t cnt = 0; + + while (state->stack->top != NULL) { + SCLogDebug("Remaining on stack: [%p]=>[%p]", state->stack->top, state->stack->top->data); + + PopStack(state->stack); + cnt++; + } + + if (cnt > 1) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Warning: Stack is not empty upon completion of " + "processing (%u items remaining)", + cnt); + } + + SCFree(state->hname); + FreeDataValue(state->hvalue); + FreeMimeDecStack(state->stack); + if (state->md5_ctx) + SCMd5Free(state->md5_ctx); + SCFree(state); +} + +/** + * \brief Called to indicate that the last message line has been processed and + * the parsing operation is complete + * + * This function should be called directly by the caller. + * + * \param state The parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +int MimeDecParseComplete(MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + SCLogDebug("Parsing flagged as completed"); + + if (state->state_flag == PARSE_ERROR) { + SCLogDebug("parser in error state: PARSE_ERROR"); + return MIME_DEC_ERR_STATE; + } + + /* Store the header value */ + ret = StoreMimeHeader(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: StoreMimeHeader() function failed"); + return ret; + } + + /* Lets complete the body */ + ret = ProcessBodyComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyComplete() function failed"); + return ret; + } + + if (state->md5_ctx) { + SCMd5Finalize(state->md5_ctx, state->md5, sizeof(state->md5)); + state->md5_ctx = NULL; + state->has_md5 = true; + } + + if (state->stack->top == NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* If encapsulated, pop off the stack */ + if (state->stack->top->is_encap) { + PopStack(state->stack); + if (state->stack->top == NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + + /* Look extra stack items remaining */ + if (state->stack->top->next != NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Warning: Message has unclosed message part boundary"); + } + + state->state_flag = PARSE_DONE; + + return ret; +} + +/** + * \brief Parse a line of a MIME message and update the parser state + * + * \param line A string representing the line (w/out CRLF) + * \param len The length of the line + * \param delim_len The length of the line end delimiter + * \param state The parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +int MimeDecParseLine( + const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + /* For debugging purposes */ + if (len > 0) { + PrintChars(SC_LOG_DEBUG, "SMTP LINE", line, len); + } else { + SCLogDebug("SMTP LINE - EMPTY"); + } + + state->current_line_delimiter_len = delim_len; + /* Process the entity */ + ret = ProcessMimeEntity(line, len, state); + if (ret != MIME_DEC_OK) { + state->state_flag = PARSE_ERROR; + SCLogDebug("Error: ProcessMimeEntity() function failed: %d", ret); + } + + return ret; +} + +/** + * \brief Parses an entire message when available in its entirety (wraps the + * line-based parsing functions) + * + * \param buf Buffer pointing to the full message + * \param blen Length of the buffer + * \param data Caller data to be available in callback + * \param dcpfunc Callback for processing each decoded body data chunk + * + * \return A pointer to the decoded MIME message, or NULL if the operation fails + */ +MimeDecEntity *MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, + int (*dcpfunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)) +{ + int ret = MIME_DEC_OK; + uint8_t *remainPtr, *tok; + uint32_t tokLen; + + MimeDecParseState *state = MimeDecInitParser(data, dcpfunc); + if (state == NULL) { + SCLogDebug("Error: MimeDecInitParser() function failed to create " + "state"); + return NULL; + } + + MimeDecEntity *msg = state->msg; + + /* Parse each line one by one */ + remainPtr = (uint8_t *)buf; + uint8_t *line = NULL; + do { + tok = GetLine(remainPtr, blen - (remainPtr - buf), &remainPtr, &tokLen); + if (tok != remainPtr) { + + line = tok; + + if ((remainPtr - tok) - tokLen > UINT8_MAX) { + SCLogDebug("Error: MimeDecParseLine() overflow: %ld", (remainPtr - tok) - tokLen); + ret = MIME_DEC_ERR_OVERFLOW; + break; + } + state->current_line_delimiter_len = (uint8_t)((remainPtr - tok) - tokLen); + /* Parse the line */ + ret = MimeDecParseLine(line, tokLen, state->current_line_delimiter_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: MimeDecParseLine() function failed: %d", ret); + break; + } + } + + } while (tok != remainPtr && remainPtr - buf < (int)blen); + + if (ret == MIME_DEC_OK) { + SCLogDebug("Message parser was successful"); + + /* Now complete message */ + ret = MimeDecParseComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: MimeDecParseComplete() function failed"); + } + } + + /* De-allocate memory for parser */ + MimeDecDeInitParser(state); + + if (ret != MIME_DEC_OK) { + MimeDecFreeEntity(msg); + msg = NULL; + } + + return msg; +} + +#ifdef UNITTESTS + +/* Helper body chunk callback function */ +static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, MimeDecParseState *state) +{ + uint32_t *line_count = (uint32_t *)state->data; + + if (state->body_begin) { + SCLogDebug("Body begin (len=%u)", len); + } + + /* Add up the line counts */ + if (len > 0) { + if ((*line_count) == 0) { + (*line_count)++; + } + PrintChars(SC_LOG_DEBUG, "CHUNK", chunk, len); + for (uint32_t i = 0; i < len; i++) { + if (chunk[i] == CR || chunk[i] == LF) { + if (i + 1 < len && chunk[i] != chunk[i + 1] && + (chunk[i + 1] == CR || chunk[i + 1] == LF)) { + i++; + } + (*line_count)++; + } + } + + SCLogDebug("line count (len=%u): %u", len, *line_count); + } + + if (state->body_end) { + SCLogDebug("Body end (len=%u)", len); + } + + return MIME_DEC_OK; +} + +/* Test simple case of line counts */ +static int MimeDecParseLineTest01(void) +{ + uint32_t line_count = 0; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "From: Sender1\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); + + str = "To: Recipient1\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); + + str = "Content-Type: text/plain\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); + + str = "\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); + + str = "A simple message line 1\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); + + str = "A simple message line 2\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); + + str = "A simple message line 3\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 1, 1, state) == MIME_DEC_OK); + + /* Completed */ + FAIL_IF_NOT(MimeDecParseComplete(state) == MIME_DEC_OK); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NOT_NULL(msg->next); + FAIL_IF_NOT_NULL(msg->child); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + FAIL_IF_NOT(line_count == 3); + PASS; +} + +/* Test simple case of EXE URL extraction */ +static int MimeDecParseLineTest02(void) +{ + uint32_t line_count = 0; + + ConfNode *url_schemes = ConfNodeNew(); + ConfNode *scheme = ConfNodeNew(); + FAIL_IF_NULL(url_schemes); + FAIL_IF_NULL(scheme); + + url_schemes->is_seq = 1; + scheme->val = SCStrdup("http://"); + FAIL_IF_NULL(scheme->val); + TAILQ_INSERT_TAIL(&url_schemes->head, scheme, next); + + MimeDecGetConfig()->decode_base64 = true; + MimeDecGetConfig()->decode_quoted_printable = true; + MimeDecGetConfig()->extract_urls = true; + MimeDecGetConfig()->extract_urls_schemes = url_schemes; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "From: Sender1\r\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); + + str = "To: Recipient1\r\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); + + str = "Content-Type: text/plain\r\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); + + str = "\r\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); + + str = "A simple message line 1\r\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); + + str = "A simple message line 2 click on http://www.test.com/malware.exe?" + "hahah hopefully you click this link\r\n"; + FAIL_IF_NOT(MimeDecParseLine((uint8_t *)str, strlen(str) - 2, 2, state) == MIME_DEC_OK); + + /* Completed */ + FAIL_IF_NOT(MimeDecParseComplete(state) == MIME_DEC_OK); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NULL(msg); + FAIL_IF_NULL(msg->url_list); + FAIL_IF_NOT((msg->url_list->url_flags & URL_IS_EXE)); + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + ConfNodeFree(url_schemes); + MimeDecGetConfig()->extract_urls_schemes = NULL; + + FAIL_IF_NOT(line_count == 2); + PASS; +} + +/* Test error case where no url schemes set in config */ +static int MimeFindUrlStringsTest01(void) +{ + int ret = MIME_DEC_OK; + uint32_t line_count = 0; + + MimeDecGetConfig()->extract_urls = true; + MimeDecGetConfig()->extract_urls_schemes = NULL; + MimeDecGetConfig()->log_url_scheme = false; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "test"; + ret = FindUrlStrings((uint8_t *)str, strlen(str), state); + /* Expected error since extract_url_schemes is NULL */ + FAIL_IF_NOT(ret == MIME_DEC_ERR_DATA); + + /* Completed */ + ret = MimeDecParseComplete(state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + MimeDecEntity *msg = state->msg; + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + PASS; +} + +/* Test simple case of URL extraction */ +static int MimeFindUrlStringsTest02(void) +{ + int ret = MIME_DEC_OK; + uint32_t line_count = 0; + ConfNode *url_schemes = ConfNodeNew(); + ConfNode *scheme = ConfNodeNew(); + FAIL_IF_NULL(url_schemes); + FAIL_IF_NULL(scheme); + + url_schemes->is_seq = 1; + scheme->val = SCStrdup("http://"); + FAIL_IF_NULL(scheme->val); + TAILQ_INSERT_TAIL(&url_schemes->head, scheme, next); + + MimeDecGetConfig()->extract_urls = true; + MimeDecGetConfig()->extract_urls_schemes = url_schemes; + MimeDecGetConfig()->log_url_scheme = false; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "A simple message click on " + "http://www.test.com/malware.exe? " + "hahah hopefully you click this link"; + ret = FindUrlStrings((uint8_t *)str, strlen(str), state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + /* Completed */ + ret = MimeDecParseComplete(state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + MimeDecEntity *msg = state->msg; + + FAIL_IF(msg->url_list == NULL); + + FAIL_IF_NOT(msg->url_list->url_flags & URL_IS_EXE); + FAIL_IF_NOT( + memcmp("www.test.com/malware.exe?", msg->url_list->url, msg->url_list->url_len) == 0); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + ConfNodeFree(url_schemes); + MimeDecGetConfig()->extract_urls_schemes = NULL; + + PASS; +} + +/* Test URL extraction with multiple schemes and URLs */ +static int MimeFindUrlStringsTest03(void) +{ + int ret = MIME_DEC_OK; + uint32_t line_count = 0; + ConfNode *url_schemes = ConfNodeNew(); + ConfNode *scheme1 = ConfNodeNew(); + ConfNode *scheme2 = ConfNodeNew(); + FAIL_IF_NULL(url_schemes); + FAIL_IF_NULL(scheme1); + FAIL_IF_NULL(scheme2); + + url_schemes->is_seq = 1; + scheme1->val = SCStrdup("http://"); + FAIL_IF_NULL(scheme1->val); + TAILQ_INSERT_TAIL(&url_schemes->head, scheme1, next); + scheme2->val = SCStrdup("https://"); + FAIL_IF_NULL(scheme2->val); + TAILQ_INSERT_TAIL(&url_schemes->head, scheme2, next); + + MimeDecGetConfig()->extract_urls = true; + MimeDecGetConfig()->extract_urls_schemes = url_schemes; + MimeDecGetConfig()->log_url_scheme = false; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "A simple message click on " + "http://www.test.com/malware.exe? " + "hahah hopefully you click this link, or " + "you can go to http://www.test.com/test/01.html and " + "https://www.test.com/test/02.php"; + ret = FindUrlStrings((uint8_t *)str, strlen(str), state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + /* Completed */ + ret = MimeDecParseComplete(state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + MimeDecEntity *msg = state->msg; + + FAIL_IF(msg->url_list == NULL); + + MimeDecUrl *url = msg->url_list; + FAIL_IF_NOT(memcmp("www.test.com/test/02.php", url->url, url->url_len) == 0); + + url = url->next; + FAIL_IF_NOT(memcmp("www.test.com/test/01.html", url->url, url->url_len) == 0); + + url = url->next; + FAIL_IF_NOT(memcmp("www.test.com/malware.exe?", url->url, url->url_len) == 0); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + ConfNodeFree(url_schemes); + MimeDecGetConfig()->extract_urls_schemes = NULL; + + PASS; +} + +/* Test URL extraction with multiple schemes and URLs with + * log_url_scheme enabled in the MIME config */ +static int MimeFindUrlStringsTest04(void) +{ + int ret = MIME_DEC_OK; + uint32_t line_count = 0; + ConfNode *url_schemes = ConfNodeNew(); + ConfNode *scheme1 = ConfNodeNew(); + ConfNode *scheme2 = ConfNodeNew(); + FAIL_IF_NULL(url_schemes); + FAIL_IF_NULL(scheme1); + FAIL_IF_NULL(scheme2); + + url_schemes->is_seq = 1; + scheme1->val = SCStrdup("http://"); + FAIL_IF_NULL(scheme1->val); + TAILQ_INSERT_TAIL(&url_schemes->head, scheme1, next); + scheme2->val = SCStrdup("https://"); + FAIL_IF_NULL(scheme2->val); + TAILQ_INSERT_TAIL(&url_schemes->head, scheme2, next); + + MimeDecGetConfig()->extract_urls = true; + MimeDecGetConfig()->extract_urls_schemes = url_schemes; + MimeDecGetConfig()->log_url_scheme = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "A simple message click on " + "http://www.test.com/malware.exe? " + "hahah hopefully you click this link, or " + "you can go to http://www.test.com/test/01.html and " + "https://www.test.com/test/02.php"; + ret = FindUrlStrings((uint8_t *)str, strlen(str), state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + /* Completed */ + ret = MimeDecParseComplete(state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + MimeDecEntity *msg = state->msg; + + FAIL_IF(msg->url_list == NULL); + + MimeDecUrl *url = msg->url_list; + FAIL_IF_NOT(memcmp("https://www.test.com/test/02.php", url->url, url->url_len) == 0); + + url = url->next; + FAIL_IF_NOT(memcmp("http://www.test.com/test/01.html", url->url, url->url_len) == 0); + + url = url->next; + FAIL_IF_NOT(memcmp("http://www.test.com/malware.exe?", url->url, url->url_len) == 0); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + ConfNodeFree(url_schemes); + MimeDecGetConfig()->extract_urls_schemes = NULL; + + PASS; +} + +/* Test URL extraction of IPV4 and IPV6 URLs with log_url_scheme + * enabled in the MIME config */ +static int MimeFindUrlStringsTest05(void) +{ + int ret = MIME_DEC_OK; + uint32_t line_count = 0; + ConfNode *url_schemes = ConfNodeNew(); + ConfNode *scheme = ConfNodeNew(); + FAIL_IF_NULL(url_schemes); + FAIL_IF_NULL(scheme); + + url_schemes->is_seq = 1; + scheme->val = SCStrdup("http://"); + FAIL_IF_NULL(scheme->val); + TAILQ_INSERT_TAIL(&url_schemes->head, scheme, next); + + MimeDecGetConfig()->extract_urls = true; + MimeDecGetConfig()->extract_urls_schemes = url_schemes; + MimeDecGetConfig()->log_url_scheme = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "A simple message click on " + "http://192.168.1.1/test/01.html " + "hahah hopefully you click this link or this one " + "http://0:0:0:0:0:0:0:0/test/02.php"; + ret = FindUrlStrings((uint8_t *)str, strlen(str), state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + /* Completed */ + ret = MimeDecParseComplete(state); + FAIL_IF_NOT(ret == MIME_DEC_OK); + + MimeDecEntity *msg = state->msg; + + FAIL_IF(msg->url_list == NULL); + + MimeDecUrl *url = msg->url_list; + FAIL_IF_NOT(url->url_flags & URL_IS_IP6); + FAIL_IF_NOT(memcmp("http://0:0:0:0:0:0:0:0/test/02.php", url->url, url->url_len) == 0); + + url = url->next; + FAIL_IF_NOT(url->url_flags & URL_IS_IP4); + FAIL_IF_NOT(memcmp("http://192.168.1.1/test/01.html", url->url, url->url_len) == 0); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + ConfNodeFree(url_schemes); + MimeDecGetConfig()->extract_urls_schemes = NULL; + + PASS; +} + +/* Test full message with linebreaks */ +static int MimeDecParseFullMsgTest01(void) +{ + uint32_t expected_count = 3; + uint32_t line_count = 0; + + char msg[] = "From: Sender1\r\n" + "To: Recipient1\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Line 1\r\n" + "Line 2\r\n" + "Line 3\r\n"; + + MimeDecEntity *entity = + MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, TestDataChunkCallback); + if (entity == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return 0; + } + + MimeDecFreeEntity(entity); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count, + line_count); + return 0; + } + + return 1; +} + +/* Test full message with linebreaks */ +static int MimeDecParseFullMsgTest02(void) +{ + uint32_t expected_count = 3; + uint32_t line_count = 0; + + char msg[] = "From: Sender2\r\n" + "To: Recipient2\r\n" + "Subject: subject2\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Line 1\r\n" + "Line 2\r\n" + "Line 3\r\n"; + + MimeDecEntity *entity = + MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, TestDataChunkCallback); + + if (entity == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return 0; + } + + MimeDecField *field = MimeDecFindField(entity, "subject"); + if (field == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return 0; + } + + if (field->value_len != sizeof("subject2") - 1) { + SCLogInfo("Warning: failed to get subject"); + return 0; + } + + if (memcmp(field->value, "subject2", field->value_len) != 0) { + SCLogInfo("Warning: failed to get subject"); + return 0; + } + + MimeDecFreeEntity(entity); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count, + line_count); + return 0; + } + + return 1; +} + +static int MimeBase64DecodeTest01(void) +{ + int ret = 0; + uint32_t consumed_bytes = 0, num_decoded = 0; + + const char *msg = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@" + "#$%^&*()-=_+,./;'[]<>?:"; + const char *base64msg = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QU" + "VJTVFVWV1hZWjEyMzQ1Njc4OTBAIyQlXiYqKCktPV8rLC4vOydbXTw+Pzo="; + + uint8_t *dst = SCMalloc(strlen(msg) + 1); + if (dst == NULL) + return 0; + + ret = DecodeBase64(dst, strlen(msg) + 1, (const uint8_t *)base64msg, strlen(base64msg), + &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045); + + if (memcmp(dst, msg, strlen(msg)) == 0) { + ret = 1; + } + + SCFree(dst); + + return ret; +} + +static int MimeIsExeURLTest01(void) +{ + int ret = 0; + const char *url1 = "http://www.google.com/"; + const char *url2 = "http://www.google.com/test.exe"; + + if (IsExeUrl((const uint8_t *)url1, strlen(url1)) != 0) { + SCLogDebug("Debug: URL1 error"); + goto end; + } + if (IsExeUrl((const uint8_t *)url2, strlen(url2)) != 1) { + SCLogDebug("Debug: URL2 error"); + goto end; + } + ret = 1; + +end: + + return ret; +} + +#define TEST(str, len, expect) \ + { \ + SCLogDebug("str %s", (str)); \ + int r = IsIpv4Host((const uint8_t *)(str), (len)); \ + FAIL_IF_NOT(r == (expect)); \ + } +static int MimeIsIpv4HostTest01(void) +{ + TEST("192.168.1.1", 11, 1); + TEST("192.168.1.1.4", 13, 0); + TEST("999.168.1.1", 11, 0); + TEST("1111.168.1.1", 12, 0); + TEST("999.oogle.com", 14, 0); + TEST("0:0:0:0:0:0:0:0", 15, 0); + TEST("192.168.255.255", 15, 1); + TEST("192.168.255.255/testurl.html", 28, 1); + TEST("www.google.com", 14, 0); + PASS; +} +#undef TEST + +#define TEST(str, len, expect) \ + { \ + SCLogDebug("str %s", (str)); \ + int r = IsIpv6Host((const uint8_t *)(str), (len)); \ + FAIL_IF_NOT(r == (expect)); \ + } +static int MimeIsIpv6HostTest01(void) +{ + TEST("0:0:0:0:0:0:0:0", 19, 1); + TEST("0000:0000:0000:0000:0000:0000:0000:0000", 39, 1); + TEST("XXXX:0000:0000:0000:0000:0000:0000:0000", 39, 0); + TEST("00001:0000:0000:0000:0000:0000:0000:0000", 40, 0); + TEST("0:0:0:0:0:0:0:0", 19, 1); + TEST("0:0:0:0:0:0:0:0:0", 20, 0); + TEST("192:168:1:1:0:0:0:0", 19, 1); + TEST("999.oogle.com", 14, 0); + TEST("192.168.255.255", 15, 0); + TEST("192.168.255.255/testurl.html", 28, 0); + TEST("www.google.com", 14, 0); + PASS; +} +#undef TEST + +static int MimeDecParseLongFilename01(void) +{ + /* contains 276 character filename -- length restricted to 255 chars */ + char mimemsg[] = "Content-Disposition: attachment; filename=\"" + "12characters12characters12characters12characters" + "12characters12characters12characters12characters" + "12characters12characters12characters12characters" + "12characters12characters12characters12characters" + "12characters12characters12characters12characters" + "12characters12characters12characters.exe\""; + + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = true; + MimeDecGetConfig()->decode_quoted_printable = true; + MimeDecGetConfig()->extract_urls = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "From: Sender1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "To: Recipient1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Type: text/plain"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + /* Contains 276 character filename */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); + + str = ""; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "A simple message line 1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + /* Completed */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NOT(msg); + + FAIL_IF_NOT(msg->anomaly_flags & ANOM_LONG_FILENAME); + FAIL_IF_NOT(msg->filename_len == RS_MIME_MAX_TOKEN_LEN); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + PASS; +} + +static int MimeDecParseSmallRemInp(void) +{ + // Remainder dA + // New input: AAAA + char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vdA"; + + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = true; + MimeDecGetConfig()->decode_quoted_printable = true; + MimeDecGetConfig()->extract_urls = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; + + const char *str = "From: Sender1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "To: Recipient1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Type: text/plain"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Transfer-Encoding: base64"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = ""; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); + + str = "AAAA"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + /* Completed */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NOT(msg); + + /* filename is not too long */ + FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + PASS; +} + +static int MimeDecParseRemSp(void) +{ + // Should have remainder vd A + char mimemsg[] = "TWltZSBkZWNvZGluZyBpc yBzbyBOT1QgZnVuISBJIGNhbm5vd A"; + + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = true; + MimeDecGetConfig()->decode_quoted_printable = true; + MimeDecGetConfig()->extract_urls = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; + + const char *str = "From: Sender1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "To: Recipient1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Type: text/plain"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Transfer-Encoding: base64"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = ""; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); + /* Completed */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NOT(msg); + + /* filename is not too long */ + FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + PASS; +} + +static int MimeDecVerySmallInp(void) +{ + // Remainder: A + // New input: aA + char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vA"; + + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = true; + MimeDecGetConfig()->decode_quoted_printable = true; + MimeDecGetConfig()->extract_urls = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; + + const char *str = "From: Sender1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "To: Recipient1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Type: text/plain"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Transfer-Encoding: base64"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = ""; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); + + str = "aA"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + /* Completed */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NOT(msg); + + /* filename is not too long */ + FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + PASS; +} + +static int MimeDecParseOddLen(void) +{ + char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vdA"; + + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = true; + MimeDecGetConfig()->decode_quoted_printable = true; + MimeDecGetConfig()->extract_urls = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT; + + const char *str = "From: Sender1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "To: Recipient1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Type: text/plain"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Transfer-Encoding: base64"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = ""; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); + /* Completed */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NOT(msg); + + /* filename is not too long */ + FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + PASS; +} + +static int MimeDecParseLongFilename02(void) +{ + /* contains 40 character filename and 500+ characters following filename */ + char mimemsg[] = "Content-Disposition: attachment; filename=\"" + "12characters12characters12characters.exe\"; " + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd" + "somejunkasfdasfsafasafdsasdasassdssdsd"; + + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = true; + MimeDecGetConfig()->decode_quoted_printable = true; + MimeDecGetConfig()->extract_urls = true; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback); + + const char *str = "From: Sender1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "To: Recipient1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "Content-Type: text/plain"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + /* Contains 40 character filename */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state)); + + str = ""; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + str = "A simple message line 1"; + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state)); + + /* Completed */ + FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state)); + + MimeDecEntity *msg = state->msg; + FAIL_IF_NOT(msg); + + /* filename is not too long */ + FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME); + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + PASS; +} + +#endif /* UNITTESTS */ + +void MimeDecRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01); + UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02); + UtRegisterTest("MimeFindUrlStringsTest01", MimeFindUrlStringsTest01); + UtRegisterTest("MimeFindUrlStringsTest02", MimeFindUrlStringsTest02); + UtRegisterTest("MimeFindUrlStringsTest03", MimeFindUrlStringsTest03); + UtRegisterTest("MimeFindUrlStringsTest04", MimeFindUrlStringsTest04); + UtRegisterTest("MimeFindUrlStringsTest05", MimeFindUrlStringsTest05); + UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01); + UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02); + UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01); + UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01); + UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01); + UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01); + UtRegisterTest("MimeDecParseLongFilename01", MimeDecParseLongFilename01); + UtRegisterTest("MimeDecParseLongFilename02", MimeDecParseLongFilename02); + UtRegisterTest("MimeDecParseSmallRemInp", MimeDecParseSmallRemInp); + UtRegisterTest("MimeDecParseRemSp", MimeDecParseRemSp); + UtRegisterTest("MimeDecVerySmallInp", MimeDecVerySmallInp); + UtRegisterTest("MimeDecParseOddLen", MimeDecParseOddLen); +#endif /* UNITTESTS */ +} diff --git a/src/util/decode-mime.h b/src/util/decode-mime.h new file mode 100644 index 000000000000..2f4627d10a04 --- /dev/null +++ b/src/util/decode-mime.h @@ -0,0 +1,247 @@ +/* Copyright (C) 2012 BAE Systems + * Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#ifndef MIME_DECODE_H_ +#define MIME_DECODE_H_ + +#include "../conf.h" +#include "util/base64.h" +#include "util/file.h" + +/* Content Flags */ +#define CTNT_IS_MSG 1 +#define CTNT_IS_ENV 2 +#define CTNT_IS_ENCAP 4 +#define CTNT_IS_BODYPART 8 +#define CTNT_IS_MULTIPART 16 +#define CTNT_IS_ATTACHMENT 32 +#define CTNT_IS_BASE64 64 +#define CTNT_IS_QP 128 +#define CTNT_IS_TEXT 256 +#define CTNT_IS_HTML 512 + +/* URL Flags */ +#define URL_IS_IP4 1 +#define URL_IS_IP6 2 +#define URL_IS_EXE 4 + +/* Anomaly Flags */ +#define ANOM_INVALID_BASE64 1 /* invalid base64 chars */ +#define ANOM_INVALID_QP 2 /* invalid quoted-printable chars */ +#define ANOM_LONG_HEADER_NAME 4 /* header is abnormally long */ +#define ANOM_LONG_HEADER_VALUE \ + 8 /* header value is abnormally long \ + * (includes multi-line) */ +#define ANOM_LONG_LINE 16 /* Lines that exceed 998 octets */ +#define ANOM_LONG_ENC_LINE 32 /* Lines that exceed 76 octets */ +#define ANOM_MALFORMED_MSG 64 /* Misc msg format errors found */ +#define ANOM_LONG_BOUNDARY 128 /* Boundary too long */ +#define ANOM_LONG_FILENAME 256 /* filename truncated */ + +/* Publicly exposed size constants */ +#define DATA_CHUNK_SIZE 3072 /* Should be divisible by 3 */ + +/* Mime Parser Constants */ +#define HEADER_READY 0x01 +#define HEADER_STARTED 0x02 +#define HEADER_DONE 0x03 +#define BODY_STARTED 0x04 +#define BODY_DONE 0x05 +#define BODY_END_BOUND 0x06 +#define PARSE_DONE 0x07 +#define PARSE_ERROR 0x08 + +/** + * \brief Mime Decoder Error Codes + */ +typedef enum MimeDecRetCode { + MIME_DEC_OK = 0, + MIME_DEC_MORE = 1, + MIME_DEC_ERR_DATA = -1, + MIME_DEC_ERR_MEM = -2, + MIME_DEC_ERR_PARSE = -3, + MIME_DEC_ERR_STATE = -4, /**< parser in error state */ + MIME_DEC_ERR_OVERFLOW = -5, +} MimeDecRetCode; + +/** + * \brief Structure for containing configuration options + * + */ +typedef struct MimeDecConfig { + bool decode_base64; /**< Decode base64 bodies */ + bool decode_quoted_printable; /**< Decode quoted-printable bodies */ + bool extract_urls; /**< Extract and store URLs in data structure */ + ConfNode *extract_urls_schemes; /**< List of schemes of which to + extract urls */ + bool log_url_scheme; /**< Log the scheme of extracted URLs */ + bool body_md5; /**< Compute md5 sum of body */ + uint32_t header_value_depth; /**< Depth of which to store header values + (Default is 2000) */ +} MimeDecConfig; + +/** + * \brief This represents a header field name and associated value + */ +typedef struct MimeDecField { + uint8_t *name; /**< Name of the header field */ + uint32_t name_len; /**< Length of the name */ + uint32_t value_len; /**< Length of the value */ + uint8_t *value; /**< Value of the header field */ + struct MimeDecField *next; /**< Pointer to next field */ +} MimeDecField; + +/** + * \brief This represents a URL value node in a linked list + * + * Since HTML can sometimes contain a high number of URLs, this + * structure only features the URL host name/IP or those that are + * pointing to an executable file (see url_flags to determine which). + */ +typedef struct MimeDecUrl { + uint8_t *url; /**< String representation of full or partial URL (lowercase) */ + uint32_t url_len; /**< Length of the URL string */ + uint32_t url_flags; /**< Flags indicating type of URL */ + struct MimeDecUrl *next; /**< Pointer to next URL */ +} MimeDecUrl; + +/** + * \brief This represents the MIME Entity (or also top level message) in a + * child-sibling tree + */ +typedef struct MimeDecEntity { + MimeDecField *field_list; /**< Pointer to list of header fields */ + MimeDecUrl *url_list; /**< Pointer to list of URLs */ + uint32_t header_flags; /**< Flags indicating header characteristics */ + uint32_t ctnt_flags; /**< Flags indicating type of content */ + uint32_t anomaly_flags; /**< Flags indicating an anomaly in the message */ + uint32_t filename_len; /**< Length of file attachment name */ + uint8_t *filename; /**< Name of file attachment */ + uint8_t *ctnt_type; /**< Quick access pointer to short-hand content type field */ + uint32_t ctnt_type_len; /**< Length of content type field value */ + uint32_t msg_id_len; /**< Quick access pointer to message Id */ + uint8_t *msg_id; /**< Quick access pointer to message Id */ + struct MimeDecEntity *next; /**< Pointer to list of sibling entities */ + struct MimeDecEntity *child; /**< Pointer to list of child entities */ + struct MimeDecEntity *last_child; /**< Pointer to tail of the list of child entities */ +} MimeDecEntity; + +/** + * \brief Structure contains boundary and entity for the current node (entity) + * in the stack + * + */ +typedef struct MimeDecStackNode { + MimeDecEntity *data; /**< Pointer to the entity data structure */ + uint8_t *bdef; /**< Copy of boundary definition for child entity */ + uint16_t bdef_len; /**< Boundary length for child entity */ + bool is_encap; /**< Flag indicating entity is encapsulated in message */ + struct MimeDecStackNode *next; /**< Pointer to next item on the stack */ +} MimeDecStackNode; + +/** + * \brief Structure holds the top of the stack along with some free reusable nodes + * + */ +typedef struct MimeDecStack { + MimeDecStackNode *top; /**< Pointer to the top of the stack */ + MimeDecStackNode *free_nodes; /**< Pointer to the list of free nodes */ + uint32_t free_nodes_cnt; /**< Count of free nodes in the list */ +} MimeDecStack; + +/** + * \brief Structure contains a list of value and lengths for robust data processing + * + */ +typedef struct DataValue { + uint8_t *value; /**< Copy of data value */ + uint32_t value_len; /**< Length of data value */ + struct DataValue *next; /**< Pointer to next value in the list */ +} DataValue; + +/** + * \brief Structure contains the current state of the MIME parser + * + */ +typedef struct MimeDecParseState { + MimeDecEntity *msg; /**< Pointer to the top-level message entity */ + MimeDecStack *stack; /**< Pointer to the top of the entity stack */ + uint8_t *hname; /**< Copy of the last known header name */ + uint32_t hlen; /**< Length of the last known header name */ + uint32_t hvlen; /**< Total length of value list */ + DataValue *hvalue; /**< Pointer to the incomplete header value list */ + uint8_t bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ + uint8_t bvr_len; /**< Length of remainder from base64-decoded line */ + uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */ + SCMd5 *md5_ctx; + uint8_t md5[SC_MD5_LEN]; + bool has_md5; + uint8_t state_flag; /**< Flag representing current state of parser */ + uint32_t data_chunk_len; /**< Length of data chunk */ + int found_child; /**< Flag indicating a child entity was found */ + int body_begin; /**< Currently at beginning of body */ + int body_end; /**< Currently at end of body */ + uint8_t current_line_delimiter_len; /**< Length of line delimiter */ + void *data; /**< Pointer to data specific to the caller */ + int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, + struct MimeDecParseState *state); /**< Data chunk processing function callback */ +} MimeDecParseState; + +/* Config functions */ +void MimeDecSetConfig(MimeDecConfig *config); +MimeDecConfig *MimeDecGetConfig(void); + +/* Memory functions */ +void MimeDecFreeEntity(MimeDecEntity *entity); +void MimeDecFreeField(MimeDecField *field); +void MimeDecFreeUrl(MimeDecUrl *url); + +/* List functions */ +MimeDecField *MimeDecAddField(MimeDecEntity *entity); +MimeDecField *MimeDecFindField(const MimeDecEntity *entity, const char *name); +int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, + int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data); +MimeDecEntity *MimeDecAddEntity(MimeDecEntity *parent); + +/* Helper functions */ +// MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, +// uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value); + +/* Parser functions */ +MimeDecParseState *MimeDecInitParser( + void *data, int (*dcpfunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); +void MimeDecDeInitParser(MimeDecParseState *state); +int MimeDecParseComplete(MimeDecParseState *state); +int MimeDecParseLine( + const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state); +MimeDecEntity *MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, + int (*DataChunkProcessorFunc)( + const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); +const char *MimeDecParseStateGetStatus(MimeDecParseState *state); + +/* Test functions */ +void MimeDecRegisterTests(void); + +#endif diff --git a/src/util/detect.c b/src/util/detect.c new file mode 100644 index 000000000000..b267bf76e4fe --- /dev/null +++ b/src/util/detect.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Giuseppe Longo + * + * Detection engine helper functions + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "../detect.h" +#include "util/detect.h" + +/** + * \brief Allocate SigString list member + * + * \retval Pointer to SigString + */ +SigString *SigStringAlloc(void) +{ + SigString *sigstr = SCCalloc(1, sizeof(SigString)); + if (unlikely(sigstr == NULL)) + return NULL; + + sigstr->line = 0; + + return sigstr; +} + +/** + * \brief Assigns the filename, signature, lineno to SigString list member + * + * \param sig pointer to SigString + * \param sig_file filename that contains the signature + * \param sig_str signature in string format + * \param sig_error signature parsing error + * \param line line line number + * + * \retval 1 on success 0 on failure + */ +static int SigStringAddSig( + SigString *sig, const char *sig_file, const char *sig_str, const char *sig_error, int line) +{ + if (sig_file == NULL || sig_str == NULL) { + return 0; + } + + sig->filename = SCStrdup(sig_file); + if (sig->filename == NULL) { + SCLogError("Error allocating memory"); + return 0; + } + + sig->sig_str = SCStrdup(sig_str); + if (sig->sig_str == NULL) { + SCLogError("Error allocating memory"); + SCFree(sig->filename); + return 0; + } + + if (sig_error) { + sig->sig_error = SCStrdup(sig_error); + if (sig->sig_error == NULL) { + SCLogError("Error allocating memory"); + SCFree(sig->filename); + SCFree(sig->sig_str); + return 0; + } + } + + sig->line = line; + + return 1; +} + +/** + * \brief Append a new list member to SigString list + * + * \param list pointer to the start of the SigString list + * \param sig_file filename that contains the signature + * \param sig_str signature in string format + * \param line line line number + * + * \retval 1 on success 0 on failure + */ +int SigStringAppend(SigFileLoaderStat *sig_stats, const char *sig_file, const char *sig_str, + const char *sig_error, int line) +{ + SigString *item = SigStringAlloc(); + if (item == NULL) { + return 0; + } + + if (!SigStringAddSig(item, sig_file, sig_str, sig_error, line)) { + SCFree(item); + return 0; + } + + TAILQ_INSERT_TAIL(&sig_stats->failed_sigs, item, next); + + return 1; +} diff --git a/src/util/detect.h b/src/util/detect.h new file mode 100644 index 000000000000..611d3ffce0f3 --- /dev/null +++ b/src/util/detect.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Giuseppe Longo + * + * Detection engine helper functions + */ + +SigString *SigStringAlloc(void); +int SigStringAppend(SigFileLoaderStat *sigs_stats, const char *sig_file, const char *sig_str, + const char *sig_error, int line); diff --git a/src/util/device.c b/src/util/device.c new file mode 100644 index 000000000000..b68346af6848 --- /dev/null +++ b/src/util/device.c @@ -0,0 +1,617 @@ +/* Copyright (C) 2011-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "../conf.h" +#include "util/device.h" +#include "util/ioctl.h" +#include "util/misc.h" +#include "util/dpdk.h" + +#include "device-storage.h" +#include "util/debug.h" + +#define MAX_DEVNAME 10 + +static LiveDevStorageId g_bypass_storage_id = { .id = -1 }; + +/** + * \file + * + * \author Eric Leblond + * + * \brief Utility functions to handle device list + */ + +/** private device list */ +static TAILQ_HEAD(, LiveDevice_) live_devices = TAILQ_HEAD_INITIALIZER(live_devices); + +/** List of the name of devices + * + * As we don't know the size of the Storage on devices + * before the parsing we need to wait and use this list + * to create later the LiveDevice via LiveDeviceFinalize() + */ +static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices = TAILQ_HEAD_INITIALIZER(pre_live_devices); + +typedef struct BypassInfo_ { + SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count); + SC_ATOMIC_DECLARE(uint64_t, ipv4_fail); + SC_ATOMIC_DECLARE(uint64_t, ipv4_success); + SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count); + SC_ATOMIC_DECLARE(uint64_t, ipv6_fail); + SC_ATOMIC_DECLARE(uint64_t, ipv6_success); +} BypassInfo; + +/** if set to 0 when we don't have real devices */ +static int live_devices_stats = 1; + +static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen); + +static int g_live_devices_disable_offloading = 1; + +void LiveSetOffloadDisable(void) +{ + g_live_devices_disable_offloading = 1; +} + +void LiveSetOffloadWarn(void) +{ + g_live_devices_disable_offloading = 0; +} + +int LiveGetOffload(void) +{ + return g_live_devices_disable_offloading; +} + +/** + * \brief Add a device for monitoring + * + * To be used during option parsing. When a device has + * to be created during runmode init, use LiveRegisterDevice() + * + * \param dev string with the device name + * + * \retval 0 on success. + * \retval -1 on failure. + */ +int LiveRegisterDeviceName(const char *dev) +{ + LiveDeviceName *pd = NULL; + + pd = SCCalloc(1, sizeof(LiveDeviceName)); + if (unlikely(pd == NULL)) { + return -1; + } + + pd->dev = SCStrdup(dev); + if (unlikely(pd->dev == NULL)) { + SCFree(pd); + return -1; + } + + TAILQ_INSERT_TAIL(&pre_live_devices, pd, next); + + SCLogDebug("Device \"%s\" registered.", dev); + return 0; +} + +/** + * \brief Add a pcap device for monitoring and create structure + * + * \param dev string with the device name + * + * \retval 0 on success. + * \retval -1 on failure. + */ +int LiveRegisterDevice(const char *dev) +{ + LiveDevice *pd = NULL; + + pd = SCCalloc(1, sizeof(LiveDevice) + LiveDevStorageSize()); + if (unlikely(pd == NULL)) { + return -1; + } + + int id = LiveGetDeviceCount(); + if (id > UINT16_MAX) { + SCFree(pd); + return -1; + } + + pd->dev = SCStrdup(dev); + if (unlikely(pd->dev == NULL)) { + SCFree(pd); + return -1; + } + /* create a short version to be used in thread names */ + LiveSafeDeviceName(pd->dev, pd->dev_short, sizeof(pd->dev_short)); + + SC_ATOMIC_INIT(pd->pkts); + SC_ATOMIC_INIT(pd->drop); + SC_ATOMIC_INIT(pd->invalid_checksums); + pd->id = (uint16_t)id; + TAILQ_INSERT_TAIL(&live_devices, pd, next); + + SCLogDebug("Device \"%s\" registered and created.", dev); + return 0; +} + +/** + * \brief Get the number of registered devices + * + * \retval cnt the number of registered devices + */ +int LiveGetDeviceCount(void) +{ + int i = 0; + LiveDevice *pd; + + TAILQ_FOREACH (pd, &live_devices, next) { + i++; + } + + return i; +} + +/** + * \brief Get a pointer to the device name at idx + * + * \param number idx of the device in our list + * + * \retval ptr pointer to the string containing the device + * \retval NULL on error + */ +const char *LiveGetDeviceName(int number) +{ + int i = 0; + LiveDevice *pd; + + TAILQ_FOREACH (pd, &live_devices, next) { + if (i == number) { + return pd->dev; + } + + i++; + } + + return NULL; +} + +/** \internal + * \brief Shorten a device name that is to long + * + * \param device name from config and destination for modified + * + * \retval None, is added to destination char *newdevname + */ +static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) +{ + const size_t devnamelen = strlen(devname); + + /* If we have to shorten the interface name */ + if (devnamelen > MAX_DEVNAME) { + /* special mode for DPDK pci addresses */ + if (devnamelen >= 5 && strncmp(devname, "0000:", 5) == 0) { + strlcpy(newdevname, devname + 5, destlen); + return 0; + } + + /* IF the dest length is over 10 chars long it will not do any + * good for the shortening. The shortening is done due to the + * max length of pthread names (15 chars) and we use 3 chars + * for the threadname indicator eg. "W#-" and one-two chars for + * the thread number. And if the destination buffer is under + * 6 chars there is no point in shortening it since we must at + * least enter two periods (.) into the string. + */ + if ((destlen - 1) > 10 || (destlen - 1) < 6) { + return 1; + } + + ShortenString(devname, newdevname, destlen, '.'); + + SCLogInfo("%s: shortening device name to %s", devname, newdevname); + } else { + strlcpy(newdevname, devname, destlen); + } + return 0; +} + +/** + * \brief Get a pointer to the device at idx + * + * \param number idx of the device in our list + * + * \retval ptr pointer to the string containing the device + * \retval NULL on error + */ +LiveDevice *LiveGetDevice(const char *name) +{ + LiveDevice *pd; + + if (name == NULL) { + SCLogWarning("Name of device should not be null"); + return NULL; + } + + TAILQ_FOREACH (pd, &live_devices, next) { + if (!strcmp(name, pd->dev)) { + return pd; + } + } + + return NULL; +} + +const char *LiveGetShortName(const char *dev) +{ + LiveDevice *live_dev = LiveGetDevice(dev); + if (live_dev == NULL) + return NULL; + return live_dev->dev_short; +} + +int LiveBuildDeviceList(const char *runmode) +{ + return LiveBuildDeviceListCustom(runmode, "interface"); +} + +int LiveBuildDeviceListCustom(const char *runmode, const char *itemname) +{ + ConfNode *base = ConfGetNode(runmode); + ConfNode *child; + int i = 0; + + if (base == NULL) + return 0; + + TAILQ_FOREACH (child, &base->head, next) { + ConfNode *subchild; + TAILQ_FOREACH (subchild, &child->head, next) { + if ((!strcmp(subchild->name, itemname))) { + if (!strcmp(subchild->val, "default")) + break; + SCLogConfig("Adding %s %s from config file", itemname, subchild->val); + LiveRegisterDeviceName(subchild->val); + i++; + } + } + } + + return i; +} + +/** Call this function to disable stat on live devices + * + * This can be useful in the case, this is not a real interface. + */ +void LiveDeviceHasNoStats(void) +{ + live_devices_stats = 0; +} + +int LiveDeviceListClean(void) +{ + SCEnter(); + LiveDevice *pd, *tpd; + + /* dpdk: need to close all devices before freeing them. */ + TAILQ_FOREACH (pd, &live_devices, next) { + DPDKCloseDevice(pd); + } + TAILQ_FOREACH_SAFE (pd, &live_devices, next, tpd) { + if (live_devices_stats) { + SCLogNotice("%s: packets: %" PRIu64 ", drops: %" PRIu64 + " (%.2f%%), invalid chksum: %" PRIu64, + pd->dev, SC_ATOMIC_GET(pd->pkts), SC_ATOMIC_GET(pd->drop), + SC_ATOMIC_GET(pd->pkts) > 0 ? 100 * ((double)SC_ATOMIC_GET(pd->drop)) / + (double)SC_ATOMIC_GET(pd->pkts) + : 0, + SC_ATOMIC_GET(pd->invalid_checksums)); + } + + RestoreIfaceOffloading(pd); + DPDKFreeDevice(pd); + + if (pd->dev) + SCFree(pd->dev); + LiveDevFreeStorage(pd); + SCFree(pd); + } + + SCReturnInt(TM_ECODE_OK); +} + +#ifdef BUILD_UNIX_SOCKET +TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *answer, void *data) +{ + SCEnter(); + LiveDevice *pd; + const char *name = NULL; + json_t *jarg = json_object_get(cmd, "iface"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("Iface is not a string")); + SCReturnInt(TM_ECODE_FAILED); + } + name = json_string_value(jarg); + if (name == NULL) { + json_object_set_new(answer, "message", json_string("Iface name is NULL")); + SCReturnInt(TM_ECODE_FAILED); + } + + TAILQ_FOREACH (pd, &live_devices, next) { + if (!strcmp(name, pd->dev)) { + json_t *jdata = json_object(); + if (jdata == NULL) { + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); + SCReturnInt(TM_ECODE_FAILED); + } + json_object_set_new(jdata, "pkts", json_integer(SC_ATOMIC_GET(pd->pkts))); + json_object_set_new( + jdata, "invalid-checksums", json_integer(SC_ATOMIC_GET(pd->invalid_checksums))); + json_object_set_new(jdata, "drop", json_integer(SC_ATOMIC_GET(pd->drop))); + json_object_set_new(jdata, "bypassed", json_integer(SC_ATOMIC_GET(pd->bypassed))); + json_object_set_new(answer, "message", jdata); + SCReturnInt(TM_ECODE_OK); + } + } + json_object_set_new(answer, "message", json_string("Iface does not exist")); + SCReturnInt(TM_ECODE_FAILED); +} + +TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *answer, void *data) +{ + SCEnter(); + json_t *jdata; + json_t *jarray; + LiveDevice *pd; + int i = 0; + + jdata = json_object(); + if (jdata == NULL) { + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); + return TM_ECODE_FAILED; + } + jarray = json_array(); + if (jarray == NULL) { + json_object_set_new( + answer, "message", json_string("internal error at json object creation")); + return TM_ECODE_FAILED; + } + TAILQ_FOREACH (pd, &live_devices, next) { + json_array_append_new(jarray, json_string(pd->dev)); + i++; + } + + json_object_set_new(jdata, "count", json_integer(i)); + json_object_set_new(jdata, "ifaces", jarray); + json_object_set_new(answer, "message", jdata); + SCReturnInt(TM_ECODE_OK); +} + +#endif /* BUILD_UNIX_SOCKET */ + +LiveDevice *LiveDeviceForEach(LiveDevice **ldev, LiveDevice **ndev) +{ + if (*ldev == NULL) { + *ldev = TAILQ_FIRST(&live_devices); + *ndev = TAILQ_NEXT(*ldev, next); + return *ldev; + } else { + *ldev = *ndev; + if (*ldev) { + *ndev = TAILQ_NEXT(*ldev, next); + } + return *ldev; + } + return NULL; +} + +/** + * Create registered devices + * + * This function creates all needed LiveDevice from + * the LiveDeviceName list created via LiveRegisterDevice() + */ +void LiveDeviceFinalize(void) +{ + LiveDeviceName *ld, *pld; + SCLogDebug("Finalize live device"); + /* Iter on devices and register them */ + TAILQ_FOREACH_SAFE (ld, &pre_live_devices, next, pld) { + if (ld->dev) { + LiveRegisterDevice(ld->dev); + SCFree(ld->dev); + } + SCFree(ld); + } +} + +static void LiveDevExtensionFree(void *x) +{ + if (x) + SCFree(x); +} + +/** + * Register bypass stats storage + */ +void LiveDevRegisterExtension(void) +{ + g_bypass_storage_id = + LiveDevStorageRegister("bypass_stats", sizeof(void *), NULL, LiveDevExtensionFree); +} + +/** + * Prepare a LiveDevice so we can set bypass stats + */ +int LiveDevUseBypass(LiveDevice *dev) +{ + BypassInfo *bpinfo = SCCalloc(1, sizeof(*bpinfo)); + if (bpinfo == NULL) { + SCLogError("Can't allocate bypass info structure"); + return -1; + } + + SC_ATOMIC_INIT(bpinfo->ipv4_hash_count); + SC_ATOMIC_INIT(bpinfo->ipv4_hash_count); + + LiveDevSetStorageById(dev, g_bypass_storage_id, bpinfo); + return 0; +} + +/** + * Set number of currently bypassed flows for a protocol family + * + * \param dev pointer to LiveDevice to set stats for + * \param cnt number of currently bypassed flows + * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count + */ +void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family) +{ + BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); + if (bpfdata) { + if (family == AF_INET) { + SC_ATOMIC_SET(bpfdata->ipv4_hash_count, cnt); + } else if (family == AF_INET6) { + SC_ATOMIC_SET(bpfdata->ipv6_hash_count, cnt); + } + } +} + +/** + * Increase number of currently bypassed flows for a protocol family + * + * \param dev pointer to LiveDevice to set stats for + * \param cnt number of flows to add + * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count + */ +void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family) +{ + BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); + if (bpfdata) { + if (family == AF_INET) { + SC_ATOMIC_ADD(bpfdata->ipv4_hash_count, cnt); + } else if (family == AF_INET6) { + SC_ATOMIC_ADD(bpfdata->ipv6_hash_count, cnt); + } + } +} + +/** + * Decrease number of currently bypassed flows for a protocol family + * + * \param dev pointer to LiveDevice to set stats for + * \param cnt number of flows to remove + * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count + */ +void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family) +{ + BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); + if (bpfdata) { + if (family == AF_INET) { + SC_ATOMIC_SUB(bpfdata->ipv4_hash_count, cnt); + } else if (family == AF_INET6) { + SC_ATOMIC_SUB(bpfdata->ipv6_hash_count, cnt); + } + } +} + +/** + * Increase number of failed captured flows for a protocol family + * + * \param dev pointer to LiveDevice to set stats for + * \param cnt number of flows to add + * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count + */ +void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family) +{ + BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); + if (bpfdata) { + if (family == AF_INET) { + SC_ATOMIC_ADD(bpfdata->ipv4_fail, cnt); + } else if (family == AF_INET6) { + SC_ATOMIC_ADD(bpfdata->ipv6_fail, cnt); + } + } +} + +/** + * Increase number of currently successfully bypassed flows for a protocol family + * + * \param dev pointer to LiveDevice to set stats for + * \param cnt number of flows to add + * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count + */ +void LiveDevAddBypassSuccess(LiveDevice *dev, uint64_t cnt, int family) +{ + BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); + if (bpfdata) { + if (family == AF_INET) { + SC_ATOMIC_ADD(bpfdata->ipv4_success, cnt); + } else if (family == AF_INET6) { + SC_ATOMIC_ADD(bpfdata->ipv6_success, cnt); + } + } +} + +#ifdef BUILD_UNIX_SOCKET +TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data) +{ + LiveDevice *ldev = NULL, *ndev = NULL; + + json_t *ifaces = NULL; + while (LiveDeviceForEach(&ldev, &ndev)) { + BypassInfo *bpinfo = LiveDevGetStorageById(ldev, g_bypass_storage_id); + if (bpinfo) { + uint64_t ipv4_hash_count = SC_ATOMIC_GET(bpinfo->ipv4_hash_count); + uint64_t ipv6_hash_count = SC_ATOMIC_GET(bpinfo->ipv6_hash_count); + uint64_t ipv4_success = SC_ATOMIC_GET(bpinfo->ipv4_success); + uint64_t ipv4_fail = SC_ATOMIC_GET(bpinfo->ipv4_fail); + uint64_t ipv6_success = SC_ATOMIC_GET(bpinfo->ipv6_success); + uint64_t ipv6_fail = SC_ATOMIC_GET(bpinfo->ipv6_fail); + json_t *iface = json_object(); + if (ifaces == NULL) { + ifaces = json_object(); + if (ifaces == NULL) { + json_object_set_new(answer, "message", + json_string("internal error at json object creation")); + return TM_ECODE_FAILED; + } + } + json_object_set_new(iface, "ipv4_maps_count", json_integer(ipv4_hash_count)); + json_object_set_new(iface, "ipv4_success", json_integer(ipv4_success)); + json_object_set_new(iface, "ipv4_fail", json_integer(ipv4_fail)); + json_object_set_new(iface, "ipv6_maps_count", json_integer(ipv6_hash_count)); + json_object_set_new(iface, "ipv6_success", json_integer(ipv6_success)); + json_object_set_new(iface, "ipv6_fail", json_integer(ipv6_fail)); + json_object_set_new(ifaces, ldev->dev, iface); + } + } + if (ifaces) { + json_object_set_new(answer, "message", ifaces); + SCReturnInt(TM_ECODE_OK); + } + + json_object_set_new(answer, "message", json_string("No interface using bypass")); + SCReturnInt(TM_ECODE_FAILED); +} +#endif diff --git a/src/util/device.h b/src/util/device.h new file mode 100644 index 000000000000..1f2af8ee1340 --- /dev/null +++ b/src/util/device.h @@ -0,0 +1,108 @@ +/* Copyright (C) 2011-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_DEVICE_H__ +#define __UTIL_DEVICE_H__ + +#ifdef HAVE_DPDK +#include +#endif /* HAVE_DPDK */ + +#include "queue.h" +#include "util/storage.h" + +#define OFFLOAD_FLAG_SG (1 << 0) +#define OFFLOAD_FLAG_TSO (1 << 1) +#define OFFLOAD_FLAG_GSO (1 << 2) +#define OFFLOAD_FLAG_GRO (1 << 3) +#define OFFLOAD_FLAG_LRO (1 << 4) +#define OFFLOAD_FLAG_RXCSUM (1 << 5) +#define OFFLOAD_FLAG_TXCSUM (1 << 6) +#define OFFLOAD_FLAG_TOE (1 << 7) + +void LiveSetOffloadDisable(void); +void LiveSetOffloadWarn(void); +int LiveGetOffload(void); + +#define MAX_DEVNAME 10 + +#ifdef HAVE_DPDK +typedef struct { + struct rte_mempool *pkt_mp; +} DPDKDeviceResources; +#endif /* HAVE_DPDK */ + +/** storage for live device names */ +typedef struct LiveDevice_ { + char *dev; /**< the device (e.g. "eth0") */ + char dev_short[MAX_DEVNAME + 1]; + int mtu; /* MTU of the device */ + bool tenant_id_set; + + uint16_t id; + + SC_ATOMIC_DECLARE(uint64_t, pkts); + SC_ATOMIC_DECLARE(uint64_t, drop); + SC_ATOMIC_DECLARE(uint64_t, bypassed); + SC_ATOMIC_DECLARE(uint64_t, invalid_checksums); + TAILQ_ENTRY(LiveDevice_) next; + + uint32_t tenant_id; /**< tenant id in multi-tenancy */ + uint32_t offload_orig; /**< original offload settings to restore @exit */ +#ifdef HAVE_DPDK + // DPDK resources that needs to be cleaned after workers are stopped and devices closed + DPDKDeviceResources dpdk_vars; +#endif + /** storage handle as a flex array member */ + Storage storage[]; +} LiveDevice; + +typedef struct LiveDeviceName_ { + char *dev; /**< the device (e.g. "eth0") */ + TAILQ_ENTRY(LiveDeviceName_) next; +} LiveDeviceName; + +void LiveDevRegisterExtension(void); + +int LiveRegisterDeviceName(const char *dev); +int LiveRegisterDevice(const char *dev); +int LiveDevUseBypass(LiveDevice *dev); +void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family); +void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family); +void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family); +void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family); +void LiveDevAddBypassSuccess(LiveDevice *dev, uint64_t cnt, int family); +int LiveGetDeviceCount(void); +const char *LiveGetDeviceName(int number); +LiveDevice *LiveGetDevice(const char *dev); +const char *LiveGetShortName(const char *dev); +int LiveBuildDeviceList(const char *base); +void LiveDeviceHasNoStats(void); +int LiveDeviceListClean(void); +int LiveBuildDeviceListCustom(const char *base, const char *itemname); + +LiveDevice *LiveDeviceForEach(LiveDevice **ldev, LiveDevice **ndev); + +void LiveDeviceFinalize(void); + +#ifdef BUILD_UNIX_SOCKET +TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *server_msg, void *data); +TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *server_msg, void *data); +TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data); +#endif + +#endif /* __UTIL_DEVICE_H__ */ diff --git a/src/util/dpdk-bonding.c b/src/util/dpdk-bonding.c new file mode 100644 index 000000000000..03ecbbc5c1b0 --- /dev/null +++ b/src/util/dpdk-bonding.c @@ -0,0 +1,125 @@ +/* Copyright (C) 2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Lukas Sismis + */ + +#ifndef UTIL_DPDK_BONDING_C +#define UTIL_DPDK_BONDING_C + +#include "suricata-common.h" +#include "util/dpdk-bonding.h" + +#ifdef HAVE_DPDK + +#include "util/dpdk.h" +#include "util/debug.h" + +/** + * Determines if the port is Bond or not by evaluating device driver name + * @param pid port ID + * @return 0 - the device si Bond PMD, 1 - regular device, <0 error + */ +int32_t BondingIsBond(uint16_t pid) +{ + struct rte_eth_dev_info di; + int32_t ret = rte_eth_dev_info_get(pid, &di); + if (ret < 0) { + SCLogError("%s: unable to get device info (err: %s)", DPDKGetPortNameByPortID(pid), + rte_strerror(-ret)); + return ret; + } + + return strcmp(di.driver_name, "net_bonding") == 0 ? 0 : 1; +} + +uint16_t BondingMemberDevicesGet( + uint16_t bond_pid, uint16_t bonded_devs[], uint16_t bonded_devs_length) +{ +#ifdef HAVE_DPDK_BOND +#if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0) + int32_t len = rte_eth_bond_members_get(bond_pid, bonded_devs, bonded_devs_length); +#else + int32_t len = rte_eth_bond_slaves_get(bond_pid, bonded_devs, bonded_devs_length); +#endif /* RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0) */ + + if (len == 0) + FatalError("%s: no bonded devices found", DPDKGetPortNameByPortID(bond_pid)); + else if (len < 0) + FatalError("%s: unable to get bonded devices (err: %s)", DPDKGetPortNameByPortID(bond_pid), + rte_strerror(-len)); + + return len; +#else + FatalError( + "%s: bond port not supported in DPDK installation", DPDKGetPortNameByPortID(bond_pid)); +#endif +} + +int32_t BondingAllDevicesSameDriver(uint16_t bond_pid) +{ + uint16_t bonded_devs[RTE_MAX_ETHPORTS] = { 0 }; + uint16_t len = BondingMemberDevicesGet(bond_pid, bonded_devs, RTE_MAX_ETHPORTS); + + const char *driver_name = NULL, *first_driver_name = NULL; + struct rte_eth_dev_info di = { 0 }; + + for (uint16_t i = 0; i < len; i++) { + int32_t ret = rte_eth_dev_info_get(bonded_devs[i], &di); + if (ret < 0) + FatalError("%s: unable to get device info (err: %s)", + DPDKGetPortNameByPortID(bonded_devs[i]), rte_strerror(-ret)); + + if (i == 0) { + first_driver_name = di.driver_name; + } else { + driver_name = di.driver_name; + if (strncmp(first_driver_name, driver_name, + MIN(strlen(first_driver_name), strlen(driver_name))) != 0) { + return -EINVAL; // inconsistent drivers + } + } + } + + return 0; +} + +/** + * Translates to the driver that is actually used by the bonded ports + * \param bond_pid + * \return driver name, FatalError otherwise + */ +const char *BondingDeviceDriverGet(uint16_t bond_pid) +{ + uint16_t bonded_devs[RTE_MAX_ETHPORTS] = { 0 }; + BondingMemberDevicesGet(bond_pid, bonded_devs, RTE_MAX_ETHPORTS); + + struct rte_eth_dev_info di = { 0 }; + int32_t ret = rte_eth_dev_info_get(bonded_devs[0], &di); + if (ret < 0) + FatalError("%s: unable to get device info (err: %s)", + DPDKGetPortNameByPortID(bonded_devs[0]), rte_strerror(-ret)); + + return di.driver_name; +} + +#endif /* HAVE_DPDK */ + +#endif /* UTIL_DPDK_BONDING_C */ diff --git a/src/util-dpdk-bonding.h b/src/util/dpdk-bonding.h similarity index 100% rename from src/util-dpdk-bonding.h rename to src/util/dpdk-bonding.h diff --git a/src/util/dpdk-i40e.c b/src/util/dpdk-i40e.c new file mode 100644 index 000000000000..f1cf3f669060 --- /dev/null +++ b/src/util/dpdk-i40e.c @@ -0,0 +1,416 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \defgroup dpdk DPDK Intel I40E driver helpers functions + * + * @{ + */ + +/** + * \file + * + * \author Lukas Sismis + * + * DPDK driver's helper functions + * + */ + +#include "util/dpdk-i40e.h" +#include "util/dpdk.h" +#include "util/debug.h" +#include "util/dpdk-bonding.h" + +#ifdef HAVE_DPDK + +#define I40E_RSS_HKEY_LEN 52 + +#if RTE_VERSION < RTE_VERSION_NUM(20, 0, 0, 0) +static int i40eDeviceEnableSymHash( + int port_id, const char *port_name, uint32_t ftype, enum rte_eth_hash_function function) +{ + struct rte_eth_hash_filter_info info; + int retval; + uint32_t idx, offset; + + memset(&info, 0, sizeof(info)); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + retval = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_HASH); +#pragma GCC diagnostic pop + if (retval < 0) { + SCLogError("RTE_ETH_FILTER_HASH not supported on port: %s", port_name); + return retval; + } + + info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG; + info.info.global_conf.hash_func = function; + + idx = ftype / UINT64_BIT; + offset = ftype % UINT64_BIT; + info.info.global_conf.valid_bit_mask[idx] |= (1ULL << offset); + info.info.global_conf.sym_hash_enable_mask[idx] |= (1ULL << offset); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + retval = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH, RTE_ETH_FILTER_SET, &info); +#pragma GCC diagnostic pop + + if (retval < 0) { + SCLogError("Cannot set global hash configurations on port %s", port_name); + return retval; + } + + return 0; +} + +static int i40eDeviceSetSymHash(int port_id, const char *port_name, int enable) +{ + int ret; + struct rte_eth_hash_filter_info info; + + memset(&info, 0, sizeof(info)); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_HASH); +#pragma GCC diagnostic pop + + if (ret < 0) { + SCLogError("RTE_ETH_FILTER_HASH not supported on port: %s", port_name); + return ret; + } + + info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT; + info.info.enable = enable; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH, RTE_ETH_FILTER_SET, &info); +#pragma GCC diagnostic pop + + if (ret < 0) { + SCLogError("Cannot set symmetric hash enable per port on port %s", port_name); + return ret; + } + + return 0; +} + +static int i40eDeviceApplyRSSFilter(int port_id, const char *port_name) +{ + int retval = 0; + + // Behavior of RTE_FLOW in DPDK version 19.xx and less is different than on versions + // above. For that reason RSS on i40e driver is set differently. + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_FRAG_IPV4, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_FRAG_IPV6, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_TCP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_SCTP, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + retval |= i40eDeviceEnableSymHash( + port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, RTE_ETH_HASH_FUNCTION_TOEPLITZ); + + retval |= i40eDeviceSetSymHash(port_id, port_name, 1); + return retval; +} + +static int32_t i40eDeviceSetRSSWithFilter(int port_id, const char *port_name) +{ + int32_t ret = BondingIsBond(port_id); + if (ret < 0) + return -ret; + + if (ret == 1) { // regular device + i40eDeviceApplyRSSFilter(port_id, port_name); + } else if (ret == 0) { // the device is Bond PMD + uint16_t bonded_devs[RTE_MAX_ETHPORTS]; + ret = BondingMemberDevicesGet(port_id, bonded_devs, RTE_MAX_ETHPORTS); + for (int i = 0; i < ret; i++) { + i40eDeviceApplyRSSFilter(bonded_devs[i], port_name); + } + } else { + FatalError("Unknown return value from BondingIsBond()"); + } + + return 0; +} + +#else + +static int i40eDeviceSetRSSFlowQueues( + int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf, int nb_rx_queues) +{ + struct rte_flow_action_rss rss_action_conf = { 0 }; + struct rte_flow_attr attr = { 0 }; + struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } }; + struct rte_flow_action action[] = { { 0 }, { 0 } }; + struct rte_flow *flow; + struct rte_flow_error flow_error = { 0 }; + uint16_t queues[RTE_MAX_QUEUES_PER_PORT]; + + for (int i = 0; i < nb_rx_queues; ++i) + queues[i] = i; + + rss_action_conf.func = RTE_ETH_HASH_FUNCTION_DEFAULT; + rss_action_conf.level = 0; + rss_action_conf.types = 0; // queues region can not be configured with types + rss_action_conf.key_len = 0; + rss_action_conf.key = NULL; + + if (nb_rx_queues < 1) { + FatalError("The number of queues for RSS configuration must be " + "configured with a positive number"); + } + + rss_action_conf.queue_num = nb_rx_queues; + rss_action_conf.queue = queues; + + attr.ingress = 1; + pattern[0].type = RTE_FLOW_ITEM_TYPE_END; + action[0].type = RTE_FLOW_ACTION_TYPE_RSS; + action[0].conf = &rss_action_conf; + action[1].type = RTE_FLOW_ACTION_TYPE_END; + + flow = rte_flow_create(port_id, &attr, pattern, action, &flow_error); + if (flow == NULL) { + SCLogError("Error when creating rte_flow rule on %s: %s", port_name, flow_error.message); + int ret = rte_flow_validate(port_id, &attr, pattern, action, &flow_error); + SCLogError("Error on rte_flow validation for port %s: %s errmsg: %s", port_name, + rte_strerror(-ret), flow_error.message); + return ret; + } else { + SCLogInfo("RTE_FLOW queue region created for port %s", port_name); + } + return 0; +} + +static int i40eDeviceCreateRSSFlow(int port_id, const char *port_name, + struct rte_eth_rss_conf rss_conf, uint64_t rss_type, struct rte_flow_item *pattern) +{ + struct rte_flow_action_rss rss_action_conf = { 0 }; + struct rte_flow_attr attr = { 0 }; + struct rte_flow_action action[] = { { 0 }, { 0 } }; + struct rte_flow *flow; + struct rte_flow_error flow_error = { 0 }; + + rss_action_conf.func = RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ; + rss_action_conf.level = 0; + rss_action_conf.types = rss_type; + rss_action_conf.key_len = rss_conf.rss_key_len; + rss_action_conf.key = rss_conf.rss_key; + rss_action_conf.queue_num = 0; + rss_action_conf.queue = NULL; + + attr.ingress = 1; + action[0].type = RTE_FLOW_ACTION_TYPE_RSS; + action[0].conf = &rss_action_conf; + action[1].type = RTE_FLOW_ACTION_TYPE_END; + + flow = rte_flow_create(port_id, &attr, pattern, action, &flow_error); + if (flow == NULL) { + SCLogError("Error when creating rte_flow rule on %s: %s", port_name, flow_error.message); + int ret = rte_flow_validate(port_id, &attr, pattern, action, &flow_error); + SCLogError("Error on rte_flow validation for port %s: %s errmsg: %s", port_name, + rte_strerror(-ret), flow_error.message); + return ret; + } else { + SCLogInfo("RTE_FLOW flow rule created for port %s", port_name); + } + + return 0; +} + +static int i40eDeviceSetRSSFlowIPv4( + int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf) +{ + int ret = 0; + struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } }; + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; + pattern[2].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_OTHER, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; + pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP; + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_UDP, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; + pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP; + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_TCP, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; + pattern[2].type = RTE_FLOW_ITEM_TYPE_SCTP; + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV4_SCTP, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; + pattern[2].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, RTE_ETH_RSS_FRAG_IPV4, pattern); + + return ret; +} + +static int i40eDeviceSetRSSFlowIPv6( + int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf) +{ + int ret = 0; + struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } }; + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; + pattern[2].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_OTHER, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; + pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP; + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_UDP, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; + pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP; + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_TCP, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; + pattern[2].type = RTE_FLOW_ITEM_TYPE_SCTP; + pattern[3].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow( + port_id, port_name, rss_conf, RTE_ETH_RSS_NONFRAG_IPV6_SCTP, pattern); + memset(pattern, 0, sizeof(pattern)); + + pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; + pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6; + pattern[2].type = RTE_FLOW_ITEM_TYPE_END; + ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, RTE_ETH_RSS_FRAG_IPV6, pattern); + + return ret; +} + +static int i40eDeviceSetRSSWithFlows(int port_id, const char *port_name, int nb_rx_queues) +{ + int retval; + uint8_t rss_key[I40E_RSS_HKEY_LEN]; + struct rte_flow_error flush_error = { 0 }; + struct rte_eth_rss_conf rss_conf = { + .rss_key = rss_key, + .rss_key_len = I40E_RSS_HKEY_LEN, + }; + + retval = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf); + if (retval != 0) { + SCLogError("Unable to get RSS hash configuration of port %s", port_name); + return retval; + } + + retval = 0; + retval |= i40eDeviceSetRSSFlowQueues(port_id, port_name, rss_conf, nb_rx_queues); + retval |= i40eDeviceSetRSSFlowIPv4(port_id, port_name, rss_conf); + retval |= i40eDeviceSetRSSFlowIPv6(port_id, port_name, rss_conf); + if (retval != 0) { + retval = rte_flow_flush(port_id, &flush_error); + if (retval != 0) { + SCLogError("Unable to flush rte_flow rules of %s: %s Flush error msg: %s", port_name, + rte_strerror(-retval), flush_error.message); + } + return retval; + } + + return 0; +} + +#endif /* RTE_VERSION < RTE_VERSION_NUM(20,0,0,0) */ + +int i40eDeviceSetRSS(int port_id, int nb_rx_queues) +{ + int retval; + (void)nb_rx_queues; // avoid unused variable warnings + char port_name[RTE_ETH_NAME_MAX_LEN]; + + retval = rte_eth_dev_get_name_by_port(port_id, port_name); + if (unlikely(retval != 0)) { + SCLogError("Failed to convert port id %d to the interface name: %s", port_id, + strerror(-retval)); + return retval; + } + +#if RTE_VERSION >= RTE_VERSION_NUM(20, 0, 0, 0) + i40eDeviceSetRSSWithFlows(port_id, port_name, nb_rx_queues); +#else + i40eDeviceSetRSSWithFilter(port_id, port_name); +#endif + return 0; +} + +void i40eDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf) +{ +#if RTE_VERSION >= RTE_VERSION_NUM(20, 0, 0, 0) + rss_conf->rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | + RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_OTHER; + rss_conf->rss_key = NULL; + rss_conf->rss_key_len = 0; +#else + rss_conf->rss_hf = + RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV4_UDP | + RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 | + RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_NONFRAG_IPV6_UDP | + RTE_ETH_RSS_NONFRAG_IPV6_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_OTHER | RTE_ETH_RSS_SCTP; +#endif +} + +#endif /* HAVE_DPDK */ +/** + * @} + */ diff --git a/src/util/dpdk-i40e.h b/src/util/dpdk-i40e.h new file mode 100644 index 000000000000..af47a99d93bb --- /dev/null +++ b/src/util/dpdk-i40e.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Lukas Sismis + */ + +#ifndef UTIL_DPDK_I40E_H +#define UTIL_DPDK_I40E_H + +#include "suricata-common.h" + +#ifdef HAVE_DPDK + +#include "util/dpdk.h" + +int i40eDeviceSetRSS(int port_id, int nb_rx_queues); +void i40eDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf); + +#endif /* HAVE_DPDK */ + +#endif /* UTIL_DPDK_I40E_H */ diff --git a/src/util/dpdk-ice.c b/src/util/dpdk-ice.c new file mode 100644 index 000000000000..0f316beb96e2 --- /dev/null +++ b/src/util/dpdk-ice.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \defgroup dpdk DPDK Intel ICE driver helpers functions + * + * @{ + */ + +/** + * \file + * + * \author Lukas Sismis + * + * DPDK driver's helper functions + * + */ + +#include "util/dpdk-ice.h" +#include "util/dpdk.h" + +#ifdef HAVE_DPDK + +void iceDeviceSetRSSHashFunction(uint64_t *rss_hf) +{ +#if RTE_VERSION < RTE_VERSION_NUM(20, 0, 0, 0) + *rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 | + RTE_ETH_RSS_NONFRAG_IPV6_OTHER; +#else + *rss_hf = RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | + RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_OTHER; +#endif +} + +#endif /* HAVE_DPDK */ +/** + * @} + */ diff --git a/src/util-dpdk-ice.h b/src/util/dpdk-ice.h similarity index 100% rename from src/util-dpdk-ice.h rename to src/util/dpdk-ice.h diff --git a/src/util/dpdk-ixgbe.c b/src/util/dpdk-ixgbe.c new file mode 100644 index 000000000000..c0c74a6f3645 --- /dev/null +++ b/src/util/dpdk-ixgbe.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \defgroup dpdk DPDK Intel IXGBE driver helpers functions + * + * @{ + */ + +/** + * \file + * + * \author Lukas Sismis + * + * DPDK driver's helper functions + * + */ + +#include "util/dpdk-ixgbe.h" +#include "util/dpdk.h" + +#ifdef HAVE_DPDK + +void ixgbeDeviceSetRSSHashFunction(uint64_t *rss_hf) +{ + *rss_hf = RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_IPV6_EX; +} + +#endif /* HAVE_DPDK */ +/** + * @} + */ diff --git a/src/util-dpdk-ixgbe.h b/src/util/dpdk-ixgbe.h similarity index 100% rename from src/util-dpdk-ixgbe.h rename to src/util/dpdk-ixgbe.h diff --git a/src/util/dpdk.c b/src/util/dpdk.c new file mode 100644 index 000000000000..76bfb638981c --- /dev/null +++ b/src/util/dpdk.c @@ -0,0 +1,185 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Lukas Sismis + */ + +#include "suricata.h" +#include "util/dpdk.h" +#include "util/debug.h" +#include "util/byte.h" + +void DPDKCleanupEAL(void) +{ +#ifdef HAVE_DPDK + if (run_mode == RUNMODE_DPDK) { + int retval = rte_eal_cleanup(); + if (retval != 0) + SCLogError("EAL cleanup failed: %s", strerror(-retval)); + } +#endif +} + +void DPDKCloseDevice(LiveDevice *ldev) +{ + (void)ldev; // avoid warnings of unused variable +#ifdef HAVE_DPDK + if (run_mode == RUNMODE_DPDK) { + uint16_t port_id; + int retval = rte_eth_dev_get_port_by_name(ldev->dev, &port_id); + if (retval < 0) { + SCLogError("%s: failed get port id, error: %s", ldev->dev, rte_strerror(-retval)); + return; + } + + SCLogPerf("%s: closing device", ldev->dev); + rte_eth_dev_close(port_id); + } +#endif +} + +void DPDKFreeDevice(LiveDevice *ldev) +{ + (void)ldev; // avoid warnings of unused variable +#ifdef HAVE_DPDK + if (run_mode == RUNMODE_DPDK) { + SCLogDebug("%s: releasing packet mempool", ldev->dev); + rte_mempool_free(ldev->dpdk_vars.pkt_mp); + } +#endif +} + +static FILE *HugepagesMeminfoOpen(void) +{ + FILE *fp = fopen("/proc/meminfo", "r"); + if (fp == NULL) { + SCLogInfo("Can't analyze hugepage usage: failed to open /proc/meminfo"); + } + return fp; +} + +static void HugepagesMeminfoClose(FILE *fp) +{ + if (fp) { + fclose(fp); + } +} + +/** + * Parsing values of meminfo + * + * \param fp Opened file pointer for reading of file /proc/meminfo at beginning + * \param keyword Entry to look for e.g. "HugePages_Free:" + * \return n Value of the entry + * \return -1 On error + * + */ +static int32_t MemInfoParseValue(FILE *fp, const char *keyword) +{ + char path[256], value_str[64]; + int32_t value = -1; + + while (fscanf(fp, "%255s", path) != EOF) { + if (strcmp(path, keyword) == 0) { + if (fscanf(fp, "%63s", value_str) == EOF) { + SCLogDebug("%s: not followed by any number", keyword); + break; + } + + if (StringParseInt32(&value, 10, 23, value_str) < 0) { + SCLogDebug("Failed to convert %s from /proc/meminfo", keyword); + value = -1; + } + break; + } + } + return value; +} + +static void MemInfoEvaluateHugepages(FILE *fp) +{ + int32_t free_hugepages = MemInfoParseValue(fp, "HugePages_Free:"); + if (free_hugepages < 0) { + SCLogInfo("HugePages_Free information not found in /proc/meminfo"); + return; + } + + rewind(fp); + + int32_t total_hugepages = MemInfoParseValue(fp, "HugePages_Total:"); + if (total_hugepages < 0) { + SCLogInfo("HugePages_Total information not found in /proc/meminfo"); + return; + } else if (total_hugepages == 0) { + SCLogInfo("HugePages_Total equals to zero"); + return; + } + + float free_hugepages_ratio = (float)free_hugepages / (float)total_hugepages; + if (free_hugepages_ratio > 0.5) { + SCLogInfo("%" PRIu32 " of %" PRIu32 + " of hugepages are free - number of hugepages can be lowered to e.g. %.0lf", + free_hugepages, total_hugepages, ceil((total_hugepages - free_hugepages) * 1.15)); + } +} + +static void MemInfoWith(void (*callback)(FILE *)) +{ + FILE *fp = HugepagesMeminfoOpen(); + if (fp) { + callback(fp); + HugepagesMeminfoClose(fp); + } +} + +void DPDKEvaluateHugepages(void) +{ + if (run_mode != RUNMODE_DPDK) + return; + +#ifdef HAVE_DPDK + if (rte_eal_has_hugepages() == 0) { // hugepages disabled + SCLogPerf("Hugepages not enabled - enabling hugepages can improve performance"); + return; + } +#endif + + MemInfoWith(MemInfoEvaluateHugepages); +} + +#ifdef HAVE_DPDK + +/** + * Retrieves name of the port from port id + * Not thread-safe + * @param pid + * @return static dev_name on success + */ +const char *DPDKGetPortNameByPortID(uint16_t pid) +{ + static char dev_name[RTE_ETH_NAME_MAX_LEN]; + int32_t ret = rte_eth_dev_get_name_by_port(pid, dev_name); + if (ret < 0) { + FatalError("Port %d: Failed to obtain port name (err: %s)", pid, rte_strerror(-ret)); + } + return dev_name; +} + +#endif /* HAVE_DPDK */ diff --git a/src/util/dpdk.h b/src/util/dpdk.h new file mode 100644 index 000000000000..7339178b4963 --- /dev/null +++ b/src/util/dpdk.h @@ -0,0 +1,130 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Lukas Sismis + */ + +#ifndef UTIL_DPDK_H +#define UTIL_DPDK_H + +#ifdef HAVE_DPDK + +#include +#include +#ifdef HAVE_DPDK_BOND +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#if RTE_VERSION < RTE_VERSION_NUM(22, 0, 0, 0) +#define RTE_ETH_MQ_RX_RSS ETH_MQ_RX_RSS +#endif + +#if RTE_VERSION < RTE_VERSION_NUM(21, 11, 0, 0) +#define RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE DEV_TX_OFFLOAD_MBUF_FAST_FREE + +#define RTE_ETH_RX_OFFLOAD_CHECKSUM DEV_RX_OFFLOAD_CHECKSUM + +#define RTE_ETH_RX_OFFLOAD_VLAN_STRIP DEV_RX_OFFLOAD_VLAN_STRIP +#define RTE_ETH_RX_OFFLOAD_IPV4_CKSUM DEV_RX_OFFLOAD_IPV4_CKSUM +#define RTE_ETH_RX_OFFLOAD_UDP_CKSUM DEV_RX_OFFLOAD_UDP_CKSUM +#define RTE_ETH_RX_OFFLOAD_TCP_CKSUM DEV_RX_OFFLOAD_TCP_CKSUM +#define RTE_ETH_RX_OFFLOAD_TCP_LRO DEV_RX_OFFLOAD_TCP_LRO +#define RTE_ETH_RX_OFFLOAD_QINQ_STRIP DEV_RX_OFFLOAD_QINQ_STRIP +#define RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM +#define RTE_ETH_RX_OFFLOAD_MACSEC_STRIP DEV_RX_OFFLOAD_MACSEC_STRIP +#define RTE_ETH_RX_OFFLOAD_HEADER_SPLIT DEV_RX_OFFLOAD_HEADER_SPLIT +#define RTE_ETH_RX_OFFLOAD_VLAN_FILTER DEV_RX_OFFLOAD_VLAN_FILTER +#define RTE_ETH_RX_OFFLOAD_VLAN_EXTEND DEV_RX_OFFLOAD_VLAN_EXTEND +#define RTE_ETH_RX_OFFLOAD_SCATTER DEV_RX_OFFLOAD_SCATTER +#define RTE_ETH_RX_OFFLOAD_TIMESTAMP DEV_RX_OFFLOAD_TIMESTAMP +#define RTE_ETH_RX_OFFLOAD_SECURITY DEV_RX_OFFLOAD_SECURITY +#define RTE_ETH_RX_OFFLOAD_KEEP_CRC DEV_RX_OFFLOAD_KEEP_CRC +#define RTE_ETH_RX_OFFLOAD_SCTP_CKSUM DEV_RX_OFFLOAD_SCTP_CKSUM +#define RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM DEV_RX_OFFLOAD_OUTER_UDP_CKSUM +#define RTE_ETH_RX_OFFLOAD_RSS_HASH DEV_RX_OFFLOAD_RSS_HASH + +#define RTE_ETH_MQ_TX_NONE ETH_MQ_TX_NONE + +#define RTE_ETH_MQ_RX_NONE ETH_MQ_RX_NONE + +#define RTE_ETH_RSS_IP ETH_RSS_IP +#define RTE_ETH_RSS_UDP ETH_RSS_UDP +#define RTE_ETH_RSS_TCP ETH_RSS_TCP +#define RTE_ETH_RSS_SCTP ETH_RSS_SCTP +#define RTE_ETH_RSS_TUNNEL ETH_RSS_TUNNEL + +#define RTE_ETH_RSS_L3_SRC_ONLY ETH_RSS_L3_SRC_ONLY +#define RTE_ETH_RSS_L3_DST_ONLY ETH_RSS_L3_DST_ONLY +#define RTE_ETH_RSS_L4_SRC_ONLY ETH_RSS_L4_SRC_ONLY +#define RTE_ETH_RSS_L4_DST_ONLY ETH_RSS_L4_DST_ONLY + +#define RTE_ETH_RSS_IPV4 ETH_RSS_IPV4 +#define RTE_ETH_RSS_FRAG_IPV4 ETH_RSS_FRAG_IPV4 +#define RTE_ETH_RSS_NONFRAG_IPV4_TCP ETH_RSS_NONFRAG_IPV4_TCP +#define RTE_ETH_RSS_NONFRAG_IPV4_UDP ETH_RSS_NONFRAG_IPV4_UDP +#define RTE_ETH_RSS_NONFRAG_IPV4_SCTP ETH_RSS_NONFRAG_IPV4_SCTP +#define RTE_ETH_RSS_NONFRAG_IPV4_OTHER ETH_RSS_NONFRAG_IPV4_OTHER +#define RTE_ETH_RSS_IPV6 ETH_RSS_IPV6 +#define RTE_ETH_RSS_FRAG_IPV6 ETH_RSS_FRAG_IPV6 +#define RTE_ETH_RSS_NONFRAG_IPV6_TCP ETH_RSS_NONFRAG_IPV6_TCP +#define RTE_ETH_RSS_NONFRAG_IPV6_UDP ETH_RSS_NONFRAG_IPV6_UDP +#define RTE_ETH_RSS_NONFRAG_IPV6_SCTP ETH_RSS_NONFRAG_IPV6_SCTP +#define RTE_ETH_RSS_NONFRAG_IPV6_OTHER ETH_RSS_NONFRAG_IPV6_OTHER +#define RTE_ETH_RSS_L2_PAYLOAD ETH_RSS_L2_PAYLOAD +#define RTE_ETH_RSS_IPV6_EX ETH_RSS_IPV6_EX +#define RTE_ETH_RSS_IPV6_TCP_EX ETH_RSS_IPV6_TCP_EX +#define RTE_ETH_RSS_IPV6_UDP_EX ETH_RSS_IPV6_UDP_EX +#define RTE_ETH_RSS_PORT ETH_RSS_PORT +#define RTE_ETH_RSS_VXLAN ETH_RSS_VXLAN +#define RTE_ETH_RSS_NVGRE ETH_RSS_NVGRE +#define RTE_ETH_RSS_GTPU ETH_RSS_GTPU + +#define RTE_MBUF_F_RX_IP_CKSUM_MASK PKT_RX_IP_CKSUM_MASK +#define RTE_MBUF_F_RX_IP_CKSUM_NONE PKT_RX_IP_CKSUM_NONE +#define RTE_MBUF_F_RX_IP_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD +#define RTE_MBUF_F_RX_IP_CKSUM_BAD PKT_RX_IP_CKSUM_BAD + +#define RTE_MBUF_F_RX_L4_CKSUM_MASK PKT_RX_L4_CKSUM_MASK +#define RTE_MBUF_F_RX_L4_CKSUM_GOOD PKT_RX_L4_CKSUM_GOOD +#define RTE_MBUF_F_RX_L4_CKSUM_BAD PKT_RX_L4_CKSUM_BAD +#endif + +#endif /* HAVE_DPDK */ + +#include "util/device.h" + +void DPDKCleanupEAL(void); + +void DPDKCloseDevice(LiveDevice *ldev); +void DPDKFreeDevice(LiveDevice *ldev); +void DPDKEvaluateHugepages(void); + +#ifdef HAVE_DPDK +const char *DPDKGetPortNameByPortID(uint16_t pid); +#endif /* HAVE_DPDK */ + +#endif /* UTIL_DPDK_H */ diff --git a/src/util/ebpf.c b/src/util/ebpf.c new file mode 100644 index 000000000000..a079ba1d6a3d --- /dev/null +++ b/src/util/ebpf.c @@ -0,0 +1,1049 @@ +/* Copyright (C) 2018-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup afppacket + * + * @{ + */ + +/** + * \file + * + * \author Eric Leblond + * + * eBPF utility + * + */ + +#define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 +#define SC_PCAP_DONT_INCLUDE_PCAP_H 1 + +#include "suricata-common.h" +#include "flow-bypass.h" + +#ifdef HAVE_PACKET_EBPF + +#include +#include + +#include "util/ebpf.h" +#include "util/affinity.h" +#include "util/cpu.h" +#include "util/device.h" + +#include "device-storage.h" +#include "flow-storage.h" +#include "flow.h" +#include "flow-hash.h" +#include "tm-threads.h" + +#include +#include +#include +#include "autoconf.h" + +#define BPF_MAP_MAX_COUNT 16 + +#define BYPASSED_FLOW_TIMEOUT 60 + +static LiveDevStorageId g_livedev_storage_id = { .id = -1 }; +static FlowStorageId g_flow_storage_id = { .id = -1 }; + +struct bpf_map_item { + char iface[IFNAMSIZ]; + char *name; + int fd; + uint8_t to_unlink; +}; + +struct bpf_maps_info { + struct bpf_map_item array[BPF_MAP_MAX_COUNT]; + int last; +}; + +typedef struct BypassedIfaceList_ { + LiveDevice *dev; + struct BypassedIfaceList_ *next; +} BypassedIfaceList; + +static void BpfMapsInfoFree(void *bpf) +{ + struct bpf_maps_info *bpfinfo = (struct bpf_maps_info *)bpf; + int i; + for (i = 0; i < bpfinfo->last; i++) { + if (bpfinfo->array[i].name) { + if (bpfinfo->array[i].to_unlink) { + char pinnedpath[PATH_MAX]; + int ret = snprintf(pinnedpath, sizeof(pinnedpath), "/sys/fs/bpf/suricata-%s-%s", + bpfinfo->array[i].iface, bpfinfo->array[i].name); + if (ret > 0) { + /* Unlink the pinned entry */ + ret = unlink(pinnedpath); + if (ret == -1) { + int error = errno; + SCLogWarning( + "Unable to remove %s: %s (%d)", pinnedpath, strerror(error), error); + } + } else { + SCLogWarning("Unable to remove map %s", bpfinfo->array[i].name); + } + } + SCFree(bpfinfo->array[i].name); + } + } + SCFree(bpfinfo); +} + +static void BypassedListFree(void *ifl) +{ + BypassedIfaceList *mifl = (BypassedIfaceList *)ifl; + BypassedIfaceList *nifl; + while (mifl) { + nifl = mifl->next; + SCFree(mifl); + mifl = nifl; + } +} + +void EBPFDeleteKey(int fd, void *key) +{ + int ret = bpf_map_delete_elem(fd, key); + if (ret < 0) { + SCLogWarning("Unable to delete entry: %s (%d)", strerror(errno), errno); + } +} + +static struct bpf_maps_info *EBPFGetBpfMap(const char *iface) +{ + LiveDevice *livedev = LiveGetDevice(iface); + if (livedev == NULL) + return NULL; + void *data = LiveDevGetStorageById(livedev, g_livedev_storage_id); + + return (struct bpf_maps_info *)data; +} + +/** + * Get file descriptor of a map in the scope of a interface + * + * \param iface the interface where the map need to be looked for + * \param name the name of the map + * \return the file descriptor or -1 in case of error + */ +int EBPFGetMapFDByName(const char *iface, const char *name) +{ + int i; + + if (iface == NULL || name == NULL) + return -1; + struct bpf_maps_info *bpf_maps = EBPFGetBpfMap(iface); + if (bpf_maps == NULL) + return -1; + + for (i = 0; i < BPF_MAP_MAX_COUNT; i++) { + if (!bpf_maps->array[i].name) + continue; + if (!strcmp(bpf_maps->array[i].name, name)) { + SCLogDebug("Got fd %d for eBPF map '%s'", bpf_maps->array[i].fd, name); + return bpf_maps->array[i].fd; + } + } + + return -1; +} + +static int EBPFLoadPinnedMapsFile(LiveDevice *livedev, const char *file) +{ + char pinnedpath[1024]; + snprintf(pinnedpath, sizeof(pinnedpath), "/sys/fs/bpf/suricata-%s-%s", livedev->dev, file); + + return bpf_obj_get(pinnedpath); +} + +static int EBPFLoadPinnedMaps(LiveDevice *livedev, struct ebpf_timeout_config *config) +{ + int fd_v4 = -1, fd_v6 = -1; + + /* First try to load the eBPF check map and return if found */ + if (config->pinned_maps_name) { + int ret = EBPFLoadPinnedMapsFile(livedev, config->pinned_maps_name); + if (ret == 0) { + /* pinned maps found, let's just exit as XDP filter is in place */ + return ret; + } + } + + if (config->mode == AFP_MODE_XDP_BYPASS) { + /* Get flow v4 table */ + fd_v4 = EBPFLoadPinnedMapsFile(livedev, "flow_table_v4"); + if (fd_v4 < 0) { + return fd_v4; + } + + /* Get flow v6 table */ + fd_v6 = EBPFLoadPinnedMapsFile(livedev, "flow_table_v6"); + if (fd_v6 < 0) { + SCLogWarning("Found a flow_table_v4 map but no flow_table_v6 map"); + return fd_v6; + } + } + + struct bpf_maps_info *bpf_map_data = SCCalloc(1, sizeof(*bpf_map_data)); + if (bpf_map_data == NULL) { + SCLogError("Can't allocate bpf map array"); + return -1; + } + + if (config->mode == AFP_MODE_XDP_BYPASS) { + bpf_map_data->array[0].fd = fd_v4; + bpf_map_data->array[0].name = SCStrdup("flow_table_v4"); + if (bpf_map_data->array[0].name == NULL) { + goto alloc_error; + } + bpf_map_data->array[1].fd = fd_v6; + bpf_map_data->array[1].name = SCStrdup("flow_table_v6"); + if (bpf_map_data->array[1].name == NULL) { + goto alloc_error; + } + bpf_map_data->last = 2; + } else { + bpf_map_data->last = 0; + } + + /* Load other known maps: cpu_map, cpus_available, tx_peer, tx_peer_int */ + int fd = EBPFLoadPinnedMapsFile(livedev, "cpu_map"); + if (fd >= 0) { + bpf_map_data->array[bpf_map_data->last].fd = fd; + bpf_map_data->array[bpf_map_data->last].name = SCStrdup("cpu_map"); + if (bpf_map_data->array[bpf_map_data->last].name == NULL) { + goto alloc_error; + } + bpf_map_data->last++; + } + fd = EBPFLoadPinnedMapsFile(livedev, "cpus_available"); + if (fd >= 0) { + bpf_map_data->array[bpf_map_data->last].fd = fd; + bpf_map_data->array[bpf_map_data->last].name = SCStrdup("cpus_available"); + if (bpf_map_data->array[bpf_map_data->last].name == NULL) { + goto alloc_error; + } + bpf_map_data->last++; + } + fd = EBPFLoadPinnedMapsFile(livedev, "tx_peer"); + if (fd >= 0) { + bpf_map_data->array[bpf_map_data->last].fd = fd; + bpf_map_data->array[bpf_map_data->last].name = SCStrdup("tx_peer"); + if (bpf_map_data->array[bpf_map_data->last].name == NULL) { + goto alloc_error; + } + bpf_map_data->last++; + } + fd = EBPFLoadPinnedMapsFile(livedev, "tx_peer_int"); + if (fd >= 0) { + bpf_map_data->array[bpf_map_data->last].fd = fd; + bpf_map_data->array[bpf_map_data->last].name = SCStrdup("tx_peer_int"); + if (bpf_map_data->array[bpf_map_data->last].name == NULL) { + goto alloc_error; + } + bpf_map_data->last++; + } + + /* Attach the bpf_maps_info to the LiveDevice via the device storage */ + LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data); + /* Declare that device will use bypass stats */ + LiveDevUseBypass(livedev); + + return 0; + +alloc_error: + for (int i = 0; i < bpf_map_data->last; i++) { + SCFree(bpf_map_data->array[i].name); + } + bpf_map_data->last = 0; + SCLogError("Can't allocate bpf map name"); + return -1; +} + +/** + * Load a section of an eBPF file + * + * This function loads a section inside an eBPF and return + * via the parameter val the file descriptor that will be used to + * inject the eBPF code into the kernel via a syscall. + * + * \param path the path of the eBPF file to load + * \param section the section in the eBPF file to load + * \param val a pointer to an integer that will be the file desc + * \return -1 in case of error, 0 in case of success, 1 if pinned maps is loaded + */ +int EBPFLoadFile(const char *iface, const char *path, const char *section, int *val, + struct ebpf_timeout_config *config) +{ + int err, pfd; + bool found = false; + struct bpf_object *bpfobj = NULL; + struct bpf_program *bpfprog = NULL; + struct bpf_map *map = NULL; + + if (iface == NULL) + return -1; + LiveDevice *livedev = LiveGetDevice(iface); + if (livedev == NULL) + return -1; + + if (config->flags & EBPF_XDP_CODE && config->flags & EBPF_PINNED_MAPS) { + /* We try to get our flow table maps and if we have them we can simply return */ + if (EBPFLoadPinnedMaps(livedev, config) == 0) { + SCLogInfo("Loaded pinned maps, will use already loaded eBPF filter"); + return 1; + } + } + + if (!path) { + SCLogError("No file defined to load eBPF from"); + return -1; + } + + /* Sending the eBPF code to the kernel requires a large amount of + * locked memory so we set it to unlimited to avoid a ENOPERM error */ + struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY }; + if (setrlimit(RLIMIT_MEMLOCK, &r) != 0) { + SCLogError("Unable to lock memory: %s (%d)", strerror(errno), errno); + return -1; + } + + /* Open the eBPF file and parse it */ + bpfobj = bpf_object__open(path); + long error = libbpf_get_error(bpfobj); + if (error) { + char err_buf[128]; + libbpf_strerror(error, err_buf, sizeof(err_buf)); + SCLogError("Unable to load eBPF objects in '%s': %s", path, err_buf); + return -1; + } + + if (config->flags & EBPF_XDP_HW_MODE) { + unsigned int ifindex = if_nametoindex(iface); + bpf_object__for_each_program(bpfprog, bpfobj) + { + bpf_program__set_ifindex(bpfprog, ifindex); + } + bpf_map__for_each(map, bpfobj) + { + bpf_map__set_ifindex(map, ifindex); + } + } + + /* Let's check that our section is here */ + bpf_object__for_each_program(bpfprog, bpfobj) + { +#ifdef HAVE_BPF_PROGRAM__SECTION_NAME + const char *title = bpf_program__section_name(bpfprog); +#else + const char *title = bpf_program__title(bpfprog, 0); +#endif + if (!strcmp(title, section)) { + if (config->flags & EBPF_SOCKET_FILTER) { +#ifdef HAVE_BPF_PROGRAM__SET_TYPE + bpf_program__set_type(bpfprog, BPF_PROG_TYPE_SOCKET_FILTER); +#else + /* Fall back to legacy API */ + bpf_program__set_socket_filter(bpfprog); +#endif + } else { +#ifdef HAVE_BPF_PROGRAM__SET_TYPE + bpf_program__set_type(bpfprog, BPF_PROG_TYPE_XDP); +#else + /* Fall back to legacy API */ + bpf_program__set_xdp(bpfprog); +#endif + } + found = true; + break; + } + } + + if (found == false) { + SCLogError("No section '%s' in '%s' file. Will not be able to use the file", section, path); + return -1; + } + + err = bpf_object__load(bpfobj); + if (err < 0) { + if (err == -EPERM) { + SCLogError("Permission issue when loading eBPF object" + " (check libbpf error on stdout)"); + } else { + char buf[129]; + libbpf_strerror(err, buf, sizeof(buf)); + SCLogError("Unable to load eBPF object: %s (%d)", buf, err); + } + return -1; + } + + /* Kernel and userspace are sharing data via map. Userspace access to the + * map via a file descriptor. So we need to store the map to fd info. For + * that we use bpf_maps_info:: */ + struct bpf_maps_info *bpf_map_data = SCCalloc(1, sizeof(*bpf_map_data)); + if (bpf_map_data == NULL) { + SCLogError("Can't allocate bpf map array"); + return -1; + } + + /* Store the maps in bpf_maps_info:: */ + bpf_map__for_each(map, bpfobj) + { + if (bpf_map_data->last == BPF_MAP_MAX_COUNT) { + SCLogError("Too many BPF maps in eBPF files"); + break; + } + SCLogDebug("Got a map '%s' with fd '%d'", bpf_map__name(map), bpf_map__fd(map)); + bpf_map_data->array[bpf_map_data->last].fd = bpf_map__fd(map); + bpf_map_data->array[bpf_map_data->last].name = SCStrdup(bpf_map__name(map)); + snprintf(bpf_map_data->array[bpf_map_data->last].iface, IFNAMSIZ, "%s", iface); + if (!bpf_map_data->array[bpf_map_data->last].name) { + SCLogError("Unable to duplicate map name"); + BpfMapsInfoFree(bpf_map_data); + return -1; + } + bpf_map_data->array[bpf_map_data->last].to_unlink = 0; + if (config->flags & EBPF_PINNED_MAPS) { + SCLogConfig("Pinning: %d to %s", bpf_map_data->array[bpf_map_data->last].fd, + bpf_map_data->array[bpf_map_data->last].name); + char buf[1024]; + snprintf(buf, sizeof(buf), "/sys/fs/bpf/suricata-%s-%s", iface, + bpf_map_data->array[bpf_map_data->last].name); + int ret = bpf_obj_pin(bpf_map_data->array[bpf_map_data->last].fd, buf); + if (ret != 0) { + SCLogWarning("Can not pin: %s", strerror(errno)); + } + /* Don't unlink pinned maps in XDP mode to avoid a state reset */ + if (config->flags & EBPF_XDP_CODE) { + bpf_map_data->array[bpf_map_data->last].to_unlink = 0; + } else { + bpf_map_data->array[bpf_map_data->last].to_unlink = 1; + } + } + bpf_map_data->last++; + } + + /* Attach the bpf_maps_info to the LiveDevice via the device storage */ + LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data); + LiveDevUseBypass(livedev); + + /* Finally we get the file descriptor for our eBPF program. We will use + * the fd to attach the program to the socket (eBPF case) or to the device + * (XDP case). */ + pfd = bpf_program__fd(bpfprog); + if (pfd == -1) { + SCLogError("Unable to find %s section", section); + return -1; + } + + SCLogInfo("Successfully loaded eBPF file '%s' on '%s'", path, iface); + *val = pfd; + return 0; +} + +/** + * Attach a XDP program identified by its file descriptor to a device + * + * \param iface the name of interface + * \param fd the eBPF/XDP program file descriptor + * \param a flag to pass to attach function mostly used to set XDP mode + * \return -1 in case of error, 0 if success + */ +int EBPFSetupXDP(const char *iface, int fd, uint8_t flags) +{ +#ifdef HAVE_PACKET_XDP + unsigned int ifindex = if_nametoindex(iface); + if (ifindex == 0) { + SCLogError("Unknown interface '%s'", iface); + return -1; + } +#ifdef HAVE_BPF_XDP_ATTACH + int err = bpf_xdp_attach(ifindex, fd, flags, NULL); +#else + /* Fall back to legacy API */ + int err = bpf_set_link_xdp_fd(ifindex, fd, flags); +#endif + if (err != 0) { + char buf[129]; + libbpf_strerror(err, buf, sizeof(buf)); + SCLogError("Unable to set XDP on '%s': %s (%d)", iface, buf, err); + return -1; + } +#endif + return 0; +} + +/** + * Create a Flow in the table for a Flowkey + * + * \return false (this create function never returns true) + */ +static bool EBPFCreateFlowForKey(struct flows_stats *flowstats, LiveDevice *dev, void *key, + size_t skey, FlowKey *flow_key, struct timespec *ctime, uint64_t pkts_cnt, + uint64_t bytes_cnt, int mapfd, int cpus_count) +{ + Flow *f = NULL; + uint32_t hash = FlowKeyGetHash(flow_key); + + f = FlowGetFromFlowKey(flow_key, ctime, hash); + if (f == NULL) + return false; + + /* set accounting, we can't know the direction, so let's just start to + * serve them if we already have something from server to client. We need + * these numbers as we will use it to see if we have new traffic coming + * on the flow */ + FlowBypassInfo *fc = FlowGetStorageById(f, GetFlowBypassInfoID()); + if (fc == NULL) { + fc = SCCalloc(sizeof(FlowBypassInfo), 1); + if (fc) { + FlowUpdateState(f, FLOW_STATE_CAPTURE_BYPASSED); + FlowSetStorageById(f, GetFlowBypassInfoID(), fc); + fc->BypassUpdate = EBPFBypassUpdate; + fc->BypassFree = EBPFBypassFree; + fc->todstpktcnt = pkts_cnt; + fc->todstbytecnt = bytes_cnt; + f->livedev = dev; + EBPFBypassData *eb = SCCalloc(1, sizeof(EBPFBypassData)); + if (eb == NULL) { + SCFree(fc); + FLOWLOCK_UNLOCK(f); + return false; + } + void *mkey = SCCalloc(1, skey); + if (mkey == NULL) { + SCFree(fc); + SCFree(eb); + FLOWLOCK_UNLOCK(f); + return false; + } + memcpy(mkey, key, skey); + eb->key[0] = mkey; + eb->mapfd = mapfd; + eb->cpus_count = cpus_count; + fc->bypass_data = eb; + flowstats->count++; + } else { + FLOWLOCK_UNLOCK(f); + return false; + } + } else { + EBPFBypassData *eb = (EBPFBypassData *)fc->bypass_data; + if (eb == NULL) { + FLOWLOCK_UNLOCK(f); + return false; + } + /* if both keys are here, then it is a flow bypassed by this + * instance so we ignore it */ + if (eb->key[0] && eb->key[1]) { + FLOWLOCK_UNLOCK(f); + return false; + } + fc->tosrcpktcnt = pkts_cnt; + fc->tosrcbytecnt = bytes_cnt; + void *mkey = SCCalloc(1, skey); + if (mkey == NULL) { + FLOWLOCK_UNLOCK(f); + return false; + } + memcpy(mkey, key, skey); + eb->key[1] = mkey; + } + f->livedev = dev; + FLOWLOCK_UNLOCK(f); + return false; +} + +void EBPFBypassFree(void *data) +{ + EBPFBypassData *eb = (EBPFBypassData *)data; + if (eb == NULL) + return; + SCFree(eb->key[0]); + if (eb->key[1]) { + SCFree(eb->key[1]); + } + SCFree(eb); + return; +} + +/** + * + * Compare eBPF half flow to Flow + * + * \return true if entries have activity, false if not + */ + +static bool EBPFBypassCheckHalfFlow( + Flow *f, FlowBypassInfo *fc, EBPFBypassData *eb, void *key, int index) +{ + int i; + uint64_t pkts_cnt = 0; + uint64_t bytes_cnt = 0; + /* We use a per CPU structure so we will get a array of values. But if nr_cpus + * is 1 then we have a global hash. */ + BPF_DECLARE_PERCPU(struct pair, values_array, eb->cpus_count); + memset(values_array, 0, sizeof(values_array)); + int res = bpf_map_lookup_elem(eb->mapfd, key, values_array); + if (res < 0) { + SCLogDebug("errno: (%d) %s", errno, strerror(errno)); + return false; + } + for (i = 0; i < eb->cpus_count; i++) { + /* let's start accumulating value so we can compute the counters */ + SCLogDebug("%d: Adding pkts %lu bytes %lu", i, BPF_PERCPU(values_array, i).packets, + BPF_PERCPU(values_array, i).bytes); + pkts_cnt += BPF_PERCPU(values_array, i).packets; + bytes_cnt += BPF_PERCPU(values_array, i).bytes; + } + if (index == 0) { + if (pkts_cnt != fc->todstpktcnt) { + fc->todstpktcnt = pkts_cnt; + fc->todstbytecnt = bytes_cnt; + return true; + } + } else { + if (pkts_cnt != fc->tosrcpktcnt) { + fc->tosrcpktcnt = pkts_cnt; + fc->tosrcbytecnt = bytes_cnt; + return true; + } + } + + return false; +} + +/** Check both half flows for update + * + * Update lastts in the flow and do accounting + * + * */ +bool EBPFBypassUpdate(Flow *f, void *data, time_t tsec) +{ + EBPFBypassData *eb = (EBPFBypassData *)data; + if (eb == NULL) { + return false; + } + FlowBypassInfo *fc = FlowGetStorageById(f, GetFlowBypassInfoID()); + if (fc == NULL) { + return false; + } + bool activity = EBPFBypassCheckHalfFlow(f, fc, eb, eb->key[0], 0); + activity |= EBPFBypassCheckHalfFlow(f, fc, eb, eb->key[1], 1); + if (!activity) { + SCLogDebug("Delete entry: %u (%ld)", FLOW_IS_IPV6(f), FlowGetId(f)); + /* delete the entries if no time update */ + EBPFDeleteKey(eb->mapfd, eb->key[0]); + EBPFDeleteKey(eb->mapfd, eb->key[1]); + SCLogDebug("Done delete entry: %u", FLOW_IS_IPV6(f)); + } else { + f->lastts = SCTIME_FROM_SECS(tsec); + return true; + } + return false; +} + +typedef bool (*OpFlowForKey)(struct flows_stats *flowstats, LiveDevice *dev, void *key, size_t skey, + FlowKey *flow_key, struct timespec *ctime, uint64_t pkts_cnt, uint64_t bytes_cnt, int mapfd, + int cpus_count); + +/** + * Bypassed flows iterator for IPv4 + * + * This function iterates on all the flows of the IPv4 table + * running a callback function on each flow. + */ +static int EBPFForEachFlowV4Table(ThreadVars *th_v, LiveDevice *dev, const char *name, + struct timespec *ctime, struct ebpf_timeout_config *tcfg, OpFlowForKey EBPFOpFlowForKey) +{ + struct flows_stats flowstats = { 0, 0, 0 }; + int mapfd = EBPFGetMapFDByName(dev->dev, name); + if (mapfd == -1) + return -1; + + struct flowv4_keys key = {}, next_key; + int found = 0; + unsigned int i; + uint64_t hash_cnt = 0; + + if (tcfg->cpus_count == 0) { + return 0; + } + + bool dead_flow = false; + while (bpf_map_get_next_key(mapfd, &key, &next_key) == 0) { + uint64_t bytes_cnt = 0; + uint64_t pkts_cnt = 0; + hash_cnt++; + if (dead_flow) { + EBPFDeleteKey(mapfd, &key); + dead_flow = false; + } + /* We use a per CPU structure so we will get a array of values. But if nr_cpus + * is 1 then we have a global hash. */ + BPF_DECLARE_PERCPU(struct pair, values_array, tcfg->cpus_count); + memset(values_array, 0, sizeof(values_array)); + int res = bpf_map_lookup_elem(mapfd, &next_key, values_array); + if (res < 0) { + SCLogDebug("no entry in v4 table for %d -> %d", key.port16[0], key.port16[1]); + SCLogDebug("errno: (%d) %s", errno, strerror(errno)); + key = next_key; + continue; + } + for (i = 0; i < tcfg->cpus_count; i++) { + /* let's start accumulating value so we can compute the counters */ + SCLogDebug("%d: Adding pkts %lu bytes %lu", i, BPF_PERCPU(values_array, i).packets, + BPF_PERCPU(values_array, i).bytes); + pkts_cnt += BPF_PERCPU(values_array, i).packets; + bytes_cnt += BPF_PERCPU(values_array, i).bytes; + } + /* Get the corresponding Flow in the Flow table to compare and update + * its counters and lastseen if needed */ + FlowKey flow_key; + if (tcfg->mode == AFP_MODE_XDP_BYPASS) { + flow_key.sp = ntohs(next_key.port16[0]); + flow_key.dp = ntohs(next_key.port16[1]); + flow_key.src.addr_data32[0] = next_key.src; + flow_key.dst.addr_data32[0] = next_key.dst; + } else { + flow_key.sp = next_key.port16[0]; + flow_key.dp = next_key.port16[1]; + flow_key.src.addr_data32[0] = ntohl(next_key.src); + flow_key.dst.addr_data32[0] = ntohl(next_key.dst); + } + flow_key.src.family = AF_INET; + flow_key.src.addr_data32[1] = 0; + flow_key.src.addr_data32[2] = 0; + flow_key.src.addr_data32[3] = 0; + flow_key.dst.family = AF_INET; + flow_key.dst.addr_data32[1] = 0; + flow_key.dst.addr_data32[2] = 0; + flow_key.dst.addr_data32[3] = 0; + flow_key.vlan_id[0] = next_key.vlan0; + flow_key.vlan_id[1] = next_key.vlan1; + flow_key.vlan_id[2] = next_key.vlan2; + if (next_key.ip_proto == 1) { + flow_key.proto = IPPROTO_TCP; + } else { + flow_key.proto = IPPROTO_UDP; + } + flow_key.recursion_level = 0; + flow_key.livedev_id = dev->id; + dead_flow = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key, ctime, + pkts_cnt, bytes_cnt, mapfd, tcfg->cpus_count); + if (dead_flow) { + found = 1; + } + + if (TmThreadsCheckFlag(th_v, THV_KILL)) { + return 0; + } + + key = next_key; + } + if (dead_flow) { + EBPFDeleteKey(mapfd, &key); + found = 1; + } + SC_ATOMIC_ADD(dev->bypassed, flowstats.packets); + + LiveDevAddBypassStats(dev, flowstats.count, AF_INET); + SCLogInfo("IPv4 bypassed flow table size: %" PRIu64, hash_cnt); + + return found; +} + +/** + * Bypassed flows iterator for IPv6 + * + * This function iterates on all the flows of the IPv4 table + * running a callback function on each flow. + */ +static int EBPFForEachFlowV6Table(ThreadVars *th_v, LiveDevice *dev, const char *name, + struct timespec *ctime, struct ebpf_timeout_config *tcfg, OpFlowForKey EBPFOpFlowForKey) +{ + struct flows_stats flowstats = { 0, 0, 0 }; + int mapfd = EBPFGetMapFDByName(dev->dev, name); + if (mapfd == -1) + return -1; + + struct flowv6_keys key = {}, next_key; + int found = 0; + unsigned int i; + uint64_t hash_cnt = 0; + + if (tcfg->cpus_count == 0) { + SCLogWarning("CPU count should not be 0"); + return 0; + } + + uint64_t pkts_cnt = 0; + while (bpf_map_get_next_key(mapfd, &key, &next_key) == 0) { + uint64_t bytes_cnt = 0; + hash_cnt++; + if (pkts_cnt > 0) { + EBPFDeleteKey(mapfd, &key); + } + pkts_cnt = 0; + /* We use a per CPU structure so we will get a array of values. But if nr_cpus + * is 1 then we have a global hash. */ + BPF_DECLARE_PERCPU(struct pair, values_array, tcfg->cpus_count); + memset(values_array, 0, sizeof(values_array)); + int res = bpf_map_lookup_elem(mapfd, &next_key, values_array); + if (res < 0) { + SCLogDebug("no entry in v4 table for %d -> %d", key.port16[0], key.port16[1]); + key = next_key; + continue; + } + for (i = 0; i < tcfg->cpus_count; i++) { + /* let's start accumulating value so we can compute the counters */ + SCLogDebug("%d: Adding pkts %lu bytes %lu", i, BPF_PERCPU(values_array, i).packets, + BPF_PERCPU(values_array, i).bytes); + pkts_cnt += BPF_PERCPU(values_array, i).packets; + bytes_cnt += BPF_PERCPU(values_array, i).bytes; + } + /* Get the corresponding Flow in the Flow table to compare and update + * its counters and lastseen if needed */ + FlowKey flow_key; + if (tcfg->mode == AFP_MODE_XDP_BYPASS) { + flow_key.sp = ntohs(next_key.port16[0]); + flow_key.dp = ntohs(next_key.port16[1]); + flow_key.src.family = AF_INET6; + flow_key.src.addr_data32[0] = next_key.src[0]; + flow_key.src.addr_data32[1] = next_key.src[1]; + flow_key.src.addr_data32[2] = next_key.src[2]; + flow_key.src.addr_data32[3] = next_key.src[3]; + flow_key.dst.family = AF_INET6; + flow_key.dst.addr_data32[0] = next_key.dst[0]; + flow_key.dst.addr_data32[1] = next_key.dst[1]; + flow_key.dst.addr_data32[2] = next_key.dst[2]; + flow_key.dst.addr_data32[3] = next_key.dst[3]; + } else { + flow_key.sp = next_key.port16[0]; + flow_key.dp = next_key.port16[1]; + flow_key.src.family = AF_INET6; + flow_key.src.addr_data32[0] = ntohl(next_key.src[0]); + flow_key.src.addr_data32[1] = ntohl(next_key.src[1]); + flow_key.src.addr_data32[2] = ntohl(next_key.src[2]); + flow_key.src.addr_data32[3] = ntohl(next_key.src[3]); + flow_key.dst.family = AF_INET6; + flow_key.dst.addr_data32[0] = ntohl(next_key.dst[0]); + flow_key.dst.addr_data32[1] = ntohl(next_key.dst[1]); + flow_key.dst.addr_data32[2] = ntohl(next_key.dst[2]); + flow_key.dst.addr_data32[3] = ntohl(next_key.dst[3]); + } + flow_key.vlan_id[0] = next_key.vlan0; + flow_key.vlan_id[1] = next_key.vlan1; + flow_key.vlan_id[2] = next_key.vlan2; + if (next_key.ip_proto == 1) { + flow_key.proto = IPPROTO_TCP; + } else { + flow_key.proto = IPPROTO_UDP; + } + flow_key.recursion_level = 0; + flow_key.livedev_id = dev->id; + pkts_cnt = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key, ctime, + pkts_cnt, bytes_cnt, mapfd, tcfg->cpus_count); + if (pkts_cnt > 0) { + found = 1; + } + + if (TmThreadsCheckFlag(th_v, THV_KILL)) { + return 0; + } + + key = next_key; + } + if (pkts_cnt > 0) { + EBPFDeleteKey(mapfd, &key); + found = 1; + } + SC_ATOMIC_ADD(dev->bypassed, flowstats.packets); + + LiveDevAddBypassStats(dev, flowstats.count, AF_INET6); + SCLogInfo("IPv6 bypassed flow table size: %" PRIu64, hash_cnt); + return found; +} + +int EBPFCheckBypassedFlowCreate(ThreadVars *th_v, struct timespec *curtime, void *data) +{ + LiveDevice *ldev = NULL, *ndev; + struct ebpf_timeout_config *cfg = (struct ebpf_timeout_config *)data; + while (LiveDeviceForEach(&ldev, &ndev)) { + EBPFForEachFlowV4Table(th_v, ldev, "flow_table_v4", curtime, cfg, EBPFCreateFlowForKey); + EBPFForEachFlowV6Table(th_v, ldev, "flow_table_v6", curtime, cfg, EBPFCreateFlowForKey); + } + + return 0; +} + +void EBPFRegisterExtension(void) +{ + g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree); + g_flow_storage_id = FlowStorageRegister("bypassedlist", sizeof(void *), NULL, BypassedListFree); +} + +#ifdef HAVE_PACKET_XDP + +static uint32_t g_redirect_iface_cpu_counter = 0; + +static int EBPFAddCPUToMap(const char *iface, uint32_t i) +{ + int cpumap = EBPFGetMapFDByName(iface, "cpu_map"); + uint32_t queue_size = 4096; + int ret; + + if (cpumap < 0) { + SCLogError("Can't find cpu_map"); + return -1; + } + ret = bpf_map_update_elem(cpumap, &i, &queue_size, 0); + if (ret) { + SCLogError("Create CPU entry failed (err:%d)", ret); + return -1; + } + int cpus_available = EBPFGetMapFDByName(iface, "cpus_available"); + if (cpus_available < 0) { + SCLogError("Can't find cpus_available map"); + return -1; + } + + ret = bpf_map_update_elem(cpus_available, &g_redirect_iface_cpu_counter, &i, 0); + if (ret) { + SCLogError("Create CPU entry failed (err:%d)", ret); + return -1; + } + return 0; +} + +static void EBPFRedirectMapAddCPU(int i, void *data) +{ + if (EBPFAddCPUToMap(data, i) < 0) { + SCLogError("Unable to add CPU %d to set", i); + } else { + g_redirect_iface_cpu_counter++; + } +} + +void EBPFBuildCPUSet(ConfNode *node, char *iface) +{ + uint32_t key0 = 0; + int mapfd = EBPFGetMapFDByName(iface, "cpus_count"); + if (mapfd < 0) { + SCLogError("Unable to find 'cpus_count' map"); + return; + } + g_redirect_iface_cpu_counter = 0; + if (node == NULL) { + bpf_map_update_elem(mapfd, &key0, &g_redirect_iface_cpu_counter, BPF_ANY); + return; + } + BuildCpusetWithCallback("xdp-cpu-redirect", node, EBPFRedirectMapAddCPU, iface); + bpf_map_update_elem(mapfd, &key0, &g_redirect_iface_cpu_counter, BPF_ANY); +} + +/** + * Setup peer interface in XDP system + * + * Ths function set up the peer interface in the XDP maps used by the + * bypass filter. The first map tx_peer has type device map and is + * used to store the peer. The second map tx_peer_int is used by the + * code to check if we have a peer defined for this interface. + * + * As the map are per device we just need maps with one single element. + * In both case, we use the key 0 to enter element so XDP kernel code + * is using the same key. + */ +int EBPFSetPeerIface(const char *iface, const char *out_iface) +{ + int mapfd = EBPFGetMapFDByName(iface, "tx_peer"); + if (mapfd < 0) { + SCLogError("Unable to find 'tx_peer' map"); + return -1; + } + int intmapfd = EBPFGetMapFDByName(iface, "tx_peer_int"); + if (intmapfd < 0) { + SCLogError("Unable to find 'tx_peer_int' map"); + return -1; + } + + int key0 = 0; + unsigned int peer_index = if_nametoindex(out_iface); + if (peer_index == 0) { + SCLogError("No iface '%s'", out_iface); + return -1; + } + int ret = bpf_map_update_elem(mapfd, &key0, &peer_index, BPF_ANY); + if (ret) { + SCLogError("Create peer entry failed (err:%d)", ret); + return -1; + } + ret = bpf_map_update_elem(intmapfd, &key0, &peer_index, BPF_ANY); + if (ret) { + SCLogError("Create peer entry failed (err:%d)", ret); + return -1; + } + return 0; +} + +/** + * Bypass the flow on all ifaces it is seen on. This is used + * in IPS mode. + */ + +int EBPFUpdateFlow(Flow *f, Packet *p, void *data) +{ + BypassedIfaceList *ifl = (BypassedIfaceList *)FlowGetStorageById(f, g_flow_storage_id); + if (ifl == NULL) { + ifl = SCCalloc(1, sizeof(*ifl)); + if (ifl == NULL) { + return 0; + } + ifl->dev = p->livedev; + FlowSetStorageById(f, g_flow_storage_id, ifl); + return 1; + } + /* Look for packet iface in the list */ + BypassedIfaceList *ldev = ifl; + while (ldev) { + if (p->livedev == ldev->dev) { + return 1; + } + ldev = ldev->next; + } + /* Call bypass function if ever not in the list */ + p->BypassPacketsFlow(p); + + /* Add iface to the list */ + BypassedIfaceList *nifl = SCCalloc(1, sizeof(*nifl)); + if (nifl == NULL) { + return 0; + } + nifl->dev = p->livedev; + nifl->next = ifl; + FlowSetStorageById(f, g_flow_storage_id, nifl); + return 1; +} + +#endif /* HAVE_PACKET_XDP */ + +#endif diff --git a/src/util/ebpf.h b/src/util/ebpf.h new file mode 100644 index 000000000000..a534f0d6de4b --- /dev/null +++ b/src/util/ebpf.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2018 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#ifndef __UTIL_EBPF_H__ +#define __UTIL_EBPF_H__ + +#include "flow-bypass.h" + +#ifdef HAVE_PACKET_EBPF + +#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0) +#define XDP_FLAGS_SKB_MODE (1U << 1) +#define XDP_FLAGS_DRV_MODE (1U << 2) +#define XDP_FLAGS_HW_MODE (1U << 3) + +struct flowv4_keys { + __be32 src; + __be32 dst; + union { + __be32 ports; + __be16 port16[2]; + }; + __u8 ip_proto : 1; + __u16 vlan0 : 15; + __u16 vlan1; + __u16 vlan2; +}; + +struct flowv6_keys { + __be32 src[4]; + __be32 dst[4]; + union { + __be32 ports; + __be16 port16[2]; + }; + __u8 ip_proto : 1; + __u16 vlan0 : 15; + __u16 vlan1; + __u16 vlan2; +}; + +struct pair { + uint64_t packets; + uint64_t bytes; +}; + +typedef struct EBPFBypassData_ { + void *key[2]; + int mapfd; + int cpus_count; +} EBPFBypassData; + +#define EBPF_SOCKET_FILTER (1 << 0) +#define EBPF_XDP_CODE (1 << 1) +#define EBPF_PINNED_MAPS (1 << 2) +#define EBPF_XDP_HW_MODE (1 << 3) + +int EBPFGetMapFDByName(const char *iface, const char *name); +int EBPFLoadFile(const char *iface, const char *path, const char *section, int *val, + struct ebpf_timeout_config *config); +int EBPFSetupXDP(const char *iface, int fd, uint8_t flags); + +int EBPFCheckBypassedFlowCreate(ThreadVars *th_v, struct timespec *curtime, void *data); + +void EBPFRegisterExtension(void); + +void EBPFBuildCPUSet(ConfNode *node, char *iface); + +int EBPFSetPeerIface(const char *iface, const char *out_iface); + +int EBPFUpdateFlow(Flow *f, Packet *p, void *data); +bool EBPFBypassUpdate(Flow *f, void *data, time_t tsec); +void EBPFBypassFree(void *data); + +void EBPFDeleteKey(int fd, void *key); + +#define __bpf_percpu_val_align __attribute__((__aligned__(8))) + +#define BPF_DECLARE_PERCPU(type, name, nr_cpus) \ + struct { \ + type v; /* padding */ \ + } __bpf_percpu_val_align name[nr_cpus] +#define BPF_PERCPU(name, cpu) name[(cpu)].v + +#endif + +#endif diff --git a/src/util/enum.c b/src/util/enum.c new file mode 100644 index 000000000000..271237630656 --- /dev/null +++ b/src/util/enum.c @@ -0,0 +1,84 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata-common.h" + +#include "util/enum.h" +#include "util/debug.h" + +/** + * \brief Maps a string name to an enum value from the supplied table. Please + * specify the last element of any map table with a {NULL, -1}. If + * missing, you will be welcomed with a segfault :) + * + * \param enum_name Character string that has to be mapped to an enum value + * from the table + * \param table Enum-Char table, from which the mapping is retrieved + * + * \retval result The enum_value for the enum_name string or -1 on failure + */ +int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table) +{ + int result = -1; + + if (enum_name == NULL || table == NULL) { + SCLogDebug("Invalid argument(s) passed into SCMapEnumNameToValue"); + return -1; + } + + for (; table->enum_name != NULL; table++) { + if (strcasecmp(table->enum_name, enum_name) == 0) { + result = table->enum_value; + break; + } + } + + return result; +} + +/** + * \brief Maps an enum value to a string name, from the supplied table + * + * \param enum_value Enum_value that has to be mapped to a string_value + * from the table + * \param table Enum-Char table, from which the mapping is retrieved + * + * \retval result The enum_name for the enum_value supplied or NULL on failure + */ +const char *SCMapEnumValueToName(int enum_value, SCEnumCharMap *table) +{ + if (table == NULL) { + SCLogDebug("Invalid argument(s) passed into SCMapEnumValueToName"); + return NULL; + } + + for (; table->enum_name != NULL; table++) { + if (table->enum_value == enum_value) { + return table->enum_name; + } + } + + SCLogDebug("A enum by the value %d doesn't exist in this table", enum_value); + + return NULL; +} diff --git a/src/util/enum.h b/src/util/enum.h new file mode 100644 index 000000000000..c214af58d3d2 --- /dev/null +++ b/src/util/enum.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_ENUM_H__ +#define __UTIL_ENUM_H__ + +typedef struct SCEnumCharMap_ { + const char *enum_name; + int enum_value; +} SCEnumCharMap; + +int SCMapEnumNameToValue(const char *, SCEnumCharMap *); + +const char *SCMapEnumValueToName(int, SCEnumCharMap *); + +#endif /* __UTIL_ENUM_H__ */ diff --git a/src/util/error.c b/src/util/error.c new file mode 100644 index 000000000000..30c8f5a423f6 --- /dev/null +++ b/src/util/error.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Error utility functions + * + * \todo Needs refining of the error codes. Renaming with a prefix of SC_ERR, + * removal of duplicates and entries have to be made in util-error.c + */ + +#include "util/error.h" + +thread_local SCError sc_errno = SC_OK; +#define CASE_CODE(E) \ + case E: \ + return #E + +/** + * \brief Maps the error code, to its string equivalent + * + * \param The error code + * + * \retval The string equivalent for the error code + */ +const char *SCErrorToString(SCError err) +{ + switch (err) { + CASE_CODE(SC_OK); + + CASE_CODE(SC_ENOMEM); + CASE_CODE(SC_EINVAL); + CASE_CODE(SC_ELIMIT); + CASE_CODE(SC_EEXIST); + + CASE_CODE(SC_ERR_MAX); + } + + return "UNKNOWN_ERROR"; +} diff --git a/src/util-error.h b/src/util/error.h similarity index 100% rename from src/util-error.h rename to src/util/error.h diff --git a/src/util/exception-policy.c b/src/util/exception-policy.c new file mode 100644 index 000000000000..b918e4adf9c2 --- /dev/null +++ b/src/util/exception-policy.c @@ -0,0 +1,377 @@ +/* Copyright (C) 2022-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "packet.h" +#include "util/exception-policy.h" +#include "util/misc.h" +#include "stream-tcp-reassemble.h" +#include "action-globals.h" + +enum ExceptionPolicy g_eps_master_switch = EXCEPTION_POLICY_NOT_SET; +/** true if exception policy was defined in config */ +static bool g_eps_have_exception_policy = false; + +static const char *ExceptionPolicyEnumToString(enum ExceptionPolicy policy) +{ + switch (policy) { + case EXCEPTION_POLICY_NOT_SET: + return "ignore"; + case EXCEPTION_POLICY_AUTO: + return "auto"; + case EXCEPTION_POLICY_REJECT: + return "reject"; + case EXCEPTION_POLICY_BYPASS_FLOW: + return "bypass"; + case EXCEPTION_POLICY_DROP_FLOW: + return "drop-flow"; + case EXCEPTION_POLICY_DROP_PACKET: + return "drop-packet"; + case EXCEPTION_POLICY_PASS_PACKET: + return "pass-packet"; + case EXCEPTION_POLICY_PASS_FLOW: + return "pass-flow"; + } + // TODO we shouldn't reach this, but if we do, better not to leave this as simply null... + return "not set"; +} + +void SetMasterExceptionPolicy(void) +{ + g_eps_master_switch = ExceptionPolicyParse("exception-policy", true); +} + +static enum ExceptionPolicy GetMasterExceptionPolicy(const char *option) +{ + return g_eps_master_switch; +} + +void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason) +{ + SCLogDebug("start: pcap_cnt %" PRIu64 ", policy %u", p->pcap_cnt, policy); + switch (policy) { + case EXCEPTION_POLICY_AUTO: + break; + case EXCEPTION_POLICY_NOT_SET: + break; + case EXCEPTION_POLICY_REJECT: + SCLogDebug("EXCEPTION_POLICY_REJECT"); + PacketDrop(p, ACTION_REJECT, drop_reason); + if (!EngineModeIsIPS()) { + break; + } + /* fall through */ + case EXCEPTION_POLICY_DROP_FLOW: + SCLogDebug("EXCEPTION_POLICY_DROP_FLOW"); + if (p->flow) { + p->flow->flags |= FLOW_ACTION_DROP; + FlowSetNoPayloadInspectionFlag(p->flow); + FlowSetNoPacketInspectionFlag(p->flow); + StreamTcpDisableAppLayer(p->flow); + } + /* fall through */ + case EXCEPTION_POLICY_DROP_PACKET: + SCLogDebug("EXCEPTION_POLICY_DROP_PACKET"); + DecodeSetNoPayloadInspectionFlag(p); + DecodeSetNoPacketInspectionFlag(p); + PacketDrop(p, ACTION_DROP, drop_reason); + break; + case EXCEPTION_POLICY_BYPASS_FLOW: + PacketBypassCallback(p); + /* fall through */ + case EXCEPTION_POLICY_PASS_FLOW: + SCLogDebug("EXCEPTION_POLICY_PASS_FLOW"); + if (p->flow) { + p->flow->flags |= FLOW_ACTION_PASS; + FlowSetNoPacketInspectionFlag(p->flow); // TODO util func + } + /* fall through */ + case EXCEPTION_POLICY_PASS_PACKET: + SCLogDebug("EXCEPTION_POLICY_PASS_PACKET"); + DecodeSetNoPayloadInspectionFlag(p); + DecodeSetNoPacketInspectionFlag(p); + break; + } + SCLogDebug("end"); +} + +static enum ExceptionPolicy PickPacketAction(const char *option, enum ExceptionPolicy p) +{ + switch (p) { + case EXCEPTION_POLICY_DROP_FLOW: + SCLogWarning( + "flow actions not supported for %s, defaulting to \"drop-packet\"", option); + return EXCEPTION_POLICY_DROP_PACKET; + case EXCEPTION_POLICY_PASS_FLOW: + SCLogWarning( + "flow actions not supported for %s, defaulting to \"pass-packet\"", option); + return EXCEPTION_POLICY_PASS_PACKET; + case EXCEPTION_POLICY_BYPASS_FLOW: + SCLogWarning("flow actions not supported for %s, defaulting to \"ignore\"", option); + return EXCEPTION_POLICY_NOT_SET; + /* add all cases, to make sure new cases not handle will raise + * errors */ + case EXCEPTION_POLICY_DROP_PACKET: + break; + case EXCEPTION_POLICY_PASS_PACKET: + break; + case EXCEPTION_POLICY_REJECT: + break; + case EXCEPTION_POLICY_NOT_SET: + break; + case EXCEPTION_POLICY_AUTO: + break; + } + return p; +} + +static enum ExceptionPolicy ExceptionPolicyConfigValueParse( + const char *option, const char *value_str) +{ + enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; + if (strcmp(value_str, "drop-flow") == 0) { + policy = EXCEPTION_POLICY_DROP_FLOW; + } else if (strcmp(value_str, "pass-flow") == 0) { + policy = EXCEPTION_POLICY_PASS_FLOW; + } else if (strcmp(value_str, "bypass") == 0) { + policy = EXCEPTION_POLICY_BYPASS_FLOW; + } else if (strcmp(value_str, "drop-packet") == 0) { + policy = EXCEPTION_POLICY_DROP_PACKET; + } else if (strcmp(value_str, "pass-packet") == 0) { + policy = EXCEPTION_POLICY_PASS_PACKET; + } else if (strcmp(value_str, "reject") == 0) { + policy = EXCEPTION_POLICY_REJECT; + } else if (strcmp(value_str, "ignore") == 0) { // TODO name? + policy = EXCEPTION_POLICY_NOT_SET; + } else if (strcmp(value_str, "auto") == 0) { + policy = EXCEPTION_POLICY_AUTO; + } else { + FatalErrorOnInit( + "\"%s\" is not a valid exception policy value. Valid options are drop-flow, " + "pass-flow, bypass, reject, drop-packet, pass-packet, ignore or auto.", + value_str); + } + + return policy; +} + +/* Select an exception policy in case the configuration value was set to 'auto' */ +static enum ExceptionPolicy ExceptionPolicyPickAuto(bool midstream_enabled, bool support_flow) +{ + enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; + if (!midstream_enabled && EngineModeIsIPS()) { + if (support_flow) { + policy = EXCEPTION_POLICY_DROP_FLOW; + } else { + policy = EXCEPTION_POLICY_DROP_PACKET; + } + } + return policy; +} + +static enum ExceptionPolicy ExceptionPolicyMasterParse(const char *value) +{ + enum ExceptionPolicy policy = ExceptionPolicyConfigValueParse("exception-policy", value); + if (!EngineModeIsIPS() && + (policy == EXCEPTION_POLICY_DROP_PACKET || policy == EXCEPTION_POLICY_DROP_FLOW)) { + policy = EXCEPTION_POLICY_NOT_SET; + } + g_eps_have_exception_policy = true; + + SCLogInfo("master exception-policy set to: %s", ExceptionPolicyEnumToString(policy)); + + return policy; +} + +static enum ExceptionPolicy ExceptionPolicyGetDefault( + const char *option, bool support_flow, bool midstream) +{ + enum ExceptionPolicy p = EXCEPTION_POLICY_NOT_SET; + if (g_eps_have_exception_policy) { + p = GetMasterExceptionPolicy(option); + + if (p == EXCEPTION_POLICY_AUTO) { + p = ExceptionPolicyPickAuto(midstream, support_flow); + } + + if (!support_flow) { + p = PickPacketAction(option, p); + } + SCLogConfig("%s: %s (defined via 'exception-policy' master switch)", option, + ExceptionPolicyEnumToString(p)); + return p; + } else if (EngineModeIsIPS() && !midstream) { + p = EXCEPTION_POLICY_DROP_FLOW; + } + SCLogConfig("%s: %s (defined via 'built-in default' for %s-mode)", option, + ExceptionPolicyEnumToString(p), EngineModeIsIPS() ? "IPS" : "IDS"); + + return p; +} + +enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow) +{ + enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; + const char *value_str = NULL; + + if ((ConfGet(option, &value_str) == 1) && value_str != NULL) { + if (strcmp(option, "exception-policy") == 0) { + policy = ExceptionPolicyMasterParse(value_str); + } else { + policy = ExceptionPolicyConfigValueParse(option, value_str); + if (policy == EXCEPTION_POLICY_AUTO) { + policy = ExceptionPolicyPickAuto(false, support_flow); + } + if (!support_flow) { + policy = PickPacketAction(option, policy); + } + SCLogConfig("%s: %s", option, ExceptionPolicyEnumToString(policy)); + } + } else { + policy = ExceptionPolicyGetDefault(option, support_flow, false); + } + + return policy; +} + +enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled) +{ + enum ExceptionPolicy policy = EXCEPTION_POLICY_NOT_SET; + const char *value_str = NULL; + /* policy was set directly */ + if ((ConfGet("stream.midstream-policy", &value_str)) == 1 && value_str != NULL) { + policy = ExceptionPolicyConfigValueParse("midstream-policy", value_str); + if (policy == EXCEPTION_POLICY_AUTO) { + policy = ExceptionPolicyPickAuto(midstream_enabled, true); + } else if (midstream_enabled) { + if (policy != EXCEPTION_POLICY_NOT_SET && policy != EXCEPTION_POLICY_PASS_FLOW) { + FatalErrorOnInit( + "Error parsing stream.midstream-policy from config file. \"%s\" is " + "not a valid exception policy when midstream is enabled. Valid options " + "are pass-flow and ignore.", + value_str); + } + } + if (!EngineModeIsIPS()) { + if (policy == EXCEPTION_POLICY_DROP_FLOW) { + FatalErrorOnInit( + "Error parsing stream.midstream-policy from config file. \"%s\" is " + "not a valid exception policy in IDS mode. See our documentation for a " + "list of all possible values.", + value_str); + } + } + } else { + policy = ExceptionPolicyGetDefault("stream.midstream-policy", true, midstream_enabled); + } + + if (policy == EXCEPTION_POLICY_PASS_PACKET || policy == EXCEPTION_POLICY_DROP_PACKET) { + FatalErrorOnInit("Error parsing stream.midstream-policy from config file. \"%s\" is " + "not valid for this exception policy. See our documentation for a list of " + "all possible values.", + value_str); + } + + return policy; +} + +#ifndef DEBUG + +int ExceptionSimulationCommandLineParser(const char *name, const char *arg) +{ + return 0; +} + +#else + +/* exception policy simulation (eps) handling */ + +uint64_t g_eps_applayer_error_offset_ts = UINT64_MAX; +uint64_t g_eps_applayer_error_offset_tc = UINT64_MAX; +uint64_t g_eps_pcap_packet_loss = UINT64_MAX; +uint64_t g_eps_stream_ssn_memcap = UINT64_MAX; +uint64_t g_eps_stream_reassembly_memcap = UINT64_MAX; +uint64_t g_eps_flow_memcap = UINT64_MAX; +uint64_t g_eps_defrag_memcap = UINT64_MAX; +bool g_eps_is_alert_queue_fail_mode = false; + +/* 1: parsed, 0: not for us, -1: error */ +int ExceptionSimulationCommandLineParser(const char *name, const char *arg) +{ + if (strcmp(name, "simulate-applayer-error-at-offset-ts") == 0) { + BUG_ON(arg == NULL); + uint64_t offset = 0; + if (ParseSizeStringU64(arg, &offset) < 0) { + return -1; + } + g_eps_applayer_error_offset_ts = offset; + } else if (strcmp(name, "simulate-applayer-error-at-offset-tc") == 0) { + BUG_ON(arg == NULL); + uint64_t offset = 0; + if (ParseSizeStringU64(arg, &offset) < 0) { + return TM_ECODE_FAILED; + } + g_eps_applayer_error_offset_tc = offset; + } else if (strcmp(name, "simulate-packet-loss") == 0) { + BUG_ON(arg == NULL); + uint64_t pkt_num = 0; + if (ParseSizeStringU64(arg, &pkt_num) < 0) { + return TM_ECODE_FAILED; + } + g_eps_pcap_packet_loss = pkt_num; + } else if (strcmp(name, "simulate-packet-tcp-reassembly-memcap") == 0) { + BUG_ON(arg == NULL); + uint64_t pkt_num = 0; + if (ParseSizeStringU64(arg, &pkt_num) < 0) { + return TM_ECODE_FAILED; + } + g_eps_stream_reassembly_memcap = pkt_num; + } else if (strcmp(name, "simulate-packet-tcp-ssn-memcap") == 0) { + BUG_ON(arg == NULL); + uint64_t pkt_num = 0; + if (ParseSizeStringU64(arg, &pkt_num) < 0) { + return TM_ECODE_FAILED; + } + g_eps_stream_ssn_memcap = pkt_num; + } else if (strcmp(name, "simulate-packet-flow-memcap") == 0) { + BUG_ON(arg == NULL); + uint64_t pkt_num = 0; + if (ParseSizeStringU64(arg, &pkt_num) < 0) { + return TM_ECODE_FAILED; + } + g_eps_flow_memcap = pkt_num; + } else if (strcmp(name, "simulate-packet-defrag-memcap") == 0) { + BUG_ON(arg == NULL); + uint64_t pkt_num = 0; + if (ParseSizeStringU64(arg, &pkt_num) < 0) { + return TM_ECODE_FAILED; + } + g_eps_defrag_memcap = pkt_num; + } else if (strcmp(name, "simulate-alert-queue-realloc-failure") == 0) { + g_eps_is_alert_queue_fail_mode = true; + } else { + // not for us + return 0; + } + return 1; +} +#endif diff --git a/src/util-exception-policy.h b/src/util/exception-policy.h similarity index 100% rename from src/util-exception-policy.h rename to src/util/exception-policy.h diff --git a/src/util/file-decompression.c b/src/util/file-decompression.c new file mode 100644 index 000000000000..98c226ae5708 --- /dev/null +++ b/src/util/file-decompression.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Giuseppe Longo + * + * \brief Decompress files transferred via HTTP corresponding to file_data + * keyword. + * + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "detect-engine.h" +#include "app-layer/http/parser.h" + +#include "util/file-decompression.h" +#include "util/file-swf-decompression.h" +#include "util/misc.h" +#include "util/print.h" + +#define SWF_ZLIB_MIN_VERSION 0x06 +#define SWF_LZMA_MIN_VERSION 0x0D + +int FileIsSwfFile(const uint8_t *buffer, uint32_t buffer_len) +{ + if (buffer_len >= 3 && buffer[1] == 'W' && buffer[2] == 'S') { + if (buffer[0] == 'F') + return FILE_SWF_NO_COMPRESSION; + else if (buffer[0] == 'C') + return FILE_SWF_ZLIB_COMPRESSION; + else if (buffer[0] == 'Z') + return FILE_SWF_LZMA_COMPRESSION; + else + return FILE_IS_NOT_SWF; + } + + return FILE_IS_NOT_SWF; +} + +/** + * \brief This function decompresses a buffer with zlib/lzma algorithm + * + * \param buffer compressed buffer + * \param buffer_len compressed buffer length + * \param decompressed_buffer buffer that store decompressed data + * \param decompressed_buffer_len decompressed data length + * \param swf_type decompression algorithm to use + * \param decompress_depth how much decompressed data we want to store + * \param compress_depth how much compressed data we want to decompress + * + * \retval 1 if decompression works + * \retval 0 an error occurred, and event set + */ +int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len, DetectEngineThreadCtx *det_ctx, + InspectionBuffer *out_buffer, int swf_type, uint32_t decompress_depth, + uint32_t compress_depth) +{ + int r = 0; + + int compression_type = FileIsSwfFile(buffer, buffer_len); + if (compression_type == FILE_SWF_NO_COMPRESSION) { + return 0; + } + + uint32_t offset = 0; + if (compression_type == FILE_SWF_ZLIB_COMPRESSION) { + /* compressed data start from the 4th bytes */ + offset = 8; + } else if (compression_type == FILE_SWF_LZMA_COMPRESSION) { + /* compressed data start from the 17th bytes */ + offset = 17; + } + + if (buffer_len <= offset) { + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_LENGTH); + return 0; + } + + uint32_t compressed_data_len = 0; + if (compress_depth > 0 && compress_depth <= buffer_len - offset) { + compressed_data_len = compress_depth; + } else { + compressed_data_len = buffer_len - offset; + } + + /* get swf version */ + uint8_t swf_version = FileGetSwfVersion(buffer, buffer_len); + if (compression_type == FILE_SWF_ZLIB_COMPRESSION && swf_version < SWF_ZLIB_MIN_VERSION) { + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_VERSION); + return 0; + } + if (compression_type == FILE_SWF_LZMA_COMPRESSION && swf_version < SWF_LZMA_MIN_VERSION) { + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_INVALID_SWF_VERSION); + return 0; + } + + /* get flash decompressed file length */ + uint32_t decompressed_swf_len = FileGetSwfDecompressedLen(buffer, buffer_len); + if (decompressed_swf_len == 0) { + decompressed_swf_len = MIN_SWF_LEN; + } + + /* if decompress_depth is 0, keep the flash file length */ + uint32_t decompressed_data_len = + (decompress_depth == 0) ? decompressed_swf_len : decompress_depth; + decompressed_data_len += 8; + + /* make sure the inspection buffer has enough space */ + InspectionBufferCheckAndExpand(out_buffer, decompressed_data_len); + if (out_buffer->size < decompressed_data_len) { + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_NO_MEM); + return 0; + } + out_buffer->len = decompressed_data_len; + + /* + * FWS format + * | 4 bytes | 4 bytes | n bytes | + * | 'FWS' + version | script len | data | + */ + out_buffer->buf[0] = 'F'; + out_buffer->buf[1] = 'W'; + out_buffer->buf[2] = 'S'; + out_buffer->buf[3] = swf_version; + memcpy(out_buffer->buf + 4, &decompressed_swf_len, 4); + memset(out_buffer->buf + 8, 0, decompressed_data_len - 8); + + if ((swf_type == HTTP_SWF_COMPRESSION_ZLIB || swf_type == HTTP_SWF_COMPRESSION_BOTH) && + compression_type == FILE_SWF_ZLIB_COMPRESSION) { + /* the first 8 bytes represents the fws header, see 'FWS format' above. + * data will start from 8th bytes + */ + r = FileSwfZlibDecompression(det_ctx, (uint8_t *)buffer + offset, compressed_data_len, + out_buffer->buf + 8, out_buffer->len - 8); + if (r == 0) + goto error; + + } else if ((swf_type == HTTP_SWF_COMPRESSION_LZMA || swf_type == HTTP_SWF_COMPRESSION_BOTH) && + compression_type == FILE_SWF_LZMA_COMPRESSION) { + /* we need to setup the lzma header */ + /* + * | 5 bytes | 8 bytes | n bytes | + * | LZMA properties | Uncompressed length | Compressed data | + */ + compressed_data_len += 13; + uint8_t compressed_data[compressed_data_len]; + /* put lzma properties */ + memcpy(compressed_data, buffer + 12, 5); + /* put lzma end marker */ + memset(compressed_data + 5, 0xFF, 8); + /* put compressed data */ + memcpy(compressed_data + 13, buffer + offset, compressed_data_len - 13); + + /* the first 8 bytes represents the fws header, see 'FWS format' above. + * data will start from 8th bytes + */ + r = FileSwfLzmaDecompression(det_ctx, compressed_data, compressed_data_len, + out_buffer->buf + 8, out_buffer->len - 8); + if (r == 0) + goto error; + } else { + goto error; + } + + /* all went well so switch the buffer's inspect pointer/size + * to use the new data. */ + out_buffer->inspect = out_buffer->buf; + out_buffer->inspect_len = out_buffer->len; + + return 1; + +error: + return 0; +} diff --git a/src/util/file-decompression.h b/src/util/file-decompression.h new file mode 100644 index 000000000000..ce9074e4611d --- /dev/null +++ b/src/util/file-decompression.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Giuseppe Longo + * + * + */ + +#ifndef __UTIL_FILE_DECOMPRESSION_H__ +#define __UTIL_FILE_DECOMPRESSION_H__ + +#include "../detect.h" + +enum { + FILE_IS_NOT_SWF = 0, + FILE_SWF_NO_COMPRESSION, + FILE_SWF_ZLIB_COMPRESSION, + FILE_SWF_LZMA_COMPRESSION, +}; + +int FileIsSwfFile(const uint8_t *buffer, uint32_t buffer_len); +int FileSwfDecompression(const uint8_t *buffer, uint32_t buffer_len, DetectEngineThreadCtx *det_ctx, + InspectionBuffer *out_buffer, int swf_type, uint32_t decompress_depth, + uint32_t compress_depth); + +#endif /* __UTIL_FILE_DECOMPRESSION_H__ */ diff --git a/src/util/file-swf-decompression.c b/src/util/file-swf-decompression.c new file mode 100644 index 000000000000..48b71f613dca --- /dev/null +++ b/src/util/file-swf-decompression.c @@ -0,0 +1,175 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Giuseppe Longo + * + */ + +#include "suricata.h" +#include "suricata-common.h" + +#include "app-layer/http/parser.h" + +#include "util/file-decompression.h" +#include "util/file-swf-decompression.h" +#include "util/misc.h" +#include "util/print.h" +#include "util/validate.h" + +#include "rust.h" + +#include + +#define MAX_SWF_DECOMPRESSED_LEN 50000000 +/* + * Return uncompressed file length + * in little-endian order + */ +uint32_t FileGetSwfDecompressedLen(const uint8_t *buffer, const uint32_t buffer_len) +{ + if (buffer_len < 8) { + return 0; + } + + uint32_t a = buffer[4]; + uint32_t b = buffer[5]; + uint32_t c = buffer[6]; + uint32_t d = buffer[7]; + + uint32_t value = + (((a & 0xff) << 24UL) | ((b & 0xff) << 16UL) | ((c & 0xff) << 8UL) | (d & 0xff)); + + uint32_t len = (((value >> 24) & 0x000000FFUL) | ((value >> 8) & 0x0000FF00UL) | + ((value << 8) & 0x00FF0000UL) | ((value << 24) & 0xFF000000UL)); + + return MIN(MAX_SWF_DECOMPRESSED_LEN, len); +} + +uint8_t FileGetSwfVersion(const uint8_t *buffer, const uint32_t buffer_len) +{ + if (buffer_len > 3) + return buffer[3]; + + return 0; +} + +/* CWS format */ +/* + * | 4 bytes | 4 bytes | n bytes | + * | 'CWS' + version | script len | compressed data | + */ +int FileSwfZlibDecompression(DetectEngineThreadCtx *det_ctx, uint8_t *compressed_data, + uint32_t compressed_data_len, uint8_t *decompressed_data, uint32_t decompressed_data_len) +{ + int ret = 1; + z_stream infstream; + memset(&infstream, 0, sizeof(infstream)); + infstream.zalloc = Z_NULL; + infstream.zfree = Z_NULL; + infstream.opaque = Z_NULL; + + infstream.avail_in = (uInt)compressed_data_len; + infstream.next_in = (Bytef *)compressed_data; + infstream.avail_out = (uInt)decompressed_data_len; + infstream.next_out = (Bytef *)decompressed_data; + + int result = inflateInit(&infstream); + if (result != Z_OK) { + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_UNKNOWN_ERROR); + return 0; + } + + result = inflate(&infstream, Z_NO_FLUSH); + switch (result) { + case Z_STREAM_END: + break; + case Z_OK: + break; + case Z_DATA_ERROR: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_DATA_ERROR); + ret = 0; + break; + case Z_STREAM_ERROR: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_STREAM_ERROR); + ret = 0; + break; + case Z_BUF_ERROR: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_BUF_ERROR); + ret = 0; + break; + default: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_Z_UNKNOWN_ERROR); + ret = 0; + break; + } + inflateEnd(&infstream); + + return ret; +} + +/* ZWS format */ +/* + * | 4 bytes | 4 bytes | 4 bytes | 5 bytes | n bytes | 6 bytes | + * | 'ZWS' + version | script len | compressed len | LZMA props | LZMA data | LZMA end marker | + */ +int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, uint8_t *compressed_data, + uint32_t compressed_data_len, uint8_t *decompressed_data, uint32_t decompressed_data_len) +{ + int ret = 0; + + size_t inprocessed = compressed_data_len; + size_t outprocessed = decompressed_data_len; + + ret = lzma_decompress(compressed_data, &inprocessed, decompressed_data, &outprocessed, + MAX_SWF_DECOMPRESSED_LEN); + + switch (ret) { + case LzmaOk: + ret = 1; + break; + case LzmaIoError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_IO_ERROR); + ret = 0; + break; + case LzmaHeaderTooShortError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR); + ret = 0; + break; + case LzmaError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_DECODER_ERROR); + ret = 0; + break; + case LzmaMemoryError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR); + ret = 0; + break; + case LzmaXzError: + /* We should not see XZ compressed SWF files */ + DEBUG_VALIDATE_BUG_ON(ret == LzmaXzError); + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_XZ_ERROR); + ret = 0; + break; + default: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR); + ret = 0; + break; + } + + return ret; +} diff --git a/src/util/file-swf-decompression.h b/src/util/file-swf-decompression.h new file mode 100644 index 000000000000..7855d694a3e5 --- /dev/null +++ b/src/util/file-swf-decompression.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Giuseppe Longo + * + * + */ + +#ifndef __UTIL_FILE_SWF_DECOMPRESSION_H__ +#define __UTIL_FILE_SWF_DECOMPRESSION_H__ + +/* If we don't have the decompressed data len, + * we use a default value. + */ +#define MIN_SWF_LEN 2920 + +uint8_t FileGetSwfVersion(const uint8_t *buffer, const uint32_t buffer_len); +uint32_t FileGetSwfDecompressedLen(const uint8_t *buffer, uint32_t buffer_len); +int FileSwfZlibDecompression(DetectEngineThreadCtx *det_ctx, uint8_t *compressed_data, + uint32_t compressed_data_len, uint8_t *decompressed_data, uint32_t decompressed_data_len); +int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, uint8_t *compressed_data, + uint32_t compressed_data_len, uint8_t *decompressed_data, uint32_t decompressed_data_len); + +#endif /* __UTIL_FILE_SWF_DECOMPRESSION_H__ */ diff --git a/src/util/file.c b/src/util/file.c new file mode 100644 index 000000000000..edbfd9337aef --- /dev/null +++ b/src/util/file.c @@ -0,0 +1,1219 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Pablo Rincon + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "flow.h" +#include "stream.h" +#include "stream-tcp.h" +#include "runmodes.h" +#include "util/hash.h" +#include "util/debug.h" +#include "util/memcmp.h" +#include "util/print.h" +#include "app-layer-parser.h" +#include "util/validate.h" +#include "rust.h" + +extern int g_detect_disabled; + +/** \brief mask of file flags we'll not set + * This mask is set based on global file settings and + * cannot be overridden by detection. + */ +static uint16_t g_file_flow_mask = 0; + +/** \brief switch to force filestore on all files + * regardless of the rules. + */ +static int g_file_force_filestore = 0; + +/** \brief switch to force magic checks on all files + * regardless of the rules. + */ +static int g_file_force_magic = 0; + +/** \brief switch to force md5 calculation on all files + * regardless of the rules. + */ +static int g_file_force_md5 = 0; + +/** \brief switch to force sha1 calculation on all files + * regardless of the rules. + */ +static int g_file_force_sha1 = 0; + +/** \brief switch to force sha256 calculation on all files + * regardless of the rules. + */ +static int g_file_force_sha256 = 0; + +/** \brief switch to force tracking off all files + * regardless of the rules. + */ +static int g_file_force_tracking = 0; + +/** \brief switch to use g_file_store_reassembly_depth + * to reassembly files + */ +static int g_file_store_enable = 0; + +/** \brief stream_config.reassembly_depth equivalent + * for files + */ +static uint32_t g_file_store_reassembly_depth = 0; + +/* prototypes */ +static void FileFree(File *, const StreamingBufferConfig *cfg); +static void FileEndSha256(File *ff); + +void FileForceFilestoreEnable(void) +{ + g_file_force_filestore = 1; + g_file_flow_mask |= (FLOWFILE_NO_STORE_TS | FLOWFILE_NO_STORE_TC); +} + +void FileForceMagicEnable(void) +{ + g_file_force_magic = 1; + g_file_flow_mask |= (FLOWFILE_NO_MAGIC_TS | FLOWFILE_NO_MAGIC_TC); +} + +void FileForceMd5Enable(void) +{ + g_file_force_md5 = 1; + g_file_flow_mask |= (FLOWFILE_NO_MD5_TS | FLOWFILE_NO_MD5_TC); +} + +void FileForceSha1Enable(void) +{ + g_file_force_sha1 = 1; + g_file_flow_mask |= (FLOWFILE_NO_SHA1_TS | FLOWFILE_NO_SHA1_TC); +} + +void FileForceSha256Enable(void) +{ + g_file_force_sha256 = 1; + g_file_flow_mask |= (FLOWFILE_NO_SHA256_TS | FLOWFILE_NO_SHA256_TC); +} + +int FileForceFilestore(void) +{ + return g_file_force_filestore; +} + +void FileReassemblyDepthEnable(uint32_t size) +{ + g_file_store_enable = 1; + g_file_store_reassembly_depth = size; +} + +uint32_t FileReassemblyDepth(void) +{ + if (g_file_store_enable == 1) + return g_file_store_reassembly_depth; + else + return stream_config.reassembly_depth; +} + +int FileForceMagic(void) +{ + return g_file_force_magic; +} + +int FileForceMd5(void) +{ + return g_file_force_md5; +} + +int FileForceSha1(void) +{ + return g_file_force_sha1; +} + +int FileForceSha256(void) +{ + return g_file_force_sha256; +} + +void FileForceTrackingEnable(void) +{ + g_file_force_tracking = 1; + g_file_flow_mask |= (FLOWFILE_NO_SIZE_TS | FLOWFILE_NO_SIZE_TC); +} + +/** + * \brief Function to parse forced file hashing configuration. + */ +void FileForceHashParseCfg(ConfNode *conf) +{ + BUG_ON(conf == NULL); + + ConfNode *forcehash_node = NULL; + + /* legacy option */ + const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); + if (force_md5 != NULL) { + SCLogWarning("deprecated 'force-md5' option " + "found. Please use 'force-hash: [md5]' instead"); + + if (ConfValIsTrue(force_md5)) { + if (g_disable_hashing) { + SCLogInfo( + "not forcing md5 calculation for logged files: hashing globally disabled"); + } else { + FileForceMd5Enable(); + SCLogInfo("forcing md5 calculation for logged files"); + } + } + } + + if (conf != NULL) + forcehash_node = ConfNodeLookupChild(conf, "force-hash"); + + if (forcehash_node != NULL) { + ConfNode *field = NULL; + + TAILQ_FOREACH (field, &forcehash_node->head, next) { + if (strcasecmp("md5", field->val) == 0) { + if (g_disable_hashing) { + SCLogInfo("not forcing md5 calculation for logged files: hashing globally " + "disabled"); + } else { + FileForceMd5Enable(); + SCLogConfig("forcing md5 calculation for logged or stored files"); + } + } + + if (strcasecmp("sha1", field->val) == 0) { + if (g_disable_hashing) { + SCLogInfo("not forcing sha1 calculation for logged files: hashing globally " + "disabled"); + } else { + FileForceSha1Enable(); + SCLogConfig("forcing sha1 calculation for logged or stored files"); + } + } + + if (strcasecmp("sha256", field->val) == 0) { + if (g_disable_hashing) { + SCLogInfo("not forcing sha256 calculation for logged files: hashing globally " + "disabled"); + } else { + FileForceSha256Enable(); + SCLogConfig("forcing sha256 calculation for logged or stored files"); + } + } + } + } +} + +uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction) +{ + uint16_t flags = 0; + + if (direction == STREAM_TOSERVER) { + if ((flow_file_flags & (FLOWFILE_NO_STORE_TS | FLOWFILE_STORE)) == FLOWFILE_NO_STORE_TS) { + flags |= FILE_NOSTORE; + } + + if (flow_file_flags & FLOWFILE_NO_MAGIC_TS) { + flags |= FILE_NOMAGIC; + } + + if (flow_file_flags & FLOWFILE_NO_MD5_TS) { + flags |= FILE_NOMD5; + } + + if (flow_file_flags & FLOWFILE_NO_SHA1_TS) { + flags |= FILE_NOSHA1; + } + + if (flow_file_flags & FLOWFILE_NO_SHA256_TS) { + flags |= FILE_NOSHA256; + } + } else { + if ((flow_file_flags & (FLOWFILE_NO_STORE_TC | FLOWFILE_STORE)) == FLOWFILE_NO_STORE_TC) { + flags |= FILE_NOSTORE; + } + + if (flow_file_flags & FLOWFILE_NO_MAGIC_TC) { + flags |= FILE_NOMAGIC; + } + + if (flow_file_flags & FLOWFILE_NO_MD5_TC) { + flags |= FILE_NOMD5; + } + + if (flow_file_flags & FLOWFILE_NO_SHA1_TC) { + flags |= FILE_NOSHA1; + } + + if (flow_file_flags & FLOWFILE_NO_SHA256_TC) { + flags |= FILE_NOSHA256; + } + } + if (flow_file_flags & FLOWFILE_STORE) { + flags |= FILE_STORE; + } + DEBUG_VALIDATE_BUG_ON((flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); + + SCLogDebug("direction %02x flags %02x", direction, flags); + return flags; +} + +uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction) +{ + return FileFlowFlagsToFlags(flow->file_flags, direction); +} + +void FileApplyTxFlags(const AppLayerTxData *txd, const uint8_t direction, File *file) +{ + SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags, + (file->flags & FILE_STORE) ? "true" : "false", + (file->flags & FILE_NOSTORE) ? "true" : "false"); + uint16_t update_flags = FileFlowFlagsToFlags(txd->file_flags, direction); + DEBUG_VALIDATE_BUG_ON( + (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); + if (file->flags & FILE_STORE) + update_flags &= ~FILE_NOSTORE; + + file->flags |= update_flags; + SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags, + (file->flags & FILE_STORE) ? "true" : "false", + (file->flags & FILE_NOSTORE) ? "true" : "false"); + DEBUG_VALIDATE_BUG_ON( + (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE)); +} + +static int FileMagicSize(void) +{ + /** \todo make this size configurable */ + return 512; +} + +/** + * \brief get the size of the file data + * + * This doesn't reflect how much of the file we have in memory, just the + * total size of filedata so far. + */ +uint64_t FileDataSize(const File *file) +{ + if (file != NULL && file->sb != NULL) { + const uint64_t size = StreamingBufferGetConsecutiveDataRightEdge(file->sb); + SCLogDebug("returning %" PRIu64, size); + return size; + } + SCLogDebug("returning 0 (default)"); + return 0; +} + +/** + * \brief get the size of the file + * + * This doesn't reflect how much of the file we have in memory, just the + * total size of file so far. + */ +uint64_t FileTrackedSize(const File *file) +{ + if (file != NULL) { + return file->size; + } + return 0; +} + +/** \brief test if file is ready to be pruned + * + * If a file is in the 'CLOSED' state, it means it has been processed + * completely by the pipeline in the correct direction. So we can + * prune it then. + * + * For other states, as well as for files we may not need to track + * until the close state, more specific checks are done. + * + * Also does house keeping within the file: move streaming buffer + * forward if possible. + * + * \retval 1 prune (free) this file + * \retval 0 file not ready to be freed + */ +static int FilePruneFile(File *file, const StreamingBufferConfig *cfg) +{ + SCEnter(); + + /* file is done when state is closed+, logging/storing is done (if any) */ + SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s", file->state, + (file->state >= FILE_STATE_CLOSED) ? "yes" : "no"); + if (file->state >= FILE_STATE_CLOSED) { + SCReturnInt(1); + } + +#ifdef HAVE_MAGIC + if (!(file->flags & FILE_NOMAGIC)) { + /* need magic but haven't set it yet, bail out */ + if (file->magic == NULL) + SCReturnInt(0); + else + SCLogDebug("file->magic %s", file->magic); + } else { + SCLogDebug("file->flags & FILE_NOMAGIC == true"); + } +#endif + uint64_t left_edge = FileDataSize(file); + if (file->flags & FILE_STORE) { + left_edge = MIN(left_edge, file->content_stored); + } + + if (!g_detect_disabled) { + left_edge = MIN(left_edge, file->content_inspected); + /* if file has inspect window and min size set, we + * do some house keeping here */ + if (file->inspect_window != 0 && file->inspect_min_size != 0) { + const uint64_t file_offset = StreamingBufferGetOffset(file->sb); + uint32_t window = file->inspect_window; + if (file_offset == 0) + window = MAX(window, file->inspect_min_size); + + uint64_t file_size = FileDataSize(file); + uint64_t data_size = file_size - file_offset; + + SCLogDebug("window %" PRIu32 ", file_size %" PRIu64 ", data_size %" PRIu64, window, + file_size, data_size); + + if (data_size > (window * 3)) { + file->content_inspected = MAX(file->content_inspected, file->size - window); + SCLogDebug("file->content_inspected now %" PRIu64, file->content_inspected); + } + + if (left_edge > window) + left_edge -= window; + else + left_edge = 0; + } + } + + if (left_edge) { + SCLogDebug("sliding to %" PRIu64, left_edge); + StreamingBufferSlideToOffset(file->sb, cfg, left_edge); + } + + SCReturnInt(0); +} + +#ifdef DEBUG +#define P(file, flag) ((file)->flags & (flag)) ? "true" : "false" +void FilePrintFlags(const File *file) +{ + SCLogDebug("file %p flags %04x " + "FILE_TRUNCATED %s " + "FILE_NOMAGIC %s " + "FILE_NOMD5 %s " + "FILE_MD5 %s " + "FILE_NOSHA1 %s " + "FILE_SHA1 %s " + "FILE_NOSHA256 %s " + "FILE_SHA256 %s " + "FILE_LOGGED %s " + "FILE_NOSTORE %s " + "FILE_STORE %s " + "FILE_STORED %s " + "FILE_NOTRACK %s " + "FILE_HAS_GAPS %s", + file, file->flags, P(file, FILE_TRUNCATED), P(file, FILE_NOMAGIC), P(file, FILE_NOMD5), + P(file, FILE_MD5), P(file, FILE_NOSHA1), P(file, FILE_SHA1), P(file, FILE_NOSHA256), + P(file, FILE_SHA256), P(file, FILE_LOGGED), P(file, FILE_NOSTORE), P(file, FILE_STORE), + P(file, FILE_STORED), P(file, FILE_NOTRACK), P(file, FILE_HAS_GAPS)); +} +#undef P +#endif + +static void FilePrune(FileContainer *ffc, const StreamingBufferConfig *cfg) +{ + SCEnter(); + SCLogDebug("ffc %p head %p", ffc, ffc->head); + File *file = ffc->head; + File *prev = NULL; + + while (file) { +#ifdef DEBUG + FilePrintFlags(file); +#endif + if (FilePruneFile(file, cfg) == 0) { + prev = file; + file = file->next; + continue; + } + + SCLogDebug("removing file %p", file); + + File *file_next = file->next; + + if (prev) + prev->next = file_next; + /* update head and tail */ + if (file == ffc->head) + ffc->head = file_next; + if (file == ffc->tail) + ffc->tail = prev; + + FileFree(file, cfg); + file = file_next; + } + SCReturn; +} + +/** + * \brief allocate a FileContainer + * + * \retval new newly allocated FileContainer + * \retval NULL error + */ +FileContainer *FileContainerAlloc(void) +{ + FileContainer *new = SCCalloc(1, sizeof(FileContainer)); + if (unlikely(new == NULL)) { + SCLogError("Error allocating mem"); + return NULL; + } + new->head = new->tail = NULL; + return new; +} + +/** + * \brief Recycle a FileContainer + * + * \param ffc FileContainer + */ +void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg) +{ + SCLogDebug("ffc %p", ffc); + if (ffc == NULL) + return; + + File *cur = ffc->head; + File *next = NULL; + for (; cur != NULL; cur = next) { + next = cur->next; + FileFree(cur, cfg); + } + ffc->head = ffc->tail = NULL; +} + +/** + * \brief Free a FileContainer + * + * \param ffc FileContainer + */ +void FileContainerFree(FileContainer *ffc, const StreamingBufferConfig *cfg) +{ + SCLogDebug("ffc %p", ffc); + if (ffc == NULL) + return; + + File *ptr = ffc->head; + File *next = NULL; + for (; ptr != NULL; ptr = next) { + next = ptr->next; + FileFree(ptr, cfg); + } + ffc->head = ffc->tail = NULL; + SCFree(ffc); +} + +/** + * \brief Alloc a new File + * + * \param name character array containing the name (not a string) + * \param name_len length in bytes of the name + * + * \retval new File object or NULL on error + */ +static File *FileAlloc(const uint8_t *name, uint16_t name_len) +{ + File *new = SCCalloc(1, sizeof(File)); + if (unlikely(new == NULL)) { + SCLogError("Error allocating mem"); + return NULL; + } + + new->name = SCMalloc(name_len); + if (new->name == NULL) { + SCFree(new); + return NULL; + } + + new->name_len = name_len; + memcpy(new->name, name, name_len); + + new->sid_cnt = 0; + new->sid_max = 8; + /* SCMalloc() is allowed to fail here because sid well be checked later on */ + new->sid = SCMalloc(sizeof(uint32_t) * new->sid_max); + if (new->sid == NULL) + new->sid_max = 0; + + return new; +} + +static void FileFree(File *ff, const StreamingBufferConfig *sbcfg) +{ + SCLogDebug("ff %p", ff); + if (ff == NULL) + return; + + if (ff->name != NULL) + SCFree(ff->name); + if (ff->sid != NULL) + SCFree(ff->sid); +#ifdef HAVE_MAGIC + /* magic returned by libmagic is strdup'd by MagicLookup. */ + if (ff->magic != NULL) + SCFree(ff->magic); +#endif + if (ff->sb != NULL) { + StreamingBufferFree(ff->sb, sbcfg); + } + + if (ff->md5_ctx) + SCMd5Free(ff->md5_ctx); + if (ff->sha1_ctx) + SCSha1Free(ff->sha1_ctx); + if (ff->sha256_ctx) + SCSha256Free(ff->sha256_ctx); + SCFree(ff); +} + +void FileContainerAdd(FileContainer *ffc, File *ff) +{ + SCLogDebug("ffc %p ff %p", ffc, ff); + if (ffc->head == NULL || ffc->tail == NULL) { + ffc->head = ffc->tail = ff; + } else { + ffc->tail->next = ff; + ffc->tail = ff; + } +} + +/** + * \brief Tag a file for storing + * + * \param ff The file to store + */ +int FileStore(File *ff) +{ + SCLogDebug("ff %p", ff); + ff->flags |= FILE_STORE; + SCReturnInt(0); +} + +/** + * \brief check if we have stored enough + * + * \param ff file + * + * \retval 0 limit not reached yet + * \retval 1 limit reached + */ +static int FileStoreNoStoreCheck(File *ff) +{ + SCEnter(); + + if (ff == NULL) { + SCReturnInt(0); + } + + if (ff->flags & FILE_NOSTORE) { + if (ff->state == FILE_STATE_OPENED && FileDataSize(ff) >= (uint64_t)FileMagicSize()) { + SCReturnInt(1); + } + } + + SCReturnInt(0); +} + +static int AppendData( + const StreamingBufferConfig *sbcfg, File *file, const uint8_t *data, uint32_t data_len) +{ + SCLogDebug("file %p data_len %u", file, data_len); + if (StreamingBufferAppendNoTrack(file->sb, sbcfg, data, data_len) != 0) { + SCLogDebug("file %p StreamingBufferAppendNoTrack failed", file); + SCReturnInt(-1); + } + + if (file->md5_ctx) { + SCMd5Update(file->md5_ctx, data, data_len); + } + if (file->sha1_ctx) { + SCSha1Update(file->sha1_ctx, data, data_len); + } + if (file->sha256_ctx) { + SCLogDebug("SHA256 file %p data %p data_len %u", file, data, data_len); + SCSha256Update(file->sha256_ctx, data, data_len); + } else { + SCLogDebug("NO SHA256 file %p data %p data_len %u", file, data, data_len); + } + SCReturnInt(0); +} + +/** \internal + * \brief Flags a file as having gaps + * + * \param ff the file + */ +static void FileFlagGap(File *ff) +{ + ff->flags |= FILE_HAS_GAPS; + ff->flags |= (FILE_NOMD5 | FILE_NOSHA1 | FILE_NOSHA256); + ff->flags &= ~(FILE_MD5 | FILE_SHA1 | FILE_SHA256); +} + +/** \internal + * \brief Store/handle a chunk of file data in the File structure + * + * \param ff the file + * \param data data chunk + * \param data_len data chunk len + * + * \retval 0 ok + * \retval -1 error + * \retval -2 no store for this file + */ +static int FileAppendDataDo( + const StreamingBufferConfig *sbcfg, File *ff, const uint8_t *data, uint32_t data_len) +{ + SCEnter(); +#ifdef DEBUG_VALIDATION + BUG_ON(ff == NULL); +#endif + + ff->size += data_len; + if (data == NULL) { + FileFlagGap(ff); + SCReturnInt(0); + } + + if (ff->state != FILE_STATE_OPENED) { + if (ff->flags & FILE_NOSTORE) { + SCReturnInt(-2); + } + SCReturnInt(-1); + } + + if (g_detect_disabled && FileStoreNoStoreCheck(ff) == 1) { + int hash_done = 0; + /* no storage but forced hashing */ + if (ff->md5_ctx) { + SCMd5Update(ff->md5_ctx, data, data_len); + hash_done = 1; + } + if (ff->sha1_ctx) { + SCSha1Update(ff->sha1_ctx, data, data_len); + hash_done = 1; + } + if (ff->sha256_ctx) { + SCLogDebug("file %p data %p data_len %u", ff, data, data_len); + SCSha256Update(ff->sha256_ctx, data, data_len); + hash_done = 1; + } + + if (hash_done) + SCReturnInt(0); + + if (g_file_force_tracking || (!(ff->flags & FILE_NOTRACK))) + SCReturnInt(0); + + ff->state = FILE_STATE_TRUNCATED; + SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); + SCReturnInt(-2); + } + + SCLogDebug("appending %" PRIu32 " bytes", data_len); + + int r = AppendData(sbcfg, ff, data, data_len); + if (r != 0) { + ff->state = FILE_STATE_ERROR; + SCReturnInt(r); + } + + SCReturnInt(0); +} + +/** + * \brief Store/handle a chunk of file data in the File structure + * The last file in the FileContainer will be used. + * + * \param ffc FileContainer used to append to + * \param data data chunk + * \param data_len data chunk len + * + * \retval 0 ok + * \retval -1 error + * \retval -2 no store for this file + */ +int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, + uint32_t data_len) +{ + SCEnter(); + + if (ffc == NULL || ffc->tail == NULL || data_len == 0 || sbcfg == NULL) { + SCReturnInt(-1); + } + int r = FileAppendDataDo(sbcfg, ffc->tail, data, data_len); + SCReturnInt(r); +} + +/** + * \brief Store/handle a chunk of file data in the File structure + * The file with 'track_id' in the FileContainer will be used. + * + * \param ffc FileContainer used to append to + * \param track_id id to lookup the file + * \param data data chunk + * \param data_len data chunk len + * + * \retval 0 ok + * \retval -1 error + * \retval -2 no store for this file + */ +int FileAppendDataById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, + const uint8_t *data, uint32_t data_len) +{ + SCEnter(); + + if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) { + SCReturnInt(-1); + } + File *ff = ffc->head; + for (; ff != NULL; ff = ff->next) { + if (track_id == ff->file_track_id) { + int r = FileAppendDataDo(sbcfg, ff, data, data_len); + SCReturnInt(r); + } + } + SCReturnInt(-1); +} + +/** + * \brief Store/handle a chunk of file data in the File structure + * The file with 'track_id' in the FileContainer will be used. + * + * \param ffc FileContainer used to append to + * \param track_id id to lookup the file + * \param data data chunk + * \param data_len data chunk len + * + * \retval 0 ok + * \retval -1 error + * \retval -2 no store for this file + */ +int FileAppendGAPById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, + const uint8_t *data, uint32_t data_len) +{ + SCEnter(); + + if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) { + SCReturnInt(-1); + } + File *ff = ffc->head; + for (; ff != NULL; ff = ff->next) { + if (track_id == ff->file_track_id) { + FileFlagGap(ff); + SCLogDebug("FILE_HAS_GAPS set"); + + int r = FileAppendDataDo(sbcfg, ff, data, data_len); + SCReturnInt(r); + } + } + SCReturnInt(-1); +} + +void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min) +{ + file->inspect_window = win; + file->inspect_min_size = min; +} + +/** + * \brief Sets the offset range for a file. + * + * \param ffc the container + * \param start start offset + * \param end end offset + * + * \retval 0 ok + * \retval -1 error + */ +int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end) +{ + SCEnter(); + + if (ffc == NULL || ffc->tail == NULL) { + SCReturnInt(-1); + } + ffc->tail->start = start; + ffc->tail->end = end; + SCReturnInt(0); +} + +/** + * \brief Open a new File + * + * \param ffc flow container + * \param sbcfg buffer config + * \param name filename character array + * \param name_len filename len + * \param data initial data + * \param data_len initial data len + * \param flags open flags + * + * \retval ff flowfile object + * + * \note filename is not a string, so it's not nul terminated. + */ +static File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, + const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, + uint16_t flags) +{ + SCEnter(); + + // PrintRawDataFp(stdout, name, name_len); + + File *ff = FileAlloc(name, name_len); + if (ff == NULL) { + SCReturnPtr(NULL, "File"); + } + + ff->sb = StreamingBufferInit(sbcfg); + if (ff->sb == NULL) { + FileFree(ff, sbcfg); + SCReturnPtr(NULL, "File"); + } + SCLogDebug("ff->sb %p", ff->sb); + + if (flags & FILE_STORE || g_file_force_filestore) { + FileStore(ff); + } else if (flags & FILE_NOSTORE) { + SCLogDebug("not storing this file"); + ff->flags |= FILE_NOSTORE; + } + if (flags & FILE_NOMAGIC) { + SCLogDebug("not doing magic for this file"); + ff->flags |= FILE_NOMAGIC; + } + if (flags & FILE_NOMD5) { + SCLogDebug("not doing md5 for this file"); + ff->flags |= FILE_NOMD5; + } + if (flags & FILE_NOSHA1) { + SCLogDebug("not doing sha1 for this file"); + ff->flags |= FILE_NOSHA1; + } + if (flags & FILE_NOSHA256) { + SCLogDebug("not doing sha256 for this file"); + ff->flags |= FILE_NOSHA256; + } + + if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) { + ff->md5_ctx = SCMd5New(); + } + if (!(ff->flags & FILE_NOSHA1) || g_file_force_sha1) { + ff->sha1_ctx = SCSha1New(); + } + if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) { + ff->sha256_ctx = SCSha256New(); + SCLogDebug("ff %p ff->sha256_ctx %p", ff, ff->sha256_ctx); + } + + ff->state = FILE_STATE_OPENED; + SCLogDebug("flowfile state transitioned to FILE_STATE_OPENED"); + + ff->fd = -1; + + FileContainerAdd(ffc, ff); + + /* set default window and min inspection size */ + FileSetInspectSizes(ff, FILEDATA_CONTENT_INSPECT_WINDOW, FILEDATA_CONTENT_INSPECT_MIN_SIZE); + + ff->size += data_len; + if (data != NULL) { + if (AppendData(sbcfg, ff, data, data_len) != 0) { + ff->state = FILE_STATE_ERROR; + SCReturnPtr(NULL, "File"); + } + SCLogDebug("file size is now %" PRIu64, FileTrackedSize(ff)); + } else if (data_len > 0) { + FileFlagGap(ff); + } + + SCReturnPtr(ff, "File"); +} + +/** + * \retval 0 ok + * \retval -1 failed */ +int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, + const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, + uint16_t flags) +{ + SCLogDebug("ffc %p track_id %u", ffc, track_id); + File *ff = FileOpenFile(ffc, sbcfg, name, name_len, data, data_len, flags); + if (ff == NULL) + return -1; + + ff->file_track_id = track_id; + return 0; +} + +int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data, + uint32_t data_len, uint16_t flags) +{ + SCEnter(); + + if (ff == NULL) { + SCReturnInt(-1); + } + + if (ff->state != FILE_STATE_OPENED) { + SCReturnInt(-1); + } + + ff->size += data_len; + if (data != NULL) { + if (ff->flags & FILE_NOSTORE) { + /* no storage but hashing */ + if (ff->md5_ctx) + SCMd5Update(ff->md5_ctx, data, data_len); + if (ff->sha1_ctx) + SCSha1Update(ff->sha1_ctx, data, data_len); + if (ff->sha256_ctx) { + SCLogDebug("file %p data %p data_len %u", ff, data, data_len); + SCSha256Update(ff->sha256_ctx, data, data_len); + } + } else { + if (AppendData(sbcfg, ff, data, data_len) != 0) { + ff->state = FILE_STATE_ERROR; + SCReturnInt(-1); + } + } + } + + if ((flags & FILE_TRUNCATED) || (ff->flags & FILE_HAS_GAPS)) { + SCLogDebug("flags FILE_TRUNCATED %s", (flags & FILE_TRUNCATED) ? "true" : "false"); + SCLogDebug("ff->flags FILE_HAS_GAPS %s", (ff->flags & FILE_HAS_GAPS) ? "true" : "false"); + + ff->state = FILE_STATE_TRUNCATED; + SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED"); + + if (flags & FILE_NOSTORE) { + SCLogDebug("not storing this file"); + ff->flags |= FILE_NOSTORE; + } else { + if (g_file_force_sha256 && ff->sha256_ctx) { + SCLogDebug("file %p data %p data_len %u", ff, data, data_len); + FileEndSha256(ff); + } + } + } else { + ff->state = FILE_STATE_CLOSED; + SCLogDebug("flowfile state transitioned to FILE_STATE_CLOSED"); + + if (ff->md5_ctx) { + SCMd5Finalize(ff->md5_ctx, ff->md5, sizeof(ff->md5)); + ff->md5_ctx = NULL; + ff->flags |= FILE_MD5; + } + if (ff->sha1_ctx) { + SCSha1Finalize(ff->sha1_ctx, ff->sha1, sizeof(ff->sha1)); + ff->sha1_ctx = NULL; + ff->flags |= FILE_SHA1; + } + if (ff->sha256_ctx) { + SCLogDebug("file %p data %p data_len %u", ff, data, data_len); + FileEndSha256(ff); + } + } + + SCReturnInt(0); +} + +/** + * \brief Close a File + * + * \param ffc the container + * \param data final data if any + * \param data_len data len if any + * \param flags flags + * + * \retval 0 ok + * \retval -1 error + */ +int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, + uint32_t data_len, uint16_t flags) +{ + SCEnter(); + + if (ffc == NULL || ffc->tail == NULL) { + SCReturnInt(-1); + } + + if (FileCloseFilePtr(ffc->tail, sbcfg, data, data_len, flags) == -1) { + SCReturnInt(-1); + } + + SCReturnInt(0); +} + +int FileCloseFileById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, + const uint8_t *data, uint32_t data_len, uint16_t flags) +{ + SCEnter(); + + if (ffc == NULL || ffc->tail == NULL) { + SCReturnInt(-1); + } + + File *ff = ffc->head; + for (; ff != NULL; ff = ff->next) { + if (track_id == ff->file_track_id) { + int r = FileCloseFilePtr(ff, sbcfg, data, data_len, flags); + SCReturnInt(r); + } + } + SCReturnInt(-1); +} + +/** \brief set a flow's file flags + * \param set_file_flags flags in both directions that are requested to set + * + * This function will ignore the flags for the irrelevant direction and + * also mask the flags with the global settings. + */ +void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction) +{ + SCEnter(); + DEBUG_ASSERT_FLOW_LOCKED(f); + + /* remove flags not in our direction and + don't disable what is globally enabled */ + if (direction == STREAM_TOSERVER) { + set_file_flags &= ~(FLOWFILE_NONE_TC | g_file_flow_mask); + } else { + set_file_flags &= ~(FLOWFILE_NONE_TS | g_file_flow_mask); + } + f->file_flags |= set_file_flags; + + SCLogDebug("f->file_flags %04x set_file_flags %04x g_file_flow_mask %04x", f->file_flags, + set_file_flags, g_file_flow_mask); + + if (set_file_flags != 0 && f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) { + AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate); + if (sd != NULL) { + if ((sd->file_flags & f->file_flags) != f->file_flags) { + SCLogDebug("state data: updating file_flags %04x with flow file_flags %04x", + sd->file_flags, f->file_flags); + sd->file_flags |= f->file_flags; + } + } + } +} + +/** + * \brief disable file storing for files in a transaction + * + * \param f *LOCKED* flow + * \param direction flow direction + * \param tx_id transaction id + */ +void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id) +{ + if (g_file_force_filestore == 0) { + AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, tx); + if (txd != NULL) { + if (direction & STREAM_TOSERVER) { + txd->file_flags |= FLOWFILE_NO_STORE_TS; + } else { + txd->file_flags |= FLOWFILE_NO_STORE_TC; + } + } + } +} + +/** + * \brief flag a file with id "file_id" to be stored. + * + * \param fc file store + * \param file_id the file's id + */ +void FileStoreFileById(FileContainer *fc, uint32_t file_id) +{ + File *ptr = NULL; + + SCEnter(); + + if (fc != NULL) { + for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { + if (ptr->file_track_id == file_id) { + FileStore(ptr); + } + } + } +} + +static void FileTruncateAllOpenFiles(FileContainer *fc, const StreamingBufferConfig *sbcfg) +{ + File *ptr = NULL; + + SCEnter(); + + if (fc != NULL) { + for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { + if (ptr->state == FILE_STATE_OPENED) { + FileCloseFilePtr(ptr, sbcfg, NULL, 0, FILE_TRUNCATED); + } + } + } +} + +void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc) +{ + if (trunc) { + FileTruncateAllOpenFiles(fc, sbcfg); + } + FilePrune(fc, sbcfg); +} + +/** + * \brief Finish the SHA256 calculation. + */ +static void FileEndSha256(File *ff) +{ + SCLogDebug("ff %p ff->size %" PRIu64, ff, ff->size); + if (!(ff->flags & FILE_SHA256) && ff->sha256_ctx) { + SCSha256Finalize(ff->sha256_ctx, ff->sha256, sizeof(ff->sha256)); + ff->sha256_ctx = NULL; + ff->flags |= FILE_SHA256; + } +} diff --git a/src/util/file.h b/src/util/file.h new file mode 100644 index 000000000000..23c0a147d4a0 --- /dev/null +++ b/src/util/file.h @@ -0,0 +1,255 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#ifndef __UTIL_FILE_H__ +#define __UTIL_FILE_H__ + +#include "../conf.h" +#include "util/streaming-buffer.h" +#include "flow.h" + +/* Hack: Pulling rust.h to get the SCSha256 causes all sorts of problems with + * header include orders, which is something we'll have to resolve as we provide + * more functionality via Rust. But this lets me continue with replacing nss + * without fighting the headers at this time. */ +typedef struct SCSha256 SCSha256; +#define SC_SHA256_LEN 32 + +typedef struct SCSha1 SCSha1; +#define SC_SHA1_LEN 20 + +typedef struct SCMd5 SCMd5; +#define SC_MD5_LEN 16 + +#define FILE_TRUNCATED BIT_U16(0) +#define FILE_NOMAGIC BIT_U16(1) +#define FILE_NOMD5 BIT_U16(2) +#define FILE_MD5 BIT_U16(3) +#define FILE_NOSHA1 BIT_U16(4) +#define FILE_SHA1 BIT_U16(5) +#define FILE_NOSHA256 BIT_U16(6) +#define FILE_SHA256 BIT_U16(7) +#define FILE_LOGGED BIT_U16(8) +#define FILE_NOSTORE BIT_U16(9) +#define FILE_STORE BIT_U16(10) +#define FILE_STORED BIT_U16(11) +#define FILE_NOTRACK BIT_U16(12) /**< track size of file */ +#define FILE_USE_DETECT BIT_U16(13) /**< use content_inspected tracker */ +#define FILE_HAS_GAPS BIT_U16(15) + +// to be used instead of PATH_MAX which depends on the OS +#define SC_FILENAME_MAX 4096 + +#define FILEDATA_CONTENT_LIMIT 100000 +#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768 +#define FILEDATA_CONTENT_INSPECT_WINDOW 4096 + +typedef enum FileState_ { + FILE_STATE_NONE = 0, /**< no state */ + FILE_STATE_OPENED, /**< flow file is opened */ + FILE_STATE_CLOSED, /**< flow file is completed, + there will be no more data. */ + FILE_STATE_TRUNCATED, /**< flow file is not complete, but + there will be no more data. */ + FILE_STATE_ERROR, /**< file is in an error state */ + FILE_STATE_MAX +} FileState; + +typedef struct File_ { + uint16_t flags; + uint16_t name_len; + FileState state; + StreamingBuffer *sb; + uint32_t file_track_id; /**< id used by protocol parser */ + uint32_t file_store_id; /**< id used in store file name file. */ + int fd; /**< file descriptor for filestore, not + open if equal to -1 */ + uint8_t *name; +#ifdef HAVE_MAGIC + char *magic; +#endif + struct File_ *next; + SCMd5 *md5_ctx; + uint8_t md5[SC_MD5_LEN]; + SCSha1 *sha1_ctx; + uint8_t sha1[SC_SHA1_LEN]; + SCSha256 *sha256_ctx; + uint8_t sha256[SC_SHA256_LEN]; + uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT + * flag is set */ + uint64_t content_stored; + uint64_t size; + uint32_t inspect_window; + uint32_t inspect_min_size; + uint64_t start; + uint64_t end; + + uint32_t *sid; /* signature id of a rule that triggered the filestore event */ + uint32_t sid_cnt; + uint32_t sid_max; +} File; + +typedef struct FileContainer_ { + File *head; + File *tail; +} FileContainer; + +FileContainer *FileContainerAlloc(void); +void FileContainerFree(FileContainer *, const StreamingBufferConfig *cfg); + +void FileContainerRecycle(FileContainer *, const StreamingBufferConfig *cfg); + +void FileContainerAdd(FileContainer *, File *); + +/** + * \brief Open a new File + * + * \param ffc flow container + * \param sbcfg buffer config + * \param name filename character array + * \param name_len filename len + * \param data initial data + * \param data_len initial data len + * \param flags open flags + * + * \retval ff flowfile object + * + * \note filename is not a string, so it's not nul terminated. + * + * If flags contains the FILE_USE_DETECT bit, the pruning code will + * consider not just the content_stored tracker, but also content_inspected. + * It's the responsibility of the API user to make sure this tracker is + * properly updated. + */ +int FileOpenFileWithId(FileContainer *, const StreamingBufferConfig *, uint32_t track_id, + const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, + uint16_t flags); + +/** + * \brief Close a File + * + * \param ffc the container + * \param data final data if any + * \param data_len data len if any + * \param flags flags + * + * \retval 0 ok + * \retval -1 error + */ +int FileCloseFile(FileContainer *, const StreamingBufferConfig *sbcfg, const uint8_t *data, + uint32_t data_len, uint16_t flags); +int FileCloseFileById(FileContainer *, const StreamingBufferConfig *sbcfg, uint32_t track_id, + const uint8_t *data, uint32_t data_len, uint16_t flags); +int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data, + uint32_t data_len, uint16_t flags); + +/** + * \brief Store a chunk of file data in the flow. The open "flowfile" + * will be used. + * + * \param ffc the container + * \param data data chunk + * \param data_len data chunk len + * + * \retval 0 ok + * \retval -1 error + */ +int FileAppendData(FileContainer *, const StreamingBufferConfig *sbcfg, const uint8_t *data, + uint32_t data_len); +int FileAppendDataById(FileContainer *, const StreamingBufferConfig *sbcfg, uint32_t track_id, + const uint8_t *data, uint32_t data_len); +int FileAppendGAPById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, + const uint8_t *data, uint32_t data_len); + +void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min); + +/** + * \brief Sets the offset range for a file. + * + * \param ffc the container + * \param start start offset + * \param end end offset + * + * \retval 0 ok + * \retval -1 error + */ +int FileSetRange(FileContainer *, uint64_t start, uint64_t end); + +/** + * \brief Tag a file for storing + * + * \param ff The file to store + */ +int FileStore(File *); + +/** + * \brief disable file storing for a transaction + * + * \param f flow + * \param direction STREAM_TOSERVER or STREAM_TOCLIENT + * \param tx transaction pointer + * \param tx_id transaction id + */ +void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id); + +void FileForceFilestoreEnable(void); +int FileForceFilestore(void); +void FileReassemblyDepthEnable(uint32_t size); +uint32_t FileReassemblyDepth(void); + +void FileForceMagicEnable(void); +int FileForceMagic(void); + +void FileForceMd5Enable(void); +int FileForceMd5(void); + +void FileForceSha1Enable(void); +int FileForceSha1(void); + +void FileForceSha256Enable(void); +int FileForceSha256(void); + +void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction); + +void FileForceHashParseCfg(ConfNode *); + +void FileForceTrackingEnable(void); + +void FileStoreFileById(FileContainer *fc, uint32_t); + +uint64_t FileDataSize(const File *file); +uint64_t FileTrackedSize(const File *file); + +uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction); +uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction); + +#ifdef DEBUG +void FilePrintFlags(const File *file); +#else +#define FilePrintFlags(file) +#endif + +void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc); + +#endif /* __UTIL_FILE_H__ */ diff --git a/src/util/fix_checksum.c b/src/util/fix_checksum.c new file mode 100644 index 000000000000..3832419f3c1c --- /dev/null +++ b/src/util/fix_checksum.c @@ -0,0 +1,58 @@ +/* + * Reference: OpenBSD's pf.c. + * + * Copyright (c) 2001 Daniel Hartmeier + * Copyright (c) 2002 - 2008 Henning Brauer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + */ + +#include + +#include "util/fix_checksum.h" + +/** + * \brief Fix-up an IP checksum. + * + * \param sum The current checksum. + * \param old Value of old header parameter. + * \param new Value of new header parameter. + * + * \retval New checksum. + */ +uint16_t FixChecksum(uint16_t sum, uint16_t old, uint16_t new) +{ + uint32_t l; + + l = sum + old - new; + l = (l >> 16) + (l & 65535); + + return (uint16_t)(l & 65535); +} diff --git a/src/util-fix_checksum.h b/src/util/fix_checksum.h similarity index 100% rename from src/util-fix_checksum.h rename to src/util/fix_checksum.h diff --git a/src/util/fmemopen.c b/src/util/fmemopen.c new file mode 100644 index 000000000000..48685ffc3a8a --- /dev/null +++ b/src/util/fmemopen.c @@ -0,0 +1,199 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * Based on FMem.c of Alexandre Flori (2008/10/17 AF) + */ + +#include "suricata-common.h" +#include "util/fmemopen.h" + +#ifdef OS_DARWIN +#define USE_FMEM_WRAPPER 1 +#endif + +#ifdef OS_FREEBSD +#define USE_FMEM_WRAPPER 1 +#endif + +#ifdef __OpenBSD__ +#define USE_FMEM_WRAPPER 1 +#endif + +#ifdef USE_FMEM_WRAPPER + +#ifdef OS_WIN32 + +/** + * \brief portable version of SCFmemopen for Windows works on top of real temp files + * \param buffer that holds the file content + * \param size of the file buffer + * \param mode mode of the file to open + * \retval pointer to the file; NULL if something is wrong + */ +FILE *SCFmemopen(void *buf, size_t size, const char *mode) +{ + char temppath[MAX_PATH - 13]; + if (0 == GetTempPath(sizeof(temppath), temppath)) + return NULL; + + char filename[MAX_PATH + 1]; + if (0 == GetTempFileName(temppath, "SC", 0, filename)) + return NULL; + + FILE *f = fopen(filename, "wb"); + if (NULL == f) + return NULL; + + fwrite(buf, size, 1, f); + fclose(f); + + return fopen(filename, mode); +} + +#else + +typedef struct SCFmem_ { + size_t pos; + size_t size; + char *buffer; +} SCFmem; + +/** + * \brief Seek the mem file from offset and whence + * \param handler pointer to the memfile + * \param offset number of bytes to move from whence + * \param whence SEEK_SET, SEEK_CUR, SEEK_END + * \retval pos the position by the last operation, -1 if sizes are out of bounds + */ +static fpos_t SeekFn(void *handler, fpos_t offset, int whence) +{ + size_t pos = 0; + SCFmem *mem = handler; + + switch (whence) { + case SEEK_SET: + if (offset >= 0 && (size_t)offset <= mem->size) { + return mem->pos = offset; + } + break; + case SEEK_CUR: + if (mem->pos + offset <= mem->size) + return mem->pos += offset; + break; + case SEEK_END: + /* must be negative */ + if (mem->size + offset <= mem->size) + return pos = mem->size + offset; + break; + } + + return -1; +} + +/** + * \brief Read from the buffer looking for the available memory limits + * \param handler pointer to the memfile + * \param buf buffer to read from the handler + * \param number of bytes to read + * \retval count , the number of bytes read + */ +static int ReadFn(void *handler, char *buf, int size) +{ + size_t count = 0; + SCFmem *mem = handler; + size_t available = mem->size - mem->pos; + int is_eof = 0; + + if (size < 0) + return -1; + + if ((size_t)size > available) { + size = available; + } else { + is_eof = 1; + } + + while (count < (size_t)size) + buf[count++] = mem->buffer[mem->pos++]; + + if (is_eof == 1) + return 0; + + return count; +} + +/** + * \brief Write into the buffer looking for the available memory limits + * \param handler pointer to the memfile + * \param buf buffer to write in the handler + * \param number of bytes to write + * \retval count , the number of bytes written + */ +static int WriteFn(void *handler, const char *buf, int size) +{ + size_t count = 0; + SCFmem *mem = handler; + size_t available = mem->size - mem->pos; + + if (size < 0) + return -1; + + if ((size_t)size > available) + size = available; + + while (count < (size_t)size) + mem->buffer[mem->pos++] = buf[count++]; + + return count; +} + +/** + * \brief close the mem file handler + * \param handler pointer to the memfile + * \retval 0 on succesful + */ +static int CloseFn(void *handler) +{ + SCFree(handler); + return 0; +} + +/** + * \brief portable version of SCFmemopen for OS X / BSD built on top of funopen() + * \param buffer that holds the file content + * \param size of the file buffer + * \param mode mode of the file to open + * \retval pointer to the file; NULL if something is wrong + */ +FILE *SCFmemopen(void *buf, size_t size, const char *mode) +{ + SCFmem *mem = (SCFmem *)SCCalloc(1, sizeof(SCFmem)); + if (mem == NULL) + return NULL; + + mem->size = size, mem->buffer = buf; + + return funopen(mem, ReadFn, WriteFn, SeekFn, CloseFn); +} + +#endif /* OS_WIN32 */ + +#endif /* USE_FMEM_WRAPPER */ diff --git a/src/util-fmemopen.h b/src/util/fmemopen.h similarity index 100% rename from src/util-fmemopen.h rename to src/util/fmemopen.h diff --git a/src/util/hash-lookup3.c b/src/util/hash-lookup3.c new file mode 100644 index 000000000000..e4eb1ca8b9c1 --- /dev/null +++ b/src/util/hash-lookup3.c @@ -0,0 +1,1466 @@ +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ +// #define SELF_TEST 1 + +#include /* defines printf for tests */ +#include /* defines time_t for timings in the test */ +#include /* defines uint32_t etc */ +#include /* attempt to define endianness */ +#ifdef linux +#include /* attempt to define endianness */ +#endif +#include "util/hash-lookup3.h" + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || \ + defined(__i686__) || defined(vax) || defined(MIPSEL)) +#define HASH_LITTLE_ENDIAN 1 +#define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 1 +#else +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1 << (n)) +#define hashmask(n) (hashsize(n) - 1) +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a, b, c) \ + { \ + a -= c; \ + a ^= rot(c, 4); \ + c += b; \ + b -= a; \ + b ^= rot(a, 6); \ + a += c; \ + c -= b; \ + c ^= rot(b, 8); \ + b += a; \ + a -= c; \ + a ^= rot(c, 16); \ + c += b; \ + b -= a; \ + b ^= rot(a, 19); \ + a += c; \ + c -= b; \ + c ^= rot(b, 4); \ + b += a; \ + } + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a, b, c) \ + { \ + c ^= b; \ + c -= rot(b, 14); \ + a ^= c; \ + a -= rot(c, 11); \ + b ^= a; \ + b -= rot(a, 25); \ + c ^= b; \ + c -= rot(b, 16); \ + a ^= c; \ + a -= rot(c, 4); \ + b ^= a; \ + b -= rot(a, 14); \ + c ^= b; \ + c -= rot(b, 24); \ + } + +/* +-------------------------------------------------------------------- + This works on all machines. To be useful, it requires + -- that the key be an array of uint32_t's, and + -- that the length be the number of uint32_t's in the key + + The function hashword() is identical to hashlittle() on little-endian + machines, and identical to hashbig() on big-endian machines, + except that the length has to be measured in uint32_ts rather than in + bytes. hashlittle() is more complicated than hashword() only because + hashlittle() has to dance around fitting the key bytes into registers. +-------------------------------------------------------------------- +*/ +uint32_t hashword(const uint32_t *k, /* the key, an array of uint32_t values */ + size_t length, /* the length of the key, in uint32_ts */ + uint32_t initval) /* the previous hash, or an arbitrary value */ +{ + uint32_t a, b, c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + (((uint32_t)length) << 2) + initval; + + /*------------------------------------------------- handle most of the key */ + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 3; + k += 3; + } + + /*------------------------------------------- handle the last 3 uint32_t's */ + switch (length) /* all the case statements fall through */ + { + case 3: + c += k[2]; /* fall through */ + case 2: + b += k[1]; /* fall through */ + case 1: + a += k[0]; + final(a, b, c); /* fall through */ + case 0: /* case 0: nothing left to add */ + break; + } + /*------------------------------------------------------ report the result */ + return c; +} + +/* +-------------------------------------------------------------------- +hashword2() -- same as hashword(), but take two seeds and return two +32-bit values. pc and pb must both be nonnull, and *pc and *pb must +both be initialized with seeds. If you pass in (*pb)==0, the output +(*pc) will be the same as the return value from hashword(). +-------------------------------------------------------------------- +*/ +void hashword2(const uint32_t *k, /* the key, an array of uint32_t values */ + size_t length, /* the length of the key, in uint32_ts */ + uint32_t *pc, /* IN: seed OUT: primary hash value */ + uint32_t *pb) /* IN: more seed OUT: secondary hash value */ +{ + uint32_t a, b, c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)(length << 2)) + *pc; + c += *pb; + + /*------------------------------------------------- handle most of the key */ + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 3; + k += 3; + } + + /*------------------------------------------- handle the last 3 uint32_t's */ + switch (length) /* all the case statements fall through */ + { + case 3: + c += k[2]; /* fall through */ + case 2: + b += k[1]; /* fall through */ + case 1: + a += k[0]; + final(a, b, c); /* fall through */ + case 0: /* case 0: nothing left to add */ + break; + } + /*------------------------------------------------------ report the result */ + *pc = c; + *pb = b; +} + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff; + b += k[1]; + a += k[0]; + break; + case 9: + c += k[2] & 0xff; + b += k[1]; + a += k[0]; + break; + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += k[1] & 0xffffff; + a += k[0]; + break; + case 6: + b += k[1] & 0xffff; + a += k[0]; + break; + case 5: + b += k[1] & 0xff; + a += k[0]; + break; + case 4: + a += k[0]; + break; + case 3: + a += k[0] & 0xffffff; + break; + case 2: + a += k[0] & 0xffff; + break; + case 1: + a += k[0] & 0xff; + break; + case 0: + return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + const uint8_t *k8 = (const uint8_t *)k; + + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t)k8[9]) << 8; /* fall through */ + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t)k8[5]) << 8; /* fall through */ + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0]; + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t)k8[1]) << 8; /* fall through */ + case 1: + a += k8[0]; + break; + case 0: + return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) { + a += k[0] + (((uint32_t)k[1]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + c += k[4] + (((uint32_t)k[5]) << 16); + mix(a, b, c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch (length) { + case 12: + c += k[4] + (((uint32_t)k[5]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += k[4]; + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += k[2]; + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += k[0]; + break; + case 1: + a += k8[0]; + break; + case 0: + return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + a += k[0]; + a += ((uint32_t)k[1]) << 8; + a += ((uint32_t)k[2]) << 16; + a += ((uint32_t)k[3]) << 24; + b += k[4]; + b += ((uint32_t)k[5]) << 8; + b += ((uint32_t)k[6]) << 16; + b += ((uint32_t)k[7]) << 24; + c += k[8]; + c += ((uint32_t)k[9]) << 8; + c += ((uint32_t)k[10]) << 16; + c += ((uint32_t)k[11]) << 24; + mix(a, b, c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch (length) /* all the case statements fall through */ + { + case 12: + c += ((uint32_t)k[11]) << 24; /* fall through */ + case 11: + c += ((uint32_t)k[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t)k[9]) << 8; /* fall through */ + case 9: + c += k[8]; /* fall through */ + case 8: + b += ((uint32_t)k[7]) << 24; /* fall through */ + case 7: + b += ((uint32_t)k[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t)k[5]) << 8; /* fall through */ + case 5: + b += k[4]; /* fall through */ + case 4: + a += ((uint32_t)k[3]) << 24; /* fall through */ + case 3: + a += ((uint32_t)k[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t)k[1]) << 8; /* fall through */ + case 1: + a += k[0]; + break; + case 0: + return c; + } + } + + final(a, b, c); + return c; +} + +/* +------------------------------------------------------------------------------- +hashlittle_safe() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * Note that unlike hashlittle() above, we use the "safe" version of this + * block that is #ifdef VALGRIND above, in order to avoid warnings from + * Valgrind or Address Sanitizer. + */ + + const uint8_t *k8 = (const uint8_t *)k; + + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t)k8[9]) << 8; /* fall through */ + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t)k8[5]) << 8; /* fall through */ + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0]; + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t)k8[1]) << 8; /* fall through */ + case 1: + a += k8[0]; + break; + case 0: + return c; + } + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) { + a += k[0] + (((uint32_t)k[1]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + c += k[4] + (((uint32_t)k[5]) << 16); + mix(a, b, c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch (length) { + case 12: + c += k[4] + (((uint32_t)k[5]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += k[4]; + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += k[2]; + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += k[0]; + break; + case 1: + a += k8[0]; + break; + case 0: + return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + a += k[0]; + a += ((uint32_t)k[1]) << 8; + a += ((uint32_t)k[2]) << 16; + a += ((uint32_t)k[3]) << 24; + b += k[4]; + b += ((uint32_t)k[5]) << 8; + b += ((uint32_t)k[6]) << 16; + b += ((uint32_t)k[7]) << 24; + c += k[8]; + c += ((uint32_t)k[9]) << 8; + c += ((uint32_t)k[10]) << 16; + c += ((uint32_t)k[11]) << 24; + mix(a, b, c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch (length) /* all the case statements fall through */ + { + case 12: + c += ((uint32_t)k[11]) << 24; /* fall through */ + case 11: + c += ((uint32_t)k[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t)k[9]) << 8; /* fall through */ + case 9: + c += k[8]; /* fall through */ + case 8: + b += ((uint32_t)k[7]) << 24; /* fall through */ + case 7: + b += ((uint32_t)k[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t)k[5]) << 8; /* fall through */ + case 5: + b += k[4]; /* fall through */ + case 4: + a += ((uint32_t)k[3]) << 24; /* fall through */ + case 3: + a += ((uint32_t)k[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t)k[1]) << 8; /* fall through */ + case 1: + a += k[0]; + break; + case 0: + return c; + } + } + + final(a, b, c); + return c; +} + +/* + * hashlittle2: return 2 32-bit hash values + * + * This is identical to hashlittle(), except it returns two 32-bit hash + * values instead of just one. This is good enough for hash table + * lookup with 2^^64 buckets, or if you want a second hash if you're not + * happy with the first, or if you want a probably-unique 64-bit ID for + * the key. *pc is better mixed than *pb, so use *pc first. If you want + * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". + */ +void hashlittle2(const void *key, /* the key to hash */ + size_t length, /* length of the key */ + uint32_t *pc, /* IN: primary initval, OUT: primary hash */ + uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ +{ + uint32_t a, b, c; /* internal state */ + union { + const void *ptr; + size_t i; + } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc; + c += *pb; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff; + b += k[1]; + a += k[0]; + break; + case 9: + c += k[2] & 0xff; + b += k[1]; + a += k[0]; + break; + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += k[1] & 0xffffff; + a += k[0]; + break; + case 6: + b += k[1] & 0xffff; + a += k[0]; + break; + case 5: + b += k[1] & 0xff; + a += k[0]; + break; + case 4: + a += k[0]; + break; + case 3: + a += k[0] & 0xffffff; + break; + case 2: + a += k[0] & 0xffff; + break; + case 1: + a += k[0] & 0xff; + break; + case 0: + *pc = c; + *pb = b; + return; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + const uint8_t *k8 = (const uint8_t *)k; + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t)k8[9]) << 8; /* fall through */ + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t)k8[5]) << 8; /* fall through */ + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0]; + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t)k8[1]) << 8; /* fall through */ + case 1: + a += k8[0]; + break; + case 0: + *pc = c; + *pb = b; + return; /* zero length strings require no mixing */ + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) { + a += k[0] + (((uint32_t)k[1]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + c += k[4] + (((uint32_t)k[5]) << 16); + mix(a, b, c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch (length) { + case 12: + c += k[4] + (((uint32_t)k[5]) << 16); + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 11: + c += ((uint32_t)k8[10]) << 16; /* fall through */ + case 10: + c += k[4]; + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[2] + (((uint32_t)k[3]) << 16); + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 7: + b += ((uint32_t)k8[6]) << 16; /* fall through */ + case 6: + b += k[2]; + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0] + (((uint32_t)k[1]) << 16); + break; + case 3: + a += ((uint32_t)k8[2]) << 16; /* fall through */ + case 2: + a += k[0]; + break; + case 1: + a += k8[0]; + break; + case 0: + *pc = c; + *pb = b; + return; /* zero length strings require no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + a += k[0]; + a += ((uint32_t)k[1]) << 8; + a += ((uint32_t)k[2]) << 16; + a += ((uint32_t)k[3]) << 24; + b += k[4]; + b += ((uint32_t)k[5]) << 8; + b += ((uint32_t)k[6]) << 16; + b += ((uint32_t)k[7]) << 24; + c += k[8]; + c += ((uint32_t)k[9]) << 8; + c += ((uint32_t)k[10]) << 16; + c += ((uint32_t)k[11]) << 24; + mix(a, b, c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch (length) /* all the case statements fall through */ + { + case 12: + c += ((uint32_t)k[11]) << 24; /* fall through */ + case 11: + c += ((uint32_t)k[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t)k[9]) << 8; /* fall through */ + case 9: + c += k[8]; /* fall through */ + case 8: + b += ((uint32_t)k[7]) << 24; /* fall through */ + case 7: + b += ((uint32_t)k[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t)k[5]) << 8; /* fall through */ + case 5: + b += k[4]; /* fall through */ + case 4: + a += ((uint32_t)k[3]) << 24; /* fall through */ + case 3: + a += ((uint32_t)k[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t)k[1]) << 8; /* fall through */ + case 1: + a += k[0]; + break; + case 0: + *pc = c; + *pb = b; + return; /* zero length strings require no mixing */ + } + } + + final(a, b, c); + *pc = c; + *pb = b; +} + +/* + * hashbig(): + * This is the same as hashword() on big-endian machines. It is different + * from hashlittle() on all machines. hashbig() takes advantage of + * big-endian byte ordering. + */ +uint32_t hashbig(const void *key, size_t length, uint32_t initval) +{ + uint32_t a, b, c; + union { + const void *ptr; + size_t i; + } u; /* to cast key to (size_t) happily */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a, b, c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]<<8" actually reads beyond the end of the string, but + * then shifts out the part it's not allowed to read. Because the + * string is aligned, the illegal read is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (length) { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff00; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff0000; + b += k[1]; + a += k[0]; + break; + case 9: + c += k[2] & 0xff000000; + b += k[1]; + a += k[0]; + break; + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += k[1] & 0xffffff00; + a += k[0]; + break; + case 6: + b += k[1] & 0xffff0000; + a += k[0]; + break; + case 5: + b += k[1] & 0xff000000; + a += k[0]; + break; + case 4: + a += k[0]; + break; + case 3: + a += k[0] & 0xffffff00; + break; + case 2: + a += k[0] & 0xffff0000; + break; + case 1: + a += k[0] & 0xff000000; + break; + case 0: + return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + const uint8_t *k8 = (const uint8_t *)k; + switch (length) /* all the case statements fall through */ + { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t)k8[10]) << 8; /* fall through */ + case 10: + c += ((uint32_t)k8[9]) << 16; /* fall through */ + case 9: + c += ((uint32_t)k8[8]) << 24; /* fall through */ + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += ((uint32_t)k8[6]) << 8; /* fall through */ + case 6: + b += ((uint32_t)k8[5]) << 16; /* fall through */ + case 5: + b += ((uint32_t)k8[4]) << 24; /* fall through */ + case 4: + a += k[0]; + break; + case 3: + a += ((uint32_t)k8[2]) << 8; /* fall through */ + case 2: + a += ((uint32_t)k8[1]) << 16; /* fall through */ + case 1: + a += ((uint32_t)k8[0]) << 24; + break; + case 0: + return c; + } + +#endif /* !VALGRIND */ + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + a += ((uint32_t)k[0]) << 24; + a += ((uint32_t)k[1]) << 16; + a += ((uint32_t)k[2]) << 8; + a += ((uint32_t)k[3]); + b += ((uint32_t)k[4]) << 24; + b += ((uint32_t)k[5]) << 16; + b += ((uint32_t)k[6]) << 8; + b += ((uint32_t)k[7]); + c += ((uint32_t)k[8]) << 24; + c += ((uint32_t)k[9]) << 16; + c += ((uint32_t)k[10]) << 8; + c += ((uint32_t)k[11]); + mix(a, b, c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch (length) /* all the case statements fall through */ + { + case 12: + c += k[11]; /* fall through */ + case 11: + c += ((uint32_t)k[10]) << 8; /* fall through */ + case 10: + c += ((uint32_t)k[9]) << 16; /* fall through */ + case 9: + c += ((uint32_t)k[8]) << 24; /* fall through */ + case 8: + b += k[7]; /* fall through */ + case 7: + b += ((uint32_t)k[6]) << 8; /* fall through */ + case 6: + b += ((uint32_t)k[5]) << 16; /* fall through */ + case 5: + b += ((uint32_t)k[4]) << 24; /* fall through */ + case 4: + a += k[3]; /* fall through */ + case 3: + a += ((uint32_t)k[2]) << 8; /* fall through */ + case 2: + a += ((uint32_t)k[1]) << 16; /* fall through */ + case 1: + a += ((uint32_t)k[0]) << 24; + break; + case 0: + return c; + } + } + + final(a, b, c); + return c; +} + +#ifdef SELF_TEST + +/* used for timings */ +void driver1(void) +{ + uint8_t buf[256]; + uint32_t i; + uint32_t h = 0; + time_t a, z; + + time(&a); + for (i = 0; i < 256; ++i) + buf[i] = 'x'; + for (i = 0; i < 1; ++i) { + h = hashlittle(&buf[0], 1, h); + } + time(&z); + if (z - a > 0) + printf("time %d %.8x\n", z - a, h); +} + +/* check that every input bit changes every output bit half the time */ +#define HASHSTATE 1 +#define HASHLEN 1 +#define MAXPAIR 60 +#define MAXLEN 70 +void driver2(void) +{ + uint8_t qa[MAXLEN + 1], qb[MAXLEN + 2], *a = &qa[0], *b = &qb[1]; + uint32_t c[HASHSTATE], d[HASHSTATE], i = 0, j = 0, k, l, m = 0, z; + uint32_t e[HASHSTATE], f[HASHSTATE], g[HASHSTATE], h[HASHSTATE]; + uint32_t x[HASHSTATE], y[HASHSTATE]; + uint32_t hlen; + + printf("No more than %d trials should ever be needed \n", MAXPAIR / 2); + for (hlen = 0; hlen < MAXLEN; ++hlen) { + z = 0; + for (i = 0; i < hlen; ++i) /*----------------------- for each input byte, */ + { + for (j = 0; j < 8; ++j) /*------------------------ for each input bit, */ + { + for (m = 1; m < 8; ++m) /*------------ for several possible initvals, */ + { + for (l = 0; l < HASHSTATE; ++l) + e[l] = f[l] = g[l] = h[l] = x[l] = y[l] = ~((uint32_t)0); + + /*---- check that every output bit is affected by that input bit */ + for (k = 0; k < MAXPAIR; k += 2) { + uint32_t finished = 1; + /* keys have one bit different */ + for (l = 0; l < hlen + 1; ++l) { + a[l] = b[l] = (uint8_t)0; + } + /* have a and b be two keys differing in only one bit */ + a[i] ^= (k << j); + a[i] ^= (k >> (8 - j)); + c[0] = hashlittle(a, hlen, m); + b[i] ^= ((k + 1) << j); + b[i] ^= ((k + 1) >> (8 - j)); + d[0] = hashlittle(b, hlen, m); + /* check every bit is 1, 0, set, and not set at least once */ + for (l = 0; l < HASHSTATE; ++l) { + e[l] &= (c[l] ^ d[l]); + f[l] &= ~(c[l] ^ d[l]); + g[l] &= c[l]; + h[l] &= ~c[l]; + x[l] &= d[l]; + y[l] &= ~d[l]; + if (e[l] | f[l] | g[l] | h[l] | x[l] | y[l]) + finished = 0; + } + if (finished) + break; + } + if (k > z) + z = k; + if (k == MAXPAIR) { + printf("Some bit didn't change: "); + printf("%.8x %.8x %.8x %.8x %.8x %.8x ", e[0], f[0], g[0], h[0], x[0], + y[0]); + printf("i %d j %d m %d len %d\n", i, j, m, hlen); + } + if (z == MAXPAIR) + goto done; + } + } + } + done: + if (z < MAXPAIR) { + printf("Mix success %2d bytes %2d initvals ", i, m); + printf("required %d trials\n", z / 2); + } + } + printf("\n"); +} + +/* Check for reading beyond the end of the buffer and alignment problems */ +void driver3(void) +{ + uint8_t buf[MAXLEN + 20], *b; + uint32_t len; + uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; + uint32_t h; + uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; + uint32_t i; + uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; + uint32_t j; + uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; + uint32_t ref, x, y; + uint8_t *p; + + printf("Endianness. These lines should all be the same (for values filled in):\n"); + printf("%.8x %.8x %.8x\n", + hashword((const uint32_t *)q, (sizeof(q) - 1) / 4, 13), + hashword((const uint32_t *)q, (sizeof(q) - 5) / 4, 13), + hashword((const uint32_t *)q, (sizeof(q) - 9) / 4, 13)); + p = q; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q) - 1, 13), hashlittle(p, sizeof(q) - 2, 13), + hashlittle(p, sizeof(q) - 3, 13), hashlittle(p, sizeof(q) - 4, 13), + hashlittle(p, sizeof(q) - 5, 13), hashlittle(p, sizeof(q) - 6, 13), + hashlittle(p, sizeof(q) - 7, 13), hashlittle(p, sizeof(q) - 8, 13), + hashlittle(p, sizeof(q) - 9, 13), hashlittle(p, sizeof(q) - 10, 13), + hashlittle(p, sizeof(q) - 11, 13), hashlittle(p, sizeof(q) - 12, 13)); + p = &qq[1]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q) - 1, 13), hashlittle(p, sizeof(q) - 2, 13), + hashlittle(p, sizeof(q) - 3, 13), hashlittle(p, sizeof(q) - 4, 13), + hashlittle(p, sizeof(q) - 5, 13), hashlittle(p, sizeof(q) - 6, 13), + hashlittle(p, sizeof(q) - 7, 13), hashlittle(p, sizeof(q) - 8, 13), + hashlittle(p, sizeof(q) - 9, 13), hashlittle(p, sizeof(q) - 10, 13), + hashlittle(p, sizeof(q) - 11, 13), hashlittle(p, sizeof(q) - 12, 13)); + p = &qqq[2]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q) - 1, 13), hashlittle(p, sizeof(q) - 2, 13), + hashlittle(p, sizeof(q) - 3, 13), hashlittle(p, sizeof(q) - 4, 13), + hashlittle(p, sizeof(q) - 5, 13), hashlittle(p, sizeof(q) - 6, 13), + hashlittle(p, sizeof(q) - 7, 13), hashlittle(p, sizeof(q) - 8, 13), + hashlittle(p, sizeof(q) - 9, 13), hashlittle(p, sizeof(q) - 10, 13), + hashlittle(p, sizeof(q) - 11, 13), hashlittle(p, sizeof(q) - 12, 13)); + p = &qqqq[3]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q) - 1, 13), hashlittle(p, sizeof(q) - 2, 13), + hashlittle(p, sizeof(q) - 3, 13), hashlittle(p, sizeof(q) - 4, 13), + hashlittle(p, sizeof(q) - 5, 13), hashlittle(p, sizeof(q) - 6, 13), + hashlittle(p, sizeof(q) - 7, 13), hashlittle(p, sizeof(q) - 8, 13), + hashlittle(p, sizeof(q) - 9, 13), hashlittle(p, sizeof(q) - 10, 13), + hashlittle(p, sizeof(q) - 11, 13), hashlittle(p, sizeof(q) - 12, 13)); + printf("\n"); + + /* check that hashlittle2 and hashlittle produce the same results */ + i = 47; + j = 0; + hashlittle2(q, sizeof(q), &i, &j); + if (hashlittle(q, sizeof(q), 47) != i) + printf("hashlittle2 and hashlittle mismatch\n"); + + /* check that hashword2 and hashword produce the same results */ + len = 0xdeadbeef; + i = 47, j = 0; + hashword2(&len, 1, &i, &j); + if (hashword(&len, 1, 47) != i) + printf("hashword2 and hashword mismatch %x %x\n", i, hashword(&len, 1, 47)); + + /* check hashlittle doesn't read before or after the ends of the string */ + for (h = 0, b = buf + 1; h < 8; ++h, ++b) { + for (i = 0; i < MAXLEN; ++i) { + len = i; + for (j = 0; j < i; ++j) + *(b + j) = 0; + + /* these should all be equal */ + ref = hashlittle(b, len, (uint32_t)1); + *(b + i) = (uint8_t)~0; + *(b - 1) = (uint8_t)~0; + x = hashlittle(b, len, (uint32_t)1); + y = hashlittle(b, len, (uint32_t)1); + if ((ref != x) || (ref != y)) { + printf("alignment error: %.8x %.8x %.8x %d %d\n", ref, x, y, h, i); + } + } + } +} + +/* check for problems with nulls */ +void driver4(void) +{ + uint8_t buf[1]; + uint32_t h, i, state[HASHSTATE]; + + buf[0] = ~0; + for (i = 0; i < HASHSTATE; ++i) + state[i] = 1; + printf("These should all be different\n"); + for (i = 0, h = 0; i < 8; ++i) { + h = hashlittle(buf, 0, h); + printf("%2ld 0-byte strings, hash is %.8x\n", i, h); + } +} + +void driver5(void) +{ + uint32_t b, c; + b = 0, c = 0, hashlittle2("", 0, &c, &b); + printf("hash is %.8lx %.8lx\n", c, b); /* deadbeef deadbeef */ + b = 0xdeadbeef, c = 0, hashlittle2("", 0, &c, &b); + printf("hash is %.8lx %.8lx\n", c, b); /* bd5b7dde deadbeef */ + b = 0xdeadbeef, c = 0xdeadbeef, hashlittle2("", 0, &c, &b); + printf("hash is %.8lx %.8lx\n", c, b); /* 9c093ccd bd5b7dde */ + b = 0, c = 0, hashlittle2("Four score and seven years ago", 30, &c, &b); + printf("hash is %.8lx %.8lx\n", c, b); /* 17770551 ce7226e6 */ + b = 1, c = 0, hashlittle2("Four score and seven years ago", 30, &c, &b); + printf("hash is %.8lx %.8lx\n", c, b); /* e3607cae bd371de4 */ + b = 0, c = 1, hashlittle2("Four score and seven years ago", 30, &c, &b); + printf("hash is %.8lx %.8lx\n", c, b); /* cd628161 6cbea4b3 */ + c = hashlittle("Four score and seven years ago", 30, 0); + printf("hash is %.8lx\n", c); /* 17770551 */ + c = hashlittle("Four score and seven years ago", 30, 1); + printf("hash is %.8lx\n", c); /* cd628161 */ +} + +int main(void) +{ + driver1(); /* test that the key is hashed: used for timings */ + driver2(); /* test that whole key is hashed thoroughly */ + driver3(); /* test that nothing but the key is hashed */ + driver4(); /* test hashing multiple buffers (all buffers are null) */ + driver5(); /* test the hash against known vectors */ + return 1; +} + +#endif /* SELF_TEST */ diff --git a/src/util/hash-lookup3.h b/src/util/hash-lookup3.h new file mode 100644 index 000000000000..13b520d6b6a4 --- /dev/null +++ b/src/util/hash-lookup3.h @@ -0,0 +1,66 @@ +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +#ifndef __UTIL_HASH_LOOKUP3_H__ +#define __UTIL_HASH_LOOKUP3_H__ + +#define hashsize(n) ((uint32_t)1 << (n)) +#define hashmask(n) (hashsize(n) - 1) + +uint32_t hashword(const uint32_t *k, /* the key, an array of uint32_t values */ + size_t length, /* the length of the key, in uint32_ts */ + uint32_t initval); /* the previous hash, or an arbitrary value */ + +void hashword2(const uint32_t *k, /* the key, an array of uint32_t values */ + size_t length, /* the length of the key, in uint32_ts */ + uint32_t *pc, /* IN: seed OUT: primary hash value */ + uint32_t *pb); /* IN: more seed OUT: secondary hash value */ + +uint32_t hashlittle(const void *key, size_t length, uint32_t initval); + +/* A variant of hashlittle() that ensures avoids accesses beyond the last byte + * of the string, which will cause warnings from tools like Valgrind or Address + * Sanitizer. */ +uint32_t hashlittle_safe(const void *key, size_t length, uint32_t initval); + +void hashlittle2(const void *key, /* the key to hash */ + size_t length, /* length of the key */ + uint32_t *pc, /* IN: primary initval, OUT: primary hash */ + uint32_t *pb); /* IN: secondary initval, OUT: secondary hash */ + +uint32_t hashbig(const void *key, size_t length, uint32_t initval); + +#endif /* __UTIL_HASH_LOOKUP3_H__ */ diff --git a/src/util/hash-string.c b/src/util/hash-string.c new file mode 100644 index 000000000000..b5e65e2bf6d8 --- /dev/null +++ b/src/util/hash-string.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "util/hash-string.h" + +/* djb2 string hashing */ +uint32_t StringHashDjb2(const uint8_t *data, uint32_t datalen) +{ + uint32_t hash = 5381; + for (uint32_t i = 0; i < datalen; i++) { + uint32_t c = data[i]; + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + } + return hash; +} + +/* djb2 string hashing */ +uint32_t StringHashFunc(HashTable *ht, void *data, uint16_t datalen) +{ + return StringHashDjb2(data, datalen) % ht->array_size; +} + +char StringHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) +{ + int len1 = strlen((char *)data1); + int len2 = strlen((char *)data2); + + if (len1 == len2 && memcmp(data1, data2, len1) == 0) { + return 1; + } + + return 0; +} + +void StringHashFreeFunc(void *data) +{ + SCFree(data); +} diff --git a/src/util/hash-string.h b/src/util/hash-string.h new file mode 100644 index 000000000000..7671c9fdf1ca --- /dev/null +++ b/src/util/hash-string.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_HASH_STRING_H__ +#define __UTIL_HASH_STRING_H__ + +#include "util/hash.h" + +uint32_t StringHashDjb2(const uint8_t *data, uint32_t datalen); +uint32_t StringHashFunc(HashTable *ht, void *data, uint16_t datalen); +char StringHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2); +void StringHashFreeFunc(void *data); + +#endif /* __UTIL_HASH_STRING_H__ */ diff --git a/src/util/hash.c b/src/util/hash.c new file mode 100644 index 000000000000..fa925f52a5ab --- /dev/null +++ b/src/util/hash.c @@ -0,0 +1,450 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Chained hash table implementation + * + * The 'Free' pointer can be used to have the API free your + * hashed data. If it's NULL it's the callers responsibility + */ + +#include "suricata-common.h" +#include "util/hash.h" +#include "util/unittest.h" +#include "util/memcmp.h" +#include "util/debug.h" + +HashTable *HashTableInit(uint32_t size, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), + char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)) +{ + + HashTable *ht = NULL; + + if (size == 0) { + goto error; + } + + if (Hash == NULL) { + // printf("ERROR: HashTableInit no Hash function\n"); + goto error; + } + + /* setup the filter */ + ht = SCCalloc(1, sizeof(HashTable)); + if (unlikely(ht == NULL)) + goto error; + ht->array_size = size; + ht->Hash = Hash; + ht->Free = Free; + + if (Compare != NULL) + ht->Compare = Compare; + else + ht->Compare = HashTableDefaultCompare; + + /* setup the bitarray */ + ht->array = SCCalloc(ht->array_size, sizeof(HashTableBucket *)); + if (ht->array == NULL) + goto error; + + return ht; + +error: + if (ht != NULL) { + if (ht->array != NULL) + SCFree(ht->array); + + SCFree(ht); + } + return NULL; +} + +void HashTableFree(HashTable *ht) +{ + uint32_t i = 0; + + if (ht == NULL) + return; + + /* free the buckets */ + for (i = 0; i < ht->array_size; i++) { + HashTableBucket *hashbucket = ht->array[i]; + while (hashbucket != NULL) { + HashTableBucket *next_hashbucket = hashbucket->next; + if (ht->Free != NULL) + ht->Free(hashbucket->data); + SCFree(hashbucket); + hashbucket = next_hashbucket; + } + } + + /* free the array */ + if (ht->array != NULL) + SCFree(ht->array); + + SCFree(ht); +} + +void HashTablePrint(HashTable *ht) +{ + printf("\n----------- Hash Table Stats ------------\n"); + printf("Buckets: %" PRIu32 "\n", ht->array_size); + printf("Hash function pointer: %p\n", ht->Hash); + printf("-----------------------------------------\n"); +} + +int HashTableAdd(HashTable *ht, void *data, uint16_t datalen) +{ + if (ht == NULL || data == NULL) + return -1; + + uint32_t hash = ht->Hash(ht, data, datalen); + + HashTableBucket *hb = SCCalloc(1, sizeof(HashTableBucket)); + if (unlikely(hb == NULL)) + goto error; + hb->data = data; + hb->size = datalen; + hb->next = NULL; + + if (hash >= ht->array_size) { + SCLogWarning("attempt to insert element out of hash array\n"); + goto error; + } + + if (ht->array[hash] == NULL) { + ht->array[hash] = hb; + } else { + hb->next = ht->array[hash]; + ht->array[hash] = hb; + } + +#ifdef UNITTESTS + ht->count++; +#endif + + return 0; + +error: + if (hb != NULL) + SCFree(hb); + return -1; +} + +int HashTableRemove(HashTable *ht, void *data, uint16_t datalen) +{ + uint32_t hash = ht->Hash(ht, data, datalen); + + if (ht->array[hash] == NULL) { + return -1; + } + + if (ht->array[hash]->next == NULL) { + if (ht->Free != NULL) + ht->Free(ht->array[hash]->data); + SCFree(ht->array[hash]); + ht->array[hash] = NULL; + return 0; + } + + HashTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL; + do { + if (ht->Compare(hashbucket->data, hashbucket->size, data, datalen) == 1) { + if (prev_hashbucket == NULL) { + /* root bucket */ + ht->array[hash] = hashbucket->next; + } else { + /* child bucket */ + prev_hashbucket->next = hashbucket->next; + } + + /* remove this */ + if (ht->Free != NULL) + ht->Free(hashbucket->data); + SCFree(hashbucket); + return 0; + } + + prev_hashbucket = hashbucket; + hashbucket = hashbucket->next; + } while (hashbucket != NULL); + + return -1; +} + +void *HashTableLookup(HashTable *ht, void *data, uint16_t datalen) +{ + uint32_t hash = 0; + + if (ht == NULL) + return NULL; + + hash = ht->Hash(ht, data, datalen); + + if (hash >= ht->array_size) { + SCLogWarning("attempt to access element out of hash array\n"); + return NULL; + } + + if (ht->array[hash] == NULL) + return NULL; + + HashTableBucket *hashbucket = ht->array[hash]; + do { + if (ht->Compare(hashbucket->data, hashbucket->size, data, datalen) == 1) + return hashbucket->data; + + hashbucket = hashbucket->next; + } while (hashbucket != NULL); + + return NULL; +} + +uint32_t HashTableGenericHash(HashTable *ht, void *data, uint16_t datalen) +{ + uint8_t *d = (uint8_t *)data; + uint32_t i; + uint32_t hash = 0; + + for (i = 0; i < datalen; i++) { + if (i == 0) + hash += (((uint32_t)*d++)); + else if (i == 1) + hash += (((uint32_t)*d++) * datalen); + else + hash *= (((uint32_t)*d++) * i) + datalen + i; + } + + hash *= datalen; + hash %= ht->array_size; + return hash; +} + +char HashTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2) +{ + if (len1 != len2) + return 0; + + if (SCMemcmp(data1, data2, len1) != 0) + return 0; + + return 1; +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +static int HashTableTestInit01(void) +{ + HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + return 0; + + HashTableFree(ht); + return 1; +} + +/* no hash function, so it should fail */ +static int HashTableTestInit02(void) +{ + HashTable *ht = HashTableInit(1024, NULL, NULL, NULL); + if (ht == NULL) + return 1; + + HashTableFree(ht); + return 0; +} + +static int HashTableTestInit03(void) +{ + int result = 0; + HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + return 0; + + if (ht->Hash == HashTableGenericHash) + result = 1; + + HashTableFree(ht); + return result; +} + +static int HashTableTestInit04(void) +{ + HashTable *ht = HashTableInit(0, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + return 1; + + HashTableFree(ht); + return 0; +} + +static int HashTableTestInit05(void) +{ + int result = 0; + HashTable *ht = HashTableInit(1024, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + return 0; + + if (ht->Compare == HashTableDefaultCompare) + result = 1; + + HashTableFree(ht); + return result; +} + +static char HashTableDefaultCompareTest(void *data1, uint16_t len1, void *data2, uint16_t len2) +{ + if (len1 != len2) + return 0; + + if (SCMemcmp(data1, data2, len1) != 0) + return 0; + + return 1; +} + +static int HashTableTestInit06(void) +{ + int result = 0; + HashTable *ht = HashTableInit(1024, HashTableGenericHash, HashTableDefaultCompareTest, NULL); + if (ht == NULL) + return 0; + + if (ht->Compare == HashTableDefaultCompareTest) + result = 1; + + HashTableFree(ht); + return result; +} + +static int HashTableTestAdd01(void) +{ + int result = 0; + HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashTableAdd(ht, (char *)"test", 0); + if (r != 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashTableFree(ht); + return result; +} + +static int HashTableTestAdd02(void) +{ + int result = 0; + HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashTableAdd(ht, NULL, 4); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashTableFree(ht); + return result; +} + +static int HashTableTestFull01(void) +{ + int result = 0; + HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashTableAdd(ht, (char *)"test", 4); + if (r != 0) + goto end; + + char *rp = HashTableLookup(ht, (char *)"test", 4); + if (rp == NULL) + goto end; + + r = HashTableRemove(ht, (char *)"test", 4); + if (r != 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashTableFree(ht); + return result; +} + +static int HashTableTestFull02(void) +{ + int result = 0; + HashTable *ht = HashTableInit(32, HashTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashTableAdd(ht, (char *)"test", 4); + if (r != 0) + goto end; + + char *rp = HashTableLookup(ht, (char *)"test", 4); + if (rp == NULL) + goto end; + + r = HashTableRemove(ht, (char *)"test2", 5); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashTableFree(ht); + return result; +} +#endif + +void HashTableRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HashTableTestInit01", HashTableTestInit01); + UtRegisterTest("HashTableTestInit02", HashTableTestInit02); + UtRegisterTest("HashTableTestInit03", HashTableTestInit03); + UtRegisterTest("HashTableTestInit04", HashTableTestInit04); + UtRegisterTest("HashTableTestInit05", HashTableTestInit05); + UtRegisterTest("HashTableTestInit06", HashTableTestInit06); + + UtRegisterTest("HashTableTestAdd01", HashTableTestAdd01); + UtRegisterTest("HashTableTestAdd02", HashTableTestAdd02); + + UtRegisterTest("HashTableTestFull01", HashTableTestFull01); + UtRegisterTest("HashTableTestFull02", HashTableTestFull02); +#endif +} diff --git a/src/util/hash.h b/src/util/hash.h new file mode 100644 index 000000000000..7623aa47ed7c --- /dev/null +++ b/src/util/hash.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __HASH_H__ +#define __HASH_H__ + +/* hash bucket structure */ +typedef struct HashTableBucket_ { + void *data; + uint16_t size; + struct HashTableBucket_ *next; +} HashTableBucket; + +/* hash table structure */ +typedef struct HashTable_ { + HashTableBucket **array; + uint32_t array_size; +#ifdef UNITTESTS + uint32_t count; +#endif + uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t); + char (*Compare)(void *, uint16_t, void *, uint16_t); + void (*Free)(void *); +} HashTable; + +#define HASH_NO_SIZE 0 + +/* prototypes */ +HashTable *HashTableInit(uint32_t, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), + char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)); +void HashTableFree(HashTable *); +void HashTablePrint(HashTable *); +int HashTableAdd(HashTable *, void *, uint16_t); +int HashTableRemove(HashTable *, void *, uint16_t); +void *HashTableLookup(HashTable *, void *, uint16_t); +uint32_t HashTableGenericHash(HashTable *, void *, uint16_t); +char HashTableDefaultCompare(void *, uint16_t, void *, uint16_t); + +void HashTableRegisterTests(void); + +#endif /* __HASH_H__ */ diff --git a/src/util/hashlist.c b/src/util/hashlist.c new file mode 100644 index 000000000000..4d46894483ad --- /dev/null +++ b/src/util/hashlist.c @@ -0,0 +1,531 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Chained hash table implementation + * + * The 'Free' pointer can be used to have the API free your + * hashed data. If it's NULL it's the callers responsibility + */ + +#include "suricata-common.h" +#include "util/hashlist.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/memcmp.h" + +HashListTable *HashListTableInit(uint32_t size, + uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t), + char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)) +{ + sc_errno = SC_OK; + HashListTable *ht = NULL; + + if (size == 0) { + sc_errno = SC_EINVAL; + goto error; + } + + if (Hash == NULL) { + sc_errno = SC_EINVAL; + goto error; + } + + /* setup the filter */ + ht = SCCalloc(1, sizeof(HashListTable)); + if (unlikely(ht == NULL)) { + sc_errno = SC_ENOMEM; + goto error; + } + ht->array_size = size; + ht->Hash = Hash; + ht->Free = Free; + + if (Compare != NULL) + ht->Compare = Compare; + else + ht->Compare = HashListTableDefaultCompare; + + /* setup the bitarray */ + ht->array = SCCalloc(ht->array_size, sizeof(HashListTableBucket *)); + if (ht->array == NULL) { + sc_errno = SC_ENOMEM; + goto error; + } + + ht->listhead = NULL; + ht->listtail = NULL; + return ht; + +error: + if (ht != NULL) { + if (ht->array != NULL) + SCFree(ht->array); + + SCFree(ht); + } + return NULL; +} + +void HashListTableFree(HashListTable *ht) +{ + uint32_t i = 0; + + if (ht == NULL) + return; + + /* free the buckets */ + for (i = 0; i < ht->array_size; i++) { + HashListTableBucket *hashbucket = ht->array[i]; + while (hashbucket != NULL) { + HashListTableBucket *next_hashbucket = hashbucket->bucknext; + if (ht->Free != NULL) + ht->Free(hashbucket->data); + SCFree(hashbucket); + hashbucket = next_hashbucket; + } + } + + /* free the array */ + if (ht->array != NULL) + SCFree(ht->array); + + SCFree(ht); +} + +void HashListTablePrint(HashListTable *ht) +{ + printf("\n----------- Hash Table Stats ------------\n"); + printf("Buckets: %" PRIu32 "\n", ht->array_size); + printf("Hash function pointer: %p\n", ht->Hash); + printf("-----------------------------------------\n"); +} + +int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen) +{ + if (ht == NULL || data == NULL) + return -1; + + uint32_t hash = ht->Hash(ht, data, datalen); + + SCLogDebug("ht %p hash %" PRIu32 "", ht, hash); + + HashListTableBucket *hb = SCCalloc(1, sizeof(HashListTableBucket)); + if (unlikely(hb == NULL)) + goto error; + hb->data = data; + hb->size = datalen; + hb->bucknext = NULL; + hb->listnext = NULL; + hb->listprev = NULL; + + if (ht->array[hash] == NULL) { + ht->array[hash] = hb; + } else { + hb->bucknext = ht->array[hash]; + ht->array[hash] = hb; + } + + if (ht->listtail == NULL) { + ht->listhead = hb; + ht->listtail = hb; + } else { + hb->listprev = ht->listtail; + ht->listtail->listnext = hb; + ht->listtail = hb; + } + + return 0; + +error: + return -1; +} + +int HashListTableRemove(HashListTable *ht, void *data, uint16_t datalen) +{ + uint32_t hash = ht->Hash(ht, data, datalen); + + SCLogDebug("ht %p hash %" PRIu32 "", ht, hash); + + if (ht->array[hash] == NULL) { + SCLogDebug("ht->array[hash] NULL"); + return -1; + } + + /* fast track for just one data part */ + if (ht->array[hash]->bucknext == NULL) { + HashListTableBucket *hb = ht->array[hash]; + + if (ht->Compare(hb->data, hb->size, data, datalen) == 1) { + /* remove from the list */ + if (hb->listprev == NULL) { + ht->listhead = hb->listnext; + } else { + hb->listprev->listnext = hb->listnext; + } + if (hb->listnext == NULL) { + ht->listtail = hb->listprev; + } else { + hb->listnext->listprev = hb->listprev; + } + + if (ht->Free != NULL) + ht->Free(hb->data); + + SCFree(ht->array[hash]); + ht->array[hash] = NULL; + return 0; + } + + SCLogDebug("fast track default case"); + return -1; + } + + /* more data in this bucket */ + HashListTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL; + do { + if (ht->Compare(hashbucket->data, hashbucket->size, data, datalen) == 1) { + + /* remove from the list */ + if (hashbucket->listprev == NULL) { + ht->listhead = hashbucket->listnext; + } else { + hashbucket->listprev->listnext = hashbucket->listnext; + } + if (hashbucket->listnext == NULL) { + ht->listtail = hashbucket->listprev; + } else { + hashbucket->listnext->listprev = hashbucket->listprev; + } + + if (prev_hashbucket == NULL) { + /* root bucket */ + ht->array[hash] = hashbucket->bucknext; + } else { + /* child bucket */ + prev_hashbucket->bucknext = hashbucket->bucknext; + } + + /* remove this */ + if (ht->Free != NULL) + ht->Free(hashbucket->data); + SCFree(hashbucket); + return 0; + } + + prev_hashbucket = hashbucket; + hashbucket = hashbucket->bucknext; + } while (hashbucket != NULL); + + SCLogDebug("slow track default case"); + return -1; +} + +char HashListTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2) +{ + if (len1 != len2) + return 0; + + if (SCMemcmp(data1, data2, len1) != 0) + return 0; + + return 1; +} + +void *HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen) +{ + + if (ht == NULL) { + SCLogDebug("Hash List table is NULL"); + return NULL; + } + + uint32_t hash = ht->Hash(ht, data, datalen); + + if (ht->array[hash] == NULL) { + return NULL; + } + + HashListTableBucket *hashbucket = ht->array[hash]; + do { + if (ht->Compare(hashbucket->data, hashbucket->size, data, datalen) == 1) + return hashbucket->data; + + hashbucket = hashbucket->bucknext; + } while (hashbucket != NULL); + + return NULL; +} + +uint32_t HashListTableGenericHash(HashListTable *ht, void *data, uint16_t datalen) +{ + uint8_t *d = (uint8_t *)data; + uint32_t i; + uint32_t hash = 0; + + for (i = 0; i < datalen; i++) { + if (i == 0) + hash += (((uint32_t)*d++)); + else if (i == 1) + hash += (((uint32_t)*d++) * datalen); + else + hash *= (((uint32_t)*d++) * i) + datalen + i; + } + + hash *= datalen; + hash %= ht->array_size; + return hash; +} + +HashListTableBucket *HashListTableGetListHead(HashListTable *ht) +{ + return ht->listhead; +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +static int HashListTableTestInit01(void) +{ + HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + return 0; + + HashListTableFree(ht); + return 1; +} + +/* no hash function, so it should fail */ +static int HashListTableTestInit02(void) +{ + HashListTable *ht = HashListTableInit(1024, NULL, NULL, NULL); + if (ht == NULL) + return 1; + + HashListTableFree(ht); + return 0; +} + +static int HashListTableTestInit03(void) +{ + int result = 0; + HashListTable *ht = HashListTableInit(1024, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + return 0; + + if (ht->Hash == HashListTableGenericHash) + result = 1; + + HashListTableFree(ht); + return result; +} + +static int HashListTableTestInit04(void) +{ + HashListTable *ht = HashListTableInit(0, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + return 1; + + HashListTableFree(ht); + return 0; +} + +static int HashListTableTestAdd01(void) +{ + int result = 0; + HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashListTableAdd(ht, (char *)"test", 0); + if (r != 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashListTableFree(ht); + return result; +} + +static int HashListTableTestAdd02(void) +{ + int result = 0; + HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashListTableAdd(ht, NULL, 4); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashListTableFree(ht); + return result; +} + +static int HashListTableTestAdd03(void) +{ + int result = 0; + HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashListTableAdd(ht, (char *)"test", 0); + if (r != 0) + goto end; + + if (ht->listhead == NULL) { + printf("ht->listhead == NULL: "); + goto end; + } + + if (ht->listtail == NULL) { + printf("ht->listtail == NULL: "); + goto end; + } + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashListTableFree(ht); + return result; +} + +static int HashListTableTestAdd04(void) +{ + int result = 0; + HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashListTableAdd(ht, (char *)"test", 4); + if (r != 0) + goto end; + + char *rp = HashListTableLookup(ht, (char *)"test", 4); + if (rp == NULL) + goto end; + + HashListTableBucket *htb = HashListTableGetListHead(ht); + if (htb == NULL) { + printf("htb == NULL: "); + goto end; + } + + char *rp2 = HashListTableGetListData(htb); + if (rp2 == NULL) { + printf("rp2 == NULL: "); + goto end; + } + + if (rp != rp2) { + printf("rp != rp2: "); + goto end; + } + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashListTableFree(ht); + return result; +} + +static int HashListTableTestFull01(void) +{ + int result = 0; + HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashListTableAdd(ht, (char *)"test", 4); + if (r != 0) + goto end; + + char *rp = HashListTableLookup(ht, (char *)"test", 4); + if (rp == NULL) + goto end; + + r = HashListTableRemove(ht, (char *)"test", 4); + if (r != 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashListTableFree(ht); + return result; +} + +static int HashListTableTestFull02(void) +{ + int result = 0; + HashListTable *ht = HashListTableInit(32, HashListTableGenericHash, NULL, NULL); + if (ht == NULL) + goto end; + + int r = HashListTableAdd(ht, (char *)"test", 4); + if (r != 0) + goto end; + + char *rp = HashListTableLookup(ht, (char *)"test", 4); + if (rp == NULL) + goto end; + + r = HashListTableRemove(ht, (char *)"test2", 5); + if (r == 0) + goto end; + + /* all is good! */ + result = 1; +end: + if (ht != NULL) + HashListTableFree(ht); + return result; +} +#endif /* UNITTESTS */ + +void HashListTableRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01); + UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02); + UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03); + UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04); + + UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01); + UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02); + UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03); + UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04); + + UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01); + UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02); +#endif /* UNITTESTS */ +} diff --git a/src/util/hashlist.h b/src/util/hashlist.h new file mode 100644 index 000000000000..a41d0e6d2df4 --- /dev/null +++ b/src/util/hashlist.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __HASHLIST_H__ +#define __HASHLIST_H__ + +/* hash bucket structure */ +typedef struct HashListTableBucket_ { + void *data; + uint16_t size; + struct HashListTableBucket_ *bucknext; + struct HashListTableBucket_ *listnext; + struct HashListTableBucket_ *listprev; +} HashListTableBucket; + +/* hash table structure */ +typedef struct HashListTable_ { + HashListTableBucket **array; + HashListTableBucket *listhead; + HashListTableBucket *listtail; + uint32_t array_size; + uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t); + char (*Compare)(void *, uint16_t, void *, uint16_t); + void (*Free)(void *); +} HashListTable; + +/* prototypes */ +HashListTable *HashListTableInit(uint32_t, + uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t), + char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)); +void HashListTableFree(HashListTable *); +void HashListTablePrint(HashListTable *); +int HashListTableAdd(HashListTable *, void *, uint16_t); +int HashListTableRemove(HashListTable *, void *, uint16_t); +void *HashListTableLookup(HashListTable *, void *, uint16_t); +uint32_t HashListTableGenericHash(HashListTable *, void *, uint16_t); +HashListTableBucket *HashListTableGetListHead(HashListTable *); +#define HashListTableGetListNext(hb) (hb)->listnext +#define HashListTableGetListData(hb) (hb)->data +char HashListTableDefaultCompare(void *, uint16_t, void *, uint16_t); + +void HashListTableRegisterTests(void); + +#endif /* __HASHLIST_H__ */ diff --git a/src/util/host-info.c b/src/util/host-info.c new file mode 100644 index 000000000000..1ca2a549e18a --- /dev/null +++ b/src/util/host-info.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + * Get information on running host + * + */ + +#include "suricata-common.h" +#include "util/host-info.h" +#include "util/byte.h" +#include "util/debug.h" + +#ifndef OS_WIN32 +#include + +#define VERSION_REGEX "^([0-9]+)\\.([0-9]+)" + +int SCKernelVersionIsAtLeast(int major, int minor) +{ + struct utsname kuname; + pcre2_code *version_regex; + pcre2_match_data *version_regex_match; + int en; + int opts = 0; + PCRE2_SIZE eo; + int ret; + int kmajor, kminor; + PCRE2_UCHAR **list; + + /* get local version */ + if (uname(&kuname) != 0) { + SCLogError("Invalid uname return: %s", strerror(errno)); + return 0; + } + + SCLogDebug("Kernel release is '%s'", kuname.release); + + version_regex = + pcre2_compile((PCRE2_SPTR8)VERSION_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + if (version_regex == NULL) { + PCRE2_UCHAR errbuffer[256]; + pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); + SCLogError("pcre2 compile of \"%s\" failed at " + "offset %d: %s", + VERSION_REGEX, (int)eo, errbuffer); + goto error; + } + version_regex_match = pcre2_match_data_create_from_pattern(version_regex, NULL); + + ret = pcre2_match(version_regex, (PCRE2_SPTR8)kuname.release, strlen(kuname.release), 0, 0, + version_regex_match, NULL); + + if (ret < 0) { + SCLogError("Version did not cut"); + goto error; + } + + if (ret < 3) { + SCLogError("Version major and minor not found (ret %d)", ret); + goto error; + } + + pcre2_substring_list_get(version_regex_match, &list, NULL); + + bool err = false; + if (StringParseInt32(&kmajor, 10, 0, (const char *)list[1]) < 0) { + SCLogError("Invalid value for kmajor: '%s'", list[1]); + err = true; + } + if (StringParseInt32(&kminor, 10, 0, (const char *)list[2]) < 0) { + SCLogError("Invalid value for kminor: '%s'", list[2]); + err = true; + } + + pcre2_substring_list_free((PCRE2_SPTR *)list); + pcre2_match_data_free(version_regex_match); + pcre2_code_free(version_regex); + + if (err) + goto error; + + if (kmajor > major) + return 1; + if (kmajor == major && kminor >= minor) + return 1; +error: + return 0; +} + +#else /* OS_WIN32 */ + +int SCKernelVersionIsAtLeast(int major, int minor) +{ + SCLogError("OS compare is not supported on Windows"); + return 0; +} + +#endif /* OS_WIN32 */ diff --git a/src/util-host-info.h b/src/util/host-info.h similarity index 100% rename from src/util-host-info.h rename to src/util/host-info.h diff --git a/src/util/host-os-info.c b/src/util/host-os-info.c new file mode 100644 index 000000000000..a0b9472d9c39 --- /dev/null +++ b/src/util/host-os-info.c @@ -0,0 +1,1590 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Host info utility functions + */ + +#include "suricata-common.h" +#include "util/host-os-info.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/ip.h" +#include "util/radix-tree.h" +#include "util/byte.h" +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" + +#include "../conf.h" +#include "conf-yaml-loader.h" + +#include "util/enum.h" +#include "util/unittest.h" + +/** Enum map for the various OS flavours */ +SCEnumCharMap sc_hinfo_os_policy_map[] = { + { "none", OS_POLICY_NONE }, + { "bsd", OS_POLICY_BSD }, + { "bsd-right", OS_POLICY_BSD_RIGHT }, + { "old-linux", OS_POLICY_OLD_LINUX }, + { "linux", OS_POLICY_LINUX }, + { "old-solaris", OS_POLICY_OLD_SOLARIS }, + { "solaris", OS_POLICY_SOLARIS }, + { "hpux10", OS_POLICY_HPUX10 }, + { "hpux11", OS_POLICY_HPUX11 }, + { "irix", OS_POLICY_IRIX }, + { "macos", OS_POLICY_MACOS }, + { "windows", OS_POLICY_WINDOWS }, + { "vista", OS_POLICY_VISTA }, + { "windows2k3", OS_POLICY_WINDOWS2K3 }, + { NULL, -1 }, +}; + +/** Radix tree that holds the host OS information */ +static SCRadixTree *sc_hinfo_tree = NULL; + +/** + * \brief Allocates the host_os flavour wrapped in user_data variable to be sent + * along with the key to the radix tree + * + * \param host_os Pointer to a character string containing the host_os flavour + * + * \retval user_data On success, pointer to the user_data that has to be sent + * along with the key, to be added to the Radix tree; NULL on + * failure + * \initonly + */ +static void *SCHInfoAllocUserDataOSPolicy(const char *host_os) +{ + int *user_data = NULL; + + if ((user_data = SCMalloc(sizeof(int))) == NULL) { + FatalError("Error allocating memory. Exiting"); + } + + /* the host os flavour that has to be sent as user data */ + if ((*user_data = SCMapEnumNameToValue(host_os, sc_hinfo_os_policy_map)) == -1) { + SCLogError("Invalid enum map inside " + "SCHInfoAddHostOSInfo()"); + SCFree(user_data); + return NULL; + } + + return (void *)user_data; +} + +/** + * \brief Used to free the user data that is allocated by host_os_info API + * + * \param Pointer to the data that has to be freed + */ +static void SCHInfoFreeUserDataOSPolicy(void *data) +{ + if (data != NULL) + SCFree(data); + + return; +} + +/** + * \brief Used to add the host-os-info data obtained from the conf + * + * \param host_os The host_os name/flavour from the conf file + * \param host_os_ip_range Pointer to a char string holding the ip/ip_netblock + * for the host_os specified in the first argument + * \param is_ipv4 Indicates if the ip address to be considered for the + * default configuration is IPV4; if not it is IPV6. + * Specified using SC_HINFO_IS_IPV6 or SC_HINFO_IS_IPV4 + * + * \retval 0 On successfully adding the host os info to the Radix tree + * \retval -1 On failure + * \initonly (only specified from config, at the startup) + */ +int SCHInfoAddHostOSInfo(const char *host_os, const char *host_os_ip_range, int is_ipv4) +{ + char *ip_str = NULL; + char *ip_str_rem = NULL; + struct in_addr *ipv4_addr = NULL; + struct in6_addr *ipv6_addr = NULL; + char *netmask_str = NULL; + uint8_t netmask_value = 0; + int *user_data = NULL; + bool recursive = false; + + if (host_os == NULL || host_os_ip_range == NULL || strlen(host_os_ip_range) == 0) { + SCLogError("Invalid arguments"); + return -1; + } + + /* create the radix tree that would hold all the host os info */ + if (sc_hinfo_tree == NULL) + sc_hinfo_tree = SCRadixCreateRadixTree(SCHInfoFreeUserDataOSPolicy, NULL); + + /* the host os flavour that has to be sent as user data */ + if ((user_data = SCHInfoAllocUserDataOSPolicy(host_os)) == NULL) { + SCLogError("Invalid enum map inside"); + return -1; + } + + /* if we have a default configuration set the appropriate values for the + * netblocks */ + if ((strcasecmp(host_os_ip_range, "default")) == 0) { + if (is_ipv4) + host_os_ip_range = "0.0.0.0/0"; + else + host_os_ip_range = "::/0"; + } + + if ((ip_str = SCStrdup(host_os_ip_range)) == NULL) { + FatalError("Error allocating memory"); + } + + /* check if we have more addresses in the host_os_ip_range */ + if ((ip_str_rem = strchr(ip_str, ',')) != NULL) { + ip_str_rem[0] = '\0'; + ip_str_rem++; + recursive = true; + } + + /* check if we have received a netblock */ + if ((netmask_str = strchr(ip_str, '/')) != NULL) { + netmask_str[0] = '\0'; + netmask_str++; + } + + if (strchr(ip_str, ':') == NULL) { + /* if we are here, we have an IPV4 address */ + if ((ipv4_addr = ValidateIPV4Address(ip_str)) == NULL) { + SCLogError("Invalid IPV4 address"); + SCHInfoFreeUserDataOSPolicy(user_data); + SCFree(ip_str); + return -1; + } + + if (netmask_str == NULL) { + SCRadixAddKeyIPV4((uint8_t *)ipv4_addr, sc_hinfo_tree, (void *)user_data); + } else { + if (StringParseU8RangeCheck(&netmask_value, 10, 0, (const char *)netmask_str, 0, 32) < + 0) { + SCLogError("Invalid IPV4 Netblock"); + SCHInfoFreeUserDataOSPolicy(user_data); + SCFree(ipv4_addr); + SCFree(ip_str); + return -1; + } + + MaskIPNetblock((uint8_t *)ipv4_addr, netmask_value, 32); + SCRadixAddKeyIPV4Netblock( + (uint8_t *)ipv4_addr, sc_hinfo_tree, (void *)user_data, netmask_value); + } + } else { + /* if we are here, we have an IPV6 address */ + if ((ipv6_addr = ValidateIPV6Address(ip_str)) == NULL) { + SCLogError("Invalid IPV6 address inside"); + SCHInfoFreeUserDataOSPolicy(user_data); + SCFree(ip_str); + return -1; + } + + if (netmask_str == NULL) { + SCRadixAddKeyIPV6((uint8_t *)ipv6_addr, sc_hinfo_tree, (void *)user_data); + } else { + if (StringParseU8RangeCheck(&netmask_value, 10, 0, (const char *)netmask_str, 0, 128) < + 0) { + SCLogError("Invalid IPV6 Netblock"); + SCHInfoFreeUserDataOSPolicy(user_data); + SCFree(ipv6_addr); + SCFree(ip_str); + return -1; + } + + MaskIPNetblock((uint8_t *)ipv6_addr, netmask_value, 128); + SCRadixAddKeyIPV6Netblock( + (uint8_t *)ipv6_addr, sc_hinfo_tree, (void *)user_data, netmask_value); + } + } + + if (recursive) { + SCHInfoAddHostOSInfo(host_os, ip_str_rem, is_ipv4); + } + + SCFree(ip_str); + if (ipv4_addr != NULL) + SCFree(ipv4_addr); + if (ipv6_addr != NULL) + SCFree(ipv6_addr); + return *user_data; +} + +/** + * \brief Retrieves the host os flavour, given an ipv4/ipv6 address as a string. + * + * \param Pointer to a string containing an IP address + * + * \retval The OS flavour on success; -1 on failure, or on not finding the key + */ +int SCHInfoGetHostOSFlavour(const char *ip_addr_str) +{ + struct in_addr *ipv4_addr = NULL; + struct in6_addr *ipv6_addr = NULL; + void *user_data = NULL; + + if (ip_addr_str == NULL || strchr(ip_addr_str, '/') != NULL) + return -1; + + if (strchr(ip_addr_str, ':') != NULL) { + if ((ipv6_addr = ValidateIPV6Address(ip_addr_str)) == NULL) { + SCLogError("Invalid IPV4 address"); + return -1; + } + + (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)ipv6_addr, sc_hinfo_tree, &user_data); + SCFree(ipv6_addr); + if (user_data == NULL) + return -1; + else + return *((int *)user_data); + } else { + if ((ipv4_addr = ValidateIPV4Address(ip_addr_str)) == NULL) { + SCLogError("Invalid IPV4 address"); + return -1; + } + + (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)ipv4_addr, sc_hinfo_tree, &user_data); + SCFree(ipv4_addr); + if (user_data == NULL) + return -1; + else + return *((int *)user_data); + } +} + +/** + * \brief Retrieves the host os flavour, given an ipv4 address in the raw + * address format. + * + * \param Pointer to a raw ipv4 address. + * + * \retval The OS flavour on success; -1 on failure, or on not finding the key + */ +int SCHInfoGetIPv4HostOSFlavour(uint8_t *ipv4_addr) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, sc_hinfo_tree, &user_data); + if (user_data == NULL) + return -1; + else + return *((int *)user_data); +} + +/** + * \brief Retrieves the host os flavour, given an ipv6 address in the raw + * address format. + * + * \param Pointer to a raw ipv6 address. + * + * \retval The OS flavour on success; -1 on failure, or on not finding the key + */ +int SCHInfoGetIPv6HostOSFlavour(uint8_t *ipv6_addr) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, sc_hinfo_tree, &user_data); + if (user_data == NULL) + return -1; + else + return *((int *)user_data); +} + +void SCHInfoCleanResources(void) +{ + if (sc_hinfo_tree != NULL) { + SCRadixReleaseRadixTree(sc_hinfo_tree); + sc_hinfo_tree = NULL; + } + + return; +} + +/** + * \brief Load the host os policy information from the configuration. + * + * \initonly (A mem alloc error should cause an exit failure) + */ +void SCHInfoLoadFromConfig(void) +{ + ConfNode *root = ConfGetNode("host-os-policy"); + if (root == NULL) + return; + + ConfNode *policy; + TAILQ_FOREACH (policy, &root->head, next) { + ConfNode *host; + TAILQ_FOREACH (host, &policy->head, next) { + int is_ipv4 = 1; + if (host->val != NULL && strchr(host->val, ':') != NULL) + is_ipv4 = 0; + if (SCHInfoAddHostOSInfo(policy->name, host->val, is_ipv4) == -1) { + SCLogError("Failed to add host \"%s\" with policy \"%s\" to host " + "info database", + host->val, policy->name); + exit(EXIT_FAILURE); + } + } + } +} + +/*------------------------------------Unit_Tests------------------------------*/ + +#ifdef UNITTESTS +static SCRadixTree *sc_hinfo_tree_backup = NULL; + +static void SCHInfoCreateContextBackup(void) +{ + sc_hinfo_tree_backup = sc_hinfo_tree; + sc_hinfo_tree = NULL; + + return; +} + +static void SCHInfoRestoreContextBackup(void) +{ + sc_hinfo_tree = sc_hinfo_tree_backup; + sc_hinfo_tree_backup = NULL; + + return; +} + +/** + * \test Check if we the IPs with the right OS flavours are added to the host OS + * radix tree, and the IPS with invalid flavours returns an error(-1) + */ +static int SCHInfoTestInvalidOSFlavour01(void) +{ + SCHInfoCreateContextBackup(); + + int result = 0; + + if (SCHInfoAddHostOSInfo("bamboo", "192.168.1.1", SC_HINFO_IS_IPV4) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("windows", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("hpux10", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("hpux11", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("irix", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("bsd", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("bsd", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("old_linux", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("old_linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("macos", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("vista", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("windows2k3", "192.168.1.1", SC_HINFO_IS_IPV4) != + SCMapEnumNameToValue("windows2k3", sc_hinfo_os_policy_map)) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that invalid ipv4 addresses and ipv4 netblocks are rejected by + * the host os info API + */ +static int SCHInfoTestInvalidIPV4Address02(void) +{ + SCHInfoCreateContextBackup(); + + int result = 0; + + if (SCHInfoAddHostOSInfo("linux", "192.168.1.566", SC_HINFO_IS_IPV4) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "192.", SC_HINFO_IS_IPV4) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "192.168", SC_HINFO_IS_IPV4) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV4) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "192.168.1.1/33", SC_HINFO_IS_IPV4) != -1) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that invalid ipv4 addresses and ipv4 netblocks are rejected by + * the host os info API + */ +static int SCHInfoTestInvalidIPV6Address03(void) +{ + SCHInfoCreateContextBackup(); + + int result = 0; + + if (SCHInfoAddHostOSInfo("linux", "2362:7322", SC_HINFO_IS_IPV6) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "19YW:", SC_HINFO_IS_IPV6) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "1235", SC_HINFO_IS_IPV6) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "1922:236115:", SC_HINFO_IS_IPV6) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "", SC_HINFO_IS_IPV6) != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "linux", "1921.6311:6241:6422:7352:ABBB:DDDD:EEEE/129", SC_HINFO_IS_IPV6) != -1) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that valid ipv4 addresses are inserted into the host os radix + * tree, and the host os api retrieves the right value for the host os + * flavour, on supplying as arg an ipv4 addresses that has been added to + * the host os radix tree. + */ +static int SCHInfoTestValidIPV4Address04(void) +{ + SCHInfoCreateContextBackup(); + + int result = 0; + + if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "11.1.120.210", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "19.18.110.210", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("windows", "19.18.120.110", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("hpux11", "191.168.11.128", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("vista", "191.168.11.192", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + + if (SCHInfoGetHostOSFlavour("192.168.1.1") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.1.2") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.1.100") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.192.2.4") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.2.4") != + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.192.1.5") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.10.20") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.163.151.62") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("11.1.120.210") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("19.18.110.210") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("19.18.120.110") != + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("191.168.11.128") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("191.168.11.192") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("191.168.11.224") != -1) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that valid ipv4 addresses/netblocks are inserted into the host os + * radix tree, and the host os api retrieves the right value for the host + * os flavour, on supplying as arg an ipv4 addresses that has been added + * to the host os radix tree. + */ +static int SCHInfoTestValidIPV4Address05(void) +{ + SCHInfoCreateContextBackup(); + + struct in_addr in; + int result = 0; + + if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "192.168.1.100", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("hpux10", "192.168.2.4", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "192.192.1.5", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("vista", "192.168.10.20", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "111.163.151.62", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("hpux11", "111.162.208.124/20", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("windows", "111.162.240.1", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "111.162.214.100", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("vista", "111.162.208.100", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("linux", "111.162.194.112", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + + if (SCHInfoGetHostOSFlavour("192.168.1.1") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.1.2") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.1.100") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.192.2.4") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.2.4") != + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.192.1.5") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.10.20") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.163.151.62") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.208.0") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.210.1") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.214.1") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.0.0") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.240.112") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.240.1") != + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.214.100") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (inet_pton(AF_INET, "111.162.208.100", &in) < 0) { + goto end; + } + if (SCHInfoGetIPv4HostOSFlavour((uint8_t *)&in) != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.194.112") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.208.200") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (inet_pton(AF_INET, "111.162.208.200", &in) < 0) { + goto end; + } + if (SCHInfoGetIPv4HostOSFlavour((uint8_t *)&in) != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("111.162.200.201") != -1) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that valid ipv6 addresses are inserted into the host os radix + * tree, and the host os api retrieves the right value for the host os + * flavour, on supplying as arg an ipv6 address that has been added to + * the host os radix tree. + */ +static int SCHInfoTestValidIPV6Address06(void) +{ + SCHInfoCreateContextBackup(); + + int result = 0; + + if (SCHInfoAddHostOSInfo( + "linux", "2351:2512:6211:6246:235A:6242:2352:62AD", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "windows", "6961:6121:2132:6241:423A:2135:2461:621D", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "DD13:613D:F312:62DD:6213:421A:6212:2652", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "hpux10", "9891:2131:2151:6426:1342:674D:622F:2342", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "linux", "3525:2351:4223:6211:2311:2667:6242:2154", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "vista", "1511:6211:6726:7777:1212:2333:6222:7722", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "2666:6222:7222:2335:6223:7722:3425:2362", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "8762:2352:6241:7245:EE23:21AD:2312:622C", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "linux", "6422:EE1A:2621:34AD:2462:432D:642E:E13A", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "windows", "3521:7622:6241:6242:7277:1234:2352:6234", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "hpux11", "2141:6232:6252:2223:7734:2345:6245:6222", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "vista", "5222:6432:6432:2322:6662:3423:4322:3245", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + + if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("6422:EE1A:2621:34AD:2462:432D:642E:E13A") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("3521:7622:6241:6242:7277:1234:2352:6234") != + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("2141:6232:6252:2223:7734:2345:6245:6222") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:3245") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != -1) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that valid ipv6 addresses/netblocks are inserted into the host os + * radix tree, and the host os api retrieves the right value for the host + * os flavour, on supplying as arg an ipv6 address that has been added to + * the host os radix tree. + */ +static int SCHInfoTestValidIPV6Address07(void) +{ + SCHInfoCreateContextBackup(); + + int result = 0; + + if (SCHInfoAddHostOSInfo( + "linux", "2351:2512:6211:6246:235A:6242:2352:62AD", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "windows", "6961:6121:2132:6241:423A:2135:2461:621D", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "DD13:613D:F312:62DD:6213:421A:6212:2652", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "hpux10", "9891:2131:2151:6426:1342:674D:622F:2342", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "linux", "3525:2351:4223:6211:2311:2667:6242:2154", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "vista", "1511:6211:6726:7777:1212:2333:6222:7722", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "2666:6222:7222:2335:6223:7722:3425:2362", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "8762:2352:6241:7245:EE23:21AD:2312:622C/68", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "linux", "8762:2352:6241:7245:EE23:21AD:2412:622C", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "windows", "8762:2352:6241:7245:EE23:21AD:FFFF:622C", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "hpux11", "8762:2352:6241:7245:EE23:21AD:2312:62FF", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "vista", "8762:2352:6241:7245:EE23:21AD:2121:1212", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + + if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFFE") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") != + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:E000:0000:0000:0000") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that valid ipv6 addresses/netblocks are inserted into the host os + * radix tree, and the host os api retrieves the right value for the host + * os flavour, on supplying as arg an ipv6 address that has been added to + * the host os radix tree. + */ +static int SCHInfoTestValidIPV6Address08(void) +{ + SCHInfoCreateContextBackup(); + + struct in6_addr in6; + int result = 0; + + if (SCHInfoAddHostOSInfo( + "linux", "2351:2512:6211:6246:235A:6242:2352:62AD", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "windows", "6961:6121:2132:6241:423A:2135:2461:621D", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "DD13:613D:F312:62DD:6213:421A:6212:2652", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "hpux10", "9891:2131:2151:6426:1342:674D:622F:2342", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "linux", "3525:2351:4223:6211:2311:2667:6242:2154", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "vista", "1511:6211:6726:7777:1212:2333:6222:7722", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "2666:6222:7222:2335:6223:7722:3425:2362", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "solaris", "8762:2352:6241:7245:EE23:21AD:2312:622C/68", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "linux", "8762:2352:6241:7245:EE23:21AD:2412:622C", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "windows", "8762:2352:6241:7245:EE23:21AD:FFFF:622C", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "hpux11", "8762:2352:6241:7245:EE23:21AD:2312:62FF", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo( + "vista", "8762:2352:6241:7245:EE23:21AD:2121:1212", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("vista", "8.8.8.0/24", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("irix", "default", SC_HINFO_IS_IPV6) == -1) { + goto end; + } + + if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:62AD") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("2351:2512:6211:6246:235A:6242:2352:6FFF") != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2652") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("DD13:613D:F312:62DD:6213:421A:6212:2222") != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("9891:2131:2151:6426:1342:674D:622F:2342") != + SCMapEnumNameToValue("hpux10", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("3525:2351:4223:6211:2311:2667:6242:2154") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("1511:6211:6726:7777:1212:2333:6222:7722") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("2666:6222:7222:2335:6223:7722:3425:2362") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2412:622C") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:FFFF:622C") != + SCMapEnumNameToValue("windows", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:62FF") != + SCMapEnumNameToValue("hpux11", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1212") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("5222:6432:6432:2322:6662:3423:4322:DDDD") != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2121:1DDD") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:FFFF:2121:1DDD") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE23:21AD:2312:622C") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8762:2352:6241:7245:EE00:0000:0000:0000") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (inet_pton(AF_INET6, "8762:2352:6241:7245:E000:0000:0000:0000", &in6) < 0) { + goto end; + } + if (SCHInfoGetIPv6HostOSFlavour((uint8_t *)&in6) != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + if (inet_pton(AF_INET6, "AD23:2DDA:6D1D:A223:E235:0232:1241:1666", &in6) < 0) { + goto end; + } + if (SCHInfoGetIPv6HostOSFlavour((uint8_t *)&in6) != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoGetHostOSFlavour("8.8.8.8") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check that valid ipv4 addresses are inserted into the host os radix + * tree, and the host os api retrieves the right value for the host os + * flavour, on supplying as arg an ipv4 addresses that has been added to + * the host os radix tree. + */ +static int SCHInfoTestValidIPV4Address09(void) +{ + SCHInfoCreateContextBackup(); + + int result = 0; + + if (SCHInfoAddHostOSInfo("linux", "192.168.1.0", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.1.0") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.1.0") != + SCMapEnumNameToValue("linux", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("vista", "192.168.50.128/25", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.50.128") != + SCMapEnumNameToValue("vista", sc_hinfo_os_policy_map)) { + goto end; + } + if (SCHInfoAddHostOSInfo("irix", "192.168.50.128", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoGetHostOSFlavour("192.168.50.128") != + SCMapEnumNameToValue("irix", sc_hinfo_os_policy_map)) { + goto end; + } + + if (SCHInfoGetHostOSFlavour("192.168.1.100") != + SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { + goto end; + } + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { + goto end; + } + + SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); + + if (SCHInfoGetHostOSFlavour("192.168.1.100") != + SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { + goto end; + } + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { + goto end; + } + SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); + + if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("solaris", "192.168.1.0/16", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + if (SCHInfoAddHostOSInfo("macos", "192.168.1.0/20", SC_HINFO_IS_IPV4) == -1) { + goto end; + } + + /* 192.168.1.100 should match "macos" as its more specific than + * "solaris". */ + if (SCHInfoGetHostOSFlavour("192.168.1.100") != + SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { + goto end; + } + + /* Remove the 192.168.1.0/20 -> macos entry. */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { + goto end; + } + SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); + + if (SCHInfoGetHostOSFlavour("192.168.1.100") != + SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { + goto end; + } + + /* Remove the 192.168.1.0/16 -> solaris entry. */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { + goto end; + } + SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 16); + + if (SCHInfoGetHostOSFlavour("192.168.1.100") != -1) { + goto end; + } + + result = 1; + +end: + SCHInfoCleanResources(); + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check the loading of host info from a configuration file. + */ +static int SCHInfoTestLoadFromConfig01(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +host-os-policy:\n\ + bsd: [0.0.0.0/0]\n\ + windows: [10.0.0.0/8, 192.168.1.0/24]\n\ + linux: [10.0.0.5/32]\n\ +\n"; + + int result = 0; + + SCHInfoCreateContextBackup(); + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + SCHInfoLoadFromConfig(); + if (SCHInfoGetHostOSFlavour("10.0.0.4") != OS_POLICY_WINDOWS) + goto end; + if (SCHInfoGetHostOSFlavour("10.0.0.5") != OS_POLICY_LINUX) + goto end; + if (SCHInfoGetHostOSFlavour("192.168.1.1") != OS_POLICY_WINDOWS) + goto end; + if (SCHInfoGetHostOSFlavour("172.168.1.1") != OS_POLICY_BSD) + goto end; + + result = 1; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check the loading of host info from a configuration file. + */ +static int SCHInfoTestLoadFromConfig02(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +host-os-policy:\n\ + one-two: [0.0.0.0/0]\n\ + one-two-three:\n\ + four_five:\n\ + six-seven_eight: [10.0.0.0/8, 192.168.1.0/24]\n\ + nine_ten_eleven: [10.0.0.5/32]\n\ +\n"; + + int result = 0; + + SCHInfoCreateContextBackup(); + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ConfNode *root = ConfGetNode("host-os-policy"); + if (root == NULL) + goto end; + + int count = 0; + + ConfNode *policy; + TAILQ_FOREACH (policy, &root->head, next) { + switch (count) { + case 0: + if (strcmp("one-two", policy->name) != 0) + goto end; + break; + case 1: + if (strcmp("one-two-three", policy->name) != 0) + goto end; + break; + case 2: + if (strcmp("four-five", policy->name) != 0) + goto end; + break; + case 3: + if (strcmp("six-seven-eight", policy->name) != 0) + goto end; + break; + case 4: + if (strcmp("nine-ten-eleven", policy->name) != 0) + goto end; + break; + } + count++; + } + + result = 1; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + SCHInfoRestoreContextBackup(); + + return result; +} + +/** + * \test Check the loading of host info from a configuration file. + */ +static int SCHInfoTestLoadFromConfig03(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +host-os-policy:\n\ + bsd-right: [0.0.0.1]\n\ + old-linux: [0.0.0.2]\n\ + old-solaris: [0.0.0.3]\n\ + windows: [0.0.0.4]\n\ + vista: [0.0.0.5]\n\ +\n"; + + int result = 0; + + SCHInfoCreateContextBackup(); + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ConfNode *root = ConfGetNode("host-os-policy"); + if (root == NULL) + goto end; + + ConfNode *policy; + TAILQ_FOREACH (policy, &root->head, next) { + if (SCMapEnumNameToValue(policy->name, sc_hinfo_os_policy_map) == -1) { + printf("Invalid enum map inside\n"); + goto end; + } + } + + result = 1; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + SCHInfoRestoreContextBackup(); + return result; +} + +/** + * \test Check the loading of host info from a configuration file. + */ +static int SCHInfoTestLoadFromConfig04(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +host-os-policy:\n\ + bsd_right: [0.0.0.1]\n\ + old_linux: [0.0.0.2]\n\ + old_solaris: [0.0.0.3]\n\ + windows: [0.0.0.4]\n\ + vista: [0.0.0.5]\n\ +\n"; + + int result = 0; + + SCHInfoCreateContextBackup(); + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + + ConfNode *root = ConfGetNode("host-os-policy"); + if (root == NULL) + goto end; + + ConfNode *policy; + TAILQ_FOREACH (policy, &root->head, next) { + if (SCMapEnumNameToValue(policy->name, sc_hinfo_os_policy_map) == -1) { + printf("Invalid enum map inside\n"); + goto end; + } + } + + result = 1; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + SCHInfoRestoreContextBackup(); + return result; +} + +/** + * \test Check the loading of host info from a configuration file. + */ +static int SCHInfoTestLoadFromConfig05(void) +{ + char config[] = "\ +%YAML 1.1\n\ +---\n\ +host-os-policy:\n\ + bsd_right: [0.0.0.1]\n\ + old_linux: [0.0.0.2]\n\ + old-solaris: [0.0.0.3]\n\ + windows: [0.0.0.4]\n\ + linux: [0.0.0.5]\n\ +\n"; + + SCHInfoCreateContextBackup(); + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(config, strlen(config)); + SCHInfoLoadFromConfig(); + + FAIL_IF(SCHInfoGetHostOSFlavour("0.0.0.1") != OS_POLICY_BSD_RIGHT); + FAIL_IF(SCHInfoGetHostOSFlavour("0.0.0.2") != OS_POLICY_OLD_LINUX); + FAIL_IF(SCHInfoGetHostOSFlavour("0.0.0.3") != OS_POLICY_OLD_SOLARIS); + FAIL_IF(SCHInfoGetHostOSFlavour("0.0.0.4") != OS_POLICY_WINDOWS); + FAIL_IF(SCHInfoGetHostOSFlavour("0.0.0.5") != OS_POLICY_LINUX); + FAIL_IF(SCHInfoGetHostOSFlavour("0.0.0.0") != -1); + FAIL_IF(SCHInfoGetHostOSFlavour("0.0.0.6") != -1); + + ConfDeInit(); + ConfRestoreContextBackup(); + SCHInfoRestoreContextBackup(); + PASS; +} + +#endif /* UNITTESTS */ + +void SCHInfoRegisterTests(void) +{ + +#ifdef UNITTESTS + + UtRegisterTest("SCHInfoTesInvalidOSFlavour01", SCHInfoTestInvalidOSFlavour01); + UtRegisterTest("SCHInfoTestInvalidIPV4Address02", SCHInfoTestInvalidIPV4Address02); + UtRegisterTest("SCHInfoTestInvalidIPV6Address03", SCHInfoTestInvalidIPV6Address03); + UtRegisterTest("SCHInfoTestValidIPV4Address04", SCHInfoTestValidIPV4Address04); + UtRegisterTest("SCHInfoTestValidIPV4Address05", SCHInfoTestValidIPV4Address05); + UtRegisterTest("SCHInfoTestValidIPV6Address06", SCHInfoTestValidIPV6Address06); + UtRegisterTest("SCHInfoTestValidIPV6Address07", SCHInfoTestValidIPV6Address07); + UtRegisterTest("SCHInfoTestValidIPV6Address08", SCHInfoTestValidIPV6Address08); + UtRegisterTest("SCHInfoTestValidIPV4Address09", SCHInfoTestValidIPV4Address09); + + UtRegisterTest("SCHInfoTestLoadFromConfig01", SCHInfoTestLoadFromConfig01); + UtRegisterTest("SCHInfoTestLoadFromConfig02", SCHInfoTestLoadFromConfig02); + UtRegisterTest("SCHInfoTestLoadFromConfig03", SCHInfoTestLoadFromConfig03); + UtRegisterTest("SCHInfoTestLoadFromConfig04", SCHInfoTestLoadFromConfig04); + UtRegisterTest("SCHInfoTestLoadFromConfig05", SCHInfoTestLoadFromConfig05); +#endif /* UNITTESTS */ +} diff --git a/src/util-host-os-info.h b/src/util/host-os-info.h similarity index 100% rename from src/util-host-os-info.h rename to src/util/host-os-info.h diff --git a/src/util/hyperscan.c b/src/util/hyperscan.c new file mode 100644 index 000000000000..d08ef8fb692c --- /dev/null +++ b/src/util/hyperscan.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Justin Viiret + * + * Support functions for Hyperscan library integration. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#ifdef BUILD_HYPERSCAN +#include "util/hyperscan.h" + +/** + * \internal + * \brief Convert a pattern into a regex string accepted by the Hyperscan + * compiler. + * + * For simplicity, we just take each byte of the original pattern and render it + * with a hex escape (i.e. ' ' -> "\x20")/ + */ +char *HSRenderPattern(const uint8_t *pat, uint16_t pat_len) +{ + if (pat == NULL) { + return NULL; + } + const size_t hex_len = (pat_len * 4) + 1; + char *str = SCCalloc(1, hex_len); + if (str == NULL) { + return NULL; + } + char *sp = str; + for (uint16_t i = 0; i < pat_len; i++) { + snprintf(sp, 5, "\\x%02x", pat[i]); + sp += 4; + } + *sp = '\0'; + return str; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-hyperscan.h b/src/util/hyperscan.h similarity index 100% rename from src/util-hyperscan.h rename to src/util/hyperscan.h diff --git a/src/util/ioctl.c b/src/util/ioctl.c new file mode 100644 index 000000000000..88dc30c3e9d0 --- /dev/null +++ b/src/util/ioctl.c @@ -0,0 +1,736 @@ +/* Copyright (C) 2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "util/ioctl.h" +#include "../conf.h" +#include "decode.h" +#include "decode-sll.h" + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_LINUX_ETHTOOL_H +#include +#include +#ifdef HAVE_LINUX_SOCKIOS_H +#include +#else +#error "ethtool.h present but sockios.h is missing" +#endif /* HAVE_LINUX_SOCKIOS_H */ +#endif /* HAVE_LINUX_ETHTOOL_H */ + +#ifdef HAVE_NET_IF_H +#include +#endif + +#ifdef OS_WIN32 +#include "windows/win32-syscall.h" +#endif + +/** + * \brief output a majorant of hardware header length + * + * \param Name of a network interface + */ +static int GetIfaceMaxHWHeaderLength(const char *dev) +{ + if ((!strcmp("eth", dev)) || (!strcmp("br", dev)) || (!strcmp("bond", dev)) || + (!strcmp("wlan", dev)) || (!strcmp("tun", dev)) || (!strcmp("tap", dev)) || + (!strcmp("lo", dev))) { + /* Add possible VLAN tag or Qing headers */ + return 8 + ETHERNET_HEADER_LEN; + } + + if (!strcmp("ppp", dev)) + return SLL_HEADER_LEN; + /* SLL_HEADER_LEN is the biggest one and + add possible VLAN tag and Qing headers */ + return 8 + SLL_HEADER_LEN; +} + +/** + * \brief output the link MTU + * + * \param Name of link + * \retval -1 in case of error, 0 if MTU can not be found + */ +int GetIfaceMTU(const char *dev) +{ +#if defined SIOCGIFMTU + struct ifreq ifr; + int fd; + + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + + if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { + SCLogWarning("Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev, + strerror(errno), errno); + close(fd); + return -1; + } + close(fd); + SCLogInfo("%s: MTU %d", dev, ifr.ifr_mtu); + return ifr.ifr_mtu; +#elif defined OS_WIN32 + return GetIfaceMTUWin32(dev); +#else + /* ioctl is not defined, let's pretend returning 0 is ok */ + return 0; +#endif +} + +/** + * \brief output max packet size for a link + * + * This does a best effort to find the maximum packet size + * for the link. In case of uncertainty, it will output a + * majorant to be sure avoid the cost of dynamic allocation. + * + * \param LiveDevice object + * \retval 0 in case of error + */ +int GetIfaceMaxPacketSize(LiveDevice *ld) +{ + if (ld == NULL) + return 0; + + const char *dev = ld->dev; + if ((dev == NULL) || strlen(dev) == 0) + return 0; + + int mtu = GetIfaceMTU(dev); + switch (mtu) { + case 0: + case -1: + return 0; + } + ld->mtu = mtu; + int ll_header = GetIfaceMaxHWHeaderLength(dev); + return ll_header + mtu; +} + +#ifdef SIOCGIFFLAGS +/** + * \brief Get interface flags. + * \param ifname Interface name. + * \return Interface flags or -1 on error + */ +int GetIfaceFlags(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { + SCLogError("%s: failed to get device flags: %s", ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); +#ifdef OS_FREEBSD + int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + return flags; +#else + return ifr.ifr_flags; +#endif +} +#endif + +#ifdef SIOCSIFFLAGS +/** + * \brief Set interface flags. + * \param ifname Interface name. + * \param flags Flags to set. + * \return Zero on success. + */ +int SetIfaceFlags(const char *ifname, int flags) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +#ifdef OS_FREEBSD + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; +#else + ifr.ifr_flags = (uint16_t)flags; +#endif + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { + SCLogError("%s: unable to set device flags: %s", ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} +#endif /* SIOCGIFFLAGS */ + +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { + SCLogError("%s: unable to get device caps: %s", ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return ifr.ifr_curcap; +} +#endif +#ifdef SIOCSIFCAP +int SetIfaceCaps(const char *ifname, int caps) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_reqcap = caps; + + if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) { + SCLogError("%s: unable to set caps: %s", ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} +#endif + +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL +static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) +{ + struct ifreq ifr; + int fd; + struct ethtool_value ethv; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + + ethv.cmd = cmd; + ifr.ifr_data = (void *)ðv; + if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { + SCLogWarning("%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno)); + close(fd); + return -1; + } + + *value = ethv.data; + close(fd); + return 0; +} + +static int SetEthtoolValue(const char *dev, int cmd, uint32_t value) +{ + struct ifreq ifr; + int fd; + struct ethtool_value ethv; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + + ethv.cmd = cmd; + ethv.data = value; + ifr.ifr_data = (void *)ðv; + if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { + SCLogWarning("%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} + +static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) +{ + int ret = 0; + uint32_t value = 0; + + if (csum) { + const char *rx = "unset", *tx = "unset"; + int csum_ret = 0; +#ifdef ETHTOOL_GRXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { + rx = "SET"; + csum_ret = 1; + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { + tx = "SET"; + csum_ret = 1; + } +#endif + if (csum_ret == 0) + SCLogPerf("%s: NIC offloading: RX %s TX %s", dev, rx, tx); + else { + SCLogWarning("%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev, + rx, tx, dev); + ret = 1; + } + } + + if (other) { + const char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; + const char *sg = "unset"; + int other_ret = 0; +#ifdef ETHTOOL_GGRO + if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { + gro = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GTSO + if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { + tso = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GGSO + if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { + gso = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GSG + if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { + sg = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GFLAGS + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + if (value & ETH_FLAG_LRO) { + lro = "SET"; + other_ret = 1; + } + } +#endif + if (other_ret == 0) { + SCLogPerf("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg, + gro, lro, tso, gso); + } else { + SCLogWarning("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: " + "ethtool -K %s sg off gro off lro off tso off gso off", + dev, sg, gro, lro, tso, gso, dev); + ret = 1; + } + } + return ret; +} + +static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) +{ + int ret = 0; + uint32_t value = 0; + + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + + if (csum) { +#ifdef ETHTOOL_GRXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling rxcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling txcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM; + } +#endif + } + if (other) { +#ifdef ETHTOOL_GGRO + if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling gro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGRO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GRO; + } +#endif +#ifdef ETHTOOL_GTSO + if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling tso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TSO; + } +#endif +#ifdef ETHTOOL_GGSO + if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling gso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GSO; + } +#endif +#ifdef ETHTOOL_GSG + if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling sg offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SSG, 0); + ldev->offload_orig |= OFFLOAD_FLAG_SG; + } +#endif +#ifdef ETHTOOL_GFLAGS + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + if (value & ETH_FLAG_LRO) { + SCLogPerf("%s: disabling lro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); + ldev->offload_orig |= OFFLOAD_FLAG_LRO; + } + } +#endif + } + return ret; +} + +static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) +{ + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + +#ifdef ETHTOOL_GRXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { + SCLogPerf("%s: restoring rxcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) { + SCLogPerf("%s: restoring txcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GGRO + if (ldev->offload_orig & OFFLOAD_FLAG_GRO) { + SCLogPerf("%s: restoring gro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGRO, 1); + } +#endif +#ifdef ETHTOOL_GTSO + if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { + SCLogPerf("%s: restoring tso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STSO, 1); + } +#endif +#ifdef ETHTOOL_GGSO + if (ldev->offload_orig & OFFLOAD_FLAG_GSO) { + SCLogPerf("%s: restoring gso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGSO, 1); + } +#endif +#ifdef ETHTOOL_GSG + if (ldev->offload_orig & OFFLOAD_FLAG_SG) { + SCLogPerf("%s: restoring sg offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SSG, 1); + } +#endif +#ifdef ETHTOOL_GFLAGS + if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { + uint32_t value = 0; + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + SCLogPerf("%s: restoring lro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO); + } + } +#endif + return 0; +} + +#endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ + +#ifdef SIOCGIFCAP +static int GetIfaceOffloadingBSD(const char *ifname) +{ + int ret = 0; + int if_caps = GetIfaceCaps(ifname); + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogWarning("%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum", + ifname, ifname); + ret = 1; + } +#ifdef IFCAP_TOE + if (if_caps & (IFCAP_TSO | IFCAP_TOE | IFCAP_LRO)) { + SCLogWarning("%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s " + "-tso -toe -lro", + ifname, ifname); + ret = 1; + } +#else + if (if_caps & (IFCAP_TSO | IFCAP_LRO)) { + SCLogWarning( + "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro", + ifname, ifname); + ret = 1; + } +#endif + return ret; +} +#endif + +#ifdef SIOCSIFCAP +static int DisableIfaceOffloadingBSD(LiveDevice *ldev) +{ + int ret = 0; + + if (ldev == NULL) + return -1; + + const char *ifname = ldev->dev; + int if_caps = GetIfaceCaps(ifname); + int set_caps = if_caps; + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogPerf("%s: disabling rxcsum offloading", ifname); + set_caps &= ~IFCAP_RXCSUM; + } + if (if_caps & IFCAP_TXCSUM) { + SCLogPerf("%s: disabling txcsum offloading", ifname); + set_caps &= ~IFCAP_TXCSUM; + } +#ifdef IFCAP_RXCSUM_IPV6 + if (if_caps & IFCAP_RXCSUM_IPV6) { + SCLogPerf("%s: disabling rxcsum6 offloading", ifname); + set_caps &= ~IFCAP_RXCSUM_IPV6; + } +#endif +#ifdef IFCAP_TXCSUM_IPV6 + if (if_caps & IFCAP_TXCSUM_IPV6) { + SCLogPerf("%s: disabling txcsum6 offloading", ifname); + set_caps &= ~IFCAP_TXCSUM_IPV6; + } +#endif +#ifdef IFCAP_TOE + if (if_caps & (IFCAP_TSO | IFCAP_TOE | IFCAP_LRO)) { + SCLogPerf("%s: disabling tso|toe|lro offloading", ifname); + set_caps &= ~(IFCAP_TSO | IFCAP_LRO); + } +#else + if (if_caps & (IFCAP_TSO | IFCAP_LRO)) { + SCLogPerf("%s: disabling tso|lro offloading", ifname); + set_caps &= ~(IFCAP_TSO | IFCAP_LRO); + } +#endif + if (set_caps != if_caps) { + if (if_caps & IFCAP_RXCSUM) + ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; + if (if_caps & IFCAP_TSO) + ldev->offload_orig |= OFFLOAD_FLAG_TSO; +#ifdef IFCAP_TOE + if (if_caps & IFCAP_TOE) + ldev->offload_orig |= OFFLOAD_FLAG_TOE; +#endif + if (if_caps & IFCAP_LRO) + ldev->offload_orig |= OFFLOAD_FLAG_LRO; + + SetIfaceCaps(ifname, set_caps); + } + return ret; +} + +static int RestoreIfaceOffloadingBSD(LiveDevice *ldev) +{ + int ret = 0; + + if (ldev == NULL) + return -1; + + const char *ifname = ldev->dev; + int if_caps = GetIfaceCaps(ifname); + int set_caps = if_caps; + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { + SCLogPerf("%s: restoring rxcsum offloading", ifname); + set_caps |= IFCAP_RXCSUM; + } + if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { + SCLogPerf("%s: restoring tso offloading", ifname); + set_caps |= IFCAP_TSO; + } +#ifdef IFCAP_TOE + if (ldev->offload_orig & OFFLOAD_FLAG_TOE) { + SCLogPerf("%s: restoring toe offloading", ifname); + set_caps |= IFCAP_TOE; + } +#endif + if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { + SCLogPerf("%s: restoring lro offloading", ifname); + set_caps |= IFCAP_LRO; + } + + if (set_caps != if_caps) { + SetIfaceCaps(ifname, set_caps); + } + return ret; +} +#endif + +/** + * \brief output offloading status of the link + * + * Test interface for offloading features. If one of them is + * activated then suricata mays received packets merge at reception. + * The result is oversized packets and this may cause some serious + * problem in some capture mode where the size of the packet is + * limited (AF_PACKET in V2 more for example). + * + * \param Name of link + * \param csum check if checksums are offloaded + * \param other check if other things are offloaded: TSO, GRO, etc. + * \retval -1 in case of error, 0 if none, 1 if some + */ +int GetIfaceOffloading(const char *dev, int csum, int other) +{ +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + return GetIfaceOffloadingLinux(dev, csum, other); +#elif defined SIOCGIFCAP + return GetIfaceOffloadingBSD(dev); +#elif defined OS_WIN32 + return GetIfaceOffloadingWin32(dev, csum, other); +#else + return 0; +#endif +} + +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other) +{ + /* already set */ + if (dev->offload_orig != 0) + return 0; +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + return DisableIfaceOffloadingLinux(dev, csum, other); +#elif defined SIOCSIFCAP + return DisableIfaceOffloadingBSD(dev); +#elif defined OS_WIN32 + return DisableIfaceOffloadingWin32(dev, csum, other); +#else + return 0; +#endif +} + +void RestoreIfaceOffloading(LiveDevice *dev) +{ + if (dev->offload_orig != 0) { +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + RestoreIfaceOffloadingLinux(dev); +#elif defined SIOCSIFCAP + RestoreIfaceOffloadingBSD(dev); +#elif defined OS_WIN32 + RestoreIfaceOffloadingWin32(dev); +#endif + } +} + +int GetIfaceRSSQueuesNum(const char *dev) +{ +#if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS + struct ifreq ifr; + struct ethtool_rxnfc nfccmd; + int fd; + + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + SCLogWarning("%s: failed to open socket for ioctl: %s", dev, strerror(errno)); + return -1; + } + + nfccmd.cmd = ETHTOOL_GRXRINGS; + ifr.ifr_data = (void *)&nfccmd; + + if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { + if (errno != ENOTSUP) { + SCLogWarning("%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno)); + } + close(fd); + return 0; + } + close(fd); + SCLogInfo("%s: RX RSS queues: %d", dev, (int)nfccmd.data); + return (int)nfccmd.data; +#else + return 0; +#endif +} diff --git a/src/util/ioctl.h b/src/util/ioctl.h new file mode 100644 index 000000000000..82583e1ada83 --- /dev/null +++ b/src/util/ioctl.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#include "suricata-common.h" +#include "util/device.h" + +int GetIfaceMTU(const char *pcap_dev); +int GetIfaceMaxPacketSize(LiveDevice *ld); +int GetIfaceOffloading(const char *dev, int csum, int other); +int GetIfaceRSSQueuesNum(const char *pcap_dev); +#ifdef SIOCGIFFLAGS +int GetIfaceFlags(const char *ifname); +#endif +#ifdef SIOCSIFFLAGS +int SetIfaceFlags(const char *ifname, int flags); +#endif +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname); +#endif +#ifdef SIOCSIFCAP +int SetIfaceCaps(const char *ifname, int caps); +#endif +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other); +void RestoreIfaceOffloading(LiveDevice *dev); diff --git a/src/util/ip.c b/src/util/ip.c new file mode 100644 index 000000000000..906acc76bae1 --- /dev/null +++ b/src/util/ip.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * \author Duarte Silva + * + * IP addresses related utility functions + */ + +#include "suricata-common.h" +#include "util/ip.h" +#include "util/byte.h" +#include "util/debug.h" + +/** \brief determine if a string is a valid ipv4 address + * \retval bool is addr valid? + */ +bool IPv4AddressStringIsValid(const char *str) +{ + int alen = 0; + char addr[4][4]; + int dots = 0; + + memset(&addr, 0, sizeof(addr)); + + uint32_t len = strlen(str); + uint32_t i = 0; + for (i = 0; i < len; i++) { + if (!(str[i] == '.' || isdigit(str[i]))) { + return false; + } + if (str[i] == '.') { + if (dots == 3) { + SCLogDebug("too many dots"); + return false; + } + addr[dots][alen] = '\0'; + dots++; + alen = 0; + } else { + if (alen >= 3) { + SCLogDebug("too long"); + return false; + } + addr[dots][alen++] = str[i]; + } + } + if (dots != 3) + return false; + + addr[dots][alen] = '\0'; + for (int x = 0; x < 4; x++) { + uint8_t a; + if (StringParseUint8(&a, 10, 0, (const char *)addr[x]) < 0) { + SCLogDebug("invalid value for address byte: %s", addr[x]); + return false; + } + } + return true; +} + +/** \brief determine if a string is a valid ipv6 address + * \retval bool is addr valid? + */ +bool IPv6AddressStringIsValid(const char *str) +{ + int block_size = 0; + int sep = 0; + bool colon_seen = false; + + uint32_t len = strlen(str); + uint32_t i = 0; + for (i = 0; i < len && str[i] != 0; i++) { + if (!(str[i] == '.' || str[i] == ':' || isxdigit(str[i]))) + return false; + + if (str[i] == ':') { + block_size = 0; + colon_seen = true; + sep++; + } else if (str[i] == '.') { + block_size = false; + sep++; + } else { + if (block_size == 4) + return false; + block_size++; + } + } + + if (!colon_seen) + return false; + if (sep > 7) { + SCLogDebug("too many seps %d", sep); + return false; + } + return true; +} + +/** + * \brief Validates an IPV4 address and returns the network endian arranged + * version of the IPV4 address + * + * \param addr Pointer to a character string containing an IPV4 address. A + * valid IPV4 address is a character string containing a dotted + * format of "ddd.ddd.ddd.ddd" + * + * \retval Pointer to an in_addr instance containing the network endian format + * of the IPV4 address + * \retval NULL if the IPV4 address is invalid + */ +struct in_addr *ValidateIPV4Address(const char *addr_str) +{ + struct in_addr *addr = NULL; + + if (!IPv4AddressStringIsValid(addr_str)) + return NULL; + + if ((addr = SCMalloc(sizeof(struct in_addr))) == NULL) { + FatalError("Fatal error encountered in ValidateIPV4Address. Exiting..."); + } + + if (inet_pton(AF_INET, addr_str, addr) <= 0) { + SCFree(addr); + return NULL; + } + + return addr; +} + +/** + * \brief Validates an IPV6 address and returns the network endian arranged + * version of the IPV6 address + * + * \param addr Pointer to a character string containing an IPV6 address + * + * \retval Pointer to a in6_addr instance containing the network endian format + * of the IPV6 address + * \retval NULL if the IPV6 address is invalid + */ +struct in6_addr *ValidateIPV6Address(const char *addr_str) +{ + struct in6_addr *addr = NULL; + + if (!IPv6AddressStringIsValid(addr_str)) + return NULL; + + if ((addr = SCMalloc(sizeof(struct in6_addr))) == NULL) { + FatalError("Fatal error encountered in ValidateIPV6Address. Exiting..."); + } + + if (inet_pton(AF_INET6, addr_str, addr) <= 0) { + SCFree(addr); + return NULL; + } + + return addr; +} + +/** + * \brief Culls the non-netmask portion of the IP address. For example an IP + * address 192.168.240.1 would be chopped to 192.168.224.0 against a + * netmask value of 19. + * + * \param stream Pointer the IP address that has to be masked + * \param netmask The netmask value (cidr) to which the IP address has to be culled + * \param key_bitlen The bitlen of the stream + */ +void MaskIPNetblock(uint8_t *stream, int netmask, int key_bitlen) +{ + uint32_t mask = 0; + int i = 0; + int bytes = key_bitlen / 8; + + for (i = 0; i < bytes; i++) { + mask = UINT_MAX; + if (((i + 1) * 8) > netmask) { + if (((i + 1) * 8 - netmask) < 8) + mask = UINT_MAX << ((i + 1) * 8 - netmask); + else + mask = 0; + } + stream[i] &= mask; + } + + return; +} diff --git a/src/util-ip.h b/src/util/ip.h similarity index 100% rename from src/util-ip.h rename to src/util/ip.h diff --git a/src/util/ja3.c b/src/util/ja3.c new file mode 100644 index 000000000000..31d9c07f5f7a --- /dev/null +++ b/src/util/ja3.c @@ -0,0 +1,299 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Functions used to generate JA3 fingerprint. + */ + +#include "suricata-common.h" +#include "app-layer/ssl/parser.h" +#include "util/validate.h" +#include "util/ja3.h" + +#include "detect-engine.h" + +/** + * \brief Allocate new buffer. + * + * \return pointer to buffer on success. + * \return NULL on failure. + */ +JA3Buffer *Ja3BufferInit(void) +{ + JA3Buffer *buffer = SCCalloc(1, sizeof(JA3Buffer)); + if (buffer == NULL) { + return NULL; + } + + return buffer; +} + +/** + * \brief Free allocated buffer. + * + * \param buffer The buffer to free. + */ +void Ja3BufferFree(JA3Buffer **buffer) +{ + DEBUG_VALIDATE_BUG_ON(*buffer == NULL); + + if ((*buffer)->data != NULL) { + SCFree((*buffer)->data); + (*buffer)->data = NULL; + } + + SCFree(*buffer); + *buffer = NULL; +} + +/** + * \internal + * \brief Resize buffer if it is full. + * + * \param buffer The buffer. + * \param len The length of the data that should fit into the buffer. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +static int Ja3BufferResizeIfFull(JA3Buffer *buffer, uint32_t len) +{ + DEBUG_VALIDATE_BUG_ON(buffer == NULL); + + while (buffer->used + len + 2 > buffer->size) { + buffer->size *= 2; + char *tmp = SCRealloc(buffer->data, buffer->size); + if (tmp == NULL) { + SCLogError("Error resizing JA3 buffer"); + return -1; + } + buffer->data = tmp; + } + + return 0; +} + +/** + * \brief Append buffer to buffer. + * + * Append the second buffer to the first and then free it. + * + * \param buffer1 The first buffer. + * \param buffer2 The second buffer. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +int Ja3BufferAppendBuffer(JA3Buffer **buffer1, JA3Buffer **buffer2) +{ + if (*buffer1 == NULL || *buffer2 == NULL) { + SCLogError("Buffers should not be NULL"); + return -1; + } + + /* If buffer1 contains no data, then we just copy the second buffer + instead of appending its data. */ + if ((*buffer1)->data == NULL) { + (*buffer1)->data = (*buffer2)->data; + (*buffer1)->used = (*buffer2)->used; + (*buffer1)->size = (*buffer2)->size; + SCFree(*buffer2); + return 0; + } + + int rc = Ja3BufferResizeIfFull(*buffer1, (*buffer2)->used); + if (rc != 0) { + Ja3BufferFree(buffer1); + Ja3BufferFree(buffer2); + return -1; + } + + if ((*buffer2)->used == 0) { + (*buffer1)->used += snprintf( + (*buffer1)->data + (*buffer1)->used, (*buffer1)->size - (*buffer1)->used, ","); + } else { + (*buffer1)->used += snprintf((*buffer1)->data + (*buffer1)->used, + (*buffer1)->size - (*buffer1)->used, ",%s", (*buffer2)->data); + } + + Ja3BufferFree(buffer2); + + return 0; +} + +/** + * \internal + * \brief Return number of digits in number. + * + * \param num The number. + * + * \return digits Number of digits. + */ +static uint32_t NumberOfDigits(uint32_t num) +{ + if (num < 10) { + return 1; + } + + return 1 + NumberOfDigits(num / 10); +} + +/** + * \brief Add value to buffer. + * + * \param buffer The buffer. + * \param value The value. + * + * \retval 0 on success. + * \retval -1 on failure. + */ +int Ja3BufferAddValue(JA3Buffer **buffer, uint32_t value) +{ + if (*buffer == NULL) { + SCLogError("Buffer should not be NULL"); + return -1; + } + + if ((*buffer)->data == NULL) { + (*buffer)->data = SCMalloc(JA3_BUFFER_INITIAL_SIZE); + if ((*buffer)->data == NULL) { + SCLogError("Error allocating memory for JA3 data"); + Ja3BufferFree(buffer); + return -1; + } + (*buffer)->size = JA3_BUFFER_INITIAL_SIZE; + } + + uint32_t value_len = NumberOfDigits(value); + + int rc = Ja3BufferResizeIfFull(*buffer, value_len); + if (rc != 0) { + Ja3BufferFree(buffer); + return -1; + } + + if ((*buffer)->used == 0) { + (*buffer)->used += snprintf((*buffer)->data, (*buffer)->size, "%u", value); + } else { + (*buffer)->used += snprintf( + (*buffer)->data + (*buffer)->used, (*buffer)->size - (*buffer)->used, "-%u", value); + } + + return 0; +} + +/** + * \brief Generate Ja3 hash string. + * + * \param buffer The Ja3 buffer. + * + * \retval pointer to hash string on success. + * \retval NULL on failure. + */ +char *Ja3GenerateHash(JA3Buffer *buffer) +{ + if (buffer == NULL) { + SCLogError("Buffer should not be NULL"); + return NULL; + } + + if (buffer->data == NULL) { + SCLogError("Buffer data should not be NULL"); + return NULL; + } + + char *ja3_hash = SCMalloc(SC_MD5_HEX_LEN + 1); + if (ja3_hash == NULL) { + SCLogError("Error allocating memory for JA3 hash"); + return NULL; + } + + SCMd5HashBufferToHex((unsigned char *)buffer->data, buffer->used, ja3_hash, SC_MD5_HEX_LEN + 1); + return ja3_hash; +} + +/** + * \brief Check if JA3 is disabled. + * + * Issue warning if JA3 is disabled or if we are lacking support for JA3. + * + * \param type Type to add to warning. + * + * \retval 1 if disabled. + * \retval 0 otherwise. + */ +int Ja3IsDisabled(const char *type) +{ + bool is_enabled = SSLJA3IsEnabled(); + if (is_enabled == 0) { + if (strcmp(type, "rule") != 0) { + SCLogWarning("JA3 is disabled, skipping %s", type); + } + return 1; + } + + return 0; +} + +InspectionBuffer *Ja3DetectGetHash(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_quic_tx_get_ja3(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + uint8_t ja3_hash[SC_MD5_HEX_LEN + 1]; + // this adds a final zero + SCMd5HashBufferToHex(b, b_len, (char *)ja3_hash, SC_MD5_HEX_LEN + 1); + + InspectionBufferSetup(det_ctx, list_id, buffer, NULL, 0); + InspectionBufferCopy(buffer, ja3_hash, SC_MD5_HEX_LEN); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +InspectionBuffer *Ja3DetectGetString(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + + if (rs_quic_tx_get_ja3(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} diff --git a/src/util/ja3.h b/src/util/ja3.h new file mode 100644 index 000000000000..3d1fe6dc3788 --- /dev/null +++ b/src/util/ja3.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __UTIL_JA3_H__ +#define __UTIL_JA3_H__ + +#define JA3_BUFFER_INITIAL_SIZE 128 + +#include "../detect.h" + +typedef struct JA3Buffer_ { + char *data; + size_t size; + size_t used; +} JA3Buffer; + +JA3Buffer *Ja3BufferInit(void); +void Ja3BufferFree(JA3Buffer **); +int Ja3BufferAppendBuffer(JA3Buffer **, JA3Buffer **); +int Ja3BufferAddValue(JA3Buffer **, uint32_t); +char *Ja3GenerateHash(JA3Buffer *); +int Ja3IsDisabled(const char *); + +InspectionBuffer *Ja3DetectGetHash(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); + +InspectionBuffer *Ja3DetectGetString(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); + +#endif /* __UTIL_JA3_H__ */ diff --git a/src/util/landlock.c b/src/util/landlock.c new file mode 100644 index 000000000000..42512f1f04b5 --- /dev/null +++ b/src/util/landlock.c @@ -0,0 +1,282 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#include "suricata.h" +#include "feature.h" +#include "util/conf.h" +#include "util/file.h" +#include "util/landlock.h" +#include "util/mem.h" +#include "util/path.h" + +#ifndef HAVE_LINUX_LANDLOCK_H + +void LandlockSandboxing(SCInstance *suri) +{ + return; +} + +#else /* HAVE_LINUX_LANDLOCK_H */ + +#include + +#ifndef landlock_create_ruleset +static inline int landlock_create_ruleset( + const struct landlock_ruleset_attr *const attr, const size_t size, const __u32 flags) +{ + return syscall(__NR_landlock_create_ruleset, attr, size, flags); +} +#endif + +#ifndef landlock_add_rule +static inline int landlock_add_rule(const int ruleset_fd, const enum landlock_rule_type rule_type, + const void *const rule_attr, const __u32 flags) +{ + return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags); +} +#endif + +#ifndef landlock_restrict_self +static inline int landlock_restrict_self(const int ruleset_fd, const __u32 flags) +{ + return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); +} +#endif + +#ifndef LANDLOCK_ACCESS_FS_REFER +#define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) +#endif + +#define _LANDLOCK_ACCESS_FS_WRITE \ + (LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | \ + LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_CHAR | \ + LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | \ + LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | \ + LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM | \ + LANDLOCK_ACCESS_FS_REFER) + +#define _LANDLOCK_ACCESS_FS_READ (LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR) + +#define _LANDLOCK_SURI_ACCESS_FS_WRITE \ + (LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | \ + LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) + +struct landlock_ruleset { + int fd; + struct landlock_ruleset_attr attr; +}; + +static inline struct landlock_ruleset *LandlockCreateRuleset(void) +{ + struct landlock_ruleset *ruleset = SCCalloc(1, sizeof(struct landlock_ruleset)); + if (ruleset == NULL) { + SCLogError("Can't alloc landlock ruleset"); + return NULL; + } + + ruleset->attr.handled_access_fs = + _LANDLOCK_ACCESS_FS_READ | _LANDLOCK_ACCESS_FS_WRITE | LANDLOCK_ACCESS_FS_EXECUTE; + + int abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); + if (abi < 0) { + SCFree(ruleset); + return NULL; + } + if (abi < 2) { + if (RequiresFeature(FEATURE_OUTPUT_FILESTORE)) { + SCLogError("Landlock disabled: need Linux 5.19+ for file store support"); + SCFree(ruleset); + return NULL; + } else { + ruleset->attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; + } + } + + ruleset->fd = landlock_create_ruleset(&ruleset->attr, sizeof(ruleset->attr), 0); + if (ruleset->fd < 0) { + SCFree(ruleset); + SCLogError("Can't create landlock ruleset"); + return NULL; + } + return ruleset; +} + +static inline void LandlockEnforceRuleset(struct landlock_ruleset *ruleset) +{ + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) { + SCLogError("Can't self restrict (prctl phase): %s", strerror(errno)); + return; + } + if (landlock_restrict_self(ruleset->fd, 0)) { + SCLogError("Can't self restrict (landlock phase): %s", strerror(errno)); + } +} + +static int LandlockSandboxingAddRule( + struct landlock_ruleset *ruleset, const char *directory, uint64_t permission) +{ + struct landlock_path_beneath_attr path_beneath = { + .allowed_access = permission & ruleset->attr.handled_access_fs, + }; + + int dir_fd = open(directory, O_PATH | O_CLOEXEC | O_DIRECTORY); + if (dir_fd == -1) { + SCLogError("Can't open %s", directory); + return -1; + } + path_beneath.parent_fd = dir_fd; + + if (landlock_add_rule(ruleset->fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0)) { + SCLogError("Can't add write rule: %s", strerror(errno)); + close(dir_fd); + return -1; + } + + close(dir_fd); + return 0; +} + +static inline void LandlockSandboxingWritePath( + struct landlock_ruleset *ruleset, const char *directory) +{ + if (LandlockSandboxingAddRule(ruleset, directory, _LANDLOCK_SURI_ACCESS_FS_WRITE) == 0) { + SCLogConfig("Added write permission to '%s'", directory); + } +} + +static inline void LandlockSandboxingReadPath( + struct landlock_ruleset *ruleset, const char *directory) +{ + if (LandlockSandboxingAddRule(ruleset, directory, _LANDLOCK_ACCESS_FS_READ) == 0) { + SCLogConfig("Added read permission to '%s'", directory); + } +} + +void LandlockSandboxing(SCInstance *suri) +{ + /* Read configuration variable and exit if no enforcement */ + int conf_status; + if (ConfGetBool("security.landlock.enabled", &conf_status) == 0) { + conf_status = 0; + } + if (!conf_status) { + SCLogConfig("Landlock is not enabled in configuration"); + return; + } + struct landlock_ruleset *ruleset = LandlockCreateRuleset(); + if (ruleset == NULL) { + SCLogError("Kernel does not support Landlock"); + return; + } + + LandlockSandboxingWritePath(ruleset, ConfigGetLogDirectory()); + struct stat sb; + if (stat(ConfigGetDataDirectory(), &sb) == 0) { + LandlockSandboxingAddRule(ruleset, ConfigGetDataDirectory(), + _LANDLOCK_SURI_ACCESS_FS_WRITE | _LANDLOCK_ACCESS_FS_READ); + } + if (suri->run_mode == RUNMODE_PCAP_FILE) { + const char *pcap_file; + if (ConfGet("pcap-file.file", &pcap_file) == 1) { + char *file_name = SCStrdup(pcap_file); + if (file_name != NULL) { + struct stat statbuf; + if (stat(file_name, &statbuf) != -1) { + if (S_ISDIR(statbuf.st_mode)) { + LandlockSandboxingReadPath(ruleset, file_name); + } else { + LandlockSandboxingReadPath(ruleset, dirname(file_name)); + } + } else { + SCLogError("Can't open pcap file"); + } + SCFree(file_name); + } + } + } + if (suri->sig_file) { + char *file_name = SCStrdup(suri->sig_file); + if (file_name != NULL) { + LandlockSandboxingReadPath(ruleset, dirname(file_name)); + SCFree(file_name); + } + } + if (suri->pid_filename) { + char *file_name = SCStrdup(suri->pid_filename); + if (file_name != NULL) { + LandlockSandboxingWritePath(ruleset, dirname(file_name)); + SCFree(file_name); + } + } + if (ConfUnixSocketIsEnable()) { + const char *socketname; + if (ConfGet("unix-command.filename", &socketname) == 1) { + if (PathIsAbsolute(socketname)) { + char *file_name = SCStrdup(socketname); + if (file_name != NULL) { + LandlockSandboxingWritePath(ruleset, dirname(file_name)); + SCFree(file_name); + } + } else { + LandlockSandboxingWritePath(ruleset, LOCAL_STATE_DIR "/run/suricata/"); + } + } else { + LandlockSandboxingWritePath(ruleset, LOCAL_STATE_DIR "/run/suricata/"); + } + } + if (!suri->sig_file_exclusive) { + const char *rule_path; + if (ConfGet("default-rule-path", &rule_path) == 1 && rule_path) { + LandlockSandboxingReadPath(ruleset, rule_path); + } + } + + ConfNode *read_dirs = ConfGetNode("security.landlock.directories.read"); + if (read_dirs) { + if (!ConfNodeIsSequence(read_dirs)) { + SCLogWarning("Invalid security.landlock.directories.read configuration section: " + "expected a list of directory names."); + } else { + ConfNode *directory; + TAILQ_FOREACH (directory, &read_dirs->head, next) { + LandlockSandboxingReadPath(ruleset, directory->val); + } + } + } + ConfNode *write_dirs = ConfGetNode("security.landlock.directories.write"); + if (write_dirs) { + if (!ConfNodeIsSequence(write_dirs)) { + SCLogWarning("Invalid security.landlock.directories.write configuration section: " + "expected a list of directory names."); + } else { + ConfNode *directory; + TAILQ_FOREACH (directory, &write_dirs->head, next) { + LandlockSandboxingWritePath(ruleset, directory->val); + } + } + } + LandlockEnforceRuleset(ruleset); + SCFree(ruleset); +} + +#endif /* HAVE_LINUX_LANDLOCK_H */ diff --git a/src/util-landlock.h b/src/util/landlock.h similarity index 100% rename from src/util-landlock.h rename to src/util/landlock.h diff --git a/src/util/log-redis.c b/src/util/log-redis.c new file mode 100644 index 000000000000..c4a508ce41fe --- /dev/null +++ b/src/util/log-redis.c @@ -0,0 +1,586 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Paulo Pacheco + * + * File-like output for logging: redis + */ +#include "suricata-common.h" /* errno.h, string.h, etc. */ +#include "util/log-redis.h" +#include "util/logopenfile.h" +#include "util/byte.h" +#include "util/debug.h" + +#ifdef HAVE_LIBHIREDIS + +#ifdef HAVE_LIBEVENT_PTHREADS +#include +#endif /* HAVE_LIBEVENT_PTHREADS */ + +static const char *redis_lpush_cmd = "LPUSH"; +static const char *redis_rpush_cmd = "RPUSH"; +static const char *redis_publish_cmd = "PUBLISH"; +static const char *redis_default_key = "suricata"; +static const char *redis_default_server = "127.0.0.1"; + +static int SCConfLogReopenSyncRedis(LogFileCtx *log_ctx); +static void SCLogFileCloseRedis(LogFileCtx *log_ctx); + +/** + * \brief SCLogRedisInit() - Initializes global stuff before threads + */ +void SCLogRedisInit(void) +{ +#ifdef HAVE_LIBEVENT_PTHREADS + evthread_use_pthreads(); +#endif /* HAVE_LIBEVENT_PTHREADS */ +} + +/** \brief SCLogRedisContextAlloc() - Allocates and initializes redis context + */ +static SCLogRedisContext *SCLogRedisContextAlloc(void) +{ + SCLogRedisContext *ctx = (SCLogRedisContext *)SCCalloc(1, sizeof(SCLogRedisContext)); + if (ctx == NULL) { + FatalError("Unable to allocate redis context"); + } + ctx->sync = NULL; +#if HAVE_LIBEVENT + ctx->ev_base = NULL; + ctx->async = NULL; +#endif + ctx->batch_count = 0; + ctx->last_push = 0; + ctx->tried = 0; + + return ctx; +} + +#ifdef HAVE_LIBEVENT + +static int SCConfLogReopenAsyncRedis(LogFileCtx *log_ctx); +#include + +/** \brief SCLogRedisAsyncContextAlloc() - Allocates and initializes redis context with async + */ +static SCLogRedisContext *SCLogRedisContextAsyncAlloc(void) +{ + SCLogRedisContext *ctx = (SCLogRedisContext *)SCCalloc(1, sizeof(SCLogRedisContext)); + if (unlikely(ctx == NULL)) { + FatalError("Unable to allocate redis context"); + } + + ctx->sync = NULL; + ctx->async = NULL; + ctx->ev_base = NULL; + ctx->connected = 0; + ctx->batch_count = 0; + ctx->last_push = 0; + ctx->tried = 0; + + return ctx; +} + +/** \brief SCRedisAsyncCommandCallback() Callback when reply from redis happens. + * \param ac redis async context + * \param r redis reply + * \param privdata opaque data with pointer to LogFileCtx + */ +static void SCRedisAsyncCommandCallback(redisAsyncContext *ac, void *r, void *privdata) +{ + redisReply *reply = r; + LogFileCtx *log_ctx = privdata; + SCLogRedisContext *ctx = log_ctx->redis; + + if (reply == NULL) { + if (ctx->connected > 0) + SCLogInfo("Missing reply from redis, disconnected."); + ctx->connected = 0; + } else { + ctx->connected = 1; + event_base_loopbreak(ctx->ev_base); + } +} + +/** \brief SCRedisAsyncEchoCommandCallback() Callback for an ECHO command reply + * This is used to check if redis is connected. + * \param ac redis async context + * \param r redis reply + * \param privdata opaque data with pointer to LogFileCtx + */ +static void SCRedisAsyncEchoCommandCallback(redisAsyncContext *ac, void *r, void *privdata) +{ + redisReply *reply = r; + SCLogRedisContext *ctx = privdata; + + if (reply) { + if (ctx->connected == 0) { + SCLogNotice("Connected to Redis."); + ctx->connected = 1; + ctx->tried = 0; + } + } else { + ctx->connected = 0; + if (ctx->tried == 0) { + SCLogWarning("Failed to connect to Redis... (will keep trying)"); + } + ctx->tried = time(NULL); + } + event_base_loopbreak(ctx->ev_base); +} + +/** \brief SCRedisAsyncEchoCommandCallback() Callback for an QUIT command reply + * Emits and awaits response for an async ECHO command. + * It's used for check if redis is alive. + * \param ctx redis context + */ +static void SCLogAsyncRedisSendEcho(SCLogRedisContext *ctx) +{ + redisAsyncCommand(ctx->async, SCRedisAsyncEchoCommandCallback, ctx, "ECHO suricata"); + event_base_dispatch(ctx->ev_base); +} + +/** \brief SCRedisAsyncEchoCommandCallback() Callback for an QUIT command reply + * This is used to terminate connection with redis. + * \param ac redis async context + * \param r redis reply + * \param privdata opaque data with pointer to LogFileCtx + */ +static void SCRedisAsyncQuitCommandCallback(redisAsyncContext *ac, void *r, void *privdata) +{ + SCLogInfo("Disconnecting from redis!"); +} + +/** \brief QUIT command + * Emits and awaits response for an async QUIT command. + * It's used to disconnect with redis + * \param ctx redis context + */ +static void SCLogAsyncRedisSendQuit(SCLogRedisContext *ctx) +{ + if (ctx->connected) { + redisAsyncCommand(ctx->async, SCRedisAsyncQuitCommandCallback, ctx, "QUIT"); + SCLogInfo("QUIT Command sent to redis. Connection will terminate!"); + } + + redisAsyncFree(ctx->async); + event_base_dispatch(ctx->ev_base); + ctx->async = NULL; + event_base_free(ctx->ev_base); + ctx->ev_base = NULL; + ctx->connected = 0; +} + +/** \brief SCConfLogReopenAsyncRedis() Open or re-opens connection to redis for logging. + * \param log_ctx Log file context allocated by caller + */ +static int SCConfLogReopenAsyncRedis(LogFileCtx *log_ctx) +{ + SCLogRedisContext *ctx = log_ctx->redis; + const char *redis_server = log_ctx->redis_setup.server; + int redis_port = log_ctx->redis_setup.port; + + /* only try to reconnect once per second */ + if (ctx->tried >= time(NULL)) { + return -1; + } + + if (strchr(redis_server, '/') == NULL) { + ctx->async = redisAsyncConnect(redis_server, redis_port); + } else { + ctx->async = redisAsyncConnectUnix(redis_server); + } + + if (ctx->ev_base != NULL) { + event_base_free(ctx->ev_base); + ctx->ev_base = NULL; + } + + if (ctx->async == NULL) { + SCLogError("Error allocate redis async."); + ctx->tried = time(NULL); + return -1; + } + + if (ctx->async != NULL && ctx->async->err) { + SCLogError("Error setting to redis async: [%s].", ctx->async->errstr); + ctx->tried = time(NULL); + return -1; + } + + ctx->ev_base = event_base_new(); + + if (ctx->ev_base == NULL) { + ctx->tried = time(NULL); + redisAsyncFree(ctx->async); + ctx->async = NULL; + return -1; + } + + redisLibeventAttach(ctx->async, ctx->ev_base); + + log_ctx->redis = ctx; + log_ctx->Close = SCLogFileCloseRedis; + return 0; +} + +/** \brief SCLogRedisWriteAsync() writes string to redis output in async mode + * \param file_ctx Log file context allocated by caller + * \param string Buffer to output + */ +static int SCLogRedisWriteAsync(LogFileCtx *file_ctx, const char *string, size_t string_len) +{ + SCLogRedisContext *ctx = file_ctx->redis; + + if (!ctx->connected) { + if (SCConfLogReopenAsyncRedis(file_ctx) == -1) { + return -1; + } + if (ctx->tried == 0) { + SCLogNotice("Trying to connect to Redis"); + } + SCLogAsyncRedisSendEcho(ctx); + } + + if (!ctx->connected) { + return -1; + } + + if (ctx->async == NULL) { + return -1; + } + + redisAsyncCommand(ctx->async, SCRedisAsyncCommandCallback, file_ctx, "%s %s %s", + file_ctx->redis_setup.command, file_ctx->redis_setup.key, string); + + event_base_loop(ctx->ev_base, EVLOOP_NONBLOCK); + + return 0; +} + +#endif // HAVE_LIBEVENT + +/** \brief SCConfLogReopenSyncRedis() Open or re-opens connection to redis for logging. + * \param log_ctx Log file context allocated by caller + */ +static int SCConfLogReopenSyncRedis(LogFileCtx *log_ctx) +{ + SCLogRedisContext *ctx = log_ctx->redis; + + /* only try to reconnect once per second */ + if (ctx->tried >= time(NULL)) { + return -1; + } + + const char *redis_server = log_ctx->redis_setup.server; + int redis_port = log_ctx->redis_setup.port; + + if (ctx->sync != NULL) { + redisFree(ctx->sync); + } + + if (strchr(redis_server, '/') == NULL) { + ctx->sync = redisConnect(redis_server, redis_port); + } else { + ctx->sync = redisConnectUnix(redis_server); + } + if (ctx->sync == NULL) { + SCLogError("Error connecting to redis server."); + ctx->tried = time(NULL); + return -1; + } + if (ctx->sync->err) { + SCLogError("Error connecting to redis server: [%s].", ctx->sync->errstr); + redisFree(ctx->sync); + ctx->sync = NULL; + ctx->tried = time(NULL); + return -1; + } + SCLogInfo("Connected to redis server [%s].", log_ctx->redis_setup.server); + + log_ctx->redis = ctx; + log_ctx->Close = SCLogFileCloseRedis; + return 0; +} +/** \brief SCLogRedisWriteSync() writes string to redis output in sync mode + * \param file_ctx Log file context allocated by caller + * \param string Buffer to output + */ +static int SCLogRedisWriteSync(LogFileCtx *file_ctx, const char *string) +{ + SCLogRedisContext *ctx = file_ctx->redis; + int ret = -1; + redisContext *redis = ctx->sync; + if (redis == NULL) { + SCConfLogReopenSyncRedis(file_ctx); + redis = ctx->sync; + if (redis == NULL) { + SCLogDebug("Redis after re-open is not available."); + return -1; + } + } + + /* synchronous mode */ + if (file_ctx->redis_setup.batch_size) { + redisAppendCommand(redis, "%s %s %s", file_ctx->redis_setup.command, + file_ctx->redis_setup.key, string); + time_t now = time(NULL); + if ((ctx->batch_count == file_ctx->redis_setup.batch_size) || (ctx->last_push < now)) { + redisReply *reply; + int i; + int batch_size = ctx->batch_count; + ctx->batch_count = 0; + ctx->last_push = now; + for (i = 0; i <= batch_size; i++) { + if (redisGetReply(redis, (void **)&reply) == REDIS_OK) { + freeReplyObject(reply); + ret = 0; + } else { + if (redis->err) { + SCLogInfo("Error when fetching reply: %s (%d)", redis->errstr, redis->err); + } + switch (redis->err) { + case REDIS_ERR_EOF: + case REDIS_ERR_IO: + SCLogInfo("Reopening connection to redis server"); + SCConfLogReopenSyncRedis(file_ctx); + redis = ctx->sync; + if (redis) { + SCLogInfo("Reconnected to redis server"); + redisAppendCommand(redis, "%s %s %s", file_ctx->redis_setup.command, + file_ctx->redis_setup.key, string); + ctx->batch_count++; + return 0; + } else { + SCLogInfo("Unable to reconnect to redis server"); + return -1; + } + break; + default: + SCLogWarning("Unsupported error code %d", redis->err); + return -1; + } + } + } + } else { + ctx->batch_count++; + } + } else { + redisReply *reply = redisCommand(redis, "%s %s %s", file_ctx->redis_setup.command, + file_ctx->redis_setup.key, string); + /* We may lose the reply if disconnection happens*/ + if (reply) { + switch (reply->type) { + case REDIS_REPLY_ERROR: + SCLogWarning("Redis error: %s", reply->str); + SCConfLogReopenSyncRedis(file_ctx); + break; + case REDIS_REPLY_INTEGER: + SCLogDebug("Redis integer %lld", reply->integer); + ret = 0; + break; + default: + SCLogError("Redis default triggered with %d", reply->type); + SCConfLogReopenSyncRedis(file_ctx); + break; + } + freeReplyObject(reply); + } else { + SCConfLogReopenSyncRedis(file_ctx); + } + } + return ret; +} + +/** + * \brief LogFileWriteRedis() writes log data to redis output. + * \param log_ctx Log file context allocated by caller + * \param string buffer with data to write + * \param string_len data length + * \retval 0 on success; + * \retval -1 on failure; + */ +int LogFileWriteRedis(void *lf_ctx, const char *string, size_t string_len) +{ + LogFileCtx *file_ctx = lf_ctx; + if (file_ctx == NULL) { + return -1; + } + +#if HAVE_LIBEVENT + /* async mode on */ + if (file_ctx->redis_setup.is_async) { + return SCLogRedisWriteAsync(file_ctx, string, string_len); + } +#endif + /* sync mode */ + if (!file_ctx->redis_setup.is_async) { + return SCLogRedisWriteSync(file_ctx, string); + } + return -1; +} + +/** \brief configure and initializes redis output logging + * \param conf ConfNode structure for the output section in question + * \param log_ctx Log file context allocated by caller + * \retval 0 on success + */ +int SCConfLogOpenRedis(ConfNode *redis_node, void *lf_ctx) +{ + LogFileCtx *log_ctx = lf_ctx; + + if (log_ctx->threaded) { + FatalError("redis does not support threaded output"); + } + + const char *redis_port = NULL; + const char *redis_mode = NULL; + + int is_async = 0; + + if (redis_node) { + log_ctx->redis_setup.server = ConfNodeLookupChildValue(redis_node, "server"); + log_ctx->redis_setup.key = ConfNodeLookupChildValue(redis_node, "key"); + + redis_port = ConfNodeLookupChildValue(redis_node, "port"); + redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); + + (void)ConfGetChildValueBool(redis_node, "async", &is_async); + } + if (!log_ctx->redis_setup.server) { + log_ctx->redis_setup.server = redis_default_server; + SCLogInfo("Using default redis server (127.0.0.1)"); + } + if (!redis_port) + redis_port = "6379"; + if (!redis_mode) + redis_mode = "list"; + if (!log_ctx->redis_setup.key) { + log_ctx->redis_setup.key = redis_default_key; + } + +#ifndef HAVE_LIBEVENT + if (is_async) { + SCLogWarning("async option not available."); + } + is_async = 0; +#endif // ifndef HAVE_LIBEVENT + + log_ctx->redis_setup.is_async = is_async; + log_ctx->redis_setup.batch_size = 0; + if (redis_node) { + ConfNode *pipelining = ConfNodeLookupChild(redis_node, "pipelining"); + if (pipelining) { + int enabled = 0; + int ret; + intmax_t val; + ret = ConfGetChildValueBool(pipelining, "enabled", &enabled); + if (ret && enabled) { + ret = ConfGetChildValueInt(pipelining, "batch-size", &val); + if (ret) { + log_ctx->redis_setup.batch_size = val; + } else { + log_ctx->redis_setup.batch_size = 10; + } + } + } + } else { + log_ctx->redis_setup.batch_size = 0; + } + + if (!strcmp(redis_mode, "list") || !strcmp(redis_mode, "lpush")) { + log_ctx->redis_setup.command = redis_lpush_cmd; + } else if (!strcmp(redis_mode, "rpush")) { + log_ctx->redis_setup.command = redis_rpush_cmd; + } else if (!strcmp(redis_mode, "channel") || !strcmp(redis_mode, "publish")) { + log_ctx->redis_setup.command = redis_publish_cmd; + } else { + FatalError("Invalid redis mode"); + } + + /* store server params for reconnection */ + if (!log_ctx->redis_setup.server) { + FatalError("Error allocating redis server string"); + } + if (StringParseUint16(&log_ctx->redis_setup.port, 10, 0, (const char *)redis_port) < 0) { + FatalError("Invalid value for redis port: %s", redis_port); + } + log_ctx->Close = SCLogFileCloseRedis; + +#ifdef HAVE_LIBEVENT + if (is_async) { + log_ctx->redis = SCLogRedisContextAsyncAlloc(); + } +#endif /*HAVE_LIBEVENT*/ + if (!is_async) { + log_ctx->redis = SCLogRedisContextAlloc(); + SCConfLogReopenSyncRedis(log_ctx); + } + return 0; +} + +/** \brief SCLogFileCloseRedis() Closes redis log more + * \param log_ctx Log file context allocated by caller + */ +void SCLogFileCloseRedis(LogFileCtx *log_ctx) +{ + SCLogRedisContext *ctx = log_ctx->redis; + if (ctx == NULL) { + return; + } + /* asynchronous */ + if (log_ctx->redis_setup.is_async) { +#if HAVE_LIBEVENT == 1 + if (ctx->async) { + if (ctx->connected > 0) { + SCLogAsyncRedisSendQuit(ctx); + } + if (ctx->ev_base != NULL) { + event_base_free(ctx->ev_base); + ctx->ev_base = NULL; + } + } +#endif + } + + /* synchronous */ + if (!log_ctx->redis_setup.is_async) { + if (ctx->sync) { + redisReply *reply; + int i; + for (i = 0; i < ctx->batch_count; i++) { + redisGetReply(ctx->sync, (void **)&reply); + if (reply) { + freeReplyObject(reply); + } + } + redisFree(ctx->sync); + ctx->sync = NULL; + } + ctx->tried = 0; + ctx->batch_count = 0; + } + + if (ctx != NULL) { + SCFree(ctx); + } +} + +#endif // #ifdef HAVE_LIBHIREDIS diff --git a/src/util/log-redis.h b/src/util/log-redis.h new file mode 100644 index 000000000000..498d9ef689ae --- /dev/null +++ b/src/util/log-redis.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Paulo Pacheco + */ + +#ifndef __UTIL_LOG_REDIS_H__ +#define __UTIL_LOG_REDIS_H__ + +#ifdef HAVE_LIBHIREDIS +#include + +#ifdef HAVE_LIBEVENT +#include +#endif /* HAVE_LIBEVENT */ + +#include "../conf.h" /* ConfNode */ + +enum RedisMode { REDIS_LIST, REDIS_CHANNEL }; + +typedef struct RedisSetup_ { + enum RedisMode mode; + const char *command; + const char *key; + const char *server; + uint16_t port; + int is_async; + int batch_size; +} RedisSetup; + +typedef struct SCLogRedisContext_ { + redisContext *sync; +#if HAVE_LIBEVENT + redisAsyncContext *async; + struct event_base *ev_base; + int connected; +#endif /* HAVE_LIBEVENT */ + time_t tried; + int batch_count; + time_t last_push; +} SCLogRedisContext; + +void SCLogRedisInit(void); +int SCConfLogOpenRedis(ConfNode *, void *); +int LogFileWriteRedis(void *, const char *, size_t); + +#endif /* HAVE_LIBHIREDIS */ +#endif /* __UTIL_LOG_REDIS_H__ */ diff --git a/src/util/logopenfile.c b/src/util/logopenfile.c new file mode 100644 index 000000000000..a224990c5f1a --- /dev/null +++ b/src/util/logopenfile.c @@ -0,0 +1,927 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mike Pomraning + * + * File-like output for logging: regular files and sockets. + */ + +#include "suricata-common.h" /* errno.h, string.h, etc. */ +#include "util/logopenfile.h" +#include "suricata.h" +#include "../conf.h" /* ConfNode, etc. */ +#include "output/output.h" /* DEFAULT_LOG_* */ +#include "util/byte.h" +#include "util/conf.h" +#include "util/path.h" +#include "util/time.h" + +#if defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SYS_TYPES_H) +#define BUILD_WITH_UNIXSOCKET +#include +#include +#include +#endif + +#ifdef HAVE_LIBHIREDIS +#include "util/log-redis.h" +#endif /* HAVE_LIBHIREDIS */ + +#define LOGFILE_NAME_MAX 255 + +static bool LogFileNewThreadedCtx(LogFileCtx *parent_ctx, const char *log_path, const char *append, + ThreadLogFileHashEntry *entry); + +// Threaded eve.json identifier +static SC_ATOMIC_DECL_AND_INIT_WITH_VAL(uint32_t, eve_file_id, 1); + +#ifdef BUILD_WITH_UNIXSOCKET +/** \brief connect to the indicated local stream socket, logging any errors + * \param path filesystem path to connect to + * \param log_err, non-zero if connect failure should be logged. + * \retval FILE* on success (fdopen'd wrapper of underlying socket) + * \retval NULL on error + */ +static FILE *SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err) +{ + struct sockaddr_un saun; + int s = -1; + FILE *ret = NULL; + + memset(&saun, 0x00, sizeof(saun)); + + s = socket(PF_UNIX, sock_type, 0); + if (s < 0) + goto err; + + saun.sun_family = AF_UNIX; + strlcpy(saun.sun_path, path, sizeof(saun.sun_path)); + + if (connect(s, (const struct sockaddr *)&saun, sizeof(saun)) < 0) + goto err; + + ret = fdopen(s, "w"); + if (ret == NULL) + goto err; + + return ret; + +err: + if (log_err) + SCLogWarning( + "Error connecting to socket \"%s\": %s (will keep trying)", path, strerror(errno)); + + if (s >= 0) + close(s); + + return NULL; +} + +/** + * \brief Attempt to reconnect a disconnected (or never-connected) Unix domain socket. + * \retval 1 if it is now connected; otherwise 0 + */ +static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx) +{ + int disconnected = 0; + if (log_ctx->fp) { + SCLogWarning("Write error on Unix socket \"%s\": %s; reconnecting...", log_ctx->filename, + strerror(errno)); + fclose(log_ctx->fp); + log_ctx->fp = NULL; + log_ctx->reconn_timer = 0; + disconnected = 1; + } + + struct timeval tv; + uint64_t now; + gettimeofday(&tv, NULL); + now = (uint64_t)tv.tv_sec * 1000; + now += tv.tv_usec / 1000; /* msec resolution */ + if (log_ctx->reconn_timer != 0 && (now - log_ctx->reconn_timer) < LOGFILE_RECONN_MIN_TIME) { + /* Don't bother to try reconnecting too often. */ + return 0; + } + log_ctx->reconn_timer = now; + + log_ctx->fp = SCLogOpenUnixSocketFp(log_ctx->filename, log_ctx->sock_type, 0); + if (log_ctx->fp) { + /* Connected at last (or reconnected) */ + SCLogNotice("Reconnected socket \"%s\"", log_ctx->filename); + } else if (disconnected) { + SCLogWarning("Reconnect failed: %s (will keep trying)", strerror(errno)); + } + + return log_ctx->fp ? 1 : 0; +} + +static int SCLogFileWriteSocket(const char *buffer, int buffer_len, LogFileCtx *ctx) +{ + int tries = 0; + int ret = 0; + bool reopen = false; + if (ctx->fp == NULL && ctx->is_sock) { + SCLogUnixSocketReconnect(ctx); + } +tryagain: + ret = -1; + reopen = 0; + errno = 0; + if (ctx->fp != NULL) { + int fd = fileno(ctx->fp); + ssize_t size = send(fd, buffer, buffer_len, ctx->send_flags); + if (size > -1) { + ret = 0; + } else { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + SCLogDebug("Socket would block, dropping event."); + } else if (errno == EINTR) { + if (tries++ == 0) { + SCLogDebug("Interrupted system call, trying again."); + goto tryagain; + } + SCLogDebug("Too many interrupted system calls, " + "dropping event."); + } else { + /* Some other error. Assume badness and reopen. */ + SCLogDebug("Send failed: %s", strerror(errno)); + reopen = true; + } + } + } + + if (reopen && tries++ == 0) { + if (SCLogUnixSocketReconnect(ctx)) { + goto tryagain; + } + } + + if (ret == -1) { + ctx->dropped++; + } + + return ret; +} +#endif /* BUILD_WITH_UNIXSOCKET */ +static inline void OutputWriteLock(pthread_mutex_t *m) +{ + SCMutexLock(m); +} + +/** + * \brief Write buffer to log file. + * \retval 0 on failure; otherwise, the return value of fwrite_unlocked (number of + * characters successfully written). + */ +static int SCLogFileWriteNoLock(const char *buffer, int buffer_len, LogFileCtx *log_ctx) +{ + int ret = 0; + + BUG_ON(log_ctx->is_sock); + + /* Check for rotation. */ + if (log_ctx->rotation_flag) { + log_ctx->rotation_flag = 0; + SCConfLogReopen(log_ctx); + } + + if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { + time_t now = time(NULL); + if (now >= log_ctx->rotate_time) { + SCConfLogReopen(log_ctx); + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + + if (log_ctx->fp) { + SCClearErrUnlocked(log_ctx->fp); + if (1 != SCFwriteUnlocked(buffer, buffer_len, 1, log_ctx->fp)) { + /* Only the first error is logged */ + if (!log_ctx->output_errors) { + SCLogError("%s error while writing to %s", + SCFerrorUnlocked(log_ctx->fp) ? strerror(errno) : "unknown error", + log_ctx->filename); + } + log_ctx->output_errors++; + } else { + SCFflushUnlocked(log_ctx->fp); + } + } + + return ret; +} + +/** + * \brief Write buffer to log file. + * \retval 0 on failure; otherwise, the return value of fwrite (number of + * characters successfully written). + */ +static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) +{ + OutputWriteLock(&log_ctx->fp_mutex); + int ret = 0; + +#ifdef BUILD_WITH_UNIXSOCKET + if (log_ctx->is_sock) { + ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx); + } else +#endif + { + + /* Check for rotation. */ + if (log_ctx->rotation_flag) { + log_ctx->rotation_flag = 0; + SCConfLogReopen(log_ctx); + } + + if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { + time_t now = time(NULL); + if (now >= log_ctx->rotate_time) { + SCConfLogReopen(log_ctx); + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + + if (log_ctx->fp) { + clearerr(log_ctx->fp); + if (1 != fwrite(buffer, buffer_len, 1, log_ctx->fp)) { + /* Only the first error is logged */ + if (!log_ctx->output_errors) { + SCLogError("%s error while writing to %s", + ferror(log_ctx->fp) ? strerror(errno) : "unknown error", + log_ctx->filename); + } + log_ctx->output_errors++; + } else { + fflush(log_ctx->fp); + } + } + } + + SCMutexUnlock(&log_ctx->fp_mutex); + + return ret; +} + +/** \brief generate filename based on pattern + * \param pattern pattern to use + * \retval char* on success + * \retval NULL on error + */ +static char *SCLogFilenameFromPattern(const char *pattern) +{ + char *filename = SCMalloc(PATH_MAX); + if (filename == NULL) { + return NULL; + } + + int rc = SCTimeToStringPattern(time(NULL), pattern, filename, PATH_MAX); + if (rc != 0) { + SCFree(filename); + return NULL; + } + + return filename; +} + +static void SCLogFileCloseNoLock(LogFileCtx *log_ctx) +{ + SCLogDebug("Closing %s", log_ctx->filename); + if (log_ctx->fp) + fclose(log_ctx->fp); + + if (log_ctx->output_errors) { + SCLogError("There were %" PRIu64 " output errors to %s", log_ctx->output_errors, + log_ctx->filename); + } +} + +static void SCLogFileClose(LogFileCtx *log_ctx) +{ + SCMutexLock(&log_ctx->fp_mutex); + SCLogFileCloseNoLock(log_ctx); + SCMutexUnlock(&log_ctx->fp_mutex); +} + +static char ThreadLogFileHashCompareFunc( + void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) +{ + ThreadLogFileHashEntry *p1 = (ThreadLogFileHashEntry *)data1; + ThreadLogFileHashEntry *p2 = (ThreadLogFileHashEntry *)data2; + + if (p1 == NULL || p2 == NULL) + return 0; + + return p1->thread_id == p2->thread_id; +} +static uint32_t ThreadLogFileHashFunc(HashTable *ht, void *data, uint16_t datalen) +{ + const ThreadLogFileHashEntry *ent = (ThreadLogFileHashEntry *)data; + + return ent->thread_id % ht->array_size; +} + +static void ThreadLogFileHashFreeFunc(void *data) +{ + BUG_ON(data == NULL); + ThreadLogFileHashEntry *thread_ent = (ThreadLogFileHashEntry *)data; + + if (thread_ent) { + LogFileCtx *lf_ctx = thread_ent->ctx; + /* Free the leaf log file entries */ + if (!lf_ctx->threaded) { + LogFileFreeCtx(lf_ctx); + } + SCFree(thread_ent); + } +} + +bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx) +{ + parent_ctx->threads = SCCalloc(1, sizeof(LogThreadedFileCtx)); + if (!parent_ctx->threads) { + SCLogError("Unable to allocate threads container"); + return false; + } + + parent_ctx->threads->ht = HashTableInit( + 255, ThreadLogFileHashFunc, ThreadLogFileHashCompareFunc, ThreadLogFileHashFreeFunc); + if (!parent_ctx->threads->ht) { + FatalError("Unable to initialize thread/entry hash table"); + } + + parent_ctx->threads->append = SCStrdup(append == NULL ? DEFAULT_LOG_MODE_APPEND : append); + if (!parent_ctx->threads->append) { + SCLogError("Unable to allocate threads append setting"); + goto error_exit; + } + + SCMutexInit(&parent_ctx->threads->mutex, NULL); + return true; + +error_exit: + + if (parent_ctx->threads->append) { + SCFree(parent_ctx->threads->append); + } + if (parent_ctx->threads->ht) { + HashTableFree(parent_ctx->threads->ht); + } + SCFree(parent_ctx->threads); + parent_ctx->threads = NULL; + return false; +} + +/** \brief open the indicated file, logging any errors + * \param path filesystem path to open + * \param append_setting open file with O_APPEND: "yes" or "no" + * \param mode permissions to set on file + * \retval FILE* on success + * \retval NULL on error + */ +static FILE *SCLogOpenFileFp(const char *path, const char *append_setting, uint32_t mode) +{ + FILE *ret = NULL; + + char *filename = SCLogFilenameFromPattern(path); + if (filename == NULL) { + return NULL; + } + + int rc = SCCreateDirectoryTree(filename, false); + if (rc < 0) { + SCFree(filename); + return NULL; + } + + if (ConfValIsTrue(append_setting)) { + ret = fopen(filename, "a"); + } else { + ret = fopen(filename, "w"); + } + + if (ret == NULL) { + SCLogError("Error opening file: \"%s\": %s", filename, strerror(errno)); + } else { + if (mode != 0) { +#ifdef OS_WIN32 + int r = _chmod(filename, (mode_t)mode); +#else + int r = fchmod(fileno(ret), (mode_t)mode); +#endif + if (r < 0) { + SCLogWarning("Could not chmod %s to %o: %s", filename, mode, strerror(errno)); + } + } + } + + SCFree(filename); + return ret; +} + +/** \brief open a generic output "log file", which may be a regular file or a socket + * \param conf ConfNode structure for the output section in question + * \param log_ctx Log file context allocated by caller + * \param default_filename Default name of file to open, if not specified in ConfNode + * \param rotate Register the file for rotation in HUP. + * \retval 0 on success + * \retval -1 on error + */ +int SCConfLogOpenGeneric( + ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate) +{ + char log_path[PATH_MAX]; + const char *log_dir; + const char *filename, *filetype; + + // Arg check + if (conf == NULL || log_ctx == NULL || default_filename == NULL) { + SCLogError("SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " + "missing an argument", + conf, log_ctx, default_filename); + return -1; + } + if (log_ctx->fp != NULL) { + SCLogError("SCConfLogOpenGeneric: previously initialized Log CTX " + "encountered"); + return -1; + } + + // Resolve the given config + filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename == NULL) + filename = default_filename; + + log_dir = ConfigGetLogDirectory(); + + if (PathIsAbsolute(filename)) { + snprintf(log_path, PATH_MAX, "%s", filename); + } else { + snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); + } + + /* Rotate log file based on time */ + const char *rotate_int = ConfNodeLookupChildValue(conf, "rotate-interval"); + if (rotate_int != NULL) { + time_t now = time(NULL); + log_ctx->flags |= LOGFILE_ROTATE_INTERVAL; + + /* Use a specific time */ + if (strcmp(rotate_int, "minute") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 60; + } else if (strcmp(rotate_int, "hour") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 3600; + } else if (strcmp(rotate_int, "day") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 86400; + } + + /* Use a timer */ + else { + log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int); + if (log_ctx->rotate_interval == 0) { + FatalError("invalid rotate-interval value"); + } + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + + filetype = ConfNodeLookupChildValue(conf, "filetype"); + if (filetype == NULL) + filetype = DEFAULT_LOG_FILETYPE; + + const char *filemode = ConfNodeLookupChildValue(conf, "filemode"); + uint32_t mode = 0; + if (filemode != NULL && StringParseUint32(&mode, 8, (uint16_t)strlen(filemode), filemode) > 0) { + log_ctx->filemode = mode; + } + + const char *append = ConfNodeLookupChildValue(conf, "append"); + if (append == NULL) + append = DEFAULT_LOG_MODE_APPEND; + + /* JSON flags */ + log_ctx->json_flags = + JSON_PRESERVE_ORDER | JSON_COMPACT | JSON_ENSURE_ASCII | JSON_ESCAPE_SLASH; + + ConfNode *json_flags = ConfNodeLookupChild(conf, "json"); + + if (json_flags != 0) { + const char *preserve_order = ConfNodeLookupChildValue(json_flags, "preserve-order"); + if (preserve_order != NULL && ConfValIsFalse(preserve_order)) + log_ctx->json_flags &= ~(JSON_PRESERVE_ORDER); + + const char *compact = ConfNodeLookupChildValue(json_flags, "compact"); + if (compact != NULL && ConfValIsFalse(compact)) + log_ctx->json_flags &= ~(JSON_COMPACT); + + const char *ensure_ascii = ConfNodeLookupChildValue(json_flags, "ensure-ascii"); + if (ensure_ascii != NULL && ConfValIsFalse(ensure_ascii)) + log_ctx->json_flags &= ~(JSON_ENSURE_ASCII); + + const char *escape_slash = ConfNodeLookupChildValue(json_flags, "escape-slash"); + if (escape_slash != NULL && ConfValIsFalse(escape_slash)) + log_ctx->json_flags &= ~(JSON_ESCAPE_SLASH); + } + +#ifdef BUILD_WITH_UNIXSOCKET + if (log_ctx->threaded) { + if (strcasecmp(filetype, "unix_stream") == 0 || strcasecmp(filetype, "unix_dgram") == 0) { + FatalError("Socket file types do not support threaded output"); + } + } +#endif + // Now, what have we been asked to open? + if (strcasecmp(filetype, "unix_stream") == 0) { +#ifdef BUILD_WITH_UNIXSOCKET + /* Don't bail. May be able to connect later. */ + log_ctx->is_sock = 1; + log_ctx->sock_type = SOCK_STREAM; + log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1); +#else + return -1; +#endif + } else if (strcasecmp(filetype, "unix_dgram") == 0) { +#ifdef BUILD_WITH_UNIXSOCKET + /* Don't bail. May be able to connect later. */ + log_ctx->is_sock = 1; + log_ctx->sock_type = SOCK_DGRAM; + log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); +#else + return -1; +#endif + } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || + strcasecmp(filetype, "file") == 0) { + log_ctx->is_regular = 1; + if (!log_ctx->threaded) { + log_ctx->fp = SCLogOpenFileFp(log_path, append, log_ctx->filemode); + if (log_ctx->fp == NULL) + return -1; // Error already logged by Open...Fp routine + } else { + if (!SCLogOpenThreadedFile(log_path, append, log_ctx)) { + return -1; + } + } + if (rotate) { + OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); + } + } else { + SCLogError("Invalid entry for " + "%s.filetype. Expected \"regular\" (default), \"unix_stream\", " + "or \"unix_dgram\"", + conf->name); + } + log_ctx->filename = SCStrdup(log_path); + if (unlikely(log_ctx->filename == NULL)) { + SCLogError("Failed to allocate memory for filename"); + return -1; + } + +#ifdef BUILD_WITH_UNIXSOCKET + /* If a socket and running live, do non-blocking writes. */ + if (log_ctx->is_sock && !IsRunModeOffline(RunmodeGetCurrent())) { + SCLogInfo("Setting logging socket of non-blocking in live mode."); + log_ctx->send_flags |= MSG_DONTWAIT; + } +#endif + SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); + + return 0; +} + +/** + * \brief Reopen a regular log file with the side-affect of truncating it. + * + * This is useful to clear the log file and start a new one, or to + * re-open the file after its been moved by something external + * (eg. logrotate). + */ +int SCConfLogReopen(LogFileCtx *log_ctx) +{ + if (!log_ctx->is_regular) { + /* Not supported and not needed on non-regular files. */ + return 0; + } + + if (log_ctx->filename == NULL) { + SCLogWarning("Can't re-open LogFileCtx without a filename."); + return -1; + } + + if (log_ctx->fp != NULL) { + fclose(log_ctx->fp); + } + + /* Reopen the file. Append is forced in case the file was not + * moved as part of a rotation process. */ + SCLogDebug("Reopening log file %s.", log_ctx->filename); + log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "yes", log_ctx->filemode); + if (log_ctx->fp == NULL) { + return -1; // Already logged by Open..Fp routine. + } + + return 0; +} + +/** \brief LogFileNewCtx() Get a new LogFileCtx + * \retval LogFileCtx * pointer if successful, NULL if error + * */ +LogFileCtx *LogFileNewCtx(void) +{ + LogFileCtx *lf_ctx; + lf_ctx = (LogFileCtx *)SCCalloc(1, sizeof(LogFileCtx)); + + if (lf_ctx == NULL) + return NULL; + + lf_ctx->Write = SCLogFileWrite; + lf_ctx->Close = SCLogFileClose; + + return lf_ctx; +} + +/** \brief LogFileThread2Slot() Return a file entry + * \retval ThreadLogFileHashEntry * file entry for caller + * + * This function returns the file entry for the calling thread. + * Each thread -- identified by its operating system thread-id -- has its + * own file entry that includes a file pointer. + */ +static ThreadLogFileHashEntry *LogFileThread2Slot(LogThreadedFileCtx *parent) +{ + ThreadLogFileHashEntry thread_hash_entry; + + /* Check hash table for thread id*/ + thread_hash_entry.thread_id = SCGetThreadIdLong(); + ThreadLogFileHashEntry *ent = + HashTableLookup(parent->ht, &thread_hash_entry, sizeof(thread_hash_entry)); + + if (!ent) { + ent = SCCalloc(1, sizeof(*ent)); + if (!ent) { + FatalError("Unable to allocate thread/entry entry"); + } + ent->thread_id = thread_hash_entry.thread_id; + SCLogDebug("Trying to add thread %ld to entry %d", ent->thread_id, ent->slot_number); + if (0 != HashTableAdd(parent->ht, ent, 0)) { + FatalError("Unable to add thread/entry mapping"); + } + } + return ent; +} + +/** \brief LogFileEnsureExists() Ensure a log file context for the thread exists + * \param parent_ctx + * \retval LogFileCtx * pointer if successful; NULL otherwise + */ +LogFileCtx *LogFileEnsureExists(LogFileCtx *parent_ctx) +{ + /* threaded output disabled */ + if (!parent_ctx->threaded) + return parent_ctx; + + SCMutexLock(&parent_ctx->threads->mutex); + /* Find this thread's entry */ + ThreadLogFileHashEntry *entry = LogFileThread2Slot(parent_ctx->threads); + SCLogDebug("Adding reference for thread %ld [slot %d] to file %s [ctx %p]", SCGetThreadIdLong(), + entry->slot_number, parent_ctx->filename, parent_ctx); + + bool new = entry->isopen; + /* has it been opened yet? */ + if (!entry->isopen) { + SCLogDebug("Opening new file for thread/slot %d to file %s [ctx %p]", entry->slot_number, + parent_ctx->filename, parent_ctx); + if (LogFileNewThreadedCtx( + parent_ctx, parent_ctx->filename, parent_ctx->threads->append, entry)) { + entry->isopen = true; + } else { + SCLogError( + "Unable to open slot %d for file %s", entry->slot_number, parent_ctx->filename); + (void)HashTableRemove(parent_ctx->threads->ht, entry, 0); + } + } + SCMutexUnlock(&parent_ctx->threads->mutex); + + if (sc_log_global_log_level >= SC_LOG_DEBUG) { + if (new) { + SCLogDebug("Existing file for thread/entry %p reference to file %s [ctx %p]", entry, + parent_ctx->filename, parent_ctx); + } + } + + return entry->ctx; +} + +/** \brief LogFileThreadedName() Create file name for threaded EVE storage + * + */ +static bool LogFileThreadedName( + const char *original_name, char *threaded_name, size_t len, uint32_t unique_id) +{ + sc_errno = SC_OK; + + if (strcmp("/dev/null", original_name) == 0) { + strlcpy(threaded_name, original_name, len); + return true; + } + + const char *base = SCBasename(original_name); + if (!base) { + FatalError("Invalid filename for threaded mode \"%s\"; " + "no basename found.", + original_name); + } + + /* Check if basename has an extension */ + char *dot = strrchr(base, '.'); + if (dot) { + char *tname = SCStrdup(original_name); + if (!tname) { + sc_errno = SC_ENOMEM; + return false; + } + + /* Fetch extension location from original, not base + * for update + */ + dot = strrchr(original_name, '.'); + int dotpos = dot - original_name; + tname[dotpos] = '\0'; + char *ext = tname + dotpos + 1; + if (strlen(tname) && strlen(ext)) { + snprintf(threaded_name, len, "%s.%u.%s", tname, unique_id, ext); + } else { + FatalError("Invalid filename for threaded mode \"%s\"; " + "filenames must include an extension, e.g: \"name.ext\"", + original_name); + } + SCFree(tname); + } else { + snprintf(threaded_name, len, "%s.%u", original_name, unique_id); + } + return true; +} + +/** \brief LogFileNewThreadedCtx() Create file context for threaded output + * \param parent_ctx + * \param log_path + * \param append + * \param entry + */ +static bool LogFileNewThreadedCtx(LogFileCtx *parent_ctx, const char *log_path, const char *append, + ThreadLogFileHashEntry *entry) +{ + LogFileCtx *thread = SCCalloc(1, sizeof(LogFileCtx)); + if (!thread) { + SCLogError("Unable to allocate thread file context entry %p", entry); + return false; + } + + *thread = *parent_ctx; + if (parent_ctx->type == LOGFILE_TYPE_FILE) { + char fname[LOGFILE_NAME_MAX]; + if (!LogFileThreadedName(log_path, fname, sizeof(fname), SC_ATOMIC_ADD(eve_file_id, 1))) { + SCLogError("Unable to create threaded filename for log"); + goto error; + } + SCLogDebug("Thread open -- using name %s [replaces %s]", fname, log_path); + thread->fp = SCLogOpenFileFp(fname, append, thread->filemode); + if (thread->fp == NULL) { + goto error; + } + thread->filename = SCStrdup(fname); + if (!thread->filename) { + SCLogError("Unable to duplicate filename for context entry %p", entry); + goto error; + } + thread->is_regular = true; + thread->Write = SCLogFileWriteNoLock; + thread->Close = SCLogFileCloseNoLock; + OutputRegisterFileRotationFlag(&thread->rotation_flag); + } else if (parent_ctx->type == LOGFILE_TYPE_PLUGIN) { + entry->slot_number = SC_ATOMIC_ADD(eve_file_id, 1); + thread->plugin.plugin->ThreadInit( + thread->plugin.init_data, entry->slot_number, &thread->plugin.thread_data); + } + thread->threaded = false; + thread->parent = parent_ctx; + thread->entry = entry; + entry->ctx = thread; + + return true; + +error: + if (parent_ctx->type == LOGFILE_TYPE_FILE) { + SC_ATOMIC_SUB(eve_file_id, 1); + if (thread->fp) { + thread->Close(thread); + } + } + + if (thread) { + SCFree(thread); + } + return false; +} + +/** \brief LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory) + * \param lf_ctx pointer to the OutputCtx + * \retval int 1 if successful, 0 if error + * */ +int LogFileFreeCtx(LogFileCtx *lf_ctx) +{ + if (lf_ctx == NULL) { + SCReturnInt(0); + } + + if (lf_ctx->type == LOGFILE_TYPE_PLUGIN && lf_ctx->parent != NULL) { + lf_ctx->plugin.plugin->ThreadDeinit(lf_ctx->plugin.init_data, lf_ctx->plugin.thread_data); + } + + if (lf_ctx->threaded) { + BUG_ON(lf_ctx->threads == NULL); + SCMutexDestroy(&lf_ctx->threads->mutex); + if (lf_ctx->threads->append) + SCFree(lf_ctx->threads->append); + if (lf_ctx->threads->ht) { + HashTableFree(lf_ctx->threads->ht); + } + SCFree(lf_ctx->threads); + } else { + if (lf_ctx->type != LOGFILE_TYPE_PLUGIN) { + if (lf_ctx->fp != NULL) { + lf_ctx->Close(lf_ctx); + } + } + SCMutexDestroy(&lf_ctx->fp_mutex); + } + + if (lf_ctx->prefix != NULL) { + SCFree(lf_ctx->prefix); + lf_ctx->prefix_len = 0; + } + + if (lf_ctx->filename != NULL) + SCFree(lf_ctx->filename); + + if (lf_ctx->sensor_name) + SCFree(lf_ctx->sensor_name); + + if (!lf_ctx->threaded) { + OutputUnregisterFileRotationFlag(&lf_ctx->rotation_flag); + } + + /* Deinitialize output plugins. We only want to call this for the + * parent of threaded output, or always for non-threaded + * output. */ + if (lf_ctx->type == LOGFILE_TYPE_PLUGIN && lf_ctx->parent == NULL) { + lf_ctx->plugin.plugin->Deinit(lf_ctx->plugin.init_data); + } + + memset(lf_ctx, 0, sizeof(*lf_ctx)); + SCFree(lf_ctx); + + SCReturnInt(1); +} + +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer) +{ + if (file_ctx->type == LOGFILE_TYPE_FILE || file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || + file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) { + /* append \n for files only */ + MemBufferWriteString(buffer, "\n"); + file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer), file_ctx); + } else if (file_ctx->type == LOGFILE_TYPE_PLUGIN) { + file_ctx->plugin.plugin->Write((const char *)MEMBUFFER_BUFFER(buffer), + MEMBUFFER_OFFSET(buffer), file_ctx->plugin.init_data, file_ctx->plugin.thread_data); + } +#ifdef HAVE_LIBHIREDIS + else if (file_ctx->type == LOGFILE_TYPE_REDIS) { + SCMutexLock(&file_ctx->fp_mutex); + LogFileWriteRedis( + file_ctx, (const char *)MEMBUFFER_BUFFER(buffer), MEMBUFFER_OFFSET(buffer)); + SCMutexUnlock(&file_ctx->fp_mutex); + } +#endif + + return 0; +} diff --git a/src/util/logopenfile.h b/src/util/logopenfile.h new file mode 100644 index 000000000000..a8652050c743 --- /dev/null +++ b/src/util/logopenfile.h @@ -0,0 +1,176 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mike Pomraning + */ + +#ifndef __UTIL_LOGOPENFILE_H__ +#define __UTIL_LOGOPENFILE_H__ + +#include "threads.h" +#include "../conf.h" /* ConfNode */ +#include "util/buffer.h" +#include "util/hash.h" + +#ifdef HAVE_LIBHIREDIS +#include "util/log-redis.h" +#endif /* HAVE_LIBHIREDIS */ + +#include "suricata-plugin.h" + +enum LogFileType { + LOGFILE_TYPE_FILE, + LOGFILE_TYPE_UNIX_DGRAM, + LOGFILE_TYPE_UNIX_STREAM, + LOGFILE_TYPE_REDIS, + LOGFILE_TYPE_PLUGIN, + LOGFILE_TYPE_NOTSET +}; + +typedef struct SyslogSetup_ { + int alert_syslog_level; +} SyslogSetup; + +typedef struct ThreadLogFileHashEntry { + uint64_t thread_id; + int slot_number; /* slot identifier -- for plugins */ + bool isopen; + struct LogFileCtx_ *ctx; +} ThreadLogFileHashEntry; + +struct LogFileCtx_; +typedef struct LogThreadedFileCtx_ { + SCMutex mutex; + HashTable *ht; + char *append; +} LogThreadedFileCtx; + +typedef struct LogFilePluginCtx_ { + SCEveFileType *plugin; + void *init_data; + void *thread_data; +} LogFilePluginCtx; + +/** Global structure for Output Context */ +typedef struct LogFileCtx_ { + union { + FILE *fp; +#ifdef HAVE_LIBHIREDIS + void *redis; +#endif + }; + LogThreadedFileCtx *threads; + + union { +#ifdef HAVE_LIBHIREDIS + RedisSetup redis_setup; +#endif + }; + + int (*Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp); + void (*Close)(struct LogFileCtx_ *fp); + + LogFilePluginCtx plugin; + + /** It will be locked if the log/alert + * record cannot be written to the file in one call */ + SCMutex fp_mutex; + + /** When threaded, track of the parent and thread id */ + bool threaded; + struct LogFileCtx_ *parent; + ThreadLogFileHashEntry *entry; + + /** the type of file */ + enum LogFileType type; + + /** The name of the file */ + char *filename; + + /** File permissions */ + uint32_t filemode; + + /** Suricata sensor name */ + char *sensor_name; + + /** Handle auto-connecting / reconnecting sockets */ + int is_sock; + int sock_type; + uint64_t reconn_timer; + + /** The next time to rotate log file, if rotate interval is + specified. */ + time_t rotate_time; + + /** The interval to rotate the log file */ + uint64_t rotate_interval; + + /**< Used by some alert loggers like the unified ones that append + * the date onto the end of files. */ + char *prefix; + size_t prefix_len; + + /** Generic size_limit and size_current + * They must be common to the threads accessing the same file */ + uint64_t size_limit; /**< file size limit */ + uint64_t size_current; /**< file current size */ + + /* flag to avoid multiple threads printing the same stats */ + uint8_t flags; + + /* flags to set when sending over a socket */ + uint8_t send_flags; + + /* Flag if file is a regular file or not. Only regular files + * allow for rotation. */ + uint8_t is_regular; + + /* JSON flags */ + size_t json_flags; /* passed to json_dump_callback() */ + + /* Flag set when file rotation notification is received. */ + int rotation_flag; + + /* if set to true EVE will add a pcap file record */ + bool is_pcap_offline; + + /* Socket types may need to drop events to keep from blocking + * Suricata. */ + uint64_t dropped; + + uint64_t output_errors; +} LogFileCtx; + +/* Min time (msecs) before trying to reconnect a Unix domain socket */ +#define LOGFILE_RECONN_MIN_TIME 500 + +/* flags for LogFileCtx */ +#define LOGFILE_ROTATE_INTERVAL 0x04 + +LogFileCtx *LogFileNewCtx(void); +int LogFileFreeCtx(LogFileCtx *); +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer); + +LogFileCtx *LogFileEnsureExists(LogFileCtx *lf_ctx); +int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *, int); +int SCConfLogReopen(LogFileCtx *); +bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx); + +#endif /* __UTIL_LOGOPENFILE_H__ */ diff --git a/src/util/lua/lua-common.c b/src/util/lua/lua-common.c new file mode 100644 index 000000000000..c693927803a9 --- /dev/null +++ b/src/util/lua/lua-common.c @@ -0,0 +1,1009 @@ +/* Copyright (C) 2014-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Common function for Lua Output + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "../../conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer/http/parser.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" +#include "util/conf.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "action-globals.h" + +int LuaCallbackError(lua_State *luastate, const char *msg) +{ + lua_pushnil(luastate); + lua_pushstring(luastate, msg); + return 2; +} + +const char *LuaGetStringArgument(lua_State *luastate, int argc) +{ + /* get argument */ + if (!lua_isstring(luastate, argc)) + return NULL; + const char *str = lua_tostring(luastate, argc); + if (str == NULL) + return NULL; + if (strlen(str) == 0) + return NULL; + return str; +} + +void LuaPushTableKeyValueInt(lua_State *luastate, const char *key, int value) +{ + lua_pushstring(luastate, key); + lua_pushnumber(luastate, value); + lua_settable(luastate, -3); +} + +/** \brief Push a key plus string value to the stack + * + * If value is NULL, string "(null")" will be put on the stack. + */ +void LuaPushTableKeyValueString(lua_State *luastate, const char *key, const char *value) +{ + lua_pushstring(luastate, key); + lua_pushstring(luastate, value ? value : "(null)"); + lua_settable(luastate, -3); +} + +void LuaPushTableKeyValueArray( + lua_State *luastate, const char *key, const uint8_t *value, size_t len) +{ + lua_pushstring(luastate, key); + LuaPushStringBuffer(luastate, value, len); + lua_settable(luastate, -3); +} + +/** \internal + * \brief fill lua stack with payload + * \param luastate the lua state + * \param p packet + * \retval cnt number of data items placed on the stack + * + * Places: payload (string), open (bool), close (bool), toserver (bool), toclient (bool) + */ +static int LuaCallbackStreamingBufferPushToStack(lua_State *luastate, const LuaStreamingBuffer *b) +{ + // PrintRawDataFp(stdout, (uint8_t *)b->data, b->data_len); + lua_pushlstring(luastate, (const char *)b->data, b->data_len); + lua_pushboolean(luastate, (b->flags & OUTPUT_STREAMING_FLAG_OPEN)); + lua_pushboolean(luastate, (b->flags & OUTPUT_STREAMING_FLAG_CLOSE)); + lua_pushboolean(luastate, (b->flags & OUTPUT_STREAMING_FLAG_TOSERVER)); + lua_pushboolean(luastate, (b->flags & OUTPUT_STREAMING_FLAG_TOCLIENT)); + return 5; +} + +/** \internal + * \brief Wrapper for getting payload into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackStreamingBuffer(lua_State *luastate) +{ + const LuaStreamingBuffer *b = LuaStateGetStreamingBuffer(luastate); + if (b == NULL) + return LuaCallbackError(luastate, "internal error: no buffer"); + + return LuaCallbackStreamingBufferPushToStack(luastate, b); +} + +/** \internal + * \brief fill lua stack with payload + * \param luastate the lua state + * \param p packet + * \retval cnt number of data items placed on the stack + * + * Places: payload (string) + */ +static int LuaCallbackPacketPayloadPushToStackFromPacket(lua_State *luastate, const Packet *p) +{ + lua_pushlstring(luastate, (const char *)p->payload, p->payload_len); + return 1; +} + +/** \internal + * \brief Wrapper for getting payload into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackPacketPayload(lua_State *luastate) +{ + const Packet *p = LuaStateGetPacket(luastate); + if (p == NULL) + return LuaCallbackError(luastate, "internal error: no packet"); + + return LuaCallbackPacketPayloadPushToStackFromPacket(luastate, p); +} + +/** \internal + * \brief fill lua stack with packet timestamp + * \param luastate the lua state + * \param p packet + * \retval cnt number of data items placed on the stack + * + * Places: seconds (number), microseconds (number) + */ +static int LuaCallbackTimestampPushToStack(lua_State *luastate, const SCTime_t ts) +{ + lua_pushnumber(luastate, (double)SCTIME_SECS(ts)); + lua_pushnumber(luastate, (double)SCTIME_USECS(ts)); + return 2; +} + +/** \internal + * \brief fill lua stack with header info + * \param luastate the lua state + * \param p packet + * \retval cnt number of data items placed on the stack + * + * Places: ts (string) + */ +static int LuaCallbackTimeStringPushToStackFromPacket(lua_State *luastate, const Packet *p) +{ + char timebuf[64]; + CreateTimeString(p->ts, timebuf, sizeof(timebuf)); + lua_pushstring(luastate, timebuf); + return 1; +} + +/** \internal + * \brief Wrapper for getting packet timestamp (as numbers) into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackPacketTimestamp(lua_State *luastate) +{ + const Packet *p = LuaStateGetPacket(luastate); + if (p == NULL) + return LuaCallbackError(luastate, "internal error: no packet"); + + return LuaCallbackTimestampPushToStack(luastate, p->ts); +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackPacketTimeString(lua_State *luastate) +{ + const Packet *p = LuaStateGetPacket(luastate); + if (p == NULL) + return LuaCallbackError(luastate, "internal error: no packet"); + + return LuaCallbackTimeStringPushToStackFromPacket(luastate, p); +} + +/** \internal + * \brief fill lua stack with flow timestamps + * \param luastate the lua state + * \param startts timestamp of first packet in the flow + * \param lastts timestamp of last packet in the flow + * \retval cnt number of data items placed on the stack + * + * Places: seconds (number), seconds (number), microseconds (number), + * microseconds (number) + */ +static int LuaCallbackFlowTimestampsPushToStack( + lua_State *luastate, const SCTime_t startts, const SCTime_t lastts) +{ + lua_pushnumber(luastate, (double)SCTIME_SECS(startts)); + lua_pushnumber(luastate, (double)SCTIME_SECS(lastts)); + lua_pushnumber(luastate, (double)SCTIME_USECS(startts)); + lua_pushnumber(luastate, (double)SCTIME_USECS(lastts)); + return 4; +} + +/** \internal + * \brief Wrapper for getting flow timestamp (as numbers) into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowTimestamps(lua_State *luastate) +{ + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) { + return LuaCallbackError(luastate, "internal error: no flow"); + } + + return LuaCallbackFlowTimestampsPushToStack(luastate, flow->startts, flow->lastts); +} + +/** \internal + * \brief fill lua stack with time string + * \param luastate the lua state + * \param flow flow + * \retval cnt number of data items placed on the stack + * + * Places: ts (string) + */ +static int LuaCallbackTimeStringPushToStackFromFlow(lua_State *luastate, const Flow *flow) +{ + char timebuf[64]; + CreateTimeString(flow->startts, timebuf, sizeof(timebuf)); + lua_pushstring(luastate, timebuf); + return 1; +} + +/** \internal + * \brief Wrapper for getting ts info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowTimeString(lua_State *luastate) +{ + int r = 0; + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); + + return r; +} + +/** \internal + * \brief fill lua stack with flow has alerts + * \param luastate the lua state + * \param flow flow + * \retval cnt number of data items placed on the stack + * + * Places alerts (bool) + */ +static int LuaCallbackHasAlertsPushToStackFromFlow(lua_State *luastate, const Flow *flow) +{ + lua_pushboolean(luastate, FlowHasAlerts(flow)); + + return 1; +} + +/** \internal + * \brief Wrapper for getting flow has alerts info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowHasAlerts(lua_State *luastate) +{ + int r = 0; + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackHasAlertsPushToStackFromFlow(luastate, flow); + + return r; +} + +/** \internal + * \brief fill lua stack with header info + * \param luastate the lua state + * \param p packet + * \retval cnt number of data items placed on the stack + * + * Places: ipver (number), src ip (string), dst ip (string), protocol (number), + * sp or icmp type (number), dp or icmp code (number). + */ +static int LuaCallbackTuplePushToStackFromPacket(lua_State *luastate, const Packet *p) +{ + int ipver = 0; + if (PKT_IS_IPV4(p)) { + ipver = 4; + } else if (PKT_IS_IPV6(p)) { + ipver = 6; + } + lua_pushinteger(luastate, ipver); + if (ipver == 0) + return 1; + + char srcip[46] = "", dstip[46] = ""; + if (PKT_IS_IPV4(p)) { + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + } else if (PKT_IS_IPV6(p)) { + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + } + + lua_pushstring(luastate, srcip); + lua_pushstring(luastate, dstip); + + /* proto and ports (or type/code) */ + lua_pushinteger(luastate, p->proto); + if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP) { + lua_pushinteger(luastate, p->sp); + lua_pushinteger(luastate, p->dp); + + } else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) { + lua_pushinteger(luastate, p->icmp_s.type); + lua_pushinteger(luastate, p->icmp_s.code); + } else { + lua_pushinteger(luastate, 0); + lua_pushinteger(luastate, 0); + } + + return 6; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackTuple(lua_State *luastate) +{ + const Packet *p = LuaStateGetPacket(luastate); + if (p == NULL) + return LuaCallbackError(luastate, "internal error: no packet"); + + return LuaCallbackTuplePushToStackFromPacket(luastate, p); +} + +/** \internal + * \brief fill lua stack with header info + * \param luastate the lua state + * \param f flow, locked + * \retval cnt number of data items placed on the stack + * + * Places: ipver (number), src ip (string), dst ip (string), protocol (number), + * sp or icmp type (number), dp or icmp code (number). + */ +static int LuaCallbackTuplePushToStackFromFlow(lua_State *luastate, const Flow *f) +{ + int ipver = 0; + if (FLOW_IS_IPV4(f)) { + ipver = 4; + } else if (FLOW_IS_IPV6(f)) { + ipver = 6; + } + lua_pushinteger(luastate, ipver); + if (ipver == 0) + return 1; + + char srcip[46] = "", dstip[46] = ""; + if (FLOW_IS_IPV4(f)) { + PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), dstip, sizeof(dstip)); + } else if (FLOW_IS_IPV6(f)) { + PrintInet(AF_INET6, (const void *)&(f->src.address), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)&(f->dst.address), dstip, sizeof(dstip)); + } + + lua_pushstring(luastate, srcip); + lua_pushstring(luastate, dstip); + + /* proto and ports (or type/code) */ + lua_pushinteger(luastate, f->proto); + if (f->proto == IPPROTO_TCP || f->proto == IPPROTO_UDP) { + lua_pushinteger(luastate, f->sp); + lua_pushinteger(luastate, f->dp); + + } else if (f->proto == IPPROTO_ICMP || f->proto == IPPROTO_ICMPV6) { + lua_pushinteger(luastate, f->icmp_s.type); + lua_pushinteger(luastate, f->icmp_s.code); + } else { + lua_pushinteger(luastate, 0); + lua_pushinteger(luastate, 0); + } + + return 6; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackTupleFlow(lua_State *luastate) +{ + int r = 0; + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackTuplePushToStackFromFlow(luastate, f); + + return r; +} + +/** \internal + * \brief fill lua stack with AppLayerProto + * \param luastate the lua state + * \param alproto AppProto to push to stack as string + * \retval cnt number of data items placed on the stack + * + * Places: alproto as string (string) + */ +static int LuaCallbackAppLayerProtoPushToStackFromFlow(lua_State *luastate, const AppProto alproto) +{ + const char *string = AppProtoToString(alproto); + if (string == NULL) + string = "unknown"; + lua_pushstring(luastate, string); + return 1; +} + +/** \internal + * \brief Wrapper for getting AppLayerProto info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackAppLayerProtoFlow(lua_State *luastate) +{ + int r = 0; + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto); + r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_ts); + r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_tc); + r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_orig); + r += LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f->alproto_expect); + + return r; +} + +/** \internal + * \brief fill lua stack with flow stats + * \param luastate the lua state + * \param f flow, locked + * \retval cnt number of data items placed on the stack + * + * Places: ts pkts (number), ts bytes (number), tc pkts (number), tc bytes (number) + */ +static int LuaCallbackStatsPushToStackFromFlow(lua_State *luastate, const Flow *f) +{ + lua_pushinteger(luastate, f->todstpktcnt); + lua_pushinteger(luastate, f->todstbytecnt); + lua_pushinteger(luastate, f->tosrcpktcnt); + lua_pushinteger(luastate, f->tosrcbytecnt); + return 4; +} + +/** \internal + * \brief Wrapper for getting AppLayerProto info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackStatsFlow(lua_State *luastate) +{ + int r = 0; + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackStatsPushToStackFromFlow(luastate, f); + + return r; +} + +/** \internal + * \brief fill lua stack with flow id + * \param luastate the lua state + * \param f flow, locked + * \retval cnt number of data items placed on the stack + * + * Places: flow id (number) + */ +static int LuaCallbackPushFlowIdToStackFromFlow(lua_State *luastate, const Flow *f) +{ + int64_t id = FlowGetId(f); + lua_pushinteger(luastate, id); + return 1; +} + +/** \internal + * \brief Wrapper for getting FlowId into lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowId(lua_State *luastate) +{ + int r = 0; + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackPushFlowIdToStackFromFlow(luastate, f); + + return r; +} + +/** \internal + * \brief fill lua stack with signature info + * \param luastate the lua state + * \param s pointer to signature struct + * \retval cnt number of data items placed on the stack + * + * Places: sid (number), rev (number), gid (number) + */ +static int LuaCallbackRuleIdsPushToStackFromSignature(lua_State *luastate, const Signature *s) +{ + lua_pushinteger(luastate, s->id); + lua_pushinteger(luastate, s->rev); + lua_pushinteger(luastate, s->gid); + return 3; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + * + * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) + * otherwise pulled from Signature in lua registry (for match scripts) + */ +static int LuaCallbackRuleIds(lua_State *luastate) +{ + const Signature *s = NULL; + const PacketAlert *pa = LuaStateGetPacketAlert(luastate); + if (pa != NULL) { + s = pa->s; + } else { + s = LuaStateGetSignature(luastate); + if (s == NULL) + return LuaCallbackError(luastate, "internal error: no packet alert or signature"); + } + return LuaCallbackRuleIdsPushToStackFromSignature(luastate, s); +} + +/** \internal + * \brief fill lua stack with signature info + * \param luastate the lua state + * \param s pointer to signature struct + * \retval cnt number of data items placed on the stack + * + * Places: action (string) + */ +static int LuaCallbackRuleActionPushToStackFromSignature(lua_State *luastate, const Signature *s) +{ + const char *action = ""; + if (s->action & ACTION_PASS) { + action = "pass"; + } else if ((s->action & ACTION_REJECT) || (s->action & ACTION_REJECT_BOTH) || + (s->action & ACTION_REJECT_DST)) { + action = "reject"; + } else if (s->action & ACTION_DROP) { + action = "drop"; + } else if (s->action & ACTION_ALERT) { + action = "alert"; + } + lua_pushstring(luastate, action); + return 1; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + * + * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) + * otherwise pulled from Signature in lua registry (for match scripts) + */ +static int LuaCallbackRuleAction(lua_State *luastate) +{ + const Signature *s = NULL; + const PacketAlert *pa = LuaStateGetPacketAlert(luastate); + if (pa != NULL) { + s = pa->s; + } else { + s = LuaStateGetSignature(luastate); + if (s == NULL) + return LuaCallbackError(luastate, "internal error: no packet alert or signature"); + } + return LuaCallbackRuleActionPushToStackFromSignature(luastate, s); +} + +/** \internal + * \brief fill lua stack with signature info + * \param luastate the lua state + * \param s pointer to signature struct + * \retval cnt number of data items placed on the stack + * + * Places: msg (string) + */ +static int LuaCallbackRuleMsgPushToStackFromSignature(lua_State *luastate, const Signature *s) +{ + lua_pushstring(luastate, s->msg); + return 1; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + * + * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) + * otherwise pulled from Signature in lua registry (for match scripts) + */ +static int LuaCallbackRuleMsg(lua_State *luastate) +{ + const Signature *s = NULL; + const PacketAlert *pa = LuaStateGetPacketAlert(luastate); + if (pa != NULL) { + s = pa->s; + } else { + s = LuaStateGetSignature(luastate); + if (s == NULL) + return LuaCallbackError(luastate, "internal error: no packet alert or signature"); + } + return LuaCallbackRuleMsgPushToStackFromSignature(luastate, s); +} + +/** \internal + * \brief fill lua stack with signature info + * \param luastate the lua state + * \param s pointer to signature struct + * \retval cnt number of data items placed on the stack + * + * Places: class (string), prio (number) + */ +static int LuaCallbackRuleClassPushToStackFromSignature(lua_State *luastate, const Signature *s) +{ + lua_pushstring(luastate, s->class_msg); + lua_pushinteger(luastate, s->prio); + return 2; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + * + * Info is pulled from PacketAlert if it exists in lua registry (true for logging scripts) + * otherwise pulled from Signature in lua registry (for match scripts) + */ +static int LuaCallbackRuleClass(lua_State *luastate) +{ + const Signature *s = NULL; + const PacketAlert *pa = LuaStateGetPacketAlert(luastate); + if (pa != NULL) { + s = pa->s; + } else { + s = LuaStateGetSignature(luastate); + if (s == NULL) + return LuaCallbackError(luastate, "internal error: no packet alert or signature"); + } + return LuaCallbackRuleClassPushToStackFromSignature(luastate, s); +} + +static int LuaCallbackLogPath(lua_State *luastate) +{ + const char *ld = ConfigGetLogDirectory(); + if (ld == NULL) + return LuaCallbackError(luastate, "internal error: no log dir"); + + return LuaPushStringBuffer(luastate, (const uint8_t *)ld, strlen(ld)); +} + +static int LuaCallbackLogDebug(lua_State *luastate) +{ + const char *msg = LuaGetStringArgument(luastate, 1); + if (msg == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + SCLogDebug("%s", msg); + return 0; +} + +static int LuaCallbackLogInfo(lua_State *luastate) +{ + const char *msg = LuaGetStringArgument(luastate, 1); + if (msg == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogInfoRaw(ar.short_src, funcname, ar.currentline, "%s", msg); + return 0; +} + +static int LuaCallbackLogNotice(lua_State *luastate) +{ + const char *msg = LuaGetStringArgument(luastate, 1); + if (msg == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogNoticeRaw(ar.short_src, funcname, ar.currentline, "%s", msg); + return 0; +} + +static int LuaCallbackLogWarning(lua_State *luastate) +{ + const char *msg = LuaGetStringArgument(luastate, 1); + if (msg == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogWarningRaw(ar.short_src, funcname, ar.currentline, "%s", msg); + return 0; +} + +static int LuaCallbackLogError(lua_State *luastate) +{ + const char *msg = LuaGetStringArgument(luastate, 1); + if (msg == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogErrorRaw(ar.short_src, funcname, ar.currentline, "%s", msg); + return 0; +} + +/** \internal + * \brief fill lua stack with file info + * \param luastate the lua state + * \param pa pointer to packet alert struct + * \retval cnt number of data items placed on the stack + * + * Places: fileid (number), txid (number), name (string), + * size (number), magic (string), md5 in hex (string), + * sha1 (string), sha256 (string) + */ +static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const File *file) +{ + char *md5ptr = NULL; + char *sha1ptr = NULL; + char *sha256ptr = NULL; + + char md5[33] = ""; + md5ptr = md5; + if (file->flags & FILE_MD5) { + size_t x; + for (x = 0; x < sizeof(file->md5); x++) { + char one[3] = ""; + snprintf(one, sizeof(one), "%02x", file->md5[x]); + strlcat(md5, one, sizeof(md5)); + } + } + char sha1[41] = ""; + sha1ptr = sha1; + if (file->flags & FILE_SHA1) { + size_t x; + for (x = 0; x < sizeof(file->sha1); x++) { + char one[3] = ""; + snprintf(one, sizeof(one), "%02x", file->sha1[x]); + strlcat(sha1, one, sizeof(sha1)); + } + } + char sha256[65] = ""; + sha256ptr = sha256; + if (file->flags & FILE_SHA256) { + size_t x; + for (x = 0; x < sizeof(file->sha256); x++) { + char one[3] = ""; + snprintf(one, sizeof(one), "%02x", file->sha256[x]); + strlcat(sha256, one, sizeof(sha256)); + } + } + + lua_Integer tx_id = LuaStateGetTxId(luastate); + lua_pushinteger(luastate, file->file_store_id); + lua_pushinteger(luastate, tx_id); + lua_pushlstring(luastate, (char *)file->name, file->name_len); + lua_pushinteger(luastate, FileTrackedSize(file)); + lua_pushstring(luastate, +#ifdef HAVE_MAGIC + file->magic +#else + "nomagic" +#endif + ); + lua_pushstring(luastate, md5ptr); + lua_pushstring(luastate, sha1ptr); + lua_pushstring(luastate, sha256ptr); + return 8; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFileInfo(lua_State *luastate) +{ + const File *file = LuaStateGetFile(luastate); + if (file == NULL) + return LuaCallbackError(luastate, "internal error: no file"); + + return LuaCallbackFileInfoPushToStackFromFile(luastate, file); +} + +/** \internal + * \brief fill lua stack with file info + * \param luastate the lua state + * \param pa pointer to packet alert struct + * \retval cnt number of data items placed on the stack + * + * Places: state (string), stored (bool) + */ +static int LuaCallbackFileStatePushToStackFromFile(lua_State *luastate, const File *file) +{ + const char *state = "UNKNOWN"; + switch (file->state) { + case FILE_STATE_CLOSED: + state = "CLOSED"; + break; + case FILE_STATE_TRUNCATED: + state = "TRUNCATED"; + break; + case FILE_STATE_ERROR: + state = "ERROR"; + break; + case FILE_STATE_OPENED: + state = "OPENED"; + break; + case FILE_STATE_NONE: + state = "NONE"; + break; + case FILE_STATE_MAX: + break; + } + + lua_pushstring(luastate, state); + lua_pushboolean(luastate, file->flags & FILE_STORED); + return 2; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFileState(lua_State *luastate) +{ + const File *file = LuaStateGetFile(luastate); + if (file == NULL) + return LuaCallbackError(luastate, "internal error: no file"); + + return LuaCallbackFileStatePushToStackFromFile(luastate, file); +} + +/** \internal + * \brief fill lua stack with thread info + * \param luastate the lua state + * \param pa pointer to packet alert struct + * \retval cnt number of data items placed on the stack + * + * Places: thread id (number), thread name (string, thread group name (string) + */ +static int LuaCallbackThreadInfoPushToStackFromThreadVars(lua_State *luastate, const ThreadVars *tv) +{ + unsigned long tid = SCGetThreadIdLong(); + lua_pushinteger(luastate, (lua_Integer)tid); + lua_pushstring(luastate, tv->name); + lua_pushstring(luastate, tv->thread_group_name); + return 3; +} + +/** \internal + * \brief Wrapper for getting tuple info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackThreadInfo(lua_State *luastate) +{ + const ThreadVars *tv = LuaStateGetThreadVars(luastate); + if (tv == NULL) + return LuaCallbackError(luastate, "internal error: no tv"); + + return LuaCallbackThreadInfoPushToStackFromThreadVars(luastate, tv); +} + +int LuaRegisterFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, LuaCallbackPacketPayload); + lua_setglobal(luastate, "SCPacketPayload"); + lua_pushcfunction(luastate, LuaCallbackPacketTimestamp); + lua_setglobal(luastate, "SCPacketTimestamp"); + lua_pushcfunction(luastate, LuaCallbackPacketTimeString); + lua_setglobal(luastate, "SCPacketTimeString"); + lua_pushcfunction(luastate, LuaCallbackTuple); + lua_setglobal(luastate, "SCPacketTuple"); + + lua_pushcfunction(luastate, LuaCallbackFlowTimestamps); + lua_setglobal(luastate, "SCFlowTimestamps"); + lua_pushcfunction(luastate, LuaCallbackFlowTimeString); + lua_setglobal(luastate, "SCFlowTimeString"); + lua_pushcfunction(luastate, LuaCallbackTupleFlow); + lua_setglobal(luastate, "SCFlowTuple"); + lua_pushcfunction(luastate, LuaCallbackAppLayerProtoFlow); + lua_setglobal(luastate, "SCFlowAppLayerProto"); + lua_pushcfunction(luastate, LuaCallbackStatsFlow); + lua_setglobal(luastate, "SCFlowStats"); + lua_pushcfunction(luastate, LuaCallbackFlowHasAlerts); + lua_setglobal(luastate, "SCFlowHasAlerts"); + lua_pushcfunction(luastate, LuaCallbackFlowId); + lua_setglobal(luastate, "SCFlowId"); + + lua_pushcfunction(luastate, LuaCallbackStreamingBuffer); + lua_setglobal(luastate, "SCStreamingBuffer"); + + lua_pushcfunction(luastate, LuaCallbackLogPath); + lua_setglobal(luastate, "SCLogPath"); + + lua_pushcfunction(luastate, LuaCallbackLogDebug); + lua_setglobal(luastate, "SCLogDebug"); + lua_pushcfunction(luastate, LuaCallbackLogInfo); + lua_setglobal(luastate, "SCLogInfo"); + lua_pushcfunction(luastate, LuaCallbackLogNotice); + lua_setglobal(luastate, "SCLogNotice"); + lua_pushcfunction(luastate, LuaCallbackLogWarning); + lua_setglobal(luastate, "SCLogWarning"); + lua_pushcfunction(luastate, LuaCallbackLogError); + lua_setglobal(luastate, "SCLogError"); + + lua_pushcfunction(luastate, LuaCallbackRuleIds); + lua_setglobal(luastate, "SCRuleIds"); + lua_pushcfunction(luastate, LuaCallbackRuleAction); + lua_setglobal(luastate, "SCRuleAction"); + lua_pushcfunction(luastate, LuaCallbackRuleMsg); + lua_setglobal(luastate, "SCRuleMsg"); + lua_pushcfunction(luastate, LuaCallbackRuleClass); + lua_setglobal(luastate, "SCRuleClass"); + + lua_pushcfunction(luastate, LuaCallbackFileInfo); + lua_setglobal(luastate, "SCFileInfo"); + lua_pushcfunction(luastate, LuaCallbackFileState); + lua_setglobal(luastate, "SCFileState"); + + lua_pushcfunction(luastate, LuaCallbackThreadInfo); + lua_setglobal(luastate, "SCThreadInfo"); + return 0; +} + +int LuaStateNeedProto(lua_State *luastate, AppProto alproto) +{ + AppProto flow_alproto = 0; + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + flow_alproto = flow->alproto; + + return (alproto == flow_alproto); +} + +#endif /* HAVE_LUA */ diff --git a/src/util/lua/lua-common.h b/src/util/lua/lua-common.h new file mode 100644 index 000000000000..ad34530c9bac --- /dev/null +++ b/src/util/lua/lua-common.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_LUA_COMMON_H__ +#define __UTIL_LUA_COMMON_H__ + +#ifdef HAVE_LUA + +int LuaCallbackError(lua_State *luastate, const char *msg); +const char *LuaGetStringArgument(lua_State *luastate, int argc); + +void LuaPushTableKeyValueInt(lua_State *luastate, const char *key, int value); +void LuaPushTableKeyValueString(lua_State *luastate, const char *key, const char *value); +void LuaPushTableKeyValueArray( + lua_State *luastate, const char *key, const uint8_t *value, size_t len); + +int LuaRegisterFunctions(lua_State *luastate); + +int LuaStateNeedProto(lua_State *luastate, AppProto alproto); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_COMMON_H__ */ diff --git a/src/util/lua/lua-ja3.c b/src/util/lua/lua-ja3.c new file mode 100644 index 000000000000..3e0e710ee02c --- /dev/null +++ b/src/util/lua/lua-ja3.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "../../conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer/ssl/parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" +#include "util/lua/lua-common.h" +#include "util/lua/lua-ja3.h" + +static int Ja3GetHash(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol is not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->client_connp.ja3_hash == NULL) + return LuaCallbackError(luastate, "error: no JA3 hash"); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->client_connp.ja3_hash, + strlen(ssl_state->client_connp.ja3_hash)); +} + +static int Ja3GetString(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol is not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->client_connp.ja3_str == NULL || ssl_state->client_connp.ja3_str->data == NULL) + return LuaCallbackError(luastate, "error: no JA3 str"); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->client_connp.ja3_str->data, + ssl_state->client_connp.ja3_str->used); +} + +static int Ja3SGetHash(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol is not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->server_connp.ja3_hash == NULL) + return LuaCallbackError(luastate, "error: no JA3S hash"); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->server_connp.ja3_hash, + strlen(ssl_state->server_connp.ja3_hash)); +} + +static int Ja3SGetString(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol is not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->server_connp.ja3_str == NULL || ssl_state->server_connp.ja3_str->data == NULL) + return LuaCallbackError(luastate, "error: no JA3S str"); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->server_connp.ja3_str->data, + ssl_state->server_connp.ja3_str->used); +} + +/** *\brief Register JA3 Lua extensions */ +int LuaRegisterJa3Functions(lua_State *luastate) +{ + lua_pushcfunction(luastate, Ja3GetHash); + lua_setglobal(luastate, "Ja3GetHash"); + + lua_pushcfunction(luastate, Ja3GetString); + lua_setglobal(luastate, "Ja3GetString"); + + lua_pushcfunction(luastate, Ja3SGetHash); + lua_setglobal(luastate, "Ja3SGetHash"); + + lua_pushcfunction(luastate, Ja3SGetString); + lua_setglobal(luastate, "Ja3SGetString"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-ja3.h b/src/util/lua/lua-ja3.h similarity index 100% rename from src/util-lua-ja3.h rename to src/util/lua/lua-ja3.h diff --git a/src/util/lua/lua.c b/src/util/lua/lua.c new file mode 100644 index 000000000000..097d23b22d0c --- /dev/null +++ b/src/util/lua/lua.c @@ -0,0 +1,356 @@ +/* Copyright (C) 2014-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Common function for Lua + */ + +#include "suricata-common.h" +#include "../../detect.h" +#include "pkt-var.h" +#include "../../conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util/print.h" +#include "util/unittest.h" +#include "util/lua/luajit.h" + +#include "util/debug.h" + +#include "output/output.h" +#include "app-layer/http/parser.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/privs.h" +#include "util/buffer.h" +#include "util/proto-name.h" +#include "util/logopenfile.h" +#include "util/time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util/lua/lua.h" + +lua_State *LuaGetState(void) +{ + lua_State *s = NULL; +#ifdef HAVE_LUAJIT + s = LuajitGetState(); +#else + s = luaL_newstate(); +#endif + return s; +} + +void LuaReturnState(lua_State *s) +{ + if (s != NULL) { + /* clear the stack */ + while (lua_gettop(s) > 0) { + lua_pop(s, 1); + } +#ifdef HAVE_LUAJIT + LuajitReturnState(s); +#else + lua_close(s); +#endif + } +} + +/* key for tv (threadvars) pointer */ +const char lua_ext_key_tv[] = "suricata:lua:tv:ptr"; +/* key for tx pointer */ +const char lua_ext_key_tx[] = "suricata:lua:tx:ptr"; +/* key for tx id */ +const char lua_ext_key_tx_id[] = "suricata:lua:tx_id"; +/* key for p (packet) pointer */ +const char lua_ext_key_p[] = "suricata:lua:pkt:ptr"; +/* key for f (flow) pointer */ +const char lua_ext_key_flow[] = "suricata:lua:flow:ptr"; +/* key for flow lock hint bool */ +const char lua_ext_key_flow_lock_hint[] = "suricata:lua:flow:lock_hint"; +/* key for direction */ +const char lua_ext_key_direction[] = "suricata:lua:direction"; + +/* key for pa (packet alert) pointer */ +const char lua_ext_key_pa[] = "suricata:lua:pkt:alert:ptr"; +/* key for s (signature) pointer */ +const char lua_ext_key_s[] = "suricata:lua:signature:ptr"; +/* key for file pointer */ +const char lua_ext_key_file[] = "suricata:lua:file:ptr"; +/* key for DetectEngineThreadCtx pointer */ +const char lua_ext_key_det_ctx[] = "suricata:lua:det_ctx:ptr"; +/* key for streaming buffer pointer */ +const char lua_ext_key_streaming_buffer[] = "suricata:lua:streaming_buffer:ptr"; + +/** \brief get tv pointer from the lua state */ +ThreadVars *LuaStateGetThreadVars(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tv); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *tv = lua_touserdata(luastate, -1); + return (ThreadVars *)tv; +} + +void LuaStateSetThreadVars(lua_State *luastate, ThreadVars *tv) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tv); + lua_pushlightuserdata(luastate, (void *)tv); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief get packet pointer from the lua state */ +Packet *LuaStateGetPacket(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_p); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *p = lua_touserdata(luastate, -1); + return (Packet *)p; +} + +void LuaStateSetPacket(lua_State *luastate, Packet *p) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_p); + lua_pushlightuserdata(luastate, (void *)p); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief get tx pointer from the lua state */ +void *LuaStateGetTX(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *tx = lua_touserdata(luastate, -1); + return tx; +} + +/** \brief get tx id from the lua state */ +uint64_t LuaStateGetTxId(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx_id); + lua_gettable(luastate, LUA_REGISTRYINDEX); + uint64_t tx_id = lua_tointeger(luastate, -1); + return tx_id; +} +void LuaStateSetTX(lua_State *luastate, void *txptr, const uint64_t tx_id) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx); + lua_pushlightuserdata(luastate, (void *)txptr); + lua_settable(luastate, LUA_REGISTRYINDEX); + + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx_id); + lua_pushinteger(luastate, tx_id); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +Flow *LuaStateGetFlow(lua_State *luastate) +{ + Flow *f = NULL; + + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); + lua_gettable(luastate, LUA_REGISTRYINDEX); + f = lua_touserdata(luastate, -1); + + /* need flow lock hint */ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); + lua_gettable(luastate, LUA_REGISTRYINDEX); + + return f; +} + +void LuaStateSetFlow(lua_State *luastate, Flow *f) +{ + /* flow */ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); + lua_pushlightuserdata(luastate, (void *)f); + lua_settable(luastate, LUA_REGISTRYINDEX); + + /* flow lock status hint */ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); + /* locking is not required, set to 0 for backwards compatibility */ + lua_pushboolean(luastate, 0); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief get packet alert pointer from the lua state */ +PacketAlert *LuaStateGetPacketAlert(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_pa); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *pa = lua_touserdata(luastate, -1); + return (PacketAlert *)pa; +} + +void LuaStateSetPacketAlert(lua_State *luastate, PacketAlert *pa) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_pa); + lua_pushlightuserdata(luastate, (void *)pa); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief get signature pointer from the lua state */ +Signature *LuaStateGetSignature(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_s); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *s = lua_touserdata(luastate, -1); + return (Signature *)s; +} + +void LuaStateSetSignature(lua_State *luastate, const Signature *s) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_s); + lua_pushlightuserdata(luastate, (void *)s); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief get file pointer from the lua state */ +File *LuaStateGetFile(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_file); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *file = lua_touserdata(luastate, -1); + return (File *)file; +} + +void LuaStateSetFile(lua_State *luastate, File *file) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_file); + lua_pushlightuserdata(luastate, (void *)file); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief get DetectEngineThreadCtx pointer from the lua state */ +DetectEngineThreadCtx *LuaStateGetDetCtx(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_det_ctx); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *det_ctx = lua_touserdata(luastate, -1); + return (DetectEngineThreadCtx *)det_ctx; +} + +void LuaStateSetDetCtx(lua_State *luastate, DetectEngineThreadCtx *det_ctx) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_det_ctx); + lua_pushlightuserdata(luastate, (void *)det_ctx); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +LuaStreamingBuffer *LuaStateGetStreamingBuffer(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_streaming_buffer); + lua_gettable(luastate, LUA_REGISTRYINDEX); + void *b = lua_touserdata(luastate, -1); + return (LuaStreamingBuffer *)b; +} + +void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_streaming_buffer); + lua_pushlightuserdata(luastate, (void *)b); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief get packet pointer from the lua state */ +int LuaStateGetDirection(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); + lua_gettable(luastate, LUA_REGISTRYINDEX); + int dir = lua_toboolean(luastate, -1); + return dir; +} + +void LuaStateSetDirection(lua_State *luastate, int direction) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); + lua_pushboolean(luastate, direction); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + +/** \brief dump stack from lua state to screen */ +void LuaPrintStack(lua_State *state) +{ + int size = lua_gettop(state); + int i; + + for (i = 1; i <= size; i++) { + int type = lua_type(state, i); + printf("Stack size=%d, level=%d, type=%d, ", size, i, type); + + switch (type) { + case LUA_TFUNCTION: + printf("function %s", lua_tostring(state, i) ? "true" : "false"); + break; + case LUA_TBOOLEAN: + printf("bool %s", lua_toboolean(state, i) ? "true" : "false"); + break; + case LUA_TNUMBER: + printf("number %g", lua_tonumber(state, i)); + break; + case LUA_TSTRING: + printf("string `%s'", lua_tostring(state, i)); + break; + case LUA_TTABLE: + printf("table `%s'", lua_tostring(state, i)); + break; + default: + printf("other %s", lua_typename(state, type)); + break; + } + printf("\n"); + } +} + +int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len) +{ + if (input_len % 4 != 0) { + /* we're using a buffer sized at a multiple of 4 as lua_pushlstring generates + * invalid read errors in valgrind otherwise. Adding in a nul to be sure. + * + * Buffer size = len + 1 (for nul) + whatever makes it a multiple of 4 */ + size_t buflen = input_len + 1 + ((input_len + 1) % 4); + uint8_t buf[buflen]; + memset(buf, 0x00, buflen); + memcpy(buf, input, input_len); + buf[input_len] = '\0'; + + /* return value through luastate, as a luastring */ + lua_pushlstring(luastate, (char *)buf, input_len); + } else { + lua_pushlstring(luastate, (char *)input, input_len); + } + return 1; +} + +int LuaPushInteger(lua_State *luastate, lua_Integer n) +{ + lua_pushinteger(luastate, n); + return 1; +} + +#endif /* HAVE_LUA */ diff --git a/src/util/lua/lua.h b/src/util/lua/lua.h new file mode 100644 index 000000000000..5c5e19bb639e --- /dev/null +++ b/src/util/lua/lua.h @@ -0,0 +1,108 @@ +/* Copyright (C) 2014-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_LUA_H__ +#define __UTIL_LUA_H__ + +#ifndef HAVE_LUA + +/* If we don't have Lua, create a typedef for lua_State so the + * exported Lua functions don't fail the build. */ +typedef void lua_State; + +#else +#include "threadvars.h" +#include "../../detect.h" + +typedef struct LuaStreamingBuffer_ { + const uint8_t *data; + uint32_t data_len; + uint8_t flags; +} LuaStreamingBuffer; + +lua_State *LuaGetState(void); +void LuaReturnState(lua_State *s); + +/* gets */ + +/** \brief get tv pointer from the lua state */ +ThreadVars *LuaStateGetThreadVars(lua_State *luastate); + +Packet *LuaStateGetPacket(lua_State *luastate); +void *LuaStateGetTX(lua_State *luastate); +uint64_t LuaStateGetTxId(lua_State *luastate); + +/** \brief get flow pointer from lua state + * + * \retval f flow pointer or NULL if it was not set + */ +Flow *LuaStateGetFlow(lua_State *luastate); + +PacketAlert *LuaStateGetPacketAlert(lua_State *luastate); + +Signature *LuaStateGetSignature(lua_State *luastate); + +/** \brief get file pointer from the lua state */ +File *LuaStateGetFile(lua_State *luastate); + +/** \brief get detect engine thread context pointer from the lua state */ +DetectEngineThreadCtx *LuaStateGetDetCtx(lua_State *luastate); + +LuaStreamingBuffer *LuaStateGetStreamingBuffer(lua_State *luastate); + +int LuaStateGetDirection(lua_State *luastate); + +/* sets */ + +void LuaStateSetPacket(lua_State *luastate, Packet *p); +void LuaStateSetTX(lua_State *luastate, void *tx, const uint64_t tx_id); + +/** \brief set a flow pointer in the lua state + * + * \param f flow pointer + */ +void LuaStateSetFlow(lua_State *luastate, Flow *f); + +void LuaStateSetPacketAlert(lua_State *luastate, PacketAlert *pa); + +void LuaStateSetSignature(lua_State *luastate, const Signature *s); + +void LuaStateSetFile(lua_State *luastate, File *file); + +void LuaStateSetDetCtx(lua_State *luastate, DetectEngineThreadCtx *det_ctx); + +void LuaStateSetThreadVars(lua_State *luastate, ThreadVars *tv); + +void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b); + +void LuaStateSetDirection(lua_State *luastate, int direction); + +void LuaPrintStack(lua_State *state); + +int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len); + +int LuaPushInteger(lua_State *luastate, lua_Integer n); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_H__ */ diff --git a/src/util/lua/luajit.c b/src/util/lua/luajit.c new file mode 100644 index 000000000000..8a7d531923f2 --- /dev/null +++ b/src/util/lua/luajit.c @@ -0,0 +1,157 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" + +#ifdef HAVE_LUAJIT +#include "../../conf.h" +#include "util/pool.h" +#include "util/lua/lua.h" +#include "util/lua/luajit.h" + +/** \brief lua_State pool + * + * Lua requires states to be alloc'd in memory <2GB. For this reason we + * prealloc the states early during engine startup so we have a better chance + * of getting the states. We protect the pool with a lock as the detect + * threads access it during their init and cleanup. + * + * Pool size is automagically determined based on number of keyword occurrences, + * cpus/cores and rule reloads being enabled or not. + * + * Alternatively, the "detect-engine.luajit-states" var can be set. + */ +static Pool *luajit_states = NULL; +static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; +static int luajit_states_cnt = 0; +static int luajit_states_cnt_max = 0; +static int luajit_states_size = 0; +#define LUAJIT_DEFAULT_STATES 128 + +static void *LuaStatePoolAlloc(void) +{ + return luaL_newstate(); +} + +static void LuaStatePoolFree(void *d) +{ + lua_State *s = (lua_State *)d; + if (s != NULL) + lua_close(s); +} + +/** \brief Populate lua states pool + * + * \param num keyword instances + * \param reloads bool indicating we have rule reloads enabled + */ +int LuajitSetupStatesPool(void) +{ + int retval = 0; + pthread_mutex_lock(&luajit_states_lock); + + if (luajit_states == NULL) { + intmax_t cnt = 0; + if (ConfGetInt("luajit.states", &cnt) != 1) { + ConfNode *denode = NULL; + ConfNode *decnf = ConfGetNode("detect-engine"); + if (decnf != NULL) { + TAILQ_FOREACH (denode, &decnf->head, next) { + if (denode->val && strcmp(denode->val, "luajit-states") == 0) { + ConfGetChildValueInt(denode, "luajit-states", &cnt); + } + } + } + } + if (cnt == 0) { + cnt = LUAJIT_DEFAULT_STATES; + } + luajit_states_size = cnt; + + luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); + if (luajit_states == NULL) { + SCLogError("luastate pool init failed, lua/luajit keywords won't work"); + retval = -1; + } + + if (retval == 0) { + SCLogConfig("luajit states preallocated: %d", luajit_states_size); + } + } + + pthread_mutex_unlock(&luajit_states_lock); + return retval; +} + +void LuajitFreeStatesPool(void) +{ + pthread_mutex_lock(&luajit_states_lock); + if (luajit_states_cnt_max > luajit_states_size) { + SCLogNotice("luajit states used %d is bigger than pool size %d. Set " + "luajit.states to %d to avoid memory issues. " + "See tickets #1577 and #1955.", + luajit_states_cnt_max, luajit_states_size, luajit_states_cnt_max); + } + PoolFree(luajit_states); + luajit_states = NULL; + luajit_states_size = 0; + luajit_states_cnt = 0; + pthread_mutex_unlock(&luajit_states_lock); +} + +lua_State *LuajitGetState(void) +{ + lua_State *s = NULL; + pthread_mutex_lock(&luajit_states_lock); + if (luajit_states != NULL) { + s = (lua_State *)PoolGet(luajit_states); + if (s != NULL) { + if (luajit_states_cnt == luajit_states_size) { + SCLogWarning("luajit states pool size %d " + "reached. Increase luajit.states config option. " + "See tickets #1577 and #1955", + luajit_states_size); + } + + luajit_states_cnt++; + if (luajit_states_cnt > luajit_states_cnt_max) + luajit_states_cnt_max = luajit_states_cnt; + } + } + pthread_mutex_unlock(&luajit_states_lock); + return s; +} + +void LuajitReturnState(lua_State *s) +{ + if (s != NULL) { + pthread_mutex_lock(&luajit_states_lock); + PoolReturn(luajit_states, (void *)s); + BUG_ON(luajit_states_cnt <= 0); + luajit_states_cnt--; + pthread_mutex_unlock(&luajit_states_lock); + } +} + +#endif /* HAVE_LUAJIT */ diff --git a/src/util/lua/luajit.h b/src/util/lua/luajit.h new file mode 100644 index 000000000000..4a64ad2bb04e --- /dev/null +++ b/src/util/lua/luajit.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_LUAJIT_H__ +#define __UTIL_LUAJIT_H__ + +#ifdef HAVE_LUAJIT + +#include "util/lua/lua.h" + +int LuajitSetupStatesPool(void); +void LuajitFreeStatesPool(void); +lua_State *LuajitGetState(void); +void LuajitReturnState(lua_State *s); + +#endif /* HAVE_LUAJIT */ + +#endif /* __UTIL_LUAJIT_H__ */ diff --git a/src/util/macset.c b/src/util/macset.c new file mode 100644 index 000000000000..a1ac0f176915 --- /dev/null +++ b/src/util/macset.c @@ -0,0 +1,429 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + * + * Set-like data store for MAC addresses. Implemented as array for memory + * locality reasons as the expected number of items is typically low. + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "flow-util.h" +#include "flow-private.h" +#include "flow-storage.h" +#include "util/macset.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +typedef uint8_t MacAddr[6]; +typedef enum { + EMPTY_SET, /* no address inserted yet */ + SINGLE_MAC, /* we have a single pair of addresses (likely) */ + MULTI_MAC /* we have multiple addresses per flow */ +} MacSetState; + +struct MacSet_ { + /* static store for a single MAC address per side */ + MacAddr singles[2]; + /* state determines how addresses are stored per side: + - SINGLE_MAC uses static locations allocated with the MacSet + itself to store a single address (most likely case) + - MULTI_MAC is used when more than one distinct address + is detected (causes another allocation and linear-time add) */ + MacSetState state[2]; + /* buffer for multiple MACs per flow and direction */ + MacAddr *buf[2]; + int size, last[2]; +}; + +FlowStorageId g_macset_storage_id = { .id = -1 }; + +void MacSetRegisterFlowStorage(void) +{ + ConfNode *root = ConfGetNode("outputs"); + ConfNode *node = NULL; + /* we only need to register if at least one enabled 'eve-log' output + has the ethernet setting enabled */ + if (root != NULL) { + TAILQ_FOREACH (node, &root->head, next) { + if (node->val && strcmp(node->val, "eve-log") == 0) { + const char *enabled = ConfNodeLookupChildValue(node->head.tqh_first, "enabled"); + if (enabled != NULL && ConfValIsTrue(enabled)) { + const char *ethernet = + ConfNodeLookupChildValue(node->head.tqh_first, "ethernet"); + if (ethernet != NULL && ConfValIsTrue(ethernet)) { + g_macset_storage_id = FlowStorageRegister( + "macset", sizeof(void *), NULL, (void (*)(void *))MacSetFree); + return; + } + } + } + } + } +} + +bool MacSetFlowStorageEnabled(void) +{ + return (g_macset_storage_id.id != -1); +} + +MacSet *MacSetInit(int size) +{ + MacSet *ms = NULL; + if (!FLOW_CHECK_MEMCAP(sizeof(*ms))) { + return NULL; + } + ms = SCCalloc(1, sizeof(*ms)); + if (unlikely(ms == NULL)) { + SCLogError("Unable to allocate MacSet memory"); + return NULL; + } + (void)SC_ATOMIC_ADD(flow_memuse, (sizeof(*ms))); + ms->state[MAC_SET_SRC] = ms->state[MAC_SET_DST] = EMPTY_SET; + if (size < 3) { + /* we want to make sure we have at space for at least 3 items to + fit MACs during the initial extension to MULTI_MAC storage */ + size = 3; + } + ms->size = size; + ms->last[MAC_SET_SRC] = ms->last[MAC_SET_DST] = 0; + return ms; +} + +FlowStorageId MacSetGetFlowStorageID(void) +{ + return g_macset_storage_id; +} + +static inline void MacUpdateEntry(MacSet *ms, uint8_t *addr, int side, ThreadVars *tv, uint16_t ctr) +{ + switch (ms->state[side]) { + case EMPTY_SET: + memcpy(ms->singles[side], addr, sizeof(MacAddr)); + ms->state[side] = SINGLE_MAC; + if (tv != NULL) + StatsSetUI64(tv, ctr, 1); + break; + case SINGLE_MAC: + if (unlikely(memcmp(addr, ms->singles[side], sizeof(MacAddr)) != 0)) { + if (ms->buf[side] == NULL) { + if (!FLOW_CHECK_MEMCAP(ms->size * sizeof(MacAddr))) { + /* in this case there is not much we can do */ + return; + } + ms->buf[side] = SCCalloc(ms->size, sizeof(MacAddr)); + if (unlikely(ms->buf[side] == NULL)) { + SCLogError("Unable to allocate " + "MacSet memory"); + return; + } + (void)SC_ATOMIC_ADD(flow_memuse, (ms->size * sizeof(MacAddr))); + } + memcpy(ms->buf[side], ms->singles[side], sizeof(MacAddr)); + memcpy(ms->buf[side] + 1, addr, sizeof(MacAddr)); + ms->last[side] = 2; + if (tv != NULL) + StatsSetUI64(tv, ctr, 2); + ms->state[side] = MULTI_MAC; + } + break; + case MULTI_MAC: + if (unlikely(ms->last[side] == ms->size)) { + /* MacSet full, ignore item. We intentionally do not output + any warning in order not to stall packet processing */ + return; + } + /* If the set is non-empty... */ + if (ms->last[side] > 0) { + /* ...we search for duplicates in the set to decide whether + we need to insert the current item. We do this backwards, + since we expect the latest item to match more likely than + the first */ + for (int i = ms->last[side] - 1; i >= 0; i--) { + uint8_t *addr2 = (uint8_t *)((ms->buf[side]) + i); + /* If we find a match, we return early with no action */ + if (likely(memcmp(addr2, addr, sizeof(MacAddr)) == 0)) { + return; + } + } + } + /* Otherwise, we insert the new address at the end */ + memcpy(ms->buf[side] + ms->last[side], addr, sizeof(MacAddr)); + ms->last[side]++; + if (tv != NULL) + StatsSetUI64(tv, ctr, ms->last[side]); + break; + } +} + +void MacSetAddWithCtr(MacSet *ms, uint8_t *src_addr, uint8_t *dst_addr, ThreadVars *tv, + uint16_t ctr_src, uint16_t ctr_dst) +{ + if (ms == NULL) + return; + MacUpdateEntry(ms, src_addr, MAC_SET_SRC, tv, ctr_src); + MacUpdateEntry(ms, dst_addr, MAC_SET_DST, tv, ctr_dst); +} + +void MacSetAdd(MacSet *ms, uint8_t *src_addr, uint8_t *dst_addr) +{ + MacSetAddWithCtr(ms, src_addr, dst_addr, NULL, 0, 0); +} + +static inline int MacSetIterateSide( + const MacSet *ms, MacSetIteratorFunc IterFunc, MacSetSide side, void *data) +{ + int ret = 0; + switch (ms->state[side]) { + case EMPTY_SET: + return 0; + case SINGLE_MAC: + ret = IterFunc((uint8_t *)ms->singles[side], side, data); + if (unlikely(ret != 0)) { + return ret; + } + break; + case MULTI_MAC: + for (int i = 0; i < ms->last[side]; i++) { + ret = IterFunc((uint8_t *)ms->buf[side][i], side, data); + if (unlikely(ret != 0)) { + return ret; + } + } + break; + } + return 0; +} + +int MacSetForEach(const MacSet *ms, MacSetIteratorFunc IterFunc, void *data) +{ + int ret = 0; + if (ms == NULL) + return 0; + + ret = MacSetIterateSide(ms, IterFunc, MAC_SET_SRC, data); + if (ret != 0) { + return ret; + } + return MacSetIterateSide(ms, IterFunc, MAC_SET_DST, data); +} + +int MacSetSize(const MacSet *ms) +{ + int size = 0; + if (ms == NULL) + return 0; + + switch (ms->state[MAC_SET_SRC]) { + case EMPTY_SET: + /* pass */ + break; + case SINGLE_MAC: + size += 1; + break; + case MULTI_MAC: + size += ms->last[MAC_SET_SRC]; + break; + } + switch (ms->state[MAC_SET_DST]) { + case EMPTY_SET: + /* pass */ + break; + case SINGLE_MAC: + size += 1; + break; + case MULTI_MAC: + size += ms->last[MAC_SET_DST]; + break; + } + return size; +} + +void MacSetFree(MacSet *ms) +{ + size_t total_free = 0; + if (ms == NULL) + return; + if (ms->buf[MAC_SET_SRC] != NULL) { + SCFree(ms->buf[MAC_SET_SRC]); + total_free += ms->size * sizeof(MacAddr); + } + if (ms->buf[MAC_SET_DST] != NULL) { + SCFree(ms->buf[MAC_SET_DST]); + total_free += ms->size * sizeof(MacAddr); + } + SCFree(ms); + total_free += sizeof(*ms); + (void)SC_ATOMIC_SUB(flow_memuse, total_free); +} + +#ifdef UNITTESTS + +static int CheckTest1Membership(uint8_t *addr, MacSetSide side, void *data) +{ + int *i = (int *)data; + switch (*i) { + case 0: + if (addr[5] != 1) + return 1; + break; + case 1: + if (addr[5] != 2) + return 1; + break; + case 2: + if (addr[5] != 3) + return 1; + break; + } + (*i)++; + return 0; +} + +static int MacSetTest01(void) +{ + MacSet *ms = NULL; + int ret = 0, i = 0; + MacAddr addr1 = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 }, addr2 = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 }, + addr3 = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x3 }; + SC_ATOMIC_SET(flow_config.memcap, 10000); + + ms = MacSetInit(10); + FAIL_IF_NULL(ms); + FAIL_IF_NOT(MacSetSize(ms) == 0); + + ret = MacSetForEach(ms, CheckTest1Membership, &i); + FAIL_IF_NOT(ret == 0); + + MacSetAdd(ms, addr1, addr2); + FAIL_IF_NOT(MacSetSize(ms) == 2); + + ret = MacSetForEach(ms, CheckTest1Membership, &i); + FAIL_IF_NOT(ret == 0); + + MacSetAdd(ms, addr1, addr3); + FAIL_IF_NOT(MacSetSize(ms) == 3); + + i = 0; + ret = MacSetForEach(ms, CheckTest1Membership, &i); + FAIL_IF_NOT(ret == 0); + + MacSetFree(ms); + PASS; +} + +static int MacSetTest02(void) +{ + MacSet *ms = NULL; + int ret = 0, i = 0; + SC_ATOMIC_SET(flow_config.memcap, 10000); + + ms = MacSetInit(10); + FAIL_IF_NULL(ms); + FAIL_IF_NOT(MacSetSize(ms) == 0); + + for (i = 1; i < 100; i++) { + MacAddr addr1 = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 }, addr2 = { 0x1, 0x0, 0x0, 0x0, 0x0, 0x2 }; + MacSetAdd(ms, addr1, addr2); + } + FAIL_IF_NOT(MacSetSize(ms) == 2); + + ret = MacSetForEach(ms, CheckTest1Membership, &i); + FAIL_IF_NOT(ret == 0); + + MacSetFree(ms); + PASS; +} + +static int MacSetTest03(void) +{ + MacSet *ms = NULL; + SC_ATOMIC_SET(flow_config.memcap, 10000); + + ms = MacSetInit(10); + FAIL_IF_NULL(ms); + FAIL_IF_NOT(MacSetSize(ms) == 0); + + for (uint8_t i = 1; i < 100; i++) { + MacAddr addr1 = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 }, addr2 = { 0x1, 0x0, 0x0, 0x0, 0x0, 0x1 }; + addr1[5] = i; + addr2[5] = i; + MacSetAdd(ms, addr1, addr2); + } + FAIL_IF_NOT(MacSetSize(ms) == 20); + + MacSetFree(ms); + PASS; +} + +static int MacSetTest04(void) +{ + MacSet *ms = NULL; + SC_ATOMIC_SET(flow_config.memcap, 2); + + ms = MacSetInit(10); + FAIL_IF_NOT_NULL(ms); + + PASS; +} + +static int MacSetTest05(void) +{ + MacSet *ms = NULL; + int ret = 0; + SC_ATOMIC_SET(flow_config.memcap, 64); + + ms = MacSetInit(10); + FAIL_IF_NULL(ms); + FAIL_IF_NOT(MacSetSize(ms) == 0); + + for (uint8_t i = 1; i < 100; i++) { + MacAddr addr1 = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 }, addr2 = { 0x1, 0x0, 0x0, 0x0, 0x0, 0x1 }; + addr1[5] = i; + addr2[5] = i; + MacSetAdd(ms, addr1, addr2); + } + FAIL_IF_NOT(MacSetSize(ms) == 2); + + int i2 = 100; + ret = MacSetForEach(ms, CheckTest1Membership, &i2); + FAIL_IF_NOT(ret == 0); + + MacSetFree(ms); + PASS; +} + +#endif /* UNITTESTS */ + +void MacSetRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("MacSetTest01", MacSetTest01); + UtRegisterTest("MacSetTest02", MacSetTest02); + UtRegisterTest("MacSetTest03", MacSetTest03); + UtRegisterTest("MacSetTest04", MacSetTest04); + UtRegisterTest("MacSetTest05", MacSetTest05); +#endif + + return; +} diff --git a/src/util/macset.h b/src/util/macset.h new file mode 100644 index 000000000000..02ba51a3f67a --- /dev/null +++ b/src/util/macset.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Sascha Steinbiss + */ + +#ifndef __UTIL_MACSET_H__ +#define __UTIL_MACSET_H__ + +typedef struct MacSet_ MacSet; +typedef enum { MAC_SET_SRC = 0, MAC_SET_DST } MacSetSide; + +typedef int (*MacSetIteratorFunc)(uint8_t *addr, MacSetSide side, void *); + +MacSet *MacSetInit(int size); +void MacSetAdd(MacSet *, uint8_t *src_addr, uint8_t *dst_addr); +void MacSetAddWithCtr(MacSet *, uint8_t *src_addr, uint8_t *dst_addr, ThreadVars *tv, + uint16_t ctr_src, uint16_t ctr_dst); +int MacSetForEach(const MacSet *, MacSetIteratorFunc, void *); +int MacSetSize(const MacSet *); +void MacSetReset(MacSet *); +void MacSetFree(MacSet *); +void MacSetRegisterFlowStorage(void); +FlowStorageId MacSetGetFlowStorageID(void); +bool MacSetFlowStorageEnabled(void); +void MacSetRegisterTests(void); + +#endif /* __UTIL_MACSET_H__ */ diff --git a/src/util/magic.c b/src/util/magic.c new file mode 100644 index 000000000000..9e7975fae0d2 --- /dev/null +++ b/src/util/magic.c @@ -0,0 +1,889 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Wrappers and tests for libmagic usage. + * + * Libmagic's API is not thread safe. The data the pointer returned by + * magic_buffer is overwritten by the next magic_buffer call. This is + * why we need to lock calls and copy the returned string. + */ + +#include "suricata-common.h" +#include "../conf.h" +#include "util/unittest.h" +#include "util/magic.h" +#include "util/debug.h" + +#ifdef HAVE_MAGIC + +/** + * \brief Initialize a "magic" context. + */ +magic_t MagicInitContext(void) +{ + magic_t ctx; + const char *filename = NULL; + FILE *fd = NULL; + + ctx = magic_open(0); + if (ctx == NULL) { + SCLogError("magic_open failed: %s", magic_error(ctx)); + goto error; + } + + (void)ConfGet("magic-file", &filename); + + if (filename != NULL) { + if (strlen(filename) == 0) { + /* set filename to NULL on *nix systems so magic_load uses system + * default path (see man libmagic) */ + SCLogConfig("using system default magic-file"); + filename = NULL; + } else { + SCLogConfig("using magic-file %s", filename); + + if ((fd = fopen(filename, "r")) == NULL) { + SCLogWarning("Error opening file: \"%s\": %s", filename, strerror(errno)); + goto error; + } + fclose(fd); + } + } + + if (magic_load(ctx, filename) != 0) { + SCLogError("magic_load failed: %s", magic_error(ctx)); + goto error; + } + return ctx; + +error: + if (ctx != NULL) { + magic_close(ctx); + ctx = NULL; + } + return NULL; +} + +void MagicDeinitContext(magic_t ctx) +{ + if (ctx != NULL) + magic_close(ctx); +} + +/** + * \brief Find the magic value for a buffer. + * + * \param buf the buffer + * \param buflen length of the buffer + * + * \retval result pointer to null terminated string + */ +char *MagicThreadLookup(magic_t *ctx, const uint8_t *buf, uint32_t buflen) +{ + const char *result = NULL; + char *magic = NULL; + + if (buf != NULL && buflen > 0) { + result = magic_buffer(*ctx, (void *)buf, (size_t)buflen); + if (result != NULL) { + magic = SCStrdup(result); + if (unlikely(magic == NULL)) { + SCLogError("Unable to dup magic"); + } + } + } + + SCReturnPtr(magic, "const char"); +} + +#ifdef UNITTESTS + +#if defined OS_FREEBSD || defined OS_DARWIN +#define MICROSOFT_OFFICE_DOC "OLE 2 Compound Document" +#else +#define MICROSOFT_OFFICE_DOC "Microsoft Office Document" +#endif + +/** \test magic lib calls -- init */ +static int MagicInitTest01(void) +{ + int result = 0; + magic_t magic_ctx; + + magic_ctx = magic_open(0); + if (magic_ctx == NULL) { + printf("failure retrieving magic_ctx\n"); + return 0; + } + + if (magic_load(magic_ctx, NULL) == -1) { + printf("failure magic_load\n"); + goto end; + } + + result = 1; +end: + magic_close(magic_ctx); + return result; +} + +/** \test magic lib calls -- lookup */ +static int MagicDetectTest01(void) +{ + magic_t magic_ctx; + char *result = NULL; + char buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a }; + size_t buffer_len = sizeof(buffer); + int retval = 0; + + magic_ctx = magic_open(0); + if (magic_ctx == NULL) { + printf("failure retrieving magic_ctx\n"); + return 0; + } + + if (magic_load(magic_ctx, NULL) == -1) { + printf("magic_load failure\n"); + goto end; + } + + result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); + if (result == NULL || strncmp(result, "PDF document", 12) != 0) { + printf("result %p:%s, not \"PDF document\": ", result, result ? result : "(null)"); + goto end; + } + + retval = 1; +end: + magic_close(magic_ctx); + return retval; +} +#if 0 +/** \test magic lib calls -- lookup */ +static int MagicDetectTest02(void) +{ + magic_t magic_ctx; + char *result = NULL; + + char buffer[] = { + 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0xfe, 0xff, 0x09, 0x00, + + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, + + 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; + size_t buffer_len = sizeof(buffer); + int retval = 0; + + magic_ctx = magic_open(0); + if (magic_ctx == NULL) { + printf("failure retrieving magic_ctx\n"); + return 0; + } + + if (magic_load(magic_ctx, NULL) == -1) { + printf("magic_load failure\n"); + goto end; + } + + result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); + if (result == NULL || strcmp(result, MICROSOFT_OFFICE_DOC) != 0) { + printf("result %p:%s, not \"Microsoft Office Document\": ", result,result?result:"(null)"); + goto end; + } + + retval = 1; +end: + magic_close(magic_ctx); + return retval; +} +#endif +/** \test magic lib calls -- lookup */ +static int MagicDetectTest03(void) +{ + char buffer[] = { + 0x50, + 0x4b, + 0x03, + 0x04, + 0x14, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0b, + 0x55, + 0x2a, + 0x36, + 0x5e, + 0xc6, + 0x32, + 0x0c, + 0x27, + 0x00, + 0x00, + 0x00, + 0x27, + 0x00, + 0x00, + 0x00, + 0x08, + 0x00, + 0x00, + 0x00, + 0x6d, + 0x69, + + 0x6d, + 0x65, + 0x74, + 0x79, + 0x70, + 0x65, + 0x61, + 0x70, + 0x70, + 0x6c, + 0x69, + 0x63, + 0x61, + 0x74, + 0x69, + 0x6f, + 0x6e, + 0x2f, + 0x76, + 0x6e, + 0x64, + 0x2e, + 0x6f, + 0x61, + 0x73, + 0x69, + 0x73, + 0x2e, + 0x6f, + 0x70, + 0x65, + 0x6e, + + 0x64, + 0x6f, + 0x63, + 0x75, + 0x6d, + 0x65, + 0x6e, + 0x74, + 0x2e, + 0x74, + 0x65, + 0x78, + 0x74, + 0x50, + 0x4b, + 0x03, + 0x04, + 0x14, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0b, + 0x55, + 0x2a, + 0x36, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x1a, + 0x00, + 0x00, + 0x00, + 0x43, + 0x6f, + 0x6e, + 0x66, + 0x69, + 0x67, + 0x75, + 0x72, + 0x61, + 0x74, + 0x69, + 0x6f, + 0x6e, + 0x73, + 0x32, + 0x2f, + 0x73, + 0x74, + 0x61, + 0x74, + 0x75, + + 0x73, + 0x62, + 0x61, + 0x72, + 0x2f, + 0x50, + 0x4b, + 0x03, + 0x04, + 0x14, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x0b, + }; + size_t buffer_len = sizeof(buffer); + + magic_t magic_ctx = magic_open(0); + FAIL_IF_NULL(magic_ctx); + + FAIL_IF(magic_load(magic_ctx, NULL) == -1); + + char *result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); + FAIL_IF_NULL(result); + + char *str = strstr(result, "OpenDocument Text"); + FAIL_IF_NULL(str); + + magic_close(magic_ctx); + PASS; +} + +/** \test magic lib calls -- lookup */ +static int MagicDetectTest04(void) +{ + magic_t magic_ctx; + char *result = NULL; + + char buffer[] = { + 0x50, + 0x4b, + 0x03, + 0x04, + 0x14, + 0x00, + 0x00, + 0x08, + 0x00, + 0x00, + 0x52, + 0x7b, + 0x86, + 0x3c, + 0x8b, + 0x70, + 0x96, + 0x08, + 0x1c, + 0x00, + 0x00, + 0x00, + 0x1c, + 0x00, + 0x00, + 0x00, + 0x08, + 0x00, + 0x00, + 0x00, + 0x6d, + 0x69, + + 0x6d, + 0x65, + 0x74, + 0x79, + 0x70, + 0x65, + 0x61, + 0x70, + 0x70, + 0x6c, + 0x69, + 0x63, + 0x61, + 0x74, + 0x69, + 0x6f, + 0x6e, + 0x2f, + 0x76, + 0x6e, + 0x64, + 0x2e, + 0x73, + 0x75, + 0x6e, + 0x2e, + 0x78, + 0x6d, + 0x6c, + 0x2e, + 0x62, + 0x61, + + 0x73, + 0x65, + 0x50, + 0x4b, + 0x03, + 0x04, + 0x14, + 0x00, + 0x00, + 0x08, + 0x00, + 0x00, + 0x52, + 0x7b, + 0x86, + 0x3c, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x09, + 0x00, + 0x00, + 0x00, + + 0x4d, + 0x45, + 0x54, + 0x41, + 0x2d, + 0x49, + 0x4e, + 0x46, + 0x2f, + 0x50, + 0x4b, + 0x03, + 0x04, + 0x14, + 0x00, + 0x00, + 0x08, + 0x08, + 0x00, + 0xa8, + 0x42, + 0x1d, + 0x37, + 0x5d, + 0xa7, + 0xb2, + 0xc1, + 0xde, + 0x01, + 0x00, + 0x00, + 0x7e, + + 0x04, + 0x00, + 0x00, + 0x0b, + 0x00, + 0x00, + 0x00, + 0x63, + 0x6f, + 0x6e, + 0x74, + 0x65, + 0x6e, + 0x74, + 0x2e, + 0x78, + 0x6d, + 0x6c, + 0x95, + 0x54, + 0x4d, + 0x6f, + 0xdb, + 0x30, + 0x0c, + 0xbd, + 0xe7, + 0x57, + 0x18, + 0x02, + 0x06, + 0x6c, + + 0x07, + 0xc5, + 0xe9, + 0xb6, + 0xc3, + 0x22, + 0xc4, + 0x29, + 0x86, + 0x7d, + 0x00, + 0x05, + 0x8a, + 0x9d, + 0xb2, + 0x43, + 0x8f, + 0xb2, + 0x24, + 0xa7, + 0xc2, + 0x64, + 0xc9, + 0x15, + }; + size_t buffer_len = sizeof(buffer); + int retval = 0; + + magic_ctx = magic_open(0); + if (magic_ctx == NULL) { + printf("failure retrieving magic_ctx\n"); + return 0; + } + + if (magic_load(magic_ctx, NULL) == -1) { + printf("magic_load failure\n"); + goto end; + } + + result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); + if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { + printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result, result ? result : "(null)"); + goto end; + } + + retval = 1; +end: + magic_close(magic_ctx); + return retval; +} + +/** \test magic api calls -- lookup */ +static int MagicDetectTest05(void) +{ + const char *result = NULL; + magic_t ctx = NULL; + uint8_t buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a }; + size_t buffer_len = sizeof(buffer); + int retval = 0; + + ctx = MagicInitContext(); + FAIL_IF(ctx == NULL); + + result = MagicThreadLookup(&ctx, buffer, buffer_len); + if (result == NULL || strncmp(result, "PDF document", 12) != 0) { + printf("result %p:%s, not \"PDF document\": ", result, result ? result : "(null)"); + goto end; + } + + retval = 1; +end: + MagicDeinitContext(ctx); + return retval; +} + +#if 0 +/** \test magic api calls -- lookup */ +static int MagicDetectTest06(void) +{ + const char *result = NULL; + // clang-format off + uint8_t buffer[] = { + 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0xfe, 0xff, 0x09, 0x00, + + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, + + 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x97, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; + // clang-format on + size_t buffer_len = sizeof(buffer); + int retval = 0; + + if (MagicInit() < 0) { + printf("MagicInit() failure\n"); + return 0; + } + + result = MagicGlobalLookup(buffer, buffer_len); + if (result == NULL || strcmp(result, MICROSOFT_OFFICE_DOC) != 0) { + printf("result %p:%s, not \"Microsoft Office Document\": ", result,result?result:"(null)"); + goto end; + } + + retval = 1; + +end: + MagicDeinit(); + return retval; +} +#endif +/** \test magic api calls -- lookup */ +static int MagicDetectTest07(void) +{ + const char *result = NULL; + magic_t ctx = NULL; + // clang-format off + uint8_t buffer[] = { + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6, + 0x32, 0x0c, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, + + 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, + 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x2e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x4b, 0x03, + 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x55, 0x2a, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, + 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, + + 0x73, 0x62, 0x61, 0x72, 0x2f, 0x50, 0x4b, 0x03, + 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, + }; + // clang-format on + size_t buffer_len = sizeof(buffer); + + ctx = MagicInitContext(); + FAIL_IF(ctx == NULL); + + result = MagicThreadLookup(&ctx, buffer, buffer_len); + FAIL_IF_NULL(result); + + char *str = strstr(result, "OpenDocument Text"); + FAIL_IF_NULL(str); + + MagicDeinitContext(ctx); + PASS; +} + +/** \test magic api calls -- lookup */ +static int MagicDetectTest08(void) +{ + const char *result = NULL; + magic_t ctx = NULL; + // clang-format off + uint8_t buffer[] = { + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, 0x8b, 0x70, + 0x96, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6d, 0x69, + + 0x6d, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, + 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x62, 0x61, + + 0x73, 0x65, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x52, 0x7b, 0x86, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + + 0x4d, 0x45, 0x54, 0x41, 0x2d, 0x49, 0x4e, 0x46, + 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, + 0x08, 0x08, 0x00, 0xa8, 0x42, 0x1d, 0x37, 0x5d, + 0xa7, 0xb2, 0xc1, 0xde, 0x01, 0x00, 0x00, 0x7e, + + 0x04, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x78, + 0x6d, 0x6c, 0x95, 0x54, 0x4d, 0x6f, 0xdb, 0x30, + + 0x0c, 0xbd, 0xe7, 0x57, 0x18, 0x02, 0x06, 0x6c, + 0x07, 0xc5, 0xe9, 0xb6, 0xc3, 0x22, 0xc4, 0x29, + 0x86, 0x7d, 0x00, 0x05, 0x8a, 0x9d, 0xb2, 0x43, + 0x8f, 0xb2, 0x24, 0xa7, 0xc2, 0x64, 0xc9, 0x15, + }; + // clang-format on + size_t buffer_len = sizeof(buffer); + int retval = 0; + + ctx = MagicInitContext(); + FAIL_IF(ctx == NULL); + + result = MagicThreadLookup(&ctx, buffer, buffer_len); + if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { + printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result, result ? result : "(null)"); + goto end; + } + + retval = 1; +end: + MagicDeinitContext(ctx); + return retval; +} +#if 0 +/** \test magic api calls -- make sure memory is shared */ +static int MagicDetectTest09(void) +{ + const char *result1 = NULL; + const char *result2 = NULL; + uint8_t buffer[] = { 0x25, 'P', 'D', 'F', '-', '1', '.', '3', 0x0d, 0x0a}; + size_t buffer_len = sizeof(buffer); + int retval = 0; + + if (MagicInit() < 0) { + printf("MagicInit() failure\n"); + return 0; + } + + result1 = MagicGlobalLookup(buffer, buffer_len); + if (result1 == NULL || strncmp(result1, "PDF document", 12) != 0) { + printf("result %p:%s, not \"PDF document\": ", result1,result1?result1:"(null)"); + goto end; + } + + result2 = MagicGlobalLookup(buffer, buffer_len); + if (result2 == NULL || strncmp(result2, "PDF document", 12) != 0) { + printf("result %p:%s, not \"PDF document\": ", result2,result2?result2:"(null)"); + goto end; + } + + if (result1 != result2) { + printf("pointers not equal, weird... %p != %p: ", result1, result2); + goto end; + } + + retval = 1; +end: + MagicDeinit(); + return retval; +} +#endif +/** \test results in valgrind warning about invalid read, tested with + * file 5.09 and 5.11 */ +static int MagicDetectTest10ValgrindError(void) +{ + const char *result = NULL; + magic_t ctx = NULL; + // clang-format off + uint8_t buffer[] = { + 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2C, + 0x01,0x2C,0x00,0x00,0xFF,0xFE,0x00,0x4C,0x53,0x69,0x67,0x6E,0x61,0x74,0x75,0x72, + 0x65,0x3A,0x34,0x31,0x31,0x65,0x33,0x38,0x61,0x61,0x61,0x31,0x37,0x65,0x33,0x30, + 0x66,0x30,0x32,0x38,0x62,0x61,0x30,0x31,0x36,0x32,0x36,0x37,0x66,0x66,0x30,0x31, + 0x36,0x36,0x61,0x65,0x35,0x39,0x65,0x38,0x31,0x39,0x62,0x61,0x32,0x34,0x63,0x39, + 0x62,0x31,0x33,0x37,0x33,0x62,0x31,0x61,0x35,0x61,0x38,0x65,0x64,0x63,0x36,0x30, + 0x65,0x37,0xFF,0xE2,0x02,0x2C,0x49,0x43,0x43,0x5F,0x50,0x52,0x4F,0x46,0x49,0x4C, + 0x45,0x00,0x01,0x01,0x00,0x00,0x02,0x1C,0x41,0x44,0x42,0x45,0x02,0x10,0x00,0x00, + 0x6D,0x6E,0x74,0x72,0x52,0x47,0x42,0x20,0x58,0x59,0x5A,0x20,0x07,0xCF,0x00,0x05, + 0x00,0x09,0x00,0x15,0x00,0x0B,0x00,0x21,0x61,0x63,0x73,0x70,0x41,0x50,0x50,0x4C, + 0x00,0x00,0x00,0x00,0x6E,0x6F,0x6E,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + }; + // clang-format on + size_t buffer_len = sizeof(buffer); + int retval = 0; + + ctx = MagicInitContext(); + FAIL_IF(ctx == NULL); + + result = MagicThreadLookup(&ctx, buffer, buffer_len); + if (result == NULL || strncmp(result, "JPEG", 4) != 0) { + printf("result %p:%s, not \"JPEG\": ", result, result ? result : "(null)"); + goto end; + } + + retval = 1; +end: + MagicDeinitContext(ctx); + return retval; +} + +#endif /* UNITTESTS */ +#endif + +void MagicRegisterTests(void) +{ +#ifdef HAVE_MAGIC +#ifdef UNITTESTS + UtRegisterTest("MagicInitTest01", MagicInitTest01); + UtRegisterTest("MagicDetectTest01", MagicDetectTest01); + // UtRegisterTest("MagicDetectTest02", MagicDetectTest02, 1); + UtRegisterTest("MagicDetectTest03", MagicDetectTest03); + UtRegisterTest("MagicDetectTest04", MagicDetectTest04); + UtRegisterTest("MagicDetectTest05", MagicDetectTest05); + // UtRegisterTest("MagicDetectTest06", MagicDetectTest06, 1); + UtRegisterTest("MagicDetectTest07", MagicDetectTest07); + UtRegisterTest("MagicDetectTest08", MagicDetectTest08); + /* fails in valgrind, somehow it returns different pointers then. + UtRegisterTest("MagicDetectTest09", MagicDetectTest09, 1); */ + + UtRegisterTest("MagicDetectTest10ValgrindError", MagicDetectTest10ValgrindError); +#endif /* UNITTESTS */ +#endif /* HAVE_MAGIC */ +} diff --git a/src/util-magic.h b/src/util/magic.h similarity index 100% rename from src/util-magic.h rename to src/util/magic.h diff --git a/src/util/mem.c b/src/util/mem.c new file mode 100644 index 000000000000..8fba1faf1551 --- /dev/null +++ b/src/util/mem.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util/atomic.h" +#include "util/debug.h" + +#if defined(_WIN32) || defined(__WIN32) +#include +#endif + +SC_ATOMIC_EXTERN(unsigned int, engine_stage); + +void *SCMallocFunc(const size_t sz) +{ + void *ptrmem = malloc(sz); + if (unlikely(ptrmem == NULL)) { + if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { + uintmax_t scmalloc_size_ = (uintmax_t)sz; + SCLogError("SCMalloc failed: %s, while trying " + "to allocate %" PRIuMAX " bytes", + strerror(errno), scmalloc_size_); + FatalError("Out of memory. The engine cannot be initialized. Exiting..."); + } + } + return ptrmem; +} + +void *SCReallocFunc(void *ptr, const size_t size) +{ + void *ptrmem = realloc(ptr, size); + if (unlikely(ptrmem == NULL)) { + if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { + SCLogError("SCRealloc failed: %s, while trying " + "to allocate %" PRIuMAX " bytes", + strerror(errno), (uintmax_t)size); + FatalError("Out of memory. The engine cannot be initialized. Exiting..."); + } + } + return ptrmem; +} + +void *SCCallocFunc(const size_t nm, const size_t sz) +{ + void *ptrmem = calloc(nm, sz); + if (unlikely(ptrmem == NULL)) { + if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { + SCLogError("SCCalloc failed: %s, while trying " + "to allocate %" PRIuMAX " bytes", + strerror(errno), (uintmax_t)nm * sz); + FatalError("Out of memory. The engine cannot be initialized. Exiting..."); + } + } + return ptrmem; +} + +char *SCStrdupFunc(const char *s) +{ + char *ptrmem = strdup(s); + if (unlikely(ptrmem == NULL)) { + if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { + size_t _scstrdup_len = strlen(s); + SCLogError("SCStrdup failed: %s, while trying " + "to allocate %" PRIuMAX " bytes", + strerror(errno), (uintmax_t)_scstrdup_len); + FatalError("Out of memory. The engine cannot be initialized. Exiting..."); + } + } + return ptrmem; +} + +char *SCStrndupFunc(const char *s, size_t n) +{ +#ifdef HAVE_STRNDUP + char *ptrmem = strndup(s, n); +#else + const size_t sz = n + 1; + char *ptrmem = (char *)malloc(sz); + if (likely(ptrmem != NULL)) { + strlcpy(ptrmem, s, sz); + } +#endif + if (unlikely(ptrmem == NULL)) { + if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { + SCLogError("SCStrndup failed: %s, while trying " + "to allocate %" PRIuMAX " bytes", + strerror(errno), (uintmax_t)(n + 1)); + FatalError("Out of memory. The engine cannot be initialized. Exiting..."); + } + } + return ptrmem; +} + +void *SCMallocAlignedFunc(const size_t size, const size_t align) +{ +#if defined(__WIN32) || defined(_WIN32) + void *ptrmem = _mm_malloc(size, align); + if (unlikely(ptrmem == NULL)) { + if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { + SCLogError("SCMallocAligned(posix_memalign) failed: %s, while trying " + "to allocate %" PRIuMAX " bytes, alignment %" PRIuMAX, + strerror(errno), (uintmax_t)size, (uintmax_t)align); + FatalError("Out of memory. The engine cannot be initialized. Exiting..."); + } + } +#else + void *ptrmem = NULL; + int r = posix_memalign(&ptrmem, align, size); + if (unlikely(r != 0 || ptrmem == NULL)) { + if (ptrmem != NULL) { + free(ptrmem); + ptrmem = NULL; + } + if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) { + SCLogError("SCMallocAligned(posix_memalign) failed: %s, while trying " + "to allocate %" PRIuMAX " bytes, alignment %" PRIuMAX, + strerror(errno), (uintmax_t)size, (uintmax_t)align); + FatalError("Out of memory. The engine cannot be initialized. Exiting..."); + } + } +#endif + return ptrmem; +} + +void SCFreeAlignedFunc(void *ptr) +{ +#if defined(__WIN32) || defined(_WIN32) + _mm_free(ptr); +#else + free(ptr); +#endif +} diff --git a/src/util/mem.h b/src/util/mem.h new file mode 100644 index 000000000000..b106aa496f9f --- /dev/null +++ b/src/util/mem.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * \author Bill Meeks + * + * Utility Macros for memory management + * + * \todo Add wrappers for functions that allocate/free memory here. + * Currently we have malloc, calloc, realloc, strdup, strndup and + * free, but there are more. + */ + +#ifndef __UTIL_MEM_H__ +#define __UTIL_MEM_H__ + +#if CPPCHECK == 1 || defined(__clang_analyzer__) +#define SCMalloc malloc +#define SCCalloc calloc +#define SCRealloc realloc +#define SCFree free +#define SCStrdup strdup +#define SCStrndup strndup +#define SCMallocAligned _mm_malloc +#define SCFreeAligned _mm_free +#else /* CPPCHECK */ + +void *SCMallocFunc(const size_t sz); +#define SCMalloc(sz) SCMallocFunc((sz)) + +void *SCReallocFunc(void *ptr, const size_t size); +#define SCRealloc(ptr, sz) SCReallocFunc((ptr), (sz)) + +void *SCCallocFunc(const size_t nm, const size_t sz); +#define SCCalloc(nm, sz) SCCallocFunc((nm), (sz)) + +char *SCStrdupFunc(const char *s); +#define SCStrdup(s) SCStrdupFunc((s)) + +char *SCStrndupFunc(const char *s, size_t n); +#define SCStrndup(s, n) SCStrndupFunc((s), (n)) + +#define SCFree(p) free((p)) + +/** \brief wrapper for allocing aligned mem + * \param a size + * \param b alignment + */ +void *SCMallocAlignedFunc(const size_t size, const size_t align); +#define SCMallocAligned(size, align) SCMallocAlignedFunc((size), (align)) + +/** \brief Free aligned memory + * + * Not needed for mem alloc'd by posix_memalign, + * but for possible future use of _mm_malloc needing + * _mm_free. + */ +void SCFreeAlignedFunc(void *ptr); +#define SCFreeAligned(p) SCFreeAlignedFunc((p)) + +#endif /* CPPCHECK */ + +#endif /* __UTIL_MEM_H__ */ diff --git a/src/util/memcmp.c b/src/util/memcmp.c new file mode 100644 index 000000000000..7e45db53d639 --- /dev/null +++ b/src/util/memcmp.c @@ -0,0 +1,448 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Memcmp implementations. + */ + +#include "suricata-common.h" +#include "util/memcmp.h" +#include "util/unittest.h" + +/* code is implemented in util-memcmp.h as it's all inlined */ + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "util/debug.h" + +static int MemcmpTest01(void) +{ + uint8_t a[] = "abcd"; + uint8_t b[] = "abcd"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); + PASS; +} + +static int MemcmpTest02(void) +{ + uint8_t a[] = "abcdabcdabcdabcd"; + uint8_t b[] = "abcdabcdabcdabcd"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); + PASS; +} + +static int MemcmpTest03(void) +{ + uint8_t a[] = "abcdabcd"; + uint8_t b[] = "abcdabcd"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); + PASS; +} + +static int MemcmpTest04(void) +{ + uint8_t a[] = "abcd"; + uint8_t b[] = "abcD"; + + int r = SCMemcmp(a, b, sizeof(a) - 1); + FAIL_IF(r != 1); + + PASS; +} + +static int MemcmpTest05(void) +{ + uint8_t a[] = "abcdabcdabcdabcd"; + uint8_t b[] = "abcDabcdabcdabcd"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); + PASS; +} + +static int MemcmpTest06(void) +{ + uint8_t a[] = "abcdabcd"; + uint8_t b[] = "abcDabcd"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); + PASS; +} + +static int MemcmpTest07(void) +{ + uint8_t a[] = "abcd"; + uint8_t b[] = "abcde"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); + PASS; +} + +static int MemcmpTest08(void) +{ + uint8_t a[] = "abcdabcdabcdabcd"; + uint8_t b[] = "abcdabcdabcdabcde"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); + PASS; +} + +static int MemcmpTest09(void) +{ + uint8_t a[] = "abcdabcd"; + uint8_t b[] = "abcdabcde"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 0); + PASS; +} + +static int MemcmpTest10(void) +{ + uint8_t a[] = "abcd"; + uint8_t b[] = "Zbcde"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); + PASS; +} + +static int MemcmpTest11(void) +{ + uint8_t a[] = "abcdabcdabcdabcd"; + uint8_t b[] = "Zbcdabcdabcdabcde"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); + PASS; +} + +static int MemcmpTest12(void) +{ + uint8_t a[] = "abcdabcd"; + uint8_t b[] = "Zbcdabcde"; + + FAIL_IF(SCMemcmp(a, b, sizeof(a) - 1) != 1); + PASS; +} + +static int MemcmpTest13(void) +{ + uint8_t a[] = "abcdefgh"; + uint8_t b[] = "AbCdEfGhIjK"; + + FAIL_IF(SCMemcmpLowercase(a, b, sizeof(a) - 1) != 0); + PASS; +} + +#include "util/cpu.h" + +#define TEST_RUNS 1000000 + +static int MemcmpTest14(void) +{ +#ifdef PROFILING + uint64_t ticks_start = 0; + uint64_t ticks_end = 0; + const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + + int t = 0; + int i, j; + int r1 = 0; + + printf("\n"); + + ticks_start = UtilCpuGetTicks(); + for (t = 0; t < TEST_RUNS; t++) { + for (i = 0; a[i] != NULL; i++) { + // printf("a[%d] = %s\n", i, a[i]); + size_t alen = strlen(a[i]) - 1; + + for (j = 0; b[j] != NULL; j++) { + // printf("b[%d] = %s\n", j, b[j]); + size_t blen = strlen(b[j]) - 1; + + r1 += (memcmp((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen) ? 1 + : 0); + } + } + } + ticks_end = UtilCpuGetTicks(); + printf("memcmp(%d) \t\t\t%" PRIu64 "\n", TEST_RUNS, + ((uint64_t)(ticks_end - ticks_start)) / TEST_RUNS); + SCLogInfo("ticks passed %" PRIu64, ticks_end - ticks_start); + + printf("r1 %d\n", r1); + FAIL_IF(r1 != (51 * TEST_RUNS)); +#endif + PASS; +} + +static int MemcmpTest15(void) +{ +#ifdef PROFILING + uint64_t ticks_start = 0; + uint64_t ticks_end = 0; + const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + + int t = 0; + int i, j; + int r2 = 0; + + printf("\n"); + + ticks_start = UtilCpuGetTicks(); + for (t = 0; t < TEST_RUNS; t++) { + for (i = 0; a[i] != NULL; i++) { + // printf("a[%d] = %s\n", i, a[i]); + size_t alen = strlen(a[i]) - 1; + + for (j = 0; b[j] != NULL; j++) { + // printf("b[%d] = %s\n", j, b[j]); + size_t blen = strlen(b[j]) - 1; + + r2 += MemcmpLowercase( + (uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); + } + } + } + ticks_end = UtilCpuGetTicks(); + printf("MemcmpLowercase(%d) \t\t%" PRIu64 "\n", TEST_RUNS, + ((uint64_t)(ticks_end - ticks_start)) / TEST_RUNS); + SCLogInfo("ticks passed %" PRIu64, ticks_end - ticks_start); + + printf("r2 %d\n", r2); + FAIL_IF(r2 != (51 * TEST_RUNS)); +#endif + PASS; +} + +static int MemcmpTest16(void) +{ +#ifdef PROFILING + uint64_t ticks_start = 0; + uint64_t ticks_end = 0; + const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + + int t = 0; + int i, j; + int r3 = 0; + + printf("\n"); + + ticks_start = UtilCpuGetTicks(); + for (t = 0; t < TEST_RUNS; t++) { + for (i = 0; a[i] != NULL; i++) { + // printf("a[%d] = %s\n", i, a[i]); + size_t alen = strlen(a[i]) - 1; + + for (j = 0; b[j] != NULL; j++) { + // printf("b[%d] = %s\n", j, b[j]); + size_t blen = strlen(b[j]) - 1; + + r3 += SCMemcmp((uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); + } + } + } + ticks_end = UtilCpuGetTicks(); + printf("SCMemcmp(%d) \t\t\t%" PRIu64 "\n", TEST_RUNS, + ((uint64_t)(ticks_end - ticks_start)) / TEST_RUNS); + SCLogInfo("ticks passed %" PRIu64, ticks_end - ticks_start); + + printf("r3 %d\n", r3); + FAIL_IF(r3 != (51 * TEST_RUNS)); +#endif + PASS; +} + +static int MemcmpTest17(void) +{ +#ifdef PROFILING + uint64_t ticks_start = 0; + uint64_t ticks_end = 0; + const char *a[] = { "0123456789012345", "abc", "abcdefghij", "suricata", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + const char *b[] = { "1234567890123456", "abc", "abcdefghik", "suricatb", "test", "xyz", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr", + "abcdefghijklmnopqrstuvwxyz", NULL }; + + int t = 0; + int i, j; + int r4 = 0; + + printf("\n"); + + ticks_start = UtilCpuGetTicks(); + for (t = 0; t < TEST_RUNS; t++) { + for (i = 0; a[i] != NULL; i++) { + // printf("a[%d] = %s\n", i, a[i]); + size_t alen = strlen(a[i]) - 1; + + for (j = 0; b[j] != NULL; j++) { + // printf("b[%d] = %s\n", j, b[j]); + size_t blen = strlen(b[j]) - 1; + + r4 += SCMemcmpLowercase( + (uint8_t *)a[i], (uint8_t *)b[j], (alen < blen) ? alen : blen); + } + } + } + ticks_end = UtilCpuGetTicks(); + printf("SCMemcmpLowercase(%d) \t\t%" PRIu64 "\n", TEST_RUNS, + ((uint64_t)(ticks_end - ticks_start)) / TEST_RUNS); + SCLogInfo("ticks passed %" PRIu64, ticks_end - ticks_start); + + printf("r4 %d\n", r4); + FAIL_IF(r4 != (51 * TEST_RUNS)); +#endif + PASS; +} + +struct MemcmpTest18Tests { + const char *a; + const char *b; + int result; +} memcmp_tests18_tests[] = { + { + "abcdefgh", + "!bcdefgh", + 1, + }, + { + "?bcdefgh", + "!bcdefgh", + 1, + }, + { + "!bcdefgh", + "abcdefgh", + 1, + }, + { + "!bcdefgh", + "?bcdefgh", + 1, + }, + { + "zbcdefgh", + "bbcdefgh", + 1, + }, + + { + "abcdefgh12345678", + "!bcdefgh12345678", + 1, + }, + { + "?bcdefgh12345678", + "!bcdefgh12345678", + 1, + }, + { + "!bcdefgh12345678", + "abcdefgh12345678", + 1, + }, + { + "!bcdefgh12345678", + "?bcdefgh12345678", + 1, + }, + { + "bbcdefgh12345678", + "zbcdefgh12345678", + 1, + }, + + { + "abcdefgh", + "abcdefgh", + 0, + }, + { + "abcdefgh", + "Abcdefgh", + 0, + }, + { + "abcdefgh12345678", + "Abcdefgh12345678", + 0, + }, + + { NULL, NULL, 0 }, + +}; + +static int MemcmpTest18(void) +{ + struct MemcmpTest18Tests *t = memcmp_tests18_tests; + + while (t && t->a != NULL) { + + FAIL_IF(SCMemcmpLowercase(t->a, t->b, strlen(t->a) - 1) != t->result); + t++; + } + + PASS; +} + +#endif /* UNITTESTS */ + +void MemcmpRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MemcmpTest01", MemcmpTest01); + UtRegisterTest("MemcmpTest02", MemcmpTest02); + UtRegisterTest("MemcmpTest03", MemcmpTest03); + UtRegisterTest("MemcmpTest04", MemcmpTest04); + UtRegisterTest("MemcmpTest05", MemcmpTest05); + UtRegisterTest("MemcmpTest06", MemcmpTest06); + UtRegisterTest("MemcmpTest07", MemcmpTest07); + UtRegisterTest("MemcmpTest08", MemcmpTest08); + UtRegisterTest("MemcmpTest09", MemcmpTest09); + UtRegisterTest("MemcmpTest10", MemcmpTest10); + UtRegisterTest("MemcmpTest11", MemcmpTest11); + UtRegisterTest("MemcmpTest12", MemcmpTest12); + UtRegisterTest("MemcmpTest13", MemcmpTest13); + UtRegisterTest("MemcmpTest14", MemcmpTest14); + UtRegisterTest("MemcmpTest15", MemcmpTest15); + UtRegisterTest("MemcmpTest16", MemcmpTest16); + UtRegisterTest("MemcmpTest17", MemcmpTest17); + UtRegisterTest("MemcmpTest18", MemcmpTest18); +#endif /* UNITTESTS */ +} diff --git a/src/util/memcmp.h b/src/util/memcmp.h new file mode 100644 index 000000000000..df65f2b3aaf0 --- /dev/null +++ b/src/util/memcmp.h @@ -0,0 +1,324 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Memcmp implementations for SSE3, SSE4.1, SSE4.2. + * + * Both SCMemcmp and SCMemcmpLowercase return 0 on a exact match, + * 1 on a failed match. + */ + +#ifndef __UTIL_MEMCMP_H__ +#define __UTIL_MEMCMP_H__ + +#include "suricata-common.h" +#include "util/optimize.h" + +/** \brief compare two patterns, converting the 2nd to lowercase + * \warning *ONLY* the 2nd pattern is converted to lowercase + */ +static inline int SCMemcmpLowercase(const void *, const void *, size_t); + +void MemcmpRegisterTests(void); + +static inline int MemcmpLowercase(const void *s1, const void *s2, size_t n) +{ + for (size_t i = 0; i < n; i++) { + if (((uint8_t *)s1)[i] != u8_tolower(((uint8_t *)s2)[i])) + return 1; + } + + return 0; +} + +#if defined(__SSE4_2__) +#include +#define SCMEMCMP_BYTES 16 + +static inline int SCMemcmp(const void *s1, const void *s2, size_t n) +{ + int r = 0; + /* counter for how far we already matched in the buffer */ + size_t m = 0; + do { + if (likely(n - m < SCMEMCMP_BYTES)) { + return memcmp(s1, s2, n - m) ? 1 : 0; + } + + /* load the buffers into the 128bit vars */ + __m128i b1 = _mm_loadu_si128((const __m128i *)s1); + __m128i b2 = _mm_loadu_si128((const __m128i *)s2); + + /* do the actual compare: _mm_cmpestri() returns the number of matching bytes */ + r = _mm_cmpestri(b1, SCMEMCMP_BYTES, b2, SCMEMCMP_BYTES, + _SIDD_CMP_EQUAL_EACH | _SIDD_MASKED_NEGATIVE_POLARITY); + m += r; + s1 += SCMEMCMP_BYTES; + s2 += SCMEMCMP_BYTES; + } while (r == SCMEMCMP_BYTES); + + return ((m == n) ? 0 : 1); +} + +/* Range of values of uppercase characters. We only use the first 2 bytes. */ +static char scmemcmp_uppercase[16] __attribute__((aligned(16))) = { + 'A', + 'Z', + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +/** \brief compare two buffers in a case insensitive way + * \param s1 buffer already in lowercase + * \param s2 buffer with mixed upper and lowercase + */ +static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t n) +{ + /* counter for how far we already matched in the buffer */ + size_t m = 0; + int r = 0; + __m128i ucase = _mm_load_si128((const __m128i *)scmemcmp_uppercase); + __m128i uplow = _mm_set1_epi8(0x20); + + do { + const size_t len = n - m; + if (likely(len < SCMEMCMP_BYTES)) { + return MemcmpLowercase(s1, s2, len); + } + + __m128i b1 = _mm_loadu_si128((const __m128i *)s1); + __m128i b2 = _mm_loadu_si128((const __m128i *)s2); + /* The first step is creating a mask that is FF for all uppercase + * characters, 00 for all others */ + __m128i mask = _mm_cmpestrm(ucase, 2, b2, len, _SIDD_CMP_RANGES | _SIDD_UNIT_MASK); + /* Next we use that mask to create a new: this one has 0x20 for + * the uppercase chars, 00 for all other. */ + mask = _mm_and_si128(uplow, mask); + /* finally, merge the mask and the buffer converting the + * uppercase to lowercase */ + b2 = _mm_add_epi8(b2, mask); + + /* search using our converted buffer, return number of matching bytes */ + r = _mm_cmpestri(b1, SCMEMCMP_BYTES, b2, SCMEMCMP_BYTES, + _SIDD_CMP_EQUAL_EACH | _SIDD_MASKED_NEGATIVE_POLARITY); + m += r; + s1 += SCMEMCMP_BYTES; + s2 += SCMEMCMP_BYTES; + } while (r == SCMEMCMP_BYTES); + + return ((m == n) ? 0 : 1); +} + +#elif defined(__SSE4_1__) +#include +#define SCMEMCMP_BYTES 16 + +static inline int SCMemcmp(const void *s1, const void *s2, size_t len) +{ + size_t offset = 0; + do { + if (likely(len - offset < SCMEMCMP_BYTES)) { + return memcmp(s1, s2, len - offset) ? 1 : 0; + } + + /* unaligned loads */ + __m128i b1 = _mm_loadu_si128((const __m128i *)s1); + __m128i b2 = _mm_loadu_si128((const __m128i *)s2); + __m128i c = _mm_cmpeq_epi8(b1, b2); + + if (_mm_movemask_epi8(c) != 0x0000FFFF) { + return 1; + } + + offset += SCMEMCMP_BYTES; + s1 += SCMEMCMP_BYTES; + s2 += SCMEMCMP_BYTES; + } while (len > offset); + + return 0; +} + +#define UPPER_LOW 0x40 /* "A" - 1 */ +#define UPPER_HIGH 0x5B /* "Z" + 1 */ + +static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) +{ + size_t offset = 0; + __m128i b1, b2, mask1, mask2, upper1, upper2, uplow; + + /* setup registers for upper to lower conversion */ + upper1 = _mm_set1_epi8(UPPER_LOW); + upper2 = _mm_set1_epi8(UPPER_HIGH); + uplow = _mm_set1_epi8(0x20); + + do { + if (likely(len - offset < SCMEMCMP_BYTES)) { + return MemcmpLowercase(s1, s2, len - offset); + } + + /* unaligned loading of the bytes to compare */ + b1 = _mm_loadu_si128((const __m128i *)s1); + b2 = _mm_loadu_si128((const __m128i *)s2); + + /* mark all chars bigger than upper1 */ + mask1 = _mm_cmpgt_epi8(b2, upper1); + /* mark all chars lower than upper2 */ + mask2 = _mm_cmplt_epi8(b2, upper2); + /* merge the two, leaving only those that are true in both */ + mask1 = _mm_cmpeq_epi8(mask1, mask2); + /* Next we use that mask to create a new: this one has 0x20 for + * the uppercase chars, 00 for all other. */ + mask1 = _mm_and_si128(uplow, mask1); + /* add to b2, converting uppercase to lowercase */ + b2 = _mm_add_epi8(b2, mask1); + /* now all is lowercase, let's do the actual compare (reuse mask1 reg) */ + mask1 = _mm_cmpeq_epi8(b1, b2); + + if (_mm_movemask_epi8(mask1) != 0x0000FFFF) { + return 1; + } + + offset += SCMEMCMP_BYTES; + s1 += SCMEMCMP_BYTES; + s2 += SCMEMCMP_BYTES; + } while (len > offset); + + return 0; +} + +#elif defined(__SSE3__) +#include /* for SSE3 */ +#define SCMEMCMP_BYTES 16 + +static inline int SCMemcmp(const void *s1, const void *s2, size_t len) +{ + size_t offset = 0; + __m128i b1, b2, c; + + do { + if (likely(len - offset < SCMEMCMP_BYTES)) { + return memcmp(s1, s2, len - offset) ? 1 : 0; + } + + /* unaligned loads */ + b1 = _mm_loadu_si128((const __m128i *)s1); + b2 = _mm_loadu_si128((const __m128i *)s2); + c = _mm_cmpeq_epi8(b1, b2); + + if (_mm_movemask_epi8(c) != 0x0000FFFF) { + return 1; + } + + offset += SCMEMCMP_BYTES; + s1 += SCMEMCMP_BYTES; + s2 += SCMEMCMP_BYTES; + } while (len > offset); + + return 0; +} + +#define UPPER_LOW 0x40 /* "A" - 1 */ +#define UPPER_HIGH 0x5B /* "Z" + 1 */ +#define UPPER_DELTA 0xDF /* 0xFF - 0x20 */ + +static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) +{ + size_t offset = 0; + __m128i b1, b2, mask1, mask2, upper1, upper2, delta; + + /* setup registers for upper to lower conversion */ + upper1 = _mm_set1_epi8(UPPER_LOW); + upper2 = _mm_set1_epi8(UPPER_HIGH); + delta = _mm_set1_epi8(UPPER_DELTA); + + do { + if (likely(len - offset < SCMEMCMP_BYTES)) { + return MemcmpLowercase(s1, s2, len - offset); + } + + /* unaligned loading of the bytes to compare */ + b1 = _mm_loadu_si128((const __m128i *)s1); + b2 = _mm_loadu_si128((const __m128i *)s2); + + /* mark all chars bigger than upper1 */ + mask1 = _mm_cmpgt_epi8(b2, upper1); + /* mark all chars lower than upper2 */ + mask2 = _mm_cmplt_epi8(b2, upper2); + /* merge the two, leaving only those that are true in both */ + mask1 = _mm_cmpeq_epi8(mask1, mask2); + /* sub delta leaves 0x20 only for uppercase positions, the + rest is 0x00 due to the saturation (reuse mask1 reg)*/ + mask1 = _mm_subs_epu8(mask1, delta); + /* add to b2, converting uppercase to lowercase */ + b2 = _mm_add_epi8(b2, mask1); + + /* now all is lowercase, let's do the actual compare (reuse mask1 reg) */ + mask1 = _mm_cmpeq_epi8(b1, b2); + + if (_mm_movemask_epi8(mask1) != 0x0000FFFF) { + return 1; + } + + offset += SCMEMCMP_BYTES; + s1 += SCMEMCMP_BYTES; + s2 += SCMEMCMP_BYTES; + } while (len > offset); + + return 0; +} + +#else + +/* No SIMD support, fall back to plain memcmp and a home grown lowercase one */ + +/* wrapper around memcmp to match the retvals of the SIMD implementations */ +#define SCMemcmp(a, b, c) ({ memcmp((a), (b), (c)) ? 1 : 0; }) + +static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) +{ + return MemcmpLowercase(s1, s2, len); +} + +#endif /* SIMD */ + +static inline int SCBufferCmp(const void *s1, size_t len1, const void *s2, size_t len2) +{ + if (len1 == len2) { + return SCMemcmp(s1, s2, len1); + } else if (len1 < len2) { + return -1; + } + return 1; +} + +#endif /* __UTIL_MEMCMP_H__ */ diff --git a/src/util-memcpy.h b/src/util/memcpy.h similarity index 100% rename from src/util-memcpy.h rename to src/util/memcpy.h diff --git a/src/util/memrchr.c b/src/util/memrchr.c new file mode 100644 index 000000000000..fd6137288c15 --- /dev/null +++ b/src/util/memrchr.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" +#include "util/unittest.h" +#include "util/memrchr.h" + +#ifndef HAVE_MEMRCHR +void *memrchr(const void *s, int c, size_t n) +{ + const char *end = s + n; + + while (end > (const char *)s) { + if (*end == (char)c) + return (void *)end; + end--; + } + return NULL; +} +#endif /* HAVE_MEMRCHR */ + +#ifdef UNITTESTS +static int MemrchrTest01(void) +{ + const char *haystack = "abcabc"; + char needle = 'b'; + + char *ptr = memrchr(haystack, needle, strlen(haystack)); + if (ptr == NULL) + return 0; + + if (strlen(ptr) != 2) + return 0; + + if (strcmp(ptr, "bc") != 0) + return 0; + + return 1; +} +#endif + +void MemrchrRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MemrchrTest01", MemrchrTest01); +#endif +} diff --git a/src/util-memrchr.h b/src/util/memrchr.h similarity index 100% rename from src/util-memrchr.h rename to src/util/memrchr.h diff --git a/src/util/misc.c b/src/util/misc.c new file mode 100644 index 000000000000..43f50cebad41 --- /dev/null +++ b/src/util/misc.c @@ -0,0 +1,776 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util/byte.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/misc.h" + +#define PARSE_REGEX "^\\s*(\\d+(?:.\\d+)?)\\s*([a-zA-Z]{2})?\\s*$" +static pcre2_code *parse_regex = NULL; +static pcre2_match_data *parse_regex_match = NULL; + +void ParseSizeInit(void) +{ + int en; + PCRE2_SIZE eo; + int opts = 0; + + parse_regex = + pcre2_compile((PCRE2_SPTR8)PARSE_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + if (parse_regex == NULL) { + PCRE2_UCHAR errbuffer[256]; + pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); + SCLogError("pcre2 compile of \"%s\" failed at " + "offset %d: %s", + PARSE_REGEX, (int)eo, errbuffer); + exit(EXIT_FAILURE); + } + parse_regex_match = pcre2_match_data_create_from_pattern(parse_regex, NULL); +} + +void ParseSizeDeinit(void) +{ + pcre2_code_free(parse_regex); + pcre2_match_data_free(parse_regex_match); +} + +/* size string parsing API */ + +static int ParseSizeString(const char *size, double *res) +{ + int pcre2_match_ret; + int r; + int retval = 0; + char str[128]; + char str2[128]; + + *res = 0; + + if (size == NULL) { + SCLogError("invalid size argument - NULL. Valid size " + "argument should be in the format - \n" + "xxx <- indicates it is just bytes\n" + "xxxkb or xxxKb or xxxKB or xxxkB <- indicates kilobytes\n" + "xxxmb or xxxMb or xxxMB or xxxmB <- indicates megabytes\n" + "xxxgb or xxxGb or xxxGB or xxxgB <- indicates gigabytes.\n"); + retval = -2; + goto end; + } + + pcre2_match_ret = pcre2_match( + parse_regex, (PCRE2_SPTR8)size, strlen(size), 0, 0, parse_regex_match, NULL); + + if (!(pcre2_match_ret == 2 || pcre2_match_ret == 3)) { + SCLogError("invalid size argument - %s. Valid size " + "argument should be in the format - \n" + "xxx <- indicates it is just bytes\n" + "xxxkb or xxxKb or xxxKB or xxxkB <- indicates kilobytes\n" + "xxxmb or xxxMb or xxxMB or xxxmB <- indicates megabytes\n" + "xxxgb or xxxGb or xxxGB or xxxgB <- indicates gigabytes.\n", + size); + retval = -2; + goto end; + } + + size_t copylen = sizeof(str); + r = pcre2_substring_copy_bynumber(parse_regex_match, 1, (PCRE2_UCHAR8 *)str, ©len); + if (r < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + retval = -2; + goto end; + } + + char *endptr, *str_ptr = str; + errno = 0; + *res = strtod(str_ptr, &endptr); + if (errno == ERANGE) { + SCLogError("Numeric value out of range"); + retval = -1; + goto end; + } else if (endptr == str_ptr) { + SCLogError("Invalid numeric value"); + retval = -1; + goto end; + } + + if (pcre2_match_ret == 3) { + copylen = sizeof(str2); + r = pcre2_substring_copy_bynumber(parse_regex_match, 2, (PCRE2_UCHAR8 *)str2, ©len); + + if (r < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + retval = -2; + goto end; + } + + if (strcasecmp(str2, "kb") == 0) { + *res *= 1024; + } else if (strcasecmp(str2, "mb") == 0) { + *res *= 1024 * 1024; + } else if (strcasecmp(str2, "gb") == 0) { + *res *= 1024 * 1024 * 1024; + } else { + /* Bad unit. */ + retval = -1; + goto end; + } + } + + retval = 0; +end: + return retval; +} + +int ParseSizeStringU8(const char *size, uint8_t *res) +{ + double temp_res = 0; + + *res = 0; + int r = ParseSizeString(size, &temp_res); + if (r < 0) + return r; + + if (temp_res > UINT8_MAX) + return -1; + + *res = temp_res; + + return 0; +} + +int ParseSizeStringU16(const char *size, uint16_t *res) +{ + double temp_res = 0; + + *res = 0; + int r = ParseSizeString(size, &temp_res); + if (r < 0) + return r; + + if (temp_res > UINT16_MAX) + return -1; + + *res = temp_res; + + return 0; +} + +int ParseSizeStringU32(const char *size, uint32_t *res) +{ + double temp_res = 0; + + *res = 0; + int r = ParseSizeString(size, &temp_res); + if (r < 0) + return r; + + if (temp_res > UINT32_MAX) + return -1; + + *res = temp_res; + + return 0; +} + +int ParseSizeStringU64(const char *size, uint64_t *res) +{ + double temp_res = 0; + + *res = 0; + int r = ParseSizeString(size, &temp_res); + if (r < 0) + return r; + + if (temp_res > (double)UINT64_MAX) + return -1; + + *res = temp_res; + + return 0; +} + +void ShortenString(const char *input, char *output, size_t output_size, char c) +{ + const size_t str_len = strlen(input); + size_t half = (output_size - 1) / 2; + + /* If the output size is an even number */ + if (half * 2 == (output_size - 1)) { + half = half - 1; + } + + size_t spaces = (output_size - 1) - (half * 2); + + /* Add the first half to the new string */ + snprintf(output, half + 1, "%s", input); + + /* Add the amount of spaces wanted */ + size_t length = half; + for (size_t i = half; i < half + spaces; i++) { + char s[2] = ""; + snprintf(s, sizeof(s), "%c", c); + length = strlcat(output, s, output_size); + } + + snprintf(output + length, half + 1, "%s", input + (str_len - half)); +} + +/*********************************Unittests********************************/ + +#ifdef UNITTESTS + +static int UtilMiscParseSizeStringTest01(void) +{ + const char *str; + double result; + + /* no space */ + + str = "10"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = "10kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = "10gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240UL); + + /* space start */ + + str = " 10"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = " 10kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = " 10gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240); + + /* space end */ + + str = "10 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = "10kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = "10gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240); + + /* space start - space end */ + + str = " 10 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = " 10kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = " 10gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240); + + /* space between number and scale */ + + /* no space */ + + str = "10"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = "10 kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10 Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10 KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10 mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = "10 gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240); + + /* space start */ + + str = " 10"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = " 10 kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10 Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10 KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10 mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = " 10 gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240); + + /* space end */ + + str = "10 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = "10 kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10 Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10 KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = "10 mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = "10 gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240); + + /* space start - space end */ + + str = " 10 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10); + + str = " 10 kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10 Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10 KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024); + + str = " 10 mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10 * 1024 * 1024); + + str = " 10 gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10737418240); + + /* no space */ + + str = "10.5"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = "10.5kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = "10.5gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* space start */ + + str = " 10.5"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = " 10.5kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = " 10.5gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* space end */ + + str = "10.5 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = "10.5kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = "10.5gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* space start - space end */ + + str = " 10.5 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = " 10.5kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = " 10.5gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* space between number and scale */ + + /* no space */ + + str = "10.5"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = "10.5 kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5 Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5 KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5 mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = "10.5 gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* space start */ + + str = " 10.5"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = " 10.5 kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5 Kb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5 KB"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5 mb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = " 10.5 gb"; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* space end */ + + str = "10.5 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = "10.5 kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5 Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5 KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = "10.5 mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = "10.5 gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* space start - space end */ + + str = " 10.5 "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5); + + str = " 10.5 kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5 Kb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5 KB "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024); + + str = " 10.5 mb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024); + + str = " 10.5 gb "; + result = 0; + FAIL_IF(ParseSizeString(str, &result) > 0); + FAIL_IF(result != 10.5 * 1024 * 1024 * 1024); + + /* Should fail on unknown units. */ + FAIL_IF(ParseSizeString("32eb", &result) > 0); + + PASS; +} + +void UtilMiscRegisterTests(void) +{ + UtRegisterTest("UtilMiscParseSizeStringTest01", UtilMiscParseSizeStringTest01); +} +#endif /* UNITTESTS */ diff --git a/src/util/misc.h b/src/util/misc.h new file mode 100644 index 000000000000..e9adc0190391 --- /dev/null +++ b/src/util/misc.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_MISC_H__ +#define __UTIL_MISC_H__ + +/** + * \brief Generic API that can be used by all to log an + * invalid conf entry. + * \param param_name A string specifying the param name. + * \param format Format for the below value. For example "%s", "%"PRIu32, + etc. + * \param value Default value to be printed. + */ +#define WarnInvalidConfEntry(param_name, format, value) \ + do { \ + SCLogWarning("Invalid conf entry found for " \ + "\"%s\". Using default value of \"" format "\".", \ + param_name, value); \ + } while (0) + +/* size string parsing API */ + +int ParseSizeStringU8(const char *, uint8_t *); +int ParseSizeStringU16(const char *, uint16_t *); +int ParseSizeStringU32(const char *, uint32_t *); +int ParseSizeStringU64(const char *, uint64_t *); + +#ifdef UNITTESTS +void UtilMiscRegisterTests(void); +#endif /* UNITTESTS */ + +void ParseSizeInit(void); +void ParseSizeDeinit(void); + +void ShortenString(const char *input, char *output, size_t output_size, char c); + +#endif /* __UTIL_MISC_H__ */ diff --git a/src/util/mpm/mpm-ac-ks-small.c b/src/util/mpm/mpm-ac-ks-small.c new file mode 100644 index 000000000000..021fffa16ba7 --- /dev/null +++ b/src/util/mpm/mpm-ac-ks-small.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2013-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Ken Steele + + * Included by util-mpm-ac-ks.c with different SLOAD, SINDEX and + * FUNC_NAME + * + */ + +/* Only included into util-mpm-ac-ks.c, which defines FUNC_NAME + * + */ +#ifdef FUNC_NAME + +/* This function handles (ctx->state_count < 32767) */ +uint32_t FUNC_NAME(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen) +{ + uint32_t i = 0; + int matches = 0; + + uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; + memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); + + const uint8_t *restrict xlate = ctx->translate_table; + STYPE *state_table = (STYPE *)ctx->state_table; + STYPE state = 0; + int c = xlate[buf[0]]; + /* If buflen at least 4 bytes and buf 4-byte aligned. */ + if (buflen >= (4 + EXTRA) && ((uintptr_t)buf & 0x3) == 0) { + BUF_TYPE data = *(BUF_TYPE * restrict)(&buf[0]); + uint64_t index = 0; + /* Process 4*floor(buflen/4) bytes. */ + i = 0; + while ((i + EXTRA) < (buflen & ~0x3)) { + BUF_TYPE data1 = *(BUF_TYPE * restrict)(&buf[i + 4]); + index = SINDEX(index, state); + state = SLOAD(state_table + index + c); + c = xlate[BYTE1(data)]; + if (unlikely(SCHECK(state))) { + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); + } + i++; + index = SINDEX(index, state); + state = SLOAD(state_table + index + c); + c = xlate[BYTE2(data)]; + if (unlikely(SCHECK(state))) { + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); + } + i++; + index = SINDEX(index, state); + state = SLOAD(state_table + index + c); + c = xlate[BYTE3(data)]; + if (unlikely(SCHECK(state))) { + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); + } + data = data1; + i++; + index = SINDEX(index, state); + state = SLOAD(state_table + index + c); + c = xlate[BYTE0(data)]; + if (unlikely(SCHECK(state))) { + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); + } + i++; + } + } + /* Process buflen % 4 bytes. */ + for (; i < buflen; i++) { + size_t index = 0; + index = SINDEX(index, state); + state = SLOAD(state_table + index + c); + if (likely(i + 1 < buflen)) + c = xlate[buf[i + 1]]; + if (unlikely(SCHECK(state))) { + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); + } + } /* for (i = 0; i < buflen; i++) */ + + return matches; +} + +#endif /* FUNC_NAME */ diff --git a/src/util/mpm/mpm-ac-ks.c b/src/util/mpm/mpm-ac-ks.c new file mode 100644 index 000000000000..d89d50692724 --- /dev/null +++ b/src/util/mpm/mpm-ac-ks.c @@ -0,0 +1,2374 @@ +/* Copyright (C) 2013-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Ken Steele + * \author Anoop Saldanha + * + * Aho-corasick MPM optimized for the Tilera Tile-Gx architecture. + * + * Efficient String Matching: An Aid to Bibliographic Search + * Alfred V. Aho and Margaret J. Corasick + * + * - Started with util-mpm-ac.c: + * - Uses the delta table for calculating transitions, + * instead of having separate goto and failure + * transitions. + * - If we cross 2 ** 16 states, we use 4 bytes in the + * transition table to hold each state, otherwise we use + * 2 bytes. + * - This version of the MPM is heavy on memory, but it + * performs well. If you can fit the ruleset with this + * mpm on your box without hitting swap, this is the MPM + * to go for. + * + * - Added these optimizations: + * - Compress the input alphabet from 256 characters down + * to the actual characters used in the patterns, plus + * one character for all the unused characters. + * - Reduce the size of the delta table so that each state + * is the smallest power of two that is larger than the + * size of the compressed alphabet. + * - Specialized the search function based on state count + * (small for 8-bit large for 16-bit) and the size of + * the alphabet, so that it is constant inside the + * function for better optimization. + * + * \todo - Do a proper analysis of our existing MPMs and suggest a good + * one based on the pattern distribution and the expected + * traffic(say http). + + * - Irrespective of whether we cross 2 ** 16 states or + * not,shift to using uint32_t for state type, so that we can + * integrate it's status as a final state or not in the + * topmost byte. We are already doing it if state_count is > + * 2 ** 16. + * - Test case-sensitive patterns if they have any ascii chars. + * If they don't treat them as nocase. + * - Reorder the compressed alphabet to put the most common characters + * first. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "../../detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-build.h" + +#include "../../conf.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/memcmp.h" +#include "util/memcpy.h" +#include "util/validate.h" +#include "util/mpm/mpm-ac-ks.h" + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +void SCACTileInitCtx(MpmCtx *); +void SCACTileDestroyCtx(MpmCtx *); +int SCACTileAddPatternCI( + MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int SCACTileAddPatternCS( + MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int SCACTilePreparePatterns(MpmCtx *mpm_ctx); +uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +void SCACTilePrintInfo(MpmCtx *mpm_ctx); +void SCACTileRegisterTests(void); + +uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchSmall256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchSmall128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchSmall64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchSmall32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchSmall16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchSmall8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); + +uint32_t SCACTileSearchTiny256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchTiny128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchTiny64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchTiny32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchTiny16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); +uint32_t SCACTileSearchTiny8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen); + +static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx); + +/* a placeholder to denote a failure transition in the goto table */ +#define SC_AC_TILE_FAIL (-1) + +#define STATE_QUEUE_CONTAINER_SIZE 65536 + +/** + * \brief Helper structure used by AC during state table creation + */ +typedef struct StateQueue_ { + int32_t store[STATE_QUEUE_CONTAINER_SIZE]; + int top; + int bot; +} StateQueue; + +/** + * \internal + * \brief Initialize the AC context with user specified conf parameters. We + * aren't retrieving anything for AC conf now, but we will certainly + * need it, when we customize AC. + */ +static void SCACTileGetConfig(void) +{ +} + +/** + * \internal + * \brief Count the occurrences of each character in the pattern and + * accumulate into a histogram. Really only used to detect unused + * characters, so could just set to 1 instead of counting. + */ +static inline void SCACTileHistogramAlphabet(SCACTileCtx *ctx, MpmPattern *p) +{ + for (int i = 0; i < p->len; i++) { + ctx->alpha_hist[p->ci[i]]++; + } +} + +/* Use Alphabet Histogram to create compressed alphabet. + */ +static void SCACTileInitTranslateTable(SCACTileCtx *ctx) +{ + /* Count the number of ASCII values actually appearing in any + * pattern. Create compressed mapping table with unused + * characters mapping to zero. + */ + for (int i = 0; i < 256; i++) { + /* Move all upper case counts to lower case */ + if (i >= 'A' && i <= 'Z') { + ctx->alpha_hist[i - 'A' + 'a'] += ctx->alpha_hist[i]; + ctx->alpha_hist[i] = 0; + } + if (ctx->alpha_hist[i]) { + ctx->alphabet_size++; + DEBUG_VALIDATE_BUG_ON(ctx->alphabet_size > UINT8_MAX); + ctx->translate_table[i] = (uint8_t)ctx->alphabet_size; + } else + ctx->translate_table[i] = 0; + } + /* Fix up translation table for uppercase */ + for (int i = 'A'; i <= 'Z'; i++) + ctx->translate_table[i] = ctx->translate_table[i - 'A' + 'a']; + + SCLogDebug(" Alphabet size %d", ctx->alphabet_size); + + /* Round alphabet size up to next power-of-two Leave one extra + * space For the unused-characters = 0 mapping. + */ + ctx->alphabet_size += 1; /* Extra space for unused-character */ + if (ctx->alphabet_size <= 8) { + ctx->alphabet_storage = 8; + } else if (ctx->alphabet_size <= 16) { + ctx->alphabet_storage = 16; + } else if (ctx->alphabet_size <= 32) { + ctx->alphabet_storage = 32; + } else if (ctx->alphabet_size <= 64) { + ctx->alphabet_storage = 64; + } else if (ctx->alphabet_size <= 128) { + ctx->alphabet_storage = 128; + } else + ctx->alphabet_storage = 256; +} + +static void SCACTileReallocOutputTable(SCACTileCtx *ctx, int new_state_count) +{ + + /* reallocate space in the output table for the new state */ + size_t size = ctx->allocated_state_count * sizeof(SCACTileOutputTable); + void *ptmp = SCRealloc(ctx->output_table, size); + if (ptmp == NULL) { + SCFree(ctx->output_table); + ctx->output_table = NULL; + FatalError("Error allocating memory"); + } + ctx->output_table = ptmp; +} + +static void SCACTileReallocState(SCACTileCtx *ctx, int new_state_count) +{ + /* reallocate space in the goto table to include a new state */ + size_t size = ctx->allocated_state_count * sizeof(int32_t) * 256; + void *ptmp = SCRealloc(ctx->goto_table, size); + if (ptmp == NULL) { + SCFree(ctx->goto_table); + ctx->goto_table = NULL; + FatalError("Error allocating memory"); + } + ctx->goto_table = ptmp; + + SCACTileReallocOutputTable(ctx, new_state_count); +} + +/** + * \internal + * \brief Initialize a new state in the goto and output tables. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval The state id, of the newly created state. + */ +static inline int SCACTileInitNewState(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + int aa = 0; + + /* Exponentially increase the allocated space when needed. */ + if (ctx->allocated_state_count < ctx->state_count + 1) { + if (ctx->allocated_state_count == 0) + ctx->allocated_state_count = 256; + else + ctx->allocated_state_count *= 2; + + SCACTileReallocState(ctx, ctx->allocated_state_count); + } + + /* set all transitions for the newly assigned state as FAIL transitions */ + for (aa = 0; aa < ctx->alphabet_size; aa++) { + ctx->goto_table[ctx->state_count][aa] = SC_AC_TILE_FAIL; + } + + memset(ctx->output_table + ctx->state_count, 0, sizeof(SCACTileOutputTable)); + + return ctx->state_count++; +} + +/** + * \internal + * \brief Adds a pid to the output table for a state. + * + * \param state The state to whose output table we should add the pid. + * \param pid The pattern id to add. + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACTileSetOutputState(int32_t state, MpmPatternIndex pindex, MpmCtx *mpm_ctx) +{ + void *ptmp; + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + SCACTileOutputTable *output_state = &ctx->output_table[state]; + uint32_t i = 0; + + /* Don't add the pattern more than once to the same state. */ + for (i = 0; i < output_state->no_of_entries; i++) { + if (output_state->patterns[i] == pindex) + return; + } + + /* Increase the size of the array of pids for this state and add + * the new pid. */ + output_state->no_of_entries++; + ptmp = SCRealloc(output_state->patterns, output_state->no_of_entries * sizeof(MpmPatternIndex)); + if (ptmp == NULL) { + SCFree(output_state->patterns); + output_state->patterns = NULL; + FatalError("Error allocating memory"); + } + output_state->patterns = ptmp; + + output_state->patterns[output_state->no_of_entries - 1] = pindex; +} + +/** + * \brief Helper function used by SCACTileCreateGotoTable. Adds a + * pattern to the goto table. + * + * \param pattern Pointer to the pattern. + * \param pattern_len Pattern length. + * \param pid The pattern id, that corresponds to this pattern. We + * need it to updated the output table for this pattern. + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACTileEnter( + uint8_t *pattern, uint16_t pattern_len, MpmPatternIndex pindex, MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + int32_t state = 0; + int32_t newstate = 0; + int i = 0; + int p = 0; + int tc; + + /* Walk down the trie till we have a match for the pattern prefix */ + state = 0; + for (i = 0; i < pattern_len; i++) { + tc = ctx->translate_table[pattern[i]]; + if (ctx->goto_table[state][tc] == SC_AC_TILE_FAIL) + break; + state = ctx->goto_table[state][tc]; + } + + /* Add the non-matching pattern suffix to the trie, from the last state + * we left off */ + for (p = i; p < pattern_len; p++) { + newstate = SCACTileInitNewState(mpm_ctx); + tc = ctx->translate_table[pattern[p]]; + ctx->goto_table[state][tc] = newstate; + state = newstate; + } + + /* Add this pattern id, to the output table of the last state, where the + * pattern ends in the trie */ + SCACTileSetOutputState(state, pindex, mpm_ctx); +} + +/** + * \internal + * \brief Create the goto table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACTileCreateGotoTable(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + uint32_t i = 0; + + /* add each pattern to create the goto table */ + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + SCACTileEnter(ctx->parray[i]->ci, ctx->parray[i]->len, i, mpm_ctx); + } + + int aa = 0; + for (aa = 0; aa < ctx->alphabet_size; aa++) { + if (ctx->goto_table[0][aa] == SC_AC_TILE_FAIL) { + ctx->goto_table[0][aa] = 0; + } + } +} + +static inline int SCACTileStateQueueIsEmpty(StateQueue *q) +{ + if (q->top == q->bot) + return 1; + else + return 0; +} + +static inline void SCACTileEnqueue(StateQueue *q, int32_t state) +{ + int i = 0; + + /*if we already have this */ + for (i = q->bot; i < q->top; i++) { + if (q->store[i] == state) + return; + } + + q->store[q->top++] = state; + + if (q->top == STATE_QUEUE_CONTAINER_SIZE) + q->top = 0; + + if (q->top == q->bot) { + FatalError("Just ran out of space in the queue. " + "Fatal Error. Exiting. Please file a bug report on this"); + } +} + +static inline int32_t SCACTileDequeue(StateQueue *q) +{ + if (q->bot == STATE_QUEUE_CONTAINER_SIZE) + q->bot = 0; + + if (q->bot == q->top) { + FatalError("StateQueue behaving weirdly. " + "Fatal Error. Exiting. Please file a bug report on this"); + } + + return q->store[q->bot++]; +} + +/** + * \internal + * \brief Club the output data from 2 states and store it in the 1st state. + * dst_state_data = {dst_state_data} UNION {src_state_data} + * + * \param dst_state First state(also the destination) for the union operation. + * \param src_state Second state for the union operation. + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACTileClubOutputStates(int32_t dst_state, int32_t src_state, MpmCtx *mpm_ctx) +{ + void *ptmp; + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + uint32_t i = 0; + uint32_t j = 0; + + SCACTileOutputTable *output_dst_state = &ctx->output_table[dst_state]; + SCACTileOutputTable *output_src_state = &ctx->output_table[src_state]; + + for (i = 0; i < output_src_state->no_of_entries; i++) { + for (j = 0; j < output_dst_state->no_of_entries; j++) { + if (output_src_state->patterns[i] == output_dst_state->patterns[j]) { + break; + } + } + if (j == output_dst_state->no_of_entries) { + output_dst_state->no_of_entries++; + + ptmp = SCRealloc(output_dst_state->patterns, + (output_dst_state->no_of_entries * sizeof(uint32_t))); + if (ptmp == NULL) { + SCFree(output_dst_state->patterns); + output_dst_state->patterns = NULL; + FatalError("Error allocating memory"); + } + output_dst_state->patterns = ptmp; + + output_dst_state->patterns[output_dst_state->no_of_entries - 1] = + output_src_state->patterns[i]; + } + } +} + +/** + * \internal + * \brief Create the failure table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACTileCreateFailureTable(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + int aa = 0; + int32_t state = 0; + int32_t r_state = 0; + + StateQueue q; + memset(&q, 0, sizeof(StateQueue)); + + /* Allocate space for the failure table. A failure entry in the table for + * every state(SCACTileCtx->state_count) */ + ctx->failure_table = SCCalloc(ctx->state_count, sizeof(int32_t)); + if (ctx->failure_table == NULL) { + FatalError("Error allocating memory"); + } + + /* Add the failure transitions for the 0th state, and add every non-fail + * transition from the 0th state to the queue for further processing + * of failure states */ + for (aa = 0; aa < ctx->alphabet_size; aa++) { + int32_t temp_state = ctx->goto_table[0][aa]; + if (temp_state != 0) { + SCACTileEnqueue(&q, temp_state); + ctx->failure_table[temp_state] = 0; + } + } + + while (!SCACTileStateQueueIsEmpty(&q)) { + /* pick up every state from the queue and add failure transitions */ + r_state = SCACTileDequeue(&q); + for (aa = 0; aa < ctx->alphabet_size; aa++) { + int32_t temp_state = ctx->goto_table[r_state][aa]; + if (temp_state == SC_AC_TILE_FAIL) + continue; + SCACTileEnqueue(&q, temp_state); + state = ctx->failure_table[r_state]; + + while (ctx->goto_table[state][aa] == SC_AC_TILE_FAIL) + state = ctx->failure_table[state]; + ctx->failure_table[temp_state] = ctx->goto_table[state][aa]; + SCACTileClubOutputStates(temp_state, ctx->failure_table[temp_state], mpm_ctx); + } + } +} + +/* + * Set the next state for 1 byte next-state. + */ +static void SCACTileSetState1Byte(SCACTileCtx *ctx, int state, int aa, int next_state, int outputs) +{ + uint8_t *state_table = (uint8_t *)ctx->state_table; + DEBUG_VALIDATE_BUG_ON(next_state < 0 || next_state > UINT8_MAX); + uint8_t encoded_next_state = (uint8_t)next_state; + + if (next_state == SC_AC_TILE_FAIL) { + FatalError("Error FAIL state in output"); + } + + if (outputs == 0) + encoded_next_state |= (1 << 7); + + state_table[state * ctx->alphabet_storage + aa] = encoded_next_state; +} + +/* + * Set the next state for 2 byte next-state. + */ +static void SCACTileSetState2Bytes(SCACTileCtx *ctx, int state, int aa, int next_state, int outputs) +{ + uint16_t *state_table = (uint16_t *)ctx->state_table; + DEBUG_VALIDATE_BUG_ON(next_state < 0 || next_state > UINT16_MAX); + uint16_t encoded_next_state = (uint16_t)next_state; + + if (next_state == SC_AC_TILE_FAIL) { + FatalError("Error FAIL state in output"); + } + + if (outputs == 0) + encoded_next_state |= (1 << 15); + + state_table[state * ctx->alphabet_storage + aa] = encoded_next_state; +} + +/* + * Set the next state for 4 byte next-state. + */ +static void SCACTileSetState4Bytes(SCACTileCtx *ctx, int state, int aa, int next_state, int outputs) +{ + uint32_t *state_table = (uint32_t *)ctx->state_table; + uint32_t encoded_next_state = next_state; + + if (next_state == SC_AC_TILE_FAIL) { + FatalError("Error FAIL state in output"); + } + + if (outputs == 0) + encoded_next_state |= (1UL << 31); + + state_table[state * ctx->alphabet_storage + aa] = encoded_next_state; +} + +/** + * \internal + * \brief Create the delta table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static inline void SCACTileCreateDeltaTable(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + int aa = 0; + int32_t r_state = 0; + + if (ctx->state_count < 32767) { + if (ctx->state_count < 128) { + ctx->bytes_per_state = 1; + ctx->SetNextState = SCACTileSetState1Byte; + + switch (ctx->alphabet_storage) { + case 8: + ctx->Search = SCACTileSearchTiny8; + break; + case 16: + ctx->Search = SCACTileSearchTiny16; + break; + case 32: + ctx->Search = SCACTileSearchTiny32; + break; + case 64: + ctx->Search = SCACTileSearchTiny64; + break; + case 128: + ctx->Search = SCACTileSearchTiny128; + break; + default: + ctx->Search = SCACTileSearchTiny256; + } + } else { + /* 16-bit state needed */ + ctx->bytes_per_state = 2; + ctx->SetNextState = SCACTileSetState2Bytes; + + switch (ctx->alphabet_storage) { + case 8: + ctx->Search = SCACTileSearchSmall8; + break; + case 16: + ctx->Search = SCACTileSearchSmall16; + break; + case 32: + ctx->Search = SCACTileSearchSmall32; + break; + case 64: + ctx->Search = SCACTileSearchSmall64; + break; + case 128: + ctx->Search = SCACTileSearchSmall128; + break; + default: + ctx->Search = SCACTileSearchSmall256; + } + } + } else { + /* 32-bit next state */ + ctx->Search = SCACTileSearchLarge; + ctx->bytes_per_state = 4; + ctx->SetNextState = SCACTileSetState4Bytes; + + ctx->alphabet_storage = 256; /* Change? */ + } + + StateQueue q; + memset(&q, 0, sizeof(StateQueue)); + + for (aa = 0; aa < ctx->alphabet_size; aa++) { + int temp_state = ctx->goto_table[0][aa]; + if (temp_state != 0) + SCACTileEnqueue(&q, temp_state); + } + + while (!SCACTileStateQueueIsEmpty(&q)) { + r_state = SCACTileDequeue(&q); + + for (aa = 0; aa < ctx->alphabet_size; aa++) { + int temp_state = ctx->goto_table[r_state][aa]; + if (temp_state != SC_AC_TILE_FAIL) { + SCACTileEnqueue(&q, temp_state); + } else { + int f_state = ctx->failure_table[r_state]; + ctx->goto_table[r_state][aa] = ctx->goto_table[f_state][aa]; + } + } + } +} + +static void SCACTileClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + int aa = 0; + uint32_t state = 0; + + /* Allocate next-state table. */ + int size = ctx->state_count * ctx->bytes_per_state * ctx->alphabet_storage; + void *state_table = SCCalloc(1, size); + if (unlikely(state_table == NULL)) { + FatalError("Error allocating memory"); + } + ctx->state_table = state_table; + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += size; + + SCLogDebug("Delta Table size %d, alphabet: %d, %d-byte states: %d", size, ctx->alphabet_size, + ctx->bytes_per_state, ctx->state_count); + + /* Copy next state from Goto table, which is 32 bits and encode it into the next + * state table, which can be 1, 2 or 4 bytes each and include if there is an + * output. + */ + for (state = 0; state < ctx->state_count; state++) { + for (aa = 0; aa < ctx->alphabet_size; aa++) { + int next_state = ctx->goto_table[state][aa]; + int next_state_outputs = ctx->output_table[next_state].no_of_entries; + ctx->SetNextState(ctx, state, aa, next_state, next_state_outputs); + } + } +} + +static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + uint32_t state = 0; + uint32_t k = 0; + + for (state = 0; state < ctx->state_count; state++) { + if (ctx->output_table[state].no_of_entries == 0) + continue; + + for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { + if (ctx->pattern_list[ctx->output_table[state].patterns[k]].cs != NULL) { + /* TODO - Find better way to store this. */ + ctx->output_table[state].patterns[k] &= 0x0FFFFFFF; + ctx->output_table[state].patterns[k] |= (uint32_t)1 << 31; + } + } + } +} + +#if 0 +static void SCACTilePrintDeltaTable(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + int i = 0, j = 0; + + printf("##############Delta Table##############\n"); + for (i = 0; i < ctx->state_count; i++) { + printf("%d: \n", i); + for (j = 0; j < ctx->alphabet_size; j++) { + if (SCACTileGetDelta(i, j, mpm_ctx) != 0) { + printf(" %c -> %d\n", j, SCACTileGetDelta(i, j, mpm_ctx)); + } + } + } +} +#endif + +/** + * \brief Process the patterns and prepare the state table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACTilePrepareStateTable(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + /* Create Alphabet compression and Lower Case translation table. */ + SCACTileInitTranslateTable(ctx); + + /* create the 0th state in the goto table and output_table */ + SCACTileInitNewState(mpm_ctx); + + /* create the goto table */ + SCACTileCreateGotoTable(mpm_ctx); + /* create the failure table */ + SCACTileCreateFailureTable(mpm_ctx); + /* create the final state(delta) table */ + SCACTileCreateDeltaTable(mpm_ctx); + /* club the output state presence with delta transition entries */ + SCACTileClubOutputStatePresenceWithDeltaTable(mpm_ctx); + + /* club nocase entries */ + SCACTileInsertCaseSensitiveEntriesForPatterns(mpm_ctx); + +#if 0 + SCACTilePrintDeltaTable(mpm_ctx); +#endif + + /* we don't need these anymore */ + SCFree(ctx->goto_table); + ctx->goto_table = NULL; + SCFree(ctx->failure_table); + ctx->failure_table = NULL; +} + +/** + * \brief Process Internal AC MPM tables to create the Search Context + * + * The search context is only the data needed to search the MPM. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACTilePrepareSearch(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + /* Resize the output table to be only as big as its final size. */ + SCACTileReallocOutputTable(ctx, ctx->state_count); + + search_ctx->Search = ctx->Search; + memcpy(search_ctx->translate_table, ctx->translate_table, sizeof(ctx->translate_table)); + + /* Move the state table from the Init context */ + search_ctx->state_table = ctx->state_table; + ctx->state_table = NULL; /* So that it won't get freed twice. */ + + /* Move the output_table from the Init context to the Search Context */ + /* TODO: Could be made more compact */ + search_ctx->output_table = ctx->output_table; + ctx->output_table = NULL; + search_ctx->state_count = ctx->state_count; + + search_ctx->pattern_list = ctx->pattern_list; + ctx->pattern_list = NULL; + search_ctx->pattern_cnt = mpm_ctx->pattern_cnt; + + /* One bit per pattern, rounded up to the next byte size. */ + search_ctx->mpm_bitarray_size = (mpm_ctx->pattern_cnt + 7) / 8; + + /* Can now free the Initialization data */ + SCACTileDestroyInitCtx(mpm_ctx); +} + +/** + * \brief Process the patterns added to the mpm, and create the internal tables. + * + * \param mpm_ctx Pointer to the mpm context. + */ +int SCACTilePreparePatterns(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + + if (mpm_ctx->pattern_cnt == 0 || search_ctx->init_ctx == NULL) { + SCLogDebug("no patterns supplied to this mpm_ctx"); + return 0; + } + SCACTileCtx *ctx = search_ctx->init_ctx; + if (mpm_ctx->init_hash == NULL) { + SCLogDebug("no patterns supplied to this mpm_ctx"); + return 0; + } + + /* alloc the pattern array */ + ctx->parray = (MpmPattern **)SCCalloc(mpm_ctx->pattern_cnt, sizeof(MpmPattern *)); + if (ctx->parray == NULL) + goto error; + + /* populate it with the patterns in the hash */ + uint32_t i = 0, p = 0; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; + while (node != NULL) { + nnode = node->next; + node->next = NULL; + ctx->parray[p++] = node; + SCACTileHistogramAlphabet(ctx, node); + node = nnode; + } + } + + /* we no longer need the hash, so free it's memory */ + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; + + /* Handle case patterns by storing a copy of the pattern to compare + * to each possible match (no-case). + * + * Allocate the memory for the array and each of the strings as one block. + */ + size_t string_space_needed = 0; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { + /* Round up to next 8 byte aligned length */ + uint32_t space = ((ctx->parray[i]->len + 7) / 8) * 8; + string_space_needed += space; + } + } + + size_t pattern_list_size = mpm_ctx->pattern_cnt * sizeof(SCACTilePatternList); + size_t mem_size = string_space_needed + pattern_list_size; + void *mem_block = SCCalloc(1, mem_size); + if (mem_block == NULL) { + FatalError("Error allocating memory"); + } + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += mem_size; + /* Split the allocated block into pattern list array and string space. */ + ctx->pattern_list = mem_block; + uint8_t *string_space = mem_block + pattern_list_size; + + /* Now make the copies of the no-case strings. */ + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { + uint16_t len = ctx->parray[i]->len; + uint32_t space = ((len + 7) / 8) * 8; + memcpy(string_space, ctx->parray[i]->original_pat, len); + ctx->pattern_list[i].cs = string_space; + ctx->pattern_list[i].patlen = len; + string_space += space; + } + ctx->pattern_list[i].offset = ctx->parray[i]->offset; + ctx->pattern_list[i].depth = ctx->parray[i]->depth; + ctx->pattern_list[i].pid = ctx->parray[i]->id; + + /* ACPatternList now owns this memory */ + ctx->pattern_list[i].sids_size = ctx->parray[i]->sids_size; + ctx->pattern_list[i].sids = ctx->parray[i]->sids; + ctx->parray[i]->sids = NULL; + ctx->parray[i]->sids_size = 0; + } + + /* prepare the state table required by AC */ + SCACTilePrepareStateTable(mpm_ctx); + + /* Convert to the Search Context structure */ + SCACTilePrepareSearch(mpm_ctx); + + return 0; + +error: + return -1; +} + +/** + * \brief Initialize the AC context. + * + * \param mpm_ctx Mpm context. + */ +void SCACTileInitCtx(MpmCtx *mpm_ctx) +{ + if (mpm_ctx->ctx != NULL) + return; + + /* Search Context */ + mpm_ctx->ctx = SCCalloc(1, sizeof(SCACTileSearchCtx)); + if (mpm_ctx->ctx == NULL) { + exit(EXIT_FAILURE); + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCACTileSearchCtx); + + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + + /* MPM Creation context */ + search_ctx->init_ctx = SCCalloc(1, sizeof(SCACTileCtx)); + if (search_ctx->init_ctx == NULL) { + exit(EXIT_FAILURE); + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCACTileCtx); + + /* initialize the hash we use to speed up pattern insertions */ + mpm_ctx->init_hash = SCCalloc(MPM_INIT_HASH_SIZE, sizeof(MpmPattern *)); + if (mpm_ctx->init_hash == NULL) { + exit(EXIT_FAILURE); + } + + /* get conf values for AC from our yaml file. We have no conf values for + * now. We will certainly need this, as we develop the algo */ + SCACTileGetConfig(); +} + +static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + if (ctx == NULL) + return; + + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; + } + + if (ctx->parray != NULL) { + uint32_t i; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (ctx->parray[i] != NULL) { + MpmFreePattern(mpm_ctx, ctx->parray[i]); + } + } + + SCFree(ctx->parray); + ctx->parray = NULL; + } + + if (ctx->state_table != NULL) { + SCFree(ctx->state_table); + + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (ctx->state_count * ctx->bytes_per_state * ctx->alphabet_storage); + } + + if (ctx->output_table != NULL) { + uint32_t state; + for (state = 0; state < ctx->state_count; state++) { + if (ctx->output_table[state].patterns != NULL) { + SCFree(ctx->output_table[state].patterns); + } + } + SCFree(ctx->output_table); + } + + if (ctx->pattern_list != NULL) { + uint32_t i; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (ctx->pattern_list[i].cs != NULL) + SCFree(ctx->pattern_list[i].cs); + if (ctx->pattern_list[i].sids != NULL) + SCFree(ctx->pattern_list[i].sids); + } + SCFree(ctx->pattern_list); + } + + SCFree(ctx); + search_ctx->init_ctx = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCACTileCtx); +} + +/** + * \brief Destroy the mpm context. + * + * \param mpm_ctx Pointer to the mpm context. + */ +void SCACTileDestroyCtx(MpmCtx *mpm_ctx) +{ + SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + if (search_ctx == NULL) + return; + + /* Destroy Initialization data */ + SCACTileDestroyInitCtx(mpm_ctx); + + /* Free Search tables */ + SCFree(search_ctx->state_table); + + if (search_ctx->pattern_list != NULL) { + uint32_t i; + for (i = 0; i < search_ctx->pattern_cnt; i++) { + if (search_ctx->pattern_list[i].sids != NULL) + SCFree(search_ctx->pattern_list[i].sids); + } + SCFree(search_ctx->pattern_list); + } + + if (search_ctx->output_table != NULL) { + uint32_t state; + for (state = 0; state < search_ctx->state_count; state++) { + if (search_ctx->output_table[state].patterns != NULL) { + SCFree(search_ctx->output_table[state].patterns); + } + } + SCFree(search_ctx->output_table); + } + + SCFree(search_ctx); + mpm_ctx->ctx = NULL; + + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCACTileSearchCtx); +} + +/* + * Heavily optimized pattern matching routine for TILE-Gx. + */ + +#define SCHECK(x) ((x) > 0) +#define BUF_TYPE int32_t +// Extract byte N=0,1,2,3 from x +#define BYTE0(x) (((x)&0x000000ff) >> 0) +#define BYTE1(x) (((x)&0x0000ff00) >> 8) +#define BYTE2(x) (((x)&0x00ff0000) >> 16) +#define BYTE3(x) (((x)&0xff000000) >> 24) +#define EXTRA 4 // need 4 extra bytes to avoid OOB reads + +static int CheckMatch(const SCACTileSearchCtx *ctx, PrefilterRuleStore *pmq, const uint8_t *buf, + uint32_t buflen, uint16_t state, int i, int matches, uint8_t *mpm_bitarray) +{ + const SCACTilePatternList *pattern_list = ctx->pattern_list; + const uint8_t *buf_offset = buf + i + 1; // Lift out of loop + uint32_t no_of_entries = ctx->output_table[state].no_of_entries; + MpmPatternIndex *patterns = ctx->output_table[state].patterns; + uint32_t k; + + for (k = 0; k < no_of_entries; k++) { + MpmPatternIndex pindex = patterns[k] & 0x0FFFFFFF; + if (mpm_bitarray[pindex / 8] & (1 << (pindex % 8))) { + /* Pattern already seen by this MPM. */ + continue; + } + const SCACTilePatternList *pat = &pattern_list[pindex]; + const int offset = i - pat->patlen + 1; + if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) + continue; + + /* Double check case-sensitive match now. */ + if (patterns[k] >> 31) { + const uint16_t patlen = pat->patlen; + if (SCMemcmp(pat->cs, buf_offset - patlen, patlen) != 0) { + /* Case-sensitive match failed. */ + continue; + } + } + /* New match found */ + mpm_bitarray[pindex / 8] |= (1 << (pindex % 8)); + + /* Always add the Signature IDs, since they could be different in the current MPM + * than in a previous MPM on the same PMQ when finding the same pattern. + */ + PrefilterAddSids(pmq, pattern_list[pindex].sids, pattern_list[pindex].sids_size); + matches++; + } + + return matches; +} + +/** + * \brief The aho corasick search function. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + * \param pmq Pointer to the Pattern Matcher Queue to hold + * search matches. + * \param buf Buffer to be searched. + * \param buflen Buffer length. + * + * \retval matches Match count. + */ +uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen) +{ + const SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + + if (buflen == 0) + return 0; + + /* Context specific matching function. */ + return search_ctx->Search(search_ctx, mpm_thread_ctx, pmq, buf, buflen); +} + +/* This function handles (ctx->state_count >= 32767) */ +uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen) +{ + uint32_t i = 0; + int matches = 0; + + uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; + memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); + + const uint8_t *restrict xlate = ctx->translate_table; + register int state = 0; + int32_t(*state_table_u32)[256] = ctx->state_table; + for (i = 0; i < buflen; i++) { + state = state_table_u32[state & 0x00FFFFFF][xlate[buf[i]]]; + if (SCHECK(state)) { + DEBUG_VALIDATE_BUG_ON(state < 0 || state > UINT16_MAX); + matches = CheckMatch(ctx, pmq, buf, buflen, (uint16_t)state, i, matches, mpm_bitarray); + } + } /* for (i = 0; i < buflen; i++) */ + + return matches; +} + +/* + * Search with Alphabet size of 256 and 16-bit next-state entries. + * Next state entry has MSB as "match" and 15 LSB bits as next-state index. + */ +// y = 1<ctx; + SCACTileCtx *ctx = search_ctx->init_ctx; + + printf("MPM AC Information:\n"); + printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); + printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); + printf(" Sizeof:\n"); + printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); + printf(" SCACTileCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACTileCtx)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); + printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); + printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); + printf("Total states in the state table: %u\n", ctx->state_count); + printf("\n"); +} + +/************************** Mpm Registration ***************************/ + +/** + * \brief Register the aho-corasick mpm 'ks' originally developed by + * Ken Steele for Tilera Tile-Gx processor. + */ +void MpmACTileRegister(void) +{ + mpm_table[MPM_AC_KS].name = "ac-ks"; + mpm_table[MPM_AC_KS].InitCtx = SCACTileInitCtx; + mpm_table[MPM_AC_KS].DestroyCtx = SCACTileDestroyCtx; + mpm_table[MPM_AC_KS].AddPattern = SCACTileAddPatternCS; + mpm_table[MPM_AC_KS].AddPatternNocase = SCACTileAddPatternCI; + mpm_table[MPM_AC_KS].Prepare = SCACTilePreparePatterns; + mpm_table[MPM_AC_KS].Search = SCACTileSearch; + mpm_table[MPM_AC_KS].PrintCtx = SCACTilePrintInfo; + mpm_table[MPM_AC_KS].RegisterUnittests = SCACTileRegisterTests; +} + +/*************************************Unittests********************************/ + +#ifdef UNITTESTS +#include "detect-engine-alert.h" + +static int SCACTileTest01(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest02(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest03(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest04(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest05(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest06(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcd"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest07(void) +{ + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* should match 30 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); + /* should match 29 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); + /* should match 28 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); + /* 26 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); + /* 21 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); + PmqSetup(&pmq); + /* total matches: 135: 6 unique */ + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + FAIL_IF_NOT(cnt == 6); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + PASS; +} + +static int SCACTileTest08(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest09(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest10(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "abcdefgh" + "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest11(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) + goto end; + PmqSetup(&pmq); + + if (SCACTilePreparePatterns(&mpm_ctx) == -1) + goto end; + + result = 1; + + const char *buf = "he"; + result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "she"; + result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + buf = "his"; + result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "hers"; + result &= (SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + +end: + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest12(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest13(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest14(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest15(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest16(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABC"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABC"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest17(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzAB"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzAB"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest18(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + const char pat[] = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest19(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 */ + const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest20(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 */ + const char pat[] = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest21(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest22(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest23(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 0) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest24(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 1 */ + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest25(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest26(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "works"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest27(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "tone"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest28(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC_KS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACTilePreparePatterns(&mpm_ctx); + + const char *buf = "tONE"; + uint32_t cnt = SCACTileSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACTileDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTileTest29(void) +{ + uint8_t buf[] = "onetwothreefourfivesixseveneightnine"; + uint16_t buflen = sizeof(buf) - 1; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); + if (de_ctx->sig_list->next == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1) != 1) { + printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); + goto end; + } + if (PacketAlertCheck(p, 2) != 1) { + printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + } + + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +void SCACTileRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("SCACTileTest01", SCACTileTest01); + UtRegisterTest("SCACTileTest02", SCACTileTest02); + UtRegisterTest("SCACTileTest03", SCACTileTest03); + UtRegisterTest("SCACTileTest04", SCACTileTest04); + UtRegisterTest("SCACTileTest05", SCACTileTest05); + UtRegisterTest("SCACTileTest06", SCACTileTest06); + UtRegisterTest("SCACTileTest07", SCACTileTest07); + UtRegisterTest("SCACTileTest08", SCACTileTest08); + UtRegisterTest("SCACTileTest09", SCACTileTest09); + UtRegisterTest("SCACTileTest10", SCACTileTest10); + UtRegisterTest("SCACTileTest11", SCACTileTest11); + UtRegisterTest("SCACTileTest12", SCACTileTest12); + UtRegisterTest("SCACTileTest13", SCACTileTest13); + UtRegisterTest("SCACTileTest14", SCACTileTest14); + UtRegisterTest("SCACTileTest15", SCACTileTest15); + UtRegisterTest("SCACTileTest16", SCACTileTest16); + UtRegisterTest("SCACTileTest17", SCACTileTest17); + UtRegisterTest("SCACTileTest18", SCACTileTest18); + UtRegisterTest("SCACTileTest19", SCACTileTest19); + UtRegisterTest("SCACTileTest20", SCACTileTest20); + UtRegisterTest("SCACTileTest21", SCACTileTest21); + UtRegisterTest("SCACTileTest22", SCACTileTest22); + UtRegisterTest("SCACTileTest23", SCACTileTest23); + UtRegisterTest("SCACTileTest24", SCACTileTest24); + UtRegisterTest("SCACTileTest25", SCACTileTest25); + UtRegisterTest("SCACTileTest26", SCACTileTest26); + UtRegisterTest("SCACTileTest27", SCACTileTest27); + UtRegisterTest("SCACTileTest28", SCACTileTest28); + UtRegisterTest("SCACTileTest29", SCACTileTest29); +#endif +} + +#else /* we're big endian */ + +void MpmACTileRegister(void) +{ + /* no-op on big endian */ +} + +#endif /* little endian check */ diff --git a/src/util/mpm/mpm-ac-ks.h b/src/util/mpm/mpm-ac-ks.h new file mode 100644 index 000000000000..e4f9ac7a6f3b --- /dev/null +++ b/src/util/mpm/mpm-ac-ks.h @@ -0,0 +1,148 @@ +/* Copyright (C) 2013-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * \author Ken Steele + * + */ + +#ifndef __UTIL_MPM_AC_KS__H__ +#define __UTIL_MPM_AC_KS__H__ + +typedef struct SCACTilePatternList_ { + uint8_t *cs; + uint16_t patlen; + + uint16_t offset; + uint16_t depth; + + /* Pattern Id */ + uint32_t pid; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; +} SCACTilePatternList; + +typedef struct SCACTileOutputTable_ { + /* list of pattern indexes */ + MpmPatternIndex *patterns; + /* number of entries in pattern list */ + uint32_t no_of_entries; +} SCACTileOutputTable; + +struct SCACTileSearchCtx_; + +/* Reordered for Tilera cache */ +typedef struct SCACTileCtx_ { + + /* Convert input character to matching alphabet */ + uint8_t translate_table[256]; + + /* The all important memory hungry state_table. + * The size of each next-state is determined by bytes_per_state. + */ + void *state_table; + + /* Specialized search function based on size of data in delta + * tables. The alphabet size determines address shifting and the + * number of states could make the next state could be 16 bits or + * 32 bits. + */ + uint32_t (*Search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, + PrefilterRuleStore *, const uint8_t *, uint32_t); + + /* Function to set the next state based on size of next state + * (bytes_per_state). + */ + void (*SetNextState)(struct SCACTileCtx_ *ctx, int state, int aa, int new_state, int outputs); + + /* List of patterns that match for this state. Indexed by State Number */ + SCACTileOutputTable *output_table; + /* Indexed by MpmPatternIndex */ + SCACTilePatternList *pattern_list; + + /* pattern arrays. We need this only during the goto table + creation phase */ + MpmPattern **parray; + + /* goto_table, failure table and output table. Needed to create + * state_table. Will be freed, once we have created the + * state_table */ + int32_t (*goto_table)[256]; + int32_t *failure_table; + + /* Number of states used */ + uint32_t state_count; + /* Number of states allocated. */ + uint32_t allocated_state_count; + + uint32_t alpha_hist[256]; + /* Number of characters in the compressed alphabet. */ + uint16_t alphabet_size; + /* Space used to store compressed alphabet is the next + * larger or equal power-of-2. + */ + uint16_t alphabet_storage; + + /* How many bytes are used to store the next state. */ + uint8_t bytes_per_state; + +} SCACTileCtx; + +/* Only the stuff used at search time. This + * structure is created after all the patterns are added. + */ +typedef struct SCACTileSearchCtx_ { + + /* Specialized search function based on size of data in delta + * tables. The alphabet size determines address shifting and the + * number of states could make the next state could be 16 bits or + * 32 bits. + */ + uint32_t (*Search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, + PrefilterRuleStore *, const uint8_t *, uint32_t); + + /* Convert input character to matching alphabet */ + uint8_t translate_table[256]; + + /* the all important memory hungry state_table */ + void *state_table; + + /* List of patterns that match for this state. Indexed by State Number */ + SCACTileOutputTable *output_table; + SCACTilePatternList *pattern_list; + + /* Number of bytes in the array of bits. One bit per pattern in this MPM. */ + uint32_t mpm_bitarray_size; + + /* Number of states used */ + uint32_t state_count; + + uint32_t pattern_cnt; + + /* MPM Creation data, only used at initialization. */ + SCACTileCtx *init_ctx; + +} SCACTileSearchCtx; + +void MpmACTileRegister(void); + +#endif /* __UTIL_MPM_AC_KS__H__ */ diff --git a/src/util/mpm/mpm-ac.c b/src/util/mpm/mpm-ac.c new file mode 100644 index 000000000000..10d2e035acba --- /dev/null +++ b/src/util/mpm/mpm-ac.c @@ -0,0 +1,2127 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * First iteration of aho-corasick MPM from - + * + * Efficient String Matching: An Aid to Bibliographic Search + * Alfred V. Aho and Margaret J. Corasick + * + * - Uses the delta table for calculating transitions, instead of having + * separate goto and failure transitions. + * - If we cross 2 ** 16 states, we use 4 bytes in the transition table + * to hold each state, otherwise we use 2 bytes. + * - This version of the MPM is heavy on memory, but it performs well. + * If you can fit the ruleset with this mpm on your box without hitting + * swap, this is the MPM to go for. + * + * \todo - Do a proper analysis of our existing MPMs and suggest a good one based + * on the pattern distribution and the expected traffic(say http). + * - Tried out loop unrolling without any perf increase. Need to dig deeper. + * - Irrespective of whether we cross 2 ** 16 states or not,shift to using + * uint32_t for state type, so that we can integrate it's status as a + * final state or not in the topmost byte. We are already doing it if + * state_count is > 2 ** 16. + * - Test case-sensitive patterns if they have any ascii chars. If they + * don't treat them as nocase. + * - Carry out other optimizations we are working on. hashes, compression. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "../../detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-build.h" + +#include "../../conf.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/memcmp.h" +#include "util/mpm/mpm-ac.h" +#include "util/memcpy.h" +#include "util/validate.h" + +void SCACInitCtx(MpmCtx *); +void SCACDestroyCtx(MpmCtx *); +int SCACAddPatternCI( + MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int SCACAddPatternCS( + MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int SCACPreparePatterns(MpmCtx *mpm_ctx); +uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PrefilterRuleStore *pmq, + const uint8_t *buf, uint32_t buflen); +void SCACPrintInfo(MpmCtx *mpm_ctx); +void SCACRegisterTests(void); + +/* a placeholder to denote a failure transition in the goto table */ +#define SC_AC_FAIL (-1) + +#define STATE_QUEUE_CONTAINER_SIZE 65536 + +#define AC_CASE_MASK 0x80000000 +#define AC_PID_MASK 0x7FFFFFFF +#define AC_CASE_BIT 31 + +static int construct_both_16_and_32_state_tables = 0; + +/** + * \brief Helper structure used by AC during state table creation + */ +typedef struct StateQueue_ { + int32_t store[STATE_QUEUE_CONTAINER_SIZE]; + int top; + int bot; +} StateQueue; + +/** + * \internal + * \brief Initialize the AC context with user specified conf parameters. We + * aren't retrieving anything for AC conf now, but we will certainly + * need it, when we customize AC. + */ +static void SCACGetConfig(void) +{ + // ConfNode *ac_conf; + // const char *hash_val = NULL; + + // ConfNode *pm = ConfGetNode("pattern-matcher"); + + return; +} + +/** + * \internal + * \brief Check if size_t multiplication would overflow and perform operation + * if safe. In case of an overflow we exit(). + * + * \param a First size_t value to multiplicate. + * \param b Second size_t value to multiplicate. + * + * \retval The product of a and b, guaranteed to not overflow. + */ +static inline size_t SCACCheckSafeSizetMult(size_t a, size_t b) +{ + /* check for safety of multiplication operation */ + if (b > 0 && a > SIZE_MAX / b) { + SCLogError("%" PRIuMAX " * %" PRIuMAX " > %" PRIuMAX + " would overflow size_t calculating buffer size", + (uintmax_t)a, (uintmax_t)b, (uintmax_t)SIZE_MAX); + exit(EXIT_FAILURE); + } + return a * b; +} + +/** + * \internal + * \brief Initialize a new state in the goto and output tables. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval The state id, of the newly created state. + */ +static inline int SCACReallocState(SCACCtx *ctx, uint32_t cnt) +{ + void *ptmp = NULL; + size_t size = 0; + + /* reallocate space in the goto table to include a new state */ + size = SCACCheckSafeSizetMult((size_t)cnt, (size_t)ctx->single_state_size); + if (size > 0) + ptmp = SCRealloc(ctx->goto_table, size); + if (ptmp == NULL) { + SCFree(ctx->goto_table); + ctx->goto_table = NULL; + FatalError("Error allocating memory"); + } + ctx->goto_table = ptmp; + + /* reallocate space in the output table for the new state */ + size_t oldsize = SCACCheckSafeSizetMult((size_t)ctx->state_count, sizeof(SCACOutputTable)); + size = SCACCheckSafeSizetMult((size_t)cnt, sizeof(SCACOutputTable)); + SCLogDebug("oldsize %" PRIuMAX " size %" PRIuMAX " cnt %d ctx->state_count %u", + (uintmax_t)oldsize, (uintmax_t)size, cnt, ctx->state_count); + + ptmp = NULL; + if (size > 0) + ptmp = SCRealloc(ctx->output_table, size); + if (ptmp == NULL) { + SCFree(ctx->output_table); + ctx->output_table = NULL; + FatalError("Error allocating memory"); + } + ctx->output_table = ptmp; + + memset(((uint8_t *)ctx->output_table + oldsize), 0, (size - oldsize)); + + /* \todo using it temporarily now during dev, since I have restricted + * state var in SCACCtx->state_table to uint16_t. */ + // if (ctx->state_count > 65536) { + // printf("state count exceeded\n"); + // exit(EXIT_FAILURE); + // } + + return 0; // ctx->state_count++; +} + +/** \internal + * \brief Shrink state after setup is done + * + * Shrinks only the output table, goto table is freed after calling this + */ +static void SCACShrinkState(SCACCtx *ctx) +{ + /* reallocate space in the output table for the new state */ +#ifdef DEBUG + int oldsize = ctx->allocated_state_count * sizeof(SCACOutputTable); +#endif + int newsize = ctx->state_count * sizeof(SCACOutputTable); + + SCLogDebug("oldsize %d newsize %d ctx->allocated_state_count %u " + "ctx->state_count %u: shrink by %d bytes", + oldsize, newsize, ctx->allocated_state_count, ctx->state_count, oldsize - newsize); + + void *ptmp = SCRealloc(ctx->output_table, newsize); + if (ptmp == NULL) { + SCFree(ctx->output_table); + ctx->output_table = NULL; + FatalError("Error allocating memory"); + } + ctx->output_table = ptmp; +} + +static inline int SCACInitNewState(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + + /* Exponentially increase the allocated space when needed. */ + if (ctx->allocated_state_count < ctx->state_count + 1) { + if (ctx->allocated_state_count == 0) + ctx->allocated_state_count = 256; + else + ctx->allocated_state_count *= 2; + + SCACReallocState(ctx, ctx->allocated_state_count); + } +#if 0 + if (ctx->allocated_state_count > 260) { + SCACOutputTable *output_state = &ctx->output_table[260]; + SCLogInfo("output_state %p %p %u", output_state, output_state->pids, output_state->no_of_entries); + } +#endif + int ascii_code = 0; + /* set all transitions for the newly assigned state as FAIL transitions */ + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_FAIL; + } + + return ctx->state_count++; +} + +/** + * \internal + * \brief Adds a pid to the output table for a state. + * + * \param state The state to whose output table we should add the pid. + * \param pid The pattern id to add. + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) +{ + void *ptmp; + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + SCACOutputTable *output_state = &ctx->output_table[state]; + uint32_t i = 0; + + for (i = 0; i < output_state->no_of_entries; i++) { + if (output_state->pids[i] == pid) + return; + } + + output_state->no_of_entries++; + ptmp = SCRealloc(output_state->pids, output_state->no_of_entries * sizeof(uint32_t)); + if (ptmp == NULL) { + SCFree(output_state->pids); + output_state->pids = NULL; + FatalError("Error allocating memory"); + } + output_state->pids = ptmp; + + output_state->pids[output_state->no_of_entries - 1] = pid; + + return; +} + +/** + * \brief Helper function used by SCACCreateGotoTable. Adds a pattern to the + * goto table. + * + * \param pattern Pointer to the pattern. + * \param pattern_len Pattern length. + * \param pid The pattern id, that corresponds to this pattern. We + * need it to updated the output table for this pattern. + * \param mpm_ctx Pointer to the mpm context. + */ +static inline void SCACEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + int32_t state = 0; + int32_t newstate = 0; + int i = 0; + int p = 0; + + /* walk down the trie till we have a match for the pattern prefix */ + state = 0; + for (i = 0; i < pattern_len; i++) { + if (ctx->goto_table[state][pattern[i]] != SC_AC_FAIL) { + state = ctx->goto_table[state][pattern[i]]; + } else { + break; + } + } + + /* add the non-matching pattern suffix to the trie, from the last state + * we left off */ + for (p = i; p < pattern_len; p++) { + newstate = SCACInitNewState(mpm_ctx); + ctx->goto_table[state][pattern[p]] = newstate; + state = newstate; + } + + /* add this pattern id, to the output table of the last state, where the + * pattern ends in the trie */ + SCACSetOutputState(state, pid, mpm_ctx); + + return; +} + +/** + * \internal + * \brief Create the goto table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static inline void SCACCreateGotoTable(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + uint32_t i = 0; + + /* add each pattern to create the goto table */ + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + SCACEnter(ctx->parray[i]->ci, ctx->parray[i]->len, ctx->parray[i]->id, mpm_ctx); + } + + int ascii_code = 0; + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + if (ctx->goto_table[0][ascii_code] == SC_AC_FAIL) { + ctx->goto_table[0][ascii_code] = 0; + } + } + + return; +} + +static inline void SCACDetermineLevel1Gap(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + uint32_t u = 0; + + uint8_t map[256]; + memset(map, 0, sizeof(map)); + + for (u = 0; u < mpm_ctx->pattern_cnt; u++) + map[ctx->parray[u]->ci[0]] = 1; + + for (u = 0; u < 256; u++) { + if (map[u] == 0) + continue; + int32_t newstate = SCACInitNewState(mpm_ctx); + ctx->goto_table[0][u] = newstate; + } + + return; +} + +static inline int SCACStateQueueIsEmpty(StateQueue *q) +{ + if (q->top == q->bot) + return 1; + else + return 0; +} + +static inline void SCACEnqueue(StateQueue *q, int32_t state) +{ + int i = 0; + + /*if we already have this */ + for (i = q->bot; i < q->top; i++) { + if (q->store[i] == state) + return; + } + + q->store[q->top++] = state; + + if (q->top == STATE_QUEUE_CONTAINER_SIZE) + q->top = 0; + + if (q->top == q->bot) { + FatalError("Just ran out of space in the queue. Please file a bug report on this"); + } + + return; +} + +static inline int32_t SCACDequeue(StateQueue *q) +{ + if (q->bot == STATE_QUEUE_CONTAINER_SIZE) + q->bot = 0; + + if (q->bot == q->top) { + FatalError("StateQueue behaving weirdly. Please file a bug report on this"); + } + + return q->store[q->bot++]; +} + +/** + * \internal + * \brief Club the output data from 2 states and store it in the 1st state. + * dst_state_data = {dst_state_data} UNION {src_state_data} + * + * \param dst_state First state(also the destination) for the union operation. + * \param src_state Second state for the union operation. + * \param mpm_ctx Pointer to the mpm context. + */ +static inline void SCACClubOutputStates(int32_t dst_state, int32_t src_state, MpmCtx *mpm_ctx) +{ + void *ptmp; + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + uint32_t i = 0; + uint32_t j = 0; + + SCACOutputTable *output_dst_state = &ctx->output_table[dst_state]; + SCACOutputTable *output_src_state = &ctx->output_table[src_state]; + + for (i = 0; i < output_src_state->no_of_entries; i++) { + for (j = 0; j < output_dst_state->no_of_entries; j++) { + if (output_src_state->pids[i] == output_dst_state->pids[j]) { + break; + } + } + if (j == output_dst_state->no_of_entries) { + output_dst_state->no_of_entries++; + + ptmp = SCRealloc( + output_dst_state->pids, (output_dst_state->no_of_entries * sizeof(uint32_t))); + if (ptmp == NULL) { + SCFree(output_dst_state->pids); + output_dst_state->pids = NULL; + FatalError("Error allocating memory"); + } + output_dst_state->pids = ptmp; + + output_dst_state->pids[output_dst_state->no_of_entries - 1] = output_src_state->pids[i]; + } + } + + return; +} + +/** + * \internal + * \brief Create the failure table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static inline void SCACCreateFailureTable(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + int ascii_code = 0; + int32_t state = 0; + int32_t r_state = 0; + + StateQueue *q = SCCalloc(1, sizeof(StateQueue)); + if (q == NULL) { + FatalError("Error allocating memory"); + } + + /* allot space for the failure table. A failure entry in the table for + * every state(SCACCtx->state_count) */ + ctx->failure_table = SCCalloc(ctx->state_count, sizeof(int32_t)); + if (ctx->failure_table == NULL) { + FatalError("Error allocating memory"); + } + + /* add the failure transitions for the 0th state, and add every non-fail + * transition from the 0th state to the queue for further processing + * of failure states */ + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + int32_t temp_state = ctx->goto_table[0][ascii_code]; + if (temp_state != 0) { + SCACEnqueue(q, temp_state); + ctx->failure_table[temp_state] = 0; + } + } + + while (!SCACStateQueueIsEmpty(q)) { + /* pick up every state from the queue and add failure transitions */ + r_state = SCACDequeue(q); + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + int32_t temp_state = ctx->goto_table[r_state][ascii_code]; + if (temp_state == SC_AC_FAIL) + continue; + SCACEnqueue(q, temp_state); + state = ctx->failure_table[r_state]; + + while (ctx->goto_table[state][ascii_code] == SC_AC_FAIL) + state = ctx->failure_table[state]; + ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code]; + SCACClubOutputStates(temp_state, ctx->failure_table[temp_state], mpm_ctx); + } + } + SCFree(q); + + return; +} + +/** + * \internal + * \brief Create the delta table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static inline void SCACCreateDeltaTable(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + int ascii_code = 0; + int32_t r_state = 0; + + if ((ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { + ctx->state_table_u16 = SCCalloc(ctx->state_count, sizeof(*ctx->state_table_u16)); + if (ctx->state_table_u16 == NULL) { + FatalError("Error allocating memory"); + } + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (ctx->state_count * sizeof(*ctx->state_table_u16)); + + StateQueue *q = SCCalloc(1, sizeof(StateQueue)); + if (q == NULL) { + FatalError("Error allocating memory"); + } + + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + DEBUG_VALIDATE_BUG_ON(ctx->goto_table[0][ascii_code] > UINT16_MAX); + SC_AC_STATE_TYPE_U16 temp_state = (uint16_t)ctx->goto_table[0][ascii_code]; + ctx->state_table_u16[0][ascii_code] = temp_state; + if (temp_state != 0) + SCACEnqueue(q, temp_state); + } + + while (!SCACStateQueueIsEmpty(q)) { + r_state = SCACDequeue(q); + + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + int32_t temp_state = ctx->goto_table[r_state][ascii_code]; + if (temp_state != SC_AC_FAIL) { + SCACEnqueue(q, temp_state); + DEBUG_VALIDATE_BUG_ON(temp_state > UINT16_MAX); + ctx->state_table_u16[r_state][ascii_code] = (uint16_t)temp_state; + } else { + ctx->state_table_u16[r_state][ascii_code] = + ctx->state_table_u16[ctx->failure_table[r_state]][ascii_code]; + } + } + } + SCFree(q); + } + + if (!(ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { + /* create space for the state table. We could have used the existing goto + * table, but since we have it set to hold 32 bit state values, we will create + * a new state table here of type SC_AC_STATE_TYPE(current set to uint16_t) */ + ctx->state_table_u32 = SCCalloc(ctx->state_count, sizeof(*ctx->state_table_u32)); + if (ctx->state_table_u32 == NULL) { + FatalError("Error allocating memory"); + } + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (ctx->state_count * sizeof(*ctx->state_table_u32)); + + StateQueue *q = SCCalloc(1, sizeof(StateQueue)); + if (q == NULL) { + FatalError("Error allocating memory"); + } + + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + SC_AC_STATE_TYPE_U32 temp_state = ctx->goto_table[0][ascii_code]; + ctx->state_table_u32[0][ascii_code] = temp_state; + if (temp_state != 0) + SCACEnqueue(q, temp_state); + } + + while (!SCACStateQueueIsEmpty(q)) { + r_state = SCACDequeue(q); + + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + int32_t temp_state = ctx->goto_table[r_state][ascii_code]; + if (temp_state != SC_AC_FAIL) { + SCACEnqueue(q, temp_state); + ctx->state_table_u32[r_state][ascii_code] = temp_state; + } else { + ctx->state_table_u32[r_state][ascii_code] = + ctx->state_table_u32[ctx->failure_table[r_state]][ascii_code]; + } + } + } + SCFree(q); + } + + return; +} + +static inline void SCACClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + int ascii_code = 0; + uint32_t state = 0; + uint32_t temp_state = 0; + + if ((ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { + for (state = 0; state < ctx->state_count; state++) { + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + temp_state = ctx->state_table_u16[state & 0x7FFF][ascii_code]; + if (ctx->output_table[temp_state & 0x7FFF].no_of_entries != 0) + ctx->state_table_u16[state & 0x7FFF][ascii_code] |= (1 << 15); + } + } + } + + if (!(ctx->state_count < 32767) || construct_both_16_and_32_state_tables) { + for (state = 0; state < ctx->state_count; state++) { + for (ascii_code = 0; ascii_code < 256; ascii_code++) { + temp_state = ctx->state_table_u32[state & 0x00FFFFFF][ascii_code]; + if (ctx->output_table[temp_state & 0x00FFFFFF].no_of_entries != 0) + ctx->state_table_u32[state & 0x00FFFFFF][ascii_code] |= (1 << 24); + } + } + } + + return; +} + +static inline void SCACInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + uint32_t state = 0; + uint32_t k = 0; + + for (state = 0; state < ctx->state_count; state++) { + if (ctx->output_table[state].no_of_entries == 0) + continue; + + for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { + if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { + ctx->output_table[state].pids[k] &= AC_PID_MASK; + ctx->output_table[state].pids[k] |= ((uint32_t)1 << AC_CASE_BIT); + } + } + } + + return; +} + +#if 0 +static void SCACPrintDeltaTable(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + int i = 0, j = 0; + + printf("##############Delta Table##############\n"); + for (i = 0; i < ctx->state_count; i++) { + printf("%d: \n", i); + for (j = 0; j < 256; j++) { + if (SCACGetDelta(i, j, mpm_ctx) != 0) { + printf(" %c -> %d\n", j, SCACGetDelta(i, j, mpm_ctx)); + } + } + } + + return; +} +#endif + +/** + * \brief Process the patterns and prepare the state table. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACPrepareStateTable(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + + /* create the 0th state in the goto table and output_table */ + SCACInitNewState(mpm_ctx); + + SCACDetermineLevel1Gap(mpm_ctx); + + /* create the goto table */ + SCACCreateGotoTable(mpm_ctx); + /* create the failure table */ + SCACCreateFailureTable(mpm_ctx); + /* create the final state(delta) table */ + SCACCreateDeltaTable(mpm_ctx); + /* club the output state presence with delta transition entries */ + SCACClubOutputStatePresenceWithDeltaTable(mpm_ctx); + + /* club nocase entries */ + SCACInsertCaseSensitiveEntriesForPatterns(mpm_ctx); + + /* shrink the memory */ + SCACShrinkState(ctx); + +#if 0 + SCACPrintDeltaTable(mpm_ctx); +#endif + + /* we don't need these anymore */ + SCFree(ctx->goto_table); + ctx->goto_table = NULL; + SCFree(ctx->failure_table); + ctx->failure_table = NULL; + + return; +} + +/** + * \brief Process the patterns added to the mpm, and create the internal tables. + * + * \param mpm_ctx Pointer to the mpm context. + */ +int SCACPreparePatterns(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + + if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) { + SCLogDebug("no patterns supplied to this mpm_ctx"); + return 0; + } + + /* alloc the pattern array */ + ctx->parray = (MpmPattern **)SCCalloc(mpm_ctx->pattern_cnt, sizeof(MpmPattern *)); + if (ctx->parray == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); + + /* populate it with the patterns in the hash */ + uint32_t i = 0, p = 0; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; + while (node != NULL) { + nnode = node->next; + node->next = NULL; + ctx->parray[p++] = node; + node = nnode; + } + } + + /* we no longer need the hash, so free it's memory */ + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; + + /* the memory consumed by a single state in our goto table */ + ctx->single_state_size = sizeof(int32_t) * 256; + + /* handle no case patterns */ + ctx->pid_pat_list = SCCalloc((mpm_ctx->max_pat_id + 1), sizeof(SCACPatternList)); + if (ctx->pid_pat_list == NULL) { + FatalError("Error allocating memory"); + } + + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { + ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); + if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { + FatalError("Error allocating memory"); + } + memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, ctx->parray[i]->original_pat, + ctx->parray[i]->len); + ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; + } + ctx->pid_pat_list[ctx->parray[i]->id].offset = ctx->parray[i]->offset; + ctx->pid_pat_list[ctx->parray[i]->id].depth = ctx->parray[i]->depth; + + /* ACPatternList now owns this memory */ + // SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size); + ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; + ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; + + ctx->parray[i]->sids_size = 0; + ctx->parray[i]->sids = NULL; + } + + /* prepare the state table required by AC */ + SCACPrepareStateTable(mpm_ctx); + + /* free all the stored patterns. Should save us a good 100-200 mbs */ + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (ctx->parray[i] != NULL) { + MpmFreePattern(mpm_ctx, ctx->parray[i]); + } + } + SCFree(ctx->parray); + ctx->parray = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); + + ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1; + SCLogDebug("ctx->pattern_id_bitarray_size %u", ctx->pattern_id_bitarray_size); + + return 0; + +error: + return -1; +} + +/** + * \brief Initialize the AC context. + * + * \param mpm_ctx Mpm context. + */ +void SCACInitCtx(MpmCtx *mpm_ctx) +{ + if (mpm_ctx->ctx != NULL) + return; + + mpm_ctx->ctx = SCCalloc(1, sizeof(SCACCtx)); + if (mpm_ctx->ctx == NULL) { + exit(EXIT_FAILURE); + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCACCtx); + + /* initialize the hash we use to speed up pattern insertions */ + mpm_ctx->init_hash = SCCalloc(MPM_INIT_HASH_SIZE, sizeof(MpmPattern *)); + if (mpm_ctx->init_hash == NULL) { + exit(EXIT_FAILURE); + } + + /* get conf values for AC from our yaml file. We have no conf values for + * now. We will certainly need this, as we develop the algo */ + SCACGetConfig(); + + SCReturn; +} + +/** + * \brief Destroy the mpm context. + * + * \param mpm_ctx Pointer to the mpm context. + */ +void SCACDestroyCtx(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + if (ctx == NULL) + return; + + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *)); + } + + if (ctx->parray != NULL) { + uint32_t i; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (ctx->parray[i] != NULL) { + MpmFreePattern(mpm_ctx, ctx->parray[i]); + } + } + + SCFree(ctx->parray); + ctx->parray = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); + } + + if (ctx->state_table_u16 != NULL) { + SCFree(ctx->state_table_u16); + ctx->state_table_u16 = NULL; + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_STATE_TYPE_U16) * 256); + } + if (ctx->state_table_u32 != NULL) { + SCFree(ctx->state_table_u32); + ctx->state_table_u32 = NULL; + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_STATE_TYPE_U32) * 256); + } + + if (ctx->output_table != NULL) { + uint32_t state_count; + for (state_count = 0; state_count < ctx->state_count; state_count++) { + if (ctx->output_table[state_count].pids != NULL) { + SCFree(ctx->output_table[state_count].pids); + } + } + SCFree(ctx->output_table); + } + + if (ctx->pid_pat_list != NULL) { + uint32_t i; + for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) { + if (ctx->pid_pat_list[i].cs != NULL) + SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pid_pat_list[i].sids != NULL) + SCFree(ctx->pid_pat_list[i].sids); + } + SCFree(ctx->pid_pat_list); + } + + SCFree(mpm_ctx->ctx); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCACCtx); + + return; +} + +/** + * \brief The aho corasick search function. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + * \param pmq Pointer to the Pattern Matcher Queue to hold + * search matches. + * \param buf Buffer to be searched. + * \param buflen Buffer length. + * + * \retval matches Match count: counts unique matches per pattern. + */ +uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PrefilterRuleStore *pmq, + const uint8_t *buf, uint32_t buflen) +{ + const SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + uint32_t i = 0; + int matches = 0; + + /* \todo tried loop unrolling with register var, with no perf increase. Need + * to dig deeper */ + /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ + const SCACPatternList *pid_pat_list = ctx->pid_pat_list; + + uint8_t bitarray[ctx->pattern_id_bitarray_size]; + memset(bitarray, 0, ctx->pattern_id_bitarray_size); + + if (ctx->state_count < 32767) { + register SC_AC_STATE_TYPE_U16 state = 0; + SC_AC_STATE_TYPE_U16(*state_table_u16)[256] = ctx->state_table_u16; + for (i = 0; i < buflen; i++) { + state = state_table_u16[state & 0x7FFF][u8_tolower(buf[i])]; + if (state & 0x8000) { + uint32_t no_of_entries = ctx->output_table[state & 0x7FFF].no_of_entries; + uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; + uint32_t k; + for (k = 0; k < no_of_entries; k++) { + if (pids[k] & AC_CASE_MASK) { + uint32_t lower_pid = pids[k] & AC_PID_MASK; + const SCACPatternList *pat = &pid_pat_list[lower_pid]; + const int offset = i - pat->patlen + 1; + + if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) + continue; + + if (SCMemcmp(pat->cs, buf + offset, pat->patlen) != 0) { + /* inside loop */ + continue; + } + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { + ; + } else { + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + PrefilterAddSids(pmq, pat->sids, pat->sids_size); + matches++; + } + } else { + const SCACPatternList *pat = &pid_pat_list[pids[k]]; + const int offset = i - pat->patlen + 1; + + if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) + continue; + + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + ; + } else { + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + PrefilterAddSids(pmq, pat->sids, pat->sids_size); + matches++; + } + } + // loop1: + //; + } + } + } /* for (i = 0; i < buflen; i++) */ + + } else { + register SC_AC_STATE_TYPE_U32 state = 0; + SC_AC_STATE_TYPE_U32(*state_table_u32)[256] = ctx->state_table_u32; + for (i = 0; i < buflen; i++) { + state = state_table_u32[state & 0x00FFFFFF][u8_tolower(buf[i])]; + if (state & 0xFF000000) { + uint32_t no_of_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; + uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; + uint32_t k; + for (k = 0; k < no_of_entries; k++) { + if (pids[k] & AC_CASE_MASK) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + const SCACPatternList *pat = &pid_pat_list[lower_pid]; + const int offset = i - pat->patlen + 1; + + if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) + continue; + + if (SCMemcmp(pat->cs, buf + offset, pat->patlen) != 0) { + /* inside loop */ + continue; + } + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { + ; + } else { + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + PrefilterAddSids(pmq, pat->sids, pat->sids_size); + matches++; + } + } else { + const SCACPatternList *pat = &pid_pat_list[pids[k]]; + const int offset = i - pat->patlen + 1; + + if (offset < (int)pat->offset || (pat->depth && i > pat->depth)) + continue; + + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + ; + } else { + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + PrefilterAddSids(pmq, pat->sids, pat->sids_size); + matches++; + } + } + // loop1: + //; + } + } + } /* for (i = 0; i < buflen; i++) */ + } + + return matches; +} + +/** + * \brief Add a case insensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patnen The pattern length. + * \param offset Ignored. + * \param depth Ignored. + * \param pid The pattern id. + * \param sid Ignored. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + flags |= MPM_PATTERN_FLAG_NOCASE; + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +/** + * \brief Add a case sensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patnen The pattern length. + * \param offset Ignored. + * \param depth Ignored. + * \param pid The pattern id. + * \param sid Ignored. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCACAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +void SCACPrintInfo(MpmCtx *mpm_ctx) +{ + SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + + printf("MPM AC Information:\n"); + printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); + printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); + printf(" Sizeof:\n"); + printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); + printf(" SCACCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACCtx)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); + printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); + printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); + printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count); + printf("\n"); + + return; +} + +/************************** Mpm Registration ***************************/ + +/** + * \brief Register the aho-corasick mpm. + */ +void MpmACRegister(void) +{ + mpm_table[MPM_AC].name = "ac"; + mpm_table[MPM_AC].InitCtx = SCACInitCtx; + mpm_table[MPM_AC].DestroyCtx = SCACDestroyCtx; + mpm_table[MPM_AC].AddPattern = SCACAddPatternCS; + mpm_table[MPM_AC].AddPatternNocase = SCACAddPatternCI; + mpm_table[MPM_AC].Prepare = SCACPreparePatterns; + mpm_table[MPM_AC].Search = SCACSearch; + mpm_table[MPM_AC].PrintCtx = SCACPrintInfo; + mpm_table[MPM_AC].RegisterUnittests = SCACRegisterTests; + + return; +} + +/*************************************Unittests********************************/ + +#ifdef UNITTESTS +#include "detect-engine-alert.h" + +static int SCACTest01(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest02(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest03(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest04(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest05(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest06(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcd"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest07(void) +{ + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* should match 30 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); + /* should match 29 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); + /* should match 28 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); + /* 26 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); + /* 21 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); + PmqSetup(&pmq); + /* total matches: 135: unique matches: 6 */ + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + FAIL_IF_NOT(cnt == 6); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + PASS; +} + +static int SCACTest08(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest09(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest10(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "abcdefgh" + "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest11(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) + goto end; + PmqSetup(&pmq); + + if (SCACPreparePatterns(&mpm_ctx) == -1) + goto end; + + result = 1; + + const char *buf = "he"; + result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "she"; + result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + buf = "his"; + result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "hers"; + result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + +end: + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest12(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest13(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest14(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest15(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest16(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABC"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABC"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest17(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzAB"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzAB"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest18(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + const char pat[] = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest19(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 */ + const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest20(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 */ + const char pat[] = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest21(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest22(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest23(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 0) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest24(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 1 */ + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest25(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest26(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "works"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest27(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "tone"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest28(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_AC); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACPreparePatterns(&mpm_ctx); + + const char *buf = "tONE"; + uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACTest29(void) +{ + uint8_t buf[] = "onetwothreefourfivesixseveneightnine"; + uint16_t buflen = sizeof(buf) - 1; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); + if (de_ctx->sig_list->next == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1) != 1) { + printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); + goto end; + } + if (PacketAlertCheck(p, 2) != 1) { + printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + } + + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +void SCACRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("SCACTest01", SCACTest01); + UtRegisterTest("SCACTest02", SCACTest02); + UtRegisterTest("SCACTest03", SCACTest03); + UtRegisterTest("SCACTest04", SCACTest04); + UtRegisterTest("SCACTest05", SCACTest05); + UtRegisterTest("SCACTest06", SCACTest06); + UtRegisterTest("SCACTest07", SCACTest07); + UtRegisterTest("SCACTest08", SCACTest08); + UtRegisterTest("SCACTest09", SCACTest09); + UtRegisterTest("SCACTest10", SCACTest10); + UtRegisterTest("SCACTest11", SCACTest11); + UtRegisterTest("SCACTest12", SCACTest12); + UtRegisterTest("SCACTest13", SCACTest13); + UtRegisterTest("SCACTest14", SCACTest14); + UtRegisterTest("SCACTest15", SCACTest15); + UtRegisterTest("SCACTest16", SCACTest16); + UtRegisterTest("SCACTest17", SCACTest17); + UtRegisterTest("SCACTest18", SCACTest18); + UtRegisterTest("SCACTest19", SCACTest19); + UtRegisterTest("SCACTest20", SCACTest20); + UtRegisterTest("SCACTest21", SCACTest21); + UtRegisterTest("SCACTest22", SCACTest22); + UtRegisterTest("SCACTest23", SCACTest23); + UtRegisterTest("SCACTest24", SCACTest24); + UtRegisterTest("SCACTest25", SCACTest25); + UtRegisterTest("SCACTest26", SCACTest26); + UtRegisterTest("SCACTest27", SCACTest27); + UtRegisterTest("SCACTest28", SCACTest28); + UtRegisterTest("SCACTest29", SCACTest29); +#endif + + return; +} diff --git a/src/util/mpm/mpm-ac.h b/src/util/mpm/mpm-ac.h new file mode 100644 index 000000000000..bb588a230bf5 --- /dev/null +++ b/src/util/mpm/mpm-ac.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + */ + +#ifndef __UTIL_MPM_AC__H__ +#define __UTIL_MPM_AC__H__ + +#include "util/mpm/mpm.h" + +#define SC_AC_STATE_TYPE_U16 uint16_t +#define SC_AC_STATE_TYPE_U32 uint32_t + +typedef struct SCACPatternList_ { + uint8_t *cs; + uint16_t patlen; + + uint16_t offset; + uint16_t depth; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; +} SCACPatternList; + +typedef struct SCACOutputTable_ { + /* list of pattern sids */ + uint32_t *pids; + /* no of entries we have in pids */ + uint32_t no_of_entries; +} SCACOutputTable; + +typedef struct SCACCtx_ { + /* pattern arrays. We need this only during the goto table creation phase */ + MpmPattern **parray; + + /* no of states used by ac */ + uint32_t state_count; + + uint32_t pattern_id_bitarray_size; + + /* the all important memory hungry state_table */ + SC_AC_STATE_TYPE_U16 (*state_table_u16)[256]; + /* the all important memory hungry state_table */ + SC_AC_STATE_TYPE_U32 (*state_table_u32)[256]; + + /* goto_table, failure table and output table. Needed to create state_table. + * Will be freed, once we have created the state_table */ + int32_t (*goto_table)[256]; + int32_t *failure_table; + SCACOutputTable *output_table; + SCACPatternList *pid_pat_list; + + /* the size of each state */ + uint32_t single_state_size; + + uint32_t allocated_state_count; + +} SCACCtx; + +void MpmACRegister(void); + +#endif /* __UTIL_MPM_AC__H__ */ diff --git a/src/util/mpm/mpm-hs.c b/src/util/mpm/mpm-hs.c new file mode 100644 index 000000000000..62e94796411e --- /dev/null +++ b/src/util/mpm/mpm-hs.c @@ -0,0 +1,2125 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jim Xu + * \author Justin Viiret + * + * MPM pattern matcher that calls the Hyperscan regex matcher. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "../../detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-build.h" + +#include "../../conf.h" +#include "util/debug.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/memcmp.h" +#include "util/mpm/mpm-hs.h" +#include "util/memcpy.h" +#include "util/hash.h" +#include "util/hash-lookup3.h" +#include "util/hyperscan.h" + +#ifdef BUILD_HYPERSCAN + +#include + +void SCHSInitCtx(MpmCtx *); +void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *); +void SCHSDestroyCtx(MpmCtx *); +void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); +int SCHSAddPatternCI( + MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int SCHSAddPatternCS( + MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); +int SCHSPreparePatterns(MpmCtx *mpm_ctx); +uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PrefilterRuleStore *pmq, + const uint8_t *buf, const uint32_t buflen); +void SCHSPrintInfo(MpmCtx *mpm_ctx); +void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); +void SCHSRegisterTests(void); + +/* size of the hash table used to speed up pattern insertions initially */ +#define INIT_HASH_SIZE 65536 + +/* Initial size of the global database hash (used for de-duplication). */ +#define INIT_DB_HASH_SIZE 1000 + +/* Global prototype scratch, built incrementally as Hyperscan databases are + * built and then cloned for each thread context. Access is serialised via + * g_scratch_proto_mutex. */ +static hs_scratch_t *g_scratch_proto = NULL; +static SCMutex g_scratch_proto_mutex = SCMUTEX_INITIALIZER; + +/* Global hash table of Hyperscan databases, used for de-duplication. Access is + * serialised via g_db_table_mutex. */ +static HashTable *g_db_table = NULL; +static SCMutex g_db_table_mutex = SCMUTEX_INITIALIZER; + +/** + * \internal + * \brief Wraps SCMalloc (which is a macro) so that it can be passed to + * hs_set_allocator() for Hyperscan's use. + */ +static void *SCHSMalloc(size_t size) +{ + return SCMalloc(size); +} + +/** + * \internal + * \brief Wraps SCFree (which is a macro) so that it can be passed to + * hs_set_allocator() for Hyperscan's use. + */ +static void SCHSFree(void *ptr) +{ + SCFree(ptr); +} + +/** \brief Register Suricata malloc/free with Hyperscan. + * + * Requests that Hyperscan use Suricata's allocator for allocation of + * databases, scratch space, etc. + */ +static void SCHSSetAllocators(void) +{ + hs_error_t err = hs_set_allocator(SCHSMalloc, SCHSFree); + if (err != HS_SUCCESS) { + FatalError("Failed to set Hyperscan allocator."); + } +} + +/** + * \internal + * \brief Creates a hash of the pattern. We use it for the hashing process + * during the initial pattern insertion time, to cull duplicate sigs. + * + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline uint32_t SCHSInitHashRaw(uint8_t *pat, uint16_t patlen) +{ + uint32_t hash = patlen * pat[0]; + if (patlen > 1) + hash += pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +/** + * \internal + * \brief Looks up a pattern. We use it for the hashing process during + * the initial pattern insertion time, to cull duplicate sigs. + * + * \param ctx Pointer to the HS ctx. + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * \param flags Flags. We don't need this. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline SCHSPattern *SCHSInitHashLookup(SCHSCtx *ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, char flags, uint32_t pid) +{ + uint32_t hash = SCHSInitHashRaw(pat, patlen); + + if (ctx->init_hash == NULL) { + return NULL; + } + + SCHSPattern *t = ctx->init_hash[hash]; + for (; t != NULL; t = t->next) { + /* Since Hyperscan uses offset/depth, we must distinguish between + * patterns with the same ID but different offset/depth here. */ + if (t->id == pid && t->offset == offset && t->depth == depth) { + BUG_ON(t->len != patlen); + BUG_ON(SCMemcmp(t->original_pat, pat, patlen) != 0); + return t; + } + } + + return NULL; +} + +/** + * \internal + * \brief Allocates a new pattern instance. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval p Pointer to the newly created pattern. + */ +static inline SCHSPattern *SCHSAllocPattern(MpmCtx *mpm_ctx) +{ + SCHSPattern *p = SCCalloc(1, sizeof(SCHSPattern)); + if (unlikely(p == NULL)) { + exit(EXIT_FAILURE); + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCHSPattern); + + return p; +} + +/** + * \internal + * \brief Used to free SCHSPattern instances. + * + * \param mpm_ctx Pointer to the mpm context. + * \param p Pointer to the SCHSPattern instance to be freed. + * \param free Free the above pointer or not. + */ +static inline void SCHSFreePattern(MpmCtx *mpm_ctx, SCHSPattern *p) +{ + if (p != NULL && p->original_pat != NULL) { + SCFree(p->original_pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p != NULL && p->sids != NULL) { + SCFree(p->sids); + } + + if (p != NULL) { + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCHSPattern); + } +} + +static inline uint32_t SCHSInitHash(SCHSPattern *p) +{ + uint32_t hash = p->len * p->original_pat[0]; + if (p->len > 1) + hash += p->original_pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +static inline int SCHSInitHashAdd(SCHSCtx *ctx, SCHSPattern *p) +{ + uint32_t hash = SCHSInitHash(p); + + if (ctx->init_hash == NULL) { + return -1; + } + + if (ctx->init_hash[hash] == NULL) { + ctx->init_hash[hash] = p; + return 0; + } + + SCHSPattern *tt = NULL; + SCHSPattern *t = ctx->init_hash[hash]; + + /* get the list tail */ + do { + tt = t; + t = t->next; + } while (t != NULL); + + tt->next = p; + + return 0; +} + +/** + * \internal + * \brief Add a pattern to the mpm-hs context. + * + * \param mpm_ctx Mpm context. + * \param pat Pointer to the pattern. + * \param patlen Length of the pattern. + * \param pid Pattern id + * \param sid Signature id (internal id). + * \param flags Pattern's MPM_PATTERN_* flags. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int SCHSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + if (offset != 0) { + flags |= MPM_PATTERN_FLAG_OFFSET; + } + if (depth != 0) { + flags |= MPM_PATTERN_FLAG_DEPTH; + } + + if (patlen == 0) { + SCLogWarning("pattern length 0"); + return 0; + } + + /* check if we have already inserted this pattern */ + SCHSPattern *p = SCHSInitHashLookup(ctx, pat, patlen, offset, depth, flags, pid); + if (p == NULL) { + SCLogDebug("Allocing new pattern"); + + /* p will never be NULL */ + p = SCHSAllocPattern(mpm_ctx); + + p->len = patlen; + p->flags = flags; + p->id = pid; + + p->offset = offset; + p->depth = depth; + + p->original_pat = SCMalloc(patlen); + if (p->original_pat == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->original_pat, pat, patlen); + + /* put in the pattern hash */ + if (SCHSInitHashAdd(ctx, p) != 0) + goto error; + + mpm_ctx->pattern_cnt++; + + if (!(mpm_ctx->flags & MPMCTX_FLAGS_NODEPTH)) { + if (depth) { + mpm_ctx->maxdepth = MAX(mpm_ctx->maxdepth, depth); + SCLogDebug("%p: depth %u max %u", mpm_ctx, depth, mpm_ctx->maxdepth); + } else { + mpm_ctx->flags |= MPMCTX_FLAGS_NODEPTH; + mpm_ctx->maxdepth = 0; + SCLogDebug("%p: alas, no depth for us", mpm_ctx); + } + } + + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + + if (mpm_ctx->minlen == 0) { + mpm_ctx->minlen = patlen; + } else { + if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; + } + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } + } + + return 0; + +error: + SCHSFreePattern(mpm_ctx, p); + return -1; +} + +/** + * \brief Pattern database information used only as input to the Hyperscan + * compiler. + */ +typedef struct SCHSCompileData_ { + unsigned int *ids; + unsigned int *flags; + char **expressions; + hs_expr_ext_t **ext; + unsigned int pattern_cnt; +} SCHSCompileData; + +static SCHSCompileData *SCHSAllocCompileData(unsigned int pattern_cnt) +{ + SCHSCompileData *cd = SCCalloc(pattern_cnt, sizeof(SCHSCompileData)); + if (cd == NULL) { + goto error; + } + + cd->pattern_cnt = pattern_cnt; + + cd->ids = SCCalloc(pattern_cnt, sizeof(unsigned int)); + if (cd->ids == NULL) { + goto error; + } + + cd->flags = SCCalloc(pattern_cnt, sizeof(unsigned int)); + if (cd->flags == NULL) { + goto error; + } + + cd->expressions = SCCalloc(pattern_cnt, sizeof(char *)); + if (cd->expressions == NULL) { + goto error; + } + + cd->ext = SCCalloc(pattern_cnt, sizeof(hs_expr_ext_t *)); + if (cd->ext == NULL) { + goto error; + } + + return cd; + +error: + SCLogDebug("SCHSCompileData alloc failed"); + if (cd) { + SCFree(cd->ids); + SCFree(cd->flags); + SCFree(cd->expressions); + SCFree(cd->ext); + SCFree(cd); + } + return NULL; +} + +static void SCHSFreeCompileData(SCHSCompileData *cd) +{ + if (cd == NULL) { + return; + } + + SCFree(cd->ids); + SCFree(cd->flags); + if (cd->expressions) { + for (unsigned int i = 0; i < cd->pattern_cnt; i++) { + SCFree(cd->expressions[i]); + } + SCFree(cd->expressions); + } + if (cd->ext) { + for (unsigned int i = 0; i < cd->pattern_cnt; i++) { + SCFree(cd->ext[i]); + } + SCFree(cd->ext); + } + SCFree(cd); +} + +typedef struct PatternDatabase_ { + SCHSPattern **parray; + hs_database_t *hs_db; + uint32_t pattern_cnt; + + /* Reference count: number of MPM contexts using this pattern database. */ + uint32_t ref_cnt; +} PatternDatabase; + +static uint32_t SCHSPatternHash(const SCHSPattern *p, uint32_t hash) +{ + BUG_ON(p->original_pat == NULL); + BUG_ON(p->sids == NULL); + + hash = hashlittle_safe(&p->len, sizeof(p->len), hash); + hash = hashlittle_safe(&p->flags, sizeof(p->flags), hash); + hash = hashlittle_safe(p->original_pat, p->len, hash); + hash = hashlittle_safe(&p->id, sizeof(p->id), hash); + hash = hashlittle_safe(&p->offset, sizeof(p->offset), hash); + hash = hashlittle_safe(&p->depth, sizeof(p->depth), hash); + hash = hashlittle_safe(&p->sids_size, sizeof(p->sids_size), hash); + hash = hashlittle_safe(p->sids, p->sids_size * sizeof(SigIntId), hash); + return hash; +} + +static char SCHSPatternCompare(const SCHSPattern *p1, const SCHSPattern *p2) +{ + if ((p1->len != p2->len) || (p1->flags != p2->flags) || (p1->id != p2->id) || + (p1->offset != p2->offset) || (p1->depth != p2->depth) || + (p1->sids_size != p2->sids_size)) { + return 0; + } + + if (SCMemcmp(p1->original_pat, p2->original_pat, p1->len) != 0) { + return 0; + } + + if (SCMemcmp(p1->sids, p2->sids, p1->sids_size * sizeof(p1->sids[0])) != 0) { + return 0; + } + + return 1; +} + +static uint32_t PatternDatabaseHash(HashTable *ht, void *data, uint16_t len) +{ + const PatternDatabase *pd = data; + uint32_t hash = 0; + hash = hashword(&pd->pattern_cnt, 1, hash); + + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + hash = SCHSPatternHash(pd->parray[i], hash); + } + + hash %= ht->array_size; + return hash; +} + +static char PatternDatabaseCompare(void *data1, uint16_t len1, void *data2, uint16_t len2) +{ + const PatternDatabase *pd1 = data1; + const PatternDatabase *pd2 = data2; + + if (pd1->pattern_cnt != pd2->pattern_cnt) { + return 0; + } + + for (uint32_t i = 0; i < pd1->pattern_cnt; i++) { + if (SCHSPatternCompare(pd1->parray[i], pd2->parray[i]) == 0) { + return 0; + } + } + + return 1; +} + +static void PatternDatabaseFree(PatternDatabase *pd) +{ + BUG_ON(pd->ref_cnt != 0); + + if (pd->parray != NULL) { + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + SCHSPattern *p = pd->parray[i]; + if (p != NULL) { + SCFree(p->original_pat); + SCFree(p->sids); + SCFree(p); + } + } + SCFree(pd->parray); + } + + hs_free_database(pd->hs_db); + + SCFree(pd); +} + +static void PatternDatabaseTableFree(void *data) +{ + /* Stub function handed to hash table; actual freeing of PatternDatabase + * structures is done in MPM destruction when the ref_cnt drops to zero. */ +} + +static PatternDatabase *PatternDatabaseAlloc(uint32_t pattern_cnt) +{ + PatternDatabase *pd = SCCalloc(1, sizeof(PatternDatabase)); + if (pd == NULL) { + return NULL; + } + pd->pattern_cnt = pattern_cnt; + pd->ref_cnt = 0; + pd->hs_db = NULL; + + /* alloc the pattern array */ + pd->parray = (SCHSPattern **)SCCalloc(pd->pattern_cnt, sizeof(SCHSPattern *)); + if (pd->parray == NULL) { + SCFree(pd); + return NULL; + } + + return pd; +} + +/** + * \brief Process the patterns added to the mpm, and create the internal tables. + * + * \param mpm_ctx Pointer to the mpm context. + */ +int SCHSPreparePatterns(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { + SCLogDebug("no patterns supplied to this mpm_ctx"); + return 0; + } + + hs_error_t err; + hs_compile_error_t *compile_err = NULL; + SCHSCompileData *cd = NULL; + PatternDatabase *pd = NULL; + + cd = SCHSAllocCompileData(mpm_ctx->pattern_cnt); + if (cd == NULL) { + goto error; + } + + pd = PatternDatabaseAlloc(mpm_ctx->pattern_cnt); + if (pd == NULL) { + goto error; + } + + /* populate the pattern array with the patterns in the hash */ + for (uint32_t i = 0, p = 0; i < INIT_HASH_SIZE; i++) { + SCHSPattern *node = ctx->init_hash[i], *nnode = NULL; + while (node != NULL) { + nnode = node->next; + node->next = NULL; + pd->parray[p++] = node; + node = nnode; + } + } + + /* we no longer need the hash, so free its memory */ + SCFree(ctx->init_hash); + ctx->init_hash = NULL; + + /* Serialise whole database compilation as a relatively easy way to ensure + * dedupe is safe. */ + SCMutexLock(&g_db_table_mutex); + + /* Init global pattern database hash if necessary. */ + if (g_db_table == NULL) { + g_db_table = HashTableInit(INIT_DB_HASH_SIZE, PatternDatabaseHash, PatternDatabaseCompare, + PatternDatabaseTableFree); + if (g_db_table == NULL) { + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + } + + /* Check global hash table to see if we've seen this pattern database + * before, and reuse the Hyperscan database if so. */ + PatternDatabase *pd_cached = HashTableLookup(g_db_table, pd, 1); + + if (pd_cached != NULL) { + SCLogDebug("Reusing cached database %p with %" PRIu32 " patterns (ref_cnt=%" PRIu32 ")", + pd_cached->hs_db, pd_cached->pattern_cnt, pd_cached->ref_cnt); + pd_cached->ref_cnt++; + ctx->pattern_db = pd_cached; + SCMutexUnlock(&g_db_table_mutex); + PatternDatabaseFree(pd); + SCHSFreeCompileData(cd); + return 0; + } + + BUG_ON(ctx->pattern_db != NULL); /* already built? */ + + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + const SCHSPattern *p = pd->parray[i]; + + cd->ids[i] = i; + cd->flags[i] = HS_FLAG_SINGLEMATCH; + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + cd->flags[i] |= HS_FLAG_CASELESS; + } + + cd->expressions[i] = HSRenderPattern(p->original_pat, p->len); + + if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) { + cd->ext[i] = SCCalloc(1, sizeof(hs_expr_ext_t)); + if (cd->ext[i] == NULL) { + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + + if (p->flags & MPM_PATTERN_FLAG_OFFSET) { + cd->ext[i]->flags |= HS_EXT_FLAG_MIN_OFFSET; + cd->ext[i]->min_offset = p->offset + p->len; + } + if (p->flags & MPM_PATTERN_FLAG_DEPTH) { + cd->ext[i]->flags |= HS_EXT_FLAG_MAX_OFFSET; + cd->ext[i]->max_offset = p->offset + p->depth; + } + } + } + + BUG_ON(mpm_ctx->pattern_cnt == 0); + + err = hs_compile_ext_multi((const char *const *)cd->expressions, cd->flags, cd->ids, + (const hs_expr_ext_t *const *)cd->ext, cd->pattern_cnt, HS_MODE_BLOCK, NULL, &pd->hs_db, + &compile_err); + + if (err != HS_SUCCESS) { + SCLogError("failed to compile hyperscan database"); + if (compile_err) { + SCLogError("compile error: %s", compile_err->message); + } + hs_free_compile_error(compile_err); + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + + ctx->pattern_db = pd; + + SCMutexLock(&g_scratch_proto_mutex); + err = hs_alloc_scratch(pd->hs_db, &g_scratch_proto); + SCMutexUnlock(&g_scratch_proto_mutex); + if (err != HS_SUCCESS) { + SCLogError("failed to allocate scratch"); + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + + err = hs_database_size(pd->hs_db, &ctx->hs_db_size); + if (err != HS_SUCCESS) { + SCLogError("failed to query database size"); + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += ctx->hs_db_size; + + SCLogDebug("Built %" PRIu32 " patterns into a database of size %" PRIuMAX " bytes", + mpm_ctx->pattern_cnt, (uintmax_t)ctx->hs_db_size); + + /* Cache this database globally for later. */ + pd->ref_cnt = 1; + int r = HashTableAdd(g_db_table, pd, 1); + SCMutexUnlock(&g_db_table_mutex); + if (r < 0) + goto error; + + SCHSFreeCompileData(cd); + return 0; + +error: + if (pd) { + PatternDatabaseFree(pd); + } + if (cd) { + SCHSFreeCompileData(cd); + } + return -1; +} + +/** + * \brief Init the mpm thread context. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + */ +void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) +{ + memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + + SCHSThreadCtx *ctx = SCCalloc(1, sizeof(SCHSThreadCtx)); + if (ctx == NULL) { + exit(EXIT_FAILURE); + } + mpm_thread_ctx->ctx = ctx; + + mpm_thread_ctx->memory_cnt++; + mpm_thread_ctx->memory_size += sizeof(SCHSThreadCtx); + + ctx->scratch = NULL; + ctx->scratch_size = 0; + + SCMutexLock(&g_scratch_proto_mutex); + + if (g_scratch_proto == NULL) { + /* There is no scratch prototype: this means that we have not compiled + * any Hyperscan databases. */ + SCMutexUnlock(&g_scratch_proto_mutex); + SCLogDebug("No scratch space prototype"); + return; + } + + hs_error_t err = hs_clone_scratch(g_scratch_proto, (hs_scratch_t **)&ctx->scratch); + + SCMutexUnlock(&g_scratch_proto_mutex); + + if (err != HS_SUCCESS) { + FatalError("Unable to clone scratch prototype"); + } + + err = hs_scratch_size(ctx->scratch, &ctx->scratch_size); + if (err != HS_SUCCESS) { + FatalError("Unable to query scratch size"); + } + + mpm_thread_ctx->memory_cnt++; + mpm_thread_ctx->memory_size += ctx->scratch_size; +} + +/** + * \brief Initialize the HS context. + * + * \param mpm_ctx Mpm context. + */ +void SCHSInitCtx(MpmCtx *mpm_ctx) +{ + if (mpm_ctx->ctx != NULL) + return; + + mpm_ctx->ctx = SCCalloc(1, sizeof(SCHSCtx)); + if (mpm_ctx->ctx == NULL) { + exit(EXIT_FAILURE); + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCHSCtx); + + /* initialize the hash we use to speed up pattern insertions */ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + ctx->init_hash = SCCalloc(INIT_HASH_SIZE, sizeof(SCHSPattern *)); + if (ctx->init_hash == NULL) { + exit(EXIT_FAILURE); + } +} + +/** + * \brief Destroy the mpm thread context. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + */ +void SCHSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) +{ + SCHSPrintSearchStats(mpm_thread_ctx); + + if (mpm_thread_ctx->ctx != NULL) { + SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx; + + if (thr_ctx->scratch != NULL) { + hs_free_scratch(thr_ctx->scratch); + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= thr_ctx->scratch_size; + } + + SCFree(mpm_thread_ctx->ctx); + mpm_thread_ctx->ctx = NULL; + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= sizeof(SCHSThreadCtx); + } +} + +/** + * \brief Destroy the mpm context. + * + * \param mpm_ctx Pointer to the mpm context. + */ +void SCHSDestroyCtx(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + if (ctx == NULL) + return; + + if (ctx->init_hash != NULL) { + SCFree(ctx->init_hash); + ctx->init_hash = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCHSPattern *)); + } + + /* Decrement pattern database ref count, and delete it entirely if the + * count has dropped to zero. */ + SCMutexLock(&g_db_table_mutex); + PatternDatabase *pd = ctx->pattern_db; + if (pd) { + BUG_ON(pd->ref_cnt == 0); + pd->ref_cnt--; + if (pd->ref_cnt == 0) { + HashTableRemove(g_db_table, pd, 1); + PatternDatabaseFree(pd); + } + } + SCMutexUnlock(&g_db_table_mutex); + + SCFree(mpm_ctx->ctx); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCHSCtx); +} + +typedef struct SCHSCallbackCtx_ { + SCHSCtx *ctx; + void *pmq; + uint32_t match_count; +} SCHSCallbackCtx; + +/* Hyperscan MPM match event handler */ +static int SCHSMatchEvent(unsigned int id, unsigned long long from, unsigned long long to, + unsigned int flags, void *ctx) +{ + SCHSCallbackCtx *cctx = ctx; + PrefilterRuleStore *pmq = cctx->pmq; + const PatternDatabase *pd = cctx->ctx->pattern_db; + const SCHSPattern *pat = pd->parray[id]; + + SCLogDebug("Hyperscan Match %" PRIu32 ": id=%" PRIu32 " @ %" PRIuMAX " (pat id=%" PRIu32 ")", + cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id); + + PrefilterAddSids(pmq, pat->sids, pat->sids_size); + + cctx->match_count++; + return 0; +} + +/** + * \brief The Hyperscan search function. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + * \param pmq Pointer to the Pattern Matcher Queue to hold + * search matches. + * \param buf Buffer to be searched. + * \param buflen Buffer length. + * + * \retval matches Match count. + */ +uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PrefilterRuleStore *pmq, + const uint8_t *buf, const uint32_t buflen) +{ + uint32_t ret = 0; + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + SCHSThreadCtx *hs_thread_ctx = (SCHSThreadCtx *)(mpm_thread_ctx->ctx); + const PatternDatabase *pd = ctx->pattern_db; + + if (unlikely(buflen == 0)) { + return 0; + } + + SCHSCallbackCtx cctx = { .ctx = ctx, .pmq = pmq, .match_count = 0 }; + + /* scratch should have been cloned from g_scratch_proto at thread init. */ + hs_scratch_t *scratch = hs_thread_ctx->scratch; + BUG_ON(pd->hs_db == NULL); + BUG_ON(scratch == NULL); + + hs_error_t err = + hs_scan(pd->hs_db, (const char *)buf, buflen, 0, scratch, SCHSMatchEvent, &cctx); + if (err != HS_SUCCESS) { + /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() + * indicates that it was passed an invalid database or scratch region, + * which is not something we can recover from at scan time. */ + SCLogError("Hyperscan returned error %d", err); + exit(EXIT_FAILURE); + } else { + ret = cctx.match_count; + } + + return ret; +} + +/** + * \brief Add a case insensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patlen The pattern length. + * \param offset The pattern offset. + * \param depth The pattern depth. + * \param pid The pattern id. + * \param sid The pattern signature id. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCHSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + flags |= MPM_PATTERN_FLAG_NOCASE; + return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +/** + * \brief Add a case sensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patlen The pattern length. + * \param offset The pattern offset. + * \param depth The pattern depth. + * \param pid The pattern id. + * \param sid The pattern signature id. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCHSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) +{ + return; +} + +void SCHSPrintInfo(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + printf("MPM HS Information:\n"); + printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); + printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); + printf(" Sizeof:\n"); + printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); + printf(" SCHSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSCtx)); + printf(" SCHSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSPattern)); + printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); + printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); + printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); + printf("\n"); + + if (ctx) { + PatternDatabase *pd = ctx->pattern_db; + char *db_info = NULL; + if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) { + printf("HS Database Info: %s\n", db_info); + SCFree(db_info); + } + printf("HS Database Size: %" PRIuMAX " bytes\n", (uintmax_t)ctx->hs_db_size); + } + + printf("\n"); +} + +/************************** Mpm Registration ***************************/ + +/** + * \brief Register the Hyperscan MPM. + */ +void MpmHSRegister(void) +{ + mpm_table[MPM_HS].name = "hs"; + mpm_table[MPM_HS].InitCtx = SCHSInitCtx; + mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx; + mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx; + mpm_table[MPM_HS].DestroyThreadCtx = SCHSDestroyThreadCtx; + mpm_table[MPM_HS].AddPattern = SCHSAddPatternCS; + mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI; + mpm_table[MPM_HS].Prepare = SCHSPreparePatterns; + mpm_table[MPM_HS].Search = SCHSSearch; + mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo; + mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats; + mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests; + + /* Set Hyperscan memory allocators */ + SCHSSetAllocators(); +} + +/** + * \brief Clean up global memory used by all Hyperscan MPM instances. + * + * Currently, this is just the global scratch prototype. + */ +void MpmHSGlobalCleanup(void) +{ + SCMutexLock(&g_scratch_proto_mutex); + if (g_scratch_proto) { + SCLogDebug("Cleaning up Hyperscan global scratch"); + hs_free_scratch(g_scratch_proto); + g_scratch_proto = NULL; + } + SCMutexUnlock(&g_scratch_proto_mutex); + + SCMutexLock(&g_db_table_mutex); + if (g_db_table != NULL) { + SCLogDebug("Clearing Hyperscan database cache"); + HashTableFree(g_db_table); + g_db_table = NULL; + } + SCMutexUnlock(&g_db_table_mutex); +} + +/*************************************Unittests********************************/ + +#ifdef UNITTESTS +#include "detect-engine-alert.h" + +static int SCHSTest01(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest02(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest03(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest04(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest05(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest06(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcd"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest07(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* should match 30 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); + /* should match 29 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); + /* should match 28 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); + /* 26 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); + /* 21 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 6) + result = 1; + else + printf("6 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest08(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest09(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest10(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "abcdefgh" + "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest11(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) + goto end; + PmqSetup(&pmq); + + if (SCHSPreparePatterns(&mpm_ctx) == -1) + goto end; + + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + result = 1; + + const char *buf = "he"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "she"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + buf = "his"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "hers"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + +end: + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest12(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest13(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest14(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest15(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest16(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABC"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABC"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest17(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzAB"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzAB"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest18(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + const char pat[] = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest19(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest20(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + const char pat[] = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest21(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest22(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest23(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 0) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest24(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest25(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest26(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "works"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest27(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "tone"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest28(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + const char *buf = "tONE"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest29(void) +{ + uint8_t buf[] = "onetwothreefourfivesixseveneightnine"; + uint16_t buflen = sizeof(buf) - 1; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + de_ctx->mpm_matcher = MPM_HS; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = + SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; " + "fast_pattern:3,3; sid:2;)"); + if (de_ctx->sig_list->next == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1) != 1) { + printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); + goto end; + } + if (PacketAlertCheck(p, 2) != 1) { + printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + } + + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +void SCHSRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCHSTest01", SCHSTest01); + UtRegisterTest("SCHSTest02", SCHSTest02); + UtRegisterTest("SCHSTest03", SCHSTest03); + UtRegisterTest("SCHSTest04", SCHSTest04); + UtRegisterTest("SCHSTest05", SCHSTest05); + UtRegisterTest("SCHSTest06", SCHSTest06); + UtRegisterTest("SCHSTest07", SCHSTest07); + UtRegisterTest("SCHSTest08", SCHSTest08); + UtRegisterTest("SCHSTest09", SCHSTest09); + UtRegisterTest("SCHSTest10", SCHSTest10); + UtRegisterTest("SCHSTest11", SCHSTest11); + UtRegisterTest("SCHSTest12", SCHSTest12); + UtRegisterTest("SCHSTest13", SCHSTest13); + UtRegisterTest("SCHSTest14", SCHSTest14); + UtRegisterTest("SCHSTest15", SCHSTest15); + UtRegisterTest("SCHSTest16", SCHSTest16); + UtRegisterTest("SCHSTest17", SCHSTest17); + UtRegisterTest("SCHSTest18", SCHSTest18); + UtRegisterTest("SCHSTest19", SCHSTest19); + UtRegisterTest("SCHSTest20", SCHSTest20); + UtRegisterTest("SCHSTest21", SCHSTest21); + UtRegisterTest("SCHSTest22", SCHSTest22); + UtRegisterTest("SCHSTest23", SCHSTest23); + UtRegisterTest("SCHSTest24", SCHSTest24); + UtRegisterTest("SCHSTest25", SCHSTest25); + UtRegisterTest("SCHSTest26", SCHSTest26); + UtRegisterTest("SCHSTest27", SCHSTest27); + UtRegisterTest("SCHSTest28", SCHSTest28); + UtRegisterTest("SCHSTest29", SCHSTest29); +#endif + + return; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-mpm-hs.h b/src/util/mpm/mpm-hs.h similarity index 100% rename from src/util-mpm-hs.h rename to src/util/mpm/mpm-hs.h diff --git a/src/util/mpm/mpm.c b/src/util/mpm/mpm.c new file mode 100644 index 000000000000..b248d167919d --- /dev/null +++ b/src/util/mpm/mpm.c @@ -0,0 +1,586 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Pattern matcher utility Functions + */ + +#include "suricata-common.h" +#include "util/mpm/mpm.h" +#include "util/debug.h" + +/* include pattern matchers */ +#include "util/mpm/mpm-ac.h" +#include "util/mpm/mpm-ac-ks.h" +#include "util/mpm/mpm-hs.h" +#include "util/hashlist.h" + +#include "detect-engine.h" +#include "util/misc.h" +#include "../../conf.h" +#include "conf-yaml-loader.h" +#include "queue.h" +#include "util/unittest.h" +#include "util/memcpy.h" +#ifdef BUILD_HYPERSCAN +#include "hs.h" +#endif + +MpmTableElmt mpm_table[MPM_TABLE_SIZE]; +uint8_t mpm_default_matcher; + +/** + * \brief Register a new Mpm Context. + * + * \param name A new profile to be registered to store this MpmCtx. + * \param sm_list sm_list for this name (might be variable with xforms) + * \param alproto app proto or ALPROTO_UNKNOWN if not for app-layer + * + * \retval id Return the id created for the new MpmCtx profile. + */ +int32_t MpmFactoryRegisterMpmCtxProfile( + DetectEngineCtx *de_ctx, const char *name, const int sm_list, const AppProto alproto) +{ + /* the very first entry */ + if (de_ctx->mpm_ctx_factory_container == NULL) { + de_ctx->mpm_ctx_factory_container = SCCalloc(1, sizeof(MpmCtxFactoryContainer)); + if (de_ctx->mpm_ctx_factory_container == NULL) { + FatalError("Error allocating memory"); + } + de_ctx->mpm_ctx_factory_container->max_id = ENGINE_SGH_MPM_FACTORY_CONTEXT_START_ID_RANGE; + } + + MpmCtxFactoryItem *item = de_ctx->mpm_ctx_factory_container->items; + MpmCtxFactoryItem *pitem = NULL; + while (item) { + if (item->sm_list == sm_list && item->alproto == alproto && item->name != NULL && + strcmp(item->name, name) == 0) { + return item->id; + } + pitem = item; + item = item->next; + } + + MpmCtxFactoryItem *nitem = SCCalloc(1, sizeof(MpmCtxFactoryItem)); + if (unlikely(nitem == NULL)) { + FatalError("Error allocating memory"); + } + nitem->name = name; + nitem->sm_list = sm_list; + nitem->id = de_ctx->mpm_ctx_factory_container->max_id++; + nitem->alproto = alproto; + + /* toserver */ + nitem->mpm_ctx_ts = SCCalloc(1, sizeof(MpmCtx)); + if (nitem->mpm_ctx_ts == NULL) { + FatalError("Error allocating memory"); + } + nitem->mpm_ctx_ts->flags |= MPMCTX_FLAGS_GLOBAL; + + /* toclient */ + nitem->mpm_ctx_tc = SCCalloc(1, sizeof(MpmCtx)); + if (nitem->mpm_ctx_tc == NULL) { + FatalError("Error allocating memory"); + } + nitem->mpm_ctx_tc->flags |= MPMCTX_FLAGS_GLOBAL; + + /* store the newly created item */ + if (pitem == NULL) + de_ctx->mpm_ctx_factory_container->items = nitem; + else + pitem->next = nitem; + + de_ctx->mpm_ctx_factory_container->no_of_items++; + return nitem->id; +} + +int32_t MpmFactoryIsMpmCtxAvailable(const DetectEngineCtx *de_ctx, const MpmCtx *mpm_ctx) +{ + if (mpm_ctx == NULL) + return 0; + + if (de_ctx->mpm_ctx_factory_container == NULL) { + return 0; + } + + for (MpmCtxFactoryItem *i = de_ctx->mpm_ctx_factory_container->items; i != NULL; i = i->next) { + if (mpm_ctx == i->mpm_ctx_ts || mpm_ctx == i->mpm_ctx_tc) { + return 1; + } + } + return 0; +} + +MpmCtx *MpmFactoryGetMpmCtxForProfile(const DetectEngineCtx *de_ctx, int32_t id, int direction) +{ + if (id == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + MpmCtx *mpm_ctx = SCCalloc(1, sizeof(MpmCtx)); + if (unlikely(mpm_ctx == NULL)) { + FatalError("Error allocating memory"); + } + return mpm_ctx; + } else if (id < -1) { + SCLogError("Invalid argument - %d\n", id); + return NULL; + } else if (id >= de_ctx->mpm_ctx_factory_container->max_id) { + /* this id does not exist */ + return NULL; + } else { + for (MpmCtxFactoryItem *i = de_ctx->mpm_ctx_factory_container->items; i != NULL; + i = i->next) { + if (id == i->id) { + return (direction == 0) ? i->mpm_ctx_ts : i->mpm_ctx_tc; + } + } + return NULL; + } +} + +void MpmFactoryReClaimMpmCtx(const DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) +{ + if (mpm_ctx == NULL) + return; + + if (!MpmFactoryIsMpmCtxAvailable(de_ctx, mpm_ctx)) { + if (mpm_ctx->mpm_type != MPM_NOTSET) + mpm_table[mpm_ctx->mpm_type].DestroyCtx(mpm_ctx); + SCFree(mpm_ctx); + } +} + +void MpmFactoryDeRegisterAllMpmCtxProfiles(DetectEngineCtx *de_ctx) +{ + if (de_ctx->mpm_ctx_factory_container == NULL) + return; + + MpmCtxFactoryItem *item = de_ctx->mpm_ctx_factory_container->items; + while (item) { + if (item->mpm_ctx_ts != NULL) { + if (item->mpm_ctx_ts->mpm_type != MPM_NOTSET) + mpm_table[item->mpm_ctx_ts->mpm_type].DestroyCtx(item->mpm_ctx_ts); + SCFree(item->mpm_ctx_ts); + } + if (item->mpm_ctx_tc != NULL) { + if (item->mpm_ctx_tc->mpm_type != MPM_NOTSET) + mpm_table[item->mpm_ctx_tc->mpm_type].DestroyCtx(item->mpm_ctx_tc); + SCFree(item->mpm_ctx_tc); + } + + MpmCtxFactoryItem *next = item->next; + SCFree(item); + item = next; + } + + SCFree(de_ctx->mpm_ctx_factory_container); + de_ctx->mpm_ctx_factory_container = NULL; +} + +void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher) +{ + if (mpm_table[matcher].InitThreadCtx != NULL) { + mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx); + } +} + +void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher) +{ + if (mpm_table[matcher].DestroyThreadCtx != NULL) { + mpm_table[matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); + } +} + +void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher) +{ + mpm_ctx->mpm_type = matcher; + mpm_table[matcher].InitCtx(mpm_ctx); +} + +/* MPM matcher to use by default, i.e. when "mpm-algo" is set to "auto". + * If Hyperscan is available, use it. Otherwise, use AC. */ +#ifdef BUILD_HYPERSCAN +#define DEFAULT_MPM MPM_HS +#define DEFAULT_MPM_AC MPM_AC +#else +#define DEFAULT_MPM MPM_AC +#endif + +void MpmTableSetup(void) +{ + memset(mpm_table, 0, sizeof(mpm_table)); + mpm_default_matcher = DEFAULT_MPM; + + MpmACRegister(); + MpmACTileRegister(); +#ifdef BUILD_HYPERSCAN +#ifdef HAVE_HS_VALID_PLATFORM + /* Enable runtime check for SSSE3. Do not use Hyperscan MPM matcher if + * check is not successful. */ + if (hs_valid_platform() != HS_SUCCESS) { + SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " + "MPM"); + /* Fall back to best Aho-Corasick variant. */ + mpm_default_matcher = DEFAULT_MPM_AC; + } else { + MpmHSRegister(); + } +#else + MpmHSRegister(); +#endif /* HAVE_HS_VALID_PLATFORM */ +#endif /* BUILD_HYPERSCAN */ +} + +int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + return mpm_table[mpm_ctx->mpm_type].AddPattern( + mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + return mpm_table[mpm_ctx->mpm_type].AddPatternNocase( + mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +/** + * \internal + * \brief Creates a hash of the pattern. We use it for the hashing process + * during the initial pattern insertion time, to cull duplicate sigs. + * + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline uint32_t MpmInitHashRaw(uint8_t *pat, uint16_t patlen) +{ + uint32_t hash = patlen * pat[0]; + if (patlen > 1) + hash += pat[1]; + + return (hash % MPM_INIT_HASH_SIZE); +} + +/** + * \internal + * \brief Looks up a pattern. We use it for the hashing process during the + * the initial pattern insertion time, to cull duplicate sigs. + * + * \param ctx Pointer to the AC ctx. + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * \param flags Flags. We don't need this. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline MpmPattern *MpmInitHashLookup(MpmCtx *ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint8_t flags, uint32_t pid) +{ + uint32_t hash = MpmInitHashRaw(pat, patlen); + + if (ctx->init_hash == NULL) { + return NULL; + } + + MpmPattern *t = ctx->init_hash[hash]; + for (; t != NULL; t = t->next) { + if (!(flags & MPM_PATTERN_CTX_OWNS_ID)) { + if (t->id == pid) + return t; + } else { + if (t->len == patlen && t->offset == offset && t->depth == depth && + memcmp(pat, t->original_pat, patlen) == 0 && t->flags == flags) { + return t; + } + } + } + + return NULL; +} + +/** + * \internal + * \brief Allocs a new pattern instance. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval p Pointer to the newly created pattern. + */ +static inline MpmPattern *MpmAllocPattern(MpmCtx *mpm_ctx) +{ + MpmPattern *p = SCCalloc(1, sizeof(MpmPattern)); + if (unlikely(p == NULL)) { + exit(EXIT_FAILURE); + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(MpmPattern); + + return p; +} + +/** + * \internal + * \brief Used to free MpmPattern instances. + * + * \param mpm_ctx Pointer to the mpm context. + * \param p Pointer to the MpmPattern instance to be freed. + */ +void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p) +{ + if (p == NULL) + return; + + if (p->cs != NULL && p->cs != p->ci) { + SCFree(p->cs); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p->ci != NULL) { + SCFree(p->ci); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p->original_pat != NULL) { + SCFree(p->original_pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p->sids != NULL) { + SCFree(p->sids); + } + + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(MpmPattern); +} + +static inline uint32_t MpmInitHash(MpmPattern *p) +{ + uint32_t hash = p->len * p->original_pat[0]; + if (p->len > 1) + hash += p->original_pat[1]; + + return (hash % MPM_INIT_HASH_SIZE); +} + +static inline int MpmInitHashAdd(MpmCtx *ctx, MpmPattern *p) +{ + uint32_t hash = MpmInitHash(p); + + if (ctx->init_hash == NULL) { + return -1; + } + + if (ctx->init_hash[hash] == NULL) { + ctx->init_hash[hash] = p; + return 0; + } + + MpmPattern *tt = NULL; + MpmPattern *t = ctx->init_hash[hash]; + + /* get the list tail */ + do { + tt = t; + t = t->next; + } while (t != NULL); + + tt->next = p; + + return 0; +} + +/** + * \internal + * \brief Add a pattern to the mpm-ac context. + * + * \param mpm_ctx Mpm context. + * \param pat Pointer to the pattern. + * \param patlen Length of the pattern. + * \param pid Pattern id + * \param sid Signature id (internal id). + * \param flags Pattern's MPM_PATTERN_* flags. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, + uint32_t pid, SigIntId sid, uint8_t flags) +{ + SCLogDebug( + "Adding pattern for ctx %p, patlen %" PRIu16 " and pid %" PRIu32, mpm_ctx, patlen, pid); + + if (patlen == 0) { + SCLogWarning("pattern length 0"); + return 0; + } + + if (flags & MPM_PATTERN_CTX_OWNS_ID) + pid = UINT_MAX; + + /* check if we have already inserted this pattern */ + MpmPattern *p = MpmInitHashLookup(mpm_ctx, pat, patlen, offset, depth, flags, pid); + if (p == NULL) { + SCLogDebug("Allocing new pattern"); + + /* p will never be NULL */ + p = MpmAllocPattern(mpm_ctx); + + p->len = patlen; + p->flags = flags; + p->offset = offset; + p->depth = depth; + if (flags & MPM_PATTERN_CTX_OWNS_ID) + p->id = mpm_ctx->max_pat_id++; + else + p->id = pid; + + p->original_pat = SCMalloc(patlen); + if (p->original_pat == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->original_pat, pat, patlen); + + p->ci = SCMalloc(patlen); + if (p->ci == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy_tolower(p->ci, pat, patlen); + + /* setup the case sensitive part of the pattern */ + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + /* nocase means no difference between cs and ci */ + p->cs = p->ci; + } else { + if (memcmp(p->ci, pat, p->len) == 0) { + /* no diff between cs and ci: pat is lowercase */ + p->cs = p->ci; + } else { + p->cs = SCMalloc(patlen); + if (p->cs == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->cs, pat, patlen); + } + } + + /* put in the pattern hash */ + if (MpmInitHashAdd(mpm_ctx, p) != 0) + goto error; + + mpm_ctx->pattern_cnt++; + + if (!(mpm_ctx->flags & MPMCTX_FLAGS_NODEPTH)) { + if (depth) { + mpm_ctx->maxdepth = MAX(mpm_ctx->maxdepth, depth); + SCLogDebug("%p: depth %u max %u", mpm_ctx, depth, mpm_ctx->maxdepth); + } else { + mpm_ctx->flags |= MPMCTX_FLAGS_NODEPTH; + mpm_ctx->maxdepth = 0; + SCLogDebug("%p: alas, no depth for us", mpm_ctx); + } + } + + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + + if (mpm_ctx->minlen == 0) { + mpm_ctx->minlen = patlen; + } else { + if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; + } + + /* we need the max pat id */ + if (p->id > mpm_ctx->max_pat_id) + mpm_ctx->max_pat_id = p->id; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* we can be called multiple times for the same sid in the case + * of the 'single' modus. Here multiple rule groups share the + * same mpm ctx and might be adding the same pattern to the + * mpm_ctx */ + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + + if (!found) { + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } + } + + return 0; + +error: + MpmFreePattern(mpm_ctx, p); + return -1; +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS +#endif /* UNITTESTS */ + +void MpmRegisterTests(void) +{ +#ifdef UNITTESTS + uint16_t i; + + for (i = 0; i < MPM_TABLE_SIZE; i++) { + if (i == MPM_NOTSET) + continue; + + g_ut_modules++; + + if (mpm_table[i].RegisterUnittests != NULL) { + g_ut_covered++; + mpm_table[i].RegisterUnittests(); + } else { + if (coverage_unittests) + SCLogWarning("mpm module %s has no " + "unittest registration function.", + mpm_table[i].name); + } + } + +#endif +} diff --git a/src/util/mpm/mpm.h b/src/util/mpm/mpm.h new file mode 100644 index 000000000000..e617ff926d7f --- /dev/null +++ b/src/util/mpm/mpm.h @@ -0,0 +1,202 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_MPM_H__ +#define __UTIL_MPM_H__ + +#include "app-layer-protos.h" +#include "util/prefilter.h" + +#define MPM_INIT_HASH_SIZE 65536 + +enum { + MPM_NOTSET = 0, + + /* aho-corasick */ + MPM_AC, + MPM_AC_KS, + MPM_HS, + /* table size */ + MPM_TABLE_SIZE, +}; + +/* Internal Pattern Index: 0 to pattern_cnt-1 */ +typedef uint32_t MpmPatternIndex; + +typedef struct MpmThreadCtx_ { + void *ctx; + + uint32_t memory_cnt; + uint32_t memory_size; + +} MpmThreadCtx; + +typedef struct MpmPattern_ { + /* length of the pattern */ + uint16_t len; + /* flags describing the pattern */ + uint8_t flags; + + /* offset into the buffer where match may start */ + uint16_t offset; + + /* offset into the buffer before which match much complete */ + uint16_t depth; + + /* holds the original pattern that was added */ + uint8_t *original_pat; + /* case sensitive */ + uint8_t *cs; + /* case insensitive */ + uint8_t *ci; + /* pattern id */ + uint32_t id; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; + + struct MpmPattern_ *next; +} MpmPattern; + +/* Indicates if this a global mpm_ctx. Global mpm_ctx is the one that + * is instantiated when we use "single". Non-global is "full", i.e. + * one per sgh. */ +#define MPMCTX_FLAGS_GLOBAL BIT_U8(0) +#define MPMCTX_FLAGS_NODEPTH BIT_U8(1) + +typedef struct MpmCtx_ { + void *ctx; + uint8_t mpm_type; + + uint8_t flags; + + uint16_t maxdepth; + + /* unique patterns */ + uint32_t pattern_cnt; + + uint16_t minlen; + uint16_t maxlen; + + uint32_t memory_cnt; + uint32_t memory_size; + + uint32_t max_pat_id; + + /* hash used during ctx initialization */ + MpmPattern **init_hash; +} MpmCtx; + +/* if we want to retrieve an unique mpm context from the mpm context factory + * we should supply this as the key */ +#define MPM_CTX_FACTORY_UNIQUE_CONTEXT -1 + +typedef struct MpmCtxFactoryItem { + const char *name; + MpmCtx *mpm_ctx_ts; + MpmCtx *mpm_ctx_tc; + int32_t id; + int32_t sm_list; + AppProto alproto; /**< ALPROTO_UNKNOWN is not an app item */ + struct MpmCtxFactoryItem *next; +} MpmCtxFactoryItem; + +typedef struct MpmCtxFactoryContainer_ { + MpmCtxFactoryItem *items; + int32_t no_of_items; + int32_t max_id; +} MpmCtxFactoryContainer; + +/** pattern is case insensitive */ +#define MPM_PATTERN_FLAG_NOCASE 0x01 +/** pattern has a depth setting */ +#define MPM_PATTERN_FLAG_DEPTH 0x04 +/** pattern has an offset setting */ +#define MPM_PATTERN_FLAG_OFFSET 0x08 +/** the ctx uses it's own internal id instead of + * what is passed through the API */ +#define MPM_PATTERN_CTX_OWNS_ID 0x20 + +typedef struct MpmTableElmt_ { + const char *name; + void (*InitCtx)(struct MpmCtx_ *); + void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); + void (*DestroyCtx)(struct MpmCtx_ *); + void (*DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); + + /** function pointers for adding patterns to the mpm ctx. + * + * \param mpm_ctx Mpm context to add the pattern to + * \param pattern pointer to the pattern + * \param pattern_len length of the pattern in bytes + * \param offset pattern offset setting + * \param depth pattern depth setting + * \param pid pattern id + * \param sid signature _internal_ id + * \param flags pattern flags + */ + int (*AddPattern)( + struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); + int (*AddPatternNocase)( + struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); + int (*Prepare)(struct MpmCtx_ *); + /** \retval cnt number of patterns that matches: once per pattern max. */ + uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, + const uint8_t *, uint32_t); + void (*PrintCtx)(struct MpmCtx_ *); + void (*PrintThreadCtx)(struct MpmThreadCtx_ *); + void (*RegisterUnittests)(void); + uint8_t flags; +} MpmTableElmt; + +extern MpmTableElmt mpm_table[MPM_TABLE_SIZE]; +extern uint8_t mpm_default_matcher; + +struct DetectEngineCtx_; + +int32_t MpmFactoryRegisterMpmCtxProfile( + struct DetectEngineCtx_ *, const char *, const int, const AppProto); +void MpmFactoryReClaimMpmCtx(const struct DetectEngineCtx_ *, MpmCtx *); +MpmCtx *MpmFactoryGetMpmCtxForProfile(const struct DetectEngineCtx_ *, int32_t, int); +void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); +int32_t MpmFactoryIsMpmCtxAvailable(const struct DetectEngineCtx_ *, const MpmCtx *); + +void MpmTableSetup(void); +void MpmRegisterTests(void); + +void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher); +void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t); +void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher); + +int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); +int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags); + +void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p); + +int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, + uint32_t pid, SigIntId sid, uint8_t flags); + +#endif /* __UTIL_MPM_H__ */ diff --git a/src/util/napatech.c b/src/util/napatech.c new file mode 100644 index 000000000000..d239ad1a5f94 --- /dev/null +++ b/src/util/napatech.c @@ -0,0 +1,1846 @@ +/* Copyright (C) 2017-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +/** + * \file + * + * \author Napatech Inc. + * \author Phil Young + * + * + */ +#include "suricata-common.h" + +#ifdef HAVE_NAPATECH +#include "suricata.h" +#include "util/device.h" +#include "util/cpu.h" +#include "util/byte.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "util/napatech.h" +#include "source-napatech.h" +#include "runmode-napatech.h" + +#ifdef NAPATECH_ENABLE_BYPASS + +/* + * counters to track the number of flows programmed on + * the adapter. + */ +typedef struct FlowStatsCounters_ { + uint16_t active_bypass_flows; + uint16_t total_bypass_flows; +} FlowStatsCounters; + +static int bypass_supported; +int NapatechIsBypassSupported(void) +{ + return bypass_supported; +} + +/** + * \brief Returns the number of Napatech Adapters in the system. + * + * \return count of the Napatech adapters present in the system. + */ +int NapatechGetNumAdapters(void) +{ + NtInfoStream_t hInfo; + NtInfo_t hInfoSys; + int status; + static int num_adapters = -1; + + if (num_adapters == -1) { + if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + hInfoSys.cmd = NT_INFO_CMD_READ_SYSTEM; + if ((status = NT_InfoRead(hInfo, &hInfoSys)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + num_adapters = hInfoSys.u.system.data.numAdapters; + + NT_InfoClose(hInfo); + } + + return num_adapters; +} + +/** + * \brief Verifies that the Napatech adapters support bypass. + * + * Attempts to opens a FlowStream on each adapter present in the system. + * If successful then bypass is supported + * + * \return 1 if Bypass functionality is supported; zero otherwise. + */ +int NapatechVerifyBypassSupport(void) +{ + int status; + int adapter = 0; + int num_adapters = NapatechGetNumAdapters(); + SCLogInfo("Found %d Napatech adapters.", num_adapters); + NtFlowStream_t hFlowStream; + + if (!NapatechUseHWBypass()) { + /* HW Bypass is disabled in the conf file */ + return 0; + } + + for (adapter = 0; adapter < num_adapters; ++adapter) { + NtFlowAttr_t attr; + char flow_name[80]; + + NT_FlowOpenAttrInit(&attr); + NT_FlowOpenAttrSetAdapterNo(&attr, adapter); + + snprintf(flow_name, sizeof(flow_name), "Flow stream %d", adapter); + SCLogInfo("Opening flow programming stream: %s\n", flow_name); + if ((status = NT_FlowOpen_Attr(&hFlowStream, flow_name, &attr)) != NT_SUCCESS) { + SCLogWarning("Napatech bypass functionality not supported by the FPGA version on " + "adapter %d - disabling support.", + adapter); + bypass_supported = 0; + return 0; + } + NT_FlowClose(hFlowStream); + } + + bypass_supported = 1; + return bypass_supported; +} + +/** + * \brief Updates statistic counters for Napatech FlowStats + * + * \param tv Thread variable to ThreadVars + * \param hInfo Handle to the Napatech InfoStream. + * \param hstat_stream Handle to the Napatech Statistics Stream. + * \param flow_counters The flow counters statistics to update. + * \param clear_stats Indicates if statistics on the card should be reset to zero. + * + */ +static void UpdateFlowStats(ThreadVars *tv, NtInfoStream_t hInfo, NtStatStream_t hstat_stream, + FlowStatsCounters flow_counters, int clear_stats) +{ + NtStatistics_t hStat; + int status; + + uint64_t programed = 0; + uint64_t removed = 0; + int adapter = 0; + + for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) { + hStat.cmd = NT_STATISTICS_READ_CMD_FLOW_V0; + hStat.u.flowData_v0.clear = clear_stats; + hStat.u.flowData_v0.adapterNo = adapter; + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(1); + } + programed = hStat.u.flowData_v0.learnDone; + removed = hStat.u.flowData_v0.unlearnDone + hStat.u.flowData_v0.automaticUnlearnDone + + hStat.u.flowData_v0.timeoutUnlearnDone; + } + + StatsSetUI64(tv, flow_counters.active_bypass_flows, programed - removed); + StatsSetUI64(tv, flow_counters.total_bypass_flows, programed); +} + +#endif /* NAPATECH_ENABLE_BYPASS */ + +/*----------------------------------------------------------------------------- + *----------------------------------------------------------------------------- + * Statistics code + *----------------------------------------------------------------------------- + */ +typedef struct PacketCounters_ { + uint16_t pkts; + uint16_t byte; + uint16_t drop_pkts; + uint16_t drop_byte; +} PacketCounters; + +NapatechCurrentStats total_stats; +NapatechCurrentStats current_stats[MAX_STREAMS]; + +NapatechCurrentStats NapatechGetCurrentStats(uint16_t id) +{ + + return current_stats[id]; +} + +enum CONFIG_SPECIFIER { + CONFIG_SPECIFIER_UNDEFINED = 0, + CONFIG_SPECIFIER_RANGE, + CONFIG_SPECIFIER_INDIVIDUAL +}; + +#define MAX_HOSTBUFFERS 8 + +/** + * \brief Test to see if any of the configured streams are active + * + * \param hInfo Handle to Napatech Info Stream. + * \param hStatsStream Handle to Napatech Statistics stream + * \param stream_config array of stream configuration structures + * \param num_inst + * + */ +static uint16_t TestStreamConfig(NtInfoStream_t hInfo, NtStatStream_t hstat_stream, + NapatechStreamConfig stream_config[], uint16_t num_inst) +{ + uint16_t num_active = 0; + + for (uint16_t inst = 0; inst < num_inst; ++inst) { + int status; + NtStatistics_t stat; // Stat handle. + + /* Check to see if it is an active stream */ + memset(&stat, 0, sizeof(NtStatistics_t)); + + /* Read usage data for the chosen stream ID */ + stat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; + stat.u.usageData_v0.streamid = (uint8_t)stream_config[inst].stream_id; + + if ((status = NT_StatRead(hstat_stream, &stat)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return 0; + } + + if (stat.u.usageData_v0.data.numHostBufferUsed > 0) { + stream_config[inst].is_active = true; + num_active++; + } else { + stream_config[inst].is_active = false; + } + } + + return num_active; +} + +/** + * \brief Updates Napatech packet counters + * + * \param tv Pointer to ThreadVars structure + * \param hInfo Handle to Napatech Info Stream. + * \param hstat_stream Handle to Napatech Statistics stream + * \param num_streams the number of streams that are currently active + * \param stream_config array of stream configuration structures + * \param total_counters - cumulative count of all packets received. + * \param dispatch_host, - Count of packets that were delivered to the host buffer + * \param dispatch_drop - count of packets that were dropped as a result of a rule + * \param dispatch_fwd - count of packets forwarded out the egress port as the result of a rule + * \param is_inline - are we running in inline mode? + * \param enable_stream_stats - are per thread/stream statistics enabled. + * \param stream_counters - counters for each thread/stream configured. + * + * \return The number of active streams that were updated. + * + */ +static uint32_t UpdateStreamStats(ThreadVars *tv, NtInfoStream_t hInfo, NtStatStream_t hstat_stream, + uint16_t num_streams, NapatechStreamConfig stream_config[], PacketCounters total_counters, + PacketCounters dispatch_host, PacketCounters dispatch_drop, PacketCounters dispatch_fwd, + int is_inline, int enable_stream_stats, PacketCounters stream_counters[]) +{ + static uint64_t rxPktsStart[MAX_STREAMS] = { 0 }; + static uint64_t rxByteStart[MAX_STREAMS] = { 0 }; + static uint64_t dropPktStart[MAX_STREAMS] = { 0 }; + static uint64_t dropByteStart[MAX_STREAMS] = { 0 }; + + int status; + NtInfo_t hStreamInfo; + NtStatistics_t hStat; // Stat handle. + + /* Query the system to get the number of streams currently instantiated */ + hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM; + if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + uint16_t num_active; + if ((num_active = TestStreamConfig(hInfo, hstat_stream, stream_config, num_streams)) == 0) { + /* None of the configured streams are active */ + return 0; + } + + /* At least one stream is active so proceed with the stats. */ + uint16_t inst_id = 0; + uint32_t stream_cnt = 0; + for (stream_cnt = 0; stream_cnt < num_streams; ++stream_cnt) { + while (inst_id < num_streams) { + if (stream_config[inst_id].is_active) { + break; + } else { + ++inst_id; + } + } + if (inst_id == num_streams) + break; + + /* Read usage data for the chosen stream ID */ + memset(&hStat, 0, sizeof(NtStatistics_t)); + hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; + hStat.u.usageData_v0.streamid = (uint8_t)stream_config[inst_id].stream_id; + + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return 0; + } + + uint16_t stream_id = stream_config[inst_id].stream_id; + if (stream_config[inst_id].is_active) { + uint64_t rx_pkts_total = 0; + uint64_t rx_byte_total = 0; + uint64_t drop_pkts_total = 0; + uint64_t drop_byte_total = 0; + + for (uint32_t hbCount = 0; hbCount < hStat.u.usageData_v0.data.numHostBufferUsed; + hbCount++) { + if (unlikely(stream_config[inst_id].initialized == false)) { + rxPktsStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.frames; + rxByteStart[stream_id] += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.bytes; + dropPktStart[stream_id] += + hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames; + dropByteStart[stream_id] += + hStat.u.usageData_v0.data.hb[hbCount].stat.drop.bytes; + stream_config[inst_id].initialized = true; + } else { + rx_pkts_total += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.frames; + rx_byte_total += hStat.u.usageData_v0.data.hb[hbCount].stat.rx.bytes; + drop_pkts_total += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.frames; + drop_byte_total += hStat.u.usageData_v0.data.hb[hbCount].stat.drop.bytes; + } + } + + current_stats[stream_id].current_packets = rx_pkts_total - rxPktsStart[stream_id]; + current_stats[stream_id].current_bytes = rx_byte_total - rxByteStart[stream_id]; + current_stats[stream_id].current_drop_packets = + drop_pkts_total - dropPktStart[stream_id]; + current_stats[stream_id].current_drop_bytes = + drop_byte_total - dropByteStart[stream_id]; + } + + if (enable_stream_stats) { + StatsSetUI64( + tv, stream_counters[inst_id].pkts, current_stats[stream_id].current_packets); + StatsSetUI64(tv, stream_counters[inst_id].byte, current_stats[stream_id].current_bytes); + StatsSetUI64(tv, stream_counters[inst_id].drop_pkts, + current_stats[stream_id].current_drop_packets); + StatsSetUI64(tv, stream_counters[inst_id].drop_byte, + current_stats[stream_id].current_drop_bytes); + } + + ++inst_id; + } + + uint32_t stream_id; + for (stream_id = 0; stream_id < num_streams; ++stream_id) { + +#ifndef NAPATECH_ENABLE_BYPASS + total_stats.current_packets += current_stats[stream_id].current_packets; + total_stats.current_bytes += current_stats[stream_id].current_bytes; +#endif /* NAPATECH_ENABLE_BYPASS */ + total_stats.current_drop_packets += current_stats[stream_id].current_drop_packets; + total_stats.current_drop_bytes += current_stats[stream_id].current_drop_bytes; + } + +#ifndef NAPATECH_ENABLE_BYPASS + StatsSetUI64(tv, total_counters.pkts, total_stats.current_packets); + StatsSetUI64(tv, total_counters.byte, total_stats.current_bytes); +#endif /* NAPATECH_ENABLE_BYPASS */ + + StatsSetUI64(tv, total_counters.drop_pkts, total_stats.current_drop_packets); + StatsSetUI64(tv, total_counters.drop_byte, total_stats.current_drop_bytes); + + total_stats.current_packets = 0; + total_stats.current_bytes = 0; + total_stats.current_drop_packets = 0; + total_stats.current_drop_bytes = 0; + + /* Read usage data for the chosen stream ID */ + memset(&hStat, 0, sizeof(NtStatistics_t)); + +#ifdef NAPATECH_ENABLE_BYPASS + hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V3; + hStat.u.query_v3.clear = 0; +#else /* NAPATECH_ENABLE_BYPASS */ + /* Older versions of the API have a different structure. */ + hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V2; + hStat.u.query_v2.clear = 0; +#endif /* !NAPATECH_ENABLE_BYPASS */ + + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + if (status == NT_STATUS_TIMEOUT) { + SCLogInfo("Statistics timed out - will retry next time."); + return 0; + } else { + NAPATECH_ERROR(status); + return 0; + } + } + +#ifdef NAPATECH_ENABLE_BYPASS + + int adapter = 0; + uint64_t total_dispatch_host_pkts = 0; + uint64_t total_dispatch_host_byte = 0; + uint64_t total_dispatch_drop_pkts = 0; + uint64_t total_dispatch_drop_byte = 0; + uint64_t total_dispatch_fwd_pkts = 0; + uint64_t total_dispatch_fwd_byte = 0; + + for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) { + total_dispatch_host_pkts += + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].pkts; + total_dispatch_host_byte += + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].octets; + + total_dispatch_drop_pkts += + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].pkts + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].pkts; + total_dispatch_drop_byte += + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].octets + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].octets; + + total_dispatch_fwd_pkts += + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].pkts + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[4].pkts; + total_dispatch_fwd_byte += + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].octets + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[4].octets; + + total_stats.current_packets += + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].pkts + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].pkts + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].pkts + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[3].pkts; + + total_stats.current_bytes = + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[0].octets + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[1].octets + + hStat.u.query_v3.data.adapter.aAdapters[adapter].color.aColor[2].octets; + } + + StatsSetUI64(tv, dispatch_host.pkts, total_dispatch_host_pkts); + StatsSetUI64(tv, dispatch_host.byte, total_dispatch_host_byte); + + StatsSetUI64(tv, dispatch_drop.pkts, total_dispatch_drop_pkts); + StatsSetUI64(tv, dispatch_drop.byte, total_dispatch_drop_byte); + + if (is_inline) { + StatsSetUI64(tv, dispatch_fwd.pkts, total_dispatch_fwd_pkts); + StatsSetUI64(tv, dispatch_fwd.byte, total_dispatch_fwd_byte); + } + + StatsSetUI64(tv, total_counters.pkts, total_stats.current_packets); + StatsSetUI64(tv, total_counters.byte, total_stats.current_bytes); + +#endif /* NAPATECH_ENABLE_BYPASS */ + + return num_active; +} + +/** + * \brief Statistics processing loop + * + * Instantiated on the stats thread. Periodically retrieves + * statistics from the Napatech card and updates the packet counters + * + * \param arg Pointer that is cast into a ThreadVars structure + */ +static void *NapatechStatsLoop(void *arg) +{ + ThreadVars *tv = (ThreadVars *)arg; + + int status; + NtInfoStream_t hInfo; + NtStatStream_t hstat_stream; + int is_inline = 0; + int enable_stream_stats = 0; + PacketCounters stream_counters[MAX_STREAMS]; + + if (ConfGetBool("napatech.inline", &is_inline) == 0) { + is_inline = 0; + } + + if (ConfGetBool("napatech.enable-stream-stats", &enable_stream_stats) == 0) { + /* default is "no" */ + enable_stream_stats = 0; + } + + NapatechStreamConfig stream_config[MAX_STREAMS]; + uint16_t stream_cnt = NapatechGetStreamConfig(stream_config); + + /* Open the info and Statistics */ + if ((status = NT_InfoOpen(&hInfo, "StatsLoopInfoStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return NULL; + } + + if ((status = NT_StatOpen(&hstat_stream, "StatsLoopStatsStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return NULL; + } + + NtStatistics_t hStat; + memset(&hStat, 0, sizeof(NtStatistics_t)); + +#ifdef NAPATECH_ENABLE_BYPASS + hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V3; + hStat.u.query_v3.clear = 1; +#else /* NAPATECH_ENABLE_BYPASS */ + hStat.cmd = NT_STATISTICS_READ_CMD_QUERY_V2; + hStat.u.query_v2.clear = 1; +#endif /* !NAPATECH_ENABLE_BYPASS */ + + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return 0; + } + + PacketCounters total_counters; + memset(&total_counters, 0, sizeof(total_counters)); + + PacketCounters dispatch_host; + memset(&dispatch_host, 0, sizeof(dispatch_host)); + + PacketCounters dispatch_drop; + memset(&dispatch_drop, 0, sizeof(dispatch_drop)); + + PacketCounters dispatch_fwd; + memset(&dispatch_fwd, 0, sizeof(dispatch_fwd)); + + total_counters.pkts = StatsRegisterCounter("napa_total.pkts", tv); + dispatch_host.pkts = StatsRegisterCounter("napa_dispatch_host.pkts", tv); + dispatch_drop.pkts = StatsRegisterCounter("napa_dispatch_drop.pkts", tv); + if (is_inline) { + dispatch_fwd.pkts = StatsRegisterCounter("napa_dispatch_fwd.pkts", tv); + } + + total_counters.byte = StatsRegisterCounter("napa_total.byte", tv); + dispatch_host.byte = StatsRegisterCounter("napa_dispatch_host.byte", tv); + dispatch_drop.byte = StatsRegisterCounter("napa_dispatch_drop.byte", tv); + if (is_inline) { + dispatch_fwd.byte = StatsRegisterCounter("napa_dispatch_fwd.byte", tv); + } + + total_counters.drop_pkts = StatsRegisterCounter("napa_total.overflow_drop_pkts", tv); + total_counters.drop_byte = StatsRegisterCounter("napa_total.overflow_drop_byte", tv); + + if (enable_stream_stats) { + for (int i = 0; i < stream_cnt; ++i) { + char *pkts_buf = SCCalloc(1, 32); + if (unlikely(pkts_buf == NULL)) { + FatalError("Failed to allocate memory for NAPATECH stream counter."); + } + + snprintf(pkts_buf, 32, "napa%d.pkts", stream_config[i].stream_id); + stream_counters[i].pkts = StatsRegisterCounter(pkts_buf, tv); + + char *byte_buf = SCCalloc(1, 32); + if (unlikely(byte_buf == NULL)) { + FatalError("Failed to allocate memory for NAPATECH stream counter."); + } + snprintf(byte_buf, 32, "napa%d.bytes", stream_config[i].stream_id); + stream_counters[i].byte = StatsRegisterCounter(byte_buf, tv); + + char *drop_pkts_buf = SCCalloc(1, 32); + if (unlikely(drop_pkts_buf == NULL)) { + FatalError("Failed to allocate memory for NAPATECH stream counter."); + } + snprintf(drop_pkts_buf, 32, "napa%d.drop_pkts", stream_config[i].stream_id); + stream_counters[i].drop_pkts = StatsRegisterCounter(drop_pkts_buf, tv); + + char *drop_byte_buf = SCCalloc(1, 32); + if (unlikely(drop_byte_buf == NULL)) { + FatalError("Failed to allocate memory for NAPATECH stream counter."); + } + snprintf(drop_byte_buf, 32, "napa%d.drop_byte", stream_config[i].stream_id); + stream_counters[i].drop_byte = StatsRegisterCounter(drop_byte_buf, tv); + } + } + +#ifdef NAPATECH_ENABLE_BYPASS + FlowStatsCounters flow_counters; + if (bypass_supported) { + flow_counters.active_bypass_flows = StatsRegisterCounter("napa_bypass.active_flows", tv); + flow_counters.total_bypass_flows = StatsRegisterCounter("napa_bypass.total_flows", tv); + } +#endif /* NAPATECH_ENABLE_BYPASS */ + + StatsSetupPrivate(tv); + + StatsSetUI64(tv, total_counters.pkts, 0); + StatsSetUI64(tv, total_counters.byte, 0); + StatsSetUI64(tv, total_counters.drop_pkts, 0); + StatsSetUI64(tv, total_counters.drop_byte, 0); + +#ifdef NAPATECH_ENABLE_BYPASS + if (bypass_supported) { + StatsSetUI64(tv, dispatch_host.pkts, 0); + StatsSetUI64(tv, dispatch_drop.pkts, 0); + + if (is_inline) { + StatsSetUI64(tv, dispatch_fwd.pkts, 0); + } + + StatsSetUI64(tv, dispatch_host.byte, 0); + StatsSetUI64(tv, dispatch_drop.byte, 0); + if (is_inline) { + StatsSetUI64(tv, dispatch_fwd.byte, 0); + } + + if (enable_stream_stats) { + for (int i = 0; i < stream_cnt; ++i) { + StatsSetUI64(tv, stream_counters[i].pkts, 0); + StatsSetUI64(tv, stream_counters[i].byte, 0); + StatsSetUI64(tv, stream_counters[i].drop_pkts, 0); + StatsSetUI64(tv, stream_counters[i].drop_byte, 0); + } + } + + StatsSetUI64(tv, flow_counters.active_bypass_flows, 0); + StatsSetUI64(tv, flow_counters.total_bypass_flows, 0); + UpdateFlowStats(tv, hInfo, hstat_stream, flow_counters, 1); + } +#endif /* NAPATECH_ENABLE_BYPASS */ + + uint32_t num_active = UpdateStreamStats(tv, hInfo, hstat_stream, stream_cnt, stream_config, + total_counters, dispatch_host, dispatch_drop, dispatch_fwd, is_inline, + enable_stream_stats, stream_counters); + + if (!NapatechIsAutoConfigEnabled() && (num_active < stream_cnt)) { + SCLogInfo("num_active: %d, stream_cnt: %d", num_active, stream_cnt); + SCLogWarning("Some or all of the configured streams are not created. Proceeding with " + "active streams."); + } + + TmThreadsSetFlag(tv, THV_INIT_DONE | THV_RUNNING); + while (1) { + if (TmThreadsCheckFlag(tv, THV_KILL)) { + SCLogDebug("NapatechStatsLoop THV_KILL detected"); + break; + } + + UpdateStreamStats(tv, hInfo, hstat_stream, stream_cnt, stream_config, total_counters, + dispatch_host, dispatch_drop, dispatch_fwd, is_inline, enable_stream_stats, + stream_counters); + +#ifdef NAPATECH_ENABLE_BYPASS + if (bypass_supported) { + UpdateFlowStats(tv, hInfo, hstat_stream, flow_counters, 0); + } +#endif /* NAPATECH_ENABLE_BYPASS */ + + StatsSyncCountersIfSignalled(tv); + usleep(1000000); + } + + /* CLEAN UP NT Resources and Close the info stream */ + if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return NULL; + } + + /* Close the statistics stream */ + if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return NULL; + } + + SCLogDebug("Exiting NapatechStatsLoop"); + TmThreadsSetFlag(tv, THV_RUNNING_DONE); + TmThreadWaitForFlag(tv, THV_DEINIT); + TmThreadsSetFlag(tv, THV_CLOSED); + + return NULL; +} + +#define MAX_HOSTBUFFER 4 +#define MAX_STREAMS 256 +#define HB_HIGHWATER 2048 // 1982 + +/** + * \brief Tests whether a particular stream_id is actively registered + * + * \param stream_id - ID of the stream to look up + * \param num_registered - The total number of registered streams + * \param registered_streams - An array containing actively registered streams. + * + * \return Bool indicating is the specified stream is registered. + * + */ +static bool RegisteredStream( + uint16_t stream_id, uint16_t num_registered, NapatechStreamConfig registered_streams[]) +{ + for (uint16_t reg_id = 0; reg_id < num_registered; ++reg_id) { + if (stream_id == registered_streams[reg_id].stream_id) { + return true; + } + } + return false; +} + +/** + * \brief Count the number of worker threads defined in the conf file. + * + * \return - The number of worker threads defined by the configuration + */ +static uint32_t CountWorkerThreads(void) +{ + int worker_count = 0; + + ConfNode *affinity; + ConfNode *root = ConfGetNode("threading.cpu-affinity"); + + if (root != NULL) { + + TAILQ_FOREACH (affinity, &root->head, next) { + if (strcmp(affinity->val, "decode-cpu-set") == 0 || + strcmp(affinity->val, "stream-cpu-set") == 0 || + strcmp(affinity->val, "reject-cpu-set") == 0 || + strcmp(affinity->val, "output-cpu-set") == 0) { + continue; + } + + if (strcmp(affinity->val, "worker-cpu-set") == 0) { + ConfNode *node = ConfNodeLookupChild(affinity->head.tqh_first, "cpu"); + ConfNode *lnode; + + enum CONFIG_SPECIFIER cpu_spec = CONFIG_SPECIFIER_UNDEFINED; + + TAILQ_FOREACH (lnode, &node->head, next) { + uint8_t start, end; + char *end_str; + if (strncmp(lnode->val, "all", 4) == 0) { + /* check that the sting in the config file is correctly specified */ + if (cpu_spec != CONFIG_SPECIFIER_UNDEFINED) { + FatalError("Only one Napatech port specifier type allowed."); + } + cpu_spec = CONFIG_SPECIFIER_RANGE; + worker_count = UtilCpuGetNumProcessorsConfigured(); + } else if ((end_str = strchr(lnode->val, '-'))) { + /* check that the sting in the config file is correctly specified */ + if (cpu_spec != CONFIG_SPECIFIER_UNDEFINED) { + FatalError("Only one Napatech port specifier type allowed."); + } + cpu_spec = CONFIG_SPECIFIER_RANGE; + + if (StringParseUint8(&start, 10, end_str - lnode->val, + (const char *)lnode->val) < 0) { + FatalError("Napatech invalid" + " worker range start: '%s'", + lnode->val); + } + if (StringParseUint8(&end, 10, 0, (const char *)(end_str + 1)) < 0) { + FatalError("Napatech invalid" + " worker range end: '%s'", + (end_str != NULL) ? (const char *)(end_str + 1) : "Null"); + } + if (end < start) { + FatalError("Napatech invalid" + " worker range start: '%d' is greater than end: '%d'", + start, end); + } + worker_count = end - start + 1; + + } else { + /* check that the sting in the config file is correctly specified */ + if (cpu_spec == CONFIG_SPECIFIER_RANGE) { + FatalError("Napatech port range specifiers cannot be combined with " + "individual stream specifiers."); + } + cpu_spec = CONFIG_SPECIFIER_INDIVIDUAL; + ++worker_count; + } + } + break; + } + } + } + return worker_count; +} + +/** + * \brief Reads and parses the stream configuration defined in the config file. + * + * \param stream_config - array to be filled in with active stream info. + * + * \return the number of streams configured or -1 if an error occurred + * + */ +int NapatechGetStreamConfig(NapatechStreamConfig stream_config[]) +{ + int status; + char error_buffer[80]; // Error buffer + NtStatStream_t hstat_stream; + NtStatistics_t hStat; // Stat handle. + NtInfoStream_t info_stream; + NtInfo_t info; + uint16_t instance_cnt = 0; + int use_all_streams = 0; + int set_cpu_affinity = 0; + ConfNode *ntstreams; + uint16_t stream_id = 0; + uint8_t start = 0; + uint8_t end = 0; + + for (uint16_t i = 0; i < MAX_STREAMS; ++i) { + stream_config[i].stream_id = 0; + stream_config[i].is_active = false; + stream_config[i].initialized = false; + } + + if (ConfGetBool("napatech.use-all-streams", &use_all_streams) == 0) { + /* default is "no" */ + use_all_streams = 0; + } + + if ((status = NT_InfoOpen(&info_stream, "SuricataStreamInfo")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return -1; + } + + if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return -1; + } + + if (use_all_streams) { + info.cmd = NT_INFO_CMD_READ_STREAM; + if ((status = NT_InfoRead(info_stream, &info)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return -1; + } + + while (instance_cnt < info.u.stream.data.count) { + + /* + * For each stream ID query the number of host-buffers used by + * the stream. If zero, then that streamID is not used; skip + * over it and continue until we get a streamID with a non-zero + * count of the host-buffers. + */ + memset(&hStat, 0, sizeof(NtStatistics_t)); + + /* Read usage data for the chosen stream ID */ + hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; + hStat.u.usageData_v0.streamid = (uint8_t)stream_id; + + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + /* Get the status code as text */ + NT_ExplainError(status, error_buffer, sizeof(error_buffer)); + SCLogError("NT_StatRead() failed: %s\n", error_buffer); + return -1; + } + + if (hStat.u.usageData_v0.data.numHostBufferUsed == 0) { + ++stream_id; + continue; + } + + /* if we get here it is an active stream */ + stream_config[instance_cnt].stream_id = stream_id++; + stream_config[instance_cnt].is_active = true; + instance_cnt++; + } + + } else { + (void)ConfGetBool("threading.set-cpu-affinity", &set_cpu_affinity); + if (NapatechIsAutoConfigEnabled() && (set_cpu_affinity == 1)) { + start = 0; + end = CountWorkerThreads() - 1; + } else { + /* When not using the default streams we need to + * parse the array of streams from the conf */ + if ((ntstreams = ConfGetNode("napatech.streams")) == NULL) { + SCLogError("Failed retrieving napatech.streams from Config"); + if (NapatechIsAutoConfigEnabled() && (set_cpu_affinity == 0)) { + SCLogError("if set-cpu-affinity: no in conf then napatech.streams must be " + "defined"); + } + exit(EXIT_FAILURE); + } + + /* Loop through all stream numbers in the array and register the devices */ + ConfNode *stream; + enum CONFIG_SPECIFIER stream_spec = CONFIG_SPECIFIER_UNDEFINED; + instance_cnt = 0; + + TAILQ_FOREACH (stream, &ntstreams->head, next) { + + if (stream == NULL) { + SCLogError("Couldn't Parse Stream Configuration"); + return -1; + } + + char *end_str = strchr(stream->val, '-'); + if (end_str) { + if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) { + SCLogError("Only one Napatech stream range specifier allowed."); + return -1; + } + stream_spec = CONFIG_SPECIFIER_RANGE; + + if (StringParseUint8( + &start, 10, end_str - stream->val, (const char *)stream->val) < 0) { + FatalError("Napatech invalid " + "stream id start: '%s'", + stream->val); + } + if (StringParseUint8(&end, 10, 0, (const char *)(end_str + 1)) < 0) { + FatalError("Napatech invalid " + "stream id end: '%s'", + (end_str != NULL) ? (const char *)(end_str + 1) : "Null"); + } + } else { + if (stream_spec == CONFIG_SPECIFIER_RANGE) { + FatalError("Napatech range and individual specifiers cannot be combined."); + } + stream_spec = CONFIG_SPECIFIER_INDIVIDUAL; + if (StringParseUint8(&stream_config[instance_cnt].stream_id, 10, 0, + (const char *)stream->val) < 0) { + FatalError("Napatech invalid " + "stream id: '%s'", + stream->val); + } + start = stream_config[instance_cnt].stream_id; + end = stream_config[instance_cnt].stream_id; + } + } + } + + for (stream_id = start; stream_id <= end; ++stream_id) { + /* if we get here it is configured in the .yaml file */ + stream_config[instance_cnt].stream_id = stream_id; + + /* Check to see if it is an active stream */ + memset(&hStat, 0, sizeof(NtStatistics_t)); + + /* Read usage data for the chosen stream ID */ + hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; + hStat.u.usageData_v0.streamid = (uint8_t)stream_config[instance_cnt].stream_id; + + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return -1; + } + + if (hStat.u.usageData_v0.data.numHostBufferUsed > 0) { + stream_config[instance_cnt].is_active = true; + } + instance_cnt++; + } + } + + /* Close the statistics stream */ + if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return -1; + } + + if ((status = NT_InfoClose(info_stream)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return -1; + } + + return instance_cnt; +} + +static void *NapatechBufMonitorLoop(void *arg) +{ + ThreadVars *tv = (ThreadVars *)arg; + + NtInfo_t hStreamInfo; + NtStatistics_t hStat; // Stat handle. + NtInfoStream_t hInfo; + NtStatStream_t hstat_stream; + int status; // Status variable + + const uint32_t alertInterval = 25; + +#ifndef NAPATECH_ENABLE_BYPASS + uint32_t OB_fill_level[MAX_STREAMS] = { 0 }; + uint32_t OB_alert_level[MAX_STREAMS] = { 0 }; + uint32_t ave_OB_fill_level[MAX_STREAMS] = { 0 }; +#endif /* NAPATECH_ENABLE_BYPASS */ + + uint32_t HB_fill_level[MAX_STREAMS] = { 0 }; + uint32_t HB_alert_level[MAX_STREAMS] = { 0 }; + uint32_t ave_HB_fill_level[MAX_STREAMS] = { 0 }; + + /* Open the info and Statistics */ + if ((status = NT_InfoOpen(&hInfo, "InfoStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + /* Read the info on all streams instantiated in the system */ + hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM; + if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + NapatechStreamConfig registered_streams[MAX_STREAMS]; + int num_registered = NapatechGetStreamConfig(registered_streams); + if (num_registered == -1) { + exit(EXIT_FAILURE); + } + + TmThreadsSetFlag(tv, THV_INIT_DONE | THV_RUNNING); + while (1) { + if (TmThreadsCheckFlag(tv, THV_KILL)) { + SCLogDebug("NapatechBufMonitorLoop THV_KILL detected"); + break; + } + + usleep(200000); + + /* Read the info on all streams instantiated in the system */ + hStreamInfo.cmd = NT_INFO_CMD_READ_STREAM; + if ((status = NT_InfoRead(hInfo, &hStreamInfo)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + char pktCntStr[4096]; + memset(pktCntStr, 0, sizeof(pktCntStr)); + + uint32_t stream_id = 0; + uint32_t stream_cnt = 0; + uint32_t num_streams = hStreamInfo.u.stream.data.count; + + for (stream_cnt = 0; stream_cnt < num_streams; ++stream_cnt) { + + do { + + /* Read usage data for the chosen stream ID */ + hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; + hStat.u.usageData_v0.streamid = (uint8_t)stream_id; + + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + if (hStat.u.usageData_v0.data.numHostBufferUsed == 0) { + ++stream_id; + continue; + } + } while (hStat.u.usageData_v0.data.numHostBufferUsed == 0); + + if (RegisteredStream(stream_id, num_registered, registered_streams)) { + +#ifndef NAPATECH_ENABLE_BYPASS + ave_OB_fill_level[stream_id] = 0; +#endif /* NAPATECH_ENABLE_BYPASS */ + + ave_HB_fill_level[stream_id] = 0; + + for (uint32_t hb_count = 0; hb_count < hStat.u.usageData_v0.data.numHostBufferUsed; + hb_count++) { + +#ifndef NAPATECH_ENABLE_BYPASS + OB_fill_level[hb_count] = + ((100 * hStat.u.usageData_v0.data.hb[hb_count].onboardBuffering.used) / + hStat.u.usageData_v0.data.hb[hb_count].onboardBuffering.size); + + if (OB_fill_level[hb_count] > 100) { + OB_fill_level[hb_count] = 100; + } +#endif /* NAPATECH_ENABLE_BYPASS */ + uint32_t bufSize = + hStat.u.usageData_v0.data.hb[hb_count].enQueuedAdapter / 1024 + + hStat.u.usageData_v0.data.hb[hb_count].deQueued / 1024 + + hStat.u.usageData_v0.data.hb[hb_count].enQueued / 1024 - HB_HIGHWATER; + + HB_fill_level[hb_count] = (uint32_t)( + (100 * hStat.u.usageData_v0.data.hb[hb_count].deQueued / 1024) / + bufSize); + +#ifndef NAPATECH_ENABLE_BYPASS + ave_OB_fill_level[stream_id] += OB_fill_level[hb_count]; +#endif /* NAPATECH_ENABLE_BYPASS */ + + ave_HB_fill_level[stream_id] += HB_fill_level[hb_count]; + } + +#ifndef NAPATECH_ENABLE_BYPASS + ave_OB_fill_level[stream_id] /= hStat.u.usageData_v0.data.numHostBufferUsed; +#endif /* NAPATECH_ENABLE_BYPASS */ + + ave_HB_fill_level[stream_id] /= hStat.u.usageData_v0.data.numHostBufferUsed; + + /* Host Buffer Fill Level warnings... */ + if (ave_HB_fill_level[stream_id] >= (HB_alert_level[stream_id] + alertInterval)) { + + while (ave_HB_fill_level[stream_id] >= + HB_alert_level[stream_id] + alertInterval) { + HB_alert_level[stream_id] += alertInterval; + } + SCLogPerf("nt%d - Increasing Host Buffer Fill Level : %4d%%", stream_id, + ave_HB_fill_level[stream_id] - 1); + } + + if (HB_alert_level[stream_id] > 0) { + if ((ave_HB_fill_level[stream_id] <= + (HB_alert_level[stream_id] - alertInterval))) { + SCLogPerf("nt%d - Decreasing Host Buffer Fill Level: %4d%%", stream_id, + ave_HB_fill_level[stream_id]); + + while (ave_HB_fill_level[stream_id] <= + (HB_alert_level[stream_id] - alertInterval)) { + if ((HB_alert_level[stream_id]) > 0) { + HB_alert_level[stream_id] -= alertInterval; + } else + break; + } + } + } + +#ifndef NAPATECH_ENABLE_BYPASS + /* On Board SDRAM Fill Level warnings... */ + if (ave_OB_fill_level[stream_id] >= (OB_alert_level[stream_id] + alertInterval)) { + while (ave_OB_fill_level[stream_id] >= + OB_alert_level[stream_id] + alertInterval) { + OB_alert_level[stream_id] += alertInterval; + } + SCLogPerf("nt%d - Increasing Adapter SDRAM Fill Level: %4d%%", stream_id, + ave_OB_fill_level[stream_id]); + } + + if (OB_alert_level[stream_id] > 0) { + if ((ave_OB_fill_level[stream_id] <= + (OB_alert_level[stream_id] - alertInterval))) { + SCLogPerf("nt%d - Decreasing Adapter SDRAM Fill Level : %4d%%", stream_id, + ave_OB_fill_level[stream_id]); + + while (ave_OB_fill_level[stream_id] <= + (OB_alert_level[stream_id] - alertInterval)) { + if ((OB_alert_level[stream_id]) > 0) { + OB_alert_level[stream_id] -= alertInterval; + } else + break; + } + } + } +#endif /* NAPATECH_ENABLE_BYPASS */ + } + ++stream_id; + } + } + + if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + /* Close the statistics stream */ + if ((status = NT_StatClose(hstat_stream)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + SCLogDebug("Exiting NapatechStatsLoop"); + TmThreadsSetFlag(tv, THV_RUNNING_DONE); + TmThreadWaitForFlag(tv, THV_DEINIT); + TmThreadsSetFlag(tv, THV_CLOSED); + + return NULL; +} + +void NapatechStartStats(void) +{ + /* Creates the Statistic threads */ + ThreadVars *stats_tv = + TmThreadCreate("NapatechStats", NULL, NULL, NULL, NULL, "custom", NapatechStatsLoop, 0); + + if (stats_tv == NULL) { + FatalError("Error creating a thread for NapatechStats - Killing engine."); + } + + if (TmThreadSpawn(stats_tv) != 0) { + FatalError("Failed to spawn thread for NapatechStats - Killing engine."); + } + +#ifdef NAPATECH_ENABLE_BYPASS + if (bypass_supported) { + SCLogInfo("Napatech bypass functionality enabled."); + } +#endif /* NAPATECH_ENABLE_BYPASS */ + + ThreadVars *buf_monitor_tv = TmThreadCreate( + "NapatechBufMonitor", NULL, NULL, NULL, NULL, "custom", NapatechBufMonitorLoop, 0); + + if (buf_monitor_tv == NULL) { + FatalError("Error creating a thread for NapatechBufMonitor - Killing engine."); + } + + if (TmThreadSpawn(buf_monitor_tv) != 0) { + FatalError("Failed to spawn thread for NapatechBufMonitor - Killing engine."); + } + + return; +} + +bool NapatechSetupNuma(uint32_t stream, uint32_t numa) +{ + uint32_t status = 0; + static NtConfigStream_t hconfig; + + char ntpl_cmd[64]; + snprintf(ntpl_cmd, 64, "setup[numanode=%d] = streamid == %d", numa, stream); + + NtNtplInfo_t ntpl_info; + + if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return false; + } + + if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) == + NT_SUCCESS) { + status = ntpl_info.ntplId; + + } else { + NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); + return false; + } + + return status; +} + +static uint32_t NapatechSetHashmode(void) +{ + uint32_t status = 0; + const char *hash_mode; + static NtConfigStream_t hconfig; + char ntpl_cmd[64]; + NtNtplInfo_t ntpl_info; + + uint32_t filter_id = 0; + + /* Get the hashmode from the conf file. */ + ConfGet("napatech.hashmode", &hash_mode); + + snprintf(ntpl_cmd, 64, "hashmode = %s", hash_mode); + + /* Issue the NTPL command */ + if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + return false; + } + + if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) == + NT_SUCCESS) { + filter_id = ntpl_info.ntplId; + SCLogConfig("Napatech hashmode: %s ID: %d", hash_mode, status); + } else { + NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); + status = 0; + } + + return filter_id; +} + +static uint32_t GetStreamNUMAs(uint32_t stream_id, int stream_numas[]) +{ + NtStatistics_t hStat; // Stat handle. + NtStatStream_t hstat_stream; + int status; // Status variable + + for (int i = 0; i < MAX_HOSTBUFFERS; ++i) + stream_numas[i] = -1; + + if ((status = NT_StatOpen(&hstat_stream, "StatsStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + char pktCntStr[4096]; + memset(pktCntStr, 0, sizeof(pktCntStr)); + + /* Read usage data for the chosen stream ID */ + hStat.cmd = NT_STATISTICS_READ_CMD_USAGE_DATA_V0; + hStat.u.usageData_v0.streamid = (uint8_t)stream_id; + + if ((status = NT_StatRead(hstat_stream, &hStat)) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + for (uint32_t hb_id = 0; hb_id < hStat.u.usageData_v0.data.numHostBufferUsed; ++hb_id) { + stream_numas[hb_id] = hStat.u.usageData_v0.data.hb[hb_id].numaNode; + } + + return hStat.u.usageData_v0.data.numHostBufferUsed; +} + +static int NapatechSetFilter(NtConfigStream_t hconfig, char *ntpl_cmd) +{ + int status = 0; + int local_filter_id = 0; + + NtNtplInfo_t ntpl_info; + if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) == + NT_SUCCESS) { + SCLogConfig( + "NTPL filter assignment \"%s\" returned filter id %4d", ntpl_cmd, local_filter_id); + } else { + NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); + exit(EXIT_FAILURE); + } + + return local_filter_id; +} + +uint32_t NapatechDeleteFilters(void) +{ + uint32_t status = 0; + static NtConfigStream_t hconfig; + char ntpl_cmd[64]; + NtNtplInfo_t ntpl_info; + + if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + snprintf(ntpl_cmd, 64, "delete = all"); + if ((status = NT_NTPL(hconfig, ntpl_cmd, &ntpl_info, NT_NTPL_PARSER_VALIDATE_NORMAL)) == + NT_SUCCESS) { + status = ntpl_info.ntplId; + } else { + NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status); + status = 0; + } + + NT_ConfigClose(hconfig); + + return status; +} + +uint32_t NapatechSetupTraffic(uint32_t first_stream, uint32_t last_stream) +{ +#define PORTS_SPEC_SIZE 64 + + struct ports_spec_s { + uint8_t first[MAX_PORTS]; + uint8_t second[MAX_PORTS]; + bool all; + char str[PORTS_SPEC_SIZE]; + } ports_spec; + + ports_spec.all = false; + + ConfNode *ntports; + int iteration = 0; + int status = 0; + NtConfigStream_t hconfig; + char ntpl_cmd[512]; + int is_inline = 0; +#ifdef NAPATECH_ENABLE_BYPASS + int is_span_port[MAX_PORTS] = { 0 }; +#endif + + char span_ports[128]; + memset(span_ports, 0, sizeof(span_ports)); + + if (ConfGetBool("napatech.inline", &is_inline) == 0) { + is_inline = 0; + } + + NapatechSetHashmode(); + + if ((status = NT_ConfigOpen(&hconfig, "ConfigStream")) != NT_SUCCESS) { + NAPATECH_ERROR(status); + exit(EXIT_FAILURE); + } + + if (first_stream == last_stream) { + snprintf( + ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=inactive] = StreamId == %d", first_stream); + } else { + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=inactive] = StreamId == (%d..%d)", + first_stream, last_stream); + } + NapatechSetFilter(hconfig, ntpl_cmd); + +#ifdef NAPATECH_ENABLE_BYPASS + if (NapatechUseHWBypass()) { + SCLogInfo("Napatech Hardware Bypass enabled."); + } +#else + if (NapatechUseHWBypass()) { + SCLogInfo("Napatech Hardware Bypass requested in conf but is not available."); + exit(EXIT_FAILURE); + } else { + SCLogInfo("Napatech Hardware Bypass disabled."); + } +#endif + + if (is_inline) { + SCLogInfo("Napatech configured for inline mode."); + } else { + + SCLogInfo("Napatech configured for passive (non-inline) mode."); + } + + /* When not using the default streams we need to parse + * the array of streams from the conf + */ + if ((ntports = ConfGetNode("napatech.ports")) == NULL) { + FatalError("Failed retrieving napatech.ports from Conf"); + } + + /* Loop through all ports in the array */ + ConfNode *port; + enum CONFIG_SPECIFIER stream_spec = CONFIG_SPECIFIER_UNDEFINED; + + if (NapatechUseHWBypass()) { + SCLogInfo("Listening on the following Napatech ports:"); + } + /* Build the NTPL command using values in the config file. */ + TAILQ_FOREACH (port, &ntports->head, next) { + if (port == NULL) { + FatalError("Couldn't Parse Port Configuration"); + } + + if (NapatechUseHWBypass()) { +#ifdef NAPATECH_ENABLE_BYPASS + if (strchr(port->val, '-')) { + stream_spec = CONFIG_SPECIFIER_RANGE; + + if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) { + FatalError("Invalid value '%s' in napatech.ports specification in conf file.", + port->val); + } + + if (ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0, + strchr(port->val, '-') + 1) == -1) { + FatalError("Invalid value '%s' in napatech.ports specification in conf file.", + port->val); + } + + if (ports_spec.first[iteration] == ports_spec.second[iteration]) { + if (is_inline) { + FatalError( + "Error with napatech.ports in conf file. When running in inline " + "mode the two ports specifying a segment must be different."); + } else { + /* SPAN port configuration */ + is_span_port[ports_spec.first[iteration]] = 1; + + if (strlen(span_ports) == 0) { + snprintf(span_ports, sizeof(span_ports), "%d", + ports_spec.first[iteration]); + } else { + char temp[16]; + snprintf(temp, sizeof(temp), ",%d", ports_spec.first[iteration]); + strlcat(span_ports, temp, sizeof(span_ports)); + } + } + } + + if (NapatechGetAdapter(ports_spec.first[iteration]) != + NapatechGetAdapter(ports_spec.first[iteration])) { + SCLogError("Invalid napatech.ports specification in conf file."); + SCLogError("Two ports on a segment must reside on the same adapter. port %d " + "is on adapter %d, port %d is on adapter %d.", + ports_spec.first[iteration], + NapatechGetAdapter(ports_spec.first[iteration]), + ports_spec.second[iteration], + NapatechGetAdapter(ports_spec.second[iteration])); + exit(EXIT_FAILURE); + } + + NapatechSetPortmap(ports_spec.first[iteration], ports_spec.second[iteration]); + if (ports_spec.first[iteration] == ports_spec.second[iteration]) { + SCLogInfo(" span_port: %d", ports_spec.first[iteration]); + } else { + SCLogInfo(" %s: %d - %d", is_inline ? "inline_ports" : "tap_ports", + ports_spec.first[iteration], ports_spec.second[iteration]); + } + + if (iteration == 0) { + if (ports_spec.first[iteration] == ports_spec.second[iteration]) { + snprintf(ports_spec.str, sizeof(ports_spec.str), "%d", + ports_spec.first[iteration]); + } else { + snprintf(ports_spec.str, sizeof(ports_spec.str), "%d,%d", + ports_spec.first[iteration], ports_spec.second[iteration]); + } + } else { + char temp[16]; + if (ports_spec.first[iteration] == ports_spec.second[iteration]) { + snprintf(temp, sizeof(temp), ",%d", ports_spec.first[iteration]); + } else { + snprintf(temp, sizeof(temp), ",%d,%d", ports_spec.first[iteration], + ports_spec.second[iteration]); + } + strlcat(ports_spec.str, temp, sizeof(ports_spec.str)); + } + } else { + FatalError("When using hardware flow bypass ports must be specified as segments. " + "E.g. ports: [0-1, 0-2]"); + } +#endif + } else { // !NapatechUseHWBypass() + if (strncmp(port->val, "all", 3) == 0) { + /* check that the sting in the config file is correctly specified */ + if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) { + FatalError("Only one Napatech port specifier type is allowed."); + } + stream_spec = CONFIG_SPECIFIER_RANGE; + + ports_spec.all = true; + snprintf(ports_spec.str, sizeof(ports_spec.str), "all"); + } else if (strchr(port->val, '-')) { + /* check that the sting in the config file is correctly specified */ + if (stream_spec != CONFIG_SPECIFIER_UNDEFINED) { + FatalError("Only one Napatech port specifier is allowed when hardware bypass " + "is disabled. (E.g. ports: [0-4], NOT ports: [0-1,2-3])"); + } + stream_spec = CONFIG_SPECIFIER_RANGE; + + if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) { + FatalError("Invalid value '%s' in napatech.ports specification in conf file.", + port->val); + } + + if (ByteExtractStringUint8(&ports_spec.second[iteration], 10, 0, + strchr(port->val, '-') + 1) == -1) { + FatalError("Invalid value '%s' in napatech.ports specification in conf file.", + port->val); + } + + snprintf(ports_spec.str, sizeof(ports_spec.str), "(%d..%d)", + ports_spec.first[iteration], ports_spec.second[iteration]); + } else { + /* check that the sting in the config file is correctly specified */ + if (stream_spec == CONFIG_SPECIFIER_RANGE) { + FatalError("Napatech port range specifiers cannot be combined with individual " + "stream specifiers."); + } + stream_spec = CONFIG_SPECIFIER_INDIVIDUAL; + + if (ByteExtractStringUint8(&ports_spec.first[iteration], 10, 0, port->val) == -1) { + FatalError("Invalid value '%s' in napatech.ports specification in conf file.", + port->val); + } + + /* Determine the ports to use on the NTPL assign statement*/ + if (iteration == 0) { + snprintf(ports_spec.str, sizeof(ports_spec.str), "%s", port->val); + } else { + strlcat(ports_spec.str, ",", sizeof(ports_spec.str)); + strlcat(ports_spec.str, port->val, sizeof(ports_spec.str)); + } + } + } // if !NapatechUseHWBypass() + ++iteration; + } /* TAILQ_FOREACH */ + +#ifdef NAPATECH_ENABLE_BYPASS + if (bypass_supported) { + if (is_inline) { + char inline_setup_cmd[512]; + if (first_stream == last_stream) { + snprintf(inline_setup_cmd, sizeof(ntpl_cmd), + "Setup[TxDescriptor=Dyn;TxPorts=%s;RxCRC=False;TxPortPos=112;UseWL=True] = " + "StreamId == %d", + ports_spec.str, first_stream); + } else { + snprintf(inline_setup_cmd, sizeof(ntpl_cmd), + "Setup[TxDescriptor=Dyn;TxPorts=%s;RxCRC=False;TxPortPos=112;UseWL=True] = " + "StreamId == (%d..%d)", + ports_spec.str, first_stream, last_stream); + } + NapatechSetFilter(hconfig, inline_setup_cmd); + } + /* Build the NTPL command */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=3;streamid=(%d..%d);colormask=0x10000000;" + "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=" + "Layer4Header[0]]= %s%s", + first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=2;streamid=(%d..%d);colormask=0x11000000;" + "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=" + "Layer4Header[0]" + "]= %s%s and (Layer3Protocol==IPV4)", + first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=2;streamid=(%d..%d);colormask=0x14000000;" + "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=" + "Layer4Header[0]]= %s%s and (Layer3Protocol==IPV6)", + first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=2;streamid=(%d..%d);colormask=0x10100000;" + "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=" + "Layer4Header[0]]= %s%s and (Layer4Protocol==TCP)", + first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=2;streamid=(%d..%d);colormask=0x10200000;" + "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=" + "Layer4Header[0]" + "]= %s%s and (Layer4Protocol==UDP)", + first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); + NapatechSetFilter(hconfig, ntpl_cmd); + + if (strlen(span_ports) > 0) { + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=2;streamid=(%d..%d);colormask=0x00001000;" + "Descriptor=DYN3,length=24,colorbits=32,Offset0=Layer3Header[0],Offset1=" + "Layer4Header[0]" + "]= port==%s", + first_stream, last_stream, span_ports); + NapatechSetFilter(hconfig, ntpl_cmd); + } + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={sw_32_32,sw_16_16}", + NAPATECH_KEYTYPE_IPV4); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER]=(Layer3Header[12]/32/" + "32,Layer4Header[0]/16/16)", + NAPATECH_KEYTYPE_IPV4, NAPATECH_KEYTYPE_IPV4); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={32,32,16,16}", + NAPATECH_KEYTYPE_IPV4_SPAN); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER;keysort=sorted]=(" + "Layer3Header[12]/32,Layer3Header[16]/32,Layer4Header[0]/16,Layer4Header[2]/16)", + NAPATECH_KEYTYPE_IPV4_SPAN, NAPATECH_KEYTYPE_IPV4_SPAN); + NapatechSetFilter(hconfig, ntpl_cmd); + + /* IPv6 5tuple for inline and tap ports */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={sw_128_128,sw_16_16}", + NAPATECH_KEYTYPE_IPV6); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER]=(Layer3Header[8]/128/" + "128,Layer4Header[0]/16/16)", + NAPATECH_KEYTYPE_IPV6, NAPATECH_KEYTYPE_IPV6); + NapatechSetFilter(hconfig, ntpl_cmd); + + /* IPv6 5tuple for SPAN Ports */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "KeyType[name=KT%u]={128,128,16,16}", + NAPATECH_KEYTYPE_IPV6_SPAN); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "KeyDef[name=KDEF%u;KeyType=KT%u;ipprotocolfield=OUTER;keysort=sorted]=(" + "Layer3Header[8]/128,Layer3Header[24]/128,Layer4Header[0]/16,Layer4Header[2]/16)", + NAPATECH_KEYTYPE_IPV6_SPAN, NAPATECH_KEYTYPE_IPV6_SPAN); + NapatechSetFilter(hconfig, ntpl_cmd); + + int pair; + char ports_ntpl_a[64]; + char ports_ntpl_b[64]; + memset(ports_ntpl_a, 0, sizeof(ports_ntpl_a)); + memset(ports_ntpl_b, 0, sizeof(ports_ntpl_b)); + + for (pair = 0; pair < iteration; ++pair) { + char port_str[8]; + + if (!is_span_port[ports_spec.first[pair]]) { + snprintf(port_str, sizeof(port_str), "%s%u ", strlen(ports_ntpl_a) == 0 ? "" : ",", + ports_spec.first[pair]); + strlcat(ports_ntpl_a, port_str, sizeof(ports_ntpl_a)); + + snprintf(port_str, sizeof(port_str), "%s%u ", strlen(ports_ntpl_b) == 0 ? "" : ",", + ports_spec.second[pair]); + strlcat(ports_ntpl_b, port_str, sizeof(ports_ntpl_b)); + } + } + + if (strlen(ports_ntpl_a) > 0) { + /* This is the assign for dropping upstream traffic */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port " + "== %s)and(Key(KDEF%u,KeyID=%u)==%u)", + ports_ntpl_a, NAPATECH_KEYTYPE_IPV4, NAPATECH_KEYTYPE_IPV4, + NAPATECH_FLOWTYPE_DROP); + NapatechSetFilter(hconfig, ntpl_cmd); + } + + if (strlen(ports_ntpl_b) > 0) { + /* This is the assign for dropping downstream traffic */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port " + "== %s)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)", + ports_ntpl_b, // ports_spec.str, + NAPATECH_KEYTYPE_IPV4, NAPATECH_KEYTYPE_IPV4, NAPATECH_FLOWTYPE_DROP); + NapatechSetFilter(hconfig, ntpl_cmd); + } + + if (strlen(span_ports) > 0) { + /* This is the assign for dropping SPAN Port traffic */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV4)and(port " + "== %s)and(Key(KDEF%u,KeyID=%u)==%u)", + span_ports, NAPATECH_KEYTYPE_IPV4_SPAN, NAPATECH_KEYTYPE_IPV4_SPAN, + NAPATECH_FLOWTYPE_DROP); + NapatechSetFilter(hconfig, ntpl_cmd); + } + + if (is_inline) { + for (pair = 0; pair < iteration; ++pair) { + /* This is the assignment for forwarding traffic */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x2]=(" + "Layer3Protocol==IPV4)and(port == %d)and(Key(KDEF%u,KeyID=%u)==%u)", + ports_spec.second[pair], ports_spec.first[pair], NAPATECH_KEYTYPE_IPV4, + NAPATECH_KEYTYPE_IPV4, NAPATECH_FLOWTYPE_PASS); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x2]=(" + "Layer3Protocol==IPV4)and(port == " + "%d)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)", + ports_spec.first[pair], ports_spec.second[pair], NAPATECH_KEYTYPE_IPV4, + NAPATECH_KEYTYPE_IPV4, NAPATECH_FLOWTYPE_PASS); + NapatechSetFilter(hconfig, ntpl_cmd); + } + } + + if (strlen(ports_ntpl_a) > 0) { + /* This is the assign for dropping upstream traffic */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port " + "== %s)and(Key(KDEF%u,KeyID=%u)==%u)", + ports_ntpl_a, NAPATECH_KEYTYPE_IPV6, NAPATECH_KEYTYPE_IPV6, + NAPATECH_FLOWTYPE_DROP); + NapatechSetFilter(hconfig, ntpl_cmd); + } + + if (strlen(ports_ntpl_b) > 0) { + /* This is the assign for dropping downstream traffic */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port " + "== %s)and(Key(KDEF%u,KeyID=%u,fieldaction=swap)==%u)", + ports_ntpl_b, // ports_spec.str, + NAPATECH_KEYTYPE_IPV6, NAPATECH_KEYTYPE_IPV6, NAPATECH_FLOWTYPE_DROP); + NapatechSetFilter(hconfig, ntpl_cmd); + } + + if (strlen(span_ports) > 0) { + /* This is the assign for dropping SPAN Port traffic */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;colormask=0x1]=(Layer3Protocol==IPV6)and(port " + "== %s)and(Key(KDEF%u,KeyID=%u)==%u)", + span_ports, NAPATECH_KEYTYPE_IPV6_SPAN, NAPATECH_KEYTYPE_IPV6_SPAN, + NAPATECH_FLOWTYPE_DROP); + NapatechSetFilter(hconfig, ntpl_cmd); + } + + if (is_inline) { + for (pair = 0; pair < iteration; ++pair) { + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x4]=(" + "Layer3Protocol==IPV6)and(port==%d)and(Key(KDEF%u,KeyID=%u)==%u)", + ports_spec.second[pair], ports_spec.first[pair], NAPATECH_KEYTYPE_IPV6, + NAPATECH_KEYTYPE_IPV6, NAPATECH_FLOWTYPE_PASS); + NapatechSetFilter(hconfig, ntpl_cmd); + + snprintf(ntpl_cmd, sizeof(ntpl_cmd), + "assign[priority=1;streamid=drop;DestinationPort=%d;colormask=0x4]=(" + "Layer3Protocol==IPV6)and(port==%d)and(Key(KDEF%u,KeyID=%u,fieldaction=" + "swap)==%u)", + ports_spec.first[pair], ports_spec.second[pair], NAPATECH_KEYTYPE_IPV6, + NAPATECH_KEYTYPE_IPV6, NAPATECH_FLOWTYPE_PASS); + NapatechSetFilter(hconfig, ntpl_cmd); + } + } + } else { + if (is_inline) { + FatalError("Napatech Inline operation not supported by this FPGA version."); + } + + if (NapatechIsAutoConfigEnabled()) { + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "assign[streamid=(%d..%d);colormask=0x0] = %s%s", + first_stream, last_stream, ports_spec.all ? "" : "port==", ports_spec.str); + NapatechSetFilter(hconfig, ntpl_cmd); + } + } + +#else /* NAPATECH_ENABLE_BYPASS */ + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "assign[streamid=(%d..%d)] = %s%s", first_stream, + last_stream, ports_spec.all ? "" : "port==", ports_spec.str); + NapatechSetFilter(hconfig, ntpl_cmd); + +#endif /* !NAPATECH_ENABLE_BYPASS */ + + SCLogConfig("Host-buffer NUMA assignments: "); + int numa_nodes[MAX_HOSTBUFFERS]; + uint32_t stream_id; + for (stream_id = first_stream; stream_id < last_stream; ++stream_id) { + char temp1[256]; + char temp2[256]; + + uint32_t num_host_buffers = GetStreamNUMAs(stream_id, numa_nodes); + + snprintf(temp1, 256, " stream %d: ", stream_id); + + for (uint32_t hb_id = 0; hb_id < num_host_buffers; ++hb_id) { + snprintf(temp2, 256, "%d ", numa_nodes[hb_id]); + strlcat(temp1, temp2, sizeof(temp1)); + } + + SCLogConfig("%s", temp1); + } + + if (first_stream == last_stream) { + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=active] = StreamId == %d", first_stream); + } else { + snprintf(ntpl_cmd, sizeof(ntpl_cmd), "Setup[state=active] = StreamId == (%d..%d)", + first_stream, last_stream); + } + NapatechSetFilter(hconfig, ntpl_cmd); + + NT_ConfigClose(hconfig); + + return status; +} + +#endif // HAVE_NAPATECH diff --git a/src/util/napatech.h b/src/util/napatech.h new file mode 100644 index 000000000000..9b0a20135223 --- /dev/null +++ b/src/util/napatech.h @@ -0,0 +1,117 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +/** + * \file + * + * \author Phil Young + * + */ +#ifndef __UTIL_NAPATECH_H__ +#define __UTIL_NAPATECH_H__ + +#ifdef HAVE_NAPATECH +#include + +typedef struct NapatechPacketVars_ { + uint64_t stream_id; + NtNetBuf_t nt_packet_buf; + NtNetStreamRx_t rx_stream; + NtFlowStream_t flow_stream; + ThreadVars *tv; +#ifdef NAPATECH_ENABLE_BYPASS + NtDyn3Descr_t *dyn3; + int bypass; +#endif +} NapatechPacketVars; + +typedef struct NapatechStreamConfig_ { + uint8_t stream_id; + bool is_active; + bool initialized; +} NapatechStreamConfig; + +typedef struct NapatechCurrentStats_ { + uint64_t current_packets; + uint64_t current_bytes; + uint64_t current_drop_packets; + uint64_t current_drop_bytes; +} NapatechCurrentStats; + +#define MAX_HOSTBUFFER 4 +#define MAX_STREAMS 256 +#define MAX_PORTS 80 +#define MAX_ADAPTERS 8 +#define HB_HIGHWATER 2048 // 1982 + +extern void NapatechStartStats(void); + +#define NAPATECH_ERROR(status) \ + { \ + char errorBuffer[1024]; \ + NT_ExplainError((status), errorBuffer, sizeof(errorBuffer) - 1); \ + SCLogError("Napatech Error: %s", errorBuffer); \ + } + +#define NAPATECH_NTPL_ERROR(ntpl_cmd, ntpl_info, status) \ + { \ + char errorBuffer[1024]; \ + NT_ExplainError(status, errorBuffer, sizeof(errorBuffer) - 1); \ + SCLogError(" NTPL failed: %s", errorBuffer); \ + SCLogError(" cmd: %s", ntpl_cmd); \ + if (strncmp(ntpl_info.u.errorData.errBuffer[0], "", 256) != 0) \ + SCLogError(" %s", ntpl_info.u.errorData.errBuffer[0]); \ + if (strncmp(ntpl_info.u.errorData.errBuffer[1], "", 256) != 0) \ + SCLogError(" %s", ntpl_info.u.errorData.errBuffer[1]); \ + if (strncmp(ntpl_info.u.errorData.errBuffer[2], "", 256) != 0) \ + SCLogError(" %s", ntpl_info.u.errorData.errBuffer[2]); \ + } + +// #define ENABLE_NT_DEBUG +#ifdef ENABLE_NT_DEBUG +void NapatechPrintIP(uint32_t address); + +#define NAPATECH_DEBUG(...) printf(__VA_ARGS__) +#define NAPATECH_PRINTIP(a) NapatechPrintIP(uint32_t address) +#else +#define NAPATECH_DEBUG(...) +#define NAPATECH_PRINTIP(a) +#endif + +NapatechCurrentStats NapatechGetCurrentStats(uint16_t id); +int NapatechGetStreamConfig(NapatechStreamConfig stream_config[]); +bool NapatechSetupNuma(uint32_t stream, uint32_t numa); +uint32_t NapatechSetupTraffic(uint32_t first_stream, uint32_t last_stream); +uint32_t NapatechDeleteFilters(void); + +#ifdef NAPATECH_ENABLE_BYPASS + +/* */ +#define NAPATECH_KEYTYPE_IPV4 3 +#define NAPATECH_KEYTYPE_IPV4_SPAN 4 +#define NAPATECH_KEYTYPE_IPV6 5 +#define NAPATECH_KEYTYPE_IPV6_SPAN 6 +#define NAPATECH_FLOWTYPE_DROP 7 +#define NAPATECH_FLOWTYPE_PASS 8 + +int NapatechVerifyBypassSupport(void); +int NapatechGetNumAdapters(void); + +int NapatechIsBypassSupported(void); + +#endif /* NAPATECH_ENABLE_BYPASS */ +#endif /* HAVE_NAPATECH */ +#endif /* __UTIL_NAPATECH_H__ */ diff --git a/src/util/optimize.h b/src/util/optimize.h new file mode 100644 index 000000000000..5df31fcc4ee5 --- /dev/null +++ b/src/util/optimize.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_OPTIMIZE_H__ +#define __UTIL_OPTIMIZE_H__ + +/** + * \file + * + * \author Victor Julien + */ + +#if CPPCHECK == 1 +#define likely +#define unlikely +#else +#ifndef likely +#define likely(expr) __builtin_expect(!!(expr), 1) +#endif +#ifndef unlikely +#define unlikely(expr) __builtin_expect(!!(expr), 0) +#endif +#endif + +/** from http://en.wikipedia.org/wiki/Memory_ordering + * + * C Compiler memory barrier + */ +#define cc_barrier() __asm__ __volatile__("" : : : "memory") + +/** from http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html + * + * Hardware memory barrier + */ +#define hw_barrier() __sync_synchronize() + +#endif /* __UTIL_OPTIMIZE_H__ */ diff --git a/src/util/pages.c b/src/util/pages.c new file mode 100644 index 000000000000..996db32fbf6c --- /dev/null +++ b/src/util/pages.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Page util functions + */ + +#include "suricata-common.h" +#include "util/pages.h" +#include "util/debug.h" + +#ifndef HAVE_PAGESUPPORTSRWX_AS_MACRO + +/** \brief check if OS allows for RWX pages + * + * Some OS' disallow RWX pages for security reasons. This function mmaps + * some memory RW and then tries to turn it into RWX. If this fails we + * assume that the OS doesn't allow for this. + * + * Thanks to Shawn Webb from HardenedBSD for the suggestion. + * + * \retval 1 RWX supported + * \retval 0 not supported + */ +int PageSupportsRWX(void) +{ + int retval = 1; + void *ptr; + ptr = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); + if (ptr != MAP_FAILED) { + if (mprotect(ptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { + SCLogConfig("RWX pages denied by OS"); + retval = 0; + } + munmap(ptr, getpagesize()); + } + return retval; +} +#endif /* HAVE_PAGESUPPORTSRWX_AS_MACRO */ diff --git a/src/util/pages.h b/src/util/pages.h new file mode 100644 index 000000000000..3ca1490de036 --- /dev/null +++ b/src/util/pages.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#ifndef __UTIL_PAGES_H__ +#define __UTIL_PAGES_H__ + +#include "suricata-common.h" + +#ifdef __OpenBSD__ +/* OpenBSD won't allow for this test: + * "suricata(...): mprotect W^X violation" */ +#define PageSupportsRWX() 0 +#define HAVE_PAGESUPPORTSRWX_AS_MACRO 1 +#else +#ifndef HAVE_SYS_MMAN_H +#define PageSupportsRWX() 1 +#define HAVE_PAGESUPPORTSRWX_AS_MACRO 1 +#else +int PageSupportsRWX(void); +#endif /* HAVE_SYS_MMAN_H */ +#endif + +#endif /* __UTIL_PAGES_H__ */ diff --git a/src/util/path.c b/src/util/path.c new file mode 100644 index 000000000000..aea04cea8321 --- /dev/null +++ b/src/util/path.c @@ -0,0 +1,314 @@ +/* Copyright (C) 2007-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util/debug.h" +#include "util/path.h" + +#ifdef OS_WIN32 +#define DIRECTORY_SEPARATOR '\\' +#else +#define DIRECTORY_SEPARATOR '/' +#endif + +/** + * \brief Check if a path is absolute + * + * \param path string with the path + * + * \retval 1 absolute + * \retval 0 not absolute + */ +int PathIsAbsolute(const char *path) +{ + if (strlen(path) > 1 && path[0] == '/') { + return 1; + } + +#if (defined OS_WIN32 || defined __CYGWIN__) + if (strlen(path) > 2) { + if (isalpha((unsigned char)path[0]) && path[1] == ':') { + return 1; + } + } +#endif + + return 0; +} + +/** + * \brief Check if a path is relative + * + * \param path string with the path + * + * \retval 1 relative + * \retval 0 not relative + */ +int PathIsRelative(const char *path) +{ + return PathIsAbsolute(path) ? 0 : 1; +} + +int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname) +{ + char path[PATH_MAX]; + if (dir == NULL || strlen(dir) == 0) + return -1; + + size_t r = strlcpy(path, dir, sizeof(path)); + if (r >= sizeof(path)) { + return -1; + } + +#if defined OS_WIN32 || defined __CYGWIN__ + if (path[strlen(path) - 1] != '\\') + r = strlcat(path, "\\\\", sizeof(path)); +#else + if (path[strlen(path) - 1] != '/') + r = strlcat(path, "/", sizeof(path)); +#endif + if (r >= sizeof(path)) { + return -1; + } + r = strlcat(path, fname, sizeof(path)); + if (r >= sizeof(path)) { + return -1; + } + r = strlcpy(out_buf, path, buf_size); + if (r >= buf_size) { + return -1; + } + + return 0; +} + +char *PathMergeAlloc(const char *const dir, const char *const fname) +{ + char path[PATH_MAX]; + if (PathMerge(path, sizeof(path), dir, fname) != 0) + return NULL; + + char *ret = SCStrdup(path); + if (ret == NULL) + return NULL; + + return ret; +} + +/** + * \brief Wrapper to join a directory and filename and resolve using realpath + * _fullpath is used for WIN32 + * + * \param out_buf output buffer. Up to PATH_MAX will be written. Unchanged on exit failure. + * \param buf_size length of output buffer, must be PATH_MAX + * \param dir the directory + * \param fname the filename + * + * \retval 0 on success + * \retval -1 on failure + */ +int PathJoin(char *out_buf, size_t buf_size, const char *const dir, const char *const fname) +{ + SCEnter(); + if (buf_size != PATH_MAX) { + return -1; + } + if (PathMerge(out_buf, buf_size, dir, fname) != 0) { + SCLogError("Could not join filename to path"); + return -1; + } + char *tmp_buf = SCRealPath(out_buf, NULL); + if (tmp_buf == NULL) { + SCLogError("Error resolving path: %s", strerror(errno)); + return -1; + } + memset(out_buf, 0, buf_size); + size_t ret = strlcpy(out_buf, tmp_buf, buf_size); + free(tmp_buf); + if (ret >= buf_size) { + return -1; + } + return 0; +} + +/** + * \brief Wrapper around SCMkDir with default mode arguments. + */ +int SCDefaultMkDir(const char *path) +{ + return SCMkDir(path, S_IRWXU | S_IRGRP | S_IXGRP); +} + +/** + * \brief Recursively create a directory. + * + * \param path Path to create + * \param final true will create the final path component, false will not + * + * \retval 0 on success + * \retval -1 on error + */ +int SCCreateDirectoryTree(const char *path, const bool final) +{ + char pathbuf[PATH_MAX]; + char *p; + size_t len = strlen(path); + + if (len > PATH_MAX - 1) { + return -1; + } + + strlcpy(pathbuf, path, sizeof(pathbuf)); + + for (p = pathbuf + 1; *p; p++) { + if (*p == '/') { + /* Truncate, while creating directory */ + *p = '\0'; + + if (SCDefaultMkDir(pathbuf) != 0) { + if (errno != EEXIST) { + return -1; + } + } + + *p = '/'; + } + } + + if (final) { + if (SCDefaultMkDir(pathbuf) != 0) { + if (errno != EEXIST) { + return -1; + } + } + } + + return 0; +} + +/** + * \brief Check if a path exists. + * + * \param Path to check for existence + * + * \retval true if path exists + * \retval false if path does not exist + */ +bool SCPathExists(const char *path) +{ + struct stat sb; + if (stat(path, &sb) == 0) { + return true; + } + return false; +} + +/** + * \brief OS independent wrapper for directory check + * + * \param dir_entry object to check + * + * \retval True if the object is a regular directory, otherwise false. This directory + * and parent directory will return false. + */ +bool SCIsRegularDirectory(const struct dirent *const dir_entry) +{ +#ifndef OS_WIN32 + if ((dir_entry->d_type == DT_DIR) && (strcmp(dir_entry->d_name, ".") != 0) && + (strcmp(dir_entry->d_name, "..") != 0)) { + return true; + } +#endif + return false; +} +/** + * \brief OS independent to check for regular file + * + * \param dir_entry object to check + * + * \retval True if the object is a regular file. Otherwise false. + */ +bool SCIsRegularFile(const struct dirent *const dir_entry) +{ +#ifndef OS_WIN32 + return dir_entry->d_type == DT_REG; +#endif + return false; +} + +/** + * \brief OS independent wrapper for realpath + * + * \param path the path to resolve + * \param resolved_path the resolved path; if null, a buffer will be allocated + * + * \retval the resolved_path; or a pointer to a new resolved_path buffer + */ +char *SCRealPath(const char *path, char *resolved_path) +{ +#ifdef OS_WIN32 + return _fullpath(resolved_path, path, PATH_MAX); +#else + return realpath(path, resolved_path); +#endif +} + +/* + * \brief Return the basename of the provided path. + * \param path The path on which to compute the basename + * + * \retval the basename of the path or NULL if the path lacks a non-leaf + */ +const char *SCBasename(const char *path) +{ + if (!path || strlen(path) == 0) + return NULL; + + char *final = strrchr(path, DIRECTORY_SEPARATOR); + if (!final) + return path; + + if (*(final + 1) == '\0') + return NULL; + + return final + 1; +} + +/** + * \brief Check for directory traversal + * + * \param path The path string to check for traversal + * + * \retval true if directory traversal is found, otherwise false + */ +bool SCPathContainsTraversal(const char *path) +{ +#ifdef OS_WIN32 + const char *pattern = "..\\"; +#else + const char *pattern = "../"; +#endif + return strstr(path, pattern) != NULL; +} diff --git a/src/util/path.h b/src/util/path.h new file mode 100644 index 000000000000..da483c70942b --- /dev/null +++ b/src/util/path.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#ifndef __UTIL_PATH_H__ +#define __UTIL_PATH_H__ + +#ifdef OS_WIN32 +typedef struct _stat SCStat; +#define SCFstatFn(fd, statbuf) _fstat((fd), (statbuf)) +#define SCStatFn(pathname, statbuf) _stat((pathname), (statbuf)) +#else +typedef struct stat SCStat; +#define SCFstatFn(fd, statbuf) fstat((fd), (statbuf)) +#define SCStatFn(pathname, statbuf) stat((pathname), (statbuf)) +#endif + +#if defined OS_WIN32 || defined __CYGWIN__ +#define PATH_SEPARATOR_SIZE 2 +#else +#define PATH_SEPARATOR_SIZE 1 +#endif + +#ifndef HAVE_NON_POSIX_MKDIR +#define SCMkDir(a, b) mkdir(a, b) +#else +#define SCMkDir(a, b) mkdir(a) +#endif + +int PathIsAbsolute(const char *); +int PathIsRelative(const char *); +int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname); +char *PathMergeAlloc(const char *const dir, const char *const fname); +int PathJoin(char *out_buf, size_t buf_len, const char *const dir, const char *const fname); +int SCDefaultMkDir(const char *path); +int SCCreateDirectoryTree(const char *path, const bool final); +bool SCPathExists(const char *path); +bool SCIsRegularDirectory(const struct dirent *const dir_entry); +bool SCIsRegularFile(const struct dirent *const dir_entry); +char *SCRealPath(const char *path, char *resolved_path); +const char *SCBasename(const char *path); +bool SCPathContainsTraversal(const char *path); + +#endif /* __UTIL_PATH_H__ */ diff --git a/src/util/pidfile.c b/src/util/pidfile.c new file mode 100644 index 000000000000..38058b6b2e49 --- /dev/null +++ b/src/util/pidfile.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * \author Victor Julien + * + * Utility code for dealing with a pidfile. + * Adaptation of Steve Grubbs patch to our coding guidelines + * (thanks for the patch Steve ;) + */ + +#include "suricata-common.h" +#include "util/pidfile.h" +#include "util/debug.h" + +/** + * \brief Write a pid file (used at the startup) + * This commonly needed by the init scripts + * + * \param pointer to the name of the pid file to write (optarg) + * + * \retval 0 if succes + * \retval -1 on failure + */ +int SCPidfileCreate(const char *pidfile) +{ + SCEnter(); + + int pidfd = 0; + char val[16]; + + size_t len = snprintf(val, sizeof(val), "%" PRIuMAX "\n", (uintmax_t)getpid()); + if (len <= 0) { + SCLogError("Pid error (%s)", strerror(errno)); + SCReturnInt(-1); + } + + pidfd = open(pidfile, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644); + if (pidfd < 0) { + SCLogError("unable to set pidfile '%s': %s", pidfile, strerror(errno)); + SCReturnInt(-1); + } + + ssize_t r = write(pidfd, val, (unsigned int)len); + if (r == -1) { + SCLogError("unable to write pidfile: %s", strerror(errno)); + close(pidfd); + SCReturnInt(-1); + } else if ((size_t)r != len) { + SCLogError("unable to write pidfile: wrote" + " %" PRIdMAX " of %" PRIuMAX " bytes.", + (intmax_t)r, (uintmax_t)len); + close(pidfd); + SCReturnInt(-1); + } + + close(pidfd); + SCReturnInt(0); +} + +/** + * \brief Remove the pid file (used at the startup) + * + * \param pointer to the name of the pid file to write (optarg) + */ +void SCPidfileRemove(const char *pid_filename) +{ + if (pid_filename != NULL) { + /* we ignore the result, the user may have removed the file already. */ + (void)unlink(pid_filename); + } +} + +/** + * \brief Check the Suricata pid file (used at the startup) + * + * This commonly needed by the init scripts. + * + * This function will fail if the PID file exists, but tries to log a + * meaningful message if appears Suricata is running, or if the PID + * file appears to be stale. + * + * \param pointer to the name of the pid file to write (optarg) + * + * \retval 0 if succes + * \retval -1 on failure + */ +int SCPidfileTestRunning(const char *pid_filename) +{ + /* Check if the existing process is still alive. */ + FILE *pf; + + pf = fopen(pid_filename, "r"); + if (pf == NULL) { + if (access(pid_filename, F_OK) == 0) { + SCLogError("pid file '%s' exists and can not be read. Aborting!", pid_filename); + return -1; + } else { + return 0; + } + } + +#ifndef OS_WIN32 + pid_t pidv; + if (fscanf(pf, "%d", &pidv) == 1 && kill(pidv, 0) == 0) { + SCLogError("pid file '%s' exists and Suricata appears to be running. " + "Aborting!", + pid_filename); + } else +#endif + { + SCLogError("pid file '%s' exists but appears stale. " + "Make sure Suricata is not running and then remove %s. " + "Aborting!", + pid_filename, pid_filename); + } + + fclose(pf); + return -1; +} diff --git a/src/util/pidfile.h b/src/util/pidfile.h new file mode 100644 index 000000000000..9c133c86a989 --- /dev/null +++ b/src/util/pidfile.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * \author Victor Julien + */ + +#ifndef __UTIL_PID_H__ +#define __UTIL_PID_H__ + +int SCPidfileCreate(const char *); +void SCPidfileRemove(const char *); +int SCPidfileTestRunning(const char *pid_filename); + +#endif /* __UTIL_PID_H__ */ diff --git a/src/util/plugin.c b/src/util/plugin.c new file mode 100644 index 000000000000..fad8622cc3c9 --- /dev/null +++ b/src/util/plugin.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2020-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "suricata-plugin.h" +#include "suricata.h" +#include "runmodes.h" +#include "output/eve/output-eve-syslog.h" +#include "util/plugin.h" +#include "util/debug.h" + +#ifdef HAVE_PLUGINS + +#include + +typedef struct PluginListNode_ { + SCPlugin *plugin; + void *lib; + TAILQ_ENTRY(PluginListNode_) entries; +} PluginListNode; + +/** + * The list of loaded plugins. + * + * Currently only used as a place to stash the pointer returned from + * dlopen, but could have other uses, such as a plugin unload destructor. + */ +static TAILQ_HEAD(, PluginListNode_) plugins = TAILQ_HEAD_INITIALIZER(plugins); + +static TAILQ_HEAD(, SCEveFileType_) output_types = TAILQ_HEAD_INITIALIZER(output_types); + +static TAILQ_HEAD(, SCCapturePlugin_) capture_plugins = TAILQ_HEAD_INITIALIZER(capture_plugins); + +bool RegisterPlugin(SCPlugin *plugin, void *lib) +{ + BUG_ON(plugin->name == NULL); + BUG_ON(plugin->author == NULL); + BUG_ON(plugin->license == NULL); + BUG_ON(plugin->Init == NULL); + + PluginListNode *node = SCCalloc(1, sizeof(*node)); + if (node == NULL) { + SCLogError("Failed to allocate memory for plugin"); + return false; + } + node->plugin = plugin; + node->lib = lib; + TAILQ_INSERT_TAIL(&plugins, node, entries); + SCLogNotice("Initializing plugin %s; author=%s; license=%s", plugin->name, plugin->author, + plugin->license); + (*plugin->Init)(); + return true; +} + +static void InitPlugin(char *path) +{ + void *lib = dlopen(path, RTLD_NOW); + if (lib == NULL) { + SCLogNotice("Failed to open %s as a plugin: %s", path, dlerror()); + } else { + SCLogNotice("Loading plugin %s", path); + + SCPluginRegisterFunc plugin_register = dlsym(lib, "SCPluginRegister"); + if (plugin_register == NULL) { + SCLogError("Plugin does not export SCPluginRegister function: %s", path); + dlclose(lib); + return; + } + + if (!RegisterPlugin(plugin_register(), lib)) { + SCLogError("Plugin registration failed: %s", path); + dlclose(lib); + return; + } + } +} + +void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args) +{ + ConfNode *conf = ConfGetNode("plugins"); + if (conf == NULL) { + return; + } + ConfNode *plugin = NULL; + TAILQ_FOREACH (plugin, &conf->head, next) { + struct stat statbuf; + if (stat(plugin->val, &statbuf) == -1) { + SCLogError("Bad plugin path: %s: %s", plugin->val, strerror(errno)); + continue; + } + if (S_ISDIR(statbuf.st_mode)) { + // coverity[toctou : FALSE] + DIR *dir = opendir(plugin->val); + if (dir == NULL) { + SCLogError("Failed to open plugin directory %s: %s", plugin->val, strerror(errno)); + continue; + } + struct dirent *entry = NULL; + char path[PATH_MAX]; + while ((entry = readdir(dir)) != NULL) { + if (strstr(entry->d_name, ".so") != NULL) { + snprintf(path, sizeof(path), "%s/%s", plugin->val, entry->d_name); + InitPlugin(path); + } + } + closedir(dir); + } else { + InitPlugin(plugin->val); + } + } + + if (run_mode == RUNMODE_PLUGIN) { + SCCapturePlugin *capture = SCPluginFindCaptureByName(capture_plugin_name); + if (capture == NULL) { + FatalError("No capture plugin found with name %s", capture_plugin_name); + } + capture->Init(capture_plugin_args, RUNMODE_PLUGIN, TMM_RECEIVEPLUGIN, TMM_DECODEPLUGIN); + } +} + +static bool IsBuiltinTypeName(const char *name) +{ + const char *builtin[] = { + "regular", + "unix_dgram", + "unix_stream", + "redis", + NULL, + }; + for (int i = 0;; i++) { + if (builtin[i] == NULL) { + break; + } + if (strcmp(builtin[i], name) == 0) { + return true; + } + } + return false; +} + +/** + * \brief Register an Eve file type. + * + * \retval true if registered successfully, false if the file type name + * conflicts with a built-in or previously registered + * file type. + */ +bool SCRegisterEveFileType(SCEveFileType *plugin) +{ + /* First check that the name doesn't conflict with a built-in filetype. */ + if (IsBuiltinTypeName(plugin->name)) { + SCLogError("Eve file type name conflicts with built-in type: %s", plugin->name); + return false; + } + + /* Now check against previously registered file types. */ + SCEveFileType *existing = NULL; + TAILQ_FOREACH (existing, &output_types, entries) { + if (strcmp(existing->name, plugin->name) == 0) { + SCLogError("Eve file type name conflicts with previously registered type: %s", + plugin->name); + return false; + } + } + + SCLogDebug("Registering EVE file type plugin %s", plugin->name); + TAILQ_INSERT_TAIL(&output_types, plugin, entries); + return true; +} + +SCEveFileType *SCPluginFindFileType(const char *name) +{ + SCEveFileType *plugin = NULL; + TAILQ_FOREACH (plugin, &output_types, entries) { + if (strcmp(name, plugin->name) == 0) { + return plugin; + } + } + return NULL; +} + +int SCPluginRegisterCapture(SCCapturePlugin *plugin) +{ + TAILQ_INSERT_TAIL(&capture_plugins, plugin, entries); + SCLogNotice("Capture plugin registered: %s", plugin->name); + return 0; +} + +SCCapturePlugin *SCPluginFindCaptureByName(const char *name) +{ + SCCapturePlugin *plugin = NULL; + TAILQ_FOREACH (plugin, &capture_plugins, entries) { + if (strcmp(name, plugin->name) == 0) { + return plugin; + } + } + return plugin; +} +#endif diff --git a/src/util-plugin.h b/src/util/plugin.h similarity index 100% rename from src/util-plugin.h rename to src/util/plugin.h diff --git a/src/util/pool-thread.c b/src/util/pool-thread.c new file mode 100644 index 000000000000..4c2a52680dc7 --- /dev/null +++ b/src/util/pool-thread.c @@ -0,0 +1,409 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \defgroup utilpool Pool + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Pool utility functions + */ + +#include "suricata-common.h" +#include "util/pool.h" +#include "util/pool-thread.h" +#include "util/unittest.h" +#include "util/debug.h" + +/** + * \brief per thread Pool, initialization function + * \param thread number of threads this is for. Can start with 1 and be expanded. + * Other params are as for PoolInit() + */ +PoolThread *PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, + void *(*Alloc)(void), int (*Init)(void *, void *), void *InitData, void (*Cleanup)(void *), + void (*Free)(void *)) +{ + sc_errno = SC_OK; + + if (threads <= 0) { + SCLogDebug("error"); + sc_errno = SC_EINVAL; + return NULL; + } + + PoolThread *pt = SCCalloc(1, sizeof(*pt)); + if (unlikely(pt == NULL)) { + SCLogDebug("memory alloc error"); + sc_errno = SC_ENOMEM; + goto error; + } + + SCLogDebug("size %d", threads); + pt->array = SCMalloc(threads * sizeof(PoolThreadElement)); + if (pt->array == NULL) { + SCLogDebug("memory alloc error"); + sc_errno = SC_ENOMEM; + goto error; + } + pt->size = threads; + + for (int i = 0; i < threads; i++) { + PoolThreadElement *e = &pt->array[i]; + + SCMutexInit(&e->lock, NULL); + SCMutexLock(&e->lock); + // SCLogDebug("size %u prealloc_size %u elt_size %u Alloc %p Init %p InitData %p + // Cleanup %p Free %p", + // size, prealloc_size, elt_size, + // Alloc, Init, InitData, Cleanup, Free); + e->pool = PoolInit(size, prealloc_size, elt_size, Alloc, Init, InitData, Cleanup, Free); + SCMutexUnlock(&e->lock); + if (e->pool == NULL) { + SCLogDebug("error"); + goto error; + } + } + + return pt; +error: + if (pt != NULL) + PoolThreadFree(pt); + return NULL; +} + +/** \brief expand pool by one for a new thread + * \retval -1 or pool thread id + */ +int PoolThreadExpand(PoolThread *pt) +{ + if (pt == NULL || pt->array == NULL || pt->size == 0) { + SCLogError("pool grow failed"); + return -1; + } + + size_t newsize = pt->size + 1; + SCLogDebug("newsize %" PRIuMAX, (uintmax_t)newsize); + + void *ptmp = SCRealloc(pt->array, (newsize * sizeof(PoolThreadElement))); + if (ptmp == NULL) { + SCFree(pt->array); + pt->array = NULL; + SCLogError("pool grow failed"); + return -1; + } + pt->array = ptmp; + pt->size = newsize; + + /* copy settings from first thread that registered the pool */ + Pool settings; + memset(&settings, 0x0, sizeof(settings)); + PoolThreadElement *e = &pt->array[0]; + SCMutexLock(&e->lock); + settings.max_buckets = e->pool->max_buckets; + settings.preallocated = e->pool->preallocated; + settings.elt_size = e->pool->elt_size; + settings.Alloc = e->pool->Alloc; + settings.Init = e->pool->Init; + settings.InitData = e->pool->InitData; + settings.Cleanup = e->pool->Cleanup; + settings.Free = e->pool->Free; + SCMutexUnlock(&e->lock); + + e = &pt->array[newsize - 1]; + memset(e, 0x00, sizeof(*e)); + SCMutexInit(&e->lock, NULL); + SCMutexLock(&e->lock); + e->pool = PoolInit(settings.max_buckets, settings.preallocated, settings.elt_size, + settings.Alloc, settings.Init, settings.InitData, settings.Cleanup, settings.Free); + SCMutexUnlock(&e->lock); + if (e->pool == NULL) { + SCLogError("pool grow failed"); + return -1; + } + + return (int)(newsize - 1); +} + +int PoolThreadSize(PoolThread *pt) +{ + if (pt == NULL) + return -1; + return (int)pt->size; +} + +void PoolThreadFree(PoolThread *pt) +{ + if (pt == NULL) + return; + + if (pt->array != NULL) { + for (int i = 0; i < (int)pt->size; i++) { + PoolThreadElement *e = &pt->array[i]; + SCMutexLock(&e->lock); + PoolFree(e->pool); + SCMutexUnlock(&e->lock); + SCMutexDestroy(&e->lock); + } + SCFree(pt->array); + } + SCFree(pt); +} + +void *PoolThreadGetById(PoolThread *pt, uint16_t id) +{ + void *data = NULL; + + if (pt == NULL || id >= pt->size) + return NULL; + + PoolThreadElement *e = &pt->array[id]; + SCMutexLock(&e->lock); + data = PoolGet(e->pool); + SCMutexUnlock(&e->lock); + if (data) { + PoolThreadId *did = data; + *did = id; + } + + return data; +} + +void PoolThreadReturn(PoolThread *pt, void *data) +{ + PoolThreadId *id = data; + + if (pt == NULL || *id >= pt->size) + return; + + SCLogDebug("returning to id %u", *id); + + PoolThreadElement *e = &pt->array[*id]; + SCMutexLock(&e->lock); + PoolReturn(e->pool, data); + SCMutexUnlock(&e->lock); +} + +void PoolThreadLock(PoolThread *pt, PoolThreadId id) +{ + BUG_ON(pt == NULL || id >= pt->size); + PoolThreadElement *e = &pt->array[id]; + SCMutexLock(&e->lock); +} + +void PoolThreadReturnRaw(PoolThread *pt, PoolThreadId id, void *data) +{ + BUG_ON(pt == NULL || id >= pt->size); + PoolThreadElement *e = &pt->array[id]; + PoolReturn(e->pool, data); +} + +void PoolThreadUnlock(PoolThread *pt, PoolThreadId id) +{ + BUG_ON(pt == NULL || id >= pt->size); + PoolThreadElement *e = &pt->array[id]; + SCMutexUnlock(&e->lock); +} + +#ifdef UNITTESTS +struct PoolThreadTestData { + PoolThreadId res; + int abc; +}; + +static void *PoolThreadTestAlloc(void) +{ + void *data = SCMalloc(sizeof(struct PoolThreadTestData)); + return data; +} + +static int PoolThreadTestInit(void *data, void *allocdata) +{ + if (!data) + return 0; + + memset(data, 0x00, sizeof(allocdata)); + struct PoolThreadTestData *pdata = data; + pdata->abc = *(int *)allocdata; + return 1; +} + +static void PoolThreadTestFree(void *data) +{ +} + +static int PoolThreadTestInit01(void) +{ + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, NULL, NULL, NULL, NULL); + FAIL_IF(pt == NULL); + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestInit02(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF(pt == NULL); + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGet01(void) +{ + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, NULL, NULL, NULL, NULL); + FAIL_IF(pt == NULL); + + void *data = PoolThreadGetById(pt, 3); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF(pdata->res != 3); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGet02(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + + void *data = PoolThreadGetById(pt, 3); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF_NOT(pdata->res == 3); + + FAIL_IF_NOT(pdata->abc == 123); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestReturn01(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + + void *data = PoolThreadGetById(pt, 3); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF_NOT(pdata->res == 3); + + FAIL_IF_NOT(pdata->abc == 123); + + FAIL_IF_NOT(pt->array[3].pool->outstanding == 1); + + PoolThreadReturn(pt, data); + + FAIL_IF_NOT(pt->array[3].pool->outstanding == 0); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGrow01(void) +{ + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, NULL, NULL, NULL, NULL); + FAIL_IF_NULL(pt); + FAIL_IF(PoolThreadExpand(pt) < 0); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGrow02(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + FAIL_IF(PoolThreadExpand(pt) < 0); + + PoolThreadFree(pt); + PASS; +} + +static int PoolThreadTestGrow03(void) +{ + int i = 123; + + PoolThread *pt = PoolThreadInit(4, /* threads */ + 10, 5, 10, PoolThreadTestAlloc, PoolThreadTestInit, &i, PoolThreadTestFree, NULL); + FAIL_IF_NULL(pt); + FAIL_IF(PoolThreadExpand(pt) < 0); + + void *data = PoolThreadGetById(pt, 4); + FAIL_IF_NULL(data); + + struct PoolThreadTestData *pdata = data; + FAIL_IF_NOT(pdata->res == 4); + + FAIL_IF_NOT(pdata->abc == 123); + + FAIL_IF_NOT(pt->array[4].pool->outstanding == 1); + + PoolThreadReturn(pt, data); + + FAIL_IF_NOT(pt->array[4].pool->outstanding == 0); + + PoolThreadFree(pt); + PASS; +} + +#endif + +void PoolThreadRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01); + UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02); + + UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01); + UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02); + + UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01); + + UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01); + UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02); + UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03); +#endif +} + +/** + * @} + */ diff --git a/src/util/pool-thread.h b/src/util/pool-thread.h new file mode 100644 index 000000000000..278055bd57ba --- /dev/null +++ b/src/util/pool-thread.h @@ -0,0 +1,109 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup utilpool + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + */ + +/** + * Consumers of this API MUST add PoolThreadReserved as the first + * member in the data structure. They also MUST ignore that data + * completely. It's managed by this API. + * + * It's purpose is to make sure thread X can return data to a pool + * from thread Y. + */ + +#ifndef __UTIL_POOL_THREAD_H__ +#define __UTIL_POOL_THREAD_H__ + +#include "threads.h" +#include "util/pool.h" + +struct PoolThreadElement_ { + SCMutex lock; /**< lock, should have low contention */ + Pool *pool; /**< actual pool */ +}; +// __attribute__((aligned(CLS))); <- VJ: breaks on clang 32bit, segv in PoolThreadTestGrow01 + +typedef struct PoolThreadElement_ PoolThreadElement; + +typedef struct PoolThread_ { + size_t size; /**< size of the array */ + PoolThreadElement *array; /**< array of elements */ +} PoolThread; + +/** per data item reserved data containing the + * thread pool id */ +typedef uint16_t PoolThreadId; + +void PoolThreadRegisterTests(void); + +/** \brief initialize a thread pool + * \note same as PoolInit() except for "threads" + * \param threads number of threads to use this + * \retval pt thread pool or NULL on error */ +PoolThread *PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, + void *(*Alloc)(void), int (*Init)(void *, void *), void *InitData, void (*Cleanup)(void *), + void (*Free)(void *)); + +/** \brief grow a thread pool by one + * \note copies settings from initial PoolThreadInit() call + * \param pt thread pool to grow + * \retval r id of new entry on succes, -1 on error */ +int PoolThreadExpand(PoolThread *pt); + +/** \brief destroy the thread pool + * \note wrapper around PoolFree() + * \param pt thread pool */ +void PoolThreadFree(PoolThread *pt); + +/** \brief get data from thread pool by thread id + * \note wrapper around PoolGet() + * \param pt thread pool + * \param id thread id + * \retval ptr data or NULL */ +void *PoolThreadGetById(PoolThread *pt, uint16_t id); + +/** \brief return data to thread pool + * \note wrapper around PoolReturn() + * \param pt thread pool + * \param data memory block to return, with PoolThreadReserved as it's first member */ +void PoolThreadReturn(PoolThread *pt, void *data); + +void PoolThreadLock(PoolThread *pt, PoolThreadId id); +void PoolThreadReturnRaw(PoolThread *pt, PoolThreadId id, void *data); +void PoolThreadUnlock(PoolThread *pt, PoolThreadId id); + +/** \brief get size of PoolThread (number of 'threads', so array elements) + * \param pt thread pool + * \retval size or -1 on error */ +int PoolThreadSize(PoolThread *pt); + +#endif /* __UTIL_POOL_THREAD_H__ */ + +/** + * @} + */ diff --git a/src/util/pool.c b/src/util/pool.c new file mode 100644 index 000000000000..62385c4487dd --- /dev/null +++ b/src/util/pool.c @@ -0,0 +1,740 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \defgroup utilpool Pool + * + * ::Pool are an effective way to maintain a set of ready to use + * structures. + * + * To create a ::Pool, you need to use PoolInit(). You can + * get an item from the ::Pool by using PoolGet(). When you're + * done with it call PoolReturn(). + * To destroy the ::Pool, call PoolFree(), it will free all used + * memory. + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + * + * Pool utility functions + */ + +#include "suricata-common.h" +#include "util/pool.h" +#include "util/pool-thread.h" +#include "util/unittest.h" +#include "util/debug.h" + +static int PoolMemset(void *pitem, void *initdata) +{ + Pool *p = (Pool *)initdata; + + memset(pitem, 0, p->elt_size); + return 1; +} + +/** + * \brief Check if data is preallocated + * \retval false if not inside the prealloc'd block, true if inside */ +static bool PoolDataPreAllocated(Pool *p, void *data) +{ + ptrdiff_t delta = data - p->data_buffer; + if ((delta < 0) || (delta > p->data_buffer_size)) { + return false; + } + return true; +} + +/** \brief Init a Pool + * + * PoolInit() creates a ::Pool. The Alloc function must only do + * allocation stuff. The Cleanup function must not try to free + * the PoolBucket::data. This is done by the ::Pool management + * system. + * + * \param size + * \param prealloc_size + * \param elt_size Memory size of an element + * \param Alloc An allocation function or NULL to use a standard SCMalloc + * \param Init An init function or NULL to use a standard memset to 0 + * \param InitData Init data + * \param Cleanup a free function or NULL if no special treatment is needed + * \param Free free func + * \retval the allocated Pool + */ +Pool *PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), + int (*Init)(void *, void *), void *InitData, void (*Cleanup)(void *), void (*Free)(void *)) +{ + sc_errno = SC_OK; + + Pool *p = NULL; + + if (size != 0 && prealloc_size > size) { + sc_errno = SC_EINVAL; + goto error; + } + if (size != 0 && elt_size == 0) { + sc_errno = SC_EINVAL; + goto error; + } + if (elt_size && Free) { + sc_errno = SC_EINVAL; + goto error; + } + if (elt_size == 0 && Alloc == NULL) { + sc_errno = SC_EINVAL; + goto error; + } + + /* setup the filter */ + p = SCCalloc(1, sizeof(Pool)); + if (unlikely(p == NULL)) { + sc_errno = SC_ENOMEM; + goto error; + } + + p->max_buckets = size; + p->preallocated = prealloc_size; + p->elt_size = elt_size; + p->data_buffer_size = prealloc_size * elt_size; + p->Alloc = Alloc; + p->Init = Init; + p->InitData = InitData; + p->Cleanup = Cleanup; + p->Free = Free; + if (p->Init == NULL) { + p->Init = PoolMemset; + p->InitData = p; + } + + /* alloc the buckets and place them in the empty list */ + uint32_t u32 = 0; + if (size > 0) { + PoolBucket *pb = SCCalloc(size, sizeof(PoolBucket)); + if (unlikely(pb == NULL)) { + sc_errno = SC_ENOMEM; + goto error; + } + memset(pb, 0, size * sizeof(PoolBucket)); + p->pb_buffer = pb; + for (u32 = 0; u32 < size; u32++) { + /* populate pool */ + pb->next = p->empty_stack; + pb->flags |= POOL_BUCKET_PREALLOCATED; + p->empty_stack = pb; + p->empty_stack_size++; + pb++; + } + + p->data_buffer = SCCalloc(prealloc_size, elt_size); + /* FIXME better goto */ + if (p->data_buffer == NULL) { + sc_errno = SC_ENOMEM; + goto error; + } + } + /* prealloc the buckets and requeue them to the alloc list */ + for (u32 = 0; u32 < prealloc_size; u32++) { + if (size == 0) { /* unlimited */ + PoolBucket *pb = SCCalloc(1, sizeof(PoolBucket)); + if (unlikely(pb == NULL)) { + sc_errno = SC_ENOMEM; + goto error; + } + + if (p->Alloc) { + pb->data = p->Alloc(); + } else { + pb->data = SCMalloc(p->elt_size); + } + if (pb->data == NULL) { + SCFree(pb); + sc_errno = SC_ENOMEM; + goto error; + } + if (p->Init(pb->data, p->InitData) != 1) { + if (p->Free) + p->Free(pb->data); + else + SCFree(pb->data); + SCFree(pb); + sc_errno = SC_EINVAL; + goto error; + } + p->allocated++; + + pb->next = p->alloc_stack; + p->alloc_stack = pb; + p->alloc_stack_size++; + } else { + PoolBucket *pb = p->empty_stack; + if (pb == NULL) { + sc_errno = SC_ENOMEM; + goto error; + } + + pb->data = (char *)p->data_buffer + u32 * elt_size; + if (p->Init(pb->data, p->InitData) != 1) { + pb->data = NULL; + sc_errno = SC_EINVAL; + goto error; + } + + p->empty_stack = pb->next; + p->empty_stack_size--; + + p->allocated++; + + pb->next = p->alloc_stack; + p->alloc_stack = pb; + p->alloc_stack_size++; + } + } + + return p; + +error: + if (p != NULL) { + PoolFree(p); + } + return NULL; +} + +void PoolFree(Pool *p) +{ + if (p == NULL) + return; + + while (p->alloc_stack != NULL) { + PoolBucket *pb = p->alloc_stack; + p->alloc_stack = pb->next; + if (p->Cleanup) + p->Cleanup(pb->data); + if (!PoolDataPreAllocated(p, pb->data)) { + if (p->Free) + p->Free(pb->data); + else + SCFree(pb->data); + } + pb->data = NULL; + if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { + SCFree(pb); + } + } + + while (p->empty_stack != NULL) { + PoolBucket *pb = p->empty_stack; + p->empty_stack = pb->next; + if (pb->data != NULL) { + if (p->Cleanup) + p->Cleanup(pb->data); + if (!PoolDataPreAllocated(p, pb->data)) { + if (p->Free) + p->Free(pb->data); + else + SCFree(pb->data); + } + pb->data = NULL; + } + if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { + SCFree(pb); + } + } + + if (p->pb_buffer) + SCFree(p->pb_buffer); + if (p->data_buffer) + SCFree(p->data_buffer); + SCFree(p); +} + +void PoolPrint(Pool *p) +{ + printf("\n----------- Hash Table Stats ------------\n"); + printf("Buckets: %" PRIu32 "\n", p->empty_stack_size + p->alloc_stack_size); + printf("-----------------------------------------\n"); +} + +void *PoolGet(Pool *p) +{ + SCEnter(); + + PoolBucket *pb = p->alloc_stack; + if (pb != NULL) { + /* pull from the alloc list */ + p->alloc_stack = pb->next; + p->alloc_stack_size--; + + /* put in the empty list */ + pb->next = p->empty_stack; + p->empty_stack = pb; + p->empty_stack_size++; + } else { + if (p->max_buckets == 0 || p->allocated < p->max_buckets) { + void *pitem; + SCLogDebug("max_buckets %" PRIu32 "", p->max_buckets); + + if (p->Alloc != NULL) { + pitem = p->Alloc(); + } else { + pitem = SCMalloc(p->elt_size); + } + + if (pitem != NULL) { + if (p->Init(pitem, p->InitData) != 1) { + if (p->Free != NULL) + p->Free(pitem); + else + SCFree(pitem); + SCReturnPtr(NULL, "void"); + } + + p->allocated++; + p->outstanding++; +#ifdef DEBUG + if (p->outstanding > p->max_outstanding) + p->max_outstanding = p->outstanding; +#endif + } + + SCReturnPtr(pitem, "void"); + } else { + SCReturnPtr(NULL, "void"); + } + } + + void *ptr = pb->data; + pb->data = NULL; + p->outstanding++; +#ifdef DEBUG + if (p->outstanding > p->max_outstanding) + p->max_outstanding = p->outstanding; +#endif + SCReturnPtr(ptr, "void"); +} + +void PoolReturn(Pool *p, void *data) +{ + SCEnter(); + + PoolBucket *pb = p->empty_stack; + + SCLogDebug("pb %p", pb); + + if (pb == NULL) { + p->allocated--; + p->outstanding--; + if (p->Cleanup != NULL) { + p->Cleanup(data); + } + if (!PoolDataPreAllocated(p, data)) { + if (p->Free) + p->Free(data); + else + SCFree(data); + } + + SCLogDebug("tried to return data %p to the pool %p, but no more " + "buckets available. Just freeing the data.", + data, p); + SCReturn; + } + + /* pull from the alloc list */ + p->empty_stack = pb->next; + p->empty_stack_size--; + + /* put in the alloc list */ + pb->next = p->alloc_stack; + p->alloc_stack = pb; + p->alloc_stack_size++; + + pb->data = data; + p->outstanding--; + SCReturn; +} + +void PoolPrintSaturation(Pool *p) +{ + if (p->max_buckets > 0) { + SCLogDebug("pool %p is using %" PRIu32 " out of %" PRIu32 " items (%02.1f%%), max %" PRIu32 + " (%02.1f%%): pool struct memory %" PRIu64 ".", + p, p->outstanding, p->max_buckets, + (float)(p->outstanding) / (float)(p->max_buckets) * 100, p->max_outstanding, + (float)(p->max_outstanding) / (float)(p->max_buckets) * 100, + (uint64_t)(p->max_buckets * sizeof(PoolBucket))); + } +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +#ifdef UNITTESTS +static void *PoolTestAlloc(void) +{ + void *ptr = SCMalloc(10); + if (unlikely(ptr == NULL)) + return NULL; + return ptr; +} +static int PoolTestInitArg(void *data, void *allocdata) +{ + size_t len = strlen((char *)allocdata) + 1; + char *str = data; + if (str != NULL) + strlcpy(str, (char *)allocdata, len); + return 1; +} + +static void PoolTestFree(void *ptr) +{ + return; +} + +static int PoolTestInit01(void) +{ + Pool *p = PoolInit(10, 5, 10, PoolTestAlloc, NULL, NULL, PoolTestFree, NULL); + if (p == NULL) + return 0; + + PoolFree(p); + return 1; +} + +static int PoolTestInit02(void) +{ + int retval = 0; + + Pool *p = PoolInit(10, 5, 10, PoolTestAlloc, NULL, NULL, PoolTestFree, NULL); + if (p == NULL) + goto end; + + if (p->alloc_stack == NULL || p->empty_stack == NULL) { + printf("list(s) not properly initialized (a:%p e:%p): ", p->alloc_stack, p->empty_stack); + retval = 0; + goto end; + } + + if (p->Alloc != PoolTestAlloc) { + printf("Alloc func ptr %p != %p: ", p->Alloc, PoolTestAlloc); + retval = 0; + goto end; + } + + if (p->Cleanup != PoolTestFree) { + printf("Free func ptr %p != %p: ", p->Cleanup, PoolTestFree); + retval = 0; + goto end; + } + + retval = 1; +end: + if (p != NULL) + PoolFree(p); + return retval; +} + +static int PoolTestInit03(void) +{ + int retval = 0; + void *data = NULL; + + Pool *p = PoolInit(10, 5, 10, PoolTestAlloc, NULL, NULL, PoolTestFree, NULL); + if (p == NULL) + goto end; + + data = PoolGet(p); + if (data == NULL) { + printf("PoolGet returned NULL: "); + retval = 0; + goto end; + } + + if (p->alloc_stack_size != 4) { + printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size); + retval = 0; + goto end; + } + + if (p->empty_stack_size != 6) { + printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size); + retval = 0; + goto end; + } + + retval = 1; +end: + if (p != NULL) + PoolFree(p); + return retval; +} + +static int PoolTestInit04(void) +{ + int retval = 0; + char *str = NULL; + + Pool *p = PoolInit( + 10, 5, strlen("test") + 1, NULL, PoolTestInitArg, (void *)"test", PoolTestFree, NULL); + if (p == NULL) + goto end; + + str = PoolGet(p); + if (str == NULL) { + printf("PoolGet returned NULL: "); + retval = 0; + goto end; + } + + if (strcmp(str, "test") != 0) { + printf("Memory not properly initialized: "); + retval = 0; + goto end; + } + + if (p->alloc_stack_size != 4) { + printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size); + retval = 0; + goto end; + } + + if (p->empty_stack_size != 6) { + printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size); + retval = 0; + goto end; + } + + retval = 1; +end: + if (p != NULL) + PoolFree(p); + return retval; +} + +static int PoolTestInit05(void) +{ + int retval = 0; + void *data = NULL; + + Pool *p = PoolInit(10, 5, 10, PoolTestAlloc, NULL, NULL, PoolTestFree, NULL); + if (p == NULL) + goto end; + + data = PoolGet(p); + if (data == NULL) { + printf("PoolGet returned NULL: "); + retval = 0; + goto end; + } + + if (p->alloc_stack_size != 4) { + printf("p->alloc_stack_size 4 != %" PRIu32 ": ", p->alloc_stack_size); + retval = 0; + goto end; + } + + if (p->empty_stack_size != 6) { + printf("p->empty_stack_size 6 != %" PRIu32 ": ", p->empty_stack_size); + retval = 0; + goto end; + } + + PoolReturn(p, data); + data = NULL; + + if (p->alloc_stack_size != 5) { + printf("p->alloc_stack_size 5 != %" PRIu32 ": ", p->alloc_stack_size); + retval = 0; + goto end; + } + + if (p->empty_stack_size != 5) { + printf("p->empty_stack_size 5 != %" PRIu32 ": ", p->empty_stack_size); + retval = 0; + goto end; + } + + retval = 1; +end: + if (p != NULL) + PoolFree(p); + return retval; +} + +static int PoolTestInit06(void) +{ + int retval = 0; + void *data = NULL; + void *data2 = NULL; + + Pool *p = PoolInit(1, 0, 10, PoolTestAlloc, NULL, NULL, PoolTestFree, NULL); + if (p == NULL) + goto end; + + if (p->allocated != 0) { + printf("p->allocated 0 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + data = PoolGet(p); + if (data == NULL) { + printf("PoolGet returned NULL: "); + retval = 0; + goto end; + } + + if (p->allocated != 1) { + printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + data2 = PoolGet(p); + if (data2 != NULL) { + printf("PoolGet returned %p, expected NULL: ", data2); + retval = 0; + goto end; + } + + PoolReturn(p, data); + data = NULL; + + if (p->allocated != 1) { + printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + if (p->alloc_stack_size != 1) { + printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size); + retval = 0; + goto end; + } + + retval = 1; +end: + if (p != NULL) + PoolFree(p); + return retval; +} + +/** \test pool with unlimited size */ +static int PoolTestInit07(void) +{ + int retval = 0; + void *data = NULL; + void *data2 = NULL; + + Pool *p = PoolInit(0, 1, 10, PoolTestAlloc, NULL, NULL, PoolTestFree, NULL); + if (p == NULL) + goto end; + + if (p->max_buckets != 0) { + printf("p->max_buckets 0 != %" PRIu32 ": ", p->max_buckets); + retval = 0; + goto end; + } + + if (p->allocated != 1) { + printf("p->allocated 1 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + data = PoolGet(p); + if (data == NULL) { + printf("PoolGet returned NULL: "); + retval = 0; + goto end; + } + + if (p->allocated != 1) { + printf("(2) p->allocated 1 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + data2 = PoolGet(p); + if (data2 == NULL) { + printf("PoolGet returned NULL: "); + retval = 0; + goto end; + } + + if (p->allocated != 2) { + printf("(3) p->allocated 2 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + PoolReturn(p, data); + data = NULL; + + if (p->allocated != 2) { + printf("(4) p->allocated 2 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + if (p->alloc_stack_size != 1) { + printf("p->alloc_stack_size 1 != %" PRIu32 ": ", p->alloc_stack_size); + retval = 0; + goto end; + } + + PoolReturn(p, data2); + data2 = NULL; + + if (p->allocated != 1) { + printf("(5) p->allocated 1 != %" PRIu32 ": ", p->allocated); + retval = 0; + goto end; + } + + retval = 1; +end: + if (p != NULL) + PoolFree(p); + return retval; +} +#endif /* UNITTESTS */ + +void PoolRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("PoolTestInit01", PoolTestInit01); + UtRegisterTest("PoolTestInit02", PoolTestInit02); + UtRegisterTest("PoolTestInit03", PoolTestInit03); + UtRegisterTest("PoolTestInit04", PoolTestInit04); + UtRegisterTest("PoolTestInit05", PoolTestInit05); + UtRegisterTest("PoolTestInit06", PoolTestInit06); + UtRegisterTest("PoolTestInit07", PoolTestInit07); + + PoolThreadRegisterTests(); +#endif /* UNITTESTS */ +} + +/** + * @} + */ diff --git a/src/util/pool.h b/src/util/pool.h new file mode 100644 index 000000000000..f7b5d7285a6b --- /dev/null +++ b/src/util/pool.h @@ -0,0 +1,90 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup utilpool + * + * @{ + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_POOL_H__ +#define __UTIL_POOL_H__ + +#define POOL_BUCKET_PREALLOCATED (1 << 0) + +/* pool bucket structure */ +typedef struct PoolBucket_ { + void *data; + uint8_t flags; + struct PoolBucket_ *next; +} PoolBucket; + +/* pool structure */ +typedef struct Pool_ { + uint32_t max_buckets; + uint32_t preallocated; + uint32_t allocated; /**< counter of data elements, both currently in + * the pool and outside of it (outstanding) */ + + uint32_t alloc_stack_size; + + PoolBucket *alloc_stack; + + PoolBucket *empty_stack; + uint32_t empty_stack_size; + + int data_buffer_size; + void *data_buffer; + PoolBucket *pb_buffer; + + void *(*Alloc)(void); + int (*Init)(void *, void *); + void *InitData; + void (*Cleanup)(void *); + void (*Free)(void *); + + uint32_t elt_size; + uint32_t outstanding; /**< counter of data items 'in use'. Pretty much + * the diff between PoolGet and PoolReturn */ +#ifdef DEBUG + uint32_t max_outstanding; /**< max value of outstanding we saw */ +#endif +} Pool; + +/* prototypes */ +Pool *PoolInit(uint32_t, uint32_t, uint32_t, void *(*Alloc)(void), int (*Init)(void *, void *), + void *, void (*Cleanup)(void *), void (*Free)(void *)); +void PoolFree(Pool *); +void PoolPrint(Pool *); +void PoolPrintSaturation(Pool *p); + +void *PoolGet(Pool *); +void PoolReturn(Pool *, void *); + +void PoolRegisterTests(void); + +#endif /* __UTIL_POOL_H__ */ + +/** + * @} + */ diff --git a/src/util/prefilter.c b/src/util/prefilter.c new file mode 100644 index 000000000000..102c5a99a3f2 --- /dev/null +++ b/src/util/prefilter.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Pattern matcher utility Functions + */ + +#include "suricata-common.h" +#include "util/prefilter.h" + +/** + * \brief Setup a pmq + * + * \param pmq Pattern matcher queue to be initialized + * + * \retval -1 error + * \retval 0 ok + */ +int PmqSetup(PrefilterRuleStore *pmq) +{ + SCEnter(); + + if (pmq == NULL) { + SCReturnInt(-1); + } + + memset(pmq, 0, sizeof(PrefilterRuleStore)); + + pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ + pmq->rule_id_array_cnt = 0; + + size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); + pmq->rule_id_array = (SigIntId *)SCMalloc(bytes); + if (pmq->rule_id_array == NULL) { + pmq->rule_id_array_size = 0; + SCReturnInt(-1); + } + // Don't need to zero memory since it is always written first. + + SCReturnInt(0); +} + +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first + * + * \param pmq storage for match results + * \param new_size number of Signature IDs needing to be stored. + * + */ +int PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size) +{ + /* Need to make the array bigger. Double the size needed to + * also handle the case that sids_size might still be + * larger than the old size. + */ + new_size = new_size * 2; + SigIntId *new_array = (SigIntId *)SCRealloc(pmq->rule_id_array, new_size * sizeof(SigIntId)); + if (unlikely(new_array == NULL)) { + /* Try again just big enough. */ + new_size = new_size / 2; + new_array = (SigIntId *)SCRealloc(pmq->rule_id_array, new_size * sizeof(SigIntId)); + if (unlikely(new_array == NULL)) { + + SCLogError("Failed to realloc PatternMatchQueue" + " rule ID array. Some signature ID matches lost"); + return 0; + } + } + pmq->rule_id_array = new_array; + pmq->rule_id_array_size = new_size; + + return new_size; +} + +/** \brief Reset a Pmq for reusage. Meant to be called after a single search. + * \param pmq Pattern matcher to be reset. + * \todo memset is expensive, but we need it as we merge pmq's. We might use + * a flag so we can clear pmq's the old way if we can. + */ +void PmqReset(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + + PMQ_RESET(pmq); +} + +/** \brief Cleanup a Pmq + * \param pmq Pattern matcher queue to be cleaned up. + */ +void PmqCleanup(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + if (pmq->rule_id_array != NULL) { + SCFree(pmq->rule_id_array); + pmq->rule_id_array = NULL; + } +} + +/** \brief Cleanup and free a Pmq + * \param pmq Pattern matcher queue to be free'd. + */ +void PmqFree(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + + PmqCleanup(pmq); +} diff --git a/src/util/prefilter.h b/src/util/prefilter.h new file mode 100644 index 000000000000..e3ac4b6b068d --- /dev/null +++ b/src/util/prefilter.h @@ -0,0 +1,90 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_PREFILTER_H__ +#define __UTIL_PREFILTER_H__ + +#include "util/debug.h" + +/** \brief structure for storing potential rule matches + * + * Helper structure for the prefilter engine. The Pattern Matchers + * and other prefilter engines will add rule id's for potential + * rule matches */ +typedef struct PrefilterRuleStore_ { + /* used for storing rule id's */ + + /* Array of rule IDs found. */ + SigIntId *rule_id_array; + /* Number of rule IDs in the array. */ + uint32_t rule_id_array_cnt; + /* The number of slots allocated for storing rule IDs */ + uint32_t rule_id_array_size; + +} PrefilterRuleStore; + +#define PMQ_RESET(pmq) (pmq)->rule_id_array_cnt = 0 + +/* Resize Signature ID array. Only called from MpmAddSids(). */ +int PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size); + +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first. Calls PrefilterAddSidsResize to increase + * The size of the array, since that is the slow path. + * + * \param pmq storage for match results + * \param sids pointer to array of Signature IDs + * \param sids_size number of Signature IDs in sids array. + * + */ +static inline void PrefilterAddSids( + PrefilterRuleStore *pmq, const SigIntId *sids, uint32_t sids_size) +{ + if (sids_size == 0) + return; + + uint32_t new_size = pmq->rule_id_array_cnt + sids_size; + if (new_size > pmq->rule_id_array_size) { + if (PrefilterAddSidsResize(pmq, new_size) == 0) { + // Failed to allocate larger memory for all the SIDS, but + // keep as many as we can. + sids_size = pmq->rule_id_array_size - pmq->rule_id_array_cnt; + } + } + SCLogDebug("Adding %u sids", sids_size); + // Add SIDs for this pattern to the end of the array + SigIntId *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; + SigIntId *end = ptr + sids_size; + do { + *ptr++ = *sids++; + } while (ptr != end); + pmq->rule_id_array_cnt += sids_size; +} + +int PmqSetup(PrefilterRuleStore *); +void PmqReset(PrefilterRuleStore *); +void PmqCleanup(PrefilterRuleStore *); +void PmqFree(PrefilterRuleStore *); + +#endif /* __UTIL_PREFILTER_H__ */ diff --git a/src/util/print.c b/src/util/print.c new file mode 100644 index 000000000000..60b4b0140600 --- /dev/null +++ b/src/util/print.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2007-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Print utility functions + */ + +#include "suricata-common.h" +#include "util/print.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/validate.h" +#include "rust.h" + +/** + * \brief print a buffer as hex on a single line + * + * Prints in the format "00 AA BB" + * + * \param nbuf buffer into which the output is written + * \param offset of where to start writing into the buffer + * \param max_size the size of the output buffer + * \param buf buffer to print from + * \param buflen length of the input buffer + */ +void PrintBufferRawLineHex( + char *nbuf, int *offset, int max_size, const uint8_t *buf, uint32_t buflen) +{ + for (uint32_t u = 0; u < buflen; u++) { + PrintBufferData(nbuf, offset, max_size, "%02X ", buf[u]); + } +} + +/** + * \brief print a buffer as hex on a single line into retbuf buffer + * + * Prints in the format "00 AA BB" + * + * \param retbuf pointer to the buffer which will have the result + * \param rebuflen length of the buffer + * \param buf buffer to print from + * \param buflen length of the input buffer + */ +void PrintRawLineHexBuf(char *retbuf, uint32_t retbuflen, const uint8_t *buf, uint32_t buflen) +{ + uint32_t offset = 0; + for (uint32_t u = 0; u < buflen; u++) { + PrintBufferData(retbuf, &offset, retbuflen, "%02X ", buf[u]); + } +} + +void PrintRawJsonFp(FILE *fp, uint8_t *buf, uint32_t buflen) +{ +#define BUFFER_LENGTH 2048 + char nbuf[BUFFER_LENGTH] = ""; + uint32_t offset = 0; + + for (uint32_t u = 0; u < buflen; u++) { + if (buf[u] == '\\' || buf[u] == '/' || buf[u] == '\"') { + PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "\\%c", buf[u]); + } else if (isprint(buf[u])) { + PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "%c", buf[u]); + } else { + PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "\\\\x%02X", buf[u]); + } + } + fprintf(fp, "%s", nbuf); +} + +void PrintRawUriFp(FILE *fp, uint8_t *buf, uint32_t buflen) +{ +#define BUFFER_LENGTH 2048 + char nbuf[BUFFER_LENGTH] = ""; + uint32_t offset = 0; + + for (uint32_t u = 0; u < buflen; u++) { + if (isprint(buf[u]) && buf[u] != '\"') { + if (buf[u] == '\\') { + PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "\\\\"); + } else { + PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "%c", buf[u]); + } + } else { + PrintBufferData(nbuf, &offset, BUFFER_LENGTH, "\\x%02X", buf[u]); + } + } + + fprintf(fp, "%s", nbuf); +} + +void PrintRawUriBuf( + char *retbuf, uint32_t *offset, uint32_t retbuflen, uint8_t *buf, uint32_t buflen) +{ + for (uint32_t u = 0; u < buflen; u++) { + if (isprint(buf[u]) && buf[u] != '\"') { + if (buf[u] == '\\') { + PrintBufferData(retbuf, offset, retbuflen, "\\\\"); + } else { + PrintBufferData(retbuf, offset, retbuflen, "%c", buf[u]); + } + } else { + PrintBufferData(retbuf, offset, retbuflen, "\\x%02X", buf[u]); + } + } + + return; +} + +void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen) +{ + int ch = 0; + + if (buf == NULL) { + fprintf(fp, " (null)\n"); + return; + } + for (uint32_t u = 0; u < buflen; u += 16) { + fprintf(fp, " %04X ", u); + for (ch = 0; (u + ch) < buflen && ch < 16; ch++) { + fprintf(fp, "%02X ", (uint8_t)buf[u + ch]); + + if (ch == 7) + fprintf(fp, " "); + } + if (ch == 16) + fprintf(fp, " "); + else if (ch < 8) { + int spaces = (16 - ch) * 3 + 2 + 1; + int s = 0; + for (; s < spaces; s++) + fprintf(fp, " "); + } else if (ch < 16) { + int spaces = (16 - ch) * 3 + 2; + int s = 0; + for (; s < spaces; s++) + fprintf(fp, " "); + } + + for (ch = 0; (u + ch) < buflen && ch < 16; ch++) { + fprintf(fp, "%c", isprint((uint8_t)buf[u + ch]) ? (uint8_t)buf[u + ch] : '.'); + + if (ch == 7) + fprintf(fp, " "); + if (ch == 15) + fprintf(fp, "\n"); + } + } + if (ch != 16) + fprintf(fp, "\n"); +} + +void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, + const uint8_t *src_buf, uint32_t src_buf_len) +{ + int ch = 0; + + for (uint32_t u = 0; u < src_buf_len; u += 16) { + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " %04X ", u); + for (ch = 0; (u + ch) < src_buf_len && ch < 16; ch++) { + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "%02X ", + (uint8_t)src_buf[u + ch]); + + if (ch == 7) { + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); + } + } + if (ch == 16) { + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); + } else if (ch < 8) { + int spaces = (16 - ch) * 3 + 2 + 1; + int s = 0; + for (; s < spaces; s++) + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); + } else if (ch < 16) { + int spaces = (16 - ch) * 3 + 2; + int s = 0; + for (; s < spaces; s++) + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); + } + + for (ch = 0; (u + ch) < src_buf_len && ch < 16; ch++) { + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "%c", + isprint((uint8_t)src_buf[u + ch]) ? (uint8_t)src_buf[u + ch] : '.'); + + if (ch == 7) + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, " "); + if (ch == 15) + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "\n"); + } + } + if (ch != 16) + PrintBufferData((char *)dst_buf, dst_buf_offset_ptr, dst_buf_size, "\n"); + + return; +} + +void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, + const uint8_t *src_buf, const uint32_t src_buf_len) +{ + for (uint32_t ch = 0; ch < src_buf_len && *dst_buf_offset_ptr < dst_buf_size; + ch++, (*dst_buf_offset_ptr)++) { + if (isprint((uint8_t)src_buf[ch]) || src_buf[ch] == '\n' || src_buf[ch] == '\r') { + dst_buf[*dst_buf_offset_ptr] = src_buf[ch]; + } else { + dst_buf[*dst_buf_offset_ptr] = '.'; + } + } + dst_buf[dst_buf_size - 1] = 0; + + return; +} + +#ifndef s6_addr16 +#define s6_addr16 __u6_addr.__u6_addr16 +#endif + +static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size) +{ + char s_part[6]; + uint16_t x[8]; + memcpy(&x, src, 16); + + /* current IPv6 format is fixed size */ + if (size < 8 * 5) { + SCLogWarning("Too small buffer to write IPv6 address"); + return NULL; + } + memset(dst, 0, size); + for (int i = 0; i < 8; i++) { + snprintf(s_part, sizeof(s_part), "%04x:", htons(x[i])); + strlcat(dst, s_part, size); + } + /* suppress last ':' */ + dst[strlen(dst) - 1] = 0; + + return dst; +} + +const char *PrintInet(int af, const void *src, char *dst, socklen_t size) +{ + switch (af) { + case AF_INET: +#if defined(OS_WIN32) && NTDDI_VERSION >= NTDDI_VISTA + { + // because Windows has to provide a non-conformant inet_ntop, of + // course! + struct in_addr _src; + memcpy(&_src, src, sizeof(struct in_addr)); + return inet_ntop(af, &_src, dst, size); + } +#else + return inet_ntop(af, src, dst, size); +#endif + case AF_INET6: + /* Format IPv6 without deleting zeroes */ + return PrintInetIPv6(src, dst, size); + default: + SCLogError("Unsupported protocol: %d", af); + } + return NULL; +} + +void PrintHexString(char *str, size_t size, uint8_t *buf, size_t buf_len) +{ + DEBUG_VALIDATE_BUG_ON(size < 2 * buf_len); + rs_to_hex((uint8_t *)str, size, buf, buf_len); +} diff --git a/src/util/print.h b/src/util/print.h new file mode 100644 index 000000000000..63d051c11b72 --- /dev/null +++ b/src/util/print.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_PRINT_H__ +#define __UTIL_PRINT_H__ + +#define PrintBufferData(buf, buf_offset_ptr, buf_size, ...) \ + do { \ + int cw = snprintf((buf) + *(buf_offset_ptr), (buf_size) - *(buf_offset_ptr), __VA_ARGS__); \ + if (cw >= 0) { \ + if ((*(buf_offset_ptr) + cw) >= buf_size) { \ + SCLogDebug("Truncating data write since it exceeded buffer " \ + "limit of - %" PRIu32 "\n", \ + buf_size); \ + *(buf_offset_ptr) = buf_size - 1; \ + } else { \ + *(buf_offset_ptr) += cw; \ + } \ + } \ + } while (0) + +void PrintBufferRawLineHex(char *, int *, int, const uint8_t *, uint32_t); +void PrintRawUriFp(FILE *, uint8_t *, uint32_t); +void PrintRawUriBuf(char *, uint32_t *, uint32_t, uint8_t *, uint32_t); +void PrintRawJsonFp(FILE *, uint8_t *, uint32_t); +void PrintRawDataFp(FILE *, const uint8_t *, uint32_t); +void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, + const uint8_t *src_buf, uint32_t src_buf_len); +void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, + const uint8_t *src_buf, const uint32_t src_buf_len); +void PrintRawLineHexBuf(char *, uint32_t, const uint8_t *, uint32_t); +const char *PrintInet(int, const void *, char *, socklen_t); +void PrintHexString(char *str, size_t size, uint8_t *buf, size_t buf_len); + +#endif /* __UTIL_PRINT_H__ */ diff --git a/src/util/privs.c b/src/util/privs.c new file mode 100644 index 000000000000..1ab132c39de6 --- /dev/null +++ b/src/util/privs.c @@ -0,0 +1,256 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + * + * File to drop the engine capabilities using libcap-ng by + * Steve Grubb + */ + +#ifndef OS_WIN32 + +#include "suricata-common.h" +#include "util/debug.h" +#include "suricata.h" + +#include "util/privs.h" +#include "util/byte.h" + +#ifdef HAVE_LIBCAP_NG + +#include +#ifdef HAVE_SYS_PRCTL_H +#include +#endif +#include "threadvars.h" +#include "util/cpu.h" +#include "runmodes.h" + +/** flag indicating if we'll be using caps */ +extern bool sc_set_caps; + +/** our current runmode */ +extern int run_mode; + +/** + * \brief Drop the privileges of the main thread + */ +void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) +{ + if (!sc_set_caps) + return; + + capng_clear(CAPNG_SELECT_BOTH); + + switch (run_mode) { + case RUNMODE_PCAP_DEV: + case RUNMODE_AFP_DEV: + case RUNMODE_AFXDP_DEV: + capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, + CAP_NET_RAW, /* needed for pcap live mode */ + CAP_SYS_NICE, CAP_NET_ADMIN, -1); + break; + case RUNMODE_PFRING: + capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_NET_ADMIN, CAP_NET_RAW, + CAP_SYS_NICE, -1); + break; + case RUNMODE_NFLOG: + case RUNMODE_NFQ: + capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, + CAP_NET_ADMIN, /* needed for nflog and nfqueue inline mode */ + CAP_SYS_NICE, -1); + break; + } + + if (capng_change_id(userid, groupid, CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING) < 0) { + FatalError("capng_change_id for main thread" + " failed"); + } + + SCLogInfo("dropped the caps for main thread"); +} + +void SCDropCaps(ThreadVars *tv) +{ +#if 0 + capng_clear(CAPNG_SELECT_BOTH); + capng_apply(CAPNG_SELECT_BOTH); + if (tv->cap_flags & SC_CAP_IPC_LOCK) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_ADMIN) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_BROADCAST) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_RAW) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_SYS_ADMIN) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); + } +#endif +} + +#endif /* HAVE_LIBCAP_NG */ + +/** + * \brief Function to get the user and group ID from the specified user name + * + * \param user_name pointer to the given user name + * \param uid pointer to the user id in which result will be stored + * \param gid pointer to the group id in which result will be stored + * + * \retval FatalError on a failure + */ +void SCGetUserID(const char *user_name, const char *group_name, uint32_t *uid, uint32_t *gid) +{ + uint32_t userid = 0; + uint32_t groupid = 0; + struct passwd *pw; + + if (user_name == NULL || strlen(user_name) == 0) { + FatalError("no user name was provided - ensure it is specified either in the configuration " + "file (run-as.user) or in command-line arguments (--user)"); + } + + /* Get the user ID */ + if (isdigit((unsigned char)user_name[0]) != 0) { + if (ByteExtractStringUint32(&userid, 10, 0, (const char *)user_name) < 0) { + FatalError("invalid user id value: '%s'", user_name); + } + pw = getpwuid(userid); + if (pw == NULL) { + FatalError("unable to get the user ID, " + "check if user exist!!"); + } + } else { + pw = getpwnam(user_name); + if (pw == NULL) { + FatalError("unable to get the user ID, " + "check if user exist!!"); + } + userid = pw->pw_uid; + } + + /* Get the group ID */ + if (group_name != NULL) { + struct group *gp; + + if (isdigit((unsigned char)group_name[0]) != 0) { + if (ByteExtractStringUint32(&groupid, 10, 0, (const char *)group_name) < 0) { + FatalError("invalid group id: '%s'", group_name); + } + } else { + gp = getgrnam(group_name); + if (gp == NULL) { + FatalError("unable to get the group" + " ID, check if group exist!!"); + } + groupid = gp->gr_gid; + } + } else { + groupid = pw->pw_gid; + } + + /* close the group database */ + endgrent(); + /* close the user database */ + endpwent(); + + *uid = userid; + *gid = groupid; +} + +/** + * \brief Function to get the group ID from the specified group name + * + * \param group_name pointer to the given group name + * \param gid pointer to the group id in which result will be stored + * + * \retval FatalError on a failure + */ +void SCGetGroupID(const char *group_name, uint32_t *gid) +{ + uint32_t grpid = 0; + struct group *gp; + + if (group_name == NULL || strlen(group_name) == 0) { + FatalError("no group name was provided - ensure it is specified either in the " + "configuration file (run-as.group) or in command-line arguments (--group)"); + } + + /* Get the group ID */ + if (isdigit((unsigned char)group_name[0]) != 0) { + if (ByteExtractStringUint32(&grpid, 10, 0, (const char *)group_name) < 0) { + FatalError("invalid group id: '%s'", group_name); + } + } else { + gp = getgrnam(group_name); + if (gp == NULL) { + FatalError("unable to get the group ID," + " check if group exist!!"); + } + grpid = gp->gr_gid; + } + + /* close the group database */ + endgrent(); + + *gid = grpid; +} + +#ifdef __OpenBSD__ +int SCPledge(void) +{ + int ret = pledge("stdio rpath wpath cpath fattr unix dns bpf", NULL); + + if (ret != 0) { + SCLogError("unable to pledge," + " check permissions!! ret=%i errno=%i", + ret, errno); + exit(EXIT_FAILURE); + } + + return 0; +} +#endif /* __OpenBSD__ */ +#endif /* OS_WIN32 */ diff --git a/src/util/privs.h b/src/util/privs.h new file mode 100644 index 000000000000..21322d6224ee --- /dev/null +++ b/src/util/privs.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + */ + +#ifndef _UTIL_PRIVS_H +#define _UTIL_PRIVS_H + +#define SC_CAP_NONE 0x01 +#define SC_CAP_SYS_ADMIN 0x02 +#define SC_CAP_SYS_RAW_IO 0x04 +#define SC_CAP_IPC_LOCK 0x08 +#define SC_CAP_NET_ADMIN 0x10 +#define SC_CAP_NET_RAW 0x20 +#define SC_CAP_NET_BIND_SERVICE 0x40 +#define SC_CAP_NET_BROADCAST 0x80 + +#ifdef HAVE_LIBCAP_NG +#include +#include "threadvars.h" + +/**Drop the privileges of the given thread tv, based on the thread cap_flags + * which implies the capability requirement of the given thread. Initially all + * caps are dropped and later, the required caps are set for the given thread + */ +void SCDropCaps(ThreadVars *tv); +/* +#define SCDropCaps(tv) ({ \ + capng_clear(CAPNG_SELECT_BOTH); \ + capng_apply(CAPNG_SELECT_BOTH); \ + if (tv->cap_flags & SC_CAP_IPC_LOCK) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_ADMIN) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); +\ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), +CAP_NET_BIND_SERVICE); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_BROADCAST) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), +CAP_NET_BROADCAST); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_RAW) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_SYS_ADMIN) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); +\ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); +\ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); \ + } \ +}) +*/ +void SCDropMainThreadCaps(uint32_t, uint32_t); + +#else +#define SCDropCaps(...) +#define SCDropMainThreadCaps(...) +#endif /* HAVE_LIBCAP_NG */ + +void SCGetUserID(const char *, const char *, uint32_t *, uint32_t *); +void SCGetGroupID(const char *, uint32_t *); + +#ifdef __OpenBSD__ +int SCPledge(void); +#else /* __OpenBSD__ */ +#define SCPledge(...) +#endif /* __OpenBSD__ */ + +#endif /* _UTIL_PRIVS_H */ diff --git a/src/util/profiling-keywords.c b/src/util/profiling-keywords.c new file mode 100644 index 000000000000..f12f5f10f038 --- /dev/null +++ b/src/util/profiling-keywords.c @@ -0,0 +1,395 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited. + * \author Victor Julien + * + * An API for rule profiling operations. + */ + +#include "suricata-common.h" +#include "util/profiling.h" +#include "util/profiling-locks.h" + +#ifdef PROFILING +#include "detect-engine.h" +#include "tm-threads.h" +#include "util/conf.h" +#include "util/time.h" + +/** + * Extra data for rule profiling. + */ +typedef struct SCProfileKeywordData_ { + uint64_t checks; + uint64_t matches; + uint64_t max; + uint64_t ticks_match; + uint64_t ticks_no_match; +} SCProfileKeywordData; + +typedef struct SCProfileKeywordDetectCtx_ { + uint32_t id; + SCProfileKeywordData *data; + pthread_mutex_t data_m; +} SCProfileKeywordDetectCtx; + +static int profiling_keywords_output_to_file = 0; +int profiling_keyword_enabled = 0; +thread_local int profiling_keyword_entered = 0; +static char profiling_file_name[PATH_MAX]; +static const char *profiling_file_mode = "a"; + +void SCProfilingKeywordsGlobalInit(void) +{ + ConfNode *conf; + + conf = ConfGetNode("profiling.keywords"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + profiling_keyword_enabled = 1; + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + const char *log_dir; + log_dir = ConfigGetLogDirectory(); + + snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", log_dir, + filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_file_mode = "a"; + } else { + profiling_file_mode = "w"; + } + + profiling_keywords_output_to_file = 1; + } + } + } +} + +static void DoDump(SCProfileKeywordDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + int i; + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Stats for: %s\n", name); + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-16s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Keyword", "Ticks", "Checks", + "Matches", "Max Ticks", "Avg", "Avg Match", "Avg No Match"); + fprintf(fp, " ---------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "\n"); + for (i = 0; i < DETECT_TBLSIZE; i++) { + SCProfileKeywordData *d = &rules_ctx->data[i]; + if (d == NULL || d->checks == 0) + continue; + + uint64_t ticks = d->ticks_match + d->ticks_no_match; + double avgticks = 0; + double avgticks_match = 0; + double avgticks_no_match = 0; + if (ticks && d->checks) { + avgticks = (double)(ticks / d->checks); + + if (d->ticks_match && d->matches) + avgticks_match = (double)(d->ticks_match / d->matches); + if (d->ticks_no_match && (d->checks - d->matches) != 0) + avgticks_no_match = (double)(d->ticks_no_match / (d->checks - d->matches)); + } + + fprintf(fp, + " %-16s %-15" PRIu64 " %-15" PRIu64 " %-15" PRIu64 " %-15" PRIu64 + " %-15.2f %-15.2f %-15.2f\n", + sigmatch_table[i].name, ticks, d->checks, d->matches, d->max, avgticks, + avgticks_match, avgticks_no_match); + } +} + +static void SCProfilingKeywordDump(DetectEngineCtx *de_ctx) +{ + int i; + FILE *fp; + struct timeval tval; + struct tm *tms; + struct tm local_tm; + + if (profiling_keyword_enabled == 0) + return; + + const int nlists = de_ctx->buffer_type_id; + gettimeofday(&tval, NULL); + tms = SCLocalTime(tval.tv_sec, &local_tm); + + if (profiling_keywords_output_to_file == 1) { + SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); + + fp = fopen(profiling_file_name, profiling_file_mode); + + if (fp == NULL) { + SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); + return; + } + } else { + fp = stdout; + } + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, + " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d\n", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, + tms->tm_sec); + + /* global stats first */ + DoDump(de_ctx->profile_keyword_ctx, fp, "total"); + /* per buffer stats next, but only if there are stats to print */ + for (i = 0; i < nlists; i++) { + int j; + uint64_t checks = 0; + for (j = 0; j < DETECT_TBLSIZE; j++) { + checks += de_ctx->profile_keyword_ctx_per_list[i]->data[j].checks; + } + + if (checks) { + const char *name = NULL; + if (i < DETECT_SM_LIST_DYNAMIC_START) { + name = DetectSigmatchListEnumToString(i); + } else { + name = DetectEngineBufferTypeGetNameById(de_ctx, i); + } + + DoDump(de_ctx->profile_keyword_ctx_per_list[i], fp, name); + } + } + + fprintf(fp, "\n"); + if (fp != stdout) + fclose(fp); + + SCLogPerf("Done dumping keyword profiling data."); +} + +/** + * \brief Update a rule counter. + * + * \param id The ID of this counter. + * \param ticks Number of CPU ticks for this rule. + * \param match Did the rule match? + */ +void SCProfilingKeywordUpdateCounter( + DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, int match) +{ + if (det_ctx != NULL && det_ctx->keyword_perf_data != NULL && id < DETECT_TBLSIZE) { + SCProfileKeywordData *p = &det_ctx->keyword_perf_data[id]; + + p->checks++; + p->matches += match; + if (ticks > p->max) + p->max = ticks; + if (match == 1) + p->ticks_match += ticks; + else + p->ticks_no_match += ticks; + + /* store per list (buffer type) as well */ + if (det_ctx->keyword_perf_list >= + 0) { // && det_ctx->keyword_perf_list < DETECT_SM_LIST_MAX) { + p = &det_ctx->keyword_perf_data_per_list[det_ctx->keyword_perf_list][id]; + p->checks++; + p->matches += match; + if (ticks > p->max) + p->max = ticks; + if (match == 1) + p->ticks_match += ticks; + else + p->ticks_no_match += ticks; + } + } +} + +static SCProfileKeywordDetectCtx *SCProfilingKeywordInitCtx(void) +{ + SCProfileKeywordDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileKeywordDetectCtx)); + if (ctx != NULL) { + + if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { + FatalError("Failed to initialize hash table mutex."); + } + } + + return ctx; +} + +static void DetroyCtx(SCProfileKeywordDetectCtx *ctx) +{ + if (ctx) { + if (ctx->data != NULL) + SCFree(ctx->data); + pthread_mutex_destroy(&ctx->data_m); + SCFree(ctx); + } +} + +void SCProfilingKeywordDestroyCtx(DetectEngineCtx *de_ctx) +{ + if (de_ctx != NULL) { + SCProfilingKeywordDump(de_ctx); + + DetroyCtx(de_ctx->profile_keyword_ctx); + + const int nlists = de_ctx->buffer_type_id; + int i; + for (i = 0; i < nlists; i++) { + DetroyCtx(de_ctx->profile_keyword_ctx_per_list[i]); + } + SCFree(de_ctx->profile_keyword_ctx_per_list); + } +} + +void SCProfilingKeywordThreadSetup(SCProfileKeywordDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) +{ + if (ctx == NULL) + return; + + SCProfileKeywordData *a = SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); + if (a != NULL) { + det_ctx->keyword_perf_data = a; + } + + const int nlists = det_ctx->de_ctx->buffer_type_id; + det_ctx->keyword_perf_data_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordData *)); + BUG_ON(det_ctx->keyword_perf_data_per_list == NULL); + + int i; + for (i = 0; i < nlists; i++) { + SCProfileKeywordData *b = SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); + if (b != NULL) { + det_ctx->keyword_perf_data_per_list[i] = b; + } + } +} + +static void SCProfilingKeywordThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) +{ + if (de_ctx == NULL || de_ctx->profile_keyword_ctx == NULL || + de_ctx->profile_keyword_ctx->data == NULL || det_ctx == NULL || + det_ctx->keyword_perf_data == NULL) + return; + + int i; + for (i = 0; i < DETECT_TBLSIZE; i++) { + de_ctx->profile_keyword_ctx->data[i].checks += det_ctx->keyword_perf_data[i].checks; + de_ctx->profile_keyword_ctx->data[i].matches += det_ctx->keyword_perf_data[i].matches; + de_ctx->profile_keyword_ctx->data[i].ticks_match += + det_ctx->keyword_perf_data[i].ticks_match; + de_ctx->profile_keyword_ctx->data[i].ticks_no_match += + det_ctx->keyword_perf_data[i].ticks_no_match; + if (det_ctx->keyword_perf_data[i].max > de_ctx->profile_keyword_ctx->data[i].max) + de_ctx->profile_keyword_ctx->data[i].max = det_ctx->keyword_perf_data[i].max; + } + + const int nlists = det_ctx->de_ctx->buffer_type_id; + int j; + for (j = 0; j < nlists; j++) { + for (i = 0; i < DETECT_TBLSIZE; i++) { + de_ctx->profile_keyword_ctx_per_list[j]->data[i].checks += + det_ctx->keyword_perf_data_per_list[j][i].checks; + de_ctx->profile_keyword_ctx_per_list[j]->data[i].matches += + det_ctx->keyword_perf_data_per_list[j][i].matches; + de_ctx->profile_keyword_ctx_per_list[j]->data[i].ticks_match += + det_ctx->keyword_perf_data_per_list[j][i].ticks_match; + de_ctx->profile_keyword_ctx_per_list[j]->data[i].ticks_no_match += + det_ctx->keyword_perf_data_per_list[j][i].ticks_no_match; + if (det_ctx->keyword_perf_data_per_list[j][i].max > + de_ctx->profile_keyword_ctx_per_list[j]->data[i].max) + de_ctx->profile_keyword_ctx_per_list[j]->data[i].max = + det_ctx->keyword_perf_data_per_list[j][i].max; + } + } +} + +void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->keyword_perf_data == NULL) + return; + + pthread_mutex_lock(&det_ctx->de_ctx->profile_keyword_ctx->data_m); + SCProfilingKeywordThreadMerge(det_ctx->de_ctx, det_ctx); + pthread_mutex_unlock(&det_ctx->de_ctx->profile_keyword_ctx->data_m); + + SCFree(det_ctx->keyword_perf_data); + det_ctx->keyword_perf_data = NULL; + + const int nlists = det_ctx->de_ctx->buffer_type_id; + int i; + for (i = 0; i < nlists; i++) { + SCFree(det_ctx->keyword_perf_data_per_list[i]); + det_ctx->keyword_perf_data_per_list[i] = NULL; + } + SCFree(det_ctx->keyword_perf_data_per_list); +} + +/** + * \brief Register the keyword profiling counters. + * + * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. + */ +void SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) +{ + if (profiling_keyword_enabled == 0) + return; + + const int nlists = de_ctx->buffer_type_id; + + de_ctx->profile_keyword_ctx = SCProfilingKeywordInitCtx(); + BUG_ON(de_ctx->profile_keyword_ctx == NULL); + + de_ctx->profile_keyword_ctx->data = SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); + BUG_ON(de_ctx->profile_keyword_ctx->data == NULL); + + de_ctx->profile_keyword_ctx_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordDetectCtx *)); + BUG_ON(de_ctx->profile_keyword_ctx_per_list == NULL); + + int i; + for (i = 0; i < nlists; i++) { + de_ctx->profile_keyword_ctx_per_list[i] = SCProfilingKeywordInitCtx(); + BUG_ON(de_ctx->profile_keyword_ctx_per_list[i] == NULL); + de_ctx->profile_keyword_ctx_per_list[i]->data = + SCCalloc(DETECT_TBLSIZE, sizeof(SCProfileKeywordData)); + BUG_ON(de_ctx->profile_keyword_ctx_per_list[i]->data == NULL); + } + + SCLogPerf("Registered %" PRIu32 " keyword profiling counters.", DETECT_TBLSIZE); +} + +#endif /* PROFILING */ diff --git a/src/util/profiling-locks.c b/src/util/profiling-locks.c new file mode 100644 index 000000000000..7195159f57e0 --- /dev/null +++ b/src/util/profiling-locks.c @@ -0,0 +1,246 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * An API for profiling locks. + * + */ + +#include "suricata-common.h" +#include "util/profiling-locks.h" + +#ifdef PROFILING +#ifdef PROFILE_LOCKING +#include "threads.h" +#include "util/hashlist.h" +#include "util/debug.h" + +thread_local ProfilingLock locks[PROFILING_MAX_LOCKS]; +thread_local int locks_idx = 0; +thread_local int record_locks = 0; + +int profiling_locks_enabled = 0; +int profiling_locks_output_to_file = 0; +char *profiling_locks_file_name = NULL; +const char *profiling_locks_file_mode = "a"; + +typedef struct LockRecord_ { + char *file; // hash + + char *func; // info + int type; // info + + int line; // hash + + uint32_t cont; + uint32_t ticks_cnt; + uint64_t ticks_total; + uint64_t ticks_max; +} LockRecord; + +HashListTable *lock_records; +pthread_mutex_t lock_records_mutex; + +static uint32_t LockRecordHash(HashListTable *ht, void *buf, uint16_t buflen) +{ + LockRecord *fn = (LockRecord *)buf; + uint32_t hash = strlen(fn->file) + fn->line; + uint16_t u; + + for (u = 0; u < strlen(fn->file); u++) { + hash += fn->file[u]; + } + + return hash % ht->array_size; +} + +static char LockRecordCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) +{ + LockRecord *fn1 = (LockRecord *)buf1; + LockRecord *fn2 = (LockRecord *)buf2; + + if (fn1->line != fn2->line) + return 0; + + if (fn1->file == fn2->file) + return 1; + + return 0; +} + +static void LockRecordFree(void *data) +{ + LockRecord *fn = (LockRecord *)data; + + if (fn == NULL) + return; + SCFree(fn); +} + +int LockRecordInitHash(void) +{ + pthread_mutex_init(&lock_records_mutex, NULL); + pthread_mutex_lock(&lock_records_mutex); + + lock_records = HashListTableInit(512, LockRecordHash, LockRecordCompare, LockRecordFree); + BUG_ON(lock_records == NULL); + + pthread_mutex_unlock(&lock_records_mutex); + + return 0; +} + +static void LockRecordAdd(ProfilingLock *l) +{ + LockRecord fn = { NULL, NULL, 0, 0, 0, 0, 0, 0 }, *ptr = &fn; + fn.file = l->file; + fn.line = l->line; + + LockRecord *lookup_fn = (LockRecord *)HashListTableLookup(lock_records, (void *)ptr, 0); + if (lookup_fn == NULL) { + LockRecord *new = SCMalloc(sizeof(LockRecord)); + BUG_ON(new == NULL); + + new->file = l->file; + new->line = l->line; + new->type = l->type; + new->cont = l->cont; + new->func = l->func; + new->ticks_max = l->ticks; + new->ticks_total = l->ticks; + new->ticks_cnt = 1; + + HashListTableAdd(lock_records, (void *)new, 0); + } else { + lookup_fn->ticks_total += l->ticks; + if (l->ticks > lookup_fn->ticks_max) + lookup_fn->ticks_max = l->ticks; + lookup_fn->ticks_cnt++; + lookup_fn->cont += l->cont; + } + + return; +} + +/** \param p void ptr to Packet struct */ +void SCProfilingAddPacketLocks(void *p) +{ + int i; + + if (profiling_locks_enabled == 0) + return; + + for (i = 0; i < locks_idx; i++) { + pthread_mutex_lock(&lock_records_mutex); + LockRecordAdd(&locks[i]); + pthread_mutex_unlock(&lock_records_mutex); + } +} + +static void SCProfilingListLocks(void) +{ + FILE *fp = NULL; + + if (profiling_locks_output_to_file == 1) { + fp = fopen(profiling_locks_file_name, profiling_locks_file_mode); + + if (fp == NULL) { + SCLogError("failed to open %s: %s", profiling_locks_file_name, strerror(errno)); + return; + } + } else { + fp = stdout; + } + + fprintf(fp, "\n\nLock Cnt Avg ticks Max " + "ticks Total ticks Cont Func\n"); + fprintf(fp, "------------------ ---------- --------- " + "------------ ------------ ------- ---------\n"); + + uint64_t total = 0; + uint32_t cont = 0; + uint64_t cnt = 0; + + HashListTableBucket *b = HashListTableGetListHead(lock_records); + while (b) { + LockRecord *r = HashListTableGetListData(b); + + const char *lock; + switch (r->type) { + case LOCK_MUTEX: + lock = "mtx"; + break; + case LOCK_SPIN: + lock = "spn"; + break; + case LOCK_RWW: + lock = "rww"; + break; + case LOCK_RWR: + lock = "rwr"; + break; + default: + lock = "bug"; + break; + } + + char str[128] = ""; + snprintf(str, sizeof(str), "(%s) %s:%d", lock, r->file, r->line); + + fprintf(fp, "%-50s %-10u %-9" PRIu64 " %-12" PRIu64 " %-12" PRIu64 " %-7u %-s\n", str, + r->ticks_cnt, (uint64_t)((uint64_t)r->ticks_total / (uint64_t)r->ticks_cnt), + r->ticks_max, r->ticks_total, r->cont, r->func); + + total += r->ticks_total; + cnt += r->ticks_cnt; + cont += r->cont; + + b = HashListTableGetListNext(b); + } + + fprintf(fp, + "\nOverall: locks %" PRIu64 ", average cost %" PRIu64 ", contentions %" PRIu32 + ", total ticks %" PRIu64 "\n", + cnt, (uint64_t)((uint64_t)total / (uint64_t)cnt), cont, total); + + fclose(fp); +} + +void LockRecordFreeHash(void) +{ + if (profiling_locks_enabled == 0) + return; + + pthread_mutex_lock(&lock_records_mutex); + + SCProfilingListLocks(); + + if (lock_records != NULL) { + HashListTableFree(lock_records); + lock_records = NULL; + } + pthread_mutex_unlock(&lock_records_mutex); + + pthread_mutex_destroy(&lock_records_mutex); +} + +#endif +#endif diff --git a/src/util/profiling-locks.h b/src/util/profiling-locks.h new file mode 100644 index 000000000000..ae17cbfafe86 --- /dev/null +++ b/src/util/profiling-locks.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_PROFILE_LOCKS_H__ +#define __UTIL_PROFILE_LOCKS_H__ + +#ifdef PROFILING + +void SCProfilingAddPacketLocks(void *); + +int LockRecordInitHash(void); +void LockRecordFreeHash(void); + +#endif /* PROFILING */ +#endif /* __UTIL_PROFILE_LOCKS_H__ */ diff --git a/src/util/profiling-prefilter.c b/src/util/profiling-prefilter.c new file mode 100644 index 000000000000..be7ead76ed6d --- /dev/null +++ b/src/util/profiling-prefilter.c @@ -0,0 +1,324 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited. + * \author Victor Julien + * + * An API for rule profiling operations. + */ + +#include "suricata-common.h" +#include "util/profiling.h" + +#ifdef PROFILING +#include "detect-engine-prefilter.h" +#include "util/conf.h" +#include "util/time.h" + +typedef struct SCProfilePrefilterData_ { + uint64_t called; + uint64_t total; + uint64_t max; + uint64_t total_bytes; + uint64_t max_bytes; + uint64_t bytes_called; /**< number of times total_bytes was updated. Differs from `called` as a + prefilter engine may skip mpm if the smallest pattern is bigger than + the buffer to inspect. */ + const char *name; +} SCProfilePrefilterData; + +typedef struct SCProfilePrefilterDetectCtx_ { + uint32_t id; + uint32_t size; /**< size in elements */ + SCProfilePrefilterData *data; + pthread_mutex_t data_m; +} SCProfilePrefilterDetectCtx; + +static int profiling_prefilter_output_to_file = 0; +int profiling_prefilter_enabled = 0; +thread_local int profiling_prefilter_entered = 0; +static char profiling_file_name[PATH_MAX]; +static const char *profiling_file_mode = "a"; + +void SCProfilingPrefilterGlobalInit(void) +{ + ConfNode *conf; + + conf = ConfGetNode("profiling.prefilter"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + profiling_prefilter_enabled = 1; + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + const char *log_dir; + log_dir = ConfigGetLogDirectory(); + + snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", log_dir, + filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_file_mode = "a"; + } else { + profiling_file_mode = "w"; + } + + profiling_prefilter_output_to_file = 1; + } + } + } +} + +static void DoDump(SCProfilePrefilterDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + int i; + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Stats for: %s\n", name); + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-32s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Prefilter", + "Ticks", "Called", "Max Ticks", "Avg", "Bytes", "Called", "Max Bytes", "Avg Bytes", + "Ticks/Byte"); + fprintf(fp, " -------------------------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "\n"); + for (i = 0; i < (int)rules_ctx->size; i++) { + SCProfilePrefilterData *d = &rules_ctx->data[i]; + if (d == NULL || d->called == 0) + continue; + + uint64_t ticks = d->total; + double avgticks = 0; + if (ticks && d->called) { + avgticks = (double)(ticks / d->called); + } + double avgbytes = 0; + if (d->total_bytes && d->bytes_called) { + avgbytes = (double)(d->total_bytes / d->bytes_called); + } + double ticks_per_byte = 0; + if (ticks && d->total_bytes) { + ticks_per_byte = (double)(ticks / d->total_bytes); + } + + fprintf(fp, + " %-32s %-15" PRIu64 " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15" PRIu64 + " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15.2f\n", + d->name, ticks, d->called, d->max, avgticks, d->total_bytes, d->bytes_called, + d->max_bytes, avgbytes, ticks_per_byte); + } +} + +static void SCProfilingPrefilterDump(DetectEngineCtx *de_ctx) +{ + FILE *fp; + struct timeval tval; + struct tm *tms; + struct tm local_tm; + + if (profiling_prefilter_enabled == 0 || de_ctx->profile_prefilter_ctx == NULL) + return; + + gettimeofday(&tval, NULL); + tms = SCLocalTime(tval.tv_sec, &local_tm); + + if (profiling_prefilter_output_to_file == 1) { + SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); + + fp = fopen(profiling_file_name, profiling_file_mode); + + if (fp == NULL) { + SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); + return; + } + } else { + fp = stdout; + } + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, + " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d\n", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, + tms->tm_sec); + + /* global stats first */ + DoDump(de_ctx->profile_prefilter_ctx, fp, "total"); + + fprintf(fp, "\n"); + if (fp != stdout) + fclose(fp); + + SCLogPerf("Done dumping prefilter profiling data."); +} + +/** + * \brief Update a rule counter. + * + * \param id The ID of this counter. + * \param ticks Number of CPU ticks for this rule. + * \param match Did the rule match? + */ +void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, + uint64_t bytes, uint64_t bytes_called) +{ + if (det_ctx != NULL && det_ctx->prefilter_perf_data != NULL && + id < (int)det_ctx->de_ctx->prefilter_id) { + SCProfilePrefilterData *p = &det_ctx->prefilter_perf_data[id]; + + p->called++; + if (ticks > p->max) + p->max = ticks; + p->total += ticks; + + p->bytes_called += bytes_called; + if (bytes > p->max_bytes) + p->max_bytes = bytes; + p->total_bytes += bytes; + } +} + +static SCProfilePrefilterDetectCtx *SCProfilingPrefilterInitCtx(void) +{ + SCProfilePrefilterDetectCtx *ctx = SCCalloc(1, sizeof(SCProfilePrefilterDetectCtx)); + if (ctx != NULL) { + if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { + FatalError("Failed to initialize hash table mutex."); + } + } + + return ctx; +} + +static void DetroyCtx(SCProfilePrefilterDetectCtx *ctx) +{ + if (ctx) { + if (ctx->data != NULL) + SCFree(ctx->data); + pthread_mutex_destroy(&ctx->data_m); + SCFree(ctx); + } +} + +void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *de_ctx) +{ + if (de_ctx != NULL) { + SCProfilingPrefilterDump(de_ctx); + + DetroyCtx(de_ctx->profile_prefilter_ctx); + } +} + +void SCProfilingPrefilterThreadSetup( + SCProfilePrefilterDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) +{ + if (ctx == NULL) + return; + + const uint32_t size = det_ctx->de_ctx->prefilter_id; + + SCProfilePrefilterData *a = SCCalloc(1, sizeof(SCProfilePrefilterData) * size); + if (a != NULL) { + det_ctx->prefilter_perf_data = a; + } +} + +static void SCProfilingPrefilterThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) +{ + if (de_ctx == NULL || de_ctx->profile_prefilter_ctx == NULL || + de_ctx->profile_prefilter_ctx->data == NULL || det_ctx == NULL || + det_ctx->prefilter_perf_data == NULL) + return; + + for (uint32_t i = 0; i < de_ctx->prefilter_id; i++) { + de_ctx->profile_prefilter_ctx->data[i].called += det_ctx->prefilter_perf_data[i].called; + de_ctx->profile_prefilter_ctx->data[i].total += det_ctx->prefilter_perf_data[i].total; + if (det_ctx->prefilter_perf_data[i].max > de_ctx->profile_prefilter_ctx->data[i].max) + de_ctx->profile_prefilter_ctx->data[i].max = det_ctx->prefilter_perf_data[i].max; + de_ctx->profile_prefilter_ctx->data[i].total_bytes += + det_ctx->prefilter_perf_data[i].total_bytes; + if (det_ctx->prefilter_perf_data[i].max_bytes > + de_ctx->profile_prefilter_ctx->data[i].max_bytes) + de_ctx->profile_prefilter_ctx->data[i].max_bytes = + det_ctx->prefilter_perf_data[i].max_bytes; + de_ctx->profile_prefilter_ctx->data[i].bytes_called += + det_ctx->prefilter_perf_data[i].bytes_called; + } +} + +void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->prefilter_perf_data == NULL) + return; + + pthread_mutex_lock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m); + SCProfilingPrefilterThreadMerge(det_ctx->de_ctx, det_ctx); + pthread_mutex_unlock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m); + + SCFree(det_ctx->prefilter_perf_data); + det_ctx->prefilter_perf_data = NULL; +} + +/** + * \brief Register the prefilter profiling counters. + * + * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. + */ +void SCProfilingPrefilterInitCounters(DetectEngineCtx *de_ctx) +{ + if (profiling_prefilter_enabled == 0) + return; + + const uint32_t size = de_ctx->prefilter_id; + if (size == 0) + return; + + de_ctx->profile_prefilter_ctx = SCProfilingPrefilterInitCtx(); + BUG_ON(de_ctx->profile_prefilter_ctx == NULL); + de_ctx->profile_prefilter_ctx->size = size; + + de_ctx->profile_prefilter_ctx->data = SCCalloc(1, sizeof(SCProfilePrefilterData) * size); + BUG_ON(de_ctx->profile_prefilter_ctx->data == NULL); + + HashListTableBucket *hb = HashListTableGetListHead(de_ctx->prefilter_hash_table); + for (; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterStore *ctx = HashListTableGetListData(hb); + de_ctx->profile_prefilter_ctx->data[ctx->id].name = ctx->name; + SCLogDebug("prefilter %s set up", de_ctx->profile_prefilter_ctx->data[ctx->id].name); + } + SCLogDebug("size alloc'd %u", (uint32_t)size * (uint32_t)sizeof(SCProfilePrefilterData)); + + SCLogPerf("Registered %" PRIu32 " prefilter profiling counters.", size); +} + +#endif /* PROFILING */ diff --git a/src/util/profiling-rulegroups.c b/src/util/profiling-rulegroups.c new file mode 100644 index 000000000000..e63280229d91 --- /dev/null +++ b/src/util/profiling-rulegroups.c @@ -0,0 +1,383 @@ +/* Copyright (C) 2007-2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited. + * \author Victor Julien + * + * An API for rule profiling operations. + */ + +#include "suricata-common.h" +#include "util/profiling.h" + +#ifdef PROFILING +#include "util/conf.h" +#include "util/time.h" + +/** + * Extra data for rule profiling. + */ +typedef struct SCProfileSghData_ { + uint64_t checks; + + uint64_t non_mpm_generic; + uint64_t non_mpm_syn; + + uint64_t post_prefilter_sigs_total; + uint64_t post_prefilter_sigs_max; + + uint64_t mpm_match_cnt_total; + uint64_t mpm_match_cnt_max; + +} SCProfileSghData; + +typedef struct SCProfileSghDetectCtx_ { + uint32_t cnt; + SCProfileSghData *data; + pthread_mutex_t data_m; +} SCProfileSghDetectCtx; + +static int profiling_sghs_output_to_file = 0; +int profiling_sghs_enabled = 0; +static char profiling_file_name[PATH_MAX]; +static const char *profiling_file_mode = "a"; +static int profiling_rulegroup_json = 0; + +void SCProfilingSghsGlobalInit(void) +{ + ConfNode *conf; + + conf = ConfGetNode("profiling.rulegroups"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + profiling_sghs_enabled = 1; + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + const char *log_dir; + log_dir = ConfigGetLogDirectory(); + + snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", log_dir, + filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_file_mode = "a"; + } else { + profiling_file_mode = "w"; + } + + profiling_sghs_output_to_file = 1; + } + if (ConfNodeChildValueIsTrue(conf, "json")) { + profiling_rulegroup_json = 1; + } + } + } +} + +static void DoDumpJSON(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + char timebuf[64]; + uint32_t i; + struct timeval tval; + + json_t *js = json_object(); + if (js == NULL) + return; + json_t *jsa = json_array(); + if (jsa == NULL) { + json_decref(js); + return; + } + + gettimeofday(&tval, NULL); + CreateIsoTimeString(SCTIME_FROM_TIMEVAL(&tval), timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + + for (i = 0; i < rules_ctx->cnt; i++) { + SCProfileSghData *d = &rules_ctx->data[i]; + if (d == NULL || d->checks == 0) + continue; + + double avgsigs = 0; + double avgmpms = 0; + + if (d->post_prefilter_sigs_total && d->checks) { + avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); + } + if (d->mpm_match_cnt_total && d->checks) { + avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); + } + + json_t *jsm = json_object(); + if (jsm) { + json_object_set_new(jsm, "id", json_integer(i)); + json_object_set_new(jsm, "checks", json_integer(d->checks)); + json_object_set_new(jsm, "non_mpm_generic", json_integer(d->non_mpm_generic)); + json_object_set_new(jsm, "non_mpm_syn", json_integer(d->non_mpm_syn)); + json_object_set_new(jsm, "avgmpms", json_real(avgmpms)); + json_object_set_new(jsm, "mpm_match_cnt_max", json_integer(d->mpm_match_cnt_max)); + json_object_set_new(jsm, "avgsigs", json_real(avgsigs)); + json_object_set_new( + jsm, "post_prefilter_sigs_max", json_integer(d->post_prefilter_sigs_max)); + json_array_append_new(jsa, jsm); + } + } + json_object_set_new(js, "rule_groups", jsa); + + char *js_s = json_dumps( + js, JSON_PRESERVE_ORDER | JSON_COMPACT | JSON_ENSURE_ASCII | JSON_ESCAPE_SLASH); + if (likely(js_s != NULL)) { + fprintf(fp, "%s", js_s); + free(js_s); + } + json_decref(js); +} + +static void DoDump(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + uint32_t i; + struct timeval tval; + struct tm *tms; + struct tm local_tm; + + gettimeofday(&tval, NULL); + tms = SCLocalTime(tval.tv_sec, &local_tm); + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, + " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d\n", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, + tms->tm_sec); + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Stats for: %s %u\n", name, rules_ctx->cnt); + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-16s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Sgh", "Checks", + "Non-MPM(gen)", "Non-Mpm(syn)", "MPM Matches", "MPM Match Max", "Post-Filter", + "Post-Filter Max"); + fprintf(fp, " ---------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "\n"); + for (i = 0; i < rules_ctx->cnt; i++) { + SCProfileSghData *d = &rules_ctx->data[i]; + if (d == NULL || d->checks == 0) + continue; + + double avgsigs = 0; + double avgmpms = 0; + + if (d->post_prefilter_sigs_total && d->checks) { + avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); + } + if (d->mpm_match_cnt_total && d->checks) { + avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); + } + + fprintf(fp, + " %-16u %-15" PRIu64 " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15" PRIu64 + " %-15.2f %-15" PRIu64 "\n", + i, d->checks, d->non_mpm_generic, d->non_mpm_syn, avgmpms, d->mpm_match_cnt_max, + avgsigs, d->post_prefilter_sigs_max); + } + fprintf(fp, "\n"); +} + +static void SCProfilingSghDump(DetectEngineCtx *de_ctx) +{ + FILE *fp; + + if (profiling_sghs_enabled == 0) + return; + + if (profiling_sghs_output_to_file == 1) { + SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); + + fp = fopen(profiling_file_name, profiling_file_mode); + + if (fp == NULL) { + SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); + return; + } + } else { + fp = stdout; + } + + if (profiling_rulegroup_json) { + DoDumpJSON(de_ctx->profile_sgh_ctx, fp, "rule groups"); + } else { + DoDump(de_ctx->profile_sgh_ctx, fp, "rule groups"); + } + + if (fp != stdout) + fclose(fp); + + SCLogPerf("Done dumping rulegroup profiling data."); +} + +/** + * \brief Update a rule counter. + * + * \param id The ID of this counter. + * \param ticks Number of CPU ticks for this rule. + * \param match Did the rule match? + */ +void SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh) +{ + if (det_ctx != NULL && det_ctx->sgh_perf_data != NULL && + sgh->id < det_ctx->de_ctx->sgh_array_cnt) { + SCProfileSghData *p = &det_ctx->sgh_perf_data[sgh->id]; + p->checks++; + + if (det_ctx->non_pf_store_cnt > 0) { + if (det_ctx->non_pf_store_ptr == sgh->non_pf_syn_store_array) + p->non_mpm_syn++; + else + p->non_mpm_generic++; + } + p->post_prefilter_sigs_total += det_ctx->match_array_cnt; + if (det_ctx->match_array_cnt > p->post_prefilter_sigs_max) + p->post_prefilter_sigs_max = det_ctx->match_array_cnt; + p->mpm_match_cnt_total += det_ctx->pmq.rule_id_array_cnt; + if (det_ctx->pmq.rule_id_array_cnt > p->mpm_match_cnt_max) + p->mpm_match_cnt_max = det_ctx->pmq.rule_id_array_cnt; + } +} + +static SCProfileSghDetectCtx *SCProfilingSghInitCtx(void) +{ + SCProfileSghDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileSghDetectCtx)); + if (ctx != NULL) { + if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { + FatalError("Failed to initialize mutex."); + } + } + + return ctx; +} + +static void DetroyCtx(SCProfileSghDetectCtx *ctx) +{ + if (ctx) { + if (ctx->data != NULL) + SCFree(ctx->data); + pthread_mutex_destroy(&ctx->data_m); + SCFree(ctx); + } +} + +void SCProfilingSghDestroyCtx(DetectEngineCtx *de_ctx) +{ + if (de_ctx != NULL) { + SCProfilingSghDump(de_ctx); + + DetroyCtx(de_ctx->profile_sgh_ctx); + } +} + +void SCProfilingSghThreadSetup(SCProfileSghDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) +{ + if (ctx == NULL) + return; + + uint32_t array_size = det_ctx->de_ctx->sgh_array_cnt; + + SCProfileSghData *a = SCCalloc(array_size, sizeof(SCProfileSghData)); + if (a != NULL) { + det_ctx->sgh_perf_data = a; + } +} + +static void SCProfilingSghThreadMerge(DetectEngineCtx *de_ctx, const DetectEngineThreadCtx *det_ctx) +{ + if (de_ctx == NULL || de_ctx->profile_sgh_ctx == NULL || + de_ctx->profile_sgh_ctx->data == NULL || det_ctx == NULL || + det_ctx->sgh_perf_data == NULL) + return; + +#define ADD(name) de_ctx->profile_sgh_ctx->data[i].name += det_ctx->sgh_perf_data[i].name + uint32_t i; + for (i = 0; i < de_ctx->sgh_array_cnt; i++) { + ADD(checks); + ADD(non_mpm_generic); + ADD(non_mpm_syn); + ADD(post_prefilter_sigs_total); + ADD(mpm_match_cnt_total); + + if (det_ctx->sgh_perf_data[i].mpm_match_cnt_max > + de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max) + de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max = + det_ctx->sgh_perf_data[i].mpm_match_cnt_max; + if (det_ctx->sgh_perf_data[i].post_prefilter_sigs_max > + de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max) + de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max = + det_ctx->sgh_perf_data[i].post_prefilter_sigs_max; + } +#undef ADD +} + +void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->sgh_perf_data == NULL) + return; + + pthread_mutex_lock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); + SCProfilingSghThreadMerge(det_ctx->de_ctx, det_ctx); + pthread_mutex_unlock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); + + SCFree(det_ctx->sgh_perf_data); + det_ctx->sgh_perf_data = NULL; +} + +/** + * \brief Register the keyword profiling counters. + * + * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. + */ +void SCProfilingSghInitCounters(DetectEngineCtx *de_ctx) +{ + if (profiling_sghs_enabled == 0) + return; + + de_ctx->profile_sgh_ctx = SCProfilingSghInitCtx(); + BUG_ON(de_ctx->profile_sgh_ctx == NULL); + + de_ctx->profile_sgh_ctx->data = SCCalloc(de_ctx->sgh_array_cnt, sizeof(SCProfileSghData)); + BUG_ON(de_ctx->profile_sgh_ctx->data == NULL); + + de_ctx->profile_sgh_ctx->cnt = de_ctx->sgh_array_cnt; + + SCLogPerf("Registered %" PRIu32 " rulegroup profiling counters.", de_ctx->sgh_array_cnt); +} + +#endif /* PROFILING */ diff --git a/src/util/profiling-rules.c b/src/util/profiling-rules.c new file mode 100644 index 000000000000..0fdad230dd00 --- /dev/null +++ b/src/util/profiling-rules.c @@ -0,0 +1,657 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited. + * \author Victor Julien + * + * An API for rule profiling operations. + */ + +#include "suricata-common.h" +#include "util/profiling.h" + +#include "util/byte.h" +#include "util/conf.h" +#include "util/time.h" + +#ifdef PROFILE_RULES + +/** + * Used for generating the summary data to print. + */ +typedef struct SCProfileSummary_ { + uint32_t sid; + uint32_t gid; + uint32_t rev; + uint64_t ticks; + double avgticks; + double avgticks_match; + double avgticks_no_match; + uint64_t checks; + uint64_t matches; + uint64_t max; + uint64_t ticks_match; + uint64_t ticks_no_match; +} SCProfileSummary; + +extern int profiling_output_to_file; +int profiling_rules_enabled = 0; +static char profiling_file_name[PATH_MAX] = ""; +static const char *profiling_file_mode = "a"; +static int profiling_rule_json = 0; + +/** + * Sort orders for dumping profiled rules. + */ +enum { + SC_PROFILING_RULES_SORT_BY_TICKS = 0, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS, + SC_PROFILING_RULES_SORT_BY_CHECKS, + SC_PROFILING_RULES_SORT_BY_MATCHES, + SC_PROFILING_RULES_SORT_BY_MAX_TICKS, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, +}; + +static int profiling_rules_sort_orders[8] = { SC_PROFILING_RULES_SORT_BY_TICKS, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS, SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, SC_PROFILING_RULES_SORT_BY_CHECKS, + SC_PROFILING_RULES_SORT_BY_MATCHES, SC_PROFILING_RULES_SORT_BY_MAX_TICKS, -1 }; + +/** + * Maximum number of rules to dump. + */ +static uint32_t profiling_rules_limit = UINT32_MAX; + +void SCProfilingRulesGlobalInit(void) +{ +#define SET_ONE(x) \ + { \ + profiling_rules_sort_orders[0] = (x); \ + profiling_rules_sort_orders[1] = -1; \ + } + + ConfNode *conf; + const char *val; + + conf = ConfGetNode("profiling.rules"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + profiling_rules_enabled = 1; + + val = ConfNodeLookupChildValue(conf, "sort"); + if (val != NULL) { + if (strcmp(val, "ticks") == 0) { + SET_ONE(SC_PROFILING_RULES_SORT_BY_TICKS); + } else if (strcmp(val, "avgticks") == 0) { + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS); + } else if (strcmp(val, "avgticks_match") == 0) { + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH); + } else if (strcmp(val, "avgticks_no_match") == 0) { + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH); + } else if (strcmp(val, "checks") == 0) { + SET_ONE(SC_PROFILING_RULES_SORT_BY_CHECKS); + } else if (strcmp(val, "matches") == 0) { + SET_ONE(SC_PROFILING_RULES_SORT_BY_MATCHES); + } else if (strcmp(val, "maxticks") == 0) { + SET_ONE(SC_PROFILING_RULES_SORT_BY_MAX_TICKS); + } else { + SCLogError("Invalid profiling sort order: %s", val); + exit(EXIT_FAILURE); + } + } + + val = ConfNodeLookupChildValue(conf, "limit"); + if (val != NULL) { + if (StringParseUint32(&profiling_rules_limit, 10, (uint16_t)strlen(val), val) <= + 0) { + SCLogError("Invalid limit: %s", val); + exit(EXIT_FAILURE); + } + } + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + + const char *log_dir; + log_dir = ConfigGetLogDirectory(); + + snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", log_dir, + filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_file_mode = "a"; + } else { + profiling_file_mode = "w"; + } + + profiling_output_to_file = 1; + } + if (ConfNodeChildValueIsTrue(conf, "json")) { + profiling_rule_json = 1; + } + } + } +#undef SET_ONE +} + +/** + * \brief Qsort comparison function to sort by ticks. + */ +static int SCProfileSummarySortByTicks(const void *a, const void *b) +{ + const SCProfileSummary *s0 = a; + const SCProfileSummary *s1 = b; + if (s1->ticks == s0->ticks) + return 0; + else + return s0->ticks > s1->ticks ? -1 : 1; +} + +/** + * \brief Qsort comparison function to sort by average ticks per match. + */ +static int SCProfileSummarySortByAvgTicksMatch(const void *a, const void *b) +{ + const SCProfileSummary *s0 = a; + const SCProfileSummary *s1 = b; + if (s1->avgticks_match == s0->avgticks_match) + return 0; + else + return s0->avgticks_match > s1->avgticks_match ? -1 : 1; +} + +/** + * \brief Qsort comparison function to sort by average ticks per non match. + */ +static int SCProfileSummarySortByAvgTicksNoMatch(const void *a, const void *b) +{ + const SCProfileSummary *s0 = a; + const SCProfileSummary *s1 = b; + if (s1->avgticks_no_match == s0->avgticks_no_match) + return 0; + else + return s0->avgticks_no_match > s1->avgticks_no_match ? -1 : 1; +} + +/** + * \brief Qsort comparison function to sort by average ticks. + */ +static int SCProfileSummarySortByAvgTicks(const void *a, const void *b) +{ + const SCProfileSummary *s0 = a; + const SCProfileSummary *s1 = b; + if (s1->avgticks == s0->avgticks) + return 0; + else + return s0->avgticks > s1->avgticks ? -1 : 1; +} + +/** + * \brief Qsort comparison function to sort by checks. + */ +static int SCProfileSummarySortByChecks(const void *a, const void *b) +{ + const SCProfileSummary *s0 = a; + const SCProfileSummary *s1 = b; + if (s1->checks == s0->checks) + return 0; + else + return s0->checks > s1->checks ? -1 : 1; +} + +/** + * \brief Qsort comparison function to sort by matches. + */ +static int SCProfileSummarySortByMatches(const void *a, const void *b) +{ + const SCProfileSummary *s0 = a; + const SCProfileSummary *s1 = b; + if (s1->matches == s0->matches) + return 0; + else + return s0->matches > s1->matches ? -1 : 1; +} + +/** + * \brief Qsort comparison function to sort by max ticks. + */ +static int SCProfileSummarySortByMaxTicks(const void *a, const void *b) +{ + const SCProfileSummary *s0 = a; + const SCProfileSummary *s1 = b; + if (s1->max == s0->max) + return 0; + else + return s0->max > s1->max ? -1 : 1; +} + +static json_t *BuildJson( + SCProfileSummary *summary, uint32_t count, uint64_t total_ticks, const char *sort_desc) +{ + + char timebuf[64]; + uint32_t i; + struct timeval tval; + + json_t *js = json_object(); + if (js == NULL) + return js; + json_t *jsa = json_array(); + if (jsa == NULL) { + json_decref(js); + return js; + } + + gettimeofday(&tval, NULL); + CreateIsoTimeString(SCTIME_FROM_TIMEVAL(&tval), timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + json_object_set_new(js, "sort", json_string(sort_desc)); + + for (i = 0; i < MIN(count, profiling_rules_limit); i++) { + /* Stop dumping when we hit our first rule with 0 checks. Due + * to sorting this will be the beginning of all the rules with + * 0 checks. */ + if (summary[i].checks == 0) + break; + + json_t *jsm = json_object(); + if (jsm) { + json_object_set_new(jsm, "signature_id", json_integer(summary[i].sid)); + json_object_set_new(jsm, "gid", json_integer(summary[i].gid)); + json_object_set_new(jsm, "rev", json_integer(summary[i].rev)); + + json_object_set_new(jsm, "checks", json_integer(summary[i].checks)); + json_object_set_new(jsm, "matches", json_integer(summary[i].matches)); + + json_object_set_new(jsm, "ticks_total", json_integer(summary[i].ticks)); + json_object_set_new(jsm, "ticks_max", json_integer(summary[i].max)); + json_object_set_new(jsm, "ticks_avg", json_integer(summary[i].avgticks)); + json_object_set_new(jsm, "ticks_avg_match", json_integer(summary[i].avgticks_match)); + json_object_set_new( + jsm, "ticks_avg_nomatch", json_integer(summary[i].avgticks_no_match)); + + double percent = (long double)summary[i].ticks / (long double)total_ticks * 100; + json_object_set_new(jsm, "percent", json_integer(percent)); + json_array_append_new(jsa, jsm); + } + } + json_object_set_new(js, "rules", jsa); + return js; +} + +static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks, + const char *sort_desc) +{ + json_t *js = BuildJson(summary, count, total_ticks, sort_desc); + if (unlikely(js == NULL)) + return; + char *js_s = json_dumps( + js, JSON_PRESERVE_ORDER | JSON_COMPACT | JSON_ENSURE_ASCII | JSON_ESCAPE_SLASH); + + if (unlikely(js_s == NULL)) + return; + fprintf(fp, "%s\n", js_s); + free(js_s); + json_decref(js); +} + +static void DumpText(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks, + const char *sort_desc) +{ + uint32_t i; + struct timeval tval; + struct tm *tms; + gettimeofday(&tval, NULL); + struct tm local_tm; + tms = SCLocalTime(tval.tv_sec, &local_tm); + + fprintf(fp, " ----------------------------------------------" + "----------------------------\n"); + fprintf(fp, + " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d.", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, + tms->tm_sec); + fprintf(fp, " Sorted by: %s.\n", sort_desc); + fprintf(fp, " ----------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", + "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", + "Avg Match", "Avg No Match"); + fprintf(fp, " -------- " + "------------ " + "-------- " + "-------- " + "------------ " + "------ " + "-------- " + "-------- " + "----------- " + "----------- " + "----------- " + "-------------- " + "\n"); + for (i = 0; i < MIN(count, profiling_rules_limit); i++) { + + /* Stop dumping when we hit our first rule with 0 checks. Due + * to sorting this will be the beginning of all the rules with + * 0 checks. */ + if (summary[i].checks == 0) + break; + + double percent = (long double)summary[i].ticks / (long double)total_ticks * 100; + fprintf(fp, + " %-8" PRIu32 " %-12u %-8" PRIu32 " %-8" PRIu32 " %-12" PRIu64 " %-6.2f %-8" PRIu64 + " %-8" PRIu64 " %-11" PRIu64 " %-11.2f %-11.2f %-11.2f\n", + i + 1, summary[i].sid, summary[i].gid, summary[i].rev, summary[i].ticks, percent, + summary[i].checks, summary[i].matches, summary[i].max, summary[i].avgticks, + summary[i].avgticks_match, summary[i].avgticks_no_match); + } + + fprintf(fp, "\n"); +} + +/** + * \brief Dump rule profiling information to file + * + * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. + */ +static void *SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx, int file_output) +{ + uint32_t i; + FILE *fp = NULL; + + if (rules_ctx == NULL) + return NULL; + + if (file_output != 0) { + if (profiling_output_to_file == 1) { + fp = fopen(profiling_file_name, profiling_file_mode); + + if (fp == NULL) { + SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno)); + return NULL; + } + } else { + fp = stdout; + } + } + + int summary_size = sizeof(SCProfileSummary) * rules_ctx->size; + SCProfileSummary *summary = SCMalloc(summary_size); + if (unlikely(summary == NULL)) { + SCLogError("Error allocating memory for profiling summary"); + return NULL; + } + + uint32_t count = rules_ctx->size; + uint64_t total_ticks = 0; + + SCLogPerf("Dumping profiling data for %u rules.", count); + + memset(summary, 0, summary_size); + for (i = 0; i < count; i++) { + summary[i].sid = rules_ctx->data[i].sid; + summary[i].rev = rules_ctx->data[i].rev; + summary[i].gid = rules_ctx->data[i].gid; + + summary[i].ticks = rules_ctx->data[i].ticks_match + rules_ctx->data[i].ticks_no_match; + summary[i].checks = rules_ctx->data[i].checks; + + if (summary[i].checks > 0) { + summary[i].avgticks = (long double)summary[i].ticks / (long double)summary[i].checks; + } + + summary[i].matches = rules_ctx->data[i].matches; + summary[i].max = rules_ctx->data[i].max; + summary[i].ticks_match = rules_ctx->data[i].ticks_match; + summary[i].ticks_no_match = rules_ctx->data[i].ticks_no_match; + if (summary[i].ticks_match > 0) { + summary[i].avgticks_match = + (long double)summary[i].ticks_match / (long double)summary[i].matches; + } + + if (summary[i].ticks_no_match > 0) { + summary[i].avgticks_no_match = + (long double)summary[i].ticks_no_match / + ((long double)summary[i].checks - (long double)summary[i].matches); + } + total_ticks += summary[i].ticks; + } + + int *order = profiling_rules_sort_orders; + while (*order != -1) { + const char *sort_desc = NULL; + switch (*order) { + case SC_PROFILING_RULES_SORT_BY_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByTicks); + sort_desc = "ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByAvgTicks); + sort_desc = "average ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_CHECKS: + qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByChecks); + sort_desc = "number of checks"; + break; + case SC_PROFILING_RULES_SORT_BY_MATCHES: + qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByMatches); + sort_desc = "number of matches"; + break; + case SC_PROFILING_RULES_SORT_BY_MAX_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), SCProfileSummarySortByMaxTicks); + sort_desc = "max ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicksMatch); + sort_desc = "average ticks (match)"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicksNoMatch); + sort_desc = "average ticks (no match)"; + break; + } + if (profiling_rule_json) { + if (file_output != 1) { + json_t *js = BuildJson(summary, count, total_ticks, sort_desc); + SCFree(summary); + return js; + } else { + DumpJson(fp, summary, count, total_ticks, sort_desc); + } + } else { + DumpText(fp, summary, count, total_ticks, sort_desc); + } + order++; + } + + if (file_output != 0) { + if (fp != stdout) + fclose(fp); + } + SCFree(summary); + SCLogPerf("Done dumping profiling data."); + return NULL; +} + +/** + * \brief Register a rule profiling counter. + * + * \retval Returns the ID of the counter on success, 0 on failure. + */ +static uint16_t SCProfilingRegisterRuleCounter(SCProfileDetectCtx *ctx) +{ + ctx->size++; + return ctx->id++; +} + +/** + * \brief Update a rule counter. + * + * \param id The ID of this counter. + * \param ticks Number of CPU ticks for this rule. + * \param match Did the rule match? + */ +void SCProfilingRuleUpdateCounter( + DetectEngineThreadCtx *det_ctx, uint16_t id, uint64_t ticks, int match) +{ + if (det_ctx != NULL && det_ctx->rule_perf_data != NULL && det_ctx->rule_perf_data_size > id) { + SCProfileData *p = &det_ctx->rule_perf_data[id]; + + p->checks++; + p->matches += match; + if (ticks > p->max) + p->max = ticks; + if (match == 1) + p->ticks_match += ticks; + else + p->ticks_no_match += ticks; + } +} + +static SCProfileDetectCtx *SCProfilingRuleInitCtx(void) +{ + SCProfileDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileDetectCtx)); + if (ctx != NULL) { + if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { + FatalError("Failed to initialize hash table mutex."); + } + } + + return ctx; +} + +void SCProfilingRuleDestroyCtx(SCProfileDetectCtx *ctx) +{ + if (ctx != NULL) { + SCProfilingRuleDump(ctx, 1); + if (ctx->data != NULL) + SCFree(ctx->data); + pthread_mutex_destroy(&ctx->data_m); + SCFree(ctx); + } +} + +void SCProfilingRuleThreadSetup(SCProfileDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) +{ + if (ctx == NULL || ctx->size == 0) + return; + + SCProfileData *a = SCCalloc(ctx->size, sizeof(SCProfileData)); + if (a != NULL) { + det_ctx->rule_perf_data = a; + det_ctx->rule_perf_data_size = ctx->size; + } +} + +static void SCProfilingRuleThreadMerge( + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, bool reset) +{ + if (de_ctx == NULL || de_ctx->profile_ctx == NULL || de_ctx->profile_ctx->data == NULL || + det_ctx == NULL || det_ctx->rule_perf_data == NULL) + return; + + for (int i = 0; i < det_ctx->rule_perf_data_size; i++) { + de_ctx->profile_ctx->data[i].checks += det_ctx->rule_perf_data[i].checks; + de_ctx->profile_ctx->data[i].matches += det_ctx->rule_perf_data[i].matches; + de_ctx->profile_ctx->data[i].ticks_match += det_ctx->rule_perf_data[i].ticks_match; + de_ctx->profile_ctx->data[i].ticks_no_match += det_ctx->rule_perf_data[i].ticks_no_match; + if (reset) { + det_ctx->rule_perf_data[i].checks = 0; + det_ctx->rule_perf_data[i].matches = 0; + det_ctx->rule_perf_data[i].ticks_match = 0; + det_ctx->rule_perf_data[i].ticks_no_match = 0; + } + if (det_ctx->rule_perf_data[i].max > de_ctx->profile_ctx->data[i].max) + de_ctx->profile_ctx->data[i].max = det_ctx->rule_perf_data[i].max; + } +} + +void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->rule_perf_data == NULL) + return; + + pthread_mutex_lock(&det_ctx->de_ctx->profile_ctx->data_m); + SCProfilingRuleThreadMerge(det_ctx->de_ctx, det_ctx, false); + pthread_mutex_unlock(&det_ctx->de_ctx->profile_ctx->data_m); + + SCFree(det_ctx->rule_perf_data); + det_ctx->rule_perf_data = NULL; + det_ctx->rule_perf_data_size = 0; +} + +void SCProfilingRuleThreatAggregate(DetectEngineThreadCtx *det_ctx) +{ + + if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->de_ctx->profile_ctx == NULL) + return; + pthread_mutex_lock(&det_ctx->de_ctx->profile_ctx->data_m); + SCProfilingRuleThreadMerge(det_ctx->de_ctx, det_ctx, true); + pthread_mutex_unlock(&det_ctx->de_ctx->profile_ctx->data_m); +} + +/** + * \brief Register the rule profiling counters. + * + * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. + */ +void SCProfilingRuleInitCounters(DetectEngineCtx *de_ctx) +{ + if (profiling_rules_enabled == 0) + return; + + de_ctx->profile_ctx = SCProfilingRuleInitCtx(); + BUG_ON(de_ctx->profile_ctx == NULL); + + Signature *sig = de_ctx->sig_list; + uint32_t count = 0; + while (sig != NULL) { + sig->profiling_id = SCProfilingRegisterRuleCounter(de_ctx->profile_ctx); + sig = sig->next; + count++; + } + + if (count > 0) { + de_ctx->profile_ctx->data = SCCalloc(de_ctx->profile_ctx->size, sizeof(SCProfileData)); + BUG_ON(de_ctx->profile_ctx->data == NULL); + + sig = de_ctx->sig_list; + while (sig != NULL) { + de_ctx->profile_ctx->data[sig->profiling_id].sid = sig->id; + de_ctx->profile_ctx->data[sig->profiling_id].gid = sig->gid; + de_ctx->profile_ctx->data[sig->profiling_id].rev = sig->rev; + sig = sig->next; + } + } + + SCLogPerf("Registered %" PRIu32 " rule profiling counters.", count); +} + +json_t *SCProfileRuleTriggerDump(DetectEngineCtx *de_ctx) +{ + return SCProfilingRuleDump(de_ctx->profile_ctx, 0); +} + +#endif /* PROFILING */ diff --git a/src/util/profiling.c b/src/util/profiling.c new file mode 100644 index 000000000000..a28ff6f499ab --- /dev/null +++ b/src/util/profiling.c @@ -0,0 +1,1506 @@ +/* Copyright (C) 2007-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited. + * \author Victor Julien + * + * An API for profiling operations. + * + * Really just a wrapper around the existing perf counters. + */ + +#include "suricata-common.h" +#include "util/profiling.h" + +#ifdef PROFILING +#include "tm-threads.h" +#include "../conf.h" +#include "util/unittest.h" +#include "util/byte.h" +#include "util/profiling-locks.h" +#include "util/conf.h" + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define DEFAULT_LOG_FILENAME "profile.log" +#define DEFAULT_LOG_MODE_APPEND "yes" + +static pthread_mutex_t packet_profile_lock; +static FILE *packet_profile_csv_fp = NULL; + +extern int profiling_locks_enabled; +extern int profiling_locks_output_to_file; +extern char *profiling_locks_file_name; +extern const char *profiling_locks_file_mode; + +typedef struct SCProfilePacketData_ { + uint64_t min; + uint64_t max; + uint64_t tot; + uint64_t cnt; +#ifdef PROFILE_LOCKING + uint64_t lock; + uint64_t ticks; + uint64_t contention; + + uint64_t slock; + uint64_t sticks; + uint64_t scontention; +#endif +} SCProfilePacketData; +SCProfilePacketData packet_profile_data4[257]; /**< all proto's + tunnel */ +SCProfilePacketData packet_profile_data6[257]; /**< all proto's + tunnel */ + +/* each module, each proto */ +SCProfilePacketData packet_profile_tmm_data4[TMM_SIZE][257]; +SCProfilePacketData packet_profile_tmm_data6[TMM_SIZE][257]; + +SCProfilePacketData packet_profile_app_data4[TMM_SIZE][257]; +SCProfilePacketData packet_profile_app_data6[TMM_SIZE][257]; + +SCProfilePacketData packet_profile_app_pd_data4[257]; +SCProfilePacketData packet_profile_app_pd_data6[257]; + +SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]; +SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]; + +SCProfilePacketData packet_profile_log_data4[LOGGER_SIZE][256]; +SCProfilePacketData packet_profile_log_data6[LOGGER_SIZE][256]; + +struct ProfileProtoRecords { + SCProfilePacketData records4[257]; + SCProfilePacketData records6[257]; +}; + +struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]; + +int profiling_packets_enabled = 0; +int profiling_output_to_file = 0; + +static int profiling_packets_csv_enabled = 0; +static int profiling_packets_output_to_file = 0; +static char *profiling_file_name; +static char profiling_packets_file_name[PATH_MAX]; +static char *profiling_csv_file_name; +static const char *profiling_packets_file_mode = "a"; + +static int rate = 1; +static SC_ATOMIC_DECLARE(uint64_t, samples); + +/** + * Used as a check so we don't double enter a profiling run. + */ +thread_local int profiling_rules_entered = 0; + +void SCProfilingDumpPacketStats(void); +const char *PacketProfileDetectIdToString(PacketProfileDetectId id); +const char *PacketProfileLoggerIdToString(LoggerId id); +static void PrintCSVHeader(void); + +static void FormatNumber(uint64_t num, char *str, size_t size) +{ + if (num < 1000UL) + snprintf(str, size, "%" PRIu64, num); + else if (num < 1000000UL) + snprintf(str, size, "%3.1fk", (float)num / 1000UL); + else if (num < 1000000000UL) + snprintf(str, size, "%3.1fm", (float)num / 1000000UL); + else + snprintf(str, size, "%3.1fb", (float)num / 1000000000UL); +} + +/** + * \brief Initialize profiling. + */ +void SCProfilingInit(void) +{ + ConfNode *conf; + + SC_ATOMIC_INIT(samples); + + intmax_t rate_v = 0; + (void)ConfGetInt("profiling.sample-rate", &rate_v); + if (rate_v > 0 && rate_v < INT_MAX) { + rate = (int)rate_v; + if (rate != 1) + SCLogInfo("profiling runs for every %dth packet", rate); + else + SCLogInfo("profiling runs for every packet"); + } + + conf = ConfGetNode("profiling.packets"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + profiling_packets_enabled = 1; + + if (pthread_mutex_init(&packet_profile_lock, NULL) != 0) { + FatalError("Failed to initialize packet profiling mutex."); + } + memset(&packet_profile_data4, 0, sizeof(packet_profile_data4)); + 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)); + 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)); + memset(&packet_profile_detect_data6, 0, sizeof(packet_profile_detect_data6)); + memset(&packet_profile_log_data4, 0, sizeof(packet_profile_log_data4)); + memset(&packet_profile_log_data6, 0, sizeof(packet_profile_log_data6)); + memset(&packet_profile_flowworker_data, 0, sizeof(packet_profile_flowworker_data)); + + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + const char *log_dir; + log_dir = ConfigGetLogDirectory(); + + snprintf(profiling_packets_file_name, sizeof(profiling_packets_file_name), "%s/%s", + log_dir, filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_packets_file_mode = "a"; + } else { + profiling_packets_file_mode = "w"; + } + + profiling_packets_output_to_file = 1; + } + } + + conf = ConfGetNode("profiling.packets.csv"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename == NULL) { + filename = "packet_profile.csv"; + } + + const char *log_dir = ConfigGetLogDirectory(); + + profiling_csv_file_name = SCMalloc(PATH_MAX); + if (unlikely(profiling_csv_file_name == NULL)) { + FatalError("out of memory"); + } + snprintf(profiling_csv_file_name, PATH_MAX, "%s/%s", log_dir, filename); + + packet_profile_csv_fp = fopen(profiling_csv_file_name, "w"); + if (packet_profile_csv_fp == NULL) { + SCFree(profiling_csv_file_name); + profiling_csv_file_name = NULL; + return; + } + + PrintCSVHeader(); + + profiling_packets_csv_enabled = 1; + } + } + } + + conf = ConfGetNode("profiling.locks"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { +#ifndef PROFILE_LOCKING + SCLogWarning( + "lock profiling not compiled in. Add --enable-profiling-locks to configure."); +#else + profiling_locks_enabled = 1; + + LockRecordInitHash(); + + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + const char *log_dir = ConfigGetLogDirectory(); + + profiling_locks_file_name = SCMalloc(PATH_MAX); + if (unlikely(profiling_locks_file_name == NULL)) { + FatalError("can't duplicate file name"); + } + + snprintf(profiling_locks_file_name, PATH_MAX, "%s/%s", log_dir, filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_locks_file_mode = "a"; + } else { + profiling_locks_file_mode = "w"; + } + + profiling_locks_output_to_file = 1; + } +#endif + } + } +} + +/** + * \brief Free resources used by profiling. + */ +void SCProfilingDestroy(void) +{ + if (profiling_packets_enabled) { + pthread_mutex_destroy(&packet_profile_lock); + } + + if (profiling_packets_csv_enabled) { + if (packet_profile_csv_fp != NULL) + fclose(packet_profile_csv_fp); + packet_profile_csv_fp = NULL; + } + + if (profiling_csv_file_name != NULL) + SCFree(profiling_csv_file_name); + profiling_csv_file_name = NULL; + + if (profiling_file_name != NULL) + SCFree(profiling_file_name); + profiling_file_name = NULL; + +#ifdef PROFILE_LOCKING + LockRecordFreeHash(); +#endif +} + +void SCProfilingDump(void) +{ + SCProfilingDumpPacketStats(); + SCLogPerf("Done dumping profiling data."); +} + +static void DumpFlowWorkerIP(FILE *fp, int ipv, uint64_t total) +{ + char totalstr[256]; + + enum ProfileFlowWorkerId fwi; + for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = ipv == 4 ? &r->records4[p] : &r->records6[p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-20s IPv%d %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %-6.2f\n", + ProfileFlowWorkerIdToString(fwi), ipv, p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } +} + +static void DumpFlowWorker(FILE *fp) +{ + uint64_t total = 0; + + enum ProfileFlowWorkerId fwi; + for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &r->records4[p]; + total += pd->tot; + pd = &r->records6[p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", "Flow Worker", "IP ver", + "Proto", "cnt", "min", "max", "avg"); + fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", "--------------------", + "------", "-----", "----------", "------------", "------------", "-----------"); + DumpFlowWorkerIP(fp, 4, total); + DumpFlowWorkerIP(fp, 6, total); + fprintf(fp, "Note: %s includes app-layer for TCP\n", + ProfileFlowWorkerIdToString(PROFILE_FLOWWORKER_STREAM)); +} + +void SCProfilingDumpPacketStats(void) +{ + FILE *fp; + char totalstr[256]; + uint64_t total; + + if (profiling_packets_enabled == 0) + return; + + if (profiling_packets_output_to_file == 1) { + fp = fopen(profiling_packets_file_name, profiling_packets_file_mode); + + if (fp == NULL) { + SCLogError("failed to open %s: %s", profiling_packets_file_name, strerror(errno)); + return; + } + } else { + fp = stdout; + } + + fprintf(fp, "\n\nPacket profile dump:\n"); + + fprintf(fp, "\n%-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s\n", "IP ver", "Proto", + "cnt", "min", "max", "avg", "tot", "%%"); + fprintf(fp, "%-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s\n", "------", "-----", + "----------", "------------", "------------", "-----------", "-----------", "---"); + total = 0; + for (int i = 0; i < 257; i++) { + SCProfilePacketData *pd = &packet_profile_data4[i]; + total += pd->tot; + pd = &packet_profile_data6[i]; + total += pd->tot; + } + + for (int i = 0; i < 257; i++) { + SCProfilePacketData *pd = &packet_profile_data4[i]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + " IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12s %6.2f\n", + i, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + + for (int i = 0; i < 257; i++) { + SCProfilePacketData *pd = &packet_profile_data6[i]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + " IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12s %6.2f\n", + i, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + fprintf(fp, "Note: Protocol 256 tracks pseudo/tunnel packets.\n"); + + fprintf(fp, "\nPer Thread module stats:\n"); + + fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", + "Thread Module", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%"); +#ifdef PROFILE_LOCKING + fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", "locks", + "ticks", "cont.", "cont.avg", "slocks", "sticks", "scont.", "scont.avg"); +#else + fprintf(fp, "\n"); +#endif + fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", + "------------------------", "------", "-----", "----------", "------------", + "------------", "-----------", "-----------", "---"); +#ifdef PROFILE_LOCKING + fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", "--------", + "--------", "----------", "-----------", "--------", "--------", "------------", + "-----------"); +#else + fprintf(fp, "\n"); +#endif + total = 0; + for (int m = 0; m < TMM_SIZE; m++) { + if (tmm_modules[m].flags & TM_FLAG_LOGAPI_TM) + continue; + + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; + total += pd->tot; + + pd = &packet_profile_tmm_data6[m][p]; + total += pd->tot; + } + } + + for (int m = 0; m < TMM_SIZE; m++) { + if (tmm_modules[m].flags & TM_FLAG_LOGAPI_TM) + continue; + + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %6.2f", + TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); +#ifdef PROFILE_LOCKING + fprintf(fp, + " %10.2f %12" PRIu64 " %12" PRIu64 " %10.2f %10.2f %12" PRIu64 + " %12" PRIu64 " %10.2f\n", + (float)pd->lock / pd->cnt, (uint64_t)pd->ticks / pd->cnt, pd->contention, + (float)pd->contention / pd->cnt, (float)pd->slock / pd->cnt, + (uint64_t)pd->sticks / pd->cnt, pd->scontention, + (float)pd->scontention / pd->cnt); +#else + fprintf(fp, "\n"); +#endif + } + } + + for (int m = 0; m < TMM_SIZE; m++) { + if (tmm_modules[m].flags & TM_FLAG_LOGAPI_TM) + continue; + + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_tmm_data6[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %6.2f\n", + TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + + DumpFlowWorker(fp); + + fprintf(fp, "\nPer App layer parser stats:\n"); + + fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", "App Layer", "IP ver", + "Proto", "cnt", "min", "max", "avg"); + fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", "--------------------", + "------", "-----", "----------", "------------", "------------", "-----------"); + + total = 0; + for (AppProto a = 0; a < ALPROTO_MAX; a++) { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_app_data4[a][p]; + total += pd->tot; + + pd = &packet_profile_app_data6[a][p]; + total += pd->tot; + } + } + for (AppProto a = 0; a < ALPROTO_MAX; a++) { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_app_data4[a][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-20s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %-6.2f\n", + AppProtoToString(a), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + + for (AppProto a = 0; a < ALPROTO_MAX; a++) { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_app_data6[a][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-20s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %-6.2f\n", + AppProtoToString(a), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + + /* proto detect output */ + { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_app_pd_data4[p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + fprintf(fp, + "%-20s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s\n", + "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), + totalstr); + } + + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_app_pd_data6[p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + fprintf(fp, + "%-20s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s\n", + "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), + totalstr); + } + } + + total = 0; + for (int m = 0; m < PROF_DETECT_SIZE; m++) { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_detect_data4[m][p]; + total += pd->tot; + + pd = &packet_profile_detect_data6[m][p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", + "Log Thread Module", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%"); +#ifdef PROFILE_LOCKING + fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", "locks", + "ticks", "cont.", "cont.avg", "slocks", "sticks", "scont.", "scont.avg"); +#else + fprintf(fp, "\n"); +#endif + fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s", + "------------------------", "------", "-----", "----------", "------------", + "------------", "-----------", "-----------", "---"); +#ifdef PROFILE_LOCKING + fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n", "--------", + "--------", "----------", "-----------", "--------", "--------", "------------", + "-----------"); +#else + fprintf(fp, "\n"); +#endif + total = 0; + for (int m = 0; m < TMM_SIZE; m++) { + if (!(tmm_modules[m].flags & TM_FLAG_LOGAPI_TM)) + continue; + + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; + total += pd->tot; + + pd = &packet_profile_tmm_data6[m][p]; + total += pd->tot; + } + } + + for (int m = 0; m < TMM_SIZE; m++) { + if (!(tmm_modules[m].flags & TM_FLAG_LOGAPI_TM)) + continue; + + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_tmm_data4[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %6.2f", + TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); +#ifdef PROFILE_LOCKING + fprintf(fp, + " %10.2f %12" PRIu64 " %12" PRIu64 " %10.2f %10.2f %12" PRIu64 + " %12" PRIu64 " %10.2f\n", + (float)pd->lock / pd->cnt, (uint64_t)pd->ticks / pd->cnt, pd->contention, + (float)pd->contention / pd->cnt, (float)pd->slock / pd->cnt, + (uint64_t)pd->sticks / pd->cnt, pd->scontention, + (float)pd->scontention / pd->cnt); +#else + fprintf(fp, "\n"); +#endif + } + } + + for (int m = 0; m < TMM_SIZE; m++) { + if (!(tmm_modules[m].flags & TM_FLAG_LOGAPI_TM)) + continue; + + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_tmm_data6[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %6.2f\n", + TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + + fprintf(fp, "\nLogger/output stats:\n"); + + total = 0; + for (int m = 0; m < LOGGER_SIZE; m++) { + for (int p = 0; p < 256; p++) { + SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; + total += pd->tot; + pd = &packet_profile_log_data6[m][p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", "Logger", + "IP ver", "Proto", "cnt", "min", "max", "avg", "tot"); + fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", + "------------------------", "------", "-----", "----------", "------------", + "------------", "-----------", "-----------"); + for (int m = 0; m < LOGGER_SIZE; m++) { + for (int p = 0; p < 256; p++) { + SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %-6.2f\n", + PacketProfileLoggerIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + for (int m = 0; m < LOGGER_SIZE; m++) { + for (int p = 0; p < 256; p++) { + SCProfilePacketData *pd = &packet_profile_log_data6[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %-6.2f\n", + PacketProfileLoggerIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + + fprintf(fp, "\nGeneral detection engine stats:\n"); + + total = 0; + for (int m = 0; m < PROF_DETECT_SIZE; m++) { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_detect_data4[m][p]; + total += pd->tot; + pd = &packet_profile_detect_data6[m][p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", + "Detection phase", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot"); + fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", + "------------------------", "------", "-----", "----------", "------------", + "------------", "-----------", "-----------"); + for (int m = 0; m < PROF_DETECT_SIZE; m++) { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_detect_data4[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %-6.2f\n", + PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + for (int m = 0; m < PROF_DETECT_SIZE; m++) { + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_detect_data6[m][p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / (long double)total * 100; + + fprintf(fp, + "%-24s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " %12" PRIu64 " %12s %-6.2f\n", + PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, + (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + fclose(fp); +} + +static void PrintCSVHeader(void) +{ + fprintf(packet_profile_csv_fp, "pcap_cnt,total,receive,decode,flowworker,"); + fprintf(packet_profile_csv_fp, "threading,"); + fprintf(packet_profile_csv_fp, "proto detect,"); + + for (enum ProfileFlowWorkerId fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + fprintf(packet_profile_csv_fp, "%s,", ProfileFlowWorkerIdToString(fwi)); + } + fprintf(packet_profile_csv_fp, "loggers,"); + + /* detect stages */ + for (int i = 0; i < PROF_DETECT_SIZE; i++) { + fprintf(packet_profile_csv_fp, "%s,", PacketProfileDetectIdToString(i)); + } + + /* individual loggers */ + for (LoggerId i = 0; i < LOGGER_SIZE; i++) { + fprintf(packet_profile_csv_fp, "%s,", PacketProfileLoggerIdToString(i)); + } + + fprintf(packet_profile_csv_fp, "\n"); +} + +void SCProfilingPrintPacketProfile(Packet *p) +{ + if (profiling_packets_csv_enabled == 0 || p == NULL || packet_profile_csv_fp == NULL || + p->profile == NULL) { + return; + } + + uint64_t tmm_total = 0; + uint64_t receive = 0; + uint64_t decode = 0; + + /* total cost from acquisition to return to packetpool */ + uint64_t delta = p->profile->ticks_end - p->profile->ticks_start; + fprintf(packet_profile_csv_fp, "%" PRIu64 ",%" PRIu64 ",", p->pcap_cnt, delta); + + for (int i = 0; i < TMM_SIZE; i++) { + const PktProfilingTmmData *pdt = &p->profile->tmm[i]; + uint64_t tmm_delta = pdt->ticks_end - pdt->ticks_start; + + if (tmm_modules[i].flags & TM_FLAG_RECEIVE_TM) { + if (tmm_delta) { + receive = tmm_delta; + } + continue; + + } else if (tmm_modules[i].flags & TM_FLAG_DECODE_TM) { + if (tmm_delta) { + decode = tmm_delta; + } + continue; + } + + tmm_total += tmm_delta; + } + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", receive); + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", decode); + PktProfilingTmmData *fw_pdt = &p->profile->tmm[TMM_FLOWWORKER]; + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", fw_pdt->ticks_end - fw_pdt->ticks_start); + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", delta - tmm_total); + + /* count ticks for app layer */ + uint64_t app_total = 0; + for (AppProto i = 1; i < ALPROTO_FAILED; i++) { + const PktProfilingAppData *pdt = &p->profile->app[i]; + + if (p->proto == IPPROTO_TCP) { + app_total += pdt->ticks_spent; + } + } + + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", p->profile->proto_detect); + + /* print flowworker steps */ + for (enum ProfileFlowWorkerId fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + const PktProfilingData *pd = &p->profile->flowworker[fwi]; + uint64_t ticks_spent = pd->ticks_end - pd->ticks_start; + if (fwi == PROFILE_FLOWWORKER_STREAM) { + ticks_spent -= app_total; + } else if (fwi == PROFILE_FLOWWORKER_APPLAYERUDP && app_total) { + ticks_spent = app_total; + } + + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", ticks_spent); + } + + /* count loggers cost and print as a single cost */ + uint64_t loggers = 0; + for (LoggerId i = 0; i < LOGGER_SIZE; i++) { + const PktProfilingLoggerData *pd = &p->profile->logger[i]; + loggers += pd->ticks_spent; + } + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", loggers); + + /* detect steps */ + for (int i = 0; i < PROF_DETECT_SIZE; i++) { + const PktProfilingDetectData *pdt = &p->profile->detect[i]; + + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", pdt->ticks_spent); + } + + /* print individual loggers */ + for (LoggerId i = 0; i < LOGGER_SIZE; i++) { + const PktProfilingLoggerData *pd = &p->profile->logger[i]; + fprintf(packet_profile_csv_fp, "%" PRIu64 ",", pd->ticks_spent); + } + + fprintf(packet_profile_csv_fp, "\n"); +} + +static void SCProfilingUpdatePacketDetectRecord( + PacketProfileDetectId id, uint8_t ipproto, PktProfilingDetectData *pdt, int ipver) +{ + if (pdt == NULL) { + return; + } + + SCProfilePacketData *pd; + if (ipver == 4) + pd = &packet_profile_detect_data4[id][ipproto]; + else + pd = &packet_profile_detect_data6[id][ipproto]; + + if (pd->min == 0 || pdt->ticks_spent < pd->min) { + pd->min = pdt->ticks_spent; + } + if (pd->max < pdt->ticks_spent) { + pd->max = pdt->ticks_spent; + } + + pd->tot += pdt->ticks_spent; + pd->cnt++; +} + +static void SCProfilingUpdatePacketDetectRecords(Packet *p) +{ + PacketProfileDetectId i; + for (i = 0; i < PROF_DETECT_SIZE; i++) { + PktProfilingDetectData *pdt = &p->profile->detect[i]; + + if (pdt->ticks_spent > 0) { + if (PKT_IS_IPV4(p)) { + SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 4); + } else { + SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 6); + } + } + } +} + +static void SCProfilingUpdatePacketAppPdRecord(uint8_t ipproto, uint32_t ticks_spent, int ipver) +{ + SCProfilePacketData *pd; + if (ipver == 4) + pd = &packet_profile_app_pd_data4[ipproto]; + else + pd = &packet_profile_app_pd_data6[ipproto]; + + if (pd->min == 0 || ticks_spent < pd->min) { + pd->min = ticks_spent; + } + if (pd->max < ticks_spent) { + pd->max = ticks_spent; + } + + pd->tot += ticks_spent; + pd->cnt++; +} + +static void SCProfilingUpdatePacketAppRecord( + int alproto, uint8_t ipproto, PktProfilingAppData *pdt, int ipver) +{ + if (pdt == NULL) { + return; + } + + SCProfilePacketData *pd; + if (ipver == 4) + pd = &packet_profile_app_data4[alproto][ipproto]; + else + pd = &packet_profile_app_data6[alproto][ipproto]; + + if (pd->min == 0 || pdt->ticks_spent < pd->min) { + pd->min = pdt->ticks_spent; + } + if (pd->max < pdt->ticks_spent) { + pd->max = pdt->ticks_spent; + } + + pd->tot += pdt->ticks_spent; + pd->cnt++; +} + +static void SCProfilingUpdatePacketAppRecords(Packet *p) +{ + int i; + for (i = 0; i < ALPROTO_MAX; i++) { + PktProfilingAppData *pdt = &p->profile->app[i]; + + if (pdt->ticks_spent > 0) { + if (PKT_IS_IPV4(p)) { + SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 4); + } else { + SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 6); + } + } + } + + if (p->profile->proto_detect > 0) { + if (PKT_IS_IPV4(p)) { + SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 4); + } else { + SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 6); + } + } +} + +static void SCProfilingUpdatePacketTmmRecord( + int module, uint8_t proto, PktProfilingTmmData *pdt, int ipver) +{ + if (pdt == NULL) { + return; + } + + SCProfilePacketData *pd; + if (ipver == 4) + pd = &packet_profile_tmm_data4[module][proto]; + else + pd = &packet_profile_tmm_data6[module][proto]; + + uint32_t delta = (uint32_t)pdt->ticks_end - pdt->ticks_start; + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += (uint64_t)delta; + pd->cnt++; + +#ifdef PROFILE_LOCKING + pd->lock += pdt->mutex_lock_cnt; + pd->ticks += pdt->mutex_lock_wait_ticks; + pd->contention += pdt->mutex_lock_contention; + pd->slock += pdt->spin_lock_cnt; + pd->sticks += pdt->spin_lock_wait_ticks; + pd->scontention += pdt->spin_lock_contention; +#endif +} + +static void SCProfilingUpdatePacketTmmRecords(Packet *p) +{ + int i; + for (i = 0; i < TMM_SIZE; i++) { + PktProfilingTmmData *pdt = &p->profile->tmm[i]; + + if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) { + continue; + } + + if (PKT_IS_IPV4(p)) { + SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 4); + } else { + SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 6); + } + } +} + +static inline void SCProfilingUpdatePacketGenericRecord( + PktProfilingData *pdt, SCProfilePacketData *pd) +{ + if (pdt == NULL || pd == NULL) { + return; + } + + uint64_t delta = pdt->ticks_end - pdt->ticks_start; + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += delta; + pd->cnt++; +} + +static void SCProfilingUpdatePacketGenericRecords( + Packet *p, PktProfilingData *pd, struct ProfileProtoRecords *records, int size) +{ + int i; + for (i = 0; i < size; i++) { + PktProfilingData *pdt = &pd[i]; + + if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) { + continue; + } + + struct ProfileProtoRecords *r = &records[i]; + SCProfilePacketData *store = NULL; + + if (PKT_IS_IPV4(p)) { + store = &(r->records4[p->proto]); + } else { + store = &(r->records6[p->proto]); + } + + SCProfilingUpdatePacketGenericRecord(pdt, store); + } +} + +static void SCProfilingUpdatePacketLogRecord( + LoggerId id, uint8_t ipproto, PktProfilingLoggerData *pdt, int ipver) +{ + if (pdt == NULL) { + return; + } + + SCProfilePacketData *pd; + if (ipver == 4) + pd = &packet_profile_log_data4[id][ipproto]; + else + pd = &packet_profile_log_data6[id][ipproto]; + + if (pd->min == 0 || pdt->ticks_spent < pd->min) { + pd->min = pdt->ticks_spent; + } + if (pd->max < pdt->ticks_spent) { + pd->max = pdt->ticks_spent; + } + + pd->tot += pdt->ticks_spent; + pd->cnt++; +} + +static void SCProfilingUpdatePacketLogRecords(Packet *p) +{ + for (LoggerId i = 0; i < LOGGER_SIZE; i++) { + PktProfilingLoggerData *pdt = &p->profile->logger[i]; + + if (pdt->ticks_spent > 0) { + if (PKT_IS_IPV4(p)) { + SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 4); + } else { + SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 6); + } + } + } +} + +void SCProfilingAddPacket(Packet *p) +{ + if (p == NULL || p->profile == NULL || p->profile->ticks_start == 0 || + p->profile->ticks_end == 0 || p->profile->ticks_start > p->profile->ticks_end) + return; + + pthread_mutex_lock(&packet_profile_lock); + { + + if (PKT_IS_IPV4(p)) { + SCProfilePacketData *pd = &packet_profile_data4[p->proto]; + + uint64_t delta = p->profile->ticks_end - p->profile->ticks_start; + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += delta; + pd->cnt++; + + if (IS_TUNNEL_PKT(p)) { + pd = &packet_profile_data4[256]; + + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += delta; + pd->cnt++; + } + + SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, + packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); + + SCProfilingUpdatePacketTmmRecords(p); + SCProfilingUpdatePacketAppRecords(p); + SCProfilingUpdatePacketDetectRecords(p); + SCProfilingUpdatePacketLogRecords(p); + + } else if (PKT_IS_IPV6(p)) { + SCProfilePacketData *pd = &packet_profile_data6[p->proto]; + + uint64_t delta = p->profile->ticks_end - p->profile->ticks_start; + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += delta; + pd->cnt++; + + if (IS_TUNNEL_PKT(p)) { + pd = &packet_profile_data6[256]; + + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += delta; + pd->cnt++; + } + + SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, + packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); + + SCProfilingUpdatePacketTmmRecords(p); + SCProfilingUpdatePacketAppRecords(p); + SCProfilingUpdatePacketDetectRecords(p); + SCProfilingUpdatePacketLogRecords(p); + } + + if (profiling_packets_csv_enabled) + SCProfilingPrintPacketProfile(p); + } + pthread_mutex_unlock(&packet_profile_lock); +} + +PktProfiling *SCProfilePacketStart(void) +{ + uint64_t sample = SC_ATOMIC_ADD(samples, 1); + if (sample % rate == 0) + return SCCalloc(1, sizeof(PktProfiling)); + else + return NULL; +} + +/* see if we want to profile rules for this packet */ +int SCProfileRuleStart(Packet *p) +{ +#ifdef PROFILE_LOCKING + if (p->profile != NULL) { + p->flags |= PKT_PROFILE; + return 1; + } +#else + uint64_t sample = SC_ATOMIC_ADD(samples, 1); + if (sample % rate == 0) { + p->flags |= PKT_PROFILE; + return 1; + } +#endif + if (p->flags & PKT_PROFILE) + return 1; + return 0; +} + +#define CASE_CODE(E) \ + case E: \ + return #E + +/** + * \brief Maps the PacketProfileDetectId, to its string equivalent + * + * \param id PacketProfileDetectId id + * + * \retval string equivalent for the PacketProfileDetectId id + */ +const char *PacketProfileDetectIdToString(PacketProfileDetectId id) +{ + switch (id) { + CASE_CODE(PROF_DETECT_SETUP); + CASE_CODE(PROF_DETECT_GETSGH); + CASE_CODE(PROF_DETECT_IPONLY); + CASE_CODE(PROF_DETECT_RULES); + CASE_CODE(PROF_DETECT_PF_PKT); + CASE_CODE(PROF_DETECT_PF_PAYLOAD); + CASE_CODE(PROF_DETECT_PF_TX); + CASE_CODE(PROF_DETECT_PF_RECORD); + CASE_CODE(PROF_DETECT_PF_SORT1); + CASE_CODE(PROF_DETECT_PF_SORT2); + CASE_CODE(PROF_DETECT_NONMPMLIST); + CASE_CODE(PROF_DETECT_TX); + CASE_CODE(PROF_DETECT_ALERT); + CASE_CODE(PROF_DETECT_TX_UPDATE); + CASE_CODE(PROF_DETECT_CLEANUP); + default: + return "UNKNOWN"; + } +} + +/** + * \brief Maps the LoggerId's to its string equivalent for profiling output. + * + * \param id LoggerId id + * + * \retval string equivalent for the LoggerId id + */ +const char *PacketProfileLoggerIdToString(LoggerId id) +{ + switch (id) { + CASE_CODE(LOGGER_UNDEFINED); + CASE_CODE(LOGGER_HTTP); + CASE_CODE(LOGGER_TLS_STORE); + CASE_CODE(LOGGER_TLS); + CASE_CODE(LOGGER_JSON_TX); + CASE_CODE(LOGGER_FILE); + CASE_CODE(LOGGER_FILEDATA); + CASE_CODE(LOGGER_ALERT_DEBUG); + CASE_CODE(LOGGER_ALERT_FAST); + CASE_CODE(LOGGER_ALERT_SYSLOG); + CASE_CODE(LOGGER_JSON_ALERT); + CASE_CODE(LOGGER_JSON_ANOMALY); + CASE_CODE(LOGGER_JSON_DROP); + CASE_CODE(LOGGER_FILE_STORE); + CASE_CODE(LOGGER_JSON_FILE); + CASE_CODE(LOGGER_TCP_DATA); + CASE_CODE(LOGGER_JSON_FLOW); + CASE_CODE(LOGGER_JSON_NETFLOW); + CASE_CODE(LOGGER_STATS); + CASE_CODE(LOGGER_JSON_STATS); + CASE_CODE(LOGGER_PCAP); + CASE_CODE(LOGGER_JSON_METADATA); + CASE_CODE(LOGGER_JSON_FRAME); + CASE_CODE(LOGGER_JSON_STREAM); + + case LOGGER_SIZE: + return "UNKNOWN"; + } + return "UNKNOWN"; +} + +#ifdef UNITTESTS + +static int ProfilingGenericTicksTest01(void) +{ +#define TEST_RUNS 1024 + uint64_t ticks_start = 0; + uint64_t ticks_end = 0; + void *ptr[TEST_RUNS]; + unsigned int i; + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + ptr[i] = SCMalloc(1024); + } + ticks_end = UtilCpuGetTicks(); + printf("malloc(1024) %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCFree(ptr[i]); + } + ticks_end = UtilCpuGetTicks(); + printf("SCFree(1024) %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + SCMutex m[TEST_RUNS]; + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCMutexInit(&m[i], NULL); + } + ticks_end = UtilCpuGetTicks(); + printf("SCMutexInit() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCMutexLock(&m[i]); + } + ticks_end = UtilCpuGetTicks(); + printf("SCMutexLock() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCMutexUnlock(&m[i]); + } + ticks_end = UtilCpuGetTicks(); + printf("SCMutexUnlock() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCMutexDestroy(&m[i]); + } + ticks_end = UtilCpuGetTicks(); + printf("SCMutexDestroy() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + SCSpinlock s[TEST_RUNS]; + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCSpinInit(&s[i], 0); + } + ticks_end = UtilCpuGetTicks(); + printf("SCSpinInit() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCSpinLock(&s[i]); + } + ticks_end = UtilCpuGetTicks(); + printf("SCSpinLock() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCSpinUnlock(&s[i]); + } + ticks_end = UtilCpuGetTicks(); + printf("SCSpinUnlock() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SCSpinDestroy(&s[i]); + } + ticks_end = UtilCpuGetTicks(); + printf("SCSpinDestroy() %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + SC_ATOMIC_DECL_AND_INIT(unsigned int, test); + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + (void)SC_ATOMIC_ADD(test, 1); + } + ticks_end = UtilCpuGetTicks(); + printf("SC_ATOMIC_ADD %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + + ticks_start = UtilCpuGetTicks(); + for (i = 0; i < TEST_RUNS; i++) { + SC_ATOMIC_CAS(&test, i, i + 1); + } + ticks_end = UtilCpuGetTicks(); + printf("SC_ATOMIC_CAS %" PRIu64 "\n", (ticks_end - ticks_start) / TEST_RUNS); + return 1; +} + +#endif /* UNITTESTS */ + +void SCProfilingRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01); +#endif /* UNITTESTS */ +} + +void SCProfileRuleStartCollection(void) +{ +} + +void SCProfileRuleStopCollection(void) +{ +} + +#elif PROFILE_RULES + +thread_local int profiling_rules_entered = 0; +int profiling_output_to_file = 0; +static SC_ATOMIC_DECLARE(uint64_t, samples); +static uint64_t rate = 0; +static SC_ATOMIC_DECLARE(bool, profiling_rules_active); + +/** + * \brief Initialize profiling. + */ +void SCProfilingInit(void) +{ + SC_ATOMIC_INIT(profiling_rules_active); + SC_ATOMIC_INIT(samples); + intmax_t rate_v = 0; + + (void)ConfGetInt("profiling.sample-rate", &rate_v); + if (rate_v > 0 && rate_v < INT_MAX) { + int literal_rate = (int)rate_v; + for (int i = literal_rate; i >= 1; i--) { + /* If i is a power of 2 */ + if ((i & (i - 1)) == 0) { + rate = i - 1; + break; + } + } + if (rate != 0) + SCLogInfo("profiling runs for every %luth packet", rate + 1); + else + SCLogInfo("profiling runs for every packet"); + } +} + +/* see if we want to profile rules for this packet */ +int SCProfileRuleStart(Packet *p) +{ + if (!SC_ATOMIC_GET(profiling_rules_active)) { + return 0; + } + uint64_t sample = SC_ATOMIC_ADD(samples, 1); + if ((sample & rate) == 0) { + p->flags |= PKT_PROFILE; + return 1; + } + + if (p->flags & PKT_PROFILE) + return 1; + return 0; +} + +void SCProfileRuleStartCollection(void) +{ + SC_ATOMIC_SET(profiling_rules_active, true); +} + +void SCProfileRuleStopCollection(void) +{ + SC_ATOMIC_SET(profiling_rules_active, false); +} + +#endif /* PROFILING */ diff --git a/src/util/profiling.h b/src/util/profiling.h new file mode 100644 index 000000000000..2c8f519062da --- /dev/null +++ b/src/util/profiling.h @@ -0,0 +1,446 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited. + * \author Victor Julien + */ + +#ifndef __UTIL_PROFILE_H__ +#define __UTIL_PROFILE_H__ + +#include "util/cpu.h" + +#include "../detect.h" + +#ifdef PROFILING + +#include "util/cpu.h" +#include "util/profiling-locks.h" + +extern int profiling_rules_enabled; +extern int profiling_packets_enabled; +extern int profiling_sghs_enabled; + +void SCProfilingPrintPacketProfile(Packet *); +void SCProfilingAddPacket(Packet *); +extern int profiling_keyword_enabled; +extern thread_local int profiling_keyword_entered; + +#define KEYWORD_PROFILING_SET_LIST(ctx, list) \ + { \ + (ctx)->keyword_perf_list = (list); \ + } + +#define KEYWORD_PROFILING_START \ + uint64_t profile_keyword_start_ = 0; \ + uint64_t profile_keyword_end_ = 0; \ + if (profiling_keyword_enabled) { \ + if (profiling_keyword_entered > 0) { \ + SCLogError("Re-entered profiling, exiting."); \ + abort(); \ + } \ + profiling_keyword_entered++; \ + profile_keyword_start_ = UtilCpuGetTicks(); \ + } + +/* we allow this macro to be called if profiling_keyword_entered == 0, + * so that we don't have to refactor some of the detection code. */ +#define KEYWORD_PROFILING_END(ctx, type, m) \ + if (profiling_keyword_enabled && profiling_keyword_entered) { \ + profile_keyword_end_ = UtilCpuGetTicks(); \ + SCProfilingKeywordUpdateCounter( \ + (ctx), (type), (profile_keyword_end_ - profile_keyword_start_), (m)); \ + profiling_keyword_entered--; \ + } + +PktProfiling *SCProfilePacketStart(void); + +#define PACKET_PROFILING_START(p) \ + if (profiling_packets_enabled) { \ + (p)->profile = SCProfilePacketStart(); \ + if ((p)->profile != NULL) \ + (p)->profile->ticks_start = UtilCpuGetTicks(); \ + } + +#define PACKET_PROFILING_RESTART(p) \ + if (profiling_packets_enabled) { \ + if ((p)->profile != NULL) \ + (p)->profile->ticks_start = UtilCpuGetTicks(); \ + } + +#define PACKET_PROFILING_END(p) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + (p)->profile->ticks_end = UtilCpuGetTicks(); \ + SCProfilingAddPacket((p)); \ + } + +#ifdef PROFILE_LOCKING +#define PACKET_PROFILING_RESET_LOCKS \ + do { \ + mutex_lock_cnt = 0; \ + mutex_lock_wait_ticks = 0; \ + mutex_lock_contention = 0; \ + spin_lock_cnt = 0; \ + spin_lock_wait_ticks = 0; \ + spin_lock_contention = 0; \ + rww_lock_cnt = 0; \ + rww_lock_wait_ticks = 0; \ + rww_lock_contention = 0; \ + rwr_lock_cnt = 0; \ + rwr_lock_wait_ticks = 0; \ + rwr_lock_contention = 0; \ + locks_idx = 0; \ + record_locks = 1; \ + } while (0) + +#define PACKET_PROFILING_COPY_LOCKS(p, id) \ + do { \ + (p)->profile->tmm[(id)].mutex_lock_cnt = mutex_lock_cnt; \ + (p)->profile->tmm[(id)].mutex_lock_wait_ticks = mutex_lock_wait_ticks; \ + (p)->profile->tmm[(id)].mutex_lock_contention = mutex_lock_contention; \ + (p)->profile->tmm[(id)].spin_lock_cnt = spin_lock_cnt; \ + (p)->profile->tmm[(id)].spin_lock_wait_ticks = spin_lock_wait_ticks; \ + (p)->profile->tmm[(id)].spin_lock_contention = spin_lock_contention; \ + (p)->profile->tmm[(id)].rww_lock_cnt = rww_lock_cnt; \ + (p)->profile->tmm[(id)].rww_lock_wait_ticks = rww_lock_wait_ticks; \ + (p)->profile->tmm[(id)].rww_lock_contention = rww_lock_contention; \ + (p)->profile->tmm[(id)].rwr_lock_cnt = rwr_lock_cnt; \ + (p)->profile->tmm[(id)].rwr_lock_wait_ticks = rwr_lock_wait_ticks; \ + (p)->profile->tmm[(id)].rwr_lock_contention = rwr_lock_contention; \ + record_locks = 0; \ + SCProfilingAddPacketLocks((p)); \ + } while (0) +#else +#define PACKET_PROFILING_RESET_LOCKS +#define PACKET_PROFILING_COPY_LOCKS(p, id) +#endif + +#define PACKET_PROFILING_TMM_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < TMM_SIZE) { \ + (p)->profile->tmm[(id)].ticks_start = UtilCpuGetTicks(); \ + PACKET_PROFILING_RESET_LOCKS; \ + } \ + } + +#define PACKET_PROFILING_TMM_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < TMM_SIZE) { \ + PACKET_PROFILING_COPY_LOCKS((p), (id)); \ + (p)->profile->tmm[(id)].ticks_end = UtilCpuGetTicks(); \ + } \ + } + +#define FLOWWORKER_PROFILING_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROFILE_FLOWWORKER_SIZE) { \ + (p)->profile->flowworker[(id)].ticks_start = UtilCpuGetTicks(); \ + } \ + } + +#define FLOWWORKER_PROFILING_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROFILE_FLOWWORKER_SIZE) { \ + (p)->profile->flowworker[(id)].ticks_end = UtilCpuGetTicks(); \ + } \ + } + +#define PACKET_PROFILING_RESET(p) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + SCFree((p)->profile); \ + (p)->profile = NULL; \ + } + +#define PACKET_PROFILING_APP_START(dp, id) \ + if (profiling_packets_enabled) { \ + (dp)->ticks_start = UtilCpuGetTicks(); \ + (dp)->alproto = (id); \ + } + +#define PACKET_PROFILING_APP_END(dp, id) \ + if (profiling_packets_enabled) { \ + BUG_ON((id) != (dp)->alproto); \ + (dp)->ticks_end = UtilCpuGetTicks(); \ + if ((dp)->ticks_start != 0 && (dp)->ticks_start < ((dp)->ticks_end)) { \ + (dp)->ticks_spent = ((dp)->ticks_end - (dp)->ticks_start); \ + } \ + } + +#define PACKET_PROFILING_APP_PD_START(dp) \ + if (profiling_packets_enabled) { \ + (dp)->proto_detect_ticks_start = UtilCpuGetTicks(); \ + } + +#define PACKET_PROFILING_APP_PD_END(dp) \ + if (profiling_packets_enabled) { \ + (dp)->proto_detect_ticks_end = UtilCpuGetTicks(); \ + if ((dp)->proto_detect_ticks_start != 0 && \ + (dp)->proto_detect_ticks_start < ((dp)->proto_detect_ticks_end)) { \ + (dp)->proto_detect_ticks_spent = \ + ((dp)->proto_detect_ticks_end - (dp)->proto_detect_ticks_start); \ + } \ + } + +#define PACKET_PROFILING_APP_RESET(dp) \ + if (profiling_packets_enabled) { \ + (dp)->ticks_start = 0; \ + (dp)->ticks_end = 0; \ + (dp)->ticks_spent = 0; \ + (dp)->alproto = 0; \ + (dp)->proto_detect_ticks_start = 0; \ + (dp)->proto_detect_ticks_end = 0; \ + (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_DETECT_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROF_DETECT_SIZE) { \ + (p)->profile->detect[(id)].ticks_start = UtilCpuGetTicks(); \ + } \ + } + +#define PACKET_PROFILING_DETECT_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROF_DETECT_SIZE) { \ + (p)->profile->detect[(id)].ticks_end = UtilCpuGetTicks(); \ + if ((p)->profile->detect[(id)].ticks_start != 0 && \ + (p)->profile->detect[(id)].ticks_start < \ + (p)->profile->detect[(id)].ticks_end) { \ + (p)->profile->detect[(id)].ticks_spent += \ + ((p)->profile->detect[(id)].ticks_end - \ + (p)->profile->detect[(id)].ticks_start); \ + } \ + } \ + } + +#define PACKET_PROFILING_LOGGER_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < LOGGER_SIZE) { \ + (p)->profile->logger[(id)].ticks_start = UtilCpuGetTicks(); \ + } \ + } + +#define PACKET_PROFILING_LOGGER_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < LOGGER_SIZE) { \ + (p)->profile->logger[(id)].ticks_end = UtilCpuGetTicks(); \ + if ((p)->profile->logger[(id)].ticks_start != 0 && \ + (p)->profile->logger[(id)].ticks_start < \ + (p)->profile->logger[(id)].ticks_end) { \ + (p)->profile->logger[(id)].ticks_spent += \ + ((p)->profile->logger[(id)].ticks_end - \ + (p)->profile->logger[(id)].ticks_start); \ + } \ + } \ + } + +#define SGH_PROFILING_RECORD(det_ctx, sgh) \ + if (profiling_sghs_enabled) { \ + SCProfilingSghUpdateCounter((det_ctx), (sgh)); \ + } + +extern int profiling_prefilter_enabled; +extern thread_local int profiling_prefilter_entered; + +#define PREFILTER_PROFILING_START(det_ctx) \ + (det_ctx)->prefilter_bytes = 0; \ + (det_ctx)->prefilter_bytes_called = 0; \ + uint64_t profile_prefilter_start_ = 0; \ + uint64_t profile_prefilter_end_ = 0; \ + if (profiling_prefilter_enabled) { \ + if (profiling_prefilter_entered > 0) { \ + SCLogError("Re-entered profiling, exiting."); \ + abort(); \ + } \ + profiling_prefilter_entered++; \ + profile_prefilter_start_ = UtilCpuGetTicks(); \ + } + +/* we allow this macro to be called if profiling_prefilter_entered == 0, + * so that we don't have to refactor some of the detection code. */ +#define PREFILTER_PROFILING_END(ctx, profile_id) \ + if (profiling_prefilter_enabled && profiling_prefilter_entered) { \ + profile_prefilter_end_ = UtilCpuGetTicks(); \ + if (profile_prefilter_end_ > profile_prefilter_start_) \ + SCProfilingPrefilterUpdateCounter((ctx), (profile_id), \ + (profile_prefilter_end_ - profile_prefilter_start_), (ctx)->prefilter_bytes, \ + (ctx)->prefilter_bytes_called); \ + profiling_prefilter_entered--; \ + } + +#define PREFILTER_PROFILING_ADD_BYTES(det_ctx, bytes) \ + (det_ctx)->prefilter_bytes += (bytes); \ + (det_ctx)->prefilter_bytes_called++ + +struct SCProfileDetectCtx_; +void SCProfilingRulesGlobalInit(void); +void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); +void SCProfilingRuleInitCounters(DetectEngineCtx *); +void SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *, uint16_t, uint64_t, int); +void SCProfilingRuleThreadSetup(struct SCProfileDetectCtx_ *, DetectEngineThreadCtx *); +void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *); + +void SCProfilingKeywordsGlobalInit(void); +void SCProfilingKeywordDestroyCtx(DetectEngineCtx *); // struct SCProfileKeywordDetectCtx_ *); +void SCProfilingKeywordInitCounters(DetectEngineCtx *); +void SCProfilingKeywordUpdateCounter( + DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, int match); +void SCProfilingKeywordThreadSetup(struct SCProfileKeywordDetectCtx_ *, DetectEngineThreadCtx *); +void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *); + +struct SCProfilePrefilterDetectCtx_; +void SCProfilingPrefilterGlobalInit(void); +void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *); +void SCProfilingPrefilterInitCounters(DetectEngineCtx *); +void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, + uint64_t bytes, uint64_t bytes_called); +void SCProfilingPrefilterThreadSetup( + struct SCProfilePrefilterDetectCtx_ *, DetectEngineThreadCtx *); +void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *); + +void SCProfilingSghsGlobalInit(void); +void SCProfilingSghDestroyCtx(DetectEngineCtx *); +void SCProfilingSghInitCounters(DetectEngineCtx *); +void SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh); +void SCProfilingSghThreadSetup(struct SCProfileSghDetectCtx_ *, DetectEngineThreadCtx *); +void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *); + +void SCProfilingInit(void); +void SCProfilingDestroy(void); +void SCProfilingRegisterTests(void); +void SCProfilingDump(void); + +#else + +#define KEYWORD_PROFILING_SET_LIST(a, b) +#define KEYWORD_PROFILING_START +#define KEYWORD_PROFILING_END(a, b, c) + +#define PACKET_PROFILING_START(p) +#define PACKET_PROFILING_RESTART(p) +#define PACKET_PROFILING_END(p) + +#define PACKET_PROFILING_TMM_START(p, id) +#define PACKET_PROFILING_TMM_END(p, id) + +#define PACKET_PROFILING_RESET(p) + +#define PACKET_PROFILING_APP_START(dp, id) +#define PACKET_PROFILING_APP_END(dp, id) +#define PACKET_PROFILING_APP_RESET(dp) +#define PACKET_PROFILING_APP_STORE(dp, p) + +#define PACKET_PROFILING_APP_PD_START(dp) +#define PACKET_PROFILING_APP_PD_END(dp) + +#define PACKET_PROFILING_DETECT_START(p, id) +#define PACKET_PROFILING_DETECT_END(p, id) + +#define PACKET_PROFILING_LOGGER_START(p, id) +#define PACKET_PROFILING_LOGGER_END(p, id) + +#define SGH_PROFILING_RECORD(det_ctx, sgh) + +#define FLOWWORKER_PROFILING_START(p, id) +#define FLOWWORKER_PROFILING_END(p, id) + +#define PREFILTER_PROFILING_START(ctx) +#define PREFILTER_PROFILING_END(ctx, profile_id) +#define PREFILTER_PROFILING_ADD_BYTES(det_ctx, bytes) + +#endif /* PROFILING */ + +#ifdef PROFILE_RULES + +extern int profiling_rules_enabled; +extern thread_local int profiling_rules_entered; + +#ifndef PROFILING +void SCProfilingInit(void); +#endif +/** + * Extra data for rule profiling. + */ +typedef struct SCProfileData_ { + uint32_t sid; + uint32_t gid; + uint32_t rev; + uint64_t checks; + uint64_t matches; + uint64_t max; + uint64_t ticks_match; + uint64_t ticks_no_match; +} SCProfileData; + +typedef struct SCProfileDetectCtx_ { + uint32_t size; + uint32_t id; + SCProfileData *data; + pthread_mutex_t data_m; +} SCProfileDetectCtx; + +void SCProfilingRulesGlobalInit(void); +void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); +void SCProfilingRuleInitCounters(DetectEngineCtx *); +void SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *, uint16_t, uint64_t, int); +void SCProfilingRuleThreadSetup(struct SCProfileDetectCtx_ *, DetectEngineThreadCtx *); +void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *); +int SCProfileRuleStart(Packet *p); +json_t *SCProfileRuleTriggerDump(DetectEngineCtx *de_ctx); +void SCProfileRuleStartCollection(void); +void SCProfileRuleStopCollection(void); +void SCProfilingRuleThreatAggregate(DetectEngineThreadCtx *det_ctx); + +#define RULE_PROFILING_START(p) \ + uint64_t profile_rule_start_ = 0; \ + uint64_t profile_rule_end_ = 0; \ + if (profiling_rules_enabled && SCProfileRuleStart((p))) { \ + if (profiling_rules_entered > 0) { \ + FatalError("Re-entered profiling, exiting."); \ + } \ + profiling_rules_entered++; \ + profile_rule_start_ = UtilCpuGetTicks(); \ + } + +#define RULE_PROFILING_END(ctx, r, m, p) \ + if (profiling_rules_enabled && ((p)->flags & PKT_PROFILE)) { \ + profile_rule_end_ = UtilCpuGetTicks(); \ + SCProfilingRuleUpdateCounter( \ + ctx, r->profiling_id, profile_rule_end_ - profile_rule_start_, m); \ + profiling_rules_entered--; \ + BUG_ON(profiling_rules_entered < 0); \ + } + +#else /* PROFILE_RULES */ + +#define RULE_PROFILING_START(p) +#define RULE_PROFILING_END(a, b, c, p) + +#endif /* PROFILE_RULES */ + +#endif /* ! __UTIL_PROFILE_H__ */ diff --git a/src/util/proto-name.c b/src/util/proto-name.c new file mode 100644 index 000000000000..10b84556034e --- /dev/null +++ b/src/util/proto-name.c @@ -0,0 +1,507 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + * + * File to provide the protocol names based on protocol numbers defined by the + * IANA + */ + +#include "suricata-common.h" +#include "util/hash-string.h" +#include "util/proto-name.h" +#include "util/debug.h" + +#ifdef UNITTESTS +#include "util/unittest.h" +#endif + +/** Lookup array to hold the information related to known protocol + * values + */ + +const char *known_proto[256] = { + "HOPOPT", /* 0x00: 0 - IPv6 Hop-by-Hop Option RFC 8200 */ + "ICMP", /* 0x01: 1 - Internet Control Message Protocol RFC 792 */ + "IGMP", /* 0x02: 2 - Internet Group Management Protocol RFC 1112 */ + "GGP", /* 0x03: 3 - Gateway-to-Gateway Protocol RFC 823 */ + "IP-in-IP", /* 0x04: 4 - IP in IP (encapsulation) RFC 2003 */ + "ST", /* 0x05: 5 - Internet Stream Protocol RFC 1190, RFC 1819 */ + "TCP", /* 0x06: 6 - Transmission Control Protocol RFC 793 */ + "CBT", /* 0x07: 7 - Core-based trees RFC 2189 */ + "EGP", /* 0x08: 8 - Exterior Gateway Protocol RFC 888 */ + "IGP", /* 0x09: 9 - Interior Gateway Protocol (any private interior gateway, for example Cisco's + IGRP) */ + "BBN-RCC-MON", /* 0x0A: 10 - BBN RCC Monitoring */ + "NVP-II", /* 0x0B: 11 - Network Voice Protocol RFC 741 */ + "PUP", /* 0x0C: 12 - Xerox PUP */ + "ARGUS", /* 0x0D: 13 - ARGUS */ + "EMCON", /* 0x0E: 14 - EMCON */ + "XNET", /* 0x0F: 15 - Cross Net Debugger IEN 158[2] */ + "CHAOS", /* 0x10: 16 - Chaos */ + "UDP", /* 0x11: 17 - User Datagram Protocol RFC 768 */ + "MUX", /* 0x12: 18 - Multiplexing IEN 90[3] */ + "DCN-MEAS", /* 0x13: 19 - DCN Measurement Subsystems */ + "HMP", /* 0x14: 20 - Host Monitoring Protocol RFC 869 */ + "PRM", /* 0x15: 21 - Packet Radio Measurement */ + "XNS-IDP", /* 0x16: 22 - XEROX NS IDP */ + "TRUNK-1", /* 0x17: 23 - Trunk-1 */ + "TRUNK-2", /* 0x18: 24 - Trunk-2 */ + "LEAF-1", /* 0x19: 25 - Leaf-1 */ + "LEAF-2", /* 0x1A: 26 - Leaf-2 */ + "RDP", /* 0x1B: 27 - Reliable Data Protocol RFC 908 */ + "IRTP", /* 0x1C: 28 - Internet Reliable Transaction Protocol RFC 938 */ + "ISO-TP4", /* 0x1D: 29 - ISO Transport Protocol Class 4 RFC 905 */ + "NETBLT", /* 0x1E: 30 - Bulk Data Transfer Protocol RFC 998 */ + "MFE-NSP", /* 0x1F: 31 - MFE Network Services Protocol */ + "MERIT-INP", /* 0x20: 32 - MERIT Internodal Protocol */ + "DCCP", /* 0x21: 33 - Datagram Congestion Control Protocol RFC 4340 */ + "3PC", /* 0x22: 34 - Third Party Connect Protocol */ + "IDPR", /* 0x23: 35 - Inter-Domain Policy Routing Protocol RFC 1479 */ + "XTP", /* 0x24: 36 - Xpress Transport Protocol */ + "DDP", /* 0x25: 37 - Datagram Delivery Protocol */ + "IDPR-CMTP", /* 0x26: 38 - IDPR Control Message Transport Protocol */ + "TP++", /* 0x27: 39 - TP++ Transport Protocol */ + "IL", /* 0x28: 40 - IL Transport Protocol */ + "IPv6", /* 0x29: 41 - IPv6 Encapsulation RFC 2473 */ + "SDRP", /* 0x2A: 42 - Source Demand Routing Protocol RFC 1940 */ + "IPv6-Route", /* 0x2B: 43 - Routing Header for IPv6 RFC 8200 */ + "IPv6-Frag", /* 0x2C: 44 - Fragment Header for IPv6 RFC 8200 */ + "IDRP", /* 0x2D: 45 - Inter-Domain Routing Protocol */ + "RSVP", /* 0x2E: 46 - Resource Reservation Protocol RFC 2205 */ + "GRE", /* 0x2F: 47 - Generic Routing Encapsulation RFC 2784, RFC 2890 */ + "DSR", /* 0x30: 48 - Dynamic Source Routing Protocol RFC 4728 */ + "BNA", /* 0x31: 49 - Burroughs Network Architecture */ + "ESP", /* 0x32: 50 - Encapsulating Security Payload RFC 4303 */ + "AH", /* 0x33: 51 - Authentication Header RFC 4302 */ + "I-NLSP", /* 0x34: 52 - Integrated Net Layer Security Protocol TUBA */ + "SwIPe", /* 0x35: 53 - SwIPe RFC 5237 */ + "NARP", /* 0x36: 54 - NBMA Address Resolution Protocol RFC 1735 */ + "MOBILE", /* 0x37: 55 - IP Mobility (Min Encap) RFC 2004 */ + "TLSP", /* 0x38: 56 - Transport Layer Security Protocol (using Kryptonet key management) */ + "SKIP", /* 0x39: 57 - Simple Key-Management for Internet Protocol RFC 2356 */ + "IPv6-ICMP", /* 0x3A: 58 - ICMP for IPv6 RFC 4443, RFC 4884 */ + "IPv6-NoNxt", /* 0x3B: 59 - No Next Header for IPv6 RFC 8200 */ + "IPv6-Opts", /* 0x3C: 60 - Destination Options for IPv6 RFC 8200 */ + "Any", /* 0x3D: 61 - host internal protocol */ + "CFTP", /* 0x3E: 62 - CFTP */ + "Any", /* 0x3F: 63 - local network */ + "SAT-EXPAK", /* 0x40: 64 - SATNET and Backroom EXPAK */ + "KRYPTOLAN", /* 0x41: 65 - Kryptolan */ + "RVD", /* 0x42: 66 - MIT Remote Virtual Disk Protocol */ + "IPPC", /* 0x43: 67 - Internet Pluribus Packet Core */ + "Any", /* 0x44: 68 - distributed file system */ + "SAT-MON", /* 0x45: 69 - SATNET Monitoring */ + "VISA", /* 0x46: 70 - VISA Protocol */ + "IPCU", /* 0x47: 71 - Internet Packet Core Utility */ + "CPNX", /* 0x48: 72 - Computer Protocol Network Executive */ + "CPHB", /* 0x49: 73 - Computer Protocol Heart Beat */ + "WSN", /* 0x4A: 74 - Wang Span Network */ + "PVP", /* 0x4B: 75 - Packet Video Protocol */ + "BR-SAT-MON", /* 0x4C: 76 - Backroom SATNET Monitoring */ + "SUN-ND", /* 0x4D: 77 - SUN ND PROTOCOL-Temporary */ + "WB-MON", /* 0x4E: 78 - WIDEBAND Monitoring */ + "WB-EXPAK", /* 0x4F: 79 - WIDEBAND EXPAK */ + "ISO-IP", /* 0x50: 80 - International Organization for Standardization Internet Protocol */ + "VMTP", /* 0x51: 81 - Versatile Message Transaction Protocol RFC 1045 */ + "SECURE-VMTP", /* 0x52: 82 - Secure Versatile Message Transaction Protocol RFC 1045 */ + "VINES", /* 0x53: 83 - VINES */ + "TTP", /* 0x54: 84 - TTP */ + "NSFNET-IGP", /* 0x55: 85 - NSFNET-IGP */ + "DGP", /* 0x56: 86 - Dissimilar Gateway Protocol */ + "TCF", /* 0x57: 87 - TCF */ + "EIGRP", /* 0x58: 88 - EIGRP Informational RFC 7868 */ + "OSPF", /* 0x59: 89 - Open Shortest Path First RFC 2328 */ + "Sprite-RPC", /* 0x5A: 90 - Sprite RPC Protocol */ + "LARP", /* 0x5B: 91 - Locus Address Resolution Protocol */ + "MTP", /* 0x5C: 92 - Multicast Transport Protocol */ + "AX.25", /* 0x5D: 93 - AX.25 */ + "OS", /* 0x5E: 94 - KA9Q NOS compatible IP over IP tunneling */ + "MICP", /* 0x5F: 95 - Mobile Internetworking Control Protocol */ + "SCC-SP", /* 0x60: 96 - Semaphore Communications Sec. Pro */ + "ETHERIP", /* 0x61: 97 - Ethernet-within-IP Encapsulation RFC 3378 */ + "ENCAP", /* 0x62: 98 - Encapsulation Header RFC 1241 */ + "Any", /* 0x63: 99 - private encryption scheme */ + "GMTP", /* 0x64: 100 - GMTP */ + "IFMP", /* 0x65: 101 - Ipsilon Flow Management Protocol */ + "PNNI", /* 0x66: 102 - PNNI over IP */ + "PIM", /* 0x67: 103 - Protocol Independent Multicast */ + "ARIS", /* 0x68: 104 - IBM's ARIS (Aggregate Route IP Switching) Protocol */ + "SCPS", /* 0x69: 105 - SCPS (Space Communications Protocol Standards) SCPS-TP[4] */ + "QNX", /* 0x6A: 106 - QNX */ + "A/N", /* 0x6B: 107 - Active Networks */ + "IPComp", /* 0x6C: 108 - IP Payload Compression Protocol RFC 3173 */ + "SNP", /* 0x6D: 109 - Sitara Networks Protocol */ + "Compaq-Peer", /* 0x6E: 110 - Compaq Peer Protocol */ + "IPX-in-IP", /* 0x6F: 111 - IPX in IP */ + "VRRP", /* 0x70: 112 - Virtual Router Redundancy Protocol, Common Address Redundancy Protocol + (not IANA assigned) VRRP:RFC 3768 */ + "PGM", /* 0x71: 113 - PGM Reliable Transport Protocol RFC 3208 */ + "Any", /* 0x72: 114 - 0-hop protocol */ + "L2TP", /* 0x73: 115 - Layer Two Tunneling Protocol Version 3 RFC 3931 */ + "DDX", /* 0x74: 116 - D-II Data Exchange (DDX) */ + "IATP", /* 0x75: 117 - Interactive Agent Transfer Protocol */ + "STP", /* 0x76: 118 - Schedule Transfer Protocol */ + "SRP", /* 0x77: 119 - SpectraLink Radio Protocol */ + "UTI", /* 0x78: 120 - Universal Transport Interface Protocol */ + "SMP", /* 0x79: 121 - Simple Message Protocol */ + "SM", /* 0x7A: 122 - Simple Multicast Protocol draft-perlman-simple-multicast-03 */ + "PTP", /* 0x7B: 123 - Performance Transparency Protocol */ + "IS-IS", /* 0x7C: 124 - over IPv4 Intermediate System to Intermediate System (IS-IS) Protocol + over IPv4 RFC 1142 and RFC 1195 */ + "FIRE", /* 0x7D: 125 - Flexible Intra-AS Routing Environment */ + "CRTP", /* 0x7E: 126 - Combat Radio Transport Protocol */ + "CRUDP", /* 0x7F: 127 - Combat Radio User Datagram */ + "SSCOPMCE", /* 0x80: 128 - Service-Specific Connection-Oriented Protocol in a Multilink and + Connectionless Environment ITU-T Q.2111 (1999) */ + "IPLT", /* 0x81: 129 - */ + "SPS", /* 0x82: 130 - Secure Packet Shield */ + "PIPE", /* 0x83: 131 - Private IP Encapsulation within IP Expired I-D + draft-petri-mobileip-pipe-00.txt */ + "SCTP", /* 0x84: 132 - Stream Control Transmission Protocol RFC 4960 */ + "FC", /* 0x85: 133 - Fibre Channel */ + "RSVP-E2E-IGNORE", /* 0x86: 134 - Reservation Protocol (RSVP) End-to-End Ignore RFC 3175 */ + "Mobility", /* 0x87: 135 - Header Mobility Extension Header for IPv6 RFC 6275 */ + "UDPLite", /* 0x88: 136 - Lightweight User Datagram Protocol RFC 3828 */ + "MPLS-in-IP", /* 0x89: 137 - Multiprotocol Label Switching Encapsulated in IP RFC 4023, + RFC 5332 */ + "manet", /* 0x8A: 138 - MANET Protocols RFC 5498 */ + "HIP", /* 0x8B: 139 - Host Identity Protocol RFC 5201 */ + "Shim6", /* 0x8C: 140 - Site Multihoming by IPv6 Intermediation RFC 5533 */ + "WESP", /* 0x8D: 141 - Wrapped Encapsulating Security Payload RFC 5840 */ + "ROHC", /* 0x8E: 142 - Robust Header Compression RFC 5856 */ + "Ethernet" /* 0x8F: 143 - IPv6 Segment Routing (TEMPORARY - registered 2020-01-31, expires + 2021-01-31) */ +}; + +/* + * Protocol name aliases + */ +const char *proto_aliases[256] = { + "ip", /* 0x00: 0 - IPv6 Hop-by-Hop Option RFC 8200 */ + "icmp", /* 0x01: 1 - Internet Control Message Protocol RFC 792 */ + "igmp", /* 0x02: 2 - Internet Group Management Protocol RFC 1112 */ + "ggp", /* 0x03: 3 - Gateway-to-Gateway Protocol RFC 823 */ + "ipencap", /* 0x04: 4 - IP in IP (encapsulation) RFC 2003 */ + "st", /* 0x05: 5 - Internet Stream Protocol RFC 1190, RFC 1819 */ + "tcp", /* 0x06: 6 - Transmission Control Protocol RFC 793 */ + NULL, /* 0x07: 7 - Core-based trees RFC 2189 */ + "egp", /* 0x08: 8 - Exterior Gateway Protocol RFC 888 */ + "igp", /* 0x09: 9 - Interior Gateway Protocol (any private interior gateway, for example Cisco's + IGRP) */ + NULL, /* 0x0A: 10 - BBN RCC Monitoring */ + NULL, /* 0x0B: 11 - Network Voice Protocol RFC 741 */ + "pup", /* 0x0C: 12 - Xerox PUP */ + NULL, /* 0x0D: 13 - ARGUS */ + NULL, /* 0x0E: 14 - EMCON */ + NULL, /* 0x0F: 15 - Cross Net Debugger IEN 158[2] */ + NULL, /* 0x10: 16 - Chaos */ + "udp", /* 0x11: 17 - User Datagram Protocol RFC 768 */ + NULL, /* 0x12: 18 - Multiplexing IEN 90[3] */ + NULL, /* 0x13: 19 - DCN Measurement Subsystems */ + "hmp", /* 0x14: 20 - Host Monitoring Protocol RFC 869 */ + NULL, /* 0x15: 21 - Packet Radio Measurement */ + "xns-idp", /* 0x16: 22 - XEROX NS IDP */ + NULL, /* 0x17: 23 - Trunk-1 */ + NULL, /* 0x18: 24 - Trunk-2 */ + NULL, /* 0x19: 25 - Leaf-1 */ + NULL, /* 0x1A: 26 - Leaf-2 */ + "rdp", /* 0x1B: 27 - Reliable Data Protocol RFC 908 */ + NULL, /* 0x1C: 28 - Internet Reliable Transaction Protocol RFC 938 */ + "iso-tp4", /* 0x1D: 29 - ISO Transport Protocol Class 4 RFC 905 */ + NULL, /* 0x1E: 30 - Bulk Data Transfer Protocol RFC 998 */ + NULL, /* 0x1F: 31 - MFE Network Services Protocol */ + NULL, /* 0x20: 32 - MERIT Internodal Protocol */ + "dccp", /* 0x21: 33 - Datagram Congestion Control Protocol RFC 4340 */ + NULL, /* 0x22: 34 - Third Party Connect Protocol */ + NULL, /* 0x23: 35 - Inter-Domain Policy Routing Protocol RFC 1479 */ + "xtp", /* 0x24: 36 - Xpress Transport Protocol */ + "ddp", /* 0x25: 37 - Datagram Delivery Protocol */ + "idpr-cmtp", /* 0x26: 38 - IDPR Control Message Transport Protocol */ + NULL, /* 0x27: 39 - TP++ Transport Protocol */ + NULL, /* 0x28: 40 - IL Transport Protocol */ + "ipV6", /* 0x29: 41 - IPv6 Encapsulation RFC 2473 */ + NULL, /* 0x2A: 42 - Source Demand Routing Protocol RFC 1940 */ + "ipv6-route", /* 0x2B: 43 - Routing Header for IPv6 RFC 8200 */ + "ipv6-frag", /* 0x2C: 44 - Fragment Header for IPv6 RFC 8200 */ + "idrp", /* 0x2D: 45 - Inter-Domain Routing Protocol */ + "rsvp", /* 0x2E: 46 - Resource Reservation Protocol RFC 2205 */ + "gre", /* 0x2F: 47 - Generic Routing Encapsulation RFC 2784, RFC 2890 */ + NULL, /* 0x30: 48 - Dynamic Source Routing Protocol RFC 4728 */ + NULL, /* 0x31: 49 - Burroughs Network Architecture */ + "esp", /* 0x32: 50 - Encapsulating Security Payload RFC 4303 */ + "ah", /* 0x33: 51 - Authentication Header RFC 4302 */ + NULL, /* 0x34: 52 - Integrated Net Layer Security Protocol TUBA */ + NULL, /* 0x35: 53 - SwIPe RFC 5237 */ + NULL, /* 0x36: 54 - NBMA Address Resolution Protocol RFC 1735 */ + NULL, /* 0x37: 55 - IP Mobility (Min Encap) RFC 2004 */ + NULL, /* 0x38: 56 - Transport Layer Security Protocol (using Kryptonet key management) */ + "skip", /* 0x39: 57 - Simple Key-Management for Internet Protocol RFC 2356 */ + "ipv6-icmp", /* 0x3A: 58 - ICMP for IPv6 RFC 4443, RFC 4884 */ + "ipv6-nonxt", /* 0x3B: 59 - No Next Header for IPv6 RFC 8200 */ + "ipv6-opts", /* 0x3C: 60 - Destination Options for IPv6 RFC 8200 */ + NULL, /* 0x3D: 61 - host internal protocol */ + NULL, /* 0x3E: 62 - CFTP */ + NULL, /* 0x3F: 63 - local network */ + NULL, /* 0x40: 64 - SATNET and Backroom EXPAK */ + NULL, /* 0x41: 65 - Kryptolan */ + NULL, /* 0x42: 66 - MIT Remote Virtual Disk Protocol */ + NULL, /* 0x43: 67 - Internet Pluribus Packet Core */ + NULL, /* 0x44: 68 - distributed file system */ + NULL, /* 0x45: 69 - SATNET Monitoring */ + NULL, /* 0x46: 70 - VISA Protocol */ + NULL, /* 0x47: 71 - Internet Packet Core Utility */ + NULL, /* 0x48: 72 - Computer Protocol Network Executive */ + "cphb", /* 0x49: 73 - Computer Protocol Heart Beat */ + NULL, /* 0x4A: 74 - Wang Span Network */ + NULL, /* 0x4B: 75 - Packet Video Protocol */ + NULL, /* 0x4C: 76 - Backroom SATNET Monitoring */ + NULL, /* 0x4D: 77 - SUN ND PROTOCOL-Temporary */ + NULL, /* 0x4E: 78 - WIDEBAND Monitoring */ + NULL, /* 0x4F: 79 - WIDEBAND EXPAK */ + NULL, /* 0x50: 80 - International Organization for Standardization Internet Protocol */ + "vmtp", /* 0x51: 81 - Versatile Message Transaction Protocol RFC 1045 */ + NULL, /* 0x52: 82 - Secure Versatile Message Transaction Protocol RFC 1045 */ + NULL, /* 0x53: 83 - VINES */ + NULL, /* 0x54: 84 - TTP */ + NULL, /* 0x55: 85 - NSFNET-IGP */ + NULL, /* 0x56: 86 - Dissimilar Gateway Protocol */ + NULL, /* 0x57: 87 - TCF */ + "eigrp", /* 0x58: 88 - EIGRP Informational RFC 7868 */ + "ospf", /* 0x59: 89 - Open Shortest Path First RFC 2328 */ + NULL, /* 0x5A: 90 - Sprite RPC Protocol */ + NULL, /* 0x5B: 91 - Locus Address Resolution Protocol */ + NULL, /* 0x5C: 92 - Multicast Transport Protocol */ + "ax.25", /* 0x5D: 93 - AX.25 */ + "ipip", /* 0x5E: 94 - KA9Q NOS compatible IP over IP tunneling */ + NULL, /* 0x5F: 95 - Mobile Internetworking Control Protocol */ + NULL, /* 0x60: 96 - Semaphore Communications Sec. Pro */ + "etherip", /* 0x61: 97 - Ethernet-within-IP Encapsulation RFC 3378 */ + "encap", /* 0x62: 98 - Encapsulation Header RFC 1241 */ + NULL, /* 0x63: 99 - private encryption scheme */ + "GMTP", /* 0x64: 100 - GMTP */ + NULL, /* 0x65: 101 - Ipsilon Flow Management Protocol */ + NULL, /* 0x66: 102 - PNNI over IP */ + "pim", /* 0x67: 103 - Protocol Independent Multicast */ + NULL, /* 0x68: 104 - IBM's ARIS (Aggregate Route IP Switching) Protocol */ + NULL, /* 0x69: 105 - SCPS (Space Communications Protocol Standards) SCPS-TP[4] */ + NULL, /* 0x6A: 106 - QNX */ + NULL, /* 0x6B: 107 - Active Networks */ + "ipcomp", /* 0x6C: 108 - IP Payload Compression Protocol RFC 3173 */ + NULL, /* 0x6D: 109 - Sitara Networks Protocol */ + NULL, /* 0x6E: 110 - Compaq Peer Protocol */ + NULL, /* 0x6F: 111 - IPX in IP */ + "vrrp", /* 0x70: 112 - Virtual Router Redundancy Protocol, Common Address Redundancy Protocol + (not IANA assigned) VRRP:RFC 3768 */ + NULL, /* 0x71: 113 - PGM Reliable Transport Protocol RFC 3208 */ + NULL, /* 0x72: 114 - 0-hop protocol */ + "l2tp", /* 0x73: 115 - Layer Two Tunneling Protocol Version 3 RFC 3931 */ + NULL, /* 0x74: 116 - D-II Data Exchange (DDX) */ + NULL, /* 0x75: 117 - Interactive Agent Transfer Protocol */ + NULL, /* 0x76: 118 - Schedule Transfer Protocol */ + NULL, /* 0x77: 119 - SpectraLink Radio Protocol */ + NULL, /* 0x78: 120 - Universal Transport Interface Protocol */ + NULL, /* 0x79: 121 - Simple Message Protocol */ + NULL, /* 0x7A: 122 - Simple Multicast Protocol draft-perlman-simple-multicast-03 */ + NULL, /* 0x7B: 123 - Performance Transparency Protocol */ + "isis", /* 0x7C: 124 - over IPv4 Intermediate System to Intermediate System (IS-IS) Protocol + over IPv4 RFC 1142 and RFC 1195 */ + NULL, /* 0x7D: 125 - Flexible Intra-AS Routing Environment */ + NULL, /* 0x7E: 126 - Combat Radio Transport Protocol */ + NULL, /* 0x7F: 127 - Combat Radio User Datagram */ + NULL, /* 0x80: 128 - Service-Specific Connection-Oriented Protocol in a Multilink and + Connectionless Environment ITU-T Q.2111 (1999) */ + NULL, /* 0x81: 129 - */ + NULL, /* 0x82: 130 - Secure Packet Shield */ + NULL, /* 0x83: 131 - Private IP Encapsulation within IP Expired I-D + draft-petri-mobileip-pipe-00.txt */ + "sctp", /* 0x84: 132 - Stream Control Transmission Protocol RFC 4960 */ + "fc", /* 0x85: 133 - Fibre Channel */ + NULL, /* 0x86: 134 - Reservation Protocol (RSVP) End-to-End Ignore RFC 3175 */ + "mobility-header", /* 0x87: 135 - Header Mobility Extension Header for IPv6 RFC 6275 */ + "udplite", /* 0x88: 136 - Lightweight User Datagram Protocol RFC 3828 */ + "mpls-in-ip", /* 0x89: 137 - Multiprotocol Label Switching Encapsulated in IP RFC 4023, + RFC 5332 */ + NULL, /* 0x8A: 138 - MANET Protocols RFC 5498 */ + "hip", /* 0x8B: 139 - Host Identity Protocol RFC 5201 */ + "shim6", /* 0x8C: 140 - Site Multihoming by IPv6 Intermediation RFC 5533 */ + "wesp", /* 0x8D: 141 - Wrapped Encapsulating Security Payload RFC 5840 */ + "rohc", /* 0x8E: 142 - Robust Header Compression RFC 5856 */ + /* no aliases for 142-255 */ +}; + +typedef struct ProtoNameHashEntry_ { + const char *name; + uint8_t number; +} ProtoNameHashEntry; + +static HashTable *proto_ht = NULL; + +static uint32_t ProtoNameHashFunc(HashTable *ht, void *data, uint16_t datalen) +{ + /* + * datalen covers the entire struct -- only the proto name is hashed + * as the proto number is not used for lookups + */ + ProtoNameHashEntry *p = (ProtoNameHashEntry *)data; + return StringHashDjb2((uint8_t *)p->name, strlen(p->name)) % ht->array_size; +} + +static char ProtoNameHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) +{ + ProtoNameHashEntry *p1 = (ProtoNameHashEntry *)data1; + ProtoNameHashEntry *p2 = (ProtoNameHashEntry *)data2; + + if (p1 == NULL || p2 == NULL) + return 0; + + if (p1->name == NULL || p2->name == NULL) + return 0; + + int len1 = strlen(p1->name); + int len2 = strlen(p2->name); + + return len1 == len2 && memcmp(p1->name, p2->name, len1) == 0; +} + +static void ProtoNameAddEntry(const char *proto_name, const uint8_t proto_number) +{ + ProtoNameHashEntry *proto_ent = SCCalloc(1, sizeof(ProtoNameHashEntry)); + if (!proto_ent) { + FatalError("Unable to allocate protocol hash entry"); + } + + proto_ent->name = SCStrdup(proto_name); + if (!proto_ent->name) + FatalError("Unable to allocate memory for protocol name entries"); + + proto_ent->number = proto_number; + + SCLogDebug("new protocol entry: name: \"%s\"; protocol number: %d", proto_ent->name, + proto_ent->number); + if (0 != HashTableAdd(proto_ht, proto_ent, 0)) { + FatalError("Unable to add entry to proto hash table for " + "name: \"%s\"; number: %d", + proto_ent->name, proto_ent->number); + } + return; +} + +static void ProtoNameHashFreeFunc(void *data) +{ + ProtoNameHashEntry *proto_ent = (ProtoNameHashEntry *)data; + + if (proto_ent) { + if (proto_ent->name) + SCFree((void *)proto_ent->name); + SCFree(proto_ent); + } +} + +void SCProtoNameInit(void) +{ + proto_ht = + HashTableInit(256, ProtoNameHashFunc, ProtoNameHashCompareFunc, ProtoNameHashFreeFunc); + if (proto_ht == NULL) { + FatalError("Unable to initialize protocol name/number table"); + } + + for (uint16_t i = 0; i < ARRAY_SIZE(known_proto); i++) { + if (known_proto[i]) { + ProtoNameAddEntry(known_proto[i], (uint8_t)i); + } + } + + for (uint16_t i = 0; i < ARRAY_SIZE(proto_aliases); i++) { + if (proto_aliases[i]) { + ProtoNameAddEntry(proto_aliases[i], (uint8_t)i); + } + } +} + +void SCProtoNameRelease(void) +{ + if (proto_ht != NULL) { + HashTableFree(proto_ht); + proto_ht = NULL; + } +} + +/** + * \brief Function to check if the received protocol number is valid and do + * we have corresponding name entry for this number or not. + * + * \param proto Protocol number to be validated + * \retval ret On success returns true otherwise false + */ +bool SCProtoNameValid(uint16_t proto) +{ + return (proto <= 255 && known_proto[proto] != NULL); +} + +/** + * \brief Function to return the protocol number for a named protocol. Note + * that protocol name aliases are honored. + * + * \param protoname Protocol name (or alias for a protocol name). + * \param proto_number Where to return protocol number + * \retval ret On success returns the protocol number; else -1 + */ +bool SCGetProtoByName(const char *protoname, uint8_t *proto_number) +{ + if (!protoname || !proto_number) { + return false; + } + + ProtoNameHashEntry proto; + proto.name = protoname; + + ProtoNameHashEntry *proto_ent = HashTableLookup(proto_ht, &proto, sizeof(proto)); + if (proto_ent) { + *proto_number = proto_ent->number; + return true; + } + return false; +} + +#ifdef UNITTESTS +static int ProtoNameTest01(void) +{ + uint8_t proto; + FAIL_IF(!SCGetProtoByName("tcp", &proto)); + FAIL_IF(SCGetProtoByName("TcP", &proto)); + FAIL_IF(!SCGetProtoByName("TCP", &proto)); + FAIL_IF(SCGetProtoByName("Invalid", &proto)); + FAIL_IF(!SCGetProtoByName("Ethernet", &proto)); + + /* 'ip' is an alias for 'HOPOPT' */ + FAIL_IF(!SCGetProtoByName("ip", &proto)); + FAIL_IF(!SCGetProtoByName("HOPOPT", &proto)); + + FAIL_IF(SCGetProtoByName("IP", &proto)); + + PASS; +} + +void SCProtoNameRegisterTests(void) +{ + UtRegisterTest("ProtoNameTest01", ProtoNameTest01); +} +#endif diff --git a/src/util/proto-name.h b/src/util/proto-name.h new file mode 100644 index 000000000000..298ea0b28a2f --- /dev/null +++ b/src/util/proto-name.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + */ + +#ifndef __UTIL_PROTO_NAME_H__ +#define __UTIL_PROTO_NAME_H__ + +/** Lookup array to hold the information related to known protocol + * values + */ +extern const char *known_proto[256]; + +bool SCProtoNameValid(uint16_t); +bool SCGetProtoByName(const char *protoname, uint8_t *proto_number); +void SCProtoNameInit(void); +void SCProtoNameRelease(void); + +#ifdef UNITTESTS +void SCProtoNameRegisterTests(void); +#endif + +#endif /* __UTIL_PROTO_NAME_H__ */ diff --git a/src/util/radix-tree.c b/src/util/radix-tree.c new file mode 100644 index 000000000000..b28b3424481b --- /dev/null +++ b/src/util/radix-tree.c @@ -0,0 +1,3753 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Implementation of radix trees + */ + +#include "suricata-common.h" +#include "util/radix-tree.h" +#include "util/debug.h" +#include "util/error.h" +#include "util/ip.h" +#include "util/unittest.h" +#include "util/memcmp.h" +#include "util/byte.h" +#include "util/cidr.h" +#include "util/print.h" +#include "util/validate.h" + +/** + * \brief Allocates and returns a new instance of SCRadixUserData. + * + * \param netmask The netmask entry (cidr) that has to be made in the new + * SCRadixUserData instance + * \param user The user data that has to be set for the above + * netmask in the newly created SCRadixUserData instance. + * + * \retval user_data Pointer to a new instance of SCRadixUserData. + */ +static SCRadixUserData *SCRadixAllocSCRadixUserData(uint8_t netmask, void *user) +{ + SCRadixUserData *user_data = SCCalloc(1, sizeof(SCRadixUserData)); + if (unlikely(user_data == NULL)) { + SCLogError("Error allocating memory"); + return NULL; + } + + user_data->netmask = netmask; + user_data->user = user; + + return user_data; +} + +/** + * \brief Deallocates an instance of SCRadixUserData. + * + * \param user_data Pointer to the instance of SCRadixUserData that has to be + * freed. + */ +static void SCRadixDeAllocSCRadixUserData(SCRadixUserData *user_data) +{ + SCFree(user_data); + + return; +} + +/** + * \brief Appends a user_data instance(SCRadixUserData) to a + * user_data(SCRadixUserData) list. We add the new entry in descending + * order with respect to the netmask contained in the SCRadixUserData. + * + * \param new Pointer to the SCRadixUserData to be added to the list. + * \param list Pointer to the SCRadixUserData list head, to which "new" has to + * be appended. + */ +static void SCRadixAppendToSCRadixUserDataList(SCRadixUserData *new, SCRadixUserData **list) +{ + SCRadixUserData *temp = NULL; + SCRadixUserData *prev = NULL; + + if (new == NULL || list == NULL) { + FatalError("new or list supplied as NULL"); + } + + /* add to the list in descending order. The reason we do this is for + * optimizing key retrieval for a ip key under a netblock */ + prev = temp = *list; + while (temp != NULL) { + if (new->netmask > temp->netmask) + break; + prev = temp; + temp = temp->next; + } + + if (temp == *list) { + new->next = *list; + *list = new; + } else { + new->next = prev->next; + prev->next = new; + } + + return; +} + +/** + * \brief Creates a new Prefix for a key. Used internally by the API. + * + * \param key_stream Data that has to be wrapped in a SCRadixPrefix instance to + * be processed for insertion/lookup/removal of a node by the + * radix tree + * \param key_bitlen The bitlen of the above stream. For example if the + * stream holds the ipv4 address(4 bytes), bitlen would be 32 + * \param user Pointer to the user data that has to be associated with + * this key + * + * \retval prefix The newly created prefix instance on success; NULL on failure + */ +static SCRadixPrefix *SCRadixCreatePrefix( + uint8_t *key_stream, uint16_t key_bitlen, void *user, uint8_t netmask) +{ + SCRadixPrefix *prefix = NULL; + + if (key_bitlen == 0 || (key_bitlen % 8 != 0)) { + SCLogError("Invalid argument bitlen - %d", key_bitlen); + return NULL; + } + + if (key_stream == NULL) { + SCLogError("Argument \"stream\" NULL"); + return NULL; + } + + if ((prefix = SCCalloc(1, sizeof(SCRadixPrefix))) == NULL) + goto error; + + if ((prefix->stream = SCCalloc(1, key_bitlen / 8)) == NULL) + goto error; + + memcpy(prefix->stream, key_stream, key_bitlen / 8); + prefix->bitlen = key_bitlen; + + prefix->user_data = SCRadixAllocSCRadixUserData(netmask, user); + if (prefix->user_data == NULL) { + goto error; + } + + return prefix; + +error: + if (prefix != NULL) { + if (prefix->stream != NULL) { + SCFree(prefix->stream); + } + SCFree(prefix); + } + + return NULL; +} + +/** + * \brief Adds a netmask and its user_data for a particular prefix stream. + * + * \param prefix The prefix stream to which the netmask and its corresponding + * user data has to be added. + * \param netmask The netmask value (cidr) that has to be added to the prefix. + * \param user The pointer to the user data corresponding to the above + * netmask. + */ +static void SCRadixAddNetmaskUserDataToPrefix(SCRadixPrefix *prefix, uint8_t netmask, void *user) +{ + if (prefix == NULL || user == NULL) { + FatalError("prefix or user NULL"); + } + + SCRadixAppendToSCRadixUserDataList( + SCRadixAllocSCRadixUserData(netmask, user), &prefix->user_data); + + return; +} + +/** + * \brief Removes a particular user_data corresponding to a particular netmask + * entry, from a prefix. + * + * \param prefix Pointer to the prefix from which the user_data/netmask entry + * has to be removed. + * \param netmask The netmask value (cidr) whose user_data has to be deleted. + */ +static void SCRadixRemoveNetmaskUserDataFromPrefix(SCRadixPrefix *prefix, uint8_t netmask) +{ + SCRadixUserData *temp = NULL, *prev = NULL; + + if (prefix == NULL) { + FatalError("prefix NULL"); + } + + prev = temp = prefix->user_data; + while (temp != NULL) { + if (temp->netmask == netmask) { + if (temp == prefix->user_data) + prefix->user_data = temp->next; + else + prev->next = temp->next; + + SCRadixDeAllocSCRadixUserData(temp); + break; + } + prev = temp; + temp = temp->next; + } + + return; +} + +/** + * \brief Indicates if prefix contains an entry for an ip with a specific netmask. + * + * \param prefix Pointer to the ip prefix that is being checked. + * \param netmask The netmask value (cidr) that has to be checked for + * presence in the prefix. + * + * \retval 1 On match. + * \retval 0 On no match. + */ +static int SCRadixPrefixContainNetmask(SCRadixPrefix *prefix, uint8_t netmask) +{ + SCRadixUserData *user_data = NULL; + + if (prefix == NULL) { + SCLogError("prefix is NULL"); + goto no_match; + } + + user_data = prefix->user_data; + while (user_data != NULL) { + if (user_data->netmask == netmask) + return 1; + user_data = user_data->next; + } + +no_match: + return 0; +} + +/** + * \brief Returns the total netmask count for this prefix. + * + * \param prefix Pointer to the prefix + * + * \retval count The total netmask count for this prefix. + */ +static int SCRadixPrefixNetmaskCount(SCRadixPrefix *prefix) +{ + SCRadixUserData *user_data = NULL; + uint32_t count = 0; + + if (prefix == NULL) { + SCLogError("prefix is NULL"); + return 0; + } + + user_data = prefix->user_data; + while (user_data != NULL) { + count++; + user_data = user_data->next; + } + + return count; +} + +/** + * \brief Indicates if prefix contains an entry for an ip with a specific netmask + * and if it does, it sets the user data field + * SCRadixPrefix->user_data_result to the netmask user_data entry. + * + * \param prefix Pointer to the ip prefix that is being checked. + * \param netmask The netmask value for which we will have to return the user_data + * \param exact_match flag which indicates if we should check if the prefix + * holds proper netblock(< 32 for ipv4 and < 128 for ipv6) or not. + * + * \retval 1 On match. + * \retval 0 On no match. + */ +static int SCRadixPrefixContainNetmaskAndSetUserData( + SCRadixPrefix *prefix, uint16_t netmask, bool exact_match, void **user_data_result) +{ + SCRadixUserData *user_data = NULL; + + if (prefix == NULL) { + SCLogError("prefix is NULL"); + goto no_match; + } + + user_data = prefix->user_data; + /* Check if we have a match for an exact ip. An exact ip as in not a proper + * netblock, i.e. an ip with a netmask of 32(ipv4) or 128(ipv6) */ + if (exact_match) { + if (user_data->netmask == netmask) { + if (user_data_result) + *user_data_result = user_data->user; + return 1; + } else { + goto no_match; + } + } + + /* Check for the user_data entry for this netmask_value */ + while (user_data != NULL) { + if (user_data->netmask == netmask) { + if (user_data_result) + *user_data_result = user_data->user; + return 1; + } + user_data = user_data->next; + } + +no_match: + if (user_data_result != NULL) + *user_data_result = NULL; + return 0; +} + +/** + * \brief Frees a SCRadixPrefix instance + * + * \param prefix Pointer to a prefix instance + * \param tree Pointer to the Radix tree to which this prefix belongs + */ +static void SCRadixReleasePrefix(SCRadixPrefix *prefix, SCRadixTree *tree) +{ + SCRadixUserData *user_data_temp1 = NULL; + SCRadixUserData *user_data_temp2 = NULL; + + if (prefix != NULL) { + if (prefix->stream != NULL) + SCFree(prefix->stream); + + user_data_temp1 = prefix->user_data; + if (tree->Free != NULL) { + while (user_data_temp1 != NULL) { + user_data_temp2 = user_data_temp1; + user_data_temp1 = user_data_temp1->next; + tree->Free(user_data_temp2->user); + SCRadixDeAllocSCRadixUserData(user_data_temp2); + } + } else if (user_data_temp1 != NULL) { + SCFree(user_data_temp1); + } + + SCFree(prefix); + } + + return; +} + +/** + * \brief Creates a new node for the Radix tree + * + * \retval node The newly created node for the radix tree + */ +static inline SCRadixNode *SCRadixCreateNode(void) +{ + SCRadixNode *node = NULL; + + if ((node = SCCalloc(1, sizeof(SCRadixNode))) == NULL) { + SCLogError("Fatal error encountered in SCRadixCreateNode. Mem not allocated..."); + return NULL; + } + + return node; +} + +/** + * \brief Frees a Radix tree node + * + * \param node Pointer to a Radix tree node + * \param tree Pointer to the Radix tree to which this node belongs + */ +static void SCRadixReleaseNode(SCRadixNode *node, SCRadixTree *tree) +{ + if (node != NULL) { + SCRadixReleasePrefix(node->prefix, tree); + + if (node->netmasks != NULL) + SCFree(node->netmasks); + + SCFree(node); + } + + return; +} + +/** + * \brief Creates a new Radix tree + * + * \param Free Function pointer supplied by the user to be used by the Radix + * cleanup API to free the user supplied data + * + * \retval tree The newly created radix tree on success + * + * \initonly (all radix trees should be created at init) + */ +SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void *), void (*PrintData)(void *)) +{ + SCRadixTree *tree = NULL; + + if ((tree = SCCalloc(1, sizeof(SCRadixTree))) == NULL) { + FatalError("Fatal error encountered in SCRadixCreateRadixTree. Exiting..."); + } + + tree->Free = Free; + tree->PrintData = PrintData; + + return tree; +} + +/** + * \brief Internal helper function used by SCRadixReleaseRadixTree to free a + * subtree + * + * \param node Pointer to the root of the subtree that has to be freed + * \param tree Pointer to the Radix tree to which this subtree belongs + */ +static void SCRadixReleaseRadixSubtree(SCRadixNode *node, SCRadixTree *tree) +{ + if (node != NULL) { + SCRadixReleaseRadixSubtree(node->left, tree); + SCRadixReleaseRadixSubtree(node->right, tree); + SCRadixReleaseNode(node, tree); + } + + return; +} + +/** + * \brief Frees a Radix tree and all its nodes + * + * \param tree Pointer to the Radix tree that has to be freed + */ +void SCRadixReleaseRadixTree(SCRadixTree *tree) +{ + if (tree == NULL) + return; + + SCRadixReleaseRadixSubtree(tree->head, tree); + tree->head = NULL; + SCFree(tree); + return; +} + +/** + * \brief Adds a key to the Radix tree. Used internally by the API. + * + * \param key_stream Data that has to added to the Radix tree + * \param key_bitlen The bitlen of the above stream. For example if the + * stream is the string "abcd", the bitlen would be 32. If + * the stream is an IPV6 address bitlen would be 128 + * \param tree Pointer to the Radix tree + * \param user Pointer to the user data that has to be associated with + * this key + * \param netmask The netmask (cidr) if we are adding an IP netblock; 255 + * if we are not adding an IP netblock + * \param exclusive True if the node should be added iff it doesn't exist. + * + * \retval node Pointer to the newly created node + */ +static SCRadixNode *SCRadixAddKeyInternal(uint8_t *key_stream, uint8_t key_bitlen, + SCRadixTree *tree, void *user, uint8_t netmask, bool exclusive) +{ + SCRadixNode *node = NULL; + SCRadixNode *new_node = NULL; + SCRadixNode *parent = NULL; + SCRadixNode *inter_node = NULL; + SCRadixNode *bottom_node = NULL; + void *ptmp; + + uint8_t *stream = NULL; + uint8_t bitlen = 0; + + uint16_t check_bit = 0; + uint16_t differ_bit = 0; + + uint16_t i = 0; + uint16_t j = 0; + + if (tree == NULL) { + SCLogError("Argument \"tree\" NULL"); + sc_errno = SC_EINVAL; + return NULL; + } + + /* chop the ip address against a netmask */ + MaskIPNetblock(key_stream, netmask, key_bitlen); + + /* the very first element in the radix tree */ + if (tree->head == NULL) { + SCRadixPrefix *prefix = NULL; + if ((prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, netmask)) == NULL) { + SCLogError("Error creating prefix"); + sc_errno = SC_EINVAL; + return NULL; + } + node = SCRadixCreateNode(); + if (node == NULL) { + SCRadixReleasePrefix(prefix, tree); + sc_errno = SC_ENOMEM; + return NULL; + } + node->prefix = prefix; + node->bit = prefix->bitlen; + tree->head = node; + if (netmask == 255 || (netmask == 32 && key_bitlen == 32) || + (netmask == 128 && key_bitlen == 128)) { + sc_errno = SC_EINVAL; + return node; + } + + /* if we have reached here, we are actually having a proper netblock in + * our hand(i.e. < 32 for ipv4 and < 128 for ipv6). Add the netmask for + * this node. The reason we add netmasks other than 32 and 128, is + * because we need those netmasks in case of searches for ips contained + * in netblocks. If the netmask is 32 or 128, either ways we will be + * having an exact match for that ip value. If it is not, we start + * chopping the incoming search ip key using the netmask values added + * into the tree and then verify for a match */ + node->netmask_cnt++; + if ((ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * sizeof(uint8_t)))) == NULL) { + SCFree(node->netmasks); + node->netmasks = NULL; + SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated"); + sc_errno = SC_ENOMEM; + return NULL; + } + node->netmasks = ptmp; + node->netmasks[0] = netmask; + return node; + } + + node = tree->head; + stream = key_stream; + bitlen = key_bitlen; + + /* we walk down the tree only when we satisfy 2 conditions. The first one + * being the incoming prefix is shorter than the differ bit of the current + * node. In case we fail in this aspect, we walk down to the tree, till we + * arrive at a node that ends in a prefix */ + while (node->bit < bitlen || node->prefix == NULL) { + /* if the bitlen isn't long enough to handle the bit test, we just walk + * down along one of the paths, since either paths should end up with a + * node that has a common prefix whose differ bit is greater than the + * bitlen of the incoming prefix */ + if (bitlen <= node->bit) { + if (node->right == NULL) + break; + node = node->right; + } else { + if (SC_RADIX_BITTEST(stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + if (node->right == NULL) + break; + node = node->right; + } else { + if (node->left == NULL) + break; + node = node->left; + } + } + } + + /* we need to keep a reference to the bottom-most node, that actually holds + * the prefix */ + bottom_node = node; + + DEBUG_VALIDATE_BUG_ON(bottom_node == NULL); + DEBUG_VALIDATE_BUG_ON(bottom_node->prefix == NULL); + + /* get the first bit position where the ips differ */ + check_bit = (node->bit < bitlen) ? node->bit : bitlen; + for (i = 0; (i * 8) < check_bit; i++) { + int temp; + if ((temp = (stream[i] ^ bottom_node->prefix->stream[i])) == 0) { + differ_bit = (i + 1) * 8; + continue; + } + + /* find out the position where the first bit differs. This method is + * faster, but at the cost of being larger. But with larger caches + * these days we don't have to worry about cache misses */ + temp = temp * 2; + if (temp >= 256) + j = 0; + else if (temp >= 128) + j = 1; + else if (temp >= 64) + j = 2; + else if (temp >= 32) + j = 3; + else if (temp >= 16) + j = 4; + else if (temp >= 8) + j = 5; + else if (temp >= 4) + j = 6; + else if (temp >= 2) + j = 7; + + differ_bit = i * 8 + j; + break; + } + if (check_bit < differ_bit) + differ_bit = check_bit; + + /* walk up the tree till we find the position, to fit our new node in */ + parent = node->parent; + while (parent && differ_bit <= parent->bit) { + node = parent; + parent = node->parent; + } + + /* We already have the node in the tree with the same differing bit pstn */ + if (differ_bit == bitlen && node->bit == bitlen) { + if (node->prefix != NULL) { + /* Check if we already have this netmask entry covered by this prefix */ + if (SCRadixPrefixContainNetmask(node->prefix, netmask)) { + /* Basically we already have this stream prefix, as well as the + * netblock entry for this. A perfect duplicate. */ + if (exclusive) { + SCLogDebug("not inserting since it already exists"); + sc_errno = SC_EEXIST; + return NULL; + } + SCLogDebug("Duplicate entry for this ip address/netblock"); + } else { + /* Basically we already have this stream prefix, but we don't + * have an entry for this particular netmask value for this + * prefix. For example, we have an entry for 192.168.0.0 and + * 192.168.0.0/16 and now we are trying to enter 192.168.0.0/20 */ + SCRadixAddNetmaskUserDataToPrefix(node->prefix, netmask, user); + + /* if we are adding a netmask of 32(for ipv4) or 128(for ipv6) + * it indicates we are adding an exact host ip into the radix + * tree, in which case we don't need to add the netmask value + * into the tree */ + if (netmask == 255 || (netmask == 32 && bitlen == 32) || + (netmask == 128 && bitlen == 128)) + return node; + + /* looks like we have a netmask which is != 32 or 128, in which + * case we walk up the tree to insert this netmask value in the + * correct node */ + parent = node->parent; + while (parent != NULL && netmask < (parent->bit + 1)) { + node = parent; + parent = parent->parent; + } + + node->netmask_cnt++; + new_node = node; + + if ((ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * sizeof(uint8_t)))) == + NULL) { + SCFree(node->netmasks); + node->netmasks = NULL; + SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated..."); + sc_errno = SC_ENOMEM; + return NULL; + } + node->netmasks = ptmp; + + if (node->netmask_cnt == 1) { + node->netmasks[0] = netmask; + return new_node; + } + + node->netmasks[node->netmask_cnt - 1] = netmask; + + for (i = node->netmask_cnt - 1; i > 0; i--) { + if (netmask < node->netmasks[i - 1]) { + node->netmasks[i] = netmask; + break; + } + + node->netmasks[i] = node->netmasks[i - 1]; + node->netmasks[i - 1] = netmask; + } + } + } else { + node->prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, 255); + } + return node; + } + + /* create the leaf node for the new key */ + SCRadixPrefix *prefix = NULL; + if ((prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, netmask)) == NULL) { + SCLogError("Error creating prefix"); + sc_errno = SC_EINVAL; + return NULL; + } + new_node = SCRadixCreateNode(); + new_node->prefix = prefix; + new_node->bit = prefix->bitlen; + + /* indicates that we have got a key that has length that is already covered + * by a prefix of some other key in the tree. We create a new intermediate + * node with a single child and stick it in. We need the if only in the + * case of variable length keys */ + if (differ_bit == bitlen) { + if (SC_RADIX_BITTEST( + bottom_node->prefix->stream[differ_bit >> 3], (0x80 >> (differ_bit % 8)))) { + new_node->right = node; + } else { + new_node->left = node; + } + new_node->parent = node->parent; + + if (node->parent == NULL) + tree->head = new_node; + else if (node->parent->right == node) + node->parent->right = new_node; + else + node->parent->left = new_node; + + node->parent = new_node; + /* stick our new_node into the tree. Create a node that holds the + * differing bit position and break the branch. Also handle the + * transfer of netmasks between node and inter_node(explained in more + * detail below) */ + } else { + inter_node = SCRadixCreateNode(); + inter_node->prefix = NULL; + inter_node->bit = differ_bit; + inter_node->parent = node->parent; + + if (node->netmasks != NULL) { + for (i = 0; i < node->netmask_cnt; i++) { + if (node->netmasks[i] < differ_bit + 1) + break; + } + + if (i < node->netmask_cnt) { + if ((inter_node->netmasks = SCMalloc((node->netmask_cnt - i) * sizeof(uint8_t))) == + NULL) { + SCLogError("Fatal error encountered in SCRadixAddKey. Mem not allocated..."); + SCRadixReleaseNode(inter_node, tree); + SCRadixReleaseNode(new_node, tree); + sc_errno = SC_ENOMEM; + return NULL; + } + + for (j = 0; j < (node->netmask_cnt - i); j++) + inter_node->netmasks[j] = node->netmasks[i + j]; + + inter_node->netmask_cnt = (node->netmask_cnt - i); + node->netmask_cnt = i; + } + } + + if (SC_RADIX_BITTEST(stream[differ_bit >> 3], (0x80 >> (differ_bit % 8)))) { + inter_node->left = node; + inter_node->right = new_node; + } else { + inter_node->left = new_node; + inter_node->right = node; + } + new_node->parent = inter_node; + + if (node->parent == NULL) + tree->head = inter_node; + else if (node->parent->right == node) + node->parent->right = inter_node; + else + node->parent->left = inter_node; + + node->parent = inter_node; + } + + /* insert the netmask into the tree */ + if (netmask != 255 && (netmask != 32 || (netmask == 32 && bitlen != 32)) && netmask != 128) { + node = new_node; + parent = new_node->parent; + while (parent != NULL && netmask < (parent->bit + 1)) { + node = parent; + parent = parent->parent; + } + + node->netmask_cnt++; + if ((ptmp = SCRealloc(node->netmasks, (node->netmask_cnt * sizeof(uint8_t)))) == NULL) { + SCFree(node->netmasks); + node->netmasks = NULL; + FatalError("Fatal error encountered in SCRadixAddKey. Exiting..."); + } + node->netmasks = ptmp; + + if (node->netmask_cnt == 1) { + node->netmasks[0] = netmask; + return new_node; + } + + node->netmasks[node->netmask_cnt - 1] = netmask; + + for (i = node->netmask_cnt - 1; i > 0; i--) { + if (netmask < node->netmasks[i - 1]) { + node->netmasks[i] = netmask; + break; + } + + node->netmasks[i] = node->netmasks[i - 1]; + node->netmasks[i - 1] = netmask; + } + } + + return new_node; +} + +static SCRadixNode *SCRadixAddKeyExclusive( + uint8_t *key_stream, uint8_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask) +{ + return SCRadixAddKeyInternal(key_stream, key_bitlen, tree, user, netmask, true); +} + +static SCRadixNode *SCRadixAddKey( + uint8_t *key_stream, uint8_t key_bitlen, SCRadixTree *tree, void *user, uint8_t netmask) +{ + return SCRadixAddKeyInternal(key_stream, key_bitlen, tree, user, netmask, false); +} + +/** + * \brief Adds a new IPV4 address to the Radix tree + * + * \param key_stream Data that has to be added to the Radix tree. In this case + * a pointer to an IPV4 address + * \param tree Pointer to the Radix tree + * \param user Pointer to the user data that has to be associated with the + * key + * + * \retval node Pointer to the newly created node + */ +SCRadixNode *SCRadixAddKeyIPV4(uint8_t *key_stream, SCRadixTree *tree, void *user) +{ + SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, 32); + + return node; +} + +/** + * \brief Adds a new IPV6 address to the Radix tree + * + * \param key_stream Data that has to be added to the Radix tree. In this case + * the pointer to an IPV6 address + * \param tree Pointer to the Radix tree + * \param user Pointer to the user data that has to be associated with the + * key + * + * \retval node Pointer to the newly created node + */ +SCRadixNode *SCRadixAddKeyIPV6(uint8_t *key_stream, SCRadixTree *tree, void *user) +{ + SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, 128); + + return node; +} + +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) +static void SCRadixValidateIPv4Key(uint8_t *key, const uint8_t netmask) +{ + uint32_t address; + memcpy(&address, key, sizeof(address)); + uint32_t mask = CIDRGet(netmask); + if (address != (address & mask)) { + uint32_t masked = address & mask; + char ostr[16], nstr[16]; + PrintInet(AF_INET, (void *)&address, ostr, sizeof(ostr)); + PrintInet(AF_INET, (void *)&masked, nstr, sizeof(nstr)); + SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask); + abort(); + } +} + +static void SCRadixValidateIPv6Key(uint8_t *key, const uint8_t netmask) +{ + uint32_t address[4]; + memcpy(&address, key, sizeof(address)); + + uint32_t mask[4]; + memset(&mask, 0, sizeof(mask)); + struct in6_addr mask6; + CIDRGetIPv6(netmask, &mask6); + memcpy(&mask, &mask6.s6_addr, sizeof(mask)); + + uint32_t masked[4]; + masked[0] = address[0] & mask[0]; + masked[1] = address[1] & mask[1]; + masked[2] = address[2] & mask[2]; + masked[3] = address[3] & mask[3]; + + if (memcmp(masked, address, sizeof(masked)) != 0) { + char ostr[64], nstr[64]; + PrintInet(AF_INET6, (void *)&address, ostr, sizeof(ostr)); + PrintInet(AF_INET6, (void *)&masked, nstr, sizeof(nstr)); + SCLogNotice("input %s/%u != expected %s/%u", ostr, netmask, nstr, netmask); + abort(); + } +} +#endif + +/** + * \brief Adds a new IPV4 netblock to the Radix tree + * + * \param key_stream Data that has to be added to the Radix tree. In this case + * a pointer to an IPV4 netblock + * \param tree Pointer to the Radix tree + * \param user Pointer to the user data that has to be associated with the + * key + * \param netmask The netmask (cidr) if we are adding a netblock + * + * \retval node Pointer to the newly created node + */ +SCRadixNode *SCRadixAddKeyIPV4Netblock( + uint8_t *key_stream, SCRadixTree *tree, void *user, uint8_t netmask) +{ +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv4Key(key_stream, netmask); +#endif + SCRadixNode *node = SCRadixAddKey(key_stream, 32, tree, user, netmask); + + return node; +} + +/** + * \brief Adds a new IPV6 netblock to the Radix tree + * + * \param key_stream Data that has to be added to the Radix tree. In this case + * a pointer to an IPV6 netblock + * \param tree Pointer to the Radix tree + * \param user Pointer to the user data that has to be associated with the + * key + * \param netmask The netmask (cidr) if we are adding a netblock + * + * \retval node Pointer to the newly created node + */ +SCRadixNode *SCRadixAddKeyIPV6Netblock( + uint8_t *key_stream, SCRadixTree *tree, void *user, uint8_t netmask) +{ +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv6Key(key_stream, netmask); +#endif + SCRadixNode *node = SCRadixAddKey(key_stream, 128, tree, user, netmask); + + return node; +} + +/** + * \brief Adds a new IPV4/netblock to the Radix tree from a string + * + * \param str IPV4 string with optional /cidr netmask + * \param tree Pointer to the Radix tree + * \param user Pointer to the user data that has to be associated with + * the key + * + * \retval bool true (false) if the node was (wasn't) added. + * + * sc_errno is set: + * - SC_OK: Node added + * - SC_EEXIST: Node already exists + * - SC_EINVAL: Parameter value error + */ +bool SCRadixAddKeyIPV4String(const char *str, SCRadixTree *tree, void *user) +{ + uint32_t ip; + uint8_t netmask = 32; + char ip_str[32]; /* Max length for full ipv4/mask string with NUL */ + char *mask_str = NULL; + struct in_addr addr; + + /* Make a copy of the string so it can be modified */ + strlcpy(ip_str, str, sizeof(ip_str) - 2); + *(ip_str + (sizeof(ip_str) - 1)) = '\0'; + + /* Does it have a mask? */ + if (NULL != (mask_str = strchr(ip_str, '/'))) { + uint8_t cidr; + *(mask_str++) = '\0'; + + /* Dotted type netmask not supported (yet) */ + if (strchr(mask_str, '.') != NULL) { + sc_errno = SC_EINVAL; + return false; + } + + /* Get binary values for cidr mask */ + if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 32) < 0) { + sc_errno = SC_EINVAL; + return false; + } + + netmask = (uint8_t)cidr; + } + + /* Validate the IP */ + if (inet_pton(AF_INET, ip_str, &addr) <= 0) { + sc_errno = SC_EINVAL; + return false; + } + ip = addr.s_addr; + if (netmask != 32) { + uint32_t mask = CIDRGet(netmask); + uint32_t masked = ip & mask; + if (masked != ip) { + char nstr[16]; + PrintInet(AF_INET, (void *)&masked, nstr, sizeof(nstr)); + SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask); + ip = masked; + } +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv4Key((uint8_t *)&ip, netmask); +#endif + } + + SCLogDebug("trying to add %s, but only if it doesn't exist", ip_str); + /* Add, but only if not there */ + if (SCRadixAddKeyExclusive((uint8_t *)&ip, 32, tree, user, netmask) == NULL) { + return false; + } + + return true; +} + +/** + * \brief Adds a new IPV6/netblock to the Radix tree from a string + * + * \param str IPV6 string with optional /cidr netmask + * \param tree Pointer to the Radix tree + * \param user Pointer to the user data that has to be associated with + * the key + * + * \retval bool true (false) if the node was (wasn't) added. + * sc_errno is set: + * - SC_OK: Node added + * - SC_EEXIST: Node already exists + * - SC_EINVAL: Parameter value error + */ +bool SCRadixAddKeyIPV6String(const char *str, SCRadixTree *tree, void *user) +{ + uint8_t netmask = 128; + char ip_str[80]; /* Max length for full ipv6/mask string with NUL */ + char *mask_str = NULL; + struct in6_addr addr; + + /* Make a copy of the string so it can be modified */ + strlcpy(ip_str, str, sizeof(ip_str) - 2); + *(ip_str + sizeof(ip_str) - 1) = '\0'; + + /* Does it have a mask? */ + if (NULL != (mask_str = strchr(ip_str, '/'))) { + uint8_t cidr; + *(mask_str++) = '\0'; + + /* Dotted type netmask not supported (yet) */ + if (strchr(mask_str, '.') != NULL) { + sc_errno = SC_EINVAL; + return false; + } + + /* Get binary values for cidr mask */ + if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask_str, 0, 128) < 0) { + sc_errno = SC_EINVAL; + return false; + } + + netmask = (uint8_t)cidr; + } + + /* Validate the IP */ + if (inet_pton(AF_INET6, ip_str, &addr) <= 0) { + sc_errno = SC_EINVAL; + return false; + } + + if (netmask != 128) { + struct in6_addr mask6, check; + CIDRGetIPv6(netmask, &mask6); + memcpy(&check, &addr, sizeof(check)); + bool diff = false; + for (int i = 0; i < 16; i++) { + addr.s6_addr[i] &= mask6.s6_addr[i]; + diff |= (addr.s6_addr[i] != check.s6_addr[i]); + } + if (diff) { + char nstr[64]; + PrintInet(AF_INET6, (void *)&addr.s6_addr, nstr, sizeof(nstr)); + SCLogWarning("adding '%s' as '%s/%u'", str, nstr, netmask); + } +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv6Key((uint8_t *)&addr.s6_addr, netmask); +#endif + } + + SCLogDebug("trying to add %s, but only if it doesn't exist", str); + /* Add, but only if not there */ + if (SCRadixAddKeyExclusive(addr.s6_addr, 128, tree, user, netmask) == NULL) { + return false; + } + + sc_errno = SC_OK; + return true; +} + +static void SCRadixTransferNetmasksBWNodes(SCRadixNode *dest, SCRadixNode *src) +{ + int i = 0, j = 0; + void *ptmp = NULL; + + if (src == NULL || dest == NULL) { + SCLogError("src or dest NULL"); + return; + } + + /* no netmasks in the source node, to transfer to the destination node */ + if (src->netmasks == NULL) + return; + + if ((ptmp = SCRealloc(dest->netmasks, + (src->netmask_cnt + dest->netmask_cnt) * sizeof(uint8_t))) == NULL) { + SCFree(dest->netmasks); + dest->netmasks = NULL; + return; + } + dest->netmasks = ptmp; + + for (i = dest->netmask_cnt, j = 0; j < src->netmask_cnt; i++, j++) + dest->netmasks[i] = src->netmasks[j]; + + return; +} + +/** + * \brief Removes a netblock entry from an ip node. The function first + * deletes the netblock/user_data entry for the prefix and then + * removes the netmask entry that has been made in the tree, by + * walking up the tree and deleting the entry from the specific node. + * + * \param node The node from which the netblock entry has to be removed. + * \param netmask The netmask entry (cidr) that has to be removed. + */ +static void SCRadixRemoveNetblockEntry(SCRadixNode *node, uint8_t netmask) +{ + void *ptmp; + SCRadixNode *parent = NULL; + int i = 0; + + if (node == NULL) { + SCLogError("Invalid argument. Node is NULL"); + return; + } + + SCRadixRemoveNetmaskUserDataFromPrefix(node->prefix, netmask); + + if (netmask == 32 || netmask == 128) + return; + + parent = node->parent; + while (parent != NULL && netmask < (parent->bit + 1)) { + parent = parent->parent; + } + + for (i = 0; i < node->netmask_cnt; i++) { + if (node->netmasks[i] == netmask) + break; + } + + if (i == node->netmask_cnt) { + SCLogDebug("Something's wrong with the tree. We are unable to find the " + "netmask entry"); + return; + } + + for (; i < node->netmask_cnt - 1; i++) + node->netmasks[i] = node->netmasks[i + 1]; + + node->netmask_cnt--; + if (node->netmask_cnt == 0) { + SCFree(node->netmasks); + node->netmasks = NULL; + return; + } + + ptmp = SCRealloc(node->netmasks, node->netmask_cnt * sizeof(uint8_t)); + if (ptmp == NULL) { + SCFree(node->netmasks); + node->netmasks = NULL; + return; + } + node->netmasks = ptmp; + + return; +} + +/** + * \brief Removes a key from the Radix tree + * + * \param key_stream Data that has to be removed from the Radix tree + * \param key_bitlen The bitlen of the above stream. For example if the + * stream holds an IPV4 address(4 bytes), bitlen would be 32 + * \param tree Pointer to the Radix tree from which the key has to be + * removed + */ +static void SCRadixRemoveKey( + uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree, uint8_t netmask) +{ + SCRadixNode *node = tree->head; + SCRadixNode *parent = NULL; + SCRadixNode *temp_dest = NULL; + + SCRadixPrefix *prefix = NULL; + + uint32_t mask = 0; + int i = 0; + + if (node == NULL) + return; + + if ((prefix = SCRadixCreatePrefix(key_stream, key_bitlen, NULL, 255)) == NULL) + return; + + while (node->bit < prefix->bitlen) { + if (SC_RADIX_BITTEST(prefix->stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + node = node->right; + } else { + node = node->left; + } + + if (node == NULL) { + SCRadixReleasePrefix(prefix, tree); + return; + } + } + + if (node->bit != prefix->bitlen || node->prefix == NULL) { + SCRadixReleasePrefix(prefix, tree); + return; + } + + i = prefix->bitlen / 8; + if (SCMemcmp(node->prefix->stream, prefix->stream, i) == 0) { + mask = UINT_MAX << (8 - prefix->bitlen % 8); + + if (prefix->bitlen % 8 == 0 || + (node->prefix->stream[i] & mask) == (prefix->stream[i] & mask)) { + if (!SCRadixPrefixContainNetmask(node->prefix, netmask)) { + SCLogDebug("The ip key exists in the Radix Tree, but this(%d) " + "netblock entry doesn't exist", + netmask); + SCRadixReleasePrefix(prefix, tree); + return; + } + } else { + SCLogDebug("You are trying to remove a key that doesn't exist in " + "the Radix Tree"); + SCRadixReleasePrefix(prefix, tree); + return; + } + } else { + SCLogDebug("You are trying to remove a key that doesn't exist in the " + "Radix Tree"); + SCRadixReleasePrefix(prefix, tree); + return; + } + + /* The ip node does exist, and the netblock entry does exist in this node, if + * we have reached this point. If we have more than one netblock entry, it + * indicates we have multiple entries for this key. So we delete that + * particular netblock entry, and make our way out of this function */ + if (SCRadixPrefixNetmaskCount(node->prefix) > 1) { + SCRadixRemoveNetblockEntry(node, netmask); + SCRadixReleasePrefix(prefix, tree); + return; + } + + /* we are deleting the root of the tree. This would be the only node left + * in the tree */ + if (tree->head == node) { + SCRadixReleaseNode(node, tree); + tree->head = NULL; + SCRadixReleasePrefix(prefix, tree); + return; + } + + parent = node->parent; + /* parent->parent is not the root of the tree */ + if (parent->parent != NULL) { + if (parent->parent->left == parent) { + if (node->parent->left == node) { + temp_dest = parent->right; + parent->parent->left = parent->right; + parent->right->parent = parent->parent; + } else { + temp_dest = parent->left; + parent->parent->left = parent->left; + parent->left->parent = parent->parent; + } + } else { + if (node->parent->left == node) { + temp_dest = parent->right; + parent->parent->right = parent->right; + parent->right->parent = parent->parent; + } else { + temp_dest = parent->left; + parent->parent->right = parent->left; + parent->left->parent = parent->parent; + } + } + /* parent is the root of the tree */ + } else { + if (parent->left == node) { + temp_dest = tree->head->right; + tree->head->right->parent = NULL; + tree->head = tree->head->right; + } else { + temp_dest = tree->head->left; + tree->head->left->parent = NULL; + tree->head = tree->head->left; + } + } + /* We need to shift the netmask entries from the node that would be + * deleted to its immediate descendant */ + SCRadixTransferNetmasksBWNodes(temp_dest, parent); + /* release the nodes */ + SCRadixReleaseNode(parent, tree); + SCRadixReleaseNode(node, tree); + SCRadixReleasePrefix(prefix, tree); + + return; +} + +/** + * \brief Removes a key from the Radix tree + * + * \param key_stream Data that has to be removed from the Radix tree + * \param key_bitlen The bitlen of the above stream. + * \param tree Pointer to the Radix tree from which the key has to be + * removed + */ +void SCRadixRemoveKeyGeneric(uint8_t *key_stream, uint16_t key_bitlen, SCRadixTree *tree) +{ + SCRadixRemoveKey(key_stream, key_bitlen, tree, 255); + return; +} + +/** + * \brief Removes an IPV4 address netblock key from the Radix tree. + * + * \param key_stream Data that has to be removed from the Radix tree. In this + * case an IPV4 address + * \param tree Pointer to the Radix tree from which the key has to be + * removed + */ +void SCRadixRemoveKeyIPV4Netblock(uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask) +{ +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv4Key(key_stream, netmask); +#endif + SCRadixRemoveKey(key_stream, 32, tree, netmask); + return; +} + +/** + * \brief Removes an IPV4 address key(not a netblock) from the Radix tree. + * Instead of using this function, we can also used + * SCRadixRemoveKeyIPV4Netblock(), by supplying a netmask value of 32. + * + * \param key_stream Data that has to be removed from the Radix tree. In this + * case an IPV4 address + * \param tree Pointer to the Radix tree from which the key has to be + * removed + */ +void SCRadixRemoveKeyIPV4(uint8_t *key_stream, SCRadixTree *tree) +{ + SCRadixRemoveKey(key_stream, 32, tree, 32); + return; +} + +/** + * \brief Removes an IPV6 netblock address key from the Radix tree. + * + * \param key_stream Data that has to be removed from the Radix tree. In this + * case an IPV6 address + * \param tree Pointer to the Radix tree from which the key has to be + * removed + */ +void SCRadixRemoveKeyIPV6Netblock(uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask) +{ +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv6Key(key_stream, netmask); +#endif + SCRadixRemoveKey(key_stream, 128, tree, netmask); + return; +} + +/** + * \brief Removes an IPV6 address key(not a netblock) from the Radix tree. + * Instead of using this function, we can also used + * SCRadixRemoveKeyIPV6Netblock(), by supplying a netmask value of 128. + * + * \param key_stream Data that has to be removed from the Radix tree. In this + * case an IPV6 address + * \param tree Pointer to the Radix tree from which the key has to be + * removed + */ +void SCRadixRemoveKeyIPV6(uint8_t *key_stream, SCRadixTree *tree) +{ + SCRadixRemoveKey(key_stream, 128, tree, 128); + return; +} + +/** + * \brief Checks if an IP prefix falls under a netblock, in the path to the root + * of the tree, from the node. Used internally by SCRadixFindKey() + * + * \param prefix Pointer to the prefix that contains the ip address + * \param node Pointer to the node from where we have to climb the tree + */ +static inline SCRadixNode *SCRadixFindKeyIPNetblock( + uint8_t *key_stream, uint8_t key_bitlen, SCRadixNode *node, void **user_data_result) +{ + SCRadixNode *netmask_node = NULL; + uint32_t mask = 0; + int bytes = 0; + int i = 0; + int j = 0; + + while (node != NULL && node->netmasks == NULL) + node = node->parent; + + if (node == NULL) + return NULL; + /* hold the node found containing a netmask. We will need it when we call + * this function recursively */ + netmask_node = node; + + for (j = 0; j < netmask_node->netmask_cnt; j++) { + bytes = key_bitlen / 8; + for (i = 0; i < bytes; i++) { + mask = UINT_MAX; + if (((i + 1) * 8) > netmask_node->netmasks[j]) { + if (((i + 1) * 8 - netmask_node->netmasks[j]) < 8) + mask = UINT_MAX << ((i + 1) * 8 - netmask_node->netmasks[j]); + else + mask = 0; + } + key_stream[i] &= mask; + } + + while (node->bit < key_bitlen) { + if (SC_RADIX_BITTEST(key_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + node = node->right; + } else { + node = node->left; + } + + if (node == NULL) + return NULL; + } + + if (node->bit != key_bitlen || node->prefix == NULL) + return NULL; + + if (SCMemcmp(node->prefix->stream, key_stream, bytes) == 0) { + mask = UINT_MAX << (8 - key_bitlen % 8); + + if (key_bitlen % 8 == 0 || + (node->prefix->stream[bytes] & mask) == (key_stream[bytes] & mask)) { + if (SCRadixPrefixContainNetmaskAndSetUserData( + node->prefix, netmask_node->netmasks[j], false, user_data_result)) + return node; + } + } + } + + return SCRadixFindKeyIPNetblock(key_stream, key_bitlen, netmask_node->parent, user_data_result); +} + +/** + * \brief Checks if an IP address key is present in the tree. The function + * apart from handling any normal data, also handles ipv4/ipv6 netblocks + * + * \param key_stream Data that has to be found in the Radix tree + * \param key_bitlen The bitlen of the above stream. + * \param tree Pointer to the Radix tree + * \param exact_match The key to be searched is an ip address + * \param netmask Netmask used during exact match + */ +static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint8_t key_bitlen, uint8_t netmask, + SCRadixTree *tree, bool exact_match, void **user_data_result) +{ + if (tree == NULL || tree->head == NULL) + return NULL; + + SCRadixNode *node = tree->head; + uint32_t mask = 0; + int bytes = 0; + uint8_t tmp_stream[255]; + + memset(tmp_stream, 0, 255); + memcpy(tmp_stream, key_stream, key_bitlen / 8); + + while (node->bit < key_bitlen) { + if (SC_RADIX_BITTEST(tmp_stream[node->bit >> 3], (0x80 >> (node->bit % 8)))) { + node = node->right; + } else { + node = node->left; + } + + if (node == NULL) { + return NULL; + } + } + + if (node->bit != key_bitlen || node->prefix == NULL) { + return NULL; + } + + bytes = key_bitlen / 8; + if (SCMemcmp(node->prefix->stream, tmp_stream, bytes) == 0) { + mask = UINT_MAX << (8 - key_bitlen % 8); + + if (key_bitlen % 8 == 0 || + (node->prefix->stream[bytes] & mask) == (tmp_stream[bytes] & mask)) { + if (SCRadixPrefixContainNetmaskAndSetUserData( + node->prefix, netmask, true, user_data_result)) { + return node; + } + } + } + + /* if you are not an ip key, get out of here */ + if (exact_match) { + return NULL; + } + + SCRadixNode *ret = SCRadixFindKeyIPNetblock(tmp_stream, key_bitlen, node, user_data_result); + return ret; +} + +/** + * \brief Checks if an IPV4 address is present in the tree + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV4 address + * \param tree Pointer to the Radix tree instance + */ +SCRadixNode *SCRadixFindKeyIPV4ExactMatch( + uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) +{ + return SCRadixFindKey(key_stream, 32, 32, tree, true, user_data_result); +} + +/** + * \brief Checks if an IPV4 address is present in the tree under a netblock + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV4 address + * \param tree Pointer to the Radix tree instance + */ +SCRadixNode *SCRadixFindKeyIPV4BestMatch( + uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) +{ + return SCRadixFindKey(key_stream, 32, 32, tree, false, user_data_result); +} + +/** + * \brief Checks if an IPV4 Netblock address is present in the tree + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV4 netblock address + * \param tree Pointer to the Radix tree instance + */ +SCRadixNode *SCRadixFindKeyIPV4Netblock( + uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask, void **user_data_result) +{ +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv4Key(key_stream, netmask); +#endif + SCRadixNode *node = SCRadixFindKey(key_stream, 32, netmask, tree, true, user_data_result); + return node; +} + +/** + * \brief Checks if an IPV6 Netblock address is present in the tree + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV6 netblock address + * \param tree Pointer to the Radix tree instance + */ +SCRadixNode *SCRadixFindKeyIPV6Netblock( + uint8_t *key_stream, SCRadixTree *tree, uint8_t netmask, void **user_data_result) +{ +#if defined(DEBUG_VALIDATION) || defined(UNITTESTS) + SCRadixValidateIPv6Key(key_stream, netmask); +#endif + SCRadixNode *node = SCRadixFindKey(key_stream, 128, netmask, tree, true, user_data_result); + return node; +} + +/** + * \brief Checks if an IPV6 address is present in the tree + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV6 address + * \param tree Pointer to the Radix tree instance + */ +SCRadixNode *SCRadixFindKeyIPV6ExactMatch( + uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) +{ + return SCRadixFindKey(key_stream, 128, 128, tree, true, user_data_result); +} + +/** + * \brief Checks if an IPV6 address is present in the tree under a netblock + * + * \param key_stream Data that has to be found in the Radix tree. In this case + * an IPV6 address + * \param tree Pointer to the Radix tree instance + */ +SCRadixNode *SCRadixFindKeyIPV6BestMatch( + uint8_t *key_stream, SCRadixTree *tree, void **user_data_result) +{ + return SCRadixFindKey(key_stream, 128, 128, tree, false, user_data_result); +} + +/** + * \brief Prints the node information from a Radix tree + * + * \param node Pointer to the Radix node whose information has to be printed + * \param level Used for indentation purposes + */ +void SCRadixPrintNodeInfo(SCRadixNode *node, int level, void (*PrintData)(void *)) +{ + int i = 0; + + if (node == NULL) + return; + + for (i = 0; i < level; i++) + printf(" "); + + printf("%d [", node->bit); + + if (node->netmasks == NULL) { + printf("%d, ", -1); + } else { + for (i = 0; i < node->netmask_cnt; i++) + printf("%s%d", (0 == i ? "" : ", "), node->netmasks[i]); + } + + printf("] ("); + if (node->prefix != NULL) { + for (i = 0; i * 8 < node->prefix->bitlen; i++) + printf("%s%d", (0 == i ? "" : "."), node->prefix->stream[i]); + printf(") user_data %p\n", node->prefix->user_data); + + SCRadixUserData *ud = node->prefix->user_data; + do { + for (int x = 0; x <= level; x++) + printf(" "); + printf("[%d] (%p): ", ud->netmask, ud->user); + if (PrintData != NULL) { + PrintData(ud->user); + } else { + printf("NULL"); + } + printf("\n"); + ud = ud->next; + } while (ud != NULL); + } else { + printf("inter_node)\n"); + } + + return; +} + +/** + * \brief Helper function used by SCRadixPrintTree. Prints the subtree with + * node as the root of the subtree + * + * \param node Pointer to the node that is the root of the subtree to be printed + * \param level Used for indentation purposes + */ +static void SCRadixPrintRadixSubtree(SCRadixNode *node, int level, void (*PrintData)(void *)) +{ + if (node != NULL) { + SCRadixPrintNodeInfo(node, level, PrintData); + SCRadixPrintRadixSubtree(node->left, level + 1, PrintData); + SCRadixPrintRadixSubtree(node->right, level + 1, PrintData); + } + + return; +} + +/** + * \brief Prints the Radix Tree. While printing the radix tree we use the + * following format + * + * Parent_0 + * Left_Child_1 + * Left_Child_2 + * Right_Child_2 + * Right_Child_1 + * Left_Child_2 + * Right_Child_2 and so on + * + * Each node printed out holds details on the next bit that differs + * amongst its children, and if the node holds a prefix, the perfix is + * printed as well. + * + * \param tree Pointer to the Radix tree that has to be printed + */ +void SCRadixPrintTree(SCRadixTree *tree) +{ + printf("Printing the Radix Tree: \n"); + + SCRadixPrintRadixSubtree(tree->head, 0, tree->PrintData); + + return; +} + +/*------------------------------------Unit_Tests------------------------------*/ + +#ifdef UNITTESTS + +static int SCRadixTestIPV4Insertion03(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + /* add a key that already exists in the tree */ + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + /* test for the existence of a key */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + /* test for the existence of a key */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + /* continue adding keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + /* test the existence of keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.3", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "127.234.2.62", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +static int SCRadixTestIPV4Removal04(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + /* remove the keys from the tree */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.1", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4((uint8_t *)&servaddr.sin_addr, tree); + + result &= (tree->head == NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +static int SCRadixTestIPV6Insertion07(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in6 servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + /* Try to add the prefix that already exists in the tree */ + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + /* test the existence of keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +static int SCRadixTestIPV6Removal08(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in6 servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + /* Try to add the prefix that already exists in the tree */ + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + /* test the existence of keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "8888:0BF1:5346:BDEA:6422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2006:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + /* test for existence */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:DDDD:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + /* remove keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); + + /* test for existence */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + /* remove keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree); + + /* test for existence */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +/** Bug #5066 + * + * insert: + * - 100.117.241.0/25: 100.117.241.0 - 100.117.241.127 + * - 100.117.241.0/26: 100.117.241.0 - 100.117.241.63 + * + * check: + * - 100.117.241.64/26: 100.117.241.64 - 100.117.241.127 + */ + +static int SCRadixTestIPV4Bug5066(void) +{ + struct sockaddr_in servaddr; + SCRadixNode *node = NULL; + + SCLogDebug("setup tree"); + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "100.117.241.0", &servaddr.sin_addr) <= 0); + SCLogDebug("add 100.117.241.0/25"); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1"), 25); + SCRadixPrintTree(tree); + SCLogDebug("find 100.117.241.0/25"); + char *r = NULL; + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 25, (void **)&r); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCLogDebug("add 100.117.241.0/26"); + FAIL_IF(inet_pton(AF_INET, "100.117.241.0", &servaddr.sin_addr) <= 0); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("2"), 26); + SCRadixPrintTree(tree); + SCLogDebug("find 100.117.241.0/26"); + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCLogDebug("find 100.117.241.64/26 (should fail)"); + FAIL_IF(inet_pton(AF_INET, "100.117.241.64", &servaddr.sin_addr) <= 0); + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); + FAIL_IF_NOT_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCLogDebug("add 100.117.241.64/26"); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("3"), 26); + SCLogDebug("find 100.117.241.64/26 (should succeed)"); + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, NULL); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCRadixPrintTree(tree); + + SCRadixReleaseRadixTree(tree); + PASS; +} + +static void SCRadixTestIPV4Bug5066v2PrintData(void *d) +{ + const char *s = d; + printf("%s", s); +} + +static int SCRadixTestIPV4Bug5066v2(void) +{ + struct sockaddr_in servaddr; + SCRadixNode *node = NULL; + + SCLogDebug("setup tree"); + SCRadixTree *tree = SCRadixCreateRadixTree(free, SCRadixTestIPV4Bug5066v2PrintData); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/24"), 24); + SCRadixPrintTree(tree); + char *r = NULL; + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 24, (void **)&r); + SCRadixPrintTree(tree); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + FAIL_IF_NOT(strcmp(r, "1.2.3.0/24") == 0); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/25"), 25); + SCRadixPrintTree(tree); + r = NULL; + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 25, (void **)&r); + SCRadixPrintTree(tree); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + FAIL_IF_NOT(strcmp(r, "1.2.3.0/25") == 0); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "1.2.3.0", &servaddr.sin_addr) <= 0); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.0/26"), 26); + SCRadixPrintTree(tree); + r = NULL; + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, (void **)&r); + SCRadixPrintTree(tree); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + FAIL_IF_NOT(strcmp(r, "1.2.3.0/26") == 0); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "1.2.3.64", &servaddr.sin_addr) <= 0); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.64/26"), 26); + SCRadixPrintTree(tree); + r = NULL; + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 26, (void **)&r); + SCRadixPrintTree(tree); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + FAIL_IF_NOT(strcmp(r, "1.2.3.64/26") == 0); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "1.2.3.64", &servaddr.sin_addr) <= 0); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.64/27"), 27); + SCRadixPrintTree(tree); + r = NULL; + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 27, (void **)&r); + SCRadixPrintTree(tree); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + FAIL_IF_NOT(strcmp(r, "1.2.3.64/27") == 0); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "1.2.3.96", &servaddr.sin_addr) <= 0); + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, strdup("1.2.3.96/27"), 27); + SCRadixPrintTree(tree); + r = NULL; + node = SCRadixFindKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 27, (void **)&r); + SCRadixPrintTree(tree); + FAIL_IF_NULL(node); + SCLogNotice("node:"); + SCRadixPrintNodeInfo(node, 0, NULL); + FAIL_IF_NOT(strcmp(r, "1.2.3.96/27") == 0); + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** Bug #5066 + */ +static int SCRadixTestIPV6Bug5066(void) +{ + struct sockaddr_in6 servaddr; + SCRadixNode *node = NULL; + + SCLogDebug("setup tree"); + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "2000::1:0", &servaddr.sin6_addr) <= 0); + SCLogDebug("add 2000::1:0/121"); + SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("1"), 121); + SCRadixPrintTree(tree); + SCLogDebug("find 2000::1:0/121"); + char *r = NULL; + node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 121, (void **)&r); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCLogDebug("add 2000::1:0/122"); + FAIL_IF(inet_pton(AF_INET6, "2000::1:0", &servaddr.sin6_addr) <= 0); + SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("2"), 122); + SCRadixPrintTree(tree); + SCLogDebug("find 2000::1:0/122"); + node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCLogDebug("find 2000::1:40/122 (should fail)"); + FAIL_IF(inet_pton(AF_INET6, "2000::1:40", &servaddr.sin6_addr) <= 0); + node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); + FAIL_IF_NOT_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCLogDebug("add 2000::1:40/122"); + SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, strdup("3"), 122); + SCLogDebug("find 2000::1:40/122 (should succeed)"); + node = SCRadixFindKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, 122, NULL); + FAIL_IF_NULL(node); + SCRadixPrintNodeInfo(node, 0, NULL); + + SCRadixPrintTree(tree); + + SCRadixReleaseRadixTree(tree); + PASS; +} + +static int SCRadixTestIPV4NetblockInsertion09(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.3", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.1.2", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.5", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.18", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.192.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); + + if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + /* test for the existence of a key */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.170.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.145", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.64.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.191.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.224.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.174.224.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.175.224.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +static int SCRadixTestIPV4NetblockInsertion10(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node[2]; + struct sockaddr_in servaddr; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) + return 0; + node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); + + if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + SCRadixPrintTree(tree); + + /* test for the existence of a key */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) + return 0; + SCRadixNode *found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); + FAIL_IF_NOT(found == node[0]); + + SCLogDebug("search \"exact\" match for 192.171.128.45"); + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + found = SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); + FAIL_IF_NOT(found == node[1]); + + SCLogDebug("search \"best\" match for 192.171.128.45"); + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); + FAIL_IF_NOT(found == node[1]); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) + return 0; + found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); + FAIL_IF_NOT(found == node[0]); + + /* let us remove a netblock */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) + return 0; + found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); + FAIL_IF_NOT_NULL(found); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) + return 0; + found = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL); + FAIL_IF_NOT_NULL(found); + + SCRadixReleaseRadixTree(tree); + PASS; +} + +static int SCRadixTestIPV4NetblockInsertion11(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node = NULL; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); + + if (inet_pton(AF_INET, "192.175.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) + return 0; + node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 0); + + /* test for the existence of a key */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && + SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "245.63.62.121", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && + SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL && + SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node); + + /* remove node 0.0.0.0 */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, 0); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.6", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "1.1.1.1", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.255.254.25", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "169.255.254.25", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +static int SCRadixTestIPV4NetblockInsertion12(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node[2]; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.192.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.192.235.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.167.1.4", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "220.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "253.224.1.5", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.0", &servaddr.sin_addr) <= 0) + return 0; + node[0] = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 24); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + node[1] = SCRadixAddKeyIPV4((uint8_t *)&servaddr.sin_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 18); + + if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 32); + + /* test for the existence of a key */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[0]); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.53", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.45", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[1]); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.128.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == node[0]); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.171.127.78", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.228", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.224", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.229", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "225.175.21.230", &servaddr.sin_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV4ExactMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) == NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +static int SCRadixTestIPV6NetblockInsertion13(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in6 servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + /* test the existence of keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABC2:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF5:5346:1251:7422:1112:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBCA:1245:2342:1111:2212", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1146:6241", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1356:1241", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DAAA:1245:2342:1146:6241", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +static int SCRadixTestIPV6NetblockInsertion14(void) +{ + SCRadixTree *tree = NULL; + SCRadixNode *node = NULL; + struct sockaddr_in6 servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + /* add the keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2003:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "BD15:9791:5346:6223:AADB:8713:9882:2432", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "1111:A21B:6221:BDEA:BBBA::DBAA:9861", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "4444:0BF7:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "5555:0BF1:ABCD:ADEA:7922:ABCD:9124:2375", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DB00:0000:0000:0000:0000", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 56); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) + return 0; + SCRadixAddKeyIPV6((uint8_t *)&servaddr.sin6_addr, tree, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "::", &servaddr.sin6_addr) <= 0) + return 0; + node = SCRadixAddKeyIPV6Netblock((uint8_t *)&servaddr.sin6_addr, tree, NULL, 0); + + /* test the existence of keys */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2004:0BF1:5346:BDEA:7422:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2004:0BF1:5346:B116:2362:8713:9124:2315", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "2004:0B23:3252:BDEA:7422:8713:9124:2341", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) == node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL && + SCRadixFindKeyIPV6ExactMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != node); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET6, "DBCA:ABCD:ABCD:DBAA:1245:2342:1145:6241", &servaddr.sin6_addr) <= 0) + return 0; + result &= (SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != NULL && + SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, NULL) != node); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV4NetBlocksAndBestSearch15(void) +{ + + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "192.168.0.1", &servaddr.sin_addr) <= 0); + + for (uint32_t i = 0; i <= 32; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[32]; + snprintf(str, sizeof(str), "192.168.0.1/%u", i); + SCRadixAddKeyIPV4String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV4NetBlocksAndBestSearch16(void) +{ + + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr) <= 0); + + for (uint32_t i = 0; i <= 32; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[32]; + snprintf(str, sizeof(str), "192.168.1.1/%u", i); + SCRadixAddKeyIPV4String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV4NetBlocksAndBestSearch17(void) +{ + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "10.0.0.1", &servaddr.sin_addr) <= 0); + + for (uint32_t i = 0; i <= 32; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[32]; + snprintf(str, sizeof(str), "10.0.0.1/%u", i); + SCRadixAddKeyIPV4String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV4NetBlocksAndBestSearch18(void) +{ + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "172.26.0.1", &servaddr.sin_addr) <= 0); + + for (uint32_t i = 0; i <= 32; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[32]; + snprintf(str, sizeof(str), "172.26.0.1/%u", i); + SCRadixAddKeyIPV4String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check special combinations of netblocks and addresses + * on best search checking the returned userdata + */ +static int SCRadixTestIPV4NetBlocksAndBestSearch19(void) +{ + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); + + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 100; + + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 0); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "192.168.1.15", &servaddr.sin_addr) <= 0); + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "177.0.0.0", &servaddr.sin_addr) <= 0); + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 200; + + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 8); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0); + + node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "178.168.1.15", &servaddr.sin_addr) <= 0); + + node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "177.160.0.0", &servaddr.sin_addr) <= 0); + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 300; + + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, user, 12); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "177.168.1.15", &servaddr.sin_addr) <= 0); + + node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "177.167.1.15", &servaddr.sin_addr) <= 0); + + node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "177.178.1.15", &servaddr.sin_addr) <= 0); + + node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "197.178.1.15", &servaddr.sin_addr) <= 0); + + node = SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV6NetBlocksAndBestSearch20(void) +{ + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in6 servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ABAB:CDCD:ABAB:CDCD:1234:4321:1234:4321", &servaddr.sin6_addr) <= + 0); + + for (uint32_t i = 0; i <= 128; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[64]; + snprintf(str, sizeof(str), "ABAB:CDCD:ABAB:CDCD:1234:4321:1234:4321/%u", i); + SCRadixAddKeyIPV6String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV6NetBlocksAndBestSearch21(void) +{ + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in6 servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ff00::1", &servaddr.sin6_addr) <= 0); + + for (uint32_t i = 0; i <= 128; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[64]; + snprintf(str, sizeof(str), "ff00::1/%u", i); + SCRadixAddKeyIPV6String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV6NetBlocksAndBestSearch22(void) +{ + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in6 servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ff00::192:168:1:1", &servaddr.sin6_addr) <= 0); + + for (uint32_t i = 0; i <= 128; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[64]; + snprintf(str, sizeof(str), "ff00::192:168:1:1/%u", i); + SCRadixAddKeyIPV6String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check that the best match search works for all the + * possible netblocks of a fixed address + */ +static int SCRadixTestIPV6NetBlocksAndBestSearch23(void) +{ + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + struct sockaddr_in6 servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "FF00:ABCD:BCDA::ABCD", &servaddr.sin6_addr) <= 0); + + for (uint32_t i = 0; i <= 128; i++) { + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = i; + + char str[64]; + snprintf(str, sizeof(str), "FF00:ABCD:BCDA::ABCD/%u", i); + SCRadixAddKeyIPV6String(str, tree, user); + + void *user_data = NULL; + SCRadixNode *node = + SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != i); + } + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test Check special combinations of netblocks and addresses + * on best search checking the returned userdata + */ +static int SCRadixTestIPV6NetBlocksAndBestSearch24(void) +{ + struct sockaddr_in6 servaddr; + void *user_data = NULL; + + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + uint32_t *user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 100; + SCRadixAddKeyIPV6String("::/0", tree, user); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0); + SCRadixNode *node = + SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + + user_data = NULL; + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 200; + SCRadixAddKeyIPV6String("ABCD::0/8", tree, user); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ABCD::1", &servaddr.sin6_addr) <= 0); + node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "DCBA::1", &servaddr.sin6_addr) <= 0); + + node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + + user_data = NULL; + user = SCMalloc(sizeof(uint32_t)); + FAIL_IF_NULL(user); + *user = 300; + SCRadixAddKeyIPV6String("ABCD:ABCD::0/12", tree, user); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ABCD:ABCD::1", &servaddr.sin6_addr) <= 0); + node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ABCD:AAAA::1", &servaddr.sin6_addr) <= 0); + node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 300); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "ABAB::1", &servaddr.sin6_addr) <= 0); + node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 200); + + user_data = NULL; + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET6, "CABD::1", &servaddr.sin6_addr) <= 0); + node = SCRadixFindKeyIPV6BestMatch((uint8_t *)&servaddr.sin6_addr, tree, &user_data); + FAIL_IF_NULL(node); + FAIL_IF_NULL(user_data); + FAIL_IF(*((uint32_t *)user_data) != 100); + + SCRadixReleaseRadixTree(tree); + PASS; +} + +/** + * \test SCRadixTestIPV4NetblockInsertion15 insert a node searching on it. + * Should always return true but the purpose of the test is to monitor + * the memory usage to detect memleaks (there was one on searching) + */ +static int SCRadixTestIPV4NetblockInsertion25(void) +{ + SCRadixTree *tree = NULL; + struct sockaddr_in servaddr; + int result = 1; + + tree = SCRadixCreateRadixTree(free, NULL); + + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) + return 0; + SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, NULL, 16); + + /* test for the existence of a key */ + memset(&servaddr, 0, sizeof(servaddr)); + if (inet_pton(AF_INET, "192.168.128.53", &servaddr.sin_addr) <= 0) + return 0; + + result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree, NULL) != NULL); + + SCRadixReleaseRadixTree(tree); + + return result; +} + +/** + * \test SCRadixTestIPV4NetblockInsertion26 insert a node searching on it. + * Should always return true but the purpose of the test is to monitor + * the memory usage to detect memleaks (there was one on searching) + */ +static int SCRadixTestIPV4NetblockInsertion26(void) +{ + struct sockaddr_in servaddr; + + SCRadixTree *tree = SCRadixCreateRadixTree(free, NULL); + FAIL_IF_NULL(tree); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); + + char *str = SCStrdup("Hello1"); + FAIL_IF_NULL(str); + SCRadixNode *node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 0); + FAIL_IF_NULL(node); + + str = SCStrdup("Hello1"); + FAIL_IF_NULL(str); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "176.0.0.0", &servaddr.sin_addr) <= 0); + + node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 5); + FAIL_IF_NULL(node); + + str = SCStrdup("Hello1"); + FAIL_IF_NULL(str); + + memset(&servaddr, 0, sizeof(servaddr)); + FAIL_IF(inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr) <= 0); + + node = SCRadixAddKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, tree, str, 7); + FAIL_IF_NULL(node); + + /* test for the existence of a key */ + // result &= (SCRadixFindKeyIPV4BestMatch((uint8_t *)&servaddr.sin_addr, tree) != NULL); + + SCRadixReleaseRadixTree(tree); + + PASS; +} + +#endif + +void SCRadixRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03); + UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04); + UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07); + UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion09", SCRadixTestIPV4NetblockInsertion09); + UtRegisterTest("SCRadixTestIPV4Bug5066", SCRadixTestIPV4Bug5066); + UtRegisterTest("SCRadixTestIPV4Bug5066v2", SCRadixTestIPV4Bug5066v2); + UtRegisterTest("SCRadixTestIPV6Bug5066", SCRadixTestIPV6Bug5066); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion10", SCRadixTestIPV4NetblockInsertion10); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion11", SCRadixTestIPV4NetblockInsertion11); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion12", SCRadixTestIPV4NetblockInsertion12); + UtRegisterTest("SCRadixTestIPV6NetblockInsertion13", SCRadixTestIPV6NetblockInsertion13); + UtRegisterTest("SCRadixTestIPV6NetblockInsertion14", SCRadixTestIPV6NetblockInsertion14); + UtRegisterTest( + "SCRadixTestIPV4NetBlocksAndBestSearch15", SCRadixTestIPV4NetBlocksAndBestSearch15); + UtRegisterTest( + "SCRadixTestIPV4NetBlocksAndBestSearch16", SCRadixTestIPV4NetBlocksAndBestSearch16); + UtRegisterTest( + "SCRadixTestIPV4NetBlocksAndBestSearch17", SCRadixTestIPV4NetBlocksAndBestSearch17); + UtRegisterTest( + "SCRadixTestIPV4NetBlocksAndBestSearch18", SCRadixTestIPV4NetBlocksAndBestSearch18); + UtRegisterTest( + "SCRadixTestIPV4NetBlocksAndBestSearch19", SCRadixTestIPV4NetBlocksAndBestSearch19); + UtRegisterTest( + "SCRadixTestIPV6NetBlocksAndBestSearch20", SCRadixTestIPV6NetBlocksAndBestSearch20); + UtRegisterTest( + "SCRadixTestIPV6NetBlocksAndBestSearch21", SCRadixTestIPV6NetBlocksAndBestSearch21); + UtRegisterTest( + "SCRadixTestIPV6NetBlocksAndBestSearch22", SCRadixTestIPV6NetBlocksAndBestSearch22); + UtRegisterTest( + "SCRadixTestIPV6NetBlocksAndBestSearch23", SCRadixTestIPV6NetBlocksAndBestSearch23); + UtRegisterTest( + "SCRadixTestIPV6NetBlocksAndBestSearch24", SCRadixTestIPV6NetBlocksAndBestSearch24); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion25", SCRadixTestIPV4NetblockInsertion25); + UtRegisterTest("SCRadixTestIPV4NetblockInsertion26", SCRadixTestIPV4NetblockInsertion26); +#endif + + return; +} diff --git a/src/util/radix-tree.h b/src/util/radix-tree.h new file mode 100644 index 000000000000..de4a48a16c5e --- /dev/null +++ b/src/util/radix-tree.h @@ -0,0 +1,125 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_RADIX_TREE_H__ +#define __UTIL_RADIX_TREE_H__ + +#define SC_RADIX_BITTEST(x, y) ((x) & (y)) + +/** + * \brief Structure that hold the user data and the netmask associated with it. + */ +typedef struct SCRadixUserData_ { + /* holds a pointer to the user data associated with the particular netmask */ + void *user; + /* pointer to the next user data in the list */ + struct SCRadixUserData_ *next; + /* holds the netmask value that corresponds to this user data pointer */ + uint8_t netmask; +} SCRadixUserData; + +/** + * \brief Structure for the prefix/key in the radix tree + */ +typedef struct SCRadixPrefix_ { + /* length of the stream */ + uint16_t bitlen; + + /* the key that has been stored in the tree */ + uint8_t *stream; + + /* any user data that has to be associated with this key. We need a user + * data field for each netblock value possible since one ip can be associated + * with any of the 32 or 128 netblocks. Also for non-ips, we store the + * netmask as 255 in SCRadixUserData->netmask */ + SCRadixUserData *user_data; +} SCRadixPrefix; + +/** + * \brief Structure for the node in the radix tree + */ +typedef struct SCRadixNode_ { + /* the bit position where the bits differ in the nodes children. Used + * to determine the path to be taken during a lookup*/ + uint16_t bit; + + uint16_t pad0; + + /* total no of netmasks that are registered under this node */ + uint16_t netmask_cnt; + /* holds a list of netmasks that come under this node in the tree */ + uint8_t *netmasks; + + /* holds the prefix that the path to this node holds */ + SCRadixPrefix *prefix; + + /* the left and the right children of a node */ + struct SCRadixNode_ *left, *right; + + /* the parent node for this tree */ + struct SCRadixNode_ *parent; +} SCRadixNode; + +/** + * \brief Structure for the radix tree + */ +typedef struct SCRadixTree_ { + /* the root node in the radix tree */ + SCRadixNode *head; + + /* function pointer that is supplied by the user to free the user data + * held by the user field of SCRadixNode */ + void (*PrintData)(void *); + void (*Free)(void *); +} SCRadixTree; + +SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void *), void (*PrintData)(void *)); +void SCRadixReleaseRadixTree(SCRadixTree *); + +SCRadixNode *SCRadixAddKeyIPV4(uint8_t *, SCRadixTree *, void *); +SCRadixNode *SCRadixAddKeyIPV6(uint8_t *, SCRadixTree *, void *); +SCRadixNode *SCRadixAddKeyIPV4Netblock(uint8_t *, SCRadixTree *, void *, uint8_t); +SCRadixNode *SCRadixAddKeyIPV6Netblock(uint8_t *, SCRadixTree *, void *, uint8_t); +bool SCRadixAddKeyIPV4String(const char *, SCRadixTree *, void *); +bool SCRadixAddKeyIPV6String(const char *, SCRadixTree *, void *); + +void SCRadixRemoveKeyGeneric(uint8_t *, uint16_t, SCRadixTree *); +void SCRadixRemoveKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t); +void SCRadixRemoveKeyIPV4(uint8_t *, SCRadixTree *); +void SCRadixRemoveKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t); +void SCRadixRemoveKeyIPV6(uint8_t *, SCRadixTree *); + +SCRadixNode *SCRadixFindKeyIPV4ExactMatch(uint8_t *, SCRadixTree *, void **); +SCRadixNode *SCRadixFindKeyIPV4Netblock(uint8_t *, SCRadixTree *, uint8_t, void **); +SCRadixNode *SCRadixFindKeyIPV4BestMatch(uint8_t *, SCRadixTree *, void **); + +SCRadixNode *SCRadixFindKeyIPV6ExactMatch(uint8_t *, SCRadixTree *, void **); +SCRadixNode *SCRadixFindKeyIPV6Netblock(uint8_t *, SCRadixTree *, uint8_t, void **); +SCRadixNode *SCRadixFindKeyIPV6BestMatch(uint8_t *, SCRadixTree *, void **); + +void SCRadixPrintTree(SCRadixTree *); +void SCRadixPrintNodeInfo(SCRadixNode *, int, void (*PrintData)(void *)); + +void SCRadixRegisterTests(void); + +#endif /* __UTIL_RADIX_TREE_H__ */ diff --git a/src/util/random.c b/src/util/random.c new file mode 100644 index 000000000000..1adcf70b02f2 --- /dev/null +++ b/src/util/random.c @@ -0,0 +1,135 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Functions for getting a random value based on + * SEI CERT C Coding Standard MSC30-C + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util/random.h" +#include "util/debug.h" + +#if !(defined(HAVE_WINCRYPT_H) && defined(OS_WIN32)) +#if defined(HAVE_CLOCK_GETTIME) + +static long int RandomGetClock(void) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + // coverity[dont_call : FALSE] + srandom(ts.tv_nsec ^ ts.tv_sec); + long int value = random(); + return value; +} + +#else + +static long int RandomGetPosix(void) +{ + struct timeval tv; + memset(&tv, 0, sizeof(tv)); + gettimeofday(&tv, NULL); + + // coverity[dont_call : FALSE] + srandom(tv.tv_usec ^ tv.tv_sec); + long int value = random(); + return value; +} + +#endif +#endif /* !(defined(HAVE_WINCRYPT_H) && defined(OS_WIN32)) */ + +#if defined(HAVE_WINCRYPT_H) && defined(OS_WIN32) +#include + +long int RandomGet(void) +{ + if (g_disable_randomness) + return 0; + + HCRYPTPROV p; + if (!CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, 0)) { + DWORD err = GetLastError(); + SCLogDebug("CryptAcquireContext error: %" PRIu32, (uint32_t)err); + if (err == (DWORD)NTE_BAD_KEYSET) { + /* The key doesn't exist yet, create it */ + if (!CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + + SCLogDebug("CryptAcquireContext error: %" PRIu32, (uint32_t)err); + return -1; + } + } else { + return -1; + } + } + + long int value = 0; + if (!CryptGenRandom(p, sizeof(value), (BYTE *)&value)) { + (void)CryptReleaseContext(p, 0); + return -1; + } + + (void)CryptReleaseContext(p, 0); + + return value; +} +#elif defined(HAVE_GETRANDOM) +long int RandomGet(void) +{ + if (g_disable_randomness) + return 0; + + long int value = 0; + int ret = getrandom(&value, sizeof(value), 0); + /* ret should be sizeof(value), but if it is > 0 and < sizeof(value) + * it's still better than nothing so we return what we have */ + if (ret <= 0) { + if (ret == -1 && errno == ENOSYS) { +#if defined(HAVE_CLOCK_GETTIME) + return RandomGetClock(); +#else + return RandomGetPosix(); +#endif + } + return -1; + } + return value; +} +#elif defined(HAVE_CLOCK_GETTIME) +long int RandomGet(void) +{ + if (g_disable_randomness) + return 0; + + return RandomGetClock(); +} +#else +long int RandomGet(void) +{ + if (g_disable_randomness) + return 0; + + return RandomGetPosix(); +} +#endif diff --git a/src/util/random.h b/src/util/random.h new file mode 100644 index 000000000000..16e5569be111 --- /dev/null +++ b/src/util/random.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_RANDOM_H__ +#define __UTIL_RANDOM_H__ + +long int RandomGet(void); + +#endif /* __UTIL_RANDOM_H__ */ diff --git a/src/util/reference-config.c b/src/util/reference-config.c new file mode 100644 index 000000000000..932c115d2b03 --- /dev/null +++ b/src/util/reference-config.c @@ -0,0 +1,786 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata-common.h" +#include "../detect.h" +#include "detect-engine.h" +#include "util/hash.h" + +#include "util/reference-config.h" +#include "../conf.h" +#include "util/unittest.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/fmemopen.h" + +/* Regex to parse each line from reference.config file. The first substring + * is for the system name and the second for the url */ +/*-----------------------------------------------------------system-------------------url----*/ +#define SC_RCONF_REGEX "^\\s*config\\s+reference\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s+(.+)\\s*$" + +/* Default path for the reference.conf file */ +#define SC_RCONF_DEFAULT_FILE_PATH CONFIG_DIR "/reference.config" + +/* the hash functions */ +uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen); +char SCRConfReferenceHashCompareFunc( + void *data1, uint16_t datalen1, void *data2, uint16_t datalen2); +void SCRConfReferenceHashFree(void *ch); + +/* used to get the reference.config file path */ +static const char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx); + +void SCReferenceConfInit(DetectEngineCtx *de_ctx) +{ + int en; + PCRE2_SIZE eo; + int opts = 0; + + de_ctx->reference_conf_regex = + pcre2_compile((PCRE2_SPTR8)SC_RCONF_REGEX, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + if (de_ctx->reference_conf_regex == NULL) { + PCRE2_UCHAR errbuffer[256]; + pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); + SCLogWarning("pcre2 compile of \"%s\" failed at " + "offset %d: %s", + SC_RCONF_REGEX, (int)eo, errbuffer); + return; + } + de_ctx->reference_conf_regex_match = + pcre2_match_data_create_from_pattern(de_ctx->reference_conf_regex, NULL); + return; +} + +void SCReferenceConfDeinit(DetectEngineCtx *de_ctx) +{ + if (de_ctx->reference_conf_regex != NULL) { + pcre2_code_free(de_ctx->reference_conf_regex); + de_ctx->reference_conf_regex = NULL; + } + if (de_ctx->reference_conf_regex_match != NULL) { + pcre2_match_data_free(de_ctx->reference_conf_regex_match); + de_ctx->reference_conf_regex_match = NULL; + } +} + +/** + * \brief Inits the context to be used by the Reference Config parsing API. + * + * This function initializes the hash table to be used by the Detection + * Engine Context to hold the data from reference.config file, + * obtains the file descriptor to parse the reference.config file, and + * inits the regex used to parse the lines from reference.config file. + * + * \param de_ctx Pointer to the Detection Engine Context. + * + * \note if file open fails, we leave de_ctx->reference_conf_ht initialized + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) +{ + /* init the hash table to be used by the reference config references */ + de_ctx->reference_conf_ht = HashTableInit(128, SCRConfReferenceHashFunc, + SCRConfReferenceHashCompareFunc, SCRConfReferenceHashFree); + if (de_ctx->reference_conf_ht == NULL) { + SCLogError("Error initializing the hash " + "table"); + return NULL; + } + + /* if it is not NULL, use the file descriptor. The hack so that we can + * avoid using a dummy reference file for testing purposes and + * instead use an input stream against a buffer containing the + * reference strings */ + if (fd == NULL) { + const char *filename = SCRConfGetConfFilename(de_ctx); + if ((fd = fopen(filename, "r")) == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) { + return NULL; // silently fail + } +#endif + SCLogError("Error opening file: \"%s\": %s", filename, strerror(errno)); + return NULL; + } + } + + return fd; +} + +/** + * \brief Returns the path for the Reference Config file. We check if we + * can retrieve the path from the yaml conf file. If it is not present, + * return the default path for the reference.config file which is + * "./reference.config". + * + * \retval log_filename Pointer to a string containing the path for the + * reference.config file. + */ +static const char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx) +{ + const char *path = NULL; + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; + snprintf(config_value, sizeof(config_value), "%s.reference-config-file", + de_ctx->config_prefix); + + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &path) != 1) { + if (ConfGet("reference-config-file", &path) != 1) { + return (char *)SC_RCONF_DEFAULT_FILE_PATH; + } + } + } else { + if (ConfGet("reference-config-file", &path) != 1) { + return (char *)SC_RCONF_DEFAULT_FILE_PATH; + } + } + return path; +} + +/** + * \brief Releases local resources used by the Reference Config API. + */ +static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) +{ + if (fd != NULL) { + fclose(fd); + } + + return; +} + +/** + * \brief Releases de_ctx resources related to Reference Config API. + */ +void SCRConfDeInitContext(DetectEngineCtx *de_ctx) +{ + if (de_ctx->reference_conf_ht != NULL) + HashTableFree(de_ctx->reference_conf_ht); + + de_ctx->reference_conf_ht = NULL; + + return; +} + +/** + * \brief Converts a string to lowercase. + * + * \param str Pointer to the string to be converted. + */ +static char *SCRConfStringToLowercase(const char *str) +{ + char *new_str = NULL; + char *temp_str = NULL; + + if ((new_str = SCStrdup(str)) == NULL) { + return NULL; + } + + temp_str = new_str; + while (*temp_str != '\0') { + *temp_str = u8_tolower((unsigned char)*temp_str); + temp_str++; + } + + return new_str; +} + +/** + * \brief Parses a line from the reference config file and adds it to Reference + * Config hash table DetectEngineCtx->reference_conf_ht. + * + * \param rawstr Pointer to the string to be parsed. + * \param de_ctx Pointer to the Detection Engine Context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCRConfAddReference(DetectEngineCtx *de_ctx, const char *line) +{ + char system[REFERENCE_SYSTEM_NAME_MAX]; + char url[REFERENCE_CONTENT_NAME_MAX]; + + SCRConfReference *ref_new = NULL; + SCRConfReference *ref_lookup = NULL; + + int ret = 0; + + ret = pcre2_match(de_ctx->reference_conf_regex, (PCRE2_SPTR8)line, strlen(line), 0, 0, + de_ctx->reference_conf_regex_match, NULL); + if (ret < 0) { + SCLogError("Invalid Reference Config in " + "reference.config file"); + goto error; + } + + /* retrieve the reference system */ + size_t copylen = sizeof(system); + ret = pcre2_substring_copy_bynumber( + de_ctx->reference_conf_regex_match, 1, (PCRE2_UCHAR8 *)system, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber() failed"); + goto error; + } + + /* retrieve the reference url */ + copylen = sizeof(url); + ret = pcre2_substring_copy_bynumber( + de_ctx->reference_conf_regex_match, 2, (PCRE2_UCHAR8 *)url, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber() failed"); + goto error; + } + + /* Create a new instance of the parsed Reference string */ + ref_new = SCRConfAllocSCRConfReference(system, url); + if (ref_new == NULL) + goto error; + + /* Check if the Reference is present in the HashTable. In case it's present + * ignore it, as it's a duplicate. If not present, add it to the table */ + ref_lookup = HashTableLookup(de_ctx->reference_conf_ht, ref_new, 0); + if (ref_lookup == NULL) { + if (HashTableAdd(de_ctx->reference_conf_ht, ref_new, 0) < 0) { + SCLogDebug("HashTable Add failed"); + } + } else { + SCLogDebug("Duplicate reference found inside reference.config"); + SCRConfDeAllocSCRConfReference(ref_new); + } + + return 0; + +error: + return -1; +} + +/** + * \brief Checks if a string is a comment or a blank line. + * + * Comments lines are lines of the following format - + * "# This is a comment string" or + * " # This is a comment string". + * + * \param line String that has to be checked. + * + * \retval 1 On the argument string being a comment or blank line. + * \retval 0 Otherwise. + */ +static int SCRConfIsLineBlankOrComment(char *line) +{ + while (*line != '\0') { + /* we have a comment */ + if (*line == '#') + return 1; + + /* this line is neither a comment line, nor a blank line */ + if (!isspace((unsigned char)*line)) + return 0; + + line++; + } + + /* we have a blank line */ + return 1; +} + +/** + * \brief Parses the Reference Config file and updates the + * DetectionEngineCtx->reference_conf_ht with the Reference information. + * + * \param de_ctx Pointer to the Detection Engine Context. + */ +static bool SCRConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) +{ + char line[1024]; + int runmode = RunmodeGetCurrent(); + bool is_conf_test_mode = runmode == RUNMODE_CONF_TEST; + while (fgets(line, sizeof(line), fd) != NULL) { + if (SCRConfIsLineBlankOrComment(line)) + continue; + + if (SCRConfAddReference(de_ctx, line) != 0) { + if (is_conf_test_mode) { + return false; + } + } + } + +#ifdef UNITTESTS + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) + SCLogInfo("tenant id %d: Added \"%d\" reference types from the reference.config file", + de_ctx->tenant_id, de_ctx->reference_conf_ht->count); + else + SCLogInfo("Added \"%d\" reference types from the reference.config file", + de_ctx->reference_conf_ht->count); +#endif /* UNITTESTS */ + return true; +} + +/** + * \brief Returns a new SCRConfReference instance. The reference string + * is converted into lowercase, before being assigned to the instance. + * + * \param system Pointer to the system. + * \param url Pointer to the reference url. + * + * \retval ref Pointer to the new instance of SCRConfReference. + */ +SCRConfReference *SCRConfAllocSCRConfReference(const char *system, const char *url) +{ + SCRConfReference *ref = NULL; + + if (system == NULL) { + SCLogError("Invalid arguments. system NULL"); + return NULL; + } + + if ((ref = SCCalloc(1, sizeof(SCRConfReference))) == NULL) { + return NULL; + } + + if ((ref->system = SCRConfStringToLowercase(system)) == NULL) { + SCFree(ref); + return NULL; + } + + if (url != NULL && (ref->url = SCStrdup(url)) == NULL) { + SCFree(ref->system); + SCFree(ref); + return NULL; + } + + return ref; +} + +/** + * \brief Frees a SCRConfReference instance. + * + * \param Pointer to the SCRConfReference instance that has to be freed. + */ +void SCRConfDeAllocSCRConfReference(SCRConfReference *ref) +{ + if (ref != NULL) { + if (ref->system != NULL) + SCFree(ref->system); + + if (ref->url != NULL) + SCFree(ref->url); + + SCFree(ref); + } + + return; +} + +/** + * \brief Hashing function to be used to hash the Reference name. Would be + * supplied as an argument to the HashTableInit function for + * DetectEngineCtx->reference_conf_ht. + * + * \param ht Pointer to the HashTable. + * \param data Pointer to the data to be hashed. In this case, the data + * would be a pointer to a SCRConfReference instance. + * \param datalen Not used by this function. + */ +uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen) +{ + SCRConfReference *ref = (SCRConfReference *)data; + uint32_t hash = 0; + int i = 0; + + int len = strlen(ref->system); + + for (i = 0; i < len; i++) + hash += u8_tolower((unsigned char)ref->system[i]); + + hash = hash % ht->array_size; + + return hash; +} + +/** + * \brief Used to compare two References that have been stored in the HashTable. + * This function is supplied as an argument to the HashTableInit function + * for DetectionEngineCtx->reference_conf_ct. + * + * \param data1 Pointer to the first SCRConfReference to be compared. + * \param len1 Not used by this function. + * \param data2 Pointer to the second SCRConfReference to be compared. + * \param len2 Not used by this function. + * + * \retval 1 On data1 and data2 being equal. + * \retval 0 On data1 and data2 not being equal. + */ +char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2) +{ + SCRConfReference *ref1 = (SCRConfReference *)data1; + SCRConfReference *ref2 = (SCRConfReference *)data2; + int len1 = 0; + int len2 = 0; + + if (ref1 == NULL || ref2 == NULL) + return 0; + + if (ref1->system == NULL || ref2->system == NULL) + return 0; + + len1 = strlen(ref1->system); + len2 = strlen(ref2->system); + + if (len1 == len2 && memcmp(ref1->system, ref2->system, len1) == 0) { + SCLogDebug("Match found inside Reference-Config hash function"); + return 1; + } + + return 0; +} + +/** + * \brief Used to free the Reference Config Hash Data that was stored in + * DetectEngineCtx->reference_conf_ht Hashtable. + * + * \param data Pointer to the data that has to be freed. + */ +void SCRConfReferenceHashFree(void *data) +{ + SCRConfDeAllocSCRConfReference(data); + + return; +} + +/** + * \brief Loads the Reference info from the reference.config file. + * + * The reference.config file contains references that can be used in + * Signatures. Each line of the file should have the following format - + * config reference: system_name, reference_url. + * + * \param de_ctx Pointer to the Detection Engine Context that should be updated + * with reference information. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx, FILE *fd) +{ + fd = SCRConfInitContextAndLocalResources(de_ctx, fd); + if (fd == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) { + return -1; + } +#endif + SCLogError("please check the \"reference-config-file\" " + "option in your suricata.yaml file"); + return -1; + } + + bool rc = SCRConfParseFile(de_ctx, fd); + SCRConfDeInitLocalResources(de_ctx, fd); + + return rc ? 0 : -1; +} + +/** + * \brief Gets the reference config from the corresponding hash table stored + * in the Detection Engine Context's reference conf ht, given the + * reference name. + * + * \param ct_name Pointer to the reference name that has to be looked up. + * \param de_ctx Pointer to the Detection Engine Context. + * + * \retval lookup_rconf_info Pointer to the SCRConfReference instance from + * the hash table on success; NULL on failure. + */ +SCRConfReference *SCRConfGetReference(const char *rconf_name, DetectEngineCtx *de_ctx) +{ + SCRConfReference *ref_conf = SCRConfAllocSCRConfReference(rconf_name, NULL); + if (ref_conf == NULL) + return NULL; + SCRConfReference *lookup_ref_conf = HashTableLookup(de_ctx->reference_conf_ht, ref_conf, 0); + + SCRConfDeAllocSCRConfReference(ref_conf); + return lookup_ref_conf; +} + +/*----------------------------------Unittests---------------------------------*/ + +#ifdef UNITTESTS + +/** + * \brief Creates a dummy reference config, with all valid references, for + * testing purposes. + */ +FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void) +{ + const char *buffer = "config reference: one http://www.one.com\n" + "config reference: two http://www.two.com\n" + "config reference: three http://www.three.com\n" + "config reference: one http://www.one.com\n" + "config reference: three http://www.three.com\n"; + + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy reference config, with some valid references and a + * couple of invalid references, for testing purposes. + */ +FILE *SCRConfGenerateInvalidDummyReferenceConfigFD02(void) +{ + const char *buffer = "config reference: one http://www.one.com\n" + "config_ reference: two http://www.two.com\n" + "config reference_: three http://www.three.com\n" + "config reference: four\n" + "config reference five http://www.five.com\n"; + + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy reference config, with all invalid references, for + * testing purposes. + */ +FILE *SCRConfGenerateInvalidDummyReferenceConfigFD03(void) +{ + const char *buffer = "config reference one http://www.one.com\n" + "config_ reference: two http://www.two.com\n" + "config reference_: three http://www.three.com\n" + "config reference: four\n"; + + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); + + return fd; +} + +/** + * \test Check that the reference file is loaded and the detection engine + * content reference_conf_ht loaded with the reference data. + */ +static int SCRConfTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 0; + + if (de_ctx == NULL) + return result; + + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); + + if (de_ctx->reference_conf_ht == NULL) + goto end; + + result = (de_ctx->reference_conf_ht->count == 3); + if (result == 0) + printf("FAILED: de_ctx->reference_conf_ht->count %u: ", de_ctx->reference_conf_ht->count); + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check that invalid references present in the reference.config file + * aren't loaded. + */ +static int SCRConfTest02(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 0; + + if (de_ctx == NULL) + return result; + + FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD03(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); + + if (de_ctx->reference_conf_ht == NULL) + goto end; + + result = (de_ctx->reference_conf_ht->count == 0); + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check that only valid references are loaded into the hash table from + * the reference.config file. + */ +static int SCRConfTest03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 0; + + if (de_ctx == NULL) + return result; + + FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD02(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); + + if (de_ctx->reference_conf_ht == NULL) + goto end; + + result = (de_ctx->reference_conf_ht->count == 1); + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check if the reference info from the reference.config file have + * been loaded into the hash table. + */ +static int SCRConfTest04(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 1; + + if (de_ctx == NULL) + return 0; + + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); + + if (de_ctx->reference_conf_ht == NULL) + goto end; + + result = (de_ctx->reference_conf_ht->count == 3); + + result &= (SCRConfGetReference("one", de_ctx) != NULL); + result &= (SCRConfGetReference("two", de_ctx) != NULL); + result &= (SCRConfGetReference("three", de_ctx) != NULL); + result &= (SCRConfGetReference("four", de_ctx) == NULL); + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check if the reference info from the invalid reference.config file + * have not been loaded into the hash table, and cross verify to check + * that the hash table contains no reference data. + */ +static int SCRConfTest05(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 1; + + if (de_ctx == NULL) + return 0; + + FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD03(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); + + if (de_ctx->reference_conf_ht == NULL) + goto end; + + result = (de_ctx->reference_conf_ht->count == 0); + + result &= (SCRConfGetReference("one", de_ctx) == NULL); + result &= (SCRConfGetReference("two", de_ctx) == NULL); + result &= (SCRConfGetReference("three", de_ctx) == NULL); + result &= (SCRConfGetReference("four", de_ctx) == NULL); + result &= (SCRConfGetReference("five", de_ctx) == NULL); + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check if the reference info from the reference.config file have + * been loaded into the hash table. + */ +static int SCRConfTest06(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + int result = 1; + + if (de_ctx == NULL) + return 0; + + FILE *fd = SCRConfGenerateInvalidDummyReferenceConfigFD02(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); + + if (de_ctx->reference_conf_ht == NULL) + goto end; + + result = (de_ctx->reference_conf_ht->count == 1); + + result &= (SCRConfGetReference("one", de_ctx) != NULL); + result &= (SCRConfGetReference("two", de_ctx) == NULL); + result &= (SCRConfGetReference("three", de_ctx) == NULL); + result &= (SCRConfGetReference("four", de_ctx) == NULL); + result &= (SCRConfGetReference("five", de_ctx) == NULL); + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif /* UNITTESTS */ + +/** + * \brief This function registers unit tests for Reference Config API. + */ +void SCRConfRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("SCRConfTest01", SCRConfTest01); + UtRegisterTest("SCRConfTest02", SCRConfTest02); + UtRegisterTest("SCRConfTest03", SCRConfTest03); + UtRegisterTest("SCRConfTest04", SCRConfTest04); + UtRegisterTest("SCRConfTest05", SCRConfTest05); + UtRegisterTest("SCRConfTest06", SCRConfTest06); +#endif /* UNITTESTS */ + + return; +} diff --git a/src/util/reference-config.h b/src/util/reference-config.h new file mode 100644 index 000000000000..6f7c9f6a188a --- /dev/null +++ b/src/util/reference-config.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_REFERENCE_CONFIG_H__ +#define __UTIL_REFERENCE_CONFIG_H__ + +#include "../detect.h" + +#define REFERENCE_SYSTEM_NAME_MAX 64 +#define REFERENCE_CONTENT_NAME_MAX 1024 + +/** + * \brief Holds a reference from the file - reference.config. + */ +typedef struct SCRConfReference_ { + /* The system name. This is the primary key for a reference. */ + char *system; + /* The url for the above reference */ + char *url; +} SCRConfReference; + +SCRConfReference *SCRConfAllocSCRConfReference(const char *, const char *); +void SCRConfDeAllocSCRConfReference(SCRConfReference *); +int SCRConfLoadReferenceConfigFile(DetectEngineCtx *, FILE *); +void SCRConfDeInitContext(DetectEngineCtx *); +SCRConfReference *SCRConfGetReference(const char *, DetectEngineCtx *); +int SCRConfAddReference(DetectEngineCtx *de_ctx, const char *line); +void SCRConfRegisterTests(void); + +/* these below functions are only used by unittests */ +FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void); +FILE *SCRConfGenerateInvalidDummyReferenceConfigFD02(void); +FILE *SCRConfGenerateInvalidDummyReferenceConfigFD03(void); + +void SCReferenceConfInit(DetectEngineCtx *de_ctx); +void SCReferenceConfDeinit(DetectEngineCtx *de_ctx); + +#endif /* __UTIL_REFERENCE_CONFIG_H__ */ diff --git a/src/util/rohash.c b/src/util/rohash.c new file mode 100644 index 000000000000..04028a9bddf4 --- /dev/null +++ b/src/util/rohash.c @@ -0,0 +1,248 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Chained read only hash table implementation, meaning that + * after the initial fill no changes are allowed. + * + * Loading takes 2 stages. + * - stage1 maps data + * - stage2 fills blob + * + * \todo a bloomfilter in the ROHashTableOffsets could possibly prevent + * a lot of cache misses when validating a potential match + * + * \todo maybe add a user ctx to be returned instead, something like a + * 4/8 byte ptr or simply a flag + */ + +#include "suricata-common.h" +#include "util/hash.h" +#include "util/unittest.h" +#include "util/memcmp.h" +#include "util/hash-lookup3.h" +#include "util/rohash.h" +#include "util/debug.h" + +/** item_size data beyond this header */ +typedef struct ROHashTableItem_ { + uint32_t pos; /**< position relative to other values with same hash */ + TAILQ_ENTRY(ROHashTableItem_) next; +} ROHashTableItem; + +/** offset table */ +typedef struct ROHashTableOffsets_ { + uint32_t cnt; /**< number of items for this hash */ + uint32_t offset; /**< position in the blob of the first item */ +} ROHashTableOffsets; + +/** \brief initialize a new rohash + * + * \param hash_bits hash size as 2^hash_bits, so power of 2, max 31 + * \param item_size size of the data to store + * + * \retval table ptr or NULL on error + */ +ROHashTable *ROHashInit(uint8_t hash_bits, uint16_t item_size) +{ + if (item_size % 4 != 0 || item_size == 0) { + SCLogError("data size must be multiple of 4"); + return NULL; + } + if (hash_bits < 4 || hash_bits > 31) { + SCLogError("invalid hash_bits setting, valid range is 4-31"); + return NULL; + } + + uint32_t size = hashsize(hash_bits) * sizeof(ROHashTableOffsets); + + ROHashTable *table = SCCalloc(1, sizeof(ROHashTable) + size); + if (unlikely(table == NULL)) { + SCLogError("failed to alloc memory"); + return NULL; + } + + table->items = 0; + table->item_size = item_size; + table->hash_bits = hash_bits; + TAILQ_INIT(&table->head); + + return table; +} + +void ROHashFree(ROHashTable *table) +{ + if (table != NULL) { + if (table->data != NULL) { + SCFree(table->data); + } + + SCFree(table); + } +} + +uint32_t ROHashMemorySize(ROHashTable *table) +{ + uint32_t r1 = hashsize(table->hash_bits) * sizeof(ROHashTableOffsets); + uint32_t r2 = table->items * table->item_size; + return (uint32_t)(r1 + r2 + sizeof(ROHashTable)); +} + +/** + * \retval NULL not found + * \retval ptr found + */ +void *ROHashLookup(ROHashTable *table, void *data, uint16_t size) +{ + if (data == NULL || size != table->item_size) { + SCReturnPtr(NULL, "void"); + } + + uint32_t hash = hashword(data, table->item_size / 4, 0) & hashmask(table->hash_bits); + + /* get offsets start */ + ROHashTableOffsets *os = (void *)table + sizeof(ROHashTable); + ROHashTableOffsets *o = &os[hash]; + + /* no matches */ + if (o->cnt == 0) { + SCReturnPtr(NULL, "void"); + } + + uint32_t u; + for (u = 0; u < o->cnt; u++) { + uint32_t offset = (o->offset + u) * table->item_size; + + if (SCMemcmp(table->data + offset, data, table->item_size) == 0) { + SCReturnPtr(table->data + offset, "void"); + } + } + SCReturnPtr(NULL, "void"); +} + +/** \brief Add a new value to the hash + * + * \note can only be done when table isn't in a locked state yet + * + * \param table the hash table + * \param value value to add + * \param size value size. *MUST* match table item_size + * + * \retval 0 error + * \retval 1 ok + */ +int ROHashInitQueueValue(ROHashTable *table, void *value, uint16_t size) +{ + if (table->locked) { + SCLogError("can't add value to locked table"); + return 0; + } + if (table->item_size != size) { + SCLogError("wrong size for data %u != %u", size, table->item_size); + return 0; + } + + ROHashTableItem *item = SCCalloc(1, sizeof(ROHashTableItem) + table->item_size); + if (item != NULL) { + memcpy((void *)item + sizeof(ROHashTableItem), value, table->item_size); + TAILQ_INSERT_TAIL(&table->head, item, next); + return 1; + } + + return 0; +} + +/** \brief create final hash data structure + * + * \param table the hash table + * + * \retval 0 error + * \retval 1 ok + * + * \note after this call the nothing can be added to the hash anymore. + */ +int ROHashInitFinalize(ROHashTable *table) +{ + if (table->locked) { + SCLogError("table already locked"); + return 0; + } + + ROHashTableItem *item = NULL; + ROHashTableOffsets *os = (void *)table + sizeof(ROHashTable); + + /* count items per hash value */ + TAILQ_FOREACH (item, &table->head, next) { + uint32_t hash = hashword((void *)item + sizeof(*item), table->item_size / 4, 0) & + hashmask(table->hash_bits); + ROHashTableOffsets *o = &os[hash]; + + item->pos = o->cnt; + o->cnt++; + table->items++; + } + + if (table->items == 0) { + SCLogError("no items"); + return 0; + } + + /* get the data block */ + uint32_t newsize = table->items * table->item_size; + table->data = SCCalloc(1, newsize); + if (table->data == NULL) { + SCLogError("failed to alloc memory"); + return 0; + } + + /* calc offsets into the block per hash value */ + uint32_t total = 0; + uint32_t x; + for (x = 0; x < hashsize(table->hash_bits); x++) { + ROHashTableOffsets *o = &os[x]; + + if (o->cnt == 0) + continue; + + o->offset = total; + total += o->cnt; + } + + /* copy each value into the data block */ + TAILQ_FOREACH (item, &table->head, next) { + uint32_t hash = hashword((void *)item + sizeof(*item), table->item_size / 4, 0) & + hashmask(table->hash_bits); + + ROHashTableOffsets *o = &os[hash]; + uint32_t offset = (o->offset + item->pos) * table->item_size; + + memcpy(table->data + offset, (void *)item + sizeof(*item), table->item_size); + } + + /* clean up temp items */ + while ((item = TAILQ_FIRST(&table->head))) { + TAILQ_REMOVE(&table->head, item, next); + SCFree(item); + } + + table->locked = 1; + return 1; +} diff --git a/src/util/rohash.h b/src/util/rohash.h new file mode 100644 index 000000000000..1f86aecc53a8 --- /dev/null +++ b/src/util/rohash.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_ROHASH_H__ +#define __UTIL_ROHASH_H__ + +typedef struct ROHashTable_ { + uint8_t locked; + uint8_t hash_bits; + uint16_t item_size; + uint32_t items; + void *data; + TAILQ_HEAD(, ROHashTableItem_) head; +} ROHashTable; + +/* init time */ +ROHashTable *ROHashInit(uint8_t hash_bits, uint16_t item_size); +int ROHashInitFinalize(ROHashTable *table); +void ROHashFree(ROHashTable *table); +int ROHashInitQueueValue(ROHashTable *table, void *value, uint16_t size); +uint32_t ROHashMemorySize(ROHashTable *table); + +/* run time */ +void *ROHashLookup(ROHashTable *table, void *data, uint16_t size); + +#endif /* __UTIL_ROHASH_H__ */ diff --git a/src/util/rule-vars.c b/src/util/rule-vars.c new file mode 100644 index 000000000000..c7dcd401e44e --- /dev/null +++ b/src/util/rule-vars.c @@ -0,0 +1,406 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + * + * Rule variable utility functions + */ + +#include "suricata-common.h" +#include "../conf.h" +#include "conf-yaml-loader.h" + +#include "../detect.h" +#include "detect-content.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" + +#include "util/rule-vars.h" +#include "util/enum.h" +#include "util/debug.h" +#include "util/unittest.h" + +/** An enum-string map, that maps the different vars type in the yaml conf + * type with the mapping path in the yaml conf file */ +SCEnumCharMap sc_rule_vars_type_map[] = { { "vars.address-groups", SC_RULE_VARS_ADDRESS_GROUPS }, + { "vars.port-groups", SC_RULE_VARS_PORT_GROUPS } }; + +/** + * \internal + * \brief Retrieves a value for a yaml mapping. The sequence from the yaml + * conf file, from which the conf value has to be retrieved can be + * specified by supplying a SCRuleVarsType enum. The string mapping + * for each of the SCRuleVarsType is present in sc_rule_vars_type_map. + * + * \param conf_var_name Pointer to a character string containing the conf var + * name, whose value has to be retrieved from the yaml + * conf file. + * \param conf_vars_type Holds an enum value that indicates the kind of yaml + * mapping that has to be retrieved. Can be one of the + * values in SCRuleVarsType. + * + * \retval conf_var_name_value Pointer to the string containing the conf value + * on success; NULL on failure. + */ +const char *SCRuleVarsGetConfVar( + const DetectEngineCtx *de_ctx, const char *conf_var_name, SCRuleVarsType conf_vars_type) +{ + SCEnter(); + + const char *conf_var_type_name = NULL; + char conf_var_full_name[2048]; + const char *conf_var_full_name_value = NULL; + + if (conf_var_name == NULL) + goto end; + + while (conf_var_name[0] != '\0' && isspace((unsigned char)conf_var_name[0])) { + conf_var_name++; + } + + (conf_var_name[0] == '$') ? conf_var_name++ : conf_var_name; + conf_var_type_name = SCMapEnumValueToName(conf_vars_type, sc_rule_vars_type_map); + if (conf_var_type_name == NULL) + goto end; + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s.%s", + de_ctx->config_prefix, conf_var_type_name, conf_var_name) < 0) { + goto end; + } + } else { + if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s", conf_var_type_name, + conf_var_name) < 0) { + goto end; + } + } + + if (ConfGet(conf_var_full_name, &conf_var_full_name_value) != 1) { + SCLogError("Variable \"%s\" is not defined in " + "configuration file", + conf_var_name); + goto end; + } + + SCLogDebug("Value obtained from the yaml conf file, for the var " + "\"%s\" is \"%s\"", + conf_var_name, conf_var_full_name_value); + +end: + SCReturnCharPtr(conf_var_full_name_value); +} + +/**********************************Unittests***********************************/ +#ifdef UNITTESTS + +static const char *dummy_conf_string = + "%YAML 1.1\n" + "---\n" + "\n" + "default-log-dir: /var/log/suricata\n" + "\n" + "logging:\n" + "\n" + " default-log-level: debug\n" + "\n" + " default-format: \"<%t> - <%l>\"\n" + "\n" + " default-startup-message: Your IDS has started.\n" + "\n" + " default-output-filter:\n" + "\n" + " output:\n" + "\n" + " - interface: console\n" + " log-level: info\n" + "\n" + " - interface: file\n" + " filename: /var/log/suricata.log\n" + "\n" + " - interface: syslog\n" + " facility: local5\n" + " format: \"%l\"\n" + "\n" + "pfring:\n" + "\n" + " interface: eth0\n" + "\n" + " clusterid: 99\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" + "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" + "\n" + " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" + "\n" + " HTTP_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " SMTP_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " SQL_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " DNS_SERVERS: any\n" + "\n" + " TELNET_SERVERS: any\n" + "\n" + " AIM_SERVERS: any\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"80:81,88\"\n" + "\n" + " SHELLCODE_PORTS: 80\n" + "\n" + " ORACLE_PORTS: 1521\n" + "\n" + " SSH_PORTS: 22\n" + "\n"; + +/** + * \test Check that valid address and port group vars are correctly retrieved + * from the configuration. + */ +static int SCRuleVarsPositiveTest01(void) +{ + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + + /* check for address-groups */ + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:13c5:" + "5AFE::/64,2001:888:13c5:CAFE::/64]") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[!192.168.0.0/16,2000::/3]") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "!192.168.0.0/16") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "!192.168.0.0/16") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "!192.168.0.0/16") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "any") == 0); + FAIL_IF_NOT( + SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "any") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "any") == 0); + + /* Test that a leading space is stripped. */ + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "any") == 0); + + /* check for port-groups */ + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + "80:81,88") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS), + "80") == 0); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS), + "1521") == 0); + FAIL_IF_NOT( + SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), "22") == 0); + + ConfDeInit(); + ConfRestoreContextBackup(); + PASS; +} + +/** + * \test Check that invalid address and port groups are properly handled by the + * API. + */ +static int SCRuleVarsNegativeTest02(void) +{ + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL); + FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL); + + ConfDeInit(); + ConfRestoreContextBackup(); + PASS; +} + +/** + * \test Check that Signatures with valid address and port groups are parsed + * without any errors by the Signature parsing API. + */ +static int SCRuleVarsPositiveTest03(void) +{ + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp [$HTTP_SERVERS,$HOME_NET,192.168.2.5] $HTTP_PORTS -> $EXTERNAL_NET " + "[80,[!$HTTP_PORTS,$ORACLE_PORTS]] (msg:\"Rule Vars Test\"; sid:1;)"); + FAIL_IF_NULL(s); + + ConfDeInit(); + ConfRestoreContextBackup(); + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check that Signatures with invalid address and port groups, are + * are invalidated by the Signature parsing API. + */ +static int SCRuleVarsNegativeTest04(void) +{ + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig( + de_ctx, "alert tcp $HTTP_SERVER any -> any any (msg:\"Rule Vars Test\"; sid:1;)"); + FAIL_IF_NOT_NULL(s); + s = DetectEngineAppendSig( + de_ctx, "alert tcp $http_servers any -> any any (msg:\"Rule Vars Test\"; sid:1;)"); + FAIL_IF_NOT_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp $http_servers any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); + FAIL_IF_NOT_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp !$TELNET_SERVERS !80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)"); + FAIL_IF_NOT_NULL(s); + + DetectEngineCtxFree(de_ctx); + ConfDeInit(); + ConfRestoreContextBackup(); + PASS; +} + +static const char *dummy_mt_conf_string = "%YAML 1.1\n" + "---\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[1.2.3.4]\"\n" + " port-groups:\n" + " HTTP_PORTS: \"12345\"\n" + "multi-detect:\n" + " 0:\n" + " vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[8.8.8.8]\"\n" + " port-groups:\n" + " HTTP_PORTS: \"54321\"\n" + "\n"; + +/** + * \test Check that valid address and port group vars are correctly retrieved + * from the configuration. + */ +static int SCRuleVarsMTest01(void) +{ + int result = 0; + DetectEngineCtx *de_ctx = NULL; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_mt_conf_string, strlen(dummy_mt_conf_string)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) + return 0; + de_ctx->flags |= DE_QUIET; + snprintf(de_ctx->config_prefix, sizeof(de_ctx->config_prefix), "multi-detect.0"); + + /* check for address-groups */ + result = (SCRuleVarsGetConfVar(de_ctx, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(de_ctx, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[8.8.8.8]") == 0); + if (result == 0) + goto end; + + result = (SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[1.2.3.4]") == 0); + if (result == 0) + goto end; + + /* check for port-groups */ + result = (SCRuleVarsGetConfVar(de_ctx, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(de_ctx, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + "54321") == 0); + if (result == 0) + goto end; + + result = (SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + "12345") == 0); + if (result == 0) + goto end; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif /* UNITTESTS */ + +void SCRuleVarsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01); + UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02); + UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03); + UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04); + + UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01); +#endif + + return; +} diff --git a/src/util/rule-vars.h b/src/util/rule-vars.h new file mode 100644 index 000000000000..d183f5848271 --- /dev/null +++ b/src/util/rule-vars.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#ifndef __UTIL_RULE_VARS_H__ +#define __UTIL_RULE_VARS_H__ + +#include "../detect.h" + +/** Enum indicating the various vars type in the yaml conf file */ +typedef enum { + SC_RULE_VARS_ADDRESS_GROUPS, + SC_RULE_VARS_PORT_GROUPS, +} SCRuleVarsType; + +const char *SCRuleVarsGetConfVar(const DetectEngineCtx *, const char *, SCRuleVarsType); +void SCRuleVarsRegisterTests(void); + +#endif /* __UTIL_RULE_VARS_H__ */ diff --git a/src/util/runmodes.c b/src/util/runmodes.c new file mode 100644 index 000000000000..1980ea1283de --- /dev/null +++ b/src/util/runmodes.c @@ -0,0 +1,532 @@ +/* Copyright (C) 2011-2019 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + * + * Helper function for runmode. + * + */ + +#include "suricata-common.h" +#include "tm-threads.h" +#include "../conf.h" +#include "runmodes.h" +#include "runmode-af-packet.h" +#include "output/output.h" +#include "app-layer/http/log-httplog.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" + +#include "alert-fastlog.h" +#include "alert-debuglog.h" + +#include "util/debug.h" +#include "util/time.h" +#include "util/cpu.h" +#include "util/affinity.h" +#include "util/device.h" + +#include "util/runmodes.h" + +#include "flow-hash.h" + +/** \brief create a queue string for autofp to pass to + * the flow queue handler. + * + * The string will be "pickup1,pickup2,pickup3\0" + */ +char *RunmodeAutoFpCreatePickupQueuesString(int n) +{ + if (n > 1024) + return NULL; + + /* 13 because pickup12345, = 12 + \0 */ + size_t queues_size = n * 13; + char qname[TM_QUEUE_NAME_MAX]; + + char *queues = SCCalloc(1, queues_size); + if (unlikely(queues == NULL)) { + SCLogError("failed to alloc queues buffer: %s", strerror(errno)); + return NULL; + } + + for (int thread = 0; thread < n; thread++) { + if (strlen(queues) > 0) + strlcat(queues, ",", queues_size); + + snprintf(qname, sizeof(qname), "pickup%d", (int16_t)thread + 1); + strlcat(queues, qname, queues_size); + } + + SCLogDebug("%d %" PRIuMAX ", queues %s", n, (uintmax_t)queues_size, queues); + return queues; +} + +/** + */ +int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, + ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev) +{ + char tname[TM_THREAD_NAME_MAX]; + char qname[TM_QUEUE_NAME_MAX]; + + /* Available cpus */ + int nlive = LiveGetDeviceCount(); + uint16_t thread_max = TmThreadsGetWorkerThreadMax(); + + char *queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); + if (queues == NULL) { + FatalError("RunmodeAutoFpCreatePickupQueuesString failed"); + } + + if ((nlive <= 1) && (live_dev != NULL)) { + SCLogDebug("live_dev %s", live_dev); + + void *aconf = ConfigParser(live_dev); + if (aconf == NULL) { + FatalError("Failed to allocate config for %s", live_dev); + } + + int threads_count = ModThreadsCount(aconf); + SCLogInfo("Going to use %" PRId32 " %s receive thread(s)", threads_count, recv_mod_name); + + /* create the threads */ + for (int thread = 0; thread < threads_count; thread++) { + snprintf(tname, sizeof(tname), "%s#%02d", thread_name, thread + 1); + ThreadVars *tv_receive = TmThreadCreatePacketHandler( + tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); + if (tv_receive == NULL) { + FatalError("TmThreadsCreate failed"); + } + TmModule *tm_module = TmModuleGetByName(recv_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName failed for %s", recv_mod_name); + } + TmSlotSetFuncAppend(tv_receive, tm_module, aconf); + + tm_module = TmModuleGetByName(decode_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName %s failed", decode_mod_name); + } + TmSlotSetFuncAppend(tv_receive, tm_module, NULL); + + TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); + + if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + } else { /* Multiple input device */ + SCLogInfo("Using %d live device(s).", nlive); + + for (int lthread = 0; lthread < nlive; lthread++) { + const char *dev = LiveGetDeviceName(lthread); + const char *visual_devname = LiveGetShortName(dev); + + if (dev == NULL) { + FatalError("Failed to lookup live dev %d", lthread); + } + SCLogDebug("dev %s", dev); + + void *aconf = ConfigParser(dev); + if (aconf == NULL) { + FatalError("Multidev: Failed to allocate config for %s (%d)", dev, lthread); + } + + int threads_count = ModThreadsCount(aconf); + for (int thread = 0; thread < threads_count; thread++) { + char *printable_threadname = + SCMalloc(sizeof(char) * (strlen(thread_name) + 5 + strlen(dev))); + if (unlikely(printable_threadname == NULL)) { + FatalError("failed to alloc printable thread name: %s", strerror(errno)); + } + snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, thread + 1, + visual_devname); + snprintf(printable_threadname, strlen(thread_name) + 5 + strlen(dev), "%s#%02d-%s", + thread_name, thread + 1, dev); + + ThreadVars *tv_receive = TmThreadCreatePacketHandler( + tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); + if (tv_receive == NULL) { + FatalError("TmThreadsCreate failed"); + } + tv_receive->printable_name = printable_threadname; + TmModule *tm_module = TmModuleGetByName(recv_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName failed for %s", recv_mod_name); + } + TmSlotSetFuncAppend(tv_receive, tm_module, aconf); + + tm_module = TmModuleGetByName(decode_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName %s failed", decode_mod_name); + } + TmSlotSetFuncAppend(tv_receive, tm_module, NULL); + + TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); + + if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + } + } + + for (uint16_t thread = 0; thread < thread_max; thread++) { + snprintf(tname, sizeof(tname), "%s#%02u", thread_name_workers, (uint16_t)(thread + 1)); + snprintf(qname, sizeof(qname), "pickup%u", (uint16_t)(thread + 1)); + + SCLogDebug("tname %s, qname %s", tname, qname); + + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler( + tname, qname, "flow", "packetpool", "packetpool", "varslot"); + if (tv_detect_ncpu == NULL) { + FatalError("TmThreadsCreate failed"); + } + TmModule *tm_module = TmModuleGetByName("FlowWorker"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName for FlowWorker failed"); + } + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); + + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); + + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); + + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName RespondReject failed"); + } + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + + SCFree(queues); + return 0; +} + +/** + */ +static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc ModThreadsCount, + const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, + const char *live_dev, void *aconf, unsigned char single_mode) +{ + int threads_count; + uint16_t thread_max = TmThreadsGetWorkerThreadMax(); + + if (single_mode) { + threads_count = 1; + } else { + threads_count = MIN(ModThreadsCount(aconf), thread_max); + SCLogInfo("%s: creating %" PRId32 " thread%s", live_dev, threads_count, + threads_count > 1 ? "s" : ""); + } + + /* create the threads */ + for (int thread = 0; thread < threads_count; thread++) { + char tname[TM_THREAD_NAME_MAX]; + TmModule *tm_module = NULL; + const char *visual_devname = LiveGetShortName(live_dev); + char *printable_threadname = + SCMalloc(sizeof(char) * (strlen(thread_name) + 5 + strlen(live_dev))); + if (unlikely(printable_threadname == NULL)) { + FatalError("failed to alloc printable thread name: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + if (single_mode) { + snprintf(tname, sizeof(tname), "%s#01-%s", thread_name, visual_devname); + snprintf(printable_threadname, strlen(thread_name) + 5 + strlen(live_dev), "%s#01-%s", + thread_name, live_dev); + } else { + snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, thread + 1, visual_devname); + snprintf(printable_threadname, strlen(thread_name) + 5 + strlen(live_dev), "%s#%02d-%s", + thread_name, thread + 1, live_dev); + } + ThreadVars *tv = TmThreadCreatePacketHandler( + tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); + if (tv == NULL) { + FatalError("TmThreadsCreate failed"); + } + tv->printable_name = printable_threadname; + + tm_module = TmModuleGetByName(recv_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName failed for %s", recv_mod_name); + } + TmSlotSetFuncAppend(tv, tm_module, aconf); + + tm_module = TmModuleGetByName(decode_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName %s failed", decode_mod_name); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + tm_module = TmModuleGetByName("FlowWorker"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName for FlowWorker failed"); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName RespondReject failed"); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + TmThreadSetCPU(tv, WORKER_CPU_SET); + + if (TmThreadSpawn(tv) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + + return 0; +} + +int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, + ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev) +{ + int nlive = LiveGetDeviceCount(); + void *aconf; + int ldev; + + for (ldev = 0; ldev < nlive; ldev++) { + const char *live_dev_c = NULL; + if ((nlive <= 1) && (live_dev != NULL)) { + aconf = ConfigParser(live_dev); + live_dev_c = live_dev; + } else { + live_dev_c = LiveGetDeviceName(ldev); + aconf = ConfigParser(live_dev_c); + } + RunModeSetLiveCaptureWorkersForDevice( + ModThreadsCount, recv_mod_name, decode_mod_name, thread_name, live_dev_c, aconf, 0); + } + + return 0; +} + +int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, + ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev) +{ + int nlive = LiveGetDeviceCount(); + const char *live_dev_c = NULL; + void *aconf; + + if (nlive > 1) { + FatalError("Can't use the 'single' runmode with multiple devices"); + } + + if (live_dev != NULL) { + aconf = ConfigParser(live_dev); + live_dev_c = live_dev; + } else { + live_dev_c = LiveGetDeviceName(0); + aconf = ConfigParser(live_dev_c); + } + + return RunModeSetLiveCaptureWorkersForDevice( + ModThreadsCount, recv_mod_name, decode_mod_name, thread_name, live_dev_c, aconf, 1); +} + +/** + */ +int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, const char *recv_mod_name, + const char *verdict_mod_name, const char *decode_mod_name) +{ + SCEnter(); + char tname[TM_THREAD_NAME_MAX]; + TmModule *tm_module; + + /* Available cpus */ + const int nqueue = LiveGetDeviceCount(); + + uint16_t thread_max = TmThreadsGetWorkerThreadMax(); + + char *queues = RunmodeAutoFpCreatePickupQueuesString(thread_max); + if (queues == NULL) { + FatalError("RunmodeAutoFpCreatePickupQueuesString failed"); + } + + /* create the threads */ + for (int i = 0; i < nqueue; i++) { + const char *cur_queue = LiveGetDeviceName(i); + if (cur_queue == NULL) { + FatalError("invalid queue number"); + } + memset(tname, 0, sizeof(tname)); + snprintf(tname, sizeof(tname), "%s-%s", thread_name_autofp, cur_queue); + + ThreadVars *tv_receive = TmThreadCreatePacketHandler( + tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); + if (tv_receive == NULL) { + FatalError("TmThreadsCreate failed"); + } + tm_module = TmModuleGetByName(recv_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName failed for %s", recv_mod_name); + } + TmSlotSetFuncAppend(tv_receive, tm_module, (void *)ConfigParser(i)); + + tm_module = TmModuleGetByName(decode_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName %s failed", decode_mod_name); + } + TmSlotSetFuncAppend(tv_receive, tm_module, NULL); + + TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); + + if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + for (int thread = 0; thread < thread_max; thread++) { + snprintf(tname, sizeof(tname), "%s#%02u", thread_name_workers, (uint16_t)(thread + 1)); + char qname[TM_QUEUE_NAME_MAX]; + snprintf(qname, sizeof(qname), "pickup%u", (uint16_t)(thread + 1)); + + SCLogDebug("tname %s, qname %s", tname, qname); + + ThreadVars *tv_detect_ncpu = TmThreadCreatePacketHandler( + tname, qname, "flow", "verdict-queue", "simple", "varslot"); + if (tv_detect_ncpu == NULL) { + FatalError("TmThreadsCreate failed"); + } + + tm_module = TmModuleGetByName("FlowWorker"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName for FlowWorker failed"); + } + TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); + + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); + + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); + + if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + + /* create the threads */ + for (int i = 0; i < nqueue; i++) { + memset(tname, 0, sizeof(tname)); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_verdict, i); + + ThreadVars *tv_verdict = TmThreadCreatePacketHandler( + tname, "verdict-queue", "simple", "packetpool", "packetpool", "varslot"); + if (tv_verdict == NULL) { + FatalError("TmThreadsCreate failed"); + } + tm_module = TmModuleGetByName(verdict_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName %s failed", verdict_mod_name); + } + TmSlotSetFuncAppend(tv_verdict, tm_module, (void *)ConfigParser(i)); + + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName for RespondReject failed"); + } + TmSlotSetFuncAppend(tv_verdict, tm_module, NULL); + + TmThreadSetCPU(tv_verdict, VERDICT_CPU_SET); + + if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + + SCFree(queues); + return 0; +} + +/** + */ +int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, const char *recv_mod_name, + const char *verdict_mod_name, const char *decode_mod_name) +{ + TmModule *tm_module = NULL; + const int nqueue = LiveGetDeviceCount(); + + for (int i = 0; i < nqueue; i++) { + /* create the threads */ + const char *cur_queue = LiveGetDeviceName(i); + if (cur_queue == NULL) { + FatalError("invalid queue number"); + } + + char tname[TM_THREAD_NAME_MAX]; + memset(tname, 0, sizeof(tname)); + snprintf(tname, sizeof(tname), "%s-%s", thread_name_workers, cur_queue); + + ThreadVars *tv = TmThreadCreatePacketHandler( + tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); + if (tv == NULL) { + FatalError("TmThreadsCreate failed"); + } + + tm_module = TmModuleGetByName(recv_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName failed for %s", recv_mod_name); + } + TmSlotSetFuncAppend(tv, tm_module, (void *)ConfigParser(i)); + + tm_module = TmModuleGetByName(decode_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName %s failed", decode_mod_name); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + tm_module = TmModuleGetByName("FlowWorker"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName for FlowWorker failed"); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + tm_module = TmModuleGetByName(verdict_mod_name); + if (tm_module == NULL) { + FatalError("TmModuleGetByName %s failed", verdict_mod_name); + } + TmSlotSetFuncAppend(tv, tm_module, (void *)ConfigParser(i)); + + tm_module = TmModuleGetByName("RespondReject"); + if (tm_module == NULL) { + FatalError("TmModuleGetByName for RespondReject failed"); + } + TmSlotSetFuncAppend(tv, tm_module, NULL); + + TmThreadSetCPU(tv, WORKER_CPU_SET); + + if (TmThreadSpawn(tv) != TM_ECODE_OK) { + FatalError("TmThreadSpawn failed"); + } + } + + return 0; +} diff --git a/src/util/runmodes.h b/src/util/runmodes.h new file mode 100644 index 000000000000..d217236a2a02 --- /dev/null +++ b/src/util/runmodes.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2011 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Eric Leblond + */ + +#ifndef __UTIL_RUNMODES_H__ +#define __UTIL_RUNMODES_H__ + +typedef void *(*ConfigIfaceParserFunc)(const char *); +typedef void *(*ConfigIPSParserFunc)(int); +typedef int (*ConfigIfaceThreadsCountFunc)(void *); + +int RunModeSetLiveCaptureAuto(ConfigIfaceParserFunc configparser, + ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); + +int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc configparser, + ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); + +int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc configparser, + ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); + +int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc configparser, + ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); + +int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, const char *recv_mod_name, + const char *verdict_mod_name, const char *decode_mod_name); + +int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, const char *recv_mod_name, + const char *verdict_mod_name, const char *decode_mod_name); + +char *RunmodeAutoFpCreatePickupQueuesString(int n); + +#endif /* __UTIL_RUNMODES_H__ */ diff --git a/src/util/running-modes.c b/src/util/running-modes.c new file mode 100644 index 000000000000..d9614ec76b4b --- /dev/null +++ b/src/util/running-modes.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Eric Leblond + */ + +#include "suricata-common.h" +#include "app-layer-detect-proto.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "conf-yaml-loader.h" +#include "util/running-modes.h" + +int ListKeywords(const char *keyword_info) +{ + EngineModeSetIDS(); + SCLogLoadConfig(0, 0, 0, 0); + MpmTableSetup(); + SpmTableSetup(); + AppLayerSetup(); + SigTableSetup(); /* load the rule keywords */ + return SigTableList(keyword_info); +} + +int ListAppLayerProtocols(const char *conf_filename) +{ + EngineModeSetIDS(); + if (ConfYamlLoadFile(conf_filename) != -1) + SCLogLoadConfig(0, 0, 0, 0); + MpmTableSetup(); + SpmTableSetup(); + AppLayerSetup(); + AppLayerListSupportedProtocols(); + + return TM_ECODE_DONE; +} diff --git a/src/util-running-modes.h b/src/util/running-modes.h similarity index 100% rename from src/util-running-modes.h rename to src/util/running-modes.h diff --git a/src/util/signal.c b/src/util/signal.c new file mode 100644 index 000000000000..e851ff3ff606 --- /dev/null +++ b/src/util/signal.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Anoop Saldanha + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util/debug.h" +#include "util/signal.h" + +int UtilSignalBlock(int signum) +{ +#ifndef OS_WIN32 + sigset_t x; + if (sigemptyset(&x) < 0) + return -1; + if (sigaddset(&x, signum) < 0) + return -1; + /* don't use sigprocmask(), as it's undefined for + * multithreaded programs. Use phtread_sigmask(). + */ + if (pthread_sigmask(SIG_BLOCK, &x, NULL) != 0) + return -1; +#endif + return 0; +} + +int UtilSignalUnblock(int signum) +{ +#ifndef OS_WIN32 + sigset_t x; + if (sigemptyset(&x) < 0) + return -1; + if (sigaddset(&x, signum) < 0) + return -1; + if (pthread_sigmask(SIG_UNBLOCK, &x, NULL) != 0) + return -1; +#endif + return 0; +} + +void UtilSignalHandlerSetup(int sig, void (*handler)(int)) +{ +#ifdef OS_WIN32 + signal(sig, handler); +#else + struct sigaction action; + memset(&action, 0x00, sizeof(struct sigaction)); + + action.sa_handler = handler; + sigemptyset(&(action.sa_mask)); + sigaddset(&(action.sa_mask), sig); + action.sa_flags = 0; + sigaction(sig, &action, 0); +#endif /* OS_WIN32 */ + + return; +} + +#if 0 +int UtilSignalIsHandler(int sig, void (*handler)(int)) +{ + struct sigaction action; + memset(&action, 0x00, sizeof(struct sigaction)); + + sigaction(sig, NULL, &action); + + return (action.sa_handler == handler); +} +#endif diff --git a/src/util-signal.h b/src/util/signal.h similarity index 100% rename from src/util-signal.h rename to src/util/signal.h diff --git a/src/util/spm-bm.c b/src/util/spm-bm.c new file mode 100644 index 000000000000..f8fb4d985825 --- /dev/null +++ b/src/util/spm-bm.c @@ -0,0 +1,508 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * + * Boyer Moore simple pattern matcher implementation + * + * Boyer Moore algorithm has a really good performance. It need two arrays + * of context for each pattern that hold applicable shifts on the text + * to search in, based on characters not available in the pattern + * and combinations of characters that start a suffix of the pattern. + * If possible, we should store the context of patterns that we are going + * to search for multiple times, so we don't spend time on rebuilding them. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "util/spm-bm.h" +#include "util/spm.h" +#include "util/debug.h" +#include "util/error.h" +#include "util/memcpy.h" +#include "util/validate.h" + +static int PreBmGs(const uint8_t *x, uint16_t m, uint16_t *bmGs); +static void PreBmBc(const uint8_t *x, uint16_t m, uint16_t *bmBc); +static void PreBmBcNocase(const uint8_t *x, uint16_t m, uint16_t *bmBc); +static void BoyerMooreSuffixesNocase(const uint8_t *x, uint16_t m, uint16_t *suff); +static void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs); + +/** + * \brief Given a BmCtx structure, recreate the pre/suffixes for + * nocase + * + * \retval BmCtx pointer to the already created BmCtx (with BoyerMooreCtxInit()) + * \param str pointer to the pattern string + * \param size length of the string + */ +void BoyerMooreCtxToNocase(BmCtx *bm_ctx, uint8_t *needle, uint16_t needle_len) +{ + /* Store the content as lower case to make searching faster */ + memcpy_tolower(needle, needle, needle_len); + + /* Prepare bad chars with nocase chars */ + PreBmBcNocase(needle, needle_len, bm_ctx->bmBc); + + /* Prepare good Suffixes with nocase chars */ + PreBmGsNocase(needle, needle_len, bm_ctx->bmGs); +} + +/** + * \brief Setup a Boyer Moore context. + * + * \param str pointer to the pattern string + * \param size length of the string + * \retval BmCtx pointer to the newly created Context for the pattern + * \initonly BoyerMoore contexts should be created at init + */ +BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len) +{ + BmCtx *new = SCMalloc(sizeof(BmCtx) + sizeof(uint16_t) * (needle_len + 1)); + if (unlikely(new == NULL)) { + FatalError("Fatal error encountered in BoyerMooreCtxInit. Exiting..."); + } + + /* Prepare bad chars */ + PreBmBc(needle, needle_len, new->bmBc); + + /* Prepare good Suffixes */ + if (PreBmGs(needle, needle_len, new->bmGs) == -1) { + FatalError("Fatal error encountered in BoyerMoreCtxInit. Exiting..."); + } + + return new; +} + +/** + * \brief Setup a Boyer Moore context for nocase search + * + * \param str pointer to the pattern string + * \param size length of the string + * \retval BmCtx pointer to the newly created Context for the pattern + * \initonly BoyerMoore contexts should be created at init + */ +BmCtx *BoyerMooreNocaseCtxInit(uint8_t *needle, uint16_t needle_len) +{ + BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needle_len); + + BoyerMooreCtxToNocase(bm_ctx, needle, needle_len); + + return bm_ctx; +} + +/** + * \brief Free the memory allocated to Boyer Moore context. + * + * \param bmCtx pointer to the Context for the pattern + */ +void BoyerMooreCtxDeInit(BmCtx *bmctx) +{ + SCEnter(); + if (bmctx == NULL) + SCReturn; + + SCFree(bmctx); + + SCReturn; +} +/** + * \brief Array setup function for bad characters that split the pattern + * Remember that the result array should be the length of ALPHABET_SIZE + * + * \param str pointer to the pattern string + * \param size length of the string + * \param result pointer to an empty array that will hold the badchars + */ +static void PreBmBc(const uint8_t *x, uint16_t m, uint16_t *bmBc) +{ + uint16_t i; + + for (i = 0; i < 256; ++i) { + bmBc[i] = m; + } + for (i = 0; i < m - 1; ++i) { + bmBc[(unsigned char)x[i]] = m - i - 1; + } +} + +/** + * \brief Array setup function for building prefixes (shift for valid prefixes) for boyermoore + * context + * + * \param x pointer to the pattern string + * \param m length of the string + * \param suff pointer to an empty array that will hold the prefixes (shifts) + */ +static void BoyerMooreSuffixes(const uint8_t *x, uint16_t m, uint16_t *suff) +{ + int32_t f = 0, g, i; + suff[m - 1] = m; + g = m - 1; + for (i = m - 2; i >= 0; --i) { + if (i > g && suff[i + m - 1 - f] < i - g) + suff[i] = suff[i + m - 1 - f]; + else { + if (i < g) + g = i; + f = i; + while (g >= 0 && x[g] == x[g + m - 1 - f]) + --g; + DEBUG_VALIDATE_BUG_ON(f - g < 0 || f - g > UINT16_MAX); + suff[i] = (uint16_t)(f - g); + } + } +} + +/** + * \brief Array setup function for building prefixes (shift for valid prefixes) for boyermoore + * context + * + * \param x pointer to the pattern string + * \param m length of the string + * \param bmGs pointer to an empty array that will hold the prefixes (shifts) + * \retval 0 ok, -1 failed + */ +static int PreBmGs(const uint8_t *x, uint16_t m, uint16_t *bmGs) +{ + int32_t i, j; + uint16_t suff[m + 1]; + + BoyerMooreSuffixes(x, m, suff); + + for (i = 0; i < m; ++i) + bmGs[i] = m; + + j = 0; + + for (i = m - 1; i >= -1; --i) + if (i == -1 || suff[i] == i + 1) + for (; j < m - 1 - i; ++j) + if (bmGs[j] == m) + bmGs[j] = (uint16_t)(m - 1 - i); + + for (i = 0; i <= m - 2; ++i) + bmGs[m - 1 - suff[i]] = (uint16_t)(m - 1 - i); + return 0; +} + +/** + * \brief Array setup function for bad characters that split the pattern + * Remember that the result array should be the length of ALPHABET_SIZE + * + * \param str pointer to the pattern string + * \param size length of the string + * \param result pointer to an empty array that will hold the badchars + */ +static void PreBmBcNocase(const uint8_t *x, uint16_t m, uint16_t *bmBc) +{ + uint16_t i; + + for (i = 0; i < 256; ++i) { + bmBc[i] = m; + } + for (i = 0; i < m - 1; ++i) { + bmBc[u8_tolower(x[i])] = m - 1 - i; + bmBc[u8_toupper(x[i])] = m - 1 - i; + } +} + +static void BoyerMooreSuffixesNocase(const uint8_t *x, uint16_t m, uint16_t *suff) +{ + int32_t f = 0, g, i; + + suff[m - 1] = m; + g = m - 1; + for (i = m - 2; i >= 0; --i) { + if (i > g && suff[i + m - 1 - f] < i - g) { + suff[i] = suff[i + m - 1 - f]; + } else { + if (i < g) { + g = i; + } + f = i; + while (g >= 0 && u8_tolower(x[g]) == u8_tolower(x[g + m - 1 - f])) { + --g; + } + DEBUG_VALIDATE_BUG_ON(f - g < 0 || f - g > UINT16_MAX); + suff[i] = (uint16_t)(f - g); + } + } +} + +/** + * \brief Array setup function for building prefixes (shift for valid prefixes) + * for boyermoore context case less + * + * \param x pointer to the pattern string + * \param m length of the string + * \param bmGs pointer to an empty array that will hold the prefixes (shifts) + */ +static void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs) +{ + uint16_t i, j; + uint16_t suff[m + 1]; + + BoyerMooreSuffixesNocase(x, m, suff); + + for (i = 0; i < m; ++i) { + bmGs[i] = m; + } + j = 0; + for (i = m; i > 0; --i) { + if (suff[i - 1] == i) { + for (; j < m - i; ++j) { + if (bmGs[j] == m) { + bmGs[j] = m - i; + } + } + } + } + for (i = 0; i <= m - 2; ++i) { + bmGs[m - 1 - suff[i]] = m - 1 - i; + } +} + +/** + * \brief Boyer Moore search algorithm + * Is better as the pattern length increases and for big buffers to search in. + * The algorithm needs a context of two arrays already prepared + * by prep_bad_chars() and prep_good_suffix() + * + * \param y pointer to the buffer to search in + * \param n length limit of the buffer + * \param x pointer to the pattern we ar searching for + * \param m length limit of the needle + * \param bmBc pointer to an array of BoyerMooreSuffixes prepared by prep_good_suffix() + * \param bmGs pointer to an array of bachars prepared by prep_bad_chars() + * + * \retval ptr to start of the match; NULL if no match + */ +uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx) +{ + uint16_t *bmGs = bm_ctx->bmGs; + uint16_t *bmBc = bm_ctx->bmBc; + + int i, j, m1, m2; + int32_t int_n; +#if 0 + printf("\nBad:\n"); + for (i=0;i INT32_MAX) ? INT32_MAX : n; + j = 0; + while (j <= int_n - m) { + for (i = m - 1; i >= 0 && x[i] == y[i + j]; --i) + ; + + if (i < 0) { + return (uint8_t *)(y + j); + // j += bmGs[0]; + } else { + // printf("%c", y[i+j]); + j += (m1 = bmGs[i]) > (m2 = bmBc[y[i + j]] - m + 1 + i) ? m1 : m2; + // printf("%d, %d\n", m1, m2); + } + } + return NULL; +} + +/** + * \brief Boyer Moore search algorithm + * Is better as the pattern length increases and for big buffers to search in. + * The algorithm needs a context of two arrays already prepared + * by prep_bad_chars() and prep_good_suffix() + * + * \param y pointer to the buffer to search in + * \param n length limit of the buffer + * \param x pointer to the pattern we ar searching for + * \param m length limit of the needle + * \param bmBc pointer to an array of BoyerMooreSuffixes prepared by prep_good_suffix() + * \param bmGs pointer to an array of bachars prepared by prep_bad_chars() + * + * \retval ptr to start of the match; NULL if no match + */ +uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx) +{ + uint16_t *bmGs = bm_ctx->bmGs; + uint16_t *bmBc = bm_ctx->bmBc; + int i, j, m1, m2; + int32_t int_n; +#if 0 + printf("\nBad:\n"); + for (i=0;i INT32_MAX) ? INT32_MAX : n; + j = 0; + while (j <= int_n - m) { + /* x is stored in lowercase. */ + for (i = m - 1; i >= 0 && x[i] == u8_tolower(y[i + j]); --i) + ; + + if (i < 0) { + return (uint8_t *)(y + j); + } else { + j += (m1 = bmGs[i]) > (m2 = bmBc[y[i + j]] - m + 1 + i) ? m1 : m2; + } + } + return NULL; +} + +typedef struct SpmBmCtx_ { + BmCtx *bm_ctx; + uint8_t *needle; + uint16_t needle_len; + int nocase; +} SpmBmCtx; + +static SpmCtx *BMInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmCtx *ctx = SCCalloc(1, sizeof(SpmCtx)); + if (ctx == NULL) { + SCLogDebug("Unable to alloc SpmCtx."); + return NULL; + } + ctx->matcher = SPM_BM; + + SpmBmCtx *sctx = SCCalloc(1, sizeof(SpmBmCtx)); + if (sctx == NULL) { + SCLogDebug("Unable to alloc SpmBmCtx."); + SCFree(ctx); + return NULL; + } + + sctx->needle = SCMalloc(needle_len); + if (sctx->needle == NULL) { + SCLogDebug("Unable to alloc string."); + SCFree(sctx); + SCFree(ctx); + return NULL; + } + memcpy(sctx->needle, needle, needle_len); + sctx->needle_len = needle_len; + + if (nocase) { + sctx->bm_ctx = BoyerMooreNocaseCtxInit(sctx->needle, sctx->needle_len); + sctx->nocase = 1; + } else { + sctx->bm_ctx = BoyerMooreCtxInit(sctx->needle, sctx->needle_len); + sctx->nocase = 0; + } + + ctx->ctx = sctx; + return ctx; +} + +static void BMDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + + SpmBmCtx *sctx = ctx->ctx; + if (sctx != NULL) { + BoyerMooreCtxDeInit(sctx->bm_ctx); + if (sctx->needle != NULL) { + SCFree(sctx->needle); + } + SCFree(sctx); + } + + SCFree(ctx); +} + +static uint8_t *BMScan( + const SpmCtx *ctx, SpmThreadCtx *thread_ctx, const uint8_t *haystack, uint32_t haystack_len) +{ + const SpmBmCtx *sctx = ctx->ctx; + + if (sctx->nocase) { + return BoyerMooreNocase( + sctx->needle, sctx->needle_len, haystack, haystack_len, sctx->bm_ctx); + } else { + return BoyerMoore(sctx->needle, sctx->needle_len, haystack, haystack_len, sctx->bm_ctx); + } +} + +static SpmGlobalThreadCtx *BMInitGlobalThreadCtx(void) +{ + SpmGlobalThreadCtx *global_thread_ctx = SCCalloc(1, sizeof(SpmGlobalThreadCtx)); + if (global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + global_thread_ctx->matcher = SPM_BM; + return global_thread_ctx; +} + +static void BMDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + SCFree(global_thread_ctx); +} + +static void BMDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + SCFree(thread_ctx); +} + +static SpmThreadCtx *BMMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmThreadCtx *thread_ctx = SCCalloc(1, sizeof(SpmThreadCtx)); + if (thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + thread_ctx->matcher = SPM_BM; + return thread_ctx; +} + +void SpmBMRegister(void) +{ + spm_table[SPM_BM].name = "bm"; + spm_table[SPM_BM].InitGlobalThreadCtx = BMInitGlobalThreadCtx; + spm_table[SPM_BM].DestroyGlobalThreadCtx = BMDestroyGlobalThreadCtx; + spm_table[SPM_BM].MakeThreadCtx = BMMakeThreadCtx; + spm_table[SPM_BM].DestroyThreadCtx = BMDestroyThreadCtx; + spm_table[SPM_BM].InitCtx = BMInitCtx; + spm_table[SPM_BM].DestroyCtx = BMDestroyCtx; + spm_table[SPM_BM].Scan = BMScan; +} diff --git a/src/util/spm-bm.h b/src/util/spm-bm.h new file mode 100644 index 000000000000..c6fff8f0a881 --- /dev/null +++ b/src/util/spm-bm.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * + */ + +#ifndef __UTIL_SPM_BM__ +#define __UTIL_SPM_BM__ + +#include "suricata-common.h" + +#define ALPHABET_SIZE 256 + +/* Context for boyer moore */ +typedef struct BmCtx_ { + uint16_t bmBc[ALPHABET_SIZE]; + // C99 "flexible array member" + uint16_t bmGs[]; // = SCMalloc(sizeof(int16_t)*(needlelen + 1)); +} BmCtx; + +/** Prepare and return a Boyer Moore context */ +BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len); +BmCtx *BoyerMooreNocaseCtxInit(uint8_t *needle, uint16_t needle_len); + +void BoyerMooreCtxToNocase(BmCtx *, uint8_t *, uint16_t); +uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx); +uint8_t *BoyerMooreNocase( + const uint8_t *x, uint16_t m, const uint8_t *y, uint32_t n, BmCtx *bm_ctx); +void BoyerMooreCtxDeInit(BmCtx *); + +void SpmBMRegister(void); + +#endif /* __UTIL_SPM_BM__ */ diff --git a/src/util/spm-bs.c b/src/util/spm-bs.c new file mode 100644 index 000000000000..e47fe9ee6f75 --- /dev/null +++ b/src/util/spm-bs.c @@ -0,0 +1,139 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Pablo Rincon Crespo + * + * bs is a bruteforce search. It will try to search the pattern + * from all characters until the available text len is less + * than the length of the pattern. It needs no context but it + * time cost is not good. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "util/debug.h" +#include "util/spm-bs.h" + +/** + * \brief Basic search improved. Limits are better handled, so + * it doesn't start searches that wont fit in the remaining buffer + * + * \param haystack pointer to the buffer to search in + * \param haystack_len length limit of the buffer + * \param needle pointer to the pattern we ar searching for + * \param needle_len length limit of the needle + * + * \retval ptr to start of the match; NULL if no match + */ +uint8_t *BasicSearch( + const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len) +{ + SCEnter(); + + const uint8_t *h, *n; + const uint8_t *hmax = haystack + haystack_len; + const uint8_t *nmax = needle + needle_len; + + if (needle_len == 0 || needle_len > haystack_len) { + SCReturnPtr(NULL, "uint8_t"); + } + + // PrintRawDataFp(stdout,needle,needle_len); + + // PrintRawDataFp(stdout,haystack,haystack_len); + + for (n = needle; nmax - n <= hmax - haystack; haystack++) { + if (*haystack != *n) { + continue; + } + + SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); + + /* one byte needles */ + if (needle_len == 1) { + SCReturnPtr((uint8_t *)haystack, "uint8_t"); + } + + for (h = haystack + 1, n++; nmax - n <= hmax - haystack; h++, n++) { + if (*h != *n) { + break; + } + SCLogDebug("*haystack == *n, %c == %c", *haystack, *n); + /* if we run out of needle we fully matched */ + if (n == nmax - 1) { + SCReturnPtr((uint8_t *)haystack, "uint8_t"); + } + } + n = needle; + } + + SCReturnPtr(NULL, "uint8_t"); +} + +/** + * \brief Basic search case less + * + * \param haystack pointer to the buffer to search in + * \param haystack_len length limit of the buffer + * \param needle pointer to the pattern we ar searching for + * \param needle_len length limit of the needle + * + * \retval ptr to start of the match; NULL if no match + */ +uint8_t *BasicSearchNocase( + const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len) +{ + const uint8_t *h, *n; + const uint8_t *hmax = haystack + haystack_len; + const uint8_t *nmax = needle + needle_len; + + if (needle_len == 0 || needle_len > haystack_len) + return NULL; + + for (n = needle; nmax - n <= hmax - haystack; haystack++) { + if (u8_tolower(*haystack) != u8_tolower(*n)) { + continue; + } + /* one byte needles */ + if (needle_len == 1) { + return (uint8_t *)haystack; + } + + for (h = haystack + 1, n++; nmax - n <= hmax - h; h++, n++) { + if (u8_tolower(*h) != u8_tolower(*n)) { + break; + } + /* if we run out of needle we fully matched */ + if (n == nmax - 1) { + return (uint8_t *)haystack; + } + } + n = needle; + } + + return NULL; +} + +void BasicSearchInit(void) +{ + /* nothing no more */ +} diff --git a/src/util/spm-bs.h b/src/util/spm-bs.h new file mode 100644 index 000000000000..167dbaa50c1a --- /dev/null +++ b/src/util/spm-bs.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Pablo Rincon Crespo + */ + +#ifndef __UTIL_SPM_BS__ +#define __UTIL_SPM_BS__ + +#include "suricata-common.h" + +uint8_t *BasicSearch(const uint8_t *, uint32_t, const uint8_t *, uint16_t); +uint8_t *BasicSearchNocase(const uint8_t *, uint32_t, const uint8_t *, uint16_t); +void BasicSearchInit(void); + +#endif /* __UTIL_SPM_BS__ */ diff --git a/src/util/spm-bs2bm.c b/src/util/spm-bs2bm.c new file mode 100644 index 000000000000..f2a27288c081 --- /dev/null +++ b/src/util/spm-bs2bm.c @@ -0,0 +1,177 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * + * Bs2Bm use a simple context array to determine the characters + * that are not present on the pattern. This way on partial matches + * broken by a char not present, we can skip to the next character + * making less checks + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "util/spm-bs2bm.h" + +/** + * \brief Array setup function for Bs2Bm of bad characters index (not found at the needle) + * + * \param needle pointer to the pattern we ar searching for + * \param needle_len length limit of the needle + * \param badchars pointer to an empty array of bachars. The array prepared contains + * characters that can't be inside the needle_len. So the skips can be + * faster + */ +void Bs2BmBadchars(const uint8_t *needle, uint16_t needle_len, uint8_t *badchars) +{ + uint32_t i; + for (i = 0; i < ALPHABET_SIZE; i++) + badchars[i] = 1; + + /* set to 0 the values where index as ascii is present + * because they are not badchars + */ + for (i = 0; i < needle_len; i++) + badchars[needle[i]] = 0; +} + +/** + * \brief Array setup function for Bs2BmNocase of bad characters index (not found at the needle) + * + * \param needle pointer to the pattern we ar searching for + * \param needle_len length limit of the needle + * \param badchars pointer to an empty array of bachars. The array prepared contains + * characters that can't be inside the needle_len. So the skips can be + * faster + */ +void Bs2BmBadcharsNocase(const uint8_t *needle, uint16_t needle_len, uint8_t *badchars) +{ + uint32_t i; + for (i = 0; i < ALPHABET_SIZE; i++) + badchars[i] = 1; + + /* set to 0 the values where index as ascii is present + * because they are not badchars + */ + for (i = 0; i < needle_len; i++) { + badchars[u8_tolower(needle[i])] = 0; + } +} + +/** + * \brief Basic search with a bad characters array. The array badchars contains + * flags at character's ascii index that can't be inside the needle. So the skips can be + * faster + * + * \param haystack pointer to the buffer to search in + * \param haystack_len length limit of the buffer + * \param needle pointer to the pattern we ar searching for + * \param needle_len length limit of the needle + * \param badchars pointer to an array of bachars prepared by Bs2BmBadchars() + * + * \retval ptr to start of the match; NULL if no match + */ +uint8_t *Bs2Bm(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, + uint16_t needle_len, const uint8_t badchars[]) +{ + const uint8_t *h, *n; + const uint8_t *hmax = haystack + haystack_len; + const uint8_t *nmax = needle + needle_len; + + if (needle_len == 0 || needle_len > haystack_len) + return NULL; + + for (n = needle; nmax - n <= hmax - haystack; haystack++) { + if (*haystack != *n) { + continue; + } + /* one byte needles */ + if (needle_len == 1) + return (uint8_t *)haystack; + + for (h = haystack + 1, n++; nmax - n <= hmax - haystack; h++, n++) { + if (*h != *n) { + if (badchars[*h] == 1) { + /* skip it! */ + haystack = h; + } + break; + } + /* if we run out of needle we fully matched */ + if (n == nmax - 1) { + return (uint8_t *)haystack; + } + } + n = needle; + } + + return NULL; +} + +/** + * \brief Basic search case less with a bad characters array. The array badchars contains + * flags at character's ascii index that can't be inside the needle. So the skips can be + * faster + * + * \param haystack pointer to the buffer to search in + * \param haystack_len length limit of the buffer + * \param needle pointer to the pattern we ar searching for + * \param needle_len length limit of the needle + * \param badchars pointer to an array of bachars prepared by Bs2BmBadchars() + * + * \retval ptr to start of the match; NULL if no match + */ +uint8_t *Bs2BmNocase(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, + uint16_t needle_len, const uint8_t badchars[]) +{ + const uint8_t *h, *n; + const uint8_t *hmax = haystack + haystack_len; + const uint8_t *nmax = needle + needle_len; + + if (needle_len == 0 || needle_len > haystack_len) + return NULL; + + for (n = needle; nmax - n <= hmax - haystack; haystack++) { + if (u8_tolower(*haystack) != u8_tolower(*n)) { + continue; + } + /* one byte needles */ + if (needle_len == 1) + return (uint8_t *)haystack; + + for (h = haystack + 1, n++; nmax - n <= hmax - haystack; h++, n++) { + if (u8_tolower(*h) != u8_tolower(*n)) { + if (badchars[u8_tolower(*h)] == 1) { + /* skip it! */ + haystack = h; + } + break; + } + /* if we run out of needle we fully matched */ + if (n == nmax - 1) { + return (uint8_t *)haystack; + } + } + n = needle; + } + + return NULL; +} diff --git a/src/util/spm-bs2bm.h b/src/util/spm-bs2bm.h new file mode 100644 index 000000000000..e705c519ee97 --- /dev/null +++ b/src/util/spm-bs2bm.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + */ + +#ifndef __UTIL_SPM_BS2BM__ +#define __UTIL_SPM_BS2BM__ + +#include "suricata-common.h" + +#define ALPHABET_SIZE 256 + +void Bs2BmBadchars(const uint8_t *, uint16_t, uint8_t *); +void Bs2BmBadcharsNocase(const uint8_t *, uint16_t, uint8_t *); +uint8_t *Bs2Bm(const uint8_t *, uint32_t, const uint8_t *, uint16_t, const uint8_t[]); +uint8_t *Bs2BmNocase(const uint8_t *, uint32_t, const uint8_t *, uint16_t, const uint8_t[]); + +#endif /* __UTIL_SPM_BS2BM__ */ diff --git a/src/util/spm-hs.c b/src/util/spm-hs.c new file mode 100644 index 000000000000..742f8f84205d --- /dev/null +++ b/src/util/spm-hs.c @@ -0,0 +1,232 @@ +/* Copyright (C) 2016-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Justin Viiret + * + * Single pattern matcher that uses the Hyperscan regex matcher. + */ + +#include "suricata-common.h" +#include "util/hyperscan.h" +#include "util/spm.h" +#include "util/spm-hs.h" +#include "util/debug.h" + +#ifdef BUILD_HYPERSCAN + +#include + +/** + * \internal + * \brief Hyperscan match callback, called by hs_scan. + */ +static int MatchEvent(unsigned int id, unsigned long long from, unsigned long long to, + unsigned int flags, void *context) +{ + uint64_t *match_offset = context; + BUG_ON(*match_offset != UINT64_MAX); + *match_offset = to; + return 1; /* Terminate matching. */ +} + +typedef struct SpmHsCtx_ { + hs_database_t *db; + uint16_t needle_len; +} SpmHsCtx; + +static void HSDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + SpmHsCtx *sctx = ctx->ctx; + if (sctx) { + hs_free_database(sctx->db); + SCFree(sctx); + } + SCFree(ctx); +} + +static int HSBuildDatabase(const uint8_t *needle, uint16_t needle_len, int nocase, SpmHsCtx *sctx, + SpmGlobalThreadCtx *global_thread_ctx) +{ + char *expr = HSRenderPattern(needle, needle_len); + if (expr == NULL) { + SCLogDebug("HSRenderPattern returned NULL"); + return -1; + } + + unsigned flags = nocase ? HS_FLAG_CASELESS : 0; + + hs_database_t *db = NULL; + hs_compile_error_t *compile_err = NULL; + hs_error_t err = hs_compile(expr, flags, HS_MODE_BLOCK, NULL, &db, &compile_err); + if (err != HS_SUCCESS) { + SCLogError("Unable to compile '%s' with Hyperscan, " + "returned %d.", + expr, err); + return -1; + } + + SCFree(expr); + + /* Update scratch for this database. */ + hs_scratch_t *scratch = global_thread_ctx->ctx; + err = hs_alloc_scratch(db, &scratch); + if (err != HS_SUCCESS) { + /* If scratch allocation failed, this is not recoverable: other SPM + * contexts may need this scratch space. */ + SCLogError("Unable to alloc scratch for Hyperscan, returned %d.", err); + return -1; + } + global_thread_ctx->ctx = scratch; + sctx->db = db; + sctx->needle_len = needle_len; + + return 0; +} + +static SpmCtx *HSInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmCtx *ctx = SCCalloc(1, sizeof(SpmCtx)); + if (ctx == NULL) { + SCLogDebug("Unable to alloc SpmCtx."); + return NULL; + } + ctx->matcher = SPM_HS; + + SpmHsCtx *sctx = SCCalloc(1, sizeof(SpmHsCtx)); + if (sctx == NULL) { + SCLogDebug("Unable to alloc SpmHsCtx."); + SCFree(ctx); + return NULL; + } + ctx->ctx = sctx; + + if (HSBuildDatabase(needle, needle_len, nocase, sctx, global_thread_ctx) != 0) { + SCLogDebug("HSBuildDatabase failed."); + HSDestroyCtx(ctx); + return NULL; + } + + return ctx; +} + +static uint8_t *HSScan( + const SpmCtx *ctx, SpmThreadCtx *thread_ctx, const uint8_t *haystack, uint32_t haystack_len) +{ + const SpmHsCtx *sctx = ctx->ctx; + hs_scratch_t *scratch = thread_ctx->ctx; + + if (unlikely(haystack_len == 0)) { + return NULL; + } + + uint64_t match_offset = UINT64_MAX; + hs_error_t err = hs_scan( + sctx->db, (const char *)haystack, haystack_len, 0, scratch, MatchEvent, &match_offset); + if (err != HS_SUCCESS && err != HS_SCAN_TERMINATED) { + /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() + * indicates that it was passed an invalid database or scratch region, + * which is not something we can recover from at scan time. */ + SCLogError("Hyperscan returned fatal error %d.", err); + exit(EXIT_FAILURE); + } + + if (match_offset == UINT64_MAX) { + return NULL; + } + + BUG_ON(match_offset < sctx->needle_len); + + /* Note: existing API returns non-const ptr */ + return (uint8_t *)haystack + (match_offset - sctx->needle_len); +} + +static SpmGlobalThreadCtx *HSInitGlobalThreadCtx(void) +{ + SpmGlobalThreadCtx *global_thread_ctx = SCCalloc(1, sizeof(SpmGlobalThreadCtx)); + if (global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmGlobalThreadCtx."); + return NULL; + } + global_thread_ctx->matcher = SPM_HS; + + /* We store scratch in the HS-specific ctx. This will be initialized as + * patterns are compiled by SpmInitCtx. */ + global_thread_ctx->ctx = NULL; + + return global_thread_ctx; +} + +static void HSDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + hs_free_scratch(global_thread_ctx->ctx); + SCFree(global_thread_ctx); +} + +static void HSDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + hs_free_scratch(thread_ctx->ctx); + SCFree(thread_ctx); +} + +static SpmThreadCtx *HSMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmThreadCtx *thread_ctx = SCCalloc(1, sizeof(SpmThreadCtx)); + if (thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + thread_ctx->matcher = SPM_HS; + + if (global_thread_ctx->ctx != NULL) { + hs_scratch_t *scratch = NULL; + hs_error_t err = hs_clone_scratch(global_thread_ctx->ctx, &scratch); + if (err != HS_SUCCESS) { + SCLogError("Unable to clone scratch (error %d).", err); + exit(EXIT_FAILURE); + } + thread_ctx->ctx = scratch; + } + + return thread_ctx; +} + +void SpmHSRegister(void) +{ + spm_table[SPM_HS].name = "hs"; + spm_table[SPM_HS].InitGlobalThreadCtx = HSInitGlobalThreadCtx; + spm_table[SPM_HS].DestroyGlobalThreadCtx = HSDestroyGlobalThreadCtx; + spm_table[SPM_HS].MakeThreadCtx = HSMakeThreadCtx; + spm_table[SPM_HS].DestroyThreadCtx = HSDestroyThreadCtx; + spm_table[SPM_HS].InitCtx = HSInitCtx; + spm_table[SPM_HS].DestroyCtx = HSDestroyCtx; + spm_table[SPM_HS].Scan = HSScan; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-spm-hs.h b/src/util/spm-hs.h similarity index 100% rename from src/util-spm-hs.h rename to src/util/spm-hs.h diff --git a/src/util/spm.c b/src/util/spm.c new file mode 100644 index 000000000000..deccb9f3495b --- /dev/null +++ b/src/util/spm.c @@ -0,0 +1,3133 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * + * PR (17/01/2010): Single pattern search algorithms: + * Currently there are 3 algorithms to choose: BasicSearch, Bs2Bm and + * BoyerMoore (Boyer Moores algorithm). The first one doesn't need a context. + * But for Bs2Bm and BoyerMoore, you'll need to build some arrays. + * + * !! If you are going to use the same pattern multiple times, + * please, try to store the context some where. For Bs2Bm, the + * context is an array of "badchars". For BoyerMoore you need to store + * two arrays of shifts. Have a look at the wrappers and unittests + * for examples of this. If you cant store the context, use the + * wrappers: Bs2bmSearch, BoyerMooreSearch, and the ones caseless, or BasicSearch + * That is the most basic. + * + * Use the stats and util-clock.h to determine which one fit better for you + * Boyer Moore should be used for patterns greater than 1 of length + * In the range of 2 - 6, if the text length is greater than 1000 you could + * use boyer moore, otherwise, basic search. If the pattern is greater + * than 6 and the textlen is greater than 500, use boyer moore. + * This is an aproximation, but use the stats and util-clock to determine which one + * fit better for your case. + * + */ + +#include "suricata-common.h" +#include "util/unittest.h" + +#include "../conf.h" + +#include "util/spm.h" +#include "util/spm-bs.h" +#include "util/spm-bs2bm.h" +#include "util/spm-bm.h" +#include "util/spm-hs.h" +#include "util/clock.h" +#ifdef BUILD_HYPERSCAN +#include "hs.h" +#endif +#include "util/debug.h" + +SpmTableElmt spm_table[SPM_TABLE_SIZE]; + +/** + * \brief Returns the single pattern matcher algorithm to be used, based on the + * spm-algo setting in yaml. + */ +uint8_t SinglePatternMatchDefaultMatcher(void) +{ + const char *spm_algo; + if ((ConfGet("spm-algo", &spm_algo)) == 1) { + if (spm_algo != NULL) { + if (strcmp("auto", spm_algo) == 0) { + goto default_matcher; + } + for (uint8_t i = 0; i < SPM_TABLE_SIZE; i++) { + if (spm_table[i].name == NULL) { + continue; + } + if (strcmp(spm_table[i].name, spm_algo) == 0) { + return i; + } + } + } + +#ifndef BUILD_HYPERSCAN + if ((spm_algo != NULL) && (strcmp(spm_algo, "hs") == 0)) { + FatalError("Hyperscan (hs) support for spm-algo is " + "not compiled into Suricata."); + } +#endif + SCLogError("Invalid spm algo supplied " + "in the yaml conf file: \"%s\"", + spm_algo); + exit(EXIT_FAILURE); + } + +default_matcher: + /* When Suricata is built with Hyperscan support, default to using it for + * SPM. */ +#ifdef BUILD_HYPERSCAN +#ifdef HAVE_HS_VALID_PLATFORM + /* Enable runtime check for SSSE3. Do not use Hyperscan SPM matcher if + * check is not successful. */ + if (hs_valid_platform() != HS_SUCCESS) { + SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " + "SPM"); + /* Use Boyer-Moore as fallback. */ + return SPM_BM; + } else { + return SPM_HS; + } +#else + return SPM_HS; +#endif +#else + /* Otherwise, default to Boyer-Moore */ + return SPM_BM; +#endif +} + +void SpmTableSetup(void) +{ + memset(spm_table, 0, sizeof(spm_table)); + + SpmBMRegister(); +#ifdef BUILD_HYPERSCAN +#ifdef HAVE_HS_VALID_PLATFORM + if (hs_valid_platform() == HS_SUCCESS) { + SpmHSRegister(); + } +#else + SpmHSRegister(); +#endif +#endif +} + +SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint8_t matcher) +{ + BUG_ON(spm_table[matcher].InitGlobalThreadCtx == NULL); + return spm_table[matcher].InitGlobalThreadCtx(); +} + +void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + uint8_t matcher = global_thread_ctx->matcher; + spm_table[matcher].DestroyGlobalThreadCtx(global_thread_ctx); +} + +SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return NULL; + } + uint8_t matcher = global_thread_ctx->matcher; + BUG_ON(spm_table[matcher].MakeThreadCtx == NULL); + return spm_table[matcher].MakeThreadCtx(global_thread_ctx); +} + +void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + uint8_t matcher = thread_ctx->matcher; + BUG_ON(spm_table[matcher].DestroyThreadCtx == NULL); + spm_table[matcher].DestroyThreadCtx(thread_ctx); +} + +SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + BUG_ON(global_thread_ctx == NULL); + uint8_t matcher = global_thread_ctx->matcher; + BUG_ON(spm_table[matcher].InitCtx == NULL); + return spm_table[matcher].InitCtx(needle, needle_len, nocase, global_thread_ctx); +} + +void SpmDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + uint8_t matcher = ctx->matcher; + BUG_ON(spm_table[matcher].DestroyCtx == NULL); + spm_table[matcher].DestroyCtx(ctx); +} + +uint8_t *SpmScan( + const SpmCtx *ctx, SpmThreadCtx *thread_ctx, const uint8_t *haystack, uint32_t haystack_len) +{ + uint8_t matcher = ctx->matcher; + return spm_table[matcher].Scan(ctx, thread_ctx, haystack, haystack_len); +} + +/** + * Wrappers for building context and searching (Bs2Bm and boyermoore) + * Use them if you cant store the context + * + */ + +/** + * \brief Search a pattern in the text using the Bs2Bm algorithm (build a bad characters array) + * + * \param text Text to search in + * \param textlen length of the text + * \param needle pattern to search for + * \param needlelen length of the pattern + */ +uint8_t *Bs2bmSearch( + const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen) +{ + uint8_t badchars[ALPHABET_SIZE]; + Bs2BmBadchars(needle, needlelen, badchars); + + return Bs2Bm(text, textlen, needle, needlelen, badchars); +} + +/** + * \brief Search a pattern in the text using the Bs2Bm nocase algorithm (build a bad characters + * array) + * + * \param text Text to search in + * \param textlen length of the text + * \param needle pattern to search for + * \param needlelen length of the pattern + */ +uint8_t *Bs2bmNocaseSearch( + const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen) +{ + uint8_t badchars[ALPHABET_SIZE]; + Bs2BmBadchars(needle, needlelen, badchars); + + return Bs2BmNocase(text, textlen, needle, needlelen, badchars); +} + +/** + * \brief Search a pattern in the text using Boyer Moore algorithm + * (build a bad character shifts array and good prefixes shift array) + * + * \param text Text to search in + * \param textlen length of the text + * \param needle pattern to search for + * \param needlelen length of the pattern + */ +uint8_t *BoyerMooreSearch( + const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen) +{ + BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); + + uint8_t *ret = BoyerMoore(needle, needlelen, text, textlen, bm_ctx); + BoyerMooreCtxDeInit(bm_ctx); + + return ret; +} + +/** + * \brief Search a pattern in the text using Boyer Moore nocase algorithm + * (build a bad character shifts array and good prefixes shift array) + * + * \param text Text to search in + * \param textlen length of the text + * \param needle pattern to search for + * \param needlelen length of the pattern + */ +uint8_t *BoyerMooreNocaseSearch( + const uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +{ + BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); + + uint8_t *ret = BoyerMooreNocase(needle, needlelen, text, textlen, bm_ctx); + BoyerMooreCtxDeInit(bm_ctx); + + return ret; +} + +#ifdef UNITTESTS + +/** Comment out this if you want stats + * #define ENABLE_SEARCH_STATS 1 + */ + +/* Number of times to repeat the search (for stats) */ +#define STATS_TIMES 1000000 + +/** + * \brief Unittest helper function wrappers for the search algorithms + * \param text pointer to the buffer to search in + * \param needle pointer to the pattern to search for + * \param times If you are testing performance, se the numebr of times + * that you want to repeat the search + */ +static uint8_t *BasicSearchWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = (uint16_t)strlen((char *)needle); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + + for (i = 0; i < times; i++) { + ret = BasicSearch(text, textlen, needle, needlelen); + } + + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *BasicSearchNocaseWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = (uint16_t)strlen((char *)needle); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + ret = BasicSearchNocase(text, textlen, needle, needlelen); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *Bs2bmWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = (uint16_t)strlen((char *)needle); + + uint8_t badchars[ALPHABET_SIZE]; + Bs2BmBadchars(needle, needlelen, badchars); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + ret = Bs2Bm(text, textlen, needle, needlelen, badchars); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *Bs2bmNocaseWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = (uint16_t)strlen((char *)needle); + + uint8_t badchars[ALPHABET_SIZE]; + Bs2BmBadchars(needle, needlelen, badchars); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + ret = Bs2BmNocase(text, textlen, needle, needlelen, badchars); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *BoyerMooreWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = (uint16_t)strlen((char *)needle); + + BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + ret = BoyerMoore(needle, needlelen, text, textlen, bm_ctx); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + BoyerMooreCtxDeInit(bm_ctx); + return ret; +} + +static uint8_t *BoyerMooreNocaseWrapper(uint8_t *text, uint8_t *in_needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = (uint16_t)strlen((char *)in_needle); + + /* Make a copy of in_needle to be able to convert it to lowercase. */ + uint8_t *needle = SCMalloc(needlelen); + if (needle == NULL) + return NULL; + memcpy(needle, in_needle, needlelen); + + BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + ret = BoyerMooreNocase(needle, needlelen, text, textlen, bm_ctx); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + BoyerMooreCtxDeInit(bm_ctx); + free(needle); + return ret; +} + +#ifdef ENABLE_SEARCH_STATS +/** + * \brief Unittest helper function wrappers for the search algorithms + * \param text pointer to the buffer to search in + * \param needle pointer to the pattern to search for + * \param times If you are testing performance, se the numebr of times + * that you want to repeat the search + */ +static uint8_t *BasicSearchCtxWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = strlen((char *)needle); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + /* This wrapper is a fake, no context needed! */ + ret = BasicSearch(text, textlen, needle, needlelen); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *BasicSearchNocaseCtxWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = strlen((char *)needle); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + /* This wrapper is a fake, no context needed! */ + ret = BasicSearchNocase(text, textlen, needle, needlelen); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *Bs2bmCtxWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = strlen((char *)needle); + + uint8_t badchars[ALPHABET_SIZE]; + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + /* Stats including context building */ + Bs2BmBadchars(needle, needlelen, badchars); + ret = Bs2Bm(text, textlen, needle, needlelen, badchars); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *Bs2bmNocaseCtxWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = strlen((char *)needle); + + uint8_t badchars[ALPHABET_SIZE]; + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + /* Stats including context building */ + Bs2BmBadchars(needle, needlelen, badchars); + ret = Bs2BmNocase(text, textlen, needle, needlelen, badchars); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *BoyerMooreCtxWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = strlen((char *)needle); + + BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + /* Stats including context building */ + ret = BoyerMoore(needle, needlelen, text, textlen, bm_ctx); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + BoyerMooreCtxDeInit(bm_ctx); + + return ret; +} + +static uint8_t *RawCtxWrapper(uint8_t *text, uint8_t *needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = strlen((char *)needle); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + ret = SpmSearch(text, textlen, needle, needlelen); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + return ret; +} + +static uint8_t *BoyerMooreNocaseCtxWrapper(uint8_t *text, uint8_t *in_needle, int times) +{ + uint32_t textlen = strlen((char *)text); + uint16_t needlelen = strlen((char *)in_needle); + + /* Make a copy of in_needle to be able to convert it to lowercase. */ + uint8_t *needle = SCMalloc(needlelen); + if (needle == NULL) + return NULL; + memcpy(needle, in_needle, needlelen); + + BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); + + uint8_t *ret = NULL; + int i = 0; + + CLOCK_INIT; + if (times > 1) + CLOCK_START; + for (i = 0; i < times; i++) { + ret = BoyerMooreNocase(needle, needlelen, text, textlen, bm_ctx); + } + if (times > 1) { + CLOCK_END; + CLOCK_PRINT_SEC; + }; + BoyerMooreCtxDeInit(bm_ctx); + free(needle); + return ret; +} +#endif + +/** + * \test Generic test for BasicSearch matching + */ +static int UtilSpmBasicSearchTest01(void) +{ + uint8_t *needle = (uint8_t *)"oPqRsT"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BasicSearchWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 1; + else + return 0; +} + +/** + * \test Generic test for BasicSearch nocase matching + */ +static int UtilSpmBasicSearchNocaseTest01(void) +{ + uint8_t *needle = (uint8_t *)"OpQrSt"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BasicSearchNocaseWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 1; + else + return 0; +} + +/** + * \test Generic test for Bs2Bm matching + */ +static int UtilSpmBs2bmSearchTest01(void) +{ + uint8_t *needle = (uint8_t *)"oPqRsT"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = Bs2bmWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 1; + else + return 0; +} + +/** + * \test Generic test for Bs2Bm no case matching + */ +static int UtilSpmBs2bmSearchNocaseTest01(void) +{ + uint8_t *needle = (uint8_t *)"OpQrSt"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = Bs2bmNocaseWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 1; + else + return 0; +} + +/** + * \test Generic test for boyer moore matching + */ +static int UtilSpmBoyerMooreSearchTest01(void) +{ + uint8_t *needle = (uint8_t *)"oPqRsT"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BoyerMooreWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 1; + else + return 0; +} + +/** + * \test Generic test for boyer moore nocase matching + */ +static int UtilSpmBoyerMooreSearchNocaseTest01(void) +{ + uint8_t *needle = (uint8_t *)"OpQrSt"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 1; + else + return 0; +} + +/** + * \test issue 130 (@redmine) check to ensure that the + * problem is not the algorithm implementation + */ +static int UtilSpmBoyerMooreSearchNocaseTestIssue130(void) +{ + uint8_t *needle = (uint8_t *)"WWW-Authenticate: "; + uint8_t *text = + (uint8_t *)"Date: Mon, 23 Feb 2009 13:31:49 GMT" + "Server: Apache\r\n" + "Www-authenticate: Basic realm=\"Authentification user password\"\r\n" + "Vary: accept-language,accept-charset\r\n" + "Accept-ranges: bytes\r\n" + "Connection: close\r\n" + "Content-type: text/html; charset=iso-8859-1\r\n" + "Content-language: fr\r\n" + "Expires: Mon, 23 Feb 2009 13:31:49 GMT\r\n\r\n"; + uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 1; + else + return 0; +} + +/* Generic tests that should not match */ +static int UtilSpmBasicSearchTest02(void) +{ + uint8_t *needle = (uint8_t *)"oPQRsT"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BasicSearchWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 0; + else + return 1; +} + +static int UtilSpmBasicSearchNocaseTest02(void) +{ + uint8_t *needle = (uint8_t *)"OpZrSt"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BasicSearchNocaseWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 0; + else + return 1; +} + +static int UtilSpmBs2bmSearchTest02(void) +{ + uint8_t *needle = (uint8_t *)"oPQRsT"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = Bs2bmWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 0; + else + return 1; +} + +static int UtilSpmBs2bmSearchNocaseTest02(void) +{ + uint8_t *needle = (uint8_t *)"OpZrSt"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = Bs2bmNocaseWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 0; + else + return 1; +} + +static int UtilSpmBoyerMooreSearchTest02(void) +{ + uint8_t *needle = (uint8_t *)"oPQRsT"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BoyerMooreWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 0; + else + return 1; +} + +static int UtilSpmBoyerMooreSearchNocaseTest02(void) +{ + uint8_t *needle = (uint8_t *)"OpZrSt"; + uint8_t *text = (uint8_t *)"aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + uint8_t *found = BoyerMooreNocaseWrapper(text, needle, 1); + // printf("found: %s\n", found); + if (found != NULL) + return 0; + else + return 1; +} + +/** + * \test Check that all the algorithms work at any offset and any pattern length + */ +static int UtilSpmSearchOffsetsTest01(void) +{ + const char *text[26][27]; + text[0][0] = "azzzzzzzzzzzzzzzzzzzzzzzzzz"; + text[0][1] = "zazzzzzzzzzzzzzzzzzzzzzzzzz"; + text[0][2] = "zzazzzzzzzzzzzzzzzzzzzzzzzz"; + text[0][3] = "zzzazzzzzzzzzzzzzzzzzzzzzzz"; + text[0][4] = "zzzzazzzzzzzzzzzzzzzzzzzzzz"; + text[0][5] = "zzzzzazzzzzzzzzzzzzzzzzzzzz"; + text[0][6] = "zzzzzzazzzzzzzzzzzzzzzzzzzz"; + text[0][7] = "zzzzzzzazzzzzzzzzzzzzzzzzzz"; + text[0][8] = "zzzzzzzzazzzzzzzzzzzzzzzzzz"; + text[0][9] = "zzzzzzzzzazzzzzzzzzzzzzzzzz"; + text[0][10] = "zzzzzzzzzzazzzzzzzzzzzzzzzz"; + text[0][11] = "zzzzzzzzzzzazzzzzzzzzzzzzzz"; + text[0][12] = "zzzzzzzzzzzzazzzzzzzzzzzzzz"; + text[0][13] = "zzzzzzzzzzzzzazzzzzzzzzzzzz"; + text[0][14] = "zzzzzzzzzzzzzzazzzzzzzzzzzz"; + text[0][15] = "zzzzzzzzzzzzzzzazzzzzzzzzzz"; + text[0][16] = "zzzzzzzzzzzzzzzzazzzzzzzzzz"; + text[0][17] = "zzzzzzzzzzzzzzzzzazzzzzzzzz"; + text[0][18] = "zzzzzzzzzzzzzzzzzzazzzzzzzz"; + text[0][19] = "zzzzzzzzzzzzzzzzzzzazzzzzzz"; + text[0][20] = "zzzzzzzzzzzzzzzzzzzzazzzzzz"; + text[0][21] = "zzzzzzzzzzzzzzzzzzzzzazzzzz"; + text[0][22] = "zzzzzzzzzzzzzzzzzzzzzzazzzz"; + text[0][23] = "zzzzzzzzzzzzzzzzzzzzzzzazzz"; + text[0][24] = "zzzzzzzzzzzzzzzzzzzzzzzzazz"; + text[0][25] = "zzzzzzzzzzzzzzzzzzzzzzzzzaz"; + text[0][26] = "zzzzzzzzzzzzzzzzzzzzzzzzzza"; + text[1][0] = "aBzzzzzzzzzzzzzzzzzzzzzzzzz"; + text[1][1] = "zaBzzzzzzzzzzzzzzzzzzzzzzzz"; + text[1][2] = "zzaBzzzzzzzzzzzzzzzzzzzzzzz"; + text[1][3] = "zzzaBzzzzzzzzzzzzzzzzzzzzzz"; + text[1][4] = "zzzzaBzzzzzzzzzzzzzzzzzzzzz"; + text[1][5] = "zzzzzaBzzzzzzzzzzzzzzzzzzzz"; + text[1][6] = "zzzzzzaBzzzzzzzzzzzzzzzzzzz"; + text[1][7] = "zzzzzzzaBzzzzzzzzzzzzzzzzzz"; + text[1][8] = "zzzzzzzzaBzzzzzzzzzzzzzzzzz"; + text[1][9] = "zzzzzzzzzaBzzzzzzzzzzzzzzzz"; + text[1][10] = "zzzzzzzzzzaBzzzzzzzzzzzzzzz"; + text[1][11] = "zzzzzzzzzzzaBzzzzzzzzzzzzzz"; + text[1][12] = "zzzzzzzzzzzzaBzzzzzzzzzzzzz"; + text[1][13] = "zzzzzzzzzzzzzaBzzzzzzzzzzzz"; + text[1][14] = "zzzzzzzzzzzzzzaBzzzzzzzzzzz"; + text[1][15] = "zzzzzzzzzzzzzzzaBzzzzzzzzzz"; + text[1][16] = "zzzzzzzzzzzzzzzzaBzzzzzzzzz"; + text[1][17] = "zzzzzzzzzzzzzzzzzaBzzzzzzzz"; + text[1][18] = "zzzzzzzzzzzzzzzzzzaBzzzzzzz"; + text[1][19] = "zzzzzzzzzzzzzzzzzzzaBzzzzzz"; + text[1][20] = "zzzzzzzzzzzzzzzzzzzzaBzzzzz"; + text[1][21] = "zzzzzzzzzzzzzzzzzzzzzaBzzzz"; + text[1][22] = "zzzzzzzzzzzzzzzzzzzzzzaBzzz"; + text[1][23] = "zzzzzzzzzzzzzzzzzzzzzzzaBzz"; + text[1][24] = "zzzzzzzzzzzzzzzzzzzzzzzzaBz"; + text[1][25] = "zzzzzzzzzzzzzzzzzzzzzzzzzaB"; + text[2][0] = "aBczzzzzzzzzzzzzzzzzzzzzzzz"; + text[2][1] = "zaBczzzzzzzzzzzzzzzzzzzzzzz"; + text[2][2] = "zzaBczzzzzzzzzzzzzzzzzzzzzz"; + text[2][3] = "zzzaBczzzzzzzzzzzzzzzzzzzzz"; + text[2][4] = "zzzzaBczzzzzzzzzzzzzzzzzzzz"; + text[2][5] = "zzzzzaBczzzzzzzzzzzzzzzzzzz"; + text[2][6] = "zzzzzzaBczzzzzzzzzzzzzzzzzz"; + text[2][7] = "zzzzzzzaBczzzzzzzzzzzzzzzzz"; + text[2][8] = "zzzzzzzzaBczzzzzzzzzzzzzzzz"; + text[2][9] = "zzzzzzzzzaBczzzzzzzzzzzzzzz"; + text[2][10] = "zzzzzzzzzzaBczzzzzzzzzzzzzz"; + text[2][11] = "zzzzzzzzzzzaBczzzzzzzzzzzzz"; + text[2][12] = "zzzzzzzzzzzzaBczzzzzzzzzzzz"; + text[2][13] = "zzzzzzzzzzzzzaBczzzzzzzzzzz"; + text[2][14] = "zzzzzzzzzzzzzzaBczzzzzzzzzz"; + text[2][15] = "zzzzzzzzzzzzzzzaBczzzzzzzzz"; + text[2][16] = "zzzzzzzzzzzzzzzzaBczzzzzzzz"; + text[2][17] = "zzzzzzzzzzzzzzzzzaBczzzzzzz"; + text[2][18] = "zzzzzzzzzzzzzzzzzzaBczzzzzz"; + text[2][19] = "zzzzzzzzzzzzzzzzzzzaBczzzzz"; + text[2][20] = "zzzzzzzzzzzzzzzzzzzzaBczzzz"; + text[2][21] = "zzzzzzzzzzzzzzzzzzzzzaBczzz"; + text[2][22] = "zzzzzzzzzzzzzzzzzzzzzzaBczz"; + text[2][23] = "zzzzzzzzzzzzzzzzzzzzzzzaBcz"; + text[2][24] = "zzzzzzzzzzzzzzzzzzzzzzzzaBc"; + text[3][0] = "aBcDzzzzzzzzzzzzzzzzzzzzzzz"; + text[3][1] = "zaBcDzzzzzzzzzzzzzzzzzzzzzz"; + text[3][2] = "zzaBcDzzzzzzzzzzzzzzzzzzzzz"; + text[3][3] = "zzzaBcDzzzzzzzzzzzzzzzzzzzz"; + text[3][4] = "zzzzaBcDzzzzzzzzzzzzzzzzzzz"; + text[3][5] = "zzzzzaBcDzzzzzzzzzzzzzzzzzz"; + text[3][6] = "zzzzzzaBcDzzzzzzzzzzzzzzzzz"; + text[3][7] = "zzzzzzzaBcDzzzzzzzzzzzzzzzz"; + text[3][8] = "zzzzzzzzaBcDzzzzzzzzzzzzzzz"; + text[3][9] = "zzzzzzzzzaBcDzzzzzzzzzzzzzz"; + text[3][10] = "zzzzzzzzzzaBcDzzzzzzzzzzzzz"; + text[3][11] = "zzzzzzzzzzzaBcDzzzzzzzzzzzz"; + text[3][12] = "zzzzzzzzzzzzaBcDzzzzzzzzzzz"; + text[3][13] = "zzzzzzzzzzzzzaBcDzzzzzzzzzz"; + text[3][14] = "zzzzzzzzzzzzzzaBcDzzzzzzzzz"; + text[3][15] = "zzzzzzzzzzzzzzzaBcDzzzzzzzz"; + text[3][16] = "zzzzzzzzzzzzzzzzaBcDzzzzzzz"; + text[3][17] = "zzzzzzzzzzzzzzzzzaBcDzzzzzz"; + text[3][18] = "zzzzzzzzzzzzzzzzzzaBcDzzzzz"; + text[3][19] = "zzzzzzzzzzzzzzzzzzzaBcDzzzz"; + text[3][20] = "zzzzzzzzzzzzzzzzzzzzaBcDzzz"; + text[3][21] = "zzzzzzzzzzzzzzzzzzzzzaBcDzz"; + text[3][22] = "zzzzzzzzzzzzzzzzzzzzzzaBcDz"; + text[3][23] = "zzzzzzzzzzzzzzzzzzzzzzzaBcD"; + text[4][0] = "aBcDezzzzzzzzzzzzzzzzzzzzzz"; + text[4][1] = "zaBcDezzzzzzzzzzzzzzzzzzzzz"; + text[4][2] = "zzaBcDezzzzzzzzzzzzzzzzzzzz"; + text[4][3] = "zzzaBcDezzzzzzzzzzzzzzzzzzz"; + text[4][4] = "zzzzaBcDezzzzzzzzzzzzzzzzzz"; + text[4][5] = "zzzzzaBcDezzzzzzzzzzzzzzzzz"; + text[4][6] = "zzzzzzaBcDezzzzzzzzzzzzzzzz"; + text[4][7] = "zzzzzzzaBcDezzzzzzzzzzzzzzz"; + text[4][8] = "zzzzzzzzaBcDezzzzzzzzzzzzzz"; + text[4][9] = "zzzzzzzzzaBcDezzzzzzzzzzzzz"; + text[4][10] = "zzzzzzzzzzaBcDezzzzzzzzzzzz"; + text[4][11] = "zzzzzzzzzzzaBcDezzzzzzzzzzz"; + text[4][12] = "zzzzzzzzzzzzaBcDezzzzzzzzzz"; + text[4][13] = "zzzzzzzzzzzzzaBcDezzzzzzzzz"; + text[4][14] = "zzzzzzzzzzzzzzaBcDezzzzzzzz"; + text[4][15] = "zzzzzzzzzzzzzzzaBcDezzzzzzz"; + text[4][16] = "zzzzzzzzzzzzzzzzaBcDezzzzzz"; + text[4][17] = "zzzzzzzzzzzzzzzzzaBcDezzzzz"; + text[4][18] = "zzzzzzzzzzzzzzzzzzaBcDezzzz"; + text[4][19] = "zzzzzzzzzzzzzzzzzzzaBcDezzz"; + text[4][20] = "zzzzzzzzzzzzzzzzzzzzaBcDezz"; + text[4][21] = "zzzzzzzzzzzzzzzzzzzzzaBcDez"; + text[4][22] = "zzzzzzzzzzzzzzzzzzzzzzaBcDe"; + text[5][0] = "aBcDeFzzzzzzzzzzzzzzzzzzzzz"; + text[5][1] = "zaBcDeFzzzzzzzzzzzzzzzzzzzz"; + text[5][2] = "zzaBcDeFzzzzzzzzzzzzzzzzzzz"; + text[5][3] = "zzzaBcDeFzzzzzzzzzzzzzzzzzz"; + text[5][4] = "zzzzaBcDeFzzzzzzzzzzzzzzzzz"; + text[5][5] = "zzzzzaBcDeFzzzzzzzzzzzzzzzz"; + text[5][6] = "zzzzzzaBcDeFzzzzzzzzzzzzzzz"; + text[5][7] = "zzzzzzzaBcDeFzzzzzzzzzzzzzz"; + text[5][8] = "zzzzzzzzaBcDeFzzzzzzzzzzzzz"; + text[5][9] = "zzzzzzzzzaBcDeFzzzzzzzzzzzz"; + text[5][10] = "zzzzzzzzzzaBcDeFzzzzzzzzzzz"; + text[5][11] = "zzzzzzzzzzzaBcDeFzzzzzzzzzz"; + text[5][12] = "zzzzzzzzzzzzaBcDeFzzzzzzzzz"; + text[5][13] = "zzzzzzzzzzzzzaBcDeFzzzzzzzz"; + text[5][14] = "zzzzzzzzzzzzzzaBcDeFzzzzzzz"; + text[5][15] = "zzzzzzzzzzzzzzzaBcDeFzzzzzz"; + text[5][16] = "zzzzzzzzzzzzzzzzaBcDeFzzzzz"; + text[5][17] = "zzzzzzzzzzzzzzzzzaBcDeFzzzz"; + text[5][18] = "zzzzzzzzzzzzzzzzzzaBcDeFzzz"; + text[5][19] = "zzzzzzzzzzzzzzzzzzzaBcDeFzz"; + text[5][20] = "zzzzzzzzzzzzzzzzzzzzaBcDeFz"; + text[5][21] = "zzzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6][0] = "aBcDeFgzzzzzzzzzzzzzzzzzzzz"; + text[6][1] = "zaBcDeFgzzzzzzzzzzzzzzzzzzz"; + text[6][2] = "zzaBcDeFgzzzzzzzzzzzzzzzzzz"; + text[6][3] = "zzzaBcDeFgzzzzzzzzzzzzzzzzz"; + text[6][4] = "zzzzaBcDeFgzzzzzzzzzzzzzzzz"; + text[6][5] = "zzzzzaBcDeFgzzzzzzzzzzzzzzz"; + text[6][6] = "zzzzzzaBcDeFgzzzzzzzzzzzzzz"; + text[6][7] = "zzzzzzzaBcDeFgzzzzzzzzzzzzz"; + text[6][8] = "zzzzzzzzaBcDeFgzzzzzzzzzzzz"; + text[6][9] = "zzzzzzzzzaBcDeFgzzzzzzzzzzz"; + text[6][10] = "zzzzzzzzzzaBcDeFgzzzzzzzzzz"; + text[6][11] = "zzzzzzzzzzzaBcDeFgzzzzzzzzz"; + text[6][12] = "zzzzzzzzzzzzaBcDeFgzzzzzzzz"; + text[6][13] = "zzzzzzzzzzzzzaBcDeFgzzzzzzz"; + text[6][14] = "zzzzzzzzzzzzzzaBcDeFgzzzzzz"; + text[6][15] = "zzzzzzzzzzzzzzzaBcDeFgzzzzz"; + text[6][16] = "zzzzzzzzzzzzzzzzaBcDeFgzzzz"; + text[6][17] = "zzzzzzzzzzzzzzzzzaBcDeFgzzz"; + text[6][18] = "zzzzzzzzzzzzzzzzzzaBcDeFgzz"; + text[6][19] = "zzzzzzzzzzzzzzzzzzzaBcDeFgz"; + text[6][20] = "zzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7][0] = "aBcDeFgHzzzzzzzzzzzzzzzzzzz"; + text[7][1] = "zaBcDeFgHzzzzzzzzzzzzzzzzzz"; + text[7][2] = "zzaBcDeFgHzzzzzzzzzzzzzzzzz"; + text[7][3] = "zzzaBcDeFgHzzzzzzzzzzzzzzzz"; + text[7][4] = "zzzzaBcDeFgHzzzzzzzzzzzzzzz"; + text[7][5] = "zzzzzaBcDeFgHzzzzzzzzzzzzzz"; + text[7][6] = "zzzzzzaBcDeFgHzzzzzzzzzzzzz"; + text[7][7] = "zzzzzzzaBcDeFgHzzzzzzzzzzzz"; + text[7][8] = "zzzzzzzzaBcDeFgHzzzzzzzzzzz"; + text[7][9] = "zzzzzzzzzaBcDeFgHzzzzzzzzzz"; + text[7][10] = "zzzzzzzzzzaBcDeFgHzzzzzzzzz"; + text[7][11] = "zzzzzzzzzzzaBcDeFgHzzzzzzzz"; + text[7][12] = "zzzzzzzzzzzzaBcDeFgHzzzzzzz"; + text[7][13] = "zzzzzzzzzzzzzaBcDeFgHzzzzzz"; + text[7][14] = "zzzzzzzzzzzzzzaBcDeFgHzzzzz"; + text[7][15] = "zzzzzzzzzzzzzzzaBcDeFgHzzzz"; + text[7][16] = "zzzzzzzzzzzzzzzzaBcDeFgHzzz"; + text[7][17] = "zzzzzzzzzzzzzzzzzaBcDeFgHzz"; + text[7][18] = "zzzzzzzzzzzzzzzzzzaBcDeFgHz"; + text[7][19] = "zzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8][0] = "aBcDeFgHizzzzzzzzzzzzzzzzzz"; + text[8][1] = "zaBcDeFgHizzzzzzzzzzzzzzzzz"; + text[8][2] = "zzaBcDeFgHizzzzzzzzzzzzzzzz"; + text[8][3] = "zzzaBcDeFgHizzzzzzzzzzzzzzz"; + text[8][4] = "zzzzaBcDeFgHizzzzzzzzzzzzzz"; + text[8][5] = "zzzzzaBcDeFgHizzzzzzzzzzzzz"; + text[8][6] = "zzzzzzaBcDeFgHizzzzzzzzzzzz"; + text[8][7] = "zzzzzzzaBcDeFgHizzzzzzzzzzz"; + text[8][8] = "zzzzzzzzaBcDeFgHizzzzzzzzzz"; + text[8][9] = "zzzzzzzzzaBcDeFgHizzzzzzzzz"; + text[8][10] = "zzzzzzzzzzaBcDeFgHizzzzzzzz"; + text[8][11] = "zzzzzzzzzzzaBcDeFgHizzzzzzz"; + text[8][12] = "zzzzzzzzzzzzaBcDeFgHizzzzzz"; + text[8][13] = "zzzzzzzzzzzzzaBcDeFgHizzzzz"; + text[8][14] = "zzzzzzzzzzzzzzaBcDeFgHizzzz"; + text[8][15] = "zzzzzzzzzzzzzzzaBcDeFgHizzz"; + text[8][16] = "zzzzzzzzzzzzzzzzaBcDeFgHizz"; + text[8][17] = "zzzzzzzzzzzzzzzzzaBcDeFgHiz"; + text[8][18] = "zzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9][0] = "aBcDeFgHiJzzzzzzzzzzzzzzzzz"; + text[9][1] = "zaBcDeFgHiJzzzzzzzzzzzzzzzz"; + text[9][2] = "zzaBcDeFgHiJzzzzzzzzzzzzzzz"; + text[9][3] = "zzzaBcDeFgHiJzzzzzzzzzzzzzz"; + text[9][4] = "zzzzaBcDeFgHiJzzzzzzzzzzzzz"; + text[9][5] = "zzzzzaBcDeFgHiJzzzzzzzzzzzz"; + text[9][6] = "zzzzzzaBcDeFgHiJzzzzzzzzzzz"; + text[9][7] = "zzzzzzzaBcDeFgHiJzzzzzzzzzz"; + text[9][8] = "zzzzzzzzaBcDeFgHiJzzzzzzzzz"; + text[9][9] = "zzzzzzzzzaBcDeFgHiJzzzzzzzz"; + text[9][10] = "zzzzzzzzzzaBcDeFgHiJzzzzzzz"; + text[9][11] = "zzzzzzzzzzzaBcDeFgHiJzzzzzz"; + text[9][12] = "zzzzzzzzzzzzaBcDeFgHiJzzzzz"; + text[9][13] = "zzzzzzzzzzzzzaBcDeFgHiJzzzz"; + text[9][14] = "zzzzzzzzzzzzzzaBcDeFgHiJzzz"; + text[9][15] = "zzzzzzzzzzzzzzzaBcDeFgHiJzz"; + text[9][16] = "zzzzzzzzzzzzzzzzaBcDeFgHiJz"; + text[9][17] = "zzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10][0] = "aBcDeFgHiJkzzzzzzzzzzzzzzzz"; + text[10][1] = "zaBcDeFgHiJkzzzzzzzzzzzzzzz"; + text[10][2] = "zzaBcDeFgHiJkzzzzzzzzzzzzzz"; + text[10][3] = "zzzaBcDeFgHiJkzzzzzzzzzzzzz"; + text[10][4] = "zzzzaBcDeFgHiJkzzzzzzzzzzzz"; + text[10][5] = "zzzzzaBcDeFgHiJkzzzzzzzzzzz"; + text[10][6] = "zzzzzzaBcDeFgHiJkzzzzzzzzzz"; + text[10][7] = "zzzzzzzaBcDeFgHiJkzzzzzzzzz"; + text[10][8] = "zzzzzzzzaBcDeFgHiJkzzzzzzzz"; + text[10][9] = "zzzzzzzzzaBcDeFgHiJkzzzzzzz"; + text[10][10] = "zzzzzzzzzzaBcDeFgHiJkzzzzzz"; + text[10][11] = "zzzzzzzzzzzaBcDeFgHiJkzzzzz"; + text[10][12] = "zzzzzzzzzzzzaBcDeFgHiJkzzzz"; + text[10][13] = "zzzzzzzzzzzzzaBcDeFgHiJkzzz"; + text[10][14] = "zzzzzzzzzzzzzzaBcDeFgHiJkzz"; + text[10][15] = "zzzzzzzzzzzzzzzaBcDeFgHiJkz"; + text[10][16] = "zzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11][0] = "aBcDeFgHiJkLzzzzzzzzzzzzzzz"; + text[11][1] = "zaBcDeFgHiJkLzzzzzzzzzzzzzz"; + text[11][2] = "zzaBcDeFgHiJkLzzzzzzzzzzzzz"; + text[11][3] = "zzzaBcDeFgHiJkLzzzzzzzzzzzz"; + text[11][4] = "zzzzaBcDeFgHiJkLzzzzzzzzzzz"; + text[11][5] = "zzzzzaBcDeFgHiJkLzzzzzzzzzz"; + text[11][6] = "zzzzzzaBcDeFgHiJkLzzzzzzzzz"; + text[11][7] = "zzzzzzzaBcDeFgHiJkLzzzzzzzz"; + text[11][8] = "zzzzzzzzaBcDeFgHiJkLzzzzzzz"; + text[11][9] = "zzzzzzzzzaBcDeFgHiJkLzzzzzz"; + text[11][10] = "zzzzzzzzzzaBcDeFgHiJkLzzzzz"; + text[11][11] = "zzzzzzzzzzzaBcDeFgHiJkLzzzz"; + text[11][12] = "zzzzzzzzzzzzaBcDeFgHiJkLzzz"; + text[11][13] = "zzzzzzzzzzzzzaBcDeFgHiJkLzz"; + text[11][14] = "zzzzzzzzzzzzzzaBcDeFgHiJkLz"; + text[11][15] = "zzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12][0] = "aBcDeFgHiJkLmzzzzzzzzzzzzzz"; + text[12][1] = "zaBcDeFgHiJkLmzzzzzzzzzzzzz"; + text[12][2] = "zzaBcDeFgHiJkLmzzzzzzzzzzzz"; + text[12][3] = "zzzaBcDeFgHiJkLmzzzzzzzzzzz"; + text[12][4] = "zzzzaBcDeFgHiJkLmzzzzzzzzzz"; + text[12][5] = "zzzzzaBcDeFgHiJkLmzzzzzzzzz"; + text[12][6] = "zzzzzzaBcDeFgHiJkLmzzzzzzzz"; + text[12][7] = "zzzzzzzaBcDeFgHiJkLmzzzzzzz"; + text[12][8] = "zzzzzzzzaBcDeFgHiJkLmzzzzzz"; + text[12][9] = "zzzzzzzzzaBcDeFgHiJkLmzzzzz"; + text[12][10] = "zzzzzzzzzzaBcDeFgHiJkLmzzzz"; + text[12][11] = "zzzzzzzzzzzaBcDeFgHiJkLmzzz"; + text[12][12] = "zzzzzzzzzzzzaBcDeFgHiJkLmzz"; + text[12][13] = "zzzzzzzzzzzzzaBcDeFgHiJkLmz"; + text[12][14] = "zzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13][0] = "aBcDeFgHiJkLmNzzzzzzzzzzzzz"; + text[13][1] = "zaBcDeFgHiJkLmNzzzzzzzzzzzz"; + text[13][2] = "zzaBcDeFgHiJkLmNzzzzzzzzzzz"; + text[13][3] = "zzzaBcDeFgHiJkLmNzzzzzzzzzz"; + text[13][4] = "zzzzaBcDeFgHiJkLmNzzzzzzzzz"; + text[13][5] = "zzzzzaBcDeFgHiJkLmNzzzzzzzz"; + text[13][6] = "zzzzzzaBcDeFgHiJkLmNzzzzzzz"; + text[13][7] = "zzzzzzzaBcDeFgHiJkLmNzzzzzz"; + text[13][8] = "zzzzzzzzaBcDeFgHiJkLmNzzzzz"; + text[13][9] = "zzzzzzzzzaBcDeFgHiJkLmNzzzz"; + text[13][10] = "zzzzzzzzzzaBcDeFgHiJkLmNzzz"; + text[13][11] = "zzzzzzzzzzzaBcDeFgHiJkLmNzz"; + text[13][12] = "zzzzzzzzzzzzaBcDeFgHiJkLmNz"; + text[13][13] = "zzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14][0] = "aBcDeFgHiJkLmNozzzzzzzzzzzz"; + text[14][1] = "zaBcDeFgHiJkLmNozzzzzzzzzzz"; + text[14][2] = "zzaBcDeFgHiJkLmNozzzzzzzzzz"; + text[14][3] = "zzzaBcDeFgHiJkLmNozzzzzzzzz"; + text[14][4] = "zzzzaBcDeFgHiJkLmNozzzzzzzz"; + text[14][5] = "zzzzzaBcDeFgHiJkLmNozzzzzzz"; + text[14][6] = "zzzzzzaBcDeFgHiJkLmNozzzzzz"; + text[14][7] = "zzzzzzzaBcDeFgHiJkLmNozzzzz"; + text[14][8] = "zzzzzzzzaBcDeFgHiJkLmNozzzz"; + text[14][9] = "zzzzzzzzzaBcDeFgHiJkLmNozzz"; + text[14][10] = "zzzzzzzzzzaBcDeFgHiJkLmNozz"; + text[14][11] = "zzzzzzzzzzzaBcDeFgHiJkLmNoz"; + text[14][12] = "zzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15][0] = "aBcDeFgHiJkLmNoPzzzzzzzzzzz"; + text[15][1] = "zaBcDeFgHiJkLmNoPzzzzzzzzzz"; + text[15][2] = "zzaBcDeFgHiJkLmNoPzzzzzzzzz"; + text[15][3] = "zzzaBcDeFgHiJkLmNoPzzzzzzzz"; + text[15][4] = "zzzzaBcDeFgHiJkLmNoPzzzzzzz"; + text[15][5] = "zzzzzaBcDeFgHiJkLmNoPzzzzzz"; + text[15][6] = "zzzzzzaBcDeFgHiJkLmNoPzzzzz"; + text[15][7] = "zzzzzzzaBcDeFgHiJkLmNoPzzzz"; + text[15][8] = "zzzzzzzzaBcDeFgHiJkLmNoPzzz"; + text[15][9] = "zzzzzzzzzaBcDeFgHiJkLmNoPzz"; + text[15][10] = "zzzzzzzzzzaBcDeFgHiJkLmNoPz"; + text[15][11] = "zzzzzzzzzzzaBcDeFgHiJkLmNoP"; + text[16][0] = "aBcDeFgHiJkLmNoPqzzzzzzzzzz"; + text[16][1] = "zaBcDeFgHiJkLmNoPqzzzzzzzzz"; + text[16][2] = "zzaBcDeFgHiJkLmNoPqzzzzzzzz"; + text[16][3] = "zzzaBcDeFgHiJkLmNoPqzzzzzzz"; + text[16][4] = "zzzzaBcDeFgHiJkLmNoPqzzzzzz"; + text[16][5] = "zzzzzaBcDeFgHiJkLmNoPqzzzzz"; + text[16][6] = "zzzzzzaBcDeFgHiJkLmNoPqzzzz"; + text[16][7] = "zzzzzzzaBcDeFgHiJkLmNoPqzzz"; + text[16][8] = "zzzzzzzzaBcDeFgHiJkLmNoPqzz"; + text[16][9] = "zzzzzzzzzaBcDeFgHiJkLmNoPqz"; + text[16][10] = "zzzzzzzzzzaBcDeFgHiJkLmNoPq"; + text[17][0] = "aBcDeFgHiJkLmNoPqRzzzzzzzzz"; + text[17][1] = "zaBcDeFgHiJkLmNoPqRzzzzzzzz"; + text[17][2] = "zzaBcDeFgHiJkLmNoPqRzzzzzzz"; + text[17][3] = "zzzaBcDeFgHiJkLmNoPqRzzzzzz"; + text[17][4] = "zzzzaBcDeFgHiJkLmNoPqRzzzzz"; + text[17][5] = "zzzzzaBcDeFgHiJkLmNoPqRzzzz"; + text[17][6] = "zzzzzzaBcDeFgHiJkLmNoPqRzzz"; + text[17][7] = "zzzzzzzaBcDeFgHiJkLmNoPqRzz"; + text[17][8] = "zzzzzzzzaBcDeFgHiJkLmNoPqRz"; + text[17][9] = "zzzzzzzzzaBcDeFgHiJkLmNoPqR"; + text[18][0] = "aBcDeFgHiJkLmNoPqRszzzzzzzz"; + text[18][1] = "zaBcDeFgHiJkLmNoPqRszzzzzzz"; + text[18][2] = "zzaBcDeFgHiJkLmNoPqRszzzzzz"; + text[18][3] = "zzzaBcDeFgHiJkLmNoPqRszzzzz"; + text[18][4] = "zzzzaBcDeFgHiJkLmNoPqRszzzz"; + text[18][5] = "zzzzzaBcDeFgHiJkLmNoPqRszzz"; + text[18][6] = "zzzzzzaBcDeFgHiJkLmNoPqRszz"; + text[18][7] = "zzzzzzzaBcDeFgHiJkLmNoPqRsz"; + text[18][8] = "zzzzzzzzaBcDeFgHiJkLmNoPqRs"; + text[19][0] = "aBcDeFgHiJkLmNoPqRsTzzzzzzz"; + text[19][1] = "zaBcDeFgHiJkLmNoPqRsTzzzzzz"; + text[19][2] = "zzaBcDeFgHiJkLmNoPqRsTzzzzz"; + text[19][3] = "zzzaBcDeFgHiJkLmNoPqRsTzzzz"; + text[19][4] = "zzzzaBcDeFgHiJkLmNoPqRsTzzz"; + text[19][5] = "zzzzzaBcDeFgHiJkLmNoPqRsTzz"; + text[19][6] = "zzzzzzaBcDeFgHiJkLmNoPqRsTz"; + text[19][7] = "zzzzzzzaBcDeFgHiJkLmNoPqRsT"; + text[20][0] = "aBcDeFgHiJkLmNoPqRsTuzzzzzz"; + text[20][1] = "zaBcDeFgHiJkLmNoPqRsTuzzzzz"; + text[20][2] = "zzaBcDeFgHiJkLmNoPqRsTuzzzz"; + text[20][3] = "zzzaBcDeFgHiJkLmNoPqRsTuzzz"; + text[20][4] = "zzzzaBcDeFgHiJkLmNoPqRsTuzz"; + text[20][5] = "zzzzzaBcDeFgHiJkLmNoPqRsTuz"; + text[20][6] = "zzzzzzaBcDeFgHiJkLmNoPqRsTu"; + text[21][0] = "aBcDeFgHiJkLmNoPqRsTuVzzzzz"; + text[21][1] = "zaBcDeFgHiJkLmNoPqRsTuVzzzz"; + text[21][2] = "zzaBcDeFgHiJkLmNoPqRsTuVzzz"; + text[21][3] = "zzzaBcDeFgHiJkLmNoPqRsTuVzz"; + text[21][4] = "zzzzaBcDeFgHiJkLmNoPqRsTuVz"; + text[21][5] = "zzzzzaBcDeFgHiJkLmNoPqRsTuV"; + text[22][0] = "aBcDeFgHiJkLmNoPqRsTuVwzzzz"; + text[22][1] = "zaBcDeFgHiJkLmNoPqRsTuVwzzz"; + text[22][2] = "zzaBcDeFgHiJkLmNoPqRsTuVwzz"; + text[22][3] = "zzzaBcDeFgHiJkLmNoPqRsTuVwz"; + text[22][4] = "zzzzaBcDeFgHiJkLmNoPqRsTuVw"; + text[23][0] = "aBcDeFgHiJkLmNoPqRsTuVwXzzz"; + text[23][1] = "zaBcDeFgHiJkLmNoPqRsTuVwXzz"; + text[23][2] = "zzaBcDeFgHiJkLmNoPqRsTuVwXz"; + text[23][3] = "zzzaBcDeFgHiJkLmNoPqRsTuVwX"; + text[24][0] = "aBcDeFgHiJkLmNoPqRsTuVwXyzz"; + text[24][1] = "zaBcDeFgHiJkLmNoPqRsTuVwXyz"; + text[24][2] = "zzaBcDeFgHiJkLmNoPqRsTuVwXy"; + text[25][0] = "aBcDeFgHiJkLmNoPqRsTuVwXyZz"; + text[25][1] = "zaBcDeFgHiJkLmNoPqRsTuVwXyZ"; + + const char *needle[26]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + needle[16] = "aBcDeFgHiJkLmNoPq"; + needle[17] = "aBcDeFgHiJkLmNoPqR"; + needle[18] = "aBcDeFgHiJkLmNoPqRs"; + needle[19] = "aBcDeFgHiJkLmNoPqRsT"; + needle[20] = "aBcDeFgHiJkLmNoPqRsTu"; + needle[21] = "aBcDeFgHiJkLmNoPqRsTuV"; + needle[22] = "aBcDeFgHiJkLmNoPqRsTuVw"; + needle[23] = "aBcDeFgHiJkLmNoPqRsTuVwX"; + needle[24] = "aBcDeFgHiJkLmNoPqRsTuVwXy"; + needle[25] = "aBcDeFgHiJkLmNoPqRsTuVwXyZ"; + + int i, j; + uint8_t *found = NULL; + for (i = 0; i < 26; i++) { + for (j = 0; j <= (26 - i); j++) { + found = BasicSearchWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i][j]); + return 0; + } + found = Bs2bmWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i][j]); + return 0; + } + found = BoyerMooreWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i][j]); + return 0; + } + } + } + return 1; +} + +/** + * \test Check that all the algorithms (no case) work at any offset and any pattern length + */ +static int UtilSpmSearchOffsetsNocaseTest01(void) +{ + const char *text[26][27]; + text[0][0] = "azzzzzzzzzzzzzzzzzzzzzzzzzz"; + text[0][1] = "zazzzzzzzzzzzzzzzzzzzzzzzzz"; + text[0][2] = "zzazzzzzzzzzzzzzzzzzzzzzzzz"; + text[0][3] = "zzzazzzzzzzzzzzzzzzzzzzzzzz"; + text[0][4] = "zzzzazzzzzzzzzzzzzzzzzzzzzz"; + text[0][5] = "zzzzzazzzzzzzzzzzzzzzzzzzzz"; + text[0][6] = "zzzzzzazzzzzzzzzzzzzzzzzzzz"; + text[0][7] = "zzzzzzzazzzzzzzzzzzzzzzzzzz"; + text[0][8] = "zzzzzzzzazzzzzzzzzzzzzzzzzz"; + text[0][9] = "zzzzzzzzzazzzzzzzzzzzzzzzzz"; + text[0][10] = "zzzzzzzzzzazzzzzzzzzzzzzzzz"; + text[0][11] = "zzzzzzzzzzzazzzzzzzzzzzzzzz"; + text[0][12] = "zzzzzzzzzzzzazzzzzzzzzzzzzz"; + text[0][13] = "zzzzzzzzzzzzzazzzzzzzzzzzzz"; + text[0][14] = "zzzzzzzzzzzzzzazzzzzzzzzzzz"; + text[0][15] = "zzzzzzzzzzzzzzzazzzzzzzzzzz"; + text[0][16] = "zzzzzzzzzzzzzzzzazzzzzzzzzz"; + text[0][17] = "zzzzzzzzzzzzzzzzzazzzzzzzzz"; + text[0][18] = "zzzzzzzzzzzzzzzzzzazzzzzzzz"; + text[0][19] = "zzzzzzzzzzzzzzzzzzzazzzzzzz"; + text[0][20] = "zzzzzzzzzzzzzzzzzzzzazzzzzz"; + text[0][21] = "zzzzzzzzzzzzzzzzzzzzzazzzzz"; + text[0][22] = "zzzzzzzzzzzzzzzzzzzzzzazzzz"; + text[0][23] = "zzzzzzzzzzzzzzzzzzzzzzzazzz"; + text[0][24] = "zzzzzzzzzzzzzzzzzzzzzzzzazz"; + text[0][25] = "zzzzzzzzzzzzzzzzzzzzzzzzzaz"; + text[0][26] = "zzzzzzzzzzzzzzzzzzzzzzzzzza"; + text[1][0] = "aBzzzzzzzzzzzzzzzzzzzzzzzzz"; + text[1][1] = "zaBzzzzzzzzzzzzzzzzzzzzzzzz"; + text[1][2] = "zzaBzzzzzzzzzzzzzzzzzzzzzzz"; + text[1][3] = "zzzaBzzzzzzzzzzzzzzzzzzzzzz"; + text[1][4] = "zzzzaBzzzzzzzzzzzzzzzzzzzzz"; + text[1][5] = "zzzzzaBzzzzzzzzzzzzzzzzzzzz"; + text[1][6] = "zzzzzzaBzzzzzzzzzzzzzzzzzzz"; + text[1][7] = "zzzzzzzaBzzzzzzzzzzzzzzzzzz"; + text[1][8] = "zzzzzzzzaBzzzzzzzzzzzzzzzzz"; + text[1][9] = "zzzzzzzzzaBzzzzzzzzzzzzzzzz"; + text[1][10] = "zzzzzzzzzzaBzzzzzzzzzzzzzzz"; + text[1][11] = "zzzzzzzzzzzaBzzzzzzzzzzzzzz"; + text[1][12] = "zzzzzzzzzzzzaBzzzzzzzzzzzzz"; + text[1][13] = "zzzzzzzzzzzzzaBzzzzzzzzzzzz"; + text[1][14] = "zzzzzzzzzzzzzzaBzzzzzzzzzzz"; + text[1][15] = "zzzzzzzzzzzzzzzaBzzzzzzzzzz"; + text[1][16] = "zzzzzzzzzzzzzzzzaBzzzzzzzzz"; + text[1][17] = "zzzzzzzzzzzzzzzzzaBzzzzzzzz"; + text[1][18] = "zzzzzzzzzzzzzzzzzzaBzzzzzzz"; + text[1][19] = "zzzzzzzzzzzzzzzzzzzaBzzzzzz"; + text[1][20] = "zzzzzzzzzzzzzzzzzzzzaBzzzzz"; + text[1][21] = "zzzzzzzzzzzzzzzzzzzzzaBzzzz"; + text[1][22] = "zzzzzzzzzzzzzzzzzzzzzzaBzzz"; + text[1][23] = "zzzzzzzzzzzzzzzzzzzzzzzaBzz"; + text[1][24] = "zzzzzzzzzzzzzzzzzzzzzzzzaBz"; + text[1][25] = "zzzzzzzzzzzzzzzzzzzzzzzzzaB"; + text[2][0] = "aBczzzzzzzzzzzzzzzzzzzzzzzz"; + text[2][1] = "zaBczzzzzzzzzzzzzzzzzzzzzzz"; + text[2][2] = "zzaBczzzzzzzzzzzzzzzzzzzzzz"; + text[2][3] = "zzzaBczzzzzzzzzzzzzzzzzzzzz"; + text[2][4] = "zzzzaBczzzzzzzzzzzzzzzzzzzz"; + text[2][5] = "zzzzzaBczzzzzzzzzzzzzzzzzzz"; + text[2][6] = "zzzzzzaBczzzzzzzzzzzzzzzzzz"; + text[2][7] = "zzzzzzzaBczzzzzzzzzzzzzzzzz"; + text[2][8] = "zzzzzzzzaBczzzzzzzzzzzzzzzz"; + text[2][9] = "zzzzzzzzzaBczzzzzzzzzzzzzzz"; + text[2][10] = "zzzzzzzzzzaBczzzzzzzzzzzzzz"; + text[2][11] = "zzzzzzzzzzzaBczzzzzzzzzzzzz"; + text[2][12] = "zzzzzzzzzzzzaBczzzzzzzzzzzz"; + text[2][13] = "zzzzzzzzzzzzzaBczzzzzzzzzzz"; + text[2][14] = "zzzzzzzzzzzzzzaBczzzzzzzzzz"; + text[2][15] = "zzzzzzzzzzzzzzzaBczzzzzzzzz"; + text[2][16] = "zzzzzzzzzzzzzzzzaBczzzzzzzz"; + text[2][17] = "zzzzzzzzzzzzzzzzzaBczzzzzzz"; + text[2][18] = "zzzzzzzzzzzzzzzzzzaBczzzzzz"; + text[2][19] = "zzzzzzzzzzzzzzzzzzzaBczzzzz"; + text[2][20] = "zzzzzzzzzzzzzzzzzzzzaBczzzz"; + text[2][21] = "zzzzzzzzzzzzzzzzzzzzzaBczzz"; + text[2][22] = "zzzzzzzzzzzzzzzzzzzzzzaBczz"; + text[2][23] = "zzzzzzzzzzzzzzzzzzzzzzzaBcz"; + text[2][24] = "zzzzzzzzzzzzzzzzzzzzzzzzaBc"; + text[3][0] = "aBcDzzzzzzzzzzzzzzzzzzzzzzz"; + text[3][1] = "zaBcDzzzzzzzzzzzzzzzzzzzzzz"; + text[3][2] = "zzaBcDzzzzzzzzzzzzzzzzzzzzz"; + text[3][3] = "zzzaBcDzzzzzzzzzzzzzzzzzzzz"; + text[3][4] = "zzzzaBcDzzzzzzzzzzzzzzzzzzz"; + text[3][5] = "zzzzzaBcDzzzzzzzzzzzzzzzzzz"; + text[3][6] = "zzzzzzaBcDzzzzzzzzzzzzzzzzz"; + text[3][7] = "zzzzzzzaBcDzzzzzzzzzzzzzzzz"; + text[3][8] = "zzzzzzzzaBcDzzzzzzzzzzzzzzz"; + text[3][9] = "zzzzzzzzzaBcDzzzzzzzzzzzzzz"; + text[3][10] = "zzzzzzzzzzaBcDzzzzzzzzzzzzz"; + text[3][11] = "zzzzzzzzzzzaBcDzzzzzzzzzzzz"; + text[3][12] = "zzzzzzzzzzzzaBcDzzzzzzzzzzz"; + text[3][13] = "zzzzzzzzzzzzzaBcDzzzzzzzzzz"; + text[3][14] = "zzzzzzzzzzzzzzaBcDzzzzzzzzz"; + text[3][15] = "zzzzzzzzzzzzzzzaBcDzzzzzzzz"; + text[3][16] = "zzzzzzzzzzzzzzzzaBcDzzzzzzz"; + text[3][17] = "zzzzzzzzzzzzzzzzzaBcDzzzzzz"; + text[3][18] = "zzzzzzzzzzzzzzzzzzaBcDzzzzz"; + text[3][19] = "zzzzzzzzzzzzzzzzzzzaBcDzzzz"; + text[3][20] = "zzzzzzzzzzzzzzzzzzzzaBcDzzz"; + text[3][21] = "zzzzzzzzzzzzzzzzzzzzzaBcDzz"; + text[3][22] = "zzzzzzzzzzzzzzzzzzzzzzaBcDz"; + text[3][23] = "zzzzzzzzzzzzzzzzzzzzzzzaBcD"; + text[4][0] = "aBcDezzzzzzzzzzzzzzzzzzzzzz"; + text[4][1] = "zaBcDezzzzzzzzzzzzzzzzzzzzz"; + text[4][2] = "zzaBcDezzzzzzzzzzzzzzzzzzzz"; + text[4][3] = "zzzaBcDezzzzzzzzzzzzzzzzzzz"; + text[4][4] = "zzzzaBcDezzzzzzzzzzzzzzzzzz"; + text[4][5] = "zzzzzaBcDezzzzzzzzzzzzzzzzz"; + text[4][6] = "zzzzzzaBcDezzzzzzzzzzzzzzzz"; + text[4][7] = "zzzzzzzaBcDezzzzzzzzzzzzzzz"; + text[4][8] = "zzzzzzzzaBcDezzzzzzzzzzzzzz"; + text[4][9] = "zzzzzzzzzaBcDezzzzzzzzzzzzz"; + text[4][10] = "zzzzzzzzzzaBcDezzzzzzzzzzzz"; + text[4][11] = "zzzzzzzzzzzaBcDezzzzzzzzzzz"; + text[4][12] = "zzzzzzzzzzzzaBcDezzzzzzzzzz"; + text[4][13] = "zzzzzzzzzzzzzaBcDezzzzzzzzz"; + text[4][14] = "zzzzzzzzzzzzzzaBcDezzzzzzzz"; + text[4][15] = "zzzzzzzzzzzzzzzaBcDezzzzzzz"; + text[4][16] = "zzzzzzzzzzzzzzzzaBcDezzzzzz"; + text[4][17] = "zzzzzzzzzzzzzzzzzaBcDezzzzz"; + text[4][18] = "zzzzzzzzzzzzzzzzzzaBcDezzzz"; + text[4][19] = "zzzzzzzzzzzzzzzzzzzaBcDezzz"; + text[4][20] = "zzzzzzzzzzzzzzzzzzzzaBcDezz"; + text[4][21] = "zzzzzzzzzzzzzzzzzzzzzaBcDez"; + text[4][22] = "zzzzzzzzzzzzzzzzzzzzzzaBcDe"; + text[5][0] = "aBcDeFzzzzzzzzzzzzzzzzzzzzz"; + text[5][1] = "zaBcDeFzzzzzzzzzzzzzzzzzzzz"; + text[5][2] = "zzaBcDeFzzzzzzzzzzzzzzzzzzz"; + text[5][3] = "zzzaBcDeFzzzzzzzzzzzzzzzzzz"; + text[5][4] = "zzzzaBcDeFzzzzzzzzzzzzzzzzz"; + text[5][5] = "zzzzzaBcDeFzzzzzzzzzzzzzzzz"; + text[5][6] = "zzzzzzaBcDeFzzzzzzzzzzzzzzz"; + text[5][7] = "zzzzzzzaBcDeFzzzzzzzzzzzzzz"; + text[5][8] = "zzzzzzzzaBcDeFzzzzzzzzzzzzz"; + text[5][9] = "zzzzzzzzzaBcDeFzzzzzzzzzzzz"; + text[5][10] = "zzzzzzzzzzaBcDeFzzzzzzzzzzz"; + text[5][11] = "zzzzzzzzzzzaBcDeFzzzzzzzzzz"; + text[5][12] = "zzzzzzzzzzzzaBcDeFzzzzzzzzz"; + text[5][13] = "zzzzzzzzzzzzzaBcDeFzzzzzzzz"; + text[5][14] = "zzzzzzzzzzzzzzaBcDeFzzzzzzz"; + text[5][15] = "zzzzzzzzzzzzzzzaBcDeFzzzzzz"; + text[5][16] = "zzzzzzzzzzzzzzzzaBcDeFzzzzz"; + text[5][17] = "zzzzzzzzzzzzzzzzzaBcDeFzzzz"; + text[5][18] = "zzzzzzzzzzzzzzzzzzaBcDeFzzz"; + text[5][19] = "zzzzzzzzzzzzzzzzzzzaBcDeFzz"; + text[5][20] = "zzzzzzzzzzzzzzzzzzzzaBcDeFz"; + text[5][21] = "zzzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6][0] = "aBcDeFgzzzzzzzzzzzzzzzzzzzz"; + text[6][1] = "zaBcDeFgzzzzzzzzzzzzzzzzzzz"; + text[6][2] = "zzaBcDeFgzzzzzzzzzzzzzzzzzz"; + text[6][3] = "zzzaBcDeFgzzzzzzzzzzzzzzzzz"; + text[6][4] = "zzzzaBcDeFgzzzzzzzzzzzzzzzz"; + text[6][5] = "zzzzzaBcDeFgzzzzzzzzzzzzzzz"; + text[6][6] = "zzzzzzaBcDeFgzzzzzzzzzzzzzz"; + text[6][7] = "zzzzzzzaBcDeFgzzzzzzzzzzzzz"; + text[6][8] = "zzzzzzzzaBcDeFgzzzzzzzzzzzz"; + text[6][9] = "zzzzzzzzzaBcDeFgzzzzzzzzzzz"; + text[6][10] = "zzzzzzzzzzaBcDeFgzzzzzzzzzz"; + text[6][11] = "zzzzzzzzzzzaBcDeFgzzzzzzzzz"; + text[6][12] = "zzzzzzzzzzzzaBcDeFgzzzzzzzz"; + text[6][13] = "zzzzzzzzzzzzzaBcDeFgzzzzzzz"; + text[6][14] = "zzzzzzzzzzzzzzaBcDeFgzzzzzz"; + text[6][15] = "zzzzzzzzzzzzzzzaBcDeFgzzzzz"; + text[6][16] = "zzzzzzzzzzzzzzzzaBcDeFgzzzz"; + text[6][17] = "zzzzzzzzzzzzzzzzzaBcDeFgzzz"; + text[6][18] = "zzzzzzzzzzzzzzzzzzaBcDeFgzz"; + text[6][19] = "zzzzzzzzzzzzzzzzzzzaBcDeFgz"; + text[6][20] = "zzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7][0] = "aBcDeFgHzzzzzzzzzzzzzzzzzzz"; + text[7][1] = "zaBcDeFgHzzzzzzzzzzzzzzzzzz"; + text[7][2] = "zzaBcDeFgHzzzzzzzzzzzzzzzzz"; + text[7][3] = "zzzaBcDeFgHzzzzzzzzzzzzzzzz"; + text[7][4] = "zzzzaBcDeFgHzzzzzzzzzzzzzzz"; + text[7][5] = "zzzzzaBcDeFgHzzzzzzzzzzzzzz"; + text[7][6] = "zzzzzzaBcDeFgHzzzzzzzzzzzzz"; + text[7][7] = "zzzzzzzaBcDeFgHzzzzzzzzzzzz"; + text[7][8] = "zzzzzzzzaBcDeFgHzzzzzzzzzzz"; + text[7][9] = "zzzzzzzzzaBcDeFgHzzzzzzzzzz"; + text[7][10] = "zzzzzzzzzzaBcDeFgHzzzzzzzzz"; + text[7][11] = "zzzzzzzzzzzaBcDeFgHzzzzzzzz"; + text[7][12] = "zzzzzzzzzzzzaBcDeFgHzzzzzzz"; + text[7][13] = "zzzzzzzzzzzzzaBcDeFgHzzzzzz"; + text[7][14] = "zzzzzzzzzzzzzzaBcDeFgHzzzzz"; + text[7][15] = "zzzzzzzzzzzzzzzaBcDeFgHzzzz"; + text[7][16] = "zzzzzzzzzzzzzzzzaBcDeFgHzzz"; + text[7][17] = "zzzzzzzzzzzzzzzzzaBcDeFgHzz"; + text[7][18] = "zzzzzzzzzzzzzzzzzzaBcDeFgHz"; + text[7][19] = "zzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8][0] = "aBcDeFgHizzzzzzzzzzzzzzzzzz"; + text[8][1] = "zaBcDeFgHizzzzzzzzzzzzzzzzz"; + text[8][2] = "zzaBcDeFgHizzzzzzzzzzzzzzzz"; + text[8][3] = "zzzaBcDeFgHizzzzzzzzzzzzzzz"; + text[8][4] = "zzzzaBcDeFgHizzzzzzzzzzzzzz"; + text[8][5] = "zzzzzaBcDeFgHizzzzzzzzzzzzz"; + text[8][6] = "zzzzzzaBcDeFgHizzzzzzzzzzzz"; + text[8][7] = "zzzzzzzaBcDeFgHizzzzzzzzzzz"; + text[8][8] = "zzzzzzzzaBcDeFgHizzzzzzzzzz"; + text[8][9] = "zzzzzzzzzaBcDeFgHizzzzzzzzz"; + text[8][10] = "zzzzzzzzzzaBcDeFgHizzzzzzzz"; + text[8][11] = "zzzzzzzzzzzaBcDeFgHizzzzzzz"; + text[8][12] = "zzzzzzzzzzzzaBcDeFgHizzzzzz"; + text[8][13] = "zzzzzzzzzzzzzaBcDeFgHizzzzz"; + text[8][14] = "zzzzzzzzzzzzzzaBcDeFgHizzzz"; + text[8][15] = "zzzzzzzzzzzzzzzaBcDeFgHizzz"; + text[8][16] = "zzzzzzzzzzzzzzzzaBcDeFgHizz"; + text[8][17] = "zzzzzzzzzzzzzzzzzaBcDeFgHiz"; + text[8][18] = "zzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9][0] = "aBcDeFgHiJzzzzzzzzzzzzzzzzz"; + text[9][1] = "zaBcDeFgHiJzzzzzzzzzzzzzzzz"; + text[9][2] = "zzaBcDeFgHiJzzzzzzzzzzzzzzz"; + text[9][3] = "zzzaBcDeFgHiJzzzzzzzzzzzzzz"; + text[9][4] = "zzzzaBcDeFgHiJzzzzzzzzzzzzz"; + text[9][5] = "zzzzzaBcDeFgHiJzzzzzzzzzzzz"; + text[9][6] = "zzzzzzaBcDeFgHiJzzzzzzzzzzz"; + text[9][7] = "zzzzzzzaBcDeFgHiJzzzzzzzzzz"; + text[9][8] = "zzzzzzzzaBcDeFgHiJzzzzzzzzz"; + text[9][9] = "zzzzzzzzzaBcDeFgHiJzzzzzzzz"; + text[9][10] = "zzzzzzzzzzaBcDeFgHiJzzzzzzz"; + text[9][11] = "zzzzzzzzzzzaBcDeFgHiJzzzzzz"; + text[9][12] = "zzzzzzzzzzzzaBcDeFgHiJzzzzz"; + text[9][13] = "zzzzzzzzzzzzzaBcDeFgHiJzzzz"; + text[9][14] = "zzzzzzzzzzzzzzaBcDeFgHiJzzz"; + text[9][15] = "zzzzzzzzzzzzzzzaBcDeFgHiJzz"; + text[9][16] = "zzzzzzzzzzzzzzzzaBcDeFgHiJz"; + text[9][17] = "zzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10][0] = "aBcDeFgHiJkzzzzzzzzzzzzzzzz"; + text[10][1] = "zaBcDeFgHiJkzzzzzzzzzzzzzzz"; + text[10][2] = "zzaBcDeFgHiJkzzzzzzzzzzzzzz"; + text[10][3] = "zzzaBcDeFgHiJkzzzzzzzzzzzzz"; + text[10][4] = "zzzzaBcDeFgHiJkzzzzzzzzzzzz"; + text[10][5] = "zzzzzaBcDeFgHiJkzzzzzzzzzzz"; + text[10][6] = "zzzzzzaBcDeFgHiJkzzzzzzzzzz"; + text[10][7] = "zzzzzzzaBcDeFgHiJkzzzzzzzzz"; + text[10][8] = "zzzzzzzzaBcDeFgHiJkzzzzzzzz"; + text[10][9] = "zzzzzzzzzaBcDeFgHiJkzzzzzzz"; + text[10][10] = "zzzzzzzzzzaBcDeFgHiJkzzzzzz"; + text[10][11] = "zzzzzzzzzzzaBcDeFgHiJkzzzzz"; + text[10][12] = "zzzzzzzzzzzzaBcDeFgHiJkzzzz"; + text[10][13] = "zzzzzzzzzzzzzaBcDeFgHiJkzzz"; + text[10][14] = "zzzzzzzzzzzzzzaBcDeFgHiJkzz"; + text[10][15] = "zzzzzzzzzzzzzzzaBcDeFgHiJkz"; + text[10][16] = "zzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11][0] = "aBcDeFgHiJkLzzzzzzzzzzzzzzz"; + text[11][1] = "zaBcDeFgHiJkLzzzzzzzzzzzzzz"; + text[11][2] = "zzaBcDeFgHiJkLzzzzzzzzzzzzz"; + text[11][3] = "zzzaBcDeFgHiJkLzzzzzzzzzzzz"; + text[11][4] = "zzzzaBcDeFgHiJkLzzzzzzzzzzz"; + text[11][5] = "zzzzzaBcDeFgHiJkLzzzzzzzzzz"; + text[11][6] = "zzzzzzaBcDeFgHiJkLzzzzzzzzz"; + text[11][7] = "zzzzzzzaBcDeFgHiJkLzzzzzzzz"; + text[11][8] = "zzzzzzzzaBcDeFgHiJkLzzzzzzz"; + text[11][9] = "zzzzzzzzzaBcDeFgHiJkLzzzzzz"; + text[11][10] = "zzzzzzzzzzaBcDeFgHiJkLzzzzz"; + text[11][11] = "zzzzzzzzzzzaBcDeFgHiJkLzzzz"; + text[11][12] = "zzzzzzzzzzzzaBcDeFgHiJkLzzz"; + text[11][13] = "zzzzzzzzzzzzzaBcDeFgHiJkLzz"; + text[11][14] = "zzzzzzzzzzzzzzaBcDeFgHiJkLz"; + text[11][15] = "zzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12][0] = "aBcDeFgHiJkLmzzzzzzzzzzzzzz"; + text[12][1] = "zaBcDeFgHiJkLmzzzzzzzzzzzzz"; + text[12][2] = "zzaBcDeFgHiJkLmzzzzzzzzzzzz"; + text[12][3] = "zzzaBcDeFgHiJkLmzzzzzzzzzzz"; + text[12][4] = "zzzzaBcDeFgHiJkLmzzzzzzzzzz"; + text[12][5] = "zzzzzaBcDeFgHiJkLmzzzzzzzzz"; + text[12][6] = "zzzzzzaBcDeFgHiJkLmzzzzzzzz"; + text[12][7] = "zzzzzzzaBcDeFgHiJkLmzzzzzzz"; + text[12][8] = "zzzzzzzzaBcDeFgHiJkLmzzzzzz"; + text[12][9] = "zzzzzzzzzaBcDeFgHiJkLmzzzzz"; + text[12][10] = "zzzzzzzzzzaBcDeFgHiJkLmzzzz"; + text[12][11] = "zzzzzzzzzzzaBcDeFgHiJkLmzzz"; + text[12][12] = "zzzzzzzzzzzzaBcDeFgHiJkLmzz"; + text[12][13] = "zzzzzzzzzzzzzaBcDeFgHiJkLmz"; + text[12][14] = "zzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13][0] = "aBcDeFgHiJkLmNzzzzzzzzzzzzz"; + text[13][1] = "zaBcDeFgHiJkLmNzzzzzzzzzzzz"; + text[13][2] = "zzaBcDeFgHiJkLmNzzzzzzzzzzz"; + text[13][3] = "zzzaBcDeFgHiJkLmNzzzzzzzzzz"; + text[13][4] = "zzzzaBcDeFgHiJkLmNzzzzzzzzz"; + text[13][5] = "zzzzzaBcDeFgHiJkLmNzzzzzzzz"; + text[13][6] = "zzzzzzaBcDeFgHiJkLmNzzzzzzz"; + text[13][7] = "zzzzzzzaBcDeFgHiJkLmNzzzzzz"; + text[13][8] = "zzzzzzzzaBcDeFgHiJkLmNzzzzz"; + text[13][9] = "zzzzzzzzzaBcDeFgHiJkLmNzzzz"; + text[13][10] = "zzzzzzzzzzaBcDeFgHiJkLmNzzz"; + text[13][11] = "zzzzzzzzzzzaBcDeFgHiJkLmNzz"; + text[13][12] = "zzzzzzzzzzzzaBcDeFgHiJkLmNz"; + text[13][13] = "zzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14][0] = "aBcDeFgHiJkLmNozzzzzzzzzzzz"; + text[14][1] = "zaBcDeFgHiJkLmNozzzzzzzzzzz"; + text[14][2] = "zzaBcDeFgHiJkLmNozzzzzzzzzz"; + text[14][3] = "zzzaBcDeFgHiJkLmNozzzzzzzzz"; + text[14][4] = "zzzzaBcDeFgHiJkLmNozzzzzzzz"; + text[14][5] = "zzzzzaBcDeFgHiJkLmNozzzzzzz"; + text[14][6] = "zzzzzzaBcDeFgHiJkLmNozzzzzz"; + text[14][7] = "zzzzzzzaBcDeFgHiJkLmNozzzzz"; + text[14][8] = "zzzzzzzzaBcDeFgHiJkLmNozzzz"; + text[14][9] = "zzzzzzzzzaBcDeFgHiJkLmNozzz"; + text[14][10] = "zzzzzzzzzzaBcDeFgHiJkLmNozz"; + text[14][11] = "zzzzzzzzzzzaBcDeFgHiJkLmNoz"; + text[14][12] = "zzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15][0] = "aBcDeFgHiJkLmNoPzzzzzzzzzzz"; + text[15][1] = "zaBcDeFgHiJkLmNoPzzzzzzzzzz"; + text[15][2] = "zzaBcDeFgHiJkLmNoPzzzzzzzzz"; + text[15][3] = "zzzaBcDeFgHiJkLmNoPzzzzzzzz"; + text[15][4] = "zzzzaBcDeFgHiJkLmNoPzzzzzzz"; + text[15][5] = "zzzzzaBcDeFgHiJkLmNoPzzzzzz"; + text[15][6] = "zzzzzzaBcDeFgHiJkLmNoPzzzzz"; + text[15][7] = "zzzzzzzaBcDeFgHiJkLmNoPzzzz"; + text[15][8] = "zzzzzzzzaBcDeFgHiJkLmNoPzzz"; + text[15][9] = "zzzzzzzzzaBcDeFgHiJkLmNoPzz"; + text[15][10] = "zzzzzzzzzzaBcDeFgHiJkLmNoPz"; + text[15][11] = "zzzzzzzzzzzaBcDeFgHiJkLmNoP"; + text[16][0] = "aBcDeFgHiJkLmNoPqzzzzzzzzzz"; + text[16][1] = "zaBcDeFgHiJkLmNoPqzzzzzzzzz"; + text[16][2] = "zzaBcDeFgHiJkLmNoPqzzzzzzzz"; + text[16][3] = "zzzaBcDeFgHiJkLmNoPqzzzzzzz"; + text[16][4] = "zzzzaBcDeFgHiJkLmNoPqzzzzzz"; + text[16][5] = "zzzzzaBcDeFgHiJkLmNoPqzzzzz"; + text[16][6] = "zzzzzzaBcDeFgHiJkLmNoPqzzzz"; + text[16][7] = "zzzzzzzaBcDeFgHiJkLmNoPqzzz"; + text[16][8] = "zzzzzzzzaBcDeFgHiJkLmNoPqzz"; + text[16][9] = "zzzzzzzzzaBcDeFgHiJkLmNoPqz"; + text[16][10] = "zzzzzzzzzzaBcDeFgHiJkLmNoPq"; + text[17][0] = "aBcDeFgHiJkLmNoPqRzzzzzzzzz"; + text[17][1] = "zaBcDeFgHiJkLmNoPqRzzzzzzzz"; + text[17][2] = "zzaBcDeFgHiJkLmNoPqRzzzzzzz"; + text[17][3] = "zzzaBcDeFgHiJkLmNoPqRzzzzzz"; + text[17][4] = "zzzzaBcDeFgHiJkLmNoPqRzzzzz"; + text[17][5] = "zzzzzaBcDeFgHiJkLmNoPqRzzzz"; + text[17][6] = "zzzzzzaBcDeFgHiJkLmNoPqRzzz"; + text[17][7] = "zzzzzzzaBcDeFgHiJkLmNoPqRzz"; + text[17][8] = "zzzzzzzzaBcDeFgHiJkLmNoPqRz"; + text[17][9] = "zzzzzzzzzaBcDeFgHiJkLmNoPqR"; + text[18][0] = "aBcDeFgHiJkLmNoPqRszzzzzzzz"; + text[18][1] = "zaBcDeFgHiJkLmNoPqRszzzzzzz"; + text[18][2] = "zzaBcDeFgHiJkLmNoPqRszzzzzz"; + text[18][3] = "zzzaBcDeFgHiJkLmNoPqRszzzzz"; + text[18][4] = "zzzzaBcDeFgHiJkLmNoPqRszzzz"; + text[18][5] = "zzzzzaBcDeFgHiJkLmNoPqRszzz"; + text[18][6] = "zzzzzzaBcDeFgHiJkLmNoPqRszz"; + text[18][7] = "zzzzzzzaBcDeFgHiJkLmNoPqRsz"; + text[18][8] = "zzzzzzzzaBcDeFgHiJkLmNoPqRs"; + text[19][0] = "aBcDeFgHiJkLmNoPqRsTzzzzzzz"; + text[19][1] = "zaBcDeFgHiJkLmNoPqRsTzzzzzz"; + text[19][2] = "zzaBcDeFgHiJkLmNoPqRsTzzzzz"; + text[19][3] = "zzzaBcDeFgHiJkLmNoPqRsTzzzz"; + text[19][4] = "zzzzaBcDeFgHiJkLmNoPqRsTzzz"; + text[19][5] = "zzzzzaBcDeFgHiJkLmNoPqRsTzz"; + text[19][6] = "zzzzzzaBcDeFgHiJkLmNoPqRsTz"; + text[19][7] = "zzzzzzzaBcDeFgHiJkLmNoPqRsT"; + text[20][0] = "aBcDeFgHiJkLmNoPqRsTuzzzzzz"; + text[20][1] = "zaBcDeFgHiJkLmNoPqRsTuzzzzz"; + text[20][2] = "zzaBcDeFgHiJkLmNoPqRsTuzzzz"; + text[20][3] = "zzzaBcDeFgHiJkLmNoPqRsTuzzz"; + text[20][4] = "zzzzaBcDeFgHiJkLmNoPqRsTuzz"; + text[20][5] = "zzzzzaBcDeFgHiJkLmNoPqRsTuz"; + text[20][6] = "zzzzzzaBcDeFgHiJkLmNoPqRsTu"; + text[21][0] = "aBcDeFgHiJkLmNoPqRsTuVzzzzz"; + text[21][1] = "zaBcDeFgHiJkLmNoPqRsTuVzzzz"; + text[21][2] = "zzaBcDeFgHiJkLmNoPqRsTuVzzz"; + text[21][3] = "zzzaBcDeFgHiJkLmNoPqRsTuVzz"; + text[21][4] = "zzzzaBcDeFgHiJkLmNoPqRsTuVz"; + text[21][5] = "zzzzzaBcDeFgHiJkLmNoPqRsTuV"; + text[22][0] = "aBcDeFgHiJkLmNoPqRsTuVwzzzz"; + text[22][1] = "zaBcDeFgHiJkLmNoPqRsTuVwzzz"; + text[22][2] = "zzaBcDeFgHiJkLmNoPqRsTuVwzz"; + text[22][3] = "zzzaBcDeFgHiJkLmNoPqRsTuVwz"; + text[22][4] = "zzzzaBcDeFgHiJkLmNoPqRsTuVw"; + text[23][0] = "aBcDeFgHiJkLmNoPqRsTuVwXzzz"; + text[23][1] = "zaBcDeFgHiJkLmNoPqRsTuVwXzz"; + text[23][2] = "zzaBcDeFgHiJkLmNoPqRsTuVwXz"; + text[23][3] = "zzzaBcDeFgHiJkLmNoPqRsTuVwX"; + text[24][0] = "aBcDeFgHiJkLmNoPqRsTuVwXyzz"; + text[24][1] = "zaBcDeFgHiJkLmNoPqRsTuVwXyz"; + text[24][2] = "zzaBcDeFgHiJkLmNoPqRsTuVwXy"; + text[25][0] = "aBcDeFgHiJkLmNoPqRsTuVwXyZz"; + text[25][1] = "zaBcDeFgHiJkLmNoPqRsTuVwXyZ"; + + const char *needle[26]; + needle[0] = "A"; + needle[1] = "Ab"; + needle[2] = "AbC"; + needle[3] = "AbCd"; + needle[4] = "AbCdE"; + needle[5] = "AbCdEf"; + needle[6] = "AbCdEfG"; + needle[7] = "AbCdEfGh"; + needle[8] = "AbCdEfGhI"; + needle[9] = "AbCdEfGhIJ"; + needle[10] = "AbCdEfGhIjK"; + needle[11] = "AbCdEfGhIjKl"; + needle[12] = "AbCdEfGhIjKlM"; + needle[13] = "AbCdEfGhIjKlMn"; + needle[14] = "AbCdEfGhIjKlMnO"; + needle[15] = "AbCdEfGhIjKlMnOp"; + needle[16] = "AbCdEfGhIjKlMnOpQ"; + needle[17] = "AbCdEfGhIjKlMnOpQr"; + needle[18] = "AbCdEfGhIjKlMnOpQrS"; + needle[19] = "AbCdEfGhIjKlMnOpQrSt"; + needle[20] = "AbCdEfGhIjKlMnOpQrStU"; + needle[21] = "AbCdEfGhIjKlMnOpQrStUv"; + needle[22] = "AbCdEfGhIjKlMnOpQrStUvW"; + needle[23] = "AbCdEfGhIjKlMnOpQrStUvWx"; + needle[24] = "AbCdEfGhIjKlMnOpQrStUvWxY"; + needle[25] = "AbCdEfGhIjKlMnOpQrStUvWxYZ"; + + int i, j; + uint8_t *found = NULL; + for (i = 0; i < 26; i++) { + for (j = 0; j <= (26 - i); j++) { + found = BasicSearchNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i][j]); + return 0; + } + found = Bs2bmNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i][j]); + return 0; + } + found = BoyerMooreNocaseWrapper((uint8_t *)text[i][j], (uint8_t *)needle[i], 1); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i][j]); + return 0; + } + } + } + return 1; +} + +#ifdef ENABLE_SEARCH_STATS +/** + * \test Give some stats + */ +static int UtilSpmSearchStatsTest01(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzza"; + text[1] = "aaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaa" + "aaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaaaaaa" + "aaazaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaraaaaazaaaaaaazaaaaaaaaaaaaaazaaaaaa" + "aazaaaaaaaaazaaaaaaaaaaaaB"; + text[2] = "aBaBaBaBaBaBaBaBazaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBzB" + "aBaBaBaBaBaBzBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBaB" + "aBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBaBaz" + "aBaBaBaBaBaBaBazaBaBaBaBaBc"; + text[3] = "aBcaBcaBcaBcaBczBcaBcaBzaBcaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBzaBcaBcaBcaBc" + "aBcaBczBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBc" + "aBcaBcaBczBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBz" + "aBcaBcaBcazcaBcaBcaBcaBcaBcD"; + text[4] = "aBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDzBcDaBcDaBczaBcD" + "aBcDaBczaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBcDaBzD" + "aBcDaBcDaBcDaBzDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDazcDaBcDaBcDaBcD" + "aBcDzBcDaBcDaBcDaBcDaBcDaBcDe"; + text[5] = "aBcDeaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcD" + "zaBcDeaBcDezBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBczeaBcDeaBcDeaBzDeaBc" + "DeaBcDezBcDeaBcDzaBcDeaBcDezBcDeaBcDezBcDeaBczeaBcDeaBcDeaBzDeaBcDezBcDeaBcDeaBcDeaB" + "cDeaBcDeaBcDeaBcDeaBcDezzzaBcDeF"; + text[6] = "aBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcD" + "zaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBc" + "zzaBcDeaBcDeaBcDzazcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBczeaB" + "cDeaBcDeaBcDeaBczeaBcDezzzaBcDeFg"; + text[7] = "aBcDeaBczeaBcDzaBcDezBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBzDzaBcDeaBcDeazcDeaBcDzaBcD" + "eaBczeaBcDeaBcDeaBzDzaBcDeaBcDeaBcDezBcDzaBcDeaBzDeaBcDeaBcDezBcDzaBcDeaBcDeaBzDeaBc" + "DeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaB" + "cDeaBcDeaBrDeaBcDeaBcDezzzaBcDeFgH"; + text[8] = "aBcDeaBcDeaBczzaBcDeazcDeaBcDezBcDeaBcDzaBcDeaBcDeaBcDeaBczzaBcDeaBcDeaBczeaBcDeaBcD" + "zzBcDeaBcDeaBcDzaBczeaBcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDzaBc" + "DeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBczeaBcDeaB" + "zDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHi"; + text[9] = "aBcDeaBcDzaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeazcDeaBcDeaBcDzzBcDeaBcDeaBczeaBcDzaBcD" + "ezBcDeaBczeaBcDzaBcDezBcDeaBcDzaBczeaBcDeaBcDzaBcDeazcDeaBcDeaBcDzaBczeaBcDeaBcDzaBz" + "DeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDeaz" + "cDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJ"; + text[10] = "aBcDeaBcDeaBczeaBcDzaBczeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDeaBzDzaBcDeazc" + "DeaBcDeazcDeaBcDzaBcDeazcDeaBcDeaBczzaBcDeaBcDeaBzDeaBcDeaBcDzaBczeaBcDeaBcDeaBcDea" + "BczeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcD" + "eaBcDeaBcDeaBzDeaBcDeaBcDezzzaBcDeFgHiJk"; + text[11] = "aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDeazcDeaBcDzaBcDeaBcDeaBc" + "DeaBcDzaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzzBcDeaBcDeaBcDeaBcDzaBcDzaBcDeaBzDeaBcDea" + "BcDezBcDeaBcDeazcDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBzDeaBcDeaBczeaBcDeazcDeaBcD" + "ezBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkL"; + text[12] = "aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDeazcDeaBcDeaBc" + "zeaBcDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDea" + "BcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcD" + "eaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLm"; + text[13] = "aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBc" + "DzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDea" + "BcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcD" + "eaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmN"; + text[14] = "aBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBc" + "DeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDea" + "BcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcD" + "eaBcDeaBcDzaBcDeaBcDzaBcDezzzaBcDeFgHiJkLmNo"; + text[15] = "aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBc" + "DeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDea" + "BcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcD" + "eaBcDzaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of greater length (text with a lot of partial matches, worst case for " + "a basic search):\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch:", i + 1); + found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch:", i + 1); + found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch:", i + 1); + found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +/** + * \test Give some stats for + */ +static int UtilSpmSearchStatsTest02(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzza"; + text[1] = "zzzzzzzzzzzzzzzzzzaB"; + text[2] = "zzzzzzzzzzzzzzzzzzaBc"; + text[3] = "zzzzzzzzzzzzzzzzzzaBcD"; + text[4] = "zzzzzzzzzzzzzzzzzzaBcDe"; + text[5] = "zzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6] = "zzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length:\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch:", i + 1); + found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch:", i + 1); + found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch:", i + 1); + found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmSearchStatsTest03(void) +{ + char *text[16]; + text[0] = "zzzzzza"; + text[1] = "zzzzzzaB"; + text[2] = "zzzzzzaBc"; + text[3] = "zzzzzzaBcD"; + text[4] = "zzzzzzaBcDe"; + text[5] = "zzzzzzzzaBcDeF"; + text[6] = "zzzzzzzzaBcDeFg"; + text[7] = "zzzzzzzzaBcDeFgH"; + text[8] = "zzzzzzzzaBcDeFgHi"; + text[9] = "zzzzzzzzaBcDeFgHiJ"; + text[10] = "zzzzzzzzaBcDeFgHiJk"; + text[11] = "zzzzzzzzaBcDeFgHiJkL"; + text[12] = "zzzzzzzzaBcDeFgHiJkLm"; + text[13] = "zzzzzzzzaBcDeFgHiJkLmN"; + text[14] = "zzzzzzzzaBcDeFgHiJkLmNo"; + text[15] = "zzzzzzzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length (badcase for):\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch:", i + 1); + found = BasicSearchWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch:", i + 1); + found = Bs2bmWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch:", i + 1); + found = BoyerMooreWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +/** + * \test Give some stats + */ +static int UtilSpmSearchStatsTest04(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzza"; + text[1] = "aaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaa" + "aaaazaaaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaaaaaa" + "aaazaaaaaaaaaaaaaaaaazaaaaaaaaazaaaaaaaaaazaaaaaraaaaazaaaaaaazaaaaaaaaaaaaaazaaaaaa" + "aazaaaaaaaaazaaaaaaaaaaaaB"; + text[2] = "aBaBaBaBaBaBaBaBazaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBzB" + "aBaBaBaBaBaBzBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBzBaBaBaBaBaBaBaBazaBaBaBaBaBaBaBaBaBaB" + "aBaBazaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBzBaBaBaBaBaBaBaBaBaBaBaz" + "aBaBaBaBaBaBaBazaBaBaBaBaBc"; + text[3] = "aBcaBcaBcaBcaBczBcaBcaBzaBcaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBzaBcaBcaBcaBc" + "aBcaBczBcaBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBcaBcaBczBcaBcaBcaBc" + "aBcaBcaBczBcaBcaBcaBcaBzaBcaBcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcazcaBcaBcaBcaBcaBcaBz" + "aBcaBcaBcazcaBcaBcaBcaBcaBcD"; + text[4] = "aBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDzBcDaBcDaBcDaBcDzBcDaBcDaBczaBcD" + "aBcDaBczaBcDaBcDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDaBcDaBzD" + "aBcDaBcDaBcDaBzDaBcDaBcDaBzDaBcDaBcDaBcDaBcDaBcDaBczaBcDaBcDaBcDaBcDazcDaBcDaBcDaBcD" + "aBcDzBcDaBcDaBcDaBcDaBcDaBcDe"; + text[5] = "aBcDeaBcDeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcD" + "zaBcDeaBcDezBcDeaBzDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBczeaBcDeaBcDeaBzDeaBc" + "DeaBcDezBcDeaBcDzaBcDeaBcDezBcDeaBcDezBcDeaBczeaBcDeaBcDeaBzDeaBcDezBcDeaBcDeaBcDeaB" + "cDeaBcDeaBcDeaBcDeaBcDezzzaBcDeF"; + text[6] = "aBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcD" + "zaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBc" + "zzaBcDeaBcDeaBcDzazcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeaBczeaB" + "cDeaBcDeaBcDeaBczeaBcDezzzaBcDeFg"; + text[7] = "aBcDeaBczeaBcDzaBcDezBcDeaBcDeaBcDeaBcDzaBzDeaBcDeaBcDeaBzDzaBcDeaBcDeazcDeaBcDzaBcD" + "eaBczeaBcDeaBcDeaBzDzaBcDeaBcDeaBcDezBcDzaBcDeaBzDeaBcDeaBcDezBcDzaBcDeaBcDeaBzDeaBc" + "DeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaB" + "cDeaBcDeaBrDeaBcDeaBcDezzzaBcDeFgH"; + text[8] = "aBcDeaBcDeaBczzaBcDeazcDeaBcDezBcDeaBcDzaBcDeaBcDeaBcDeaBczzaBcDeaBcDeaBczeaBcDeaBcD" + "zzBcDeaBcDeaBcDzaBczeaBcDeaBcDzaBcDeaBczeaBcDeaBcDeaBzDeaBcDeaBcDeaBzDeaBcDeaBcDzaBc" + "DeaBcDeazcDeaBcDeaBcDzaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBcDeazcDeaBcDeaBcDeaBczeaBcDeaB" + "zDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHi"; + text[9] = "aBcDeaBcDzaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeazcDeaBcDeaBcDzzBcDeaBcDeaBczeaBcDzaBcD" + "ezBcDeaBczeaBcDzaBcDezBcDeaBcDzaBczeaBcDeaBcDzaBcDeazcDeaBcDeaBcDzaBczeaBcDeaBcDzaBz" + "DeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeaBzDeaBcDeaBcDeaBczeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDeaz" + "cDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJ"; + text[10] = "aBcDeaBcDeaBczeaBcDzaBczeaBcDeaBczeaBcDeaBcDzaBcDeaBcDeazcDeaBcDeaBcDeaBzDzaBcDeazc" + "DeaBcDeazcDeaBcDzaBcDeazcDeaBcDeaBczzaBcDeaBcDeaBzDeaBcDeaBcDzaBczeaBcDeaBcDeaBcDea" + "BczeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDezBcD" + "eaBcDeaBcDeaBzDeaBcDeaBcDezzzaBcDeFgHiJk"; + text[11] = "aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDeazcDeaBcDzaBcDeaBcDeaBc" + "DeaBcDzaBcDeaBcDzaBcDzaBcDeaBcDeaBcDeaBcDzzBcDeaBcDeaBcDeaBcDzaBcDzaBcDeaBzDeaBcDea" + "BcDezBcDeaBcDeazcDeaBcDeaBcDezBcDeaBcDeaBcDeazcDeaBcDeaBzDeaBcDeaBczeaBcDeazcDeaBcD" + "ezBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkL"; + text[12] = "aBcDeaBcDeaBcDeaBcDeaBzDeaBcDeaBzDeaBcDeaBcDezBcDeaBcDeazcDeaBcDeaBcDeazcDeaBcDeaBc" + "zeaBcDeaBcDeaBcDezBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDea" + "BcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcD" + "eaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLm"; + text[13] = "aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBc" + "DzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDea" + "BcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcDeaBcD" + "eaBcDeaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmN"; + text[14] = "aBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBcDeaBcDeaBcDzaBcDeaBc" + "DeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDea" + "BcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcD" + "eaBcDeaBcDzaBcDeaBcDzaBcDezzzaBcDeFgHiJkLmNo"; + text[15] = "aBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBc" + "DeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDea" + "BcDzaBcDeaBcDzaBcDeaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcDeaBcDzaBcD" + "eaBcDzaBcDeaBcDeaBcDeaBcDezzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of greater length:\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with SpmSearch (Building Context):", i + 1); + found = RawCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +/** + * \test Give some stats for + */ +static int UtilSpmSearchStatsTest05(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzza"; + text[1] = "zzzzzzzzzzzzzzzzzzaB"; + text[2] = "zzzzzzzzzzzzzzzzzzaBc"; + text[3] = "zzzzzzzzzzzzzzzzzzaBcD"; + text[4] = "zzzzzzzzzzzzzzzzzzaBcDe"; + text[5] = "zzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6] = "zzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length:\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmSearchStatsTest06(void) +{ + char *text[16]; + text[0] = "zzzzkzzzzzzzkzzzzzza"; + text[1] = "BBBBkBBBBBBBkBBBBBaB"; + text[2] = "BcBckcBcBcBckcBcBcaBc"; + text[3] = "BcDBkDBcDBcDkcDBcDaBcD"; + text[4] = "BcDekcDeBcDekcDezzaBcDe"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length (badcase for):\n"); + for (i = 0; i < 5; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmSearchStatsTest07(void) +{ + char *text[16]; + text[0] = "zzzza"; + text[1] = "BBBaB"; + text[2] = "bbaBc"; + text[3] = "aaBcD"; + text[4] = "aBcDe"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of real lower length (badcase for):\n"); + for (i = 0; i < 5; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +/** + * \test Give some stats for no case algorithms + */ +static int UtilSpmNocaseSearchStatsTest01(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; + text[1] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaB"; + text[2] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBc"; + text[3] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcD"; + text[4] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDe"; + text[5] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of greater length:\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch:", i + 1); + found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch:", i + 1); + found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch:", i + 1); + found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmNocaseSearchStatsTest02(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzza"; + text[1] = "zzzzzzzzzzzzzzzzzzaB"; + text[2] = "zzzzzzzzzzzzzzzzzzaBc"; + text[3] = "zzzzzzzzzzzzzzzzzzaBcD"; + text[4] = "zzzzzzzzzzzzzzzzzzaBcDe"; + text[5] = "zzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6] = "zzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length:\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch:", i + 1); + found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch:", i + 1); + found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch:", i + 1); + found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmNocaseSearchStatsTest03(void) +{ + char *text[16]; + text[0] = "zzzzkzzzzzzzkzzzzzza"; + text[1] = "BBBBkBBBBBBBkBBBBBaB"; + text[2] = "BcBckcBcBcBckcBcBcaBc"; + text[3] = "BcDBkDBcDBcDkcDBcDaBcD"; + text[4] = "BcDekcDeBcDekcDezzaBcDe"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length (badcase for):\n"); + for (i = 0; i < 5; i++) { + printf("Pattern length %d with BasicSearch:", i + 1); + found = BasicSearchNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch:", i + 1); + found = Bs2bmNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch:", i + 1); + found = BoyerMooreNocaseWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +/** + * \test Give some stats for no case algorithms + */ +static int UtilSpmNocaseSearchStatsTest04(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza"; + text[1] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaB"; + text[2] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBc"; + text[3] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcD"; + text[4] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDe"; + text[5] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15] = + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of greater length:\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmNocaseSearchStatsTest05(void) +{ + char *text[16]; + text[0] = "zzzzzzzzzzzzzzzzzza"; + text[1] = "zzzzzzzzzzzzzzzzzzaB"; + text[2] = "zzzzzzzzzzzzzzzzzzaBc"; + text[3] = "zzzzzzzzzzzzzzzzzzaBcD"; + text[4] = "zzzzzzzzzzzzzzzzzzaBcDe"; + text[5] = "zzzzzzzzzzzzzzzzzzzzaBcDeF"; + text[6] = "zzzzzzzzzzzzzzzzzzzzaBcDeFg"; + text[7] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgH"; + text[8] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHi"; + text[9] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJ"; + text[10] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJk"; + text[11] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkL"; + text[12] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLm"; + text[13] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmN"; + text[14] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNo"; + text[15] = "zzzzzzzzzzzzzzzzzzzzaBcDeFgHiJkLmNoP"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + needle[5] = "aBcDeF"; + needle[6] = "aBcDeFg"; + needle[7] = "aBcDeFgH"; + needle[8] = "aBcDeFgHi"; + needle[9] = "aBcDeFgHiJ"; + needle[10] = "aBcDeFgHiJk"; + needle[11] = "aBcDeFgHiJkL"; + needle[12] = "aBcDeFgHiJkLm"; + needle[13] = "aBcDeFgHiJkLmN"; + needle[14] = "aBcDeFgHiJkLmNo"; + needle[15] = "aBcDeFgHiJkLmNoP"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length:\n"); + for (i = 0; i < 16; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmNocaseSearchStatsTest06(void) +{ + char *text[16]; + text[0] = "zzzzkzzzzzzzkzzzzzza"; + text[1] = "BBBBkBBBBBBBkBBBBBaB"; + text[2] = "BcBckcBcBcBckcBcBcaBc"; + text[3] = "BcDBkDBcDBcDkcDBcDaBcD"; + text[4] = "BcDekcDeBcDekcDezzaBcDe"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of lower length (badcase for):\n"); + for (i = 0; i < 5; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} + +static int UtilSpmNocaseSearchStatsTest07(void) +{ + char *text[16]; + text[0] = "zzzza"; + text[1] = "bbbAb"; + text[2] = "bbAbC"; + text[3] = "bAbCd"; + text[4] = "AbCdE"; + + char *needle[16]; + needle[0] = "a"; + needle[1] = "aB"; + needle[2] = "aBc"; + needle[3] = "aBcD"; + needle[4] = "aBcDe"; + + int i; + uint8_t *found = NULL; + printf("\nStats for text of real lower length (badcase for):\n"); + for (i = 0; i < 5; i++) { + printf("Pattern length %d with BasicSearch (Building Context):", i + 1); + found = BasicSearchNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error1 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with Bs2BmSearch (Building Context):", i + 1); + found = Bs2bmNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error2 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("Pattern length %d with BoyerMooreSearch (Building Context):", i + 1); + found = BoyerMooreNocaseCtxWrapper((uint8_t *)text[i], (uint8_t *)needle[i], STATS_TIMES); + if (found == 0) { + printf("Error3 searching for %s in text %s\n", needle[i], text[i]); + return 0; + } + printf("\n"); + } + return 1; +} +#endif + +/* Unit tests for new SPM API. */ + +#define SPM_NO_MATCH UINT32_MAX + +/* Helper structure describing a particular search. */ +typedef struct SpmTestData_ { + const char *needle; + uint16_t needle_len; + const char *haystack; + uint16_t haystack_len; + int nocase; + uint32_t match_offset; /* offset in haystack, or SPM_NO_MATCH. */ +} SpmTestData; + +/* Helper function to conduct a search with a particular SPM matcher. */ +static int SpmTestSearch(const SpmTestData *d, uint8_t matcher) +{ + int ret = 1; + SpmGlobalThreadCtx *global_thread_ctx = NULL; + SpmThreadCtx *thread_ctx = NULL; + SpmCtx *ctx = NULL; + uint8_t *found = NULL; + + global_thread_ctx = SpmInitGlobalThreadCtx(matcher); + if (global_thread_ctx == NULL) { + ret = 0; + goto exit; + } + + ctx = SpmInitCtx((const uint8_t *)d->needle, d->needle_len, d->nocase, global_thread_ctx); + if (ctx == NULL) { + ret = 0; + goto exit; + } + + thread_ctx = SpmMakeThreadCtx(global_thread_ctx); + if (thread_ctx == NULL) { + ret = 0; + goto exit; + } + + found = SpmScan(ctx, thread_ctx, (const uint8_t *)d->haystack, d->haystack_len); + if (found == NULL) { + if (d->match_offset != SPM_NO_MATCH) { + printf(" should have matched at %" PRIu32 " but didn't\n", d->match_offset); + ret = 0; + } + } else { + uint32_t offset = (uint32_t)(found - (const uint8_t *)d->haystack); + if (offset != d->match_offset) { + printf(" should have matched at %" PRIu32 " but matched at %" PRIu32 "\n", + d->match_offset, offset); + ret = 0; + } + } + +exit: + SpmDestroyCtx(ctx); + SpmDestroyThreadCtx(thread_ctx); + SpmDestroyGlobalThreadCtx(global_thread_ctx); + return ret; +} + +static int SpmSearchTest01(void) +{ + SpmTableSetup(); + printf("\n"); + + /* Each of the following tests will be run against every registered SPM + * algorithm. */ + + static const SpmTestData data[] = { + /* Some trivial single-character case/nocase tests */ + { "a", 1, "a", 1, 0, 0 }, + { "a", 1, "A", 1, 1, 0 }, + { "A", 1, "A", 1, 0, 0 }, + { "A", 1, "a", 1, 1, 0 }, + { "a", 1, "A", 1, 0, SPM_NO_MATCH }, + { "A", 1, "a", 1, 0, SPM_NO_MATCH }, + /* Nulls and odd characters */ + { "\x00", 1, "test\x00test", 9, 0, 4 }, + { "\x00", 1, "testtest", 8, 0, SPM_NO_MATCH }, + { "\n", 1, "new line\n", 9, 0, 8 }, + { "\n", 1, "new line\x00\n", 10, 0, 9 }, + { "\xff", 1, "abcdef\xff", 7, 0, 6 }, + { "\xff", 1, "abcdef\xff", 7, 1, 6 }, + { "$", 1, "dollar$", 7, 0, 6 }, + { "^", 1, "caret^", 6, 0, 5 }, + /* Longer literals */ + { "Suricata", 8, "This is a Suricata test", 23, 0, 10 }, + { "Suricata", 8, "This is a suricata test", 23, 1, 10 }, + { "Suricata", 8, "This is a suriCATA test", 23, 1, 10 }, + { "suricata", 8, "This is a Suricata test", 23, 0, SPM_NO_MATCH }, + { "Suricata", 8, "This is a Suricat_ test", 23, 0, SPM_NO_MATCH }, + { "Suricata", 8, "This is a _uricata test", 23, 0, SPM_NO_MATCH }, + /* First occurrence with the correct case should match */ + { "foo", 3, "foofoofoo", 9, 0, 0 }, + { "foo", 3, "_foofoofoo", 9, 0, 1 }, + { "FOO", 3, "foofoofoo", 9, 1, 0 }, + { "FOO", 3, "_foofoofoo", 9, 1, 1 }, + { "FOO", 3, "foo Foo FOo fOo foO FOO", 23, 0, 20 }, + { "foo", 3, "Foo FOo fOo foO FOO foo", 23, 0, 20 }, + }; + + int ret = 1; + + uint8_t matcher; + for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { + const SpmTableElmt *m = &spm_table[matcher]; + if (m->name == NULL) { + continue; + } + printf("matcher: %s\n", m->name); + + uint32_t i; + for (i = 0; i < sizeof(data) / sizeof(data[0]); i++) { + const SpmTestData *d = &data[i]; + if (SpmTestSearch(d, matcher) == 0) { + printf(" test %" PRIu32 ": fail\n", i); + ret = 0; + } + } + printf(" %" PRIu32 " tests passed\n", i); + } + + return ret; +} + +static int SpmSearchTest02(void) +{ + SpmTableSetup(); + printf("\n"); + + /* Test that we can find needles of various lengths at various alignments + * in the haystack. Note that these are passed to strlen. */ + + static const char *needles[] = { + /* Single bytes */ + "a", + "b", + "c", + ":", + "/", + "\x7f", + "\xff", + /* Repeats */ + "aa", + "aaa", + "aaaaaaaaaaaaaaaaaaaaaaa", + /* Longer literals */ + "suricata", + "meerkat", + "aardvark", + "raptor", + "marmot", + "lemming", + /* Mixed case */ + "Suricata", + "CAPS LOCK", + "mIxEd cAsE", + }; + + int ret = 1; + + uint8_t matcher; + for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { + const SpmTableElmt *m = &spm_table[matcher]; + if (m->name == NULL) { + continue; + } + printf("matcher: %s\n", m->name); + + SpmTestData d; + + uint32_t i; + for (i = 0; i < sizeof(needles) / sizeof(needles[0]); i++) { + const char *needle = needles[i]; + uint16_t prefix; + for (prefix = 0; prefix < 32; prefix++) { + d.needle = needle; + d.needle_len = (uint16_t)strlen(needle); + uint16_t haystack_len = prefix + d.needle_len; + char *haystack = SCMalloc(haystack_len); + if (haystack == NULL) { + printf("alloc failure\n"); + return 0; + } + memset(haystack, ' ', haystack_len); + memcpy(haystack + prefix, d.needle, d.needle_len); + d.haystack = haystack; + d.haystack_len = haystack_len; + d.nocase = 0; + d.match_offset = prefix; + + /* Case-sensitive scan */ + if (SpmTestSearch(&d, matcher) == 0) { + printf(" test %" PRIu32 ": fail (case-sensitive)\n", i); + ret = 0; + } + + /* Case-insensitive scan */ + d.nocase = 1; + uint16_t j; + for (j = 0; j < haystack_len; j++) { + haystack[j] = u8_toupper(haystack[j]); + } + if (SpmTestSearch(&d, matcher) == 0) { + printf(" test %" PRIu32 ": fail (case-insensitive)\n", i); + ret = 0; + } + + SCFree(haystack); + } + } + printf(" %" PRIu32 " tests passed\n", i); + } + + return ret; +} + +/* Register unittests */ +void UtilSpmSearchRegistertests(void) +{ + /* Generic tests */ + UtRegisterTest("UtilSpmBasicSearchTest01", UtilSpmBasicSearchTest01); + UtRegisterTest("UtilSpmBasicSearchNocaseTest01", UtilSpmBasicSearchNocaseTest01); + + UtRegisterTest("UtilSpmBs2bmSearchTest01", UtilSpmBs2bmSearchTest01); + UtRegisterTest("UtilSpmBs2bmSearchNocaseTest01", UtilSpmBs2bmSearchNocaseTest01); + + UtRegisterTest("UtilSpmBoyerMooreSearchTest01", UtilSpmBoyerMooreSearchTest01); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest01", UtilSpmBoyerMooreSearchNocaseTest01); + UtRegisterTest( + "UtilSpmBoyerMooreSearchNocaseTestIssue130", UtilSpmBoyerMooreSearchNocaseTestIssue130); + + UtRegisterTest("UtilSpmBs2bmSearchTest02", UtilSpmBs2bmSearchTest02); + UtRegisterTest("UtilSpmBs2bmSearchNocaseTest02", UtilSpmBs2bmSearchNocaseTest02); + + UtRegisterTest("UtilSpmBasicSearchTest02", UtilSpmBasicSearchTest02); + UtRegisterTest("UtilSpmBasicSearchNocaseTest02", UtilSpmBasicSearchNocaseTest02); + + UtRegisterTest("UtilSpmBoyerMooreSearchTest02", UtilSpmBoyerMooreSearchTest02); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest02", UtilSpmBoyerMooreSearchNocaseTest02); + + /* test matches at any offset */ + UtRegisterTest("UtilSpmSearchOffsetsTest01", UtilSpmSearchOffsetsTest01); + UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", UtilSpmSearchOffsetsNocaseTest01); + + /* new SPM API */ + UtRegisterTest("SpmSearchTest01", SpmSearchTest01); + UtRegisterTest("SpmSearchTest02", SpmSearchTest02); + +#ifdef ENABLE_SEARCH_STATS + /* Give some stats searching given a prepared context (look at the wrappers) */ + UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01); + UtRegisterTest("UtilSpmSearchStatsTest02", UtilSpmSearchStatsTest02); + UtRegisterTest("UtilSpmSearchStatsTest03", UtilSpmSearchStatsTest03); + + UtRegisterTest("UtilSpmNocaseSearchStatsTest01", UtilSpmNocaseSearchStatsTest01); + UtRegisterTest("UtilSpmNocaseSearchStatsTest02", UtilSpmNocaseSearchStatsTest02); + UtRegisterTest("UtilSpmNocaseSearchStatsTest03", UtilSpmNocaseSearchStatsTest03); + + /* Stats building context and searching */ + UtRegisterTest("UtilSpmSearchStatsTest04", UtilSpmSearchStatsTest04); + UtRegisterTest("UtilSpmSearchStatsTest05", UtilSpmSearchStatsTest05); + UtRegisterTest("UtilSpmSearchStatsTest06", UtilSpmSearchStatsTest06); + UtRegisterTest("UtilSpmSearchStatsTest07", UtilSpmSearchStatsTest07); + + UtRegisterTest("UtilSpmNocaseSearchStatsTest04", UtilSpmNocaseSearchStatsTest04); + UtRegisterTest("UtilSpmNocaseSearchStatsTest05", UtilSpmNocaseSearchStatsTest05); + UtRegisterTest("UtilSpmNocaseSearchStatsTest06", UtilSpmNocaseSearchStatsTest06); + UtRegisterTest("UtilSpmNocaseSearchStatsTest07", UtilSpmNocaseSearchStatsTest07); + +#endif +} +#endif diff --git a/src/util/spm.h b/src/util/spm.h new file mode 100644 index 000000000000..ec181ee15942 --- /dev/null +++ b/src/util/spm.h @@ -0,0 +1,130 @@ +/* Copyright (C) 2007-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + */ + +#ifndef __UTIL_SPM_H__ +#define __UTIL_SPM_H__ + +#include "util/spm-bs.h" + +enum { + SPM_BM, /* Boyer-Moore */ + SPM_HS, /* Hyperscan */ + /* Other SPM matchers will go here. */ + SPM_TABLE_SIZE +}; + +uint8_t SinglePatternMatchDefaultMatcher(void); + +/** Structure holding an immutable "built" SPM matcher (such as the Boyer-Moore + * tables, Hyperscan database etc) that is passed to the Scan call. */ +typedef struct SpmCtx_ { + uint8_t matcher; + void *ctx; +} SpmCtx; + +/** Structure holding a global prototype for per-thread scratch space, passed + * to each InitCtx call. */ +typedef struct SpmGlobalThreadCtx_ { + uint8_t matcher; + void *ctx; +} SpmGlobalThreadCtx; + +/** Structure holding some mutable per-thread space for use by a matcher at + * scan time. Constructed from SpmGlobalThreadCtx by the MakeThreadCtx call. */ +typedef struct SpmThreadCtx_ { + uint8_t matcher; + void *ctx; +} SpmThreadCtx; + +typedef struct SpmTableElmt_ { + const char *name; + SpmGlobalThreadCtx *(*InitGlobalThreadCtx)(void); + void (*DestroyGlobalThreadCtx)(SpmGlobalThreadCtx *g_thread_ctx); + SpmThreadCtx *(*MakeThreadCtx)(const SpmGlobalThreadCtx *g_thread_ctx); + void (*DestroyThreadCtx)(SpmThreadCtx *thread_ctx); + SpmCtx *(*InitCtx)(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *g_thread_ctx); + void (*DestroyCtx)(SpmCtx *); + uint8_t *(*Scan)(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, const uint8_t *haystack, + uint32_t haystack_len); +} SpmTableElmt; + +extern SpmTableElmt spm_table[SPM_TABLE_SIZE]; + +void SpmTableSetup(void); + +SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint8_t matcher); + +void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *g_thread_ctx); + +SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *g_thread_ctx); + +void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx); + +SpmCtx *SpmInitCtx( + const uint8_t *needle, uint16_t needle_len, int nocase, SpmGlobalThreadCtx *g_thread_ctx); + +void SpmDestroyCtx(SpmCtx *ctx); + +uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, const uint8_t *haystack, + uint32_t haystack_len); + +/** Default algorithm to use: Boyer Moore */ +uint8_t *Bs2bmSearch( + const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *Bs2bmNocaseSearch( + const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *BoyerMooreSearch( + const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *BoyerMooreNocaseSearch( + const uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); + +/* Macros for automatic algorithm selection (use them only when you can't store the context) */ +#define SpmSearch(text, textlen, needle, needlelen) \ + ({ \ + uint8_t *mfound; \ + if (needlelen < 4 && textlen < 512) \ + mfound = BasicSearch(text, textlen, needle, needlelen); \ + else if (needlelen < 4) \ + mfound = BasicSearch(text, textlen, needle, needlelen); \ + else \ + mfound = BoyerMooreSearch(text, textlen, needle, needlelen); \ + mfound; \ + }) + +#define SpmNocaseSearch(text, textlen, needle, needlelen) \ + ({ \ + uint8_t *mfound; \ + if (needlelen < 4 && textlen < 512) \ + mfound = BasicSearchNocase(text, textlen, needle, needlelen); \ + else if (needlelen < 4) \ + mfound = BasicSearchNocase(text, textlen, needle, needlelen); \ + else \ + mfound = BoyerMooreNocaseSearch(text, textlen, needle, needlelen); \ + mfound; \ + }) + +#ifdef UNITTESTS +void UtilSpmSearchRegistertests(void); +#endif +#endif /* __UTIL_SPM_H__ */ diff --git a/src/util/storage.c b/src/util/storage.c new file mode 100644 index 000000000000..51a8554c4629 --- /dev/null +++ b/src/util/storage.c @@ -0,0 +1,410 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Storage API + */ + +#include "suricata-common.h" +#include "util/unittest.h" +#include "util/storage.h" +#include "util/debug.h" + +typedef struct StorageMapping_ { + const char *name; + StorageEnum type; // host, flow, tx, stream, ssn, etc + unsigned int size; + void *(*Alloc)(unsigned int); + void (*Free)(void *); +} StorageMapping; + +/** \brief list of StorageMapping used at registration time */ +typedef struct StorageList_ { + StorageMapping map; + int id; + struct StorageList_ *next; +} StorageList; + +static StorageList *storage_list = NULL; +static int storage_max_id[STORAGE_MAX]; +static int storage_registration_closed = 0; +static StorageMapping **storage_map = NULL; + +static const char *StoragePrintType(StorageEnum type) +{ + switch (type) { + case STORAGE_HOST: + return "host"; + case STORAGE_FLOW: + return "flow"; + case STORAGE_IPPAIR: + return "ippair"; + case STORAGE_DEVICE: + return "livedevice"; + case STORAGE_MAX: + return "max"; + } + return "invalid"; +} + +void StorageInit(void) +{ + memset(&storage_max_id, 0x00, sizeof(storage_max_id)); + storage_list = NULL; + storage_map = NULL; + storage_registration_closed = 0; +} + +void StorageCleanup(void) +{ + if (storage_map) { + int i; + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_map[i] != NULL) { + SCFree(storage_map[i]); + storage_map[i] = NULL; + } + } + SCFree(storage_map); + storage_map = NULL; + } + + StorageList *entry = storage_list; + while (entry) { + StorageList *next = entry->next; + SCFree(entry); + entry = next; + } + + storage_list = NULL; +} + +int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, + void *(*Alloc)(unsigned int), void (*Free)(void *)) +{ + if (storage_registration_closed) + return -1; + + if (type >= STORAGE_MAX || name == NULL || strlen(name) == 0 || size == 0 || + (size != sizeof(void *) && Alloc == NULL) || Free == NULL) + return -1; + + StorageList *list = storage_list; + while (list) { + if (strcmp(name, list->map.name) == 0 && type == list->map.type) { + SCLogError("storage for type \"%s\" with " + "name \"%s\" already registered", + StoragePrintType(type), name); + return -1; + } + + list = list->next; + } + + StorageList *entry = SCCalloc(1, sizeof(StorageList)); + if (unlikely(entry == NULL)) + return -1; + + entry->map.type = type; + entry->map.name = name; + entry->map.size = size; + entry->map.Alloc = Alloc; + entry->map.Free = Free; + + entry->id = storage_max_id[type]++; + entry->next = storage_list; + storage_list = entry; + + return entry->id; +} + +int StorageFinalize(void) +{ + int count = 0; + int i; + + storage_registration_closed = 1; + + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_max_id[i] > 0) + count++; + } + if (count == 0) + return 0; + + storage_map = SCCalloc(STORAGE_MAX, sizeof(StorageMapping *)); + if (unlikely(storage_map == NULL)) { + return -1; + } + + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_max_id[i] > 0) { + storage_map[i] = SCCalloc(storage_max_id[i], sizeof(StorageMapping)); + if (storage_map[i] == NULL) + return -1; + } + } + + StorageList *entry = storage_list; + while (entry) { + if (storage_map[entry->map.type] != NULL) { + storage_map[entry->map.type][entry->id].name = entry->map.name; + storage_map[entry->map.type][entry->id].type = entry->map.type; + storage_map[entry->map.type][entry->id].size = entry->map.size; + storage_map[entry->map.type][entry->id].Alloc = entry->map.Alloc; + storage_map[entry->map.type][entry->id].Free = entry->map.Free; + } + + StorageList *next = entry->next; + SCFree(entry); + entry = next; + }; + storage_list = NULL; + +#ifdef DEBUG + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_map[i] == NULL) + continue; + + int j; + for (j = 0; j < storage_max_id[i]; j++) { + StorageMapping *m = &storage_map[i][j]; + SCLogDebug("type \"%s\" name \"%s\" size \"%" PRIuMAX "\"", StoragePrintType(m->type), + m->name, (uintmax_t)m->size); + } + } +#endif + return 0; +} + +unsigned int StorageGetCnt(StorageEnum type) +{ + return storage_max_id[type]; +} + +/** \brief get the size of the void array used to store + * the pointers + * \retval size size in bytes, can return 0 if not storage is needed + * + * \todo we could return -1 when registration isn't closed yet, however + * this will break lots of tests currently, so not doing it now */ +unsigned int StorageGetSize(StorageEnum type) +{ + return storage_max_id[type] * sizeof(void *); +} + +void *StorageGetById(const Storage *storage, const StorageEnum type, const int id) +{ +#ifdef DEBUG + BUG_ON(!storage_registration_closed); +#endif + SCLogDebug("storage %p id %d", storage, id); + if (storage == NULL) + return NULL; + return storage[id].ptr; +} + +int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr) +{ +#ifdef DEBUG + BUG_ON(!storage_registration_closed); +#endif + SCLogDebug("storage %p id %d", storage, id); + if (storage == NULL) + return -1; + storage[id].ptr = ptr; + return 0; +} + +void *StorageAllocByIdPrealloc(Storage *storage, StorageEnum type, int id) +{ +#ifdef DEBUG + BUG_ON(!storage_registration_closed); +#endif + SCLogDebug("storage %p id %d", storage, id); + + StorageMapping *map = &storage_map[type][id]; + if (storage[id].ptr == NULL && map->Alloc != NULL) { + storage[id].ptr = map->Alloc(map->size); + if (storage[id].ptr == NULL) { + return NULL; + } + } + + return storage[id].ptr; +} + +void StorageFreeById(Storage *storage, StorageEnum type, int id) +{ +#ifdef DEBUG + BUG_ON(!storage_registration_closed); +#endif +#ifdef UNITTESTS + if (storage_map == NULL) + return; +#endif + SCLogDebug("storage %p id %d", storage, id); + + Storage *store = storage; + if (store != NULL) { + SCLogDebug("store %p", store); + if (store[id].ptr != NULL) { + StorageMapping *map = &storage_map[type][id]; + map->Free(store[id].ptr); + store[id].ptr = NULL; + } + } +} + +void StorageFreeAll(Storage *storage, StorageEnum type) +{ + if (storage == NULL) + return; +#ifdef DEBUG + BUG_ON(!storage_registration_closed); +#endif +#ifdef UNITTESTS + if (storage_map == NULL) + return; +#endif + + Storage *store = storage; + int i; + for (i = 0; i < storage_max_id[type]; i++) { + if (store[i].ptr != NULL) { + StorageMapping *map = &storage_map[type][i]; + map->Free(store[i].ptr); + store[i].ptr = NULL; + } + } +} + +#ifdef UNITTESTS + +static void *StorageTestAlloc(unsigned int size) +{ + void *x = SCMalloc(size); + return x; +} +static void StorageTestFree(void *x) +{ + if (x) + SCFree(x); +} + +static int StorageTest01(void) +{ + StorageInit(); + + int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree); + if (id < 0) + goto error; + id = StorageRegister(STORAGE_HOST, "variable", 24, StorageTestAlloc, StorageTestFree); + if (id < 0) + goto error; + id = StorageRegister(STORAGE_FLOW, "store", sizeof(void *), StorageTestAlloc, StorageTestFree); + if (id < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + StorageCleanup(); + return 1; +error: + StorageCleanup(); + return 0; +} + +static int StorageTest03(void) +{ + StorageInit(); + + int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree); + if (id < 0) + goto error; + id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed: "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "test1", 6, NULL, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (2): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "test2", 8, StorageTestAlloc, NULL); + if (id != -1) { + printf("duplicate registration should have failed (3): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "test3", 0, StorageTestAlloc, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (4): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "", 8, StorageTestAlloc, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (5): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, NULL, 8, StorageTestAlloc, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (6): "); + goto error; + } + + id = StorageRegister(STORAGE_MAX, "test4", 8, StorageTestAlloc, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (7): "); + goto error; + } + + id = StorageRegister(38, "test5", 8, StorageTestAlloc, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (8): "); + goto error; + } + + id = StorageRegister(-1, "test6", 8, StorageTestAlloc, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (9): "); + goto error; + } + + StorageCleanup(); + return 1; +error: + StorageCleanup(); + return 0; +} + +void StorageRegisterTests(void) +{ + UtRegisterTest("StorageTest01", StorageTest01); + UtRegisterTest("StorageTest03", StorageTest03); +} +#endif diff --git a/src/util/storage.h b/src/util/storage.h new file mode 100644 index 000000000000..d62a320feeac --- /dev/null +++ b/src/util/storage.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Storage API + */ + +#ifndef __UTIL_STORAGE_H__ +#define __UTIL_STORAGE_H__ + +typedef enum StorageEnum_ { + STORAGE_HOST, + STORAGE_FLOW, + STORAGE_IPPAIR, + STORAGE_DEVICE, + + STORAGE_MAX, +} StorageEnum; + +/** void ptr array for now */ +typedef struct Storage { + void *ptr; +} Storage; + +void StorageInit(void); +void StorageCleanup(void); + +/** \brief Register new storage + * + * \param type type from StorageEnum + * \param name name + * \param size size of the per instance storage + * \param Alloc alloc function for per instance storage + * \param Free free function for per instance storage + * + * \note if size == ptr size (so sizeof(void *)) and Alloc == NULL the API just + * gives the caller a ptr to store something it alloc'ed itself. + */ +int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, + void *(*Alloc)(unsigned int), void (*Free)(void *)); +int StorageFinalize(void); + +unsigned int StorageGetCnt(const StorageEnum type); +unsigned int StorageGetSize(const StorageEnum type); + +/** \brief get storage for id */ +void *StorageGetById(const Storage *storage, const StorageEnum type, const int id); +/** \brief set storage for id */ +int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr); + +/** \brief AllocById func for prealloc'd base storage (storage ptrs are part + * of another memory block) */ +void *StorageAllocByIdPrealloc(Storage *storage, StorageEnum type, int id); +void StorageFreeById(Storage *storage, const StorageEnum type, const int id); +void StorageFreeAll(Storage *storage, const StorageEnum type); + +void StorageRegisterTests(void); +#endif diff --git a/src/util/streaming-buffer.c b/src/util/streaming-buffer.c new file mode 100644 index 000000000000..80599665192c --- /dev/null +++ b/src/util/streaming-buffer.c @@ -0,0 +1,2323 @@ +/* Copyright (C) 2015-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "util/streaming-buffer.h" +#include "util/unittest.h" +#include "util/print.h" +#include "util/validate.h" +#include "util/debug.h" +#include "util/error.h" + +static void ListRegions(StreamingBuffer *sb); + +#define DUMP_REGIONS 0 // set to 1 to dump a visual representation of the regions list and sbb tree. + +/** + * \file + * + * \author Victor Julien + * + * \brief Streaming Buffer API + */ + +static void *ReallocFunc(void *ptr, const size_t size) +{ + void *ptrmem = SCRealloc(ptr, size); + if (unlikely(ptrmem == NULL)) { + sc_errno = SC_ENOMEM; + } + return ptrmem; +} + +static void *CallocFunc(const size_t nm, const size_t sz) +{ + void *ptrmem = SCCalloc(nm, sz); + if (unlikely(ptrmem == NULL)) { + sc_errno = SC_ENOMEM; + } + return ptrmem; +} + +/* memory handling wrappers. If config doesn't define it's own set of + * functions, use the defaults */ +// TODO the default allocators don't set `sc_errno` yet. +#define CALLOC(cfg, n, s) (cfg)->Calloc ? (cfg)->Calloc((n), (s)) : CallocFunc((n), (s)) +#define REALLOC(cfg, ptr, orig_s, s) \ + (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : ReallocFunc((ptr), (s)) +#define FREE(cfg, ptr, s) (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr)) + +static void SBBFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg); + +RB_GENERATE(SBB, StreamingBufferBlock, rb, SBBCompare); + +int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b) +{ + SCLogDebug("a %" PRIu64 " len %u, b %" PRIu64 " len %u", a->offset, a->len, b->offset, b->len); + + if (a->offset > b->offset) + SCReturnInt(1); + else if (a->offset < b->offset) + SCReturnInt(-1); + else { + if (a->len == 0 || b->len == 0 || a->len == b->len) + SCReturnInt(0); + else if (a->len > b->len) + SCReturnInt(1); + else + SCReturnInt(-1); + } +} + +/* inclusive compare function that also considers the right edge, + * not just the offset. */ +static inline int InclusiveCompare(StreamingBufferBlock *lookup, StreamingBufferBlock *intree) +{ + const uint64_t lre = lookup->offset + lookup->len; + const uint64_t tre = intree->offset + intree->len; + if (lre <= intree->offset) // entirely before + return -1; + else if (lookup->offset < tre && lre <= tre) // (some) overlap + return 0; + else + return 1; // entirely after +} + +StreamingBufferBlock *SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm) +{ + SCLogDebug("looking up %" PRIu64, elm->offset); + + struct StreamingBufferBlock *tmp = RB_ROOT(head); + struct StreamingBufferBlock *res = NULL; + while (tmp) { + SCLogDebug("compare with %" PRIu64 "/%u", tmp->offset, tmp->len); + const int comp = InclusiveCompare(elm, tmp); + SCLogDebug("compare result: %d", comp); + if (comp < 0) { + res = tmp; + tmp = RB_LEFT(tmp, rb); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp, rb); + } else { + return tmp; + } + } + return res; +} + +/** \interal + * \brief does data region intersect with list region 'r' + * Takes the max gap into account. + */ +static inline bool RegionsIntersect(const StreamingBuffer *sb, const StreamingBufferConfig *cfg, + const StreamingBufferRegion *r, const uint64_t offset, const uint64_t re) +{ + /* create the data range for the region, adding the max gap */ + const uint64_t reg_o = + r->stream_offset > cfg->region_gap ? (r->stream_offset - cfg->region_gap) : 0; + const uint64_t reg_re = r->stream_offset + r->buf_size + cfg->region_gap; + SCLogDebug("r %p: %" PRIu64 "/%" PRIu64 " - adjusted %" PRIu64 "/%" PRIu64, r, r->stream_offset, + r->stream_offset + r->buf_size, reg_o, reg_re); + /* check if data range intersects with region range */ + if (offset >= reg_o && offset <= reg_re) { + SCLogDebug("r %p is in-scope", r); + return true; + } + if (re >= reg_o && re <= reg_re) { + SCLogDebug("r %p is in-scope: %" PRIu64 " >= %" PRIu64 " && %" PRIu64 " <= %" PRIu64, r, re, + reg_o, re, reg_re); + return true; + } + SCLogDebug("r %p is out of scope: %" PRIu64 "/%" PRIu64, r, offset, re); + return false; +} + +/** \internal + * \brief find the first region for merging. + */ +static StreamingBufferRegion *FindFirstRegionForOffset(const StreamingBuffer *sb, + const StreamingBufferConfig *cfg, StreamingBufferRegion *r, const uint64_t offset, + const uint32_t len, StreamingBufferRegion **prev) +{ + const uint64_t data_re = offset + len; + SCLogDebug("looking for first region matching %" PRIu64 "/%" PRIu64, offset, data_re); + + StreamingBufferRegion *p = NULL; + for (; r != NULL; r = r->next) { + if (RegionsIntersect(sb, cfg, r, offset, data_re) == true) { + *prev = p; + return r; + } + p = r; + } + *prev = NULL; + return NULL; +} + +static StreamingBufferRegion *FindLargestRegionForOffset(const StreamingBuffer *sb, + const StreamingBufferConfig *cfg, StreamingBufferRegion *r, const uint64_t offset, + const uint32_t len) +{ + const uint64_t data_re = offset + len; + SCLogDebug("starting at %p/%" PRIu64 ", offset %" PRIu64 ", data_re %" PRIu64, r, + r->stream_offset, offset, data_re); + StreamingBufferRegion *candidate = r; + for (; r != NULL; r = r->next) { +#ifdef DEBUG + const uint64_t reg_re = r->stream_offset + r->buf_size; + SCLogDebug("checking: %p/%" PRIu64 "/%" PRIu64 ", offset %" PRIu64 "/%" PRIu64, r, + r->stream_offset, reg_re, offset, data_re); +#endif + if (!RegionsIntersect(sb, cfg, r, offset, data_re)) + return candidate; + + if (r->buf_size > candidate->buf_size) { + SCLogDebug("candidate %p as size %u > %u", candidate, r->buf_size, candidate->buf_size); + candidate = r; + } + } + return candidate; +} + +static StreamingBufferRegion *FindRightEdge(const StreamingBuffer *sb, + const StreamingBufferConfig *cfg, StreamingBufferRegion *r, const uint64_t offset, + const uint32_t len) +{ + const uint64_t data_re = offset + len; + StreamingBufferRegion *candidate = r; + for (; r != NULL; r = r->next) { + if (!RegionsIntersect(sb, cfg, r, offset, data_re)) { + SCLogDebug( + "r %p is out of scope: %" PRIu64 "/%u/%" PRIu64, r, offset, len, offset + len); + return candidate; + } + candidate = r; + } + return candidate; +} + +/** \note uses sc_errno to give error details */ +static inline StreamingBufferRegion *InitBufferRegion( + StreamingBuffer *sb, const StreamingBufferConfig *cfg, const uint32_t min_size) +{ + if (sb->regions == USHRT_MAX || (cfg->max_regions != 0 && sb->regions >= cfg->max_regions)) { + SCLogDebug("max regions reached"); + sc_errno = SC_ELIMIT; + return NULL; + } + + StreamingBufferRegion *aux_r = CALLOC(cfg, 1, sizeof(*aux_r)); + if (aux_r == NULL) { + return NULL; + } + + aux_r->buf = CALLOC(cfg, 1, MAX(cfg->buf_size, min_size)); + if (aux_r->buf == NULL) { + FREE(cfg, aux_r, sizeof(*aux_r)); + return NULL; + } + aux_r->buf_size = MAX(cfg->buf_size, min_size); + sb->regions++; + sb->max_regions = MAX(sb->regions, sb->max_regions); + return aux_r; +} + +static inline int InitBuffer(StreamingBuffer *sb, const StreamingBufferConfig *cfg) +{ + sb->region.buf = CALLOC(cfg, 1, cfg->buf_size); + if (sb->region.buf == NULL) { + return sc_errno; + } + sb->region.buf_size = cfg->buf_size; + return SC_OK; +} + +StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg) +{ + StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer)); + if (sb == NULL) { + return NULL; + } + + sb->region.buf_size = cfg->buf_size; + sb->regions = sb->max_regions = 1; + + if (cfg->buf_size == 0) { + return sb; + } + + int r = InitBuffer(sb, cfg); + if (r != SC_OK) { + FREE(cfg, sb, sizeof(StreamingBuffer)); + sc_errno = r; + return NULL; + } + return sb; +} + +void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg) +{ + if (sb != NULL) { + SCLogDebug("sb->region.buf_size %u max %u", sb->region.buf_size, sb->buf_size_max); + + SBBFree(sb, cfg); + ListRegions(sb); + if (sb->region.buf != NULL) { + FREE(cfg, sb->region.buf, sb->region.buf_size); + sb->region.buf = NULL; + } + + for (StreamingBufferRegion *r = sb->region.next; r != NULL;) { + StreamingBufferRegion *next = r->next; + FREE(cfg, r->buf, r->buf_size); + FREE(cfg, r, sizeof(*r)); + r = next; + } + sb->region.next = NULL; + sb->regions = sb->max_regions = 1; + } +} + +void StreamingBufferFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg) +{ + if (sb != NULL) { + StreamingBufferClear(sb, cfg); + FREE(cfg, sb, sizeof(StreamingBuffer)); + } +} + +#ifdef DEBUG +static void SBBPrintList(StreamingBuffer *sb) +{ + StreamingBufferBlock *sbb = NULL; + RB_FOREACH(sbb, SBB, &sb->sbb_tree) + { + SCLogDebug("sbb: offset %" PRIu64 ", len %u", sbb->offset, sbb->len); + StreamingBufferBlock *next = SBB_RB_NEXT(sbb); + if (next) { + if ((sbb->offset + sbb->len) != next->offset) { + SCLogDebug("gap: offset %" PRIu64 ", len %" PRIu64, (sbb->offset + sbb->len), + next->offset - (sbb->offset + sbb->len)); + } + } + } +} +#endif + +/* setup with gap between 2 blocks + * + * [block][gap][block] + **/ +static int WARN_UNUSED SBBInit(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferRegion *region, uint32_t rel_offset, uint32_t data_len) +{ + DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree)); + DEBUG_VALIDATE_BUG_ON(region->buf_offset > region->stream_offset + rel_offset); + + /* need to set up 2: existing data block and new data block */ + StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb)); + if (sbb == NULL) { + return sc_errno; + } + sbb->offset = sb->region.stream_offset; + sbb->len = sb->region.buf_offset; + (void)SBB_RB_INSERT(&sb->sbb_tree, sbb); + sb->head = sbb; + sb->sbb_size = sbb->len; + + StreamingBufferBlock *sbb2 = CALLOC(cfg, 1, sizeof(*sbb2)); + if (sbb2 == NULL) { + return sc_errno; + } + sbb2->offset = region->stream_offset + rel_offset; + sbb2->len = data_len; + DEBUG_VALIDATE_BUG_ON(sbb2->offset < sbb->len); + SCLogDebug("sbb1 %" PRIu64 ", len %u, sbb2 %" PRIu64 ", len %u", sbb->offset, sbb->len, + sbb2->offset, sbb2->len); + + sb->sbb_size += sbb2->len; + if (SBB_RB_INSERT(&sb->sbb_tree, sbb2) != NULL) { + FREE(cfg, sbb2, sizeof(*sbb2)); + return SC_EINVAL; + } + +#ifdef DEBUG + SBBPrintList(sb); +#endif + return SC_OK; +} + +/* setup with leading gap + * + * [gap][block] + **/ +static int WARN_UNUSED SBBInitLeadingGap(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferRegion *region, uint64_t offset, uint32_t data_len) +{ + DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree)); + + StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb)); + if (sbb == NULL) { + return sc_errno; + } + sbb->offset = offset; + sbb->len = data_len; + + sb->head = sbb; + sb->sbb_size = sbb->len; + (void)SBB_RB_INSERT(&sb->sbb_tree, sbb); + + SCLogDebug("sbb %" PRIu64 ", len %u", sbb->offset, sbb->len); +#ifdef DEBUG + SBBPrintList(sb); +#endif + return SC_OK; +} + +static inline void ConsolidateFwd(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferRegion *region, struct SBB *tree, StreamingBufferBlock *sa) +{ + uint64_t sa_re = sa->offset + sa->len; + StreamingBufferBlock *tr, *s = sa; + RB_FOREACH_FROM (tr, SBB, s) { + if (sa == tr) + continue; + + const uint64_t tr_re = tr->offset + tr->len; + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u re %" PRIu64, tr, tr->offset, tr->len, tr_re); + + if (sa_re < tr->offset) { + SCLogDebug("entirely before: %" PRIu64 " < %" PRIu64, sa_re, tr->offset); + break; // entirely before + } + + /* new block (sa) entirely eclipsed by in tree block (tr) + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + if (sa->offset >= tr->offset && sa_re <= tr_re) { + sb->sbb_size -= sa->len; + sa->len = tr->len; + sa->offset = tr->offset; + sa_re = sa->offset + sa->len; + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr, + tr->offset, tr->len); + SBB_RB_REMOVE(tree, tr); + FREE(cfg, tr, sizeof(StreamingBufferBlock)); + /* new block (sa) entire eclipses in tree block (tr) + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + } else if (sa->offset <= tr->offset && sa_re >= tr_re) { + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr, + tr->offset, tr->len); + SBB_RB_REMOVE(tree, tr); + sb->sbb_size -= tr->len; + FREE(cfg, tr, sizeof(StreamingBufferBlock)); + + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, + sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + if (sa->offset == region->stream_offset && + sa_re > (region->stream_offset + region->buf_offset)) { + DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); + region->buf_offset = sa_re - region->stream_offset; + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 + " bo %u sz %u BUF_OFFSET UPDATED", + sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + } + /* new block (sa) extended by in tree block (tr) + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + } else if (sa->offset < tr->offset && // starts before + sa_re >= tr->offset && sa_re < tr_re) // ends inside + { + // merge. sb->sbb_size includes both so we need to adjust that too. + uint32_t combined_len = sa->len + tr->len; + sa->len = tr_re - sa->offset; + sa_re = sa->offset + sa->len; + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len); + SBB_RB_REMOVE(tree, tr); + sb->sbb_size -= (combined_len - sa->len); // remove what we added twice + FREE(cfg, tr, sizeof(StreamingBufferBlock)); + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u RESULT", sa, sa->offset, sa->len); + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, + sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + if (sa->offset == region->stream_offset && + sa_re > (region->stream_offset + region->buf_offset)) { + DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); + region->buf_offset = sa_re - region->stream_offset; + SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 + " bo %u sz %u BUF_OFFSET UPDATED", + sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + } + } + } +} + +static inline void ConsolidateBackward(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferRegion *region, struct SBB *tree, StreamingBufferBlock *sa) +{ + uint64_t sa_re = sa->offset + sa->len; + StreamingBufferBlock *tr, *s = sa; + RB_FOREACH_REVERSE_FROM (tr, SBB, s) { + if (sa == tr) + continue; + const uint64_t tr_re = tr->offset + tr->len; + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u", tr, tr->offset, tr->len); + + if (sa->offset > tr_re) + break; // entirely after + + /* new block (sa) entirely eclipsed by in tree block (tr) + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + if (sa->offset >= tr->offset && sa_re <= tr_re) { + sb->sbb_size -= sa->len; // sa entirely eclipsed so remove double accounting + sa->len = tr->len; + sa->offset = tr->offset; + sa_re = sa->offset + sa->len; + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr, + tr->offset, tr->len); + if (sb->head == tr) + sb->head = sa; + SBB_RB_REMOVE(tree, tr); + FREE(cfg, tr, sizeof(StreamingBufferBlock)); + /* new block (sa) entire eclipses in tree block (tr) + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + } else if (sa->offset <= tr->offset && sa_re >= tr_re) { + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr, + tr->offset, tr->len); + if (sb->head == tr) + sb->head = sa; + SBB_RB_REMOVE(tree, tr); + sb->sbb_size -= tr->len; // tr entirely eclipsed so remove double accounting + FREE(cfg, tr, sizeof(StreamingBufferBlock)); + + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, + sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + + if (sa->offset == region->stream_offset && + sa_re > (region->stream_offset + region->buf_offset)) { + DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); + region->buf_offset = sa_re - region->stream_offset; + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 + " bo %u sz %u BUF_OFFSET UPDATED", + sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + } + + /* new block (sa) extends in tree block (tr) + sa: [ ] + tr: [ ] + sa: [ ] + tr: [ ] + */ + } else if (sa->offset > tr->offset && sa_re > tr_re && sa->offset <= tr_re) { + // merge. sb->sbb_size includes both so we need to adjust that too. + uint32_t combined_len = sa->len + tr->len; + sa->len = sa_re - tr->offset; + sa->offset = tr->offset; + sa_re = sa->offset + sa->len; + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len); + if (sb->head == tr) + sb->head = sa; + SBB_RB_REMOVE(tree, tr); + sb->sbb_size -= (combined_len - sa->len); // remove what we added twice + FREE(cfg, tr, sizeof(StreamingBufferBlock)); + + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa, + sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + if (sa->offset == region->stream_offset && + sa_re > (region->stream_offset + region->buf_offset)) { + DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset); + region->buf_offset = sa_re - region->stream_offset; + SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 + " bo %u sz %u BUF_OFFSET UPDATED", + sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset, + region->buf_size); + } + } + } +} + +/** \internal + * \param region the region that holds the new data + */ +static int SBBUpdate(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferRegion *region, uint32_t rel_offset, uint32_t len) +{ + struct SBB *tree = &sb->sbb_tree; + SCLogDebug("* inserting: %u/%u", rel_offset, len); + + StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb)); + if (sbb == NULL) { + return sc_errno; + } + sbb->offset = region->stream_offset + rel_offset; + sbb->len = len; + + StreamingBufferBlock *res = SBB_RB_INSERT(tree, sbb); + if (res) { + // exact overlap + SCLogDebug("* insert failed: exact match in tree with %p %" PRIu64 "/%u", res, res->offset, + res->len); + FREE(cfg, sbb, sizeof(StreamingBufferBlock)); + return SC_OK; + } + sb->sbb_size += len; // may adjust based on consolidation below + + /* handle backwards and forwards overlaps */ + if (SBB_RB_PREV(sbb) == NULL) { + sb->head = sbb; + } else { + ConsolidateBackward(sb, cfg, region, tree, sbb); + } + ConsolidateFwd(sb, cfg, region, tree, sbb); +#ifdef DEBUG + SBBPrintList(sb); +#endif + if (sbb->offset == region->stream_offset) { + SCLogDebug("insert at region head"); + region->buf_offset = sbb->len; + } + return SC_OK; +} + +static void SBBFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg) +{ + StreamingBufferBlock *sbb = NULL, *safe = NULL; + RB_FOREACH_SAFE (sbb, SBB, &sb->sbb_tree, safe) { + SBB_RB_REMOVE(&sb->sbb_tree, sbb); + sb->sbb_size -= sbb->len; + FREE(cfg, sbb, sizeof(StreamingBufferBlock)); + } + sb->head = NULL; +} + +static void SBBPrune(StreamingBuffer *sb, const StreamingBufferConfig *cfg) +{ + SCLogDebug("pruning %p to %" PRIu64, sb, sb->region.stream_offset); + StreamingBufferBlock *sbb = NULL, *safe = NULL; + RB_FOREACH_SAFE (sbb, SBB, &sb->sbb_tree, safe) { + /* completely beyond window, we're done */ + if (sbb->offset >= sb->region.stream_offset) { + sb->head = sbb; + if (sbb->offset == sb->region.stream_offset) { + SCLogDebug("set buf_offset?"); + if (sbb->offset == sb->region.stream_offset) { + SCLogDebug("set buf_offset to first sbb len %u", sbb->len); + DEBUG_VALIDATE_BUG_ON(sbb->len > sb->region.buf_size); + sb->region.buf_offset = sbb->len; + } + } + break; + } + + /* partly before, partly beyond. Adjust */ + if (sbb->offset < sb->region.stream_offset && + sbb->offset + sbb->len > sb->region.stream_offset) { + uint32_t shrink_by = sb->region.stream_offset - sbb->offset; + DEBUG_VALIDATE_BUG_ON(shrink_by > sbb->len); + if (sbb->len >= shrink_by) { + sbb->len -= shrink_by; + sbb->offset += shrink_by; + sb->sbb_size -= shrink_by; + SCLogDebug("shrunk by %u", shrink_by); + DEBUG_VALIDATE_BUG_ON(sbb->offset != sb->region.stream_offset); + } + sb->head = sbb; + if (sbb->offset == sb->region.stream_offset) { + SCLogDebug("set buf_offset to first sbb len %u", sbb->len); + DEBUG_VALIDATE_BUG_ON(sbb->len > sb->region.buf_size); + sb->region.buf_offset = sbb->len; + } + break; + } + + SBB_RB_REMOVE(&sb->sbb_tree, sbb); + /* either we set it again for the next sbb, or there isn't any */ + sb->head = NULL; + sb->sbb_size -= sbb->len; + SCLogDebug("sb %p removed %p %" PRIu64 ", %u", sb, sbb, sbb->offset, sbb->len); + FREE(cfg, sbb, sizeof(StreamingBufferBlock)); + } +#ifdef DEBUG + SBBPrintList(sb); +#endif +} + +static inline uint32_t ToNextMultipleOf(const uint32_t in, const uint32_t m) +{ + uint32_t r = in; + if (m > 0) { + const uint32_t x = in % m; + if (x != 0) { + r = (in - x) + m; + } + } + return r; +} + +static thread_local bool g2s_warn_once = false; + +static inline int WARN_UNUSED GrowRegionToSize(StreamingBuffer *sb, + const StreamingBufferConfig *cfg, StreamingBufferRegion *region, const uint32_t size) +{ + DEBUG_VALIDATE_BUG_ON(region->buf_size > BIT_U32(30)); + if (size > BIT_U32(30)) { // 1GiB + if (!g2s_warn_once) { + SCLogWarning("StreamingBuffer::GrowRegionToSize() tried to alloc %u bytes, exceeds " + "limit of %lu", + size, BIT_U32(30)); + g2s_warn_once = true; + } + return SC_ELIMIT; + } + + /* try to grow in multiples of cfg->buf_size */ + const uint32_t grow = ToNextMultipleOf(size, cfg->buf_size); + SCLogDebug("grow %u", grow); + + void *ptr = REALLOC(cfg, region->buf, region->buf_size, grow); + if (ptr == NULL) { + return sc_errno; + } + /* for safe printing and general caution, lets memset the + * new data to 0 */ + size_t diff = grow - region->buf_size; + void *new_mem = ((char *)ptr) + region->buf_size; + memset(new_mem, 0, diff); + + region->buf = ptr; + region->buf_size = grow; + SCLogDebug("grown buffer to %u", grow); +#ifdef DEBUG + if (region->buf_size > sb->buf_size_max) { + sb->buf_size_max = region->buf_size; + } +#endif + return SC_OK; +} + +static int WARN_UNUSED GrowToSize( + StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint32_t size) +{ + return GrowRegionToSize(sb, cfg, &sb->region, size); +} + +static inline bool RegionBeforeOffset(const StreamingBufferRegion *r, const uint64_t o) +{ + return (r->stream_offset + r->buf_size <= o); +} + +static inline bool RegionContainsOffset(const StreamingBufferRegion *r, const uint64_t o) +{ + return (o >= r->stream_offset && (r->stream_offset + r->buf_size) >= o); +} + +/** \internal + * \brief slide to offset for regions + * + * + * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] + * ^ + * - main reset to 0 + * + * + * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] + * ^ + * - main shift + * + * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] + * ^ + * - main reset + * - move aux into main + * - free aux + * - shift + * + * [ main ] [ gap ] [ aux ] [ gap ] [ aux ] + * ^ + * - main reset + * - move aux into main + * - free aux + * - no shift + */ +static inline void StreamingBufferSlideToOffsetWithRegions( + StreamingBuffer *sb, const StreamingBufferConfig *cfg, const uint64_t slide_offset) +{ + ListRegions(sb); + DEBUG_VALIDATE_BUG_ON(slide_offset == sb->region.stream_offset); + + SCLogDebug("slide_offset %" PRIu64, slide_offset); + SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", sb->region.stream_offset, + sb->region.buf, sb->region.buf_size, sb->region.buf_offset); + + StreamingBufferRegion *to_shift = NULL; + const bool main_is_oow = RegionBeforeOffset(&sb->region, slide_offset); + if (main_is_oow) { + SCLogDebug("main_is_oow"); + if (sb->region.buf != NULL) { + SCLogDebug("clearing main"); + FREE(cfg, sb->region.buf, sb->region.buf_size); + sb->region.buf = NULL; + sb->region.buf_size = 0; + sb->region.buf_offset = 0; + sb->region.stream_offset = slide_offset; + } else { + sb->region.stream_offset = slide_offset; + } + + /* remove regions that are out of window & select the region to + * become the new main */ + StreamingBufferRegion *prev = &sb->region; + for (StreamingBufferRegion *r = sb->region.next; r != NULL;) { + SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64, r, r->stream_offset, + r->stream_offset + r->buf_offset); + StreamingBufferRegion *next = r->next; + if (RegionBeforeOffset(r, slide_offset)) { + SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> before", r, r->stream_offset, + r->stream_offset + r->buf_offset); + DEBUG_VALIDATE_BUG_ON(r == &sb->region); + prev->next = next; + + FREE(cfg, r->buf, r->buf_size); + FREE(cfg, r, sizeof(*r)); + sb->regions--; + DEBUG_VALIDATE_BUG_ON(sb->regions == 0); + } else if (RegionContainsOffset(r, slide_offset)) { + SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> within", r, r->stream_offset, + r->stream_offset + r->buf_offset); + /* remove from list, we will xfer contents to main below */ + prev->next = next; + to_shift = r; + break; + } else { + SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> post", r, r->stream_offset, + r->stream_offset + r->buf_offset); + /* implied beyond slide offset */ + DEBUG_VALIDATE_BUG_ON(r->stream_offset < slide_offset); + break; + } + r = next; + } + SCLogDebug("to_shift %p", to_shift); + } else { + to_shift = &sb->region; + SCLogDebug("shift start region %p", to_shift); + } + + // this region is main, or will xfer its buffer to main + if (to_shift) { + SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", to_shift->stream_offset, + to_shift->buf, to_shift->buf_size, to_shift->buf_offset); + if (to_shift != &sb->region) { + DEBUG_VALIDATE_BUG_ON(sb->region.buf != NULL); + + sb->region.buf = to_shift->buf; + sb->region.stream_offset = to_shift->stream_offset; + sb->region.buf_offset = to_shift->buf_offset; + sb->region.buf_size = to_shift->buf_size; + sb->region.next = to_shift->next; + + FREE(cfg, to_shift, sizeof(*to_shift)); + to_shift = &sb->region; + sb->regions--; + DEBUG_VALIDATE_BUG_ON(sb->regions == 0); + } + + // Do the shift. If new region is exactly at the slide offset we can skip this. + DEBUG_VALIDATE_BUG_ON(to_shift->stream_offset > slide_offset); + const uint32_t s = slide_offset - to_shift->stream_offset; + if (s > 0) { + const uint32_t new_data_size = to_shift->buf_size - s; + uint32_t new_mem_size = ToNextMultipleOf(new_data_size, cfg->buf_size); + + /* see if after the slide we'd overlap with the next region. If so, we need + * to consolidate them into one. Error handling is a bit peculiar. We need + * to grow a region, move data from another region into it, then free the + * other region. This could fail if we're close to the memcap. In this case + * we relax our rounding up logic so we only shrink and don't merge the 2 + * regions after all. */ + if (to_shift->next && slide_offset + new_mem_size >= to_shift->next->stream_offset) { + StreamingBufferRegion *start = to_shift; + StreamingBufferRegion *next = start->next; + const uint64_t next_re = next->stream_offset + next->buf_size; + const uint32_t mem_size = ToNextMultipleOf(next_re - slide_offset, cfg->buf_size); + + /* using next as the new main */ + if (start->buf_size < next->buf_size) { + SCLogDebug("replace main with the next bigger region"); + + const uint32_t next_data_offset = next->stream_offset - slide_offset; + const uint32_t prev_buf_size = next->buf_size; + const uint32_t start_data_offset = slide_offset - start->stream_offset; + DEBUG_VALIDATE_BUG_ON(start_data_offset > start->buf_size); + if (start_data_offset > start->buf_size) { + new_mem_size = new_data_size; + goto just_main; + } + /* expand "next" to include relevant part of "start" */ + if (GrowRegionToSize(sb, cfg, next, mem_size) != 0) { + new_mem_size = new_data_size; + goto just_main; + } + SCLogDebug("region now sized %u", mem_size); + + // slide "next": + // pre-grow: [nextnextnext] + // post-grow [nextnextnextXXX] + // post-move [XXXnextnextnext] + memmove(next->buf + next_data_offset, next->buf, prev_buf_size); + + // move portion of "start" into "next" + // + // start: [ooooookkkkk] (o: old, k: keep) + // pre-next [xxxxxnextnextnext] + // post-next [kkkkknextnextnext] + const uint32_t start_data_size = start->buf_size - start_data_offset; + memcpy(next->buf, start->buf + start_data_offset, start_data_size); + + // free "start"s buffer, we will use the one from "next" + FREE(cfg, start->buf, start->buf_size); + + // update "main" to use "next" + start->stream_offset = slide_offset; + start->buf = next->buf; + start->buf_size = next->buf_size; + start->next = next->next; + + // free "next" + FREE(cfg, next, sizeof(*next)); + sb->regions--; + DEBUG_VALIDATE_BUG_ON(sb->regions == 0); + goto done; + } else { + /* using "main", expand to include "next" */ + if (GrowRegionToSize(sb, cfg, start, mem_size) != 0) { + new_mem_size = new_data_size; + goto just_main; + } + SCLogDebug("start->buf now size %u", mem_size); + + // slide "start" + // pre: [xxxxxxxAAA] + // post: [AAAxxxxxxx] + SCLogDebug("s %u new_data_size %u", s, new_data_size); + memmove(start->buf, start->buf + s, new_data_size); + + // copy in "next" + // pre: [AAAxxxxxxx] + // [BBBBBBB] + // post: [AAABBBBBBB] + SCLogDebug("copy next->buf %p/%u to start->buf offset %u", next->buf, + next->buf_size, new_data_size); + memcpy(start->buf + new_data_size, next->buf, next->buf_size); + + start->stream_offset = slide_offset; + start->next = next->next; + + // free "next" + FREE(cfg, next->buf, next->buf_size); + FREE(cfg, next, sizeof(*next)); + sb->regions--; + DEBUG_VALIDATE_BUG_ON(sb->regions == 0); + goto done; + } + } + + just_main: + SCLogDebug("s %u new_data_size %u", s, new_data_size); + memmove(to_shift->buf, to_shift->buf + s, new_data_size); + /* shrink memory region. If this fails we keep the old */ + void *ptr = REALLOC(cfg, to_shift->buf, to_shift->buf_size, new_mem_size); + if (ptr != NULL) { + to_shift->buf = ptr; + to_shift->buf_size = new_mem_size; + SCLogDebug("new buf_size %u", to_shift->buf_size); + } + if (s < to_shift->buf_offset) + to_shift->buf_offset -= s; + else + to_shift->buf_offset = 0; + to_shift->stream_offset = slide_offset; + } + } + +done: + SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", sb->region.stream_offset, + sb->region.buf, sb->region.buf_size, sb->region.buf_offset); + SCLogDebug("end of slide"); +} + +/** + * \brief slide to absolute offset + * \todo if sliding beyond window, we could perhaps reset? + */ +void StreamingBufferSlideToOffset( + StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint64_t offset) +{ + SCLogDebug("sliding to offset %" PRIu64, offset); + ListRegions(sb); +#ifdef DEBUG + SBBPrintList(sb); +#endif + + if (sb->region.next) { + StreamingBufferSlideToOffsetWithRegions(sb, cfg, offset); + SBBPrune(sb, cfg); + SCLogDebug("post SBBPrune"); + ListRegions(sb); +#ifdef DEBUG + SBBPrintList(sb); +#endif + DEBUG_VALIDATE_BUG_ON(sb->region.buf != NULL && sb->region.buf_size == 0); + DEBUG_VALIDATE_BUG_ON(sb->region.buf_offset > sb->region.buf_size); + DEBUG_VALIDATE_BUG_ON(offset > sb->region.stream_offset); + DEBUG_VALIDATE_BUG_ON(sb->head && sb->head->offset == sb->region.stream_offset && + sb->head->len > sb->region.buf_offset); + DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset); + return; + } + + if (offset > sb->region.stream_offset) { + const uint32_t slide = offset - sb->region.stream_offset; + if (sb->head != NULL) { + /* have sbb's, so can't rely on buf_offset for the slide */ + if (slide < sb->region.buf_size) { + const uint32_t size = sb->region.buf_size - slide; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, + size); + memmove(sb->region.buf, sb->region.buf + slide, size); + if (sb->region.buf_offset > slide) { + sb->region.buf_offset -= slide; + } else { + sb->region.buf_offset = 0; + } + } else { + sb->region.buf_offset = 0; + } + sb->region.stream_offset = offset; + } else { + /* no sbb's, so we can use buf_offset */ + if (offset <= sb->region.stream_offset + sb->region.buf_offset) { + const uint32_t size = sb->region.buf_offset - slide; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, + size); + memmove(sb->region.buf, sb->region.buf + slide, size); + sb->region.stream_offset = offset; + sb->region.buf_offset = size; + } else { + /* moved past all data */ + sb->region.stream_offset = offset; + sb->region.buf_offset = 0; + } + } + SBBPrune(sb, cfg); + } +#ifdef DEBUG + SBBPrintList(sb); +#endif + DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset); +} + +#define DATA_FITS(sb, len) ((sb)->region.buf_offset + (len) <= (sb)->region.buf_size) + +int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len) +{ + DEBUG_VALIDATE_BUG_ON(seg == NULL); + + if (sb->region.buf == NULL) { + if (InitBuffer(sb, cfg) == -1) + return -1; + } + + if (!DATA_FITS(sb, data_len)) { + if (sb->region.buf_size == 0) { + if (GrowToSize(sb, cfg, data_len) != SC_OK) + return -1; + } else { + if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK) + return -1; + } + } + DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len)); + + memcpy(sb->region.buf + sb->region.buf_offset, data, data_len); + seg->stream_offset = sb->region.stream_offset + sb->region.buf_offset; + seg->segment_len = data_len; + uint32_t rel_offset = sb->region.buf_offset; + sb->region.buf_offset += data_len; + + if (!RB_EMPTY(&sb->sbb_tree)) { + return SBBUpdate(sb, cfg, &sb->region, rel_offset, data_len); + } else { + return 0; + } +} + +/** + * \brief add data w/o tracking a segment + */ +int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + const uint8_t *data, uint32_t data_len) +{ + if (sb->region.buf == NULL) { + if (InitBuffer(sb, cfg) == -1) + return -1; + } + + if (!DATA_FITS(sb, data_len)) { + if (sb->region.buf_size == 0) { + if (GrowToSize(sb, cfg, data_len) != SC_OK) + return -1; + } else { + if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK) + return -1; + } + } + DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len)); + + memcpy(sb->region.buf + sb->region.buf_offset, data, data_len); + uint32_t rel_offset = sb->region.buf_offset; + sb->region.buf_offset += data_len; + + if (!RB_EMPTY(&sb->sbb_tree)) { + return SBBUpdate(sb, cfg, &sb->region, rel_offset, data_len); + } else { + return 0; + } +} + +#define DATA_FITS_AT_OFFSET(region, len, offset) ((offset) + (len) <= (region)->buf_size) + +#if defined(DEBUG) || defined(DEBUG_VALIDATION) +static void Validate(const StreamingBuffer *sb) +{ + bool bail = false; + uint32_t cnt = 0; + for (const StreamingBufferRegion *r = &sb->region; r != NULL; r = r->next) { + cnt++; + if (r->next) { + bail |= ((r->stream_offset + r->buf_size) > r->next->stream_offset); + } + + bail |= (r->buf != NULL && r->buf_size == 0); + bail |= (r->buf_offset > r->buf_size); + } + // leading gap, so buf_offset should be 0? + if (sb->head && sb->head->offset > sb->region.stream_offset) { + SCLogDebug("leading gap of size %" PRIu64, sb->head->offset - sb->region.stream_offset); + BUG_ON(sb->region.buf_offset != 0); + } + + if (sb->head && sb->head->offset == sb->region.stream_offset) { + BUG_ON(sb->head->len > sb->region.buf_offset); + BUG_ON(sb->head->len < sb->region.buf_offset); + } + BUG_ON(sb->regions != cnt); + BUG_ON(bail); +} +#endif + +static void ListRegions(StreamingBuffer *sb) +{ + if (sb->region.buf == NULL && sb->region.buf_offset == 0 && sb->region.next == NULL) + return; +#if defined(DEBUG) && DUMP_REGIONS == 1 + uint32_t cnt = 0; + for (StreamingBufferRegion *r = &sb->region; r != NULL; r = r->next) { + cnt++; + char gap[64] = ""; + if (r->next) { + snprintf(gap, sizeof(gap), "[ gap:%" PRIu64 " ]", + r->next->stream_offset - (r->stream_offset + r->buf_size)); + } + + printf("[ %s offset:%" PRIu64 " size:%u offset:%u ]%s", r == &sb->region ? "main" : "aux", + r->stream_offset, r->buf_size, r->buf_offset, gap); + } + printf("(max %u, cnt %u, sb->regions %u)\n", sb->max_regions, cnt, sb->regions); + bool at_least_one = false; + uint64_t last_re = sb->region.stream_offset; + StreamingBufferBlock *sbb = NULL; + RB_FOREACH(sbb, SBB, &sb->sbb_tree) + { + if (last_re != sbb->offset) { + printf("[ gap:%" PRIu64 " ]", sbb->offset - last_re); + } + printf("[ sbb offset:%" PRIu64 " len:%u ]", sbb->offset, sbb->len); + at_least_one = true; + last_re = sbb->offset + sbb->len; + } + if (at_least_one) + printf("\n"); +#endif +#if defined(DEBUG) || defined(DEBUG_VALIDATION) + StreamingBufferBlock *sbb2 = NULL; + RB_FOREACH(sbb2, SBB, &sb->sbb_tree) + { + const uint8_t *_data = NULL; + uint32_t _data_len = 0; + (void)StreamingBufferSBBGetData(sb, sbb2, &_data, &_data_len); + } + Validate(sb); +#endif +} + +/** \internal + * \brief process insert by consolidating the affected regions into one + * \note sets sc_errno + */ +static StreamingBufferRegion *BufferInsertAtRegionConsolidate(StreamingBuffer *sb, + const StreamingBufferConfig *cfg, StreamingBufferRegion *dst, + StreamingBufferRegion *src_start, StreamingBufferRegion *src_end, + const uint64_t data_offset, const uint32_t data_len, StreamingBufferRegion *prev, + uint32_t dst_buf_size) +{ + int retval; +#ifdef DEBUG + const uint64_t data_re = data_offset + data_len; + SCLogDebug("sb %p dst %p src_start %p src_end %p data_offset %" PRIu64 + "/data_len %u/data_re %" PRIu64, + sb, dst, src_start, src_end, data_offset, data_len, data_re); +#endif + + // 1. determine size and offset for dst. + const uint64_t dst_offset = MIN(src_start->stream_offset, data_offset); + DEBUG_VALIDATE_BUG_ON(dst_offset < sb->region.stream_offset); + const uint32_t dst_size = dst_buf_size; + SCLogDebug("dst_size %u", dst_size); + + // 2. resize dst + const uint32_t old_size = dst->buf_size; + const uint32_t dst_copy_offset = dst->stream_offset - dst_offset; +#ifdef DEBUG + const uint32_t old_offset = dst->buf_offset; + SCLogDebug("old_size %u, old_offset %u, dst_copy_offset %u", old_size, old_offset, + dst_copy_offset); +#endif + if ((retval = GrowRegionToSize(sb, cfg, dst, dst_size)) != SC_OK) { + sc_errno = retval; + return NULL; + } + SCLogDebug("resized to %u -> %u", dst_size, dst->buf_size); + /* validate that the size is exactly what we asked for */ + DEBUG_VALIDATE_BUG_ON(dst_size != dst->buf_size); + if (dst_copy_offset != 0) + memmove(dst->buf + dst_copy_offset, dst->buf, old_size); + if (dst_offset != dst->stream_offset) { + dst->stream_offset = dst_offset; + // buf_offset no longer valid, reset. + dst->buf_offset = 0; + } + + uint32_t new_offset = src_start->buf_offset; + if (data_offset == src_start->stream_offset + src_start->buf_offset) { + new_offset += data_len; + } + + bool start_is_main = false; + if (src_start == &sb->region) { + DEBUG_VALIDATE_BUG_ON(src_start->stream_offset != dst_offset); + + start_is_main = true; + SCLogDebug("src_start is main region"); + if (src_start != dst) + memcpy(dst->buf, src_start->buf, src_start->buf_offset); + if (src_start == src_end) { + SCLogDebug("src_start == src_end == main, we're done"); + DEBUG_VALIDATE_BUG_ON(src_start != dst); + return src_start; + } + prev = src_start; + src_start = src_start->next; // skip in the loop below + } + + // 3. copy all regions from src_start to dst_start into the new region + for (StreamingBufferRegion *r = src_start; r != NULL;) { + SCLogDebug("r %p %" PRIu64 ", offset %u, len %u, %s, last %s", r, r->stream_offset, + r->buf_offset, r->buf_size, r == &sb->region ? "main" : "aux", + BOOL2STR(r == src_end)); + // skip dst + if (r == dst) { + SCLogDebug("skipping r %p as it is 'dst'", r); + if (r == src_end) + break; + prev = r; + r = r->next; + continue; + } + const uint32_t target_offset = r->stream_offset - dst_offset; + SCLogDebug("r %p: target_offset %u", r, target_offset); + DEBUG_VALIDATE_BUG_ON(target_offset > dst->buf_size); + DEBUG_VALIDATE_BUG_ON(target_offset + r->buf_size > dst->buf_size); + memcpy(dst->buf + target_offset, r->buf, r->buf_size); + + StreamingBufferRegion *next = r->next; + FREE(cfg, r->buf, r->buf_size); + FREE(cfg, r, sizeof(*r)); + sb->regions--; + DEBUG_VALIDATE_BUG_ON(sb->regions == 0); + + DEBUG_VALIDATE_BUG_ON(prev == NULL && src_start != &sb->region); + if (prev != NULL) { + SCLogDebug("setting prev %p next to %p (was %p)", prev, next, prev->next); + prev->next = next; + } else { + SCLogDebug("no prev yet"); + } + + if (r == src_end) + break; + r = next; + } + + /* special handling of main region being the start, but not the + * region we expand. In this case we'll have main and dst. We will + * move the buffer from dst into main and free dst. */ + if (start_is_main && dst != &sb->region) { + DEBUG_VALIDATE_BUG_ON(sb->region.next != dst); + SCLogDebug("start_is_main && dst != main region"); + FREE(cfg, sb->region.buf, sb->region.buf_size); + sb->region.buf = dst->buf; + sb->region.buf_size = dst->buf_size; + sb->region.buf_offset = new_offset; + SCLogDebug("sb->region.buf_offset set to %u", sb->region.buf_offset); + sb->region.next = dst->next; + FREE(cfg, dst, sizeof(*dst)); + dst = &sb->region; + sb->regions--; + DEBUG_VALIDATE_BUG_ON(sb->regions == 0); + } else { + SCLogDebug("dst: %p next %p", dst, dst->next); + } + + SCLogDebug("returning dst %p stream_offset %" PRIu64 " buf_offset %u buf_size %u", dst, + dst->stream_offset, dst->buf_offset, dst->buf_size); + return dst; +} + +/** \note sets sc_errno */ +static StreamingBufferRegion *BufferInsertAtRegionDo(StreamingBuffer *sb, + const StreamingBufferConfig *cfg, const uint64_t offset, const uint32_t len) +{ + SCLogDebug("offset %" PRIu64 ", len %u", offset, len); + StreamingBufferRegion *start_prev = NULL; + StreamingBufferRegion *start = + FindFirstRegionForOffset(sb, cfg, &sb->region, offset, len, &start_prev); + if (start) { + const uint64_t insert_re = offset + len; + const uint64_t insert_start_offset = MIN(start->stream_offset, offset); + uint64_t insert_adjusted_re = insert_re; + + SCLogDebug("start region %p/%" PRIu64 "/%u", start, start->stream_offset, start->buf_size); + StreamingBufferRegion *big = FindLargestRegionForOffset(sb, cfg, start, offset, len); + DEBUG_VALIDATE_BUG_ON(big == NULL); + if (big == NULL) { + sc_errno = SC_EINVAL; + return NULL; + } + SCLogDebug("big region %p/%" PRIu64 "/%u", big, big->stream_offset, big->buf_size); + StreamingBufferRegion *end = FindRightEdge(sb, cfg, big, offset, len); + DEBUG_VALIDATE_BUG_ON(end == NULL); + if (end == NULL) { + sc_errno = SC_EINVAL; + return NULL; + } + insert_adjusted_re = MAX(insert_adjusted_re, (end->stream_offset + end->buf_size)); + + uint32_t new_buf_size = + ToNextMultipleOf(insert_adjusted_re - insert_start_offset, cfg->buf_size); + SCLogDebug("new_buf_size %u", new_buf_size); + + /* see if our new buf size + cfg->buf_size margin leads to an overlap with the next region. + * If so, include that in the consolidation. */ + if (end->next != NULL && new_buf_size + insert_start_offset > end->next->stream_offset) { + SCLogDebug("adjusted end from %p to %p", end, end->next); + end = end->next; + insert_adjusted_re = MAX(insert_adjusted_re, (end->stream_offset + end->buf_size)); + new_buf_size = + ToNextMultipleOf(insert_adjusted_re - insert_start_offset, cfg->buf_size); + SCLogDebug("new_buf_size %u", new_buf_size); + } + + SCLogDebug("end region %p/%" PRIu64 "/%u", end, end->stream_offset, end->buf_size); + /* sets sc_errno */ + StreamingBufferRegion *ret = BufferInsertAtRegionConsolidate( + sb, cfg, big, start, end, offset, len, start_prev, new_buf_size); + return ret; + } else { + /* if there was no region we can use we add a new region and insert it */ + StreamingBufferRegion *append = &sb->region; + for (StreamingBufferRegion *r = append; r != NULL; r = r->next) { + if (r->stream_offset > offset) { + break; + } else { + append = r; + } + } + + SCLogDebug("no matching region found, append to %p (%s)", append, + append == &sb->region ? "main" : "aux"); + /* sets sc_errno */ + StreamingBufferRegion *add = InitBufferRegion(sb, cfg, len); + if (add == NULL) + return NULL; + add->stream_offset = offset; + add->next = append->next; + append->next = add; + SCLogDebug("new region %p offset %" PRIu64, add, add->stream_offset); + return add; + } +} + +/** \internal + * \brief return the region to put the new data in + * + * Will find an existing region, expand it if needed. If no existing region exists or is + * a good fit, it will try to set up a new region. If the region then overlaps or gets + * too close to the next, merge them. + * + * \note sets sc_errno + */ +static StreamingBufferRegion *BufferInsertAtRegion(StreamingBuffer *sb, + const StreamingBufferConfig *cfg, const uint8_t *data, const uint32_t data_len, + const uint64_t data_offset) +{ + SCLogDebug("data_offset %" PRIu64 ", data_len %u, re %" PRIu64, data_offset, data_len, + data_offset + data_len); + ListRegions(sb); + + if (RegionsIntersect(sb, cfg, &sb->region, data_offset, data_offset + data_len)) { + SCLogDebug("data_offset %" PRIu64 ", data_len %u intersects with main region (next %p)", + data_offset, data_len, sb->region.next); + if (sb->region.next == NULL || + !RegionsIntersect(sb, cfg, sb->region.next, data_offset, data_offset + data_len)) { + SCLogDebug( + "data_offset %" PRIu64 + ", data_len %u intersects with main region, no next or way before next region", + data_offset, data_len); + if (sb->region.buf == NULL) { + int r; + if ((r = InitBuffer(sb, cfg)) != SC_OK) { // TODO init with size + sc_errno = r; + return NULL; + } + } + return &sb->region; + } + } else if (sb->region.next == NULL) { + /* InitBufferRegion sets sc_errno */ + StreamingBufferRegion *aux_r = sb->region.next = InitBufferRegion(sb, cfg, data_len); + if (aux_r == NULL) + return NULL; + aux_r->stream_offset = data_offset; + DEBUG_VALIDATE_BUG_ON(data_len > aux_r->buf_size); + SCLogDebug("created new region %p with offset %" PRIu64 ", size %u", aux_r, + aux_r->stream_offset, aux_r->buf_size); + return aux_r; + } + /* BufferInsertAtRegionDo sets sc_errno */ + StreamingBufferRegion *blob = BufferInsertAtRegionDo(sb, cfg, data_offset, data_len); + SCLogDebug("blob %p (%s)", blob, blob == &sb->region ? "main" : "aux"); + return blob; +} + +/** + * \param offset offset relative to StreamingBuffer::stream_offset + * + * \return SC_OK in case of success + * \return SC_E* errors otherwise + */ +int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, uint64_t offset) +{ + int r; + + DEBUG_VALIDATE_BUG_ON(seg == NULL); + DEBUG_VALIDATE_BUG_ON(offset < sb->region.stream_offset); + if (offset < sb->region.stream_offset) { + return SC_EINVAL; + } + + StreamingBufferRegion *region = BufferInsertAtRegion(sb, cfg, data, data_len, offset); + if (region == NULL) { + return sc_errno; + } + + const bool region_is_main = region == &sb->region; + + SCLogDebug("inserting %" PRIu64 "/%u using %s region %p", offset, data_len, + region == &sb->region ? "main" : "aux", region); + + uint32_t rel_offset = offset - region->stream_offset; + if (!DATA_FITS_AT_OFFSET(region, data_len, rel_offset)) { + if ((r = GrowToSize(sb, cfg, (rel_offset + data_len))) != SC_OK) + return r; + } + DEBUG_VALIDATE_BUG_ON(!DATA_FITS_AT_OFFSET(region, data_len, rel_offset)); + + SCLogDebug("offset %" PRIu64 " data_len %u, rel_offset %u into region offset %" PRIu64 + ", buf_offset %u, buf_size %u", + offset, data_len, rel_offset, region->stream_offset, region->buf_offset, + region->buf_size); + memcpy(region->buf + rel_offset, data, data_len); + seg->stream_offset = offset; + seg->segment_len = data_len; + + SCLogDebug("rel_offset %u region->stream_offset %" PRIu64 ", buf_offset %u", rel_offset, + region->stream_offset, region->buf_offset); + + if (RB_EMPTY(&sb->sbb_tree)) { + SCLogDebug("empty sbb list"); + + if (region_is_main) { + if (sb->region.stream_offset == offset) { + SCLogDebug("empty sbb list: block exactly what was expected, fall through"); + /* empty list, data is exactly what is expected (append), + * so do nothing. + * Update buf_offset if needed, but in case of overlaps it might be beyond us. */ + sb->region.buf_offset = MAX(sb->region.buf_offset, rel_offset + data_len); + } else if ((rel_offset + data_len) <= sb->region.buf_offset) { + SCLogDebug("empty sbb list: block is within existing main data region"); + } else { + if (sb->region.buf_offset && rel_offset == sb->region.buf_offset) { + SCLogDebug("exactly at expected offset"); + // nothing to do + sb->region.buf_offset = rel_offset + data_len; + + } else if (rel_offset < sb->region.buf_offset) { + // nothing to do + + SCLogDebug("before expected offset: %u < sb->region.buf_offset %u", rel_offset, + sb->region.buf_offset); + if (rel_offset + data_len > sb->region.buf_offset) { + SCLogDebug("before expected offset, ends after: %u < sb->region.buf_offset " + "%u, %u > %u", + rel_offset, sb->region.buf_offset, rel_offset + data_len, + sb->region.buf_offset); + sb->region.buf_offset = rel_offset + data_len; + } + + } else if (sb->region.buf_offset) { + SCLogDebug("beyond expected offset: SBBInit"); + /* existing data, but there is a gap between us */ + if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK) + return r; + } else { + /* gap before data in empty list */ + SCLogDebug("empty sbb list: invoking SBBInitLeadingGap"); + if ((r = SBBInitLeadingGap(sb, cfg, region, offset, data_len)) != SC_OK) + return r; + } + } + } else { + if (sb->region.buf_offset) { + /* existing data, but there is a gap between us */ + SCLogDebug("empty sbb list, no data in main: use SBBInit"); + if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK) + return r; + } else { + /* gap before data in empty list */ + SCLogDebug("empty sbb list: invoking SBBInitLeadingGap"); + if ((r = SBBInitLeadingGap(sb, cfg, region, offset, data_len)) != SC_OK) + return r; + } + if (rel_offset == region->buf_offset) { + SCLogDebug("pre region->buf_offset %u", region->buf_offset); + region->buf_offset = rel_offset + data_len; + SCLogDebug("post region->buf_offset %u", region->buf_offset); + } + } + } else { + SCLogDebug("updating sbb tree"); + /* already have blocks, so append new block based on new data */ + if ((r = SBBUpdate(sb, cfg, region, rel_offset, data_len)) != SC_OK) + return r; + } + DEBUG_VALIDATE_BUG_ON(!region_is_main && sb->head == NULL); + + ListRegions(sb); + if (RB_EMPTY(&sb->sbb_tree)) { + DEBUG_VALIDATE_BUG_ON(offset + data_len > sb->region.stream_offset + sb->region.buf_offset); + } + + return SC_OK; +} + +int StreamingBufferSegmentIsBeforeWindow( + const StreamingBuffer *sb, const StreamingBufferSegment *seg) +{ + if (seg->stream_offset < sb->region.stream_offset) { + if (seg->stream_offset + seg->segment_len <= sb->region.stream_offset) { + return 1; + } + } + return 0; +} + +static inline const StreamingBufferRegion *GetRegionForOffset( + const StreamingBuffer *sb, const uint64_t offset) +{ + if (sb == NULL) + return NULL; + if (sb->region.next == NULL) { + return &sb->region; + } + if (offset >= sb->region.stream_offset && + offset < (sb->region.stream_offset + sb->region.buf_size)) { + return &sb->region; + } + for (const StreamingBufferRegion *r = sb->region.next; r != NULL; r = r->next) { + if (offset >= r->stream_offset && offset < (r->stream_offset + r->buf_size)) { + return r; + } + } + return NULL; +} + +/** \brief get the data for one SBB */ +void StreamingBufferSBBGetData(const StreamingBuffer *sb, const StreamingBufferBlock *sbb, + const uint8_t **data, uint32_t *data_len) +{ + const StreamingBufferRegion *region = GetRegionForOffset(sb, sbb->offset); + SCLogDebug("first find our region (offset %" PRIu64 ") -> %p", sbb->offset, region); + if (region) { + SCLogDebug("region %p found %" PRIu64 "/%u/%u", region, region->stream_offset, + region->buf_size, region->buf_offset); + DEBUG_VALIDATE_BUG_ON( + region->stream_offset == sbb->offset && region->buf_offset > sbb->len); + // buf_offset should match first sbb len if it has the same offset + + if (sbb->offset >= region->stream_offset) { + SCLogDebug("1"); + uint64_t offset = sbb->offset - region->stream_offset; + *data = region->buf + offset; + DEBUG_VALIDATE_BUG_ON(offset + sbb->len > region->buf_size); + *data_len = sbb->len; + return; + } else { + SCLogDebug("2"); + uint64_t offset = region->stream_offset - sbb->offset; + if (offset < sbb->len) { + *data = region->buf; + *data_len = sbb->len - offset; + return; + } + SCLogDebug("3"); + } + } + *data = NULL; + *data_len = 0; + return; +} + +/** \brief get the data for one SBB */ +void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb, const StreamingBufferBlock *sbb, + const uint8_t **data, uint32_t *data_len, uint64_t offset) +{ + /* validate that we are looking for a offset within the sbb */ + DEBUG_VALIDATE_BUG_ON(!(offset >= sbb->offset && offset < (sbb->offset + sbb->len))); + if (!(offset >= sbb->offset && offset < (sbb->offset + sbb->len))) { + *data = NULL; + *data_len = 0; + return; + } + + const StreamingBufferRegion *region = GetRegionForOffset(sb, offset); + if (region) { + uint32_t sbblen = sbb->len - (offset - sbb->offset); + + if (offset >= region->stream_offset) { + uint64_t data_offset = offset - region->stream_offset; + *data = region->buf + data_offset; + if (data_offset + sbblen > region->buf_size) + *data_len = region->buf_size - data_offset; + else + *data_len = sbblen; + DEBUG_VALIDATE_BUG_ON(*data_len > sbblen); + return; + } else { + uint64_t data_offset = region->stream_offset - sbb->offset; + if (data_offset < sbblen) { + *data = region->buf; + *data_len = sbblen - data_offset; + DEBUG_VALIDATE_BUG_ON(*data_len > sbblen); + return; + } + } + } + + *data = NULL; + *data_len = 0; + return; +} + +void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, + const uint8_t **data, uint32_t *data_len) +{ + const StreamingBufferRegion *region = GetRegionForOffset(sb, seg->stream_offset); + if (region) { + if (seg->stream_offset >= region->stream_offset) { + uint64_t offset = seg->stream_offset - region->stream_offset; + *data = region->buf + offset; + if (offset + seg->segment_len > region->buf_size) + *data_len = region->buf_size - offset; + else + *data_len = seg->segment_len; + SCLogDebug("*data_len %u", *data_len); + return; + } else { + uint64_t offset = region->stream_offset - seg->stream_offset; + if (offset < seg->segment_len) { + *data = region->buf; + *data_len = seg->segment_len - offset; + SCLogDebug("*data_len %u", *data_len); + return; + } + } + } + *data = NULL; + *data_len = 0; + return; +} + +/** + * \retval 1 data is the same + * \retval 0 data is different + */ +int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, const uint8_t *rawdata, uint32_t rawdata_len) +{ + const uint8_t *segdata = NULL; + uint32_t segdata_len = 0; + StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len); + if (segdata && segdata_len && segdata_len == rawdata_len && + memcmp(segdata, rawdata, segdata_len) == 0) { + return 1; + } + return 0; +} + +int StreamingBufferGetData(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, + uint64_t *stream_offset) +{ + if (sb != NULL && sb->region.buf != NULL) { + *data = sb->region.buf; + *data_len = sb->region.buf_offset; + *stream_offset = sb->region.stream_offset; + return 1; + } else { + *data = NULL; + *data_len = 0; + *stream_offset = 0; + return 0; + } +} + +int StreamingBufferGetDataAtOffset( + const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset) +{ + const StreamingBufferRegion *region = GetRegionForOffset(sb, offset); + if (region != NULL && region->buf != NULL && offset >= region->stream_offset && + offset < (region->stream_offset + region->buf_offset)) { + uint32_t skip = offset - region->stream_offset; + *data = region->buf + skip; + *data_len = region->buf_offset - skip; + return 1; + } else { + *data = NULL; + *data_len = 0; + return 0; + } +} + +/** + * \retval 1 data is the same + * \retval 0 data is different + */ +int StreamingBufferCompareRawData( + const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len) +{ + const uint8_t *sbdata = NULL; + uint32_t sbdata_len = 0; + uint64_t offset = 0; + StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset); + if (offset == 0 && sbdata && sbdata_len && sbdata_len == rawdata_len && + memcmp(sbdata, rawdata, sbdata_len) == 0) { + return 1; + } + SCLogDebug("sbdata_len %u, offset %" PRIu64, sbdata_len, offset); + printf("got:\n"); + PrintRawDataFp(stdout, sbdata, sbdata_len); + printf("wanted:\n"); + PrintRawDataFp(stdout, rawdata, rawdata_len); + return 0; +} + +#ifdef UNITTESTS +static void Dump(StreamingBuffer *sb) +{ + PrintRawDataFp(stdout, sb->region.buf, sb->region.buf_offset); +} + +static void DumpSegment(StreamingBuffer *sb, StreamingBufferSegment *seg) +{ + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(sb, seg, &data, &data_len); + if (data && data_len) { + PrintRawDataFp(stdout, data, data_len); + } +} + +static int StreamingBufferTest02(void) +{ + StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8) != 0); + FAIL_IF(sb->region.stream_offset != 0); + FAIL_IF(sb->region.buf_offset != 16); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + FAIL_IF_NOT_NULL(sb->head); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSlideToOffset(sb, &cfg, 6); + FAIL_IF_NOT_NULL(sb->head); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6) != 0); + FAIL_IF(sb->region.stream_offset != 6); + FAIL_IF(sb->region.buf_offset != 16); + FAIL_IF(seg3.stream_offset != 16); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + FAIL_IF_NOT_NULL(sb->head); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSlideToOffset(sb, &cfg, 12); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + FAIL_IF_NOT_NULL(sb->head); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +static int StreamingBufferTest03(void) +{ + StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); + FAIL_IF(sb->region.stream_offset != 0); + FAIL_IF(sb->region.buf_offset != 8); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 14); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 16); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); + FAIL_IF(sb->region.stream_offset != 0); + FAIL_IF(sb->region.buf_offset != 22); + FAIL_IF(seg3.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 22); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSlideToOffset(sb, &cfg, 10); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 12); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +static int StreamingBufferTest04(void) +{ + StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); + FAIL_IF(!RB_EMPTY(&sb->sbb_tree)); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); + FAIL_IF(sb->region.stream_offset != 0); + FAIL_IF(sb->region.buf_offset != 8); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 14); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + FAIL_IF(RB_EMPTY(&sb->sbb_tree)); + StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF(sbb1 != sb->head); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 8); + StreamingBufferBlock *sbb2 = SBB_RB_NEXT(sbb1); + FAIL_IF_NULL(sbb2); + FAIL_IF(sbb2 == sb->head); + FAIL_IF(sbb2->offset != 14); + FAIL_IF(sbb2->len != 8); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); + FAIL_IF(sb->region.stream_offset != 0); + FAIL_IF(sb->region.buf_offset != 22); + FAIL_IF(seg3.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg3)); + sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1 != sb->head); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 22); + FAIL_IF(SBB_RB_NEXT(sbb1)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 22); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + /* far ahead of curve: */ + StreamingBufferSegment seg4; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"XYZ", 3, 124) != 0); + FAIL_IF(sb->region.stream_offset != 0); + FAIL_IF(sb->region.buf_offset != 22); + FAIL_IF(sb->region.buf_size != 128); + FAIL_IF(seg4.stream_offset != 124); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb, &seg4)); + sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1 != sb->head); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 22); + FAIL_IF(!SBB_RB_NEXT(sbb1)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + DumpSegment(sb, &seg4); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 25); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb, &seg2, (const uint8_t *)"01234567", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb, &seg3, (const uint8_t *)"QWERTY", 6)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb, &seg4, (const uint8_t *)"XYZ", 3)); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +/** \test lots of gaps in block list */ +static int StreamingBufferTest06(void) +{ + StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"A", 1) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"C", 1, 2) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 2); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 3); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg4; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 4); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg5; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); + Dump(sb); + StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg6; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0); + Dump(sb); + sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +/** \test lots of gaps in block list */ +static int StreamingBufferTest07(void) +{ + StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 2); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 3); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg4; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 4); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg5; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); + Dump(sb); + StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg6; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0); + Dump(sb); + sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +/** \test lots of gaps in block list */ +static int StreamingBufferTest08(void) +{ + StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 2); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 3); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg4; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 4); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg5; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); + Dump(sb); + StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg6; + FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10) != 0); + Dump(sb); + sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 20); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 20); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +/** \test lots of gaps in block list */ +static int StreamingBufferTest09(void) +{ + StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 2); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"H", 1, 7) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 3); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg4; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"F", 1, 5) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 4); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg5; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); + Dump(sb); + StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferSegment seg6; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0); + Dump(sb); + sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +/** \test lots of gaps in block list */ +static int StreamingBufferTest10(void) +{ + StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"A", 1, 0) != 0); + Dump(sb); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0); + Dump(sb); + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"H", 1, 7) != 0); + Dump(sb); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 3); + + StreamingBufferSegment seg4; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"B", 1, 1) != 0); + Dump(sb); + StreamingBufferSegment seg5; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"C", 1, 2) != 0); + Dump(sb); + StreamingBufferSegment seg6; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"G", 1, 6) != 0); + Dump(sb); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 6); + + StreamingBufferSegment seg7; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg7, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0); + Dump(sb); + StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + + StreamingBufferSegment seg8; + FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg8, (const uint8_t *)"abcdefghij", 10, 0) != 0); + Dump(sb); + sbb1 = RB_MIN(SBB, &sb->sbb_tree); + FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree)); + FAIL_IF_NULL(sbb1); + FAIL_IF(sbb1->offset != 0); + FAIL_IF(sbb1->len != 10); + FAIL_IF(SBB_RB_NEXT(sbb1)); + FAIL_IF_NULL(sb->head); + FAIL_IF_NOT(sb->sbb_size == 10); + + StreamingBufferFree(sb, &cfg); + PASS; +} + +#endif + +void StreamingBufferRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02); + UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03); + UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04); + UtRegisterTest("StreamingBufferTest06", StreamingBufferTest06); + UtRegisterTest("StreamingBufferTest07", StreamingBufferTest07); + UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08); + UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09); + UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10); +#endif +} diff --git a/src/util/streaming-buffer.h b/src/util/streaming-buffer.h new file mode 100644 index 000000000000..a766dd6c6b12 --- /dev/null +++ b/src/util/streaming-buffer.h @@ -0,0 +1,195 @@ +/* Copyright (C) 2015-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * This API is meant to be used with streaming data. A single memory + * block is used to store the data. StreamingBufferSegment points to + * chunk of data in the single StreamingBuffer. It points by offset + * and length, so no pointers. The buffer is resized on demand and + * slides forward, either automatically or manually. + * + * When a segment needs it's data it uses StreamingBufferSegmentGetData + * which takes care of checking if the segment still has a valid offset + * and length. + * + * The StreamingBuffer::stream_offset is an absolute offset since the + * start of the data streaming. + * + * Similarly, StreamingBufferSegment::stream_offset is also an absolute + * offset. + * + * Using the segments is optional. + * + * + * stream_offset buf_offset stream_offset + buf_size + * ^ ^ ^ + * | | | + * | | | + * +--------------------------------------------+ + * | data | empty | + * | xxxxxxxxxx | | + * +------^--------^--------+-------------------+ + * | | + * | | + * | | + * | | + * | | + * +------+--------+-------+ + * | StreamingBufferSegment| + * +-----------+-----------+ + * | offset | len | + * +-----------+-----------+ + */ + +#ifndef __UTIL_STREAMING_BUFFER_H__ +#define __UTIL_STREAMING_BUFFER_H__ + +#include "tree.h" + +#define STREAMING_BUFFER_REGION_GAP_DEFAULT 262144 + +typedef struct StreamingBufferConfig_ { + uint32_t buf_size; + uint16_t max_regions; /**< max concurrent memory regions. 0 means no limit. */ + uint32_t region_gap; /**< max gap size before a new region will be created. */ + void *(*Calloc)(size_t n, size_t size); + void *(*Realloc)(void *ptr, size_t orig_size, size_t size); + void (*Free)(void *ptr, size_t size); +} StreamingBufferConfig; + +#define STREAMING_BUFFER_CONFIG_INITIALIZER \ + { \ + 2048, 8, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL, \ + } + +#define STREAMING_BUFFER_REGION_INIT \ + { \ + NULL, 0, 0, 0ULL, NULL, \ + } + +typedef struct StreamingBufferRegion_ { + uint8_t *buf; /**< memory block for reassembly */ + uint32_t buf_size; /**< size of memory block */ + uint32_t buf_offset; /**< how far we are in buf_size */ + uint64_t stream_offset; /**< stream offset of this region */ + struct StreamingBufferRegion_ *next; +} StreamingBufferRegion; + +/** + * \brief block of continues data + */ +typedef struct StreamingBufferBlock { + uint64_t offset; + RB_ENTRY(StreamingBufferBlock) rb; + uint32_t len; +} __attribute__((__packed__)) StreamingBufferBlock; + +int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b); + +/* red-black tree prototype for SACK records */ +RB_HEAD(SBB, StreamingBufferBlock); +RB_PROTOTYPE(SBB, StreamingBufferBlock, rb, SBBCompare); +StreamingBufferBlock *SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm); + +typedef struct StreamingBuffer_ { + StreamingBufferRegion region; + struct SBB sbb_tree; /**< red black tree of Stream Buffer Blocks */ + StreamingBufferBlock *head; /**< head, should always be the same as RB_MIN */ + uint32_t sbb_size; /**< data size covered by sbbs */ + uint16_t regions; + uint16_t max_regions; +#ifdef DEBUG + uint32_t buf_size_max; +#endif +} StreamingBuffer; + +static inline bool StreamingBufferHasData(const StreamingBuffer *sb) +{ + return (sb->region.stream_offset || sb->region.buf_offset || sb->region.next != NULL || + !RB_EMPTY(&sb->sbb_tree)); +} + +static inline uint64_t StreamingBufferGetConsecutiveDataRightEdge(const StreamingBuffer *sb) +{ + return sb->region.stream_offset + sb->region.buf_offset; +} + +static inline uint64_t StreamingBufferGetOffset(const StreamingBuffer *sb) +{ + return sb->region.stream_offset; +} + +#ifndef DEBUG +#define STREAMING_BUFFER_INITIALIZER \ + { \ + STREAMING_BUFFER_REGION_INIT, \ + { NULL }, \ + NULL, \ + 0, \ + 1, \ + 1, \ + }; +#else +#define STREAMING_BUFFER_INITIALIZER { STREAMING_BUFFER_REGION_INIT, { NULL }, NULL, 0, 1, 1, 0 }; +#endif + +typedef struct StreamingBufferSegment_ { + uint32_t segment_len; + uint64_t stream_offset; +} __attribute__((__packed__)) StreamingBufferSegment; + +StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg); +void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg); +void StreamingBufferFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg); + +void StreamingBufferSlideToOffset( + StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint64_t offset); + +int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len) WARN_UNUSED; +int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + const uint8_t *data, uint32_t data_len) WARN_UNUSED; +int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg, + StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, + uint64_t offset) WARN_UNUSED; + +void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, + const uint8_t **data, uint32_t *data_len); + +void StreamingBufferSBBGetData(const StreamingBuffer *sb, const StreamingBufferBlock *sbb, + const uint8_t **data, uint32_t *data_len); + +void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb, const StreamingBufferBlock *sbb, + const uint8_t **data, uint32_t *data_len, uint64_t offset); + +int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, const uint8_t *rawdata, uint32_t rawdata_len); +int StreamingBufferCompareRawData( + const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len); + +int StreamingBufferGetData(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, + uint64_t *stream_offset); + +int StreamingBufferGetDataAtOffset( + const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset); + +int StreamingBufferSegmentIsBeforeWindow( + const StreamingBuffer *sb, const StreamingBufferSegment *seg); + +void StreamingBufferRegisterTests(void); + +#endif /* __UTIL_STREAMING_BUFFER_H__ */ diff --git a/src/util/strlcatu.c b/src/util/strlcatu.c new file mode 100644 index 000000000000..d3665b4ebbe3 --- /dev/null +++ b/src/util/strlcatu.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1998 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id: strlcatu.c,v 1.4 2003/10/20 15:03:27 chrisgreen Exp $ */ + +#include "suricata-common.h" + +#ifndef HAVE_STRLCAT + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcat.c,v 1.5 2001/01/13 16:17:24 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(initial dst) + strlen(src); if retval >= siz, + * truncation occurred. + */ +size_t strlcat(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return (dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return (dlen + (s - src)); /* count does not include NUL */ +} +#endif diff --git a/src/util/strlcpyu.c b/src/util/strlcpyu.c new file mode 100644 index 000000000000..e0dc54823181 --- /dev/null +++ b/src/util/strlcpyu.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1998 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id: strlcpyu.c,v 1.4 2003/10/20 15:03:27 chrisgreen Exp $ */ + +#include "suricata-common.h" + +#ifndef HAVE_STRLCPY + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return (s - src - 1); /* count does not include NUL */ +} +#endif diff --git a/src/util/strptime.c b/src/util/strptime.c new file mode 100644 index 000000000000..55a4b19eeed0 --- /dev/null +++ b/src/util/strptime.c @@ -0,0 +1,582 @@ +/* $NetBSD: strptime.c,v 1.36 2012/03/13 21:13:48 christos Exp $ */ + +/*- + * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Klaus Klein. + * Heavily optimised by David Laight + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* +#include +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: strptime.c,v 1.36 2012/03/13 21:13:48 christos Exp $"); +#endif + +#include "namespace.h" +#include +*/ +#include "suricata-common.h" +#ifndef HAVE_STRPTIME +#include +#include +#include +#include +#include +/* +#include +#include "private.h" + +#ifdef __weak_alias +__weak_alias(strptime,_strptime) +#endif +*/ + +#define _ctloc(x) (_CurrentTimeLocale->x) + +/* + * We do not implement alternate representations. However, we always + * check whether a given modifier is allowed for a certain conversion. + */ +#define ALT_E 0x01 +#define ALT_O 0x02 +#define LEGAL_ALT(x) \ + { \ + if (alt_format & ~(x)) \ + return NULL; \ + } + +static int TM_YEAR_BASE = 1900; +static char gmt[] = { "GMT" }; +static char utc[] = { "UTC" }; +/* RFC-822/RFC-2822 */ +static const char *const nast[5] = { "EST", "CST", "MST", "PST", "\0\0\0" }; +static const char *const nadt[5] = { "EDT", "CDT", "MDT", "PDT", "\0\0\0" }; +static const char *const am_pm[2] = { "am", "pm" }; +static const char *const day[7] = { "sunday", "monday", "tuesday", "wednesday", "thursday", + "friday", "saturday" }; +static const char *const abday[7] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; +static const char *const mon[12] = { "january", "february", "march", "april", "may", "june", "july", + "august", "september", "october", "november", "december" }; +static const char *const abmon[12] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", + "sep", "oct", "nov", "dec" }; + +static const u_char *conv_num(const unsigned char *, int *, unsigned int, unsigned int); +static const u_char *find_string( + const u_char *, int *, const char *const *, const char *const *, int); + +char *strptime(const char *buf, const char *fmt, struct tm *tm) +{ + unsigned char c; + const unsigned char *bp, *ep; + int alt_format, i, split_year = 0, neg = 0, offs; + const char *new_fmt; + + bp = (const u_char *)buf; + + while (bp != NULL && (c = *fmt++) != '\0') { + /* Clear `alternate' modifier prior to new conversion. */ + alt_format = 0; + i = 0; + + /* Eat up white-space. */ + if (isspace(c)) { + while (isspace(*bp)) + bp++; + continue; + } + + if (c != '%') + goto literal; + + again: + switch (c = *fmt++) { + case '%': /* "%%" is converted to "%". */ + literal: + if (c != *bp++) + return NULL; + LEGAL_ALT(0); + continue; + + /* + * "Alternative" modifiers. Just set the appropriate flag + * and start over again. + */ + case 'E': /* "%E?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_E; + goto again; + + case 'O': /* "%O?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_O; + goto again; + + /* + * "Complex" conversion rules, implemented through recursion. + */ + /* we do not need 'c' + case 'c': Date and time, using the locale's format. + new_fmt = _ctloc(d_t_fmt); + goto recurse; + */ + + case 'D': /* The date as "%m/%d/%y". */ + new_fmt = "%m/%d/%y"; + LEGAL_ALT(0); + goto recurse; + + case 'F': /* The date as "%Y-%m-%d". */ + new_fmt = "%Y-%m-%d"; + LEGAL_ALT(0); + goto recurse; + + case 'R': /* The time as "%H:%M". */ + new_fmt = "%H:%M"; + LEGAL_ALT(0); + goto recurse; + + case 'r': /* The time in 12-hour clock representation. */ + new_fmt = "%I:%M:S %p"; //_ctloc(t_fmt_ampm); + LEGAL_ALT(0); + goto recurse; + + case 'T': /* The time as "%H:%M:%S". */ + new_fmt = "%H:%M:%S"; + LEGAL_ALT(0); + goto recurse; + + /* we don't use 'X' + case 'X': The time, using the locale's format. + new_fmt =_ctloc(t_fmt); + goto recurse; + */ + + /* we do not need 'x' + case 'x': The date, using the locale's format. + new_fmt =_ctloc(d_fmt);*/ + recurse: + bp = (const u_char *)strptime((const char *)bp, new_fmt, tm); + LEGAL_ALT(ALT_E); + continue; + + /* + * "Elementary" conversion rules. + */ + case 'A': /* The day of week, using the locale's form. */ + case 'a': + bp = find_string(bp, &tm->tm_wday, day, abday, 7); + LEGAL_ALT(0); + continue; + + case 'B': /* The month, using the locale's form. */ + case 'b': + case 'h': + bp = find_string(bp, &tm->tm_mon, mon, abmon, 12); + LEGAL_ALT(0); + continue; + + case 'C': /* The century number. */ + i = 20; + bp = conv_num(bp, &i, 0, 99); + + i = i * 100 - TM_YEAR_BASE; + if (split_year) + i += tm->tm_year % 100; + split_year = 1; + tm->tm_year = i; + LEGAL_ALT(ALT_E); + continue; + + case 'd': /* The day of month. */ + case 'e': + bp = conv_num(bp, &tm->tm_mday, 1, 31); + LEGAL_ALT(ALT_O); + continue; + + case 'k': /* The hour (24-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'H': + bp = conv_num(bp, &tm->tm_hour, 0, 23); + LEGAL_ALT(ALT_O); + continue; + + case 'l': /* The hour (12-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'I': + bp = conv_num(bp, &tm->tm_hour, 1, 12); + if (tm->tm_hour == 12) + tm->tm_hour = 0; + LEGAL_ALT(ALT_O); + continue; + + case 'j': /* The day of year. */ + i = 1; + bp = conv_num(bp, &i, 1, 366); + tm->tm_yday = i - 1; + LEGAL_ALT(0); + continue; + + case 'M': /* The minute. */ + bp = conv_num(bp, &tm->tm_min, 0, 59); + LEGAL_ALT(ALT_O); + continue; + + case 'm': /* The month. */ + i = 1; + bp = conv_num(bp, &i, 1, 12); + tm->tm_mon = i - 1; + LEGAL_ALT(ALT_O); + continue; + + case 'p': /* The locale's equivalent of AM/PM. */ + bp = find_string(bp, &i, am_pm, NULL, 2); + if (tm->tm_hour > 11) + return NULL; + tm->tm_hour += i * 12; + LEGAL_ALT(0); + continue; + + case 'S': /* The seconds. */ + bp = conv_num(bp, &tm->tm_sec, 0, 61); + LEGAL_ALT(ALT_O); + continue; + +#ifndef TIME_MAX +#define TIME_MAX INT64_MAX +#endif + case 's': /* seconds since the epoch */ + { + time_t sse = 0; + uint64_t rulim = TIME_MAX; + + if (*bp < '0' || *bp > '9') { + bp = NULL; + continue; + } + + do { + sse *= 10; + sse += *bp++ - '0'; + rulim /= 10; + } while (((uint64_t)sse * 10 <= TIME_MAX) && rulim && *bp >= '0' && *bp <= '9'); + + if (sse < 0 || (uint64_t)sse > TIME_MAX) { + bp = NULL; + continue; + } + + tm = localtime(&sse); + if (tm == NULL) + bp = NULL; + } + continue; + + case 'U': /* The week of year, beginning on sunday. */ + case 'W': /* The week of year, beginning on monday. */ + /* + * XXX This is bogus, as we can not assume any valid + * information present in the tm structure at this + * point to calculate a real value, so just check the + * range for now. + */ + bp = conv_num(bp, &i, 0, 53); + LEGAL_ALT(ALT_O); + continue; + + case 'w': /* The day of week, beginning on sunday. */ + bp = conv_num(bp, &tm->tm_wday, 0, 6); + LEGAL_ALT(ALT_O); + continue; + + case 'u': /* The day of week, monday = 1. */ + bp = conv_num(bp, &i, 1, 7); + tm->tm_wday = i % 7; + LEGAL_ALT(ALT_O); + continue; + + case 'g': /* The year corresponding to the ISO week + * number but without the century. + */ + bp = conv_num(bp, &i, 0, 99); + continue; + + case 'G': /* The year corresponding to the ISO week + * number with century. + */ + do + bp++; + while (isdigit(*bp)); + continue; + + case 'V': /* The ISO 8601:1988 week number as decimal */ + bp = conv_num(bp, &i, 0, 53); + continue; + + case 'Y': /* The year. */ + i = TM_YEAR_BASE; /* just for data sanity... */ + bp = conv_num(bp, &i, 0, 9999); + tm->tm_year = i - TM_YEAR_BASE; + LEGAL_ALT(ALT_E); + continue; + + case 'y': /* The year within 100 years of the epoch. */ + /* LEGAL_ALT(ALT_E | ALT_O); */ + bp = conv_num(bp, &i, 0, 99); + + if (split_year) + /* preserve century */ + i += (tm->tm_year / 100) * 100; + else { + split_year = 1; + if (i <= 68) + i = i + 2000 - TM_YEAR_BASE; + else + i = i + 1900 - TM_YEAR_BASE; + } + tm->tm_year = i; + continue; + + case 'Z': + tzset(); + if (strncasecmp((const char *)bp, gmt, 3) == 0 || + strncasecmp((const char *)bp, utc, 3) == 0) { + tm->tm_isdst = 0; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = 0; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = gmt; +#endif + bp += 3; + } else { + ep = find_string(bp, &i, (const char *const *)tzname, NULL, 2); + if (ep != NULL) { + tm->tm_isdst = i; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -(timezone); +#endif +#ifdef TM_ZONE + tm->TM_ZONE = tzname[i]; +#endif + } + bp = ep; + } + continue; + + case 'z': + /* + * We recognize all ISO 8601 formats: + * Z = Zulu time/UTC + * [+-]hhmm + * [+-]hh:mm + * [+-]hh + * We recognize all RFC-822/RFC-2822 formats: + * UT|GMT + * North American : UTC offsets + * E[DS]T = Eastern : -4 | -5 + * C[DS]T = Central : -5 | -6 + * M[DS]T = Mountain: -6 | -7 + * P[DS]T = Pacific : -7 | -8 + * Military + * [A-IL-M] = -1 ... -9 (J not used) + * [N-Y] = +1 ... +12 + */ + while (isspace(*bp)) + bp++; + + switch (*bp++) { + case 'G': + if (*bp++ != 'M') + return NULL; + /*FALLTHROUGH*/ + case 'U': + if (*bp++ != 'T') + return NULL; + /*FALLTHROUGH*/ + case 'Z': + tm->tm_isdst = 0; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = 0; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = utc; +#endif + continue; + case '+': + neg = 0; + break; + case '-': + neg = 1; + break; + default: + --bp; + ep = find_string(bp, &i, nast, NULL, 4); + if (ep != NULL) { +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -5 - i; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = __UNCONST(nast[i]); +#endif + bp = ep; + continue; + } + ep = find_string(bp, &i, nadt, NULL, 4); + if (ep != NULL) { + tm->tm_isdst = 1; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -4 - i; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = __UNCONST(nadt[i]); +#endif + bp = ep; + continue; + } + + if ((*bp >= 'A' && *bp <= 'I') || (*bp >= 'L' && *bp <= 'Y')) { +#ifdef TM_GMTOFF + /* Argh! No 'J'! */ + if (*bp >= 'A' && *bp <= 'I') + tm->TM_GMTOFF = ('A' - 1) - (int)*bp; + else if (*bp >= 'L' && *bp <= 'M') + tm->TM_GMTOFF = 'A' - (int)*bp; + else if (*bp >= 'N' && *bp <= 'Y') + tm->TM_GMTOFF = (int)*bp - 'M'; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = NULL; /* XXX */ +#endif + bp++; + continue; + } + return NULL; + } + offs = 0; + for (i = 0; i < 4;) { + if (isdigit(*bp)) { + offs = offs * 10 + (*bp++ - '0'); + i++; + continue; + } + if (i == 2 && *bp == ':') { + bp++; + continue; + } + break; + } + switch (i) { + case 2: + offs *= 100; + break; + case 4: + i = offs % 100; + if (i >= 60) + return NULL; + /* Convert minutes into decimal */ + offs = (offs / 100) * 100 + (i * 50) / 30; + break; + default: + return NULL; + } + if (neg) + offs = -offs; + tm->tm_isdst = 0; /* XXX */ +#ifdef TM_GMTOFF + tm->TM_GMTOFF = offs; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = NULL; /* XXX */ +#endif + continue; + + /* + * Miscellaneous conversions. + */ + case 'n': /* Any kind of white-space. */ + case 't': + while (isspace(*bp)) + bp++; + LEGAL_ALT(0); + continue; + + default: /* Unknown/unsupported conversion. */ + return NULL; + } + } + + return (char *)(bp); +} + +static const u_char *conv_num( + const unsigned char *buf, int *dest, unsigned int llim, unsigned int ulim) +{ + unsigned int result = 0; + unsigned char ch; + + /* The limit also determines the number of valid digits. */ + unsigned int rulim = ulim; + + ch = *buf; + if (ch < '0' || ch > '9') + return NULL; + + do { + result *= 10; + result += ch - '0'; + rulim /= 10; + ch = *++buf; + } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9'); + + if (result < llim || result > ulim) + return NULL; + + *dest = result; + return buf; +} + +static const u_char *find_string( + const u_char *bp, int *tgt, const char *const *n1, const char *const *n2, int c) +{ + int i; + size_t len; + + /* check full name - then abbreviated ones */ + for (; n1 != NULL; n1 = n2, n2 = NULL) { + for (i = 0; i < c; i++, n1++) { + len = strlen(*n1); + if (strncasecmp(*n1, (const char *)bp, len) == 0) { + *tgt = i; + return bp + len; + } + } + } + + /* Nothing matched */ + return NULL; +} +#endif /* HAVE_STRPTIME */ diff --git a/src/util/sysfs.c b/src/util/sysfs.c new file mode 100644 index 000000000000..6cba6c3f717d --- /dev/null +++ b/src/util/sysfs.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2011-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Richard McConnell + * + * Sysfs utility file + */ + +#include "util/sysfs.h" + +#define SYSFS_MAX_FILENAME_LEN (SYSFS_MAX_FILENAME_SIZE + 5) + +TmEcode SysFsWriteValue(const char *path, int64_t value) +{ +#if defined(__linux__) + char fname[SYSFS_MAX_FILENAME_LEN] = "/sys/"; + char sentence[64]; + + if (!path || strlen(path) > SYSFS_MAX_FILENAME_SIZE) { + SCLogWarning("File path too long, max allowed: %d", SYSFS_MAX_FILENAME_SIZE); + SCReturnInt(TM_ECODE_FAILED); + } + + strlcat(fname, path, sizeof(fname)); + + /* File must be present and process have correct capabilities to open */ + int fd = open(fname, O_WRONLY); + if (fd < 0) { + SCLogError("Could not open file: %s", fname); + SCReturnInt(TM_ECODE_FAILED); + } + + snprintf(sentence, sizeof(sentence), "%" PRIu64, value); + ssize_t len = strlen(sentence); + + if (write(fd, sentence, len) != len) { + SCLogError("Could not write to file: %s", fname); + close(fd); + SCReturnInt(TM_ECODE_FAILED); + } + close(fd); +#endif /* __LINUX__ */ + + SCReturnInt(TM_ECODE_OK); +} diff --git a/src/util/sysfs.h b/src/util/sysfs.h new file mode 100644 index 000000000000..60ed817eaba2 --- /dev/null +++ b/src/util/sysfs.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2011-2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Richard McConnell + * + */ + +#ifndef UTIL_SYSFS_H +#define UTIL_SYSFS_H + +#include "util/error.h" +#include "util/debug.h" + +/* /sys/ prepended as mount point 251 + 5 = 256 */ +#define SYSFS_MAX_FILENAME_SIZE 251 + +TmEcode SysFsWriteValue(const char *path, int64_t value); + +#endif /* UTIL_SYSFS_H */ diff --git a/src/util/syslog.c b/src/util/syslog.c new file mode 100644 index 000000000000..ee03ac79c77e --- /dev/null +++ b/src/util/syslog.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + * + * Syslog utility file + * + */ + +#include "suricata-common.h" +#include "util/syslog.h" + +/* holds the string-enum mapping for the syslog facility in SCLogOPIfaceCtx */ +SCEnumCharMap sc_syslog_facility_map[] = { { "auth", LOG_AUTH }, { "authpriv", LOG_AUTHPRIV }, + { "cron", LOG_CRON }, { "daemon", LOG_DAEMON }, { "ftp", LOG_FTP }, { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, { "mail", LOG_MAIL }, { "news", LOG_NEWS }, { "security", LOG_AUTH }, + { "syslog", LOG_SYSLOG }, { "user", LOG_USER }, { "uucp", LOG_UUCP }, { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, { NULL, -1 } }; + +/** \brief returns the syslog facility enum map */ +SCEnumCharMap *SCSyslogGetFacilityMap(void) +{ + return sc_syslog_facility_map; +} + +SCEnumCharMap sc_syslog_level_map[] = { { "Emergency", LOG_EMERG }, { "Alert", LOG_ALERT }, + { "Critical", LOG_CRIT }, { "Error", LOG_ERR }, { "Warning", LOG_WARNING }, + { "Notice", LOG_NOTICE }, { "Info", LOG_INFO }, { "Debug", LOG_DEBUG }, { NULL, -1 } }; + +/** \brief returns the syslog facility enum map */ +SCEnumCharMap *SCSyslogGetLogLevelMap(void) +{ + return sc_syslog_level_map; +} diff --git a/src/util/syslog.h b/src/util/syslog.h new file mode 100644 index 000000000000..3f236fed57af --- /dev/null +++ b/src/util/syslog.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + * + */ + +#ifndef UTIL_SYSLOG_H +#define UTIL_SYSLOG_H + +#include "util/enum.h" + +SCEnumCharMap *SCSyslogGetFacilityMap(void); +SCEnumCharMap *SCSyslogGetLogLevelMap(void); + +#ifndef OS_WIN32 +#define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" +#define DEFAULT_ALERT_SYSLOG_FACILITY LOG_LOCAL0 +#define DEFAULT_ALERT_SYSLOG_LEVEL LOG_ERR +#endif + +#endif /* UTIL_SYSLOG_H */ diff --git a/src/util/thash.c b/src/util/thash.c new file mode 100644 index 000000000000..7af56c12f761 --- /dev/null +++ b/src/util/thash.c @@ -0,0 +1,819 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" +#include "../conf.h" + +#include "util/debug.h" +#include "util/thash.h" + +#include "util/random.h" +#include "util/misc.h" +#include "util/byte.h" + +#include "util/hash-lookup3.h" +#include "util/validate.h" + +static THashData *THashGetUsed(THashTableContext *ctx); +static void THashDataEnqueue(THashDataQueue *q, THashData *h); + +void THashDataMoveToSpare(THashTableContext *ctx, THashData *h) +{ + THashDataEnqueue(&ctx->spare_q, h); + (void)SC_ATOMIC_SUB(ctx->counter, 1); +} + +static THashDataQueue *THashDataQueueInit(THashDataQueue *q) +{ + if (q != NULL) { + memset(q, 0, sizeof(THashDataQueue)); + HQLOCK_INIT(q); + } + return q; +} + +THashDataQueue *THashDataQueueNew(void) +{ + THashDataQueue *q = (THashDataQueue *)SCMalloc(sizeof(THashDataQueue)); + if (q == NULL) { + SCLogError("Fatal error encountered in THashDataQueueNew. Exiting..."); + exit(EXIT_SUCCESS); + } + q = THashDataQueueInit(q); + return q; +} + +/** + * \brief Destroy a queue + * + * \param q the queue to destroy + */ +static void THashDataQueueDestroy(THashDataQueue *q) +{ + HQLOCK_DESTROY(q); +} + +/** + * \brief add to queue + * + * \param q queue + * \param h data + */ +static void THashDataEnqueue(THashDataQueue *q, THashData *h) +{ +#ifdef DEBUG + BUG_ON(q == NULL || h == NULL); +#endif + + HQLOCK_LOCK(q); + + /* more data in queue */ + if (q->top != NULL) { + h->next = q->top; + q->top->prev = h; + q->top = h; + /* only data */ + } else { + q->top = h; + q->bot = h; + } + q->len++; +#ifdef DBG_PERF + if (q->len > q->dbg_maxlen) + q->dbg_maxlen = q->len; +#endif /* DBG_PERF */ + HQLOCK_UNLOCK(q); +} + +/** + * \brief remove data from the queue + * + * \param q queue + * + * \retval h data or NULL if empty list. + */ +static THashData *THashDataDequeue(THashDataQueue *q) +{ + HQLOCK_LOCK(q); + + THashData *h = q->bot; + if (h == NULL) { + HQLOCK_UNLOCK(q); + return NULL; + } + + /* more packets in queue */ + if (q->bot->prev != NULL) { + q->bot = q->bot->prev; + q->bot->next = NULL; + /* just the one we remove, so now empty */ + } else { + q->top = NULL; + q->bot = NULL; + } + +#ifdef DEBUG + BUG_ON(q->len == 0); +#endif + if (q->len > 0) + q->len--; + + h->next = NULL; + h->prev = NULL; + + HQLOCK_UNLOCK(q); + return h; +} + +#if 0 +static uint32_t THashDataQueueLen(THashDataQueue *q) +{ + uint32_t len; + HQLOCK_LOCK(q); + len = q->len; + HQLOCK_UNLOCK(q); + return len; +} +#endif + +static THashData *THashDataAlloc(THashTableContext *ctx) +{ + const size_t data_size = THASH_DATA_SIZE(ctx); + + if (!(THASH_CHECK_MEMCAP(ctx, data_size))) { + return NULL; + } + + (void)SC_ATOMIC_ADD(ctx->memuse, data_size); + + THashData *h = SCCalloc(1, data_size); + if (unlikely(h == NULL)) + goto error; + + /* points to data right after THashData block */ + h->data = (uint8_t *)h + sizeof(THashData); + + // memset(h, 0x00, data_size); + + SCMutexInit(&h->m, NULL); + SC_ATOMIC_INIT(h->use_cnt); + return h; + +error: + return NULL; +} + +static void THashDataFree(THashTableContext *ctx, THashData *h) +{ + if (h != NULL) { + DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(h->use_cnt) != 0); + + if (h->data != NULL) { + ctx->config.DataFree(h->data); + } + SCMutexDestroy(&h->m); + SCFree(h); + (void)SC_ATOMIC_SUB(ctx->memuse, THASH_DATA_SIZE(ctx)); + } +} + +#define THASH_DEFAULT_HASHSIZE 4096 +#define THASH_DEFAULT_MEMCAP 16777216 +#define THASH_DEFAULT_PREALLOC 1000 + +#define GET_VAR(prefix, name) snprintf(varname, sizeof(varname), "%s.%s", (prefix), (name)) + +/** \brief initialize the configuration + * \warning Not thread safe */ +static int THashInitConfig(THashTableContext *ctx, const char *cnf_prefix) +{ + char varname[256]; + + SCLogDebug("initializing thash engine..."); + + /* Check if we have memcap and hash_size defined at config */ + const char *conf_val; + uint32_t configval = 0; + + /** set config values for memcap, prealloc and hash_size */ + GET_VAR(cnf_prefix, "memcap"); + if ((ConfGet(varname, &conf_val)) == 1) { + if (ParseSizeStringU64(conf_val, &ctx->config.memcap) < 0) { + SCLogError("Error parsing %s " + "from conf file - %s. Killing engine", + varname, conf_val); + return -1; + } + } + GET_VAR(cnf_prefix, "hash-size"); + if ((ConfGet(varname, &conf_val)) == 1) { + if (StringParseUint32(&configval, 10, (uint16_t)strlen(conf_val), conf_val) > 0) { + ctx->config.hash_size = configval; + } + } + + GET_VAR(cnf_prefix, "prealloc"); + if ((ConfGet(varname, &conf_val)) == 1) { + if (StringParseUint32(&configval, 10, (uint16_t)strlen(conf_val), conf_val) > 0) { + ctx->config.prealloc = configval; + } else { + WarnInvalidConfEntry(varname, "%" PRIu32, ctx->config.prealloc); + } + } + + /* alloc hash memory */ + uint64_t hash_size = ctx->config.hash_size * sizeof(THashHashRow); + if (!(THASH_CHECK_MEMCAP(ctx, hash_size))) { + SCLogError("allocating hash failed: " + "max hash memcap is smaller than projected hash size. " + "Memcap: %" PRIu64 ", Hash table size %" PRIu64 ". Calculate " + "total hash size by multiplying \"hash-size\" with %" PRIuMAX ", " + "which is the hash bucket size.", + ctx->config.memcap, hash_size, (uintmax_t)sizeof(THashHashRow)); + return -1; + } + ctx->array = SCMallocAligned(ctx->config.hash_size * sizeof(THashHashRow), CLS); + if (unlikely(ctx->array == NULL)) { + SCLogError("Fatal error encountered in THashInitConfig. Exiting..."); + return -1; + } + memset(ctx->array, 0, ctx->config.hash_size * sizeof(THashHashRow)); + + uint32_t i = 0; + for (i = 0; i < ctx->config.hash_size; i++) { + HRLOCK_INIT(&ctx->array[i]); + } + (void)SC_ATOMIC_ADD(ctx->memuse, (ctx->config.hash_size * sizeof(THashHashRow))); + + /* pre allocate prealloc */ + for (i = 0; i < ctx->config.prealloc; i++) { + if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) { + SCLogError("preallocating data failed: " + "max thash memcap reached. Memcap %" PRIu64 ", " + "Memuse %" PRIu64 ".", + ctx->config.memcap, + ((uint64_t)SC_ATOMIC_GET(ctx->memuse) + THASH_DATA_SIZE(ctx))); + return -1; + } + + THashData *h = THashDataAlloc(ctx); + if (h == NULL) { + SCLogError("preallocating data failed: %s", strerror(errno)); + return -1; + } + THashDataEnqueue(&ctx->spare_q, h); + } + + return 0; +} + +THashTableContext *THashInit(const char *cnf_prefix, size_t data_size, + int (*DataSet)(void *, void *), void (*DataFree)(void *), uint32_t (*DataHash)(void *), + bool (*DataCompare)(void *, void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize) +{ + THashTableContext *ctx = SCCalloc(1, sizeof(*ctx)); + BUG_ON(!ctx); + + ctx->config.data_size = data_size; + ctx->config.DataSet = DataSet; + ctx->config.DataFree = DataFree; + ctx->config.DataHash = DataHash; + ctx->config.DataCompare = DataCompare; + + /* set defaults */ + ctx->config.hash_rand = (uint32_t)RandomGet(); + ctx->config.hash_size = hashsize > 0 ? hashsize : THASH_DEFAULT_HASHSIZE; + /* Reset memcap in case of loading from file to the highest possible value + unless defined by the rule keyword */ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // limit memcap size to default when fuzzing + ctx->config.memcap = THASH_DEFAULT_MEMCAP; +#else + if (memcap > 0) { + ctx->config.memcap = memcap; + } else { + ctx->config.memcap = reset_memcap ? UINT64_MAX : THASH_DEFAULT_MEMCAP; + } +#endif + ctx->config.prealloc = THASH_DEFAULT_PREALLOC; + + SC_ATOMIC_INIT(ctx->counter); + SC_ATOMIC_INIT(ctx->memuse); + SC_ATOMIC_INIT(ctx->prune_idx); + THashDataQueueInit(&ctx->spare_q); + + if (THashInitConfig(ctx, cnf_prefix) < 0) { + THashShutdown(ctx); + ctx = NULL; + } + return ctx; +} + +/* \brief Set memcap to current memuse + * */ +void THashConsolidateMemcap(THashTableContext *ctx) +{ + ctx->config.memcap = MAX(SC_ATOMIC_GET(ctx->memuse), ctx->config.memcap); + SCLogDebug("memcap after load set to: %" PRIu64, ctx->config.memcap); +} + +/** \brief shutdown the flow engine + * \warning Not thread safe */ +void THashShutdown(THashTableContext *ctx) +{ + THashData *h; + + /* free spare queue */ + while ((h = THashDataDequeue(&ctx->spare_q))) { + BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0); + THashDataFree(ctx, h); + } + + /* clear and free the hash */ + if (ctx->array != NULL) { + for (uint32_t u = 0; u < ctx->config.hash_size; u++) { + h = ctx->array[u].head; + while (h) { + THashData *n = h->next; + THashDataFree(ctx, h); + h = n; + } + + HRLOCK_DESTROY(&ctx->array[u]); + } + SCFreeAligned(ctx->array); + ctx->array = NULL; + } + (void)SC_ATOMIC_SUB(ctx->memuse, ctx->config.hash_size * sizeof(THashHashRow)); + THashDataQueueDestroy(&ctx->spare_q); + SCFree(ctx); + return; +} + +/** \brief Walk the hash + * + */ +int THashWalk(THashTableContext *ctx, THashFormatFunc FormatterFunc, THashOutputFunc OutputterFunc, + void *output_ctx) +{ + uint32_t u; + + if (ctx->array == NULL) + return -1; + + bool err = false; + for (u = 0; u < ctx->config.hash_size; u++) { + THashHashRow *hb = &ctx->array[u]; + HRLOCK_LOCK(hb); + THashData *h = hb->head; + while (h) { + char output_string[1024] = ""; + int size = FormatterFunc(h->data, output_string, sizeof(output_string)); + if (size > 0) { + if (OutputterFunc(output_ctx, (const uint8_t *)output_string, size) < 0) { + err = true; + break; + } + } + h = h->next; + } + HRLOCK_UNLOCK(hb); + if (err == true) + return -1; + } + return 0; +} + +/** \brief Cleanup the thash engine + * + * Cleanup the thash engine from tag and threshold. + * + */ +void THashCleanup(THashTableContext *ctx) +{ + uint32_t u; + + if (ctx->array == NULL) + return; + + for (u = 0; u < ctx->config.hash_size; u++) { + THashHashRow *hb = &ctx->array[u]; + HRLOCK_LOCK(hb); + THashData *h = hb->head; + while (h) { + if ((SC_ATOMIC_GET(h->use_cnt) > 0)) { + h = h->next; + } else { + THashData *n = h->next; + /* remove from the hash */ + if (h->prev != NULL) + h->prev->next = h->next; + if (h->next != NULL) + h->next->prev = h->prev; + if (hb->head == h) + hb->head = h->next; + if (hb->tail == h) + hb->tail = h->prev; + h->next = NULL; + h->prev = NULL; + THashDataMoveToSpare(ctx, h); + h = n; + } + } + HRLOCK_UNLOCK(hb); + } + return; +} + +/* calculate the hash key for this packet + * + * we're using: + * hash_rand -- set at init time + * source address + */ +static uint32_t THashGetKey(const THashConfig *cnf, void *data) +{ + uint32_t key; + + key = cnf->DataHash(data); + key %= cnf->hash_size; + + return key; +} + +static inline int THashCompare(const THashConfig *cnf, void *a, void *b) +{ + if (cnf->DataCompare(a, b)) + return 1; + return 0; +} + +/** + * \brief Get new data + * + * Get new data. We're checking memcap first and will try to make room + * if the memcap is reached. + * + * \retval h *LOCKED* data on succes, NULL on error. + */ +static THashData *THashDataGetNew(THashTableContext *ctx, void *data) +{ + THashData *h = NULL; + + /* get data from the spare queue */ + h = THashDataDequeue(&ctx->spare_q); + if (h == NULL) { + /* If we reached the max memcap, we get used data */ + if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) { + h = THashGetUsed(ctx); + if (h == NULL) { + return NULL; + } + + if (!SC_ATOMIC_GET(ctx->memcap_reached)) { + SC_ATOMIC_SET(ctx->memcap_reached, true); + } + + /* freed data, but it's unlocked */ + } else { + /* now see if we can alloc a new data */ + h = THashDataAlloc(ctx); + if (h == NULL) { + return NULL; + } + + /* data is initialized but *unlocked* */ + } + } else { + /* data has been recycled before it went into the spare queue */ + + /* data is initialized (recycled) but *unlocked* */ + } + + // setup the data + BUG_ON(ctx->config.DataSet(h->data, data) != 0); + + (void)SC_ATOMIC_ADD(ctx->counter, 1); + SCMutexLock(&h->m); + return h; +} + +/* + * returns a *LOCKED* data or NULL + */ + +struct THashDataGetResult THashGetFromHash(THashTableContext *ctx, void *data) +{ + struct THashDataGetResult res = { + .data = NULL, + .is_new = false, + }; + THashData *h = NULL; + + /* get the key to our bucket */ + uint32_t key = THashGetKey(&ctx->config, data); + /* get our hash bucket and lock it */ + THashHashRow *hb = &ctx->array[key]; + HRLOCK_LOCK(hb); + + /* see if the bucket already has data */ + if (hb->head == NULL) { + h = THashDataGetNew(ctx, data); + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return res; + } + + /* data is locked */ + hb->head = h; + hb->tail = h; + + /* initialize and return */ + (void)THashIncrUsecnt(h); + + HRLOCK_UNLOCK(hb); + res.data = h; + res.is_new = true; + return res; + } + + /* ok, we have data in the bucket. Let's find out if it is our data */ + h = hb->head; + + /* see if this is the data we are looking for */ + if (THashCompare(&ctx->config, h->data, data) == 0) { + THashData *ph = NULL; /* previous data */ + + while (h) { + ph = h; + h = h->next; + + if (h == NULL) { + h = ph->next = THashDataGetNew(ctx, data); + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return res; + } + hb->tail = h; + + /* data is locked */ + + h->prev = ph; + + /* initialize and return */ + (void)THashIncrUsecnt(h); + + HRLOCK_UNLOCK(hb); + res.data = h; + res.is_new = true; + return res; + } + + if (THashCompare(&ctx->config, h->data, data) != 0) { + /* we found our data, lets put it on top of the + * hash list -- this rewards active data */ + if (h->next) { + h->next->prev = h->prev; + } + if (h->prev) { + h->prev->next = h->next; + } + if (h == hb->tail) { + hb->tail = h->prev; + } + + h->next = hb->head; + h->prev = NULL; + hb->head->prev = h; + hb->head = h; + + /* found our data, lock & return */ + SCMutexLock(&h->m); + (void)THashIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + res.data = h; + res.is_new = false; + /* coverity[missing_unlock : FALSE] */ + return res; + } + } + } + + /* lock & return */ + SCMutexLock(&h->m); + (void)THashIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + res.data = h; + res.is_new = false; + /* coverity[missing_unlock : FALSE] */ + return res; +} + +/** \brief look up data in the hash + * + * \param data data to look up + * + * \retval h *LOCKED* data or NULL + */ +THashData *THashLookupFromHash(THashTableContext *ctx, void *data) +{ + THashData *h = NULL; + + /* get the key to our bucket */ + uint32_t key = THashGetKey(&ctx->config, data); + /* get our hash bucket and lock it */ + THashHashRow *hb = &ctx->array[key]; + HRLOCK_LOCK(hb); + + if (hb->head == NULL) { + HRLOCK_UNLOCK(hb); + return h; + } + + /* ok, we have data in the bucket. Let's find out if it is our data */ + h = hb->head; + + /* see if this is the data we are looking for */ + if (THashCompare(&ctx->config, h->data, data) == 0) { + while (h) { + h = h->next; + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return h; + } + + if (THashCompare(&ctx->config, h->data, data) != 0) { + /* we found our data, lets put it on top of the + * hash list -- this rewards active data */ + if (h->next) { + h->next->prev = h->prev; + } + if (h->prev) { + h->prev->next = h->next; + } + if (h == hb->tail) { + hb->tail = h->prev; + } + + h->next = hb->head; + h->prev = NULL; + hb->head->prev = h; + hb->head = h; + + /* found our data, lock & return */ + SCMutexLock(&h->m); + (void)THashIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; + } + } + } + + /* lock & return */ + SCMutexLock(&h->m); + (void)THashIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; +} + +/** \internal + * \brief Get data from the hash directly. + * + * Called in conditions where the spare queue is empty and memcap is + * reached. + * + * Walks the hash until data can be freed. "prune_idx" atomic int makes + * sure we don't start at the top each time since that would clear the top + * of the hash leading to longer and longer search times under high + * pressure (observed). + * + * \retval h data or NULL + */ +static THashData *THashGetUsed(THashTableContext *ctx) +{ + uint32_t idx = SC_ATOMIC_GET(ctx->prune_idx) % ctx->config.hash_size; + uint32_t cnt = ctx->config.hash_size; + + while (cnt--) { + if (++idx >= ctx->config.hash_size) + idx = 0; + + THashHashRow *hb = &ctx->array[idx]; + + if (HRLOCK_TRYLOCK(hb) != 0) + continue; + + THashData *h = hb->tail; + if (h == NULL) { + HRLOCK_UNLOCK(hb); + continue; + } + + if (SCMutexTrylock(&h->m) != 0) { + HRLOCK_UNLOCK(hb); + continue; + } + + if (SC_ATOMIC_GET(h->use_cnt) > 0) { + HRLOCK_UNLOCK(hb); + SCMutexUnlock(&h->m); + continue; + } + + /* remove from the hash */ + if (h->prev != NULL) + h->prev->next = h->next; + if (h->next != NULL) + h->next->prev = h->prev; + if (hb->head == h) + hb->head = h->next; + if (hb->tail == h) + hb->tail = h->prev; + + h->next = NULL; + h->prev = NULL; + HRLOCK_UNLOCK(hb); + + if (h->data != NULL) { + ctx->config.DataFree(h->data); + } + SCMutexUnlock(&h->m); + + (void)SC_ATOMIC_ADD(ctx->prune_idx, (ctx->config.hash_size - cnt)); + return h; + } + + return NULL; +} + +/** + * \retval int -1 not found + * \retval int 0 found, but it was busy (ref cnt) + * \retval int 1 found and removed */ +int THashRemoveFromHash(THashTableContext *ctx, void *data) +{ + /* get the key to our bucket */ + uint32_t key = THashGetKey(&ctx->config, data); + /* get our hash bucket and lock it */ + THashHashRow *hb = &ctx->array[key]; + + HRLOCK_LOCK(hb); + THashData *h = hb->head; + while (h != NULL) { + /* see if this is the data we are looking for */ + if (THashCompare(&ctx->config, h->data, data) == 0) { + h = h->next; + continue; + } + + SCMutexLock(&h->m); + if (SC_ATOMIC_GET(h->use_cnt) > 0) { + SCMutexUnlock(&h->m); + HRLOCK_UNLOCK(hb); + return 0; + } + + /* remove from the hash */ + if (h->prev != NULL) + h->prev->next = h->next; + if (h->next != NULL) + h->next->prev = h->prev; + if (hb->head == h) + hb->head = h->next; + if (hb->tail == h) + hb->tail = h->prev; + + h->next = NULL; + h->prev = NULL; + SCMutexUnlock(&h->m); + HRLOCK_UNLOCK(hb); + THashDataFree(ctx, h); + SCLogDebug("found and removed"); + return 1; + } + + HRLOCK_UNLOCK(hb); + SCLogDebug("data not found"); + return -1; +} diff --git a/src/util/thash.h b/src/util/thash.h new file mode 100644 index 000000000000..92073a773560 --- /dev/null +++ b/src/util/thash.h @@ -0,0 +1,198 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * thash -> thread hash. Hash table with locking handling. + */ + +#ifndef __THASH_H__ +#define __THASH_H__ + +#include "threads.h" + +/** Spinlocks or Mutex for the buckets. */ +// #define HRLOCK_SPIN +#define HRLOCK_MUTEX + +#ifdef HRLOCK_SPIN +#ifdef HRLOCK_MUTEX +#error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX +#endif +#endif + +#ifdef HRLOCK_SPIN +#define HRLOCK_TYPE SCSpinlock +#define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) +#define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) +#define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) +#define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) +#define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) +#elif defined HRLOCK_MUTEX +#define HRLOCK_TYPE SCMutex +#define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) +#define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) +#define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) +#define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) +#define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) +#else +#error Enable HRLOCK_SPIN or HRLOCK_MUTEX +#endif + +/** Spinlocks or Mutex for the queues. */ +// #define HQLOCK_SPIN +#define HQLOCK_MUTEX + +#ifdef HQLOCK_SPIN +#ifdef HQLOCK_MUTEX +#error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX +#endif +#endif + +#ifdef HQLOCK_SPIN +#define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) +#define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) +#define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) +#define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) +#define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) +#elif defined HQLOCK_MUTEX +#define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) +#define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) +#define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) +#define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) +#define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) +#else +#error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#endif + +typedef struct THashData_ { + /** ippair mutex */ + SCMutex m; + + /** use cnt, reference counter */ + SC_ATOMIC_DECLARE(unsigned int, use_cnt); + + void *data; + + struct THashData_ *next; + struct THashData_ *prev; +} THashData; + +typedef struct THashHashRow_ { + HRLOCK_TYPE lock; + THashData *head; + THashData *tail; +} __attribute__((aligned(CLS))) THashHashRow; + +typedef struct THashDataQueue_ { + THashData *top; + THashData *bot; + uint32_t len; +#ifdef DBG_PERF + uint32_t dbg_maxlen; +#endif /* DBG_PERF */ +#ifdef HQLOCK_MUTEX + SCMutex m; +#elif defined HQLOCK_SPIN + SCSpinlock s; +#else +#error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#endif +} THashDataQueue; + +typedef int (*THashOutputFunc)(void *output_ctx, const uint8_t *data, const uint32_t data_len); +typedef int (*THashFormatFunc)(const void *in_data, char *output, size_t output_size); + +typedef struct THashDataConfig_ { + uint64_t memcap; + uint32_t hash_rand; + uint32_t hash_size; + uint32_t prealloc; + + uint32_t data_size; + int (*DataSet)(void *dst, void *src); + void (*DataFree)(void *); + uint32_t (*DataHash)(void *); + bool (*DataCompare)(void *, void *); +} THashConfig; + +#define THASH_DATA_SIZE(ctx) (sizeof(THashData) + (ctx)->config.data_size) + +typedef struct THashTableContext_ { + /* array of rows indexed by the hash value % hash size */ + THashHashRow *array; + + SC_ATOMIC_DECLARE(uint64_t, memuse); + SC_ATOMIC_DECLARE(uint32_t, counter); + SC_ATOMIC_DECLARE(uint32_t, prune_idx); + + THashDataQueue spare_q; + + THashConfig config; + + /* flag set if memcap was reached at least once. */ + SC_ATOMIC_DECLARE(bool, memcap_reached); +} THashTableContext; + +/** \brief check if a memory alloc would fit in the memcap + * + * \param size memory allocation size to check + * + * \retval 1 it fits + * \retval 0 no fit + */ +#define THASH_CHECK_MEMCAP(ctx, size) \ + ((((uint64_t)SC_ATOMIC_GET((ctx)->memuse) + (uint64_t)(size)) <= (ctx)->config.memcap)) + +#define THashIncrUsecnt(h) (void)SC_ATOMIC_ADD((h)->use_cnt, 1) +#define THashDecrUsecnt(h) (void)SC_ATOMIC_SUB((h)->use_cnt, 1) + +THashTableContext *THashInit(const char *cnf_prefix, size_t data_size, + int (*DataSet)(void *dst, void *src), void (*DataFree)(void *), + uint32_t (*DataHash)(void *), bool (*DataCompare)(void *, void *), bool reset_memcap, + uint64_t memcap, uint32_t hashsize); + +void THashShutdown(THashTableContext *ctx); + +static inline void THashDataLock(THashData *d) +{ + SCMutexLock(&d->m); +} + +static inline void THashDataUnlock(THashData *d) +{ + SCMutexUnlock(&d->m); +} + +struct THashDataGetResult { + THashData *data; + bool is_new; +}; + +struct THashDataGetResult THashGetFromHash(THashTableContext *ctx, void *data); +THashData *THashLookupFromHash(THashTableContext *ctx, void *data); +THashDataQueue *THashDataQueueNew(void); +void THashCleanup(THashTableContext *ctx); +int THashWalk(THashTableContext *, THashFormatFunc, THashOutputFunc, void *); +int THashRemoveFromHash(THashTableContext *ctx, void *data); +void THashConsolidateMemcap(THashTableContext *ctx); +void THashDataMoveToSpare(THashTableContext *ctx, THashData *h); + +#endif /* __THASH_H__ */ diff --git a/src/util/threshold-config.c b/src/util/threshold-config.c new file mode 100644 index 000000000000..9e66cc3ec0e1 --- /dev/null +++ b/src/util/threshold-config.c @@ -0,0 +1,2625 @@ +/* Copyright (C) 2007-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup threshold + * @{ + */ + +/** + * \file + * + * \author Breno Silva Pinto + * + * Implements Threshold support + */ + +#include "suricata-common.h" + +#include "host.h" +#include "ippair.h" + +#include "../detect.h" +#include "detect-engine.h" +#include "detect-engine-address.h" +#include "detect-engine-threshold.h" +#include "detect-threshold.h" +#include "detect-parse.h" +#include "detect-engine-build.h" + +#include "../conf.h" +#include "util/threshold-config.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" +#include "util/byte.h" +#include "util/time.h" +#include "util/error.h" +#include "util/debug.h" +#include "util/fmemopen.h" + +typedef enum ThresholdRuleType { + THRESHOLD_TYPE_EVENT_FILTER, + THRESHOLD_TYPE_THRESHOLD, + THRESHOLD_TYPE_RATE, + THRESHOLD_TYPE_SUPPRESS, +} ThresholdRuleType; + +#ifdef UNITTESTS +/* File descriptor for unittests */ +static FILE *g_ut_threshold_fp = NULL; +#endif + +/* common base for all options */ +#define DETECT_BASE_REGEX \ + "^\\s*(event_filter|threshold|rate_filter|suppress)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(" \ + "\\d+)\\s*(.*)\\s*$" + +#define DETECT_THRESHOLD_REGEX \ + "^,\\s*type\\s*(limit|both|threshold)\\s*,\\s*track\\s*(by_dst|by_src|by_both|by_rule)\\s*," \ + "\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*$" + +/* TODO: "apply_to" */ +#define DETECT_RATE_REGEX \ + "^,\\s*track\\s*(by_dst|by_src|by_both|by_rule)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(" \ + "\\d+)\\s*,\\s*new_action\\s*(alert|drop|pass|log|sdrop|reject)\\s*,\\s*timeout\\s*(\\d+)\\s*" \ + "$" + +/* + * suppress has two form: + * suppress gen_id 0, sig_id 0, track by_dst, ip 10.88.0.14 + * suppress gen_id 1, sig_id 2000328 + * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10 + */ +#define DETECT_SUPPRESS_REGEX \ + "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\s\\da-zA-Z.:/_]+)*\\s*$" + +/* Default path for the threshold.config file */ +#if defined OS_WIN32 || defined __CYGWIN__ +#define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "\\\\threshold.config" +#else +#define THRESHOLD_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/threshold.config" +#endif + +static DetectParseRegex *regex_base = NULL; +static DetectParseRegex *regex_threshold = NULL; +static DetectParseRegex *regex_rate = NULL; +static DetectParseRegex *regex_suppress = NULL; + +static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd); + +void SCThresholdConfGlobalInit(void) +{ + regex_base = DetectSetupPCRE2(DETECT_BASE_REGEX, 0); + if (regex_base == NULL) { + FatalError("classification base regex setup failed"); + } + regex_threshold = DetectSetupPCRE2(DETECT_THRESHOLD_REGEX, 0); + if (regex_threshold == NULL) { + FatalError("classification threshold regex setup failed"); + } + regex_rate = DetectSetupPCRE2(DETECT_RATE_REGEX, 0); + if (regex_rate == NULL) { + FatalError("classification rate_filter regex setup failed"); + } + regex_suppress = DetectSetupPCRE2(DETECT_SUPPRESS_REGEX, 0); + if (regex_suppress == NULL) { + FatalError("classification suppress regex setup failed"); + } +} + +/** + * \brief Returns the path for the Threshold Config file. We check if we + * can retrieve the path from the yaml conf file. If it is not present, + * return the default path for the threshold file which is + * "./threshold.config". + * + * \retval log_filename Pointer to a string containing the path for the + * Threshold Config file. + */ +static const char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx) +{ + const char *log_filename = NULL; + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; + snprintf(config_value, sizeof(config_value), "%s.threshold-file", de_ctx->config_prefix); + + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &log_filename) != 1) { + if (ConfGet("threshold-file", &log_filename) != 1) { + log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; + } + } + } else { + if (ConfGet("threshold-file", &log_filename) != 1) { + log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; + } + } + return log_filename; +} + +/** + * \brief Inits the context to be used by the Threshold Config parsing API. + * + * This function initializes the hash table to be used by the Detection + * Engine Context to hold the data from the threshold.config file, + * obtains the file desc to parse the threshold.config file, and + * inits the regex used to parse the lines from threshold.config + * file. + * + * \param de_ctx Pointer to the Detection Engine Context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCThresholdConfInitContext(DetectEngineCtx *de_ctx) +{ + const char *filename = NULL; + int ret = 0; +#ifndef UNITTESTS + FILE *fd = NULL; +#else + FILE *fd = g_ut_threshold_fp; + if (fd == NULL) { +#endif + filename = SCThresholdConfGetConfFilename(de_ctx); + if ((fd = fopen(filename, "r")) == NULL) { + SCLogWarning("Error opening file: \"%s\": %s", filename, strerror(errno)); + SCThresholdConfDeInitContext(de_ctx, fd); + return 0; + } +#ifdef UNITTESTS +} +#endif + +if (SCThresholdConfParseFile(de_ctx, fd) < 0) { + SCLogWarning("Error loading threshold configuration from %s", filename); + SCThresholdConfDeInitContext(de_ctx, fd); + /* maintain legacy behavior so no errors unless config testing */ + if (RunmodeGetCurrent() == RUNMODE_CONF_TEST) { + ret = -1; + } + return ret; +} +SCThresholdConfDeInitContext(de_ctx, fd); + +#ifdef UNITTESTS +g_ut_threshold_fp = NULL; +#endif +SCLogDebug("Global thresholding options defined"); +return 0; +} + +/** + * \brief Releases resources used by the Threshold Config API. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param fd Pointer to file descriptor. + */ +static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) +{ + if (fd != NULL) + fclose(fd); + return; +} + +/** \internal + * \brief setup suppress rules + * \retval 0 ok + * \retval -1 error + */ +static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, + uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, uint32_t parsed_seconds, + uint32_t parsed_timeout, uint8_t parsed_new_action, const char *th_ip) +{ + Signature *s = NULL; + DetectThresholdData *de = NULL; + + BUG_ON(parsed_type != TYPE_SUPPRESS); + + DetectThresholdData *orig_de = NULL; + if (parsed_track != TRACK_RULE) { + orig_de = SCCalloc(1, sizeof(DetectThresholdData)); + if (unlikely(orig_de == NULL)) + goto error; + + orig_de->type = TYPE_SUPPRESS; + orig_de->track = parsed_track; + orig_de->count = parsed_count; + orig_de->seconds = parsed_seconds; + orig_de->new_action = parsed_new_action; + orig_de->timeout = parsed_timeout; + if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &orig_de->addrs, (char *)th_ip) < + 0) { + SCLogError("failed to parse %s", th_ip); + goto error; + } + } + + /* Install it */ + if (id == 0 && gid == 0) { + if (parsed_track == TRACK_RULE) { + SCLogWarning("suppressing all rules"); + } + + /* update each sig with our suppress info */ + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + /* tag the rule as noalert */ + if (parsed_track == TRACK_RULE) { + s->flags |= SIG_FLAG_NOALERT; + continue; + } + + de = DetectThresholdDataCopy(orig_de); + if (unlikely(de == NULL)) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_THRESHOLD, (SigMatchCtx *)de, + DETECT_SM_LIST_SUPPRESS) == NULL) { + goto error; + } + } + } else if (id == 0 && gid > 0) { + if (parsed_track == TRACK_RULE) { + SCLogWarning("suppressing all rules with gid %" PRIu32, gid); + } + /* set up suppression for each signature with a matching gid */ + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + if (s->gid != gid) + continue; + + /* tag the rule as noalert */ + if (parsed_track == TRACK_RULE) { + s->flags |= SIG_FLAG_NOALERT; + continue; + } + + de = DetectThresholdDataCopy(orig_de); + if (unlikely(de == NULL)) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_THRESHOLD, (SigMatchCtx *)de, + DETECT_SM_LIST_SUPPRESS) == NULL) { + goto error; + } + } + } else if (id > 0 && gid == 0) { + SCLogError("Can't use a event config that has " + "sid > 0 and gid == 0. Please fix this " + "in your threshold.config file"); + goto error; + } else { + s = SigFindSignatureBySidGid(de_ctx, id, gid); + if (s == NULL) { + SCLogWarning("can't suppress sid " + "%" PRIu32 ", gid %" PRIu32 ": unknown rule", + id, gid); + } else { + if (parsed_track == TRACK_RULE) { + s->flags |= SIG_FLAG_NOALERT; + goto end; + } + + de = DetectThresholdDataCopy(orig_de); + if (unlikely(de == NULL)) + goto error; + + if (SigMatchAppendSMToList(de_ctx, s, DETECT_THRESHOLD, (SigMatchCtx *)de, + DETECT_SM_LIST_SUPPRESS) == NULL) { + goto error; + } + } + } + +end: + if (orig_de != NULL) { + DetectAddressHeadCleanup(&orig_de->addrs); + SCFree(orig_de); + } + return 0; +error: + if (orig_de != NULL) { + DetectAddressHeadCleanup(&orig_de->addrs); + SCFree(orig_de); + } + if (de != NULL) { + DetectAddressHeadCleanup(&de->addrs); + SCFree(de); + } + return -1; +} + +/** \internal + * \brief setup suppress rules + * \retval 0 ok + * \retval -1 error + */ +static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, + uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, uint32_t parsed_seconds, + uint32_t parsed_timeout, uint8_t parsed_new_action, const char *th_ip) +{ + Signature *s = NULL; + SigMatch *sm = NULL; + DetectThresholdData *de = NULL; + + BUG_ON(parsed_type == TYPE_SUPPRESS); + + /* Install it */ + if (id == 0 && gid == 0) { + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + if (sm != NULL) { + SCLogWarning("signature sid:%" PRIu32 " has " + "an event var set. The signature event var is " + "given precedence over the threshold.conf one. " + "We'll change this in the future though.", + s->id); + continue; + } + + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, DETECT_DETECTION_FILTER, -1); + if (sm != NULL) { + SCLogWarning("signature sid:%" PRIu32 " has " + "an event var set. The signature event var is " + "given precedence over the threshold.conf one. " + "We'll change this in the future though.", + s->id); + continue; + } + + de = SCCalloc(1, sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) + goto error; + + de->type = parsed_type; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + + uint16_t smtype = DETECT_THRESHOLD; + if (parsed_type == TYPE_RATE) + smtype = DETECT_DETECTION_FILTER; + + if (SigMatchAppendSMToList( + de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) { + goto error; + } + } + + } else if (id == 0 && gid > 0) { + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + if (s->gid == gid) { + sm = DetectGetLastSMByListId( + s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); + if (sm != NULL) { + SCLogWarning("signature sid:%" PRIu32 " has " + "an event var set. The signature event var is " + "given precedence over the threshold.conf one. " + "We'll change this in the future though.", + id); + continue; + } + + de = SCCalloc(1, sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) + goto error; + + de->type = parsed_type; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + + uint16_t smtype = DETECT_THRESHOLD; + if (parsed_type == TYPE_RATE) + smtype = DETECT_DETECTION_FILTER; + + if (SigMatchAppendSMToList(de_ctx, s, smtype, (SigMatchCtx *)de, + DETECT_SM_LIST_THRESHOLD) == NULL) { + goto error; + } + } + } + } else if (id > 0 && gid == 0) { + SCLogError("Can't use a event config that has " + "sid > 0 and gid == 0. Please fix this " + "in your threshold.conf file"); + } else { + s = SigFindSignatureBySidGid(de_ctx, id, gid); + if (s == NULL) { + SCLogWarning("can't suppress sid " + "%" PRIu32 ", gid %" PRIu32 ": unknown rule", + id, gid); + } else { + if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD && + parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) { + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + if (sm != NULL) { + SCLogWarning("signature sid:%" PRIu32 " has " + "a threshold set. The signature event var is " + "given precedence over the threshold.conf one. " + "Bug #425.", + s->id); + goto end; + } + + sm = DetectGetLastSMByListId( + s, DETECT_SM_LIST_THRESHOLD, DETECT_DETECTION_FILTER, -1); + if (sm != NULL) { + SCLogWarning("signature sid:%" PRIu32 " has " + "a detection_filter set. The signature event var is " + "given precedence over the threshold.conf one. " + "Bug #425.", + s->id); + goto end; + } + + /* replace threshold on sig if we have a global override for it */ + } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || + parsed_type == TYPE_LIMIT) { + sm = DetectGetLastSMByListId( + s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); + if (sm != NULL) { + SigMatchRemoveSMFromList(s, sm, DETECT_SM_LIST_THRESHOLD); + SigMatchFree(de_ctx, sm); + } + } + + de = SCCalloc(1, sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) + goto error; + + de->type = parsed_type; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + + uint16_t smtype = DETECT_THRESHOLD; + if (parsed_type == TYPE_RATE) + smtype = DETECT_DETECTION_FILTER; + + if (SigMatchAppendSMToList( + de_ctx, s, smtype, (SigMatchCtx *)de, DETECT_SM_LIST_THRESHOLD) == NULL) { + goto error; + } + } + } +end: + return 0; +error: + if (de != NULL) { + DetectAddressHeadCleanup(&de->addrs); + SCFree(de); + } + return -1; +} + +static int ParseThresholdRule(const DetectEngineCtx *de_ctx, char *rawstr, uint32_t *ret_id, + uint32_t *ret_gid, uint8_t *ret_parsed_type, uint8_t *ret_parsed_track, + uint32_t *ret_parsed_count, uint32_t *ret_parsed_seconds, uint32_t *ret_parsed_timeout, + uint8_t *ret_parsed_new_action, char **ret_th_ip) +{ + char th_rule_type[32]; + char th_gid[16]; + char th_sid[16]; + const char *rule_extend = NULL; + char th_type[16] = ""; + char th_track[16] = ""; + char th_count[16] = ""; + char th_seconds[16] = ""; + char th_new_action[16] = ""; + char th_timeout[16] = ""; + const char *th_ip = NULL; + + uint8_t parsed_type = 0; + uint8_t parsed_track = 0; + uint8_t parsed_new_action = 0; + uint32_t parsed_count = 0; + uint32_t parsed_seconds = 0; + uint32_t parsed_timeout = 0; + + int ret = 0; + uint32_t id = 0, gid = 0; + ThresholdRuleType rule_type; + + if (de_ctx == NULL) + return -1; + + pcre2_match_data *regex_base_match = NULL; + ret = DetectParsePcreExec(regex_base, ®ex_base_match, rawstr, 0, 0); + if (ret < 4) { + SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, rawstr); + pcre2_match_data_free(regex_base_match); + goto error; + } + + /* retrieve the classtype name */ + size_t copylen = sizeof(th_rule_type); + ret = pcre2_substring_copy_bynumber( + regex_base_match, 1, (PCRE2_UCHAR8 *)th_rule_type, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(regex_base_match); + goto error; + } + + /* retrieve the classtype name */ + copylen = sizeof(th_gid); + ret = pcre2_substring_copy_bynumber(regex_base_match, 2, (PCRE2_UCHAR8 *)th_gid, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(regex_base_match); + goto error; + } + + copylen = sizeof(th_sid); + ret = pcre2_substring_copy_bynumber(regex_base_match, 3, (PCRE2_UCHAR8 *)th_sid, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(regex_base_match); + goto error; + } + + /* Use "get" for heap allocation */ + ret = pcre2_substring_get_bynumber( + regex_base_match, 4, (PCRE2_UCHAR8 **)&rule_extend, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_get_bynumber failed"); + pcre2_match_data_free(regex_base_match); + goto error; + } + pcre2_match_data_free(regex_base_match); + regex_base_match = NULL; + + /* get type of rule */ + if (strcasecmp(th_rule_type, "event_filter") == 0) { + rule_type = THRESHOLD_TYPE_EVENT_FILTER; + } else if (strcasecmp(th_rule_type, "threshold") == 0) { + rule_type = THRESHOLD_TYPE_THRESHOLD; + } else if (strcasecmp(th_rule_type, "rate_filter") == 0) { + rule_type = THRESHOLD_TYPE_RATE; + } else if (strcasecmp(th_rule_type, "suppress") == 0) { + rule_type = THRESHOLD_TYPE_SUPPRESS; + } else { + SCLogError("rule type %s is unknown", th_rule_type); + goto error; + } + + /* get end of rule */ + switch (rule_type) { + case THRESHOLD_TYPE_EVENT_FILTER: + case THRESHOLD_TYPE_THRESHOLD: + if (strlen(rule_extend) > 0) { + pcre2_match_data *match = NULL; + + ret = DetectParsePcreExec(regex_threshold, &match, rule_extend, 0, 0); + if (ret < 4) { + SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, + rule_extend); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_type); + ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_type, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_track); + ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_track, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_count); + ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_count, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_seconds); + ret = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)th_seconds, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + pcre2_match_data_free(match); + + if (strcasecmp(th_type, "limit") == 0) + parsed_type = TYPE_LIMIT; + else if (strcasecmp(th_type, "both") == 0) + parsed_type = TYPE_BOTH; + else if (strcasecmp(th_type, "threshold") == 0) + parsed_type = TYPE_THRESHOLD; + else { + SCLogError("limit type not supported: %s", th_type); + goto error; + } + } else { + SCLogError("rule invalid: %s", rawstr); + goto error; + } + break; + case THRESHOLD_TYPE_SUPPRESS: + if (strlen(rule_extend) > 0) { + pcre2_match_data *match = NULL; + ret = DetectParsePcreExec(regex_suppress, &match, rule_extend, 0, 0); + if (ret < 2) { + SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, + rule_extend); + pcre2_match_data_free(match); + goto error; + } + /* retrieve the track mode */ + copylen = sizeof(th_seconds); + ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + /* retrieve the IP; use "get" for heap allocation */ + ret = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&th_ip, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_get_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + pcre2_match_data_free(match); + } else { + parsed_track = TRACK_RULE; + } + parsed_type = TYPE_SUPPRESS; + break; + case THRESHOLD_TYPE_RATE: + if (strlen(rule_extend) > 0) { + pcre2_match_data *match = NULL; + ret = DetectParsePcreExec(regex_rate, &match, rule_extend, 0, 0); + if (ret < 5) { + SCLogError("pcre2_match parse error, ret %" PRId32 ", string %s", ret, + rule_extend); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_track); + ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)th_track, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_count); + ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)th_count, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_seconds); + ret = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)th_seconds, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_new_action); + ret = pcre2_substring_copy_bynumber( + match, 4, (PCRE2_UCHAR8 *)th_new_action, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + + copylen = sizeof(th_timeout); + ret = pcre2_substring_copy_bynumber(match, 5, (PCRE2_UCHAR8 *)th_timeout, ©len); + if (ret < 0) { + SCLogError("pcre2_substring_copy_bynumber failed"); + pcre2_match_data_free(match); + goto error; + } + pcre2_match_data_free(match); + + /* TODO: implement option "apply_to" */ + + if (StringParseUint32(&parsed_timeout, 10, sizeof(th_timeout), th_timeout) <= 0) { + goto error; + } + + /* Get the new action to take */ + if (strcasecmp(th_new_action, "alert") == 0) + parsed_new_action = TH_ACTION_ALERT; + if (strcasecmp(th_new_action, "drop") == 0) + parsed_new_action = TH_ACTION_DROP; + if (strcasecmp(th_new_action, "pass") == 0) + parsed_new_action = TH_ACTION_PASS; + if (strcasecmp(th_new_action, "reject") == 0) + parsed_new_action = TH_ACTION_REJECT; + if (strcasecmp(th_new_action, "log") == 0) { + SCLogInfo("log action for rate_filter not supported yet"); + parsed_new_action = TH_ACTION_LOG; + } + if (strcasecmp(th_new_action, "sdrop") == 0) { + SCLogInfo("sdrop action for rate_filter not supported yet"); + parsed_new_action = TH_ACTION_SDROP; + } + parsed_type = TYPE_RATE; + } else { + SCLogError("rule invalid: %s", rawstr); + goto error; + } + break; + } + + switch (rule_type) { + /* This part is common to threshold/event_filter/rate_filter */ + case THRESHOLD_TYPE_EVENT_FILTER: + case THRESHOLD_TYPE_THRESHOLD: + case THRESHOLD_TYPE_RATE: + if (strcasecmp(th_track, "by_dst") == 0) + parsed_track = TRACK_DST; + else if (strcasecmp(th_track, "by_src") == 0) + parsed_track = TRACK_SRC; + else if (strcasecmp(th_track, "by_both") == 0) { + parsed_track = TRACK_BOTH; + } else if (strcasecmp(th_track, "by_rule") == 0) + parsed_track = TRACK_RULE; + else { + SCLogError("Invalid track parameter %s in %s", th_track, rawstr); + goto error; + } + + if (StringParseUint32(&parsed_count, 10, sizeof(th_count), th_count) <= 0) { + goto error; + } + if (parsed_count == 0) { + SCLogError("rate filter count should be > 0"); + goto error; + } + + if (StringParseUint32(&parsed_seconds, 10, sizeof(th_seconds), th_seconds) <= 0) { + goto error; + } + + break; + case THRESHOLD_TYPE_SUPPRESS: + /* need to get IP if extension is provided */ + if (strcmp("", th_track) != 0) { + if (strcasecmp(th_track, "by_dst") == 0) + parsed_track = TRACK_DST; + else if (strcasecmp(th_track, "by_src") == 0) + parsed_track = TRACK_SRC; + else if (strcasecmp(th_track, "by_either") == 0) { + parsed_track = TRACK_EITHER; + } else { + SCLogError("Invalid track parameter %s in %s", th_track, rule_extend); + goto error; + } + } + break; + } + + if (StringParseUint32(&id, 10, sizeof(th_sid), th_sid) <= 0) { + goto error; + } + + if (StringParseUint32(&gid, 10, sizeof(th_gid), th_gid) <= 0) { + goto error; + } + + *ret_id = id; + *ret_gid = gid; + *ret_parsed_type = parsed_type; + *ret_parsed_track = parsed_track; + *ret_parsed_new_action = parsed_new_action; + *ret_parsed_count = parsed_count; + *ret_parsed_seconds = parsed_seconds; + *ret_parsed_timeout = parsed_timeout; + *ret_th_ip = NULL; + if (th_ip != NULL) { + *ret_th_ip = (char *)th_ip; + } + pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend); + return 0; + +error: + if (rule_extend != NULL) { + pcre2_substring_free((PCRE2_UCHAR8 *)rule_extend); + } + if (th_ip != NULL) { + pcre2_substring_free((PCRE2_UCHAR8 *)th_ip); + } + return -1; +} + +/** + * \brief Parses a line from the threshold file and applies it to the + * detection engine + * + * \param rawstr Pointer to the string to be parsed. + * \param de_ctx Pointer to the Detection Engine Context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) +{ + uint8_t parsed_type = 0; + uint8_t parsed_track = 0; + uint8_t parsed_new_action = 0; + uint32_t parsed_count = 0; + uint32_t parsed_seconds = 0; + uint32_t parsed_timeout = 0; + char *th_ip = NULL; + uint32_t id = 0, gid = 0; + + int r = ParseThresholdRule(de_ctx, rawstr, &id, &gid, &parsed_type, &parsed_track, + &parsed_count, &parsed_seconds, &parsed_timeout, &parsed_new_action, &th_ip); + if (r < 0) + goto error; + + if (parsed_type == TYPE_SUPPRESS) { + r = SetupSuppressRule(de_ctx, id, gid, parsed_type, parsed_track, parsed_count, + parsed_seconds, parsed_timeout, parsed_new_action, th_ip); + } else { + r = SetupThresholdRule(de_ctx, id, gid, parsed_type, parsed_track, parsed_count, + parsed_seconds, parsed_timeout, parsed_new_action, th_ip); + } + if (r < 0) { + goto error; + } + + pcre2_substring_free((PCRE2_UCHAR8 *)th_ip); + return 0; +error: + if (th_ip != NULL) + pcre2_substring_free((PCRE2_UCHAR8 *)th_ip); + return -1; +} + +/** + * \brief Checks if a string is a comment or a blank line. + * + * Comments lines are lines of the following format - + * "# This is a comment string" or + * " # This is a comment string". + * + * \param line String that has to be checked + * + * \retval 1 On the argument string being a comment or blank line + * \retval 0 Otherwise + */ +static int SCThresholdConfIsLineBlankOrComment(char *line) +{ + while (*line != '\0') { + /* we have a comment */ + if (*line == '#') + return 1; + + /* this line is neither a comment line, nor a blank line */ + if (!isspace((unsigned char)*line)) + return 0; + + line++; + } + + /* we have a blank line */ + return 1; +} + +/** + * \brief Checks if the rule is multiline, by searching an ending slash + * + * \param line String that has to be checked + * + * \retval the position of the slash making it multiline + * \retval 0 Otherwise + */ +static int SCThresholdConfLineIsMultiline(char *line) +{ + int flag = 0; + char *rline = line; + int len = strlen(line); + + while (line < rline + len && *line != '\n') { + /* we have a comment */ + if (*line == '\\') + flag = line - rline; + else if (!isspace((unsigned char)*line)) + flag = 0; + + line++; + } + + /* we have a blank line */ + return flag; +} + +/** + * \brief Parses the Threshold Config file + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param fd Pointer to file descriptor. + */ +int SCThresholdConfParseFile(DetectEngineCtx *de_ctx, FILE *fp) +{ + char line[8192] = ""; + int rule_num = 0; + + /* position of "\", on multiline rules */ + int esc_pos = 0; + + if (fp == NULL) + return -1; + + while (fgets(line + esc_pos, (int)sizeof(line) - esc_pos, fp) != NULL) { + if (SCThresholdConfIsLineBlankOrComment(line)) { + continue; + } + + esc_pos = SCThresholdConfLineIsMultiline(line); + if (esc_pos == 0) { + if (SCThresholdConfAddThresholdtype(line, de_ctx) < 0) { + if (RunmodeGetCurrent() == RUNMODE_CONF_TEST) + return -1; + } else { + SCLogDebug("Adding threshold.config rule num %" PRIu32 "( %s )", rule_num, line); + rule_num++; + } + } + } + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) + SCLogInfo("tenant id %d: Threshold config parsed: %d rule(s) found", de_ctx->tenant_id, + rule_num); + else + SCLogInfo("Threshold config parsed: %d rule(s) found", rule_num); + return 0; +} + +#ifdef UNITTESTS +#include "detect-engine-alert.h" +#include "packet.h" +#include "action-globals.h" + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD01(void) +{ + FILE *fd = NULL; + const char *buffer = + "event_filter gen_id 1, sig_id 10, type limit, track by_src, count 1, seconds 60\n" + "threshold gen_id 1, sig_id 100, type both, track by_dst, count 10, seconds 60\n" + "event_filter gen_id 1, sig_id 1000, type threshold, track by_src, count 100, seconds " + "60\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with some valid options and a couple of invalid options. + * For testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateInvalidDummyFD02(void) +{ + FILE *fd; + const char *buffer = "event_filter gen_id 1, sig_id 1000, type invalid, track by_src, count " + "100, seconds 60\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD03(void) +{ + FILE *fd; + const char *buffer = "event_filter gen_id 0, sig_id 0, type threshold, track by_src, count " + "100, seconds 60\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with split rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD04(void) +{ + FILE *fd = NULL; + const char *buffer = "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, " + "\\\ncount 1, seconds 60\n" + "threshold gen_id 1, \\\nsig_id 100, type both\\\n, track by_dst, count " + "10, \\\n seconds 60\n" + "event_filter gen_id 1, sig_id 1000, \\\ntype threshold, track " + "\\\nby_src, count 100, seconds 60\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD05(void) +{ + FILE *fd = NULL; + const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_src, count 1, seconds 60, " + "new_action drop, timeout 10\n" + "rate_filter gen_id 1, sig_id 100, track by_dst, count 10, seconds 60, " + "new_action pass, timeout 5\n" + "rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, " + "new_action alert, timeout 30\n" + "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, seconds " + "60, new_action reject, timeout 21\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with split rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD06(void) +{ + FILE *fd = NULL; + const char *buffer = "rate_filter \\\ngen_id 1, sig_id 10, track by_src, count 1, seconds " + "60\\\n, new_action drop, timeout 10\n" + "rate_filter gen_id 1, \\\nsig_id 100, track by_dst, \\\ncount 10, " + "seconds 60, new_action pass, timeout 5\n" + "rate_filter gen_id 1, sig_id 1000, \\\ntrack by_rule, count 100, seconds " + "60, new_action alert, timeout 30\n" + "rate_filter gen_id 1, sig_id 10000, track by_both, count 1000, " + "\\\nseconds 60, new_action reject, timeout 21\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with split rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD07(void) +{ + FILE *fd = NULL; + const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_src, count 3, seconds 3, " + "new_action drop, timeout 10\n" + "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, " + "new_action drop, timeout 5\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, for testing rate_filter, track by_rule + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD08(void) +{ + FILE *fd = NULL; + const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_rule, count 3, seconds 3, " + "new_action drop, timeout 10\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with split rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD09(void) +{ + FILE *fd = NULL; + const char *buffer = "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, " + "\\\ncount 2, seconds 60\n" + "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, " + "count 3, \\\n seconds 60\n" + "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count " + "2, seconds 60\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with split rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD10(void) +{ + FILE *fd = NULL; + const char *buffer = "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, " + "\\\ncount 5, seconds 2\n" + "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, " + "count 5, \\\n seconds 2\n" + "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count " + "5, seconds 2\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD11(void) +{ + FILE *fd = NULL; + const char *buffer = "suppress gen_id 1, sig_id 10000\n" + "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + + FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && + de->seconds == 60); + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest02(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + + FAIL_IF_NOT(de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && + de->seconds == 60); + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest03(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && + de->seconds == 60); + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest04(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD02(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NOT_NULL(m); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest05(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD03(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + Signature *s = de_ctx->sig_list; + SigMatch *m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && + de->seconds == 60); + + s = de_ctx->sig_list->next; + m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && + de->seconds == 60); + + s = de_ctx->sig_list->next->next; + m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && + de->seconds == 60); + + PASS; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest06(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && + de->seconds == 60); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the rate_filter rules are loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest07(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = + DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, DETECT_DETECTION_FILTER, -1); + FAIL_IF_NULL(m); + + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT( + de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the rate_filter rules are loaded and well parsed + * with multilines + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest08(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = + DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, DETECT_DETECTION_FILTER, -1); + FAIL_IF_NULL(m); + + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT( + de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the rate_filter rules work + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest09(void) +{ + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + HostInitConfig(HOST_QUIET); + + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); + + DetectEngineThreadCtx *det_ctx = NULL; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->ts = TimeGet(); + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); + + TimeSetIncrementTime(2); + p->ts = TimeGet(); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP))); + + TimeSetIncrementTime(3); + p->ts = TimeGet(); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(p->alerts.cnt != 1 || !(PacketTestAction(p, ACTION_DROP))); + + TimeSetIncrementTime(10); + p->ts = TimeGet(); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(p->alerts.cnt != 1 || PacketTestAction(p, ACTION_DROP)); + + UTHFreePacket(p); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \test Check if the rate_filter rules work with track by_rule + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest10(void) +{ + HostInitConfig(HOST_QUIET); + + /* Create two different packets falling to the same rule, and + * because count:3, we should drop on match #4. + */ + Packet *p1 = + UTHBuildPacketSrcDst((uint8_t *)"lalala", 6, IPPROTO_TCP, "172.26.0.2", "172.26.0.11"); + FAIL_IF_NULL(p1); + Packet *p2 = + UTHBuildPacketSrcDst((uint8_t *)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); + FAIL_IF_NULL(p2); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; + + Signature *s = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + p1->ts = TimeGet(); + p2->ts = p1->ts; + + /* All should be alerted, none dropped */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + p1->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + FAIL_IF(PacketTestAction(p2, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p2, 10) != 1); + p2->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + p1->action = 0; + + /* Match #4 should be dropped*/ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p2, 10) != 1); + p2->action = 0; + + TimeSetIncrementTime(2); + p1->ts = TimeGet(); + + /* Still dropped because timeout not expired */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + p1->action = 0; + + TimeSetIncrementTime(10); + p1->ts = TimeGet(); + + /* Not dropped because timeout expired */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + + /* Ensure that a Threshold entry was installed at the sig */ + FAIL_IF_NULL(de_ctx->ths_ctx.th_entry[s->num]); + + UTHFreePacket(p1); + UTHFreePacket(p2); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \test Check if the rate_filter rules work + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest11(void) +{ + HostInitConfig(HOST_QUIET); + + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->ts = TimeGet(); + + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + TimeSetIncrementTime(100); + p->ts = TimeGet(); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + + TimeSetIncrementTime(10); + p->ts = TimeGet(); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + FAIL_IF_NOT(alerts10 == 4); + /* One on the first interval, another on the second */ + FAIL_IF_NOT(alerts11 == 2); + FAIL_IF_NOT(alerts12 == 2); + + UTHFreePacket(p); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \test Check if the rate_filter rules work + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest12(void) +{ + HostInitConfig(HOST_QUIET); + + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->ts = TimeGet(); + + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + TimeSetIncrementTime(100); + p->ts = TimeGet(); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + + TimeSetIncrementTime(10); + p->ts = TimeGet(); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + FAIL_IF_NOT(alerts10 == 10); + /* One on the first interval, another on the second */ + FAIL_IF_NOT(alerts11 == 1); + FAIL_IF_NOT(alerts12 == 1); + + UTHFreePacket(p); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest13(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_SUPPRESS, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test Check if the suppress rules work + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest14(void) +{ + HostInitConfig(HOST_QUIET); + + Packet *p1 = UTHBuildPacketReal( + (uint8_t *)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); + FAIL_IF_NULL(p1); + Packet *p2 = UTHBuildPacketReal( + (uint8_t *)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); + FAIL_IF_NULL(p2); + + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig( + de_ctx, "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0); + FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1); + FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1); + FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0); + + UTHFreePacket(p1); + UTHFreePacket(p2); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + PASS; +} + +/** + * \test Check if the suppress rules work + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest15(void) +{ + HostInitConfig(HOST_QUIET); + + Packet *p = UTHBuildPacketReal( + (uint8_t *)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); + FAIL_IF_NULL(p); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = + DetectEngineAppendSig(de_ctx, "drop tcp any any -> any any (msg:\"suppress test\"; " + "content:\"lalala\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + /* 10000 shouldn't match */ + FAIL_IF(PacketAlertCheck(p, 10000) != 0); + /* however, it should have set the drop flag */ + FAIL_IF(!(PacketTestAction(p, ACTION_DROP))); + + UTHFreePacket(p); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \test Check if the suppress rules work + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest16(void) +{ + HostInitConfig(HOST_QUIET); + + Packet *p = UTHBuildPacketReal( + (uint8_t *)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); + FAIL_IF_NULL(p); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig( + de_ctx, "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1000) != 0); + /* however, it should have set the drop flag */ + FAIL_IF(!(PacketTestAction(p, ACTION_DROP))); + + UTHFreePacket(p); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \test Check if the suppress rules work - ip only rule + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest17(void) +{ + HostInitConfig(HOST_QUIET); + + Packet *p = UTHBuildPacketReal( + (uint8_t *)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); + FAIL_IF_NULL(p); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig(de_ctx, "drop tcp 192.168.0.10 any -> 192.168.0.100 any " + "(msg:\"suppress test\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + /* 10000 shouldn't match */ + FAIL_IF(PacketAlertCheck(p, 10000) != 0); + /* however, it should have set the drop flag */ + FAIL_IF(!(PacketTestAction(p, ACTION_DROP))); + + UTHFreePacket(p); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateInvalidDummyFD12(void) +{ + FILE *fd = NULL; + const char *buffer = "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n" + "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \test Check if the suppress rule parsing handles errors correctly + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest18(void) +{ + HostInitConfig(HOST_QUIET); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any " + "(msg:\"suppress test\"; gid:1; sid:2200029;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + SigGroupBuild(de_ctx); + + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); + + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateInvalidDummyFD13(void) +{ + FILE *fd = NULL; + const char *buffer = "suppress gen_id 1, sig_id 2200029, track by_stc, ip fe80::/16\n" + "suppress gen_id 1, sig_id 2200029, track by_dst, ip fe80::/16\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \test Check if the suppress rule parsing handles errors correctly + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest19(void) +{ + HostInitConfig(HOST_QUIET); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any " + "(msg:\"suppress test\"; gid:1; sid:2200029;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + SigGroupBuild(de_ctx); + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD20(void) +{ + FILE *fd = NULL; + const char *buffer = "suppress gen_id 1, sig_id 1000, track by_src, ip 2.2.3.4\n" + "suppress gen_id 1, sig_id 1000, track by_src, ip 1.2.3.4\n" + "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest20(void) +{ + HostInitConfig(HOST_QUIET); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + SigGroupBuild(de_ctx); + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF_NOT(smd->is_last); + + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \test Check if the threshold file is loaded and well parsed, and applied + * correctly to a rule with thresholding + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest21(void) +{ + HostInitConfig(HOST_QUIET); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + FAIL_IF_NULL(s); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + SigGroupBuild(de_ctx); + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF_NOT(smd->is_last); + + DetectEngineCtxFree(de_ctx); + HostShutdown(); + PASS; +} + +/** + * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and + * destination + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD22(void) +{ + FILE *fd = NULL; + const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_both, count 2, seconds 5, " + "new_action drop, timeout 6\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \test Check if the rate_filter rules work with track by_both + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest22(void) +{ + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + IPPairInitConfig(IPPAIR_QUIET); + + /* This packet will cause rate_filter */ + Packet *p1 = + UTHBuildPacketSrcDst((uint8_t *)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); + FAIL_IF_NULL(p1); + + /* Should not be filtered for different destination */ + Packet *p2 = + UTHBuildPacketSrcDst((uint8_t *)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.2"); + FAIL_IF_NULL(p2); + + /* Should not be filtered when both src and dst the same */ + Packet *p3 = + UTHBuildPacketSrcDst((uint8_t *)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.1"); + FAIL_IF_NULL(p3); + + DetectEngineThreadCtx *det_ctx = NULL; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD22(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p1->ts = TimeGet(); + p2->ts = p3->ts = p1->ts; + + /* All should be alerted, none dropped */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + FAIL_IF(PacketTestAction(p2, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p2, 10) != 1); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); + FAIL_IF(PacketTestAction(p3, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p3, 10) != 1); + + p1->action = p2->action = p3->action = 0; + + TimeSetIncrementTime(2); + p1->ts = TimeGet(); + p2->ts = p3->ts = p1->ts; + + /* p1 still shouldn't be dropped after 2nd alert */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + + p1->action = 0; + + TimeSetIncrementTime(2); + p1->ts = TimeGet(); + p2->ts = p3->ts = p1->ts; + + /* All should be alerted, only p1 must be dropped due to rate_filter*/ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF_NOT(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + FAIL_IF(PacketTestAction(p2, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p2, 10) != 1); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); + FAIL_IF(PacketTestAction(p3, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p3, 10) != 1); + + p1->action = p2->action = p3->action = 0; + + TimeSetIncrementTime(7); + p1->ts = TimeGet(); + p2->ts = p3->ts = p1->ts; + + /* All should be alerted, none dropped (because timeout expired) */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + FAIL_IF(PacketTestAction(p2, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p2, 10) != 1); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p3); + FAIL_IF(PacketTestAction(p3, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p3, 10) != 1); + + UTHFreePacket(p3); + UTHFreePacket(p2); + UTHFreePacket(p1); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + IPPairShutdown(); + PASS; +} + +/** + * \brief Creates a dummy rate_filter file, for testing rate filtering by_both source and + * destination + * + * \retval fd Pointer to file descriptor. + */ +static FILE *SCThresholdConfGenerateValidDummyFD23(void) +{ + FILE *fd = NULL; + const char *buffer = "rate_filter gen_id 1, sig_id 10, track by_both, count 1, seconds 5, " + "new_action drop, timeout 6\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \test Check if the rate_filter by_both work when similar packets + * going in opposite direction + * + * \retval 1 on success + * \retval 0 on failure + */ +static int SCThresholdConfTest23(void) +{ + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + + IPPairInitConfig(IPPAIR_QUIET); + + /* Create two packets between same addresses in opposite direction */ + Packet *p1 = + UTHBuildPacketSrcDst((uint8_t *)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); + FAIL_IF_NULL(p1); + + Packet *p2 = + UTHBuildPacketSrcDst((uint8_t *)"lalala", 6, IPPROTO_TCP, "172.26.0.10", "172.26.0.1"); + FAIL_IF_NULL(p2); + + DetectEngineThreadCtx *det_ctx = NULL; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"ratefilter by_both test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD23(); + FAIL_IF_NULL(g_ut_threshold_fp); + FAIL_IF(-1 == SCThresholdConfInitContext(de_ctx)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p1->ts = TimeGet(); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + /* First packet should be alerted, not dropped */ + FAIL_IF(PacketTestAction(p1, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p1, 10) != 1); + + TimeSetIncrementTime(2); + p2->ts = TimeGet(); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + /* Second packet should be dropped because it considered as "the same pair" + and rate_filter count reached*/ + FAIL_IF_NOT(PacketTestAction(p2, ACTION_DROP)); + FAIL_IF(PacketAlertCheck(p2, 10) != 1); + + UTHFreePacket(p2); + UTHFreePacket(p1); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + IPPairShutdown(); + PASS; +} +#endif /* UNITTESTS */ + +/** + * \brief This function registers unit tests for Classification Config API. + */ +void SCThresholdConfRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01); + UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02); + UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03); + UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04); + UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05); + UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06); + UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07); + UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08); + UtRegisterTest("SCThresholdConfTest09 - rate_filter", SCThresholdConfTest09); + UtRegisterTest("SCThresholdConfTest10 - rate_filter", SCThresholdConfTest10); + UtRegisterTest("SCThresholdConfTest11 - event_filter", SCThresholdConfTest11); + UtRegisterTest("SCThresholdConfTest12 - event_filter", SCThresholdConfTest12); + UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13); + UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14); + UtRegisterTest("SCThresholdConfTest15 - suppress drop", SCThresholdConfTest15); + UtRegisterTest("SCThresholdConfTest16 - suppress drop", SCThresholdConfTest16); + UtRegisterTest("SCThresholdConfTest17 - suppress drop", SCThresholdConfTest17); + + UtRegisterTest("SCThresholdConfTest18 - suppress parsing", SCThresholdConfTest18); + UtRegisterTest("SCThresholdConfTest19 - suppress parsing", SCThresholdConfTest19); + UtRegisterTest("SCThresholdConfTest20 - suppress parsing", SCThresholdConfTest20); + UtRegisterTest("SCThresholdConfTest21 - suppress parsing", SCThresholdConfTest21); + UtRegisterTest("SCThresholdConfTest22 - rate_filter by_both", SCThresholdConfTest22); + UtRegisterTest("SCThresholdConfTest23 - rate_filter by_both opposite", SCThresholdConfTest23); + +#endif /* UNITTESTS */ +} + +/** + * @} + */ diff --git a/src/util-threshold-config.h b/src/util/threshold-config.h similarity index 100% rename from src/util-threshold-config.h rename to src/util/threshold-config.h diff --git a/src/util/time.c b/src/util/time.c new file mode 100644 index 000000000000..2189c866cc1b --- /dev/null +++ b/src/util/time.c @@ -0,0 +1,640 @@ +/* Copyright (C) 2007-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Ken Steele + * + * Time keeping for offline (non-live) packet handling (pcap files). + * And time string generation for alerts. + */ + +/* Real time vs offline time + * + * When we run on live traffic, time handling is simple. Packets have a + * timestamp set by the capture method. Management threads can simply + * use 'gettimeofday' to know the current time. There should never be + * any serious gap between the two. + * + * In offline mode, things are dramatically different. Here we try to keep + * the time from the pcap, which means that if the packets are in 2011 the + * log output should also reflect this. Multiple issues: + * 1. merged pcaps might have huge time jumps or time going backward + * 2. slowly recorded pcaps may be processed much faster than their 'realtime' + * 3. management threads need a concept of what the 'current' time is for + * enforcing timeouts + * 4. due to (1) individual threads may have very different views on what + * the current time is. E.g. T1 processed packet 1 with TS X, while T2 + * at the very same time processes packet 2 with TS X+100000s. + * + * In offline mode we keep the timestamp per thread. If a management thread + * needs current time, it will get the minimum of the threads' values. This + * is to avoid the problem that T2s time value might already trigger a flow + * timeout as the flow lastts + 100000s is almost certainly meaning the flow + * would be considered timed out. + */ + +#ifdef OS_WIN32 +/* for MinGW we need to set _POSIX_C_SOURCE before including + * sys/time.h. */ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#endif + +#include "suricata-common.h" +#include "suricata.h" +#include "../detect.h" +#include "threads.h" +#include "tm-threads.h" +#include "util/debug.h" +#include "util/time.h" + +#ifdef UNITTESTS +static struct timeval current_time = { 0, 0 }; +#endif +// static SCMutex current_time_mutex = SCMUTEX_INITIALIZER; +static SCSpinlock current_time_spinlock; +static bool live_time_tracking = true; + +struct tm *SCLocalTime(time_t timep, struct tm *result); +struct tm *SCUtcTime(time_t timep, struct tm *result); + +void TimeInit(void) +{ + SCSpinInit(¤t_time_spinlock, 0); + + /* Initialize Time Zone settings. */ + tzset(); +} + +void TimeDeinit(void) +{ + SCSpinDestroy(¤t_time_spinlock); +} + +bool TimeModeIsReady(void) +{ + if (live_time_tracking) + return true; + return TmThreadsTimeSubsysIsReady(); +} + +void TimeModeSetLive(void) +{ + live_time_tracking = true; + SCLogDebug("live time mode enabled"); +} + +void TimeModeSetOffline(void) +{ + live_time_tracking = false; + SCLogDebug("offline time mode enabled"); +} + +bool TimeModeIsLive(void) +{ + return live_time_tracking; +} + +void TimeSetByThread(const int thread_id, SCTime_t tv) +{ + if (live_time_tracking) + return; + + TmThreadsSetThreadTimestamp(thread_id, tv); +} + +#ifdef UNITTESTS +void TimeSet(SCTime_t ts) +{ + if (live_time_tracking) + return; + + SCSpinLock(¤t_time_spinlock); + SCTIME_TO_TIMEVAL(¤t_time, ts); + + SCLogDebug("time set to %" PRIuMAX " sec, %" PRIuMAX " usec", (uintmax_t)current_time.tv_sec, + (uintmax_t)current_time.tv_usec); + + SCSpinUnlock(¤t_time_spinlock); +} + +/** \brief set the time to "gettimeofday" meant for testing */ +void TimeSetToCurrentTime(void) +{ + struct timeval tv; + memset(&tv, 0x00, sizeof(tv)); + + gettimeofday(&tv, NULL); + + SCTime_t ts = SCTIME_FROM_TIMEVAL(&tv); + TimeSet(ts); +} +#endif + +SCTime_t TimeGet(void) +{ + struct timeval tv = { 0 }; + if (live_time_tracking) { + gettimeofday(&tv, NULL); + } else { +#ifdef UNITTESTS + if (unlikely(RunmodeIsUnittests())) { + SCSpinLock(¤t_time_spinlock); + tv.tv_sec = current_time.tv_sec; + tv.tv_usec = current_time.tv_usec; + SCSpinUnlock(¤t_time_spinlock); + } else { +#endif + TmThreadsGetMinimalTimestamp(&tv); +#ifdef UNITTESTS + } +#endif + } + + SCLogDebug("time we got is %" PRIuMAX " sec, %" PRIuMAX " usec", (uintmax_t)tv.tv_sec, + (uintmax_t)tv.tv_usec); + return SCTIME_FROM_TIMEVAL(&tv); +} + +#ifdef UNITTESTS +/** \brief increment the time in the engine + * \param tv_sec seconds to increment the time with */ +void TimeSetIncrementTime(uint32_t tv_sec) +{ + SCTime_t ts = TimeGet(); + + ts = SCTIME_ADD_SECS(ts, tv_sec); + + TimeSet(ts); +} +#endif + +#ifdef OS_WIN32 +/** \internal + * \brief wrapper around strftime on Windows to provide output + * compatible with posix %z + */ +static inline void WinStrftime(const SCTime_t ts, const struct tm *t, char *str, size_t size) +{ + char time_fmt[64] = { 0 }; + char tz[6] = { 0 }; + const long int tzdiff = -_timezone; + const int h = abs(_timezone) / 3600 + _daylight; + const int m = (abs(_timezone) % 3600) / 60; + snprintf(tz, sizeof(tz), "%c%02d%02d", tzdiff < 0 ? '-' : '+', h, m); + strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S.%%06u", t); + snprintf(str, size, time_fmt, SCTIME_USECS(ts)); + strlcat(str, tz, size); // append our timezone +} +#endif + +void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size) +{ + time_t time = SCTIME_SECS(ts); + struct tm local_tm; + memset(&local_tm, 0, sizeof(local_tm)); + struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); + + if (likely(t != NULL)) { +#ifdef OS_WIN32 + WinStrftime(ts, t, str, size); +#else + char time_fmt[64] = { 0 }; + int64_t usec = SCTIME_USECS(ts); + strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S.%%06" PRIi64 "%z", t); + snprintf(str, size, time_fmt, usec); +#endif + } else { + snprintf(str, size, "ts-error"); + } +} + +void CreateUtcIsoTimeString(const SCTime_t ts, char *str, size_t size) +{ + time_t time = SCTIME_SECS(ts); + struct tm local_tm; + memset(&local_tm, 0, sizeof(local_tm)); + struct tm *t = (struct tm *)SCUtcTime(time, &local_tm); + + if (likely(t != NULL)) { + char time_fmt[64] = { 0 }; + strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S", t); + snprintf(str, size, time_fmt, SCTIME_USECS(ts)); + } else { + snprintf(str, size, "ts-error"); + } +} + +void CreateFormattedTimeString(const struct tm *t, const char *fmt, char *str, size_t size) +{ + if (likely(t != NULL)) { + strftime(str, size, fmt, t); + } else { + snprintf(str, size, "ts-error"); + } +} + +struct tm *SCUtcTime(time_t timep, struct tm *result) +{ + return gmtime_r(&timep, result); +} + +/* + * Time Caching code + */ + +#ifndef TLS +/* OpenBSD does not support thread_local, so don't use time caching on BSD + */ +struct tm *SCLocalTime(time_t timep, struct tm *result) +{ + return localtime_r(&timep, result); +} + +void CreateTimeString(const SCTime_t ts, char *str, size_t size) +{ + time_t time = SCTIME_SECS(ts); + struct tm local_tm; + struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); + + if (likely(t != NULL)) { + snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, + t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t)SCTIME_USECS(ts)); + } else { + snprintf(str, size, "ts-error"); + } +} + +#else + +/* On systems supporting thread_local, use Per-thread values for caching + * in CreateTimeString */ + +/* The maximum possible length of the time string. + * "%02d/%02d/%02d-%02d:%02d:%02d.%06u" + * Or "01/01/2013-15:42:21.123456", which is 26, so round up to 32. */ +#define MAX_LOCAL_TIME_STRING 32 + +static thread_local int mru_time_slot; /* Most recently used cached value */ +static thread_local time_t last_local_time[2]; +static thread_local short int cached_local_time_len[2]; +static thread_local char cached_local_time[2][MAX_LOCAL_TIME_STRING]; + +/* Per-thread values for caching SCLocalTime() These cached values are + * independent from the CreateTimeString cached values. */ +static thread_local int mru_tm_slot; /* Most recently used local tm */ +static thread_local time_t cached_minute_start[2]; +static thread_local struct tm cached_local_tm[2]; + +/** \brief Convert time_t into Year, month, day, hour and minutes. + * \param timep Time in seconds since defined date. + * \param result The structure into which the broken down time it put. + * + * To convert a time in seconds into year, month, day, hours, minutes + * and seconds, call localtime_r(), which uses the current time zone + * to compute these values. Note, glibc's localtime_r() acquires a lock + * each time it is called, which limits parallelism. To call + * localtime_r() less often, the values returned are cached for the + * current and previous minute and then seconds are adjusted to + * compute the returned result. This is valid as long as the + * difference between the start of the current minute and the current + * time is less than 60 seconds. Once the minute value changes, all + * the other values could change. + * + * Two values are cached to prevent thrashing when changing from one + * minute to the next. The two cached minutes are independent and are + * not required to be M and M+1. If more than two minutes are + * requested, the least-recently-used cached value is updated more + * often, the results are still correct, but performance will be closer + * to previous performance. + */ +struct tm *SCLocalTime(time_t timep, struct tm *result) +{ + /* Only get a new local time when the time crosses into a new + * minute. */ + int mru = mru_tm_slot; + int lru = 1 - mru; + int mru_seconds = timep - cached_minute_start[mru]; + int lru_seconds = timep - cached_minute_start[lru]; + int new_seconds; + if (cached_minute_start[mru] == 0 && cached_minute_start[lru] == 0) { + localtime_r(&timep, &cached_local_tm[lru]); + /* Subtract seconds to get back to the start of the minute. */ + new_seconds = cached_local_tm[lru].tm_sec; + cached_minute_start[lru] = timep - new_seconds; + mru = lru; + mru_tm_slot = mru; + } else if (lru_seconds > 0 && (mru_seconds >= 0 && mru_seconds <= 59)) { + /* Use most-recently cached time, adjusting the seconds. */ + new_seconds = mru_seconds; + } else if (mru_seconds > 0 && (lru_seconds >= 0 && lru_seconds <= 59)) { + /* Use least-recently cached time, update to most recently used. */ + new_seconds = lru_seconds; + mru = lru; + mru_tm_slot = mru; + } else { + /* Update least-recent cached time. */ + if (localtime_r(&timep, &cached_local_tm[lru]) == NULL) + return NULL; + /* Subtract seconds to get back to the start of the minute. */ + new_seconds = cached_local_tm[lru].tm_sec; + cached_minute_start[lru] = timep - new_seconds; + mru = lru; + mru_tm_slot = mru; + } + memcpy(result, &cached_local_tm[mru], sizeof(struct tm)); + result->tm_sec = new_seconds; + + return result; +} + +/* Update the cached time string in cache index N, for the current minute. */ +static int UpdateCachedTime(int n, time_t time) +{ + struct tm local_tm; + struct tm *t = (struct tm *)SCLocalTime(time, &local_tm); + int cached_len = snprintf(cached_local_time[n], MAX_LOCAL_TIME_STRING, + "%02d/%02d/%02d-%02d:%02d:", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, + t->tm_min); + cached_local_time_len[n] = cached_len; + /* Store the time of the beginning of the minute. */ + last_local_time[n] = time - t->tm_sec; + mru_time_slot = n; + + return t->tm_sec; +} + +/** \brief Return a formatted string for the provided time. + * + * Cache the Month/Day/Year - Hours:Min part of the time string for + * the current minute. Copy that result into the return string and + * then only print the seconds for each call. + */ +void CreateTimeString(const SCTime_t ts, char *str, size_t size) +{ + time_t time = SCTIME_SECS(ts); + int seconds; + + /* Only get a new local time when the time crosses into a new + * minute */ + int mru = mru_time_slot; + int lru = 1 - mru; + int mru_seconds = time - last_local_time[mru]; + int lru_seconds = time - last_local_time[lru]; + if (last_local_time[mru] == 0 && last_local_time[lru] == 0) { + /* First time here, update both caches */ + UpdateCachedTime(mru, time); + seconds = UpdateCachedTime(lru, time); + } else if (mru_seconds >= 0 && mru_seconds <= 59) { + /* Use most-recently cached time. */ + seconds = mru_seconds; + } else if (lru_seconds >= 0 && lru_seconds <= 59) { + /* Use least-recently cached time. Change this slot to Most-recent */ + seconds = lru_seconds; + mru_time_slot = lru; + } else { + /* Update least-recent cached time. Lock accessing local time + * function because it keeps any internal non-spin lock. */ + seconds = UpdateCachedTime(lru, time); + } + + /* Copy the string up to the current minute then print the seconds + into the return string buffer. */ + char *cached_str = cached_local_time[mru_time_slot]; + int cached_len = cached_local_time_len[mru_time_slot]; + if (cached_len >= (int)size) + cached_len = size; + memcpy(str, cached_str, cached_len); + snprintf(str + cached_len, size - cached_len, "%02d.%06u", seconds, (uint32_t)SCTIME_USECS(ts)); +} + +#endif /* defined(__OpenBSD__) */ + +/** + * \brief Convert broken-down time to seconds since Unix epoch. + * + * This function is based on: http://www.catb.org/esr/time-programming + * (released to the public domain). + * + * \param tp Pointer to broken-down time. + * + * \retval Seconds since Unix epoch. + */ +time_t SCMkTimeUtc(struct tm *tp) +{ + time_t result; + long year; +#define MONTHSPERYEAR 12 + static const int mdays[MONTHSPERYEAR] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, + 334 }; + + year = 1900 + tp->tm_year + tp->tm_mon / MONTHSPERYEAR; + result = (year - 1970) * 365 + mdays[tp->tm_mon % MONTHSPERYEAR]; + result += (year - 1968) / 4; + result -= (year - 1900) / 100; + result += (year - 1600) / 400; + if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) && + (tp->tm_mon % MONTHSPERYEAR) < 2) + result--; + result += tp->tm_mday - 1; + result *= 24; + result += tp->tm_hour; + result *= 60; + result += tp->tm_min; + result *= 60; + result += tp->tm_sec; +#ifndef OS_WIN32 + if (tp->tm_gmtoff) + result -= tp->tm_gmtoff; +#endif + return result; +} + +/** + * \brief Parse a date string based on specified patterns. + * + * This function is based on GNU C library getdate. + * + * \param string Date string to parse. + * \param patterns String array containing patterns. + * \param num_patterns Number of patterns to check. + * \param tp Pointer to broken-down time. + * + * \retval 0 on success. + * \retval 1 on failure. + */ +int SCStringPatternToTime(char *string, const char **patterns, int num_patterns, struct tm *tp) +{ + char *result = NULL; + int i = 0; + + /* Do the pattern matching */ + for (i = 0; i < num_patterns; i++) { + if (patterns[i] == NULL) + continue; + + tp->tm_hour = tp->tm_min = tp->tm_sec = 0; + tp->tm_year = tp->tm_mon = tp->tm_mday = tp->tm_wday = INT_MIN; + tp->tm_isdst = -1; +#ifndef OS_WIN32 + tp->tm_gmtoff = 0; + tp->tm_zone = NULL; +#endif + result = strptime(string, patterns[i], tp); + + if (result && *result == '\0') + break; + } + + /* Return if no patterns matched */ + if (result == NULL || *result != '\0') + return 1; + + /* Return if no date is given */ + if (tp->tm_year == INT_MIN && tp->tm_mon == INT_MIN && tp->tm_mday == INT_MIN) + return 1; + + /* The first of the month is assumed, if only year and + month is given */ + if (tp->tm_year != INT_MIN && tp->tm_mon != INT_MIN && tp->tm_mday <= 0) + tp->tm_mday = 1; + + return 0; +} + +/** + * \brief Convert epoch time to string pattern. + * + * This function converts epoch time to a string based on a pattern. + * + * \param epoch Epoch time. + * \param pattern String pattern. + * \param str Formated string. + * \param size Size of allocated string. + * + * \retval 0 on success. + * \retval 1 on failure. + */ +int SCTimeToStringPattern(time_t epoch, const char *pattern, char *str, size_t size) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); + char buffer[PATH_MAX] = { 0 }; + + if (unlikely(tp == NULL)) { + return 1; + } + + int r = strftime(buffer, sizeof(buffer), pattern, tp); + if (r == 0) { + return 1; + } + + strlcpy(str, buffer, size); + + return 0; +} + +/** + * \brief Parse string containing time size (1m, 1h, etc). + * + * \param str String to parse. + * + * \retval size on success. + * \retval 0 on failure. + */ +uint64_t SCParseTimeSizeString(const char *str) +{ + uint64_t size = 0; + uint64_t modifier = 1; + char last = str[strlen(str) - 1]; + + switch (last) { + case '0' ... '9': + break; + /* seconds */ + case 's': + break; + /* minutes */ + case 'm': + modifier = 60; + break; + /* hours */ + case 'h': + modifier = 60 * 60; + break; + /* days */ + case 'd': + modifier = 60 * 60 * 24; + break; + /* weeks */ + case 'w': + modifier = 60 * 60 * 24 * 7; + break; + /* invalid */ + default: + return 0; + } + + errno = 0; + size = strtoumax(str, NULL, 10); + if (errno) { + return 0; + } + + return (size * modifier); +} + +/** + * \brief Get seconds until a time unit changes. + * + * \param str String containing time type (minute, hour, etc). + * \param epoch Epoch time. + * + * \retval seconds. + */ +uint64_t SCGetSecondsUntil(const char *str, time_t epoch) +{ + uint64_t seconds = 0; + struct tm tm; + memset(&tm, 0, sizeof(tm)); + struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); + + if (strcmp(str, "minute") == 0) + seconds = 60 - tp->tm_sec; + else if (strcmp(str, "hour") == 0) + seconds = (60 * (60 - tp->tm_min)) + (60 - tp->tm_sec); + else if (strcmp(str, "day") == 0) + seconds = (3600 * (24 - tp->tm_hour)) + (60 * (60 - tp->tm_min)) + (60 - tp->tm_sec); + + return seconds; +} + +uint64_t SCTimespecAsEpochMillis(const struct timespec *ts) +{ + return ts->tv_sec * 1000L + ts->tv_nsec / 1000000L; +} + +uint64_t TimeDifferenceMicros(struct timeval t0, struct timeval t1) +{ + return (uint64_t)(t1.tv_sec - t0.tv_sec) * 1000000L + (t1.tv_usec - t1.tv_usec); +} diff --git a/src/util/time.h b/src/util/time.h new file mode 100644 index 000000000000..365f088839fc --- /dev/null +++ b/src/util/time.h @@ -0,0 +1,158 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_TIME_H__ +#define __UTIL_TIME_H__ + +/* + * The SCTime_t member is broken up as + * seconds: 44 + * useconds: 20 + * + * Over 500000 years can be represented in 44 bits of seconds: + * 2^44/(365*24*60*60) + * 557855.560 + * 1048576 microseconds can be represented in 20 bits: + * 2^20 + * 1048576 + */ + +typedef struct { + uint64_t secs : 44; + uint64_t usecs : 20; +} SCTime_t; + +#define SCTIME_INIT(t) \ + { \ + (t).secs = 0; \ + (t).usecs = 0; \ + } + +#define SCTIME_INITIALIZER \ + (SCTime_t) \ + { \ + .secs = 0, .usecs = 0 \ + } +#define SCTIME_USECS(t) ((uint64_t)(t).usecs) +#define SCTIME_SECS(t) ((uint64_t)(t).secs) +#define SCTIME_MSECS(t) (SCTIME_SECS(t) * 1000 + SCTIME_USECS(t) / 1000) +#define SCTIME_ADD_SECS(ts, s) SCTIME_FROM_SECS((ts).secs + (s)) +#define SCTIME_ADD_USECS(ts, us) SCTIME_FROM_USECS((ts).usecs + (us)) +#define SCTIME_FROM_SECS(s) \ + (SCTime_t) \ + { \ + .secs = (s), .usecs = 0 \ + } +#define SCTIME_FROM_USECS(us) \ + (SCTime_t) \ + { \ + .secs = 0, .usecs = (us) \ + } +#define SCTIME_FROM_TIMEVAL(tv) \ + (SCTime_t) \ + { \ + .secs = (tv)->tv_sec, .usecs = (tv)->tv_usec \ + } +/** \brief variant to deal with potentially bad timestamps, like from pcap files */ +#define SCTIME_FROM_TIMEVAL_UNTRUSTED(tv) \ + (SCTime_t) \ + { \ + .secs = ((tv)->tv_sec > 0) ? (tv)->tv_sec : 0, \ + .usecs = ((tv)->tv_usec > 0) ? (tv)->tv_usec : 0 \ + } +#define SCTIME_FROM_TIMESPEC(ts) \ + (SCTime_t) \ + { \ + .secs = (ts)->tv_sec, .usecs = (ts)->tv_nsec * 1000 \ + } + +#define SCTIME_TO_TIMEVAL(tv, t) \ + (tv)->tv_sec = SCTIME_SECS((t)); \ + (tv)->tv_usec = SCTIME_USECS((t)); +#define SCTIME_CMP(a, b, CMP) \ + ((SCTIME_SECS(a) == SCTIME_SECS(b)) ? (SCTIME_USECS(a) CMP SCTIME_USECS(b)) \ + : (SCTIME_SECS(a) CMP SCTIME_SECS(b))) +#define SCTIME_CMP_GTE(a, b) SCTIME_CMP((a), (b), >=) +#define SCTIME_CMP_GT(a, b) SCTIME_CMP((a), (b), >) +#define SCTIME_CMP_LT(a, b) SCTIME_CMP((a), (b), <) +#define SCTIME_CMP_LTE(a, b) SCTIME_CMP((a), (b), <=) +#define SCTIME_CMP_NEQ(a, b) SCTIME_CMP((a), (b), !=) + +void TimeInit(void); +void TimeDeinit(void); + +void TimeSetByThread(const int thread_id, SCTime_t tv); +SCTime_t TimeGet(void); + +/** \brief initialize a 'struct timespec' from a 'struct timeval'. */ +#define FROM_TIMEVAL(timev) \ + { \ + .tv_sec = (timev).tv_sec, .tv_nsec = (timev).tv_usec * 1000 \ + } + +/** \brief compare two 'struct timeval' and return if the first is earlier than the second */ +static inline bool TimevalEarlier(struct timeval *first, struct timeval *second) +{ + /* from man timercmp on Linux: "Some systems (but not Linux/glibc), have a broken timercmp() + * implementation, in which CMP of >=, <=, and == do not work; portable applications can instead + * use ... !timercmp(..., >) */ + return !timercmp(first, second, >); +} + +#ifndef timeradd +#define timeradd(a, b, r) \ + do { \ + (r)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (r)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((r)->tv_usec >= 1000000) { \ + (r)->tv_sec++; \ + (r)->tv_usec -= 1000000; \ + } \ + } while (0) +#endif + +#ifdef UNITTESTS +void TimeSet(SCTime_t); +void TimeSetToCurrentTime(void); +void TimeSetIncrementTime(uint32_t); +#endif + +bool TimeModeIsReady(void); +void TimeModeSetLive(void); +void TimeModeSetOffline(void); +bool TimeModeIsLive(void); + +struct tm *SCLocalTime(time_t timep, struct tm *result); +void CreateTimeString(const SCTime_t ts, char *str, size_t size); +void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size); +void CreateUtcIsoTimeString(const SCTime_t ts, char *str, size_t size); +void CreateFormattedTimeString(const struct tm *t, const char *fmt, char *str, size_t size); +time_t SCMkTimeUtc(struct tm *tp); +int SCStringPatternToTime(char *string, const char **patterns, int num_patterns, struct tm *time); +int SCTimeToStringPattern(time_t epoch, const char *pattern, char *str, size_t size); +uint64_t SCParseTimeSizeString(const char *str); +uint64_t SCGetSecondsUntil(const char *str, time_t epoch); +uint64_t SCTimespecAsEpochMillis(const struct timespec *ts); +uint64_t TimeDifferenceMicros(struct timeval t0, struct timeval t1); + +#endif /* __UTIL_TIME_H__ */ diff --git a/src/util/unittest-helper.c b/src/util/unittest-helper.c new file mode 100644 index 000000000000..081f54bbeae3 --- /dev/null +++ b/src/util/unittest-helper.c @@ -0,0 +1,1141 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + * + * This file provide a set of helper functions for reducing the complexity + * when constructing unittests + */ + +#include "suricata-common.h" + +#include "decode.h" + +#include "flow-private.h" +#include "flow-util.h" +#include "flow-spare-pool.h" + +#include "../detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-alert.h" +#include "detect-engine-sigorder.h" +#include "detect-engine-build.h" + +#include "stream-tcp.h" +#include "stream-tcp-private.h" + +#include "util/debug.h" +#include "util/time.h" +#include "util/error.h" +#include "util/unittest.h" +#include "util/unittest-helper.h" + +#if defined(UNITTESTS) || defined(FUZZ) +Flow *TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp) +{ + struct in_addr in; + + Flow *f = SCMalloc(sizeof(Flow)); + if (unlikely(f == NULL)) { + printf("FlowAlloc failed\n"); + ; + return NULL; + } + memset(f, 0x00, sizeof(Flow)); + + FLOW_INITIALIZE(f); + + if (family == AF_INET) { + f->flags |= FLOW_IPV4; + } else if (family == AF_INET6) { + f->flags |= FLOW_IPV6; + } + + if (src != NULL) { + if (family == AF_INET) { + if (inet_pton(AF_INET, src, &in) != 1) { + printf("invalid address %s\n", src); + SCFree(f); + return NULL; + } + f->src.addr_data32[0] = in.s_addr; + } else { + BUG_ON(1); + } + } + if (dst != NULL) { + if (family == AF_INET) { + if (inet_pton(AF_INET, dst, &in) != 1) { + printf("invalid address %s\n", dst); + SCFree(f); + return NULL; + } + f->dst.addr_data32[0] = in.s_addr; + } else { + BUG_ON(1); + } + } + + f->sp = sp; + f->dp = dp; + + return f; +} +/** \brief writes the contents of a buffer into a file */ +int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size) +{ + if (remove(name) != 0) { + if (errno != ENOENT) { + printf("failed remove, errno=%d\n", errno); + return -1; + } + } + FILE *fd = fopen(name, "wb"); + if (fd == NULL) { + printf("failed open, errno=%d\n", errno); + return -2; + } + if (fwrite(data, 1, size, fd) != size) { + fclose(fd); + return -3; + } + fclose(fd); + return 0; +} + +#endif +#ifdef UNITTESTS + +/** + * \brief return the uint32_t for a ipv4 address string + * + * \param str Valid ipaddress in string form (e.g. 1.2.3.4) + * + * \retval uint the uin32_t representation + */ +uint32_t UTHSetIPv4Address(const char *str) +{ + struct in_addr in; + if (inet_pton(AF_INET, str, &in) != 1) { + printf("invalid IPv6 address %s\n", str); + exit(EXIT_FAILURE); + } + return (uint32_t)in.s_addr; +} + +/** + * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests + * specifying ip and port sources and destinations (IPV6) + * + * \param payload pointer to the payload buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * \param src pointer to a string containing the ip source + * \param dst pointer to a string containing the ip destination + * \param sport pointer to a string containing the port source + * \param dport pointer to a string containing the port destination + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, + const char *src, const char *dst, uint16_t sport, uint16_t dport) +{ + uint32_t in[4]; + + Packet *p = PacketGetFromAlloc(); + if (unlikely(p == NULL)) + return NULL; + + p->ts = TimeGet(); + + p->src.family = AF_INET6; + p->dst.family = AF_INET6; + p->payload = payload; + p->payload_len = payload_len; + p->proto = ipproto; + + p->ip6h = SCMalloc(sizeof(IPV6Hdr)); + if (p->ip6h == NULL) + goto error; + memset(p->ip6h, 0, sizeof(IPV6Hdr)); + p->ip6h->s_ip6_nxt = ipproto; + p->ip6h->s_ip6_plen = htons(payload_len + sizeof(TCPHdr)); + + if (inet_pton(AF_INET6, src, &in) != 1) + goto error; + p->src.addr_data32[0] = in[0]; + p->src.addr_data32[1] = in[1]; + p->src.addr_data32[2] = in[2]; + p->src.addr_data32[3] = in[3]; + p->sp = sport; + p->ip6h->s_ip6_src[0] = in[0]; + p->ip6h->s_ip6_src[1] = in[1]; + p->ip6h->s_ip6_src[2] = in[2]; + p->ip6h->s_ip6_src[3] = in[3]; + + if (inet_pton(AF_INET6, dst, &in) != 1) + goto error; + p->dst.addr_data32[0] = in[0]; + p->dst.addr_data32[1] = in[1]; + p->dst.addr_data32[2] = in[2]; + p->dst.addr_data32[3] = in[3]; + p->dp = dport; + p->ip6h->s_ip6_dst[0] = in[0]; + p->ip6h->s_ip6_dst[1] = in[1]; + p->ip6h->s_ip6_dst[2] = in[2]; + p->ip6h->s_ip6_dst[3] = in[3]; + + p->tcph = SCMalloc(sizeof(TCPHdr)); + if (p->tcph == NULL) + goto error; + memset(p->tcph, 0, sizeof(TCPHdr)); + p->tcph->th_sport = htons(sport); + p->tcph->th_dport = htons(dport); + + SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len); + return p; + +error: + if (p != NULL) { + if (p->ip6h != NULL) { + SCFree(p->ip6h); + } + if (p->tcph != NULL) { + SCFree(p->tcph); + } + SCFree(p); + } + return NULL; +} + +/** + * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests + * specifying ip and port sources and destinations + * + * \param payload pointer to the payload buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * \param src pointer to a string containing the ip source + * \param dst pointer to a string containing the ip destination + * \param sport pointer to a string containing the port source + * \param dport pointer to a string containing the port destination + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, + const char *dst, uint16_t sport, uint16_t dport) +{ + struct in_addr in; + + Packet *p = PacketGetFromAlloc(); + if (unlikely(p == NULL)) + return NULL; + + p->ts = TimeGet(); + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = payload; + p->payload_len = payload_len; + p->proto = ipproto; + + if (inet_pton(AF_INET, src, &in) != 1) + goto error; + p->src.addr_data32[0] = in.s_addr; + p->sp = sport; + + if (inet_pton(AF_INET, dst, &in) != 1) + goto error; + p->dst.addr_data32[0] = in.s_addr; + p->dp = dport; + + p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); + if (p->ip4h == NULL) + goto error; + + p->ip4h->s_ip_src.s_addr = p->src.addr_data32[0]; + p->ip4h->s_ip_dst.s_addr = p->dst.addr_data32[0]; + p->ip4h->ip_proto = ipproto; + p->ip4h->ip_verhl = sizeof(IPV4Hdr); + p->proto = ipproto; + + int hdr_offset = sizeof(IPV4Hdr); + switch (ipproto) { + case IPPROTO_UDP: + p->udph = (UDPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); + if (p->udph == NULL) + goto error; + + p->udph->uh_sport = sport; + p->udph->uh_dport = dport; + hdr_offset += sizeof(UDPHdr); + break; + case IPPROTO_TCP: + p->tcph = (TCPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); + if (p->tcph == NULL) + goto error; + + p->tcph->th_sport = htons(sport); + p->tcph->th_dport = htons(dport); + hdr_offset += sizeof(TCPHdr); + break; + case IPPROTO_ICMP: + p->icmpv4h = (ICMPV4Hdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr)); + if (p->icmpv4h == NULL) + goto error; + + hdr_offset += sizeof(ICMPV4Hdr); + break; + default: + break; + /* TODO: Add more protocols */ + } + + if (payload && payload_len) { + PacketCopyDataOffset(p, hdr_offset, payload, payload_len); + } + SET_PKT_LEN(p, hdr_offset + payload_len); + p->payload = GET_PKT_DATA(p) + hdr_offset; + + return p; + +error: + SCFree(p); + return NULL; +} + +/** + * \brief UTHBuildPacket is a wrapper that build packets with default ip + * and port fields + * + * \param payload pointer to the payload buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto) +{ + return UTHBuildPacketReal( + payload, payload_len, ipproto, "192.168.1.5", "192.168.1.1", 41424, 80); +} + +/** + * \brief UTHBuildPacketArrayFromEth is a wrapper that build a packets from an array of + * packets in ethernet rawbytes. Hint: It also share the flows. + * + * \param raw_eth pointer to the array of ethernet packets in rawbytes + * \param pktsize pointer to the array of sizes corresponding to each buffer pointed + * from pktsize. + * \param numpkts number of packets in the array + * + * \retval Packet pointer to the array of built in packets; NULL if something fail + */ +Packet **UTHBuildPacketArrayFromEth(uint8_t *raw_eth[], int *pktsize, int numpkts) +{ + DecodeThreadVars dtv; + ThreadVars th_v; + if (raw_eth == NULL || pktsize == NULL || numpkts <= 0) { + SCLogError("The arrays cant be null, and the number" + " of packets should be grater thatn zero"); + return NULL; + } + Packet **p = NULL; + p = SCMalloc(sizeof(Packet *) * numpkts); + if (unlikely(p == NULL)) + return NULL; + + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + int i = 0; + for (; i < numpkts; i++) { + p[i] = PacketGetFromAlloc(); + if (p[i] == NULL) { + SCFree(p); + return NULL; + } + DecodeEthernet(&th_v, &dtv, p[i], raw_eth[i], pktsize[i]); + } + return p; +} + +/** + * \brief UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes + * + * \param raw_eth pointer to the rawbytes containing an ethernet packet + * (and any other headers inside) + * \param pktsize pointer to the length of the payload + * + * \retval Packet pointer to the built in packet; NULL if something fail + */ +Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize) +{ + DecodeThreadVars dtv; + ThreadVars th_v; + Packet *p = PacketGetFromAlloc(); + if (unlikely(p == NULL)) + return NULL; + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + DecodeEthernet(&th_v, &dtv, p, raw_eth, pktsize); + return p; +} + +/** + * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs + * and defaulting ports + * + * \param payload pointer to the payload buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketSrcDst( + uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst) +{ + return UTHBuildPacketReal(payload, payload_len, ipproto, src, dst, 41424, 80); +} + +/** + * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs + * and defaulting ports (IPV6) + * + * \param payload pointer to the payload buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketIPV6SrcDst( + uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst) +{ + return UTHBuildPacketIPV6Real(payload, payload_len, ipproto, src, dst, 41424, 80); +} + +/** + * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying + * src and dst ports and defaulting IPs + * + * \param payload pointer to the payload buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketSrcDstPorts( + uint8_t *payload, uint16_t payload_len, uint8_t ipproto, uint16_t sport, uint16_t dport) +{ + return UTHBuildPacketReal( + payload, payload_len, ipproto, "192.168.1.5", "192.168.1.1", sport, dport); +} + +/** + * \brief UTHFreePackets: function to release the allocated data + * from UTHBuildPacket and the packet itself + * + * \param p pointer to the Packet + */ +void UTHFreePackets(Packet **p, int numpkts) +{ + if (p == NULL) + return; + + int i = 0; + for (; i < numpkts; i++) { + UTHFreePacket(p[i]); + } +} + +/** + * \brief UTHFreePacket: function to release the allocated data + * from UTHBuildPacket and the packet itself + * + * \param p pointer to the Packet + */ +void UTHFreePacket(Packet *p) +{ + if (p == NULL) + return; + PacketFree(p); +} + +void UTHAssignFlow(Packet *p, Flow *f) +{ + if (p && f) { + p->flow = f; + p->flags |= PKT_HAS_FLOW; + } +} + +Flow *UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp) +{ + return TestHelperBuildFlow(family, src, dst, sp, dp); +} + +void UTHFreeFlow(Flow *flow) +{ + if (flow != NULL) { + SCFree(flow); // FlowFree(flow); + } +} + +int UTHAddStreamToFlow(Flow *f, int direction, uint8_t *data, uint32_t data_len) +{ + FAIL_IF_NULL(f); + FAIL_IF_NOT(f->proto == IPPROTO_TCP); + FAIL_IF_NULL(f->protoctx); + TcpSession *ssn = f->protoctx; + + StreamingBufferSegment seg; + TcpStream *stream = direction == 0 ? &ssn->client : &ssn->server; + int r = StreamingBufferAppend(&stream->sb, &stream_config.sbcnf, &seg, data, data_len); + FAIL_IF_NOT(r == 0); + stream->last_ack += data_len; + return 1; +} + +int UTHAddSessionToFlow(Flow *f, uint32_t ts_isn, uint32_t tc_isn) +{ + FAIL_IF_NULL(f); + + TcpSession *ssn = SCCalloc(1, sizeof(*ssn)); + FAIL_IF_NULL(ssn); + + StreamingBuffer x = STREAMING_BUFFER_INITIALIZER; + ssn->client.sb = x; + ssn->server.sb = x; + + ssn->client.isn = ts_isn; + ssn->server.isn = tc_isn; + + f->protoctx = ssn; + return 1; +} + +int UTHRemoveSessionFromFlow(Flow *f) +{ + FAIL_IF_NULL(f); + FAIL_IF_NOT(f->proto == IPPROTO_TCP); + TcpSession *ssn = f->protoctx; + FAIL_IF_NULL(ssn); + StreamTcpSessionCleanup(ssn); + SCFree(ssn); + f->protoctx = NULL; + return 1; +} + +/** + * \brief UTHGenericTest: function that perform a generic check taking care of + * as maximum common unittest elements as possible. + * It will create a detection engine, append an array + * of signatures an check the expected results for each + * of them, it check matches for an array of packets + * + * \param pkt pointer to the array of packets + * \param numpkts number of packets to match + * \param sigs array of char* pointing to signatures to load + * \param numsigs number of signatures to load and check + * \param results pointer to arrays of numbers, each of them foreach packet + * to check if sids matches that packet as expected with + * that number of times or not. The size of results should be + * numpkts * numsigs * sizeof(uint16_t *) + * + * Example: + * result[1][3] would mean the number of times the pkt[1] + * match the sid[3] + * + * \retval int 1 if the match of all the sids is the specified has the + * specified results; 0 if not + */ +int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], + uint32_t *results, int numsigs) +{ + + int result = 0; + if (pkt == NULL || sigs == NULL || numpkts == 0 || sids == NULL || results == NULL || + numsigs == 0) { + SCLogError("Arguments invalid, that the pointer/arrays are not NULL, and the number of " + "signatures and packets is > 0"); + goto end; + } + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->flags |= DE_QUIET; + + if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0) + goto cleanup; + + result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs); + +cleanup: + DetectEngineCtxFree(de_ctx); +end: + return result; +} + +/** + * \brief UTHCheckPacketMatches: function to check if a packet match some sids + * + * + * \param p pointer to the Packet + * \param sigs array of char* pointing to signatures to load + * \param numsigs number of signatures to load from the array + * \param results pointer to an array of numbers to check if sids matches + * that number of times or not. + * + * \retval int 1 if the match of all the sids is the specified has the + * specified results; 0 if not + */ +int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs) +{ + if (p == NULL || sids == NULL) { + SCLogError("Arguments invalid, check if the " + "packet is NULL, and if the array contain sids is set"); + return 0; + } + + int i = 0; + int res = 1; + for (; i < numsigs; i++) { + uint32_t r = PacketAlertCheck(p, sids[i]); + if (r != results[i]) { + SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, and not %" PRIu32 " as expected", + sids[i], r, results[i]); + res = 0; + } else { + SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, as expected", sids[i], r); + } + } + return res; +} + +/** + * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors + * + * \param de_ctx pointer to the DetectEngineCtx used + * \param sigs array of char* pointing to signatures to load + * \param numsigs number of signatures to load from the array + * (size of the array) + * + * \retval int 0 if we have errors; 1 if all the signatures loaded successfully + */ +int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs) +{ + BUG_ON(de_ctx == NULL); + BUG_ON(numsigs <= 0); + BUG_ON(sigs == NULL); + + for (int i = 0; i < numsigs; i++) { + if (sigs[i] == NULL) { + SCLogError("Check the signature" + " at position %d", + i); + return 0; + } + Signature *s = DetectEngineAppendSig(de_ctx, sigs[i]); + if (s == NULL) { + SCLogError("Check the signature at" + " position %d (%s)", + i, sigs[i]); + return 0; + } + } + return 1; +} + +/** + * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs + * of a de_ctx, checking that each signature matches X times for certain packets + * + * \param de_ctx pointer with the signatures loaded + * \param p pointer to the array of packets + * \param num_packets number of packets in the array + * + * \retval return 1 if all goes well + * \retval return 0 if something fail + */ +int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, + uint32_t sids[], uint32_t *results, int numsigs) +{ + BUG_ON(de_ctx == NULL); + BUG_ON(p == NULL); + + int result = 0; + DecodeThreadVars dtv; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + for (int i = 0; i < num_packets; i++) { + SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); + if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0) + goto cleanup; + } + + result = 1; +cleanup: + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + return result; +} + +/** + * \test UTHMatchPackets Match a packet or a array of packets against sigs + * of a de_ctx, but note that the return value doesn't mean that we have a + * match, we have to check it later with PacketAlertCheck() + * + * \param de_ctx pointer with the signatures loaded + * \param p pointer to the array of packets + * \param num_packets number of packets in the array + * + * \retval return 1 if all goes well + * \retval return 0 if something fail + */ +int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets) +{ + BUG_ON(de_ctx == NULL); + BUG_ON(p == NULL); + int result = 1; + DecodeThreadVars dtv; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + for (int i = 0; i < num_packets; i++) + SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); + + /* Here we don't check if the packet matched or not, because + * the de_ctx can have multiple signatures, and some of them may match + * and others may not. That check will be outside + */ + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + return result; +} + +/** + * \test Test if a packet match a signature given as string and a mpm_type + * Hint: Useful for unittests with only one packet and one signature + * + * \param sig pointer to the string signature to test + * \param sid sid number of the signature + * + * \retval return 1 if match + * \retval return 0 if not + */ +int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type) +{ + SCEnter(); + + int result = 0; + + DecodeThreadVars dtv; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + printf("de_ctx == NULL: "); + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->mpm_matcher = mpm_type; + + de_ctx->sig_list = SigInit(de_ctx, sig); + if (de_ctx->sig_list == NULL) { + printf("signature == NULL: "); + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) { + printf("signature didn't alert: "); + goto end; + } + + result = 1; +end: + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + SCReturnInt(result); +} + +/** + * \test Test if a packet match a signature given as string + * Hint: Useful for unittests with only one packet and one signature + * + * \param sig pointer to the string signature to test + * \param sid sid number of the signature + * + * \retval return 1 if match + * \retval return 0 if not + */ +int UTHPacketMatchSig(Packet *p, const char *sig) +{ + int result = 1; + + DecodeThreadVars dtv; + + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + result = 0; + goto end; + } + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, sig); + if (de_ctx->sig_list == NULL) { + result = 0; + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) { + result = 0; + goto end; + } + +end: + if (de_ctx) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + return result; +} + +uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir) +{ + FlowLookupStruct fls; + memset(&fls, 0, sizeof(fls)); + + uint32_t i = start; + uint8_t payload[] = "Payload"; + for (; i < end; i++) { + Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (dir == 0) { + p->src.addr_data32[0] = i; + p->dst.addr_data32[0] = i + 1; + } else { + p->src.addr_data32[0] = i + 1; + p->dst.addr_data32[0] = i; + } + FlowHandlePacket(NULL, &fls, p); + if (p->flow != NULL) { + FLOWLOCK_UNLOCK(p->flow); + } + + /* Now the queues should be updated */ + UTHFreePacket(p); + } + + Flow *f; + while ((f = FlowQueuePrivateGetFromTop(&fls.spare_queue))) { + FlowFree(f); + } + while ((f = FlowQueuePrivateGetFromTop(&fls.work_queue))) { + FlowFree(f); + } + + return i; +} + +/** \brief parser a sig and see if the expected result is correct */ +int UTHParseSignature(const char *str, bool expect) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, str); + if (expect) + FAIL_IF_NULL(s); + else + FAIL_IF_NOT_NULL(s); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/* + * unittests for the unittest helpers + */ + +/** + * \brief CheckUTHTestPacket wrapper to check packets for unittests + */ +static int CheckUTHTestPacket(Packet *p, uint8_t ipproto) +{ + uint16_t sport = 41424; + uint16_t dport = 80; + uint8_t payload[] = "Payload"; + + uint8_t len = sizeof(payload); + + if (p == NULL) + return 0; + + if (p->payload_len != len) + return 0; + + if (strncmp((char *)payload, (char *)p->payload, len) != 0) + return 0; + + if (p->src.family != AF_INET) + return 0; + if (p->dst.family != AF_INET) + return 0; + if (p->proto != ipproto) + return 0; + + switch (ipproto) { + case IPPROTO_UDP: + if (p->udph == NULL) + return 0; + if (p->udph->uh_sport != sport) + return 0; + if (p->udph->uh_dport != dport) + return 0; + break; + case IPPROTO_TCP: + if (p->tcph == NULL) + return 0; + if (SCNtohs(p->tcph->th_sport) != sport) + return 0; + if (SCNtohs(p->tcph->th_dport) != dport) + return 0; + break; + } + return 1; +} + +#ifdef HAVE_MEMMEM +#include +void *UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) +{ + return memmem(big, big_len, little, little_len); +} +#else +#include "util/spm-bs.h" +void *UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) +{ + return BasicSearch(big, big_len, little, little_len); +} +#endif // HAVE_MEMMEM + +/** + * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests + */ +static int UTHBuildPacketRealTest01(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketReal( + payload, sizeof(payload), IPPROTO_TCP, "192.168.1.5", "192.168.1.1", 41424, 80); + + int ret = CheckUTHTestPacket(p, IPPROTO_TCP); + UTHFreePacket(p); + + return ret; +} + +/** + * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests + */ +static int UTHBuildPacketRealTest02(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketReal( + payload, sizeof(payload), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 80); + + int ret = CheckUTHTestPacket(p, IPPROTO_UDP); + UTHFreePacket(p); + return ret; +} + +/** + * \brief UTHBuildPacketTest01 wrapper to check packets for unittests + */ +static int UTHBuildPacketTest01(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + + int ret = CheckUTHTestPacket(p, IPPROTO_TCP); + UTHFreePacket(p); + + return ret; +} + +/** + * \brief UTHBuildPacketTest02 wrapper to check packets for unittests + */ +static int UTHBuildPacketTest02(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP); + + int ret = CheckUTHTestPacket(p, IPPROTO_UDP); + UTHFreePacket(p); + + return ret; +} + +/** + * \brief UTHBuildPacketOfFlowsTest01 wrapper to check packets for unittests + */ +static int UTHBuildPacketOfFlowsTest01(void) +{ + int result = 0; + + FlowInitConfig(FLOW_QUIET); + uint32_t flow_spare_q_len = FlowSpareGetPoolSize(); + + UTHBuildPacketOfFlows(0, 100, 0); + + if (FlowSpareGetPoolSize() != flow_spare_q_len - 100) + result = 0; + else + result = 1; + FlowShutdown(); + + return result; +} + +/** + * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests + */ +static int UTHBuildPacketSrcDstTest01(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDst( + payload, sizeof(payload), IPPROTO_TCP, "192.168.1.5", "192.168.1.1"); + + int ret = CheckUTHTestPacket(p, IPPROTO_TCP); + UTHFreePacket(p); + + return ret; +} + +/** + * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests + */ +static int UTHBuildPacketSrcDstTest02(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDst( + payload, sizeof(payload), IPPROTO_UDP, "192.168.1.5", "192.168.1.1"); + + int ret = CheckUTHTestPacket(p, IPPROTO_UDP); + UTHFreePacket(p); + + return ret; +} + +/** + * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests + */ +static int UTHBuildPacketSrcDstPortsTest01(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP, 41424, 80); + + int ret = CheckUTHTestPacket(p, IPPROTO_TCP); + UTHFreePacket(p); + + return ret; +} + +/** + * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests + */ +static int UTHBuildPacketSrcDstPortsTest02(void) +{ + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP, 41424, 80); + + int ret = CheckUTHTestPacket(p, IPPROTO_UDP); + UTHFreePacket(p); + + return ret; +} + +#endif /* UNITTESTS */ + +void UTHRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01); + UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02); + UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01); + UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02); + UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01); + UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", UTHBuildPacketSrcDstPortsTest01); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", UTHBuildPacketSrcDstPortsTest02); + UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01); + +#endif /* UNITTESTS */ +} diff --git a/src/util/unittest-helper.h b/src/util/unittest-helper.h new file mode 100644 index 000000000000..c973b10697a1 --- /dev/null +++ b/src/util/unittest-helper.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Pablo Rincon Crespo + */ + +#ifndef __UTIL_UNITTEST_HELPER__ +#define __UTIL_UNITTEST_HELPER__ + +#if defined(UNITTESTS) +#include "flow.h" +#include "../detect.h" +#elif defined(FUZZ) +#include "flow.h" +#endif + +#if defined(UNITTESTS) || defined(FUZZ) +Flow *TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp); +int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size); +#endif +#ifdef UNITTESTS +uint32_t UTHSetIPv4Address(const char *); + +Packet *UTHBuildPacketReal( + uint8_t *, uint16_t, uint8_t ipproto, const char *, const char *, uint16_t, uint16_t); +Packet *UTHBuildPacket(uint8_t *, uint16_t, uint8_t ipproto); +Packet *UTHBuildPacketSrcDst(uint8_t *, uint16_t, uint8_t ipproto, const char *, const char *); +Packet *UTHBuildPacketSrcDstPorts(uint8_t *, uint16_t, uint8_t ipproto, uint16_t, uint16_t); + +Packet *UTHBuildPacketIPV6SrcDst(uint8_t *, uint16_t, uint8_t ipproto, const char *, const char *); + +int UTHPacketMatchSigMpm(Packet *, char *, uint16_t); +Packet **UTHBuildPacketArrayFromEth(uint8_t **, int *, int); +Packet *UTHBuildPacketFromEth(uint8_t *, uint16_t); + +void UTHFreePacket(Packet *); +void UTHFreePackets(Packet **, int); + +void UTHAssignFlow(Packet *p, Flow *f); +Flow *UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp); +void UTHFreeFlow(Flow *flow); +int UTHAddStreamToFlow(Flow *f, int direction, uint8_t *data, uint32_t data_len); +int UTHAddSessionToFlow(Flow *f, uint32_t ts_isn, uint32_t tc_isn); +int UTHRemoveSessionFromFlow(Flow *f); + +int UTHAppendSigs(DetectEngineCtx *, const char **, int); +int UTHMatchPackets(DetectEngineCtx *, Packet **, int); +int UTHPacketMatchSig(Packet *p, const char *); +int UTHCheckPacketMatch(Packet *, uint32_t *, uint32_t *, int); + +int UTHCheckPacketMatchResults(Packet *, uint32_t *, uint32_t *, int); +int UTHMatchPacketsWithResults(DetectEngineCtx *, Packet **, int, uint32_t *, uint32_t *, int); +int UTHGenericTest(Packet **, int, const char **, uint32_t *, uint32_t *, int); + +uint32_t UTHBuildPacketOfFlows(uint32_t, uint32_t, uint8_t); +Packet *UTHBuildPacketIPV6Real( + uint8_t *, uint16_t, uint8_t ipproto, const char *, const char *, uint16_t, uint16_t); + +void *UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len); +int UTHParseSignature(const char *str, bool expect); +#endif + +void UTHRegisterTests(void); + +#endif /* __UTIL_UNITTEST_HELPER__ */ diff --git a/src/util/unittest.c b/src/util/unittest.c new file mode 100644 index 000000000000..7246b06c1d1f --- /dev/null +++ b/src/util/unittest.c @@ -0,0 +1,349 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Breno Silva + * + * Unit test framework + */ + +/** + * \defgroup Testing Testing + * + * \brief Unit testing support functions. + * + * @{ + */ + +#include "suricata-common.h" +#include "runmodes.h" +#include "util/unittest.h" +#include "util/debug.h" +#include "util/time.h" +#include "../conf.h" + +#include "stream-tcp.h" +#include "stream-tcp-reassemble.h" + +#ifdef UNITTESTS + +static pcre2_code *parse_regex; +static pcre2_match_data *parse_regex_match; + +static UtTest *ut_list; + +int unittests_fatal = 0; + +/** + * \brief Allocate UtTest list member + * + * \retval ut Pointer to UtTest + */ + +static UtTest *UtAllocTest(void) +{ + UtTest *ut = SCMalloc(sizeof(UtTest)); + if (unlikely(ut == NULL)) + return NULL; + + memset(ut, 0, sizeof(UtTest)); + + return ut; +} + +/** + * \brief Append test in UtTest list + * + * \param list Pointer to the start of the IP packet + * \param test Pointer to unit test + * + * \retval 0 Function always returns zero + */ + +static int UtAppendTest(UtTest **list, UtTest *test) +{ + if (*list == NULL) { + *list = test; + } else { + UtTest *tmp = *list; + + while (tmp->next != NULL) { + tmp = tmp->next; + } + tmp->next = test; + } + + return 0; +} + +/** + * \brief Register unit test + * + * \param name Unit test name + * \param TestFn Unit test function + */ + +void UtRegisterTest(const char *name, int (*TestFn)(void)) +{ + UtTest *ut = UtAllocTest(); + if (ut == NULL) + return; + + ut->name = name; + ut->TestFn = TestFn; + ut->next = NULL; + + /* append */ + UtAppendTest(&ut_list, ut); +} + +/** + * \brief Compile a regex to run a specific unit test + * + * \param regex_arg The regular expression + * + * \retval 1 Regex compiled + * \retval -1 Regex error + */ +static int UtRegex(const char *regex_arg) +{ + int en; + PCRE2_SIZE eo; + int opts = PCRE2_CASELESS; + + if (regex_arg == NULL) + return -1; + + parse_regex = + pcre2_compile((PCRE2_SPTR8)regex_arg, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + if (parse_regex == NULL) { + PCRE2_UCHAR errbuffer[256]; + pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); + SCLogError("pcre2 compile of \"%s\" failed at " + "offset %d: %s", + regex_arg, (int)eo, errbuffer); + goto error; + } + parse_regex_match = pcre2_match_data_create_from_pattern(parse_regex, NULL); + + return 1; + +error: + return -1; +} + +/** \brief List all registered unit tests. + * + * \param regex_arg Regular expression to limit listed tests. + */ +void UtListTests(const char *regex_arg) +{ + UtTest *ut; + int ret = 0, rcomp = 0; + + rcomp = UtRegex(regex_arg); + + for (ut = ut_list; ut != NULL; ut = ut->next) { + if (rcomp == 1) { + ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0, + parse_regex_match, NULL); + if (ret >= 1) { + printf("%s\n", ut->name); + } + } else { + printf("%s\n", ut->name); + } + } + pcre2_code_free(parse_regex); + pcre2_match_data_free(parse_regex_match); +} + +/** \brief Run all registered unittests. + * + * \param regex_arg The regular expression + * + * \retval 0 all successful + * \retval result number of tests that failed + */ + +uint32_t UtRunTests(const char *regex_arg) +{ + UtTest *ut; + uint32_t good = 0, bad = 0, matchcnt = 0; + int ret = 0, rcomp = 0; + + StreamTcpInitMemuse(); + StreamTcpReassembleInitMemuse(); + + rcomp = UtRegex(regex_arg); + + if (rcomp == 1) { + for (ut = ut_list; ut != NULL; ut = ut->next) { + ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0, + parse_regex_match, NULL); + if (ret >= 1) { + printf("Test %-60.60s : ", ut->name); + matchcnt++; + fflush(stdout); /* flush so in case of a segv we see the testname */ + + /* reset the time */ + TimeModeSetOffline(); + TimeSetToCurrentTime(); + + ret = ut->TestFn(); + + if (StreamTcpMemuseCounter() != 0) { + printf("STREAM MEMORY IN USE %" PRIu64 "\n", StreamTcpMemuseCounter()); + ret = 0; + } + if (FlowGetMemuse() != 0) { + printf("FLOW MEMORY IN USE %" PRIu64 "\n", FlowGetMemuse()); + ret = 0; + } + + if (StreamTcpReassembleMemuseGlobalCounter() != 0) { + printf("STREAM REASSEMBLY MEMORY IN USE %" PRIu64 "\n", + StreamTcpReassembleMemuseGlobalCounter()); + ret = 0; + } + + printf("%s\n", ret ? "pass" : "FAILED"); + + if (!ret) { + if (unittests_fatal == 1) { + fprintf(stderr, "ERROR: unittest failed.\n"); + exit(EXIT_FAILURE); + } + bad++; + } else { + good++; + } + } + } + if (matchcnt > 0) { + printf("==== TEST RESULTS ====\n"); + printf("PASSED: %" PRIu32 "\n", good); + printf("FAILED: %" PRIu32 "\n", bad); + printf("======================\n"); + } else { + SCLogInfo( + "UtRunTests: regex provided regex_arg: %s did not match any tests", regex_arg); + } + } else { + SCLogInfo("UtRunTests: pcre compilation failed"); + } + pcre2_code_free(parse_regex); + pcre2_match_data_free(parse_regex_match); + return bad; +} +/** + * \brief Initialize unit test list + */ + +void UtInitialize(void) +{ + ut_list = NULL; +} + +/** + * \brief Cleanup unit test list + */ + +void UtCleanup(void) +{ + + UtTest *tmp = ut_list, *otmp; + + while (tmp != NULL) { + otmp = tmp->next; + SCFree(tmp); + tmp = otmp; + } + + ut_list = NULL; +} + +void UtRunModeRegister(void) +{ + RunModeRegisterNewRunMode(RUNMODE_UNITTEST, "unittest", "Unittest mode", NULL, NULL); + + return; +} + +/* + * unittests for the unittests code + */ + +/** \brief True test + * + * \retval 1 True + * \retval 0 False + */ +static int UtSelftestTrue(void) +{ + if (1) + return 1; + else + return 0; +} + +/** \brief False test + * + * \retval 1 False + * \retval 0 True + */ +static int UtSelftestFalse(void) +{ + if (0) + return 0; + else + return 1; +} + +/** \brief Run self tests + * + * \param regex_arg The regular expression + * + * \retval 0 all successful + */ + +int UtRunSelftest(const char *regex_arg) +{ + printf("* Running Unittesting subsystem selftests...\n"); + + UtInitialize(); + + UtRegisterTest("true", UtSelftestTrue); + UtRegisterTest("false", UtSelftestFalse); + + int ret = UtRunTests(regex_arg); + if (ret == 0) + printf("* Done running Unittesting subsystem selftests...\n"); + else + printf("* ERROR running Unittesting subsystem selftests failed...\n"); + + UtCleanup(); + return 0; +} +#endif /* UNITTESTS */ + +/** + * @} + */ diff --git a/src/util/unittest.h b/src/util/unittest.h new file mode 100644 index 000000000000..de19d1e01938 --- /dev/null +++ b/src/util/unittest.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2007-2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Breno Silva + * + * Unit test framework + */ + +/** + * \addtogroup Testing + * + * @{ + */ + +#ifndef __UTIL_UNITTEST_H__ +#define __UTIL_UNITTEST_H__ + +#ifdef UNITTESTS + +typedef struct UtTest_ { + const char *name; + int (*TestFn)(void); + + struct UtTest_ *next; + +} UtTest; + +void UtRegisterTest(const char *name, int (*TestFn)(void)); +uint32_t UtRunTests(const char *regex_arg); +void UtInitialize(void); +void UtCleanup(void); +int UtRunSelftest(const char *regex_arg); +void UtListTests(const char *regex_arg); +void UtRunModeRegister(void); + +extern int unittests_fatal; + +/** + * \brief Fail a test. + */ +#define FAIL \ + do { \ + if (unittests_fatal) { \ + BUG_ON(1); \ + } else { \ + return 0; \ + } \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to true. + */ +#define FAIL_IF(expr) \ + do { \ + if (unittests_fatal) { \ + BUG_ON(expr); \ + } else if (expr) { \ + return 0; \ + } \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to false. + */ +#define FAIL_IF_NOT(expr) \ + do { \ + FAIL_IF(!(expr)); \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to NULL. + */ +#define FAIL_IF_NULL(expr) \ + do { \ + FAIL_IF(NULL == expr); \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to non-NULL. + */ +#define FAIL_IF_NOT_NULL(expr) \ + do { \ + FAIL_IF(NULL != expr); \ + } while (0) + +/** + * \brief Pass the test. + * + * Only to be used at the end of a function instead of "return 1." + */ +#define PASS \ + do { \ + return 1; \ + } while (0) + +#endif + +#endif /* __UTIL_UNITTEST_H__ */ + +/** + * @} + */ diff --git a/src/util/validate.h b/src/util/validate.h new file mode 100644 index 000000000000..1df9ae72aa8d --- /dev/null +++ b/src/util/validate.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Functions & Macro's for validation of data structures. This is used for + * code correctness. + * + * These will abort() the program if they fail, so they should _only_ be + * used for testing. + */ + +#ifndef __UTIL_VALIDATE_H__ +#define __UTIL_VALIDATE_H__ + +#ifdef DEBUG_VALIDATION + +/** \brief test if a flow is locked. + * + * If trylock returns 0 it got a lock. Which means + * the flow was previously unlocked. + */ +#define DEBUG_ASSERT_FLOW_LOCKED(f) \ + do { \ + if ((f) != NULL) { \ + int r = SCMutexTrylock(&(f)->m); \ + if (r == 0) { \ + BUG_ON(1); \ + } \ + } \ + } while (0) + +/** \brief validate the integrity of the flow + * + * BUG_ON's on problems + */ +#define DEBUG_VALIDATE_FLOW(f) \ + do { \ + if ((f) != NULL) { \ + BUG_ON((f)->flags &FLOW_IPV4 && (f)->flags & FLOW_IPV6); \ + if ((f)->proto == IPPROTO_TCP) { \ + BUG_ON((f)->alstate != NULL && (f)->alparser == NULL); \ + } \ + } \ + } while (0) + +/** \brief validate the integrity of the packet + * + * BUG_ON's on problems + */ +#define DEBUG_VALIDATE_PACKET(p) \ + do { \ + if ((p) != NULL) { \ + if ((p)->flow != NULL) { \ + DEBUG_VALIDATE_FLOW((p)->flow); \ + } \ + if (!((p)->flags & (PKT_IS_FRAGMENT | PKT_IS_INVALID))) { \ + if ((p)->proto == IPPROTO_TCP) { \ + BUG_ON((p)->tcph == NULL); \ + } else if ((p)->proto == IPPROTO_UDP) { \ + BUG_ON((p)->udph == NULL); \ + } else if ((p)->proto == IPPROTO_ICMP) { \ + BUG_ON((p)->icmpv4h == NULL); \ + } else if ((p)->proto == IPPROTO_SCTP) { \ + BUG_ON((p)->sctph == NULL); \ + } else if ((p)->proto == IPPROTO_ICMPV6) { \ + BUG_ON((p)->icmpv6h == NULL); \ + } \ + } \ + if ((p)->payload_len > 0) { \ + BUG_ON((p)->payload == NULL); \ + } \ + BUG_ON((p)->ip4h != NULL && (p)->ip6h != NULL); \ + BUG_ON((p)->flowflags != 0 && (p)->flow == NULL); \ + BUG_ON((p)->flowflags &FLOW_PKT_TOSERVER && (p)->flowflags & FLOW_PKT_TOCLIENT); \ + } \ + } while (0) + +#define DEBUG_VALIDATE_BUG_ON(exp) BUG_ON((exp)) + +#else /* DEBUG_VALIDATE */ + +#define DEBUG_ASSERT_FLOW_LOCKED(f) +#define DEBUG_VALIDATE_FLOW(f) +#define DEBUG_VALIDATE_PACKET(p) +#define DEBUG_VALIDATE_BUG_ON(exp) + +#endif /* DEBUG_VALIDATE */ + +#endif /* __UTIL_VALIDATE_H__ */ diff --git a/src/util/var-name.c b/src/util/var-name.c new file mode 100644 index 000000000000..8e04c78c4d1b --- /dev/null +++ b/src/util/var-name.c @@ -0,0 +1,375 @@ +/* Copyright (C) 2007-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Generic variable name utility functions + */ + +#include "suricata-common.h" +#include "../detect.h" +#include "util/hash-string.h" +#include "util/hashlist.h" +#include "util/var-name.h" +#include "util/validate.h" + +/* Overall Design: + * + * Base Store: "base" + * + * Used during keyword registration. Operates under lock. Base is shared + * between all detect engines, detect engine versions and tenants. + * Each variable name is ref counted. + * + * During the freeing of a detect engine / tenant, unregistration decreases + * the ref cnt. + * + * Base has both a string to id and a id to string hash table. String to + * id is used during parsing/registration. id to string during unregistration. + * + * + * Active Store Pointer (atomic) + * + * The "active" store atomic pointer points to the active store. The call + * to `VarNameStoreActivate` will build a new lookup store and hot swap + * the pointer. + * + * Ensuring memory safety. During the hot swap, the pointer is replaced, so + * any new call to the lookup functions will automatically use the new store. + * This leaves the case of any lookup happening concurrently with the pointer + * swap. For this case we add the old store to a free list. It gets a timestamp + * before which it cannot be freed. + * + * + * Free List + * + * The free list contains old stores that are waiting to get removed. They + * contain a timestamp that is checked before they are freed. + * + */ +typedef struct VarNameStore_ { + HashListTable *names; + HashListTable *ids; + uint32_t max_id; + struct timeval free_after; + TAILQ_ENTRY(VarNameStore_) next; +} VarNameStore; +typedef VarNameStore *VarNameStorePtr; + +/** \brief Name2idx mapping structure for flowbits, flowvars and pktvars. */ +typedef struct VariableName_ { + char *name; + enum VarTypes type; /* flowbit, pktvar, etc */ + uint32_t id; + uint32_t ref_cnt; +} VariableName; + +#define VARNAME_HASHSIZE 0x1000 +#define VARID_HASHSIZE 0x1000 + +static SCMutex base_lock = SCMUTEX_INITIALIZER; +static VarNameStore base = { .names = NULL, .ids = NULL, .max_id = 0 }; +static TAILQ_HEAD(, VarNameStore_) free_list = TAILQ_HEAD_INITIALIZER(free_list); +static SC_ATOMIC_DECLARE(VarNameStorePtr, active); + +static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen); +static char VariableNameCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2); +static uint32_t VariableIdHash(HashListTable *ht, void *ptr, uint16_t _unused); +static char VariableIdCompare(void *ptr1, uint16_t _unused1, void *ptr2, uint16_t _unused2); +static void VariableNameFree(void *data); + +void VarNameStoreInit(void) +{ + SCMutexLock(&base_lock); + base.names = HashListTableInit( + VARNAME_HASHSIZE, VariableNameHash, VariableNameCompare, VariableNameFree); + if (base.names == NULL) { + FatalError("failed to initialize variable name hash (names)"); + } + + /* base.names owns the allocation, so use a NULL Free pointer here */ + base.ids = HashListTableInit(VARID_HASHSIZE, VariableIdHash, VariableIdCompare, NULL); + if (base.ids == NULL) { + FatalError("failed to initialize variable name hash (names)"); + } + SC_ATOMIC_INITPTR(active); + SCMutexUnlock(&base_lock); +} + +void VarNameStoreDestroy(void) +{ + SCMutexLock(&base_lock); + VarNameStore *s = SC_ATOMIC_GET(active); + if (s) { + HashListTableFree(s->names); + HashListTableFree(s->ids); + SCFree(s); + s = NULL; + } + SC_ATOMIC_SET(active, NULL); + + while ((s = TAILQ_FIRST(&free_list))) { + TAILQ_REMOVE(&free_list, s, next); + HashListTableFree(s->names); + HashListTableFree(s->ids); + SCFree(s); + } + + for (HashListTableBucket *b = HashListTableGetListHead(base.names); b != NULL; + b = HashListTableGetListNext(b)) { + VariableName *vn = HashListTableGetListData(b); + DEBUG_VALIDATE_BUG_ON(vn->ref_cnt > 0); + if (vn->ref_cnt > 0) { + SCLogWarning("%s (type %u, id %u) still has ref_cnt %u", vn->name, vn->type, vn->id, + vn->ref_cnt); + } + } + HashListTableFree(base.ids); + base.ids = NULL; + HashListTableFree(base.names); + base.names = NULL; + base.max_id = 0; + SCMutexUnlock(&base_lock); +} + +/** + * \retval id or 0 on error + */ +uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type) +{ + SCMutexLock(&base_lock); + uint32_t id = 0; + + SCLogDebug("registering: name %s type %u", name, type); + VariableName lookup = { .type = type, .name = (char *)name }; + VariableName *found = (VariableName *)HashListTableLookup(base.names, (void *)&lookup, 0); + if (found == NULL) { + VariableName *vn = SCCalloc(1, sizeof(VariableName)); + if (likely(vn != NULL)) { + vn->type = type; + vn->name = SCStrdup(name); + if (vn->name != NULL) { + vn->ref_cnt = 1; + id = vn->id = ++base.max_id; + HashListTableAdd(base.names, (void *)vn, 0); + HashListTableAdd(base.ids, (void *)vn, 0); + SCLogDebug( + "new registration %s id %u type %u -> %u", vn->name, vn->id, vn->type, id); + } else { + SCFree(vn); + } + } + } else { + id = found->id; + found->ref_cnt++; + SCLogDebug("existing registration %s ref_cnt %u -> %u", name, found->ref_cnt, id); + } + SCMutexUnlock(&base_lock); + return id; +} + +const char *VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type) +{ + const char *name = NULL; + SCMutexLock(&base_lock); + VariableName lookup = { .type = type, .id = id }; + VariableName *found = (VariableName *)HashListTableLookup(base.ids, (void *)&lookup, 0); + if (found) { + name = found->name; + } + SCMutexUnlock(&base_lock); + return name; +} + +void VarNameStoreUnregister(const uint32_t id, const enum VarTypes type) +{ + SCMutexLock(&base_lock); + VariableName lookup = { .type = type, .id = id }; + VariableName *found = (VariableName *)HashListTableLookup(base.ids, (void *)&lookup, 0); + if (found) { + SCLogDebug("found %s ref_cnt %u", found->name, found->ref_cnt); + DEBUG_VALIDATE_BUG_ON(found->ref_cnt == 0); + found->ref_cnt--; + } + SCMutexUnlock(&base_lock); +} + +int VarNameStoreActivate(void) +{ + int result = 0; + SCMutexLock(&base_lock); + SCLogDebug("activating new lookup store"); + + VarNameStore *new_active = NULL; + + // create lookup hash for id to string, strings should point to base + for (HashListTableBucket *b = HashListTableGetListHead(base.names); b != NULL; + b = HashListTableGetListNext(b)) { + VariableName *vn = HashListTableGetListData(b); + BUG_ON(vn == NULL); + SCLogDebug("base: %s/%u/%u", vn->name, vn->id, vn->ref_cnt); + if (vn->ref_cnt == 0) + continue; + + if (new_active == NULL) { + new_active = SCCalloc(1, sizeof(*new_active)); + if (new_active == NULL) { + result = -1; + goto out; + } + + new_active->names = HashListTableInit( + VARNAME_HASHSIZE, VariableNameHash, VariableNameCompare, NULL); + if (new_active->names == NULL) { + SCFree(new_active); + result = -1; + goto out; + } + new_active->ids = + HashListTableInit(VARID_HASHSIZE, VariableIdHash, VariableIdCompare, NULL); + if (new_active->ids == NULL) { + HashListTableFree(new_active->names); + SCFree(new_active); + result = -1; + goto out; + } + } + + /* memory is still owned by "base" */ + HashListTableAdd(new_active->names, (void *)vn, 0); + HashListTableAdd(new_active->ids, (void *)vn, 0); + } + + if (new_active) { + VarNameStore *old_active = SC_ATOMIC_GET(active); + if (old_active) { + struct timeval ts, add; + memset(&ts, 0, sizeof(ts)); + memset(&add, 0, sizeof(add)); + gettimeofday(&ts, NULL); + add.tv_sec = 60; + timeradd(&ts, &add, &ts); + old_active->free_after = ts; + + TAILQ_INSERT_TAIL(&free_list, old_active, next); + SCLogDebug("old active is stored in free list"); + } + + SC_ATOMIC_SET(active, new_active); + SCLogDebug("new store active"); + + struct timeval now; + memset(&now, 0, sizeof(now)); + gettimeofday(&now, NULL); + + VarNameStore *s = NULL; + while ((s = TAILQ_FIRST(&free_list))) { + char timebuf[64]; + CreateIsoTimeString(SCTIME_FROM_TIMEVAL(&s->free_after), timebuf, sizeof(timebuf)); + + if (!timercmp(&now, &s->free_after, >)) { + SCLogDebug("not yet freeing store %p before %s", s, timebuf); + break; + } + SCLogDebug("freeing store %p with time %s", s, timebuf); + TAILQ_REMOVE(&free_list, s, next); + HashListTableFree(s->names); + HashListTableFree(s->ids); + SCFree(s); + } + } +out: + SCLogDebug("activating new lookup store: complete %d", result); + SCMutexUnlock(&base_lock); + return result; +} + +/** \brief find name for id+type at packet time. */ +const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type) +{ + const char *name = NULL; + + const VarNameStore *current = SC_ATOMIC_GET(active); + if (current) { + VariableName lookup = { .type = type, .id = id }; + const VariableName *found = HashListTableLookup(current->ids, (void *)&lookup, 0); + if (found) { + return found->name; + } + } + + return name; +} + +/** \brief find name for id+type at packet time. */ +uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type) +{ + const VarNameStore *current = SC_ATOMIC_GET(active); + if (current) { + VariableName lookup = { .name = (char *)name, .type = type }; + const VariableName *found = HashListTableLookup(current->names, (void *)&lookup, 0); + if (found) { + return found->id; + } + } + + return 0; +} + +static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen) +{ + VariableName *vn = (VariableName *)buf; + uint32_t hash = StringHashDjb2((const uint8_t *)vn->name, strlen(vn->name)) + vn->type; + return (hash % VARNAME_HASHSIZE); +} + +static char VariableNameCompare(void *buf1, uint16_t len1, void *buf2, uint16_t len2) +{ + VariableName *vn1 = (VariableName *)buf1; + VariableName *vn2 = (VariableName *)buf2; + return (vn1->type == vn2->type && strcmp(vn1->name, vn2->name) == 0); +} + +static uint32_t VariableIdHash(HashListTable *ht, void *ptr, uint16_t _unused) +{ + VariableName *vn = (VariableName *)ptr; + uint32_t hash = vn->id << vn->type; + return (hash % VARID_HASHSIZE); +} + +static char VariableIdCompare(void *ptr1, uint16_t _unused1, void *ptr2, uint16_t _unused2) +{ + VariableName *vn1 = (VariableName *)ptr1; + VariableName *vn2 = (VariableName *)ptr2; + + return (vn1->id == vn2->id && vn1->type == vn2->type); +} + +static void VariableNameFree(void *data) +{ + VariableName *vn = (VariableName *)data; + if (vn == NULL) + return; + if (vn->name != NULL) { + SCFree(vn->name); + vn->name = NULL; + } + SCFree(vn); +} diff --git a/src/util/var-name.h b/src/util/var-name.h new file mode 100644 index 000000000000..7ee985c34847 --- /dev/null +++ b/src/util/var-name.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_VAR_NAME_H__ +#define __UTIL_VAR_NAME_H__ + +void VarNameStoreInit(void); +void VarNameStoreDestroy(void); + +uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type); +const char *VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type); +void VarNameStoreUnregister(const uint32_t id, const enum VarTypes type); +int VarNameStoreActivate(void); + +const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type); +uint32_t VarNameStoreLookupByName(const char *, const enum VarTypes type); + +#endif diff --git a/src/util/var.c b/src/util/var.c new file mode 100644 index 000000000000..04fb1abb506d --- /dev/null +++ b/src/util/var.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Generic variable utility functions + */ + +#include "suricata-common.h" +#include "../detect.h" + +#include "util/var.h" + +#include "flow-var.h" +#include "flow-bit.h" +#include "pkt-var.h" +#include "host-bit.h" +#include "ippair-bit.h" + +#include "util/debug.h" + +void XBitFree(XBit *fb) +{ + if (fb == NULL) + return; + + SCFree(fb); +} + +void GenericVarFree(GenericVar *gv) +{ + if (gv == NULL) + return; + + SCLogDebug("gv %p, gv->type %" PRIu32 "", gv, gv->type); + GenericVar *next_gv = gv->next; + + switch (gv->type) { + case DETECT_FLOWBITS: { + FlowBit *fb = (FlowBit *)gv; + // printf("GenericVarFree: fb %p, removing\n", fb); + FlowBitFree(fb); + break; + } + case DETECT_XBITS: { + XBit *fb = (XBit *)gv; + // printf("GenericVarFree: fb %p, removing\n", fb); + XBitFree(fb); + break; + } + case DETECT_FLOWVAR: { + FlowVar *fv = (FlowVar *)gv; + FlowVarFree(fv); + break; + } + case DETECT_PKTVAR: { + PktVar *pv = (PktVar *)gv; + PktVarFree(pv); + break; + } + default: { + printf("ERROR: GenericVarFree unknown type %" PRIu32 "\n", gv->type); + break; + } + } + + GenericVarFree(next_gv); +} + +void GenericVarAppend(GenericVar **list, GenericVar *gv) +{ + gv->next = NULL; + + if (*list == NULL) { + *list = gv; + } else { + GenericVar *tgv = *list; + while (tgv) { + if (tgv->next == NULL) { + tgv->next = gv; + return; + } + + tgv = tgv->next; + } + } +} + +void GenericVarRemove(GenericVar **list, GenericVar *gv) +{ + if (*list == NULL) + return; + + GenericVar *listgv = *list, *prevgv = NULL; + while (listgv != NULL) { + if (listgv == gv) { + if (prevgv == NULL) + *list = gv->next; + else + prevgv->next = gv->next; + + return; + } + + prevgv = listgv; + listgv = listgv->next; + } +} + +// Checks if a variable is already in a resolve list and if it's not, adds it. +int AddVariableToResolveList(ResolvedVariablesList *list, const char *var) +{ + ResolvedVariable *p_item; + + if (list == NULL || var == NULL) + return 0; + + if (var[0] != '$') { + return 0; + } + + TAILQ_FOREACH (p_item, list, next) { + if (!strcmp(p_item->var_name, var)) { + return -1; + } + } + + p_item = SCMalloc(sizeof(ResolvedVariable)); + + if (unlikely(p_item == NULL)) { + return -1; + } + + strlcpy(p_item->var_name, var, sizeof(p_item->var_name) - 1); + TAILQ_INSERT_TAIL(list, p_item, next); + + return 0; +} + +void CleanVariableResolveList(ResolvedVariablesList *var_list) +{ + if (var_list == NULL) { + return; + } + + ResolvedVariable *p_item; + + while ((p_item = TAILQ_FIRST(var_list))) { + TAILQ_REMOVE(var_list, p_item, next); + SCFree(p_item); + } +} diff --git a/src/util/var.h b/src/util/var.h new file mode 100644 index 000000000000..2ae6bb284e02 --- /dev/null +++ b/src/util/var.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_VAR_H__ +#define __UTIL_VAR_H__ + +enum VarTypes { + VAR_TYPE_NOT_SET, + + VAR_TYPE_PKT_BIT, + VAR_TYPE_PKT_INT, + VAR_TYPE_PKT_VAR, + VAR_TYPE_PKT_VAR_KV, // key-value + + VAR_TYPE_FLOW_BIT, + VAR_TYPE_FLOW_INT, + VAR_TYPE_FLOW_VAR, + + VAR_TYPE_HOST_BIT, + VAR_TYPE_HOST_INT, + VAR_TYPE_HOST_VAR, + + VAR_TYPE_IPPAIR_BIT, + VAR_TYPE_IPPAIR_INT, + VAR_TYPE_IPPAIR_VAR, +}; + +typedef struct GenericVar_ { + uint8_t type; + uint8_t pad[3]; + uint32_t idx; + struct GenericVar_ *next; +} GenericVar; + +typedef struct XBit_ { + uint8_t type; /* type, DETECT_XBITS in this case */ + uint8_t pad[3]; + uint32_t idx; /* name idx */ + GenericVar *next; + uint32_t expire; +} XBit; + +void XBitFree(XBit *); + +// A list of variables we try to resolve while parsing configuration file. +// Helps to detect recursive declarations. +typedef struct ResolvedVariable_ { + char var_name[256]; + TAILQ_ENTRY(ResolvedVariable_) next; +} ResolvedVariable; + +typedef TAILQ_HEAD(, ResolvedVariable_) ResolvedVariablesList; + +void GenericVarFree(GenericVar *); +void GenericVarAppend(GenericVar **, GenericVar *); +void GenericVarRemove(GenericVar **, GenericVar *); + +int AddVariableToResolveList(ResolvedVariablesList *list, const char *var); +void CleanVariableResolveList(ResolvedVariablesList *var_list); + +#endif /* __UTIL_VAR_H__ */ diff --git a/src/win32-syslog.h b/src/win32-syslog.h deleted file mode 100644 index 78aa06671fde..000000000000 --- a/src/win32-syslog.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * syslog.h does not exist in the mingw environment, this file replaces it - */ - -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)syslog.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef __WIN32_SYSLOG_H__ -#define __WIN32_SYSLOG_H__ - -#define LOG_EMERG 0 /* system is unusable */ -#define LOG_ALERT 1 /* action must be taken immediately */ -#define LOG_CRIT 2 /* critical conditions */ -#define LOG_ERR 3 /* error conditions */ -#define LOG_WARNING 4 /* warning conditions */ -#define LOG_NOTICE 5 /* normal but significant condition */ -#define LOG_INFO 6 /* informational */ -#define LOG_DEBUG 7 /* debug-level messages */ - -#define LOG_KERN (0<<3) /* kernel messages */ -#define LOG_USER (1<<3) /* random user-level messages */ -#define LOG_MAIL (2<<3) /* mail system */ -#define LOG_DAEMON (3<<3) /* system daemons */ -#define LOG_AUTH (4<<3) /* security/authorization messages */ -#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ -#define LOG_LPR (6<<3) /* line printer subsystem */ -#define LOG_NEWS (7<<3) /* network news subsystem */ -#define LOG_UUCP (8<<3) /* UUCP subsystem */ -#define LOG_CRON (9<<3) /* clock daemon */ -#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */ -#define LOG_FTP (11<<3) /* ftp daemon */ - - /* other codes through 15 reserved for system use */ -#define LOG_LOCAL0 (16<<3) /* reserved for local use */ -#define LOG_LOCAL1 (17<<3) /* reserved for local use */ -#define LOG_LOCAL2 (18<<3) /* reserved for local use */ -#define LOG_LOCAL3 (19<<3) /* reserved for local use */ -#define LOG_LOCAL4 (20<<3) /* reserved for local use */ -#define LOG_LOCAL5 (21<<3) /* reserved for local use */ -#define LOG_LOCAL6 (22<<3) /* reserved for local use */ -#define LOG_LOCAL7 (23<<3) /* reserved for local use */ - - -/* - * The current win32 implementation of syslog is dummy and does nothing. - */ -#define closelog() -#define openlog(__ident, __option, __facility) -#define setlogmask (__mask) -#define syslog(__pri, __fmt, __param) - -#endif diff --git a/src/win32-misc.c b/src/windows/win32-misc.c similarity index 83% rename from src/win32-misc.c rename to src/windows/win32-misc.c index 1dc28a69268a..5be5888c9245 100644 --- a/src/win32-misc.c +++ b/src/windows/win32-misc.c @@ -26,9 +26,9 @@ #ifdef OS_WIN32 #include "suricata-common.h" -#include "win32-misc.h" +#include "windows/win32-misc.h" #include "direct.h" -#include "util-ip.h" +#include "util/ip.h" void setenv(const char *name, const char *value, int overwrite) { @@ -54,24 +54,23 @@ void unsetenv(const char *name) /* these functions have been defined on Vista and later */ #if NTDDI_VERSION < NTDDI_VISTA -const char* inet_ntop(int af, const void *src, char *dst, uint32_t cnt) +const char *inet_ntop(int af, const void *src, char *dst, uint32_t cnt) { - if (af == AF_INET) - { + if (af == AF_INET) { struct sockaddr_in in; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; memcpy(&in.sin_addr, src, sizeof(struct in_addr)); - if (0 == getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST)) + if (0 == getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, + NI_NUMERICHOST)) return dst; - } - else if (af == AF_INET6) - { + } else if (af == AF_INET6) { struct sockaddr_in6 in6; memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; memcpy(&in6.sin6_addr, src, sizeof(struct in_addr6)); - if (0 == getnameinfo((struct sockaddr *)&in6, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST)) + if (0 == getnameinfo((struct sockaddr *)&in6, sizeof(struct sockaddr_in6), dst, cnt, NULL, + 0, NI_NUMERICHOST)) return dst; } return NULL; @@ -94,20 +93,18 @@ int inet_pton(int af, const char *src, void *dst) return -1; } - struct addrinfo* result = NULL; + struct addrinfo *result = NULL; if (0 != getaddrinfo(src, NULL, &hints, &result)) return -1; if (result) { if (result->ai_family == AF_INET) { - struct sockaddr_in* in = (struct sockaddr_in*)result->ai_addr; + struct sockaddr_in *in = (struct sockaddr_in *)result->ai_addr; memcpy(dst, &in->sin_addr, 4); - } - else if (result->ai_family == AF_INET6) { - struct sockaddr_in6* in6 = (struct sockaddr_in6*)result->ai_addr; + } else if (result->ai_family == AF_INET6) { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)result->ai_addr; memcpy(dst, &in6->sin6_addr, 16); - } - else { + } else { freeaddrinfo(result); return -1; } diff --git a/src/win32-misc.h b/src/windows/win32-misc.h similarity index 94% rename from src/win32-misc.h rename to src/windows/win32-misc.h index adecd05e5fa6..4c3e17812216 100644 --- a/src/win32-misc.h +++ b/src/windows/win32-misc.h @@ -34,7 +34,7 @@ void setenv(const char *name, const char *value, int overwrite); void unsetenv(const char *name); #if NTDDI_VERSION < NTDDI_VISTA -const char* inet_ntop(int af, const void *src, char *dst, uint32_t cnt); +const char *inet_ntop(int af, const void *src, char *dst, uint32_t cnt); int inet_pton(int af, const char *src, void *dst); #endif diff --git a/src/win32-service.c b/src/windows/win32-service.c similarity index 78% rename from src/win32-service.c rename to src/windows/win32-service.c index 0b7bd24e5fab..41966f922c5e 100644 --- a/src/win32-service.c +++ b/src/windows/win32-service.c @@ -27,8 +27,8 @@ #include "suricata-common.h" #include "suricata.h" -#include "win32-service.h" -#include "util-debug.h" +#include "windows/win32-service.h" +#include "util/debug.h" static SERVICE_STATUS_HANDLE service_status_handle = 0; @@ -46,7 +46,8 @@ int main(int argc, char **argv); int SCRunningAsService(void) { HANDLE h = INVALID_HANDLE_VALUE; - if ((h = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { + if ((h = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { SCLogInfo("Running as service: yes"); return 1; } @@ -60,15 +61,8 @@ int SCRunningAsService(void) */ static void SCAtExitHandler(void) { - SERVICE_STATUS status = { - SERVICE_WIN32, - SERVICE_STOPPED, - SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, - NO_ERROR, - NO_ERROR, - 0, - 0 - }; + SERVICE_STATUS status = { SERVICE_WIN32, SERVICE_STOPPED, + SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, NO_ERROR, NO_ERROR, 0, 0 }; SCLogInfo("Exit handler called."); @@ -86,18 +80,12 @@ static void SCAtExitHandler(void) static DWORD WINAPI SCServiceCtrlHandlerEx(DWORD code, DWORD etype, LPVOID edata, LPVOID context) { if (code == SERVICE_CONTROL_SHUTDOWN || code == SERVICE_CONTROL_STOP) { - SERVICE_STATUS status = { - SERVICE_WIN32, - SERVICE_STOP_PENDING, - SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, - NO_ERROR, - NO_ERROR, - 0, - 0 - }; + SERVICE_STATUS status = { SERVICE_WIN32, SERVICE_STOP_PENDING, + SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, NO_ERROR, NO_ERROR, 0, 0 }; SCLogInfo("Service control handler called with %s control code.", - ((code == SERVICE_CONTROL_SHUTDOWN) ? ("SERVICE_CONTROL_SHUTDOWN") : ("SERVICE_CONTROL_STOP"))); + ((code == SERVICE_CONTROL_SHUTDOWN) ? ("SERVICE_CONTROL_SHUTDOWN") + : ("SERVICE_CONTROL_STOP"))); /* mark service as stop pending */ if (!SetServiceStatus(service_status_handle, &status)) { @@ -118,19 +106,13 @@ static DWORD WINAPI SCServiceCtrlHandlerEx(DWORD code, DWORD etype, LPVOID edata /** * \brief Service main function */ -static void WINAPI SCServiceMain(uint32_t argc, char** argv) +static void WINAPI SCServiceMain(uint32_t argc, char **argv) { - SERVICE_STATUS status = { - SERVICE_WIN32, - SERVICE_RUNNING, - SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, - NO_ERROR, - NO_ERROR, - 0, - 0 - }; + SERVICE_STATUS status = { SERVICE_WIN32, SERVICE_RUNNING, + SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, NO_ERROR, NO_ERROR, 0, 0 }; - if ((service_status_handle = RegisterServiceCtrlHandlerEx((char *)PROG_NAME, SCServiceCtrlHandlerEx, NULL)) == (SERVICE_STATUS_HANDLE)0) { + if ((service_status_handle = RegisterServiceCtrlHandlerEx( + (char *)PROG_NAME, SCServiceCtrlHandlerEx, NULL)) == (SERVICE_STATUS_HANDLE)0) { SCLogError("Can't register service control handler: %d", (int)GetLastError()); return; } @@ -172,9 +154,8 @@ static void WINAPI SCServiceMain(uint32_t argc, char** argv) */ int SCServiceInit(int argc, char **argv) { - SERVICE_TABLE_ENTRY DispatchTable[] = { - {(char *)PROG_NAME, (LPSERVICE_MAIN_FUNCTION) SCServiceMain}, - {NULL, NULL} + SERVICE_TABLE_ENTRY DispatchTable[] = { + { (char *)PROG_NAME, (LPSERVICE_MAIN_FUNCTION)SCServiceMain }, { NULL, NULL } }; /* continue with suricata initialization */ @@ -219,14 +200,15 @@ int SCServiceInstall(int argc, char **argv) do { memset(path, 0, sizeof(path)); - if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){ + if (GetModuleFileName(NULL, path, MAX_PATH) == 0) { SCLogError("Can't get path to service binary: %d", (int)GetLastError()); break; } /* skip name of binary itself */ for (i = 1; i < argc; i++) { - if ((strlen(argv[i]) <= strlen("--service-install")) && (strncmp("--service-install", argv[i], strlen(argv[i])) == 0)) { + if ((strlen(argv[i]) <= strlen("--service-install")) && + (strncmp("--service-install", argv[i], strlen(argv[i])) == 0)) { continue; } strlcat(path, " ", sizeof(path) - strlen(path) - 1); @@ -238,20 +220,9 @@ int SCServiceInstall(int argc, char **argv) break; } - service = CreateService( - scm, - PROG_NAME, - PROG_NAME, - SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS, - SERVICE_DEMAND_START, - SERVICE_ERROR_NORMAL, - path, - NULL, - NULL, - NULL, - NULL, - NULL); + service = CreateService(scm, PROG_NAME, PROG_NAME, SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path, NULL, + NULL, NULL, NULL, NULL); if (service == NULL) { SCLogError("Can't create service: %d", (int)GetLastError()); @@ -260,7 +231,7 @@ int SCServiceInstall(int argc, char **argv) ret = 0; - } while(0); + } while (0); if (service) { CloseServiceHandle(service); @@ -314,7 +285,7 @@ int SCServiceRemove(int argc, char **argv) ret = 0; - } while(0); + } while (0); if (service) { CloseServiceHandle(service); @@ -344,14 +315,15 @@ int SCServiceChangeParams(int argc, char **argv) do { memset(path, 0, sizeof(path)); - if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){ + if (GetModuleFileName(NULL, path, MAX_PATH) == 0) { SCLogError("Can't get path to service binary: %d", (int)GetLastError()); break; } /* skip name of binary itself */ for (i = 1; i < argc; i++) { - if ((strlen(argv[i]) <= strlen("--service-change-params")) && (strncmp("--service-change-params", argv[i], strlen(argv[i])) == 0)) { + if ((strlen(argv[i]) <= strlen("--service-change-params")) && + (strncmp("--service-change-params", argv[i], strlen(argv[i])) == 0)) { continue; } strlcat(path, " ", sizeof(path) - strlen(path) - 1); @@ -368,26 +340,15 @@ int SCServiceChangeParams(int argc, char **argv) break; } - if (!ChangeServiceConfig( - service, - SERVICE_WIN32_OWN_PROCESS, - SERVICE_DEMAND_START, - SERVICE_ERROR_NORMAL, - path, - NULL, - NULL, - NULL, - NULL, - NULL, - PROG_NAME)) - { + if (!ChangeServiceConfig(service, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, + SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL, PROG_NAME)) { SCLogError("Can't change service configuration: %d", (int)GetLastError()); break; } ret = 0; - } while(0); + } while (0); return ret; } diff --git a/src/win32-service.h b/src/windows/win32-service.h similarity index 100% rename from src/win32-service.h rename to src/windows/win32-service.h diff --git a/src/win32-syscall.c b/src/windows/win32-syscall.c similarity index 79% rename from src/win32-syscall.c rename to src/windows/win32-syscall.c index 4e9145e118b7..0526c117638a 100644 --- a/src/win32-syscall.c +++ b/src/windows/win32-syscall.c @@ -52,14 +52,14 @@ #define _snprintf StringCbPrintfA #include "suricata-common.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-mem.h" -#include "util-unittest.h" +#include "util/debug.h" +#include "util/device.h" +#include "util/mem.h" +#include "util/unittest.h" #include "suricata.h" -#include "win32-syscall.h" +#include "windows/win32-syscall.h" /** * \brief return only the GUID portion of the name @@ -98,20 +98,17 @@ uint32_t Win32GetAdaptersAddresses(IP_ADAPTER_ADDRESSES **pif_info_list) return NO_ERROR; } -uint32_t Win32FindAdapterAddresses(IP_ADAPTER_ADDRESSES *if_info_list, - const char *adapter_name, - IP_ADAPTER_ADDRESSES **pif_info) +uint32_t Win32FindAdapterAddresses(IP_ADAPTER_ADDRESSES *if_info_list, const char *adapter_name, + IP_ADAPTER_ADDRESSES **pif_info) { DWORD ret = NO_ERROR; adapter_name = StripPcapPrefix(adapter_name); *pif_info = NULL; - for (IP_ADAPTER_ADDRESSES *current = if_info_list; current != NULL; - current = current->Next) { + for (IP_ADAPTER_ADDRESSES *current = if_info_list; current != NULL; current = current->Next) { /* if we find the adapter, return that data */ - if (strncmp(adapter_name, current->AdapterName, strlen(adapter_name)) == - 0) { + if (strncmp(adapter_name, current->AdapterName, strlen(adapter_name)) == 0) { *pif_info = current; break; @@ -127,8 +124,14 @@ uint32_t Win32FindAdapterAddresses(IP_ADAPTER_ADDRESSES *if_info_list, #if NTDDI_VERSION < NTDDI_VISTA -int GetIfaceMTUWin32(const char *pcap_dev) { return 0; } -int GetGlobalMTUWin32(void) { return 0; } +int GetIfaceMTUWin32(const char *pcap_dev) +{ + return 0; +} +int GetGlobalMTUWin32(void) +{ + return 0; +} int GetIfaceOffloadingWin32(const char *ifname, int csum, int other) { @@ -162,8 +165,7 @@ static HMODULE wmiutils_dll = NULL; static HMODULE WmiUtils(void) { if (wmiutils_dll == NULL) { - wmiutils_dll = - LoadLibraryA("C:\\Windows\\System32\\wbem\\wmiutils.dll"); + wmiutils_dll = LoadLibraryA("C:\\Windows\\System32\\wbem\\wmiutils.dll"); } return wmiutils_dll; @@ -189,16 +191,14 @@ const char *Win32GetErrorString(DWORD error_code, HMODULE ext_module) { char *error_string = NULL; - DWORD flags = - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS; + DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS; if (ext_module != NULL) { flags |= FORMAT_MESSAGE_FROM_HMODULE; } else { flags |= FORMAT_MESSAGE_FROM_SYSTEM; } - FormatMessageA(flags, ext_module, error_code, 0, (LPTSTR)&error_string, 0, - NULL); + FormatMessageA(flags, ext_module, error_code, 0, (LPTSTR)&error_string, 0, NULL); if (error_string == NULL) { return ""; @@ -213,16 +213,15 @@ const char *Win32GetErrorString(DWORD error_code, HMODULE ext_module) /** * \brief log an HRESULT */ -static void _Win32HResultLog(SCLogLevel level, HRESULT hr, const char *file, - const char *function, const int line) +static void _Win32HResultLog( + SCLogLevel level, HRESULT hr, const char *file, const char *function, const int line) { const char *err_str = Win32GetErrorString(hr, WmiUtils()); - SCLog(level, file, function, line, "HRESULT: %s (0x%08" PRIx32 ")", err_str, - (uint32_t)(hr)); + SCLog(level, file, function, line, "HRESULT: %s (0x%08" PRIx32 ")", err_str, (uint32_t)(hr)); LocalFree((LPVOID)err_str); } -#define Win32HResultLogDebug(hr) \ +#define Win32HResultLogDebug(hr) \ _Win32HResultLog(SC_LOG_DEBUG, (hr), __FILE__, __FUNCTION__, __LINE__) #else #define Win32HResultLogDebug(hr) @@ -233,8 +232,7 @@ static void _Win32HResultLog(SCLogLevel level, HRESULT hr, const char *file, */ #define WbemLogDebug(hr) (_WbemLogDebug)((hr), __FILE__, __FUNCTION__, __LINE__) -static void _WbemLogDebug(HRESULT hr, const char *file, const char *function, - const int line) +static void _WbemLogDebug(HRESULT hr, const char *file, const char *function, const int line) { #ifdef DEBUG IErrorInfo *err_info; @@ -244,8 +242,7 @@ static void _WbemLogDebug(HRESULT hr, const char *file, const char *function, _Win32HResultLog(SC_LOG_DEBUG, hr, file, function, line); GetErrorInfo(0, &err_info); - if (!SUCCEEDED( - err_info->lpVtbl->GetDescription(err_info, &err_description))) { + if (!SUCCEEDED(err_info->lpVtbl->GetDescription(err_info, &err_description))) { // not much to do when your error log errors out... goto release; } @@ -259,12 +256,10 @@ static void _WbemLogDebug(HRESULT hr, const char *file, const char *function, // do the actual multibyte conversion err_description_mb[SysStringLen(err_description)] = 0; - wcstombs(err_description_mb, err_description, - SysStringLen(err_description)); + wcstombs(err_description_mb, err_description, SysStringLen(err_description)); // log the description - SCLog(SC_LOG_DEBUG, file, function, line, "WBEM error: %s", - err_description_mb); + SCLog(SC_LOG_DEBUG, file, function, line, "WBEM error: %s", err_description_mb); release: SCFree(err_description_mb); @@ -350,7 +345,7 @@ int GetGlobalMTUWin32(void) const char *errbuf = NULL; FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, 0, (LPTSTR)&errbuf, 0, NULL); + NULL, err, 0, (LPTSTR)&errbuf, 0, NULL); SCLogWarning("Failure when trying to get global MTU via syscall: %s (%" PRId32 ")", errbuf, (uint32_t)err); @@ -358,12 +353,12 @@ int GetGlobalMTUWin32(void) return -1; } -#define ReleaseObject(objptr) \ - do { \ - if ((objptr) != NULL) { \ - (objptr)->lpVtbl->Release(objptr); \ - (objptr) = NULL; \ - } \ +#define ReleaseObject(objptr) \ + do { \ + if ((objptr) != NULL) { \ + (objptr)->lpVtbl->Release(objptr); \ + (objptr) = NULL; \ + } \ } while (0); typedef enum Win32TcpOffloadFlags_ { @@ -377,14 +372,13 @@ typedef enum Win32TcpOffloadFlags_ { WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6 = 1 << 6, /* aggregates */ - WIN32_TCP_OFFLOAD_FLAG_CSUM = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX | - WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX | - WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX | - WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX, - WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4 = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX | - WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX, - WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6 = WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX | - WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX, + WIN32_TCP_OFFLOAD_FLAG_CSUM = + WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX | WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX | + WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX | WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX, + WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4 = + WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX | WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX, + WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6 = + WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX | WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX, WIN32_TCP_OFFLOAD_FLAG_LSO = WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4 | WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4 | WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6, @@ -422,8 +416,7 @@ static HRESULT ComInstanceInit(ComInstance *instance, LPCWSTR resource) SCLogWarning("COM CoInitializeEx failed: 0x%" PRIx32, (uint32_t)hr); goto release; } - hr = CoInitializeSecurity( - NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, + hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); if (hr != S_OK) { SCLogWarning("COM CoInitializeSecurity failed: 0x%" PRIx32, (uint32_t)hr); @@ -432,15 +425,14 @@ static HRESULT ComInstanceInit(ComInstance *instance, LPCWSTR resource) } /* connect to WMI */ - hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, - &IID_IWbemLocator, (LPVOID *)&instance->locator); + hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, + (LPVOID *)&instance->locator); if (hr != S_OK) { SCLogWarning("COM CoCreateInstance failed: 0x%" PRIx32, (uint32_t)hr); goto release; } hr = instance->locator->lpVtbl->ConnectServer( - instance->locator, resource_bstr, NULL, NULL, NULL, 0, NULL, NULL, - &instance->services); + instance->locator, resource_bstr, NULL, NULL, NULL, 0, NULL, NULL, &instance->services); if (hr != S_OK) { SCLogWarning("COM ConnectServer failed: 0x%" PRIx32, (uint32_t)hr); goto release; @@ -467,14 +459,12 @@ static void ComInstanceRelease(ComInstance *instance) /** * \brief obtains a class definition from COM services */ -static HRESULT GetWbemClass(ComInstance *instance, LPCWSTR name, - IWbemClassObject **p_class) +static HRESULT GetWbemClass(ComInstance *instance, LPCWSTR name, IWbemClassObject **p_class) { HRESULT hr = WBEM_S_NO_ERROR; BSTR name_bstr = NULL; - if (instance == NULL || name == NULL || p_class == NULL || - *p_class != NULL) { + if (instance == NULL || name == NULL || p_class == NULL || *p_class != NULL) { hr = HRESULT_FROM_WIN32(E_INVALIDARG); Win32HResultLogDebug(hr); goto release; @@ -489,9 +479,8 @@ static HRESULT GetWbemClass(ComInstance *instance, LPCWSTR name, } /* obtain object */ - hr = instance->services->lpVtbl->GetObject(instance->services, name_bstr, - WBEM_FLAG_RETURN_WBEM_COMPLETE, - NULL, p_class, NULL); + hr = instance->services->lpVtbl->GetObject( + instance->services, name_bstr, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, p_class, NULL); if (hr != S_OK) { WbemLogDebug(hr); SCLogWarning("WMI GetObject failed: 0x%" PRIx32, (uint32_t)hr); @@ -507,8 +496,8 @@ static HRESULT GetWbemClass(ComInstance *instance, LPCWSTR name, /** * \brief spawns an empty class instance of the specified type */ -static HRESULT GetWbemClassInstance(ComInstance *instance, LPCWSTR name, - IWbemClassObject **p_instance) +static HRESULT GetWbemClassInstance( + ComInstance *instance, LPCWSTR name, IWbemClassObject **p_instance) { HRESULT hr = WBEM_S_NO_ERROR; @@ -541,8 +530,8 @@ typedef struct WbemMethod_ { /** * \brief initializes resources for a WMI method handle */ -static HRESULT GetWbemMethod(ComInstance *com_instance, LPCWSTR class_name, - LPCWSTR method_name, WbemMethod *method) +static HRESULT GetWbemMethod( + ComInstance *com_instance, LPCWSTR class_name, LPCWSTR method_name, WbemMethod *method) { HRESULT hr = S_OK; IWbemClassObject *class = NULL; @@ -569,8 +558,7 @@ static HRESULT GetWbemMethod(ComInstance *com_instance, LPCWSTR class_name, } /* find the method on the retrieved class */ - hr = class->lpVtbl->GetMethod(class, method_name, 0, &method->in_params, - &method->out_params); + hr = class->lpVtbl->GetMethod(class, method_name, 0, &method->in_params, &method->out_params); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); SCLogWarning("WMI GetMethod failed: 0x%" PRIx32, (uint32_t)hr); @@ -610,8 +598,7 @@ typedef struct WbemMethodCall_ { /** * \brief generates a single-use WMI method call */ -static HRESULT GetWbemMethodCall(WbemMethod *method, LPCWSTR instance_path, - WbemMethodCall *call) +static HRESULT GetWbemMethodCall(WbemMethod *method, LPCWSTR instance_path, WbemMethodCall *call) { HRESULT hr = S_OK; @@ -624,8 +611,7 @@ static HRESULT GetWbemMethodCall(WbemMethod *method, LPCWSTR instance_path, } /* make an instance of the in/out params */ - hr = method->in_params->lpVtbl->SpawnInstance(method->in_params, 0, - &call->in_params); + hr = method->in_params->lpVtbl->SpawnInstance(method->in_params, 0, &call->in_params); if (hr != S_OK) { WbemLogDebug(hr); SCLogWarning("WMI SpawnInstance failed on in_params: 0x%" PRIx32, (uint32_t)hr); @@ -652,15 +638,13 @@ static void WbemMethodCallRelease(WbemMethodCall *call) /** * \brief executes the method after the client has set applicable parameters. */ -static HRESULT WbemMethodCallExec(WbemMethodCall *call, - IWbemClassObject **p_out_params) +static HRESULT WbemMethodCallExec(WbemMethodCall *call, IWbemClassObject **p_out_params) { HRESULT hr = S_OK; hr = call->method->com_instance->services->lpVtbl->ExecMethod( - call->method->com_instance->services, call->instance_path, - call->method->method_name, 0, NULL, call->in_params, p_out_params, - NULL); + call->method->com_instance->services, call->instance_path, call->method->method_name, 0, + NULL, call->in_params, p_out_params, NULL); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); SCLogDebug("WMI ExecMethod failed: 0x%" PRIx32, (uint32_t)hr); @@ -674,8 +658,8 @@ static HRESULT WbemMethodCallExec(WbemMethodCall *call, /** * Obtains an IWbemClassObject named property of a parent IWbemClassObject */ -static HRESULT WbemGetSubObject(IWbemClassObject *object, LPCWSTR property_name, - IWbemClassObject **sub_object) +static HRESULT WbemGetSubObject( + IWbemClassObject *object, LPCWSTR property_name, IWbemClassObject **sub_object) { HRESULT hr = S_OK; @@ -687,8 +671,7 @@ static HRESULT WbemGetSubObject(IWbemClassObject *object, LPCWSTR property_name, } IUnknown *unknown = V_UNKNOWN(&out_var); - hr = unknown->lpVtbl->QueryInterface(unknown, &IID_IWbemClassObject, - (void **)sub_object); + hr = unknown->lpVtbl->QueryInterface(unknown, &IID_IWbemClassObject, (void **)sub_object); if (hr != S_OK) { SCLogWarning("WMI QueryInterface (IWbemClassObject) failed: 0x%" PRIx32, (uint32_t)hr); goto release; @@ -702,8 +685,8 @@ static HRESULT WbemGetSubObject(IWbemClassObject *object, LPCWSTR property_name, /** * Obtains an Encapsulation value from an MSNdis_WmiOffload property */ -static HRESULT GetEncapsulation(IWbemClassObject *object, LPCWSTR category, - LPCWSTR subcategory, ULONG *encapsulation) +static HRESULT GetEncapsulation( + IWbemClassObject *object, LPCWSTR category, LPCWSTR subcategory, ULONG *encapsulation) { HRESULT hr = WBEM_S_NO_ERROR; @@ -724,8 +707,8 @@ static HRESULT GetEncapsulation(IWbemClassObject *object, LPCWSTR category, if (hr != WBEM_S_NO_ERROR) { goto release; } - hr = subcategory_object->lpVtbl->Get(subcategory_object, L"Encapsulation", - 0, &out_var, NULL, NULL); + hr = subcategory_object->lpVtbl->Get( + subcategory_object, L"Encapsulation", 0, &out_var, NULL, NULL); if (hr != WBEM_S_NO_ERROR) { goto release; } @@ -748,8 +731,7 @@ static HRESULT GetIUnknown(IWbemClassObject *object, IUnknown **p_unknown) goto release; } - hr = object->lpVtbl->QueryInterface(object, &IID_IUnknown, - (void **)p_unknown); + hr = object->lpVtbl->QueryInterface(object, &IID_IUnknown, (void **)p_unknown); if (hr != S_OK) { SCLogWarning("WMI QueryInterface (IUnknown) failed: 0x%" PRIx32, (uint32_t)hr); goto release; @@ -759,14 +741,12 @@ static HRESULT GetIUnknown(IWbemClassObject *object, IUnknown **p_unknown) return hr; } -static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t type, - uint8_t revision, uint16_t size, - IWbemClassObject **p_ndis_object_header) +static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t type, uint8_t revision, + uint16_t size, IWbemClassObject **p_ndis_object_header) { HRESULT hr = WBEM_S_NO_ERROR; - if (instance == NULL || p_ndis_object_header == NULL || - *p_ndis_object_header != NULL) { + if (instance == NULL || p_ndis_object_header == NULL || *p_ndis_object_header != NULL) { hr = HRESULT_FROM_WIN32(E_INVALIDARG); Win32HResultLogDebug(hr); @@ -774,8 +754,7 @@ static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t type, } /* obtain object */ - hr = GetWbemClassInstance(instance, L"MSNdis_ObjectHeader", - p_ndis_object_header); + hr = GetWbemClassInstance(instance, L"MSNdis_ObjectHeader", p_ndis_object_header); if (hr != WBEM_S_NO_ERROR) { goto release; } @@ -787,8 +766,7 @@ static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t type, /* set parameters */ V_VT(¶m_variant) = VT_UI1; V_UI1(¶m_variant) = type; - hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L"Type", 0, - ¶m_variant, 0); + hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L"Type", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -797,8 +775,7 @@ static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t type, V_VT(¶m_variant) = VT_UI1; V_UI1(¶m_variant) = revision; - hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L"Revision", 0, - ¶m_variant, 0); + hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L"Revision", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -809,8 +786,7 @@ static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t type, */ V_VT(¶m_variant) = VT_I4; V_I4(¶m_variant) = size; - hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L"Size", 0, - ¶m_variant, 0); + hr = ndis_object_header->lpVtbl->Put(ndis_object_header, L"Size", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -821,17 +797,15 @@ static HRESULT BuildNdisObjectHeader(ComInstance *instance, uint8_t type, return hr; } -static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, - uint64_t net_luid, uint32_t port_number, - uint64_t request_id, uint32_t timeout, - IWbemClassObject **p_ndis_method_header) +static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, uint64_t net_luid, + uint32_t port_number, uint64_t request_id, uint32_t timeout, + IWbemClassObject **p_ndis_method_header) { HRESULT hr = WBEM_S_NO_ERROR; IWbemClassObject *ndis_object_header = NULL; - if (instance == NULL || p_ndis_method_header == NULL || - *p_ndis_method_header != NULL) { + if (instance == NULL || p_ndis_method_header == NULL || *p_ndis_method_header != NULL) { hr = HRESULT_FROM_WIN32(E_INVALIDARG); Win32HResultLogDebug(hr); @@ -839,8 +813,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, } /* obtain object */ - hr = GetWbemClassInstance(instance, L"MSNdis_WmiMethodHeader", - p_ndis_method_header); + hr = GetWbemClassInstance(instance, L"MSNdis_WmiMethodHeader", p_ndis_method_header); if (hr != WBEM_S_NO_ERROR) { goto release; } @@ -850,8 +823,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, /* get embedded MSNdis_ObjectHeader */ hr = BuildNdisObjectHeader(instance, NDIS_WMI_OBJECT_TYPE_METHOD, - NDIS_WMI_METHOD_HEADER_REVISION_1, 0xFFFF, - &ndis_object_header); + NDIS_WMI_METHOD_HEADER_REVISION_1, 0xFFFF, &ndis_object_header); if (hr != WBEM_S_NO_ERROR) { goto release; } @@ -865,8 +837,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, IWbemClassObject *ndis_method_header = *p_ndis_method_header; /* set parameters */ - hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"Header", 0, - ¶m_variant, 0); + hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"Header", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -875,8 +846,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, V_VT(¶m_variant) = VT_BSTR; V_BSTR(¶m_variant) = utob(net_luid); - hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"NetLuid", 0, - ¶m_variant, 0); + hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"NetLuid", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -885,8 +855,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, V_VT(¶m_variant) = VT_BSTR; V_BSTR(¶m_variant) = utob((uint64_t)port_number); - hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"PortNumber", 0, - ¶m_variant, 0); + hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"PortNumber", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -895,8 +864,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, V_VT(¶m_variant) = VT_BSTR; V_BSTR(¶m_variant) = utob(request_id); - hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"RequestId", 0, - ¶m_variant, 0); + hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"RequestId", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -905,8 +873,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, V_VT(¶m_variant) = VT_BSTR; V_BSTR(¶m_variant) = utob((uint64_t)timeout); - hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"Timeout", 0, - ¶m_variant, 0); + hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"Timeout", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -915,8 +882,7 @@ static HRESULT BuildNdisWmiMethodHeader(ComInstance *instance, V_VT(¶m_variant) = VT_BSTR; V_BSTR(¶m_variant) = utob((uint64_t)0); - hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"Padding", 0, - ¶m_variant, 0); + hr = ndis_method_header->lpVtbl->Put(ndis_method_header, L"Padding", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -952,16 +918,14 @@ static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags) LPCWSTR class_name = L"MSNdis_TcpOffloadCurrentConfig"; LPCWSTR instance_name_fmt = L"%s=\"%s\""; - size_t n_chars = wcslen(class_name) + wcslen(if_description) + - wcslen(instance_name_fmt); + size_t n_chars = wcslen(class_name) + wcslen(if_description) + wcslen(instance_name_fmt); LPWSTR instance_name = SCMalloc((n_chars + 1) * sizeof(wchar_t)); if (instance_name == NULL) { SCLogWarning("Failed to allocate buffer for instance path"); goto release; } instance_name[n_chars] = 0; /* defensively null-terminate */ - hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name, - if_description); + hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name, if_description); if (hr != S_OK) { SCLogWarning("Failed to format WMI class instance name: 0x%" PRIx32, (uint32_t)hr); goto release; @@ -1005,8 +969,7 @@ static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags) } /* Set in_params */ - hr = call.in_params->lpVtbl->Put(call.in_params, L"Header", 0, - ¶m_variant, 0); + hr = call.in_params->lpVtbl->Put(call.in_params, L"Header", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); @@ -1026,7 +989,7 @@ static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags) wcstombs(if_description_ansi, if_description, if_description_len); SCLogInfo("Obtaining offload state failed, device \"%s\" may not " "support offload. Error: 0x%" PRIx32, - if_description_ansi, (uint32_t)hr); + if_description_ansi, (uint32_t)hr); SCFree(if_description_ansi); Win32HResultLogDebug(hr); goto release; @@ -1040,8 +1003,7 @@ static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags) ULONG encapsulation = 0; /* Checksum */ - hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv4Receive", - &encapsulation); + hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv4Receive", &encapsulation); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; @@ -1049,8 +1011,7 @@ static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags) if (encapsulation != 0) { *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX; } - hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv4Transmit", - &encapsulation); + hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv4Transmit", &encapsulation); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; @@ -1058,8 +1019,7 @@ static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags) if (encapsulation != 0) { *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX; } - hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv6Receive", - &encapsulation); + hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv6Receive", &encapsulation); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; @@ -1067,8 +1027,7 @@ static HRESULT GetNdisOffload(LPCWSTR if_description, uint32_t *offload_flags) if (encapsulation != 0) { *offload_flags |= WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX; } - hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv6Transmit", - &encapsulation); + hr = GetEncapsulation(ndis_offload, L"Checksum", L"IPv6Transmit", &encapsulation); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; @@ -1160,14 +1119,13 @@ int GetIfaceOffloadingWin32(const char *pcap_dev, int csum, int other) if (ret == 0) { SCLogPerf("NIC offloading on %s: Checksum IPv4 Rx: %d Tx: %d IPv6 " "Rx: %d Tx: %d LSOv1 IPv4: %d LSOv2 IPv4: %d IPv6: %d", - pcap_dev, - (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0, - (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0, - (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0, - (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0, - (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0, - (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0, - (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0); + pcap_dev, (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0, + (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0, + (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0, + (offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0, + (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0, + (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0, + (offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0); } else { SCLogWarning("NIC offloading on %s: Checksum IPv4 Rx: %d Tx: %d IPv6 " "Rx: %d Tx: %d LSOv1 IPv4: %d LSOv2 IPv4: %d IPv6: %d", @@ -1194,17 +1152,15 @@ int GetIfaceOffloadingWin32(const char *pcap_dev, int csum, int other) return ret; } -static HRESULT -BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, - bool enable, - IWbemClassObject **p_ndis_tcp_offload_parameters) +static HRESULT BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, + bool enable, IWbemClassObject **p_ndis_tcp_offload_parameters) { HRESULT hr = WBEM_S_NO_ERROR; IWbemClassObject *ndis_object_header = NULL; if (instance == NULL || p_ndis_tcp_offload_parameters == NULL || - *p_ndis_tcp_offload_parameters != NULL) { + *p_ndis_tcp_offload_parameters != NULL) { hr = HRESULT_FROM_WIN32(E_INVALIDARG); Win32HResultLogDebug(hr); @@ -1212,8 +1168,8 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, } /* obtain object */ - hr = GetWbemClassInstance(instance, L"MSNdis_TcpOffloadParameters", - p_ndis_tcp_offload_parameters); + hr = GetWbemClassInstance( + instance, L"MSNdis_TcpOffloadParameters", p_ndis_tcp_offload_parameters); if (hr != WBEM_S_NO_ERROR) { goto release; } @@ -1223,9 +1179,8 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, /* get embedded MSNdis_ObjectHeader */ hr = BuildNdisObjectHeader(instance, NDIS_OBJECT_TYPE_DEFAULT, - NDIS_OFFLOAD_PARAMETERS_REVISION_1, - NDIS_SIZEOF_OFFLOAD_PARAMETERS_REVISION_1, - &ndis_object_header); + NDIS_OFFLOAD_PARAMETERS_REVISION_1, NDIS_SIZEOF_OFFLOAD_PARAMETERS_REVISION_1, + &ndis_object_header); if (hr != WBEM_S_NO_ERROR) { goto release; } @@ -1236,8 +1191,7 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, goto release; } - IWbemClassObject *ndis_tcp_offload_parameters = - *p_ndis_tcp_offload_parameters; + IWbemClassObject *ndis_tcp_offload_parameters = *p_ndis_tcp_offload_parameters; /* set parameters */ hr = ndis_tcp_offload_parameters->lpVtbl->Put( @@ -1260,12 +1214,10 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED); } else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4RX) != 0) { /* implied enable */ - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED); } else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP4TX) != 0) { /* implied enable */ - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED); } hr = ndis_tcp_offload_parameters->lpVtbl->Put( ndis_tcp_offload_parameters, L"IPv4Checksum", 0, ¶m_variant, 0); @@ -1273,16 +1225,14 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, WbemLogDebug(hr); goto release; } - hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters, - L"TCPIPv4Checksum", 0, - ¶m_variant, 0); + hr = ndis_tcp_offload_parameters->lpVtbl->Put( + ndis_tcp_offload_parameters, L"TCPIPv4Checksum", 0, ¶m_variant, 0); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; } - hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters, - L"UDPIPv4Checksum", 0, - ¶m_variant, 0); + hr = ndis_tcp_offload_parameters->lpVtbl->Put( + ndis_tcp_offload_parameters, L"UDPIPv4Checksum", 0, ¶m_variant, 0); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; @@ -1301,23 +1251,19 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED); } else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6RX) != 0) { /* implied enable */ - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED); } else if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_CSUM_IP6TX) != 0) { /* implied enable */ - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED); } - hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters, - L"TCPIPv6Checksum", 0, - ¶m_variant, 0); + hr = ndis_tcp_offload_parameters->lpVtbl->Put( + ndis_tcp_offload_parameters, L"TCPIPv6Checksum", 0, ¶m_variant, 0); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; } - hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters, - L"UDPIPv6Checksum", 0, - ¶m_variant, 0); + hr = ndis_tcp_offload_parameters->lpVtbl->Put( + ndis_tcp_offload_parameters, L"UDPIPv6Checksum", 0, ¶m_variant, 0); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; @@ -1329,11 +1275,9 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE); if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV1_IP4) != 0) { if (enable) { - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED); } else { - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_DISABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_LSOV1_DISABLED); } } hr = ndis_tcp_offload_parameters->lpVtbl->Put( @@ -1349,11 +1293,9 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE); if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP4) != 0) { if (enable) { - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED); } else { - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED); } } hr = ndis_tcp_offload_parameters->lpVtbl->Put( @@ -1369,11 +1311,9 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_NO_CHANGE); if ((offload_flags & WIN32_TCP_OFFLOAD_FLAG_LSOV2_IP6) != 0) { if (enable) { - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED); } else { - V_BSTR(¶m_variant) = - utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED); + V_BSTR(¶m_variant) = utob(NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED); } } hr = ndis_tcp_offload_parameters->lpVtbl->Put( @@ -1393,16 +1333,14 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, WbemLogDebug(hr); goto release; } - hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters, - L"TcpConnectionIPv4", 0, - ¶m_variant, 0); + hr = ndis_tcp_offload_parameters->lpVtbl->Put( + ndis_tcp_offload_parameters, L"TcpConnectionIPv4", 0, ¶m_variant, 0); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; } - hr = ndis_tcp_offload_parameters->lpVtbl->Put(ndis_tcp_offload_parameters, - L"TcpConnectionIPv6", 0, - ¶m_variant, 0); + hr = ndis_tcp_offload_parameters->lpVtbl->Put( + ndis_tcp_offload_parameters, L"TcpConnectionIPv6", 0, ¶m_variant, 0); if (hr != WBEM_S_NO_ERROR) { WbemLogDebug(hr); goto release; @@ -1421,8 +1359,7 @@ BuildNdisTcpOffloadParameters(ComInstance *instance, uint32_t offload_flags, return hr; } -static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags, - bool enable) +static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags, bool enable) { HRESULT hr = S_OK; @@ -1442,16 +1379,14 @@ static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags, LPCWSTR class_name = L"MSNdis_SetTcpOffloadParameters"; LPCWSTR instance_name_fmt = L"%s=\"%s\""; - size_t n_chars = wcslen(class_name) + wcslen(if_description) + - wcslen(instance_name_fmt); + size_t n_chars = wcslen(class_name) + wcslen(if_description) + wcslen(instance_name_fmt); LPWSTR instance_name = SCMalloc((n_chars + 1) * sizeof(wchar_t)); if (instance_name == NULL) { SCLogWarning("Failed to allocate buffer for instance path"); goto release; } instance_name[n_chars] = 0; /* defensively null-terminate */ - hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name, - if_description); + hr = StringCchPrintfW(instance_name, n_chars, instance_name_fmt, class_name, if_description); if (hr != S_OK) { SCLogWarning("Failed to format WMI class instance name: 0x%" PRIx32, (uint32_t)hr); goto release; @@ -1495,8 +1430,7 @@ static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags, if (hr != WBEM_S_NO_ERROR) { goto release; } - hr = call.in_params->lpVtbl->Put(call.in_params, L"MethodHeader", 0, - ¶m_variant, 0); + hr = call.in_params->lpVtbl->Put(call.in_params, L"MethodHeader", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { Win32HResultLogDebug(hr); @@ -1504,8 +1438,8 @@ static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags, } /* Make MSNdis_TcpOffloadParameters */ - hr = BuildNdisTcpOffloadParameters(&instance, offload_flags, enable, - &ndis_tcp_offload_parameters); + hr = BuildNdisTcpOffloadParameters( + &instance, offload_flags, enable, &ndis_tcp_offload_parameters); if (hr != WBEM_S_NO_ERROR) { goto release; } @@ -1516,8 +1450,7 @@ static HRESULT SetNdisOffload(LPCWSTR if_description, uint32_t offload_flags, if (hr != WBEM_S_NO_ERROR) { goto release; } - hr = call.in_params->lpVtbl->Put(call.in_params, L"TcpOffloadParameters", 0, - ¶m_variant, 0); + hr = call.in_params->lpVtbl->Put(call.in_params, L"TcpOffloadParameters", 0, ¶m_variant, 0); VariantClear(¶m_variant); if (hr != WBEM_S_NO_ERROR) { Win32HResultLogDebug(hr); @@ -1643,11 +1576,9 @@ static int Win32TestStripPcapPrefix(void) const char *name2 = "{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}"; const char *expect_name2 = "{D4A32435-1BA7-4008-93A6-1518AA4BBD9B}"; - result &= (strncmp(expect_name1, StripPcapPrefix(name1), - strlen(expect_name1)) == 0); + result &= (strncmp(expect_name1, StripPcapPrefix(name1), strlen(expect_name1)) == 0); - result &= (strncmp(expect_name2, StripPcapPrefix(name2), - strlen(expect_name2)) == 0); + result &= (strncmp(expect_name2, StripPcapPrefix(name2), strlen(expect_name2)) == 0); return result; } diff --git a/src/win32-syscall.h b/src/windows/win32-syscall.h similarity index 90% rename from src/win32-syscall.h rename to src/windows/win32-syscall.h index beb164df19ee..2432010fc097 100644 --- a/src/win32-syscall.h +++ b/src/windows/win32-syscall.h @@ -31,14 +31,13 @@ #include -#include "util-device.h" +#include "util/device.h" const char *Win32GetErrorString(DWORD error_code, HMODULE ext_module); uint32_t Win32GetAdaptersAddresses(IP_ADAPTER_ADDRESSES **pif_info_list); -uint32_t Win32FindAdapterAddresses(IP_ADAPTER_ADDRESSES *if_info_list, - const char *adapter_name, - IP_ADAPTER_ADDRESSES **pif_info); +uint32_t Win32FindAdapterAddresses(IP_ADAPTER_ADDRESSES *if_info_list, const char *adapter_name, + IP_ADAPTER_ADDRESSES **pif_info); int GetIfaceMTUWin32(const char *pcap_dev); int GetGlobalMTUWin32(void); diff --git a/src/windows/win32-syslog.h b/src/windows/win32-syslog.h new file mode 100644 index 000000000000..3b3d98e3c4ec --- /dev/null +++ b/src/windows/win32-syslog.h @@ -0,0 +1,79 @@ +/** + * syslog.h does not exist in the mingw environment, this file replaces it + */ + +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)syslog.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef __WIN32_SYSLOG_H__ +#define __WIN32_SYSLOG_H__ + +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ + +#define LOG_KERN (0 << 3) /* kernel messages */ +#define LOG_USER (1 << 3) /* random user-level messages */ +#define LOG_MAIL (2 << 3) /* mail system */ +#define LOG_DAEMON (3 << 3) /* system daemons */ +#define LOG_AUTH (4 << 3) /* security/authorization messages */ +#define LOG_SYSLOG (5 << 3) /* messages generated internally by syslogd */ +#define LOG_LPR (6 << 3) /* line printer subsystem */ +#define LOG_NEWS (7 << 3) /* network news subsystem */ +#define LOG_UUCP (8 << 3) /* UUCP subsystem */ +#define LOG_CRON (9 << 3) /* clock daemon */ +#define LOG_AUTHPRIV (10 << 3) /* security/authorization messages (private) */ +#define LOG_FTP (11 << 3) /* ftp daemon */ + +/* other codes through 15 reserved for system use */ +#define LOG_LOCAL0 (16 << 3) /* reserved for local use */ +#define LOG_LOCAL1 (17 << 3) /* reserved for local use */ +#define LOG_LOCAL2 (18 << 3) /* reserved for local use */ +#define LOG_LOCAL3 (19 << 3) /* reserved for local use */ +#define LOG_LOCAL4 (20 << 3) /* reserved for local use */ +#define LOG_LOCAL5 (21 << 3) /* reserved for local use */ +#define LOG_LOCAL6 (22 << 3) /* reserved for local use */ +#define LOG_LOCAL7 (23 << 3) /* reserved for local use */ + +/* + * The current win32 implementation of syslog is dummy and does nothing. + */ +#define closelog() +#define openlog(__ident, __option, __facility) +#define setlogmask (__mask) +#define syslog(__pri, __fmt, __param) + +#endif